18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* Copyright (c) 2019 HiSilicon Limited. */ 38c2ecf20Sopenharmony_ci#include <crypto/akcipher.h> 48c2ecf20Sopenharmony_ci#include <crypto/dh.h> 58c2ecf20Sopenharmony_ci#include <crypto/internal/akcipher.h> 68c2ecf20Sopenharmony_ci#include <crypto/internal/kpp.h> 78c2ecf20Sopenharmony_ci#include <crypto/internal/rsa.h> 88c2ecf20Sopenharmony_ci#include <crypto/kpp.h> 98c2ecf20Sopenharmony_ci#include <crypto/scatterwalk.h> 108c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h> 118c2ecf20Sopenharmony_ci#include <linux/fips.h> 128c2ecf20Sopenharmony_ci#include <linux/module.h> 138c2ecf20Sopenharmony_ci#include <linux/time.h> 148c2ecf20Sopenharmony_ci#include "hpre.h" 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_cistruct hpre_ctx; 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#define HPRE_CRYPTO_ALG_PRI 1000 198c2ecf20Sopenharmony_ci#define HPRE_ALIGN_SZ 64 208c2ecf20Sopenharmony_ci#define HPRE_BITS_2_BYTES_SHIFT 3 218c2ecf20Sopenharmony_ci#define HPRE_RSA_512BITS_KSZ 64 228c2ecf20Sopenharmony_ci#define HPRE_RSA_1536BITS_KSZ 192 238c2ecf20Sopenharmony_ci#define HPRE_CRT_PRMS 5 248c2ecf20Sopenharmony_ci#define HPRE_CRT_Q 2 258c2ecf20Sopenharmony_ci#define HPRE_CRT_P 3 268c2ecf20Sopenharmony_ci#define HPRE_CRT_INV 4 278c2ecf20Sopenharmony_ci#define HPRE_DH_G_FLAG 0x02 288c2ecf20Sopenharmony_ci#define HPRE_TRY_SEND_TIMES 100 298c2ecf20Sopenharmony_ci#define HPRE_INVLD_REQ_ID (-1) 308c2ecf20Sopenharmony_ci#define HPRE_DEV(ctx) (&((ctx)->qp->qm->pdev->dev)) 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci#define HPRE_SQE_ALG_BITS 5 338c2ecf20Sopenharmony_ci#define HPRE_SQE_DONE_SHIFT 30 348c2ecf20Sopenharmony_ci#define HPRE_DH_MAX_P_SZ 512 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci#define HPRE_DFX_SEC_TO_US 1000000 378c2ecf20Sopenharmony_ci#define HPRE_DFX_US_TO_NS 1000 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_citypedef void (*hpre_cb)(struct hpre_ctx *ctx, void *sqe); 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_cistruct hpre_rsa_ctx { 428c2ecf20Sopenharmony_ci /* low address: e--->n */ 438c2ecf20Sopenharmony_ci char *pubkey; 448c2ecf20Sopenharmony_ci dma_addr_t dma_pubkey; 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci /* low address: d--->n */ 478c2ecf20Sopenharmony_ci char *prikey; 488c2ecf20Sopenharmony_ci dma_addr_t dma_prikey; 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci /* low address: dq->dp->q->p->qinv */ 518c2ecf20Sopenharmony_ci char *crt_prikey; 528c2ecf20Sopenharmony_ci dma_addr_t dma_crt_prikey; 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci struct crypto_akcipher *soft_tfm; 558c2ecf20Sopenharmony_ci}; 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_cistruct hpre_dh_ctx { 588c2ecf20Sopenharmony_ci /* 598c2ecf20Sopenharmony_ci * If base is g we compute the public key 608c2ecf20Sopenharmony_ci * ya = g^xa mod p; [RFC2631 sec 2.1.1] 618c2ecf20Sopenharmony_ci * else if base if the counterpart public key we 628c2ecf20Sopenharmony_ci * compute the shared secret 638c2ecf20Sopenharmony_ci * ZZ = yb^xa mod p; [RFC2631 sec 2.1.1] 648c2ecf20Sopenharmony_ci */ 658c2ecf20Sopenharmony_ci char *xa_p; /* low address: d--->n, please refer to Hisilicon HPRE UM */ 668c2ecf20Sopenharmony_ci dma_addr_t dma_xa_p; 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci char *g; /* m */ 698c2ecf20Sopenharmony_ci dma_addr_t dma_g; 708c2ecf20Sopenharmony_ci}; 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_cistruct hpre_ctx { 738c2ecf20Sopenharmony_ci struct hisi_qp *qp; 748c2ecf20Sopenharmony_ci struct hpre_asym_request **req_list; 758c2ecf20Sopenharmony_ci struct hpre *hpre; 768c2ecf20Sopenharmony_ci spinlock_t req_lock; 778c2ecf20Sopenharmony_ci unsigned int key_sz; 788c2ecf20Sopenharmony_ci bool crt_g2_mode; 798c2ecf20Sopenharmony_ci struct idr req_idr; 808c2ecf20Sopenharmony_ci union { 818c2ecf20Sopenharmony_ci struct hpre_rsa_ctx rsa; 828c2ecf20Sopenharmony_ci struct hpre_dh_ctx dh; 838c2ecf20Sopenharmony_ci }; 848c2ecf20Sopenharmony_ci}; 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_cistruct hpre_asym_request { 878c2ecf20Sopenharmony_ci char *src; 888c2ecf20Sopenharmony_ci char *dst; 898c2ecf20Sopenharmony_ci struct hpre_sqe req; 908c2ecf20Sopenharmony_ci struct hpre_ctx *ctx; 918c2ecf20Sopenharmony_ci union { 928c2ecf20Sopenharmony_ci struct akcipher_request *rsa; 938c2ecf20Sopenharmony_ci struct kpp_request *dh; 948c2ecf20Sopenharmony_ci } areq; 958c2ecf20Sopenharmony_ci int err; 968c2ecf20Sopenharmony_ci int req_id; 978c2ecf20Sopenharmony_ci hpre_cb cb; 988c2ecf20Sopenharmony_ci struct timespec64 req_time; 998c2ecf20Sopenharmony_ci}; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_cistatic int hpre_alloc_req_id(struct hpre_ctx *ctx) 1028c2ecf20Sopenharmony_ci{ 1038c2ecf20Sopenharmony_ci unsigned long flags; 1048c2ecf20Sopenharmony_ci int id; 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci spin_lock_irqsave(&ctx->req_lock, flags); 1078c2ecf20Sopenharmony_ci id = idr_alloc(&ctx->req_idr, NULL, 0, QM_Q_DEPTH, GFP_ATOMIC); 1088c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ctx->req_lock, flags); 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci return id; 1118c2ecf20Sopenharmony_ci} 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_cistatic void hpre_free_req_id(struct hpre_ctx *ctx, int req_id) 1148c2ecf20Sopenharmony_ci{ 1158c2ecf20Sopenharmony_ci unsigned long flags; 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci spin_lock_irqsave(&ctx->req_lock, flags); 1188c2ecf20Sopenharmony_ci idr_remove(&ctx->req_idr, req_id); 1198c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ctx->req_lock, flags); 1208c2ecf20Sopenharmony_ci} 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_cistatic int hpre_add_req_to_ctx(struct hpre_asym_request *hpre_req) 1238c2ecf20Sopenharmony_ci{ 1248c2ecf20Sopenharmony_ci struct hpre_ctx *ctx; 1258c2ecf20Sopenharmony_ci struct hpre_dfx *dfx; 1268c2ecf20Sopenharmony_ci int id; 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci ctx = hpre_req->ctx; 1298c2ecf20Sopenharmony_ci id = hpre_alloc_req_id(ctx); 1308c2ecf20Sopenharmony_ci if (unlikely(id < 0)) 1318c2ecf20Sopenharmony_ci return -EINVAL; 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci ctx->req_list[id] = hpre_req; 1348c2ecf20Sopenharmony_ci hpre_req->req_id = id; 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci dfx = ctx->hpre->debug.dfx; 1378c2ecf20Sopenharmony_ci if (atomic64_read(&dfx[HPRE_OVERTIME_THRHLD].value)) 1388c2ecf20Sopenharmony_ci ktime_get_ts64(&hpre_req->req_time); 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci return id; 1418c2ecf20Sopenharmony_ci} 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_cistatic void hpre_rm_req_from_ctx(struct hpre_asym_request *hpre_req) 1448c2ecf20Sopenharmony_ci{ 1458c2ecf20Sopenharmony_ci struct hpre_ctx *ctx = hpre_req->ctx; 1468c2ecf20Sopenharmony_ci int id = hpre_req->req_id; 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci if (hpre_req->req_id >= 0) { 1498c2ecf20Sopenharmony_ci hpre_req->req_id = HPRE_INVLD_REQ_ID; 1508c2ecf20Sopenharmony_ci ctx->req_list[id] = NULL; 1518c2ecf20Sopenharmony_ci hpre_free_req_id(ctx, id); 1528c2ecf20Sopenharmony_ci } 1538c2ecf20Sopenharmony_ci} 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_cistatic struct hisi_qp *hpre_get_qp_and_start(void) 1568c2ecf20Sopenharmony_ci{ 1578c2ecf20Sopenharmony_ci struct hisi_qp *qp; 1588c2ecf20Sopenharmony_ci int ret; 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci qp = hpre_create_qp(); 1618c2ecf20Sopenharmony_ci if (!qp) { 1628c2ecf20Sopenharmony_ci pr_err("Can not create hpre qp!\n"); 1638c2ecf20Sopenharmony_ci return ERR_PTR(-ENODEV); 1648c2ecf20Sopenharmony_ci } 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci ret = hisi_qm_start_qp(qp, 0); 1678c2ecf20Sopenharmony_ci if (ret < 0) { 1688c2ecf20Sopenharmony_ci hisi_qm_free_qps(&qp, 1); 1698c2ecf20Sopenharmony_ci pci_err(qp->qm->pdev, "Can not start qp!\n"); 1708c2ecf20Sopenharmony_ci return ERR_PTR(-EINVAL); 1718c2ecf20Sopenharmony_ci } 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci return qp; 1748c2ecf20Sopenharmony_ci} 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_cistatic int hpre_get_data_dma_addr(struct hpre_asym_request *hpre_req, 1778c2ecf20Sopenharmony_ci struct scatterlist *data, unsigned int len, 1788c2ecf20Sopenharmony_ci int is_src, dma_addr_t *tmp) 1798c2ecf20Sopenharmony_ci{ 1808c2ecf20Sopenharmony_ci struct hpre_ctx *ctx = hpre_req->ctx; 1818c2ecf20Sopenharmony_ci struct device *dev = HPRE_DEV(ctx); 1828c2ecf20Sopenharmony_ci enum dma_data_direction dma_dir; 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci if (is_src) { 1858c2ecf20Sopenharmony_ci hpre_req->src = NULL; 1868c2ecf20Sopenharmony_ci dma_dir = DMA_TO_DEVICE; 1878c2ecf20Sopenharmony_ci } else { 1888c2ecf20Sopenharmony_ci hpre_req->dst = NULL; 1898c2ecf20Sopenharmony_ci dma_dir = DMA_FROM_DEVICE; 1908c2ecf20Sopenharmony_ci } 1918c2ecf20Sopenharmony_ci *tmp = dma_map_single(dev, sg_virt(data), len, dma_dir); 1928c2ecf20Sopenharmony_ci if (unlikely(dma_mapping_error(dev, *tmp))) { 1938c2ecf20Sopenharmony_ci dev_err(dev, "dma map data err!\n"); 1948c2ecf20Sopenharmony_ci return -ENOMEM; 1958c2ecf20Sopenharmony_ci } 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci return 0; 1988c2ecf20Sopenharmony_ci} 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_cistatic int hpre_prepare_dma_buf(struct hpre_asym_request *hpre_req, 2018c2ecf20Sopenharmony_ci struct scatterlist *data, unsigned int len, 2028c2ecf20Sopenharmony_ci int is_src, dma_addr_t *tmp) 2038c2ecf20Sopenharmony_ci{ 2048c2ecf20Sopenharmony_ci struct hpre_ctx *ctx = hpre_req->ctx; 2058c2ecf20Sopenharmony_ci struct device *dev = HPRE_DEV(ctx); 2068c2ecf20Sopenharmony_ci void *ptr; 2078c2ecf20Sopenharmony_ci int shift; 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci shift = ctx->key_sz - len; 2108c2ecf20Sopenharmony_ci if (unlikely(shift < 0)) 2118c2ecf20Sopenharmony_ci return -EINVAL; 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci ptr = dma_alloc_coherent(dev, ctx->key_sz, tmp, GFP_ATOMIC); 2148c2ecf20Sopenharmony_ci if (unlikely(!ptr)) 2158c2ecf20Sopenharmony_ci return -ENOMEM; 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci if (is_src) { 2188c2ecf20Sopenharmony_ci scatterwalk_map_and_copy(ptr + shift, data, 0, len, 0); 2198c2ecf20Sopenharmony_ci hpre_req->src = ptr; 2208c2ecf20Sopenharmony_ci } else { 2218c2ecf20Sopenharmony_ci hpre_req->dst = ptr; 2228c2ecf20Sopenharmony_ci } 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci return 0; 2258c2ecf20Sopenharmony_ci} 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_cistatic int hpre_hw_data_init(struct hpre_asym_request *hpre_req, 2288c2ecf20Sopenharmony_ci struct scatterlist *data, unsigned int len, 2298c2ecf20Sopenharmony_ci int is_src, int is_dh) 2308c2ecf20Sopenharmony_ci{ 2318c2ecf20Sopenharmony_ci struct hpre_sqe *msg = &hpre_req->req; 2328c2ecf20Sopenharmony_ci struct hpre_ctx *ctx = hpre_req->ctx; 2338c2ecf20Sopenharmony_ci dma_addr_t tmp = 0; 2348c2ecf20Sopenharmony_ci int ret; 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci /* when the data is dh's source, we should format it */ 2378c2ecf20Sopenharmony_ci if ((sg_is_last(data) && len == ctx->key_sz) && 2388c2ecf20Sopenharmony_ci ((is_dh && !is_src) || !is_dh)) 2398c2ecf20Sopenharmony_ci ret = hpre_get_data_dma_addr(hpre_req, data, len, is_src, &tmp); 2408c2ecf20Sopenharmony_ci else 2418c2ecf20Sopenharmony_ci ret = hpre_prepare_dma_buf(hpre_req, data, len, is_src, &tmp); 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci if (unlikely(ret)) 2448c2ecf20Sopenharmony_ci return ret; 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci if (is_src) 2478c2ecf20Sopenharmony_ci msg->in = cpu_to_le64(tmp); 2488c2ecf20Sopenharmony_ci else 2498c2ecf20Sopenharmony_ci msg->out = cpu_to_le64(tmp); 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci return 0; 2528c2ecf20Sopenharmony_ci} 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_cistatic void hpre_hw_data_clr_all(struct hpre_ctx *ctx, 2558c2ecf20Sopenharmony_ci struct hpre_asym_request *req, 2568c2ecf20Sopenharmony_ci struct scatterlist *dst, 2578c2ecf20Sopenharmony_ci struct scatterlist *src) 2588c2ecf20Sopenharmony_ci{ 2598c2ecf20Sopenharmony_ci struct device *dev = HPRE_DEV(ctx); 2608c2ecf20Sopenharmony_ci struct hpre_sqe *sqe = &req->req; 2618c2ecf20Sopenharmony_ci dma_addr_t tmp; 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci tmp = le64_to_cpu(sqe->in); 2648c2ecf20Sopenharmony_ci if (unlikely(!tmp)) 2658c2ecf20Sopenharmony_ci return; 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci if (src) { 2688c2ecf20Sopenharmony_ci if (req->src) 2698c2ecf20Sopenharmony_ci dma_free_coherent(dev, ctx->key_sz, req->src, tmp); 2708c2ecf20Sopenharmony_ci else 2718c2ecf20Sopenharmony_ci dma_unmap_single(dev, tmp, ctx->key_sz, DMA_TO_DEVICE); 2728c2ecf20Sopenharmony_ci } 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci tmp = le64_to_cpu(sqe->out); 2758c2ecf20Sopenharmony_ci if (unlikely(!tmp)) 2768c2ecf20Sopenharmony_ci return; 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci if (req->dst) { 2798c2ecf20Sopenharmony_ci if (dst) 2808c2ecf20Sopenharmony_ci scatterwalk_map_and_copy(req->dst, dst, 0, 2818c2ecf20Sopenharmony_ci ctx->key_sz, 1); 2828c2ecf20Sopenharmony_ci dma_free_coherent(dev, ctx->key_sz, req->dst, tmp); 2838c2ecf20Sopenharmony_ci } else { 2848c2ecf20Sopenharmony_ci dma_unmap_single(dev, tmp, ctx->key_sz, DMA_FROM_DEVICE); 2858c2ecf20Sopenharmony_ci } 2868c2ecf20Sopenharmony_ci} 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_cistatic int hpre_alg_res_post_hf(struct hpre_ctx *ctx, struct hpre_sqe *sqe, 2898c2ecf20Sopenharmony_ci void **kreq) 2908c2ecf20Sopenharmony_ci{ 2918c2ecf20Sopenharmony_ci struct hpre_asym_request *req; 2928c2ecf20Sopenharmony_ci int err, id, done; 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci#define HPRE_NO_HW_ERR 0 2958c2ecf20Sopenharmony_ci#define HPRE_HW_TASK_DONE 3 2968c2ecf20Sopenharmony_ci#define HREE_HW_ERR_MASK 0x7ff 2978c2ecf20Sopenharmony_ci#define HREE_SQE_DONE_MASK 0x3 2988c2ecf20Sopenharmony_ci id = (int)le16_to_cpu(sqe->tag); 2998c2ecf20Sopenharmony_ci req = ctx->req_list[id]; 3008c2ecf20Sopenharmony_ci hpre_rm_req_from_ctx(req); 3018c2ecf20Sopenharmony_ci *kreq = req; 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci err = (le32_to_cpu(sqe->dw0) >> HPRE_SQE_ALG_BITS) & 3048c2ecf20Sopenharmony_ci HREE_HW_ERR_MASK; 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci done = (le32_to_cpu(sqe->dw0) >> HPRE_SQE_DONE_SHIFT) & 3078c2ecf20Sopenharmony_ci HREE_SQE_DONE_MASK; 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci if (likely(err == HPRE_NO_HW_ERR && done == HPRE_HW_TASK_DONE)) 3108c2ecf20Sopenharmony_ci return 0; 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci return -EINVAL; 3138c2ecf20Sopenharmony_ci} 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_cistatic int hpre_ctx_set(struct hpre_ctx *ctx, struct hisi_qp *qp, int qlen) 3168c2ecf20Sopenharmony_ci{ 3178c2ecf20Sopenharmony_ci struct hpre *hpre; 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci if (!ctx || !qp || qlen < 0) 3208c2ecf20Sopenharmony_ci return -EINVAL; 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci spin_lock_init(&ctx->req_lock); 3238c2ecf20Sopenharmony_ci ctx->qp = qp; 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci hpre = container_of(ctx->qp->qm, struct hpre, qm); 3268c2ecf20Sopenharmony_ci ctx->hpre = hpre; 3278c2ecf20Sopenharmony_ci ctx->req_list = kcalloc(qlen, sizeof(void *), GFP_KERNEL); 3288c2ecf20Sopenharmony_ci if (!ctx->req_list) 3298c2ecf20Sopenharmony_ci return -ENOMEM; 3308c2ecf20Sopenharmony_ci ctx->key_sz = 0; 3318c2ecf20Sopenharmony_ci ctx->crt_g2_mode = false; 3328c2ecf20Sopenharmony_ci idr_init(&ctx->req_idr); 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci return 0; 3358c2ecf20Sopenharmony_ci} 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_cistatic void hpre_ctx_clear(struct hpre_ctx *ctx, bool is_clear_all) 3388c2ecf20Sopenharmony_ci{ 3398c2ecf20Sopenharmony_ci if (is_clear_all) { 3408c2ecf20Sopenharmony_ci idr_destroy(&ctx->req_idr); 3418c2ecf20Sopenharmony_ci kfree(ctx->req_list); 3428c2ecf20Sopenharmony_ci hisi_qm_free_qps(&ctx->qp, 1); 3438c2ecf20Sopenharmony_ci } 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci ctx->crt_g2_mode = false; 3468c2ecf20Sopenharmony_ci ctx->key_sz = 0; 3478c2ecf20Sopenharmony_ci} 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_cistatic bool hpre_is_bd_timeout(struct hpre_asym_request *req, 3508c2ecf20Sopenharmony_ci u64 overtime_thrhld) 3518c2ecf20Sopenharmony_ci{ 3528c2ecf20Sopenharmony_ci struct timespec64 reply_time; 3538c2ecf20Sopenharmony_ci u64 time_use_us; 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci ktime_get_ts64(&reply_time); 3568c2ecf20Sopenharmony_ci time_use_us = (reply_time.tv_sec - req->req_time.tv_sec) * 3578c2ecf20Sopenharmony_ci HPRE_DFX_SEC_TO_US + 3588c2ecf20Sopenharmony_ci (reply_time.tv_nsec - req->req_time.tv_nsec) / 3598c2ecf20Sopenharmony_ci HPRE_DFX_US_TO_NS; 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci if (time_use_us <= overtime_thrhld) 3628c2ecf20Sopenharmony_ci return false; 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci return true; 3658c2ecf20Sopenharmony_ci} 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_cistatic void hpre_dh_cb(struct hpre_ctx *ctx, void *resp) 3688c2ecf20Sopenharmony_ci{ 3698c2ecf20Sopenharmony_ci struct hpre_dfx *dfx = ctx->hpre->debug.dfx; 3708c2ecf20Sopenharmony_ci struct hpre_asym_request *req; 3718c2ecf20Sopenharmony_ci struct kpp_request *areq; 3728c2ecf20Sopenharmony_ci u64 overtime_thrhld; 3738c2ecf20Sopenharmony_ci int ret; 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci ret = hpre_alg_res_post_hf(ctx, resp, (void **)&req); 3768c2ecf20Sopenharmony_ci areq = req->areq.dh; 3778c2ecf20Sopenharmony_ci areq->dst_len = ctx->key_sz; 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci overtime_thrhld = atomic64_read(&dfx[HPRE_OVERTIME_THRHLD].value); 3808c2ecf20Sopenharmony_ci if (overtime_thrhld && hpre_is_bd_timeout(req, overtime_thrhld)) 3818c2ecf20Sopenharmony_ci atomic64_inc(&dfx[HPRE_OVER_THRHLD_CNT].value); 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci hpre_hw_data_clr_all(ctx, req, areq->dst, areq->src); 3848c2ecf20Sopenharmony_ci kpp_request_complete(areq, ret); 3858c2ecf20Sopenharmony_ci atomic64_inc(&dfx[HPRE_RECV_CNT].value); 3868c2ecf20Sopenharmony_ci} 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_cistatic void hpre_rsa_cb(struct hpre_ctx *ctx, void *resp) 3898c2ecf20Sopenharmony_ci{ 3908c2ecf20Sopenharmony_ci struct hpre_dfx *dfx = ctx->hpre->debug.dfx; 3918c2ecf20Sopenharmony_ci struct hpre_asym_request *req; 3928c2ecf20Sopenharmony_ci struct akcipher_request *areq; 3938c2ecf20Sopenharmony_ci u64 overtime_thrhld; 3948c2ecf20Sopenharmony_ci int ret; 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci ret = hpre_alg_res_post_hf(ctx, resp, (void **)&req); 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci overtime_thrhld = atomic64_read(&dfx[HPRE_OVERTIME_THRHLD].value); 3998c2ecf20Sopenharmony_ci if (overtime_thrhld && hpre_is_bd_timeout(req, overtime_thrhld)) 4008c2ecf20Sopenharmony_ci atomic64_inc(&dfx[HPRE_OVER_THRHLD_CNT].value); 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci areq = req->areq.rsa; 4038c2ecf20Sopenharmony_ci areq->dst_len = ctx->key_sz; 4048c2ecf20Sopenharmony_ci hpre_hw_data_clr_all(ctx, req, areq->dst, areq->src); 4058c2ecf20Sopenharmony_ci akcipher_request_complete(areq, ret); 4068c2ecf20Sopenharmony_ci atomic64_inc(&dfx[HPRE_RECV_CNT].value); 4078c2ecf20Sopenharmony_ci} 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_cistatic void hpre_alg_cb(struct hisi_qp *qp, void *resp) 4108c2ecf20Sopenharmony_ci{ 4118c2ecf20Sopenharmony_ci struct hpre_ctx *ctx = qp->qp_ctx; 4128c2ecf20Sopenharmony_ci struct hpre_dfx *dfx = ctx->hpre->debug.dfx; 4138c2ecf20Sopenharmony_ci struct hpre_sqe *sqe = resp; 4148c2ecf20Sopenharmony_ci struct hpre_asym_request *req = ctx->req_list[le16_to_cpu(sqe->tag)]; 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci if (unlikely(!req)) { 4188c2ecf20Sopenharmony_ci atomic64_inc(&dfx[HPRE_INVALID_REQ_CNT].value); 4198c2ecf20Sopenharmony_ci return; 4208c2ecf20Sopenharmony_ci } 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci req->cb(ctx, resp); 4238c2ecf20Sopenharmony_ci} 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_cistatic int hpre_ctx_init(struct hpre_ctx *ctx) 4268c2ecf20Sopenharmony_ci{ 4278c2ecf20Sopenharmony_ci struct hisi_qp *qp; 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci qp = hpre_get_qp_and_start(); 4308c2ecf20Sopenharmony_ci if (IS_ERR(qp)) 4318c2ecf20Sopenharmony_ci return PTR_ERR(qp); 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci qp->qp_ctx = ctx; 4348c2ecf20Sopenharmony_ci qp->req_cb = hpre_alg_cb; 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci return hpre_ctx_set(ctx, qp, QM_Q_DEPTH); 4378c2ecf20Sopenharmony_ci} 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_cistatic int hpre_msg_request_set(struct hpre_ctx *ctx, void *req, bool is_rsa) 4408c2ecf20Sopenharmony_ci{ 4418c2ecf20Sopenharmony_ci struct hpre_asym_request *h_req; 4428c2ecf20Sopenharmony_ci struct hpre_sqe *msg; 4438c2ecf20Sopenharmony_ci int req_id; 4448c2ecf20Sopenharmony_ci void *tmp; 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ci if (is_rsa) { 4478c2ecf20Sopenharmony_ci struct akcipher_request *akreq = req; 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci if (akreq->dst_len < ctx->key_sz) { 4508c2ecf20Sopenharmony_ci akreq->dst_len = ctx->key_sz; 4518c2ecf20Sopenharmony_ci return -EOVERFLOW; 4528c2ecf20Sopenharmony_ci } 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci tmp = akcipher_request_ctx(akreq); 4558c2ecf20Sopenharmony_ci h_req = PTR_ALIGN(tmp, HPRE_ALIGN_SZ); 4568c2ecf20Sopenharmony_ci h_req->cb = hpre_rsa_cb; 4578c2ecf20Sopenharmony_ci h_req->areq.rsa = akreq; 4588c2ecf20Sopenharmony_ci msg = &h_req->req; 4598c2ecf20Sopenharmony_ci memset(msg, 0, sizeof(*msg)); 4608c2ecf20Sopenharmony_ci } else { 4618c2ecf20Sopenharmony_ci struct kpp_request *kreq = req; 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci if (kreq->dst_len < ctx->key_sz) { 4648c2ecf20Sopenharmony_ci kreq->dst_len = ctx->key_sz; 4658c2ecf20Sopenharmony_ci return -EOVERFLOW; 4668c2ecf20Sopenharmony_ci } 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci tmp = kpp_request_ctx(kreq); 4698c2ecf20Sopenharmony_ci h_req = PTR_ALIGN(tmp, HPRE_ALIGN_SZ); 4708c2ecf20Sopenharmony_ci h_req->cb = hpre_dh_cb; 4718c2ecf20Sopenharmony_ci h_req->areq.dh = kreq; 4728c2ecf20Sopenharmony_ci msg = &h_req->req; 4738c2ecf20Sopenharmony_ci memset(msg, 0, sizeof(*msg)); 4748c2ecf20Sopenharmony_ci msg->key = cpu_to_le64(ctx->dh.dma_xa_p); 4758c2ecf20Sopenharmony_ci } 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_ci msg->dw0 |= cpu_to_le32(0x1 << HPRE_SQE_DONE_SHIFT); 4788c2ecf20Sopenharmony_ci msg->task_len1 = (ctx->key_sz >> HPRE_BITS_2_BYTES_SHIFT) - 1; 4798c2ecf20Sopenharmony_ci h_req->ctx = ctx; 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_ci req_id = hpre_add_req_to_ctx(h_req); 4828c2ecf20Sopenharmony_ci if (req_id < 0) 4838c2ecf20Sopenharmony_ci return -EBUSY; 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci msg->tag = cpu_to_le16((u16)req_id); 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci return 0; 4888c2ecf20Sopenharmony_ci} 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_cistatic int hpre_send(struct hpre_ctx *ctx, struct hpre_sqe *msg) 4918c2ecf20Sopenharmony_ci{ 4928c2ecf20Sopenharmony_ci struct hpre_dfx *dfx = ctx->hpre->debug.dfx; 4938c2ecf20Sopenharmony_ci int ctr = 0; 4948c2ecf20Sopenharmony_ci int ret; 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci do { 4978c2ecf20Sopenharmony_ci atomic64_inc(&dfx[HPRE_SEND_CNT].value); 4988c2ecf20Sopenharmony_ci ret = hisi_qp_send(ctx->qp, msg); 4998c2ecf20Sopenharmony_ci if (ret != -EBUSY) 5008c2ecf20Sopenharmony_ci break; 5018c2ecf20Sopenharmony_ci atomic64_inc(&dfx[HPRE_SEND_BUSY_CNT].value); 5028c2ecf20Sopenharmony_ci } while (ctr++ < HPRE_TRY_SEND_TIMES); 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci if (likely(!ret)) 5058c2ecf20Sopenharmony_ci return ret; 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci if (ret != -EBUSY) 5088c2ecf20Sopenharmony_ci atomic64_inc(&dfx[HPRE_SEND_FAIL_CNT].value); 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_ci return ret; 5118c2ecf20Sopenharmony_ci} 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci#ifdef CONFIG_CRYPTO_DH 5148c2ecf20Sopenharmony_cistatic int hpre_dh_compute_value(struct kpp_request *req) 5158c2ecf20Sopenharmony_ci{ 5168c2ecf20Sopenharmony_ci struct crypto_kpp *tfm = crypto_kpp_reqtfm(req); 5178c2ecf20Sopenharmony_ci struct hpre_ctx *ctx = kpp_tfm_ctx(tfm); 5188c2ecf20Sopenharmony_ci void *tmp = kpp_request_ctx(req); 5198c2ecf20Sopenharmony_ci struct hpre_asym_request *hpre_req = PTR_ALIGN(tmp, HPRE_ALIGN_SZ); 5208c2ecf20Sopenharmony_ci struct hpre_sqe *msg = &hpre_req->req; 5218c2ecf20Sopenharmony_ci int ret; 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_ci ret = hpre_msg_request_set(ctx, req, false); 5248c2ecf20Sopenharmony_ci if (unlikely(ret)) 5258c2ecf20Sopenharmony_ci return ret; 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ci if (req->src) { 5288c2ecf20Sopenharmony_ci ret = hpre_hw_data_init(hpre_req, req->src, req->src_len, 1, 1); 5298c2ecf20Sopenharmony_ci if (unlikely(ret)) 5308c2ecf20Sopenharmony_ci goto clear_all; 5318c2ecf20Sopenharmony_ci } else { 5328c2ecf20Sopenharmony_ci msg->in = cpu_to_le64(ctx->dh.dma_g); 5338c2ecf20Sopenharmony_ci } 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_ci ret = hpre_hw_data_init(hpre_req, req->dst, req->dst_len, 0, 1); 5368c2ecf20Sopenharmony_ci if (unlikely(ret)) 5378c2ecf20Sopenharmony_ci goto clear_all; 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci if (ctx->crt_g2_mode && !req->src) 5408c2ecf20Sopenharmony_ci msg->dw0 = cpu_to_le32(le32_to_cpu(msg->dw0) | HPRE_ALG_DH_G2); 5418c2ecf20Sopenharmony_ci else 5428c2ecf20Sopenharmony_ci msg->dw0 = cpu_to_le32(le32_to_cpu(msg->dw0) | HPRE_ALG_DH); 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_ci /* success */ 5458c2ecf20Sopenharmony_ci ret = hpre_send(ctx, msg); 5468c2ecf20Sopenharmony_ci if (likely(!ret)) 5478c2ecf20Sopenharmony_ci return -EINPROGRESS; 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ciclear_all: 5508c2ecf20Sopenharmony_ci hpre_rm_req_from_ctx(hpre_req); 5518c2ecf20Sopenharmony_ci hpre_hw_data_clr_all(ctx, hpre_req, req->dst, req->src); 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_ci return ret; 5548c2ecf20Sopenharmony_ci} 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_cistatic int hpre_is_dh_params_length_valid(unsigned int key_sz) 5578c2ecf20Sopenharmony_ci{ 5588c2ecf20Sopenharmony_ci#define _HPRE_DH_GRP1 768 5598c2ecf20Sopenharmony_ci#define _HPRE_DH_GRP2 1024 5608c2ecf20Sopenharmony_ci#define _HPRE_DH_GRP5 1536 5618c2ecf20Sopenharmony_ci#define _HPRE_DH_GRP14 2048 5628c2ecf20Sopenharmony_ci#define _HPRE_DH_GRP15 3072 5638c2ecf20Sopenharmony_ci#define _HPRE_DH_GRP16 4096 5648c2ecf20Sopenharmony_ci switch (key_sz) { 5658c2ecf20Sopenharmony_ci case _HPRE_DH_GRP1: 5668c2ecf20Sopenharmony_ci case _HPRE_DH_GRP2: 5678c2ecf20Sopenharmony_ci case _HPRE_DH_GRP5: 5688c2ecf20Sopenharmony_ci case _HPRE_DH_GRP14: 5698c2ecf20Sopenharmony_ci case _HPRE_DH_GRP15: 5708c2ecf20Sopenharmony_ci case _HPRE_DH_GRP16: 5718c2ecf20Sopenharmony_ci return 0; 5728c2ecf20Sopenharmony_ci } 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_ci return -EINVAL; 5758c2ecf20Sopenharmony_ci} 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_cistatic int hpre_dh_set_params(struct hpre_ctx *ctx, struct dh *params) 5788c2ecf20Sopenharmony_ci{ 5798c2ecf20Sopenharmony_ci struct device *dev = HPRE_DEV(ctx); 5808c2ecf20Sopenharmony_ci unsigned int sz; 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_ci if (params->p_size > HPRE_DH_MAX_P_SZ) 5838c2ecf20Sopenharmony_ci return -EINVAL; 5848c2ecf20Sopenharmony_ci 5858c2ecf20Sopenharmony_ci if (hpre_is_dh_params_length_valid(params->p_size << 5868c2ecf20Sopenharmony_ci HPRE_BITS_2_BYTES_SHIFT)) 5878c2ecf20Sopenharmony_ci return -EINVAL; 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_ci sz = ctx->key_sz = params->p_size; 5908c2ecf20Sopenharmony_ci ctx->dh.xa_p = dma_alloc_coherent(dev, sz << 1, 5918c2ecf20Sopenharmony_ci &ctx->dh.dma_xa_p, GFP_KERNEL); 5928c2ecf20Sopenharmony_ci if (!ctx->dh.xa_p) 5938c2ecf20Sopenharmony_ci return -ENOMEM; 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci memcpy(ctx->dh.xa_p + sz, params->p, sz); 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_ci /* If g equals 2 don't copy it */ 5988c2ecf20Sopenharmony_ci if (params->g_size == 1 && *(char *)params->g == HPRE_DH_G_FLAG) { 5998c2ecf20Sopenharmony_ci ctx->crt_g2_mode = true; 6008c2ecf20Sopenharmony_ci return 0; 6018c2ecf20Sopenharmony_ci } 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_ci ctx->dh.g = dma_alloc_coherent(dev, sz, &ctx->dh.dma_g, GFP_KERNEL); 6048c2ecf20Sopenharmony_ci if (!ctx->dh.g) { 6058c2ecf20Sopenharmony_ci dma_free_coherent(dev, sz << 1, ctx->dh.xa_p, 6068c2ecf20Sopenharmony_ci ctx->dh.dma_xa_p); 6078c2ecf20Sopenharmony_ci ctx->dh.xa_p = NULL; 6088c2ecf20Sopenharmony_ci return -ENOMEM; 6098c2ecf20Sopenharmony_ci } 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_ci memcpy(ctx->dh.g + (sz - params->g_size), params->g, params->g_size); 6128c2ecf20Sopenharmony_ci 6138c2ecf20Sopenharmony_ci return 0; 6148c2ecf20Sopenharmony_ci} 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_cistatic void hpre_dh_clear_ctx(struct hpre_ctx *ctx, bool is_clear_all) 6178c2ecf20Sopenharmony_ci{ 6188c2ecf20Sopenharmony_ci struct device *dev = HPRE_DEV(ctx); 6198c2ecf20Sopenharmony_ci unsigned int sz = ctx->key_sz; 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_ci if (is_clear_all) 6228c2ecf20Sopenharmony_ci hisi_qm_stop_qp(ctx->qp); 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_ci if (ctx->dh.g) { 6258c2ecf20Sopenharmony_ci dma_free_coherent(dev, sz, ctx->dh.g, ctx->dh.dma_g); 6268c2ecf20Sopenharmony_ci ctx->dh.g = NULL; 6278c2ecf20Sopenharmony_ci } 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_ci if (ctx->dh.xa_p) { 6308c2ecf20Sopenharmony_ci memzero_explicit(ctx->dh.xa_p, sz); 6318c2ecf20Sopenharmony_ci dma_free_coherent(dev, sz << 1, ctx->dh.xa_p, 6328c2ecf20Sopenharmony_ci ctx->dh.dma_xa_p); 6338c2ecf20Sopenharmony_ci ctx->dh.xa_p = NULL; 6348c2ecf20Sopenharmony_ci } 6358c2ecf20Sopenharmony_ci 6368c2ecf20Sopenharmony_ci hpre_ctx_clear(ctx, is_clear_all); 6378c2ecf20Sopenharmony_ci} 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_cistatic int hpre_dh_set_secret(struct crypto_kpp *tfm, const void *buf, 6408c2ecf20Sopenharmony_ci unsigned int len) 6418c2ecf20Sopenharmony_ci{ 6428c2ecf20Sopenharmony_ci struct hpre_ctx *ctx = kpp_tfm_ctx(tfm); 6438c2ecf20Sopenharmony_ci struct dh params; 6448c2ecf20Sopenharmony_ci int ret; 6458c2ecf20Sopenharmony_ci 6468c2ecf20Sopenharmony_ci if (crypto_dh_decode_key(buf, len, ¶ms) < 0) 6478c2ecf20Sopenharmony_ci return -EINVAL; 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_ci /* Free old secret if any */ 6508c2ecf20Sopenharmony_ci hpre_dh_clear_ctx(ctx, false); 6518c2ecf20Sopenharmony_ci 6528c2ecf20Sopenharmony_ci ret = hpre_dh_set_params(ctx, ¶ms); 6538c2ecf20Sopenharmony_ci if (ret < 0) 6548c2ecf20Sopenharmony_ci goto err_clear_ctx; 6558c2ecf20Sopenharmony_ci 6568c2ecf20Sopenharmony_ci memcpy(ctx->dh.xa_p + (ctx->key_sz - params.key_size), params.key, 6578c2ecf20Sopenharmony_ci params.key_size); 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_ci return 0; 6608c2ecf20Sopenharmony_ci 6618c2ecf20Sopenharmony_cierr_clear_ctx: 6628c2ecf20Sopenharmony_ci hpre_dh_clear_ctx(ctx, false); 6638c2ecf20Sopenharmony_ci return ret; 6648c2ecf20Sopenharmony_ci} 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_cistatic unsigned int hpre_dh_max_size(struct crypto_kpp *tfm) 6678c2ecf20Sopenharmony_ci{ 6688c2ecf20Sopenharmony_ci struct hpre_ctx *ctx = kpp_tfm_ctx(tfm); 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_ci return ctx->key_sz; 6718c2ecf20Sopenharmony_ci} 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_cistatic int hpre_dh_init_tfm(struct crypto_kpp *tfm) 6748c2ecf20Sopenharmony_ci{ 6758c2ecf20Sopenharmony_ci struct hpre_ctx *ctx = kpp_tfm_ctx(tfm); 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_ci return hpre_ctx_init(ctx); 6788c2ecf20Sopenharmony_ci} 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_cistatic void hpre_dh_exit_tfm(struct crypto_kpp *tfm) 6818c2ecf20Sopenharmony_ci{ 6828c2ecf20Sopenharmony_ci struct hpre_ctx *ctx = kpp_tfm_ctx(tfm); 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_ci hpre_dh_clear_ctx(ctx, true); 6858c2ecf20Sopenharmony_ci} 6868c2ecf20Sopenharmony_ci#endif 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_cistatic void hpre_rsa_drop_leading_zeros(const char **ptr, size_t *len) 6898c2ecf20Sopenharmony_ci{ 6908c2ecf20Sopenharmony_ci while (!**ptr && *len) { 6918c2ecf20Sopenharmony_ci (*ptr)++; 6928c2ecf20Sopenharmony_ci (*len)--; 6938c2ecf20Sopenharmony_ci } 6948c2ecf20Sopenharmony_ci} 6958c2ecf20Sopenharmony_ci 6968c2ecf20Sopenharmony_cistatic bool hpre_rsa_key_size_is_support(unsigned int len) 6978c2ecf20Sopenharmony_ci{ 6988c2ecf20Sopenharmony_ci unsigned int bits = len << HPRE_BITS_2_BYTES_SHIFT; 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_ci#define _RSA_1024BITS_KEY_WDTH 1024 7018c2ecf20Sopenharmony_ci#define _RSA_2048BITS_KEY_WDTH 2048 7028c2ecf20Sopenharmony_ci#define _RSA_3072BITS_KEY_WDTH 3072 7038c2ecf20Sopenharmony_ci#define _RSA_4096BITS_KEY_WDTH 4096 7048c2ecf20Sopenharmony_ci 7058c2ecf20Sopenharmony_ci switch (bits) { 7068c2ecf20Sopenharmony_ci case _RSA_1024BITS_KEY_WDTH: 7078c2ecf20Sopenharmony_ci case _RSA_2048BITS_KEY_WDTH: 7088c2ecf20Sopenharmony_ci case _RSA_3072BITS_KEY_WDTH: 7098c2ecf20Sopenharmony_ci case _RSA_4096BITS_KEY_WDTH: 7108c2ecf20Sopenharmony_ci return true; 7118c2ecf20Sopenharmony_ci default: 7128c2ecf20Sopenharmony_ci return false; 7138c2ecf20Sopenharmony_ci } 7148c2ecf20Sopenharmony_ci} 7158c2ecf20Sopenharmony_ci 7168c2ecf20Sopenharmony_cistatic int hpre_rsa_enc(struct akcipher_request *req) 7178c2ecf20Sopenharmony_ci{ 7188c2ecf20Sopenharmony_ci struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req); 7198c2ecf20Sopenharmony_ci struct hpre_ctx *ctx = akcipher_tfm_ctx(tfm); 7208c2ecf20Sopenharmony_ci void *tmp = akcipher_request_ctx(req); 7218c2ecf20Sopenharmony_ci struct hpre_asym_request *hpre_req = PTR_ALIGN(tmp, HPRE_ALIGN_SZ); 7228c2ecf20Sopenharmony_ci struct hpre_sqe *msg = &hpre_req->req; 7238c2ecf20Sopenharmony_ci int ret; 7248c2ecf20Sopenharmony_ci 7258c2ecf20Sopenharmony_ci /* For 512 and 1536 bits key size, use soft tfm instead */ 7268c2ecf20Sopenharmony_ci if (ctx->key_sz == HPRE_RSA_512BITS_KSZ || 7278c2ecf20Sopenharmony_ci ctx->key_sz == HPRE_RSA_1536BITS_KSZ) { 7288c2ecf20Sopenharmony_ci akcipher_request_set_tfm(req, ctx->rsa.soft_tfm); 7298c2ecf20Sopenharmony_ci ret = crypto_akcipher_encrypt(req); 7308c2ecf20Sopenharmony_ci akcipher_request_set_tfm(req, tfm); 7318c2ecf20Sopenharmony_ci return ret; 7328c2ecf20Sopenharmony_ci } 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_ci if (unlikely(!ctx->rsa.pubkey)) 7358c2ecf20Sopenharmony_ci return -EINVAL; 7368c2ecf20Sopenharmony_ci 7378c2ecf20Sopenharmony_ci ret = hpre_msg_request_set(ctx, req, true); 7388c2ecf20Sopenharmony_ci if (unlikely(ret)) 7398c2ecf20Sopenharmony_ci return ret; 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_ci msg->dw0 |= cpu_to_le32(HPRE_ALG_NC_NCRT); 7428c2ecf20Sopenharmony_ci msg->key = cpu_to_le64(ctx->rsa.dma_pubkey); 7438c2ecf20Sopenharmony_ci 7448c2ecf20Sopenharmony_ci ret = hpre_hw_data_init(hpre_req, req->src, req->src_len, 1, 0); 7458c2ecf20Sopenharmony_ci if (unlikely(ret)) 7468c2ecf20Sopenharmony_ci goto clear_all; 7478c2ecf20Sopenharmony_ci 7488c2ecf20Sopenharmony_ci ret = hpre_hw_data_init(hpre_req, req->dst, req->dst_len, 0, 0); 7498c2ecf20Sopenharmony_ci if (unlikely(ret)) 7508c2ecf20Sopenharmony_ci goto clear_all; 7518c2ecf20Sopenharmony_ci 7528c2ecf20Sopenharmony_ci /* success */ 7538c2ecf20Sopenharmony_ci ret = hpre_send(ctx, msg); 7548c2ecf20Sopenharmony_ci if (likely(!ret)) 7558c2ecf20Sopenharmony_ci return -EINPROGRESS; 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_ciclear_all: 7588c2ecf20Sopenharmony_ci hpre_rm_req_from_ctx(hpre_req); 7598c2ecf20Sopenharmony_ci hpre_hw_data_clr_all(ctx, hpre_req, req->dst, req->src); 7608c2ecf20Sopenharmony_ci 7618c2ecf20Sopenharmony_ci return ret; 7628c2ecf20Sopenharmony_ci} 7638c2ecf20Sopenharmony_ci 7648c2ecf20Sopenharmony_cistatic int hpre_rsa_dec(struct akcipher_request *req) 7658c2ecf20Sopenharmony_ci{ 7668c2ecf20Sopenharmony_ci struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req); 7678c2ecf20Sopenharmony_ci struct hpre_ctx *ctx = akcipher_tfm_ctx(tfm); 7688c2ecf20Sopenharmony_ci void *tmp = akcipher_request_ctx(req); 7698c2ecf20Sopenharmony_ci struct hpre_asym_request *hpre_req = PTR_ALIGN(tmp, HPRE_ALIGN_SZ); 7708c2ecf20Sopenharmony_ci struct hpre_sqe *msg = &hpre_req->req; 7718c2ecf20Sopenharmony_ci int ret; 7728c2ecf20Sopenharmony_ci 7738c2ecf20Sopenharmony_ci /* For 512 and 1536 bits key size, use soft tfm instead */ 7748c2ecf20Sopenharmony_ci if (ctx->key_sz == HPRE_RSA_512BITS_KSZ || 7758c2ecf20Sopenharmony_ci ctx->key_sz == HPRE_RSA_1536BITS_KSZ) { 7768c2ecf20Sopenharmony_ci akcipher_request_set_tfm(req, ctx->rsa.soft_tfm); 7778c2ecf20Sopenharmony_ci ret = crypto_akcipher_decrypt(req); 7788c2ecf20Sopenharmony_ci akcipher_request_set_tfm(req, tfm); 7798c2ecf20Sopenharmony_ci return ret; 7808c2ecf20Sopenharmony_ci } 7818c2ecf20Sopenharmony_ci 7828c2ecf20Sopenharmony_ci if (unlikely(!ctx->rsa.prikey)) 7838c2ecf20Sopenharmony_ci return -EINVAL; 7848c2ecf20Sopenharmony_ci 7858c2ecf20Sopenharmony_ci ret = hpre_msg_request_set(ctx, req, true); 7868c2ecf20Sopenharmony_ci if (unlikely(ret)) 7878c2ecf20Sopenharmony_ci return ret; 7888c2ecf20Sopenharmony_ci 7898c2ecf20Sopenharmony_ci if (ctx->crt_g2_mode) { 7908c2ecf20Sopenharmony_ci msg->key = cpu_to_le64(ctx->rsa.dma_crt_prikey); 7918c2ecf20Sopenharmony_ci msg->dw0 = cpu_to_le32(le32_to_cpu(msg->dw0) | 7928c2ecf20Sopenharmony_ci HPRE_ALG_NC_CRT); 7938c2ecf20Sopenharmony_ci } else { 7948c2ecf20Sopenharmony_ci msg->key = cpu_to_le64(ctx->rsa.dma_prikey); 7958c2ecf20Sopenharmony_ci msg->dw0 = cpu_to_le32(le32_to_cpu(msg->dw0) | 7968c2ecf20Sopenharmony_ci HPRE_ALG_NC_NCRT); 7978c2ecf20Sopenharmony_ci } 7988c2ecf20Sopenharmony_ci 7998c2ecf20Sopenharmony_ci ret = hpre_hw_data_init(hpre_req, req->src, req->src_len, 1, 0); 8008c2ecf20Sopenharmony_ci if (unlikely(ret)) 8018c2ecf20Sopenharmony_ci goto clear_all; 8028c2ecf20Sopenharmony_ci 8038c2ecf20Sopenharmony_ci ret = hpre_hw_data_init(hpre_req, req->dst, req->dst_len, 0, 0); 8048c2ecf20Sopenharmony_ci if (unlikely(ret)) 8058c2ecf20Sopenharmony_ci goto clear_all; 8068c2ecf20Sopenharmony_ci 8078c2ecf20Sopenharmony_ci /* success */ 8088c2ecf20Sopenharmony_ci ret = hpre_send(ctx, msg); 8098c2ecf20Sopenharmony_ci if (likely(!ret)) 8108c2ecf20Sopenharmony_ci return -EINPROGRESS; 8118c2ecf20Sopenharmony_ci 8128c2ecf20Sopenharmony_ciclear_all: 8138c2ecf20Sopenharmony_ci hpre_rm_req_from_ctx(hpre_req); 8148c2ecf20Sopenharmony_ci hpre_hw_data_clr_all(ctx, hpre_req, req->dst, req->src); 8158c2ecf20Sopenharmony_ci 8168c2ecf20Sopenharmony_ci return ret; 8178c2ecf20Sopenharmony_ci} 8188c2ecf20Sopenharmony_ci 8198c2ecf20Sopenharmony_cistatic int hpre_rsa_set_n(struct hpre_ctx *ctx, const char *value, 8208c2ecf20Sopenharmony_ci size_t vlen, bool private) 8218c2ecf20Sopenharmony_ci{ 8228c2ecf20Sopenharmony_ci const char *ptr = value; 8238c2ecf20Sopenharmony_ci 8248c2ecf20Sopenharmony_ci hpre_rsa_drop_leading_zeros(&ptr, &vlen); 8258c2ecf20Sopenharmony_ci 8268c2ecf20Sopenharmony_ci ctx->key_sz = vlen; 8278c2ecf20Sopenharmony_ci 8288c2ecf20Sopenharmony_ci /* if invalid key size provided, we use software tfm */ 8298c2ecf20Sopenharmony_ci if (!hpre_rsa_key_size_is_support(ctx->key_sz)) 8308c2ecf20Sopenharmony_ci return 0; 8318c2ecf20Sopenharmony_ci 8328c2ecf20Sopenharmony_ci ctx->rsa.pubkey = dma_alloc_coherent(HPRE_DEV(ctx), vlen << 1, 8338c2ecf20Sopenharmony_ci &ctx->rsa.dma_pubkey, 8348c2ecf20Sopenharmony_ci GFP_KERNEL); 8358c2ecf20Sopenharmony_ci if (!ctx->rsa.pubkey) 8368c2ecf20Sopenharmony_ci return -ENOMEM; 8378c2ecf20Sopenharmony_ci 8388c2ecf20Sopenharmony_ci if (private) { 8398c2ecf20Sopenharmony_ci ctx->rsa.prikey = dma_alloc_coherent(HPRE_DEV(ctx), vlen << 1, 8408c2ecf20Sopenharmony_ci &ctx->rsa.dma_prikey, 8418c2ecf20Sopenharmony_ci GFP_KERNEL); 8428c2ecf20Sopenharmony_ci if (!ctx->rsa.prikey) { 8438c2ecf20Sopenharmony_ci dma_free_coherent(HPRE_DEV(ctx), vlen << 1, 8448c2ecf20Sopenharmony_ci ctx->rsa.pubkey, 8458c2ecf20Sopenharmony_ci ctx->rsa.dma_pubkey); 8468c2ecf20Sopenharmony_ci ctx->rsa.pubkey = NULL; 8478c2ecf20Sopenharmony_ci return -ENOMEM; 8488c2ecf20Sopenharmony_ci } 8498c2ecf20Sopenharmony_ci memcpy(ctx->rsa.prikey + vlen, ptr, vlen); 8508c2ecf20Sopenharmony_ci } 8518c2ecf20Sopenharmony_ci memcpy(ctx->rsa.pubkey + vlen, ptr, vlen); 8528c2ecf20Sopenharmony_ci 8538c2ecf20Sopenharmony_ci /* Using hardware HPRE to do RSA */ 8548c2ecf20Sopenharmony_ci return 1; 8558c2ecf20Sopenharmony_ci} 8568c2ecf20Sopenharmony_ci 8578c2ecf20Sopenharmony_cistatic int hpre_rsa_set_e(struct hpre_ctx *ctx, const char *value, 8588c2ecf20Sopenharmony_ci size_t vlen) 8598c2ecf20Sopenharmony_ci{ 8608c2ecf20Sopenharmony_ci const char *ptr = value; 8618c2ecf20Sopenharmony_ci 8628c2ecf20Sopenharmony_ci hpre_rsa_drop_leading_zeros(&ptr, &vlen); 8638c2ecf20Sopenharmony_ci 8648c2ecf20Sopenharmony_ci if (!ctx->key_sz || !vlen || vlen > ctx->key_sz) 8658c2ecf20Sopenharmony_ci return -EINVAL; 8668c2ecf20Sopenharmony_ci 8678c2ecf20Sopenharmony_ci memcpy(ctx->rsa.pubkey + ctx->key_sz - vlen, ptr, vlen); 8688c2ecf20Sopenharmony_ci 8698c2ecf20Sopenharmony_ci return 0; 8708c2ecf20Sopenharmony_ci} 8718c2ecf20Sopenharmony_ci 8728c2ecf20Sopenharmony_cistatic int hpre_rsa_set_d(struct hpre_ctx *ctx, const char *value, 8738c2ecf20Sopenharmony_ci size_t vlen) 8748c2ecf20Sopenharmony_ci{ 8758c2ecf20Sopenharmony_ci const char *ptr = value; 8768c2ecf20Sopenharmony_ci 8778c2ecf20Sopenharmony_ci hpre_rsa_drop_leading_zeros(&ptr, &vlen); 8788c2ecf20Sopenharmony_ci 8798c2ecf20Sopenharmony_ci if (!ctx->key_sz || !vlen || vlen > ctx->key_sz) 8808c2ecf20Sopenharmony_ci return -EINVAL; 8818c2ecf20Sopenharmony_ci 8828c2ecf20Sopenharmony_ci memcpy(ctx->rsa.prikey + ctx->key_sz - vlen, ptr, vlen); 8838c2ecf20Sopenharmony_ci 8848c2ecf20Sopenharmony_ci return 0; 8858c2ecf20Sopenharmony_ci} 8868c2ecf20Sopenharmony_ci 8878c2ecf20Sopenharmony_cistatic int hpre_crt_para_get(char *para, size_t para_sz, 8888c2ecf20Sopenharmony_ci const char *raw, size_t raw_sz) 8898c2ecf20Sopenharmony_ci{ 8908c2ecf20Sopenharmony_ci const char *ptr = raw; 8918c2ecf20Sopenharmony_ci size_t len = raw_sz; 8928c2ecf20Sopenharmony_ci 8938c2ecf20Sopenharmony_ci hpre_rsa_drop_leading_zeros(&ptr, &len); 8948c2ecf20Sopenharmony_ci if (!len || len > para_sz) 8958c2ecf20Sopenharmony_ci return -EINVAL; 8968c2ecf20Sopenharmony_ci 8978c2ecf20Sopenharmony_ci memcpy(para + para_sz - len, ptr, len); 8988c2ecf20Sopenharmony_ci 8998c2ecf20Sopenharmony_ci return 0; 9008c2ecf20Sopenharmony_ci} 9018c2ecf20Sopenharmony_ci 9028c2ecf20Sopenharmony_cistatic int hpre_rsa_setkey_crt(struct hpre_ctx *ctx, struct rsa_key *rsa_key) 9038c2ecf20Sopenharmony_ci{ 9048c2ecf20Sopenharmony_ci unsigned int hlf_ksz = ctx->key_sz >> 1; 9058c2ecf20Sopenharmony_ci struct device *dev = HPRE_DEV(ctx); 9068c2ecf20Sopenharmony_ci u64 offset; 9078c2ecf20Sopenharmony_ci int ret; 9088c2ecf20Sopenharmony_ci 9098c2ecf20Sopenharmony_ci ctx->rsa.crt_prikey = dma_alloc_coherent(dev, hlf_ksz * HPRE_CRT_PRMS, 9108c2ecf20Sopenharmony_ci &ctx->rsa.dma_crt_prikey, 9118c2ecf20Sopenharmony_ci GFP_KERNEL); 9128c2ecf20Sopenharmony_ci if (!ctx->rsa.crt_prikey) 9138c2ecf20Sopenharmony_ci return -ENOMEM; 9148c2ecf20Sopenharmony_ci 9158c2ecf20Sopenharmony_ci ret = hpre_crt_para_get(ctx->rsa.crt_prikey, hlf_ksz, 9168c2ecf20Sopenharmony_ci rsa_key->dq, rsa_key->dq_sz); 9178c2ecf20Sopenharmony_ci if (ret) 9188c2ecf20Sopenharmony_ci goto free_key; 9198c2ecf20Sopenharmony_ci 9208c2ecf20Sopenharmony_ci offset = hlf_ksz; 9218c2ecf20Sopenharmony_ci ret = hpre_crt_para_get(ctx->rsa.crt_prikey + offset, hlf_ksz, 9228c2ecf20Sopenharmony_ci rsa_key->dp, rsa_key->dp_sz); 9238c2ecf20Sopenharmony_ci if (ret) 9248c2ecf20Sopenharmony_ci goto free_key; 9258c2ecf20Sopenharmony_ci 9268c2ecf20Sopenharmony_ci offset = hlf_ksz * HPRE_CRT_Q; 9278c2ecf20Sopenharmony_ci ret = hpre_crt_para_get(ctx->rsa.crt_prikey + offset, hlf_ksz, 9288c2ecf20Sopenharmony_ci rsa_key->q, rsa_key->q_sz); 9298c2ecf20Sopenharmony_ci if (ret) 9308c2ecf20Sopenharmony_ci goto free_key; 9318c2ecf20Sopenharmony_ci 9328c2ecf20Sopenharmony_ci offset = hlf_ksz * HPRE_CRT_P; 9338c2ecf20Sopenharmony_ci ret = hpre_crt_para_get(ctx->rsa.crt_prikey + offset, hlf_ksz, 9348c2ecf20Sopenharmony_ci rsa_key->p, rsa_key->p_sz); 9358c2ecf20Sopenharmony_ci if (ret) 9368c2ecf20Sopenharmony_ci goto free_key; 9378c2ecf20Sopenharmony_ci 9388c2ecf20Sopenharmony_ci offset = hlf_ksz * HPRE_CRT_INV; 9398c2ecf20Sopenharmony_ci ret = hpre_crt_para_get(ctx->rsa.crt_prikey + offset, hlf_ksz, 9408c2ecf20Sopenharmony_ci rsa_key->qinv, rsa_key->qinv_sz); 9418c2ecf20Sopenharmony_ci if (ret) 9428c2ecf20Sopenharmony_ci goto free_key; 9438c2ecf20Sopenharmony_ci 9448c2ecf20Sopenharmony_ci ctx->crt_g2_mode = true; 9458c2ecf20Sopenharmony_ci 9468c2ecf20Sopenharmony_ci return 0; 9478c2ecf20Sopenharmony_ci 9488c2ecf20Sopenharmony_cifree_key: 9498c2ecf20Sopenharmony_ci offset = hlf_ksz * HPRE_CRT_PRMS; 9508c2ecf20Sopenharmony_ci memzero_explicit(ctx->rsa.crt_prikey, offset); 9518c2ecf20Sopenharmony_ci dma_free_coherent(dev, hlf_ksz * HPRE_CRT_PRMS, ctx->rsa.crt_prikey, 9528c2ecf20Sopenharmony_ci ctx->rsa.dma_crt_prikey); 9538c2ecf20Sopenharmony_ci ctx->rsa.crt_prikey = NULL; 9548c2ecf20Sopenharmony_ci ctx->crt_g2_mode = false; 9558c2ecf20Sopenharmony_ci 9568c2ecf20Sopenharmony_ci return ret; 9578c2ecf20Sopenharmony_ci} 9588c2ecf20Sopenharmony_ci 9598c2ecf20Sopenharmony_ci/* If it is clear all, all the resources of the QP will be cleaned. */ 9608c2ecf20Sopenharmony_cistatic void hpre_rsa_clear_ctx(struct hpre_ctx *ctx, bool is_clear_all) 9618c2ecf20Sopenharmony_ci{ 9628c2ecf20Sopenharmony_ci unsigned int half_key_sz = ctx->key_sz >> 1; 9638c2ecf20Sopenharmony_ci struct device *dev = HPRE_DEV(ctx); 9648c2ecf20Sopenharmony_ci 9658c2ecf20Sopenharmony_ci if (is_clear_all) 9668c2ecf20Sopenharmony_ci hisi_qm_stop_qp(ctx->qp); 9678c2ecf20Sopenharmony_ci 9688c2ecf20Sopenharmony_ci if (ctx->rsa.pubkey) { 9698c2ecf20Sopenharmony_ci dma_free_coherent(dev, ctx->key_sz << 1, 9708c2ecf20Sopenharmony_ci ctx->rsa.pubkey, ctx->rsa.dma_pubkey); 9718c2ecf20Sopenharmony_ci ctx->rsa.pubkey = NULL; 9728c2ecf20Sopenharmony_ci } 9738c2ecf20Sopenharmony_ci 9748c2ecf20Sopenharmony_ci if (ctx->rsa.crt_prikey) { 9758c2ecf20Sopenharmony_ci memzero_explicit(ctx->rsa.crt_prikey, 9768c2ecf20Sopenharmony_ci half_key_sz * HPRE_CRT_PRMS); 9778c2ecf20Sopenharmony_ci dma_free_coherent(dev, half_key_sz * HPRE_CRT_PRMS, 9788c2ecf20Sopenharmony_ci ctx->rsa.crt_prikey, ctx->rsa.dma_crt_prikey); 9798c2ecf20Sopenharmony_ci ctx->rsa.crt_prikey = NULL; 9808c2ecf20Sopenharmony_ci } 9818c2ecf20Sopenharmony_ci 9828c2ecf20Sopenharmony_ci if (ctx->rsa.prikey) { 9838c2ecf20Sopenharmony_ci memzero_explicit(ctx->rsa.prikey, ctx->key_sz); 9848c2ecf20Sopenharmony_ci dma_free_coherent(dev, ctx->key_sz << 1, ctx->rsa.prikey, 9858c2ecf20Sopenharmony_ci ctx->rsa.dma_prikey); 9868c2ecf20Sopenharmony_ci ctx->rsa.prikey = NULL; 9878c2ecf20Sopenharmony_ci } 9888c2ecf20Sopenharmony_ci 9898c2ecf20Sopenharmony_ci hpre_ctx_clear(ctx, is_clear_all); 9908c2ecf20Sopenharmony_ci} 9918c2ecf20Sopenharmony_ci 9928c2ecf20Sopenharmony_ci/* 9938c2ecf20Sopenharmony_ci * we should judge if it is CRT or not, 9948c2ecf20Sopenharmony_ci * CRT: return true, N-CRT: return false . 9958c2ecf20Sopenharmony_ci */ 9968c2ecf20Sopenharmony_cistatic bool hpre_is_crt_key(struct rsa_key *key) 9978c2ecf20Sopenharmony_ci{ 9988c2ecf20Sopenharmony_ci u16 len = key->p_sz + key->q_sz + key->dp_sz + key->dq_sz + 9998c2ecf20Sopenharmony_ci key->qinv_sz; 10008c2ecf20Sopenharmony_ci 10018c2ecf20Sopenharmony_ci#define LEN_OF_NCRT_PARA 5 10028c2ecf20Sopenharmony_ci 10038c2ecf20Sopenharmony_ci /* N-CRT less than 5 parameters */ 10048c2ecf20Sopenharmony_ci return len > LEN_OF_NCRT_PARA; 10058c2ecf20Sopenharmony_ci} 10068c2ecf20Sopenharmony_ci 10078c2ecf20Sopenharmony_cistatic int hpre_rsa_setkey(struct hpre_ctx *ctx, const void *key, 10088c2ecf20Sopenharmony_ci unsigned int keylen, bool private) 10098c2ecf20Sopenharmony_ci{ 10108c2ecf20Sopenharmony_ci struct rsa_key rsa_key; 10118c2ecf20Sopenharmony_ci int ret; 10128c2ecf20Sopenharmony_ci 10138c2ecf20Sopenharmony_ci hpre_rsa_clear_ctx(ctx, false); 10148c2ecf20Sopenharmony_ci 10158c2ecf20Sopenharmony_ci if (private) 10168c2ecf20Sopenharmony_ci ret = rsa_parse_priv_key(&rsa_key, key, keylen); 10178c2ecf20Sopenharmony_ci else 10188c2ecf20Sopenharmony_ci ret = rsa_parse_pub_key(&rsa_key, key, keylen); 10198c2ecf20Sopenharmony_ci if (ret < 0) 10208c2ecf20Sopenharmony_ci return ret; 10218c2ecf20Sopenharmony_ci 10228c2ecf20Sopenharmony_ci ret = hpre_rsa_set_n(ctx, rsa_key.n, rsa_key.n_sz, private); 10238c2ecf20Sopenharmony_ci if (ret <= 0) 10248c2ecf20Sopenharmony_ci return ret; 10258c2ecf20Sopenharmony_ci 10268c2ecf20Sopenharmony_ci if (private) { 10278c2ecf20Sopenharmony_ci ret = hpre_rsa_set_d(ctx, rsa_key.d, rsa_key.d_sz); 10288c2ecf20Sopenharmony_ci if (ret < 0) 10298c2ecf20Sopenharmony_ci goto free; 10308c2ecf20Sopenharmony_ci 10318c2ecf20Sopenharmony_ci if (hpre_is_crt_key(&rsa_key)) { 10328c2ecf20Sopenharmony_ci ret = hpre_rsa_setkey_crt(ctx, &rsa_key); 10338c2ecf20Sopenharmony_ci if (ret < 0) 10348c2ecf20Sopenharmony_ci goto free; 10358c2ecf20Sopenharmony_ci } 10368c2ecf20Sopenharmony_ci } 10378c2ecf20Sopenharmony_ci 10388c2ecf20Sopenharmony_ci ret = hpre_rsa_set_e(ctx, rsa_key.e, rsa_key.e_sz); 10398c2ecf20Sopenharmony_ci if (ret < 0) 10408c2ecf20Sopenharmony_ci goto free; 10418c2ecf20Sopenharmony_ci 10428c2ecf20Sopenharmony_ci if ((private && !ctx->rsa.prikey) || !ctx->rsa.pubkey) { 10438c2ecf20Sopenharmony_ci ret = -EINVAL; 10448c2ecf20Sopenharmony_ci goto free; 10458c2ecf20Sopenharmony_ci } 10468c2ecf20Sopenharmony_ci 10478c2ecf20Sopenharmony_ci return 0; 10488c2ecf20Sopenharmony_ci 10498c2ecf20Sopenharmony_cifree: 10508c2ecf20Sopenharmony_ci hpre_rsa_clear_ctx(ctx, false); 10518c2ecf20Sopenharmony_ci return ret; 10528c2ecf20Sopenharmony_ci} 10538c2ecf20Sopenharmony_ci 10548c2ecf20Sopenharmony_cistatic int hpre_rsa_setpubkey(struct crypto_akcipher *tfm, const void *key, 10558c2ecf20Sopenharmony_ci unsigned int keylen) 10568c2ecf20Sopenharmony_ci{ 10578c2ecf20Sopenharmony_ci struct hpre_ctx *ctx = akcipher_tfm_ctx(tfm); 10588c2ecf20Sopenharmony_ci int ret; 10598c2ecf20Sopenharmony_ci 10608c2ecf20Sopenharmony_ci ret = crypto_akcipher_set_pub_key(ctx->rsa.soft_tfm, key, keylen); 10618c2ecf20Sopenharmony_ci if (ret) 10628c2ecf20Sopenharmony_ci return ret; 10638c2ecf20Sopenharmony_ci 10648c2ecf20Sopenharmony_ci return hpre_rsa_setkey(ctx, key, keylen, false); 10658c2ecf20Sopenharmony_ci} 10668c2ecf20Sopenharmony_ci 10678c2ecf20Sopenharmony_cistatic int hpre_rsa_setprivkey(struct crypto_akcipher *tfm, const void *key, 10688c2ecf20Sopenharmony_ci unsigned int keylen) 10698c2ecf20Sopenharmony_ci{ 10708c2ecf20Sopenharmony_ci struct hpre_ctx *ctx = akcipher_tfm_ctx(tfm); 10718c2ecf20Sopenharmony_ci int ret; 10728c2ecf20Sopenharmony_ci 10738c2ecf20Sopenharmony_ci ret = crypto_akcipher_set_priv_key(ctx->rsa.soft_tfm, key, keylen); 10748c2ecf20Sopenharmony_ci if (ret) 10758c2ecf20Sopenharmony_ci return ret; 10768c2ecf20Sopenharmony_ci 10778c2ecf20Sopenharmony_ci return hpre_rsa_setkey(ctx, key, keylen, true); 10788c2ecf20Sopenharmony_ci} 10798c2ecf20Sopenharmony_ci 10808c2ecf20Sopenharmony_cistatic unsigned int hpre_rsa_max_size(struct crypto_akcipher *tfm) 10818c2ecf20Sopenharmony_ci{ 10828c2ecf20Sopenharmony_ci struct hpre_ctx *ctx = akcipher_tfm_ctx(tfm); 10838c2ecf20Sopenharmony_ci 10848c2ecf20Sopenharmony_ci /* For 512 and 1536 bits key size, use soft tfm instead */ 10858c2ecf20Sopenharmony_ci if (ctx->key_sz == HPRE_RSA_512BITS_KSZ || 10868c2ecf20Sopenharmony_ci ctx->key_sz == HPRE_RSA_1536BITS_KSZ) 10878c2ecf20Sopenharmony_ci return crypto_akcipher_maxsize(ctx->rsa.soft_tfm); 10888c2ecf20Sopenharmony_ci 10898c2ecf20Sopenharmony_ci return ctx->key_sz; 10908c2ecf20Sopenharmony_ci} 10918c2ecf20Sopenharmony_ci 10928c2ecf20Sopenharmony_cistatic int hpre_rsa_init_tfm(struct crypto_akcipher *tfm) 10938c2ecf20Sopenharmony_ci{ 10948c2ecf20Sopenharmony_ci struct hpre_ctx *ctx = akcipher_tfm_ctx(tfm); 10958c2ecf20Sopenharmony_ci int ret; 10968c2ecf20Sopenharmony_ci 10978c2ecf20Sopenharmony_ci ctx->rsa.soft_tfm = crypto_alloc_akcipher("rsa-generic", 0, 0); 10988c2ecf20Sopenharmony_ci if (IS_ERR(ctx->rsa.soft_tfm)) { 10998c2ecf20Sopenharmony_ci pr_err("Can not alloc_akcipher!\n"); 11008c2ecf20Sopenharmony_ci return PTR_ERR(ctx->rsa.soft_tfm); 11018c2ecf20Sopenharmony_ci } 11028c2ecf20Sopenharmony_ci 11038c2ecf20Sopenharmony_ci ret = hpre_ctx_init(ctx); 11048c2ecf20Sopenharmony_ci if (ret) 11058c2ecf20Sopenharmony_ci crypto_free_akcipher(ctx->rsa.soft_tfm); 11068c2ecf20Sopenharmony_ci 11078c2ecf20Sopenharmony_ci return ret; 11088c2ecf20Sopenharmony_ci} 11098c2ecf20Sopenharmony_ci 11108c2ecf20Sopenharmony_cistatic void hpre_rsa_exit_tfm(struct crypto_akcipher *tfm) 11118c2ecf20Sopenharmony_ci{ 11128c2ecf20Sopenharmony_ci struct hpre_ctx *ctx = akcipher_tfm_ctx(tfm); 11138c2ecf20Sopenharmony_ci 11148c2ecf20Sopenharmony_ci hpre_rsa_clear_ctx(ctx, true); 11158c2ecf20Sopenharmony_ci crypto_free_akcipher(ctx->rsa.soft_tfm); 11168c2ecf20Sopenharmony_ci} 11178c2ecf20Sopenharmony_ci 11188c2ecf20Sopenharmony_cistatic struct akcipher_alg rsa = { 11198c2ecf20Sopenharmony_ci .sign = hpre_rsa_dec, 11208c2ecf20Sopenharmony_ci .verify = hpre_rsa_enc, 11218c2ecf20Sopenharmony_ci .encrypt = hpre_rsa_enc, 11228c2ecf20Sopenharmony_ci .decrypt = hpre_rsa_dec, 11238c2ecf20Sopenharmony_ci .set_pub_key = hpre_rsa_setpubkey, 11248c2ecf20Sopenharmony_ci .set_priv_key = hpre_rsa_setprivkey, 11258c2ecf20Sopenharmony_ci .max_size = hpre_rsa_max_size, 11268c2ecf20Sopenharmony_ci .init = hpre_rsa_init_tfm, 11278c2ecf20Sopenharmony_ci .exit = hpre_rsa_exit_tfm, 11288c2ecf20Sopenharmony_ci .reqsize = sizeof(struct hpre_asym_request) + HPRE_ALIGN_SZ, 11298c2ecf20Sopenharmony_ci .base = { 11308c2ecf20Sopenharmony_ci .cra_ctxsize = sizeof(struct hpre_ctx), 11318c2ecf20Sopenharmony_ci .cra_priority = HPRE_CRYPTO_ALG_PRI, 11328c2ecf20Sopenharmony_ci .cra_name = "rsa", 11338c2ecf20Sopenharmony_ci .cra_driver_name = "hpre-rsa", 11348c2ecf20Sopenharmony_ci .cra_module = THIS_MODULE, 11358c2ecf20Sopenharmony_ci }, 11368c2ecf20Sopenharmony_ci}; 11378c2ecf20Sopenharmony_ci 11388c2ecf20Sopenharmony_ci#ifdef CONFIG_CRYPTO_DH 11398c2ecf20Sopenharmony_cistatic struct kpp_alg dh = { 11408c2ecf20Sopenharmony_ci .set_secret = hpre_dh_set_secret, 11418c2ecf20Sopenharmony_ci .generate_public_key = hpre_dh_compute_value, 11428c2ecf20Sopenharmony_ci .compute_shared_secret = hpre_dh_compute_value, 11438c2ecf20Sopenharmony_ci .max_size = hpre_dh_max_size, 11448c2ecf20Sopenharmony_ci .init = hpre_dh_init_tfm, 11458c2ecf20Sopenharmony_ci .exit = hpre_dh_exit_tfm, 11468c2ecf20Sopenharmony_ci .reqsize = sizeof(struct hpre_asym_request) + HPRE_ALIGN_SZ, 11478c2ecf20Sopenharmony_ci .base = { 11488c2ecf20Sopenharmony_ci .cra_ctxsize = sizeof(struct hpre_ctx), 11498c2ecf20Sopenharmony_ci .cra_priority = HPRE_CRYPTO_ALG_PRI, 11508c2ecf20Sopenharmony_ci .cra_name = "dh", 11518c2ecf20Sopenharmony_ci .cra_driver_name = "hpre-dh", 11528c2ecf20Sopenharmony_ci .cra_module = THIS_MODULE, 11538c2ecf20Sopenharmony_ci }, 11548c2ecf20Sopenharmony_ci}; 11558c2ecf20Sopenharmony_ci#endif 11568c2ecf20Sopenharmony_ci 11578c2ecf20Sopenharmony_ciint hpre_algs_register(void) 11588c2ecf20Sopenharmony_ci{ 11598c2ecf20Sopenharmony_ci int ret; 11608c2ecf20Sopenharmony_ci 11618c2ecf20Sopenharmony_ci rsa.base.cra_flags = 0; 11628c2ecf20Sopenharmony_ci ret = crypto_register_akcipher(&rsa); 11638c2ecf20Sopenharmony_ci if (ret) 11648c2ecf20Sopenharmony_ci return ret; 11658c2ecf20Sopenharmony_ci#ifdef CONFIG_CRYPTO_DH 11668c2ecf20Sopenharmony_ci ret = crypto_register_kpp(&dh); 11678c2ecf20Sopenharmony_ci if (ret) 11688c2ecf20Sopenharmony_ci crypto_unregister_akcipher(&rsa); 11698c2ecf20Sopenharmony_ci#endif 11708c2ecf20Sopenharmony_ci 11718c2ecf20Sopenharmony_ci return ret; 11728c2ecf20Sopenharmony_ci} 11738c2ecf20Sopenharmony_ci 11748c2ecf20Sopenharmony_civoid hpre_algs_unregister(void) 11758c2ecf20Sopenharmony_ci{ 11768c2ecf20Sopenharmony_ci crypto_unregister_akcipher(&rsa); 11778c2ecf20Sopenharmony_ci#ifdef CONFIG_CRYPTO_DH 11788c2ecf20Sopenharmony_ci crypto_unregister_kpp(&dh); 11798c2ecf20Sopenharmony_ci#endif 11808c2ecf20Sopenharmony_ci} 1181