|
@@ -43,6 +43,7 @@
|
|
|
#include <crypto/aes.h>
|
|
|
#include <crypto/des.h>
|
|
|
#include <crypto/sha.h>
|
|
|
+#include <crypto/md5.h>
|
|
|
#include <crypto/aead.h>
|
|
|
#include <crypto/authenc.h>
|
|
|
#include <crypto/skcipher.h>
|
|
@@ -67,6 +68,13 @@ struct talitos_ptr {
|
|
|
__be32 ptr; /* address */
|
|
|
};
|
|
|
|
|
|
+static const struct talitos_ptr zero_entry = {
|
|
|
+ .len = 0,
|
|
|
+ .j_extent = 0,
|
|
|
+ .eptr = 0,
|
|
|
+ .ptr = 0
|
|
|
+};
|
|
|
+
|
|
|
/* descriptor */
|
|
|
struct talitos_desc {
|
|
|
__be32 hdr; /* header high bits */
|
|
@@ -694,7 +702,7 @@ static void talitos_unregister_rng(struct device *dev)
|
|
|
#define TALITOS_MAX_KEY_SIZE 64
|
|
|
#define TALITOS_MAX_IV_LENGTH 16 /* max of AES_BLOCK_SIZE, DES3_EDE_BLOCK_SIZE */
|
|
|
|
|
|
-#define MD5_DIGEST_SIZE 16
|
|
|
+#define MD5_BLOCK_SIZE 64
|
|
|
|
|
|
struct talitos_ctx {
|
|
|
struct device *dev;
|
|
@@ -707,6 +715,22 @@ struct talitos_ctx {
|
|
|
unsigned int authsize;
|
|
|
};
|
|
|
|
|
|
+#define HASH_MAX_BLOCK_SIZE SHA512_BLOCK_SIZE
|
|
|
+#define TALITOS_MDEU_MAX_CONTEXT_SIZE TALITOS_MDEU_CONTEXT_SIZE_SHA384_SHA512
|
|
|
+
|
|
|
+struct talitos_ahash_req_ctx {
|
|
|
+ u64 count;
|
|
|
+ u8 hw_context[TALITOS_MDEU_MAX_CONTEXT_SIZE];
|
|
|
+ unsigned int hw_context_size;
|
|
|
+ u8 buf[HASH_MAX_BLOCK_SIZE];
|
|
|
+ u8 bufnext[HASH_MAX_BLOCK_SIZE];
|
|
|
+ unsigned int first;
|
|
|
+ unsigned int last;
|
|
|
+ unsigned int to_hash_later;
|
|
|
+ struct scatterlist bufsl[2];
|
|
|
+ struct scatterlist *psrc;
|
|
|
+};
|
|
|
+
|
|
|
static int aead_setauthsize(struct crypto_aead *authenc,
|
|
|
unsigned int authsize)
|
|
|
{
|
|
@@ -823,10 +847,14 @@ static void talitos_sg_unmap(struct device *dev,
|
|
|
else
|
|
|
dma_unmap_sg(dev, src, src_nents, DMA_TO_DEVICE);
|
|
|
|
|
|
- if (edesc->dst_is_chained)
|
|
|
- talitos_unmap_sg_chain(dev, dst, DMA_FROM_DEVICE);
|
|
|
- else
|
|
|
- dma_unmap_sg(dev, dst, dst_nents, DMA_FROM_DEVICE);
|
|
|
+ if (dst) {
|
|
|
+ if (edesc->dst_is_chained)
|
|
|
+ talitos_unmap_sg_chain(dev, dst,
|
|
|
+ DMA_FROM_DEVICE);
|
|
|
+ else
|
|
|
+ dma_unmap_sg(dev, dst, dst_nents,
|
|
|
+ DMA_FROM_DEVICE);
|
|
|
+ }
|
|
|
} else
|
|
|
if (edesc->src_is_chained)
|
|
|
talitos_unmap_sg_chain(dev, src, DMA_BIDIRECTIONAL);
|
|
@@ -1116,12 +1144,67 @@ static int sg_count(struct scatterlist *sg_list, int nbytes, int *chained)
|
|
|
return sg_nents;
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * sg_copy_end_to_buffer - Copy end data from SG list to a linear buffer
|
|
|
+ * @sgl: The SG list
|
|
|
+ * @nents: Number of SG entries
|
|
|
+ * @buf: Where to copy to
|
|
|
+ * @buflen: The number of bytes to copy
|
|
|
+ * @skip: The number of bytes to skip before copying.
|
|
|
+ * Note: skip + buflen should equal SG total size.
|
|
|
+ *
|
|
|
+ * Returns the number of copied bytes.
|
|
|
+ *
|
|
|
+ **/
|
|
|
+static size_t sg_copy_end_to_buffer(struct scatterlist *sgl, unsigned int nents,
|
|
|
+ void *buf, size_t buflen, unsigned int skip)
|
|
|
+{
|
|
|
+ unsigned int offset = 0;
|
|
|
+ unsigned int boffset = 0;
|
|
|
+ struct sg_mapping_iter miter;
|
|
|
+ unsigned long flags;
|
|
|
+ unsigned int sg_flags = SG_MITER_ATOMIC;
|
|
|
+ size_t total_buffer = buflen + skip;
|
|
|
+
|
|
|
+ sg_flags |= SG_MITER_FROM_SG;
|
|
|
+
|
|
|
+ sg_miter_start(&miter, sgl, nents, sg_flags);
|
|
|
+
|
|
|
+ local_irq_save(flags);
|
|
|
+
|
|
|
+ while (sg_miter_next(&miter) && offset < total_buffer) {
|
|
|
+ unsigned int len;
|
|
|
+ unsigned int ignore;
|
|
|
+
|
|
|
+ if ((offset + miter.length) > skip) {
|
|
|
+ if (offset < skip) {
|
|
|
+ /* Copy part of this segment */
|
|
|
+ ignore = skip - offset;
|
|
|
+ len = miter.length - ignore;
|
|
|
+ memcpy(buf + boffset, miter.addr + ignore, len);
|
|
|
+ } else {
|
|
|
+ /* Copy all of this segment */
|
|
|
+ len = miter.length;
|
|
|
+ memcpy(buf + boffset, miter.addr, len);
|
|
|
+ }
|
|
|
+ boffset += len;
|
|
|
+ }
|
|
|
+ offset += miter.length;
|
|
|
+ }
|
|
|
+
|
|
|
+ sg_miter_stop(&miter);
|
|
|
+
|
|
|
+ local_irq_restore(flags);
|
|
|
+ return boffset;
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* allocate and map the extended descriptor
|
|
|
*/
|
|
|
static struct talitos_edesc *talitos_edesc_alloc(struct device *dev,
|
|
|
struct scatterlist *src,
|
|
|
struct scatterlist *dst,
|
|
|
+ int hash_result,
|
|
|
unsigned int cryptlen,
|
|
|
unsigned int authsize,
|
|
|
int icv_stashing,
|
|
@@ -1141,11 +1224,16 @@ static struct talitos_edesc *talitos_edesc_alloc(struct device *dev,
|
|
|
src_nents = sg_count(src, cryptlen + authsize, &src_chained);
|
|
|
src_nents = (src_nents == 1) ? 0 : src_nents;
|
|
|
|
|
|
- if (dst == src) {
|
|
|
- dst_nents = src_nents;
|
|
|
+ if (hash_result) {
|
|
|
+ dst_nents = 0;
|
|
|
} else {
|
|
|
- dst_nents = sg_count(dst, cryptlen + authsize, &dst_chained);
|
|
|
- dst_nents = (dst_nents == 1) ? 0 : dst_nents;
|
|
|
+ if (dst == src) {
|
|
|
+ dst_nents = src_nents;
|
|
|
+ } else {
|
|
|
+ dst_nents = sg_count(dst, cryptlen + authsize,
|
|
|
+ &dst_chained);
|
|
|
+ dst_nents = (dst_nents == 1) ? 0 : dst_nents;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
/*
|
|
@@ -1174,8 +1262,10 @@ static struct talitos_edesc *talitos_edesc_alloc(struct device *dev,
|
|
|
edesc->src_is_chained = src_chained;
|
|
|
edesc->dst_is_chained = dst_chained;
|
|
|
edesc->dma_len = dma_len;
|
|
|
- edesc->dma_link_tbl = dma_map_single(dev, &edesc->link_tbl[0],
|
|
|
- edesc->dma_len, DMA_BIDIRECTIONAL);
|
|
|
+ if (dma_len)
|
|
|
+ edesc->dma_link_tbl = dma_map_single(dev, &edesc->link_tbl[0],
|
|
|
+ edesc->dma_len,
|
|
|
+ DMA_BIDIRECTIONAL);
|
|
|
|
|
|
return edesc;
|
|
|
}
|
|
@@ -1186,7 +1276,7 @@ static struct talitos_edesc *aead_edesc_alloc(struct aead_request *areq,
|
|
|
struct crypto_aead *authenc = crypto_aead_reqtfm(areq);
|
|
|
struct talitos_ctx *ctx = crypto_aead_ctx(authenc);
|
|
|
|
|
|
- return talitos_edesc_alloc(ctx->dev, areq->src, areq->dst,
|
|
|
+ return talitos_edesc_alloc(ctx->dev, areq->src, areq->dst, 0,
|
|
|
areq->cryptlen, ctx->authsize, icv_stashing,
|
|
|
areq->base.flags);
|
|
|
}
|
|
@@ -1443,8 +1533,8 @@ static struct talitos_edesc *ablkcipher_edesc_alloc(struct ablkcipher_request *
|
|
|
struct crypto_ablkcipher *cipher = crypto_ablkcipher_reqtfm(areq);
|
|
|
struct talitos_ctx *ctx = crypto_ablkcipher_ctx(cipher);
|
|
|
|
|
|
- return talitos_edesc_alloc(ctx->dev, areq->src, areq->dst, areq->nbytes,
|
|
|
- 0, 0, areq->base.flags);
|
|
|
+ return talitos_edesc_alloc(ctx->dev, areq->src, areq->dst, 0,
|
|
|
+ areq->nbytes, 0, 0, areq->base.flags);
|
|
|
}
|
|
|
|
|
|
static int ablkcipher_encrypt(struct ablkcipher_request *areq)
|
|
@@ -1480,6 +1570,286 @@ static int ablkcipher_decrypt(struct ablkcipher_request *areq)
|
|
|
return common_nonsnoop(edesc, areq, NULL, ablkcipher_done);
|
|
|
}
|
|
|
|
|
|
+static void common_nonsnoop_hash_unmap(struct device *dev,
|
|
|
+ struct talitos_edesc *edesc,
|
|
|
+ struct ahash_request *areq)
|
|
|
+{
|
|
|
+ struct talitos_ahash_req_ctx *req_ctx = ahash_request_ctx(areq);
|
|
|
+
|
|
|
+ unmap_single_talitos_ptr(dev, &edesc->desc.ptr[5], DMA_FROM_DEVICE);
|
|
|
+
|
|
|
+ /* When using hashctx-in, must unmap it. */
|
|
|
+ if (edesc->desc.ptr[1].len)
|
|
|
+ unmap_single_talitos_ptr(dev, &edesc->desc.ptr[1],
|
|
|
+ DMA_TO_DEVICE);
|
|
|
+
|
|
|
+ if (edesc->desc.ptr[2].len)
|
|
|
+ unmap_single_talitos_ptr(dev, &edesc->desc.ptr[2],
|
|
|
+ DMA_TO_DEVICE);
|
|
|
+
|
|
|
+ talitos_sg_unmap(dev, edesc, req_ctx->psrc, NULL);
|
|
|
+
|
|
|
+ if (edesc->dma_len)
|
|
|
+ dma_unmap_single(dev, edesc->dma_link_tbl, edesc->dma_len,
|
|
|
+ DMA_BIDIRECTIONAL);
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+static void ahash_done(struct device *dev,
|
|
|
+ struct talitos_desc *desc, void *context,
|
|
|
+ int err)
|
|
|
+{
|
|
|
+ struct ahash_request *areq = context;
|
|
|
+ struct talitos_edesc *edesc =
|
|
|
+ container_of(desc, struct talitos_edesc, desc);
|
|
|
+ struct talitos_ahash_req_ctx *req_ctx = ahash_request_ctx(areq);
|
|
|
+
|
|
|
+ if (!req_ctx->last && req_ctx->to_hash_later) {
|
|
|
+ /* Position any partial block for next update/final/finup */
|
|
|
+ memcpy(req_ctx->buf, req_ctx->bufnext, req_ctx->to_hash_later);
|
|
|
+ }
|
|
|
+ common_nonsnoop_hash_unmap(dev, edesc, areq);
|
|
|
+
|
|
|
+ kfree(edesc);
|
|
|
+
|
|
|
+ areq->base.complete(&areq->base, err);
|
|
|
+}
|
|
|
+
|
|
|
+static int common_nonsnoop_hash(struct talitos_edesc *edesc,
|
|
|
+ struct ahash_request *areq, unsigned int length,
|
|
|
+ void (*callback) (struct device *dev,
|
|
|
+ struct talitos_desc *desc,
|
|
|
+ void *context, int error))
|
|
|
+{
|
|
|
+ struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);
|
|
|
+ struct talitos_ctx *ctx = crypto_ahash_ctx(tfm);
|
|
|
+ struct talitos_ahash_req_ctx *req_ctx = ahash_request_ctx(areq);
|
|
|
+ struct device *dev = ctx->dev;
|
|
|
+ struct talitos_desc *desc = &edesc->desc;
|
|
|
+ int sg_count, ret;
|
|
|
+
|
|
|
+ /* first DWORD empty */
|
|
|
+ desc->ptr[0] = zero_entry;
|
|
|
+
|
|
|
+ /* hash context in (if not first) */
|
|
|
+ if (!req_ctx->first) {
|
|
|
+ map_single_talitos_ptr(dev, &desc->ptr[1],
|
|
|
+ req_ctx->hw_context_size,
|
|
|
+ (char *)req_ctx->hw_context, 0,
|
|
|
+ DMA_TO_DEVICE);
|
|
|
+ } else {
|
|
|
+ desc->ptr[1] = zero_entry;
|
|
|
+ /* Indicate next op is not the first. */
|
|
|
+ req_ctx->first = 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* HMAC key */
|
|
|
+ if (ctx->keylen)
|
|
|
+ map_single_talitos_ptr(dev, &desc->ptr[2], ctx->keylen,
|
|
|
+ (char *)&ctx->key, 0, DMA_TO_DEVICE);
|
|
|
+ else
|
|
|
+ desc->ptr[2] = zero_entry;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * data in
|
|
|
+ */
|
|
|
+ desc->ptr[3].len = cpu_to_be16(length);
|
|
|
+ desc->ptr[3].j_extent = 0;
|
|
|
+
|
|
|
+ sg_count = talitos_map_sg(dev, req_ctx->psrc,
|
|
|
+ edesc->src_nents ? : 1,
|
|
|
+ DMA_TO_DEVICE,
|
|
|
+ edesc->src_is_chained);
|
|
|
+
|
|
|
+ if (sg_count == 1) {
|
|
|
+ to_talitos_ptr(&desc->ptr[3], sg_dma_address(req_ctx->psrc));
|
|
|
+ } else {
|
|
|
+ sg_count = sg_to_link_tbl(req_ctx->psrc, sg_count, length,
|
|
|
+ &edesc->link_tbl[0]);
|
|
|
+ if (sg_count > 1) {
|
|
|
+ desc->ptr[3].j_extent |= DESC_PTR_LNKTBL_JUMP;
|
|
|
+ to_talitos_ptr(&desc->ptr[3], edesc->dma_link_tbl);
|
|
|
+ dma_sync_single_for_device(ctx->dev,
|
|
|
+ edesc->dma_link_tbl,
|
|
|
+ edesc->dma_len,
|
|
|
+ DMA_BIDIRECTIONAL);
|
|
|
+ } else {
|
|
|
+ /* Only one segment now, so no link tbl needed */
|
|
|
+ to_talitos_ptr(&desc->ptr[3],
|
|
|
+ sg_dma_address(req_ctx->psrc));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /* fifth DWORD empty */
|
|
|
+ desc->ptr[4] = zero_entry;
|
|
|
+
|
|
|
+ /* hash/HMAC out -or- hash context out */
|
|
|
+ if (req_ctx->last)
|
|
|
+ map_single_talitos_ptr(dev, &desc->ptr[5],
|
|
|
+ crypto_ahash_digestsize(tfm),
|
|
|
+ areq->result, 0, DMA_FROM_DEVICE);
|
|
|
+ else
|
|
|
+ map_single_talitos_ptr(dev, &desc->ptr[5],
|
|
|
+ req_ctx->hw_context_size,
|
|
|
+ req_ctx->hw_context, 0, DMA_FROM_DEVICE);
|
|
|
+
|
|
|
+ /* last DWORD empty */
|
|
|
+ desc->ptr[6] = zero_entry;
|
|
|
+
|
|
|
+ ret = talitos_submit(dev, desc, callback, areq);
|
|
|
+ if (ret != -EINPROGRESS) {
|
|
|
+ common_nonsnoop_hash_unmap(dev, edesc, areq);
|
|
|
+ kfree(edesc);
|
|
|
+ }
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+static struct talitos_edesc *ahash_edesc_alloc(struct ahash_request *areq,
|
|
|
+ unsigned int nbytes)
|
|
|
+{
|
|
|
+ struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);
|
|
|
+ struct talitos_ctx *ctx = crypto_ahash_ctx(tfm);
|
|
|
+ struct talitos_ahash_req_ctx *req_ctx = ahash_request_ctx(areq);
|
|
|
+
|
|
|
+ return talitos_edesc_alloc(ctx->dev, req_ctx->psrc, NULL, 1,
|
|
|
+ nbytes, 0, 0, areq->base.flags);
|
|
|
+}
|
|
|
+
|
|
|
+static int ahash_init(struct ahash_request *areq)
|
|
|
+{
|
|
|
+ struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);
|
|
|
+ struct talitos_ahash_req_ctx *req_ctx = ahash_request_ctx(areq);
|
|
|
+
|
|
|
+ /* Initialize the context */
|
|
|
+ req_ctx->count = 0;
|
|
|
+ req_ctx->first = 1; /* first indicates h/w must init it's context */
|
|
|
+ req_ctx->hw_context_size =
|
|
|
+ (crypto_ahash_digestsize(tfm) <= SHA256_DIGEST_SIZE)
|
|
|
+ ? TALITOS_MDEU_CONTEXT_SIZE_MD5_SHA1_SHA256
|
|
|
+ : TALITOS_MDEU_CONTEXT_SIZE_SHA384_SHA512;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static int ahash_process_req(struct ahash_request *areq, unsigned int nbytes)
|
|
|
+{
|
|
|
+ struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);
|
|
|
+ struct talitos_ctx *ctx = crypto_ahash_ctx(tfm);
|
|
|
+ struct talitos_ahash_req_ctx *req_ctx = ahash_request_ctx(areq);
|
|
|
+ struct talitos_edesc *edesc;
|
|
|
+ unsigned int blocksize =
|
|
|
+ crypto_tfm_alg_blocksize(crypto_ahash_tfm(tfm));
|
|
|
+ unsigned int nbytes_to_hash;
|
|
|
+ unsigned int to_hash_later;
|
|
|
+ unsigned int index;
|
|
|
+ int chained;
|
|
|
+
|
|
|
+ index = req_ctx->count & (blocksize - 1);
|
|
|
+ req_ctx->count += nbytes;
|
|
|
+
|
|
|
+ if (!req_ctx->last && (index + nbytes) < blocksize) {
|
|
|
+ /* Buffer the partial block */
|
|
|
+ sg_copy_to_buffer(areq->src,
|
|
|
+ sg_count(areq->src, nbytes, &chained),
|
|
|
+ req_ctx->buf + index, nbytes);
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (index) {
|
|
|
+ /* partial block from previous update; chain it in. */
|
|
|
+ sg_init_table(req_ctx->bufsl, (nbytes) ? 2 : 1);
|
|
|
+ sg_set_buf(req_ctx->bufsl, req_ctx->buf, index);
|
|
|
+ if (nbytes)
|
|
|
+ scatterwalk_sg_chain(req_ctx->bufsl, 2,
|
|
|
+ areq->src);
|
|
|
+ req_ctx->psrc = req_ctx->bufsl;
|
|
|
+ } else {
|
|
|
+ req_ctx->psrc = areq->src;
|
|
|
+ }
|
|
|
+ nbytes_to_hash = index + nbytes;
|
|
|
+ if (!req_ctx->last) {
|
|
|
+ to_hash_later = (nbytes_to_hash & (blocksize - 1));
|
|
|
+ if (to_hash_later) {
|
|
|
+ int nents;
|
|
|
+ /* Must copy to_hash_later bytes from the end
|
|
|
+ * to bufnext (a partial block) for later.
|
|
|
+ */
|
|
|
+ nents = sg_count(areq->src, nbytes, &chained);
|
|
|
+ sg_copy_end_to_buffer(areq->src, nents,
|
|
|
+ req_ctx->bufnext,
|
|
|
+ to_hash_later,
|
|
|
+ nbytes - to_hash_later);
|
|
|
+
|
|
|
+ /* Adjust count for what will be hashed now */
|
|
|
+ nbytes_to_hash -= to_hash_later;
|
|
|
+ }
|
|
|
+ req_ctx->to_hash_later = to_hash_later;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* allocate extended descriptor */
|
|
|
+ edesc = ahash_edesc_alloc(areq, nbytes_to_hash);
|
|
|
+ if (IS_ERR(edesc))
|
|
|
+ return PTR_ERR(edesc);
|
|
|
+
|
|
|
+ edesc->desc.hdr = ctx->desc_hdr_template;
|
|
|
+
|
|
|
+ /* On last one, request SEC to pad; otherwise continue */
|
|
|
+ if (req_ctx->last)
|
|
|
+ edesc->desc.hdr |= DESC_HDR_MODE0_MDEU_PAD;
|
|
|
+ else
|
|
|
+ edesc->desc.hdr |= DESC_HDR_MODE0_MDEU_CONT;
|
|
|
+
|
|
|
+ /* On first one, request SEC to INIT hash. */
|
|
|
+ if (req_ctx->first)
|
|
|
+ edesc->desc.hdr |= DESC_HDR_MODE0_MDEU_INIT;
|
|
|
+
|
|
|
+ /* When the tfm context has a keylen, it's an HMAC.
|
|
|
+ * A first or last (ie. not middle) descriptor must request HMAC.
|
|
|
+ */
|
|
|
+ if (ctx->keylen && (req_ctx->first || req_ctx->last))
|
|
|
+ edesc->desc.hdr |= DESC_HDR_MODE0_MDEU_HMAC;
|
|
|
+
|
|
|
+ return common_nonsnoop_hash(edesc, areq, nbytes_to_hash,
|
|
|
+ ahash_done);
|
|
|
+}
|
|
|
+
|
|
|
+static int ahash_update(struct ahash_request *areq)
|
|
|
+{
|
|
|
+ struct talitos_ahash_req_ctx *req_ctx = ahash_request_ctx(areq);
|
|
|
+
|
|
|
+ req_ctx->last = 0;
|
|
|
+
|
|
|
+ return ahash_process_req(areq, areq->nbytes);
|
|
|
+}
|
|
|
+
|
|
|
+static int ahash_final(struct ahash_request *areq)
|
|
|
+{
|
|
|
+ struct talitos_ahash_req_ctx *req_ctx = ahash_request_ctx(areq);
|
|
|
+
|
|
|
+ req_ctx->last = 1;
|
|
|
+
|
|
|
+ return ahash_process_req(areq, 0);
|
|
|
+}
|
|
|
+
|
|
|
+static int ahash_finup(struct ahash_request *areq)
|
|
|
+{
|
|
|
+ struct talitos_ahash_req_ctx *req_ctx = ahash_request_ctx(areq);
|
|
|
+
|
|
|
+ req_ctx->last = 1;
|
|
|
+
|
|
|
+ return ahash_process_req(areq, areq->nbytes);
|
|
|
+}
|
|
|
+
|
|
|
+static int ahash_digest(struct ahash_request *areq)
|
|
|
+{
|
|
|
+ struct talitos_ahash_req_ctx *req_ctx = ahash_request_ctx(areq);
|
|
|
+
|
|
|
+ ahash_init(areq);
|
|
|
+ req_ctx->last = 1;
|
|
|
+
|
|
|
+ return ahash_process_req(areq, areq->nbytes);
|
|
|
+}
|
|
|
+
|
|
|
struct talitos_alg_template {
|
|
|
u32 type;
|
|
|
union {
|
|
@@ -1695,7 +2065,113 @@ static struct talitos_alg_template driver_algs[] = {
|
|
|
DESC_HDR_SEL0_DEU |
|
|
|
DESC_HDR_MODE0_DEU_CBC |
|
|
|
DESC_HDR_MODE0_DEU_3DES,
|
|
|
- }
|
|
|
+ },
|
|
|
+ /* AHASH algorithms. */
|
|
|
+ { .type = CRYPTO_ALG_TYPE_AHASH,
|
|
|
+ .alg.hash = {
|
|
|
+ .init = ahash_init,
|
|
|
+ .update = ahash_update,
|
|
|
+ .final = ahash_final,
|
|
|
+ .finup = ahash_finup,
|
|
|
+ .digest = ahash_digest,
|
|
|
+ .halg.digestsize = MD5_DIGEST_SIZE,
|
|
|
+ .halg.base = {
|
|
|
+ .cra_name = "md5",
|
|
|
+ .cra_driver_name = "md5-talitos",
|
|
|
+ .cra_blocksize = MD5_BLOCK_SIZE,
|
|
|
+ .cra_flags = CRYPTO_ALG_TYPE_AHASH |
|
|
|
+ CRYPTO_ALG_ASYNC,
|
|
|
+ .cra_type = &crypto_ahash_type
|
|
|
+ }
|
|
|
+ },
|
|
|
+ .desc_hdr_template = DESC_HDR_TYPE_COMMON_NONSNOOP_NO_AFEU |
|
|
|
+ DESC_HDR_SEL0_MDEUA |
|
|
|
+ DESC_HDR_MODE0_MDEU_MD5,
|
|
|
+ },
|
|
|
+ { .type = CRYPTO_ALG_TYPE_AHASH,
|
|
|
+ .alg.hash = {
|
|
|
+ .init = ahash_init,
|
|
|
+ .update = ahash_update,
|
|
|
+ .final = ahash_final,
|
|
|
+ .finup = ahash_finup,
|
|
|
+ .digest = ahash_digest,
|
|
|
+ .halg.digestsize = SHA1_DIGEST_SIZE,
|
|
|
+ .halg.base = {
|
|
|
+ .cra_name = "sha1",
|
|
|
+ .cra_driver_name = "sha1-talitos",
|
|
|
+ .cra_blocksize = SHA1_BLOCK_SIZE,
|
|
|
+ .cra_flags = CRYPTO_ALG_TYPE_AHASH |
|
|
|
+ CRYPTO_ALG_ASYNC,
|
|
|
+ .cra_type = &crypto_ahash_type
|
|
|
+ }
|
|
|
+ },
|
|
|
+ .desc_hdr_template = DESC_HDR_TYPE_COMMON_NONSNOOP_NO_AFEU |
|
|
|
+ DESC_HDR_SEL0_MDEUA |
|
|
|
+ DESC_HDR_MODE0_MDEU_SHA1,
|
|
|
+ },
|
|
|
+ { .type = CRYPTO_ALG_TYPE_AHASH,
|
|
|
+ .alg.hash = {
|
|
|
+ .init = ahash_init,
|
|
|
+ .update = ahash_update,
|
|
|
+ .final = ahash_final,
|
|
|
+ .finup = ahash_finup,
|
|
|
+ .digest = ahash_digest,
|
|
|
+ .halg.digestsize = SHA256_DIGEST_SIZE,
|
|
|
+ .halg.base = {
|
|
|
+ .cra_name = "sha256",
|
|
|
+ .cra_driver_name = "sha256-talitos",
|
|
|
+ .cra_blocksize = SHA256_BLOCK_SIZE,
|
|
|
+ .cra_flags = CRYPTO_ALG_TYPE_AHASH |
|
|
|
+ CRYPTO_ALG_ASYNC,
|
|
|
+ .cra_type = &crypto_ahash_type
|
|
|
+ }
|
|
|
+ },
|
|
|
+ .desc_hdr_template = DESC_HDR_TYPE_COMMON_NONSNOOP_NO_AFEU |
|
|
|
+ DESC_HDR_SEL0_MDEUA |
|
|
|
+ DESC_HDR_MODE0_MDEU_SHA256,
|
|
|
+ },
|
|
|
+ { .type = CRYPTO_ALG_TYPE_AHASH,
|
|
|
+ .alg.hash = {
|
|
|
+ .init = ahash_init,
|
|
|
+ .update = ahash_update,
|
|
|
+ .final = ahash_final,
|
|
|
+ .finup = ahash_finup,
|
|
|
+ .digest = ahash_digest,
|
|
|
+ .halg.digestsize = SHA384_DIGEST_SIZE,
|
|
|
+ .halg.base = {
|
|
|
+ .cra_name = "sha384",
|
|
|
+ .cra_driver_name = "sha384-talitos",
|
|
|
+ .cra_blocksize = SHA384_BLOCK_SIZE,
|
|
|
+ .cra_flags = CRYPTO_ALG_TYPE_AHASH |
|
|
|
+ CRYPTO_ALG_ASYNC,
|
|
|
+ .cra_type = &crypto_ahash_type
|
|
|
+ }
|
|
|
+ },
|
|
|
+ .desc_hdr_template = DESC_HDR_TYPE_COMMON_NONSNOOP_NO_AFEU |
|
|
|
+ DESC_HDR_SEL0_MDEUB |
|
|
|
+ DESC_HDR_MODE0_MDEUB_SHA384,
|
|
|
+ },
|
|
|
+ { .type = CRYPTO_ALG_TYPE_AHASH,
|
|
|
+ .alg.hash = {
|
|
|
+ .init = ahash_init,
|
|
|
+ .update = ahash_update,
|
|
|
+ .final = ahash_final,
|
|
|
+ .finup = ahash_finup,
|
|
|
+ .digest = ahash_digest,
|
|
|
+ .halg.digestsize = SHA512_DIGEST_SIZE,
|
|
|
+ .halg.base = {
|
|
|
+ .cra_name = "sha512",
|
|
|
+ .cra_driver_name = "sha512-talitos",
|
|
|
+ .cra_blocksize = SHA512_BLOCK_SIZE,
|
|
|
+ .cra_flags = CRYPTO_ALG_TYPE_AHASH |
|
|
|
+ CRYPTO_ALG_ASYNC,
|
|
|
+ .cra_type = &crypto_ahash_type
|
|
|
+ }
|
|
|
+ },
|
|
|
+ .desc_hdr_template = DESC_HDR_TYPE_COMMON_NONSNOOP_NO_AFEU |
|
|
|
+ DESC_HDR_SEL0_MDEUB |
|
|
|
+ DESC_HDR_MODE0_MDEUB_SHA512,
|
|
|
+ },
|
|
|
};
|
|
|
|
|
|
struct talitos_crypto_alg {
|
|
@@ -1710,8 +2186,13 @@ static int talitos_cra_init(struct crypto_tfm *tfm)
|
|
|
struct talitos_crypto_alg *talitos_alg;
|
|
|
struct talitos_ctx *ctx = crypto_tfm_ctx(tfm);
|
|
|
|
|
|
- talitos_alg = container_of(alg, struct talitos_crypto_alg,
|
|
|
- algt.alg.crypto);
|
|
|
+ if ((alg->cra_flags & CRYPTO_ALG_TYPE_MASK) == CRYPTO_ALG_TYPE_AHASH)
|
|
|
+ talitos_alg = container_of(__crypto_ahash_alg(alg),
|
|
|
+ struct talitos_crypto_alg,
|
|
|
+ algt.alg.hash);
|
|
|
+ else
|
|
|
+ talitos_alg = container_of(alg, struct talitos_crypto_alg,
|
|
|
+ algt.alg.crypto);
|
|
|
|
|
|
/* update context with ptr to dev */
|
|
|
ctx->dev = talitos_alg->dev;
|
|
@@ -1719,12 +2200,34 @@ static int talitos_cra_init(struct crypto_tfm *tfm)
|
|
|
/* copy descriptor header template value */
|
|
|
ctx->desc_hdr_template = talitos_alg->algt.desc_hdr_template;
|
|
|
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static int talitos_cra_init_aead(struct crypto_tfm *tfm)
|
|
|
+{
|
|
|
+ struct talitos_ctx *ctx = crypto_tfm_ctx(tfm);
|
|
|
+
|
|
|
+ talitos_cra_init(tfm);
|
|
|
+
|
|
|
/* random first IV */
|
|
|
get_random_bytes(ctx->iv, TALITOS_MAX_IV_LENGTH);
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+static int talitos_cra_init_ahash(struct crypto_tfm *tfm)
|
|
|
+{
|
|
|
+ struct talitos_ctx *ctx = crypto_tfm_ctx(tfm);
|
|
|
+
|
|
|
+ talitos_cra_init(tfm);
|
|
|
+
|
|
|
+ ctx->keylen = 0;
|
|
|
+ crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm),
|
|
|
+ sizeof(struct talitos_ahash_req_ctx));
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* given the alg's descriptor header template, determine whether descriptor
|
|
|
* type and primary/secondary execution units required match the hw
|
|
@@ -1806,15 +2309,20 @@ static struct talitos_crypto_alg *talitos_alg_alloc(struct device *dev,
|
|
|
|
|
|
switch (t_alg->algt.type) {
|
|
|
case CRYPTO_ALG_TYPE_ABLKCIPHER:
|
|
|
+ alg = &t_alg->algt.alg.crypto;
|
|
|
+ alg->cra_init = talitos_cra_init;
|
|
|
+ break;
|
|
|
case CRYPTO_ALG_TYPE_AEAD:
|
|
|
alg = &t_alg->algt.alg.crypto;
|
|
|
+ alg->cra_init = talitos_cra_init_aead;
|
|
|
break;
|
|
|
case CRYPTO_ALG_TYPE_AHASH:
|
|
|
alg = &t_alg->algt.alg.hash.halg.base;
|
|
|
+ alg->cra_init = talitos_cra_init_ahash;
|
|
|
+ break;
|
|
|
}
|
|
|
|
|
|
alg->cra_module = THIS_MODULE;
|
|
|
- alg->cra_init = talitos_cra_init;
|
|
|
alg->cra_priority = TALITOS_CRA_PRIORITY;
|
|
|
alg->cra_alignmask = 0;
|
|
|
alg->cra_ctxsize = sizeof(struct talitos_ctx);
|