Add AMD MDB Endpoint and non-LL mode Support
Subsystems (3)
v8 cover Add AMD MDB Endpoint and non-LL mode Support
This series of patch support the following:
- AMD MDB Endpoint Support, as part of this patch following are added:
o AMD supported device ID and vendor ID (Xilinx)
o AMD MDB specific driver data
o AMD specific VSEC capabilities to retrieve the base of phys address of MDB side DDR
o Logic to assign the offsets to LL and data blocks if more number of channels are enabled than configured in the given pci_data struct.
- Addition of non-LL mode
o The IP supported non-LL mode functions
o Flexibility to choose non-LL mode via dma_slave_config param peripheral_config, by the client for all the vendors using HDMA IP.
o Allow IP utilization if LL mode is not available
Devendra K Verma (2):
dmaengine: dw-edma: Add AMD MDB Endpoint Support
dmaengine: dw-edma: Add non-LL mode
drivers/dma/dw-edma/dw-edma-core.c | 42 ++++++- drivers/dma/dw-edma/dw-edma-core.h | 1 + drivers/dma/dw-edma/dw-edma-pcie.c | 222 +++++++++++++++++++++++++++++++--- drivers/dma/dw-edma/dw-hdma-v0-core.c | 61 +++++++++- drivers/dma/dw-edma/dw-hdma-v0-regs.h | 1 + include/linux/dma/edma.h | 1 + 6 files changed, 302 insertions(+), 26 deletions(-)
Signature · 1 line
1.8.3.1
PATCH v8 1/2 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.
---
Changes in v8:
Changed the contant names to includer product vendor. Moved the vendor specific code to vendor specific functions.
Changes in v7:
Introduced vendor specific functions to retrieve the vsec data.
Changes in v6:
Included "sizes.h" header and used the appropriate definitions instead of constants.
Changes in v5:
Added the definitions for Xilinx specific VSEC header id, revision, and register offsets.
Corrected the error type when no physical offset found for device side memory.
Corrected the order of variables.
Changes in v4:
Configured 8 read and 8 write channels for Xilinx vendor Added checks to validate vendor ID for vendor specific vsec id.
Added Xilinx specific vendor id for vsec specific to Xilinx Added the LL and data region offsets, size as input params to function dw_edma_set_chan_region_offset().
Moved the LL and data region offsets assignment to function for Xilinx specific case.
Corrected comments.
Changes in v3:
Corrected a typo when assigning AMD (Xilinx) vsec id macro and condition check.
Changes in v2:
Reverted the devmem_phys_off type to u64. Renamed the function appropriately to suit the functionality for setting the LL & data region offsets.
Changes in v1:
Removed the pci device id from pci_ids.h file.
Added the vendor id macro as per the suggested method. Changed the type of the newly added devmem_phys_off variable. Added to logic to assign offsets for LL and data region blocks in case more number of channels are enabled than given in amd_mdb_data struct.
--- drivers/dma/dw-edma/dw-edma-pcie.c | 192 ++++++++++++++++++++++++++++++++++--- 1 file changed, 178 insertions(+), 14 deletions(-)
drivers/dma/dw-edma/dw-edma-pcie.c +178 -14
@@ -14,14 +14,35 @@#include <linux/pci-epf.h> #include <linux/msi.h> #include <linux/bitfield.h> +#include <linux/sizes.h> #include "dw-edma-core.h" -#define DW_PCIE_VSEC_DMA_ID 0x6 -#define DW_PCIE_VSEC_DMA_BAR GENMASK(10, 8) -#define DW_PCIE_VSEC_DMA_MAP GENMASK(2, 0) -#define DW_PCIE_VSEC_DMA_WR_CH GENMASK(9, 0) -#define DW_PCIE_VSEC_DMA_RD_CH GENMASK(25, 16) +/* Synopsys */ +#define DW_PCIE_SYNOPSYS_VSEC_DMA_ID 0x6 +#define DW_PCIE_SYNOPSYS_VSEC_DMA_BAR GENMASK(10, 8) +#define DW_PCIE_SYNOPSYS_VSEC_DMA_MAP GENMASK(2, 0) +#define DW_PCIE_SYNOPSYS_VSEC_DMA_WR_CH GENMASK(9, 0) +#define DW_PCIE_SYNOPSYS_VSEC_DMA_RD_CH GENMASK(25, 16) + +/* AMD MDB (Xilinx) specific defines */ +#define PCI_DEVICE_ID_XILINX_B054 0xb054 + +#define DW_PCIE_XILINX_MDB_VSEC_DMA_ID 0x6 +#define DW_PCIE_XILINX_MDB_VSEC_ID 0x20 +#define DW_PCIE_XILINX_MDB_VSEC_DMA_BAR GENMASK(10, 8) +#define DW_PCIE_XILINX_MDB_VSEC_DMA_MAP GENMASK(2, 0) +#define DW_PCIE_XILINX_MDB_VSEC_DMA_WR_CH GENMASK(9, 0) +#define DW_PCIE_XILINX_MDB_VSEC_DMA_RD_CH GENMASK(25, 16) + +#define DW_PCIE_XILINX_MDB_DEVMEM_OFF_REG_HIGH 0xc +#define DW_PCIE_XILINX_MDB_DEVMEM_OFF_REG_LOW 0x8 +#define DW_PCIE_XILINX_MDB_INVALID_ADDR (~0ULL) + +#define DW_PCIE_XILINX_MDB_LL_OFF_GAP 0x200000 +#define DW_PCIE_XILINX_MDB_LL_SIZE 0x800 +#define DW_PCIE_XILINX_MDB_DT_OFF_GAP 0x100000 +#define DW_PCIE_XILINX_MDB_DT_SIZE 0x800#define DW_BLOCK (a, b, c) \ { \
@@ -50,6 +71,7 @@ struct dw_edma_pcie_data {u8 irqs;u16 wr_ch_cnt;u16 rd_ch_cnt; +u64 devmem_phys_off; };static const struct dw_edma_pcie_data snps_edda_data = {
@@ -90,6 +112,64 @@ struct dw_edma_pcie_data { .rd_ch_cnt = 2, }; +static const struct dw_edma_pcie_data xilinx_mdb_data = { +/* MDB registers location */ + .rg.bar =BAR_0 , + .rg.off =SZ_4K ,/* 4 Kbytes */ + .rg.sz =SZ_8K ,/* 8 Kbytes */ + +/* Other */ + .mf =EDMA_MF_HDMA_NATIVE , + .irqs =1 , + .wr_ch_cnt =8 , + .rd_ch_cnt =8 , +}; + +static void dw_edma_set_chan_region_offset (struct dw_edma_pcie_data *pdata, +enum pci_barno bar,off_t start_off, +off_t ll_off_gap,size_t ll_size, +off_t dt_off_gap,size_t dt_size) +{ +u16 wr_ch = pdata->wr_ch_cnt; +u16 rd_ch = pdata->rd_ch_cnt; +off_t off; +u16 i; + + off = start_off; + +/* Write channel LL region */ +for (i =0 ; i < wr_ch; i++) { + pdata->ll_wr[i].bar = bar; + pdata->ll_wr[i].off = off; + pdata->ll_wr[i].sz = ll_size; + off += ll_off_gap; + } + +/* Read channel LL region */ +for (i =0 ; i < rd_ch; i++) { + pdata->ll_rd[i].bar = bar; + pdata->ll_rd[i].off = off; + pdata->ll_rd[i].sz = ll_size; + off += ll_off_gap; + } + +/* Write channel data region */ +for (i =0 ; i < wr_ch; i++) { + pdata->dt_wr[i].bar = bar; + pdata->dt_wr[i].off = off; + pdata->dt_wr[i].sz = dt_size; + off += dt_off_gap; + } + +/* Read channel data region */ +for (i =0 ; i < rd_ch; i++) { + pdata->dt_rd[i].bar = bar; + pdata->dt_rd[i].off = off; + pdata->dt_rd[i].sz = dt_size; + off += dt_off_gap; + } +} +static int dw_edma_pcie_irq_vector (struct device *dev,unsigned int nr) {return pci_irq_vector (to_pci_dev (dev), nr);
@@ -114,15 +194,15 @@ static u64 dw_edma_pcie_address(struct device *dev, phys_addr_t cpu_addr) .pci_address = dw_edma_pcie_address, }; -static void dw_edma_pcie_get_vsec_dma_data (struct pci_dev *pdev, -struct dw_edma_pcie_data *pdata) +static void dw_edma_pcie_get_synopsys_dma_data (struct pci_dev *pdev, +struct dw_edma_pcie_data *pdata) {u32 val, map;u16 vsec;u64 off; vsec =pci_find_vsec_capability (pdev,PCI_VENDOR_ID_SYNOPSYS , -DW_PCIE_VSEC_DMA_ID ); +DW_PCIE_SYNOPSYS_VSEC_DMA_ID );if (!vsec)return ;
@@ -131,9 +211,9 @@ static void dw_edma_pcie_get_vsec_dma_data(struct pci_dev *pdev, PCI_VNDR_HEADER_LEN(val) != 0x18)return ; -pci_dbg (pdev,"Detected PCIe Vendor-Specific Extended Capability DMA\n" ); +pci_dbg (pdev,"Detected Synopsys PCIe Vendor-Specific Extended Capability DMA\n" );pci_read_config_dword (pdev, vsec +0x8 , &val); - map =FIELD_GET (DW_PCIE_VSEC_DMA_MAP , val); + map =FIELD_GET (DW_PCIE_SYNOPSYS_VSEC_DMA_MAP , val); if (map != EDMA_MF_EDMA_LEGACY && map != EDMA_MF_EDMA_UNROLL && map != EDMA_MF_HDMA_COMPAT &&
@@ -141,13 +221,13 @@ static void dw_edma_pcie_get_vsec_dma_data(struct pci_dev *pdev,return ; pdata->mf = map; - pdata->rg.bar =FIELD_GET (DW_PCIE_VSEC_DMA_BAR , val); + pdata->rg.bar =FIELD_GET (DW_PCIE_SYNOPSYS_VSEC_DMA_BAR , val);pci_read_config_dword (pdev, vsec +0xc , &val); pdata->wr_ch_cnt =min_t (u16, pdata->wr_ch_cnt, -FIELD_GET (DW_PCIE_VSEC_DMA_WR_CH , val)); +FIELD_GET (DW_PCIE_SYNOPSYS_VSEC_DMA_WR_CH , val)); pdata->rd_ch_cnt =min_t (u16, pdata->rd_ch_cnt, -FIELD_GET (DW_PCIE_VSEC_DMA_RD_CH , val)); +FIELD_GET (DW_PCIE_SYNOPSYS_VSEC_DMA_RD_CH , val));pci_read_config_dword (pdev, vsec +0x14 , &val); off = val;
@@ -157,6 +237,67 @@ static void dw_edma_pcie_get_vsec_dma_data(struct pci_dev *pdev, pdata->rg.off = off; } +static void dw_edma_pcie_get_xilinx_dma_data (struct pci_dev *pdev, +struct dw_edma_pcie_data *pdata) +{ +u32 val, map; +u16 vsec; +u64 off; + + pdata->devmem_phys_off =DW_PCIE_XILINX_MDB_INVALID_ADDR ; + + vsec =pci_find_vsec_capability (pdev,PCI_VENDOR_ID_XILINX , +DW_PCIE_XILINX_MDB_VSEC_DMA_ID ); +if (!vsec) +return ; + +pci_read_config_dword (pdev, vsec +PCI_VNDR_HEADER , &val); +if (PCI_VNDR_HEADER_REV (val) !=0x00 || +PCI_VNDR_HEADER_LEN (val) !=0x18 ) +return ; + +pci_dbg (pdev,"Detected Xilinx PCIe Vendor-Specific Extended Capability DMA\n" ); +pci_read_config_dword (pdev, vsec +0x8 , &val); + map =FIELD_GET (DW_PCIE_XILINX_MDB_VSEC_DMA_MAP , val); +if (map !=EDMA_MF_EDMA_LEGACY && + map !=EDMA_MF_EDMA_UNROLL && + map !=EDMA_MF_HDMA_COMPAT && + map !=EDMA_MF_HDMA_NATIVE ) +return ; + + pdata->mf = map; + pdata->rg.bar =FIELD_GET (DW_PCIE_XILINX_MDB_VSEC_DMA_BAR , val); + +pci_read_config_dword (pdev, vsec +0xc , &val); + pdata->wr_ch_cnt =min_t (u16, pdata->wr_ch_cnt, +FIELD_GET (DW_PCIE_XILINX_MDB_VSEC_DMA_WR_CH , val)); + pdata->rd_ch_cnt =min_t (u16, pdata->rd_ch_cnt, +FIELD_GET (DW_PCIE_XILINX_MDB_VSEC_DMA_RD_CH , val)); + +pci_read_config_dword (pdev, vsec +0x14 , &val); + off = val; +pci_read_config_dword (pdev, vsec +0x10 , &val); + off <<=32 ; + off |= val; + pdata->rg.off = off; + + vsec =pci_find_vsec_capability (pdev,PCI_VENDOR_ID_XILINX , +DW_PCIE_XILINX_MDB_VSEC_ID ); +if (!vsec) +return ; + +pci_read_config_dword (pdev, + vsec +DW_PCIE_XILINX_MDB_DEVMEM_OFF_REG_HIGH , + &val); + off = val; +pci_read_config_dword (pdev, + vsec +DW_PCIE_XILINX_MDB_DEVMEM_OFF_REG_LOW , + &val); + off <<=32 ; + off |= val; + pdata->devmem_phys_off = off; +} +static int dw_edma_pcie_probe (struct pci_dev *pdev,const struct pci_device_id *pid) {
@@ -184,7 +325,28 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,* Tries to find if exists a PCIe Vendor-Specific Extended Capability * for the DMA, if one exists, then reconfigures it. */ -dw_edma_pcie_get_vsec_dma_data (pdev, vsec_data); +dw_edma_pcie_get_synopsys_dma_data (pdev, vsec_data); +dw_edma_pcie_get_xilinx_dma_data (pdev, vsec_data); + +if (pdev->vendor ==PCI_VENDOR_ID_XILINX ) { +/* +* There is no valid address found for the LL memory +* space on the device side. +*/ +if (vsec_data->devmem_phys_off ==DW_PCIE_XILINX_MDB_INVALID_ADDR ) +return -ENOMEM ; + +/* +* Configure the channel LL and data blocks if number of +* channels enabled in VSEC capability are more than the +* channels configured in xilinx_mdb_data. +*/ +dw_edma_set_chan_region_offset (vsec_data,BAR_2 ,0 , +DW_PCIE_XILINX_MDB_LL_OFF_GAP , +DW_PCIE_XILINX_MDB_LL_SIZE , +DW_PCIE_XILINX_MDB_DT_OFF_GAP , +DW_PCIE_XILINX_MDB_DT_SIZE ); + }/* Mapping PCI BAR regions */ mask =BIT (vsec_data->rg.bar);
@@ -367,6 +529,8 @@ static void dw_edma_pcie_remove(struct pci_dev *pdev)static const struct pci_device_id dw_edma_pcie_id_table[] = { {PCI_DEVICE_DATA (SYNOPSYS ,EDDA , &snps_edda_data) }, + {PCI_VDEVICE (XILINX ,PCI_DEVICE_ID_XILINX_B054 ), + (kernel_ulong_t)&xilinx_mdb_data }, { } };MODULE_DEVICE_TABLE (pci, dw_edma_pcie_id_table);
Signature · 1 line
1.8.3.1
Re: [PATCH v8 1/2] dmaengine: dw-edma: Add AMD MDB Endpoint Support
Quoted 72 lines · Devendra K Verma
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 <[email protected]>---
Changes in v8:
Changed the contant names to includer product vendor. Moved the vendor specific code to vendor specific functions.Changes in v7:
Introduced vendor specific functions to retrieve the vsec data.Changes in v6:
Included "sizes.h" header and used the appropriate definitions instead of constants.Changes in v5:
Added the definitions for Xilinx specific VSEC header id, revision, and register offsets.
Corrected the error type when no physical offset found for device side memory.
Corrected the order of variables.Changes in v4:
Configured 8 read and 8 write channels for Xilinx vendor Added checks to validate vendor ID for vendor specific vsec id.
Added Xilinx specific vendor id for vsec specific to Xilinx Added the LL and data region offsets, size as input params to functiondw_edma_set_chan_region_offset().
Moved the LL and data region offsets assignment to function for Xilinx specific case.
Corrected comments.Changes in v3:
Corrected a typo when assigning AMD (Xilinx) vsec id macro and condition check.Changes in v2:
Reverted thedevmem_phys_offtype to u64. Renamed the function appropriately to suit the functionality for setting the LL & data region offsets.Changes in v1:
Removed the pci device id frompci_ids.hfile.
Added the vendor id macro as per the suggested method. Changed the type of the newly addeddevmem_phys_offvariable. Added to logic to assign offsets for LL and data region blocks in case more number of channels are enabled than given inamd_mdb_datastruct.--- drivers/dma/dw-edma/dw-edma-pcie.c | 192 ++++++++++++++++++++++++++++++++++--- 1 file changed, 178 insertions(+), 14 deletions(-)drivers/dma/dw-edma/dw-edma-pcie.c +1
-1@@ -14,14 +14,35 @@#include <linux/pci-epf.h> #include <linux/msi.h> #include <linux/bitfield.h> +#include <linux/sizes.h> #include "dw-edma-core.h" -#define DW_PCIE_VSEC_DMA_ID 0x6
drivers/dma/dw-edma/dw-edma-pcie.c line 26
Quoted 10 lines
drivers/dma/dw-edma/dw-edma-pcie.c +6
-4-#define DW_PCIE_VSEC_DMA_BAR GENMASK(10, 8) -#define DW_PCIE_VSEC_DMA_MAP GENMASK(2, 0) -#define DW_PCIE_VSEC_DMA_WR_CH GENMASK(9, 0) -#define DW_PCIE_VSEC_DMA_RD_CH GENMASK(25, 16) +/* Synopsys */ +#define DW_PCIE_SYNOPSYS_VSEC_DMA_ID 0x6 +#define DW_PCIE_SYNOPSYS_VSEC_DMA_BAR GENMASK(10, 8) +#define DW_PCIE_SYNOPSYS_VSEC_DMA_MAP GENMASK(2, 0) +#define DW_PCIE_SYNOPSYS_VSEC_DMA_WR_CH GENMASK(9, 0) +#define DW_PCIE_SYNOPSYS_VSEC_DMA_RD_CH GENMASK(25, 16)
Sorry, jump into at v8.
According to my understand 'DW' means 'Synopsys'.
drivers/dma/dw-edma/dw-edma-pcie.c line 36
Quoted 10 lines
drivers/dma/dw-edma/dw-edma-pcie.c +10
-0+ +/* AMD MDB (Xilinx) specific defines */ +#define PCI_DEVICE_ID_XILINX_B054 0xb054 + +#define DW_PCIE_XILINX_MDB_VSEC_DMA_ID 0x6 +#define DW_PCIE_XILINX_MDB_VSEC_ID 0x20 +#define DW_PCIE_XILINX_MDB_VSEC_DMA_BAR GENMASK(10, 8) +#define DW_PCIE_XILINX_MDB_VSEC_DMA_MAP GENMASK(2, 0) +#define DW_PCIE_XILINX_MDB_VSEC_DMA_WR_CH GENMASK(9, 0) +#define DW_PCIE_XILINX_MDB_VSEC_DMA_RD_CH GENMASK(25, 16)
These defination is the same. Need redefine again
drivers/dma/dw-edma/dw-edma-pcie.c line 40
Quoted 4 lines
drivers/dma/dw-edma/dw-edma-pcie.c +4
-0+ +#define DW_PCIE_XILINX_MDB_DEVMEM_OFF_REG_HIGH 0xc +#define DW_PCIE_XILINX_MDB_DEVMEM_OFF_REG_LOW 0x8 +#define DW_PCIE_XILINX_MDB_INVALID_ADDR (~0ULL)
I think XILINX_PCIE_MDB_DEVMEM_OFF_REG_HIGH
Quoted 116 lines
drivers/dma/dw-edma/dw-edma-pcie.c +69
-5+ +#define DW_PCIE_XILINX_MDB_LL_OFF_GAP 0x200000 +#define DW_PCIE_XILINX_MDB_LL_SIZE 0x800 +#define DW_PCIE_XILINX_MDB_DT_OFF_GAP 0x100000 +#define DW_PCIE_XILINX_MDB_DT_SIZE 0x800#define DW_BLOCK (a, b, c) \ { \@@ -50,6 +71,7 @@ struct dw_edma_pcie_data {u8 irqs;u16 wr_ch_cnt;u16 rd_ch_cnt; +u64 devmem_phys_off; };static const struct dw_edma_pcie_data snps_edda_data = {@@ -90,6 +112,64 @@ struct dw_edma_pcie_data { .rd_ch_cnt = 2, }; +static const struct dw_edma_pcie_data xilinx_mdb_data = { +/* MDB registers location */ + .rg.bar =BAR_0 , + .rg.off =SZ_4K ,/* 4 Kbytes */ + .rg.sz =SZ_8K ,/* 8 Kbytes */ + +/* Other */ + .mf =EDMA_MF_HDMA_NATIVE , + .irqs =1 , + .wr_ch_cnt =8 , + .rd_ch_cnt =8 , +}; + +static void dw_edma_set_chan_region_offset (struct dw_edma_pcie_data *pdata, +enum pci_barno bar,off_t start_off, +off_t ll_off_gap,size_t ll_size, +off_t dt_off_gap,size_t dt_size) +{ +u16 wr_ch = pdata->wr_ch_cnt; +u16 rd_ch = pdata->rd_ch_cnt; +off_t off; +u16 i; + + off = start_off; + +/* Write channel LL region */ +for (i =0 ; i < wr_ch; i++) { + pdata->ll_wr[i].bar = bar; + pdata->ll_wr[i].off = off; + pdata->ll_wr[i].sz = ll_size; + off += ll_off_gap; + } + +/* Read channel LL region */ +for (i =0 ; i < rd_ch; i++) { + pdata->ll_rd[i].bar = bar; + pdata->ll_rd[i].off = off; + pdata->ll_rd[i].sz = ll_size; + off += ll_off_gap; + } + +/* Write channel data region */ +for (i =0 ; i < wr_ch; i++) { + pdata->dt_wr[i].bar = bar; + pdata->dt_wr[i].off = off; + pdata->dt_wr[i].sz = dt_size; + off += dt_off_gap; + } + +/* Read channel data region */ +for (i =0 ; i < rd_ch; i++) { + pdata->dt_rd[i].bar = bar; + pdata->dt_rd[i].off = off; + pdata->dt_rd[i].sz = dt_size; + off += dt_off_gap; + } +} +static int dw_edma_pcie_irq_vector (struct device *dev,unsigned int nr) {return pci_irq_vector (to_pci_dev (dev), nr);@@ -114,15 +194,15 @@ static u64 dw_edma_pcie_address(struct device *dev, phys_addr_t cpu_addr) .pci_address = dw_edma_pcie_address, }; -static void dw_edma_pcie_get_vsec_dma_data (struct pci_dev *pdev, -struct dw_edma_pcie_data *pdata) +static void dw_edma_pcie_get_synopsys_dma_data (struct pci_dev *pdev, +struct dw_edma_pcie_data *pdata) {u32 val, map;u16 vsec;u64 off; vsec =pci_find_vsec_capability (pdev,PCI_VENDOR_ID_SYNOPSYS , -DW_PCIE_VSEC_DMA_ID ); +DW_PCIE_SYNOPSYS_VSEC_DMA_ID );if (!vsec)return ;@@ -131,9 +211,9 @@ static void dw_edma_pcie_get_vsec_dma_data(struct pci_dev *pdev, PCI_VNDR_HEADER_LEN(val) != 0x18)return ; -pci_dbg (pdev,"Detected PCIe Vendor-Specific Extended Capability DMA\n" ); +pci_dbg (pdev,"Detected Synopsys PCIe Vendor-Specific Extended Capability DMA\n" );pci_read_config_dword (pdev, vsec +0x8 , &val); - map =FIELD_GET (DW_PCIE_VSEC_DMA_MAP , val); + map =FIELD_GET (DW_PCIE_SYNOPSYS_VSEC_DMA_MAP , val); if (map != EDMA_MF_EDMA_LEGACY && map != EDMA_MF_EDMA_UNROLL && map != EDMA_MF_HDMA_COMPAT &&@@ -141,13 +221,13 @@ static void dw_edma_pcie_get_vsec_dma_data(struct pci_dev *pdev,return ; pdata->mf = map;
drivers/dma/dw-edma/dw-edma-pcie.c static void dw_edma_pcie_get_vsec_dma_data(struct pci_dev *pdev, · line 230
Quoted 10 lines
drivers/dma/dw-edma/dw-edma-pcie.c +3
-3- pdata->rg.bar =FIELD_GET (DW_PCIE_VSEC_DMA_BAR , val); + pdata->rg.bar =FIELD_GET (DW_PCIE_SYNOPSYS_VSEC_DMA_BAR , val);pci_read_config_dword (pdev, vsec +0xc , &val); pdata->wr_ch_cnt =min_t (u16, pdata->wr_ch_cnt, -FIELD_GET (DW_PCIE_VSEC_DMA_WR_CH , val)); +FIELD_GET (DW_PCIE_SYNOPSYS_VSEC_DMA_WR_CH , val)); pdata->rd_ch_cnt =min_t (u16, pdata->rd_ch_cnt, -FIELD_GET (DW_PCIE_VSEC_DMA_RD_CH , val)); +FIELD_GET (DW_PCIE_SYNOPSYS_VSEC_DMA_RD_CH , val));
If you don't change macro name, these change is not necessary. If really need change macro name, make change macro name as sperated patch.
Quoted 72 lines
drivers/dma/dw-edma/dw-edma-pcie.c +61
-0pci_read_config_dword (pdev, vsec +0x14 , &val); off = val;@@ -157,6 +237,67 @@ static void dw_edma_pcie_get_vsec_dma_data(struct pci_dev *pdev, pdata->rg.off = off; } +static void dw_edma_pcie_get_xilinx_dma_data (struct pci_dev *pdev, +struct dw_edma_pcie_data *pdata) +{ +u32 val, map; +u16 vsec; +u64 off; + + pdata->devmem_phys_off =DW_PCIE_XILINX_MDB_INVALID_ADDR ; + + vsec =pci_find_vsec_capability (pdev,PCI_VENDOR_ID_XILINX , +DW_PCIE_XILINX_MDB_VSEC_DMA_ID ); +if (!vsec) +return ; + +pci_read_config_dword (pdev, vsec +PCI_VNDR_HEADER , &val); +if (PCI_VNDR_HEADER_REV (val) !=0x00 || +PCI_VNDR_HEADER_LEN (val) !=0x18 ) +return ; + +pci_dbg (pdev,"Detected Xilinx PCIe Vendor-Specific Extended Capability DMA\n" ); +pci_read_config_dword (pdev, vsec +0x8 , &val); + map =FIELD_GET (DW_PCIE_XILINX_MDB_VSEC_DMA_MAP , val); +if (map !=EDMA_MF_EDMA_LEGACY && + map !=EDMA_MF_EDMA_UNROLL && + map !=EDMA_MF_HDMA_COMPAT && + map !=EDMA_MF_HDMA_NATIVE ) +return ; + + pdata->mf = map; + pdata->rg.bar =FIELD_GET (DW_PCIE_XILINX_MDB_VSEC_DMA_BAR , val); + +pci_read_config_dword (pdev, vsec +0xc , &val); + pdata->wr_ch_cnt =min_t (u16, pdata->wr_ch_cnt, +FIELD_GET (DW_PCIE_XILINX_MDB_VSEC_DMA_WR_CH , val)); + pdata->rd_ch_cnt =min_t (u16, pdata->rd_ch_cnt, +FIELD_GET (DW_PCIE_XILINX_MDB_VSEC_DMA_RD_CH , val)); + +pci_read_config_dword (pdev, vsec +0x14 , &val); + off = val; +pci_read_config_dword (pdev, vsec +0x10 , &val); + off <<=32 ; + off |= val; + pdata->rg.off = off; + + vsec =pci_find_vsec_capability (pdev,PCI_VENDOR_ID_XILINX , +DW_PCIE_XILINX_MDB_VSEC_ID ); +if (!vsec) +return ; + +pci_read_config_dword (pdev, + vsec +DW_PCIE_XILINX_MDB_DEVMEM_OFF_REG_HIGH , + &val); + off = val; +pci_read_config_dword (pdev, + vsec +DW_PCIE_XILINX_MDB_DEVMEM_OFF_REG_LOW , + &val); + off <<=32 ; + off |= val; + pdata->devmem_phys_off = off; +} +static int dw_edma_pcie_probe (struct pci_dev *pdev,const struct pci_device_id *pid) {
drivers/dma/dw-edma/dw-edma-pcie.c static int dw_edma_pcie_probe(struct pci_dev *pdev, · line 331
Quoted 8 lines
drivers/dma/dw-edma/dw-edma-pcie.c +4
-1@@ -184,7 +325,28 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,* Tries to find if exists a PCIe Vendor-Specific Extended Capability * for the DMA, if one exists, then reconfigures it. */ -dw_edma_pcie_get_vsec_dma_data (pdev, vsec_data); +dw_edma_pcie_get_synopsys_dma_data (pdev, vsec_data); +dw_edma_pcie_get_xilinx_dma_data (pdev, vsec_data); + +if (pdev->vendor ==PCI_VENDOR_ID_XILINX ) {
dw_edma_pcie_get_xilinx_dma_data() should be here.
Frank
Quoted 33 lines
drivers/dma/dw-edma/dw-edma-pcie.c +20
-1+/* +* There is no valid address found for the LL memory +* space on the device side. +*/ +if (vsec_data->devmem_phys_off ==DW_PCIE_XILINX_MDB_INVALID_ADDR ) +return -ENOMEM ; + +/* +* Configure the channel LL and data blocks if number of +* channels enabled in VSEC capability are more than the +* channels configured in xilinx_mdb_data. +*/ +dw_edma_set_chan_region_offset (vsec_data,BAR_2 ,0 , +DW_PCIE_XILINX_MDB_LL_OFF_GAP , +DW_PCIE_XILINX_MDB_LL_SIZE , +DW_PCIE_XILINX_MDB_DT_OFF_GAP , +DW_PCIE_XILINX_MDB_DT_SIZE ); + }/* Mapping PCI BAR regions */ mask =BIT (vsec_data->rg.bar);@@ -367,6 +529,8 @@ static void dw_edma_pcie_remove(struct pci_dev *pdev)static const struct pci_device_id dw_edma_pcie_id_table[] = { {PCI_DEVICE_DATA (SYNOPSYS ,EDDA , &snps_edda_data) }, + {PCI_VDEVICE (XILINX ,PCI_DEVICE_ID_XILINX_B054 ), + (kernel_ulong_t)&xilinx_mdb_data }, { } };MODULE_DEVICE_TABLE (pci, dw_edma_pcie_id_table); --1.8.3.1
RE: [PATCH v8 1/2] dmaengine: dw-edma: Add AMD MDB Endpoint Support
[AMD Official Use Only - AMD Internal Distribution Only]
Hi Frank
Please check my comments inline.
Regards,
Devendra
Quoted 85 lines
-----Original Message-----
From: Frank Li <[email protected]>
Sent: Thursday, January 15, 2026 9:51 PM
To: Verma, Devendra <[email protected]>
Cc: [email protected]; [email protected]; [email protected]; [email protected]; [email protected]; linux- [email protected]; Simek, Michal <[email protected]>
Subject: Re: [PATCH v8 1/2] dmaengine: dw-edma: Add AMD MDB Endpoint SupportCaution: This message originated from an External Source. Use proper caution when opening attachments, clicking links, or responding.
Quoted 70 lines · Devendra K Verma
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 <[email protected]>---
Changes in v8:
Changed the contant names to includer product vendor. Moved the vendor specific code to vendor specific functions.Changes in v7:
Introduced vendor specific functions to retrieve the vsec data.Changes in v6:
Included "sizes.h" header and used the appropriate definitions instead of constants.Changes in v5:
Added the definitions for Xilinx specific VSEC header id, revision, and register offsets.
Corrected the error type when no physical offset found for device side memory.
Corrected the order of variables.Changes in v4:
Configured 8 read and 8 write channels for Xilinx vendor Added checks to validate vendor ID for vendor specific vsec id.
Added Xilinx specific vendor id for vsec specific to Xilinx Added the LL and data region offsets, size as input params to functiondw_edma_set_chan_region_offset().
Moved the LL and data region offsets assignment to function for Xilinx specific case.
Corrected comments.Changes in v3:
Corrected a typo when assigning AMD (Xilinx) vsec id macro and condition check.Changes in v2:
Reverted thedevmem_phys_offtype to u64.
Renamed the function appropriately to suit the functionality for setting the LL & data region offsets.Changes in v1:
Removed the pci device id frompci_ids.hfile.
Added the vendor id macro as per the suggested method. Changed the type of the newly addeddevmem_phys_offvariable. Added to logic to assign offsets for LL and data region blocks in case more number of channels are enabled than given inamd_mdb_datastruct.--- drivers/dma/dw-edma/dw-edma-pcie.c | 192 ++++++++++++++++++++++++++++++++++--- 1 file changed, 178 insertions(+), 14 deletions(-)drivers/dma/dw-edma/dw-edma-pcie.c +1
-0@@ -14,14 +14,35 @@#include <linux/pci-epf.h> #include <linux/msi.h> #include <linux/bitfield.h> +#include <linux/sizes.h> #include "dw-edma-core.h"
Quoted 15 lines
drivers/dma/dw-edma/dw-edma-pcie.c line 26
Quoted 11 lines
drivers/dma/dw-edma/dw-edma-pcie.c +6
-5-#define DW_PCIE_VSEC_DMA_ID 0x6 -#define DW_PCIE_VSEC_DMA_BAR GENMASK(10, 8) -#define DW_PCIE_VSEC_DMA_MAP GENMASK(2, 0) -#define DW_PCIE_VSEC_DMA_WR_CH GENMASK(9, 0) -#define DW_PCIE_VSEC_DMA_RD_CH GENMASK(25, 16) +/* Synopsys */ +#define DW_PCIE_SYNOPSYS_VSEC_DMA_ID 0x6 +#define DW_PCIE_SYNOPSYS_VSEC_DMA_BAR GENMASK(10, 8) +#define DW_PCIE_SYNOPSYS_VSEC_DMA_MAP GENMASK(2, 0) +#define DW_PCIE_SYNOPSYS_VSEC_DMA_WR_CH GENMASK(9, 0) +#define DW_PCIE_SYNOPSYS_VSEC_DMA_RD_CH GENMASK(25, 16)Sorry, jump into at v8.
According to my understand 'DW' means 'Synopsys'.
Yes, DW means Designware representing Synopsys here.
For the sake of clarity, a distinction was required to separate the names of macros having the similar purpose for other IP, Xilinx in this case. Otherwise, it is causing confusion which macros to use for which vendor. This also helps in future if any of the vendors try to retrieve a new or different VSEC IDs then all they need is to define macros which clearly show the association with the vendor, thus eliminating the confusion.
Quoted 4 lines
Quoted 4 lines
drivers/dma/dw-edma/dw-edma-pcie.c +4
-0+ +/* AMD MDB (Xilinx) specific defines */ +#define PCI_DEVICE_ID_XILINX_B054 0xb054 +
Quoted 9 lines
drivers/dma/dw-edma/dw-edma-pcie.c line 36
Quoted 6 lines
drivers/dma/dw-edma/dw-edma-pcie.c +6
-0+#define DW_PCIE_XILINX_MDB_VSEC_DMA_ID 0x6 +#define DW_PCIE_XILINX_MDB_VSEC_ID 0x20 +#define DW_PCIE_XILINX_MDB_VSEC_DMA_BAR GENMASK(10, 8) +#define DW_PCIE_XILINX_MDB_VSEC_DMA_MAP GENMASK(2, 0) +#define DW_PCIE_XILINX_MDB_VSEC_DMA_WR_CH GENMASK(9, 0) +#define DW_PCIE_XILINX_MDB_VSEC_DMA_RD_CH GENMASK(25, 16)These defination is the same. Need redefine again
It is the similar case as explained for the previous comment. Please check.
Quoted 132 lines
drivers/dma/dw-edma/dw-edma-pcie.c line 40
Quoted 4 lines
drivers/dma/dw-edma/dw-edma-pcie.c +4
-0+ +#define DW_PCIE_XILINX_MDB_DEVMEM_OFF_REG_HIGH 0xc +#define DW_PCIE_XILINX_MDB_DEVMEM_OFF_REG_LOW 0x8 +#define DW_PCIE_XILINX_MDB_INVALID_ADDR (~0ULL)I think
XILINX_PCIE_MDB_DEVMEM_OFF_REG_HIGHQuoted 24 lines
drivers/dma/dw-edma/dw-edma-pcie.c +11
-0+ +#define DW_PCIE_XILINX_MDB_LL_OFF_GAP 0x200000 +#define DW_PCIE_XILINX_MDB_LL_SIZE 0x800 +#define DW_PCIE_XILINX_MDB_DT_OFF_GAP 0x100000 +#define DW_PCIE_XILINX_MDB_DT_SIZE 0x800#define DW_BLOCK (a, b, c) \ { \@@ -50,6 +71,7 @@ struct dw_edma_pcie_data {u8 irqs;u16 wr_ch_cnt;u16 rd_ch_cnt; +u64 devmem_phys_off; }; static const struct dw_edma_pcie_data snps_edda_data = { @@ -90,6 +112,64 @@ struct dw_edma_pcie_data { .rd_ch_cnt =2 , }; +static const struct dw_edma_pcie_data xilinx_mdb_data = { + /* MDB registers location */ + .rg.bar = BAR_0, + .rg.off = SZ_4K, /* 4 Kbytes */drivers/dma/dw-edma/dw-edma-pcie.c struct dw_edma_pcie_data {
Quoted 10 lines
drivers/dma/dw-edma/dw-edma-pcie.c +10
-0+ .rg.sz = SZ_8K, /* 8 Kbytes */ + +/* Other */ + .mf = EDMA_MF_HDMA_NATIVE, + .irqs = 1, + .wr_ch_cnt = 8, + .rd_ch_cnt = 8, +}; + +static void dw_edma_set_chan_region_offset(struct dw_edma_pcie_data*pdata,
Quoted 47 lines
drivers/dma/dw-edma/dw-edma-pcie.c +44
-0+ enum pci_barno bar, off_t start_off, + off_t ll_off_gap, size_t ll_size, + off_t dt_off_gap, size_t +dt_size) { + u16 wr_ch = pdata->wr_ch_cnt; +u16 rd_ch = pdata->rd_ch_cnt; +off_t off; +u16 i; + + off = start_off; + +/* Write channel LL region */ +for (i =0 ; i < wr_ch; i++) { + pdata->ll_wr[i].bar = bar; + pdata->ll_wr[i].off = off; + pdata->ll_wr[i].sz = ll_size; + off += ll_off_gap; + } + +/* Read channel LL region */ +for (i =0 ; i < rd_ch; i++) { + pdata->ll_rd[i].bar = bar; + pdata->ll_rd[i].off = off; + pdata->ll_rd[i].sz = ll_size; + off += ll_off_gap; + } + +/* Write channel data region */ +for (i =0 ; i < wr_ch; i++) { + pdata->dt_wr[i].bar = bar; + pdata->dt_wr[i].off = off; + pdata->dt_wr[i].sz = dt_size; + off += dt_off_gap; + } + +/* Read channel data region */ +for (i =0 ; i < rd_ch; i++) { + pdata->dt_rd[i].bar = bar; + pdata->dt_rd[i].off = off; + pdata->dt_rd[i].sz = dt_size; + off += dt_off_gap; + } +} + static int dw_edma_pcie_irq_vector(struct device *dev, unsigned intnr) { return pci_irq_vector(to_pci_dev(dev), nr); @@ -114,15 +194,15Quoted 1 line
@@ static u64 dw_edma_pcie_address(struct device *dev,
phys_addr_t
cpu_addr)drivers/dma/dw-edma/dw-edma-pcie.c static void
Quoted 19 lines
.pci_address = dw_edma_pcie_address, };drivers/dma/dw-edma/dw-edma-pcie.c +4
-3-static void dw_edma_pcie_get_vsec_dma_data (struct pci_dev *pdev, -struct dw_edma_pcie_data *pdata) +static void dw_edma_pcie_get_synopsys_dma_data (struct pci_dev *pdev, +struct dw_edma_pcie_data +*pdata) {u32 val, map;u16 vsec;u64 off; vsec =pci_find_vsec_capability (pdev,PCI_VENDOR_ID_SYNOPSYS , -DW_PCIE_VSEC_DMA_ID ); +DW_PCIE_SYNOPSYS_VSEC_DMA_ID );if (!vsec)return ;@@ -131,9 +211,9 @@ static voiddw_edma_pcie_get_vsec_dma_data(struct
pci_dev*pdev,drivers/dma/dw-edma/dw-edma-pcie.c static void dw_edma_pcie_get_vsec_dma_data(struct pci_dev *pdev,
Quoted 4 lines
drivers/dma/dw-edma/dw-edma-pcie.c +0
-1PCI_VNDR_HEADER_LEN(val) != 0x18)return ; - pci_dbg(pdev, "Detected PCIe Vendor-Specific Extended CapabilityDMA\n");
drivers/dma/dw-edma/dw-edma-pcie.c static void dw_edma_pcie_get_vsec_dma_data(struct pci_dev *pdev,
Quoted 8 lines
drivers/dma/dw-edma/dw-edma-pcie.c +3
-1+ pci_dbg(pdev, "Detected Synopsys PCIe Vendor-Specific Extended + Capability DMA\n"); pci_read_config_dword(pdev, vsec + 0x8, &val); - map =FIELD_GET (DW_PCIE_VSEC_DMA_MAP , val); + map =FIELD_GET (DW_PCIE_SYNOPSYS_VSEC_DMA_MAP , val); if (map != EDMA_MF_EDMA_LEGACY && map != EDMA_MF_EDMA_UNROLL && map != EDMA_MF_HDMA_COMPAT && @@ -141,13 +221,13 @@static
Quoted 7 lines
void dw_edma_pcie_get_vsec_dma_data(struct
pci_dev*pdev,return; pdata->mf = map;drivers/dma/dw-edma/dw-edma-pcie.c +1
-1- pdata->rg.bar =FIELD_GET (DW_PCIE_VSEC_DMA_BAR , val); + pdata->rg.bar =FIELD_GET (DW_PCIE_SYNOPSYS_VSEC_DMA_BAR , val);
Quoted 13 lines
drivers/dma/dw-edma/dw-edma-pcie.c static void dw_edma_pcie_get_vsec_dma_data(struct pci_dev *pdev, · line 230
Quoted 9 lines
pci_read_config_dword(pdev, vsec + 0xc, &val); pdata->wr_ch_cnt = min_t(u16, pdata->wr_ch_cnt,drivers/dma/dw-edma/dw-edma-pcie.c +4
-2- FIELD_GET(DW_PCIE_VSEC_DMA_WR_CH, val)); + + FIELD_GET(DW_PCIE_SYNOPSYS_VSEC_DMA_WR_CH, val)); pdata->rd_ch_cnt =min_t (u16, pdata->rd_ch_cnt, -FIELD_GET (DW_PCIE_VSEC_DMA_RD_CH , val)); + +FIELD_GET (DW_PCIE_SYNOPSYS_VSEC_DMA_RD_CH , val));If you don't change macro name, these change is not necessary. If really need change macro name, make change macro name as sperated patch.
As explained above, the name change is required to avoid confusion.
The trigger to have the separate names for each IP is the inclusion of Xilinx IP that is why no separate patch is created.
Quoted 87 lines
drivers/dma/dw-edma/dw-edma-pcie.c static void
Quoted 4 lines
pci_read_config_dword(pdev, vsec + 0x14, &val); off = val;drivers/dma/dw-edma/dw-edma-pcie.c +0
-0@@ -157,6 +237,67 @@ static voiddw_edma_pcie_get_vsec_dma_data(struct
pci_dev*pdev,Quoted 13 lines
drivers/dma/dw-edma/dw-edma-pcie.c +10
-0pdata->rg.off = off; } +static void dw_edma_pcie_get_xilinx_dma_data (struct pci_dev *pdev, +struct dw_edma_pcie_data +*pdata) { +u32 val, map; +u16 vsec; +u64 off; + + pdata->devmem_phys_off =DW_PCIE_XILINX_MDB_INVALID_ADDR ; + + vsec = pci_find_vsec_capability(pdev, PCI_VENDOR_ID_XILINX,drivers/dma/dw-edma/dw-edma-pcie.c static void dw_edma_pcie_get_vsec_dma_data(struct pci_dev *pdev,
Quoted 10 lines
drivers/dma/dw-edma/dw-edma-pcie.c +10
-0+ DW_PCIE_XILINX_MDB_VSEC_DMA_ID); +if (!vsec) +return ; + +pci_read_config_dword (pdev, vsec +PCI_VNDR_HEADER , &val); +if (PCI_VNDR_HEADER_REV (val) !=0x00 || +PCI_VNDR_HEADER_LEN (val) !=0x18 ) +return ; + + pci_dbg(pdev, "Detected Xilinx PCIe Vendor-Specific Extended CapabilityDMA\n");
drivers/dma/dw-edma/dw-edma-pcie.c static void dw_edma_pcie_get_vsec_dma_data(struct pci_dev *pdev,
Quoted 10 lines
drivers/dma/dw-edma/dw-edma-pcie.c +10
-0+pci_read_config_dword (pdev, vsec +0x8 , &val); + map =FIELD_GET (DW_PCIE_XILINX_MDB_VSEC_DMA_MAP , val); +if (map !=EDMA_MF_EDMA_LEGACY && + map !=EDMA_MF_EDMA_UNROLL && + map !=EDMA_MF_HDMA_COMPAT && + map !=EDMA_MF_HDMA_NATIVE ) +return ; + + pdata->mf = map; + pdata->rg.bar = FIELD_GET(DW_PCIE_XILINX_MDB_VSEC_DMA_BAR,val);
drivers/dma/dw-edma/dw-edma-pcie.c static void dw_edma_pcie_get_vsec_dma_data(struct pci_dev *pdev,
Quoted 4 lines
drivers/dma/dw-edma/dw-edma-pcie.c +4
-0+ +pci_read_config_dword (pdev, vsec +0xc , &val); + pdata->wr_ch_cnt = min_t(u16, pdata->wr_ch_cnt, + FIELD_GET(DW_PCIE_XILINX_MDB_VSEC_DMA_WR_CH,val));
Quoted 34 lines
drivers/dma/dw-edma/dw-edma-pcie.c +28
-1+ pdata->rd_ch_cnt =min_t (u16, pdata->rd_ch_cnt, + +FIELD_GET (DW_PCIE_XILINX_MDB_VSEC_DMA_RD_CH , val)); + +pci_read_config_dword (pdev, vsec +0x14 , &val); + off = val; +pci_read_config_dword (pdev, vsec +0x10 , &val); + off <<=32 ; + off |= val; + pdata->rg.off = off; + + vsec =pci_find_vsec_capability (pdev,PCI_VENDOR_ID_XILINX , +DW_PCIE_XILINX_MDB_VSEC_ID ); +if (!vsec) +return ; + +pci_read_config_dword (pdev, + vsec +DW_PCIE_XILINX_MDB_DEVMEM_OFF_REG_HIGH , + &val); + off = val; +pci_read_config_dword (pdev, + vsec +DW_PCIE_XILINX_MDB_DEVMEM_OFF_REG_LOW , + &val); + off <<=32 ; + off |= val; + pdata->devmem_phys_off = off; +} +static int dw_edma_pcie_probe (struct pci_dev *pdev, const struct pci_device_id *pid) { @@ -184,7 +325,28 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,* Tries to find if exists a PCIe Vendor-Specific Extended Capability
* for the DMA, if one exists, then reconfigures it.
*/drivers/dma/dw-edma/dw-edma-pcie.c static int dw_edma_pcie_probe(struct pci_dev *pdev, · line 331
Quoted 5 lines
drivers/dma/dw-edma/dw-edma-pcie.c +4
-1-dw_edma_pcie_get_vsec_dma_data (pdev, vsec_data); +dw_edma_pcie_get_synopsys_dma_data (pdev, vsec_data); +dw_edma_pcie_get_xilinx_dma_data (pdev, vsec_data); + +if (pdev->vendor ==PCI_VENDOR_ID_XILINX ) {
dw_edma_pcie_get_xilinx_dma_data()should be here.
Quoted 1 line
Frank
Yes, this is good suggestion. Thanks!
Quoted 35 lines
drivers/dma/dw-edma/dw-edma-pcie.c static int dw_edma_pcie_probe(struct pci_dev *pdev,
Quoted 5 lines
drivers/dma/dw-edma/dw-edma-pcie.c +5
-0+/* +* There is no valid address found for the LL memory +* space on the device side. +*/ + if (vsec_data->devmem_phys_off ==
DW_PCIE_XILINX_MDB_INVALID_ADDR)Quoted 29 lines
drivers/dma/dw-edma/dw-edma-pcie.c +15
-0+return -ENOMEM ; + +/* +* Configure the channel LL and data blocks if number of +* channels enabled in VSEC capability are more than the +* channels configured in xilinx_mdb_data. +*/ +dw_edma_set_chan_region_offset (vsec_data,BAR_2 ,0 , +DW_PCIE_XILINX_MDB_LL_OFF_GAP , +DW_PCIE_XILINX_MDB_LL_SIZE , +DW_PCIE_XILINX_MDB_DT_OFF_GAP , +DW_PCIE_XILINX_MDB_DT_SIZE ); + }/* Mapping PCI BAR regions */ mask =BIT (vsec_data->rg.bar);@@ -367,6 +529,8 @@ static void dw_edma_pcie_remove(struct pci_dev *pdev)static const struct pci_device_id dw_edma_pcie_id_table[] = { {PCI_DEVICE_DATA (SYNOPSYS ,EDDA , &snps_edda_data) }, + {PCI_VDEVICE (XILINX ,PCI_DEVICE_ID_XILINX_B054 ), + (kernel_ulong_t)&xilinx_mdb_data }, { } };
MODULE_DEVICE_TABLE(pci, dw_edma_pcie_id_table);
--
1.8.3.1
Re: [PATCH v8 1/2] dmaengine: dw-edma: Add AMD MDB Endpoint Support
Quoted 110 lines · Devendra
[AMD Official Use Only - AMD Internal Distribution Only]
Hi Frank
Please check my comments inline.
Regards,
DevendraQuoted 85 lines
-----Original Message-----
From: Frank Li <[email protected]>
Sent: Thursday, January 15, 2026 9:51 PM
To: Verma, Devendra <[email protected]>
Cc: [email protected]; [email protected]; [email protected]; [email protected]; [email protected]; linux- [email protected]; Simek, Michal <[email protected]>
Subject: Re: [PATCH v8 1/2] dmaengine: dw-edma: Add AMD MDB Endpoint SupportCaution: This message originated from an External Source. Use proper caution when opening attachments, clicking links, or responding.
Quoted 70 lines · Devendra K Verma
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 <[email protected]>---
Changes in v8:
Changed the contant names to includer product vendor. Moved the vendor specific code to vendor specific functions.Changes in v7:
Introduced vendor specific functions to retrieve the vsec data.Changes in v6:
Included "sizes.h" header and used the appropriate definitions instead of constants.Changes in v5:
Added the definitions for Xilinx specific VSEC header id, revision, and register offsets.
Corrected the error type when no physical offset found for device side memory.
Corrected the order of variables.Changes in v4:
Configured 8 read and 8 write channels for Xilinx vendor Added checks to validate vendor ID for vendor specific vsec id.
Added Xilinx specific vendor id for vsec specific to Xilinx Added the LL and data region offsets, size as input params to functiondw_edma_set_chan_region_offset().
Moved the LL and data region offsets assignment to function for Xilinx specific case.
Corrected comments.Changes in v3:
Corrected a typo when assigning AMD (Xilinx) vsec id macro and condition check.Changes in v2:
Reverted thedevmem_phys_offtype to u64.
Renamed the function appropriately to suit the functionality for setting the LL & data region offsets.Changes in v1:
Removed the pci device id frompci_ids.hfile.
Added the vendor id macro as per the suggested method. Changed the type of the newly addeddevmem_phys_offvariable. Added to logic to assign offsets for LL and data region blocks in case more number of channels are enabled than given inamd_mdb_datastruct.--- drivers/dma/dw-edma/dw-edma-pcie.c | 192 ++++++++++++++++++++++++++++++++++--- 1 file changed, 178 insertions(+), 14 deletions(-)drivers/dma/dw-edma/dw-edma-pcie.c +1
-0@@ -14,14 +14,35 @@#include <linux/pci-epf.h> #include <linux/msi.h> #include <linux/bitfield.h> +#include <linux/sizes.h> #include "dw-edma-core.h" Quoted 15 lines
drivers/dma/dw-edma/dw-edma-pcie.c line 26
Quoted 11 lines
drivers/dma/dw-edma/dw-edma-pcie.c +6
-5-#define DW_PCIE_VSEC_DMA_ID 0x6 -#define DW_PCIE_VSEC_DMA_BAR GENMASK(10, 8) -#define DW_PCIE_VSEC_DMA_MAP GENMASK(2, 0) -#define DW_PCIE_VSEC_DMA_WR_CH GENMASK(9, 0) -#define DW_PCIE_VSEC_DMA_RD_CH GENMASK(25, 16) +/* Synopsys */ +#define DW_PCIE_SYNOPSYS_VSEC_DMA_ID 0x6 +#define DW_PCIE_SYNOPSYS_VSEC_DMA_BAR GENMASK(10, 8) +#define DW_PCIE_SYNOPSYS_VSEC_DMA_MAP GENMASK(2, 0) +#define DW_PCIE_SYNOPSYS_VSEC_DMA_WR_CH GENMASK(9, 0) +#define DW_PCIE_SYNOPSYS_VSEC_DMA_RD_CH GENMASK(25, 16)Sorry, jump into at v8.
According to my understand 'DW' means 'Synopsys'.
Quoted 6 lines
Yes, DW means Designware representing Synopsys here.
For the sake of clarity, a distinction was required to separate the names of macros having the similar purpose for other IP, Xilinx in this case. Otherwise, it is causing confusion which macros to use for which vendor. This also helps in future if any of the vendors try to retrieve a new or different VSEC IDs then all they need is to define macros which clearly show the association with the vendor, thus eliminating the confusion.
If want to reuse the driver, driver owner take reponsiblity to find the difference.
If define a whole set of register, the reader is hard to find real difference.
Quoted 163 lines
Quoted 14 lines
drivers/dma/dw-edma/dw-edma-pcie.c line 36
Quoted 11 lines
drivers/dma/dw-edma/dw-edma-pcie.c +10
-0+ +/* AMD MDB (Xilinx) specific defines */ +#define PCI_DEVICE_ID_XILINX_B054 0xb054 + +#define DW_PCIE_XILINX_MDB_VSEC_DMA_ID 0x6 +#define DW_PCIE_XILINX_MDB_VSEC_ID 0x20 +#define DW_PCIE_XILINX_MDB_VSEC_DMA_BAR GENMASK(10, 8) +#define DW_PCIE_XILINX_MDB_VSEC_DMA_MAP GENMASK(2, 0) +#define DW_PCIE_XILINX_MDB_VSEC_DMA_WR_CH GENMASK(9, 0) +#define DW_PCIE_XILINX_MDB_VSEC_DMA_RD_CH GENMASK(25, 16)These defination is the same. Need redefine again
It is the similar case as explained for the previous comment. Please check.
Quoted 132 lines
drivers/dma/dw-edma/dw-edma-pcie.c line 40
Quoted 4 lines
drivers/dma/dw-edma/dw-edma-pcie.c +4
-0+ +#define DW_PCIE_XILINX_MDB_DEVMEM_OFF_REG_HIGH 0xc +#define DW_PCIE_XILINX_MDB_DEVMEM_OFF_REG_LOW 0x8 +#define DW_PCIE_XILINX_MDB_INVALID_ADDR (~0ULL)I think
XILINX_PCIE_MDB_DEVMEM_OFF_REG_HIGHQuoted 24 lines
drivers/dma/dw-edma/dw-edma-pcie.c +11
-0+ +#define DW_PCIE_XILINX_MDB_LL_OFF_GAP 0x200000 +#define DW_PCIE_XILINX_MDB_LL_SIZE 0x800 +#define DW_PCIE_XILINX_MDB_DT_OFF_GAP 0x100000 +#define DW_PCIE_XILINX_MDB_DT_SIZE 0x800#define DW_BLOCK (a, b, c) \ { \@@ -50,6 +71,7 @@ struct dw_edma_pcie_data {u8 irqs;u16 wr_ch_cnt;u16 rd_ch_cnt; +u64 devmem_phys_off; }; static const struct dw_edma_pcie_data snps_edda_data = { @@ -90,6 +112,64 @@ struct dw_edma_pcie_data { .rd_ch_cnt =2 , }; +static const struct dw_edma_pcie_data xilinx_mdb_data = { + /* MDB registers location */ + .rg.bar = BAR_0, + .rg.off = SZ_4K, /* 4 Kbytes */drivers/dma/dw-edma/dw-edma-pcie.c struct dw_edma_pcie_data {
Quoted 10 lines
drivers/dma/dw-edma/dw-edma-pcie.c +10
-0+ .rg.sz = SZ_8K, /* 8 Kbytes */ + +/* Other */ + .mf = EDMA_MF_HDMA_NATIVE, + .irqs = 1, + .wr_ch_cnt = 8, + .rd_ch_cnt = 8, +}; + +static void dw_edma_set_chan_region_offset(struct dw_edma_pcie_data*pdata,
Quoted 47 lines
drivers/dma/dw-edma/dw-edma-pcie.c +44
-0+ enum pci_barno bar, off_t start_off, + off_t ll_off_gap, size_t ll_size, + off_t dt_off_gap, size_t +dt_size) { + u16 wr_ch = pdata->wr_ch_cnt; +u16 rd_ch = pdata->rd_ch_cnt; +off_t off; +u16 i; + + off = start_off; + +/* Write channel LL region */ +for (i =0 ; i < wr_ch; i++) { + pdata->ll_wr[i].bar = bar; + pdata->ll_wr[i].off = off; + pdata->ll_wr[i].sz = ll_size; + off += ll_off_gap; + } + +/* Read channel LL region */ +for (i =0 ; i < rd_ch; i++) { + pdata->ll_rd[i].bar = bar; + pdata->ll_rd[i].off = off; + pdata->ll_rd[i].sz = ll_size; + off += ll_off_gap; + } + +/* Write channel data region */ +for (i =0 ; i < wr_ch; i++) { + pdata->dt_wr[i].bar = bar; + pdata->dt_wr[i].off = off; + pdata->dt_wr[i].sz = dt_size; + off += dt_off_gap; + } + +/* Read channel data region */ +for (i =0 ; i < rd_ch; i++) { + pdata->dt_rd[i].bar = bar; + pdata->dt_rd[i].off = off; + pdata->dt_rd[i].sz = dt_size; + off += dt_off_gap; + } +} + static int dw_edma_pcie_irq_vector(struct device *dev, unsigned intnr) { return pci_irq_vector(to_pci_dev(dev), nr); @@ -114,15 +194,15Quoted 1 line
@@ static u64 dw_edma_pcie_address(struct device *dev,
phys_addr_t
cpu_addr)drivers/dma/dw-edma/dw-edma-pcie.c static void
Quoted 19 lines
.pci_address = dw_edma_pcie_address, };drivers/dma/dw-edma/dw-edma-pcie.c +4
-3-static void dw_edma_pcie_get_vsec_dma_data (struct pci_dev *pdev, -struct dw_edma_pcie_data *pdata) +static void dw_edma_pcie_get_synopsys_dma_data (struct pci_dev *pdev, +struct dw_edma_pcie_data +*pdata) {u32 val, map;u16 vsec;u64 off; vsec =pci_find_vsec_capability (pdev,PCI_VENDOR_ID_SYNOPSYS , -DW_PCIE_VSEC_DMA_ID ); +DW_PCIE_SYNOPSYS_VSEC_DMA_ID );if (!vsec)return ;@@ -131,9 +211,9 @@ static voiddw_edma_pcie_get_vsec_dma_data(struct
pci_dev*pdev,drivers/dma/dw-edma/dw-edma-pcie.c static void dw_edma_pcie_get_vsec_dma_data(struct pci_dev *pdev,
Quoted 4 lines
drivers/dma/dw-edma/dw-edma-pcie.c +0
-1PCI_VNDR_HEADER_LEN(val) != 0x18)return ; - pci_dbg(pdev, "Detected PCIe Vendor-Specific Extended CapabilityDMA\n");
drivers/dma/dw-edma/dw-edma-pcie.c static void dw_edma_pcie_get_vsec_dma_data(struct pci_dev *pdev,
Quoted 8 lines
drivers/dma/dw-edma/dw-edma-pcie.c +3
-1+ pci_dbg(pdev, "Detected Synopsys PCIe Vendor-Specific Extended + Capability DMA\n"); pci_read_config_dword(pdev, vsec + 0x8, &val); - map =FIELD_GET (DW_PCIE_VSEC_DMA_MAP , val); + map =FIELD_GET (DW_PCIE_SYNOPSYS_VSEC_DMA_MAP , val); if (map != EDMA_MF_EDMA_LEGACY && map != EDMA_MF_EDMA_UNROLL && map != EDMA_MF_HDMA_COMPAT && @@ -141,13 +221,13 @@static
Quoted 7 lines
void dw_edma_pcie_get_vsec_dma_data(struct
pci_dev*pdev,return; pdata->mf = map;drivers/dma/dw-edma/dw-edma-pcie.c +1
-1- pdata->rg.bar =FIELD_GET (DW_PCIE_VSEC_DMA_BAR , val); + pdata->rg.bar =FIELD_GET (DW_PCIE_SYNOPSYS_VSEC_DMA_BAR , val);Quoted 13 lines
drivers/dma/dw-edma/dw-edma-pcie.c static void dw_edma_pcie_get_vsec_dma_data(struct pci_dev *pdev, · line 230
Quoted 9 lines
pci_read_config_dword(pdev, vsec + 0xc, &val); pdata->wr_ch_cnt = min_t(u16, pdata->wr_ch_cnt,drivers/dma/dw-edma/dw-edma-pcie.c +4
-2- FIELD_GET(DW_PCIE_VSEC_DMA_WR_CH, val)); + + FIELD_GET(DW_PCIE_SYNOPSYS_VSEC_DMA_WR_CH, val)); pdata->rd_ch_cnt =min_t (u16, pdata->rd_ch_cnt, -FIELD_GET (DW_PCIE_VSEC_DMA_RD_CH , val)); + +FIELD_GET (DW_PCIE_SYNOPSYS_VSEC_DMA_RD_CH , val));If you don't change macro name, these change is not necessary. If really need change macro name, make change macro name as sperated patch.
Quoted 3 lines
As explained above, the name change is required to avoid confusion.
The trigger to have the separate names for each IP is the inclusion of Xilinx IP that is why no separate patch is created.
Separate patch renmae macro only. Reviewer can simple bypass this typo trivial patch.
Then add new one.
Actually, Needn't rename at all. You can directly use XLINNK_PCIE_*
Frank
Quoted 127 lines
Quoted 88 lines
drivers/dma/dw-edma/dw-edma-pcie.c static void
Quoted 5 lines
pci_read_config_dword(pdev, vsec + 0x14, &val); off = val;drivers/dma/dw-edma/dw-edma-pcie.c +0
-0@@ -157,6 +237,67 @@ static voiddw_edma_pcie_get_vsec_dma_data(struct
pci_dev*pdev,Quoted 13 lines
drivers/dma/dw-edma/dw-edma-pcie.c +10
-0pdata->rg.off = off; } +static void dw_edma_pcie_get_xilinx_dma_data (struct pci_dev *pdev, +struct dw_edma_pcie_data +*pdata) { +u32 val, map; +u16 vsec; +u64 off; + + pdata->devmem_phys_off =DW_PCIE_XILINX_MDB_INVALID_ADDR ; + + vsec = pci_find_vsec_capability(pdev, PCI_VENDOR_ID_XILINX,drivers/dma/dw-edma/dw-edma-pcie.c static void dw_edma_pcie_get_vsec_dma_data(struct pci_dev *pdev,
Quoted 10 lines
drivers/dma/dw-edma/dw-edma-pcie.c +10
-0+ DW_PCIE_XILINX_MDB_VSEC_DMA_ID); +if (!vsec) +return ; + +pci_read_config_dword (pdev, vsec +PCI_VNDR_HEADER , &val); +if (PCI_VNDR_HEADER_REV (val) !=0x00 || +PCI_VNDR_HEADER_LEN (val) !=0x18 ) +return ; + + pci_dbg(pdev, "Detected Xilinx PCIe Vendor-Specific Extended CapabilityDMA\n");
drivers/dma/dw-edma/dw-edma-pcie.c static void dw_edma_pcie_get_vsec_dma_data(struct pci_dev *pdev,
Quoted 10 lines
drivers/dma/dw-edma/dw-edma-pcie.c +10
-0+pci_read_config_dword (pdev, vsec +0x8 , &val); + map =FIELD_GET (DW_PCIE_XILINX_MDB_VSEC_DMA_MAP , val); +if (map !=EDMA_MF_EDMA_LEGACY && + map !=EDMA_MF_EDMA_UNROLL && + map !=EDMA_MF_HDMA_COMPAT && + map !=EDMA_MF_HDMA_NATIVE ) +return ; + + pdata->mf = map; + pdata->rg.bar = FIELD_GET(DW_PCIE_XILINX_MDB_VSEC_DMA_BAR,val);
drivers/dma/dw-edma/dw-edma-pcie.c static void dw_edma_pcie_get_vsec_dma_data(struct pci_dev *pdev,
Quoted 4 lines
drivers/dma/dw-edma/dw-edma-pcie.c +4
-0+ +pci_read_config_dword (pdev, vsec +0xc , &val); + pdata->wr_ch_cnt = min_t(u16, pdata->wr_ch_cnt, + FIELD_GET(DW_PCIE_XILINX_MDB_VSEC_DMA_WR_CH,val));
Quoted 34 lines
drivers/dma/dw-edma/dw-edma-pcie.c +28
-1+ pdata->rd_ch_cnt =min_t (u16, pdata->rd_ch_cnt, + +FIELD_GET (DW_PCIE_XILINX_MDB_VSEC_DMA_RD_CH , val)); + +pci_read_config_dword (pdev, vsec +0x14 , &val); + off = val; +pci_read_config_dword (pdev, vsec +0x10 , &val); + off <<=32 ; + off |= val; + pdata->rg.off = off; + + vsec =pci_find_vsec_capability (pdev,PCI_VENDOR_ID_XILINX , +DW_PCIE_XILINX_MDB_VSEC_ID ); +if (!vsec) +return ; + +pci_read_config_dword (pdev, + vsec +DW_PCIE_XILINX_MDB_DEVMEM_OFF_REG_HIGH , + &val); + off = val; +pci_read_config_dword (pdev, + vsec +DW_PCIE_XILINX_MDB_DEVMEM_OFF_REG_LOW , + &val); + off <<=32 ; + off |= val; + pdata->devmem_phys_off = off; +} +static int dw_edma_pcie_probe (struct pci_dev *pdev, const struct pci_device_id *pid) { @@ -184,7 +325,28 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,* Tries to find if exists a PCIe Vendor-Specific Extended Capability
* for the DMA, if one exists, then reconfigures it.
*/drivers/dma/dw-edma/dw-edma-pcie.c static int dw_edma_pcie_probe(struct pci_dev *pdev, · line 331
Quoted 5 lines
drivers/dma/dw-edma/dw-edma-pcie.c +4
-1-dw_edma_pcie_get_vsec_dma_data (pdev, vsec_data); +dw_edma_pcie_get_synopsys_dma_data (pdev, vsec_data); +dw_edma_pcie_get_xilinx_dma_data (pdev, vsec_data); + +if (pdev->vendor ==PCI_VENDOR_ID_XILINX ) {
dw_edma_pcie_get_xilinx_dma_data()should be here.Quoted 1 line
Frank
Yes, this is good suggestion. Thanks!
Quoted 35 lines
drivers/dma/dw-edma/dw-edma-pcie.c static int dw_edma_pcie_probe(struct pci_dev *pdev,
Quoted 5 lines
drivers/dma/dw-edma/dw-edma-pcie.c +5
-0+/* +* There is no valid address found for the LL memory +* space on the device side. +*/ + if (vsec_data->devmem_phys_off ==
DW_PCIE_XILINX_MDB_INVALID_ADDR)Quoted 29 lines
drivers/dma/dw-edma/dw-edma-pcie.c +15
-0+return -ENOMEM ; + +/* +* Configure the channel LL and data blocks if number of +* channels enabled in VSEC capability are more than the +* channels configured in xilinx_mdb_data. +*/ +dw_edma_set_chan_region_offset (vsec_data,BAR_2 ,0 , +DW_PCIE_XILINX_MDB_LL_OFF_GAP , +DW_PCIE_XILINX_MDB_LL_SIZE , +DW_PCIE_XILINX_MDB_DT_OFF_GAP , +DW_PCIE_XILINX_MDB_DT_SIZE ); + }/* Mapping PCI BAR regions */ mask =BIT (vsec_data->rg.bar);@@ -367,6 +529,8 @@ static void dw_edma_pcie_remove(struct pci_dev *pdev)static const struct pci_device_id dw_edma_pcie_id_table[] = { {PCI_DEVICE_DATA (SYNOPSYS ,EDDA , &snps_edda_data) }, + {PCI_VDEVICE (XILINX ,PCI_DEVICE_ID_XILINX_B054 ), + (kernel_ulong_t)&xilinx_mdb_data }, { } };
MODULE_DEVICE_TABLE(pci, dw_edma_pcie_id_table);
--
1.8.3.1
RE: [PATCH v8 1/2] dmaengine: dw-edma: Add AMD MDB Endpoint Support
[AMD Official Use Only - AMD Internal Distribution Only]
Quoted 136 lines
-----Original Message-----
From: Frank Li <[email protected]>
Sent: Monday, January 19, 2026 9:30 PM
To: Verma, Devendra <[email protected]>
Cc: [email protected]; [email protected]; [email protected]; [email protected]; [email protected]; linux- [email protected]; Simek, Michal <[email protected]>
Subject: Re: [PATCH v8 1/2] dmaengine: dw-edma: Add AMD MDB Endpoint SupportCaution: This message originated from an External Source. Use proper caution when opening attachments, clicking links, or responding.
Quoted 17 lines · Devendra
[AMD Official Use Only - AMD Internal Distribution Only]
Hi Frank
Please check my comments inline.
Regards,
DevendraQuoted 8 lines
-----Original Message-----
From: Frank Li <[email protected]>
Sent: Thursday, January 15, 2026 9:51 PM
To: Verma, Devendra <[email protected]>
Cc: [email protected]; [email protected]; [email protected]; [email protected]; [email protected]; linux- [email protected]; Simek, Michal <[email protected]>
Subject: Re: [PATCH v8 1/2] dmaengine: dw-edma: Add AMD MDBEndpoint
Quoted 53 lines
Quoted 53 lines
Support
Caution: This message originated from an External Source. Use proper caution when opening attachments, clicking links, or responding.
Quoted 46 lines · Devendra K Verma
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 <[email protected]>---
Changes in v8:
Changed the contant names to includer product vendor. Moved the vendor specific code to vendor specific functions.Changes in v7:
Introduced vendor specific functions to retrieve the vsec data.Changes in v6:
Included "sizes.h" header and used the appropriate definitions instead of constants.Changes in v5:
Added the definitions for Xilinx specific VSEC header id, revision, and register offsets.
Corrected the error type when no physical offset found for device side memory.
Corrected the order of variables.Changes in v4:
Configured 8 read and 8 write channels for Xilinx vendor Added checks to validate vendor ID for vendor specific vsec id. Added Xilinx specific vendor id for vsec specific to Xilinx Added the LL and data region offsets, size as input params to functiondw_edma_set_chan_region_offset().
Moved the LL and data region offsets assignment to function for Xilinx specific case.
Corrected comments.Changes in v3:
Corrected a typo when assigning AMD (Xilinx) vsec id macro and condition check.Changes in v2:
Reverted thedevmem_phys_offtype to u64.
Renamed the function appropriately to suit the functionality for setting the LL & data region offsets.Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Changes in v1:
Removed the pci device id frompci_ids.hfile.
Added the vendor id macro as per the suggested method. Changed the type of the newly addeddevmem_phys_offvariable. Added to logic to assign offsets for LL and data region blocks in case more number of channels are enabled than given in
amd_mdb_datastruct.Quoted 18 lines
Quoted 18 lines
Quoted 18 lines
--- drivers/dma/dw-edma/dw-edma-pcie.c | 192 ++++++++++++++++++++++++++++++++++--- 1 file changed, 178 insertions(+), 14 deletions(-)drivers/dma/dw-edma/dw-edma-pcie.c +1
-0@@ -14,14 +14,35 @@#include <linux/pci-epf.h> #include <linux/msi.h> #include <linux/bitfield.h> +#include <linux/sizes.h> #include "dw-edma-core.h" Quoted 8 lines
Quoted 8 lines
drivers/dma/dw-edma/dw-edma-pcie.c
Quoted 8 lines
drivers/dma/dw-edma/dw-edma-pcie.c +3
-5-#define DW_PCIE_VSEC_DMA_ID 0x6 -#define DW_PCIE_VSEC_DMA_BAR GENMASK(10, 8) -#define DW_PCIE_VSEC_DMA_MAP GENMASK(2, 0) -#define DW_PCIE_VSEC_DMA_WR_CH GENMASK(9, 0) -#define DW_PCIE_VSEC_DMA_RD_CH GENMASK(25, 16) +/* Synopsys */ +#define DW_PCIE_SYNOPSYS_VSEC_DMA_ID 0x6 +#define DW_PCIE_SYNOPSYS_VSEC_DMA_BAR GENMASK(10,8)
Quoted 2 lines
Quoted 2 lines
drivers/dma/dw-edma/dw-edma-pcie.c line 25
Quoted 2 lines
drivers/dma/dw-edma/dw-edma-pcie.c +2
-0+#define DW_PCIE_SYNOPSYS_VSEC_DMA_MAP GENMASK(2, 0) +#define DW_PCIE_SYNOPSYS_VSEC_DMA_WR_CH GENMASK(9,0)
Quoted 1 line
Quoted 1 line
drivers/dma/dw-edma/dw-edma-pcie.c line 26
Quoted 1 line
drivers/dma/dw-edma/dw-edma-pcie.c +1
-0+#define DW_PCIE_SYNOPSYS_VSEC_DMA_RD_CH GENMASK(25,16)
Quoted 11 lines
Quoted 4 lines
Sorry, jump into at v8.
According to my understand 'DW' means 'Synopsys'.Yes, DW means Designware representing Synopsys here.
For the sake of clarity, a distinction was required to separate the names of macros having the similar purpose for other IP, Xilinx in this case. Otherwise, it is causing confusion which macros to use for which vendor. This also helps in future if any of the vendors try to retrieve a new or different VSEC IDs then all they need is to define macros
Quoted 8 lines
which clearly show the association with the vendor, thus eliminating the confusion.
If want to reuse the driver, driver owner take reponsiblity to find the difference.
If define a whole set of register, the reader is hard to find real difference.
It is not regarding the register set rather VSEC capability which can differ in the purpose even for the similar IPs. As is the current case where one VSEC ID serves the similar purpose for both the IPs while the VSEC ID = 0x20 differs in meaning for Synopsys and Xilinx thus I think it is OK to define new macros as long as they do not create confusion.
Quoted 178 lines
Quoted 8 lines
Quoted 8 lines
drivers/dma/dw-edma/dw-edma-pcie.c
Quoted 8 lines
drivers/dma/dw-edma/dw-edma-pcie.c +7
-0+ +/* AMD MDB (Xilinx) specific defines */ +#define PCI_DEVICE_ID_XILINX_B054 0xb054 + +#define DW_PCIE_XILINX_MDB_VSEC_DMA_ID 0x6 +#define DW_PCIE_XILINX_MDB_VSEC_ID 0x20 +#define DW_PCIE_XILINX_MDB_VSEC_DMA_BAR GENMASK(10,8)
Quoted 1 line
Quoted 1 line
drivers/dma/dw-edma/dw-edma-pcie.c line 34
Quoted 1 line
drivers/dma/dw-edma/dw-edma-pcie.c +1
-0+#define DW_PCIE_XILINX_MDB_VSEC_DMA_MAP GENMASK(2,0)
Quoted 2 lines
Quoted 2 lines
drivers/dma/dw-edma/dw-edma-pcie.c line 36
Quoted 2 lines
drivers/dma/dw-edma/dw-edma-pcie.c +2
-0+#define DW_PCIE_XILINX_MDB_VSEC_DMA_WR_CH GENMASK(9, 0) +#define DW_PCIE_XILINX_MDB_VSEC_DMA_RD_CH GENMASK(25,16)
Quoted 100 lines
Quoted 3 lines
These defination is the same. Need redefine again
It is the similar case as explained for the previous comment. Please check.
Quoted 94 lines
drivers/dma/dw-edma/dw-edma-pcie.c line 40
Quoted 4 lines
drivers/dma/dw-edma/dw-edma-pcie.c +4
-0+ +#define DW_PCIE_XILINX_MDB_DEVMEM_OFF_REG_HIGH 0xc +#define DW_PCIE_XILINX_MDB_DEVMEM_OFF_REG_LOW 0x8 +#define DW_PCIE_XILINX_MDB_INVALID_ADDR (~0ULL)I think
XILINX_PCIE_MDB_DEVMEM_OFF_REG_HIGHQuoted 25 lines
drivers/dma/dw-edma/dw-edma-pcie.c +12
-0+ +#define DW_PCIE_XILINX_MDB_LL_OFF_GAP 0x200000 +#define DW_PCIE_XILINX_MDB_LL_SIZE 0x800 +#define DW_PCIE_XILINX_MDB_DT_OFF_GAP 0x100000 +#define DW_PCIE_XILINX_MDB_DT_SIZE 0x800#define DW_BLOCK (a, b, c) \ { \@@ -50,6 +71,7 @@ struct dw_edma_pcie_data {u8 irqs;u16 wr_ch_cnt;u16 rd_ch_cnt; +u64 devmem_phys_off; }; static const struct dw_edma_pcie_data snps_edda_data = { @@ -90,6 +112,64 @@ struct dw_edma_pcie_data { .rd_ch_cnt =2 , }; +static const struct dw_edma_pcie_data xilinx_mdb_data = { + /* MDB registers location */ + .rg.bar = BAR_0, + .rg.off = SZ_4K, /* 4 Kbytes */ + .rg.sz = SZ_8K, /* 8 Kbytes */drivers/dma/dw-edma/dw-edma-pcie.c struct dw_edma_pcie_data {
Quoted 10 lines
drivers/dma/dw-edma/dw-edma-pcie.c +10
-0+ +/* Other */ + .mf = EDMA_MF_HDMA_NATIVE, + .irqs = 1, + .wr_ch_cnt = 8, + .rd_ch_cnt = 8, +}; + +static void dw_edma_set_chan_region_offset (struct +dw_edma_pcie_data*pdata,
Quoted 46 lines
drivers/dma/dw-edma/dw-edma-pcie.c +44
-0+ enum pci_barno bar, off_t start_off, + off_t ll_off_gap, size_t ll_size, + off_t dt_off_gap, size_t +dt_size) { + u16 wr_ch = pdata->wr_ch_cnt; +u16 rd_ch = pdata->rd_ch_cnt; +off_t off; +u16 i; + + off = start_off; + +/* Write channel LL region */ +for (i =0 ; i < wr_ch; i++) { + pdata->ll_wr[i].bar = bar; + pdata->ll_wr[i].off = off; + pdata->ll_wr[i].sz = ll_size; + off += ll_off_gap; + } + +/* Read channel LL region */ +for (i =0 ; i < rd_ch; i++) { + pdata->ll_rd[i].bar = bar; + pdata->ll_rd[i].off = off; + pdata->ll_rd[i].sz = ll_size; + off += ll_off_gap; + } + +/* Write channel data region */ +for (i =0 ; i < wr_ch; i++) { + pdata->dt_wr[i].bar = bar; + pdata->dt_wr[i].off = off; + pdata->dt_wr[i].sz = dt_size; + off += dt_off_gap; + } + +/* Read channel data region */ +for (i =0 ; i < rd_ch; i++) { + pdata->dt_rd[i].bar = bar; + pdata->dt_rd[i].off = off; + pdata->dt_rd[i].sz = dt_size; + off += dt_off_gap; + } +} + static int dw_edma_pcie_irq_vector(struct device *dev, unsignedint
Quoted 4 lines
nr) { return pci_irq_vector(to_pci_dev(dev), nr); @@ -114,15+194,15 @@ static u64 dw_edma_pcie_address(struct device *dev,
phys_addr_t
cpu_addr)Quoted 5 lines
Quoted 5 lines
drivers/dma/dw-edma/dw-edma-pcie.c static u64 dw_edma_pcie_address(struct device *dev, phys_addr_t cpu_addr)
Quoted 5 lines
.pci_address = dw_edma_pcie_address, };drivers/dma/dw-edma/dw-edma-pcie.c +1
-2-static void dw_edma_pcie_get_vsec_dma_data (struct pci_dev *pdev, -struct dw_edma_pcie_data *pdata) +static void dw_edma_pcie_get_synopsys_dma_data(struct pci_dev*pdev,
Quoted 39 lines
Quoted 39 lines
drivers/dma/dw-edma/dw-edma-pcie.c static void
Quoted 16 lines
drivers/dma/dw-edma/dw-edma-pcie.c +5
-1+struct +dw_edma_pcie_data +*pdata) {u32 val, map;u16 vsec;u64 off; vsec =pci_find_vsec_capability (pdev,PCI_VENDOR_ID_SYNOPSYS , -DW_PCIE_VSEC_DMA_ID ); + +DW_PCIE_SYNOPSYS_VSEC_DMA_ID );if (!vsec)return ;@@ -131,9 +211,9 @@ static voiddw_edma_pcie_get_vsec_dma_data(struct
pci_dev*pdev,drivers/dma/dw-edma/dw-edma-pcie.c static void dw_edma_pcie_get_vsec_dma_data(struct pci_dev *pdev,
Quoted 4 lines
drivers/dma/dw-edma/dw-edma-pcie.c +0
-1PCI_VNDR_HEADER_LEN(val) != 0x18)return ; - pci_dbg(pdev, "Detected PCIe Vendor-Specific Extended CapabilityDMA\n");
drivers/dma/dw-edma/dw-edma-pcie.c static void dw_edma_pcie_get_vsec_dma_data(struct pci_dev *pdev,
Quoted 8 lines
drivers/dma/dw-edma/dw-edma-pcie.c +3
-1+ pci_dbg(pdev, "Detected Synopsys PCIe Vendor-Specific + Extended Capability DMA\n"); pci_read_config_dword(pdev, vsec + 0x8, &val); - map =FIELD_GET (DW_PCIE_VSEC_DMA_MAP , val); + map =FIELD_GET (DW_PCIE_SYNOPSYS_VSEC_DMA_MAP , val); if (map != EDMA_MF_EDMA_LEGACY && map != EDMA_MF_EDMA_UNROLL && map != EDMA_MF_HDMA_COMPAT && @@ -141,13 +221,13 @@static
Quoted 8 lines
void dw_edma_pcie_get_vsec_dma_data(struct
pci_dev*pdev,return; pdata->mf = map;drivers/dma/dw-edma/dw-edma-pcie.c +2
-1- pdata->rg.bar =FIELD_GET (DW_PCIE_VSEC_DMA_BAR , val); + pdata->rg.bar =FIELD_GET (DW_PCIE_SYNOPSYS_VSEC_DMA_BAR , + val);Quoted 12 lines
Quoted 4 lines
Quoted 4 lines
pci_read_config_dword(pdev, vsec + 0xc, &val); pdata->wr_ch_cnt = min_t(u16, pdata->wr_ch_cnt,drivers/dma/dw-edma/dw-edma-pcie.c +1
-1- FIELD_GET(DW_PCIE_VSEC_DMA_WR_CH, val)); +Quoted 8 lines
drivers/dma/dw-edma/dw-edma-pcie.c static void dw_edma_pcie_get_vsec_dma_data(struct pci_dev *pdev, · line 230
Quoted 5 lines
+ FIELD_GET(DW_PCIE_SYNOPSYS_VSEC_DMA_WR_CH, val)); pdata->rd_ch_cnt = min_t(u16, pdata->rd_ch_cnt,drivers/dma/dw-edma/dw-edma-pcie.c +2
-1- FIELD_GET(DW_PCIE_VSEC_DMA_RD_CH, val)); + + FIELD_GET(DW_PCIE_SYNOPSYS_VSEC_DMA_RD_CH, val));If you don't change macro name, these change is not necessary. If really need change macro name, make change macro name as sperated
patch.
Quoted 5 lines
Quoted 1 line
As explained above, the name change is required to avoid confusion. The trigger to have the separate names for each IP is the inclusion of Xilinx IP that is why no separate patch is created.
Quoted 8 lines
Separate patch renmae macro only. Reviewer can simple bypass this typo trivial patch.
Then add new one.
Actually, Needn't rename at all. You can directly use XLINNK_PCIE_*
Frank
Please check the discussion on previous versions of the same patch series. We have this patch as the outcome of those discussions.
Other reviewing members felt it that keeping the name similar for the
VSEC ID having similar purpose for two different IPs was causing the confusion that is why it was agreed upon the separate out the naming as per the vendor-name of VSEC ID. Regarding the separate patch, the reason is introduction of the new IP which mostly supports the similar functionality except in case of VSEC IDs that's why the name separation became part of these patches. It sets the context for changing the name of the existing macros.
Quoted 134 lines
Quoted 9 lines
Quoted 9 lines
drivers/dma/dw-edma/dw-edma-pcie.c static void
Quoted 5 lines
pci_read_config_dword(pdev, vsec + 0x14, &val); off = val;drivers/dma/dw-edma/dw-edma-pcie.c +0
-0@@ -157,6 +237,67 @@ static voiddw_edma_pcie_get_vsec_dma_data(struct
pci_dev*pdev,Quoted 3 lines
drivers/dma/dw-edma/dw-edma-pcie.c +0
-0pdata->rg.off = off; }Quoted 9 lines
Quoted 9 lines
drivers/dma/dw-edma/dw-edma-pcie.c static void dw_edma_pcie_get_vsec_dma_data(struct pci_dev *pdev,
Quoted 9 lines
drivers/dma/dw-edma/dw-edma-pcie.c +9
-0+static void dw_edma_pcie_get_xilinx_dma_data (struct pci_dev *pdev, +struct +dw_edma_pcie_data +*pdata) { +u32 val, map; +u16 vsec; +u64 off; + + pdata->devmem_phys_off =
DW_PCIE_XILINX_MDB_INVALID_ADDR;Quoted 14 lines
Quoted 14 lines
drivers/dma/dw-edma/dw-edma-pcie.c static void dw_edma_pcie_get_vsec_dma_data(struct pci_dev *pdev,
Quoted 13 lines
drivers/dma/dw-edma/dw-edma-pcie.c +13
-0+ + vsec =pci_find_vsec_capability (pdev,PCI_VENDOR_ID_XILINX , +DW_PCIE_XILINX_MDB_VSEC_DMA_ID ); +if (!vsec) +return ; + +pci_read_config_dword (pdev, vsec +PCI_VNDR_HEADER , &val); +if (PCI_VNDR_HEADER_REV (val) !=0x00 || +PCI_VNDR_HEADER_LEN (val) !=0x18 ) +return ; + + pci_dbg(pdev, "Detected Xilinx PCIe Vendor-Specific Extended + CapabilityDMA\n");
Quoted 10 lines
Quoted 10 lines
drivers/dma/dw-edma/dw-edma-pcie.c static void dw_edma_pcie_get_vsec_dma_data(struct pci_dev *pdev,
Quoted 10 lines
drivers/dma/dw-edma/dw-edma-pcie.c +10
-0+pci_read_config_dword (pdev, vsec +0x8 , &val); + map =FIELD_GET (DW_PCIE_XILINX_MDB_VSEC_DMA_MAP , val); +if (map !=EDMA_MF_EDMA_LEGACY && + map !=EDMA_MF_EDMA_UNROLL && + map !=EDMA_MF_HDMA_COMPAT && + map !=EDMA_MF_HDMA_NATIVE ) +return ; + + pdata->mf = map; + pdata->rg.bar =FIELD_GET(DW_PCIE_XILINX_MDB_VSEC_DMA_BAR,
Quoted 17 lines
Quoted 17 lines
val);
drivers/dma/dw-edma/dw-edma-pcie.c static void dw_edma_pcie_get_vsec_dma_data(struct pci_dev *pdev,
Quoted 5 lines
drivers/dma/dw-edma/dw-edma-pcie.c +5
-0+ +pci_read_config_dword (pdev, vsec +0xc , &val); + pdata->wr_ch_cnt = min_t(u16, pdata->wr_ch_cnt, + + FIELD_GET(DW_PCIE_XILINX_MDB_VSEC_DMA_WR_CH,val));
Quoted 10 lines
drivers/dma/dw-edma/dw-edma-pcie.c +10
-0+ pdata->rd_ch_cnt =min_t (u16, pdata->rd_ch_cnt, + +FIELD_GET (DW_PCIE_XILINX_MDB_VSEC_DMA_RD_CH , val)); + +pci_read_config_dword (pdev, vsec +0x14 , &val); + off = val; +pci_read_config_dword (pdev, vsec +0x10 , &val); + off <<=32 ; + off |= val; + pdata->rg.off = off;Quoted 8 lines
Quoted 8 lines
drivers/dma/dw-edma/dw-edma-pcie.c static void dw_edma_pcie_get_vsec_dma_data(struct pci_dev *pdev,
Quoted 8 lines
drivers/dma/dw-edma/dw-edma-pcie.c +8
-0+ + vsec =pci_find_vsec_capability (pdev,PCI_VENDOR_ID_XILINX , +DW_PCIE_XILINX_MDB_VSEC_ID ); +if (!vsec) +return ; + + pci_read_config_dword(pdev, + vsec +
DW_PCIE_XILINX_MDB_DEVMEM_OFF_REG_HIGH,Quoted 4 lines
Quoted 4 lines
drivers/dma/dw-edma/dw-edma-pcie.c static void dw_edma_pcie_get_vsec_dma_data(struct pci_dev *pdev,
Quoted 4 lines
drivers/dma/dw-edma/dw-edma-pcie.c +4
-0+ &val); + off = val; + pci_read_config_dword(pdev, + vsec +
DW_PCIE_XILINX_MDB_DEVMEM_OFF_REG_LOW,Quoted 8 lines
Quoted 8 lines
drivers/dma/dw-edma/dw-edma-pcie.c static void dw_edma_pcie_get_vsec_dma_data(struct pci_dev *pdev,
Quoted 8 lines
drivers/dma/dw-edma/dw-edma-pcie.c +5
-1+ &val); + off <<=32 ; + off |= val; + pdata->devmem_phys_off = off; } +static int dw_edma_pcie_probe (struct pci_dev *pdev, const struct pci_device_id *pid) { @@ -184,7 +325,28 @@ static int dw_edma_pcie_probe(struct pci_dev*pdev,
Quoted 50 lines
Quoted 9 lines
drivers/dma/dw-edma/dw-edma-pcie.c static int dw_edma_pcie_probe(struct pci_dev *pdev, · line 331
Quoted 8 lines
* Tries to find if exists a PCIe Vendor-Specific Extended Capability
* for the DMA, if one exists, then reconfigures it.
*/drivers/dma/dw-edma/dw-edma-pcie.c +4
-1-dw_edma_pcie_get_vsec_dma_data (pdev, vsec_data); +dw_edma_pcie_get_synopsys_dma_data (pdev, vsec_data); +dw_edma_pcie_get_xilinx_dma_data (pdev, vsec_data); + +if (pdev->vendor ==PCI_VENDOR_ID_XILINX ) {Quoted 3 lines
dw_edma_pcie_get_xilinx_dma_data()should be here.Frank
Yes, this is good suggestion. Thanks!
Quoted 35 lines
drivers/dma/dw-edma/dw-edma-pcie.c static int dw_edma_pcie_probe(struct pci_dev *pdev,
Quoted 5 lines
drivers/dma/dw-edma/dw-edma-pcie.c +5
-0+/* +* There is no valid address found for the LL memory +* space on the device side. +*/ + if (vsec_data->devmem_phys_off ==
DW_PCIE_XILINX_MDB_INVALID_ADDR)Quoted 29 lines
drivers/dma/dw-edma/dw-edma-pcie.c +13
-0+return -ENOMEM ; + +/* +* Configure the channel LL and data blocks if number of +* channels enabled in VSEC capability are more than the +* channels configured in xilinx_mdb_data. +*/ +dw_edma_set_chan_region_offset (vsec_data,BAR_2 ,0 , +DW_PCIE_XILINX_MDB_LL_OFF_GAP , +DW_PCIE_XILINX_MDB_LL_SIZE , +DW_PCIE_XILINX_MDB_DT_OFF_GAP , +DW_PCIE_XILINX_MDB_DT_SIZE ); + }/* Mapping PCI BAR regions */ mask = BIT(vsec_data->rg.bar); @@ -367,6 +529,8 @@ staticvoid dw_edma_pcie_remove(struct
pci_dev
*pdev)static const struct
pci_device_iddw_edma_pcie_id_table[] = {
{PCI_DEVICE_DATA(SYNOPSYS, EDDA, &snps_edda_data)},drivers/dma/dw-edma/dw-edma-pcie.c +2
-1+ {PCI_VDEVICE (XILINX ,PCI_DEVICE_ID_XILINX_B054 ), + (kernel_ulong_t)&xilinx_mdb_data }, { } };MODULE_DEVICE_TABLE (pci, dw_edma_pcie_id_table); --1.8.3.1
Re: [PATCH v8 1/2] dmaengine: dw-edma: Add AMD MDB Endpoint Support
Quoted 144 lines · Devendra
[AMD Official Use Only - AMD Internal Distribution Only]
Quoted 142 lines
-----Original Message-----
From: Frank Li <[email protected]>
Sent: Monday, January 19, 2026 9:30 PM
To: Verma, Devendra <[email protected]>
Cc: [email protected]; [email protected]; [email protected]; [email protected]; [email protected]; linux- [email protected]; Simek, Michal <[email protected]>
Subject: Re: [PATCH v8 1/2] dmaengine: dw-edma: Add AMD MDB Endpoint SupportCaution: This message originated from an External Source. Use proper caution when opening attachments, clicking links, or responding.
Quoted 17 lines · Devendra
[AMD Official Use Only - AMD Internal Distribution Only]
Hi Frank
Please check my comments inline.
Regards,
DevendraQuoted 8 lines
-----Original Message-----
From: Frank Li <[email protected]>
Sent: Thursday, January 15, 2026 9:51 PM
To: Verma, Devendra <[email protected]>
Cc: [email protected]; [email protected]; [email protected]; [email protected]; [email protected]; linux- [email protected]; Simek, Michal <[email protected]>
Subject: Re: [PATCH v8 1/2] dmaengine: dw-edma: Add AMD MDBEndpoint
Quoted 53 lines
Quoted 53 lines
Support
Caution: This message originated from an External Source. Use proper caution when opening attachments, clicking links, or responding.
Quoted 46 lines · Devendra K Verma
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 <[email protected]>---
Changes in v8:
Changed the contant names to includer product vendor. Moved the vendor specific code to vendor specific functions.Changes in v7:
Introduced vendor specific functions to retrieve the vsec data.Changes in v6:
Included "sizes.h" header and used the appropriate definitions instead of constants.Changes in v5:
Added the definitions for Xilinx specific VSEC header id, revision, and register offsets.
Corrected the error type when no physical offset found for device side memory.
Corrected the order of variables.Changes in v4:
Configured 8 read and 8 write channels for Xilinx vendor Added checks to validate vendor ID for vendor specific vsec id. Added Xilinx specific vendor id for vsec specific to Xilinx Added the LL and data region offsets, size as input params to functiondw_edma_set_chan_region_offset().
Moved the LL and data region offsets assignment to function for Xilinx specific case.
Corrected comments.Changes in v3:
Corrected a typo when assigning AMD (Xilinx) vsec id macro and condition check.Changes in v2:
Reverted thedevmem_phys_offtype to u64.
Renamed the function appropriately to suit the functionality for setting the LL & data region offsets.Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Changes in v1:
Removed the pci device id frompci_ids.hfile.
Added the vendor id macro as per the suggested method. Changed the type of the newly addeddevmem_phys_offvariable. Added to logic to assign offsets for LL and data region blocks in case more number of channels are enabled than given in
amd_mdb_datastruct.Quoted 18 lines
Quoted 18 lines
Quoted 18 lines
--- drivers/dma/dw-edma/dw-edma-pcie.c | 192 ++++++++++++++++++++++++++++++++++--- 1 file changed, 178 insertions(+), 14 deletions(-)drivers/dma/dw-edma/dw-edma-pcie.c +1
-0@@ -14,14 +14,35 @@#include <linux/pci-epf.h> #include <linux/msi.h> #include <linux/bitfield.h> +#include <linux/sizes.h> #include "dw-edma-core.h" Quoted 8 lines
Quoted 8 lines
drivers/dma/dw-edma/dw-edma-pcie.c
Quoted 8 lines
drivers/dma/dw-edma/dw-edma-pcie.c +3
-5-#define DW_PCIE_VSEC_DMA_ID 0x6 -#define DW_PCIE_VSEC_DMA_BAR GENMASK(10, 8) -#define DW_PCIE_VSEC_DMA_MAP GENMASK(2, 0) -#define DW_PCIE_VSEC_DMA_WR_CH GENMASK(9, 0) -#define DW_PCIE_VSEC_DMA_RD_CH GENMASK(25, 16) +/* Synopsys */ +#define DW_PCIE_SYNOPSYS_VSEC_DMA_ID 0x6 +#define DW_PCIE_SYNOPSYS_VSEC_DMA_BAR GENMASK(10,8)
Quoted 2 lines
Quoted 2 lines
drivers/dma/dw-edma/dw-edma-pcie.c line 25
Quoted 2 lines
drivers/dma/dw-edma/dw-edma-pcie.c +2
-0+#define DW_PCIE_SYNOPSYS_VSEC_DMA_MAP GENMASK(2, 0) +#define DW_PCIE_SYNOPSYS_VSEC_DMA_WR_CH GENMASK(9,0)
Quoted 1 line
Quoted 1 line
drivers/dma/dw-edma/dw-edma-pcie.c line 26
Quoted 1 line
drivers/dma/dw-edma/dw-edma-pcie.c +1
-0+#define DW_PCIE_SYNOPSYS_VSEC_DMA_RD_CH GENMASK(25,16)
Quoted 11 lines
Quoted 4 lines
Sorry, jump into at v8.
According to my understand 'DW' means 'Synopsys'.Yes, DW means Designware representing Synopsys here.
For the sake of clarity, a distinction was required to separate the names of macros having the similar purpose for other IP, Xilinx in this case. Otherwise, it is causing confusion which macros to use for which vendor. This also helps in future if any of the vendors try to retrieve a new or different VSEC IDs then all they need is to define macroswhich clearly show the association with the vendor, thus eliminating the confusion.
If want to reuse the driver, driver owner take reponsiblity to find the difference.
Quoted 8 lines
Quoted 2 lines
If define a whole set of register, the reader is hard to find real difference.
It is not regarding the register set rather VSEC capability which can differ in the purpose even for the similar IPs. As is the current case where one VSEC ID serves the similar purpose for both the IPs while the VSEC ID =
0x20differs in meaning for Synopsys and Xilinx thus I think it is OK to define new macros as long as they do not create confusion.
But need put rename existing macro to new patches. And I think use XILINX_PCIE_MDB_* should be enough without renaming. Everyone know DW is SYNOPSYS.
Quoted 19 lines
Quoted 19 lines
Quoted 9 lines
Quoted 9 lines
drivers/dma/dw-edma/dw-edma-pcie.c
Quoted 9 lines
drivers/dma/dw-edma/dw-edma-pcie.c +7
-0+ +/* AMD MDB (Xilinx) specific defines */ +#define PCI_DEVICE_ID_XILINX_B054 0xb054 + +#define DW_PCIE_XILINX_MDB_VSEC_DMA_ID 0x6 +#define DW_PCIE_XILINX_MDB_VSEC_ID 0x20 +#define DW_PCIE_XILINX_MDB_VSEC_DMA_BAR GENMASK(10,8)
Quoted 1 line
Quoted 1 line
drivers/dma/dw-edma/dw-edma-pcie.c line 34
Quoted 1 line
drivers/dma/dw-edma/dw-edma-pcie.c +1
-0+#define DW_PCIE_XILINX_MDB_VSEC_DMA_MAP GENMASK(2,0)
Quoted 2 lines
Quoted 2 lines
drivers/dma/dw-edma/dw-edma-pcie.c line 36
Quoted 2 lines
drivers/dma/dw-edma/dw-edma-pcie.c +2
-0+#define DW_PCIE_XILINX_MDB_VSEC_DMA_WR_CH GENMASK(9, 0) +#define DW_PCIE_XILINX_MDB_VSEC_DMA_RD_CH GENMASK(25,16)
Quoted 4 lines
Quoted 3 lines
These defination is the same. Need redefine again
...
Quoted 8 lines
Quoted 8 lines
Quoted 4 lines
As explained above, the name change is required to avoid confusion. The trigger to have the separate names for each IP is the inclusion of Xilinx IP that is why no separate patch is created.
Separate patch renmae macro only. Reviewer can simple bypass this typo trivial patch.
Quoted 7 lines
Quoted 5 lines
Then add new one.
Actually, Needn't rename at all. You can directly use XLINNK_PCIE_*
Frank
Please check the discussion on previous versions of the same patch series.
It'd better you put link here to support your purposal.
Quoted 8 lines
We have this patch as the outcome of those discussions.
Other reviewing members felt it that keeping the name similar for the
VSEC ID having similar purpose for two different IPs was causing the confusion that is why it was agreed upon the separate out the naming as per the vendor-name of VSEC ID. Regarding the separate patch, the reason is introduction of the new IP which mostly supports the similar functionality except in case of VSEC IDs that's why the name separation became part of these patches. It sets the context for changing the name of the existing macros.
If put trivial big part to new patch to reduce, it will reduce review efforts.
Frank
Quoted 135 lines
Quoted 135 lines
Quoted 10 lines
Quoted 10 lines
drivers/dma/dw-edma/dw-edma-pcie.c static void
Quoted 6 lines
pci_read_config_dword(pdev, vsec + 0x14, &val); off = val;drivers/dma/dw-edma/dw-edma-pcie.c +0
-0@@ -157,6 +237,67 @@ static voiddw_edma_pcie_get_vsec_dma_data(struct
pci_dev*pdev,Quoted 3 lines
drivers/dma/dw-edma/dw-edma-pcie.c +0
-0pdata->rg.off = off; }Quoted 9 lines
Quoted 9 lines
drivers/dma/dw-edma/dw-edma-pcie.c static void dw_edma_pcie_get_vsec_dma_data(struct pci_dev *pdev,
Quoted 9 lines
drivers/dma/dw-edma/dw-edma-pcie.c +9
-0+static void dw_edma_pcie_get_xilinx_dma_data (struct pci_dev *pdev, +struct +dw_edma_pcie_data +*pdata) { +u32 val, map; +u16 vsec; +u64 off; + + pdata->devmem_phys_off =
DW_PCIE_XILINX_MDB_INVALID_ADDR;Quoted 14 lines
Quoted 14 lines
drivers/dma/dw-edma/dw-edma-pcie.c static void dw_edma_pcie_get_vsec_dma_data(struct pci_dev *pdev,
Quoted 13 lines
drivers/dma/dw-edma/dw-edma-pcie.c +13
-0+ + vsec =pci_find_vsec_capability (pdev,PCI_VENDOR_ID_XILINX , +DW_PCIE_XILINX_MDB_VSEC_DMA_ID ); +if (!vsec) +return ; + +pci_read_config_dword (pdev, vsec +PCI_VNDR_HEADER , &val); +if (PCI_VNDR_HEADER_REV (val) !=0x00 || +PCI_VNDR_HEADER_LEN (val) !=0x18 ) +return ; + + pci_dbg(pdev, "Detected Xilinx PCIe Vendor-Specific Extended + CapabilityDMA\n");
Quoted 10 lines
Quoted 10 lines
drivers/dma/dw-edma/dw-edma-pcie.c static void dw_edma_pcie_get_vsec_dma_data(struct pci_dev *pdev,
Quoted 10 lines
drivers/dma/dw-edma/dw-edma-pcie.c +10
-0+pci_read_config_dword (pdev, vsec +0x8 , &val); + map =FIELD_GET (DW_PCIE_XILINX_MDB_VSEC_DMA_MAP , val); +if (map !=EDMA_MF_EDMA_LEGACY && + map !=EDMA_MF_EDMA_UNROLL && + map !=EDMA_MF_HDMA_COMPAT && + map !=EDMA_MF_HDMA_NATIVE ) +return ; + + pdata->mf = map; + pdata->rg.bar =FIELD_GET(DW_PCIE_XILINX_MDB_VSEC_DMA_BAR,
Quoted 17 lines
Quoted 17 lines
val);
drivers/dma/dw-edma/dw-edma-pcie.c static void dw_edma_pcie_get_vsec_dma_data(struct pci_dev *pdev,
Quoted 5 lines
drivers/dma/dw-edma/dw-edma-pcie.c +5
-0+ +pci_read_config_dword (pdev, vsec +0xc , &val); + pdata->wr_ch_cnt = min_t(u16, pdata->wr_ch_cnt, + + FIELD_GET(DW_PCIE_XILINX_MDB_VSEC_DMA_WR_CH,val));
Quoted 10 lines
drivers/dma/dw-edma/dw-edma-pcie.c +10
-0+ pdata->rd_ch_cnt =min_t (u16, pdata->rd_ch_cnt, + +FIELD_GET (DW_PCIE_XILINX_MDB_VSEC_DMA_RD_CH , val)); + +pci_read_config_dword (pdev, vsec +0x14 , &val); + off = val; +pci_read_config_dword (pdev, vsec +0x10 , &val); + off <<=32 ; + off |= val; + pdata->rg.off = off;Quoted 8 lines
Quoted 8 lines
drivers/dma/dw-edma/dw-edma-pcie.c static void dw_edma_pcie_get_vsec_dma_data(struct pci_dev *pdev,
Quoted 8 lines
drivers/dma/dw-edma/dw-edma-pcie.c +8
-0+ + vsec =pci_find_vsec_capability (pdev,PCI_VENDOR_ID_XILINX , +DW_PCIE_XILINX_MDB_VSEC_ID ); +if (!vsec) +return ; + + pci_read_config_dword(pdev, + vsec +
DW_PCIE_XILINX_MDB_DEVMEM_OFF_REG_HIGH,Quoted 4 lines
Quoted 4 lines
drivers/dma/dw-edma/dw-edma-pcie.c static void dw_edma_pcie_get_vsec_dma_data(struct pci_dev *pdev,
Quoted 4 lines
drivers/dma/dw-edma/dw-edma-pcie.c +4
-0+ &val); + off = val; + pci_read_config_dword(pdev, + vsec +
DW_PCIE_XILINX_MDB_DEVMEM_OFF_REG_LOW,Quoted 8 lines
Quoted 8 lines
drivers/dma/dw-edma/dw-edma-pcie.c static void dw_edma_pcie_get_vsec_dma_data(struct pci_dev *pdev,
Quoted 8 lines
drivers/dma/dw-edma/dw-edma-pcie.c +5
-1+ &val); + off <<=32 ; + off |= val; + pdata->devmem_phys_off = off; } +static int dw_edma_pcie_probe (struct pci_dev *pdev, const struct pci_device_id *pid) { @@ -184,7 +325,28 @@ static int dw_edma_pcie_probe(struct pci_dev*pdev,
Quoted 50 lines
Quoted 9 lines
drivers/dma/dw-edma/dw-edma-pcie.c static int dw_edma_pcie_probe(struct pci_dev *pdev, · line 331
Quoted 8 lines
* Tries to find if exists a PCIe Vendor-Specific Extended Capability
* for the DMA, if one exists, then reconfigures it.
*/drivers/dma/dw-edma/dw-edma-pcie.c +4
-1-dw_edma_pcie_get_vsec_dma_data (pdev, vsec_data); +dw_edma_pcie_get_synopsys_dma_data (pdev, vsec_data); +dw_edma_pcie_get_xilinx_dma_data (pdev, vsec_data); + +if (pdev->vendor ==PCI_VENDOR_ID_XILINX ) {Quoted 3 lines
dw_edma_pcie_get_xilinx_dma_data()should be here.Frank
Yes, this is good suggestion. Thanks!
Quoted 35 lines
drivers/dma/dw-edma/dw-edma-pcie.c static int dw_edma_pcie_probe(struct pci_dev *pdev,
Quoted 5 lines
drivers/dma/dw-edma/dw-edma-pcie.c +5
-0+/* +* There is no valid address found for the LL memory +* space on the device side. +*/ + if (vsec_data->devmem_phys_off ==
DW_PCIE_XILINX_MDB_INVALID_ADDR)Quoted 29 lines
drivers/dma/dw-edma/dw-edma-pcie.c +13
-0+return -ENOMEM ; + +/* +* Configure the channel LL and data blocks if number of +* channels enabled in VSEC capability are more than the +* channels configured in xilinx_mdb_data. +*/ +dw_edma_set_chan_region_offset (vsec_data,BAR_2 ,0 , +DW_PCIE_XILINX_MDB_LL_OFF_GAP , +DW_PCIE_XILINX_MDB_LL_SIZE , +DW_PCIE_XILINX_MDB_DT_OFF_GAP , +DW_PCIE_XILINX_MDB_DT_SIZE ); + }/* Mapping PCI BAR regions */ mask = BIT(vsec_data->rg.bar); @@ -367,6 +529,8 @@ staticvoid dw_edma_pcie_remove(struct
pci_dev
*pdev)static const struct
pci_device_iddw_edma_pcie_id_table[] = {
{PCI_DEVICE_DATA(SYNOPSYS, EDDA, &snps_edda_data)},drivers/dma/dw-edma/dw-edma-pcie.c +2
-1+ {PCI_VDEVICE (XILINX ,PCI_DEVICE_ID_XILINX_B054 ), + (kernel_ulong_t)&xilinx_mdb_data }, { } };MODULE_DEVICE_TABLE (pci, dw_edma_pcie_id_table); --1.8.3.1
RE: [PATCH v8 1/2] dmaengine: dw-edma: Add AMD MDB Endpoint Support
[AMD Official Use Only - AMD Internal Distribution Only]
Hi Frank
Please check my response inline.
Regards,
Devendra
Quoted 10 lines
-----Original Message-----
From: Frank Li <[email protected]>
Sent: Wednesday, January 21, 2026 10:24 PM
To: Verma, Devendra <[email protected]>
Cc: [email protected]; [email protected]; [email protected]; [email protected]; [email protected]; linux- [email protected]; Simek, Michal <[email protected]>
Subject: Re: [PATCH v8 1/2] dmaengine: dw-edma: Add AMD MDB Endpoint Support
[Removed some extra headers to reduce the size of the mail]
Quoted 118 lines
Quoted 70 lines
Quoted 70 lines
Quoted 47 lines
Quoted 47 lines · Devendra K Verma
Quoted 46 lines
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 <[email protected]>---
Changes in v8:
Changed the contant names to includer product vendor. Moved the vendor specific code to vendor specific functions.Changes in v7:
Introduced vendor specific functions to retrieve the vsec data.Changes in v6:
Included "sizes.h" header and used the appropriate definitions instead of constants.Changes in v5:
Added the definitions for Xilinx specific VSEC header id, revision, and register offsets.
Corrected the error type when no physical offset found for device side memory.
Corrected the order of variables.Changes in v4:
Configured 8 read and 8 write channels for Xilinx vendor Added checks to validate vendor ID for vendor specific vsec id. Added Xilinx specific vendor id for vsec specific to Xilinx Added the LL and data region offsets, size as input params to functiondw_edma_set_chan_region_offset().
Moved the LL and data region offsets assignment to function for Xilinx specific case.
Corrected comments.Changes in v3:
Corrected a typo when assigning AMD (Xilinx) vsec id macro and condition check.Changes in v2:
Reverted thedevmem_phys_offtype to u64.
Renamed the function appropriately to suit the functionality for setting the LL & data region offsets.Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Changes in v1:
Removed the pci device id frompci_ids.hfile.
Added the vendor id macro as per the suggested method. Changed the type of the newly addeddevmem_phys_offvariable. Added to logic to assign offsets for LL and data region blocks in case more number of channels are enabled than given in
amd_mdb_datastruct.Quoted 16 lines
Quoted 16 lines
Quoted 16 lines
--- drivers/dma/dw-edma/dw-edma-pcie.c | 192 ++++++++++++++++++++++++++++++++++--- 1 file changed, 178 insertions(+), 14 deletions(-)drivers/dma/dw-edma/dw-edma-pcie.c +1
-0@@ -14,14 +14,35 @@#include <linux/pci-epf.h> #include <linux/msi.h> #include <linux/bitfield.h> +#include <linux/sizes.h> Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
drivers/dma/dw-edma/dw-edma-pcie.c
Quoted 7 lines
drivers/dma/dw-edma/dw-edma-pcie.c +0
-5#include "dw-edma-core.h" -#define DW_PCIE_VSEC_DMA_ID 0x6 -#define DW_PCIE_VSEC_DMA_BAR GENMASK(10, 8) -#define DW_PCIE_VSEC_DMA_MAP GENMASK(2, 0) -#define DW_PCIE_VSEC_DMA_WR_CH GENMASK(9, 0) -#define DW_PCIE_VSEC_DMA_RD_CH GENMASK(25,16)
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
drivers/dma/dw-edma/dw-edma-pcie.c
Quoted 3 lines
drivers/dma/dw-edma/dw-edma-pcie.c +3
-0+/* Synopsys */ +#define DW_PCIE_SYNOPSYS_VSEC_DMA_ID 0x6 +#define DW_PCIE_SYNOPSYS_VSEC_DMA_BAR GENMASK(10,
Quoted 2 lines
Quoted 2 lines
8)
Quoted 1 line
Quoted 1 line
Quoted 1 line
drivers/dma/dw-edma/dw-edma-pcie.c +1
-0+#define DW_PCIE_SYNOPSYS_VSEC_DMA_MAP
GENMASK(2, 0)Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
drivers/dma/dw-edma/dw-edma-pcie.c line 25
Quoted 1 line
drivers/dma/dw-edma/dw-edma-pcie.c +1
-0+#define DW_PCIE_SYNOPSYS_VSEC_DMA_WR_CH GENMASK(9,
Quoted 2 lines
Quoted 2 lines
0)
Quoted 1 line
Quoted 1 line
Quoted 1 line
drivers/dma/dw-edma/dw-edma-pcie.c +1
-0+#define DW_PCIE_SYNOPSYS_VSEC_DMA_RD_CH GENMASK(25,
Quoted 19 lines
Quoted 19 lines
16)
Quoted 5 lines
Quoted 4 lines
Sorry, jump into at v8.
According to my understand 'DW' means 'Synopsys'.Quoted 7 lines
Yes, DW means Designware representing Synopsys here. For the sake of clarity, a distinction was required to separate the names of macros having the similar purpose for other IP, Xilinx in this case. Otherwise, it is causing confusion which macros to use for which vendor. This also helps in future if any of the vendors try to retrieve a new or different VSEC IDs then all they need is to define macros
which clearly show the association with the vendor, thus eliminating the confusion.
If want to reuse the driver, driver owner take reponsiblity to find the difference.
Quoted 8 lines
Quoted 2 lines
If define a whole set of register, the reader is hard to find real difference.
It is not regarding the register set rather VSEC capability which can differ in the purpose even for the similar IPs. As is the current case where one VSEC ID serves the similar purpose for both the IPs while the VSEC ID =
0x20differs in meaning for Synopsys and Xilinx thus I think it is OK to define new macros as long as they do not create confusion.
Quoted 4 lines
But need put rename existing macro to new patches. And I think use XILINX_PCIE_MDB_* should be enough without renaming. Everyone know DW is SYNOPSYS.
As the current addition of the code related to Xilinx piggybacking on the existing DW code the prefix "DW" was added to the macros related to Xilinx as well. The format available in the file has been followed.
When a necessity arises then perhaps the files can be separated and the name suggestion would clearly indicate the distinction and difference required between these two drivers.
Thanks to the reviewer(s), I had received multiple reviews regarding the naming and finally it was agreed upon the convention available in this version.
Please check the discussion in the following thread:
https://lore.kernel.org/all/SA1PR12MB81204C807C2F7C72730EC82295ADA@SA1PR12MB8120.namprd12.prod.outlook.com/
Quoted 49 lines
Quoted 9 lines
Quoted 9 lines
Quoted 9 lines
Quoted 9 lines
drivers/dma/dw-edma/dw-edma-pcie.c
Quoted 9 lines
drivers/dma/dw-edma/dw-edma-pcie.c +7
-0+ +/* AMD MDB (Xilinx) specific defines */ +#define PCI_DEVICE_ID_XILINX_B054 0xb054 + +#define DW_PCIE_XILINX_MDB_VSEC_DMA_ID 0x6 +#define DW_PCIE_XILINX_MDB_VSEC_ID 0x20 +#define DW_PCIE_XILINX_MDB_VSEC_DMA_BAR GENMASK(10,
Quoted 2 lines
Quoted 2 lines
8)
Quoted 1 line
Quoted 1 line
Quoted 1 line
drivers/dma/dw-edma/dw-edma-pcie.c +1
-0+#define DW_PCIE_XILINX_MDB_VSEC_DMA_MAP GENMASK(2,
Quoted 2 lines
Quoted 2 lines
0)
Quoted 1 line
Quoted 1 line
Quoted 1 line
drivers/dma/dw-edma/dw-edma-pcie.c +1
-0+#define DW_PCIE_XILINX_MDB_VSEC_DMA_WR_CH GENMASK(9,0)
Quoted 6 lines
Quoted 6 lines
Quoted 1 line
Quoted 1 line
drivers/dma/dw-edma/dw-edma-pcie.c line 36
Quoted 1 line
drivers/dma/dw-edma/dw-edma-pcie.c +1
-0+#define DW_PCIE_XILINX_MDB_VSEC_DMA_RD_CH GENMASK(25,16)
Quoted 4 lines
Quoted 3 lines
These defination is the same. Need redefine again
...
Quoted 8 lines
Quoted 8 lines
Quoted 4 lines
As explained above, the name change is required to avoid confusion. The trigger to have the separate names for each IP is the inclusion of Xilinx IP that is why no separate patch is created.
Separate patch renmae macro only. Reviewer can simple bypass this typo trivial patch.
Quoted 7 lines
Quoted 5 lines
Then add new one.
Actually, Needn't rename at all. You can directly use XLINNK_PCIE_*
Frank
Please check the discussion on previous versions of the same patch series.
It'd better you put link here to support your purposal.
Quoted 8 lines
We have this patch as the outcome of those discussions.
Other reviewing members felt it that keeping the name similar for the VSEC ID having similar purpose for two different IPs was causing the confusion that is why it was agreed upon the separate out the naming as per the vendor-name of VSEC ID. Regarding the separate patch, the reason is introduction of the new IP which mostly supports the similar functionality except in case of VSEC IDs that's why the name separation became part of these patches. It sets the context for changing
Quoted 6 lines
the name of the existing macros.
If put trivial big part to new patch to reduce, it will reduce review efforts.
Frank
As requested, a link related to discussion in this regard is available on the above comments, please take a look.
Quoted 137 lines
Quoted 11 lines
Quoted 11 lines
Quoted 11 lines
Quoted 11 lines
drivers/dma/dw-edma/dw-edma-pcie.c static void
Quoted 6 lines
pci_read_config_dword(pdev, vsec + 0x14, &val); off = val;drivers/dma/dw-edma/dw-edma-pcie.c +0
-0@@ -157,6 +237,67 @@ static voiddw_edma_pcie_get_vsec_dma_data(struct
pci_dev*pdev,Quoted 4 lines
drivers/dma/dw-edma/dw-edma-pcie.c +1
-0pdata->rg.off = off; } +static void dw_edma_pcie_get_xilinx_dma_data(struct pci_dev*pdev,
Quoted 125 lines
Quoted 125 lines
Quoted 8 lines
Quoted 8 lines
drivers/dma/dw-edma/dw-edma-pcie.c static void dw_edma_pcie_get_vsec_dma_data(struct pci_dev *pdev,
Quoted 8 lines
drivers/dma/dw-edma/dw-edma-pcie.c +8
-0+struct +dw_edma_pcie_data +*pdata) { +u32 val, map; +u16 vsec; +u64 off; + + pdata->devmem_phys_off =
DW_PCIE_XILINX_MDB_INVALID_ADDR;Quoted 14 lines
Quoted 14 lines
drivers/dma/dw-edma/dw-edma-pcie.c static void dw_edma_pcie_get_vsec_dma_data(struct pci_dev *pdev,
Quoted 13 lines
drivers/dma/dw-edma/dw-edma-pcie.c +13
-0+ + vsec =pci_find_vsec_capability (pdev,PCI_VENDOR_ID_XILINX , +DW_PCIE_XILINX_MDB_VSEC_DMA_ID ); +if (!vsec) +return ; + +pci_read_config_dword (pdev, vsec +PCI_VNDR_HEADER , &val); +if (PCI_VNDR_HEADER_REV (val) !=0x00 || +PCI_VNDR_HEADER_LEN (val) !=0x18 ) +return ; + + pci_dbg(pdev, "Detected Xilinx PCIe Vendor-Specific + Extended CapabilityDMA\n");
Quoted 10 lines
Quoted 10 lines
drivers/dma/dw-edma/dw-edma-pcie.c static void dw_edma_pcie_get_vsec_dma_data(struct pci_dev *pdev,
Quoted 10 lines
drivers/dma/dw-edma/dw-edma-pcie.c +10
-0+pci_read_config_dword (pdev, vsec +0x8 , &val); + map =FIELD_GET (DW_PCIE_XILINX_MDB_VSEC_DMA_MAP , val); +if (map !=EDMA_MF_EDMA_LEGACY && + map !=EDMA_MF_EDMA_UNROLL && + map !=EDMA_MF_HDMA_COMPAT && + map !=EDMA_MF_HDMA_NATIVE ) +return ; + + pdata->mf = map; + pdata->rg.bar =FIELD_GET(DW_PCIE_XILINX_MDB_VSEC_DMA_BAR,
Quoted 17 lines
Quoted 17 lines
val);
drivers/dma/dw-edma/dw-edma-pcie.c static void dw_edma_pcie_get_vsec_dma_data(struct pci_dev *pdev,
Quoted 5 lines
drivers/dma/dw-edma/dw-edma-pcie.c +5
-0+ +pci_read_config_dword (pdev, vsec +0xc , &val); + pdata->wr_ch_cnt = min_t(u16, pdata->wr_ch_cnt, + + FIELD_GET(DW_PCIE_XILINX_MDB_VSEC_DMA_WR_CH,val));
Quoted 10 lines
drivers/dma/dw-edma/dw-edma-pcie.c +10
-0+ pdata->rd_ch_cnt =min_t (u16, pdata->rd_ch_cnt, + +FIELD_GET (DW_PCIE_XILINX_MDB_VSEC_DMA_RD_CH , val)); + +pci_read_config_dword (pdev, vsec +0x14 , &val); + off = val; +pci_read_config_dword (pdev, vsec +0x10 , &val); + off <<=32 ; + off |= val; + pdata->rg.off = off;Quoted 8 lines
Quoted 8 lines
drivers/dma/dw-edma/dw-edma-pcie.c static void dw_edma_pcie_get_vsec_dma_data(struct pci_dev *pdev,
Quoted 8 lines
drivers/dma/dw-edma/dw-edma-pcie.c +8
-0+ + vsec =pci_find_vsec_capability (pdev,PCI_VENDOR_ID_XILINX , +DW_PCIE_XILINX_MDB_VSEC_ID ); +if (!vsec) +return ; + + pci_read_config_dword(pdev, + vsec +
DW_PCIE_XILINX_MDB_DEVMEM_OFF_REG_HIGH,Quoted 4 lines
Quoted 4 lines
drivers/dma/dw-edma/dw-edma-pcie.c static void dw_edma_pcie_get_vsec_dma_data(struct pci_dev *pdev,
Quoted 4 lines
drivers/dma/dw-edma/dw-edma-pcie.c +4
-0+ &val); + off = val; + pci_read_config_dword(pdev, + vsec +
DW_PCIE_XILINX_MDB_DEVMEM_OFF_REG_LOW,Quoted 9 lines
Quoted 9 lines
Quoted 9 lines
drivers/dma/dw-edma/dw-edma-pcie.c +5
-0+ &val); + off <<=32 ; + off |= val; + pdata->devmem_phys_off = off; } +static int dw_edma_pcie_probe (struct pci_dev *pdev,const struct pci_device_id *pid){ @@
-184,7 +325,28 @@ static int dw_edma_pcie_probe(structpci_dev*pdev,
Quoted 50 lines
Quoted 9 lines
drivers/dma/dw-edma/dw-edma-pcie.c static int dw_edma_pcie_probe(struct pci_dev *pdev, · line 331
Quoted 8 lines
* Tries to find if exists a PCIe Vendor-Specific Extended Capability
* for the DMA, if one exists, then reconfigures it.
*/drivers/dma/dw-edma/dw-edma-pcie.c +4
-1-dw_edma_pcie_get_vsec_dma_data (pdev, vsec_data); +dw_edma_pcie_get_synopsys_dma_data (pdev, vsec_data); +dw_edma_pcie_get_xilinx_dma_data (pdev, vsec_data); + +if (pdev->vendor ==PCI_VENDOR_ID_XILINX ) {Quoted 3 lines
dw_edma_pcie_get_xilinx_dma_data()should be here.Frank
Yes, this is good suggestion. Thanks!
Quoted 35 lines
drivers/dma/dw-edma/dw-edma-pcie.c static int dw_edma_pcie_probe(struct pci_dev *pdev,
Quoted 5 lines
drivers/dma/dw-edma/dw-edma-pcie.c +5
-0+/* +* There is no valid address found for the LL memory +* space on the device side. +*/ + if (vsec_data->devmem_phys_off ==
DW_PCIE_XILINX_MDB_INVALID_ADDR)Quoted 29 lines
drivers/dma/dw-edma/dw-edma-pcie.c +13
-0+return -ENOMEM ; + +/* +* Configure the channel LL and data blocks if number of +* channels enabled in VSEC capability are more than the +* channels configured in xilinx_mdb_data. +*/ +dw_edma_set_chan_region_offset (vsec_data,BAR_2 ,0 , +DW_PCIE_XILINX_MDB_LL_OFF_GAP , +DW_PCIE_XILINX_MDB_LL_SIZE , +DW_PCIE_XILINX_MDB_DT_OFF_GAP , +DW_PCIE_XILINX_MDB_DT_SIZE ); + }/* Mapping PCI BAR regions */ mask = BIT(vsec_data->rg.bar); @@ -367,6 +529,8 @@static void dw_edma_pcie_remove(struct
pci_dev
*pdev)static const struct
pci_device_iddw_edma_pcie_id_table[] = {
{PCI_DEVICE_DATA(SYNOPSYS, EDDA, &snps_edda_data)},drivers/dma/dw-edma/dw-edma-pcie.c +2
-1+ {PCI_VDEVICE (XILINX ,PCI_DEVICE_ID_XILINX_B054 ), + (kernel_ulong_t)&xilinx_mdb_data }, { } };MODULE_DEVICE_TABLE (pci, dw_edma_pcie_id_table); --1.8.3.1
PATCH v8 2/2 dmaengine: dw-edma: Add non-LL mode
In reply to Devendra K VermaAMD MDB IP supports Linked List (LL) mode as well as non-LL mode. The current code does not have the mechanisms to enable the DMA transactions using the non-LL mode. The following two cases are added with this patch:
- For the AMD (Xilinx) only, when a valid physical base address of the device side DDR is not configured, then the IP can still be used in non-LL mode. For all the channels DMA transactions will be using the non-LL mode only. This, the default non-LL mode, is not applicable for Synopsys IP with the current code addition.
- If the default mode is LL-mode, for both AMD (Xilinx) and Synosys, and if user wants to use non-LL mode then user can do so via configuring the peripheral_config param of dma_slave_config.
---
Changes in v8
Cosmetic change related to comment and code.
Changes in v7
No change
Changes in v6
Gave definition to bits used for channel configuration. Removed the comment related to doorbell.
Changes in v5
Variable name 'nollp' changed to 'non_ll'.
In the dw_edma_device_config() WARN_ON replaced with dev_err(). Comments follow the 80-column guideline.
Changes in v4
No change
Changes in v3
No change
Changes in v2
Reverted the function return type to u64 for
dw_edma_get_phys_addr().
Changes in v1
Changed the function return type for dw_edma_get_phys_addr(). Corrected the typo raised in review.
--- drivers/dma/dw-edma/dw-edma-core.c | 42 +++++++++++++++++++++--- drivers/dma/dw-edma/dw-edma-core.h | 1 + drivers/dma/dw-edma/dw-edma-pcie.c | 46 ++++++++++++++++++-------- drivers/dma/dw-edma/dw-hdma-v0-core.c | 61 ++++++++++++++++++++++++++++++++++- drivers/dma/dw-edma/dw-hdma-v0-regs.h | 1 + include/linux/dma/edma.h | 1 + 6 files changed, 132 insertions(+), 20 deletions(-)
drivers/dma/dw-edma/dw-edma-core.c +37 -5
@@ -223,8 +223,32 @@ static int dw_edma_device_config(struct dma_chan *dchan, struct dma_slave_config *config) {struct dw_edma_chan *chan =dchan2dw_edma_chan (dchan); +int non_ll =0 ; + +if (config->peripheral_config && + config->peripheral_size !=sizeof (int )) { +dev_err (dchan->device->dev, +"config param peripheral size mismatch\n" ); +return -EINVAL ; + }memcpy (&chan->config, config,sizeof (*config)); + +/* +* When there is no valid LLP base address available then the default +* DMA ops will use the non-LL mode. +* +* Cases where LL mode is enabled and client wants to use the non-LL +* mode then also client can do so via providing the peripheral_config +* param. +*/ +if (config->peripheral_config) + non_ll = *(int *)config->peripheral_config; + + chan->non_ll = false; +if (chan->dw->chip->non_ll || (!chan->dw->chip->non_ll && non_ll)) + chan->non_ll = true; + chan->configured = true;return 0 ;
@@ -353,7 +377,7 @@ static void dw_edma_device_issue_pending(struct dma_chan *dchan)struct dw_edma_chan *chan =dchan2dw_edma_chan (xfer->dchan);enum dma_transfer_direction dir = xfer->direction;struct scatterlist *sg =NULL ; -struct dw_edma_chunk *chunk; +struct dw_edma_chunk *chunk =NULL ;struct dw_edma_burst *burst;struct dw_edma_desc *desc;u64 src_addr, dst_addr;
@@ -419,9 +443,11 @@ static void dw_edma_device_issue_pending(struct dma_chan *dchan)if (unlikely (!desc)) goto err_alloc; - chunk =dw_edma_alloc_chunk (desc); -if (unlikely (!chunk)) - goto err_alloc; +if (!chan->non_ll) { + chunk =dw_edma_alloc_chunk (desc); +if (unlikely (!chunk)) + goto err_alloc; + }if (xfer->type ==EDMA_XFER_INTERLEAVED ) { src_addr = xfer->xfer.il->src_start;
@@ -450,7 +476,13 @@ static void dw_edma_device_issue_pending(struct dma_chan *dchan)if (xfer->type ==EDMA_XFER_SCATTER_GATHER && !sg)break ; -if (chunk->bursts_alloc == chan->ll_max) { +/* +* For non-LL mode, only a single burst can be handled +* in a single chunk unlike LL mode where multiple bursts +* can be configured in a single chunk. +*/ +if ((chunk && chunk->bursts_alloc == chan->ll_max) || + chan->non_ll) { chunk =dw_edma_alloc_chunk (desc);if (unlikely (!chunk)) goto err_alloc;
drivers/dma/dw-edma/dw-edma-core.h +1 -0
@@ -86,6 +86,7 @@ struct dw_edma_chan {u8 configured;struct dma_slave_config config; +bool non_ll; };struct dw_edma_irq {
drivers/dma/dw-edma/dw-edma-pcie.c +32 -14
111 lines not on this page · raw message
drivers/dma/dw-edma/dw-hdma-v0-core.c +60 -1
73 lines not on this page · raw message
drivers/dma/dw-edma/dw-hdma-v0-regs.h +1 -0
@@ -12,6 +12,7 @@#include <linux/dmaengine.h> #define HDMA_V0_MAX_NR_CH 8 +#define HDMA_V0_CH_EN BIT(0)#define HDMA_V0_LOCAL_ABORT_INT_EN BIT(6)#define HDMA_V0_REMOTE_ABORT_INT_EN BIT(5)#define HDMA_V0_LOCAL_STOP_INT_EN BIT(4)
include/linux/dma/edma.h +1 -0
@@ -99,6 +99,7 @@ struct dw_edma_chip {enum dw_edma_map_format mf;struct dw_edma *dw; +bool non_ll; };/* Export to the platform drivers */
Signature · 1 line
1.8.3.1
Re: [PATCH v8 2/2] dmaengine: dw-edma: Add non-LL mode
Quoted 7 lines · Devendra K Verma
AMD MDB IP supports Linked List (LL) mode as well as non-LL mode. The current code does not have the mechanisms to enable the DMA transactions using the non-LL mode. The following two cases are added with this patch:
- For the AMD (Xilinx) only, when a valid physical base address of the device side DDR is not configured, then the IP can still be used in non-LL mode. For all the channels DMA transactions will
If DDR have not configured, where DATA send to in device side by non-LL mode.
Quoted 37 lines
be using the non-LL mode only. This, the default non-LL mode, is not applicable for Synopsys IP with the current code addition.
- If the default mode is LL-mode, for both AMD (Xilinx) and Synosys, and if user wants to use non-LL mode then user can do so via configuring the
peripheral_configparam ofdma_slave_config.Signed-off-by Devendra K Verma <[email protected]>---
Changes in v8
Cosmetic change related to comment and code.Changes in v7
No changeChanges in v6
Gave definition to bits used for channel configuration. Removed the comment related to doorbell.Changes in v5
Variable name 'nollp' changed to 'non_ll'.
In thedw_edma_device_config()WARN_ONreplaced withdev_err(). Comments follow the 80-column guideline.Changes in v4
No changeChanges in v3
No changeChanges in v2
Reverted the function return type to u64 for
dw_edma_get_phys_addr().Changes in v1
Changed the function return type fordw_edma_get_phys_addr(). Corrected the typo raised in review.
Quoted 6 lines
--- drivers/dma/dw-edma/dw-edma-core.c | 42 +++++++++++++++++++++--- drivers/dma/dw-edma/dw-edma-core.h | 1 + drivers/dma/dw-edma/dw-edma-pcie.c | 46 ++++++++++++++++++-------- drivers/dma/dw-edma/dw-hdma-v0-core.c | 61 ++++++++++++++++++++++++++++++++++- drivers/dma/dw-edma/dw-hdma-v0-regs.h | 1 +
edma-v0-core.c have not update, if don't support, at least need return failure at dw_edma_device_config() when backend is eDMA.
Quoted 51 lines
include/linux/dma/edma.h | 1 + 6 files changed, 132 insertions(+), 20 deletions(-)drivers/dma/dw-edma/dw-edma-core.c +25
-1@@ -223,8 +223,32 @@ static int dw_edma_device_config(struct dma_chan *dchan, struct dma_slave_config *config) {struct dw_edma_chan *chan =dchan2dw_edma_chan (dchan); +int non_ll =0 ; + +if (config->peripheral_config && + config->peripheral_size !=sizeof (int )) { +dev_err (dchan->device->dev, +"config param peripheral size mismatch\n" ); +return -EINVAL ; + }memcpy (&chan->config, config,sizeof (*config)); + +/* +* When there is no valid LLP base address available then the default +* DMA ops will use the non-LL mode. +* +* Cases where LL mode is enabled and client wants to use the non-LL +* mode then also client can do so via providing the peripheral_config +* param. +*/ +if (config->peripheral_config) + non_ll = *(int *)config->peripheral_config; + + chan->non_ll = false; +if (chan->dw->chip->non_ll || (!chan->dw->chip->non_ll && non_ll)) + chan->non_ll = true; + chan->configured = true;return 0 ;@@ -353,7 +377,7 @@ static void dw_edma_device_issue_pending(struct dma_chan *dchan)struct dw_edma_chan *chan =dchan2dw_edma_chan (xfer->dchan);enum dma_transfer_direction dir = xfer->direction;struct scatterlist *sg =NULL ; -struct dw_edma_chunk *chunk; +struct dw_edma_chunk *chunk =NULL ;struct dw_edma_burst *burst;struct dw_edma_desc *desc;u64 src_addr, dst_addr;@@ -419,9 +443,11 @@ static void dw_edma_device_issue_pending(struct dma_chan *dchan)if (unlikely (!desc))
drivers/dma/dw-edma/dw-edma-core.c static void dw_edma_device_issue_pending(struct dma_chan *dchan) · line 450
Quoted 10 lines
drivers/dma/dw-edma/dw-edma-core.c +5
-3goto err_alloc; - chunk =dw_edma_alloc_chunk (desc); -if (unlikely (!chunk)) - goto err_alloc; +if (!chan->non_ll) { + chunk =dw_edma_alloc_chunk (desc); +if (unlikely (!chunk)) + goto err_alloc; + }
non_ll is the same as ll_max = 1. (or 2, there are link back entry).
If you set ll_max = 1, needn't change this code.
Quoted 109 lines
drivers/dma/dw-edma/dw-edma-core.c +7
-1if (xfer->type ==EDMA_XFER_INTERLEAVED ) { src_addr = xfer->xfer.il->src_start;@@ -450,7 +476,13 @@ static void dw_edma_device_issue_pending(struct dma_chan *dchan)if (xfer->type ==EDMA_XFER_SCATTER_GATHER && !sg)break ; -if (chunk->bursts_alloc == chan->ll_max) { +/* +* For non-LL mode, only a single burst can be handled +* in a single chunk unlike LL mode where multiple bursts +* can be configured in a single chunk. +*/ +if ((chunk && chunk->bursts_alloc == chan->ll_max) || + chan->non_ll) { chunk =dw_edma_alloc_chunk (desc);if (unlikely (!chunk)) goto err_alloc;drivers/dma/dw-edma/dw-edma-core.h +1
-0@@ -86,6 +86,7 @@ struct dw_edma_chan {u8 configured;struct dma_slave_config config; +bool non_ll; };struct dw_edma_irq {drivers/dma/dw-edma/dw-edma-pcie.c +23
-9@@ -298,6 +298,15 @@ static void dw_edma_pcie_get_xilinx_dma_data(struct pci_dev *pdev, pdata->devmem_phys_off = off; } +static u64 dw_edma_get_phys_addr (struct pci_dev *pdev, +struct dw_edma_pcie_data *pdata, +enum pci_barno bar) +{ +if (pdev->vendor ==PCI_VENDOR_ID_XILINX ) +return pdata->devmem_phys_off; +return pci_bus_address (pdev, bar); +} +static int dw_edma_pcie_probe (struct pci_dev *pdev,const struct pci_device_id *pid) {@@ -307,6 +316,7 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,struct dw_edma_chip *chip;int err, nr_irqs;int i, mask; +bool non_ll = false; vsec_data =kmalloc (sizeof (*vsec_data),GFP_KERNEL );if (!vsec_data)@@ -331,21 +341,24 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,if (pdev->vendor ==PCI_VENDOR_ID_XILINX ) {/* * There is no valid address found for the LL memory -* space on the device side. +* space on the device side. In the absence of LL base +* address use the non-LL mode or simple mode supported by +* the HDMA IP. */ -if (vsec_data->devmem_phys_off ==DW_PCIE_XILINX_MDB_INVALID_ADDR ) -return -ENOMEM ; +if (vsec_data->devmem_phys_off ==DW_PCIE_AMD_MDB_INVALID_ADDR ) + non_ll = true;/* * Configure the channel LL and data blocks if number of * channels enabled in VSEC capability are more than the * channels configured in xilinx_mdb_data. */ -dw_edma_set_chan_region_offset (vsec_data,BAR_2 ,0 , -DW_PCIE_XILINX_MDB_LL_OFF_GAP , -DW_PCIE_XILINX_MDB_LL_SIZE , -DW_PCIE_XILINX_MDB_DT_OFF_GAP , -DW_PCIE_XILINX_MDB_DT_SIZE ); +if (!non_ll) +dw_edma_set_chan_region_offset (vsec_data,BAR_2 ,0 , +DW_PCIE_XILINX_LL_OFF_GAP , +DW_PCIE_XILINX_LL_SIZE , +DW_PCIE_XILINX_DT_OFF_GAP , +DW_PCIE_XILINX_DT_SIZE ); }/* Mapping PCI BAR regions */ @@ -393,6 +406,7 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev, chip->mf = vsec_data->mf; chip->nr_irqs = nr_irqs; chip->ops = &dw_edma_pcie_plat_ops; + chip->non_ll = non_ll; chip->ll_wr_cnt = vsec_data->wr_ch_cnt; chip->ll_rd_cnt = vsec_data->rd_ch_cnt;@@ -401,7 +415,7 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,if (!chip->reg_base)return -ENOMEM ; -for (i =0 ; i < chip->ll_wr_cnt; i++) { +for (i =0 ; i < chip->ll_wr_cnt && !non_ll; i++) {struct dw_edma_region *ll_region = &chip->ll_region_wr[i];struct dw_edma_region *dt_region = &chip->dt_region_wr[i];struct dw_edma_block *ll_block = &vsec_data->ll_wr[i];
drivers/dma/dw-edma/dw-edma-pcie.c static int dw_edma_pcie_probe(struct pci_dev *pdev, · line 430
Quoted 6 lines
drivers/dma/dw-edma/dw-edma-pcie.c +2
-1@@ -412,7 +426,8 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,return -ENOMEM ; ll_region->vaddr.io += ll_block->off; - ll_region->paddr =pci_bus_address (pdev, ll_block->bar); + ll_region->paddr =dw_edma_get_phys_addr (pdev, vsec_data, + ll_block->bar);
This change need do prepare patch, which only change pci_bus_address() to dw_edma_get_phys_addr().
Quoted 54 lines
drivers/dma/dw-edma/dw-edma-pcie.c +7
-4ll_region->paddr += ll_block->off; ll_region->sz = ll_block->sz;@@ -421,12 +436,13 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,return -ENOMEM ; dt_region->vaddr.io += dt_block->off; - dt_region->paddr =pci_bus_address (pdev, dt_block->bar); + dt_region->paddr =dw_edma_get_phys_addr (pdev, vsec_data, + dt_block->bar); dt_region->paddr += dt_block->off; dt_region->sz = dt_block->sz; } -for (i =0 ; i < chip->ll_rd_cnt; i++) { +for (i =0 ; i < chip->ll_rd_cnt && !non_ll; i++) {struct dw_edma_region *ll_region = &chip->ll_region_rd[i];struct dw_edma_region *dt_region = &chip->dt_region_rd[i];struct dw_edma_block *ll_block = &vsec_data->ll_rd[i];@@ -437,7 +453,8 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,return -ENOMEM ; ll_region->vaddr.io += ll_block->off; - ll_region->paddr =pci_bus_address (pdev, ll_block->bar); + ll_region->paddr =dw_edma_get_phys_addr (pdev, vsec_data, + ll_block->bar); ll_region->paddr += ll_block->off; ll_region->sz = ll_block->sz;@@ -446,7 +463,8 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,return -ENOMEM ; dt_region->vaddr.io += dt_block->off; - dt_region->paddr =pci_bus_address (pdev, dt_block->bar); + dt_region->paddr =dw_edma_get_phys_addr (pdev, vsec_data, + dt_block->bar); dt_region->paddr += dt_block->off; dt_region->sz = dt_block->sz; }drivers/dma/dw-edma/dw-hdma-v0-core.c +1
-1@@ -225,7 +225,7 @@ static void dw_hdma_v0_sync_ll_data(struct dw_edma_chunk *chunk)readl (chunk->ll_region.vaddr.io); } -static void dw_hdma_v0_core_start (struct dw_edma_chunk *chunk,bool first) +static void dw_hdma_v0_core_ll_start (struct dw_edma_chunk *chunk,bool first) {struct dw_edma_chan *chan = chunk->chan;struct dw_edma *dw = chan->dw;@@ -263,6 +263,65 @@ static void dw_hdma_v0_core_start(struct dw_edma_chunk *chunk, bool first)SET_CH_32 (dw, chan->dir, chan->id, doorbell,HDMA_V0_DOORBELL_START );
drivers/dma/dw-edma/dw-hdma-v0-core.c static void dw_hdma_v0_core_start(struct dw_edma_chunk *chunk, bool first) · line 273
Quoted 10 lines
drivers/dma/dw-edma/dw-hdma-v0-core.c +8
-0} +static void dw_hdma_v0_core_non_ll_start (struct dw_edma_chunk *chunk) +{ +struct dw_edma_chan *chan = chunk->chan; +struct dw_edma *dw = chan->dw; +struct dw_edma_burst *child; +u32 val; + +list_for_each_entry (child, &chunk->burst->list, list) {
why need iterated list, it doesn't support ll. Need wait for irq to start next one.
Frank
Quoted 81 lines
drivers/dma/dw-edma/dw-hdma-v0-core.c +51
-0+SET_CH_32 (dw, chan->dir, chan->id, ch_en,HDMA_V0_CH_EN ); + +/* Source address */ +SET_CH_32 (dw, chan->dir, chan->id, sar.lsb, +lower_32_bits (child->sar)); +SET_CH_32 (dw, chan->dir, chan->id, sar.msb, +upper_32_bits (child->sar)); + +/* Destination address */ +SET_CH_32 (dw, chan->dir, chan->id, dar.lsb, +lower_32_bits (child->dar)); +SET_CH_32 (dw, chan->dir, chan->id, dar.msb, +upper_32_bits (child->dar)); + +/* Transfer size */ +SET_CH_32 (dw, chan->dir, chan->id, transfer_size, child->sz); + +/* Interrupt setup */ + val =GET_CH_32 (dw, chan->dir, chan->id, int_setup) | +HDMA_V0_STOP_INT_MASK | +HDMA_V0_ABORT_INT_MASK | +HDMA_V0_LOCAL_STOP_INT_EN | +HDMA_V0_LOCAL_ABORT_INT_EN ; + +if (!(dw->chip->flags &DW_EDMA_CHIP_LOCAL )) { + val |=HDMA_V0_REMOTE_STOP_INT_EN | +HDMA_V0_REMOTE_ABORT_INT_EN ; + } + +SET_CH_32 (dw, chan->dir, chan->id, int_setup, val); + +/* Channel control setup */ + val =GET_CH_32 (dw, chan->dir, chan->id, control1); + val &= ~HDMA_V0_LINKLIST_EN ; +SET_CH_32 (dw, chan->dir, chan->id, control1, val); + +SET_CH_32 (dw, chan->dir, chan->id, doorbell, +HDMA_V0_DOORBELL_START ); + } +} + +static void dw_hdma_v0_core_start (struct dw_edma_chunk *chunk,bool first) +{ +struct dw_edma_chan *chan = chunk->chan; + +if (chan->non_ll) +dw_hdma_v0_core_non_ll_start (chunk); +else +dw_hdma_v0_core_ll_start (chunk, first); +} +static void dw_hdma_v0_core_ch_config (struct dw_edma_chan *chan) {struct dw_edma *dw = chan->dw;drivers/dma/dw-edma/dw-hdma-v0-regs.h +1
-0@@ -12,6 +12,7 @@#include <linux/dmaengine.h> #define HDMA_V0_MAX_NR_CH 8 +#define HDMA_V0_CH_EN BIT(0)#define HDMA_V0_LOCAL_ABORT_INT_EN BIT(6)#define HDMA_V0_REMOTE_ABORT_INT_EN BIT(5)#define HDMA_V0_LOCAL_STOP_INT_EN BIT(4)include/linux/dma/edma.h +1
-1@@ -99,6 +99,7 @@ struct dw_edma_chip {enum dw_edma_map_format mf;struct dw_edma *dw; +bool non_ll; };/* Export to the platform drivers */ --1.8.3.1
RE: [PATCH v8 2/2] dmaengine: dw-edma: Add non-LL mode
[AMD Official Use Only - AMD Internal Distribution Only]
Hi Frank
Please check my response inline.
Regards,
Devendra
Quoted 22 lines
-----Original Message-----
From: Frank Li <[email protected]>
Sent: Thursday, January 15, 2026 10:07 PM
To: Verma, Devendra <[email protected]>
Cc: [email protected]; [email protected]; [email protected]; [email protected]; [email protected]; linux- [email protected]; Simek, Michal <[email protected]>
Subject: Re: [PATCH v8 2/2] dmaengine: dw-edma: Add non-LL modeCaution: This message originated from an External Source. Use proper caution when opening attachments, clicking links, or responding.
Quoted 7 lines · Devendra K Verma
AMD MDB IP supports Linked List (LL) mode as well as non-LL mode. The current code does not have the mechanisms to enable the DMA transactions using the non-LL mode. The following two cases are added with this patch:
- For the AMD (Xilinx) only, when a valid physical base address of the device side DDR is not configured, then the IP can still be used in non-LL mode. For all the channels DMA transactions will
Quoted 3 lines
If DDR have not configured, where DATA send to in device side by non-LL mode.
The DDR base address in the VSEC capability is used for driving the DMA transfers when used in the LL mode. The DDR is configured and present all the time but the DMA PCIe driver uses this DDR base address (physical address) to configure the LLP address.
In the scenario, where this DDR base address in VSEC capability is not configured then the current controller cannot be used as the default mode supported is LL mode only. In order to make the controller usable non-LL mode is being added which just needs SAR, DAR, XFERLEN and control register to initiate the transfer. So, the DDR is always present, but the DMA PCIe driver need to know the DDR base physical address to make the transfer. This is useful in scenarios where the memory allocated for LL can be used for DMA transactions as well.
Quoted 113 lines
Quoted 37 lines
be using the non-LL mode only. This, the default non-LL mode, is not applicable for Synopsys IP with the current code addition.
- If the default mode is LL-mode, for both AMD (Xilinx) and Synosys, and if user wants to use non-LL mode then user can do so via configuring the
peripheral_configparam ofdma_slave_config.Signed-off-by Devendra K Verma <[email protected]>---
Changes in v8
Cosmetic change related to comment and code.Changes in v7
No changeChanges in v6
Gave definition to bits used for channel configuration. Removed the comment related to doorbell.Changes in v5
Variable name 'nollp' changed to 'non_ll'.
In thedw_edma_device_config()WARN_ONreplaced withdev_err(). Comments follow the 80-column guideline.Changes in v4
No changeChanges in v3
No changeChanges in v2
Reverted the function return type to u64 for
dw_edma_get_phys_addr().Changes in v1
Changed the function return type fordw_edma_get_phys_addr(). Corrected the typo raised in review.Quoted 7 lines
--- drivers/dma/dw-edma/dw-edma-core.c | 42 +++++++++++++++++++++--- drivers/dma/dw-edma/dw-edma-core.h | 1 + drivers/dma/dw-edma/dw-edma-pcie.c | 46 ++++++++++++++++++-------- drivers/dma/dw-edma/dw-hdma-v0-core.c | 61 ++++++++++++++++++++++++++++++++++- drivers/dma/dw-edma/dw-hdma-v0-regs.h | 1 +
edma-v0-core.chave not update, if don't support, at least need return failure atdw_edma_device_config()when backend is eDMA.drivers/dma/dw-edma/dw-edma-core.c static int dw_edma_device_config(struct
Quoted 9 lines
include/linux/dma/edma.h | 1 + 6 files changed, 132 insertions(+), 20 deletions(-)drivers/dma/dw-edma/dw-edma-core.c +0
-0@@ -223,8 +223,32 @@ static int dw_edma_device_config(struct
dma_chan*dchan,drivers/dma/dw-edma/dw-edma-core.c static void dw_edma_device_issue_pending(struct
Quoted 32 lines
drivers/dma/dw-edma/dw-edma-core.c +24
-0struct dma_slave_config *config) {struct dw_edma_chan *chan =dchan2dw_edma_chan (dchan); +int non_ll =0 ; + +if (config->peripheral_config && + config->peripheral_size !=sizeof (int )) { +dev_err (dchan->device->dev, +"config param peripheral size mismatch\n" ); +return -EINVAL ; + }memcpy (&chan->config, config,sizeof (*config)); + +/* +* When there is no valid LLP base address available then the default +* DMA ops will use the non-LL mode. +* +* Cases where LL mode is enabled and client wants to use the non-LL +* mode then also client can do so via providing the peripheral_config +* param. +*/ +if (config->peripheral_config) + non_ll = *(int *)config->peripheral_config; + + chan->non_ll = false; +if (chan->dw->chip->non_ll || (!chan->dw->chip->non_ll && non_ll)) + chan->non_ll = true; + chan->configured = true;return 0 ;@@ -353,7 +377,7 @@ static void dw_edma_device_issue_pending(struct
dma_chan*dchan)drivers/dma/dw-edma/dw-edma-core.c static void dw_edma_device_issue_pending(struct
Quoted 9 lines
drivers/dma/dw-edma/dw-edma-core.c +1
-1struct dw_edma_chan *chan =dchan2dw_edma_chan (xfer->dchan);enum dma_transfer_direction dir = xfer->direction;struct scatterlist *sg =NULL ; -struct dw_edma_chunk *chunk; +struct dw_edma_chunk *chunk =NULL ;struct dw_edma_burst *burst;struct dw_edma_desc *desc;u64 src_addr, dst_addr;@@ -419,9 +443,11 @@ static void dw_edma_device_issue_pending(struct
dma_chan*dchan)drivers/dma/dw-edma/dw-edma-core.c static void dw_edma_device_issue_pending(struct dma_chan *dchan) · line 450
Quoted 11 lines
drivers/dma/dw-edma/dw-edma-core.c +5
-3if (unlikely (!desc)) goto err_alloc; - chunk =dw_edma_alloc_chunk (desc); -if (unlikely (!chunk)) - goto err_alloc; +if (!chan->non_ll) { + chunk =dw_edma_alloc_chunk (desc); +if (unlikely (!chunk)) + goto err_alloc; + }
Quoted 4 lines
non_llis the same asll_max= 1. (or 2, there are link back entry).If you set
ll_max= 1, needn't change this code.
The ll_max is defined for the session till the driver is loaded in the kernel. This code also enables the non-LL mode dynamically upon input from the DMA client. In this scenario, touching ll_max would not be a good idea as the ll_max controls the LL entries for all the DMA channels not just for a single DMA transaction.
Quoted 117 lines
drivers/dma/dw-edma/dw-edma-pcie.c static void
Quoted 37 lines
drivers/dma/dw-edma/dw-edma-core.c +0
-0if (xfer->type ==EDMA_XFER_INTERLEAVED ) { src_addr = xfer->xfer.il->src_start; @@ -450,7 +476,13 @@ static void dw_edma_device_issue_pending(struct dma_chan *dchan)if (xfer->type == EDMA_XFER_SCATTER_GATHER && !sg) break;drivers/dma/dw-edma/dw-edma-core.c +7
-1-if (chunk->bursts_alloc == chan->ll_max) { +/* +* For non-LL mode, only a single burst can be handled +* in a single chunk unlike LL mode where multiple bursts +* can be configured in a single chunk. +*/ +if ((chunk && chunk->bursts_alloc == chan->ll_max) || + chan->non_ll) { chunk =dw_edma_alloc_chunk (desc);if (unlikely (!chunk)) goto err_alloc; diff --git
a/drivers/dma/dw-edma/dw-edma-core.hb/drivers/dma/dw-edma/dw-edma-core.h
index 71894b9..c8e3d19 100644drivers/dma/dw-edma/dw-edma-core.h +1
-0@@ -86,6 +86,7 @@ struct dw_edma_chan {u8 configured;struct dma_slave_config config; +bool non_ll; };struct dw_edma_irq {drivers/dma/dw-edma/dw-edma-pcie.c +0
-0@@ -298,6 +298,15 @@ static voiddw_edma_pcie_get_xilinx_dma_data(struct
pci_dev*pdev,drivers/dma/dw-edma/dw-edma-pcie.c static int dw_edma_pcie_probe(struct pci_dev
Quoted 21 lines
drivers/dma/dw-edma/dw-edma-pcie.c +8
-1pdata->devmem_phys_off = off; } +static u64 dw_edma_get_phys_addr (struct pci_dev *pdev, +struct dw_edma_pcie_data *pdata, +enum pci_barno bar) { +if (pdev->vendor ==PCI_VENDOR_ID_XILINX ) +return pdata->devmem_phys_off; +return pci_bus_address (pdev, bar); } +static int dw_edma_pcie_probe (struct pci_dev *pdev, const struct pci_device_id *pid) { @@ -307,6 +316,7 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,struct dw_edma_chip *chip;int err, nr_irqs;int i, mask; +bool non_ll = false; vsec_data =kmalloc (sizeof (*vsec_data),GFP_KERNEL );if (!vsec_data)@@ -331,21 +341,24 @@ static int dw_edma_pcie_probe(struct pci_dev*pdev,
drivers/dma/dw-edma/dw-edma-pcie.c static int dw_edma_pcie_probe(struct pci_dev *pdev,
Quoted 9 lines
drivers/dma/dw-edma/dw-edma-pcie.c +3
-2if (pdev->vendor ==PCI_VENDOR_ID_XILINX ) {/* * There is no valid address found for the LL memory -* space on the device side. +* space on the device side. In the absence of LL base +* address use the non-LL mode or simple mode supported by +* the HDMA IP. */ - if (vsec_data->devmem_phys_off ==
DW_PCIE_XILINX_MDB_INVALID_ADDR)drivers/dma/dw-edma/dw-edma-pcie.c static int dw_edma_pcie_probe(struct pci_dev · line 348
Quoted 2 lines
drivers/dma/dw-edma/dw-edma-pcie.c +1
-1-return -ENOMEM ; + if (vsec_data->devmem_phys_off ==
DW_PCIE_AMD_MDB_INVALID_ADDR)drivers/dma/dw-edma/dw-edma-pcie.c static int dw_edma_pcie_probe(struct pci_dev
Quoted 23 lines
drivers/dma/dw-edma/dw-edma-pcie.c +8
-5+ non_ll = true;/* * Configure the channel LL and data blocks if number of * channels enabled in VSEC capability are more than the * channels configured in xilinx_mdb_data. */ -dw_edma_set_chan_region_offset (vsec_data,BAR_2 ,0 , -DW_PCIE_XILINX_MDB_LL_OFF_GAP , -DW_PCIE_XILINX_MDB_LL_SIZE , -DW_PCIE_XILINX_MDB_DT_OFF_GAP , -DW_PCIE_XILINX_MDB_DT_SIZE ); +if (!non_ll) +dw_edma_set_chan_region_offset (vsec_data,BAR_2 ,0 , +DW_PCIE_XILINX_LL_OFF_GAP , +DW_PCIE_XILINX_LL_SIZE , +DW_PCIE_XILINX_DT_OFF_GAP , + +DW_PCIE_XILINX_DT_SIZE ); }/* Mapping PCI BAR regions */ @@ -393,6 +406,7 @@ static int dw_edma_pcie_probe(struct pci_dev*pdev,
drivers/dma/dw-edma/dw-edma-pcie.c static int dw_edma_pcie_probe(struct pci_dev
Quoted 17 lines
drivers/dma/dw-edma/dw-edma-pcie.c +1
-0chip->mf = vsec_data->mf; chip->nr_irqs = nr_irqs; chip->ops = &dw_edma_pcie_plat_ops; + chip->non_ll = non_ll; chip->ll_wr_cnt = vsec_data->wr_ch_cnt; chip->ll_rd_cnt = vsec_data->rd_ch_cnt; @@ -401,7 +415,7 @@static int dw_edma_pcie_probe(struct
pci_dev*pdev,if (!chip->reg_base) return -ENOMEM;drivers/dma/dw-edma/dw-edma-pcie.c +1
-1-for (i =0 ; i < chip->ll_wr_cnt; i++) { +for (i =0 ; i < chip->ll_wr_cnt && !non_ll; i++) {struct dw_edma_region *ll_region = &chip->ll_region_wr[i];struct dw_edma_region *dt_region = &chip->dt_region_wr[i];struct dw_edma_block *ll_block = &vsec_data->ll_wr[i];@@ -412,7 +426,8 @@ static int dw_edma_pcie_probe(struct pci_dev*pdev,
Quoted 2 lines
drivers/dma/dw-edma/dw-edma-pcie.c +0
-0return -ENOMEM ;
Quoted 8 lines
drivers/dma/dw-edma/dw-edma-pcie.c static int dw_edma_pcie_probe(struct pci_dev *pdev, · line 430
Quoted 4 lines
drivers/dma/dw-edma/dw-edma-pcie.c +2
-1ll_region->vaddr.io += ll_block->off; - ll_region->paddr =pci_bus_address (pdev, ll_block->bar); + ll_region->paddr =dw_edma_get_phys_addr (pdev, vsec_data, + ll_block->bar);This change need do prepare patch, which only change
pci_bus_address()todw_edma_get_phys_addr().
This is not clear.
Quoted 75 lines
drivers/dma/dw-edma/dw-edma-pcie.c static int dw_edma_pcie_probe(struct pci_dev
Quoted 4 lines
drivers/dma/dw-edma/dw-edma-pcie.c +0
-0ll_region->paddr += ll_block->off; ll_region->sz = ll_block->sz;@@ -421,12 +436,13 @@ static int dw_edma_pcie_probe(struct pci_dev*pdev,
drivers/dma/dw-edma/dw-edma-pcie.c static int dw_edma_pcie_probe(struct pci_dev
Quoted 16 lines
drivers/dma/dw-edma/dw-edma-pcie.c +3
-2return -ENOMEM ; dt_region->vaddr.io += dt_block->off; - dt_region->paddr =pci_bus_address (pdev, dt_block->bar); + dt_region->paddr =dw_edma_get_phys_addr (pdev, vsec_data, + dt_block->bar); dt_region->paddr += dt_block->off; dt_region->sz = dt_block->sz; } -for (i =0 ; i < chip->ll_rd_cnt; i++) { +for (i =0 ; i < chip->ll_rd_cnt && !non_ll; i++) {struct dw_edma_region *ll_region = &chip->ll_region_rd[i];struct dw_edma_region *dt_region = &chip->dt_region_rd[i];struct dw_edma_block *ll_block = &vsec_data->ll_rd[i];@@ -437,7 +453,8 @@ static int dw_edma_pcie_probe(struct pci_dev*pdev,
drivers/dma/dw-edma/dw-edma-pcie.c static int dw_edma_pcie_probe(struct pci_dev
Quoted 10 lines
drivers/dma/dw-edma/dw-edma-pcie.c +2
-1return -ENOMEM ; ll_region->vaddr.io += ll_block->off; - ll_region->paddr =pci_bus_address (pdev, ll_block->bar); + ll_region->paddr =dw_edma_get_phys_addr (pdev, vsec_data, + ll_block->bar); ll_region->paddr += ll_block->off; ll_region->sz = ll_block->sz;@@ -446,7 +463,8 @@ static int dw_edma_pcie_probe(struct pci_dev*pdev,
drivers/dma/dw-edma/dw-hdma-v0-core.c static void dw_hdma_v0_sync_ll_data(struct
Quoted 15 lines
drivers/dma/dw-edma/dw-edma-pcie.c +2
-1return -ENOMEM ; dt_region->vaddr.io += dt_block->off; - dt_region->paddr =pci_bus_address (pdev, dt_block->bar); + dt_region->paddr =dw_edma_get_phys_addr (pdev, vsec_data, + dt_block->bar); dt_region->paddr += dt_block->off; dt_region->sz = dt_block->sz; }drivers/dma/dw-edma/dw-hdma-v0-core.c +0
-0@@ -225,7 +225,7 @@ static void dw_hdma_v0_sync_ll_data(struct
dw_edma_chunk*chunk)drivers/dma/dw-edma/dw-hdma-v0-core.c static void dw_hdma_v0_core_start(struct
Quoted 10 lines
drivers/dma/dw-edma/dw-hdma-v0-core.c +2
-1readl (chunk->ll_region.vaddr.io); } -static void dw_hdma_v0_core_start (struct dw_edma_chunk *chunk,bool first) +static void dw_hdma_v0_core_ll_start(struct dw_edma_chunk *chunk, +bool first) {struct dw_edma_chan *chan = chunk->chan;struct dw_edma *dw = chan->dw;@@ -263,6 +263,65 @@ static void dw_hdma_v0_core_start(struct
dw_edma_chunk*chunk, bool first)drivers/dma/dw-edma/dw-hdma-v0-core.c static void dw_hdma_v0_core_start(struct · line 266
Quoted 4 lines
drivers/dma/dw-edma/dw-hdma-v0-core.c +1
-0SET_CH_32 (dw, chan->dir, chan->id, doorbell,HDMA_V0_DOORBELL_START ); } +static void dw_hdma_v0_core_non_ll_start(struct dw_edma_chunk*chunk)
drivers/dma/dw-edma/dw-hdma-v0-core.c static void dw_hdma_v0_core_start(struct dw_edma_chunk *chunk, bool first) · line 273
Quoted 7 lines
drivers/dma/dw-edma/dw-hdma-v0-core.c +7
-0+{ +struct dw_edma_chan *chan = chunk->chan; +struct dw_edma *dw = chan->dw; +struct dw_edma_burst *child; +u32 val; + +list_for_each_entry (child, &chunk->burst->list, list) {why need iterated list, it doesn't support ll. Need wait for irq to start next one.
Quoted 1 line
Frank
Yes, this is true. The format is kept similar to LL mode.
Quoted 83 lines
Quoted 83 lines
drivers/dma/dw-edma/dw-hdma-v0-core.c +52
-0+SET_CH_32 (dw, chan->dir, chan->id, ch_en, +HDMA_V0_CH_EN ); + +/* Source address */ +SET_CH_32 (dw, chan->dir, chan->id, sar.lsb, +lower_32_bits (child->sar)); +SET_CH_32 (dw, chan->dir, chan->id, sar.msb, +upper_32_bits (child->sar)); + +/* Destination address */ +SET_CH_32 (dw, chan->dir, chan->id, dar.lsb, +lower_32_bits (child->dar)); +SET_CH_32 (dw, chan->dir, chan->id, dar.msb, +upper_32_bits (child->dar)); + +/* Transfer size */ +SET_CH_32 (dw, chan->dir, chan->id, transfer_size, + child->sz); + +/* Interrupt setup */ + val =GET_CH_32 (dw, chan->dir, chan->id, int_setup) | +HDMA_V0_STOP_INT_MASK | +HDMA_V0_ABORT_INT_MASK | +HDMA_V0_LOCAL_STOP_INT_EN | +HDMA_V0_LOCAL_ABORT_INT_EN ; + +if (!(dw->chip->flags &DW_EDMA_CHIP_LOCAL )) { + val |=HDMA_V0_REMOTE_STOP_INT_EN | +HDMA_V0_REMOTE_ABORT_INT_EN ; + } + +SET_CH_32 (dw, chan->dir, chan->id, int_setup, val); + +/* Channel control setup */ + val =GET_CH_32 (dw, chan->dir, chan->id, control1); + val &= ~HDMA_V0_LINKLIST_EN ; +SET_CH_32 (dw, chan->dir, chan->id, control1, val); + +SET_CH_32 (dw, chan->dir, chan->id, doorbell, +HDMA_V0_DOORBELL_START ); + } +} + +static void dw_hdma_v0_core_start (struct dw_edma_chunk *chunk,bool +first) { +struct dw_edma_chan *chan = chunk->chan; + +if (chan->non_ll) +dw_hdma_v0_core_non_ll_start (chunk); +else +dw_hdma_v0_core_ll_start (chunk, first); } +static void dw_hdma_v0_core_ch_config (struct dw_edma_chan *chan) {struct dw_edma *dw = chan->dw;drivers/dma/dw-edma/dw-hdma-v0-regs.h +1
-0@@ -12,6 +12,7 @@#include <linux/dmaengine.h> #define HDMA_V0_MAX_NR_CH 8 +#define HDMA_V0_CH_EN BIT(0)#define HDMA_V0_LOCAL_ABORT_INT_EN BIT(6)#define HDMA_V0_REMOTE_ABORT_INT_EN BIT(5)#define HDMA_V0_LOCAL_STOP_INT_EN BIT(4)include/linux/dma/edma.h index renamed from include/linux/dma/edma.h +0
-03080747..78ce31b 100644
include/linux/dma/edma.h +1
-1@@ -99,6 +99,7 @@ struct dw_edma_chip {enum dw_edma_map_format mf;struct dw_edma *dw; +bool non_ll; };/* Export to the platform drivers */ --1.8.3.1
Re: [PATCH v8 2/2] dmaengine: dw-edma: Add non-LL mode
Quoted 39 lines · Devendra
[AMD Official Use Only - AMD Internal Distribution Only]
Hi Frank
Please check my response inline.
Regards,
DevendraQuoted 22 lines
-----Original Message-----
From: Frank Li <[email protected]>
Sent: Thursday, January 15, 2026 10:07 PM
To: Verma, Devendra <[email protected]>
Cc: [email protected]; [email protected]; [email protected]; [email protected]; [email protected]; linux- [email protected]; Simek, Michal <[email protected]>
Subject: Re: [PATCH v8 2/2] dmaengine: dw-edma: Add non-LL modeCaution: This message originated from an External Source. Use proper caution when opening attachments, clicking links, or responding.
Quoted 7 lines · Devendra K Verma
AMD MDB IP supports Linked List (LL) mode as well as non-LL mode. The current code does not have the mechanisms to enable the DMA transactions using the non-LL mode. The following two cases are added with this patch:
- For the AMD (Xilinx) only, when a valid physical base address of the device side DDR is not configured, then the IP can still be used in non-LL mode. For all the channels DMA transactions willQuoted 3 lines
If DDR have not configured, where DATA send to in device side by non-LL mode.
The DDR base address in the VSEC capability is used for driving the DMA transfers when used in the LL mode. The DDR is configured and present all the time but the DMA PCIe driver uses this DDR base address (physical address) to configure the LLP address.
Quoted 7 lines
In the scenario, where this DDR base address in VSEC capability is not configured then the current controller cannot be used as the default mode supported is LL mode only. In order to make the controller usable non-LL mode is being added which just needs SAR, DAR, XFERLEN and control register to initiate the transfer. So, the DDR is always present, but the DMA PCIe driver need to know the DDR base physical address to make the transfer. This is useful in scenarios where the memory allocated for LL can be used for DMA transactions as well.
Do you means use DMA transfer LL's context?
Quoted 116 lines
Quoted 116 lines
Quoted 38 lines
be using the non-LL mode only. This, the default non-LL mode, is not applicable for Synopsys IP with the current code addition.
- If the default mode is LL-mode, for both AMD (Xilinx) and Synosys, and if user wants to use non-LL mode then user can do so via configuring the
peripheral_configparam ofdma_slave_config.Signed-off-by Devendra K Verma <[email protected]>---
Changes in v8
Cosmetic change related to comment and code.Changes in v7
No changeChanges in v6
Gave definition to bits used for channel configuration. Removed the comment related to doorbell.Changes in v5
Variable name 'nollp' changed to 'non_ll'.
In thedw_edma_device_config()WARN_ONreplaced withdev_err(). Comments follow the 80-column guideline.Changes in v4
No changeChanges in v3
No changeChanges in v2
Reverted the function return type to u64 for
dw_edma_get_phys_addr().Changes in v1
Changed the function return type fordw_edma_get_phys_addr(). Corrected the typo raised in review.Quoted 7 lines
--- drivers/dma/dw-edma/dw-edma-core.c | 42 +++++++++++++++++++++--- drivers/dma/dw-edma/dw-edma-core.h | 1 + drivers/dma/dw-edma/dw-edma-pcie.c | 46 ++++++++++++++++++-------- drivers/dma/dw-edma/dw-hdma-v0-core.c | 61 ++++++++++++++++++++++++++++++++++- drivers/dma/dw-edma/dw-hdma-v0-regs.h | 1 +
edma-v0-core.chave not update, if don't support, at least need return failure atdw_edma_device_config()when backend is eDMA.drivers/dma/dw-edma/dw-edma-core.c static int dw_edma_device_config(struct
Quoted 9 lines
include/linux/dma/edma.h | 1 + 6 files changed, 132 insertions(+), 20 deletions(-)drivers/dma/dw-edma/dw-edma-core.c +0
-0@@ -223,8 +223,32 @@ static int dw_edma_device_config(struct
dma_chan*dchan,drivers/dma/dw-edma/dw-edma-core.c static void dw_edma_device_issue_pending(struct
Quoted 32 lines
drivers/dma/dw-edma/dw-edma-core.c +24
-0struct dma_slave_config *config) {struct dw_edma_chan *chan =dchan2dw_edma_chan (dchan); +int non_ll =0 ; + +if (config->peripheral_config && + config->peripheral_size !=sizeof (int )) { +dev_err (dchan->device->dev, +"config param peripheral size mismatch\n" ); +return -EINVAL ; + }memcpy (&chan->config, config,sizeof (*config)); + +/* +* When there is no valid LLP base address available then the default +* DMA ops will use the non-LL mode. +* +* Cases where LL mode is enabled and client wants to use the non-LL +* mode then also client can do so via providing the peripheral_config +* param. +*/ +if (config->peripheral_config) + non_ll = *(int *)config->peripheral_config; + + chan->non_ll = false; +if (chan->dw->chip->non_ll || (!chan->dw->chip->non_ll && non_ll)) + chan->non_ll = true; + chan->configured = true;return 0 ;@@ -353,7 +377,7 @@ static void dw_edma_device_issue_pending(struct
dma_chan*dchan)drivers/dma/dw-edma/dw-edma-core.c static void dw_edma_device_issue_pending(struct
Quoted 9 lines
drivers/dma/dw-edma/dw-edma-core.c +1
-1struct dw_edma_chan *chan =dchan2dw_edma_chan (xfer->dchan);enum dma_transfer_direction dir = xfer->direction;struct scatterlist *sg =NULL ; -struct dw_edma_chunk *chunk; +struct dw_edma_chunk *chunk =NULL ;struct dw_edma_burst *burst;struct dw_edma_desc *desc;u64 src_addr, dst_addr;@@ -419,9 +443,11 @@ static void dw_edma_device_issue_pending(struct
dma_chan*dchan)drivers/dma/dw-edma/dw-edma-core.c static void dw_edma_device_issue_pending(struct dma_chan *dchan) · line 450
Quoted 11 lines
drivers/dma/dw-edma/dw-edma-core.c +5
-3if (unlikely (!desc)) goto err_alloc; - chunk =dw_edma_alloc_chunk (desc); -if (unlikely (!chunk)) - goto err_alloc; +if (!chan->non_ll) { + chunk =dw_edma_alloc_chunk (desc); +if (unlikely (!chunk)) + goto err_alloc; + }
non_llis the same asll_max= 1. (or 2, there are link back entry).
Quoted 8 lines
Quoted 2 lines
If you set
ll_max= 1, needn't change this code.The
ll_maxis defined for the session till the driver is loaded in the kernel. This code also enables the non-LL mode dynamically upon input from the DMA client. In this scenario, touchingll_maxwould not be a good idea as thell_maxcontrols the LL entries for all the DMA channels not just for a single DMA transaction.
You can use new variable, such as ll_avail.
Quoted 123 lines
Quoted 123 lines
drivers/dma/dw-edma/dw-edma-pcie.c static void
Quoted 38 lines
drivers/dma/dw-edma/dw-edma-core.c +0
-0if (xfer->type ==EDMA_XFER_INTERLEAVED ) { src_addr = xfer->xfer.il->src_start; @@ -450,7 +476,13 @@ static void dw_edma_device_issue_pending(struct dma_chan *dchan)if (xfer->type == EDMA_XFER_SCATTER_GATHER && !sg) break;drivers/dma/dw-edma/dw-edma-core.c +7
-1-if (chunk->bursts_alloc == chan->ll_max) { +/* +* For non-LL mode, only a single burst can be handled +* in a single chunk unlike LL mode where multiple bursts +* can be configured in a single chunk. +*/ +if ((chunk && chunk->bursts_alloc == chan->ll_max) || + chan->non_ll) { chunk =dw_edma_alloc_chunk (desc);if (unlikely (!chunk)) goto err_alloc; diff --git
a/drivers/dma/dw-edma/dw-edma-core.hb/drivers/dma/dw-edma/dw-edma-core.h
index 71894b9..c8e3d19 100644drivers/dma/dw-edma/dw-edma-core.h +1
-0@@ -86,6 +86,7 @@ struct dw_edma_chan {u8 configured;struct dma_slave_config config; +bool non_ll; };struct dw_edma_irq {drivers/dma/dw-edma/dw-edma-pcie.c +0
-0@@ -298,6 +298,15 @@ static voiddw_edma_pcie_get_xilinx_dma_data(struct
pci_dev*pdev,drivers/dma/dw-edma/dw-edma-pcie.c static int dw_edma_pcie_probe(struct pci_dev
Quoted 21 lines
drivers/dma/dw-edma/dw-edma-pcie.c +8
-1pdata->devmem_phys_off = off; } +static u64 dw_edma_get_phys_addr (struct pci_dev *pdev, +struct dw_edma_pcie_data *pdata, +enum pci_barno bar) { +if (pdev->vendor ==PCI_VENDOR_ID_XILINX ) +return pdata->devmem_phys_off; +return pci_bus_address (pdev, bar); } +static int dw_edma_pcie_probe (struct pci_dev *pdev, const struct pci_device_id *pid) { @@ -307,6 +316,7 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,struct dw_edma_chip *chip;int err, nr_irqs;int i, mask; +bool non_ll = false; vsec_data =kmalloc (sizeof (*vsec_data),GFP_KERNEL );if (!vsec_data)@@ -331,21 +341,24 @@ static int dw_edma_pcie_probe(struct pci_dev*pdev,
drivers/dma/dw-edma/dw-edma-pcie.c static int dw_edma_pcie_probe(struct pci_dev *pdev,
Quoted 9 lines
drivers/dma/dw-edma/dw-edma-pcie.c +3
-2if (pdev->vendor ==PCI_VENDOR_ID_XILINX ) {/* * There is no valid address found for the LL memory -* space on the device side. +* space on the device side. In the absence of LL base +* address use the non-LL mode or simple mode supported by +* the HDMA IP. */ - if (vsec_data->devmem_phys_off ==
DW_PCIE_XILINX_MDB_INVALID_ADDR)drivers/dma/dw-edma/dw-edma-pcie.c static int dw_edma_pcie_probe(struct pci_dev · line 348
Quoted 2 lines
drivers/dma/dw-edma/dw-edma-pcie.c +1
-1-return -ENOMEM ; + if (vsec_data->devmem_phys_off ==
DW_PCIE_AMD_MDB_INVALID_ADDR)drivers/dma/dw-edma/dw-edma-pcie.c static int dw_edma_pcie_probe(struct pci_dev
Quoted 23 lines
drivers/dma/dw-edma/dw-edma-pcie.c +8
-5+ non_ll = true;/* * Configure the channel LL and data blocks if number of * channels enabled in VSEC capability are more than the * channels configured in xilinx_mdb_data. */ -dw_edma_set_chan_region_offset (vsec_data,BAR_2 ,0 , -DW_PCIE_XILINX_MDB_LL_OFF_GAP , -DW_PCIE_XILINX_MDB_LL_SIZE , -DW_PCIE_XILINX_MDB_DT_OFF_GAP , -DW_PCIE_XILINX_MDB_DT_SIZE ); +if (!non_ll) +dw_edma_set_chan_region_offset (vsec_data,BAR_2 ,0 , +DW_PCIE_XILINX_LL_OFF_GAP , +DW_PCIE_XILINX_LL_SIZE , +DW_PCIE_XILINX_DT_OFF_GAP , + +DW_PCIE_XILINX_DT_SIZE ); }/* Mapping PCI BAR regions */ @@ -393,6 +406,7 @@ static int dw_edma_pcie_probe(struct pci_dev*pdev,
drivers/dma/dw-edma/dw-edma-pcie.c static int dw_edma_pcie_probe(struct pci_dev
Quoted 17 lines
drivers/dma/dw-edma/dw-edma-pcie.c +1
-0chip->mf = vsec_data->mf; chip->nr_irqs = nr_irqs; chip->ops = &dw_edma_pcie_plat_ops; + chip->non_ll = non_ll; chip->ll_wr_cnt = vsec_data->wr_ch_cnt; chip->ll_rd_cnt = vsec_data->rd_ch_cnt; @@ -401,7 +415,7 @@static int dw_edma_pcie_probe(struct
pci_dev*pdev,if (!chip->reg_base) return -ENOMEM;drivers/dma/dw-edma/dw-edma-pcie.c +1
-1-for (i =0 ; i < chip->ll_wr_cnt; i++) { +for (i =0 ; i < chip->ll_wr_cnt && !non_ll; i++) {struct dw_edma_region *ll_region = &chip->ll_region_wr[i];struct dw_edma_region *dt_region = &chip->dt_region_wr[i];struct dw_edma_block *ll_block = &vsec_data->ll_wr[i];@@ -412,7 +426,8 @@ static int dw_edma_pcie_probe(struct pci_dev*pdev,
Quoted 6 lines
drivers/dma/dw-edma/dw-edma-pcie.c +2
-1return -ENOMEM ; ll_region->vaddr.io += ll_block->off; - ll_region->paddr =pci_bus_address (pdev, ll_block->bar); + ll_region->paddr =dw_edma_get_phys_addr (pdev, vsec_data, + ll_block->bar);
Quoted 5 lines
Quoted 3 lines
This change need do prepare patch, which only change
pci_bus_address()todw_edma_get_phys_addr().This is not clear.
why not. only trivial add helper patch, which help reviewer
Quoted 76 lines
Quoted 76 lines
drivers/dma/dw-edma/dw-edma-pcie.c static int dw_edma_pcie_probe(struct pci_dev
Quoted 5 lines
drivers/dma/dw-edma/dw-edma-pcie.c +0
-0ll_region->paddr += ll_block->off; ll_region->sz = ll_block->sz;@@ -421,12 +436,13 @@ static int dw_edma_pcie_probe(struct pci_dev*pdev,
drivers/dma/dw-edma/dw-edma-pcie.c static int dw_edma_pcie_probe(struct pci_dev
Quoted 16 lines
drivers/dma/dw-edma/dw-edma-pcie.c +3
-2return -ENOMEM ; dt_region->vaddr.io += dt_block->off; - dt_region->paddr =pci_bus_address (pdev, dt_block->bar); + dt_region->paddr =dw_edma_get_phys_addr (pdev, vsec_data, + dt_block->bar); dt_region->paddr += dt_block->off; dt_region->sz = dt_block->sz; } -for (i =0 ; i < chip->ll_rd_cnt; i++) { +for (i =0 ; i < chip->ll_rd_cnt && !non_ll; i++) {struct dw_edma_region *ll_region = &chip->ll_region_rd[i];struct dw_edma_region *dt_region = &chip->dt_region_rd[i];struct dw_edma_block *ll_block = &vsec_data->ll_rd[i];@@ -437,7 +453,8 @@ static int dw_edma_pcie_probe(struct pci_dev*pdev,
drivers/dma/dw-edma/dw-edma-pcie.c static int dw_edma_pcie_probe(struct pci_dev
Quoted 10 lines
drivers/dma/dw-edma/dw-edma-pcie.c +2
-1return -ENOMEM ; ll_region->vaddr.io += ll_block->off; - ll_region->paddr =pci_bus_address (pdev, ll_block->bar); + ll_region->paddr =dw_edma_get_phys_addr (pdev, vsec_data, + ll_block->bar); ll_region->paddr += ll_block->off; ll_region->sz = ll_block->sz;@@ -446,7 +463,8 @@ static int dw_edma_pcie_probe(struct pci_dev*pdev,
drivers/dma/dw-edma/dw-hdma-v0-core.c static void dw_hdma_v0_sync_ll_data(struct
Quoted 15 lines
drivers/dma/dw-edma/dw-edma-pcie.c +2
-1return -ENOMEM ; dt_region->vaddr.io += dt_block->off; - dt_region->paddr =pci_bus_address (pdev, dt_block->bar); + dt_region->paddr =dw_edma_get_phys_addr (pdev, vsec_data, + dt_block->bar); dt_region->paddr += dt_block->off; dt_region->sz = dt_block->sz; }drivers/dma/dw-edma/dw-hdma-v0-core.c +0
-0@@ -225,7 +225,7 @@ static void dw_hdma_v0_sync_ll_data(struct
dw_edma_chunk*chunk)drivers/dma/dw-edma/dw-hdma-v0-core.c static void dw_hdma_v0_core_start(struct
Quoted 10 lines
drivers/dma/dw-edma/dw-hdma-v0-core.c +2
-1readl (chunk->ll_region.vaddr.io); } -static void dw_hdma_v0_core_start (struct dw_edma_chunk *chunk,bool first) +static void dw_hdma_v0_core_ll_start(struct dw_edma_chunk *chunk, +bool first) {struct dw_edma_chan *chan = chunk->chan;struct dw_edma *dw = chan->dw;@@ -263,6 +263,65 @@ static void dw_hdma_v0_core_start(struct
dw_edma_chunk*chunk, bool first)drivers/dma/dw-edma/dw-hdma-v0-core.c static void dw_hdma_v0_core_start(struct · line 266
Quoted 4 lines
drivers/dma/dw-edma/dw-hdma-v0-core.c +1
-0SET_CH_32 (dw, chan->dir, chan->id, doorbell,HDMA_V0_DOORBELL_START ); } +static void dw_hdma_v0_core_non_ll_start(struct dw_edma_chunk*chunk)
drivers/dma/dw-edma/dw-hdma-v0-core.c static void dw_hdma_v0_core_start(struct dw_edma_chunk *chunk, bool first) · line 273
Quoted 7 lines
drivers/dma/dw-edma/dw-hdma-v0-core.c +7
-0+{ +struct dw_edma_chan *chan = chunk->chan; +struct dw_edma *dw = chan->dw; +struct dw_edma_burst *child; +u32 val; + +list_for_each_entry (child, &chunk->burst->list, list) {why need iterated list, it doesn't support ll. Need wait for irq to start next one.
Quoted 3 lines
Quoted 1 line
Frank
Yes, this is true. The format is kept similar to LL mode.
Just fill one. list_for_each_entry() cause confuse.
Frank
Quoted 84 lines
Quoted 84 lines
Quoted 84 lines
drivers/dma/dw-edma/dw-hdma-v0-core.c +52
-0+SET_CH_32 (dw, chan->dir, chan->id, ch_en, +HDMA_V0_CH_EN ); + +/* Source address */ +SET_CH_32 (dw, chan->dir, chan->id, sar.lsb, +lower_32_bits (child->sar)); +SET_CH_32 (dw, chan->dir, chan->id, sar.msb, +upper_32_bits (child->sar)); + +/* Destination address */ +SET_CH_32 (dw, chan->dir, chan->id, dar.lsb, +lower_32_bits (child->dar)); +SET_CH_32 (dw, chan->dir, chan->id, dar.msb, +upper_32_bits (child->dar)); + +/* Transfer size */ +SET_CH_32 (dw, chan->dir, chan->id, transfer_size, + child->sz); + +/* Interrupt setup */ + val =GET_CH_32 (dw, chan->dir, chan->id, int_setup) | +HDMA_V0_STOP_INT_MASK | +HDMA_V0_ABORT_INT_MASK | +HDMA_V0_LOCAL_STOP_INT_EN | +HDMA_V0_LOCAL_ABORT_INT_EN ; + +if (!(dw->chip->flags &DW_EDMA_CHIP_LOCAL )) { + val |=HDMA_V0_REMOTE_STOP_INT_EN | +HDMA_V0_REMOTE_ABORT_INT_EN ; + } + +SET_CH_32 (dw, chan->dir, chan->id, int_setup, val); + +/* Channel control setup */ + val =GET_CH_32 (dw, chan->dir, chan->id, control1); + val &= ~HDMA_V0_LINKLIST_EN ; +SET_CH_32 (dw, chan->dir, chan->id, control1, val); + +SET_CH_32 (dw, chan->dir, chan->id, doorbell, +HDMA_V0_DOORBELL_START ); + } +} + +static void dw_hdma_v0_core_start (struct dw_edma_chunk *chunk,bool +first) { +struct dw_edma_chan *chan = chunk->chan; + +if (chan->non_ll) +dw_hdma_v0_core_non_ll_start (chunk); +else +dw_hdma_v0_core_ll_start (chunk, first); } +static void dw_hdma_v0_core_ch_config (struct dw_edma_chan *chan) {struct dw_edma *dw = chan->dw;drivers/dma/dw-edma/dw-hdma-v0-regs.h +1
-0@@ -12,6 +12,7 @@#include <linux/dmaengine.h> #define HDMA_V0_MAX_NR_CH 8 +#define HDMA_V0_CH_EN BIT(0)#define HDMA_V0_LOCAL_ABORT_INT_EN BIT(6)#define HDMA_V0_REMOTE_ABORT_INT_EN BIT(5)#define HDMA_V0_LOCAL_STOP_INT_EN BIT(4)include/linux/dma/edma.h index renamed from include/linux/dma/edma.h +0
-03080747..78ce31b 100644
include/linux/dma/edma.h +1
-1@@ -99,6 +99,7 @@ struct dw_edma_chip {enum dw_edma_map_format mf;struct dw_edma *dw; +bool non_ll; };/* Export to the platform drivers */ --1.8.3.1
RE: [PATCH v8 2/2] dmaengine: dw-edma: Add non-LL mode
[AMD Official Use Only - AMD Internal Distribution Only]
Quoted 60 lines
-----Original Message-----
From: Frank Li <[email protected]>
Sent: Monday, January 19, 2026 9:15 PM
To: Verma, Devendra <[email protected]>
Cc: [email protected]; [email protected]; [email protected]; [email protected]; [email protected]; linux- [email protected]; Simek, Michal <[email protected]>
Subject: Re: [PATCH v8 2/2] dmaengine: dw-edma: Add non-LL modeCaution: This message originated from an External Source. Use proper caution when opening attachments, clicking links, or responding.
Quoted 39 lines · Devendra
[AMD Official Use Only - AMD Internal Distribution Only]
Hi Frank
Please check my response inline.
Regards,
DevendraQuoted 22 lines
-----Original Message-----
From: Frank Li <[email protected]>
Sent: Thursday, January 15, 2026 10:07 PM
To: Verma, Devendra <[email protected]>
Cc: [email protected]; [email protected]; [email protected]; [email protected]; [email protected]; linux- [email protected]; Simek, Michal <[email protected]>
Subject: Re: [PATCH v8 2/2] dmaengine: dw-edma: Add non-LL modeCaution: This message originated from an External Source. Use proper caution when opening attachments, clicking links, or responding.
Quoted 7 lines · Devendra K Verma
AMD MDB IP supports Linked List (LL) mode as well as non-LL mode. The current code does not have the mechanisms to enable the DMA transactions using the non-LL mode. The following two cases are added with this patch:
- For the AMD (Xilinx) only, when a valid physical base address of the device side DDR is not configured, then the IP can still be used in non-LL mode. For all the channels DMA transactions willQuoted 3 lines
If DDR have not configured, where DATA send to in device side by non-LL mode.
The DDR base address in the VSEC capability is used for driving the DMA transfers when used in the LL mode. The DDR is configured and present all the time but the DMA PCIe driver uses this DDR base address (physical address) to configure the LLP address.
Quoted 7 lines
In the scenario, where this DDR base address in VSEC capability is not configured then the current controller cannot be used as the default mode supported is LL mode only. In order to make the controller usable non-LL mode is being added which just needs SAR, DAR, XFERLEN and control register to initiate the transfer. So, the DDR is always present, but the DMA PCIe driver need to know the DDR base physical address to make the transfer. This is useful in scenarios where the memory
Quoted 4 lines
allocated for LL can be used for DMA transactions as well.
Do you means use DMA transfer LL's context?
Yes, the device side memory reserved for the link list to store the descriptors, accessed by the host via BAR_2 in this driver code.
Quoted 123 lines
Quoted 35 lines
Quoted 35 lines
Quoted 35 lines
be using the non-LL mode only. This, the default non-LL mode, is not applicable for Synopsys IP with the current code addition.
- If the default mode is LL-mode, for both AMD (Xilinx) and Synosys, and if user wants to use non-LL mode then user can do so via configuring the
peripheral_configparam ofdma_slave_config.Signed-off-by Devendra K Verma <[email protected]>---
Changes in v8
Cosmetic change related to comment and code.Changes in v7
No changeChanges in v6
Gave definition to bits used for channel configuration. Removed the comment related to doorbell.Changes in v5
Variable name 'nollp' changed to 'non_ll'.
In thedw_edma_device_config()WARN_ONreplaced withdev_err(). Comments follow the 80-column guideline.Changes in v4
No changeChanges in v3
No changeChanges in v2
Reverted the function return type to u64 for
dw_edma_get_phys_addr().Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Changes in v1
Changed the function return type fordw_edma_get_phys_addr(). Corrected the typo raised in review.--- drivers/dma/dw-edma/dw-edma-core.c | 42+++++++++++++++++++++---
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
drivers/dma/dw-edma/dw-edma-core.h | 1 + drivers/dma/dw-edma/dw-edma-pcie.c | 46 ++++++++++++++++++--------
Quoted 79 lines
Quoted 78 lines
Quoted 3 lines
drivers/dma/dw-edma/dw-hdma-v0-core.c | 61 ++++++++++++++++++++++++++++++++++- drivers/dma/dw-edma/dw-hdma-v0-regs.h | 1 +
edma-v0-core.chave not update, if don't support, at least need return failure atdw_edma_device_config()when backend is eDMA.drivers/dma/dw-edma/dw-edma-core.c static int dw_edma_device_config(struct
Quoted 9 lines
include/linux/dma/edma.h | 1 + 6 files changed, 132 insertions(+), 20 deletions(-)drivers/dma/dw-edma/dw-edma-core.c +0
-0@@ -223,8 +223,32 @@ static int dw_edma_device_config(struct
dma_chan*dchan,Quoted 32 lines
drivers/dma/dw-edma/dw-edma-core.c +24
-0struct dma_slave_config *config) {struct dw_edma_chan *chan =dchan2dw_edma_chan (dchan); +int non_ll =0 ; + +if (config->peripheral_config && + config->peripheral_size !=sizeof (int )) { +dev_err (dchan->device->dev, +"config param peripheral size mismatch\n" ); +return -EINVAL ; + }memcpy (&chan->config, config,sizeof (*config)); + +/* +* When there is no valid LLP base address available then the default +* DMA ops will use the non-LL mode. +* +* Cases where LL mode is enabled and client wants to use the non-LL +* mode then also client can do so via providing the peripheral_config +* param. +*/ +if (config->peripheral_config) + non_ll = *(int *)config->peripheral_config; + + chan->non_ll = false; +if (chan->dw->chip->non_ll || (!chan->dw->chip->non_ll && non_ll)) + chan->non_ll = true; + chan->configured = true;return 0 ;@@ -353,7 +377,7 @@ static voidQuoted 1 line
dw_edma_device_issue_pending(struct
dma_chan*dchan)Quoted 10 lines
struct dw_edma_chan *chan = dchan2dw_edma_chan(xfer->dchan); enum dma_transfer_direction dir = xfer->direction; struct scatterlist *sg = NULL;drivers/dma/dw-edma/dw-edma-core.c +1
-1-struct dw_edma_chunk *chunk; +struct dw_edma_chunk *chunk =NULL ;struct dw_edma_burst *burst;struct dw_edma_desc *desc;u64 src_addr, dst_addr;@@ -419,9 +443,11 @@ static voiddw_edma_device_issue_pending(struct
dma_chan*dchan)drivers/dma/dw-edma/dw-edma-core.c static void dw_edma_device_issue_pending(struct dma_chan *dchan) · line 450
Quoted 11 lines
if (unlikely(!desc)) goto err_alloc;drivers/dma/dw-edma/dw-edma-core.c +5
-3- chunk =dw_edma_alloc_chunk (desc); -if (unlikely (!chunk)) - goto err_alloc; +if (!chan->non_ll) { + chunk =dw_edma_alloc_chunk (desc); +if (unlikely (!chunk)) + goto err_alloc; + }
non_llis the same asll_max= 1. (or 2, there are link back entry).If you set
ll_max= 1, needn't change this code.
Quoted 8 lines
Quoted 5 lines
The
ll_maxis defined for the session till the driver is loaded in the kernel. This code also enables the non-LL mode dynamically upon input from the DMA client. In this scenario, touchingll_maxwould not be a good idea as thell_maxcontrols the LL entries for all the DMA channels not just for a single DMA transaction.You can use new variable, such as
ll_avail.
In order to separate out the execution paths a new meaningful variable "non_ll" is used. The variable "non_ll" alone is sufficient. Using another variable along side "non_ll" for the similar purpose may not have any added advantage.
Quoted 127 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
if (xfer->type == EDMA_XFER_INTERLEAVED) { src_addr = xfer->xfer.il->src_start; @@ -450,7+476,13 @@ static void dw_edma_device_issue_pending(struct
dma_chan*dchan)Quoted 51 lines
Quoted 51 lines
drivers/dma/dw-edma/dw-edma-pcie.c static void
Quoted 33 lines
if (xfer->type == EDMA_XFER_SCATTER_GATHER && !sg) break;drivers/dma/dw-edma/dw-edma-core.c +7
-1-if (chunk->bursts_alloc == chan->ll_max) { +/* +* For non-LL mode, only a single burst can be handled +* in a single chunk unlike LL mode where multiple bursts +* can be configured in a single chunk. +*/ +if ((chunk && chunk->bursts_alloc == chan->ll_max) || + chan->non_ll) { chunk =dw_edma_alloc_chunk (desc);if (unlikely (!chunk)) goto err_alloc; diff --git
a/drivers/dma/dw-edma/dw-edma-core.hb/drivers/dma/dw-edma/dw-edma-core.h
index 71894b9..c8e3d19 100644drivers/dma/dw-edma/dw-edma-core.h +1
-0@@ -86,6 +86,7 @@ struct dw_edma_chan {u8 configured;struct dma_slave_config config; +bool non_ll; };struct dw_edma_irq {drivers/dma/dw-edma/dw-edma-pcie.c +0
-0@@ -298,6 +298,15 @@ static voiddw_edma_pcie_get_xilinx_dma_data(struct
pci_dev*pdev,Quoted 17 lines
drivers/dma/dw-edma/dw-edma-pcie.c +8
-1pdata->devmem_phys_off = off; } +static u64 dw_edma_get_phys_addr (struct pci_dev *pdev, +struct dw_edma_pcie_data *pdata, +enum pci_barno bar) { +if (pdev->vendor ==PCI_VENDOR_ID_XILINX ) +return pdata->devmem_phys_off; +return pci_bus_address (pdev, bar); } +static int dw_edma_pcie_probe (struct pci_dev *pdev, const struct pci_device_id *pid) { @@ -307,6 +316,7 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,struct dw_edma_chip *chip;int err, nr_irqs;int i, mask; +bool non_ll = false;Quoted 3 lines
Quoted 3 lines
drivers/dma/dw-edma/dw-edma-pcie.c static int dw_edma_pcie_probe(struct
Quoted 3 lines
vsec_data = kmalloc(sizeof(*vsec_data), GFP_KERNEL); if (!vsec_data)drivers/dma/dw-edma/dw-edma-pcie.c +0
-0@@ -331,21 +341,24 @@ static int dw_edma_pcie_probe(struct
pci_devQuoted 66 lines
Quoted 66 lines
*pdev,
drivers/dma/dw-edma/dw-edma-pcie.c static int dw_edma_pcie_probe(struct pci_dev *pdev,
Quoted 9 lines
drivers/dma/dw-edma/dw-edma-pcie.c +3
-2if (pdev->vendor ==PCI_VENDOR_ID_XILINX ) {/* * There is no valid address found for the LL memory -* space on the device side. +* space on the device side. In the absence of LL base +* address use the non-LL mode or simple mode supported by +* the HDMA IP. */ - if (vsec_data->devmem_phys_off ==
DW_PCIE_XILINX_MDB_INVALID_ADDR)drivers/dma/dw-edma/dw-edma-pcie.c static int dw_edma_pcie_probe(struct · line 348
Quoted 2 lines
drivers/dma/dw-edma/dw-edma-pcie.c +1
-1-return -ENOMEM ; + if (vsec_data->devmem_phys_off ==
DW_PCIE_AMD_MDB_INVALID_ADDR)Quoted 23 lines
drivers/dma/dw-edma/dw-edma-pcie.c +9
-5+ non_ll = true;/* * Configure the channel LL and data blocks if number of * channels enabled in VSEC capability are more than the * channels configured in xilinx_mdb_data. */ -dw_edma_set_chan_region_offset (vsec_data,BAR_2 ,0 , -DW_PCIE_XILINX_MDB_LL_OFF_GAP , -DW_PCIE_XILINX_MDB_LL_SIZE , -DW_PCIE_XILINX_MDB_DT_OFF_GAP , -DW_PCIE_XILINX_MDB_DT_SIZE ); +if (!non_ll) +dw_edma_set_chan_region_offset (vsec_data,BAR_2 ,0 , +DW_PCIE_XILINX_LL_OFF_GAP , +DW_PCIE_XILINX_LL_SIZE , + +DW_PCIE_XILINX_DT_OFF_GAP , + +DW_PCIE_XILINX_DT_SIZE ); } /* Mapping PCI BAR regions */ @@ -393,6 +406,7 @@ static intQuoted 1 line
dw_edma_pcie_probe(struct
pci_dev*pdev,
Quoted 16 lines
chip->mf = vsec_data->mf; chip->nr_irqs = nr_irqs; chip->ops = &dw_edma_pcie_plat_ops;+
chip->non_ll=non_ll;chip->ll_wr_cnt = vsec_data->wr_ch_cnt; chip->ll_rd_cnt = vsec_data->rd_ch_cnt; @@ -401,7 +415,7 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev, if (!chip->reg_base) return -ENOMEM;drivers/dma/dw-edma/dw-edma-pcie.c +1
-1-for (i =0 ; i < chip->ll_wr_cnt; i++) { +for (i =0 ; i < chip->ll_wr_cnt && !non_ll; i++) {struct dw_edma_region *ll_region = &chip->ll_region_wr[i];struct dw_edma_region *dt_region = &chip->dt_region_wr[i]; struct dw_edma_block *ll_block =Quoted 2 lines
&vsec_data->ll_wr[i]; @@ -412,7 +426,8 @@ static int dw_edma_pcie_probe(struct
pci_dev*pdev,
Quoted 7 lines
return -ENOMEM; ll_region->vaddr.io += ll_block->off;drivers/dma/dw-edma/dw-edma-pcie.c +3
-1- ll_region->paddr =pci_bus_address (pdev, ll_block->bar); + ll_region->paddr =dw_edma_get_phys_addr (pdev, vsec_data, + + ll_block->bar);
Quoted 8 lines
Quoted 5 lines
Quoted 3 lines
This change need do prepare patch, which only change
pci_bus_address()todw_edma_get_phys_addr().This is not clear.
why not. only trivial add helper patch, which help reviewer
I was not clear on the question you asked.
It does not look justified when a patch is raised alone just to replace this function. The function change is required cause the same code *can* support different IPs from different vendors. And, with this single change alone in the code the support for another IP is added. That's why it is easier to get the reason for the change in the function name and syntax.
Quoted 83 lines
Quoted 5 lines
Quoted 5 lines
drivers/dma/dw-edma/dw-edma-pcie.c static int dw_edma_pcie_probe(struct
Quoted 5 lines
ll_region->paddr += ll_block->off; ll_region->sz = ll_block->sz;drivers/dma/dw-edma/dw-edma-pcie.c +0
-0@@ -421,12 +436,13 @@ static int dw_edma_pcie_probe(struct
pci_devQuoted 66 lines
Quoted 66 lines
*pdev,
Quoted 16 lines
drivers/dma/dw-edma/dw-edma-pcie.c +4
-2return -ENOMEM ; dt_region->vaddr.io += dt_block->off; - dt_region->paddr =pci_bus_address (pdev, dt_block->bar); + dt_region->paddr =dw_edma_get_phys_addr (pdev, vsec_data, + + dt_block->bar); dt_region->paddr += dt_block->off; dt_region->sz = dt_block->sz; } -for (i =0 ; i < chip->ll_rd_cnt; i++) { +for (i =0 ; i < chip->ll_rd_cnt && !non_ll; i++) {struct dw_edma_region *ll_region = &chip->ll_region_rd[i];struct dw_edma_region *dt_region = &chip->dt_region_rd[i]; struct dw_edma_block *ll_block =Quoted 2 lines
&vsec_data->ll_rd[i]; @@ -437,7 +453,8 @@ static int dw_edma_pcie_probe(struct
pci_dev*pdev,
drivers/dma/dw-edma/dw-edma-pcie.c static int dw_edma_pcie_probe(struct pci_dev
Quoted 11 lines
return -ENOMEM; ll_region->vaddr.io += ll_block->off;drivers/dma/dw-edma/dw-edma-pcie.c +3
-1- ll_region->paddr =pci_bus_address (pdev, ll_block->bar); + ll_region->paddr =dw_edma_get_phys_addr (pdev, vsec_data, + + ll_block->bar); ll_region->paddr += ll_block->off; ll_region->sz = ll_block->sz;@@ -446,7 +463,8 @@ static int dw_edma_pcie_probe(struct pci_dev*pdev,
drivers/dma/dw-edma/dw-hdma-v0-core.c static void dw_hdma_v0_sync_ll_data(struct
Quoted 16 lines
drivers/dma/dw-edma/dw-edma-pcie.c +3
-1return -ENOMEM ; dt_region->vaddr.io += dt_block->off; - dt_region->paddr =pci_bus_address (pdev, dt_block->bar); + dt_region->paddr =dw_edma_get_phys_addr (pdev, vsec_data, + + dt_block->bar); dt_region->paddr += dt_block->off; dt_region->sz = dt_block->sz; }drivers/dma/dw-edma/dw-hdma-v0-core.c +0
-0@@ -225,7 +225,7 @@ static void dw_hdma_v0_sync_ll_data(struct
dw_edma_chunk*chunk)Quoted 11 lines
drivers/dma/dw-edma/dw-hdma-v0-core.c +0
-1readl (chunk->ll_region.vaddr.io); } -static void dw_hdma_v0_core_start(struct dw_edma_chunk *chunk,bool
first)drivers/dma/dw-edma/dw-hdma-v0-core.c +2
-0+static void dw_hdma_v0_core_ll_start (struct dw_edma_chunk *chunk, +bool first) {struct dw_edma_chan *chan = chunk->chan; struct dw_edma *dw = chan->dw; @@ -263,6 +263,65 @@ staticvoid dw_hdma_v0_core_start(struct
dw_edma_chunk*chunk, bool first)Quoted 4 lines
SET_CH_32(dw, chan->dir, chan->id, doorbell,
HDMA_V0_DOORBELL_START); }+static void dw_hdma_v0_core_non_ll_start(struct
dw_edma_chunk*chunk)
Quoted 9 lines
Quoted 9 lines
drivers/dma/dw-edma/dw-hdma-v0-core.c static void dw_hdma_v0_core_start(struct dw_edma_chunk *chunk, bool first) · line 273
Quoted 7 lines
drivers/dma/dw-edma/dw-hdma-v0-core.c +7
-0+{ +struct dw_edma_chan *chan = chunk->chan; +struct dw_edma *dw = chan->dw; +struct dw_edma_burst *child; +u32 val; + +list_for_each_entry (child, &chunk->burst->list, list) {why need iterated list, it doesn't support ll. Need wait for irq to start next
one.
Quoted 1 line
Quoted 1 line
Quoted 7 lines
Quoted 3 lines
Quoted 1 line
Frank
Yes, this is true. The format is kept similar to LL mode.
Just fill one.
list_for_each_entry()cause confuse.Frank
I see, we can use list_first_entry_or_null() which is dependent on giving the type of pointer, compared to this list_for_each_entry() looks neat and agnostic to the pointer type being used. Though, it can be explored further. Also, when the chunk is allocated, the comment clearly spells out how the allocation would be for the non LL mode so it is evident that each chunk would have single entry and with that understanding it is clear that loop will also be used in a similar manner, to retrieve a single entry. It is a similar use case as of "do {}while (0)" albeit needs a context to understand it.
Quoted 86 lines
Quoted 48 lines
Quoted 48 lines
Quoted 48 lines
drivers/dma/dw-edma/dw-hdma-v0-core.c +46
-0+SET_CH_32 (dw, chan->dir, chan->id, ch_en, +HDMA_V0_CH_EN ); + +/* Source address */ +SET_CH_32 (dw, chan->dir, chan->id, sar.lsb, +lower_32_bits (child->sar)); +SET_CH_32 (dw, chan->dir, chan->id, sar.msb, +upper_32_bits (child->sar)); + +/* Destination address */ +SET_CH_32 (dw, chan->dir, chan->id, dar.lsb, +lower_32_bits (child->dar)); +SET_CH_32 (dw, chan->dir, chan->id, dar.msb, +upper_32_bits (child->dar)); + +/* Transfer size */ +SET_CH_32 (dw, chan->dir, chan->id, transfer_size, + child->sz); + +/* Interrupt setup */ + val =GET_CH_32 (dw, chan->dir, chan->id, int_setup) | +HDMA_V0_STOP_INT_MASK | +HDMA_V0_ABORT_INT_MASK | +HDMA_V0_LOCAL_STOP_INT_EN | +HDMA_V0_LOCAL_ABORT_INT_EN ; + +if (!(dw->chip->flags &DW_EDMA_CHIP_LOCAL )) { + val |=HDMA_V0_REMOTE_STOP_INT_EN | +HDMA_V0_REMOTE_ABORT_INT_EN ; + } + +SET_CH_32 (dw, chan->dir, chan->id, int_setup, val); + +/* Channel control setup */ + val =GET_CH_32 (dw, chan->dir, chan->id, control1); + val &= ~HDMA_V0_LINKLIST_EN ; +SET_CH_32 (dw, chan->dir, chan->id, control1, val); + +SET_CH_32 (dw, chan->dir, chan->id, doorbell, +HDMA_V0_DOORBELL_START ); + } +} + +static void dw_hdma_v0_core_start (struct dw_edma_chunk *chunk, +bool +first) {Quoted 8 lines
Quoted 8 lines
drivers/dma/dw-edma/dw-hdma-v0-core.c static void dw_hdma_v0_core_start(struct dw_edma_chunk *chunk, bool first) · line 325
Quoted 8 lines
drivers/dma/dw-edma/dw-hdma-v0-core.c +7
-0+struct dw_edma_chan *chan = chunk->chan; + +if (chan->non_ll) +dw_hdma_v0_core_non_ll_start (chunk); +else +dw_hdma_v0_core_ll_start (chunk, first); } +static void dw_hdma_v0_core_ch_config (struct dw_edma_chan *chan){
Quoted 29 lines
Quoted 29 lines
Quoted 29 lines
struct dw_edma *dw = chan->dw; diff --git
a/drivers/dma/dw-edma/dw-hdma-v0-regs.hb/drivers/dma/dw-edma/dw-hdma-v0-regs.h
index eab5fd7..7759ba9 100644drivers/dma/dw-edma/dw-hdma-v0-regs.h +1
-0@@ -12,6 +12,7 @@#include <linux/dmaengine.h> #define HDMA_V0_MAX_NR_CH 8 +#define HDMA_V0_CH_EN BIT(0)#define HDMA_V0_LOCAL_ABORT_INT_EN BIT(6)#define HDMA_V0_REMOTE_ABORT_INT_EN BIT(5)#define HDMA_V0_LOCAL_STOP_INT_EN BIT(4)include/linux/dma/edma.h +1
-1@@ -99,6 +99,7 @@ struct dw_edma_chip {enum dw_edma_map_format mf;struct dw_edma *dw; +bool non_ll; };/* Export to the platform drivers */ --1.8.3.1
Re: [PATCH v8 2/2] dmaengine: dw-edma: Add non-LL mode
Quoted 199 lines · Devendra
[AMD Official Use Only - AMD Internal Distribution Only]
Quoted 60 lines
-----Original Message-----
From: Frank Li <[email protected]>
Sent: Monday, January 19, 2026 9:15 PM
To: Verma, Devendra <[email protected]>
Cc: [email protected]; [email protected]; [email protected]; [email protected]; [email protected]; linux- [email protected]; Simek, Michal <[email protected]>
Subject: Re: [PATCH v8 2/2] dmaengine: dw-edma: Add non-LL modeCaution: This message originated from an External Source. Use proper caution when opening attachments, clicking links, or responding.
Quoted 39 lines · Devendra
[AMD Official Use Only - AMD Internal Distribution Only]
Hi Frank
Please check my response inline.
Regards,
DevendraQuoted 22 lines
-----Original Message-----
From: Frank Li <[email protected]>
Sent: Thursday, January 15, 2026 10:07 PM
To: Verma, Devendra <[email protected]>
Cc: [email protected]; [email protected]; [email protected]; [email protected]; [email protected]; linux- [email protected]; Simek, Michal <[email protected]>
Subject: Re: [PATCH v8 2/2] dmaengine: dw-edma: Add non-LL modeCaution: This message originated from an External Source. Use proper caution when opening attachments, clicking links, or responding.
Quoted 7 lines · Devendra K Verma
AMD MDB IP supports Linked List (LL) mode as well as non-LL mode. The current code does not have the mechanisms to enable the DMA transactions using the non-LL mode. The following two cases are added with this patch:
- For the AMD (Xilinx) only, when a valid physical base address of the device side DDR is not configured, then the IP can still be used in non-LL mode. For all the channels DMA transactions willQuoted 3 lines
If DDR have not configured, where DATA send to in device side by non-LL mode.
The DDR base address in the VSEC capability is used for driving the DMA transfers when used in the LL mode. The DDR is configured and present all the time but the DMA PCIe driver uses this DDR base address (physical address) to configure the LLP address.
Quoted 7 lines
In the scenario, where this DDR base address in VSEC capability is not configured then the current controller cannot be used as the default mode supported is LL mode only. In order to make the controller usable non-LL mode is being added which just needs SAR, DAR, XFERLEN and control register to initiate the transfer. So, the DDR is always present, but the DMA PCIe driver need to know the DDR base physical address to make the transfer. This is useful in scenarios where the memory
Quoted 4 lines
allocated for LL can be used for DMA transactions as well.
Do you means use DMA transfer LL's context?
Yes, the device side memory reserved for the link list to store the descriptors, accessed by the host via
BAR_2in this driver code.Quoted 129 lines
Quoted 35 lines
Quoted 35 lines
Quoted 35 lines
be using the non-LL mode only. This, the default non-LL mode, is not applicable for Synopsys IP with the current code addition.
- If the default mode is LL-mode, for both AMD (Xilinx) and Synosys, and if user wants to use non-LL mode then user can do so via configuring the
peripheral_configparam ofdma_slave_config.Signed-off-by Devendra K Verma <[email protected]>---
Changes in v8
Cosmetic change related to comment and code.Changes in v7
No changeChanges in v6
Gave definition to bits used for channel configuration. Removed the comment related to doorbell.Changes in v5
Variable name 'nollp' changed to 'non_ll'.
In thedw_edma_device_config()WARN_ONreplaced withdev_err(). Comments follow the 80-column guideline.Changes in v4
No changeChanges in v3
No changeChanges in v2
Reverted the function return type to u64 for
dw_edma_get_phys_addr().Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Changes in v1
Changed the function return type fordw_edma_get_phys_addr(). Corrected the typo raised in review.--- drivers/dma/dw-edma/dw-edma-core.c | 42+++++++++++++++++++++---
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
drivers/dma/dw-edma/dw-edma-core.h | 1 + drivers/dma/dw-edma/dw-edma-pcie.c | 46 ++++++++++++++++++--------
Quoted 84 lines
Quoted 74 lines
Quoted 3 lines
drivers/dma/dw-edma/dw-hdma-v0-core.c | 61 ++++++++++++++++++++++++++++++++++- drivers/dma/dw-edma/dw-hdma-v0-regs.h | 1 +
edma-v0-core.chave not update, if don't support, at least need return failure atdw_edma_device_config()when backend is eDMA.drivers/dma/dw-edma/dw-edma-core.c static int dw_edma_device_config(struct
Quoted 9 lines
include/linux/dma/edma.h | 1 + 6 files changed, 132 insertions(+), 20 deletions(-)drivers/dma/dw-edma/dw-edma-core.c +0
-0@@ -223,8 +223,32 @@ static int dw_edma_device_config(struct
dma_chan*dchan,Quoted 32 lines
drivers/dma/dw-edma/dw-edma-core.c +24
-0struct dma_slave_config *config) {struct dw_edma_chan *chan =dchan2dw_edma_chan (dchan); +int non_ll =0 ; + +if (config->peripheral_config && + config->peripheral_size !=sizeof (int )) { +dev_err (dchan->device->dev, +"config param peripheral size mismatch\n" ); +return -EINVAL ; + }memcpy (&chan->config, config,sizeof (*config)); + +/* +* When there is no valid LLP base address available then the default +* DMA ops will use the non-LL mode. +* +* Cases where LL mode is enabled and client wants to use the non-LL +* mode then also client can do so via providing the peripheral_config +* param. +*/ +if (config->peripheral_config) + non_ll = *(int *)config->peripheral_config; + + chan->non_ll = false; +if (chan->dw->chip->non_ll || (!chan->dw->chip->non_ll && non_ll)) + chan->non_ll = true; + chan->configured = true;return 0 ;@@ -353,7 +377,7 @@ static voidQuoted 1 line
dw_edma_device_issue_pending(struct
dma_chan*dchan)Quoted 10 lines
struct dw_edma_chan *chan = dchan2dw_edma_chan(xfer->dchan); enum dma_transfer_direction dir = xfer->direction; struct scatterlist *sg = NULL;drivers/dma/dw-edma/dw-edma-core.c +1
-1-struct dw_edma_chunk *chunk; +struct dw_edma_chunk *chunk =NULL ;struct dw_edma_burst *burst;struct dw_edma_desc *desc;u64 src_addr, dst_addr;@@ -419,9 +443,11 @@ static voiddw_edma_device_issue_pending(struct
dma_chan*dchan)drivers/dma/dw-edma/dw-edma-core.c static void dw_edma_device_issue_pending(struct dma_chan *dchan) · line 450
Quoted 11 lines
if (unlikely(!desc)) goto err_alloc;drivers/dma/dw-edma/dw-edma-core.c +5
-3- chunk =dw_edma_alloc_chunk (desc); -if (unlikely (!chunk)) - goto err_alloc; +if (!chan->non_ll) { + chunk =dw_edma_alloc_chunk (desc); +if (unlikely (!chunk)) + goto err_alloc; + }Quoted 4 lines
non_llis the same asll_max= 1. (or 2, there are link back entry).If you set
ll_max= 1, needn't change this code.The
ll_maxis defined for the session till the driver is loaded in the kernel. This code also enables the non-LL mode dynamically upon input from the DMA client. In this scenario, touchingll_maxwould not be a good idea as thell_maxcontrols the LL entries for all the DMA channels not just for a single DMA transaction.
Quoted 6 lines
Quoted 2 lines
You can use new variable, such as
ll_avail.In order to separate out the execution paths a new meaningful variable "
non_ll" is used. The variable "non_ll" alone is sufficient. Using another variable along side "non_ll" for the similar purpose may not have any added advantage.
ll_avail can help debug/fine tune how much impact preformance by adjust ll length. And it make code logic clean and consistent. also ll_avail can help test corner case when ll item small. Normall case it is hard to reach ll_max.
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
...
Quoted 12 lines
Quoted 11 lines
Quoted 8 lines
Quoted 6 lines
Quoted 2 lines
+
+ll_block->bar);This change need do prepare patch, which only change
pci_bus_address()todw_edma_get_phys_addr().This is not clear.
why not. only trivial add helper patch, which help reviewer
Quoted 6 lines
I was not clear on the question you asked.
It does not look justified when a patch is raised alone just to replace this function. The function change is required cause the same code *can* support different IPs from different vendors. And, with this single change alone in the code the support for another IP is added. That's why it is easier to get the reason for the change in the function name and syntax.
Add replace pci_bus_address() with dw_edma_get_phys_addr() to make review easily and get ack for such replacement patches.
two patches
patch1, just replace exist pci_bus_address() with dw_edma_get_phys_addr() patch2, add new logic in dw_edma_get_phys_addr() to support new vendor.
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
ll_region->paddr += ll_block->off; ll_region->sz = ll_block->sz;
...
Quoted 22 lines
Quoted 14 lines
Quoted 12 lines
Quoted 12 lines
Quoted 2 lines
+static void dw_hdma_v0_core_non_ll_start(struct
dw_edma_chunk*chunk)
drivers/dma/dw-edma/dw-edma-core.c
Quoted 7 lines
drivers/dma/dw-edma/dw-edma-core.c +7
-0+{ +struct dw_edma_chan *chan = chunk->chan; +struct dw_edma *dw = chan->dw; +struct dw_edma_burst *child; +u32 val; + +list_for_each_entry (child, &chunk->burst->list, list) {why need iterated list, it doesn't support ll. Need wait for irq to start next
one.
Quoted 1 line
Quoted 1 line
Quoted 7 lines
Quoted 3 lines
Quoted 1 line
Frank
Yes, this is true. The format is kept similar to LL mode.
Just fill one.
list_for_each_entry()cause confuse.Frank
Quoted 8 lines
I see, we can use
list_first_entry_or_null()which is dependent on giving the type of pointer, compared to thislist_for_each_entry()looks neat and agnostic to the pointer type being used. Though, it can be explored further. Also, when the chunk is allocated, the comment clearly spells out how the allocation would be for the non LL mode so it is evident that each chunk would have single entry and with that understanding it is clear that loop will also be used in a similar manner, to retrieve a single entry. It is a similar use case as of "do {}while (0)" albeit needs a context to understand it.
I don't think so. list_for_each_entry() is miss leading to reader think it is not only to one item in burst list, and use polling method to to finish many burst transfer.
list_for_each_entry() {
...
readl_timeout()
}Generally, EDMA is very quick, polling is much quicker than irq if data is small.
Frank
Quoted 87 lines
Quoted 87 lines
Quoted 49 lines
Quoted 49 lines
Quoted 49 lines
drivers/dma/dw-edma/dw-edma-core.c +46
-0+SET_CH_32 (dw, chan->dir, chan->id, ch_en, +HDMA_V0_CH_EN ); + +/* Source address */ +SET_CH_32 (dw, chan->dir, chan->id, sar.lsb, +lower_32_bits (child->sar)); +SET_CH_32 (dw, chan->dir, chan->id, sar.msb, +upper_32_bits (child->sar)); + +/* Destination address */ +SET_CH_32 (dw, chan->dir, chan->id, dar.lsb, +lower_32_bits (child->dar)); +SET_CH_32 (dw, chan->dir, chan->id, dar.msb, +upper_32_bits (child->dar)); + +/* Transfer size */ +SET_CH_32 (dw, chan->dir, chan->id, transfer_size, + child->sz); + +/* Interrupt setup */ + val =GET_CH_32 (dw, chan->dir, chan->id, int_setup) | +HDMA_V0_STOP_INT_MASK | +HDMA_V0_ABORT_INT_MASK | +HDMA_V0_LOCAL_STOP_INT_EN | +HDMA_V0_LOCAL_ABORT_INT_EN ; + +if (!(dw->chip->flags &DW_EDMA_CHIP_LOCAL )) { + val |=HDMA_V0_REMOTE_STOP_INT_EN | +HDMA_V0_REMOTE_ABORT_INT_EN ; + } + +SET_CH_32 (dw, chan->dir, chan->id, int_setup, val); + +/* Channel control setup */ + val =GET_CH_32 (dw, chan->dir, chan->id, control1); + val &= ~HDMA_V0_LINKLIST_EN ; +SET_CH_32 (dw, chan->dir, chan->id, control1, val); + +SET_CH_32 (dw, chan->dir, chan->id, doorbell, +HDMA_V0_DOORBELL_START ); + } +} + +static void dw_hdma_v0_core_start (struct dw_edma_chunk *chunk, +bool +first) {Quoted 8 lines
Quoted 8 lines
drivers/dma/dw-edma/dw-edma-core.c
Quoted 8 lines
drivers/dma/dw-edma/dw-edma-core.c +7
-0+struct dw_edma_chan *chan = chunk->chan; + +if (chan->non_ll) +dw_hdma_v0_core_non_ll_start (chunk); +else +dw_hdma_v0_core_ll_start (chunk, first); } +static void dw_hdma_v0_core_ch_config (struct dw_edma_chan *chan){
Quoted 29 lines
Quoted 29 lines
Quoted 29 lines
struct dw_edma *dw = chan->dw; diff --git
a/drivers/dma/dw-edma/dw-hdma-v0-regs.hb/drivers/dma/dw-edma/dw-hdma-v0-regs.h
index eab5fd7..7759ba9 100644drivers/dma/dw-edma/dw-hdma-v0-regs.h +1
-0@@ -12,6 +12,7 @@#include <linux/dmaengine.h> #define HDMA_V0_MAX_NR_CH 8 +#define HDMA_V0_CH_EN BIT(0)#define HDMA_V0_LOCAL_ABORT_INT_EN BIT(6)#define HDMA_V0_REMOTE_ABORT_INT_EN BIT(5)#define HDMA_V0_LOCAL_STOP_INT_EN BIT(4)include/linux/dma/edma.h +1
-1@@ -99,6 +99,7 @@ struct dw_edma_chip {enum dw_edma_map_format mf;struct dw_edma *dw; +bool non_ll; };/* Export to the platform drivers */ --1.8.3.1
RE: [PATCH v8 2/2] dmaengine: dw-edma: Add non-LL mode
[AMD Official Use Only - AMD Internal Distribution Only]
Quoted 11 lines
-----Original Message-----
From: Frank Li <[email protected]>
Sent: Wednesday, January 21, 2026 10:49 PM
To: Verma, Devendra <[email protected]>
Cc: [email protected]; [email protected]; [email protected]; [email protected]; [email protected]; linux- [email protected]; Simek, Michal <[email protected]>
Subject: Re: [PATCH v8 2/2] dmaengine: dw-edma: Add non-LL modeCaution: This message originated from an External Source. Use proper caution when opening attachments, clicking links, or responding.
--[ Snipped some headers to reduce the size of this mail ]--
Quoted 177 lines
Quoted 28 lines
Quoted 28 lines
Quoted 28 lines
Quoted 11 lines · Devendra K Verma
Quoted 8 lines
AMD MDB IP supports Linked List (LL) mode as well as non-LL mode. The current code does not have the mechanisms to enable the DMA transactions using the non-LL mode. The following two cases are added with this patch:
- For the AMD (Xilinx) only, when a valid physical base address of the device side DDR is not configured, then the IP can still be used in non-LL mode. For all the channels DMA transactions
willQuoted 3 lines
If DDR have not configured, where DATA send to in device side by non-LL mode.
The DDR base address in the VSEC capability is used for driving the DMA transfers when used in the LL mode. The DDR is configured and present all the time but the DMA PCIe driver uses this DDR base address (physical address) to configure the LLP address.
In the scenario, where this DDR base address in VSEC capability is not configured then the current controller cannot be used as the default mode supported is LL mode only. In order to make the controller usable non-LL mode is being added which just needs SAR, DAR, XFERLEN and control register to initiate the transfer. So, the DDR is always present, but the DMA PCIe driver need to know the DDR base physical address to make the transfer. This is useful in scenarios where the memory
Quoted 31 lines
Quoted 4 lines
allocated for LL can be used for DMA transactions as well.
Do you means use DMA transfer LL's context?
Yes, the device side memory reserved for the link list to store the descriptors, accessed by the host via
BAR_2in this driver code.Quoted 23 lines
Quoted 23 lines
Quoted 23 lines
Quoted 23 lines
be using the non-LL mode only. This, the default non-LL mode, is not applicable for Synopsys IP with the current code addition.
- If the default mode is LL-mode, for both AMD (Xilinx) and Synosys, and if user wants to use non-LL mode then user can do so via configuring the
peripheral_configparam ofdma_slave_config.Signed-off-by Devendra K Verma <[email protected]>---
Changes in v8
Cosmetic change related to comment and code.Changes in v7
No changeChanges in v6
Gave definition to bits used for channel configuration. Removed the comment related to doorbell.Changes in v5
Variable name 'nollp' changed to 'non_ll'. In thedw_edma_device_config()WARN_ONreplaced with
dev_err().Quoted 12 lines
Quoted 12 lines
Quoted 12 lines
Quoted 12 lines
Quoted 12 lines
Comments follow the 80-column guideline.
Changes in v4
No changeChanges in v3
No changeChanges in v2
Reverted the function return type to u64 for
dw_edma_get_phys_addr().Quoted 8 lines
Quoted 8 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Changes in v1
Changed the function return type fordw_edma_get_phys_addr(). Corrected the typo raised in review.--- drivers/dma/dw-edma/dw-edma-core.c | 42+++++++++++++++++++++---
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
drivers/dma/dw-edma/dw-edma-core.h | 1 + drivers/dma/dw-edma/dw-edma-pcie.c | 46++++++++++++++++++--
Quoted 29 lines
Quoted 29 lines
------
Quoted 28 lines
Quoted 28 lines
Quoted 3 lines
drivers/dma/dw-edma/dw-hdma-v0-core.c | 61 ++++++++++++++++++++++++++++++++++- drivers/dma/dw-edma/dw-hdma-v0-regs.h | 1 +
edma-v0-core.chave not update, if don't support, at least need return failure atdw_edma_device_config()when backend is eDMA.drivers/dma/dw-edma/dw-edma-core.c static int dw_edma_device_config(struct
Quoted 9 lines
include/linux/dma/edma.h | 1 + 6 files changed, 132 insertions(+), 20 deletions(-)drivers/dma/dw-edma/dw-edma-core.c +0
-0@@ -223,8 +223,32 @@ static int dw_edma_device_config(struct
dma_chan*dchan,Quoted 11 lines
drivers/dma/dw-edma/dw-edma-core.c +8
-0struct dma_slave_config *config) {struct dw_edma_chan *chan =dchan2dw_edma_chan (dchan); +int non_ll =0 ; + +if (config->peripheral_config && + config->peripheral_size !=sizeof (int )) { +dev_err (dchan->device->dev, +"config param peripheral size mismatch\n" ); +return -EINVAL ; + }Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
drivers/dma/dw-edma/dw-edma-core.c static int dw_edma_device_config(struct dma_chan *dchan,
Quoted 4 lines
drivers/dma/dw-edma/dw-edma-core.c +3
-0memcpy (&chan->config, config,sizeof (*config)); + +/* +* When there is no valid LLP base address available then the default
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
drivers/dma/dw-edma/dw-edma-core.c static int dw_edma_device_config(struct dma_chan *dchan,
Quoted 3 lines
drivers/dma/dw-edma/dw-edma-core.c +3
-0+* DMA ops will use the non-LL mode. +* +* Cases where LL mode is enabled and client wants to use the non-LL
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
drivers/dma/dw-edma/dw-edma-core.c static int dw_edma_device_config(struct · line 241
Quoted 1 line
drivers/dma/dw-edma/dw-edma-core.c +1
-0+* mode then also client can do so via providing the
peripheral_configQuoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
drivers/dma/dw-edma/dw-edma-core.c static int dw_edma_device_config(struct dma_chan *dchan,
Quoted 7 lines
drivers/dma/dw-edma/dw-edma-core.c +7
-0+* param. +*/ +if (config->peripheral_config) + non_ll = *(int *)config->peripheral_config; + + chan->non_ll = false; + if (chan->dw->chip->non_ll || (!chan->dw->chip->non_ll &&
non_ll))Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
drivers/dma/dw-edma/dw-edma-core.c +2
-0+ chan->non_ll = true; + chan->configured = true;Quoted 34 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 3 lines
drivers/dma/dw-edma/dw-edma-core.c +0
-0return 0 ;@@ -353,7 +377,7 @@ static voiddw_edma_device_issue_pending(struct
dma_chan*dchan)Quoted 1 line
struct
dw_edma_chan*chan = dchan2dw_edma_chan(xfer-dchan);
Quoted 28 lines
Quoted 28 lines
Quoted 22 lines
Quoted 9 lines
enum dma_transfer_direction dir = xfer->direction; struct scatterlist *sg = NULL;drivers/dma/dw-edma/dw-edma-core.c +1
-1-struct dw_edma_chunk *chunk; +struct dw_edma_chunk *chunk =NULL ;struct dw_edma_burst *burst;struct dw_edma_desc *desc;u64 src_addr, dst_addr;@@ -419,9 +443,11 @@ static voiddw_edma_device_issue_pending(struct
dma_chan*dchan)drivers/dma/dw-edma/dw-edma-core.c static void dw_edma_device_issue_pending(struct dma_chan *dchan) · line 450
Quoted 11 lines
if (unlikely(!desc)) goto err_alloc;drivers/dma/dw-edma/dw-edma-core.c +5
-3- chunk =dw_edma_alloc_chunk (desc); -if (unlikely (!chunk)) - goto err_alloc; +if (!chan->non_ll) { + chunk =dw_edma_alloc_chunk (desc); +if (unlikely (!chunk)) + goto err_alloc; + }Quoted 4 lines
non_llis the same asll_max= 1. (or 2, there are link back entry).If you set
ll_max= 1, needn't change this code.The
ll_maxis defined for the session till the driver is loaded in thekernel.
Quoted 9 lines
Quoted 7 lines
Quoted 4 lines
This code also enables the non-LL mode dynamically upon input from the DMA client. In this scenario, touching
ll_maxwould not be a good idea as thell_maxcontrols the LL entries for all the DMA channels not just for a single DMA transaction.You can use new variable, such as
ll_avail.In order to separate out the execution paths a new meaningful variable
Quoted 9 lines
"
non_ll"Quoted 2 lines
is used. The variable "
non_ll" alone is sufficient. Using another variable along side "non_ll" for the similar purpose may not have anyadded advantage.
ll_availcan help debug/fine tune how much impact preformance by adjust ll length. And it make code logic clean and consistent. alsoll_availcan help test corner case when ll item small. Normall case it is hard to reachll_max.
Thank you for your suggestion. The ll_max is max limit on the descriptors that can be accommodated on the device side DDR. The ll_avail will always be less than ll_max. The optimization being referred can be tried without even having to declare the ll_avail cause the number of descriptors given can be controlled by the DMA client based on the length argument to the dmaengine_prep_* APIs. So, the use of dynamic ll_avail is not necessarily required. Without increasing the ll_max, ll_avail cannot be increased. In order to increase ll_max one may need to alter size and recompile this driver.
However, the requirement of ll_avail does not help for the supporting the non-LL mode. For non-LL mode to use:
1) Either LL mode shall be not available, as it can happen for the Xilinx IP.
2) User provides the preference for non-LL mode.
For both above, the function calls are different which can be differentiated by using the "non_ll" flag. So, even if I try to accommodate ll_avail, the call for LL or non-LL would be ambiguous as in case of LL mode also we can have a single descriptor as similar to non-LL mode. Please check the function dw_hdma_v0_core_start() in this review where the decision is taken Based on non_ll flag.
Quoted 24 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
...
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 6 lines
Quoted 2 lines
+
+ll_block->bar);This change need do prepare patch, which only change
pci_bus_address()todw_edma_get_phys_addr().Quoted 7 lines
Quoted 4 lines
Quoted 1 line
This is not clear.
why not. only trivial add helper patch, which help reviewer
I was not clear on the question you asked.
It does not look justified when a patch is raised alone just to replace thisfunction.
Quoted 4 lines
The function change is required cause the same code *can* support different IPs from different vendors. And, with this single change alone in the code the support for another IP is added. That's why it is easier to get the reason for the change in the function name and syntax.
Quoted 7 lines
Add replace
pci_bus_address()withdw_edma_get_phys_addr()to make review easily and get ack for such replacement patches.two patches
patch1, just replace existpci_bus_address()withdw_edma_get_phys_addr()patch2, add new logic indw_edma_get_phys_addr()to support new vendor.
I understand your concern about making the review easier. However, given that we've been iterating on this patch series since September and are now at v9, I believe the current approach is justified. The function renames from pci_bus_address() to dw_edma_get_phys_addr() is directly tied to the non-LL mode functionality being added - it's needed because the same code now supports different IPs from different vendors.
Splitting this into a separate preparatory patch at this stage would further delay the review process. The change is kind of straightforward and the context is clear within the current patch. I request you to review this patch to avoid additional review cycles.
This also increases the work related to testing and maintaining multiple patches. I have commitment for delivery of this, and I can see adding one more series definitely add 3-4 months of review cycle from here. Please excuse me but this code has already been reviewed extensively by other reviewers and almost by you as well. You can check the detailed discussion wrt this function at the following link:
https://lore.kernel.org/all/SA1PR12MB8120341DFFD56D90EAD70EDE9514A@SA1PR12MB8120.namprd12.prod.outlook.com/
Quoted 44 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
ll_region->paddr += ll_block->off; ll_region->sz = ll_block->sz;...
Quoted 19 lines
Quoted 19 lines
Quoted 13 lines
Quoted 13 lines
Quoted 2 lines
+static void dw_hdma_v0_core_non_ll_start(struct
dw_edma_chunk*chunk)
drivers/dma/dw-edma/dw-edma-core.c
Quoted 7 lines
drivers/dma/dw-edma/dw-edma-core.c +7
-0+{ +struct dw_edma_chan *chan = chunk->chan; +struct dw_edma *dw = chan->dw; +struct dw_edma_burst *child; +u32 val; + +list_for_each_entry (child, &chunk->burst->list, list) {why need iterated list, it doesn't support ll. Need wait for irq to start next
one.
Quoted 4 lines
Quoted 2 lines
Frank
Yes, this is true. The format is kept similar to LL mode.
Quoted 7 lines
Quoted 3 lines
Just fill one.
list_for_each_entry()cause confuse.Frank
I see, we can use
list_first_entry_or_null()which is dependent on giving the type of pointer, compared to thislist_for_each_entry()looks neat and agnostic to the pointer type being used. Though, it can beexplored further.
Quoted 5 lines
Also, when the chunk is allocated, the comment clearly spells out how the allocation would be for the non LL mode so it is evident that each chunk would have single entry and with that understanding it is clear that loop will also be used in a similar manner, to retrieve a single entry. It is a similar use case as of "do {}while (0)" albeit needs a context to
understand it.
I don't think so.
list_for_each_entry()is miss leading to reader think it is not only to one item in burst list, and use polling method to to finish many burst transfer.
Quoted 9 lines
list_for_each_entry() { ... readl_timeout() }Generally, EDMA is very quick, polling is much quicker than irq if data is small.
Frank
The polling is not required. The single burst will raise the interrupt and from the interrupt context another chunk will be scheduled. This cycle repeats till all the chunks with single burst are exhausted.
The following comment made in function dw_edma_device_transfer() in the same patch makes it amply clear that only a single burst would be handled for the non-LL mode.
+ /*
+ * For non-LL mode, only a single burst can be handled + * in a single chunk unlike LL mode where multiple bursts + * can be configured in a single chunk. + */
Looking at the way bursts are appended to chunks and chunks in dw_edma_device_transfer() are scheduled for non-LL mode then it is clear what non-LL mode would handle in terms of bursts. I just kept the format to match it with the LL mode format otherwise there is no need of this comment and we can follow the syntax for a single entry alone. Please share your suggestion if these descriptions fail to provide the clear context and intent.
Quoted 91 lines
Quoted 91 lines
Quoted 91 lines
Quoted 53 lines
Quoted 53 lines
Quoted 53 lines
drivers/dma/dw-edma/dw-edma-core.c +50
-0+SET_CH_32 (dw, chan->dir, chan->id, ch_en, +HDMA_V0_CH_EN ); + +/* Source address */ +SET_CH_32 (dw, chan->dir, chan->id, sar.lsb, +lower_32_bits (child->sar)); +SET_CH_32 (dw, chan->dir, chan->id, sar.msb, +upper_32_bits (child->sar)); + +/* Destination address */ +SET_CH_32 (dw, chan->dir, chan->id, dar.lsb, +lower_32_bits (child->dar)); +SET_CH_32 (dw, chan->dir, chan->id, dar.msb, +upper_32_bits (child->dar)); + +/* Transfer size */ +SET_CH_32 (dw, chan->dir, chan->id, + transfer_size, + child->sz); + +/* Interrupt setup */ + val =GET_CH_32 (dw, chan->dir, chan->id, int_setup) | +HDMA_V0_STOP_INT_MASK | +HDMA_V0_ABORT_INT_MASK | +HDMA_V0_LOCAL_STOP_INT_EN | +HDMA_V0_LOCAL_ABORT_INT_EN ; + +if (!(dw->chip->flags &DW_EDMA_CHIP_LOCAL )) { + val |=HDMA_V0_REMOTE_STOP_INT_EN | +HDMA_V0_REMOTE_ABORT_INT_EN ; + } + +SET_CH_32 (dw, chan->dir, chan->id, int_setup, + val); + +/* Channel control setup */ + val =GET_CH_32 (dw, chan->dir, chan->id, control1); + val &= ~HDMA_V0_LINKLIST_EN ; +SET_CH_32 (dw, chan->dir, chan->id, control1, + val); + +SET_CH_32 (dw, chan->dir, chan->id, doorbell, +HDMA_V0_DOORBELL_START ); + } +} + +static void dw_hdma_v0_core_start (struct dw_edma_chunk +*chunk,bool +first) { +struct dw_edma_chan *chan = chunk->chan;Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
drivers/dma/dw-edma/dw-edma-core.c +6
-0+ +if (chan->non_ll) +dw_hdma_v0_core_non_ll_start (chunk); +else +dw_hdma_v0_core_ll_start (chunk, first); } + static void dw_hdma_v0_core_ch_config(struct dw_edma_chan*chan)
{
Quoted 29 lines
Quoted 29 lines
Quoted 29 lines
struct dw_edma *dw = chan->dw; diff --git
a/drivers/dma/dw-edma/dw-hdma-v0-regs.hb/drivers/dma/dw-edma/dw-hdma-v0-regs.h
index eab5fd7..7759ba9 100644drivers/dma/dw-edma/dw-hdma-v0-regs.h +1
-0@@ -12,6 +12,7 @@#include <linux/dmaengine.h> #define HDMA_V0_MAX_NR_CH 8 +#define HDMA_V0_CH_EN BIT(0)#define HDMA_V0_LOCAL_ABORT_INT_EN BIT(6)#define HDMA_V0_REMOTE_ABORT_INT_EN BIT(5)#define HDMA_V0_LOCAL_STOP_INT_EN BIT(4)(quoted diff) +0
-0
b/include/linux/dma/edma.hindex 3080747..78ce31b 100644include/linux/dma/edma.h +1
-1@@ -99,6 +99,7 @@ struct dw_edma_chip {enum dw_edma_map_format mf;struct dw_edma *dw; +bool non_ll; };/* Export to the platform drivers */ --1.8.3.1
Re: [PATCH v8 2/2] dmaengine: dw-edma: Add non-LL mode
Quoted 203 lines · Devendra
[AMD Official Use Only - AMD Internal Distribution Only]
Quoted 11 lines
-----Original Message-----
From: Frank Li <[email protected]>
Sent: Wednesday, January 21, 2026 10:49 PM
To: Verma, Devendra <[email protected]>
Cc: [email protected]; [email protected]; [email protected]; [email protected]; [email protected]; linux- [email protected]; Simek, Michal <[email protected]>
Subject: Re: [PATCH v8 2/2] dmaengine: dw-edma: Add non-LL modeCaution: This message originated from an External Source. Use proper caution when opening attachments, clicking links, or responding.
--[ Snipped some headers to reduce the size of this mail ]--
Quoted 177 lines
Quoted 28 lines
Quoted 28 lines
Quoted 28 lines
Quoted 11 lines · Devendra K Verma
Quoted 8 lines
AMD MDB IP supports Linked List (LL) mode as well as non-LL mode. The current code does not have the mechanisms to enable the DMA transactions using the non-LL mode. The following two cases are added with this patch:
- For the AMD (Xilinx) only, when a valid physical base address of the device side DDR is not configured, then the IP can still be used in non-LL mode. For all the channels DMA transactions
willQuoted 3 lines
If DDR have not configured, where DATA send to in device side by non-LL mode.
The DDR base address in the VSEC capability is used for driving the DMA transfers when used in the LL mode. The DDR is configured and present all the time but the DMA PCIe driver uses this DDR base address (physical address) to configure the LLP address.
In the scenario, where this DDR base address in VSEC capability is not configured then the current controller cannot be used as the default mode supported is LL mode only. In order to make the controller usable non-LL mode is being added which just needs SAR, DAR, XFERLEN and control register to initiate the transfer. So, the DDR is always present, but the DMA PCIe driver need to know the DDR base physical address to make the transfer. This is useful in scenarios where the memory
Quoted 31 lines
Quoted 4 lines
allocated for LL can be used for DMA transactions as well.
Do you means use DMA transfer LL's context?
Yes, the device side memory reserved for the link list to store the descriptors, accessed by the host via
BAR_2in this driver code.Quoted 23 lines
Quoted 23 lines
Quoted 23 lines
Quoted 23 lines
be using the non-LL mode only. This, the default non-LL mode, is not applicable for Synopsys IP with the current code addition.
- If the default mode is LL-mode, for both AMD (Xilinx) and Synosys, and if user wants to use non-LL mode then user can do so via configuring the
peripheral_configparam ofdma_slave_config.Signed-off-by Devendra K Verma <[email protected]>---
Changes in v8
Cosmetic change related to comment and code.Changes in v7
No changeChanges in v6
Gave definition to bits used for channel configuration. Removed the comment related to doorbell.Changes in v5
Variable name 'nollp' changed to 'non_ll'. In thedw_edma_device_config()WARN_ONreplaced with
dev_err().Quoted 12 lines
Quoted 12 lines
Quoted 12 lines
Quoted 12 lines
Quoted 12 lines
Comments follow the 80-column guideline.
Changes in v4
No changeChanges in v3
No changeChanges in v2
Reverted the function return type to u64 for
dw_edma_get_phys_addr().Quoted 8 lines
Quoted 8 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Changes in v1
Changed the function return type fordw_edma_get_phys_addr(). Corrected the typo raised in review.--- drivers/dma/dw-edma/dw-edma-core.c | 42+++++++++++++++++++++---
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
drivers/dma/dw-edma/dw-edma-core.h | 1 + drivers/dma/dw-edma/dw-edma-pcie.c | 46++++++++++++++++++--
Quoted 29 lines
Quoted 29 lines
------
Quoted 28 lines
Quoted 28 lines
Quoted 3 lines
drivers/dma/dw-edma/dw-hdma-v0-core.c | 61 ++++++++++++++++++++++++++++++++++- drivers/dma/dw-edma/dw-hdma-v0-regs.h | 1 +
edma-v0-core.chave not update, if don't support, at least need return failure atdw_edma_device_config()when backend is eDMA.drivers/dma/dw-edma/dw-edma-core.c static int dw_edma_device_config(struct
Quoted 9 lines
include/linux/dma/edma.h | 1 + 6 files changed, 132 insertions(+), 20 deletions(-)drivers/dma/dw-edma/dw-edma-core.c +0
-0@@ -223,8 +223,32 @@ static int dw_edma_device_config(struct
dma_chan*dchan,Quoted 11 lines
drivers/dma/dw-edma/dw-edma-core.c +8
-0struct dma_slave_config *config) {struct dw_edma_chan *chan =dchan2dw_edma_chan (dchan); +int non_ll =0 ; + +if (config->peripheral_config && + config->peripheral_size !=sizeof (int )) { +dev_err (dchan->device->dev, +"config param peripheral size mismatch\n" ); +return -EINVAL ; + }Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
drivers/dma/dw-edma/dw-edma-core.c static int dw_edma_device_config(struct · line 237
Quoted 4 lines
drivers/dma/dw-edma/dw-edma-core.c +3
-0memcpy (&chan->config, config,sizeof (*config)); + +/* +* When there is no valid LLP base address available then the default
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
drivers/dma/dw-edma/dw-edma-core.c static int dw_edma_device_config(struct · line 240
Quoted 3 lines
drivers/dma/dw-edma/dw-edma-core.c +3
-0+* DMA ops will use the non-LL mode. +* +* Cases where LL mode is enabled and client wants to use the non-LL
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
drivers/dma/dw-edma/dw-edma-core.c static int dw_edma_device_config(struct · line 241
Quoted 1 line
drivers/dma/dw-edma/dw-edma-core.c +1
-0+* mode then also client can do so via providing the
peripheral_configQuoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
drivers/dma/dw-edma/dw-edma-core.c static int dw_edma_device_config(struct · line 248
Quoted 7 lines
drivers/dma/dw-edma/dw-edma-core.c +7
-0+* param. +*/ +if (config->peripheral_config) + non_ll = *(int *)config->peripheral_config; + + chan->non_ll = false; + if (chan->dw->chip->non_ll || (!chan->dw->chip->non_ll &&
non_ll))Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
drivers/dma/dw-edma/dw-edma-core.c +2
-0+ chan->non_ll = true; + chan->configured = true;Quoted 34 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 3 lines
drivers/dma/dw-edma/dw-edma-core.c +0
-0return 0 ;@@ -353,7 +377,7 @@ static voiddw_edma_device_issue_pending(struct
dma_chan*dchan)Quoted 1 line
struct
dw_edma_chan*chan = dchan2dw_edma_chan(xfer-dchan);
Quoted 28 lines
Quoted 28 lines
Quoted 22 lines
Quoted 9 lines
enum dma_transfer_direction dir = xfer->direction; struct scatterlist *sg = NULL;drivers/dma/dw-edma/dw-edma-core.c +1
-1-struct dw_edma_chunk *chunk; +struct dw_edma_chunk *chunk =NULL ;struct dw_edma_burst *burst;struct dw_edma_desc *desc;u64 src_addr, dst_addr;@@ -419,9 +443,11 @@ static voiddw_edma_device_issue_pending(struct
dma_chan*dchan)drivers/dma/dw-edma/dw-edma-core.c
Quoted 11 lines
if (unlikely(!desc)) goto err_alloc;drivers/dma/dw-edma/dw-edma-core.c +5
-3- chunk =dw_edma_alloc_chunk (desc); -if (unlikely (!chunk)) - goto err_alloc; +if (!chan->non_ll) { + chunk =dw_edma_alloc_chunk (desc); +if (unlikely (!chunk)) + goto err_alloc; + }Quoted 4 lines
non_llis the same asll_max= 1. (or 2, there are link back entry).If you set
ll_max= 1, needn't change this code.The
ll_maxis defined for the session till the driver is loaded in thekernel.
Quoted 9 lines
Quoted 7 lines
Quoted 4 lines
This code also enables the non-LL mode dynamically upon input from the DMA client. In this scenario, touching
ll_maxwould not be a good idea as thell_maxcontrols the LL entries for all the DMA channels not just for a single DMA transaction.You can use new variable, such as
ll_avail.In order to separate out the execution paths a new meaningful variable
Quoted 9 lines
"
non_ll"Quoted 2 lines
is used. The variable "
non_ll" alone is sufficient. Using another variable along side "non_ll" for the similar purpose may not have anyadded advantage.
ll_availcan help debug/fine tune how much impact preformance by adjust ll length. And it make code logic clean and consistent. alsoll_availcan help test corner case when ll item small. Normall case it is hard to reachll_max.
Quoted 5 lines
Thank you for your suggestion. The
ll_maxis max limit on the descriptors that can be accommodated on the device side DDR. Thell_availwill always be less thanll_max. The optimization being referred can be tried without even having to declare thell_availcause the number of descriptors given can be controlled by the DMA client based on the length argument to the dmaengine_prep_* APIs.
I optimzied it to allow dynatmic appended dma descriptors.
https://lore.kernel.org/dmaengine/[email protected]/T/#t
Quoted 4 lines
So, the use of dynamic
ll_availis not necessarily
required. Without increasing thell_max,ll_availcannot be increased. In order to increasell_maxone may need to alter size and recompile this driver.
Quoted 9 lines
However, the requirement of
ll_availdoes not help for the supporting the non-LL mode. For non-LL mode to use:
1) Either LL mode shall be not available, as it can happen for the Xilinx IP.
2) User provides the preference for non-LL mode.
For both above, the function calls are different which can be differentiated by using the "non_ll" flag. So, even if I try to accommodatell_avail, the call for LL or non-LL would be ambiguous as in case of LL mode also we can have a single descriptor as similar to non-LL mode. Please check the functiondw_hdma_v0_core_start()in this review where the decision is taken Based onnon_llflag.
We can treat ll_avail == 1 as no_ll mode because needn't set extra LL in memory at all.
Quoted 40 lines
Quoted 25 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
...
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 6 lines
Quoted 2 lines
+
+ll_block->bar);This change need do prepare patch, which only change
pci_bus_address()todw_edma_get_phys_addr().Quoted 7 lines
Quoted 4 lines
Quoted 1 line
This is not clear.
why not. only trivial add helper patch, which help reviewer
I was not clear on the question you asked.
It does not look justified when a patch is raised alone just to replace thisfunction.
Quoted 4 lines
The function change is required cause the same code *can* support different IPs from different vendors. And, with this single change alone in the code the support for another IP is added. That's why it is easier to get the reason for the change in the function name and syntax.
Quoted 7 lines
Add replace
pci_bus_address()withdw_edma_get_phys_addr()to make review easily and get ack for such replacement patches.two patches
patch1, just replace existpci_bus_address()withdw_edma_get_phys_addr()patch2, add new logic indw_edma_get_phys_addr()to support new vendor.I understand your concern about making the review easier. However, given that we've been iterating on this patch series since September and are now at v9, I believe the current approach is justified. The function renames from
pci_bus_address()todw_edma_get_phys_addr()is directly tied to the non-LL mode functionality being added - it's needed because the same code now supports different IPs from different vendors.
Quoted 7 lines
Splitting this into a separate preparatory patch at this stage would further delay the review process. The change is kind of straightforward and the context is clear within the current patch. I request you to review this patch to avoid additional review cycles.
This also increases the work related to testing and maintaining multiple patches. I have commitment for delivery of this, and I can see adding one more series definitely add 3-4 months of review cycle from here. Please excuse me but this code has already
Thank you for your persevere.
Quoted 4 lines
been reviewed extensively by other reviewers and almost by you as well. You can check the detailed discussion wrt this function at the following link:
https://lore.kernel.org/all/SA1PR12MB8120341DFFD56D90EAD70EDE9514A@SA1PR12MB8120.namprd12.prod.outlook.com/
But still not got reviewed by tags. The recently, Manivannan Sadhasivam , Niklas Cassel and me active worked on this driver. You'd better to get their feedback. Bjorn as pci maintainer to provide generally feedback.
Quoted 66 lines
Quoted 44 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
ll_region->paddr += ll_block->off; ll_region->sz = ll_block->sz;...
Quoted 19 lines
Quoted 19 lines
Quoted 13 lines
Quoted 13 lines
Quoted 2 lines
+static void dw_hdma_v0_core_non_ll_start(struct
dw_edma_chunk*chunk)
drivers/dma/dw-edma/dw-edma-core.c
Quoted 7 lines
drivers/dma/dw-edma/dw-edma-core.c +7
-0+{ +struct dw_edma_chan *chan = chunk->chan; +struct dw_edma *dw = chan->dw; +struct dw_edma_burst *child; +u32 val; + +list_for_each_entry (child, &chunk->burst->list, list) {why need iterated list, it doesn't support ll. Need wait for irq to start next
one.
Quoted 4 lines
Quoted 2 lines
Frank
Yes, this is true. The format is kept similar to LL mode.
Quoted 7 lines
Quoted 3 lines
Just fill one.
list_for_each_entry()cause confuse.Frank
I see, we can use
list_first_entry_or_null()which is dependent on giving the type of pointer, compared to thislist_for_each_entry()looks neat and agnostic to the pointer type being used. Though, it can beexplored further.
Quoted 5 lines
Also, when the chunk is allocated, the comment clearly spells out how the allocation would be for the non LL mode so it is evident that each chunk would have single entry and with that understanding it is clear that loop will also be used in a similar manner, to retrieve a single entry. It is a similar use case as of "do {}while (0)" albeit needs a context to
understand it.
I don't think so.
list_for_each_entry()is miss leading to reader think it is not only to one item in burst list, and use polling method to to finish many burst transfer.Quoted 9 lines
list_for_each_entry() { ... readl_timeout() }Generally, EDMA is very quick, polling is much quicker than irq if data is small.
Frank
The polling is not required. The single burst will raise the interrupt and from the interrupt context another chunk will be scheduled. This cycle repeats till all the chunks with single burst are exhausted.
The following comment made in function
dw_edma_device_transfer()in the same patch makes it amply clear that only a single burst would be handled for the non-LL mode.(quoted diff) +5
-0+ /* + * For non-LL mode, only a single burst can be handled + * in a single chunk unlike LL mode where multiple bursts + * can be configured in a single chunk. + */
Quoted 5 lines
Looking at the way bursts are appended to chunks and chunks in
dw_edma_device_transfer()are scheduled for non-LL mode then it is clear what non-LL mode would handle in terms of bursts. I just kept the format to match it with the LL mode format otherwise there is no need of this comment and we can follow the syntax for a single entry alone. Please share your suggestion if these descriptions fail to provide the clear context and intent.
Avoid use list_for_each_entry() here to prevent miss-leading.
Frank
Quoted 92 lines
Quoted 92 lines
Quoted 92 lines
Quoted 92 lines
Quoted 54 lines
Quoted 54 lines
Quoted 54 lines
drivers/dma/dw-edma/dw-edma-core.c +50
-0+SET_CH_32 (dw, chan->dir, chan->id, ch_en, +HDMA_V0_CH_EN ); + +/* Source address */ +SET_CH_32 (dw, chan->dir, chan->id, sar.lsb, +lower_32_bits (child->sar)); +SET_CH_32 (dw, chan->dir, chan->id, sar.msb, +upper_32_bits (child->sar)); + +/* Destination address */ +SET_CH_32 (dw, chan->dir, chan->id, dar.lsb, +lower_32_bits (child->dar)); +SET_CH_32 (dw, chan->dir, chan->id, dar.msb, +upper_32_bits (child->dar)); + +/* Transfer size */ +SET_CH_32 (dw, chan->dir, chan->id, + transfer_size, + child->sz); + +/* Interrupt setup */ + val =GET_CH_32 (dw, chan->dir, chan->id, int_setup) | +HDMA_V0_STOP_INT_MASK | +HDMA_V0_ABORT_INT_MASK | +HDMA_V0_LOCAL_STOP_INT_EN | +HDMA_V0_LOCAL_ABORT_INT_EN ; + +if (!(dw->chip->flags &DW_EDMA_CHIP_LOCAL )) { + val |=HDMA_V0_REMOTE_STOP_INT_EN | +HDMA_V0_REMOTE_ABORT_INT_EN ; + } + +SET_CH_32 (dw, chan->dir, chan->id, int_setup, + val); + +/* Channel control setup */ + val =GET_CH_32 (dw, chan->dir, chan->id, control1); + val &= ~HDMA_V0_LINKLIST_EN ; +SET_CH_32 (dw, chan->dir, chan->id, control1, + val); + +SET_CH_32 (dw, chan->dir, chan->id, doorbell, +HDMA_V0_DOORBELL_START ); + } +} + +static void dw_hdma_v0_core_start (struct dw_edma_chunk +*chunk,bool +first) { +struct dw_edma_chan *chan = chunk->chan;Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
drivers/dma/dw-edma/dw-edma-core.c +6
-0+ +if (chan->non_ll) +dw_hdma_v0_core_non_ll_start (chunk); +else +dw_hdma_v0_core_ll_start (chunk, first); } + static void dw_hdma_v0_core_ch_config(struct dw_edma_chan*chan)
{
Quoted 29 lines
Quoted 29 lines
Quoted 29 lines
struct dw_edma *dw = chan->dw; diff --git
a/drivers/dma/dw-edma/dw-hdma-v0-regs.hb/drivers/dma/dw-edma/dw-hdma-v0-regs.h
index eab5fd7..7759ba9 100644drivers/dma/dw-edma/dw-hdma-v0-regs.h +1
-0@@ -12,6 +12,7 @@#include <linux/dmaengine.h> #define HDMA_V0_MAX_NR_CH 8 +#define HDMA_V0_CH_EN BIT(0)#define HDMA_V0_LOCAL_ABORT_INT_EN BIT(6)#define HDMA_V0_REMOTE_ABORT_INT_EN BIT(5)#define HDMA_V0_LOCAL_STOP_INT_EN BIT(4)(quoted diff) +0
-0
b/include/linux/dma/edma.hindex 3080747..78ce31b 100644include/linux/dma/edma.h +1
-1@@ -99,6 +99,7 @@ struct dw_edma_chip {enum dw_edma_map_format mf;struct dw_edma *dw; +bool non_ll; };/* Export to the platform drivers */ --1.8.3.1
RE: [PATCH v8 2/2] dmaengine: dw-edma: Add non-LL mode
[AMD Official Use Only - AMD Internal Distribution Only]
Quoted 8 lines
-----Original Message-----
From: Frank Li <[email protected]>
Sent: Tuesday, January 27, 2026 12:30 AM
To: Verma, Devendra <[email protected]>
Cc: [email protected]; [email protected]; [email protected]; [email protected]; [email protected]; linux- [email protected]; Simek, Michal <[email protected]>
Subject: Re: [PATCH v8 2/2] dmaengine: dw-edma: Add non-LL mode
--[ Snipped some headers to reduce the size of this mail ]--
Quoted 224 lines
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
AMD MDB IP supports Linked List (LL) mode as well as non-LL
mode.
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 7 lines
The current code does not have the mechanisms to enable the DMA transactions using the non-LL mode. The following two cases are added with this patch:
- For the AMD (Xilinx) only, when a valid physical base address of the device side DDR is not configured, then the IP can still be used in non-LL mode. For all the channels DMA
transactions willQuoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 3 lines
If DDR have not configured, where DATA send to in device side by non-LL mode.
The DDR base address in the VSEC capability is used for driving the DMA transfers when used in the LL mode. The DDR is configured and present all the time but the DMA PCIe driver uses this DDR base address (physical address) to configure the LLP
address.
Quoted 15 lines
Quoted 15 lines
Quoted 15 lines
Quoted 14 lines
Quoted 10 lines
In the scenario, where this DDR base address in VSEC capability is not configured then the current controller cannot be used as the default mode supported is LL mode only. In order to make the controller usable non-LL mode is being added which just needs SAR, DAR, XFERLEN and control register to initiate the transfer. So, the DDR is always present, but the DMA PCIe driver need to know the DDR base physical address to make the transfer. This is useful in scenarios where the memory
allocated for LL can be used for DMA transactions as well.
Do you means use DMA transfer LL's context?
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Yes, the device side memory reserved for the link list to store the descriptors, accessed by the host via
BAR_2in this driver code.Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
be using the non-LL mode only. This, the default non-LL mode, is not applicable for Synopsys IP with the current code addition.
- If the default mode is LL-mode, for both AMD (Xilinx) and
Synosys,
Quoted 27 lines
Quoted 27 lines
Quoted 11 lines
Quoted 11 lines
Quoted 11 lines
Quoted 11 lines
Quoted 11 lines
and if user wants to use non-LL mode then user can do so via configuring the
peripheral_configparam ofdma_slave_config.Signed-off-by Devendra K Verma <[email protected]>---
Changes in v8
Cosmetic change related to comment and code.Changes in v7
No changeQuoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Changes in v6
Gave definition to bits used for channel configuration. Removed the comment related to doorbell.Changes in v5
Variable name 'nollp' changed to 'non_ll'. In thedw_edma_device_config()WARN_ONreplaced with
dev_err().Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Comments follow the 80-column guideline.
Changes in v4
No changeChanges in v3
No changeQuoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Changes in v2
Reverted the function return type to u64 for
dw_edma_get_phys_addr().Changes in v1
Changed the function return type for
dw_edma_get_phys_addr().Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Corrected the typo raised in review.
--- drivers/dma/dw-edma/dw-edma-core.c | 42+++++++++++++++++++++---
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
drivers/dma/dw-edma/dw-edma-core.h | 1 + drivers/dma/dw-edma/dw-edma-pcie.c | 46Quoted 8 lines
Quoted 8 lines
++++++++++++++++++--
Quoted 7 lines
Quoted 7 lines
------
Quoted 6 lines
Quoted 6 lines
Quoted 3 lines
drivers/dma/dw-edma/dw-hdma-v0-core.c | 61 ++++++++++++++++++++++++++++++++++- drivers/dma/dw-edma/dw-hdma-v0-regs.h | 1 +
edma-v0-core.chave not update, if don't support, at least need return failure atdw_edma_device_config()when backend iseDMA.
Quoted 96 lines
Quoted 96 lines
Quoted 24 lines
Quoted 24 lines
Quoted 24 lines
Quoted 24 lines
Quoted 11 lines
include/linux/dma/edma.h | 1 + 6 files changed, 132 insertions(+), 20 deletions(-)drivers/dma/dw-edma/dw-edma-core.c +0
-0@@ -223,8 +223,32 @@ static intdw_edma_device_config(struct
dma_chan*dchan,Quoted 12 lines
struct
dma_slave_config*config) {
structdw_edma_chan*chan =dchan2dw_edma_chan(dchan);drivers/dma/dw-edma/dw-edma-core.c +8
-0+int non_ll =0 ; + +if (config->peripheral_config && + config->peripheral_size !=sizeof (int )) { +dev_err (dchan->device->dev, +"config param peripheral size mismatch\n" ); +return -EINVAL ; + }Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
drivers/dma/dw-edma/dw-edma-core.c
Quoted 5 lines
memcpy(&chan->config, config, sizeof(*config));drivers/dma/dw-edma/dw-edma-core.c +4
-0+ +/* +* When there is no valid LLP base address available +then the default
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
drivers/dma/dw-edma/dw-edma-core.c
Quoted 4 lines
drivers/dma/dw-edma/dw-edma-core.c +4
-0+* DMA ops will use the non-LL mode. +* +* Cases where LL mode is enabled and client wants +to use the non-LL
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
+ * mode then also client can do so via providing the
peripheral_configQuoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
drivers/dma/dw-edma/dw-edma-core.c
Quoted 8 lines
drivers/dma/dw-edma/dw-edma-core.c +8
-0+* param. +*/ +if (config->peripheral_config) + non_ll = *(int *)config->peripheral_config; + + chan->non_ll = false; + if (chan->dw->chip->non_ll || + (!chan->dw->chip->non_ll &&
non_ll))Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
drivers/dma/dw-edma/dw-edma-core.c +2
-0+ chan->non_ll = true; + chan->configured = true;Quoted 34 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 3 lines
return 0;drivers/dma/dw-edma/dw-edma-core.c +0
-0@@ -353,7 +377,7 @@ static voiddw_edma_device_issue_pending(struct
dma_chan*dchan)Quoted 1 line
struct
dw_edma_chan*chan = dchan2dw_edma_chan(xfer-dchan);
Quoted 28 lines
Quoted 28 lines
Quoted 21 lines
Quoted 8 lines
enum dma_transfer_direction dir = xfer->direction; struct scatterlist *sg = NULL;drivers/dma/dw-edma/dw-edma-core.c +1
-1-struct dw_edma_chunk *chunk; +struct dw_edma_chunk *chunk =NULL ;struct dw_edma_burst *burst;struct dw_edma_desc *desc; u64 src_addr, dst_addr; @@ -419,9 +443,11 @@ staticvoid dw_edma_device_issue_pending(struct
dma_chan*dchan)drivers/dma/dw-edma/dw-edma-core.c
Quoted 11 lines
if (unlikely(!desc)) goto err_alloc;drivers/dma/dw-edma/dw-edma-core.c +5
-3- chunk =dw_edma_alloc_chunk (desc); -if (unlikely (!chunk)) - goto err_alloc; +if (!chan->non_ll) { + chunk =dw_edma_alloc_chunk (desc); +if (unlikely (!chunk)) + goto err_alloc; + }Quoted 4 lines
non_llis the same asll_max= 1. (or 2, there are link back entry).If you set
ll_max= 1, needn't change this code.The
ll_maxis defined for the session till the driver is loaded in thekernel.
Quoted 10 lines
Quoted 7 lines
Quoted 4 lines
This code also enables the non-LL mode dynamically upon input from the DMA client. In this scenario, touching
ll_maxwould not be a good idea as thell_maxcontrols the LL entries for all the DMA channels not just for a single DMA transaction.You can use new variable, such as
ll_avail.In order to separate out the execution paths a new meaningful variable
"
non_ll"Quoted 8 lines
Quoted 8 lines
Quoted 3 lines
is used. The variable "
non_ll" alone is sufficient. Using another variable along side "non_ll" for the similar purpose may not have anyadded advantage.
ll_availcan help debug/fine tune how much impact preformance by adjust ll length. And it make code logic clean and consistent. alsoll_availcan help test corner case when ll item small. Normall case it ishard to reach
ll_max.Quoted 4 lines
Quoted 1 line
Thank you for your suggestion. The
ll_maxis max limit on the descriptors that can be accommodated on the device side DDR. Thell_availwill always be less than
ll_max.Quoted 3 lines
The optimization being referred can be tried without even having to declare the
ll_availcause the number of descriptors given can be controlled by the DMA client based on the length argument to thedmaengine_prep_* APIs.
I optimzied it to allow dynatmic appended dma descriptors.
https://lore.kernel.org/dmaengine/20260109-edma_dymatic-v1-0-
[email protected]/T/#tQuoted 5 lines
So, the use of dynamic
ll_availis not necessarily required. Without increasing thell_max,ll_availcannot be increased. In order to increasell_maxone may need to alter size and recompile this driver.However, the requirement of
ll_availdoes not help for the supporting thenon-LL mode.
Quoted 6 lines
For non-LL mode to use:
1) Either LL mode shall be not available, as it can happen for the Xilinx IP.
2) User provides the preference for non-LL mode.
For both above, the function calls are different which can be differentiated by using the "non_ll" flag. So, even if I try to accommodatell_avail, the call for LL or non-LL would be ambiguous as in
Quoted 8 lines
case of LL mode also we can have a single descriptor as similar to non-LL mode.
Quoted 2 lines
Please check the function
dw_hdma_v0_core_start()in this review where the decision is taken Based onnon_llflag.We can treat
ll_avail== 1 asno_llmode because needn't set extra LL in memory at all.
I analyzed the use of ll_avail but I think the use of this variable does not fit at this location in the code for the following reasons:
1. The use of a new variable breaks the continuity for non-LL mode. The variable name non_ll is being used for driving the non-LL mode not only in this file but also in the files relevant to HDMA. This flag gives the clear indication of LL vs non-LL mode. In the function dw_hdma_v0_core_start(), non_ll decided the mode to choose.
2. The use of "ll_avail" is ambiguous for both the modes. First, it is associated with LL mode only. It will be used for optimizing / testing the Controller performance based on the number of descriptors available on the Device DDR side which is for LL mode. So when it is being used for LL mode then it is obvious that it excludes any use for non-LL mode. In the API dw_edma_device_transfer(), the ll_avail will be used for creating the bursts. If ll_avail = 1 in the above API, then it is ambiguous whether it is creating the burst for LL or non-LL mode. In the above API, the non_ll is sufficient to have the LL mode and non-LL burst allocation related piece of code.
I think ll_avail, if used for trying out to optimize / debug the settings related to number of descriptors for LL mode then it should be part of the separate discussion / update not related to non-LL.
Quoted 49 lines
Quoted 17 lines
Quoted 17 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
...
Quoted 12 lines
Quoted 11 lines
Quoted 8 lines
Quoted 6 lines
Quoted 2 lines
+
+ll_block->bar);This change need do prepare patch, which only change
pci_bus_address()todw_edma_get_phys_addr().This is not clear.
why not. only trivial add helper patch, which help reviewer
Quoted 8 lines
Quoted 8 lines
Quoted 3 lines
I was not clear on the question you asked.
It does not look justified when a patch is raised alone just to replace thisfunction.
Quoted 4 lines
The function change is required cause the same code *can* support different IPs from different vendors. And, with this single change alone in the code the support for another IP is added. That's why it is easier to get the reason for the change in the function name and
syntax.
Quoted 7 lines
Quoted 7 lines
Add replace
pci_bus_address()withdw_edma_get_phys_addr()to make review easily and get ack for such replacement patches.two patches
patch1, just replace existpci_bus_address()withdw_edma_get_phys_addr()patch2, add new logic in
dw_edma_get_phys_addr()to support new vendor.Quoted 10 lines
Quoted 1 line
I understand your concern about making the review easier. However, given that we've been iterating on this patch series since September and are now at v9, I believe the current approach is justified. The function renames from
pci_bus_address()todw_edma_get_phys_addr()is directly tied to the non-LL mode functionality being added - it's needed because the same code now supports different IPs from different vendors.Quoted 3 lines
Splitting this into a separate preparatory patch at this stage would further delay the review process. The change is kind of straightforward and the context is clear within the current patch. I request
you to review this patch to avoid additional review cycles.
Quoted 1 line
Quoted 8 lines
Quoted 1 line
This also increases the work related to testing and maintaining multiple
patches.
Quoted 3 lines
I have commitment for delivery of this, and I can see adding one more series definitely add 3-4 months of review cycle from here. Please excuse me but this code has already
Thank you for your persevere.
Thank you for your support.
Quoted 4 lines
Quoted 2 lines
been reviewed extensively by other reviewers and almost by you as well. You can check the detailed discussion wrt this function at the following
link:
Quoted 1 line
Quoted 9 lines
https://lore.kernel.org/all/SA1PR12MB8120341DFFD56D90EAD70EDE9514A@
SA1Quoted 2 lines
PR12MB8120.namprd12.prod.outlook.com/
But still not got reviewed by tags. The recently, Manivannan Sadhasivam , Niklas Cassel and me active worked on this driver. You'd better to get their feedback. Bjorn as pci maintainer to provide generally feedback.
Hi Manivannan Sadhasivam, Vinod Koul and Bjorn Helgaas
Could you please provide your feedback on the patch?
You have reviewed these patches extensively on the previous versions of the same series.
Regards,
Devendra
Quoted 78 lines
Quoted 49 lines
Quoted 49 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
ll_region->paddr += ll_block->off; ll_region->sz = ll_block->sz;...
Quoted 21 lines
Quoted 21 lines
Quoted 4 lines
Quoted 4 lines
drivers/dma/dw-edma/dw-edma-core.c
Quoted 3 lines
drivers/dma/dw-edma/dw-edma-core.c +2
-0+static void dw_hdma_v0_core_non_ll_start (struct +dw_edma_chunk*chunk)
Quoted 11 lines
Quoted 11 lines
drivers/dma/dw-edma/dw-edma-core.c
Quoted 8 lines
drivers/dma/dw-edma/dw-edma-core.c +8
-0+{ +struct dw_edma_chan *chan = chunk->chan; +struct dw_edma *dw = chan->dw; +struct dw_edma_burst *child; +u32 val; + +list_for_each_entry (child, &chunk->burst->list, + list) {why need iterated list, it doesn't support ll. Need wait for irq to start next
one.
Quoted 4 lines
Quoted 2 lines
Frank
Yes, this is true. The format is kept similar to LL mode.
Quoted 8 lines
Quoted 3 lines
Just fill one.
list_for_each_entry()cause confuse.Frank
I see, we can use
list_first_entry_or_null()which is dependent on giving the type of pointer, compared to thislist_for_each_entry()looks neat and agnostic to the pointer type being used. Though, it can beexplored further.
Quoted 6 lines
Also, when the chunk is allocated, the comment clearly spells out how the allocation would be for the non LL mode so it is evident that each chunk would have single entry and with that understanding it is clear that loop will also be used in a similar manner, to retrieve a single entry. It is a similar use case as of "do {}while (0)" albeit needs a context to
understand it.
I don't think so.
list_for_each_entry()is miss leading to reader think it is not only to one item in burst list, and use polling method to to finish many burst transfer.Quoted 6 lines
Quoted 6 lines
list_for_each_entry() { ... readl_timeout() }Generally, EDMA is very quick, polling is much quicker than irq if data is
small.
Quoted 10 lines
Quoted 3 lines
Frank
The polling is not required. The single burst will raise the interrupt and from the interrupt context another chunk will be scheduled. This cycle repeats till all the chunks with single burst are exhausted.
The following comment made in function
dw_edma_device_transfer()in the same patch makes it amply clear that only a single burst would behandled for the non-LL mode.
Quoted 8 lines
(quoted diff) +5
-0+ /* + * For non-LL mode, only a single burst can be handled + * in a single chunk unlike LL mode where multiple bursts + * can be configured in a single chunk. + */Looking at the way bursts are appended to chunks and chunks in
dw_edma_device_transfer()are scheduled for non-LL mode then it is clearwhat non-LL mode would handle in terms of bursts.
Quoted 2 lines
I just kept the format to match it with the LL mode format otherwise there is no need of this comment and we can follow the syntax for a single
Quoted 8 lines
entry alone.
Quoted 1 line
Please share your suggestion if these descriptions fail to provide the clear
context and intent.
Avoid use
list_for_each_entry()here to prevent miss-leading.Frank
Sure, thanks, I will push this change in next version.
Quoted 92 lines
Quoted 92 lines
Quoted 92 lines
Quoted 92 lines
Quoted 92 lines
Quoted 54 lines
Quoted 54 lines
Quoted 54 lines
drivers/dma/dw-edma/dw-edma-core.c +50
-0+SET_CH_32 (dw, chan->dir, chan->id, ch_en, +HDMA_V0_CH_EN ); + +/* Source address */ +SET_CH_32 (dw, chan->dir, chan->id, sar.lsb, +lower_32_bits (child->sar)); +SET_CH_32 (dw, chan->dir, chan->id, sar.msb, +upper_32_bits (child->sar)); + +/* Destination address */ +SET_CH_32 (dw, chan->dir, chan->id, dar.lsb, +lower_32_bits (child->dar)); +SET_CH_32 (dw, chan->dir, chan->id, dar.msb, +upper_32_bits (child->dar)); + +/* Transfer size */ +SET_CH_32 (dw, chan->dir, chan->id, + transfer_size, + child->sz); + +/* Interrupt setup */ + val =GET_CH_32 (dw, chan->dir, chan->id, int_setup) | +HDMA_V0_STOP_INT_MASK | +HDMA_V0_ABORT_INT_MASK | +HDMA_V0_LOCAL_STOP_INT_EN | +HDMA_V0_LOCAL_ABORT_INT_EN ; + +if (!(dw->chip->flags &DW_EDMA_CHIP_LOCAL )) { + val |=HDMA_V0_REMOTE_STOP_INT_EN | +HDMA_V0_REMOTE_ABORT_INT_EN ; + } + +SET_CH_32 (dw, chan->dir, chan->id, + int_setup, val); + +/* Channel control setup */ + val =GET_CH_32 (dw, chan->dir, chan->id, control1); + val &= ~HDMA_V0_LINKLIST_EN ; +SET_CH_32 (dw, chan->dir, chan->id, control1, + val); + +SET_CH_32 (dw, chan->dir, chan->id, doorbell, +HDMA_V0_DOORBELL_START ); + } +} + +static void dw_hdma_v0_core_start (struct dw_edma_chunk +*chunk,bool +first) { +struct dw_edma_chan *chan = chunk->chan;Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
drivers/dma/dw-edma/dw-edma-core.c +6
-0+ +if (chan->non_ll) +dw_hdma_v0_core_non_ll_start (chunk); +else +dw_hdma_v0_core_ll_start (chunk, first); } + static void dw_hdma_v0_core_ch_config(struct dw_edma_chan*chan)
{
Quoted 29 lines
Quoted 29 lines
Quoted 29 lines
struct dw_edma *dw = chan->dw; diff --git
a/drivers/dma/dw-edma/dw-hdma-v0-regs.hb/drivers/dma/dw-edma/dw-hdma-v0-regs.h
index eab5fd7..7759ba9 100644drivers/dma/dw-edma/dw-hdma-v0-regs.h +1
-0@@ -12,6 +12,7 @@#include <linux/dmaengine.h> #define HDMA_V0_MAX_NR_CH 8 +#define HDMA_V0_CH_EN BIT(0)#define HDMA_V0_LOCAL_ABORT_INT_EN BIT(6)#define HDMA_V0_REMOTE_ABORT_INT_EN BIT(5)#define HDMA_V0_LOCAL_STOP_INT_EN BIT(4)(quoted diff) +0
-0
b/include/linux/dma/edma.hindex 3080747..78ce31b 100644include/linux/dma/edma.h +1
-1@@ -99,6 +99,7 @@ struct dw_edma_chip {enum dw_edma_map_format mf;struct dw_edma *dw; +bool non_ll; };/* Export to the platform drivers */ --1.8.3.1
Re: [PATCH v8 2/2] dmaengine: dw-edma: Add non-LL mode
Quoted 246 lines · Devendra
[AMD Official Use Only - AMD Internal Distribution Only]
Quoted 8 lines
-----Original Message-----
From: Frank Li <[email protected]>
Sent: Tuesday, January 27, 2026 12:30 AM
To: Verma, Devendra <[email protected]>
Cc: [email protected]; [email protected]; [email protected]; [email protected]; [email protected]; linux- [email protected]; Simek, Michal <[email protected]>
Subject: Re: [PATCH v8 2/2] dmaengine: dw-edma: Add non-LL mode--[ Snipped some headers to reduce the size of this mail ]--
Quoted 224 lines
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
AMD MDB IP supports Linked List (LL) mode as well as non-LL
mode.
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 7 lines
The current code does not have the mechanisms to enable the DMA transactions using the non-LL mode. The following two cases are added with this patch:
- For the AMD (Xilinx) only, when a valid physical base address of the device side DDR is not configured, then the IP can still be used in non-LL mode. For all the channels DMA
transactions willQuoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 3 lines
If DDR have not configured, where DATA send to in device side by non-LL mode.
The DDR base address in the VSEC capability is used for driving the DMA transfers when used in the LL mode. The DDR is configured and present all the time but the DMA PCIe driver uses this DDR base address (physical address) to configure the LLP
address.
Quoted 15 lines
Quoted 15 lines
Quoted 15 lines
Quoted 14 lines
Quoted 10 lines
In the scenario, where this DDR base address in VSEC capability is not configured then the current controller cannot be used as the default mode supported is LL mode only. In order to make the controller usable non-LL mode is being added which just needs SAR, DAR, XFERLEN and control register to initiate the transfer. So, the DDR is always present, but the DMA PCIe driver need to know the DDR base physical address to make the transfer. This is useful in scenarios where the memory
allocated for LL can be used for DMA transactions as well.
Do you means use DMA transfer LL's context?
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Yes, the device side memory reserved for the link list to store the descriptors, accessed by the host via
BAR_2in this driver code.Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
be using the non-LL mode only. This, the default non-LL mode, is not applicable for Synopsys IP with the current code addition.
- If the default mode is LL-mode, for both AMD (Xilinx) and
Synosys,
Quoted 27 lines
Quoted 27 lines
Quoted 11 lines
Quoted 11 lines
Quoted 11 lines
Quoted 11 lines
Quoted 11 lines
and if user wants to use non-LL mode then user can do so via configuring the
peripheral_configparam ofdma_slave_config.Signed-off-by Devendra K Verma <[email protected]>---
Changes in v8
Cosmetic change related to comment and code.Changes in v7
No changeQuoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Changes in v6
Gave definition to bits used for channel configuration. Removed the comment related to doorbell.Changes in v5
Variable name 'nollp' changed to 'non_ll'. In thedw_edma_device_config()WARN_ONreplaced with
dev_err().Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Comments follow the 80-column guideline.
Changes in v4
No changeChanges in v3
No changeQuoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Changes in v2
Reverted the function return type to u64 for
dw_edma_get_phys_addr().Changes in v1
Changed the function return type for
dw_edma_get_phys_addr().Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Corrected the typo raised in review.
--- drivers/dma/dw-edma/dw-edma-core.c | 42+++++++++++++++++++++---
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
drivers/dma/dw-edma/dw-edma-core.h | 1 + drivers/dma/dw-edma/dw-edma-pcie.c | 46Quoted 8 lines
Quoted 8 lines
++++++++++++++++++--
Quoted 7 lines
Quoted 7 lines
------
Quoted 6 lines
Quoted 6 lines
Quoted 3 lines
drivers/dma/dw-edma/dw-hdma-v0-core.c | 61 ++++++++++++++++++++++++++++++++++- drivers/dma/dw-edma/dw-hdma-v0-regs.h | 1 +
edma-v0-core.chave not update, if don't support, at least need return failure atdw_edma_device_config()when backend iseDMA.
Quoted 96 lines
Quoted 96 lines
Quoted 24 lines
Quoted 24 lines
Quoted 24 lines
Quoted 24 lines
Quoted 11 lines
include/linux/dma/edma.h | 1 + 6 files changed, 132 insertions(+), 20 deletions(-)drivers/dma/dw-edma/dw-edma-core.c +0
-0@@ -223,8 +223,32 @@ static intdw_edma_device_config(struct
dma_chan*dchan,Quoted 12 lines
struct
dma_slave_config*config) {
structdw_edma_chan*chan =dchan2dw_edma_chan(dchan);drivers/dma/dw-edma/dw-edma-core.c +8
-0+int non_ll =0 ; + +if (config->peripheral_config && + config->peripheral_size !=sizeof (int )) { +dev_err (dchan->device->dev, +"config param peripheral size mismatch\n" ); +return -EINVAL ; + }Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
drivers/dma/dw-edma/dw-edma-core.c
Quoted 5 lines
memcpy(&chan->config, config, sizeof(*config));drivers/dma/dw-edma/dw-edma-core.c +4
-0+ +/* +* When there is no valid LLP base address available +then the default
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
drivers/dma/dw-edma/dw-edma-core.c
Quoted 4 lines
drivers/dma/dw-edma/dw-edma-core.c +4
-0+* DMA ops will use the non-LL mode. +* +* Cases where LL mode is enabled and client wants +to use the non-LL
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
+ * mode then also client can do so via providing the
peripheral_configQuoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
drivers/dma/dw-edma/dw-edma-core.c
Quoted 8 lines
drivers/dma/dw-edma/dw-edma-core.c +8
-0+* param. +*/ +if (config->peripheral_config) + non_ll = *(int *)config->peripheral_config; + + chan->non_ll = false; + if (chan->dw->chip->non_ll || + (!chan->dw->chip->non_ll &&
non_ll))Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
drivers/dma/dw-edma/dw-edma-core.c +2
-0+ chan->non_ll = true; + chan->configured = true;Quoted 34 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 3 lines
return 0;drivers/dma/dw-edma/dw-edma-core.c +0
-0@@ -353,7 +377,7 @@ static voiddw_edma_device_issue_pending(struct
dma_chan*dchan)Quoted 1 line
struct
dw_edma_chan*chan = dchan2dw_edma_chan(xfer-dchan);
Quoted 28 lines
Quoted 28 lines
Quoted 21 lines
Quoted 8 lines
enum dma_transfer_direction dir = xfer->direction; struct scatterlist *sg = NULL;drivers/dma/dw-edma/dw-edma-core.c +1
-1-struct dw_edma_chunk *chunk; +struct dw_edma_chunk *chunk =NULL ;struct dw_edma_burst *burst;struct dw_edma_desc *desc; u64 src_addr, dst_addr; @@ -419,9 +443,11 @@ staticvoid dw_edma_device_issue_pending(struct
dma_chan*dchan)drivers/dma/dw-edma/dw-edma-core.c
Quoted 11 lines
if (unlikely(!desc)) goto err_alloc;drivers/dma/dw-edma/dw-edma-core.c +5
-3- chunk =dw_edma_alloc_chunk (desc); -if (unlikely (!chunk)) - goto err_alloc; +if (!chan->non_ll) { + chunk =dw_edma_alloc_chunk (desc); +if (unlikely (!chunk)) + goto err_alloc; + }Quoted 4 lines
non_llis the same asll_max= 1. (or 2, there are link back entry).If you set
ll_max= 1, needn't change this code.The
ll_maxis defined for the session till the driver is loaded in thekernel.
Quoted 10 lines
Quoted 7 lines
Quoted 4 lines
This code also enables the non-LL mode dynamically upon input from the DMA client. In this scenario, touching
ll_maxwould not be a good idea as thell_maxcontrols the LL entries for all the DMA channels not just for a single DMA transaction.You can use new variable, such as
ll_avail.In order to separate out the execution paths a new meaningful variable
"
non_ll"Quoted 8 lines
Quoted 8 lines
Quoted 3 lines
is used. The variable "
non_ll" alone is sufficient. Using another variable along side "non_ll" for the similar purpose may not have anyadded advantage.
ll_availcan help debug/fine tune how much impact preformance by adjust ll length. And it make code logic clean and consistent. alsoll_availcan help test corner case when ll item small. Normall case it ishard to reach
ll_max.Quoted 4 lines
Quoted 1 line
Thank you for your suggestion. The
ll_maxis max limit on the descriptors that can be accommodated on the device side DDR. Thell_availwill always be less than
ll_max.Quoted 3 lines
The optimization being referred can be tried without even having to declare the
ll_availcause the number of descriptors given can be controlled by the DMA client based on the length argument to thedmaengine_prep_* APIs.
I optimzied it to allow dynatmic appended dma descriptors.
https://lore.kernel.org/dmaengine/20260109-edma_dymatic-v1-0-
[email protected]/T/#tQuoted 5 lines
So, the use of dynamic
ll_availis not necessarily required. Without increasing thell_max,ll_availcannot be increased. In order to increasell_maxone may need to alter size and recompile this driver.However, the requirement of
ll_availdoes not help for the supporting thenon-LL mode.
Quoted 6 lines
For non-LL mode to use:
1) Either LL mode shall be not available, as it can happen for the Xilinx IP.
2) User provides the preference for non-LL mode.
For both above, the function calls are different which can be differentiated by using the "non_ll" flag. So, even if I try to accommodatell_avail, the call for LL or non-LL would be ambiguous as inQuoted 8 lines
case of LL mode also we can have a single descriptor as similar to non-LL mode.
Quoted 2 lines
Please check the function
dw_hdma_v0_core_start()in this review where the decision is taken Based onnon_llflag.We can treat
ll_avail== 1 asno_llmode because needn't set extra LL in memory at all.
Quoted 14 lines
I analyzed the use of
ll_availbut I think the use of this variable does not fit at this location in the code for the following reasons:
1. The use of a new variable breaks the continuity for non-LL mode. The variable namenon_llis being used for driving the non-LL mode not only in this file but also in the files relevant to HDMA. This flag gives the clear indication of LL vs non-LL mode. In the functiondw_hdma_v0_core_start(),non_lldecided the mode to choose.
2. The use of "ll_avail" is ambiguous for both the modes. First, it is associated with LL mode only. It will be used for optimizing / testing the Controller performance based on the number of descriptors available on the Device DDR side which is for LL mode. So when it is being used for LL mode then it is obvious that it excludes any use for non-LL mode. In the APIdw_edma_device_transfer(), thell_availwill be used for creating the bursts. Ifll_avail= 1 in the above API, then it is ambiguous whether it is creating the burst for LL or non-LL mode. In the above API, thenon_llis sufficient to have the LL mode and non-LL burst allocation related piece of code.
If really like non-ll, you'd better set ll_avail = 1 in prepare code. Normal case ll_avail should be ll_max. It will reduce if-else branch in prep dma burst code.
+ /*
+ * For non-LL mode, only a single burst can be handled
+ * in a single chunk unlike LL mode where multiple bursts
+ * can be configured in a single chunk.
+ */
It is actually wrong, current software should handle that. If there are multiple bursts, only HEAD of bursts trigger DMA, in irq handle, it will auto move to next burst. (only irq latency is bigger compared to LL, software's resule is the same).
The code logic is totally equal ll_max = 1, except write differece registers.
And anthor important is that,
in dw_edma_device_config() should return if backend is not HDMA.
Frank
Quoted 267 lines
I think
ll_avail, if used for trying out to optimize / debug the settings related to number of descriptors for LL mode then it should be part of the separate discussion / update not related to non-LL.Quoted 49 lines
Quoted 17 lines
Quoted 17 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
...
Quoted 12 lines
Quoted 11 lines
Quoted 8 lines
Quoted 6 lines
Quoted 2 lines
+
+ll_block->bar);This change need do prepare patch, which only change
pci_bus_address()todw_edma_get_phys_addr().This is not clear.
why not. only trivial add helper patch, which help reviewer
Quoted 8 lines
Quoted 8 lines
Quoted 3 lines
I was not clear on the question you asked.
It does not look justified when a patch is raised alone just to replace thisfunction.
Quoted 4 lines
The function change is required cause the same code *can* support different IPs from different vendors. And, with this single change alone in the code the support for another IP is added. That's why it is easier to get the reason for the change in the function name and
syntax.
Quoted 7 lines
Quoted 7 lines
Add replace
pci_bus_address()withdw_edma_get_phys_addr()to make review easily and get ack for such replacement patches.two patches
patch1, just replace existpci_bus_address()withdw_edma_get_phys_addr()patch2, add new logic in
dw_edma_get_phys_addr()to support new vendor.Quoted 10 lines
Quoted 1 line
I understand your concern about making the review easier. However, given that we've been iterating on this patch series since September and are now at v9, I believe the current approach is justified. The function renames from
pci_bus_address()todw_edma_get_phys_addr()is directly tied to the non-LL mode functionality being added - it's needed because the same code now supports different IPs from different vendors.Quoted 3 lines
Splitting this into a separate preparatory patch at this stage would further delay the review process. The change is kind of straightforward and the context is clear within the current patch. I request
you to review this patch to avoid additional review cycles.
Quoted 1 line
Quoted 8 lines
Quoted 1 line
This also increases the work related to testing and maintaining multiple
patches.
Quoted 3 lines
I have commitment for delivery of this, and I can see adding one more series definitely add 3-4 months of review cycle from here. Please excuse me but this code has already
Thank you for your persevere.
Thank you for your support.
Quoted 4 lines
Quoted 2 lines
been reviewed extensively by other reviewers and almost by you as well. You can check the detailed discussion wrt this function at the following
link:
Quoted 1 line
Quoted 9 lines
https://lore.kernel.org/all/SA1PR12MB8120341DFFD56D90EAD70EDE9514A@
SA1Quoted 2 lines
PR12MB8120.namprd12.prod.outlook.com/
But still not got reviewed by tags. The recently, Manivannan Sadhasivam , Niklas Cassel and me active worked on this driver. You'd better to get their feedback. Bjorn as pci maintainer to provide generally feedback.
Hi Manivannan Sadhasivam, Vinod Koul and Bjorn Helgaas
Could you please provide your feedback on the patch?
You have reviewed these patches extensively on the previous versions of the same series.Regards,
DevendraQuoted 78 lines
Quoted 49 lines
Quoted 49 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
ll_region->paddr += ll_block->off; ll_region->sz = ll_block->sz;...
Quoted 21 lines
Quoted 21 lines
Quoted 4 lines
Quoted 4 lines
drivers/dma/dw-edma/dw-edma-core.c
Quoted 3 lines
drivers/dma/dw-edma/dw-edma-core.c +2
-0+static void dw_hdma_v0_core_non_ll_start (struct +dw_edma_chunk*chunk)
Quoted 11 lines
Quoted 11 lines
drivers/dma/dw-edma/dw-edma-core.c
Quoted 8 lines
drivers/dma/dw-edma/dw-edma-core.c +8
-0+{ +struct dw_edma_chan *chan = chunk->chan; +struct dw_edma *dw = chan->dw; +struct dw_edma_burst *child; +u32 val; + +list_for_each_entry (child, &chunk->burst->list, + list) {why need iterated list, it doesn't support ll. Need wait for irq to start next
one.
Quoted 4 lines
Quoted 2 lines
Frank
Yes, this is true. The format is kept similar to LL mode.
Quoted 8 lines
Quoted 3 lines
Just fill one.
list_for_each_entry()cause confuse.Frank
I see, we can use
list_first_entry_or_null()which is dependent on giving the type of pointer, compared to thislist_for_each_entry()looks neat and agnostic to the pointer type being used. Though, it can beexplored further.
Quoted 6 lines
Also, when the chunk is allocated, the comment clearly spells out how the allocation would be for the non LL mode so it is evident that each chunk would have single entry and with that understanding it is clear that loop will also be used in a similar manner, to retrieve a single entry. It is a similar use case as of "do {}while (0)" albeit needs a context to
understand it.
I don't think so.
list_for_each_entry()is miss leading to reader think it is not only to one item in burst list, and use polling method to to finish many burst transfer.Quoted 6 lines
Quoted 6 lines
list_for_each_entry() { ... readl_timeout() }Generally, EDMA is very quick, polling is much quicker than irq if data is
small.
Quoted 10 lines
Quoted 3 lines
Frank
The polling is not required. The single burst will raise the interrupt and from the interrupt context another chunk will be scheduled. This cycle repeats till all the chunks with single burst are exhausted.
The following comment made in function
dw_edma_device_transfer()in the same patch makes it amply clear that only a single burst would behandled for the non-LL mode.
Quoted 8 lines
(quoted diff) +5
-0+ /* + * For non-LL mode, only a single burst can be handled + * in a single chunk unlike LL mode where multiple bursts + * can be configured in a single chunk. + */Looking at the way bursts are appended to chunks and chunks in
dw_edma_device_transfer()are scheduled for non-LL mode then it is clearwhat non-LL mode would handle in terms of bursts.
Quoted 2 lines
I just kept the format to match it with the LL mode format otherwise there is no need of this comment and we can follow the syntax for a single
Quoted 8 lines
entry alone.
Quoted 1 line
Please share your suggestion if these descriptions fail to provide the clear
context and intent.
Avoid use
list_for_each_entry()here to prevent miss-leading.Frank
Sure, thanks, I will push this change in next version.
Quoted 92 lines
Quoted 92 lines
Quoted 92 lines
Quoted 92 lines
Quoted 92 lines
Quoted 54 lines
Quoted 54 lines
Quoted 54 lines
drivers/dma/dw-edma/dw-edma-core.c +50
-0+SET_CH_32 (dw, chan->dir, chan->id, ch_en, +HDMA_V0_CH_EN ); + +/* Source address */ +SET_CH_32 (dw, chan->dir, chan->id, sar.lsb, +lower_32_bits (child->sar)); +SET_CH_32 (dw, chan->dir, chan->id, sar.msb, +upper_32_bits (child->sar)); + +/* Destination address */ +SET_CH_32 (dw, chan->dir, chan->id, dar.lsb, +lower_32_bits (child->dar)); +SET_CH_32 (dw, chan->dir, chan->id, dar.msb, +upper_32_bits (child->dar)); + +/* Transfer size */ +SET_CH_32 (dw, chan->dir, chan->id, + transfer_size, + child->sz); + +/* Interrupt setup */ + val =GET_CH_32 (dw, chan->dir, chan->id, int_setup) | +HDMA_V0_STOP_INT_MASK | +HDMA_V0_ABORT_INT_MASK | +HDMA_V0_LOCAL_STOP_INT_EN | +HDMA_V0_LOCAL_ABORT_INT_EN ; + +if (!(dw->chip->flags &DW_EDMA_CHIP_LOCAL )) { + val |=HDMA_V0_REMOTE_STOP_INT_EN | +HDMA_V0_REMOTE_ABORT_INT_EN ; + } + +SET_CH_32 (dw, chan->dir, chan->id, + int_setup, val); + +/* Channel control setup */ + val =GET_CH_32 (dw, chan->dir, chan->id, control1); + val &= ~HDMA_V0_LINKLIST_EN ; +SET_CH_32 (dw, chan->dir, chan->id, control1, + val); + +SET_CH_32 (dw, chan->dir, chan->id, doorbell, +HDMA_V0_DOORBELL_START ); + } +} + +static void dw_hdma_v0_core_start (struct dw_edma_chunk +*chunk,bool +first) { +struct dw_edma_chan *chan = chunk->chan;Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
drivers/dma/dw-edma/dw-edma-core.c +6
-0+ +if (chan->non_ll) +dw_hdma_v0_core_non_ll_start (chunk); +else +dw_hdma_v0_core_ll_start (chunk, first); } + static void dw_hdma_v0_core_ch_config(struct dw_edma_chan*chan)
{
Quoted 29 lines
Quoted 29 lines
Quoted 29 lines
struct dw_edma *dw = chan->dw; diff --git
a/drivers/dma/dw-edma/dw-hdma-v0-regs.hb/drivers/dma/dw-edma/dw-hdma-v0-regs.h
index eab5fd7..7759ba9 100644drivers/dma/dw-edma/dw-hdma-v0-regs.h +1
-0@@ -12,6 +12,7 @@#include <linux/dmaengine.h> #define HDMA_V0_MAX_NR_CH 8 +#define HDMA_V0_CH_EN BIT(0)#define HDMA_V0_LOCAL_ABORT_INT_EN BIT(6)#define HDMA_V0_REMOTE_ABORT_INT_EN BIT(5)#define HDMA_V0_LOCAL_STOP_INT_EN BIT(4)(quoted diff) +0
-0
b/include/linux/dma/edma.hindex 3080747..78ce31b 100644include/linux/dma/edma.h +1
-1@@ -99,6 +99,7 @@ struct dw_edma_chip {enum dw_edma_map_format mf;struct dw_edma *dw; +bool non_ll; };/* Export to the platform drivers */ --1.8.3.1
RE: [PATCH v8 2/2] dmaengine: dw-edma: Add non-LL mode
[AMD Official Use Only - AMD Internal Distribution Only]
Quoted 8 lines
-----Original Message-----
From: Frank Li <[email protected]>
Sent: Wednesday, January 28, 2026 8:38 PM
To: Verma, Devendra <[email protected]>
Cc: [email protected]; [email protected]; [email protected]; [email protected]; [email protected]; linux- [email protected]; Simek, Michal <[email protected]>
Subject: Re: [PATCH v8 2/2] dmaengine: dw-edma: Add non-LL mode
--[ Snipped some headers to reduce the size of this mail ]--
Quoted 276 lines
Quoted 7 lines
Quoted 7 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
AMD MDB IP supports Linked List (LL) mode as well as non-LL
mode.
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
The current code does not have the mechanisms to enable the DMA transactions using the non-LL mode. The following two cases are added with this patch:
- For the AMD (Xilinx) only, when a valid physical baseaddress of
Quoted 24 lines
Quoted 24 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 7 lines
Quoted 3 lines
the device side DDR is not configured, then the IP can still be used in non-LL mode. For all the channels DMA
transactions willIf DDR have not configured, where DATA send to in device side by non-LL mode.
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
The DDR base address in the VSEC capability is used for driving the DMA transfers when used in the LL mode. The DDR is configured and present all the time but the DMA PCIe driver uses this DDR base address (physical address) to configure the LLP
address.
Quoted 10 lines
Quoted 10 lines
Quoted 10 lines
Quoted 10 lines
Quoted 10 lines
In the scenario, where this DDR base address in VSEC capability is not configured then the current controller cannot be used as the default mode supported is LL mode only. In order to make the controller usable non-LL mode is being added which just needs SAR, DAR, XFERLEN and control register to initiate the transfer. So, the DDR is always present, but the DMA PCIe driver need to know the DDR base physical address to make the transfer. This is useful in scenarios where the memory
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 4 lines
allocated for LL can be used for DMA transactions as well.
Do you means use DMA transfer LL's context?
Yes, the device side memory reserved for the link list to store the descriptors, accessed by the host via
BAR_2in this drivercode.
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
be using the non-LL mode only. This, the default non-LL
mode,
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
is not applicable for Synopsys IP with the current code
addition.
Quoted 5 lines
Quoted 5 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
- If the default mode is LL-mode, for both AMD
(Xilinx) andSynosys,
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
and if user wants to use non-LL mode then user can do so
via
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
configuring the
peripheral_configparam of
dma_slave_config.Quoted 129 lines
Quoted 129 lines
Quoted 26 lines
Quoted 26 lines
Quoted 10 lines
Quoted 10 lines
Quoted 10 lines
Quoted 10 lines
Quoted 10 lines
Signed-off-by: Devendra K Verma
<[email protected]>
---
Changes in v8
Cosmetic change related to comment and code.Changes in v7
No changeQuoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Changes in v6
Gave definition to bits used for channel configuration. Removed the comment related to doorbell.Changes in v5
Variable name 'nollp' changed to 'non_ll'. In thedw_edma_device_config()WARN_ONreplaced with
dev_err().Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Comments follow the 80-column guideline.
Changes in v4
No changeChanges in v3
No changeQuoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Changes in v2
Reverted the function return type to u64 for
dw_edma_get_phys_addr().Changes in v1
Changed the function return type for
dw_edma_get_phys_addr().Quoted 7 lines
Quoted 7 lines
Quoted 6 lines
Quoted 6 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Corrected the typo raised in review.
--- drivers/dma/dw-edma/dw-edma-core.c | 42+++++++++++++++++++++---
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
drivers/dma/dw-edma/dw-edma-core.h | 1 + drivers/dma/dw-edma/dw-edma-pcie.c | 46++++++++++++++++++--
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
------
Quoted 7 lines
Quoted 7 lines
Quoted 3 lines
drivers/dma/dw-edma/dw-hdma-v0-core.c | 61 ++++++++++++++++++++++++++++++++++- drivers/dma/dw-edma/dw-hdma-v0-regs.h | 1 +
edma-v0-core.chave not update, if don't support, at least need return failure atdw_edma_device_config()when backend iseDMA.
Quoted 80 lines
Quoted 80 lines
Quoted 24 lines
Quoted 24 lines
Quoted 24 lines
Quoted 24 lines
Quoted 11 lines
include/linux/dma/edma.h | 1 + 6 files changed, 132 insertions(+), 20 deletions(-)drivers/dma/dw-edma/dw-edma-core.c +0
-0@@ -223,8 +223,32 @@ static intdw_edma_device_config(struct
dma_chan*dchan,Quoted 12 lines
struct
dma_slave_config*config) {
structdw_edma_chan*chan =dchan2dw_edma_chan(dchan);drivers/dma/dw-edma/dw-edma-core.c +8
-0+int non_ll =0 ; + +if (config->peripheral_config && + config->peripheral_size !=sizeof (int )) { +dev_err (dchan->device->dev, +"config param peripheral size mismatch\n" ); +return -EINVAL ; + }Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
drivers/dma/dw-edma/dw-edma-core.c
Quoted 5 lines
memcpy(&chan->config, config, sizeof(*config));drivers/dma/dw-edma/dw-edma-core.c +4
-0+ +/* +* When there is no valid LLP base address +available then the default
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
drivers/dma/dw-edma/dw-edma-core.c
Quoted 4 lines
drivers/dma/dw-edma/dw-edma-core.c +4
-0+* DMA ops will use the non-LL mode. +* +* Cases where LL mode is enabled and client +wants to use the non-LL
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
+ * mode then also client can do so via providing
+ the
peripheral_configQuoted 9 lines
Quoted 9 lines
Quoted 9 lines
Quoted 9 lines
drivers/dma/dw-edma/dw-edma-core.c
Quoted 9 lines
drivers/dma/dw-edma/dw-edma-core.c +9
-0+* param. +*/ +if (config->peripheral_config) + non_ll = *(int + *)config->peripheral_config; + + chan->non_ll = false; + if (chan->dw->chip->non_ll || + (!chan->dw->chip->non_ll &&
non_ll))Quoted 32 lines
Quoted 10 lines
Quoted 10 lines
Quoted 10 lines
Quoted 7 lines
drivers/dma/dw-edma/dw-edma-core.c +2
-0+ chan->non_ll = true; + chan->configured = true;return 0 ;@@ -353,7 +377,7 @@ static voiddw_edma_device_issue_pending(struct
dma_chan*dchan)Quoted 2 lines
struct
dw_edma_chan*chan =
dchan2dw_edma_chan(xfer-dchan);
Quoted 21 lines
Quoted 21 lines
Quoted 21 lines
Quoted 8 lines
enum dma_transfer_direction dir = xfer->direction; struct scatterlist *sg = NULL;drivers/dma/dw-edma/dw-edma-core.c +1
-1-struct dw_edma_chunk *chunk; +struct dw_edma_chunk *chunk =NULL ;struct dw_edma_burst *burst;struct dw_edma_desc *desc; u64 src_addr, dst_addr; @@ -419,9 +443,11 @@static void dw_edma_device_issue_pending(struct
dma_chan*dchan)Quoted 11 lines
if (unlikely(!desc)) goto err_alloc;drivers/dma/dw-edma/dw-edma-core.c +5
-3- chunk =dw_edma_alloc_chunk (desc); -if (unlikely (!chunk)) - goto err_alloc; +if (!chan->non_ll) { + chunk =dw_edma_alloc_chunk (desc); +if (unlikely (!chunk)) + goto err_alloc; + }Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
non_llis the same asll_max= 1. (or 2, there are link backentry).
Quoted 11 lines
Quoted 11 lines
Quoted 11 lines
Quoted 11 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 3 lines
If you set
ll_max= 1, needn't change this code.The
ll_maxis defined for the session till the driver is loaded in thekernel.
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
This code also enables the non-LL mode dynamically upon input from the DMA client. In this scenario, touching
ll_maxwould not be a good idea as thell_maxcontrols the LL entries for all the DMA channels not just for a single DMAtransaction.
Quoted 29 lines
Quoted 29 lines
Quoted 10 lines
Quoted 10 lines
Quoted 6 lines
Quoted 3 lines
You can use new variable, such as
ll_avail.In order to separate out the execution paths a new meaningful variable
"
non_ll"Quoted 3 lines
is used. The variable "
non_ll" alone is sufficient. Using another variable along side "non_ll" for the similar purpose may not have anyQuoted 6 lines
Quoted 6 lines
added advantage.
ll_availcan help debug/fine tune how much impact preformance by adjust ll length. And it make code logic clean and consistent. alsoll_availcan help test corner case when ll item small. Normall case it ishard to reach
ll_max.Quoted 5 lines
Quoted 1 line
Thank you for your suggestion. The
ll_maxis max limit on the descriptors that can be accommodated on the device side DDR. Thell_availwill always be less than
ll_max.Quoted 4 lines
The optimization being referred can be tried without even having to declare the
ll_availcause the number of descriptors given can be controlled by the DMA client based on the length argument to thedmaengine_prep_* APIs.
Quoted 8 lines
Quoted 8 lines
I optimzied it to allow dynatmic appended dma descriptors.
https://lore.kernel.org/dmaengine/20260109-edma_dymatic-v1-0-
[email protected]/T/#tQuoted 3 lines
So, the use of dynamic
ll_availis not necessarily required. Without increasing thell_max,ll_availcannot be increased. In order to increasell_maxone may need to alter size and recompile thisdriver.
Quoted 16 lines
Quoted 16 lines
Quoted 3 lines
However, the requirement of
ll_availdoes not help for the supporting thenon-LL mode.
Quoted 7 lines
For non-LL mode to use:
1) Either LL mode shall be not available, as it can happen for the Xilinx IP.
2) User provides the preference for non-LL mode.
For both above, the function calls are different which can be differentiated by using the "non_ll" flag. So, even if I try to accommodatell_avail, the call for LL or non-LL would be ambiguous as incase of LL mode also we can have a single descriptor as similar to non-LL mode.
Quoted 2 lines
Please check the function
dw_hdma_v0_core_start()in this review where the decision is taken Based onnon_llflag.Quoted 7 lines
Quoted 3 lines
We can treat
ll_avail== 1 asno_llmode because needn't set extra LL in memory at all.I analyzed the use of
ll_availbut I think the use of this variable does not fit at this location in the code for the following reasons:
1. The use of a new variable breaks the continuity for non-LL mode. Thevariable
Quoted 1 line
name
non_llis being used for driving the non-LL mode not only in this filebut also
Quoted 1 line
in the files relevant to HDMA. This flag gives the clear indication of LL vs
non-LL mode.
Quoted 1 line
In the function
dw_hdma_v0_core_start(),non_lldecided the mode tochoose.
Quoted 1 line
2. The use of "
ll_avail" is ambiguous for both the modes. First, it isassociated with LL mode only.
Quoted 1 line
It will be used for optimizing / testing the Controller performance based
on the
Quoted 1 line
number of descriptors available on the Device DDR side which is for LL
mode. So when
Quoted 1 line
it is being used for LL mode then it is obvious that it excludes any use for
non-LL mode.
Quoted 1 line
In the API
dw_edma_device_transfer(), thell_availwill be used forcreating the bursts.
Quoted 1 line
If
ll_avail= 1 in the above API, then it is ambiguous whether it is creating
Quoted 9 lines
the burst for
Quoted 1 line
LL or non-LL mode. In the above API, the
non_llis sufficient to have theLL mode
Quoted 1 line
and non-LL burst allocation related piece of code.
If really like non-ll, you'd better set
ll_avail= 1 in prepare code. Normal casell_availshould bell_max. It will reduce if-else branch in prep dma burst code.
I think we are not on the same page, and it is creating confusion.
If non_ll flag is being used to differentiate between the modes, then in this scenario the use of ll_avail does not fit any requirement related to differentiation of different modes. In the last response, I pointed out that ll_avail, if used, creates ambiguity rather than bringing clarity for both LL & non-LL mode. If non_ll flag is used and initialized properly then this is sufficient to drive the execution for non-LL mode.
In the function doing the preparation, there also no if-else clause is introduced rather the same "if" condition is extended to support the non-LL mode.
Could you elaborate what is the approach using ll_avail if I need to maintain the continuity of the non-LL context and use non-LL mode without any ambiguity anywhere, instead of using non_ll flag?
If possible, please give a code snippet. Depending upon the usability and issue it fixes, I will check its feasibility.
Quoted 6 lines
(quoted diff) +5
-0+ /* + * For non-LL mode, only a single burst can be handled + * in a single chunk unlike LL mode where multiple bursts + * can be configured in a single chunk. + */
Quoted 7 lines
It is actually wrong, current software should handle that. If there are multiple bursts, only HEAD of bursts trigger DMA, in irq handle, it will auto move to next burst. (only irq latency is bigger compared to LL, software's resule is the same).
The code logic is totally equal
ll_max= 1, except write differece registers.
Changing the ll_max dynamically for a single request is not feasible. As pointed out earlier it may require the logic to retain the initially configured value, during the probe, and then use the retained value depending on the use-case.
Could you elaborate the statement,
" The code logic is totally equal ll_max = 1, except write differece registers." ?
The irq_handler() for success case calls dw_edma_start_transfer() which schedules the chunks not bursts. The bursts associated with that chunk will get written to controller DDR area / scheduled (for non-LL) in the dw_hdma_v0_core_start(), for HDMA.
With this flow, for the non-LL mode each chunk needs to contain a single burst as controller can handle only one burst at a time in non-LL mode.
Quoted 4 lines
And anthor important is that,
in
dw_edma_device_config()should return if backend is not HDMA.
Thanks, this is a valid concern, will address in the upcoming version.
Quoted 287 lines
Frank
Quoted 59 lines
I think
ll_avail, if used for trying out to optimize / debug the settings related to number of descriptors for LL mode then it should be part of the separate discussion / update not related to non-LL.Quoted 54 lines
Quoted 20 lines
Quoted 20 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
...
Quoted 15 lines
Quoted 11 lines
Quoted 8 lines
Quoted 6 lines
Quoted 2 lines
+
+ll_block->bar);This change need do prepare patch, which only change
pci_bus_address()todw_edma_get_phys_addr().This is not clear.
why not. only trivial add helper patch, which help reviewer
I was not clear on the question you asked.
It does not look justified when a patch is raised alone just to replace thisQuoted 6 lines
Quoted 6 lines
function.
Quoted 5 lines
The function change is required cause the same code *can* support different IPs from different vendors. And, with this single change alone in the code the support for another IP is added. That's why it is easier to get the reason for the change in the function name and
syntax.
Quoted 7 lines
Quoted 7 lines
Add replace
pci_bus_address()withdw_edma_get_phys_addr()to make review easily and get ack for such replacement patches.two patches
patch1, just replace existpci_bus_address()withdw_edma_get_phys_addr()patch2, add new logic in
dw_edma_get_phys_addr()to support new vendor.Quoted 10 lines
Quoted 1 line
I understand your concern about making the review easier. However, given that we've been iterating on this patch series since September and are now at v9, I believe the current approach is justified. The function renames from
pci_bus_address()todw_edma_get_phys_addr()is directly tied to the non-LL mode functionality being added - it's needed because the same code now supports different IPs from different vendors.Quoted 4 lines
Splitting this into a separate preparatory patch at this stage would further delay the review process. The change is kind of straightforward and the context is clear within the current patch. I request
you to review this patch to avoid additional review cycles.
Quoted 3 lines
This also increases the work related to testing and maintaining multiple
patches.
Quoted 15 lines
Quoted 6 lines
Quoted 3 lines
I have commitment for delivery of this, and I can see adding one more series definitely add 3-4 months of review cycle from here. Please excuse me but this code has already
Thank you for your persevere.
Thank you for your support.
Quoted 6 lines
Quoted 3 lines
been reviewed extensively by other reviewers and almost by you as well. You can check the detailed discussion wrt this function at the following
link:
Quoted 1 line
https://lore.kernel.org/all/SA1PR12MB8120341DFFD56D90EAD70EDE9514A@
Quoted 7 lines
Quoted 7 lines
SA1
Quoted 2 lines
PR12MB8120.namprd12.prod.outlook.com/
But still not got reviewed by tags. The recently, Manivannan Sadhasivam , Niklas Cassel and me active worked on this driver. You'd better to get their feedback. Bjorn as pci maintainer to provide
generally feedback.
Quoted 5 lines
Quoted 1 line
Hi Manivannan Sadhasivam, Vinod Koul and Bjorn Helgaas Could you please provide your feedback on the patch?
You have reviewed these patches extensively on the previous versions ofthe same series.
Quoted 68 lines
Regards,
DevendraQuoted 64 lines
Quoted 49 lines
Quoted 49 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
ll_region->paddr += ll_block->off; ll_region->sz = ll_block->sz;...
Quoted 21 lines
Quoted 21 lines
Quoted 4 lines
Quoted 4 lines
drivers/dma/dw-edma/dw-edma-core.c
Quoted 3 lines
drivers/dma/dw-edma/dw-edma-core.c +2
-0+static void dw_hdma_v0_core_non_ll_start (struct +dw_edma_chunk*chunk)
Quoted 11 lines
Quoted 11 lines
drivers/dma/dw-edma/dw-edma-core.c
Quoted 8 lines
drivers/dma/dw-edma/dw-edma-core.c +8
-0+{ +struct dw_edma_chan *chan = chunk->chan; +struct dw_edma *dw = chan->dw; +struct dw_edma_burst *child; +u32 val; + +list_for_each_entry (child, &chunk->burst->list, + list) {why need iterated list, it doesn't support ll. Need wait for irq to start next
one.
Quoted 4 lines
Quoted 2 lines
Frank
Yes, this is true. The format is kept similar to LL mode.
Quoted 8 lines
Quoted 3 lines
Just fill one.
list_for_each_entry()cause confuse.Frank
I see, we can use
list_first_entry_or_null()which is dependent on giving the type of pointer, compared to thislist_for_each_entry()looks neat and agnostic to the pointer type being used. Though, it can beexplored further.
Quoted 6 lines
Also, when the chunk is allocated, the comment clearly spells out how the allocation would be for the non LL mode so it is evident that each chunk would have single entry and with that understanding it is clear that loop will also be used in a similar manner, to retrieve a single entry. It is a similar use case as of "do {}while (0)" albeit needs a context to
understand it.
I don't think so.
list_for_each_entry()is miss leading to reader think it is not only to one item in burst list, and use polling method to to finish many burst transfer.Quoted 7 lines
Quoted 7 lines
list_for_each_entry() { ... readl_timeout() }Generally, EDMA is very quick, polling is much quicker than irq if data is
small.
Quoted 7 lines
Quoted 3 lines
Frank
The polling is not required. The single burst will raise the interrupt and from the interrupt context another chunk will be scheduled. This cycle repeats till all the chunks with single burst are
exhausted.
Quoted 48 lines
Quoted 18 lines
Quoted 4 lines
The following comment made in function
dw_edma_device_transfer()in the same patch makes it amply clear that only a single burst would behandled for the non-LL mode.
Quoted 9 lines
(quoted diff) +5
-0+ /* + * For non-LL mode, only a single burst can be handled + * in a single chunk unlike LL mode where multiple bursts + * can be configured in a single chunk. + */Looking at the way bursts are appended to chunks and chunks in
dw_edma_device_transfer()are scheduled for non-LL mode then it is clearwhat non-LL mode would handle in terms of bursts.
Quoted 3 lines
I just kept the format to match it with the LL mode format otherwise there is no need of this comment and we can follow the syntax for a single
Quoted 9 lines
entry alone.
Quoted 2 lines
Please share your suggestion if these descriptions fail to provide the clear
context and intent.
Avoid use
list_for_each_entry()here to prevent miss-leading.Frank
Sure, thanks, I will push this change in next version.
Quoted 18 lines
Quoted 18 lines
Quoted 18 lines
Quoted 18 lines
Quoted 18 lines
Quoted 18 lines
Quoted 18 lines
Quoted 18 lines
drivers/dma/dw-edma/dw-edma-core.c +14
-0+SET_CH_32 (dw, chan->dir, chan->id, + ch_en,HDMA_V0_CH_EN ); + +/* Source address */ +SET_CH_32 (dw, chan->dir, chan->id, sar.lsb, +lower_32_bits (child->sar)); +SET_CH_32 (dw, chan->dir, chan->id, sar.msb, +upper_32_bits (child->sar)); + +/* Destination address */ +SET_CH_32 (dw, chan->dir, chan->id, dar.lsb, +lower_32_bits (child->dar)); +SET_CH_32 (dw, chan->dir, chan->id, dar.msb, +upper_32_bits (child->dar));Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
drivers/dma/dw-edma/dw-edma-core.c
Quoted 8 lines
drivers/dma/dw-edma/dw-edma-core.c +8
-0+ +/* Transfer size */ +SET_CH_32 (dw, chan->dir, chan->id, + transfer_size, + child->sz); + +/* Interrupt setup */ + val =GET_CH_32 (dw, chan->dir, chan->id, int_setup)|
Quoted 70 lines
Quoted 70 lines
Quoted 70 lines
Quoted 70 lines
Quoted 70 lines
Quoted 70 lines
Quoted 31 lines
Quoted 31 lines
Quoted 31 lines
drivers/dma/dw-edma/dw-edma-core.c +31
-0+HDMA_V0_STOP_INT_MASK | +HDMA_V0_ABORT_INT_MASK | +HDMA_V0_LOCAL_STOP_INT_EN | + +HDMA_V0_LOCAL_ABORT_INT_EN ; + +if (!(dw->chip->flags &DW_EDMA_CHIP_LOCAL )) { + val |=HDMA_V0_REMOTE_STOP_INT_EN | +HDMA_V0_REMOTE_ABORT_INT_EN ; + } + +SET_CH_32 (dw, chan->dir, chan->id, + int_setup, val); + +/* Channel control setup */ + val =GET_CH_32 (dw, chan->dir, chan->id, control1); + val &= ~HDMA_V0_LINKLIST_EN ; +SET_CH_32 (dw, chan->dir, chan->id, + control1, val); + +SET_CH_32 (dw, chan->dir, chan->id, doorbell, +HDMA_V0_DOORBELL_START ); + } +} + +static void dw_hdma_v0_core_start (struct +dw_edma_chunk *chunk,bool +first) { +struct dw_edma_chan *chan = chunk->chan; + +if (chan->non_ll)Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
drivers/dma/dw-edma/dw-edma-core.c +5
-0+dw_hdma_v0_core_non_ll_start (chunk); + else +dw_hdma_v0_core_ll_start (chunk ,first ); + } + static void dw_hdma_v0_core_ch_config(struct
dw_edma_chan
*chan){
Quoted 30 lines
Quoted 30 lines
Quoted 30 lines
struct dw_edma *dw = chan->dw; diff --git
a/drivers/dma/dw-edma/dw-hdma-v0-regs.hb/drivers/dma/dw-edma/dw-hdma-v0-regs.h
index eab5fd7..7759ba9 100644drivers/dma/dw-edma/dw-hdma-v0-regs.h +1
-0@@ -12,6 +12,7 @@#include <linux/dmaengine.h> #define HDMA_V0_MAX_NR_CH 8 +#define HDMA_V0_CH_EN BIT(0)#define HDMA_V0_LOCAL_ABORT_INT_EN BIT(6)#define HDMA_V0_REMOTE_ABORT_INT_EN BIT(5)#define HDMA_V0_LOCAL_STOP_INT_EN BIT(4)(quoted diff) +0
-0
b/include/linux/dma/edma.hindex 3080747..78ce31b
100644include/linux/dma/edma.h +1
-1@@ -99,6 +99,7 @@ struct dw_edma_chip {enum dw_edma_map_format mf;struct dw_edma *dw; +bool non_ll; };/* Export to the platform drivers */ --1.8.3.1
RE: [PATCH v8 2/2] dmaengine: dw-edma: Add non-LL mode
[AMD Official Use Only - AMD Internal Distribution Only]
Hi Frank
Any update on this review?
Regards,
Devendra
Quoted 682 lines
-----Original Message-----
From: Verma, Devendra <[email protected]>
Sent: Thursday, January 29, 2026 5:26 PM
To: Frank Li <[email protected]>
Cc: [email protected]; [email protected]; [email protected]; [email protected]; [email protected]; linux- [email protected]; Simek, Michal <[email protected]>; Verma, Devendra <[email protected]>
Subject: RE: [PATCH v8 2/2] dmaengine: dw-edma: Add non-LL mode[AMD Official Use Only - AMD Internal Distribution Only]
Quoted 8 lines
-----Original Message-----
From: Frank Li <[email protected]>
Sent: Wednesday, January 28, 2026 8:38 PM
To: Verma, Devendra <[email protected]>
Cc: [email protected]; [email protected]; [email protected]; [email protected]; [email protected]; linux- [email protected]; Simek, Michal <[email protected]>
Subject: Re: [PATCH v8 2/2] dmaengine: dw-edma: Add non-LL mode--[ Snipped some headers to reduce the size of this mail ]--
Quoted 10 lines
Quoted 8 lines
Quoted 8 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
AMD MDB IP supports Linked List (LL) mode as well as non-LL
mode.
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
The current code does not have the mechanisms to enable the DMA transactions using the non-LL mode. The following two cases are added with this patch:
- For the AMD (Xilinx) only, when a valid physical baseaddress of
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
the device side DDR is not configured, then the IP can still
be
Quoted 227 lines
Quoted 23 lines
Quoted 23 lines
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 6 lines
Quoted 2 lines
used in non-LL mode. For all the channels DMA
transactions willIf DDR have not configured, where DATA send to in device side by non-LL mode.
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
The DDR base address in the VSEC capability is used for driving the DMA transfers when used in the LL mode. The DDR is configured and present all the time but the DMA PCIe driver uses this DDR base address (physical address) to configure the LLP
address.
Quoted 10 lines
Quoted 10 lines
Quoted 10 lines
Quoted 10 lines
Quoted 10 lines
In the scenario, where this DDR base address in VSEC capability is not configured then the current controller cannot be used as the default mode supported is LL mode only. In order to make the controller usable non-LL mode is being added which just needs SAR, DAR, XFERLEN and control register to initiate the transfer. So, the DDR is always present, but the DMA PCIe driver need to know the DDR base physical address to make the transfer. This is useful in scenarios where the memory
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 4 lines
allocated for LL can be used for DMA transactions as well.
Do you means use DMA transfer LL's context?
Yes, the device side memory reserved for the link list to store the descriptors, accessed by the host via
BAR_2in this drivercode.
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
be using the non-LL mode only. This, the default
non-LLmode,
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
is not applicable for Synopsys IP with the current
codeaddition.
Quoted 6 lines
Quoted 6 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
- If the default mode is LL-mode, for both AMD
(Xilinx) andSynosys,
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
and if user wants to use non-LL mode then user can
do sovia
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
configuring the
peripheral_configparam of
dma_slave_config.Quoted 131 lines
Quoted 131 lines
Quoted 27 lines
Quoted 27 lines
Quoted 10 lines
Quoted 10 lines
Quoted 10 lines
Quoted 10 lines
Quoted 10 lines
Signed-off-by: Devendra K Verma
<[email protected]>
---
Changes in v8
Cosmetic change related to comment and code.Changes in v7
No changeQuoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Changes in v6
Gave definition to bits used for channel configuration. Removed the comment related to doorbell.Changes in v5
Variable name 'nollp' changed to 'non_ll'.
In thedw_edma_device_config()WARN_ONreplaced
with
dev_err().Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Comments follow the 80-column guideline.
Changes in v4
No changeChanges in v3
No changeQuoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Changes in v2
Reverted the function return type to u64 for
dw_edma_get_phys_addr().Changes in v1
Changed the function return type for
dw_edma_get_phys_addr().Quoted 7 lines
Quoted 7 lines
Quoted 6 lines
Quoted 6 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Corrected the typo raised in review.
--- drivers/dma/dw-edma/dw-edma-core.c | 42+++++++++++++++++++++---
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
drivers/dma/dw-edma/dw-edma-core.h | 1 + drivers/dma/dw-edma/dw-edma-pcie.c | 46++++++++++++++++++--
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
------
Quoted 7 lines
Quoted 7 lines
Quoted 3 lines
drivers/dma/dw-edma/dw-hdma-v0-core.c | 61 ++++++++++++++++++++++++++++++++++- drivers/dma/dw-edma/dw-hdma-v0-regs.h | 1 +
edma-v0-core.chave not update, if don't support, at least need return failure atdw_edma_device_config()when backend iseDMA.
Quoted 81 lines
Quoted 81 lines
Quoted 24 lines
Quoted 24 lines
Quoted 24 lines
Quoted 24 lines
Quoted 11 lines
include/linux/dma/edma.h | 1 + 6 files changed, 132 insertions(+), 20 deletions(-)drivers/dma/dw-edma/dw-edma-core.c +0
-0@@ -223,8 +223,32 @@ static intdw_edma_device_config(struct
dma_chan*dchan,Quoted 12 lines
struct
dma_slave_config*config) {
structdw_edma_chan*chan =dchan2dw_edma_chan(dchan);drivers/dma/dw-edma/dw-edma-core.c +8
-0+int non_ll =0 ; + +if (config->peripheral_config && + config->peripheral_size !=sizeof (int )) { +dev_err (dchan->device->dev, +"config param peripheral size mismatch\n" ); +return -EINVAL ; + }Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
drivers/dma/dw-edma/dw-edma-core.c
Quoted 6 lines
memcpy(&chan->config, config,
sizeof(*config));drivers/dma/dw-edma/dw-edma-core.c +4
-0+ +/* +* When there is no valid LLP base address +available then the default
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
drivers/dma/dw-edma/dw-edma-core.c
Quoted 4 lines
drivers/dma/dw-edma/dw-edma-core.c +4
-0+* DMA ops will use the non-LL mode. +* +* Cases where LL mode is enabled and client +wants to use the non-LL
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
+ * mode then also client can do so via
+ providing the
peripheral_configQuoted 9 lines
Quoted 9 lines
Quoted 9 lines
Quoted 9 lines
drivers/dma/dw-edma/dw-edma-core.c
Quoted 9 lines
drivers/dma/dw-edma/dw-edma-core.c +9
-0+* param. +*/ +if (config->peripheral_config) + non_ll = *(int + *)config->peripheral_config; + + chan->non_ll = false; + if (chan->dw->chip->non_ll || + (!chan->dw->chip->non_ll &&
non_ll))Quoted 32 lines
Quoted 10 lines
Quoted 10 lines
Quoted 10 lines
Quoted 7 lines
drivers/dma/dw-edma/dw-edma-core.c +2
-0+ chan->non_ll = true; + chan->configured = true;return 0 ;@@ -353,7 +377,7 @@ static voiddw_edma_device_issue_pending(struct
dma_chan*dchan)Quoted 2 lines
struct
dw_edma_chan*chan =
dchan2dw_edma_chan(xfer-dchan);
Quoted 21 lines
Quoted 21 lines
Quoted 21 lines
Quoted 8 lines
enum dma_transfer_direction dir = xfer->direction; struct scatterlist *sg = NULL;drivers/dma/dw-edma/dw-edma-core.c +1
-1-struct dw_edma_chunk *chunk; +struct dw_edma_chunk *chunk =NULL ;struct dw_edma_burst *burst;struct dw_edma_desc *desc; u64 src_addr, dst_addr; @@ -419,9 +443,11 @@static void dw_edma_device_issue_pending(struct
dma_chan*dchan)Quoted 11 lines
if (unlikely(!desc)) goto err_alloc;drivers/dma/dw-edma/dw-edma-core.c +5
-3- chunk =dw_edma_alloc_chunk (desc); -if (unlikely (!chunk)) - goto err_alloc; +if (!chan->non_ll) { + chunk =dw_edma_alloc_chunk (desc); +if (unlikely (!chunk)) + goto err_alloc; + }Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
non_llis the same asll_max= 1. (or 2, there are link backentry).
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 3 lines
If you set
ll_max= 1, needn't change this code.Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
The
ll_maxis defined for the session till the driver is loaded in thekernel.
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
This code also enables the non-LL mode dynamically upon input from the DMA client. In this scenario, touching
ll_maxwould not be a good idea as thell_maxcontrols the LL entries for all the DMA channels not just for a single DMAtransaction.
Quoted 31 lines
Quoted 31 lines
Quoted 10 lines
Quoted 10 lines
Quoted 6 lines
Quoted 3 lines
You can use new variable, such as
ll_avail.In order to separate out the execution paths a new meaningful variable
"
non_ll"Quoted 3 lines
is used. The variable "
non_ll" alone is sufficient. Using another variable along side "non_ll" for the similar purpose may not have anyQuoted 6 lines
Quoted 6 lines
added advantage.
ll_availcan help debug/fine tune how much impact preformance by adjust ll length. And it make code logic clean and consistent. alsoll_availcan help test corner case when ll item small. Normall case it ishard to reach
ll_max.Quoted 5 lines
Quoted 1 line
Thank you for your suggestion. The
ll_maxis max limit on the descriptors that can be accommodated on the device side DDR. Thell_availwill always be less than
ll_max.Quoted 4 lines
The optimization being referred can be tried without even having to declare the
ll_availcause the number of descriptors given can be controlled by the DMA client based on the length argument to thedmaengine_prep_* APIs.
I optimzied it to allow dynatmic appended dma descriptors.
Quoted 14 lines
Quoted 7 lines
Quoted 7 lines
https://lore.kernel.org/dmaengine/20260109-edma_dymatic-v1-0-
[email protected]/T/#tQuoted 4 lines
So, the use of dynamic
ll_availis not necessarily required. Without increasing thell_max,ll_availcannot be increased. In order to increasell_maxone may need to alter size and recompile thisdriver.
Quoted 6 lines
Quoted 6 lines
Quoted 3 lines
However, the requirement of
ll_availdoes not help for the supporting thenon-LL mode.
Quoted 2 lines
For non-LL mode to use:
1) Either LL mode shall be not available, as it can happen for the XilinxIP.
Quoted 46 lines
Quoted 10 lines
Quoted 10 lines
Quoted 5 lines
2) User provides the preference for non-LL mode.
For both above, the function calls are different which can be differentiated by using the "non_ll" flag. So, even if I try to accommodatell_avail, the call for LL or non-LL would be ambiguous as incase of LL mode also we can have a single descriptor as similar to non-LL mode.
Quoted 2 lines
Please check the function
dw_hdma_v0_core_start()in this review where the decision is taken Based onnon_llflag.Quoted 8 lines
Quoted 3 lines
We can treat
ll_avail== 1 asno_llmode because needn't set extra LL in memory at all.I analyzed the use of
ll_availbut I think the use of this variable does not fit at this location in the code for the following reasons:
1. The use of a new variable breaks the continuity for non-LL mode. Thevariable
Quoted 2 lines
name
non_llis being used for driving the non-LL mode not only
in this filebut also
Quoted 2 lines
in the files relevant to HDMA. This flag gives the clear
indication of LL vsnon-LL mode.
Quoted 2 lines
In the function
dw_hdma_v0_core_start(),non_lldecided the mode
tochoose.
Quoted 2 lines
2. The use of "
ll_avail" is ambiguous for both the modes. First, it isassociated with LL mode only.
Quoted 2 lines
It will be used for optimizing / testing the Controller
performance basedon the
Quoted 2 lines
number of descriptors available on the Device DDR side which is
for LLmode. So when
Quoted 2 lines
it is being used for LL mode then it is obvious that it excludes
any use fornon-LL mode.
Quoted 2 lines
In the API
dw_edma_device_transfer(), thell_availwill be used
forcreating the bursts.
Quoted 2 lines
If
ll_avail= 1 in the above API, then it is ambiguous whether
it is creatingthe burst for
Quoted 9 lines
Quoted 2 lines
LL or non-LL mode. In the above API, the
non_llis sufficient
to have theLL mode
Quoted 1 line
and non-LL burst allocation related piece of code.
If really like non-ll, you'd better set
ll_avail= 1 in prepare code. Normal casell_availshould bell_max. It will reduce if-else branch in prep dma burst code.I think we are not on the same page, and it is creating confusion. If
non_llflag is being used to differentiate between the modes, then in this scenario the use ofll_availdoes not fit any requirement related to differentiation of different modes. In the last response, I pointed out thatll_avail, if used, creates ambiguity rather than bringing clarity for both LL & non-LL mode. Ifnon_llflag is used and initialized properly then this is sufficient to drive the execution for non-LL mode.In the function doing the preparation, there also no if-else clause is introduced rather the same "if" condition is extended to support the non-LL mode.
Could you elaborate what is the approach using
ll_availif I need to maintain the continuity of the non-LL context and use non-LL mode without any ambiguity anywhere, instead of usingnon_llflag?
If possible, please give a code snippet. Depending upon the usability and issue it fixes, I will check its feasibility.Quoted 6 lines
(quoted diff) +5
-0+ /* + * For non-LL mode, only a single burst can be handled + * in a single chunk unlike LL mode where multiple bursts + * can be configured in a single chunk. + */Quoted 7 lines
It is actually wrong, current software should handle that. If there are multiple bursts, only HEAD of bursts trigger DMA, in irq handle, it will auto move to next burst. (only irq latency is bigger compared to LL, software's resule is the same).
The code logic is totally equal
ll_max= 1, except write differece registers.Changing the
ll_maxdynamically for a single request is not feasible. As pointed out earlier it may require the logic to retain the initially configured value, during the probe, and then use the retained value depending on the use-case.
Could you elaborate the statement,
" The code logic is totally equalll_max= 1, except write differece registers." ?The
irq_handler()for success case callsdw_edma_start_transfer()which schedules the chunks not bursts. The bursts associated with that chunk will get written to controller DDR area / scheduled (for non-LL) in thedw_hdma_v0_core_start(), for HDMA.
With this flow, for the non-LL mode each chunk needs to contain a single burst as controller can handle only one burst at a time in non-LL mode.Quoted 4 lines
And anthor important is that,
in
dw_edma_device_config()should return if backend is not HDMA.Thanks, this is a valid concern, will address in the upcoming version.
Quoted 78 lines
Frank
Quoted 75 lines
I think
ll_avail, if used for trying out to optimize / debug the settings related to number of descriptors for LL mode then it should be part of the separate discussion / update not related to non-LL.Quoted 52 lines
Quoted 21 lines
Quoted 21 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
...
Quoted 16 lines
Quoted 12 lines
Quoted 8 lines
Quoted 6 lines
Quoted 2 lines
+
+ll_block->bar);This change need do prepare patch, which only change
pci_bus_address()todw_edma_get_phys_addr().This is not clear.
why not. only trivial add helper patch, which help reviewer
I was not clear on the question you asked.
It does not look justified when a patch is raised alone just to replace thisQuoted 6 lines
Quoted 6 lines
function.
Quoted 5 lines
The function change is required cause the same code *can* support different IPs from different vendors. And, with this single change alone in the code the support for another IP is added. That's why it is easier to get the reason for the change in the function name and
syntax.
Quoted 7 lines
Quoted 7 lines
Add replace
pci_bus_address()withdw_edma_get_phys_addr()to make review easily and get ack for such replacement patches.two patches
patch1, just replace existpci_bus_address()withdw_edma_get_phys_addr()patch2, add new logic in
dw_edma_get_phys_addr()to support new vendor.Quoted 10 lines
Quoted 1 line
I understand your concern about making the review easier. However, given that we've been iterating on this patch series since September and are now at v9, I believe the current approach is justified. The function renames from
pci_bus_address()todw_edma_get_phys_addr()is directly tied to the non-LL mode functionality being added - it's needed because the same code now supports different IPs from different vendors.Quoted 4 lines
Splitting this into a separate preparatory patch at this stage would further delay the review process. The change is kind of straightforward and the context is clear within the current patch. I request
you to review this patch to avoid additional review cycles.
Quoted 1 line
Quoted 9 lines
Quoted 2 lines
This also increases the work related to testing and maintaining multiple
patches.
Quoted 3 lines
I have commitment for delivery of this, and I can see adding one more series definitely add 3-4 months of review cycle from here. Please excuse me but this code has already
Thank you for your persevere.
Thank you for your support.
Quoted 6 lines
Quoted 3 lines
been reviewed extensively by other reviewers and almost by you as well. You can check the detailed discussion wrt this function at the following
link:
Quoted 1 line
https://lore.kernel.org/all/SA1PR12MB8120341DFFD56D90EAD70EDE9514A@
Quoted 217 lines
Quoted 8 lines
Quoted 8 lines
SA1
Quoted 2 lines
PR12MB8120.namprd12.prod.outlook.com/
But still not got reviewed by tags. The recently, Manivannan Sadhasivam , Niklas Cassel and me active worked on this driver. You'd better to get their feedback. Bjorn as pci maintainer to provide
generally feedback.
Quoted 6 lines
Quoted 1 line
Hi Manivannan Sadhasivam, Vinod Koul and Bjorn Helgaas Could you please provide your feedback on the patch?
You have reviewed these patches extensively on the previous versions ofthe same series.
Quoted 71 lines
Regards,
DevendraQuoted 67 lines
Quoted 51 lines
Quoted 51 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
ll_region->paddr += ll_block->off; ll_region->sz = ll_block->sz;...
Quoted 22 lines
Quoted 22 lines
Quoted 4 lines
Quoted 4 lines
drivers/dma/dw-edma/dw-edma-core.c
Quoted 3 lines
drivers/dma/dw-edma/dw-edma-core.c +2
-0+static void dw_hdma_v0_core_non_ll_start (struct +dw_edma_chunk*chunk)
Quoted 12 lines
Quoted 4 lines
Quoted 4 lines
drivers/dma/dw-edma/dw-edma-core.c +4
-0+{ +struct dw_edma_chan *chan = chunk->chan; +struct dw_edma *dw = chan->dw; +struct dw_edma_burst *child;Quoted 8 lines
drivers/dma/dw-edma/dw-edma-core.c
Quoted 5 lines
drivers/dma/dw-edma/dw-edma-core.c +5
-0+u32 val; + +list_for_each_entry (child, + &chunk->burst->list, + list) {why need iterated list, it doesn't support ll. Need wait for irq to start next
one.
Quoted 4 lines
Quoted 2 lines
Frank
Yes, this is true. The format is kept similar to LL mode.
Quoted 8 lines
Quoted 3 lines
Just fill one.
list_for_each_entry()cause confuse.Frank
I see, we can use
list_first_entry_or_null()which is dependent on giving the type of pointer, compared to thislist_for_each_entry()looks neat and agnostic to the pointer type being used. Though, it can beexplored further.
Quoted 7 lines
Also, when the chunk is allocated, the comment clearly spells out how the allocation would be for the non LL mode so it is evident that each chunk would have single entry and with that understanding it is clear that loop will also be used in a similar manner, to retrieve a single entry. It is a similar use case as of "do {}while (0)" albeit needs a context to
understand it.
I don't think so.
list_for_each_entry()is miss leading to reader think it is not only to one item in burst list, and use polling method to to finish many burst transfer.Quoted 7 lines
Quoted 7 lines
list_for_each_entry() { ... readl_timeout() }Generally, EDMA is very quick, polling is much quicker than irq if data is
small.
Quoted 8 lines
Quoted 3 lines
Frank
The polling is not required. The single burst will raise the interrupt and from the interrupt context another chunk will be scheduled. This cycle repeats till all the chunks with single burst are
exhausted.
Quoted 49 lines
Quoted 18 lines
Quoted 4 lines
The following comment made in function
dw_edma_device_transfer()in the same patch makes it amply clear that only a single burst would behandled for the non-LL mode.
Quoted 9 lines
(quoted diff) +5
-0+ /* + * For non-LL mode, only a single burst can be handled + * in a single chunk unlike LL mode where multiple bursts + * can be configured in a single chunk. + */Looking at the way bursts are appended to chunks and chunks in
dw_edma_device_transfer()are scheduled for non-LL mode then it is clearwhat non-LL mode would handle in terms of bursts.
Quoted 3 lines
I just kept the format to match it with the LL mode format otherwise there is no need of this comment and we can follow the syntax for a single
Quoted 9 lines
entry alone.
Quoted 2 lines
Please share your suggestion if these descriptions fail to provide the clear
context and intent.
Avoid use
list_for_each_entry()here to prevent miss-leading.Frank
Sure, thanks, I will push this change in next version.
Quoted 19 lines
Quoted 19 lines
Quoted 19 lines
Quoted 19 lines
Quoted 19 lines
Quoted 19 lines
Quoted 19 lines
Quoted 19 lines
drivers/dma/dw-edma/dw-edma-core.c +15
-0+SET_CH_32 (dw, chan->dir, chan->id, + ch_en,HDMA_V0_CH_EN ); + +/* Source address */ +SET_CH_32 (dw, chan->dir, chan->id, sar.lsb, +lower_32_bits (child->sar)); +SET_CH_32 (dw, chan->dir, chan->id, sar.msb, +upper_32_bits (child->sar)); + +/* Destination address */ +SET_CH_32 (dw, chan->dir, chan->id, dar.lsb, +lower_32_bits (child->dar)); +SET_CH_32 (dw, chan->dir, chan->id, dar.msb, +upper_32_bits (child->dar)); +Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
drivers/dma/dw-edma/dw-edma-core.c
Quoted 8 lines
drivers/dma/dw-edma/dw-edma-core.c +8
-0+/* Transfer size */ +SET_CH_32 (dw, chan->dir, chan->id, + transfer_size, + child->sz); + +/* Interrupt setup */ + val =GET_CH_32 (dw, chan->dir, + chan->id, int_setup)|
Quoted 71 lines
Quoted 71 lines
Quoted 71 lines
Quoted 71 lines
Quoted 71 lines
Quoted 71 lines
Quoted 32 lines
Quoted 32 lines
Quoted 32 lines
drivers/dma/dw-edma/dw-edma-core.c +32
-0+HDMA_V0_STOP_INT_MASK | +HDMA_V0_ABORT_INT_MASK | + +HDMA_V0_LOCAL_STOP_INT_EN | + +HDMA_V0_LOCAL_ABORT_INT_EN ; + +if (!(dw->chip->flags &DW_EDMA_CHIP_LOCAL )) { + val |=HDMA_V0_REMOTE_STOP_INT_EN | +HDMA_V0_REMOTE_ABORT_INT_EN ; + } + +SET_CH_32 (dw, chan->dir, chan->id, + int_setup, val); + +/* Channel control setup */ + val =GET_CH_32 (dw, chan->dir, chan->id, control1); + val &= ~HDMA_V0_LINKLIST_EN ; +SET_CH_32 (dw, chan->dir, chan->id, + control1, val); + +SET_CH_32 (dw, chan->dir, chan->id, doorbell, +HDMA_V0_DOORBELL_START ); + } +} + +static void dw_hdma_v0_core_start (struct +dw_edma_chunk *chunk,bool +first) { +struct dw_edma_chan *chan = chunk->chan; + +if (chan->non_ll)Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
drivers/dma/dw-edma/dw-edma-core.c +5
-0+dw_hdma_v0_core_non_ll_start (chunk); + else +dw_hdma_v0_core_ll_start (chunk , +first ); } + static void dw_hdma_v0_core_ch_config(struct
dw_edma_chan
*chan){
Quoted 30 lines
Quoted 30 lines
Quoted 30 lines
struct dw_edma *dw = chan->dw; diff --git
a/drivers/dma/dw-edma/dw-hdma-v0-regs.hb/drivers/dma/dw-edma/dw-hdma-v0-regs.h
index eab5fd7..7759ba9 100644drivers/dma/dw-edma/dw-hdma-v0-regs.h +1
-0@@ -12,6 +12,7 @@#include <linux/dmaengine.h> #define HDMA_V0_MAX_NR_CH 8 +#define HDMA_V0_CH_EN BIT(0)#define HDMA_V0_LOCAL_ABORT_INT_EN BIT(6)#define HDMA_V0_REMOTE_ABORT_INT_EN BIT(5)#define HDMA_V0_LOCAL_STOP_INT_EN BIT(4)(quoted diff) +0
-0
b/include/linux/dma/edma.hindex 3080747..78ce31b
100644include/linux/dma/edma.h +1
-1@@ -99,6 +99,7 @@ struct dw_edma_chip {enum dw_edma_map_format mf;struct dw_edma *dw; +bool non_ll; };/* Export to the platform drivers */ --1.8.3.1
Re: [PATCH v8 2/2] dmaengine: dw-edma: Add non-LL mode
Quoted 377 lines · Devendra
[AMD Official Use Only - AMD Internal Distribution Only]
Hi Frank
Any update on this review?
Regards,
DevendraQuoted 368 lines
-----Original Message-----
From: Verma, Devendra <[email protected]>
Sent: Thursday, January 29, 2026 5:26 PM
To: Frank Li <[email protected]>
Cc: [email protected]; [email protected]; [email protected]; [email protected]; [email protected]; linux- [email protected]; Simek, Michal <[email protected]>; Verma, Devendra <[email protected]>
Subject: RE: [PATCH v8 2/2] dmaengine: dw-edma: Add non-LL mode[AMD Official Use Only - AMD Internal Distribution Only]
Quoted 8 lines
-----Original Message-----
From: Frank Li <[email protected]>
Sent: Wednesday, January 28, 2026 8:38 PM
To: Verma, Devendra <[email protected]>
Cc: [email protected]; [email protected]; [email protected]; [email protected]; [email protected]; linux- [email protected]; Simek, Michal <[email protected]>
Subject: Re: [PATCH v8 2/2] dmaengine: dw-edma: Add non-LL mode--[ Snipped some headers to reduce the size of this mail ]--
Quoted 10 lines
Quoted 8 lines
Quoted 8 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
AMD MDB IP supports Linked List (LL) mode as well as non-LL
mode.
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
The current code does not have the mechanisms to enable the DMA transactions using the non-LL mode. The following two cases are added with this patch:
- For the AMD (Xilinx) only, when a valid physical baseaddress of
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
the device side DDR is not configured, then the IP can still
be
Quoted 227 lines
Quoted 23 lines
Quoted 23 lines
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 6 lines
Quoted 2 lines
used in non-LL mode. For all the channels DMA
transactions willIf DDR have not configured, where DATA send to in device side by non-LL mode.
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
The DDR base address in the VSEC capability is used for driving the DMA transfers when used in the LL mode. The DDR is configured and present all the time but the DMA PCIe driver uses this DDR base address (physical address) to configure the LLP
address.
Quoted 10 lines
Quoted 10 lines
Quoted 10 lines
Quoted 10 lines
Quoted 10 lines
In the scenario, where this DDR base address in VSEC capability is not configured then the current controller cannot be used as the default mode supported is LL mode only. In order to make the controller usable non-LL mode is being added which just needs SAR, DAR, XFERLEN and control register to initiate the transfer. So, the DDR is always present, but the DMA PCIe driver need to know the DDR base physical address to make the transfer. This is useful in scenarios where the memory
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 4 lines
allocated for LL can be used for DMA transactions as well.
Do you means use DMA transfer LL's context?
Yes, the device side memory reserved for the link list to store the descriptors, accessed by the host via
BAR_2in this drivercode.
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
be using the non-LL mode only. This, the default
non-LLmode,
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
is not applicable for Synopsys IP with the current
codeaddition.
Quoted 6 lines
Quoted 6 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
- If the default mode is LL-mode, for both AMD
(Xilinx) andSynosys,
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
and if user wants to use non-LL mode then user can
do sovia
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
configuring the
peripheral_configparam of
dma_slave_config.Quoted 131 lines
Quoted 131 lines
Quoted 27 lines
Quoted 27 lines
Quoted 10 lines
Quoted 10 lines
Quoted 10 lines
Quoted 10 lines
Quoted 10 lines
Signed-off-by: Devendra K Verma
<[email protected]>
---
Changes in v8
Cosmetic change related to comment and code.Changes in v7
No changeQuoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Changes in v6
Gave definition to bits used for channel configuration. Removed the comment related to doorbell.Changes in v5
Variable name 'nollp' changed to 'non_ll'.
In thedw_edma_device_config()WARN_ONreplaced
with
dev_err().Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Comments follow the 80-column guideline.
Changes in v4
No changeChanges in v3
No changeQuoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Changes in v2
Reverted the function return type to u64 for
dw_edma_get_phys_addr().Changes in v1
Changed the function return type for
dw_edma_get_phys_addr().Quoted 7 lines
Quoted 7 lines
Quoted 6 lines
Quoted 6 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Corrected the typo raised in review.
--- drivers/dma/dw-edma/dw-edma-core.c | 42+++++++++++++++++++++---
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
drivers/dma/dw-edma/dw-edma-core.h | 1 + drivers/dma/dw-edma/dw-edma-pcie.c | 46++++++++++++++++++--
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
------
Quoted 7 lines
Quoted 7 lines
Quoted 3 lines
drivers/dma/dw-edma/dw-hdma-v0-core.c | 61 ++++++++++++++++++++++++++++++++++- drivers/dma/dw-edma/dw-hdma-v0-regs.h | 1 +
edma-v0-core.chave not update, if don't support, at least need return failure atdw_edma_device_config()when backend iseDMA.
Quoted 81 lines
Quoted 81 lines
Quoted 24 lines
Quoted 24 lines
Quoted 24 lines
Quoted 24 lines
Quoted 11 lines
include/linux/dma/edma.h | 1 + 6 files changed, 132 insertions(+), 20 deletions(-)drivers/dma/dw-edma/dw-edma-core.c +0
-0@@ -223,8 +223,32 @@ static intdw_edma_device_config(struct
dma_chan*dchan,Quoted 12 lines
struct
dma_slave_config*config) {
structdw_edma_chan*chan =dchan2dw_edma_chan(dchan);drivers/dma/dw-edma/dw-edma-core.c +8
-0+int non_ll =0 ; + +if (config->peripheral_config && + config->peripheral_size !=sizeof (int )) { +dev_err (dchan->device->dev, +"config param peripheral size mismatch\n" ); +return -EINVAL ; + }Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
drivers/dma/dw-edma/dw-edma-core.c
Quoted 6 lines
memcpy(&chan->config, config,
sizeof(*config));drivers/dma/dw-edma/dw-edma-core.c +4
-0+ +/* +* When there is no valid LLP base address +available then the default
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
drivers/dma/dw-edma/dw-edma-core.c
Quoted 4 lines
drivers/dma/dw-edma/dw-edma-core.c +4
-0+* DMA ops will use the non-LL mode. +* +* Cases where LL mode is enabled and client +wants to use the non-LL
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
+ * mode then also client can do so via
+ providing the
peripheral_configQuoted 9 lines
Quoted 9 lines
Quoted 9 lines
Quoted 9 lines
drivers/dma/dw-edma/dw-edma-core.c
Quoted 9 lines
drivers/dma/dw-edma/dw-edma-core.c +9
-0+* param. +*/ +if (config->peripheral_config) + non_ll = *(int + *)config->peripheral_config; + + chan->non_ll = false; + if (chan->dw->chip->non_ll || + (!chan->dw->chip->non_ll &&
non_ll))Quoted 32 lines
Quoted 10 lines
Quoted 10 lines
Quoted 10 lines
Quoted 7 lines
drivers/dma/dw-edma/dw-edma-core.c +2
-0+ chan->non_ll = true; + chan->configured = true;return 0 ;@@ -353,7 +377,7 @@ static voiddw_edma_device_issue_pending(struct
dma_chan*dchan)Quoted 2 lines
struct
dw_edma_chan*chan =
dchan2dw_edma_chan(xfer-dchan);
Quoted 21 lines
Quoted 21 lines
Quoted 21 lines
Quoted 8 lines
enum dma_transfer_direction dir = xfer->direction; struct scatterlist *sg = NULL;drivers/dma/dw-edma/dw-edma-core.c +1
-1-struct dw_edma_chunk *chunk; +struct dw_edma_chunk *chunk =NULL ;struct dw_edma_burst *burst;struct dw_edma_desc *desc; u64 src_addr, dst_addr; @@ -419,9 +443,11 @@static void dw_edma_device_issue_pending(struct
dma_chan*dchan)Quoted 11 lines
if (unlikely(!desc)) goto err_alloc;drivers/dma/dw-edma/dw-edma-core.c +5
-3- chunk =dw_edma_alloc_chunk (desc); -if (unlikely (!chunk)) - goto err_alloc; +if (!chan->non_ll) { + chunk =dw_edma_alloc_chunk (desc); +if (unlikely (!chunk)) + goto err_alloc; + }Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
non_llis the same asll_max= 1. (or 2, there are link backentry).
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 3 lines
If you set
ll_max= 1, needn't change this code.Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
The
ll_maxis defined for the session till the driver is loaded in thekernel.
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
This code also enables the non-LL mode dynamically upon input from the DMA client. In this scenario, touching
ll_maxwould not be a good idea as thell_maxcontrols the LL entries for all the DMA channels not just for a single DMAtransaction.
Quoted 31 lines
Quoted 31 lines
Quoted 10 lines
Quoted 10 lines
Quoted 6 lines
Quoted 3 lines
You can use new variable, such as
ll_avail.In order to separate out the execution paths a new meaningful variable
"
non_ll"Quoted 3 lines
is used. The variable "
non_ll" alone is sufficient. Using another variable along side "non_ll" for the similar purpose may not have anyQuoted 6 lines
Quoted 6 lines
added advantage.
ll_availcan help debug/fine tune how much impact preformance by adjust ll length. And it make code logic clean and consistent. alsoll_availcan help test corner case when ll item small. Normall case it ishard to reach
ll_max.Quoted 5 lines
Quoted 1 line
Thank you for your suggestion. The
ll_maxis max limit on the descriptors that can be accommodated on the device side DDR. Thell_availwill always be less than
ll_max.Quoted 4 lines
The optimization being referred can be tried without even having to declare the
ll_availcause the number of descriptors given can be controlled by the DMA client based on the length argument to thedmaengine_prep_* APIs.
I optimzied it to allow dynatmic appended dma descriptors.
Quoted 14 lines
Quoted 7 lines
Quoted 7 lines
https://lore.kernel.org/dmaengine/20260109-edma_dymatic-v1-0-
[email protected]/T/#tQuoted 4 lines
So, the use of dynamic
ll_availis not necessarily required. Without increasing thell_max,ll_availcannot be increased. In order to increasell_maxone may need to alter size and recompile thisdriver.
Quoted 6 lines
Quoted 6 lines
Quoted 3 lines
However, the requirement of
ll_availdoes not help for the supporting thenon-LL mode.
Quoted 2 lines
For non-LL mode to use:
1) Either LL mode shall be not available, as it can happen for the XilinxIP.
Quoted 46 lines
Quoted 10 lines
Quoted 10 lines
Quoted 5 lines
2) User provides the preference for non-LL mode.
For both above, the function calls are different which can be differentiated by using the "non_ll" flag. So, even if I try to accommodatell_avail, the call for LL or non-LL would be ambiguous as incase of LL mode also we can have a single descriptor as similar to non-LL mode.
Quoted 2 lines
Please check the function
dw_hdma_v0_core_start()in this review where the decision is taken Based onnon_llflag.Quoted 8 lines
Quoted 3 lines
We can treat
ll_avail== 1 asno_llmode because needn't set extra LL in memory at all.I analyzed the use of
ll_availbut I think the use of this variable does not fit at this location in the code for the following reasons:
1. The use of a new variable breaks the continuity for non-LL mode. Thevariable
Quoted 2 lines
name
non_llis being used for driving the non-LL mode not only
in this filebut also
Quoted 2 lines
in the files relevant to HDMA. This flag gives the clear
indication of LL vsnon-LL mode.
Quoted 2 lines
In the function
dw_hdma_v0_core_start(),non_lldecided the mode
tochoose.
Quoted 2 lines
2. The use of "
ll_avail" is ambiguous for both the modes. First, it isassociated with LL mode only.
Quoted 2 lines
It will be used for optimizing / testing the Controller
performance basedon the
Quoted 2 lines
number of descriptors available on the Device DDR side which is
for LLmode. So when
Quoted 2 lines
it is being used for LL mode then it is obvious that it excludes
any use fornon-LL mode.
Quoted 2 lines
In the API
dw_edma_device_transfer(), thell_availwill be used
forcreating the bursts.
Quoted 2 lines
If
ll_avail= 1 in the above API, then it is ambiguous whether
it is creatingthe burst for
Quoted 9 lines
Quoted 2 lines
LL or non-LL mode. In the above API, the
non_llis sufficient
to have theLL mode
Quoted 1 line
and non-LL burst allocation related piece of code.
If really like non-ll, you'd better set
ll_avail= 1 in prepare code. Normal casell_availshould bell_max. It will reduce if-else branch in prep dma burst code.I think we are not on the same page, and it is creating confusion. If
non_llflag is being used to differentiate between the modes, then in this scenario the use ofll_availdoes not fit any requirement related to differentiation of different modes. In the last response, I pointed out thatll_avail, if used, creates ambiguity rather than bringing clarity for both LL & non-LL mode. Ifnon_llflag is used and initialized properly then this is sufficient to drive the execution for non-LL mode.In the function doing the preparation, there also no if-else clause is introduced rather the same "if" condition is extended to support the non-LL mode.
Could you elaborate what is the approach using
ll_availif I need to maintain the continuity of the non-LL context and use non-LL mode without any ambiguity anywhere, instead of usingnon_llflag?
If possible, please give a code snippet. Depending upon the usability and issue it fixes, I will check its feasibility.Quoted 6 lines
(quoted diff) +5
-0+ /* + * For non-LL mode, only a single burst can be handled + * in a single chunk unlike LL mode where multiple bursts + * can be configured in a single chunk. + */Quoted 7 lines
It is actually wrong, current software should handle that. If there are multiple bursts, only HEAD of bursts trigger DMA, in irq handle, it will auto move to next burst. (only irq latency is bigger compared to LL, software's resule is the same).
The code logic is totally equal
ll_max= 1, except write differece registers.Changing the
ll_maxdynamically for a single request is not feasible. As pointed out earlier it may require the logic to retain the initially configured value, during the probe, and then use the retained value depending on the use-case.
As my previous suggest, add ll_avail, config can set it in [1..ll_max]. then replace ll_max with ll_avail.
Quoted 2 lines
Quoted 2 lines
Could you elaborate the statement,
" The code logic is totally equalll_max= 1, except write differece registers." ?
My means don't touch actual logic in dw_edma_device_transfer() except change ll_max to ll_avail or other variable, with value 1.
Even though you really want to use non_ll, you can use below code
dw_edma_device_transfer()
{
size_t avail = no_ll ? 1 : ll_max; ... if (chunk->bursts_alloc == avail) ... }
Quoted 3 lines
Quoted 3 lines
The
irq_handler()for success case callsdw_edma_start_transfer()which schedules the chunks not bursts.
Current code, it is that. I forget I just change it.
Quoted 3 lines
The bursts associated with that chunk will
Quoted 2 lines
get written to controller DDR area / scheduled (for non-LL) in the
dw_hdma_v0_core_start(), for HDMA.
Original code have unnecessary complex about chunks and burst, which actually add overhead.
See my patch to reduce 2 useless malloc()
https://lore.kernel.org/dmaengine/[email protected]/
Quoted 2 lines
Quoted 2 lines
With this flow, for the non-LL mode each chunk needs to contain a single burst as controller can handle only one burst at a time in non-LL mode.
Non-LL case, you just fill one. The only difference is fill to DDR or registers.
Frank
Quoted 306 lines
Quoted 305 lines
Quoted 6 lines
And anthor important is that,
in
dw_edma_device_config()should return if backend is not HDMA.Thanks, this is a valid concern, will address in the upcoming version.
Quoted 78 lines
Frank
Quoted 75 lines
I think
ll_avail, if used for trying out to optimize / debug the settings related to number of descriptors for LL mode then it should be part of the separate discussion / update not related to non-LL.Quoted 52 lines
Quoted 21 lines
Quoted 21 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
...
Quoted 16 lines
Quoted 12 lines
Quoted 8 lines
Quoted 6 lines
Quoted 2 lines
+
+ll_block->bar);This change need do prepare patch, which only change
pci_bus_address()todw_edma_get_phys_addr().This is not clear.
why not. only trivial add helper patch, which help reviewer
I was not clear on the question you asked.
It does not look justified when a patch is raised alone just to replace thisQuoted 6 lines
Quoted 6 lines
function.
Quoted 5 lines
The function change is required cause the same code *can* support different IPs from different vendors. And, with this single change alone in the code the support for another IP is added. That's why it is easier to get the reason for the change in the function name and
syntax.
Quoted 7 lines
Quoted 7 lines
Add replace
pci_bus_address()withdw_edma_get_phys_addr()to make review easily and get ack for such replacement patches.two patches
patch1, just replace existpci_bus_address()withdw_edma_get_phys_addr()patch2, add new logic in
dw_edma_get_phys_addr()to support new vendor.Quoted 10 lines
Quoted 1 line
I understand your concern about making the review easier. However, given that we've been iterating on this patch series since September and are now at v9, I believe the current approach is justified. The function renames from
pci_bus_address()todw_edma_get_phys_addr()is directly tied to the non-LL mode functionality being added - it's needed because the same code now supports different IPs from different vendors.Quoted 4 lines
Splitting this into a separate preparatory patch at this stage would further delay the review process. The change is kind of straightforward and the context is clear within the current patch. I request
you to review this patch to avoid additional review cycles.
Quoted 1 line
Quoted 9 lines
Quoted 2 lines
This also increases the work related to testing and maintaining multiple
patches.
Quoted 3 lines
I have commitment for delivery of this, and I can see adding one more series definitely add 3-4 months of review cycle from here. Please excuse me but this code has already
Thank you for your persevere.
Thank you for your support.
Quoted 6 lines
Quoted 3 lines
been reviewed extensively by other reviewers and almost by you as well. You can check the detailed discussion wrt this function at the following
link:
Quoted 1 line
https://lore.kernel.org/all/SA1PR12MB8120341DFFD56D90EAD70EDE9514A@
Quoted 217 lines
Quoted 8 lines
Quoted 8 lines
SA1
Quoted 2 lines
PR12MB8120.namprd12.prod.outlook.com/
But still not got reviewed by tags. The recently, Manivannan Sadhasivam , Niklas Cassel and me active worked on this driver. You'd better to get their feedback. Bjorn as pci maintainer to provide
generally feedback.
Quoted 6 lines
Quoted 1 line
Hi Manivannan Sadhasivam, Vinod Koul and Bjorn Helgaas Could you please provide your feedback on the patch?
You have reviewed these patches extensively on the previous versions ofthe same series.
Quoted 71 lines
Regards,
DevendraQuoted 67 lines
Quoted 51 lines
Quoted 51 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
ll_region->paddr += ll_block->off; ll_region->sz = ll_block->sz;...
Quoted 22 lines
Quoted 22 lines
Quoted 4 lines
Quoted 4 lines
drivers/dma/dw-edma/dw-edma-core.c
Quoted 3 lines
drivers/dma/dw-edma/dw-edma-core.c +2
-0+static void dw_hdma_v0_core_non_ll_start (struct +dw_edma_chunk*chunk)
Quoted 12 lines
Quoted 4 lines
Quoted 4 lines
drivers/dma/dw-edma/dw-edma-core.c +4
-0+{ +struct dw_edma_chan *chan = chunk->chan; +struct dw_edma *dw = chan->dw; +struct dw_edma_burst *child;Quoted 8 lines
drivers/dma/dw-edma/dw-edma-core.c
Quoted 5 lines
drivers/dma/dw-edma/dw-edma-core.c +5
-0+u32 val; + +list_for_each_entry (child, + &chunk->burst->list, + list) {why need iterated list, it doesn't support ll. Need wait for irq to start next
one.
Quoted 4 lines
Quoted 2 lines
Frank
Yes, this is true. The format is kept similar to LL mode.
Quoted 8 lines
Quoted 3 lines
Just fill one.
list_for_each_entry()cause confuse.Frank
I see, we can use
list_first_entry_or_null()which is dependent on giving the type of pointer, compared to thislist_for_each_entry()looks neat and agnostic to the pointer type being used. Though, it can beexplored further.
Quoted 7 lines
Also, when the chunk is allocated, the comment clearly spells out how the allocation would be for the non LL mode so it is evident that each chunk would have single entry and with that understanding it is clear that loop will also be used in a similar manner, to retrieve a single entry. It is a similar use case as of "do {}while (0)" albeit needs a context to
understand it.
I don't think so.
list_for_each_entry()is miss leading to reader think it is not only to one item in burst list, and use polling method to to finish many burst transfer.Quoted 7 lines
Quoted 7 lines
list_for_each_entry() { ... readl_timeout() }Generally, EDMA is very quick, polling is much quicker than irq if data is
small.
Quoted 8 lines
Quoted 3 lines
Frank
The polling is not required. The single burst will raise the interrupt and from the interrupt context another chunk will be scheduled. This cycle repeats till all the chunks with single burst are
exhausted.
Quoted 49 lines
Quoted 18 lines
Quoted 4 lines
The following comment made in function
dw_edma_device_transfer()in the same patch makes it amply clear that only a single burst would behandled for the non-LL mode.
Quoted 9 lines
(quoted diff) +5
-0+ /* + * For non-LL mode, only a single burst can be handled + * in a single chunk unlike LL mode where multiple bursts + * can be configured in a single chunk. + */Looking at the way bursts are appended to chunks and chunks in
dw_edma_device_transfer()are scheduled for non-LL mode then it is clearwhat non-LL mode would handle in terms of bursts.
Quoted 3 lines
I just kept the format to match it with the LL mode format otherwise there is no need of this comment and we can follow the syntax for a single
Quoted 9 lines
entry alone.
Quoted 2 lines
Please share your suggestion if these descriptions fail to provide the clear
context and intent.
Avoid use
list_for_each_entry()here to prevent miss-leading.Frank
Sure, thanks, I will push this change in next version.
Quoted 19 lines
Quoted 19 lines
Quoted 19 lines
Quoted 19 lines
Quoted 19 lines
Quoted 19 lines
Quoted 19 lines
Quoted 19 lines
drivers/dma/dw-edma/dw-edma-core.c +15
-0+SET_CH_32 (dw, chan->dir, chan->id, + ch_en,HDMA_V0_CH_EN ); + +/* Source address */ +SET_CH_32 (dw, chan->dir, chan->id, sar.lsb, +lower_32_bits (child->sar)); +SET_CH_32 (dw, chan->dir, chan->id, sar.msb, +upper_32_bits (child->sar)); + +/* Destination address */ +SET_CH_32 (dw, chan->dir, chan->id, dar.lsb, +lower_32_bits (child->dar)); +SET_CH_32 (dw, chan->dir, chan->id, dar.msb, +upper_32_bits (child->dar)); +Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
drivers/dma/dw-edma/dw-edma-core.c
Quoted 8 lines
drivers/dma/dw-edma/dw-edma-core.c +8
-0+/* Transfer size */ +SET_CH_32 (dw, chan->dir, chan->id, + transfer_size, + child->sz); + +/* Interrupt setup */ + val =GET_CH_32 (dw, chan->dir, + chan->id, int_setup)|
Quoted 71 lines
Quoted 71 lines
Quoted 71 lines
Quoted 71 lines
Quoted 71 lines
Quoted 71 lines
Quoted 32 lines
Quoted 32 lines
Quoted 32 lines
drivers/dma/dw-edma/dw-edma-core.c +32
-0+HDMA_V0_STOP_INT_MASK | +HDMA_V0_ABORT_INT_MASK | + +HDMA_V0_LOCAL_STOP_INT_EN | + +HDMA_V0_LOCAL_ABORT_INT_EN ; + +if (!(dw->chip->flags &DW_EDMA_CHIP_LOCAL )) { + val |=HDMA_V0_REMOTE_STOP_INT_EN | +HDMA_V0_REMOTE_ABORT_INT_EN ; + } + +SET_CH_32 (dw, chan->dir, chan->id, + int_setup, val); + +/* Channel control setup */ + val =GET_CH_32 (dw, chan->dir, chan->id, control1); + val &= ~HDMA_V0_LINKLIST_EN ; +SET_CH_32 (dw, chan->dir, chan->id, + control1, val); + +SET_CH_32 (dw, chan->dir, chan->id, doorbell, +HDMA_V0_DOORBELL_START ); + } +} + +static void dw_hdma_v0_core_start (struct +dw_edma_chunk *chunk,bool +first) { +struct dw_edma_chan *chan = chunk->chan; + +if (chan->non_ll)Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
drivers/dma/dw-edma/dw-edma-core.c +5
-0+dw_hdma_v0_core_non_ll_start (chunk); + else +dw_hdma_v0_core_ll_start (chunk , +first ); } + static void dw_hdma_v0_core_ch_config(struct
dw_edma_chan
*chan){
Quoted 30 lines
Quoted 30 lines
Quoted 30 lines
struct dw_edma *dw = chan->dw; diff --git
a/drivers/dma/dw-edma/dw-hdma-v0-regs.hb/drivers/dma/dw-edma/dw-hdma-v0-regs.h
index eab5fd7..7759ba9 100644drivers/dma/dw-edma/dw-hdma-v0-regs.h +1
-0@@ -12,6 +12,7 @@#include <linux/dmaengine.h> #define HDMA_V0_MAX_NR_CH 8 +#define HDMA_V0_CH_EN BIT(0)#define HDMA_V0_LOCAL_ABORT_INT_EN BIT(6)#define HDMA_V0_REMOTE_ABORT_INT_EN BIT(5)#define HDMA_V0_LOCAL_STOP_INT_EN BIT(4)(quoted diff) +0
-0
b/include/linux/dma/edma.hindex 3080747..78ce31b
100644include/linux/dma/edma.h +1
-1@@ -99,6 +99,7 @@ struct dw_edma_chip {enum dw_edma_map_format mf;struct dw_edma *dw; +bool non_ll; };/* Export to the platform drivers */ --1.8.3.1
RE: [PATCH v8 2/2] dmaengine: dw-edma: Add non-LL mode
[AMD Official Use Only - AMD Internal Distribution Only]
Hi Frank
Thanks for your suggestions, please check my response inline.
Regards,
Devendra
Quoted 9 lines
-----Original Message-----
From: Frank Li <[email protected]>
Sent: Tuesday, February 3, 2026 10:23 PM
To: Verma, Devendra <[email protected]>
Cc: [email protected]; [email protected]; [email protected]; [email protected]; [email protected]; linux- [email protected]; Simek, Michal <[email protected]>
Subject: Re: [PATCH v8 2/2] dmaengine: dw-edma: Add non-LL mode
--[ Snipped some headers to reduce the size of this mail ]--
Quoted 373 lines
Quoted 26 lines
Quoted 26 lines
Quoted 12 lines
Quoted 9 lines
Quoted 9 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
AMD MDB IP supports Linked List (LL) mode as
well as non-LLmode.
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
The current code does not have the mechanisms to
enable the DMA transactions using the non-LL mode.
The following two cases are added with this patch:
- For the AMD (Xilinx) only, when a valid
physical baseaddress of
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
the device side DDR is not configured, then
the IP can stillbe
Quoted 13 lines
Quoted 13 lines
Quoted 13 lines
Quoted 13 lines
Quoted 13 lines
Quoted 13 lines
Quoted 13 lines
Quoted 13 lines
Quoted 6 lines
Quoted 2 lines
used in non-LL mode. For all the channels DMA
transactions willIf DDR have not configured, where DATA send to in device side by non-LL mode.
The DDR base address in the VSEC capability is used for driving the DMA transfers when used in the LL mode. The DDR is configured and present all the time but the DMA PCIe driver uses this DDR base address (physical
address) to configure the LLPQuoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
address.
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
In the scenario, where this DDR base address in VSEC capability is not configured then the current controller cannot be used as the default mode supported is
LL mode only.
Quoted 96 lines
Quoted 96 lines
Quoted 96 lines
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
In order to make the controller usable non-LL mode is being added which just needs SAR, DAR, XFERLEN and control register to initiate the transfer. So, the DDR is always present, but the DMA PCIe driver need to know the DDR base physical address to make the transfer. This is useful in scenarios where the memory
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 4 lines
allocated for LL can be used for DMA transactions as well.
Do you means use DMA transfer LL's context?
Yes, the device side memory reserved for the link list to store the descriptors, accessed by the host via
BAR_2in this drivercode.
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
be using the non-LL mode only. This, the
default non-LLmode,
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
is not applicable for Synopsys IP with the
current codeaddition.
Quoted 6 lines
Quoted 6 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
- If the default mode is LL-mode, for both AMD
(Xilinx) andSynosys,
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
and if user wants to use non-LL mode then user
can do sovia
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
configuring the peripheral_config param of
dma_slave_config.Quoted 63 lines
Quoted 63 lines
Quoted 27 lines
Quoted 27 lines
Quoted 10 lines
Quoted 10 lines
Quoted 10 lines
Quoted 10 lines
Quoted 10 lines
Signed-off-by: Devendra K Verma
<[email protected]>
---
Changes in v8
Cosmetic change related to comment and code.Changes in v7
No changeQuoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Changes in v6
Gave definition to bits used for channel configuration.
Removed the comment related to doorbell.Changes in v5
Variable name 'nollp' changed to 'non_ll'.
In the dw_edma_device_config() WARN_ON
replaced with
dev_err().Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Comments follow the 80-column guideline.
Changes in v4
No changeChanges in v3
No changeQuoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Changes in v2
Reverted the function return type to u64 for
dw_edma_get_phys_addr().Changes in v1
Changed the function return type for
dw_edma_get_phys_addr().Quoted 7 lines
Quoted 7 lines
Quoted 6 lines
Quoted 6 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Corrected the typo raised in review.
---
drivers/dma/dw-edma/dw-edma-core.c | 42+++++++++++++++++++++---
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
drivers/dma/dw-edma/dw-edma-core.h | 1 +
drivers/dma/dw-edma/dw-edma-pcie.c | 46++++++++++++++++++--
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
------
Quoted 7 lines
Quoted 7 lines
Quoted 3 lines
drivers/dma/dw-edma/dw-hdma-v0-core.c | 61
++++++++++++++++++++++++++++++++++-
drivers/dma/dw-edma/dw-hdma-v0-regs.h | 1 +
edma-v0-core.chave not update, if don't support, at least need return failure atdw_edma_device_config()when backend iseDMA.
Quoted 13 lines
Quoted 13 lines
Quoted 13 lines
Quoted 13 lines
Quoted 13 lines
Quoted 13 lines
Quoted 12 lines
include/linux/dma/edma.h | 1 +
6 files changed, 132 insertions(+), 20
deletions(-)diff --git a/drivers/dma/dw-edma/dw-edma-core.c
b/drivers/dma/dw-edma/dw-edma-core.c
index b43255f..d37112b 100644
--- a/drivers/dma/dw-edma/dw-edma-core.c
+++ b/drivers/dma/dw-edma/dw-edma-core.c
@@ -223,8 +223,32 @@ static int
dw_edma_device_config(struct
dma_chan*dchan,Quoted 9 lines
Quoted 9 lines
Quoted 9 lines
Quoted 9 lines
Quoted 9 lines
Quoted 9 lines
Quoted 9 lines
Quoted 9 lines
Quoted 9 lines
Quoted 9 lines
Quoted 9 lines
Quoted 9 lines
struct dma_slave_config *config) {
struct dw_edma_chan *chan =
dchan2dw_edma_chan(dchan);
+ int non_ll = 0;
+
+ if (config->peripheral_config &&
+ config->peripheral_size != sizeof(int)) {
+ dev_err(dchan->device->dev,
+ "config param peripheral sizemismatch\n");
Quoted 83 lines
Quoted 83 lines
Quoted 83 lines
Quoted 61 lines
Quoted 61 lines
Quoted 61 lines
Quoted 61 lines
Quoted 9 lines
Quoted 9 lines
Quoted 9 lines
Quoted 9 lines
Quoted 9 lines
+ return -EINVAL;
+ }memcpy(&chan->config, config,
sizeof(*config));
+
+ /*
+ * When there is no valid LLP base address
+ available then thedefault
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
+ * DMA ops will use the non-LL mode.
+ *
+ * Cases where LL mode is enabled and
+ client wants to use thenon-LL
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
+ * mode then also client can do so via
+ providing the
peripheral_configQuoted 9 lines
Quoted 9 lines
Quoted 9 lines
Quoted 9 lines
Quoted 9 lines
+ * param.
+ */
+ if (config->peripheral_config)
+ non_ll = *(int
+ *)config->peripheral_config;
+
+ chan->non_ll = false;
+ if (chan->dw->chip->non_ll ||
+ (!chan->dw->chip->non_ll &&
non_ll))Quoted 33 lines
Quoted 10 lines
Quoted 10 lines
Quoted 10 lines
Quoted 7 lines
+ chan->non_ll = true;
+
chan->configured = true;return 0;
@@ -353,7 +377,7 @@ static void
dw_edma_device_issue_pending(struct
dma_chan*dchan)Quoted 2 lines
struct dw_edma_chan *chan =
dchan2dw_edma_chan(xfer-dchan);
Quoted 22 lines
Quoted 22 lines
Quoted 22 lines
Quoted 9 lines
enum dma_transfer_direction dir = xfer->direction;
struct scatterlist *sg = NULL;
- struct dw_edma_chunk *chunk;
+ struct dw_edma_chunk *chunk = NULL;
struct dw_edma_burst *burst;
struct dw_edma_desc *desc;
u64 src_addr, dst_addr; @@ -419,9 +443,11
@@ static void
dw_edma_device_issue_pending(struct
dma_chan*dchan)Quoted 11 lines
if (unlikely(!desc))
goto err_alloc;- chunk = dw_edma_alloc_chunk(desc);
- if (unlikely(!chunk))
- goto err_alloc;
+ if (!chan->non_ll) {
+ chunk = dw_edma_alloc_chunk(desc);
+ if (unlikely(!chunk))
+ goto err_alloc;
+ }Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
non_llis the same asll_max= 1. (or 2, there are link backentry).
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 3 lines
If you set
ll_max= 1, needn't change this code.Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
The
ll_maxis defined for the session till the driver is loaded in thekernel.
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
This code also enables the non-LL mode dynamically upon input from the DMA client. In this scenario, touching
ll_maxwould not be a good idea as thell_maxcontrols the LL entries for all the DMA channels not just for a single DMAtransaction.
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 3 lines
You can use new variable, such as
ll_avail.In order to separate out the execution paths a new meaningful variable
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
"
non_ll"Quoted 3 lines
is used. The variable "
non_ll" alone is sufficient. Using another variable along side "non_ll" for the similar purpose may not have anyadded advantage.
ll_availcan help debug/fine tune how much impact preformance by adjust ll length. And it make code logic clean andconsistent.
Quoted 43 lines
Quoted 43 lines
Quoted 17 lines
Quoted 17 lines
Quoted 17 lines
Quoted 2 lines
Quoted 2 lines
also
ll_availcan help test corner case when ll item small. Normall case it ishard to reach
ll_max.Quoted 5 lines
Quoted 1 line
Thank you for your suggestion. The
ll_maxis max limit on the descriptors that can be accommodated on the device side DDR. Thell_availwill always be less than
ll_max.Quoted 4 lines
The optimization being referred can be tried without even having to declare the
ll_availcause the number of descriptors given can be controlled by the DMA client based on the length argument to thedmaengine_prep_* APIs.
I optimzied it to allow dynatmic appended dma descriptors.
Quoted 15 lines
Quoted 7 lines
Quoted 7 lines
https://lore.kernel.org/dmaengine/20260109-edma_dymatic-v1-0-
[email protected]/T/#tQuoted 4 lines
So, the use of dynamic
ll_availis not necessarily required. Without increasing thell_max,ll_availcannot be increased. In order to increasell_maxone may need to alter size and recompile thisdriver.
Quoted 7 lines
Quoted 7 lines
Quoted 3 lines
However, the requirement of
ll_availdoes not help for the supporting thenon-LL mode.
Quoted 3 lines
For non-LL mode to use:
1) Either LL mode shall be not available, as it can happen for the XilinxIP.
Quoted 10 lines
Quoted 10 lines
Quoted 10 lines
Quoted 5 lines
2) User provides the preference for non-LL mode. For both above, the function calls are different which can be differentiated by using the "
non_ll" flag. So, even if I try to accommodatell_avail, the call for LL or non-LL would be ambiguous as incase of LL mode also we can have a single descriptor as similar to non-LL mode.
Quoted 2 lines
Please check the function
dw_hdma_v0_core_start()in this review where the decision is taken Based onnon_llflag.Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 3 lines
We can treat
ll_avail== 1 asno_llmode because needn't set extra LL in memory at all.I analyzed the use of
ll_availbut I think the use of this variable does not fit at this location in the code for the followingreasons:
Quoted 40 lines
Quoted 40 lines
Quoted 39 lines
Quoted 2 lines
1. The use of a new variable breaks the continuity for non-LL mode. The
variable
Quoted 2 lines
name
non_llis being used for driving the non-LL mode not
only in this filebut also
Quoted 2 lines
in the files relevant to HDMA. This flag gives the clear
indication of LL vsnon-LL mode.
Quoted 2 lines
In the function
dw_hdma_v0_core_start(),non_lldecided the
mode tochoose.
Quoted 2 lines
2. The use of "
ll_avail" is ambiguous for both the modes. First, it isassociated with LL mode only.
Quoted 2 lines
It will be used for optimizing / testing the Controller
performance basedon the
Quoted 2 lines
number of descriptors available on the Device DDR side which
is for LLmode. So when
Quoted 2 lines
it is being used for LL mode then it is obvious that it
excludes any use fornon-LL mode.
Quoted 2 lines
In the API
dw_edma_device_transfer(), thell_availwill be
used forcreating the bursts.
Quoted 2 lines
If
ll_avail= 1 in the above API, then it is ambiguous
whether it is creatingthe burst for
Quoted 2 lines
LL or non-LL mode. In the above API, the
non_llis
sufficient to have theLL mode
Quoted 1 line
and non-LL burst allocation related piece of code.
If really like non-ll, you'd better set
ll_avail= 1 in prepare code. Normal casell_availshould bell_max. It will reduce if-else branch in prep dma burst code.Quoted 7 lines
Quoted 7 lines
I think we are not on the same page, and it is creating confusion. If
non_llflag is being used to differentiate between the modes, then in this scenario the use ofll_availdoes not fit any requirement related to differentiation of different modes. In the last response, I pointed out thatll_avail, if used, creates ambiguity rather than bringing clarity for both LL & non-LL mode. Ifnon_llflag is used and initialized properly then this is sufficient to drivethe execution for non-LL mode.
Quoted 22 lines
Quoted 22 lines
In the function doing the preparation, there also no if-else clause is introduced rather the same "if" condition is extended to support the non-LL mode.
Could you elaborate what is the approach using
ll_availif I need to maintain the continuity of the non-LL context and use non-LL mode without any ambiguity anywhere, instead of usingnon_llflag? If possible, please give a code snippet. Depending upon the usability and issue it fixes, I will check its feasibility.Quoted 11 lines
(quoted diff) +5
-0+ /* + * For non-LL mode, only a single burst can be handled + * in a single chunk unlike LL mode where multiple bursts + * can be configured in a single chunk. + */It is actually wrong, current software should handle that. If there are multiple bursts, only HEAD of bursts trigger DMA, in irq handle, it will auto move to next burst. (only irq latency is bigger compared to LL, software's resule is the same).
Quoted 7 lines
Quoted 7 lines
Quoted 2 lines
The code logic is totally equal
ll_max= 1, except write differece registers.Changing the
ll_maxdynamically for a single request is not feasible. As pointed out earlier it may require the logic to retain the initially configured value, during the probe, and then use the retained value depending on the use-case.As my previous suggest, add
ll_avail, config can set it in [1..ll_max]. then replacell_maxwithll_avail.Quoted 2 lines
Quoted 2 lines
Could you elaborate the statement,
" The code logic is totally equalll_max= 1, except write differeceregisters." ?
My means don't touch actual logic in
dw_edma_device_transfer()except changell_maxtoll_availor other variable, with value 1.Even though you really want to use
non_ll, you can use below code
dw_edma_device_transfer()
{
Quoted 7 lines
size_t avail = no_ll ? 1 : ll_max;
...
if (chunk->bursts_alloc == avail)
...
}Thank you for the code illustration, this is clear to me.
I suggest we shall use the bursts_max variable to compare with chunk->bursts_alloc instead of ll_avail, that way it is easy to convey the meaning. I tried using ll_avail but it did not suite well with the intent. The use of ll_avail puts the upper limit on the allocation of bursts which bursts_max shows well in comparison to ll_avail. Please review the next update with these suggestions included.
Quoted 18 lines
Quoted 3 lines
Quoted 3 lines
The
irq_handler()for success case callsdw_edma_start_transfer()which schedules the chunks not bursts.Current code, it is that. I forget I just change it.
Quoted 3 lines
The bursts associated with that chunk will
Quoted 2 lines
get written to controller DDR area / scheduled (for non-LL) in the
dw_hdma_v0_core_start(), for HDMA.Original code have unnecessary complex about chunks and burst, which actually add overhead.
See my patch to reduce 2 useless
malloc()https://lore.kernel.org/dmaengine/20251212-edma_ll-v1-0-
[email protected]/
Quoted 8 lines
Quoted 2 lines
Quoted 2 lines
With this flow, for the non-LL mode each chunk needs to contain a single burst as controller can handle only one burst at a time in non-LL
mode.
Non-LL case, you just fill one. The only difference is fill to DDR or registers.
Frank
Thanks for the link, it is good improvement.
Quoted 320 lines
Quoted 7 lines
Quoted 7 lines
Quoted 6 lines
And anthor important is that,
in
dw_edma_device_config()should return if backend is not HDMA.Quoted 8 lines
Quoted 8 lines
Thanks, this is a valid concern, will address in the upcoming version.
Quoted 6 lines
Frank
Quoted 4 lines
I think
ll_avail, if used for trying out to optimize / debug the settings related to number of descriptors for LL mode then it should be part of the separate discussion / update not related to non-LL.
Quoted 40 lines
Quoted 40 lines
Quoted 40 lines
Quoted 40 lines
Quoted 40 lines
Quoted 23 lines
Quoted 23 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
...
Quoted 17 lines
Quoted 8 lines
Quoted 8 lines
Quoted 7 lines
Quoted 2 lines
+
+ ll_block->bar);This change need do prepare patch, which only change
pci_bus_address()todw_edma_get_phys_addr().Quoted 5 lines
Quoted 1 line
This is not clear.
why not. only trivial add helper patch, which help reviewer
I was not clear on the question you asked.
It does not look justified when a patch is raised alone just to replace thisQuoted 6 lines
Quoted 6 lines
function.
Quoted 5 lines
The function change is required cause the same code *can* support different IPs from different vendors. And, with this single change alone in the code the support for another IP is added. That's why it is easier to get the reason for the change in the function name and
syntax.
Quoted 7 lines
Quoted 7 lines
Add replace
pci_bus_address()withdw_edma_get_phys_addr()to make review easily and get ack for such replacement patches.two patches
patch1, just replace existpci_bus_address()withdw_edma_get_phys_addr()patch2, add new logic in
dw_edma_get_phys_addr()to support new vendor.Quoted 2 lines
Quoted 1 line
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
I understand your concern about making the review easier. However, given that we've been iterating on this patch series since September and are now at v9, I believe the current approach is justified. The function renames from
pci_bus_address()todw_edma_get_phys_addr()is directly tied to the non-LL mode functionality being added - it's needed because the same code now supports different IPs fromdifferent vendors.
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Splitting this into a separate preparatory patch at this stage would further delay the review process. The change is kind of straightforward and the context is clear within the current
patch.
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 1 line
I request
you to review this patch to avoid additional review cycles.
Quoted 3 lines
This also increases the work related to testing and maintaining multiple
patches.
Quoted 2 lines
I have commitment for delivery of this, and I can see adding one more series definitely add 3-4 months of review cycle from
here.
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
Quoted 4 lines
Quoted 1 line
Please excuse me but this code has already
Thank you for your persevere.
Thank you for your support.
Quoted 8 lines
Quoted 8 lines
Quoted 7 lines
Quoted 6 lines
Quoted 6 lines
Quoted 3 lines
been reviewed extensively by other reviewers and almost by you as well. You can check the detailed discussion wrt this function at the following
link:
Quoted 1 line
https://lore.kernel.org/all/SA1PR12MB8120341DFFD56D90EAD70EDE9514A@
Quoted 150 lines
Quoted 150 lines
Quoted 150 lines
Quoted 8 lines
Quoted 8 lines
SA1
Quoted 2 lines
PR12MB8120.namprd12.prod.outlook.com/
But still not got reviewed by tags. The recently, Manivannan Sadhasivam , Niklas Cassel and me active worked on this driver. You'd better to get their feedback. Bjorn as pci maintainer to provide
generally feedback.
Quoted 6 lines
Quoted 1 line
Hi Manivannan Sadhasivam, Vinod Koul and Bjorn Helgaas Could you please provide your feedback on the patch?
You have reviewed these patches extensively on the previous versions ofthe same series.
Quoted 72 lines
Regards,
DevendraQuoted 68 lines
Quoted 52 lines
Quoted 52 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
ll_region->paddr += ll_block->off;
ll_region->sz = ll_block->sz;...
Quoted 24 lines
Quoted 24 lines
Quoted 4 lines
Quoted 4 lines
Quoted 3 lines
+static void dw_hdma_v0_core_non_ll_start(struct
+dw_edma_chunk*chunk)
Quoted 12 lines
Quoted 4 lines
Quoted 4 lines
+{
+ struct dw_edma_chan *chan = chunk->chan;
+ struct dw_edma *dw = chan->dw;
+ struct dw_edma_burst *child;Quoted 8 lines
Quoted 5 lines
+ u32 val;
+
+ list_for_each_entry(child,
+ &chunk->burst->list,
+ list) {why need iterated list, it doesn't support ll. Need wait for irq to start next
one.
Quoted 4 lines
Quoted 2 lines
Frank
Yes, this is true. The format is kept similar to LL mode.
Just fill one.
list_for_each_entry()cause confuse.Quoted 7 lines
Quoted 1 line
Frank
I see, we can use
list_first_entry_or_null()which is dependent on giving the type of pointer, compared to thislist_for_each_entry()looks neat and agnostic to the pointer type being used. Though, it can beexplored further.
Quoted 7 lines
Also, when the chunk is allocated, the comment clearly spells out how the allocation would be for the non LL mode so it is evident that each chunk would have single entry and with that understanding it is clear that loop will also be used in a similar manner, to retrieve a single entry. It is a similar use case as of "do {}while (0)" albeit needs a context to
understand it.
I don't think so.
list_for_each_entry()is miss leading to reader think it is not only to one item in burst list, and use polling method to to finish many burst transfer.Quoted 7 lines
Quoted 7 lines
list_for_each_entry() { ... readl_timeout() }Generally, EDMA is very quick, polling is much quicker than irq if data is
small.
Quoted 8 lines
Quoted 3 lines
Frank
The polling is not required. The single burst will raise the interrupt and from the interrupt context another chunk will be scheduled. This cycle repeats till all the chunks with single burst are
exhausted.
Quoted 52 lines
Quoted 19 lines
Quoted 4 lines
The following comment made in function
dw_edma_device_transfer()in the same patch makes it amply clear that only a single burst would behandled for the non-LL mode.
Quoted 10 lines
(quoted diff) +5
-0+ /* + * For non-LL mode, only a single burst can be handled + * in a single chunk unlike LL mode where multiple bursts + * can be configured in a single chunk. + */Looking at the way bursts are appended to chunks and chunks in
dw_edma_device_transfer()are scheduled for non-LL mode then it is clearwhat non-LL mode would handle in terms of bursts.
Quoted 3 lines
I just kept the format to match it with the LL mode format otherwise there is no need of this comment and we can follow the syntax for a single
Quoted 9 lines
entry alone.
Quoted 2 lines
Please share your suggestion if these descriptions fail to provide the clear
context and intent.
Avoid use
list_for_each_entry()here to prevent miss-leading.Frank
Sure, thanks, I will push this change in next version.
Quoted 21 lines
Quoted 21 lines
Quoted 21 lines
Quoted 21 lines
Quoted 21 lines
Quoted 21 lines
Quoted 21 lines
Quoted 21 lines
+ SET_CH_32(dw, chan->dir, chan->id,
+ ch_en, HDMA_V0_CH_EN);
+
+ /* Source address */
+ SET_CH_32(dw, chan->dir, chan->id, sar.lsb,
+ lower_32_bits(child->sar));
+ SET_CH_32(dw, chan->dir, chan->id, sar.msb,
+
+ upper_32_bits(child->sar));
+
+ /* Destination address */
+ SET_CH_32(dw, chan->dir, chan->id, dar.lsb,
+ lower_32_bits(child->dar));
+ SET_CH_32(dw, chan->dir, chan->id, dar.msb,
+
+ upper_32_bits(child->dar));
+Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
+ /* Transfer size */
+ SET_CH_32(dw, chan->dir, chan->id,
+ transfer_size,
+ child->sz);
+
+ /* Interrupt setup */
+ val = GET_CH_32(dw, chan->dir,
+ chan->id, int_setup)|
Quoted 9 lines
Quoted 9 lines
Quoted 9 lines
Quoted 9 lines
Quoted 9 lines
Quoted 9 lines
Quoted 9 lines
Quoted 9 lines
Quoted 9 lines
Quoted 9 lines
Quoted 9 lines
Quoted 9 lines
+ HDMA_V0_STOP_INT_MASK |
+
+ HDMA_V0_ABORT_INT_MASK |
+
+ HDMA_V0_LOCAL_STOP_INT_EN |
+
+ HDMA_V0_LOCAL_ABORT_INT_EN;
+
+ if (!(dw->chip->flags &
DW_EDMA_CHIP_LOCAL)) {Quoted 9 lines
Quoted 9 lines
Quoted 9 lines
Quoted 9 lines
Quoted 9 lines
Quoted 9 lines
Quoted 9 lines
Quoted 9 lines
Quoted 9 lines
Quoted 9 lines
Quoted 9 lines
Quoted 9 lines
+ val |= HDMA_V0_REMOTE_STOP_INT_EN |
+ HDMA_V0_REMOTE_ABORT_INT_EN;
+ }
+
+ SET_CH_32(dw, chan->dir, chan->id,
+ int_setup, val);
+
+ /* Channel control setup */
+ val = GET_CH_32(dw, chan->dir, chan->id,control1);
Quoted 32 lines
Quoted 32 lines
Quoted 32 lines
Quoted 32 lines
Quoted 32 lines
Quoted 32 lines
Quoted 32 lines
Quoted 32 lines
Quoted 32 lines
Quoted 15 lines
Quoted 15 lines
Quoted 15 lines
+ val &= ~HDMA_V0_LINKLIST_EN;
+ SET_CH_32(dw, chan->dir, chan->id,
+ control1, val);
+
+ SET_CH_32(dw, chan->dir, chan->id, doorbell,
+ HDMA_V0_DOORBELL_START);
+ }
+}
+
+static void dw_hdma_v0_core_start(struct
+dw_edma_chunk *chunk, bool
+first) {
+ struct dw_edma_chan *chan = chunk->chan;
+
+ if (chan->non_ll)Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
+ dw_hdma_v0_core_non_ll_start(chunk);
+ else
+ dw_hdma_v0_core_ll_start(chunk,
+ first); }
+
static void dw_hdma_v0_core_ch_config(struct
dw_edma_chan
*chan){
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
struct dw_edma *dw = chan->dw; diff --git
a/drivers/dma/dw-edma/dw-hdma-v0-regs.h
b/drivers/dma/dw-edma/dw-hdma-v0-regs.h
index eab5fd7..7759ba9 100644
--- a/drivers/dma/dw-edma/dw-hdma-v0-regs.h
+++ b/drivers/dma/dw-edma/dw-hdma-v0-regs.h
@@ -12,6 +12,7 @@ #include <linux/dmaengine.h>Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines
#define HDMA_V0_MAX_NR_CH 8
+#define HDMA_V0_CH_EN BIT(0)
#define HDMA_V0_LOCAL_ABORT_INT_EN BIT(6)
#define HDMA_V0_REMOTE_ABORT_INT_ENBIT(5)
Quoted 19 lines
Quoted 18 lines
Quoted 18 lines
Quoted 18 lines
Quoted 18 lines
Quoted 18 lines
Quoted 18 lines
Quoted 18 lines
Quoted 18 lines
Quoted 18 lines
Quoted 18 lines
Quoted 18 lines
#define HDMA_V0_LOCAL_STOP_INT_EN BIT(4)
diff --git a/include/linux/dma/edma.h
b/include/linux/dma/edma.h index
3080747..78ce31b
100644
--- a/include/linux/dma/edma.h
+++ b/include/linux/dma/edma.h
@@ -99,6 +99,7 @@ struct dw_edma_chip {
enum dw_edma_map_format mf;struct dw_edma *dw;
+ bool non_ll;
};/* Export to the platform drivers */
--
1.8.3.1
kernel test robot
build botRe: [PATCH v8 2/2] dmaengine: dw-edma: Add non-LL mode
In reply to Devendra K Vermakernel test robot noticed the following build errors:
Hi Devendra,
kernel test robot noticed the following build errors:
[auto build test ERROR on v6.19-rc4]
[also build test ERROR on linus/master next-20260115] [cannot apply to vkoul-dmaengine/next]
[If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Devendra-K-Verma/dmaengine-dw-edma-Add-AMD-MDB-Endpoint-Support/20260109-200654 base: v6.19-rc4 patch link: https://lore.kernel.org/r/20260109120354.306048-3-devendra.verma%40amd.com patch subject: [PATCH v8 2/2] dmaengine: dw-edma: Add non-LL mode config: s390-allmodconfig (https://download.01.org/0day-ci/archive/20260116/[email protected]/config) compiler: clang version 18.1.8 (https://github.com/llvm/llvm-project 3b5b5c1ec4a3095ab096dd780e84d7ab81f3d7ff) reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260116/[email protected]/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <[email protected]>
| Closes: https://lore.kernel.org/oe-kbuild-all/[email protected]/
All errors (new ones prefixed by >>):
>> drivers/dma/dw-edma/dw-edma-pcie.c:348:37: error: use of undeclared identifier 'DW_PCIE_AMD_MDB_INVALID_ADDR'
348 | if (vsec_data->devmem_phys_off == DW_PCIE_AMD_MDB_INVALID_ADDR)
| ^
>> drivers/dma/dw-edma/dw-edma-pcie.c:358:14: error: use of undeclared identifier 'DW_PCIE_XILINX_LL_OFF_GAP'
358 | DW_PCIE_XILINX_LL_OFF_GAP,
| ^
>> drivers/dma/dw-edma/dw-edma-pcie.c:359:14: error: use of undeclared identifier 'DW_PCIE_XILINX_LL_SIZE'
359 | DW_PCIE_XILINX_LL_SIZE,
| ^
>> drivers/dma/dw-edma/dw-edma-pcie.c:360:14: error: use of undeclared identifier 'DW_PCIE_XILINX_DT_OFF_GAP'
360 | DW_PCIE_XILINX_DT_OFF_GAP,
| ^
>> drivers/dma/dw-edma/dw-edma-pcie.c:361:14: error: use of undeclared identifier 'DW_PCIE_XILINX_DT_SIZE'
361 | DW_PCIE_XILINX_DT_SIZE);
| ^5 errors generated.
vim +/DW_PCIE_AMD_MDB_INVALID_ADDR +348 drivers/dma/dw-edma/dw-edma-pcie.c
309
310 static int dw_edma_pcie_probe(struct pci_dev *pdev,
311 const struct pci_device_id *pid)
312 {
313 struct dw_edma_pcie_data *pdata = (void *)pid->driver_data;
314 struct dw_edma_pcie_data *vsec_data __free(kfree) = NULL;
315 struct device *dev = &pdev->dev;
316 struct dw_edma_chip *chip;
317 int err, nr_irqs;
318 int i, mask;
319 bool non_ll = false;
320
321 vsec_data = kmalloc(sizeof(*vsec_data), GFP_KERNEL);
322 if (!vsec_data)
323 return -ENOMEM;
324
325 /* Enable PCI device */
326 err = pcim_enable_device(pdev);
327 if (err) {
328 pci_err(pdev, "enabling device failed\n");
329 return err;
330 }
331
332 memcpy(vsec_data, pdata, sizeof(struct dw_edma_pcie_data));
333
334 /*
335 * Tries to find if exists a PCIe Vendor-Specific Extended Capability
336 * for the DMA, if one exists, then reconfigures it.
337 */
338 dw_edma_pcie_get_synopsys_dma_data(pdev, vsec_data);
339 dw_edma_pcie_get_xilinx_dma_data(pdev, vsec_data);
340
341 if (pdev->vendor == PCI_VENDOR_ID_XILINX) {
342 /*
343 * There is no valid address found for the LL memory
344 * space on the device side. In the absence of LL base
345 * address use the non-LL mode or simple mode supported by
346 * the HDMA IP.
347 */
> 348 if (vsec_data->devmem_phys_off == DW_PCIE_AMD_MDB_INVALID_ADDR) 349 non_ll = true; 350 351 /* 352 * Configure the channel LL and data blocks if number of 353 * channels enabled in VSEC capability are more than the 354 * channels configured in xilinx_mdb_data. 355 */ 356 if (!non_ll) 357 dw_edma_set_chan_region_offset(vsec_data, BAR_2, 0, > 358 DW_PCIE_XILINX_LL_OFF_GAP, > 359 DW_PCIE_XILINX_LL_SIZE, > 360 DW_PCIE_XILINX_DT_OFF_GAP, > 361 DW_PCIE_XILINX_DT_SIZE);
362 }
363
364 /* Mapping PCI BAR regions */
365 mask = BIT(vsec_data->rg.bar);
366 for (i = 0; i < vsec_data->wr_ch_cnt; i++) {
367 mask |= BIT(vsec_data->ll_wr[i].bar);
368 mask |= BIT(vsec_data->dt_wr[i].bar);
369 }
370 for (i = 0; i < vsec_data->rd_ch_cnt; i++) {
371 mask |= BIT(vsec_data->ll_rd[i].bar);
372 mask |= BIT(vsec_data->dt_rd[i].bar);
373 }
374 err = pcim_iomap_regions(pdev, mask, pci_name(pdev));
375 if (err) {
376 pci_err(pdev, "eDMA BAR I/O remapping failed\n");
377 return err;
378 }
379
380 pci_set_master(pdev);
381
382 /* DMA configuration */
383 err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));
384 if (err) {
385 pci_err(pdev, "DMA mask 64 set failed\n");
386 return err;
387 }
388
389 /* Data structure allocation */
390 chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
391 if (!chip)
392 return -ENOMEM;
393
394 /* IRQs allocation */
395 nr_irqs = pci_alloc_irq_vectors(pdev, 1, vsec_data->irqs,
396 PCI_IRQ_MSI | PCI_IRQ_MSIX);
397 if (nr_irqs < 1) {
398 pci_err(pdev, "fail to alloc IRQ vector (number of IRQs=%u)\n",
399 nr_irqs);
400 return -EPERM;
401 }
402
403 /* Data structure initialization */
404 chip->dev = dev;
405
406 chip->mf = vsec_data->mf;
407 chip->nr_irqs = nr_irqs;
408 chip->ops = &dw_edma_pcie_plat_ops;
409 chip->non_ll = non_ll;
410
411 chip->ll_wr_cnt = vsec_data->wr_ch_cnt;
412 chip->ll_rd_cnt = vsec_data->rd_ch_cnt;
413
414 chip->reg_base = pcim_iomap_table(pdev)[vsec_data->rg.bar];
415 if (!chip->reg_base)
416 return -ENOMEM;
417
418 for (i = 0; i < chip->ll_wr_cnt && !non_ll; i++) {
419 struct dw_edma_region *ll_region = &chip->ll_region_wr[i];
420 struct dw_edma_region *dt_region = &chip->dt_region_wr[i];
421 struct dw_edma_block *ll_block = &vsec_data->ll_wr[i];
422 struct dw_edma_block *dt_block = &vsec_data->dt_wr[i];
423
424 ll_region->vaddr.io = pcim_iomap_table(pdev)[ll_block->bar];
425 if (!ll_region->vaddr.io)
426 return -ENOMEM;
427
428 ll_region->vaddr.io += ll_block->off;
429 ll_region->paddr = dw_edma_get_phys_addr(pdev, vsec_data,
430 ll_block->bar);
431 ll_region->paddr += ll_block->off;
432 ll_region->sz = ll_block->sz;
433
434 dt_region->vaddr.io = pcim_iomap_table(pdev)[dt_block->bar];
435 if (!dt_region->vaddr.io)
436 return -ENOMEM;
437
438 dt_region->vaddr.io += dt_block->off;
439 dt_region->paddr = dw_edma_get_phys_addr(pdev, vsec_data,
440 dt_block->bar);
441 dt_region->paddr += dt_block->off;
442 dt_region->sz = dt_block->sz;
443 }
444
445 for (i = 0; i < chip->ll_rd_cnt && !non_ll; i++) {
446 struct dw_edma_region *ll_region = &chip->ll_region_rd[i];
447 struct dw_edma_region *dt_region = &chip->dt_region_rd[i];
448 struct dw_edma_block *ll_block = &vsec_data->ll_rd[i];
449 struct dw_edma_block *dt_block = &vsec_data->dt_rd[i];
450
451 ll_region->vaddr.io = pcim_iomap_table(pdev)[ll_block->bar];
452 if (!ll_region->vaddr.io)
453 return -ENOMEM;
454
455 ll_region->vaddr.io += ll_block->off;
456 ll_region->paddr = dw_edma_get_phys_addr(pdev, vsec_data,
457 ll_block->bar);
458 ll_region->paddr += ll_block->off;
459 ll_region->sz = ll_block->sz;
460
461 dt_region->vaddr.io = pcim_iomap_table(pdev)[dt_block->bar];
462 if (!dt_region->vaddr.io)
463 return -ENOMEM;
464
465 dt_region->vaddr.io += dt_block->off;
466 dt_region->paddr = dw_edma_get_phys_addr(pdev, vsec_data,
467 dt_block->bar);
468 dt_region->paddr += dt_block->off;
469 dt_region->sz = dt_block->sz;
470 }
471
472 /* Debug info */
473 if (chip->mf == EDMA_MF_EDMA_LEGACY)
474 pci_dbg(pdev, "Version:\teDMA Port Logic (0x%x)\n", chip->mf);
475 else if (chip->mf == EDMA_MF_EDMA_UNROLL)
476 pci_dbg(pdev, "Version:\teDMA Unroll (0x%x)\n", chip->mf);
477 else if (chip->mf == EDMA_MF_HDMA_COMPAT)
478 pci_dbg(pdev, "Version:\tHDMA Compatible (0x%x)\n", chip->mf);
479 else if (chip->mf == EDMA_MF_HDMA_NATIVE)
480 pci_dbg(pdev, "Version:\tHDMA Native (0x%x)\n", chip->mf);
481 else
482 pci_dbg(pdev, "Version:\tUnknown (0x%x)\n", chip->mf);
483
484 pci_dbg(pdev, "Registers:\tBAR=%u, off=0x%.8lx, sz=0x%zx bytes, addr(v=%p)\n",
485 vsec_data->rg.bar, vsec_data->rg.off, vsec_data->rg.sz,
486 chip->reg_base);
487
488
489 for (i = 0; i < chip->ll_wr_cnt; i++) {
490 pci_dbg(pdev, "L. List:\tWRITE CH%.2u, BAR=%u, off=0x%.8lx, sz=0x%zx bytes, addr(v=%p, p=%pa)\n",
491 i, vsec_data->ll_wr[i].bar,
492 vsec_data->ll_wr[i].off, chip->ll_region_wr[i].sz,
493 chip->ll_region_wr[i].vaddr.io, &chip->ll_region_wr[i].paddr);
494
495 pci_dbg(pdev, "Data:\tWRITE CH%.2u, BAR=%u, off=0x%.8lx, sz=0x%zx bytes, addr(v=%p, p=%pa)\n",
496 i, vsec_data->dt_wr[i].bar,
497 vsec_data->dt_wr[i].off, chip->dt_region_wr[i].sz,
498 chip->dt_region_wr[i].vaddr.io, &chip->dt_region_wr[i].paddr);
499 }
500
501 for (i = 0; i < chip->ll_rd_cnt; i++) {
502 pci_dbg(pdev, "L. List:\tREAD CH%.2u, BAR=%u, off=0x%.8lx, sz=0x%zx bytes, addr(v=%p, p=%pa)\n",
503 i, vsec_data->ll_rd[i].bar,
504 vsec_data->ll_rd[i].off, chip->ll_region_rd[i].sz,
505 chip->ll_region_rd[i].vaddr.io, &chip->ll_region_rd[i].paddr);
506
507 pci_dbg(pdev, "Data:\tREAD CH%.2u, BAR=%u, off=0x%.8lx, sz=0x%zx bytes, addr(v=%p, p=%pa)\n",
508 i, vsec_data->dt_rd[i].bar,
509 vsec_data->dt_rd[i].off, chip->dt_region_rd[i].sz,
510 chip->dt_region_rd[i].vaddr.io, &chip->dt_region_rd[i].paddr);
511 }
512
513 pci_dbg(pdev, "Nr. IRQs:\t%u\n", chip->nr_irqs);
514
515 /* Validating if PCI interrupts were enabled */
516 if (!pci_dev_msi_enabled(pdev)) {
517 pci_err(pdev, "enable interrupt failed\n");
518 return -EPERM;
519 }
520
521 /* Starting eDMA driver */
522 err = dw_edma_probe(chip);
523 if (err) {
524 pci_err(pdev, "eDMA probe failed\n");
525 return err;
526 }
527
528 /* Saving data structure reference */
529 pci_set_drvdata(pdev, chip);
530
531 return 0;
532 }
533
Signature · 2 lines
0-DAY CI Kernel Test Service https://github.com/intel/lkp-tests/wiki
kernel test robot
build botRe: [PATCH v8 2/2] dmaengine: dw-edma: Add non-LL mode
In reply to Devendra K Vermakernel test robot noticed the following build errors:
Hi Devendra,
kernel test robot noticed the following build errors:
[auto build test ERROR on v6.19-rc4]
[also build test ERROR on linus/master next-20260115] [cannot apply to vkoul-dmaengine/next]
[If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Devendra-K-Verma/dmaengine-dw-edma-Add-AMD-MDB-Endpoint-Support/20260109-200654 base: v6.19-rc4 patch link: https://lore.kernel.org/r/20260109120354.306048-3-devendra.verma%40amd.com patch subject: [PATCH v8 2/2] dmaengine: dw-edma: Add non-LL mode config: alpha-allyesconfig (https://download.01.org/0day-ci/archive/20260116/[email protected]/config) compiler: alpha-linux-gcc (GCC) 15.2.0 reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260116/[email protected]/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <[email protected]>
| Closes: https://lore.kernel.org/oe-kbuild-all/[email protected]/
All errors (new ones prefixed by >>):
drivers/dma/dw-edma/dw-edma-pcie.c: In function 'dw_edma_pcie_probe':
>> drivers/dma/dw-edma/dw-edma-pcie.c:348:51: error: 'DW_PCIE_AMD_MDB_INVALID_ADDR' undeclared (first use in this function); did you mean 'DW_PCIE_XILINX_MDB_INVALID_ADDR'?
348 | if (vsec_data->devmem_phys_off == DW_PCIE_AMD_MDB_INVALID_ADDR)
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
| DW_PCIE_XILINX_MDB_INVALID_ADDR
drivers/dma/dw-edma/dw-edma-pcie.c:348:51: note: each undeclared identifier is reported only once for each function it appears in
>> drivers/dma/dw-edma/dw-edma-pcie.c:358:56: error: 'DW_PCIE_XILINX_LL_OFF_GAP' undeclared (first use in this function); did you mean 'DW_PCIE_XILINX_MDB_LL_OFF_GAP'?
358 | DW_PCIE_XILINX_LL_OFF_GAP,
| ^~~~~~~~~~~~~~~~~~~~~~~~~
| DW_PCIE_XILINX_MDB_LL_OFF_GAP
>> drivers/dma/dw-edma/dw-edma-pcie.c:359:56: error: 'DW_PCIE_XILINX_LL_SIZE' undeclared (first use in this function); did you mean 'DW_PCIE_XILINX_MDB_LL_SIZE'?
359 | DW_PCIE_XILINX_LL_SIZE,
| ^~~~~~~~~~~~~~~~~~~~~~
| DW_PCIE_XILINX_MDB_LL_SIZE
>> drivers/dma/dw-edma/dw-edma-pcie.c:360:56: error: 'DW_PCIE_XILINX_DT_OFF_GAP' undeclared (first use in this function); did you mean 'DW_PCIE_XILINX_MDB_DT_OFF_GAP'?
360 | DW_PCIE_XILINX_DT_OFF_GAP,
| ^~~~~~~~~~~~~~~~~~~~~~~~~
| DW_PCIE_XILINX_MDB_DT_OFF_GAP
>> drivers/dma/dw-edma/dw-edma-pcie.c:361:56: error: 'DW_PCIE_XILINX_DT_SIZE' undeclared (first use in this function); did you mean 'DW_PCIE_XILINX_MDB_DT_SIZE'?
361 | DW_PCIE_XILINX_DT_SIZE);
| ^~~~~~~~~~~~~~~~~~~~~~
| DW_PCIE_XILINX_MDB_DT_SIZEvim +348 drivers/dma/dw-edma/dw-edma-pcie.c
309
310 static int dw_edma_pcie_probe(struct pci_dev *pdev,
311 const struct pci_device_id *pid)
312 {
313 struct dw_edma_pcie_data *pdata = (void *)pid->driver_data;
314 struct dw_edma_pcie_data *vsec_data __free(kfree) = NULL;
315 struct device *dev = &pdev->dev;
316 struct dw_edma_chip *chip;
317 int err, nr_irqs;
318 int i, mask;
319 bool non_ll = false;
320
321 vsec_data = kmalloc(sizeof(*vsec_data), GFP_KERNEL);
322 if (!vsec_data)
323 return -ENOMEM;
324
325 /* Enable PCI device */
326 err = pcim_enable_device(pdev);
327 if (err) {
328 pci_err(pdev, "enabling device failed\n");
329 return err;
330 }
331
332 memcpy(vsec_data, pdata, sizeof(struct dw_edma_pcie_data));
333
334 /*
335 * Tries to find if exists a PCIe Vendor-Specific Extended Capability
336 * for the DMA, if one exists, then reconfigures it.
337 */
338 dw_edma_pcie_get_synopsys_dma_data(pdev, vsec_data);
339 dw_edma_pcie_get_xilinx_dma_data(pdev, vsec_data);
340
341 if (pdev->vendor == PCI_VENDOR_ID_XILINX) {
342 /*
343 * There is no valid address found for the LL memory
344 * space on the device side. In the absence of LL base
345 * address use the non-LL mode or simple mode supported by
346 * the HDMA IP.
347 */
> 348 if (vsec_data->devmem_phys_off == DW_PCIE_AMD_MDB_INVALID_ADDR) 349 non_ll = true; 350 351 /* 352 * Configure the channel LL and data blocks if number of 353 * channels enabled in VSEC capability are more than the 354 * channels configured in xilinx_mdb_data. 355 */ 356 if (!non_ll) 357 dw_edma_set_chan_region_offset(vsec_data, BAR_2, 0, > 358 DW_PCIE_XILINX_LL_OFF_GAP, > 359 DW_PCIE_XILINX_LL_SIZE, > 360 DW_PCIE_XILINX_DT_OFF_GAP, > 361 DW_PCIE_XILINX_DT_SIZE);
362 }
363
364 /* Mapping PCI BAR regions */
365 mask = BIT(vsec_data->rg.bar);
366 for (i = 0; i < vsec_data->wr_ch_cnt; i++) {
367 mask |= BIT(vsec_data->ll_wr[i].bar);
368 mask |= BIT(vsec_data->dt_wr[i].bar);
369 }
370 for (i = 0; i < vsec_data->rd_ch_cnt; i++) {
371 mask |= BIT(vsec_data->ll_rd[i].bar);
372 mask |= BIT(vsec_data->dt_rd[i].bar);
373 }
374 err = pcim_iomap_regions(pdev, mask, pci_name(pdev));
375 if (err) {
376 pci_err(pdev, "eDMA BAR I/O remapping failed\n");
377 return err;
378 }
379
380 pci_set_master(pdev);
381
382 /* DMA configuration */
383 err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));
384 if (err) {
385 pci_err(pdev, "DMA mask 64 set failed\n");
386 return err;
387 }
388
389 /* Data structure allocation */
390 chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
391 if (!chip)
392 return -ENOMEM;
393
394 /* IRQs allocation */
395 nr_irqs = pci_alloc_irq_vectors(pdev, 1, vsec_data->irqs,
396 PCI_IRQ_MSI | PCI_IRQ_MSIX);
397 if (nr_irqs < 1) {
398 pci_err(pdev, "fail to alloc IRQ vector (number of IRQs=%u)\n",
399 nr_irqs);
400 return -EPERM;
401 }
402
403 /* Data structure initialization */
404 chip->dev = dev;
405
406 chip->mf = vsec_data->mf;
407 chip->nr_irqs = nr_irqs;
408 chip->ops = &dw_edma_pcie_plat_ops;
409 chip->non_ll = non_ll;
410
411 chip->ll_wr_cnt = vsec_data->wr_ch_cnt;
412 chip->ll_rd_cnt = vsec_data->rd_ch_cnt;
413
414 chip->reg_base = pcim_iomap_table(pdev)[vsec_data->rg.bar];
415 if (!chip->reg_base)
416 return -ENOMEM;
417
418 for (i = 0; i < chip->ll_wr_cnt && !non_ll; i++) {
419 struct dw_edma_region *ll_region = &chip->ll_region_wr[i];
420 struct dw_edma_region *dt_region = &chip->dt_region_wr[i];
421 struct dw_edma_block *ll_block = &vsec_data->ll_wr[i];
422 struct dw_edma_block *dt_block = &vsec_data->dt_wr[i];
423
424 ll_region->vaddr.io = pcim_iomap_table(pdev)[ll_block->bar];
425 if (!ll_region->vaddr.io)
426 return -ENOMEM;
427
428 ll_region->vaddr.io += ll_block->off;
429 ll_region->paddr = dw_edma_get_phys_addr(pdev, vsec_data,
430 ll_block->bar);
431 ll_region->paddr += ll_block->off;
432 ll_region->sz = ll_block->sz;
433
434 dt_region->vaddr.io = pcim_iomap_table(pdev)[dt_block->bar];
435 if (!dt_region->vaddr.io)
436 return -ENOMEM;
437
438 dt_region->vaddr.io += dt_block->off;
439 dt_region->paddr = dw_edma_get_phys_addr(pdev, vsec_data,
440 dt_block->bar);
441 dt_region->paddr += dt_block->off;
442 dt_region->sz = dt_block->sz;
443 }
444
445 for (i = 0; i < chip->ll_rd_cnt && !non_ll; i++) {
446 struct dw_edma_region *ll_region = &chip->ll_region_rd[i];
447 struct dw_edma_region *dt_region = &chip->dt_region_rd[i];
448 struct dw_edma_block *ll_block = &vsec_data->ll_rd[i];
449 struct dw_edma_block *dt_block = &vsec_data->dt_rd[i];
450
451 ll_region->vaddr.io = pcim_iomap_table(pdev)[ll_block->bar];
452 if (!ll_region->vaddr.io)
453 return -ENOMEM;
454
455 ll_region->vaddr.io += ll_block->off;
456 ll_region->paddr = dw_edma_get_phys_addr(pdev, vsec_data,
457 ll_block->bar);
458 ll_region->paddr += ll_block->off;
459 ll_region->sz = ll_block->sz;
460
461 dt_region->vaddr.io = pcim_iomap_table(pdev)[dt_block->bar];
462 if (!dt_region->vaddr.io)
463 return -ENOMEM;
464
465 dt_region->vaddr.io += dt_block->off;
466 dt_region->paddr = dw_edma_get_phys_addr(pdev, vsec_data,
467 dt_block->bar);
468 dt_region->paddr += dt_block->off;
469 dt_region->sz = dt_block->sz;
470 }
471
472 /* Debug info */
473 if (chip->mf == EDMA_MF_EDMA_LEGACY)
474 pci_dbg(pdev, "Version:\teDMA Port Logic (0x%x)\n", chip->mf);
475 else if (chip->mf == EDMA_MF_EDMA_UNROLL)
476 pci_dbg(pdev, "Version:\teDMA Unroll (0x%x)\n", chip->mf);
477 else if (chip->mf == EDMA_MF_HDMA_COMPAT)
478 pci_dbg(pdev, "Version:\tHDMA Compatible (0x%x)\n", chip->mf);
479 else if (chip->mf == EDMA_MF_HDMA_NATIVE)
480 pci_dbg(pdev, "Version:\tHDMA Native (0x%x)\n", chip->mf);
481 else
482 pci_dbg(pdev, "Version:\tUnknown (0x%x)\n", chip->mf);
483
484 pci_dbg(pdev, "Registers:\tBAR=%u, off=0x%.8lx, sz=0x%zx bytes, addr(v=%p)\n",
485 vsec_data->rg.bar, vsec_data->rg.off, vsec_data->rg.sz,
486 chip->reg_base);
487
488
489 for (i = 0; i < chip->ll_wr_cnt; i++) {
490 pci_dbg(pdev, "L. List:\tWRITE CH%.2u, BAR=%u, off=0x%.8lx, sz=0x%zx bytes, addr(v=%p, p=%pa)\n",
491 i, vsec_data->ll_wr[i].bar,
492 vsec_data->ll_wr[i].off, chip->ll_region_wr[i].sz,
493 chip->ll_region_wr[i].vaddr.io, &chip->ll_region_wr[i].paddr);
494
495 pci_dbg(pdev, "Data:\tWRITE CH%.2u, BAR=%u, off=0x%.8lx, sz=0x%zx bytes, addr(v=%p, p=%pa)\n",
496 i, vsec_data->dt_wr[i].bar,
497 vsec_data->dt_wr[i].off, chip->dt_region_wr[i].sz,
498 chip->dt_region_wr[i].vaddr.io, &chip->dt_region_wr[i].paddr);
499 }
500
501 for (i = 0; i < chip->ll_rd_cnt; i++) {
502 pci_dbg(pdev, "L. List:\tREAD CH%.2u, BAR=%u, off=0x%.8lx, sz=0x%zx bytes, addr(v=%p, p=%pa)\n",
503 i, vsec_data->ll_rd[i].bar,
504 vsec_data->ll_rd[i].off, chip->ll_region_rd[i].sz,
505 chip->ll_region_rd[i].vaddr.io, &chip->ll_region_rd[i].paddr);
506
507 pci_dbg(pdev, "Data:\tREAD CH%.2u, BAR=%u, off=0x%.8lx, sz=0x%zx bytes, addr(v=%p, p=%pa)\n",
508 i, vsec_data->dt_rd[i].bar,
509 vsec_data->dt_rd[i].off, chip->dt_region_rd[i].sz,
510 chip->dt_region_rd[i].vaddr.io, &chip->dt_region_rd[i].paddr);
511 }
512
513 pci_dbg(pdev, "Nr. IRQs:\t%u\n", chip->nr_irqs);
514
515 /* Validating if PCI interrupts were enabled */
516 if (!pci_dev_msi_enabled(pdev)) {
517 pci_err(pdev, "enable interrupt failed\n");
518 return -EPERM;
519 }
520
521 /* Starting eDMA driver */
522 err = dw_edma_probe(chip);
523 if (err) {
524 pci_err(pdev, "eDMA probe failed\n");
525 return err;
526 }
527
528 /* Saving data structure reference */
529 pci_set_drvdata(pdev, chip);
530
531 return 0;
532 }
533
Signature · 2 lines
0-DAY CI Kernel Test Service https://github.com/intel/lkp-tests/wiki