Commit f34dad17 authored by Romain Perier's avatar Romain Perier Committed by Herbert Xu

crypto: marvell - Don't break chain for computable last ahash requests

Currently, the driver breaks chain for all kind of hash requests in order to
don't override intermediate states of partial ahash updates. However, some final
ahash requests can be directly processed by the engine, and so without
intermediate state. This is typically the case for most for the HMAC requests
processed via IPSec.

This commits adds a TDMA descriptor to copy context for these of requests
into the "op" dma pool, then it allow to chain these requests at the DMA level.
The 'complete' operation is also updated to retrieve the MAC digest from the
right location.
Signed-off-by: default avatarRomain Perier <romain.perier@free-electrons.com>
Acked-by: default avatarBoris Brezillon <boris.brezillon@free-electrons.com>
Signed-off-by: default avatarHerbert Xu <herbert@gondor.apana.org.au>
parent 0c99620f
...@@ -312,24 +312,40 @@ static void mv_cesa_ahash_complete(struct crypto_async_request *req) ...@@ -312,24 +312,40 @@ static void mv_cesa_ahash_complete(struct crypto_async_request *req)
int i; int i;
digsize = crypto_ahash_digestsize(crypto_ahash_reqtfm(ahashreq)); digsize = crypto_ahash_digestsize(crypto_ahash_reqtfm(ahashreq));
for (i = 0; i < digsize / 4; i++)
creq->state[i] = readl_relaxed(engine->regs + CESA_IVDIG(i));
if (creq->last_req) { if (mv_cesa_req_get_type(&creq->base) == CESA_DMA_REQ &&
(creq->base.chain.last->flags & CESA_TDMA_TYPE_MSK) == CESA_TDMA_RESULT) {
__le32 *data = NULL;
/* /*
* Hardware's MD5 digest is in little endian format, but * Result is already in the correct endianess when the SA is
* SHA in big endian format * used
*/ */
if (creq->algo_le) { data = creq->base.chain.last->op->ctx.hash.hash;
__le32 *result = (void *)ahashreq->result; for (i = 0; i < digsize / 4; i++)
creq->state[i] = cpu_to_le32(data[i]);
for (i = 0; i < digsize / 4; i++) memcpy(ahashreq->result, data, digsize);
result[i] = cpu_to_le32(creq->state[i]); } else {
} else { for (i = 0; i < digsize / 4; i++)
__be32 *result = (void *)ahashreq->result; creq->state[i] = readl_relaxed(engine->regs +
CESA_IVDIG(i));
if (creq->last_req) {
/*
* Hardware's MD5 digest is in little endian format, but
* SHA in big endian format
*/
if (creq->algo_le) {
__le32 *result = (void *)ahashreq->result;
for (i = 0; i < digsize / 4; i++)
result[i] = cpu_to_le32(creq->state[i]);
} else {
__be32 *result = (void *)ahashreq->result;
for (i = 0; i < digsize / 4; i++) for (i = 0; i < digsize / 4; i++)
result[i] = cpu_to_be32(creq->state[i]); result[i] = cpu_to_be32(creq->state[i]);
}
} }
} }
...@@ -504,6 +520,12 @@ mv_cesa_ahash_dma_last_req(struct mv_cesa_tdma_chain *chain, ...@@ -504,6 +520,12 @@ mv_cesa_ahash_dma_last_req(struct mv_cesa_tdma_chain *chain,
CESA_SA_DESC_CFG_LAST_FRAG, CESA_SA_DESC_CFG_LAST_FRAG,
CESA_SA_DESC_CFG_FRAG_MSK); CESA_SA_DESC_CFG_FRAG_MSK);
ret = mv_cesa_dma_add_result_op(chain,
CESA_SA_CFG_SRAM_OFFSET,
CESA_SA_DATA_SRAM_OFFSET,
CESA_TDMA_SRC_IN_SRAM, flags);
if (ret)
return ERR_PTR(-ENOMEM);
return op; return op;
} }
...@@ -564,6 +586,7 @@ static int mv_cesa_ahash_dma_req_init(struct ahash_request *req) ...@@ -564,6 +586,7 @@ static int mv_cesa_ahash_dma_req_init(struct ahash_request *req)
struct mv_cesa_op_ctx *op = NULL; struct mv_cesa_op_ctx *op = NULL;
unsigned int frag_len; unsigned int frag_len;
int ret; int ret;
u32 type;
basereq->chain.first = NULL; basereq->chain.first = NULL;
basereq->chain.last = NULL; basereq->chain.last = NULL;
...@@ -635,7 +658,15 @@ static int mv_cesa_ahash_dma_req_init(struct ahash_request *req) ...@@ -635,7 +658,15 @@ static int mv_cesa_ahash_dma_req_init(struct ahash_request *req)
goto err_free_tdma; goto err_free_tdma;
} }
if (op) { /*
* If results are copied via DMA, this means that this
* request can be directly processed by the engine,
* without partial updates. So we can chain it at the
* DMA level with other requests.
*/
type = basereq->chain.last->flags & CESA_TDMA_TYPE_MSK;
if (op && type != CESA_TDMA_RESULT) {
/* Add dummy desc to wait for crypto operation end */ /* Add dummy desc to wait for crypto operation end */
ret = mv_cesa_dma_add_dummy_end(&basereq->chain, flags); ret = mv_cesa_dma_add_dummy_end(&basereq->chain, flags);
if (ret) if (ret)
...@@ -648,8 +679,10 @@ static int mv_cesa_ahash_dma_req_init(struct ahash_request *req) ...@@ -648,8 +679,10 @@ static int mv_cesa_ahash_dma_req_init(struct ahash_request *req)
else else
creq->cache_ptr = 0; creq->cache_ptr = 0;
basereq->chain.last->flags |= (CESA_TDMA_END_OF_REQ | basereq->chain.last->flags |= CESA_TDMA_END_OF_REQ;
CESA_TDMA_BREAK_CHAIN);
if (type != CESA_TDMA_RESULT)
basereq->chain.last->flags |= CESA_TDMA_BREAK_CHAIN;
return 0; return 0;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment