Re: [PATCH v2 05/12] dmaengine: dw-edma-pcie: Add capability match data
From: Frank Li
Date: Thu Jun 04 2026 - 16:34:08 EST
On Mon, May 25, 2026 at 03:24:13PM +0900, Koichiro Den wrote:
> Move device-specific capability parsing behind per-device match data.
>
> The existing probe path mixes two decisions: which static template a PCI
> ID uses, and which device-specific capability parser adjusts that
> template. Split those decisions so device-specific discovery can be
> added through match data instead of adding more vendor checks to
> dw_edma_pcie_probe().
>
> No functional change is intended for the existing Synopsys EDDA and
> AMD/Xilinx MDB matches. They still copy the same static template data and
> run the same capability parsing logic before BAR mapping. The MDB entry
> also keeps using endpoint memory physical addresses for descriptor
> windows through a new match-data flag.
>
> Suggested-by: Frank Li <Frank.Li@xxxxxxx>
> Signed-off-by: Koichiro Den <den@xxxxxxxxxxxxx>
> ---
Reviewed-by: Frank Li <Frank.Li@xxxxxxx>
> Changes in v2:
> - Keep non-LL mode in dw_edma_pcie_data instead of a separate
> parse_caps() output parameter.
> - While at here, use a named .driver_data initializer for the Xilinx MDB ID
> entry, per Frank's suggestion.
>
> drivers/dma/dw-edma/dw-edma-pcie.c | 127 +++++++++++++++++++----------
> 1 file changed, 85 insertions(+), 42 deletions(-)
>
> diff --git a/drivers/dma/dw-edma/dw-edma-pcie.c b/drivers/dma/dw-edma/dw-edma-pcie.c
> index e92ff5dc6f67..5a6f5af358d0 100644
> --- a/drivers/dma/dw-edma/dw-edma-pcie.c
> +++ b/drivers/dma/dw-edma/dw-edma-pcie.c
> @@ -75,6 +75,19 @@ struct dw_edma_pcie_data {
> bool cfg_non_ll;
> };
>
> +struct dw_edma_pcie_match_data {
> + const struct dw_edma_pcie_data *data;
> + /*
> + * Mandatory callback. It may leave @pdata unchanged when the static
> + * template already describes the device.
> + */
> + int (*parse_caps)(struct pci_dev *pdev,
> + struct dw_edma_pcie_data *pdata);
> + unsigned long flags;
> +};
> +
> +#define DW_EDMA_PCIE_F_DEVMEM_PHYS_OFF BIT(0)
> +
> static const struct dw_edma_pcie_data snps_edda_data = {
> /* eDMA registers location */
> .rg.bar = BAR_0,
> @@ -296,19 +309,61 @@ static void dw_edma_pcie_get_xilinx_dma_data(struct pci_dev *pdev,
> pdata->devmem_phys_off = off;
> }
>
> +static int
> +dw_edma_pcie_parse_synopsys_caps(struct pci_dev *pdev,
> + struct dw_edma_pcie_data *pdata)
> +{
> + dw_edma_pcie_get_synopsys_dma_data(pdev, pdata);
> +
> + return 0;
> +}
> +
> +static int
> +dw_edma_pcie_parse_xilinx_caps(struct pci_dev *pdev,
> + struct dw_edma_pcie_data *pdata)
> +{
> + dw_edma_pcie_get_xilinx_dma_data(pdev, pdata);
> +
> + /*
> + * There is no valid address found for the LL memory 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 (pdata->devmem_phys_off == DW_PCIE_XILINX_MDB_INVALID_ADDR) {
> + pdata->cfg_non_ll = true;
> + return 0;
> + }
> +
> + /*
> + * 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(pdata, 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);
> +
> + return 0;
> +}
> +
> static u64 dw_edma_get_phys_addr(struct pci_dev *pdev,
> + const struct dw_edma_pcie_match_data *match,
> struct dw_edma_pcie_data *pdata,
> enum pci_barno bar)
> {
> - if (pdev->vendor == PCI_VENDOR_ID_XILINX)
> + if (match->flags & DW_EDMA_PCIE_F_DEVMEM_PHYS_OFF)
> 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)
> {
> - struct dw_edma_pcie_data *pdata = (void *)pid->driver_data;
> + const struct dw_edma_pcie_match_data *match = (void *)pid->driver_data;
> + const struct dw_edma_pcie_data *pdata = match->data;
> struct device *dev = &pdev->dev;
> struct dw_edma_chip *chip;
> int err, nr_irqs;
> @@ -328,36 +383,13 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
>
> memcpy(vsec_data, pdata, sizeof(struct dw_edma_pcie_data));
>
> - /*
> - * Tries to find if exists a PCIe Vendor-Specific Extended Capability
> - * for the DMA, if one exists, then reconfigures it.
> - */
> - dw_edma_pcie_get_synopsys_dma_data(pdev, vsec_data);
> -
> - if (pdev->vendor == PCI_VENDOR_ID_XILINX) {
> - dw_edma_pcie_get_xilinx_dma_data(pdev, vsec_data);
> -
> - /*
> - * There is no valid address found for the LL memory
> - * 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)
> - vsec_data->cfg_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.
> - */
> - if (!vsec_data->cfg_non_ll)
> - 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);
> - }
> + /* Let device-specific discovery override the static template data. */
> + if (!match->parse_caps)
> + return -EINVAL;
> +
> + err = match->parse_caps(pdev, vsec_data);
> + if (err)
> + return err;
>
> /* Mapping PCI BAR regions */
> mask = BIT(vsec_data->rg.bar);
> @@ -424,8 +456,8 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
> return -ENOMEM;
>
> ll_region->vaddr.io += ll_block->off;
> - ll_region->paddr = dw_edma_get_phys_addr(pdev, vsec_data,
> - ll_block->bar);
> + ll_region->paddr = dw_edma_get_phys_addr(pdev, match,
> + vsec_data, ll_block->bar);
> ll_region->paddr += ll_block->off;
> ll_region->sz = ll_block->sz;
>
> @@ -434,8 +466,8 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
> return -ENOMEM;
>
> dt_region->vaddr.io += dt_block->off;
> - dt_region->paddr = dw_edma_get_phys_addr(pdev, vsec_data,
> - dt_block->bar);
> + dt_region->paddr = dw_edma_get_phys_addr(pdev, match,
> + vsec_data, dt_block->bar);
> dt_region->paddr += dt_block->off;
> dt_region->sz = dt_block->sz;
> }
> @@ -451,8 +483,8 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
> return -ENOMEM;
>
> ll_region->vaddr.io += ll_block->off;
> - ll_region->paddr = dw_edma_get_phys_addr(pdev, vsec_data,
> - ll_block->bar);
> + ll_region->paddr = dw_edma_get_phys_addr(pdev, match,
> + vsec_data, ll_block->bar);
> ll_region->paddr += ll_block->off;
> ll_region->sz = ll_block->sz;
>
> @@ -461,8 +493,8 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
> return -ENOMEM;
>
> dt_region->vaddr.io += dt_block->off;
> - dt_region->paddr = dw_edma_get_phys_addr(pdev, vsec_data,
> - dt_block->bar);
> + dt_region->paddr = dw_edma_get_phys_addr(pdev, match,
> + vsec_data, dt_block->bar);
> dt_region->paddr += dt_block->off;
> dt_region->sz = dt_block->sz;
> }
> @@ -543,10 +575,21 @@ static void dw_edma_pcie_remove(struct pci_dev *pdev)
> pci_free_irq_vectors(pdev);
> }
>
> +static const struct dw_edma_pcie_match_data snps_edda_match_data = {
> + .data = &snps_edda_data,
> + .parse_caps = dw_edma_pcie_parse_synopsys_caps,
> +};
> +
> +static const struct dw_edma_pcie_match_data xilinx_mdb_match_data = {
> + .data = &xilinx_mdb_data,
> + .parse_caps = dw_edma_pcie_parse_xilinx_caps,
> + .flags = DW_EDMA_PCIE_F_DEVMEM_PHYS_OFF,
> +};
> +
> static const struct pci_device_id dw_edma_pcie_id_table[] = {
> - { PCI_DEVICE_DATA(SYNOPSYS, EDDA, &snps_edda_data) },
> + { PCI_DEVICE_DATA(SYNOPSYS, EDDA, &snps_edda_match_data) },
> { PCI_VDEVICE(XILINX, PCI_DEVICE_ID_XILINX_B054),
> - (kernel_ulong_t)&xilinx_mdb_data },
> + .driver_data = (kernel_ulong_t)&xilinx_mdb_match_data },
> { }
> };
> MODULE_DEVICE_TABLE(pci, dw_edma_pcie_id_table);
> --
> 2.51.0
>