mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Nathan Lynch via B4 Relay <devnull+nathan.lynch.amd.com@kernel.org>
To: Vinod Koul <vkoul@kernel.org>, Frank Li <Frank.Li@kernel.org>
Cc: Bjorn Helgaas <bhelgaas@google.com>,
	 David Rientjes <rientjes@google.com>,
	John.Kariuki@amd.com,  Jonathan Cameron <jic23@kernel.org>,
	Kinsey Ho <kinseyho@google.com>,
	 Mario Limonciello <mario.limonciello@amd.com>,
	 PradeepVineshReddy.Kodamati@amd.com,
	Shivank Garg <shivankg@amd.com>,
	 Stephen Bates <Stephen.Bates@amd.com>,
	Tycho Andersen <tycho@kernel.org>,
	 Wei Huang <wei.huang2@amd.com>, Wei Xu <weixugc@google.com>,
	 dmaengine@vger.kernel.org, linux-kernel@vger.kernel.org,
	 linux-pci@vger.kernel.org, Nathan Lynch <nathan.lynch@amd.com>
Subject: [PATCH v4 25/25] dmaengine: sdxi: Add DMA engine provider
Date: Tue, 03 Nov 2026 20:50:06 -0600	[thread overview]
Message-ID: <20261103-sdxi-base-v4-25-3668ccc7aab8@amd.com> (raw)
In-Reply-To: <20261103-sdxi-base-v4-0-3668ccc7aab8@amd.com>

From: Nathan Lynch <nathan.lynch@amd.com>

Register a virt-dma memcpy provider with a configurable number of channels
per function. Publish transactions in cookie order, batching copies behind
fenced completion interrupts. Keep transactions pending when ring slots or
completion blocks are unavailable.

Published descriptors cannot be withdrawn. Termination frees submitted and
pending transactions and retains published transactions for reaping without
completing cookies or invoking callbacks.

Synchronize by polling and reaping transactions under the channel lock,
then flushing virt-dma callbacks. The wait is uninterruptible and bounded
to ten seconds. On timeout, suppress remaining callbacks and retain unreaped
status blocks until context teardown; this timeout path does not establish
hardware quiescence for client buffers.

Co-developed-by: Wei Huang <wei.huang2@amd.com>
Signed-off-by: Wei Huang <wei.huang2@amd.com>
Signed-off-by: Nathan Lynch <nathan.lynch@amd.com>
---
 drivers/dma/sdxi/Kconfig  |   1 +
 drivers/dma/sdxi/Makefile |   1 +
 drivers/dma/sdxi/device.c |   2 +
 drivers/dma/sdxi/dma.c    | 509 ++++++++++++++++++++++++++++++++++++++++++++++
 drivers/dma/sdxi/dma.h    |  11 +
 5 files changed, 524 insertions(+)

diff --git a/drivers/dma/sdxi/Kconfig b/drivers/dma/sdxi/Kconfig
index 314b3e725ccb..85e23608405c 100644
--- a/drivers/dma/sdxi/Kconfig
+++ b/drivers/dma/sdxi/Kconfig
@@ -4,6 +4,7 @@ config SDXI_CORE
 	# SDXI 1.0 9 MMIO Control Registers.
 	depends on 64BIT
 	select DMA_ENGINE
+	select DMA_VIRTUAL_CHANNELS
 	help
 	  Enable support for Smart Data Accelerator Interface (SDXI)
 	  Platform Data Mover devices. SDXI is a vendor-neutral
diff --git a/drivers/dma/sdxi/Makefile b/drivers/dma/sdxi/Makefile
index 1e261fb03225..3a1d36997b44 100644
--- a/drivers/dma/sdxi/Makefile
+++ b/drivers/dma/sdxi/Makefile
@@ -5,6 +5,7 @@ sdxi-core-y := \
 	context.o     \
 	descriptor.o  \
 	device.o      \
+	dma.o         \
 	ring.o
 
 obj-$(CONFIG_SDXI_PCI) += sdxi-pci.o
diff --git a/drivers/dma/sdxi/device.c b/drivers/dma/sdxi/device.c
index 30c4e687cedf..265ebea1e350 100644
--- a/drivers/dma/sdxi/device.c
+++ b/drivers/dma/sdxi/device.c
@@ -23,6 +23,7 @@
 #include <linux/xarray.h>
 
 #include "context.h"
+#include "dma.h"
 #include "hw.h"
 #include "mmio.h"
 #include "sdxi.h"
@@ -424,6 +425,7 @@ static int sdxi_device_init(struct sdxi_dev *sdxi)
 	if (err)
 		return err;
 
+	sdxi_dma_register(sdxi);
 	return 0;
 }
 
diff --git a/drivers/dma/sdxi/dma.c b/drivers/dma/sdxi/dma.c
new file mode 100644
index 000000000000..512855c83da2
--- /dev/null
+++ b/drivers/dma/sdxi/dma.c
@@ -0,0 +1,509 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * SDXI dmaengine provider
+ *
+ * Copyright Advanced Micro Devices, Inc.
+ */
+
+#include <linux/cleanup.h>
+#include <linux/delay.h>
+#include <linux/dev_printk.h>
+#include <linux/container_of.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmaengine.h>
+#include <linux/iopoll.h>
+#include <linux/list.h>
+#include <linux/lockdep.h>
+#include <linux/module.h>
+#include <linux/overflow.h>
+#include <linux/spinlock.h>
+
+#include "../dmaengine.h"
+#include "../virt-dma.h"
+#include "completion.h"
+#include "context.h"
+#include "descriptor.h"
+#include "dma.h"
+#include "ring.h"
+#include "sdxi.h"
+
+static unsigned short dma_channels = 1;
+module_param(dma_channels, ushort, 0644);
+MODULE_PARM_DESC(dma_channels, "DMA channels per function (default: 1)");
+
+/*
+ * Each channel owns an SDXI context. Transactions enter the ring in cookie
+ * order. Each transaction produces one copy descriptor with its own completion
+ * block, and batches end with a shared fenced interrupt descriptor. Each copy
+ * owns its completion block until reaped. Transactions awaiting capacity remain
+ * pending. Termination retains published transactions for reaping while
+ * suppressing their callbacks.
+ */
+
+struct sdxi_dma_chan {
+	struct virt_dma_chan vchan;
+	struct sdxi_cxt *cxt;
+	unsigned int vector;
+	unsigned int irq;
+	struct sdxi_akey_ent *akey;
+	/*
+	 * Transactions awaiting ring slots or completion blocks; protected by
+	 * vchan.lock.
+	 */
+	struct list_head pending;
+};
+
+struct sdxi_dma_txd {
+	struct virt_dma_desc vdesc;
+	struct sdxi_copy copy;	/* Copy operation parameters */
+	/* Completion ownership is acquired at issue and released after reaping. */
+	struct sdxi_completion completion;
+};
+
+static void sdxi_dma_reap_locked(struct sdxi_dma_chan *sdchan);
+
+struct sdxi_dma_dev {
+	struct dma_device dma_dev;
+	size_t nr_channels;
+	struct sdxi_dma_chan sdchan[] __counted_by(nr_channels);
+};
+
+static struct sdxi_dma_chan *to_sdxi_dma_chan(const struct dma_chan *dma_chan)
+{
+	const struct virt_dma_chan *vchan;
+
+	vchan = container_of_const(dma_chan, struct virt_dma_chan, chan);
+	return container_of(vchan, struct sdxi_dma_chan, vchan);
+}
+
+static struct sdxi_dma_txd *
+to_sdxi_dma_txd(const struct virt_dma_desc *vdesc)
+{
+	return container_of(vdesc, struct sdxi_dma_txd, vdesc);
+}
+
+static void sdxi_dma_txd_free(struct virt_dma_desc *vdesc)
+{
+	struct sdxi_dma_txd *txd = to_sdxi_dma_txd(vdesc);
+
+	kfree(txd);
+}
+
+static struct dma_async_tx_descriptor *
+sdxi_dma_prep_memcpy(struct dma_chan *dma_chan, dma_addr_t dst,
+		     dma_addr_t src, size_t len, unsigned long flags)
+{
+	struct sdxi_dma_chan *sdchan = to_sdxi_dma_chan(dma_chan);
+	struct sdxi_cxt *cxt = sdchan->cxt;
+	u16 akey_index = sdxi_akey_index(cxt, sdchan->akey);
+	struct sdxi_dma_txd *txd;
+	struct sdxi_copy copy = {
+		.src = src,
+		.dst = dst,
+		.src_akey = akey_index,
+		.dst_akey = akey_index,
+		.len = len,
+	};
+
+	/*
+	 * Validate now, with a throwaway encode onto the stack. The real
+	 * encode into the ring happens at issue.
+	 */
+	if (sdxi_encode_copy(&(struct sdxi_desc){}, &copy))
+		return NULL;
+
+	txd = kmalloc_obj(*txd, GFP_NOWAIT);
+	if (!txd)
+		return NULL;
+
+	*txd = (typeof(*txd)) {
+		.copy = copy,
+	};
+
+	return vchan_tx_prep(&sdchan->vchan, &txd->vdesc, flags);
+}
+
+static enum dma_status sdxi_tx_status(struct dma_chan *chan,
+				      dma_cookie_t cookie,
+				      struct dma_tx_state *state)
+{
+	struct sdxi_dma_chan *sdchan = to_sdxi_dma_chan(chan);
+	struct virt_dma_desc *vdesc;
+
+	/* Under the lock for a consistent cookie snapshot; the IRQ reaps. */
+	guard(spinlock_irqsave)(&sdchan->vchan.lock);
+
+	/* vchan_find_desc() only returns issued txds, which own a completion. */
+	vdesc = vchan_find_desc(&sdchan->vchan, cookie);
+	if (vdesc) {
+		struct sdxi_dma_txd *txd = to_sdxi_dma_txd(vdesc);
+
+		if (sdxi_cst_blk_check(txd->completion.cst_blk) == SDXI_COMPLETION_ERROR)
+			return DMA_ERROR;
+	}
+
+	return dma_cookie_status(chan, cookie, state);
+}
+
+/*
+ * Fill capacity with complete, fenced batches in cookie order. Return true
+ * if descriptors were published; the caller kicks once with the lock held.
+ */
+static bool sdxi_dma_drain_locked(struct sdxi_dma_chan *sdchan)
+{
+	struct sdxi_cxt *cxt = sdchan->cxt;
+	struct sdxi_ring_state *rs = cxt->ring_state;
+	bool pushed = false;
+
+	lockdep_assert_held(&sdchan->vchan.lock);
+
+	while (!list_empty(&sdchan->pending)) {
+		struct virt_dma_desc *vdesc;
+		struct sdxi_ring_resv resv;
+		struct sdxi_desc *desc;
+		size_t claimed = 0, copies, i = 0;
+
+		/* Claim a pending prefix, stopping at a flag boundary or capacity limit. */
+		list_for_each_entry(vdesc, &sdchan->pending, node) {
+			struct sdxi_dma_txd *txd = to_sdxi_dma_txd(vdesc);
+
+			if (!sdxi_cst_pool_get(cxt->cst_pool, &txd->completion))
+				break;
+			claimed++;
+			if (vdesc->tx.flags & (DMA_PREP_INTERRUPT | DMA_PREP_FENCE) ||
+			    claimed == rs->sq->count - 1)
+				break;
+		}
+		if (!claimed)
+			break;
+
+		/* Ring reservations cannot be undone; acquire completions first. */
+		copies = 0;
+		if (!sdxi_ring_try_reserve_range(rs, 2, claimed + 1, &resv))
+			copies = sdxi_ring_resv_count(&resv) - 1;
+
+		/* Return claims not covered by this (possibly failed) reservation. */
+		list_for_each_entry(vdesc, &sdchan->pending, node) {
+			struct sdxi_dma_txd *txd = to_sdxi_dma_txd(vdesc);
+
+			if (i == claimed)
+				break;
+			if (i++ < copies)
+				continue;
+			sdxi_cst_pool_put(cxt->cst_pool, txd->completion.cst_blk);
+			txd->completion = (struct sdxi_completion) {};
+		}
+		if (!copies)
+			break;
+		for (size_t i = 0; i < copies; i++) {
+			struct sdxi_dma_txd *txd;
+			struct sdxi_slot slot = sdxi_ring_resv_slot(&resv, i);
+
+			vdesc = list_first_entry(&sdchan->pending,
+						struct virt_dma_desc, node);
+			txd = to_sdxi_dma_txd(vdesc);
+			desc = sdxi_slot_desc(slot);
+			(void)sdxi_encode_copy(desc, &txd->copy); /* validated at prep */
+			sdxi_cxt_attach_cst(slot, &txd->completion);
+			sdxi_desc_make_valid(desc);
+			list_move_tail(&vdesc->node, &sdchan->vchan.desc_issued);
+		}
+
+		/*
+		 * FE waits for all copies before notifying and before parsing
+		 * subsequent copies (SDXI 1.0a 5.3, steps 7-9). One terminator
+		 * satisfies both flags and supplies internal completion IRQs.
+		 */
+		desc = sdxi_slot_desc(sdxi_ring_resv_slot(&resv, copies));
+		sdxi_encode_intr(desc, &(const struct sdxi_intr) {
+			.akey = sdxi_akey_index(cxt, sdchan->akey),
+		});
+		sdxi_desc_set_fence(desc);
+		sdxi_desc_make_valid(desc);
+		pushed = true;
+	}
+
+	return pushed;
+}
+
+static void sdxi_dma_issue_pending(struct dma_chan *dma_chan)
+{
+	struct sdxi_dma_chan *sdchan = to_sdxi_dma_chan(dma_chan);
+
+	guard(spinlock_irqsave)(&sdchan->vchan.lock);
+
+	list_splice_tail_init(&sdchan->vchan.desc_submitted, &sdchan->pending);
+	if (sdxi_dma_drain_locked(sdchan))
+		sdxi_cxt_kick(sdchan->cxt);
+}
+
+static int sdxi_dma_terminate_all(struct dma_chan *dma_chan)
+{
+	struct sdxi_dma_chan *sdchan = to_sdxi_dma_chan(dma_chan);
+	struct virt_dma_chan *vchan = &sdchan->vchan;
+	LIST_HEAD(head);
+
+	/*
+	 * Prepared descriptors remain caller-owned. Free submitted and pending
+	 * transactions, and move published transactions to desc_terminated in ring
+	 * order for callback-free reaping.
+	 */
+	scoped_guard(spinlock_irqsave, &vchan->lock) {
+		list_splice_tail_init(&sdchan->pending, &head);
+		list_splice_tail_init(&vchan->desc_submitted, &head);
+		list_splice_tail_init(&vchan->desc_issued, &vchan->desc_terminated);
+	}
+	vchan_dma_desc_free_list(vchan, &head);
+
+	return 0;
+}
+
+/* Bound the wait for issued and pending copies to complete. */
+#define SDXI_DMA_SYNC_TIMEOUT_US	(10 * USEC_PER_SEC)
+
+/*
+ * Reap without relying on the completion IRQ, and report whether the
+ * device is done with every txd that has been or may be placed in the
+ * ring. Pending txds count because dma_chan_put() synchronizes without
+ * terminating first.
+ */
+static bool sdxi_dma_idle(struct sdxi_dma_chan *sdchan)
+{
+	struct virt_dma_chan *vchan = &sdchan->vchan;
+
+	guard(spinlock_irqsave)(&vchan->lock);
+
+	sdxi_dma_reap_locked(sdchan);
+	if (sdxi_dma_drain_locked(sdchan))
+		sdxi_cxt_kick(sdchan->cxt);
+
+	return list_empty(&vchan->desc_terminated) &&
+	       list_empty(&vchan->desc_issued) &&
+	       list_empty(&sdchan->pending);
+}
+
+static void sdxi_dma_synchronize(struct dma_chan *dma_chan)
+{
+	struct sdxi_dma_chan *sdchan = to_sdxi_dma_chan(dma_chan);
+	struct virt_dma_chan *vchan = &sdchan->vchan;
+	LIST_HEAD(head);
+	bool idle;
+	int err;
+
+	/*
+	 * Callers cannot handle failure, so the wait is not interruptible.
+	 * Every completion was reaped under vchan.lock, so the tasklet that
+	 * runs its callback is already scheduled for vchan_synchronize().
+	 */
+	err = read_poll_timeout(sdxi_dma_idle, idle, idle, 100,
+				SDXI_DMA_SYNC_TIMEOUT_US, false, sdchan);
+	if (err) {
+		/*
+		 * Suppress callbacks for outstanding transactions. Completion blocks
+		 * not released by the reaper stay claimed until context teardown.
+		 */
+		scoped_guard(spinlock_irqsave, &vchan->lock) {
+			list_splice_tail_init(&vchan->desc_issued,
+					      &vchan->desc_terminated);
+			list_splice_tail_init(&sdchan->pending, &head);
+		}
+		vchan_dma_desc_free_list(vchan, &head);
+		dev_err(dma_chan->device->dev,
+			"timed out waiting for DMA channel %d to drain\n",
+			dma_chan->chan_id);
+	}
+
+	vchan_synchronize(vchan);
+}
+
+static void sdxi_dma_reap_locked(struct sdxi_dma_chan *sdchan)
+{
+	struct virt_dma_chan *vchan = &sdchan->vchan;
+	struct virt_dma_desc *vdesc, *tmp;
+
+	lockdep_assert_held(&vchan->lock);
+
+	/*
+	 * Terminated txds are still in the ring. Release them once the device
+	 * is done, without completing their cookies or invoking callbacks.
+	 */
+	list_for_each_entry_safe(vdesc, tmp, &vchan->desc_terminated, node) {
+		struct sdxi_dma_txd *txd = to_sdxi_dma_txd(vdesc);
+
+		if (sdxi_cst_blk_check(txd->completion.cst_blk) == SDXI_COMPLETION_PENDING)
+			break;
+
+		list_del(&vdesc->node);
+		sdxi_cst_pool_put(sdchan->cxt->cst_pool, txd->completion.cst_blk);
+		sdxi_dma_txd_free(vdesc);
+	}
+
+	/* Reap completed transactions in cookie order. */
+	while ((vdesc = vchan_next_desc(vchan))) {
+		struct sdxi_dma_txd *txd = to_sdxi_dma_txd(vdesc);
+		enum sdxi_completion_state state;
+
+		state = sdxi_cst_blk_check(txd->completion.cst_blk);
+		if (state == SDXI_COMPLETION_PENDING)
+			break;
+
+		if (state == SDXI_COMPLETION_ERROR)
+			txd->vdesc.tx_result.result = DMA_TRANS_ABORTED;
+
+		list_del(&vdesc->node);
+		sdxi_cst_pool_put(sdchan->cxt->cst_pool, txd->completion.cst_blk);
+		txd->completion = (struct sdxi_completion) {};
+		vchan_cookie_complete(&txd->vdesc);
+	}
+
+	sdxi_ring_wake_up(sdchan->cxt->ring_state);
+}
+
+static irqreturn_t sdxi_dma_cxt_irq(int irq, void *data)
+{
+	struct sdxi_dma_chan *sdchan = data;
+
+	guard(spinlock_irqsave)(&sdchan->vchan.lock);
+
+	sdxi_dma_reap_locked(sdchan);
+	/* Consumed completion blocks may let stalled pending txds proceed. */
+	if (sdxi_dma_drain_locked(sdchan))
+		sdxi_cxt_kick(sdchan->cxt);
+
+	return IRQ_HANDLED;
+}
+
+static int sdxi_dma_alloc_chan_resources(struct dma_chan *dma_chan)
+{
+	struct sdxi_dev *sdxi = dev_get_drvdata(dma_chan->device->dev);
+	struct sdxi_dma_chan *sdchan = to_sdxi_dma_chan(dma_chan);
+	int vector, irq, err;
+
+	sdchan->cxt = sdxi_cxt_new(sdxi);
+	if (!sdchan->cxt)
+		return -ENOMEM;
+	err = vector = sdxi_alloc_vector(sdxi);
+	if (vector < 0)
+		goto exit_cxt;
+
+	sdchan->vector = vector;
+
+	err = irq = sdxi_vector_to_irq(sdxi, vector);
+	if (irq < 0)
+		goto free_vector;
+
+	sdchan->irq = irq;
+
+	/*
+	 * Note this akey entry is used for both the completion
+	 * interrupt and source and destination access for copies.
+	 */
+	sdchan->akey = sdxi_alloc_akey(sdchan->cxt);
+	if (!sdchan->akey) {
+		err = -ENOMEM;
+		goto free_vector;
+	}
+
+	*sdchan->akey = (typeof(*sdchan->akey)) {
+		.intr_num = cpu_to_le16(FIELD_PREP(SDXI_AKEY_ENT_VL, 1) |
+					FIELD_PREP(SDXI_AKEY_ENT_IV, 1) |
+					FIELD_PREP(SDXI_AKEY_ENT_INTR_NUM,
+						   vector)),
+	};
+
+	err = request_irq(sdchan->irq, sdxi_dma_cxt_irq,
+			  IRQF_TRIGGER_NONE, "SDXI DMAengine", sdchan);
+	if (err)
+		goto free_akey;
+
+	err = sdxi_start_cxt(sdchan->cxt);
+	if (err)
+		goto free_irq;
+
+	return 0;
+free_irq:
+	free_irq(sdchan->irq, sdchan);
+free_akey:
+	sdxi_free_akey(sdchan->cxt, sdchan->akey);
+free_vector:
+	sdxi_free_vector(sdxi, vector);
+exit_cxt:
+	sdxi_cxt_exit(sdchan->cxt);
+	return err;
+}
+
+static void sdxi_dma_free_chan_resources(struct dma_chan *dma_chan)
+{
+	struct sdxi_dma_chan *sdchan = to_sdxi_dma_chan(dma_chan);
+	LIST_HEAD(head);
+
+	sdxi_stop_cxt(sdchan->cxt);
+	free_irq(sdchan->irq, sdchan);
+	sdxi_free_vector(sdchan->cxt->sdxi, sdchan->vector);
+	sdxi_free_akey(sdchan->cxt, sdchan->akey);
+	/* virt-dma does not know about the driver's pending list. */
+	scoped_guard(spinlock_irqsave, &sdchan->vchan.lock)
+		list_splice_tail_init(&sdchan->pending, &head);
+	vchan_dma_desc_free_list(&sdchan->vchan, &head);
+	vchan_free_chan_resources(to_virt_chan(dma_chan));
+	sdxi_cxt_exit(sdchan->cxt);
+}
+
+int sdxi_dma_register(struct sdxi_dev *sdxi)
+{
+	struct device *dev = sdxi->dev;
+	struct sdxi_dma_dev *sddev;
+	struct dma_device *dma_dev;
+	unsigned int nr_channels = dma_channels; /* writable module param; snapshot it */
+	int err;
+
+	if (!nr_channels)
+		return 0;
+	/*
+	 * TODO: Require IntrGrp support before registering the DMAengine provider
+	 * (SDXI 1.0a Table 6-1).
+	 */
+
+	sddev = devm_kzalloc(dev, struct_size(sddev, sdchan, nr_channels),
+			     GFP_KERNEL);
+	if (!sddev)
+		return -ENOMEM;
+
+	sddev->nr_channels = nr_channels;
+
+	dma_dev = &sddev->dma_dev;
+	*dma_dev = (typeof(*dma_dev)) {
+		.dev                 = dev,
+		.src_addr_widths     = DMA_SLAVE_BUSWIDTH_64_BYTES,
+		.dst_addr_widths     = DMA_SLAVE_BUSWIDTH_64_BYTES,
+		.directions          = BIT(DMA_MEM_TO_MEM),
+		.residue_granularity = DMA_RESIDUE_GRANULARITY_DESCRIPTOR,
+
+		.device_alloc_chan_resources = sdxi_dma_alloc_chan_resources,
+		.device_free_chan_resources  = sdxi_dma_free_chan_resources,
+
+		.device_prep_dma_memcpy = sdxi_dma_prep_memcpy,
+
+		.device_terminate_all = sdxi_dma_terminate_all,
+		.device_synchronize = sdxi_dma_synchronize,
+		.device_tx_status = sdxi_tx_status,
+		.device_issue_pending = sdxi_dma_issue_pending,
+	};
+
+	dma_cap_set(DMA_MEMCPY, dma_dev->cap_mask);
+	INIT_LIST_HEAD(&dma_dev->channels);
+
+	for (size_t i = 0; i < sddev->nr_channels; ++i) {
+		struct sdxi_dma_chan *sdchan = &sddev->sdchan[i];
+
+		sdchan->vchan.desc_free = sdxi_dma_txd_free;
+		vchan_init(&sdchan->vchan, &sddev->dma_dev);
+		INIT_LIST_HEAD(&sdchan->pending);
+	}
+
+	err = dmaenginem_async_device_register(dma_dev);
+	if (err)
+		return dev_warn_probe(dev, err, "failed to register dma device\n");
+
+	return 0;
+}
diff --git a/drivers/dma/sdxi/dma.h b/drivers/dma/sdxi/dma.h
new file mode 100644
index 000000000000..d38870ea7d91
--- /dev/null
+++ b/drivers/dma/sdxi/dma.h
@@ -0,0 +1,11 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/* Copyright Advanced Micro Devices, Inc. */
+
+#ifndef DMA_SDXI_DMA_H
+#define DMA_SDXI_DMA_H
+
+struct sdxi_dev;
+
+int sdxi_dma_register(struct sdxi_dev *sdxi);
+
+#endif /* DMA_SDXI_DMA_H */

-- 
2.56.0



      parent reply	other threads:[~2026-11-04  2:50 UTC|newest]

Thread overview: 26+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-11-04  2:49 [PATCH v4 00/25] dmaengine: Smart Data Accelerator Interface (SDXI) basic support Nathan Lynch via B4 Relay
2026-11-04  2:49 ` [PATCH v4 01/25] PCI: Add SNIA SDXI accelerator sub-class Nathan Lynch via B4 Relay
2026-11-04  2:49 ` [PATCH v4 02/25] MAINTAINERS: Add entry for SDXI driver Nathan Lynch via B4 Relay
2026-11-04  2:49 ` [PATCH v4 03/25] dmaengine: sdxi: Add PCI initialization Nathan Lynch via B4 Relay
2026-11-04  2:49 ` [PATCH v4 04/25] dmaengine: sdxi: Prepare function and sanitize MMIO state Nathan Lynch via B4 Relay
2026-11-04  2:49 ` [PATCH v4 05/25] dmaengine: sdxi: Feature discovery and initial configuration Nathan Lynch via B4 Relay
2026-11-04  2:49 ` [PATCH v4 06/25] dmaengine: sdxi: Configure context tables Nathan Lynch via B4 Relay
2026-11-04  2:49 ` [PATCH v4 07/25] dmaengine: sdxi: Allocate context control DMA pool Nathan Lynch via B4 Relay
2026-11-04  2:49 ` [PATCH v4 08/25] dmaengine: sdxi: Introduce submission queue Nathan Lynch via B4 Relay
2026-11-04  2:49 ` [PATCH v4 09/25] dmaengine: sdxi: Allocate administrative context Nathan Lynch via B4 Relay
2026-11-04  2:49 ` [PATCH v4 10/25] dmaengine: sdxi: Install " Nathan Lynch via B4 Relay
2026-11-04  2:49 ` [PATCH v4 11/25] dmaengine: sdxi: Start functions on probe, stop on remove Nathan Lynch via B4 Relay
2026-11-04  2:49 ` [PATCH v4 12/25] dmaengine: sdxi: Add client context allocation API Nathan Lynch via B4 Relay
2026-11-04  2:49 ` [PATCH v4 13/25] dmaengine: sdxi: Add descriptor ring management Nathan Lynch via B4 Relay
2026-11-04  2:49 ` [PATCH v4 14/25] dmaengine: sdxi: Add unit tests for descriptor ring reservations Nathan Lynch via B4 Relay
2026-11-04  2:49 ` [PATCH v4 15/25] dmaengine: sdxi: Per-context access key (AKey) table entry allocator Nathan Lynch via B4 Relay
2026-11-04  2:49 ` [PATCH v4 16/25] dmaengine: sdxi: Add completion status block API Nathan Lynch via B4 Relay
2026-11-04  2:49 ` [PATCH v4 17/25] dmaengine: sdxi: Add unit tests for completion pool ownership Nathan Lynch via B4 Relay
2026-11-04  2:49 ` [PATCH v4 18/25] dmaengine: sdxi: Add context submission helper Nathan Lynch via B4 Relay
2026-11-04  2:50 ` [PATCH v4 19/25] dmaengine: sdxi: Encode context start, stop, update, and sync descriptors Nathan Lynch via B4 Relay
2026-11-04  2:50 ` [PATCH v4 20/25] dmaengine: sdxi: Add client context release with update and sync Nathan Lynch via B4 Relay
2026-11-04  2:50 ` [PATCH v4 21/25] dmaengine: sdxi: Provide context start and stop APIs Nathan Lynch via B4 Relay
2026-11-04  2:50 ` [PATCH v4 22/25] dmaengine: sdxi: Encode copy and interrupt descriptors Nathan Lynch via B4 Relay
2026-11-04  2:50 ` [PATCH v4 23/25] dmaengine: sdxi: Add unit tests for descriptor encoding Nathan Lynch via B4 Relay
2026-11-04  2:50 ` [PATCH v4 24/25] dmaengine: sdxi: MSI/MSI-X vector allocation and mapping Nathan Lynch via B4 Relay
2026-11-04  2:50 ` Nathan Lynch via B4 Relay [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20261103-sdxi-base-v4-25-3668ccc7aab8@amd.com \
    --to=devnull+nathan.lynch.amd.com@kernel.org \
    --cc=Frank.Li@kernel.org \
    --cc=John.Kariuki@amd.com \
    --cc=PradeepVineshReddy.Kodamati@amd.com \
    --cc=Stephen.Bates@amd.com \
    --cc=bhelgaas@google.com \
    --cc=dmaengine@vger.kernel.org \
    --cc=jic23@kernel.org \
    --cc=kinseyho@google.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-pci@vger.kernel.org \
    --cc=mario.limonciello@amd.com \
    --cc=nathan.lynch@amd.com \
    --cc=rientjes@google.com \
    --cc=shivankg@amd.com \
    --cc=tycho@kernel.org \
    --cc=vkoul@kernel.org \
    --cc=wei.huang2@amd.com \
    --cc=weixugc@google.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®