18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Driver for ARTPEC-6 crypto block using the kernel asynchronous crypto api. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2014-2017 Axis Communications AB 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <linux/bitfield.h> 108c2ecf20Sopenharmony_ci#include <linux/crypto.h> 118c2ecf20Sopenharmony_ci#include <linux/debugfs.h> 128c2ecf20Sopenharmony_ci#include <linux/delay.h> 138c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h> 148c2ecf20Sopenharmony_ci#include <linux/fault-inject.h> 158c2ecf20Sopenharmony_ci#include <linux/init.h> 168c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 178c2ecf20Sopenharmony_ci#include <linux/kernel.h> 188c2ecf20Sopenharmony_ci#include <linux/list.h> 198c2ecf20Sopenharmony_ci#include <linux/module.h> 208c2ecf20Sopenharmony_ci#include <linux/of.h> 218c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 228c2ecf20Sopenharmony_ci#include <linux/scatterlist.h> 238c2ecf20Sopenharmony_ci#include <linux/slab.h> 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci#include <crypto/aes.h> 268c2ecf20Sopenharmony_ci#include <crypto/gcm.h> 278c2ecf20Sopenharmony_ci#include <crypto/internal/aead.h> 288c2ecf20Sopenharmony_ci#include <crypto/internal/hash.h> 298c2ecf20Sopenharmony_ci#include <crypto/internal/skcipher.h> 308c2ecf20Sopenharmony_ci#include <crypto/scatterwalk.h> 318c2ecf20Sopenharmony_ci#include <crypto/sha.h> 328c2ecf20Sopenharmony_ci#include <crypto/xts.h> 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci/* Max length of a line in all cache levels for Artpec SoCs. */ 358c2ecf20Sopenharmony_ci#define ARTPEC_CACHE_LINE_MAX 32 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci#define PDMA_OUT_CFG 0x0000 388c2ecf20Sopenharmony_ci#define PDMA_OUT_BUF_CFG 0x0004 398c2ecf20Sopenharmony_ci#define PDMA_OUT_CMD 0x0008 408c2ecf20Sopenharmony_ci#define PDMA_OUT_DESCRQ_PUSH 0x0010 418c2ecf20Sopenharmony_ci#define PDMA_OUT_DESCRQ_STAT 0x0014 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci#define A6_PDMA_IN_CFG 0x0028 448c2ecf20Sopenharmony_ci#define A6_PDMA_IN_BUF_CFG 0x002c 458c2ecf20Sopenharmony_ci#define A6_PDMA_IN_CMD 0x0030 468c2ecf20Sopenharmony_ci#define A6_PDMA_IN_STATQ_PUSH 0x0038 478c2ecf20Sopenharmony_ci#define A6_PDMA_IN_DESCRQ_PUSH 0x0044 488c2ecf20Sopenharmony_ci#define A6_PDMA_IN_DESCRQ_STAT 0x0048 498c2ecf20Sopenharmony_ci#define A6_PDMA_INTR_MASK 0x0068 508c2ecf20Sopenharmony_ci#define A6_PDMA_ACK_INTR 0x006c 518c2ecf20Sopenharmony_ci#define A6_PDMA_MASKED_INTR 0x0074 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci#define A7_PDMA_IN_CFG 0x002c 548c2ecf20Sopenharmony_ci#define A7_PDMA_IN_BUF_CFG 0x0030 558c2ecf20Sopenharmony_ci#define A7_PDMA_IN_CMD 0x0034 568c2ecf20Sopenharmony_ci#define A7_PDMA_IN_STATQ_PUSH 0x003c 578c2ecf20Sopenharmony_ci#define A7_PDMA_IN_DESCRQ_PUSH 0x0048 588c2ecf20Sopenharmony_ci#define A7_PDMA_IN_DESCRQ_STAT 0x004C 598c2ecf20Sopenharmony_ci#define A7_PDMA_INTR_MASK 0x006c 608c2ecf20Sopenharmony_ci#define A7_PDMA_ACK_INTR 0x0070 618c2ecf20Sopenharmony_ci#define A7_PDMA_MASKED_INTR 0x0078 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci#define PDMA_OUT_CFG_EN BIT(0) 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci#define PDMA_OUT_BUF_CFG_DATA_BUF_SIZE GENMASK(4, 0) 668c2ecf20Sopenharmony_ci#define PDMA_OUT_BUF_CFG_DESCR_BUF_SIZE GENMASK(9, 5) 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci#define PDMA_OUT_CMD_START BIT(0) 698c2ecf20Sopenharmony_ci#define A6_PDMA_OUT_CMD_STOP BIT(3) 708c2ecf20Sopenharmony_ci#define A7_PDMA_OUT_CMD_STOP BIT(2) 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci#define PDMA_OUT_DESCRQ_PUSH_LEN GENMASK(5, 0) 738c2ecf20Sopenharmony_ci#define PDMA_OUT_DESCRQ_PUSH_ADDR GENMASK(31, 6) 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci#define PDMA_OUT_DESCRQ_STAT_LEVEL GENMASK(3, 0) 768c2ecf20Sopenharmony_ci#define PDMA_OUT_DESCRQ_STAT_SIZE GENMASK(7, 4) 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci#define PDMA_IN_CFG_EN BIT(0) 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci#define PDMA_IN_BUF_CFG_DATA_BUF_SIZE GENMASK(4, 0) 818c2ecf20Sopenharmony_ci#define PDMA_IN_BUF_CFG_DESCR_BUF_SIZE GENMASK(9, 5) 828c2ecf20Sopenharmony_ci#define PDMA_IN_BUF_CFG_STAT_BUF_SIZE GENMASK(14, 10) 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci#define PDMA_IN_CMD_START BIT(0) 858c2ecf20Sopenharmony_ci#define A6_PDMA_IN_CMD_FLUSH_STAT BIT(2) 868c2ecf20Sopenharmony_ci#define A6_PDMA_IN_CMD_STOP BIT(3) 878c2ecf20Sopenharmony_ci#define A7_PDMA_IN_CMD_FLUSH_STAT BIT(1) 888c2ecf20Sopenharmony_ci#define A7_PDMA_IN_CMD_STOP BIT(2) 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci#define PDMA_IN_STATQ_PUSH_LEN GENMASK(5, 0) 918c2ecf20Sopenharmony_ci#define PDMA_IN_STATQ_PUSH_ADDR GENMASK(31, 6) 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci#define PDMA_IN_DESCRQ_PUSH_LEN GENMASK(5, 0) 948c2ecf20Sopenharmony_ci#define PDMA_IN_DESCRQ_PUSH_ADDR GENMASK(31, 6) 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci#define PDMA_IN_DESCRQ_STAT_LEVEL GENMASK(3, 0) 978c2ecf20Sopenharmony_ci#define PDMA_IN_DESCRQ_STAT_SIZE GENMASK(7, 4) 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci#define A6_PDMA_INTR_MASK_IN_DATA BIT(2) 1008c2ecf20Sopenharmony_ci#define A6_PDMA_INTR_MASK_IN_EOP BIT(3) 1018c2ecf20Sopenharmony_ci#define A6_PDMA_INTR_MASK_IN_EOP_FLUSH BIT(4) 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci#define A7_PDMA_INTR_MASK_IN_DATA BIT(3) 1048c2ecf20Sopenharmony_ci#define A7_PDMA_INTR_MASK_IN_EOP BIT(4) 1058c2ecf20Sopenharmony_ci#define A7_PDMA_INTR_MASK_IN_EOP_FLUSH BIT(5) 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci#define A6_CRY_MD_OPER GENMASK(19, 16) 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci#define A6_CRY_MD_HASH_SEL_CTX GENMASK(21, 20) 1108c2ecf20Sopenharmony_ci#define A6_CRY_MD_HASH_HMAC_FIN BIT(23) 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci#define A6_CRY_MD_CIPHER_LEN GENMASK(21, 20) 1138c2ecf20Sopenharmony_ci#define A6_CRY_MD_CIPHER_DECR BIT(22) 1148c2ecf20Sopenharmony_ci#define A6_CRY_MD_CIPHER_TWEAK BIT(23) 1158c2ecf20Sopenharmony_ci#define A6_CRY_MD_CIPHER_DSEQ BIT(24) 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci#define A7_CRY_MD_OPER GENMASK(11, 8) 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci#define A7_CRY_MD_HASH_SEL_CTX GENMASK(13, 12) 1208c2ecf20Sopenharmony_ci#define A7_CRY_MD_HASH_HMAC_FIN BIT(15) 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci#define A7_CRY_MD_CIPHER_LEN GENMASK(13, 12) 1238c2ecf20Sopenharmony_ci#define A7_CRY_MD_CIPHER_DECR BIT(14) 1248c2ecf20Sopenharmony_ci#define A7_CRY_MD_CIPHER_TWEAK BIT(15) 1258c2ecf20Sopenharmony_ci#define A7_CRY_MD_CIPHER_DSEQ BIT(16) 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci/* DMA metadata constants */ 1288c2ecf20Sopenharmony_ci#define regk_crypto_aes_cbc 0x00000002 1298c2ecf20Sopenharmony_ci#define regk_crypto_aes_ctr 0x00000003 1308c2ecf20Sopenharmony_ci#define regk_crypto_aes_ecb 0x00000001 1318c2ecf20Sopenharmony_ci#define regk_crypto_aes_gcm 0x00000004 1328c2ecf20Sopenharmony_ci#define regk_crypto_aes_xts 0x00000005 1338c2ecf20Sopenharmony_ci#define regk_crypto_cache 0x00000002 1348c2ecf20Sopenharmony_ci#define a6_regk_crypto_dlkey 0x0000000a 1358c2ecf20Sopenharmony_ci#define a7_regk_crypto_dlkey 0x0000000e 1368c2ecf20Sopenharmony_ci#define regk_crypto_ext 0x00000001 1378c2ecf20Sopenharmony_ci#define regk_crypto_hmac_sha1 0x00000007 1388c2ecf20Sopenharmony_ci#define regk_crypto_hmac_sha256 0x00000009 1398c2ecf20Sopenharmony_ci#define regk_crypto_init 0x00000000 1408c2ecf20Sopenharmony_ci#define regk_crypto_key_128 0x00000000 1418c2ecf20Sopenharmony_ci#define regk_crypto_key_192 0x00000001 1428c2ecf20Sopenharmony_ci#define regk_crypto_key_256 0x00000002 1438c2ecf20Sopenharmony_ci#define regk_crypto_null 0x00000000 1448c2ecf20Sopenharmony_ci#define regk_crypto_sha1 0x00000006 1458c2ecf20Sopenharmony_ci#define regk_crypto_sha256 0x00000008 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci/* DMA descriptor structures */ 1488c2ecf20Sopenharmony_cistruct pdma_descr_ctrl { 1498c2ecf20Sopenharmony_ci unsigned char short_descr : 1; 1508c2ecf20Sopenharmony_ci unsigned char pad1 : 1; 1518c2ecf20Sopenharmony_ci unsigned char eop : 1; 1528c2ecf20Sopenharmony_ci unsigned char intr : 1; 1538c2ecf20Sopenharmony_ci unsigned char short_len : 3; 1548c2ecf20Sopenharmony_ci unsigned char pad2 : 1; 1558c2ecf20Sopenharmony_ci} __packed; 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_cistruct pdma_data_descr { 1588c2ecf20Sopenharmony_ci unsigned int len : 24; 1598c2ecf20Sopenharmony_ci unsigned int buf : 32; 1608c2ecf20Sopenharmony_ci} __packed; 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_cistruct pdma_short_descr { 1638c2ecf20Sopenharmony_ci unsigned char data[7]; 1648c2ecf20Sopenharmony_ci} __packed; 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_cistruct pdma_descr { 1678c2ecf20Sopenharmony_ci struct pdma_descr_ctrl ctrl; 1688c2ecf20Sopenharmony_ci union { 1698c2ecf20Sopenharmony_ci struct pdma_data_descr data; 1708c2ecf20Sopenharmony_ci struct pdma_short_descr shrt; 1718c2ecf20Sopenharmony_ci }; 1728c2ecf20Sopenharmony_ci}; 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_cistruct pdma_stat_descr { 1758c2ecf20Sopenharmony_ci unsigned char pad1 : 1; 1768c2ecf20Sopenharmony_ci unsigned char pad2 : 1; 1778c2ecf20Sopenharmony_ci unsigned char eop : 1; 1788c2ecf20Sopenharmony_ci unsigned char pad3 : 5; 1798c2ecf20Sopenharmony_ci unsigned int len : 24; 1808c2ecf20Sopenharmony_ci}; 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci/* Each descriptor array can hold max 64 entries */ 1838c2ecf20Sopenharmony_ci#define PDMA_DESCR_COUNT 64 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci#define MODULE_NAME "Artpec-6 CA" 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci/* Hash modes (including HMAC variants) */ 1888c2ecf20Sopenharmony_ci#define ARTPEC6_CRYPTO_HASH_SHA1 1 1898c2ecf20Sopenharmony_ci#define ARTPEC6_CRYPTO_HASH_SHA256 2 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci/* Crypto modes */ 1928c2ecf20Sopenharmony_ci#define ARTPEC6_CRYPTO_CIPHER_AES_ECB 1 1938c2ecf20Sopenharmony_ci#define ARTPEC6_CRYPTO_CIPHER_AES_CBC 2 1948c2ecf20Sopenharmony_ci#define ARTPEC6_CRYPTO_CIPHER_AES_CTR 3 1958c2ecf20Sopenharmony_ci#define ARTPEC6_CRYPTO_CIPHER_AES_XTS 5 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci/* The PDMA is a DMA-engine tightly coupled with a ciphering engine. 1988c2ecf20Sopenharmony_ci * It operates on a descriptor array with up to 64 descriptor entries. 1998c2ecf20Sopenharmony_ci * The arrays must be 64 byte aligned in memory. 2008c2ecf20Sopenharmony_ci * 2018c2ecf20Sopenharmony_ci * The ciphering unit has no registers and is completely controlled by 2028c2ecf20Sopenharmony_ci * a 4-byte metadata that is inserted at the beginning of each dma packet. 2038c2ecf20Sopenharmony_ci * 2048c2ecf20Sopenharmony_ci * A dma packet is a sequence of descriptors terminated by setting the .eop 2058c2ecf20Sopenharmony_ci * field in the final descriptor of the packet. 2068c2ecf20Sopenharmony_ci * 2078c2ecf20Sopenharmony_ci * Multiple packets are used for providing context data, key data and 2088c2ecf20Sopenharmony_ci * the plain/ciphertext. 2098c2ecf20Sopenharmony_ci * 2108c2ecf20Sopenharmony_ci * PDMA Descriptors (Array) 2118c2ecf20Sopenharmony_ci * +------+------+------+~~+-------+------+---- 2128c2ecf20Sopenharmony_ci * | 0 | 1 | 2 |~~| 11 EOP| 12 | .... 2138c2ecf20Sopenharmony_ci * +--+---+--+---+----+-+~~+-------+----+-+---- 2148c2ecf20Sopenharmony_ci * | | | | | 2158c2ecf20Sopenharmony_ci * | | | | | 2168c2ecf20Sopenharmony_ci * __|__ +-------++-------++-------+ +----+ 2178c2ecf20Sopenharmony_ci * | MD | |Payload||Payload||Payload| | MD | 2188c2ecf20Sopenharmony_ci * +-----+ +-------++-------++-------+ +----+ 2198c2ecf20Sopenharmony_ci */ 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_cistruct artpec6_crypto_bounce_buffer { 2228c2ecf20Sopenharmony_ci struct list_head list; 2238c2ecf20Sopenharmony_ci size_t length; 2248c2ecf20Sopenharmony_ci struct scatterlist *sg; 2258c2ecf20Sopenharmony_ci size_t offset; 2268c2ecf20Sopenharmony_ci /* buf is aligned to ARTPEC_CACHE_LINE_MAX and 2278c2ecf20Sopenharmony_ci * holds up to ARTPEC_CACHE_LINE_MAX bytes data. 2288c2ecf20Sopenharmony_ci */ 2298c2ecf20Sopenharmony_ci void *buf; 2308c2ecf20Sopenharmony_ci}; 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_cistruct artpec6_crypto_dma_map { 2338c2ecf20Sopenharmony_ci dma_addr_t dma_addr; 2348c2ecf20Sopenharmony_ci size_t size; 2358c2ecf20Sopenharmony_ci enum dma_data_direction dir; 2368c2ecf20Sopenharmony_ci}; 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_cistruct artpec6_crypto_dma_descriptors { 2398c2ecf20Sopenharmony_ci struct pdma_descr out[PDMA_DESCR_COUNT] __aligned(64); 2408c2ecf20Sopenharmony_ci struct pdma_descr in[PDMA_DESCR_COUNT] __aligned(64); 2418c2ecf20Sopenharmony_ci u32 stat[PDMA_DESCR_COUNT] __aligned(64); 2428c2ecf20Sopenharmony_ci struct list_head bounce_buffers; 2438c2ecf20Sopenharmony_ci /* Enough maps for all out/in buffers, and all three descr. arrays */ 2448c2ecf20Sopenharmony_ci struct artpec6_crypto_dma_map maps[PDMA_DESCR_COUNT * 2 + 2]; 2458c2ecf20Sopenharmony_ci dma_addr_t out_dma_addr; 2468c2ecf20Sopenharmony_ci dma_addr_t in_dma_addr; 2478c2ecf20Sopenharmony_ci dma_addr_t stat_dma_addr; 2488c2ecf20Sopenharmony_ci size_t out_cnt; 2498c2ecf20Sopenharmony_ci size_t in_cnt; 2508c2ecf20Sopenharmony_ci size_t map_count; 2518c2ecf20Sopenharmony_ci}; 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_cienum artpec6_crypto_variant { 2548c2ecf20Sopenharmony_ci ARTPEC6_CRYPTO, 2558c2ecf20Sopenharmony_ci ARTPEC7_CRYPTO, 2568c2ecf20Sopenharmony_ci}; 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_cistruct artpec6_crypto { 2598c2ecf20Sopenharmony_ci void __iomem *base; 2608c2ecf20Sopenharmony_ci spinlock_t queue_lock; 2618c2ecf20Sopenharmony_ci struct list_head queue; /* waiting for pdma fifo space */ 2628c2ecf20Sopenharmony_ci struct list_head pending; /* submitted to pdma fifo */ 2638c2ecf20Sopenharmony_ci struct tasklet_struct task; 2648c2ecf20Sopenharmony_ci struct kmem_cache *dma_cache; 2658c2ecf20Sopenharmony_ci int pending_count; 2668c2ecf20Sopenharmony_ci struct timer_list timer; 2678c2ecf20Sopenharmony_ci enum artpec6_crypto_variant variant; 2688c2ecf20Sopenharmony_ci void *pad_buffer; /* cache-aligned block padding buffer */ 2698c2ecf20Sopenharmony_ci void *zero_buffer; 2708c2ecf20Sopenharmony_ci}; 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_cienum artpec6_crypto_hash_flags { 2738c2ecf20Sopenharmony_ci HASH_FLAG_INIT_CTX = 2, 2748c2ecf20Sopenharmony_ci HASH_FLAG_UPDATE = 4, 2758c2ecf20Sopenharmony_ci HASH_FLAG_FINALIZE = 8, 2768c2ecf20Sopenharmony_ci HASH_FLAG_HMAC = 16, 2778c2ecf20Sopenharmony_ci HASH_FLAG_UPDATE_KEY = 32, 2788c2ecf20Sopenharmony_ci}; 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_cistruct artpec6_crypto_req_common { 2818c2ecf20Sopenharmony_ci struct list_head list; 2828c2ecf20Sopenharmony_ci struct list_head complete_in_progress; 2838c2ecf20Sopenharmony_ci struct artpec6_crypto_dma_descriptors *dma; 2848c2ecf20Sopenharmony_ci struct crypto_async_request *req; 2858c2ecf20Sopenharmony_ci void (*complete)(struct crypto_async_request *req); 2868c2ecf20Sopenharmony_ci gfp_t gfp_flags; 2878c2ecf20Sopenharmony_ci}; 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_cistruct artpec6_hash_request_context { 2908c2ecf20Sopenharmony_ci char partial_buffer[SHA256_BLOCK_SIZE]; 2918c2ecf20Sopenharmony_ci char partial_buffer_out[SHA256_BLOCK_SIZE]; 2928c2ecf20Sopenharmony_ci char key_buffer[SHA256_BLOCK_SIZE]; 2938c2ecf20Sopenharmony_ci char pad_buffer[SHA256_BLOCK_SIZE + 32]; 2948c2ecf20Sopenharmony_ci unsigned char digeststate[SHA256_DIGEST_SIZE]; 2958c2ecf20Sopenharmony_ci size_t partial_bytes; 2968c2ecf20Sopenharmony_ci u64 digcnt; 2978c2ecf20Sopenharmony_ci u32 key_md; 2988c2ecf20Sopenharmony_ci u32 hash_md; 2998c2ecf20Sopenharmony_ci enum artpec6_crypto_hash_flags hash_flags; 3008c2ecf20Sopenharmony_ci struct artpec6_crypto_req_common common; 3018c2ecf20Sopenharmony_ci}; 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_cistruct artpec6_hash_export_state { 3048c2ecf20Sopenharmony_ci char partial_buffer[SHA256_BLOCK_SIZE]; 3058c2ecf20Sopenharmony_ci unsigned char digeststate[SHA256_DIGEST_SIZE]; 3068c2ecf20Sopenharmony_ci size_t partial_bytes; 3078c2ecf20Sopenharmony_ci u64 digcnt; 3088c2ecf20Sopenharmony_ci int oper; 3098c2ecf20Sopenharmony_ci unsigned int hash_flags; 3108c2ecf20Sopenharmony_ci}; 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_cistruct artpec6_hashalg_context { 3138c2ecf20Sopenharmony_ci char hmac_key[SHA256_BLOCK_SIZE]; 3148c2ecf20Sopenharmony_ci size_t hmac_key_length; 3158c2ecf20Sopenharmony_ci struct crypto_shash *child_hash; 3168c2ecf20Sopenharmony_ci}; 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_cistruct artpec6_crypto_request_context { 3198c2ecf20Sopenharmony_ci u32 cipher_md; 3208c2ecf20Sopenharmony_ci bool decrypt; 3218c2ecf20Sopenharmony_ci struct artpec6_crypto_req_common common; 3228c2ecf20Sopenharmony_ci}; 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_cistruct artpec6_cryptotfm_context { 3258c2ecf20Sopenharmony_ci unsigned char aes_key[2*AES_MAX_KEY_SIZE]; 3268c2ecf20Sopenharmony_ci size_t key_length; 3278c2ecf20Sopenharmony_ci u32 key_md; 3288c2ecf20Sopenharmony_ci int crypto_type; 3298c2ecf20Sopenharmony_ci struct crypto_sync_skcipher *fallback; 3308c2ecf20Sopenharmony_ci}; 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_cistruct artpec6_crypto_aead_hw_ctx { 3338c2ecf20Sopenharmony_ci __be64 aad_length_bits; 3348c2ecf20Sopenharmony_ci __be64 text_length_bits; 3358c2ecf20Sopenharmony_ci __u8 J0[AES_BLOCK_SIZE]; 3368c2ecf20Sopenharmony_ci}; 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_cistruct artpec6_crypto_aead_req_ctx { 3398c2ecf20Sopenharmony_ci struct artpec6_crypto_aead_hw_ctx hw_ctx; 3408c2ecf20Sopenharmony_ci u32 cipher_md; 3418c2ecf20Sopenharmony_ci bool decrypt; 3428c2ecf20Sopenharmony_ci struct artpec6_crypto_req_common common; 3438c2ecf20Sopenharmony_ci __u8 decryption_tag[AES_BLOCK_SIZE] ____cacheline_aligned; 3448c2ecf20Sopenharmony_ci}; 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci/* The crypto framework makes it hard to avoid this global. */ 3478c2ecf20Sopenharmony_cistatic struct device *artpec6_crypto_dev; 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci#ifdef CONFIG_FAULT_INJECTION 3508c2ecf20Sopenharmony_cistatic DECLARE_FAULT_ATTR(artpec6_crypto_fail_status_read); 3518c2ecf20Sopenharmony_cistatic DECLARE_FAULT_ATTR(artpec6_crypto_fail_dma_array_full); 3528c2ecf20Sopenharmony_ci#endif 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_cienum { 3558c2ecf20Sopenharmony_ci ARTPEC6_CRYPTO_PREPARE_HASH_NO_START, 3568c2ecf20Sopenharmony_ci ARTPEC6_CRYPTO_PREPARE_HASH_START, 3578c2ecf20Sopenharmony_ci}; 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_cistatic int artpec6_crypto_prepare_aead(struct aead_request *areq); 3608c2ecf20Sopenharmony_cistatic int artpec6_crypto_prepare_crypto(struct skcipher_request *areq); 3618c2ecf20Sopenharmony_cistatic int artpec6_crypto_prepare_hash(struct ahash_request *areq); 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_cistatic void 3648c2ecf20Sopenharmony_ciartpec6_crypto_complete_crypto(struct crypto_async_request *req); 3658c2ecf20Sopenharmony_cistatic void 3668c2ecf20Sopenharmony_ciartpec6_crypto_complete_cbc_encrypt(struct crypto_async_request *req); 3678c2ecf20Sopenharmony_cistatic void 3688c2ecf20Sopenharmony_ciartpec6_crypto_complete_cbc_decrypt(struct crypto_async_request *req); 3698c2ecf20Sopenharmony_cistatic void 3708c2ecf20Sopenharmony_ciartpec6_crypto_complete_aead(struct crypto_async_request *req); 3718c2ecf20Sopenharmony_cistatic void 3728c2ecf20Sopenharmony_ciartpec6_crypto_complete_hash(struct crypto_async_request *req); 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_cistatic int 3758c2ecf20Sopenharmony_ciartpec6_crypto_common_destroy(struct artpec6_crypto_req_common *common); 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_cistatic void 3788c2ecf20Sopenharmony_ciartpec6_crypto_start_dma(struct artpec6_crypto_req_common *common); 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_cistruct artpec6_crypto_walk { 3818c2ecf20Sopenharmony_ci struct scatterlist *sg; 3828c2ecf20Sopenharmony_ci size_t offset; 3838c2ecf20Sopenharmony_ci}; 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_cistatic void artpec6_crypto_walk_init(struct artpec6_crypto_walk *awalk, 3868c2ecf20Sopenharmony_ci struct scatterlist *sg) 3878c2ecf20Sopenharmony_ci{ 3888c2ecf20Sopenharmony_ci awalk->sg = sg; 3898c2ecf20Sopenharmony_ci awalk->offset = 0; 3908c2ecf20Sopenharmony_ci} 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_cistatic size_t artpec6_crypto_walk_advance(struct artpec6_crypto_walk *awalk, 3938c2ecf20Sopenharmony_ci size_t nbytes) 3948c2ecf20Sopenharmony_ci{ 3958c2ecf20Sopenharmony_ci while (nbytes && awalk->sg) { 3968c2ecf20Sopenharmony_ci size_t piece; 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci WARN_ON(awalk->offset > awalk->sg->length); 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci piece = min(nbytes, (size_t)awalk->sg->length - awalk->offset); 4018c2ecf20Sopenharmony_ci nbytes -= piece; 4028c2ecf20Sopenharmony_ci awalk->offset += piece; 4038c2ecf20Sopenharmony_ci if (awalk->offset == awalk->sg->length) { 4048c2ecf20Sopenharmony_ci awalk->sg = sg_next(awalk->sg); 4058c2ecf20Sopenharmony_ci awalk->offset = 0; 4068c2ecf20Sopenharmony_ci } 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci } 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ci return nbytes; 4118c2ecf20Sopenharmony_ci} 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_cistatic size_t 4148c2ecf20Sopenharmony_ciartpec6_crypto_walk_chunklen(const struct artpec6_crypto_walk *awalk) 4158c2ecf20Sopenharmony_ci{ 4168c2ecf20Sopenharmony_ci WARN_ON(awalk->sg->length == awalk->offset); 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci return awalk->sg->length - awalk->offset; 4198c2ecf20Sopenharmony_ci} 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_cistatic dma_addr_t 4228c2ecf20Sopenharmony_ciartpec6_crypto_walk_chunk_phys(const struct artpec6_crypto_walk *awalk) 4238c2ecf20Sopenharmony_ci{ 4248c2ecf20Sopenharmony_ci return sg_phys(awalk->sg) + awalk->offset; 4258c2ecf20Sopenharmony_ci} 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_cistatic void 4288c2ecf20Sopenharmony_ciartpec6_crypto_copy_bounce_buffers(struct artpec6_crypto_req_common *common) 4298c2ecf20Sopenharmony_ci{ 4308c2ecf20Sopenharmony_ci struct artpec6_crypto_dma_descriptors *dma = common->dma; 4318c2ecf20Sopenharmony_ci struct artpec6_crypto_bounce_buffer *b; 4328c2ecf20Sopenharmony_ci struct artpec6_crypto_bounce_buffer *next; 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci list_for_each_entry_safe(b, next, &dma->bounce_buffers, list) { 4358c2ecf20Sopenharmony_ci pr_debug("bounce entry %p: %zu bytes @ %zu from %p\n", 4368c2ecf20Sopenharmony_ci b, b->length, b->offset, b->buf); 4378c2ecf20Sopenharmony_ci sg_pcopy_from_buffer(b->sg, 4388c2ecf20Sopenharmony_ci 1, 4398c2ecf20Sopenharmony_ci b->buf, 4408c2ecf20Sopenharmony_ci b->length, 4418c2ecf20Sopenharmony_ci b->offset); 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci list_del(&b->list); 4448c2ecf20Sopenharmony_ci kfree(b); 4458c2ecf20Sopenharmony_ci } 4468c2ecf20Sopenharmony_ci} 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_cistatic inline bool artpec6_crypto_busy(void) 4498c2ecf20Sopenharmony_ci{ 4508c2ecf20Sopenharmony_ci struct artpec6_crypto *ac = dev_get_drvdata(artpec6_crypto_dev); 4518c2ecf20Sopenharmony_ci int fifo_count = ac->pending_count; 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci return fifo_count > 6; 4548c2ecf20Sopenharmony_ci} 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_cistatic int artpec6_crypto_submit(struct artpec6_crypto_req_common *req) 4578c2ecf20Sopenharmony_ci{ 4588c2ecf20Sopenharmony_ci struct artpec6_crypto *ac = dev_get_drvdata(artpec6_crypto_dev); 4598c2ecf20Sopenharmony_ci int ret = -EBUSY; 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci spin_lock_bh(&ac->queue_lock); 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci if (!artpec6_crypto_busy()) { 4648c2ecf20Sopenharmony_ci list_add_tail(&req->list, &ac->pending); 4658c2ecf20Sopenharmony_ci artpec6_crypto_start_dma(req); 4668c2ecf20Sopenharmony_ci ret = -EINPROGRESS; 4678c2ecf20Sopenharmony_ci } else if (req->req->flags & CRYPTO_TFM_REQ_MAY_BACKLOG) { 4688c2ecf20Sopenharmony_ci list_add_tail(&req->list, &ac->queue); 4698c2ecf20Sopenharmony_ci } else { 4708c2ecf20Sopenharmony_ci artpec6_crypto_common_destroy(req); 4718c2ecf20Sopenharmony_ci } 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci spin_unlock_bh(&ac->queue_lock); 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci return ret; 4768c2ecf20Sopenharmony_ci} 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_cistatic void artpec6_crypto_start_dma(struct artpec6_crypto_req_common *common) 4798c2ecf20Sopenharmony_ci{ 4808c2ecf20Sopenharmony_ci struct artpec6_crypto *ac = dev_get_drvdata(artpec6_crypto_dev); 4818c2ecf20Sopenharmony_ci enum artpec6_crypto_variant variant = ac->variant; 4828c2ecf20Sopenharmony_ci void __iomem *base = ac->base; 4838c2ecf20Sopenharmony_ci struct artpec6_crypto_dma_descriptors *dma = common->dma; 4848c2ecf20Sopenharmony_ci u32 ind, statd, outd; 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci /* Make descriptor content visible to the DMA before starting it. */ 4878c2ecf20Sopenharmony_ci wmb(); 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ci ind = FIELD_PREP(PDMA_IN_DESCRQ_PUSH_LEN, dma->in_cnt - 1) | 4908c2ecf20Sopenharmony_ci FIELD_PREP(PDMA_IN_DESCRQ_PUSH_ADDR, dma->in_dma_addr >> 6); 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci statd = FIELD_PREP(PDMA_IN_STATQ_PUSH_LEN, dma->in_cnt - 1) | 4938c2ecf20Sopenharmony_ci FIELD_PREP(PDMA_IN_STATQ_PUSH_ADDR, dma->stat_dma_addr >> 6); 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_ci outd = FIELD_PREP(PDMA_OUT_DESCRQ_PUSH_LEN, dma->out_cnt - 1) | 4968c2ecf20Sopenharmony_ci FIELD_PREP(PDMA_OUT_DESCRQ_PUSH_ADDR, dma->out_dma_addr >> 6); 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_ci if (variant == ARTPEC6_CRYPTO) { 4998c2ecf20Sopenharmony_ci writel_relaxed(ind, base + A6_PDMA_IN_DESCRQ_PUSH); 5008c2ecf20Sopenharmony_ci writel_relaxed(statd, base + A6_PDMA_IN_STATQ_PUSH); 5018c2ecf20Sopenharmony_ci writel_relaxed(PDMA_IN_CMD_START, base + A6_PDMA_IN_CMD); 5028c2ecf20Sopenharmony_ci } else { 5038c2ecf20Sopenharmony_ci writel_relaxed(ind, base + A7_PDMA_IN_DESCRQ_PUSH); 5048c2ecf20Sopenharmony_ci writel_relaxed(statd, base + A7_PDMA_IN_STATQ_PUSH); 5058c2ecf20Sopenharmony_ci writel_relaxed(PDMA_IN_CMD_START, base + A7_PDMA_IN_CMD); 5068c2ecf20Sopenharmony_ci } 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci writel_relaxed(outd, base + PDMA_OUT_DESCRQ_PUSH); 5098c2ecf20Sopenharmony_ci writel_relaxed(PDMA_OUT_CMD_START, base + PDMA_OUT_CMD); 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_ci ac->pending_count++; 5128c2ecf20Sopenharmony_ci} 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_cistatic void 5158c2ecf20Sopenharmony_ciartpec6_crypto_init_dma_operation(struct artpec6_crypto_req_common *common) 5168c2ecf20Sopenharmony_ci{ 5178c2ecf20Sopenharmony_ci struct artpec6_crypto_dma_descriptors *dma = common->dma; 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_ci dma->out_cnt = 0; 5208c2ecf20Sopenharmony_ci dma->in_cnt = 0; 5218c2ecf20Sopenharmony_ci dma->map_count = 0; 5228c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&dma->bounce_buffers); 5238c2ecf20Sopenharmony_ci} 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_cistatic bool fault_inject_dma_descr(void) 5268c2ecf20Sopenharmony_ci{ 5278c2ecf20Sopenharmony_ci#ifdef CONFIG_FAULT_INJECTION 5288c2ecf20Sopenharmony_ci return should_fail(&artpec6_crypto_fail_dma_array_full, 1); 5298c2ecf20Sopenharmony_ci#else 5308c2ecf20Sopenharmony_ci return false; 5318c2ecf20Sopenharmony_ci#endif 5328c2ecf20Sopenharmony_ci} 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ci/** artpec6_crypto_setup_out_descr_phys - Setup an out channel with a 5358c2ecf20Sopenharmony_ci * physical address 5368c2ecf20Sopenharmony_ci * 5378c2ecf20Sopenharmony_ci * @addr: The physical address of the data buffer 5388c2ecf20Sopenharmony_ci * @len: The length of the data buffer 5398c2ecf20Sopenharmony_ci * @eop: True if this is the last buffer in the packet 5408c2ecf20Sopenharmony_ci * 5418c2ecf20Sopenharmony_ci * @return 0 on success or -ENOSPC if there are no more descriptors available 5428c2ecf20Sopenharmony_ci */ 5438c2ecf20Sopenharmony_cistatic int 5448c2ecf20Sopenharmony_ciartpec6_crypto_setup_out_descr_phys(struct artpec6_crypto_req_common *common, 5458c2ecf20Sopenharmony_ci dma_addr_t addr, size_t len, bool eop) 5468c2ecf20Sopenharmony_ci{ 5478c2ecf20Sopenharmony_ci struct artpec6_crypto_dma_descriptors *dma = common->dma; 5488c2ecf20Sopenharmony_ci struct pdma_descr *d; 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_ci if (dma->out_cnt >= PDMA_DESCR_COUNT || 5518c2ecf20Sopenharmony_ci fault_inject_dma_descr()) { 5528c2ecf20Sopenharmony_ci pr_err("No free OUT DMA descriptors available!\n"); 5538c2ecf20Sopenharmony_ci return -ENOSPC; 5548c2ecf20Sopenharmony_ci } 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_ci d = &dma->out[dma->out_cnt++]; 5578c2ecf20Sopenharmony_ci memset(d, 0, sizeof(*d)); 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_ci d->ctrl.short_descr = 0; 5608c2ecf20Sopenharmony_ci d->ctrl.eop = eop; 5618c2ecf20Sopenharmony_ci d->data.len = len; 5628c2ecf20Sopenharmony_ci d->data.buf = addr; 5638c2ecf20Sopenharmony_ci return 0; 5648c2ecf20Sopenharmony_ci} 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_ci/** artpec6_crypto_setup_out_descr_short - Setup a short out descriptor 5678c2ecf20Sopenharmony_ci * 5688c2ecf20Sopenharmony_ci * @dst: The virtual address of the data 5698c2ecf20Sopenharmony_ci * @len: The length of the data, must be between 1 to 7 bytes 5708c2ecf20Sopenharmony_ci * @eop: True if this is the last buffer in the packet 5718c2ecf20Sopenharmony_ci * 5728c2ecf20Sopenharmony_ci * @return 0 on success 5738c2ecf20Sopenharmony_ci * -ENOSPC if no more descriptors are available 5748c2ecf20Sopenharmony_ci * -EINVAL if the data length exceeds 7 bytes 5758c2ecf20Sopenharmony_ci */ 5768c2ecf20Sopenharmony_cistatic int 5778c2ecf20Sopenharmony_ciartpec6_crypto_setup_out_descr_short(struct artpec6_crypto_req_common *common, 5788c2ecf20Sopenharmony_ci void *dst, unsigned int len, bool eop) 5798c2ecf20Sopenharmony_ci{ 5808c2ecf20Sopenharmony_ci struct artpec6_crypto_dma_descriptors *dma = common->dma; 5818c2ecf20Sopenharmony_ci struct pdma_descr *d; 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci if (dma->out_cnt >= PDMA_DESCR_COUNT || 5848c2ecf20Sopenharmony_ci fault_inject_dma_descr()) { 5858c2ecf20Sopenharmony_ci pr_err("No free OUT DMA descriptors available!\n"); 5868c2ecf20Sopenharmony_ci return -ENOSPC; 5878c2ecf20Sopenharmony_ci } else if (len > 7 || len < 1) { 5888c2ecf20Sopenharmony_ci return -EINVAL; 5898c2ecf20Sopenharmony_ci } 5908c2ecf20Sopenharmony_ci d = &dma->out[dma->out_cnt++]; 5918c2ecf20Sopenharmony_ci memset(d, 0, sizeof(*d)); 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_ci d->ctrl.short_descr = 1; 5948c2ecf20Sopenharmony_ci d->ctrl.short_len = len; 5958c2ecf20Sopenharmony_ci d->ctrl.eop = eop; 5968c2ecf20Sopenharmony_ci memcpy(d->shrt.data, dst, len); 5978c2ecf20Sopenharmony_ci return 0; 5988c2ecf20Sopenharmony_ci} 5998c2ecf20Sopenharmony_ci 6008c2ecf20Sopenharmony_cistatic int artpec6_crypto_dma_map_page(struct artpec6_crypto_req_common *common, 6018c2ecf20Sopenharmony_ci struct page *page, size_t offset, 6028c2ecf20Sopenharmony_ci size_t size, 6038c2ecf20Sopenharmony_ci enum dma_data_direction dir, 6048c2ecf20Sopenharmony_ci dma_addr_t *dma_addr_out) 6058c2ecf20Sopenharmony_ci{ 6068c2ecf20Sopenharmony_ci struct artpec6_crypto_dma_descriptors *dma = common->dma; 6078c2ecf20Sopenharmony_ci struct device *dev = artpec6_crypto_dev; 6088c2ecf20Sopenharmony_ci struct artpec6_crypto_dma_map *map; 6098c2ecf20Sopenharmony_ci dma_addr_t dma_addr; 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_ci *dma_addr_out = 0; 6128c2ecf20Sopenharmony_ci 6138c2ecf20Sopenharmony_ci if (dma->map_count >= ARRAY_SIZE(dma->maps)) 6148c2ecf20Sopenharmony_ci return -ENOMEM; 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci dma_addr = dma_map_page(dev, page, offset, size, dir); 6178c2ecf20Sopenharmony_ci if (dma_mapping_error(dev, dma_addr)) 6188c2ecf20Sopenharmony_ci return -ENOMEM; 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_ci map = &dma->maps[dma->map_count++]; 6218c2ecf20Sopenharmony_ci map->size = size; 6228c2ecf20Sopenharmony_ci map->dma_addr = dma_addr; 6238c2ecf20Sopenharmony_ci map->dir = dir; 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_ci *dma_addr_out = dma_addr; 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_ci return 0; 6288c2ecf20Sopenharmony_ci} 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_cistatic int 6318c2ecf20Sopenharmony_ciartpec6_crypto_dma_map_single(struct artpec6_crypto_req_common *common, 6328c2ecf20Sopenharmony_ci void *ptr, size_t size, 6338c2ecf20Sopenharmony_ci enum dma_data_direction dir, 6348c2ecf20Sopenharmony_ci dma_addr_t *dma_addr_out) 6358c2ecf20Sopenharmony_ci{ 6368c2ecf20Sopenharmony_ci struct page *page = virt_to_page(ptr); 6378c2ecf20Sopenharmony_ci size_t offset = (uintptr_t)ptr & ~PAGE_MASK; 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_ci return artpec6_crypto_dma_map_page(common, page, offset, size, dir, 6408c2ecf20Sopenharmony_ci dma_addr_out); 6418c2ecf20Sopenharmony_ci} 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_cistatic int 6448c2ecf20Sopenharmony_ciartpec6_crypto_dma_map_descs(struct artpec6_crypto_req_common *common) 6458c2ecf20Sopenharmony_ci{ 6468c2ecf20Sopenharmony_ci struct artpec6_crypto_dma_descriptors *dma = common->dma; 6478c2ecf20Sopenharmony_ci int ret; 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_ci ret = artpec6_crypto_dma_map_single(common, dma->in, 6508c2ecf20Sopenharmony_ci sizeof(dma->in[0]) * dma->in_cnt, 6518c2ecf20Sopenharmony_ci DMA_TO_DEVICE, &dma->in_dma_addr); 6528c2ecf20Sopenharmony_ci if (ret) 6538c2ecf20Sopenharmony_ci return ret; 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_ci ret = artpec6_crypto_dma_map_single(common, dma->out, 6568c2ecf20Sopenharmony_ci sizeof(dma->out[0]) * dma->out_cnt, 6578c2ecf20Sopenharmony_ci DMA_TO_DEVICE, &dma->out_dma_addr); 6588c2ecf20Sopenharmony_ci if (ret) 6598c2ecf20Sopenharmony_ci return ret; 6608c2ecf20Sopenharmony_ci 6618c2ecf20Sopenharmony_ci /* We only read one stat descriptor */ 6628c2ecf20Sopenharmony_ci dma->stat[dma->in_cnt - 1] = 0; 6638c2ecf20Sopenharmony_ci 6648c2ecf20Sopenharmony_ci /* 6658c2ecf20Sopenharmony_ci * DMA_BIDIRECTIONAL since we need our zeroing of the stat descriptor 6668c2ecf20Sopenharmony_ci * to be written. 6678c2ecf20Sopenharmony_ci */ 6688c2ecf20Sopenharmony_ci return artpec6_crypto_dma_map_single(common, 6698c2ecf20Sopenharmony_ci dma->stat, 6708c2ecf20Sopenharmony_ci sizeof(dma->stat[0]) * dma->in_cnt, 6718c2ecf20Sopenharmony_ci DMA_BIDIRECTIONAL, 6728c2ecf20Sopenharmony_ci &dma->stat_dma_addr); 6738c2ecf20Sopenharmony_ci} 6748c2ecf20Sopenharmony_ci 6758c2ecf20Sopenharmony_cistatic void 6768c2ecf20Sopenharmony_ciartpec6_crypto_dma_unmap_all(struct artpec6_crypto_req_common *common) 6778c2ecf20Sopenharmony_ci{ 6788c2ecf20Sopenharmony_ci struct artpec6_crypto_dma_descriptors *dma = common->dma; 6798c2ecf20Sopenharmony_ci struct device *dev = artpec6_crypto_dev; 6808c2ecf20Sopenharmony_ci int i; 6818c2ecf20Sopenharmony_ci 6828c2ecf20Sopenharmony_ci for (i = 0; i < dma->map_count; i++) { 6838c2ecf20Sopenharmony_ci struct artpec6_crypto_dma_map *map = &dma->maps[i]; 6848c2ecf20Sopenharmony_ci 6858c2ecf20Sopenharmony_ci dma_unmap_page(dev, map->dma_addr, map->size, map->dir); 6868c2ecf20Sopenharmony_ci } 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_ci dma->map_count = 0; 6898c2ecf20Sopenharmony_ci} 6908c2ecf20Sopenharmony_ci 6918c2ecf20Sopenharmony_ci/** artpec6_crypto_setup_out_descr - Setup an out descriptor 6928c2ecf20Sopenharmony_ci * 6938c2ecf20Sopenharmony_ci * @dst: The virtual address of the data 6948c2ecf20Sopenharmony_ci * @len: The length of the data 6958c2ecf20Sopenharmony_ci * @eop: True if this is the last buffer in the packet 6968c2ecf20Sopenharmony_ci * @use_short: If this is true and the data length is 7 bytes or less then 6978c2ecf20Sopenharmony_ci * a short descriptor will be used 6988c2ecf20Sopenharmony_ci * 6998c2ecf20Sopenharmony_ci * @return 0 on success 7008c2ecf20Sopenharmony_ci * Any errors from artpec6_crypto_setup_out_descr_short() or 7018c2ecf20Sopenharmony_ci * setup_out_descr_phys() 7028c2ecf20Sopenharmony_ci */ 7038c2ecf20Sopenharmony_cistatic int 7048c2ecf20Sopenharmony_ciartpec6_crypto_setup_out_descr(struct artpec6_crypto_req_common *common, 7058c2ecf20Sopenharmony_ci void *dst, unsigned int len, bool eop, 7068c2ecf20Sopenharmony_ci bool use_short) 7078c2ecf20Sopenharmony_ci{ 7088c2ecf20Sopenharmony_ci if (use_short && len < 7) { 7098c2ecf20Sopenharmony_ci return artpec6_crypto_setup_out_descr_short(common, dst, len, 7108c2ecf20Sopenharmony_ci eop); 7118c2ecf20Sopenharmony_ci } else { 7128c2ecf20Sopenharmony_ci int ret; 7138c2ecf20Sopenharmony_ci dma_addr_t dma_addr; 7148c2ecf20Sopenharmony_ci 7158c2ecf20Sopenharmony_ci ret = artpec6_crypto_dma_map_single(common, dst, len, 7168c2ecf20Sopenharmony_ci DMA_TO_DEVICE, 7178c2ecf20Sopenharmony_ci &dma_addr); 7188c2ecf20Sopenharmony_ci if (ret) 7198c2ecf20Sopenharmony_ci return ret; 7208c2ecf20Sopenharmony_ci 7218c2ecf20Sopenharmony_ci return artpec6_crypto_setup_out_descr_phys(common, dma_addr, 7228c2ecf20Sopenharmony_ci len, eop); 7238c2ecf20Sopenharmony_ci } 7248c2ecf20Sopenharmony_ci} 7258c2ecf20Sopenharmony_ci 7268c2ecf20Sopenharmony_ci/** artpec6_crypto_setup_in_descr_phys - Setup an in channel with a 7278c2ecf20Sopenharmony_ci * physical address 7288c2ecf20Sopenharmony_ci * 7298c2ecf20Sopenharmony_ci * @addr: The physical address of the data buffer 7308c2ecf20Sopenharmony_ci * @len: The length of the data buffer 7318c2ecf20Sopenharmony_ci * @intr: True if an interrupt should be fired after HW processing of this 7328c2ecf20Sopenharmony_ci * descriptor 7338c2ecf20Sopenharmony_ci * 7348c2ecf20Sopenharmony_ci */ 7358c2ecf20Sopenharmony_cistatic int 7368c2ecf20Sopenharmony_ciartpec6_crypto_setup_in_descr_phys(struct artpec6_crypto_req_common *common, 7378c2ecf20Sopenharmony_ci dma_addr_t addr, unsigned int len, bool intr) 7388c2ecf20Sopenharmony_ci{ 7398c2ecf20Sopenharmony_ci struct artpec6_crypto_dma_descriptors *dma = common->dma; 7408c2ecf20Sopenharmony_ci struct pdma_descr *d; 7418c2ecf20Sopenharmony_ci 7428c2ecf20Sopenharmony_ci if (dma->in_cnt >= PDMA_DESCR_COUNT || 7438c2ecf20Sopenharmony_ci fault_inject_dma_descr()) { 7448c2ecf20Sopenharmony_ci pr_err("No free IN DMA descriptors available!\n"); 7458c2ecf20Sopenharmony_ci return -ENOSPC; 7468c2ecf20Sopenharmony_ci } 7478c2ecf20Sopenharmony_ci d = &dma->in[dma->in_cnt++]; 7488c2ecf20Sopenharmony_ci memset(d, 0, sizeof(*d)); 7498c2ecf20Sopenharmony_ci 7508c2ecf20Sopenharmony_ci d->ctrl.intr = intr; 7518c2ecf20Sopenharmony_ci d->data.len = len; 7528c2ecf20Sopenharmony_ci d->data.buf = addr; 7538c2ecf20Sopenharmony_ci return 0; 7548c2ecf20Sopenharmony_ci} 7558c2ecf20Sopenharmony_ci 7568c2ecf20Sopenharmony_ci/** artpec6_crypto_setup_in_descr - Setup an in channel descriptor 7578c2ecf20Sopenharmony_ci * 7588c2ecf20Sopenharmony_ci * @buffer: The virtual address to of the data buffer 7598c2ecf20Sopenharmony_ci * @len: The length of the data buffer 7608c2ecf20Sopenharmony_ci * @last: If this is the last data buffer in the request (i.e. an interrupt 7618c2ecf20Sopenharmony_ci * is needed 7628c2ecf20Sopenharmony_ci * 7638c2ecf20Sopenharmony_ci * Short descriptors are not used for the in channel 7648c2ecf20Sopenharmony_ci */ 7658c2ecf20Sopenharmony_cistatic int 7668c2ecf20Sopenharmony_ciartpec6_crypto_setup_in_descr(struct artpec6_crypto_req_common *common, 7678c2ecf20Sopenharmony_ci void *buffer, unsigned int len, bool last) 7688c2ecf20Sopenharmony_ci{ 7698c2ecf20Sopenharmony_ci dma_addr_t dma_addr; 7708c2ecf20Sopenharmony_ci int ret; 7718c2ecf20Sopenharmony_ci 7728c2ecf20Sopenharmony_ci ret = artpec6_crypto_dma_map_single(common, buffer, len, 7738c2ecf20Sopenharmony_ci DMA_FROM_DEVICE, &dma_addr); 7748c2ecf20Sopenharmony_ci if (ret) 7758c2ecf20Sopenharmony_ci return ret; 7768c2ecf20Sopenharmony_ci 7778c2ecf20Sopenharmony_ci return artpec6_crypto_setup_in_descr_phys(common, dma_addr, len, last); 7788c2ecf20Sopenharmony_ci} 7798c2ecf20Sopenharmony_ci 7808c2ecf20Sopenharmony_cistatic struct artpec6_crypto_bounce_buffer * 7818c2ecf20Sopenharmony_ciartpec6_crypto_alloc_bounce(gfp_t flags) 7828c2ecf20Sopenharmony_ci{ 7838c2ecf20Sopenharmony_ci void *base; 7848c2ecf20Sopenharmony_ci size_t alloc_size = sizeof(struct artpec6_crypto_bounce_buffer) + 7858c2ecf20Sopenharmony_ci 2 * ARTPEC_CACHE_LINE_MAX; 7868c2ecf20Sopenharmony_ci struct artpec6_crypto_bounce_buffer *bbuf = kzalloc(alloc_size, flags); 7878c2ecf20Sopenharmony_ci 7888c2ecf20Sopenharmony_ci if (!bbuf) 7898c2ecf20Sopenharmony_ci return NULL; 7908c2ecf20Sopenharmony_ci 7918c2ecf20Sopenharmony_ci base = bbuf + 1; 7928c2ecf20Sopenharmony_ci bbuf->buf = PTR_ALIGN(base, ARTPEC_CACHE_LINE_MAX); 7938c2ecf20Sopenharmony_ci return bbuf; 7948c2ecf20Sopenharmony_ci} 7958c2ecf20Sopenharmony_ci 7968c2ecf20Sopenharmony_cistatic int setup_bounce_buffer_in(struct artpec6_crypto_req_common *common, 7978c2ecf20Sopenharmony_ci struct artpec6_crypto_walk *walk, size_t size) 7988c2ecf20Sopenharmony_ci{ 7998c2ecf20Sopenharmony_ci struct artpec6_crypto_bounce_buffer *bbuf; 8008c2ecf20Sopenharmony_ci int ret; 8018c2ecf20Sopenharmony_ci 8028c2ecf20Sopenharmony_ci bbuf = artpec6_crypto_alloc_bounce(common->gfp_flags); 8038c2ecf20Sopenharmony_ci if (!bbuf) 8048c2ecf20Sopenharmony_ci return -ENOMEM; 8058c2ecf20Sopenharmony_ci 8068c2ecf20Sopenharmony_ci bbuf->length = size; 8078c2ecf20Sopenharmony_ci bbuf->sg = walk->sg; 8088c2ecf20Sopenharmony_ci bbuf->offset = walk->offset; 8098c2ecf20Sopenharmony_ci 8108c2ecf20Sopenharmony_ci ret = artpec6_crypto_setup_in_descr(common, bbuf->buf, size, false); 8118c2ecf20Sopenharmony_ci if (ret) { 8128c2ecf20Sopenharmony_ci kfree(bbuf); 8138c2ecf20Sopenharmony_ci return ret; 8148c2ecf20Sopenharmony_ci } 8158c2ecf20Sopenharmony_ci 8168c2ecf20Sopenharmony_ci pr_debug("BOUNCE %zu offset %zu\n", size, walk->offset); 8178c2ecf20Sopenharmony_ci list_add_tail(&bbuf->list, &common->dma->bounce_buffers); 8188c2ecf20Sopenharmony_ci return 0; 8198c2ecf20Sopenharmony_ci} 8208c2ecf20Sopenharmony_ci 8218c2ecf20Sopenharmony_cistatic int 8228c2ecf20Sopenharmony_ciartpec6_crypto_setup_sg_descrs_in(struct artpec6_crypto_req_common *common, 8238c2ecf20Sopenharmony_ci struct artpec6_crypto_walk *walk, 8248c2ecf20Sopenharmony_ci size_t count) 8258c2ecf20Sopenharmony_ci{ 8268c2ecf20Sopenharmony_ci size_t chunk; 8278c2ecf20Sopenharmony_ci int ret; 8288c2ecf20Sopenharmony_ci dma_addr_t addr; 8298c2ecf20Sopenharmony_ci 8308c2ecf20Sopenharmony_ci while (walk->sg && count) { 8318c2ecf20Sopenharmony_ci chunk = min(count, artpec6_crypto_walk_chunklen(walk)); 8328c2ecf20Sopenharmony_ci addr = artpec6_crypto_walk_chunk_phys(walk); 8338c2ecf20Sopenharmony_ci 8348c2ecf20Sopenharmony_ci /* When destination buffers are not aligned to the cache line 8358c2ecf20Sopenharmony_ci * size we need bounce buffers. The DMA-API requires that the 8368c2ecf20Sopenharmony_ci * entire line is owned by the DMA buffer and this holds also 8378c2ecf20Sopenharmony_ci * for the case when coherent DMA is used. 8388c2ecf20Sopenharmony_ci */ 8398c2ecf20Sopenharmony_ci if (!IS_ALIGNED(addr, ARTPEC_CACHE_LINE_MAX)) { 8408c2ecf20Sopenharmony_ci chunk = min_t(dma_addr_t, chunk, 8418c2ecf20Sopenharmony_ci ALIGN(addr, ARTPEC_CACHE_LINE_MAX) - 8428c2ecf20Sopenharmony_ci addr); 8438c2ecf20Sopenharmony_ci 8448c2ecf20Sopenharmony_ci pr_debug("CHUNK-b %pad:%zu\n", &addr, chunk); 8458c2ecf20Sopenharmony_ci ret = setup_bounce_buffer_in(common, walk, chunk); 8468c2ecf20Sopenharmony_ci } else if (chunk < ARTPEC_CACHE_LINE_MAX) { 8478c2ecf20Sopenharmony_ci pr_debug("CHUNK-b %pad:%zu\n", &addr, chunk); 8488c2ecf20Sopenharmony_ci ret = setup_bounce_buffer_in(common, walk, chunk); 8498c2ecf20Sopenharmony_ci } else { 8508c2ecf20Sopenharmony_ci dma_addr_t dma_addr; 8518c2ecf20Sopenharmony_ci 8528c2ecf20Sopenharmony_ci chunk = chunk & ~(ARTPEC_CACHE_LINE_MAX-1); 8538c2ecf20Sopenharmony_ci 8548c2ecf20Sopenharmony_ci pr_debug("CHUNK %pad:%zu\n", &addr, chunk); 8558c2ecf20Sopenharmony_ci 8568c2ecf20Sopenharmony_ci ret = artpec6_crypto_dma_map_page(common, 8578c2ecf20Sopenharmony_ci sg_page(walk->sg), 8588c2ecf20Sopenharmony_ci walk->sg->offset + 8598c2ecf20Sopenharmony_ci walk->offset, 8608c2ecf20Sopenharmony_ci chunk, 8618c2ecf20Sopenharmony_ci DMA_FROM_DEVICE, 8628c2ecf20Sopenharmony_ci &dma_addr); 8638c2ecf20Sopenharmony_ci if (ret) 8648c2ecf20Sopenharmony_ci return ret; 8658c2ecf20Sopenharmony_ci 8668c2ecf20Sopenharmony_ci ret = artpec6_crypto_setup_in_descr_phys(common, 8678c2ecf20Sopenharmony_ci dma_addr, 8688c2ecf20Sopenharmony_ci chunk, false); 8698c2ecf20Sopenharmony_ci } 8708c2ecf20Sopenharmony_ci 8718c2ecf20Sopenharmony_ci if (ret) 8728c2ecf20Sopenharmony_ci return ret; 8738c2ecf20Sopenharmony_ci 8748c2ecf20Sopenharmony_ci count = count - chunk; 8758c2ecf20Sopenharmony_ci artpec6_crypto_walk_advance(walk, chunk); 8768c2ecf20Sopenharmony_ci } 8778c2ecf20Sopenharmony_ci 8788c2ecf20Sopenharmony_ci if (count) 8798c2ecf20Sopenharmony_ci pr_err("EOL unexpected %zu bytes left\n", count); 8808c2ecf20Sopenharmony_ci 8818c2ecf20Sopenharmony_ci return count ? -EINVAL : 0; 8828c2ecf20Sopenharmony_ci} 8838c2ecf20Sopenharmony_ci 8848c2ecf20Sopenharmony_cistatic int 8858c2ecf20Sopenharmony_ciartpec6_crypto_setup_sg_descrs_out(struct artpec6_crypto_req_common *common, 8868c2ecf20Sopenharmony_ci struct artpec6_crypto_walk *walk, 8878c2ecf20Sopenharmony_ci size_t count) 8888c2ecf20Sopenharmony_ci{ 8898c2ecf20Sopenharmony_ci size_t chunk; 8908c2ecf20Sopenharmony_ci int ret; 8918c2ecf20Sopenharmony_ci dma_addr_t addr; 8928c2ecf20Sopenharmony_ci 8938c2ecf20Sopenharmony_ci while (walk->sg && count) { 8948c2ecf20Sopenharmony_ci chunk = min(count, artpec6_crypto_walk_chunklen(walk)); 8958c2ecf20Sopenharmony_ci addr = artpec6_crypto_walk_chunk_phys(walk); 8968c2ecf20Sopenharmony_ci 8978c2ecf20Sopenharmony_ci pr_debug("OUT-CHUNK %pad:%zu\n", &addr, chunk); 8988c2ecf20Sopenharmony_ci 8998c2ecf20Sopenharmony_ci if (addr & 3) { 9008c2ecf20Sopenharmony_ci char buf[3]; 9018c2ecf20Sopenharmony_ci 9028c2ecf20Sopenharmony_ci chunk = min_t(size_t, chunk, (4-(addr&3))); 9038c2ecf20Sopenharmony_ci 9048c2ecf20Sopenharmony_ci sg_pcopy_to_buffer(walk->sg, 1, buf, chunk, 9058c2ecf20Sopenharmony_ci walk->offset); 9068c2ecf20Sopenharmony_ci 9078c2ecf20Sopenharmony_ci ret = artpec6_crypto_setup_out_descr_short(common, buf, 9088c2ecf20Sopenharmony_ci chunk, 9098c2ecf20Sopenharmony_ci false); 9108c2ecf20Sopenharmony_ci } else { 9118c2ecf20Sopenharmony_ci dma_addr_t dma_addr; 9128c2ecf20Sopenharmony_ci 9138c2ecf20Sopenharmony_ci ret = artpec6_crypto_dma_map_page(common, 9148c2ecf20Sopenharmony_ci sg_page(walk->sg), 9158c2ecf20Sopenharmony_ci walk->sg->offset + 9168c2ecf20Sopenharmony_ci walk->offset, 9178c2ecf20Sopenharmony_ci chunk, 9188c2ecf20Sopenharmony_ci DMA_TO_DEVICE, 9198c2ecf20Sopenharmony_ci &dma_addr); 9208c2ecf20Sopenharmony_ci if (ret) 9218c2ecf20Sopenharmony_ci return ret; 9228c2ecf20Sopenharmony_ci 9238c2ecf20Sopenharmony_ci ret = artpec6_crypto_setup_out_descr_phys(common, 9248c2ecf20Sopenharmony_ci dma_addr, 9258c2ecf20Sopenharmony_ci chunk, false); 9268c2ecf20Sopenharmony_ci } 9278c2ecf20Sopenharmony_ci 9288c2ecf20Sopenharmony_ci if (ret) 9298c2ecf20Sopenharmony_ci return ret; 9308c2ecf20Sopenharmony_ci 9318c2ecf20Sopenharmony_ci count = count - chunk; 9328c2ecf20Sopenharmony_ci artpec6_crypto_walk_advance(walk, chunk); 9338c2ecf20Sopenharmony_ci } 9348c2ecf20Sopenharmony_ci 9358c2ecf20Sopenharmony_ci if (count) 9368c2ecf20Sopenharmony_ci pr_err("EOL unexpected %zu bytes left\n", count); 9378c2ecf20Sopenharmony_ci 9388c2ecf20Sopenharmony_ci return count ? -EINVAL : 0; 9398c2ecf20Sopenharmony_ci} 9408c2ecf20Sopenharmony_ci 9418c2ecf20Sopenharmony_ci 9428c2ecf20Sopenharmony_ci/** artpec6_crypto_terminate_out_descrs - Set the EOP on the last out descriptor 9438c2ecf20Sopenharmony_ci * 9448c2ecf20Sopenharmony_ci * If the out descriptor list is non-empty, then the eop flag on the 9458c2ecf20Sopenharmony_ci * last used out descriptor will be set. 9468c2ecf20Sopenharmony_ci * 9478c2ecf20Sopenharmony_ci * @return 0 on success 9488c2ecf20Sopenharmony_ci * -EINVAL if the out descriptor is empty or has overflown 9498c2ecf20Sopenharmony_ci */ 9508c2ecf20Sopenharmony_cistatic int 9518c2ecf20Sopenharmony_ciartpec6_crypto_terminate_out_descrs(struct artpec6_crypto_req_common *common) 9528c2ecf20Sopenharmony_ci{ 9538c2ecf20Sopenharmony_ci struct artpec6_crypto_dma_descriptors *dma = common->dma; 9548c2ecf20Sopenharmony_ci struct pdma_descr *d; 9558c2ecf20Sopenharmony_ci 9568c2ecf20Sopenharmony_ci if (!dma->out_cnt || dma->out_cnt > PDMA_DESCR_COUNT) { 9578c2ecf20Sopenharmony_ci pr_err("%s: OUT descriptor list is %s\n", 9588c2ecf20Sopenharmony_ci MODULE_NAME, dma->out_cnt ? "empty" : "full"); 9598c2ecf20Sopenharmony_ci return -EINVAL; 9608c2ecf20Sopenharmony_ci 9618c2ecf20Sopenharmony_ci } 9628c2ecf20Sopenharmony_ci 9638c2ecf20Sopenharmony_ci d = &dma->out[dma->out_cnt-1]; 9648c2ecf20Sopenharmony_ci d->ctrl.eop = 1; 9658c2ecf20Sopenharmony_ci 9668c2ecf20Sopenharmony_ci return 0; 9678c2ecf20Sopenharmony_ci} 9688c2ecf20Sopenharmony_ci 9698c2ecf20Sopenharmony_ci/** artpec6_crypto_terminate_in_descrs - Set the interrupt flag on the last 9708c2ecf20Sopenharmony_ci * in descriptor 9718c2ecf20Sopenharmony_ci * 9728c2ecf20Sopenharmony_ci * See artpec6_crypto_terminate_out_descrs() for return values 9738c2ecf20Sopenharmony_ci */ 9748c2ecf20Sopenharmony_cistatic int 9758c2ecf20Sopenharmony_ciartpec6_crypto_terminate_in_descrs(struct artpec6_crypto_req_common *common) 9768c2ecf20Sopenharmony_ci{ 9778c2ecf20Sopenharmony_ci struct artpec6_crypto_dma_descriptors *dma = common->dma; 9788c2ecf20Sopenharmony_ci struct pdma_descr *d; 9798c2ecf20Sopenharmony_ci 9808c2ecf20Sopenharmony_ci if (!dma->in_cnt || dma->in_cnt > PDMA_DESCR_COUNT) { 9818c2ecf20Sopenharmony_ci pr_err("%s: IN descriptor list is %s\n", 9828c2ecf20Sopenharmony_ci MODULE_NAME, dma->in_cnt ? "empty" : "full"); 9838c2ecf20Sopenharmony_ci return -EINVAL; 9848c2ecf20Sopenharmony_ci } 9858c2ecf20Sopenharmony_ci 9868c2ecf20Sopenharmony_ci d = &dma->in[dma->in_cnt-1]; 9878c2ecf20Sopenharmony_ci d->ctrl.intr = 1; 9888c2ecf20Sopenharmony_ci return 0; 9898c2ecf20Sopenharmony_ci} 9908c2ecf20Sopenharmony_ci 9918c2ecf20Sopenharmony_ci/** create_hash_pad - Create a Secure Hash conformant pad 9928c2ecf20Sopenharmony_ci * 9938c2ecf20Sopenharmony_ci * @dst: The destination buffer to write the pad. Must be at least 64 bytes 9948c2ecf20Sopenharmony_ci * @dgstlen: The total length of the hash digest in bytes 9958c2ecf20Sopenharmony_ci * @bitcount: The total length of the digest in bits 9968c2ecf20Sopenharmony_ci * 9978c2ecf20Sopenharmony_ci * @return The total number of padding bytes written to @dst 9988c2ecf20Sopenharmony_ci */ 9998c2ecf20Sopenharmony_cistatic size_t 10008c2ecf20Sopenharmony_cicreate_hash_pad(int oper, unsigned char *dst, u64 dgstlen, u64 bitcount) 10018c2ecf20Sopenharmony_ci{ 10028c2ecf20Sopenharmony_ci unsigned int mod, target, diff, pad_bytes, size_bytes; 10038c2ecf20Sopenharmony_ci __be64 bits = __cpu_to_be64(bitcount); 10048c2ecf20Sopenharmony_ci 10058c2ecf20Sopenharmony_ci switch (oper) { 10068c2ecf20Sopenharmony_ci case regk_crypto_sha1: 10078c2ecf20Sopenharmony_ci case regk_crypto_sha256: 10088c2ecf20Sopenharmony_ci case regk_crypto_hmac_sha1: 10098c2ecf20Sopenharmony_ci case regk_crypto_hmac_sha256: 10108c2ecf20Sopenharmony_ci target = 448 / 8; 10118c2ecf20Sopenharmony_ci mod = 512 / 8; 10128c2ecf20Sopenharmony_ci size_bytes = 8; 10138c2ecf20Sopenharmony_ci break; 10148c2ecf20Sopenharmony_ci default: 10158c2ecf20Sopenharmony_ci target = 896 / 8; 10168c2ecf20Sopenharmony_ci mod = 1024 / 8; 10178c2ecf20Sopenharmony_ci size_bytes = 16; 10188c2ecf20Sopenharmony_ci break; 10198c2ecf20Sopenharmony_ci } 10208c2ecf20Sopenharmony_ci 10218c2ecf20Sopenharmony_ci target -= 1; 10228c2ecf20Sopenharmony_ci diff = dgstlen & (mod - 1); 10238c2ecf20Sopenharmony_ci pad_bytes = diff > target ? target + mod - diff : target - diff; 10248c2ecf20Sopenharmony_ci 10258c2ecf20Sopenharmony_ci memset(dst + 1, 0, pad_bytes); 10268c2ecf20Sopenharmony_ci dst[0] = 0x80; 10278c2ecf20Sopenharmony_ci 10288c2ecf20Sopenharmony_ci if (size_bytes == 16) { 10298c2ecf20Sopenharmony_ci memset(dst + 1 + pad_bytes, 0, 8); 10308c2ecf20Sopenharmony_ci memcpy(dst + 1 + pad_bytes + 8, &bits, 8); 10318c2ecf20Sopenharmony_ci } else { 10328c2ecf20Sopenharmony_ci memcpy(dst + 1 + pad_bytes, &bits, 8); 10338c2ecf20Sopenharmony_ci } 10348c2ecf20Sopenharmony_ci 10358c2ecf20Sopenharmony_ci return pad_bytes + size_bytes + 1; 10368c2ecf20Sopenharmony_ci} 10378c2ecf20Sopenharmony_ci 10388c2ecf20Sopenharmony_cistatic int artpec6_crypto_common_init(struct artpec6_crypto_req_common *common, 10398c2ecf20Sopenharmony_ci struct crypto_async_request *parent, 10408c2ecf20Sopenharmony_ci void (*complete)(struct crypto_async_request *req), 10418c2ecf20Sopenharmony_ci struct scatterlist *dstsg, unsigned int nbytes) 10428c2ecf20Sopenharmony_ci{ 10438c2ecf20Sopenharmony_ci gfp_t flags; 10448c2ecf20Sopenharmony_ci struct artpec6_crypto *ac = dev_get_drvdata(artpec6_crypto_dev); 10458c2ecf20Sopenharmony_ci 10468c2ecf20Sopenharmony_ci flags = (parent->flags & CRYPTO_TFM_REQ_MAY_SLEEP) ? 10478c2ecf20Sopenharmony_ci GFP_KERNEL : GFP_ATOMIC; 10488c2ecf20Sopenharmony_ci 10498c2ecf20Sopenharmony_ci common->gfp_flags = flags; 10508c2ecf20Sopenharmony_ci common->dma = kmem_cache_alloc(ac->dma_cache, flags); 10518c2ecf20Sopenharmony_ci if (!common->dma) 10528c2ecf20Sopenharmony_ci return -ENOMEM; 10538c2ecf20Sopenharmony_ci 10548c2ecf20Sopenharmony_ci common->req = parent; 10558c2ecf20Sopenharmony_ci common->complete = complete; 10568c2ecf20Sopenharmony_ci return 0; 10578c2ecf20Sopenharmony_ci} 10588c2ecf20Sopenharmony_ci 10598c2ecf20Sopenharmony_cistatic void 10608c2ecf20Sopenharmony_ciartpec6_crypto_bounce_destroy(struct artpec6_crypto_dma_descriptors *dma) 10618c2ecf20Sopenharmony_ci{ 10628c2ecf20Sopenharmony_ci struct artpec6_crypto_bounce_buffer *b; 10638c2ecf20Sopenharmony_ci struct artpec6_crypto_bounce_buffer *next; 10648c2ecf20Sopenharmony_ci 10658c2ecf20Sopenharmony_ci list_for_each_entry_safe(b, next, &dma->bounce_buffers, list) { 10668c2ecf20Sopenharmony_ci kfree(b); 10678c2ecf20Sopenharmony_ci } 10688c2ecf20Sopenharmony_ci} 10698c2ecf20Sopenharmony_ci 10708c2ecf20Sopenharmony_cistatic int 10718c2ecf20Sopenharmony_ciartpec6_crypto_common_destroy(struct artpec6_crypto_req_common *common) 10728c2ecf20Sopenharmony_ci{ 10738c2ecf20Sopenharmony_ci struct artpec6_crypto *ac = dev_get_drvdata(artpec6_crypto_dev); 10748c2ecf20Sopenharmony_ci 10758c2ecf20Sopenharmony_ci artpec6_crypto_dma_unmap_all(common); 10768c2ecf20Sopenharmony_ci artpec6_crypto_bounce_destroy(common->dma); 10778c2ecf20Sopenharmony_ci kmem_cache_free(ac->dma_cache, common->dma); 10788c2ecf20Sopenharmony_ci common->dma = NULL; 10798c2ecf20Sopenharmony_ci return 0; 10808c2ecf20Sopenharmony_ci} 10818c2ecf20Sopenharmony_ci 10828c2ecf20Sopenharmony_ci/* 10838c2ecf20Sopenharmony_ci * Ciphering functions. 10848c2ecf20Sopenharmony_ci */ 10858c2ecf20Sopenharmony_cistatic int artpec6_crypto_encrypt(struct skcipher_request *req) 10868c2ecf20Sopenharmony_ci{ 10878c2ecf20Sopenharmony_ci struct crypto_skcipher *cipher = crypto_skcipher_reqtfm(req); 10888c2ecf20Sopenharmony_ci struct artpec6_cryptotfm_context *ctx = crypto_skcipher_ctx(cipher); 10898c2ecf20Sopenharmony_ci struct artpec6_crypto_request_context *req_ctx = NULL; 10908c2ecf20Sopenharmony_ci void (*complete)(struct crypto_async_request *req); 10918c2ecf20Sopenharmony_ci int ret; 10928c2ecf20Sopenharmony_ci 10938c2ecf20Sopenharmony_ci req_ctx = skcipher_request_ctx(req); 10948c2ecf20Sopenharmony_ci 10958c2ecf20Sopenharmony_ci switch (ctx->crypto_type) { 10968c2ecf20Sopenharmony_ci case ARTPEC6_CRYPTO_CIPHER_AES_CBC: 10978c2ecf20Sopenharmony_ci case ARTPEC6_CRYPTO_CIPHER_AES_ECB: 10988c2ecf20Sopenharmony_ci case ARTPEC6_CRYPTO_CIPHER_AES_XTS: 10998c2ecf20Sopenharmony_ci req_ctx->decrypt = 0; 11008c2ecf20Sopenharmony_ci break; 11018c2ecf20Sopenharmony_ci default: 11028c2ecf20Sopenharmony_ci break; 11038c2ecf20Sopenharmony_ci } 11048c2ecf20Sopenharmony_ci 11058c2ecf20Sopenharmony_ci switch (ctx->crypto_type) { 11068c2ecf20Sopenharmony_ci case ARTPEC6_CRYPTO_CIPHER_AES_CBC: 11078c2ecf20Sopenharmony_ci complete = artpec6_crypto_complete_cbc_encrypt; 11088c2ecf20Sopenharmony_ci break; 11098c2ecf20Sopenharmony_ci default: 11108c2ecf20Sopenharmony_ci complete = artpec6_crypto_complete_crypto; 11118c2ecf20Sopenharmony_ci break; 11128c2ecf20Sopenharmony_ci } 11138c2ecf20Sopenharmony_ci 11148c2ecf20Sopenharmony_ci ret = artpec6_crypto_common_init(&req_ctx->common, 11158c2ecf20Sopenharmony_ci &req->base, 11168c2ecf20Sopenharmony_ci complete, 11178c2ecf20Sopenharmony_ci req->dst, req->cryptlen); 11188c2ecf20Sopenharmony_ci if (ret) 11198c2ecf20Sopenharmony_ci return ret; 11208c2ecf20Sopenharmony_ci 11218c2ecf20Sopenharmony_ci ret = artpec6_crypto_prepare_crypto(req); 11228c2ecf20Sopenharmony_ci if (ret) { 11238c2ecf20Sopenharmony_ci artpec6_crypto_common_destroy(&req_ctx->common); 11248c2ecf20Sopenharmony_ci return ret; 11258c2ecf20Sopenharmony_ci } 11268c2ecf20Sopenharmony_ci 11278c2ecf20Sopenharmony_ci return artpec6_crypto_submit(&req_ctx->common); 11288c2ecf20Sopenharmony_ci} 11298c2ecf20Sopenharmony_ci 11308c2ecf20Sopenharmony_cistatic int artpec6_crypto_decrypt(struct skcipher_request *req) 11318c2ecf20Sopenharmony_ci{ 11328c2ecf20Sopenharmony_ci int ret; 11338c2ecf20Sopenharmony_ci struct crypto_skcipher *cipher = crypto_skcipher_reqtfm(req); 11348c2ecf20Sopenharmony_ci struct artpec6_cryptotfm_context *ctx = crypto_skcipher_ctx(cipher); 11358c2ecf20Sopenharmony_ci struct artpec6_crypto_request_context *req_ctx = NULL; 11368c2ecf20Sopenharmony_ci void (*complete)(struct crypto_async_request *req); 11378c2ecf20Sopenharmony_ci 11388c2ecf20Sopenharmony_ci req_ctx = skcipher_request_ctx(req); 11398c2ecf20Sopenharmony_ci 11408c2ecf20Sopenharmony_ci switch (ctx->crypto_type) { 11418c2ecf20Sopenharmony_ci case ARTPEC6_CRYPTO_CIPHER_AES_CBC: 11428c2ecf20Sopenharmony_ci case ARTPEC6_CRYPTO_CIPHER_AES_ECB: 11438c2ecf20Sopenharmony_ci case ARTPEC6_CRYPTO_CIPHER_AES_XTS: 11448c2ecf20Sopenharmony_ci req_ctx->decrypt = 1; 11458c2ecf20Sopenharmony_ci break; 11468c2ecf20Sopenharmony_ci default: 11478c2ecf20Sopenharmony_ci break; 11488c2ecf20Sopenharmony_ci } 11498c2ecf20Sopenharmony_ci 11508c2ecf20Sopenharmony_ci 11518c2ecf20Sopenharmony_ci switch (ctx->crypto_type) { 11528c2ecf20Sopenharmony_ci case ARTPEC6_CRYPTO_CIPHER_AES_CBC: 11538c2ecf20Sopenharmony_ci complete = artpec6_crypto_complete_cbc_decrypt; 11548c2ecf20Sopenharmony_ci break; 11558c2ecf20Sopenharmony_ci default: 11568c2ecf20Sopenharmony_ci complete = artpec6_crypto_complete_crypto; 11578c2ecf20Sopenharmony_ci break; 11588c2ecf20Sopenharmony_ci } 11598c2ecf20Sopenharmony_ci 11608c2ecf20Sopenharmony_ci ret = artpec6_crypto_common_init(&req_ctx->common, &req->base, 11618c2ecf20Sopenharmony_ci complete, 11628c2ecf20Sopenharmony_ci req->dst, req->cryptlen); 11638c2ecf20Sopenharmony_ci if (ret) 11648c2ecf20Sopenharmony_ci return ret; 11658c2ecf20Sopenharmony_ci 11668c2ecf20Sopenharmony_ci ret = artpec6_crypto_prepare_crypto(req); 11678c2ecf20Sopenharmony_ci if (ret) { 11688c2ecf20Sopenharmony_ci artpec6_crypto_common_destroy(&req_ctx->common); 11698c2ecf20Sopenharmony_ci return ret; 11708c2ecf20Sopenharmony_ci } 11718c2ecf20Sopenharmony_ci 11728c2ecf20Sopenharmony_ci return artpec6_crypto_submit(&req_ctx->common); 11738c2ecf20Sopenharmony_ci} 11748c2ecf20Sopenharmony_ci 11758c2ecf20Sopenharmony_cistatic int 11768c2ecf20Sopenharmony_ciartpec6_crypto_ctr_crypt(struct skcipher_request *req, bool encrypt) 11778c2ecf20Sopenharmony_ci{ 11788c2ecf20Sopenharmony_ci struct crypto_skcipher *cipher = crypto_skcipher_reqtfm(req); 11798c2ecf20Sopenharmony_ci struct artpec6_cryptotfm_context *ctx = crypto_skcipher_ctx(cipher); 11808c2ecf20Sopenharmony_ci size_t iv_len = crypto_skcipher_ivsize(cipher); 11818c2ecf20Sopenharmony_ci unsigned int counter = be32_to_cpup((__be32 *) 11828c2ecf20Sopenharmony_ci (req->iv + iv_len - 4)); 11838c2ecf20Sopenharmony_ci unsigned int nblks = ALIGN(req->cryptlen, AES_BLOCK_SIZE) / 11848c2ecf20Sopenharmony_ci AES_BLOCK_SIZE; 11858c2ecf20Sopenharmony_ci 11868c2ecf20Sopenharmony_ci /* 11878c2ecf20Sopenharmony_ci * The hardware uses only the last 32-bits as the counter while the 11888c2ecf20Sopenharmony_ci * kernel tests (aes_ctr_enc_tv_template[4] for example) expect that 11898c2ecf20Sopenharmony_ci * the whole IV is a counter. So fallback if the counter is going to 11908c2ecf20Sopenharmony_ci * overlow. 11918c2ecf20Sopenharmony_ci */ 11928c2ecf20Sopenharmony_ci if (counter + nblks < counter) { 11938c2ecf20Sopenharmony_ci int ret; 11948c2ecf20Sopenharmony_ci 11958c2ecf20Sopenharmony_ci pr_debug("counter %x will overflow (nblks %u), falling back\n", 11968c2ecf20Sopenharmony_ci counter, counter + nblks); 11978c2ecf20Sopenharmony_ci 11988c2ecf20Sopenharmony_ci ret = crypto_sync_skcipher_setkey(ctx->fallback, ctx->aes_key, 11998c2ecf20Sopenharmony_ci ctx->key_length); 12008c2ecf20Sopenharmony_ci if (ret) 12018c2ecf20Sopenharmony_ci return ret; 12028c2ecf20Sopenharmony_ci 12038c2ecf20Sopenharmony_ci { 12048c2ecf20Sopenharmony_ci SYNC_SKCIPHER_REQUEST_ON_STACK(subreq, ctx->fallback); 12058c2ecf20Sopenharmony_ci 12068c2ecf20Sopenharmony_ci skcipher_request_set_sync_tfm(subreq, ctx->fallback); 12078c2ecf20Sopenharmony_ci skcipher_request_set_callback(subreq, req->base.flags, 12088c2ecf20Sopenharmony_ci NULL, NULL); 12098c2ecf20Sopenharmony_ci skcipher_request_set_crypt(subreq, req->src, req->dst, 12108c2ecf20Sopenharmony_ci req->cryptlen, req->iv); 12118c2ecf20Sopenharmony_ci ret = encrypt ? crypto_skcipher_encrypt(subreq) 12128c2ecf20Sopenharmony_ci : crypto_skcipher_decrypt(subreq); 12138c2ecf20Sopenharmony_ci skcipher_request_zero(subreq); 12148c2ecf20Sopenharmony_ci } 12158c2ecf20Sopenharmony_ci return ret; 12168c2ecf20Sopenharmony_ci } 12178c2ecf20Sopenharmony_ci 12188c2ecf20Sopenharmony_ci return encrypt ? artpec6_crypto_encrypt(req) 12198c2ecf20Sopenharmony_ci : artpec6_crypto_decrypt(req); 12208c2ecf20Sopenharmony_ci} 12218c2ecf20Sopenharmony_ci 12228c2ecf20Sopenharmony_cistatic int artpec6_crypto_ctr_encrypt(struct skcipher_request *req) 12238c2ecf20Sopenharmony_ci{ 12248c2ecf20Sopenharmony_ci return artpec6_crypto_ctr_crypt(req, true); 12258c2ecf20Sopenharmony_ci} 12268c2ecf20Sopenharmony_ci 12278c2ecf20Sopenharmony_cistatic int artpec6_crypto_ctr_decrypt(struct skcipher_request *req) 12288c2ecf20Sopenharmony_ci{ 12298c2ecf20Sopenharmony_ci return artpec6_crypto_ctr_crypt(req, false); 12308c2ecf20Sopenharmony_ci} 12318c2ecf20Sopenharmony_ci 12328c2ecf20Sopenharmony_ci/* 12338c2ecf20Sopenharmony_ci * AEAD functions 12348c2ecf20Sopenharmony_ci */ 12358c2ecf20Sopenharmony_cistatic int artpec6_crypto_aead_init(struct crypto_aead *tfm) 12368c2ecf20Sopenharmony_ci{ 12378c2ecf20Sopenharmony_ci struct artpec6_cryptotfm_context *tfm_ctx = crypto_aead_ctx(tfm); 12388c2ecf20Sopenharmony_ci 12398c2ecf20Sopenharmony_ci memset(tfm_ctx, 0, sizeof(*tfm_ctx)); 12408c2ecf20Sopenharmony_ci 12418c2ecf20Sopenharmony_ci crypto_aead_set_reqsize(tfm, 12428c2ecf20Sopenharmony_ci sizeof(struct artpec6_crypto_aead_req_ctx)); 12438c2ecf20Sopenharmony_ci 12448c2ecf20Sopenharmony_ci return 0; 12458c2ecf20Sopenharmony_ci} 12468c2ecf20Sopenharmony_ci 12478c2ecf20Sopenharmony_cistatic int artpec6_crypto_aead_set_key(struct crypto_aead *tfm, const u8 *key, 12488c2ecf20Sopenharmony_ci unsigned int len) 12498c2ecf20Sopenharmony_ci{ 12508c2ecf20Sopenharmony_ci struct artpec6_cryptotfm_context *ctx = crypto_tfm_ctx(&tfm->base); 12518c2ecf20Sopenharmony_ci 12528c2ecf20Sopenharmony_ci if (len != 16 && len != 24 && len != 32) 12538c2ecf20Sopenharmony_ci return -EINVAL; 12548c2ecf20Sopenharmony_ci 12558c2ecf20Sopenharmony_ci ctx->key_length = len; 12568c2ecf20Sopenharmony_ci 12578c2ecf20Sopenharmony_ci memcpy(ctx->aes_key, key, len); 12588c2ecf20Sopenharmony_ci return 0; 12598c2ecf20Sopenharmony_ci} 12608c2ecf20Sopenharmony_ci 12618c2ecf20Sopenharmony_cistatic int artpec6_crypto_aead_encrypt(struct aead_request *req) 12628c2ecf20Sopenharmony_ci{ 12638c2ecf20Sopenharmony_ci int ret; 12648c2ecf20Sopenharmony_ci struct artpec6_crypto_aead_req_ctx *req_ctx = aead_request_ctx(req); 12658c2ecf20Sopenharmony_ci 12668c2ecf20Sopenharmony_ci req_ctx->decrypt = false; 12678c2ecf20Sopenharmony_ci ret = artpec6_crypto_common_init(&req_ctx->common, &req->base, 12688c2ecf20Sopenharmony_ci artpec6_crypto_complete_aead, 12698c2ecf20Sopenharmony_ci NULL, 0); 12708c2ecf20Sopenharmony_ci if (ret) 12718c2ecf20Sopenharmony_ci return ret; 12728c2ecf20Sopenharmony_ci 12738c2ecf20Sopenharmony_ci ret = artpec6_crypto_prepare_aead(req); 12748c2ecf20Sopenharmony_ci if (ret) { 12758c2ecf20Sopenharmony_ci artpec6_crypto_common_destroy(&req_ctx->common); 12768c2ecf20Sopenharmony_ci return ret; 12778c2ecf20Sopenharmony_ci } 12788c2ecf20Sopenharmony_ci 12798c2ecf20Sopenharmony_ci return artpec6_crypto_submit(&req_ctx->common); 12808c2ecf20Sopenharmony_ci} 12818c2ecf20Sopenharmony_ci 12828c2ecf20Sopenharmony_cistatic int artpec6_crypto_aead_decrypt(struct aead_request *req) 12838c2ecf20Sopenharmony_ci{ 12848c2ecf20Sopenharmony_ci int ret; 12858c2ecf20Sopenharmony_ci struct artpec6_crypto_aead_req_ctx *req_ctx = aead_request_ctx(req); 12868c2ecf20Sopenharmony_ci 12878c2ecf20Sopenharmony_ci req_ctx->decrypt = true; 12888c2ecf20Sopenharmony_ci if (req->cryptlen < AES_BLOCK_SIZE) 12898c2ecf20Sopenharmony_ci return -EINVAL; 12908c2ecf20Sopenharmony_ci 12918c2ecf20Sopenharmony_ci ret = artpec6_crypto_common_init(&req_ctx->common, 12928c2ecf20Sopenharmony_ci &req->base, 12938c2ecf20Sopenharmony_ci artpec6_crypto_complete_aead, 12948c2ecf20Sopenharmony_ci NULL, 0); 12958c2ecf20Sopenharmony_ci if (ret) 12968c2ecf20Sopenharmony_ci return ret; 12978c2ecf20Sopenharmony_ci 12988c2ecf20Sopenharmony_ci ret = artpec6_crypto_prepare_aead(req); 12998c2ecf20Sopenharmony_ci if (ret) { 13008c2ecf20Sopenharmony_ci artpec6_crypto_common_destroy(&req_ctx->common); 13018c2ecf20Sopenharmony_ci return ret; 13028c2ecf20Sopenharmony_ci } 13038c2ecf20Sopenharmony_ci 13048c2ecf20Sopenharmony_ci return artpec6_crypto_submit(&req_ctx->common); 13058c2ecf20Sopenharmony_ci} 13068c2ecf20Sopenharmony_ci 13078c2ecf20Sopenharmony_cistatic int artpec6_crypto_prepare_hash(struct ahash_request *areq) 13088c2ecf20Sopenharmony_ci{ 13098c2ecf20Sopenharmony_ci struct artpec6_hashalg_context *ctx = crypto_tfm_ctx(areq->base.tfm); 13108c2ecf20Sopenharmony_ci struct artpec6_hash_request_context *req_ctx = ahash_request_ctx(areq); 13118c2ecf20Sopenharmony_ci size_t digestsize = crypto_ahash_digestsize(crypto_ahash_reqtfm(areq)); 13128c2ecf20Sopenharmony_ci size_t contextsize = digestsize; 13138c2ecf20Sopenharmony_ci size_t blocksize = crypto_tfm_alg_blocksize( 13148c2ecf20Sopenharmony_ci crypto_ahash_tfm(crypto_ahash_reqtfm(areq))); 13158c2ecf20Sopenharmony_ci struct artpec6_crypto_req_common *common = &req_ctx->common; 13168c2ecf20Sopenharmony_ci struct artpec6_crypto *ac = dev_get_drvdata(artpec6_crypto_dev); 13178c2ecf20Sopenharmony_ci enum artpec6_crypto_variant variant = ac->variant; 13188c2ecf20Sopenharmony_ci u32 sel_ctx; 13198c2ecf20Sopenharmony_ci bool ext_ctx = false; 13208c2ecf20Sopenharmony_ci bool run_hw = false; 13218c2ecf20Sopenharmony_ci int error = 0; 13228c2ecf20Sopenharmony_ci 13238c2ecf20Sopenharmony_ci artpec6_crypto_init_dma_operation(common); 13248c2ecf20Sopenharmony_ci 13258c2ecf20Sopenharmony_ci /* Upload HMAC key, must be first the first packet */ 13268c2ecf20Sopenharmony_ci if (req_ctx->hash_flags & HASH_FLAG_HMAC) { 13278c2ecf20Sopenharmony_ci if (variant == ARTPEC6_CRYPTO) { 13288c2ecf20Sopenharmony_ci req_ctx->key_md = FIELD_PREP(A6_CRY_MD_OPER, 13298c2ecf20Sopenharmony_ci a6_regk_crypto_dlkey); 13308c2ecf20Sopenharmony_ci } else { 13318c2ecf20Sopenharmony_ci req_ctx->key_md = FIELD_PREP(A7_CRY_MD_OPER, 13328c2ecf20Sopenharmony_ci a7_regk_crypto_dlkey); 13338c2ecf20Sopenharmony_ci } 13348c2ecf20Sopenharmony_ci 13358c2ecf20Sopenharmony_ci /* Copy and pad up the key */ 13368c2ecf20Sopenharmony_ci memcpy(req_ctx->key_buffer, ctx->hmac_key, 13378c2ecf20Sopenharmony_ci ctx->hmac_key_length); 13388c2ecf20Sopenharmony_ci memset(req_ctx->key_buffer + ctx->hmac_key_length, 0, 13398c2ecf20Sopenharmony_ci blocksize - ctx->hmac_key_length); 13408c2ecf20Sopenharmony_ci 13418c2ecf20Sopenharmony_ci error = artpec6_crypto_setup_out_descr(common, 13428c2ecf20Sopenharmony_ci (void *)&req_ctx->key_md, 13438c2ecf20Sopenharmony_ci sizeof(req_ctx->key_md), false, false); 13448c2ecf20Sopenharmony_ci if (error) 13458c2ecf20Sopenharmony_ci return error; 13468c2ecf20Sopenharmony_ci 13478c2ecf20Sopenharmony_ci error = artpec6_crypto_setup_out_descr(common, 13488c2ecf20Sopenharmony_ci req_ctx->key_buffer, blocksize, 13498c2ecf20Sopenharmony_ci true, false); 13508c2ecf20Sopenharmony_ci if (error) 13518c2ecf20Sopenharmony_ci return error; 13528c2ecf20Sopenharmony_ci } 13538c2ecf20Sopenharmony_ci 13548c2ecf20Sopenharmony_ci if (!(req_ctx->hash_flags & HASH_FLAG_INIT_CTX)) { 13558c2ecf20Sopenharmony_ci /* Restore context */ 13568c2ecf20Sopenharmony_ci sel_ctx = regk_crypto_ext; 13578c2ecf20Sopenharmony_ci ext_ctx = true; 13588c2ecf20Sopenharmony_ci } else { 13598c2ecf20Sopenharmony_ci sel_ctx = regk_crypto_init; 13608c2ecf20Sopenharmony_ci } 13618c2ecf20Sopenharmony_ci 13628c2ecf20Sopenharmony_ci if (variant == ARTPEC6_CRYPTO) { 13638c2ecf20Sopenharmony_ci req_ctx->hash_md &= ~A6_CRY_MD_HASH_SEL_CTX; 13648c2ecf20Sopenharmony_ci req_ctx->hash_md |= FIELD_PREP(A6_CRY_MD_HASH_SEL_CTX, sel_ctx); 13658c2ecf20Sopenharmony_ci 13668c2ecf20Sopenharmony_ci /* If this is the final round, set the final flag */ 13678c2ecf20Sopenharmony_ci if (req_ctx->hash_flags & HASH_FLAG_FINALIZE) 13688c2ecf20Sopenharmony_ci req_ctx->hash_md |= A6_CRY_MD_HASH_HMAC_FIN; 13698c2ecf20Sopenharmony_ci } else { 13708c2ecf20Sopenharmony_ci req_ctx->hash_md &= ~A7_CRY_MD_HASH_SEL_CTX; 13718c2ecf20Sopenharmony_ci req_ctx->hash_md |= FIELD_PREP(A7_CRY_MD_HASH_SEL_CTX, sel_ctx); 13728c2ecf20Sopenharmony_ci 13738c2ecf20Sopenharmony_ci /* If this is the final round, set the final flag */ 13748c2ecf20Sopenharmony_ci if (req_ctx->hash_flags & HASH_FLAG_FINALIZE) 13758c2ecf20Sopenharmony_ci req_ctx->hash_md |= A7_CRY_MD_HASH_HMAC_FIN; 13768c2ecf20Sopenharmony_ci } 13778c2ecf20Sopenharmony_ci 13788c2ecf20Sopenharmony_ci /* Setup up metadata descriptors */ 13798c2ecf20Sopenharmony_ci error = artpec6_crypto_setup_out_descr(common, 13808c2ecf20Sopenharmony_ci (void *)&req_ctx->hash_md, 13818c2ecf20Sopenharmony_ci sizeof(req_ctx->hash_md), false, false); 13828c2ecf20Sopenharmony_ci if (error) 13838c2ecf20Sopenharmony_ci return error; 13848c2ecf20Sopenharmony_ci 13858c2ecf20Sopenharmony_ci error = artpec6_crypto_setup_in_descr(common, ac->pad_buffer, 4, false); 13868c2ecf20Sopenharmony_ci if (error) 13878c2ecf20Sopenharmony_ci return error; 13888c2ecf20Sopenharmony_ci 13898c2ecf20Sopenharmony_ci if (ext_ctx) { 13908c2ecf20Sopenharmony_ci error = artpec6_crypto_setup_out_descr(common, 13918c2ecf20Sopenharmony_ci req_ctx->digeststate, 13928c2ecf20Sopenharmony_ci contextsize, false, false); 13938c2ecf20Sopenharmony_ci 13948c2ecf20Sopenharmony_ci if (error) 13958c2ecf20Sopenharmony_ci return error; 13968c2ecf20Sopenharmony_ci } 13978c2ecf20Sopenharmony_ci 13988c2ecf20Sopenharmony_ci if (req_ctx->hash_flags & HASH_FLAG_UPDATE) { 13998c2ecf20Sopenharmony_ci size_t done_bytes = 0; 14008c2ecf20Sopenharmony_ci size_t total_bytes = areq->nbytes + req_ctx->partial_bytes; 14018c2ecf20Sopenharmony_ci size_t ready_bytes = round_down(total_bytes, blocksize); 14028c2ecf20Sopenharmony_ci struct artpec6_crypto_walk walk; 14038c2ecf20Sopenharmony_ci 14048c2ecf20Sopenharmony_ci run_hw = ready_bytes > 0; 14058c2ecf20Sopenharmony_ci if (req_ctx->partial_bytes && ready_bytes) { 14068c2ecf20Sopenharmony_ci /* We have a partial buffer and will at least some bytes 14078c2ecf20Sopenharmony_ci * to the HW. Empty this partial buffer before tackling 14088c2ecf20Sopenharmony_ci * the SG lists 14098c2ecf20Sopenharmony_ci */ 14108c2ecf20Sopenharmony_ci memcpy(req_ctx->partial_buffer_out, 14118c2ecf20Sopenharmony_ci req_ctx->partial_buffer, 14128c2ecf20Sopenharmony_ci req_ctx->partial_bytes); 14138c2ecf20Sopenharmony_ci 14148c2ecf20Sopenharmony_ci error = artpec6_crypto_setup_out_descr(common, 14158c2ecf20Sopenharmony_ci req_ctx->partial_buffer_out, 14168c2ecf20Sopenharmony_ci req_ctx->partial_bytes, 14178c2ecf20Sopenharmony_ci false, true); 14188c2ecf20Sopenharmony_ci if (error) 14198c2ecf20Sopenharmony_ci return error; 14208c2ecf20Sopenharmony_ci 14218c2ecf20Sopenharmony_ci /* Reset partial buffer */ 14228c2ecf20Sopenharmony_ci done_bytes += req_ctx->partial_bytes; 14238c2ecf20Sopenharmony_ci req_ctx->partial_bytes = 0; 14248c2ecf20Sopenharmony_ci } 14258c2ecf20Sopenharmony_ci 14268c2ecf20Sopenharmony_ci artpec6_crypto_walk_init(&walk, areq->src); 14278c2ecf20Sopenharmony_ci 14288c2ecf20Sopenharmony_ci error = artpec6_crypto_setup_sg_descrs_out(common, &walk, 14298c2ecf20Sopenharmony_ci ready_bytes - 14308c2ecf20Sopenharmony_ci done_bytes); 14318c2ecf20Sopenharmony_ci if (error) 14328c2ecf20Sopenharmony_ci return error; 14338c2ecf20Sopenharmony_ci 14348c2ecf20Sopenharmony_ci if (walk.sg) { 14358c2ecf20Sopenharmony_ci size_t sg_skip = ready_bytes - done_bytes; 14368c2ecf20Sopenharmony_ci size_t sg_rem = areq->nbytes - sg_skip; 14378c2ecf20Sopenharmony_ci 14388c2ecf20Sopenharmony_ci sg_pcopy_to_buffer(areq->src, sg_nents(areq->src), 14398c2ecf20Sopenharmony_ci req_ctx->partial_buffer + 14408c2ecf20Sopenharmony_ci req_ctx->partial_bytes, 14418c2ecf20Sopenharmony_ci sg_rem, sg_skip); 14428c2ecf20Sopenharmony_ci 14438c2ecf20Sopenharmony_ci req_ctx->partial_bytes += sg_rem; 14448c2ecf20Sopenharmony_ci } 14458c2ecf20Sopenharmony_ci 14468c2ecf20Sopenharmony_ci req_ctx->digcnt += ready_bytes; 14478c2ecf20Sopenharmony_ci req_ctx->hash_flags &= ~(HASH_FLAG_UPDATE); 14488c2ecf20Sopenharmony_ci } 14498c2ecf20Sopenharmony_ci 14508c2ecf20Sopenharmony_ci /* Finalize */ 14518c2ecf20Sopenharmony_ci if (req_ctx->hash_flags & HASH_FLAG_FINALIZE) { 14528c2ecf20Sopenharmony_ci size_t hash_pad_len; 14538c2ecf20Sopenharmony_ci u64 digest_bits; 14548c2ecf20Sopenharmony_ci u32 oper; 14558c2ecf20Sopenharmony_ci 14568c2ecf20Sopenharmony_ci if (variant == ARTPEC6_CRYPTO) 14578c2ecf20Sopenharmony_ci oper = FIELD_GET(A6_CRY_MD_OPER, req_ctx->hash_md); 14588c2ecf20Sopenharmony_ci else 14598c2ecf20Sopenharmony_ci oper = FIELD_GET(A7_CRY_MD_OPER, req_ctx->hash_md); 14608c2ecf20Sopenharmony_ci 14618c2ecf20Sopenharmony_ci /* Write out the partial buffer if present */ 14628c2ecf20Sopenharmony_ci if (req_ctx->partial_bytes) { 14638c2ecf20Sopenharmony_ci memcpy(req_ctx->partial_buffer_out, 14648c2ecf20Sopenharmony_ci req_ctx->partial_buffer, 14658c2ecf20Sopenharmony_ci req_ctx->partial_bytes); 14668c2ecf20Sopenharmony_ci error = artpec6_crypto_setup_out_descr(common, 14678c2ecf20Sopenharmony_ci req_ctx->partial_buffer_out, 14688c2ecf20Sopenharmony_ci req_ctx->partial_bytes, 14698c2ecf20Sopenharmony_ci false, true); 14708c2ecf20Sopenharmony_ci if (error) 14718c2ecf20Sopenharmony_ci return error; 14728c2ecf20Sopenharmony_ci 14738c2ecf20Sopenharmony_ci req_ctx->digcnt += req_ctx->partial_bytes; 14748c2ecf20Sopenharmony_ci req_ctx->partial_bytes = 0; 14758c2ecf20Sopenharmony_ci } 14768c2ecf20Sopenharmony_ci 14778c2ecf20Sopenharmony_ci if (req_ctx->hash_flags & HASH_FLAG_HMAC) 14788c2ecf20Sopenharmony_ci digest_bits = 8 * (req_ctx->digcnt + blocksize); 14798c2ecf20Sopenharmony_ci else 14808c2ecf20Sopenharmony_ci digest_bits = 8 * req_ctx->digcnt; 14818c2ecf20Sopenharmony_ci 14828c2ecf20Sopenharmony_ci /* Add the hash pad */ 14838c2ecf20Sopenharmony_ci hash_pad_len = create_hash_pad(oper, req_ctx->pad_buffer, 14848c2ecf20Sopenharmony_ci req_ctx->digcnt, digest_bits); 14858c2ecf20Sopenharmony_ci error = artpec6_crypto_setup_out_descr(common, 14868c2ecf20Sopenharmony_ci req_ctx->pad_buffer, 14878c2ecf20Sopenharmony_ci hash_pad_len, false, 14888c2ecf20Sopenharmony_ci true); 14898c2ecf20Sopenharmony_ci req_ctx->digcnt = 0; 14908c2ecf20Sopenharmony_ci 14918c2ecf20Sopenharmony_ci if (error) 14928c2ecf20Sopenharmony_ci return error; 14938c2ecf20Sopenharmony_ci 14948c2ecf20Sopenharmony_ci /* Descriptor for the final result */ 14958c2ecf20Sopenharmony_ci error = artpec6_crypto_setup_in_descr(common, areq->result, 14968c2ecf20Sopenharmony_ci digestsize, 14978c2ecf20Sopenharmony_ci true); 14988c2ecf20Sopenharmony_ci if (error) 14998c2ecf20Sopenharmony_ci return error; 15008c2ecf20Sopenharmony_ci 15018c2ecf20Sopenharmony_ci } else { /* This is not the final operation for this request */ 15028c2ecf20Sopenharmony_ci if (!run_hw) 15038c2ecf20Sopenharmony_ci return ARTPEC6_CRYPTO_PREPARE_HASH_NO_START; 15048c2ecf20Sopenharmony_ci 15058c2ecf20Sopenharmony_ci /* Save the result to the context */ 15068c2ecf20Sopenharmony_ci error = artpec6_crypto_setup_in_descr(common, 15078c2ecf20Sopenharmony_ci req_ctx->digeststate, 15088c2ecf20Sopenharmony_ci contextsize, false); 15098c2ecf20Sopenharmony_ci if (error) 15108c2ecf20Sopenharmony_ci return error; 15118c2ecf20Sopenharmony_ci /* fall through */ 15128c2ecf20Sopenharmony_ci } 15138c2ecf20Sopenharmony_ci 15148c2ecf20Sopenharmony_ci req_ctx->hash_flags &= ~(HASH_FLAG_INIT_CTX | HASH_FLAG_UPDATE | 15158c2ecf20Sopenharmony_ci HASH_FLAG_FINALIZE); 15168c2ecf20Sopenharmony_ci 15178c2ecf20Sopenharmony_ci error = artpec6_crypto_terminate_in_descrs(common); 15188c2ecf20Sopenharmony_ci if (error) 15198c2ecf20Sopenharmony_ci return error; 15208c2ecf20Sopenharmony_ci 15218c2ecf20Sopenharmony_ci error = artpec6_crypto_terminate_out_descrs(common); 15228c2ecf20Sopenharmony_ci if (error) 15238c2ecf20Sopenharmony_ci return error; 15248c2ecf20Sopenharmony_ci 15258c2ecf20Sopenharmony_ci error = artpec6_crypto_dma_map_descs(common); 15268c2ecf20Sopenharmony_ci if (error) 15278c2ecf20Sopenharmony_ci return error; 15288c2ecf20Sopenharmony_ci 15298c2ecf20Sopenharmony_ci return ARTPEC6_CRYPTO_PREPARE_HASH_START; 15308c2ecf20Sopenharmony_ci} 15318c2ecf20Sopenharmony_ci 15328c2ecf20Sopenharmony_ci 15338c2ecf20Sopenharmony_cistatic int artpec6_crypto_aes_ecb_init(struct crypto_skcipher *tfm) 15348c2ecf20Sopenharmony_ci{ 15358c2ecf20Sopenharmony_ci struct artpec6_cryptotfm_context *ctx = crypto_skcipher_ctx(tfm); 15368c2ecf20Sopenharmony_ci 15378c2ecf20Sopenharmony_ci tfm->reqsize = sizeof(struct artpec6_crypto_request_context); 15388c2ecf20Sopenharmony_ci ctx->crypto_type = ARTPEC6_CRYPTO_CIPHER_AES_ECB; 15398c2ecf20Sopenharmony_ci 15408c2ecf20Sopenharmony_ci return 0; 15418c2ecf20Sopenharmony_ci} 15428c2ecf20Sopenharmony_ci 15438c2ecf20Sopenharmony_cistatic int artpec6_crypto_aes_ctr_init(struct crypto_skcipher *tfm) 15448c2ecf20Sopenharmony_ci{ 15458c2ecf20Sopenharmony_ci struct artpec6_cryptotfm_context *ctx = crypto_skcipher_ctx(tfm); 15468c2ecf20Sopenharmony_ci 15478c2ecf20Sopenharmony_ci ctx->fallback = 15488c2ecf20Sopenharmony_ci crypto_alloc_sync_skcipher(crypto_tfm_alg_name(&tfm->base), 15498c2ecf20Sopenharmony_ci 0, CRYPTO_ALG_NEED_FALLBACK); 15508c2ecf20Sopenharmony_ci if (IS_ERR(ctx->fallback)) 15518c2ecf20Sopenharmony_ci return PTR_ERR(ctx->fallback); 15528c2ecf20Sopenharmony_ci 15538c2ecf20Sopenharmony_ci tfm->reqsize = sizeof(struct artpec6_crypto_request_context); 15548c2ecf20Sopenharmony_ci ctx->crypto_type = ARTPEC6_CRYPTO_CIPHER_AES_CTR; 15558c2ecf20Sopenharmony_ci 15568c2ecf20Sopenharmony_ci return 0; 15578c2ecf20Sopenharmony_ci} 15588c2ecf20Sopenharmony_ci 15598c2ecf20Sopenharmony_cistatic int artpec6_crypto_aes_cbc_init(struct crypto_skcipher *tfm) 15608c2ecf20Sopenharmony_ci{ 15618c2ecf20Sopenharmony_ci struct artpec6_cryptotfm_context *ctx = crypto_skcipher_ctx(tfm); 15628c2ecf20Sopenharmony_ci 15638c2ecf20Sopenharmony_ci tfm->reqsize = sizeof(struct artpec6_crypto_request_context); 15648c2ecf20Sopenharmony_ci ctx->crypto_type = ARTPEC6_CRYPTO_CIPHER_AES_CBC; 15658c2ecf20Sopenharmony_ci 15668c2ecf20Sopenharmony_ci return 0; 15678c2ecf20Sopenharmony_ci} 15688c2ecf20Sopenharmony_ci 15698c2ecf20Sopenharmony_cistatic int artpec6_crypto_aes_xts_init(struct crypto_skcipher *tfm) 15708c2ecf20Sopenharmony_ci{ 15718c2ecf20Sopenharmony_ci struct artpec6_cryptotfm_context *ctx = crypto_skcipher_ctx(tfm); 15728c2ecf20Sopenharmony_ci 15738c2ecf20Sopenharmony_ci tfm->reqsize = sizeof(struct artpec6_crypto_request_context); 15748c2ecf20Sopenharmony_ci ctx->crypto_type = ARTPEC6_CRYPTO_CIPHER_AES_XTS; 15758c2ecf20Sopenharmony_ci 15768c2ecf20Sopenharmony_ci return 0; 15778c2ecf20Sopenharmony_ci} 15788c2ecf20Sopenharmony_ci 15798c2ecf20Sopenharmony_cistatic void artpec6_crypto_aes_exit(struct crypto_skcipher *tfm) 15808c2ecf20Sopenharmony_ci{ 15818c2ecf20Sopenharmony_ci struct artpec6_cryptotfm_context *ctx = crypto_skcipher_ctx(tfm); 15828c2ecf20Sopenharmony_ci 15838c2ecf20Sopenharmony_ci memset(ctx, 0, sizeof(*ctx)); 15848c2ecf20Sopenharmony_ci} 15858c2ecf20Sopenharmony_ci 15868c2ecf20Sopenharmony_cistatic void artpec6_crypto_aes_ctr_exit(struct crypto_skcipher *tfm) 15878c2ecf20Sopenharmony_ci{ 15888c2ecf20Sopenharmony_ci struct artpec6_cryptotfm_context *ctx = crypto_skcipher_ctx(tfm); 15898c2ecf20Sopenharmony_ci 15908c2ecf20Sopenharmony_ci crypto_free_sync_skcipher(ctx->fallback); 15918c2ecf20Sopenharmony_ci artpec6_crypto_aes_exit(tfm); 15928c2ecf20Sopenharmony_ci} 15938c2ecf20Sopenharmony_ci 15948c2ecf20Sopenharmony_cistatic int 15958c2ecf20Sopenharmony_ciartpec6_crypto_cipher_set_key(struct crypto_skcipher *cipher, const u8 *key, 15968c2ecf20Sopenharmony_ci unsigned int keylen) 15978c2ecf20Sopenharmony_ci{ 15988c2ecf20Sopenharmony_ci struct artpec6_cryptotfm_context *ctx = 15998c2ecf20Sopenharmony_ci crypto_skcipher_ctx(cipher); 16008c2ecf20Sopenharmony_ci 16018c2ecf20Sopenharmony_ci switch (keylen) { 16028c2ecf20Sopenharmony_ci case 16: 16038c2ecf20Sopenharmony_ci case 24: 16048c2ecf20Sopenharmony_ci case 32: 16058c2ecf20Sopenharmony_ci break; 16068c2ecf20Sopenharmony_ci default: 16078c2ecf20Sopenharmony_ci return -EINVAL; 16088c2ecf20Sopenharmony_ci } 16098c2ecf20Sopenharmony_ci 16108c2ecf20Sopenharmony_ci memcpy(ctx->aes_key, key, keylen); 16118c2ecf20Sopenharmony_ci ctx->key_length = keylen; 16128c2ecf20Sopenharmony_ci return 0; 16138c2ecf20Sopenharmony_ci} 16148c2ecf20Sopenharmony_ci 16158c2ecf20Sopenharmony_cistatic int 16168c2ecf20Sopenharmony_ciartpec6_crypto_xts_set_key(struct crypto_skcipher *cipher, const u8 *key, 16178c2ecf20Sopenharmony_ci unsigned int keylen) 16188c2ecf20Sopenharmony_ci{ 16198c2ecf20Sopenharmony_ci struct artpec6_cryptotfm_context *ctx = 16208c2ecf20Sopenharmony_ci crypto_skcipher_ctx(cipher); 16218c2ecf20Sopenharmony_ci int ret; 16228c2ecf20Sopenharmony_ci 16238c2ecf20Sopenharmony_ci ret = xts_check_key(&cipher->base, key, keylen); 16248c2ecf20Sopenharmony_ci if (ret) 16258c2ecf20Sopenharmony_ci return ret; 16268c2ecf20Sopenharmony_ci 16278c2ecf20Sopenharmony_ci switch (keylen) { 16288c2ecf20Sopenharmony_ci case 32: 16298c2ecf20Sopenharmony_ci case 48: 16308c2ecf20Sopenharmony_ci case 64: 16318c2ecf20Sopenharmony_ci break; 16328c2ecf20Sopenharmony_ci default: 16338c2ecf20Sopenharmony_ci return -EINVAL; 16348c2ecf20Sopenharmony_ci } 16358c2ecf20Sopenharmony_ci 16368c2ecf20Sopenharmony_ci memcpy(ctx->aes_key, key, keylen); 16378c2ecf20Sopenharmony_ci ctx->key_length = keylen; 16388c2ecf20Sopenharmony_ci return 0; 16398c2ecf20Sopenharmony_ci} 16408c2ecf20Sopenharmony_ci 16418c2ecf20Sopenharmony_ci/** artpec6_crypto_process_crypto - Prepare an async block cipher crypto request 16428c2ecf20Sopenharmony_ci * 16438c2ecf20Sopenharmony_ci * @req: The asynch request to process 16448c2ecf20Sopenharmony_ci * 16458c2ecf20Sopenharmony_ci * @return 0 if the dma job was successfully prepared 16468c2ecf20Sopenharmony_ci * <0 on error 16478c2ecf20Sopenharmony_ci * 16488c2ecf20Sopenharmony_ci * This function sets up the PDMA descriptors for a block cipher request. 16498c2ecf20Sopenharmony_ci * 16508c2ecf20Sopenharmony_ci * The required padding is added for AES-CTR using a statically defined 16518c2ecf20Sopenharmony_ci * buffer. 16528c2ecf20Sopenharmony_ci * 16538c2ecf20Sopenharmony_ci * The PDMA descriptor list will be as follows: 16548c2ecf20Sopenharmony_ci * 16558c2ecf20Sopenharmony_ci * OUT: [KEY_MD][KEY][EOP]<CIPHER_MD>[IV]<data_0>...[data_n][AES-CTR_pad]<eop> 16568c2ecf20Sopenharmony_ci * IN: <CIPHER_MD><data_0>...[data_n]<intr> 16578c2ecf20Sopenharmony_ci * 16588c2ecf20Sopenharmony_ci */ 16598c2ecf20Sopenharmony_cistatic int artpec6_crypto_prepare_crypto(struct skcipher_request *areq) 16608c2ecf20Sopenharmony_ci{ 16618c2ecf20Sopenharmony_ci int ret; 16628c2ecf20Sopenharmony_ci struct artpec6_crypto_walk walk; 16638c2ecf20Sopenharmony_ci struct crypto_skcipher *cipher = crypto_skcipher_reqtfm(areq); 16648c2ecf20Sopenharmony_ci struct artpec6_cryptotfm_context *ctx = crypto_skcipher_ctx(cipher); 16658c2ecf20Sopenharmony_ci struct artpec6_crypto_request_context *req_ctx = NULL; 16668c2ecf20Sopenharmony_ci size_t iv_len = crypto_skcipher_ivsize(cipher); 16678c2ecf20Sopenharmony_ci struct artpec6_crypto *ac = dev_get_drvdata(artpec6_crypto_dev); 16688c2ecf20Sopenharmony_ci enum artpec6_crypto_variant variant = ac->variant; 16698c2ecf20Sopenharmony_ci struct artpec6_crypto_req_common *common; 16708c2ecf20Sopenharmony_ci bool cipher_decr = false; 16718c2ecf20Sopenharmony_ci size_t cipher_klen; 16728c2ecf20Sopenharmony_ci u32 cipher_len = 0; /* Same as regk_crypto_key_128 for NULL crypto */ 16738c2ecf20Sopenharmony_ci u32 oper; 16748c2ecf20Sopenharmony_ci 16758c2ecf20Sopenharmony_ci req_ctx = skcipher_request_ctx(areq); 16768c2ecf20Sopenharmony_ci common = &req_ctx->common; 16778c2ecf20Sopenharmony_ci 16788c2ecf20Sopenharmony_ci artpec6_crypto_init_dma_operation(common); 16798c2ecf20Sopenharmony_ci 16808c2ecf20Sopenharmony_ci if (variant == ARTPEC6_CRYPTO) 16818c2ecf20Sopenharmony_ci ctx->key_md = FIELD_PREP(A6_CRY_MD_OPER, a6_regk_crypto_dlkey); 16828c2ecf20Sopenharmony_ci else 16838c2ecf20Sopenharmony_ci ctx->key_md = FIELD_PREP(A7_CRY_MD_OPER, a7_regk_crypto_dlkey); 16848c2ecf20Sopenharmony_ci 16858c2ecf20Sopenharmony_ci ret = artpec6_crypto_setup_out_descr(common, (void *)&ctx->key_md, 16868c2ecf20Sopenharmony_ci sizeof(ctx->key_md), false, false); 16878c2ecf20Sopenharmony_ci if (ret) 16888c2ecf20Sopenharmony_ci return ret; 16898c2ecf20Sopenharmony_ci 16908c2ecf20Sopenharmony_ci ret = artpec6_crypto_setup_out_descr(common, ctx->aes_key, 16918c2ecf20Sopenharmony_ci ctx->key_length, true, false); 16928c2ecf20Sopenharmony_ci if (ret) 16938c2ecf20Sopenharmony_ci return ret; 16948c2ecf20Sopenharmony_ci 16958c2ecf20Sopenharmony_ci req_ctx->cipher_md = 0; 16968c2ecf20Sopenharmony_ci 16978c2ecf20Sopenharmony_ci if (ctx->crypto_type == ARTPEC6_CRYPTO_CIPHER_AES_XTS) 16988c2ecf20Sopenharmony_ci cipher_klen = ctx->key_length/2; 16998c2ecf20Sopenharmony_ci else 17008c2ecf20Sopenharmony_ci cipher_klen = ctx->key_length; 17018c2ecf20Sopenharmony_ci 17028c2ecf20Sopenharmony_ci /* Metadata */ 17038c2ecf20Sopenharmony_ci switch (cipher_klen) { 17048c2ecf20Sopenharmony_ci case 16: 17058c2ecf20Sopenharmony_ci cipher_len = regk_crypto_key_128; 17068c2ecf20Sopenharmony_ci break; 17078c2ecf20Sopenharmony_ci case 24: 17088c2ecf20Sopenharmony_ci cipher_len = regk_crypto_key_192; 17098c2ecf20Sopenharmony_ci break; 17108c2ecf20Sopenharmony_ci case 32: 17118c2ecf20Sopenharmony_ci cipher_len = regk_crypto_key_256; 17128c2ecf20Sopenharmony_ci break; 17138c2ecf20Sopenharmony_ci default: 17148c2ecf20Sopenharmony_ci pr_err("%s: Invalid key length %d!\n", 17158c2ecf20Sopenharmony_ci MODULE_NAME, ctx->key_length); 17168c2ecf20Sopenharmony_ci return -EINVAL; 17178c2ecf20Sopenharmony_ci } 17188c2ecf20Sopenharmony_ci 17198c2ecf20Sopenharmony_ci switch (ctx->crypto_type) { 17208c2ecf20Sopenharmony_ci case ARTPEC6_CRYPTO_CIPHER_AES_ECB: 17218c2ecf20Sopenharmony_ci oper = regk_crypto_aes_ecb; 17228c2ecf20Sopenharmony_ci cipher_decr = req_ctx->decrypt; 17238c2ecf20Sopenharmony_ci break; 17248c2ecf20Sopenharmony_ci 17258c2ecf20Sopenharmony_ci case ARTPEC6_CRYPTO_CIPHER_AES_CBC: 17268c2ecf20Sopenharmony_ci oper = regk_crypto_aes_cbc; 17278c2ecf20Sopenharmony_ci cipher_decr = req_ctx->decrypt; 17288c2ecf20Sopenharmony_ci break; 17298c2ecf20Sopenharmony_ci 17308c2ecf20Sopenharmony_ci case ARTPEC6_CRYPTO_CIPHER_AES_CTR: 17318c2ecf20Sopenharmony_ci oper = regk_crypto_aes_ctr; 17328c2ecf20Sopenharmony_ci cipher_decr = false; 17338c2ecf20Sopenharmony_ci break; 17348c2ecf20Sopenharmony_ci 17358c2ecf20Sopenharmony_ci case ARTPEC6_CRYPTO_CIPHER_AES_XTS: 17368c2ecf20Sopenharmony_ci oper = regk_crypto_aes_xts; 17378c2ecf20Sopenharmony_ci cipher_decr = req_ctx->decrypt; 17388c2ecf20Sopenharmony_ci 17398c2ecf20Sopenharmony_ci if (variant == ARTPEC6_CRYPTO) 17408c2ecf20Sopenharmony_ci req_ctx->cipher_md |= A6_CRY_MD_CIPHER_DSEQ; 17418c2ecf20Sopenharmony_ci else 17428c2ecf20Sopenharmony_ci req_ctx->cipher_md |= A7_CRY_MD_CIPHER_DSEQ; 17438c2ecf20Sopenharmony_ci break; 17448c2ecf20Sopenharmony_ci 17458c2ecf20Sopenharmony_ci default: 17468c2ecf20Sopenharmony_ci pr_err("%s: Invalid cipher mode %d!\n", 17478c2ecf20Sopenharmony_ci MODULE_NAME, ctx->crypto_type); 17488c2ecf20Sopenharmony_ci return -EINVAL; 17498c2ecf20Sopenharmony_ci } 17508c2ecf20Sopenharmony_ci 17518c2ecf20Sopenharmony_ci if (variant == ARTPEC6_CRYPTO) { 17528c2ecf20Sopenharmony_ci req_ctx->cipher_md |= FIELD_PREP(A6_CRY_MD_OPER, oper); 17538c2ecf20Sopenharmony_ci req_ctx->cipher_md |= FIELD_PREP(A6_CRY_MD_CIPHER_LEN, 17548c2ecf20Sopenharmony_ci cipher_len); 17558c2ecf20Sopenharmony_ci if (cipher_decr) 17568c2ecf20Sopenharmony_ci req_ctx->cipher_md |= A6_CRY_MD_CIPHER_DECR; 17578c2ecf20Sopenharmony_ci } else { 17588c2ecf20Sopenharmony_ci req_ctx->cipher_md |= FIELD_PREP(A7_CRY_MD_OPER, oper); 17598c2ecf20Sopenharmony_ci req_ctx->cipher_md |= FIELD_PREP(A7_CRY_MD_CIPHER_LEN, 17608c2ecf20Sopenharmony_ci cipher_len); 17618c2ecf20Sopenharmony_ci if (cipher_decr) 17628c2ecf20Sopenharmony_ci req_ctx->cipher_md |= A7_CRY_MD_CIPHER_DECR; 17638c2ecf20Sopenharmony_ci } 17648c2ecf20Sopenharmony_ci 17658c2ecf20Sopenharmony_ci ret = artpec6_crypto_setup_out_descr(common, 17668c2ecf20Sopenharmony_ci &req_ctx->cipher_md, 17678c2ecf20Sopenharmony_ci sizeof(req_ctx->cipher_md), 17688c2ecf20Sopenharmony_ci false, false); 17698c2ecf20Sopenharmony_ci if (ret) 17708c2ecf20Sopenharmony_ci return ret; 17718c2ecf20Sopenharmony_ci 17728c2ecf20Sopenharmony_ci ret = artpec6_crypto_setup_in_descr(common, ac->pad_buffer, 4, false); 17738c2ecf20Sopenharmony_ci if (ret) 17748c2ecf20Sopenharmony_ci return ret; 17758c2ecf20Sopenharmony_ci 17768c2ecf20Sopenharmony_ci if (iv_len) { 17778c2ecf20Sopenharmony_ci ret = artpec6_crypto_setup_out_descr(common, areq->iv, iv_len, 17788c2ecf20Sopenharmony_ci false, false); 17798c2ecf20Sopenharmony_ci if (ret) 17808c2ecf20Sopenharmony_ci return ret; 17818c2ecf20Sopenharmony_ci } 17828c2ecf20Sopenharmony_ci /* Data out */ 17838c2ecf20Sopenharmony_ci artpec6_crypto_walk_init(&walk, areq->src); 17848c2ecf20Sopenharmony_ci ret = artpec6_crypto_setup_sg_descrs_out(common, &walk, areq->cryptlen); 17858c2ecf20Sopenharmony_ci if (ret) 17868c2ecf20Sopenharmony_ci return ret; 17878c2ecf20Sopenharmony_ci 17888c2ecf20Sopenharmony_ci /* Data in */ 17898c2ecf20Sopenharmony_ci artpec6_crypto_walk_init(&walk, areq->dst); 17908c2ecf20Sopenharmony_ci ret = artpec6_crypto_setup_sg_descrs_in(common, &walk, areq->cryptlen); 17918c2ecf20Sopenharmony_ci if (ret) 17928c2ecf20Sopenharmony_ci return ret; 17938c2ecf20Sopenharmony_ci 17948c2ecf20Sopenharmony_ci /* CTR-mode padding required by the HW. */ 17958c2ecf20Sopenharmony_ci if (ctx->crypto_type == ARTPEC6_CRYPTO_CIPHER_AES_CTR || 17968c2ecf20Sopenharmony_ci ctx->crypto_type == ARTPEC6_CRYPTO_CIPHER_AES_XTS) { 17978c2ecf20Sopenharmony_ci size_t pad = ALIGN(areq->cryptlen, AES_BLOCK_SIZE) - 17988c2ecf20Sopenharmony_ci areq->cryptlen; 17998c2ecf20Sopenharmony_ci 18008c2ecf20Sopenharmony_ci if (pad) { 18018c2ecf20Sopenharmony_ci ret = artpec6_crypto_setup_out_descr(common, 18028c2ecf20Sopenharmony_ci ac->pad_buffer, 18038c2ecf20Sopenharmony_ci pad, false, false); 18048c2ecf20Sopenharmony_ci if (ret) 18058c2ecf20Sopenharmony_ci return ret; 18068c2ecf20Sopenharmony_ci 18078c2ecf20Sopenharmony_ci ret = artpec6_crypto_setup_in_descr(common, 18088c2ecf20Sopenharmony_ci ac->pad_buffer, pad, 18098c2ecf20Sopenharmony_ci false); 18108c2ecf20Sopenharmony_ci if (ret) 18118c2ecf20Sopenharmony_ci return ret; 18128c2ecf20Sopenharmony_ci } 18138c2ecf20Sopenharmony_ci } 18148c2ecf20Sopenharmony_ci 18158c2ecf20Sopenharmony_ci ret = artpec6_crypto_terminate_out_descrs(common); 18168c2ecf20Sopenharmony_ci if (ret) 18178c2ecf20Sopenharmony_ci return ret; 18188c2ecf20Sopenharmony_ci 18198c2ecf20Sopenharmony_ci ret = artpec6_crypto_terminate_in_descrs(common); 18208c2ecf20Sopenharmony_ci if (ret) 18218c2ecf20Sopenharmony_ci return ret; 18228c2ecf20Sopenharmony_ci 18238c2ecf20Sopenharmony_ci return artpec6_crypto_dma_map_descs(common); 18248c2ecf20Sopenharmony_ci} 18258c2ecf20Sopenharmony_ci 18268c2ecf20Sopenharmony_cistatic int artpec6_crypto_prepare_aead(struct aead_request *areq) 18278c2ecf20Sopenharmony_ci{ 18288c2ecf20Sopenharmony_ci size_t count; 18298c2ecf20Sopenharmony_ci int ret; 18308c2ecf20Sopenharmony_ci size_t input_length; 18318c2ecf20Sopenharmony_ci struct artpec6_cryptotfm_context *ctx = crypto_tfm_ctx(areq->base.tfm); 18328c2ecf20Sopenharmony_ci struct artpec6_crypto_aead_req_ctx *req_ctx = aead_request_ctx(areq); 18338c2ecf20Sopenharmony_ci struct crypto_aead *cipher = crypto_aead_reqtfm(areq); 18348c2ecf20Sopenharmony_ci struct artpec6_crypto_req_common *common = &req_ctx->common; 18358c2ecf20Sopenharmony_ci struct artpec6_crypto *ac = dev_get_drvdata(artpec6_crypto_dev); 18368c2ecf20Sopenharmony_ci enum artpec6_crypto_variant variant = ac->variant; 18378c2ecf20Sopenharmony_ci u32 md_cipher_len; 18388c2ecf20Sopenharmony_ci 18398c2ecf20Sopenharmony_ci artpec6_crypto_init_dma_operation(common); 18408c2ecf20Sopenharmony_ci 18418c2ecf20Sopenharmony_ci /* Key */ 18428c2ecf20Sopenharmony_ci if (variant == ARTPEC6_CRYPTO) { 18438c2ecf20Sopenharmony_ci ctx->key_md = FIELD_PREP(A6_CRY_MD_OPER, 18448c2ecf20Sopenharmony_ci a6_regk_crypto_dlkey); 18458c2ecf20Sopenharmony_ci } else { 18468c2ecf20Sopenharmony_ci ctx->key_md = FIELD_PREP(A7_CRY_MD_OPER, 18478c2ecf20Sopenharmony_ci a7_regk_crypto_dlkey); 18488c2ecf20Sopenharmony_ci } 18498c2ecf20Sopenharmony_ci ret = artpec6_crypto_setup_out_descr(common, (void *)&ctx->key_md, 18508c2ecf20Sopenharmony_ci sizeof(ctx->key_md), false, false); 18518c2ecf20Sopenharmony_ci if (ret) 18528c2ecf20Sopenharmony_ci return ret; 18538c2ecf20Sopenharmony_ci 18548c2ecf20Sopenharmony_ci ret = artpec6_crypto_setup_out_descr(common, ctx->aes_key, 18558c2ecf20Sopenharmony_ci ctx->key_length, true, false); 18568c2ecf20Sopenharmony_ci if (ret) 18578c2ecf20Sopenharmony_ci return ret; 18588c2ecf20Sopenharmony_ci 18598c2ecf20Sopenharmony_ci req_ctx->cipher_md = 0; 18608c2ecf20Sopenharmony_ci 18618c2ecf20Sopenharmony_ci switch (ctx->key_length) { 18628c2ecf20Sopenharmony_ci case 16: 18638c2ecf20Sopenharmony_ci md_cipher_len = regk_crypto_key_128; 18648c2ecf20Sopenharmony_ci break; 18658c2ecf20Sopenharmony_ci case 24: 18668c2ecf20Sopenharmony_ci md_cipher_len = regk_crypto_key_192; 18678c2ecf20Sopenharmony_ci break; 18688c2ecf20Sopenharmony_ci case 32: 18698c2ecf20Sopenharmony_ci md_cipher_len = regk_crypto_key_256; 18708c2ecf20Sopenharmony_ci break; 18718c2ecf20Sopenharmony_ci default: 18728c2ecf20Sopenharmony_ci return -EINVAL; 18738c2ecf20Sopenharmony_ci } 18748c2ecf20Sopenharmony_ci 18758c2ecf20Sopenharmony_ci if (variant == ARTPEC6_CRYPTO) { 18768c2ecf20Sopenharmony_ci req_ctx->cipher_md |= FIELD_PREP(A6_CRY_MD_OPER, 18778c2ecf20Sopenharmony_ci regk_crypto_aes_gcm); 18788c2ecf20Sopenharmony_ci req_ctx->cipher_md |= FIELD_PREP(A6_CRY_MD_CIPHER_LEN, 18798c2ecf20Sopenharmony_ci md_cipher_len); 18808c2ecf20Sopenharmony_ci if (req_ctx->decrypt) 18818c2ecf20Sopenharmony_ci req_ctx->cipher_md |= A6_CRY_MD_CIPHER_DECR; 18828c2ecf20Sopenharmony_ci } else { 18838c2ecf20Sopenharmony_ci req_ctx->cipher_md |= FIELD_PREP(A7_CRY_MD_OPER, 18848c2ecf20Sopenharmony_ci regk_crypto_aes_gcm); 18858c2ecf20Sopenharmony_ci req_ctx->cipher_md |= FIELD_PREP(A7_CRY_MD_CIPHER_LEN, 18868c2ecf20Sopenharmony_ci md_cipher_len); 18878c2ecf20Sopenharmony_ci if (req_ctx->decrypt) 18888c2ecf20Sopenharmony_ci req_ctx->cipher_md |= A7_CRY_MD_CIPHER_DECR; 18898c2ecf20Sopenharmony_ci } 18908c2ecf20Sopenharmony_ci 18918c2ecf20Sopenharmony_ci ret = artpec6_crypto_setup_out_descr(common, 18928c2ecf20Sopenharmony_ci (void *) &req_ctx->cipher_md, 18938c2ecf20Sopenharmony_ci sizeof(req_ctx->cipher_md), false, 18948c2ecf20Sopenharmony_ci false); 18958c2ecf20Sopenharmony_ci if (ret) 18968c2ecf20Sopenharmony_ci return ret; 18978c2ecf20Sopenharmony_ci 18988c2ecf20Sopenharmony_ci ret = artpec6_crypto_setup_in_descr(common, ac->pad_buffer, 4, false); 18998c2ecf20Sopenharmony_ci if (ret) 19008c2ecf20Sopenharmony_ci return ret; 19018c2ecf20Sopenharmony_ci 19028c2ecf20Sopenharmony_ci /* For the decryption, cryptlen includes the tag. */ 19038c2ecf20Sopenharmony_ci input_length = areq->cryptlen; 19048c2ecf20Sopenharmony_ci if (req_ctx->decrypt) 19058c2ecf20Sopenharmony_ci input_length -= crypto_aead_authsize(cipher); 19068c2ecf20Sopenharmony_ci 19078c2ecf20Sopenharmony_ci /* Prepare the context buffer */ 19088c2ecf20Sopenharmony_ci req_ctx->hw_ctx.aad_length_bits = 19098c2ecf20Sopenharmony_ci __cpu_to_be64(8*areq->assoclen); 19108c2ecf20Sopenharmony_ci 19118c2ecf20Sopenharmony_ci req_ctx->hw_ctx.text_length_bits = 19128c2ecf20Sopenharmony_ci __cpu_to_be64(8*input_length); 19138c2ecf20Sopenharmony_ci 19148c2ecf20Sopenharmony_ci memcpy(req_ctx->hw_ctx.J0, areq->iv, crypto_aead_ivsize(cipher)); 19158c2ecf20Sopenharmony_ci // The HW omits the initial increment of the counter field. 19168c2ecf20Sopenharmony_ci memcpy(req_ctx->hw_ctx.J0 + GCM_AES_IV_SIZE, "\x00\x00\x00\x01", 4); 19178c2ecf20Sopenharmony_ci 19188c2ecf20Sopenharmony_ci ret = artpec6_crypto_setup_out_descr(common, &req_ctx->hw_ctx, 19198c2ecf20Sopenharmony_ci sizeof(struct artpec6_crypto_aead_hw_ctx), false, false); 19208c2ecf20Sopenharmony_ci if (ret) 19218c2ecf20Sopenharmony_ci return ret; 19228c2ecf20Sopenharmony_ci 19238c2ecf20Sopenharmony_ci { 19248c2ecf20Sopenharmony_ci struct artpec6_crypto_walk walk; 19258c2ecf20Sopenharmony_ci 19268c2ecf20Sopenharmony_ci artpec6_crypto_walk_init(&walk, areq->src); 19278c2ecf20Sopenharmony_ci 19288c2ecf20Sopenharmony_ci /* Associated data */ 19298c2ecf20Sopenharmony_ci count = areq->assoclen; 19308c2ecf20Sopenharmony_ci ret = artpec6_crypto_setup_sg_descrs_out(common, &walk, count); 19318c2ecf20Sopenharmony_ci if (ret) 19328c2ecf20Sopenharmony_ci return ret; 19338c2ecf20Sopenharmony_ci 19348c2ecf20Sopenharmony_ci if (!IS_ALIGNED(areq->assoclen, 16)) { 19358c2ecf20Sopenharmony_ci size_t assoc_pad = 16 - (areq->assoclen % 16); 19368c2ecf20Sopenharmony_ci /* The HW mandates zero padding here */ 19378c2ecf20Sopenharmony_ci ret = artpec6_crypto_setup_out_descr(common, 19388c2ecf20Sopenharmony_ci ac->zero_buffer, 19398c2ecf20Sopenharmony_ci assoc_pad, false, 19408c2ecf20Sopenharmony_ci false); 19418c2ecf20Sopenharmony_ci if (ret) 19428c2ecf20Sopenharmony_ci return ret; 19438c2ecf20Sopenharmony_ci } 19448c2ecf20Sopenharmony_ci 19458c2ecf20Sopenharmony_ci /* Data to crypto */ 19468c2ecf20Sopenharmony_ci count = input_length; 19478c2ecf20Sopenharmony_ci ret = artpec6_crypto_setup_sg_descrs_out(common, &walk, count); 19488c2ecf20Sopenharmony_ci if (ret) 19498c2ecf20Sopenharmony_ci return ret; 19508c2ecf20Sopenharmony_ci 19518c2ecf20Sopenharmony_ci if (!IS_ALIGNED(input_length, 16)) { 19528c2ecf20Sopenharmony_ci size_t crypto_pad = 16 - (input_length % 16); 19538c2ecf20Sopenharmony_ci /* The HW mandates zero padding here */ 19548c2ecf20Sopenharmony_ci ret = artpec6_crypto_setup_out_descr(common, 19558c2ecf20Sopenharmony_ci ac->zero_buffer, 19568c2ecf20Sopenharmony_ci crypto_pad, 19578c2ecf20Sopenharmony_ci false, 19588c2ecf20Sopenharmony_ci false); 19598c2ecf20Sopenharmony_ci if (ret) 19608c2ecf20Sopenharmony_ci return ret; 19618c2ecf20Sopenharmony_ci } 19628c2ecf20Sopenharmony_ci } 19638c2ecf20Sopenharmony_ci 19648c2ecf20Sopenharmony_ci /* Data from crypto */ 19658c2ecf20Sopenharmony_ci { 19668c2ecf20Sopenharmony_ci struct artpec6_crypto_walk walk; 19678c2ecf20Sopenharmony_ci size_t output_len = areq->cryptlen; 19688c2ecf20Sopenharmony_ci 19698c2ecf20Sopenharmony_ci if (req_ctx->decrypt) 19708c2ecf20Sopenharmony_ci output_len -= crypto_aead_authsize(cipher); 19718c2ecf20Sopenharmony_ci 19728c2ecf20Sopenharmony_ci artpec6_crypto_walk_init(&walk, areq->dst); 19738c2ecf20Sopenharmony_ci 19748c2ecf20Sopenharmony_ci /* skip associated data in the output */ 19758c2ecf20Sopenharmony_ci count = artpec6_crypto_walk_advance(&walk, areq->assoclen); 19768c2ecf20Sopenharmony_ci if (count) 19778c2ecf20Sopenharmony_ci return -EINVAL; 19788c2ecf20Sopenharmony_ci 19798c2ecf20Sopenharmony_ci count = output_len; 19808c2ecf20Sopenharmony_ci ret = artpec6_crypto_setup_sg_descrs_in(common, &walk, count); 19818c2ecf20Sopenharmony_ci if (ret) 19828c2ecf20Sopenharmony_ci return ret; 19838c2ecf20Sopenharmony_ci 19848c2ecf20Sopenharmony_ci /* Put padding between the cryptotext and the auth tag */ 19858c2ecf20Sopenharmony_ci if (!IS_ALIGNED(output_len, 16)) { 19868c2ecf20Sopenharmony_ci size_t crypto_pad = 16 - (output_len % 16); 19878c2ecf20Sopenharmony_ci 19888c2ecf20Sopenharmony_ci ret = artpec6_crypto_setup_in_descr(common, 19898c2ecf20Sopenharmony_ci ac->pad_buffer, 19908c2ecf20Sopenharmony_ci crypto_pad, false); 19918c2ecf20Sopenharmony_ci if (ret) 19928c2ecf20Sopenharmony_ci return ret; 19938c2ecf20Sopenharmony_ci } 19948c2ecf20Sopenharmony_ci 19958c2ecf20Sopenharmony_ci /* The authentication tag shall follow immediately after 19968c2ecf20Sopenharmony_ci * the output ciphertext. For decryption it is put in a context 19978c2ecf20Sopenharmony_ci * buffer for later compare against the input tag. 19988c2ecf20Sopenharmony_ci */ 19998c2ecf20Sopenharmony_ci 20008c2ecf20Sopenharmony_ci if (req_ctx->decrypt) { 20018c2ecf20Sopenharmony_ci ret = artpec6_crypto_setup_in_descr(common, 20028c2ecf20Sopenharmony_ci req_ctx->decryption_tag, AES_BLOCK_SIZE, false); 20038c2ecf20Sopenharmony_ci if (ret) 20048c2ecf20Sopenharmony_ci return ret; 20058c2ecf20Sopenharmony_ci 20068c2ecf20Sopenharmony_ci } else { 20078c2ecf20Sopenharmony_ci /* For encryption the requested tag size may be smaller 20088c2ecf20Sopenharmony_ci * than the hardware's generated tag. 20098c2ecf20Sopenharmony_ci */ 20108c2ecf20Sopenharmony_ci size_t authsize = crypto_aead_authsize(cipher); 20118c2ecf20Sopenharmony_ci 20128c2ecf20Sopenharmony_ci ret = artpec6_crypto_setup_sg_descrs_in(common, &walk, 20138c2ecf20Sopenharmony_ci authsize); 20148c2ecf20Sopenharmony_ci if (ret) 20158c2ecf20Sopenharmony_ci return ret; 20168c2ecf20Sopenharmony_ci 20178c2ecf20Sopenharmony_ci if (authsize < AES_BLOCK_SIZE) { 20188c2ecf20Sopenharmony_ci count = AES_BLOCK_SIZE - authsize; 20198c2ecf20Sopenharmony_ci ret = artpec6_crypto_setup_in_descr(common, 20208c2ecf20Sopenharmony_ci ac->pad_buffer, 20218c2ecf20Sopenharmony_ci count, false); 20228c2ecf20Sopenharmony_ci if (ret) 20238c2ecf20Sopenharmony_ci return ret; 20248c2ecf20Sopenharmony_ci } 20258c2ecf20Sopenharmony_ci } 20268c2ecf20Sopenharmony_ci 20278c2ecf20Sopenharmony_ci } 20288c2ecf20Sopenharmony_ci 20298c2ecf20Sopenharmony_ci ret = artpec6_crypto_terminate_in_descrs(common); 20308c2ecf20Sopenharmony_ci if (ret) 20318c2ecf20Sopenharmony_ci return ret; 20328c2ecf20Sopenharmony_ci 20338c2ecf20Sopenharmony_ci ret = artpec6_crypto_terminate_out_descrs(common); 20348c2ecf20Sopenharmony_ci if (ret) 20358c2ecf20Sopenharmony_ci return ret; 20368c2ecf20Sopenharmony_ci 20378c2ecf20Sopenharmony_ci return artpec6_crypto_dma_map_descs(common); 20388c2ecf20Sopenharmony_ci} 20398c2ecf20Sopenharmony_ci 20408c2ecf20Sopenharmony_cistatic void artpec6_crypto_process_queue(struct artpec6_crypto *ac, 20418c2ecf20Sopenharmony_ci struct list_head *completions) 20428c2ecf20Sopenharmony_ci{ 20438c2ecf20Sopenharmony_ci struct artpec6_crypto_req_common *req; 20448c2ecf20Sopenharmony_ci 20458c2ecf20Sopenharmony_ci while (!list_empty(&ac->queue) && !artpec6_crypto_busy()) { 20468c2ecf20Sopenharmony_ci req = list_first_entry(&ac->queue, 20478c2ecf20Sopenharmony_ci struct artpec6_crypto_req_common, 20488c2ecf20Sopenharmony_ci list); 20498c2ecf20Sopenharmony_ci list_move_tail(&req->list, &ac->pending); 20508c2ecf20Sopenharmony_ci artpec6_crypto_start_dma(req); 20518c2ecf20Sopenharmony_ci 20528c2ecf20Sopenharmony_ci list_add_tail(&req->complete_in_progress, completions); 20538c2ecf20Sopenharmony_ci } 20548c2ecf20Sopenharmony_ci 20558c2ecf20Sopenharmony_ci /* 20568c2ecf20Sopenharmony_ci * In some cases, the hardware can raise an in_eop_flush interrupt 20578c2ecf20Sopenharmony_ci * before actually updating the status, so we have an timer which will 20588c2ecf20Sopenharmony_ci * recheck the status on timeout. Since the cases are expected to be 20598c2ecf20Sopenharmony_ci * very rare, we use a relatively large timeout value. There should be 20608c2ecf20Sopenharmony_ci * no noticeable negative effect if we timeout spuriously. 20618c2ecf20Sopenharmony_ci */ 20628c2ecf20Sopenharmony_ci if (ac->pending_count) 20638c2ecf20Sopenharmony_ci mod_timer(&ac->timer, jiffies + msecs_to_jiffies(100)); 20648c2ecf20Sopenharmony_ci else 20658c2ecf20Sopenharmony_ci del_timer(&ac->timer); 20668c2ecf20Sopenharmony_ci} 20678c2ecf20Sopenharmony_ci 20688c2ecf20Sopenharmony_cistatic void artpec6_crypto_timeout(struct timer_list *t) 20698c2ecf20Sopenharmony_ci{ 20708c2ecf20Sopenharmony_ci struct artpec6_crypto *ac = from_timer(ac, t, timer); 20718c2ecf20Sopenharmony_ci 20728c2ecf20Sopenharmony_ci dev_info_ratelimited(artpec6_crypto_dev, "timeout\n"); 20738c2ecf20Sopenharmony_ci 20748c2ecf20Sopenharmony_ci tasklet_schedule(&ac->task); 20758c2ecf20Sopenharmony_ci} 20768c2ecf20Sopenharmony_ci 20778c2ecf20Sopenharmony_cistatic void artpec6_crypto_task(unsigned long data) 20788c2ecf20Sopenharmony_ci{ 20798c2ecf20Sopenharmony_ci struct artpec6_crypto *ac = (struct artpec6_crypto *)data; 20808c2ecf20Sopenharmony_ci struct artpec6_crypto_req_common *req; 20818c2ecf20Sopenharmony_ci struct artpec6_crypto_req_common *n; 20828c2ecf20Sopenharmony_ci struct list_head complete_done; 20838c2ecf20Sopenharmony_ci struct list_head complete_in_progress; 20848c2ecf20Sopenharmony_ci 20858c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&complete_done); 20868c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&complete_in_progress); 20878c2ecf20Sopenharmony_ci 20888c2ecf20Sopenharmony_ci if (list_empty(&ac->pending)) { 20898c2ecf20Sopenharmony_ci pr_debug("Spurious IRQ\n"); 20908c2ecf20Sopenharmony_ci return; 20918c2ecf20Sopenharmony_ci } 20928c2ecf20Sopenharmony_ci 20938c2ecf20Sopenharmony_ci spin_lock_bh(&ac->queue_lock); 20948c2ecf20Sopenharmony_ci 20958c2ecf20Sopenharmony_ci list_for_each_entry_safe(req, n, &ac->pending, list) { 20968c2ecf20Sopenharmony_ci struct artpec6_crypto_dma_descriptors *dma = req->dma; 20978c2ecf20Sopenharmony_ci u32 stat; 20988c2ecf20Sopenharmony_ci dma_addr_t stataddr; 20998c2ecf20Sopenharmony_ci 21008c2ecf20Sopenharmony_ci stataddr = dma->stat_dma_addr + 4 * (req->dma->in_cnt - 1); 21018c2ecf20Sopenharmony_ci dma_sync_single_for_cpu(artpec6_crypto_dev, 21028c2ecf20Sopenharmony_ci stataddr, 21038c2ecf20Sopenharmony_ci 4, 21048c2ecf20Sopenharmony_ci DMA_BIDIRECTIONAL); 21058c2ecf20Sopenharmony_ci 21068c2ecf20Sopenharmony_ci stat = req->dma->stat[req->dma->in_cnt-1]; 21078c2ecf20Sopenharmony_ci 21088c2ecf20Sopenharmony_ci /* A non-zero final status descriptor indicates 21098c2ecf20Sopenharmony_ci * this job has finished. 21108c2ecf20Sopenharmony_ci */ 21118c2ecf20Sopenharmony_ci pr_debug("Request %p status is %X\n", req, stat); 21128c2ecf20Sopenharmony_ci if (!stat) 21138c2ecf20Sopenharmony_ci break; 21148c2ecf20Sopenharmony_ci 21158c2ecf20Sopenharmony_ci /* Allow testing of timeout handling with fault injection */ 21168c2ecf20Sopenharmony_ci#ifdef CONFIG_FAULT_INJECTION 21178c2ecf20Sopenharmony_ci if (should_fail(&artpec6_crypto_fail_status_read, 1)) 21188c2ecf20Sopenharmony_ci continue; 21198c2ecf20Sopenharmony_ci#endif 21208c2ecf20Sopenharmony_ci 21218c2ecf20Sopenharmony_ci pr_debug("Completing request %p\n", req); 21228c2ecf20Sopenharmony_ci 21238c2ecf20Sopenharmony_ci list_move_tail(&req->list, &complete_done); 21248c2ecf20Sopenharmony_ci 21258c2ecf20Sopenharmony_ci ac->pending_count--; 21268c2ecf20Sopenharmony_ci } 21278c2ecf20Sopenharmony_ci 21288c2ecf20Sopenharmony_ci artpec6_crypto_process_queue(ac, &complete_in_progress); 21298c2ecf20Sopenharmony_ci 21308c2ecf20Sopenharmony_ci spin_unlock_bh(&ac->queue_lock); 21318c2ecf20Sopenharmony_ci 21328c2ecf20Sopenharmony_ci /* Perform the completion callbacks without holding the queue lock 21338c2ecf20Sopenharmony_ci * to allow new request submissions from the callbacks. 21348c2ecf20Sopenharmony_ci */ 21358c2ecf20Sopenharmony_ci list_for_each_entry_safe(req, n, &complete_done, list) { 21368c2ecf20Sopenharmony_ci artpec6_crypto_dma_unmap_all(req); 21378c2ecf20Sopenharmony_ci artpec6_crypto_copy_bounce_buffers(req); 21388c2ecf20Sopenharmony_ci artpec6_crypto_common_destroy(req); 21398c2ecf20Sopenharmony_ci 21408c2ecf20Sopenharmony_ci req->complete(req->req); 21418c2ecf20Sopenharmony_ci } 21428c2ecf20Sopenharmony_ci 21438c2ecf20Sopenharmony_ci list_for_each_entry_safe(req, n, &complete_in_progress, 21448c2ecf20Sopenharmony_ci complete_in_progress) { 21458c2ecf20Sopenharmony_ci req->req->complete(req->req, -EINPROGRESS); 21468c2ecf20Sopenharmony_ci } 21478c2ecf20Sopenharmony_ci} 21488c2ecf20Sopenharmony_ci 21498c2ecf20Sopenharmony_cistatic void artpec6_crypto_complete_crypto(struct crypto_async_request *req) 21508c2ecf20Sopenharmony_ci{ 21518c2ecf20Sopenharmony_ci req->complete(req, 0); 21528c2ecf20Sopenharmony_ci} 21538c2ecf20Sopenharmony_ci 21548c2ecf20Sopenharmony_cistatic void 21558c2ecf20Sopenharmony_ciartpec6_crypto_complete_cbc_decrypt(struct crypto_async_request *req) 21568c2ecf20Sopenharmony_ci{ 21578c2ecf20Sopenharmony_ci struct skcipher_request *cipher_req = container_of(req, 21588c2ecf20Sopenharmony_ci struct skcipher_request, base); 21598c2ecf20Sopenharmony_ci 21608c2ecf20Sopenharmony_ci scatterwalk_map_and_copy(cipher_req->iv, cipher_req->src, 21618c2ecf20Sopenharmony_ci cipher_req->cryptlen - AES_BLOCK_SIZE, 21628c2ecf20Sopenharmony_ci AES_BLOCK_SIZE, 0); 21638c2ecf20Sopenharmony_ci req->complete(req, 0); 21648c2ecf20Sopenharmony_ci} 21658c2ecf20Sopenharmony_ci 21668c2ecf20Sopenharmony_cistatic void 21678c2ecf20Sopenharmony_ciartpec6_crypto_complete_cbc_encrypt(struct crypto_async_request *req) 21688c2ecf20Sopenharmony_ci{ 21698c2ecf20Sopenharmony_ci struct skcipher_request *cipher_req = container_of(req, 21708c2ecf20Sopenharmony_ci struct skcipher_request, base); 21718c2ecf20Sopenharmony_ci 21728c2ecf20Sopenharmony_ci scatterwalk_map_and_copy(cipher_req->iv, cipher_req->dst, 21738c2ecf20Sopenharmony_ci cipher_req->cryptlen - AES_BLOCK_SIZE, 21748c2ecf20Sopenharmony_ci AES_BLOCK_SIZE, 0); 21758c2ecf20Sopenharmony_ci req->complete(req, 0); 21768c2ecf20Sopenharmony_ci} 21778c2ecf20Sopenharmony_ci 21788c2ecf20Sopenharmony_cistatic void artpec6_crypto_complete_aead(struct crypto_async_request *req) 21798c2ecf20Sopenharmony_ci{ 21808c2ecf20Sopenharmony_ci int result = 0; 21818c2ecf20Sopenharmony_ci 21828c2ecf20Sopenharmony_ci /* Verify GCM hashtag. */ 21838c2ecf20Sopenharmony_ci struct aead_request *areq = container_of(req, 21848c2ecf20Sopenharmony_ci struct aead_request, base); 21858c2ecf20Sopenharmony_ci struct crypto_aead *aead = crypto_aead_reqtfm(areq); 21868c2ecf20Sopenharmony_ci struct artpec6_crypto_aead_req_ctx *req_ctx = aead_request_ctx(areq); 21878c2ecf20Sopenharmony_ci 21888c2ecf20Sopenharmony_ci if (req_ctx->decrypt) { 21898c2ecf20Sopenharmony_ci u8 input_tag[AES_BLOCK_SIZE]; 21908c2ecf20Sopenharmony_ci unsigned int authsize = crypto_aead_authsize(aead); 21918c2ecf20Sopenharmony_ci 21928c2ecf20Sopenharmony_ci sg_pcopy_to_buffer(areq->src, 21938c2ecf20Sopenharmony_ci sg_nents(areq->src), 21948c2ecf20Sopenharmony_ci input_tag, 21958c2ecf20Sopenharmony_ci authsize, 21968c2ecf20Sopenharmony_ci areq->assoclen + areq->cryptlen - 21978c2ecf20Sopenharmony_ci authsize); 21988c2ecf20Sopenharmony_ci 21998c2ecf20Sopenharmony_ci if (crypto_memneq(req_ctx->decryption_tag, 22008c2ecf20Sopenharmony_ci input_tag, 22018c2ecf20Sopenharmony_ci authsize)) { 22028c2ecf20Sopenharmony_ci pr_debug("***EBADMSG:\n"); 22038c2ecf20Sopenharmony_ci print_hex_dump_debug("ref:", DUMP_PREFIX_ADDRESS, 32, 1, 22048c2ecf20Sopenharmony_ci input_tag, authsize, true); 22058c2ecf20Sopenharmony_ci print_hex_dump_debug("out:", DUMP_PREFIX_ADDRESS, 32, 1, 22068c2ecf20Sopenharmony_ci req_ctx->decryption_tag, 22078c2ecf20Sopenharmony_ci authsize, true); 22088c2ecf20Sopenharmony_ci 22098c2ecf20Sopenharmony_ci result = -EBADMSG; 22108c2ecf20Sopenharmony_ci } 22118c2ecf20Sopenharmony_ci } 22128c2ecf20Sopenharmony_ci 22138c2ecf20Sopenharmony_ci req->complete(req, result); 22148c2ecf20Sopenharmony_ci} 22158c2ecf20Sopenharmony_ci 22168c2ecf20Sopenharmony_cistatic void artpec6_crypto_complete_hash(struct crypto_async_request *req) 22178c2ecf20Sopenharmony_ci{ 22188c2ecf20Sopenharmony_ci req->complete(req, 0); 22198c2ecf20Sopenharmony_ci} 22208c2ecf20Sopenharmony_ci 22218c2ecf20Sopenharmony_ci 22228c2ecf20Sopenharmony_ci/*------------------- Hash functions -----------------------------------------*/ 22238c2ecf20Sopenharmony_cistatic int 22248c2ecf20Sopenharmony_ciartpec6_crypto_hash_set_key(struct crypto_ahash *tfm, 22258c2ecf20Sopenharmony_ci const u8 *key, unsigned int keylen) 22268c2ecf20Sopenharmony_ci{ 22278c2ecf20Sopenharmony_ci struct artpec6_hashalg_context *tfm_ctx = crypto_tfm_ctx(&tfm->base); 22288c2ecf20Sopenharmony_ci size_t blocksize; 22298c2ecf20Sopenharmony_ci int ret; 22308c2ecf20Sopenharmony_ci 22318c2ecf20Sopenharmony_ci if (!keylen) { 22328c2ecf20Sopenharmony_ci pr_err("Invalid length (%d) of HMAC key\n", 22338c2ecf20Sopenharmony_ci keylen); 22348c2ecf20Sopenharmony_ci return -EINVAL; 22358c2ecf20Sopenharmony_ci } 22368c2ecf20Sopenharmony_ci 22378c2ecf20Sopenharmony_ci memset(tfm_ctx->hmac_key, 0, sizeof(tfm_ctx->hmac_key)); 22388c2ecf20Sopenharmony_ci 22398c2ecf20Sopenharmony_ci blocksize = crypto_tfm_alg_blocksize(crypto_ahash_tfm(tfm)); 22408c2ecf20Sopenharmony_ci 22418c2ecf20Sopenharmony_ci if (keylen > blocksize) { 22428c2ecf20Sopenharmony_ci tfm_ctx->hmac_key_length = blocksize; 22438c2ecf20Sopenharmony_ci 22448c2ecf20Sopenharmony_ci ret = crypto_shash_tfm_digest(tfm_ctx->child_hash, key, keylen, 22458c2ecf20Sopenharmony_ci tfm_ctx->hmac_key); 22468c2ecf20Sopenharmony_ci if (ret) 22478c2ecf20Sopenharmony_ci return ret; 22488c2ecf20Sopenharmony_ci } else { 22498c2ecf20Sopenharmony_ci memcpy(tfm_ctx->hmac_key, key, keylen); 22508c2ecf20Sopenharmony_ci tfm_ctx->hmac_key_length = keylen; 22518c2ecf20Sopenharmony_ci } 22528c2ecf20Sopenharmony_ci 22538c2ecf20Sopenharmony_ci return 0; 22548c2ecf20Sopenharmony_ci} 22558c2ecf20Sopenharmony_ci 22568c2ecf20Sopenharmony_cistatic int 22578c2ecf20Sopenharmony_ciartpec6_crypto_init_hash(struct ahash_request *req, u8 type, int hmac) 22588c2ecf20Sopenharmony_ci{ 22598c2ecf20Sopenharmony_ci struct artpec6_crypto *ac = dev_get_drvdata(artpec6_crypto_dev); 22608c2ecf20Sopenharmony_ci enum artpec6_crypto_variant variant = ac->variant; 22618c2ecf20Sopenharmony_ci struct artpec6_hash_request_context *req_ctx = ahash_request_ctx(req); 22628c2ecf20Sopenharmony_ci u32 oper; 22638c2ecf20Sopenharmony_ci 22648c2ecf20Sopenharmony_ci memset(req_ctx, 0, sizeof(*req_ctx)); 22658c2ecf20Sopenharmony_ci 22668c2ecf20Sopenharmony_ci req_ctx->hash_flags = HASH_FLAG_INIT_CTX; 22678c2ecf20Sopenharmony_ci if (hmac) 22688c2ecf20Sopenharmony_ci req_ctx->hash_flags |= (HASH_FLAG_HMAC | HASH_FLAG_UPDATE_KEY); 22698c2ecf20Sopenharmony_ci 22708c2ecf20Sopenharmony_ci switch (type) { 22718c2ecf20Sopenharmony_ci case ARTPEC6_CRYPTO_HASH_SHA1: 22728c2ecf20Sopenharmony_ci oper = hmac ? regk_crypto_hmac_sha1 : regk_crypto_sha1; 22738c2ecf20Sopenharmony_ci break; 22748c2ecf20Sopenharmony_ci case ARTPEC6_CRYPTO_HASH_SHA256: 22758c2ecf20Sopenharmony_ci oper = hmac ? regk_crypto_hmac_sha256 : regk_crypto_sha256; 22768c2ecf20Sopenharmony_ci break; 22778c2ecf20Sopenharmony_ci default: 22788c2ecf20Sopenharmony_ci pr_err("%s: Unsupported hash type 0x%x\n", MODULE_NAME, type); 22798c2ecf20Sopenharmony_ci return -EINVAL; 22808c2ecf20Sopenharmony_ci } 22818c2ecf20Sopenharmony_ci 22828c2ecf20Sopenharmony_ci if (variant == ARTPEC6_CRYPTO) 22838c2ecf20Sopenharmony_ci req_ctx->hash_md = FIELD_PREP(A6_CRY_MD_OPER, oper); 22848c2ecf20Sopenharmony_ci else 22858c2ecf20Sopenharmony_ci req_ctx->hash_md = FIELD_PREP(A7_CRY_MD_OPER, oper); 22868c2ecf20Sopenharmony_ci 22878c2ecf20Sopenharmony_ci return 0; 22888c2ecf20Sopenharmony_ci} 22898c2ecf20Sopenharmony_ci 22908c2ecf20Sopenharmony_cistatic int artpec6_crypto_prepare_submit_hash(struct ahash_request *req) 22918c2ecf20Sopenharmony_ci{ 22928c2ecf20Sopenharmony_ci struct artpec6_hash_request_context *req_ctx = ahash_request_ctx(req); 22938c2ecf20Sopenharmony_ci int ret; 22948c2ecf20Sopenharmony_ci 22958c2ecf20Sopenharmony_ci if (!req_ctx->common.dma) { 22968c2ecf20Sopenharmony_ci ret = artpec6_crypto_common_init(&req_ctx->common, 22978c2ecf20Sopenharmony_ci &req->base, 22988c2ecf20Sopenharmony_ci artpec6_crypto_complete_hash, 22998c2ecf20Sopenharmony_ci NULL, 0); 23008c2ecf20Sopenharmony_ci 23018c2ecf20Sopenharmony_ci if (ret) 23028c2ecf20Sopenharmony_ci return ret; 23038c2ecf20Sopenharmony_ci } 23048c2ecf20Sopenharmony_ci 23058c2ecf20Sopenharmony_ci ret = artpec6_crypto_prepare_hash(req); 23068c2ecf20Sopenharmony_ci switch (ret) { 23078c2ecf20Sopenharmony_ci case ARTPEC6_CRYPTO_PREPARE_HASH_START: 23088c2ecf20Sopenharmony_ci ret = artpec6_crypto_submit(&req_ctx->common); 23098c2ecf20Sopenharmony_ci break; 23108c2ecf20Sopenharmony_ci 23118c2ecf20Sopenharmony_ci case ARTPEC6_CRYPTO_PREPARE_HASH_NO_START: 23128c2ecf20Sopenharmony_ci ret = 0; 23138c2ecf20Sopenharmony_ci fallthrough; 23148c2ecf20Sopenharmony_ci 23158c2ecf20Sopenharmony_ci default: 23168c2ecf20Sopenharmony_ci artpec6_crypto_common_destroy(&req_ctx->common); 23178c2ecf20Sopenharmony_ci break; 23188c2ecf20Sopenharmony_ci } 23198c2ecf20Sopenharmony_ci 23208c2ecf20Sopenharmony_ci return ret; 23218c2ecf20Sopenharmony_ci} 23228c2ecf20Sopenharmony_ci 23238c2ecf20Sopenharmony_cistatic int artpec6_crypto_hash_final(struct ahash_request *req) 23248c2ecf20Sopenharmony_ci{ 23258c2ecf20Sopenharmony_ci struct artpec6_hash_request_context *req_ctx = ahash_request_ctx(req); 23268c2ecf20Sopenharmony_ci 23278c2ecf20Sopenharmony_ci req_ctx->hash_flags |= HASH_FLAG_FINALIZE; 23288c2ecf20Sopenharmony_ci 23298c2ecf20Sopenharmony_ci return artpec6_crypto_prepare_submit_hash(req); 23308c2ecf20Sopenharmony_ci} 23318c2ecf20Sopenharmony_ci 23328c2ecf20Sopenharmony_cistatic int artpec6_crypto_hash_update(struct ahash_request *req) 23338c2ecf20Sopenharmony_ci{ 23348c2ecf20Sopenharmony_ci struct artpec6_hash_request_context *req_ctx = ahash_request_ctx(req); 23358c2ecf20Sopenharmony_ci 23368c2ecf20Sopenharmony_ci req_ctx->hash_flags |= HASH_FLAG_UPDATE; 23378c2ecf20Sopenharmony_ci 23388c2ecf20Sopenharmony_ci return artpec6_crypto_prepare_submit_hash(req); 23398c2ecf20Sopenharmony_ci} 23408c2ecf20Sopenharmony_ci 23418c2ecf20Sopenharmony_cistatic int artpec6_crypto_sha1_init(struct ahash_request *req) 23428c2ecf20Sopenharmony_ci{ 23438c2ecf20Sopenharmony_ci return artpec6_crypto_init_hash(req, ARTPEC6_CRYPTO_HASH_SHA1, 0); 23448c2ecf20Sopenharmony_ci} 23458c2ecf20Sopenharmony_ci 23468c2ecf20Sopenharmony_cistatic int artpec6_crypto_sha1_digest(struct ahash_request *req) 23478c2ecf20Sopenharmony_ci{ 23488c2ecf20Sopenharmony_ci struct artpec6_hash_request_context *req_ctx = ahash_request_ctx(req); 23498c2ecf20Sopenharmony_ci 23508c2ecf20Sopenharmony_ci artpec6_crypto_init_hash(req, ARTPEC6_CRYPTO_HASH_SHA1, 0); 23518c2ecf20Sopenharmony_ci 23528c2ecf20Sopenharmony_ci req_ctx->hash_flags |= HASH_FLAG_UPDATE | HASH_FLAG_FINALIZE; 23538c2ecf20Sopenharmony_ci 23548c2ecf20Sopenharmony_ci return artpec6_crypto_prepare_submit_hash(req); 23558c2ecf20Sopenharmony_ci} 23568c2ecf20Sopenharmony_ci 23578c2ecf20Sopenharmony_cistatic int artpec6_crypto_sha256_init(struct ahash_request *req) 23588c2ecf20Sopenharmony_ci{ 23598c2ecf20Sopenharmony_ci return artpec6_crypto_init_hash(req, ARTPEC6_CRYPTO_HASH_SHA256, 0); 23608c2ecf20Sopenharmony_ci} 23618c2ecf20Sopenharmony_ci 23628c2ecf20Sopenharmony_cistatic int artpec6_crypto_sha256_digest(struct ahash_request *req) 23638c2ecf20Sopenharmony_ci{ 23648c2ecf20Sopenharmony_ci struct artpec6_hash_request_context *req_ctx = ahash_request_ctx(req); 23658c2ecf20Sopenharmony_ci 23668c2ecf20Sopenharmony_ci artpec6_crypto_init_hash(req, ARTPEC6_CRYPTO_HASH_SHA256, 0); 23678c2ecf20Sopenharmony_ci req_ctx->hash_flags |= HASH_FLAG_UPDATE | HASH_FLAG_FINALIZE; 23688c2ecf20Sopenharmony_ci 23698c2ecf20Sopenharmony_ci return artpec6_crypto_prepare_submit_hash(req); 23708c2ecf20Sopenharmony_ci} 23718c2ecf20Sopenharmony_ci 23728c2ecf20Sopenharmony_cistatic int artpec6_crypto_hmac_sha256_init(struct ahash_request *req) 23738c2ecf20Sopenharmony_ci{ 23748c2ecf20Sopenharmony_ci return artpec6_crypto_init_hash(req, ARTPEC6_CRYPTO_HASH_SHA256, 1); 23758c2ecf20Sopenharmony_ci} 23768c2ecf20Sopenharmony_ci 23778c2ecf20Sopenharmony_cistatic int artpec6_crypto_hmac_sha256_digest(struct ahash_request *req) 23788c2ecf20Sopenharmony_ci{ 23798c2ecf20Sopenharmony_ci struct artpec6_hash_request_context *req_ctx = ahash_request_ctx(req); 23808c2ecf20Sopenharmony_ci 23818c2ecf20Sopenharmony_ci artpec6_crypto_init_hash(req, ARTPEC6_CRYPTO_HASH_SHA256, 1); 23828c2ecf20Sopenharmony_ci req_ctx->hash_flags |= HASH_FLAG_UPDATE | HASH_FLAG_FINALIZE; 23838c2ecf20Sopenharmony_ci 23848c2ecf20Sopenharmony_ci return artpec6_crypto_prepare_submit_hash(req); 23858c2ecf20Sopenharmony_ci} 23868c2ecf20Sopenharmony_ci 23878c2ecf20Sopenharmony_cistatic int artpec6_crypto_ahash_init_common(struct crypto_tfm *tfm, 23888c2ecf20Sopenharmony_ci const char *base_hash_name) 23898c2ecf20Sopenharmony_ci{ 23908c2ecf20Sopenharmony_ci struct artpec6_hashalg_context *tfm_ctx = crypto_tfm_ctx(tfm); 23918c2ecf20Sopenharmony_ci 23928c2ecf20Sopenharmony_ci crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm), 23938c2ecf20Sopenharmony_ci sizeof(struct artpec6_hash_request_context)); 23948c2ecf20Sopenharmony_ci memset(tfm_ctx, 0, sizeof(*tfm_ctx)); 23958c2ecf20Sopenharmony_ci 23968c2ecf20Sopenharmony_ci if (base_hash_name) { 23978c2ecf20Sopenharmony_ci struct crypto_shash *child; 23988c2ecf20Sopenharmony_ci 23998c2ecf20Sopenharmony_ci child = crypto_alloc_shash(base_hash_name, 0, 24008c2ecf20Sopenharmony_ci CRYPTO_ALG_NEED_FALLBACK); 24018c2ecf20Sopenharmony_ci 24028c2ecf20Sopenharmony_ci if (IS_ERR(child)) 24038c2ecf20Sopenharmony_ci return PTR_ERR(child); 24048c2ecf20Sopenharmony_ci 24058c2ecf20Sopenharmony_ci tfm_ctx->child_hash = child; 24068c2ecf20Sopenharmony_ci } 24078c2ecf20Sopenharmony_ci 24088c2ecf20Sopenharmony_ci return 0; 24098c2ecf20Sopenharmony_ci} 24108c2ecf20Sopenharmony_ci 24118c2ecf20Sopenharmony_cistatic int artpec6_crypto_ahash_init(struct crypto_tfm *tfm) 24128c2ecf20Sopenharmony_ci{ 24138c2ecf20Sopenharmony_ci return artpec6_crypto_ahash_init_common(tfm, NULL); 24148c2ecf20Sopenharmony_ci} 24158c2ecf20Sopenharmony_ci 24168c2ecf20Sopenharmony_cistatic int artpec6_crypto_ahash_init_hmac_sha256(struct crypto_tfm *tfm) 24178c2ecf20Sopenharmony_ci{ 24188c2ecf20Sopenharmony_ci return artpec6_crypto_ahash_init_common(tfm, "sha256"); 24198c2ecf20Sopenharmony_ci} 24208c2ecf20Sopenharmony_ci 24218c2ecf20Sopenharmony_cistatic void artpec6_crypto_ahash_exit(struct crypto_tfm *tfm) 24228c2ecf20Sopenharmony_ci{ 24238c2ecf20Sopenharmony_ci struct artpec6_hashalg_context *tfm_ctx = crypto_tfm_ctx(tfm); 24248c2ecf20Sopenharmony_ci 24258c2ecf20Sopenharmony_ci if (tfm_ctx->child_hash) 24268c2ecf20Sopenharmony_ci crypto_free_shash(tfm_ctx->child_hash); 24278c2ecf20Sopenharmony_ci 24288c2ecf20Sopenharmony_ci memset(tfm_ctx->hmac_key, 0, sizeof(tfm_ctx->hmac_key)); 24298c2ecf20Sopenharmony_ci tfm_ctx->hmac_key_length = 0; 24308c2ecf20Sopenharmony_ci} 24318c2ecf20Sopenharmony_ci 24328c2ecf20Sopenharmony_cistatic int artpec6_crypto_hash_export(struct ahash_request *req, void *out) 24338c2ecf20Sopenharmony_ci{ 24348c2ecf20Sopenharmony_ci const struct artpec6_hash_request_context *ctx = ahash_request_ctx(req); 24358c2ecf20Sopenharmony_ci struct artpec6_hash_export_state *state = out; 24368c2ecf20Sopenharmony_ci struct artpec6_crypto *ac = dev_get_drvdata(artpec6_crypto_dev); 24378c2ecf20Sopenharmony_ci enum artpec6_crypto_variant variant = ac->variant; 24388c2ecf20Sopenharmony_ci 24398c2ecf20Sopenharmony_ci BUILD_BUG_ON(sizeof(state->partial_buffer) != 24408c2ecf20Sopenharmony_ci sizeof(ctx->partial_buffer)); 24418c2ecf20Sopenharmony_ci BUILD_BUG_ON(sizeof(state->digeststate) != sizeof(ctx->digeststate)); 24428c2ecf20Sopenharmony_ci 24438c2ecf20Sopenharmony_ci state->digcnt = ctx->digcnt; 24448c2ecf20Sopenharmony_ci state->partial_bytes = ctx->partial_bytes; 24458c2ecf20Sopenharmony_ci state->hash_flags = ctx->hash_flags; 24468c2ecf20Sopenharmony_ci 24478c2ecf20Sopenharmony_ci if (variant == ARTPEC6_CRYPTO) 24488c2ecf20Sopenharmony_ci state->oper = FIELD_GET(A6_CRY_MD_OPER, ctx->hash_md); 24498c2ecf20Sopenharmony_ci else 24508c2ecf20Sopenharmony_ci state->oper = FIELD_GET(A7_CRY_MD_OPER, ctx->hash_md); 24518c2ecf20Sopenharmony_ci 24528c2ecf20Sopenharmony_ci memcpy(state->partial_buffer, ctx->partial_buffer, 24538c2ecf20Sopenharmony_ci sizeof(state->partial_buffer)); 24548c2ecf20Sopenharmony_ci memcpy(state->digeststate, ctx->digeststate, 24558c2ecf20Sopenharmony_ci sizeof(state->digeststate)); 24568c2ecf20Sopenharmony_ci 24578c2ecf20Sopenharmony_ci return 0; 24588c2ecf20Sopenharmony_ci} 24598c2ecf20Sopenharmony_ci 24608c2ecf20Sopenharmony_cistatic int artpec6_crypto_hash_import(struct ahash_request *req, const void *in) 24618c2ecf20Sopenharmony_ci{ 24628c2ecf20Sopenharmony_ci struct artpec6_hash_request_context *ctx = ahash_request_ctx(req); 24638c2ecf20Sopenharmony_ci const struct artpec6_hash_export_state *state = in; 24648c2ecf20Sopenharmony_ci struct artpec6_crypto *ac = dev_get_drvdata(artpec6_crypto_dev); 24658c2ecf20Sopenharmony_ci enum artpec6_crypto_variant variant = ac->variant; 24668c2ecf20Sopenharmony_ci 24678c2ecf20Sopenharmony_ci memset(ctx, 0, sizeof(*ctx)); 24688c2ecf20Sopenharmony_ci 24698c2ecf20Sopenharmony_ci ctx->digcnt = state->digcnt; 24708c2ecf20Sopenharmony_ci ctx->partial_bytes = state->partial_bytes; 24718c2ecf20Sopenharmony_ci ctx->hash_flags = state->hash_flags; 24728c2ecf20Sopenharmony_ci 24738c2ecf20Sopenharmony_ci if (variant == ARTPEC6_CRYPTO) 24748c2ecf20Sopenharmony_ci ctx->hash_md = FIELD_PREP(A6_CRY_MD_OPER, state->oper); 24758c2ecf20Sopenharmony_ci else 24768c2ecf20Sopenharmony_ci ctx->hash_md = FIELD_PREP(A7_CRY_MD_OPER, state->oper); 24778c2ecf20Sopenharmony_ci 24788c2ecf20Sopenharmony_ci memcpy(ctx->partial_buffer, state->partial_buffer, 24798c2ecf20Sopenharmony_ci sizeof(state->partial_buffer)); 24808c2ecf20Sopenharmony_ci memcpy(ctx->digeststate, state->digeststate, 24818c2ecf20Sopenharmony_ci sizeof(state->digeststate)); 24828c2ecf20Sopenharmony_ci 24838c2ecf20Sopenharmony_ci return 0; 24848c2ecf20Sopenharmony_ci} 24858c2ecf20Sopenharmony_ci 24868c2ecf20Sopenharmony_cistatic int init_crypto_hw(struct artpec6_crypto *ac) 24878c2ecf20Sopenharmony_ci{ 24888c2ecf20Sopenharmony_ci enum artpec6_crypto_variant variant = ac->variant; 24898c2ecf20Sopenharmony_ci void __iomem *base = ac->base; 24908c2ecf20Sopenharmony_ci u32 out_descr_buf_size; 24918c2ecf20Sopenharmony_ci u32 out_data_buf_size; 24928c2ecf20Sopenharmony_ci u32 in_data_buf_size; 24938c2ecf20Sopenharmony_ci u32 in_descr_buf_size; 24948c2ecf20Sopenharmony_ci u32 in_stat_buf_size; 24958c2ecf20Sopenharmony_ci u32 in, out; 24968c2ecf20Sopenharmony_ci 24978c2ecf20Sopenharmony_ci /* 24988c2ecf20Sopenharmony_ci * The PDMA unit contains 1984 bytes of internal memory for the OUT 24998c2ecf20Sopenharmony_ci * channels and 1024 bytes for the IN channel. This is an elastic 25008c2ecf20Sopenharmony_ci * memory used to internally store the descriptors and data. The values 25018c2ecf20Sopenharmony_ci * ares specified in 64 byte incremements. Trustzone buffers are not 25028c2ecf20Sopenharmony_ci * used at this stage. 25038c2ecf20Sopenharmony_ci */ 25048c2ecf20Sopenharmony_ci out_data_buf_size = 16; /* 1024 bytes for data */ 25058c2ecf20Sopenharmony_ci out_descr_buf_size = 15; /* 960 bytes for descriptors */ 25068c2ecf20Sopenharmony_ci in_data_buf_size = 8; /* 512 bytes for data */ 25078c2ecf20Sopenharmony_ci in_descr_buf_size = 4; /* 256 bytes for descriptors */ 25088c2ecf20Sopenharmony_ci in_stat_buf_size = 4; /* 256 bytes for stat descrs */ 25098c2ecf20Sopenharmony_ci 25108c2ecf20Sopenharmony_ci BUILD_BUG_ON_MSG((out_data_buf_size 25118c2ecf20Sopenharmony_ci + out_descr_buf_size) * 64 > 1984, 25128c2ecf20Sopenharmony_ci "Invalid OUT configuration"); 25138c2ecf20Sopenharmony_ci 25148c2ecf20Sopenharmony_ci BUILD_BUG_ON_MSG((in_data_buf_size 25158c2ecf20Sopenharmony_ci + in_descr_buf_size 25168c2ecf20Sopenharmony_ci + in_stat_buf_size) * 64 > 1024, 25178c2ecf20Sopenharmony_ci "Invalid IN configuration"); 25188c2ecf20Sopenharmony_ci 25198c2ecf20Sopenharmony_ci in = FIELD_PREP(PDMA_IN_BUF_CFG_DATA_BUF_SIZE, in_data_buf_size) | 25208c2ecf20Sopenharmony_ci FIELD_PREP(PDMA_IN_BUF_CFG_DESCR_BUF_SIZE, in_descr_buf_size) | 25218c2ecf20Sopenharmony_ci FIELD_PREP(PDMA_IN_BUF_CFG_STAT_BUF_SIZE, in_stat_buf_size); 25228c2ecf20Sopenharmony_ci 25238c2ecf20Sopenharmony_ci out = FIELD_PREP(PDMA_OUT_BUF_CFG_DATA_BUF_SIZE, out_data_buf_size) | 25248c2ecf20Sopenharmony_ci FIELD_PREP(PDMA_OUT_BUF_CFG_DESCR_BUF_SIZE, out_descr_buf_size); 25258c2ecf20Sopenharmony_ci 25268c2ecf20Sopenharmony_ci writel_relaxed(out, base + PDMA_OUT_BUF_CFG); 25278c2ecf20Sopenharmony_ci writel_relaxed(PDMA_OUT_CFG_EN, base + PDMA_OUT_CFG); 25288c2ecf20Sopenharmony_ci 25298c2ecf20Sopenharmony_ci if (variant == ARTPEC6_CRYPTO) { 25308c2ecf20Sopenharmony_ci writel_relaxed(in, base + A6_PDMA_IN_BUF_CFG); 25318c2ecf20Sopenharmony_ci writel_relaxed(PDMA_IN_CFG_EN, base + A6_PDMA_IN_CFG); 25328c2ecf20Sopenharmony_ci writel_relaxed(A6_PDMA_INTR_MASK_IN_DATA | 25338c2ecf20Sopenharmony_ci A6_PDMA_INTR_MASK_IN_EOP_FLUSH, 25348c2ecf20Sopenharmony_ci base + A6_PDMA_INTR_MASK); 25358c2ecf20Sopenharmony_ci } else { 25368c2ecf20Sopenharmony_ci writel_relaxed(in, base + A7_PDMA_IN_BUF_CFG); 25378c2ecf20Sopenharmony_ci writel_relaxed(PDMA_IN_CFG_EN, base + A7_PDMA_IN_CFG); 25388c2ecf20Sopenharmony_ci writel_relaxed(A7_PDMA_INTR_MASK_IN_DATA | 25398c2ecf20Sopenharmony_ci A7_PDMA_INTR_MASK_IN_EOP_FLUSH, 25408c2ecf20Sopenharmony_ci base + A7_PDMA_INTR_MASK); 25418c2ecf20Sopenharmony_ci } 25428c2ecf20Sopenharmony_ci 25438c2ecf20Sopenharmony_ci return 0; 25448c2ecf20Sopenharmony_ci} 25458c2ecf20Sopenharmony_ci 25468c2ecf20Sopenharmony_cistatic void artpec6_crypto_disable_hw(struct artpec6_crypto *ac) 25478c2ecf20Sopenharmony_ci{ 25488c2ecf20Sopenharmony_ci enum artpec6_crypto_variant variant = ac->variant; 25498c2ecf20Sopenharmony_ci void __iomem *base = ac->base; 25508c2ecf20Sopenharmony_ci 25518c2ecf20Sopenharmony_ci if (variant == ARTPEC6_CRYPTO) { 25528c2ecf20Sopenharmony_ci writel_relaxed(A6_PDMA_IN_CMD_STOP, base + A6_PDMA_IN_CMD); 25538c2ecf20Sopenharmony_ci writel_relaxed(0, base + A6_PDMA_IN_CFG); 25548c2ecf20Sopenharmony_ci writel_relaxed(A6_PDMA_OUT_CMD_STOP, base + PDMA_OUT_CMD); 25558c2ecf20Sopenharmony_ci } else { 25568c2ecf20Sopenharmony_ci writel_relaxed(A7_PDMA_IN_CMD_STOP, base + A7_PDMA_IN_CMD); 25578c2ecf20Sopenharmony_ci writel_relaxed(0, base + A7_PDMA_IN_CFG); 25588c2ecf20Sopenharmony_ci writel_relaxed(A7_PDMA_OUT_CMD_STOP, base + PDMA_OUT_CMD); 25598c2ecf20Sopenharmony_ci } 25608c2ecf20Sopenharmony_ci 25618c2ecf20Sopenharmony_ci writel_relaxed(0, base + PDMA_OUT_CFG); 25628c2ecf20Sopenharmony_ci 25638c2ecf20Sopenharmony_ci} 25648c2ecf20Sopenharmony_ci 25658c2ecf20Sopenharmony_cistatic irqreturn_t artpec6_crypto_irq(int irq, void *dev_id) 25668c2ecf20Sopenharmony_ci{ 25678c2ecf20Sopenharmony_ci struct artpec6_crypto *ac = dev_id; 25688c2ecf20Sopenharmony_ci enum artpec6_crypto_variant variant = ac->variant; 25698c2ecf20Sopenharmony_ci void __iomem *base = ac->base; 25708c2ecf20Sopenharmony_ci u32 mask_in_data, mask_in_eop_flush; 25718c2ecf20Sopenharmony_ci u32 in_cmd_flush_stat, in_cmd_reg; 25728c2ecf20Sopenharmony_ci u32 ack_intr_reg; 25738c2ecf20Sopenharmony_ci u32 ack = 0; 25748c2ecf20Sopenharmony_ci u32 intr; 25758c2ecf20Sopenharmony_ci 25768c2ecf20Sopenharmony_ci if (variant == ARTPEC6_CRYPTO) { 25778c2ecf20Sopenharmony_ci intr = readl_relaxed(base + A6_PDMA_MASKED_INTR); 25788c2ecf20Sopenharmony_ci mask_in_data = A6_PDMA_INTR_MASK_IN_DATA; 25798c2ecf20Sopenharmony_ci mask_in_eop_flush = A6_PDMA_INTR_MASK_IN_EOP_FLUSH; 25808c2ecf20Sopenharmony_ci in_cmd_flush_stat = A6_PDMA_IN_CMD_FLUSH_STAT; 25818c2ecf20Sopenharmony_ci in_cmd_reg = A6_PDMA_IN_CMD; 25828c2ecf20Sopenharmony_ci ack_intr_reg = A6_PDMA_ACK_INTR; 25838c2ecf20Sopenharmony_ci } else { 25848c2ecf20Sopenharmony_ci intr = readl_relaxed(base + A7_PDMA_MASKED_INTR); 25858c2ecf20Sopenharmony_ci mask_in_data = A7_PDMA_INTR_MASK_IN_DATA; 25868c2ecf20Sopenharmony_ci mask_in_eop_flush = A7_PDMA_INTR_MASK_IN_EOP_FLUSH; 25878c2ecf20Sopenharmony_ci in_cmd_flush_stat = A7_PDMA_IN_CMD_FLUSH_STAT; 25888c2ecf20Sopenharmony_ci in_cmd_reg = A7_PDMA_IN_CMD; 25898c2ecf20Sopenharmony_ci ack_intr_reg = A7_PDMA_ACK_INTR; 25908c2ecf20Sopenharmony_ci } 25918c2ecf20Sopenharmony_ci 25928c2ecf20Sopenharmony_ci /* We get two interrupt notifications from each job. 25938c2ecf20Sopenharmony_ci * The in_data means all data was sent to memory and then 25948c2ecf20Sopenharmony_ci * we request a status flush command to write the per-job 25958c2ecf20Sopenharmony_ci * status to its status vector. This ensures that the 25968c2ecf20Sopenharmony_ci * tasklet can detect exactly how many submitted jobs 25978c2ecf20Sopenharmony_ci * that have finished. 25988c2ecf20Sopenharmony_ci */ 25998c2ecf20Sopenharmony_ci if (intr & mask_in_data) 26008c2ecf20Sopenharmony_ci ack |= mask_in_data; 26018c2ecf20Sopenharmony_ci 26028c2ecf20Sopenharmony_ci if (intr & mask_in_eop_flush) 26038c2ecf20Sopenharmony_ci ack |= mask_in_eop_flush; 26048c2ecf20Sopenharmony_ci else 26058c2ecf20Sopenharmony_ci writel_relaxed(in_cmd_flush_stat, base + in_cmd_reg); 26068c2ecf20Sopenharmony_ci 26078c2ecf20Sopenharmony_ci writel_relaxed(ack, base + ack_intr_reg); 26088c2ecf20Sopenharmony_ci 26098c2ecf20Sopenharmony_ci if (intr & mask_in_eop_flush) 26108c2ecf20Sopenharmony_ci tasklet_schedule(&ac->task); 26118c2ecf20Sopenharmony_ci 26128c2ecf20Sopenharmony_ci return IRQ_HANDLED; 26138c2ecf20Sopenharmony_ci} 26148c2ecf20Sopenharmony_ci 26158c2ecf20Sopenharmony_ci/*------------------- Algorithm definitions ----------------------------------*/ 26168c2ecf20Sopenharmony_ci 26178c2ecf20Sopenharmony_ci/* Hashes */ 26188c2ecf20Sopenharmony_cistatic struct ahash_alg hash_algos[] = { 26198c2ecf20Sopenharmony_ci /* SHA-1 */ 26208c2ecf20Sopenharmony_ci { 26218c2ecf20Sopenharmony_ci .init = artpec6_crypto_sha1_init, 26228c2ecf20Sopenharmony_ci .update = artpec6_crypto_hash_update, 26238c2ecf20Sopenharmony_ci .final = artpec6_crypto_hash_final, 26248c2ecf20Sopenharmony_ci .digest = artpec6_crypto_sha1_digest, 26258c2ecf20Sopenharmony_ci .import = artpec6_crypto_hash_import, 26268c2ecf20Sopenharmony_ci .export = artpec6_crypto_hash_export, 26278c2ecf20Sopenharmony_ci .halg.digestsize = SHA1_DIGEST_SIZE, 26288c2ecf20Sopenharmony_ci .halg.statesize = sizeof(struct artpec6_hash_export_state), 26298c2ecf20Sopenharmony_ci .halg.base = { 26308c2ecf20Sopenharmony_ci .cra_name = "sha1", 26318c2ecf20Sopenharmony_ci .cra_driver_name = "artpec-sha1", 26328c2ecf20Sopenharmony_ci .cra_priority = 300, 26338c2ecf20Sopenharmony_ci .cra_flags = CRYPTO_ALG_ASYNC | 26348c2ecf20Sopenharmony_ci CRYPTO_ALG_ALLOCATES_MEMORY, 26358c2ecf20Sopenharmony_ci .cra_blocksize = SHA1_BLOCK_SIZE, 26368c2ecf20Sopenharmony_ci .cra_ctxsize = sizeof(struct artpec6_hashalg_context), 26378c2ecf20Sopenharmony_ci .cra_alignmask = 3, 26388c2ecf20Sopenharmony_ci .cra_module = THIS_MODULE, 26398c2ecf20Sopenharmony_ci .cra_init = artpec6_crypto_ahash_init, 26408c2ecf20Sopenharmony_ci .cra_exit = artpec6_crypto_ahash_exit, 26418c2ecf20Sopenharmony_ci } 26428c2ecf20Sopenharmony_ci }, 26438c2ecf20Sopenharmony_ci /* SHA-256 */ 26448c2ecf20Sopenharmony_ci { 26458c2ecf20Sopenharmony_ci .init = artpec6_crypto_sha256_init, 26468c2ecf20Sopenharmony_ci .update = artpec6_crypto_hash_update, 26478c2ecf20Sopenharmony_ci .final = artpec6_crypto_hash_final, 26488c2ecf20Sopenharmony_ci .digest = artpec6_crypto_sha256_digest, 26498c2ecf20Sopenharmony_ci .import = artpec6_crypto_hash_import, 26508c2ecf20Sopenharmony_ci .export = artpec6_crypto_hash_export, 26518c2ecf20Sopenharmony_ci .halg.digestsize = SHA256_DIGEST_SIZE, 26528c2ecf20Sopenharmony_ci .halg.statesize = sizeof(struct artpec6_hash_export_state), 26538c2ecf20Sopenharmony_ci .halg.base = { 26548c2ecf20Sopenharmony_ci .cra_name = "sha256", 26558c2ecf20Sopenharmony_ci .cra_driver_name = "artpec-sha256", 26568c2ecf20Sopenharmony_ci .cra_priority = 300, 26578c2ecf20Sopenharmony_ci .cra_flags = CRYPTO_ALG_ASYNC | 26588c2ecf20Sopenharmony_ci CRYPTO_ALG_ALLOCATES_MEMORY, 26598c2ecf20Sopenharmony_ci .cra_blocksize = SHA256_BLOCK_SIZE, 26608c2ecf20Sopenharmony_ci .cra_ctxsize = sizeof(struct artpec6_hashalg_context), 26618c2ecf20Sopenharmony_ci .cra_alignmask = 3, 26628c2ecf20Sopenharmony_ci .cra_module = THIS_MODULE, 26638c2ecf20Sopenharmony_ci .cra_init = artpec6_crypto_ahash_init, 26648c2ecf20Sopenharmony_ci .cra_exit = artpec6_crypto_ahash_exit, 26658c2ecf20Sopenharmony_ci } 26668c2ecf20Sopenharmony_ci }, 26678c2ecf20Sopenharmony_ci /* HMAC SHA-256 */ 26688c2ecf20Sopenharmony_ci { 26698c2ecf20Sopenharmony_ci .init = artpec6_crypto_hmac_sha256_init, 26708c2ecf20Sopenharmony_ci .update = artpec6_crypto_hash_update, 26718c2ecf20Sopenharmony_ci .final = artpec6_crypto_hash_final, 26728c2ecf20Sopenharmony_ci .digest = artpec6_crypto_hmac_sha256_digest, 26738c2ecf20Sopenharmony_ci .import = artpec6_crypto_hash_import, 26748c2ecf20Sopenharmony_ci .export = artpec6_crypto_hash_export, 26758c2ecf20Sopenharmony_ci .setkey = artpec6_crypto_hash_set_key, 26768c2ecf20Sopenharmony_ci .halg.digestsize = SHA256_DIGEST_SIZE, 26778c2ecf20Sopenharmony_ci .halg.statesize = sizeof(struct artpec6_hash_export_state), 26788c2ecf20Sopenharmony_ci .halg.base = { 26798c2ecf20Sopenharmony_ci .cra_name = "hmac(sha256)", 26808c2ecf20Sopenharmony_ci .cra_driver_name = "artpec-hmac-sha256", 26818c2ecf20Sopenharmony_ci .cra_priority = 300, 26828c2ecf20Sopenharmony_ci .cra_flags = CRYPTO_ALG_ASYNC | 26838c2ecf20Sopenharmony_ci CRYPTO_ALG_ALLOCATES_MEMORY, 26848c2ecf20Sopenharmony_ci .cra_blocksize = SHA256_BLOCK_SIZE, 26858c2ecf20Sopenharmony_ci .cra_ctxsize = sizeof(struct artpec6_hashalg_context), 26868c2ecf20Sopenharmony_ci .cra_alignmask = 3, 26878c2ecf20Sopenharmony_ci .cra_module = THIS_MODULE, 26888c2ecf20Sopenharmony_ci .cra_init = artpec6_crypto_ahash_init_hmac_sha256, 26898c2ecf20Sopenharmony_ci .cra_exit = artpec6_crypto_ahash_exit, 26908c2ecf20Sopenharmony_ci } 26918c2ecf20Sopenharmony_ci }, 26928c2ecf20Sopenharmony_ci}; 26938c2ecf20Sopenharmony_ci 26948c2ecf20Sopenharmony_ci/* Crypto */ 26958c2ecf20Sopenharmony_cistatic struct skcipher_alg crypto_algos[] = { 26968c2ecf20Sopenharmony_ci /* AES - ECB */ 26978c2ecf20Sopenharmony_ci { 26988c2ecf20Sopenharmony_ci .base = { 26998c2ecf20Sopenharmony_ci .cra_name = "ecb(aes)", 27008c2ecf20Sopenharmony_ci .cra_driver_name = "artpec6-ecb-aes", 27018c2ecf20Sopenharmony_ci .cra_priority = 300, 27028c2ecf20Sopenharmony_ci .cra_flags = CRYPTO_ALG_ASYNC | 27038c2ecf20Sopenharmony_ci CRYPTO_ALG_ALLOCATES_MEMORY, 27048c2ecf20Sopenharmony_ci .cra_blocksize = AES_BLOCK_SIZE, 27058c2ecf20Sopenharmony_ci .cra_ctxsize = sizeof(struct artpec6_cryptotfm_context), 27068c2ecf20Sopenharmony_ci .cra_alignmask = 3, 27078c2ecf20Sopenharmony_ci .cra_module = THIS_MODULE, 27088c2ecf20Sopenharmony_ci }, 27098c2ecf20Sopenharmony_ci .min_keysize = AES_MIN_KEY_SIZE, 27108c2ecf20Sopenharmony_ci .max_keysize = AES_MAX_KEY_SIZE, 27118c2ecf20Sopenharmony_ci .setkey = artpec6_crypto_cipher_set_key, 27128c2ecf20Sopenharmony_ci .encrypt = artpec6_crypto_encrypt, 27138c2ecf20Sopenharmony_ci .decrypt = artpec6_crypto_decrypt, 27148c2ecf20Sopenharmony_ci .init = artpec6_crypto_aes_ecb_init, 27158c2ecf20Sopenharmony_ci .exit = artpec6_crypto_aes_exit, 27168c2ecf20Sopenharmony_ci }, 27178c2ecf20Sopenharmony_ci /* AES - CTR */ 27188c2ecf20Sopenharmony_ci { 27198c2ecf20Sopenharmony_ci .base = { 27208c2ecf20Sopenharmony_ci .cra_name = "ctr(aes)", 27218c2ecf20Sopenharmony_ci .cra_driver_name = "artpec6-ctr-aes", 27228c2ecf20Sopenharmony_ci .cra_priority = 300, 27238c2ecf20Sopenharmony_ci .cra_flags = CRYPTO_ALG_ASYNC | 27248c2ecf20Sopenharmony_ci CRYPTO_ALG_ALLOCATES_MEMORY | 27258c2ecf20Sopenharmony_ci CRYPTO_ALG_NEED_FALLBACK, 27268c2ecf20Sopenharmony_ci .cra_blocksize = 1, 27278c2ecf20Sopenharmony_ci .cra_ctxsize = sizeof(struct artpec6_cryptotfm_context), 27288c2ecf20Sopenharmony_ci .cra_alignmask = 3, 27298c2ecf20Sopenharmony_ci .cra_module = THIS_MODULE, 27308c2ecf20Sopenharmony_ci }, 27318c2ecf20Sopenharmony_ci .min_keysize = AES_MIN_KEY_SIZE, 27328c2ecf20Sopenharmony_ci .max_keysize = AES_MAX_KEY_SIZE, 27338c2ecf20Sopenharmony_ci .ivsize = AES_BLOCK_SIZE, 27348c2ecf20Sopenharmony_ci .setkey = artpec6_crypto_cipher_set_key, 27358c2ecf20Sopenharmony_ci .encrypt = artpec6_crypto_ctr_encrypt, 27368c2ecf20Sopenharmony_ci .decrypt = artpec6_crypto_ctr_decrypt, 27378c2ecf20Sopenharmony_ci .init = artpec6_crypto_aes_ctr_init, 27388c2ecf20Sopenharmony_ci .exit = artpec6_crypto_aes_ctr_exit, 27398c2ecf20Sopenharmony_ci }, 27408c2ecf20Sopenharmony_ci /* AES - CBC */ 27418c2ecf20Sopenharmony_ci { 27428c2ecf20Sopenharmony_ci .base = { 27438c2ecf20Sopenharmony_ci .cra_name = "cbc(aes)", 27448c2ecf20Sopenharmony_ci .cra_driver_name = "artpec6-cbc-aes", 27458c2ecf20Sopenharmony_ci .cra_priority = 300, 27468c2ecf20Sopenharmony_ci .cra_flags = CRYPTO_ALG_ASYNC | 27478c2ecf20Sopenharmony_ci CRYPTO_ALG_ALLOCATES_MEMORY, 27488c2ecf20Sopenharmony_ci .cra_blocksize = AES_BLOCK_SIZE, 27498c2ecf20Sopenharmony_ci .cra_ctxsize = sizeof(struct artpec6_cryptotfm_context), 27508c2ecf20Sopenharmony_ci .cra_alignmask = 3, 27518c2ecf20Sopenharmony_ci .cra_module = THIS_MODULE, 27528c2ecf20Sopenharmony_ci }, 27538c2ecf20Sopenharmony_ci .min_keysize = AES_MIN_KEY_SIZE, 27548c2ecf20Sopenharmony_ci .max_keysize = AES_MAX_KEY_SIZE, 27558c2ecf20Sopenharmony_ci .ivsize = AES_BLOCK_SIZE, 27568c2ecf20Sopenharmony_ci .setkey = artpec6_crypto_cipher_set_key, 27578c2ecf20Sopenharmony_ci .encrypt = artpec6_crypto_encrypt, 27588c2ecf20Sopenharmony_ci .decrypt = artpec6_crypto_decrypt, 27598c2ecf20Sopenharmony_ci .init = artpec6_crypto_aes_cbc_init, 27608c2ecf20Sopenharmony_ci .exit = artpec6_crypto_aes_exit 27618c2ecf20Sopenharmony_ci }, 27628c2ecf20Sopenharmony_ci /* AES - XTS */ 27638c2ecf20Sopenharmony_ci { 27648c2ecf20Sopenharmony_ci .base = { 27658c2ecf20Sopenharmony_ci .cra_name = "xts(aes)", 27668c2ecf20Sopenharmony_ci .cra_driver_name = "artpec6-xts-aes", 27678c2ecf20Sopenharmony_ci .cra_priority = 300, 27688c2ecf20Sopenharmony_ci .cra_flags = CRYPTO_ALG_ASYNC | 27698c2ecf20Sopenharmony_ci CRYPTO_ALG_ALLOCATES_MEMORY, 27708c2ecf20Sopenharmony_ci .cra_blocksize = 1, 27718c2ecf20Sopenharmony_ci .cra_ctxsize = sizeof(struct artpec6_cryptotfm_context), 27728c2ecf20Sopenharmony_ci .cra_alignmask = 3, 27738c2ecf20Sopenharmony_ci .cra_module = THIS_MODULE, 27748c2ecf20Sopenharmony_ci }, 27758c2ecf20Sopenharmony_ci .min_keysize = 2*AES_MIN_KEY_SIZE, 27768c2ecf20Sopenharmony_ci .max_keysize = 2*AES_MAX_KEY_SIZE, 27778c2ecf20Sopenharmony_ci .ivsize = 16, 27788c2ecf20Sopenharmony_ci .setkey = artpec6_crypto_xts_set_key, 27798c2ecf20Sopenharmony_ci .encrypt = artpec6_crypto_encrypt, 27808c2ecf20Sopenharmony_ci .decrypt = artpec6_crypto_decrypt, 27818c2ecf20Sopenharmony_ci .init = artpec6_crypto_aes_xts_init, 27828c2ecf20Sopenharmony_ci .exit = artpec6_crypto_aes_exit, 27838c2ecf20Sopenharmony_ci }, 27848c2ecf20Sopenharmony_ci}; 27858c2ecf20Sopenharmony_ci 27868c2ecf20Sopenharmony_cistatic struct aead_alg aead_algos[] = { 27878c2ecf20Sopenharmony_ci { 27888c2ecf20Sopenharmony_ci .init = artpec6_crypto_aead_init, 27898c2ecf20Sopenharmony_ci .setkey = artpec6_crypto_aead_set_key, 27908c2ecf20Sopenharmony_ci .encrypt = artpec6_crypto_aead_encrypt, 27918c2ecf20Sopenharmony_ci .decrypt = artpec6_crypto_aead_decrypt, 27928c2ecf20Sopenharmony_ci .ivsize = GCM_AES_IV_SIZE, 27938c2ecf20Sopenharmony_ci .maxauthsize = AES_BLOCK_SIZE, 27948c2ecf20Sopenharmony_ci 27958c2ecf20Sopenharmony_ci .base = { 27968c2ecf20Sopenharmony_ci .cra_name = "gcm(aes)", 27978c2ecf20Sopenharmony_ci .cra_driver_name = "artpec-gcm-aes", 27988c2ecf20Sopenharmony_ci .cra_priority = 300, 27998c2ecf20Sopenharmony_ci .cra_flags = CRYPTO_ALG_ASYNC | 28008c2ecf20Sopenharmony_ci CRYPTO_ALG_ALLOCATES_MEMORY | 28018c2ecf20Sopenharmony_ci CRYPTO_ALG_KERN_DRIVER_ONLY, 28028c2ecf20Sopenharmony_ci .cra_blocksize = 1, 28038c2ecf20Sopenharmony_ci .cra_ctxsize = sizeof(struct artpec6_cryptotfm_context), 28048c2ecf20Sopenharmony_ci .cra_alignmask = 3, 28058c2ecf20Sopenharmony_ci .cra_module = THIS_MODULE, 28068c2ecf20Sopenharmony_ci }, 28078c2ecf20Sopenharmony_ci } 28088c2ecf20Sopenharmony_ci}; 28098c2ecf20Sopenharmony_ci 28108c2ecf20Sopenharmony_ci#ifdef CONFIG_DEBUG_FS 28118c2ecf20Sopenharmony_ci 28128c2ecf20Sopenharmony_cistruct dbgfs_u32 { 28138c2ecf20Sopenharmony_ci char *name; 28148c2ecf20Sopenharmony_ci mode_t mode; 28158c2ecf20Sopenharmony_ci u32 *flag; 28168c2ecf20Sopenharmony_ci char *desc; 28178c2ecf20Sopenharmony_ci}; 28188c2ecf20Sopenharmony_ci 28198c2ecf20Sopenharmony_cistatic struct dentry *dbgfs_root; 28208c2ecf20Sopenharmony_ci 28218c2ecf20Sopenharmony_cistatic void artpec6_crypto_init_debugfs(void) 28228c2ecf20Sopenharmony_ci{ 28238c2ecf20Sopenharmony_ci dbgfs_root = debugfs_create_dir("artpec6_crypto", NULL); 28248c2ecf20Sopenharmony_ci 28258c2ecf20Sopenharmony_ci#ifdef CONFIG_FAULT_INJECTION 28268c2ecf20Sopenharmony_ci fault_create_debugfs_attr("fail_status_read", dbgfs_root, 28278c2ecf20Sopenharmony_ci &artpec6_crypto_fail_status_read); 28288c2ecf20Sopenharmony_ci 28298c2ecf20Sopenharmony_ci fault_create_debugfs_attr("fail_dma_array_full", dbgfs_root, 28308c2ecf20Sopenharmony_ci &artpec6_crypto_fail_dma_array_full); 28318c2ecf20Sopenharmony_ci#endif 28328c2ecf20Sopenharmony_ci} 28338c2ecf20Sopenharmony_ci 28348c2ecf20Sopenharmony_cistatic void artpec6_crypto_free_debugfs(void) 28358c2ecf20Sopenharmony_ci{ 28368c2ecf20Sopenharmony_ci debugfs_remove_recursive(dbgfs_root); 28378c2ecf20Sopenharmony_ci dbgfs_root = NULL; 28388c2ecf20Sopenharmony_ci} 28398c2ecf20Sopenharmony_ci#endif 28408c2ecf20Sopenharmony_ci 28418c2ecf20Sopenharmony_cistatic const struct of_device_id artpec6_crypto_of_match[] = { 28428c2ecf20Sopenharmony_ci { .compatible = "axis,artpec6-crypto", .data = (void *)ARTPEC6_CRYPTO }, 28438c2ecf20Sopenharmony_ci { .compatible = "axis,artpec7-crypto", .data = (void *)ARTPEC7_CRYPTO }, 28448c2ecf20Sopenharmony_ci {} 28458c2ecf20Sopenharmony_ci}; 28468c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, artpec6_crypto_of_match); 28478c2ecf20Sopenharmony_ci 28488c2ecf20Sopenharmony_cistatic int artpec6_crypto_probe(struct platform_device *pdev) 28498c2ecf20Sopenharmony_ci{ 28508c2ecf20Sopenharmony_ci const struct of_device_id *match; 28518c2ecf20Sopenharmony_ci enum artpec6_crypto_variant variant; 28528c2ecf20Sopenharmony_ci struct artpec6_crypto *ac; 28538c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 28548c2ecf20Sopenharmony_ci void __iomem *base; 28558c2ecf20Sopenharmony_ci int irq; 28568c2ecf20Sopenharmony_ci int err; 28578c2ecf20Sopenharmony_ci 28588c2ecf20Sopenharmony_ci if (artpec6_crypto_dev) 28598c2ecf20Sopenharmony_ci return -ENODEV; 28608c2ecf20Sopenharmony_ci 28618c2ecf20Sopenharmony_ci match = of_match_node(artpec6_crypto_of_match, dev->of_node); 28628c2ecf20Sopenharmony_ci if (!match) 28638c2ecf20Sopenharmony_ci return -EINVAL; 28648c2ecf20Sopenharmony_ci 28658c2ecf20Sopenharmony_ci variant = (enum artpec6_crypto_variant)match->data; 28668c2ecf20Sopenharmony_ci 28678c2ecf20Sopenharmony_ci base = devm_platform_ioremap_resource(pdev, 0); 28688c2ecf20Sopenharmony_ci if (IS_ERR(base)) 28698c2ecf20Sopenharmony_ci return PTR_ERR(base); 28708c2ecf20Sopenharmony_ci 28718c2ecf20Sopenharmony_ci irq = platform_get_irq(pdev, 0); 28728c2ecf20Sopenharmony_ci if (irq < 0) 28738c2ecf20Sopenharmony_ci return -ENODEV; 28748c2ecf20Sopenharmony_ci 28758c2ecf20Sopenharmony_ci ac = devm_kzalloc(&pdev->dev, sizeof(struct artpec6_crypto), 28768c2ecf20Sopenharmony_ci GFP_KERNEL); 28778c2ecf20Sopenharmony_ci if (!ac) 28788c2ecf20Sopenharmony_ci return -ENOMEM; 28798c2ecf20Sopenharmony_ci 28808c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, ac); 28818c2ecf20Sopenharmony_ci ac->variant = variant; 28828c2ecf20Sopenharmony_ci 28838c2ecf20Sopenharmony_ci spin_lock_init(&ac->queue_lock); 28848c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&ac->queue); 28858c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&ac->pending); 28868c2ecf20Sopenharmony_ci timer_setup(&ac->timer, artpec6_crypto_timeout, 0); 28878c2ecf20Sopenharmony_ci 28888c2ecf20Sopenharmony_ci ac->base = base; 28898c2ecf20Sopenharmony_ci 28908c2ecf20Sopenharmony_ci ac->dma_cache = kmem_cache_create("artpec6_crypto_dma", 28918c2ecf20Sopenharmony_ci sizeof(struct artpec6_crypto_dma_descriptors), 28928c2ecf20Sopenharmony_ci 64, 28938c2ecf20Sopenharmony_ci 0, 28948c2ecf20Sopenharmony_ci NULL); 28958c2ecf20Sopenharmony_ci if (!ac->dma_cache) 28968c2ecf20Sopenharmony_ci return -ENOMEM; 28978c2ecf20Sopenharmony_ci 28988c2ecf20Sopenharmony_ci#ifdef CONFIG_DEBUG_FS 28998c2ecf20Sopenharmony_ci artpec6_crypto_init_debugfs(); 29008c2ecf20Sopenharmony_ci#endif 29018c2ecf20Sopenharmony_ci 29028c2ecf20Sopenharmony_ci tasklet_init(&ac->task, artpec6_crypto_task, 29038c2ecf20Sopenharmony_ci (unsigned long)ac); 29048c2ecf20Sopenharmony_ci 29058c2ecf20Sopenharmony_ci ac->pad_buffer = devm_kzalloc(&pdev->dev, 2 * ARTPEC_CACHE_LINE_MAX, 29068c2ecf20Sopenharmony_ci GFP_KERNEL); 29078c2ecf20Sopenharmony_ci if (!ac->pad_buffer) 29088c2ecf20Sopenharmony_ci return -ENOMEM; 29098c2ecf20Sopenharmony_ci ac->pad_buffer = PTR_ALIGN(ac->pad_buffer, ARTPEC_CACHE_LINE_MAX); 29108c2ecf20Sopenharmony_ci 29118c2ecf20Sopenharmony_ci ac->zero_buffer = devm_kzalloc(&pdev->dev, 2 * ARTPEC_CACHE_LINE_MAX, 29128c2ecf20Sopenharmony_ci GFP_KERNEL); 29138c2ecf20Sopenharmony_ci if (!ac->zero_buffer) 29148c2ecf20Sopenharmony_ci return -ENOMEM; 29158c2ecf20Sopenharmony_ci ac->zero_buffer = PTR_ALIGN(ac->zero_buffer, ARTPEC_CACHE_LINE_MAX); 29168c2ecf20Sopenharmony_ci 29178c2ecf20Sopenharmony_ci err = init_crypto_hw(ac); 29188c2ecf20Sopenharmony_ci if (err) 29198c2ecf20Sopenharmony_ci goto free_cache; 29208c2ecf20Sopenharmony_ci 29218c2ecf20Sopenharmony_ci err = devm_request_irq(&pdev->dev, irq, artpec6_crypto_irq, 0, 29228c2ecf20Sopenharmony_ci "artpec6-crypto", ac); 29238c2ecf20Sopenharmony_ci if (err) 29248c2ecf20Sopenharmony_ci goto disable_hw; 29258c2ecf20Sopenharmony_ci 29268c2ecf20Sopenharmony_ci artpec6_crypto_dev = &pdev->dev; 29278c2ecf20Sopenharmony_ci 29288c2ecf20Sopenharmony_ci err = crypto_register_ahashes(hash_algos, ARRAY_SIZE(hash_algos)); 29298c2ecf20Sopenharmony_ci if (err) { 29308c2ecf20Sopenharmony_ci dev_err(dev, "Failed to register ahashes\n"); 29318c2ecf20Sopenharmony_ci goto disable_hw; 29328c2ecf20Sopenharmony_ci } 29338c2ecf20Sopenharmony_ci 29348c2ecf20Sopenharmony_ci err = crypto_register_skciphers(crypto_algos, ARRAY_SIZE(crypto_algos)); 29358c2ecf20Sopenharmony_ci if (err) { 29368c2ecf20Sopenharmony_ci dev_err(dev, "Failed to register ciphers\n"); 29378c2ecf20Sopenharmony_ci goto unregister_ahashes; 29388c2ecf20Sopenharmony_ci } 29398c2ecf20Sopenharmony_ci 29408c2ecf20Sopenharmony_ci err = crypto_register_aeads(aead_algos, ARRAY_SIZE(aead_algos)); 29418c2ecf20Sopenharmony_ci if (err) { 29428c2ecf20Sopenharmony_ci dev_err(dev, "Failed to register aeads\n"); 29438c2ecf20Sopenharmony_ci goto unregister_algs; 29448c2ecf20Sopenharmony_ci } 29458c2ecf20Sopenharmony_ci 29468c2ecf20Sopenharmony_ci return 0; 29478c2ecf20Sopenharmony_ci 29488c2ecf20Sopenharmony_ciunregister_algs: 29498c2ecf20Sopenharmony_ci crypto_unregister_skciphers(crypto_algos, ARRAY_SIZE(crypto_algos)); 29508c2ecf20Sopenharmony_ciunregister_ahashes: 29518c2ecf20Sopenharmony_ci crypto_unregister_ahashes(hash_algos, ARRAY_SIZE(hash_algos)); 29528c2ecf20Sopenharmony_cidisable_hw: 29538c2ecf20Sopenharmony_ci artpec6_crypto_disable_hw(ac); 29548c2ecf20Sopenharmony_cifree_cache: 29558c2ecf20Sopenharmony_ci kmem_cache_destroy(ac->dma_cache); 29568c2ecf20Sopenharmony_ci return err; 29578c2ecf20Sopenharmony_ci} 29588c2ecf20Sopenharmony_ci 29598c2ecf20Sopenharmony_cistatic int artpec6_crypto_remove(struct platform_device *pdev) 29608c2ecf20Sopenharmony_ci{ 29618c2ecf20Sopenharmony_ci struct artpec6_crypto *ac = platform_get_drvdata(pdev); 29628c2ecf20Sopenharmony_ci int irq = platform_get_irq(pdev, 0); 29638c2ecf20Sopenharmony_ci 29648c2ecf20Sopenharmony_ci crypto_unregister_ahashes(hash_algos, ARRAY_SIZE(hash_algos)); 29658c2ecf20Sopenharmony_ci crypto_unregister_skciphers(crypto_algos, ARRAY_SIZE(crypto_algos)); 29668c2ecf20Sopenharmony_ci crypto_unregister_aeads(aead_algos, ARRAY_SIZE(aead_algos)); 29678c2ecf20Sopenharmony_ci 29688c2ecf20Sopenharmony_ci tasklet_disable(&ac->task); 29698c2ecf20Sopenharmony_ci devm_free_irq(&pdev->dev, irq, ac); 29708c2ecf20Sopenharmony_ci tasklet_kill(&ac->task); 29718c2ecf20Sopenharmony_ci del_timer_sync(&ac->timer); 29728c2ecf20Sopenharmony_ci 29738c2ecf20Sopenharmony_ci artpec6_crypto_disable_hw(ac); 29748c2ecf20Sopenharmony_ci 29758c2ecf20Sopenharmony_ci kmem_cache_destroy(ac->dma_cache); 29768c2ecf20Sopenharmony_ci#ifdef CONFIG_DEBUG_FS 29778c2ecf20Sopenharmony_ci artpec6_crypto_free_debugfs(); 29788c2ecf20Sopenharmony_ci#endif 29798c2ecf20Sopenharmony_ci return 0; 29808c2ecf20Sopenharmony_ci} 29818c2ecf20Sopenharmony_ci 29828c2ecf20Sopenharmony_cistatic struct platform_driver artpec6_crypto_driver = { 29838c2ecf20Sopenharmony_ci .probe = artpec6_crypto_probe, 29848c2ecf20Sopenharmony_ci .remove = artpec6_crypto_remove, 29858c2ecf20Sopenharmony_ci .driver = { 29868c2ecf20Sopenharmony_ci .name = "artpec6-crypto", 29878c2ecf20Sopenharmony_ci .of_match_table = artpec6_crypto_of_match, 29888c2ecf20Sopenharmony_ci }, 29898c2ecf20Sopenharmony_ci}; 29908c2ecf20Sopenharmony_ci 29918c2ecf20Sopenharmony_cimodule_platform_driver(artpec6_crypto_driver); 29928c2ecf20Sopenharmony_ci 29938c2ecf20Sopenharmony_ciMODULE_AUTHOR("Axis Communications AB"); 29948c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("ARTPEC-6 Crypto driver"); 29958c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 2996