Re: [PATCH v6 6/6] PCI: dwc: Expose endpoint DMA resources
Frank Li <[email protected]> Tue, 4 Aug 2026 11:29:12 -0500
| Newsgroups | org.kernel.vger.linux-pci,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <anITWMXfOBcFAOhs@SMW015318> |
On Tue, Aug 04, 2026 at 12:38:55PM +0900, Koichiro Den wrote: > Expose the DesignWare endpoint-integrated eDMA register window, logical > DMA channels, and linked-list descriptor memories through the EPC > auxiliary resource API. This lets endpoint functions decide which > channels to publish to the host. > > When the DMA register window is already visible through a reserved BAR > region, report its BAR and offset. Otherwise report it as a normal > physical resource so an endpoint function can map it. DMA channel > resources carry hardware channel selectors and refer to linked-list > descriptor memory by ID. > > Expose DMA controller and channel resources only after the local DW eDMA > provider has been registered, and only expose channels whose linked-list > descriptor memory is available. The interrupt-emulation doorbell remains > reported when the local DW eDMA provider is registered and its offset is > valid, even if linked-list resources are unavailable. DWC non-LL exposure > needs a metadata ABI and host parser extension, so leave it unsupported > for now. Reject VF auxiliary resource queries because the > RC-programmable DWC eDMA/HDMA register window is assigned to a PF BAR > only. > > Signed-off-by: Koichiro Den <[email protected]> > --- Reviewed-by: Frank Li <[email protected]> > Changes in v6: > - Use the same DMA resource state for bounds checking and array filling. > (Sashiko) > - Move this patch after the delegation support so every advertised DMA > channel is immediately usable. (Sashiko) > > .../pci/controller/dwc/pcie-designware-ep.c | 138 +++++++++++++++++- > 1 file changed, 130 insertions(+), 8 deletions(-) > > diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c > index 8c1ac9e3c517..440311e2bed9 100644 > --- a/drivers/pci/controller/dwc/pcie-designware-ep.c > +++ b/drivers/pci/controller/dwc/pcie-designware-ep.c > @@ -858,6 +858,22 @@ dw_pcie_ep_find_bar_rsvd_region(struct dw_pcie_ep *ep, > return NULL; > } > > +static bool dw_pcie_ep_has_edma_ll_resources(struct dw_edma_chip *edma, > + u16 ll_wr_cnt, u16 ll_rd_cnt) > +{ > + unsigned int i; > + > + for (i = 0; i < ll_wr_cnt; i++) > + if (!edma->ll_region_wr[i].sz) > + return false; > + > + for (i = 0; i < ll_rd_cnt; i++) > + if (!edma->ll_region_rd[i].sz) > + return false; > + > + return true; > +} > + > static int dw_pcie_ep_check_edma_vfunc(u8 vfunc_no) > { > /* > @@ -877,14 +893,30 @@ dw_pcie_ep_get_aux_resources_count(struct pci_epc *epc, u8 func_no, > struct dw_pcie_ep *ep = epc_get_drvdata(epc); > struct dw_pcie *pci = to_dw_pcie_from_ep(ep); > struct dw_edma_chip *edma = &pci->edma; > + u16 ll_wr_cnt, ll_rd_cnt; > + int count = 0; > + int ret; > > if (!pci->edma_reg_size) > return 0; > > - if (edma->db_offset == ~0) > + ret = dw_pcie_ep_check_edma_vfunc(vfunc_no); > + if (ret) > + return ret; > + > + if (!edma->dw) > return 0; > > - return 1; > + ll_wr_cnt = edma->ll_wr_cnt; > + ll_rd_cnt = edma->ll_rd_cnt; > + > + if (dw_pcie_ep_has_edma_ll_resources(edma, ll_wr_cnt, ll_rd_cnt)) > + count += 1 + 2 * (ll_wr_cnt + ll_rd_cnt); > + > + if (edma->db_offset != ~0) > + count++; > + > + return count; > } > > static int > @@ -897,14 +929,34 @@ dw_pcie_ep_get_aux_resources(struct pci_epc *epc, u8 func_no, u8 vfunc_no, > const struct pci_epc_bar_rsvd_region *rsvd; > struct dw_edma_chip *edma = &pci->edma; > enum pci_barno dma_ctrl_bar = NO_BAR; > - resource_size_t db_offset = edma->db_offset; > + resource_size_t db_offset; > resource_size_t dma_ctrl_bar_offset = 0; > resource_size_t dma_reg_size; > - int count; > + u16 ll_wr_cnt, ll_rd_cnt; > + bool has_ll; > + unsigned int i; > + int count, ret; > > - count = dw_pcie_ep_get_aux_resources_count(epc, func_no, vfunc_no); > - if (count < 0) > - return count; > + if (!pci->edma_reg_size) > + return 0; > + > + ret = dw_pcie_ep_check_edma_vfunc(vfunc_no); > + if (ret) > + return ret; > + > + if (!edma->dw) > + return 0; > + > + /* Keep the bounds check and fill on the same provider view. */ > + ll_wr_cnt = edma->ll_wr_cnt; > + ll_rd_cnt = edma->ll_rd_cnt; > + db_offset = edma->db_offset; > + has_ll = dw_pcie_ep_has_edma_ll_resources(edma, ll_wr_cnt, > + ll_rd_cnt); > + > + count = db_offset != ~0; > + if (has_ll) > + count += 1 + 2 * (ll_wr_cnt + ll_rd_cnt); > > if (num_resources < count) > return -ENOSPC; > @@ -921,6 +973,76 @@ dw_pcie_ep_get_aux_resources(struct pci_epc *epc, u8 func_no, u8 vfunc_no, > if (rsvd && rsvd->size < dma_reg_size) > dma_reg_size = rsvd->size; > > + count = 0; > + if (has_ll) { > + resources[count++] = (struct pci_epc_aux_resource) { > + .type = PCI_EPC_AUX_DMA_CTRL_MMIO, > + .phys_addr = pci->edma_reg_phys, > + .size = dma_reg_size, > + .bar = dma_ctrl_bar, > + .bar_offset = dma_ctrl_bar_offset, > + .u.dma_ctrl = { > + .reg_layout = PCI_EPC_AUX_DMA_REG_LAYOUT_DW_EDMA, > + .reg_layout_data = edma->mf, > + .ep_to_rc_ch_cnt = ll_wr_cnt, > + .rc_to_ep_ch_cnt = ll_rd_cnt, > + }, > + }; > + > + for (i = 0; i < ll_wr_cnt; i++) { > + struct dw_edma_region *ll = &edma->ll_region_wr[i]; > + u16 desc_mem_id = i; > + > + resources[count++] = (struct pci_epc_aux_resource) { > + .type = PCI_EPC_AUX_DMA_CHAN, > + .bar = NO_BAR, > + .u.dma_chan = { > + .dir = PCI_EPC_AUX_DMA_EP_TO_RC, > + .hw_ch = i, > + .desc_mem_id = desc_mem_id, > + }, > + }; > + > + resources[count++] = (struct pci_epc_aux_resource) { > + .type = PCI_EPC_AUX_DMA_DESC_MEM, > + .phys_addr = ll->paddr, > + .size = ll->sz, > + .bar = NO_BAR, > + .u.dma_desc = { > + .id = desc_mem_id, > + }, > + }; > + } > + > + for (i = 0; i < ll_rd_cnt; i++) { > + struct dw_edma_region *ll = &edma->ll_region_rd[i]; > + u16 desc_mem_id = ll_wr_cnt + i; > + > + resources[count++] = (struct pci_epc_aux_resource) { > + .type = PCI_EPC_AUX_DMA_CHAN, > + .bar = NO_BAR, > + .u.dma_chan = { > + .dir = PCI_EPC_AUX_DMA_RC_TO_EP, > + .hw_ch = i, > + .desc_mem_id = desc_mem_id, > + }, > + }; > + > + resources[count++] = (struct pci_epc_aux_resource) { > + .type = PCI_EPC_AUX_DMA_DESC_MEM, > + .phys_addr = ll->paddr, > + .size = ll->sz, > + .bar = NO_BAR, > + .u.dma_desc = { > + .id = desc_mem_id, > + }, > + }; > + } > + } > + > + if (db_offset == ~0) > + return 0; > + > /* > * For interrupt-emulation doorbells, report a standalone resource > * instead of bundling it into the DMA controller MMIO resource. > @@ -929,7 +1051,7 @@ dw_pcie_ep_get_aux_resources(struct pci_epc *epc, u8 func_no, u8 vfunc_no, > sizeof(u32), dma_reg_size)) > return -EINVAL; > > - resources[0] = (struct pci_epc_aux_resource) { > + resources[count] = (struct pci_epc_aux_resource) { > .type = PCI_EPC_AUX_DOORBELL_MMIO, > .phys_addr = pci->edma_reg_phys + db_offset, > .size = sizeof(u32), > -- > 2.51.0 >