Some DesignWare PCIe endpoint controllers integrate a DesignWare eDMA instance. Remote-eDMA providers (e.g. vNTB) need to expose the eDMA register block to the host through a memory window so the host can ioremap it and run dw_edma_probe() against the remote view.
Record the physical base and size of the eDMA register aperture and export dw_edma_get_reg_window() so higher-level code can query the register window associated with a given PCI EPC device. Signed-off-by: Koichiro Den <[email protected]> --- drivers/pci/controller/dwc/pcie-designware.c | 26 ++++++++++++++++++++ include/linux/dma/edma.h | 25 +++++++++++++++++++ 2 files changed, 51 insertions(+) diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c index 345365ea97c7..ad18b84c9f71 100644 --- a/drivers/pci/controller/dwc/pcie-designware.c +++ b/drivers/pci/controller/dwc/pcie-designware.c @@ -162,8 +162,12 @@ int dw_pcie_get_resources(struct dw_pcie *pci) pci->edma.reg_base = devm_ioremap_resource(pci->dev, res); if (IS_ERR(pci->edma.reg_base)) return PTR_ERR(pci->edma.reg_base); + pci->edma.reg_phys = res->start; + pci->edma.reg_size = resource_size(res); } else if (pci->atu_size >= 2 * DEFAULT_DBI_DMA_OFFSET) { pci->edma.reg_base = pci->atu_base + DEFAULT_DBI_DMA_OFFSET; + pci->edma.reg_phys = pci->atu_phys_addr + DEFAULT_DBI_DMA_OFFSET; + pci->edma.reg_size = pci->atu_size - DEFAULT_DBI_DMA_OFFSET; } } @@ -1257,3 +1261,25 @@ resource_size_t dw_pcie_parent_bus_offset(struct dw_pcie *pci, return cpu_phys_addr - reg_addr; } + +int dw_edma_get_reg_window(struct pci_epc *epc, phys_addr_t *phys, + resource_size_t *sz) +{ + struct dw_pcie_ep *ep = epc_get_drvdata(epc); + struct dw_pcie *pci; + + if (!ep) + return -ENODEV; + + pci = to_dw_pcie_from_ep(ep); + if (!pci->edma.reg_size) + return -ENODEV; + + if (phys) + *phys = pci->edma.reg_phys; + if (sz) + *sz = pci->edma.reg_size; + + return 0; +} +EXPORT_SYMBOL_GPL(dw_edma_get_reg_window); diff --git a/include/linux/dma/edma.h b/include/linux/dma/edma.h index 270b5458aecf..ffad10ff2cd6 100644 --- a/include/linux/dma/edma.h +++ b/include/linux/dma/edma.h @@ -83,6 +83,8 @@ struct dw_edma_chip { u32 flags; void __iomem *reg_base; + phys_addr_t reg_phys; + resource_size_t reg_size; u16 ll_wr_cnt; u16 ll_rd_cnt; @@ -115,4 +117,27 @@ static inline int dw_edma_remove(struct dw_edma_chip *chip) } #endif /* CONFIG_DW_EDMA */ +struct pci_epc; + +#if IS_REACHABLE(CONFIG_PCIE_DW) +/** + * dw_edma_get_reg_window - get eDMA register base and size + * @epc: the EPC device with which the eDMA instance is integrated + * @phys: the output parameter that returns the register base address + * @sz: the output parameter that returns the register space size + * + * Remote eDMA users (e.g. NTB) may need to expose the integrated DW eDMA + * register block through a memory window. This helper returns the physical + * base and size for a given DesignWare EP controller. + */ +int dw_edma_get_reg_window(struct pci_epc *epc, phys_addr_t *phys, + resource_size_t *sz); +#else +static inline int dw_edma_get_reg_window(struct pci_epc *epc, phys_addr_t *phys, + resource_size_t *sz) +{ + return -ENODEV; +} +#endif /* CONFIG_PCIE_DW */ + #endif /* _DW_EDMA_H */ -- 2.51.0
