18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci// 38c2ecf20Sopenharmony_ci// Cryptographic API. 48c2ecf20Sopenharmony_ci// 58c2ecf20Sopenharmony_ci// Support for Samsung S5PV210 and Exynos HW acceleration. 68c2ecf20Sopenharmony_ci// 78c2ecf20Sopenharmony_ci// Copyright (C) 2011 NetUP Inc. All rights reserved. 88c2ecf20Sopenharmony_ci// Copyright (c) 2017 Samsung Electronics Co., Ltd. All rights reserved. 98c2ecf20Sopenharmony_ci// 108c2ecf20Sopenharmony_ci// Hash part based on omap-sham.c driver. 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#include <linux/clk.h> 138c2ecf20Sopenharmony_ci#include <linux/crypto.h> 148c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h> 158c2ecf20Sopenharmony_ci#include <linux/err.h> 168c2ecf20Sopenharmony_ci#include <linux/errno.h> 178c2ecf20Sopenharmony_ci#include <linux/init.h> 188c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 198c2ecf20Sopenharmony_ci#include <linux/io.h> 208c2ecf20Sopenharmony_ci#include <linux/kernel.h> 218c2ecf20Sopenharmony_ci#include <linux/module.h> 228c2ecf20Sopenharmony_ci#include <linux/of.h> 238c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 248c2ecf20Sopenharmony_ci#include <linux/scatterlist.h> 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci#include <crypto/ctr.h> 278c2ecf20Sopenharmony_ci#include <crypto/aes.h> 288c2ecf20Sopenharmony_ci#include <crypto/algapi.h> 298c2ecf20Sopenharmony_ci#include <crypto/scatterwalk.h> 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci#include <crypto/hash.h> 328c2ecf20Sopenharmony_ci#include <crypto/md5.h> 338c2ecf20Sopenharmony_ci#include <crypto/sha.h> 348c2ecf20Sopenharmony_ci#include <crypto/internal/hash.h> 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci#define _SBF(s, v) ((v) << (s)) 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci/* Feed control registers */ 398c2ecf20Sopenharmony_ci#define SSS_REG_FCINTSTAT 0x0000 408c2ecf20Sopenharmony_ci#define SSS_FCINTSTAT_HPARTINT BIT(7) 418c2ecf20Sopenharmony_ci#define SSS_FCINTSTAT_HDONEINT BIT(5) 428c2ecf20Sopenharmony_ci#define SSS_FCINTSTAT_BRDMAINT BIT(3) 438c2ecf20Sopenharmony_ci#define SSS_FCINTSTAT_BTDMAINT BIT(2) 448c2ecf20Sopenharmony_ci#define SSS_FCINTSTAT_HRDMAINT BIT(1) 458c2ecf20Sopenharmony_ci#define SSS_FCINTSTAT_PKDMAINT BIT(0) 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci#define SSS_REG_FCINTENSET 0x0004 488c2ecf20Sopenharmony_ci#define SSS_FCINTENSET_HPARTINTENSET BIT(7) 498c2ecf20Sopenharmony_ci#define SSS_FCINTENSET_HDONEINTENSET BIT(5) 508c2ecf20Sopenharmony_ci#define SSS_FCINTENSET_BRDMAINTENSET BIT(3) 518c2ecf20Sopenharmony_ci#define SSS_FCINTENSET_BTDMAINTENSET BIT(2) 528c2ecf20Sopenharmony_ci#define SSS_FCINTENSET_HRDMAINTENSET BIT(1) 538c2ecf20Sopenharmony_ci#define SSS_FCINTENSET_PKDMAINTENSET BIT(0) 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci#define SSS_REG_FCINTENCLR 0x0008 568c2ecf20Sopenharmony_ci#define SSS_FCINTENCLR_HPARTINTENCLR BIT(7) 578c2ecf20Sopenharmony_ci#define SSS_FCINTENCLR_HDONEINTENCLR BIT(5) 588c2ecf20Sopenharmony_ci#define SSS_FCINTENCLR_BRDMAINTENCLR BIT(3) 598c2ecf20Sopenharmony_ci#define SSS_FCINTENCLR_BTDMAINTENCLR BIT(2) 608c2ecf20Sopenharmony_ci#define SSS_FCINTENCLR_HRDMAINTENCLR BIT(1) 618c2ecf20Sopenharmony_ci#define SSS_FCINTENCLR_PKDMAINTENCLR BIT(0) 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci#define SSS_REG_FCINTPEND 0x000C 648c2ecf20Sopenharmony_ci#define SSS_FCINTPEND_HPARTINTP BIT(7) 658c2ecf20Sopenharmony_ci#define SSS_FCINTPEND_HDONEINTP BIT(5) 668c2ecf20Sopenharmony_ci#define SSS_FCINTPEND_BRDMAINTP BIT(3) 678c2ecf20Sopenharmony_ci#define SSS_FCINTPEND_BTDMAINTP BIT(2) 688c2ecf20Sopenharmony_ci#define SSS_FCINTPEND_HRDMAINTP BIT(1) 698c2ecf20Sopenharmony_ci#define SSS_FCINTPEND_PKDMAINTP BIT(0) 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci#define SSS_REG_FCFIFOSTAT 0x0010 728c2ecf20Sopenharmony_ci#define SSS_FCFIFOSTAT_BRFIFOFUL BIT(7) 738c2ecf20Sopenharmony_ci#define SSS_FCFIFOSTAT_BRFIFOEMP BIT(6) 748c2ecf20Sopenharmony_ci#define SSS_FCFIFOSTAT_BTFIFOFUL BIT(5) 758c2ecf20Sopenharmony_ci#define SSS_FCFIFOSTAT_BTFIFOEMP BIT(4) 768c2ecf20Sopenharmony_ci#define SSS_FCFIFOSTAT_HRFIFOFUL BIT(3) 778c2ecf20Sopenharmony_ci#define SSS_FCFIFOSTAT_HRFIFOEMP BIT(2) 788c2ecf20Sopenharmony_ci#define SSS_FCFIFOSTAT_PKFIFOFUL BIT(1) 798c2ecf20Sopenharmony_ci#define SSS_FCFIFOSTAT_PKFIFOEMP BIT(0) 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci#define SSS_REG_FCFIFOCTRL 0x0014 828c2ecf20Sopenharmony_ci#define SSS_FCFIFOCTRL_DESSEL BIT(2) 838c2ecf20Sopenharmony_ci#define SSS_HASHIN_INDEPENDENT _SBF(0, 0x00) 848c2ecf20Sopenharmony_ci#define SSS_HASHIN_CIPHER_INPUT _SBF(0, 0x01) 858c2ecf20Sopenharmony_ci#define SSS_HASHIN_CIPHER_OUTPUT _SBF(0, 0x02) 868c2ecf20Sopenharmony_ci#define SSS_HASHIN_MASK _SBF(0, 0x03) 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci#define SSS_REG_FCBRDMAS 0x0020 898c2ecf20Sopenharmony_ci#define SSS_REG_FCBRDMAL 0x0024 908c2ecf20Sopenharmony_ci#define SSS_REG_FCBRDMAC 0x0028 918c2ecf20Sopenharmony_ci#define SSS_FCBRDMAC_BYTESWAP BIT(1) 928c2ecf20Sopenharmony_ci#define SSS_FCBRDMAC_FLUSH BIT(0) 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci#define SSS_REG_FCBTDMAS 0x0030 958c2ecf20Sopenharmony_ci#define SSS_REG_FCBTDMAL 0x0034 968c2ecf20Sopenharmony_ci#define SSS_REG_FCBTDMAC 0x0038 978c2ecf20Sopenharmony_ci#define SSS_FCBTDMAC_BYTESWAP BIT(1) 988c2ecf20Sopenharmony_ci#define SSS_FCBTDMAC_FLUSH BIT(0) 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci#define SSS_REG_FCHRDMAS 0x0040 1018c2ecf20Sopenharmony_ci#define SSS_REG_FCHRDMAL 0x0044 1028c2ecf20Sopenharmony_ci#define SSS_REG_FCHRDMAC 0x0048 1038c2ecf20Sopenharmony_ci#define SSS_FCHRDMAC_BYTESWAP BIT(1) 1048c2ecf20Sopenharmony_ci#define SSS_FCHRDMAC_FLUSH BIT(0) 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci#define SSS_REG_FCPKDMAS 0x0050 1078c2ecf20Sopenharmony_ci#define SSS_REG_FCPKDMAL 0x0054 1088c2ecf20Sopenharmony_ci#define SSS_REG_FCPKDMAC 0x0058 1098c2ecf20Sopenharmony_ci#define SSS_FCPKDMAC_BYTESWAP BIT(3) 1108c2ecf20Sopenharmony_ci#define SSS_FCPKDMAC_DESCEND BIT(2) 1118c2ecf20Sopenharmony_ci#define SSS_FCPKDMAC_TRANSMIT BIT(1) 1128c2ecf20Sopenharmony_ci#define SSS_FCPKDMAC_FLUSH BIT(0) 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci#define SSS_REG_FCPKDMAO 0x005C 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci/* AES registers */ 1178c2ecf20Sopenharmony_ci#define SSS_REG_AES_CONTROL 0x00 1188c2ecf20Sopenharmony_ci#define SSS_AES_BYTESWAP_DI BIT(11) 1198c2ecf20Sopenharmony_ci#define SSS_AES_BYTESWAP_DO BIT(10) 1208c2ecf20Sopenharmony_ci#define SSS_AES_BYTESWAP_IV BIT(9) 1218c2ecf20Sopenharmony_ci#define SSS_AES_BYTESWAP_CNT BIT(8) 1228c2ecf20Sopenharmony_ci#define SSS_AES_BYTESWAP_KEY BIT(7) 1238c2ecf20Sopenharmony_ci#define SSS_AES_KEY_CHANGE_MODE BIT(6) 1248c2ecf20Sopenharmony_ci#define SSS_AES_KEY_SIZE_128 _SBF(4, 0x00) 1258c2ecf20Sopenharmony_ci#define SSS_AES_KEY_SIZE_192 _SBF(4, 0x01) 1268c2ecf20Sopenharmony_ci#define SSS_AES_KEY_SIZE_256 _SBF(4, 0x02) 1278c2ecf20Sopenharmony_ci#define SSS_AES_FIFO_MODE BIT(3) 1288c2ecf20Sopenharmony_ci#define SSS_AES_CHAIN_MODE_ECB _SBF(1, 0x00) 1298c2ecf20Sopenharmony_ci#define SSS_AES_CHAIN_MODE_CBC _SBF(1, 0x01) 1308c2ecf20Sopenharmony_ci#define SSS_AES_CHAIN_MODE_CTR _SBF(1, 0x02) 1318c2ecf20Sopenharmony_ci#define SSS_AES_MODE_DECRYPT BIT(0) 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci#define SSS_REG_AES_STATUS 0x04 1348c2ecf20Sopenharmony_ci#define SSS_AES_BUSY BIT(2) 1358c2ecf20Sopenharmony_ci#define SSS_AES_INPUT_READY BIT(1) 1368c2ecf20Sopenharmony_ci#define SSS_AES_OUTPUT_READY BIT(0) 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci#define SSS_REG_AES_IN_DATA(s) (0x10 + (s << 2)) 1398c2ecf20Sopenharmony_ci#define SSS_REG_AES_OUT_DATA(s) (0x20 + (s << 2)) 1408c2ecf20Sopenharmony_ci#define SSS_REG_AES_IV_DATA(s) (0x30 + (s << 2)) 1418c2ecf20Sopenharmony_ci#define SSS_REG_AES_CNT_DATA(s) (0x40 + (s << 2)) 1428c2ecf20Sopenharmony_ci#define SSS_REG_AES_KEY_DATA(s) (0x80 + (s << 2)) 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci#define SSS_REG(dev, reg) ((dev)->ioaddr + (SSS_REG_##reg)) 1458c2ecf20Sopenharmony_ci#define SSS_READ(dev, reg) __raw_readl(SSS_REG(dev, reg)) 1468c2ecf20Sopenharmony_ci#define SSS_WRITE(dev, reg, val) __raw_writel((val), SSS_REG(dev, reg)) 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci#define SSS_AES_REG(dev, reg) ((dev)->aes_ioaddr + SSS_REG_##reg) 1498c2ecf20Sopenharmony_ci#define SSS_AES_WRITE(dev, reg, val) __raw_writel((val), \ 1508c2ecf20Sopenharmony_ci SSS_AES_REG(dev, reg)) 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci/* HW engine modes */ 1538c2ecf20Sopenharmony_ci#define FLAGS_AES_DECRYPT BIT(0) 1548c2ecf20Sopenharmony_ci#define FLAGS_AES_MODE_MASK _SBF(1, 0x03) 1558c2ecf20Sopenharmony_ci#define FLAGS_AES_CBC _SBF(1, 0x01) 1568c2ecf20Sopenharmony_ci#define FLAGS_AES_CTR _SBF(1, 0x02) 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci#define AES_KEY_LEN 16 1598c2ecf20Sopenharmony_ci#define CRYPTO_QUEUE_LEN 1 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci/* HASH registers */ 1628c2ecf20Sopenharmony_ci#define SSS_REG_HASH_CTRL 0x00 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci#define SSS_HASH_USER_IV_EN BIT(5) 1658c2ecf20Sopenharmony_ci#define SSS_HASH_INIT_BIT BIT(4) 1668c2ecf20Sopenharmony_ci#define SSS_HASH_ENGINE_SHA1 _SBF(1, 0x00) 1678c2ecf20Sopenharmony_ci#define SSS_HASH_ENGINE_MD5 _SBF(1, 0x01) 1688c2ecf20Sopenharmony_ci#define SSS_HASH_ENGINE_SHA256 _SBF(1, 0x02) 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci#define SSS_HASH_ENGINE_MASK _SBF(1, 0x03) 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci#define SSS_REG_HASH_CTRL_PAUSE 0x04 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci#define SSS_HASH_PAUSE BIT(0) 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci#define SSS_REG_HASH_CTRL_FIFO 0x08 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci#define SSS_HASH_FIFO_MODE_DMA BIT(0) 1798c2ecf20Sopenharmony_ci#define SSS_HASH_FIFO_MODE_CPU 0 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci#define SSS_REG_HASH_CTRL_SWAP 0x0C 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci#define SSS_HASH_BYTESWAP_DI BIT(3) 1848c2ecf20Sopenharmony_ci#define SSS_HASH_BYTESWAP_DO BIT(2) 1858c2ecf20Sopenharmony_ci#define SSS_HASH_BYTESWAP_IV BIT(1) 1868c2ecf20Sopenharmony_ci#define SSS_HASH_BYTESWAP_KEY BIT(0) 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci#define SSS_REG_HASH_STATUS 0x10 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci#define SSS_HASH_STATUS_MSG_DONE BIT(6) 1918c2ecf20Sopenharmony_ci#define SSS_HASH_STATUS_PARTIAL_DONE BIT(4) 1928c2ecf20Sopenharmony_ci#define SSS_HASH_STATUS_BUFFER_READY BIT(0) 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci#define SSS_REG_HASH_MSG_SIZE_LOW 0x20 1958c2ecf20Sopenharmony_ci#define SSS_REG_HASH_MSG_SIZE_HIGH 0x24 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci#define SSS_REG_HASH_PRE_MSG_SIZE_LOW 0x28 1988c2ecf20Sopenharmony_ci#define SSS_REG_HASH_PRE_MSG_SIZE_HIGH 0x2C 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci#define SSS_REG_HASH_IV(s) (0xB0 + ((s) << 2)) 2018c2ecf20Sopenharmony_ci#define SSS_REG_HASH_OUT(s) (0x100 + ((s) << 2)) 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci#define HASH_BLOCK_SIZE 64 2048c2ecf20Sopenharmony_ci#define HASH_REG_SIZEOF 4 2058c2ecf20Sopenharmony_ci#define HASH_MD5_MAX_REG (MD5_DIGEST_SIZE / HASH_REG_SIZEOF) 2068c2ecf20Sopenharmony_ci#define HASH_SHA1_MAX_REG (SHA1_DIGEST_SIZE / HASH_REG_SIZEOF) 2078c2ecf20Sopenharmony_ci#define HASH_SHA256_MAX_REG (SHA256_DIGEST_SIZE / HASH_REG_SIZEOF) 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci/* 2108c2ecf20Sopenharmony_ci * HASH bit numbers, used by device, setting in dev->hash_flags with 2118c2ecf20Sopenharmony_ci * functions set_bit(), clear_bit() or tested with test_bit() or BIT(), 2128c2ecf20Sopenharmony_ci * to keep HASH state BUSY or FREE, or to signal state from irq_handler 2138c2ecf20Sopenharmony_ci * to hash_tasklet. SGS keep track of allocated memory for scatterlist 2148c2ecf20Sopenharmony_ci */ 2158c2ecf20Sopenharmony_ci#define HASH_FLAGS_BUSY 0 2168c2ecf20Sopenharmony_ci#define HASH_FLAGS_FINAL 1 2178c2ecf20Sopenharmony_ci#define HASH_FLAGS_DMA_ACTIVE 2 2188c2ecf20Sopenharmony_ci#define HASH_FLAGS_OUTPUT_READY 3 2198c2ecf20Sopenharmony_ci#define HASH_FLAGS_DMA_READY 4 2208c2ecf20Sopenharmony_ci#define HASH_FLAGS_SGS_COPIED 5 2218c2ecf20Sopenharmony_ci#define HASH_FLAGS_SGS_ALLOCED 6 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci/* HASH HW constants */ 2248c2ecf20Sopenharmony_ci#define BUFLEN HASH_BLOCK_SIZE 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci#define SSS_HASH_DMA_LEN_ALIGN 8 2278c2ecf20Sopenharmony_ci#define SSS_HASH_DMA_ALIGN_MASK (SSS_HASH_DMA_LEN_ALIGN - 1) 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci#define SSS_HASH_QUEUE_LENGTH 10 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci/** 2328c2ecf20Sopenharmony_ci * struct samsung_aes_variant - platform specific SSS driver data 2338c2ecf20Sopenharmony_ci * @aes_offset: AES register offset from SSS module's base. 2348c2ecf20Sopenharmony_ci * @hash_offset: HASH register offset from SSS module's base. 2358c2ecf20Sopenharmony_ci * @clk_names: names of clocks needed to run SSS IP 2368c2ecf20Sopenharmony_ci * 2378c2ecf20Sopenharmony_ci * Specifies platform specific configuration of SSS module. 2388c2ecf20Sopenharmony_ci * Note: A structure for driver specific platform data is used for future 2398c2ecf20Sopenharmony_ci * expansion of its usage. 2408c2ecf20Sopenharmony_ci */ 2418c2ecf20Sopenharmony_cistruct samsung_aes_variant { 2428c2ecf20Sopenharmony_ci unsigned int aes_offset; 2438c2ecf20Sopenharmony_ci unsigned int hash_offset; 2448c2ecf20Sopenharmony_ci const char *clk_names[2]; 2458c2ecf20Sopenharmony_ci}; 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_cistruct s5p_aes_reqctx { 2488c2ecf20Sopenharmony_ci unsigned long mode; 2498c2ecf20Sopenharmony_ci}; 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_cistruct s5p_aes_ctx { 2528c2ecf20Sopenharmony_ci struct s5p_aes_dev *dev; 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci u8 aes_key[AES_MAX_KEY_SIZE]; 2558c2ecf20Sopenharmony_ci u8 nonce[CTR_RFC3686_NONCE_SIZE]; 2568c2ecf20Sopenharmony_ci int keylen; 2578c2ecf20Sopenharmony_ci}; 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci/** 2608c2ecf20Sopenharmony_ci * struct s5p_aes_dev - Crypto device state container 2618c2ecf20Sopenharmony_ci * @dev: Associated device 2628c2ecf20Sopenharmony_ci * @clk: Clock for accessing hardware 2638c2ecf20Sopenharmony_ci * @pclk: APB bus clock necessary to access the hardware 2648c2ecf20Sopenharmony_ci * @ioaddr: Mapped IO memory region 2658c2ecf20Sopenharmony_ci * @aes_ioaddr: Per-varian offset for AES block IO memory 2668c2ecf20Sopenharmony_ci * @irq_fc: Feed control interrupt line 2678c2ecf20Sopenharmony_ci * @req: Crypto request currently handled by the device 2688c2ecf20Sopenharmony_ci * @ctx: Configuration for currently handled crypto request 2698c2ecf20Sopenharmony_ci * @sg_src: Scatter list with source data for currently handled block 2708c2ecf20Sopenharmony_ci * in device. This is DMA-mapped into device. 2718c2ecf20Sopenharmony_ci * @sg_dst: Scatter list with destination data for currently handled block 2728c2ecf20Sopenharmony_ci * in device. This is DMA-mapped into device. 2738c2ecf20Sopenharmony_ci * @sg_src_cpy: In case of unaligned access, copied scatter list 2748c2ecf20Sopenharmony_ci * with source data. 2758c2ecf20Sopenharmony_ci * @sg_dst_cpy: In case of unaligned access, copied scatter list 2768c2ecf20Sopenharmony_ci * with destination data. 2778c2ecf20Sopenharmony_ci * @tasklet: New request scheduling jib 2788c2ecf20Sopenharmony_ci * @queue: Crypto queue 2798c2ecf20Sopenharmony_ci * @busy: Indicates whether the device is currently handling some request 2808c2ecf20Sopenharmony_ci * thus it uses some of the fields from this state, like: 2818c2ecf20Sopenharmony_ci * req, ctx, sg_src/dst (and copies). This essentially 2828c2ecf20Sopenharmony_ci * protects against concurrent access to these fields. 2838c2ecf20Sopenharmony_ci * @lock: Lock for protecting both access to device hardware registers 2848c2ecf20Sopenharmony_ci * and fields related to current request (including the busy field). 2858c2ecf20Sopenharmony_ci * @res: Resources for hash. 2868c2ecf20Sopenharmony_ci * @io_hash_base: Per-variant offset for HASH block IO memory. 2878c2ecf20Sopenharmony_ci * @hash_lock: Lock for protecting hash_req, hash_queue and hash_flags 2888c2ecf20Sopenharmony_ci * variable. 2898c2ecf20Sopenharmony_ci * @hash_flags: Flags for current HASH op. 2908c2ecf20Sopenharmony_ci * @hash_queue: Async hash queue. 2918c2ecf20Sopenharmony_ci * @hash_tasklet: New HASH request scheduling job. 2928c2ecf20Sopenharmony_ci * @xmit_buf: Buffer for current HASH request transfer into SSS block. 2938c2ecf20Sopenharmony_ci * @hash_req: Current request sending to SSS HASH block. 2948c2ecf20Sopenharmony_ci * @hash_sg_iter: Scatterlist transferred through DMA into SSS HASH block. 2958c2ecf20Sopenharmony_ci * @hash_sg_cnt: Counter for hash_sg_iter. 2968c2ecf20Sopenharmony_ci * 2978c2ecf20Sopenharmony_ci * @use_hash: true if HASH algs enabled 2988c2ecf20Sopenharmony_ci */ 2998c2ecf20Sopenharmony_cistruct s5p_aes_dev { 3008c2ecf20Sopenharmony_ci struct device *dev; 3018c2ecf20Sopenharmony_ci struct clk *clk; 3028c2ecf20Sopenharmony_ci struct clk *pclk; 3038c2ecf20Sopenharmony_ci void __iomem *ioaddr; 3048c2ecf20Sopenharmony_ci void __iomem *aes_ioaddr; 3058c2ecf20Sopenharmony_ci int irq_fc; 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci struct skcipher_request *req; 3088c2ecf20Sopenharmony_ci struct s5p_aes_ctx *ctx; 3098c2ecf20Sopenharmony_ci struct scatterlist *sg_src; 3108c2ecf20Sopenharmony_ci struct scatterlist *sg_dst; 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci struct scatterlist *sg_src_cpy; 3138c2ecf20Sopenharmony_ci struct scatterlist *sg_dst_cpy; 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci struct tasklet_struct tasklet; 3168c2ecf20Sopenharmony_ci struct crypto_queue queue; 3178c2ecf20Sopenharmony_ci bool busy; 3188c2ecf20Sopenharmony_ci spinlock_t lock; 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci struct resource *res; 3218c2ecf20Sopenharmony_ci void __iomem *io_hash_base; 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci spinlock_t hash_lock; /* protect hash_ vars */ 3248c2ecf20Sopenharmony_ci unsigned long hash_flags; 3258c2ecf20Sopenharmony_ci struct crypto_queue hash_queue; 3268c2ecf20Sopenharmony_ci struct tasklet_struct hash_tasklet; 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci u8 xmit_buf[BUFLEN]; 3298c2ecf20Sopenharmony_ci struct ahash_request *hash_req; 3308c2ecf20Sopenharmony_ci struct scatterlist *hash_sg_iter; 3318c2ecf20Sopenharmony_ci unsigned int hash_sg_cnt; 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci bool use_hash; 3348c2ecf20Sopenharmony_ci}; 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci/** 3378c2ecf20Sopenharmony_ci * struct s5p_hash_reqctx - HASH request context 3388c2ecf20Sopenharmony_ci * @dd: Associated device 3398c2ecf20Sopenharmony_ci * @op_update: Current request operation (OP_UPDATE or OP_FINAL) 3408c2ecf20Sopenharmony_ci * @digcnt: Number of bytes processed by HW (without buffer[] ones) 3418c2ecf20Sopenharmony_ci * @digest: Digest message or IV for partial result 3428c2ecf20Sopenharmony_ci * @nregs: Number of HW registers for digest or IV read/write 3438c2ecf20Sopenharmony_ci * @engine: Bits for selecting type of HASH in SSS block 3448c2ecf20Sopenharmony_ci * @sg: sg for DMA transfer 3458c2ecf20Sopenharmony_ci * @sg_len: Length of sg for DMA transfer 3468c2ecf20Sopenharmony_ci * @sgl: sg for joining buffer and req->src scatterlist 3478c2ecf20Sopenharmony_ci * @skip: Skip offset in req->src for current op 3488c2ecf20Sopenharmony_ci * @total: Total number of bytes for current request 3498c2ecf20Sopenharmony_ci * @finup: Keep state for finup or final. 3508c2ecf20Sopenharmony_ci * @error: Keep track of error. 3518c2ecf20Sopenharmony_ci * @bufcnt: Number of bytes holded in buffer[] 3528c2ecf20Sopenharmony_ci * @buffer: For byte(s) from end of req->src in UPDATE op 3538c2ecf20Sopenharmony_ci */ 3548c2ecf20Sopenharmony_cistruct s5p_hash_reqctx { 3558c2ecf20Sopenharmony_ci struct s5p_aes_dev *dd; 3568c2ecf20Sopenharmony_ci bool op_update; 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci u64 digcnt; 3598c2ecf20Sopenharmony_ci u8 digest[SHA256_DIGEST_SIZE]; 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci unsigned int nregs; /* digest_size / sizeof(reg) */ 3628c2ecf20Sopenharmony_ci u32 engine; 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci struct scatterlist *sg; 3658c2ecf20Sopenharmony_ci unsigned int sg_len; 3668c2ecf20Sopenharmony_ci struct scatterlist sgl[2]; 3678c2ecf20Sopenharmony_ci unsigned int skip; 3688c2ecf20Sopenharmony_ci unsigned int total; 3698c2ecf20Sopenharmony_ci bool finup; 3708c2ecf20Sopenharmony_ci bool error; 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci u32 bufcnt; 3738c2ecf20Sopenharmony_ci u8 buffer[]; 3748c2ecf20Sopenharmony_ci}; 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci/** 3778c2ecf20Sopenharmony_ci * struct s5p_hash_ctx - HASH transformation context 3788c2ecf20Sopenharmony_ci * @dd: Associated device 3798c2ecf20Sopenharmony_ci * @flags: Bits for algorithm HASH. 3808c2ecf20Sopenharmony_ci * @fallback: Software transformation for zero message or size < BUFLEN. 3818c2ecf20Sopenharmony_ci */ 3828c2ecf20Sopenharmony_cistruct s5p_hash_ctx { 3838c2ecf20Sopenharmony_ci struct s5p_aes_dev *dd; 3848c2ecf20Sopenharmony_ci unsigned long flags; 3858c2ecf20Sopenharmony_ci struct crypto_shash *fallback; 3868c2ecf20Sopenharmony_ci}; 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_cistatic const struct samsung_aes_variant s5p_aes_data = { 3898c2ecf20Sopenharmony_ci .aes_offset = 0x4000, 3908c2ecf20Sopenharmony_ci .hash_offset = 0x6000, 3918c2ecf20Sopenharmony_ci .clk_names = { "secss", }, 3928c2ecf20Sopenharmony_ci}; 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_cistatic const struct samsung_aes_variant exynos_aes_data = { 3958c2ecf20Sopenharmony_ci .aes_offset = 0x200, 3968c2ecf20Sopenharmony_ci .hash_offset = 0x400, 3978c2ecf20Sopenharmony_ci .clk_names = { "secss", }, 3988c2ecf20Sopenharmony_ci}; 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_cistatic const struct samsung_aes_variant exynos5433_slim_aes_data = { 4018c2ecf20Sopenharmony_ci .aes_offset = 0x400, 4028c2ecf20Sopenharmony_ci .hash_offset = 0x800, 4038c2ecf20Sopenharmony_ci .clk_names = { "pclk", "aclk", }, 4048c2ecf20Sopenharmony_ci}; 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_cistatic const struct of_device_id s5p_sss_dt_match[] = { 4078c2ecf20Sopenharmony_ci { 4088c2ecf20Sopenharmony_ci .compatible = "samsung,s5pv210-secss", 4098c2ecf20Sopenharmony_ci .data = &s5p_aes_data, 4108c2ecf20Sopenharmony_ci }, 4118c2ecf20Sopenharmony_ci { 4128c2ecf20Sopenharmony_ci .compatible = "samsung,exynos4210-secss", 4138c2ecf20Sopenharmony_ci .data = &exynos_aes_data, 4148c2ecf20Sopenharmony_ci }, 4158c2ecf20Sopenharmony_ci { 4168c2ecf20Sopenharmony_ci .compatible = "samsung,exynos5433-slim-sss", 4178c2ecf20Sopenharmony_ci .data = &exynos5433_slim_aes_data, 4188c2ecf20Sopenharmony_ci }, 4198c2ecf20Sopenharmony_ci { }, 4208c2ecf20Sopenharmony_ci}; 4218c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, s5p_sss_dt_match); 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_cistatic inline const struct samsung_aes_variant *find_s5p_sss_version 4248c2ecf20Sopenharmony_ci (const struct platform_device *pdev) 4258c2ecf20Sopenharmony_ci{ 4268c2ecf20Sopenharmony_ci if (IS_ENABLED(CONFIG_OF) && (pdev->dev.of_node)) { 4278c2ecf20Sopenharmony_ci const struct of_device_id *match; 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci match = of_match_node(s5p_sss_dt_match, 4308c2ecf20Sopenharmony_ci pdev->dev.of_node); 4318c2ecf20Sopenharmony_ci return (const struct samsung_aes_variant *)match->data; 4328c2ecf20Sopenharmony_ci } 4338c2ecf20Sopenharmony_ci return (const struct samsung_aes_variant *) 4348c2ecf20Sopenharmony_ci platform_get_device_id(pdev)->driver_data; 4358c2ecf20Sopenharmony_ci} 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_cistatic struct s5p_aes_dev *s5p_dev; 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_cistatic void s5p_set_dma_indata(struct s5p_aes_dev *dev, 4408c2ecf20Sopenharmony_ci const struct scatterlist *sg) 4418c2ecf20Sopenharmony_ci{ 4428c2ecf20Sopenharmony_ci SSS_WRITE(dev, FCBRDMAS, sg_dma_address(sg)); 4438c2ecf20Sopenharmony_ci SSS_WRITE(dev, FCBRDMAL, sg_dma_len(sg)); 4448c2ecf20Sopenharmony_ci} 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_cistatic void s5p_set_dma_outdata(struct s5p_aes_dev *dev, 4478c2ecf20Sopenharmony_ci const struct scatterlist *sg) 4488c2ecf20Sopenharmony_ci{ 4498c2ecf20Sopenharmony_ci SSS_WRITE(dev, FCBTDMAS, sg_dma_address(sg)); 4508c2ecf20Sopenharmony_ci SSS_WRITE(dev, FCBTDMAL, sg_dma_len(sg)); 4518c2ecf20Sopenharmony_ci} 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_cistatic void s5p_free_sg_cpy(struct s5p_aes_dev *dev, struct scatterlist **sg) 4548c2ecf20Sopenharmony_ci{ 4558c2ecf20Sopenharmony_ci int len; 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci if (!*sg) 4588c2ecf20Sopenharmony_ci return; 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci len = ALIGN(dev->req->cryptlen, AES_BLOCK_SIZE); 4618c2ecf20Sopenharmony_ci free_pages((unsigned long)sg_virt(*sg), get_order(len)); 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci kfree(*sg); 4648c2ecf20Sopenharmony_ci *sg = NULL; 4658c2ecf20Sopenharmony_ci} 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_cistatic void s5p_sg_copy_buf(void *buf, struct scatterlist *sg, 4688c2ecf20Sopenharmony_ci unsigned int nbytes, int out) 4698c2ecf20Sopenharmony_ci{ 4708c2ecf20Sopenharmony_ci struct scatter_walk walk; 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci if (!nbytes) 4738c2ecf20Sopenharmony_ci return; 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci scatterwalk_start(&walk, sg); 4768c2ecf20Sopenharmony_ci scatterwalk_copychunks(buf, &walk, nbytes, out); 4778c2ecf20Sopenharmony_ci scatterwalk_done(&walk, out, 0); 4788c2ecf20Sopenharmony_ci} 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_cistatic void s5p_sg_done(struct s5p_aes_dev *dev) 4818c2ecf20Sopenharmony_ci{ 4828c2ecf20Sopenharmony_ci struct skcipher_request *req = dev->req; 4838c2ecf20Sopenharmony_ci struct s5p_aes_reqctx *reqctx = skcipher_request_ctx(req); 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci if (dev->sg_dst_cpy) { 4868c2ecf20Sopenharmony_ci dev_dbg(dev->dev, 4878c2ecf20Sopenharmony_ci "Copying %d bytes of output data back to original place\n", 4888c2ecf20Sopenharmony_ci dev->req->cryptlen); 4898c2ecf20Sopenharmony_ci s5p_sg_copy_buf(sg_virt(dev->sg_dst_cpy), dev->req->dst, 4908c2ecf20Sopenharmony_ci dev->req->cryptlen, 1); 4918c2ecf20Sopenharmony_ci } 4928c2ecf20Sopenharmony_ci s5p_free_sg_cpy(dev, &dev->sg_src_cpy); 4938c2ecf20Sopenharmony_ci s5p_free_sg_cpy(dev, &dev->sg_dst_cpy); 4948c2ecf20Sopenharmony_ci if (reqctx->mode & FLAGS_AES_CBC) 4958c2ecf20Sopenharmony_ci memcpy_fromio(req->iv, dev->aes_ioaddr + SSS_REG_AES_IV_DATA(0), AES_BLOCK_SIZE); 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ci else if (reqctx->mode & FLAGS_AES_CTR) 4988c2ecf20Sopenharmony_ci memcpy_fromio(req->iv, dev->aes_ioaddr + SSS_REG_AES_CNT_DATA(0), AES_BLOCK_SIZE); 4998c2ecf20Sopenharmony_ci} 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci/* Calls the completion. Cannot be called with dev->lock hold. */ 5028c2ecf20Sopenharmony_cistatic void s5p_aes_complete(struct skcipher_request *req, int err) 5038c2ecf20Sopenharmony_ci{ 5048c2ecf20Sopenharmony_ci req->base.complete(&req->base, err); 5058c2ecf20Sopenharmony_ci} 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_cistatic void s5p_unset_outdata(struct s5p_aes_dev *dev) 5088c2ecf20Sopenharmony_ci{ 5098c2ecf20Sopenharmony_ci dma_unmap_sg(dev->dev, dev->sg_dst, 1, DMA_FROM_DEVICE); 5108c2ecf20Sopenharmony_ci} 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_cistatic void s5p_unset_indata(struct s5p_aes_dev *dev) 5138c2ecf20Sopenharmony_ci{ 5148c2ecf20Sopenharmony_ci dma_unmap_sg(dev->dev, dev->sg_src, 1, DMA_TO_DEVICE); 5158c2ecf20Sopenharmony_ci} 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_cistatic int s5p_make_sg_cpy(struct s5p_aes_dev *dev, struct scatterlist *src, 5188c2ecf20Sopenharmony_ci struct scatterlist **dst) 5198c2ecf20Sopenharmony_ci{ 5208c2ecf20Sopenharmony_ci void *pages; 5218c2ecf20Sopenharmony_ci int len; 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_ci *dst = kmalloc(sizeof(**dst), GFP_ATOMIC); 5248c2ecf20Sopenharmony_ci if (!*dst) 5258c2ecf20Sopenharmony_ci return -ENOMEM; 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ci len = ALIGN(dev->req->cryptlen, AES_BLOCK_SIZE); 5288c2ecf20Sopenharmony_ci pages = (void *)__get_free_pages(GFP_ATOMIC, get_order(len)); 5298c2ecf20Sopenharmony_ci if (!pages) { 5308c2ecf20Sopenharmony_ci kfree(*dst); 5318c2ecf20Sopenharmony_ci *dst = NULL; 5328c2ecf20Sopenharmony_ci return -ENOMEM; 5338c2ecf20Sopenharmony_ci } 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_ci s5p_sg_copy_buf(pages, src, dev->req->cryptlen, 0); 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ci sg_init_table(*dst, 1); 5388c2ecf20Sopenharmony_ci sg_set_buf(*dst, pages, len); 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci return 0; 5418c2ecf20Sopenharmony_ci} 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_cistatic int s5p_set_outdata(struct s5p_aes_dev *dev, struct scatterlist *sg) 5448c2ecf20Sopenharmony_ci{ 5458c2ecf20Sopenharmony_ci if (!sg->length) 5468c2ecf20Sopenharmony_ci return -EINVAL; 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci if (!dma_map_sg(dev->dev, sg, 1, DMA_FROM_DEVICE)) 5498c2ecf20Sopenharmony_ci return -ENOMEM; 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_ci dev->sg_dst = sg; 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_ci return 0; 5548c2ecf20Sopenharmony_ci} 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_cistatic int s5p_set_indata(struct s5p_aes_dev *dev, struct scatterlist *sg) 5578c2ecf20Sopenharmony_ci{ 5588c2ecf20Sopenharmony_ci if (!sg->length) 5598c2ecf20Sopenharmony_ci return -EINVAL; 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_ci if (!dma_map_sg(dev->dev, sg, 1, DMA_TO_DEVICE)) 5628c2ecf20Sopenharmony_ci return -ENOMEM; 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_ci dev->sg_src = sg; 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_ci return 0; 5678c2ecf20Sopenharmony_ci} 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_ci/* 5708c2ecf20Sopenharmony_ci * Returns -ERRNO on error (mapping of new data failed). 5718c2ecf20Sopenharmony_ci * On success returns: 5728c2ecf20Sopenharmony_ci * - 0 if there is no more data, 5738c2ecf20Sopenharmony_ci * - 1 if new transmitting (output) data is ready and its address+length 5748c2ecf20Sopenharmony_ci * have to be written to device (by calling s5p_set_dma_outdata()). 5758c2ecf20Sopenharmony_ci */ 5768c2ecf20Sopenharmony_cistatic int s5p_aes_tx(struct s5p_aes_dev *dev) 5778c2ecf20Sopenharmony_ci{ 5788c2ecf20Sopenharmony_ci int ret = 0; 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ci s5p_unset_outdata(dev); 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_ci if (!sg_is_last(dev->sg_dst)) { 5838c2ecf20Sopenharmony_ci ret = s5p_set_outdata(dev, sg_next(dev->sg_dst)); 5848c2ecf20Sopenharmony_ci if (!ret) 5858c2ecf20Sopenharmony_ci ret = 1; 5868c2ecf20Sopenharmony_ci } 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci return ret; 5898c2ecf20Sopenharmony_ci} 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_ci/* 5928c2ecf20Sopenharmony_ci * Returns -ERRNO on error (mapping of new data failed). 5938c2ecf20Sopenharmony_ci * On success returns: 5948c2ecf20Sopenharmony_ci * - 0 if there is no more data, 5958c2ecf20Sopenharmony_ci * - 1 if new receiving (input) data is ready and its address+length 5968c2ecf20Sopenharmony_ci * have to be written to device (by calling s5p_set_dma_indata()). 5978c2ecf20Sopenharmony_ci */ 5988c2ecf20Sopenharmony_cistatic int s5p_aes_rx(struct s5p_aes_dev *dev/*, bool *set_dma*/) 5998c2ecf20Sopenharmony_ci{ 6008c2ecf20Sopenharmony_ci int ret = 0; 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_ci s5p_unset_indata(dev); 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_ci if (!sg_is_last(dev->sg_src)) { 6058c2ecf20Sopenharmony_ci ret = s5p_set_indata(dev, sg_next(dev->sg_src)); 6068c2ecf20Sopenharmony_ci if (!ret) 6078c2ecf20Sopenharmony_ci ret = 1; 6088c2ecf20Sopenharmony_ci } 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_ci return ret; 6118c2ecf20Sopenharmony_ci} 6128c2ecf20Sopenharmony_ci 6138c2ecf20Sopenharmony_cistatic inline u32 s5p_hash_read(struct s5p_aes_dev *dd, u32 offset) 6148c2ecf20Sopenharmony_ci{ 6158c2ecf20Sopenharmony_ci return __raw_readl(dd->io_hash_base + offset); 6168c2ecf20Sopenharmony_ci} 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_cistatic inline void s5p_hash_write(struct s5p_aes_dev *dd, 6198c2ecf20Sopenharmony_ci u32 offset, u32 value) 6208c2ecf20Sopenharmony_ci{ 6218c2ecf20Sopenharmony_ci __raw_writel(value, dd->io_hash_base + offset); 6228c2ecf20Sopenharmony_ci} 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_ci/** 6258c2ecf20Sopenharmony_ci * s5p_set_dma_hashdata() - start DMA with sg 6268c2ecf20Sopenharmony_ci * @dev: device 6278c2ecf20Sopenharmony_ci * @sg: scatterlist ready to DMA transmit 6288c2ecf20Sopenharmony_ci */ 6298c2ecf20Sopenharmony_cistatic void s5p_set_dma_hashdata(struct s5p_aes_dev *dev, 6308c2ecf20Sopenharmony_ci const struct scatterlist *sg) 6318c2ecf20Sopenharmony_ci{ 6328c2ecf20Sopenharmony_ci dev->hash_sg_cnt--; 6338c2ecf20Sopenharmony_ci SSS_WRITE(dev, FCHRDMAS, sg_dma_address(sg)); 6348c2ecf20Sopenharmony_ci SSS_WRITE(dev, FCHRDMAL, sg_dma_len(sg)); /* DMA starts */ 6358c2ecf20Sopenharmony_ci} 6368c2ecf20Sopenharmony_ci 6378c2ecf20Sopenharmony_ci/** 6388c2ecf20Sopenharmony_ci * s5p_hash_rx() - get next hash_sg_iter 6398c2ecf20Sopenharmony_ci * @dev: device 6408c2ecf20Sopenharmony_ci * 6418c2ecf20Sopenharmony_ci * Return: 6428c2ecf20Sopenharmony_ci * 2 if there is no more data and it is UPDATE op 6438c2ecf20Sopenharmony_ci * 1 if new receiving (input) data is ready and can be written to device 6448c2ecf20Sopenharmony_ci * 0 if there is no more data and it is FINAL op 6458c2ecf20Sopenharmony_ci */ 6468c2ecf20Sopenharmony_cistatic int s5p_hash_rx(struct s5p_aes_dev *dev) 6478c2ecf20Sopenharmony_ci{ 6488c2ecf20Sopenharmony_ci if (dev->hash_sg_cnt > 0) { 6498c2ecf20Sopenharmony_ci dev->hash_sg_iter = sg_next(dev->hash_sg_iter); 6508c2ecf20Sopenharmony_ci return 1; 6518c2ecf20Sopenharmony_ci } 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_ci set_bit(HASH_FLAGS_DMA_READY, &dev->hash_flags); 6548c2ecf20Sopenharmony_ci if (test_bit(HASH_FLAGS_FINAL, &dev->hash_flags)) 6558c2ecf20Sopenharmony_ci return 0; 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_ci return 2; 6588c2ecf20Sopenharmony_ci} 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_cistatic irqreturn_t s5p_aes_interrupt(int irq, void *dev_id) 6618c2ecf20Sopenharmony_ci{ 6628c2ecf20Sopenharmony_ci struct platform_device *pdev = dev_id; 6638c2ecf20Sopenharmony_ci struct s5p_aes_dev *dev = platform_get_drvdata(pdev); 6648c2ecf20Sopenharmony_ci struct skcipher_request *req; 6658c2ecf20Sopenharmony_ci int err_dma_tx = 0; 6668c2ecf20Sopenharmony_ci int err_dma_rx = 0; 6678c2ecf20Sopenharmony_ci int err_dma_hx = 0; 6688c2ecf20Sopenharmony_ci bool tx_end = false; 6698c2ecf20Sopenharmony_ci bool hx_end = false; 6708c2ecf20Sopenharmony_ci unsigned long flags; 6718c2ecf20Sopenharmony_ci u32 status, st_bits; 6728c2ecf20Sopenharmony_ci int err; 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_ci spin_lock_irqsave(&dev->lock, flags); 6758c2ecf20Sopenharmony_ci 6768c2ecf20Sopenharmony_ci /* 6778c2ecf20Sopenharmony_ci * Handle rx or tx interrupt. If there is still data (scatterlist did not 6788c2ecf20Sopenharmony_ci * reach end), then map next scatterlist entry. 6798c2ecf20Sopenharmony_ci * In case of such mapping error, s5p_aes_complete() should be called. 6808c2ecf20Sopenharmony_ci * 6818c2ecf20Sopenharmony_ci * If there is no more data in tx scatter list, call s5p_aes_complete() 6828c2ecf20Sopenharmony_ci * and schedule new tasklet. 6838c2ecf20Sopenharmony_ci * 6848c2ecf20Sopenharmony_ci * Handle hx interrupt. If there is still data map next entry. 6858c2ecf20Sopenharmony_ci */ 6868c2ecf20Sopenharmony_ci status = SSS_READ(dev, FCINTSTAT); 6878c2ecf20Sopenharmony_ci if (status & SSS_FCINTSTAT_BRDMAINT) 6888c2ecf20Sopenharmony_ci err_dma_rx = s5p_aes_rx(dev); 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_ci if (status & SSS_FCINTSTAT_BTDMAINT) { 6918c2ecf20Sopenharmony_ci if (sg_is_last(dev->sg_dst)) 6928c2ecf20Sopenharmony_ci tx_end = true; 6938c2ecf20Sopenharmony_ci err_dma_tx = s5p_aes_tx(dev); 6948c2ecf20Sopenharmony_ci } 6958c2ecf20Sopenharmony_ci 6968c2ecf20Sopenharmony_ci if (status & SSS_FCINTSTAT_HRDMAINT) 6978c2ecf20Sopenharmony_ci err_dma_hx = s5p_hash_rx(dev); 6988c2ecf20Sopenharmony_ci 6998c2ecf20Sopenharmony_ci st_bits = status & (SSS_FCINTSTAT_BRDMAINT | SSS_FCINTSTAT_BTDMAINT | 7008c2ecf20Sopenharmony_ci SSS_FCINTSTAT_HRDMAINT); 7018c2ecf20Sopenharmony_ci /* clear DMA bits */ 7028c2ecf20Sopenharmony_ci SSS_WRITE(dev, FCINTPEND, st_bits); 7038c2ecf20Sopenharmony_ci 7048c2ecf20Sopenharmony_ci /* clear HASH irq bits */ 7058c2ecf20Sopenharmony_ci if (status & (SSS_FCINTSTAT_HDONEINT | SSS_FCINTSTAT_HPARTINT)) { 7068c2ecf20Sopenharmony_ci /* cannot have both HPART and HDONE */ 7078c2ecf20Sopenharmony_ci if (status & SSS_FCINTSTAT_HPARTINT) 7088c2ecf20Sopenharmony_ci st_bits = SSS_HASH_STATUS_PARTIAL_DONE; 7098c2ecf20Sopenharmony_ci 7108c2ecf20Sopenharmony_ci if (status & SSS_FCINTSTAT_HDONEINT) 7118c2ecf20Sopenharmony_ci st_bits = SSS_HASH_STATUS_MSG_DONE; 7128c2ecf20Sopenharmony_ci 7138c2ecf20Sopenharmony_ci set_bit(HASH_FLAGS_OUTPUT_READY, &dev->hash_flags); 7148c2ecf20Sopenharmony_ci s5p_hash_write(dev, SSS_REG_HASH_STATUS, st_bits); 7158c2ecf20Sopenharmony_ci hx_end = true; 7168c2ecf20Sopenharmony_ci /* when DONE or PART, do not handle HASH DMA */ 7178c2ecf20Sopenharmony_ci err_dma_hx = 0; 7188c2ecf20Sopenharmony_ci } 7198c2ecf20Sopenharmony_ci 7208c2ecf20Sopenharmony_ci if (err_dma_rx < 0) { 7218c2ecf20Sopenharmony_ci err = err_dma_rx; 7228c2ecf20Sopenharmony_ci goto error; 7238c2ecf20Sopenharmony_ci } 7248c2ecf20Sopenharmony_ci if (err_dma_tx < 0) { 7258c2ecf20Sopenharmony_ci err = err_dma_tx; 7268c2ecf20Sopenharmony_ci goto error; 7278c2ecf20Sopenharmony_ci } 7288c2ecf20Sopenharmony_ci 7298c2ecf20Sopenharmony_ci if (tx_end) { 7308c2ecf20Sopenharmony_ci s5p_sg_done(dev); 7318c2ecf20Sopenharmony_ci if (err_dma_hx == 1) 7328c2ecf20Sopenharmony_ci s5p_set_dma_hashdata(dev, dev->hash_sg_iter); 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dev->lock, flags); 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_ci s5p_aes_complete(dev->req, 0); 7378c2ecf20Sopenharmony_ci /* Device is still busy */ 7388c2ecf20Sopenharmony_ci tasklet_schedule(&dev->tasklet); 7398c2ecf20Sopenharmony_ci } else { 7408c2ecf20Sopenharmony_ci /* 7418c2ecf20Sopenharmony_ci * Writing length of DMA block (either receiving or 7428c2ecf20Sopenharmony_ci * transmitting) will start the operation immediately, so this 7438c2ecf20Sopenharmony_ci * should be done at the end (even after clearing pending 7448c2ecf20Sopenharmony_ci * interrupts to not miss the interrupt). 7458c2ecf20Sopenharmony_ci */ 7468c2ecf20Sopenharmony_ci if (err_dma_tx == 1) 7478c2ecf20Sopenharmony_ci s5p_set_dma_outdata(dev, dev->sg_dst); 7488c2ecf20Sopenharmony_ci if (err_dma_rx == 1) 7498c2ecf20Sopenharmony_ci s5p_set_dma_indata(dev, dev->sg_src); 7508c2ecf20Sopenharmony_ci if (err_dma_hx == 1) 7518c2ecf20Sopenharmony_ci s5p_set_dma_hashdata(dev, dev->hash_sg_iter); 7528c2ecf20Sopenharmony_ci 7538c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dev->lock, flags); 7548c2ecf20Sopenharmony_ci } 7558c2ecf20Sopenharmony_ci 7568c2ecf20Sopenharmony_ci goto hash_irq_end; 7578c2ecf20Sopenharmony_ci 7588c2ecf20Sopenharmony_cierror: 7598c2ecf20Sopenharmony_ci s5p_sg_done(dev); 7608c2ecf20Sopenharmony_ci dev->busy = false; 7618c2ecf20Sopenharmony_ci req = dev->req; 7628c2ecf20Sopenharmony_ci if (err_dma_hx == 1) 7638c2ecf20Sopenharmony_ci s5p_set_dma_hashdata(dev, dev->hash_sg_iter); 7648c2ecf20Sopenharmony_ci 7658c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dev->lock, flags); 7668c2ecf20Sopenharmony_ci s5p_aes_complete(req, err); 7678c2ecf20Sopenharmony_ci 7688c2ecf20Sopenharmony_cihash_irq_end: 7698c2ecf20Sopenharmony_ci /* 7708c2ecf20Sopenharmony_ci * Note about else if: 7718c2ecf20Sopenharmony_ci * when hash_sg_iter reaches end and its UPDATE op, 7728c2ecf20Sopenharmony_ci * issue SSS_HASH_PAUSE and wait for HPART irq 7738c2ecf20Sopenharmony_ci */ 7748c2ecf20Sopenharmony_ci if (hx_end) 7758c2ecf20Sopenharmony_ci tasklet_schedule(&dev->hash_tasklet); 7768c2ecf20Sopenharmony_ci else if (err_dma_hx == 2) 7778c2ecf20Sopenharmony_ci s5p_hash_write(dev, SSS_REG_HASH_CTRL_PAUSE, 7788c2ecf20Sopenharmony_ci SSS_HASH_PAUSE); 7798c2ecf20Sopenharmony_ci 7808c2ecf20Sopenharmony_ci return IRQ_HANDLED; 7818c2ecf20Sopenharmony_ci} 7828c2ecf20Sopenharmony_ci 7838c2ecf20Sopenharmony_ci/** 7848c2ecf20Sopenharmony_ci * s5p_hash_read_msg() - read message or IV from HW 7858c2ecf20Sopenharmony_ci * @req: AHASH request 7868c2ecf20Sopenharmony_ci */ 7878c2ecf20Sopenharmony_cistatic void s5p_hash_read_msg(struct ahash_request *req) 7888c2ecf20Sopenharmony_ci{ 7898c2ecf20Sopenharmony_ci struct s5p_hash_reqctx *ctx = ahash_request_ctx(req); 7908c2ecf20Sopenharmony_ci struct s5p_aes_dev *dd = ctx->dd; 7918c2ecf20Sopenharmony_ci u32 *hash = (u32 *)ctx->digest; 7928c2ecf20Sopenharmony_ci unsigned int i; 7938c2ecf20Sopenharmony_ci 7948c2ecf20Sopenharmony_ci for (i = 0; i < ctx->nregs; i++) 7958c2ecf20Sopenharmony_ci hash[i] = s5p_hash_read(dd, SSS_REG_HASH_OUT(i)); 7968c2ecf20Sopenharmony_ci} 7978c2ecf20Sopenharmony_ci 7988c2ecf20Sopenharmony_ci/** 7998c2ecf20Sopenharmony_ci * s5p_hash_write_ctx_iv() - write IV for next partial/finup op. 8008c2ecf20Sopenharmony_ci * @dd: device 8018c2ecf20Sopenharmony_ci * @ctx: request context 8028c2ecf20Sopenharmony_ci */ 8038c2ecf20Sopenharmony_cistatic void s5p_hash_write_ctx_iv(struct s5p_aes_dev *dd, 8048c2ecf20Sopenharmony_ci const struct s5p_hash_reqctx *ctx) 8058c2ecf20Sopenharmony_ci{ 8068c2ecf20Sopenharmony_ci const u32 *hash = (const u32 *)ctx->digest; 8078c2ecf20Sopenharmony_ci unsigned int i; 8088c2ecf20Sopenharmony_ci 8098c2ecf20Sopenharmony_ci for (i = 0; i < ctx->nregs; i++) 8108c2ecf20Sopenharmony_ci s5p_hash_write(dd, SSS_REG_HASH_IV(i), hash[i]); 8118c2ecf20Sopenharmony_ci} 8128c2ecf20Sopenharmony_ci 8138c2ecf20Sopenharmony_ci/** 8148c2ecf20Sopenharmony_ci * s5p_hash_write_iv() - write IV for next partial/finup op. 8158c2ecf20Sopenharmony_ci * @req: AHASH request 8168c2ecf20Sopenharmony_ci */ 8178c2ecf20Sopenharmony_cistatic void s5p_hash_write_iv(struct ahash_request *req) 8188c2ecf20Sopenharmony_ci{ 8198c2ecf20Sopenharmony_ci struct s5p_hash_reqctx *ctx = ahash_request_ctx(req); 8208c2ecf20Sopenharmony_ci 8218c2ecf20Sopenharmony_ci s5p_hash_write_ctx_iv(ctx->dd, ctx); 8228c2ecf20Sopenharmony_ci} 8238c2ecf20Sopenharmony_ci 8248c2ecf20Sopenharmony_ci/** 8258c2ecf20Sopenharmony_ci * s5p_hash_copy_result() - copy digest into req->result 8268c2ecf20Sopenharmony_ci * @req: AHASH request 8278c2ecf20Sopenharmony_ci */ 8288c2ecf20Sopenharmony_cistatic void s5p_hash_copy_result(struct ahash_request *req) 8298c2ecf20Sopenharmony_ci{ 8308c2ecf20Sopenharmony_ci const struct s5p_hash_reqctx *ctx = ahash_request_ctx(req); 8318c2ecf20Sopenharmony_ci 8328c2ecf20Sopenharmony_ci if (!req->result) 8338c2ecf20Sopenharmony_ci return; 8348c2ecf20Sopenharmony_ci 8358c2ecf20Sopenharmony_ci memcpy(req->result, ctx->digest, ctx->nregs * HASH_REG_SIZEOF); 8368c2ecf20Sopenharmony_ci} 8378c2ecf20Sopenharmony_ci 8388c2ecf20Sopenharmony_ci/** 8398c2ecf20Sopenharmony_ci * s5p_hash_dma_flush() - flush HASH DMA 8408c2ecf20Sopenharmony_ci * @dev: secss device 8418c2ecf20Sopenharmony_ci */ 8428c2ecf20Sopenharmony_cistatic void s5p_hash_dma_flush(struct s5p_aes_dev *dev) 8438c2ecf20Sopenharmony_ci{ 8448c2ecf20Sopenharmony_ci SSS_WRITE(dev, FCHRDMAC, SSS_FCHRDMAC_FLUSH); 8458c2ecf20Sopenharmony_ci} 8468c2ecf20Sopenharmony_ci 8478c2ecf20Sopenharmony_ci/** 8488c2ecf20Sopenharmony_ci * s5p_hash_dma_enable() - enable DMA mode for HASH 8498c2ecf20Sopenharmony_ci * @dev: secss device 8508c2ecf20Sopenharmony_ci * 8518c2ecf20Sopenharmony_ci * enable DMA mode for HASH 8528c2ecf20Sopenharmony_ci */ 8538c2ecf20Sopenharmony_cistatic void s5p_hash_dma_enable(struct s5p_aes_dev *dev) 8548c2ecf20Sopenharmony_ci{ 8558c2ecf20Sopenharmony_ci s5p_hash_write(dev, SSS_REG_HASH_CTRL_FIFO, SSS_HASH_FIFO_MODE_DMA); 8568c2ecf20Sopenharmony_ci} 8578c2ecf20Sopenharmony_ci 8588c2ecf20Sopenharmony_ci/** 8598c2ecf20Sopenharmony_ci * s5p_hash_irq_disable() - disable irq HASH signals 8608c2ecf20Sopenharmony_ci * @dev: secss device 8618c2ecf20Sopenharmony_ci * @flags: bitfield with irq's to be disabled 8628c2ecf20Sopenharmony_ci */ 8638c2ecf20Sopenharmony_cistatic void s5p_hash_irq_disable(struct s5p_aes_dev *dev, u32 flags) 8648c2ecf20Sopenharmony_ci{ 8658c2ecf20Sopenharmony_ci SSS_WRITE(dev, FCINTENCLR, flags); 8668c2ecf20Sopenharmony_ci} 8678c2ecf20Sopenharmony_ci 8688c2ecf20Sopenharmony_ci/** 8698c2ecf20Sopenharmony_ci * s5p_hash_irq_enable() - enable irq signals 8708c2ecf20Sopenharmony_ci * @dev: secss device 8718c2ecf20Sopenharmony_ci * @flags: bitfield with irq's to be enabled 8728c2ecf20Sopenharmony_ci */ 8738c2ecf20Sopenharmony_cistatic void s5p_hash_irq_enable(struct s5p_aes_dev *dev, int flags) 8748c2ecf20Sopenharmony_ci{ 8758c2ecf20Sopenharmony_ci SSS_WRITE(dev, FCINTENSET, flags); 8768c2ecf20Sopenharmony_ci} 8778c2ecf20Sopenharmony_ci 8788c2ecf20Sopenharmony_ci/** 8798c2ecf20Sopenharmony_ci * s5p_hash_set_flow() - set flow inside SecSS AES/DES with/without HASH 8808c2ecf20Sopenharmony_ci * @dev: secss device 8818c2ecf20Sopenharmony_ci * @hashflow: HASH stream flow with/without crypto AES/DES 8828c2ecf20Sopenharmony_ci */ 8838c2ecf20Sopenharmony_cistatic void s5p_hash_set_flow(struct s5p_aes_dev *dev, u32 hashflow) 8848c2ecf20Sopenharmony_ci{ 8858c2ecf20Sopenharmony_ci unsigned long flags; 8868c2ecf20Sopenharmony_ci u32 flow; 8878c2ecf20Sopenharmony_ci 8888c2ecf20Sopenharmony_ci spin_lock_irqsave(&dev->lock, flags); 8898c2ecf20Sopenharmony_ci 8908c2ecf20Sopenharmony_ci flow = SSS_READ(dev, FCFIFOCTRL); 8918c2ecf20Sopenharmony_ci flow &= ~SSS_HASHIN_MASK; 8928c2ecf20Sopenharmony_ci flow |= hashflow; 8938c2ecf20Sopenharmony_ci SSS_WRITE(dev, FCFIFOCTRL, flow); 8948c2ecf20Sopenharmony_ci 8958c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dev->lock, flags); 8968c2ecf20Sopenharmony_ci} 8978c2ecf20Sopenharmony_ci 8988c2ecf20Sopenharmony_ci/** 8998c2ecf20Sopenharmony_ci * s5p_ahash_dma_init() - enable DMA and set HASH flow inside SecSS 9008c2ecf20Sopenharmony_ci * @dev: secss device 9018c2ecf20Sopenharmony_ci * @hashflow: HASH stream flow with/without AES/DES 9028c2ecf20Sopenharmony_ci * 9038c2ecf20Sopenharmony_ci * flush HASH DMA and enable DMA, set HASH stream flow inside SecSS HW, 9048c2ecf20Sopenharmony_ci * enable HASH irq's HRDMA, HDONE, HPART 9058c2ecf20Sopenharmony_ci */ 9068c2ecf20Sopenharmony_cistatic void s5p_ahash_dma_init(struct s5p_aes_dev *dev, u32 hashflow) 9078c2ecf20Sopenharmony_ci{ 9088c2ecf20Sopenharmony_ci s5p_hash_irq_disable(dev, SSS_FCINTENCLR_HRDMAINTENCLR | 9098c2ecf20Sopenharmony_ci SSS_FCINTENCLR_HDONEINTENCLR | 9108c2ecf20Sopenharmony_ci SSS_FCINTENCLR_HPARTINTENCLR); 9118c2ecf20Sopenharmony_ci s5p_hash_dma_flush(dev); 9128c2ecf20Sopenharmony_ci 9138c2ecf20Sopenharmony_ci s5p_hash_dma_enable(dev); 9148c2ecf20Sopenharmony_ci s5p_hash_set_flow(dev, hashflow & SSS_HASHIN_MASK); 9158c2ecf20Sopenharmony_ci s5p_hash_irq_enable(dev, SSS_FCINTENSET_HRDMAINTENSET | 9168c2ecf20Sopenharmony_ci SSS_FCINTENSET_HDONEINTENSET | 9178c2ecf20Sopenharmony_ci SSS_FCINTENSET_HPARTINTENSET); 9188c2ecf20Sopenharmony_ci} 9198c2ecf20Sopenharmony_ci 9208c2ecf20Sopenharmony_ci/** 9218c2ecf20Sopenharmony_ci * s5p_hash_write_ctrl() - prepare HASH block in SecSS for processing 9228c2ecf20Sopenharmony_ci * @dd: secss device 9238c2ecf20Sopenharmony_ci * @length: length for request 9248c2ecf20Sopenharmony_ci * @final: true if final op 9258c2ecf20Sopenharmony_ci * 9268c2ecf20Sopenharmony_ci * Prepare SSS HASH block for processing bytes in DMA mode. If it is called 9278c2ecf20Sopenharmony_ci * after previous updates, fill up IV words. For final, calculate and set 9288c2ecf20Sopenharmony_ci * lengths for HASH so SecSS can finalize hash. For partial, set SSS HASH 9298c2ecf20Sopenharmony_ci * length as 2^63 so it will be never reached and set to zero prelow and 9308c2ecf20Sopenharmony_ci * prehigh. 9318c2ecf20Sopenharmony_ci * 9328c2ecf20Sopenharmony_ci * This function does not start DMA transfer. 9338c2ecf20Sopenharmony_ci */ 9348c2ecf20Sopenharmony_cistatic void s5p_hash_write_ctrl(struct s5p_aes_dev *dd, size_t length, 9358c2ecf20Sopenharmony_ci bool final) 9368c2ecf20Sopenharmony_ci{ 9378c2ecf20Sopenharmony_ci struct s5p_hash_reqctx *ctx = ahash_request_ctx(dd->hash_req); 9388c2ecf20Sopenharmony_ci u32 prelow, prehigh, low, high; 9398c2ecf20Sopenharmony_ci u32 configflags, swapflags; 9408c2ecf20Sopenharmony_ci u64 tmplen; 9418c2ecf20Sopenharmony_ci 9428c2ecf20Sopenharmony_ci configflags = ctx->engine | SSS_HASH_INIT_BIT; 9438c2ecf20Sopenharmony_ci 9448c2ecf20Sopenharmony_ci if (likely(ctx->digcnt)) { 9458c2ecf20Sopenharmony_ci s5p_hash_write_ctx_iv(dd, ctx); 9468c2ecf20Sopenharmony_ci configflags |= SSS_HASH_USER_IV_EN; 9478c2ecf20Sopenharmony_ci } 9488c2ecf20Sopenharmony_ci 9498c2ecf20Sopenharmony_ci if (final) { 9508c2ecf20Sopenharmony_ci /* number of bytes for last part */ 9518c2ecf20Sopenharmony_ci low = length; 9528c2ecf20Sopenharmony_ci high = 0; 9538c2ecf20Sopenharmony_ci /* total number of bits prev hashed */ 9548c2ecf20Sopenharmony_ci tmplen = ctx->digcnt * 8; 9558c2ecf20Sopenharmony_ci prelow = (u32)tmplen; 9568c2ecf20Sopenharmony_ci prehigh = (u32)(tmplen >> 32); 9578c2ecf20Sopenharmony_ci } else { 9588c2ecf20Sopenharmony_ci prelow = 0; 9598c2ecf20Sopenharmony_ci prehigh = 0; 9608c2ecf20Sopenharmony_ci low = 0; 9618c2ecf20Sopenharmony_ci high = BIT(31); 9628c2ecf20Sopenharmony_ci } 9638c2ecf20Sopenharmony_ci 9648c2ecf20Sopenharmony_ci swapflags = SSS_HASH_BYTESWAP_DI | SSS_HASH_BYTESWAP_DO | 9658c2ecf20Sopenharmony_ci SSS_HASH_BYTESWAP_IV | SSS_HASH_BYTESWAP_KEY; 9668c2ecf20Sopenharmony_ci 9678c2ecf20Sopenharmony_ci s5p_hash_write(dd, SSS_REG_HASH_MSG_SIZE_LOW, low); 9688c2ecf20Sopenharmony_ci s5p_hash_write(dd, SSS_REG_HASH_MSG_SIZE_HIGH, high); 9698c2ecf20Sopenharmony_ci s5p_hash_write(dd, SSS_REG_HASH_PRE_MSG_SIZE_LOW, prelow); 9708c2ecf20Sopenharmony_ci s5p_hash_write(dd, SSS_REG_HASH_PRE_MSG_SIZE_HIGH, prehigh); 9718c2ecf20Sopenharmony_ci 9728c2ecf20Sopenharmony_ci s5p_hash_write(dd, SSS_REG_HASH_CTRL_SWAP, swapflags); 9738c2ecf20Sopenharmony_ci s5p_hash_write(dd, SSS_REG_HASH_CTRL, configflags); 9748c2ecf20Sopenharmony_ci} 9758c2ecf20Sopenharmony_ci 9768c2ecf20Sopenharmony_ci/** 9778c2ecf20Sopenharmony_ci * s5p_hash_xmit_dma() - start DMA hash processing 9788c2ecf20Sopenharmony_ci * @dd: secss device 9798c2ecf20Sopenharmony_ci * @length: length for request 9808c2ecf20Sopenharmony_ci * @final: true if final op 9818c2ecf20Sopenharmony_ci * 9828c2ecf20Sopenharmony_ci * Update digcnt here, as it is needed for finup/final op. 9838c2ecf20Sopenharmony_ci */ 9848c2ecf20Sopenharmony_cistatic int s5p_hash_xmit_dma(struct s5p_aes_dev *dd, size_t length, 9858c2ecf20Sopenharmony_ci bool final) 9868c2ecf20Sopenharmony_ci{ 9878c2ecf20Sopenharmony_ci struct s5p_hash_reqctx *ctx = ahash_request_ctx(dd->hash_req); 9888c2ecf20Sopenharmony_ci unsigned int cnt; 9898c2ecf20Sopenharmony_ci 9908c2ecf20Sopenharmony_ci cnt = dma_map_sg(dd->dev, ctx->sg, ctx->sg_len, DMA_TO_DEVICE); 9918c2ecf20Sopenharmony_ci if (!cnt) { 9928c2ecf20Sopenharmony_ci dev_err(dd->dev, "dma_map_sg error\n"); 9938c2ecf20Sopenharmony_ci ctx->error = true; 9948c2ecf20Sopenharmony_ci return -EINVAL; 9958c2ecf20Sopenharmony_ci } 9968c2ecf20Sopenharmony_ci 9978c2ecf20Sopenharmony_ci set_bit(HASH_FLAGS_DMA_ACTIVE, &dd->hash_flags); 9988c2ecf20Sopenharmony_ci dd->hash_sg_iter = ctx->sg; 9998c2ecf20Sopenharmony_ci dd->hash_sg_cnt = cnt; 10008c2ecf20Sopenharmony_ci s5p_hash_write_ctrl(dd, length, final); 10018c2ecf20Sopenharmony_ci ctx->digcnt += length; 10028c2ecf20Sopenharmony_ci ctx->total -= length; 10038c2ecf20Sopenharmony_ci 10048c2ecf20Sopenharmony_ci /* catch last interrupt */ 10058c2ecf20Sopenharmony_ci if (final) 10068c2ecf20Sopenharmony_ci set_bit(HASH_FLAGS_FINAL, &dd->hash_flags); 10078c2ecf20Sopenharmony_ci 10088c2ecf20Sopenharmony_ci s5p_set_dma_hashdata(dd, dd->hash_sg_iter); /* DMA starts */ 10098c2ecf20Sopenharmony_ci 10108c2ecf20Sopenharmony_ci return -EINPROGRESS; 10118c2ecf20Sopenharmony_ci} 10128c2ecf20Sopenharmony_ci 10138c2ecf20Sopenharmony_ci/** 10148c2ecf20Sopenharmony_ci * s5p_hash_copy_sgs() - copy request's bytes into new buffer 10158c2ecf20Sopenharmony_ci * @ctx: request context 10168c2ecf20Sopenharmony_ci * @sg: source scatterlist request 10178c2ecf20Sopenharmony_ci * @new_len: number of bytes to process from sg 10188c2ecf20Sopenharmony_ci * 10198c2ecf20Sopenharmony_ci * Allocate new buffer, copy data for HASH into it. If there was xmit_buf 10208c2ecf20Sopenharmony_ci * filled, copy it first, then copy data from sg into it. Prepare one sgl[0] 10218c2ecf20Sopenharmony_ci * with allocated buffer. 10228c2ecf20Sopenharmony_ci * 10238c2ecf20Sopenharmony_ci * Set bit in dd->hash_flag so we can free it after irq ends processing. 10248c2ecf20Sopenharmony_ci */ 10258c2ecf20Sopenharmony_cistatic int s5p_hash_copy_sgs(struct s5p_hash_reqctx *ctx, 10268c2ecf20Sopenharmony_ci struct scatterlist *sg, unsigned int new_len) 10278c2ecf20Sopenharmony_ci{ 10288c2ecf20Sopenharmony_ci unsigned int pages, len; 10298c2ecf20Sopenharmony_ci void *buf; 10308c2ecf20Sopenharmony_ci 10318c2ecf20Sopenharmony_ci len = new_len + ctx->bufcnt; 10328c2ecf20Sopenharmony_ci pages = get_order(len); 10338c2ecf20Sopenharmony_ci 10348c2ecf20Sopenharmony_ci buf = (void *)__get_free_pages(GFP_ATOMIC, pages); 10358c2ecf20Sopenharmony_ci if (!buf) { 10368c2ecf20Sopenharmony_ci dev_err(ctx->dd->dev, "alloc pages for unaligned case.\n"); 10378c2ecf20Sopenharmony_ci ctx->error = true; 10388c2ecf20Sopenharmony_ci return -ENOMEM; 10398c2ecf20Sopenharmony_ci } 10408c2ecf20Sopenharmony_ci 10418c2ecf20Sopenharmony_ci if (ctx->bufcnt) 10428c2ecf20Sopenharmony_ci memcpy(buf, ctx->dd->xmit_buf, ctx->bufcnt); 10438c2ecf20Sopenharmony_ci 10448c2ecf20Sopenharmony_ci scatterwalk_map_and_copy(buf + ctx->bufcnt, sg, ctx->skip, 10458c2ecf20Sopenharmony_ci new_len, 0); 10468c2ecf20Sopenharmony_ci sg_init_table(ctx->sgl, 1); 10478c2ecf20Sopenharmony_ci sg_set_buf(ctx->sgl, buf, len); 10488c2ecf20Sopenharmony_ci ctx->sg = ctx->sgl; 10498c2ecf20Sopenharmony_ci ctx->sg_len = 1; 10508c2ecf20Sopenharmony_ci ctx->bufcnt = 0; 10518c2ecf20Sopenharmony_ci ctx->skip = 0; 10528c2ecf20Sopenharmony_ci set_bit(HASH_FLAGS_SGS_COPIED, &ctx->dd->hash_flags); 10538c2ecf20Sopenharmony_ci 10548c2ecf20Sopenharmony_ci return 0; 10558c2ecf20Sopenharmony_ci} 10568c2ecf20Sopenharmony_ci 10578c2ecf20Sopenharmony_ci/** 10588c2ecf20Sopenharmony_ci * s5p_hash_copy_sg_lists() - copy sg list and make fixes in copy 10598c2ecf20Sopenharmony_ci * @ctx: request context 10608c2ecf20Sopenharmony_ci * @sg: source scatterlist request 10618c2ecf20Sopenharmony_ci * @new_len: number of bytes to process from sg 10628c2ecf20Sopenharmony_ci * 10638c2ecf20Sopenharmony_ci * Allocate new scatterlist table, copy data for HASH into it. If there was 10648c2ecf20Sopenharmony_ci * xmit_buf filled, prepare it first, then copy page, length and offset from 10658c2ecf20Sopenharmony_ci * source sg into it, adjusting begin and/or end for skip offset and 10668c2ecf20Sopenharmony_ci * hash_later value. 10678c2ecf20Sopenharmony_ci * 10688c2ecf20Sopenharmony_ci * Resulting sg table will be assigned to ctx->sg. Set flag so we can free 10698c2ecf20Sopenharmony_ci * it after irq ends processing. 10708c2ecf20Sopenharmony_ci */ 10718c2ecf20Sopenharmony_cistatic int s5p_hash_copy_sg_lists(struct s5p_hash_reqctx *ctx, 10728c2ecf20Sopenharmony_ci struct scatterlist *sg, unsigned int new_len) 10738c2ecf20Sopenharmony_ci{ 10748c2ecf20Sopenharmony_ci unsigned int skip = ctx->skip, n = sg_nents(sg); 10758c2ecf20Sopenharmony_ci struct scatterlist *tmp; 10768c2ecf20Sopenharmony_ci unsigned int len; 10778c2ecf20Sopenharmony_ci 10788c2ecf20Sopenharmony_ci if (ctx->bufcnt) 10798c2ecf20Sopenharmony_ci n++; 10808c2ecf20Sopenharmony_ci 10818c2ecf20Sopenharmony_ci ctx->sg = kmalloc_array(n, sizeof(*sg), GFP_KERNEL); 10828c2ecf20Sopenharmony_ci if (!ctx->sg) { 10838c2ecf20Sopenharmony_ci ctx->error = true; 10848c2ecf20Sopenharmony_ci return -ENOMEM; 10858c2ecf20Sopenharmony_ci } 10868c2ecf20Sopenharmony_ci 10878c2ecf20Sopenharmony_ci sg_init_table(ctx->sg, n); 10888c2ecf20Sopenharmony_ci 10898c2ecf20Sopenharmony_ci tmp = ctx->sg; 10908c2ecf20Sopenharmony_ci 10918c2ecf20Sopenharmony_ci ctx->sg_len = 0; 10928c2ecf20Sopenharmony_ci 10938c2ecf20Sopenharmony_ci if (ctx->bufcnt) { 10948c2ecf20Sopenharmony_ci sg_set_buf(tmp, ctx->dd->xmit_buf, ctx->bufcnt); 10958c2ecf20Sopenharmony_ci tmp = sg_next(tmp); 10968c2ecf20Sopenharmony_ci ctx->sg_len++; 10978c2ecf20Sopenharmony_ci } 10988c2ecf20Sopenharmony_ci 10998c2ecf20Sopenharmony_ci while (sg && skip >= sg->length) { 11008c2ecf20Sopenharmony_ci skip -= sg->length; 11018c2ecf20Sopenharmony_ci sg = sg_next(sg); 11028c2ecf20Sopenharmony_ci } 11038c2ecf20Sopenharmony_ci 11048c2ecf20Sopenharmony_ci while (sg && new_len) { 11058c2ecf20Sopenharmony_ci len = sg->length - skip; 11068c2ecf20Sopenharmony_ci if (new_len < len) 11078c2ecf20Sopenharmony_ci len = new_len; 11088c2ecf20Sopenharmony_ci 11098c2ecf20Sopenharmony_ci new_len -= len; 11108c2ecf20Sopenharmony_ci sg_set_page(tmp, sg_page(sg), len, sg->offset + skip); 11118c2ecf20Sopenharmony_ci skip = 0; 11128c2ecf20Sopenharmony_ci if (new_len <= 0) 11138c2ecf20Sopenharmony_ci sg_mark_end(tmp); 11148c2ecf20Sopenharmony_ci 11158c2ecf20Sopenharmony_ci tmp = sg_next(tmp); 11168c2ecf20Sopenharmony_ci ctx->sg_len++; 11178c2ecf20Sopenharmony_ci sg = sg_next(sg); 11188c2ecf20Sopenharmony_ci } 11198c2ecf20Sopenharmony_ci 11208c2ecf20Sopenharmony_ci set_bit(HASH_FLAGS_SGS_ALLOCED, &ctx->dd->hash_flags); 11218c2ecf20Sopenharmony_ci 11228c2ecf20Sopenharmony_ci return 0; 11238c2ecf20Sopenharmony_ci} 11248c2ecf20Sopenharmony_ci 11258c2ecf20Sopenharmony_ci/** 11268c2ecf20Sopenharmony_ci * s5p_hash_prepare_sgs() - prepare sg for processing 11278c2ecf20Sopenharmony_ci * @ctx: request context 11288c2ecf20Sopenharmony_ci * @sg: source scatterlist request 11298c2ecf20Sopenharmony_ci * @new_len: number of bytes to process from sg 11308c2ecf20Sopenharmony_ci * @final: final flag 11318c2ecf20Sopenharmony_ci * 11328c2ecf20Sopenharmony_ci * Check two conditions: (1) if buffers in sg have len aligned data, and (2) 11338c2ecf20Sopenharmony_ci * sg table have good aligned elements (list_ok). If one of this checks fails, 11348c2ecf20Sopenharmony_ci * then either (1) allocates new buffer for data with s5p_hash_copy_sgs, copy 11358c2ecf20Sopenharmony_ci * data into this buffer and prepare request in sgl, or (2) allocates new sg 11368c2ecf20Sopenharmony_ci * table and prepare sg elements. 11378c2ecf20Sopenharmony_ci * 11388c2ecf20Sopenharmony_ci * For digest or finup all conditions can be good, and we may not need any 11398c2ecf20Sopenharmony_ci * fixes. 11408c2ecf20Sopenharmony_ci */ 11418c2ecf20Sopenharmony_cistatic int s5p_hash_prepare_sgs(struct s5p_hash_reqctx *ctx, 11428c2ecf20Sopenharmony_ci struct scatterlist *sg, 11438c2ecf20Sopenharmony_ci unsigned int new_len, bool final) 11448c2ecf20Sopenharmony_ci{ 11458c2ecf20Sopenharmony_ci unsigned int skip = ctx->skip, nbytes = new_len, n = 0; 11468c2ecf20Sopenharmony_ci bool aligned = true, list_ok = true; 11478c2ecf20Sopenharmony_ci struct scatterlist *sg_tmp = sg; 11488c2ecf20Sopenharmony_ci 11498c2ecf20Sopenharmony_ci if (!sg || !sg->length || !new_len) 11508c2ecf20Sopenharmony_ci return 0; 11518c2ecf20Sopenharmony_ci 11528c2ecf20Sopenharmony_ci if (skip || !final) 11538c2ecf20Sopenharmony_ci list_ok = false; 11548c2ecf20Sopenharmony_ci 11558c2ecf20Sopenharmony_ci while (nbytes > 0 && sg_tmp) { 11568c2ecf20Sopenharmony_ci n++; 11578c2ecf20Sopenharmony_ci if (skip >= sg_tmp->length) { 11588c2ecf20Sopenharmony_ci skip -= sg_tmp->length; 11598c2ecf20Sopenharmony_ci if (!sg_tmp->length) { 11608c2ecf20Sopenharmony_ci aligned = false; 11618c2ecf20Sopenharmony_ci break; 11628c2ecf20Sopenharmony_ci } 11638c2ecf20Sopenharmony_ci } else { 11648c2ecf20Sopenharmony_ci if (!IS_ALIGNED(sg_tmp->length - skip, BUFLEN)) { 11658c2ecf20Sopenharmony_ci aligned = false; 11668c2ecf20Sopenharmony_ci break; 11678c2ecf20Sopenharmony_ci } 11688c2ecf20Sopenharmony_ci 11698c2ecf20Sopenharmony_ci if (nbytes < sg_tmp->length - skip) { 11708c2ecf20Sopenharmony_ci list_ok = false; 11718c2ecf20Sopenharmony_ci break; 11728c2ecf20Sopenharmony_ci } 11738c2ecf20Sopenharmony_ci 11748c2ecf20Sopenharmony_ci nbytes -= sg_tmp->length - skip; 11758c2ecf20Sopenharmony_ci skip = 0; 11768c2ecf20Sopenharmony_ci } 11778c2ecf20Sopenharmony_ci 11788c2ecf20Sopenharmony_ci sg_tmp = sg_next(sg_tmp); 11798c2ecf20Sopenharmony_ci } 11808c2ecf20Sopenharmony_ci 11818c2ecf20Sopenharmony_ci if (!aligned) 11828c2ecf20Sopenharmony_ci return s5p_hash_copy_sgs(ctx, sg, new_len); 11838c2ecf20Sopenharmony_ci else if (!list_ok) 11848c2ecf20Sopenharmony_ci return s5p_hash_copy_sg_lists(ctx, sg, new_len); 11858c2ecf20Sopenharmony_ci 11868c2ecf20Sopenharmony_ci /* 11878c2ecf20Sopenharmony_ci * Have aligned data from previous operation and/or current 11888c2ecf20Sopenharmony_ci * Note: will enter here only if (digest or finup) and aligned 11898c2ecf20Sopenharmony_ci */ 11908c2ecf20Sopenharmony_ci if (ctx->bufcnt) { 11918c2ecf20Sopenharmony_ci ctx->sg_len = n; 11928c2ecf20Sopenharmony_ci sg_init_table(ctx->sgl, 2); 11938c2ecf20Sopenharmony_ci sg_set_buf(ctx->sgl, ctx->dd->xmit_buf, ctx->bufcnt); 11948c2ecf20Sopenharmony_ci sg_chain(ctx->sgl, 2, sg); 11958c2ecf20Sopenharmony_ci ctx->sg = ctx->sgl; 11968c2ecf20Sopenharmony_ci ctx->sg_len++; 11978c2ecf20Sopenharmony_ci } else { 11988c2ecf20Sopenharmony_ci ctx->sg = sg; 11998c2ecf20Sopenharmony_ci ctx->sg_len = n; 12008c2ecf20Sopenharmony_ci } 12018c2ecf20Sopenharmony_ci 12028c2ecf20Sopenharmony_ci return 0; 12038c2ecf20Sopenharmony_ci} 12048c2ecf20Sopenharmony_ci 12058c2ecf20Sopenharmony_ci/** 12068c2ecf20Sopenharmony_ci * s5p_hash_prepare_request() - prepare request for processing 12078c2ecf20Sopenharmony_ci * @req: AHASH request 12088c2ecf20Sopenharmony_ci * @update: true if UPDATE op 12098c2ecf20Sopenharmony_ci * 12108c2ecf20Sopenharmony_ci * Note 1: we can have update flag _and_ final flag at the same time. 12118c2ecf20Sopenharmony_ci * Note 2: we enter here when digcnt > BUFLEN (=HASH_BLOCK_SIZE) or 12128c2ecf20Sopenharmony_ci * either req->nbytes or ctx->bufcnt + req->nbytes is > BUFLEN or 12138c2ecf20Sopenharmony_ci * we have final op 12148c2ecf20Sopenharmony_ci */ 12158c2ecf20Sopenharmony_cistatic int s5p_hash_prepare_request(struct ahash_request *req, bool update) 12168c2ecf20Sopenharmony_ci{ 12178c2ecf20Sopenharmony_ci struct s5p_hash_reqctx *ctx = ahash_request_ctx(req); 12188c2ecf20Sopenharmony_ci bool final = ctx->finup; 12198c2ecf20Sopenharmony_ci int xmit_len, hash_later, nbytes; 12208c2ecf20Sopenharmony_ci int ret; 12218c2ecf20Sopenharmony_ci 12228c2ecf20Sopenharmony_ci if (update) 12238c2ecf20Sopenharmony_ci nbytes = req->nbytes; 12248c2ecf20Sopenharmony_ci else 12258c2ecf20Sopenharmony_ci nbytes = 0; 12268c2ecf20Sopenharmony_ci 12278c2ecf20Sopenharmony_ci ctx->total = nbytes + ctx->bufcnt; 12288c2ecf20Sopenharmony_ci if (!ctx->total) 12298c2ecf20Sopenharmony_ci return 0; 12308c2ecf20Sopenharmony_ci 12318c2ecf20Sopenharmony_ci if (nbytes && (!IS_ALIGNED(ctx->bufcnt, BUFLEN))) { 12328c2ecf20Sopenharmony_ci /* bytes left from previous request, so fill up to BUFLEN */ 12338c2ecf20Sopenharmony_ci int len = BUFLEN - ctx->bufcnt % BUFLEN; 12348c2ecf20Sopenharmony_ci 12358c2ecf20Sopenharmony_ci if (len > nbytes) 12368c2ecf20Sopenharmony_ci len = nbytes; 12378c2ecf20Sopenharmony_ci 12388c2ecf20Sopenharmony_ci scatterwalk_map_and_copy(ctx->buffer + ctx->bufcnt, req->src, 12398c2ecf20Sopenharmony_ci 0, len, 0); 12408c2ecf20Sopenharmony_ci ctx->bufcnt += len; 12418c2ecf20Sopenharmony_ci nbytes -= len; 12428c2ecf20Sopenharmony_ci ctx->skip = len; 12438c2ecf20Sopenharmony_ci } else { 12448c2ecf20Sopenharmony_ci ctx->skip = 0; 12458c2ecf20Sopenharmony_ci } 12468c2ecf20Sopenharmony_ci 12478c2ecf20Sopenharmony_ci if (ctx->bufcnt) 12488c2ecf20Sopenharmony_ci memcpy(ctx->dd->xmit_buf, ctx->buffer, ctx->bufcnt); 12498c2ecf20Sopenharmony_ci 12508c2ecf20Sopenharmony_ci xmit_len = ctx->total; 12518c2ecf20Sopenharmony_ci if (final) { 12528c2ecf20Sopenharmony_ci hash_later = 0; 12538c2ecf20Sopenharmony_ci } else { 12548c2ecf20Sopenharmony_ci if (IS_ALIGNED(xmit_len, BUFLEN)) 12558c2ecf20Sopenharmony_ci xmit_len -= BUFLEN; 12568c2ecf20Sopenharmony_ci else 12578c2ecf20Sopenharmony_ci xmit_len -= xmit_len & (BUFLEN - 1); 12588c2ecf20Sopenharmony_ci 12598c2ecf20Sopenharmony_ci hash_later = ctx->total - xmit_len; 12608c2ecf20Sopenharmony_ci /* copy hash_later bytes from end of req->src */ 12618c2ecf20Sopenharmony_ci /* previous bytes are in xmit_buf, so no overwrite */ 12628c2ecf20Sopenharmony_ci scatterwalk_map_and_copy(ctx->buffer, req->src, 12638c2ecf20Sopenharmony_ci req->nbytes - hash_later, 12648c2ecf20Sopenharmony_ci hash_later, 0); 12658c2ecf20Sopenharmony_ci } 12668c2ecf20Sopenharmony_ci 12678c2ecf20Sopenharmony_ci if (xmit_len > BUFLEN) { 12688c2ecf20Sopenharmony_ci ret = s5p_hash_prepare_sgs(ctx, req->src, nbytes - hash_later, 12698c2ecf20Sopenharmony_ci final); 12708c2ecf20Sopenharmony_ci if (ret) 12718c2ecf20Sopenharmony_ci return ret; 12728c2ecf20Sopenharmony_ci } else { 12738c2ecf20Sopenharmony_ci /* have buffered data only */ 12748c2ecf20Sopenharmony_ci if (unlikely(!ctx->bufcnt)) { 12758c2ecf20Sopenharmony_ci /* first update didn't fill up buffer */ 12768c2ecf20Sopenharmony_ci scatterwalk_map_and_copy(ctx->dd->xmit_buf, req->src, 12778c2ecf20Sopenharmony_ci 0, xmit_len, 0); 12788c2ecf20Sopenharmony_ci } 12798c2ecf20Sopenharmony_ci 12808c2ecf20Sopenharmony_ci sg_init_table(ctx->sgl, 1); 12818c2ecf20Sopenharmony_ci sg_set_buf(ctx->sgl, ctx->dd->xmit_buf, xmit_len); 12828c2ecf20Sopenharmony_ci 12838c2ecf20Sopenharmony_ci ctx->sg = ctx->sgl; 12848c2ecf20Sopenharmony_ci ctx->sg_len = 1; 12858c2ecf20Sopenharmony_ci } 12868c2ecf20Sopenharmony_ci 12878c2ecf20Sopenharmony_ci ctx->bufcnt = hash_later; 12888c2ecf20Sopenharmony_ci if (!final) 12898c2ecf20Sopenharmony_ci ctx->total = xmit_len; 12908c2ecf20Sopenharmony_ci 12918c2ecf20Sopenharmony_ci return 0; 12928c2ecf20Sopenharmony_ci} 12938c2ecf20Sopenharmony_ci 12948c2ecf20Sopenharmony_ci/** 12958c2ecf20Sopenharmony_ci * s5p_hash_update_dma_stop() - unmap DMA 12968c2ecf20Sopenharmony_ci * @dd: secss device 12978c2ecf20Sopenharmony_ci * 12988c2ecf20Sopenharmony_ci * Unmap scatterlist ctx->sg. 12998c2ecf20Sopenharmony_ci */ 13008c2ecf20Sopenharmony_cistatic void s5p_hash_update_dma_stop(struct s5p_aes_dev *dd) 13018c2ecf20Sopenharmony_ci{ 13028c2ecf20Sopenharmony_ci const struct s5p_hash_reqctx *ctx = ahash_request_ctx(dd->hash_req); 13038c2ecf20Sopenharmony_ci 13048c2ecf20Sopenharmony_ci dma_unmap_sg(dd->dev, ctx->sg, ctx->sg_len, DMA_TO_DEVICE); 13058c2ecf20Sopenharmony_ci clear_bit(HASH_FLAGS_DMA_ACTIVE, &dd->hash_flags); 13068c2ecf20Sopenharmony_ci} 13078c2ecf20Sopenharmony_ci 13088c2ecf20Sopenharmony_ci/** 13098c2ecf20Sopenharmony_ci * s5p_hash_finish() - copy calculated digest to crypto layer 13108c2ecf20Sopenharmony_ci * @req: AHASH request 13118c2ecf20Sopenharmony_ci */ 13128c2ecf20Sopenharmony_cistatic void s5p_hash_finish(struct ahash_request *req) 13138c2ecf20Sopenharmony_ci{ 13148c2ecf20Sopenharmony_ci struct s5p_hash_reqctx *ctx = ahash_request_ctx(req); 13158c2ecf20Sopenharmony_ci struct s5p_aes_dev *dd = ctx->dd; 13168c2ecf20Sopenharmony_ci 13178c2ecf20Sopenharmony_ci if (ctx->digcnt) 13188c2ecf20Sopenharmony_ci s5p_hash_copy_result(req); 13198c2ecf20Sopenharmony_ci 13208c2ecf20Sopenharmony_ci dev_dbg(dd->dev, "hash_finish digcnt: %lld\n", ctx->digcnt); 13218c2ecf20Sopenharmony_ci} 13228c2ecf20Sopenharmony_ci 13238c2ecf20Sopenharmony_ci/** 13248c2ecf20Sopenharmony_ci * s5p_hash_finish_req() - finish request 13258c2ecf20Sopenharmony_ci * @req: AHASH request 13268c2ecf20Sopenharmony_ci * @err: error 13278c2ecf20Sopenharmony_ci */ 13288c2ecf20Sopenharmony_cistatic void s5p_hash_finish_req(struct ahash_request *req, int err) 13298c2ecf20Sopenharmony_ci{ 13308c2ecf20Sopenharmony_ci struct s5p_hash_reqctx *ctx = ahash_request_ctx(req); 13318c2ecf20Sopenharmony_ci struct s5p_aes_dev *dd = ctx->dd; 13328c2ecf20Sopenharmony_ci unsigned long flags; 13338c2ecf20Sopenharmony_ci 13348c2ecf20Sopenharmony_ci if (test_bit(HASH_FLAGS_SGS_COPIED, &dd->hash_flags)) 13358c2ecf20Sopenharmony_ci free_pages((unsigned long)sg_virt(ctx->sg), 13368c2ecf20Sopenharmony_ci get_order(ctx->sg->length)); 13378c2ecf20Sopenharmony_ci 13388c2ecf20Sopenharmony_ci if (test_bit(HASH_FLAGS_SGS_ALLOCED, &dd->hash_flags)) 13398c2ecf20Sopenharmony_ci kfree(ctx->sg); 13408c2ecf20Sopenharmony_ci 13418c2ecf20Sopenharmony_ci ctx->sg = NULL; 13428c2ecf20Sopenharmony_ci dd->hash_flags &= ~(BIT(HASH_FLAGS_SGS_ALLOCED) | 13438c2ecf20Sopenharmony_ci BIT(HASH_FLAGS_SGS_COPIED)); 13448c2ecf20Sopenharmony_ci 13458c2ecf20Sopenharmony_ci if (!err && !ctx->error) { 13468c2ecf20Sopenharmony_ci s5p_hash_read_msg(req); 13478c2ecf20Sopenharmony_ci if (test_bit(HASH_FLAGS_FINAL, &dd->hash_flags)) 13488c2ecf20Sopenharmony_ci s5p_hash_finish(req); 13498c2ecf20Sopenharmony_ci } else { 13508c2ecf20Sopenharmony_ci ctx->error = true; 13518c2ecf20Sopenharmony_ci } 13528c2ecf20Sopenharmony_ci 13538c2ecf20Sopenharmony_ci spin_lock_irqsave(&dd->hash_lock, flags); 13548c2ecf20Sopenharmony_ci dd->hash_flags &= ~(BIT(HASH_FLAGS_BUSY) | BIT(HASH_FLAGS_FINAL) | 13558c2ecf20Sopenharmony_ci BIT(HASH_FLAGS_DMA_READY) | 13568c2ecf20Sopenharmony_ci BIT(HASH_FLAGS_OUTPUT_READY)); 13578c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dd->hash_lock, flags); 13588c2ecf20Sopenharmony_ci 13598c2ecf20Sopenharmony_ci if (req->base.complete) 13608c2ecf20Sopenharmony_ci req->base.complete(&req->base, err); 13618c2ecf20Sopenharmony_ci} 13628c2ecf20Sopenharmony_ci 13638c2ecf20Sopenharmony_ci/** 13648c2ecf20Sopenharmony_ci * s5p_hash_handle_queue() - handle hash queue 13658c2ecf20Sopenharmony_ci * @dd: device s5p_aes_dev 13668c2ecf20Sopenharmony_ci * @req: AHASH request 13678c2ecf20Sopenharmony_ci * 13688c2ecf20Sopenharmony_ci * If req!=NULL enqueue it on dd->queue, if FLAGS_BUSY is not set on the 13698c2ecf20Sopenharmony_ci * device then processes the first request from the dd->queue 13708c2ecf20Sopenharmony_ci * 13718c2ecf20Sopenharmony_ci * Returns: see s5p_hash_final below. 13728c2ecf20Sopenharmony_ci */ 13738c2ecf20Sopenharmony_cistatic int s5p_hash_handle_queue(struct s5p_aes_dev *dd, 13748c2ecf20Sopenharmony_ci struct ahash_request *req) 13758c2ecf20Sopenharmony_ci{ 13768c2ecf20Sopenharmony_ci struct crypto_async_request *async_req, *backlog; 13778c2ecf20Sopenharmony_ci struct s5p_hash_reqctx *ctx; 13788c2ecf20Sopenharmony_ci unsigned long flags; 13798c2ecf20Sopenharmony_ci int err = 0, ret = 0; 13808c2ecf20Sopenharmony_ci 13818c2ecf20Sopenharmony_ciretry: 13828c2ecf20Sopenharmony_ci spin_lock_irqsave(&dd->hash_lock, flags); 13838c2ecf20Sopenharmony_ci if (req) 13848c2ecf20Sopenharmony_ci ret = ahash_enqueue_request(&dd->hash_queue, req); 13858c2ecf20Sopenharmony_ci 13868c2ecf20Sopenharmony_ci if (test_bit(HASH_FLAGS_BUSY, &dd->hash_flags)) { 13878c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dd->hash_lock, flags); 13888c2ecf20Sopenharmony_ci return ret; 13898c2ecf20Sopenharmony_ci } 13908c2ecf20Sopenharmony_ci 13918c2ecf20Sopenharmony_ci backlog = crypto_get_backlog(&dd->hash_queue); 13928c2ecf20Sopenharmony_ci async_req = crypto_dequeue_request(&dd->hash_queue); 13938c2ecf20Sopenharmony_ci if (async_req) 13948c2ecf20Sopenharmony_ci set_bit(HASH_FLAGS_BUSY, &dd->hash_flags); 13958c2ecf20Sopenharmony_ci 13968c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dd->hash_lock, flags); 13978c2ecf20Sopenharmony_ci 13988c2ecf20Sopenharmony_ci if (!async_req) 13998c2ecf20Sopenharmony_ci return ret; 14008c2ecf20Sopenharmony_ci 14018c2ecf20Sopenharmony_ci if (backlog) 14028c2ecf20Sopenharmony_ci backlog->complete(backlog, -EINPROGRESS); 14038c2ecf20Sopenharmony_ci 14048c2ecf20Sopenharmony_ci req = ahash_request_cast(async_req); 14058c2ecf20Sopenharmony_ci dd->hash_req = req; 14068c2ecf20Sopenharmony_ci ctx = ahash_request_ctx(req); 14078c2ecf20Sopenharmony_ci 14088c2ecf20Sopenharmony_ci err = s5p_hash_prepare_request(req, ctx->op_update); 14098c2ecf20Sopenharmony_ci if (err || !ctx->total) 14108c2ecf20Sopenharmony_ci goto out; 14118c2ecf20Sopenharmony_ci 14128c2ecf20Sopenharmony_ci dev_dbg(dd->dev, "handling new req, op_update: %u, nbytes: %d\n", 14138c2ecf20Sopenharmony_ci ctx->op_update, req->nbytes); 14148c2ecf20Sopenharmony_ci 14158c2ecf20Sopenharmony_ci s5p_ahash_dma_init(dd, SSS_HASHIN_INDEPENDENT); 14168c2ecf20Sopenharmony_ci if (ctx->digcnt) 14178c2ecf20Sopenharmony_ci s5p_hash_write_iv(req); /* restore hash IV */ 14188c2ecf20Sopenharmony_ci 14198c2ecf20Sopenharmony_ci if (ctx->op_update) { /* HASH_OP_UPDATE */ 14208c2ecf20Sopenharmony_ci err = s5p_hash_xmit_dma(dd, ctx->total, ctx->finup); 14218c2ecf20Sopenharmony_ci if (err != -EINPROGRESS && ctx->finup && !ctx->error) 14228c2ecf20Sopenharmony_ci /* no final() after finup() */ 14238c2ecf20Sopenharmony_ci err = s5p_hash_xmit_dma(dd, ctx->total, true); 14248c2ecf20Sopenharmony_ci } else { /* HASH_OP_FINAL */ 14258c2ecf20Sopenharmony_ci err = s5p_hash_xmit_dma(dd, ctx->total, true); 14268c2ecf20Sopenharmony_ci } 14278c2ecf20Sopenharmony_ciout: 14288c2ecf20Sopenharmony_ci if (err != -EINPROGRESS) { 14298c2ecf20Sopenharmony_ci /* hash_tasklet_cb will not finish it, so do it here */ 14308c2ecf20Sopenharmony_ci s5p_hash_finish_req(req, err); 14318c2ecf20Sopenharmony_ci req = NULL; 14328c2ecf20Sopenharmony_ci 14338c2ecf20Sopenharmony_ci /* 14348c2ecf20Sopenharmony_ci * Execute next request immediately if there is anything 14358c2ecf20Sopenharmony_ci * in queue. 14368c2ecf20Sopenharmony_ci */ 14378c2ecf20Sopenharmony_ci goto retry; 14388c2ecf20Sopenharmony_ci } 14398c2ecf20Sopenharmony_ci 14408c2ecf20Sopenharmony_ci return ret; 14418c2ecf20Sopenharmony_ci} 14428c2ecf20Sopenharmony_ci 14438c2ecf20Sopenharmony_ci/** 14448c2ecf20Sopenharmony_ci * s5p_hash_tasklet_cb() - hash tasklet 14458c2ecf20Sopenharmony_ci * @data: ptr to s5p_aes_dev 14468c2ecf20Sopenharmony_ci */ 14478c2ecf20Sopenharmony_cistatic void s5p_hash_tasklet_cb(unsigned long data) 14488c2ecf20Sopenharmony_ci{ 14498c2ecf20Sopenharmony_ci struct s5p_aes_dev *dd = (struct s5p_aes_dev *)data; 14508c2ecf20Sopenharmony_ci 14518c2ecf20Sopenharmony_ci if (!test_bit(HASH_FLAGS_BUSY, &dd->hash_flags)) { 14528c2ecf20Sopenharmony_ci s5p_hash_handle_queue(dd, NULL); 14538c2ecf20Sopenharmony_ci return; 14548c2ecf20Sopenharmony_ci } 14558c2ecf20Sopenharmony_ci 14568c2ecf20Sopenharmony_ci if (test_bit(HASH_FLAGS_DMA_READY, &dd->hash_flags)) { 14578c2ecf20Sopenharmony_ci if (test_and_clear_bit(HASH_FLAGS_DMA_ACTIVE, 14588c2ecf20Sopenharmony_ci &dd->hash_flags)) { 14598c2ecf20Sopenharmony_ci s5p_hash_update_dma_stop(dd); 14608c2ecf20Sopenharmony_ci } 14618c2ecf20Sopenharmony_ci 14628c2ecf20Sopenharmony_ci if (test_and_clear_bit(HASH_FLAGS_OUTPUT_READY, 14638c2ecf20Sopenharmony_ci &dd->hash_flags)) { 14648c2ecf20Sopenharmony_ci /* hash or semi-hash ready */ 14658c2ecf20Sopenharmony_ci clear_bit(HASH_FLAGS_DMA_READY, &dd->hash_flags); 14668c2ecf20Sopenharmony_ci goto finish; 14678c2ecf20Sopenharmony_ci } 14688c2ecf20Sopenharmony_ci } 14698c2ecf20Sopenharmony_ci 14708c2ecf20Sopenharmony_ci return; 14718c2ecf20Sopenharmony_ci 14728c2ecf20Sopenharmony_cifinish: 14738c2ecf20Sopenharmony_ci /* finish curent request */ 14748c2ecf20Sopenharmony_ci s5p_hash_finish_req(dd->hash_req, 0); 14758c2ecf20Sopenharmony_ci 14768c2ecf20Sopenharmony_ci /* If we are not busy, process next req */ 14778c2ecf20Sopenharmony_ci if (!test_bit(HASH_FLAGS_BUSY, &dd->hash_flags)) 14788c2ecf20Sopenharmony_ci s5p_hash_handle_queue(dd, NULL); 14798c2ecf20Sopenharmony_ci} 14808c2ecf20Sopenharmony_ci 14818c2ecf20Sopenharmony_ci/** 14828c2ecf20Sopenharmony_ci * s5p_hash_enqueue() - enqueue request 14838c2ecf20Sopenharmony_ci * @req: AHASH request 14848c2ecf20Sopenharmony_ci * @op: operation UPDATE (true) or FINAL (false) 14858c2ecf20Sopenharmony_ci * 14868c2ecf20Sopenharmony_ci * Returns: see s5p_hash_final below. 14878c2ecf20Sopenharmony_ci */ 14888c2ecf20Sopenharmony_cistatic int s5p_hash_enqueue(struct ahash_request *req, bool op) 14898c2ecf20Sopenharmony_ci{ 14908c2ecf20Sopenharmony_ci struct s5p_hash_reqctx *ctx = ahash_request_ctx(req); 14918c2ecf20Sopenharmony_ci struct s5p_hash_ctx *tctx = crypto_tfm_ctx(req->base.tfm); 14928c2ecf20Sopenharmony_ci 14938c2ecf20Sopenharmony_ci ctx->op_update = op; 14948c2ecf20Sopenharmony_ci 14958c2ecf20Sopenharmony_ci return s5p_hash_handle_queue(tctx->dd, req); 14968c2ecf20Sopenharmony_ci} 14978c2ecf20Sopenharmony_ci 14988c2ecf20Sopenharmony_ci/** 14998c2ecf20Sopenharmony_ci * s5p_hash_update() - process the hash input data 15008c2ecf20Sopenharmony_ci * @req: AHASH request 15018c2ecf20Sopenharmony_ci * 15028c2ecf20Sopenharmony_ci * If request will fit in buffer, copy it and return immediately 15038c2ecf20Sopenharmony_ci * else enqueue it with OP_UPDATE. 15048c2ecf20Sopenharmony_ci * 15058c2ecf20Sopenharmony_ci * Returns: see s5p_hash_final below. 15068c2ecf20Sopenharmony_ci */ 15078c2ecf20Sopenharmony_cistatic int s5p_hash_update(struct ahash_request *req) 15088c2ecf20Sopenharmony_ci{ 15098c2ecf20Sopenharmony_ci struct s5p_hash_reqctx *ctx = ahash_request_ctx(req); 15108c2ecf20Sopenharmony_ci 15118c2ecf20Sopenharmony_ci if (!req->nbytes) 15128c2ecf20Sopenharmony_ci return 0; 15138c2ecf20Sopenharmony_ci 15148c2ecf20Sopenharmony_ci if (ctx->bufcnt + req->nbytes <= BUFLEN) { 15158c2ecf20Sopenharmony_ci scatterwalk_map_and_copy(ctx->buffer + ctx->bufcnt, req->src, 15168c2ecf20Sopenharmony_ci 0, req->nbytes, 0); 15178c2ecf20Sopenharmony_ci ctx->bufcnt += req->nbytes; 15188c2ecf20Sopenharmony_ci return 0; 15198c2ecf20Sopenharmony_ci } 15208c2ecf20Sopenharmony_ci 15218c2ecf20Sopenharmony_ci return s5p_hash_enqueue(req, true); /* HASH_OP_UPDATE */ 15228c2ecf20Sopenharmony_ci} 15238c2ecf20Sopenharmony_ci 15248c2ecf20Sopenharmony_ci/** 15258c2ecf20Sopenharmony_ci * s5p_hash_final() - close up hash and calculate digest 15268c2ecf20Sopenharmony_ci * @req: AHASH request 15278c2ecf20Sopenharmony_ci * 15288c2ecf20Sopenharmony_ci * Note: in final req->src do not have any data, and req->nbytes can be 15298c2ecf20Sopenharmony_ci * non-zero. 15308c2ecf20Sopenharmony_ci * 15318c2ecf20Sopenharmony_ci * If there were no input data processed yet and the buffered hash data is 15328c2ecf20Sopenharmony_ci * less than BUFLEN (64) then calculate the final hash immediately by using 15338c2ecf20Sopenharmony_ci * SW algorithm fallback. 15348c2ecf20Sopenharmony_ci * 15358c2ecf20Sopenharmony_ci * Otherwise enqueues the current AHASH request with OP_FINAL operation op 15368c2ecf20Sopenharmony_ci * and finalize hash message in HW. Note that if digcnt!=0 then there were 15378c2ecf20Sopenharmony_ci * previous update op, so there are always some buffered bytes in ctx->buffer, 15388c2ecf20Sopenharmony_ci * which means that ctx->bufcnt!=0 15398c2ecf20Sopenharmony_ci * 15408c2ecf20Sopenharmony_ci * Returns: 15418c2ecf20Sopenharmony_ci * 0 if the request has been processed immediately, 15428c2ecf20Sopenharmony_ci * -EINPROGRESS if the operation has been queued for later execution or is set 15438c2ecf20Sopenharmony_ci * to processing by HW, 15448c2ecf20Sopenharmony_ci * -EBUSY if queue is full and request should be resubmitted later, 15458c2ecf20Sopenharmony_ci * other negative values denotes an error. 15468c2ecf20Sopenharmony_ci */ 15478c2ecf20Sopenharmony_cistatic int s5p_hash_final(struct ahash_request *req) 15488c2ecf20Sopenharmony_ci{ 15498c2ecf20Sopenharmony_ci struct s5p_hash_reqctx *ctx = ahash_request_ctx(req); 15508c2ecf20Sopenharmony_ci 15518c2ecf20Sopenharmony_ci ctx->finup = true; 15528c2ecf20Sopenharmony_ci if (ctx->error) 15538c2ecf20Sopenharmony_ci return -EINVAL; /* uncompleted hash is not needed */ 15548c2ecf20Sopenharmony_ci 15558c2ecf20Sopenharmony_ci if (!ctx->digcnt && ctx->bufcnt < BUFLEN) { 15568c2ecf20Sopenharmony_ci struct s5p_hash_ctx *tctx = crypto_tfm_ctx(req->base.tfm); 15578c2ecf20Sopenharmony_ci 15588c2ecf20Sopenharmony_ci return crypto_shash_tfm_digest(tctx->fallback, ctx->buffer, 15598c2ecf20Sopenharmony_ci ctx->bufcnt, req->result); 15608c2ecf20Sopenharmony_ci } 15618c2ecf20Sopenharmony_ci 15628c2ecf20Sopenharmony_ci return s5p_hash_enqueue(req, false); /* HASH_OP_FINAL */ 15638c2ecf20Sopenharmony_ci} 15648c2ecf20Sopenharmony_ci 15658c2ecf20Sopenharmony_ci/** 15668c2ecf20Sopenharmony_ci * s5p_hash_finup() - process last req->src and calculate digest 15678c2ecf20Sopenharmony_ci * @req: AHASH request containing the last update data 15688c2ecf20Sopenharmony_ci * 15698c2ecf20Sopenharmony_ci * Return values: see s5p_hash_final above. 15708c2ecf20Sopenharmony_ci */ 15718c2ecf20Sopenharmony_cistatic int s5p_hash_finup(struct ahash_request *req) 15728c2ecf20Sopenharmony_ci{ 15738c2ecf20Sopenharmony_ci struct s5p_hash_reqctx *ctx = ahash_request_ctx(req); 15748c2ecf20Sopenharmony_ci int err1, err2; 15758c2ecf20Sopenharmony_ci 15768c2ecf20Sopenharmony_ci ctx->finup = true; 15778c2ecf20Sopenharmony_ci 15788c2ecf20Sopenharmony_ci err1 = s5p_hash_update(req); 15798c2ecf20Sopenharmony_ci if (err1 == -EINPROGRESS || err1 == -EBUSY) 15808c2ecf20Sopenharmony_ci return err1; 15818c2ecf20Sopenharmony_ci 15828c2ecf20Sopenharmony_ci /* 15838c2ecf20Sopenharmony_ci * final() has to be always called to cleanup resources even if 15848c2ecf20Sopenharmony_ci * update() failed, except EINPROGRESS or calculate digest for small 15858c2ecf20Sopenharmony_ci * size 15868c2ecf20Sopenharmony_ci */ 15878c2ecf20Sopenharmony_ci err2 = s5p_hash_final(req); 15888c2ecf20Sopenharmony_ci 15898c2ecf20Sopenharmony_ci return err1 ?: err2; 15908c2ecf20Sopenharmony_ci} 15918c2ecf20Sopenharmony_ci 15928c2ecf20Sopenharmony_ci/** 15938c2ecf20Sopenharmony_ci * s5p_hash_init() - initialize AHASH request contex 15948c2ecf20Sopenharmony_ci * @req: AHASH request 15958c2ecf20Sopenharmony_ci * 15968c2ecf20Sopenharmony_ci * Init async hash request context. 15978c2ecf20Sopenharmony_ci */ 15988c2ecf20Sopenharmony_cistatic int s5p_hash_init(struct ahash_request *req) 15998c2ecf20Sopenharmony_ci{ 16008c2ecf20Sopenharmony_ci struct s5p_hash_reqctx *ctx = ahash_request_ctx(req); 16018c2ecf20Sopenharmony_ci struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); 16028c2ecf20Sopenharmony_ci struct s5p_hash_ctx *tctx = crypto_ahash_ctx(tfm); 16038c2ecf20Sopenharmony_ci 16048c2ecf20Sopenharmony_ci ctx->dd = tctx->dd; 16058c2ecf20Sopenharmony_ci ctx->error = false; 16068c2ecf20Sopenharmony_ci ctx->finup = false; 16078c2ecf20Sopenharmony_ci ctx->bufcnt = 0; 16088c2ecf20Sopenharmony_ci ctx->digcnt = 0; 16098c2ecf20Sopenharmony_ci ctx->total = 0; 16108c2ecf20Sopenharmony_ci ctx->skip = 0; 16118c2ecf20Sopenharmony_ci 16128c2ecf20Sopenharmony_ci dev_dbg(tctx->dd->dev, "init: digest size: %d\n", 16138c2ecf20Sopenharmony_ci crypto_ahash_digestsize(tfm)); 16148c2ecf20Sopenharmony_ci 16158c2ecf20Sopenharmony_ci switch (crypto_ahash_digestsize(tfm)) { 16168c2ecf20Sopenharmony_ci case MD5_DIGEST_SIZE: 16178c2ecf20Sopenharmony_ci ctx->engine = SSS_HASH_ENGINE_MD5; 16188c2ecf20Sopenharmony_ci ctx->nregs = HASH_MD5_MAX_REG; 16198c2ecf20Sopenharmony_ci break; 16208c2ecf20Sopenharmony_ci case SHA1_DIGEST_SIZE: 16218c2ecf20Sopenharmony_ci ctx->engine = SSS_HASH_ENGINE_SHA1; 16228c2ecf20Sopenharmony_ci ctx->nregs = HASH_SHA1_MAX_REG; 16238c2ecf20Sopenharmony_ci break; 16248c2ecf20Sopenharmony_ci case SHA256_DIGEST_SIZE: 16258c2ecf20Sopenharmony_ci ctx->engine = SSS_HASH_ENGINE_SHA256; 16268c2ecf20Sopenharmony_ci ctx->nregs = HASH_SHA256_MAX_REG; 16278c2ecf20Sopenharmony_ci break; 16288c2ecf20Sopenharmony_ci default: 16298c2ecf20Sopenharmony_ci ctx->error = true; 16308c2ecf20Sopenharmony_ci return -EINVAL; 16318c2ecf20Sopenharmony_ci } 16328c2ecf20Sopenharmony_ci 16338c2ecf20Sopenharmony_ci return 0; 16348c2ecf20Sopenharmony_ci} 16358c2ecf20Sopenharmony_ci 16368c2ecf20Sopenharmony_ci/** 16378c2ecf20Sopenharmony_ci * s5p_hash_digest - calculate digest from req->src 16388c2ecf20Sopenharmony_ci * @req: AHASH request 16398c2ecf20Sopenharmony_ci * 16408c2ecf20Sopenharmony_ci * Return values: see s5p_hash_final above. 16418c2ecf20Sopenharmony_ci */ 16428c2ecf20Sopenharmony_cistatic int s5p_hash_digest(struct ahash_request *req) 16438c2ecf20Sopenharmony_ci{ 16448c2ecf20Sopenharmony_ci return s5p_hash_init(req) ?: s5p_hash_finup(req); 16458c2ecf20Sopenharmony_ci} 16468c2ecf20Sopenharmony_ci 16478c2ecf20Sopenharmony_ci/** 16488c2ecf20Sopenharmony_ci * s5p_hash_cra_init_alg - init crypto alg transformation 16498c2ecf20Sopenharmony_ci * @tfm: crypto transformation 16508c2ecf20Sopenharmony_ci */ 16518c2ecf20Sopenharmony_cistatic int s5p_hash_cra_init_alg(struct crypto_tfm *tfm) 16528c2ecf20Sopenharmony_ci{ 16538c2ecf20Sopenharmony_ci struct s5p_hash_ctx *tctx = crypto_tfm_ctx(tfm); 16548c2ecf20Sopenharmony_ci const char *alg_name = crypto_tfm_alg_name(tfm); 16558c2ecf20Sopenharmony_ci 16568c2ecf20Sopenharmony_ci tctx->dd = s5p_dev; 16578c2ecf20Sopenharmony_ci /* Allocate a fallback and abort if it failed. */ 16588c2ecf20Sopenharmony_ci tctx->fallback = crypto_alloc_shash(alg_name, 0, 16598c2ecf20Sopenharmony_ci CRYPTO_ALG_NEED_FALLBACK); 16608c2ecf20Sopenharmony_ci if (IS_ERR(tctx->fallback)) { 16618c2ecf20Sopenharmony_ci pr_err("fallback alloc fails for '%s'\n", alg_name); 16628c2ecf20Sopenharmony_ci return PTR_ERR(tctx->fallback); 16638c2ecf20Sopenharmony_ci } 16648c2ecf20Sopenharmony_ci 16658c2ecf20Sopenharmony_ci crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm), 16668c2ecf20Sopenharmony_ci sizeof(struct s5p_hash_reqctx) + BUFLEN); 16678c2ecf20Sopenharmony_ci 16688c2ecf20Sopenharmony_ci return 0; 16698c2ecf20Sopenharmony_ci} 16708c2ecf20Sopenharmony_ci 16718c2ecf20Sopenharmony_ci/** 16728c2ecf20Sopenharmony_ci * s5p_hash_cra_init - init crypto tfm 16738c2ecf20Sopenharmony_ci * @tfm: crypto transformation 16748c2ecf20Sopenharmony_ci */ 16758c2ecf20Sopenharmony_cistatic int s5p_hash_cra_init(struct crypto_tfm *tfm) 16768c2ecf20Sopenharmony_ci{ 16778c2ecf20Sopenharmony_ci return s5p_hash_cra_init_alg(tfm); 16788c2ecf20Sopenharmony_ci} 16798c2ecf20Sopenharmony_ci 16808c2ecf20Sopenharmony_ci/** 16818c2ecf20Sopenharmony_ci * s5p_hash_cra_exit - exit crypto tfm 16828c2ecf20Sopenharmony_ci * @tfm: crypto transformation 16838c2ecf20Sopenharmony_ci * 16848c2ecf20Sopenharmony_ci * free allocated fallback 16858c2ecf20Sopenharmony_ci */ 16868c2ecf20Sopenharmony_cistatic void s5p_hash_cra_exit(struct crypto_tfm *tfm) 16878c2ecf20Sopenharmony_ci{ 16888c2ecf20Sopenharmony_ci struct s5p_hash_ctx *tctx = crypto_tfm_ctx(tfm); 16898c2ecf20Sopenharmony_ci 16908c2ecf20Sopenharmony_ci crypto_free_shash(tctx->fallback); 16918c2ecf20Sopenharmony_ci tctx->fallback = NULL; 16928c2ecf20Sopenharmony_ci} 16938c2ecf20Sopenharmony_ci 16948c2ecf20Sopenharmony_ci/** 16958c2ecf20Sopenharmony_ci * s5p_hash_export - export hash state 16968c2ecf20Sopenharmony_ci * @req: AHASH request 16978c2ecf20Sopenharmony_ci * @out: buffer for exported state 16988c2ecf20Sopenharmony_ci */ 16998c2ecf20Sopenharmony_cistatic int s5p_hash_export(struct ahash_request *req, void *out) 17008c2ecf20Sopenharmony_ci{ 17018c2ecf20Sopenharmony_ci const struct s5p_hash_reqctx *ctx = ahash_request_ctx(req); 17028c2ecf20Sopenharmony_ci 17038c2ecf20Sopenharmony_ci memcpy(out, ctx, sizeof(*ctx) + ctx->bufcnt); 17048c2ecf20Sopenharmony_ci 17058c2ecf20Sopenharmony_ci return 0; 17068c2ecf20Sopenharmony_ci} 17078c2ecf20Sopenharmony_ci 17088c2ecf20Sopenharmony_ci/** 17098c2ecf20Sopenharmony_ci * s5p_hash_import - import hash state 17108c2ecf20Sopenharmony_ci * @req: AHASH request 17118c2ecf20Sopenharmony_ci * @in: buffer with state to be imported from 17128c2ecf20Sopenharmony_ci */ 17138c2ecf20Sopenharmony_cistatic int s5p_hash_import(struct ahash_request *req, const void *in) 17148c2ecf20Sopenharmony_ci{ 17158c2ecf20Sopenharmony_ci struct s5p_hash_reqctx *ctx = ahash_request_ctx(req); 17168c2ecf20Sopenharmony_ci struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); 17178c2ecf20Sopenharmony_ci struct s5p_hash_ctx *tctx = crypto_ahash_ctx(tfm); 17188c2ecf20Sopenharmony_ci const struct s5p_hash_reqctx *ctx_in = in; 17198c2ecf20Sopenharmony_ci 17208c2ecf20Sopenharmony_ci memcpy(ctx, in, sizeof(*ctx) + BUFLEN); 17218c2ecf20Sopenharmony_ci if (ctx_in->bufcnt > BUFLEN) { 17228c2ecf20Sopenharmony_ci ctx->error = true; 17238c2ecf20Sopenharmony_ci return -EINVAL; 17248c2ecf20Sopenharmony_ci } 17258c2ecf20Sopenharmony_ci 17268c2ecf20Sopenharmony_ci ctx->dd = tctx->dd; 17278c2ecf20Sopenharmony_ci ctx->error = false; 17288c2ecf20Sopenharmony_ci 17298c2ecf20Sopenharmony_ci return 0; 17308c2ecf20Sopenharmony_ci} 17318c2ecf20Sopenharmony_ci 17328c2ecf20Sopenharmony_cistatic struct ahash_alg algs_sha1_md5_sha256[] = { 17338c2ecf20Sopenharmony_ci{ 17348c2ecf20Sopenharmony_ci .init = s5p_hash_init, 17358c2ecf20Sopenharmony_ci .update = s5p_hash_update, 17368c2ecf20Sopenharmony_ci .final = s5p_hash_final, 17378c2ecf20Sopenharmony_ci .finup = s5p_hash_finup, 17388c2ecf20Sopenharmony_ci .digest = s5p_hash_digest, 17398c2ecf20Sopenharmony_ci .export = s5p_hash_export, 17408c2ecf20Sopenharmony_ci .import = s5p_hash_import, 17418c2ecf20Sopenharmony_ci .halg.statesize = sizeof(struct s5p_hash_reqctx) + BUFLEN, 17428c2ecf20Sopenharmony_ci .halg.digestsize = SHA1_DIGEST_SIZE, 17438c2ecf20Sopenharmony_ci .halg.base = { 17448c2ecf20Sopenharmony_ci .cra_name = "sha1", 17458c2ecf20Sopenharmony_ci .cra_driver_name = "exynos-sha1", 17468c2ecf20Sopenharmony_ci .cra_priority = 100, 17478c2ecf20Sopenharmony_ci .cra_flags = CRYPTO_ALG_KERN_DRIVER_ONLY | 17488c2ecf20Sopenharmony_ci CRYPTO_ALG_ASYNC | 17498c2ecf20Sopenharmony_ci CRYPTO_ALG_NEED_FALLBACK, 17508c2ecf20Sopenharmony_ci .cra_blocksize = HASH_BLOCK_SIZE, 17518c2ecf20Sopenharmony_ci .cra_ctxsize = sizeof(struct s5p_hash_ctx), 17528c2ecf20Sopenharmony_ci .cra_alignmask = SSS_HASH_DMA_ALIGN_MASK, 17538c2ecf20Sopenharmony_ci .cra_module = THIS_MODULE, 17548c2ecf20Sopenharmony_ci .cra_init = s5p_hash_cra_init, 17558c2ecf20Sopenharmony_ci .cra_exit = s5p_hash_cra_exit, 17568c2ecf20Sopenharmony_ci } 17578c2ecf20Sopenharmony_ci}, 17588c2ecf20Sopenharmony_ci{ 17598c2ecf20Sopenharmony_ci .init = s5p_hash_init, 17608c2ecf20Sopenharmony_ci .update = s5p_hash_update, 17618c2ecf20Sopenharmony_ci .final = s5p_hash_final, 17628c2ecf20Sopenharmony_ci .finup = s5p_hash_finup, 17638c2ecf20Sopenharmony_ci .digest = s5p_hash_digest, 17648c2ecf20Sopenharmony_ci .export = s5p_hash_export, 17658c2ecf20Sopenharmony_ci .import = s5p_hash_import, 17668c2ecf20Sopenharmony_ci .halg.statesize = sizeof(struct s5p_hash_reqctx) + BUFLEN, 17678c2ecf20Sopenharmony_ci .halg.digestsize = MD5_DIGEST_SIZE, 17688c2ecf20Sopenharmony_ci .halg.base = { 17698c2ecf20Sopenharmony_ci .cra_name = "md5", 17708c2ecf20Sopenharmony_ci .cra_driver_name = "exynos-md5", 17718c2ecf20Sopenharmony_ci .cra_priority = 100, 17728c2ecf20Sopenharmony_ci .cra_flags = CRYPTO_ALG_KERN_DRIVER_ONLY | 17738c2ecf20Sopenharmony_ci CRYPTO_ALG_ASYNC | 17748c2ecf20Sopenharmony_ci CRYPTO_ALG_NEED_FALLBACK, 17758c2ecf20Sopenharmony_ci .cra_blocksize = HASH_BLOCK_SIZE, 17768c2ecf20Sopenharmony_ci .cra_ctxsize = sizeof(struct s5p_hash_ctx), 17778c2ecf20Sopenharmony_ci .cra_alignmask = SSS_HASH_DMA_ALIGN_MASK, 17788c2ecf20Sopenharmony_ci .cra_module = THIS_MODULE, 17798c2ecf20Sopenharmony_ci .cra_init = s5p_hash_cra_init, 17808c2ecf20Sopenharmony_ci .cra_exit = s5p_hash_cra_exit, 17818c2ecf20Sopenharmony_ci } 17828c2ecf20Sopenharmony_ci}, 17838c2ecf20Sopenharmony_ci{ 17848c2ecf20Sopenharmony_ci .init = s5p_hash_init, 17858c2ecf20Sopenharmony_ci .update = s5p_hash_update, 17868c2ecf20Sopenharmony_ci .final = s5p_hash_final, 17878c2ecf20Sopenharmony_ci .finup = s5p_hash_finup, 17888c2ecf20Sopenharmony_ci .digest = s5p_hash_digest, 17898c2ecf20Sopenharmony_ci .export = s5p_hash_export, 17908c2ecf20Sopenharmony_ci .import = s5p_hash_import, 17918c2ecf20Sopenharmony_ci .halg.statesize = sizeof(struct s5p_hash_reqctx) + BUFLEN, 17928c2ecf20Sopenharmony_ci .halg.digestsize = SHA256_DIGEST_SIZE, 17938c2ecf20Sopenharmony_ci .halg.base = { 17948c2ecf20Sopenharmony_ci .cra_name = "sha256", 17958c2ecf20Sopenharmony_ci .cra_driver_name = "exynos-sha256", 17968c2ecf20Sopenharmony_ci .cra_priority = 100, 17978c2ecf20Sopenharmony_ci .cra_flags = CRYPTO_ALG_KERN_DRIVER_ONLY | 17988c2ecf20Sopenharmony_ci CRYPTO_ALG_ASYNC | 17998c2ecf20Sopenharmony_ci CRYPTO_ALG_NEED_FALLBACK, 18008c2ecf20Sopenharmony_ci .cra_blocksize = HASH_BLOCK_SIZE, 18018c2ecf20Sopenharmony_ci .cra_ctxsize = sizeof(struct s5p_hash_ctx), 18028c2ecf20Sopenharmony_ci .cra_alignmask = SSS_HASH_DMA_ALIGN_MASK, 18038c2ecf20Sopenharmony_ci .cra_module = THIS_MODULE, 18048c2ecf20Sopenharmony_ci .cra_init = s5p_hash_cra_init, 18058c2ecf20Sopenharmony_ci .cra_exit = s5p_hash_cra_exit, 18068c2ecf20Sopenharmony_ci } 18078c2ecf20Sopenharmony_ci} 18088c2ecf20Sopenharmony_ci 18098c2ecf20Sopenharmony_ci}; 18108c2ecf20Sopenharmony_ci 18118c2ecf20Sopenharmony_cistatic void s5p_set_aes(struct s5p_aes_dev *dev, 18128c2ecf20Sopenharmony_ci const u8 *key, const u8 *iv, const u8 *ctr, 18138c2ecf20Sopenharmony_ci unsigned int keylen) 18148c2ecf20Sopenharmony_ci{ 18158c2ecf20Sopenharmony_ci void __iomem *keystart; 18168c2ecf20Sopenharmony_ci 18178c2ecf20Sopenharmony_ci if (iv) 18188c2ecf20Sopenharmony_ci memcpy_toio(dev->aes_ioaddr + SSS_REG_AES_IV_DATA(0), iv, 18198c2ecf20Sopenharmony_ci AES_BLOCK_SIZE); 18208c2ecf20Sopenharmony_ci 18218c2ecf20Sopenharmony_ci if (ctr) 18228c2ecf20Sopenharmony_ci memcpy_toio(dev->aes_ioaddr + SSS_REG_AES_CNT_DATA(0), ctr, 18238c2ecf20Sopenharmony_ci AES_BLOCK_SIZE); 18248c2ecf20Sopenharmony_ci 18258c2ecf20Sopenharmony_ci if (keylen == AES_KEYSIZE_256) 18268c2ecf20Sopenharmony_ci keystart = dev->aes_ioaddr + SSS_REG_AES_KEY_DATA(0); 18278c2ecf20Sopenharmony_ci else if (keylen == AES_KEYSIZE_192) 18288c2ecf20Sopenharmony_ci keystart = dev->aes_ioaddr + SSS_REG_AES_KEY_DATA(2); 18298c2ecf20Sopenharmony_ci else 18308c2ecf20Sopenharmony_ci keystart = dev->aes_ioaddr + SSS_REG_AES_KEY_DATA(4); 18318c2ecf20Sopenharmony_ci 18328c2ecf20Sopenharmony_ci memcpy_toio(keystart, key, keylen); 18338c2ecf20Sopenharmony_ci} 18348c2ecf20Sopenharmony_ci 18358c2ecf20Sopenharmony_cistatic bool s5p_is_sg_aligned(struct scatterlist *sg) 18368c2ecf20Sopenharmony_ci{ 18378c2ecf20Sopenharmony_ci while (sg) { 18388c2ecf20Sopenharmony_ci if (!IS_ALIGNED(sg->length, AES_BLOCK_SIZE)) 18398c2ecf20Sopenharmony_ci return false; 18408c2ecf20Sopenharmony_ci sg = sg_next(sg); 18418c2ecf20Sopenharmony_ci } 18428c2ecf20Sopenharmony_ci 18438c2ecf20Sopenharmony_ci return true; 18448c2ecf20Sopenharmony_ci} 18458c2ecf20Sopenharmony_ci 18468c2ecf20Sopenharmony_cistatic int s5p_set_indata_start(struct s5p_aes_dev *dev, 18478c2ecf20Sopenharmony_ci struct skcipher_request *req) 18488c2ecf20Sopenharmony_ci{ 18498c2ecf20Sopenharmony_ci struct scatterlist *sg; 18508c2ecf20Sopenharmony_ci int err; 18518c2ecf20Sopenharmony_ci 18528c2ecf20Sopenharmony_ci dev->sg_src_cpy = NULL; 18538c2ecf20Sopenharmony_ci sg = req->src; 18548c2ecf20Sopenharmony_ci if (!s5p_is_sg_aligned(sg)) { 18558c2ecf20Sopenharmony_ci dev_dbg(dev->dev, 18568c2ecf20Sopenharmony_ci "At least one unaligned source scatter list, making a copy\n"); 18578c2ecf20Sopenharmony_ci err = s5p_make_sg_cpy(dev, sg, &dev->sg_src_cpy); 18588c2ecf20Sopenharmony_ci if (err) 18598c2ecf20Sopenharmony_ci return err; 18608c2ecf20Sopenharmony_ci 18618c2ecf20Sopenharmony_ci sg = dev->sg_src_cpy; 18628c2ecf20Sopenharmony_ci } 18638c2ecf20Sopenharmony_ci 18648c2ecf20Sopenharmony_ci err = s5p_set_indata(dev, sg); 18658c2ecf20Sopenharmony_ci if (err) { 18668c2ecf20Sopenharmony_ci s5p_free_sg_cpy(dev, &dev->sg_src_cpy); 18678c2ecf20Sopenharmony_ci return err; 18688c2ecf20Sopenharmony_ci } 18698c2ecf20Sopenharmony_ci 18708c2ecf20Sopenharmony_ci return 0; 18718c2ecf20Sopenharmony_ci} 18728c2ecf20Sopenharmony_ci 18738c2ecf20Sopenharmony_cistatic int s5p_set_outdata_start(struct s5p_aes_dev *dev, 18748c2ecf20Sopenharmony_ci struct skcipher_request *req) 18758c2ecf20Sopenharmony_ci{ 18768c2ecf20Sopenharmony_ci struct scatterlist *sg; 18778c2ecf20Sopenharmony_ci int err; 18788c2ecf20Sopenharmony_ci 18798c2ecf20Sopenharmony_ci dev->sg_dst_cpy = NULL; 18808c2ecf20Sopenharmony_ci sg = req->dst; 18818c2ecf20Sopenharmony_ci if (!s5p_is_sg_aligned(sg)) { 18828c2ecf20Sopenharmony_ci dev_dbg(dev->dev, 18838c2ecf20Sopenharmony_ci "At least one unaligned dest scatter list, making a copy\n"); 18848c2ecf20Sopenharmony_ci err = s5p_make_sg_cpy(dev, sg, &dev->sg_dst_cpy); 18858c2ecf20Sopenharmony_ci if (err) 18868c2ecf20Sopenharmony_ci return err; 18878c2ecf20Sopenharmony_ci 18888c2ecf20Sopenharmony_ci sg = dev->sg_dst_cpy; 18898c2ecf20Sopenharmony_ci } 18908c2ecf20Sopenharmony_ci 18918c2ecf20Sopenharmony_ci err = s5p_set_outdata(dev, sg); 18928c2ecf20Sopenharmony_ci if (err) { 18938c2ecf20Sopenharmony_ci s5p_free_sg_cpy(dev, &dev->sg_dst_cpy); 18948c2ecf20Sopenharmony_ci return err; 18958c2ecf20Sopenharmony_ci } 18968c2ecf20Sopenharmony_ci 18978c2ecf20Sopenharmony_ci return 0; 18988c2ecf20Sopenharmony_ci} 18998c2ecf20Sopenharmony_ci 19008c2ecf20Sopenharmony_cistatic void s5p_aes_crypt_start(struct s5p_aes_dev *dev, unsigned long mode) 19018c2ecf20Sopenharmony_ci{ 19028c2ecf20Sopenharmony_ci struct skcipher_request *req = dev->req; 19038c2ecf20Sopenharmony_ci u32 aes_control; 19048c2ecf20Sopenharmony_ci unsigned long flags; 19058c2ecf20Sopenharmony_ci int err; 19068c2ecf20Sopenharmony_ci u8 *iv, *ctr; 19078c2ecf20Sopenharmony_ci 19088c2ecf20Sopenharmony_ci /* This sets bit [13:12] to 00, which selects 128-bit counter */ 19098c2ecf20Sopenharmony_ci aes_control = SSS_AES_KEY_CHANGE_MODE; 19108c2ecf20Sopenharmony_ci if (mode & FLAGS_AES_DECRYPT) 19118c2ecf20Sopenharmony_ci aes_control |= SSS_AES_MODE_DECRYPT; 19128c2ecf20Sopenharmony_ci 19138c2ecf20Sopenharmony_ci if ((mode & FLAGS_AES_MODE_MASK) == FLAGS_AES_CBC) { 19148c2ecf20Sopenharmony_ci aes_control |= SSS_AES_CHAIN_MODE_CBC; 19158c2ecf20Sopenharmony_ci iv = req->iv; 19168c2ecf20Sopenharmony_ci ctr = NULL; 19178c2ecf20Sopenharmony_ci } else if ((mode & FLAGS_AES_MODE_MASK) == FLAGS_AES_CTR) { 19188c2ecf20Sopenharmony_ci aes_control |= SSS_AES_CHAIN_MODE_CTR; 19198c2ecf20Sopenharmony_ci iv = NULL; 19208c2ecf20Sopenharmony_ci ctr = req->iv; 19218c2ecf20Sopenharmony_ci } else { 19228c2ecf20Sopenharmony_ci iv = NULL; /* AES_ECB */ 19238c2ecf20Sopenharmony_ci ctr = NULL; 19248c2ecf20Sopenharmony_ci } 19258c2ecf20Sopenharmony_ci 19268c2ecf20Sopenharmony_ci if (dev->ctx->keylen == AES_KEYSIZE_192) 19278c2ecf20Sopenharmony_ci aes_control |= SSS_AES_KEY_SIZE_192; 19288c2ecf20Sopenharmony_ci else if (dev->ctx->keylen == AES_KEYSIZE_256) 19298c2ecf20Sopenharmony_ci aes_control |= SSS_AES_KEY_SIZE_256; 19308c2ecf20Sopenharmony_ci 19318c2ecf20Sopenharmony_ci aes_control |= SSS_AES_FIFO_MODE; 19328c2ecf20Sopenharmony_ci 19338c2ecf20Sopenharmony_ci /* as a variant it is possible to use byte swapping on DMA side */ 19348c2ecf20Sopenharmony_ci aes_control |= SSS_AES_BYTESWAP_DI 19358c2ecf20Sopenharmony_ci | SSS_AES_BYTESWAP_DO 19368c2ecf20Sopenharmony_ci | SSS_AES_BYTESWAP_IV 19378c2ecf20Sopenharmony_ci | SSS_AES_BYTESWAP_KEY 19388c2ecf20Sopenharmony_ci | SSS_AES_BYTESWAP_CNT; 19398c2ecf20Sopenharmony_ci 19408c2ecf20Sopenharmony_ci spin_lock_irqsave(&dev->lock, flags); 19418c2ecf20Sopenharmony_ci 19428c2ecf20Sopenharmony_ci SSS_WRITE(dev, FCINTENCLR, 19438c2ecf20Sopenharmony_ci SSS_FCINTENCLR_BTDMAINTENCLR | SSS_FCINTENCLR_BRDMAINTENCLR); 19448c2ecf20Sopenharmony_ci SSS_WRITE(dev, FCFIFOCTRL, 0x00); 19458c2ecf20Sopenharmony_ci 19468c2ecf20Sopenharmony_ci err = s5p_set_indata_start(dev, req); 19478c2ecf20Sopenharmony_ci if (err) 19488c2ecf20Sopenharmony_ci goto indata_error; 19498c2ecf20Sopenharmony_ci 19508c2ecf20Sopenharmony_ci err = s5p_set_outdata_start(dev, req); 19518c2ecf20Sopenharmony_ci if (err) 19528c2ecf20Sopenharmony_ci goto outdata_error; 19538c2ecf20Sopenharmony_ci 19548c2ecf20Sopenharmony_ci SSS_AES_WRITE(dev, AES_CONTROL, aes_control); 19558c2ecf20Sopenharmony_ci s5p_set_aes(dev, dev->ctx->aes_key, iv, ctr, dev->ctx->keylen); 19568c2ecf20Sopenharmony_ci 19578c2ecf20Sopenharmony_ci s5p_set_dma_indata(dev, dev->sg_src); 19588c2ecf20Sopenharmony_ci s5p_set_dma_outdata(dev, dev->sg_dst); 19598c2ecf20Sopenharmony_ci 19608c2ecf20Sopenharmony_ci SSS_WRITE(dev, FCINTENSET, 19618c2ecf20Sopenharmony_ci SSS_FCINTENSET_BTDMAINTENSET | SSS_FCINTENSET_BRDMAINTENSET); 19628c2ecf20Sopenharmony_ci 19638c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dev->lock, flags); 19648c2ecf20Sopenharmony_ci 19658c2ecf20Sopenharmony_ci return; 19668c2ecf20Sopenharmony_ci 19678c2ecf20Sopenharmony_cioutdata_error: 19688c2ecf20Sopenharmony_ci s5p_unset_indata(dev); 19698c2ecf20Sopenharmony_ci 19708c2ecf20Sopenharmony_ciindata_error: 19718c2ecf20Sopenharmony_ci s5p_sg_done(dev); 19728c2ecf20Sopenharmony_ci dev->busy = false; 19738c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dev->lock, flags); 19748c2ecf20Sopenharmony_ci s5p_aes_complete(req, err); 19758c2ecf20Sopenharmony_ci} 19768c2ecf20Sopenharmony_ci 19778c2ecf20Sopenharmony_cistatic void s5p_tasklet_cb(unsigned long data) 19788c2ecf20Sopenharmony_ci{ 19798c2ecf20Sopenharmony_ci struct s5p_aes_dev *dev = (struct s5p_aes_dev *)data; 19808c2ecf20Sopenharmony_ci struct crypto_async_request *async_req, *backlog; 19818c2ecf20Sopenharmony_ci struct s5p_aes_reqctx *reqctx; 19828c2ecf20Sopenharmony_ci unsigned long flags; 19838c2ecf20Sopenharmony_ci 19848c2ecf20Sopenharmony_ci spin_lock_irqsave(&dev->lock, flags); 19858c2ecf20Sopenharmony_ci backlog = crypto_get_backlog(&dev->queue); 19868c2ecf20Sopenharmony_ci async_req = crypto_dequeue_request(&dev->queue); 19878c2ecf20Sopenharmony_ci 19888c2ecf20Sopenharmony_ci if (!async_req) { 19898c2ecf20Sopenharmony_ci dev->busy = false; 19908c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dev->lock, flags); 19918c2ecf20Sopenharmony_ci return; 19928c2ecf20Sopenharmony_ci } 19938c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dev->lock, flags); 19948c2ecf20Sopenharmony_ci 19958c2ecf20Sopenharmony_ci if (backlog) 19968c2ecf20Sopenharmony_ci backlog->complete(backlog, -EINPROGRESS); 19978c2ecf20Sopenharmony_ci 19988c2ecf20Sopenharmony_ci dev->req = skcipher_request_cast(async_req); 19998c2ecf20Sopenharmony_ci dev->ctx = crypto_tfm_ctx(dev->req->base.tfm); 20008c2ecf20Sopenharmony_ci reqctx = skcipher_request_ctx(dev->req); 20018c2ecf20Sopenharmony_ci 20028c2ecf20Sopenharmony_ci s5p_aes_crypt_start(dev, reqctx->mode); 20038c2ecf20Sopenharmony_ci} 20048c2ecf20Sopenharmony_ci 20058c2ecf20Sopenharmony_cistatic int s5p_aes_handle_req(struct s5p_aes_dev *dev, 20068c2ecf20Sopenharmony_ci struct skcipher_request *req) 20078c2ecf20Sopenharmony_ci{ 20088c2ecf20Sopenharmony_ci unsigned long flags; 20098c2ecf20Sopenharmony_ci int err; 20108c2ecf20Sopenharmony_ci 20118c2ecf20Sopenharmony_ci spin_lock_irqsave(&dev->lock, flags); 20128c2ecf20Sopenharmony_ci err = crypto_enqueue_request(&dev->queue, &req->base); 20138c2ecf20Sopenharmony_ci if (dev->busy) { 20148c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dev->lock, flags); 20158c2ecf20Sopenharmony_ci return err; 20168c2ecf20Sopenharmony_ci } 20178c2ecf20Sopenharmony_ci dev->busy = true; 20188c2ecf20Sopenharmony_ci 20198c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dev->lock, flags); 20208c2ecf20Sopenharmony_ci 20218c2ecf20Sopenharmony_ci tasklet_schedule(&dev->tasklet); 20228c2ecf20Sopenharmony_ci 20238c2ecf20Sopenharmony_ci return err; 20248c2ecf20Sopenharmony_ci} 20258c2ecf20Sopenharmony_ci 20268c2ecf20Sopenharmony_cistatic int s5p_aes_crypt(struct skcipher_request *req, unsigned long mode) 20278c2ecf20Sopenharmony_ci{ 20288c2ecf20Sopenharmony_ci struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); 20298c2ecf20Sopenharmony_ci struct s5p_aes_reqctx *reqctx = skcipher_request_ctx(req); 20308c2ecf20Sopenharmony_ci struct s5p_aes_ctx *ctx = crypto_skcipher_ctx(tfm); 20318c2ecf20Sopenharmony_ci struct s5p_aes_dev *dev = ctx->dev; 20328c2ecf20Sopenharmony_ci 20338c2ecf20Sopenharmony_ci if (!req->cryptlen) 20348c2ecf20Sopenharmony_ci return 0; 20358c2ecf20Sopenharmony_ci 20368c2ecf20Sopenharmony_ci if (!IS_ALIGNED(req->cryptlen, AES_BLOCK_SIZE) && 20378c2ecf20Sopenharmony_ci ((mode & FLAGS_AES_MODE_MASK) != FLAGS_AES_CTR)) { 20388c2ecf20Sopenharmony_ci dev_dbg(dev->dev, "request size is not exact amount of AES blocks\n"); 20398c2ecf20Sopenharmony_ci return -EINVAL; 20408c2ecf20Sopenharmony_ci } 20418c2ecf20Sopenharmony_ci 20428c2ecf20Sopenharmony_ci reqctx->mode = mode; 20438c2ecf20Sopenharmony_ci 20448c2ecf20Sopenharmony_ci return s5p_aes_handle_req(dev, req); 20458c2ecf20Sopenharmony_ci} 20468c2ecf20Sopenharmony_ci 20478c2ecf20Sopenharmony_cistatic int s5p_aes_setkey(struct crypto_skcipher *cipher, 20488c2ecf20Sopenharmony_ci const u8 *key, unsigned int keylen) 20498c2ecf20Sopenharmony_ci{ 20508c2ecf20Sopenharmony_ci struct crypto_tfm *tfm = crypto_skcipher_tfm(cipher); 20518c2ecf20Sopenharmony_ci struct s5p_aes_ctx *ctx = crypto_tfm_ctx(tfm); 20528c2ecf20Sopenharmony_ci 20538c2ecf20Sopenharmony_ci if (keylen != AES_KEYSIZE_128 && 20548c2ecf20Sopenharmony_ci keylen != AES_KEYSIZE_192 && 20558c2ecf20Sopenharmony_ci keylen != AES_KEYSIZE_256) 20568c2ecf20Sopenharmony_ci return -EINVAL; 20578c2ecf20Sopenharmony_ci 20588c2ecf20Sopenharmony_ci memcpy(ctx->aes_key, key, keylen); 20598c2ecf20Sopenharmony_ci ctx->keylen = keylen; 20608c2ecf20Sopenharmony_ci 20618c2ecf20Sopenharmony_ci return 0; 20628c2ecf20Sopenharmony_ci} 20638c2ecf20Sopenharmony_ci 20648c2ecf20Sopenharmony_cistatic int s5p_aes_ecb_encrypt(struct skcipher_request *req) 20658c2ecf20Sopenharmony_ci{ 20668c2ecf20Sopenharmony_ci return s5p_aes_crypt(req, 0); 20678c2ecf20Sopenharmony_ci} 20688c2ecf20Sopenharmony_ci 20698c2ecf20Sopenharmony_cistatic int s5p_aes_ecb_decrypt(struct skcipher_request *req) 20708c2ecf20Sopenharmony_ci{ 20718c2ecf20Sopenharmony_ci return s5p_aes_crypt(req, FLAGS_AES_DECRYPT); 20728c2ecf20Sopenharmony_ci} 20738c2ecf20Sopenharmony_ci 20748c2ecf20Sopenharmony_cistatic int s5p_aes_cbc_encrypt(struct skcipher_request *req) 20758c2ecf20Sopenharmony_ci{ 20768c2ecf20Sopenharmony_ci return s5p_aes_crypt(req, FLAGS_AES_CBC); 20778c2ecf20Sopenharmony_ci} 20788c2ecf20Sopenharmony_ci 20798c2ecf20Sopenharmony_cistatic int s5p_aes_cbc_decrypt(struct skcipher_request *req) 20808c2ecf20Sopenharmony_ci{ 20818c2ecf20Sopenharmony_ci return s5p_aes_crypt(req, FLAGS_AES_DECRYPT | FLAGS_AES_CBC); 20828c2ecf20Sopenharmony_ci} 20838c2ecf20Sopenharmony_ci 20848c2ecf20Sopenharmony_cistatic int s5p_aes_ctr_crypt(struct skcipher_request *req) 20858c2ecf20Sopenharmony_ci{ 20868c2ecf20Sopenharmony_ci return s5p_aes_crypt(req, FLAGS_AES_CTR); 20878c2ecf20Sopenharmony_ci} 20888c2ecf20Sopenharmony_ci 20898c2ecf20Sopenharmony_cistatic int s5p_aes_init_tfm(struct crypto_skcipher *tfm) 20908c2ecf20Sopenharmony_ci{ 20918c2ecf20Sopenharmony_ci struct s5p_aes_ctx *ctx = crypto_skcipher_ctx(tfm); 20928c2ecf20Sopenharmony_ci 20938c2ecf20Sopenharmony_ci ctx->dev = s5p_dev; 20948c2ecf20Sopenharmony_ci crypto_skcipher_set_reqsize(tfm, sizeof(struct s5p_aes_reqctx)); 20958c2ecf20Sopenharmony_ci 20968c2ecf20Sopenharmony_ci return 0; 20978c2ecf20Sopenharmony_ci} 20988c2ecf20Sopenharmony_ci 20998c2ecf20Sopenharmony_cistatic struct skcipher_alg algs[] = { 21008c2ecf20Sopenharmony_ci { 21018c2ecf20Sopenharmony_ci .base.cra_name = "ecb(aes)", 21028c2ecf20Sopenharmony_ci .base.cra_driver_name = "ecb-aes-s5p", 21038c2ecf20Sopenharmony_ci .base.cra_priority = 100, 21048c2ecf20Sopenharmony_ci .base.cra_flags = CRYPTO_ALG_ASYNC | 21058c2ecf20Sopenharmony_ci CRYPTO_ALG_KERN_DRIVER_ONLY, 21068c2ecf20Sopenharmony_ci .base.cra_blocksize = AES_BLOCK_SIZE, 21078c2ecf20Sopenharmony_ci .base.cra_ctxsize = sizeof(struct s5p_aes_ctx), 21088c2ecf20Sopenharmony_ci .base.cra_alignmask = 0x0f, 21098c2ecf20Sopenharmony_ci .base.cra_module = THIS_MODULE, 21108c2ecf20Sopenharmony_ci 21118c2ecf20Sopenharmony_ci .min_keysize = AES_MIN_KEY_SIZE, 21128c2ecf20Sopenharmony_ci .max_keysize = AES_MAX_KEY_SIZE, 21138c2ecf20Sopenharmony_ci .setkey = s5p_aes_setkey, 21148c2ecf20Sopenharmony_ci .encrypt = s5p_aes_ecb_encrypt, 21158c2ecf20Sopenharmony_ci .decrypt = s5p_aes_ecb_decrypt, 21168c2ecf20Sopenharmony_ci .init = s5p_aes_init_tfm, 21178c2ecf20Sopenharmony_ci }, 21188c2ecf20Sopenharmony_ci { 21198c2ecf20Sopenharmony_ci .base.cra_name = "cbc(aes)", 21208c2ecf20Sopenharmony_ci .base.cra_driver_name = "cbc-aes-s5p", 21218c2ecf20Sopenharmony_ci .base.cra_priority = 100, 21228c2ecf20Sopenharmony_ci .base.cra_flags = CRYPTO_ALG_ASYNC | 21238c2ecf20Sopenharmony_ci CRYPTO_ALG_KERN_DRIVER_ONLY, 21248c2ecf20Sopenharmony_ci .base.cra_blocksize = AES_BLOCK_SIZE, 21258c2ecf20Sopenharmony_ci .base.cra_ctxsize = sizeof(struct s5p_aes_ctx), 21268c2ecf20Sopenharmony_ci .base.cra_alignmask = 0x0f, 21278c2ecf20Sopenharmony_ci .base.cra_module = THIS_MODULE, 21288c2ecf20Sopenharmony_ci 21298c2ecf20Sopenharmony_ci .min_keysize = AES_MIN_KEY_SIZE, 21308c2ecf20Sopenharmony_ci .max_keysize = AES_MAX_KEY_SIZE, 21318c2ecf20Sopenharmony_ci .ivsize = AES_BLOCK_SIZE, 21328c2ecf20Sopenharmony_ci .setkey = s5p_aes_setkey, 21338c2ecf20Sopenharmony_ci .encrypt = s5p_aes_cbc_encrypt, 21348c2ecf20Sopenharmony_ci .decrypt = s5p_aes_cbc_decrypt, 21358c2ecf20Sopenharmony_ci .init = s5p_aes_init_tfm, 21368c2ecf20Sopenharmony_ci }, 21378c2ecf20Sopenharmony_ci { 21388c2ecf20Sopenharmony_ci .base.cra_name = "ctr(aes)", 21398c2ecf20Sopenharmony_ci .base.cra_driver_name = "ctr-aes-s5p", 21408c2ecf20Sopenharmony_ci .base.cra_priority = 100, 21418c2ecf20Sopenharmony_ci .base.cra_flags = CRYPTO_ALG_ASYNC | 21428c2ecf20Sopenharmony_ci CRYPTO_ALG_KERN_DRIVER_ONLY, 21438c2ecf20Sopenharmony_ci .base.cra_blocksize = 1, 21448c2ecf20Sopenharmony_ci .base.cra_ctxsize = sizeof(struct s5p_aes_ctx), 21458c2ecf20Sopenharmony_ci .base.cra_alignmask = 0x0f, 21468c2ecf20Sopenharmony_ci .base.cra_module = THIS_MODULE, 21478c2ecf20Sopenharmony_ci 21488c2ecf20Sopenharmony_ci .min_keysize = AES_MIN_KEY_SIZE, 21498c2ecf20Sopenharmony_ci .max_keysize = AES_MAX_KEY_SIZE, 21508c2ecf20Sopenharmony_ci .ivsize = AES_BLOCK_SIZE, 21518c2ecf20Sopenharmony_ci .setkey = s5p_aes_setkey, 21528c2ecf20Sopenharmony_ci .encrypt = s5p_aes_ctr_crypt, 21538c2ecf20Sopenharmony_ci .decrypt = s5p_aes_ctr_crypt, 21548c2ecf20Sopenharmony_ci .init = s5p_aes_init_tfm, 21558c2ecf20Sopenharmony_ci }, 21568c2ecf20Sopenharmony_ci}; 21578c2ecf20Sopenharmony_ci 21588c2ecf20Sopenharmony_cistatic int s5p_aes_probe(struct platform_device *pdev) 21598c2ecf20Sopenharmony_ci{ 21608c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 21618c2ecf20Sopenharmony_ci int i, j, err = -ENODEV; 21628c2ecf20Sopenharmony_ci const struct samsung_aes_variant *variant; 21638c2ecf20Sopenharmony_ci struct s5p_aes_dev *pdata; 21648c2ecf20Sopenharmony_ci struct resource *res; 21658c2ecf20Sopenharmony_ci unsigned int hash_i; 21668c2ecf20Sopenharmony_ci 21678c2ecf20Sopenharmony_ci if (s5p_dev) 21688c2ecf20Sopenharmony_ci return -EEXIST; 21698c2ecf20Sopenharmony_ci 21708c2ecf20Sopenharmony_ci pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); 21718c2ecf20Sopenharmony_ci if (!pdata) 21728c2ecf20Sopenharmony_ci return -ENOMEM; 21738c2ecf20Sopenharmony_ci 21748c2ecf20Sopenharmony_ci variant = find_s5p_sss_version(pdev); 21758c2ecf20Sopenharmony_ci res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 21768c2ecf20Sopenharmony_ci if (!res) 21778c2ecf20Sopenharmony_ci return -EINVAL; 21788c2ecf20Sopenharmony_ci 21798c2ecf20Sopenharmony_ci /* 21808c2ecf20Sopenharmony_ci * Note: HASH and PRNG uses the same registers in secss, avoid 21818c2ecf20Sopenharmony_ci * overwrite each other. This will drop HASH when CONFIG_EXYNOS_RNG 21828c2ecf20Sopenharmony_ci * is enabled in config. We need larger size for HASH registers in 21838c2ecf20Sopenharmony_ci * secss, current describe only AES/DES 21848c2ecf20Sopenharmony_ci */ 21858c2ecf20Sopenharmony_ci if (IS_ENABLED(CONFIG_CRYPTO_DEV_EXYNOS_HASH)) { 21868c2ecf20Sopenharmony_ci if (variant == &exynos_aes_data) { 21878c2ecf20Sopenharmony_ci res->end += 0x300; 21888c2ecf20Sopenharmony_ci pdata->use_hash = true; 21898c2ecf20Sopenharmony_ci } 21908c2ecf20Sopenharmony_ci } 21918c2ecf20Sopenharmony_ci 21928c2ecf20Sopenharmony_ci pdata->res = res; 21938c2ecf20Sopenharmony_ci pdata->ioaddr = devm_ioremap_resource(&pdev->dev, res); 21948c2ecf20Sopenharmony_ci if (IS_ERR(pdata->ioaddr)) { 21958c2ecf20Sopenharmony_ci if (!pdata->use_hash) 21968c2ecf20Sopenharmony_ci return PTR_ERR(pdata->ioaddr); 21978c2ecf20Sopenharmony_ci /* try AES without HASH */ 21988c2ecf20Sopenharmony_ci res->end -= 0x300; 21998c2ecf20Sopenharmony_ci pdata->use_hash = false; 22008c2ecf20Sopenharmony_ci pdata->ioaddr = devm_ioremap_resource(&pdev->dev, res); 22018c2ecf20Sopenharmony_ci if (IS_ERR(pdata->ioaddr)) 22028c2ecf20Sopenharmony_ci return PTR_ERR(pdata->ioaddr); 22038c2ecf20Sopenharmony_ci } 22048c2ecf20Sopenharmony_ci 22058c2ecf20Sopenharmony_ci pdata->clk = devm_clk_get(dev, variant->clk_names[0]); 22068c2ecf20Sopenharmony_ci if (IS_ERR(pdata->clk)) 22078c2ecf20Sopenharmony_ci return dev_err_probe(dev, PTR_ERR(pdata->clk), 22088c2ecf20Sopenharmony_ci "failed to find secss clock %s\n", 22098c2ecf20Sopenharmony_ci variant->clk_names[0]); 22108c2ecf20Sopenharmony_ci 22118c2ecf20Sopenharmony_ci err = clk_prepare_enable(pdata->clk); 22128c2ecf20Sopenharmony_ci if (err < 0) { 22138c2ecf20Sopenharmony_ci dev_err(dev, "Enabling clock %s failed, err %d\n", 22148c2ecf20Sopenharmony_ci variant->clk_names[0], err); 22158c2ecf20Sopenharmony_ci return err; 22168c2ecf20Sopenharmony_ci } 22178c2ecf20Sopenharmony_ci 22188c2ecf20Sopenharmony_ci if (variant->clk_names[1]) { 22198c2ecf20Sopenharmony_ci pdata->pclk = devm_clk_get(dev, variant->clk_names[1]); 22208c2ecf20Sopenharmony_ci if (IS_ERR(pdata->pclk)) { 22218c2ecf20Sopenharmony_ci err = dev_err_probe(dev, PTR_ERR(pdata->pclk), 22228c2ecf20Sopenharmony_ci "failed to find clock %s\n", 22238c2ecf20Sopenharmony_ci variant->clk_names[1]); 22248c2ecf20Sopenharmony_ci goto err_clk; 22258c2ecf20Sopenharmony_ci } 22268c2ecf20Sopenharmony_ci 22278c2ecf20Sopenharmony_ci err = clk_prepare_enable(pdata->pclk); 22288c2ecf20Sopenharmony_ci if (err < 0) { 22298c2ecf20Sopenharmony_ci dev_err(dev, "Enabling clock %s failed, err %d\n", 22308c2ecf20Sopenharmony_ci variant->clk_names[0], err); 22318c2ecf20Sopenharmony_ci goto err_clk; 22328c2ecf20Sopenharmony_ci } 22338c2ecf20Sopenharmony_ci } else { 22348c2ecf20Sopenharmony_ci pdata->pclk = NULL; 22358c2ecf20Sopenharmony_ci } 22368c2ecf20Sopenharmony_ci 22378c2ecf20Sopenharmony_ci spin_lock_init(&pdata->lock); 22388c2ecf20Sopenharmony_ci spin_lock_init(&pdata->hash_lock); 22398c2ecf20Sopenharmony_ci 22408c2ecf20Sopenharmony_ci pdata->aes_ioaddr = pdata->ioaddr + variant->aes_offset; 22418c2ecf20Sopenharmony_ci pdata->io_hash_base = pdata->ioaddr + variant->hash_offset; 22428c2ecf20Sopenharmony_ci 22438c2ecf20Sopenharmony_ci pdata->irq_fc = platform_get_irq(pdev, 0); 22448c2ecf20Sopenharmony_ci if (pdata->irq_fc < 0) { 22458c2ecf20Sopenharmony_ci err = pdata->irq_fc; 22468c2ecf20Sopenharmony_ci dev_warn(dev, "feed control interrupt is not available.\n"); 22478c2ecf20Sopenharmony_ci goto err_irq; 22488c2ecf20Sopenharmony_ci } 22498c2ecf20Sopenharmony_ci err = devm_request_threaded_irq(dev, pdata->irq_fc, NULL, 22508c2ecf20Sopenharmony_ci s5p_aes_interrupt, IRQF_ONESHOT, 22518c2ecf20Sopenharmony_ci pdev->name, pdev); 22528c2ecf20Sopenharmony_ci if (err < 0) { 22538c2ecf20Sopenharmony_ci dev_warn(dev, "feed control interrupt is not available.\n"); 22548c2ecf20Sopenharmony_ci goto err_irq; 22558c2ecf20Sopenharmony_ci } 22568c2ecf20Sopenharmony_ci 22578c2ecf20Sopenharmony_ci pdata->busy = false; 22588c2ecf20Sopenharmony_ci pdata->dev = dev; 22598c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, pdata); 22608c2ecf20Sopenharmony_ci s5p_dev = pdata; 22618c2ecf20Sopenharmony_ci 22628c2ecf20Sopenharmony_ci tasklet_init(&pdata->tasklet, s5p_tasklet_cb, (unsigned long)pdata); 22638c2ecf20Sopenharmony_ci crypto_init_queue(&pdata->queue, CRYPTO_QUEUE_LEN); 22648c2ecf20Sopenharmony_ci 22658c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(algs); i++) { 22668c2ecf20Sopenharmony_ci err = crypto_register_skcipher(&algs[i]); 22678c2ecf20Sopenharmony_ci if (err) 22688c2ecf20Sopenharmony_ci goto err_algs; 22698c2ecf20Sopenharmony_ci } 22708c2ecf20Sopenharmony_ci 22718c2ecf20Sopenharmony_ci if (pdata->use_hash) { 22728c2ecf20Sopenharmony_ci tasklet_init(&pdata->hash_tasklet, s5p_hash_tasklet_cb, 22738c2ecf20Sopenharmony_ci (unsigned long)pdata); 22748c2ecf20Sopenharmony_ci crypto_init_queue(&pdata->hash_queue, SSS_HASH_QUEUE_LENGTH); 22758c2ecf20Sopenharmony_ci 22768c2ecf20Sopenharmony_ci for (hash_i = 0; hash_i < ARRAY_SIZE(algs_sha1_md5_sha256); 22778c2ecf20Sopenharmony_ci hash_i++) { 22788c2ecf20Sopenharmony_ci struct ahash_alg *alg; 22798c2ecf20Sopenharmony_ci 22808c2ecf20Sopenharmony_ci alg = &algs_sha1_md5_sha256[hash_i]; 22818c2ecf20Sopenharmony_ci err = crypto_register_ahash(alg); 22828c2ecf20Sopenharmony_ci if (err) { 22838c2ecf20Sopenharmony_ci dev_err(dev, "can't register '%s': %d\n", 22848c2ecf20Sopenharmony_ci alg->halg.base.cra_driver_name, err); 22858c2ecf20Sopenharmony_ci goto err_hash; 22868c2ecf20Sopenharmony_ci } 22878c2ecf20Sopenharmony_ci } 22888c2ecf20Sopenharmony_ci } 22898c2ecf20Sopenharmony_ci 22908c2ecf20Sopenharmony_ci dev_info(dev, "s5p-sss driver registered\n"); 22918c2ecf20Sopenharmony_ci 22928c2ecf20Sopenharmony_ci return 0; 22938c2ecf20Sopenharmony_ci 22948c2ecf20Sopenharmony_cierr_hash: 22958c2ecf20Sopenharmony_ci for (j = hash_i - 1; j >= 0; j--) 22968c2ecf20Sopenharmony_ci crypto_unregister_ahash(&algs_sha1_md5_sha256[j]); 22978c2ecf20Sopenharmony_ci 22988c2ecf20Sopenharmony_ci tasklet_kill(&pdata->hash_tasklet); 22998c2ecf20Sopenharmony_ci res->end -= 0x300; 23008c2ecf20Sopenharmony_ci 23018c2ecf20Sopenharmony_cierr_algs: 23028c2ecf20Sopenharmony_ci if (i < ARRAY_SIZE(algs)) 23038c2ecf20Sopenharmony_ci dev_err(dev, "can't register '%s': %d\n", algs[i].base.cra_name, 23048c2ecf20Sopenharmony_ci err); 23058c2ecf20Sopenharmony_ci 23068c2ecf20Sopenharmony_ci for (j = 0; j < i; j++) 23078c2ecf20Sopenharmony_ci crypto_unregister_skcipher(&algs[j]); 23088c2ecf20Sopenharmony_ci 23098c2ecf20Sopenharmony_ci tasklet_kill(&pdata->tasklet); 23108c2ecf20Sopenharmony_ci 23118c2ecf20Sopenharmony_cierr_irq: 23128c2ecf20Sopenharmony_ci clk_disable_unprepare(pdata->pclk); 23138c2ecf20Sopenharmony_ci 23148c2ecf20Sopenharmony_cierr_clk: 23158c2ecf20Sopenharmony_ci clk_disable_unprepare(pdata->clk); 23168c2ecf20Sopenharmony_ci s5p_dev = NULL; 23178c2ecf20Sopenharmony_ci 23188c2ecf20Sopenharmony_ci return err; 23198c2ecf20Sopenharmony_ci} 23208c2ecf20Sopenharmony_ci 23218c2ecf20Sopenharmony_cistatic int s5p_aes_remove(struct platform_device *pdev) 23228c2ecf20Sopenharmony_ci{ 23238c2ecf20Sopenharmony_ci struct s5p_aes_dev *pdata = platform_get_drvdata(pdev); 23248c2ecf20Sopenharmony_ci int i; 23258c2ecf20Sopenharmony_ci 23268c2ecf20Sopenharmony_ci if (!pdata) 23278c2ecf20Sopenharmony_ci return -ENODEV; 23288c2ecf20Sopenharmony_ci 23298c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(algs); i++) 23308c2ecf20Sopenharmony_ci crypto_unregister_skcipher(&algs[i]); 23318c2ecf20Sopenharmony_ci 23328c2ecf20Sopenharmony_ci tasklet_kill(&pdata->tasklet); 23338c2ecf20Sopenharmony_ci if (pdata->use_hash) { 23348c2ecf20Sopenharmony_ci for (i = ARRAY_SIZE(algs_sha1_md5_sha256) - 1; i >= 0; i--) 23358c2ecf20Sopenharmony_ci crypto_unregister_ahash(&algs_sha1_md5_sha256[i]); 23368c2ecf20Sopenharmony_ci 23378c2ecf20Sopenharmony_ci pdata->res->end -= 0x300; 23388c2ecf20Sopenharmony_ci tasklet_kill(&pdata->hash_tasklet); 23398c2ecf20Sopenharmony_ci pdata->use_hash = false; 23408c2ecf20Sopenharmony_ci } 23418c2ecf20Sopenharmony_ci 23428c2ecf20Sopenharmony_ci clk_disable_unprepare(pdata->pclk); 23438c2ecf20Sopenharmony_ci 23448c2ecf20Sopenharmony_ci clk_disable_unprepare(pdata->clk); 23458c2ecf20Sopenharmony_ci s5p_dev = NULL; 23468c2ecf20Sopenharmony_ci 23478c2ecf20Sopenharmony_ci return 0; 23488c2ecf20Sopenharmony_ci} 23498c2ecf20Sopenharmony_ci 23508c2ecf20Sopenharmony_cistatic struct platform_driver s5p_aes_crypto = { 23518c2ecf20Sopenharmony_ci .probe = s5p_aes_probe, 23528c2ecf20Sopenharmony_ci .remove = s5p_aes_remove, 23538c2ecf20Sopenharmony_ci .driver = { 23548c2ecf20Sopenharmony_ci .name = "s5p-secss", 23558c2ecf20Sopenharmony_ci .of_match_table = s5p_sss_dt_match, 23568c2ecf20Sopenharmony_ci }, 23578c2ecf20Sopenharmony_ci}; 23588c2ecf20Sopenharmony_ci 23598c2ecf20Sopenharmony_cimodule_platform_driver(s5p_aes_crypto); 23608c2ecf20Sopenharmony_ci 23618c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("S5PV210 AES hw acceleration support."); 23628c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 23638c2ecf20Sopenharmony_ciMODULE_AUTHOR("Vladimir Zapolskiy <vzapolskiy@gmail.com>"); 23648c2ecf20Sopenharmony_ciMODULE_AUTHOR("Kamil Konieczny <k.konieczny@partner.samsung.com>"); 2365