From: Daniel Byrne <daniel1.byrne@intel.com>
To: Vinod Koul <vkoul@kernel.org>, Dave Jiang <dave.jiang@intel.com>
Cc: Fenghua Yu <fenghua.yu@intel.com>, Frank Li <Frank.Li@kernel.org>,
Vinicius Costa Gomes <vinicius.gomes@intel.com>,
Jonathan Corbet <corbet@lwn.net>,
Ludovic Desroches <ludovic.desroches@microchip.com>,
dmaengine@vger.kernel.org, linux-doc@vger.kernel.org,
linux-arm-kernel@lists.infradead.org,
linux-kernel@vger.kernel.org
Subject: [PATCH 1/3] dmaengine: add dmaengine_async_is_tx_complete() for channel status queries
Date: Mon, 19 Oct 2026 08:06:30 -0700 [thread overview]
Message-ID: <20261019150632.4026424-2-daniel1.byrne@intel.com> (raw)
In-Reply-To: <20261019150632.4026424-1-daniel1.byrne@intel.com>
Add dmaengine_async_is_tx_complete() as the client API for polling the
completion of one transaction. Like dma_async_is_tx_complete(), which
it deprecates, it routes the query to the channel's device_tx_status()
callback; the change is that it drops the @last and @used outputs,
which only make sense for providers that complete in cookie order.
A provider that tracks per-descriptor state can answer exactly from
that state, and a high-rate in-kernel polling user, the io_uring DSA
copy offload to be posted separately, depends on such answers.
The kernel-doc says how far such an answer goes. It is exact for a
transaction submitted without DMA_PREP_INTERRUPT, on the first query
that reports it finished. An interrupt-armed transaction reports its
result through callback_result, and a cookie whose descriptor has been
retired reads DMA_COMPLETE. The client guide's advice to pause or stop
the channel before a query points at that text.
dma_async_is_complete() was only used through dma_cookie_status(), so
delete it from the client header and open-code the cookie-window
comparison there. Move dma_set_tx_state(), which only providers call,
from the client header into drivers/dma/dmaengine.h; every in-tree
user already includes it. Convert dma_sync_wait() and dmatest to the
new helper, fix the two comments that still name the deleted helper,
and document the cookie assignment helpers in the provider guide.
Assisted-by: Claude:claude-opus-5-5
Assisted-by: Claude:claude-fable-5-1
Signed-off-by: Daniel Byrne <daniel1.byrne@intel.com>
---
Documentation/driver-api/dmaengine/client.rst | 24 ++++-----
.../driver-api/dmaengine/provider.rst | 45 ++++++++++++++--
drivers/dma/amba-pl08x.c | 2 +-
drivers/dma/at_hdmac.c | 5 +-
drivers/dma/dmaengine.c | 2 +-
drivers/dma/dmaengine.h | 21 +++++++-
drivers/dma/dmatest.c | 3 +-
include/linux/dmaengine.h | 54 +++++++++----------
8 files changed, 103 insertions(+), 53 deletions(-)
diff --git a/Documentation/driver-api/dmaengine/client.rst b/Documentation/driver-api/dmaengine/client.rst
index 5ee5d4a3596d..255aaad33339 100644
--- a/Documentation/driver-api/dmaengine/client.rst
+++ b/Documentation/driver-api/dmaengine/client.rst
@@ -277,8 +277,8 @@ The details of these operations are:
dma_cookie_t dmaengine_submit(struct dma_async_tx_descriptor *desc)
- This returns a cookie can be used to check the progress of DMA engine
- activity via other DMA engine calls not covered in this document.
+ This returns a cookie that can be used to check the progress of a transaction
+ via dmaengine_async_is_tx_complete().
dmaengine_submit() will not start the DMA operation, it merely adds
it to the pending queue. For this, see step 5, dma_async_issue_pending.
@@ -357,23 +357,23 @@ Further APIs
.. code-block:: c
- enum dma_status dma_async_is_tx_complete(struct dma_chan *chan,
- dma_cookie_t cookie, dma_cookie_t *last, dma_cookie_t *used)
+ enum dma_status dmaengine_async_is_tx_complete(struct dma_chan *chan,
+ dma_cookie_t cookie)
- This can be used to check the status of the channel. Please see
- the documentation in include/linux/dmaengine.h for a more complete
- description of this API.
-
- This can be used in conjunction with dma_async_is_complete() and
- the cookie returned from dmaengine_submit() to check for
- completion of a specific DMA transaction.
+ This can be used with the cookie returned from dmaengine_submit()
+ to check for completion of a specific DMA transaction.
.. note::
Not all DMA engine drivers can return reliable information for
a running DMA channel. It is recommended that DMA engine users
pause or stop (via dmaengine_terminate_all()) the channel before
- using this API.
+ using this API, unless the provider tracks per-descriptor state.
+ Even such a provider answers exactly only within the limits that
+ the kernel-doc of dmaengine_async_is_tx_complete() in
+ include/linux/dmaengine.h describes: for a transaction submitted
+ without DMA_PREP_INTERRUPT, and on the first query that reports it
+ finished.
5. Synchronize termination API
diff --git a/Documentation/driver-api/dmaengine/provider.rst b/Documentation/driver-api/dmaengine/provider.rst
index f4ed98f701c9..ef342886af96 100644
--- a/Documentation/driver-api/dmaengine/provider.rst
+++ b/Documentation/driver-api/dmaengine/provider.rst
@@ -419,7 +419,9 @@ supported.
- tx_submit: A pointer to a function you have to implement,
that is supposed to push the current transaction descriptor to a
- pending queue, waiting for issue_pending to be called.
+ pending queue, waiting for issue_pending to be called. Each
+ descriptor is given a cookie to identify it. See the section
+ "Cookie Management" below.
- phys: Physical address of the descriptor which is used later by
the dma engine to read the descriptor and initiate transfer.
@@ -533,6 +535,41 @@ supported.
- May sleep.
+Cookie Management
+------------------
+
+When a transaction is queued for submission via tx_submit(), the provider
+must assign that transaction a cookie (dma_cookie_t) to uniquely identify it.
+The provider is allowed to perform this assignment however it wants, but for
+convenience the following utility functions are available to create
+monotonically increasing cookies:
+
+ .. code-block:: c
+
+ void dma_cookie_init(struct dma_chan *chan);
+
+ Called once at channel creation.
+
+ .. code-block:: c
+
+ dma_cookie_t dma_cookie_assign(struct dma_async_tx_descriptor *tx);
+
+ Assign a cookie to the given descriptor.
+
+ .. code-block:: c
+
+ void dma_cookie_complete(struct dma_async_tx_descriptor *tx);
+
+ Mark the descriptor as complete and invalidate the cookie.
+
+ .. code-block:: c
+
+ enum dma_status dma_cookie_status(struct dma_chan *chan,
+ dma_cookie_t cookie, struct dma_tx_state *state);
+
+ Report the status of the cookie, filling in the state structure if
+ it is not NULL.
+
Misc notes
==========
@@ -550,10 +587,10 @@ where to put them)
dma_cookie_t
-- it's a DMA transaction ID that will increment over time.
+- it's a DMA transaction ID.
-- Not really relevant any more since the introduction of ``virt-dma``
- that abstracts it away.
+- The value can be chosen by the provider, or use the helper APIs
+ such as dma_cookie_assign() and dma_cookie_complete().
dma_vec
diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c
index 5e88fd44812d..8c235a603bb0 100644
--- a/drivers/dma/amba-pl08x.c
+++ b/drivers/dma/amba-pl08x.c
@@ -1536,7 +1536,7 @@ static void pl08x_free_chan_resources(struct dma_chan *chan)
}
/*
- * Code accessing dma_async_is_complete() in a tight loop may give problems.
+ * Code polling the transaction status in a tight loop may give problems.
* If slaves are relying on interrupts to signal completion this function
* must not be called with interrupts disabled.
*/
diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c
index e5b30a57c477..7ea0822a3900 100644
--- a/drivers/dma/at_hdmac.c
+++ b/drivers/dma/at_hdmac.c
@@ -1666,9 +1666,8 @@ static int atc_terminate_all(struct dma_chan *chan)
* @cookie: transaction identifier to check status of
* @txstate: if not %NULL updated with transaction state
*
- * If @txstate is passed in, upon return it reflect the driver
- * internal state and can be used with dma_async_is_complete() to check
- * the status of multiple cookies without re-checking hardware state.
+ * If @txstate is passed in, upon return it reflects the driver
+ * internal state: the last completed and the last issued cookie.
*/
static enum dma_status
atc_tx_status(struct dma_chan *chan,
diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c
index ced78c985d1c..d7febef65a2d 100644
--- a/drivers/dma/dmaengine.c
+++ b/drivers/dma/dmaengine.c
@@ -537,7 +537,7 @@ enum dma_status dma_sync_wait(struct dma_chan *chan, dma_cookie_t cookie)
dma_async_issue_pending(chan);
do {
- status = dma_async_is_tx_complete(chan, cookie, NULL, NULL);
+ status = dmaengine_async_is_tx_complete(chan, cookie);
if (time_after_eq(jiffies, dma_sync_wait_timeout)) {
dev_err(chan->device->dev, "%s: timeout!\n", __func__);
return DMA_ERROR;
diff --git a/drivers/dma/dmaengine.h b/drivers/dma/dmaengine.h
index 53f16d3f0029..e72876a512a3 100644
--- a/drivers/dma/dmaengine.h
+++ b/drivers/dma/dmaengine.h
@@ -79,7 +79,26 @@ static inline enum dma_status dma_cookie_status(struct dma_chan *chan,
state->residue = 0;
state->in_flight_bytes = 0;
}
- return dma_async_is_complete(cookie, complete, used);
+
+ if (complete <= used) {
+ if ((cookie <= complete) || (cookie > used))
+ return DMA_COMPLETE;
+ } else {
+ if ((cookie <= complete) && (cookie > used))
+ return DMA_COMPLETE;
+ }
+ return DMA_IN_PROGRESS;
+}
+
+static inline void dma_set_tx_state(struct dma_tx_state *st,
+ dma_cookie_t last, dma_cookie_t used, u32 residue)
+{
+ if (!st)
+ return;
+
+ st->last = last;
+ st->used = used;
+ st->residue = residue;
}
static inline void dma_set_residue(struct dma_tx_state *state, u32 residue)
diff --git a/drivers/dma/dmatest.c b/drivers/dma/dmatest.c
index 2ae3469397f3..3d0d54a97add 100644
--- a/drivers/dma/dmatest.c
+++ b/drivers/dma/dmatest.c
@@ -847,8 +847,7 @@ static int dmatest_func(void *data)
done->done,
msecs_to_jiffies(params->timeout));
- status = dma_async_is_tx_complete(chan, cookie, NULL,
- NULL);
+ status = dmaengine_async_is_tx_complete(chan, cookie);
}
if (!done->done) {
diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h
index 4178248611d9..83bef7a70b99 100644
--- a/include/linux/dmaengine.h
+++ b/include/linux/dmaengine.h
@@ -1596,9 +1596,12 @@ static inline void dma_async_issue_pending(struct dma_chan *chan)
* @last: returns last completed cookie, can be NULL
* @used: returns last issued cookie, can be NULL
*
- * If @last and @used are passed in, upon return they reflect the driver
- * internal state and can be used with dma_async_is_complete() to check
- * the status of multiple cookies without re-checking hardware state.
+ * This function is deprecated. New code should use
+ * dmaengine_async_is_tx_complete() instead.
+ *
+ * If @last and @used are passed in, upon return they reflect the most
+ * recently submitted (used) cookie and the most recently completed
+ * cookie.
*/
static inline enum dma_status dma_async_is_tx_complete(struct dma_chan *chan,
dma_cookie_t cookie, dma_cookie_t *last, dma_cookie_t *used)
@@ -1615,36 +1618,29 @@ static inline enum dma_status dma_async_is_tx_complete(struct dma_chan *chan,
}
/**
- * dma_async_is_complete - test a cookie against chan state
- * @cookie: transaction identifier to test status of
- * @last_complete: last know completed transaction
- * @last_used: last cookie value handed out
+ * dmaengine_async_is_tx_complete - poll for transaction completion
+ * @chan: DMA channel
+ * @cookie: transaction identifier to check status of
*
- * dma_async_is_complete() is used in dma_async_is_tx_complete()
- * the test logic is separated for lightweight testing of multiple cookies
+ * Query the provider's device_tx_status() callback for the state of a
+ * single transaction. Providers that rely on cookie ordering answer with
+ * the cookie-window approximation. Providers that track per-descriptor
+ * state can answer exactly, but only for a transaction submitted without
+ * DMA_PREP_INTERRUPT and only on the first query that reports it
+ * finished. A transaction submitted with DMA_PREP_INTERRUPT reports its
+ * result through callback_result, and the query only tells whether it
+ * has finished. Once the first terminal answer has retired the
+ * descriptor, a later query for the same cookie reads DMA_COMPLETE.
+ *
+ * Return: DMA_COMPLETE, DMA_IN_PROGRESS, DMA_PAUSED, DMA_ERROR or
+ * DMA_OUT_OF_ORDER.
*/
-static inline enum dma_status dma_async_is_complete(dma_cookie_t cookie,
- dma_cookie_t last_complete, dma_cookie_t last_used)
-{
- if (last_complete <= last_used) {
- if ((cookie <= last_complete) || (cookie > last_used))
- return DMA_COMPLETE;
- } else {
- if ((cookie <= last_complete) && (cookie > last_used))
- return DMA_COMPLETE;
- }
- return DMA_IN_PROGRESS;
-}
-
-static inline void
-dma_set_tx_state(struct dma_tx_state *st, dma_cookie_t last, dma_cookie_t used, u32 residue)
+static inline enum dma_status dmaengine_async_is_tx_complete(struct dma_chan *chan,
+ dma_cookie_t cookie)
{
- if (!st)
- return;
+ struct dma_tx_state state;
- st->last = last;
- st->used = used;
- st->residue = residue;
+ return chan->device->device_tx_status(chan, cookie, &state);
}
#ifdef CONFIG_DMA_ENGINE
--
2.43.0
next prev parent reply other threads:[~2026-10-19 15:14 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-19 15:06 [PATCH 0/3] [PATCH 0/3] dmaengine: polled completion status for out-of-order providers Daniel Byrne
2026-10-19 15:06 ` Daniel Byrne [this message]
2026-10-19 18:36 ` [PATCH 1/3] dmaengine: add dmaengine_async_is_tx_complete() for channel status queries Frank Li
2026-10-19 15:06 ` [PATCH 2/3] dmaengine: idxd: generation-number transaction status Daniel Byrne
2026-10-19 18:53 ` Dave Jiang
2026-10-19 15:06 ` [PATCH 3/3] dmaengine: drop DMA_COMPLETION_NO_ORDER and DMA_OUT_OF_ORDER Daniel Byrne
2026-10-19 19:02 ` Frank Li
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=20261019150632.4026424-2-daniel1.byrne@intel.com \
--to=daniel1.byrne@intel.com \
--cc=Frank.Li@kernel.org \
--cc=corbet@lwn.net \
--cc=dave.jiang@intel.com \
--cc=dmaengine@vger.kernel.org \
--cc=fenghua.yu@intel.com \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-doc@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=ludovic.desroches@microchip.com \
--cc=vinicius.gomes@intel.com \
--cc=vkoul@kernel.org \
/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®