Re: [PATCH] crypto: marvell/cesa - Do not chain submitted requests

Corentin Labbe
2025-05-07T15:16:07Z

Le Wed, May 07, 2025 at 04:43:56PM +0800, Herbert Xu a écrit :
> On Tue, May 06, 2025 at 09:19:04PM +0800, Herbert Xu wrote:
> >
> > I haven't figured out exactly what's wrong with tdma, although
> > the chaining IRQ completion handling looks a bit fragile in that
> > if something goes wrong it'll simply mark all queued requests as
> > complete, corrupting any requests that have not yet been sent to
> > the hardware.
>
> I'm fairly confident that I've found the culprit. Please try this
> patch and see if it makes tdma work again:
>
> ---8<---
> This driver tries to chain requests together before submitting them
> to hardware in order to reduce completion interrupts.
>
> However, it even extends chains that have already been submitted
> to hardware. This is dangerous because there is no way of knowing
> whether the hardware has already read the DMA memory in question
> or not.
>
> Fix this by splitting the chain list into two. One for submitted
> requests and one for requests that have not yet been submitted.
> Only extend the latter.
>
> Reported-by: Klaus Kudielka <klaus.kudielka@gmail.com>
> Fixes: 85030c5168f1 ("crypto: marvell - Add support for chaining crypto requests in TDMA mode")
> Cc: <stable@vger.kernel.org>
> Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
> ---
> drivers/crypto/marvell/cesa/cesa.c | 2 +-
> drivers/crypto/marvell/cesa/cesa.h | 9 +++--
> drivers/crypto/marvell/cesa/tdma.c | 54 ++++++++++++++++++------------
> 3 files changed, 40 insertions(+), 25 deletions(-)
>
> diff --git a/drivers/crypto/marvell/cesa/cesa.c b/drivers/crypto/marvell/cesa/cesa.c
> index fa08f10e6f3f..9c21f5d835d2 100644
> --- a/drivers/crypto/marvell/cesa/cesa.c
> +++ b/drivers/crypto/marvell/cesa/cesa.c
> @@ -94,7 +94,7 @@ static int mv_cesa_std_process(struct mv_cesa_engine *engine, u32 status)
>
> static int mv_cesa_int_process(struct mv_cesa_engine *engine, u32 status)
> {
> - if (engine->chain.first && engine->chain.last)
> + if (engine->chain_hw.first && engine->chain_hw.last)
> return mv_cesa_tdma_process(engine, status);
>
> return mv_cesa_std_process(engine, status);
> diff --git a/drivers/crypto/marvell/cesa/cesa.h b/drivers/crypto/marvell/cesa/cesa.h
> index d215a6bed6bc..50ca1039fdaa 100644
> --- a/drivers/crypto/marvell/cesa/cesa.h
> +++ b/drivers/crypto/marvell/cesa/cesa.h
> @@ -440,8 +440,10 @@ struct mv_cesa_dev {
> * SRAM
> * @queue: fifo of the pending crypto requests
> * @load: engine load counter, useful for load balancing
> - * @chain: list of the current tdma descriptors being processed
> - * by this engine.
> + * @chain_hw: list of the current tdma descriptors being processed
> + * by the hardware.
> + * @chain_sw: list of the current tdma descriptors that will be
> + * submitted to the hardware.
> * @complete_queue: fifo of the processed requests by the engine
> *
> * Structure storing CESA engine information.
> @@ -463,7 +465,8 @@ struct mv_cesa_engine {
> struct gen_pool *pool;
> struct crypto_queue queue;
> atomic_t load;
> - struct mv_cesa_tdma_chain chain;
> + struct mv_cesa_tdma_chain chain_hw;
> + struct mv_cesa_tdma_chain chain_sw;
> struct list_head complete_queue;
> int irq;
> };
> diff --git a/drivers/crypto/marvell/cesa/tdma.c b/drivers/crypto/marvell/cesa/tdma.c
> index 388a06e180d6..40fcc852adfa 100644
> --- a/drivers/crypto/marvell/cesa/tdma.c
> +++ b/drivers/crypto/marvell/cesa/tdma.c
> @@ -38,6 +38,15 @@ void mv_cesa_dma_step(struct mv_cesa_req *dreq)
> {
> struct mv_cesa_engine *engine = dreq->engine;
>
> + spin_lock_bh(&engine->lock);
> + if (engine->chain_sw.first == dreq->chain.first) {
> + engine->chain_sw.first = NULL;
> + engine->chain_sw.last = NULL;
> + }
> + engine->chain_hw.first = dreq->chain.first;
> + engine->chain_hw.last = dreq->chain.last;
> + spin_unlock_bh(&engine->lock);
> +
> writel_relaxed(0, engine->regs + CESA_SA_CFG);
>
> mv_cesa_set_int_mask(engine, CESA_SA_INT_ACC0_IDMA_DONE);
> @@ -96,25 +105,28 @@ void mv_cesa_dma_prepare(struct mv_cesa_req *dreq,
> void mv_cesa_tdma_chain(struct mv_cesa_engine *engine,
> struct mv_cesa_req *dreq)
> {
> - if (engine->chain.first == NULL && engine->chain.last == NULL) {
> - engine->chain.first = dreq->chain.first;
> - engine->chain.last = dreq->chain.last;
> + struct mv_cesa_tdma_desc *last = engine->chain_sw.last;
> +
> + /*
> + * Break the DMA chain if the request being queued needs the IV
> + * regs to be set before lauching the request.
> + */
> + if (!last || dreq->chain.first->flags & CESA_TDMA_SET_STATE) {
> + engine->chain_sw.first = dreq->chain.first;
> + engine->chain_sw.last = dreq->chain.last;
> } else {
> - struct mv_cesa_tdma_desc *last;
> -
> - last = engine->chain.last;
> last->next = dreq->chain.first;
> - engine->chain.last = dreq->chain.last;
> -
> - /*
> - * Break the DMA chain if the CESA_TDMA_BREAK_CHAIN is set on
> - * the last element of the current chain, or if the request
> - * being queued needs the IV regs to be set before lauching
> - * the request.
> - */
> - if (!(last->flags & CESA_TDMA_BREAK_CHAIN) &&
> - !(dreq->chain.first->flags & CESA_TDMA_SET_STATE))
> - last->next_dma = cpu_to_le32(dreq->chain.first->cur_dma);
> + last->next_dma = cpu_to_le32(dreq->chain.first->cur_dma);
> + last = dreq->chain.last;
> + engine->chain_sw.last = last;
> + }
> + /*
> + * Break the DMA chain if the CESA_TDMA_BREAK_CHAIN is set on
> + * the last element of the current chain.
> + */
> + if (last->flags & CESA_TDMA_BREAK_CHAIN) {
> + engine->chain_sw.first = NULL;
> + engine->chain_sw.last = NULL;
> }
> }
>
> @@ -127,7 +139,7 @@ int mv_cesa_tdma_process(struct mv_cesa_engine *engine, u32 status)
>
> tdma_cur = readl(engine->regs + CESA_TDMA_CUR);
>
> - for (tdma = engine->chain.first; tdma; tdma = next) {
> + for (tdma = engine->chain_hw.first; tdma; tdma = next) {
> spin_lock_bh(&engine->lock);
> next = tdma->next;
> spin_unlock_bh(&engine->lock);
> @@ -149,12 +161,12 @@ int mv_cesa_tdma_process(struct mv_cesa_engine *engine, u32 status)
> &backlog);
>
> /* Re-chaining to the next request */
> - engine->chain.first = tdma->next;
> + engine->chain_hw.first = tdma->next;
> tdma->next = NULL;
>
> /* If this is the last request, clear the chain */
> - if (engine->chain.first == NULL)
> - engine->chain.last = NULL;
> + if (engine->chain_hw.first == NULL)
> + engine->chain_hw.last = NULL;
> spin_unlock_bh(&engine->lock);
>
> ctx = crypto_tfm_ctx(req->tfm);
> --
> 2.39.5
>
> --

I tested this patch and my armada-388-clearfog-pro panic with:
[ 16.571926] 8<--- cut here ---
[ 16.575013] Unable to handle kernel NULL pointer dereference at virtual address 0000001c when read
[ 16.584014] [0000001c] *pgd=00000000
[ 16.587614] Internal error: Oops: 17 [#1] SMP ARM
[ 16.592334] Modules linked in: marvell_cesa(+) libdes sfp mdio_i2c
[ 16.598543] CPU: 1 UID: 0 PID: 145 Comm: cryptomgr_test Not tainted 6.15.0-rc5-g1362bea77314 #80 NONE
[ 16.607878] Hardware name: Marvell Armada 380/385 (Device Tree)
[ 16.613812] PC is at mv_cesa_tdma_chain+0x28/0x58 [marvell_cesa]
[ 16.619859] LR is at mv_cesa_queue_req+0x60/0x84 [marvell_cesa]
[ 16.625803] pc : [<bf01dfc8>] lr : [<bf01abec>] psr: 60000013
[ 16.632091] sp : f0afd8e8 ip : c8ee3d6c fp : 00000000
[ 16.637335] r10: 00000001 r9 : c8ec67c0 r8 : 00000820
[ 16.642572] r7 : c8ee3d50 r6 : c8ee3d40 r5 : c8ee3840 r4 : ffffff8d
[ 16.649116] r3 : 00000000 r2 : c681c080 r1 : c8ee3840 r0 : c8ee3d40
[ 16.655660] Flags: nZCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment none
[ 16.662806] Control: 10c5387d Table: 069a804a DAC: 00000051
[ 16.668565] Register r0 information: slab kmalloc-256 start c8ee3d00 pointer offset 64 size 256
[ 16.677297] Register r1 information: slab kmalloc-256 start c8ee3800 pointer offset 64 size 256
[ 16.686026] Register r2 information: non-slab/vmalloc memory
[ 16.691701] Register r3 information: NULL pointer
[ 16.696419] Register r4 information: non-paged memory
[ 16.701483] Register r5 information: slab kmalloc-256 start c8ee3800 pointer offset 64 size 256
[ 16.710211] Register r6 information: slab kmalloc-256 start c8ee3d00 pointer offset 64 size 256
[ 16.718938] Register r7 information: slab kmalloc-256 start c8ee3d00 pointer offset 80 size 256
[ 16.727670] Register r8 information: non-paged memory
[ 16.732744] Register r9 information: slab kmalloc-128 start c8ec6780 pointer offset 64 size 128
[ 16.741479] Register r10 information: non-paged memory
[ 16.746637] Register r11 information: NULL pointer
[ 16.751440] Register r12 information: slab kmalloc-256 start c8ee3d00 pointer offset 108 size 256
[ 16.760343] Process cryptomgr_test (pid: 145, stack limit = 0x592e8429)
[ 16.766977] Stack: (0xf0afd8e8 to 0xf0afe000)
[ 16.771346] d8e0: c8ee3810 c8ee3800 bf020000 c8ee3840 00000820 bf01b1d4
[ 16.779552] d900: 00000820 00000001 00000008 00000008 00000000 00000001 c6977020 00000008
[ 16.787763] d920: 00000000 00000002 c6977020 00000008 00000000 ae05d94e c8ee3800 00000001
[ 16.795971] d940: c134260c c8ee3800 c0756adc c6977000 f0afda28 bf01bc80 00000000 00000101
[ 16.796732] 8<--- cut here ---
[ 16.804173] d960: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 67452301
[ 16.807243] Unable to handle kernel NULL pointer dereference at virtual address 0000001c when read
[ 16.815426] d980: efcdab89 00000000 00000000 00000000 00000000 00000000 00000000 00000000
[ 16.824411] [0000001c] *pgd=00000000
[ 16.832595] d9a0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
[ 16.832601] d9c0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 ae05d94e
[ 16.836177]
[ 16.844372] d9e0: c13686e8 c07663ec 00000008 f0afda20 00000001 00000000 00000001 00000000
[ 16.844378] da00: 00000400 00000000 c89b4b40 bf020c2c f0afdd84 c1836fcc 00000000 c184da44
[ 16.870447] da20: c184e598 00000008 00000000 00000000 f0afda30 f0afda30 00000000 00000000
[ 16.878645] da40: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
[ 16.886843] da60: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
[ 16.895041] da80: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
[ 16.903239] daa0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
[ 16.911437] dac0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
[ 16.919635] dae0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
[ 16.927833] db00: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
[ 16.936031] db20: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
[ 16.944229] db40: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
[ 16.952426] db60: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
[ 16.960624] db80: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
[ 16.968822] dba0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
[ 16.977020] dbc0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 ae05d94e
[ 16.985219] dbe0: c6977000 c134260c c1344c0c 00000001 c13686e8 c8ee3800 c6977000 c134326c
[ 16.993417] dc00: 000000a1 c0766860 c8ee3800 c6977000 00000000 00000000 ef8cb4c0 00000002
[ 17.001615] dc20: fffffffe c04ed770 00000000 00000000 00000000 00000000 00000000 00000801
[ 17.009813] dc40: ef7e0534 00000000 0000000f 00000000 00000000 00000000 00000000 00000000
[ 17.018012] dc60: 0000000f 00000034 c1f6c7b4 c1f75520 00000000 60000013 ef7e0500 c1f6c9f4
[ 17.026210] dc80: c1faef98 c8c5cec0 00000000 ae05d94e 00000000 c1c72500 2db6e000 ef7e0500
[ 17.034408] dca0: 00000000 00000800 c1f6c700 00000801 00000001 c04eec18 ef7e0500 ef7e0534
[ 17.042606] dcc0: 00000000 00000000 00000000 00000000 00000801 00000000 00000000 00000000
[ 17.050804] dce0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
[ 17.059002] dd00: 00000000 00000000 00000000 f0afdde0 00000cc0 00000000 c1f6d508 00000000
[ 17.067201] dd20: 00000000 00000000 c1f75520 00000034 00000000 c8c5cec0 c1f6c9f0 00000000
[ 17.075399] dd40: 00000000 000000cc 00000001 000000d4 b6db6db7 00000003 00000000 ae05d94e
[ 17.083597] dd60: 00000000 00000007 00000001 00000001 00000000 c1343ecc 00000001 c89b4b80
[ 17.091795] dd80: c8c5cec0 00000030 00000000 00000000 00000000 00000000 00000cc0 c1d05340
[ 17.099993] dda0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
[ 17.108191] ddc0: 00000000 00000000 bf020b80 c1e065b4 f0afddd8 c04f94fc c8c5cec1 00011085
[ 17.116390] dde0: c1f6d500 00000000 c1f6d508 00000000 00000001 00000000 00000cc0 bf020b80
[ 17.124588] de00: 00000040 c6a02400 c1fbb1b0 00000000 000000a1 c0756abc c1341d48 ae05d94e
[ 17.132786] de20: c1341d48 00000007 c6977180 00000001 c6977168 c1343ecc 00000007 c6977180
[ 17.140984] de40: 00000001 c6977168 c1343ecc c0762ac8 c6977000 ae05d94e 00000000 c1344c0c
[ 17.149183] de60: c6977000 c8ee3800 00000028 c89b4b40 c89b4b80 c07670a8 c6977000 dbc252ec
[ 17.157381] de80: 00000001 c0766ff0 ffffffff c6a02400 00011085 c1343ecc c1fbb1b0 00000000
[ 17.165580] dea0: 000000a1 c0767334 ef7dce00 ef7dce00 c1d0b054 ffffffff 00000000 c6a02480
[ 17.173778] dec0: 00000400 00000005 00000000 0000006a 00000000 c8c5f1c0 c298cec0 c298cec0
[ 17.181976] dee0: c8c5cec0 ef7dce00 c8c5cec0 c2a273c0 c2a273c0 00000001 f0afdf6c c12d0dd0
[ 17.190175] df00: f0afdf34 c0399fb8 ef7dce00 c8c5cec0 00000000 c12d1484 2db6e000 c1c6ee00
[ 17.198373] df20: c1d052c4 00000000 00000002 c1f736e0 00000000 00000004 c1306950 00000000
[ 17.206571] df40: 00000002 ae05d94e 00000004 c8c5cec0 c681b080 ae05d94e f113dc10 c6a02400
[ 17.214769] df60: c681b080 c8c5cec0 c681b080 c0762528 c6a02400 00000000 00000000 c0762540
[ 17.222967] df80: 00000001 c03844c0 00000000 ae05d94e c6819b80 c03843b8 00000000 00000000
[ 17.231165] dfa0: 00000000 00000000 00000000 c03001ac 00000000 00000000 00000000 00000000
[ 17.239363] dfc0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
[ 17.247561] dfe0: 00000000 00000000 00000000 00000000 00000013 00000000 00000000 00000000
[ 17.255757] Call trace:
[ 17.255763] mv_cesa_tdma_chain [marvell_cesa] from mv_cesa_queue_req+0x60/0x84 [marvell_cesa]
[ 17.266962] mv_cesa_queue_req [marvell_cesa] from mv_cesa_skcipher_queue_req+0x14c/0x4b8 [marvell_cesa]
[ 17.276483] mv_cesa_skcipher_queue_req [marvell_cesa] from mv_cesa_ecb_des_encrypt+0x54/0x78 [marvell_cesa]
[ 17.286352] mv_cesa_ecb_des_encrypt [marvell_cesa] from test_skcipher_vec_cfg+0x2f4/0x6f8
[ 17.294653] test_skcipher_vec_cfg from test_skcipher_vec+0x70/0x1b4
[ 17.301026] test_skcipher_vec from alg_test_skcipher+0xb8/0x1f4
[ 17.307051] alg_test_skcipher from alg_test+0x150/0x658
[ 17.312380] alg_test from cryptomgr_test+0x18/0x38
[ 17.317273] cryptomgr_test from kthread+0x108/0x234
[ 17.322259] kthread from ret_from_fork+0x14/0x28
[ 17.326981] Exception stack(0xf0afdfb0 to 0xf0afdff8)
[ 17.332045] dfa0: 00000000 00000000 00000000 00000000
[ 17.340244] dfc0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
[ 17.348441] dfe0: 00000000 00000000 00000000 00000000 00000013 00000000
[ 17.355074] Code: 0a000008 e580204c e5912008 e5802050 (e593301c)
[ 17.361183] Internal error: Oops: 17 [#2] SMP ARM
[ 17.361209] ---[ end trace 0000000000000000 ]---
[ 17.365900] Modules linked in: marvell_cesa(+)
[ 17.370530] Kernel panic - not syncing: Fatal exception in interrupt