18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Cryptographic API. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Support for SAHARA cryptographic accelerator. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Copyright (c) 2014 Steffen Trumtrar <s.trumtrar@pengutronix.de> 88c2ecf20Sopenharmony_ci * Copyright (c) 2013 Vista Silicon S.L. 98c2ecf20Sopenharmony_ci * Author: Javier Martin <javier.martin@vista-silicon.com> 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * Based on omap-aes.c and tegra-aes.c 128c2ecf20Sopenharmony_ci */ 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#include <crypto/aes.h> 158c2ecf20Sopenharmony_ci#include <crypto/internal/hash.h> 168c2ecf20Sopenharmony_ci#include <crypto/internal/skcipher.h> 178c2ecf20Sopenharmony_ci#include <crypto/scatterwalk.h> 188c2ecf20Sopenharmony_ci#include <crypto/sha.h> 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#include <linux/clk.h> 218c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h> 228c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 238c2ecf20Sopenharmony_ci#include <linux/io.h> 248c2ecf20Sopenharmony_ci#include <linux/irq.h> 258c2ecf20Sopenharmony_ci#include <linux/kernel.h> 268c2ecf20Sopenharmony_ci#include <linux/kthread.h> 278c2ecf20Sopenharmony_ci#include <linux/module.h> 288c2ecf20Sopenharmony_ci#include <linux/of.h> 298c2ecf20Sopenharmony_ci#include <linux/of_device.h> 308c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 318c2ecf20Sopenharmony_ci#include <linux/spinlock.h> 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci#define SHA_BUFFER_LEN PAGE_SIZE 348c2ecf20Sopenharmony_ci#define SAHARA_MAX_SHA_BLOCK_SIZE SHA256_BLOCK_SIZE 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci#define SAHARA_NAME "sahara" 378c2ecf20Sopenharmony_ci#define SAHARA_VERSION_3 3 388c2ecf20Sopenharmony_ci#define SAHARA_VERSION_4 4 398c2ecf20Sopenharmony_ci#define SAHARA_TIMEOUT_MS 1000 408c2ecf20Sopenharmony_ci#define SAHARA_MAX_HW_DESC 2 418c2ecf20Sopenharmony_ci#define SAHARA_MAX_HW_LINK 20 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci#define FLAGS_MODE_MASK 0x000f 448c2ecf20Sopenharmony_ci#define FLAGS_ENCRYPT BIT(0) 458c2ecf20Sopenharmony_ci#define FLAGS_CBC BIT(1) 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci#define SAHARA_HDR_BASE 0x00800000 488c2ecf20Sopenharmony_ci#define SAHARA_HDR_SKHA_ALG_AES 0 498c2ecf20Sopenharmony_ci#define SAHARA_HDR_SKHA_OP_ENC (1 << 2) 508c2ecf20Sopenharmony_ci#define SAHARA_HDR_SKHA_MODE_ECB (0 << 3) 518c2ecf20Sopenharmony_ci#define SAHARA_HDR_SKHA_MODE_CBC (1 << 3) 528c2ecf20Sopenharmony_ci#define SAHARA_HDR_FORM_DATA (5 << 16) 538c2ecf20Sopenharmony_ci#define SAHARA_HDR_FORM_KEY (8 << 16) 548c2ecf20Sopenharmony_ci#define SAHARA_HDR_LLO (1 << 24) 558c2ecf20Sopenharmony_ci#define SAHARA_HDR_CHA_SKHA (1 << 28) 568c2ecf20Sopenharmony_ci#define SAHARA_HDR_CHA_MDHA (2 << 28) 578c2ecf20Sopenharmony_ci#define SAHARA_HDR_PARITY_BIT (1 << 31) 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci#define SAHARA_HDR_MDHA_SET_MODE_MD_KEY 0x20880000 608c2ecf20Sopenharmony_ci#define SAHARA_HDR_MDHA_SET_MODE_HASH 0x208D0000 618c2ecf20Sopenharmony_ci#define SAHARA_HDR_MDHA_HASH 0xA0850000 628c2ecf20Sopenharmony_ci#define SAHARA_HDR_MDHA_STORE_DIGEST 0x20820000 638c2ecf20Sopenharmony_ci#define SAHARA_HDR_MDHA_ALG_SHA1 0 648c2ecf20Sopenharmony_ci#define SAHARA_HDR_MDHA_ALG_MD5 1 658c2ecf20Sopenharmony_ci#define SAHARA_HDR_MDHA_ALG_SHA256 2 668c2ecf20Sopenharmony_ci#define SAHARA_HDR_MDHA_ALG_SHA224 3 678c2ecf20Sopenharmony_ci#define SAHARA_HDR_MDHA_PDATA (1 << 2) 688c2ecf20Sopenharmony_ci#define SAHARA_HDR_MDHA_HMAC (1 << 3) 698c2ecf20Sopenharmony_ci#define SAHARA_HDR_MDHA_INIT (1 << 5) 708c2ecf20Sopenharmony_ci#define SAHARA_HDR_MDHA_IPAD (1 << 6) 718c2ecf20Sopenharmony_ci#define SAHARA_HDR_MDHA_OPAD (1 << 7) 728c2ecf20Sopenharmony_ci#define SAHARA_HDR_MDHA_SWAP (1 << 8) 738c2ecf20Sopenharmony_ci#define SAHARA_HDR_MDHA_MAC_FULL (1 << 9) 748c2ecf20Sopenharmony_ci#define SAHARA_HDR_MDHA_SSL (1 << 10) 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci/* SAHARA can only process one request at a time */ 778c2ecf20Sopenharmony_ci#define SAHARA_QUEUE_LENGTH 1 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci#define SAHARA_REG_VERSION 0x00 808c2ecf20Sopenharmony_ci#define SAHARA_REG_DAR 0x04 818c2ecf20Sopenharmony_ci#define SAHARA_REG_CONTROL 0x08 828c2ecf20Sopenharmony_ci#define SAHARA_CONTROL_SET_THROTTLE(x) (((x) & 0xff) << 24) 838c2ecf20Sopenharmony_ci#define SAHARA_CONTROL_SET_MAXBURST(x) (((x) & 0xff) << 16) 848c2ecf20Sopenharmony_ci#define SAHARA_CONTROL_RNG_AUTORSD (1 << 7) 858c2ecf20Sopenharmony_ci#define SAHARA_CONTROL_ENABLE_INT (1 << 4) 868c2ecf20Sopenharmony_ci#define SAHARA_REG_CMD 0x0C 878c2ecf20Sopenharmony_ci#define SAHARA_CMD_RESET (1 << 0) 888c2ecf20Sopenharmony_ci#define SAHARA_CMD_CLEAR_INT (1 << 8) 898c2ecf20Sopenharmony_ci#define SAHARA_CMD_CLEAR_ERR (1 << 9) 908c2ecf20Sopenharmony_ci#define SAHARA_CMD_SINGLE_STEP (1 << 10) 918c2ecf20Sopenharmony_ci#define SAHARA_CMD_MODE_BATCH (1 << 16) 928c2ecf20Sopenharmony_ci#define SAHARA_CMD_MODE_DEBUG (1 << 18) 938c2ecf20Sopenharmony_ci#define SAHARA_REG_STATUS 0x10 948c2ecf20Sopenharmony_ci#define SAHARA_STATUS_GET_STATE(x) ((x) & 0x7) 958c2ecf20Sopenharmony_ci#define SAHARA_STATE_IDLE 0 968c2ecf20Sopenharmony_ci#define SAHARA_STATE_BUSY 1 978c2ecf20Sopenharmony_ci#define SAHARA_STATE_ERR 2 988c2ecf20Sopenharmony_ci#define SAHARA_STATE_FAULT 3 998c2ecf20Sopenharmony_ci#define SAHARA_STATE_COMPLETE 4 1008c2ecf20Sopenharmony_ci#define SAHARA_STATE_COMP_FLAG (1 << 2) 1018c2ecf20Sopenharmony_ci#define SAHARA_STATUS_DAR_FULL (1 << 3) 1028c2ecf20Sopenharmony_ci#define SAHARA_STATUS_ERROR (1 << 4) 1038c2ecf20Sopenharmony_ci#define SAHARA_STATUS_SECURE (1 << 5) 1048c2ecf20Sopenharmony_ci#define SAHARA_STATUS_FAIL (1 << 6) 1058c2ecf20Sopenharmony_ci#define SAHARA_STATUS_INIT (1 << 7) 1068c2ecf20Sopenharmony_ci#define SAHARA_STATUS_RNG_RESEED (1 << 8) 1078c2ecf20Sopenharmony_ci#define SAHARA_STATUS_ACTIVE_RNG (1 << 9) 1088c2ecf20Sopenharmony_ci#define SAHARA_STATUS_ACTIVE_MDHA (1 << 10) 1098c2ecf20Sopenharmony_ci#define SAHARA_STATUS_ACTIVE_SKHA (1 << 11) 1108c2ecf20Sopenharmony_ci#define SAHARA_STATUS_MODE_BATCH (1 << 16) 1118c2ecf20Sopenharmony_ci#define SAHARA_STATUS_MODE_DEDICATED (1 << 17) 1128c2ecf20Sopenharmony_ci#define SAHARA_STATUS_MODE_DEBUG (1 << 18) 1138c2ecf20Sopenharmony_ci#define SAHARA_STATUS_GET_ISTATE(x) (((x) >> 24) & 0xff) 1148c2ecf20Sopenharmony_ci#define SAHARA_REG_ERRSTATUS 0x14 1158c2ecf20Sopenharmony_ci#define SAHARA_ERRSTATUS_GET_SOURCE(x) ((x) & 0xf) 1168c2ecf20Sopenharmony_ci#define SAHARA_ERRSOURCE_CHA 14 1178c2ecf20Sopenharmony_ci#define SAHARA_ERRSOURCE_DMA 15 1188c2ecf20Sopenharmony_ci#define SAHARA_ERRSTATUS_DMA_DIR (1 << 8) 1198c2ecf20Sopenharmony_ci#define SAHARA_ERRSTATUS_GET_DMASZ(x)(((x) >> 9) & 0x3) 1208c2ecf20Sopenharmony_ci#define SAHARA_ERRSTATUS_GET_DMASRC(x) (((x) >> 13) & 0x7) 1218c2ecf20Sopenharmony_ci#define SAHARA_ERRSTATUS_GET_CHASRC(x) (((x) >> 16) & 0xfff) 1228c2ecf20Sopenharmony_ci#define SAHARA_ERRSTATUS_GET_CHAERR(x) (((x) >> 28) & 0x3) 1238c2ecf20Sopenharmony_ci#define SAHARA_REG_FADDR 0x18 1248c2ecf20Sopenharmony_ci#define SAHARA_REG_CDAR 0x1C 1258c2ecf20Sopenharmony_ci#define SAHARA_REG_IDAR 0x20 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_cistruct sahara_hw_desc { 1288c2ecf20Sopenharmony_ci u32 hdr; 1298c2ecf20Sopenharmony_ci u32 len1; 1308c2ecf20Sopenharmony_ci u32 p1; 1318c2ecf20Sopenharmony_ci u32 len2; 1328c2ecf20Sopenharmony_ci u32 p2; 1338c2ecf20Sopenharmony_ci u32 next; 1348c2ecf20Sopenharmony_ci}; 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_cistruct sahara_hw_link { 1378c2ecf20Sopenharmony_ci u32 len; 1388c2ecf20Sopenharmony_ci u32 p; 1398c2ecf20Sopenharmony_ci u32 next; 1408c2ecf20Sopenharmony_ci}; 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_cistruct sahara_ctx { 1438c2ecf20Sopenharmony_ci /* AES-specific context */ 1448c2ecf20Sopenharmony_ci int keylen; 1458c2ecf20Sopenharmony_ci u8 key[AES_KEYSIZE_128]; 1468c2ecf20Sopenharmony_ci struct crypto_skcipher *fallback; 1478c2ecf20Sopenharmony_ci}; 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_cistruct sahara_aes_reqctx { 1508c2ecf20Sopenharmony_ci unsigned long mode; 1518c2ecf20Sopenharmony_ci u8 iv_out[AES_BLOCK_SIZE]; 1528c2ecf20Sopenharmony_ci struct skcipher_request fallback_req; // keep at the end 1538c2ecf20Sopenharmony_ci}; 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci/* 1568c2ecf20Sopenharmony_ci * struct sahara_sha_reqctx - private data per request 1578c2ecf20Sopenharmony_ci * @buf: holds data for requests smaller than block_size 1588c2ecf20Sopenharmony_ci * @rembuf: used to prepare one block_size-aligned request 1598c2ecf20Sopenharmony_ci * @context: hw-specific context for request. Digest is extracted from this 1608c2ecf20Sopenharmony_ci * @mode: specifies what type of hw-descriptor needs to be built 1618c2ecf20Sopenharmony_ci * @digest_size: length of digest for this request 1628c2ecf20Sopenharmony_ci * @context_size: length of hw-context for this request. 1638c2ecf20Sopenharmony_ci * Always digest_size + 4 1648c2ecf20Sopenharmony_ci * @buf_cnt: number of bytes saved in buf 1658c2ecf20Sopenharmony_ci * @sg_in_idx: number of hw links 1668c2ecf20Sopenharmony_ci * @in_sg: scatterlist for input data 1678c2ecf20Sopenharmony_ci * @in_sg_chain: scatterlists for chained input data 1688c2ecf20Sopenharmony_ci * @total: total number of bytes for transfer 1698c2ecf20Sopenharmony_ci * @last: is this the last block 1708c2ecf20Sopenharmony_ci * @first: is this the first block 1718c2ecf20Sopenharmony_ci * @active: inside a transfer 1728c2ecf20Sopenharmony_ci */ 1738c2ecf20Sopenharmony_cistruct sahara_sha_reqctx { 1748c2ecf20Sopenharmony_ci u8 buf[SAHARA_MAX_SHA_BLOCK_SIZE]; 1758c2ecf20Sopenharmony_ci u8 rembuf[SAHARA_MAX_SHA_BLOCK_SIZE]; 1768c2ecf20Sopenharmony_ci u8 context[SHA256_DIGEST_SIZE + 4]; 1778c2ecf20Sopenharmony_ci unsigned int mode; 1788c2ecf20Sopenharmony_ci unsigned int digest_size; 1798c2ecf20Sopenharmony_ci unsigned int context_size; 1808c2ecf20Sopenharmony_ci unsigned int buf_cnt; 1818c2ecf20Sopenharmony_ci unsigned int sg_in_idx; 1828c2ecf20Sopenharmony_ci struct scatterlist *in_sg; 1838c2ecf20Sopenharmony_ci struct scatterlist in_sg_chain[2]; 1848c2ecf20Sopenharmony_ci size_t total; 1858c2ecf20Sopenharmony_ci unsigned int last; 1868c2ecf20Sopenharmony_ci unsigned int first; 1878c2ecf20Sopenharmony_ci unsigned int active; 1888c2ecf20Sopenharmony_ci}; 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_cistruct sahara_dev { 1918c2ecf20Sopenharmony_ci struct device *device; 1928c2ecf20Sopenharmony_ci unsigned int version; 1938c2ecf20Sopenharmony_ci void __iomem *regs_base; 1948c2ecf20Sopenharmony_ci struct clk *clk_ipg; 1958c2ecf20Sopenharmony_ci struct clk *clk_ahb; 1968c2ecf20Sopenharmony_ci spinlock_t queue_spinlock; 1978c2ecf20Sopenharmony_ci struct task_struct *kthread; 1988c2ecf20Sopenharmony_ci struct completion dma_completion; 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci struct sahara_ctx *ctx; 2018c2ecf20Sopenharmony_ci struct crypto_queue queue; 2028c2ecf20Sopenharmony_ci unsigned long flags; 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci struct sahara_hw_desc *hw_desc[SAHARA_MAX_HW_DESC]; 2058c2ecf20Sopenharmony_ci dma_addr_t hw_phys_desc[SAHARA_MAX_HW_DESC]; 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci u8 *key_base; 2088c2ecf20Sopenharmony_ci dma_addr_t key_phys_base; 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci u8 *iv_base; 2118c2ecf20Sopenharmony_ci dma_addr_t iv_phys_base; 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci u8 *context_base; 2148c2ecf20Sopenharmony_ci dma_addr_t context_phys_base; 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci struct sahara_hw_link *hw_link[SAHARA_MAX_HW_LINK]; 2178c2ecf20Sopenharmony_ci dma_addr_t hw_phys_link[SAHARA_MAX_HW_LINK]; 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci size_t total; 2208c2ecf20Sopenharmony_ci struct scatterlist *in_sg; 2218c2ecf20Sopenharmony_ci int nb_in_sg; 2228c2ecf20Sopenharmony_ci struct scatterlist *out_sg; 2238c2ecf20Sopenharmony_ci int nb_out_sg; 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci u32 error; 2268c2ecf20Sopenharmony_ci}; 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_cistatic struct sahara_dev *dev_ptr; 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_cistatic inline void sahara_write(struct sahara_dev *dev, u32 data, u32 reg) 2318c2ecf20Sopenharmony_ci{ 2328c2ecf20Sopenharmony_ci writel(data, dev->regs_base + reg); 2338c2ecf20Sopenharmony_ci} 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_cistatic inline unsigned int sahara_read(struct sahara_dev *dev, u32 reg) 2368c2ecf20Sopenharmony_ci{ 2378c2ecf20Sopenharmony_ci return readl(dev->regs_base + reg); 2388c2ecf20Sopenharmony_ci} 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_cistatic u32 sahara_aes_key_hdr(struct sahara_dev *dev) 2418c2ecf20Sopenharmony_ci{ 2428c2ecf20Sopenharmony_ci u32 hdr = SAHARA_HDR_BASE | SAHARA_HDR_SKHA_ALG_AES | 2438c2ecf20Sopenharmony_ci SAHARA_HDR_FORM_KEY | SAHARA_HDR_LLO | 2448c2ecf20Sopenharmony_ci SAHARA_HDR_CHA_SKHA | SAHARA_HDR_PARITY_BIT; 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci if (dev->flags & FLAGS_CBC) { 2478c2ecf20Sopenharmony_ci hdr |= SAHARA_HDR_SKHA_MODE_CBC; 2488c2ecf20Sopenharmony_ci hdr ^= SAHARA_HDR_PARITY_BIT; 2498c2ecf20Sopenharmony_ci } 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci if (dev->flags & FLAGS_ENCRYPT) { 2528c2ecf20Sopenharmony_ci hdr |= SAHARA_HDR_SKHA_OP_ENC; 2538c2ecf20Sopenharmony_ci hdr ^= SAHARA_HDR_PARITY_BIT; 2548c2ecf20Sopenharmony_ci } 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci return hdr; 2578c2ecf20Sopenharmony_ci} 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_cistatic u32 sahara_aes_data_link_hdr(struct sahara_dev *dev) 2608c2ecf20Sopenharmony_ci{ 2618c2ecf20Sopenharmony_ci return SAHARA_HDR_BASE | SAHARA_HDR_FORM_DATA | 2628c2ecf20Sopenharmony_ci SAHARA_HDR_CHA_SKHA | SAHARA_HDR_PARITY_BIT; 2638c2ecf20Sopenharmony_ci} 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_cistatic const char *sahara_err_src[16] = { 2668c2ecf20Sopenharmony_ci "No error", 2678c2ecf20Sopenharmony_ci "Header error", 2688c2ecf20Sopenharmony_ci "Descriptor length error", 2698c2ecf20Sopenharmony_ci "Descriptor length or pointer error", 2708c2ecf20Sopenharmony_ci "Link length error", 2718c2ecf20Sopenharmony_ci "Link pointer error", 2728c2ecf20Sopenharmony_ci "Input buffer error", 2738c2ecf20Sopenharmony_ci "Output buffer error", 2748c2ecf20Sopenharmony_ci "Output buffer starvation", 2758c2ecf20Sopenharmony_ci "Internal state fault", 2768c2ecf20Sopenharmony_ci "General descriptor problem", 2778c2ecf20Sopenharmony_ci "Reserved", 2788c2ecf20Sopenharmony_ci "Descriptor address error", 2798c2ecf20Sopenharmony_ci "Link address error", 2808c2ecf20Sopenharmony_ci "CHA error", 2818c2ecf20Sopenharmony_ci "DMA error" 2828c2ecf20Sopenharmony_ci}; 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_cistatic const char *sahara_err_dmasize[4] = { 2858c2ecf20Sopenharmony_ci "Byte transfer", 2868c2ecf20Sopenharmony_ci "Half-word transfer", 2878c2ecf20Sopenharmony_ci "Word transfer", 2888c2ecf20Sopenharmony_ci "Reserved" 2898c2ecf20Sopenharmony_ci}; 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_cistatic const char *sahara_err_dmasrc[8] = { 2928c2ecf20Sopenharmony_ci "No error", 2938c2ecf20Sopenharmony_ci "AHB bus error", 2948c2ecf20Sopenharmony_ci "Internal IP bus error", 2958c2ecf20Sopenharmony_ci "Parity error", 2968c2ecf20Sopenharmony_ci "DMA crosses 256 byte boundary", 2978c2ecf20Sopenharmony_ci "DMA is busy", 2988c2ecf20Sopenharmony_ci "Reserved", 2998c2ecf20Sopenharmony_ci "DMA HW error" 3008c2ecf20Sopenharmony_ci}; 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_cistatic const char *sahara_cha_errsrc[12] = { 3038c2ecf20Sopenharmony_ci "Input buffer non-empty", 3048c2ecf20Sopenharmony_ci "Illegal address", 3058c2ecf20Sopenharmony_ci "Illegal mode", 3068c2ecf20Sopenharmony_ci "Illegal data size", 3078c2ecf20Sopenharmony_ci "Illegal key size", 3088c2ecf20Sopenharmony_ci "Write during processing", 3098c2ecf20Sopenharmony_ci "CTX read during processing", 3108c2ecf20Sopenharmony_ci "HW error", 3118c2ecf20Sopenharmony_ci "Input buffer disabled/underflow", 3128c2ecf20Sopenharmony_ci "Output buffer disabled/overflow", 3138c2ecf20Sopenharmony_ci "DES key parity error", 3148c2ecf20Sopenharmony_ci "Reserved" 3158c2ecf20Sopenharmony_ci}; 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_cistatic const char *sahara_cha_err[4] = { "No error", "SKHA", "MDHA", "RNG" }; 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_cistatic void sahara_decode_error(struct sahara_dev *dev, unsigned int error) 3208c2ecf20Sopenharmony_ci{ 3218c2ecf20Sopenharmony_ci u8 source = SAHARA_ERRSTATUS_GET_SOURCE(error); 3228c2ecf20Sopenharmony_ci u16 chasrc = ffs(SAHARA_ERRSTATUS_GET_CHASRC(error)); 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci dev_err(dev->device, "%s: Error Register = 0x%08x\n", __func__, error); 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci dev_err(dev->device, " - %s.\n", sahara_err_src[source]); 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci if (source == SAHARA_ERRSOURCE_DMA) { 3298c2ecf20Sopenharmony_ci if (error & SAHARA_ERRSTATUS_DMA_DIR) 3308c2ecf20Sopenharmony_ci dev_err(dev->device, " * DMA read.\n"); 3318c2ecf20Sopenharmony_ci else 3328c2ecf20Sopenharmony_ci dev_err(dev->device, " * DMA write.\n"); 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci dev_err(dev->device, " * %s.\n", 3358c2ecf20Sopenharmony_ci sahara_err_dmasize[SAHARA_ERRSTATUS_GET_DMASZ(error)]); 3368c2ecf20Sopenharmony_ci dev_err(dev->device, " * %s.\n", 3378c2ecf20Sopenharmony_ci sahara_err_dmasrc[SAHARA_ERRSTATUS_GET_DMASRC(error)]); 3388c2ecf20Sopenharmony_ci } else if (source == SAHARA_ERRSOURCE_CHA) { 3398c2ecf20Sopenharmony_ci dev_err(dev->device, " * %s.\n", 3408c2ecf20Sopenharmony_ci sahara_cha_errsrc[chasrc]); 3418c2ecf20Sopenharmony_ci dev_err(dev->device, " * %s.\n", 3428c2ecf20Sopenharmony_ci sahara_cha_err[SAHARA_ERRSTATUS_GET_CHAERR(error)]); 3438c2ecf20Sopenharmony_ci } 3448c2ecf20Sopenharmony_ci dev_err(dev->device, "\n"); 3458c2ecf20Sopenharmony_ci} 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_cistatic const char *sahara_state[4] = { "Idle", "Busy", "Error", "HW Fault" }; 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_cistatic void sahara_decode_status(struct sahara_dev *dev, unsigned int status) 3508c2ecf20Sopenharmony_ci{ 3518c2ecf20Sopenharmony_ci u8 state; 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci if (!__is_defined(DEBUG)) 3548c2ecf20Sopenharmony_ci return; 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci state = SAHARA_STATUS_GET_STATE(status); 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci dev_dbg(dev->device, "%s: Status Register = 0x%08x\n", 3598c2ecf20Sopenharmony_ci __func__, status); 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci dev_dbg(dev->device, " - State = %d:\n", state); 3628c2ecf20Sopenharmony_ci if (state & SAHARA_STATE_COMP_FLAG) 3638c2ecf20Sopenharmony_ci dev_dbg(dev->device, " * Descriptor completed. IRQ pending.\n"); 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci dev_dbg(dev->device, " * %s.\n", 3668c2ecf20Sopenharmony_ci sahara_state[state & ~SAHARA_STATE_COMP_FLAG]); 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci if (status & SAHARA_STATUS_DAR_FULL) 3698c2ecf20Sopenharmony_ci dev_dbg(dev->device, " - DAR Full.\n"); 3708c2ecf20Sopenharmony_ci if (status & SAHARA_STATUS_ERROR) 3718c2ecf20Sopenharmony_ci dev_dbg(dev->device, " - Error.\n"); 3728c2ecf20Sopenharmony_ci if (status & SAHARA_STATUS_SECURE) 3738c2ecf20Sopenharmony_ci dev_dbg(dev->device, " - Secure.\n"); 3748c2ecf20Sopenharmony_ci if (status & SAHARA_STATUS_FAIL) 3758c2ecf20Sopenharmony_ci dev_dbg(dev->device, " - Fail.\n"); 3768c2ecf20Sopenharmony_ci if (status & SAHARA_STATUS_RNG_RESEED) 3778c2ecf20Sopenharmony_ci dev_dbg(dev->device, " - RNG Reseed Request.\n"); 3788c2ecf20Sopenharmony_ci if (status & SAHARA_STATUS_ACTIVE_RNG) 3798c2ecf20Sopenharmony_ci dev_dbg(dev->device, " - RNG Active.\n"); 3808c2ecf20Sopenharmony_ci if (status & SAHARA_STATUS_ACTIVE_MDHA) 3818c2ecf20Sopenharmony_ci dev_dbg(dev->device, " - MDHA Active.\n"); 3828c2ecf20Sopenharmony_ci if (status & SAHARA_STATUS_ACTIVE_SKHA) 3838c2ecf20Sopenharmony_ci dev_dbg(dev->device, " - SKHA Active.\n"); 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci if (status & SAHARA_STATUS_MODE_BATCH) 3868c2ecf20Sopenharmony_ci dev_dbg(dev->device, " - Batch Mode.\n"); 3878c2ecf20Sopenharmony_ci else if (status & SAHARA_STATUS_MODE_DEDICATED) 3888c2ecf20Sopenharmony_ci dev_dbg(dev->device, " - Dedicated Mode.\n"); 3898c2ecf20Sopenharmony_ci else if (status & SAHARA_STATUS_MODE_DEBUG) 3908c2ecf20Sopenharmony_ci dev_dbg(dev->device, " - Debug Mode.\n"); 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci dev_dbg(dev->device, " - Internal state = 0x%02x\n", 3938c2ecf20Sopenharmony_ci SAHARA_STATUS_GET_ISTATE(status)); 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci dev_dbg(dev->device, "Current DAR: 0x%08x\n", 3968c2ecf20Sopenharmony_ci sahara_read(dev, SAHARA_REG_CDAR)); 3978c2ecf20Sopenharmony_ci dev_dbg(dev->device, "Initial DAR: 0x%08x\n\n", 3988c2ecf20Sopenharmony_ci sahara_read(dev, SAHARA_REG_IDAR)); 3998c2ecf20Sopenharmony_ci} 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_cistatic void sahara_dump_descriptors(struct sahara_dev *dev) 4028c2ecf20Sopenharmony_ci{ 4038c2ecf20Sopenharmony_ci int i; 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci if (!__is_defined(DEBUG)) 4068c2ecf20Sopenharmony_ci return; 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci for (i = 0; i < SAHARA_MAX_HW_DESC; i++) { 4098c2ecf20Sopenharmony_ci dev_dbg(dev->device, "Descriptor (%d) (%pad):\n", 4108c2ecf20Sopenharmony_ci i, &dev->hw_phys_desc[i]); 4118c2ecf20Sopenharmony_ci dev_dbg(dev->device, "\thdr = 0x%08x\n", dev->hw_desc[i]->hdr); 4128c2ecf20Sopenharmony_ci dev_dbg(dev->device, "\tlen1 = %u\n", dev->hw_desc[i]->len1); 4138c2ecf20Sopenharmony_ci dev_dbg(dev->device, "\tp1 = 0x%08x\n", dev->hw_desc[i]->p1); 4148c2ecf20Sopenharmony_ci dev_dbg(dev->device, "\tlen2 = %u\n", dev->hw_desc[i]->len2); 4158c2ecf20Sopenharmony_ci dev_dbg(dev->device, "\tp2 = 0x%08x\n", dev->hw_desc[i]->p2); 4168c2ecf20Sopenharmony_ci dev_dbg(dev->device, "\tnext = 0x%08x\n", 4178c2ecf20Sopenharmony_ci dev->hw_desc[i]->next); 4188c2ecf20Sopenharmony_ci } 4198c2ecf20Sopenharmony_ci dev_dbg(dev->device, "\n"); 4208c2ecf20Sopenharmony_ci} 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_cistatic void sahara_dump_links(struct sahara_dev *dev) 4238c2ecf20Sopenharmony_ci{ 4248c2ecf20Sopenharmony_ci int i; 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci if (!__is_defined(DEBUG)) 4278c2ecf20Sopenharmony_ci return; 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci for (i = 0; i < SAHARA_MAX_HW_LINK; i++) { 4308c2ecf20Sopenharmony_ci dev_dbg(dev->device, "Link (%d) (%pad):\n", 4318c2ecf20Sopenharmony_ci i, &dev->hw_phys_link[i]); 4328c2ecf20Sopenharmony_ci dev_dbg(dev->device, "\tlen = %u\n", dev->hw_link[i]->len); 4338c2ecf20Sopenharmony_ci dev_dbg(dev->device, "\tp = 0x%08x\n", dev->hw_link[i]->p); 4348c2ecf20Sopenharmony_ci dev_dbg(dev->device, "\tnext = 0x%08x\n", 4358c2ecf20Sopenharmony_ci dev->hw_link[i]->next); 4368c2ecf20Sopenharmony_ci } 4378c2ecf20Sopenharmony_ci dev_dbg(dev->device, "\n"); 4388c2ecf20Sopenharmony_ci} 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_cistatic int sahara_hw_descriptor_create(struct sahara_dev *dev) 4418c2ecf20Sopenharmony_ci{ 4428c2ecf20Sopenharmony_ci struct sahara_ctx *ctx = dev->ctx; 4438c2ecf20Sopenharmony_ci struct scatterlist *sg; 4448c2ecf20Sopenharmony_ci int ret; 4458c2ecf20Sopenharmony_ci int i, j; 4468c2ecf20Sopenharmony_ci int idx = 0; 4478c2ecf20Sopenharmony_ci u32 len; 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci memcpy(dev->key_base, ctx->key, ctx->keylen); 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci if (dev->flags & FLAGS_CBC) { 4528c2ecf20Sopenharmony_ci dev->hw_desc[idx]->len1 = AES_BLOCK_SIZE; 4538c2ecf20Sopenharmony_ci dev->hw_desc[idx]->p1 = dev->iv_phys_base; 4548c2ecf20Sopenharmony_ci } else { 4558c2ecf20Sopenharmony_ci dev->hw_desc[idx]->len1 = 0; 4568c2ecf20Sopenharmony_ci dev->hw_desc[idx]->p1 = 0; 4578c2ecf20Sopenharmony_ci } 4588c2ecf20Sopenharmony_ci dev->hw_desc[idx]->len2 = ctx->keylen; 4598c2ecf20Sopenharmony_ci dev->hw_desc[idx]->p2 = dev->key_phys_base; 4608c2ecf20Sopenharmony_ci dev->hw_desc[idx]->next = dev->hw_phys_desc[1]; 4618c2ecf20Sopenharmony_ci dev->hw_desc[idx]->hdr = sahara_aes_key_hdr(dev); 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci idx++; 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci dev->nb_in_sg = sg_nents_for_len(dev->in_sg, dev->total); 4678c2ecf20Sopenharmony_ci if (dev->nb_in_sg < 0) { 4688c2ecf20Sopenharmony_ci dev_err(dev->device, "Invalid numbers of src SG.\n"); 4698c2ecf20Sopenharmony_ci return dev->nb_in_sg; 4708c2ecf20Sopenharmony_ci } 4718c2ecf20Sopenharmony_ci dev->nb_out_sg = sg_nents_for_len(dev->out_sg, dev->total); 4728c2ecf20Sopenharmony_ci if (dev->nb_out_sg < 0) { 4738c2ecf20Sopenharmony_ci dev_err(dev->device, "Invalid numbers of dst SG.\n"); 4748c2ecf20Sopenharmony_ci return dev->nb_out_sg; 4758c2ecf20Sopenharmony_ci } 4768c2ecf20Sopenharmony_ci if ((dev->nb_in_sg + dev->nb_out_sg) > SAHARA_MAX_HW_LINK) { 4778c2ecf20Sopenharmony_ci dev_err(dev->device, "not enough hw links (%d)\n", 4788c2ecf20Sopenharmony_ci dev->nb_in_sg + dev->nb_out_sg); 4798c2ecf20Sopenharmony_ci return -EINVAL; 4808c2ecf20Sopenharmony_ci } 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_ci ret = dma_map_sg(dev->device, dev->in_sg, dev->nb_in_sg, 4838c2ecf20Sopenharmony_ci DMA_TO_DEVICE); 4848c2ecf20Sopenharmony_ci if (ret != dev->nb_in_sg) { 4858c2ecf20Sopenharmony_ci dev_err(dev->device, "couldn't map in sg\n"); 4868c2ecf20Sopenharmony_ci return -EINVAL; 4878c2ecf20Sopenharmony_ci } 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ci ret = dma_map_sg(dev->device, dev->out_sg, dev->nb_out_sg, 4908c2ecf20Sopenharmony_ci DMA_FROM_DEVICE); 4918c2ecf20Sopenharmony_ci if (ret != dev->nb_out_sg) { 4928c2ecf20Sopenharmony_ci dev_err(dev->device, "couldn't map out sg\n"); 4938c2ecf20Sopenharmony_ci goto unmap_in; 4948c2ecf20Sopenharmony_ci } 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci /* Create input links */ 4978c2ecf20Sopenharmony_ci dev->hw_desc[idx]->p1 = dev->hw_phys_link[0]; 4988c2ecf20Sopenharmony_ci sg = dev->in_sg; 4998c2ecf20Sopenharmony_ci len = dev->total; 5008c2ecf20Sopenharmony_ci for (i = 0; i < dev->nb_in_sg; i++) { 5018c2ecf20Sopenharmony_ci dev->hw_link[i]->len = min(len, sg->length); 5028c2ecf20Sopenharmony_ci dev->hw_link[i]->p = sg->dma_address; 5038c2ecf20Sopenharmony_ci if (i == (dev->nb_in_sg - 1)) { 5048c2ecf20Sopenharmony_ci dev->hw_link[i]->next = 0; 5058c2ecf20Sopenharmony_ci } else { 5068c2ecf20Sopenharmony_ci len -= min(len, sg->length); 5078c2ecf20Sopenharmony_ci dev->hw_link[i]->next = dev->hw_phys_link[i + 1]; 5088c2ecf20Sopenharmony_ci sg = sg_next(sg); 5098c2ecf20Sopenharmony_ci } 5108c2ecf20Sopenharmony_ci } 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_ci /* Create output links */ 5138c2ecf20Sopenharmony_ci dev->hw_desc[idx]->p2 = dev->hw_phys_link[i]; 5148c2ecf20Sopenharmony_ci sg = dev->out_sg; 5158c2ecf20Sopenharmony_ci len = dev->total; 5168c2ecf20Sopenharmony_ci for (j = i; j < dev->nb_out_sg + i; j++) { 5178c2ecf20Sopenharmony_ci dev->hw_link[j]->len = min(len, sg->length); 5188c2ecf20Sopenharmony_ci dev->hw_link[j]->p = sg->dma_address; 5198c2ecf20Sopenharmony_ci if (j == (dev->nb_out_sg + i - 1)) { 5208c2ecf20Sopenharmony_ci dev->hw_link[j]->next = 0; 5218c2ecf20Sopenharmony_ci } else { 5228c2ecf20Sopenharmony_ci len -= min(len, sg->length); 5238c2ecf20Sopenharmony_ci dev->hw_link[j]->next = dev->hw_phys_link[j + 1]; 5248c2ecf20Sopenharmony_ci sg = sg_next(sg); 5258c2ecf20Sopenharmony_ci } 5268c2ecf20Sopenharmony_ci } 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ci /* Fill remaining fields of hw_desc[1] */ 5298c2ecf20Sopenharmony_ci dev->hw_desc[idx]->hdr = sahara_aes_data_link_hdr(dev); 5308c2ecf20Sopenharmony_ci dev->hw_desc[idx]->len1 = dev->total; 5318c2ecf20Sopenharmony_ci dev->hw_desc[idx]->len2 = dev->total; 5328c2ecf20Sopenharmony_ci dev->hw_desc[idx]->next = 0; 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ci sahara_dump_descriptors(dev); 5358c2ecf20Sopenharmony_ci sahara_dump_links(dev); 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ci sahara_write(dev, dev->hw_phys_desc[0], SAHARA_REG_DAR); 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci return 0; 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_ciunmap_in: 5428c2ecf20Sopenharmony_ci dma_unmap_sg(dev->device, dev->in_sg, dev->nb_in_sg, 5438c2ecf20Sopenharmony_ci DMA_TO_DEVICE); 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_ci return -EINVAL; 5468c2ecf20Sopenharmony_ci} 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_cistatic void sahara_aes_cbc_update_iv(struct skcipher_request *req) 5498c2ecf20Sopenharmony_ci{ 5508c2ecf20Sopenharmony_ci struct crypto_skcipher *skcipher = crypto_skcipher_reqtfm(req); 5518c2ecf20Sopenharmony_ci struct sahara_aes_reqctx *rctx = skcipher_request_ctx(req); 5528c2ecf20Sopenharmony_ci unsigned int ivsize = crypto_skcipher_ivsize(skcipher); 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ci /* Update IV buffer to contain the last ciphertext block */ 5558c2ecf20Sopenharmony_ci if (rctx->mode & FLAGS_ENCRYPT) { 5568c2ecf20Sopenharmony_ci sg_pcopy_to_buffer(req->dst, sg_nents(req->dst), req->iv, 5578c2ecf20Sopenharmony_ci ivsize, req->cryptlen - ivsize); 5588c2ecf20Sopenharmony_ci } else { 5598c2ecf20Sopenharmony_ci memcpy(req->iv, rctx->iv_out, ivsize); 5608c2ecf20Sopenharmony_ci } 5618c2ecf20Sopenharmony_ci} 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_cistatic int sahara_aes_process(struct skcipher_request *req) 5648c2ecf20Sopenharmony_ci{ 5658c2ecf20Sopenharmony_ci struct crypto_skcipher *skcipher = crypto_skcipher_reqtfm(req); 5668c2ecf20Sopenharmony_ci struct sahara_dev *dev = dev_ptr; 5678c2ecf20Sopenharmony_ci struct sahara_ctx *ctx; 5688c2ecf20Sopenharmony_ci struct sahara_aes_reqctx *rctx; 5698c2ecf20Sopenharmony_ci int ret; 5708c2ecf20Sopenharmony_ci unsigned long timeout; 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_ci /* Request is ready to be dispatched by the device */ 5738c2ecf20Sopenharmony_ci dev_dbg(dev->device, 5748c2ecf20Sopenharmony_ci "dispatch request (nbytes=%d, src=%p, dst=%p)\n", 5758c2ecf20Sopenharmony_ci req->cryptlen, req->src, req->dst); 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci /* assign new request to device */ 5788c2ecf20Sopenharmony_ci dev->total = req->cryptlen; 5798c2ecf20Sopenharmony_ci dev->in_sg = req->src; 5808c2ecf20Sopenharmony_ci dev->out_sg = req->dst; 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_ci rctx = skcipher_request_ctx(req); 5838c2ecf20Sopenharmony_ci ctx = crypto_skcipher_ctx(crypto_skcipher_reqtfm(req)); 5848c2ecf20Sopenharmony_ci rctx->mode &= FLAGS_MODE_MASK; 5858c2ecf20Sopenharmony_ci dev->flags = (dev->flags & ~FLAGS_MODE_MASK) | rctx->mode; 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_ci if ((dev->flags & FLAGS_CBC) && req->iv) { 5888c2ecf20Sopenharmony_ci unsigned int ivsize = crypto_skcipher_ivsize(skcipher); 5898c2ecf20Sopenharmony_ci 5908c2ecf20Sopenharmony_ci memcpy(dev->iv_base, req->iv, ivsize); 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_ci if (!(dev->flags & FLAGS_ENCRYPT)) { 5938c2ecf20Sopenharmony_ci sg_pcopy_to_buffer(req->src, sg_nents(req->src), 5948c2ecf20Sopenharmony_ci rctx->iv_out, ivsize, 5958c2ecf20Sopenharmony_ci req->cryptlen - ivsize); 5968c2ecf20Sopenharmony_ci } 5978c2ecf20Sopenharmony_ci } 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_ci /* assign new context to device */ 6008c2ecf20Sopenharmony_ci dev->ctx = ctx; 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_ci reinit_completion(&dev->dma_completion); 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_ci ret = sahara_hw_descriptor_create(dev); 6058c2ecf20Sopenharmony_ci if (ret) 6068c2ecf20Sopenharmony_ci return -EINVAL; 6078c2ecf20Sopenharmony_ci 6088c2ecf20Sopenharmony_ci timeout = wait_for_completion_timeout(&dev->dma_completion, 6098c2ecf20Sopenharmony_ci msecs_to_jiffies(SAHARA_TIMEOUT_MS)); 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_ci dma_unmap_sg(dev->device, dev->out_sg, dev->nb_out_sg, 6128c2ecf20Sopenharmony_ci DMA_FROM_DEVICE); 6138c2ecf20Sopenharmony_ci dma_unmap_sg(dev->device, dev->in_sg, dev->nb_in_sg, 6148c2ecf20Sopenharmony_ci DMA_TO_DEVICE); 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci if (!timeout) { 6178c2ecf20Sopenharmony_ci dev_err(dev->device, "AES timeout\n"); 6188c2ecf20Sopenharmony_ci return -ETIMEDOUT; 6198c2ecf20Sopenharmony_ci } 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_ci if ((dev->flags & FLAGS_CBC) && req->iv) 6228c2ecf20Sopenharmony_ci sahara_aes_cbc_update_iv(req); 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_ci return 0; 6258c2ecf20Sopenharmony_ci} 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_cistatic int sahara_aes_setkey(struct crypto_skcipher *tfm, const u8 *key, 6288c2ecf20Sopenharmony_ci unsigned int keylen) 6298c2ecf20Sopenharmony_ci{ 6308c2ecf20Sopenharmony_ci struct sahara_ctx *ctx = crypto_skcipher_ctx(tfm); 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_ci ctx->keylen = keylen; 6338c2ecf20Sopenharmony_ci 6348c2ecf20Sopenharmony_ci /* SAHARA only supports 128bit keys */ 6358c2ecf20Sopenharmony_ci if (keylen == AES_KEYSIZE_128) { 6368c2ecf20Sopenharmony_ci memcpy(ctx->key, key, keylen); 6378c2ecf20Sopenharmony_ci return 0; 6388c2ecf20Sopenharmony_ci } 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_ci if (keylen != AES_KEYSIZE_192 && keylen != AES_KEYSIZE_256) 6418c2ecf20Sopenharmony_ci return -EINVAL; 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_ci /* 6448c2ecf20Sopenharmony_ci * The requested key size is not supported by HW, do a fallback. 6458c2ecf20Sopenharmony_ci */ 6468c2ecf20Sopenharmony_ci crypto_skcipher_clear_flags(ctx->fallback, CRYPTO_TFM_REQ_MASK); 6478c2ecf20Sopenharmony_ci crypto_skcipher_set_flags(ctx->fallback, tfm->base.crt_flags & 6488c2ecf20Sopenharmony_ci CRYPTO_TFM_REQ_MASK); 6498c2ecf20Sopenharmony_ci return crypto_skcipher_setkey(ctx->fallback, key, keylen); 6508c2ecf20Sopenharmony_ci} 6518c2ecf20Sopenharmony_ci 6528c2ecf20Sopenharmony_cistatic int sahara_aes_fallback(struct skcipher_request *req, unsigned long mode) 6538c2ecf20Sopenharmony_ci{ 6548c2ecf20Sopenharmony_ci struct sahara_aes_reqctx *rctx = skcipher_request_ctx(req); 6558c2ecf20Sopenharmony_ci struct sahara_ctx *ctx = crypto_skcipher_ctx( 6568c2ecf20Sopenharmony_ci crypto_skcipher_reqtfm(req)); 6578c2ecf20Sopenharmony_ci 6588c2ecf20Sopenharmony_ci skcipher_request_set_tfm(&rctx->fallback_req, ctx->fallback); 6598c2ecf20Sopenharmony_ci skcipher_request_set_callback(&rctx->fallback_req, 6608c2ecf20Sopenharmony_ci req->base.flags, 6618c2ecf20Sopenharmony_ci req->base.complete, 6628c2ecf20Sopenharmony_ci req->base.data); 6638c2ecf20Sopenharmony_ci skcipher_request_set_crypt(&rctx->fallback_req, req->src, 6648c2ecf20Sopenharmony_ci req->dst, req->cryptlen, req->iv); 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_ci if (mode & FLAGS_ENCRYPT) 6678c2ecf20Sopenharmony_ci return crypto_skcipher_encrypt(&rctx->fallback_req); 6688c2ecf20Sopenharmony_ci 6698c2ecf20Sopenharmony_ci return crypto_skcipher_decrypt(&rctx->fallback_req); 6708c2ecf20Sopenharmony_ci} 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_cistatic int sahara_aes_crypt(struct skcipher_request *req, unsigned long mode) 6738c2ecf20Sopenharmony_ci{ 6748c2ecf20Sopenharmony_ci struct sahara_aes_reqctx *rctx = skcipher_request_ctx(req); 6758c2ecf20Sopenharmony_ci struct sahara_ctx *ctx = crypto_skcipher_ctx( 6768c2ecf20Sopenharmony_ci crypto_skcipher_reqtfm(req)); 6778c2ecf20Sopenharmony_ci struct sahara_dev *dev = dev_ptr; 6788c2ecf20Sopenharmony_ci int err = 0; 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_ci if (!req->cryptlen) 6818c2ecf20Sopenharmony_ci return 0; 6828c2ecf20Sopenharmony_ci 6838c2ecf20Sopenharmony_ci if (unlikely(ctx->keylen != AES_KEYSIZE_128)) 6848c2ecf20Sopenharmony_ci return sahara_aes_fallback(req, mode); 6858c2ecf20Sopenharmony_ci 6868c2ecf20Sopenharmony_ci dev_dbg(dev->device, "nbytes: %d, enc: %d, cbc: %d\n", 6878c2ecf20Sopenharmony_ci req->cryptlen, !!(mode & FLAGS_ENCRYPT), !!(mode & FLAGS_CBC)); 6888c2ecf20Sopenharmony_ci 6898c2ecf20Sopenharmony_ci if (!IS_ALIGNED(req->cryptlen, AES_BLOCK_SIZE)) { 6908c2ecf20Sopenharmony_ci dev_err(dev->device, 6918c2ecf20Sopenharmony_ci "request size is not exact amount of AES blocks\n"); 6928c2ecf20Sopenharmony_ci return -EINVAL; 6938c2ecf20Sopenharmony_ci } 6948c2ecf20Sopenharmony_ci 6958c2ecf20Sopenharmony_ci rctx->mode = mode; 6968c2ecf20Sopenharmony_ci 6978c2ecf20Sopenharmony_ci spin_lock_bh(&dev->queue_spinlock); 6988c2ecf20Sopenharmony_ci err = crypto_enqueue_request(&dev->queue, &req->base); 6998c2ecf20Sopenharmony_ci spin_unlock_bh(&dev->queue_spinlock); 7008c2ecf20Sopenharmony_ci 7018c2ecf20Sopenharmony_ci wake_up_process(dev->kthread); 7028c2ecf20Sopenharmony_ci 7038c2ecf20Sopenharmony_ci return err; 7048c2ecf20Sopenharmony_ci} 7058c2ecf20Sopenharmony_ci 7068c2ecf20Sopenharmony_cistatic int sahara_aes_ecb_encrypt(struct skcipher_request *req) 7078c2ecf20Sopenharmony_ci{ 7088c2ecf20Sopenharmony_ci return sahara_aes_crypt(req, FLAGS_ENCRYPT); 7098c2ecf20Sopenharmony_ci} 7108c2ecf20Sopenharmony_ci 7118c2ecf20Sopenharmony_cistatic int sahara_aes_ecb_decrypt(struct skcipher_request *req) 7128c2ecf20Sopenharmony_ci{ 7138c2ecf20Sopenharmony_ci return sahara_aes_crypt(req, 0); 7148c2ecf20Sopenharmony_ci} 7158c2ecf20Sopenharmony_ci 7168c2ecf20Sopenharmony_cistatic int sahara_aes_cbc_encrypt(struct skcipher_request *req) 7178c2ecf20Sopenharmony_ci{ 7188c2ecf20Sopenharmony_ci return sahara_aes_crypt(req, FLAGS_ENCRYPT | FLAGS_CBC); 7198c2ecf20Sopenharmony_ci} 7208c2ecf20Sopenharmony_ci 7218c2ecf20Sopenharmony_cistatic int sahara_aes_cbc_decrypt(struct skcipher_request *req) 7228c2ecf20Sopenharmony_ci{ 7238c2ecf20Sopenharmony_ci return sahara_aes_crypt(req, FLAGS_CBC); 7248c2ecf20Sopenharmony_ci} 7258c2ecf20Sopenharmony_ci 7268c2ecf20Sopenharmony_cistatic int sahara_aes_init_tfm(struct crypto_skcipher *tfm) 7278c2ecf20Sopenharmony_ci{ 7288c2ecf20Sopenharmony_ci const char *name = crypto_tfm_alg_name(&tfm->base); 7298c2ecf20Sopenharmony_ci struct sahara_ctx *ctx = crypto_skcipher_ctx(tfm); 7308c2ecf20Sopenharmony_ci 7318c2ecf20Sopenharmony_ci ctx->fallback = crypto_alloc_skcipher(name, 0, 7328c2ecf20Sopenharmony_ci CRYPTO_ALG_NEED_FALLBACK); 7338c2ecf20Sopenharmony_ci if (IS_ERR(ctx->fallback)) { 7348c2ecf20Sopenharmony_ci pr_err("Error allocating fallback algo %s\n", name); 7358c2ecf20Sopenharmony_ci return PTR_ERR(ctx->fallback); 7368c2ecf20Sopenharmony_ci } 7378c2ecf20Sopenharmony_ci 7388c2ecf20Sopenharmony_ci crypto_skcipher_set_reqsize(tfm, sizeof(struct sahara_aes_reqctx) + 7398c2ecf20Sopenharmony_ci crypto_skcipher_reqsize(ctx->fallback)); 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_ci return 0; 7428c2ecf20Sopenharmony_ci} 7438c2ecf20Sopenharmony_ci 7448c2ecf20Sopenharmony_cistatic void sahara_aes_exit_tfm(struct crypto_skcipher *tfm) 7458c2ecf20Sopenharmony_ci{ 7468c2ecf20Sopenharmony_ci struct sahara_ctx *ctx = crypto_skcipher_ctx(tfm); 7478c2ecf20Sopenharmony_ci 7488c2ecf20Sopenharmony_ci crypto_free_skcipher(ctx->fallback); 7498c2ecf20Sopenharmony_ci} 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_cistatic u32 sahara_sha_init_hdr(struct sahara_dev *dev, 7528c2ecf20Sopenharmony_ci struct sahara_sha_reqctx *rctx) 7538c2ecf20Sopenharmony_ci{ 7548c2ecf20Sopenharmony_ci u32 hdr = 0; 7558c2ecf20Sopenharmony_ci 7568c2ecf20Sopenharmony_ci hdr = rctx->mode; 7578c2ecf20Sopenharmony_ci 7588c2ecf20Sopenharmony_ci if (rctx->first) { 7598c2ecf20Sopenharmony_ci hdr |= SAHARA_HDR_MDHA_SET_MODE_HASH; 7608c2ecf20Sopenharmony_ci hdr |= SAHARA_HDR_MDHA_INIT; 7618c2ecf20Sopenharmony_ci } else { 7628c2ecf20Sopenharmony_ci hdr |= SAHARA_HDR_MDHA_SET_MODE_MD_KEY; 7638c2ecf20Sopenharmony_ci } 7648c2ecf20Sopenharmony_ci 7658c2ecf20Sopenharmony_ci if (rctx->last) 7668c2ecf20Sopenharmony_ci hdr |= SAHARA_HDR_MDHA_PDATA; 7678c2ecf20Sopenharmony_ci 7688c2ecf20Sopenharmony_ci if (hweight_long(hdr) % 2 == 0) 7698c2ecf20Sopenharmony_ci hdr |= SAHARA_HDR_PARITY_BIT; 7708c2ecf20Sopenharmony_ci 7718c2ecf20Sopenharmony_ci return hdr; 7728c2ecf20Sopenharmony_ci} 7738c2ecf20Sopenharmony_ci 7748c2ecf20Sopenharmony_cistatic int sahara_sha_hw_links_create(struct sahara_dev *dev, 7758c2ecf20Sopenharmony_ci struct sahara_sha_reqctx *rctx, 7768c2ecf20Sopenharmony_ci int start) 7778c2ecf20Sopenharmony_ci{ 7788c2ecf20Sopenharmony_ci struct scatterlist *sg; 7798c2ecf20Sopenharmony_ci unsigned int len; 7808c2ecf20Sopenharmony_ci unsigned int i; 7818c2ecf20Sopenharmony_ci int ret; 7828c2ecf20Sopenharmony_ci 7838c2ecf20Sopenharmony_ci dev->in_sg = rctx->in_sg; 7848c2ecf20Sopenharmony_ci 7858c2ecf20Sopenharmony_ci dev->nb_in_sg = sg_nents_for_len(dev->in_sg, rctx->total); 7868c2ecf20Sopenharmony_ci if (dev->nb_in_sg < 0) { 7878c2ecf20Sopenharmony_ci dev_err(dev->device, "Invalid numbers of src SG.\n"); 7888c2ecf20Sopenharmony_ci return dev->nb_in_sg; 7898c2ecf20Sopenharmony_ci } 7908c2ecf20Sopenharmony_ci if ((dev->nb_in_sg) > SAHARA_MAX_HW_LINK) { 7918c2ecf20Sopenharmony_ci dev_err(dev->device, "not enough hw links (%d)\n", 7928c2ecf20Sopenharmony_ci dev->nb_in_sg + dev->nb_out_sg); 7938c2ecf20Sopenharmony_ci return -EINVAL; 7948c2ecf20Sopenharmony_ci } 7958c2ecf20Sopenharmony_ci 7968c2ecf20Sopenharmony_ci sg = dev->in_sg; 7978c2ecf20Sopenharmony_ci ret = dma_map_sg(dev->device, dev->in_sg, dev->nb_in_sg, DMA_TO_DEVICE); 7988c2ecf20Sopenharmony_ci if (!ret) 7998c2ecf20Sopenharmony_ci return -EFAULT; 8008c2ecf20Sopenharmony_ci 8018c2ecf20Sopenharmony_ci len = rctx->total; 8028c2ecf20Sopenharmony_ci for (i = start; i < dev->nb_in_sg + start; i++) { 8038c2ecf20Sopenharmony_ci dev->hw_link[i]->len = min(len, sg->length); 8048c2ecf20Sopenharmony_ci dev->hw_link[i]->p = sg->dma_address; 8058c2ecf20Sopenharmony_ci if (i == (dev->nb_in_sg + start - 1)) { 8068c2ecf20Sopenharmony_ci dev->hw_link[i]->next = 0; 8078c2ecf20Sopenharmony_ci } else { 8088c2ecf20Sopenharmony_ci len -= min(len, sg->length); 8098c2ecf20Sopenharmony_ci dev->hw_link[i]->next = dev->hw_phys_link[i + 1]; 8108c2ecf20Sopenharmony_ci sg = sg_next(sg); 8118c2ecf20Sopenharmony_ci } 8128c2ecf20Sopenharmony_ci } 8138c2ecf20Sopenharmony_ci 8148c2ecf20Sopenharmony_ci return i; 8158c2ecf20Sopenharmony_ci} 8168c2ecf20Sopenharmony_ci 8178c2ecf20Sopenharmony_cistatic int sahara_sha_hw_data_descriptor_create(struct sahara_dev *dev, 8188c2ecf20Sopenharmony_ci struct sahara_sha_reqctx *rctx, 8198c2ecf20Sopenharmony_ci struct ahash_request *req, 8208c2ecf20Sopenharmony_ci int index) 8218c2ecf20Sopenharmony_ci{ 8228c2ecf20Sopenharmony_ci unsigned result_len; 8238c2ecf20Sopenharmony_ci int i = index; 8248c2ecf20Sopenharmony_ci 8258c2ecf20Sopenharmony_ci if (rctx->first) 8268c2ecf20Sopenharmony_ci /* Create initial descriptor: #8*/ 8278c2ecf20Sopenharmony_ci dev->hw_desc[index]->hdr = sahara_sha_init_hdr(dev, rctx); 8288c2ecf20Sopenharmony_ci else 8298c2ecf20Sopenharmony_ci /* Create hash descriptor: #10. Must follow #6. */ 8308c2ecf20Sopenharmony_ci dev->hw_desc[index]->hdr = SAHARA_HDR_MDHA_HASH; 8318c2ecf20Sopenharmony_ci 8328c2ecf20Sopenharmony_ci dev->hw_desc[index]->len1 = rctx->total; 8338c2ecf20Sopenharmony_ci if (dev->hw_desc[index]->len1 == 0) { 8348c2ecf20Sopenharmony_ci /* if len1 is 0, p1 must be 0, too */ 8358c2ecf20Sopenharmony_ci dev->hw_desc[index]->p1 = 0; 8368c2ecf20Sopenharmony_ci rctx->sg_in_idx = 0; 8378c2ecf20Sopenharmony_ci } else { 8388c2ecf20Sopenharmony_ci /* Create input links */ 8398c2ecf20Sopenharmony_ci dev->hw_desc[index]->p1 = dev->hw_phys_link[index]; 8408c2ecf20Sopenharmony_ci i = sahara_sha_hw_links_create(dev, rctx, index); 8418c2ecf20Sopenharmony_ci 8428c2ecf20Sopenharmony_ci rctx->sg_in_idx = index; 8438c2ecf20Sopenharmony_ci if (i < 0) 8448c2ecf20Sopenharmony_ci return i; 8458c2ecf20Sopenharmony_ci } 8468c2ecf20Sopenharmony_ci 8478c2ecf20Sopenharmony_ci dev->hw_desc[index]->p2 = dev->hw_phys_link[i]; 8488c2ecf20Sopenharmony_ci 8498c2ecf20Sopenharmony_ci /* Save the context for the next operation */ 8508c2ecf20Sopenharmony_ci result_len = rctx->context_size; 8518c2ecf20Sopenharmony_ci dev->hw_link[i]->p = dev->context_phys_base; 8528c2ecf20Sopenharmony_ci 8538c2ecf20Sopenharmony_ci dev->hw_link[i]->len = result_len; 8548c2ecf20Sopenharmony_ci dev->hw_desc[index]->len2 = result_len; 8558c2ecf20Sopenharmony_ci 8568c2ecf20Sopenharmony_ci dev->hw_link[i]->next = 0; 8578c2ecf20Sopenharmony_ci 8588c2ecf20Sopenharmony_ci return 0; 8598c2ecf20Sopenharmony_ci} 8608c2ecf20Sopenharmony_ci 8618c2ecf20Sopenharmony_ci/* 8628c2ecf20Sopenharmony_ci * Load descriptor aka #6 8638c2ecf20Sopenharmony_ci * 8648c2ecf20Sopenharmony_ci * To load a previously saved context back to the MDHA unit 8658c2ecf20Sopenharmony_ci * 8668c2ecf20Sopenharmony_ci * p1: Saved Context 8678c2ecf20Sopenharmony_ci * p2: NULL 8688c2ecf20Sopenharmony_ci * 8698c2ecf20Sopenharmony_ci */ 8708c2ecf20Sopenharmony_cistatic int sahara_sha_hw_context_descriptor_create(struct sahara_dev *dev, 8718c2ecf20Sopenharmony_ci struct sahara_sha_reqctx *rctx, 8728c2ecf20Sopenharmony_ci struct ahash_request *req, 8738c2ecf20Sopenharmony_ci int index) 8748c2ecf20Sopenharmony_ci{ 8758c2ecf20Sopenharmony_ci dev->hw_desc[index]->hdr = sahara_sha_init_hdr(dev, rctx); 8768c2ecf20Sopenharmony_ci 8778c2ecf20Sopenharmony_ci dev->hw_desc[index]->len1 = rctx->context_size; 8788c2ecf20Sopenharmony_ci dev->hw_desc[index]->p1 = dev->hw_phys_link[index]; 8798c2ecf20Sopenharmony_ci dev->hw_desc[index]->len2 = 0; 8808c2ecf20Sopenharmony_ci dev->hw_desc[index]->p2 = 0; 8818c2ecf20Sopenharmony_ci 8828c2ecf20Sopenharmony_ci dev->hw_link[index]->len = rctx->context_size; 8838c2ecf20Sopenharmony_ci dev->hw_link[index]->p = dev->context_phys_base; 8848c2ecf20Sopenharmony_ci dev->hw_link[index]->next = 0; 8858c2ecf20Sopenharmony_ci 8868c2ecf20Sopenharmony_ci return 0; 8878c2ecf20Sopenharmony_ci} 8888c2ecf20Sopenharmony_ci 8898c2ecf20Sopenharmony_cistatic int sahara_sha_prepare_request(struct ahash_request *req) 8908c2ecf20Sopenharmony_ci{ 8918c2ecf20Sopenharmony_ci struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); 8928c2ecf20Sopenharmony_ci struct sahara_sha_reqctx *rctx = ahash_request_ctx(req); 8938c2ecf20Sopenharmony_ci unsigned int hash_later; 8948c2ecf20Sopenharmony_ci unsigned int block_size; 8958c2ecf20Sopenharmony_ci unsigned int len; 8968c2ecf20Sopenharmony_ci 8978c2ecf20Sopenharmony_ci block_size = crypto_tfm_alg_blocksize(crypto_ahash_tfm(tfm)); 8988c2ecf20Sopenharmony_ci 8998c2ecf20Sopenharmony_ci /* append bytes from previous operation */ 9008c2ecf20Sopenharmony_ci len = rctx->buf_cnt + req->nbytes; 9018c2ecf20Sopenharmony_ci 9028c2ecf20Sopenharmony_ci /* only the last transfer can be padded in hardware */ 9038c2ecf20Sopenharmony_ci if (!rctx->last && (len < block_size)) { 9048c2ecf20Sopenharmony_ci /* to few data, save for next operation */ 9058c2ecf20Sopenharmony_ci scatterwalk_map_and_copy(rctx->buf + rctx->buf_cnt, req->src, 9068c2ecf20Sopenharmony_ci 0, req->nbytes, 0); 9078c2ecf20Sopenharmony_ci rctx->buf_cnt += req->nbytes; 9088c2ecf20Sopenharmony_ci 9098c2ecf20Sopenharmony_ci return 0; 9108c2ecf20Sopenharmony_ci } 9118c2ecf20Sopenharmony_ci 9128c2ecf20Sopenharmony_ci /* add data from previous operation first */ 9138c2ecf20Sopenharmony_ci if (rctx->buf_cnt) 9148c2ecf20Sopenharmony_ci memcpy(rctx->rembuf, rctx->buf, rctx->buf_cnt); 9158c2ecf20Sopenharmony_ci 9168c2ecf20Sopenharmony_ci /* data must always be a multiple of block_size */ 9178c2ecf20Sopenharmony_ci hash_later = rctx->last ? 0 : len & (block_size - 1); 9188c2ecf20Sopenharmony_ci if (hash_later) { 9198c2ecf20Sopenharmony_ci unsigned int offset = req->nbytes - hash_later; 9208c2ecf20Sopenharmony_ci /* Save remaining bytes for later use */ 9218c2ecf20Sopenharmony_ci scatterwalk_map_and_copy(rctx->buf, req->src, offset, 9228c2ecf20Sopenharmony_ci hash_later, 0); 9238c2ecf20Sopenharmony_ci } 9248c2ecf20Sopenharmony_ci 9258c2ecf20Sopenharmony_ci rctx->total = len - hash_later; 9268c2ecf20Sopenharmony_ci /* have data from previous operation and current */ 9278c2ecf20Sopenharmony_ci if (rctx->buf_cnt && req->nbytes) { 9288c2ecf20Sopenharmony_ci sg_init_table(rctx->in_sg_chain, 2); 9298c2ecf20Sopenharmony_ci sg_set_buf(rctx->in_sg_chain, rctx->rembuf, rctx->buf_cnt); 9308c2ecf20Sopenharmony_ci sg_chain(rctx->in_sg_chain, 2, req->src); 9318c2ecf20Sopenharmony_ci rctx->in_sg = rctx->in_sg_chain; 9328c2ecf20Sopenharmony_ci /* only data from previous operation */ 9338c2ecf20Sopenharmony_ci } else if (rctx->buf_cnt) { 9348c2ecf20Sopenharmony_ci rctx->in_sg = rctx->in_sg_chain; 9358c2ecf20Sopenharmony_ci sg_init_one(rctx->in_sg, rctx->rembuf, rctx->buf_cnt); 9368c2ecf20Sopenharmony_ci /* no data from previous operation */ 9378c2ecf20Sopenharmony_ci } else { 9388c2ecf20Sopenharmony_ci rctx->in_sg = req->src; 9398c2ecf20Sopenharmony_ci } 9408c2ecf20Sopenharmony_ci 9418c2ecf20Sopenharmony_ci /* on next call, we only have the remaining data in the buffer */ 9428c2ecf20Sopenharmony_ci rctx->buf_cnt = hash_later; 9438c2ecf20Sopenharmony_ci 9448c2ecf20Sopenharmony_ci return -EINPROGRESS; 9458c2ecf20Sopenharmony_ci} 9468c2ecf20Sopenharmony_ci 9478c2ecf20Sopenharmony_cistatic int sahara_sha_process(struct ahash_request *req) 9488c2ecf20Sopenharmony_ci{ 9498c2ecf20Sopenharmony_ci struct sahara_dev *dev = dev_ptr; 9508c2ecf20Sopenharmony_ci struct sahara_sha_reqctx *rctx = ahash_request_ctx(req); 9518c2ecf20Sopenharmony_ci int ret; 9528c2ecf20Sopenharmony_ci unsigned long timeout; 9538c2ecf20Sopenharmony_ci 9548c2ecf20Sopenharmony_ci ret = sahara_sha_prepare_request(req); 9558c2ecf20Sopenharmony_ci if (!ret) 9568c2ecf20Sopenharmony_ci return ret; 9578c2ecf20Sopenharmony_ci 9588c2ecf20Sopenharmony_ci if (rctx->first) { 9598c2ecf20Sopenharmony_ci ret = sahara_sha_hw_data_descriptor_create(dev, rctx, req, 0); 9608c2ecf20Sopenharmony_ci if (ret) 9618c2ecf20Sopenharmony_ci return ret; 9628c2ecf20Sopenharmony_ci 9638c2ecf20Sopenharmony_ci dev->hw_desc[0]->next = 0; 9648c2ecf20Sopenharmony_ci rctx->first = 0; 9658c2ecf20Sopenharmony_ci } else { 9668c2ecf20Sopenharmony_ci memcpy(dev->context_base, rctx->context, rctx->context_size); 9678c2ecf20Sopenharmony_ci 9688c2ecf20Sopenharmony_ci sahara_sha_hw_context_descriptor_create(dev, rctx, req, 0); 9698c2ecf20Sopenharmony_ci dev->hw_desc[0]->next = dev->hw_phys_desc[1]; 9708c2ecf20Sopenharmony_ci ret = sahara_sha_hw_data_descriptor_create(dev, rctx, req, 1); 9718c2ecf20Sopenharmony_ci if (ret) 9728c2ecf20Sopenharmony_ci return ret; 9738c2ecf20Sopenharmony_ci 9748c2ecf20Sopenharmony_ci dev->hw_desc[1]->next = 0; 9758c2ecf20Sopenharmony_ci } 9768c2ecf20Sopenharmony_ci 9778c2ecf20Sopenharmony_ci sahara_dump_descriptors(dev); 9788c2ecf20Sopenharmony_ci sahara_dump_links(dev); 9798c2ecf20Sopenharmony_ci 9808c2ecf20Sopenharmony_ci reinit_completion(&dev->dma_completion); 9818c2ecf20Sopenharmony_ci 9828c2ecf20Sopenharmony_ci sahara_write(dev, dev->hw_phys_desc[0], SAHARA_REG_DAR); 9838c2ecf20Sopenharmony_ci 9848c2ecf20Sopenharmony_ci timeout = wait_for_completion_timeout(&dev->dma_completion, 9858c2ecf20Sopenharmony_ci msecs_to_jiffies(SAHARA_TIMEOUT_MS)); 9868c2ecf20Sopenharmony_ci 9878c2ecf20Sopenharmony_ci if (rctx->sg_in_idx) 9888c2ecf20Sopenharmony_ci dma_unmap_sg(dev->device, dev->in_sg, dev->nb_in_sg, 9898c2ecf20Sopenharmony_ci DMA_TO_DEVICE); 9908c2ecf20Sopenharmony_ci 9918c2ecf20Sopenharmony_ci if (!timeout) { 9928c2ecf20Sopenharmony_ci dev_err(dev->device, "SHA timeout\n"); 9938c2ecf20Sopenharmony_ci return -ETIMEDOUT; 9948c2ecf20Sopenharmony_ci } 9958c2ecf20Sopenharmony_ci 9968c2ecf20Sopenharmony_ci memcpy(rctx->context, dev->context_base, rctx->context_size); 9978c2ecf20Sopenharmony_ci 9988c2ecf20Sopenharmony_ci if (req->result && rctx->last) 9998c2ecf20Sopenharmony_ci memcpy(req->result, rctx->context, rctx->digest_size); 10008c2ecf20Sopenharmony_ci 10018c2ecf20Sopenharmony_ci return 0; 10028c2ecf20Sopenharmony_ci} 10038c2ecf20Sopenharmony_ci 10048c2ecf20Sopenharmony_cistatic int sahara_queue_manage(void *data) 10058c2ecf20Sopenharmony_ci{ 10068c2ecf20Sopenharmony_ci struct sahara_dev *dev = (struct sahara_dev *)data; 10078c2ecf20Sopenharmony_ci struct crypto_async_request *async_req; 10088c2ecf20Sopenharmony_ci struct crypto_async_request *backlog; 10098c2ecf20Sopenharmony_ci int ret = 0; 10108c2ecf20Sopenharmony_ci 10118c2ecf20Sopenharmony_ci do { 10128c2ecf20Sopenharmony_ci __set_current_state(TASK_INTERRUPTIBLE); 10138c2ecf20Sopenharmony_ci 10148c2ecf20Sopenharmony_ci spin_lock_bh(&dev->queue_spinlock); 10158c2ecf20Sopenharmony_ci backlog = crypto_get_backlog(&dev->queue); 10168c2ecf20Sopenharmony_ci async_req = crypto_dequeue_request(&dev->queue); 10178c2ecf20Sopenharmony_ci spin_unlock_bh(&dev->queue_spinlock); 10188c2ecf20Sopenharmony_ci 10198c2ecf20Sopenharmony_ci if (backlog) 10208c2ecf20Sopenharmony_ci backlog->complete(backlog, -EINPROGRESS); 10218c2ecf20Sopenharmony_ci 10228c2ecf20Sopenharmony_ci if (async_req) { 10238c2ecf20Sopenharmony_ci if (crypto_tfm_alg_type(async_req->tfm) == 10248c2ecf20Sopenharmony_ci CRYPTO_ALG_TYPE_AHASH) { 10258c2ecf20Sopenharmony_ci struct ahash_request *req = 10268c2ecf20Sopenharmony_ci ahash_request_cast(async_req); 10278c2ecf20Sopenharmony_ci 10288c2ecf20Sopenharmony_ci ret = sahara_sha_process(req); 10298c2ecf20Sopenharmony_ci } else { 10308c2ecf20Sopenharmony_ci struct skcipher_request *req = 10318c2ecf20Sopenharmony_ci skcipher_request_cast(async_req); 10328c2ecf20Sopenharmony_ci 10338c2ecf20Sopenharmony_ci ret = sahara_aes_process(req); 10348c2ecf20Sopenharmony_ci } 10358c2ecf20Sopenharmony_ci 10368c2ecf20Sopenharmony_ci async_req->complete(async_req, ret); 10378c2ecf20Sopenharmony_ci 10388c2ecf20Sopenharmony_ci continue; 10398c2ecf20Sopenharmony_ci } 10408c2ecf20Sopenharmony_ci 10418c2ecf20Sopenharmony_ci schedule(); 10428c2ecf20Sopenharmony_ci } while (!kthread_should_stop()); 10438c2ecf20Sopenharmony_ci 10448c2ecf20Sopenharmony_ci return 0; 10458c2ecf20Sopenharmony_ci} 10468c2ecf20Sopenharmony_ci 10478c2ecf20Sopenharmony_cistatic int sahara_sha_enqueue(struct ahash_request *req, int last) 10488c2ecf20Sopenharmony_ci{ 10498c2ecf20Sopenharmony_ci struct sahara_sha_reqctx *rctx = ahash_request_ctx(req); 10508c2ecf20Sopenharmony_ci struct sahara_dev *dev = dev_ptr; 10518c2ecf20Sopenharmony_ci int ret; 10528c2ecf20Sopenharmony_ci 10538c2ecf20Sopenharmony_ci if (!req->nbytes && !last) 10548c2ecf20Sopenharmony_ci return 0; 10558c2ecf20Sopenharmony_ci 10568c2ecf20Sopenharmony_ci rctx->last = last; 10578c2ecf20Sopenharmony_ci 10588c2ecf20Sopenharmony_ci if (!rctx->active) { 10598c2ecf20Sopenharmony_ci rctx->active = 1; 10608c2ecf20Sopenharmony_ci rctx->first = 1; 10618c2ecf20Sopenharmony_ci } 10628c2ecf20Sopenharmony_ci 10638c2ecf20Sopenharmony_ci spin_lock_bh(&dev->queue_spinlock); 10648c2ecf20Sopenharmony_ci ret = crypto_enqueue_request(&dev->queue, &req->base); 10658c2ecf20Sopenharmony_ci spin_unlock_bh(&dev->queue_spinlock); 10668c2ecf20Sopenharmony_ci 10678c2ecf20Sopenharmony_ci wake_up_process(dev->kthread); 10688c2ecf20Sopenharmony_ci 10698c2ecf20Sopenharmony_ci return ret; 10708c2ecf20Sopenharmony_ci} 10718c2ecf20Sopenharmony_ci 10728c2ecf20Sopenharmony_cistatic int sahara_sha_init(struct ahash_request *req) 10738c2ecf20Sopenharmony_ci{ 10748c2ecf20Sopenharmony_ci struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); 10758c2ecf20Sopenharmony_ci struct sahara_sha_reqctx *rctx = ahash_request_ctx(req); 10768c2ecf20Sopenharmony_ci 10778c2ecf20Sopenharmony_ci memset(rctx, 0, sizeof(*rctx)); 10788c2ecf20Sopenharmony_ci 10798c2ecf20Sopenharmony_ci switch (crypto_ahash_digestsize(tfm)) { 10808c2ecf20Sopenharmony_ci case SHA1_DIGEST_SIZE: 10818c2ecf20Sopenharmony_ci rctx->mode |= SAHARA_HDR_MDHA_ALG_SHA1; 10828c2ecf20Sopenharmony_ci rctx->digest_size = SHA1_DIGEST_SIZE; 10838c2ecf20Sopenharmony_ci break; 10848c2ecf20Sopenharmony_ci case SHA256_DIGEST_SIZE: 10858c2ecf20Sopenharmony_ci rctx->mode |= SAHARA_HDR_MDHA_ALG_SHA256; 10868c2ecf20Sopenharmony_ci rctx->digest_size = SHA256_DIGEST_SIZE; 10878c2ecf20Sopenharmony_ci break; 10888c2ecf20Sopenharmony_ci default: 10898c2ecf20Sopenharmony_ci return -EINVAL; 10908c2ecf20Sopenharmony_ci } 10918c2ecf20Sopenharmony_ci 10928c2ecf20Sopenharmony_ci rctx->context_size = rctx->digest_size + 4; 10938c2ecf20Sopenharmony_ci rctx->active = 0; 10948c2ecf20Sopenharmony_ci 10958c2ecf20Sopenharmony_ci return 0; 10968c2ecf20Sopenharmony_ci} 10978c2ecf20Sopenharmony_ci 10988c2ecf20Sopenharmony_cistatic int sahara_sha_update(struct ahash_request *req) 10998c2ecf20Sopenharmony_ci{ 11008c2ecf20Sopenharmony_ci return sahara_sha_enqueue(req, 0); 11018c2ecf20Sopenharmony_ci} 11028c2ecf20Sopenharmony_ci 11038c2ecf20Sopenharmony_cistatic int sahara_sha_final(struct ahash_request *req) 11048c2ecf20Sopenharmony_ci{ 11058c2ecf20Sopenharmony_ci req->nbytes = 0; 11068c2ecf20Sopenharmony_ci return sahara_sha_enqueue(req, 1); 11078c2ecf20Sopenharmony_ci} 11088c2ecf20Sopenharmony_ci 11098c2ecf20Sopenharmony_cistatic int sahara_sha_finup(struct ahash_request *req) 11108c2ecf20Sopenharmony_ci{ 11118c2ecf20Sopenharmony_ci return sahara_sha_enqueue(req, 1); 11128c2ecf20Sopenharmony_ci} 11138c2ecf20Sopenharmony_ci 11148c2ecf20Sopenharmony_cistatic int sahara_sha_digest(struct ahash_request *req) 11158c2ecf20Sopenharmony_ci{ 11168c2ecf20Sopenharmony_ci sahara_sha_init(req); 11178c2ecf20Sopenharmony_ci 11188c2ecf20Sopenharmony_ci return sahara_sha_finup(req); 11198c2ecf20Sopenharmony_ci} 11208c2ecf20Sopenharmony_ci 11218c2ecf20Sopenharmony_cistatic int sahara_sha_export(struct ahash_request *req, void *out) 11228c2ecf20Sopenharmony_ci{ 11238c2ecf20Sopenharmony_ci struct sahara_sha_reqctx *rctx = ahash_request_ctx(req); 11248c2ecf20Sopenharmony_ci 11258c2ecf20Sopenharmony_ci memcpy(out, rctx, sizeof(struct sahara_sha_reqctx)); 11268c2ecf20Sopenharmony_ci 11278c2ecf20Sopenharmony_ci return 0; 11288c2ecf20Sopenharmony_ci} 11298c2ecf20Sopenharmony_ci 11308c2ecf20Sopenharmony_cistatic int sahara_sha_import(struct ahash_request *req, const void *in) 11318c2ecf20Sopenharmony_ci{ 11328c2ecf20Sopenharmony_ci struct sahara_sha_reqctx *rctx = ahash_request_ctx(req); 11338c2ecf20Sopenharmony_ci 11348c2ecf20Sopenharmony_ci memcpy(rctx, in, sizeof(struct sahara_sha_reqctx)); 11358c2ecf20Sopenharmony_ci 11368c2ecf20Sopenharmony_ci return 0; 11378c2ecf20Sopenharmony_ci} 11388c2ecf20Sopenharmony_ci 11398c2ecf20Sopenharmony_cistatic int sahara_sha_cra_init(struct crypto_tfm *tfm) 11408c2ecf20Sopenharmony_ci{ 11418c2ecf20Sopenharmony_ci crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm), 11428c2ecf20Sopenharmony_ci sizeof(struct sahara_sha_reqctx)); 11438c2ecf20Sopenharmony_ci 11448c2ecf20Sopenharmony_ci return 0; 11458c2ecf20Sopenharmony_ci} 11468c2ecf20Sopenharmony_ci 11478c2ecf20Sopenharmony_cistatic struct skcipher_alg aes_algs[] = { 11488c2ecf20Sopenharmony_ci{ 11498c2ecf20Sopenharmony_ci .base.cra_name = "ecb(aes)", 11508c2ecf20Sopenharmony_ci .base.cra_driver_name = "sahara-ecb-aes", 11518c2ecf20Sopenharmony_ci .base.cra_priority = 300, 11528c2ecf20Sopenharmony_ci .base.cra_flags = CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK, 11538c2ecf20Sopenharmony_ci .base.cra_blocksize = AES_BLOCK_SIZE, 11548c2ecf20Sopenharmony_ci .base.cra_ctxsize = sizeof(struct sahara_ctx), 11558c2ecf20Sopenharmony_ci .base.cra_alignmask = 0x0, 11568c2ecf20Sopenharmony_ci .base.cra_module = THIS_MODULE, 11578c2ecf20Sopenharmony_ci 11588c2ecf20Sopenharmony_ci .init = sahara_aes_init_tfm, 11598c2ecf20Sopenharmony_ci .exit = sahara_aes_exit_tfm, 11608c2ecf20Sopenharmony_ci .min_keysize = AES_MIN_KEY_SIZE , 11618c2ecf20Sopenharmony_ci .max_keysize = AES_MAX_KEY_SIZE, 11628c2ecf20Sopenharmony_ci .setkey = sahara_aes_setkey, 11638c2ecf20Sopenharmony_ci .encrypt = sahara_aes_ecb_encrypt, 11648c2ecf20Sopenharmony_ci .decrypt = sahara_aes_ecb_decrypt, 11658c2ecf20Sopenharmony_ci}, { 11668c2ecf20Sopenharmony_ci .base.cra_name = "cbc(aes)", 11678c2ecf20Sopenharmony_ci .base.cra_driver_name = "sahara-cbc-aes", 11688c2ecf20Sopenharmony_ci .base.cra_priority = 300, 11698c2ecf20Sopenharmony_ci .base.cra_flags = CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK, 11708c2ecf20Sopenharmony_ci .base.cra_blocksize = AES_BLOCK_SIZE, 11718c2ecf20Sopenharmony_ci .base.cra_ctxsize = sizeof(struct sahara_ctx), 11728c2ecf20Sopenharmony_ci .base.cra_alignmask = 0x0, 11738c2ecf20Sopenharmony_ci .base.cra_module = THIS_MODULE, 11748c2ecf20Sopenharmony_ci 11758c2ecf20Sopenharmony_ci .init = sahara_aes_init_tfm, 11768c2ecf20Sopenharmony_ci .exit = sahara_aes_exit_tfm, 11778c2ecf20Sopenharmony_ci .min_keysize = AES_MIN_KEY_SIZE , 11788c2ecf20Sopenharmony_ci .max_keysize = AES_MAX_KEY_SIZE, 11798c2ecf20Sopenharmony_ci .ivsize = AES_BLOCK_SIZE, 11808c2ecf20Sopenharmony_ci .setkey = sahara_aes_setkey, 11818c2ecf20Sopenharmony_ci .encrypt = sahara_aes_cbc_encrypt, 11828c2ecf20Sopenharmony_ci .decrypt = sahara_aes_cbc_decrypt, 11838c2ecf20Sopenharmony_ci} 11848c2ecf20Sopenharmony_ci}; 11858c2ecf20Sopenharmony_ci 11868c2ecf20Sopenharmony_cistatic struct ahash_alg sha_v3_algs[] = { 11878c2ecf20Sopenharmony_ci{ 11888c2ecf20Sopenharmony_ci .init = sahara_sha_init, 11898c2ecf20Sopenharmony_ci .update = sahara_sha_update, 11908c2ecf20Sopenharmony_ci .final = sahara_sha_final, 11918c2ecf20Sopenharmony_ci .finup = sahara_sha_finup, 11928c2ecf20Sopenharmony_ci .digest = sahara_sha_digest, 11938c2ecf20Sopenharmony_ci .export = sahara_sha_export, 11948c2ecf20Sopenharmony_ci .import = sahara_sha_import, 11958c2ecf20Sopenharmony_ci .halg.digestsize = SHA1_DIGEST_SIZE, 11968c2ecf20Sopenharmony_ci .halg.statesize = sizeof(struct sahara_sha_reqctx), 11978c2ecf20Sopenharmony_ci .halg.base = { 11988c2ecf20Sopenharmony_ci .cra_name = "sha1", 11998c2ecf20Sopenharmony_ci .cra_driver_name = "sahara-sha1", 12008c2ecf20Sopenharmony_ci .cra_priority = 300, 12018c2ecf20Sopenharmony_ci .cra_flags = CRYPTO_ALG_ASYNC | 12028c2ecf20Sopenharmony_ci CRYPTO_ALG_NEED_FALLBACK, 12038c2ecf20Sopenharmony_ci .cra_blocksize = SHA1_BLOCK_SIZE, 12048c2ecf20Sopenharmony_ci .cra_ctxsize = sizeof(struct sahara_ctx), 12058c2ecf20Sopenharmony_ci .cra_alignmask = 0, 12068c2ecf20Sopenharmony_ci .cra_module = THIS_MODULE, 12078c2ecf20Sopenharmony_ci .cra_init = sahara_sha_cra_init, 12088c2ecf20Sopenharmony_ci } 12098c2ecf20Sopenharmony_ci}, 12108c2ecf20Sopenharmony_ci}; 12118c2ecf20Sopenharmony_ci 12128c2ecf20Sopenharmony_cistatic struct ahash_alg sha_v4_algs[] = { 12138c2ecf20Sopenharmony_ci{ 12148c2ecf20Sopenharmony_ci .init = sahara_sha_init, 12158c2ecf20Sopenharmony_ci .update = sahara_sha_update, 12168c2ecf20Sopenharmony_ci .final = sahara_sha_final, 12178c2ecf20Sopenharmony_ci .finup = sahara_sha_finup, 12188c2ecf20Sopenharmony_ci .digest = sahara_sha_digest, 12198c2ecf20Sopenharmony_ci .export = sahara_sha_export, 12208c2ecf20Sopenharmony_ci .import = sahara_sha_import, 12218c2ecf20Sopenharmony_ci .halg.digestsize = SHA256_DIGEST_SIZE, 12228c2ecf20Sopenharmony_ci .halg.statesize = sizeof(struct sahara_sha_reqctx), 12238c2ecf20Sopenharmony_ci .halg.base = { 12248c2ecf20Sopenharmony_ci .cra_name = "sha256", 12258c2ecf20Sopenharmony_ci .cra_driver_name = "sahara-sha256", 12268c2ecf20Sopenharmony_ci .cra_priority = 300, 12278c2ecf20Sopenharmony_ci .cra_flags = CRYPTO_ALG_ASYNC | 12288c2ecf20Sopenharmony_ci CRYPTO_ALG_NEED_FALLBACK, 12298c2ecf20Sopenharmony_ci .cra_blocksize = SHA256_BLOCK_SIZE, 12308c2ecf20Sopenharmony_ci .cra_ctxsize = sizeof(struct sahara_ctx), 12318c2ecf20Sopenharmony_ci .cra_alignmask = 0, 12328c2ecf20Sopenharmony_ci .cra_module = THIS_MODULE, 12338c2ecf20Sopenharmony_ci .cra_init = sahara_sha_cra_init, 12348c2ecf20Sopenharmony_ci } 12358c2ecf20Sopenharmony_ci}, 12368c2ecf20Sopenharmony_ci}; 12378c2ecf20Sopenharmony_ci 12388c2ecf20Sopenharmony_cistatic irqreturn_t sahara_irq_handler(int irq, void *data) 12398c2ecf20Sopenharmony_ci{ 12408c2ecf20Sopenharmony_ci struct sahara_dev *dev = (struct sahara_dev *)data; 12418c2ecf20Sopenharmony_ci unsigned int stat = sahara_read(dev, SAHARA_REG_STATUS); 12428c2ecf20Sopenharmony_ci unsigned int err = sahara_read(dev, SAHARA_REG_ERRSTATUS); 12438c2ecf20Sopenharmony_ci 12448c2ecf20Sopenharmony_ci sahara_write(dev, SAHARA_CMD_CLEAR_INT | SAHARA_CMD_CLEAR_ERR, 12458c2ecf20Sopenharmony_ci SAHARA_REG_CMD); 12468c2ecf20Sopenharmony_ci 12478c2ecf20Sopenharmony_ci sahara_decode_status(dev, stat); 12488c2ecf20Sopenharmony_ci 12498c2ecf20Sopenharmony_ci if (SAHARA_STATUS_GET_STATE(stat) == SAHARA_STATE_BUSY) { 12508c2ecf20Sopenharmony_ci return IRQ_NONE; 12518c2ecf20Sopenharmony_ci } else if (SAHARA_STATUS_GET_STATE(stat) == SAHARA_STATE_COMPLETE) { 12528c2ecf20Sopenharmony_ci dev->error = 0; 12538c2ecf20Sopenharmony_ci } else { 12548c2ecf20Sopenharmony_ci sahara_decode_error(dev, err); 12558c2ecf20Sopenharmony_ci dev->error = -EINVAL; 12568c2ecf20Sopenharmony_ci } 12578c2ecf20Sopenharmony_ci 12588c2ecf20Sopenharmony_ci complete(&dev->dma_completion); 12598c2ecf20Sopenharmony_ci 12608c2ecf20Sopenharmony_ci return IRQ_HANDLED; 12618c2ecf20Sopenharmony_ci} 12628c2ecf20Sopenharmony_ci 12638c2ecf20Sopenharmony_ci 12648c2ecf20Sopenharmony_cistatic int sahara_register_algs(struct sahara_dev *dev) 12658c2ecf20Sopenharmony_ci{ 12668c2ecf20Sopenharmony_ci int err; 12678c2ecf20Sopenharmony_ci unsigned int i, j, k, l; 12688c2ecf20Sopenharmony_ci 12698c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(aes_algs); i++) { 12708c2ecf20Sopenharmony_ci err = crypto_register_skcipher(&aes_algs[i]); 12718c2ecf20Sopenharmony_ci if (err) 12728c2ecf20Sopenharmony_ci goto err_aes_algs; 12738c2ecf20Sopenharmony_ci } 12748c2ecf20Sopenharmony_ci 12758c2ecf20Sopenharmony_ci for (k = 0; k < ARRAY_SIZE(sha_v3_algs); k++) { 12768c2ecf20Sopenharmony_ci err = crypto_register_ahash(&sha_v3_algs[k]); 12778c2ecf20Sopenharmony_ci if (err) 12788c2ecf20Sopenharmony_ci goto err_sha_v3_algs; 12798c2ecf20Sopenharmony_ci } 12808c2ecf20Sopenharmony_ci 12818c2ecf20Sopenharmony_ci if (dev->version > SAHARA_VERSION_3) 12828c2ecf20Sopenharmony_ci for (l = 0; l < ARRAY_SIZE(sha_v4_algs); l++) { 12838c2ecf20Sopenharmony_ci err = crypto_register_ahash(&sha_v4_algs[l]); 12848c2ecf20Sopenharmony_ci if (err) 12858c2ecf20Sopenharmony_ci goto err_sha_v4_algs; 12868c2ecf20Sopenharmony_ci } 12878c2ecf20Sopenharmony_ci 12888c2ecf20Sopenharmony_ci return 0; 12898c2ecf20Sopenharmony_ci 12908c2ecf20Sopenharmony_cierr_sha_v4_algs: 12918c2ecf20Sopenharmony_ci for (j = 0; j < l; j++) 12928c2ecf20Sopenharmony_ci crypto_unregister_ahash(&sha_v4_algs[j]); 12938c2ecf20Sopenharmony_ci 12948c2ecf20Sopenharmony_cierr_sha_v3_algs: 12958c2ecf20Sopenharmony_ci for (j = 0; j < k; j++) 12968c2ecf20Sopenharmony_ci crypto_unregister_ahash(&sha_v3_algs[j]); 12978c2ecf20Sopenharmony_ci 12988c2ecf20Sopenharmony_cierr_aes_algs: 12998c2ecf20Sopenharmony_ci for (j = 0; j < i; j++) 13008c2ecf20Sopenharmony_ci crypto_unregister_skcipher(&aes_algs[j]); 13018c2ecf20Sopenharmony_ci 13028c2ecf20Sopenharmony_ci return err; 13038c2ecf20Sopenharmony_ci} 13048c2ecf20Sopenharmony_ci 13058c2ecf20Sopenharmony_cistatic void sahara_unregister_algs(struct sahara_dev *dev) 13068c2ecf20Sopenharmony_ci{ 13078c2ecf20Sopenharmony_ci unsigned int i; 13088c2ecf20Sopenharmony_ci 13098c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(aes_algs); i++) 13108c2ecf20Sopenharmony_ci crypto_unregister_skcipher(&aes_algs[i]); 13118c2ecf20Sopenharmony_ci 13128c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(sha_v3_algs); i++) 13138c2ecf20Sopenharmony_ci crypto_unregister_ahash(&sha_v3_algs[i]); 13148c2ecf20Sopenharmony_ci 13158c2ecf20Sopenharmony_ci if (dev->version > SAHARA_VERSION_3) 13168c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(sha_v4_algs); i++) 13178c2ecf20Sopenharmony_ci crypto_unregister_ahash(&sha_v4_algs[i]); 13188c2ecf20Sopenharmony_ci} 13198c2ecf20Sopenharmony_ci 13208c2ecf20Sopenharmony_cistatic const struct platform_device_id sahara_platform_ids[] = { 13218c2ecf20Sopenharmony_ci { .name = "sahara-imx27" }, 13228c2ecf20Sopenharmony_ci { /* sentinel */ } 13238c2ecf20Sopenharmony_ci}; 13248c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(platform, sahara_platform_ids); 13258c2ecf20Sopenharmony_ci 13268c2ecf20Sopenharmony_cistatic const struct of_device_id sahara_dt_ids[] = { 13278c2ecf20Sopenharmony_ci { .compatible = "fsl,imx53-sahara" }, 13288c2ecf20Sopenharmony_ci { .compatible = "fsl,imx27-sahara" }, 13298c2ecf20Sopenharmony_ci { /* sentinel */ } 13308c2ecf20Sopenharmony_ci}; 13318c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, sahara_dt_ids); 13328c2ecf20Sopenharmony_ci 13338c2ecf20Sopenharmony_cistatic int sahara_probe(struct platform_device *pdev) 13348c2ecf20Sopenharmony_ci{ 13358c2ecf20Sopenharmony_ci struct sahara_dev *dev; 13368c2ecf20Sopenharmony_ci u32 version; 13378c2ecf20Sopenharmony_ci int irq; 13388c2ecf20Sopenharmony_ci int err; 13398c2ecf20Sopenharmony_ci int i; 13408c2ecf20Sopenharmony_ci 13418c2ecf20Sopenharmony_ci dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); 13428c2ecf20Sopenharmony_ci if (!dev) 13438c2ecf20Sopenharmony_ci return -ENOMEM; 13448c2ecf20Sopenharmony_ci 13458c2ecf20Sopenharmony_ci dev->device = &pdev->dev; 13468c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, dev); 13478c2ecf20Sopenharmony_ci 13488c2ecf20Sopenharmony_ci /* Get the base address */ 13498c2ecf20Sopenharmony_ci dev->regs_base = devm_platform_ioremap_resource(pdev, 0); 13508c2ecf20Sopenharmony_ci if (IS_ERR(dev->regs_base)) 13518c2ecf20Sopenharmony_ci return PTR_ERR(dev->regs_base); 13528c2ecf20Sopenharmony_ci 13538c2ecf20Sopenharmony_ci /* Get the IRQ */ 13548c2ecf20Sopenharmony_ci irq = platform_get_irq(pdev, 0); 13558c2ecf20Sopenharmony_ci if (irq < 0) 13568c2ecf20Sopenharmony_ci return irq; 13578c2ecf20Sopenharmony_ci 13588c2ecf20Sopenharmony_ci err = devm_request_irq(&pdev->dev, irq, sahara_irq_handler, 13598c2ecf20Sopenharmony_ci 0, dev_name(&pdev->dev), dev); 13608c2ecf20Sopenharmony_ci if (err) { 13618c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "failed to request irq\n"); 13628c2ecf20Sopenharmony_ci return err; 13638c2ecf20Sopenharmony_ci } 13648c2ecf20Sopenharmony_ci 13658c2ecf20Sopenharmony_ci /* clocks */ 13668c2ecf20Sopenharmony_ci dev->clk_ipg = devm_clk_get(&pdev->dev, "ipg"); 13678c2ecf20Sopenharmony_ci if (IS_ERR(dev->clk_ipg)) { 13688c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Could not get ipg clock\n"); 13698c2ecf20Sopenharmony_ci return PTR_ERR(dev->clk_ipg); 13708c2ecf20Sopenharmony_ci } 13718c2ecf20Sopenharmony_ci 13728c2ecf20Sopenharmony_ci dev->clk_ahb = devm_clk_get(&pdev->dev, "ahb"); 13738c2ecf20Sopenharmony_ci if (IS_ERR(dev->clk_ahb)) { 13748c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Could not get ahb clock\n"); 13758c2ecf20Sopenharmony_ci return PTR_ERR(dev->clk_ahb); 13768c2ecf20Sopenharmony_ci } 13778c2ecf20Sopenharmony_ci 13788c2ecf20Sopenharmony_ci /* Allocate HW descriptors */ 13798c2ecf20Sopenharmony_ci dev->hw_desc[0] = dmam_alloc_coherent(&pdev->dev, 13808c2ecf20Sopenharmony_ci SAHARA_MAX_HW_DESC * sizeof(struct sahara_hw_desc), 13818c2ecf20Sopenharmony_ci &dev->hw_phys_desc[0], GFP_KERNEL); 13828c2ecf20Sopenharmony_ci if (!dev->hw_desc[0]) { 13838c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Could not allocate hw descriptors\n"); 13848c2ecf20Sopenharmony_ci return -ENOMEM; 13858c2ecf20Sopenharmony_ci } 13868c2ecf20Sopenharmony_ci dev->hw_desc[1] = dev->hw_desc[0] + 1; 13878c2ecf20Sopenharmony_ci dev->hw_phys_desc[1] = dev->hw_phys_desc[0] + 13888c2ecf20Sopenharmony_ci sizeof(struct sahara_hw_desc); 13898c2ecf20Sopenharmony_ci 13908c2ecf20Sopenharmony_ci /* Allocate space for iv and key */ 13918c2ecf20Sopenharmony_ci dev->key_base = dmam_alloc_coherent(&pdev->dev, 2 * AES_KEYSIZE_128, 13928c2ecf20Sopenharmony_ci &dev->key_phys_base, GFP_KERNEL); 13938c2ecf20Sopenharmony_ci if (!dev->key_base) { 13948c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Could not allocate memory for key\n"); 13958c2ecf20Sopenharmony_ci return -ENOMEM; 13968c2ecf20Sopenharmony_ci } 13978c2ecf20Sopenharmony_ci dev->iv_base = dev->key_base + AES_KEYSIZE_128; 13988c2ecf20Sopenharmony_ci dev->iv_phys_base = dev->key_phys_base + AES_KEYSIZE_128; 13998c2ecf20Sopenharmony_ci 14008c2ecf20Sopenharmony_ci /* Allocate space for context: largest digest + message length field */ 14018c2ecf20Sopenharmony_ci dev->context_base = dmam_alloc_coherent(&pdev->dev, 14028c2ecf20Sopenharmony_ci SHA256_DIGEST_SIZE + 4, 14038c2ecf20Sopenharmony_ci &dev->context_phys_base, GFP_KERNEL); 14048c2ecf20Sopenharmony_ci if (!dev->context_base) { 14058c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Could not allocate memory for MDHA context\n"); 14068c2ecf20Sopenharmony_ci return -ENOMEM; 14078c2ecf20Sopenharmony_ci } 14088c2ecf20Sopenharmony_ci 14098c2ecf20Sopenharmony_ci /* Allocate space for HW links */ 14108c2ecf20Sopenharmony_ci dev->hw_link[0] = dmam_alloc_coherent(&pdev->dev, 14118c2ecf20Sopenharmony_ci SAHARA_MAX_HW_LINK * sizeof(struct sahara_hw_link), 14128c2ecf20Sopenharmony_ci &dev->hw_phys_link[0], GFP_KERNEL); 14138c2ecf20Sopenharmony_ci if (!dev->hw_link[0]) { 14148c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Could not allocate hw links\n"); 14158c2ecf20Sopenharmony_ci return -ENOMEM; 14168c2ecf20Sopenharmony_ci } 14178c2ecf20Sopenharmony_ci for (i = 1; i < SAHARA_MAX_HW_LINK; i++) { 14188c2ecf20Sopenharmony_ci dev->hw_phys_link[i] = dev->hw_phys_link[i - 1] + 14198c2ecf20Sopenharmony_ci sizeof(struct sahara_hw_link); 14208c2ecf20Sopenharmony_ci dev->hw_link[i] = dev->hw_link[i - 1] + 1; 14218c2ecf20Sopenharmony_ci } 14228c2ecf20Sopenharmony_ci 14238c2ecf20Sopenharmony_ci crypto_init_queue(&dev->queue, SAHARA_QUEUE_LENGTH); 14248c2ecf20Sopenharmony_ci 14258c2ecf20Sopenharmony_ci spin_lock_init(&dev->queue_spinlock); 14268c2ecf20Sopenharmony_ci 14278c2ecf20Sopenharmony_ci dev_ptr = dev; 14288c2ecf20Sopenharmony_ci 14298c2ecf20Sopenharmony_ci dev->kthread = kthread_run(sahara_queue_manage, dev, "sahara_crypto"); 14308c2ecf20Sopenharmony_ci if (IS_ERR(dev->kthread)) { 14318c2ecf20Sopenharmony_ci return PTR_ERR(dev->kthread); 14328c2ecf20Sopenharmony_ci } 14338c2ecf20Sopenharmony_ci 14348c2ecf20Sopenharmony_ci init_completion(&dev->dma_completion); 14358c2ecf20Sopenharmony_ci 14368c2ecf20Sopenharmony_ci err = clk_prepare_enable(dev->clk_ipg); 14378c2ecf20Sopenharmony_ci if (err) 14388c2ecf20Sopenharmony_ci return err; 14398c2ecf20Sopenharmony_ci err = clk_prepare_enable(dev->clk_ahb); 14408c2ecf20Sopenharmony_ci if (err) 14418c2ecf20Sopenharmony_ci goto clk_ipg_disable; 14428c2ecf20Sopenharmony_ci 14438c2ecf20Sopenharmony_ci version = sahara_read(dev, SAHARA_REG_VERSION); 14448c2ecf20Sopenharmony_ci if (of_device_is_compatible(pdev->dev.of_node, "fsl,imx27-sahara")) { 14458c2ecf20Sopenharmony_ci if (version != SAHARA_VERSION_3) 14468c2ecf20Sopenharmony_ci err = -ENODEV; 14478c2ecf20Sopenharmony_ci } else if (of_device_is_compatible(pdev->dev.of_node, 14488c2ecf20Sopenharmony_ci "fsl,imx53-sahara")) { 14498c2ecf20Sopenharmony_ci if (((version >> 8) & 0xff) != SAHARA_VERSION_4) 14508c2ecf20Sopenharmony_ci err = -ENODEV; 14518c2ecf20Sopenharmony_ci version = (version >> 8) & 0xff; 14528c2ecf20Sopenharmony_ci } 14538c2ecf20Sopenharmony_ci if (err == -ENODEV) { 14548c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "SAHARA version %d not supported\n", 14558c2ecf20Sopenharmony_ci version); 14568c2ecf20Sopenharmony_ci goto err_algs; 14578c2ecf20Sopenharmony_ci } 14588c2ecf20Sopenharmony_ci 14598c2ecf20Sopenharmony_ci dev->version = version; 14608c2ecf20Sopenharmony_ci 14618c2ecf20Sopenharmony_ci sahara_write(dev, SAHARA_CMD_RESET | SAHARA_CMD_MODE_BATCH, 14628c2ecf20Sopenharmony_ci SAHARA_REG_CMD); 14638c2ecf20Sopenharmony_ci sahara_write(dev, SAHARA_CONTROL_SET_THROTTLE(0) | 14648c2ecf20Sopenharmony_ci SAHARA_CONTROL_SET_MAXBURST(8) | 14658c2ecf20Sopenharmony_ci SAHARA_CONTROL_RNG_AUTORSD | 14668c2ecf20Sopenharmony_ci SAHARA_CONTROL_ENABLE_INT, 14678c2ecf20Sopenharmony_ci SAHARA_REG_CONTROL); 14688c2ecf20Sopenharmony_ci 14698c2ecf20Sopenharmony_ci err = sahara_register_algs(dev); 14708c2ecf20Sopenharmony_ci if (err) 14718c2ecf20Sopenharmony_ci goto err_algs; 14728c2ecf20Sopenharmony_ci 14738c2ecf20Sopenharmony_ci dev_info(&pdev->dev, "SAHARA version %d initialized\n", version); 14748c2ecf20Sopenharmony_ci 14758c2ecf20Sopenharmony_ci return 0; 14768c2ecf20Sopenharmony_ci 14778c2ecf20Sopenharmony_cierr_algs: 14788c2ecf20Sopenharmony_ci kthread_stop(dev->kthread); 14798c2ecf20Sopenharmony_ci dev_ptr = NULL; 14808c2ecf20Sopenharmony_ci clk_disable_unprepare(dev->clk_ahb); 14818c2ecf20Sopenharmony_ciclk_ipg_disable: 14828c2ecf20Sopenharmony_ci clk_disable_unprepare(dev->clk_ipg); 14838c2ecf20Sopenharmony_ci 14848c2ecf20Sopenharmony_ci return err; 14858c2ecf20Sopenharmony_ci} 14868c2ecf20Sopenharmony_ci 14878c2ecf20Sopenharmony_cistatic int sahara_remove(struct platform_device *pdev) 14888c2ecf20Sopenharmony_ci{ 14898c2ecf20Sopenharmony_ci struct sahara_dev *dev = platform_get_drvdata(pdev); 14908c2ecf20Sopenharmony_ci 14918c2ecf20Sopenharmony_ci kthread_stop(dev->kthread); 14928c2ecf20Sopenharmony_ci 14938c2ecf20Sopenharmony_ci sahara_unregister_algs(dev); 14948c2ecf20Sopenharmony_ci 14958c2ecf20Sopenharmony_ci clk_disable_unprepare(dev->clk_ipg); 14968c2ecf20Sopenharmony_ci clk_disable_unprepare(dev->clk_ahb); 14978c2ecf20Sopenharmony_ci 14988c2ecf20Sopenharmony_ci dev_ptr = NULL; 14998c2ecf20Sopenharmony_ci 15008c2ecf20Sopenharmony_ci return 0; 15018c2ecf20Sopenharmony_ci} 15028c2ecf20Sopenharmony_ci 15038c2ecf20Sopenharmony_cistatic struct platform_driver sahara_driver = { 15048c2ecf20Sopenharmony_ci .probe = sahara_probe, 15058c2ecf20Sopenharmony_ci .remove = sahara_remove, 15068c2ecf20Sopenharmony_ci .driver = { 15078c2ecf20Sopenharmony_ci .name = SAHARA_NAME, 15088c2ecf20Sopenharmony_ci .of_match_table = sahara_dt_ids, 15098c2ecf20Sopenharmony_ci }, 15108c2ecf20Sopenharmony_ci .id_table = sahara_platform_ids, 15118c2ecf20Sopenharmony_ci}; 15128c2ecf20Sopenharmony_ci 15138c2ecf20Sopenharmony_cimodule_platform_driver(sahara_driver); 15148c2ecf20Sopenharmony_ci 15158c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 15168c2ecf20Sopenharmony_ciMODULE_AUTHOR("Javier Martin <javier.martin@vista-silicon.com>"); 15178c2ecf20Sopenharmony_ciMODULE_AUTHOR("Steffen Trumtrar <s.trumtrar@pengutronix.de>"); 15188c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("SAHARA2 HW crypto accelerator"); 1519