[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20260204145440.950609-5-den@valinux.co.jp>
Date: Wed, 4 Feb 2026 23:54:32 +0900
From: Koichiro Den <den@...inux.co.jp>
To: vkoul@...nel.org,
mani@...nel.org,
Frank.Li@....com,
jingoohan1@...il.com,
lpieralisi@...nel.org,
kwilczynski@...nel.org,
robh@...nel.org,
bhelgaas@...gle.com
Cc: dmaengine@...r.kernel.org,
linux-pci@...r.kernel.org,
linux-kernel@...r.kernel.org
Subject: [PATCH v3 04/11] dmaengine: Add selfirq callback registration API
Some DMA controllers can generate an interrupt by software writing to a
register, without updating the normal interrupt status bits. This can be
used as a doorbell mechanism when the DMA engine is remotely programmed,
or for self-tests.
Add an optional per-DMA-device API to register/unregister callbacks for
such "selfirq" events. Providers may invoke these callbacks from their
interrupt handler when they detect an emulated interrupt.
Callbacks are invoked in hardirq context and must not sleep.
Signed-off-by: Koichiro Den <den@...inux.co.jp>
---
include/linux/dmaengine.h | 70 +++++++++++++++++++++++++++++++++++++++
1 file changed, 70 insertions(+)
diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h
index 71bc2674567f..9c6194e8bfe1 100644
--- a/include/linux/dmaengine.h
+++ b/include/linux/dmaengine.h
@@ -785,6 +785,17 @@ struct dma_filter {
const struct dma_slave_map *map;
};
+/**
+ * dma_selfirq_fn - callback for emulated/self IRQ events
+ * @dev: DMA device invoking the callback
+ * @data: opaque pointer provided at registration time
+ *
+ * Providers may invoke this callback from their interrupt handler when an
+ * emulated interrupt ("selfirq") might have occurred. The callback runs in
+ * hardirq context and must not sleep.
+ */
+typedef void (*dma_selfirq_fn)(struct dma_device *dev, void *data);
+
/**
* struct dma_device - info on the entity supplying DMA services
* @ref: reference is taken and put every time a channel is allocated or freed
@@ -853,6 +864,10 @@ struct dma_filter {
* or an error code
* @device_synchronize: Synchronizes the termination of a transfers to the
* current context.
+ * @device_register_selfirq: optional callback registration for
+ * emulated/self IRQ events
+ * @device_unregister_selfirq: unregister previously registered selfirq
+ * callback
* @device_tx_status: poll for transaction completion, the optional
* txstate parameter can be supplied with a pointer to get a
* struct with auxiliary transfer status information, otherwise the call
@@ -951,6 +966,11 @@ struct dma_device {
int (*device_terminate_all)(struct dma_chan *chan);
void (*device_synchronize)(struct dma_chan *chan);
+ int (*device_register_selfirq)(struct dma_device *dev,
+ dma_selfirq_fn fn, void *data);
+ void (*device_unregister_selfirq)(struct dma_device *dev,
+ dma_selfirq_fn fn, void *data);
+
enum dma_status (*device_tx_status)(struct dma_chan *chan,
dma_cookie_t cookie,
struct dma_tx_state *txstate);
@@ -1197,6 +1217,56 @@ static inline void dmaengine_synchronize(struct dma_chan *chan)
chan->device->device_synchronize(chan);
}
+/**
+ * dmaengine_register_selfirq() - Register a callback for emulated/self IRQ
+ * events
+ * @dev: DMA device
+ * @fn: callback invoked from the provider's IRQ handler
+ * @data: opaque callback data
+ *
+ * Some DMA controllers can raise an interrupt by software writing to a
+ * register without updating normal status bits. Providers may call
+ * registered callbacks from their interrupt handler when such events may
+ * have occurred.
+ * Callbacks are invoked in hardirq context and must not sleep.
+ *
+ * Return: 0 on success, -EOPNOTSUPP if unsupported, -EINVAL on bad args,
+ * or provider-specific -errno.
+ */
+static inline int dmaengine_register_selfirq(struct dma_device *dev,
+ dma_selfirq_fn fn, void *data)
+{
+ if (!dev || !fn)
+ return -EINVAL;
+ if (!dev->device_register_selfirq)
+ return -EOPNOTSUPP;
+
+ return dev->device_register_selfirq(dev, fn, data);
+}
+
+/**
+ * dmaengine_unregister_selfirq() - Unregister a previously registered
+ * selfirq callback
+ * @dev: DMA device
+ * @fn: callback pointer used at registration time
+ * @data: opaque pointer used at registration time
+ *
+ * Unregister a callback previously registered via
+ * dmaengine_register_selfirq(). Providers may synchronize against
+ * in-flight callbacks, therefore this function may sleep and must not be
+ * called from atomic context.
+ */
+static inline void dmaengine_unregister_selfirq(struct dma_device *dev,
+ dma_selfirq_fn fn, void *data)
+{
+ if (!dev || !fn)
+ return;
+ if (!dev->device_unregister_selfirq)
+ return;
+
+ dev->device_unregister_selfirq(dev, fn, data);
+}
+
/**
* dmaengine_terminate_sync() - Terminate all active DMA transfers
* @chan: The channel for which to terminate the transfers
--
2.51.0
Powered by blists - more mailing lists