15c8d850cSKrzysztof Kozlowski // SPDX-License-Identifier: GPL-2.0 25c8d850cSKrzysztof Kozlowski // 35c8d850cSKrzysztof Kozlowski // Cryptographic API. 45c8d850cSKrzysztof Kozlowski // 55c8d850cSKrzysztof Kozlowski // Support for Samsung S5PV210 and Exynos HW acceleration. 65c8d850cSKrzysztof Kozlowski // 75c8d850cSKrzysztof Kozlowski // Copyright (C) 2011 NetUP Inc. All rights reserved. 85c8d850cSKrzysztof Kozlowski // Copyright (c) 2017 Samsung Electronics Co., Ltd. All rights reserved. 95c8d850cSKrzysztof Kozlowski // 105c8d850cSKrzysztof Kozlowski // Hash part based on omap-sham.c driver. 11a49e490cSVladimir Zapolskiy 12a49e490cSVladimir Zapolskiy #include <linux/clk.h> 133cf9d84eSKrzysztof Kozlowski #include <linux/crypto.h> 143cf9d84eSKrzysztof Kozlowski #include <linux/dma-mapping.h> 153cf9d84eSKrzysztof Kozlowski #include <linux/err.h> 163cf9d84eSKrzysztof Kozlowski #include <linux/errno.h> 173cf9d84eSKrzysztof Kozlowski #include <linux/init.h> 183cf9d84eSKrzysztof Kozlowski #include <linux/interrupt.h> 193cf9d84eSKrzysztof Kozlowski #include <linux/io.h> 203cf9d84eSKrzysztof Kozlowski #include <linux/kernel.h> 213cf9d84eSKrzysztof Kozlowski #include <linux/module.h> 223cf9d84eSKrzysztof Kozlowski #include <linux/of.h> 23a49e490cSVladimir Zapolskiy #include <linux/platform_device.h> 24a49e490cSVladimir Zapolskiy #include <linux/scatterlist.h> 25a49e490cSVladimir Zapolskiy 26a49e490cSVladimir Zapolskiy #include <crypto/ctr.h> 273cf9d84eSKrzysztof Kozlowski #include <crypto/aes.h> 283cf9d84eSKrzysztof Kozlowski #include <crypto/algapi.h> 299e4a1100SKrzysztof Kozlowski #include <crypto/scatterwalk.h> 30a49e490cSVladimir Zapolskiy 31c2afad6cSKamil Konieczny #include <crypto/hash.h> 32c2afad6cSKamil Konieczny #include <crypto/md5.h> 33c2afad6cSKamil Konieczny #include <crypto/sha.h> 34c2afad6cSKamil Konieczny #include <crypto/internal/hash.h> 35c2afad6cSKamil Konieczny 36a49e490cSVladimir Zapolskiy #define _SBF(s, v) ((v) << (s)) 37a49e490cSVladimir Zapolskiy 38a49e490cSVladimir Zapolskiy /* Feed control registers */ 39a49e490cSVladimir Zapolskiy #define SSS_REG_FCINTSTAT 0x0000 40c2afad6cSKamil Konieczny #define SSS_FCINTSTAT_HPARTINT BIT(7) 41c2afad6cSKamil Konieczny #define SSS_FCINTSTAT_HDONEINT BIT(5) 425e00c604SKrzysztof Kozlowski #define SSS_FCINTSTAT_BRDMAINT BIT(3) 435e00c604SKrzysztof Kozlowski #define SSS_FCINTSTAT_BTDMAINT BIT(2) 445e00c604SKrzysztof Kozlowski #define SSS_FCINTSTAT_HRDMAINT BIT(1) 455e00c604SKrzysztof Kozlowski #define SSS_FCINTSTAT_PKDMAINT BIT(0) 46a49e490cSVladimir Zapolskiy 47a49e490cSVladimir Zapolskiy #define SSS_REG_FCINTENSET 0x0004 48c2afad6cSKamil Konieczny #define SSS_FCINTENSET_HPARTINTENSET BIT(7) 49c2afad6cSKamil Konieczny #define SSS_FCINTENSET_HDONEINTENSET BIT(5) 505e00c604SKrzysztof Kozlowski #define SSS_FCINTENSET_BRDMAINTENSET BIT(3) 515e00c604SKrzysztof Kozlowski #define SSS_FCINTENSET_BTDMAINTENSET BIT(2) 525e00c604SKrzysztof Kozlowski #define SSS_FCINTENSET_HRDMAINTENSET BIT(1) 535e00c604SKrzysztof Kozlowski #define SSS_FCINTENSET_PKDMAINTENSET BIT(0) 54a49e490cSVladimir Zapolskiy 55a49e490cSVladimir Zapolskiy #define SSS_REG_FCINTENCLR 0x0008 56c2afad6cSKamil Konieczny #define SSS_FCINTENCLR_HPARTINTENCLR BIT(7) 57c2afad6cSKamil Konieczny #define SSS_FCINTENCLR_HDONEINTENCLR BIT(5) 585e00c604SKrzysztof Kozlowski #define SSS_FCINTENCLR_BRDMAINTENCLR BIT(3) 595e00c604SKrzysztof Kozlowski #define SSS_FCINTENCLR_BTDMAINTENCLR BIT(2) 605e00c604SKrzysztof Kozlowski #define SSS_FCINTENCLR_HRDMAINTENCLR BIT(1) 615e00c604SKrzysztof Kozlowski #define SSS_FCINTENCLR_PKDMAINTENCLR BIT(0) 62a49e490cSVladimir Zapolskiy 63a49e490cSVladimir Zapolskiy #define SSS_REG_FCINTPEND 0x000C 64c2afad6cSKamil Konieczny #define SSS_FCINTPEND_HPARTINTP BIT(7) 65c2afad6cSKamil Konieczny #define SSS_FCINTPEND_HDONEINTP BIT(5) 665e00c604SKrzysztof Kozlowski #define SSS_FCINTPEND_BRDMAINTP BIT(3) 675e00c604SKrzysztof Kozlowski #define SSS_FCINTPEND_BTDMAINTP BIT(2) 685e00c604SKrzysztof Kozlowski #define SSS_FCINTPEND_HRDMAINTP BIT(1) 695e00c604SKrzysztof Kozlowski #define SSS_FCINTPEND_PKDMAINTP BIT(0) 70a49e490cSVladimir Zapolskiy 71a49e490cSVladimir Zapolskiy #define SSS_REG_FCFIFOSTAT 0x0010 725e00c604SKrzysztof Kozlowski #define SSS_FCFIFOSTAT_BRFIFOFUL BIT(7) 735e00c604SKrzysztof Kozlowski #define SSS_FCFIFOSTAT_BRFIFOEMP BIT(6) 745e00c604SKrzysztof Kozlowski #define SSS_FCFIFOSTAT_BTFIFOFUL BIT(5) 755e00c604SKrzysztof Kozlowski #define SSS_FCFIFOSTAT_BTFIFOEMP BIT(4) 765e00c604SKrzysztof Kozlowski #define SSS_FCFIFOSTAT_HRFIFOFUL BIT(3) 775e00c604SKrzysztof Kozlowski #define SSS_FCFIFOSTAT_HRFIFOEMP BIT(2) 785e00c604SKrzysztof Kozlowski #define SSS_FCFIFOSTAT_PKFIFOFUL BIT(1) 795e00c604SKrzysztof Kozlowski #define SSS_FCFIFOSTAT_PKFIFOEMP BIT(0) 80a49e490cSVladimir Zapolskiy 81a49e490cSVladimir Zapolskiy #define SSS_REG_FCFIFOCTRL 0x0014 825e00c604SKrzysztof Kozlowski #define SSS_FCFIFOCTRL_DESSEL BIT(2) 83a49e490cSVladimir Zapolskiy #define SSS_HASHIN_INDEPENDENT _SBF(0, 0x00) 84a49e490cSVladimir Zapolskiy #define SSS_HASHIN_CIPHER_INPUT _SBF(0, 0x01) 85a49e490cSVladimir Zapolskiy #define SSS_HASHIN_CIPHER_OUTPUT _SBF(0, 0x02) 86c2afad6cSKamil Konieczny #define SSS_HASHIN_MASK _SBF(0, 0x03) 87a49e490cSVladimir Zapolskiy 88a49e490cSVladimir Zapolskiy #define SSS_REG_FCBRDMAS 0x0020 89a49e490cSVladimir Zapolskiy #define SSS_REG_FCBRDMAL 0x0024 90a49e490cSVladimir Zapolskiy #define SSS_REG_FCBRDMAC 0x0028 915e00c604SKrzysztof Kozlowski #define SSS_FCBRDMAC_BYTESWAP BIT(1) 925e00c604SKrzysztof Kozlowski #define SSS_FCBRDMAC_FLUSH BIT(0) 93a49e490cSVladimir Zapolskiy 94a49e490cSVladimir Zapolskiy #define SSS_REG_FCBTDMAS 0x0030 95a49e490cSVladimir Zapolskiy #define SSS_REG_FCBTDMAL 0x0034 96a49e490cSVladimir Zapolskiy #define SSS_REG_FCBTDMAC 0x0038 975e00c604SKrzysztof Kozlowski #define SSS_FCBTDMAC_BYTESWAP BIT(1) 985e00c604SKrzysztof Kozlowski #define SSS_FCBTDMAC_FLUSH BIT(0) 99a49e490cSVladimir Zapolskiy 100a49e490cSVladimir Zapolskiy #define SSS_REG_FCHRDMAS 0x0040 101a49e490cSVladimir Zapolskiy #define SSS_REG_FCHRDMAL 0x0044 102a49e490cSVladimir Zapolskiy #define SSS_REG_FCHRDMAC 0x0048 1035e00c604SKrzysztof Kozlowski #define SSS_FCHRDMAC_BYTESWAP BIT(1) 1045e00c604SKrzysztof Kozlowski #define SSS_FCHRDMAC_FLUSH BIT(0) 105a49e490cSVladimir Zapolskiy 106a49e490cSVladimir Zapolskiy #define SSS_REG_FCPKDMAS 0x0050 107a49e490cSVladimir Zapolskiy #define SSS_REG_FCPKDMAL 0x0054 108a49e490cSVladimir Zapolskiy #define SSS_REG_FCPKDMAC 0x0058 1095e00c604SKrzysztof Kozlowski #define SSS_FCPKDMAC_BYTESWAP BIT(3) 1105e00c604SKrzysztof Kozlowski #define SSS_FCPKDMAC_DESCEND BIT(2) 1115e00c604SKrzysztof Kozlowski #define SSS_FCPKDMAC_TRANSMIT BIT(1) 1125e00c604SKrzysztof Kozlowski #define SSS_FCPKDMAC_FLUSH BIT(0) 113a49e490cSVladimir Zapolskiy 114a49e490cSVladimir Zapolskiy #define SSS_REG_FCPKDMAO 0x005C 115a49e490cSVladimir Zapolskiy 116a49e490cSVladimir Zapolskiy /* AES registers */ 11789245107SNaveen Krishna Chatradhi #define SSS_REG_AES_CONTROL 0x00 1185e00c604SKrzysztof Kozlowski #define SSS_AES_BYTESWAP_DI BIT(11) 1195e00c604SKrzysztof Kozlowski #define SSS_AES_BYTESWAP_DO BIT(10) 1205e00c604SKrzysztof Kozlowski #define SSS_AES_BYTESWAP_IV BIT(9) 1215e00c604SKrzysztof Kozlowski #define SSS_AES_BYTESWAP_CNT BIT(8) 1225e00c604SKrzysztof Kozlowski #define SSS_AES_BYTESWAP_KEY BIT(7) 1235e00c604SKrzysztof Kozlowski #define SSS_AES_KEY_CHANGE_MODE BIT(6) 124a49e490cSVladimir Zapolskiy #define SSS_AES_KEY_SIZE_128 _SBF(4, 0x00) 125a49e490cSVladimir Zapolskiy #define SSS_AES_KEY_SIZE_192 _SBF(4, 0x01) 126a49e490cSVladimir Zapolskiy #define SSS_AES_KEY_SIZE_256 _SBF(4, 0x02) 1275e00c604SKrzysztof Kozlowski #define SSS_AES_FIFO_MODE BIT(3) 128a49e490cSVladimir Zapolskiy #define SSS_AES_CHAIN_MODE_ECB _SBF(1, 0x00) 129a49e490cSVladimir Zapolskiy #define SSS_AES_CHAIN_MODE_CBC _SBF(1, 0x01) 130a49e490cSVladimir Zapolskiy #define SSS_AES_CHAIN_MODE_CTR _SBF(1, 0x02) 1315e00c604SKrzysztof Kozlowski #define SSS_AES_MODE_DECRYPT BIT(0) 132a49e490cSVladimir Zapolskiy 13389245107SNaveen Krishna Chatradhi #define SSS_REG_AES_STATUS 0x04 1345e00c604SKrzysztof Kozlowski #define SSS_AES_BUSY BIT(2) 1355e00c604SKrzysztof Kozlowski #define SSS_AES_INPUT_READY BIT(1) 1365e00c604SKrzysztof Kozlowski #define SSS_AES_OUTPUT_READY BIT(0) 137a49e490cSVladimir Zapolskiy 13889245107SNaveen Krishna Chatradhi #define SSS_REG_AES_IN_DATA(s) (0x10 + (s << 2)) 13989245107SNaveen Krishna Chatradhi #define SSS_REG_AES_OUT_DATA(s) (0x20 + (s << 2)) 14089245107SNaveen Krishna Chatradhi #define SSS_REG_AES_IV_DATA(s) (0x30 + (s << 2)) 14189245107SNaveen Krishna Chatradhi #define SSS_REG_AES_CNT_DATA(s) (0x40 + (s << 2)) 14289245107SNaveen Krishna Chatradhi #define SSS_REG_AES_KEY_DATA(s) (0x80 + (s << 2)) 143a49e490cSVladimir Zapolskiy 144a49e490cSVladimir Zapolskiy #define SSS_REG(dev, reg) ((dev)->ioaddr + (SSS_REG_##reg)) 145a49e490cSVladimir Zapolskiy #define SSS_READ(dev, reg) __raw_readl(SSS_REG(dev, reg)) 146a49e490cSVladimir Zapolskiy #define SSS_WRITE(dev, reg, val) __raw_writel((val), SSS_REG(dev, reg)) 147a49e490cSVladimir Zapolskiy 14889245107SNaveen Krishna Chatradhi #define SSS_AES_REG(dev, reg) ((dev)->aes_ioaddr + SSS_REG_##reg) 14989245107SNaveen Krishna Chatradhi #define SSS_AES_WRITE(dev, reg, val) __raw_writel((val), \ 15089245107SNaveen Krishna Chatradhi SSS_AES_REG(dev, reg)) 15189245107SNaveen Krishna Chatradhi 152a49e490cSVladimir Zapolskiy /* HW engine modes */ 1535e00c604SKrzysztof Kozlowski #define FLAGS_AES_DECRYPT BIT(0) 154a49e490cSVladimir Zapolskiy #define FLAGS_AES_MODE_MASK _SBF(1, 0x03) 155a49e490cSVladimir Zapolskiy #define FLAGS_AES_CBC _SBF(1, 0x01) 156a49e490cSVladimir Zapolskiy #define FLAGS_AES_CTR _SBF(1, 0x02) 157a49e490cSVladimir Zapolskiy 158a49e490cSVladimir Zapolskiy #define AES_KEY_LEN 16 159a49e490cSVladimir Zapolskiy #define CRYPTO_QUEUE_LEN 1 160a49e490cSVladimir Zapolskiy 161c2afad6cSKamil Konieczny /* HASH registers */ 162c2afad6cSKamil Konieczny #define SSS_REG_HASH_CTRL 0x00 163c2afad6cSKamil Konieczny 164c2afad6cSKamil Konieczny #define SSS_HASH_USER_IV_EN BIT(5) 165c2afad6cSKamil Konieczny #define SSS_HASH_INIT_BIT BIT(4) 166c2afad6cSKamil Konieczny #define SSS_HASH_ENGINE_SHA1 _SBF(1, 0x00) 167c2afad6cSKamil Konieczny #define SSS_HASH_ENGINE_MD5 _SBF(1, 0x01) 168c2afad6cSKamil Konieczny #define SSS_HASH_ENGINE_SHA256 _SBF(1, 0x02) 169c2afad6cSKamil Konieczny 170c2afad6cSKamil Konieczny #define SSS_HASH_ENGINE_MASK _SBF(1, 0x03) 171c2afad6cSKamil Konieczny 172c2afad6cSKamil Konieczny #define SSS_REG_HASH_CTRL_PAUSE 0x04 173c2afad6cSKamil Konieczny 174c2afad6cSKamil Konieczny #define SSS_HASH_PAUSE BIT(0) 175c2afad6cSKamil Konieczny 176c2afad6cSKamil Konieczny #define SSS_REG_HASH_CTRL_FIFO 0x08 177c2afad6cSKamil Konieczny 178c2afad6cSKamil Konieczny #define SSS_HASH_FIFO_MODE_DMA BIT(0) 179c2afad6cSKamil Konieczny #define SSS_HASH_FIFO_MODE_CPU 0 180c2afad6cSKamil Konieczny 181c2afad6cSKamil Konieczny #define SSS_REG_HASH_CTRL_SWAP 0x0C 182c2afad6cSKamil Konieczny 183c2afad6cSKamil Konieczny #define SSS_HASH_BYTESWAP_DI BIT(3) 184c2afad6cSKamil Konieczny #define SSS_HASH_BYTESWAP_DO BIT(2) 185c2afad6cSKamil Konieczny #define SSS_HASH_BYTESWAP_IV BIT(1) 186c2afad6cSKamil Konieczny #define SSS_HASH_BYTESWAP_KEY BIT(0) 187c2afad6cSKamil Konieczny 188c2afad6cSKamil Konieczny #define SSS_REG_HASH_STATUS 0x10 189c2afad6cSKamil Konieczny 190c2afad6cSKamil Konieczny #define SSS_HASH_STATUS_MSG_DONE BIT(6) 191c2afad6cSKamil Konieczny #define SSS_HASH_STATUS_PARTIAL_DONE BIT(4) 192c2afad6cSKamil Konieczny #define SSS_HASH_STATUS_BUFFER_READY BIT(0) 193c2afad6cSKamil Konieczny 194c2afad6cSKamil Konieczny #define SSS_REG_HASH_MSG_SIZE_LOW 0x20 195c2afad6cSKamil Konieczny #define SSS_REG_HASH_MSG_SIZE_HIGH 0x24 196c2afad6cSKamil Konieczny 197c2afad6cSKamil Konieczny #define SSS_REG_HASH_PRE_MSG_SIZE_LOW 0x28 198c2afad6cSKamil Konieczny #define SSS_REG_HASH_PRE_MSG_SIZE_HIGH 0x2C 199c2afad6cSKamil Konieczny 200c2afad6cSKamil Konieczny #define SSS_REG_HASH_IV(s) (0xB0 + ((s) << 2)) 201c2afad6cSKamil Konieczny #define SSS_REG_HASH_OUT(s) (0x100 + ((s) << 2)) 202c2afad6cSKamil Konieczny 203c2afad6cSKamil Konieczny #define HASH_BLOCK_SIZE 64 204c2afad6cSKamil Konieczny #define HASH_REG_SIZEOF 4 205c2afad6cSKamil Konieczny #define HASH_MD5_MAX_REG (MD5_DIGEST_SIZE / HASH_REG_SIZEOF) 206c2afad6cSKamil Konieczny #define HASH_SHA1_MAX_REG (SHA1_DIGEST_SIZE / HASH_REG_SIZEOF) 207c2afad6cSKamil Konieczny #define HASH_SHA256_MAX_REG (SHA256_DIGEST_SIZE / HASH_REG_SIZEOF) 208c2afad6cSKamil Konieczny 209c2afad6cSKamil Konieczny /* 210c2afad6cSKamil Konieczny * HASH bit numbers, used by device, setting in dev->hash_flags with 211c2afad6cSKamil Konieczny * functions set_bit(), clear_bit() or tested with test_bit() or BIT(), 212c2afad6cSKamil Konieczny * to keep HASH state BUSY or FREE, or to signal state from irq_handler 213c2afad6cSKamil Konieczny * to hash_tasklet. SGS keep track of allocated memory for scatterlist 214c2afad6cSKamil Konieczny */ 215c2afad6cSKamil Konieczny #define HASH_FLAGS_BUSY 0 216c2afad6cSKamil Konieczny #define HASH_FLAGS_FINAL 1 217c2afad6cSKamil Konieczny #define HASH_FLAGS_DMA_ACTIVE 2 218c2afad6cSKamil Konieczny #define HASH_FLAGS_OUTPUT_READY 3 219c2afad6cSKamil Konieczny #define HASH_FLAGS_DMA_READY 4 220c2afad6cSKamil Konieczny #define HASH_FLAGS_SGS_COPIED 5 221c2afad6cSKamil Konieczny #define HASH_FLAGS_SGS_ALLOCED 6 222c2afad6cSKamil Konieczny 223c2afad6cSKamil Konieczny /* HASH HW constants */ 224c2afad6cSKamil Konieczny #define BUFLEN HASH_BLOCK_SIZE 225c2afad6cSKamil Konieczny 226c2afad6cSKamil Konieczny #define SSS_HASH_DMA_LEN_ALIGN 8 227c2afad6cSKamil Konieczny #define SSS_HASH_DMA_ALIGN_MASK (SSS_HASH_DMA_LEN_ALIGN - 1) 228c2afad6cSKamil Konieczny 229c2afad6cSKamil Konieczny #define SSS_HASH_QUEUE_LENGTH 10 230c2afad6cSKamil Konieczny 23189245107SNaveen Krishna Chatradhi /** 23289245107SNaveen Krishna Chatradhi * struct samsung_aes_variant - platform specific SSS driver data 23389245107SNaveen Krishna Chatradhi * @aes_offset: AES register offset from SSS module's base. 234c2afad6cSKamil Konieczny * @hash_offset: HASH register offset from SSS module's base. 23589245107SNaveen Krishna Chatradhi * 23689245107SNaveen Krishna Chatradhi * Specifies platform specific configuration of SSS module. 23789245107SNaveen Krishna Chatradhi * Note: A structure for driver specific platform data is used for future 23889245107SNaveen Krishna Chatradhi * expansion of its usage. 23989245107SNaveen Krishna Chatradhi */ 24089245107SNaveen Krishna Chatradhi struct samsung_aes_variant { 24189245107SNaveen Krishna Chatradhi unsigned int aes_offset; 242c2afad6cSKamil Konieczny unsigned int hash_offset; 24389245107SNaveen Krishna Chatradhi }; 24489245107SNaveen Krishna Chatradhi 245a49e490cSVladimir Zapolskiy struct s5p_aes_reqctx { 246a49e490cSVladimir Zapolskiy unsigned long mode; 247a49e490cSVladimir Zapolskiy }; 248a49e490cSVladimir Zapolskiy 249a49e490cSVladimir Zapolskiy struct s5p_aes_ctx { 250a49e490cSVladimir Zapolskiy struct s5p_aes_dev *dev; 251a49e490cSVladimir Zapolskiy 252a49e490cSVladimir Zapolskiy uint8_t aes_key[AES_MAX_KEY_SIZE]; 253a49e490cSVladimir Zapolskiy uint8_t nonce[CTR_RFC3686_NONCE_SIZE]; 254a49e490cSVladimir Zapolskiy int keylen; 255a49e490cSVladimir Zapolskiy }; 256a49e490cSVladimir Zapolskiy 257106d7334SKrzysztof Kozlowski /** 258106d7334SKrzysztof Kozlowski * struct s5p_aes_dev - Crypto device state container 259106d7334SKrzysztof Kozlowski * @dev: Associated device 260106d7334SKrzysztof Kozlowski * @clk: Clock for accessing hardware 261106d7334SKrzysztof Kozlowski * @ioaddr: Mapped IO memory region 262106d7334SKrzysztof Kozlowski * @aes_ioaddr: Per-varian offset for AES block IO memory 263106d7334SKrzysztof Kozlowski * @irq_fc: Feed control interrupt line 264106d7334SKrzysztof Kozlowski * @req: Crypto request currently handled by the device 265106d7334SKrzysztof Kozlowski * @ctx: Configuration for currently handled crypto request 266106d7334SKrzysztof Kozlowski * @sg_src: Scatter list with source data for currently handled block 267106d7334SKrzysztof Kozlowski * in device. This is DMA-mapped into device. 268106d7334SKrzysztof Kozlowski * @sg_dst: Scatter list with destination data for currently handled block 269106d7334SKrzysztof Kozlowski * in device. This is DMA-mapped into device. 270106d7334SKrzysztof Kozlowski * @sg_src_cpy: In case of unaligned access, copied scatter list 271106d7334SKrzysztof Kozlowski * with source data. 272106d7334SKrzysztof Kozlowski * @sg_dst_cpy: In case of unaligned access, copied scatter list 273106d7334SKrzysztof Kozlowski * with destination data. 274106d7334SKrzysztof Kozlowski * @tasklet: New request scheduling jib 275106d7334SKrzysztof Kozlowski * @queue: Crypto queue 276106d7334SKrzysztof Kozlowski * @busy: Indicates whether the device is currently handling some request 277106d7334SKrzysztof Kozlowski * thus it uses some of the fields from this state, like: 278106d7334SKrzysztof Kozlowski * req, ctx, sg_src/dst (and copies). This essentially 279106d7334SKrzysztof Kozlowski * protects against concurrent access to these fields. 280106d7334SKrzysztof Kozlowski * @lock: Lock for protecting both access to device hardware registers 281106d7334SKrzysztof Kozlowski * and fields related to current request (including the busy field). 282c2afad6cSKamil Konieczny * @res: Resources for hash. 283c2afad6cSKamil Konieczny * @io_hash_base: Per-variant offset for HASH block IO memory. 284c2afad6cSKamil Konieczny * @hash_lock: Lock for protecting hash_req, hash_queue and hash_flags 285c2afad6cSKamil Konieczny * variable. 286c2afad6cSKamil Konieczny * @hash_flags: Flags for current HASH op. 287c2afad6cSKamil Konieczny * @hash_queue: Async hash queue. 288c2afad6cSKamil Konieczny * @hash_tasklet: New HASH request scheduling job. 289c2afad6cSKamil Konieczny * @xmit_buf: Buffer for current HASH request transfer into SSS block. 290c2afad6cSKamil Konieczny * @hash_req: Current request sending to SSS HASH block. 291c2afad6cSKamil Konieczny * @hash_sg_iter: Scatterlist transferred through DMA into SSS HASH block. 292c2afad6cSKamil Konieczny * @hash_sg_cnt: Counter for hash_sg_iter. 293c2afad6cSKamil Konieczny * 294c2afad6cSKamil Konieczny * @use_hash: true if HASH algs enabled 295106d7334SKrzysztof Kozlowski */ 296a49e490cSVladimir Zapolskiy struct s5p_aes_dev { 297a49e490cSVladimir Zapolskiy struct device *dev; 298a49e490cSVladimir Zapolskiy struct clk *clk; 299a49e490cSVladimir Zapolskiy void __iomem *ioaddr; 30089245107SNaveen Krishna Chatradhi void __iomem *aes_ioaddr; 301a49e490cSVladimir Zapolskiy int irq_fc; 302a49e490cSVladimir Zapolskiy 303a49e490cSVladimir Zapolskiy struct ablkcipher_request *req; 304a49e490cSVladimir Zapolskiy struct s5p_aes_ctx *ctx; 305a49e490cSVladimir Zapolskiy struct scatterlist *sg_src; 306a49e490cSVladimir Zapolskiy struct scatterlist *sg_dst; 307a49e490cSVladimir Zapolskiy 3089e4a1100SKrzysztof Kozlowski struct scatterlist *sg_src_cpy; 3099e4a1100SKrzysztof Kozlowski struct scatterlist *sg_dst_cpy; 3109e4a1100SKrzysztof Kozlowski 311a49e490cSVladimir Zapolskiy struct tasklet_struct tasklet; 312a49e490cSVladimir Zapolskiy struct crypto_queue queue; 313a49e490cSVladimir Zapolskiy bool busy; 314a49e490cSVladimir Zapolskiy spinlock_t lock; 315c2afad6cSKamil Konieczny 316c2afad6cSKamil Konieczny struct resource *res; 317c2afad6cSKamil Konieczny void __iomem *io_hash_base; 318c2afad6cSKamil Konieczny 319c2afad6cSKamil Konieczny spinlock_t hash_lock; /* protect hash_ vars */ 320c2afad6cSKamil Konieczny unsigned long hash_flags; 321c2afad6cSKamil Konieczny struct crypto_queue hash_queue; 322c2afad6cSKamil Konieczny struct tasklet_struct hash_tasklet; 323c2afad6cSKamil Konieczny 324c2afad6cSKamil Konieczny u8 xmit_buf[BUFLEN]; 325c2afad6cSKamil Konieczny struct ahash_request *hash_req; 326c2afad6cSKamil Konieczny struct scatterlist *hash_sg_iter; 327c2afad6cSKamil Konieczny unsigned int hash_sg_cnt; 328c2afad6cSKamil Konieczny 329c2afad6cSKamil Konieczny bool use_hash; 330a49e490cSVladimir Zapolskiy }; 331a49e490cSVladimir Zapolskiy 332c2afad6cSKamil Konieczny /** 333c2afad6cSKamil Konieczny * struct s5p_hash_reqctx - HASH request context 334c2afad6cSKamil Konieczny * @dd: Associated device 335c2afad6cSKamil Konieczny * @op_update: Current request operation (OP_UPDATE or OP_FINAL) 336c2afad6cSKamil Konieczny * @digcnt: Number of bytes processed by HW (without buffer[] ones) 337c2afad6cSKamil Konieczny * @digest: Digest message or IV for partial result 338c2afad6cSKamil Konieczny * @nregs: Number of HW registers for digest or IV read/write 339c2afad6cSKamil Konieczny * @engine: Bits for selecting type of HASH in SSS block 340c2afad6cSKamil Konieczny * @sg: sg for DMA transfer 341c2afad6cSKamil Konieczny * @sg_len: Length of sg for DMA transfer 342c2afad6cSKamil Konieczny * @sgl[]: sg for joining buffer and req->src scatterlist 343c2afad6cSKamil Konieczny * @skip: Skip offset in req->src for current op 344c2afad6cSKamil Konieczny * @total: Total number of bytes for current request 345c2afad6cSKamil Konieczny * @finup: Keep state for finup or final. 346c2afad6cSKamil Konieczny * @error: Keep track of error. 347c2afad6cSKamil Konieczny * @bufcnt: Number of bytes holded in buffer[] 348c2afad6cSKamil Konieczny * @buffer[]: For byte(s) from end of req->src in UPDATE op 349c2afad6cSKamil Konieczny */ 350c2afad6cSKamil Konieczny struct s5p_hash_reqctx { 351c2afad6cSKamil Konieczny struct s5p_aes_dev *dd; 352c2afad6cSKamil Konieczny bool op_update; 353c2afad6cSKamil Konieczny 354c2afad6cSKamil Konieczny u64 digcnt; 355c2afad6cSKamil Konieczny u8 digest[SHA256_DIGEST_SIZE]; 356c2afad6cSKamil Konieczny 357c2afad6cSKamil Konieczny unsigned int nregs; /* digest_size / sizeof(reg) */ 358c2afad6cSKamil Konieczny u32 engine; 359c2afad6cSKamil Konieczny 360c2afad6cSKamil Konieczny struct scatterlist *sg; 361c2afad6cSKamil Konieczny unsigned int sg_len; 362c2afad6cSKamil Konieczny struct scatterlist sgl[2]; 363c2afad6cSKamil Konieczny unsigned int skip; 364c2afad6cSKamil Konieczny unsigned int total; 365c2afad6cSKamil Konieczny bool finup; 366c2afad6cSKamil Konieczny bool error; 367c2afad6cSKamil Konieczny 368c2afad6cSKamil Konieczny u32 bufcnt; 369c2afad6cSKamil Konieczny u8 buffer[0]; 370c2afad6cSKamil Konieczny }; 371c2afad6cSKamil Konieczny 372c2afad6cSKamil Konieczny /** 373c2afad6cSKamil Konieczny * struct s5p_hash_ctx - HASH transformation context 374c2afad6cSKamil Konieczny * @dd: Associated device 375c2afad6cSKamil Konieczny * @flags: Bits for algorithm HASH. 376c2afad6cSKamil Konieczny * @fallback: Software transformation for zero message or size < BUFLEN. 377c2afad6cSKamil Konieczny */ 378c2afad6cSKamil Konieczny struct s5p_hash_ctx { 379c2afad6cSKamil Konieczny struct s5p_aes_dev *dd; 380c2afad6cSKamil Konieczny unsigned long flags; 381c2afad6cSKamil Konieczny struct crypto_shash *fallback; 382c2afad6cSKamil Konieczny }; 383a49e490cSVladimir Zapolskiy 38489245107SNaveen Krishna Chatradhi static const struct samsung_aes_variant s5p_aes_data = { 38589245107SNaveen Krishna Chatradhi .aes_offset = 0x4000, 386c2afad6cSKamil Konieczny .hash_offset = 0x6000, 38789245107SNaveen Krishna Chatradhi }; 38889245107SNaveen Krishna Chatradhi 38989245107SNaveen Krishna Chatradhi static const struct samsung_aes_variant exynos_aes_data = { 39089245107SNaveen Krishna Chatradhi .aes_offset = 0x200, 391c2afad6cSKamil Konieczny .hash_offset = 0x400, 39289245107SNaveen Krishna Chatradhi }; 39389245107SNaveen Krishna Chatradhi 3946b9f16e6SNaveen Krishna Chatradhi static const struct of_device_id s5p_sss_dt_match[] = { 39589245107SNaveen Krishna Chatradhi { 39689245107SNaveen Krishna Chatradhi .compatible = "samsung,s5pv210-secss", 39789245107SNaveen Krishna Chatradhi .data = &s5p_aes_data, 39889245107SNaveen Krishna Chatradhi }, 39989245107SNaveen Krishna Chatradhi { 40089245107SNaveen Krishna Chatradhi .compatible = "samsung,exynos4210-secss", 40189245107SNaveen Krishna Chatradhi .data = &exynos_aes_data, 40289245107SNaveen Krishna Chatradhi }, 4036b9f16e6SNaveen Krishna Chatradhi { }, 4046b9f16e6SNaveen Krishna Chatradhi }; 4056b9f16e6SNaveen Krishna Chatradhi MODULE_DEVICE_TABLE(of, s5p_sss_dt_match); 4066b9f16e6SNaveen Krishna Chatradhi 4076584eacbSKrzysztof Kozlowski static inline const struct samsung_aes_variant *find_s5p_sss_version 4086584eacbSKrzysztof Kozlowski (const struct platform_device *pdev) 40989245107SNaveen Krishna Chatradhi { 41089245107SNaveen Krishna Chatradhi if (IS_ENABLED(CONFIG_OF) && (pdev->dev.of_node)) { 41189245107SNaveen Krishna Chatradhi const struct of_device_id *match; 412313becd1SKrzysztof Koz?owski 41389245107SNaveen Krishna Chatradhi match = of_match_node(s5p_sss_dt_match, 41489245107SNaveen Krishna Chatradhi pdev->dev.of_node); 4156584eacbSKrzysztof Kozlowski return (const struct samsung_aes_variant *)match->data; 41689245107SNaveen Krishna Chatradhi } 4176584eacbSKrzysztof Kozlowski return (const struct samsung_aes_variant *) 41889245107SNaveen Krishna Chatradhi platform_get_device_id(pdev)->driver_data; 41989245107SNaveen Krishna Chatradhi } 42089245107SNaveen Krishna Chatradhi 421c2afad6cSKamil Konieczny static struct s5p_aes_dev *s5p_dev; 422c2afad6cSKamil Konieczny 4236584eacbSKrzysztof Kozlowski static void s5p_set_dma_indata(struct s5p_aes_dev *dev, 4246584eacbSKrzysztof Kozlowski const struct scatterlist *sg) 425a49e490cSVladimir Zapolskiy { 426a49e490cSVladimir Zapolskiy SSS_WRITE(dev, FCBRDMAS, sg_dma_address(sg)); 427a49e490cSVladimir Zapolskiy SSS_WRITE(dev, FCBRDMAL, sg_dma_len(sg)); 428a49e490cSVladimir Zapolskiy } 429a49e490cSVladimir Zapolskiy 4306584eacbSKrzysztof Kozlowski static void s5p_set_dma_outdata(struct s5p_aes_dev *dev, 4316584eacbSKrzysztof Kozlowski const struct scatterlist *sg) 432a49e490cSVladimir Zapolskiy { 433a49e490cSVladimir Zapolskiy SSS_WRITE(dev, FCBTDMAS, sg_dma_address(sg)); 434a49e490cSVladimir Zapolskiy SSS_WRITE(dev, FCBTDMAL, sg_dma_len(sg)); 435a49e490cSVladimir Zapolskiy } 436a49e490cSVladimir Zapolskiy 4379e4a1100SKrzysztof Kozlowski static void s5p_free_sg_cpy(struct s5p_aes_dev *dev, struct scatterlist **sg) 4389e4a1100SKrzysztof Kozlowski { 4399e4a1100SKrzysztof Kozlowski int len; 4409e4a1100SKrzysztof Kozlowski 4419e4a1100SKrzysztof Kozlowski if (!*sg) 4429e4a1100SKrzysztof Kozlowski return; 4439e4a1100SKrzysztof Kozlowski 4449e4a1100SKrzysztof Kozlowski len = ALIGN(dev->req->nbytes, AES_BLOCK_SIZE); 4459e4a1100SKrzysztof Kozlowski free_pages((unsigned long)sg_virt(*sg), get_order(len)); 4469e4a1100SKrzysztof Kozlowski 4479e4a1100SKrzysztof Kozlowski kfree(*sg); 4489e4a1100SKrzysztof Kozlowski *sg = NULL; 4499e4a1100SKrzysztof Kozlowski } 4509e4a1100SKrzysztof Kozlowski 4519e4a1100SKrzysztof Kozlowski static void s5p_sg_copy_buf(void *buf, struct scatterlist *sg, 4529e4a1100SKrzysztof Kozlowski unsigned int nbytes, int out) 4539e4a1100SKrzysztof Kozlowski { 4549e4a1100SKrzysztof Kozlowski struct scatter_walk walk; 4559e4a1100SKrzysztof Kozlowski 4569e4a1100SKrzysztof Kozlowski if (!nbytes) 4579e4a1100SKrzysztof Kozlowski return; 4589e4a1100SKrzysztof Kozlowski 4599e4a1100SKrzysztof Kozlowski scatterwalk_start(&walk, sg); 4609e4a1100SKrzysztof Kozlowski scatterwalk_copychunks(buf, &walk, nbytes, out); 4619e4a1100SKrzysztof Kozlowski scatterwalk_done(&walk, out, 0); 4629e4a1100SKrzysztof Kozlowski } 4639e4a1100SKrzysztof Kozlowski 46428b62b14SKrzysztof Kozlowski static void s5p_sg_done(struct s5p_aes_dev *dev) 465a49e490cSVladimir Zapolskiy { 4669e4a1100SKrzysztof Kozlowski if (dev->sg_dst_cpy) { 4679e4a1100SKrzysztof Kozlowski dev_dbg(dev->dev, 4689e4a1100SKrzysztof Kozlowski "Copying %d bytes of output data back to original place\n", 4699e4a1100SKrzysztof Kozlowski dev->req->nbytes); 4709e4a1100SKrzysztof Kozlowski s5p_sg_copy_buf(sg_virt(dev->sg_dst_cpy), dev->req->dst, 4719e4a1100SKrzysztof Kozlowski dev->req->nbytes, 1); 4729e4a1100SKrzysztof Kozlowski } 4739e4a1100SKrzysztof Kozlowski s5p_free_sg_cpy(dev, &dev->sg_src_cpy); 4749e4a1100SKrzysztof Kozlowski s5p_free_sg_cpy(dev, &dev->sg_dst_cpy); 47528b62b14SKrzysztof Kozlowski } 4769e4a1100SKrzysztof Kozlowski 47728b62b14SKrzysztof Kozlowski /* Calls the completion. Cannot be called with dev->lock hold. */ 47828b62b14SKrzysztof Kozlowski static void s5p_aes_complete(struct s5p_aes_dev *dev, int err) 47928b62b14SKrzysztof Kozlowski { 480a49e490cSVladimir Zapolskiy dev->req->base.complete(&dev->req->base, err); 481a49e490cSVladimir Zapolskiy } 482a49e490cSVladimir Zapolskiy 483a49e490cSVladimir Zapolskiy static void s5p_unset_outdata(struct s5p_aes_dev *dev) 484a49e490cSVladimir Zapolskiy { 485a49e490cSVladimir Zapolskiy dma_unmap_sg(dev->dev, dev->sg_dst, 1, DMA_FROM_DEVICE); 486a49e490cSVladimir Zapolskiy } 487a49e490cSVladimir Zapolskiy 488a49e490cSVladimir Zapolskiy static void s5p_unset_indata(struct s5p_aes_dev *dev) 489a49e490cSVladimir Zapolskiy { 490a49e490cSVladimir Zapolskiy dma_unmap_sg(dev->dev, dev->sg_src, 1, DMA_TO_DEVICE); 491a49e490cSVladimir Zapolskiy } 492a49e490cSVladimir Zapolskiy 4939e4a1100SKrzysztof Kozlowski static int s5p_make_sg_cpy(struct s5p_aes_dev *dev, struct scatterlist *src, 4949e4a1100SKrzysztof Kozlowski struct scatterlist **dst) 4959e4a1100SKrzysztof Kozlowski { 4969e4a1100SKrzysztof Kozlowski void *pages; 4979e4a1100SKrzysztof Kozlowski int len; 4989e4a1100SKrzysztof Kozlowski 4999e4a1100SKrzysztof Kozlowski *dst = kmalloc(sizeof(**dst), GFP_ATOMIC); 5009e4a1100SKrzysztof Kozlowski if (!*dst) 5019e4a1100SKrzysztof Kozlowski return -ENOMEM; 5029e4a1100SKrzysztof Kozlowski 5039e4a1100SKrzysztof Kozlowski len = ALIGN(dev->req->nbytes, AES_BLOCK_SIZE); 5049e4a1100SKrzysztof Kozlowski pages = (void *)__get_free_pages(GFP_ATOMIC, get_order(len)); 5059e4a1100SKrzysztof Kozlowski if (!pages) { 5069e4a1100SKrzysztof Kozlowski kfree(*dst); 5079e4a1100SKrzysztof Kozlowski *dst = NULL; 5089e4a1100SKrzysztof Kozlowski return -ENOMEM; 5099e4a1100SKrzysztof Kozlowski } 5109e4a1100SKrzysztof Kozlowski 5119e4a1100SKrzysztof Kozlowski s5p_sg_copy_buf(pages, src, dev->req->nbytes, 0); 5129e4a1100SKrzysztof Kozlowski 5139e4a1100SKrzysztof Kozlowski sg_init_table(*dst, 1); 5149e4a1100SKrzysztof Kozlowski sg_set_buf(*dst, pages, len); 5159e4a1100SKrzysztof Kozlowski 5169e4a1100SKrzysztof Kozlowski return 0; 5179e4a1100SKrzysztof Kozlowski } 5189e4a1100SKrzysztof Kozlowski 519a49e490cSVladimir Zapolskiy static int s5p_set_outdata(struct s5p_aes_dev *dev, struct scatterlist *sg) 520a49e490cSVladimir Zapolskiy { 521a49e490cSVladimir Zapolskiy int err; 522a49e490cSVladimir Zapolskiy 523d1497977SMarek Szyprowski if (!sg->length) { 524a49e490cSVladimir Zapolskiy err = -EINVAL; 525a49e490cSVladimir Zapolskiy goto exit; 526a49e490cSVladimir Zapolskiy } 527a49e490cSVladimir Zapolskiy 528a49e490cSVladimir Zapolskiy err = dma_map_sg(dev->dev, sg, 1, DMA_FROM_DEVICE); 529a49e490cSVladimir Zapolskiy if (!err) { 530a49e490cSVladimir Zapolskiy err = -ENOMEM; 531a49e490cSVladimir Zapolskiy goto exit; 532a49e490cSVladimir Zapolskiy } 533a49e490cSVladimir Zapolskiy 534a49e490cSVladimir Zapolskiy dev->sg_dst = sg; 535a49e490cSVladimir Zapolskiy err = 0; 536a49e490cSVladimir Zapolskiy 537a49e490cSVladimir Zapolskiy exit: 538a49e490cSVladimir Zapolskiy return err; 539a49e490cSVladimir Zapolskiy } 540a49e490cSVladimir Zapolskiy 541a49e490cSVladimir Zapolskiy static int s5p_set_indata(struct s5p_aes_dev *dev, struct scatterlist *sg) 542a49e490cSVladimir Zapolskiy { 543a49e490cSVladimir Zapolskiy int err; 544a49e490cSVladimir Zapolskiy 545d1497977SMarek Szyprowski if (!sg->length) { 546a49e490cSVladimir Zapolskiy err = -EINVAL; 547a49e490cSVladimir Zapolskiy goto exit; 548a49e490cSVladimir Zapolskiy } 549a49e490cSVladimir Zapolskiy 550a49e490cSVladimir Zapolskiy err = dma_map_sg(dev->dev, sg, 1, DMA_TO_DEVICE); 551a49e490cSVladimir Zapolskiy if (!err) { 552a49e490cSVladimir Zapolskiy err = -ENOMEM; 553a49e490cSVladimir Zapolskiy goto exit; 554a49e490cSVladimir Zapolskiy } 555a49e490cSVladimir Zapolskiy 556a49e490cSVladimir Zapolskiy dev->sg_src = sg; 557a49e490cSVladimir Zapolskiy err = 0; 558a49e490cSVladimir Zapolskiy 559a49e490cSVladimir Zapolskiy exit: 560a49e490cSVladimir Zapolskiy return err; 561a49e490cSVladimir Zapolskiy } 562a49e490cSVladimir Zapolskiy 56379152e8dSKrzysztof Kozlowski /* 56428b62b14SKrzysztof Kozlowski * Returns -ERRNO on error (mapping of new data failed). 56528b62b14SKrzysztof Kozlowski * On success returns: 56628b62b14SKrzysztof Kozlowski * - 0 if there is no more data, 56728b62b14SKrzysztof Kozlowski * - 1 if new transmitting (output) data is ready and its address+length 56828b62b14SKrzysztof Kozlowski * have to be written to device (by calling s5p_set_dma_outdata()). 56979152e8dSKrzysztof Kozlowski */ 57028b62b14SKrzysztof Kozlowski static int s5p_aes_tx(struct s5p_aes_dev *dev) 571a49e490cSVladimir Zapolskiy { 57228b62b14SKrzysztof Kozlowski int ret = 0; 573a49e490cSVladimir Zapolskiy 574a49e490cSVladimir Zapolskiy s5p_unset_outdata(dev); 575a49e490cSVladimir Zapolskiy 576a49e490cSVladimir Zapolskiy if (!sg_is_last(dev->sg_dst)) { 57728b62b14SKrzysztof Kozlowski ret = s5p_set_outdata(dev, sg_next(dev->sg_dst)); 57828b62b14SKrzysztof Kozlowski if (!ret) 57928b62b14SKrzysztof Kozlowski ret = 1; 580dc5e3f19SNaveen Krishna Chatradhi } 58179152e8dSKrzysztof Kozlowski 58279152e8dSKrzysztof Kozlowski return ret; 583a49e490cSVladimir Zapolskiy } 584a49e490cSVladimir Zapolskiy 58579152e8dSKrzysztof Kozlowski /* 58628b62b14SKrzysztof Kozlowski * Returns -ERRNO on error (mapping of new data failed). 58728b62b14SKrzysztof Kozlowski * On success returns: 58828b62b14SKrzysztof Kozlowski * - 0 if there is no more data, 58928b62b14SKrzysztof Kozlowski * - 1 if new receiving (input) data is ready and its address+length 59028b62b14SKrzysztof Kozlowski * have to be written to device (by calling s5p_set_dma_indata()). 59179152e8dSKrzysztof Kozlowski */ 59228b62b14SKrzysztof Kozlowski static int s5p_aes_rx(struct s5p_aes_dev *dev/*, bool *set_dma*/) 593a49e490cSVladimir Zapolskiy { 59428b62b14SKrzysztof Kozlowski int ret = 0; 595a49e490cSVladimir Zapolskiy 596a49e490cSVladimir Zapolskiy s5p_unset_indata(dev); 597a49e490cSVladimir Zapolskiy 598a49e490cSVladimir Zapolskiy if (!sg_is_last(dev->sg_src)) { 59928b62b14SKrzysztof Kozlowski ret = s5p_set_indata(dev, sg_next(dev->sg_src)); 60028b62b14SKrzysztof Kozlowski if (!ret) 60128b62b14SKrzysztof Kozlowski ret = 1; 602a49e490cSVladimir Zapolskiy } 603a49e490cSVladimir Zapolskiy 60479152e8dSKrzysztof Kozlowski return ret; 605a49e490cSVladimir Zapolskiy } 606a49e490cSVladimir Zapolskiy 607c2afad6cSKamil Konieczny static inline u32 s5p_hash_read(struct s5p_aes_dev *dd, u32 offset) 608c2afad6cSKamil Konieczny { 609c2afad6cSKamil Konieczny return __raw_readl(dd->io_hash_base + offset); 610c2afad6cSKamil Konieczny } 611c2afad6cSKamil Konieczny 612c2afad6cSKamil Konieczny static inline void s5p_hash_write(struct s5p_aes_dev *dd, 613c2afad6cSKamil Konieczny u32 offset, u32 value) 614c2afad6cSKamil Konieczny { 615c2afad6cSKamil Konieczny __raw_writel(value, dd->io_hash_base + offset); 616c2afad6cSKamil Konieczny } 617c2afad6cSKamil Konieczny 618c2afad6cSKamil Konieczny /** 619c2afad6cSKamil Konieczny * s5p_set_dma_hashdata() - start DMA with sg 620c2afad6cSKamil Konieczny * @dev: device 621c2afad6cSKamil Konieczny * @sg: scatterlist ready to DMA transmit 622c2afad6cSKamil Konieczny */ 623c2afad6cSKamil Konieczny static void s5p_set_dma_hashdata(struct s5p_aes_dev *dev, 6246584eacbSKrzysztof Kozlowski const struct scatterlist *sg) 625c2afad6cSKamil Konieczny { 626c2afad6cSKamil Konieczny dev->hash_sg_cnt--; 627c2afad6cSKamil Konieczny SSS_WRITE(dev, FCHRDMAS, sg_dma_address(sg)); 628c2afad6cSKamil Konieczny SSS_WRITE(dev, FCHRDMAL, sg_dma_len(sg)); /* DMA starts */ 629c2afad6cSKamil Konieczny } 630c2afad6cSKamil Konieczny 631c2afad6cSKamil Konieczny /** 632c2afad6cSKamil Konieczny * s5p_hash_rx() - get next hash_sg_iter 633c2afad6cSKamil Konieczny * @dev: device 634c2afad6cSKamil Konieczny * 635c2afad6cSKamil Konieczny * Return: 636c2afad6cSKamil Konieczny * 2 if there is no more data and it is UPDATE op 637c2afad6cSKamil Konieczny * 1 if new receiving (input) data is ready and can be written to device 638c2afad6cSKamil Konieczny * 0 if there is no more data and it is FINAL op 639c2afad6cSKamil Konieczny */ 640c2afad6cSKamil Konieczny static int s5p_hash_rx(struct s5p_aes_dev *dev) 641c2afad6cSKamil Konieczny { 642c2afad6cSKamil Konieczny if (dev->hash_sg_cnt > 0) { 643c2afad6cSKamil Konieczny dev->hash_sg_iter = sg_next(dev->hash_sg_iter); 644c2afad6cSKamil Konieczny return 1; 645c2afad6cSKamil Konieczny } 646c2afad6cSKamil Konieczny 647c2afad6cSKamil Konieczny set_bit(HASH_FLAGS_DMA_READY, &dev->hash_flags); 648c2afad6cSKamil Konieczny if (test_bit(HASH_FLAGS_FINAL, &dev->hash_flags)) 649c2afad6cSKamil Konieczny return 0; 650c2afad6cSKamil Konieczny 651c2afad6cSKamil Konieczny return 2; 652c2afad6cSKamil Konieczny } 653c2afad6cSKamil Konieczny 654a49e490cSVladimir Zapolskiy static irqreturn_t s5p_aes_interrupt(int irq, void *dev_id) 655a49e490cSVladimir Zapolskiy { 656a49e490cSVladimir Zapolskiy struct platform_device *pdev = dev_id; 657a49e490cSVladimir Zapolskiy struct s5p_aes_dev *dev = platform_get_drvdata(pdev); 65828b62b14SKrzysztof Kozlowski int err_dma_tx = 0; 65928b62b14SKrzysztof Kozlowski int err_dma_rx = 0; 660c2afad6cSKamil Konieczny int err_dma_hx = 0; 66128b62b14SKrzysztof Kozlowski bool tx_end = false; 662c2afad6cSKamil Konieczny bool hx_end = false; 6635318c53dSKrzysztof Kozlowski unsigned long flags; 6645318c53dSKrzysztof Kozlowski uint32_t status; 665c2afad6cSKamil Konieczny u32 st_bits; 66628b62b14SKrzysztof Kozlowski int err; 667a49e490cSVladimir Zapolskiy 668a49e490cSVladimir Zapolskiy spin_lock_irqsave(&dev->lock, flags); 669a49e490cSVladimir Zapolskiy 67028b62b14SKrzysztof Kozlowski /* 67128b62b14SKrzysztof Kozlowski * Handle rx or tx interrupt. If there is still data (scatterlist did not 67228b62b14SKrzysztof Kozlowski * reach end), then map next scatterlist entry. 67328b62b14SKrzysztof Kozlowski * In case of such mapping error, s5p_aes_complete() should be called. 67428b62b14SKrzysztof Kozlowski * 67528b62b14SKrzysztof Kozlowski * If there is no more data in tx scatter list, call s5p_aes_complete() 67628b62b14SKrzysztof Kozlowski * and schedule new tasklet. 677c2afad6cSKamil Konieczny * 678c2afad6cSKamil Konieczny * Handle hx interrupt. If there is still data map next entry. 67928b62b14SKrzysztof Kozlowski */ 680a49e490cSVladimir Zapolskiy status = SSS_READ(dev, FCINTSTAT); 681a49e490cSVladimir Zapolskiy if (status & SSS_FCINTSTAT_BRDMAINT) 68228b62b14SKrzysztof Kozlowski err_dma_rx = s5p_aes_rx(dev); 68328b62b14SKrzysztof Kozlowski 68428b62b14SKrzysztof Kozlowski if (status & SSS_FCINTSTAT_BTDMAINT) { 68528b62b14SKrzysztof Kozlowski if (sg_is_last(dev->sg_dst)) 68628b62b14SKrzysztof Kozlowski tx_end = true; 68728b62b14SKrzysztof Kozlowski err_dma_tx = s5p_aes_tx(dev); 68828b62b14SKrzysztof Kozlowski } 689a49e490cSVladimir Zapolskiy 690c2afad6cSKamil Konieczny if (status & SSS_FCINTSTAT_HRDMAINT) 691c2afad6cSKamil Konieczny err_dma_hx = s5p_hash_rx(dev); 692c2afad6cSKamil Konieczny 693c2afad6cSKamil Konieczny st_bits = status & (SSS_FCINTSTAT_BRDMAINT | SSS_FCINTSTAT_BTDMAINT | 694c2afad6cSKamil Konieczny SSS_FCINTSTAT_HRDMAINT); 695c2afad6cSKamil Konieczny /* clear DMA bits */ 696c2afad6cSKamil Konieczny SSS_WRITE(dev, FCINTPEND, st_bits); 697c2afad6cSKamil Konieczny 698c2afad6cSKamil Konieczny /* clear HASH irq bits */ 699c2afad6cSKamil Konieczny if (status & (SSS_FCINTSTAT_HDONEINT | SSS_FCINTSTAT_HPARTINT)) { 700c2afad6cSKamil Konieczny /* cannot have both HPART and HDONE */ 701c2afad6cSKamil Konieczny if (status & SSS_FCINTSTAT_HPARTINT) 702c2afad6cSKamil Konieczny st_bits = SSS_HASH_STATUS_PARTIAL_DONE; 703c2afad6cSKamil Konieczny 704c2afad6cSKamil Konieczny if (status & SSS_FCINTSTAT_HDONEINT) 705c2afad6cSKamil Konieczny st_bits = SSS_HASH_STATUS_MSG_DONE; 706c2afad6cSKamil Konieczny 707c2afad6cSKamil Konieczny set_bit(HASH_FLAGS_OUTPUT_READY, &dev->hash_flags); 708c2afad6cSKamil Konieczny s5p_hash_write(dev, SSS_REG_HASH_STATUS, st_bits); 709c2afad6cSKamil Konieczny hx_end = true; 710c2afad6cSKamil Konieczny /* when DONE or PART, do not handle HASH DMA */ 711c2afad6cSKamil Konieczny err_dma_hx = 0; 712c2afad6cSKamil Konieczny } 713a49e490cSVladimir Zapolskiy 71428b62b14SKrzysztof Kozlowski if (err_dma_rx < 0) { 71528b62b14SKrzysztof Kozlowski err = err_dma_rx; 71628b62b14SKrzysztof Kozlowski goto error; 71728b62b14SKrzysztof Kozlowski } 71828b62b14SKrzysztof Kozlowski if (err_dma_tx < 0) { 71928b62b14SKrzysztof Kozlowski err = err_dma_tx; 72028b62b14SKrzysztof Kozlowski goto error; 72128b62b14SKrzysztof Kozlowski } 72228b62b14SKrzysztof Kozlowski 72328b62b14SKrzysztof Kozlowski if (tx_end) { 72428b62b14SKrzysztof Kozlowski s5p_sg_done(dev); 725c2afad6cSKamil Konieczny if (err_dma_hx == 1) 726c2afad6cSKamil Konieczny s5p_set_dma_hashdata(dev, dev->hash_sg_iter); 72728b62b14SKrzysztof Kozlowski 72828b62b14SKrzysztof Kozlowski spin_unlock_irqrestore(&dev->lock, flags); 72928b62b14SKrzysztof Kozlowski 73028b62b14SKrzysztof Kozlowski s5p_aes_complete(dev, 0); 73142d5c176SKrzysztof Kozlowski /* Device is still busy */ 73228b62b14SKrzysztof Kozlowski tasklet_schedule(&dev->tasklet); 73328b62b14SKrzysztof Kozlowski } else { 73479152e8dSKrzysztof Kozlowski /* 73528b62b14SKrzysztof Kozlowski * Writing length of DMA block (either receiving or 73628b62b14SKrzysztof Kozlowski * transmitting) will start the operation immediately, so this 73728b62b14SKrzysztof Kozlowski * should be done at the end (even after clearing pending 73828b62b14SKrzysztof Kozlowski * interrupts to not miss the interrupt). 73979152e8dSKrzysztof Kozlowski */ 74028b62b14SKrzysztof Kozlowski if (err_dma_tx == 1) 74179152e8dSKrzysztof Kozlowski s5p_set_dma_outdata(dev, dev->sg_dst); 74228b62b14SKrzysztof Kozlowski if (err_dma_rx == 1) 74379152e8dSKrzysztof Kozlowski s5p_set_dma_indata(dev, dev->sg_src); 744c2afad6cSKamil Konieczny if (err_dma_hx == 1) 745c2afad6cSKamil Konieczny s5p_set_dma_hashdata(dev, dev->hash_sg_iter); 74679152e8dSKrzysztof Kozlowski 747a49e490cSVladimir Zapolskiy spin_unlock_irqrestore(&dev->lock, flags); 74828b62b14SKrzysztof Kozlowski } 74928b62b14SKrzysztof Kozlowski 750c2afad6cSKamil Konieczny goto hash_irq_end; 75128b62b14SKrzysztof Kozlowski 75228b62b14SKrzysztof Kozlowski error: 75328b62b14SKrzysztof Kozlowski s5p_sg_done(dev); 75442d5c176SKrzysztof Kozlowski dev->busy = false; 755c2afad6cSKamil Konieczny if (err_dma_hx == 1) 756c2afad6cSKamil Konieczny s5p_set_dma_hashdata(dev, dev->hash_sg_iter); 757c2afad6cSKamil Konieczny 75828b62b14SKrzysztof Kozlowski spin_unlock_irqrestore(&dev->lock, flags); 75928b62b14SKrzysztof Kozlowski s5p_aes_complete(dev, err); 760a49e490cSVladimir Zapolskiy 761c2afad6cSKamil Konieczny hash_irq_end: 762c2afad6cSKamil Konieczny /* 763c2afad6cSKamil Konieczny * Note about else if: 764c2afad6cSKamil Konieczny * when hash_sg_iter reaches end and its UPDATE op, 765c2afad6cSKamil Konieczny * issue SSS_HASH_PAUSE and wait for HPART irq 766c2afad6cSKamil Konieczny */ 767c2afad6cSKamil Konieczny if (hx_end) 768c2afad6cSKamil Konieczny tasklet_schedule(&dev->hash_tasklet); 769c2afad6cSKamil Konieczny else if (err_dma_hx == 2) 770c2afad6cSKamil Konieczny s5p_hash_write(dev, SSS_REG_HASH_CTRL_PAUSE, 771c2afad6cSKamil Konieczny SSS_HASH_PAUSE); 772c2afad6cSKamil Konieczny 773a49e490cSVladimir Zapolskiy return IRQ_HANDLED; 774a49e490cSVladimir Zapolskiy } 775a49e490cSVladimir Zapolskiy 776c2afad6cSKamil Konieczny /** 777c2afad6cSKamil Konieczny * s5p_hash_read_msg() - read message or IV from HW 778c2afad6cSKamil Konieczny * @req: AHASH request 779c2afad6cSKamil Konieczny */ 780c2afad6cSKamil Konieczny static void s5p_hash_read_msg(struct ahash_request *req) 781c2afad6cSKamil Konieczny { 782c2afad6cSKamil Konieczny struct s5p_hash_reqctx *ctx = ahash_request_ctx(req); 783c2afad6cSKamil Konieczny struct s5p_aes_dev *dd = ctx->dd; 784c2afad6cSKamil Konieczny u32 *hash = (u32 *)ctx->digest; 785c2afad6cSKamil Konieczny unsigned int i; 786c2afad6cSKamil Konieczny 787c2afad6cSKamil Konieczny for (i = 0; i < ctx->nregs; i++) 788c2afad6cSKamil Konieczny hash[i] = s5p_hash_read(dd, SSS_REG_HASH_OUT(i)); 789c2afad6cSKamil Konieczny } 790c2afad6cSKamil Konieczny 791c2afad6cSKamil Konieczny /** 792c2afad6cSKamil Konieczny * s5p_hash_write_ctx_iv() - write IV for next partial/finup op. 793c2afad6cSKamil Konieczny * @dd: device 794c2afad6cSKamil Konieczny * @ctx: request context 795c2afad6cSKamil Konieczny */ 796c2afad6cSKamil Konieczny static void s5p_hash_write_ctx_iv(struct s5p_aes_dev *dd, 7976584eacbSKrzysztof Kozlowski const struct s5p_hash_reqctx *ctx) 798c2afad6cSKamil Konieczny { 7996584eacbSKrzysztof Kozlowski const u32 *hash = (const u32 *)ctx->digest; 800c2afad6cSKamil Konieczny unsigned int i; 801c2afad6cSKamil Konieczny 802c2afad6cSKamil Konieczny for (i = 0; i < ctx->nregs; i++) 803c2afad6cSKamil Konieczny s5p_hash_write(dd, SSS_REG_HASH_IV(i), hash[i]); 804c2afad6cSKamil Konieczny } 805c2afad6cSKamil Konieczny 806c2afad6cSKamil Konieczny /** 807c2afad6cSKamil Konieczny * s5p_hash_write_iv() - write IV for next partial/finup op. 808c2afad6cSKamil Konieczny * @req: AHASH request 809c2afad6cSKamil Konieczny */ 810c2afad6cSKamil Konieczny static void s5p_hash_write_iv(struct ahash_request *req) 811c2afad6cSKamil Konieczny { 812c2afad6cSKamil Konieczny struct s5p_hash_reqctx *ctx = ahash_request_ctx(req); 813c2afad6cSKamil Konieczny 814c2afad6cSKamil Konieczny s5p_hash_write_ctx_iv(ctx->dd, ctx); 815c2afad6cSKamil Konieczny } 816c2afad6cSKamil Konieczny 817c2afad6cSKamil Konieczny /** 818c2afad6cSKamil Konieczny * s5p_hash_copy_result() - copy digest into req->result 819c2afad6cSKamil Konieczny * @req: AHASH request 820c2afad6cSKamil Konieczny */ 821c2afad6cSKamil Konieczny static void s5p_hash_copy_result(struct ahash_request *req) 822c2afad6cSKamil Konieczny { 8236584eacbSKrzysztof Kozlowski const struct s5p_hash_reqctx *ctx = ahash_request_ctx(req); 824c2afad6cSKamil Konieczny 825c2afad6cSKamil Konieczny if (!req->result) 826c2afad6cSKamil Konieczny return; 827c2afad6cSKamil Konieczny 828c2afad6cSKamil Konieczny memcpy(req->result, ctx->digest, ctx->nregs * HASH_REG_SIZEOF); 829c2afad6cSKamil Konieczny } 830c2afad6cSKamil Konieczny 831c2afad6cSKamil Konieczny /** 832c2afad6cSKamil Konieczny * s5p_hash_dma_flush() - flush HASH DMA 833c2afad6cSKamil Konieczny * @dev: secss device 834c2afad6cSKamil Konieczny */ 835c2afad6cSKamil Konieczny static void s5p_hash_dma_flush(struct s5p_aes_dev *dev) 836c2afad6cSKamil Konieczny { 837c2afad6cSKamil Konieczny SSS_WRITE(dev, FCHRDMAC, SSS_FCHRDMAC_FLUSH); 838c2afad6cSKamil Konieczny } 839c2afad6cSKamil Konieczny 840c2afad6cSKamil Konieczny /** 841c2afad6cSKamil Konieczny * s5p_hash_dma_enable() - enable DMA mode for HASH 842c2afad6cSKamil Konieczny * @dev: secss device 843c2afad6cSKamil Konieczny * 844c2afad6cSKamil Konieczny * enable DMA mode for HASH 845c2afad6cSKamil Konieczny */ 846c2afad6cSKamil Konieczny static void s5p_hash_dma_enable(struct s5p_aes_dev *dev) 847c2afad6cSKamil Konieczny { 848c2afad6cSKamil Konieczny s5p_hash_write(dev, SSS_REG_HASH_CTRL_FIFO, SSS_HASH_FIFO_MODE_DMA); 849c2afad6cSKamil Konieczny } 850c2afad6cSKamil Konieczny 851c2afad6cSKamil Konieczny /** 852c2afad6cSKamil Konieczny * s5p_hash_irq_disable() - disable irq HASH signals 853c2afad6cSKamil Konieczny * @dev: secss device 854c2afad6cSKamil Konieczny * @flags: bitfield with irq's to be disabled 855c2afad6cSKamil Konieczny */ 856c2afad6cSKamil Konieczny static void s5p_hash_irq_disable(struct s5p_aes_dev *dev, u32 flags) 857c2afad6cSKamil Konieczny { 858c2afad6cSKamil Konieczny SSS_WRITE(dev, FCINTENCLR, flags); 859c2afad6cSKamil Konieczny } 860c2afad6cSKamil Konieczny 861c2afad6cSKamil Konieczny /** 862c2afad6cSKamil Konieczny * s5p_hash_irq_enable() - enable irq signals 863c2afad6cSKamil Konieczny * @dev: secss device 864c2afad6cSKamil Konieczny * @flags: bitfield with irq's to be enabled 865c2afad6cSKamil Konieczny */ 866c2afad6cSKamil Konieczny static void s5p_hash_irq_enable(struct s5p_aes_dev *dev, int flags) 867c2afad6cSKamil Konieczny { 868c2afad6cSKamil Konieczny SSS_WRITE(dev, FCINTENSET, flags); 869c2afad6cSKamil Konieczny } 870c2afad6cSKamil Konieczny 871c2afad6cSKamil Konieczny /** 872c2afad6cSKamil Konieczny * s5p_hash_set_flow() - set flow inside SecSS AES/DES with/without HASH 873c2afad6cSKamil Konieczny * @dev: secss device 874c2afad6cSKamil Konieczny * @hashflow: HASH stream flow with/without crypto AES/DES 875c2afad6cSKamil Konieczny */ 876c2afad6cSKamil Konieczny static void s5p_hash_set_flow(struct s5p_aes_dev *dev, u32 hashflow) 877c2afad6cSKamil Konieczny { 878c2afad6cSKamil Konieczny unsigned long flags; 879c2afad6cSKamil Konieczny u32 flow; 880c2afad6cSKamil Konieczny 881c2afad6cSKamil Konieczny spin_lock_irqsave(&dev->lock, flags); 882c2afad6cSKamil Konieczny 883c2afad6cSKamil Konieczny flow = SSS_READ(dev, FCFIFOCTRL); 884c2afad6cSKamil Konieczny flow &= ~SSS_HASHIN_MASK; 885c2afad6cSKamil Konieczny flow |= hashflow; 886c2afad6cSKamil Konieczny SSS_WRITE(dev, FCFIFOCTRL, flow); 887c2afad6cSKamil Konieczny 888c2afad6cSKamil Konieczny spin_unlock_irqrestore(&dev->lock, flags); 889c2afad6cSKamil Konieczny } 890c2afad6cSKamil Konieczny 891c2afad6cSKamil Konieczny /** 892c2afad6cSKamil Konieczny * s5p_ahash_dma_init() - enable DMA and set HASH flow inside SecSS 893c2afad6cSKamil Konieczny * @dev: secss device 894c2afad6cSKamil Konieczny * @hashflow: HASH stream flow with/without AES/DES 895c2afad6cSKamil Konieczny * 896c2afad6cSKamil Konieczny * flush HASH DMA and enable DMA, set HASH stream flow inside SecSS HW, 897c2afad6cSKamil Konieczny * enable HASH irq's HRDMA, HDONE, HPART 898c2afad6cSKamil Konieczny */ 899c2afad6cSKamil Konieczny static void s5p_ahash_dma_init(struct s5p_aes_dev *dev, u32 hashflow) 900c2afad6cSKamil Konieczny { 901c2afad6cSKamil Konieczny s5p_hash_irq_disable(dev, SSS_FCINTENCLR_HRDMAINTENCLR | 902c2afad6cSKamil Konieczny SSS_FCINTENCLR_HDONEINTENCLR | 903c2afad6cSKamil Konieczny SSS_FCINTENCLR_HPARTINTENCLR); 904c2afad6cSKamil Konieczny s5p_hash_dma_flush(dev); 905c2afad6cSKamil Konieczny 906c2afad6cSKamil Konieczny s5p_hash_dma_enable(dev); 907c2afad6cSKamil Konieczny s5p_hash_set_flow(dev, hashflow & SSS_HASHIN_MASK); 908c2afad6cSKamil Konieczny s5p_hash_irq_enable(dev, SSS_FCINTENSET_HRDMAINTENSET | 909c2afad6cSKamil Konieczny SSS_FCINTENSET_HDONEINTENSET | 910c2afad6cSKamil Konieczny SSS_FCINTENSET_HPARTINTENSET); 911c2afad6cSKamil Konieczny } 912c2afad6cSKamil Konieczny 913c2afad6cSKamil Konieczny /** 914c2afad6cSKamil Konieczny * s5p_hash_write_ctrl() - prepare HASH block in SecSS for processing 915c2afad6cSKamil Konieczny * @dd: secss device 916c2afad6cSKamil Konieczny * @length: length for request 917c2afad6cSKamil Konieczny * @final: true if final op 918c2afad6cSKamil Konieczny * 919c2afad6cSKamil Konieczny * Prepare SSS HASH block for processing bytes in DMA mode. If it is called 920c2afad6cSKamil Konieczny * after previous updates, fill up IV words. For final, calculate and set 921c2afad6cSKamil Konieczny * lengths for HASH so SecSS can finalize hash. For partial, set SSS HASH 922c2afad6cSKamil Konieczny * length as 2^63 so it will be never reached and set to zero prelow and 923c2afad6cSKamil Konieczny * prehigh. 924c2afad6cSKamil Konieczny * 925c2afad6cSKamil Konieczny * This function does not start DMA transfer. 926c2afad6cSKamil Konieczny */ 927c2afad6cSKamil Konieczny static void s5p_hash_write_ctrl(struct s5p_aes_dev *dd, size_t length, 928c2afad6cSKamil Konieczny bool final) 929c2afad6cSKamil Konieczny { 930c2afad6cSKamil Konieczny struct s5p_hash_reqctx *ctx = ahash_request_ctx(dd->hash_req); 931c2afad6cSKamil Konieczny u32 prelow, prehigh, low, high; 932c2afad6cSKamil Konieczny u32 configflags, swapflags; 933c2afad6cSKamil Konieczny u64 tmplen; 934c2afad6cSKamil Konieczny 935c2afad6cSKamil Konieczny configflags = ctx->engine | SSS_HASH_INIT_BIT; 936c2afad6cSKamil Konieczny 937c2afad6cSKamil Konieczny if (likely(ctx->digcnt)) { 938c2afad6cSKamil Konieczny s5p_hash_write_ctx_iv(dd, ctx); 939c2afad6cSKamil Konieczny configflags |= SSS_HASH_USER_IV_EN; 940c2afad6cSKamil Konieczny } 941c2afad6cSKamil Konieczny 942c2afad6cSKamil Konieczny if (final) { 943c2afad6cSKamil Konieczny /* number of bytes for last part */ 944c2afad6cSKamil Konieczny low = length; 945c2afad6cSKamil Konieczny high = 0; 946c2afad6cSKamil Konieczny /* total number of bits prev hashed */ 947c2afad6cSKamil Konieczny tmplen = ctx->digcnt * 8; 948c2afad6cSKamil Konieczny prelow = (u32)tmplen; 949c2afad6cSKamil Konieczny prehigh = (u32)(tmplen >> 32); 950c2afad6cSKamil Konieczny } else { 951c2afad6cSKamil Konieczny prelow = 0; 952c2afad6cSKamil Konieczny prehigh = 0; 953c2afad6cSKamil Konieczny low = 0; 954c2afad6cSKamil Konieczny high = BIT(31); 955c2afad6cSKamil Konieczny } 956c2afad6cSKamil Konieczny 957c2afad6cSKamil Konieczny swapflags = SSS_HASH_BYTESWAP_DI | SSS_HASH_BYTESWAP_DO | 958c2afad6cSKamil Konieczny SSS_HASH_BYTESWAP_IV | SSS_HASH_BYTESWAP_KEY; 959c2afad6cSKamil Konieczny 960c2afad6cSKamil Konieczny s5p_hash_write(dd, SSS_REG_HASH_MSG_SIZE_LOW, low); 961c2afad6cSKamil Konieczny s5p_hash_write(dd, SSS_REG_HASH_MSG_SIZE_HIGH, high); 962c2afad6cSKamil Konieczny s5p_hash_write(dd, SSS_REG_HASH_PRE_MSG_SIZE_LOW, prelow); 963c2afad6cSKamil Konieczny s5p_hash_write(dd, SSS_REG_HASH_PRE_MSG_SIZE_HIGH, prehigh); 964c2afad6cSKamil Konieczny 965c2afad6cSKamil Konieczny s5p_hash_write(dd, SSS_REG_HASH_CTRL_SWAP, swapflags); 966c2afad6cSKamil Konieczny s5p_hash_write(dd, SSS_REG_HASH_CTRL, configflags); 967c2afad6cSKamil Konieczny } 968c2afad6cSKamil Konieczny 969c2afad6cSKamil Konieczny /** 970c2afad6cSKamil Konieczny * s5p_hash_xmit_dma() - start DMA hash processing 971c2afad6cSKamil Konieczny * @dd: secss device 972c2afad6cSKamil Konieczny * @length: length for request 973c2afad6cSKamil Konieczny * @final: true if final op 974c2afad6cSKamil Konieczny * 975c2afad6cSKamil Konieczny * Update digcnt here, as it is needed for finup/final op. 976c2afad6cSKamil Konieczny */ 977c2afad6cSKamil Konieczny static int s5p_hash_xmit_dma(struct s5p_aes_dev *dd, size_t length, 978c2afad6cSKamil Konieczny bool final) 979c2afad6cSKamil Konieczny { 980c2afad6cSKamil Konieczny struct s5p_hash_reqctx *ctx = ahash_request_ctx(dd->hash_req); 981c2afad6cSKamil Konieczny unsigned int cnt; 982c2afad6cSKamil Konieczny 983c2afad6cSKamil Konieczny cnt = dma_map_sg(dd->dev, ctx->sg, ctx->sg_len, DMA_TO_DEVICE); 984c2afad6cSKamil Konieczny if (!cnt) { 985c2afad6cSKamil Konieczny dev_err(dd->dev, "dma_map_sg error\n"); 986c2afad6cSKamil Konieczny ctx->error = true; 987c2afad6cSKamil Konieczny return -EINVAL; 988c2afad6cSKamil Konieczny } 989c2afad6cSKamil Konieczny 990c2afad6cSKamil Konieczny set_bit(HASH_FLAGS_DMA_ACTIVE, &dd->hash_flags); 991c2afad6cSKamil Konieczny dd->hash_sg_iter = ctx->sg; 992c2afad6cSKamil Konieczny dd->hash_sg_cnt = cnt; 993c2afad6cSKamil Konieczny s5p_hash_write_ctrl(dd, length, final); 994c2afad6cSKamil Konieczny ctx->digcnt += length; 995c2afad6cSKamil Konieczny ctx->total -= length; 996c2afad6cSKamil Konieczny 997c2afad6cSKamil Konieczny /* catch last interrupt */ 998c2afad6cSKamil Konieczny if (final) 999c2afad6cSKamil Konieczny set_bit(HASH_FLAGS_FINAL, &dd->hash_flags); 1000c2afad6cSKamil Konieczny 1001c2afad6cSKamil Konieczny s5p_set_dma_hashdata(dd, dd->hash_sg_iter); /* DMA starts */ 1002c2afad6cSKamil Konieczny 1003c2afad6cSKamil Konieczny return -EINPROGRESS; 1004c2afad6cSKamil Konieczny } 1005c2afad6cSKamil Konieczny 1006c2afad6cSKamil Konieczny /** 1007c2afad6cSKamil Konieczny * s5p_hash_copy_sgs() - copy request's bytes into new buffer 1008c2afad6cSKamil Konieczny * @ctx: request context 1009c2afad6cSKamil Konieczny * @sg: source scatterlist request 1010c2afad6cSKamil Konieczny * @new_len: number of bytes to process from sg 1011c2afad6cSKamil Konieczny * 1012c2afad6cSKamil Konieczny * Allocate new buffer, copy data for HASH into it. If there was xmit_buf 1013c2afad6cSKamil Konieczny * filled, copy it first, then copy data from sg into it. Prepare one sgl[0] 1014c2afad6cSKamil Konieczny * with allocated buffer. 1015c2afad6cSKamil Konieczny * 1016c2afad6cSKamil Konieczny * Set bit in dd->hash_flag so we can free it after irq ends processing. 1017c2afad6cSKamil Konieczny */ 1018c2afad6cSKamil Konieczny static int s5p_hash_copy_sgs(struct s5p_hash_reqctx *ctx, 1019c2afad6cSKamil Konieczny struct scatterlist *sg, unsigned int new_len) 1020c2afad6cSKamil Konieczny { 1021c2afad6cSKamil Konieczny unsigned int pages, len; 1022c2afad6cSKamil Konieczny void *buf; 1023c2afad6cSKamil Konieczny 1024c2afad6cSKamil Konieczny len = new_len + ctx->bufcnt; 1025c2afad6cSKamil Konieczny pages = get_order(len); 1026c2afad6cSKamil Konieczny 1027c2afad6cSKamil Konieczny buf = (void *)__get_free_pages(GFP_ATOMIC, pages); 1028c2afad6cSKamil Konieczny if (!buf) { 1029c2afad6cSKamil Konieczny dev_err(ctx->dd->dev, "alloc pages for unaligned case.\n"); 1030c2afad6cSKamil Konieczny ctx->error = true; 1031c2afad6cSKamil Konieczny return -ENOMEM; 1032c2afad6cSKamil Konieczny } 1033c2afad6cSKamil Konieczny 1034c2afad6cSKamil Konieczny if (ctx->bufcnt) 1035c2afad6cSKamil Konieczny memcpy(buf, ctx->dd->xmit_buf, ctx->bufcnt); 1036c2afad6cSKamil Konieczny 1037c2afad6cSKamil Konieczny scatterwalk_map_and_copy(buf + ctx->bufcnt, sg, ctx->skip, 1038c2afad6cSKamil Konieczny new_len, 0); 1039c2afad6cSKamil Konieczny sg_init_table(ctx->sgl, 1); 1040c2afad6cSKamil Konieczny sg_set_buf(ctx->sgl, buf, len); 1041c2afad6cSKamil Konieczny ctx->sg = ctx->sgl; 1042c2afad6cSKamil Konieczny ctx->sg_len = 1; 1043c2afad6cSKamil Konieczny ctx->bufcnt = 0; 1044c2afad6cSKamil Konieczny ctx->skip = 0; 1045c2afad6cSKamil Konieczny set_bit(HASH_FLAGS_SGS_COPIED, &ctx->dd->hash_flags); 1046c2afad6cSKamil Konieczny 1047c2afad6cSKamil Konieczny return 0; 1048c2afad6cSKamil Konieczny } 1049c2afad6cSKamil Konieczny 1050c2afad6cSKamil Konieczny /** 1051c2afad6cSKamil Konieczny * s5p_hash_copy_sg_lists() - copy sg list and make fixes in copy 1052c2afad6cSKamil Konieczny * @ctx: request context 1053c2afad6cSKamil Konieczny * @sg: source scatterlist request 1054c2afad6cSKamil Konieczny * @new_len: number of bytes to process from sg 1055c2afad6cSKamil Konieczny * 1056c2afad6cSKamil Konieczny * Allocate new scatterlist table, copy data for HASH into it. If there was 1057c2afad6cSKamil Konieczny * xmit_buf filled, prepare it first, then copy page, length and offset from 1058c2afad6cSKamil Konieczny * source sg into it, adjusting begin and/or end for skip offset and 1059c2afad6cSKamil Konieczny * hash_later value. 1060c2afad6cSKamil Konieczny * 1061c2afad6cSKamil Konieczny * Resulting sg table will be assigned to ctx->sg. Set flag so we can free 1062c2afad6cSKamil Konieczny * it after irq ends processing. 1063c2afad6cSKamil Konieczny */ 1064c2afad6cSKamil Konieczny static int s5p_hash_copy_sg_lists(struct s5p_hash_reqctx *ctx, 1065c2afad6cSKamil Konieczny struct scatterlist *sg, unsigned int new_len) 1066c2afad6cSKamil Konieczny { 1067c2afad6cSKamil Konieczny unsigned int skip = ctx->skip, n = sg_nents(sg); 1068c2afad6cSKamil Konieczny struct scatterlist *tmp; 1069c2afad6cSKamil Konieczny unsigned int len; 1070c2afad6cSKamil Konieczny 1071c2afad6cSKamil Konieczny if (ctx->bufcnt) 1072c2afad6cSKamil Konieczny n++; 1073c2afad6cSKamil Konieczny 1074c2afad6cSKamil Konieczny ctx->sg = kmalloc_array(n, sizeof(*sg), GFP_KERNEL); 1075c2afad6cSKamil Konieczny if (!ctx->sg) { 1076c2afad6cSKamil Konieczny ctx->error = true; 1077c2afad6cSKamil Konieczny return -ENOMEM; 1078c2afad6cSKamil Konieczny } 1079c2afad6cSKamil Konieczny 1080c2afad6cSKamil Konieczny sg_init_table(ctx->sg, n); 1081c2afad6cSKamil Konieczny 1082c2afad6cSKamil Konieczny tmp = ctx->sg; 1083c2afad6cSKamil Konieczny 1084c2afad6cSKamil Konieczny ctx->sg_len = 0; 1085c2afad6cSKamil Konieczny 1086c2afad6cSKamil Konieczny if (ctx->bufcnt) { 1087c2afad6cSKamil Konieczny sg_set_buf(tmp, ctx->dd->xmit_buf, ctx->bufcnt); 1088c2afad6cSKamil Konieczny tmp = sg_next(tmp); 1089c2afad6cSKamil Konieczny ctx->sg_len++; 1090c2afad6cSKamil Konieczny } 1091c2afad6cSKamil Konieczny 1092c2afad6cSKamil Konieczny while (sg && skip >= sg->length) { 1093c2afad6cSKamil Konieczny skip -= sg->length; 1094c2afad6cSKamil Konieczny sg = sg_next(sg); 1095c2afad6cSKamil Konieczny } 1096c2afad6cSKamil Konieczny 1097c2afad6cSKamil Konieczny while (sg && new_len) { 1098c2afad6cSKamil Konieczny len = sg->length - skip; 1099c2afad6cSKamil Konieczny if (new_len < len) 1100c2afad6cSKamil Konieczny len = new_len; 1101c2afad6cSKamil Konieczny 1102c2afad6cSKamil Konieczny new_len -= len; 1103c2afad6cSKamil Konieczny sg_set_page(tmp, sg_page(sg), len, sg->offset + skip); 1104c2afad6cSKamil Konieczny skip = 0; 1105c2afad6cSKamil Konieczny if (new_len <= 0) 1106c2afad6cSKamil Konieczny sg_mark_end(tmp); 1107c2afad6cSKamil Konieczny 1108c2afad6cSKamil Konieczny tmp = sg_next(tmp); 1109c2afad6cSKamil Konieczny ctx->sg_len++; 1110c2afad6cSKamil Konieczny sg = sg_next(sg); 1111c2afad6cSKamil Konieczny } 1112c2afad6cSKamil Konieczny 1113c2afad6cSKamil Konieczny set_bit(HASH_FLAGS_SGS_ALLOCED, &ctx->dd->hash_flags); 1114c2afad6cSKamil Konieczny 1115c2afad6cSKamil Konieczny return 0; 1116c2afad6cSKamil Konieczny } 1117c2afad6cSKamil Konieczny 1118c2afad6cSKamil Konieczny /** 1119c2afad6cSKamil Konieczny * s5p_hash_prepare_sgs() - prepare sg for processing 1120c2afad6cSKamil Konieczny * @ctx: request context 1121c2afad6cSKamil Konieczny * @sg: source scatterlist request 1122c2afad6cSKamil Konieczny * @nbytes: number of bytes to process from sg 1123c2afad6cSKamil Konieczny * @final: final flag 1124c2afad6cSKamil Konieczny * 1125c2afad6cSKamil Konieczny * Check two conditions: (1) if buffers in sg have len aligned data, and (2) 1126c2afad6cSKamil Konieczny * sg table have good aligned elements (list_ok). If one of this checks fails, 1127c2afad6cSKamil Konieczny * then either (1) allocates new buffer for data with s5p_hash_copy_sgs, copy 1128c2afad6cSKamil Konieczny * data into this buffer and prepare request in sgl, or (2) allocates new sg 1129c2afad6cSKamil Konieczny * table and prepare sg elements. 1130c2afad6cSKamil Konieczny * 1131c2afad6cSKamil Konieczny * For digest or finup all conditions can be good, and we may not need any 1132c2afad6cSKamil Konieczny * fixes. 1133c2afad6cSKamil Konieczny */ 1134c2afad6cSKamil Konieczny static int s5p_hash_prepare_sgs(struct s5p_hash_reqctx *ctx, 1135c2afad6cSKamil Konieczny struct scatterlist *sg, 1136c2afad6cSKamil Konieczny unsigned int new_len, bool final) 1137c2afad6cSKamil Konieczny { 1138c2afad6cSKamil Konieczny unsigned int skip = ctx->skip, nbytes = new_len, n = 0; 1139c2afad6cSKamil Konieczny bool aligned = true, list_ok = true; 1140c2afad6cSKamil Konieczny struct scatterlist *sg_tmp = sg; 1141c2afad6cSKamil Konieczny 1142c2afad6cSKamil Konieczny if (!sg || !sg->length || !new_len) 1143c2afad6cSKamil Konieczny return 0; 1144c2afad6cSKamil Konieczny 1145c2afad6cSKamil Konieczny if (skip || !final) 1146c2afad6cSKamil Konieczny list_ok = false; 1147c2afad6cSKamil Konieczny 1148c2afad6cSKamil Konieczny while (nbytes > 0 && sg_tmp) { 1149c2afad6cSKamil Konieczny n++; 1150c2afad6cSKamil Konieczny if (skip >= sg_tmp->length) { 1151c2afad6cSKamil Konieczny skip -= sg_tmp->length; 1152c2afad6cSKamil Konieczny if (!sg_tmp->length) { 1153c2afad6cSKamil Konieczny aligned = false; 1154c2afad6cSKamil Konieczny break; 1155c2afad6cSKamil Konieczny } 1156c2afad6cSKamil Konieczny } else { 1157c2afad6cSKamil Konieczny if (!IS_ALIGNED(sg_tmp->length - skip, BUFLEN)) { 1158c2afad6cSKamil Konieczny aligned = false; 1159c2afad6cSKamil Konieczny break; 1160c2afad6cSKamil Konieczny } 1161c2afad6cSKamil Konieczny 1162c2afad6cSKamil Konieczny if (nbytes < sg_tmp->length - skip) { 1163c2afad6cSKamil Konieczny list_ok = false; 1164c2afad6cSKamil Konieczny break; 1165c2afad6cSKamil Konieczny } 1166c2afad6cSKamil Konieczny 1167c2afad6cSKamil Konieczny nbytes -= sg_tmp->length - skip; 1168c2afad6cSKamil Konieczny skip = 0; 1169c2afad6cSKamil Konieczny } 1170c2afad6cSKamil Konieczny 1171c2afad6cSKamil Konieczny sg_tmp = sg_next(sg_tmp); 1172c2afad6cSKamil Konieczny } 1173c2afad6cSKamil Konieczny 1174c2afad6cSKamil Konieczny if (!aligned) 1175c2afad6cSKamil Konieczny return s5p_hash_copy_sgs(ctx, sg, new_len); 1176c2afad6cSKamil Konieczny else if (!list_ok) 1177c2afad6cSKamil Konieczny return s5p_hash_copy_sg_lists(ctx, sg, new_len); 1178c2afad6cSKamil Konieczny 1179c2afad6cSKamil Konieczny /* 1180c2afad6cSKamil Konieczny * Have aligned data from previous operation and/or current 1181c2afad6cSKamil Konieczny * Note: will enter here only if (digest or finup) and aligned 1182c2afad6cSKamil Konieczny */ 1183c2afad6cSKamil Konieczny if (ctx->bufcnt) { 1184c2afad6cSKamil Konieczny ctx->sg_len = n; 1185c2afad6cSKamil Konieczny sg_init_table(ctx->sgl, 2); 1186c2afad6cSKamil Konieczny sg_set_buf(ctx->sgl, ctx->dd->xmit_buf, ctx->bufcnt); 1187c2afad6cSKamil Konieczny sg_chain(ctx->sgl, 2, sg); 1188c2afad6cSKamil Konieczny ctx->sg = ctx->sgl; 1189c2afad6cSKamil Konieczny ctx->sg_len++; 1190c2afad6cSKamil Konieczny } else { 1191c2afad6cSKamil Konieczny ctx->sg = sg; 1192c2afad6cSKamil Konieczny ctx->sg_len = n; 1193c2afad6cSKamil Konieczny } 1194c2afad6cSKamil Konieczny 1195c2afad6cSKamil Konieczny return 0; 1196c2afad6cSKamil Konieczny } 1197c2afad6cSKamil Konieczny 1198c2afad6cSKamil Konieczny /** 1199c2afad6cSKamil Konieczny * s5p_hash_prepare_request() - prepare request for processing 1200c2afad6cSKamil Konieczny * @req: AHASH request 1201c2afad6cSKamil Konieczny * @update: true if UPDATE op 1202c2afad6cSKamil Konieczny * 1203c2afad6cSKamil Konieczny * Note 1: we can have update flag _and_ final flag at the same time. 1204c2afad6cSKamil Konieczny * Note 2: we enter here when digcnt > BUFLEN (=HASH_BLOCK_SIZE) or 1205c2afad6cSKamil Konieczny * either req->nbytes or ctx->bufcnt + req->nbytes is > BUFLEN or 1206c2afad6cSKamil Konieczny * we have final op 1207c2afad6cSKamil Konieczny */ 1208c2afad6cSKamil Konieczny static int s5p_hash_prepare_request(struct ahash_request *req, bool update) 1209c2afad6cSKamil Konieczny { 1210c2afad6cSKamil Konieczny struct s5p_hash_reqctx *ctx = ahash_request_ctx(req); 1211c2afad6cSKamil Konieczny bool final = ctx->finup; 1212c2afad6cSKamil Konieczny int xmit_len, hash_later, nbytes; 1213c2afad6cSKamil Konieczny int ret; 1214c2afad6cSKamil Konieczny 1215c2afad6cSKamil Konieczny if (update) 1216c2afad6cSKamil Konieczny nbytes = req->nbytes; 1217c2afad6cSKamil Konieczny else 1218c2afad6cSKamil Konieczny nbytes = 0; 1219c2afad6cSKamil Konieczny 1220c2afad6cSKamil Konieczny ctx->total = nbytes + ctx->bufcnt; 1221c2afad6cSKamil Konieczny if (!ctx->total) 1222c2afad6cSKamil Konieczny return 0; 1223c2afad6cSKamil Konieczny 1224c2afad6cSKamil Konieczny if (nbytes && (!IS_ALIGNED(ctx->bufcnt, BUFLEN))) { 1225c2afad6cSKamil Konieczny /* bytes left from previous request, so fill up to BUFLEN */ 1226c2afad6cSKamil Konieczny int len = BUFLEN - ctx->bufcnt % BUFLEN; 1227c2afad6cSKamil Konieczny 1228c2afad6cSKamil Konieczny if (len > nbytes) 1229c2afad6cSKamil Konieczny len = nbytes; 1230c2afad6cSKamil Konieczny 1231c2afad6cSKamil Konieczny scatterwalk_map_and_copy(ctx->buffer + ctx->bufcnt, req->src, 1232c2afad6cSKamil Konieczny 0, len, 0); 1233c2afad6cSKamil Konieczny ctx->bufcnt += len; 1234c2afad6cSKamil Konieczny nbytes -= len; 1235c2afad6cSKamil Konieczny ctx->skip = len; 1236c2afad6cSKamil Konieczny } else { 1237c2afad6cSKamil Konieczny ctx->skip = 0; 1238c2afad6cSKamil Konieczny } 1239c2afad6cSKamil Konieczny 1240c2afad6cSKamil Konieczny if (ctx->bufcnt) 1241c2afad6cSKamil Konieczny memcpy(ctx->dd->xmit_buf, ctx->buffer, ctx->bufcnt); 1242c2afad6cSKamil Konieczny 1243c2afad6cSKamil Konieczny xmit_len = ctx->total; 1244c2afad6cSKamil Konieczny if (final) { 1245c2afad6cSKamil Konieczny hash_later = 0; 1246c2afad6cSKamil Konieczny } else { 1247c2afad6cSKamil Konieczny if (IS_ALIGNED(xmit_len, BUFLEN)) 1248c2afad6cSKamil Konieczny xmit_len -= BUFLEN; 1249c2afad6cSKamil Konieczny else 1250c2afad6cSKamil Konieczny xmit_len -= xmit_len & (BUFLEN - 1); 1251c2afad6cSKamil Konieczny 1252c2afad6cSKamil Konieczny hash_later = ctx->total - xmit_len; 1253c2afad6cSKamil Konieczny /* copy hash_later bytes from end of req->src */ 1254c2afad6cSKamil Konieczny /* previous bytes are in xmit_buf, so no overwrite */ 1255c2afad6cSKamil Konieczny scatterwalk_map_and_copy(ctx->buffer, req->src, 1256c2afad6cSKamil Konieczny req->nbytes - hash_later, 1257c2afad6cSKamil Konieczny hash_later, 0); 1258c2afad6cSKamil Konieczny } 1259c2afad6cSKamil Konieczny 1260c2afad6cSKamil Konieczny if (xmit_len > BUFLEN) { 1261c2afad6cSKamil Konieczny ret = s5p_hash_prepare_sgs(ctx, req->src, nbytes - hash_later, 1262c2afad6cSKamil Konieczny final); 1263c2afad6cSKamil Konieczny if (ret) 1264c2afad6cSKamil Konieczny return ret; 1265c2afad6cSKamil Konieczny } else { 1266c2afad6cSKamil Konieczny /* have buffered data only */ 1267c2afad6cSKamil Konieczny if (unlikely(!ctx->bufcnt)) { 1268c2afad6cSKamil Konieczny /* first update didn't fill up buffer */ 1269c2afad6cSKamil Konieczny scatterwalk_map_and_copy(ctx->dd->xmit_buf, req->src, 1270c2afad6cSKamil Konieczny 0, xmit_len, 0); 1271c2afad6cSKamil Konieczny } 1272c2afad6cSKamil Konieczny 1273c2afad6cSKamil Konieczny sg_init_table(ctx->sgl, 1); 1274c2afad6cSKamil Konieczny sg_set_buf(ctx->sgl, ctx->dd->xmit_buf, xmit_len); 1275c2afad6cSKamil Konieczny 1276c2afad6cSKamil Konieczny ctx->sg = ctx->sgl; 1277c2afad6cSKamil Konieczny ctx->sg_len = 1; 1278c2afad6cSKamil Konieczny } 1279c2afad6cSKamil Konieczny 1280c2afad6cSKamil Konieczny ctx->bufcnt = hash_later; 1281c2afad6cSKamil Konieczny if (!final) 1282c2afad6cSKamil Konieczny ctx->total = xmit_len; 1283c2afad6cSKamil Konieczny 1284c2afad6cSKamil Konieczny return 0; 1285c2afad6cSKamil Konieczny } 1286c2afad6cSKamil Konieczny 1287c2afad6cSKamil Konieczny /** 1288c2afad6cSKamil Konieczny * s5p_hash_update_dma_stop() - unmap DMA 1289c2afad6cSKamil Konieczny * @dd: secss device 1290c2afad6cSKamil Konieczny * 1291c2afad6cSKamil Konieczny * Unmap scatterlist ctx->sg. 1292c2afad6cSKamil Konieczny */ 1293c2afad6cSKamil Konieczny static void s5p_hash_update_dma_stop(struct s5p_aes_dev *dd) 1294c2afad6cSKamil Konieczny { 12956584eacbSKrzysztof Kozlowski const struct s5p_hash_reqctx *ctx = ahash_request_ctx(dd->hash_req); 1296c2afad6cSKamil Konieczny 1297c2afad6cSKamil Konieczny dma_unmap_sg(dd->dev, ctx->sg, ctx->sg_len, DMA_TO_DEVICE); 1298c2afad6cSKamil Konieczny clear_bit(HASH_FLAGS_DMA_ACTIVE, &dd->hash_flags); 1299c2afad6cSKamil Konieczny } 1300c2afad6cSKamil Konieczny 1301c2afad6cSKamil Konieczny /** 1302c2afad6cSKamil Konieczny * s5p_hash_finish() - copy calculated digest to crypto layer 1303c2afad6cSKamil Konieczny * @req: AHASH request 1304c2afad6cSKamil Konieczny */ 1305c2afad6cSKamil Konieczny static void s5p_hash_finish(struct ahash_request *req) 1306c2afad6cSKamil Konieczny { 1307c2afad6cSKamil Konieczny struct s5p_hash_reqctx *ctx = ahash_request_ctx(req); 1308c2afad6cSKamil Konieczny struct s5p_aes_dev *dd = ctx->dd; 1309c2afad6cSKamil Konieczny 1310c2afad6cSKamil Konieczny if (ctx->digcnt) 1311c2afad6cSKamil Konieczny s5p_hash_copy_result(req); 1312c2afad6cSKamil Konieczny 1313c2afad6cSKamil Konieczny dev_dbg(dd->dev, "hash_finish digcnt: %lld\n", ctx->digcnt); 1314c2afad6cSKamil Konieczny } 1315c2afad6cSKamil Konieczny 1316c2afad6cSKamil Konieczny /** 1317c2afad6cSKamil Konieczny * s5p_hash_finish_req() - finish request 1318c2afad6cSKamil Konieczny * @req: AHASH request 1319c2afad6cSKamil Konieczny * @err: error 1320c2afad6cSKamil Konieczny */ 1321c2afad6cSKamil Konieczny static void s5p_hash_finish_req(struct ahash_request *req, int err) 1322c2afad6cSKamil Konieczny { 1323c2afad6cSKamil Konieczny struct s5p_hash_reqctx *ctx = ahash_request_ctx(req); 1324c2afad6cSKamil Konieczny struct s5p_aes_dev *dd = ctx->dd; 1325c2afad6cSKamil Konieczny unsigned long flags; 1326c2afad6cSKamil Konieczny 1327c2afad6cSKamil Konieczny if (test_bit(HASH_FLAGS_SGS_COPIED, &dd->hash_flags)) 1328c2afad6cSKamil Konieczny free_pages((unsigned long)sg_virt(ctx->sg), 1329c2afad6cSKamil Konieczny get_order(ctx->sg->length)); 1330c2afad6cSKamil Konieczny 1331c2afad6cSKamil Konieczny if (test_bit(HASH_FLAGS_SGS_ALLOCED, &dd->hash_flags)) 1332c2afad6cSKamil Konieczny kfree(ctx->sg); 1333c2afad6cSKamil Konieczny 1334c2afad6cSKamil Konieczny ctx->sg = NULL; 1335c2afad6cSKamil Konieczny dd->hash_flags &= ~(BIT(HASH_FLAGS_SGS_ALLOCED) | 1336c2afad6cSKamil Konieczny BIT(HASH_FLAGS_SGS_COPIED)); 1337c2afad6cSKamil Konieczny 1338c2afad6cSKamil Konieczny if (!err && !ctx->error) { 1339c2afad6cSKamil Konieczny s5p_hash_read_msg(req); 1340c2afad6cSKamil Konieczny if (test_bit(HASH_FLAGS_FINAL, &dd->hash_flags)) 1341c2afad6cSKamil Konieczny s5p_hash_finish(req); 1342c2afad6cSKamil Konieczny } else { 1343c2afad6cSKamil Konieczny ctx->error = true; 1344c2afad6cSKamil Konieczny } 1345c2afad6cSKamil Konieczny 1346c2afad6cSKamil Konieczny spin_lock_irqsave(&dd->hash_lock, flags); 1347c2afad6cSKamil Konieczny dd->hash_flags &= ~(BIT(HASH_FLAGS_BUSY) | BIT(HASH_FLAGS_FINAL) | 1348c2afad6cSKamil Konieczny BIT(HASH_FLAGS_DMA_READY) | 1349c2afad6cSKamil Konieczny BIT(HASH_FLAGS_OUTPUT_READY)); 1350c2afad6cSKamil Konieczny spin_unlock_irqrestore(&dd->hash_lock, flags); 1351c2afad6cSKamil Konieczny 1352c2afad6cSKamil Konieczny if (req->base.complete) 1353c2afad6cSKamil Konieczny req->base.complete(&req->base, err); 1354c2afad6cSKamil Konieczny } 1355c2afad6cSKamil Konieczny 1356c2afad6cSKamil Konieczny /** 1357c2afad6cSKamil Konieczny * s5p_hash_handle_queue() - handle hash queue 1358c2afad6cSKamil Konieczny * @dd: device s5p_aes_dev 1359c2afad6cSKamil Konieczny * @req: AHASH request 1360c2afad6cSKamil Konieczny * 1361c2afad6cSKamil Konieczny * If req!=NULL enqueue it on dd->queue, if FLAGS_BUSY is not set on the 1362c2afad6cSKamil Konieczny * device then processes the first request from the dd->queue 1363c2afad6cSKamil Konieczny * 1364c2afad6cSKamil Konieczny * Returns: see s5p_hash_final below. 1365c2afad6cSKamil Konieczny */ 1366c2afad6cSKamil Konieczny static int s5p_hash_handle_queue(struct s5p_aes_dev *dd, 1367c2afad6cSKamil Konieczny struct ahash_request *req) 1368c2afad6cSKamil Konieczny { 1369c2afad6cSKamil Konieczny struct crypto_async_request *async_req, *backlog; 1370c2afad6cSKamil Konieczny struct s5p_hash_reqctx *ctx; 1371c2afad6cSKamil Konieczny unsigned long flags; 1372c2afad6cSKamil Konieczny int err = 0, ret = 0; 1373c2afad6cSKamil Konieczny 1374c2afad6cSKamil Konieczny retry: 1375c2afad6cSKamil Konieczny spin_lock_irqsave(&dd->hash_lock, flags); 1376c2afad6cSKamil Konieczny if (req) 1377c2afad6cSKamil Konieczny ret = ahash_enqueue_request(&dd->hash_queue, req); 1378c2afad6cSKamil Konieczny 1379c2afad6cSKamil Konieczny if (test_bit(HASH_FLAGS_BUSY, &dd->hash_flags)) { 1380c2afad6cSKamil Konieczny spin_unlock_irqrestore(&dd->hash_lock, flags); 1381c2afad6cSKamil Konieczny return ret; 1382c2afad6cSKamil Konieczny } 1383c2afad6cSKamil Konieczny 1384c2afad6cSKamil Konieczny backlog = crypto_get_backlog(&dd->hash_queue); 1385c2afad6cSKamil Konieczny async_req = crypto_dequeue_request(&dd->hash_queue); 1386c2afad6cSKamil Konieczny if (async_req) 1387c2afad6cSKamil Konieczny set_bit(HASH_FLAGS_BUSY, &dd->hash_flags); 1388c2afad6cSKamil Konieczny 1389c2afad6cSKamil Konieczny spin_unlock_irqrestore(&dd->hash_lock, flags); 1390c2afad6cSKamil Konieczny 1391c2afad6cSKamil Konieczny if (!async_req) 1392c2afad6cSKamil Konieczny return ret; 1393c2afad6cSKamil Konieczny 1394c2afad6cSKamil Konieczny if (backlog) 1395c2afad6cSKamil Konieczny backlog->complete(backlog, -EINPROGRESS); 1396c2afad6cSKamil Konieczny 1397c2afad6cSKamil Konieczny req = ahash_request_cast(async_req); 1398c2afad6cSKamil Konieczny dd->hash_req = req; 1399c2afad6cSKamil Konieczny ctx = ahash_request_ctx(req); 1400c2afad6cSKamil Konieczny 1401c2afad6cSKamil Konieczny err = s5p_hash_prepare_request(req, ctx->op_update); 1402c2afad6cSKamil Konieczny if (err || !ctx->total) 1403c2afad6cSKamil Konieczny goto out; 1404c2afad6cSKamil Konieczny 1405c2afad6cSKamil Konieczny dev_dbg(dd->dev, "handling new req, op_update: %u, nbytes: %d\n", 1406c2afad6cSKamil Konieczny ctx->op_update, req->nbytes); 1407c2afad6cSKamil Konieczny 1408c2afad6cSKamil Konieczny s5p_ahash_dma_init(dd, SSS_HASHIN_INDEPENDENT); 1409c2afad6cSKamil Konieczny if (ctx->digcnt) 1410c2afad6cSKamil Konieczny s5p_hash_write_iv(req); /* restore hash IV */ 1411c2afad6cSKamil Konieczny 1412c2afad6cSKamil Konieczny if (ctx->op_update) { /* HASH_OP_UPDATE */ 1413c2afad6cSKamil Konieczny err = s5p_hash_xmit_dma(dd, ctx->total, ctx->finup); 1414c2afad6cSKamil Konieczny if (err != -EINPROGRESS && ctx->finup && !ctx->error) 1415c2afad6cSKamil Konieczny /* no final() after finup() */ 1416c2afad6cSKamil Konieczny err = s5p_hash_xmit_dma(dd, ctx->total, true); 1417c2afad6cSKamil Konieczny } else { /* HASH_OP_FINAL */ 1418c2afad6cSKamil Konieczny err = s5p_hash_xmit_dma(dd, ctx->total, true); 1419c2afad6cSKamil Konieczny } 1420c2afad6cSKamil Konieczny out: 1421c2afad6cSKamil Konieczny if (err != -EINPROGRESS) { 1422c2afad6cSKamil Konieczny /* hash_tasklet_cb will not finish it, so do it here */ 1423c2afad6cSKamil Konieczny s5p_hash_finish_req(req, err); 1424c2afad6cSKamil Konieczny req = NULL; 1425c2afad6cSKamil Konieczny 1426c2afad6cSKamil Konieczny /* 1427c2afad6cSKamil Konieczny * Execute next request immediately if there is anything 1428c2afad6cSKamil Konieczny * in queue. 1429c2afad6cSKamil Konieczny */ 1430c2afad6cSKamil Konieczny goto retry; 1431c2afad6cSKamil Konieczny } 1432c2afad6cSKamil Konieczny 1433c2afad6cSKamil Konieczny return ret; 1434c2afad6cSKamil Konieczny } 1435c2afad6cSKamil Konieczny 1436c2afad6cSKamil Konieczny /** 1437c2afad6cSKamil Konieczny * s5p_hash_tasklet_cb() - hash tasklet 1438c2afad6cSKamil Konieczny * @data: ptr to s5p_aes_dev 1439c2afad6cSKamil Konieczny */ 1440c2afad6cSKamil Konieczny static void s5p_hash_tasklet_cb(unsigned long data) 1441c2afad6cSKamil Konieczny { 1442c2afad6cSKamil Konieczny struct s5p_aes_dev *dd = (struct s5p_aes_dev *)data; 1443c2afad6cSKamil Konieczny 1444c2afad6cSKamil Konieczny if (!test_bit(HASH_FLAGS_BUSY, &dd->hash_flags)) { 1445c2afad6cSKamil Konieczny s5p_hash_handle_queue(dd, NULL); 1446c2afad6cSKamil Konieczny return; 1447c2afad6cSKamil Konieczny } 1448c2afad6cSKamil Konieczny 1449c2afad6cSKamil Konieczny if (test_bit(HASH_FLAGS_DMA_READY, &dd->hash_flags)) { 1450c2afad6cSKamil Konieczny if (test_and_clear_bit(HASH_FLAGS_DMA_ACTIVE, 1451c2afad6cSKamil Konieczny &dd->hash_flags)) { 1452c2afad6cSKamil Konieczny s5p_hash_update_dma_stop(dd); 1453c2afad6cSKamil Konieczny } 1454c2afad6cSKamil Konieczny 1455c2afad6cSKamil Konieczny if (test_and_clear_bit(HASH_FLAGS_OUTPUT_READY, 1456c2afad6cSKamil Konieczny &dd->hash_flags)) { 1457c2afad6cSKamil Konieczny /* hash or semi-hash ready */ 1458c2afad6cSKamil Konieczny clear_bit(HASH_FLAGS_DMA_READY, &dd->hash_flags); 1459c2afad6cSKamil Konieczny goto finish; 1460c2afad6cSKamil Konieczny } 1461c2afad6cSKamil Konieczny } 1462c2afad6cSKamil Konieczny 1463c2afad6cSKamil Konieczny return; 1464c2afad6cSKamil Konieczny 1465c2afad6cSKamil Konieczny finish: 1466c2afad6cSKamil Konieczny /* finish curent request */ 1467c2afad6cSKamil Konieczny s5p_hash_finish_req(dd->hash_req, 0); 1468c2afad6cSKamil Konieczny 1469c2afad6cSKamil Konieczny /* If we are not busy, process next req */ 1470c2afad6cSKamil Konieczny if (!test_bit(HASH_FLAGS_BUSY, &dd->hash_flags)) 1471c2afad6cSKamil Konieczny s5p_hash_handle_queue(dd, NULL); 1472c2afad6cSKamil Konieczny } 1473c2afad6cSKamil Konieczny 1474c2afad6cSKamil Konieczny /** 1475c2afad6cSKamil Konieczny * s5p_hash_enqueue() - enqueue request 1476c2afad6cSKamil Konieczny * @req: AHASH request 1477c2afad6cSKamil Konieczny * @op: operation UPDATE (true) or FINAL (false) 1478c2afad6cSKamil Konieczny * 1479c2afad6cSKamil Konieczny * Returns: see s5p_hash_final below. 1480c2afad6cSKamil Konieczny */ 1481c2afad6cSKamil Konieczny static int s5p_hash_enqueue(struct ahash_request *req, bool op) 1482c2afad6cSKamil Konieczny { 1483c2afad6cSKamil Konieczny struct s5p_hash_reqctx *ctx = ahash_request_ctx(req); 1484c2afad6cSKamil Konieczny struct s5p_hash_ctx *tctx = crypto_tfm_ctx(req->base.tfm); 1485c2afad6cSKamil Konieczny 1486c2afad6cSKamil Konieczny ctx->op_update = op; 1487c2afad6cSKamil Konieczny 1488c2afad6cSKamil Konieczny return s5p_hash_handle_queue(tctx->dd, req); 1489c2afad6cSKamil Konieczny } 1490c2afad6cSKamil Konieczny 1491c2afad6cSKamil Konieczny /** 1492c2afad6cSKamil Konieczny * s5p_hash_update() - process the hash input data 1493c2afad6cSKamil Konieczny * @req: AHASH request 1494c2afad6cSKamil Konieczny * 1495c2afad6cSKamil Konieczny * If request will fit in buffer, copy it and return immediately 1496c2afad6cSKamil Konieczny * else enqueue it with OP_UPDATE. 1497c2afad6cSKamil Konieczny * 1498c2afad6cSKamil Konieczny * Returns: see s5p_hash_final below. 1499c2afad6cSKamil Konieczny */ 1500c2afad6cSKamil Konieczny static int s5p_hash_update(struct ahash_request *req) 1501c2afad6cSKamil Konieczny { 1502c2afad6cSKamil Konieczny struct s5p_hash_reqctx *ctx = ahash_request_ctx(req); 1503c2afad6cSKamil Konieczny 1504c2afad6cSKamil Konieczny if (!req->nbytes) 1505c2afad6cSKamil Konieczny return 0; 1506c2afad6cSKamil Konieczny 1507c2afad6cSKamil Konieczny if (ctx->bufcnt + req->nbytes <= BUFLEN) { 1508c2afad6cSKamil Konieczny scatterwalk_map_and_copy(ctx->buffer + ctx->bufcnt, req->src, 1509c2afad6cSKamil Konieczny 0, req->nbytes, 0); 1510c2afad6cSKamil Konieczny ctx->bufcnt += req->nbytes; 1511c2afad6cSKamil Konieczny return 0; 1512c2afad6cSKamil Konieczny } 1513c2afad6cSKamil Konieczny 1514c2afad6cSKamil Konieczny return s5p_hash_enqueue(req, true); /* HASH_OP_UPDATE */ 1515c2afad6cSKamil Konieczny } 1516c2afad6cSKamil Konieczny 1517c2afad6cSKamil Konieczny /** 1518c2afad6cSKamil Konieczny * s5p_hash_shash_digest() - calculate shash digest 1519c2afad6cSKamil Konieczny * @tfm: crypto transformation 1520c2afad6cSKamil Konieczny * @flags: tfm flags 1521c2afad6cSKamil Konieczny * @data: input data 1522c2afad6cSKamil Konieczny * @len: length of data 1523c2afad6cSKamil Konieczny * @out: output buffer 1524c2afad6cSKamil Konieczny */ 1525c2afad6cSKamil Konieczny static int s5p_hash_shash_digest(struct crypto_shash *tfm, u32 flags, 1526c2afad6cSKamil Konieczny const u8 *data, unsigned int len, u8 *out) 1527c2afad6cSKamil Konieczny { 1528c2afad6cSKamil Konieczny SHASH_DESC_ON_STACK(shash, tfm); 1529c2afad6cSKamil Konieczny 1530c2afad6cSKamil Konieczny shash->tfm = tfm; 1531c2afad6cSKamil Konieczny shash->flags = flags & ~CRYPTO_TFM_REQ_MAY_SLEEP; 1532c2afad6cSKamil Konieczny 1533c2afad6cSKamil Konieczny return crypto_shash_digest(shash, data, len, out); 1534c2afad6cSKamil Konieczny } 1535c2afad6cSKamil Konieczny 1536c2afad6cSKamil Konieczny /** 1537c2afad6cSKamil Konieczny * s5p_hash_final_shash() - calculate shash digest 1538c2afad6cSKamil Konieczny * @req: AHASH request 1539c2afad6cSKamil Konieczny */ 1540c2afad6cSKamil Konieczny static int s5p_hash_final_shash(struct ahash_request *req) 1541c2afad6cSKamil Konieczny { 1542c2afad6cSKamil Konieczny struct s5p_hash_ctx *tctx = crypto_tfm_ctx(req->base.tfm); 1543c2afad6cSKamil Konieczny struct s5p_hash_reqctx *ctx = ahash_request_ctx(req); 1544c2afad6cSKamil Konieczny 1545c2afad6cSKamil Konieczny return s5p_hash_shash_digest(tctx->fallback, req->base.flags, 1546c2afad6cSKamil Konieczny ctx->buffer, ctx->bufcnt, req->result); 1547c2afad6cSKamil Konieczny } 1548c2afad6cSKamil Konieczny 1549c2afad6cSKamil Konieczny /** 1550c2afad6cSKamil Konieczny * s5p_hash_final() - close up hash and calculate digest 1551c2afad6cSKamil Konieczny * @req: AHASH request 1552c2afad6cSKamil Konieczny * 1553c2afad6cSKamil Konieczny * Note: in final req->src do not have any data, and req->nbytes can be 1554c2afad6cSKamil Konieczny * non-zero. 1555c2afad6cSKamil Konieczny * 1556c2afad6cSKamil Konieczny * If there were no input data processed yet and the buffered hash data is 1557c2afad6cSKamil Konieczny * less than BUFLEN (64) then calculate the final hash immediately by using 1558c2afad6cSKamil Konieczny * SW algorithm fallback. 1559c2afad6cSKamil Konieczny * 1560c2afad6cSKamil Konieczny * Otherwise enqueues the current AHASH request with OP_FINAL operation op 1561c2afad6cSKamil Konieczny * and finalize hash message in HW. Note that if digcnt!=0 then there were 1562c2afad6cSKamil Konieczny * previous update op, so there are always some buffered bytes in ctx->buffer, 1563c2afad6cSKamil Konieczny * which means that ctx->bufcnt!=0 1564c2afad6cSKamil Konieczny * 1565c2afad6cSKamil Konieczny * Returns: 1566c2afad6cSKamil Konieczny * 0 if the request has been processed immediately, 1567c2afad6cSKamil Konieczny * -EINPROGRESS if the operation has been queued for later execution or is set 1568c2afad6cSKamil Konieczny * to processing by HW, 1569c2afad6cSKamil Konieczny * -EBUSY if queue is full and request should be resubmitted later, 1570c2afad6cSKamil Konieczny * other negative values denotes an error. 1571c2afad6cSKamil Konieczny */ 1572c2afad6cSKamil Konieczny static int s5p_hash_final(struct ahash_request *req) 1573c2afad6cSKamil Konieczny { 1574c2afad6cSKamil Konieczny struct s5p_hash_reqctx *ctx = ahash_request_ctx(req); 1575c2afad6cSKamil Konieczny 1576c2afad6cSKamil Konieczny ctx->finup = true; 1577c2afad6cSKamil Konieczny if (ctx->error) 1578c2afad6cSKamil Konieczny return -EINVAL; /* uncompleted hash is not needed */ 1579c2afad6cSKamil Konieczny 1580c2afad6cSKamil Konieczny if (!ctx->digcnt && ctx->bufcnt < BUFLEN) 1581c2afad6cSKamil Konieczny return s5p_hash_final_shash(req); 1582c2afad6cSKamil Konieczny 1583c2afad6cSKamil Konieczny return s5p_hash_enqueue(req, false); /* HASH_OP_FINAL */ 1584c2afad6cSKamil Konieczny } 1585c2afad6cSKamil Konieczny 1586c2afad6cSKamil Konieczny /** 1587c2afad6cSKamil Konieczny * s5p_hash_finup() - process last req->src and calculate digest 1588c2afad6cSKamil Konieczny * @req: AHASH request containing the last update data 1589c2afad6cSKamil Konieczny * 1590c2afad6cSKamil Konieczny * Return values: see s5p_hash_final above. 1591c2afad6cSKamil Konieczny */ 1592c2afad6cSKamil Konieczny static int s5p_hash_finup(struct ahash_request *req) 1593c2afad6cSKamil Konieczny { 1594c2afad6cSKamil Konieczny struct s5p_hash_reqctx *ctx = ahash_request_ctx(req); 1595c2afad6cSKamil Konieczny int err1, err2; 1596c2afad6cSKamil Konieczny 1597c2afad6cSKamil Konieczny ctx->finup = true; 1598c2afad6cSKamil Konieczny 1599c2afad6cSKamil Konieczny err1 = s5p_hash_update(req); 1600c2afad6cSKamil Konieczny if (err1 == -EINPROGRESS || err1 == -EBUSY) 1601c2afad6cSKamil Konieczny return err1; 1602c2afad6cSKamil Konieczny 1603c2afad6cSKamil Konieczny /* 1604c2afad6cSKamil Konieczny * final() has to be always called to cleanup resources even if 1605c2afad6cSKamil Konieczny * update() failed, except EINPROGRESS or calculate digest for small 1606c2afad6cSKamil Konieczny * size 1607c2afad6cSKamil Konieczny */ 1608c2afad6cSKamil Konieczny err2 = s5p_hash_final(req); 1609c2afad6cSKamil Konieczny 1610c2afad6cSKamil Konieczny return err1 ?: err2; 1611c2afad6cSKamil Konieczny } 1612c2afad6cSKamil Konieczny 1613c2afad6cSKamil Konieczny /** 1614c2afad6cSKamil Konieczny * s5p_hash_init() - initialize AHASH request contex 1615c2afad6cSKamil Konieczny * @req: AHASH request 1616c2afad6cSKamil Konieczny * 1617c2afad6cSKamil Konieczny * Init async hash request context. 1618c2afad6cSKamil Konieczny */ 1619c2afad6cSKamil Konieczny static int s5p_hash_init(struct ahash_request *req) 1620c2afad6cSKamil Konieczny { 1621c2afad6cSKamil Konieczny struct s5p_hash_reqctx *ctx = ahash_request_ctx(req); 1622c2afad6cSKamil Konieczny struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); 1623c2afad6cSKamil Konieczny struct s5p_hash_ctx *tctx = crypto_ahash_ctx(tfm); 1624c2afad6cSKamil Konieczny 1625c2afad6cSKamil Konieczny ctx->dd = tctx->dd; 1626c2afad6cSKamil Konieczny ctx->error = false; 1627c2afad6cSKamil Konieczny ctx->finup = false; 1628c2afad6cSKamil Konieczny ctx->bufcnt = 0; 1629c2afad6cSKamil Konieczny ctx->digcnt = 0; 1630c2afad6cSKamil Konieczny ctx->total = 0; 1631c2afad6cSKamil Konieczny ctx->skip = 0; 1632c2afad6cSKamil Konieczny 1633c2afad6cSKamil Konieczny dev_dbg(tctx->dd->dev, "init: digest size: %d\n", 1634c2afad6cSKamil Konieczny crypto_ahash_digestsize(tfm)); 1635c2afad6cSKamil Konieczny 1636c2afad6cSKamil Konieczny switch (crypto_ahash_digestsize(tfm)) { 1637c2afad6cSKamil Konieczny case MD5_DIGEST_SIZE: 1638c2afad6cSKamil Konieczny ctx->engine = SSS_HASH_ENGINE_MD5; 1639c2afad6cSKamil Konieczny ctx->nregs = HASH_MD5_MAX_REG; 1640c2afad6cSKamil Konieczny break; 1641c2afad6cSKamil Konieczny case SHA1_DIGEST_SIZE: 1642c2afad6cSKamil Konieczny ctx->engine = SSS_HASH_ENGINE_SHA1; 1643c2afad6cSKamil Konieczny ctx->nregs = HASH_SHA1_MAX_REG; 1644c2afad6cSKamil Konieczny break; 1645c2afad6cSKamil Konieczny case SHA256_DIGEST_SIZE: 1646c2afad6cSKamil Konieczny ctx->engine = SSS_HASH_ENGINE_SHA256; 1647c2afad6cSKamil Konieczny ctx->nregs = HASH_SHA256_MAX_REG; 1648c2afad6cSKamil Konieczny break; 1649c2afad6cSKamil Konieczny default: 1650c2afad6cSKamil Konieczny ctx->error = true; 1651c2afad6cSKamil Konieczny return -EINVAL; 1652c2afad6cSKamil Konieczny } 1653c2afad6cSKamil Konieczny 1654c2afad6cSKamil Konieczny return 0; 1655c2afad6cSKamil Konieczny } 1656c2afad6cSKamil Konieczny 1657c2afad6cSKamil Konieczny /** 1658c2afad6cSKamil Konieczny * s5p_hash_digest - calculate digest from req->src 1659c2afad6cSKamil Konieczny * @req: AHASH request 1660c2afad6cSKamil Konieczny * 1661c2afad6cSKamil Konieczny * Return values: see s5p_hash_final above. 1662c2afad6cSKamil Konieczny */ 1663c2afad6cSKamil Konieczny static int s5p_hash_digest(struct ahash_request *req) 1664c2afad6cSKamil Konieczny { 1665c2afad6cSKamil Konieczny return s5p_hash_init(req) ?: s5p_hash_finup(req); 1666c2afad6cSKamil Konieczny } 1667c2afad6cSKamil Konieczny 1668c2afad6cSKamil Konieczny /** 1669c2afad6cSKamil Konieczny * s5p_hash_cra_init_alg - init crypto alg transformation 1670c2afad6cSKamil Konieczny * @tfm: crypto transformation 1671c2afad6cSKamil Konieczny */ 1672c2afad6cSKamil Konieczny static int s5p_hash_cra_init_alg(struct crypto_tfm *tfm) 1673c2afad6cSKamil Konieczny { 1674c2afad6cSKamil Konieczny struct s5p_hash_ctx *tctx = crypto_tfm_ctx(tfm); 1675c2afad6cSKamil Konieczny const char *alg_name = crypto_tfm_alg_name(tfm); 1676c2afad6cSKamil Konieczny 1677c2afad6cSKamil Konieczny tctx->dd = s5p_dev; 1678c2afad6cSKamil Konieczny /* Allocate a fallback and abort if it failed. */ 1679c2afad6cSKamil Konieczny tctx->fallback = crypto_alloc_shash(alg_name, 0, 1680c2afad6cSKamil Konieczny CRYPTO_ALG_NEED_FALLBACK); 1681c2afad6cSKamil Konieczny if (IS_ERR(tctx->fallback)) { 1682c2afad6cSKamil Konieczny pr_err("fallback alloc fails for '%s'\n", alg_name); 1683c2afad6cSKamil Konieczny return PTR_ERR(tctx->fallback); 1684c2afad6cSKamil Konieczny } 1685c2afad6cSKamil Konieczny 1686c2afad6cSKamil Konieczny crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm), 1687c2afad6cSKamil Konieczny sizeof(struct s5p_hash_reqctx) + BUFLEN); 1688c2afad6cSKamil Konieczny 1689c2afad6cSKamil Konieczny return 0; 1690c2afad6cSKamil Konieczny } 1691c2afad6cSKamil Konieczny 1692c2afad6cSKamil Konieczny /** 1693c2afad6cSKamil Konieczny * s5p_hash_cra_init - init crypto tfm 1694c2afad6cSKamil Konieczny * @tfm: crypto transformation 1695c2afad6cSKamil Konieczny */ 1696c2afad6cSKamil Konieczny static int s5p_hash_cra_init(struct crypto_tfm *tfm) 1697c2afad6cSKamil Konieczny { 1698c2afad6cSKamil Konieczny return s5p_hash_cra_init_alg(tfm); 1699c2afad6cSKamil Konieczny } 1700c2afad6cSKamil Konieczny 1701c2afad6cSKamil Konieczny /** 1702c2afad6cSKamil Konieczny * s5p_hash_cra_exit - exit crypto tfm 1703c2afad6cSKamil Konieczny * @tfm: crypto transformation 1704c2afad6cSKamil Konieczny * 1705c2afad6cSKamil Konieczny * free allocated fallback 1706c2afad6cSKamil Konieczny */ 1707c2afad6cSKamil Konieczny static void s5p_hash_cra_exit(struct crypto_tfm *tfm) 1708c2afad6cSKamil Konieczny { 1709c2afad6cSKamil Konieczny struct s5p_hash_ctx *tctx = crypto_tfm_ctx(tfm); 1710c2afad6cSKamil Konieczny 1711c2afad6cSKamil Konieczny crypto_free_shash(tctx->fallback); 1712c2afad6cSKamil Konieczny tctx->fallback = NULL; 1713c2afad6cSKamil Konieczny } 1714c2afad6cSKamil Konieczny 1715c2afad6cSKamil Konieczny /** 1716c2afad6cSKamil Konieczny * s5p_hash_export - export hash state 1717c2afad6cSKamil Konieczny * @req: AHASH request 1718c2afad6cSKamil Konieczny * @out: buffer for exported state 1719c2afad6cSKamil Konieczny */ 1720c2afad6cSKamil Konieczny static int s5p_hash_export(struct ahash_request *req, void *out) 1721c2afad6cSKamil Konieczny { 17226584eacbSKrzysztof Kozlowski const struct s5p_hash_reqctx *ctx = ahash_request_ctx(req); 1723c2afad6cSKamil Konieczny 1724c2afad6cSKamil Konieczny memcpy(out, ctx, sizeof(*ctx) + ctx->bufcnt); 1725c2afad6cSKamil Konieczny 1726c2afad6cSKamil Konieczny return 0; 1727c2afad6cSKamil Konieczny } 1728c2afad6cSKamil Konieczny 1729c2afad6cSKamil Konieczny /** 1730c2afad6cSKamil Konieczny * s5p_hash_import - import hash state 1731c2afad6cSKamil Konieczny * @req: AHASH request 1732c2afad6cSKamil Konieczny * @in: buffer with state to be imported from 1733c2afad6cSKamil Konieczny */ 1734c2afad6cSKamil Konieczny static int s5p_hash_import(struct ahash_request *req, const void *in) 1735c2afad6cSKamil Konieczny { 1736c2afad6cSKamil Konieczny struct s5p_hash_reqctx *ctx = ahash_request_ctx(req); 1737c2afad6cSKamil Konieczny struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); 1738c2afad6cSKamil Konieczny struct s5p_hash_ctx *tctx = crypto_ahash_ctx(tfm); 1739c2afad6cSKamil Konieczny const struct s5p_hash_reqctx *ctx_in = in; 1740c2afad6cSKamil Konieczny 1741c2afad6cSKamil Konieczny memcpy(ctx, in, sizeof(*ctx) + BUFLEN); 1742c2afad6cSKamil Konieczny if (ctx_in->bufcnt > BUFLEN) { 1743c2afad6cSKamil Konieczny ctx->error = true; 1744c2afad6cSKamil Konieczny return -EINVAL; 1745c2afad6cSKamil Konieczny } 1746c2afad6cSKamil Konieczny 1747c2afad6cSKamil Konieczny ctx->dd = tctx->dd; 1748c2afad6cSKamil Konieczny ctx->error = false; 1749c2afad6cSKamil Konieczny 1750c2afad6cSKamil Konieczny return 0; 1751c2afad6cSKamil Konieczny } 1752c2afad6cSKamil Konieczny 1753c2afad6cSKamil Konieczny static struct ahash_alg algs_sha1_md5_sha256[] = { 1754c2afad6cSKamil Konieczny { 1755c2afad6cSKamil Konieczny .init = s5p_hash_init, 1756c2afad6cSKamil Konieczny .update = s5p_hash_update, 1757c2afad6cSKamil Konieczny .final = s5p_hash_final, 1758c2afad6cSKamil Konieczny .finup = s5p_hash_finup, 1759c2afad6cSKamil Konieczny .digest = s5p_hash_digest, 1760c2afad6cSKamil Konieczny .export = s5p_hash_export, 1761c2afad6cSKamil Konieczny .import = s5p_hash_import, 1762c2afad6cSKamil Konieczny .halg.statesize = sizeof(struct s5p_hash_reqctx) + BUFLEN, 1763c2afad6cSKamil Konieczny .halg.digestsize = SHA1_DIGEST_SIZE, 1764c2afad6cSKamil Konieczny .halg.base = { 1765c2afad6cSKamil Konieczny .cra_name = "sha1", 1766c2afad6cSKamil Konieczny .cra_driver_name = "exynos-sha1", 1767c2afad6cSKamil Konieczny .cra_priority = 100, 17686a38f622SEric Biggers .cra_flags = CRYPTO_ALG_KERN_DRIVER_ONLY | 1769c2afad6cSKamil Konieczny CRYPTO_ALG_ASYNC | 1770c2afad6cSKamil Konieczny CRYPTO_ALG_NEED_FALLBACK, 1771c2afad6cSKamil Konieczny .cra_blocksize = HASH_BLOCK_SIZE, 1772c2afad6cSKamil Konieczny .cra_ctxsize = sizeof(struct s5p_hash_ctx), 1773c2afad6cSKamil Konieczny .cra_alignmask = SSS_HASH_DMA_ALIGN_MASK, 1774c2afad6cSKamil Konieczny .cra_module = THIS_MODULE, 1775c2afad6cSKamil Konieczny .cra_init = s5p_hash_cra_init, 1776c2afad6cSKamil Konieczny .cra_exit = s5p_hash_cra_exit, 1777c2afad6cSKamil Konieczny } 1778c2afad6cSKamil Konieczny }, 1779c2afad6cSKamil Konieczny { 1780c2afad6cSKamil Konieczny .init = s5p_hash_init, 1781c2afad6cSKamil Konieczny .update = s5p_hash_update, 1782c2afad6cSKamil Konieczny .final = s5p_hash_final, 1783c2afad6cSKamil Konieczny .finup = s5p_hash_finup, 1784c2afad6cSKamil Konieczny .digest = s5p_hash_digest, 1785c2afad6cSKamil Konieczny .export = s5p_hash_export, 1786c2afad6cSKamil Konieczny .import = s5p_hash_import, 1787c2afad6cSKamil Konieczny .halg.statesize = sizeof(struct s5p_hash_reqctx) + BUFLEN, 1788c2afad6cSKamil Konieczny .halg.digestsize = MD5_DIGEST_SIZE, 1789c2afad6cSKamil Konieczny .halg.base = { 1790c2afad6cSKamil Konieczny .cra_name = "md5", 1791c2afad6cSKamil Konieczny .cra_driver_name = "exynos-md5", 1792c2afad6cSKamil Konieczny .cra_priority = 100, 17936a38f622SEric Biggers .cra_flags = CRYPTO_ALG_KERN_DRIVER_ONLY | 1794c2afad6cSKamil Konieczny CRYPTO_ALG_ASYNC | 1795c2afad6cSKamil Konieczny CRYPTO_ALG_NEED_FALLBACK, 1796c2afad6cSKamil Konieczny .cra_blocksize = HASH_BLOCK_SIZE, 1797c2afad6cSKamil Konieczny .cra_ctxsize = sizeof(struct s5p_hash_ctx), 1798c2afad6cSKamil Konieczny .cra_alignmask = SSS_HASH_DMA_ALIGN_MASK, 1799c2afad6cSKamil Konieczny .cra_module = THIS_MODULE, 1800c2afad6cSKamil Konieczny .cra_init = s5p_hash_cra_init, 1801c2afad6cSKamil Konieczny .cra_exit = s5p_hash_cra_exit, 1802c2afad6cSKamil Konieczny } 1803c2afad6cSKamil Konieczny }, 1804c2afad6cSKamil Konieczny { 1805c2afad6cSKamil Konieczny .init = s5p_hash_init, 1806c2afad6cSKamil Konieczny .update = s5p_hash_update, 1807c2afad6cSKamil Konieczny .final = s5p_hash_final, 1808c2afad6cSKamil Konieczny .finup = s5p_hash_finup, 1809c2afad6cSKamil Konieczny .digest = s5p_hash_digest, 1810c2afad6cSKamil Konieczny .export = s5p_hash_export, 1811c2afad6cSKamil Konieczny .import = s5p_hash_import, 1812c2afad6cSKamil Konieczny .halg.statesize = sizeof(struct s5p_hash_reqctx) + BUFLEN, 1813c2afad6cSKamil Konieczny .halg.digestsize = SHA256_DIGEST_SIZE, 1814c2afad6cSKamil Konieczny .halg.base = { 1815c2afad6cSKamil Konieczny .cra_name = "sha256", 1816c2afad6cSKamil Konieczny .cra_driver_name = "exynos-sha256", 1817c2afad6cSKamil Konieczny .cra_priority = 100, 18186a38f622SEric Biggers .cra_flags = CRYPTO_ALG_KERN_DRIVER_ONLY | 1819c2afad6cSKamil Konieczny CRYPTO_ALG_ASYNC | 1820c2afad6cSKamil Konieczny CRYPTO_ALG_NEED_FALLBACK, 1821c2afad6cSKamil Konieczny .cra_blocksize = HASH_BLOCK_SIZE, 1822c2afad6cSKamil Konieczny .cra_ctxsize = sizeof(struct s5p_hash_ctx), 1823c2afad6cSKamil Konieczny .cra_alignmask = SSS_HASH_DMA_ALIGN_MASK, 1824c2afad6cSKamil Konieczny .cra_module = THIS_MODULE, 1825c2afad6cSKamil Konieczny .cra_init = s5p_hash_cra_init, 1826c2afad6cSKamil Konieczny .cra_exit = s5p_hash_cra_exit, 1827c2afad6cSKamil Konieczny } 1828c2afad6cSKamil Konieczny } 1829c2afad6cSKamil Konieczny 1830c2afad6cSKamil Konieczny }; 1831c2afad6cSKamil Konieczny 1832a49e490cSVladimir Zapolskiy static void s5p_set_aes(struct s5p_aes_dev *dev, 18336584eacbSKrzysztof Kozlowski const uint8_t *key, const uint8_t *iv, 18346584eacbSKrzysztof Kozlowski unsigned int keylen) 1835a49e490cSVladimir Zapolskiy { 1836a49e490cSVladimir Zapolskiy void __iomem *keystart; 1837a49e490cSVladimir Zapolskiy 18388f9702aaSNaveen Krishna Chatradhi if (iv) 18391e3012d0SKrzysztof Koz?owski memcpy_toio(dev->aes_ioaddr + SSS_REG_AES_IV_DATA(0), iv, 0x10); 1840a49e490cSVladimir Zapolskiy 1841a49e490cSVladimir Zapolskiy if (keylen == AES_KEYSIZE_256) 184289245107SNaveen Krishna Chatradhi keystart = dev->aes_ioaddr + SSS_REG_AES_KEY_DATA(0); 1843a49e490cSVladimir Zapolskiy else if (keylen == AES_KEYSIZE_192) 184489245107SNaveen Krishna Chatradhi keystart = dev->aes_ioaddr + SSS_REG_AES_KEY_DATA(2); 1845a49e490cSVladimir Zapolskiy else 184689245107SNaveen Krishna Chatradhi keystart = dev->aes_ioaddr + SSS_REG_AES_KEY_DATA(4); 1847a49e490cSVladimir Zapolskiy 18481e3012d0SKrzysztof Koz?owski memcpy_toio(keystart, key, keylen); 1849a49e490cSVladimir Zapolskiy } 1850a49e490cSVladimir Zapolskiy 18519e4a1100SKrzysztof Kozlowski static bool s5p_is_sg_aligned(struct scatterlist *sg) 18529e4a1100SKrzysztof Kozlowski { 18539e4a1100SKrzysztof Kozlowski while (sg) { 1854d1497977SMarek Szyprowski if (!IS_ALIGNED(sg->length, AES_BLOCK_SIZE)) 18559e4a1100SKrzysztof Kozlowski return false; 18569e4a1100SKrzysztof Kozlowski sg = sg_next(sg); 18579e4a1100SKrzysztof Kozlowski } 18589e4a1100SKrzysztof Kozlowski 18599e4a1100SKrzysztof Kozlowski return true; 18609e4a1100SKrzysztof Kozlowski } 18619e4a1100SKrzysztof Kozlowski 18629e4a1100SKrzysztof Kozlowski static int s5p_set_indata_start(struct s5p_aes_dev *dev, 18639e4a1100SKrzysztof Kozlowski struct ablkcipher_request *req) 18649e4a1100SKrzysztof Kozlowski { 18659e4a1100SKrzysztof Kozlowski struct scatterlist *sg; 18669e4a1100SKrzysztof Kozlowski int err; 18679e4a1100SKrzysztof Kozlowski 18689e4a1100SKrzysztof Kozlowski dev->sg_src_cpy = NULL; 18699e4a1100SKrzysztof Kozlowski sg = req->src; 18709e4a1100SKrzysztof Kozlowski if (!s5p_is_sg_aligned(sg)) { 18719e4a1100SKrzysztof Kozlowski dev_dbg(dev->dev, 18729e4a1100SKrzysztof Kozlowski "At least one unaligned source scatter list, making a copy\n"); 18739e4a1100SKrzysztof Kozlowski err = s5p_make_sg_cpy(dev, sg, &dev->sg_src_cpy); 18749e4a1100SKrzysztof Kozlowski if (err) 18759e4a1100SKrzysztof Kozlowski return err; 18769e4a1100SKrzysztof Kozlowski 18779e4a1100SKrzysztof Kozlowski sg = dev->sg_src_cpy; 18789e4a1100SKrzysztof Kozlowski } 18799e4a1100SKrzysztof Kozlowski 18809e4a1100SKrzysztof Kozlowski err = s5p_set_indata(dev, sg); 18819e4a1100SKrzysztof Kozlowski if (err) { 18829e4a1100SKrzysztof Kozlowski s5p_free_sg_cpy(dev, &dev->sg_src_cpy); 18839e4a1100SKrzysztof Kozlowski return err; 18849e4a1100SKrzysztof Kozlowski } 18859e4a1100SKrzysztof Kozlowski 18869e4a1100SKrzysztof Kozlowski return 0; 18879e4a1100SKrzysztof Kozlowski } 18889e4a1100SKrzysztof Kozlowski 18899e4a1100SKrzysztof Kozlowski static int s5p_set_outdata_start(struct s5p_aes_dev *dev, 18909e4a1100SKrzysztof Kozlowski struct ablkcipher_request *req) 18919e4a1100SKrzysztof Kozlowski { 18929e4a1100SKrzysztof Kozlowski struct scatterlist *sg; 18939e4a1100SKrzysztof Kozlowski int err; 18949e4a1100SKrzysztof Kozlowski 18959e4a1100SKrzysztof Kozlowski dev->sg_dst_cpy = NULL; 18969e4a1100SKrzysztof Kozlowski sg = req->dst; 18979e4a1100SKrzysztof Kozlowski if (!s5p_is_sg_aligned(sg)) { 18989e4a1100SKrzysztof Kozlowski dev_dbg(dev->dev, 18999e4a1100SKrzysztof Kozlowski "At least one unaligned dest scatter list, making a copy\n"); 19009e4a1100SKrzysztof Kozlowski err = s5p_make_sg_cpy(dev, sg, &dev->sg_dst_cpy); 19019e4a1100SKrzysztof Kozlowski if (err) 19029e4a1100SKrzysztof Kozlowski return err; 19039e4a1100SKrzysztof Kozlowski 19049e4a1100SKrzysztof Kozlowski sg = dev->sg_dst_cpy; 19059e4a1100SKrzysztof Kozlowski } 19069e4a1100SKrzysztof Kozlowski 19079e4a1100SKrzysztof Kozlowski err = s5p_set_outdata(dev, sg); 19089e4a1100SKrzysztof Kozlowski if (err) { 19099e4a1100SKrzysztof Kozlowski s5p_free_sg_cpy(dev, &dev->sg_dst_cpy); 19109e4a1100SKrzysztof Kozlowski return err; 19119e4a1100SKrzysztof Kozlowski } 19129e4a1100SKrzysztof Kozlowski 19139e4a1100SKrzysztof Kozlowski return 0; 19149e4a1100SKrzysztof Kozlowski } 19159e4a1100SKrzysztof Kozlowski 1916a49e490cSVladimir Zapolskiy static void s5p_aes_crypt_start(struct s5p_aes_dev *dev, unsigned long mode) 1917a49e490cSVladimir Zapolskiy { 1918a49e490cSVladimir Zapolskiy struct ablkcipher_request *req = dev->req; 1919a49e490cSVladimir Zapolskiy uint32_t aes_control; 1920a49e490cSVladimir Zapolskiy unsigned long flags; 19215318c53dSKrzysztof Kozlowski int err; 1922c927b080SKamil Konieczny u8 *iv; 1923a49e490cSVladimir Zapolskiy 1924a49e490cSVladimir Zapolskiy aes_control = SSS_AES_KEY_CHANGE_MODE; 1925a49e490cSVladimir Zapolskiy if (mode & FLAGS_AES_DECRYPT) 1926a49e490cSVladimir Zapolskiy aes_control |= SSS_AES_MODE_DECRYPT; 1927a49e490cSVladimir Zapolskiy 1928c927b080SKamil Konieczny if ((mode & FLAGS_AES_MODE_MASK) == FLAGS_AES_CBC) { 1929a49e490cSVladimir Zapolskiy aes_control |= SSS_AES_CHAIN_MODE_CBC; 1930c927b080SKamil Konieczny iv = req->info; 1931c927b080SKamil Konieczny } else if ((mode & FLAGS_AES_MODE_MASK) == FLAGS_AES_CTR) { 1932a49e490cSVladimir Zapolskiy aes_control |= SSS_AES_CHAIN_MODE_CTR; 1933c927b080SKamil Konieczny iv = req->info; 1934c927b080SKamil Konieczny } else { 1935c927b080SKamil Konieczny iv = NULL; /* AES_ECB */ 1936c927b080SKamil Konieczny } 1937a49e490cSVladimir Zapolskiy 1938a49e490cSVladimir Zapolskiy if (dev->ctx->keylen == AES_KEYSIZE_192) 1939a49e490cSVladimir Zapolskiy aes_control |= SSS_AES_KEY_SIZE_192; 1940a49e490cSVladimir Zapolskiy else if (dev->ctx->keylen == AES_KEYSIZE_256) 1941a49e490cSVladimir Zapolskiy aes_control |= SSS_AES_KEY_SIZE_256; 1942a49e490cSVladimir Zapolskiy 1943a49e490cSVladimir Zapolskiy aes_control |= SSS_AES_FIFO_MODE; 1944a49e490cSVladimir Zapolskiy 1945a49e490cSVladimir Zapolskiy /* as a variant it is possible to use byte swapping on DMA side */ 1946a49e490cSVladimir Zapolskiy aes_control |= SSS_AES_BYTESWAP_DI 1947a49e490cSVladimir Zapolskiy | SSS_AES_BYTESWAP_DO 1948a49e490cSVladimir Zapolskiy | SSS_AES_BYTESWAP_IV 1949a49e490cSVladimir Zapolskiy | SSS_AES_BYTESWAP_KEY 1950a49e490cSVladimir Zapolskiy | SSS_AES_BYTESWAP_CNT; 1951a49e490cSVladimir Zapolskiy 1952a49e490cSVladimir Zapolskiy spin_lock_irqsave(&dev->lock, flags); 1953a49e490cSVladimir Zapolskiy 1954a49e490cSVladimir Zapolskiy SSS_WRITE(dev, FCINTENCLR, 1955a49e490cSVladimir Zapolskiy SSS_FCINTENCLR_BTDMAINTENCLR | SSS_FCINTENCLR_BRDMAINTENCLR); 1956a49e490cSVladimir Zapolskiy SSS_WRITE(dev, FCFIFOCTRL, 0x00); 1957a49e490cSVladimir Zapolskiy 19589e4a1100SKrzysztof Kozlowski err = s5p_set_indata_start(dev, req); 1959a49e490cSVladimir Zapolskiy if (err) 1960a49e490cSVladimir Zapolskiy goto indata_error; 1961a49e490cSVladimir Zapolskiy 19629e4a1100SKrzysztof Kozlowski err = s5p_set_outdata_start(dev, req); 1963a49e490cSVladimir Zapolskiy if (err) 1964a49e490cSVladimir Zapolskiy goto outdata_error; 1965a49e490cSVladimir Zapolskiy 196689245107SNaveen Krishna Chatradhi SSS_AES_WRITE(dev, AES_CONTROL, aes_control); 1967c927b080SKamil Konieczny s5p_set_aes(dev, dev->ctx->aes_key, iv, dev->ctx->keylen); 1968a49e490cSVladimir Zapolskiy 19699e4a1100SKrzysztof Kozlowski s5p_set_dma_indata(dev, dev->sg_src); 19709e4a1100SKrzysztof Kozlowski s5p_set_dma_outdata(dev, dev->sg_dst); 1971a49e490cSVladimir Zapolskiy 1972a49e490cSVladimir Zapolskiy SSS_WRITE(dev, FCINTENSET, 1973a49e490cSVladimir Zapolskiy SSS_FCINTENSET_BTDMAINTENSET | SSS_FCINTENSET_BRDMAINTENSET); 1974a49e490cSVladimir Zapolskiy 1975a49e490cSVladimir Zapolskiy spin_unlock_irqrestore(&dev->lock, flags); 1976a49e490cSVladimir Zapolskiy 1977a49e490cSVladimir Zapolskiy return; 1978a49e490cSVladimir Zapolskiy 1979a49e490cSVladimir Zapolskiy outdata_error: 1980a49e490cSVladimir Zapolskiy s5p_unset_indata(dev); 1981a49e490cSVladimir Zapolskiy 1982a49e490cSVladimir Zapolskiy indata_error: 198328b62b14SKrzysztof Kozlowski s5p_sg_done(dev); 198442d5c176SKrzysztof Kozlowski dev->busy = false; 1985a49e490cSVladimir Zapolskiy spin_unlock_irqrestore(&dev->lock, flags); 198628b62b14SKrzysztof Kozlowski s5p_aes_complete(dev, err); 1987a49e490cSVladimir Zapolskiy } 1988a49e490cSVladimir Zapolskiy 1989a49e490cSVladimir Zapolskiy static void s5p_tasklet_cb(unsigned long data) 1990a49e490cSVladimir Zapolskiy { 1991a49e490cSVladimir Zapolskiy struct s5p_aes_dev *dev = (struct s5p_aes_dev *)data; 1992a49e490cSVladimir Zapolskiy struct crypto_async_request *async_req, *backlog; 1993a49e490cSVladimir Zapolskiy struct s5p_aes_reqctx *reqctx; 1994a49e490cSVladimir Zapolskiy unsigned long flags; 1995a49e490cSVladimir Zapolskiy 1996a49e490cSVladimir Zapolskiy spin_lock_irqsave(&dev->lock, flags); 1997a49e490cSVladimir Zapolskiy backlog = crypto_get_backlog(&dev->queue); 1998a49e490cSVladimir Zapolskiy async_req = crypto_dequeue_request(&dev->queue); 1999a49e490cSVladimir Zapolskiy 2000dc5e3f19SNaveen Krishna Chatradhi if (!async_req) { 2001dc5e3f19SNaveen Krishna Chatradhi dev->busy = false; 2002dc5e3f19SNaveen Krishna Chatradhi spin_unlock_irqrestore(&dev->lock, flags); 2003a49e490cSVladimir Zapolskiy return; 2004dc5e3f19SNaveen Krishna Chatradhi } 2005dc5e3f19SNaveen Krishna Chatradhi spin_unlock_irqrestore(&dev->lock, flags); 2006a49e490cSVladimir Zapolskiy 2007a49e490cSVladimir Zapolskiy if (backlog) 2008a49e490cSVladimir Zapolskiy backlog->complete(backlog, -EINPROGRESS); 2009a49e490cSVladimir Zapolskiy 2010a49e490cSVladimir Zapolskiy dev->req = ablkcipher_request_cast(async_req); 2011a49e490cSVladimir Zapolskiy dev->ctx = crypto_tfm_ctx(dev->req->base.tfm); 2012a49e490cSVladimir Zapolskiy reqctx = ablkcipher_request_ctx(dev->req); 2013a49e490cSVladimir Zapolskiy 2014a49e490cSVladimir Zapolskiy s5p_aes_crypt_start(dev, reqctx->mode); 2015a49e490cSVladimir Zapolskiy } 2016a49e490cSVladimir Zapolskiy 2017a49e490cSVladimir Zapolskiy static int s5p_aes_handle_req(struct s5p_aes_dev *dev, 2018a49e490cSVladimir Zapolskiy struct ablkcipher_request *req) 2019a49e490cSVladimir Zapolskiy { 2020a49e490cSVladimir Zapolskiy unsigned long flags; 2021a49e490cSVladimir Zapolskiy int err; 2022a49e490cSVladimir Zapolskiy 2023a49e490cSVladimir Zapolskiy spin_lock_irqsave(&dev->lock, flags); 2024dc5e3f19SNaveen Krishna Chatradhi err = ablkcipher_enqueue_request(&dev->queue, req); 2025a49e490cSVladimir Zapolskiy if (dev->busy) { 2026a49e490cSVladimir Zapolskiy spin_unlock_irqrestore(&dev->lock, flags); 2027a49e490cSVladimir Zapolskiy goto exit; 2028a49e490cSVladimir Zapolskiy } 2029a49e490cSVladimir Zapolskiy dev->busy = true; 2030a49e490cSVladimir Zapolskiy 2031a49e490cSVladimir Zapolskiy spin_unlock_irqrestore(&dev->lock, flags); 2032a49e490cSVladimir Zapolskiy 2033a49e490cSVladimir Zapolskiy tasklet_schedule(&dev->tasklet); 2034a49e490cSVladimir Zapolskiy 2035a49e490cSVladimir Zapolskiy exit: 2036a49e490cSVladimir Zapolskiy return err; 2037a49e490cSVladimir Zapolskiy } 2038a49e490cSVladimir Zapolskiy 2039a49e490cSVladimir Zapolskiy static int s5p_aes_crypt(struct ablkcipher_request *req, unsigned long mode) 2040a49e490cSVladimir Zapolskiy { 2041a49e490cSVladimir Zapolskiy struct crypto_ablkcipher *tfm = crypto_ablkcipher_reqtfm(req); 2042a49e490cSVladimir Zapolskiy struct s5p_aes_reqctx *reqctx = ablkcipher_request_ctx(req); 20435318c53dSKrzysztof Kozlowski struct s5p_aes_ctx *ctx = crypto_ablkcipher_ctx(tfm); 2044a49e490cSVladimir Zapolskiy struct s5p_aes_dev *dev = ctx->dev; 2045a49e490cSVladimir Zapolskiy 2046a49e490cSVladimir Zapolskiy if (!IS_ALIGNED(req->nbytes, AES_BLOCK_SIZE)) { 2047313becd1SKrzysztof Koz?owski dev_err(dev->dev, "request size is not exact amount of AES blocks\n"); 2048a49e490cSVladimir Zapolskiy return -EINVAL; 2049a49e490cSVladimir Zapolskiy } 2050a49e490cSVladimir Zapolskiy 2051a49e490cSVladimir Zapolskiy reqctx->mode = mode; 2052a49e490cSVladimir Zapolskiy 2053a49e490cSVladimir Zapolskiy return s5p_aes_handle_req(dev, req); 2054a49e490cSVladimir Zapolskiy } 2055a49e490cSVladimir Zapolskiy 2056a49e490cSVladimir Zapolskiy static int s5p_aes_setkey(struct crypto_ablkcipher *cipher, 2057a49e490cSVladimir Zapolskiy const uint8_t *key, unsigned int keylen) 2058a49e490cSVladimir Zapolskiy { 2059a49e490cSVladimir Zapolskiy struct crypto_tfm *tfm = crypto_ablkcipher_tfm(cipher); 2060a49e490cSVladimir Zapolskiy struct s5p_aes_ctx *ctx = crypto_tfm_ctx(tfm); 2061a49e490cSVladimir Zapolskiy 2062a49e490cSVladimir Zapolskiy if (keylen != AES_KEYSIZE_128 && 2063a49e490cSVladimir Zapolskiy keylen != AES_KEYSIZE_192 && 2064a49e490cSVladimir Zapolskiy keylen != AES_KEYSIZE_256) 2065a49e490cSVladimir Zapolskiy return -EINVAL; 2066a49e490cSVladimir Zapolskiy 2067a49e490cSVladimir Zapolskiy memcpy(ctx->aes_key, key, keylen); 2068a49e490cSVladimir Zapolskiy ctx->keylen = keylen; 2069a49e490cSVladimir Zapolskiy 2070a49e490cSVladimir Zapolskiy return 0; 2071a49e490cSVladimir Zapolskiy } 2072a49e490cSVladimir Zapolskiy 2073a49e490cSVladimir Zapolskiy static int s5p_aes_ecb_encrypt(struct ablkcipher_request *req) 2074a49e490cSVladimir Zapolskiy { 2075a49e490cSVladimir Zapolskiy return s5p_aes_crypt(req, 0); 2076a49e490cSVladimir Zapolskiy } 2077a49e490cSVladimir Zapolskiy 2078a49e490cSVladimir Zapolskiy static int s5p_aes_ecb_decrypt(struct ablkcipher_request *req) 2079a49e490cSVladimir Zapolskiy { 2080a49e490cSVladimir Zapolskiy return s5p_aes_crypt(req, FLAGS_AES_DECRYPT); 2081a49e490cSVladimir Zapolskiy } 2082a49e490cSVladimir Zapolskiy 2083a49e490cSVladimir Zapolskiy static int s5p_aes_cbc_encrypt(struct ablkcipher_request *req) 2084a49e490cSVladimir Zapolskiy { 2085a49e490cSVladimir Zapolskiy return s5p_aes_crypt(req, FLAGS_AES_CBC); 2086a49e490cSVladimir Zapolskiy } 2087a49e490cSVladimir Zapolskiy 2088a49e490cSVladimir Zapolskiy static int s5p_aes_cbc_decrypt(struct ablkcipher_request *req) 2089a49e490cSVladimir Zapolskiy { 2090a49e490cSVladimir Zapolskiy return s5p_aes_crypt(req, FLAGS_AES_DECRYPT | FLAGS_AES_CBC); 2091a49e490cSVladimir Zapolskiy } 2092a49e490cSVladimir Zapolskiy 2093a49e490cSVladimir Zapolskiy static int s5p_aes_cra_init(struct crypto_tfm *tfm) 2094a49e490cSVladimir Zapolskiy { 2095a49e490cSVladimir Zapolskiy struct s5p_aes_ctx *ctx = crypto_tfm_ctx(tfm); 2096a49e490cSVladimir Zapolskiy 2097a49e490cSVladimir Zapolskiy ctx->dev = s5p_dev; 2098a49e490cSVladimir Zapolskiy tfm->crt_ablkcipher.reqsize = sizeof(struct s5p_aes_reqctx); 2099a49e490cSVladimir Zapolskiy 2100a49e490cSVladimir Zapolskiy return 0; 2101a49e490cSVladimir Zapolskiy } 2102a49e490cSVladimir Zapolskiy 2103a49e490cSVladimir Zapolskiy static struct crypto_alg algs[] = { 2104a49e490cSVladimir Zapolskiy { 2105a49e490cSVladimir Zapolskiy .cra_name = "ecb(aes)", 2106a49e490cSVladimir Zapolskiy .cra_driver_name = "ecb-aes-s5p", 2107a49e490cSVladimir Zapolskiy .cra_priority = 100, 2108a49e490cSVladimir Zapolskiy .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | 2109d912bb76SNikos Mavrogiannopoulos CRYPTO_ALG_ASYNC | 2110d912bb76SNikos Mavrogiannopoulos CRYPTO_ALG_KERN_DRIVER_ONLY, 2111a49e490cSVladimir Zapolskiy .cra_blocksize = AES_BLOCK_SIZE, 2112a49e490cSVladimir Zapolskiy .cra_ctxsize = sizeof(struct s5p_aes_ctx), 2113a49e490cSVladimir Zapolskiy .cra_alignmask = 0x0f, 2114a49e490cSVladimir Zapolskiy .cra_type = &crypto_ablkcipher_type, 2115a49e490cSVladimir Zapolskiy .cra_module = THIS_MODULE, 2116a49e490cSVladimir Zapolskiy .cra_init = s5p_aes_cra_init, 2117a49e490cSVladimir Zapolskiy .cra_u.ablkcipher = { 2118a49e490cSVladimir Zapolskiy .min_keysize = AES_MIN_KEY_SIZE, 2119a49e490cSVladimir Zapolskiy .max_keysize = AES_MAX_KEY_SIZE, 2120a49e490cSVladimir Zapolskiy .setkey = s5p_aes_setkey, 2121a49e490cSVladimir Zapolskiy .encrypt = s5p_aes_ecb_encrypt, 2122a49e490cSVladimir Zapolskiy .decrypt = s5p_aes_ecb_decrypt, 2123a49e490cSVladimir Zapolskiy } 2124a49e490cSVladimir Zapolskiy }, 2125a49e490cSVladimir Zapolskiy { 2126a49e490cSVladimir Zapolskiy .cra_name = "cbc(aes)", 2127a49e490cSVladimir Zapolskiy .cra_driver_name = "cbc-aes-s5p", 2128a49e490cSVladimir Zapolskiy .cra_priority = 100, 2129a49e490cSVladimir Zapolskiy .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | 2130d912bb76SNikos Mavrogiannopoulos CRYPTO_ALG_ASYNC | 2131d912bb76SNikos Mavrogiannopoulos CRYPTO_ALG_KERN_DRIVER_ONLY, 2132a49e490cSVladimir Zapolskiy .cra_blocksize = AES_BLOCK_SIZE, 2133a49e490cSVladimir Zapolskiy .cra_ctxsize = sizeof(struct s5p_aes_ctx), 2134a49e490cSVladimir Zapolskiy .cra_alignmask = 0x0f, 2135a49e490cSVladimir Zapolskiy .cra_type = &crypto_ablkcipher_type, 2136a49e490cSVladimir Zapolskiy .cra_module = THIS_MODULE, 2137a49e490cSVladimir Zapolskiy .cra_init = s5p_aes_cra_init, 2138a49e490cSVladimir Zapolskiy .cra_u.ablkcipher = { 2139a49e490cSVladimir Zapolskiy .min_keysize = AES_MIN_KEY_SIZE, 2140a49e490cSVladimir Zapolskiy .max_keysize = AES_MAX_KEY_SIZE, 2141a49e490cSVladimir Zapolskiy .ivsize = AES_BLOCK_SIZE, 2142a49e490cSVladimir Zapolskiy .setkey = s5p_aes_setkey, 2143a49e490cSVladimir Zapolskiy .encrypt = s5p_aes_cbc_encrypt, 2144a49e490cSVladimir Zapolskiy .decrypt = s5p_aes_cbc_decrypt, 2145a49e490cSVladimir Zapolskiy } 2146a49e490cSVladimir Zapolskiy }, 2147a49e490cSVladimir Zapolskiy }; 2148a49e490cSVladimir Zapolskiy 2149a49e490cSVladimir Zapolskiy static int s5p_aes_probe(struct platform_device *pdev) 2150a49e490cSVladimir Zapolskiy { 2151a49e490cSVladimir Zapolskiy struct device *dev = &pdev->dev; 21525318c53dSKrzysztof Kozlowski int i, j, err = -ENODEV; 21536584eacbSKrzysztof Kozlowski const struct samsung_aes_variant *variant; 21545318c53dSKrzysztof Kozlowski struct s5p_aes_dev *pdata; 21555318c53dSKrzysztof Kozlowski struct resource *res; 2156c2afad6cSKamil Konieczny unsigned int hash_i; 2157a49e490cSVladimir Zapolskiy 2158a49e490cSVladimir Zapolskiy if (s5p_dev) 2159a49e490cSVladimir Zapolskiy return -EEXIST; 2160a49e490cSVladimir Zapolskiy 2161a49e490cSVladimir Zapolskiy pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); 2162a49e490cSVladimir Zapolskiy if (!pdata) 2163a49e490cSVladimir Zapolskiy return -ENOMEM; 2164a49e490cSVladimir Zapolskiy 2165c2afad6cSKamil Konieczny variant = find_s5p_sss_version(pdev); 21660fdefe2cSJingoo Han res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 2167c2afad6cSKamil Konieczny 2168c2afad6cSKamil Konieczny /* 2169c2afad6cSKamil Konieczny * Note: HASH and PRNG uses the same registers in secss, avoid 2170c2afad6cSKamil Konieczny * overwrite each other. This will drop HASH when CONFIG_EXYNOS_RNG 2171c2afad6cSKamil Konieczny * is enabled in config. We need larger size for HASH registers in 2172c2afad6cSKamil Konieczny * secss, current describe only AES/DES 2173c2afad6cSKamil Konieczny */ 2174c2afad6cSKamil Konieczny if (IS_ENABLED(CONFIG_CRYPTO_DEV_EXYNOS_HASH)) { 2175c2afad6cSKamil Konieczny if (variant == &exynos_aes_data) { 2176c2afad6cSKamil Konieczny res->end += 0x300; 2177c2afad6cSKamil Konieczny pdata->use_hash = true; 2178c2afad6cSKamil Konieczny } 2179c2afad6cSKamil Konieczny } 2180c2afad6cSKamil Konieczny 2181c2afad6cSKamil Konieczny pdata->res = res; 2182c2afad6cSKamil Konieczny pdata->ioaddr = devm_ioremap_resource(&pdev->dev, res); 2183c2afad6cSKamil Konieczny if (IS_ERR(pdata->ioaddr)) { 2184c2afad6cSKamil Konieczny if (!pdata->use_hash) 2185c2afad6cSKamil Konieczny return PTR_ERR(pdata->ioaddr); 2186c2afad6cSKamil Konieczny /* try AES without HASH */ 2187c2afad6cSKamil Konieczny res->end -= 0x300; 2188c2afad6cSKamil Konieczny pdata->use_hash = false; 21890fdefe2cSJingoo Han pdata->ioaddr = devm_ioremap_resource(&pdev->dev, res); 21900fdefe2cSJingoo Han if (IS_ERR(pdata->ioaddr)) 21910fdefe2cSJingoo Han return PTR_ERR(pdata->ioaddr); 2192c2afad6cSKamil Konieczny } 219389245107SNaveen Krishna Chatradhi 21945c22ba66SJingoo Han pdata->clk = devm_clk_get(dev, "secss"); 2195a49e490cSVladimir Zapolskiy if (IS_ERR(pdata->clk)) { 2196a49e490cSVladimir Zapolskiy dev_err(dev, "failed to find secss clock source\n"); 2197a49e490cSVladimir Zapolskiy return -ENOENT; 2198a49e490cSVladimir Zapolskiy } 2199a49e490cSVladimir Zapolskiy 2200c1eb7ef2SNaveen Krishna Chatradhi err = clk_prepare_enable(pdata->clk); 2201c1eb7ef2SNaveen Krishna Chatradhi if (err < 0) { 2202c1eb7ef2SNaveen Krishna Chatradhi dev_err(dev, "Enabling SSS clk failed, err %d\n", err); 2203c1eb7ef2SNaveen Krishna Chatradhi return err; 2204c1eb7ef2SNaveen Krishna Chatradhi } 2205a49e490cSVladimir Zapolskiy 2206a49e490cSVladimir Zapolskiy spin_lock_init(&pdata->lock); 2207c2afad6cSKamil Konieczny spin_lock_init(&pdata->hash_lock); 2208a49e490cSVladimir Zapolskiy 220989245107SNaveen Krishna Chatradhi pdata->aes_ioaddr = pdata->ioaddr + variant->aes_offset; 2210c2afad6cSKamil Konieczny pdata->io_hash_base = pdata->ioaddr + variant->hash_offset; 221189245107SNaveen Krishna Chatradhi 221296fc70b6SNaveen Krishna Chatradhi pdata->irq_fc = platform_get_irq(pdev, 0); 2213a49e490cSVladimir Zapolskiy if (pdata->irq_fc < 0) { 2214a49e490cSVladimir Zapolskiy err = pdata->irq_fc; 2215a49e490cSVladimir Zapolskiy dev_warn(dev, "feed control interrupt is not available.\n"); 2216a49e490cSVladimir Zapolskiy goto err_irq; 2217a49e490cSVladimir Zapolskiy } 221807de4bc8SKrzysztof Kozlowski err = devm_request_threaded_irq(dev, pdata->irq_fc, NULL, 221907de4bc8SKrzysztof Kozlowski s5p_aes_interrupt, IRQF_ONESHOT, 222007de4bc8SKrzysztof Kozlowski pdev->name, pdev); 2221a49e490cSVladimir Zapolskiy if (err < 0) { 2222a49e490cSVladimir Zapolskiy dev_warn(dev, "feed control interrupt is not available.\n"); 2223a49e490cSVladimir Zapolskiy goto err_irq; 2224a49e490cSVladimir Zapolskiy } 2225a49e490cSVladimir Zapolskiy 2226dc5e3f19SNaveen Krishna Chatradhi pdata->busy = false; 2227a49e490cSVladimir Zapolskiy pdata->dev = dev; 2228a49e490cSVladimir Zapolskiy platform_set_drvdata(pdev, pdata); 2229a49e490cSVladimir Zapolskiy s5p_dev = pdata; 2230a49e490cSVladimir Zapolskiy 2231a49e490cSVladimir Zapolskiy tasklet_init(&pdata->tasklet, s5p_tasklet_cb, (unsigned long)pdata); 2232a49e490cSVladimir Zapolskiy crypto_init_queue(&pdata->queue, CRYPTO_QUEUE_LEN); 2233a49e490cSVladimir Zapolskiy 2234a49e490cSVladimir Zapolskiy for (i = 0; i < ARRAY_SIZE(algs); i++) { 2235a49e490cSVladimir Zapolskiy err = crypto_register_alg(&algs[i]); 2236a49e490cSVladimir Zapolskiy if (err) 2237a49e490cSVladimir Zapolskiy goto err_algs; 2238a49e490cSVladimir Zapolskiy } 2239a49e490cSVladimir Zapolskiy 2240c2afad6cSKamil Konieczny if (pdata->use_hash) { 2241c2afad6cSKamil Konieczny tasklet_init(&pdata->hash_tasklet, s5p_hash_tasklet_cb, 2242c2afad6cSKamil Konieczny (unsigned long)pdata); 2243c2afad6cSKamil Konieczny crypto_init_queue(&pdata->hash_queue, SSS_HASH_QUEUE_LENGTH); 2244c2afad6cSKamil Konieczny 2245c2afad6cSKamil Konieczny for (hash_i = 0; hash_i < ARRAY_SIZE(algs_sha1_md5_sha256); 2246c2afad6cSKamil Konieczny hash_i++) { 2247c2afad6cSKamil Konieczny struct ahash_alg *alg; 2248c2afad6cSKamil Konieczny 2249c2afad6cSKamil Konieczny alg = &algs_sha1_md5_sha256[hash_i]; 2250c2afad6cSKamil Konieczny err = crypto_register_ahash(alg); 2251c2afad6cSKamil Konieczny if (err) { 2252c2afad6cSKamil Konieczny dev_err(dev, "can't register '%s': %d\n", 2253c2afad6cSKamil Konieczny alg->halg.base.cra_driver_name, err); 2254c2afad6cSKamil Konieczny goto err_hash; 2255c2afad6cSKamil Konieczny } 2256c2afad6cSKamil Konieczny } 2257c2afad6cSKamil Konieczny } 2258c2afad6cSKamil Konieczny 2259313becd1SKrzysztof Koz?owski dev_info(dev, "s5p-sss driver registered\n"); 2260a49e490cSVladimir Zapolskiy 2261a49e490cSVladimir Zapolskiy return 0; 2262a49e490cSVladimir Zapolskiy 2263c2afad6cSKamil Konieczny err_hash: 2264c2afad6cSKamil Konieczny for (j = hash_i - 1; j >= 0; j--) 2265c2afad6cSKamil Konieczny crypto_unregister_ahash(&algs_sha1_md5_sha256[j]); 2266c2afad6cSKamil Konieczny 2267c2afad6cSKamil Konieczny tasklet_kill(&pdata->hash_tasklet); 2268c2afad6cSKamil Konieczny res->end -= 0x300; 2269c2afad6cSKamil Konieczny 2270a49e490cSVladimir Zapolskiy err_algs: 2271c2afad6cSKamil Konieczny if (i < ARRAY_SIZE(algs)) 2272c2afad6cSKamil Konieczny dev_err(dev, "can't register '%s': %d\n", algs[i].cra_name, 2273c2afad6cSKamil Konieczny err); 2274a49e490cSVladimir Zapolskiy 2275a49e490cSVladimir Zapolskiy for (j = 0; j < i; j++) 2276a49e490cSVladimir Zapolskiy crypto_unregister_alg(&algs[j]); 2277a49e490cSVladimir Zapolskiy 2278a49e490cSVladimir Zapolskiy tasklet_kill(&pdata->tasklet); 2279a49e490cSVladimir Zapolskiy 2280a49e490cSVladimir Zapolskiy err_irq: 2281c1eb7ef2SNaveen Krishna Chatradhi clk_disable_unprepare(pdata->clk); 2282a49e490cSVladimir Zapolskiy 2283a49e490cSVladimir Zapolskiy s5p_dev = NULL; 2284a49e490cSVladimir Zapolskiy 2285a49e490cSVladimir Zapolskiy return err; 2286a49e490cSVladimir Zapolskiy } 2287a49e490cSVladimir Zapolskiy 2288a49e490cSVladimir Zapolskiy static int s5p_aes_remove(struct platform_device *pdev) 2289a49e490cSVladimir Zapolskiy { 2290a49e490cSVladimir Zapolskiy struct s5p_aes_dev *pdata = platform_get_drvdata(pdev); 2291a49e490cSVladimir Zapolskiy int i; 2292a49e490cSVladimir Zapolskiy 2293a49e490cSVladimir Zapolskiy if (!pdata) 2294a49e490cSVladimir Zapolskiy return -ENODEV; 2295a49e490cSVladimir Zapolskiy 2296a49e490cSVladimir Zapolskiy for (i = 0; i < ARRAY_SIZE(algs); i++) 2297a49e490cSVladimir Zapolskiy crypto_unregister_alg(&algs[i]); 2298a49e490cSVladimir Zapolskiy 2299a49e490cSVladimir Zapolskiy tasklet_kill(&pdata->tasklet); 2300c2afad6cSKamil Konieczny if (pdata->use_hash) { 2301c2afad6cSKamil Konieczny for (i = ARRAY_SIZE(algs_sha1_md5_sha256) - 1; i >= 0; i--) 2302c2afad6cSKamil Konieczny crypto_unregister_ahash(&algs_sha1_md5_sha256[i]); 2303c2afad6cSKamil Konieczny 2304c2afad6cSKamil Konieczny pdata->res->end -= 0x300; 2305c2afad6cSKamil Konieczny tasklet_kill(&pdata->hash_tasklet); 2306c2afad6cSKamil Konieczny pdata->use_hash = false; 2307c2afad6cSKamil Konieczny } 2308a49e490cSVladimir Zapolskiy 2309c1eb7ef2SNaveen Krishna Chatradhi clk_disable_unprepare(pdata->clk); 2310a49e490cSVladimir Zapolskiy s5p_dev = NULL; 2311a49e490cSVladimir Zapolskiy 2312a49e490cSVladimir Zapolskiy return 0; 2313a49e490cSVladimir Zapolskiy } 2314a49e490cSVladimir Zapolskiy 2315a49e490cSVladimir Zapolskiy static struct platform_driver s5p_aes_crypto = { 2316a49e490cSVladimir Zapolskiy .probe = s5p_aes_probe, 2317a49e490cSVladimir Zapolskiy .remove = s5p_aes_remove, 2318a49e490cSVladimir Zapolskiy .driver = { 2319a49e490cSVladimir Zapolskiy .name = "s5p-secss", 23206b9f16e6SNaveen Krishna Chatradhi .of_match_table = s5p_sss_dt_match, 2321a49e490cSVladimir Zapolskiy }, 2322a49e490cSVladimir Zapolskiy }; 2323a49e490cSVladimir Zapolskiy 2324741e8c2dSAxel Lin module_platform_driver(s5p_aes_crypto); 2325a49e490cSVladimir Zapolskiy 2326a49e490cSVladimir Zapolskiy MODULE_DESCRIPTION("S5PV210 AES hw acceleration support."); 2327a49e490cSVladimir Zapolskiy MODULE_LICENSE("GPL v2"); 2328a49e490cSVladimir Zapolskiy MODULE_AUTHOR("Vladimir Zapolskiy <vzapolskiy@gmail.com>"); 2329c2afad6cSKamil Konieczny MODULE_AUTHOR("Kamil Konieczny <k.konieczny@partner.samsung.com>"); 2330