mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCHv2] crypto: cesa: complete pending requests on device remove
@ 2026-09-24 23:59 Rosen Penev
  2026-09-25  0:15 ` Robert Lovrinovic
  0 siblings, 1 reply; 2+ messages in thread
From: Rosen Penev @ 2026-09-24 23:59 UTC (permalink / raw)
  To: linux-crypto
  Cc: Srujana Challa, Bharat Bhushan, Herbert Xu, David S. Miller, open list

mv_cesa_remove() unregisters the algorithms but never drains the engine
queues.  Each engine can still hold outstanding requests in three
places: engine->req (currently in flight), engine->queue (queued but
not started), and engine->complete_queue (processed but not yet
reported).  After unregistration those waiters never receive their
completion callback and block indefinitely, leaking the request and its
scatterlist buffers.

In mv_cesa_remove() stop each engine (mask interrupts, clear the CMD and
TDMA control registers, then wait for the engine to report idle), quiesce
the threaded IRQ with disable_irq()/synchronize_irq(), and drain the
three queues, completing every outstanding request with -ENOENT.  The
completion callbacks unmap DMA buffers through the global cesa_dev
pointer, so keep it valid until the engines are drained, and mark the
engines aborted under their lock so a racing submitter cannot restart a
halted engine.

Assisted-by: LLM
Signed-off-by: Rosen Penev <rosenp@gmail.com>
---
 v2: fix a bunch of sashiko errors
 drivers/crypto/marvell/cesa/cesa.c | 80 ++++++++++++++++++++++++++++++
 drivers/crypto/marvell/cesa/cesa.h |  4 ++
 2 files changed, 84 insertions(+)

diff --git a/drivers/crypto/marvell/cesa/cesa.c b/drivers/crypto/marvell/cesa/cesa.c
index 564b09773507..d91e1af0fe9c 100644
--- a/drivers/crypto/marvell/cesa/cesa.c
+++ b/drivers/crypto/marvell/cesa/cesa.c
@@ -52,6 +52,14 @@ static void mv_cesa_rearm_engine(struct mv_cesa_engine *engine)
 
 	spin_lock_bh(&engine->lock);
 	if (!engine->req) {
+		if (engine->aborted) {
+			/*
+			 * The device is being removed: do not restart the
+			 * engine nor fetch any new request.
+			 */
+			spin_unlock_bh(&engine->lock);
+			return;
+		}
 		req = mv_cesa_dequeue_req_locked(engine, &backlog);
 		engine->req = req;
 	}
@@ -542,9 +550,81 @@ static int mv_cesa_probe(struct platform_device *pdev)
 static void mv_cesa_remove(struct platform_device *pdev)
 {
 	struct mv_cesa_dev *cesa = platform_get_drvdata(pdev);
+	struct mv_cesa_engine *engine;
+	struct crypto_async_request *req;
+	unsigned int i;
+	unsigned int timeout;
 
 	mv_cesa_remove_algs(cesa);
 
+	for (i = 0; i < cesa->caps->nengines; i++) {
+		engine = &cesa->engines[i];
+
+		/*
+		 * Stop the engine so it no longer issues DMA to the SRAM
+		 * region or to request scatterlists that are about to be
+		 * unmapped.
+		 */
+		writel(0, engine->regs + CESA_SA_INT_MSK);
+		writel(0, engine->regs + CESA_SA_CMD);
+		writel(0, engine->regs + CESA_TDMA_CONTROL);
+
+		/*
+		 * Flush the posted writes above and wait for the engine to
+		 * report that it is stopped before any buffer is released.
+		 */
+		timeout = CESA_ENGINE_STOP_TIMEOUT_US;
+		while ((readl(engine->regs + CESA_SA_CMD) &
+			CESA_SA_CMD_EN_CESA_SA_ACCL0) && --timeout)
+			udelay(1);
+
+		/*
+		 * Synchronize with the threaded IRQ handler so that it cannot
+		 * run while the queues below are drained.
+		 */
+		disable_irq(engine->irq);
+		synchronize_irq(engine->irq);
+
+		spin_lock_bh(&engine->lock);
+		engine->aborted = true;
+
+		/*
+		 * Complete the request currently in flight and drain the
+		 * pending and already-processed queues with an error so that
+		 * waiters do not block indefinitely when the device is unbound
+		 * while requests are still outstanding.
+		 */
+		if (engine->req) {
+			req = engine->req;
+			engine->req = NULL;
+			spin_unlock_bh(&engine->lock);
+			mv_cesa_complete_req(crypto_tfm_ctx(req->tfm), req,
+					     -ENOENT);
+			spin_lock_bh(&engine->lock);
+		}
+
+		while ((req = crypto_dequeue_request(&engine->queue)) != NULL) {
+			spin_unlock_bh(&engine->lock);
+			mv_cesa_complete_req(crypto_tfm_ctx(req->tfm), req,
+					     -ENOENT);
+			spin_lock_bh(&engine->lock);
+		}
+
+		while ((req = mv_cesa_engine_dequeue_complete_request(engine))
+		       != NULL) {
+			spin_unlock_bh(&engine->lock);
+			mv_cesa_complete_req(crypto_tfm_ctx(req->tfm), req,
+					     -ENOENT);
+			spin_lock_bh(&engine->lock);
+		}
+		spin_unlock_bh(&engine->lock);
+	}
+
+	/*
+	 * The completion callbacks above (and any concurrent submitter) rely
+	 * on the global cesa_dev pointer: only clear it once the engines are
+	 * fully drained.
+	 */
 	cesa_dev = NULL;
 }
 
diff --git a/drivers/crypto/marvell/cesa/cesa.h b/drivers/crypto/marvell/cesa/cesa.h
index 44351b252861..56c0dd6f5772 100644
--- a/drivers/crypto/marvell/cesa/cesa.h
+++ b/drivers/crypto/marvell/cesa/cesa.h
@@ -10,6 +10,9 @@
 
 #define CESA_ENGINE_OFF(i)			(((i) * 0x2000))
 
+/* Max time in microseconds to wait for the engine to stop */
+#define CESA_ENGINE_STOP_TIMEOUT_US		1000
+
 #define CESA_TDMA_BYTE_CNT			0x800
 #define CESA_TDMA_SRC_ADDR			0x810
 #define CESA_TDMA_DST_ADDR			0x820
@@ -450,6 +453,7 @@ struct mv_cesa_engine {
 	struct mv_cesa_tdma_chain chain_sw;
 	struct list_head complete_queue;
 	int irq;
+	bool aborted;
 };
 
 /**
-- 
2.55.0


^ permalink raw reply	[flat|nested] 2+ messages in thread

* Re: [PATCHv2] crypto: cesa: complete pending requests on device remove
  2026-09-24 23:59 [PATCHv2] crypto: cesa: complete pending requests on device remove Rosen Penev
@ 2026-09-25  0:15 ` Robert Lovrinovic
  0 siblings, 0 replies; 2+ messages in thread
From: Robert Lovrinovic @ 2026-09-25  0:15 UTC (permalink / raw)
  To: Rosen Penev
  Cc: linux-crypto, Srujana Challa, Bharat Bhushan, Herbert Xu,
	David S. Miller, open list

There still appears to be a race between stopping the engine and
setting engine->aborted. An IRQ thread already in flight may call
mv_cesa_rearm_engine() after the CMD idle check but before aborted is
set, and ctx->ops->step() may restart the hardware. We can then
synchronize the IRQ and free request/DMA objects while the engine is
running.

I think engine->aborted needs to be set before the final engine stop,
so that once we have observed the engine idle, no software path can
restart it.

engine->aborted currently only prevents mv_cesa_rearm_engine() from
dequeuing a new request; it does not prevent mv_cesa_queue_req() from
enqueueing one. A submitter racing after the removal drain can
therefore leave a request permanently queued. Please check aborted
under engine->lock in mv_cesa_queue_req() before calling
crypto_enqueue_request() mv_cesa_tdma_chain(), and return an
appropriate teardown error.

The stop timeout also looks unsafe as written. If the timeout expires,
teardown still proceeds to the callbacks and cleanup, which may free
DMA-visible objects while the engine is still active. The timeout
needs an explicit failure path or hardware reset rather than simply
continuing teardown.

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2026-09-25  0:16 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-09-24 23:59 [PATCHv2] crypto: cesa: complete pending requests on device remove Rosen Penev
2026-09-25  0:15 ` Robert Lovrinovic

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®