Re: [PATCH v7 5/9] PCI: dwc: ep: Expose integrated eDMA resources via EPC aux-resource API

Koichiro Den <[email protected]>
Newsgroups dev.linux.lists.ntb,org.infradead.lists.linux-arm-kernel,org.infradead.lists.linux-rockchip,org.kernel.vger.linux-kernel,org.kernel.vger.linux-pci
Message-ID <lryeu64nxxp34mx7re3w4jy2anfie52xtxcxa4ff6dulzcwhjd@ce567iui6piz>
On Mon, Feb 16, 2026 at 03:12:53PM +0100, Niklas Cassel wrote:
> On Mon, Feb 16, 2026 at 01:38:43AM +0900, Koichiro Den wrote:
> > Implement the EPC aux-resource API for DesignWare endpoint controllers
> > with integrated eDMA.
> > 
> > Report:
> >   - DMA controller MMIO window (PCI_EPC_AUX_DMA_CTRL_MMIO)
> >   - interrupt-emulation doorbell register (PCI_EPC_AUX_DOORBELL_MMIO),
> >     including its Linux IRQ
> >   - per-channel LL descriptor regions (PCI_EPC_AUX_DMA_CHAN_DESC)
> > 
> > If the DMA controller MMIO window is already exposed via a
> > platform-owned fixed BAR subregion, also provide the BAR number and
> > offset so EPF drivers can reuse it without reprogramming the BAR.
> > 
> > Signed-off-by: Koichiro Den <[email protected]>
> > ---
> >  .../pci/controller/dwc/pcie-designware-ep.c   | 149 ++++++++++++++++++
> >  1 file changed, 149 insertions(+)
> > 
> > diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c
> > index 7e7844ff0f7e..ffd2797b7b81 100644
> > --- a/drivers/pci/controller/dwc/pcie-designware-ep.c
> > +++ b/drivers/pci/controller/dwc/pcie-designware-ep.c
> > @@ -808,6 +808,154 @@ dw_pcie_ep_get_features(struct pci_epc *epc, u8 func_no, u8 vfunc_no)
> >  	return ep->ops->get_features(ep);
> >  }
> >  
> > +static const struct pci_epc_bar_rsvd_region *
> > +dw_pcie_ep_find_bar_rsvd_region(struct dw_pcie_ep *ep,
> > +				enum pci_epc_bar_rsvd_region_type type,
> > +				enum pci_barno *bar,
> > +				resource_size_t *bar_offset)
> > +{
> > +	const struct pci_epc_features *features;
> > +	const struct pci_epc_bar_desc *bar_desc;
> > +	const struct pci_epc_bar_rsvd_region *r;
> > +	int i, j;
> > +
> > +	if (!ep->ops->get_features)
> > +		return NULL;
> > +
> > +	features = ep->ops->get_features(ep);
> > +	if (!features)
> > +		return NULL;
> > +
> > +	for (i = BAR_0; i <= BAR_5; i++) {
> > +		bar_desc = &features->bar[i];
> > +
> > +		if (!bar_desc->nr_rsvd_regions || !bar_desc->rsvd_regions)
> > +			continue;
> > +
> > +		for (j = 0; j < bar_desc->nr_rsvd_regions; j++) {
> > +			r = &bar_desc->rsvd_regions[j];
> > +
> > +			if (r->type != type)
> > +				continue;
> > +
> > +			if (bar)
> > +				*bar = i;
> > +			if (bar_offset)
> > +				*bar_offset = r->offset;
> > +			return r;
> > +		}
> > +	}
> > +
> > +	return NULL;
> > +}
> > +
> > +static int
> > +dw_pcie_ep_get_aux_resources(struct pci_epc *epc, u8 func_no, u8 vfunc_no,
> > +			     struct pci_epc_aux_resource *resources,
> > +			     int num_resources)
> > +{
> > +	struct dw_pcie_ep *ep = epc_get_drvdata(epc);
> > +	struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
> > +	const struct pci_epc_bar_rsvd_region *rsvd;
> > +	struct dw_edma_chip *edma = &pci->edma;
> > +	enum pci_barno dma_ctrl_bar = NO_BAR;
> > +	int ll_cnt = 0, needed, idx = 0;
> > +	resource_size_t db_offset = edma->db_offset;
> > +	resource_size_t dma_ctrl_bar_offset = 0;
> > +	resource_size_t dma_reg_size;
> > +	unsigned int i;
> > +
> > +	if (!pci->edma_reg_size)
> > +		return 0;
> > +
> > +	dma_reg_size = pci->edma_reg_size;
> > +
> > +	for (i = 0; i < edma->ll_wr_cnt; i++)
> > +		if (edma->ll_region_wr[i].sz)
> > +			ll_cnt++;
> > +
> > +	for (i = 0; i < edma->ll_rd_cnt; i++)
> > +		if (edma->ll_region_rd[i].sz)
> > +			ll_cnt++;
> > +
> > +	needed = 1 + ll_cnt + (db_offset != ~0 ? 1 : 0);
> > +
> > +	/* Count query mode */
> > +	if (!resources || !num_resources)
> > +		return needed;
> > +
> > +	if (num_resources < needed)
> > +		return -ENOSPC;
> > +
> > +	rsvd = dw_pcie_ep_find_bar_rsvd_region(ep,
> > +					       PCI_EPC_BAR_RSVD_DMA_CTRL_MMIO,
> > +					       &dma_ctrl_bar,
> > +					       &dma_ctrl_bar_offset);
> > +	if (rsvd && rsvd->size < dma_reg_size)
> > +		dma_reg_size = rsvd->size;
> > +
> > +	/* DMA register block */
> > +	resources[idx++] = (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,
> > +	};
> > +
> > +	/*
> > +	 * For interrupt-emulation doorbells, report a standalone resource
> > +	 * instead of bundling it into the DMA controller MMIO resource.
> > +	 */
> > +	if (db_offset != ~0) {
> > +		if (dma_reg_size < sizeof(u32) ||
> > +		    db_offset > dma_reg_size - sizeof(u32))
> 
> In your other patch, you used:
> 
> 	if (size_add(offset, sizeof(u32)) > epf->bar[bar].size)
> 
> For consistency, do you perhaps want to use the same here?
> 
> size_add(db_offset, sizeof(u32)) > dma_reg_size ?

db_offset and dma_reg_size are resource_size_t, not size_t. resource_size_t can
be wider than size_t on some 32-bit builds with CONFIG_PHYS_ADDR_T_64BIT, so
using size_add() would potentially introduce a narrowing conversion. For that
reason, I avoided it.

If that would be preferable, I'm happy to switch this part to something like:

        if (db_offset != ~0) {
                if (range_end_overflows_t(resource_size_t, db_offset,
                                          sizeof(u32), dma_reg_size))
                        return -EINVAL;

or alternatively use check_add_overflow().

Best regards,
Koichiro

> 
> 
> 
> 
> Kind regards,
> Niklas
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.