18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Xilinx ZynqMP AES Driver. 48c2ecf20Sopenharmony_ci * Copyright (c) 2020 Xilinx Inc. 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include <crypto/aes.h> 88c2ecf20Sopenharmony_ci#include <crypto/engine.h> 98c2ecf20Sopenharmony_ci#include <crypto/gcm.h> 108c2ecf20Sopenharmony_ci#include <crypto/internal/aead.h> 118c2ecf20Sopenharmony_ci#include <crypto/scatterwalk.h> 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h> 148c2ecf20Sopenharmony_ci#include <linux/module.h> 158c2ecf20Sopenharmony_ci#include <linux/of_device.h> 168c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#include <linux/firmware/xlnx-zynqmp.h> 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#define ZYNQMP_DMA_BIT_MASK 32U 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci#define ZYNQMP_AES_KEY_SIZE AES_KEYSIZE_256 238c2ecf20Sopenharmony_ci#define ZYNQMP_AES_AUTH_SIZE 16U 248c2ecf20Sopenharmony_ci#define ZYNQMP_KEY_SRC_SEL_KEY_LEN 1U 258c2ecf20Sopenharmony_ci#define ZYNQMP_AES_BLK_SIZE 1U 268c2ecf20Sopenharmony_ci#define ZYNQMP_AES_MIN_INPUT_BLK_SIZE 4U 278c2ecf20Sopenharmony_ci#define ZYNQMP_AES_WORD_LEN 4U 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci#define ZYNQMP_AES_GCM_TAG_MISMATCH_ERR 0x01 308c2ecf20Sopenharmony_ci#define ZYNQMP_AES_WRONG_KEY_SRC_ERR 0x13 318c2ecf20Sopenharmony_ci#define ZYNQMP_AES_PUF_NOT_PROGRAMMED 0xE300 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_cienum zynqmp_aead_op { 348c2ecf20Sopenharmony_ci ZYNQMP_AES_DECRYPT = 0, 358c2ecf20Sopenharmony_ci ZYNQMP_AES_ENCRYPT 368c2ecf20Sopenharmony_ci}; 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_cienum zynqmp_aead_keysrc { 398c2ecf20Sopenharmony_ci ZYNQMP_AES_KUP_KEY = 0, 408c2ecf20Sopenharmony_ci ZYNQMP_AES_DEV_KEY, 418c2ecf20Sopenharmony_ci ZYNQMP_AES_PUF_KEY 428c2ecf20Sopenharmony_ci}; 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_cistruct zynqmp_aead_drv_ctx { 458c2ecf20Sopenharmony_ci union { 468c2ecf20Sopenharmony_ci struct aead_alg aead; 478c2ecf20Sopenharmony_ci } alg; 488c2ecf20Sopenharmony_ci struct device *dev; 498c2ecf20Sopenharmony_ci struct crypto_engine *engine; 508c2ecf20Sopenharmony_ci}; 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_cistruct zynqmp_aead_hw_req { 538c2ecf20Sopenharmony_ci u64 src; 548c2ecf20Sopenharmony_ci u64 iv; 558c2ecf20Sopenharmony_ci u64 key; 568c2ecf20Sopenharmony_ci u64 dst; 578c2ecf20Sopenharmony_ci u64 size; 588c2ecf20Sopenharmony_ci u64 op; 598c2ecf20Sopenharmony_ci u64 keysrc; 608c2ecf20Sopenharmony_ci}; 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_cistruct zynqmp_aead_tfm_ctx { 638c2ecf20Sopenharmony_ci struct crypto_engine_ctx engine_ctx; 648c2ecf20Sopenharmony_ci struct device *dev; 658c2ecf20Sopenharmony_ci u8 key[ZYNQMP_AES_KEY_SIZE]; 668c2ecf20Sopenharmony_ci u8 *iv; 678c2ecf20Sopenharmony_ci u32 keylen; 688c2ecf20Sopenharmony_ci u32 authsize; 698c2ecf20Sopenharmony_ci enum zynqmp_aead_keysrc keysrc; 708c2ecf20Sopenharmony_ci struct crypto_aead *fbk_cipher; 718c2ecf20Sopenharmony_ci}; 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_cistruct zynqmp_aead_req_ctx { 748c2ecf20Sopenharmony_ci enum zynqmp_aead_op op; 758c2ecf20Sopenharmony_ci}; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_cistatic int zynqmp_aes_aead_cipher(struct aead_request *req) 788c2ecf20Sopenharmony_ci{ 798c2ecf20Sopenharmony_ci struct crypto_aead *aead = crypto_aead_reqtfm(req); 808c2ecf20Sopenharmony_ci struct zynqmp_aead_tfm_ctx *tfm_ctx = crypto_aead_ctx(aead); 818c2ecf20Sopenharmony_ci struct zynqmp_aead_req_ctx *rq_ctx = aead_request_ctx(req); 828c2ecf20Sopenharmony_ci struct device *dev = tfm_ctx->dev; 838c2ecf20Sopenharmony_ci struct zynqmp_aead_hw_req *hwreq; 848c2ecf20Sopenharmony_ci dma_addr_t dma_addr_data, dma_addr_hw_req; 858c2ecf20Sopenharmony_ci unsigned int data_size; 868c2ecf20Sopenharmony_ci unsigned int status; 878c2ecf20Sopenharmony_ci int ret; 888c2ecf20Sopenharmony_ci size_t dma_size; 898c2ecf20Sopenharmony_ci char *kbuf; 908c2ecf20Sopenharmony_ci int err; 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci if (tfm_ctx->keysrc == ZYNQMP_AES_KUP_KEY) 938c2ecf20Sopenharmony_ci dma_size = req->cryptlen + ZYNQMP_AES_KEY_SIZE 948c2ecf20Sopenharmony_ci + GCM_AES_IV_SIZE; 958c2ecf20Sopenharmony_ci else 968c2ecf20Sopenharmony_ci dma_size = req->cryptlen + GCM_AES_IV_SIZE; 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci kbuf = dma_alloc_coherent(dev, dma_size, &dma_addr_data, GFP_KERNEL); 998c2ecf20Sopenharmony_ci if (!kbuf) 1008c2ecf20Sopenharmony_ci return -ENOMEM; 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci hwreq = dma_alloc_coherent(dev, sizeof(struct zynqmp_aead_hw_req), 1038c2ecf20Sopenharmony_ci &dma_addr_hw_req, GFP_KERNEL); 1048c2ecf20Sopenharmony_ci if (!hwreq) { 1058c2ecf20Sopenharmony_ci dma_free_coherent(dev, dma_size, kbuf, dma_addr_data); 1068c2ecf20Sopenharmony_ci return -ENOMEM; 1078c2ecf20Sopenharmony_ci } 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci data_size = req->cryptlen; 1108c2ecf20Sopenharmony_ci scatterwalk_map_and_copy(kbuf, req->src, 0, req->cryptlen, 0); 1118c2ecf20Sopenharmony_ci memcpy(kbuf + data_size, req->iv, GCM_AES_IV_SIZE); 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci hwreq->src = dma_addr_data; 1148c2ecf20Sopenharmony_ci hwreq->dst = dma_addr_data; 1158c2ecf20Sopenharmony_ci hwreq->iv = hwreq->src + data_size; 1168c2ecf20Sopenharmony_ci hwreq->keysrc = tfm_ctx->keysrc; 1178c2ecf20Sopenharmony_ci hwreq->op = rq_ctx->op; 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci if (hwreq->op == ZYNQMP_AES_ENCRYPT) 1208c2ecf20Sopenharmony_ci hwreq->size = data_size; 1218c2ecf20Sopenharmony_ci else 1228c2ecf20Sopenharmony_ci hwreq->size = data_size - ZYNQMP_AES_AUTH_SIZE; 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci if (hwreq->keysrc == ZYNQMP_AES_KUP_KEY) { 1258c2ecf20Sopenharmony_ci memcpy(kbuf + data_size + GCM_AES_IV_SIZE, 1268c2ecf20Sopenharmony_ci tfm_ctx->key, ZYNQMP_AES_KEY_SIZE); 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci hwreq->key = hwreq->src + data_size + GCM_AES_IV_SIZE; 1298c2ecf20Sopenharmony_ci } else { 1308c2ecf20Sopenharmony_ci hwreq->key = 0; 1318c2ecf20Sopenharmony_ci } 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci ret = zynqmp_pm_aes_engine(dma_addr_hw_req, &status); 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci if (ret) { 1368c2ecf20Sopenharmony_ci dev_err(dev, "ERROR: AES PM API failed\n"); 1378c2ecf20Sopenharmony_ci err = ret; 1388c2ecf20Sopenharmony_ci } else if (status) { 1398c2ecf20Sopenharmony_ci switch (status) { 1408c2ecf20Sopenharmony_ci case ZYNQMP_AES_GCM_TAG_MISMATCH_ERR: 1418c2ecf20Sopenharmony_ci dev_err(dev, "ERROR: Gcm Tag mismatch\n"); 1428c2ecf20Sopenharmony_ci break; 1438c2ecf20Sopenharmony_ci case ZYNQMP_AES_WRONG_KEY_SRC_ERR: 1448c2ecf20Sopenharmony_ci dev_err(dev, "ERROR: Wrong KeySrc, enable secure mode\n"); 1458c2ecf20Sopenharmony_ci break; 1468c2ecf20Sopenharmony_ci case ZYNQMP_AES_PUF_NOT_PROGRAMMED: 1478c2ecf20Sopenharmony_ci dev_err(dev, "ERROR: PUF is not registered\n"); 1488c2ecf20Sopenharmony_ci break; 1498c2ecf20Sopenharmony_ci default: 1508c2ecf20Sopenharmony_ci dev_err(dev, "ERROR: Unknown error\n"); 1518c2ecf20Sopenharmony_ci break; 1528c2ecf20Sopenharmony_ci } 1538c2ecf20Sopenharmony_ci err = -status; 1548c2ecf20Sopenharmony_ci } else { 1558c2ecf20Sopenharmony_ci if (hwreq->op == ZYNQMP_AES_ENCRYPT) 1568c2ecf20Sopenharmony_ci data_size = data_size + ZYNQMP_AES_AUTH_SIZE; 1578c2ecf20Sopenharmony_ci else 1588c2ecf20Sopenharmony_ci data_size = data_size - ZYNQMP_AES_AUTH_SIZE; 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci sg_copy_from_buffer(req->dst, sg_nents(req->dst), 1618c2ecf20Sopenharmony_ci kbuf, data_size); 1628c2ecf20Sopenharmony_ci err = 0; 1638c2ecf20Sopenharmony_ci } 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci if (kbuf) { 1668c2ecf20Sopenharmony_ci memzero_explicit(kbuf, dma_size); 1678c2ecf20Sopenharmony_ci dma_free_coherent(dev, dma_size, kbuf, dma_addr_data); 1688c2ecf20Sopenharmony_ci } 1698c2ecf20Sopenharmony_ci if (hwreq) { 1708c2ecf20Sopenharmony_ci memzero_explicit(hwreq, sizeof(struct zynqmp_aead_hw_req)); 1718c2ecf20Sopenharmony_ci dma_free_coherent(dev, sizeof(struct zynqmp_aead_hw_req), 1728c2ecf20Sopenharmony_ci hwreq, dma_addr_hw_req); 1738c2ecf20Sopenharmony_ci } 1748c2ecf20Sopenharmony_ci return err; 1758c2ecf20Sopenharmony_ci} 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_cistatic int zynqmp_fallback_check(struct zynqmp_aead_tfm_ctx *tfm_ctx, 1788c2ecf20Sopenharmony_ci struct aead_request *req) 1798c2ecf20Sopenharmony_ci{ 1808c2ecf20Sopenharmony_ci int need_fallback = 0; 1818c2ecf20Sopenharmony_ci struct zynqmp_aead_req_ctx *rq_ctx = aead_request_ctx(req); 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci if (tfm_ctx->authsize != ZYNQMP_AES_AUTH_SIZE) 1848c2ecf20Sopenharmony_ci need_fallback = 1; 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci if (tfm_ctx->keysrc == ZYNQMP_AES_KUP_KEY && 1878c2ecf20Sopenharmony_ci tfm_ctx->keylen != ZYNQMP_AES_KEY_SIZE) { 1888c2ecf20Sopenharmony_ci need_fallback = 1; 1898c2ecf20Sopenharmony_ci } 1908c2ecf20Sopenharmony_ci if (req->assoclen != 0 || 1918c2ecf20Sopenharmony_ci req->cryptlen < ZYNQMP_AES_MIN_INPUT_BLK_SIZE) { 1928c2ecf20Sopenharmony_ci need_fallback = 1; 1938c2ecf20Sopenharmony_ci } 1948c2ecf20Sopenharmony_ci if ((req->cryptlen % ZYNQMP_AES_WORD_LEN) != 0) 1958c2ecf20Sopenharmony_ci need_fallback = 1; 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci if (rq_ctx->op == ZYNQMP_AES_DECRYPT && 1988c2ecf20Sopenharmony_ci req->cryptlen <= ZYNQMP_AES_AUTH_SIZE) { 1998c2ecf20Sopenharmony_ci need_fallback = 1; 2008c2ecf20Sopenharmony_ci } 2018c2ecf20Sopenharmony_ci return need_fallback; 2028c2ecf20Sopenharmony_ci} 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_cistatic int zynqmp_handle_aes_req(struct crypto_engine *engine, 2058c2ecf20Sopenharmony_ci void *req) 2068c2ecf20Sopenharmony_ci{ 2078c2ecf20Sopenharmony_ci struct aead_request *areq = 2088c2ecf20Sopenharmony_ci container_of(req, struct aead_request, base); 2098c2ecf20Sopenharmony_ci struct crypto_aead *aead = crypto_aead_reqtfm(req); 2108c2ecf20Sopenharmony_ci struct zynqmp_aead_tfm_ctx *tfm_ctx = crypto_aead_ctx(aead); 2118c2ecf20Sopenharmony_ci struct zynqmp_aead_req_ctx *rq_ctx = aead_request_ctx(areq); 2128c2ecf20Sopenharmony_ci struct aead_request *subreq = aead_request_ctx(req); 2138c2ecf20Sopenharmony_ci int need_fallback; 2148c2ecf20Sopenharmony_ci int err; 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci need_fallback = zynqmp_fallback_check(tfm_ctx, areq); 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci if (need_fallback) { 2198c2ecf20Sopenharmony_ci aead_request_set_tfm(subreq, tfm_ctx->fbk_cipher); 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci aead_request_set_callback(subreq, areq->base.flags, 2228c2ecf20Sopenharmony_ci NULL, NULL); 2238c2ecf20Sopenharmony_ci aead_request_set_crypt(subreq, areq->src, areq->dst, 2248c2ecf20Sopenharmony_ci areq->cryptlen, areq->iv); 2258c2ecf20Sopenharmony_ci aead_request_set_ad(subreq, areq->assoclen); 2268c2ecf20Sopenharmony_ci if (rq_ctx->op == ZYNQMP_AES_ENCRYPT) 2278c2ecf20Sopenharmony_ci err = crypto_aead_encrypt(subreq); 2288c2ecf20Sopenharmony_ci else 2298c2ecf20Sopenharmony_ci err = crypto_aead_decrypt(subreq); 2308c2ecf20Sopenharmony_ci } else { 2318c2ecf20Sopenharmony_ci err = zynqmp_aes_aead_cipher(areq); 2328c2ecf20Sopenharmony_ci } 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci crypto_finalize_aead_request(engine, areq, err); 2358c2ecf20Sopenharmony_ci return 0; 2368c2ecf20Sopenharmony_ci} 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_cistatic int zynqmp_aes_aead_setkey(struct crypto_aead *aead, const u8 *key, 2398c2ecf20Sopenharmony_ci unsigned int keylen) 2408c2ecf20Sopenharmony_ci{ 2418c2ecf20Sopenharmony_ci struct crypto_tfm *tfm = crypto_aead_tfm(aead); 2428c2ecf20Sopenharmony_ci struct zynqmp_aead_tfm_ctx *tfm_ctx = 2438c2ecf20Sopenharmony_ci (struct zynqmp_aead_tfm_ctx *)crypto_tfm_ctx(tfm); 2448c2ecf20Sopenharmony_ci unsigned char keysrc; 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci if (keylen == ZYNQMP_KEY_SRC_SEL_KEY_LEN) { 2478c2ecf20Sopenharmony_ci keysrc = *key; 2488c2ecf20Sopenharmony_ci if (keysrc == ZYNQMP_AES_KUP_KEY || 2498c2ecf20Sopenharmony_ci keysrc == ZYNQMP_AES_DEV_KEY || 2508c2ecf20Sopenharmony_ci keysrc == ZYNQMP_AES_PUF_KEY) { 2518c2ecf20Sopenharmony_ci tfm_ctx->keysrc = (enum zynqmp_aead_keysrc)keysrc; 2528c2ecf20Sopenharmony_ci } else { 2538c2ecf20Sopenharmony_ci tfm_ctx->keylen = keylen; 2548c2ecf20Sopenharmony_ci } 2558c2ecf20Sopenharmony_ci } else { 2568c2ecf20Sopenharmony_ci tfm_ctx->keylen = keylen; 2578c2ecf20Sopenharmony_ci if (keylen == ZYNQMP_AES_KEY_SIZE) { 2588c2ecf20Sopenharmony_ci tfm_ctx->keysrc = ZYNQMP_AES_KUP_KEY; 2598c2ecf20Sopenharmony_ci memcpy(tfm_ctx->key, key, keylen); 2608c2ecf20Sopenharmony_ci } 2618c2ecf20Sopenharmony_ci } 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci tfm_ctx->fbk_cipher->base.crt_flags &= ~CRYPTO_TFM_REQ_MASK; 2648c2ecf20Sopenharmony_ci tfm_ctx->fbk_cipher->base.crt_flags |= (aead->base.crt_flags & 2658c2ecf20Sopenharmony_ci CRYPTO_TFM_REQ_MASK); 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci return crypto_aead_setkey(tfm_ctx->fbk_cipher, key, keylen); 2688c2ecf20Sopenharmony_ci} 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_cistatic int zynqmp_aes_aead_setauthsize(struct crypto_aead *aead, 2718c2ecf20Sopenharmony_ci unsigned int authsize) 2728c2ecf20Sopenharmony_ci{ 2738c2ecf20Sopenharmony_ci struct crypto_tfm *tfm = crypto_aead_tfm(aead); 2748c2ecf20Sopenharmony_ci struct zynqmp_aead_tfm_ctx *tfm_ctx = 2758c2ecf20Sopenharmony_ci (struct zynqmp_aead_tfm_ctx *)crypto_tfm_ctx(tfm); 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci tfm_ctx->authsize = authsize; 2788c2ecf20Sopenharmony_ci return crypto_aead_setauthsize(tfm_ctx->fbk_cipher, authsize); 2798c2ecf20Sopenharmony_ci} 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_cistatic int zynqmp_aes_aead_encrypt(struct aead_request *req) 2828c2ecf20Sopenharmony_ci{ 2838c2ecf20Sopenharmony_ci struct zynqmp_aead_drv_ctx *drv_ctx; 2848c2ecf20Sopenharmony_ci struct crypto_aead *aead = crypto_aead_reqtfm(req); 2858c2ecf20Sopenharmony_ci struct aead_alg *alg = crypto_aead_alg(aead); 2868c2ecf20Sopenharmony_ci struct zynqmp_aead_req_ctx *rq_ctx = aead_request_ctx(req); 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci rq_ctx->op = ZYNQMP_AES_ENCRYPT; 2898c2ecf20Sopenharmony_ci drv_ctx = container_of(alg, struct zynqmp_aead_drv_ctx, alg.aead); 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci return crypto_transfer_aead_request_to_engine(drv_ctx->engine, req); 2928c2ecf20Sopenharmony_ci} 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_cistatic int zynqmp_aes_aead_decrypt(struct aead_request *req) 2958c2ecf20Sopenharmony_ci{ 2968c2ecf20Sopenharmony_ci struct zynqmp_aead_drv_ctx *drv_ctx; 2978c2ecf20Sopenharmony_ci struct crypto_aead *aead = crypto_aead_reqtfm(req); 2988c2ecf20Sopenharmony_ci struct aead_alg *alg = crypto_aead_alg(aead); 2998c2ecf20Sopenharmony_ci struct zynqmp_aead_req_ctx *rq_ctx = aead_request_ctx(req); 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci rq_ctx->op = ZYNQMP_AES_DECRYPT; 3028c2ecf20Sopenharmony_ci drv_ctx = container_of(alg, struct zynqmp_aead_drv_ctx, alg.aead); 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci return crypto_transfer_aead_request_to_engine(drv_ctx->engine, req); 3058c2ecf20Sopenharmony_ci} 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_cistatic int zynqmp_aes_aead_init(struct crypto_aead *aead) 3088c2ecf20Sopenharmony_ci{ 3098c2ecf20Sopenharmony_ci struct crypto_tfm *tfm = crypto_aead_tfm(aead); 3108c2ecf20Sopenharmony_ci struct zynqmp_aead_tfm_ctx *tfm_ctx = 3118c2ecf20Sopenharmony_ci (struct zynqmp_aead_tfm_ctx *)crypto_tfm_ctx(tfm); 3128c2ecf20Sopenharmony_ci struct zynqmp_aead_drv_ctx *drv_ctx; 3138c2ecf20Sopenharmony_ci struct aead_alg *alg = crypto_aead_alg(aead); 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci drv_ctx = container_of(alg, struct zynqmp_aead_drv_ctx, alg.aead); 3168c2ecf20Sopenharmony_ci tfm_ctx->dev = drv_ctx->dev; 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci tfm_ctx->engine_ctx.op.do_one_request = zynqmp_handle_aes_req; 3198c2ecf20Sopenharmony_ci tfm_ctx->engine_ctx.op.prepare_request = NULL; 3208c2ecf20Sopenharmony_ci tfm_ctx->engine_ctx.op.unprepare_request = NULL; 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci tfm_ctx->fbk_cipher = crypto_alloc_aead(drv_ctx->alg.aead.base.cra_name, 3238c2ecf20Sopenharmony_ci 0, 3248c2ecf20Sopenharmony_ci CRYPTO_ALG_NEED_FALLBACK); 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci if (IS_ERR(tfm_ctx->fbk_cipher)) { 3278c2ecf20Sopenharmony_ci pr_err("%s() Error: failed to allocate fallback for %s\n", 3288c2ecf20Sopenharmony_ci __func__, drv_ctx->alg.aead.base.cra_name); 3298c2ecf20Sopenharmony_ci return PTR_ERR(tfm_ctx->fbk_cipher); 3308c2ecf20Sopenharmony_ci } 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci crypto_aead_set_reqsize(aead, 3338c2ecf20Sopenharmony_ci max(sizeof(struct zynqmp_aead_req_ctx), 3348c2ecf20Sopenharmony_ci sizeof(struct aead_request) + 3358c2ecf20Sopenharmony_ci crypto_aead_reqsize(tfm_ctx->fbk_cipher))); 3368c2ecf20Sopenharmony_ci return 0; 3378c2ecf20Sopenharmony_ci} 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_cistatic void zynqmp_aes_aead_exit(struct crypto_aead *aead) 3408c2ecf20Sopenharmony_ci{ 3418c2ecf20Sopenharmony_ci struct crypto_tfm *tfm = crypto_aead_tfm(aead); 3428c2ecf20Sopenharmony_ci struct zynqmp_aead_tfm_ctx *tfm_ctx = 3438c2ecf20Sopenharmony_ci (struct zynqmp_aead_tfm_ctx *)crypto_tfm_ctx(tfm); 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci if (tfm_ctx->fbk_cipher) { 3468c2ecf20Sopenharmony_ci crypto_free_aead(tfm_ctx->fbk_cipher); 3478c2ecf20Sopenharmony_ci tfm_ctx->fbk_cipher = NULL; 3488c2ecf20Sopenharmony_ci } 3498c2ecf20Sopenharmony_ci memzero_explicit(tfm_ctx, sizeof(struct zynqmp_aead_tfm_ctx)); 3508c2ecf20Sopenharmony_ci} 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_cistatic struct zynqmp_aead_drv_ctx aes_drv_ctx = { 3538c2ecf20Sopenharmony_ci .alg.aead = { 3548c2ecf20Sopenharmony_ci .setkey = zynqmp_aes_aead_setkey, 3558c2ecf20Sopenharmony_ci .setauthsize = zynqmp_aes_aead_setauthsize, 3568c2ecf20Sopenharmony_ci .encrypt = zynqmp_aes_aead_encrypt, 3578c2ecf20Sopenharmony_ci .decrypt = zynqmp_aes_aead_decrypt, 3588c2ecf20Sopenharmony_ci .init = zynqmp_aes_aead_init, 3598c2ecf20Sopenharmony_ci .exit = zynqmp_aes_aead_exit, 3608c2ecf20Sopenharmony_ci .ivsize = GCM_AES_IV_SIZE, 3618c2ecf20Sopenharmony_ci .maxauthsize = ZYNQMP_AES_AUTH_SIZE, 3628c2ecf20Sopenharmony_ci .base = { 3638c2ecf20Sopenharmony_ci .cra_name = "gcm(aes)", 3648c2ecf20Sopenharmony_ci .cra_driver_name = "xilinx-zynqmp-aes-gcm", 3658c2ecf20Sopenharmony_ci .cra_priority = 200, 3668c2ecf20Sopenharmony_ci .cra_flags = CRYPTO_ALG_TYPE_AEAD | 3678c2ecf20Sopenharmony_ci CRYPTO_ALG_ASYNC | 3688c2ecf20Sopenharmony_ci CRYPTO_ALG_ALLOCATES_MEMORY | 3698c2ecf20Sopenharmony_ci CRYPTO_ALG_KERN_DRIVER_ONLY | 3708c2ecf20Sopenharmony_ci CRYPTO_ALG_NEED_FALLBACK, 3718c2ecf20Sopenharmony_ci .cra_blocksize = ZYNQMP_AES_BLK_SIZE, 3728c2ecf20Sopenharmony_ci .cra_ctxsize = sizeof(struct zynqmp_aead_tfm_ctx), 3738c2ecf20Sopenharmony_ci .cra_module = THIS_MODULE, 3748c2ecf20Sopenharmony_ci } 3758c2ecf20Sopenharmony_ci } 3768c2ecf20Sopenharmony_ci}; 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_cistatic int zynqmp_aes_aead_probe(struct platform_device *pdev) 3798c2ecf20Sopenharmony_ci{ 3808c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 3818c2ecf20Sopenharmony_ci int err; 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci /* ZynqMP AES driver supports only one instance */ 3848c2ecf20Sopenharmony_ci if (!aes_drv_ctx.dev) 3858c2ecf20Sopenharmony_ci aes_drv_ctx.dev = dev; 3868c2ecf20Sopenharmony_ci else 3878c2ecf20Sopenharmony_ci return -ENODEV; 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci err = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(ZYNQMP_DMA_BIT_MASK)); 3908c2ecf20Sopenharmony_ci if (err < 0) { 3918c2ecf20Sopenharmony_ci dev_err(dev, "No usable DMA configuration\n"); 3928c2ecf20Sopenharmony_ci return err; 3938c2ecf20Sopenharmony_ci } 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci aes_drv_ctx.engine = crypto_engine_alloc_init(dev, 1); 3968c2ecf20Sopenharmony_ci if (!aes_drv_ctx.engine) { 3978c2ecf20Sopenharmony_ci dev_err(dev, "Cannot alloc AES engine\n"); 3988c2ecf20Sopenharmony_ci err = -ENOMEM; 3998c2ecf20Sopenharmony_ci goto err_engine; 4008c2ecf20Sopenharmony_ci } 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci err = crypto_engine_start(aes_drv_ctx.engine); 4038c2ecf20Sopenharmony_ci if (err) { 4048c2ecf20Sopenharmony_ci dev_err(dev, "Cannot start AES engine\n"); 4058c2ecf20Sopenharmony_ci goto err_engine; 4068c2ecf20Sopenharmony_ci } 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci err = crypto_register_aead(&aes_drv_ctx.alg.aead); 4098c2ecf20Sopenharmony_ci if (err < 0) { 4108c2ecf20Sopenharmony_ci dev_err(dev, "Failed to register AEAD alg.\n"); 4118c2ecf20Sopenharmony_ci goto err_aead; 4128c2ecf20Sopenharmony_ci } 4138c2ecf20Sopenharmony_ci return 0; 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_cierr_aead: 4168c2ecf20Sopenharmony_ci crypto_unregister_aead(&aes_drv_ctx.alg.aead); 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_cierr_engine: 4198c2ecf20Sopenharmony_ci if (aes_drv_ctx.engine) 4208c2ecf20Sopenharmony_ci crypto_engine_exit(aes_drv_ctx.engine); 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci return err; 4238c2ecf20Sopenharmony_ci} 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_cistatic int zynqmp_aes_aead_remove(struct platform_device *pdev) 4268c2ecf20Sopenharmony_ci{ 4278c2ecf20Sopenharmony_ci crypto_engine_exit(aes_drv_ctx.engine); 4288c2ecf20Sopenharmony_ci crypto_unregister_aead(&aes_drv_ctx.alg.aead); 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_ci return 0; 4318c2ecf20Sopenharmony_ci} 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_cistatic const struct of_device_id zynqmp_aes_dt_ids[] = { 4348c2ecf20Sopenharmony_ci { .compatible = "xlnx,zynqmp-aes" }, 4358c2ecf20Sopenharmony_ci { /* sentinel */ } 4368c2ecf20Sopenharmony_ci}; 4378c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, zynqmp_aes_dt_ids); 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_cistatic struct platform_driver zynqmp_aes_driver = { 4408c2ecf20Sopenharmony_ci .probe = zynqmp_aes_aead_probe, 4418c2ecf20Sopenharmony_ci .remove = zynqmp_aes_aead_remove, 4428c2ecf20Sopenharmony_ci .driver = { 4438c2ecf20Sopenharmony_ci .name = "zynqmp-aes", 4448c2ecf20Sopenharmony_ci .of_match_table = zynqmp_aes_dt_ids, 4458c2ecf20Sopenharmony_ci }, 4468c2ecf20Sopenharmony_ci}; 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_cimodule_platform_driver(zynqmp_aes_driver); 4498c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 450