Skip to content

Commit 8759fec

Browse files
Romain Perierherbertx
authored andcommitted
crypto: marvell - Copy IVDIG before launching partial DMA ahash requests
Currently, inner IV/DIGEST data are only copied once into the hash engines and not set explicitly before launching a request that is not a first frag. This is an issue especially when multiple ahash reqs are computed in parallel or chained with cipher request, as the state of the request being computed is not updated into the hash engine. It leads to non-deterministic corrupted digest results. Fixes: commit 2786cee ("crypto: marvell - Move SRAM I/O operations to step functions") Signed-off-by: Romain Perier <[email protected]> Acked-by: Boris Brezillon <[email protected]> Cc: <[email protected]> Signed-off-by: Herbert Xu <[email protected]>
1 parent 18e615a commit 8759fec

File tree

3 files changed

+43
-3
lines changed

3 files changed

+43
-3
lines changed

drivers/crypto/marvell/cesa.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -273,7 +273,8 @@ struct mv_cesa_op_ctx {
273273
#define CESA_TDMA_SRC_IN_SRAM BIT(30)
274274
#define CESA_TDMA_END_OF_REQ BIT(29)
275275
#define CESA_TDMA_BREAK_CHAIN BIT(28)
276-
#define CESA_TDMA_TYPE_MSK GENMASK(27, 0)
276+
#define CESA_TDMA_SET_STATE BIT(27)
277+
#define CESA_TDMA_TYPE_MSK GENMASK(26, 0)
277278
#define CESA_TDMA_DUMMY 0
278279
#define CESA_TDMA_DATA 1
279280
#define CESA_TDMA_OP 2

drivers/crypto/marvell/hash.c

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -281,13 +281,32 @@ static void mv_cesa_ahash_std_prepare(struct ahash_request *req)
281281
sreq->offset = 0;
282282
}
283283

284+
static void mv_cesa_ahash_dma_step(struct ahash_request *req)
285+
{
286+
struct mv_cesa_ahash_req *creq = ahash_request_ctx(req);
287+
struct mv_cesa_req *base = &creq->base;
288+
289+
/* We must explicitly set the digest state. */
290+
if (base->chain.first->flags & CESA_TDMA_SET_STATE) {
291+
struct mv_cesa_engine *engine = base->engine;
292+
int i;
293+
294+
/* Set the hash state in the IVDIG regs. */
295+
for (i = 0; i < ARRAY_SIZE(creq->state); i++)
296+
writel_relaxed(creq->state[i], engine->regs +
297+
CESA_IVDIG(i));
298+
}
299+
300+
mv_cesa_dma_step(base);
301+
}
302+
284303
static void mv_cesa_ahash_step(struct crypto_async_request *req)
285304
{
286305
struct ahash_request *ahashreq = ahash_request_cast(req);
287306
struct mv_cesa_ahash_req *creq = ahash_request_ctx(ahashreq);
288307

289308
if (mv_cesa_req_get_type(&creq->base) == CESA_DMA_REQ)
290-
mv_cesa_dma_step(&creq->base);
309+
mv_cesa_ahash_dma_step(ahashreq);
291310
else
292311
mv_cesa_ahash_std_step(ahashreq);
293312
}
@@ -585,12 +604,16 @@ static int mv_cesa_ahash_dma_req_init(struct ahash_request *req)
585604
struct mv_cesa_ahash_dma_iter iter;
586605
struct mv_cesa_op_ctx *op = NULL;
587606
unsigned int frag_len;
607+
bool set_state = false;
588608
int ret;
589609
u32 type;
590610

591611
basereq->chain.first = NULL;
592612
basereq->chain.last = NULL;
593613

614+
if (!mv_cesa_mac_op_is_first_frag(&creq->op_tmpl))
615+
set_state = true;
616+
594617
if (creq->src_nents) {
595618
ret = dma_map_sg(cesa_dev->dev, req->src, creq->src_nents,
596619
DMA_TO_DEVICE);
@@ -684,6 +707,15 @@ static int mv_cesa_ahash_dma_req_init(struct ahash_request *req)
684707
if (type != CESA_TDMA_RESULT)
685708
basereq->chain.last->flags |= CESA_TDMA_BREAK_CHAIN;
686709

710+
if (set_state) {
711+
/*
712+
* Put the CESA_TDMA_SET_STATE flag on the first tdma desc to
713+
* let the step logic know that the IVDIG registers should be
714+
* explicitly set before launching a TDMA chain.
715+
*/
716+
basereq->chain.first->flags |= CESA_TDMA_SET_STATE;
717+
}
718+
687719
return 0;
688720

689721
err_free_tdma:

drivers/crypto/marvell/tdma.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,14 @@ void mv_cesa_tdma_chain(struct mv_cesa_engine *engine,
109109
last->next = dreq->chain.first;
110110
engine->chain.last = dreq->chain.last;
111111

112-
if (!(last->flags & CESA_TDMA_BREAK_CHAIN))
112+
/*
113+
* Break the DMA chain if the CESA_TDMA_BREAK_CHAIN is set on
114+
* the last element of the current chain, or if the request
115+
* being queued needs the IV regs to be set before lauching
116+
* the request.
117+
*/
118+
if (!(last->flags & CESA_TDMA_BREAK_CHAIN) &&
119+
!(dreq->chain.first->flags & CESA_TDMA_SET_STATE))
113120
last->next_dma = dreq->chain.first->cur_dma;
114121
}
115122
}

0 commit comments

Comments
 (0)