Re: [PATCH 07/15] PCI: endpoint: Add EPC DMA channel delegation hooks
Koichiro Den <[email protected]> Tue, 17 Mar 2026 12:10:48 +0900
| Newsgroups | dev.linux.lists.ntb,org.kernel.vger.dmaengine,org.kernel.vger.linux-doc,org.kernel.vger.linux-kernel,org.kernel.vger.linux-pci |
|---|---|
| Message-ID | <kvonmb54rqnjw3tsz7crj22wse4vlgsnsbwtsaa5snrthqbj7o@fzpxggkmfj7j> |
On Thu, Mar 12, 2026 at 04:39:34PM -0400, Frank Li wrote: > On Fri, Mar 13, 2026 at 01:49:57AM +0900, Koichiro Den wrote: > > Add EPC ops and core wrappers to delegate and undelegate controller-owned > > DMA channels. > > > > The exported DMA helper needs more than a passive "delegated" bitmap: > > it must be able to reserve channels away from local users, let the > > backend perform controller-specific setup (e.g. prevent the EP from > > racing to ack the completion interrupt for delegated channels), and > > later hand the channels back as a matched lifetime operation. > > > > Signed-off-by: Koichiro Den <[email protected]> > > --- > > drivers/pci/endpoint/pci-epc-core.c | 84 +++++++++++++++++++++++++++++ > > include/linux/pci-epc.h | 19 +++++++ > > 2 files changed, 103 insertions(+) > > > > diff --git a/drivers/pci/endpoint/pci-epc-core.c b/drivers/pci/endpoint/pci-epc-core.c > > index dc6d6ab4ea1e..892f7ccbd236 100644 > > --- a/drivers/pci/endpoint/pci-epc-core.c > > +++ b/drivers/pci/endpoint/pci-epc-core.c > > @@ -197,6 +197,90 @@ int pci_epc_get_aux_resources(struct pci_epc *epc, u8 func_no, u8 vfunc_no, > > } > > EXPORT_SYMBOL_GPL(pci_epc_get_aux_resources); > > > > +/** > > + * pci_epc_delegate_dma_channels() - reserve EPC-owned DMA channels > > + * @epc: EPC device > > + * @func_no: function number > > + * @vfunc_no: virtual function number > > + * @dir: DMA channel direction > > + * @req_chans: number of channels requested > > + * @chan_ids: output array of delegated channel IDs > > + * @max_chans: capacity of @chan_ids in entries > > + * > > + * Return: > > + * * > 0: number of channels delegated > > + * * -EOPNOTSUPP: backend does not support DMA delegation > > + * * other -errno on failure > > + */ > > +int pci_epc_delegate_dma_channels(struct pci_epc *epc, u8 func_no, u8 vfunc_no, > > + enum pci_epc_aux_dma_dir dir, > > + u32 req_chans, int *chan_ids, u32 max_chans) > > Use bit mask should be simple, bit 0 for channel 0, bit 1 for channel 1 Thanks for the suggestion. I'll rework this part when respinning to simplify the interface. I also posted a follow-up to clarify the overall direction of this series: https://lore.kernel.org/linux-pci/sn67hi7kljh7cgmgodatb3naz2astlaklqfobdbxyyzgoohxqb@4nnetbhqwba4/ So far there has been no feedback beyond yours, so I'll wait a bit to see if there are further comments on this series. Thank you for revieweing, Koichiro > ... > > Frank > > +{ > > + int ret; > > + > > + if (!epc || !epc->ops) > > + return -EINVAL; > > + > > + if (!pci_epc_function_is_valid(epc, func_no, vfunc_no)) > > + return -EINVAL; > > + > > + if (!req_chans || !chan_ids || !max_chans) > > + return -EINVAL; > > + > > + if (!epc->ops->delegate_dma_channels) > > + return -EOPNOTSUPP; > > + > > + mutex_lock(&epc->lock); > > + ret = epc->ops->delegate_dma_channels(epc, func_no, vfunc_no, dir, > > + req_chans, chan_ids, max_chans); > > + mutex_unlock(&epc->lock); > > + > > + return ret; > > +} > > +EXPORT_SYMBOL_GPL(pci_epc_delegate_dma_channels); > > + > > +/** > > + * pci_epc_undelegate_dma_channels() - release previously delegated channels > > + * @epc: EPC device > > + * @func_no: function number > > + * @vfunc_no: virtual function number > > + * @dir: DMA channel direction > > + * @chan_ids: array of delegated channel IDs > > + * @num_chans: number of entries in @chan_ids > > + * > > + * Return: 0 on success, negative errno otherwise. > > + */ > > +int pci_epc_undelegate_dma_channels(struct pci_epc *epc, u8 func_no, > > + u8 vfunc_no, > > + enum pci_epc_aux_dma_dir dir, > > + const int *chan_ids, u32 num_chans) > > +{ > > + int ret; > > + > > + if (!epc || !epc->ops) > > + return -EINVAL; > > + > > + if (!pci_epc_function_is_valid(epc, func_no, vfunc_no)) > > + return -EINVAL; > > + > > + if (!num_chans) > > + return 0; > > + > > + if (!chan_ids) > > + return -EINVAL; > > + > > + if (!epc->ops->undelegate_dma_channels) > > + return -EOPNOTSUPP; > > + > > + mutex_lock(&epc->lock); > > + ret = epc->ops->undelegate_dma_channels(epc, func_no, vfunc_no, dir, > > + chan_ids, num_chans); > > + mutex_unlock(&epc->lock); > > + > > + return ret; > > +} > > +EXPORT_SYMBOL_GPL(pci_epc_undelegate_dma_channels); > > + > > /** > > * pci_epc_stop() - stop the PCI link > > * @epc: the link of the EPC device that has to be stopped > > diff --git a/include/linux/pci-epc.h b/include/linux/pci-epc.h > > index 7dd2e4d5d952..db8623b84c56 100644 > > --- a/include/linux/pci-epc.h > > +++ b/include/linux/pci-epc.h > > @@ -142,6 +142,8 @@ struct pci_epc_aux_resource { > > * @stop: ops to stop the PCI link > > * @get_features: ops to get the features supported by the EPC > > * @get_aux_resources: ops to retrieve controller-owned auxiliary resources > > + * @delegate_dma_channels: reserve controller-owned DMA channels for peer use > > + * @undelegate_dma_channels: release previously delegated DMA channels > > * @owner: the module owner containing the ops > > */ > > struct pci_epc_ops { > > @@ -176,6 +178,16 @@ struct pci_epc_ops { > > int (*get_aux_resources)(struct pci_epc *epc, u8 func_no, u8 vfunc_no, > > struct pci_epc_aux_resource *resources, > > int num_resources); > > + int (*delegate_dma_channels)(struct pci_epc *epc, u8 func_no, > > + u8 vfunc_no, > > + enum pci_epc_aux_dma_dir dir, > > + u32 req_chans, int *chan_ids, > > + u32 max_chans); > > + int (*undelegate_dma_channels)(struct pci_epc *epc, u8 func_no, > > + u8 vfunc_no, > > + enum pci_epc_aux_dma_dir dir, > > + const int *chan_ids, > > + u32 num_chans); > > struct module *owner; > > }; > > > > @@ -403,6 +415,13 @@ const struct pci_epc_features *pci_epc_get_features(struct pci_epc *epc, > > int pci_epc_get_aux_resources(struct pci_epc *epc, u8 func_no, u8 vfunc_no, > > struct pci_epc_aux_resource *resources, > > int num_resources); > > +int pci_epc_delegate_dma_channels(struct pci_epc *epc, u8 func_no, > > + u8 vfunc_no, enum pci_epc_aux_dma_dir dir, > > + u32 req_chans, int *chan_ids, u32 max_chans); > > +int pci_epc_undelegate_dma_channels(struct pci_epc *epc, u8 func_no, > > + u8 vfunc_no, > > + enum pci_epc_aux_dma_dir dir, > > + const int *chan_ids, u32 num_chans); > > enum pci_barno > > pci_epc_get_first_free_bar(const struct pci_epc_features *epc_features); > > enum pci_barno pci_epc_get_next_free_bar(const struct pci_epc_features > > -- > > 2.51.0 > >