18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Hash algorithms supported by the CESA: MD5, SHA1 and SHA256. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Author: Boris Brezillon <boris.brezillon@free-electrons.com> 68c2ecf20Sopenharmony_ci * Author: Arnaud Ebalard <arno@natisbad.org> 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * This work is based on an initial version written by 98c2ecf20Sopenharmony_ci * Sebastian Andrzej Siewior < sebastian at breakpoint dot cc > 108c2ecf20Sopenharmony_ci */ 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#include <crypto/hmac.h> 138c2ecf20Sopenharmony_ci#include <crypto/md5.h> 148c2ecf20Sopenharmony_ci#include <crypto/sha.h> 158c2ecf20Sopenharmony_ci#include <linux/device.h> 168c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h> 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#include "cesa.h" 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_cistruct mv_cesa_ahash_dma_iter { 218c2ecf20Sopenharmony_ci struct mv_cesa_dma_iter base; 228c2ecf20Sopenharmony_ci struct mv_cesa_sg_dma_iter src; 238c2ecf20Sopenharmony_ci}; 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_cistatic inline void 268c2ecf20Sopenharmony_cimv_cesa_ahash_req_iter_init(struct mv_cesa_ahash_dma_iter *iter, 278c2ecf20Sopenharmony_ci struct ahash_request *req) 288c2ecf20Sopenharmony_ci{ 298c2ecf20Sopenharmony_ci struct mv_cesa_ahash_req *creq = ahash_request_ctx(req); 308c2ecf20Sopenharmony_ci unsigned int len = req->nbytes + creq->cache_ptr; 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci if (!creq->last_req) 338c2ecf20Sopenharmony_ci len &= ~CESA_HASH_BLOCK_SIZE_MSK; 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci mv_cesa_req_dma_iter_init(&iter->base, len); 368c2ecf20Sopenharmony_ci mv_cesa_sg_dma_iter_init(&iter->src, req->src, DMA_TO_DEVICE); 378c2ecf20Sopenharmony_ci iter->src.op_offset = creq->cache_ptr; 388c2ecf20Sopenharmony_ci} 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_cistatic inline bool 418c2ecf20Sopenharmony_cimv_cesa_ahash_req_iter_next_op(struct mv_cesa_ahash_dma_iter *iter) 428c2ecf20Sopenharmony_ci{ 438c2ecf20Sopenharmony_ci iter->src.op_offset = 0; 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci return mv_cesa_req_dma_iter_next_op(&iter->base); 468c2ecf20Sopenharmony_ci} 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_cistatic inline int 498c2ecf20Sopenharmony_cimv_cesa_ahash_dma_alloc_cache(struct mv_cesa_ahash_dma_req *req, gfp_t flags) 508c2ecf20Sopenharmony_ci{ 518c2ecf20Sopenharmony_ci req->cache = dma_pool_alloc(cesa_dev->dma->cache_pool, flags, 528c2ecf20Sopenharmony_ci &req->cache_dma); 538c2ecf20Sopenharmony_ci if (!req->cache) 548c2ecf20Sopenharmony_ci return -ENOMEM; 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci return 0; 578c2ecf20Sopenharmony_ci} 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_cistatic inline void 608c2ecf20Sopenharmony_cimv_cesa_ahash_dma_free_cache(struct mv_cesa_ahash_dma_req *req) 618c2ecf20Sopenharmony_ci{ 628c2ecf20Sopenharmony_ci if (!req->cache) 638c2ecf20Sopenharmony_ci return; 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci dma_pool_free(cesa_dev->dma->cache_pool, req->cache, 668c2ecf20Sopenharmony_ci req->cache_dma); 678c2ecf20Sopenharmony_ci} 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_cistatic int mv_cesa_ahash_dma_alloc_padding(struct mv_cesa_ahash_dma_req *req, 708c2ecf20Sopenharmony_ci gfp_t flags) 718c2ecf20Sopenharmony_ci{ 728c2ecf20Sopenharmony_ci if (req->padding) 738c2ecf20Sopenharmony_ci return 0; 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci req->padding = dma_pool_alloc(cesa_dev->dma->padding_pool, flags, 768c2ecf20Sopenharmony_ci &req->padding_dma); 778c2ecf20Sopenharmony_ci if (!req->padding) 788c2ecf20Sopenharmony_ci return -ENOMEM; 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci return 0; 818c2ecf20Sopenharmony_ci} 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_cistatic void mv_cesa_ahash_dma_free_padding(struct mv_cesa_ahash_dma_req *req) 848c2ecf20Sopenharmony_ci{ 858c2ecf20Sopenharmony_ci if (!req->padding) 868c2ecf20Sopenharmony_ci return; 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci dma_pool_free(cesa_dev->dma->padding_pool, req->padding, 898c2ecf20Sopenharmony_ci req->padding_dma); 908c2ecf20Sopenharmony_ci req->padding = NULL; 918c2ecf20Sopenharmony_ci} 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_cistatic inline void mv_cesa_ahash_dma_last_cleanup(struct ahash_request *req) 948c2ecf20Sopenharmony_ci{ 958c2ecf20Sopenharmony_ci struct mv_cesa_ahash_req *creq = ahash_request_ctx(req); 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci mv_cesa_ahash_dma_free_padding(&creq->req.dma); 988c2ecf20Sopenharmony_ci} 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_cistatic inline void mv_cesa_ahash_dma_cleanup(struct ahash_request *req) 1018c2ecf20Sopenharmony_ci{ 1028c2ecf20Sopenharmony_ci struct mv_cesa_ahash_req *creq = ahash_request_ctx(req); 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci dma_unmap_sg(cesa_dev->dev, req->src, creq->src_nents, DMA_TO_DEVICE); 1058c2ecf20Sopenharmony_ci mv_cesa_ahash_dma_free_cache(&creq->req.dma); 1068c2ecf20Sopenharmony_ci mv_cesa_dma_cleanup(&creq->base); 1078c2ecf20Sopenharmony_ci} 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_cistatic inline void mv_cesa_ahash_cleanup(struct ahash_request *req) 1108c2ecf20Sopenharmony_ci{ 1118c2ecf20Sopenharmony_ci struct mv_cesa_ahash_req *creq = ahash_request_ctx(req); 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci if (mv_cesa_req_get_type(&creq->base) == CESA_DMA_REQ) 1148c2ecf20Sopenharmony_ci mv_cesa_ahash_dma_cleanup(req); 1158c2ecf20Sopenharmony_ci} 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_cistatic void mv_cesa_ahash_last_cleanup(struct ahash_request *req) 1188c2ecf20Sopenharmony_ci{ 1198c2ecf20Sopenharmony_ci struct mv_cesa_ahash_req *creq = ahash_request_ctx(req); 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci if (mv_cesa_req_get_type(&creq->base) == CESA_DMA_REQ) 1228c2ecf20Sopenharmony_ci mv_cesa_ahash_dma_last_cleanup(req); 1238c2ecf20Sopenharmony_ci} 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_cistatic int mv_cesa_ahash_pad_len(struct mv_cesa_ahash_req *creq) 1268c2ecf20Sopenharmony_ci{ 1278c2ecf20Sopenharmony_ci unsigned int index, padlen; 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci index = creq->len & CESA_HASH_BLOCK_SIZE_MSK; 1308c2ecf20Sopenharmony_ci padlen = (index < 56) ? (56 - index) : (64 + 56 - index); 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci return padlen; 1338c2ecf20Sopenharmony_ci} 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_cistatic int mv_cesa_ahash_pad_req(struct mv_cesa_ahash_req *creq, u8 *buf) 1368c2ecf20Sopenharmony_ci{ 1378c2ecf20Sopenharmony_ci unsigned int padlen; 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci buf[0] = 0x80; 1408c2ecf20Sopenharmony_ci /* Pad out to 56 mod 64 */ 1418c2ecf20Sopenharmony_ci padlen = mv_cesa_ahash_pad_len(creq); 1428c2ecf20Sopenharmony_ci memset(buf + 1, 0, padlen - 1); 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci if (creq->algo_le) { 1458c2ecf20Sopenharmony_ci __le64 bits = cpu_to_le64(creq->len << 3); 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci memcpy(buf + padlen, &bits, sizeof(bits)); 1488c2ecf20Sopenharmony_ci } else { 1498c2ecf20Sopenharmony_ci __be64 bits = cpu_to_be64(creq->len << 3); 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci memcpy(buf + padlen, &bits, sizeof(bits)); 1528c2ecf20Sopenharmony_ci } 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci return padlen + 8; 1558c2ecf20Sopenharmony_ci} 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_cistatic void mv_cesa_ahash_std_step(struct ahash_request *req) 1588c2ecf20Sopenharmony_ci{ 1598c2ecf20Sopenharmony_ci struct mv_cesa_ahash_req *creq = ahash_request_ctx(req); 1608c2ecf20Sopenharmony_ci struct mv_cesa_ahash_std_req *sreq = &creq->req.std; 1618c2ecf20Sopenharmony_ci struct mv_cesa_engine *engine = creq->base.engine; 1628c2ecf20Sopenharmony_ci struct mv_cesa_op_ctx *op; 1638c2ecf20Sopenharmony_ci unsigned int new_cache_ptr = 0; 1648c2ecf20Sopenharmony_ci u32 frag_mode; 1658c2ecf20Sopenharmony_ci size_t len; 1668c2ecf20Sopenharmony_ci unsigned int digsize; 1678c2ecf20Sopenharmony_ci int i; 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci mv_cesa_adjust_op(engine, &creq->op_tmpl); 1708c2ecf20Sopenharmony_ci memcpy_toio(engine->sram, &creq->op_tmpl, sizeof(creq->op_tmpl)); 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci if (!sreq->offset) { 1738c2ecf20Sopenharmony_ci digsize = crypto_ahash_digestsize(crypto_ahash_reqtfm(req)); 1748c2ecf20Sopenharmony_ci for (i = 0; i < digsize / 4; i++) 1758c2ecf20Sopenharmony_ci writel_relaxed(creq->state[i], 1768c2ecf20Sopenharmony_ci engine->regs + CESA_IVDIG(i)); 1778c2ecf20Sopenharmony_ci } 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci if (creq->cache_ptr) 1808c2ecf20Sopenharmony_ci memcpy_toio(engine->sram + CESA_SA_DATA_SRAM_OFFSET, 1818c2ecf20Sopenharmony_ci creq->cache, creq->cache_ptr); 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci len = min_t(size_t, req->nbytes + creq->cache_ptr - sreq->offset, 1848c2ecf20Sopenharmony_ci CESA_SA_SRAM_PAYLOAD_SIZE); 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci if (!creq->last_req) { 1878c2ecf20Sopenharmony_ci new_cache_ptr = len & CESA_HASH_BLOCK_SIZE_MSK; 1888c2ecf20Sopenharmony_ci len &= ~CESA_HASH_BLOCK_SIZE_MSK; 1898c2ecf20Sopenharmony_ci } 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci if (len - creq->cache_ptr) 1928c2ecf20Sopenharmony_ci sreq->offset += sg_pcopy_to_buffer(req->src, creq->src_nents, 1938c2ecf20Sopenharmony_ci engine->sram + 1948c2ecf20Sopenharmony_ci CESA_SA_DATA_SRAM_OFFSET + 1958c2ecf20Sopenharmony_ci creq->cache_ptr, 1968c2ecf20Sopenharmony_ci len - creq->cache_ptr, 1978c2ecf20Sopenharmony_ci sreq->offset); 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci op = &creq->op_tmpl; 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci frag_mode = mv_cesa_get_op_cfg(op) & CESA_SA_DESC_CFG_FRAG_MSK; 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci if (creq->last_req && sreq->offset == req->nbytes && 2048c2ecf20Sopenharmony_ci creq->len <= CESA_SA_DESC_MAC_SRC_TOTAL_LEN_MAX) { 2058c2ecf20Sopenharmony_ci if (frag_mode == CESA_SA_DESC_CFG_FIRST_FRAG) 2068c2ecf20Sopenharmony_ci frag_mode = CESA_SA_DESC_CFG_NOT_FRAG; 2078c2ecf20Sopenharmony_ci else if (frag_mode == CESA_SA_DESC_CFG_MID_FRAG) 2088c2ecf20Sopenharmony_ci frag_mode = CESA_SA_DESC_CFG_LAST_FRAG; 2098c2ecf20Sopenharmony_ci } 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci if (frag_mode == CESA_SA_DESC_CFG_NOT_FRAG || 2128c2ecf20Sopenharmony_ci frag_mode == CESA_SA_DESC_CFG_LAST_FRAG) { 2138c2ecf20Sopenharmony_ci if (len && 2148c2ecf20Sopenharmony_ci creq->len <= CESA_SA_DESC_MAC_SRC_TOTAL_LEN_MAX) { 2158c2ecf20Sopenharmony_ci mv_cesa_set_mac_op_total_len(op, creq->len); 2168c2ecf20Sopenharmony_ci } else { 2178c2ecf20Sopenharmony_ci int trailerlen = mv_cesa_ahash_pad_len(creq) + 8; 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci if (len + trailerlen > CESA_SA_SRAM_PAYLOAD_SIZE) { 2208c2ecf20Sopenharmony_ci len &= CESA_HASH_BLOCK_SIZE_MSK; 2218c2ecf20Sopenharmony_ci new_cache_ptr = 64 - trailerlen; 2228c2ecf20Sopenharmony_ci memcpy_fromio(creq->cache, 2238c2ecf20Sopenharmony_ci engine->sram + 2248c2ecf20Sopenharmony_ci CESA_SA_DATA_SRAM_OFFSET + len, 2258c2ecf20Sopenharmony_ci new_cache_ptr); 2268c2ecf20Sopenharmony_ci } else { 2278c2ecf20Sopenharmony_ci i = mv_cesa_ahash_pad_req(creq, creq->cache); 2288c2ecf20Sopenharmony_ci len += i; 2298c2ecf20Sopenharmony_ci memcpy_toio(engine->sram + len + 2308c2ecf20Sopenharmony_ci CESA_SA_DATA_SRAM_OFFSET, 2318c2ecf20Sopenharmony_ci creq->cache, i); 2328c2ecf20Sopenharmony_ci } 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci if (frag_mode == CESA_SA_DESC_CFG_LAST_FRAG) 2358c2ecf20Sopenharmony_ci frag_mode = CESA_SA_DESC_CFG_MID_FRAG; 2368c2ecf20Sopenharmony_ci else 2378c2ecf20Sopenharmony_ci frag_mode = CESA_SA_DESC_CFG_FIRST_FRAG; 2388c2ecf20Sopenharmony_ci } 2398c2ecf20Sopenharmony_ci } 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci mv_cesa_set_mac_op_frag_len(op, len); 2428c2ecf20Sopenharmony_ci mv_cesa_update_op_cfg(op, frag_mode, CESA_SA_DESC_CFG_FRAG_MSK); 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci /* FIXME: only update enc_len field */ 2458c2ecf20Sopenharmony_ci memcpy_toio(engine->sram, op, sizeof(*op)); 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci if (frag_mode == CESA_SA_DESC_CFG_FIRST_FRAG) 2488c2ecf20Sopenharmony_ci mv_cesa_update_op_cfg(op, CESA_SA_DESC_CFG_MID_FRAG, 2498c2ecf20Sopenharmony_ci CESA_SA_DESC_CFG_FRAG_MSK); 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci creq->cache_ptr = new_cache_ptr; 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci mv_cesa_set_int_mask(engine, CESA_SA_INT_ACCEL0_DONE); 2548c2ecf20Sopenharmony_ci writel_relaxed(CESA_SA_CFG_PARA_DIS, engine->regs + CESA_SA_CFG); 2558c2ecf20Sopenharmony_ci WARN_ON(readl(engine->regs + CESA_SA_CMD) & 2568c2ecf20Sopenharmony_ci CESA_SA_CMD_EN_CESA_SA_ACCL0); 2578c2ecf20Sopenharmony_ci writel(CESA_SA_CMD_EN_CESA_SA_ACCL0, engine->regs + CESA_SA_CMD); 2588c2ecf20Sopenharmony_ci} 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_cistatic int mv_cesa_ahash_std_process(struct ahash_request *req, u32 status) 2618c2ecf20Sopenharmony_ci{ 2628c2ecf20Sopenharmony_ci struct mv_cesa_ahash_req *creq = ahash_request_ctx(req); 2638c2ecf20Sopenharmony_ci struct mv_cesa_ahash_std_req *sreq = &creq->req.std; 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci if (sreq->offset < (req->nbytes - creq->cache_ptr)) 2668c2ecf20Sopenharmony_ci return -EINPROGRESS; 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci return 0; 2698c2ecf20Sopenharmony_ci} 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_cistatic inline void mv_cesa_ahash_dma_prepare(struct ahash_request *req) 2728c2ecf20Sopenharmony_ci{ 2738c2ecf20Sopenharmony_ci struct mv_cesa_ahash_req *creq = ahash_request_ctx(req); 2748c2ecf20Sopenharmony_ci struct mv_cesa_req *basereq = &creq->base; 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci mv_cesa_dma_prepare(basereq, basereq->engine); 2778c2ecf20Sopenharmony_ci} 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_cistatic void mv_cesa_ahash_std_prepare(struct ahash_request *req) 2808c2ecf20Sopenharmony_ci{ 2818c2ecf20Sopenharmony_ci struct mv_cesa_ahash_req *creq = ahash_request_ctx(req); 2828c2ecf20Sopenharmony_ci struct mv_cesa_ahash_std_req *sreq = &creq->req.std; 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci sreq->offset = 0; 2858c2ecf20Sopenharmony_ci} 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_cistatic void mv_cesa_ahash_dma_step(struct ahash_request *req) 2888c2ecf20Sopenharmony_ci{ 2898c2ecf20Sopenharmony_ci struct mv_cesa_ahash_req *creq = ahash_request_ctx(req); 2908c2ecf20Sopenharmony_ci struct mv_cesa_req *base = &creq->base; 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci /* We must explicitly set the digest state. */ 2938c2ecf20Sopenharmony_ci if (base->chain.first->flags & CESA_TDMA_SET_STATE) { 2948c2ecf20Sopenharmony_ci struct mv_cesa_engine *engine = base->engine; 2958c2ecf20Sopenharmony_ci int i; 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci /* Set the hash state in the IVDIG regs. */ 2988c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(creq->state); i++) 2998c2ecf20Sopenharmony_ci writel_relaxed(creq->state[i], engine->regs + 3008c2ecf20Sopenharmony_ci CESA_IVDIG(i)); 3018c2ecf20Sopenharmony_ci } 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci mv_cesa_dma_step(base); 3048c2ecf20Sopenharmony_ci} 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_cistatic void mv_cesa_ahash_step(struct crypto_async_request *req) 3078c2ecf20Sopenharmony_ci{ 3088c2ecf20Sopenharmony_ci struct ahash_request *ahashreq = ahash_request_cast(req); 3098c2ecf20Sopenharmony_ci struct mv_cesa_ahash_req *creq = ahash_request_ctx(ahashreq); 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci if (mv_cesa_req_get_type(&creq->base) == CESA_DMA_REQ) 3128c2ecf20Sopenharmony_ci mv_cesa_ahash_dma_step(ahashreq); 3138c2ecf20Sopenharmony_ci else 3148c2ecf20Sopenharmony_ci mv_cesa_ahash_std_step(ahashreq); 3158c2ecf20Sopenharmony_ci} 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_cistatic int mv_cesa_ahash_process(struct crypto_async_request *req, u32 status) 3188c2ecf20Sopenharmony_ci{ 3198c2ecf20Sopenharmony_ci struct ahash_request *ahashreq = ahash_request_cast(req); 3208c2ecf20Sopenharmony_ci struct mv_cesa_ahash_req *creq = ahash_request_ctx(ahashreq); 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci if (mv_cesa_req_get_type(&creq->base) == CESA_DMA_REQ) 3238c2ecf20Sopenharmony_ci return mv_cesa_dma_process(&creq->base, status); 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci return mv_cesa_ahash_std_process(ahashreq, status); 3268c2ecf20Sopenharmony_ci} 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_cistatic void mv_cesa_ahash_complete(struct crypto_async_request *req) 3298c2ecf20Sopenharmony_ci{ 3308c2ecf20Sopenharmony_ci struct ahash_request *ahashreq = ahash_request_cast(req); 3318c2ecf20Sopenharmony_ci struct mv_cesa_ahash_req *creq = ahash_request_ctx(ahashreq); 3328c2ecf20Sopenharmony_ci struct mv_cesa_engine *engine = creq->base.engine; 3338c2ecf20Sopenharmony_ci unsigned int digsize; 3348c2ecf20Sopenharmony_ci int i; 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci digsize = crypto_ahash_digestsize(crypto_ahash_reqtfm(ahashreq)); 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci if (mv_cesa_req_get_type(&creq->base) == CESA_DMA_REQ && 3398c2ecf20Sopenharmony_ci (creq->base.chain.last->flags & CESA_TDMA_TYPE_MSK) == 3408c2ecf20Sopenharmony_ci CESA_TDMA_RESULT) { 3418c2ecf20Sopenharmony_ci __le32 *data = NULL; 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci /* 3448c2ecf20Sopenharmony_ci * Result is already in the correct endianness when the SA is 3458c2ecf20Sopenharmony_ci * used 3468c2ecf20Sopenharmony_ci */ 3478c2ecf20Sopenharmony_ci data = creq->base.chain.last->op->ctx.hash.hash; 3488c2ecf20Sopenharmony_ci for (i = 0; i < digsize / 4; i++) 3498c2ecf20Sopenharmony_ci creq->state[i] = le32_to_cpu(data[i]); 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci memcpy(ahashreq->result, data, digsize); 3528c2ecf20Sopenharmony_ci } else { 3538c2ecf20Sopenharmony_ci for (i = 0; i < digsize / 4; i++) 3548c2ecf20Sopenharmony_ci creq->state[i] = readl_relaxed(engine->regs + 3558c2ecf20Sopenharmony_ci CESA_IVDIG(i)); 3568c2ecf20Sopenharmony_ci if (creq->last_req) { 3578c2ecf20Sopenharmony_ci /* 3588c2ecf20Sopenharmony_ci * Hardware's MD5 digest is in little endian format, but 3598c2ecf20Sopenharmony_ci * SHA in big endian format 3608c2ecf20Sopenharmony_ci */ 3618c2ecf20Sopenharmony_ci if (creq->algo_le) { 3628c2ecf20Sopenharmony_ci __le32 *result = (void *)ahashreq->result; 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci for (i = 0; i < digsize / 4; i++) 3658c2ecf20Sopenharmony_ci result[i] = cpu_to_le32(creq->state[i]); 3668c2ecf20Sopenharmony_ci } else { 3678c2ecf20Sopenharmony_ci __be32 *result = (void *)ahashreq->result; 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci for (i = 0; i < digsize / 4; i++) 3708c2ecf20Sopenharmony_ci result[i] = cpu_to_be32(creq->state[i]); 3718c2ecf20Sopenharmony_ci } 3728c2ecf20Sopenharmony_ci } 3738c2ecf20Sopenharmony_ci } 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci atomic_sub(ahashreq->nbytes, &engine->load); 3768c2ecf20Sopenharmony_ci} 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_cistatic void mv_cesa_ahash_prepare(struct crypto_async_request *req, 3798c2ecf20Sopenharmony_ci struct mv_cesa_engine *engine) 3808c2ecf20Sopenharmony_ci{ 3818c2ecf20Sopenharmony_ci struct ahash_request *ahashreq = ahash_request_cast(req); 3828c2ecf20Sopenharmony_ci struct mv_cesa_ahash_req *creq = ahash_request_ctx(ahashreq); 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci creq->base.engine = engine; 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci if (mv_cesa_req_get_type(&creq->base) == CESA_DMA_REQ) 3878c2ecf20Sopenharmony_ci mv_cesa_ahash_dma_prepare(ahashreq); 3888c2ecf20Sopenharmony_ci else 3898c2ecf20Sopenharmony_ci mv_cesa_ahash_std_prepare(ahashreq); 3908c2ecf20Sopenharmony_ci} 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_cistatic void mv_cesa_ahash_req_cleanup(struct crypto_async_request *req) 3938c2ecf20Sopenharmony_ci{ 3948c2ecf20Sopenharmony_ci struct ahash_request *ahashreq = ahash_request_cast(req); 3958c2ecf20Sopenharmony_ci struct mv_cesa_ahash_req *creq = ahash_request_ctx(ahashreq); 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci if (creq->last_req) 3988c2ecf20Sopenharmony_ci mv_cesa_ahash_last_cleanup(ahashreq); 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci mv_cesa_ahash_cleanup(ahashreq); 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci if (creq->cache_ptr) 4038c2ecf20Sopenharmony_ci sg_pcopy_to_buffer(ahashreq->src, creq->src_nents, 4048c2ecf20Sopenharmony_ci creq->cache, 4058c2ecf20Sopenharmony_ci creq->cache_ptr, 4068c2ecf20Sopenharmony_ci ahashreq->nbytes - creq->cache_ptr); 4078c2ecf20Sopenharmony_ci} 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_cistatic const struct mv_cesa_req_ops mv_cesa_ahash_req_ops = { 4108c2ecf20Sopenharmony_ci .step = mv_cesa_ahash_step, 4118c2ecf20Sopenharmony_ci .process = mv_cesa_ahash_process, 4128c2ecf20Sopenharmony_ci .cleanup = mv_cesa_ahash_req_cleanup, 4138c2ecf20Sopenharmony_ci .complete = mv_cesa_ahash_complete, 4148c2ecf20Sopenharmony_ci}; 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_cistatic void mv_cesa_ahash_init(struct ahash_request *req, 4178c2ecf20Sopenharmony_ci struct mv_cesa_op_ctx *tmpl, bool algo_le) 4188c2ecf20Sopenharmony_ci{ 4198c2ecf20Sopenharmony_ci struct mv_cesa_ahash_req *creq = ahash_request_ctx(req); 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci memset(creq, 0, sizeof(*creq)); 4228c2ecf20Sopenharmony_ci mv_cesa_update_op_cfg(tmpl, 4238c2ecf20Sopenharmony_ci CESA_SA_DESC_CFG_OP_MAC_ONLY | 4248c2ecf20Sopenharmony_ci CESA_SA_DESC_CFG_FIRST_FRAG, 4258c2ecf20Sopenharmony_ci CESA_SA_DESC_CFG_OP_MSK | 4268c2ecf20Sopenharmony_ci CESA_SA_DESC_CFG_FRAG_MSK); 4278c2ecf20Sopenharmony_ci mv_cesa_set_mac_op_total_len(tmpl, 0); 4288c2ecf20Sopenharmony_ci mv_cesa_set_mac_op_frag_len(tmpl, 0); 4298c2ecf20Sopenharmony_ci creq->op_tmpl = *tmpl; 4308c2ecf20Sopenharmony_ci creq->len = 0; 4318c2ecf20Sopenharmony_ci creq->algo_le = algo_le; 4328c2ecf20Sopenharmony_ci} 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_cistatic inline int mv_cesa_ahash_cra_init(struct crypto_tfm *tfm) 4358c2ecf20Sopenharmony_ci{ 4368c2ecf20Sopenharmony_ci struct mv_cesa_hash_ctx *ctx = crypto_tfm_ctx(tfm); 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci ctx->base.ops = &mv_cesa_ahash_req_ops; 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm), 4418c2ecf20Sopenharmony_ci sizeof(struct mv_cesa_ahash_req)); 4428c2ecf20Sopenharmony_ci return 0; 4438c2ecf20Sopenharmony_ci} 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_cistatic bool mv_cesa_ahash_cache_req(struct ahash_request *req) 4468c2ecf20Sopenharmony_ci{ 4478c2ecf20Sopenharmony_ci struct mv_cesa_ahash_req *creq = ahash_request_ctx(req); 4488c2ecf20Sopenharmony_ci bool cached = false; 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ci if (creq->cache_ptr + req->nbytes < CESA_MAX_HASH_BLOCK_SIZE && 4518c2ecf20Sopenharmony_ci !creq->last_req) { 4528c2ecf20Sopenharmony_ci cached = true; 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci if (!req->nbytes) 4558c2ecf20Sopenharmony_ci return cached; 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci sg_pcopy_to_buffer(req->src, creq->src_nents, 4588c2ecf20Sopenharmony_ci creq->cache + creq->cache_ptr, 4598c2ecf20Sopenharmony_ci req->nbytes, 0); 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci creq->cache_ptr += req->nbytes; 4628c2ecf20Sopenharmony_ci } 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci return cached; 4658c2ecf20Sopenharmony_ci} 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_cistatic struct mv_cesa_op_ctx * 4688c2ecf20Sopenharmony_cimv_cesa_dma_add_frag(struct mv_cesa_tdma_chain *chain, 4698c2ecf20Sopenharmony_ci struct mv_cesa_op_ctx *tmpl, unsigned int frag_len, 4708c2ecf20Sopenharmony_ci gfp_t flags) 4718c2ecf20Sopenharmony_ci{ 4728c2ecf20Sopenharmony_ci struct mv_cesa_op_ctx *op; 4738c2ecf20Sopenharmony_ci int ret; 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci op = mv_cesa_dma_add_op(chain, tmpl, false, flags); 4768c2ecf20Sopenharmony_ci if (IS_ERR(op)) 4778c2ecf20Sopenharmony_ci return op; 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci /* Set the operation block fragment length. */ 4808c2ecf20Sopenharmony_ci mv_cesa_set_mac_op_frag_len(op, frag_len); 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_ci /* Append dummy desc to launch operation */ 4838c2ecf20Sopenharmony_ci ret = mv_cesa_dma_add_dummy_launch(chain, flags); 4848c2ecf20Sopenharmony_ci if (ret) 4858c2ecf20Sopenharmony_ci return ERR_PTR(ret); 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci if (mv_cesa_mac_op_is_first_frag(tmpl)) 4888c2ecf20Sopenharmony_ci mv_cesa_update_op_cfg(tmpl, 4898c2ecf20Sopenharmony_ci CESA_SA_DESC_CFG_MID_FRAG, 4908c2ecf20Sopenharmony_ci CESA_SA_DESC_CFG_FRAG_MSK); 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci return op; 4938c2ecf20Sopenharmony_ci} 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_cistatic int 4968c2ecf20Sopenharmony_cimv_cesa_ahash_dma_add_cache(struct mv_cesa_tdma_chain *chain, 4978c2ecf20Sopenharmony_ci struct mv_cesa_ahash_req *creq, 4988c2ecf20Sopenharmony_ci gfp_t flags) 4998c2ecf20Sopenharmony_ci{ 5008c2ecf20Sopenharmony_ci struct mv_cesa_ahash_dma_req *ahashdreq = &creq->req.dma; 5018c2ecf20Sopenharmony_ci int ret; 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ci if (!creq->cache_ptr) 5048c2ecf20Sopenharmony_ci return 0; 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_ci ret = mv_cesa_ahash_dma_alloc_cache(ahashdreq, flags); 5078c2ecf20Sopenharmony_ci if (ret) 5088c2ecf20Sopenharmony_ci return ret; 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_ci memcpy(ahashdreq->cache, creq->cache, creq->cache_ptr); 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_ci return mv_cesa_dma_add_data_transfer(chain, 5138c2ecf20Sopenharmony_ci CESA_SA_DATA_SRAM_OFFSET, 5148c2ecf20Sopenharmony_ci ahashdreq->cache_dma, 5158c2ecf20Sopenharmony_ci creq->cache_ptr, 5168c2ecf20Sopenharmony_ci CESA_TDMA_DST_IN_SRAM, 5178c2ecf20Sopenharmony_ci flags); 5188c2ecf20Sopenharmony_ci} 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_cistatic struct mv_cesa_op_ctx * 5218c2ecf20Sopenharmony_cimv_cesa_ahash_dma_last_req(struct mv_cesa_tdma_chain *chain, 5228c2ecf20Sopenharmony_ci struct mv_cesa_ahash_dma_iter *dma_iter, 5238c2ecf20Sopenharmony_ci struct mv_cesa_ahash_req *creq, 5248c2ecf20Sopenharmony_ci unsigned int frag_len, gfp_t flags) 5258c2ecf20Sopenharmony_ci{ 5268c2ecf20Sopenharmony_ci struct mv_cesa_ahash_dma_req *ahashdreq = &creq->req.dma; 5278c2ecf20Sopenharmony_ci unsigned int len, trailerlen, padoff = 0; 5288c2ecf20Sopenharmony_ci struct mv_cesa_op_ctx *op; 5298c2ecf20Sopenharmony_ci int ret; 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci /* 5328c2ecf20Sopenharmony_ci * If the transfer is smaller than our maximum length, and we have 5338c2ecf20Sopenharmony_ci * some data outstanding, we can ask the engine to finish the hash. 5348c2ecf20Sopenharmony_ci */ 5358c2ecf20Sopenharmony_ci if (creq->len <= CESA_SA_DESC_MAC_SRC_TOTAL_LEN_MAX && frag_len) { 5368c2ecf20Sopenharmony_ci op = mv_cesa_dma_add_frag(chain, &creq->op_tmpl, frag_len, 5378c2ecf20Sopenharmony_ci flags); 5388c2ecf20Sopenharmony_ci if (IS_ERR(op)) 5398c2ecf20Sopenharmony_ci return op; 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_ci mv_cesa_set_mac_op_total_len(op, creq->len); 5428c2ecf20Sopenharmony_ci mv_cesa_update_op_cfg(op, mv_cesa_mac_op_is_first_frag(op) ? 5438c2ecf20Sopenharmony_ci CESA_SA_DESC_CFG_NOT_FRAG : 5448c2ecf20Sopenharmony_ci CESA_SA_DESC_CFG_LAST_FRAG, 5458c2ecf20Sopenharmony_ci CESA_SA_DESC_CFG_FRAG_MSK); 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_ci ret = mv_cesa_dma_add_result_op(chain, 5488c2ecf20Sopenharmony_ci CESA_SA_CFG_SRAM_OFFSET, 5498c2ecf20Sopenharmony_ci CESA_SA_DATA_SRAM_OFFSET, 5508c2ecf20Sopenharmony_ci CESA_TDMA_SRC_IN_SRAM, flags); 5518c2ecf20Sopenharmony_ci if (ret) 5528c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 5538c2ecf20Sopenharmony_ci return op; 5548c2ecf20Sopenharmony_ci } 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_ci /* 5578c2ecf20Sopenharmony_ci * The request is longer than the engine can handle, or we have 5588c2ecf20Sopenharmony_ci * no data outstanding. Manually generate the padding, adding it 5598c2ecf20Sopenharmony_ci * as a "mid" fragment. 5608c2ecf20Sopenharmony_ci */ 5618c2ecf20Sopenharmony_ci ret = mv_cesa_ahash_dma_alloc_padding(ahashdreq, flags); 5628c2ecf20Sopenharmony_ci if (ret) 5638c2ecf20Sopenharmony_ci return ERR_PTR(ret); 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci trailerlen = mv_cesa_ahash_pad_req(creq, ahashdreq->padding); 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ci len = min(CESA_SA_SRAM_PAYLOAD_SIZE - frag_len, trailerlen); 5688c2ecf20Sopenharmony_ci if (len) { 5698c2ecf20Sopenharmony_ci ret = mv_cesa_dma_add_data_transfer(chain, 5708c2ecf20Sopenharmony_ci CESA_SA_DATA_SRAM_OFFSET + 5718c2ecf20Sopenharmony_ci frag_len, 5728c2ecf20Sopenharmony_ci ahashdreq->padding_dma, 5738c2ecf20Sopenharmony_ci len, CESA_TDMA_DST_IN_SRAM, 5748c2ecf20Sopenharmony_ci flags); 5758c2ecf20Sopenharmony_ci if (ret) 5768c2ecf20Sopenharmony_ci return ERR_PTR(ret); 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_ci op = mv_cesa_dma_add_frag(chain, &creq->op_tmpl, frag_len + len, 5798c2ecf20Sopenharmony_ci flags); 5808c2ecf20Sopenharmony_ci if (IS_ERR(op)) 5818c2ecf20Sopenharmony_ci return op; 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci if (len == trailerlen) 5848c2ecf20Sopenharmony_ci return op; 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ci padoff += len; 5878c2ecf20Sopenharmony_ci } 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_ci ret = mv_cesa_dma_add_data_transfer(chain, 5908c2ecf20Sopenharmony_ci CESA_SA_DATA_SRAM_OFFSET, 5918c2ecf20Sopenharmony_ci ahashdreq->padding_dma + 5928c2ecf20Sopenharmony_ci padoff, 5938c2ecf20Sopenharmony_ci trailerlen - padoff, 5948c2ecf20Sopenharmony_ci CESA_TDMA_DST_IN_SRAM, 5958c2ecf20Sopenharmony_ci flags); 5968c2ecf20Sopenharmony_ci if (ret) 5978c2ecf20Sopenharmony_ci return ERR_PTR(ret); 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_ci return mv_cesa_dma_add_frag(chain, &creq->op_tmpl, trailerlen - padoff, 6008c2ecf20Sopenharmony_ci flags); 6018c2ecf20Sopenharmony_ci} 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_cistatic int mv_cesa_ahash_dma_req_init(struct ahash_request *req) 6048c2ecf20Sopenharmony_ci{ 6058c2ecf20Sopenharmony_ci struct mv_cesa_ahash_req *creq = ahash_request_ctx(req); 6068c2ecf20Sopenharmony_ci gfp_t flags = (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ? 6078c2ecf20Sopenharmony_ci GFP_KERNEL : GFP_ATOMIC; 6088c2ecf20Sopenharmony_ci struct mv_cesa_req *basereq = &creq->base; 6098c2ecf20Sopenharmony_ci struct mv_cesa_ahash_dma_iter iter; 6108c2ecf20Sopenharmony_ci struct mv_cesa_op_ctx *op = NULL; 6118c2ecf20Sopenharmony_ci unsigned int frag_len; 6128c2ecf20Sopenharmony_ci bool set_state = false; 6138c2ecf20Sopenharmony_ci int ret; 6148c2ecf20Sopenharmony_ci u32 type; 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci basereq->chain.first = NULL; 6178c2ecf20Sopenharmony_ci basereq->chain.last = NULL; 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_ci if (!mv_cesa_mac_op_is_first_frag(&creq->op_tmpl)) 6208c2ecf20Sopenharmony_ci set_state = true; 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_ci if (creq->src_nents) { 6238c2ecf20Sopenharmony_ci ret = dma_map_sg(cesa_dev->dev, req->src, creq->src_nents, 6248c2ecf20Sopenharmony_ci DMA_TO_DEVICE); 6258c2ecf20Sopenharmony_ci if (!ret) { 6268c2ecf20Sopenharmony_ci ret = -ENOMEM; 6278c2ecf20Sopenharmony_ci goto err; 6288c2ecf20Sopenharmony_ci } 6298c2ecf20Sopenharmony_ci } 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_ci mv_cesa_tdma_desc_iter_init(&basereq->chain); 6328c2ecf20Sopenharmony_ci mv_cesa_ahash_req_iter_init(&iter, req); 6338c2ecf20Sopenharmony_ci 6348c2ecf20Sopenharmony_ci /* 6358c2ecf20Sopenharmony_ci * Add the cache (left-over data from a previous block) first. 6368c2ecf20Sopenharmony_ci * This will never overflow the SRAM size. 6378c2ecf20Sopenharmony_ci */ 6388c2ecf20Sopenharmony_ci ret = mv_cesa_ahash_dma_add_cache(&basereq->chain, creq, flags); 6398c2ecf20Sopenharmony_ci if (ret) 6408c2ecf20Sopenharmony_ci goto err_free_tdma; 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_ci if (iter.src.sg) { 6438c2ecf20Sopenharmony_ci /* 6448c2ecf20Sopenharmony_ci * Add all the new data, inserting an operation block and 6458c2ecf20Sopenharmony_ci * launch command between each full SRAM block-worth of 6468c2ecf20Sopenharmony_ci * data. We intentionally do not add the final op block. 6478c2ecf20Sopenharmony_ci */ 6488c2ecf20Sopenharmony_ci while (true) { 6498c2ecf20Sopenharmony_ci ret = mv_cesa_dma_add_op_transfers(&basereq->chain, 6508c2ecf20Sopenharmony_ci &iter.base, 6518c2ecf20Sopenharmony_ci &iter.src, flags); 6528c2ecf20Sopenharmony_ci if (ret) 6538c2ecf20Sopenharmony_ci goto err_free_tdma; 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_ci frag_len = iter.base.op_len; 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_ci if (!mv_cesa_ahash_req_iter_next_op(&iter)) 6588c2ecf20Sopenharmony_ci break; 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_ci op = mv_cesa_dma_add_frag(&basereq->chain, 6618c2ecf20Sopenharmony_ci &creq->op_tmpl, 6628c2ecf20Sopenharmony_ci frag_len, flags); 6638c2ecf20Sopenharmony_ci if (IS_ERR(op)) { 6648c2ecf20Sopenharmony_ci ret = PTR_ERR(op); 6658c2ecf20Sopenharmony_ci goto err_free_tdma; 6668c2ecf20Sopenharmony_ci } 6678c2ecf20Sopenharmony_ci } 6688c2ecf20Sopenharmony_ci } else { 6698c2ecf20Sopenharmony_ci /* Account for the data that was in the cache. */ 6708c2ecf20Sopenharmony_ci frag_len = iter.base.op_len; 6718c2ecf20Sopenharmony_ci } 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_ci /* 6748c2ecf20Sopenharmony_ci * At this point, frag_len indicates whether we have any data 6758c2ecf20Sopenharmony_ci * outstanding which needs an operation. Queue up the final 6768c2ecf20Sopenharmony_ci * operation, which depends whether this is the final request. 6778c2ecf20Sopenharmony_ci */ 6788c2ecf20Sopenharmony_ci if (creq->last_req) 6798c2ecf20Sopenharmony_ci op = mv_cesa_ahash_dma_last_req(&basereq->chain, &iter, creq, 6808c2ecf20Sopenharmony_ci frag_len, flags); 6818c2ecf20Sopenharmony_ci else if (frag_len) 6828c2ecf20Sopenharmony_ci op = mv_cesa_dma_add_frag(&basereq->chain, &creq->op_tmpl, 6838c2ecf20Sopenharmony_ci frag_len, flags); 6848c2ecf20Sopenharmony_ci 6858c2ecf20Sopenharmony_ci if (IS_ERR(op)) { 6868c2ecf20Sopenharmony_ci ret = PTR_ERR(op); 6878c2ecf20Sopenharmony_ci goto err_free_tdma; 6888c2ecf20Sopenharmony_ci } 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_ci /* 6918c2ecf20Sopenharmony_ci * If results are copied via DMA, this means that this 6928c2ecf20Sopenharmony_ci * request can be directly processed by the engine, 6938c2ecf20Sopenharmony_ci * without partial updates. So we can chain it at the 6948c2ecf20Sopenharmony_ci * DMA level with other requests. 6958c2ecf20Sopenharmony_ci */ 6968c2ecf20Sopenharmony_ci type = basereq->chain.last->flags & CESA_TDMA_TYPE_MSK; 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_ci if (op && type != CESA_TDMA_RESULT) { 6998c2ecf20Sopenharmony_ci /* Add dummy desc to wait for crypto operation end */ 7008c2ecf20Sopenharmony_ci ret = mv_cesa_dma_add_dummy_end(&basereq->chain, flags); 7018c2ecf20Sopenharmony_ci if (ret) 7028c2ecf20Sopenharmony_ci goto err_free_tdma; 7038c2ecf20Sopenharmony_ci } 7048c2ecf20Sopenharmony_ci 7058c2ecf20Sopenharmony_ci if (!creq->last_req) 7068c2ecf20Sopenharmony_ci creq->cache_ptr = req->nbytes + creq->cache_ptr - 7078c2ecf20Sopenharmony_ci iter.base.len; 7088c2ecf20Sopenharmony_ci else 7098c2ecf20Sopenharmony_ci creq->cache_ptr = 0; 7108c2ecf20Sopenharmony_ci 7118c2ecf20Sopenharmony_ci basereq->chain.last->flags |= CESA_TDMA_END_OF_REQ; 7128c2ecf20Sopenharmony_ci 7138c2ecf20Sopenharmony_ci if (type != CESA_TDMA_RESULT) 7148c2ecf20Sopenharmony_ci basereq->chain.last->flags |= CESA_TDMA_BREAK_CHAIN; 7158c2ecf20Sopenharmony_ci 7168c2ecf20Sopenharmony_ci if (set_state) { 7178c2ecf20Sopenharmony_ci /* 7188c2ecf20Sopenharmony_ci * Put the CESA_TDMA_SET_STATE flag on the first tdma desc to 7198c2ecf20Sopenharmony_ci * let the step logic know that the IVDIG registers should be 7208c2ecf20Sopenharmony_ci * explicitly set before launching a TDMA chain. 7218c2ecf20Sopenharmony_ci */ 7228c2ecf20Sopenharmony_ci basereq->chain.first->flags |= CESA_TDMA_SET_STATE; 7238c2ecf20Sopenharmony_ci } 7248c2ecf20Sopenharmony_ci 7258c2ecf20Sopenharmony_ci return 0; 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_cierr_free_tdma: 7288c2ecf20Sopenharmony_ci mv_cesa_dma_cleanup(basereq); 7298c2ecf20Sopenharmony_ci dma_unmap_sg(cesa_dev->dev, req->src, creq->src_nents, DMA_TO_DEVICE); 7308c2ecf20Sopenharmony_ci 7318c2ecf20Sopenharmony_cierr: 7328c2ecf20Sopenharmony_ci mv_cesa_ahash_last_cleanup(req); 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_ci return ret; 7358c2ecf20Sopenharmony_ci} 7368c2ecf20Sopenharmony_ci 7378c2ecf20Sopenharmony_cistatic int mv_cesa_ahash_req_init(struct ahash_request *req, bool *cached) 7388c2ecf20Sopenharmony_ci{ 7398c2ecf20Sopenharmony_ci struct mv_cesa_ahash_req *creq = ahash_request_ctx(req); 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_ci creq->src_nents = sg_nents_for_len(req->src, req->nbytes); 7428c2ecf20Sopenharmony_ci if (creq->src_nents < 0) { 7438c2ecf20Sopenharmony_ci dev_err(cesa_dev->dev, "Invalid number of src SG"); 7448c2ecf20Sopenharmony_ci return creq->src_nents; 7458c2ecf20Sopenharmony_ci } 7468c2ecf20Sopenharmony_ci 7478c2ecf20Sopenharmony_ci *cached = mv_cesa_ahash_cache_req(req); 7488c2ecf20Sopenharmony_ci 7498c2ecf20Sopenharmony_ci if (*cached) 7508c2ecf20Sopenharmony_ci return 0; 7518c2ecf20Sopenharmony_ci 7528c2ecf20Sopenharmony_ci if (cesa_dev->caps->has_tdma) 7538c2ecf20Sopenharmony_ci return mv_cesa_ahash_dma_req_init(req); 7548c2ecf20Sopenharmony_ci else 7558c2ecf20Sopenharmony_ci return 0; 7568c2ecf20Sopenharmony_ci} 7578c2ecf20Sopenharmony_ci 7588c2ecf20Sopenharmony_cistatic int mv_cesa_ahash_queue_req(struct ahash_request *req) 7598c2ecf20Sopenharmony_ci{ 7608c2ecf20Sopenharmony_ci struct mv_cesa_ahash_req *creq = ahash_request_ctx(req); 7618c2ecf20Sopenharmony_ci struct mv_cesa_engine *engine; 7628c2ecf20Sopenharmony_ci bool cached = false; 7638c2ecf20Sopenharmony_ci int ret; 7648c2ecf20Sopenharmony_ci 7658c2ecf20Sopenharmony_ci ret = mv_cesa_ahash_req_init(req, &cached); 7668c2ecf20Sopenharmony_ci if (ret) 7678c2ecf20Sopenharmony_ci return ret; 7688c2ecf20Sopenharmony_ci 7698c2ecf20Sopenharmony_ci if (cached) 7708c2ecf20Sopenharmony_ci return 0; 7718c2ecf20Sopenharmony_ci 7728c2ecf20Sopenharmony_ci engine = mv_cesa_select_engine(req->nbytes); 7738c2ecf20Sopenharmony_ci mv_cesa_ahash_prepare(&req->base, engine); 7748c2ecf20Sopenharmony_ci 7758c2ecf20Sopenharmony_ci ret = mv_cesa_queue_req(&req->base, &creq->base); 7768c2ecf20Sopenharmony_ci 7778c2ecf20Sopenharmony_ci if (mv_cesa_req_needs_cleanup(&req->base, ret)) 7788c2ecf20Sopenharmony_ci mv_cesa_ahash_cleanup(req); 7798c2ecf20Sopenharmony_ci 7808c2ecf20Sopenharmony_ci return ret; 7818c2ecf20Sopenharmony_ci} 7828c2ecf20Sopenharmony_ci 7838c2ecf20Sopenharmony_cistatic int mv_cesa_ahash_update(struct ahash_request *req) 7848c2ecf20Sopenharmony_ci{ 7858c2ecf20Sopenharmony_ci struct mv_cesa_ahash_req *creq = ahash_request_ctx(req); 7868c2ecf20Sopenharmony_ci 7878c2ecf20Sopenharmony_ci creq->len += req->nbytes; 7888c2ecf20Sopenharmony_ci 7898c2ecf20Sopenharmony_ci return mv_cesa_ahash_queue_req(req); 7908c2ecf20Sopenharmony_ci} 7918c2ecf20Sopenharmony_ci 7928c2ecf20Sopenharmony_cistatic int mv_cesa_ahash_final(struct ahash_request *req) 7938c2ecf20Sopenharmony_ci{ 7948c2ecf20Sopenharmony_ci struct mv_cesa_ahash_req *creq = ahash_request_ctx(req); 7958c2ecf20Sopenharmony_ci struct mv_cesa_op_ctx *tmpl = &creq->op_tmpl; 7968c2ecf20Sopenharmony_ci 7978c2ecf20Sopenharmony_ci mv_cesa_set_mac_op_total_len(tmpl, creq->len); 7988c2ecf20Sopenharmony_ci creq->last_req = true; 7998c2ecf20Sopenharmony_ci req->nbytes = 0; 8008c2ecf20Sopenharmony_ci 8018c2ecf20Sopenharmony_ci return mv_cesa_ahash_queue_req(req); 8028c2ecf20Sopenharmony_ci} 8038c2ecf20Sopenharmony_ci 8048c2ecf20Sopenharmony_cistatic int mv_cesa_ahash_finup(struct ahash_request *req) 8058c2ecf20Sopenharmony_ci{ 8068c2ecf20Sopenharmony_ci struct mv_cesa_ahash_req *creq = ahash_request_ctx(req); 8078c2ecf20Sopenharmony_ci struct mv_cesa_op_ctx *tmpl = &creq->op_tmpl; 8088c2ecf20Sopenharmony_ci 8098c2ecf20Sopenharmony_ci creq->len += req->nbytes; 8108c2ecf20Sopenharmony_ci mv_cesa_set_mac_op_total_len(tmpl, creq->len); 8118c2ecf20Sopenharmony_ci creq->last_req = true; 8128c2ecf20Sopenharmony_ci 8138c2ecf20Sopenharmony_ci return mv_cesa_ahash_queue_req(req); 8148c2ecf20Sopenharmony_ci} 8158c2ecf20Sopenharmony_ci 8168c2ecf20Sopenharmony_cistatic int mv_cesa_ahash_export(struct ahash_request *req, void *hash, 8178c2ecf20Sopenharmony_ci u64 *len, void *cache) 8188c2ecf20Sopenharmony_ci{ 8198c2ecf20Sopenharmony_ci struct crypto_ahash *ahash = crypto_ahash_reqtfm(req); 8208c2ecf20Sopenharmony_ci struct mv_cesa_ahash_req *creq = ahash_request_ctx(req); 8218c2ecf20Sopenharmony_ci unsigned int digsize = crypto_ahash_digestsize(ahash); 8228c2ecf20Sopenharmony_ci unsigned int blocksize; 8238c2ecf20Sopenharmony_ci 8248c2ecf20Sopenharmony_ci blocksize = crypto_ahash_blocksize(ahash); 8258c2ecf20Sopenharmony_ci 8268c2ecf20Sopenharmony_ci *len = creq->len; 8278c2ecf20Sopenharmony_ci memcpy(hash, creq->state, digsize); 8288c2ecf20Sopenharmony_ci memset(cache, 0, blocksize); 8298c2ecf20Sopenharmony_ci memcpy(cache, creq->cache, creq->cache_ptr); 8308c2ecf20Sopenharmony_ci 8318c2ecf20Sopenharmony_ci return 0; 8328c2ecf20Sopenharmony_ci} 8338c2ecf20Sopenharmony_ci 8348c2ecf20Sopenharmony_cistatic int mv_cesa_ahash_import(struct ahash_request *req, const void *hash, 8358c2ecf20Sopenharmony_ci u64 len, const void *cache) 8368c2ecf20Sopenharmony_ci{ 8378c2ecf20Sopenharmony_ci struct crypto_ahash *ahash = crypto_ahash_reqtfm(req); 8388c2ecf20Sopenharmony_ci struct mv_cesa_ahash_req *creq = ahash_request_ctx(req); 8398c2ecf20Sopenharmony_ci unsigned int digsize = crypto_ahash_digestsize(ahash); 8408c2ecf20Sopenharmony_ci unsigned int blocksize; 8418c2ecf20Sopenharmony_ci unsigned int cache_ptr; 8428c2ecf20Sopenharmony_ci int ret; 8438c2ecf20Sopenharmony_ci 8448c2ecf20Sopenharmony_ci ret = crypto_ahash_init(req); 8458c2ecf20Sopenharmony_ci if (ret) 8468c2ecf20Sopenharmony_ci return ret; 8478c2ecf20Sopenharmony_ci 8488c2ecf20Sopenharmony_ci blocksize = crypto_ahash_blocksize(ahash); 8498c2ecf20Sopenharmony_ci if (len >= blocksize) 8508c2ecf20Sopenharmony_ci mv_cesa_update_op_cfg(&creq->op_tmpl, 8518c2ecf20Sopenharmony_ci CESA_SA_DESC_CFG_MID_FRAG, 8528c2ecf20Sopenharmony_ci CESA_SA_DESC_CFG_FRAG_MSK); 8538c2ecf20Sopenharmony_ci 8548c2ecf20Sopenharmony_ci creq->len = len; 8558c2ecf20Sopenharmony_ci memcpy(creq->state, hash, digsize); 8568c2ecf20Sopenharmony_ci creq->cache_ptr = 0; 8578c2ecf20Sopenharmony_ci 8588c2ecf20Sopenharmony_ci cache_ptr = do_div(len, blocksize); 8598c2ecf20Sopenharmony_ci if (!cache_ptr) 8608c2ecf20Sopenharmony_ci return 0; 8618c2ecf20Sopenharmony_ci 8628c2ecf20Sopenharmony_ci memcpy(creq->cache, cache, cache_ptr); 8638c2ecf20Sopenharmony_ci creq->cache_ptr = cache_ptr; 8648c2ecf20Sopenharmony_ci 8658c2ecf20Sopenharmony_ci return 0; 8668c2ecf20Sopenharmony_ci} 8678c2ecf20Sopenharmony_ci 8688c2ecf20Sopenharmony_cistatic int mv_cesa_md5_init(struct ahash_request *req) 8698c2ecf20Sopenharmony_ci{ 8708c2ecf20Sopenharmony_ci struct mv_cesa_ahash_req *creq = ahash_request_ctx(req); 8718c2ecf20Sopenharmony_ci struct mv_cesa_op_ctx tmpl = { }; 8728c2ecf20Sopenharmony_ci 8738c2ecf20Sopenharmony_ci mv_cesa_set_op_cfg(&tmpl, CESA_SA_DESC_CFG_MACM_MD5); 8748c2ecf20Sopenharmony_ci 8758c2ecf20Sopenharmony_ci mv_cesa_ahash_init(req, &tmpl, true); 8768c2ecf20Sopenharmony_ci 8778c2ecf20Sopenharmony_ci creq->state[0] = MD5_H0; 8788c2ecf20Sopenharmony_ci creq->state[1] = MD5_H1; 8798c2ecf20Sopenharmony_ci creq->state[2] = MD5_H2; 8808c2ecf20Sopenharmony_ci creq->state[3] = MD5_H3; 8818c2ecf20Sopenharmony_ci 8828c2ecf20Sopenharmony_ci return 0; 8838c2ecf20Sopenharmony_ci} 8848c2ecf20Sopenharmony_ci 8858c2ecf20Sopenharmony_cistatic int mv_cesa_md5_export(struct ahash_request *req, void *out) 8868c2ecf20Sopenharmony_ci{ 8878c2ecf20Sopenharmony_ci struct md5_state *out_state = out; 8888c2ecf20Sopenharmony_ci 8898c2ecf20Sopenharmony_ci return mv_cesa_ahash_export(req, out_state->hash, 8908c2ecf20Sopenharmony_ci &out_state->byte_count, out_state->block); 8918c2ecf20Sopenharmony_ci} 8928c2ecf20Sopenharmony_ci 8938c2ecf20Sopenharmony_cistatic int mv_cesa_md5_import(struct ahash_request *req, const void *in) 8948c2ecf20Sopenharmony_ci{ 8958c2ecf20Sopenharmony_ci const struct md5_state *in_state = in; 8968c2ecf20Sopenharmony_ci 8978c2ecf20Sopenharmony_ci return mv_cesa_ahash_import(req, in_state->hash, in_state->byte_count, 8988c2ecf20Sopenharmony_ci in_state->block); 8998c2ecf20Sopenharmony_ci} 9008c2ecf20Sopenharmony_ci 9018c2ecf20Sopenharmony_cistatic int mv_cesa_md5_digest(struct ahash_request *req) 9028c2ecf20Sopenharmony_ci{ 9038c2ecf20Sopenharmony_ci int ret; 9048c2ecf20Sopenharmony_ci 9058c2ecf20Sopenharmony_ci ret = mv_cesa_md5_init(req); 9068c2ecf20Sopenharmony_ci if (ret) 9078c2ecf20Sopenharmony_ci return ret; 9088c2ecf20Sopenharmony_ci 9098c2ecf20Sopenharmony_ci return mv_cesa_ahash_finup(req); 9108c2ecf20Sopenharmony_ci} 9118c2ecf20Sopenharmony_ci 9128c2ecf20Sopenharmony_cistruct ahash_alg mv_md5_alg = { 9138c2ecf20Sopenharmony_ci .init = mv_cesa_md5_init, 9148c2ecf20Sopenharmony_ci .update = mv_cesa_ahash_update, 9158c2ecf20Sopenharmony_ci .final = mv_cesa_ahash_final, 9168c2ecf20Sopenharmony_ci .finup = mv_cesa_ahash_finup, 9178c2ecf20Sopenharmony_ci .digest = mv_cesa_md5_digest, 9188c2ecf20Sopenharmony_ci .export = mv_cesa_md5_export, 9198c2ecf20Sopenharmony_ci .import = mv_cesa_md5_import, 9208c2ecf20Sopenharmony_ci .halg = { 9218c2ecf20Sopenharmony_ci .digestsize = MD5_DIGEST_SIZE, 9228c2ecf20Sopenharmony_ci .statesize = sizeof(struct md5_state), 9238c2ecf20Sopenharmony_ci .base = { 9248c2ecf20Sopenharmony_ci .cra_name = "md5", 9258c2ecf20Sopenharmony_ci .cra_driver_name = "mv-md5", 9268c2ecf20Sopenharmony_ci .cra_priority = 300, 9278c2ecf20Sopenharmony_ci .cra_flags = CRYPTO_ALG_ASYNC | 9288c2ecf20Sopenharmony_ci CRYPTO_ALG_ALLOCATES_MEMORY | 9298c2ecf20Sopenharmony_ci CRYPTO_ALG_KERN_DRIVER_ONLY, 9308c2ecf20Sopenharmony_ci .cra_blocksize = MD5_HMAC_BLOCK_SIZE, 9318c2ecf20Sopenharmony_ci .cra_ctxsize = sizeof(struct mv_cesa_hash_ctx), 9328c2ecf20Sopenharmony_ci .cra_init = mv_cesa_ahash_cra_init, 9338c2ecf20Sopenharmony_ci .cra_module = THIS_MODULE, 9348c2ecf20Sopenharmony_ci } 9358c2ecf20Sopenharmony_ci } 9368c2ecf20Sopenharmony_ci}; 9378c2ecf20Sopenharmony_ci 9388c2ecf20Sopenharmony_cistatic int mv_cesa_sha1_init(struct ahash_request *req) 9398c2ecf20Sopenharmony_ci{ 9408c2ecf20Sopenharmony_ci struct mv_cesa_ahash_req *creq = ahash_request_ctx(req); 9418c2ecf20Sopenharmony_ci struct mv_cesa_op_ctx tmpl = { }; 9428c2ecf20Sopenharmony_ci 9438c2ecf20Sopenharmony_ci mv_cesa_set_op_cfg(&tmpl, CESA_SA_DESC_CFG_MACM_SHA1); 9448c2ecf20Sopenharmony_ci 9458c2ecf20Sopenharmony_ci mv_cesa_ahash_init(req, &tmpl, false); 9468c2ecf20Sopenharmony_ci 9478c2ecf20Sopenharmony_ci creq->state[0] = SHA1_H0; 9488c2ecf20Sopenharmony_ci creq->state[1] = SHA1_H1; 9498c2ecf20Sopenharmony_ci creq->state[2] = SHA1_H2; 9508c2ecf20Sopenharmony_ci creq->state[3] = SHA1_H3; 9518c2ecf20Sopenharmony_ci creq->state[4] = SHA1_H4; 9528c2ecf20Sopenharmony_ci 9538c2ecf20Sopenharmony_ci return 0; 9548c2ecf20Sopenharmony_ci} 9558c2ecf20Sopenharmony_ci 9568c2ecf20Sopenharmony_cistatic int mv_cesa_sha1_export(struct ahash_request *req, void *out) 9578c2ecf20Sopenharmony_ci{ 9588c2ecf20Sopenharmony_ci struct sha1_state *out_state = out; 9598c2ecf20Sopenharmony_ci 9608c2ecf20Sopenharmony_ci return mv_cesa_ahash_export(req, out_state->state, &out_state->count, 9618c2ecf20Sopenharmony_ci out_state->buffer); 9628c2ecf20Sopenharmony_ci} 9638c2ecf20Sopenharmony_ci 9648c2ecf20Sopenharmony_cistatic int mv_cesa_sha1_import(struct ahash_request *req, const void *in) 9658c2ecf20Sopenharmony_ci{ 9668c2ecf20Sopenharmony_ci const struct sha1_state *in_state = in; 9678c2ecf20Sopenharmony_ci 9688c2ecf20Sopenharmony_ci return mv_cesa_ahash_import(req, in_state->state, in_state->count, 9698c2ecf20Sopenharmony_ci in_state->buffer); 9708c2ecf20Sopenharmony_ci} 9718c2ecf20Sopenharmony_ci 9728c2ecf20Sopenharmony_cistatic int mv_cesa_sha1_digest(struct ahash_request *req) 9738c2ecf20Sopenharmony_ci{ 9748c2ecf20Sopenharmony_ci int ret; 9758c2ecf20Sopenharmony_ci 9768c2ecf20Sopenharmony_ci ret = mv_cesa_sha1_init(req); 9778c2ecf20Sopenharmony_ci if (ret) 9788c2ecf20Sopenharmony_ci return ret; 9798c2ecf20Sopenharmony_ci 9808c2ecf20Sopenharmony_ci return mv_cesa_ahash_finup(req); 9818c2ecf20Sopenharmony_ci} 9828c2ecf20Sopenharmony_ci 9838c2ecf20Sopenharmony_cistruct ahash_alg mv_sha1_alg = { 9848c2ecf20Sopenharmony_ci .init = mv_cesa_sha1_init, 9858c2ecf20Sopenharmony_ci .update = mv_cesa_ahash_update, 9868c2ecf20Sopenharmony_ci .final = mv_cesa_ahash_final, 9878c2ecf20Sopenharmony_ci .finup = mv_cesa_ahash_finup, 9888c2ecf20Sopenharmony_ci .digest = mv_cesa_sha1_digest, 9898c2ecf20Sopenharmony_ci .export = mv_cesa_sha1_export, 9908c2ecf20Sopenharmony_ci .import = mv_cesa_sha1_import, 9918c2ecf20Sopenharmony_ci .halg = { 9928c2ecf20Sopenharmony_ci .digestsize = SHA1_DIGEST_SIZE, 9938c2ecf20Sopenharmony_ci .statesize = sizeof(struct sha1_state), 9948c2ecf20Sopenharmony_ci .base = { 9958c2ecf20Sopenharmony_ci .cra_name = "sha1", 9968c2ecf20Sopenharmony_ci .cra_driver_name = "mv-sha1", 9978c2ecf20Sopenharmony_ci .cra_priority = 300, 9988c2ecf20Sopenharmony_ci .cra_flags = CRYPTO_ALG_ASYNC | 9998c2ecf20Sopenharmony_ci CRYPTO_ALG_ALLOCATES_MEMORY | 10008c2ecf20Sopenharmony_ci CRYPTO_ALG_KERN_DRIVER_ONLY, 10018c2ecf20Sopenharmony_ci .cra_blocksize = SHA1_BLOCK_SIZE, 10028c2ecf20Sopenharmony_ci .cra_ctxsize = sizeof(struct mv_cesa_hash_ctx), 10038c2ecf20Sopenharmony_ci .cra_init = mv_cesa_ahash_cra_init, 10048c2ecf20Sopenharmony_ci .cra_module = THIS_MODULE, 10058c2ecf20Sopenharmony_ci } 10068c2ecf20Sopenharmony_ci } 10078c2ecf20Sopenharmony_ci}; 10088c2ecf20Sopenharmony_ci 10098c2ecf20Sopenharmony_cistatic int mv_cesa_sha256_init(struct ahash_request *req) 10108c2ecf20Sopenharmony_ci{ 10118c2ecf20Sopenharmony_ci struct mv_cesa_ahash_req *creq = ahash_request_ctx(req); 10128c2ecf20Sopenharmony_ci struct mv_cesa_op_ctx tmpl = { }; 10138c2ecf20Sopenharmony_ci 10148c2ecf20Sopenharmony_ci mv_cesa_set_op_cfg(&tmpl, CESA_SA_DESC_CFG_MACM_SHA256); 10158c2ecf20Sopenharmony_ci 10168c2ecf20Sopenharmony_ci mv_cesa_ahash_init(req, &tmpl, false); 10178c2ecf20Sopenharmony_ci 10188c2ecf20Sopenharmony_ci creq->state[0] = SHA256_H0; 10198c2ecf20Sopenharmony_ci creq->state[1] = SHA256_H1; 10208c2ecf20Sopenharmony_ci creq->state[2] = SHA256_H2; 10218c2ecf20Sopenharmony_ci creq->state[3] = SHA256_H3; 10228c2ecf20Sopenharmony_ci creq->state[4] = SHA256_H4; 10238c2ecf20Sopenharmony_ci creq->state[5] = SHA256_H5; 10248c2ecf20Sopenharmony_ci creq->state[6] = SHA256_H6; 10258c2ecf20Sopenharmony_ci creq->state[7] = SHA256_H7; 10268c2ecf20Sopenharmony_ci 10278c2ecf20Sopenharmony_ci return 0; 10288c2ecf20Sopenharmony_ci} 10298c2ecf20Sopenharmony_ci 10308c2ecf20Sopenharmony_cistatic int mv_cesa_sha256_digest(struct ahash_request *req) 10318c2ecf20Sopenharmony_ci{ 10328c2ecf20Sopenharmony_ci int ret; 10338c2ecf20Sopenharmony_ci 10348c2ecf20Sopenharmony_ci ret = mv_cesa_sha256_init(req); 10358c2ecf20Sopenharmony_ci if (ret) 10368c2ecf20Sopenharmony_ci return ret; 10378c2ecf20Sopenharmony_ci 10388c2ecf20Sopenharmony_ci return mv_cesa_ahash_finup(req); 10398c2ecf20Sopenharmony_ci} 10408c2ecf20Sopenharmony_ci 10418c2ecf20Sopenharmony_cistatic int mv_cesa_sha256_export(struct ahash_request *req, void *out) 10428c2ecf20Sopenharmony_ci{ 10438c2ecf20Sopenharmony_ci struct sha256_state *out_state = out; 10448c2ecf20Sopenharmony_ci 10458c2ecf20Sopenharmony_ci return mv_cesa_ahash_export(req, out_state->state, &out_state->count, 10468c2ecf20Sopenharmony_ci out_state->buf); 10478c2ecf20Sopenharmony_ci} 10488c2ecf20Sopenharmony_ci 10498c2ecf20Sopenharmony_cistatic int mv_cesa_sha256_import(struct ahash_request *req, const void *in) 10508c2ecf20Sopenharmony_ci{ 10518c2ecf20Sopenharmony_ci const struct sha256_state *in_state = in; 10528c2ecf20Sopenharmony_ci 10538c2ecf20Sopenharmony_ci return mv_cesa_ahash_import(req, in_state->state, in_state->count, 10548c2ecf20Sopenharmony_ci in_state->buf); 10558c2ecf20Sopenharmony_ci} 10568c2ecf20Sopenharmony_ci 10578c2ecf20Sopenharmony_cistruct ahash_alg mv_sha256_alg = { 10588c2ecf20Sopenharmony_ci .init = mv_cesa_sha256_init, 10598c2ecf20Sopenharmony_ci .update = mv_cesa_ahash_update, 10608c2ecf20Sopenharmony_ci .final = mv_cesa_ahash_final, 10618c2ecf20Sopenharmony_ci .finup = mv_cesa_ahash_finup, 10628c2ecf20Sopenharmony_ci .digest = mv_cesa_sha256_digest, 10638c2ecf20Sopenharmony_ci .export = mv_cesa_sha256_export, 10648c2ecf20Sopenharmony_ci .import = mv_cesa_sha256_import, 10658c2ecf20Sopenharmony_ci .halg = { 10668c2ecf20Sopenharmony_ci .digestsize = SHA256_DIGEST_SIZE, 10678c2ecf20Sopenharmony_ci .statesize = sizeof(struct sha256_state), 10688c2ecf20Sopenharmony_ci .base = { 10698c2ecf20Sopenharmony_ci .cra_name = "sha256", 10708c2ecf20Sopenharmony_ci .cra_driver_name = "mv-sha256", 10718c2ecf20Sopenharmony_ci .cra_priority = 300, 10728c2ecf20Sopenharmony_ci .cra_flags = CRYPTO_ALG_ASYNC | 10738c2ecf20Sopenharmony_ci CRYPTO_ALG_ALLOCATES_MEMORY | 10748c2ecf20Sopenharmony_ci CRYPTO_ALG_KERN_DRIVER_ONLY, 10758c2ecf20Sopenharmony_ci .cra_blocksize = SHA256_BLOCK_SIZE, 10768c2ecf20Sopenharmony_ci .cra_ctxsize = sizeof(struct mv_cesa_hash_ctx), 10778c2ecf20Sopenharmony_ci .cra_init = mv_cesa_ahash_cra_init, 10788c2ecf20Sopenharmony_ci .cra_module = THIS_MODULE, 10798c2ecf20Sopenharmony_ci } 10808c2ecf20Sopenharmony_ci } 10818c2ecf20Sopenharmony_ci}; 10828c2ecf20Sopenharmony_ci 10838c2ecf20Sopenharmony_cistruct mv_cesa_ahash_result { 10848c2ecf20Sopenharmony_ci struct completion completion; 10858c2ecf20Sopenharmony_ci int error; 10868c2ecf20Sopenharmony_ci}; 10878c2ecf20Sopenharmony_ci 10888c2ecf20Sopenharmony_cistatic void mv_cesa_hmac_ahash_complete(struct crypto_async_request *req, 10898c2ecf20Sopenharmony_ci int error) 10908c2ecf20Sopenharmony_ci{ 10918c2ecf20Sopenharmony_ci struct mv_cesa_ahash_result *result = req->data; 10928c2ecf20Sopenharmony_ci 10938c2ecf20Sopenharmony_ci if (error == -EINPROGRESS) 10948c2ecf20Sopenharmony_ci return; 10958c2ecf20Sopenharmony_ci 10968c2ecf20Sopenharmony_ci result->error = error; 10978c2ecf20Sopenharmony_ci complete(&result->completion); 10988c2ecf20Sopenharmony_ci} 10998c2ecf20Sopenharmony_ci 11008c2ecf20Sopenharmony_cistatic int mv_cesa_ahmac_iv_state_init(struct ahash_request *req, u8 *pad, 11018c2ecf20Sopenharmony_ci void *state, unsigned int blocksize) 11028c2ecf20Sopenharmony_ci{ 11038c2ecf20Sopenharmony_ci struct mv_cesa_ahash_result result; 11048c2ecf20Sopenharmony_ci struct scatterlist sg; 11058c2ecf20Sopenharmony_ci int ret; 11068c2ecf20Sopenharmony_ci 11078c2ecf20Sopenharmony_ci ahash_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG, 11088c2ecf20Sopenharmony_ci mv_cesa_hmac_ahash_complete, &result); 11098c2ecf20Sopenharmony_ci sg_init_one(&sg, pad, blocksize); 11108c2ecf20Sopenharmony_ci ahash_request_set_crypt(req, &sg, pad, blocksize); 11118c2ecf20Sopenharmony_ci init_completion(&result.completion); 11128c2ecf20Sopenharmony_ci 11138c2ecf20Sopenharmony_ci ret = crypto_ahash_init(req); 11148c2ecf20Sopenharmony_ci if (ret) 11158c2ecf20Sopenharmony_ci return ret; 11168c2ecf20Sopenharmony_ci 11178c2ecf20Sopenharmony_ci ret = crypto_ahash_update(req); 11188c2ecf20Sopenharmony_ci if (ret && ret != -EINPROGRESS) 11198c2ecf20Sopenharmony_ci return ret; 11208c2ecf20Sopenharmony_ci 11218c2ecf20Sopenharmony_ci wait_for_completion_interruptible(&result.completion); 11228c2ecf20Sopenharmony_ci if (result.error) 11238c2ecf20Sopenharmony_ci return result.error; 11248c2ecf20Sopenharmony_ci 11258c2ecf20Sopenharmony_ci ret = crypto_ahash_export(req, state); 11268c2ecf20Sopenharmony_ci if (ret) 11278c2ecf20Sopenharmony_ci return ret; 11288c2ecf20Sopenharmony_ci 11298c2ecf20Sopenharmony_ci return 0; 11308c2ecf20Sopenharmony_ci} 11318c2ecf20Sopenharmony_ci 11328c2ecf20Sopenharmony_cistatic int mv_cesa_ahmac_pad_init(struct ahash_request *req, 11338c2ecf20Sopenharmony_ci const u8 *key, unsigned int keylen, 11348c2ecf20Sopenharmony_ci u8 *ipad, u8 *opad, 11358c2ecf20Sopenharmony_ci unsigned int blocksize) 11368c2ecf20Sopenharmony_ci{ 11378c2ecf20Sopenharmony_ci struct mv_cesa_ahash_result result; 11388c2ecf20Sopenharmony_ci struct scatterlist sg; 11398c2ecf20Sopenharmony_ci int ret; 11408c2ecf20Sopenharmony_ci int i; 11418c2ecf20Sopenharmony_ci 11428c2ecf20Sopenharmony_ci if (keylen <= blocksize) { 11438c2ecf20Sopenharmony_ci memcpy(ipad, key, keylen); 11448c2ecf20Sopenharmony_ci } else { 11458c2ecf20Sopenharmony_ci u8 *keydup = kmemdup(key, keylen, GFP_KERNEL); 11468c2ecf20Sopenharmony_ci 11478c2ecf20Sopenharmony_ci if (!keydup) 11488c2ecf20Sopenharmony_ci return -ENOMEM; 11498c2ecf20Sopenharmony_ci 11508c2ecf20Sopenharmony_ci ahash_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG, 11518c2ecf20Sopenharmony_ci mv_cesa_hmac_ahash_complete, 11528c2ecf20Sopenharmony_ci &result); 11538c2ecf20Sopenharmony_ci sg_init_one(&sg, keydup, keylen); 11548c2ecf20Sopenharmony_ci ahash_request_set_crypt(req, &sg, ipad, keylen); 11558c2ecf20Sopenharmony_ci init_completion(&result.completion); 11568c2ecf20Sopenharmony_ci 11578c2ecf20Sopenharmony_ci ret = crypto_ahash_digest(req); 11588c2ecf20Sopenharmony_ci if (ret == -EINPROGRESS) { 11598c2ecf20Sopenharmony_ci wait_for_completion_interruptible(&result.completion); 11608c2ecf20Sopenharmony_ci ret = result.error; 11618c2ecf20Sopenharmony_ci } 11628c2ecf20Sopenharmony_ci 11638c2ecf20Sopenharmony_ci /* Set the memory region to 0 to avoid any leak. */ 11648c2ecf20Sopenharmony_ci kfree_sensitive(keydup); 11658c2ecf20Sopenharmony_ci 11668c2ecf20Sopenharmony_ci if (ret) 11678c2ecf20Sopenharmony_ci return ret; 11688c2ecf20Sopenharmony_ci 11698c2ecf20Sopenharmony_ci keylen = crypto_ahash_digestsize(crypto_ahash_reqtfm(req)); 11708c2ecf20Sopenharmony_ci } 11718c2ecf20Sopenharmony_ci 11728c2ecf20Sopenharmony_ci memset(ipad + keylen, 0, blocksize - keylen); 11738c2ecf20Sopenharmony_ci memcpy(opad, ipad, blocksize); 11748c2ecf20Sopenharmony_ci 11758c2ecf20Sopenharmony_ci for (i = 0; i < blocksize; i++) { 11768c2ecf20Sopenharmony_ci ipad[i] ^= HMAC_IPAD_VALUE; 11778c2ecf20Sopenharmony_ci opad[i] ^= HMAC_OPAD_VALUE; 11788c2ecf20Sopenharmony_ci } 11798c2ecf20Sopenharmony_ci 11808c2ecf20Sopenharmony_ci return 0; 11818c2ecf20Sopenharmony_ci} 11828c2ecf20Sopenharmony_ci 11838c2ecf20Sopenharmony_cistatic int mv_cesa_ahmac_setkey(const char *hash_alg_name, 11848c2ecf20Sopenharmony_ci const u8 *key, unsigned int keylen, 11858c2ecf20Sopenharmony_ci void *istate, void *ostate) 11868c2ecf20Sopenharmony_ci{ 11878c2ecf20Sopenharmony_ci struct ahash_request *req; 11888c2ecf20Sopenharmony_ci struct crypto_ahash *tfm; 11898c2ecf20Sopenharmony_ci unsigned int blocksize; 11908c2ecf20Sopenharmony_ci u8 *ipad = NULL; 11918c2ecf20Sopenharmony_ci u8 *opad; 11928c2ecf20Sopenharmony_ci int ret; 11938c2ecf20Sopenharmony_ci 11948c2ecf20Sopenharmony_ci tfm = crypto_alloc_ahash(hash_alg_name, 0, 0); 11958c2ecf20Sopenharmony_ci if (IS_ERR(tfm)) 11968c2ecf20Sopenharmony_ci return PTR_ERR(tfm); 11978c2ecf20Sopenharmony_ci 11988c2ecf20Sopenharmony_ci req = ahash_request_alloc(tfm, GFP_KERNEL); 11998c2ecf20Sopenharmony_ci if (!req) { 12008c2ecf20Sopenharmony_ci ret = -ENOMEM; 12018c2ecf20Sopenharmony_ci goto free_ahash; 12028c2ecf20Sopenharmony_ci } 12038c2ecf20Sopenharmony_ci 12048c2ecf20Sopenharmony_ci crypto_ahash_clear_flags(tfm, ~0); 12058c2ecf20Sopenharmony_ci 12068c2ecf20Sopenharmony_ci blocksize = crypto_tfm_alg_blocksize(crypto_ahash_tfm(tfm)); 12078c2ecf20Sopenharmony_ci 12088c2ecf20Sopenharmony_ci ipad = kcalloc(2, blocksize, GFP_KERNEL); 12098c2ecf20Sopenharmony_ci if (!ipad) { 12108c2ecf20Sopenharmony_ci ret = -ENOMEM; 12118c2ecf20Sopenharmony_ci goto free_req; 12128c2ecf20Sopenharmony_ci } 12138c2ecf20Sopenharmony_ci 12148c2ecf20Sopenharmony_ci opad = ipad + blocksize; 12158c2ecf20Sopenharmony_ci 12168c2ecf20Sopenharmony_ci ret = mv_cesa_ahmac_pad_init(req, key, keylen, ipad, opad, blocksize); 12178c2ecf20Sopenharmony_ci if (ret) 12188c2ecf20Sopenharmony_ci goto free_ipad; 12198c2ecf20Sopenharmony_ci 12208c2ecf20Sopenharmony_ci ret = mv_cesa_ahmac_iv_state_init(req, ipad, istate, blocksize); 12218c2ecf20Sopenharmony_ci if (ret) 12228c2ecf20Sopenharmony_ci goto free_ipad; 12238c2ecf20Sopenharmony_ci 12248c2ecf20Sopenharmony_ci ret = mv_cesa_ahmac_iv_state_init(req, opad, ostate, blocksize); 12258c2ecf20Sopenharmony_ci 12268c2ecf20Sopenharmony_cifree_ipad: 12278c2ecf20Sopenharmony_ci kfree(ipad); 12288c2ecf20Sopenharmony_cifree_req: 12298c2ecf20Sopenharmony_ci ahash_request_free(req); 12308c2ecf20Sopenharmony_cifree_ahash: 12318c2ecf20Sopenharmony_ci crypto_free_ahash(tfm); 12328c2ecf20Sopenharmony_ci 12338c2ecf20Sopenharmony_ci return ret; 12348c2ecf20Sopenharmony_ci} 12358c2ecf20Sopenharmony_ci 12368c2ecf20Sopenharmony_cistatic int mv_cesa_ahmac_cra_init(struct crypto_tfm *tfm) 12378c2ecf20Sopenharmony_ci{ 12388c2ecf20Sopenharmony_ci struct mv_cesa_hmac_ctx *ctx = crypto_tfm_ctx(tfm); 12398c2ecf20Sopenharmony_ci 12408c2ecf20Sopenharmony_ci ctx->base.ops = &mv_cesa_ahash_req_ops; 12418c2ecf20Sopenharmony_ci 12428c2ecf20Sopenharmony_ci crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm), 12438c2ecf20Sopenharmony_ci sizeof(struct mv_cesa_ahash_req)); 12448c2ecf20Sopenharmony_ci return 0; 12458c2ecf20Sopenharmony_ci} 12468c2ecf20Sopenharmony_ci 12478c2ecf20Sopenharmony_cistatic int mv_cesa_ahmac_md5_init(struct ahash_request *req) 12488c2ecf20Sopenharmony_ci{ 12498c2ecf20Sopenharmony_ci struct mv_cesa_hmac_ctx *ctx = crypto_tfm_ctx(req->base.tfm); 12508c2ecf20Sopenharmony_ci struct mv_cesa_op_ctx tmpl = { }; 12518c2ecf20Sopenharmony_ci 12528c2ecf20Sopenharmony_ci mv_cesa_set_op_cfg(&tmpl, CESA_SA_DESC_CFG_MACM_HMAC_MD5); 12538c2ecf20Sopenharmony_ci memcpy(tmpl.ctx.hash.iv, ctx->iv, sizeof(ctx->iv)); 12548c2ecf20Sopenharmony_ci 12558c2ecf20Sopenharmony_ci mv_cesa_ahash_init(req, &tmpl, true); 12568c2ecf20Sopenharmony_ci 12578c2ecf20Sopenharmony_ci return 0; 12588c2ecf20Sopenharmony_ci} 12598c2ecf20Sopenharmony_ci 12608c2ecf20Sopenharmony_cistatic int mv_cesa_ahmac_md5_setkey(struct crypto_ahash *tfm, const u8 *key, 12618c2ecf20Sopenharmony_ci unsigned int keylen) 12628c2ecf20Sopenharmony_ci{ 12638c2ecf20Sopenharmony_ci struct mv_cesa_hmac_ctx *ctx = crypto_tfm_ctx(crypto_ahash_tfm(tfm)); 12648c2ecf20Sopenharmony_ci struct md5_state istate, ostate; 12658c2ecf20Sopenharmony_ci int ret, i; 12668c2ecf20Sopenharmony_ci 12678c2ecf20Sopenharmony_ci ret = mv_cesa_ahmac_setkey("mv-md5", key, keylen, &istate, &ostate); 12688c2ecf20Sopenharmony_ci if (ret) 12698c2ecf20Sopenharmony_ci return ret; 12708c2ecf20Sopenharmony_ci 12718c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(istate.hash); i++) 12728c2ecf20Sopenharmony_ci ctx->iv[i] = cpu_to_be32(istate.hash[i]); 12738c2ecf20Sopenharmony_ci 12748c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(ostate.hash); i++) 12758c2ecf20Sopenharmony_ci ctx->iv[i + 8] = cpu_to_be32(ostate.hash[i]); 12768c2ecf20Sopenharmony_ci 12778c2ecf20Sopenharmony_ci return 0; 12788c2ecf20Sopenharmony_ci} 12798c2ecf20Sopenharmony_ci 12808c2ecf20Sopenharmony_cistatic int mv_cesa_ahmac_md5_digest(struct ahash_request *req) 12818c2ecf20Sopenharmony_ci{ 12828c2ecf20Sopenharmony_ci int ret; 12838c2ecf20Sopenharmony_ci 12848c2ecf20Sopenharmony_ci ret = mv_cesa_ahmac_md5_init(req); 12858c2ecf20Sopenharmony_ci if (ret) 12868c2ecf20Sopenharmony_ci return ret; 12878c2ecf20Sopenharmony_ci 12888c2ecf20Sopenharmony_ci return mv_cesa_ahash_finup(req); 12898c2ecf20Sopenharmony_ci} 12908c2ecf20Sopenharmony_ci 12918c2ecf20Sopenharmony_cistruct ahash_alg mv_ahmac_md5_alg = { 12928c2ecf20Sopenharmony_ci .init = mv_cesa_ahmac_md5_init, 12938c2ecf20Sopenharmony_ci .update = mv_cesa_ahash_update, 12948c2ecf20Sopenharmony_ci .final = mv_cesa_ahash_final, 12958c2ecf20Sopenharmony_ci .finup = mv_cesa_ahash_finup, 12968c2ecf20Sopenharmony_ci .digest = mv_cesa_ahmac_md5_digest, 12978c2ecf20Sopenharmony_ci .setkey = mv_cesa_ahmac_md5_setkey, 12988c2ecf20Sopenharmony_ci .export = mv_cesa_md5_export, 12998c2ecf20Sopenharmony_ci .import = mv_cesa_md5_import, 13008c2ecf20Sopenharmony_ci .halg = { 13018c2ecf20Sopenharmony_ci .digestsize = MD5_DIGEST_SIZE, 13028c2ecf20Sopenharmony_ci .statesize = sizeof(struct md5_state), 13038c2ecf20Sopenharmony_ci .base = { 13048c2ecf20Sopenharmony_ci .cra_name = "hmac(md5)", 13058c2ecf20Sopenharmony_ci .cra_driver_name = "mv-hmac-md5", 13068c2ecf20Sopenharmony_ci .cra_priority = 300, 13078c2ecf20Sopenharmony_ci .cra_flags = CRYPTO_ALG_ASYNC | 13088c2ecf20Sopenharmony_ci CRYPTO_ALG_ALLOCATES_MEMORY | 13098c2ecf20Sopenharmony_ci CRYPTO_ALG_KERN_DRIVER_ONLY, 13108c2ecf20Sopenharmony_ci .cra_blocksize = MD5_HMAC_BLOCK_SIZE, 13118c2ecf20Sopenharmony_ci .cra_ctxsize = sizeof(struct mv_cesa_hmac_ctx), 13128c2ecf20Sopenharmony_ci .cra_init = mv_cesa_ahmac_cra_init, 13138c2ecf20Sopenharmony_ci .cra_module = THIS_MODULE, 13148c2ecf20Sopenharmony_ci } 13158c2ecf20Sopenharmony_ci } 13168c2ecf20Sopenharmony_ci}; 13178c2ecf20Sopenharmony_ci 13188c2ecf20Sopenharmony_cistatic int mv_cesa_ahmac_sha1_init(struct ahash_request *req) 13198c2ecf20Sopenharmony_ci{ 13208c2ecf20Sopenharmony_ci struct mv_cesa_hmac_ctx *ctx = crypto_tfm_ctx(req->base.tfm); 13218c2ecf20Sopenharmony_ci struct mv_cesa_op_ctx tmpl = { }; 13228c2ecf20Sopenharmony_ci 13238c2ecf20Sopenharmony_ci mv_cesa_set_op_cfg(&tmpl, CESA_SA_DESC_CFG_MACM_HMAC_SHA1); 13248c2ecf20Sopenharmony_ci memcpy(tmpl.ctx.hash.iv, ctx->iv, sizeof(ctx->iv)); 13258c2ecf20Sopenharmony_ci 13268c2ecf20Sopenharmony_ci mv_cesa_ahash_init(req, &tmpl, false); 13278c2ecf20Sopenharmony_ci 13288c2ecf20Sopenharmony_ci return 0; 13298c2ecf20Sopenharmony_ci} 13308c2ecf20Sopenharmony_ci 13318c2ecf20Sopenharmony_cistatic int mv_cesa_ahmac_sha1_setkey(struct crypto_ahash *tfm, const u8 *key, 13328c2ecf20Sopenharmony_ci unsigned int keylen) 13338c2ecf20Sopenharmony_ci{ 13348c2ecf20Sopenharmony_ci struct mv_cesa_hmac_ctx *ctx = crypto_tfm_ctx(crypto_ahash_tfm(tfm)); 13358c2ecf20Sopenharmony_ci struct sha1_state istate, ostate; 13368c2ecf20Sopenharmony_ci int ret, i; 13378c2ecf20Sopenharmony_ci 13388c2ecf20Sopenharmony_ci ret = mv_cesa_ahmac_setkey("mv-sha1", key, keylen, &istate, &ostate); 13398c2ecf20Sopenharmony_ci if (ret) 13408c2ecf20Sopenharmony_ci return ret; 13418c2ecf20Sopenharmony_ci 13428c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(istate.state); i++) 13438c2ecf20Sopenharmony_ci ctx->iv[i] = cpu_to_be32(istate.state[i]); 13448c2ecf20Sopenharmony_ci 13458c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(ostate.state); i++) 13468c2ecf20Sopenharmony_ci ctx->iv[i + 8] = cpu_to_be32(ostate.state[i]); 13478c2ecf20Sopenharmony_ci 13488c2ecf20Sopenharmony_ci return 0; 13498c2ecf20Sopenharmony_ci} 13508c2ecf20Sopenharmony_ci 13518c2ecf20Sopenharmony_cistatic int mv_cesa_ahmac_sha1_digest(struct ahash_request *req) 13528c2ecf20Sopenharmony_ci{ 13538c2ecf20Sopenharmony_ci int ret; 13548c2ecf20Sopenharmony_ci 13558c2ecf20Sopenharmony_ci ret = mv_cesa_ahmac_sha1_init(req); 13568c2ecf20Sopenharmony_ci if (ret) 13578c2ecf20Sopenharmony_ci return ret; 13588c2ecf20Sopenharmony_ci 13598c2ecf20Sopenharmony_ci return mv_cesa_ahash_finup(req); 13608c2ecf20Sopenharmony_ci} 13618c2ecf20Sopenharmony_ci 13628c2ecf20Sopenharmony_cistruct ahash_alg mv_ahmac_sha1_alg = { 13638c2ecf20Sopenharmony_ci .init = mv_cesa_ahmac_sha1_init, 13648c2ecf20Sopenharmony_ci .update = mv_cesa_ahash_update, 13658c2ecf20Sopenharmony_ci .final = mv_cesa_ahash_final, 13668c2ecf20Sopenharmony_ci .finup = mv_cesa_ahash_finup, 13678c2ecf20Sopenharmony_ci .digest = mv_cesa_ahmac_sha1_digest, 13688c2ecf20Sopenharmony_ci .setkey = mv_cesa_ahmac_sha1_setkey, 13698c2ecf20Sopenharmony_ci .export = mv_cesa_sha1_export, 13708c2ecf20Sopenharmony_ci .import = mv_cesa_sha1_import, 13718c2ecf20Sopenharmony_ci .halg = { 13728c2ecf20Sopenharmony_ci .digestsize = SHA1_DIGEST_SIZE, 13738c2ecf20Sopenharmony_ci .statesize = sizeof(struct sha1_state), 13748c2ecf20Sopenharmony_ci .base = { 13758c2ecf20Sopenharmony_ci .cra_name = "hmac(sha1)", 13768c2ecf20Sopenharmony_ci .cra_driver_name = "mv-hmac-sha1", 13778c2ecf20Sopenharmony_ci .cra_priority = 300, 13788c2ecf20Sopenharmony_ci .cra_flags = CRYPTO_ALG_ASYNC | 13798c2ecf20Sopenharmony_ci CRYPTO_ALG_ALLOCATES_MEMORY | 13808c2ecf20Sopenharmony_ci CRYPTO_ALG_KERN_DRIVER_ONLY, 13818c2ecf20Sopenharmony_ci .cra_blocksize = SHA1_BLOCK_SIZE, 13828c2ecf20Sopenharmony_ci .cra_ctxsize = sizeof(struct mv_cesa_hmac_ctx), 13838c2ecf20Sopenharmony_ci .cra_init = mv_cesa_ahmac_cra_init, 13848c2ecf20Sopenharmony_ci .cra_module = THIS_MODULE, 13858c2ecf20Sopenharmony_ci } 13868c2ecf20Sopenharmony_ci } 13878c2ecf20Sopenharmony_ci}; 13888c2ecf20Sopenharmony_ci 13898c2ecf20Sopenharmony_cistatic int mv_cesa_ahmac_sha256_setkey(struct crypto_ahash *tfm, const u8 *key, 13908c2ecf20Sopenharmony_ci unsigned int keylen) 13918c2ecf20Sopenharmony_ci{ 13928c2ecf20Sopenharmony_ci struct mv_cesa_hmac_ctx *ctx = crypto_tfm_ctx(crypto_ahash_tfm(tfm)); 13938c2ecf20Sopenharmony_ci struct sha256_state istate, ostate; 13948c2ecf20Sopenharmony_ci int ret, i; 13958c2ecf20Sopenharmony_ci 13968c2ecf20Sopenharmony_ci ret = mv_cesa_ahmac_setkey("mv-sha256", key, keylen, &istate, &ostate); 13978c2ecf20Sopenharmony_ci if (ret) 13988c2ecf20Sopenharmony_ci return ret; 13998c2ecf20Sopenharmony_ci 14008c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(istate.state); i++) 14018c2ecf20Sopenharmony_ci ctx->iv[i] = cpu_to_be32(istate.state[i]); 14028c2ecf20Sopenharmony_ci 14038c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(ostate.state); i++) 14048c2ecf20Sopenharmony_ci ctx->iv[i + 8] = cpu_to_be32(ostate.state[i]); 14058c2ecf20Sopenharmony_ci 14068c2ecf20Sopenharmony_ci return 0; 14078c2ecf20Sopenharmony_ci} 14088c2ecf20Sopenharmony_ci 14098c2ecf20Sopenharmony_cistatic int mv_cesa_ahmac_sha256_init(struct ahash_request *req) 14108c2ecf20Sopenharmony_ci{ 14118c2ecf20Sopenharmony_ci struct mv_cesa_hmac_ctx *ctx = crypto_tfm_ctx(req->base.tfm); 14128c2ecf20Sopenharmony_ci struct mv_cesa_op_ctx tmpl = { }; 14138c2ecf20Sopenharmony_ci 14148c2ecf20Sopenharmony_ci mv_cesa_set_op_cfg(&tmpl, CESA_SA_DESC_CFG_MACM_HMAC_SHA256); 14158c2ecf20Sopenharmony_ci memcpy(tmpl.ctx.hash.iv, ctx->iv, sizeof(ctx->iv)); 14168c2ecf20Sopenharmony_ci 14178c2ecf20Sopenharmony_ci mv_cesa_ahash_init(req, &tmpl, false); 14188c2ecf20Sopenharmony_ci 14198c2ecf20Sopenharmony_ci return 0; 14208c2ecf20Sopenharmony_ci} 14218c2ecf20Sopenharmony_ci 14228c2ecf20Sopenharmony_cistatic int mv_cesa_ahmac_sha256_digest(struct ahash_request *req) 14238c2ecf20Sopenharmony_ci{ 14248c2ecf20Sopenharmony_ci int ret; 14258c2ecf20Sopenharmony_ci 14268c2ecf20Sopenharmony_ci ret = mv_cesa_ahmac_sha256_init(req); 14278c2ecf20Sopenharmony_ci if (ret) 14288c2ecf20Sopenharmony_ci return ret; 14298c2ecf20Sopenharmony_ci 14308c2ecf20Sopenharmony_ci return mv_cesa_ahash_finup(req); 14318c2ecf20Sopenharmony_ci} 14328c2ecf20Sopenharmony_ci 14338c2ecf20Sopenharmony_cistruct ahash_alg mv_ahmac_sha256_alg = { 14348c2ecf20Sopenharmony_ci .init = mv_cesa_ahmac_sha256_init, 14358c2ecf20Sopenharmony_ci .update = mv_cesa_ahash_update, 14368c2ecf20Sopenharmony_ci .final = mv_cesa_ahash_final, 14378c2ecf20Sopenharmony_ci .finup = mv_cesa_ahash_finup, 14388c2ecf20Sopenharmony_ci .digest = mv_cesa_ahmac_sha256_digest, 14398c2ecf20Sopenharmony_ci .setkey = mv_cesa_ahmac_sha256_setkey, 14408c2ecf20Sopenharmony_ci .export = mv_cesa_sha256_export, 14418c2ecf20Sopenharmony_ci .import = mv_cesa_sha256_import, 14428c2ecf20Sopenharmony_ci .halg = { 14438c2ecf20Sopenharmony_ci .digestsize = SHA256_DIGEST_SIZE, 14448c2ecf20Sopenharmony_ci .statesize = sizeof(struct sha256_state), 14458c2ecf20Sopenharmony_ci .base = { 14468c2ecf20Sopenharmony_ci .cra_name = "hmac(sha256)", 14478c2ecf20Sopenharmony_ci .cra_driver_name = "mv-hmac-sha256", 14488c2ecf20Sopenharmony_ci .cra_priority = 300, 14498c2ecf20Sopenharmony_ci .cra_flags = CRYPTO_ALG_ASYNC | 14508c2ecf20Sopenharmony_ci CRYPTO_ALG_ALLOCATES_MEMORY | 14518c2ecf20Sopenharmony_ci CRYPTO_ALG_KERN_DRIVER_ONLY, 14528c2ecf20Sopenharmony_ci .cra_blocksize = SHA256_BLOCK_SIZE, 14538c2ecf20Sopenharmony_ci .cra_ctxsize = sizeof(struct mv_cesa_hmac_ctx), 14548c2ecf20Sopenharmony_ci .cra_init = mv_cesa_ahmac_cra_init, 14558c2ecf20Sopenharmony_ci .cra_module = THIS_MODULE, 14568c2ecf20Sopenharmony_ci } 14578c2ecf20Sopenharmony_ci } 14588c2ecf20Sopenharmony_ci}; 1459