* [RFC PATCH 0/1] dmaengine: introduce dmaengine_bh_wq and bh helpers
@ 2026-01-08 8:03 Allen Pais
2026-01-08 8:03 ` [RFC PATCH 1/1] " Allen Pais
2026-07-27 20:28 ` [PATCH v2 00/64] dmaengine: migrate channel tasklets to WQ_BH Allen Pais
0 siblings, 2 replies; 82+ messages in thread
From: Allen Pais @ 2026-01-08 8:03 UTC (permalink / raw)
To: vkoul; +Cc: arnd, kees, dmaengine, linux-kernel, Allen Pais
Hi Vinod,
This series contains a single patch that introduces a dedicated dmaengine
bottom-half workqueue along with per-channel BH helpers. The change grew
out of the earlier discussion about moving DMA tasklet usage over to a
BH workqueue and I took some time to get the semantics right
before sending this upstream:
Earlier discussion:
https://lore.kernel.org/all/2e9257af-c123-406b-a189-eaebeecc1d71@app.fastmail.com/
I’m intentionally sending only the foundational helper patch for review
to avoid spamming the list. The full set of driver conversions is already
available here: https://github.com/allenpais/dmaengine-bh-work
Once the base helper patch is reviewed, I will follow up with the
remaining driver conversions.
This series is based on v6.19-rc4 (f10c325a345fef0a688a2bcdfab1540d1c924148).
Thanks,
Allen
Allen Pais (1):
dmaengine: introduce dmaengine_bh_wq and bh helpers
drivers/dma/amd/qdma/qdma.c | 1 +
drivers/dma/bcm2835-dma.c | 2 +-
drivers/dma/dmaengine.c | 109 +++++++++++++++++-
.../dma/dw-axi-dmac/dw-axi-dmac-platform.c | 2 +-
drivers/dma/dw-edma/dw-edma-core.c | 2 +-
drivers/dma/hisi_dma.c | 2 +-
drivers/dma/img-mdc-dma.c | 2 +-
drivers/dma/imx-sdma.c | 2 +-
drivers/dma/k3dma.c | 2 +-
drivers/dma/loongson1-apb-dma.c | 2 +-
drivers/dma/mediatek/mtk-cqdma.c | 2 +-
drivers/dma/mediatek/mtk-hsdma.c | 2 +-
drivers/dma/mediatek/mtk-uart-apdma.c | 4 +-
drivers/dma/owl-dma.c | 2 +-
drivers/dma/pxa_dma.c | 2 +-
drivers/dma/qcom/bam_dma.c | 4 +-
drivers/dma/qcom/qcom_adm.c | 2 +-
drivers/dma/sa11x0-dma.c | 2 +-
drivers/dma/sprd-dma.c | 2 +-
drivers/dma/sun6i-dma.c | 2 +-
drivers/dma/tegra186-gpc-dma.c | 2 +-
drivers/dma/tegra210-adma.c | 2 +-
drivers/dma/ti/k3-udma.c | 8 +-
drivers/dma/ti/omap-dma.c | 2 +-
drivers/dma/virt-dma.c | 6 +-
drivers/dma/virt-dma.h | 8 +-
include/linux/dmaengine.h | 50 ++++++++
27 files changed, 189 insertions(+), 39 deletions(-)
--
2.43.0
^ permalink raw reply [flat|nested] 82+ messages in thread
* [RFC PATCH 1/1] dmaengine: introduce dmaengine_bh_wq and bh helpers
2026-01-08 8:03 [RFC PATCH 0/1] dmaengine: introduce dmaengine_bh_wq and bh helpers Allen Pais
@ 2026-01-08 8:03 ` Allen Pais
2026-01-08 10:26 ` Arnd Bergmann
2026-07-27 20:28 ` [PATCH v2 00/64] dmaengine: migrate channel tasklets to WQ_BH Allen Pais
1 sibling, 1 reply; 82+ messages in thread
From: Allen Pais @ 2026-01-08 8:03 UTC (permalink / raw)
To: vkoul; +Cc: arnd, kees, dmaengine, linux-kernel, Allen Pais
Create a dedicated dmaengine bottom-half workqueue (WQ_BH | WQ_PERCPU)
and provide helper APIs for queue/flush/cancel of BH work items. Add
per-channel BH helpers in dma_chan so drivers can schedule a BH callback
without maintaining their own tasklets.
Convert virt-dma to use the new per-channel BH helpers and remove the
per-channel tasklet. Update existing drivers that only need tasklet
teardown to use dma_chan_kill_bh().
This provides a common BH execution path for dmaengine and establishes
the base for converting remaining DMA tasklets to workqueue-based BHs.
Signed-off-by: Allen Pais <allen.lkml@gmail.com>
---
drivers/dma/amd/qdma/qdma.c | 1 +
drivers/dma/bcm2835-dma.c | 2 +-
drivers/dma/dmaengine.c | 109 +++++++++++++++++-
.../dma/dw-axi-dmac/dw-axi-dmac-platform.c | 2 +-
drivers/dma/dw-edma/dw-edma-core.c | 2 +-
drivers/dma/hisi_dma.c | 2 +-
drivers/dma/img-mdc-dma.c | 2 +-
drivers/dma/imx-sdma.c | 2 +-
drivers/dma/k3dma.c | 2 +-
drivers/dma/loongson1-apb-dma.c | 2 +-
drivers/dma/mediatek/mtk-cqdma.c | 2 +-
drivers/dma/mediatek/mtk-hsdma.c | 2 +-
drivers/dma/mediatek/mtk-uart-apdma.c | 4 +-
drivers/dma/owl-dma.c | 2 +-
drivers/dma/pxa_dma.c | 2 +-
drivers/dma/qcom/bam_dma.c | 4 +-
drivers/dma/qcom/qcom_adm.c | 2 +-
drivers/dma/sa11x0-dma.c | 2 +-
drivers/dma/sprd-dma.c | 2 +-
drivers/dma/sun6i-dma.c | 2 +-
drivers/dma/tegra186-gpc-dma.c | 2 +-
drivers/dma/tegra210-adma.c | 2 +-
drivers/dma/ti/k3-udma.c | 8 +-
drivers/dma/ti/omap-dma.c | 2 +-
drivers/dma/virt-dma.c | 6 +-
drivers/dma/virt-dma.h | 8 +-
include/linux/dmaengine.h | 50 ++++++++
27 files changed, 189 insertions(+), 39 deletions(-)
diff --git a/drivers/dma/amd/qdma/qdma.c b/drivers/dma/amd/qdma/qdma.c
index 8fb2d5e1df20..b57f8ebf2446 100644
--- a/drivers/dma/amd/qdma/qdma.c
+++ b/drivers/dma/amd/qdma/qdma.c
@@ -13,6 +13,7 @@
#include <linux/platform_device.h>
#include <linux/platform_data/amd_qdma.h>
#include <linux/regmap.h>
+#include <linux/interrupt.h>
#include "qdma.h"
diff --git a/drivers/dma/bcm2835-dma.c b/drivers/dma/bcm2835-dma.c
index 321748e2983e..08a206cfbb76 100644
--- a/drivers/dma/bcm2835-dma.c
+++ b/drivers/dma/bcm2835-dma.c
@@ -846,7 +846,7 @@ static void bcm2835_dma_free(struct bcm2835_dmadev *od)
list_for_each_entry_safe(c, next, &od->ddev.channels,
vc.chan.device_node) {
list_del(&c->vc.chan.device_node);
- tasklet_kill(&c->vc.task);
+ dma_chan_kill_bh(&c->vc.chan);
}
dma_unmap_page_attrs(od->ddev.dev, od->zero_page, PAGE_SIZE,
diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c
index ca13cd39330b..d3df4e943d37 100644
--- a/drivers/dma/dmaengine.c
+++ b/drivers/dma/dmaengine.c
@@ -54,6 +54,7 @@
#include <linux/of_dma.h>
#include <linux/mempool.h>
#include <linux/numa.h>
+#include <linux/workqueue.h>
#include "dmaengine.h"
@@ -61,6 +62,7 @@ static DEFINE_MUTEX(dma_list_mutex);
static DEFINE_IDA(dma_ida);
static LIST_HEAD(dma_device_list);
static long dmaengine_ref_count;
+static struct workqueue_struct *dmaengine_bh_wq;
/* --- debugfs implementation --- */
#ifdef CONFIG_DEBUG_FS
@@ -1425,6 +1427,92 @@ static void dmaengine_destroy_unmap_pool(void)
}
}
+static void dmaengine_destroy_bh_wq(void)
+{
+ if (!dmaengine_bh_wq)
+ return;
+
+ destroy_workqueue(dmaengine_bh_wq);
+ dmaengine_bh_wq = NULL;
+}
+
+bool dmaengine_queue_bh_work(struct work_struct *work)
+{
+ if (WARN_ON(!dmaengine_bh_wq))
+ return false;
+
+ return queue_work(dmaengine_bh_wq, work);
+}
+EXPORT_SYMBOL_GPL(dmaengine_queue_bh_work);
+
+void dmaengine_flush_bh_work(struct work_struct *work)
+{
+ if (!work)
+ return;
+
+ flush_work(work);
+}
+EXPORT_SYMBOL_GPL(dmaengine_flush_bh_work);
+
+void dmaengine_cancel_bh_work_sync(struct work_struct *work)
+{
+ if (!work)
+ return;
+
+ cancel_work_sync(work);
+}
+EXPORT_SYMBOL_GPL(dmaengine_cancel_bh_work_sync);
+
+static void dma_chan_bh_entry(struct work_struct *work)
+{
+ struct dma_chan *chan = container_of(work, struct dma_chan, bh_work);
+ dma_chan_bh_work_fn fn = READ_ONCE(chan->bh_work_fn);
+
+ if (fn)
+ fn(chan);
+}
+
+void dma_chan_init_bh(struct dma_chan *chan, dma_chan_bh_work_fn fn)
+{
+ if (WARN_ON(!fn))
+ return;
+
+ if (WARN_ON(chan->bh_work_initialized))
+ return;
+
+ chan->bh_work_fn = fn;
+ INIT_WORK(&chan->bh_work, dma_chan_bh_entry);
+ chan->bh_work_initialized = true;
+}
+EXPORT_SYMBOL_GPL(dma_chan_init_bh);
+
+bool dma_chan_schedule_bh(struct dma_chan *chan)
+{
+ if (WARN_ON(!chan->bh_work_initialized))
+ return false;
+
+ return dmaengine_queue_bh_work(&chan->bh_work);
+}
+EXPORT_SYMBOL_GPL(dma_chan_schedule_bh);
+
+void dma_chan_flush_bh(struct dma_chan *chan)
+{
+ if (!chan->bh_work_initialized)
+ return;
+
+ dmaengine_flush_bh_work(&chan->bh_work);
+}
+EXPORT_SYMBOL_GPL(dma_chan_flush_bh);
+
+void dma_chan_kill_bh(struct dma_chan *chan)
+{
+ if (!chan->bh_work_initialized)
+ return;
+
+ dmaengine_cancel_bh_work_sync(&chan->bh_work);
+}
+EXPORT_SYMBOL_GPL(dma_chan_kill_bh);
+
static int __init dmaengine_init_unmap_pool(void)
{
int i;
@@ -1621,15 +1709,28 @@ EXPORT_SYMBOL_GPL(dma_run_dependencies);
static int __init dma_bus_init(void)
{
- int err = dmaengine_init_unmap_pool();
+ int err;
+ dmaengine_bh_wq = alloc_workqueue("dmaengine_bh",
+ WQ_BH | WQ_PERCPU, 0);
+ if (!dmaengine_bh_wq)
+ return -ENOMEM;
+
+ err = dmaengine_init_unmap_pool();
if (err)
- return err;
+ goto err_destroy_wq;
err = class_register(&dma_devclass);
- if (!err)
- dmaengine_debugfs_init();
+ if (err)
+ goto err_destroy_pool;
+ dmaengine_debugfs_init();
+ return 0;
+
+err_destroy_pool:
+ dmaengine_destroy_unmap_pool();
+err_destroy_wq:
+ dmaengine_destroy_bh_wq();
return err;
}
arch_initcall(dma_bus_init);
diff --git a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c
index b23536645ff7..42018b21d2ab 100644
--- a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c
+++ b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c
@@ -1649,7 +1649,7 @@ static void dw_remove(struct platform_device *pdev)
list_for_each_entry_safe(chan, _chan, &dw->dma.channels,
vc.chan.device_node) {
list_del(&chan->vc.chan.device_node);
- tasklet_kill(&chan->vc.task);
+ dma_chan_kill_bh(&chan->vc.chan);
}
}
diff --git a/drivers/dma/dw-edma/dw-edma-core.c b/drivers/dma/dw-edma/dw-edma-core.c
index 8e5f7defa6b6..378650bcc430 100644
--- a/drivers/dma/dw-edma/dw-edma-core.c
+++ b/drivers/dma/dw-edma/dw-edma-core.c
@@ -1015,7 +1015,7 @@ int dw_edma_remove(struct dw_edma_chip *chip)
dma_async_device_unregister(&dw->dma);
list_for_each_entry_safe(chan, _chan, &dw->dma.channels,
vc.chan.device_node) {
- tasklet_kill(&chan->vc.task);
+ dma_chan_kill_bh(&chan->vc.chan);
list_del(&chan->vc.chan.device_node);
}
diff --git a/drivers/dma/hisi_dma.c b/drivers/dma/hisi_dma.c
index 25a4134be36b..a15491945329 100644
--- a/drivers/dma/hisi_dma.c
+++ b/drivers/dma/hisi_dma.c
@@ -720,7 +720,7 @@ static void hisi_dma_disable_qps(struct hisi_dma_dev *hdma_dev)
for (i = 0; i < hdma_dev->chan_num; i++) {
hisi_dma_disable_qp(hdma_dev, i);
- tasklet_kill(&hdma_dev->chan[i].vc.task);
+ dma_chan_kill_bh(&hdma_dev->chan[i].vc.chan);
}
}
diff --git a/drivers/dma/img-mdc-dma.c b/drivers/dma/img-mdc-dma.c
index fd55bcd060ab..d4f6d839acca 100644
--- a/drivers/dma/img-mdc-dma.c
+++ b/drivers/dma/img-mdc-dma.c
@@ -1031,7 +1031,7 @@ static void mdc_dma_remove(struct platform_device *pdev)
devm_free_irq(&pdev->dev, mchan->irq, mchan);
- tasklet_kill(&mchan->vc.task);
+ dma_chan_kill_bh(&mchan->vc.chan);
}
pm_runtime_disable(&pdev->dev);
diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c
index ed9e56de5a9b..9cbc95fbb4ee 100644
--- a/drivers/dma/imx-sdma.c
+++ b/drivers/dma/imx-sdma.c
@@ -2427,7 +2427,7 @@ static void sdma_remove(struct platform_device *pdev)
for (i = 0; i < MAX_DMA_CHANNELS; i++) {
struct sdma_channel *sdmac = &sdma->channel[i];
- tasklet_kill(&sdmac->vc.task);
+ dma_chan_kill_bh(&sdmac->vc.chan);
sdma_free_chan_resources(&sdmac->vc.chan);
}
diff --git a/drivers/dma/k3dma.c b/drivers/dma/k3dma.c
index 0f9cd7815f88..36d5df545b57 100644
--- a/drivers/dma/k3dma.c
+++ b/drivers/dma/k3dma.c
@@ -981,7 +981,7 @@ static void k3_dma_remove(struct platform_device *op)
list_for_each_entry_safe(c, cn, &d->slave.channels, vc.chan.device_node) {
list_del(&c->vc.chan.device_node);
- tasklet_kill(&c->vc.task);
+ dma_chan_kill_bh(&c->vc.chan);
}
tasklet_kill(&d->task);
clk_disable_unprepare(d->clk);
diff --git a/drivers/dma/loongson1-apb-dma.c b/drivers/dma/loongson1-apb-dma.c
index 255fe7eca212..49a78ea1514f 100644
--- a/drivers/dma/loongson1-apb-dma.c
+++ b/drivers/dma/loongson1-apb-dma.c
@@ -552,7 +552,7 @@ static void ls1x_dma_chan_remove(struct ls1x_dma *dma)
if (chan->vc.chan.device == &dma->ddev) {
list_del(&chan->vc.chan.device_node);
- tasklet_kill(&chan->vc.task);
+ dma_chan_kill_bh(&chan->vc.chan);
}
}
}
diff --git a/drivers/dma/mediatek/mtk-cqdma.c b/drivers/dma/mediatek/mtk-cqdma.c
index 9f0c41ca7770..3ba54df12bae 100644
--- a/drivers/dma/mediatek/mtk-cqdma.c
+++ b/drivers/dma/mediatek/mtk-cqdma.c
@@ -895,7 +895,7 @@ static void mtk_cqdma_remove(struct platform_device *pdev)
vc = &cqdma->vc[i];
list_del(&vc->vc.chan.device_node);
- tasklet_kill(&vc->vc.task);
+ dma_chan_kill_bh(&vc->vc.chan);
}
/* disable interrupt */
diff --git a/drivers/dma/mediatek/mtk-hsdma.c b/drivers/dma/mediatek/mtk-hsdma.c
index fa77bb24a430..0bbf865de24b 100644
--- a/drivers/dma/mediatek/mtk-hsdma.c
+++ b/drivers/dma/mediatek/mtk-hsdma.c
@@ -1020,7 +1020,7 @@ static void mtk_hsdma_remove(struct platform_device *pdev)
vc = &hsdma->vc[i];
list_del(&vc->vc.chan.device_node);
- tasklet_kill(&vc->vc.task);
+ dma_chan_kill_bh(&vc->vc.chan);
}
/* Disable DMA interrupt */
diff --git a/drivers/dma/mediatek/mtk-uart-apdma.c b/drivers/dma/mediatek/mtk-uart-apdma.c
index 08e15177427b..257b9b77cc57 100644
--- a/drivers/dma/mediatek/mtk-uart-apdma.c
+++ b/drivers/dma/mediatek/mtk-uart-apdma.c
@@ -312,7 +312,7 @@ static void mtk_uart_apdma_free_chan_resources(struct dma_chan *chan)
free_irq(c->irq, chan);
- tasklet_kill(&c->vc.task);
+ dma_chan_kill_bh(&c->vc.chan);
vchan_free_chan_resources(&c->vc);
@@ -463,7 +463,7 @@ static void mtk_uart_apdma_free(struct mtk_uart_apdmadev *mtkd)
struct mtk_chan, vc.chan.device_node);
list_del(&c->vc.chan.device_node);
- tasklet_kill(&c->vc.task);
+ dma_chan_kill_bh(&c->vc.chan);
}
}
diff --git a/drivers/dma/owl-dma.c b/drivers/dma/owl-dma.c
index 57cec757d8f5..4e6ebf990688 100644
--- a/drivers/dma/owl-dma.c
+++ b/drivers/dma/owl-dma.c
@@ -1055,7 +1055,7 @@ static inline void owl_dma_free(struct owl_dma *od)
list_for_each_entry_safe(vchan,
next, &od->dma.channels, vc.chan.device_node) {
list_del(&vchan->vc.chan.device_node);
- tasklet_kill(&vchan->vc.task);
+ dma_chan_kill_bh(&vchan->vc.chan);
}
}
diff --git a/drivers/dma/pxa_dma.c b/drivers/dma/pxa_dma.c
index 249296389771..634b723e4891 100644
--- a/drivers/dma/pxa_dma.c
+++ b/drivers/dma/pxa_dma.c
@@ -1218,7 +1218,7 @@ static void pxad_free_channels(struct dma_device *dmadev)
list_for_each_entry_safe(c, cn, &dmadev->channels,
vc.chan.device_node) {
list_del(&c->vc.chan.device_node);
- tasklet_kill(&c->vc.task);
+ dma_chan_kill_bh(&c->vc.chan);
}
}
diff --git a/drivers/dma/qcom/bam_dma.c b/drivers/dma/qcom/bam_dma.c
index 2cf060174795..6ec82adb89ce 100644
--- a/drivers/dma/qcom/bam_dma.c
+++ b/drivers/dma/qcom/bam_dma.c
@@ -1377,7 +1377,7 @@ static int bam_dma_probe(struct platform_device *pdev)
dma_async_device_unregister(&bdev->common);
err_bam_channel_exit:
for (i = 0; i < bdev->num_channels; i++)
- tasklet_kill(&bdev->channels[i].vc.task);
+ dma_chan_kill_bh(&bdev->channels[i].vc.chan);
err_tasklet_kill:
tasklet_kill(&bdev->task);
err_disable_clk:
@@ -1403,7 +1403,7 @@ static void bam_dma_remove(struct platform_device *pdev)
for (i = 0; i < bdev->num_channels; i++) {
bam_dma_terminate_all(&bdev->channels[i].vc.chan);
- tasklet_kill(&bdev->channels[i].vc.task);
+ dma_chan_kill_bh(&bdev->channels[i].vc.chan);
if (!bdev->channels[i].fifo_virt)
continue;
diff --git a/drivers/dma/qcom/qcom_adm.c b/drivers/dma/qcom/qcom_adm.c
index 6be54fddcee1..0f9e906bd463 100644
--- a/drivers/dma/qcom/qcom_adm.c
+++ b/drivers/dma/qcom/qcom_adm.c
@@ -919,7 +919,7 @@ static void adm_dma_remove(struct platform_device *pdev)
/* mask IRQs for this channel/EE pair */
writel(0, adev->regs + ADM_CH_RSLT_CONF(achan->id, adev->ee));
- tasklet_kill(&adev->channels[i].vc.task);
+ dma_chan_kill_bh(&adev->channels[i].vc.chan);
adm_terminate_all(&adev->channels[i].vc.chan);
}
diff --git a/drivers/dma/sa11x0-dma.c b/drivers/dma/sa11x0-dma.c
index dc1a9a05252e..42940079efbf 100644
--- a/drivers/dma/sa11x0-dma.c
+++ b/drivers/dma/sa11x0-dma.c
@@ -893,7 +893,7 @@ static void sa11x0_dma_free_channels(struct dma_device *dmadev)
list_for_each_entry_safe(c, cn, &dmadev->channels, vc.chan.device_node) {
list_del(&c->vc.chan.device_node);
- tasklet_kill(&c->vc.task);
+ dma_chan_kill_bh(&c->vc.chan);
kfree(c);
}
}
diff --git a/drivers/dma/sprd-dma.c b/drivers/dma/sprd-dma.c
index 6207e0b185e1..5124fe0a93bf 100644
--- a/drivers/dma/sprd-dma.c
+++ b/drivers/dma/sprd-dma.c
@@ -1253,7 +1253,7 @@ static void sprd_dma_remove(struct platform_device *pdev)
list_for_each_entry_safe(c, cn, &sdev->dma_dev.channels,
vc.chan.device_node) {
list_del(&c->vc.chan.device_node);
- tasklet_kill(&c->vc.task);
+ dma_chan_kill_bh(&c->vc.chan);
}
of_dma_controller_free(pdev->dev.of_node);
diff --git a/drivers/dma/sun6i-dma.c b/drivers/dma/sun6i-dma.c
index 2215ff877bf7..6b3ab99272a5 100644
--- a/drivers/dma/sun6i-dma.c
+++ b/drivers/dma/sun6i-dma.c
@@ -1073,7 +1073,7 @@ static inline void sun6i_dma_free(struct sun6i_dma_dev *sdev)
struct sun6i_vchan *vchan = &sdev->vchans[i];
list_del(&vchan->vc.chan.device_node);
- tasklet_kill(&vchan->vc.task);
+ dma_chan_kill_bh(&vchan->vc.chan);
}
}
diff --git a/drivers/dma/tegra186-gpc-dma.c b/drivers/dma/tegra186-gpc-dma.c
index 4d6fe0efa76e..3b9dc64eb635 100644
--- a/drivers/dma/tegra186-gpc-dma.c
+++ b/drivers/dma/tegra186-gpc-dma.c
@@ -1279,7 +1279,7 @@ static void tegra_dma_free_chan_resources(struct dma_chan *dc)
tegra_dma_terminate_all(dc);
synchronize_irq(tdc->irq);
- tasklet_kill(&tdc->vc.task);
+ dma_chan_kill_bh(&tdc->vc.chan);
tdc->config_init = false;
tdc->slave_id = -1;
tdc->sid_dir = DMA_TRANS_NONE;
diff --git a/drivers/dma/tegra210-adma.c b/drivers/dma/tegra210-adma.c
index d0e8bb27a03b..67ccb1d48361 100644
--- a/drivers/dma/tegra210-adma.c
+++ b/drivers/dma/tegra210-adma.c
@@ -793,7 +793,7 @@ static void tegra_adma_free_chan_resources(struct dma_chan *dc)
tegra_adma_terminate_all(dc);
vchan_free_chan_resources(&tdc->vc);
- tasklet_kill(&tdc->vc.task);
+ dma_chan_kill_bh(&tdc->vc.chan);
free_irq(tdc->irq, tdc);
pm_runtime_put(tdc2dev(tdc));
diff --git a/drivers/dma/ti/k3-udma.c b/drivers/dma/ti/k3-udma.c
index aa2dc762140f..89dd7926705d 100644
--- a/drivers/dma/ti/k3-udma.c
+++ b/drivers/dma/ti/k3-udma.c
@@ -4045,9 +4045,9 @@ static void udma_desc_pre_callback(struct virt_dma_chan *vc,
* This tasklet handles the completion of a DMA descriptor by
* calling its callback and freeing it.
*/
-static void udma_vchan_complete(struct tasklet_struct *t)
+static void udma_vchan_complete(struct dma_chan *chan)
{
- struct virt_dma_chan *vc = from_tasklet(vc, t, task);
+ struct virt_dma_chan *vc = to_virt_chan(chan);
struct virt_dma_desc *vd, *_vd;
struct dmaengine_desc_callback cb;
LIST_HEAD(head);
@@ -4112,7 +4112,7 @@ static void udma_free_chan_resources(struct dma_chan *chan)
}
vchan_free_chan_resources(&uc->vc);
- tasklet_kill(&uc->vc.task);
+ dma_chan_kill_bh(&uc->vc.chan);
bcdma_free_bchan_resources(uc);
udma_free_tx_resources(uc);
@@ -5628,7 +5628,7 @@ static int udma_probe(struct platform_device *pdev)
return -ENOMEM;
vchan_init(&uc->vc, &ud->ddev);
/* Use custom vchan completion handling */
- tasklet_setup(&uc->vc.task, udma_vchan_complete);
+ dma_chan_init_bh(&uc->vc.chan, udma_vchan_complete);
init_completion(&uc->teardown_completed);
INIT_DELAYED_WORK(&uc->tx_drain.work, udma_check_tx_completion);
}
diff --git a/drivers/dma/ti/omap-dma.c b/drivers/dma/ti/omap-dma.c
index 8c023c6e623a..f6aee92071e2 100644
--- a/drivers/dma/ti/omap-dma.c
+++ b/drivers/dma/ti/omap-dma.c
@@ -1521,7 +1521,7 @@ static void omap_dma_free(struct omap_dmadev *od)
struct omap_chan, vc.chan.device_node);
list_del(&c->vc.chan.device_node);
- tasklet_kill(&c->vc.task);
+ dma_chan_kill_bh(&c->vc.chan);
kfree(c);
}
}
diff --git a/drivers/dma/virt-dma.c b/drivers/dma/virt-dma.c
index 7961172a780d..c311397f3bd7 100644
--- a/drivers/dma/virt-dma.c
+++ b/drivers/dma/virt-dma.c
@@ -80,9 +80,9 @@ EXPORT_SYMBOL_GPL(vchan_find_desc);
* This tasklet handles the completion of a DMA descriptor by
* calling its callback and freeing it.
*/
-static void vchan_complete(struct tasklet_struct *t)
+static void vchan_complete(struct dma_chan *chan)
{
- struct virt_dma_chan *vc = from_tasklet(vc, t, task);
+ struct virt_dma_chan *vc = to_virt_chan(chan);
struct virt_dma_desc *vd, *_vd;
struct dmaengine_desc_callback cb;
LIST_HEAD(head);
@@ -131,7 +131,7 @@ void vchan_init(struct virt_dma_chan *vc, struct dma_device *dmadev)
INIT_LIST_HEAD(&vc->desc_completed);
INIT_LIST_HEAD(&vc->desc_terminated);
- tasklet_setup(&vc->task, vchan_complete);
+ dma_chan_init_bh(&vc->chan, vchan_complete);
vc->chan.device = dmadev;
list_add_tail(&vc->chan.device_node, &dmadev->channels);
diff --git a/drivers/dma/virt-dma.h b/drivers/dma/virt-dma.h
index 59d9eabc8b67..5299fb7367ca 100644
--- a/drivers/dma/virt-dma.h
+++ b/drivers/dma/virt-dma.h
@@ -8,7 +8,6 @@
#define VIRT_DMA_H
#include <linux/dmaengine.h>
-#include <linux/interrupt.h>
#include "dmaengine.h"
@@ -21,7 +20,6 @@ struct virt_dma_desc {
struct virt_dma_chan {
struct dma_chan chan;
- struct tasklet_struct task;
void (*desc_free)(struct virt_dma_desc *);
spinlock_t lock;
@@ -106,7 +104,7 @@ static inline void vchan_cookie_complete(struct virt_dma_desc *vd)
vd, cookie);
list_add_tail(&vd->node, &vc->desc_completed);
- tasklet_schedule(&vc->task);
+ dma_chan_schedule_bh(&vc->chan);
}
/**
@@ -137,7 +135,7 @@ static inline void vchan_cyclic_callback(struct virt_dma_desc *vd)
struct virt_dma_chan *vc = to_virt_chan(vd->tx.chan);
vc->cyclic = vd;
- tasklet_schedule(&vc->task);
+ dma_chan_schedule_bh(&vc->chan);
}
/**
@@ -223,7 +221,7 @@ static inline void vchan_synchronize(struct virt_dma_chan *vc)
LIST_HEAD(head);
unsigned long flags;
- tasklet_kill(&vc->task);
+ dma_chan_kill_bh(&vc->chan);
spin_lock_irqsave(&vc->lock, flags);
diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h
index 99efe2b9b4ea..00ad92a73c3b 100644
--- a/include/linux/dmaengine.h
+++ b/include/linux/dmaengine.h
@@ -12,6 +12,7 @@
#include <linux/scatterlist.h>
#include <linux/bitmap.h>
#include <linux/types.h>
+#include <linux/workqueue.h>
#include <asm/page.h>
/**
@@ -295,6 +296,10 @@ enum dma_desc_metadata_mode {
DESC_METADATA_ENGINE = BIT(1),
};
+struct dma_chan;
+
+typedef void (*dma_chan_bh_work_fn)(struct dma_chan *chan);
+
/**
* struct dma_chan_percpu - the per-CPU part of struct dma_chan
* @memcpy_count: transaction counter
@@ -334,6 +339,9 @@ struct dma_router {
* @router: pointer to the DMA router structure
* @route_data: channel specific data for the router
* @private: private data for certain client-channel associations
+ * @bh_work: bottom-half work item stored per-channel
+ * @bh_work_fn: callback executed when @bh_work runs
+ * @bh_work_initialized: indicates whether @bh_work has been initialized
*/
struct dma_chan {
struct dma_device *device;
@@ -359,6 +367,9 @@ struct dma_chan {
void *route_data;
void *private;
+ struct work_struct bh_work;
+ dma_chan_bh_work_fn bh_work_fn;
+ bool bh_work_initialized;
};
/**
@@ -1528,6 +1539,14 @@ struct dma_chan *devm_dma_request_chan(struct device *dev, const char *name);
void dma_release_channel(struct dma_chan *chan);
int dma_get_slave_caps(struct dma_chan *chan, struct dma_slave_caps *caps);
+bool dmaengine_queue_bh_work(struct work_struct *work);
+void dmaengine_flush_bh_work(struct work_struct *work);
+void dmaengine_cancel_bh_work_sync(struct work_struct *work);
+
+void dma_chan_init_bh(struct dma_chan *chan, dma_chan_bh_work_fn fn);
+bool dma_chan_schedule_bh(struct dma_chan *chan);
+void dma_chan_flush_bh(struct dma_chan *chan);
+void dma_chan_kill_bh(struct dma_chan *chan);
#else
static inline struct dma_chan *dma_find_channel(enum dma_transaction_type tx_type)
{
@@ -1575,6 +1594,37 @@ static inline int dma_get_slave_caps(struct dma_chan *chan,
{
return -ENXIO;
}
+
+static inline bool dmaengine_queue_bh_work(struct work_struct *work)
+{
+ return false;
+}
+
+static inline void dmaengine_flush_bh_work(struct work_struct *work)
+{
+}
+
+static inline void dmaengine_cancel_bh_work_sync(struct work_struct *work)
+{
+}
+
+static inline void dma_chan_init_bh(struct dma_chan *chan,
+ dma_chan_bh_work_fn fn)
+{
+}
+
+static inline bool dma_chan_schedule_bh(struct dma_chan *chan)
+{
+ return false;
+}
+
+static inline void dma_chan_flush_bh(struct dma_chan *chan)
+{
+}
+
+static inline void dma_chan_kill_bh(struct dma_chan *chan)
+{
+}
#endif
static inline int dmaengine_desc_set_reuse(struct dma_async_tx_descriptor *tx)
--
2.43.0
^ permalink raw reply related [flat|nested] 82+ messages in thread
* Re: [RFC PATCH 1/1] dmaengine: introduce dmaengine_bh_wq and bh helpers
2026-01-08 8:03 ` [RFC PATCH 1/1] " Allen Pais
@ 2026-01-08 10:26 ` Arnd Bergmann
2026-01-08 19:22 ` Allen
0 siblings, 1 reply; 82+ messages in thread
From: Arnd Bergmann @ 2026-01-08 10:26 UTC (permalink / raw)
To: Allen, Vinod Koul; +Cc: Kees Cook, dmaengine, linux-kernel
On Thu, Jan 8, 2026, at 09:03, Allen Pais wrote:
> Create a dedicated dmaengine bottom-half workqueue (WQ_BH | WQ_PERCPU)
> and provide helper APIs for queue/flush/cancel of BH work items. Add
> per-channel BH helpers in dma_chan so drivers can schedule a BH callback
> without maintaining their own tasklets.
>
> Convert virt-dma to use the new per-channel BH helpers and remove the
> per-channel tasklet. Update existing drivers that only need tasklet
> teardown to use dma_chan_kill_bh().
>
> This provides a common BH execution path for dmaengine and establishes
> the base for converting remaining DMA tasklets to workqueue-based BHs.
>
> Signed-off-by: Allen Pais <allen.lkml@gmail.com>
Hi Allen,
I agree that the dmaengine code should stop using tasklets here,
but I think the last time we discussed this, we ended up not
going with work queues as a replacement because of the inherent
scheduling overhead.
The use of this tasklet is to invoke the dmaengine_desc_callback(),
which at the moment clearly expects to be called from tasklet
context, but in most cases probably should just be called from
hardirq context, e.g. when all it does is to call complete()
or wake_up(). In particular, I assume this breaks any console
driver that tries to use DMA to send output to a UART.
It may make sense to take the portions of your patch that
abstract the dmaengine drivers away from tasklet and have them
interact with shared functions, but I don't think we should
introduce a workqueue at all here, at least not until we
have identified dmaengine users that want workqueue behavior.
If your goal is to reduce the number of tasklet uses in the
kernel, I would suggest taking this on at one level higher up
the stack: assume that dma_async_tx_descriptor->callback()
is always called at tasklet context, and introduce an
alternative mechanism that is called from hardirq context,
then change over each user of dma_async_tx_descriptor to
use the hardirq method instead of the tasklet method, if
at all possible.
Arnd
^ permalink raw reply [flat|nested] 82+ messages in thread
* Re: [RFC PATCH 1/1] dmaengine: introduce dmaengine_bh_wq and bh helpers
2026-01-08 10:26 ` Arnd Bergmann
@ 2026-01-08 19:22 ` Allen
2026-01-09 16:42 ` Arnd Bergmann
0 siblings, 1 reply; 82+ messages in thread
From: Allen @ 2026-01-08 19:22 UTC (permalink / raw)
To: Arnd Bergmann; +Cc: Vinod Koul, Kees Cook, dmaengine, linux-kernel
> > Create a dedicated dmaengine bottom-half workqueue (WQ_BH | WQ_PERCPU)
> > and provide helper APIs for queue/flush/cancel of BH work items. Add
> > per-channel BH helpers in dma_chan so drivers can schedule a BH callback
> > without maintaining their own tasklets.
> >
> > Convert virt-dma to use the new per-channel BH helpers and remove the
> > per-channel tasklet. Update existing drivers that only need tasklet
> > teardown to use dma_chan_kill_bh().
> >
> > This provides a common BH execution path for dmaengine and establishes
> > the base for converting remaining DMA tasklets to workqueue-based BHs.
> >
> > Signed-off-by: Allen Pais <allen.lkml@gmail.com>
>
> Hi Allen,
>
> I agree that the dmaengine code should stop using tasklets here,
> but I think the last time we discussed this, we ended up not
> going with work queues as a replacement because of the inherent
> scheduling overhead.
>
> The use of this tasklet is to invoke the dmaengine_desc_callback(),
> which at the moment clearly expects to be called from tasklet
> context, but in most cases probably should just be called from
> hardirq context, e.g. when all it does is to call complete()
> or wake_up(). In particular, I assume this breaks any console
> driver that tries to use DMA to send output to a UART.
>
> It may make sense to take the portions of your patch that
> abstract the dmaengine drivers away from tasklet and have them
> interact with shared functions, but I don't think we should
> introduce a workqueue at all here, at least not until we
> have identified dmaengine users that want workqueue behavior.
>
> If your goal is to reduce the number of tasklet uses in the
> kernel, I would suggest taking this on at one level higher up
> the stack: assume that dma_async_tx_descriptor->callback()
> is always called at tasklet context, and introduce an
> alternative mechanism that is called from hardirq context,
> then change over each user of dma_async_tx_descriptor to
> use the hardirq method instead of the tasklet method, if
> at all possible.
Arnd,
Thanks for the feedback. My intent with WQ_BH was to keep callbacks in
softirq/BH context, but I agree the scheduling overhead and existing tasklet
assumptions are valid concerns.
I can re-spin the RFC to drop the workqueue entirely and keep
tasklet semantics,
while still abstracting tasklet handling into dmaengine helpers so drivers no
longer directly manipulate tasklets. That keeps
dmaengine_desc_callback_invoke()
in tasklet context and avoids breaking DMA users that rely on that behavior.
A hardirq callback path feels like a larger API change, so I’d
prefer to handle
that as a separate follow‑up (e.g. explicit hardirq callback/flag + user
migration where safe). Thoughts?
Here’s a diff on top of v6.19-rc4 that does exactly this.
diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c
index ca13cd39330b..611047763b35 100644
--- a/drivers/dma/dmaengine.c
+++ b/drivers/dma/dmaengine.c
@@ -1425,6 +1425,48 @@ static void dmaengine_destroy_unmap_pool(void)
}
}
+static void dma_chan_bh_entry(struct tasklet_struct *t)
+{
+ struct dma_chan *chan = from_tasklet(chan, t, bh_tasklet);
+ dma_chan_bh_work_fn fn = READ_ONCE(chan->bh_work_fn);
+
+ if (fn)
+ fn(chan);
+}
+
+void dma_chan_init_bh(struct dma_chan *chan, dma_chan_bh_work_fn fn)
+{
+ if (WARN_ON(!fn))
+ return;
+
+ if (WARN_ON(chan->bh_work_initialized))
+ return;
+
+ chan->bh_work_fn = fn;
+ tasklet_setup(&chan->bh_tasklet, dma_chan_bh_entry);
+ chan->bh_work_initialized = true;
+}
+EXPORT_SYMBOL_GPL(dma_chan_init_bh);
+
+bool dma_chan_schedule_bh(struct dma_chan *chan)
+{
+ if (WARN_ON(!chan->bh_work_initialized))
+ return false;
+
+ tasklet_schedule(&chan->bh_tasklet);
+ return true;
+}
+EXPORT_SYMBOL_GPL(dma_chan_schedule_bh);
+
+void dma_chan_kill_bh(struct dma_chan *chan)
+{
+ if (!chan->bh_work_initialized)
+ return;
+
+ tasklet_kill(&chan->bh_tasklet);
+}
+EXPORT_SYMBOL_GPL(dma_chan_kill_bh);
+
static int __init dmaengine_init_unmap_pool(void)
{
int i;
diff --git a/drivers/dma/virt-dma.c b/drivers/dma/virt-dma.c
index 7961172a780d..3d3fadb81f8d 100644
--- a/drivers/dma/virt-dma.c
+++ b/drivers/dma/virt-dma.c
@@ -77,12 +77,12 @@ struct virt_dma_desc *vchan_find_desc(struct
virt_dma_chan *vc,
EXPORT_SYMBOL_GPL(vchan_find_desc);
/*
- * This tasklet handles the completion of a DMA descriptor by
- * calling its callback and freeing it.
+ * This bottom-half handler completes a DMA descriptor by invoking its
+ * callback and freeing it.
*/
-static void vchan_complete(struct tasklet_struct *t)
+static void vchan_complete(struct dma_chan *chan)
{
- struct virt_dma_chan *vc = from_tasklet(vc, t, task);
+ struct virt_dma_chan *vc = to_virt_chan(chan);
struct virt_dma_desc *vd, *_vd;
struct dmaengine_desc_callback cb;
LIST_HEAD(head);
@@ -131,7 +131,7 @@ void vchan_init(struct virt_dma_chan *vc, struct
dma_device *dmadev)
INIT_LIST_HEAD(&vc->desc_completed);
INIT_LIST_HEAD(&vc->desc_terminated);
- tasklet_setup(&vc->task, vchan_complete);
+ dma_chan_init_bh(&vc->chan, vchan_complete);
vc->chan.device = dmadev;
list_add_tail(&vc->chan.device_node, &dmadev->channels);
diff --git a/drivers/dma/virt-dma.h b/drivers/dma/virt-dma.h
index 59d9eabc8b67..75c6fee2f70e 100644
--- a/drivers/dma/virt-dma.h
+++ b/drivers/dma/virt-dma.h
@@ -8,8 +8,6 @@
#define VIRT_DMA_H
#include <linux/dmaengine.h>
-#include <linux/interrupt.h>
-
#include "dmaengine.h"
struct virt_dma_desc {
@@ -21,7 +19,6 @@ struct virt_dma_desc {
struct virt_dma_chan {
struct dma_chan chan;
- struct tasklet_struct task;
void (*desc_free)(struct virt_dma_desc *);
spinlock_t lock;
@@ -106,7 +103,7 @@ static inline void vchan_cookie_complete(struct
virt_dma_desc *vd)
vd, cookie);
list_add_tail(&vd->node, &vc->desc_completed);
- tasklet_schedule(&vc->task);
+ dma_chan_schedule_bh(&vc->chan);
}
@@ -137,7 +134,7 @@ static inline void vchan_cyclic_callback(struct
virt_dma_desc *vd)
struct virt_dma_chan *vc = to_virt_chan(vd->tx.chan);
vc->cyclic = vd;
- tasklet_schedule(&vc->task);
+ dma_chan_schedule_bh(&vc->chan);
}
@@ -223,7 +220,7 @@ static inline void vchan_synchronize(struct
virt_dma_chan *vc)
LIST_HEAD(head);
unsigned long flags;
- tasklet_kill(&vc->task);
+ dma_chan_kill_bh(&vc->chan);
spin_lock_irqsave(&vc->lock, flags);
diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h
index 99efe2b9b4ea..2d2c8ab3764d 100644
--- a/include/linux/dmaengine.h
+++ b/include/linux/dmaengine.h
@@ -12,6 +12,7 @@
#include <linux/scatterlist.h>
#include <linux/bitmap.h>
#include <linux/types.h>
+#include <linux/interrupt.h>
#include <asm/page.h>
@@ -295,6 +296,10 @@ enum dma_desc_metadata_mode {
DESC_METADATA_ENGINE = BIT(1),
};
+struct dma_chan;
+
+typedef void (*dma_chan_bh_work_fn)(struct dma_chan *chan);
+
@@ -334,6 +339,9 @@ struct dma_router {
* @router: pointer to the DMA router structure
* @route_data: channel specific data for the router
* @private: private data for certain client-channel associations
+ * @bh_tasklet: bottom-half tasklet stored per-channel
+ * @bh_work_fn: callback executed when @bh_tasklet runs
+ * @bh_work_initialized: indicates whether @bh_tasklet has been initialized
*/
struct dma_chan {
@@ -359,6 +367,9 @@ struct dma_chan {
void *route_data;
void *private;
+ struct tasklet_struct bh_tasklet;
+ dma_chan_bh_work_fn bh_work_fn;
+ bool bh_work_initialized;
};
@@ -1528,6 +1539,9 @@ struct dma_chan *devm_dma_request_chan(struct
device *dev, const char *name);
void dma_release_channel(struct dma_chan *chan);
int dma_get_slave_caps(struct dma_chan *chan, struct dma_slave_caps *caps);
+void dma_chan_init_bh(struct dma_chan *chan, dma_chan_bh_work_fn fn);
+bool dma_chan_schedule_bh(struct dma_chan *chan);
+void dma_chan_kill_bh(struct dma_chan *chan);
#else
@@ -1575,6 +1589,20 @@ static inline int dma_get_slave_caps(struct
dma_chan *chan,
{
return -ENXIO;
}
+
+static inline void dma_chan_init_bh(struct dma_chan *chan,
+ dma_chan_bh_work_fn fn)
+{
+}
+
+static inline bool dma_chan_schedule_bh(struct dma_chan *chan)
+{
+ return false;
+}
+
+static inline void dma_chan_kill_bh(struct dma_chan *chan)
+{
+}
#endif
>
> Arnd
--
- Allen
^ permalink raw reply [flat|nested] 82+ messages in thread
* Re: [RFC PATCH 1/1] dmaengine: introduce dmaengine_bh_wq and bh helpers
2026-01-08 19:22 ` Allen
@ 2026-01-09 16:42 ` Arnd Bergmann
2026-01-12 22:20 ` Allen
0 siblings, 1 reply; 82+ messages in thread
From: Arnd Bergmann @ 2026-01-09 16:42 UTC (permalink / raw)
To: Allen; +Cc: Vinod Koul, Kees Cook, dmaengine, linux-kernel
On Thu, Jan 8, 2026, at 20:22, Allen wrote:
>
> Thanks for the feedback. My intent with WQ_BH was to keep callbacks in
> softirq/BH context, but I agree the scheduling overhead and existing tasklet
> assumptions are valid concerns.
Hi Allen,
Sorry about missing the bit about WQ_BH, I forgot about the details
of or previous discussion and this is pretty much what I had
suggested last time,
> I can re-spin the RFC to drop the workqueue entirely and keep
> tasklet semantics,
> while still abstracting tasklet handling into dmaengine helpers so drivers no
> longer directly manipulate tasklets. That keeps
> dmaengine_desc_callback_invoke()
> in tasklet context and avoids breaking DMA users that rely on that behavior.
It's probably fine to do both, but a series of two patches (first introduce
the per-channel API, then move it over to WQ_BH) may be slightly
clearer here.
I'm not sure why the dmaengine_*_bh_wq() functions are exported
interfaces, as far as I can tell, you use them only internally
in the dma_chan_*_bh() functions, so making them static would
let the compiler inline them where possible.
There are of course dmaengine drivers that use tasklets for other
purposes than the channel callback. Was your idea here to use
the same workqueue for these? I would perhaps hold off on that for
the moment and see if there is a better alternative for those,
possibly hardirq context, threaded irq or a regular workqueue
depending on the driver.
> A hardirq callback path feels like a larger API change, so I’d
> prefer to handle that as a separate follow‑up (e.g. explicit hardirq
> callback/flag + user migration where safe). Thoughts?
Yes, definitely keep that separate. I still think that this is
what we want eventually for a bigger improvement, but your
patch seems valuable on its own as well.
Some more thoughts on where that later change could take us:
> /*
> - * This tasklet handles the completion of a DMA descriptor by
> - * calling its callback and freeing it.
> + * This bottom-half handler completes a DMA descriptor by invoking its
> + * callback and freeing it.
> */
> -static void vchan_complete(struct tasklet_struct *t)
> +static void vchan_complete(struct dma_chan *chan)
> {
> - struct virt_dma_chan *vc = from_tasklet(vc, t, task);
> + struct virt_dma_chan *vc = to_virt_chan(chan);
> struct virt_dma_desc *vd, *_vd;
> struct dmaengine_desc_callback cb;
> LIST_HEAD(head);
> @@ -131,7 +131,7 @@ void vchan_init(struct virt_dma_chan *vc, struct
> dma_device *dmadev)
> INIT_LIST_HEAD(&vc->desc_completed);
> INIT_LIST_HEAD(&vc->desc_terminated);
>
> - tasklet_setup(&vc->task, vchan_complete);
> + dma_chan_init_bh(&vc->chan, vchan_complete);
This is where I think it makes sense to start, again for
the vchan imlmenentation. What the dmaengine drivers have
is a per-driver tasklet (or WQ_BH) with a single complete()
function that directly calls into the client drivers for
each completion that has happened.
Since the context we want depends on the type of client
driver, I think a good approach would be to start
by modifying vchan_cookie_complete() to allow it to
call the callback function directly from hardirq context
when the client asks for that, and avoid the round trip
through the tasklet where possible.
A new bit in the dma_ctrl_flags word could be used
to ask for hardirq vs softirq context, and the existing
drivers just fall back to using a tasklet for softirq
context.
Arnd
^ permalink raw reply [flat|nested] 82+ messages in thread
* Re: [RFC PATCH 1/1] dmaengine: introduce dmaengine_bh_wq and bh helpers
2026-01-09 16:42 ` Arnd Bergmann
@ 2026-01-12 22:20 ` Allen
2026-01-13 7:33 ` Arnd Bergmann
0 siblings, 1 reply; 82+ messages in thread
From: Allen @ 2026-01-12 22:20 UTC (permalink / raw)
To: Arnd Bergmann; +Cc: Vinod Koul, Kees Cook, dmaengine, linux-kernel
> > Thanks for the feedback. My intent with WQ_BH was to keep callbacks in
> > softirq/BH context, but I agree the scheduling overhead and existing tasklet
> > assumptions are valid concerns.
>
> Hi Allen,
>
> Sorry about missing the bit about WQ_BH, I forgot about the details
> of or previous discussion and this is pretty much what I had
> suggested last time,
>
Hi Arnd,
Sorry I missed the WQ_BH point in my reply, I’d forgotten the details of our
earlier discussion, and I should have followed up on this sooner.
> > I can re-spin the RFC to drop the workqueue entirely and keep
> > tasklet semantics,
> > while still abstracting tasklet handling into dmaengine helpers so drivers no
> > longer directly manipulate tasklets. That keeps
> > dmaengine_desc_callback_invoke()
> > in tasklet context and avoids breaking DMA users that rely on that behavior.
>
> It's probably fine to do both, but a series of two patches (first introduce
> the per-channel API, then move it over to WQ_BH) may be slightly
> clearer here.
>
> I'm not sure why the dmaengine_*_bh_wq() functions are exported
> interfaces, as far as I can tell, you use them only internally
> in the dma_chan_*_bh() functions, so making them static would
> let the compiler inline them where possible.
>
> There are of course dmaengine drivers that use tasklets for other
> purposes than the channel callback. Was your idea here to use
> the same workqueue for these? I would perhaps hold off on that for
> the moment and see if there is a better alternative for those,
> possibly hardirq context, threaded irq or a regular workqueue
> depending on the driver.
>
> > A hardirq callback path feels like a larger API change, so I’d
> > prefer to handle that as a separate follow‑up (e.g. explicit hardirq
> > callback/flag + user migration where safe). Thoughts?
>
> Yes, definitely keep that separate. I still think that this is
> what we want eventually for a bigger improvement, but your
> patch seems valuable on its own as well.
>
Thanks for the detailed feedback. I’ll respin along these lines:
- Split the series into two patches: (1) introduce the per‑channel BH API,
(2) switch the vchan implementation over to the WQ_BH backend if we decide
to keep that step. This should make the progression clearer.
- The dmaengine_*_bh_wq() helpers will be made static; only dma_chan_*_bh()
stays exported.
- I won’t try to move the other per‑driver tasklets onto the shared queue in
this series. That feels like a separate discussion, and the right context
(hardirq/threaded/workqueue) may vary by driver.
- I’ll keep the hardirq callback path separate. For that follow‑up, I can plan
to add an explicit “hardirq safe” request bit (e.g. a new dma_ctrl_flags)
and update vchan_cookie_complete() to invoke the callback directly when
requested; otherwise it stays on the tasklet path.
If you’d prefer I drop the WQ_BH conversion entirely for now and keep only the
tasklet‑based per‑channel API, I can do that too.
Thanks,
Allen
> Some more thoughts on where that later change could take us:
>
> > /*
> > - * This tasklet handles the completion of a DMA descriptor by
> > - * calling its callback and freeing it.
> > + * This bottom-half handler completes a DMA descriptor by invoking its
> > + * callback and freeing it.
> > */
> > -static void vchan_complete(struct tasklet_struct *t)
> > +static void vchan_complete(struct dma_chan *chan)
> > {
> > - struct virt_dma_chan *vc = from_tasklet(vc, t, task);
> > + struct virt_dma_chan *vc = to_virt_chan(chan);
> > struct virt_dma_desc *vd, *_vd;
> > struct dmaengine_desc_callback cb;
> > LIST_HEAD(head);
> > @@ -131,7 +131,7 @@ void vchan_init(struct virt_dma_chan *vc, struct
> > dma_device *dmadev)
> > INIT_LIST_HEAD(&vc->desc_completed);
> > INIT_LIST_HEAD(&vc->desc_terminated);
> >
> > - tasklet_setup(&vc->task, vchan_complete);
> > + dma_chan_init_bh(&vc->chan, vchan_complete);
>
> This is where I think it makes sense to start, again for
> the vchan imlmenentation. What the dmaengine drivers have
> is a per-driver tasklet (or WQ_BH) with a single complete()
> function that directly calls into the client drivers for
> each completion that has happened.
>
> Since the context we want depends on the type of client
> driver, I think a good approach would be to start
> by modifying vchan_cookie_complete() to allow it to
> call the callback function directly from hardirq context
> when the client asks for that, and avoid the round trip
> through the tasklet where possible.
>
> A new bit in the dma_ctrl_flags word could be used
> to ask for hardirq vs softirq context, and the existing
> drivers just fall back to using a tasklet for softirq
> context.
>
> Arnd
--
- Allen
^ permalink raw reply [flat|nested] 82+ messages in thread
* Re: [RFC PATCH 1/1] dmaengine: introduce dmaengine_bh_wq and bh helpers
2026-01-12 22:20 ` Allen
@ 2026-01-13 7:33 ` Arnd Bergmann
2026-01-13 19:31 ` Allen
0 siblings, 1 reply; 82+ messages in thread
From: Arnd Bergmann @ 2026-01-13 7:33 UTC (permalink / raw)
To: Allen; +Cc: Vinod Koul, Kees Cook, dmaengine, linux-kernel
On Mon, Jan 12, 2026, at 23:20, Allen wrote:
>> > A hardirq callback path feels like a larger API change, so I’d
>> > prefer to handle that as a separate follow‑up (e.g. explicit hardirq
>> > callback/flag + user migration where safe). Thoughts?
>>
>> Yes, definitely keep that separate. I still think that this is
>> what we want eventually for a bigger improvement, but your
>> patch seems valuable on its own as well.
>>
>
> Thanks for the detailed feedback. I’ll respin along these lines:
>
> - Split the series into two patches: (1) introduce the per‑channel BH API,
> (2) switch the vchan implementation over to the WQ_BH backend if we decide
> to keep that step. This should make the progression clearer.
>
> - The dmaengine_*_bh_wq() helpers will be made static; only dma_chan_*_bh()
> stays exported.
Sounds good, yes.
> - I won’t try to move the other per‑driver tasklets onto the shared queue in
> this series. That feels like a separate discussion, and the right context
> (hardirq/threaded/workqueue) may vary by driver.
I'm not sure we are talking about the same thing here. I do think we should
try to have all the callbacks in each dmaengine driver go through the same
per-channel deferral mechanism. What I meant to say is that all the tasklets
that are not used for the client callbacks should be separate from those,
e.g. the pl330_dotask() handler is used for unexpected events unrelated
to a channel.
> - I’ll keep the hardirq callback path separate. For that follow‑up, I can plan
> to add an explicit “hardirq safe” request bit (e.g. a new dma_ctrl_flags)
> and update vchan_cookie_complete() to invoke the callback directly when
> requested; otherwise it stays on the tasklet path.
>
> If you’d prefer I drop the WQ_BH conversion entirely for now and keep only the
> tasklet‑based per‑channel API, I can do that too.
No, I think that part is fine.
Arnd
^ permalink raw reply [flat|nested] 82+ messages in thread
* Re: [RFC PATCH 1/1] dmaengine: introduce dmaengine_bh_wq and bh helpers
2026-01-13 7:33 ` Arnd Bergmann
@ 2026-01-13 19:31 ` Allen
0 siblings, 0 replies; 82+ messages in thread
From: Allen @ 2026-01-13 19:31 UTC (permalink / raw)
To: Arnd Bergmann; +Cc: Vinod Koul, Kees Cook, dmaengine, linux-kernel
> >> > A hardirq callback path feels like a larger API change, so I’d
> >> > prefer to handle that as a separate follow‑up (e.g. explicit hardirq
> >> > callback/flag + user migration where safe). Thoughts?
> >>
> >> Yes, definitely keep that separate. I still think that this is
> >> what we want eventually for a bigger improvement, but your
> >> patch seems valuable on its own as well.
> >>
> >
> > Thanks for the detailed feedback. I’ll respin along these lines:
> >
> > - Split the series into two patches: (1) introduce the per‑channel BH API,
> > (2) switch the vchan implementation over to the WQ_BH backend if we decide
> > to keep that step. This should make the progression clearer.
> >
> > - The dmaengine_*_bh_wq() helpers will be made static; only dma_chan_*_bh()
> > stays exported.
>
> Sounds good, yes.
>
> > - I won’t try to move the other per‑driver tasklets onto the shared queue in
> > this series. That feels like a separate discussion, and the right context
> > (hardirq/threaded/workqueue) may vary by driver.
>
> I'm not sure we are talking about the same thing here. I do think we should
> try to have all the callbacks in each dmaengine driver go through the same
> per-channel deferral mechanism. What I meant to say is that all the tasklets
> that are not used for the client callbacks should be separate from those,
> e.g. the pl330_dotask() handler is used for unexpected events unrelated
> to a channel.
Hi Arnd,
Thanks for clarifying, I understand now. Yes, the intent will be to have
all per‑channel client callbacks go through the shared per‑channel deferral
mechanism (dma_chan_*_bh), while keeping any non‑callback tasklets/work
separate (e.g. pl330_dotask() for unexpected events).
I’ll keep WQ_BH and the per‑channel API as the common callback path, and in
follow‑on patches I’ll start converting driver callback paths to use it.
Thanks,
Allen
>
> > - I’ll keep the hardirq callback path separate. For that follow‑up, I can plan
> > to add an explicit “hardirq safe” request bit (e.g. a new dma_ctrl_flags)
> > and update vchan_cookie_complete() to invoke the callback directly when
> > requested; otherwise it stays on the tasklet path.
> >
> > If you’d prefer I drop the WQ_BH conversion entirely for now and keep only the
> > tasklet‑based per‑channel API, I can do that too.
>
> No, I think that part is fine.
>
> Arnd
--
- Allen
^ permalink raw reply [flat|nested] 82+ messages in thread
* [PATCH v2 00/64] dmaengine: migrate channel tasklets to WQ_BH
2026-01-08 8:03 [RFC PATCH 0/1] dmaengine: introduce dmaengine_bh_wq and bh helpers Allen Pais
2026-01-08 8:03 ` [RFC PATCH 1/1] " Allen Pais
@ 2026-07-27 20:28 ` Allen Pais
2026-07-27 20:28 ` [PATCH v2 01/64] dmaengine: add tasklet-backed channel BH helpers Allen Pais
` (64 more replies)
1 sibling, 65 replies; 82+ messages in thread
From: Allen Pais @ 2026-07-27 20:28 UTC (permalink / raw)
To: Vinod Koul, Frank Li
Cc: Allen Pais, dmaengine, linux-kernel, Arnd Bergmann, Kees Cook
Hi Arnd, Vinod and Frank,
This series moves DMAengine client completion bottom halves from private
tasklets to a common per-channel API backed by WQ_BH.
The first patch introduces the dma_chan_*_bh() API with a tasklet backend
and converts virt-dma to it. This separates the driver-facing API from its
implementation without changing callback context.
The second patch switches that backend to a dedicated WQ_BH | WQ_PERCPU
workqueue. WQ_BH keeps callbacks in softirq context, while the common API
centralizes initialization, scheduling, and synchronization. The
workqueue helpers remain internal to DMAengine, and dma_chan_kill_bh()
drains scheduled callbacks to preserve tasklet_kill() semantics.
The remaining patches convert driver-owned channel completion tasklets
and update virt-dma teardown paths. Tasklets used for controller-level
processing, recovery, or other non-client-callback work are deliberately
left alone because the appropriate replacement may differ by driver.
As agreed in the RFC discussion, selecting hardirq callback delivery is a
separate API change and is not part of this series.
Earlier discussion:
https://lore.kernel.org/all/20260108080332.2341725-1-allen.lkml@gmail.com/
Changes since RFC v1:
- split the tasklet-backed channel API from the WQ_BH backend change
- keep the low-level workqueue helpers private to DMAengine
- preserve tasklet teardown semantics by draining scheduled BH work
- convert the remaining driver client-completion tasklets
- retain unrelated controller and recovery tasklets
- route SF-PDMA terminal errors through virt-dma completion handling
- add missing callback synchronization and teardown handling
- fix the build failures reported by the kernel test robot
- rebase onto the current Linus tree
Testing:
- x86_64 allmodconfig
- make -j$(nproc) W=1 drivers/dma/
- scripts/checkpatch.pl --strict --git origin/master..HEAD
- git diff --check origin/master..HEAD
Allen Pais (64):
dmaengine: add tasklet-backed channel BH helpers
dmaengine: back channel BH helpers with WQ_BH
dmaengine: apple-admac: use dma_chan BH callback
dmaengine: at_xdmac: move irq bottom half to dma_chan BH
dmaengine: ep93xx: hook callbacks via dma_chan BH
dmaengine: fsldma: migrate tasklet to dma_chan BH
dmaengine: fsl_raid: run completions via dma_chan BH
dmaengine: imx-dma: flip per-chan tasklet to dma_chan BH
dmaengine: ioat: convert cleanup tasklet to dma_chan BH
dmaengine: mmp_pdma: replace per-chan tasklet with dma_chan BH
dmaengine: mmp_tdma: hook completions to dma_chan BH
dmaengine: mv_xor: convert irq tasklet to dma_chan BH
dmaengine: mxs-dma: use dma_chan BH scheduling
dmaengine: nbpfaxi: switch callbacks to dma_chan BH
dmaengine: pch_dma: convert tasklet to dma_chan BH
dmaengine: ppc4xx: replace irq tasklet with dma_chan BH
dmaengine: ste_dma40: convert per-channel tasklet to dma_chan BH
dmaengine: xgene-dma: wire descriptor cleanup to dma_chan BH
dmaengine: xilinx-dma: use dma_chan BH instead of tasklets
dmaengine: xilinx-dpdma: kill vchan BH on remove
dmaengine: zynqmp-dma: switch completion tasklet to dma_chan BH
dmaengine: tegra20-apb: use channel BH helpers
dmaengine: timb_dma: route callbacks via channel BH
dmaengine: txx9dmac: route callbacks via channel BH
dmaengine: mv_xor_v2: use channel BH helpers
dmaengine: mpc512x: route callbacks via channel BH
dmaengine: k3dma: kill vchan BH on remove
dmaengine: plx_dma: use channel BH helpers
dmaengine: sf-pdma: route error callbacks through channel BH
dmaengine: sa11x0-dma: kill vchan BH on remove
dmaengine: pl330: route callbacks via channel BH
dmaengine: k3-udma: use channel BH for vchan completions
dmaengine: sun6i: kill vchan BH on teardown
dmaengine: mtk-cqdma: kill vchan BH on teardown
dmaengine: altera-msgdma: use channel BH helpers
dmaengine: sprd-dma: kill vchan BH on teardown
dmaengine: idma64: kill vchan BH on teardown
dmaengine: img-mdc-dma: kill vchan BH on teardown
dmaengine: fsl-edma-common: kill vchan BH on teardown
dmaengine: dw-axi-dmac: kill vchan BH on teardown
dmaengine: hsu: kill vchan BH on teardown
dmaengine: jz4780: kill vchan BH on teardown
dmaengine: pxa_dma: kill vchan BH on teardown
dmaengine: mtk-hsdma: kill vchan BH on teardown
dmaengine: mtk-uart-apdma: kill vchan BH on teardown
dmaengine: imx-sdma: kill vchan BH on teardown
dmaengine: loongson1-apb: kill vchan BH on teardown
dmaengine: owl-dma: kill vchan BH on teardown
dmaengine: hisi: kill vchan BH on teardown
dmaengine: dw-edma: kill vchan BH on teardown
dmaengine: bcm2835: kill vchan BH on teardown
dmaengine: tegra210-adma: kill vchan BH on teardown
dmaengine: fsl-qdma: use dma_chan_kill_bh
dmaengine: st_fdma: use dma_chan_kill_bh
dmaengine: dma-axi-dmac: use dma_chan_kill_bh
dmaengine: omap-dma: use dma_chan_kill_bh
dmaengine: edma: use dma_chan_kill_bh
dmaengine: qcom-adm: use dma_chan_kill_bh
dmaengine: tegra186-gpc: use dma_chan_kill_bh
dmaengine: bam-dma: use dma_chan_kill_bh
dmaengine: dw: defer callbacks via channel BH
dmaengine: hidma: defer callbacks via channel BH
dmaengine: qcom-gpi: defer callbacks via vchan
dmaengine: switchtec: use channel BH helpers
drivers/dma/altera-msgdma.c | 14 +--
drivers/dma/apple-admac.c | 16 ++--
drivers/dma/at_xdmac.c | 13 ++-
drivers/dma/bcm2835-dma.c | 2 +-
drivers/dma/dma-axi-dmac.c | 10 ++-
drivers/dma/dma-jz4780.c | 2 +-
drivers/dma/dmaengine.c | 89 ++++++++++++++++++-
.../dma/dw-axi-dmac/dw-axi-dmac-platform.c | 2 +-
drivers/dma/dw-edma/dw-edma-core.c | 2 +-
drivers/dma/dw/core.c | 42 +++++++--
drivers/dma/dw/regs.h | 1 +
drivers/dma/ep93xx_dma.c | 12 ++-
drivers/dma/fsl-edma-common.c | 2 +-
drivers/dma/fsl-qdma.c | 2 +-
drivers/dma/fsl_raid.c | 11 +--
drivers/dma/fsl_raid.h | 1 -
drivers/dma/fsldma.c | 10 +--
drivers/dma/fsldma.h | 1 -
drivers/dma/hisi_dma.c | 2 +-
drivers/dma/hsu/hsu.c | 2 +-
drivers/dma/idma64.c | 4 +-
drivers/dma/img-mdc-dma.c | 2 +-
drivers/dma/imx-dma.c | 26 +++---
drivers/dma/imx-sdma.c | 4 +-
drivers/dma/ioat/dma.c | 14 +--
drivers/dma/ioat/dma.h | 3 +-
drivers/dma/ioat/init.c | 2 +-
drivers/dma/k3dma.c | 2 +-
drivers/dma/loongson/loongson1-apb-dma.c | 2 +-
drivers/dma/mediatek/mtk-cqdma.c | 2 +-
drivers/dma/mediatek/mtk-hsdma.c | 2 +-
drivers/dma/mediatek/mtk-uart-apdma.c | 4 +-
drivers/dma/mmp_pdma.c | 13 ++-
drivers/dma/mmp_tdma.c | 9 +-
drivers/dma/mpc512x_dma.c | 74 +++++++++------
drivers/dma/mv_xor.c | 12 +--
drivers/dma/mv_xor.h | 2 -
drivers/dma/mv_xor_v2.c | 20 ++---
drivers/dma/mxs-dma.c | 11 ++-
drivers/dma/nbpfaxi.c | 13 ++-
drivers/dma/owl-dma.c | 2 +-
drivers/dma/pch_dma.c | 14 +--
drivers/dma/pl330.c | 18 ++--
drivers/dma/plx_dma.c | 12 +--
drivers/dma/ppc4xx/adma.c | 14 +--
drivers/dma/ppc4xx/adma.h | 2 -
drivers/dma/pxa_dma.c | 2 +-
drivers/dma/qcom/bam_dma.c | 4 +-
drivers/dma/qcom/gpi.c | 17 +++-
drivers/dma/qcom/hidma.c | 18 +++-
drivers/dma/qcom/qcom_adm.c | 4 +-
drivers/dma/sa11x0-dma.c | 2 +-
drivers/dma/sf-pdma/sf-pdma.c | 14 ++-
drivers/dma/sprd-dma.c | 2 +-
drivers/dma/st_fdma.c | 2 +-
drivers/dma/ste_dma40.c | 13 ++-
drivers/dma/sun6i-dma.c | 2 +-
drivers/dma/switchtec_dma.c | 16 ++--
drivers/dma/tegra186-gpc-dma.c | 2 +-
drivers/dma/tegra20-apb-dma.c | 18 ++--
drivers/dma/tegra210-adma.c | 2 +-
drivers/dma/ti/edma.c | 2 +-
drivers/dma/ti/k3-udma.c | 12 +--
drivers/dma/ti/omap-dma.c | 2 +-
drivers/dma/timb_dma.c | 21 +++--
drivers/dma/txx9dmac.c | 12 +--
drivers/dma/txx9dmac.h | 1 -
drivers/dma/virt-dma.c | 12 +--
drivers/dma/virt-dma.h | 7 +-
drivers/dma/xgene-dma.c | 19 ++--
drivers/dma/xilinx/xilinx_dma.c | 20 ++---
drivers/dma/xilinx/xilinx_dpdma.c | 1 +
drivers/dma/xilinx/zynqmp_dma.c | 19 ++--
include/linux/dmaengine.h | 28 ++++++
74 files changed, 482 insertions(+), 311 deletions(-)
base-commit: f5098b6bae761e346ebcd9da7f95622c04733cff
--
2.43.0
^ permalink raw reply [flat|nested] 82+ messages in thread
* [PATCH v2 01/64] dmaengine: add tasklet-backed channel BH helpers
2026-07-27 20:28 ` [PATCH v2 00/64] dmaengine: migrate channel tasklets to WQ_BH Allen Pais
@ 2026-07-27 20:28 ` Allen Pais
2026-07-29 12:48 ` Vinod Koul
2026-07-27 20:28 ` [PATCH v2 02/64] dmaengine: back channel BH helpers with WQ_BH Allen Pais
` (63 subsequent siblings)
64 siblings, 1 reply; 82+ messages in thread
From: Allen Pais @ 2026-07-27 20:28 UTC (permalink / raw)
To: Vinod Koul, Frank Li
Cc: Allen Pais, dmaengine, linux-kernel, Arnd Bergmann, Kees Cook
DMAengine drivers commonly use a per-channel tasklet to invoke client
callbacks. Add helpers that initialize, schedule, and kill a channel
bottom half, with an initial tasklet-backed implementation that preserves
the existing execution context.
Convert virt-dma to the new API and remove its private tasklet. While
touching the completion handler, avoid forming a result pointer from a
NULL cyclic descriptor.
This establishes a backend-independent API before changing how channel
bottom halves are dispatched.
Signed-off-by: Allen Pais <allen.lkml@gmail.com>
---
drivers/dma/dmaengine.c | 42 +++++++++++++++++++++++++++++++++++++++
drivers/dma/virt-dma.c | 12 +++++------
drivers/dma/virt-dma.h | 7 +++----
include/linux/dmaengine.h | 28 ++++++++++++++++++++++++++
4 files changed, 79 insertions(+), 10 deletions(-)
diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c
index 9049171df857..f43aeecb47f9 100644
--- a/drivers/dma/dmaengine.c
+++ b/drivers/dma/dmaengine.c
@@ -1428,6 +1428,48 @@ static void dmaengine_destroy_unmap_pool(void)
}
}
+static void dma_chan_bh_entry(struct tasklet_struct *tasklet)
+{
+ struct dma_chan *chan = from_tasklet(chan, tasklet, bh_tasklet);
+ dma_chan_bh_work_fn fn = READ_ONCE(chan->bh_work_fn);
+
+ if (fn)
+ fn(chan);
+}
+
+void dma_chan_init_bh(struct dma_chan *chan, dma_chan_bh_work_fn fn)
+{
+ if (WARN_ON(!fn))
+ return;
+
+ if (WARN_ON(chan->bh_work_initialized))
+ return;
+
+ chan->bh_work_fn = fn;
+ tasklet_setup(&chan->bh_tasklet, dma_chan_bh_entry);
+ chan->bh_work_initialized = true;
+}
+EXPORT_SYMBOL_GPL(dma_chan_init_bh);
+
+bool dma_chan_schedule_bh(struct dma_chan *chan)
+{
+ if (WARN_ON(!chan->bh_work_initialized))
+ return false;
+
+ tasklet_schedule(&chan->bh_tasklet);
+ return true;
+}
+EXPORT_SYMBOL_GPL(dma_chan_schedule_bh);
+
+void dma_chan_kill_bh(struct dma_chan *chan)
+{
+ if (!chan->bh_work_initialized)
+ return;
+
+ tasklet_kill(&chan->bh_tasklet);
+}
+EXPORT_SYMBOL_GPL(dma_chan_kill_bh);
+
static int __init dmaengine_init_unmap_pool(void)
{
int i;
diff --git a/drivers/dma/virt-dma.c b/drivers/dma/virt-dma.c
index 7961172a780d..89fcd51ddcab 100644
--- a/drivers/dma/virt-dma.c
+++ b/drivers/dma/virt-dma.c
@@ -77,12 +77,12 @@ struct virt_dma_desc *vchan_find_desc(struct virt_dma_chan *vc,
EXPORT_SYMBOL_GPL(vchan_find_desc);
/*
- * This tasklet handles the completion of a DMA descriptor by
- * calling its callback and freeing it.
+ * This bottom-half handler completes a DMA descriptor by invoking its
+ * callback and freeing it.
*/
-static void vchan_complete(struct tasklet_struct *t)
+static void vchan_complete(struct dma_chan *chan)
{
- struct virt_dma_chan *vc = from_tasklet(vc, t, task);
+ struct virt_dma_chan *vc = to_virt_chan(chan);
struct virt_dma_desc *vd, *_vd;
struct dmaengine_desc_callback cb;
LIST_HEAD(head);
@@ -98,7 +98,7 @@ static void vchan_complete(struct tasklet_struct *t)
}
spin_unlock_irq(&vc->lock);
- dmaengine_desc_callback_invoke(&cb, &vd->tx_result);
+ dmaengine_desc_callback_invoke(&cb, vd ? &vd->tx_result : NULL);
list_for_each_entry_safe(vd, _vd, &head, node) {
dmaengine_desc_get_callback(&vd->tx, &cb);
@@ -131,7 +131,7 @@ void vchan_init(struct virt_dma_chan *vc, struct dma_device *dmadev)
INIT_LIST_HEAD(&vc->desc_completed);
INIT_LIST_HEAD(&vc->desc_terminated);
- tasklet_setup(&vc->task, vchan_complete);
+ dma_chan_init_bh(&vc->chan, vchan_complete);
vc->chan.device = dmadev;
list_add_tail(&vc->chan.device_node, &dmadev->channels);
diff --git a/drivers/dma/virt-dma.h b/drivers/dma/virt-dma.h
index 59d9eabc8b67..abe2a4475744 100644
--- a/drivers/dma/virt-dma.h
+++ b/drivers/dma/virt-dma.h
@@ -21,7 +21,6 @@ struct virt_dma_desc {
struct virt_dma_chan {
struct dma_chan chan;
- struct tasklet_struct task;
void (*desc_free)(struct virt_dma_desc *);
spinlock_t lock;
@@ -106,7 +105,7 @@ static inline void vchan_cookie_complete(struct virt_dma_desc *vd)
vd, cookie);
list_add_tail(&vd->node, &vc->desc_completed);
- tasklet_schedule(&vc->task);
+ dma_chan_schedule_bh(&vc->chan);
}
/**
@@ -137,7 +136,7 @@ static inline void vchan_cyclic_callback(struct virt_dma_desc *vd)
struct virt_dma_chan *vc = to_virt_chan(vd->tx.chan);
vc->cyclic = vd;
- tasklet_schedule(&vc->task);
+ dma_chan_schedule_bh(&vc->chan);
}
/**
@@ -223,7 +222,7 @@ static inline void vchan_synchronize(struct virt_dma_chan *vc)
LIST_HEAD(head);
unsigned long flags;
- tasklet_kill(&vc->task);
+ dma_chan_kill_bh(&vc->chan);
spin_lock_irqsave(&vc->lock, flags);
diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h
index b3d251c9734e..c670781b3150 100644
--- a/include/linux/dmaengine.h
+++ b/include/linux/dmaengine.h
@@ -12,6 +12,7 @@
#include <linux/scatterlist.h>
#include <linux/bitmap.h>
#include <linux/types.h>
+#include <linux/interrupt.h>
#include <asm/page.h>
/**
@@ -295,6 +296,10 @@ enum dma_desc_metadata_mode {
DESC_METADATA_ENGINE = BIT(1),
};
+struct dma_chan;
+
+typedef void (*dma_chan_bh_work_fn)(struct dma_chan *chan);
+
/**
* struct dma_chan_percpu - the per-CPU part of struct dma_chan
* @memcpy_count: transaction counter
@@ -334,6 +339,9 @@ struct dma_router {
* @router: pointer to the DMA router structure
* @route_data: channel specific data for the router
* @private: private data for certain client-channel associations
+ * @bh_tasklet: bottom-half tasklet stored per-channel
+ * @bh_work_fn: callback executed when @bh_tasklet runs
+ * @bh_work_initialized: indicates whether @bh_tasklet has been initialized
*/
struct dma_chan {
struct dma_device *device;
@@ -359,6 +367,9 @@ struct dma_chan {
void *route_data;
void *private;
+ struct tasklet_struct bh_tasklet;
+ dma_chan_bh_work_fn bh_work_fn;
+ bool bh_work_initialized;
};
/**
@@ -1529,6 +1540,9 @@ struct dma_chan *devm_dma_request_chan(struct device *dev, const char *name);
void dma_release_channel(struct dma_chan *chan);
int dma_get_slave_caps(struct dma_chan *chan, struct dma_slave_caps *caps);
+void dma_chan_init_bh(struct dma_chan *chan, dma_chan_bh_work_fn fn);
+bool dma_chan_schedule_bh(struct dma_chan *chan);
+void dma_chan_kill_bh(struct dma_chan *chan);
#else
static inline struct dma_chan *dma_find_channel(enum dma_transaction_type tx_type)
{
@@ -1576,6 +1590,20 @@ static inline int dma_get_slave_caps(struct dma_chan *chan,
{
return -ENXIO;
}
+
+static inline void dma_chan_init_bh(struct dma_chan *chan,
+ dma_chan_bh_work_fn fn)
+{
+}
+
+static inline bool dma_chan_schedule_bh(struct dma_chan *chan)
+{
+ return false;
+}
+
+static inline void dma_chan_kill_bh(struct dma_chan *chan)
+{
+}
#endif
static inline int dmaengine_desc_set_reuse(struct dma_async_tx_descriptor *tx)
--
2.43.0
^ permalink raw reply related [flat|nested] 82+ messages in thread
* [PATCH v2 02/64] dmaengine: back channel BH helpers with WQ_BH
2026-07-27 20:28 ` [PATCH v2 00/64] dmaengine: migrate channel tasklets to WQ_BH Allen Pais
2026-07-27 20:28 ` [PATCH v2 01/64] dmaengine: add tasklet-backed channel BH helpers Allen Pais
@ 2026-07-27 20:28 ` Allen Pais
2026-07-27 20:28 ` [PATCH v2 03/64] dmaengine: apple-admac: use dma_chan BH callback Allen Pais
` (62 subsequent siblings)
64 siblings, 0 replies; 82+ messages in thread
From: Allen Pais @ 2026-07-27 20:28 UTC (permalink / raw)
To: Vinod Koul, Frank Li
Cc: Allen Pais, dmaengine, linux-kernel, Arnd Bergmann, Kees Cook
Replace the tasklet implementation of the channel BH helpers with a
dedicated WQ_BH | WQ_PERCPU workqueue. The public dma_chan_*_bh() API and
its softirq execution context remain unchanged.
Keep the workqueue operations internal to dmaengine. Drain scheduled work
in dma_chan_kill_bh() to preserve the completion semantics of
tasklet_kill().
Signed-off-by: Allen Pais <allen.lkml@gmail.com>
---
drivers/dma/dmaengine.c | 59 ++++++++++++++++++++++++++++++++-------
include/linux/dmaengine.h | 10 +++----
2 files changed, 54 insertions(+), 15 deletions(-)
diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c
index f43aeecb47f9..8b1b17794956 100644
--- a/drivers/dma/dmaengine.c
+++ b/drivers/dma/dmaengine.c
@@ -54,6 +54,7 @@
#include <linux/rcupdate.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
+#include <linux/workqueue.h>
#include "dmaengine.h"
@@ -61,6 +62,7 @@ static DEFINE_MUTEX(dma_list_mutex);
static DEFINE_IDA(dma_ida);
static LIST_HEAD(dma_device_list);
static long dmaengine_ref_count;
+static struct workqueue_struct *dmaengine_bh_wq;
/* --- debugfs implementation --- */
#ifdef CONFIG_DEBUG_FS
@@ -1428,9 +1430,34 @@ static void dmaengine_destroy_unmap_pool(void)
}
}
-static void dma_chan_bh_entry(struct tasklet_struct *tasklet)
+static void dmaengine_destroy_bh_wq(void)
{
- struct dma_chan *chan = from_tasklet(chan, tasklet, bh_tasklet);
+ if (!dmaengine_bh_wq)
+ return;
+
+ destroy_workqueue(dmaengine_bh_wq);
+ dmaengine_bh_wq = NULL;
+}
+
+static bool dmaengine_queue_bh_work(struct work_struct *work)
+{
+ if (WARN_ON(!dmaengine_bh_wq))
+ return false;
+
+ return queue_work(dmaengine_bh_wq, work);
+}
+
+static void dmaengine_flush_bh_work(struct work_struct *work)
+{
+ if (!work)
+ return;
+
+ flush_work(work);
+}
+
+static void dma_chan_bh_entry(struct work_struct *work)
+{
+ struct dma_chan *chan = container_of(work, struct dma_chan, bh_work);
dma_chan_bh_work_fn fn = READ_ONCE(chan->bh_work_fn);
if (fn)
@@ -1446,7 +1473,7 @@ void dma_chan_init_bh(struct dma_chan *chan, dma_chan_bh_work_fn fn)
return;
chan->bh_work_fn = fn;
- tasklet_setup(&chan->bh_tasklet, dma_chan_bh_entry);
+ INIT_WORK(&chan->bh_work, dma_chan_bh_entry);
chan->bh_work_initialized = true;
}
EXPORT_SYMBOL_GPL(dma_chan_init_bh);
@@ -1456,8 +1483,7 @@ bool dma_chan_schedule_bh(struct dma_chan *chan)
if (WARN_ON(!chan->bh_work_initialized))
return false;
- tasklet_schedule(&chan->bh_tasklet);
- return true;
+ return dmaengine_queue_bh_work(&chan->bh_work);
}
EXPORT_SYMBOL_GPL(dma_chan_schedule_bh);
@@ -1466,7 +1492,7 @@ void dma_chan_kill_bh(struct dma_chan *chan)
if (!chan->bh_work_initialized)
return;
- tasklet_kill(&chan->bh_tasklet);
+ dmaengine_flush_bh_work(&chan->bh_work);
}
EXPORT_SYMBOL_GPL(dma_chan_kill_bh);
@@ -1666,15 +1692,28 @@ EXPORT_SYMBOL_GPL(dma_run_dependencies);
static int __init dma_bus_init(void)
{
- int err = dmaengine_init_unmap_pool();
+ int err;
+ dmaengine_bh_wq = alloc_workqueue("dmaengine_bh",
+ WQ_BH | WQ_PERCPU, 0);
+ if (!dmaengine_bh_wq)
+ return -ENOMEM;
+
+ err = dmaengine_init_unmap_pool();
if (err)
- return err;
+ goto err_destroy_wq;
err = class_register(&dma_devclass);
- if (!err)
- dmaengine_debugfs_init();
+ if (err)
+ goto err_destroy_pool;
+ dmaengine_debugfs_init();
+ return 0;
+
+err_destroy_pool:
+ dmaengine_destroy_unmap_pool();
+err_destroy_wq:
+ dmaengine_destroy_bh_wq();
return err;
}
arch_initcall(dma_bus_init);
diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h
index c670781b3150..c87974d5048b 100644
--- a/include/linux/dmaengine.h
+++ b/include/linux/dmaengine.h
@@ -12,7 +12,7 @@
#include <linux/scatterlist.h>
#include <linux/bitmap.h>
#include <linux/types.h>
-#include <linux/interrupt.h>
+#include <linux/workqueue.h>
#include <asm/page.h>
/**
@@ -339,9 +339,9 @@ struct dma_router {
* @router: pointer to the DMA router structure
* @route_data: channel specific data for the router
* @private: private data for certain client-channel associations
- * @bh_tasklet: bottom-half tasklet stored per-channel
- * @bh_work_fn: callback executed when @bh_tasklet runs
- * @bh_work_initialized: indicates whether @bh_tasklet has been initialized
+ * @bh_work: bottom-half work item stored per-channel
+ * @bh_work_fn: callback executed when @bh_work runs
+ * @bh_work_initialized: indicates whether @bh_work has been initialized
*/
struct dma_chan {
struct dma_device *device;
@@ -367,7 +367,7 @@ struct dma_chan {
void *route_data;
void *private;
- struct tasklet_struct bh_tasklet;
+ struct work_struct bh_work;
dma_chan_bh_work_fn bh_work_fn;
bool bh_work_initialized;
};
--
2.43.0
^ permalink raw reply related [flat|nested] 82+ messages in thread
* [PATCH v2 03/64] dmaengine: apple-admac: use dma_chan BH callback
2026-07-27 20:28 ` [PATCH v2 00/64] dmaengine: migrate channel tasklets to WQ_BH Allen Pais
2026-07-27 20:28 ` [PATCH v2 01/64] dmaengine: add tasklet-backed channel BH helpers Allen Pais
2026-07-27 20:28 ` [PATCH v2 02/64] dmaengine: back channel BH helpers with WQ_BH Allen Pais
@ 2026-07-27 20:28 ` Allen Pais
2026-07-27 20:28 ` [PATCH v2 04/64] dmaengine: at_xdmac: move irq bottom half to dma_chan BH Allen Pais
` (61 subsequent siblings)
64 siblings, 0 replies; 82+ messages in thread
From: Allen Pais @ 2026-07-27 20:28 UTC (permalink / raw)
To: Vinod Koul, Frank Li
Cc: Allen Pais, dmaengine, linux-kernel, Arnd Bergmann, Kees Cook,
Sven Peter, Janne Grunau, Neal Gompa, asahi, linux-arm-kernel
Replace the per-channel tasklet with the shared dma_chan BH helper.
The handler continues to run in softirq context while dmaengine owns
the common scheduling and teardown mechanism.
Signed-off-by: Allen Pais <allen.lkml@gmail.com>
---
drivers/dma/apple-admac.c | 16 ++++++----------
1 file changed, 6 insertions(+), 10 deletions(-)
diff --git a/drivers/dma/apple-admac.c b/drivers/dma/apple-admac.c
index 14a5ee14a481..84483247bde6 100644
--- a/drivers/dma/apple-admac.c
+++ b/drivers/dma/apple-admac.c
@@ -89,7 +89,6 @@ struct admac_chan {
unsigned int no;
struct admac_data *host;
struct dma_chan chan;
- struct tasklet_struct tasklet;
u32 carveout;
@@ -521,10 +520,7 @@ static int admac_terminate_all(struct dma_chan *chan)
list_add_tail(&adchan->current_tx->node, &adchan->to_free);
adchan->current_tx = NULL;
}
- /*
- * Descriptors can only be freed after the tasklet
- * has been killed (in admac_synchronize).
- */
+ /* Descriptors are released once the BH is flushed in admac_synchronize */
list_splice_tail_init(&adchan->submitted, &adchan->to_free);
list_splice_tail_init(&adchan->issued, &adchan->to_free);
spin_unlock_irqrestore(&adchan->lock, flags);
@@ -543,7 +539,7 @@ static void admac_synchronize(struct dma_chan *chan)
list_splice_tail_init(&adchan->to_free, &head);
spin_unlock_irqrestore(&adchan->lock, flags);
- tasklet_kill(&adchan->tasklet);
+ dma_chan_kill_bh(&adchan->chan);
list_for_each_entry_safe(adtx, _adtx, &head, node) {
list_del(&adtx->node);
@@ -662,7 +658,7 @@ static void admac_handle_status_desc_done(struct admac_data *ad, int channo)
tx->reclaimed_pos %= 2 * tx->buf_len;
admac_cyclic_write_desc(ad, channo, tx);
- tasklet_schedule(&adchan->tasklet);
+ dma_chan_schedule_bh(&adchan->chan);
}
spin_unlock_irqrestore(&adchan->lock, flags);
}
@@ -712,9 +708,9 @@ static irqreturn_t admac_interrupt(int irq, void *devid)
return IRQ_HANDLED;
}
-static void admac_chan_tasklet(struct tasklet_struct *t)
+static void admac_chan_bh(struct dma_chan *chan)
{
- struct admac_chan *adchan = from_tasklet(adchan, t, tasklet);
+ struct admac_chan *adchan = to_admac_chan(chan);
struct admac_tx *adtx;
struct dmaengine_desc_callback cb;
struct dmaengine_result tx_result;
@@ -886,7 +882,7 @@ static int admac_probe(struct platform_device *pdev)
INIT_LIST_HEAD(&adchan->issued);
INIT_LIST_HEAD(&adchan->to_free);
list_add_tail(&adchan->chan.device_node, &dma->channels);
- tasklet_setup(&adchan->tasklet, admac_chan_tasklet);
+ dma_chan_init_bh(&adchan->chan, admac_chan_bh);
}
err = reset_control_reset(ad->rstc);
--
2.43.0
^ permalink raw reply related [flat|nested] 82+ messages in thread
* [PATCH v2 04/64] dmaengine: at_xdmac: move irq bottom half to dma_chan BH
2026-07-27 20:28 ` [PATCH v2 00/64] dmaengine: migrate channel tasklets to WQ_BH Allen Pais
` (2 preceding siblings ...)
2026-07-27 20:28 ` [PATCH v2 03/64] dmaengine: apple-admac: use dma_chan BH callback Allen Pais
@ 2026-07-27 20:28 ` Allen Pais
2026-07-27 20:28 ` [PATCH v2 05/64] dmaengine: ep93xx: hook callbacks via " Allen Pais
` (60 subsequent siblings)
64 siblings, 0 replies; 82+ messages in thread
From: Allen Pais @ 2026-07-27 20:28 UTC (permalink / raw)
To: Vinod Koul, Frank Li
Cc: Allen Pais, dmaengine, linux-kernel, Arnd Bergmann, Kees Cook,
Ludovic Desroches, linux-arm-kernel
Replace the per-channel tasklet with the shared dma_chan BH helper.
The handler continues to run in softirq context while dmaengine owns
the common scheduling and teardown mechanism.
Signed-off-by: Allen Pais <allen.lkml@gmail.com>
---
drivers/dma/at_xdmac.c | 13 ++++++-------
1 file changed, 6 insertions(+), 7 deletions(-)
diff --git a/drivers/dma/at_xdmac.c b/drivers/dma/at_xdmac.c
index 901971e8bae6..aa918043e37e 100644
--- a/drivers/dma/at_xdmac.c
+++ b/drivers/dma/at_xdmac.c
@@ -228,7 +228,6 @@ struct at_xdmac_chan {
u32 save_cndc;
u32 irq_status;
unsigned long status;
- struct tasklet_struct tasklet;
struct dma_slave_config sconfig;
spinlock_t lock;
@@ -1759,9 +1758,9 @@ static void at_xdmac_handle_error(struct at_xdmac_chan *atchan)
/* Then continue with usual descriptor management */
}
-static void at_xdmac_tasklet(struct tasklet_struct *t)
+static void at_xdmac_tasklet(struct dma_chan *chan)
{
- struct at_xdmac_chan *atchan = from_tasklet(atchan, t, tasklet);
+ struct at_xdmac_chan *atchan = to_at_xdmac_chan(chan);
struct at_xdmac *atxdmac = to_at_xdmac(atchan->chan.device);
struct at_xdmac_desc *desc;
struct dma_async_tx_descriptor *txd;
@@ -1865,7 +1864,7 @@ static irqreturn_t at_xdmac_interrupt(int irq, void *dev_id)
if (atchan->irq_status & (AT_XDMAC_CIS_RBEIS | AT_XDMAC_CIS_WBEIS))
at_xdmac_write(atxdmac, AT_XDMAC_GD, atchan->mask);
- tasklet_schedule(&atchan->tasklet);
+ dma_chan_schedule_bh(&atchan->chan);
ret = IRQ_HANDLED;
}
@@ -2317,7 +2316,7 @@ static int at_xdmac_probe(struct platform_device *pdev)
return PTR_ERR(atxdmac->clk);
}
- /* Do not use dev res to prevent races with tasklet */
+ /* Do not use devm resources to prevent races with the BH worker */
ret = request_irq(atxdmac->irq, at_xdmac_interrupt, 0, "at_xdmac", atxdmac);
if (ret) {
dev_err(&pdev->dev, "can't request irq\n");
@@ -2397,7 +2396,7 @@ static int at_xdmac_probe(struct platform_device *pdev)
spin_lock_init(&atchan->lock);
INIT_LIST_HEAD(&atchan->xfers_list);
INIT_LIST_HEAD(&atchan->free_descs_list);
- tasklet_setup(&atchan->tasklet, at_xdmac_tasklet);
+ dma_chan_init_bh(&atchan->chan, at_xdmac_tasklet);
/* Clear pending interrupts. */
while (at_xdmac_chan_read(atchan, AT_XDMAC_CIS))
@@ -2458,7 +2457,7 @@ static void at_xdmac_remove(struct platform_device *pdev)
for (i = 0; i < atxdmac->dma.chancnt; i++) {
struct at_xdmac_chan *atchan = &atxdmac->chan[i];
- tasklet_kill(&atchan->tasklet);
+ dma_chan_kill_bh(&atchan->chan);
at_xdmac_free_chan_resources(&atchan->chan);
}
}
--
2.43.0
^ permalink raw reply related [flat|nested] 82+ messages in thread
* [PATCH v2 05/64] dmaengine: ep93xx: hook callbacks via dma_chan BH
2026-07-27 20:28 ` [PATCH v2 00/64] dmaengine: migrate channel tasklets to WQ_BH Allen Pais
` (3 preceding siblings ...)
2026-07-27 20:28 ` [PATCH v2 04/64] dmaengine: at_xdmac: move irq bottom half to dma_chan BH Allen Pais
@ 2026-07-27 20:28 ` Allen Pais
2026-07-27 20:28 ` [PATCH v2 06/64] dmaengine: fsldma: migrate tasklet to " Allen Pais
` (59 subsequent siblings)
64 siblings, 0 replies; 82+ messages in thread
From: Allen Pais @ 2026-07-27 20:28 UTC (permalink / raw)
To: Vinod Koul, Frank Li
Cc: Allen Pais, dmaengine, linux-kernel, Arnd Bergmann, Kees Cook
Replace the per-channel tasklet with the shared dma_chan BH helper.
The handler continues to run in softirq context while dmaengine owns
the common scheduling and teardown mechanism.
Signed-off-by: Allen Pais <allen.lkml@gmail.com>
---
drivers/dma/ep93xx_dma.c | 12 +++++-------
1 file changed, 5 insertions(+), 7 deletions(-)
diff --git a/drivers/dma/ep93xx_dma.c b/drivers/dma/ep93xx_dma.c
index 311e55a97ba9..8f5200750fe9 100644
--- a/drivers/dma/ep93xx_dma.c
+++ b/drivers/dma/ep93xx_dma.c
@@ -167,7 +167,6 @@ struct ep93xx_dma_chan_cfg {
* @dma_cfg: channel number, direction
* @irq: interrupt number of the channel
* @clk: clock used by this channel
- * @tasklet: channel specific tasklet used for callbacks
* @lock: lock protecting the fields following
* @flags: flags for the channel
* @buffer: which buffer to use next (0/1)
@@ -196,7 +195,6 @@ struct ep93xx_dma_chan {
struct ep93xx_dma_chan_cfg dma_cfg;
int irq;
struct clk *clk;
- struct tasklet_struct tasklet;
/* protects the fields following */
spinlock_t lock;
unsigned long flags;
@@ -801,9 +799,9 @@ static void ep93xx_dma_advance_work(struct ep93xx_dma_chan *edmac)
spin_unlock_irqrestore(&edmac->lock, flags);
}
-static void ep93xx_dma_tasklet(struct tasklet_struct *t)
+static void ep93xx_dma_tasklet(struct dma_chan *chan)
{
- struct ep93xx_dma_chan *edmac = from_tasklet(edmac, t, tasklet);
+ struct ep93xx_dma_chan *edmac = to_ep93xx_dma_chan(chan);
struct ep93xx_dma_desc *desc, *d;
struct dmaengine_desc_callback cb;
LIST_HEAD(list);
@@ -858,12 +856,12 @@ static irqreturn_t ep93xx_dma_interrupt(int irq, void *dev_id)
switch (edmac->edma->hw_interrupt(edmac)) {
case INTERRUPT_DONE:
desc->complete = true;
- tasklet_schedule(&edmac->tasklet);
+ dma_chan_schedule_bh(&edmac->chan);
break;
case INTERRUPT_NEXT_BUFFER:
if (test_bit(EP93XX_DMA_IS_CYCLIC, &edmac->flags))
- tasklet_schedule(&edmac->tasklet);
+ dma_chan_schedule_bh(&edmac->chan);
break;
default:
@@ -1420,7 +1418,7 @@ static struct ep93xx_dma_engine *ep93xx_dma_of_probe(struct platform_device *pde
INIT_LIST_HEAD(&edmac->active);
INIT_LIST_HEAD(&edmac->queue);
INIT_LIST_HEAD(&edmac->free_list);
- tasklet_setup(&edmac->tasklet, ep93xx_dma_tasklet);
+ dma_chan_init_bh(&edmac->chan, ep93xx_dma_tasklet);
list_add_tail(&edmac->chan.device_node,
&dma_dev->channels);
--
2.43.0
^ permalink raw reply related [flat|nested] 82+ messages in thread
* [PATCH v2 06/64] dmaengine: fsldma: migrate tasklet to dma_chan BH
2026-07-27 20:28 ` [PATCH v2 00/64] dmaengine: migrate channel tasklets to WQ_BH Allen Pais
` (4 preceding siblings ...)
2026-07-27 20:28 ` [PATCH v2 05/64] dmaengine: ep93xx: hook callbacks via " Allen Pais
@ 2026-07-27 20:28 ` Allen Pais
2026-07-27 20:28 ` [PATCH v2 07/64] dmaengine: fsl_raid: run completions via " Allen Pais
` (58 subsequent siblings)
64 siblings, 0 replies; 82+ messages in thread
From: Allen Pais @ 2026-07-27 20:28 UTC (permalink / raw)
To: Vinod Koul, Frank Li
Cc: Allen Pais, dmaengine, linux-kernel, Arnd Bergmann, Kees Cook,
Zhang Wei, linuxppc-dev
Replace the per-channel tasklet with the shared dma_chan BH helper.
The handler continues to run in softirq context while dmaengine owns
the common scheduling and teardown mechanism.
Signed-off-by: Allen Pais <allen.lkml@gmail.com>
---
drivers/dma/fsldma.c | 10 +++++-----
drivers/dma/fsldma.h | 1 -
2 files changed, 5 insertions(+), 6 deletions(-)
diff --git a/drivers/dma/fsldma.c b/drivers/dma/fsldma.c
index 22d62d958abd..1cb6ce327078 100644
--- a/drivers/dma/fsldma.c
+++ b/drivers/dma/fsldma.c
@@ -968,18 +968,18 @@ static irqreturn_t fsldma_chan_irq(int irq, void *data)
chan_err(chan, "irq: unhandled sr 0x%08x\n", stat);
/*
- * Schedule the tasklet to handle all cleanup of the current
+ * Queue the BH worker to handle all cleanup of the current
* transaction. It will start a new transaction if there is
* one pending.
*/
- tasklet_schedule(&chan->tasklet);
+ dma_chan_schedule_bh(&chan->common);
chan_dbg(chan, "irq: Exit\n");
return IRQ_HANDLED;
}
-static void dma_do_tasklet(struct tasklet_struct *t)
+static void dma_do_tasklet(struct dma_chan *c)
{
- struct fsldma_chan *chan = from_tasklet(chan, t, tasklet);
+ struct fsldma_chan *chan = to_fsl_chan(c);
chan_dbg(chan, "tasklet entry\n");
@@ -1152,7 +1152,7 @@ static int fsl_dma_chan_probe(struct fsldma_device *fdev,
}
fdev->chan[chan->id] = chan;
- tasklet_setup(&chan->tasklet, dma_do_tasklet);
+ dma_chan_init_bh(&chan->common, dma_do_tasklet);
snprintf(chan->name, sizeof(chan->name), "chan%d", chan->id);
/* Initialize the channel */
diff --git a/drivers/dma/fsldma.h b/drivers/dma/fsldma.h
index d7b7a3138b85..cab33d010d51 100644
--- a/drivers/dma/fsldma.h
+++ b/drivers/dma/fsldma.h
@@ -173,7 +173,6 @@ struct fsldma_chan {
struct device *dev; /* Channel device */
int irq; /* Channel IRQ */
int id; /* Raw id of this channel */
- struct tasklet_struct tasklet;
u32 feature;
bool idle; /* DMA controller is idle */
#ifdef CONFIG_PM
--
2.43.0
^ permalink raw reply related [flat|nested] 82+ messages in thread
* [PATCH v2 07/64] dmaengine: fsl_raid: run completions via dma_chan BH
2026-07-27 20:28 ` [PATCH v2 00/64] dmaengine: migrate channel tasklets to WQ_BH Allen Pais
` (5 preceding siblings ...)
2026-07-27 20:28 ` [PATCH v2 06/64] dmaengine: fsldma: migrate tasklet to " Allen Pais
@ 2026-07-27 20:28 ` Allen Pais
2026-07-27 20:28 ` [PATCH v2 08/64] dmaengine: imx-dma: flip per-chan tasklet to " Allen Pais
` (57 subsequent siblings)
64 siblings, 0 replies; 82+ messages in thread
From: Allen Pais @ 2026-07-27 20:28 UTC (permalink / raw)
To: Vinod Koul, Frank Li
Cc: Allen Pais, dmaengine, linux-kernel, Arnd Bergmann, Kees Cook
Replace the per-channel tasklet with the shared dma_chan BH helper.
The handler continues to run in softirq context while dmaengine owns
the common scheduling and teardown mechanism.
Signed-off-by: Allen Pais <allen.lkml@gmail.com>
---
drivers/dma/fsl_raid.c | 11 ++++++-----
drivers/dma/fsl_raid.h | 1 -
2 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/drivers/dma/fsl_raid.c b/drivers/dma/fsl_raid.c
index 99945845d8b5..e91c18d3c327 100644
--- a/drivers/dma/fsl_raid.c
+++ b/drivers/dma/fsl_raid.c
@@ -155,9 +155,10 @@ static void fsl_re_cleanup_descs(struct fsl_re_chan *re_chan)
fsl_re_issue_pending(&re_chan->chan);
}
-static void fsl_re_dequeue(struct tasklet_struct *t)
+static void fsl_re_dequeue(struct dma_chan *chan)
{
- struct fsl_re_chan *re_chan = from_tasklet(re_chan, t, irqtask);
+ struct fsl_re_chan *re_chan = container_of(chan, struct fsl_re_chan,
+ chan);
struct fsl_re_desc *desc, *_desc;
struct fsl_re_hw_desc *hwdesc;
unsigned long flags;
@@ -224,7 +225,7 @@ static irqreturn_t fsl_re_isr(int irq, void *data)
/* Clear interrupt */
out_be32(&re_chan->jrregs->jr_interrupt_status, FSL_RE_CLR_INTR);
- tasklet_schedule(&re_chan->irqtask);
+ dma_chan_schedule_bh(&re_chan->chan);
return IRQ_HANDLED;
}
@@ -670,7 +671,7 @@ static int fsl_re_chan_probe(struct platform_device *ofdev,
snprintf(chan->name, sizeof(chan->name), "re_jr%02d", q);
chandev = &chan_ofdev->dev;
- tasklet_setup(&chan->irqtask, fsl_re_dequeue);
+ dma_chan_init_bh(&chan->chan, fsl_re_dequeue);
ret = request_irq(chan->irq, fsl_re_isr, 0, chan->name, chandev);
if (ret) {
@@ -846,7 +847,7 @@ static int fsl_re_probe(struct platform_device *ofdev)
static void fsl_re_remove_chan(struct fsl_re_chan *chan)
{
- tasklet_kill(&chan->irqtask);
+ dma_chan_kill_bh(&chan->chan);
dma_pool_free(chan->re_dev->hw_desc_pool, chan->inb_ring_virt_addr,
chan->inb_phys_addr);
diff --git a/drivers/dma/fsl_raid.h b/drivers/dma/fsl_raid.h
index 69d743c04973..a40001a4db58 100644
--- a/drivers/dma/fsl_raid.h
+++ b/drivers/dma/fsl_raid.h
@@ -275,7 +275,6 @@ struct fsl_re_chan {
struct dma_chan chan;
struct fsl_re_chan_cfg *jrregs;
int irq;
- struct tasklet_struct irqtask;
u32 alloc_count;
/* hw descriptor ring for inbound queue*/
--
2.43.0
^ permalink raw reply related [flat|nested] 82+ messages in thread
* [PATCH v2 08/64] dmaengine: imx-dma: flip per-chan tasklet to dma_chan BH
2026-07-27 20:28 ` [PATCH v2 00/64] dmaengine: migrate channel tasklets to WQ_BH Allen Pais
` (6 preceding siblings ...)
2026-07-27 20:28 ` [PATCH v2 07/64] dmaengine: fsl_raid: run completions via " Allen Pais
@ 2026-07-27 20:28 ` Allen Pais
2026-07-27 20:28 ` [PATCH v2 09/64] dmaengine: ioat: convert cleanup " Allen Pais
` (56 subsequent siblings)
64 siblings, 0 replies; 82+ messages in thread
From: Allen Pais @ 2026-07-27 20:28 UTC (permalink / raw)
To: Vinod Koul, Frank Li
Cc: Allen Pais, dmaengine, linux-kernel, Arnd Bergmann, Kees Cook,
Sascha Hauer, Pengutronix Kernel Team, Fabio Estevam, imx,
linux-arm-kernel
Replace the per-channel tasklet with the shared dma_chan BH helper.
The handler continues to run in softirq context while dmaengine owns
the common scheduling and teardown mechanism.
Signed-off-by: Allen Pais <allen.lkml@gmail.com>
---
drivers/dma/imx-dma.c | 26 +++++++++++++-------------
1 file changed, 13 insertions(+), 13 deletions(-)
diff --git a/drivers/dma/imx-dma.c b/drivers/dma/imx-dma.c
index 81c6276436f8..3ff0bfbfa5ff 100644
--- a/drivers/dma/imx-dma.c
+++ b/drivers/dma/imx-dma.c
@@ -145,7 +145,6 @@ struct imxdma_channel {
struct imxdma_engine *imxdma;
unsigned int channel;
- struct tasklet_struct dma_tasklet;
struct list_head ld_free;
struct list_head ld_queue;
struct list_head ld_active;
@@ -344,8 +343,8 @@ static void imxdma_watchdog(struct timer_list *t)
imx_dmav1_writel(imxdma, 0, DMA_CCR(channel));
- /* Tasklet watchdog error handler */
- tasklet_schedule(&imxdmac->dma_tasklet);
+ /* BH watchdog error handler */
+ dma_chan_schedule_bh(&imxdmac->chan);
dev_dbg(imxdma->dev, "channel %d: watchdog timeout!\n",
imxdmac->channel);
}
@@ -390,8 +389,8 @@ static irqreturn_t imxdma_err_handler(int irq, void *dev_id)
imx_dmav1_writel(imxdma, 1 << i, DMA_DBOSR);
errcode |= IMX_DMA_ERR_BUFFER;
}
- /* Tasklet error handler */
- tasklet_schedule(&imxdma->channel[i].dma_tasklet);
+ /* BH error handler */
+ dma_chan_schedule_bh(&imxdma->channel[i].chan);
dev_warn(imxdma->dev,
"DMA timeout on channel %d -%s%s%s%s\n", i,
@@ -448,8 +447,8 @@ static void dma_irq_handle_channel(struct imxdma_channel *imxdmac)
imx_dmav1_writel(imxdma, tmp, DMA_CCR(chno));
if (imxdma_chan_is_doing_cyclic(imxdmac))
- /* Tasklet progression */
- tasklet_schedule(&imxdmac->dma_tasklet);
+ /* BH progression */
+ dma_chan_schedule_bh(&imxdmac->chan);
return;
}
@@ -462,8 +461,8 @@ static void dma_irq_handle_channel(struct imxdma_channel *imxdmac)
out:
imx_dmav1_writel(imxdma, 0, DMA_CCR(chno));
- /* Tasklet irq */
- tasklet_schedule(&imxdmac->dma_tasklet);
+ /* Schedule the IRQ BH */
+ dma_chan_schedule_bh(&imxdmac->chan);
}
static irqreturn_t dma_irq_handler(int irq, void *dev_id)
@@ -592,9 +591,10 @@ static int imxdma_xfer_desc(struct imxdma_desc *d)
return 0;
}
-static void imxdma_tasklet(struct tasklet_struct *t)
+static void imxdma_tasklet(struct dma_chan *chan)
{
- struct imxdma_channel *imxdmac = from_tasklet(imxdmac, t, dma_tasklet);
+ struct imxdma_channel *imxdmac = container_of(chan, struct imxdma_channel,
+ chan);
struct imxdma_engine *imxdma = imxdmac->imxdma;
struct imxdma_desc *desc, *next_desc;
unsigned long flags;
@@ -1142,7 +1142,7 @@ static int __init imxdma_probe(struct platform_device *pdev)
INIT_LIST_HEAD(&imxdmac->ld_free);
INIT_LIST_HEAD(&imxdmac->ld_active);
- tasklet_setup(&imxdmac->dma_tasklet, imxdma_tasklet);
+ dma_chan_init_bh(&imxdmac->chan, imxdma_tasklet);
imxdmac->chan.device = &imxdma->dma_device;
dma_cookie_init(&imxdmac->chan);
imxdmac->channel = i;
@@ -1211,7 +1211,7 @@ static void imxdma_free_irq(struct platform_device *pdev, struct imxdma_engine *
if (!is_imx1_dma(imxdma))
disable_irq(imxdmac->irq);
- tasklet_kill(&imxdmac->dma_tasklet);
+ dma_chan_kill_bh(&imxdmac->chan);
}
}
--
2.43.0
^ permalink raw reply related [flat|nested] 82+ messages in thread
* [PATCH v2 09/64] dmaengine: ioat: convert cleanup tasklet to dma_chan BH
2026-07-27 20:28 ` [PATCH v2 00/64] dmaengine: migrate channel tasklets to WQ_BH Allen Pais
` (7 preceding siblings ...)
2026-07-27 20:28 ` [PATCH v2 08/64] dmaengine: imx-dma: flip per-chan tasklet to " Allen Pais
@ 2026-07-27 20:28 ` Allen Pais
2026-07-27 20:38 ` Dave Jiang
2026-07-27 20:28 ` [PATCH v2 10/64] dmaengine: mmp_pdma: replace per-chan tasklet with " Allen Pais
` (55 subsequent siblings)
64 siblings, 1 reply; 82+ messages in thread
From: Allen Pais @ 2026-07-27 20:28 UTC (permalink / raw)
To: Vinod Koul, Frank Li
Cc: Allen Pais, dmaengine, linux-kernel, Arnd Bergmann, Kees Cook,
Dave Jiang, Thomas Weißschuh, David Matlack, Lukas Wunner,
Giovanni Cabiddu
Replace the per-channel tasklet with the shared dma_chan BH helper.
The handler continues to run in softirq context while dmaengine owns
the common scheduling and teardown mechanism.
Signed-off-by: Allen Pais <allen.lkml@gmail.com>
---
drivers/dma/ioat/dma.c | 14 +++++++-------
drivers/dma/ioat/dma.h | 3 +--
drivers/dma/ioat/init.c | 2 +-
3 files changed, 9 insertions(+), 10 deletions(-)
diff --git a/drivers/dma/ioat/dma.c b/drivers/dma/ioat/dma.c
index ee93b029f9e3..827b46c6354a 100644
--- a/drivers/dma/ioat/dma.c
+++ b/drivers/dma/ioat/dma.c
@@ -110,7 +110,7 @@ irqreturn_t ioat_dma_do_interrupt(int irq, void *data)
for_each_set_bit(bit, &attnstatus, BITS_PER_LONG) {
ioat_chan = ioat_chan_by_index(instance, bit);
if (test_bit(IOAT_RUN, &ioat_chan->state))
- tasklet_schedule(&ioat_chan->cleanup_task);
+ dma_chan_schedule_bh(&ioat_chan->dma_chan);
}
writeb(intrctrl, instance->reg_base + IOAT_INTRCTRL_OFFSET);
@@ -127,7 +127,7 @@ irqreturn_t ioat_dma_do_interrupt_msix(int irq, void *data)
struct ioatdma_chan *ioat_chan = data;
if (test_bit(IOAT_RUN, &ioat_chan->state))
- tasklet_schedule(&ioat_chan->cleanup_task);
+ dma_chan_schedule_bh(&ioat_chan->dma_chan);
return IRQ_HANDLED;
}
@@ -161,11 +161,11 @@ void ioat_stop(struct ioatdma_chan *ioat_chan)
/* flush inflight timers */
timer_delete_sync(&ioat_chan->timer);
- /* flush inflight tasklet runs */
- tasklet_kill(&ioat_chan->cleanup_task);
+ /* flush inflight BH runs */
+ dma_chan_kill_bh(&ioat_chan->dma_chan);
/* final cleanup now that everything is quiesced and can't re-arm */
- ioat_cleanup_event(&ioat_chan->cleanup_task);
+ ioat_cleanup_event(&ioat_chan->dma_chan);
}
static void __ioat_issue_pending(struct ioatdma_chan *ioat_chan)
@@ -690,9 +690,9 @@ static void ioat_cleanup(struct ioatdma_chan *ioat_chan)
spin_unlock_bh(&ioat_chan->cleanup_lock);
}
-void ioat_cleanup_event(struct tasklet_struct *t)
+void ioat_cleanup_event(struct dma_chan *c)
{
- struct ioatdma_chan *ioat_chan = from_tasklet(ioat_chan, t, cleanup_task);
+ struct ioatdma_chan *ioat_chan = to_ioat_chan(c);
ioat_cleanup(ioat_chan);
if (!test_bit(IOAT_RUN, &ioat_chan->state))
diff --git a/drivers/dma/ioat/dma.h b/drivers/dma/ioat/dma.h
index e8a880f338c6..4bdb1ae937e4 100644
--- a/drivers/dma/ioat/dma.h
+++ b/drivers/dma/ioat/dma.h
@@ -111,7 +111,6 @@ struct ioatdma_chan {
struct ioatdma_device *ioat_dma;
dma_addr_t completion_dma;
u64 *completion;
- struct tasklet_struct cleanup_task;
struct kobject kobj;
/* ioat v2 / v3 channel attributes
@@ -385,7 +384,7 @@ int ioat_reset_hw(struct ioatdma_chan *ioat_chan);
enum dma_status
ioat_tx_status(struct dma_chan *c, dma_cookie_t cookie,
struct dma_tx_state *txstate);
-void ioat_cleanup_event(struct tasklet_struct *t);
+void ioat_cleanup_event(struct dma_chan *c);
void ioat_timer_event(struct timer_list *t);
int ioat_check_space_lock(struct ioatdma_chan *ioat_chan, int num_descs);
void ioat_issue_pending(struct dma_chan *chan);
diff --git a/drivers/dma/ioat/init.c b/drivers/dma/ioat/init.c
index 737496391109..314676e1cbc4 100644
--- a/drivers/dma/ioat/init.c
+++ b/drivers/dma/ioat/init.c
@@ -765,7 +765,7 @@ ioat_init_channel(struct ioatdma_device *ioat_dma,
list_add_tail(&ioat_chan->dma_chan.device_node, &dma->channels);
ioat_dma->idx[idx] = ioat_chan;
timer_setup(&ioat_chan->timer, ioat_timer_event, 0);
- tasklet_setup(&ioat_chan->cleanup_task, ioat_cleanup_event);
+ dma_chan_init_bh(&ioat_chan->dma_chan, ioat_cleanup_event);
}
#define IOAT_NUM_SRC_TEST 6 /* must be <= 8 */
--
2.43.0
^ permalink raw reply related [flat|nested] 82+ messages in thread
* [PATCH v2 10/64] dmaengine: mmp_pdma: replace per-chan tasklet with dma_chan BH
2026-07-27 20:28 ` [PATCH v2 00/64] dmaengine: migrate channel tasklets to WQ_BH Allen Pais
` (8 preceding siblings ...)
2026-07-27 20:28 ` [PATCH v2 09/64] dmaengine: ioat: convert cleanup " Allen Pais
@ 2026-07-27 20:28 ` Allen Pais
2026-07-27 20:28 ` [PATCH v2 11/64] dmaengine: mmp_tdma: hook completions to " Allen Pais
` (54 subsequent siblings)
64 siblings, 0 replies; 82+ messages in thread
From: Allen Pais @ 2026-07-27 20:28 UTC (permalink / raw)
To: Vinod Koul, Frank Li
Cc: Allen Pais, dmaengine, linux-kernel, Arnd Bergmann, Kees Cook
Replace the per-channel tasklet with the shared dma_chan BH helper.
The handler continues to run in softirq context while dmaengine owns
the common scheduling and teardown mechanism.
Signed-off-by: Allen Pais <allen.lkml@gmail.com>
---
drivers/dma/mmp_pdma.c | 13 +++++--------
1 file changed, 5 insertions(+), 8 deletions(-)
diff --git a/drivers/dma/mmp_pdma.c b/drivers/dma/mmp_pdma.c
index 386e85cd4882..3fd9ef59a142 100644
--- a/drivers/dma/mmp_pdma.c
+++ b/drivers/dma/mmp_pdma.c
@@ -116,7 +116,6 @@ struct mmp_pdma_chan {
* is in cyclic mode */
/* channel's basic info */
- struct tasklet_struct tasklet;
u32 dcmd;
u32 drcmr;
u32 dev_addr;
@@ -374,7 +373,7 @@ static irqreturn_t mmp_pdma_chan_handler(int irq, void *dev_id)
if (clear_chan_irq(phy) != 0)
return IRQ_NONE;
- tasklet_schedule(&phy->vchan->tasklet);
+ dma_chan_schedule_bh(&phy->vchan->chan);
return IRQ_HANDLED;
}
@@ -1047,13 +1046,11 @@ static void mmp_pdma_issue_pending(struct dma_chan *dchan)
}
/*
- * dma_do_tasklet
- * Do call back
- * Start pending list
+ * dma_do_tasklet - BH worker to process completions and kick pending work
*/
-static void dma_do_tasklet(struct tasklet_struct *t)
+static void dma_do_tasklet(struct dma_chan *c)
{
- struct mmp_pdma_chan *chan = from_tasklet(chan, t, tasklet);
+ struct mmp_pdma_chan *chan = container_of(c, struct mmp_pdma_chan, chan);
struct mmp_pdma_desc_sw *desc, *_desc;
LIST_HEAD(chain_cleanup);
unsigned long flags;
@@ -1170,7 +1167,7 @@ static int mmp_pdma_chan_init(struct mmp_pdma_device *pdev, int idx, int irq)
spin_lock_init(&chan->desc_lock);
chan->dev = pdev->dev;
chan->chan.device = &pdev->device;
- tasklet_setup(&chan->tasklet, dma_do_tasklet);
+ dma_chan_init_bh(&chan->chan, dma_do_tasklet);
INIT_LIST_HEAD(&chan->chain_pending);
INIT_LIST_HEAD(&chan->chain_running);
--
2.43.0
^ permalink raw reply related [flat|nested] 82+ messages in thread
* [PATCH v2 11/64] dmaengine: mmp_tdma: hook completions to dma_chan BH
2026-07-27 20:28 ` [PATCH v2 00/64] dmaengine: migrate channel tasklets to WQ_BH Allen Pais
` (9 preceding siblings ...)
2026-07-27 20:28 ` [PATCH v2 10/64] dmaengine: mmp_pdma: replace per-chan tasklet with " Allen Pais
@ 2026-07-27 20:28 ` Allen Pais
2026-07-27 20:28 ` [PATCH v2 12/64] dmaengine: mv_xor: convert irq tasklet " Allen Pais
` (53 subsequent siblings)
64 siblings, 0 replies; 82+ messages in thread
From: Allen Pais @ 2026-07-27 20:28 UTC (permalink / raw)
To: Vinod Koul, Frank Li
Cc: Allen Pais, dmaengine, linux-kernel, Arnd Bergmann, Kees Cook
Replace the per-channel tasklet with the shared dma_chan BH helper.
The handler continues to run in softirq context while dmaengine owns
the common scheduling and teardown mechanism.
Signed-off-by: Allen Pais <allen.lkml@gmail.com>
---
drivers/dma/mmp_tdma.c | 9 ++++-----
1 file changed, 4 insertions(+), 5 deletions(-)
diff --git a/drivers/dma/mmp_tdma.c b/drivers/dma/mmp_tdma.c
index ba03321eeff7..d1ed2886f0e7 100644
--- a/drivers/dma/mmp_tdma.c
+++ b/drivers/dma/mmp_tdma.c
@@ -102,7 +102,6 @@ struct mmp_tdma_chan {
struct device *dev;
struct dma_chan chan;
struct dma_async_tx_descriptor desc;
- struct tasklet_struct tasklet;
struct mmp_tdma_desc *desc_arr;
dma_addr_t desc_arr_phys;
@@ -320,7 +319,7 @@ static irqreturn_t mmp_tdma_chan_handler(int irq, void *dev_id)
struct mmp_tdma_chan *tdmac = dev_id;
if (mmp_tdma_clear_chan_irq(tdmac) == 0) {
- tasklet_schedule(&tdmac->tasklet);
+ dma_chan_schedule_bh(&tdmac->chan);
return IRQ_HANDLED;
} else
return IRQ_NONE;
@@ -346,9 +345,9 @@ static irqreturn_t mmp_tdma_int_handler(int irq, void *dev_id)
return IRQ_NONE;
}
-static void dma_do_tasklet(struct tasklet_struct *t)
+static void dma_do_tasklet(struct dma_chan *c)
{
- struct mmp_tdma_chan *tdmac = from_tasklet(tdmac, t, tasklet);
+ struct mmp_tdma_chan *tdmac = container_of(c, struct mmp_tdma_chan, chan);
dmaengine_desc_get_callback_invoke(&tdmac->desc, NULL);
}
@@ -583,7 +582,7 @@ static int mmp_tdma_chan_init(struct mmp_tdma_device *tdev,
tdmac->pool = pool;
tdmac->status = DMA_COMPLETE;
tdev->tdmac[tdmac->idx] = tdmac;
- tasklet_setup(&tdmac->tasklet, dma_do_tasklet);
+ dma_chan_init_bh(&tdmac->chan, dma_do_tasklet);
/* add the channel to tdma_chan list */
list_add_tail(&tdmac->chan.device_node,
--
2.43.0
^ permalink raw reply related [flat|nested] 82+ messages in thread
* [PATCH v2 12/64] dmaengine: mv_xor: convert irq tasklet to dma_chan BH
2026-07-27 20:28 ` [PATCH v2 00/64] dmaengine: migrate channel tasklets to WQ_BH Allen Pais
` (10 preceding siblings ...)
2026-07-27 20:28 ` [PATCH v2 11/64] dmaengine: mmp_tdma: hook completions to " Allen Pais
@ 2026-07-27 20:28 ` Allen Pais
2026-07-27 20:28 ` [PATCH v2 13/64] dmaengine: mxs-dma: use dma_chan BH scheduling Allen Pais
` (52 subsequent siblings)
64 siblings, 0 replies; 82+ messages in thread
From: Allen Pais @ 2026-07-27 20:28 UTC (permalink / raw)
To: Vinod Koul, Frank Li
Cc: Allen Pais, dmaengine, linux-kernel, Arnd Bergmann, Kees Cook
Replace the per-channel tasklet with the shared dma_chan BH helper.
The handler continues to run in softirq context while dmaengine owns
the common scheduling and teardown mechanism.
Signed-off-by: Allen Pais <allen.lkml@gmail.com>
---
drivers/dma/mv_xor.c | 12 ++++++------
drivers/dma/mv_xor.h | 2 --
2 files changed, 6 insertions(+), 8 deletions(-)
diff --git a/drivers/dma/mv_xor.c b/drivers/dma/mv_xor.c
index 25ed61f1b089..3a70d565e1ef 100644
--- a/drivers/dma/mv_xor.c
+++ b/drivers/dma/mv_xor.c
@@ -327,7 +327,7 @@ static void mv_chan_slot_cleanup(struct mv_xor_chan *mv_chan)
* some descriptors are still waiting
* to be cleaned
*/
- tasklet_schedule(&mv_chan->irq_tasklet);
+ dma_chan_schedule_bh(&mv_chan->dmachan);
}
}
}
@@ -336,9 +336,9 @@ static void mv_chan_slot_cleanup(struct mv_xor_chan *mv_chan)
mv_chan->dmachan.completed_cookie = cookie;
}
-static void mv_xor_tasklet(struct tasklet_struct *t)
+static void mv_xor_tasklet(struct dma_chan *c)
{
- struct mv_xor_chan *chan = from_tasklet(chan, t, irq_tasklet);
+ struct mv_xor_chan *chan = to_mv_xor_chan(c);
spin_lock(&chan->lock);
mv_chan_slot_cleanup(chan);
@@ -372,7 +372,7 @@ mv_chan_alloc_slot(struct mv_xor_chan *mv_chan)
spin_unlock_bh(&mv_chan->lock);
/* try to free some slots if the allocation fails */
- tasklet_schedule(&mv_chan->irq_tasklet);
+ dma_chan_schedule_bh(&mv_chan->dmachan);
return NULL;
}
@@ -737,7 +737,7 @@ static irqreturn_t mv_xor_interrupt_handler(int irq, void *data)
if (intr_cause & XOR_INTR_ERRORS)
mv_chan_err_interrupt_handler(chan, intr_cause);
- tasklet_schedule(&chan->irq_tasklet);
+ dma_chan_schedule_bh(&chan->dmachan);
mv_chan_clear_eoc_cause(chan);
@@ -1107,7 +1107,7 @@ mv_xor_channel_add(struct mv_xor_device *xordev,
mv_chan->mmr_base = xordev->xor_base;
mv_chan->mmr_high_base = xordev->xor_high_base;
- tasklet_setup(&mv_chan->irq_tasklet, mv_xor_tasklet);
+ dma_chan_init_bh(&mv_chan->dmachan, mv_xor_tasklet);
/* clear errors before enabling interrupts */
mv_chan_clear_err_status(mv_chan);
diff --git a/drivers/dma/mv_xor.h b/drivers/dma/mv_xor.h
index c87cefd38a07..27774abe34a6 100644
--- a/drivers/dma/mv_xor.h
+++ b/drivers/dma/mv_xor.h
@@ -98,7 +98,6 @@ struct mv_xor_device {
* @device: parent device
* @common: common dmaengine channel object members
* @slots_allocated: records the actual size of the descriptor slot pool
- * @irq_tasklet: bottom half where mv_xor_slot_cleanup runs
* @op_in_desc: new mode of driver, each op is written to descriptor.
*/
struct mv_xor_chan {
@@ -118,7 +117,6 @@ struct mv_xor_chan {
struct dma_device dmadev;
struct dma_chan dmachan;
int slots_allocated;
- struct tasklet_struct irq_tasklet;
int op_in_desc;
char dummy_src[MV_XOR_MIN_BYTE_COUNT];
char dummy_dst[MV_XOR_MIN_BYTE_COUNT];
--
2.43.0
^ permalink raw reply related [flat|nested] 82+ messages in thread
* [PATCH v2 13/64] dmaengine: mxs-dma: use dma_chan BH scheduling
2026-07-27 20:28 ` [PATCH v2 00/64] dmaengine: migrate channel tasklets to WQ_BH Allen Pais
` (11 preceding siblings ...)
2026-07-27 20:28 ` [PATCH v2 12/64] dmaengine: mv_xor: convert irq tasklet " Allen Pais
@ 2026-07-27 20:28 ` Allen Pais
2026-07-27 20:28 ` [PATCH v2 14/64] dmaengine: nbpfaxi: switch callbacks to dma_chan BH Allen Pais
` (51 subsequent siblings)
64 siblings, 0 replies; 82+ messages in thread
From: Allen Pais @ 2026-07-27 20:28 UTC (permalink / raw)
To: Vinod Koul, Frank Li
Cc: Allen Pais, dmaengine, linux-kernel, Arnd Bergmann, Kees Cook,
Sascha Hauer, Pengutronix Kernel Team, Fabio Estevam, imx,
linux-arm-kernel
Replace the per-channel tasklet with the shared dma_chan BH helper.
The handler continues to run in softirq context while dmaengine owns
the common scheduling and teardown mechanism.
Signed-off-by: Allen Pais <allen.lkml@gmail.com>
---
drivers/dma/mxs-dma.c | 11 +++++------
1 file changed, 5 insertions(+), 6 deletions(-)
diff --git a/drivers/dma/mxs-dma.c b/drivers/dma/mxs-dma.c
index 7acb3d29dad3..8cecc0add82d 100644
--- a/drivers/dma/mxs-dma.c
+++ b/drivers/dma/mxs-dma.c
@@ -109,7 +109,6 @@ struct mxs_dma_chan {
struct mxs_dma_engine *mxs_dma;
struct dma_chan chan;
struct dma_async_tx_descriptor desc;
- struct tasklet_struct tasklet;
unsigned int chan_irq;
struct mxs_dma_ccw *ccw;
dma_addr_t ccw_phys;
@@ -300,9 +299,9 @@ static dma_cookie_t mxs_dma_tx_submit(struct dma_async_tx_descriptor *tx)
return dma_cookie_assign(tx);
}
-static void mxs_dma_tasklet(struct tasklet_struct *t)
+static void mxs_dma_tasklet(struct dma_chan *chan)
{
- struct mxs_dma_chan *mxs_chan = from_tasklet(mxs_chan, t, tasklet);
+ struct mxs_dma_chan *mxs_chan = to_mxs_dma_chan(chan);
dmaengine_desc_get_callback_invoke(&mxs_chan->desc, NULL);
}
@@ -386,8 +385,8 @@ static irqreturn_t mxs_dma_int_handler(int irq, void *dev_id)
dma_cookie_complete(&mxs_chan->desc);
}
- /* schedule tasklet on this channel */
- tasklet_schedule(&mxs_chan->tasklet);
+ /* schedule BH on this channel */
+ dma_chan_schedule_bh(&mxs_chan->chan);
return IRQ_HANDLED;
}
@@ -781,7 +780,7 @@ static int mxs_dma_probe(struct platform_device *pdev)
mxs_chan->chan.device = &mxs_dma->dma_device;
dma_cookie_init(&mxs_chan->chan);
- tasklet_setup(&mxs_chan->tasklet, mxs_dma_tasklet);
+ dma_chan_init_bh(&mxs_chan->chan, mxs_dma_tasklet);
/* Add the channel to mxs_chan list */
--
2.43.0
^ permalink raw reply related [flat|nested] 82+ messages in thread
* [PATCH v2 14/64] dmaengine: nbpfaxi: switch callbacks to dma_chan BH
2026-07-27 20:28 ` [PATCH v2 00/64] dmaengine: migrate channel tasklets to WQ_BH Allen Pais
` (12 preceding siblings ...)
2026-07-27 20:28 ` [PATCH v2 13/64] dmaengine: mxs-dma: use dma_chan BH scheduling Allen Pais
@ 2026-07-27 20:28 ` Allen Pais
2026-07-27 20:28 ` [PATCH v2 15/64] dmaengine: pch_dma: convert tasklet " Allen Pais
` (50 subsequent siblings)
64 siblings, 0 replies; 82+ messages in thread
From: Allen Pais @ 2026-07-27 20:28 UTC (permalink / raw)
To: Vinod Koul, Frank Li
Cc: Allen Pais, dmaengine, linux-kernel, Arnd Bergmann, Kees Cook
Replace the per-channel tasklet with the shared dma_chan BH helper.
The handler continues to run in softirq context while dmaengine owns
the common scheduling and teardown mechanism.
Signed-off-by: Allen Pais <allen.lkml@gmail.com>
---
drivers/dma/nbpfaxi.c | 13 ++++++-------
1 file changed, 6 insertions(+), 7 deletions(-)
diff --git a/drivers/dma/nbpfaxi.c b/drivers/dma/nbpfaxi.c
index 05d7321629cc..aea94451258a 100644
--- a/drivers/dma/nbpfaxi.c
+++ b/drivers/dma/nbpfaxi.c
@@ -174,7 +174,6 @@ struct nbpf_desc_page {
/**
* struct nbpf_channel - one DMAC channel
* @dma_chan: standard dmaengine channel object
- * @tasklet: channel specific tasklet used for callbacks
* @base: register address base
* @nbpf: DMAC
* @name: IRQ name
@@ -200,7 +199,6 @@ struct nbpf_desc_page {
*/
struct nbpf_channel {
struct dma_chan dma_chan;
- struct tasklet_struct tasklet;
void __iomem *base;
struct nbpf_device *nbpf;
char name[16];
@@ -1125,9 +1123,10 @@ static struct dma_chan *nbpf_of_xlate(struct of_phandle_args *dma_spec,
return dchan;
}
-static void nbpf_chan_tasklet(struct tasklet_struct *t)
+static void nbpf_chan_tasklet(struct dma_chan *c)
{
- struct nbpf_channel *chan = from_tasklet(chan, t, tasklet);
+ struct nbpf_channel *chan = container_of(c, struct nbpf_channel,
+ dma_chan);
struct nbpf_desc *desc, *tmp;
struct dmaengine_desc_callback cb;
@@ -1228,7 +1227,7 @@ static irqreturn_t nbpf_chan_irq(int irq, void *dev)
spin_unlock(&chan->lock);
if (bh)
- tasklet_schedule(&chan->tasklet);
+ dma_chan_schedule_bh(&chan->dma_chan);
return ret;
}
@@ -1272,7 +1271,7 @@ static int nbpf_chan_probe(struct nbpf_device *nbpf, int n)
snprintf(chan->name, sizeof(chan->name), "nbpf %d", n);
- tasklet_setup(&chan->tasklet, nbpf_chan_tasklet);
+ dma_chan_init_bh(&chan->dma_chan, nbpf_chan_tasklet);
ret = devm_request_irq(dma_dev->dev, chan->irq,
nbpf_chan_irq, IRQF_SHARED,
chan->name, chan);
@@ -1478,7 +1477,7 @@ static void nbpf_remove(struct platform_device *pdev)
devm_free_irq(&pdev->dev, chan->irq, chan);
- tasklet_kill(&chan->tasklet);
+ dma_chan_kill_bh(&chan->dma_chan);
}
of_dma_controller_free(pdev->dev.of_node);
--
2.43.0
^ permalink raw reply related [flat|nested] 82+ messages in thread
* [PATCH v2 15/64] dmaengine: pch_dma: convert tasklet to dma_chan BH
2026-07-27 20:28 ` [PATCH v2 00/64] dmaengine: migrate channel tasklets to WQ_BH Allen Pais
` (13 preceding siblings ...)
2026-07-27 20:28 ` [PATCH v2 14/64] dmaengine: nbpfaxi: switch callbacks to dma_chan BH Allen Pais
@ 2026-07-27 20:28 ` Allen Pais
2026-07-27 20:28 ` [PATCH v2 16/64] dmaengine: ppc4xx: replace irq tasklet with " Allen Pais
` (49 subsequent siblings)
64 siblings, 0 replies; 82+ messages in thread
From: Allen Pais @ 2026-07-27 20:28 UTC (permalink / raw)
To: Vinod Koul, Frank Li
Cc: Allen Pais, dmaengine, linux-kernel, Arnd Bergmann, Kees Cook
Replace the per-channel tasklet with the shared dma_chan BH helper.
The handler continues to run in softirq context while dmaengine owns
the common scheduling and teardown mechanism.
Signed-off-by: Allen Pais <allen.lkml@gmail.com>
---
drivers/dma/pch_dma.c | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/drivers/dma/pch_dma.c b/drivers/dma/pch_dma.c
index bf805f1024f6..b0044bea8fe4 100644
--- a/drivers/dma/pch_dma.c
+++ b/drivers/dma/pch_dma.c
@@ -91,7 +91,6 @@ struct pch_dma_chan {
struct dma_chan chan;
void __iomem *membase;
enum dma_transfer_direction dir;
- struct tasklet_struct tasklet;
unsigned long err_status;
spinlock_t lock;
@@ -665,9 +664,10 @@ static int pd_device_terminate_all(struct dma_chan *chan)
return 0;
}
-static void pdc_tasklet(struct tasklet_struct *t)
+static void pdc_tasklet(struct dma_chan *c)
{
- struct pch_dma_chan *pd_chan = from_tasklet(pd_chan, t, tasklet);
+ struct pch_dma_chan *pd_chan = container_of(c, struct pch_dma_chan,
+ chan);
unsigned long flags;
if (!pdc_is_idle(pd_chan)) {
@@ -707,7 +707,7 @@ static irqreturn_t pd_irq(int irq, void *devid)
if (sts0 & DMA_STATUS0_ERR(i))
set_bit(0, &pd_chan->err_status);
- tasklet_schedule(&pd_chan->tasklet);
+ dma_chan_schedule_bh(&pd_chan->chan);
ret0 = IRQ_HANDLED;
}
} else {
@@ -715,7 +715,7 @@ static irqreturn_t pd_irq(int irq, void *devid)
if (sts2 & DMA_STATUS2_ERR(i))
set_bit(0, &pd_chan->err_status);
- tasklet_schedule(&pd_chan->tasklet);
+ dma_chan_schedule_bh(&pd_chan->chan);
ret2 = IRQ_HANDLED;
}
}
@@ -877,7 +877,7 @@ static int pch_dma_probe(struct pci_dev *pdev,
INIT_LIST_HEAD(&pd_chan->queue);
INIT_LIST_HEAD(&pd_chan->free_list);
- tasklet_setup(&pd_chan->tasklet, pdc_tasklet);
+ dma_chan_init_bh(&pd_chan->chan, pdc_tasklet);
list_add_tail(&pd_chan->chan.device_node, &pd->dma.channels);
}
@@ -930,7 +930,7 @@ static void pch_dma_remove(struct pci_dev *pdev)
device_node) {
pd_chan = to_pd_chan(chan);
- tasklet_kill(&pd_chan->tasklet);
+ dma_chan_kill_bh(&pd_chan->chan);
}
dma_pool_destroy(pd->pool);
--
2.43.0
^ permalink raw reply related [flat|nested] 82+ messages in thread
* [PATCH v2 16/64] dmaengine: ppc4xx: replace irq tasklet with dma_chan BH
2026-07-27 20:28 ` [PATCH v2 00/64] dmaengine: migrate channel tasklets to WQ_BH Allen Pais
` (14 preceding siblings ...)
2026-07-27 20:28 ` [PATCH v2 15/64] dmaengine: pch_dma: convert tasklet " Allen Pais
@ 2026-07-27 20:28 ` Allen Pais
2026-07-27 20:28 ` [PATCH v2 17/64] dmaengine: ste_dma40: convert per-channel tasklet to " Allen Pais
` (48 subsequent siblings)
64 siblings, 0 replies; 82+ messages in thread
From: Allen Pais @ 2026-07-27 20:28 UTC (permalink / raw)
To: Vinod Koul, Frank Li
Cc: Allen Pais, dmaengine, linux-kernel, Arnd Bergmann, Kees Cook,
Colin Ian King
Replace the per-channel tasklet with the shared dma_chan BH helper.
The handler continues to run in softirq context while dmaengine owns
the common scheduling and teardown mechanism.
Signed-off-by: Allen Pais <allen.lkml@gmail.com>
---
drivers/dma/ppc4xx/adma.c | 14 +++++++-------
drivers/dma/ppc4xx/adma.h | 2 --
2 files changed, 7 insertions(+), 9 deletions(-)
diff --git a/drivers/dma/ppc4xx/adma.c b/drivers/dma/ppc4xx/adma.c
index 279a431ccae3..98cfd012ca5b 100644
--- a/drivers/dma/ppc4xx/adma.c
+++ b/drivers/dma/ppc4xx/adma.c
@@ -1658,9 +1658,9 @@ static void __ppc440spe_adma_slot_cleanup(struct ppc440spe_adma_chan *chan)
/**
* ppc440spe_adma_tasklet - clean up watch-dog initiator
*/
-static void ppc440spe_adma_tasklet(struct tasklet_struct *t)
+static void ppc440spe_adma_tasklet(struct dma_chan *c)
{
- struct ppc440spe_adma_chan *chan = from_tasklet(chan, t, irq_tasklet);
+ struct ppc440spe_adma_chan *chan = to_ppc440spe_adma_chan(c);
spin_lock_nested(&chan->lock, SINGLE_DEPTH_NESTING);
__ppc440spe_adma_slot_cleanup(chan);
@@ -1754,7 +1754,7 @@ static struct ppc440spe_adma_desc_slot *ppc440spe_adma_alloc_slots(
goto retry;
/* try to free some slots if the allocation fails */
- tasklet_schedule(&chan->irq_tasklet);
+ dma_chan_schedule_bh(&chan->common);
return NULL;
}
@@ -3595,7 +3595,7 @@ static irqreturn_t ppc440spe_adma_eot_handler(int irq, void *data)
dev_dbg(chan->device->common.dev,
"ppc440spe adma%d: %s\n", chan->device->id, __func__);
- tasklet_schedule(&chan->irq_tasklet);
+ dma_chan_schedule_bh(&chan->common);
ppc440spe_adma_device_clear_eot_status(chan);
return IRQ_HANDLED;
@@ -3612,7 +3612,7 @@ static irqreturn_t ppc440spe_adma_err_handler(int irq, void *data)
dev_dbg(chan->device->common.dev,
"ppc440spe adma%d: %s\n", chan->device->id, __func__);
- tasklet_schedule(&chan->irq_tasklet);
+ dma_chan_schedule_bh(&chan->common);
ppc440spe_adma_device_clear_eot_status(chan);
return IRQ_HANDLED;
@@ -4137,7 +4137,7 @@ static int ppc440spe_adma_probe(struct platform_device *ofdev)
chan->common.device = &adev->common;
dma_cookie_init(&chan->common);
list_add_tail(&chan->common.device_node, &adev->common.channels);
- tasklet_setup(&chan->irq_tasklet, ppc440spe_adma_tasklet);
+ dma_chan_init_bh(&chan->common, ppc440spe_adma_tasklet);
/* allocate and map helper pages for async validation or
* async_mult/async_sum_product operations on DMA0/1.
@@ -4247,7 +4247,7 @@ static void ppc440spe_adma_remove(struct platform_device *ofdev)
device_node) {
ppc440spe_chan = to_ppc440spe_adma_chan(chan);
ppc440spe_adma_release_irqs(adev, ppc440spe_chan);
- tasklet_kill(&ppc440spe_chan->irq_tasklet);
+ dma_chan_kill_bh(&ppc440spe_chan->common);
if (adev->id != PPC440SPE_XOR_ID) {
dma_unmap_page(&ofdev->dev, ppc440spe_chan->pdest,
PAGE_SIZE, DMA_BIDIRECTIONAL);
diff --git a/drivers/dma/ppc4xx/adma.h b/drivers/dma/ppc4xx/adma.h
index f8a5d7c1fb40..9af1feaf0b9a 100644
--- a/drivers/dma/ppc4xx/adma.h
+++ b/drivers/dma/ppc4xx/adma.h
@@ -80,7 +80,6 @@ struct ppc440spe_adma_device {
* @pending: allows batching of hardware operations
* @slots_allocated: records the actual size of the descriptor slot pool
* @hw_chain_inited: h/w descriptor chain initialization flag
- * @irq_tasklet: bottom half where ppc440spe_adma_slot_cleanup runs
* @needs_unmap: if buffers should not be unmapped upon final processing
* @pdest_page: P destination page for async validate operation
* @qdest_page: Q destination page for async validate operation
@@ -97,7 +96,6 @@ struct ppc440spe_adma_chan {
int pending;
int slots_allocated;
int hw_chain_inited;
- struct tasklet_struct irq_tasklet;
u8 needs_unmap;
struct page *pdest_page;
struct page *qdest_page;
--
2.43.0
^ permalink raw reply related [flat|nested] 82+ messages in thread
* [PATCH v2 17/64] dmaengine: ste_dma40: convert per-channel tasklet to dma_chan BH
2026-07-27 20:28 ` [PATCH v2 00/64] dmaengine: migrate channel tasklets to WQ_BH Allen Pais
` (15 preceding siblings ...)
2026-07-27 20:28 ` [PATCH v2 16/64] dmaengine: ppc4xx: replace irq tasklet with " Allen Pais
@ 2026-07-27 20:28 ` Allen Pais
2026-07-28 19:33 ` Linus Walleij
2026-07-27 20:28 ` [PATCH v2 18/64] dmaengine: xgene-dma: wire descriptor cleanup " Allen Pais
` (47 subsequent siblings)
64 siblings, 1 reply; 82+ messages in thread
From: Allen Pais @ 2026-07-27 20:28 UTC (permalink / raw)
To: Vinod Koul, Frank Li
Cc: Allen Pais, dmaengine, linux-kernel, Arnd Bergmann, Kees Cook,
Linus Walleij, linux-arm-kernel
Replace the per-channel tasklet with the shared dma_chan BH helper.
The handler continues to run in softirq context while dmaengine owns
the common scheduling and teardown mechanism.
Signed-off-by: Allen Pais <allen.lkml@gmail.com>
---
drivers/dma/ste_dma40.c | 13 +++++--------
1 file changed, 5 insertions(+), 8 deletions(-)
diff --git a/drivers/dma/ste_dma40.c b/drivers/dma/ste_dma40.c
index 0d9ffa3e2663..f279a093a81f 100644
--- a/drivers/dma/ste_dma40.c
+++ b/drivers/dma/ste_dma40.c
@@ -461,8 +461,6 @@ struct d40_base;
* @phy_chan: Pointer to physical channel which this instance runs on. If this
* point is NULL, then the channel is not allocated.
* @chan: DMA engine handle.
- * @tasklet: Tasklet that gets scheduled from interrupt context to complete a
- * transfer and call client callback.
* @client: Cliented owned descriptor list.
* @pending_queue: Submitted jobs, to be issued by issue_pending()
* @active: Active descriptor.
@@ -489,7 +487,6 @@ struct d40_chan {
bool busy;
struct d40_phy_res *phy_chan;
struct dma_chan chan;
- struct tasklet_struct tasklet;
struct list_head client;
struct list_head pending_queue;
struct list_head active;
@@ -1587,13 +1584,13 @@ static void dma_tc_handle(struct d40_chan *d40c)
}
d40c->pending_tx++;
- tasklet_schedule(&d40c->tasklet);
+ dma_chan_schedule_bh(&d40c->chan);
}
-static void dma_tasklet(struct tasklet_struct *t)
+static void dma_tasklet(struct dma_chan *chan)
{
- struct d40_chan *d40c = from_tasklet(d40c, t, tasklet);
+ struct d40_chan *d40c = container_of(chan, struct d40_chan, chan);
struct d40_desc *d40d;
unsigned long flags;
bool callback_active;
@@ -1641,7 +1638,7 @@ static void dma_tasklet(struct tasklet_struct *t)
d40c->pending_tx--;
if (d40c->pending_tx)
- tasklet_schedule(&d40c->tasklet);
+ dma_chan_schedule_bh(&d40c->chan);
spin_unlock_irqrestore(&d40c->lock, flags);
@@ -2815,7 +2812,7 @@ static void __init d40_chan_init(struct d40_base *base, struct dma_device *dma,
INIT_LIST_HEAD(&d40c->client);
INIT_LIST_HEAD(&d40c->prepare_queue);
- tasklet_setup(&d40c->tasklet, dma_tasklet);
+ dma_chan_init_bh(&d40c->chan, dma_tasklet);
list_add_tail(&d40c->chan.device_node,
&dma->channels);
--
2.43.0
^ permalink raw reply related [flat|nested] 82+ messages in thread
* [PATCH v2 18/64] dmaengine: xgene-dma: wire descriptor cleanup to dma_chan BH
2026-07-27 20:28 ` [PATCH v2 00/64] dmaengine: migrate channel tasklets to WQ_BH Allen Pais
` (16 preceding siblings ...)
2026-07-27 20:28 ` [PATCH v2 17/64] dmaengine: ste_dma40: convert per-channel tasklet to " Allen Pais
@ 2026-07-27 20:28 ` Allen Pais
2026-07-27 20:28 ` [PATCH v2 19/64] dmaengine: xilinx-dma: use dma_chan BH instead of tasklets Allen Pais
` (46 subsequent siblings)
64 siblings, 0 replies; 82+ messages in thread
From: Allen Pais @ 2026-07-27 20:28 UTC (permalink / raw)
To: Vinod Koul, Frank Li
Cc: Allen Pais, dmaengine, linux-kernel, Arnd Bergmann, Kees Cook
Replace the per-channel tasklet with the shared dma_chan BH helper.
The handler continues to run in softirq context while dmaengine owns
the common scheduling and teardown mechanism.
Signed-off-by: Allen Pais <allen.lkml@gmail.com>
---
drivers/dma/xgene-dma.c | 19 +++++++++----------
1 file changed, 9 insertions(+), 10 deletions(-)
diff --git a/drivers/dma/xgene-dma.c b/drivers/dma/xgene-dma.c
index fa1173e49900..8d0428c2944e 100644
--- a/drivers/dma/xgene-dma.c
+++ b/drivers/dma/xgene-dma.c
@@ -260,7 +260,6 @@ struct xgene_dma_desc_sw {
* These descriptors have already had their cleanup actions run. They
* are waiting for the ACK bit to be set by the async tx API.
* @desc_pool: descriptor pool for DMA operations
- * @tasklet: bottom half where all completed descriptors cleans
* @tx_ring: transmit ring descriptor that we use to prepare actual
* descriptors for further executions
* @rx_ring: receive ring descriptor that we use to get completed DMA
@@ -280,7 +279,6 @@ struct xgene_dma_chan {
struct list_head ld_running;
struct list_head ld_completed;
struct dma_pool *desc_pool;
- struct tasklet_struct tasklet;
struct xgene_dma_ring tx_ring;
struct xgene_dma_ring rx_ring;
};
@@ -975,9 +973,10 @@ static enum dma_status xgene_dma_tx_status(struct dma_chan *dchan,
return dma_cookie_status(dchan, cookie, txstate);
}
-static void xgene_dma_tasklet_cb(struct tasklet_struct *t)
+static void xgene_dma_tasklet_cb(struct dma_chan *c)
{
- struct xgene_dma_chan *chan = from_tasklet(chan, t, tasklet);
+ struct xgene_dma_chan *chan = container_of(c, struct xgene_dma_chan,
+ dma_chan);
/* Run all cleanup for descriptors which have been completed */
xgene_dma_cleanup_descriptors(chan);
@@ -999,11 +998,11 @@ static irqreturn_t xgene_dma_chan_ring_isr(int irq, void *id)
disable_irq_nosync(chan->rx_irq);
/*
- * Schedule the tasklet to handle all cleanup of the current
+ * Schedule the bottom half to handle all cleanup of the current
* transaction. It will start a new transaction if there is
* one pending.
*/
- tasklet_schedule(&chan->tasklet);
+ dma_chan_schedule_bh(&chan->dma_chan);
return IRQ_HANDLED;
}
@@ -1539,7 +1538,7 @@ static int xgene_dma_async_register(struct xgene_dma *pdma, int id)
INIT_LIST_HEAD(&chan->ld_pending);
INIT_LIST_HEAD(&chan->ld_running);
INIT_LIST_HEAD(&chan->ld_completed);
- tasklet_setup(&chan->tasklet, xgene_dma_tasklet_cb);
+ dma_chan_init_bh(&chan->dma_chan, xgene_dma_tasklet_cb);
chan->pending = 0;
chan->desc_pool = NULL;
@@ -1556,7 +1555,7 @@ static int xgene_dma_async_register(struct xgene_dma *pdma, int id)
ret = dma_async_device_register(dma_dev);
if (ret) {
chan_err(chan, "Failed to register async device %d", ret);
- tasklet_kill(&chan->tasklet);
+ dma_chan_kill_bh(&chan->dma_chan);
return ret;
}
@@ -1579,7 +1578,7 @@ static int xgene_dma_init_async(struct xgene_dma *pdma)
if (ret) {
for (j = 0; j < i; j++) {
dma_async_device_unregister(&pdma->dma_dev[j]);
- tasklet_kill(&pdma->chan[j].tasklet);
+ dma_chan_kill_bh(&pdma->chan[j].dma_chan);
}
return ret;
@@ -1790,7 +1789,7 @@ static void xgene_dma_remove(struct platform_device *pdev)
for (i = 0; i < XGENE_DMA_MAX_CHANNEL; i++) {
chan = &pdma->chan[i];
- tasklet_kill(&chan->tasklet);
+ dma_chan_kill_bh(&chan->dma_chan);
xgene_dma_delete_chan_rings(chan);
}
--
2.43.0
^ permalink raw reply related [flat|nested] 82+ messages in thread
* [PATCH v2 19/64] dmaengine: xilinx-dma: use dma_chan BH instead of tasklets
2026-07-27 20:28 ` [PATCH v2 00/64] dmaengine: migrate channel tasklets to WQ_BH Allen Pais
` (17 preceding siblings ...)
2026-07-27 20:28 ` [PATCH v2 18/64] dmaengine: xgene-dma: wire descriptor cleanup " Allen Pais
@ 2026-07-27 20:28 ` Allen Pais
2026-07-27 20:28 ` [PATCH v2 20/64] dmaengine: xilinx-dpdma: kill vchan BH on remove Allen Pais
` (45 subsequent siblings)
64 siblings, 0 replies; 82+ messages in thread
From: Allen Pais @ 2026-07-27 20:28 UTC (permalink / raw)
To: Vinod Koul, Frank Li
Cc: Allen Pais, dmaengine, linux-kernel, Arnd Bergmann, Kees Cook,
Michal Simek, Suraj Gupta, Marek Vasut, Folker Schwesinger,
Tomi Valkeinen, Krzysztof Kozlowski, linux-arm-kernel
Replace the per-channel tasklet with the shared dma_chan BH helper.
The handler continues to run in softirq context while dmaengine owns
the common scheduling and teardown mechanism.
Signed-off-by: Allen Pais <allen.lkml@gmail.com>
---
drivers/dma/xilinx/xilinx_dma.c | 20 +++++++++-----------
1 file changed, 9 insertions(+), 11 deletions(-)
diff --git a/drivers/dma/xilinx/xilinx_dma.c b/drivers/dma/xilinx/xilinx_dma.c
index 404235c17353..bf9f22ed1265 100644
--- a/drivers/dma/xilinx/xilinx_dma.c
+++ b/drivers/dma/xilinx/xilinx_dma.c
@@ -402,7 +402,6 @@ struct xilinx_dma_tx_descriptor {
* @err: Channel has errors
* @idle: Check for channel idle
* @terminating: Check for channel being synchronized by user
- * @tasklet: Cleanup work after irq
* @config: Device configuration info
* @flush_on_fsync: Flush on Frame sync
* @desc_pendingcount: Descriptor pending count
@@ -441,7 +440,6 @@ struct xilinx_dma_chan {
bool err;
bool idle;
bool terminating;
- struct tasklet_struct tasklet;
struct xilinx_vdma_config config;
bool flush_on_fsync;
u32 desc_pendingcount;
@@ -1115,11 +1113,12 @@ static void xilinx_dma_chan_desc_cleanup(struct xilinx_dma_chan *chan)
/**
* xilinx_dma_do_tasklet - Schedule completion tasklet
- * @t: Pointer to the Xilinx DMA channel structure
+ * @c: Pointer to the Xilinx DMA channel structure
*/
-static void xilinx_dma_do_tasklet(struct tasklet_struct *t)
+static void xilinx_dma_do_tasklet(struct dma_chan *c)
{
- struct xilinx_dma_chan *chan = from_tasklet(chan, t, tasklet);
+ struct xilinx_dma_chan *chan = container_of(c,
+ struct xilinx_dma_chan, common);
xilinx_dma_chan_desc_cleanup(chan);
}
@@ -1898,7 +1897,7 @@ static irqreturn_t xilinx_mcdma_irq_handler(int irq, void *data)
spin_unlock(&chan->lock);
}
- tasklet_hi_schedule(&chan->tasklet);
+ dma_chan_schedule_bh(&chan->common);
return IRQ_HANDLED;
}
@@ -1955,7 +1954,7 @@ static irqreturn_t xilinx_dma_irq_handler(int irq, void *data)
spin_unlock(&chan->lock);
}
- tasklet_schedule(&chan->tasklet);
+ dma_chan_schedule_bh(&chan->common);
return IRQ_HANDLED;
}
@@ -2654,7 +2653,7 @@ static void xilinx_dma_synchronize(struct dma_chan *dchan)
{
struct xilinx_dma_chan *chan = to_xilinx_chan(dchan);
- tasklet_kill(&chan->tasklet);
+ dma_chan_kill_bh(&chan->common);
}
/**
@@ -2745,7 +2744,7 @@ static void xilinx_dma_chan_remove(struct xilinx_dma_chan *chan)
if (chan->irq > 0)
free_irq(chan->irq, chan);
- tasklet_kill(&chan->tasklet);
+ dma_chan_kill_bh(&chan->common);
list_del(&chan->common.device_node);
}
@@ -3075,8 +3074,7 @@ static int xilinx_dma_chan_probe(struct xilinx_dma_device *xdev,
str_enabled_disabled(chan->has_sg));
}
- /* Initialize the tasklet */
- tasklet_setup(&chan->tasklet, xilinx_dma_do_tasklet);
+ dma_chan_init_bh(&chan->common, xilinx_dma_do_tasklet);
/*
* Initialize the DMA channel and add it to the DMA engine channels
--
2.43.0
^ permalink raw reply related [flat|nested] 82+ messages in thread
* [PATCH v2 20/64] dmaengine: xilinx-dpdma: kill vchan BH on remove
2026-07-27 20:28 ` [PATCH v2 00/64] dmaengine: migrate channel tasklets to WQ_BH Allen Pais
` (18 preceding siblings ...)
2026-07-27 20:28 ` [PATCH v2 19/64] dmaengine: xilinx-dma: use dma_chan BH instead of tasklets Allen Pais
@ 2026-07-27 20:28 ` Allen Pais
2026-07-27 20:28 ` [PATCH v2 21/64] dmaengine: zynqmp-dma: switch completion tasklet to dma_chan BH Allen Pais
` (44 subsequent siblings)
64 siblings, 0 replies; 82+ messages in thread
From: Allen Pais @ 2026-07-27 20:28 UTC (permalink / raw)
To: Vinod Koul, Frank Li
Cc: Allen Pais, dmaengine, linux-kernel, Arnd Bergmann, Kees Cook,
Laurent Pinchart, Michal Simek, linux-arm-kernel
virt-dma now dispatches completion callbacks through per-channel BH
work. Cancel that work when removing a channel, while retaining the
driver's separate error-handling tasklet.
Signed-off-by: Allen Pais <allen.lkml@gmail.com>
---
drivers/dma/xilinx/xilinx_dpdma.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/dma/xilinx/xilinx_dpdma.c b/drivers/dma/xilinx/xilinx_dpdma.c
index d9a3542c4531..2ec82064fd2e 100644
--- a/drivers/dma/xilinx/xilinx_dpdma.c
+++ b/drivers/dma/xilinx/xilinx_dpdma.c
@@ -1685,6 +1685,7 @@ static void xilinx_dpdma_chan_remove(struct xilinx_dpdma_chan *chan)
return;
tasklet_kill(&chan->err_task);
+ dma_chan_kill_bh(&chan->vchan.chan);
list_del(&chan->vchan.chan.device_node);
}
--
2.43.0
^ permalink raw reply related [flat|nested] 82+ messages in thread
* [PATCH v2 21/64] dmaengine: zynqmp-dma: switch completion tasklet to dma_chan BH
2026-07-27 20:28 ` [PATCH v2 00/64] dmaengine: migrate channel tasklets to WQ_BH Allen Pais
` (19 preceding siblings ...)
2026-07-27 20:28 ` [PATCH v2 20/64] dmaengine: xilinx-dpdma: kill vchan BH on remove Allen Pais
@ 2026-07-27 20:28 ` Allen Pais
2026-07-27 20:28 ` [PATCH v2 22/64] dmaengine: tegra20-apb: use channel BH helpers Allen Pais
` (43 subsequent siblings)
64 siblings, 0 replies; 82+ messages in thread
From: Allen Pais @ 2026-07-27 20:28 UTC (permalink / raw)
To: Vinod Koul, Frank Li
Cc: Allen Pais, dmaengine, linux-kernel, Arnd Bergmann, Kees Cook,
Michal Simek, Abin Joseph, Radhey Shyam Pandey, Sakari Ailus,
linux-arm-kernel
Replace the per-channel tasklet with the shared dma_chan BH helper.
The handler continues to run in softirq context while dmaengine owns
the common scheduling and teardown mechanism.
Signed-off-by: Allen Pais <allen.lkml@gmail.com>
---
drivers/dma/xilinx/zynqmp_dma.c | 19 +++++++++----------
1 file changed, 9 insertions(+), 10 deletions(-)
diff --git a/drivers/dma/xilinx/zynqmp_dma.c b/drivers/dma/xilinx/zynqmp_dma.c
index f6a812e49ddc..6291126cdc9f 100644
--- a/drivers/dma/xilinx/zynqmp_dma.c
+++ b/drivers/dma/xilinx/zynqmp_dma.c
@@ -207,7 +207,6 @@ struct zynqmp_dma_desc_sw {
* @dev: The dma device
* @irq: Channel IRQ
* @is_dmacoherent: Tells whether dma operations are coherent or not
- * @tasklet: Cleanup work after irq
* @idle : Channel status;
* @desc_size: Size of the low level descriptor
* @err: Channel has errors
@@ -232,7 +231,6 @@ struct zynqmp_dma_chan {
struct device *dev;
int irq;
bool is_dmacoherent;
- struct tasklet_struct tasklet;
bool idle;
size_t desc_size;
bool err;
@@ -735,7 +733,7 @@ static irqreturn_t zynqmp_dma_irq_handler(int irq, void *data)
writel(isr, chan->regs + ZYNQMP_DMA_ISR);
if (status & ZYNQMP_DMA_INT_DONE) {
- tasklet_schedule(&chan->tasklet);
+ dma_chan_schedule_bh(&chan->common);
ret = IRQ_HANDLED;
}
@@ -744,7 +742,7 @@ static irqreturn_t zynqmp_dma_irq_handler(int irq, void *data)
if (status & ZYNQMP_DMA_INT_ERR) {
chan->err = true;
- tasklet_schedule(&chan->tasklet);
+ dma_chan_schedule_bh(&chan->common);
dev_err(chan->dev, "Channel %p has errors\n", chan);
ret = IRQ_HANDLED;
}
@@ -760,11 +758,12 @@ static irqreturn_t zynqmp_dma_irq_handler(int irq, void *data)
/**
* zynqmp_dma_do_tasklet - Schedule completion tasklet
- * @t: Pointer to the ZynqMP DMA channel structure
+ * @c: Pointer to the ZynqMP DMA channel structure
*/
-static void zynqmp_dma_do_tasklet(struct tasklet_struct *t)
+static void zynqmp_dma_do_tasklet(struct dma_chan *c)
{
- struct zynqmp_dma_chan *chan = from_tasklet(chan, t, tasklet);
+ struct zynqmp_dma_chan *chan = container_of(c,
+ struct zynqmp_dma_chan, common);
u32 count;
unsigned long irqflags;
@@ -815,7 +814,7 @@ static void zynqmp_dma_synchronize(struct dma_chan *dchan)
{
struct zynqmp_dma_chan *chan = to_chan(dchan);
- tasklet_kill(&chan->tasklet);
+ dma_chan_kill_bh(&chan->common);
}
/**
@@ -887,7 +886,7 @@ static void zynqmp_dma_chan_remove(struct zynqmp_dma_chan *chan)
if (chan->irq)
devm_free_irq(chan->zdev->dev, chan->irq, chan);
- tasklet_kill(&chan->tasklet);
+ dma_chan_kill_bh(&chan->common);
list_del(&chan->common.device_node);
}
@@ -937,7 +936,7 @@ static int zynqmp_dma_chan_probe(struct zynqmp_dma_device *zdev,
chan->is_dmacoherent = of_property_read_bool(node, "dma-coherent");
zdev->chan = chan;
- tasklet_setup(&chan->tasklet, zynqmp_dma_do_tasklet);
+ dma_chan_init_bh(&chan->common, zynqmp_dma_do_tasklet);
spin_lock_init(&chan->lock);
INIT_LIST_HEAD(&chan->active_list);
INIT_LIST_HEAD(&chan->pending_list);
--
2.43.0
^ permalink raw reply related [flat|nested] 82+ messages in thread
* [PATCH v2 22/64] dmaengine: tegra20-apb: use channel BH helpers
2026-07-27 20:28 ` [PATCH v2 00/64] dmaengine: migrate channel tasklets to WQ_BH Allen Pais
` (20 preceding siblings ...)
2026-07-27 20:28 ` [PATCH v2 21/64] dmaengine: zynqmp-dma: switch completion tasklet to dma_chan BH Allen Pais
@ 2026-07-27 20:28 ` Allen Pais
2026-07-27 20:28 ` [PATCH v2 23/64] dmaengine: timb_dma: route callbacks via channel BH Allen Pais
` (42 subsequent siblings)
64 siblings, 0 replies; 82+ messages in thread
From: Allen Pais @ 2026-07-27 20:28 UTC (permalink / raw)
To: Vinod Koul, Frank Li
Cc: Allen Pais, dmaengine, linux-kernel, Arnd Bergmann, Kees Cook,
Laxman Dewangan, Jon Hunter, Thierry Reding, linux-tegra
Switch the per-channel tasklet to dma_chan_*_bh so completion handling
runs through the shared per-channel deferral mechanism.
Signed-off-by: Allen Pais <allen.lkml@gmail.com>
---
drivers/dma/tegra20-apb-dma.c | 18 +++++++++---------
1 file changed, 9 insertions(+), 9 deletions(-)
diff --git a/drivers/dma/tegra20-apb-dma.c b/drivers/dma/tegra20-apb-dma.c
index 640b8a218c9a..de15b8d3e8cb 100644
--- a/drivers/dma/tegra20-apb-dma.c
+++ b/drivers/dma/tegra20-apb-dma.c
@@ -194,9 +194,8 @@ struct tegra_dma_channel {
struct list_head free_dma_desc;
struct list_head cb_desc;
- /* ISR handler and tasklet for bottom half of isr handling */
+ /* ISR handler for bottom-half processing */
dma_isr_handler isr_handler;
- struct tasklet_struct tasklet;
/* Channel-slave specific configuration */
unsigned int slave_id;
@@ -632,9 +631,10 @@ static void handle_cont_sngl_cycle_dma_done(struct tegra_dma_channel *tdc,
}
}
-static void tegra_dma_tasklet(struct tasklet_struct *t)
+static void tegra_dma_tasklet(struct dma_chan *chan)
{
- struct tegra_dma_channel *tdc = from_tasklet(tdc, t, tasklet);
+ struct tegra_dma_channel *tdc = container_of(chan, struct tegra_dma_channel,
+ dma_chan);
struct dmaengine_desc_callback cb;
struct tegra_dma_desc *dma_desc;
unsigned int cb_count;
@@ -670,7 +670,7 @@ static irqreturn_t tegra_dma_isr(int irq, void *dev_id)
if (status & TEGRA_APBDMA_STATUS_ISE_EOC) {
tdc_write(tdc, TEGRA_APBDMA_CHAN_STATUS, status);
tdc->isr_handler(tdc, false);
- tasklet_schedule(&tdc->tasklet);
+ dma_chan_schedule_bh(&tdc->dma_chan);
wake_up_all(&tdc->wq);
spin_unlock(&tdc->lock);
return IRQ_HANDLED;
@@ -819,7 +819,7 @@ static void tegra_dma_synchronize(struct dma_chan *dc)
*/
wait_event(tdc->wq, tegra_dma_eoc_interrupt_deasserted(tdc));
- tasklet_kill(&tdc->tasklet);
+ dma_chan_kill_bh(&tdc->dma_chan);
pm_runtime_put(tdc->tdma->dev);
}
@@ -1317,7 +1317,7 @@ static void tegra_dma_free_chan_resources(struct dma_chan *dc)
dev_dbg(tdc2dev(tdc), "Freeing channel %d\n", tdc->id);
tegra_dma_terminate_all(dc);
- tasklet_kill(&tdc->tasklet);
+ dma_chan_kill_bh(&tdc->dma_chan);
list_splice_init(&tdc->pending_sg_req, &sg_req_list);
list_splice_init(&tdc->free_sg_req, &sg_req_list);
@@ -1511,7 +1511,7 @@ static int tegra_dma_probe(struct platform_device *pdev)
tdc->id = i;
tdc->slave_id = TEGRA_APBDMA_SLAVE_ID_INVALID;
- tasklet_setup(&tdc->tasklet, tegra_dma_tasklet);
+ dma_chan_init_bh(&tdc->dma_chan, tegra_dma_tasklet);
spin_lock_init(&tdc->lock);
init_waitqueue_head(&tdc->wq);
@@ -1617,7 +1617,7 @@ static int __maybe_unused tegra_dma_dev_suspend(struct device *dev)
for (i = 0; i < tdma->chip_data->nr_channels; i++) {
struct tegra_dma_channel *tdc = &tdma->channels[i];
- tasklet_kill(&tdc->tasklet);
+ dma_chan_kill_bh(&tdc->dma_chan);
spin_lock_irqsave(&tdc->lock, flags);
busy = tdc->busy;
--
2.43.0
^ permalink raw reply related [flat|nested] 82+ messages in thread
* [PATCH v2 23/64] dmaengine: timb_dma: route callbacks via channel BH
2026-07-27 20:28 ` [PATCH v2 00/64] dmaengine: migrate channel tasklets to WQ_BH Allen Pais
` (21 preceding siblings ...)
2026-07-27 20:28 ` [PATCH v2 22/64] dmaengine: tegra20-apb: use channel BH helpers Allen Pais
@ 2026-07-27 20:28 ` Allen Pais
2026-07-27 20:28 ` [PATCH v2 24/64] dmaengine: txx9dmac: " Allen Pais
` (41 subsequent siblings)
64 siblings, 0 replies; 82+ messages in thread
From: Allen Pais @ 2026-07-27 20:28 UTC (permalink / raw)
To: Vinod Koul, Frank Li
Cc: Allen Pais, dmaengine, linux-kernel, Arnd Bergmann, Kees Cook
Schedule per-channel BH work for completions so callbacks run through
the dma_chan deferral mechanism while keeping the controller tasklet for
IRQ handling.
Signed-off-by: Allen Pais <allen.lkml@gmail.com>
---
drivers/dma/timb_dma.c | 21 ++++++++++++++++-----
1 file changed, 16 insertions(+), 5 deletions(-)
diff --git a/drivers/dma/timb_dma.c b/drivers/dma/timb_dma.c
index 4fc5119854ec..7d43e5712ffe 100644
--- a/drivers/dma/timb_dma.c
+++ b/drivers/dma/timb_dma.c
@@ -438,6 +438,8 @@ static void td_free_chan_resources(struct dma_chan *chan)
dev_dbg(chan2dev(chan), "%s: Entry\n", __func__);
+ dma_chan_kill_bh(&td_chan->chan);
+
/* check that all descriptors are free */
BUG_ON(!list_empty(&td_chan->active_list));
BUG_ON(!list_empty(&td_chan->queue));
@@ -580,17 +582,25 @@ static void td_tasklet(struct tasklet_struct *t)
for (i = 0; i < td->dma.chancnt; i++)
if (ipr & (1 << i)) {
struct timb_dma_chan *td_chan = td->channels + i;
- spin_lock(&td_chan->lock);
- __td_finish(td_chan);
- if (!list_empty(&td_chan->queue))
- __td_start_next(td_chan);
- spin_unlock(&td_chan->lock);
+ dma_chan_schedule_bh(&td_chan->chan);
}
ier = __td_ier_mask(td);
iowrite32(ier, td->membase + TIMBDMA_IER);
}
+static void timb_dma_chan_bh(struct dma_chan *chan)
+{
+ struct timb_dma_chan *td_chan = container_of(chan, struct timb_dma_chan,
+ chan);
+
+ spin_lock(&td_chan->lock);
+ __td_finish(td_chan);
+ if (!list_empty(&td_chan->queue))
+ __td_start_next(td_chan);
+ spin_unlock(&td_chan->lock);
+}
+
static irqreturn_t td_irq(int irq, void *devid)
{
@@ -697,6 +707,7 @@ static int td_probe(struct platform_device *pdev)
INIT_LIST_HEAD(&td_chan->active_list);
INIT_LIST_HEAD(&td_chan->queue);
INIT_LIST_HEAD(&td_chan->free_list);
+ dma_chan_init_bh(&td_chan->chan, timb_dma_chan_bh);
td_chan->descs = pchan->descriptors;
td_chan->desc_elems = pchan->descriptor_elements;
--
2.43.0
^ permalink raw reply related [flat|nested] 82+ messages in thread
* [PATCH v2 24/64] dmaengine: txx9dmac: route callbacks via channel BH
2026-07-27 20:28 ` [PATCH v2 00/64] dmaengine: migrate channel tasklets to WQ_BH Allen Pais
` (22 preceding siblings ...)
2026-07-27 20:28 ` [PATCH v2 23/64] dmaengine: timb_dma: route callbacks via channel BH Allen Pais
@ 2026-07-27 20:28 ` Allen Pais
2026-07-27 20:28 ` [PATCH v2 25/64] dmaengine: mv_xor_v2: use channel BH helpers Allen Pais
` (40 subsequent siblings)
64 siblings, 0 replies; 82+ messages in thread
From: Allen Pais @ 2026-07-27 20:28 UTC (permalink / raw)
To: Vinod Koul, Frank Li
Cc: Allen Pais, dmaengine, linux-kernel, Arnd Bergmann, Kees Cook
Use the per-channel BH helpers for descriptor completion handling and
schedule per-channel work from both channel and controller IRQ paths.
Signed-off-by: Allen Pais <allen.lkml@gmail.com>
---
drivers/dma/txx9dmac.c | 12 ++++++------
drivers/dma/txx9dmac.h | 1 -
2 files changed, 6 insertions(+), 7 deletions(-)
diff --git a/drivers/dma/txx9dmac.c b/drivers/dma/txx9dmac.c
index 05622b68a936..6269baa28c51 100644
--- a/drivers/dma/txx9dmac.c
+++ b/drivers/dma/txx9dmac.c
@@ -601,13 +601,13 @@ static void txx9dmac_scan_descriptors(struct txx9dmac_chan *dc)
}
}
-static void txx9dmac_chan_tasklet(struct tasklet_struct *t)
+static void txx9dmac_chan_tasklet(struct dma_chan *chan)
{
int irq;
u32 csr;
struct txx9dmac_chan *dc;
- dc = from_tasklet(dc, t, tasklet);
+ dc = container_of(chan, struct txx9dmac_chan, chan);
csr = channel_readl(dc, CSR);
dev_vdbg(chan2dev(&dc->chan), "tasklet: status=%x\n", csr);
@@ -628,7 +628,7 @@ static irqreturn_t txx9dmac_chan_interrupt(int irq, void *dev_id)
dev_vdbg(chan2dev(&dc->chan), "interrupt: status=%#x\n",
channel_readl(dc, CSR));
- tasklet_schedule(&dc->tasklet);
+ dma_chan_schedule_bh(&dc->chan);
/*
* Just disable the interrupts. We'll turn them back on in the
* softirq handler.
@@ -659,7 +659,7 @@ static void txx9dmac_tasklet(struct tasklet_struct *t)
spin_lock(&dc->lock);
if (csr & (TXX9_DMA_CSR_ABCHC | TXX9_DMA_CSR_NCHNC |
TXX9_DMA_CSR_NTRNFC))
- txx9dmac_scan_descriptors(dc);
+ dma_chan_schedule_bh(&dc->chan);
spin_unlock(&dc->lock);
}
}
@@ -1113,7 +1113,7 @@ static int __init txx9dmac_chan_probe(struct platform_device *pdev)
irq = platform_get_irq(pdev, 0);
if (irq < 0)
return irq;
- tasklet_setup(&dc->tasklet, txx9dmac_chan_tasklet);
+ dma_chan_init_bh(&dc->chan, txx9dmac_chan_tasklet);
dc->irq = irq;
err = devm_request_irq(&pdev->dev, dc->irq,
txx9dmac_chan_interrupt, 0, dev_name(&pdev->dev), dc);
@@ -1159,7 +1159,7 @@ static void txx9dmac_chan_remove(struct platform_device *pdev)
dma_async_device_unregister(&dc->dma);
if (dc->irq >= 0) {
devm_free_irq(&pdev->dev, dc->irq, dc);
- tasklet_kill(&dc->tasklet);
+ dma_chan_kill_bh(&dc->chan);
}
dc->ddev->chan[pdev->id % TXX9_DMA_MAX_NR_CHANNELS] = NULL;
}
diff --git a/drivers/dma/txx9dmac.h b/drivers/dma/txx9dmac.h
index aa53eafb1519..f2abedb73d49 100644
--- a/drivers/dma/txx9dmac.h
+++ b/drivers/dma/txx9dmac.h
@@ -162,7 +162,6 @@ struct txx9dmac_chan {
struct dma_device dma;
struct txx9dmac_dev *ddev;
void __iomem *ch_regs;
- struct tasklet_struct tasklet;
int irq;
u32 ccr;
--
2.43.0
^ permalink raw reply related [flat|nested] 82+ messages in thread
* [PATCH v2 25/64] dmaengine: mv_xor_v2: use channel BH helpers
2026-07-27 20:28 ` [PATCH v2 00/64] dmaengine: migrate channel tasklets to WQ_BH Allen Pais
` (23 preceding siblings ...)
2026-07-27 20:28 ` [PATCH v2 24/64] dmaengine: txx9dmac: " Allen Pais
@ 2026-07-27 20:28 ` Allen Pais
2026-07-27 20:28 ` [PATCH v2 26/64] dmaengine: mpc512x: route callbacks via channel BH Allen Pais
` (39 subsequent siblings)
64 siblings, 0 replies; 82+ messages in thread
From: Allen Pais @ 2026-07-27 20:28 UTC (permalink / raw)
To: Vinod Koul, Frank Li
Cc: Allen Pais, dmaengine, linux-kernel, Arnd Bergmann, Kees Cook
Replace the device tasklet with the per-channel BH helper so descriptor
callbacks run through dma_chan_*_bh.
Signed-off-by: Allen Pais <allen.lkml@gmail.com>
---
drivers/dma/mv_xor_v2.c | 20 +++++++++-----------
1 file changed, 9 insertions(+), 11 deletions(-)
diff --git a/drivers/dma/mv_xor_v2.c b/drivers/dma/mv_xor_v2.c
index cad4d4fb51ac..e5fa7a221d5b 100644
--- a/drivers/dma/mv_xor_v2.c
+++ b/drivers/dma/mv_xor_v2.c
@@ -139,7 +139,6 @@ struct mv_xor_v2_descriptor {
* @reg_clk: reference to the 'reg' clock
* @dma_base: memory mapped DMA register base
* @glob_base: memory mapped global register base
- * @irq_tasklet: tasklet used for IRQ handling call-backs
* @free_sw_desc: linked list of free SW descriptors
* @dmadev: dma device
* @dmachan: dma channel
@@ -158,7 +157,6 @@ struct mv_xor_v2_device {
void __iomem *glob_base;
struct clk *clk;
struct clk *reg_clk;
- struct tasklet_struct irq_tasklet;
struct list_head free_sw_desc;
struct dma_device dmadev;
struct dma_chan dmachan;
@@ -290,8 +288,8 @@ static irqreturn_t mv_xor_v2_interrupt_handler(int irq, void *data)
if (!ndescs)
return IRQ_NONE;
- /* schedule a tasklet to handle descriptors callbacks */
- tasklet_schedule(&xor_dev->irq_tasklet);
+ /* schedule a bottom half to handle descriptors callbacks */
+ dma_chan_schedule_bh(&xor_dev->dmachan);
return IRQ_HANDLED;
}
@@ -346,8 +344,8 @@ mv_xor_v2_prep_sw_desc(struct mv_xor_v2_device *xor_dev)
if (list_empty(&xor_dev->free_sw_desc)) {
spin_unlock_bh(&xor_dev->lock);
- /* schedule tasklet to free some descriptors */
- tasklet_schedule(&xor_dev->irq_tasklet);
+ /* schedule bottom half to free some descriptors */
+ dma_chan_schedule_bh(&xor_dev->dmachan);
return NULL;
}
@@ -553,10 +551,10 @@ int mv_xor_v2_get_pending_params(struct mv_xor_v2_device *xor_dev,
/*
* handle the descriptors after HW process
*/
-static void mv_xor_v2_tasklet(struct tasklet_struct *t)
+static void mv_xor_v2_tasklet(struct dma_chan *chan)
{
- struct mv_xor_v2_device *xor_dev = from_tasklet(xor_dev, t,
- irq_tasklet);
+ struct mv_xor_v2_device *xor_dev =
+ container_of(chan, struct mv_xor_v2_device, dmachan);
int pending_ptr, num_of_pending, i;
struct mv_xor_v2_sw_desc *next_pending_sw_desc = NULL;
@@ -760,7 +758,7 @@ static int mv_xor_v2_probe(struct platform_device *pdev)
if (ret)
goto free_msi_irqs;
- tasklet_setup(&xor_dev->irq_tasklet, mv_xor_v2_tasklet);
+ dma_chan_init_bh(&xor_dev->dmachan, mv_xor_v2_tasklet);
xor_dev->desc_size = mv_xor_v2_set_desc_size(xor_dev);
@@ -869,7 +867,7 @@ static void mv_xor_v2_remove(struct platform_device *pdev)
platform_device_msi_free_irqs_all(&pdev->dev);
- tasklet_kill(&xor_dev->irq_tasklet);
+ dma_chan_kill_bh(&xor_dev->dmachan);
}
#ifdef CONFIG_OF
--
2.43.0
^ permalink raw reply related [flat|nested] 82+ messages in thread
* [PATCH v2 26/64] dmaengine: mpc512x: route callbacks via channel BH
2026-07-27 20:28 ` [PATCH v2 00/64] dmaengine: migrate channel tasklets to WQ_BH Allen Pais
` (24 preceding siblings ...)
2026-07-27 20:28 ` [PATCH v2 25/64] dmaengine: mv_xor_v2: use channel BH helpers Allen Pais
@ 2026-07-27 20:28 ` Allen Pais
2026-07-27 20:28 ` [PATCH v2 27/64] dmaengine: k3dma: kill vchan BH on remove Allen Pais
` (38 subsequent siblings)
64 siblings, 0 replies; 82+ messages in thread
From: Allen Pais @ 2026-07-27 20:28 UTC (permalink / raw)
To: Vinod Koul, Frank Li
Cc: Allen Pais, dmaengine, linux-kernel, Arnd Bergmann, Kees Cook
Schedule per-channel BH work for completions and process callbacks there,
leaving the controller tasklet for IRQ/error handling.
Signed-off-by: Allen Pais <allen.lkml@gmail.com>
---
drivers/dma/mpc512x_dma.c | 74 +++++++++++++++++++++++++--------------
1 file changed, 47 insertions(+), 27 deletions(-)
diff --git a/drivers/dma/mpc512x_dma.c b/drivers/dma/mpc512x_dma.c
index 0adc8e01057e..552ea72a9108 100644
--- a/drivers/dma/mpc512x_dma.c
+++ b/drivers/dma/mpc512x_dma.c
@@ -372,45 +372,47 @@ static irqreturn_t mpc_dma_irq(int irq, void *data)
return IRQ_HANDLED;
}
-/* process completed descriptors */
-static void mpc_dma_process_completed(struct mpc_dma *mdma)
+static void mpc_dma_process_chan_completed(struct mpc_dma_chan *mchan)
{
dma_cookie_t last_cookie = 0;
- struct mpc_dma_chan *mchan;
struct mpc_dma_desc *mdesc;
struct dma_async_tx_descriptor *desc;
unsigned long flags;
LIST_HEAD(list);
- int i;
- for (i = 0; i < mdma->dma.chancnt; i++) {
- mchan = &mdma->channels[i];
+ /* Get all completed descriptors */
+ spin_lock_irqsave(&mchan->lock, flags);
+ if (!list_empty(&mchan->completed))
+ list_splice_tail_init(&mchan->completed, &list);
+ spin_unlock_irqrestore(&mchan->lock, flags);
- /* Get all completed descriptors */
- spin_lock_irqsave(&mchan->lock, flags);
- if (!list_empty(&mchan->completed))
- list_splice_tail_init(&mchan->completed, &list);
- spin_unlock_irqrestore(&mchan->lock, flags);
+ if (list_empty(&list))
+ return;
- if (list_empty(&list))
- continue;
+ /* Execute callbacks and run dependencies */
+ list_for_each_entry(mdesc, &list, node) {
+ desc = &mdesc->desc;
- /* Execute callbacks and run dependencies */
- list_for_each_entry(mdesc, &list, node) {
- desc = &mdesc->desc;
+ dmaengine_desc_get_callback_invoke(desc, NULL);
- dmaengine_desc_get_callback_invoke(desc, NULL);
+ last_cookie = desc->cookie;
+ dma_run_dependencies(desc);
+ }
- last_cookie = desc->cookie;
- dma_run_dependencies(desc);
- }
+ /* Free descriptors */
+ spin_lock_irqsave(&mchan->lock, flags);
+ list_splice_tail_init(&list, &mchan->free);
+ mchan->chan.completed_cookie = last_cookie;
+ spin_unlock_irqrestore(&mchan->lock, flags);
+}
- /* Free descriptors */
- spin_lock_irqsave(&mchan->lock, flags);
- list_splice_tail_init(&list, &mchan->free);
- mchan->chan.completed_cookie = last_cookie;
- spin_unlock_irqrestore(&mchan->lock, flags);
- }
+/* process completed descriptors */
+static void mpc_dma_process_completed(struct mpc_dma *mdma)
+{
+ int i;
+
+ for (i = 0; i < mdma->dma.chancnt; i++)
+ mpc_dma_process_chan_completed(&mdma->channels[i]);
}
/* DMA Tasklet */
@@ -419,6 +421,7 @@ static void mpc_dma_tasklet(struct tasklet_struct *t)
struct mpc_dma *mdma = from_tasklet(mdma, t, tasklet);
unsigned long flags;
uint es;
+ int i;
spin_lock_irqsave(&mdma->error_status_lock, flags);
es = mdma->error_status;
@@ -453,7 +456,21 @@ static void mpc_dma_tasklet(struct tasklet_struct *t)
dev_err(mdma->dma.dev, "- Destination Bus Error\n");
}
- mpc_dma_process_completed(mdma);
+ for (i = 0; i < mdma->dma.chancnt; i++) {
+ struct mpc_dma_chan *mchan = &mdma->channels[i];
+
+ spin_lock_irqsave(&mchan->lock, flags);
+ if (!list_empty(&mchan->completed))
+ dma_chan_schedule_bh(&mchan->chan);
+ spin_unlock_irqrestore(&mchan->lock, flags);
+ }
+}
+
+static void mpc_dma_chan_bh(struct dma_chan *chan)
+{
+ struct mpc_dma_chan *mchan = dma_chan_to_mpc_dma_chan(chan);
+
+ mpc_dma_process_chan_completed(mchan);
}
/* Submit descriptor to hardware */
@@ -551,6 +568,8 @@ static void mpc_dma_free_chan_resources(struct dma_chan *chan)
unsigned long flags;
LIST_HEAD(descs);
+ dma_chan_kill_bh(&mchan->chan);
+
spin_lock_irqsave(&mchan->lock, flags);
/* Channel must be idle */
@@ -1007,6 +1026,7 @@ static int mpc_dma_probe(struct platform_device *op)
INIT_LIST_HEAD(&mchan->completed);
spin_lock_init(&mchan->lock);
+ dma_chan_init_bh(&mchan->chan, mpc_dma_chan_bh);
list_add_tail(&mchan->chan.device_node, &dma->channels);
}
--
2.43.0
^ permalink raw reply related [flat|nested] 82+ messages in thread
* [PATCH v2 27/64] dmaengine: k3dma: kill vchan BH on remove
2026-07-27 20:28 ` [PATCH v2 00/64] dmaengine: migrate channel tasklets to WQ_BH Allen Pais
` (25 preceding siblings ...)
2026-07-27 20:28 ` [PATCH v2 26/64] dmaengine: mpc512x: route callbacks via channel BH Allen Pais
@ 2026-07-27 20:28 ` Allen Pais
2026-07-27 20:28 ` [PATCH v2 28/64] dmaengine: plx_dma: use channel BH helpers Allen Pais
` (37 subsequent siblings)
64 siblings, 0 replies; 82+ messages in thread
From: Allen Pais @ 2026-07-27 20:28 UTC (permalink / raw)
To: Vinod Koul, Frank Li
Cc: Allen Pais, dmaengine, linux-kernel, Arnd Bergmann, Kees Cook
Use dma_chan_kill_bh() for virt-dma cleanup now that vchan uses the
per-channel BH helper.
Signed-off-by: Allen Pais <allen.lkml@gmail.com>
---
drivers/dma/k3dma.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/dma/k3dma.c b/drivers/dma/k3dma.c
index e84f197fea76..99a70b90a02b 100644
--- a/drivers/dma/k3dma.c
+++ b/drivers/dma/k3dma.c
@@ -976,7 +976,7 @@ static void k3_dma_remove(struct platform_device *op)
list_for_each_entry_safe(c, cn, &d->slave.channels, vc.chan.device_node) {
list_del(&c->vc.chan.device_node);
- tasklet_kill(&c->vc.task);
+ dma_chan_kill_bh(&c->vc.chan);
}
tasklet_kill(&d->task);
clk_disable_unprepare(d->clk);
--
2.43.0
^ permalink raw reply related [flat|nested] 82+ messages in thread
* [PATCH v2 28/64] dmaengine: plx_dma: use channel BH helpers
2026-07-27 20:28 ` [PATCH v2 00/64] dmaengine: migrate channel tasklets to WQ_BH Allen Pais
` (26 preceding siblings ...)
2026-07-27 20:28 ` [PATCH v2 27/64] dmaengine: k3dma: kill vchan BH on remove Allen Pais
@ 2026-07-27 20:28 ` Allen Pais
2026-07-27 20:38 ` Logan Gunthorpe
2026-07-27 20:28 ` [PATCH v2 29/64] dmaengine: sf-pdma: route error callbacks through channel BH Allen Pais
` (36 subsequent siblings)
64 siblings, 1 reply; 82+ messages in thread
From: Allen Pais @ 2026-07-27 20:28 UTC (permalink / raw)
To: Vinod Koul, Frank Li
Cc: Allen Pais, dmaengine, linux-kernel, Arnd Bergmann, Kees Cook,
Logan Gunthorpe
Replace the device tasklet with the per-channel BH helper so completion
callbacks run via dma_chan_*_bh.
Signed-off-by: Allen Pais <allen.lkml@gmail.com>
---
drivers/dma/plx_dma.c | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/drivers/dma/plx_dma.c b/drivers/dma/plx_dma.c
index 84941a918b01..9d6bbdfa5a69 100644
--- a/drivers/dma/plx_dma.c
+++ b/drivers/dma/plx_dma.c
@@ -105,7 +105,6 @@ struct plx_dma_dev {
struct dma_chan dma_chan;
struct pci_dev __rcu *pdev;
void __iomem *bar;
- struct tasklet_struct desc_task;
spinlock_t ring_lock;
bool ring_active;
@@ -241,9 +240,10 @@ static void plx_dma_stop(struct plx_dma_dev *plxdev)
rcu_read_unlock();
}
-static void plx_dma_desc_task(struct tasklet_struct *t)
+static void plx_dma_desc_task(struct dma_chan *chan)
{
- struct plx_dma_dev *plxdev = from_tasklet(plxdev, t, desc_task);
+ struct plx_dma_dev *plxdev = container_of(chan, struct plx_dma_dev,
+ dma_chan);
plx_dma_process_desc(plxdev);
}
@@ -366,7 +366,7 @@ static irqreturn_t plx_dma_isr(int irq, void *devid)
return IRQ_NONE;
if (status & PLX_REG_INTR_STATUS_DESC_DONE && plxdev->ring_active)
- tasklet_schedule(&plxdev->desc_task);
+ dma_chan_schedule_bh(&plxdev->dma_chan);
writew(status, plxdev->bar + PLX_REG_INTR_STATUS);
@@ -471,7 +471,7 @@ static void plx_dma_free_chan_resources(struct dma_chan *chan)
if (irq > 0)
synchronize_irq(irq);
- tasklet_kill(&plxdev->desc_task);
+ dma_chan_kill_bh(&plxdev->dma_chan);
plx_dma_abort_desc(plxdev);
@@ -510,7 +510,7 @@ static int plx_dma_create(struct pci_dev *pdev)
goto free_plx;
spin_lock_init(&plxdev->ring_lock);
- tasklet_setup(&plxdev->desc_task, plx_dma_desc_task);
+ dma_chan_init_bh(&plxdev->dma_chan, plx_dma_desc_task);
RCU_INIT_POINTER(plxdev->pdev, pdev);
plxdev->bar = pcim_iomap_table(pdev)[0];
--
2.43.0
^ permalink raw reply related [flat|nested] 82+ messages in thread
* [PATCH v2 29/64] dmaengine: sf-pdma: route error callbacks through channel BH
2026-07-27 20:28 ` [PATCH v2 00/64] dmaengine: migrate channel tasklets to WQ_BH Allen Pais
` (27 preceding siblings ...)
2026-07-27 20:28 ` [PATCH v2 28/64] dmaengine: plx_dma: use channel BH helpers Allen Pais
@ 2026-07-27 20:28 ` Allen Pais
2026-07-27 20:28 ` [PATCH v2 30/64] dmaengine: sa11x0-dma: kill vchan BH on remove Allen Pais
` (35 subsequent siblings)
64 siblings, 0 replies; 82+ messages in thread
From: Allen Pais @ 2026-07-27 20:28 UTC (permalink / raw)
To: Vinod Koul, Frank Li
Cc: Allen Pais, dmaengine, linux-kernel, Arnd Bergmann, Kees Cook,
Paul Walmsley, Samuel Holland, linux-riscv
virt-dma now dispatches completion callbacks through per-channel BH work,
but SF-PDMA invokes the client callback directly from its error tasklet
after exhausting its retries.
Complete failed descriptors through virt-dma with an aborted result and
the remaining transfer size, then start the next pending transfer. During
removal, kill the producer tasklets before the channel BH so they cannot
enqueue callback work after it has been canceled.
Signed-off-by: Allen Pais <allen.lkml@gmail.com>
---
drivers/dma/sf-pdma/sf-pdma.c | 14 ++++++++++++--
1 file changed, 12 insertions(+), 2 deletions(-)
diff --git a/drivers/dma/sf-pdma/sf-pdma.c b/drivers/dma/sf-pdma/sf-pdma.c
index 6f79cc28703e..a6c2f53f005e 100644
--- a/drivers/dma/sf-pdma/sf-pdma.c
+++ b/drivers/dma/sf-pdma/sf-pdma.c
@@ -328,7 +328,17 @@ static void sf_pdma_errbh_tasklet(struct tasklet_struct *t)
if (chan->retries <= 0) {
/* fail to recover */
spin_unlock_irqrestore(&chan->lock, flags);
- dmaengine_desc_get_callback_invoke(desc->async_tx, NULL);
+
+ spin_lock_irqsave(&chan->vchan.lock, flags);
+ list_del(&desc->vdesc.node);
+ desc->vdesc.tx_result.result = DMA_TRANS_ABORTED;
+ desc->vdesc.tx_result.residue = desc->xfer_size;
+ vchan_cookie_complete(&desc->vdesc);
+
+ chan->desc = sf_pdma_get_first_pending_desc(chan);
+ if (chan->desc)
+ sf_pdma_xfer_desc(chan);
+ spin_unlock_irqrestore(&chan->vchan.lock, flags);
} else {
/* retry */
chan->retries--;
@@ -602,9 +612,9 @@ static void sf_pdma_remove(struct platform_device *pdev)
devm_free_irq(&pdev->dev, ch->txirq, ch);
devm_free_irq(&pdev->dev, ch->errirq, ch);
list_del(&ch->vchan.chan.device_node);
- tasklet_kill(&ch->vchan.task);
tasklet_kill(&ch->done_tasklet);
tasklet_kill(&ch->err_tasklet);
+ dma_chan_kill_bh(&ch->vchan.chan);
}
if (pdev->dev.of_node)
--
2.43.0
^ permalink raw reply related [flat|nested] 82+ messages in thread
* [PATCH v2 30/64] dmaengine: sa11x0-dma: kill vchan BH on remove
2026-07-27 20:28 ` [PATCH v2 00/64] dmaengine: migrate channel tasklets to WQ_BH Allen Pais
` (28 preceding siblings ...)
2026-07-27 20:28 ` [PATCH v2 29/64] dmaengine: sf-pdma: route error callbacks through channel BH Allen Pais
@ 2026-07-27 20:28 ` Allen Pais
2026-07-27 20:28 ` [PATCH v2 31/64] dmaengine: pl330: route callbacks via channel BH Allen Pais
` (34 subsequent siblings)
64 siblings, 0 replies; 82+ messages in thread
From: Allen Pais @ 2026-07-27 20:28 UTC (permalink / raw)
To: Vinod Koul, Frank Li
Cc: Allen Pais, dmaengine, linux-kernel, Arnd Bergmann, Kees Cook
Use dma_chan_kill_bh() when tearing down virt-dma channels.
Signed-off-by: Allen Pais <allen.lkml@gmail.com>
---
drivers/dma/sa11x0-dma.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/dma/sa11x0-dma.c b/drivers/dma/sa11x0-dma.c
index a6fa431530e3..ea4357da5e39 100644
--- a/drivers/dma/sa11x0-dma.c
+++ b/drivers/dma/sa11x0-dma.c
@@ -891,7 +891,7 @@ static void sa11x0_dma_free_channels(struct dma_device *dmadev)
list_for_each_entry_safe(c, cn, &dmadev->channels, vc.chan.device_node) {
list_del(&c->vc.chan.device_node);
- tasklet_kill(&c->vc.task);
+ dma_chan_kill_bh(&c->vc.chan);
kfree(c);
}
}
--
2.43.0
^ permalink raw reply related [flat|nested] 82+ messages in thread
* [PATCH v2 31/64] dmaengine: pl330: route callbacks via channel BH
2026-07-27 20:28 ` [PATCH v2 00/64] dmaengine: migrate channel tasklets to WQ_BH Allen Pais
` (29 preceding siblings ...)
2026-07-27 20:28 ` [PATCH v2 30/64] dmaengine: sa11x0-dma: kill vchan BH on remove Allen Pais
@ 2026-07-27 20:28 ` Allen Pais
2026-07-27 20:34 ` Allen Pais
2026-07-27 20:34 ` [PATCH v2 32/64] dmaengine: k3-udma: use channel BH for vchan completions Allen Pais
` (33 subsequent siblings)
64 siblings, 1 reply; 82+ messages in thread
From: Allen Pais @ 2026-07-27 20:28 UTC (permalink / raw)
To: Vinod Koul, Frank Li
Cc: Allen Pais, dmaengine, linux-kernel, Arnd Bergmann, Kees Cook
Convert the per-channel tasklet to dma_chan_*_bh while keeping the
controller tasklet for non-callback events.
Signed-off-by: Allen Pais <allen.lkml@gmail.com>
---
drivers/dma/pl330.c | 18 ++++++++----------
1 file changed, 8 insertions(+), 10 deletions(-)
diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c
index 25ba84b18704..f4940bd1ab84 100644
--- a/drivers/dma/pl330.c
+++ b/drivers/dma/pl330.c
@@ -417,9 +417,6 @@ enum desc_status {
};
struct dma_pl330_chan {
- /* Schedule desc completion */
- struct tasklet_struct task;
-
/* DMA-Engine Channel */
struct dma_chan chan;
@@ -1574,7 +1571,7 @@ static void dma_pl330_rqcb(struct dma_pl330_desc *desc, enum pl330_op_err err)
spin_unlock_irqrestore(&pch->lock, flags);
- tasklet_schedule(&pch->task);
+ dma_chan_schedule_bh(&pch->chan);
}
static void pl330_dotask(struct tasklet_struct *t)
@@ -2060,14 +2057,15 @@ static inline void fill_queue(struct dma_pl330_chan *pch)
desc->status = DONE;
dev_err(pch->dmac->ddma.dev, "%s:%d Bad Desc(%d)\n",
__func__, __LINE__, desc->txd.cookie);
- tasklet_schedule(&pch->task);
+ dma_chan_schedule_bh(&pch->chan);
}
}
}
-static void pl330_tasklet(struct tasklet_struct *t)
+static void pl330_tasklet(struct dma_chan *chan)
{
- struct dma_pl330_chan *pch = from_tasklet(pch, t, task);
+ struct dma_pl330_chan *pch = container_of(chan, struct dma_pl330_chan,
+ chan);
struct dma_pl330_desc *desc, *_dt;
unsigned long flags;
bool power_down = false;
@@ -2173,7 +2171,7 @@ static int pl330_alloc_chan_resources(struct dma_chan *chan)
return -ENOMEM;
}
- tasklet_setup(&pch->task, pl330_tasklet);
+ dma_chan_init_bh(&pch->chan, pl330_tasklet);
spin_unlock_irqrestore(&pl330->lock, flags);
@@ -2354,7 +2352,7 @@ static void pl330_free_chan_resources(struct dma_chan *chan)
struct pl330_dmac *pl330 = pch->dmac;
unsigned long flags;
- tasklet_kill(&pch->task);
+ dma_chan_kill_bh(&pch->chan);
pm_runtime_get_sync(pch->dmac->ddma.dev);
spin_lock_irqsave(&pl330->lock, flags);
@@ -2490,7 +2488,7 @@ static void pl330_issue_pending(struct dma_chan *chan)
list_splice_tail_init(&pch->submitted_list, &pch->work_list);
spin_unlock_irqrestore(&pch->lock, flags);
- pl330_tasklet(&pch->task);
+ pl330_tasklet(&pch->chan);
}
/*
--
2.43.0
^ permalink raw reply related [flat|nested] 82+ messages in thread
* [PATCH v2 31/64] dmaengine: pl330: route callbacks via channel BH
2026-07-27 20:28 ` [PATCH v2 31/64] dmaengine: pl330: route callbacks via channel BH Allen Pais
@ 2026-07-27 20:34 ` Allen Pais
0 siblings, 0 replies; 82+ messages in thread
From: Allen Pais @ 2026-07-27 20:34 UTC (permalink / raw)
To: Vinod Koul, Frank Li
Cc: Allen Pais, dmaengine, linux-kernel, Arnd Bergmann, Kees Cook
Convert the per-channel tasklet to dma_chan_*_bh while keeping the
controller tasklet for non-callback events.
Signed-off-by: Allen Pais <allen.lkml@gmail.com>
---
drivers/dma/pl330.c | 18 ++++++++----------
1 file changed, 8 insertions(+), 10 deletions(-)
diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c
index 25ba84b18704..f4940bd1ab84 100644
--- a/drivers/dma/pl330.c
+++ b/drivers/dma/pl330.c
@@ -417,9 +417,6 @@ enum desc_status {
};
struct dma_pl330_chan {
- /* Schedule desc completion */
- struct tasklet_struct task;
-
/* DMA-Engine Channel */
struct dma_chan chan;
@@ -1574,7 +1571,7 @@ static void dma_pl330_rqcb(struct dma_pl330_desc *desc, enum pl330_op_err err)
spin_unlock_irqrestore(&pch->lock, flags);
- tasklet_schedule(&pch->task);
+ dma_chan_schedule_bh(&pch->chan);
}
static void pl330_dotask(struct tasklet_struct *t)
@@ -2060,14 +2057,15 @@ static inline void fill_queue(struct dma_pl330_chan *pch)
desc->status = DONE;
dev_err(pch->dmac->ddma.dev, "%s:%d Bad Desc(%d)\n",
__func__, __LINE__, desc->txd.cookie);
- tasklet_schedule(&pch->task);
+ dma_chan_schedule_bh(&pch->chan);
}
}
}
-static void pl330_tasklet(struct tasklet_struct *t)
+static void pl330_tasklet(struct dma_chan *chan)
{
- struct dma_pl330_chan *pch = from_tasklet(pch, t, task);
+ struct dma_pl330_chan *pch = container_of(chan, struct dma_pl330_chan,
+ chan);
struct dma_pl330_desc *desc, *_dt;
unsigned long flags;
bool power_down = false;
@@ -2173,7 +2171,7 @@ static int pl330_alloc_chan_resources(struct dma_chan *chan)
return -ENOMEM;
}
- tasklet_setup(&pch->task, pl330_tasklet);
+ dma_chan_init_bh(&pch->chan, pl330_tasklet);
spin_unlock_irqrestore(&pl330->lock, flags);
@@ -2354,7 +2352,7 @@ static void pl330_free_chan_resources(struct dma_chan *chan)
struct pl330_dmac *pl330 = pch->dmac;
unsigned long flags;
- tasklet_kill(&pch->task);
+ dma_chan_kill_bh(&pch->chan);
pm_runtime_get_sync(pch->dmac->ddma.dev);
spin_lock_irqsave(&pl330->lock, flags);
@@ -2490,7 +2488,7 @@ static void pl330_issue_pending(struct dma_chan *chan)
list_splice_tail_init(&pch->submitted_list, &pch->work_list);
spin_unlock_irqrestore(&pch->lock, flags);
- pl330_tasklet(&pch->task);
+ pl330_tasklet(&pch->chan);
}
/*
--
2.43.0
^ permalink raw reply related [flat|nested] 82+ messages in thread
* [PATCH v2 32/64] dmaengine: k3-udma: use channel BH for vchan completions
2026-07-27 20:28 ` [PATCH v2 00/64] dmaengine: migrate channel tasklets to WQ_BH Allen Pais
` (30 preceding siblings ...)
2026-07-27 20:28 ` [PATCH v2 31/64] dmaengine: pl330: route callbacks via channel BH Allen Pais
@ 2026-07-27 20:34 ` Allen Pais
2026-07-27 20:36 ` [PATCH v2 33/64] dmaengine: sun6i: kill vchan BH on teardown Allen Pais
` (32 subsequent siblings)
64 siblings, 0 replies; 82+ messages in thread
From: Allen Pais @ 2026-07-27 20:34 UTC (permalink / raw)
To: Vinod Koul, Frank Li
Cc: Allen Pais, dmaengine, linux-kernel, Arnd Bergmann, Kees Cook,
Vignesh Raghavendra
Use the per-channel BH mechanism for custom vchan completion handling
and clean up via dma_chan_kill_bh().
Signed-off-by: Allen Pais <allen.lkml@gmail.com>
---
drivers/dma/ti/k3-udma.c | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/drivers/dma/ti/k3-udma.c b/drivers/dma/ti/k3-udma.c
index 1cf158eb7bdb..12b8a9caf4d2 100644
--- a/drivers/dma/ti/k3-udma.c
+++ b/drivers/dma/ti/k3-udma.c
@@ -4042,12 +4042,12 @@ static void udma_desc_pre_callback(struct virt_dma_chan *vc,
}
/*
- * This tasklet handles the completion of a DMA descriptor by
+ * This BH handles the completion of a DMA descriptor by
* calling its callback and freeing it.
*/
-static void udma_vchan_complete(struct tasklet_struct *t)
+static void udma_vchan_complete(struct dma_chan *chan)
{
- struct virt_dma_chan *vc = from_tasklet(vc, t, task);
+ struct virt_dma_chan *vc = to_virt_chan(chan);
struct virt_dma_desc *vd, *_vd;
struct dmaengine_desc_callback cb;
LIST_HEAD(head);
@@ -4112,7 +4112,7 @@ static void udma_free_chan_resources(struct dma_chan *chan)
}
vchan_free_chan_resources(&uc->vc);
- tasklet_kill(&uc->vc.task);
+ dma_chan_kill_bh(&uc->vc.chan);
bcdma_free_bchan_resources(uc);
udma_free_tx_resources(uc);
@@ -5627,8 +5627,8 @@ static int udma_probe(struct platform_device *pdev)
if (!uc->name)
return -ENOMEM;
vchan_init(&uc->vc, &ud->ddev);
- /* Use custom vchan completion handling */
- tasklet_setup(&uc->vc.task, udma_vchan_complete);
+ /* Override the default vchan completion handler */
+ uc->vc.chan.bh_work_fn = udma_vchan_complete;
init_completion(&uc->teardown_completed);
INIT_DELAYED_WORK(&uc->tx_drain.work, udma_check_tx_completion);
}
--
2.43.0
^ permalink raw reply related [flat|nested] 82+ messages in thread
* [PATCH v2 33/64] dmaengine: sun6i: kill vchan BH on teardown
2026-07-27 20:28 ` [PATCH v2 00/64] dmaengine: migrate channel tasklets to WQ_BH Allen Pais
` (31 preceding siblings ...)
2026-07-27 20:34 ` [PATCH v2 32/64] dmaengine: k3-udma: use channel BH for vchan completions Allen Pais
@ 2026-07-27 20:36 ` Allen Pais
2026-07-27 20:37 ` [PATCH v2 34/64] dmaengine: mtk-cqdma: " Allen Pais
` (31 subsequent siblings)
64 siblings, 0 replies; 82+ messages in thread
From: Allen Pais @ 2026-07-27 20:36 UTC (permalink / raw)
To: Vinod Koul, Frank Li
Cc: Allen Pais, dmaengine, linux-kernel, Arnd Bergmann, Kees Cook,
Chen-Yu Tsai, Jernej Skrabec, Samuel Holland, linux-arm-kernel,
linux-sunxi
Use dma_chan_kill_bh() for virt-dma channel cleanup.
Signed-off-by: Allen Pais <allen.lkml@gmail.com>
---
drivers/dma/sun6i-dma.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/dma/sun6i-dma.c b/drivers/dma/sun6i-dma.c
index a9a254dbf8cb..9289c24dfcfa 100644
--- a/drivers/dma/sun6i-dma.c
+++ b/drivers/dma/sun6i-dma.c
@@ -1097,7 +1097,7 @@ static inline void sun6i_dma_free(struct sun6i_dma_dev *sdev)
struct sun6i_vchan *vchan = &sdev->vchans[i];
list_del(&vchan->vc.chan.device_node);
- tasklet_kill(&vchan->vc.task);
+ dma_chan_kill_bh(&vchan->vc.chan);
}
}
--
2.43.0
^ permalink raw reply related [flat|nested] 82+ messages in thread
* [PATCH v2 34/64] dmaengine: mtk-cqdma: kill vchan BH on teardown
2026-07-27 20:28 ` [PATCH v2 00/64] dmaengine: migrate channel tasklets to WQ_BH Allen Pais
` (32 preceding siblings ...)
2026-07-27 20:36 ` [PATCH v2 33/64] dmaengine: sun6i: kill vchan BH on teardown Allen Pais
@ 2026-07-27 20:37 ` Allen Pais
2026-07-27 20:38 ` [PATCH v2 35/64] dmaengine: altera-msgdma: use channel BH helpers Allen Pais
` (30 subsequent siblings)
64 siblings, 0 replies; 82+ messages in thread
From: Allen Pais @ 2026-07-27 20:37 UTC (permalink / raw)
To: Vinod Koul, Frank Li
Cc: Allen Pais, dmaengine, linux-kernel, Arnd Bergmann, Kees Cook,
Sean Wang, Matthias Brugger, AngeloGioacchino Del Regno,
linux-arm-kernel, linux-mediatek
Use dma_chan_kill_bh() for virt-dma channel cleanup.
Signed-off-by: Allen Pais <allen.lkml@gmail.com>
---
drivers/dma/mediatek/mtk-cqdma.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/dma/mediatek/mtk-cqdma.c b/drivers/dma/mediatek/mtk-cqdma.c
index 80791e30aec2..3b0f1d8fa205 100644
--- a/drivers/dma/mediatek/mtk-cqdma.c
+++ b/drivers/dma/mediatek/mtk-cqdma.c
@@ -895,7 +895,7 @@ static void mtk_cqdma_remove(struct platform_device *pdev)
vc = &cqdma->vc[i];
list_del(&vc->vc.chan.device_node);
- tasklet_kill(&vc->vc.task);
+ dma_chan_kill_bh(&vc->vc.chan);
}
/* disable interrupt */
--
2.43.0
^ permalink raw reply related [flat|nested] 82+ messages in thread
* Re: [PATCH v2 28/64] dmaengine: plx_dma: use channel BH helpers
2026-07-27 20:28 ` [PATCH v2 28/64] dmaengine: plx_dma: use channel BH helpers Allen Pais
@ 2026-07-27 20:38 ` Logan Gunthorpe
0 siblings, 0 replies; 82+ messages in thread
From: Logan Gunthorpe @ 2026-07-27 20:38 UTC (permalink / raw)
To: Allen Pais, Vinod Koul, Frank Li
Cc: dmaengine, linux-kernel, Arnd Bergmann, Kees Cook
On 2026-07-27 14:28, Allen Pais wrote:
> Replace the device tasklet with the per-channel BH helper so completion
> callbacks run via dma_chan_*_bh.
>
> Signed-off-by: Allen Pais <allen.lkml@gmail.com>
Looks good to me, thanks.
Reviewed-by: Logan Gunthorpe <logang@deltatee.com>
^ permalink raw reply [flat|nested] 82+ messages in thread
* Re: [PATCH v2 09/64] dmaengine: ioat: convert cleanup tasklet to dma_chan BH
2026-07-27 20:28 ` [PATCH v2 09/64] dmaengine: ioat: convert cleanup " Allen Pais
@ 2026-07-27 20:38 ` Dave Jiang
0 siblings, 0 replies; 82+ messages in thread
From: Dave Jiang @ 2026-07-27 20:38 UTC (permalink / raw)
To: Allen Pais, Vinod Koul, Frank Li
Cc: dmaengine, linux-kernel, Arnd Bergmann, Kees Cook,
Thomas Weißschuh, David Matlack, Lukas Wunner,
Giovanni Cabiddu
On 7/27/26 1:28 PM, Allen Pais wrote:
> Replace the per-channel tasklet with the shared dma_chan BH helper.
> The handler continues to run in softirq context while dmaengine owns
> the common scheduling and teardown mechanism.
>
> Signed-off-by: Allen Pais <allen.lkml@gmail.com>
Acked-by: Dave Jiang <dave.jiang@intel.com>
> ---
> drivers/dma/ioat/dma.c | 14 +++++++-------
> drivers/dma/ioat/dma.h | 3 +--
> drivers/dma/ioat/init.c | 2 +-
> 3 files changed, 9 insertions(+), 10 deletions(-)
>
> diff --git a/drivers/dma/ioat/dma.c b/drivers/dma/ioat/dma.c
> index ee93b029f9e3..827b46c6354a 100644
> --- a/drivers/dma/ioat/dma.c
> +++ b/drivers/dma/ioat/dma.c
> @@ -110,7 +110,7 @@ irqreturn_t ioat_dma_do_interrupt(int irq, void *data)
> for_each_set_bit(bit, &attnstatus, BITS_PER_LONG) {
> ioat_chan = ioat_chan_by_index(instance, bit);
> if (test_bit(IOAT_RUN, &ioat_chan->state))
> - tasklet_schedule(&ioat_chan->cleanup_task);
> + dma_chan_schedule_bh(&ioat_chan->dma_chan);
> }
>
> writeb(intrctrl, instance->reg_base + IOAT_INTRCTRL_OFFSET);
> @@ -127,7 +127,7 @@ irqreturn_t ioat_dma_do_interrupt_msix(int irq, void *data)
> struct ioatdma_chan *ioat_chan = data;
>
> if (test_bit(IOAT_RUN, &ioat_chan->state))
> - tasklet_schedule(&ioat_chan->cleanup_task);
> + dma_chan_schedule_bh(&ioat_chan->dma_chan);
>
> return IRQ_HANDLED;
> }
> @@ -161,11 +161,11 @@ void ioat_stop(struct ioatdma_chan *ioat_chan)
> /* flush inflight timers */
> timer_delete_sync(&ioat_chan->timer);
>
> - /* flush inflight tasklet runs */
> - tasklet_kill(&ioat_chan->cleanup_task);
> + /* flush inflight BH runs */
> + dma_chan_kill_bh(&ioat_chan->dma_chan);
>
> /* final cleanup now that everything is quiesced and can't re-arm */
> - ioat_cleanup_event(&ioat_chan->cleanup_task);
> + ioat_cleanup_event(&ioat_chan->dma_chan);
> }
>
> static void __ioat_issue_pending(struct ioatdma_chan *ioat_chan)
> @@ -690,9 +690,9 @@ static void ioat_cleanup(struct ioatdma_chan *ioat_chan)
> spin_unlock_bh(&ioat_chan->cleanup_lock);
> }
>
> -void ioat_cleanup_event(struct tasklet_struct *t)
> +void ioat_cleanup_event(struct dma_chan *c)
> {
> - struct ioatdma_chan *ioat_chan = from_tasklet(ioat_chan, t, cleanup_task);
> + struct ioatdma_chan *ioat_chan = to_ioat_chan(c);
>
> ioat_cleanup(ioat_chan);
> if (!test_bit(IOAT_RUN, &ioat_chan->state))
> diff --git a/drivers/dma/ioat/dma.h b/drivers/dma/ioat/dma.h
> index e8a880f338c6..4bdb1ae937e4 100644
> --- a/drivers/dma/ioat/dma.h
> +++ b/drivers/dma/ioat/dma.h
> @@ -111,7 +111,6 @@ struct ioatdma_chan {
> struct ioatdma_device *ioat_dma;
> dma_addr_t completion_dma;
> u64 *completion;
> - struct tasklet_struct cleanup_task;
> struct kobject kobj;
>
> /* ioat v2 / v3 channel attributes
> @@ -385,7 +384,7 @@ int ioat_reset_hw(struct ioatdma_chan *ioat_chan);
> enum dma_status
> ioat_tx_status(struct dma_chan *c, dma_cookie_t cookie,
> struct dma_tx_state *txstate);
> -void ioat_cleanup_event(struct tasklet_struct *t);
> +void ioat_cleanup_event(struct dma_chan *c);
> void ioat_timer_event(struct timer_list *t);
> int ioat_check_space_lock(struct ioatdma_chan *ioat_chan, int num_descs);
> void ioat_issue_pending(struct dma_chan *chan);
> diff --git a/drivers/dma/ioat/init.c b/drivers/dma/ioat/init.c
> index 737496391109..314676e1cbc4 100644
> --- a/drivers/dma/ioat/init.c
> +++ b/drivers/dma/ioat/init.c
> @@ -765,7 +765,7 @@ ioat_init_channel(struct ioatdma_device *ioat_dma,
> list_add_tail(&ioat_chan->dma_chan.device_node, &dma->channels);
> ioat_dma->idx[idx] = ioat_chan;
> timer_setup(&ioat_chan->timer, ioat_timer_event, 0);
> - tasklet_setup(&ioat_chan->cleanup_task, ioat_cleanup_event);
> + dma_chan_init_bh(&ioat_chan->dma_chan, ioat_cleanup_event);
> }
>
> #define IOAT_NUM_SRC_TEST 6 /* must be <= 8 */
^ permalink raw reply [flat|nested] 82+ messages in thread
* [PATCH v2 35/64] dmaengine: altera-msgdma: use channel BH helpers
2026-07-27 20:28 ` [PATCH v2 00/64] dmaengine: migrate channel tasklets to WQ_BH Allen Pais
` (33 preceding siblings ...)
2026-07-27 20:37 ` [PATCH v2 34/64] dmaengine: mtk-cqdma: " Allen Pais
@ 2026-07-27 20:38 ` Allen Pais
2026-07-27 20:38 ` [PATCH v2 36/64] dmaengine: sprd-dma: kill vchan BH on teardown Allen Pais
` (29 subsequent siblings)
64 siblings, 0 replies; 82+ messages in thread
From: Allen Pais @ 2026-07-27 20:38 UTC (permalink / raw)
To: Vinod Koul, Frank Li
Cc: Allen Pais, dmaengine, linux-kernel, Arnd Bergmann, Kees Cook,
Olivier Dautricourt, Stefan Roese
Replace the device tasklet with the per-channel BH helper so completion
handling runs via dma_chan_*_bh.
Signed-off-by: Allen Pais <allen.lkml@gmail.com>
---
drivers/dma/altera-msgdma.c | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/drivers/dma/altera-msgdma.c b/drivers/dma/altera-msgdma.c
index e23e5b441a24..5969bbc84ab9 100644
--- a/drivers/dma/altera-msgdma.c
+++ b/drivers/dma/altera-msgdma.c
@@ -170,7 +170,6 @@ struct msgdma_sw_desc {
struct msgdma_device {
spinlock_t lock;
struct device *dev;
- struct tasklet_struct irq_tasklet;
struct list_head pending_list;
struct list_head free_list;
struct list_head active_list;
@@ -684,11 +683,12 @@ static int msgdma_alloc_chan_resources(struct dma_chan *dchan)
/**
* msgdma_tasklet - Schedule completion tasklet
- * @t: Pointer to the Altera sSGDMA channel structure
+ * @chan: Pointer to the Altera sSGDMA channel structure
*/
-static void msgdma_tasklet(struct tasklet_struct *t)
+static void msgdma_tasklet(struct dma_chan *chan)
{
- struct msgdma_device *mdev = from_tasklet(mdev, t, irq_tasklet);
+ struct msgdma_device *mdev = container_of(chan, struct msgdma_device,
+ dmachan);
u32 count;
u32 __maybe_unused size;
u32 __maybe_unused status;
@@ -748,7 +748,7 @@ static irqreturn_t msgdma_irq_handler(int irq, void *data)
spin_unlock(&mdev->lock);
}
- tasklet_schedule(&mdev->irq_tasklet);
+ dma_chan_schedule_bh(&mdev->dmachan);
/* Clear interrupt in mSGDMA controller */
iowrite32(MSGDMA_CSR_STAT_IRQ, mdev->csr + MSGDMA_CSR_STATUS);
@@ -766,7 +766,7 @@ static void msgdma_dev_remove(struct msgdma_device *mdev)
return;
devm_free_irq(mdev->dev, mdev->irq, mdev);
- tasklet_kill(&mdev->irq_tasklet);
+ dma_chan_kill_bh(&mdev->dmachan);
list_del(&mdev->dmachan.device_node);
}
@@ -852,7 +852,7 @@ static int msgdma_probe(struct platform_device *pdev)
if (ret)
return ret;
- tasklet_setup(&mdev->irq_tasklet, msgdma_tasklet);
+ dma_chan_init_bh(&mdev->dmachan, msgdma_tasklet);
dma_cookie_init(&mdev->dmachan);
--
2.43.0
^ permalink raw reply related [flat|nested] 82+ messages in thread
* [PATCH v2 36/64] dmaengine: sprd-dma: kill vchan BH on teardown
2026-07-27 20:28 ` [PATCH v2 00/64] dmaengine: migrate channel tasklets to WQ_BH Allen Pais
` (34 preceding siblings ...)
2026-07-27 20:38 ` [PATCH v2 35/64] dmaengine: altera-msgdma: use channel BH helpers Allen Pais
@ 2026-07-27 20:38 ` Allen Pais
2026-07-27 20:38 ` [PATCH v2 37/64] dmaengine: idma64: " Allen Pais
` (28 subsequent siblings)
64 siblings, 0 replies; 82+ messages in thread
From: Allen Pais @ 2026-07-27 20:38 UTC (permalink / raw)
To: Vinod Koul, Frank Li
Cc: Allen Pais, dmaengine, linux-kernel, Arnd Bergmann, Kees Cook,
Orson Zhai, Baolin Wang, Chunyan Zhang
Use dma_chan_kill_bh() for virt-dma cleanup.
Signed-off-by: Allen Pais <allen.lkml@gmail.com>
---
drivers/dma/sprd-dma.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/dma/sprd-dma.c b/drivers/dma/sprd-dma.c
index 087fea3af2e4..42a0c1c34337 100644
--- a/drivers/dma/sprd-dma.c
+++ b/drivers/dma/sprd-dma.c
@@ -1253,7 +1253,7 @@ static void sprd_dma_remove(struct platform_device *pdev)
list_for_each_entry_safe(c, cn, &sdev->dma_dev.channels,
vc.chan.device_node) {
list_del(&c->vc.chan.device_node);
- tasklet_kill(&c->vc.task);
+ dma_chan_kill_bh(&c->vc.chan);
}
of_dma_controller_free(pdev->dev.of_node);
--
2.43.0
^ permalink raw reply related [flat|nested] 82+ messages in thread
* [PATCH v2 37/64] dmaengine: idma64: kill vchan BH on teardown
2026-07-27 20:28 ` [PATCH v2 00/64] dmaengine: migrate channel tasklets to WQ_BH Allen Pais
` (35 preceding siblings ...)
2026-07-27 20:38 ` [PATCH v2 36/64] dmaengine: sprd-dma: kill vchan BH on teardown Allen Pais
@ 2026-07-27 20:38 ` Allen Pais
2026-07-27 20:39 ` [PATCH v2 38/64] dmaengine: img-mdc-dma: " Allen Pais
` (27 subsequent siblings)
64 siblings, 0 replies; 82+ messages in thread
From: Allen Pais @ 2026-07-27 20:38 UTC (permalink / raw)
To: Vinod Koul, Frank Li
Cc: Allen Pais, dmaengine, linux-kernel, Arnd Bergmann, Kees Cook
Use dma_chan_kill_bh() for virt-dma cleanup.
Signed-off-by: Allen Pais <allen.lkml@gmail.com>
---
drivers/dma/idma64.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/dma/idma64.c b/drivers/dma/idma64.c
index 5fcd1befc92d..8e25d828e553 100644
--- a/drivers/dma/idma64.c
+++ b/drivers/dma/idma64.c
@@ -617,14 +617,14 @@ static void idma64_remove(struct idma64_chip *chip)
/*
* Explicitly call devm_request_irq() to avoid the side effects with
- * the scheduled tasklets.
+ * scheduled BH work.
*/
devm_free_irq(chip->dev, chip->irq, idma64);
for (i = 0; i < idma64->dma.chancnt; i++) {
struct idma64_chan *idma64c = &idma64->chan[i];
- tasklet_kill(&idma64c->vchan.task);
+ dma_chan_kill_bh(&idma64c->vchan.chan);
}
}
--
2.43.0
^ permalink raw reply related [flat|nested] 82+ messages in thread
* [PATCH v2 38/64] dmaengine: img-mdc-dma: kill vchan BH on teardown
2026-07-27 20:28 ` [PATCH v2 00/64] dmaengine: migrate channel tasklets to WQ_BH Allen Pais
` (36 preceding siblings ...)
2026-07-27 20:38 ` [PATCH v2 37/64] dmaengine: idma64: " Allen Pais
@ 2026-07-27 20:39 ` Allen Pais
2026-07-27 20:39 ` [PATCH v2 39/64] dmaengine: fsl-edma-common: " Allen Pais
` (26 subsequent siblings)
64 siblings, 0 replies; 82+ messages in thread
From: Allen Pais @ 2026-07-27 20:39 UTC (permalink / raw)
To: Vinod Koul, Frank Li
Cc: Allen Pais, dmaengine, linux-kernel, Arnd Bergmann, Kees Cook
Use dma_chan_kill_bh() for virt-dma cleanup.
Signed-off-by: Allen Pais <allen.lkml@gmail.com>
---
drivers/dma/img-mdc-dma.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/dma/img-mdc-dma.c b/drivers/dma/img-mdc-dma.c
index b3765ba15803..374034c737c0 100644
--- a/drivers/dma/img-mdc-dma.c
+++ b/drivers/dma/img-mdc-dma.c
@@ -1031,7 +1031,7 @@ static void mdc_dma_remove(struct platform_device *pdev)
devm_free_irq(&pdev->dev, mchan->irq, mchan);
- tasklet_kill(&mchan->vc.task);
+ dma_chan_kill_bh(&mchan->vc.chan);
}
pm_runtime_disable(&pdev->dev);
--
2.43.0
^ permalink raw reply related [flat|nested] 82+ messages in thread
* [PATCH v2 39/64] dmaengine: fsl-edma-common: kill vchan BH on teardown
2026-07-27 20:28 ` [PATCH v2 00/64] dmaengine: migrate channel tasklets to WQ_BH Allen Pais
` (37 preceding siblings ...)
2026-07-27 20:39 ` [PATCH v2 38/64] dmaengine: img-mdc-dma: " Allen Pais
@ 2026-07-27 20:39 ` Allen Pais
2026-07-27 20:39 ` [PATCH v2 40/64] dmaengine: dw-axi-dmac: " Allen Pais
` (25 subsequent siblings)
64 siblings, 0 replies; 82+ messages in thread
From: Allen Pais @ 2026-07-27 20:39 UTC (permalink / raw)
To: Vinod Koul, Frank Li
Cc: Allen Pais, dmaengine, linux-kernel, Arnd Bergmann, Kees Cook,
Frank Li, imx
Use dma_chan_kill_bh() for virt-dma cleanup.
Signed-off-by: Allen Pais <allen.lkml@gmail.com>
---
drivers/dma/fsl-edma-common.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/dma/fsl-edma-common.c b/drivers/dma/fsl-edma-common.c
index bb7531c456df..70b40e60c39a 100644
--- a/drivers/dma/fsl-edma-common.c
+++ b/drivers/dma/fsl-edma-common.c
@@ -915,7 +915,7 @@ void fsl_edma_cleanup_vchan(struct dma_device *dmadev)
list_for_each_entry_safe(chan, _chan,
&dmadev->channels, vchan.chan.device_node) {
list_del(&chan->vchan.chan.device_node);
- tasklet_kill(&chan->vchan.task);
+ dma_chan_kill_bh(&chan->vchan.chan);
}
}
--
2.43.0
^ permalink raw reply related [flat|nested] 82+ messages in thread
* [PATCH v2 40/64] dmaengine: dw-axi-dmac: kill vchan BH on teardown
2026-07-27 20:28 ` [PATCH v2 00/64] dmaengine: migrate channel tasklets to WQ_BH Allen Pais
` (38 preceding siblings ...)
2026-07-27 20:39 ` [PATCH v2 39/64] dmaengine: fsl-edma-common: " Allen Pais
@ 2026-07-27 20:39 ` Allen Pais
2026-07-27 20:39 ` [PATCH v2 41/64] dmaengine: hsu: " Allen Pais
` (24 subsequent siblings)
64 siblings, 0 replies; 82+ messages in thread
From: Allen Pais @ 2026-07-27 20:39 UTC (permalink / raw)
To: Vinod Koul, Frank Li
Cc: Allen Pais, dmaengine, linux-kernel, Arnd Bergmann, Kees Cook,
Eugeniy Paltsev
Use dma_chan_kill_bh() for virt-dma cleanup.
Signed-off-by: Allen Pais <allen.lkml@gmail.com>
---
drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c
index bcefaff03b5c..5a5d569b188d 100644
--- a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c
+++ b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c
@@ -1663,7 +1663,7 @@ static void dw_remove(struct platform_device *pdev)
list_for_each_entry_safe(chan, _chan, &dw->dma.channels,
vc.chan.device_node) {
list_del(&chan->vc.chan.device_node);
- tasklet_kill(&chan->vc.task);
+ dma_chan_kill_bh(&chan->vc.chan);
}
}
--
2.43.0
^ permalink raw reply related [flat|nested] 82+ messages in thread
* [PATCH v2 41/64] dmaengine: hsu: kill vchan BH on teardown
2026-07-27 20:28 ` [PATCH v2 00/64] dmaengine: migrate channel tasklets to WQ_BH Allen Pais
` (39 preceding siblings ...)
2026-07-27 20:39 ` [PATCH v2 40/64] dmaengine: dw-axi-dmac: " Allen Pais
@ 2026-07-27 20:39 ` Allen Pais
2026-07-28 8:47 ` Andy Shevchenko
2026-07-27 20:39 ` [PATCH v2 42/64] dmaengine: jz4780: " Allen Pais
` (23 subsequent siblings)
64 siblings, 1 reply; 82+ messages in thread
From: Allen Pais @ 2026-07-27 20:39 UTC (permalink / raw)
To: Vinod Koul, Frank Li
Cc: Allen Pais, dmaengine, linux-kernel, Arnd Bergmann, Kees Cook,
Andy Shevchenko
Use dma_chan_kill_bh() for virt-dma cleanup.
Signed-off-by: Allen Pais <allen.lkml@gmail.com>
---
drivers/dma/hsu/hsu.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/dma/hsu/hsu.c b/drivers/dma/hsu/hsu.c
index f62d60d7bc6b..1a7f9df735a4 100644
--- a/drivers/dma/hsu/hsu.c
+++ b/drivers/dma/hsu/hsu.c
@@ -500,7 +500,7 @@ int hsu_dma_remove(struct hsu_dma_chip *chip)
for (i = 0; i < hsu->nr_channels; i++) {
struct hsu_dma_chan *hsuc = &hsu->chan[i];
- tasklet_kill(&hsuc->vchan.task);
+ dma_chan_kill_bh(&hsuc->vchan.chan);
}
return 0;
--
2.43.0
^ permalink raw reply related [flat|nested] 82+ messages in thread
* [PATCH v2 42/64] dmaengine: jz4780: kill vchan BH on teardown
2026-07-27 20:28 ` [PATCH v2 00/64] dmaengine: migrate channel tasklets to WQ_BH Allen Pais
` (40 preceding siblings ...)
2026-07-27 20:39 ` [PATCH v2 41/64] dmaengine: hsu: " Allen Pais
@ 2026-07-27 20:39 ` Allen Pais
2026-07-27 20:39 ` [PATCH v2 43/64] dmaengine: pxa_dma: " Allen Pais
` (22 subsequent siblings)
64 siblings, 0 replies; 82+ messages in thread
From: Allen Pais @ 2026-07-27 20:39 UTC (permalink / raw)
To: Vinod Koul, Frank Li
Cc: Allen Pais, dmaengine, linux-kernel, Arnd Bergmann, Kees Cook,
Paul Cercueil, linux-mips
Use dma_chan_kill_bh() for virt-dma cleanup.
Signed-off-by: Allen Pais <allen.lkml@gmail.com>
---
drivers/dma/dma-jz4780.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/dma/dma-jz4780.c b/drivers/dma/dma-jz4780.c
index 6070dfdb7114..45c1096563e3 100644
--- a/drivers/dma/dma-jz4780.c
+++ b/drivers/dma/dma-jz4780.c
@@ -1019,7 +1019,7 @@ static void jz4780_dma_remove(struct platform_device *pdev)
free_irq(jzdma->irq, jzdma);
for (i = 0; i < jzdma->soc_data->nb_channels; i++)
- tasklet_kill(&jzdma->chan[i].vchan.task);
+ dma_chan_kill_bh(&jzdma->chan[i].vchan.chan);
}
static const struct jz4780_dma_soc_data jz4740_dma_soc_data = {
--
2.43.0
^ permalink raw reply related [flat|nested] 82+ messages in thread
* [PATCH v2 43/64] dmaengine: pxa_dma: kill vchan BH on teardown
2026-07-27 20:28 ` [PATCH v2 00/64] dmaengine: migrate channel tasklets to WQ_BH Allen Pais
` (41 preceding siblings ...)
2026-07-27 20:39 ` [PATCH v2 42/64] dmaengine: jz4780: " Allen Pais
@ 2026-07-27 20:39 ` Allen Pais
2026-07-27 20:39 ` [PATCH v2 44/64] dmaengine: mtk-hsdma: " Allen Pais
` (21 subsequent siblings)
64 siblings, 0 replies; 82+ messages in thread
From: Allen Pais @ 2026-07-27 20:39 UTC (permalink / raw)
To: Vinod Koul, Frank Li
Cc: Allen Pais, dmaengine, linux-kernel, Arnd Bergmann, Kees Cook,
Daniel Mack, Haojian Zhuang, Robert Jarzmik, linux-arm-kernel
Use dma_chan_kill_bh() for virt-dma cleanup.
Signed-off-by: Allen Pais <allen.lkml@gmail.com>
---
drivers/dma/pxa_dma.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/dma/pxa_dma.c b/drivers/dma/pxa_dma.c
index fa2ee0b3e09f..d57e5e0c422c 100644
--- a/drivers/dma/pxa_dma.c
+++ b/drivers/dma/pxa_dma.c
@@ -1215,7 +1215,7 @@ static void pxad_free_channels(struct dma_device *dmadev)
list_for_each_entry_safe(c, cn, &dmadev->channels,
vc.chan.device_node) {
list_del(&c->vc.chan.device_node);
- tasklet_kill(&c->vc.task);
+ dma_chan_kill_bh(&c->vc.chan);
}
}
--
2.43.0
^ permalink raw reply related [flat|nested] 82+ messages in thread
* [PATCH v2 44/64] dmaengine: mtk-hsdma: kill vchan BH on teardown
2026-07-27 20:28 ` [PATCH v2 00/64] dmaengine: migrate channel tasklets to WQ_BH Allen Pais
` (42 preceding siblings ...)
2026-07-27 20:39 ` [PATCH v2 43/64] dmaengine: pxa_dma: " Allen Pais
@ 2026-07-27 20:39 ` Allen Pais
2026-07-27 20:39 ` [PATCH v2 45/64] dmaengine: mtk-uart-apdma: " Allen Pais
` (20 subsequent siblings)
64 siblings, 0 replies; 82+ messages in thread
From: Allen Pais @ 2026-07-27 20:39 UTC (permalink / raw)
To: Vinod Koul, Frank Li
Cc: Allen Pais, dmaengine, linux-kernel, Arnd Bergmann, Kees Cook,
Sean Wang, Matthias Brugger, AngeloGioacchino Del Regno,
linux-arm-kernel, linux-mediatek
Use dma_chan_kill_bh() for virt-dma cleanup.
Signed-off-by: Allen Pais <allen.lkml@gmail.com>
---
drivers/dma/mediatek/mtk-hsdma.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/dma/mediatek/mtk-hsdma.c b/drivers/dma/mediatek/mtk-hsdma.c
index a43412ff5edd..1c98fcedf3ac 100644
--- a/drivers/dma/mediatek/mtk-hsdma.c
+++ b/drivers/dma/mediatek/mtk-hsdma.c
@@ -1020,7 +1020,7 @@ static void mtk_hsdma_remove(struct platform_device *pdev)
vc = &hsdma->vc[i];
list_del(&vc->vc.chan.device_node);
- tasklet_kill(&vc->vc.task);
+ dma_chan_kill_bh(&vc->vc.chan);
}
/* Disable DMA interrupt */
--
2.43.0
^ permalink raw reply related [flat|nested] 82+ messages in thread
* [PATCH v2 45/64] dmaengine: mtk-uart-apdma: kill vchan BH on teardown
2026-07-27 20:28 ` [PATCH v2 00/64] dmaengine: migrate channel tasklets to WQ_BH Allen Pais
` (43 preceding siblings ...)
2026-07-27 20:39 ` [PATCH v2 44/64] dmaengine: mtk-hsdma: " Allen Pais
@ 2026-07-27 20:39 ` Allen Pais
2026-07-27 20:39 ` [PATCH v2 46/64] dmaengine: imx-sdma: " Allen Pais
` (19 subsequent siblings)
64 siblings, 0 replies; 82+ messages in thread
From: Allen Pais @ 2026-07-27 20:39 UTC (permalink / raw)
To: Vinod Koul, Frank Li
Cc: Allen Pais, dmaengine, linux-kernel, Arnd Bergmann, Kees Cook,
Sean Wang, Matthias Brugger, AngeloGioacchino Del Regno,
linux-arm-kernel, linux-mediatek
Use dma_chan_kill_bh() for virt-dma cleanup.
Signed-off-by: Allen Pais <allen.lkml@gmail.com>
---
drivers/dma/mediatek/mtk-uart-apdma.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/dma/mediatek/mtk-uart-apdma.c b/drivers/dma/mediatek/mtk-uart-apdma.c
index c269d84d7bd2..4d89927922f5 100644
--- a/drivers/dma/mediatek/mtk-uart-apdma.c
+++ b/drivers/dma/mediatek/mtk-uart-apdma.c
@@ -312,7 +312,7 @@ static void mtk_uart_apdma_free_chan_resources(struct dma_chan *chan)
free_irq(c->irq, chan);
- tasklet_kill(&c->vc.task);
+ dma_chan_kill_bh(&c->vc.chan);
vchan_free_chan_resources(&c->vc);
@@ -463,7 +463,7 @@ static void mtk_uart_apdma_free(struct mtk_uart_apdmadev *mtkd)
struct mtk_chan, vc.chan.device_node);
list_del(&c->vc.chan.device_node);
- tasklet_kill(&c->vc.task);
+ dma_chan_kill_bh(&c->vc.chan);
}
}
--
2.43.0
^ permalink raw reply related [flat|nested] 82+ messages in thread
* [PATCH v2 46/64] dmaengine: imx-sdma: kill vchan BH on teardown
2026-07-27 20:28 ` [PATCH v2 00/64] dmaengine: migrate channel tasklets to WQ_BH Allen Pais
` (44 preceding siblings ...)
2026-07-27 20:39 ` [PATCH v2 45/64] dmaengine: mtk-uart-apdma: " Allen Pais
@ 2026-07-27 20:39 ` Allen Pais
2026-07-27 20:39 ` [PATCH v2 47/64] dmaengine: loongson1-apb: " Allen Pais
` (18 subsequent siblings)
64 siblings, 0 replies; 82+ messages in thread
From: Allen Pais @ 2026-07-27 20:39 UTC (permalink / raw)
To: Vinod Koul, Frank Li
Cc: Allen Pais, dmaengine, linux-kernel, Arnd Bergmann, Kees Cook,
Sascha Hauer, Pengutronix Kernel Team, Fabio Estevam, imx,
linux-arm-kernel
Use dma_chan_kill_bh() for virt-dma cleanup.
Signed-off-by: Allen Pais <allen.lkml@gmail.com>
---
drivers/dma/imx-sdma.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c
index 36368835a845..46f66e5f9f30 100644
--- a/drivers/dma/imx-sdma.c
+++ b/drivers/dma/imx-sdma.c
@@ -2399,11 +2399,11 @@ static void sdma_remove(struct platform_device *pdev)
int i;
devm_free_irq(&pdev->dev, sdma->irq, sdma);
- /* Kill the tasklet */
+ /* Kill the channel BH */
for (i = 0; i < MAX_DMA_CHANNELS; i++) {
struct sdma_channel *sdmac = &sdma->channel[i];
- tasklet_kill(&sdmac->vc.task);
+ dma_chan_kill_bh(&sdmac->vc.chan);
sdma_free_chan_resources(&sdmac->vc.chan);
}
--
2.43.0
^ permalink raw reply related [flat|nested] 82+ messages in thread
* [PATCH v2 47/64] dmaengine: loongson1-apb: kill vchan BH on teardown
2026-07-27 20:28 ` [PATCH v2 00/64] dmaengine: migrate channel tasklets to WQ_BH Allen Pais
` (45 preceding siblings ...)
2026-07-27 20:39 ` [PATCH v2 46/64] dmaengine: imx-sdma: " Allen Pais
@ 2026-07-27 20:39 ` Allen Pais
2026-07-27 20:39 ` [PATCH v2 48/64] dmaengine: owl-dma: " Allen Pais
` (17 subsequent siblings)
64 siblings, 0 replies; 82+ messages in thread
From: Allen Pais @ 2026-07-27 20:39 UTC (permalink / raw)
To: Vinod Koul, Frank Li
Cc: Allen Pais, dmaengine, linux-kernel, Arnd Bergmann, Kees Cook,
Keguang Zhang, linux-mips
Use dma_chan_kill_bh() for virt-dma cleanup.
Signed-off-by: Allen Pais <allen.lkml@gmail.com>
---
drivers/dma/loongson/loongson1-apb-dma.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/dma/loongson/loongson1-apb-dma.c b/drivers/dma/loongson/loongson1-apb-dma.c
index 89786cbd20ab..7fc77d8e6db3 100644
--- a/drivers/dma/loongson/loongson1-apb-dma.c
+++ b/drivers/dma/loongson/loongson1-apb-dma.c
@@ -552,7 +552,7 @@ static void ls1x_dma_chan_remove(struct ls1x_dma *dma)
if (chan->vc.chan.device == &dma->ddev) {
list_del(&chan->vc.chan.device_node);
- tasklet_kill(&chan->vc.task);
+ dma_chan_kill_bh(&chan->vc.chan);
}
}
}
--
2.43.0
^ permalink raw reply related [flat|nested] 82+ messages in thread
* [PATCH v2 48/64] dmaengine: owl-dma: kill vchan BH on teardown
2026-07-27 20:28 ` [PATCH v2 00/64] dmaengine: migrate channel tasklets to WQ_BH Allen Pais
` (46 preceding siblings ...)
2026-07-27 20:39 ` [PATCH v2 47/64] dmaengine: loongson1-apb: " Allen Pais
@ 2026-07-27 20:39 ` Allen Pais
2026-07-27 20:39 ` [PATCH v2 49/64] dmaengine: hisi: " Allen Pais
` (16 subsequent siblings)
64 siblings, 0 replies; 82+ messages in thread
From: Allen Pais @ 2026-07-27 20:39 UTC (permalink / raw)
To: Vinod Koul, Frank Li
Cc: Allen Pais, dmaengine, linux-kernel, Arnd Bergmann, Kees Cook,
Andreas Färber, Manivannan Sadhasivam, linux-arm-kernel,
linux-actions
Use dma_chan_kill_bh() for virt-dma cleanup.
Signed-off-by: Allen Pais <allen.lkml@gmail.com>
---
drivers/dma/owl-dma.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/dma/owl-dma.c b/drivers/dma/owl-dma.c
index 7c80572fc71d..5f2140dc01ce 100644
--- a/drivers/dma/owl-dma.c
+++ b/drivers/dma/owl-dma.c
@@ -1055,7 +1055,7 @@ static inline void owl_dma_free(struct owl_dma *od)
list_for_each_entry_safe(vchan,
next, &od->dma.channels, vc.chan.device_node) {
list_del(&vchan->vc.chan.device_node);
- tasklet_kill(&vchan->vc.task);
+ dma_chan_kill_bh(&vchan->vc.chan);
}
}
--
2.43.0
^ permalink raw reply related [flat|nested] 82+ messages in thread
* [PATCH v2 49/64] dmaengine: hisi: kill vchan BH on teardown
2026-07-27 20:28 ` [PATCH v2 00/64] dmaengine: migrate channel tasklets to WQ_BH Allen Pais
` (47 preceding siblings ...)
2026-07-27 20:39 ` [PATCH v2 48/64] dmaengine: owl-dma: " Allen Pais
@ 2026-07-27 20:39 ` Allen Pais
2026-07-27 20:39 ` [PATCH v2 50/64] dmaengine: dw-edma: " Allen Pais
` (15 subsequent siblings)
64 siblings, 0 replies; 82+ messages in thread
From: Allen Pais @ 2026-07-27 20:39 UTC (permalink / raw)
To: Vinod Koul, Frank Li
Cc: Allen Pais, dmaengine, linux-kernel, Arnd Bergmann, Kees Cook,
Zhou Wang, Longfang Liu
Use dma_chan_kill_bh() for virt-dma cleanup.
Signed-off-by: Allen Pais <allen.lkml@gmail.com>
---
drivers/dma/hisi_dma.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/dma/hisi_dma.c b/drivers/dma/hisi_dma.c
index 28bf818f9aa6..39bc88c46513 100644
--- a/drivers/dma/hisi_dma.c
+++ b/drivers/dma/hisi_dma.c
@@ -720,7 +720,7 @@ static void hisi_dma_disable_qps(struct hisi_dma_dev *hdma_dev)
for (i = 0; i < hdma_dev->chan_num; i++) {
hisi_dma_disable_qp(hdma_dev, i);
- tasklet_kill(&hdma_dev->chan[i].vc.task);
+ dma_chan_kill_bh(&hdma_dev->chan[i].vc.chan);
}
}
--
2.43.0
^ permalink raw reply related [flat|nested] 82+ messages in thread
* [PATCH v2 50/64] dmaengine: dw-edma: kill vchan BH on teardown
2026-07-27 20:28 ` [PATCH v2 00/64] dmaengine: migrate channel tasklets to WQ_BH Allen Pais
` (48 preceding siblings ...)
2026-07-27 20:39 ` [PATCH v2 49/64] dmaengine: hisi: " Allen Pais
@ 2026-07-27 20:39 ` Allen Pais
2026-07-27 20:39 ` [PATCH v2 51/64] dmaengine: bcm2835: " Allen Pais
` (14 subsequent siblings)
64 siblings, 0 replies; 82+ messages in thread
From: Allen Pais @ 2026-07-27 20:39 UTC (permalink / raw)
To: Vinod Koul, Frank Li
Cc: Allen Pais, dmaengine, linux-kernel, Arnd Bergmann, Kees Cook,
Manivannan Sadhasivam
Use dma_chan_kill_bh() for virt-dma cleanup.
Signed-off-by: Allen Pais <allen.lkml@gmail.com>
---
drivers/dma/dw-edma/dw-edma-core.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/dma/dw-edma/dw-edma-core.c b/drivers/dma/dw-edma/dw-edma-core.c
index 89a4c498a17b..a47a4674df83 100644
--- a/drivers/dma/dw-edma/dw-edma-core.c
+++ b/drivers/dma/dw-edma/dw-edma-core.c
@@ -1170,7 +1170,7 @@ int dw_edma_remove(struct dw_edma_chip *chip)
dma_async_device_unregister(&dw->dma);
list_for_each_entry_safe(chan, _chan, &dw->dma.channels,
vc.chan.device_node) {
- tasklet_kill(&chan->vc.task);
+ dma_chan_kill_bh(&chan->vc.chan);
list_del(&chan->vc.chan.device_node);
}
--
2.43.0
^ permalink raw reply related [flat|nested] 82+ messages in thread
* [PATCH v2 51/64] dmaengine: bcm2835: kill vchan BH on teardown
2026-07-27 20:28 ` [PATCH v2 00/64] dmaengine: migrate channel tasklets to WQ_BH Allen Pais
` (49 preceding siblings ...)
2026-07-27 20:39 ` [PATCH v2 50/64] dmaengine: dw-edma: " Allen Pais
@ 2026-07-27 20:39 ` Allen Pais
2026-07-27 20:39 ` [PATCH v2 52/64] dmaengine: tegra210-adma: " Allen Pais
` (13 subsequent siblings)
64 siblings, 0 replies; 82+ messages in thread
From: Allen Pais @ 2026-07-27 20:39 UTC (permalink / raw)
To: Vinod Koul, Frank Li
Cc: Allen Pais, dmaengine, linux-kernel, Arnd Bergmann, Kees Cook,
Florian Fainelli, Broadcom internal kernel review list, Ray Jui,
Scott Branden, linux-rpi-kernel, linux-arm-kernel
Use dma_chan_kill_bh() for virt-dma cleanup.
Signed-off-by: Allen Pais <allen.lkml@gmail.com>
---
drivers/dma/bcm2835-dma.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/dma/bcm2835-dma.c b/drivers/dma/bcm2835-dma.c
index 06d830d36882..68e86c8d3d43 100644
--- a/drivers/dma/bcm2835-dma.c
+++ b/drivers/dma/bcm2835-dma.c
@@ -829,7 +829,7 @@ static void bcm2835_dma_free(struct bcm2835_dmadev *od)
list_for_each_entry_safe(c, next, &od->ddev.channels,
vc.chan.device_node) {
list_del(&c->vc.chan.device_node);
- tasklet_kill(&c->vc.task);
+ dma_chan_kill_bh(&c->vc.chan);
}
dma_unmap_page_attrs(od->ddev.dev, od->zero_page, PAGE_SIZE,
--
2.43.0
^ permalink raw reply related [flat|nested] 82+ messages in thread
* [PATCH v2 52/64] dmaengine: tegra210-adma: kill vchan BH on teardown
2026-07-27 20:28 ` [PATCH v2 00/64] dmaengine: migrate channel tasklets to WQ_BH Allen Pais
` (50 preceding siblings ...)
2026-07-27 20:39 ` [PATCH v2 51/64] dmaengine: bcm2835: " Allen Pais
@ 2026-07-27 20:39 ` Allen Pais
2026-07-27 20:39 ` [PATCH v2 53/64] dmaengine: fsl-qdma: use dma_chan_kill_bh Allen Pais
` (12 subsequent siblings)
64 siblings, 0 replies; 82+ messages in thread
From: Allen Pais @ 2026-07-27 20:39 UTC (permalink / raw)
To: Vinod Koul, Frank Li
Cc: Allen Pais, dmaengine, linux-kernel, Arnd Bergmann, Kees Cook,
Laxman Dewangan, Jon Hunter, Thierry Reding, linux-tegra
Use dma_chan_kill_bh() for virt-dma cleanup.
Signed-off-by: Allen Pais <allen.lkml@gmail.com>
---
drivers/dma/tegra210-adma.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/dma/tegra210-adma.c b/drivers/dma/tegra210-adma.c
index ceaee1e33e68..598abcc4edaa 100644
--- a/drivers/dma/tegra210-adma.c
+++ b/drivers/dma/tegra210-adma.c
@@ -811,7 +811,7 @@ static void tegra_adma_free_chan_resources(struct dma_chan *dc)
tegra_adma_terminate_all(dc);
vchan_free_chan_resources(&tdc->vc);
- tasklet_kill(&tdc->vc.task);
+ dma_chan_kill_bh(&tdc->vc.chan);
free_irq(tdc->irq, tdc);
pm_runtime_put(tdc2dev(tdc));
--
2.43.0
^ permalink raw reply related [flat|nested] 82+ messages in thread
* [PATCH v2 53/64] dmaengine: fsl-qdma: use dma_chan_kill_bh
2026-07-27 20:28 ` [PATCH v2 00/64] dmaengine: migrate channel tasklets to WQ_BH Allen Pais
` (51 preceding siblings ...)
2026-07-27 20:39 ` [PATCH v2 52/64] dmaengine: tegra210-adma: " Allen Pais
@ 2026-07-27 20:39 ` Allen Pais
2026-07-27 20:39 ` [PATCH v2 54/64] dmaengine: st_fdma: " Allen Pais
` (11 subsequent siblings)
64 siblings, 0 replies; 82+ messages in thread
From: Allen Pais @ 2026-07-27 20:39 UTC (permalink / raw)
To: Vinod Koul, Frank Li
Cc: Allen Pais, dmaengine, linux-kernel, Arnd Bergmann, Kees Cook
virt-dma now dispatches completion callbacks through per-channel BH
work instead of its tasklet. Cancel that work during teardown before
channel storage is released.
Signed-off-by: Allen Pais <allen.lkml@gmail.com>
---
drivers/dma/fsl-qdma.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/dma/fsl-qdma.c b/drivers/dma/fsl-qdma.c
index df843fad0ece..e0fb39fe821c 100644
--- a/drivers/dma/fsl-qdma.c
+++ b/drivers/dma/fsl-qdma.c
@@ -1255,7 +1255,7 @@ static void fsl_qdma_cleanup_vchan(struct dma_device *dmadev)
list_for_each_entry_safe(chan, _chan,
&dmadev->channels, vchan.chan.device_node) {
list_del(&chan->vchan.chan.device_node);
- tasklet_kill(&chan->vchan.task);
+ dma_chan_kill_bh(&chan->vchan.chan);
}
}
--
2.43.0
^ permalink raw reply related [flat|nested] 82+ messages in thread
* [PATCH v2 54/64] dmaengine: st_fdma: use dma_chan_kill_bh
2026-07-27 20:28 ` [PATCH v2 00/64] dmaengine: migrate channel tasklets to WQ_BH Allen Pais
` (52 preceding siblings ...)
2026-07-27 20:39 ` [PATCH v2 53/64] dmaengine: fsl-qdma: use dma_chan_kill_bh Allen Pais
@ 2026-07-27 20:39 ` Allen Pais
2026-07-27 20:39 ` [PATCH v2 55/64] dmaengine: dma-axi-dmac: " Allen Pais
` (10 subsequent siblings)
64 siblings, 0 replies; 82+ messages in thread
From: Allen Pais @ 2026-07-27 20:39 UTC (permalink / raw)
To: Vinod Koul, Frank Li
Cc: Allen Pais, dmaengine, linux-kernel, Arnd Bergmann, Kees Cook,
Patrice Chotard, linux-arm-kernel
virt-dma now dispatches completion callbacks through per-channel BH
work instead of its tasklet. Cancel that work during teardown before
channel storage is released.
Signed-off-by: Allen Pais <allen.lkml@gmail.com>
---
drivers/dma/st_fdma.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/dma/st_fdma.c b/drivers/dma/st_fdma.c
index d9547017f3bd..d4cff851e1d5 100644
--- a/drivers/dma/st_fdma.c
+++ b/drivers/dma/st_fdma.c
@@ -733,7 +733,7 @@ static void st_fdma_free(struct st_fdma_dev *fdev)
for (i = 0; i < fdev->nr_channels; i++) {
fchan = &fdev->chans[i];
list_del(&fchan->vchan.chan.device_node);
- tasklet_kill(&fchan->vchan.task);
+ dma_chan_kill_bh(&fchan->vchan.chan);
}
}
--
2.43.0
^ permalink raw reply related [flat|nested] 82+ messages in thread
* [PATCH v2 55/64] dmaengine: dma-axi-dmac: use dma_chan_kill_bh
2026-07-27 20:28 ` [PATCH v2 00/64] dmaengine: migrate channel tasklets to WQ_BH Allen Pais
` (53 preceding siblings ...)
2026-07-27 20:39 ` [PATCH v2 54/64] dmaengine: st_fdma: " Allen Pais
@ 2026-07-27 20:39 ` Allen Pais
2026-07-27 20:39 ` [PATCH v2 56/64] dmaengine: omap-dma: " Allen Pais
` (9 subsequent siblings)
64 siblings, 0 replies; 82+ messages in thread
From: Allen Pais @ 2026-07-27 20:39 UTC (permalink / raw)
To: Vinod Koul, Frank Li
Cc: Allen Pais, dmaengine, linux-kernel, Arnd Bergmann, Kees Cook,
Lars-Peter Clausen
virt-dma now dispatches completion callbacks through per-channel BH
work instead of its tasklet. Cancel that work during teardown before
channel storage is released.
Signed-off-by: Allen Pais <allen.lkml@gmail.com>
---
drivers/dma/dma-axi-dmac.c | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)
diff --git a/drivers/dma/dma-axi-dmac.c b/drivers/dma/dma-axi-dmac.c
index d47ff27e1408..d26bfa852806 100644
--- a/drivers/dma/dma-axi-dmac.c
+++ b/drivers/dma/dma-axi-dmac.c
@@ -1195,9 +1195,11 @@ static int axi_dmac_detect_caps(struct axi_dmac *dmac, unsigned int version)
return 0;
}
-static void axi_dmac_tasklet_kill(void *task)
+static void axi_dmac_kill_bh(void *data)
{
- tasklet_kill(task);
+ struct dma_chan *chan = data;
+
+ dma_chan_kill_bh(chan);
}
static void axi_dmac_free_dma_controller(void *of_node)
@@ -1302,8 +1304,8 @@ static int axi_dmac_probe(struct platform_device *pdev)
* Put the action in here so it get's done before unregistering the DMA
* device.
*/
- ret = devm_add_action_or_reset(&pdev->dev, axi_dmac_tasklet_kill,
- &dmac->chan.vchan.task);
+ ret = devm_add_action_or_reset(&pdev->dev, axi_dmac_kill_bh,
+ &dmac->chan.vchan.chan);
if (ret)
return ret;
--
2.43.0
^ permalink raw reply related [flat|nested] 82+ messages in thread
* [PATCH v2 56/64] dmaengine: omap-dma: use dma_chan_kill_bh
2026-07-27 20:28 ` [PATCH v2 00/64] dmaengine: migrate channel tasklets to WQ_BH Allen Pais
` (54 preceding siblings ...)
2026-07-27 20:39 ` [PATCH v2 55/64] dmaengine: dma-axi-dmac: " Allen Pais
@ 2026-07-27 20:39 ` Allen Pais
2026-07-27 20:39 ` [PATCH v2 57/64] dmaengine: edma: " Allen Pais
` (8 subsequent siblings)
64 siblings, 0 replies; 82+ messages in thread
From: Allen Pais @ 2026-07-27 20:39 UTC (permalink / raw)
To: Vinod Koul, Frank Li
Cc: Allen Pais, dmaengine, linux-kernel, Arnd Bergmann, Kees Cook,
Vignesh Raghavendra
virt-dma now dispatches completion callbacks through per-channel BH
work instead of its tasklet. Cancel that work during teardown before
channel storage is released.
Signed-off-by: Allen Pais <allen.lkml@gmail.com>
---
drivers/dma/ti/omap-dma.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/dma/ti/omap-dma.c b/drivers/dma/ti/omap-dma.c
index 55ece7fd0d99..10cdbcd12fe6 100644
--- a/drivers/dma/ti/omap-dma.c
+++ b/drivers/dma/ti/omap-dma.c
@@ -1521,7 +1521,7 @@ static void omap_dma_free(struct omap_dmadev *od)
struct omap_chan, vc.chan.device_node);
list_del(&c->vc.chan.device_node);
- tasklet_kill(&c->vc.task);
+ dma_chan_kill_bh(&c->vc.chan);
kfree(c);
}
}
--
2.43.0
^ permalink raw reply related [flat|nested] 82+ messages in thread
* [PATCH v2 57/64] dmaengine: edma: use dma_chan_kill_bh
2026-07-27 20:28 ` [PATCH v2 00/64] dmaengine: migrate channel tasklets to WQ_BH Allen Pais
` (55 preceding siblings ...)
2026-07-27 20:39 ` [PATCH v2 56/64] dmaengine: omap-dma: " Allen Pais
@ 2026-07-27 20:39 ` Allen Pais
2026-07-27 20:39 ` [PATCH v2 58/64] dmaengine: qcom-adm: " Allen Pais
` (7 subsequent siblings)
64 siblings, 0 replies; 82+ messages in thread
From: Allen Pais @ 2026-07-27 20:39 UTC (permalink / raw)
To: Vinod Koul, Frank Li
Cc: Allen Pais, dmaengine, linux-kernel, Arnd Bergmann, Kees Cook,
Vignesh Raghavendra
virt-dma now dispatches completion callbacks through per-channel BH
work instead of its tasklet. Cancel that work during teardown before
channel storage is released.
Signed-off-by: Allen Pais <allen.lkml@gmail.com>
---
drivers/dma/ti/edma.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/dma/ti/edma.c b/drivers/dma/ti/edma.c
index d97db5af3555..c0b16cd24752 100644
--- a/drivers/dma/ti/edma.c
+++ b/drivers/dma/ti/edma.c
@@ -2560,7 +2560,7 @@ static void edma_cleanupp_vchan(struct dma_device *dmadev)
list_for_each_entry_safe(echan, _echan,
&dmadev->channels, vchan.chan.device_node) {
list_del(&echan->vchan.chan.device_node);
- tasklet_kill(&echan->vchan.task);
+ dma_chan_kill_bh(&echan->vchan.chan);
}
}
--
2.43.0
^ permalink raw reply related [flat|nested] 82+ messages in thread
* [PATCH v2 58/64] dmaengine: qcom-adm: use dma_chan_kill_bh
2026-07-27 20:28 ` [PATCH v2 00/64] dmaengine: migrate channel tasklets to WQ_BH Allen Pais
` (56 preceding siblings ...)
2026-07-27 20:39 ` [PATCH v2 57/64] dmaengine: edma: " Allen Pais
@ 2026-07-27 20:39 ` Allen Pais
2026-07-27 20:39 ` [PATCH v2 59/64] dmaengine: tegra186-gpc: " Allen Pais
` (6 subsequent siblings)
64 siblings, 0 replies; 82+ messages in thread
From: Allen Pais @ 2026-07-27 20:39 UTC (permalink / raw)
To: Vinod Koul, Frank Li
Cc: Allen Pais, dmaengine, linux-kernel, Arnd Bergmann, Kees Cook,
Bjorn Andersson, Andy Shevchenko, linux-arm-msm
virt-dma now dispatches completion callbacks through per-channel BH
work instead of its tasklet. Cancel that work during teardown before
channel storage is released.
Signed-off-by: Allen Pais <allen.lkml@gmail.com>
---
drivers/dma/qcom/qcom_adm.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/dma/qcom/qcom_adm.c b/drivers/dma/qcom/qcom_adm.c
index 07fbe32d31fa..ea24e2de5154 100644
--- a/drivers/dma/qcom/qcom_adm.c
+++ b/drivers/dma/qcom/qcom_adm.c
@@ -918,8 +918,8 @@ static void adm_dma_remove(struct platform_device *pdev)
/* mask IRQs for this channel/EE pair */
writel(0, adev->regs + ADM_CH_RSLT_CONF(achan->id, adev->ee));
- tasklet_kill(&adev->channels[i].vc.task);
- adm_terminate_all(&adev->channels[i].vc.chan);
+ dma_chan_kill_bh(&achan->vc.chan);
+ adm_terminate_all(&achan->vc.chan);
}
devm_free_irq(adev->dev, adev->irq, adev);
--
2.43.0
^ permalink raw reply related [flat|nested] 82+ messages in thread
* [PATCH v2 59/64] dmaengine: tegra186-gpc: use dma_chan_kill_bh
2026-07-27 20:28 ` [PATCH v2 00/64] dmaengine: migrate channel tasklets to WQ_BH Allen Pais
` (57 preceding siblings ...)
2026-07-27 20:39 ` [PATCH v2 58/64] dmaengine: qcom-adm: " Allen Pais
@ 2026-07-27 20:39 ` Allen Pais
2026-07-27 20:39 ` [PATCH v2 60/64] dmaengine: bam-dma: " Allen Pais
` (5 subsequent siblings)
64 siblings, 0 replies; 82+ messages in thread
From: Allen Pais @ 2026-07-27 20:39 UTC (permalink / raw)
To: Vinod Koul, Frank Li
Cc: Allen Pais, dmaengine, linux-kernel, Arnd Bergmann, Kees Cook,
Laxman Dewangan, Jon Hunter, Thierry Reding, linux-tegra
virt-dma now dispatches completion callbacks through per-channel BH
work instead of its tasklet. Cancel that work during teardown before
channel storage is released.
Signed-off-by: Allen Pais <allen.lkml@gmail.com>
---
drivers/dma/tegra186-gpc-dma.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/dma/tegra186-gpc-dma.c b/drivers/dma/tegra186-gpc-dma.c
index 64cedef1050a..1ba8897ec614 100644
--- a/drivers/dma/tegra186-gpc-dma.c
+++ b/drivers/dma/tegra186-gpc-dma.c
@@ -1284,7 +1284,7 @@ static void tegra_dma_free_chan_resources(struct dma_chan *dc)
tegra_dma_terminate_all(dc);
synchronize_irq(tdc->irq);
- tasklet_kill(&tdc->vc.task);
+ dma_chan_kill_bh(&tdc->vc.chan);
tdc->config_init = false;
tdc->slave_id = -1;
tdc->sid_dir = DMA_TRANS_NONE;
--
2.43.0
^ permalink raw reply related [flat|nested] 82+ messages in thread
* [PATCH v2 60/64] dmaengine: bam-dma: use dma_chan_kill_bh
2026-07-27 20:28 ` [PATCH v2 00/64] dmaengine: migrate channel tasklets to WQ_BH Allen Pais
` (58 preceding siblings ...)
2026-07-27 20:39 ` [PATCH v2 59/64] dmaengine: tegra186-gpc: " Allen Pais
@ 2026-07-27 20:39 ` Allen Pais
2026-07-28 8:38 ` Bartosz Golaszewski
2026-07-27 20:39 ` [PATCH v2 61/64] dmaengine: dw: defer callbacks via channel BH Allen Pais
` (4 subsequent siblings)
64 siblings, 1 reply; 82+ messages in thread
From: Allen Pais @ 2026-07-27 20:39 UTC (permalink / raw)
To: Vinod Koul, Frank Li
Cc: Allen Pais, dmaengine, linux-kernel, Arnd Bergmann, Kees Cook,
Bartosz Golaszewski, Konrad Dybcio, Kuldeep Singh,
Stephan Gerhold, Andy Shevchenko, linux-arm-msm
virt-dma now dispatches completion callbacks through per-channel BH
work instead of its tasklet. Cancel that work during teardown before
channel storage is released.
Signed-off-by: Allen Pais <allen.lkml@gmail.com>
---
drivers/dma/qcom/bam_dma.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/dma/qcom/bam_dma.c b/drivers/dma/qcom/bam_dma.c
index 1bb26af0405f..74bc2fe445b3 100644
--- a/drivers/dma/qcom/bam_dma.c
+++ b/drivers/dma/qcom/bam_dma.c
@@ -1387,7 +1387,7 @@ static int bam_dma_probe(struct platform_device *pdev)
dma_async_device_unregister(&bdev->common);
err_bam_channel_exit:
for (i = 0; i < bdev->num_channels; i++)
- tasklet_kill(&bdev->channels[i].vc.task);
+ dma_chan_kill_bh(&bdev->channels[i].vc.chan);
err_tasklet_kill:
tasklet_kill(&bdev->task);
err_disable_clk:
@@ -1413,7 +1413,7 @@ static void bam_dma_remove(struct platform_device *pdev)
for (i = 0; i < bdev->num_channels; i++) {
bam_dma_terminate_all(&bdev->channels[i].vc.chan);
- tasklet_kill(&bdev->channels[i].vc.task);
+ dma_chan_kill_bh(&bdev->channels[i].vc.chan);
if (!bdev->channels[i].fifo_virt)
continue;
--
2.43.0
^ permalink raw reply related [flat|nested] 82+ messages in thread
* [PATCH v2 61/64] dmaengine: dw: defer callbacks via channel BH
2026-07-27 20:28 ` [PATCH v2 00/64] dmaengine: migrate channel tasklets to WQ_BH Allen Pais
` (59 preceding siblings ...)
2026-07-27 20:39 ` [PATCH v2 60/64] dmaengine: bam-dma: " Allen Pais
@ 2026-07-27 20:39 ` Allen Pais
2026-07-27 20:39 ` [PATCH v2 62/64] dmaengine: hidma: " Allen Pais
` (3 subsequent siblings)
64 siblings, 0 replies; 82+ messages in thread
From: Allen Pais @ 2026-07-27 20:39 UTC (permalink / raw)
To: Vinod Koul, Frank Li
Cc: Allen Pais, dmaengine, linux-kernel, Arnd Bergmann, Kees Cook,
Viresh Kumar, Andy Shevchenko
Queue completed descriptors on the channel and invoke their callbacks
from per-channel BH work instead of the controller tasklet. Add a
synchronize hook so termination can wait for deferred callbacks before
their descriptor storage is released.
Signed-off-by: Allen Pais <allen.lkml@gmail.com>
---
drivers/dma/dw/core.c | 42 ++++++++++++++++++++++++++++++++++--------
drivers/dma/dw/regs.h | 1 +
2 files changed, 35 insertions(+), 8 deletions(-)
diff --git a/drivers/dma/dw/core.c b/drivers/dma/dw/core.c
index dd75f97a33b3..e780116a944b 100644
--- a/drivers/dma/dw/core.c
+++ b/drivers/dma/dw/core.c
@@ -236,25 +236,24 @@ dwc_descriptor_complete(struct dw_dma_chan *dwc, struct dw_desc *desc,
struct dma_async_tx_descriptor *txd = &desc->txd;
struct dw_desc *child;
unsigned long flags;
- struct dmaengine_desc_callback cb;
dev_vdbg(chan2dev(&dwc->chan), "descriptor %u complete\n", txd->cookie);
spin_lock_irqsave(&dwc->lock, flags);
dma_cookie_complete(txd);
- if (callback_required)
- dmaengine_desc_get_callback(txd, &cb);
- else
- memset(&cb, 0, sizeof(cb));
+ list_del_init(&desc->desc_node);
/* async_tx_ack */
list_for_each_entry(child, &desc->tx_list, desc_node)
async_tx_ack(&child->txd);
async_tx_ack(&desc->txd);
- dwc_desc_put(dwc, desc);
+ if (callback_required) {
+ list_add_tail(&desc->desc_node, &dwc->completed_list);
+ dma_chan_schedule_bh(&dwc->chan);
+ } else {
+ dwc_desc_put(dwc, desc);
+ }
spin_unlock_irqrestore(&dwc->lock, flags);
-
- dmaengine_desc_callback_invoke(&cb, NULL);
}
static void dwc_complete_all(struct dw_dma *dw, struct dw_dma_chan *dwc)
@@ -285,6 +284,24 @@ static void dwc_complete_all(struct dw_dma *dw, struct dw_dma_chan *dwc)
dwc_descriptor_complete(dwc, desc, true);
}
+static void dwc_chan_bh(struct dma_chan *chan)
+{
+ struct dw_dma_chan *dwc = to_dw_dma_chan(chan);
+ struct dw_desc *desc, *_desc;
+ struct dmaengine_desc_callback cb;
+ LIST_HEAD(list);
+
+ spin_lock_irq(&dwc->lock);
+ list_splice_init(&dwc->completed_list, &list);
+ spin_unlock_irq(&dwc->lock);
+
+ list_for_each_entry_safe(desc, _desc, &list, desc_node) {
+ dmaengine_desc_get_callback(&desc->txd, &cb);
+ dmaengine_desc_callback_invoke(&cb, NULL);
+ dwc_desc_put(dwc, desc);
+ }
+}
+
/* Returns how many bytes were already received from source */
static inline u32 dwc_get_sent(struct dw_dma_chan *dwc)
{
@@ -965,6 +982,11 @@ static int dwc_terminate_all(struct dma_chan *chan)
return 0;
}
+static void dwc_synchronize(struct dma_chan *chan)
+{
+ dma_chan_kill_bh(chan);
+}
+
static struct dw_desc *dwc_find_desc(struct dw_dma_chan *dwc, dma_cookie_t c)
{
struct dw_desc *desc;
@@ -1256,6 +1278,8 @@ int do_dma_probe(struct dw_dma_chip *chip)
INIT_LIST_HEAD(&dwc->active_list);
INIT_LIST_HEAD(&dwc->queue);
+ INIT_LIST_HEAD(&dwc->completed_list);
+ dma_chan_init_bh(&dwc->chan, dwc_chan_bh);
channel_clear_bit(dw, CH_EN, dwc->mask);
@@ -1321,6 +1345,7 @@ int do_dma_probe(struct dw_dma_chip *chip)
dw->dma.device_pause = dwc_pause;
dw->dma.device_resume = dwc_resume;
dw->dma.device_terminate_all = dwc_terminate_all;
+ dw->dma.device_synchronize = dwc_synchronize;
dw->dma.device_tx_status = dwc_tx_status;
dw->dma.device_issue_pending = dwc_issue_pending;
@@ -1374,6 +1399,7 @@ int do_dma_remove(struct dw_dma_chip *chip)
list_for_each_entry_safe(dwc, _dwc, &dw->dma.channels,
chan.device_node) {
+ dma_chan_kill_bh(&dwc->chan);
list_del(&dwc->chan.device_node);
channel_clear_bit(dw, CH_EN, dwc->mask);
}
diff --git a/drivers/dma/dw/regs.h b/drivers/dma/dw/regs.h
index 5969d9cc8d7a..c9e32bd6110a 100644
--- a/drivers/dma/dw/regs.h
+++ b/drivers/dma/dw/regs.h
@@ -279,6 +279,7 @@ struct dw_dma_chan {
unsigned long flags;
struct list_head active_list;
struct list_head queue;
+ struct list_head completed_list;
unsigned int descs_allocated;
--
2.43.0
^ permalink raw reply related [flat|nested] 82+ messages in thread
* [PATCH v2 62/64] dmaengine: hidma: defer callbacks via channel BH
2026-07-27 20:28 ` [PATCH v2 00/64] dmaengine: migrate channel tasklets to WQ_BH Allen Pais
` (60 preceding siblings ...)
2026-07-27 20:39 ` [PATCH v2 61/64] dmaengine: dw: defer callbacks via channel BH Allen Pais
@ 2026-07-27 20:39 ` Allen Pais
2026-07-27 20:39 ` [PATCH v2 63/64] dmaengine: qcom-gpi: defer callbacks via vchan Allen Pais
` (2 subsequent siblings)
64 siblings, 0 replies; 82+ messages in thread
From: Allen Pais @ 2026-07-27 20:39 UTC (permalink / raw)
To: Vinod Koul, Frank Li
Cc: Allen Pais, dmaengine, linux-kernel, Arnd Bergmann, Kees Cook,
Sinan Kaya, linux-arm-kernel, linux-arm-msm
Move descriptor callback processing out of the low-level completion
path and schedule it through per-channel BH work. Drain that work while
freeing channels so callbacks cannot outlive channel storage.
Signed-off-by: Allen Pais <allen.lkml@gmail.com>
---
drivers/dma/qcom/hidma.c | 18 ++++++++++++++++--
1 file changed, 16 insertions(+), 2 deletions(-)
diff --git a/drivers/dma/qcom/hidma.c b/drivers/dma/qcom/hidma.c
index c939635be21d..1f875a499ab3 100644
--- a/drivers/dma/qcom/hidma.c
+++ b/drivers/dma/qcom/hidma.c
@@ -90,7 +90,13 @@ static inline struct hidma_chan *to_hidma_chan(struct dma_chan *dmach)
static void hidma_free(struct hidma_dev *dmadev)
{
- INIT_LIST_HEAD(&dmadev->ddev.channels);
+ struct hidma_chan *mchan, *next;
+
+ list_for_each_entry_safe(mchan, next, &dmadev->ddev.channels,
+ chan.device_node) {
+ dma_chan_kill_bh(&mchan->chan);
+ list_del(&mchan->chan.device_node);
+ }
}
static unsigned int nr_desc_prm;
@@ -155,6 +161,13 @@ static void hidma_process_completed(struct hidma_chan *mchan)
}
}
+static void hidma_chan_bh(struct dma_chan *chan)
+{
+ struct hidma_chan *mchan = to_hidma_chan(chan);
+
+ hidma_process_completed(mchan);
+}
+
/*
* Called once for each submitted descriptor.
* PM is locked once for each descriptor that is currently
@@ -181,7 +194,7 @@ static void hidma_callback(void *data)
}
spin_unlock_irqrestore(&mchan->lock, irqflags);
- hidma_process_completed(mchan);
+ dma_chan_schedule_bh(&mchan->chan);
if (queued) {
pm_runtime_mark_last_busy(dmadev->ddev.dev);
@@ -203,6 +216,7 @@ static int hidma_chan_init(struct hidma_dev *dmadev, u32 dma_sig)
mchan->dmadev = dmadev;
mchan->chan.device = ddev;
dma_cookie_init(&mchan->chan);
+ dma_chan_init_bh(&mchan->chan, hidma_chan_bh);
INIT_LIST_HEAD(&mchan->free);
INIT_LIST_HEAD(&mchan->prepared);
--
2.43.0
^ permalink raw reply related [flat|nested] 82+ messages in thread
* [PATCH v2 63/64] dmaengine: qcom-gpi: defer callbacks via vchan
2026-07-27 20:28 ` [PATCH v2 00/64] dmaengine: migrate channel tasklets to WQ_BH Allen Pais
` (61 preceding siblings ...)
2026-07-27 20:39 ` [PATCH v2 62/64] dmaengine: hidma: " Allen Pais
@ 2026-07-27 20:39 ` Allen Pais
2026-07-27 20:39 ` [PATCH v2 64/64] dmaengine: switchtec: use channel BH helpers Allen Pais
2026-07-28 20:39 ` [PATCH v2 00/64] dmaengine: migrate channel tasklets to WQ_BH Arnd Bergmann
64 siblings, 0 replies; 82+ messages in thread
From: Allen Pais @ 2026-07-27 20:39 UTC (permalink / raw)
To: Vinod Koul, Frank Li
Cc: Allen Pais, dmaengine, linux-kernel, Arnd Bergmann, Kees Cook,
Dmitry Baryshkov, Miaoqian Lin, Icenowy Zheng,
Jyothi Kumar Seerapu, linux-arm-msm
Complete descriptors through virt-dma instead of invoking callbacks
directly from event processing. This preserves the transfer result for
the shared vchan BH, which invokes the callback and frees the descriptor;
drain that BH before releasing channel resources.
Signed-off-by: Allen Pais <allen.lkml@gmail.com>
---
drivers/dma/qcom/gpi.c | 17 +++++++++++++----
1 file changed, 13 insertions(+), 4 deletions(-)
diff --git a/drivers/dma/qcom/gpi.c b/drivers/dma/qcom/gpi.c
index a5055a6273af..4cf68cf8eb2e 100644
--- a/drivers/dma/qcom/gpi.c
+++ b/drivers/dma/qcom/gpi.c
@@ -981,8 +981,12 @@ static void gpi_process_imed_data_event(struct gchan *gchan,
result.result = DMA_TRANS_NOERROR;
result.residue = gpi_desc->len - imed_event->length;
- dma_cookie_complete(&vd->tx);
- dmaengine_desc_get_callback_invoke(&vd->tx, &result);
+ spin_lock_irqsave(&gchan->vc.lock, flags);
+ list_del(&vd->node);
+ vd->tx_result = result;
+ vchan_cookie_complete(vd);
+ spin_unlock_irqrestore(&gchan->vc.lock, flags);
+ return;
gpi_free_desc:
spin_lock_irqsave(&gchan->vc.lock, flags);
@@ -1060,8 +1064,12 @@ static void gpi_process_xfer_compl_event(struct gchan *gchan,
result.residue = gpi_desc->len - compl_event->length;
dev_dbg(gpii->gpi_dev->dev, "Residue %d\n", result.residue);
- dma_cookie_complete(&vd->tx);
- dmaengine_desc_get_callback_invoke(&vd->tx, &result);
+ spin_lock_irqsave(&gchan->vc.lock, flags);
+ list_del(&vd->node);
+ vd->tx_result = result;
+ vchan_cookie_complete(vd);
+ spin_unlock_irqrestore(&gchan->vc.lock, flags);
+ return;
gpi_free_desc:
spin_lock_irqsave(&gchan->vc.lock, flags);
@@ -2009,6 +2017,7 @@ static void gpi_free_chan_resources(struct dma_chan *chan)
/* free all allocated memory */
gpi_free_ring(&gchan->ch_ring, gpii);
+ dma_chan_kill_bh(&gchan->vc.chan);
vchan_free_chan_resources(&gchan->vc);
kfree(gchan->config);
--
2.43.0
^ permalink raw reply related [flat|nested] 82+ messages in thread
* [PATCH v2 64/64] dmaengine: switchtec: use channel BH helpers
2026-07-27 20:28 ` [PATCH v2 00/64] dmaengine: migrate channel tasklets to WQ_BH Allen Pais
` (62 preceding siblings ...)
2026-07-27 20:39 ` [PATCH v2 63/64] dmaengine: qcom-gpi: defer callbacks via vchan Allen Pais
@ 2026-07-27 20:39 ` Allen Pais
2026-07-27 21:08 ` Logan Gunthorpe
2026-07-28 20:39 ` [PATCH v2 00/64] dmaengine: migrate channel tasklets to WQ_BH Arnd Bergmann
64 siblings, 1 reply; 82+ messages in thread
From: Allen Pais @ 2026-07-27 20:39 UTC (permalink / raw)
To: Vinod Koul, Frank Li
Cc: Allen Pais, dmaengine, linux-kernel, Arnd Bergmann, Kees Cook,
Kelvin Cao, Logan Gunthorpe
Replace the per-channel descriptor completion tasklet with the shared
dma_chan BH helpers. Client callbacks remain in softirq context while
using the common scheduling and teardown mechanism.
Signed-off-by: Allen Pais <allen.lkml@gmail.com>
---
drivers/dma/switchtec_dma.c | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)
diff --git a/drivers/dma/switchtec_dma.c b/drivers/dma/switchtec_dma.c
index 3ef928640615..f3459799e05d 100644
--- a/drivers/dma/switchtec_dma.c
+++ b/drivers/dma/switchtec_dma.c
@@ -133,8 +133,6 @@ struct switchtec_dma_chan {
/* Serialize hardware control register access */
spinlock_t hw_ctrl_lock;
- struct tasklet_struct desc_task;
-
/* Serialize descriptor preparation */
spinlock_t submit_lock;
bool ring_active;
@@ -584,6 +582,7 @@ static void switchtec_dma_synchronize(struct dma_chan *chan)
int rc;
+ dma_chan_kill_bh(chan);
switchtec_dma_abort_desc(swdma_chan, 1);
rc = enable_channel(swdma_chan);
@@ -820,9 +819,10 @@ static int switchtec_dma_resume(struct dma_chan *chan)
return ret;
}
-static void switchtec_dma_desc_task(unsigned long data)
+static void switchtec_dma_desc_task(struct dma_chan *chan)
{
- struct switchtec_dma_chan *swdma_chan = (void *)data;
+ struct switchtec_dma_chan *swdma_chan =
+ container_of(chan, struct switchtec_dma_chan, dma_chan);
switchtec_dma_cleanup_completed(swdma_chan);
}
@@ -832,7 +832,7 @@ static irqreturn_t switchtec_dma_isr(int irq, void *chan)
struct switchtec_dma_chan *swdma_chan = chan;
if (swdma_chan->comp_ring_active)
- tasklet_schedule(&swdma_chan->desc_task);
+ dma_chan_schedule_bh(&swdma_chan->dma_chan);
return IRQ_HANDLED;
}
@@ -1041,6 +1041,7 @@ static void switchtec_dma_free_chan_resources(struct dma_chan *chan)
spin_unlock_bh(&swdma_chan->complete_lock);
switchtec_dma_chan_stop(swdma_chan);
+ dma_chan_kill_bh(chan);
switchtec_dma_abort_desc(swdma_chan, 0);
switchtec_dma_free_desc(swdma_chan);
@@ -1067,8 +1068,6 @@ static int switchtec_dma_chan_init(struct switchtec_dma_dev *swdma_dev,
spin_lock_init(&swdma_chan->hw_ctrl_lock);
spin_lock_init(&swdma_chan->submit_lock);
spin_lock_init(&swdma_chan->complete_lock);
- tasklet_init(&swdma_chan->desc_task, switchtec_dma_desc_task,
- (unsigned long)swdma_chan);
swdma_chan->mmio_chan_fw =
swdma_dev->bar + SWITCHTEC_DMAC_CHAN_CFG_STS_OFFSET +
@@ -1116,6 +1115,7 @@ static int switchtec_dma_chan_init(struct switchtec_dma_dev *swdma_dev,
chan = &swdma_chan->dma_chan;
chan->device = dma;
dma_cookie_init(chan);
+ dma_chan_init_bh(chan, switchtec_dma_desc_task);
list_add_tail(&chan->device_node, &dma->channels);
@@ -1138,7 +1138,7 @@ static int switchtec_dma_chan_free(struct pci_dev *pdev,
spin_unlock_bh(&swdma_chan->complete_lock);
pci_free_irq(pdev, swdma_chan->irq, swdma_chan);
- tasklet_kill(&swdma_chan->desc_task);
+ dma_chan_kill_bh(&swdma_chan->dma_chan);
switchtec_dma_chan_stop(swdma_chan);
--
2.43.0
^ permalink raw reply related [flat|nested] 82+ messages in thread
* Re: [PATCH v2 64/64] dmaengine: switchtec: use channel BH helpers
2026-07-27 20:39 ` [PATCH v2 64/64] dmaengine: switchtec: use channel BH helpers Allen Pais
@ 2026-07-27 21:08 ` Logan Gunthorpe
0 siblings, 0 replies; 82+ messages in thread
From: Logan Gunthorpe @ 2026-07-27 21:08 UTC (permalink / raw)
To: Allen Pais, Vinod Koul, Frank Li
Cc: dmaengine, linux-kernel, Arnd Bergmann, Kees Cook, Kelvin Cao
On 2026-07-27 14:39, Allen Pais wrote:
> Replace the per-channel descriptor completion tasklet with the shared
> dma_chan BH helpers. Client callbacks remain in softirq context while
> using the common scheduling and teardown mechanism.
>
> Signed-off-by: Allen Pais <allen.lkml@gmail.com>
This one also looks good to me, thanks.
Reviewed-by: Logan Gunthorpe <logang@deltatee.com>
^ permalink raw reply [flat|nested] 82+ messages in thread
* Re: [PATCH v2 60/64] dmaengine: bam-dma: use dma_chan_kill_bh
2026-07-27 20:39 ` [PATCH v2 60/64] dmaengine: bam-dma: " Allen Pais
@ 2026-07-28 8:38 ` Bartosz Golaszewski
0 siblings, 0 replies; 82+ messages in thread
From: Bartosz Golaszewski @ 2026-07-28 8:38 UTC (permalink / raw)
To: Allen Pais
Cc: dmaengine, linux-kernel, Arnd Bergmann, Kees Cook,
Bartosz Golaszewski, Konrad Dybcio, Kuldeep Singh,
Stephan Gerhold, Andy Shevchenko, linux-arm-msm, Vinod Koul,
Frank Li
On Mon, 27 Jul 2026 22:39:22 +0200, Allen Pais <allen.lkml@gmail.com> said:
> virt-dma now dispatches completion callbacks through per-channel BH
> work instead of its tasklet. Cancel that work during teardown before
> channel storage is released.
>
> Signed-off-by: Allen Pais <allen.lkml@gmail.com>
> ---
> drivers/dma/qcom/bam_dma.c | 4 ++--
> 1 file changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/dma/qcom/bam_dma.c b/drivers/dma/qcom/bam_dma.c
> index 1bb26af0405f..74bc2fe445b3 100644
> --- a/drivers/dma/qcom/bam_dma.c
> +++ b/drivers/dma/qcom/bam_dma.c
> @@ -1387,7 +1387,7 @@ static int bam_dma_probe(struct platform_device *pdev)
> dma_async_device_unregister(&bdev->common);
> err_bam_channel_exit:
> for (i = 0; i < bdev->num_channels; i++)
> - tasklet_kill(&bdev->channels[i].vc.task);
> + dma_chan_kill_bh(&bdev->channels[i].vc.chan);
> err_tasklet_kill:
> tasklet_kill(&bdev->task);
> err_disable_clk:
> @@ -1413,7 +1413,7 @@ static void bam_dma_remove(struct platform_device *pdev)
>
> for (i = 0; i < bdev->num_channels; i++) {
> bam_dma_terminate_all(&bdev->channels[i].vc.chan);
> - tasklet_kill(&bdev->channels[i].vc.task);
> + dma_chan_kill_bh(&bdev->channels[i].vc.chan);
>
> if (!bdev->channels[i].fifo_virt)
> continue;
> --
> 2.43.0
>
>
Acked-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
^ permalink raw reply [flat|nested] 82+ messages in thread
* Re: [PATCH v2 41/64] dmaengine: hsu: kill vchan BH on teardown
2026-07-27 20:39 ` [PATCH v2 41/64] dmaengine: hsu: " Allen Pais
@ 2026-07-28 8:47 ` Andy Shevchenko
0 siblings, 0 replies; 82+ messages in thread
From: Andy Shevchenko @ 2026-07-28 8:47 UTC (permalink / raw)
To: Allen Pais
Cc: Vinod Koul, Frank Li, dmaengine, linux-kernel, Arnd Bergmann,
Kees Cook, Andy Shevchenko
On Mon, Jul 27, 2026 at 11:40 PM Allen Pais <allen.lkml@gmail.com> wrote:
>
> Use dma_chan_kill_bh() for virt-dma cleanup.
Reviewed-by: Andy Shevchenko <andy@kernel.org>
P.S. No need to Bcc, Cc is good enough and allows me to see the replies.
--
With Best Regards,
Andy Shevchenko
^ permalink raw reply [flat|nested] 82+ messages in thread
* Re: [PATCH v2 17/64] dmaengine: ste_dma40: convert per-channel tasklet to dma_chan BH
2026-07-27 20:28 ` [PATCH v2 17/64] dmaengine: ste_dma40: convert per-channel tasklet to " Allen Pais
@ 2026-07-28 19:33 ` Linus Walleij
0 siblings, 0 replies; 82+ messages in thread
From: Linus Walleij @ 2026-07-28 19:33 UTC (permalink / raw)
To: Allen Pais
Cc: Vinod Koul, Frank Li, dmaengine, linux-kernel, Arnd Bergmann,
Kees Cook, linux-arm-kernel
On Mon, Jul 27, 2026 at 10:32 PM Allen Pais <allen.lkml@gmail.com> wrote:
> Replace the per-channel tasklet with the shared dma_chan BH helper.
> The handler continues to run in softirq context while dmaengine owns
> the common scheduling and teardown mechanism.
>
> Signed-off-by: Allen Pais <allen.lkml@gmail.com>
I like it.
Reviewed-by: Linus Walleij <linusw@kernel.org>
Yours,
Linus Walleij
^ permalink raw reply [flat|nested] 82+ messages in thread
* Re: [PATCH v2 00/64] dmaengine: migrate channel tasklets to WQ_BH
2026-07-27 20:28 ` [PATCH v2 00/64] dmaengine: migrate channel tasklets to WQ_BH Allen Pais
` (63 preceding siblings ...)
2026-07-27 20:39 ` [PATCH v2 64/64] dmaengine: switchtec: use channel BH helpers Allen Pais
@ 2026-07-28 20:39 ` Arnd Bergmann
64 siblings, 0 replies; 82+ messages in thread
From: Arnd Bergmann @ 2026-07-28 20:39 UTC (permalink / raw)
To: Allen, Vinod Koul, Frank Li; +Cc: dmaengine, linux-kernel, Kees Cook
On Mon, Jul 27, 2026, at 22:28, Allen Pais wrote:
> Hi Arnd, Vinod and Frank,
>
> This series moves DMAengine client completion bottom halves from private
> tasklets to a common per-channel API backed by WQ_BH.
>
> The first patch introduces the dma_chan_*_bh() API with a tasklet backend
> and converts virt-dma to it. This separates the driver-facing API from its
> implementation without changing callback context.
>
> The second patch switches that backend to a dedicated WQ_BH | WQ_PERCPU
> workqueue. WQ_BH keeps callbacks in softirq context, while the common API
> centralizes initialization, scheduling, and synchronization. The
> workqueue helpers remain internal to DMAengine, and dma_chan_kill_bh()
> drains scheduled callbacks to preserve tasklet_kill() semantics.
>
> The remaining patches convert driver-owned channel completion tasklets
> and update virt-dma teardown paths. Tasklets used for controller-level
> processing, recovery, or other non-client-callback work are deliberately
> left alone because the appropriate replacement may differ by driver.
>
> As agreed in the RFC discussion, selecting hardirq callback delivery is a
> separate API change and is not part of this series.
Hi Allen,
I looked through the series, and this seems all fine to me,
nice work!
Arnd
^ permalink raw reply [flat|nested] 82+ messages in thread
* Re: [PATCH v2 01/64] dmaengine: add tasklet-backed channel BH helpers
2026-07-27 20:28 ` [PATCH v2 01/64] dmaengine: add tasklet-backed channel BH helpers Allen Pais
@ 2026-07-29 12:48 ` Vinod Koul
0 siblings, 0 replies; 82+ messages in thread
From: Vinod Koul @ 2026-07-29 12:48 UTC (permalink / raw)
To: Allen Pais; +Cc: Frank Li, dmaengine, linux-kernel, Arnd Bergmann, Kees Cook
On 27-07-26, 13:28, Allen Pais wrote:
> void dma_release_channel(struct dma_chan *chan);
> int dma_get_slave_caps(struct dma_chan *chan, struct dma_slave_caps *caps);
> +void dma_chan_init_bh(struct dma_chan *chan, dma_chan_bh_work_fn fn);
> +bool dma_chan_schedule_bh(struct dma_chan *chan);
> +void dma_chan_kill_bh(struct dma_chan *chan);
Can you please name these as dmaengine_xxx. Yes we have mix of these
two, but I would like to see new ones move to dmaengine_xx and then
progressively drop dma_ everywhere
--
~Vinod
^ permalink raw reply [flat|nested] 82+ messages in thread
end of thread, other threads:[~2026-07-29 12:48 UTC | newest]
Thread overview: 82+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-01-08 8:03 [RFC PATCH 0/1] dmaengine: introduce dmaengine_bh_wq and bh helpers Allen Pais
2026-01-08 8:03 ` [RFC PATCH 1/1] " Allen Pais
2026-01-08 10:26 ` Arnd Bergmann
2026-01-08 19:22 ` Allen
2026-01-09 16:42 ` Arnd Bergmann
2026-01-12 22:20 ` Allen
2026-01-13 7:33 ` Arnd Bergmann
2026-01-13 19:31 ` Allen
2026-07-27 20:28 ` [PATCH v2 00/64] dmaengine: migrate channel tasklets to WQ_BH Allen Pais
2026-07-27 20:28 ` [PATCH v2 01/64] dmaengine: add tasklet-backed channel BH helpers Allen Pais
2026-07-29 12:48 ` Vinod Koul
2026-07-27 20:28 ` [PATCH v2 02/64] dmaengine: back channel BH helpers with WQ_BH Allen Pais
2026-07-27 20:28 ` [PATCH v2 03/64] dmaengine: apple-admac: use dma_chan BH callback Allen Pais
2026-07-27 20:28 ` [PATCH v2 04/64] dmaengine: at_xdmac: move irq bottom half to dma_chan BH Allen Pais
2026-07-27 20:28 ` [PATCH v2 05/64] dmaengine: ep93xx: hook callbacks via " Allen Pais
2026-07-27 20:28 ` [PATCH v2 06/64] dmaengine: fsldma: migrate tasklet to " Allen Pais
2026-07-27 20:28 ` [PATCH v2 07/64] dmaengine: fsl_raid: run completions via " Allen Pais
2026-07-27 20:28 ` [PATCH v2 08/64] dmaengine: imx-dma: flip per-chan tasklet to " Allen Pais
2026-07-27 20:28 ` [PATCH v2 09/64] dmaengine: ioat: convert cleanup " Allen Pais
2026-07-27 20:38 ` Dave Jiang
2026-07-27 20:28 ` [PATCH v2 10/64] dmaengine: mmp_pdma: replace per-chan tasklet with " Allen Pais
2026-07-27 20:28 ` [PATCH v2 11/64] dmaengine: mmp_tdma: hook completions to " Allen Pais
2026-07-27 20:28 ` [PATCH v2 12/64] dmaengine: mv_xor: convert irq tasklet " Allen Pais
2026-07-27 20:28 ` [PATCH v2 13/64] dmaengine: mxs-dma: use dma_chan BH scheduling Allen Pais
2026-07-27 20:28 ` [PATCH v2 14/64] dmaengine: nbpfaxi: switch callbacks to dma_chan BH Allen Pais
2026-07-27 20:28 ` [PATCH v2 15/64] dmaengine: pch_dma: convert tasklet " Allen Pais
2026-07-27 20:28 ` [PATCH v2 16/64] dmaengine: ppc4xx: replace irq tasklet with " Allen Pais
2026-07-27 20:28 ` [PATCH v2 17/64] dmaengine: ste_dma40: convert per-channel tasklet to " Allen Pais
2026-07-28 19:33 ` Linus Walleij
2026-07-27 20:28 ` [PATCH v2 18/64] dmaengine: xgene-dma: wire descriptor cleanup " Allen Pais
2026-07-27 20:28 ` [PATCH v2 19/64] dmaengine: xilinx-dma: use dma_chan BH instead of tasklets Allen Pais
2026-07-27 20:28 ` [PATCH v2 20/64] dmaengine: xilinx-dpdma: kill vchan BH on remove Allen Pais
2026-07-27 20:28 ` [PATCH v2 21/64] dmaengine: zynqmp-dma: switch completion tasklet to dma_chan BH Allen Pais
2026-07-27 20:28 ` [PATCH v2 22/64] dmaengine: tegra20-apb: use channel BH helpers Allen Pais
2026-07-27 20:28 ` [PATCH v2 23/64] dmaengine: timb_dma: route callbacks via channel BH Allen Pais
2026-07-27 20:28 ` [PATCH v2 24/64] dmaengine: txx9dmac: " Allen Pais
2026-07-27 20:28 ` [PATCH v2 25/64] dmaengine: mv_xor_v2: use channel BH helpers Allen Pais
2026-07-27 20:28 ` [PATCH v2 26/64] dmaengine: mpc512x: route callbacks via channel BH Allen Pais
2026-07-27 20:28 ` [PATCH v2 27/64] dmaengine: k3dma: kill vchan BH on remove Allen Pais
2026-07-27 20:28 ` [PATCH v2 28/64] dmaengine: plx_dma: use channel BH helpers Allen Pais
2026-07-27 20:38 ` Logan Gunthorpe
2026-07-27 20:28 ` [PATCH v2 29/64] dmaengine: sf-pdma: route error callbacks through channel BH Allen Pais
2026-07-27 20:28 ` [PATCH v2 30/64] dmaengine: sa11x0-dma: kill vchan BH on remove Allen Pais
2026-07-27 20:28 ` [PATCH v2 31/64] dmaengine: pl330: route callbacks via channel BH Allen Pais
2026-07-27 20:34 ` Allen Pais
2026-07-27 20:34 ` [PATCH v2 32/64] dmaengine: k3-udma: use channel BH for vchan completions Allen Pais
2026-07-27 20:36 ` [PATCH v2 33/64] dmaengine: sun6i: kill vchan BH on teardown Allen Pais
2026-07-27 20:37 ` [PATCH v2 34/64] dmaengine: mtk-cqdma: " Allen Pais
2026-07-27 20:38 ` [PATCH v2 35/64] dmaengine: altera-msgdma: use channel BH helpers Allen Pais
2026-07-27 20:38 ` [PATCH v2 36/64] dmaengine: sprd-dma: kill vchan BH on teardown Allen Pais
2026-07-27 20:38 ` [PATCH v2 37/64] dmaengine: idma64: " Allen Pais
2026-07-27 20:39 ` [PATCH v2 38/64] dmaengine: img-mdc-dma: " Allen Pais
2026-07-27 20:39 ` [PATCH v2 39/64] dmaengine: fsl-edma-common: " Allen Pais
2026-07-27 20:39 ` [PATCH v2 40/64] dmaengine: dw-axi-dmac: " Allen Pais
2026-07-27 20:39 ` [PATCH v2 41/64] dmaengine: hsu: " Allen Pais
2026-07-28 8:47 ` Andy Shevchenko
2026-07-27 20:39 ` [PATCH v2 42/64] dmaengine: jz4780: " Allen Pais
2026-07-27 20:39 ` [PATCH v2 43/64] dmaengine: pxa_dma: " Allen Pais
2026-07-27 20:39 ` [PATCH v2 44/64] dmaengine: mtk-hsdma: " Allen Pais
2026-07-27 20:39 ` [PATCH v2 45/64] dmaengine: mtk-uart-apdma: " Allen Pais
2026-07-27 20:39 ` [PATCH v2 46/64] dmaengine: imx-sdma: " Allen Pais
2026-07-27 20:39 ` [PATCH v2 47/64] dmaengine: loongson1-apb: " Allen Pais
2026-07-27 20:39 ` [PATCH v2 48/64] dmaengine: owl-dma: " Allen Pais
2026-07-27 20:39 ` [PATCH v2 49/64] dmaengine: hisi: " Allen Pais
2026-07-27 20:39 ` [PATCH v2 50/64] dmaengine: dw-edma: " Allen Pais
2026-07-27 20:39 ` [PATCH v2 51/64] dmaengine: bcm2835: " Allen Pais
2026-07-27 20:39 ` [PATCH v2 52/64] dmaengine: tegra210-adma: " Allen Pais
2026-07-27 20:39 ` [PATCH v2 53/64] dmaengine: fsl-qdma: use dma_chan_kill_bh Allen Pais
2026-07-27 20:39 ` [PATCH v2 54/64] dmaengine: st_fdma: " Allen Pais
2026-07-27 20:39 ` [PATCH v2 55/64] dmaengine: dma-axi-dmac: " Allen Pais
2026-07-27 20:39 ` [PATCH v2 56/64] dmaengine: omap-dma: " Allen Pais
2026-07-27 20:39 ` [PATCH v2 57/64] dmaengine: edma: " Allen Pais
2026-07-27 20:39 ` [PATCH v2 58/64] dmaengine: qcom-adm: " Allen Pais
2026-07-27 20:39 ` [PATCH v2 59/64] dmaengine: tegra186-gpc: " Allen Pais
2026-07-27 20:39 ` [PATCH v2 60/64] dmaengine: bam-dma: " Allen Pais
2026-07-28 8:38 ` Bartosz Golaszewski
2026-07-27 20:39 ` [PATCH v2 61/64] dmaengine: dw: defer callbacks via channel BH Allen Pais
2026-07-27 20:39 ` [PATCH v2 62/64] dmaengine: hidma: " Allen Pais
2026-07-27 20:39 ` [PATCH v2 63/64] dmaengine: qcom-gpi: defer callbacks via vchan Allen Pais
2026-07-27 20:39 ` [PATCH v2 64/64] dmaengine: switchtec: use channel BH helpers Allen Pais
2026-07-27 21:08 ` Logan Gunthorpe
2026-07-28 20:39 ` [PATCH v2 00/64] dmaengine: migrate channel tasklets to WQ_BH Arnd Bergmann
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox