Merge branch 'linus' of git://git.kernel.org/pub/scm/linux/kernel/git/herbert/crypto-2.6
[platform/kernel/linux-rpi.git] / drivers / crypto / marvell / hash.c
index 77712b3..317cf02 100644 (file)
@@ -311,24 +311,40 @@ static void mv_cesa_ahash_complete(struct crypto_async_request *req)
        int i;
 
        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
-                * SHA in big endian format
+                * Result is already in the correct endianess when the SA is
+                * used
                 */
-               if (creq->algo_le) {
-                       __le32 *result = (void *)ahashreq->result;
+               data = creq->base.chain.last->op->ctx.hash.hash;
+               for (i = 0; i < digsize / 4; i++)
+                       creq->state[i] = cpu_to_le32(data[i]);
 
-                       for (i = 0; i < digsize / 4; i++)
-                               result[i] = cpu_to_le32(creq->state[i]);
-               } else {
-                       __be32 *result = (void *)ahashreq->result;
+               memcpy(ahashreq->result, data, digsize);
+       } else {
+               for (i = 0; i < digsize / 4; i++)
+                       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++)
-                               result[i] = cpu_to_be32(creq->state[i]);
+                               for (i = 0; i < digsize / 4; i++)
+                                       result[i] = cpu_to_be32(creq->state[i]);
+                       }
                }
        }
 
@@ -503,6 +519,12 @@ mv_cesa_ahash_dma_last_req(struct mv_cesa_tdma_chain *chain,
                                                CESA_SA_DESC_CFG_LAST_FRAG,
                                      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;
        }
 
@@ -563,6 +585,7 @@ static int mv_cesa_ahash_dma_req_init(struct ahash_request *req)
        struct mv_cesa_op_ctx *op = NULL;
        unsigned int frag_len;
        int ret;
+       u32 type;
 
        basereq->chain.first = NULL;
        basereq->chain.last = NULL;
@@ -634,7 +657,15 @@ static int mv_cesa_ahash_dma_req_init(struct ahash_request *req)
                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 */
                ret = mv_cesa_dma_add_dummy_end(&basereq->chain, flags);
                if (ret)
@@ -647,8 +678,10 @@ static int mv_cesa_ahash_dma_req_init(struct ahash_request *req)
        else
                creq->cache_ptr = 0;
 
-       basereq->chain.last->flags |= (CESA_TDMA_END_OF_REQ |
-                                      CESA_TDMA_BREAK_CHAIN);
+       basereq->chain.last->flags |= CESA_TDMA_END_OF_REQ;
+
+       if (type != CESA_TDMA_RESULT)
+               basereq->chain.last->flags |= CESA_TDMA_BREAK_CHAIN;
 
        return 0;