162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (c) 2010-2014, The Linux Foundation. All rights reserved. 462306a36Sopenharmony_ci */ 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci#include <linux/device.h> 762306a36Sopenharmony_ci#include <linux/dma-mapping.h> 862306a36Sopenharmony_ci#include <linux/interrupt.h> 962306a36Sopenharmony_ci#include <crypto/internal/hash.h> 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include "common.h" 1262306a36Sopenharmony_ci#include "core.h" 1362306a36Sopenharmony_ci#include "sha.h" 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_cistruct qce_sha_saved_state { 1662306a36Sopenharmony_ci u8 pending_buf[QCE_SHA_MAX_BLOCKSIZE]; 1762306a36Sopenharmony_ci u8 partial_digest[QCE_SHA_MAX_DIGESTSIZE]; 1862306a36Sopenharmony_ci __be32 byte_count[2]; 1962306a36Sopenharmony_ci unsigned int pending_buflen; 2062306a36Sopenharmony_ci unsigned int flags; 2162306a36Sopenharmony_ci u64 count; 2262306a36Sopenharmony_ci bool first_blk; 2362306a36Sopenharmony_ci}; 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_cistatic LIST_HEAD(ahash_algs); 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_cistatic const u32 std_iv_sha1[SHA256_DIGEST_SIZE / sizeof(u32)] = { 2862306a36Sopenharmony_ci SHA1_H0, SHA1_H1, SHA1_H2, SHA1_H3, SHA1_H4, 0, 0, 0 2962306a36Sopenharmony_ci}; 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_cistatic const u32 std_iv_sha256[SHA256_DIGEST_SIZE / sizeof(u32)] = { 3262306a36Sopenharmony_ci SHA256_H0, SHA256_H1, SHA256_H2, SHA256_H3, 3362306a36Sopenharmony_ci SHA256_H4, SHA256_H5, SHA256_H6, SHA256_H7 3462306a36Sopenharmony_ci}; 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_cistatic void qce_ahash_done(void *data) 3762306a36Sopenharmony_ci{ 3862306a36Sopenharmony_ci struct crypto_async_request *async_req = data; 3962306a36Sopenharmony_ci struct ahash_request *req = ahash_request_cast(async_req); 4062306a36Sopenharmony_ci struct crypto_ahash *ahash = crypto_ahash_reqtfm(req); 4162306a36Sopenharmony_ci struct qce_sha_reqctx *rctx = ahash_request_ctx_dma(req); 4262306a36Sopenharmony_ci struct qce_alg_template *tmpl = to_ahash_tmpl(async_req->tfm); 4362306a36Sopenharmony_ci struct qce_device *qce = tmpl->qce; 4462306a36Sopenharmony_ci struct qce_result_dump *result = qce->dma.result_buf; 4562306a36Sopenharmony_ci unsigned int digestsize = crypto_ahash_digestsize(ahash); 4662306a36Sopenharmony_ci int error; 4762306a36Sopenharmony_ci u32 status; 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci error = qce_dma_terminate_all(&qce->dma); 5062306a36Sopenharmony_ci if (error) 5162306a36Sopenharmony_ci dev_dbg(qce->dev, "ahash dma termination error (%d)\n", error); 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci dma_unmap_sg(qce->dev, req->src, rctx->src_nents, DMA_TO_DEVICE); 5462306a36Sopenharmony_ci dma_unmap_sg(qce->dev, &rctx->result_sg, 1, DMA_FROM_DEVICE); 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci memcpy(rctx->digest, result->auth_iv, digestsize); 5762306a36Sopenharmony_ci if (req->result && rctx->last_blk) 5862306a36Sopenharmony_ci memcpy(req->result, result->auth_iv, digestsize); 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci rctx->byte_count[0] = cpu_to_be32(result->auth_byte_count[0]); 6162306a36Sopenharmony_ci rctx->byte_count[1] = cpu_to_be32(result->auth_byte_count[1]); 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci error = qce_check_status(qce, &status); 6462306a36Sopenharmony_ci if (error < 0) 6562306a36Sopenharmony_ci dev_dbg(qce->dev, "ahash operation error (%x)\n", status); 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci req->src = rctx->src_orig; 6862306a36Sopenharmony_ci req->nbytes = rctx->nbytes_orig; 6962306a36Sopenharmony_ci rctx->last_blk = false; 7062306a36Sopenharmony_ci rctx->first_blk = false; 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci qce->async_req_done(tmpl->qce, error); 7362306a36Sopenharmony_ci} 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_cistatic int qce_ahash_async_req_handle(struct crypto_async_request *async_req) 7662306a36Sopenharmony_ci{ 7762306a36Sopenharmony_ci struct ahash_request *req = ahash_request_cast(async_req); 7862306a36Sopenharmony_ci struct qce_sha_reqctx *rctx = ahash_request_ctx_dma(req); 7962306a36Sopenharmony_ci struct qce_sha_ctx *ctx = crypto_tfm_ctx(async_req->tfm); 8062306a36Sopenharmony_ci struct qce_alg_template *tmpl = to_ahash_tmpl(async_req->tfm); 8162306a36Sopenharmony_ci struct qce_device *qce = tmpl->qce; 8262306a36Sopenharmony_ci unsigned long flags = rctx->flags; 8362306a36Sopenharmony_ci int ret; 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci if (IS_SHA_HMAC(flags)) { 8662306a36Sopenharmony_ci rctx->authkey = ctx->authkey; 8762306a36Sopenharmony_ci rctx->authklen = QCE_SHA_HMAC_KEY_SIZE; 8862306a36Sopenharmony_ci } else if (IS_CMAC(flags)) { 8962306a36Sopenharmony_ci rctx->authkey = ctx->authkey; 9062306a36Sopenharmony_ci rctx->authklen = AES_KEYSIZE_128; 9162306a36Sopenharmony_ci } 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci rctx->src_nents = sg_nents_for_len(req->src, req->nbytes); 9462306a36Sopenharmony_ci if (rctx->src_nents < 0) { 9562306a36Sopenharmony_ci dev_err(qce->dev, "Invalid numbers of src SG.\n"); 9662306a36Sopenharmony_ci return rctx->src_nents; 9762306a36Sopenharmony_ci } 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci ret = dma_map_sg(qce->dev, req->src, rctx->src_nents, DMA_TO_DEVICE); 10062306a36Sopenharmony_ci if (!ret) 10162306a36Sopenharmony_ci return -EIO; 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci sg_init_one(&rctx->result_sg, qce->dma.result_buf, QCE_RESULT_BUF_SZ); 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci ret = dma_map_sg(qce->dev, &rctx->result_sg, 1, DMA_FROM_DEVICE); 10662306a36Sopenharmony_ci if (!ret) { 10762306a36Sopenharmony_ci ret = -EIO; 10862306a36Sopenharmony_ci goto error_unmap_src; 10962306a36Sopenharmony_ci } 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci ret = qce_dma_prep_sgs(&qce->dma, req->src, rctx->src_nents, 11262306a36Sopenharmony_ci &rctx->result_sg, 1, qce_ahash_done, async_req); 11362306a36Sopenharmony_ci if (ret) 11462306a36Sopenharmony_ci goto error_unmap_dst; 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci qce_dma_issue_pending(&qce->dma); 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci ret = qce_start(async_req, tmpl->crypto_alg_type); 11962306a36Sopenharmony_ci if (ret) 12062306a36Sopenharmony_ci goto error_terminate; 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci return 0; 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_cierror_terminate: 12562306a36Sopenharmony_ci qce_dma_terminate_all(&qce->dma); 12662306a36Sopenharmony_cierror_unmap_dst: 12762306a36Sopenharmony_ci dma_unmap_sg(qce->dev, &rctx->result_sg, 1, DMA_FROM_DEVICE); 12862306a36Sopenharmony_cierror_unmap_src: 12962306a36Sopenharmony_ci dma_unmap_sg(qce->dev, req->src, rctx->src_nents, DMA_TO_DEVICE); 13062306a36Sopenharmony_ci return ret; 13162306a36Sopenharmony_ci} 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_cistatic int qce_ahash_init(struct ahash_request *req) 13462306a36Sopenharmony_ci{ 13562306a36Sopenharmony_ci struct qce_sha_reqctx *rctx = ahash_request_ctx_dma(req); 13662306a36Sopenharmony_ci struct qce_alg_template *tmpl = to_ahash_tmpl(req->base.tfm); 13762306a36Sopenharmony_ci const u32 *std_iv = tmpl->std_iv; 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci memset(rctx, 0, sizeof(*rctx)); 14062306a36Sopenharmony_ci rctx->first_blk = true; 14162306a36Sopenharmony_ci rctx->last_blk = false; 14262306a36Sopenharmony_ci rctx->flags = tmpl->alg_flags; 14362306a36Sopenharmony_ci memcpy(rctx->digest, std_iv, sizeof(rctx->digest)); 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci return 0; 14662306a36Sopenharmony_ci} 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_cistatic int qce_ahash_export(struct ahash_request *req, void *out) 14962306a36Sopenharmony_ci{ 15062306a36Sopenharmony_ci struct qce_sha_reqctx *rctx = ahash_request_ctx_dma(req); 15162306a36Sopenharmony_ci struct qce_sha_saved_state *export_state = out; 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci memcpy(export_state->pending_buf, rctx->buf, rctx->buflen); 15462306a36Sopenharmony_ci memcpy(export_state->partial_digest, rctx->digest, sizeof(rctx->digest)); 15562306a36Sopenharmony_ci export_state->byte_count[0] = rctx->byte_count[0]; 15662306a36Sopenharmony_ci export_state->byte_count[1] = rctx->byte_count[1]; 15762306a36Sopenharmony_ci export_state->pending_buflen = rctx->buflen; 15862306a36Sopenharmony_ci export_state->count = rctx->count; 15962306a36Sopenharmony_ci export_state->first_blk = rctx->first_blk; 16062306a36Sopenharmony_ci export_state->flags = rctx->flags; 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci return 0; 16362306a36Sopenharmony_ci} 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_cistatic int qce_ahash_import(struct ahash_request *req, const void *in) 16662306a36Sopenharmony_ci{ 16762306a36Sopenharmony_ci struct qce_sha_reqctx *rctx = ahash_request_ctx_dma(req); 16862306a36Sopenharmony_ci const struct qce_sha_saved_state *import_state = in; 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci memset(rctx, 0, sizeof(*rctx)); 17162306a36Sopenharmony_ci rctx->count = import_state->count; 17262306a36Sopenharmony_ci rctx->buflen = import_state->pending_buflen; 17362306a36Sopenharmony_ci rctx->first_blk = import_state->first_blk; 17462306a36Sopenharmony_ci rctx->flags = import_state->flags; 17562306a36Sopenharmony_ci rctx->byte_count[0] = import_state->byte_count[0]; 17662306a36Sopenharmony_ci rctx->byte_count[1] = import_state->byte_count[1]; 17762306a36Sopenharmony_ci memcpy(rctx->buf, import_state->pending_buf, rctx->buflen); 17862306a36Sopenharmony_ci memcpy(rctx->digest, import_state->partial_digest, sizeof(rctx->digest)); 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci return 0; 18162306a36Sopenharmony_ci} 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_cistatic int qce_ahash_update(struct ahash_request *req) 18462306a36Sopenharmony_ci{ 18562306a36Sopenharmony_ci struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); 18662306a36Sopenharmony_ci struct qce_sha_reqctx *rctx = ahash_request_ctx_dma(req); 18762306a36Sopenharmony_ci struct qce_alg_template *tmpl = to_ahash_tmpl(req->base.tfm); 18862306a36Sopenharmony_ci struct qce_device *qce = tmpl->qce; 18962306a36Sopenharmony_ci struct scatterlist *sg_last, *sg; 19062306a36Sopenharmony_ci unsigned int total, len; 19162306a36Sopenharmony_ci unsigned int hash_later; 19262306a36Sopenharmony_ci unsigned int nbytes; 19362306a36Sopenharmony_ci unsigned int blocksize; 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci blocksize = crypto_tfm_alg_blocksize(crypto_ahash_tfm(tfm)); 19662306a36Sopenharmony_ci rctx->count += req->nbytes; 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci /* check for buffer from previous updates and append it */ 19962306a36Sopenharmony_ci total = req->nbytes + rctx->buflen; 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci if (total <= blocksize) { 20262306a36Sopenharmony_ci scatterwalk_map_and_copy(rctx->buf + rctx->buflen, req->src, 20362306a36Sopenharmony_ci 0, req->nbytes, 0); 20462306a36Sopenharmony_ci rctx->buflen += req->nbytes; 20562306a36Sopenharmony_ci return 0; 20662306a36Sopenharmony_ci } 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci /* save the original req structure fields */ 20962306a36Sopenharmony_ci rctx->src_orig = req->src; 21062306a36Sopenharmony_ci rctx->nbytes_orig = req->nbytes; 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci /* 21362306a36Sopenharmony_ci * if we have data from previous update copy them on buffer. The old 21462306a36Sopenharmony_ci * data will be combined with current request bytes. 21562306a36Sopenharmony_ci */ 21662306a36Sopenharmony_ci if (rctx->buflen) 21762306a36Sopenharmony_ci memcpy(rctx->tmpbuf, rctx->buf, rctx->buflen); 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci /* calculate how many bytes will be hashed later */ 22062306a36Sopenharmony_ci hash_later = total % blocksize; 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci /* 22362306a36Sopenharmony_ci * At this point, there is more than one block size of data. If 22462306a36Sopenharmony_ci * the available data to transfer is exactly a multiple of block 22562306a36Sopenharmony_ci * size, save the last block to be transferred in qce_ahash_final 22662306a36Sopenharmony_ci * (with the last block bit set) if this is indeed the end of data 22762306a36Sopenharmony_ci * stream. If not this saved block will be transferred as part of 22862306a36Sopenharmony_ci * next update. If this block is not held back and if this is 22962306a36Sopenharmony_ci * indeed the end of data stream, the digest obtained will be wrong 23062306a36Sopenharmony_ci * since qce_ahash_final will see that rctx->buflen is 0 and return 23162306a36Sopenharmony_ci * doing nothing which in turn means that a digest will not be 23262306a36Sopenharmony_ci * copied to the destination result buffer. qce_ahash_final cannot 23362306a36Sopenharmony_ci * be made to alter this behavior and allowed to proceed if 23462306a36Sopenharmony_ci * rctx->buflen is 0 because the crypto engine BAM does not allow 23562306a36Sopenharmony_ci * for zero length transfers. 23662306a36Sopenharmony_ci */ 23762306a36Sopenharmony_ci if (!hash_later) 23862306a36Sopenharmony_ci hash_later = blocksize; 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci if (hash_later) { 24162306a36Sopenharmony_ci unsigned int src_offset = req->nbytes - hash_later; 24262306a36Sopenharmony_ci scatterwalk_map_and_copy(rctx->buf, req->src, src_offset, 24362306a36Sopenharmony_ci hash_later, 0); 24462306a36Sopenharmony_ci } 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci /* here nbytes is multiple of blocksize */ 24762306a36Sopenharmony_ci nbytes = total - hash_later; 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci len = rctx->buflen; 25062306a36Sopenharmony_ci sg = sg_last = req->src; 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci while (len < nbytes && sg) { 25362306a36Sopenharmony_ci if (len + sg_dma_len(sg) > nbytes) 25462306a36Sopenharmony_ci break; 25562306a36Sopenharmony_ci len += sg_dma_len(sg); 25662306a36Sopenharmony_ci sg_last = sg; 25762306a36Sopenharmony_ci sg = sg_next(sg); 25862306a36Sopenharmony_ci } 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci if (!sg_last) 26162306a36Sopenharmony_ci return -EINVAL; 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci if (rctx->buflen) { 26462306a36Sopenharmony_ci sg_init_table(rctx->sg, 2); 26562306a36Sopenharmony_ci sg_set_buf(rctx->sg, rctx->tmpbuf, rctx->buflen); 26662306a36Sopenharmony_ci sg_chain(rctx->sg, 2, req->src); 26762306a36Sopenharmony_ci req->src = rctx->sg; 26862306a36Sopenharmony_ci } 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci req->nbytes = nbytes; 27162306a36Sopenharmony_ci rctx->buflen = hash_later; 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci return qce->async_req_enqueue(tmpl->qce, &req->base); 27462306a36Sopenharmony_ci} 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_cistatic int qce_ahash_final(struct ahash_request *req) 27762306a36Sopenharmony_ci{ 27862306a36Sopenharmony_ci struct qce_sha_reqctx *rctx = ahash_request_ctx_dma(req); 27962306a36Sopenharmony_ci struct qce_alg_template *tmpl = to_ahash_tmpl(req->base.tfm); 28062306a36Sopenharmony_ci struct qce_device *qce = tmpl->qce; 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci if (!rctx->buflen) { 28362306a36Sopenharmony_ci if (tmpl->hash_zero) 28462306a36Sopenharmony_ci memcpy(req->result, tmpl->hash_zero, 28562306a36Sopenharmony_ci tmpl->alg.ahash.halg.digestsize); 28662306a36Sopenharmony_ci return 0; 28762306a36Sopenharmony_ci } 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci rctx->last_blk = true; 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci rctx->src_orig = req->src; 29262306a36Sopenharmony_ci rctx->nbytes_orig = req->nbytes; 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci memcpy(rctx->tmpbuf, rctx->buf, rctx->buflen); 29562306a36Sopenharmony_ci sg_init_one(rctx->sg, rctx->tmpbuf, rctx->buflen); 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci req->src = rctx->sg; 29862306a36Sopenharmony_ci req->nbytes = rctx->buflen; 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci return qce->async_req_enqueue(tmpl->qce, &req->base); 30162306a36Sopenharmony_ci} 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_cistatic int qce_ahash_digest(struct ahash_request *req) 30462306a36Sopenharmony_ci{ 30562306a36Sopenharmony_ci struct qce_sha_reqctx *rctx = ahash_request_ctx_dma(req); 30662306a36Sopenharmony_ci struct qce_alg_template *tmpl = to_ahash_tmpl(req->base.tfm); 30762306a36Sopenharmony_ci struct qce_device *qce = tmpl->qce; 30862306a36Sopenharmony_ci int ret; 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci ret = qce_ahash_init(req); 31162306a36Sopenharmony_ci if (ret) 31262306a36Sopenharmony_ci return ret; 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci rctx->src_orig = req->src; 31562306a36Sopenharmony_ci rctx->nbytes_orig = req->nbytes; 31662306a36Sopenharmony_ci rctx->first_blk = true; 31762306a36Sopenharmony_ci rctx->last_blk = true; 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci if (!rctx->nbytes_orig) { 32062306a36Sopenharmony_ci if (tmpl->hash_zero) 32162306a36Sopenharmony_ci memcpy(req->result, tmpl->hash_zero, 32262306a36Sopenharmony_ci tmpl->alg.ahash.halg.digestsize); 32362306a36Sopenharmony_ci return 0; 32462306a36Sopenharmony_ci } 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci return qce->async_req_enqueue(tmpl->qce, &req->base); 32762306a36Sopenharmony_ci} 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_cistatic int qce_ahash_hmac_setkey(struct crypto_ahash *tfm, const u8 *key, 33062306a36Sopenharmony_ci unsigned int keylen) 33162306a36Sopenharmony_ci{ 33262306a36Sopenharmony_ci unsigned int digestsize = crypto_ahash_digestsize(tfm); 33362306a36Sopenharmony_ci struct qce_sha_ctx *ctx = crypto_tfm_ctx(&tfm->base); 33462306a36Sopenharmony_ci struct crypto_wait wait; 33562306a36Sopenharmony_ci struct ahash_request *req; 33662306a36Sopenharmony_ci struct scatterlist sg; 33762306a36Sopenharmony_ci unsigned int blocksize; 33862306a36Sopenharmony_ci struct crypto_ahash *ahash_tfm; 33962306a36Sopenharmony_ci u8 *buf; 34062306a36Sopenharmony_ci int ret; 34162306a36Sopenharmony_ci const char *alg_name; 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci blocksize = crypto_tfm_alg_blocksize(crypto_ahash_tfm(tfm)); 34462306a36Sopenharmony_ci memset(ctx->authkey, 0, sizeof(ctx->authkey)); 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci if (keylen <= blocksize) { 34762306a36Sopenharmony_ci memcpy(ctx->authkey, key, keylen); 34862306a36Sopenharmony_ci return 0; 34962306a36Sopenharmony_ci } 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci if (digestsize == SHA1_DIGEST_SIZE) 35262306a36Sopenharmony_ci alg_name = "sha1-qce"; 35362306a36Sopenharmony_ci else if (digestsize == SHA256_DIGEST_SIZE) 35462306a36Sopenharmony_ci alg_name = "sha256-qce"; 35562306a36Sopenharmony_ci else 35662306a36Sopenharmony_ci return -EINVAL; 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci ahash_tfm = crypto_alloc_ahash(alg_name, 0, 0); 35962306a36Sopenharmony_ci if (IS_ERR(ahash_tfm)) 36062306a36Sopenharmony_ci return PTR_ERR(ahash_tfm); 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci req = ahash_request_alloc(ahash_tfm, GFP_KERNEL); 36362306a36Sopenharmony_ci if (!req) { 36462306a36Sopenharmony_ci ret = -ENOMEM; 36562306a36Sopenharmony_ci goto err_free_ahash; 36662306a36Sopenharmony_ci } 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci crypto_init_wait(&wait); 36962306a36Sopenharmony_ci ahash_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG, 37062306a36Sopenharmony_ci crypto_req_done, &wait); 37162306a36Sopenharmony_ci crypto_ahash_clear_flags(ahash_tfm, ~0); 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci buf = kzalloc(keylen + QCE_MAX_ALIGN_SIZE, GFP_KERNEL); 37462306a36Sopenharmony_ci if (!buf) { 37562306a36Sopenharmony_ci ret = -ENOMEM; 37662306a36Sopenharmony_ci goto err_free_req; 37762306a36Sopenharmony_ci } 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci memcpy(buf, key, keylen); 38062306a36Sopenharmony_ci sg_init_one(&sg, buf, keylen); 38162306a36Sopenharmony_ci ahash_request_set_crypt(req, &sg, ctx->authkey, keylen); 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci ret = crypto_wait_req(crypto_ahash_digest(req), &wait); 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci kfree(buf); 38662306a36Sopenharmony_cierr_free_req: 38762306a36Sopenharmony_ci ahash_request_free(req); 38862306a36Sopenharmony_cierr_free_ahash: 38962306a36Sopenharmony_ci crypto_free_ahash(ahash_tfm); 39062306a36Sopenharmony_ci return ret; 39162306a36Sopenharmony_ci} 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_cistatic int qce_ahash_cra_init(struct crypto_tfm *tfm) 39462306a36Sopenharmony_ci{ 39562306a36Sopenharmony_ci struct crypto_ahash *ahash = __crypto_ahash_cast(tfm); 39662306a36Sopenharmony_ci struct qce_sha_ctx *ctx = crypto_tfm_ctx(tfm); 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci crypto_ahash_set_reqsize_dma(ahash, sizeof(struct qce_sha_reqctx)); 39962306a36Sopenharmony_ci memset(ctx, 0, sizeof(*ctx)); 40062306a36Sopenharmony_ci return 0; 40162306a36Sopenharmony_ci} 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_cistruct qce_ahash_def { 40462306a36Sopenharmony_ci unsigned long flags; 40562306a36Sopenharmony_ci const char *name; 40662306a36Sopenharmony_ci const char *drv_name; 40762306a36Sopenharmony_ci unsigned int digestsize; 40862306a36Sopenharmony_ci unsigned int blocksize; 40962306a36Sopenharmony_ci unsigned int statesize; 41062306a36Sopenharmony_ci const u32 *std_iv; 41162306a36Sopenharmony_ci}; 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_cistatic const struct qce_ahash_def ahash_def[] = { 41462306a36Sopenharmony_ci { 41562306a36Sopenharmony_ci .flags = QCE_HASH_SHA1, 41662306a36Sopenharmony_ci .name = "sha1", 41762306a36Sopenharmony_ci .drv_name = "sha1-qce", 41862306a36Sopenharmony_ci .digestsize = SHA1_DIGEST_SIZE, 41962306a36Sopenharmony_ci .blocksize = SHA1_BLOCK_SIZE, 42062306a36Sopenharmony_ci .statesize = sizeof(struct qce_sha_saved_state), 42162306a36Sopenharmony_ci .std_iv = std_iv_sha1, 42262306a36Sopenharmony_ci }, 42362306a36Sopenharmony_ci { 42462306a36Sopenharmony_ci .flags = QCE_HASH_SHA256, 42562306a36Sopenharmony_ci .name = "sha256", 42662306a36Sopenharmony_ci .drv_name = "sha256-qce", 42762306a36Sopenharmony_ci .digestsize = SHA256_DIGEST_SIZE, 42862306a36Sopenharmony_ci .blocksize = SHA256_BLOCK_SIZE, 42962306a36Sopenharmony_ci .statesize = sizeof(struct qce_sha_saved_state), 43062306a36Sopenharmony_ci .std_iv = std_iv_sha256, 43162306a36Sopenharmony_ci }, 43262306a36Sopenharmony_ci { 43362306a36Sopenharmony_ci .flags = QCE_HASH_SHA1_HMAC, 43462306a36Sopenharmony_ci .name = "hmac(sha1)", 43562306a36Sopenharmony_ci .drv_name = "hmac-sha1-qce", 43662306a36Sopenharmony_ci .digestsize = SHA1_DIGEST_SIZE, 43762306a36Sopenharmony_ci .blocksize = SHA1_BLOCK_SIZE, 43862306a36Sopenharmony_ci .statesize = sizeof(struct qce_sha_saved_state), 43962306a36Sopenharmony_ci .std_iv = std_iv_sha1, 44062306a36Sopenharmony_ci }, 44162306a36Sopenharmony_ci { 44262306a36Sopenharmony_ci .flags = QCE_HASH_SHA256_HMAC, 44362306a36Sopenharmony_ci .name = "hmac(sha256)", 44462306a36Sopenharmony_ci .drv_name = "hmac-sha256-qce", 44562306a36Sopenharmony_ci .digestsize = SHA256_DIGEST_SIZE, 44662306a36Sopenharmony_ci .blocksize = SHA256_BLOCK_SIZE, 44762306a36Sopenharmony_ci .statesize = sizeof(struct qce_sha_saved_state), 44862306a36Sopenharmony_ci .std_iv = std_iv_sha256, 44962306a36Sopenharmony_ci }, 45062306a36Sopenharmony_ci}; 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_cistatic int qce_ahash_register_one(const struct qce_ahash_def *def, 45362306a36Sopenharmony_ci struct qce_device *qce) 45462306a36Sopenharmony_ci{ 45562306a36Sopenharmony_ci struct qce_alg_template *tmpl; 45662306a36Sopenharmony_ci struct ahash_alg *alg; 45762306a36Sopenharmony_ci struct crypto_alg *base; 45862306a36Sopenharmony_ci int ret; 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci tmpl = kzalloc(sizeof(*tmpl), GFP_KERNEL); 46162306a36Sopenharmony_ci if (!tmpl) 46262306a36Sopenharmony_ci return -ENOMEM; 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ci tmpl->std_iv = def->std_iv; 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci alg = &tmpl->alg.ahash; 46762306a36Sopenharmony_ci alg->init = qce_ahash_init; 46862306a36Sopenharmony_ci alg->update = qce_ahash_update; 46962306a36Sopenharmony_ci alg->final = qce_ahash_final; 47062306a36Sopenharmony_ci alg->digest = qce_ahash_digest; 47162306a36Sopenharmony_ci alg->export = qce_ahash_export; 47262306a36Sopenharmony_ci alg->import = qce_ahash_import; 47362306a36Sopenharmony_ci if (IS_SHA_HMAC(def->flags)) 47462306a36Sopenharmony_ci alg->setkey = qce_ahash_hmac_setkey; 47562306a36Sopenharmony_ci alg->halg.digestsize = def->digestsize; 47662306a36Sopenharmony_ci alg->halg.statesize = def->statesize; 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci if (IS_SHA1(def->flags)) 47962306a36Sopenharmony_ci tmpl->hash_zero = sha1_zero_message_hash; 48062306a36Sopenharmony_ci else if (IS_SHA256(def->flags)) 48162306a36Sopenharmony_ci tmpl->hash_zero = sha256_zero_message_hash; 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci base = &alg->halg.base; 48462306a36Sopenharmony_ci base->cra_blocksize = def->blocksize; 48562306a36Sopenharmony_ci base->cra_priority = 300; 48662306a36Sopenharmony_ci base->cra_flags = CRYPTO_ALG_ASYNC | CRYPTO_ALG_KERN_DRIVER_ONLY; 48762306a36Sopenharmony_ci base->cra_ctxsize = sizeof(struct qce_sha_ctx); 48862306a36Sopenharmony_ci base->cra_alignmask = 0; 48962306a36Sopenharmony_ci base->cra_module = THIS_MODULE; 49062306a36Sopenharmony_ci base->cra_init = qce_ahash_cra_init; 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci snprintf(base->cra_name, CRYPTO_MAX_ALG_NAME, "%s", def->name); 49362306a36Sopenharmony_ci snprintf(base->cra_driver_name, CRYPTO_MAX_ALG_NAME, "%s", 49462306a36Sopenharmony_ci def->drv_name); 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci INIT_LIST_HEAD(&tmpl->entry); 49762306a36Sopenharmony_ci tmpl->crypto_alg_type = CRYPTO_ALG_TYPE_AHASH; 49862306a36Sopenharmony_ci tmpl->alg_flags = def->flags; 49962306a36Sopenharmony_ci tmpl->qce = qce; 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci ret = crypto_register_ahash(alg); 50262306a36Sopenharmony_ci if (ret) { 50362306a36Sopenharmony_ci dev_err(qce->dev, "%s registration failed\n", base->cra_name); 50462306a36Sopenharmony_ci kfree(tmpl); 50562306a36Sopenharmony_ci return ret; 50662306a36Sopenharmony_ci } 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci list_add_tail(&tmpl->entry, &ahash_algs); 50962306a36Sopenharmony_ci dev_dbg(qce->dev, "%s is registered\n", base->cra_name); 51062306a36Sopenharmony_ci return 0; 51162306a36Sopenharmony_ci} 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_cistatic void qce_ahash_unregister(struct qce_device *qce) 51462306a36Sopenharmony_ci{ 51562306a36Sopenharmony_ci struct qce_alg_template *tmpl, *n; 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_ci list_for_each_entry_safe(tmpl, n, &ahash_algs, entry) { 51862306a36Sopenharmony_ci crypto_unregister_ahash(&tmpl->alg.ahash); 51962306a36Sopenharmony_ci list_del(&tmpl->entry); 52062306a36Sopenharmony_ci kfree(tmpl); 52162306a36Sopenharmony_ci } 52262306a36Sopenharmony_ci} 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_cistatic int qce_ahash_register(struct qce_device *qce) 52562306a36Sopenharmony_ci{ 52662306a36Sopenharmony_ci int ret, i; 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(ahash_def); i++) { 52962306a36Sopenharmony_ci ret = qce_ahash_register_one(&ahash_def[i], qce); 53062306a36Sopenharmony_ci if (ret) 53162306a36Sopenharmony_ci goto err; 53262306a36Sopenharmony_ci } 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci return 0; 53562306a36Sopenharmony_cierr: 53662306a36Sopenharmony_ci qce_ahash_unregister(qce); 53762306a36Sopenharmony_ci return ret; 53862306a36Sopenharmony_ci} 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_ciconst struct qce_algo_ops ahash_ops = { 54162306a36Sopenharmony_ci .type = CRYPTO_ALG_TYPE_AHASH, 54262306a36Sopenharmony_ci .register_algs = qce_ahash_register, 54362306a36Sopenharmony_ci .unregister_algs = qce_ahash_unregister, 54462306a36Sopenharmony_ci .async_req_handle = qce_ahash_async_req_handle, 54562306a36Sopenharmony_ci}; 546