18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * sun8i-ss-cipher.c - hardware cryptographic offloader for 48c2ecf20Sopenharmony_ci * Allwinner A80/A83T SoC 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Copyright (C) 2016-2019 Corentin LABBE <clabbe.montjoie@gmail.com> 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * This file add support for AES cipher with 128,192,256 bits keysize in 98c2ecf20Sopenharmony_ci * CBC and ECB mode. 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * You could find a link for the datasheet in Documentation/arm/sunxi.rst 128c2ecf20Sopenharmony_ci */ 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#include <linux/bottom_half.h> 158c2ecf20Sopenharmony_ci#include <linux/crypto.h> 168c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h> 178c2ecf20Sopenharmony_ci#include <linux/io.h> 188c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h> 198c2ecf20Sopenharmony_ci#include <crypto/scatterwalk.h> 208c2ecf20Sopenharmony_ci#include <crypto/internal/skcipher.h> 218c2ecf20Sopenharmony_ci#include "sun8i-ss.h" 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_cistatic bool sun8i_ss_need_fallback(struct skcipher_request *areq) 248c2ecf20Sopenharmony_ci{ 258c2ecf20Sopenharmony_ci struct scatterlist *in_sg = areq->src; 268c2ecf20Sopenharmony_ci struct scatterlist *out_sg = areq->dst; 278c2ecf20Sopenharmony_ci struct scatterlist *sg; 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci if (areq->cryptlen == 0 || areq->cryptlen % 16) 308c2ecf20Sopenharmony_ci return true; 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci if (sg_nents(areq->src) > 8 || sg_nents(areq->dst) > 8) 338c2ecf20Sopenharmony_ci return true; 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci sg = areq->src; 368c2ecf20Sopenharmony_ci while (sg) { 378c2ecf20Sopenharmony_ci if ((sg->length % 16) != 0) 388c2ecf20Sopenharmony_ci return true; 398c2ecf20Sopenharmony_ci if ((sg_dma_len(sg) % 16) != 0) 408c2ecf20Sopenharmony_ci return true; 418c2ecf20Sopenharmony_ci if (!IS_ALIGNED(sg->offset, 16)) 428c2ecf20Sopenharmony_ci return true; 438c2ecf20Sopenharmony_ci sg = sg_next(sg); 448c2ecf20Sopenharmony_ci } 458c2ecf20Sopenharmony_ci sg = areq->dst; 468c2ecf20Sopenharmony_ci while (sg) { 478c2ecf20Sopenharmony_ci if ((sg->length % 16) != 0) 488c2ecf20Sopenharmony_ci return true; 498c2ecf20Sopenharmony_ci if ((sg_dma_len(sg) % 16) != 0) 508c2ecf20Sopenharmony_ci return true; 518c2ecf20Sopenharmony_ci if (!IS_ALIGNED(sg->offset, 16)) 528c2ecf20Sopenharmony_ci return true; 538c2ecf20Sopenharmony_ci sg = sg_next(sg); 548c2ecf20Sopenharmony_ci } 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci /* SS need same numbers of SG (with same length) for source and destination */ 578c2ecf20Sopenharmony_ci in_sg = areq->src; 588c2ecf20Sopenharmony_ci out_sg = areq->dst; 598c2ecf20Sopenharmony_ci while (in_sg && out_sg) { 608c2ecf20Sopenharmony_ci if (in_sg->length != out_sg->length) 618c2ecf20Sopenharmony_ci return true; 628c2ecf20Sopenharmony_ci in_sg = sg_next(in_sg); 638c2ecf20Sopenharmony_ci out_sg = sg_next(out_sg); 648c2ecf20Sopenharmony_ci } 658c2ecf20Sopenharmony_ci if (in_sg || out_sg) 668c2ecf20Sopenharmony_ci return true; 678c2ecf20Sopenharmony_ci return false; 688c2ecf20Sopenharmony_ci} 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_cistatic int sun8i_ss_cipher_fallback(struct skcipher_request *areq) 718c2ecf20Sopenharmony_ci{ 728c2ecf20Sopenharmony_ci struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(areq); 738c2ecf20Sopenharmony_ci struct sun8i_cipher_tfm_ctx *op = crypto_skcipher_ctx(tfm); 748c2ecf20Sopenharmony_ci struct sun8i_cipher_req_ctx *rctx = skcipher_request_ctx(areq); 758c2ecf20Sopenharmony_ci int err; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci#ifdef CONFIG_CRYPTO_DEV_SUN8I_SS_DEBUG 788c2ecf20Sopenharmony_ci struct skcipher_alg *alg = crypto_skcipher_alg(tfm); 798c2ecf20Sopenharmony_ci struct sun8i_ss_alg_template *algt; 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci algt = container_of(alg, struct sun8i_ss_alg_template, alg.skcipher); 828c2ecf20Sopenharmony_ci algt->stat_fb++; 838c2ecf20Sopenharmony_ci#endif 848c2ecf20Sopenharmony_ci skcipher_request_set_tfm(&rctx->fallback_req, op->fallback_tfm); 858c2ecf20Sopenharmony_ci skcipher_request_set_callback(&rctx->fallback_req, areq->base.flags, 868c2ecf20Sopenharmony_ci areq->base.complete, areq->base.data); 878c2ecf20Sopenharmony_ci skcipher_request_set_crypt(&rctx->fallback_req, areq->src, areq->dst, 888c2ecf20Sopenharmony_ci areq->cryptlen, areq->iv); 898c2ecf20Sopenharmony_ci if (rctx->op_dir & SS_DECRYPTION) 908c2ecf20Sopenharmony_ci err = crypto_skcipher_decrypt(&rctx->fallback_req); 918c2ecf20Sopenharmony_ci else 928c2ecf20Sopenharmony_ci err = crypto_skcipher_encrypt(&rctx->fallback_req); 938c2ecf20Sopenharmony_ci return err; 948c2ecf20Sopenharmony_ci} 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_cistatic int sun8i_ss_setup_ivs(struct skcipher_request *areq) 978c2ecf20Sopenharmony_ci{ 988c2ecf20Sopenharmony_ci struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(areq); 998c2ecf20Sopenharmony_ci struct sun8i_cipher_tfm_ctx *op = crypto_skcipher_ctx(tfm); 1008c2ecf20Sopenharmony_ci struct sun8i_ss_dev *ss = op->ss; 1018c2ecf20Sopenharmony_ci struct sun8i_cipher_req_ctx *rctx = skcipher_request_ctx(areq); 1028c2ecf20Sopenharmony_ci struct scatterlist *sg = areq->src; 1038c2ecf20Sopenharmony_ci unsigned int todo, offset; 1048c2ecf20Sopenharmony_ci unsigned int len = areq->cryptlen; 1058c2ecf20Sopenharmony_ci unsigned int ivsize = crypto_skcipher_ivsize(tfm); 1068c2ecf20Sopenharmony_ci struct sun8i_ss_flow *sf = &ss->flows[rctx->flow]; 1078c2ecf20Sopenharmony_ci int i = 0; 1088c2ecf20Sopenharmony_ci dma_addr_t a; 1098c2ecf20Sopenharmony_ci int err; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci rctx->ivlen = ivsize; 1128c2ecf20Sopenharmony_ci if (rctx->op_dir & SS_DECRYPTION) { 1138c2ecf20Sopenharmony_ci offset = areq->cryptlen - ivsize; 1148c2ecf20Sopenharmony_ci scatterwalk_map_and_copy(sf->biv, areq->src, offset, 1158c2ecf20Sopenharmony_ci ivsize, 0); 1168c2ecf20Sopenharmony_ci } 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci /* we need to copy all IVs from source in case DMA is bi-directionnal */ 1198c2ecf20Sopenharmony_ci while (sg && len) { 1208c2ecf20Sopenharmony_ci if (sg_dma_len(sg) == 0) { 1218c2ecf20Sopenharmony_ci sg = sg_next(sg); 1228c2ecf20Sopenharmony_ci continue; 1238c2ecf20Sopenharmony_ci } 1248c2ecf20Sopenharmony_ci if (i == 0) 1258c2ecf20Sopenharmony_ci memcpy(sf->iv[0], areq->iv, ivsize); 1268c2ecf20Sopenharmony_ci a = dma_map_single(ss->dev, sf->iv[i], ivsize, DMA_TO_DEVICE); 1278c2ecf20Sopenharmony_ci if (dma_mapping_error(ss->dev, a)) { 1288c2ecf20Sopenharmony_ci memzero_explicit(sf->iv[i], ivsize); 1298c2ecf20Sopenharmony_ci dev_err(ss->dev, "Cannot DMA MAP IV\n"); 1308c2ecf20Sopenharmony_ci err = -EFAULT; 1318c2ecf20Sopenharmony_ci goto dma_iv_error; 1328c2ecf20Sopenharmony_ci } 1338c2ecf20Sopenharmony_ci rctx->p_iv[i] = a; 1348c2ecf20Sopenharmony_ci /* we need to setup all others IVs only in the decrypt way */ 1358c2ecf20Sopenharmony_ci if (rctx->op_dir == SS_ENCRYPTION) 1368c2ecf20Sopenharmony_ci return 0; 1378c2ecf20Sopenharmony_ci todo = min(len, sg_dma_len(sg)); 1388c2ecf20Sopenharmony_ci len -= todo; 1398c2ecf20Sopenharmony_ci i++; 1408c2ecf20Sopenharmony_ci if (i < MAX_SG) { 1418c2ecf20Sopenharmony_ci offset = sg->length - ivsize; 1428c2ecf20Sopenharmony_ci scatterwalk_map_and_copy(sf->iv[i], sg, offset, ivsize, 0); 1438c2ecf20Sopenharmony_ci } 1448c2ecf20Sopenharmony_ci rctx->niv = i; 1458c2ecf20Sopenharmony_ci sg = sg_next(sg); 1468c2ecf20Sopenharmony_ci } 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci return 0; 1498c2ecf20Sopenharmony_cidma_iv_error: 1508c2ecf20Sopenharmony_ci i--; 1518c2ecf20Sopenharmony_ci while (i >= 0) { 1528c2ecf20Sopenharmony_ci dma_unmap_single(ss->dev, rctx->p_iv[i], ivsize, DMA_TO_DEVICE); 1538c2ecf20Sopenharmony_ci memzero_explicit(sf->iv[i], ivsize); 1548c2ecf20Sopenharmony_ci i--; 1558c2ecf20Sopenharmony_ci } 1568c2ecf20Sopenharmony_ci return err; 1578c2ecf20Sopenharmony_ci} 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_cistatic int sun8i_ss_cipher(struct skcipher_request *areq) 1608c2ecf20Sopenharmony_ci{ 1618c2ecf20Sopenharmony_ci struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(areq); 1628c2ecf20Sopenharmony_ci struct sun8i_cipher_tfm_ctx *op = crypto_skcipher_ctx(tfm); 1638c2ecf20Sopenharmony_ci struct sun8i_ss_dev *ss = op->ss; 1648c2ecf20Sopenharmony_ci struct sun8i_cipher_req_ctx *rctx = skcipher_request_ctx(areq); 1658c2ecf20Sopenharmony_ci struct skcipher_alg *alg = crypto_skcipher_alg(tfm); 1668c2ecf20Sopenharmony_ci struct sun8i_ss_alg_template *algt; 1678c2ecf20Sopenharmony_ci struct sun8i_ss_flow *sf = &ss->flows[rctx->flow]; 1688c2ecf20Sopenharmony_ci struct scatterlist *sg; 1698c2ecf20Sopenharmony_ci unsigned int todo, len, offset, ivsize; 1708c2ecf20Sopenharmony_ci int nr_sgs = 0; 1718c2ecf20Sopenharmony_ci int nr_sgd = 0; 1728c2ecf20Sopenharmony_ci int err = 0; 1738c2ecf20Sopenharmony_ci int i; 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci algt = container_of(alg, struct sun8i_ss_alg_template, alg.skcipher); 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci dev_dbg(ss->dev, "%s %s %u %x IV(%p %u) key=%u\n", __func__, 1788c2ecf20Sopenharmony_ci crypto_tfm_alg_name(areq->base.tfm), 1798c2ecf20Sopenharmony_ci areq->cryptlen, 1808c2ecf20Sopenharmony_ci rctx->op_dir, areq->iv, crypto_skcipher_ivsize(tfm), 1818c2ecf20Sopenharmony_ci op->keylen); 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci#ifdef CONFIG_CRYPTO_DEV_SUN8I_SS_DEBUG 1848c2ecf20Sopenharmony_ci algt->stat_req++; 1858c2ecf20Sopenharmony_ci#endif 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci rctx->op_mode = ss->variant->op_mode[algt->ss_blockmode]; 1888c2ecf20Sopenharmony_ci rctx->method = ss->variant->alg_cipher[algt->ss_algo_id]; 1898c2ecf20Sopenharmony_ci rctx->keylen = op->keylen; 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci rctx->p_key = dma_map_single(ss->dev, op->key, op->keylen, DMA_TO_DEVICE); 1928c2ecf20Sopenharmony_ci if (dma_mapping_error(ss->dev, rctx->p_key)) { 1938c2ecf20Sopenharmony_ci dev_err(ss->dev, "Cannot DMA MAP KEY\n"); 1948c2ecf20Sopenharmony_ci err = -EFAULT; 1958c2ecf20Sopenharmony_ci goto theend; 1968c2ecf20Sopenharmony_ci } 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci ivsize = crypto_skcipher_ivsize(tfm); 1998c2ecf20Sopenharmony_ci if (areq->iv && crypto_skcipher_ivsize(tfm) > 0) { 2008c2ecf20Sopenharmony_ci err = sun8i_ss_setup_ivs(areq); 2018c2ecf20Sopenharmony_ci if (err) 2028c2ecf20Sopenharmony_ci goto theend_key; 2038c2ecf20Sopenharmony_ci } 2048c2ecf20Sopenharmony_ci if (areq->src == areq->dst) { 2058c2ecf20Sopenharmony_ci nr_sgs = dma_map_sg(ss->dev, areq->src, sg_nents(areq->src), 2068c2ecf20Sopenharmony_ci DMA_BIDIRECTIONAL); 2078c2ecf20Sopenharmony_ci if (nr_sgs <= 0 || nr_sgs > 8) { 2088c2ecf20Sopenharmony_ci dev_err(ss->dev, "Invalid sg number %d\n", nr_sgs); 2098c2ecf20Sopenharmony_ci err = -EINVAL; 2108c2ecf20Sopenharmony_ci goto theend_iv; 2118c2ecf20Sopenharmony_ci } 2128c2ecf20Sopenharmony_ci nr_sgd = nr_sgs; 2138c2ecf20Sopenharmony_ci } else { 2148c2ecf20Sopenharmony_ci nr_sgs = dma_map_sg(ss->dev, areq->src, sg_nents(areq->src), 2158c2ecf20Sopenharmony_ci DMA_TO_DEVICE); 2168c2ecf20Sopenharmony_ci if (nr_sgs <= 0 || nr_sgs > 8) { 2178c2ecf20Sopenharmony_ci dev_err(ss->dev, "Invalid sg number %d\n", nr_sgs); 2188c2ecf20Sopenharmony_ci err = -EINVAL; 2198c2ecf20Sopenharmony_ci goto theend_iv; 2208c2ecf20Sopenharmony_ci } 2218c2ecf20Sopenharmony_ci nr_sgd = dma_map_sg(ss->dev, areq->dst, sg_nents(areq->dst), 2228c2ecf20Sopenharmony_ci DMA_FROM_DEVICE); 2238c2ecf20Sopenharmony_ci if (nr_sgd <= 0 || nr_sgd > 8) { 2248c2ecf20Sopenharmony_ci dev_err(ss->dev, "Invalid sg number %d\n", nr_sgd); 2258c2ecf20Sopenharmony_ci err = -EINVAL; 2268c2ecf20Sopenharmony_ci goto theend_sgs; 2278c2ecf20Sopenharmony_ci } 2288c2ecf20Sopenharmony_ci } 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci len = areq->cryptlen; 2318c2ecf20Sopenharmony_ci i = 0; 2328c2ecf20Sopenharmony_ci sg = areq->src; 2338c2ecf20Sopenharmony_ci while (i < nr_sgs && sg && len) { 2348c2ecf20Sopenharmony_ci if (sg_dma_len(sg) == 0) 2358c2ecf20Sopenharmony_ci goto sgs_next; 2368c2ecf20Sopenharmony_ci rctx->t_src[i].addr = sg_dma_address(sg); 2378c2ecf20Sopenharmony_ci todo = min(len, sg_dma_len(sg)); 2388c2ecf20Sopenharmony_ci rctx->t_src[i].len = todo / 4; 2398c2ecf20Sopenharmony_ci dev_dbg(ss->dev, "%s total=%u SGS(%d %u off=%d) todo=%u\n", __func__, 2408c2ecf20Sopenharmony_ci areq->cryptlen, i, rctx->t_src[i].len, sg->offset, todo); 2418c2ecf20Sopenharmony_ci len -= todo; 2428c2ecf20Sopenharmony_ci i++; 2438c2ecf20Sopenharmony_cisgs_next: 2448c2ecf20Sopenharmony_ci sg = sg_next(sg); 2458c2ecf20Sopenharmony_ci } 2468c2ecf20Sopenharmony_ci if (len > 0) { 2478c2ecf20Sopenharmony_ci dev_err(ss->dev, "remaining len %d\n", len); 2488c2ecf20Sopenharmony_ci err = -EINVAL; 2498c2ecf20Sopenharmony_ci goto theend_sgs; 2508c2ecf20Sopenharmony_ci } 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci len = areq->cryptlen; 2538c2ecf20Sopenharmony_ci i = 0; 2548c2ecf20Sopenharmony_ci sg = areq->dst; 2558c2ecf20Sopenharmony_ci while (i < nr_sgd && sg && len) { 2568c2ecf20Sopenharmony_ci if (sg_dma_len(sg) == 0) 2578c2ecf20Sopenharmony_ci goto sgd_next; 2588c2ecf20Sopenharmony_ci rctx->t_dst[i].addr = sg_dma_address(sg); 2598c2ecf20Sopenharmony_ci todo = min(len, sg_dma_len(sg)); 2608c2ecf20Sopenharmony_ci rctx->t_dst[i].len = todo / 4; 2618c2ecf20Sopenharmony_ci dev_dbg(ss->dev, "%s total=%u SGD(%d %u off=%d) todo=%u\n", __func__, 2628c2ecf20Sopenharmony_ci areq->cryptlen, i, rctx->t_dst[i].len, sg->offset, todo); 2638c2ecf20Sopenharmony_ci len -= todo; 2648c2ecf20Sopenharmony_ci i++; 2658c2ecf20Sopenharmony_cisgd_next: 2668c2ecf20Sopenharmony_ci sg = sg_next(sg); 2678c2ecf20Sopenharmony_ci } 2688c2ecf20Sopenharmony_ci if (len > 0) { 2698c2ecf20Sopenharmony_ci dev_err(ss->dev, "remaining len %d\n", len); 2708c2ecf20Sopenharmony_ci err = -EINVAL; 2718c2ecf20Sopenharmony_ci goto theend_sgs; 2728c2ecf20Sopenharmony_ci } 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci err = sun8i_ss_run_task(ss, rctx, crypto_tfm_alg_name(areq->base.tfm)); 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_citheend_sgs: 2778c2ecf20Sopenharmony_ci if (areq->src == areq->dst) { 2788c2ecf20Sopenharmony_ci dma_unmap_sg(ss->dev, areq->src, nr_sgs, DMA_BIDIRECTIONAL); 2798c2ecf20Sopenharmony_ci } else { 2808c2ecf20Sopenharmony_ci dma_unmap_sg(ss->dev, areq->src, nr_sgs, DMA_TO_DEVICE); 2818c2ecf20Sopenharmony_ci dma_unmap_sg(ss->dev, areq->dst, nr_sgd, DMA_FROM_DEVICE); 2828c2ecf20Sopenharmony_ci } 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_citheend_iv: 2858c2ecf20Sopenharmony_ci if (areq->iv && ivsize > 0) { 2868c2ecf20Sopenharmony_ci for (i = 0; i < rctx->niv; i++) { 2878c2ecf20Sopenharmony_ci dma_unmap_single(ss->dev, rctx->p_iv[i], ivsize, DMA_TO_DEVICE); 2888c2ecf20Sopenharmony_ci memzero_explicit(sf->iv[i], ivsize); 2898c2ecf20Sopenharmony_ci } 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci offset = areq->cryptlen - ivsize; 2928c2ecf20Sopenharmony_ci if (rctx->op_dir & SS_DECRYPTION) { 2938c2ecf20Sopenharmony_ci memcpy(areq->iv, sf->biv, ivsize); 2948c2ecf20Sopenharmony_ci memzero_explicit(sf->biv, ivsize); 2958c2ecf20Sopenharmony_ci } else { 2968c2ecf20Sopenharmony_ci scatterwalk_map_and_copy(areq->iv, areq->dst, offset, 2978c2ecf20Sopenharmony_ci ivsize, 0); 2988c2ecf20Sopenharmony_ci } 2998c2ecf20Sopenharmony_ci } 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_citheend_key: 3028c2ecf20Sopenharmony_ci dma_unmap_single(ss->dev, rctx->p_key, op->keylen, DMA_TO_DEVICE); 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_citheend: 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci return err; 3078c2ecf20Sopenharmony_ci} 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_cistatic int sun8i_ss_handle_cipher_request(struct crypto_engine *engine, void *areq) 3108c2ecf20Sopenharmony_ci{ 3118c2ecf20Sopenharmony_ci int err; 3128c2ecf20Sopenharmony_ci struct skcipher_request *breq = container_of(areq, struct skcipher_request, base); 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci err = sun8i_ss_cipher(breq); 3158c2ecf20Sopenharmony_ci local_bh_disable(); 3168c2ecf20Sopenharmony_ci crypto_finalize_skcipher_request(engine, breq, err); 3178c2ecf20Sopenharmony_ci local_bh_enable(); 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci return 0; 3208c2ecf20Sopenharmony_ci} 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ciint sun8i_ss_skdecrypt(struct skcipher_request *areq) 3238c2ecf20Sopenharmony_ci{ 3248c2ecf20Sopenharmony_ci struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(areq); 3258c2ecf20Sopenharmony_ci struct sun8i_cipher_tfm_ctx *op = crypto_skcipher_ctx(tfm); 3268c2ecf20Sopenharmony_ci struct sun8i_cipher_req_ctx *rctx = skcipher_request_ctx(areq); 3278c2ecf20Sopenharmony_ci struct crypto_engine *engine; 3288c2ecf20Sopenharmony_ci int e; 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci memset(rctx, 0, sizeof(struct sun8i_cipher_req_ctx)); 3318c2ecf20Sopenharmony_ci rctx->op_dir = SS_DECRYPTION; 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci if (sun8i_ss_need_fallback(areq)) 3348c2ecf20Sopenharmony_ci return sun8i_ss_cipher_fallback(areq); 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci e = sun8i_ss_get_engine_number(op->ss); 3378c2ecf20Sopenharmony_ci engine = op->ss->flows[e].engine; 3388c2ecf20Sopenharmony_ci rctx->flow = e; 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci return crypto_transfer_skcipher_request_to_engine(engine, areq); 3418c2ecf20Sopenharmony_ci} 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ciint sun8i_ss_skencrypt(struct skcipher_request *areq) 3448c2ecf20Sopenharmony_ci{ 3458c2ecf20Sopenharmony_ci struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(areq); 3468c2ecf20Sopenharmony_ci struct sun8i_cipher_tfm_ctx *op = crypto_skcipher_ctx(tfm); 3478c2ecf20Sopenharmony_ci struct sun8i_cipher_req_ctx *rctx = skcipher_request_ctx(areq); 3488c2ecf20Sopenharmony_ci struct crypto_engine *engine; 3498c2ecf20Sopenharmony_ci int e; 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci memset(rctx, 0, sizeof(struct sun8i_cipher_req_ctx)); 3528c2ecf20Sopenharmony_ci rctx->op_dir = SS_ENCRYPTION; 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci if (sun8i_ss_need_fallback(areq)) 3558c2ecf20Sopenharmony_ci return sun8i_ss_cipher_fallback(areq); 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci e = sun8i_ss_get_engine_number(op->ss); 3588c2ecf20Sopenharmony_ci engine = op->ss->flows[e].engine; 3598c2ecf20Sopenharmony_ci rctx->flow = e; 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci return crypto_transfer_skcipher_request_to_engine(engine, areq); 3628c2ecf20Sopenharmony_ci} 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ciint sun8i_ss_cipher_init(struct crypto_tfm *tfm) 3658c2ecf20Sopenharmony_ci{ 3668c2ecf20Sopenharmony_ci struct sun8i_cipher_tfm_ctx *op = crypto_tfm_ctx(tfm); 3678c2ecf20Sopenharmony_ci struct sun8i_ss_alg_template *algt; 3688c2ecf20Sopenharmony_ci const char *name = crypto_tfm_alg_name(tfm); 3698c2ecf20Sopenharmony_ci struct crypto_skcipher *sktfm = __crypto_skcipher_cast(tfm); 3708c2ecf20Sopenharmony_ci struct skcipher_alg *alg = crypto_skcipher_alg(sktfm); 3718c2ecf20Sopenharmony_ci int err; 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci memset(op, 0, sizeof(struct sun8i_cipher_tfm_ctx)); 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci algt = container_of(alg, struct sun8i_ss_alg_template, alg.skcipher); 3768c2ecf20Sopenharmony_ci op->ss = algt->ss; 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci op->fallback_tfm = crypto_alloc_skcipher(name, 0, CRYPTO_ALG_NEED_FALLBACK); 3798c2ecf20Sopenharmony_ci if (IS_ERR(op->fallback_tfm)) { 3808c2ecf20Sopenharmony_ci dev_err(op->ss->dev, "ERROR: Cannot allocate fallback for %s %ld\n", 3818c2ecf20Sopenharmony_ci name, PTR_ERR(op->fallback_tfm)); 3828c2ecf20Sopenharmony_ci return PTR_ERR(op->fallback_tfm); 3838c2ecf20Sopenharmony_ci } 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci sktfm->reqsize = sizeof(struct sun8i_cipher_req_ctx) + 3868c2ecf20Sopenharmony_ci crypto_skcipher_reqsize(op->fallback_tfm); 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci dev_info(op->ss->dev, "Fallback for %s is %s\n", 3908c2ecf20Sopenharmony_ci crypto_tfm_alg_driver_name(&sktfm->base), 3918c2ecf20Sopenharmony_ci crypto_tfm_alg_driver_name(crypto_skcipher_tfm(op->fallback_tfm))); 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci op->enginectx.op.do_one_request = sun8i_ss_handle_cipher_request; 3948c2ecf20Sopenharmony_ci op->enginectx.op.prepare_request = NULL; 3958c2ecf20Sopenharmony_ci op->enginectx.op.unprepare_request = NULL; 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci err = pm_runtime_resume_and_get(op->ss->dev); 3988c2ecf20Sopenharmony_ci if (err < 0) { 3998c2ecf20Sopenharmony_ci dev_err(op->ss->dev, "pm error %d\n", err); 4008c2ecf20Sopenharmony_ci goto error_pm; 4018c2ecf20Sopenharmony_ci } 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci return 0; 4048c2ecf20Sopenharmony_cierror_pm: 4058c2ecf20Sopenharmony_ci crypto_free_skcipher(op->fallback_tfm); 4068c2ecf20Sopenharmony_ci return err; 4078c2ecf20Sopenharmony_ci} 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_civoid sun8i_ss_cipher_exit(struct crypto_tfm *tfm) 4108c2ecf20Sopenharmony_ci{ 4118c2ecf20Sopenharmony_ci struct sun8i_cipher_tfm_ctx *op = crypto_tfm_ctx(tfm); 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci kfree_sensitive(op->key); 4148c2ecf20Sopenharmony_ci crypto_free_skcipher(op->fallback_tfm); 4158c2ecf20Sopenharmony_ci pm_runtime_put_sync(op->ss->dev); 4168c2ecf20Sopenharmony_ci} 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ciint sun8i_ss_aes_setkey(struct crypto_skcipher *tfm, const u8 *key, 4198c2ecf20Sopenharmony_ci unsigned int keylen) 4208c2ecf20Sopenharmony_ci{ 4218c2ecf20Sopenharmony_ci struct sun8i_cipher_tfm_ctx *op = crypto_skcipher_ctx(tfm); 4228c2ecf20Sopenharmony_ci struct sun8i_ss_dev *ss = op->ss; 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci switch (keylen) { 4258c2ecf20Sopenharmony_ci case 128 / 8: 4268c2ecf20Sopenharmony_ci break; 4278c2ecf20Sopenharmony_ci case 192 / 8: 4288c2ecf20Sopenharmony_ci break; 4298c2ecf20Sopenharmony_ci case 256 / 8: 4308c2ecf20Sopenharmony_ci break; 4318c2ecf20Sopenharmony_ci default: 4328c2ecf20Sopenharmony_ci dev_dbg(ss->dev, "ERROR: Invalid keylen %u\n", keylen); 4338c2ecf20Sopenharmony_ci return -EINVAL; 4348c2ecf20Sopenharmony_ci } 4358c2ecf20Sopenharmony_ci kfree_sensitive(op->key); 4368c2ecf20Sopenharmony_ci op->keylen = keylen; 4378c2ecf20Sopenharmony_ci op->key = kmemdup(key, keylen, GFP_KERNEL | GFP_DMA); 4388c2ecf20Sopenharmony_ci if (!op->key) 4398c2ecf20Sopenharmony_ci return -ENOMEM; 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci crypto_skcipher_clear_flags(op->fallback_tfm, CRYPTO_TFM_REQ_MASK); 4428c2ecf20Sopenharmony_ci crypto_skcipher_set_flags(op->fallback_tfm, tfm->base.crt_flags & CRYPTO_TFM_REQ_MASK); 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci return crypto_skcipher_setkey(op->fallback_tfm, key, keylen); 4458c2ecf20Sopenharmony_ci} 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ciint sun8i_ss_des3_setkey(struct crypto_skcipher *tfm, const u8 *key, 4488c2ecf20Sopenharmony_ci unsigned int keylen) 4498c2ecf20Sopenharmony_ci{ 4508c2ecf20Sopenharmony_ci struct sun8i_cipher_tfm_ctx *op = crypto_skcipher_ctx(tfm); 4518c2ecf20Sopenharmony_ci struct sun8i_ss_dev *ss = op->ss; 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci if (unlikely(keylen != 3 * DES_KEY_SIZE)) { 4548c2ecf20Sopenharmony_ci dev_dbg(ss->dev, "Invalid keylen %u\n", keylen); 4558c2ecf20Sopenharmony_ci return -EINVAL; 4568c2ecf20Sopenharmony_ci } 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci kfree_sensitive(op->key); 4598c2ecf20Sopenharmony_ci op->keylen = keylen; 4608c2ecf20Sopenharmony_ci op->key = kmemdup(key, keylen, GFP_KERNEL | GFP_DMA); 4618c2ecf20Sopenharmony_ci if (!op->key) 4628c2ecf20Sopenharmony_ci return -ENOMEM; 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci crypto_skcipher_clear_flags(op->fallback_tfm, CRYPTO_TFM_REQ_MASK); 4658c2ecf20Sopenharmony_ci crypto_skcipher_set_flags(op->fallback_tfm, tfm->base.crt_flags & CRYPTO_TFM_REQ_MASK); 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci return crypto_skcipher_setkey(op->fallback_tfm, key, keylen); 4688c2ecf20Sopenharmony_ci} 469