mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Frank Li <Frank.li@oss.nxp.com>
To: Nathan Lynch <nathan.lynch@amd.com>
Cc: Vinod Koul <vkoul@kernel.org>, Frank Li <Frank.Li@kernel.org>,
	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
Subject: Re: [PATCH v4 25/25] dmaengine: sdxi: Add DMA engine provider
Date: Fri, 13 Nov 2026 12:50:06 -0500	[thread overview]
Message-ID: <avdNzgMDdDrcioVf@lizhi-Precision-Tower-5810> (raw)
In-Reply-To: <20261103-sdxi-base-v4-25-3668ccc7aab8@amd.com>

On Tue, Nov 03, 2026 at 08:50:06PM -0600, Nathan Lynch wrote:
> 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);

why not use vchan's desc_issued?

Frank

> +	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
>

      reply	other threads:[~2026-11-13 17:50 UTC|newest]

Thread overview: 56+ 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-05 18:10   ` Frank Li
2026-11-05 18:25     ` Lynch, Nathan
2026-11-12 21:28   ` Bjorn Helgaas
2026-11-04  2:49 ` [PATCH v4 02/25] MAINTAINERS: Add entry for SDXI driver Nathan Lynch via B4 Relay
2026-11-12 21:19   ` Frank Li
2026-11-04  2:49 ` [PATCH v4 03/25] dmaengine: sdxi: Add PCI initialization Nathan Lynch via B4 Relay
2026-11-05 17:59   ` Frank Li
2026-11-05 18:07     ` Lynch, Nathan
2026-11-04  2:49 ` [PATCH v4 04/25] dmaengine: sdxi: Prepare function and sanitize MMIO state Nathan Lynch via B4 Relay
2026-11-12 21:26   ` Frank Li
2026-11-04  2:49 ` [PATCH v4 05/25] dmaengine: sdxi: Feature discovery and initial configuration Nathan Lynch via B4 Relay
2026-11-12 21:32   ` Frank Li
2026-11-04  2:49 ` [PATCH v4 06/25] dmaengine: sdxi: Configure context tables Nathan Lynch via B4 Relay
2026-11-12 21:49   ` Frank Li
2026-11-04  2:49 ` [PATCH v4 07/25] dmaengine: sdxi: Allocate context control DMA pool Nathan Lynch via B4 Relay
2026-11-12 21:50   ` Frank Li
2026-11-04  2:49 ` [PATCH v4 08/25] dmaengine: sdxi: Introduce submission queue Nathan Lynch via B4 Relay
2026-11-12 21:58   ` Frank Li
2026-11-04  2:49 ` [PATCH v4 09/25] dmaengine: sdxi: Allocate administrative context Nathan Lynch via B4 Relay
2026-11-12 22:10   ` Frank Li
2026-11-04  2:49 ` [PATCH v4 10/25] dmaengine: sdxi: Install " Nathan Lynch via B4 Relay
2026-11-12 22:17   ` Frank Li
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-13 16:44   ` Frank Li
2026-11-04  2:49 ` [PATCH v4 12/25] dmaengine: sdxi: Add client context allocation API Nathan Lynch via B4 Relay
2026-11-13 16:46   ` Frank Li
2026-11-04  2:49 ` [PATCH v4 13/25] dmaengine: sdxi: Add descriptor ring management Nathan Lynch via B4 Relay
2026-11-13 16:51   ` Frank Li
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-13 16:53   ` Frank Li
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-13 16:55   ` Frank Li
2026-11-04  2:49 ` [PATCH v4 16/25] dmaengine: sdxi: Add completion status block API Nathan Lynch via B4 Relay
2026-11-13 17:04   ` Frank Li
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-13 17:07   ` Frank Li
2026-11-04  2:49 ` [PATCH v4 18/25] dmaengine: sdxi: Add context submission helper Nathan Lynch via B4 Relay
2026-11-13 17:12   ` Frank Li
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-05 16:52   ` Tycho Andersen
2026-11-13 17:17   ` Frank Li
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-13 17:23   ` Frank Li
2026-11-04  2:50 ` [PATCH v4 21/25] dmaengine: sdxi: Provide context start and stop APIs Nathan Lynch via B4 Relay
2026-11-13 17:24   ` Frank Li
2026-11-04  2:50 ` [PATCH v4 22/25] dmaengine: sdxi: Encode copy and interrupt descriptors Nathan Lynch via B4 Relay
2026-11-05 17:00   ` Tycho Andersen
2026-11-13 17:28   ` Frank Li
2026-11-04  2:50 ` [PATCH v4 23/25] dmaengine: sdxi: Add unit tests for descriptor encoding Nathan Lynch via B4 Relay
2026-11-13 17:29   ` Frank Li
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-13 17:36   ` Frank Li
2026-11-04  2:50 ` [PATCH v4 25/25] dmaengine: sdxi: Add DMA engine provider Nathan Lynch via B4 Relay
2026-11-13 17:50   ` Frank Li [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=avdNzgMDdDrcioVf@lizhi-Precision-Tower-5810 \
    --to=frank.li@oss.nxp.com \
    --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®