mirror of
https://github.com/torvalds/linux.git
synced 2026-09-23 05:04:02 +02:00
dmaengine: dw-edma-pcie: Add capability match data
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/CPM6 matches. They still copy the same static template data and run the same capability parsing logic before BAR mapping. The AMD (Xilinx) MDB/CPM6 entries also keep using endpoint memory physical addresses for descriptor windows through a new match-data flag. Suggested-by: Frank Li <Frank.Li@nxp.com> Reviewed-by: Frank Li <Frank.Li@nxp.com> Signed-off-by: Koichiro Den <den@valinux.co.jp> Link: https://patch.msgid.link/20260721062815.4117887-8-den@valinux.co.jp Signed-off-by: Vinod Koul <vkoul@kernel.org>
This commit is contained in:
parent
1415d6d1f1
commit
f3468b998a
|
|
@ -76,6 +76,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,
|
||||
|
|
@ -310,24 +323,70 @@ 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;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct dw_edma_chip *chip;
|
||||
int err, nr_irqs;
|
||||
int i, mask;
|
||||
|
||||
if (!match)
|
||||
return -ENODEV;
|
||||
pdata = match->data;
|
||||
|
||||
if (!pdata)
|
||||
return -ENODEV;
|
||||
|
||||
|
|
@ -345,36 +404,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);
|
||||
/* Let device-specific discovery override the static template data. */
|
||||
if (!match->parse_caps)
|
||||
return -EINVAL;
|
||||
|
||||
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);
|
||||
}
|
||||
err = match->parse_caps(pdev, vsec_data);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* Mapping PCI BAR regions */
|
||||
mask = BIT(vsec_data->rg.bar);
|
||||
|
|
@ -441,8 +477,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;
|
||||
|
||||
|
|
@ -451,8 +487,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;
|
||||
}
|
||||
|
|
@ -468,8 +504,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;
|
||||
|
||||
|
|
@ -478,8 +514,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;
|
||||
}
|
||||
|
|
@ -557,12 +593,29 @@ static void dw_edma_pcie_remove(struct pci_dev *pdev)
|
|||
pci_warn(pdev, "can't remove device properly: %d\n", err);
|
||||
}
|
||||
|
||||
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 dw_edma_pcie_match_data xilinx_cpm6_dma_match_data = {
|
||||
.data = &xilinx_cpm6_dma_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 },
|
||||
{ PCI_VDEVICE(XILINX, PCI_DEVICE_ID_XILINX_B00F),
|
||||
.driver_data = (kernel_ulong_t)&xilinx_cpm6_dma_data },
|
||||
.driver_data = (kernel_ulong_t)&xilinx_cpm6_dma_match_data },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pci, dw_edma_pcie_id_table);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user