[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Message-ID: <20260126073652.3293564-6-den@valinux.co.jp>
Date: Mon, 26 Jan 2026 16:36:52 +0900
From: Koichiro Den <den@...inux.co.jp>
To: vkoul@...nel.org,
mani@...nel.org,
Frank.Li@....com
Cc: dmaengine@...r.kernel.org,
linux-kernel@...r.kernel.org
Subject: [PATCH 5/5] dmaengine: dw-edma: Add notify-only channels support
Remote eDMA users may want to prepare descriptors on the remote side while
the local side only needs completion notifications.
Provide a lightweight per-channel notification callback infrastructure.
Signed-off-by: Koichiro Den <den@...inux.co.jp>
---
drivers/dma/dw-edma/dw-edma-core.c | 41 ++++++++++++++++++++++++++++++
drivers/dma/dw-edma/dw-edma-core.h | 4 +++
include/linux/dma/edma.h | 29 +++++++++++++++++++++
3 files changed, 74 insertions(+)
diff --git a/drivers/dma/dw-edma/dw-edma-core.c b/drivers/dma/dw-edma/dw-edma-core.c
index 910a4d516c3a..3396849d0606 100644
--- a/drivers/dma/dw-edma/dw-edma-core.c
+++ b/drivers/dma/dw-edma/dw-edma-core.c
@@ -616,6 +616,13 @@ static void dw_edma_done_interrupt(struct dw_edma_chan *chan)
struct virt_dma_desc *vd;
unsigned long flags;
+ if (chan->notify_only) {
+ if (chan->notify_cb)
+ chan->notify_cb(&chan->vc.chan, chan->notify_cb_param);
+ /* no cookie on this side, just return */
+ return;
+ }
+
spin_lock_irqsave(&chan->vc.lock, flags);
vd = vchan_next_desc(&chan->vc);
if (vd) {
@@ -834,6 +841,9 @@ static int dw_edma_channel_setup(struct dw_edma *dw, u32 wr_alloc, u32 rd_alloc)
chan->request = EDMA_REQ_NONE;
chan->status = EDMA_ST_IDLE;
chan->irq_mode = DW_EDMA_CH_IRQ_DEFAULT;
+ chan->notify_cb = NULL;
+ chan->notify_cb_param = NULL;
+ chan->notify_only = false;
spin_lock_init(&chan->poll_lock);
INIT_DELAYED_WORK(&chan->poll_work, dw_edma_poll_work);
@@ -1115,6 +1125,37 @@ int dw_edma_remove(struct dw_edma_chip *chip)
}
EXPORT_SYMBOL_GPL(dw_edma_remove);
+int dw_edma_chan_register_notify(struct dma_chan *dchan,
+ void (*cb)(struct dma_chan *chan, void *data),
+ void *data)
+{
+ struct dw_edma_chan *chan;
+
+ if (!dchan || !dchan->device ||
+ dchan->device->device_config != dw_edma_device_config)
+ return -ENODEV;
+
+ chan = dchan2dw_edma_chan(dchan);
+
+ /*
+ * Reject the operation while the channel is active or has queued
+ * descriptors.
+ */
+ scoped_guard(spinlock_irqsave, &chan->vc.lock) {
+ if (chan->request != EDMA_REQ_NONE ||
+ chan->status != EDMA_ST_IDLE ||
+ !list_empty(&chan->vc.desc_submitted) ||
+ !list_empty(&chan->vc.desc_issued))
+ return -EBUSY;
+ }
+
+ chan->notify_cb = cb;
+ chan->notify_cb_param = data;
+ chan->notify_only = !!cb;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(dw_edma_chan_register_notify);
+
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("Synopsys DesignWare eDMA controller core driver");
MODULE_AUTHOR("Gustavo Pimentel <gustavo.pimentel@...opsys.com>");
diff --git a/drivers/dma/dw-edma/dw-edma-core.h b/drivers/dma/dw-edma/dw-edma-core.h
index 560a2d2fea86..d5ee8330a6cb 100644
--- a/drivers/dma/dw-edma/dw-edma-core.h
+++ b/drivers/dma/dw-edma/dw-edma-core.h
@@ -84,6 +84,10 @@ struct dw_edma_chan {
enum dw_edma_ch_irq_mode irq_mode;
+ void (*notify_cb)(struct dma_chan *chan, void *data);
+ void *notify_cb_param;
+ bool notify_only;
+
struct delayed_work poll_work;
spinlock_t poll_lock;
diff --git a/include/linux/dma/edma.h b/include/linux/dma/edma.h
index d2938a88c02d..d616d22286d1 100644
--- a/include/linux/dma/edma.h
+++ b/include/linux/dma/edma.h
@@ -131,6 +131,27 @@ struct dw_edma_chip {
#if IS_REACHABLE(CONFIG_DW_EDMA)
int dw_edma_probe(struct dw_edma_chip *chip);
int dw_edma_remove(struct dw_edma_chip *chip);
+
+/**
+ * dw_edma_chan_register_notify - register completion notification callback
+ * @chan: DMA channel obtained from dma_request_channel()
+ * @cb: callback invoked when a completion is detected on @chan (NULL to
+ * unregister)
+ * @data: opaque pointer passed back to @cb
+ *
+ * This is a lightweight notification mechanism intended for channels whose
+ * descriptors are managed externally (e.g. remote eDMA). When enabled, the
+ * local dw-edma instance does not perform cookie accounting for completions,
+ * because the corresponding descriptor is not tracked locally.
+ *
+ * The callback may be invoked from atomic context and must not sleep.
+ *
+ * Return: 0 on success, -ENODEV if @chan is not a dw-edma channel,
+ * -EBUSY if the channel is active or has queued descriptors.
+ */
+int dw_edma_chan_register_notify(struct dma_chan *chan,
+ void (*cb)(struct dma_chan *chan, void *data),
+ void *data);
#else
static inline int dw_edma_probe(struct dw_edma_chip *chip)
{
@@ -141,6 +162,14 @@ static inline int dw_edma_remove(struct dw_edma_chip *chip)
{
return 0;
}
+
+static inline int dw_edma_chan_register_notify(struct dma_chan *chan,
+ void (*cb)(struct dma_chan *chan,
+ void *data),
+ void *data)
+{
+ return -ENODEV;
+}
#endif /* CONFIG_DW_EDMA */
#endif /* _DW_EDMA_H */
--
2.51.0
Powered by blists - more mailing lists