aboutsummaryrefslogtreecommitdiff
path: root/drivers/crypto/allwinner/sun8i-ss/sun8i-ss-hash.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/crypto/allwinner/sun8i-ss/sun8i-ss-hash.c')
-rw-r--r--drivers/crypto/allwinner/sun8i-ss/sun8i-ss-hash.c35
1 files changed, 26 insertions, 9 deletions
diff --git a/drivers/crypto/allwinner/sun8i-ss/sun8i-ss-hash.c b/drivers/crypto/allwinner/sun8i-ss/sun8i-ss-hash.c
index 53e5bfb99c93..1b44c1a115d6 100644
--- a/drivers/crypto/allwinner/sun8i-ss/sun8i-ss-hash.c
+++ b/drivers/crypto/allwinner/sun8i-ss/sun8i-ss-hash.c
@@ -14,6 +14,7 @@
#include <linux/pm_runtime.h>
#include <linux/scatterlist.h>
#include <crypto/internal/hash.h>
+#include <crypto/scatterwalk.h>
#include <crypto/sha1.h>
#include <crypto/sha2.h>
#include <crypto/md5.h>
@@ -262,6 +263,9 @@ static bool sun8i_ss_hash_need_fallback(struct ahash_request *areq)
if (areq->nbytes == 0)
return true;
+ if (areq->nbytes >= MAX_PAD_SIZE - 64)
+ return true;
+
/* we need to reserve one SG for the padding one */
if (sg_nents(areq->src) > MAX_SG - 1)
return true;
@@ -270,10 +274,13 @@ static bool sun8i_ss_hash_need_fallback(struct ahash_request *areq)
/* SS can operate hash only on full block size
* since SS support only MD5,sha1,sha224 and sha256, blocksize
* is always 64
- * TODO: handle request if last SG is not len%64
- * but this will need to copy data on a new SG of size=64
*/
- if (sg->length % 64 || !IS_ALIGNED(sg->offset, sizeof(u32)))
+ /* Only the last block could be bounced to the pad buffer */
+ if (sg->length % 64 && sg_next(sg))
+ return true;
+ if (!IS_ALIGNED(sg->offset, sizeof(u32)))
+ return true;
+ if (sg->length % 4)
return true;
sg = sg_next(sg);
}
@@ -361,6 +368,7 @@ int sun8i_ss_hash_run(struct crypto_engine *engine, void *breq)
goto theend;
}
+ j = 0;
len = areq->nbytes;
sg = areq->src;
i = 0;
@@ -369,12 +377,19 @@ int sun8i_ss_hash_run(struct crypto_engine *engine, void *breq)
sg = sg_next(sg);
continue;
}
- rctx->t_src[i].addr = sg_dma_address(sg);
todo = min(len, sg_dma_len(sg));
- rctx->t_src[i].len = todo / 4;
- len -= todo;
- rctx->t_dst[i].addr = addr_res;
- rctx->t_dst[i].len = digestsize / 4;
+ /* only the last SG could be with a size not modulo64 */
+ if (todo % 64 == 0) {
+ rctx->t_src[i].addr = sg_dma_address(sg);
+ rctx->t_src[i].len = todo / 4;
+ rctx->t_dst[i].addr = addr_res;
+ rctx->t_dst[i].len = digestsize / 4;
+ len -= todo;
+ } else {
+ scatterwalk_map_and_copy(bf, sg, 0, todo, 0);
+ j += todo / 4;
+ len -= todo;
+ }
sg = sg_next(sg);
i++;
}
@@ -384,8 +399,10 @@ int sun8i_ss_hash_run(struct crypto_engine *engine, void *breq)
goto theend;
}
+ if (j > 0)
+ i--;
+
byte_count = areq->nbytes;
- j = 0;
bf[j++] = cpu_to_le32(0x80);
fill = 64 - (byte_count % 64);