lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20260128-dma_ll_comlib-v1-1-1b1fa2c671f9@nxp.com>
Date: Wed, 28 Jan 2026 13:05:20 -0500
From: Frank Li <Frank.Li@....com>
To: Vinod Koul <vkoul@...nel.org>
Cc: linux-kernel@...r.kernel.org, dmaengine@...r.kernel.org, 
 imx@...ts.linux.dev, joy.zou@....com, Frank Li <Frank.Li@....com>
Subject: [PATCH RFC 01/12] dmaengine: Extend virt_chan for link list based
 DMA engines

Many DMA engines (such as fsl-edma, at-hdmac, and ste-dma40) use
linked-list descriptors for data transfers and share a large amount of
common logic. Add a basic framework to support these link list based DMA
engines and prepare for a common library.

Introduce vchan_dma_ll_terminate_all() as the first shared helper.
Additional common functionality will be added in follow-up patches.

Signed-off-by: Frank Li <Frank.Li@....com>
---
 drivers/dma/Kconfig           |  4 +++
 drivers/dma/Makefile          |  1 +
 drivers/dma/fsl-edma-common.c | 35 ++++++++++++++++++-------
 drivers/dma/ll-dma.c          | 61 +++++++++++++++++++++++++++++++++++++++++++
 drivers/dma/virt-dma.h        | 19 ++++++++++++++
 5 files changed, 111 insertions(+), 9 deletions(-)

diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
index 8bb0a119ecd48a6695404d43fce225987c9c69ff..5a61907d4d9631e61cf0c44d4104983e9113f28f 100644
--- a/drivers/dma/Kconfig
+++ b/drivers/dma/Kconfig
@@ -47,6 +47,9 @@ config DMA_ENGINE
 config DMA_VIRTUAL_CHANNELS
 	tristate
 
+config DMA_LINKLIST
+	tristate
+
 config DMA_ACPI
 	def_bool y
 	depends on ACPI
@@ -221,6 +224,7 @@ config FSL_EDMA
 	depends on HAS_IOMEM
 	select DMA_ENGINE
 	select DMA_VIRTUAL_CHANNELS
+	select DMA_LINKLIST
 	help
 	  Support the Freescale eDMA engine with programmable channel
 	  multiplexing capability for DMA request sources(slot).
diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile
index a54d7688392b1a0e956fa5d23633507f52f017d9..f1db081a8d2487968f0ca110b80706901f9903ae 100644
--- a/drivers/dma/Makefile
+++ b/drivers/dma/Makefile
@@ -6,6 +6,7 @@ subdir-ccflags-$(CONFIG_DMADEVICES_VDEBUG) += -DVERBOSE_DEBUG
 #core
 obj-$(CONFIG_DMA_ENGINE) += dmaengine.o
 obj-$(CONFIG_DMA_VIRTUAL_CHANNELS) += virt-dma.o
+obj-$(CONFIG_DMA_LINKLIST) += ll-dma.o
 obj-$(CONFIG_DMA_ACPI) += acpi-dma.o
 obj-$(CONFIG_DMA_OF) += of-dma.o
 
diff --git a/drivers/dma/fsl-edma-common.c b/drivers/dma/fsl-edma-common.c
index c4ac63d9612ce9f1f5826a2186938a785ed529d1..396ff6dfa99a150f9ce34effd64534e3d8e8576b 100644
--- a/drivers/dma/fsl-edma-common.c
+++ b/drivers/dma/fsl-edma-common.c
@@ -236,16 +236,11 @@ void fsl_edma_free_desc(struct virt_dma_desc *vdesc)
 int fsl_edma_terminate_all(struct dma_chan *chan)
 {
 	struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan);
-	unsigned long flags;
-	LIST_HEAD(head);
+	int ret;
 
-	spin_lock_irqsave(&fsl_chan->vchan.lock, flags);
-	fsl_edma_disable_request(fsl_chan);
-	fsl_chan->edesc = NULL;
-	fsl_chan->status = DMA_COMPLETE;
-	vchan_get_all_descriptors(&fsl_chan->vchan, &head);
-	spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags);
-	vchan_dma_desc_free_list(&fsl_chan->vchan, &head);
+	ret = vchan_dma_ll_terminate_all(chan);
+	if (ret)
+		return ret;
 
 	if (fsl_edma_drvflags(fsl_chan) & FSL_EDMA_DRV_HAS_PD)
 		pm_runtime_allow(fsl_chan->pd_dev);
@@ -830,6 +825,21 @@ void fsl_edma_issue_pending(struct dma_chan *chan)
 	spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags);
 }
 
+static int fsl_edma_ll_stop(struct dma_chan *chan)
+{
+	struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan);
+
+	fsl_edma_disable_request(fsl_chan);
+	fsl_chan->edesc = NULL;
+	fsl_chan->status = DMA_COMPLETE;
+
+	return 0;
+}
+
+static const struct dma_linklist_ops fsl_edma_ll_ops = {
+	.stop = fsl_edma_ll_stop,
+};
+
 int fsl_edma_alloc_chan_resources(struct dma_chan *chan)
 {
 	struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan);
@@ -838,6 +848,13 @@ int fsl_edma_alloc_chan_resources(struct dma_chan *chan)
 	if (fsl_edma_drvflags(fsl_chan) & FSL_EDMA_DRV_HAS_CHCLK)
 		clk_prepare_enable(fsl_chan->clk);
 
+	ret = vchan_dma_ll_init(to_virt_chan(chan), &fsl_edma_ll_ops,
+				fsl_edma_drvflags(fsl_chan) & FSL_EDMA_DRV_TCD64 ?
+				sizeof(struct fsl_edma_hw_tcd64) : sizeof(struct fsl_edma_hw_tcd),
+				32, 0);
+	if (ret)
+		return ret;
+
 	fsl_chan->tcd_pool = dma_pool_create("tcd_pool", chan->device->dev,
 				fsl_edma_drvflags(fsl_chan) & FSL_EDMA_DRV_TCD64 ?
 				sizeof(struct fsl_edma_hw_tcd64) : sizeof(struct fsl_edma_hw_tcd),
diff --git a/drivers/dma/ll-dma.c b/drivers/dma/ll-dma.c
new file mode 100644
index 0000000000000000000000000000000000000000..3845cca7926eb71f008cb98d8c622cb28a2369a5
--- /dev/null
+++ b/drivers/dma/ll-dma.c
@@ -0,0 +1,61 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Common library for DMA Controller, which use Link List DMA descriptor.
+ *
+ * For the DMA controller, which DMA descriptor work as Link List, there are
+ * field, which point to next DMA descriptor.
+ *
+ * Each DMA descriptor's size is the same.
+ *
+ *	┌──────┐    ┌──────┐    ┌──────┐
+ *	│      │ ┌─►│      │ ┌─►│      │
+ *	│      │ │  │      │ │  │      │
+ *	├──────┤ │  ├──────┤ │  ├──────┤
+ *	│ Next ├─┘  │ Next ├─┘  │ Next │
+ *	└──────┘    └──────┘    └──────┘
+ *
+ */
+#include <linux/cleanup.h>
+#include <linux/device.h>
+#include <linux/dmaengine.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+
+#include "virt-dma.h"
+
+int vchan_dma_ll_init(struct virt_dma_chan *vc,
+		      const struct dma_linklist_ops *ops, size_t size,
+		      size_t align, size_t boundary)
+{
+	if (!ops || !ops->stop)
+		return -EINVAL;
+
+	vc->ll.ops = ops;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(vchan_dma_ll_init);
+
+int vchan_dma_ll_terminate_all(struct dma_chan *chan)
+{
+	struct virt_dma_chan *vchan = to_virt_chan(chan);
+	LIST_HEAD(head);
+	int ret;
+
+	scoped_guard(spinlock_irqsave, &vchan->lock) {
+		ret = vchan->ll.ops->stop(chan);
+		if (ret)
+			return ret;
+
+		vchan_get_all_descriptors(vchan, &head);
+	}
+
+	vchan_dma_desc_free_list(vchan, &head);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(vchan_dma_ll_terminate_all);
+
+MODULE_AUTHOR("Frank Li");
+MODULE_DESCRIPTION("Common library for Link List DMA Descriptor");
+MODULE_LICENSE("GPL");
diff --git a/drivers/dma/virt-dma.h b/drivers/dma/virt-dma.h
index 59d9eabc8b6744a439aeed3114164c5203341a6c..081eb910d0b0cd2b60232736587c698fff787cb9 100644
--- a/drivers/dma/virt-dma.h
+++ b/drivers/dma/virt-dma.h
@@ -19,11 +19,23 @@ struct virt_dma_desc {
 	struct list_head node;
 };
 
+struct dma_linklist_ops {
+	int (*stop)(struct dma_chan *chan);
+};
+
+struct dma_linklist {
+	const struct dma_linklist_ops *ops;
+};
+
 struct virt_dma_chan {
 	struct dma_chan	chan;
 	struct tasklet_struct task;
 	void (*desc_free)(struct virt_dma_desc *);
 
+#if IS_ENABLED(CONFIG_DMA_LINKLIST)
+	struct dma_linklist ll;
+#endif
+
 	spinlock_t lock;
 
 	/* protected by vc.lock */
@@ -234,4 +246,11 @@ static inline void vchan_synchronize(struct virt_dma_chan *vc)
 	vchan_dma_desc_free_list(vc, &head);
 }
 
+#if IS_ENABLED(CONFIG_DMA_LINKLIST)
+int vchan_dma_ll_init(struct virt_dma_chan *vc,
+		      const struct dma_linklist_ops *ops, size_t size,
+		      size_t align, size_t boundary);
+int vchan_dma_ll_terminate_all(struct dma_chan *chan);
+#endif
+
 #endif

-- 
2.34.1


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ