Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

dmaengine: dw-edma: Add AMD MDB Endpoint Support

AMD MDB PCIe endpoint support. For AMD specific support
added the following
- AMD supported PCIe Device IDs and Vendor ID (Xilinx).
- AMD MDB specific driver data
- AMD MDB specific VSEC capability to retrieve the device DDR
base address.

Signed-off-by: Devendra K Verma <devendra.verma@amd.com>
Reviewed-by: Frank Li <Frank.Li@nxp.com>
Link: https://patch.msgid.link/20260318070403.1634706-2-devendra.verma@amd.com
Signed-off-by: Vinod Koul <vkoul@kernel.org>

authored by

Devendra K Verma and committed by
Vinod Koul
14eb9a1d 132e47b7

+176 -14
+176 -14
drivers/dma/dw-edma/dw-edma-pcie.c
··· 14 14 #include <linux/pci-epf.h> 15 15 #include <linux/msi.h> 16 16 #include <linux/bitfield.h> 17 + #include <linux/sizes.h> 17 18 18 19 #include "dw-edma-core.h" 19 20 20 - #define DW_PCIE_VSEC_DMA_ID 0x6 21 - #define DW_PCIE_VSEC_DMA_BAR GENMASK(10, 8) 22 - #define DW_PCIE_VSEC_DMA_MAP GENMASK(2, 0) 23 - #define DW_PCIE_VSEC_DMA_WR_CH GENMASK(9, 0) 24 - #define DW_PCIE_VSEC_DMA_RD_CH GENMASK(25, 16) 21 + /* Synopsys */ 22 + #define DW_PCIE_SYNOPSYS_VSEC_DMA_ID 0x6 23 + #define DW_PCIE_SYNOPSYS_VSEC_DMA_BAR GENMASK(10, 8) 24 + #define DW_PCIE_SYNOPSYS_VSEC_DMA_MAP GENMASK(2, 0) 25 + #define DW_PCIE_SYNOPSYS_VSEC_DMA_WR_CH GENMASK(9, 0) 26 + #define DW_PCIE_SYNOPSYS_VSEC_DMA_RD_CH GENMASK(25, 16) 27 + 28 + /* AMD MDB (Xilinx) specific defines */ 29 + #define PCI_DEVICE_ID_XILINX_B054 0xb054 30 + 31 + #define DW_PCIE_XILINX_MDB_VSEC_DMA_ID 0x6 32 + #define DW_PCIE_XILINX_MDB_VSEC_ID 0x20 33 + #define DW_PCIE_XILINX_MDB_VSEC_DMA_BAR GENMASK(10, 8) 34 + #define DW_PCIE_XILINX_MDB_VSEC_DMA_MAP GENMASK(2, 0) 35 + #define DW_PCIE_XILINX_MDB_VSEC_DMA_WR_CH GENMASK(9, 0) 36 + #define DW_PCIE_XILINX_MDB_VSEC_DMA_RD_CH GENMASK(25, 16) 37 + 38 + #define DW_PCIE_XILINX_MDB_DEVMEM_OFF_REG_HIGH 0xc 39 + #define DW_PCIE_XILINX_MDB_DEVMEM_OFF_REG_LOW 0x8 40 + #define DW_PCIE_XILINX_MDB_INVALID_ADDR (~0ULL) 41 + 42 + #define DW_PCIE_XILINX_MDB_LL_OFF_GAP 0x200000 43 + #define DW_PCIE_XILINX_MDB_LL_SIZE 0x800 44 + #define DW_PCIE_XILINX_MDB_DT_OFF_GAP 0x100000 45 + #define DW_PCIE_XILINX_MDB_DT_SIZE 0x800 25 46 26 47 #define DW_BLOCK(a, b, c) \ 27 48 { \ ··· 71 50 u8 irqs; 72 51 u16 wr_ch_cnt; 73 52 u16 rd_ch_cnt; 53 + u64 devmem_phys_off; 74 54 }; 75 55 76 56 static const struct dw_edma_pcie_data snps_edda_data = { ··· 112 90 .rd_ch_cnt = 2, 113 91 }; 114 92 93 + static const struct dw_edma_pcie_data xilinx_mdb_data = { 94 + /* MDB registers location */ 95 + .rg.bar = BAR_0, 96 + .rg.off = SZ_4K, /* 4 Kbytes */ 97 + .rg.sz = SZ_8K, /* 8 Kbytes */ 98 + 99 + /* Other */ 100 + .mf = EDMA_MF_HDMA_NATIVE, 101 + .irqs = 1, 102 + .wr_ch_cnt = 8, 103 + .rd_ch_cnt = 8, 104 + }; 105 + 106 + static void dw_edma_set_chan_region_offset(struct dw_edma_pcie_data *pdata, 107 + enum pci_barno bar, off_t start_off, 108 + off_t ll_off_gap, size_t ll_size, 109 + off_t dt_off_gap, size_t dt_size) 110 + { 111 + u16 wr_ch = pdata->wr_ch_cnt; 112 + u16 rd_ch = pdata->rd_ch_cnt; 113 + off_t off; 114 + u16 i; 115 + 116 + off = start_off; 117 + 118 + /* Write channel LL region */ 119 + for (i = 0; i < wr_ch; i++) { 120 + pdata->ll_wr[i].bar = bar; 121 + pdata->ll_wr[i].off = off; 122 + pdata->ll_wr[i].sz = ll_size; 123 + off += ll_off_gap; 124 + } 125 + 126 + /* Read channel LL region */ 127 + for (i = 0; i < rd_ch; i++) { 128 + pdata->ll_rd[i].bar = bar; 129 + pdata->ll_rd[i].off = off; 130 + pdata->ll_rd[i].sz = ll_size; 131 + off += ll_off_gap; 132 + } 133 + 134 + /* Write channel data region */ 135 + for (i = 0; i < wr_ch; i++) { 136 + pdata->dt_wr[i].bar = bar; 137 + pdata->dt_wr[i].off = off; 138 + pdata->dt_wr[i].sz = dt_size; 139 + off += dt_off_gap; 140 + } 141 + 142 + /* Read channel data region */ 143 + for (i = 0; i < rd_ch; i++) { 144 + pdata->dt_rd[i].bar = bar; 145 + pdata->dt_rd[i].off = off; 146 + pdata->dt_rd[i].sz = dt_size; 147 + off += dt_off_gap; 148 + } 149 + } 150 + 115 151 static int dw_edma_pcie_irq_vector(struct device *dev, unsigned int nr) 116 152 { 117 153 return pci_irq_vector(to_pci_dev(dev), nr); ··· 194 114 .pci_address = dw_edma_pcie_address, 195 115 }; 196 116 197 - static void dw_edma_pcie_get_vsec_dma_data(struct pci_dev *pdev, 198 - struct dw_edma_pcie_data *pdata) 117 + static void dw_edma_pcie_get_synopsys_dma_data(struct pci_dev *pdev, 118 + struct dw_edma_pcie_data *pdata) 199 119 { 200 120 u32 val, map; 201 121 u16 vsec; 202 122 u64 off; 203 123 204 124 vsec = pci_find_vsec_capability(pdev, PCI_VENDOR_ID_SYNOPSYS, 205 - DW_PCIE_VSEC_DMA_ID); 125 + DW_PCIE_SYNOPSYS_VSEC_DMA_ID); 206 126 if (!vsec) 207 127 return; 208 128 ··· 211 131 PCI_VNDR_HEADER_LEN(val) != 0x18) 212 132 return; 213 133 214 - pci_dbg(pdev, "Detected PCIe Vendor-Specific Extended Capability DMA\n"); 134 + pci_dbg(pdev, "Detected Synopsys PCIe Vendor-Specific Extended Capability DMA\n"); 215 135 pci_read_config_dword(pdev, vsec + 0x8, &val); 216 - map = FIELD_GET(DW_PCIE_VSEC_DMA_MAP, val); 136 + map = FIELD_GET(DW_PCIE_SYNOPSYS_VSEC_DMA_MAP, val); 217 137 if (map != EDMA_MF_EDMA_LEGACY && 218 138 map != EDMA_MF_EDMA_UNROLL && 219 139 map != EDMA_MF_HDMA_COMPAT && ··· 221 141 return; 222 142 223 143 pdata->mf = map; 224 - pdata->rg.bar = FIELD_GET(DW_PCIE_VSEC_DMA_BAR, val); 144 + pdata->rg.bar = FIELD_GET(DW_PCIE_SYNOPSYS_VSEC_DMA_BAR, val); 225 145 226 146 pci_read_config_dword(pdev, vsec + 0xc, &val); 227 147 pdata->wr_ch_cnt = min_t(u16, pdata->wr_ch_cnt, 228 - FIELD_GET(DW_PCIE_VSEC_DMA_WR_CH, val)); 148 + FIELD_GET(DW_PCIE_SYNOPSYS_VSEC_DMA_WR_CH, val)); 229 149 pdata->rd_ch_cnt = min_t(u16, pdata->rd_ch_cnt, 230 - FIELD_GET(DW_PCIE_VSEC_DMA_RD_CH, val)); 150 + FIELD_GET(DW_PCIE_SYNOPSYS_VSEC_DMA_RD_CH, val)); 231 151 232 152 pci_read_config_dword(pdev, vsec + 0x14, &val); 233 153 off = val; ··· 235 155 off <<= 32; 236 156 off |= val; 237 157 pdata->rg.off = off; 158 + } 159 + 160 + static void dw_edma_pcie_get_xilinx_dma_data(struct pci_dev *pdev, 161 + struct dw_edma_pcie_data *pdata) 162 + { 163 + u32 val, map; 164 + u16 vsec; 165 + u64 off; 166 + 167 + pdata->devmem_phys_off = DW_PCIE_XILINX_MDB_INVALID_ADDR; 168 + 169 + vsec = pci_find_vsec_capability(pdev, PCI_VENDOR_ID_XILINX, 170 + DW_PCIE_XILINX_MDB_VSEC_DMA_ID); 171 + if (!vsec) 172 + return; 173 + 174 + pci_read_config_dword(pdev, vsec + PCI_VNDR_HEADER, &val); 175 + if (PCI_VNDR_HEADER_REV(val) != 0x00 || 176 + PCI_VNDR_HEADER_LEN(val) != 0x18) 177 + return; 178 + 179 + pci_dbg(pdev, "Detected Xilinx PCIe Vendor-Specific Extended Capability DMA\n"); 180 + pci_read_config_dword(pdev, vsec + 0x8, &val); 181 + map = FIELD_GET(DW_PCIE_XILINX_MDB_VSEC_DMA_MAP, val); 182 + if (map != EDMA_MF_HDMA_NATIVE) 183 + return; 184 + 185 + pdata->mf = map; 186 + pdata->rg.bar = FIELD_GET(DW_PCIE_XILINX_MDB_VSEC_DMA_BAR, val); 187 + 188 + pci_read_config_dword(pdev, vsec + 0xc, &val); 189 + pdata->wr_ch_cnt = min(pdata->wr_ch_cnt, 190 + FIELD_GET(DW_PCIE_XILINX_MDB_VSEC_DMA_WR_CH, val)); 191 + pdata->rd_ch_cnt = min(pdata->rd_ch_cnt, 192 + FIELD_GET(DW_PCIE_XILINX_MDB_VSEC_DMA_RD_CH, val)); 193 + 194 + pci_read_config_dword(pdev, vsec + 0x14, &val); 195 + off = val; 196 + pci_read_config_dword(pdev, vsec + 0x10, &val); 197 + off <<= 32; 198 + off |= val; 199 + pdata->rg.off = off; 200 + 201 + vsec = pci_find_vsec_capability(pdev, PCI_VENDOR_ID_XILINX, 202 + DW_PCIE_XILINX_MDB_VSEC_ID); 203 + if (!vsec) 204 + return; 205 + 206 + pci_read_config_dword(pdev, 207 + vsec + DW_PCIE_XILINX_MDB_DEVMEM_OFF_REG_HIGH, 208 + &val); 209 + off = val; 210 + pci_read_config_dword(pdev, 211 + vsec + DW_PCIE_XILINX_MDB_DEVMEM_OFF_REG_LOW, 212 + &val); 213 + off <<= 32; 214 + off |= val; 215 + pdata->devmem_phys_off = off; 238 216 } 239 217 240 218 static int dw_edma_pcie_probe(struct pci_dev *pdev, ··· 322 184 * Tries to find if exists a PCIe Vendor-Specific Extended Capability 323 185 * for the DMA, if one exists, then reconfigures it. 324 186 */ 325 - dw_edma_pcie_get_vsec_dma_data(pdev, vsec_data); 187 + dw_edma_pcie_get_synopsys_dma_data(pdev, vsec_data); 188 + 189 + if (pdev->vendor == PCI_VENDOR_ID_XILINX) { 190 + dw_edma_pcie_get_xilinx_dma_data(pdev, vsec_data); 191 + 192 + /* 193 + * There is no valid address found for the LL memory 194 + * space on the device side. 195 + */ 196 + if (vsec_data->devmem_phys_off == DW_PCIE_XILINX_MDB_INVALID_ADDR) 197 + return -ENOMEM; 198 + 199 + /* 200 + * Configure the channel LL and data blocks if number of 201 + * channels enabled in VSEC capability are more than the 202 + * channels configured in xilinx_mdb_data. 203 + */ 204 + dw_edma_set_chan_region_offset(vsec_data, BAR_2, 0, 205 + DW_PCIE_XILINX_MDB_LL_OFF_GAP, 206 + DW_PCIE_XILINX_MDB_LL_SIZE, 207 + DW_PCIE_XILINX_MDB_DT_OFF_GAP, 208 + DW_PCIE_XILINX_MDB_DT_SIZE); 209 + } 326 210 327 211 /* Mapping PCI BAR regions */ 328 212 mask = BIT(vsec_data->rg.bar); ··· 527 367 528 368 static const struct pci_device_id dw_edma_pcie_id_table[] = { 529 369 { PCI_DEVICE_DATA(SYNOPSYS, EDDA, &snps_edda_data) }, 370 + { PCI_VDEVICE(XILINX, PCI_DEVICE_ID_XILINX_B054), 371 + (kernel_ulong_t)&xilinx_mdb_data }, 530 372 { } 531 373 }; 532 374 MODULE_DEVICE_TABLE(pci, dw_edma_pcie_id_table);