Shift the device dependency handling to the driver core by adding
support for devlinks.
The link between the consumer device and the dmaengine device is
established by the consumer via the dma_request_chan() automatically if
the dmaengine driver supports it (create_devlink flag set).
By adding the devlink support it is ensured that the supplier can't be
removed while the consumer still uses the dmaengine. Furthermore it
ensures that the supplier driver is present and actual bound before the
consumer is uses the supplier.
Additional PM and runtime-PM dependency handling can be added easily too
by setting the required flags (not implemented by this commit).
The new create_devlink flag controlls the devlink creation to not cause
any regressions with existing dmaengine drivers. This flag can be
removed once all drivers are successfully tested to support devlinks.
Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
---
drivers/dma/dmaengine.c | 15 +++++++++++++++
include/linux/dmaengine.h | 3 +++
2 files changed, 18 insertions(+)
diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c
index 758fcd0546d8bde8e8dddc6039848feeb1e24475..e81985ab806ae87ff3aa4739fe6f6328b2587f2e 100644
--- a/drivers/dma/dmaengine.c
+++ b/drivers/dma/dmaengine.c
@@ -858,6 +858,21 @@ struct dma_chan *dma_request_chan(struct device *dev, const char *name)
/* No functional issue if it fails, users are supposed to test before use */
#endif
+ /*
+ * Devlinks between the dmaengine device and the consumer device
+ * are optional till all dmaengine drivers are converted/tested.
+ */
+ if (chan->device->create_devlink) {
+ struct device_link *dl;
+
+ dl = device_link_add(dev, chan->device->dev, DL_FLAG_AUTOREMOVE_CONSUMER);
+ if (!dl) {
+ dev_err(dev, "failed to create device link to %s\n",
+ dev_name(chan->device->dev));
+ return ERR_PTR(-EINVAL);
+ }
+ }
+
chan->name = kasprintf(GFP_KERNEL, "dma:%s", name);
if (!chan->name)
return chan;
diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h
index bb146c5ac3e4ccd7bc0afbf3b28e5b3d659ad62f..c67737a358df659f2bf050a9ccb8d23b17ceb357 100644
--- a/include/linux/dmaengine.h
+++ b/include/linux/dmaengine.h
@@ -817,6 +817,8 @@ struct dma_filter {
* DMA tansaction with no software intervention for reinitialization.
* Zero value means unlimited number of entries.
* @descriptor_reuse: a submitted transfer can be resubmitted after completion
+ * @create_devlink: create a devlink between a dma_chan_dev supplier and
+ * dma-channel consumer device
* @residue_granularity: granularity of the transfer residue reported
* by tx_status
* @device_alloc_chan_resources: allocate resources and return the
@@ -894,6 +896,7 @@ struct dma_device {
u32 max_burst;
u32 max_sg_burst;
bool descriptor_reuse;
+ bool create_devlink;
enum dma_residue_granularity residue_granularity;
int (*device_alloc_chan_resources)(struct dma_chan *chan);
--
2.47.3
On Fri, Sep 12, 2025 at 12:00:41AM +0200, Marco Felsch wrote:
> Shift the device dependency handling to the driver core by adding
> support for devlinks.
>
> The link between the consumer device and the dmaengine device is
> established by the consumer via the dma_request_chan() automatically if
> the dmaengine driver supports it (create_devlink flag set).
>
> By adding the devlink support it is ensured that the supplier can't be
> removed while the consumer still uses the dmaengine. Furthermore it
> ensures that the supplier driver is present and actual bound before the
> consumer is uses the supplier.
>
> Additional PM and runtime-PM dependency handling can be added easily too
> by setting the required flags (not implemented by this commit).
>
> The new create_devlink flag controlls the devlink creation to not cause
> any regressions with existing dmaengine drivers. This flag can be
> removed once all drivers are successfully tested to support devlinks.
>
> Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
> ---
Add previous discussion link:
https://lore.kernel.org/all/aLhUv+mtr1uZTCth@lizhi-Precision-Tower-5810/
Another thread
https://lore.kernel.org/dmaengine/20250801120007.GB4906@pendragon.ideasonboard.com/
Add Laurent Pinchart, who may instest this topic also.
Add Rob Herring, who may know why dma engine can't create dev_link default
like other provider (clk, phy, gpio ...)
> drivers/dma/dmaengine.c | 15 +++++++++++++++
> include/linux/dmaengine.h | 3 +++
> 2 files changed, 18 insertions(+)
>
> diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c
> index 758fcd0546d8bde8e8dddc6039848feeb1e24475..e81985ab806ae87ff3aa4739fe6f6328b2587f2e 100644
> --- a/drivers/dma/dmaengine.c
> +++ b/drivers/dma/dmaengine.c
> @@ -858,6 +858,21 @@ struct dma_chan *dma_request_chan(struct device *dev, const char *name)
> /* No functional issue if it fails, users are supposed to test before use */
> #endif
>
> + /*
> + * Devlinks between the dmaengine device and the consumer device
> + * are optional till all dmaengine drivers are converted/tested.
> + */
> + if (chan->device->create_devlink) {
> + struct device_link *dl;
> +
> + dl = device_link_add(dev, chan->device->dev, DL_FLAG_AUTOREMOVE_CONSUMER);
I suggest link to per channel device, instead dma engine devices.
chan->dev->device like phy drivers because some dma-engine have per channel
resources, like power domain and clocks.
Frank
> + if (!dl) {
> + dev_err(dev, "failed to create device link to %s\n",
> + dev_name(chan->device->dev));
> + return ERR_PTR(-EINVAL);
> + }
> + }
> +
> chan->name = kasprintf(GFP_KERNEL, "dma:%s", name);
> if (!chan->name)
> return chan;
> diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h
> index bb146c5ac3e4ccd7bc0afbf3b28e5b3d659ad62f..c67737a358df659f2bf050a9ccb8d23b17ceb357 100644
> --- a/include/linux/dmaengine.h
> +++ b/include/linux/dmaengine.h
> @@ -817,6 +817,8 @@ struct dma_filter {
> * DMA tansaction with no software intervention for reinitialization.
> * Zero value means unlimited number of entries.
> * @descriptor_reuse: a submitted transfer can be resubmitted after completion
> + * @create_devlink: create a devlink between a dma_chan_dev supplier and
> + * dma-channel consumer device
> * @residue_granularity: granularity of the transfer residue reported
> * by tx_status
> * @device_alloc_chan_resources: allocate resources and return the
> @@ -894,6 +896,7 @@ struct dma_device {
> u32 max_burst;
> u32 max_sg_burst;
> bool descriptor_reuse;
> + bool create_devlink;
> enum dma_residue_granularity residue_granularity;
>
> int (*device_alloc_chan_resources)(struct dma_chan *chan);
>
> --
> 2.47.3
>
On Thu, Sep 25, 2025 at 12:31:56PM -0400, Frank Li wrote:
> On Fri, Sep 12, 2025 at 12:00:41AM +0200, Marco Felsch wrote:
> > Shift the device dependency handling to the driver core by adding
> > support for devlinks.
> >
> > The link between the consumer device and the dmaengine device is
> > established by the consumer via the dma_request_chan() automatically if
> > the dmaengine driver supports it (create_devlink flag set).
> >
> > By adding the devlink support it is ensured that the supplier can't be
> > removed while the consumer still uses the dmaengine. Furthermore it
> > ensures that the supplier driver is present and actual bound before the
> > consumer is uses the supplier.
How is the latter ensured by this patch ? The link is created in
dma_request_chan() (which is called by the consumer), after successfully
obtaining the channel. I don't see how the link improves that mechanism.
> >
> > Additional PM and runtime-PM dependency handling can be added easily too
> > by setting the required flags (not implemented by this commit).
I've long thought that the DMA engine API should offer calls to "prepare"
and "unprepare" (names subject to bikeshedding) a DMA engine channel, so
that consumers can explicitly indicate when they are getting ready to
use DMA, and when they stop.
> >
> > The new create_devlink flag controlls the devlink creation to not cause
> > any regressions with existing dmaengine drivers. This flag can be
> > removed once all drivers are successfully tested to support devlinks.
> >
> > Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
> > ---
>
> Add previous discussion link:
> https://lore.kernel.org/all/aLhUv+mtr1uZTCth@lizhi-Precision-Tower-5810/
>
> Another thread
> https://lore.kernel.org/dmaengine/20250801120007.GB4906@pendragon.ideasonboard.com/
>
> Add Laurent Pinchart, who may instest this topic also.
>
> Add Rob Herring, who may know why dma engine can't create dev_link default
> like other provider (clk, phy, gpio ...)
>
>
> > drivers/dma/dmaengine.c | 15 +++++++++++++++
> > include/linux/dmaengine.h | 3 +++
> > 2 files changed, 18 insertions(+)
> >
> > diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c
> > index 758fcd0546d8bde8e8dddc6039848feeb1e24475..e81985ab806ae87ff3aa4739fe6f6328b2587f2e 100644
> > --- a/drivers/dma/dmaengine.c
> > +++ b/drivers/dma/dmaengine.c
> > @@ -858,6 +858,21 @@ struct dma_chan *dma_request_chan(struct device *dev, const char *name)
> > /* No functional issue if it fails, users are supposed to test before use */
> > #endif
> >
> > + /*
> > + * Devlinks between the dmaengine device and the consumer device
> > + * are optional till all dmaengine drivers are converted/tested.
> > + */
> > + if (chan->device->create_devlink) {
> > + struct device_link *dl;
> > +
> > + dl = device_link_add(dev, chan->device->dev, DL_FLAG_AUTOREMOVE_CONSUMER);
>
> I suggest link to per channel device, instead dma engine devices.
> chan->dev->device like phy drivers because some dma-engine have per channel
> resources, like power domain and clocks.
>
> Frank
>
> > + if (!dl) {
> > + dev_err(dev, "failed to create device link to %s\n",
> > + dev_name(chan->device->dev));
> > + return ERR_PTR(-EINVAL);
> > + }
> > + }
> > +
> > chan->name = kasprintf(GFP_KERNEL, "dma:%s", name);
> > if (!chan->name)
> > return chan;
> > diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h
> > index bb146c5ac3e4ccd7bc0afbf3b28e5b3d659ad62f..c67737a358df659f2bf050a9ccb8d23b17ceb357 100644
> > --- a/include/linux/dmaengine.h
> > +++ b/include/linux/dmaengine.h
> > @@ -817,6 +817,8 @@ struct dma_filter {
> > * DMA tansaction with no software intervention for reinitialization.
> > * Zero value means unlimited number of entries.
> > * @descriptor_reuse: a submitted transfer can be resubmitted after completion
> > + * @create_devlink: create a devlink between a dma_chan_dev supplier and
> > + * dma-channel consumer device
> > * @residue_granularity: granularity of the transfer residue reported
> > * by tx_status
> > * @device_alloc_chan_resources: allocate resources and return the
> > @@ -894,6 +896,7 @@ struct dma_device {
> > u32 max_burst;
> > u32 max_sg_burst;
> > bool descriptor_reuse;
> > + bool create_devlink;
> > enum dma_residue_granularity residue_granularity;
> >
> > int (*device_alloc_chan_resources)(struct dma_chan *chan);
> >
> > --
> > 2.47.3
> >
--
Regards,
Laurent Pinchart
On Mon, Oct 27, 2025 at 03:11:03AM +0200, Laurent Pinchart wrote:
> On Thu, Sep 25, 2025 at 12:31:56PM -0400, Frank Li wrote:
> > On Fri, Sep 12, 2025 at 12:00:41AM +0200, Marco Felsch wrote:
> > > Shift the device dependency handling to the driver core by adding
> > > support for devlinks.
> > >
> > > The link between the consumer device and the dmaengine device is
> > > established by the consumer via the dma_request_chan() automatically if
> > > the dmaengine driver supports it (create_devlink flag set).
> > >
> > > By adding the devlink support it is ensured that the supplier can't be
> > > removed while the consumer still uses the dmaengine. Furthermore it
> > > ensures that the supplier driver is present and actual bound before the
> > > consumer is uses the supplier.
>
> How is the latter ensured by this patch ? The link is created in
> dma_request_chan() (which is called by the consumer), after successfully
> obtaining the channel. I don't see how the link improves that mechanism.
>
> > >
> > > Additional PM and runtime-PM dependency handling can be added easily too
> > > by setting the required flags (not implemented by this commit).
>
> I've long thought that the DMA engine API should offer calls to "prepare"
> and "unprepare" (names subject to bikeshedding) a DMA engine channel, so
> that consumers can explicitly indicate when they are getting ready to
> use DMA, and when they stop.
This is one validate method. Maybe we set flags in dma_request_chan() to
indicate auto prepare when request chan to keep compatiblity with existed
drivers.
consumers who support prepare/unprepare can clean this flags at
dma_request_chan(). So we can smooth switch each consumer and dma-engine
driver to support this prepare/unprepare.
Frank
>
> > >
> > > The new create_devlink flag controlls the devlink creation to not cause
> > > any regressions with existing dmaengine drivers. This flag can be
> > > removed once all drivers are successfully tested to support devlinks.
> > >
> > > Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
> > > ---
> >
> > Add previous discussion link:
> > https://lore.kernel.org/all/aLhUv+mtr1uZTCth@lizhi-Precision-Tower-5810/
> >
> > Another thread
> > https://lore.kernel.org/dmaengine/20250801120007.GB4906@pendragon.ideasonboard.com/
> >
> > Add Laurent Pinchart, who may instest this topic also.
> >
> > Add Rob Herring, who may know why dma engine can't create dev_link default
> > like other provider (clk, phy, gpio ...)
> >
> >
> > > drivers/dma/dmaengine.c | 15 +++++++++++++++
> > > include/linux/dmaengine.h | 3 +++
> > > 2 files changed, 18 insertions(+)
> > >
> > > diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c
> > > index 758fcd0546d8bde8e8dddc6039848feeb1e24475..e81985ab806ae87ff3aa4739fe6f6328b2587f2e 100644
> > > --- a/drivers/dma/dmaengine.c
> > > +++ b/drivers/dma/dmaengine.c
> > > @@ -858,6 +858,21 @@ struct dma_chan *dma_request_chan(struct device *dev, const char *name)
> > > /* No functional issue if it fails, users are supposed to test before use */
> > > #endif
> > >
> > > + /*
> > > + * Devlinks between the dmaengine device and the consumer device
> > > + * are optional till all dmaengine drivers are converted/tested.
> > > + */
> > > + if (chan->device->create_devlink) {
> > > + struct device_link *dl;
> > > +
> > > + dl = device_link_add(dev, chan->device->dev, DL_FLAG_AUTOREMOVE_CONSUMER);
> >
> > I suggest link to per channel device, instead dma engine devices.
> > chan->dev->device like phy drivers because some dma-engine have per channel
> > resources, like power domain and clocks.
> >
> > Frank
> >
> > > + if (!dl) {
> > > + dev_err(dev, "failed to create device link to %s\n",
> > > + dev_name(chan->device->dev));
> > > + return ERR_PTR(-EINVAL);
> > > + }
> > > + }
> > > +
> > > chan->name = kasprintf(GFP_KERNEL, "dma:%s", name);
> > > if (!chan->name)
> > > return chan;
> > > diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h
> > > index bb146c5ac3e4ccd7bc0afbf3b28e5b3d659ad62f..c67737a358df659f2bf050a9ccb8d23b17ceb357 100644
> > > --- a/include/linux/dmaengine.h
> > > +++ b/include/linux/dmaengine.h
> > > @@ -817,6 +817,8 @@ struct dma_filter {
> > > * DMA tansaction with no software intervention for reinitialization.
> > > * Zero value means unlimited number of entries.
> > > * @descriptor_reuse: a submitted transfer can be resubmitted after completion
> > > + * @create_devlink: create a devlink between a dma_chan_dev supplier and
> > > + * dma-channel consumer device
> > > * @residue_granularity: granularity of the transfer residue reported
> > > * by tx_status
> > > * @device_alloc_chan_resources: allocate resources and return the
> > > @@ -894,6 +896,7 @@ struct dma_device {
> > > u32 max_burst;
> > > u32 max_sg_burst;
> > > bool descriptor_reuse;
> > > + bool create_devlink;
> > > enum dma_residue_granularity residue_granularity;
> > >
> > > int (*device_alloc_chan_resources)(struct dma_chan *chan);
> > >
> > > --
> > > 2.47.3
> > >
>
> --
> Regards,
>
> Laurent Pinchart
© 2016 - 2026 Red Hat, Inc.