[PATCH 19/23] dmaengine: sdxi: Provide context start and stop APIs
From: Nathan Lynch via B4 Relay
Date: Fri Apr 10 2026 - 09:13:16 EST
From: Nathan Lynch <nathan.lynch@xxxxxxx>
Starting and stopping SDXI client contexts is implemented by submitting
special-purpose descriptors to a function's admin context.
Introduce high-level context start and stop APIs that operate on
struct sdxi_cxt objects, encapsulating the administrative descriptor
submission and completion signaling. These are intended for use by
clients such as the DMA engine provider to come.
Co-developed-by: Wei Huang <wei.huang2@xxxxxxx>
Signed-off-by: Wei Huang <wei.huang2@xxxxxxx>
Signed-off-by: Nathan Lynch <nathan.lynch@xxxxxxx>
---
drivers/dma/sdxi/context.c | 77 ++++++++++++++++++++++++++++++++++++++++++++++
drivers/dma/sdxi/context.h | 3 ++
2 files changed, 80 insertions(+)
diff --git a/drivers/dma/sdxi/context.c b/drivers/dma/sdxi/context.c
index 04e0d3e6a337..fc6291f12ffe 100644
--- a/drivers/dma/sdxi/context.c
+++ b/drivers/dma/sdxi/context.c
@@ -23,7 +23,9 @@
#include <asm/barrier.h>
#include <asm/rwonce.h>
+#include "completion.h"
#include "context.h"
+#include "descriptor.h"
#include "hw.h"
#include "ring.h"
#include "sdxi.h"
@@ -394,6 +396,81 @@ int sdxi_admin_cxt_init(struct sdxi_dev *sdxi)
return devm_add_action_or_reset(sdxi_to_dev(sdxi), free_admin_cxt, sdxi);
}
+int sdxi_start_cxt(struct sdxi_cxt *cxt)
+{
+ struct sdxi_cxt *adm = to_admin_cxt(cxt);
+ struct sdxi_desc *desc;
+ struct sdxi_ring_resv resv;
+ int err;
+
+ might_sleep();
+
+ struct sdxi_completion *sc __free(sdxi_completion) =
+ sdxi_completion_alloc(cxt->sdxi);
+
+ if (!sc)
+ return -ENOMEM;
+
+ /* This is not how to start the admin context. */
+ if (WARN_ON(adm == cxt))
+ return -EINVAL;
+
+ err = sdxi_ring_reserve(adm->ring_state, 1, &resv);
+ if (err)
+ return err;
+
+ desc = sdxi_ring_resv_next(&resv);
+ sdxi_encode_cxt_start(desc, &(const struct sdxi_cxt_start) {
+ .range = sdxi_cxt_range_single(cxt->id),
+ });
+ sdxi_completion_attach(desc, sc);
+ sdxi_desc_make_valid(desc);
+ sdxi_cxt_push_doorbell(adm, sdxi_ring_resv_dbval(&resv));
+ sdxi_completion_poll(sc);
+
+ return 0;
+}
+
+void sdxi_stop_cxt(struct sdxi_cxt *cxt)
+{
+ struct sdxi_cxt *adm = to_admin_cxt(cxt);
+ struct sdxi_desc *stop, *sync;
+ struct sdxi_ring_resv resv;
+ int err;
+
+ might_sleep();
+
+ struct sdxi_completion *sc __free(sdxi_completion) =
+ sdxi_completion_alloc(cxt->sdxi);
+
+ if (!sc)
+ return;
+
+ /* This is not how to stop the admin context. */
+ if (WARN_ON(adm == cxt))
+ return;
+
+ err = sdxi_ring_reserve(adm->ring_state, 2, &resv);
+ if (WARN_ON_ONCE(err))
+ return;
+
+ stop = sdxi_ring_resv_next(&resv);
+ sync = sdxi_ring_resv_next(&resv);
+
+ sdxi_encode_cxt_stop(stop, &(const struct sdxi_cxt_stop) {
+ .range = sdxi_cxt_range_single(cxt->id),
+ });
+ sdxi_encode_sync(sync, &(const struct sdxi_sync) {
+ .filter = SDXI_SYNC_FLT_STOP,
+ .range = sdxi_cxt_range_single(cxt->id),
+ });
+ sdxi_completion_attach(sync, sc);
+ sdxi_desc_make_valid(stop);
+ sdxi_desc_make_valid(sync);
+ sdxi_cxt_push_doorbell(adm, sdxi_ring_resv_dbval(&resv));
+ sdxi_completion_poll(sc);
+}
+
/*
* Allocate a context for in-kernel use. Starting the context is the
* caller's responsibility.
diff --git a/drivers/dma/sdxi/context.h b/drivers/dma/sdxi/context.h
index 5310e51a668c..9061221e86cb 100644
--- a/drivers/dma/sdxi/context.h
+++ b/drivers/dma/sdxi/context.h
@@ -67,6 +67,9 @@ int sdxi_admin_cxt_init(struct sdxi_dev *sdxi);
struct sdxi_cxt *sdxi_cxt_new(struct sdxi_dev *sdxi);
void sdxi_cxt_exit(struct sdxi_cxt *cxt);
+int sdxi_start_cxt(struct sdxi_cxt *cxt);
+void sdxi_stop_cxt(struct sdxi_cxt *cxt);
+
static inline struct sdxi_cxt *to_admin_cxt(const struct sdxi_cxt *cxt)
{
return cxt->sdxi->admin_cxt;
--
2.53.0