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 252b1b4416fSChristoph Manszewski u8 aes_key[AES_MAX_KEY_SIZE]; 253b1b4416fSChristoph Manszewski u8 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 { 466*e8e3c1caSKamil Konieczny struct ablkcipher_request *req = dev->req; 467*e8e3c1caSKamil Konieczny struct s5p_aes_reqctx *reqctx = ablkcipher_request_ctx(req); 468*e8e3c1caSKamil Konieczny 4699e4a1100SKrzysztof Kozlowski if (dev->sg_dst_cpy) { 4709e4a1100SKrzysztof Kozlowski dev_dbg(dev->dev, 4719e4a1100SKrzysztof Kozlowski "Copying %d bytes of output data back to original place\n", 4729e4a1100SKrzysztof Kozlowski dev->req->nbytes); 4739e4a1100SKrzysztof Kozlowski s5p_sg_copy_buf(sg_virt(dev->sg_dst_cpy), dev->req->dst, 4749e4a1100SKrzysztof Kozlowski dev->req->nbytes, 1); 4759e4a1100SKrzysztof Kozlowski } 4769e4a1100SKrzysztof Kozlowski s5p_free_sg_cpy(dev, &dev->sg_src_cpy); 4779e4a1100SKrzysztof Kozlowski s5p_free_sg_cpy(dev, &dev->sg_dst_cpy); 478*e8e3c1caSKamil Konieczny if (reqctx->mode & FLAGS_AES_CBC) 479*e8e3c1caSKamil Konieczny memcpy_fromio(req->info, dev->aes_ioaddr + SSS_REG_AES_IV_DATA(0), AES_BLOCK_SIZE); 480*e8e3c1caSKamil Konieczny 481*e8e3c1caSKamil Konieczny else if (reqctx->mode & FLAGS_AES_CTR) 482*e8e3c1caSKamil Konieczny memcpy_fromio(req->info, dev->aes_ioaddr + SSS_REG_AES_CNT_DATA(0), AES_BLOCK_SIZE); 48328b62b14SKrzysztof Kozlowski } 4849e4a1100SKrzysztof Kozlowski 48528b62b14SKrzysztof Kozlowski /* Calls the completion. Cannot be called with dev->lock hold. */ 4865842cd44SChristoph Manszewski static void s5p_aes_complete(struct ablkcipher_request *req, int err) 48728b62b14SKrzysztof Kozlowski { 4885842cd44SChristoph Manszewski req->base.complete(&req->base, err); 489a49e490cSVladimir Zapolskiy } 490a49e490cSVladimir Zapolskiy 491a49e490cSVladimir Zapolskiy static void s5p_unset_outdata(struct s5p_aes_dev *dev) 492a49e490cSVladimir Zapolskiy { 493a49e490cSVladimir Zapolskiy dma_unmap_sg(dev->dev, dev->sg_dst, 1, DMA_FROM_DEVICE); 494a49e490cSVladimir Zapolskiy } 495a49e490cSVladimir Zapolskiy 496a49e490cSVladimir Zapolskiy static void s5p_unset_indata(struct s5p_aes_dev *dev) 497a49e490cSVladimir Zapolskiy { 498a49e490cSVladimir Zapolskiy dma_unmap_sg(dev->dev, dev->sg_src, 1, DMA_TO_DEVICE); 499a49e490cSVladimir Zapolskiy } 500a49e490cSVladimir Zapolskiy 5019e4a1100SKrzysztof Kozlowski static int s5p_make_sg_cpy(struct s5p_aes_dev *dev, struct scatterlist *src, 5029e4a1100SKrzysztof Kozlowski struct scatterlist **dst) 5039e4a1100SKrzysztof Kozlowski { 5049e4a1100SKrzysztof Kozlowski void *pages; 5059e4a1100SKrzysztof Kozlowski int len; 5069e4a1100SKrzysztof Kozlowski 5079e4a1100SKrzysztof Kozlowski *dst = kmalloc(sizeof(**dst), GFP_ATOMIC); 5089e4a1100SKrzysztof Kozlowski if (!*dst) 5099e4a1100SKrzysztof Kozlowski return -ENOMEM; 5109e4a1100SKrzysztof Kozlowski 5119e4a1100SKrzysztof Kozlowski len = ALIGN(dev->req->nbytes, AES_BLOCK_SIZE); 5129e4a1100SKrzysztof Kozlowski pages = (void *)__get_free_pages(GFP_ATOMIC, get_order(len)); 5139e4a1100SKrzysztof Kozlowski if (!pages) { 5149e4a1100SKrzysztof Kozlowski kfree(*dst); 5159e4a1100SKrzysztof Kozlowski *dst = NULL; 5169e4a1100SKrzysztof Kozlowski return -ENOMEM; 5179e4a1100SKrzysztof Kozlowski } 5189e4a1100SKrzysztof Kozlowski 5199e4a1100SKrzysztof Kozlowski s5p_sg_copy_buf(pages, src, dev->req->nbytes, 0); 5209e4a1100SKrzysztof Kozlowski 5219e4a1100SKrzysztof Kozlowski sg_init_table(*dst, 1); 5229e4a1100SKrzysztof Kozlowski sg_set_buf(*dst, pages, len); 5239e4a1100SKrzysztof Kozlowski 5249e4a1100SKrzysztof Kozlowski return 0; 5259e4a1100SKrzysztof Kozlowski } 5269e4a1100SKrzysztof Kozlowski 527a49e490cSVladimir Zapolskiy static int s5p_set_outdata(struct s5p_aes_dev *dev, struct scatterlist *sg) 528a49e490cSVladimir Zapolskiy { 529b1b4416fSChristoph Manszewski if (!sg->length) 530b1b4416fSChristoph Manszewski return -EINVAL; 531a49e490cSVladimir Zapolskiy 532b1b4416fSChristoph Manszewski if (!dma_map_sg(dev->dev, sg, 1, DMA_FROM_DEVICE)) 533b1b4416fSChristoph Manszewski return -ENOMEM; 534a49e490cSVladimir Zapolskiy 535a49e490cSVladimir Zapolskiy dev->sg_dst = sg; 536a49e490cSVladimir Zapolskiy 537b1b4416fSChristoph Manszewski return 0; 538a49e490cSVladimir Zapolskiy } 539a49e490cSVladimir Zapolskiy 540a49e490cSVladimir Zapolskiy static int s5p_set_indata(struct s5p_aes_dev *dev, struct scatterlist *sg) 541a49e490cSVladimir Zapolskiy { 542b1b4416fSChristoph Manszewski if (!sg->length) 543b1b4416fSChristoph Manszewski return -EINVAL; 544a49e490cSVladimir Zapolskiy 545b1b4416fSChristoph Manszewski if (!dma_map_sg(dev->dev, sg, 1, DMA_TO_DEVICE)) 546b1b4416fSChristoph Manszewski return -ENOMEM; 547a49e490cSVladimir Zapolskiy 548a49e490cSVladimir Zapolskiy dev->sg_src = sg; 549a49e490cSVladimir Zapolskiy 550b1b4416fSChristoph Manszewski return 0; 551a49e490cSVladimir Zapolskiy } 552a49e490cSVladimir Zapolskiy 55379152e8dSKrzysztof Kozlowski /* 55428b62b14SKrzysztof Kozlowski * Returns -ERRNO on error (mapping of new data failed). 55528b62b14SKrzysztof Kozlowski * On success returns: 55628b62b14SKrzysztof Kozlowski * - 0 if there is no more data, 55728b62b14SKrzysztof Kozlowski * - 1 if new transmitting (output) data is ready and its address+length 55828b62b14SKrzysztof Kozlowski * have to be written to device (by calling s5p_set_dma_outdata()). 55979152e8dSKrzysztof Kozlowski */ 56028b62b14SKrzysztof Kozlowski static int s5p_aes_tx(struct s5p_aes_dev *dev) 561a49e490cSVladimir Zapolskiy { 56228b62b14SKrzysztof Kozlowski int ret = 0; 563a49e490cSVladimir Zapolskiy 564a49e490cSVladimir Zapolskiy s5p_unset_outdata(dev); 565a49e490cSVladimir Zapolskiy 566a49e490cSVladimir Zapolskiy if (!sg_is_last(dev->sg_dst)) { 56728b62b14SKrzysztof Kozlowski ret = s5p_set_outdata(dev, sg_next(dev->sg_dst)); 56828b62b14SKrzysztof Kozlowski if (!ret) 56928b62b14SKrzysztof Kozlowski ret = 1; 570dc5e3f19SNaveen Krishna Chatradhi } 57179152e8dSKrzysztof Kozlowski 57279152e8dSKrzysztof Kozlowski return ret; 573a49e490cSVladimir Zapolskiy } 574a49e490cSVladimir Zapolskiy 57579152e8dSKrzysztof Kozlowski /* 57628b62b14SKrzysztof Kozlowski * Returns -ERRNO on error (mapping of new data failed). 57728b62b14SKrzysztof Kozlowski * On success returns: 57828b62b14SKrzysztof Kozlowski * - 0 if there is no more data, 57928b62b14SKrzysztof Kozlowski * - 1 if new receiving (input) data is ready and its address+length 58028b62b14SKrzysztof Kozlowski * have to be written to device (by calling s5p_set_dma_indata()). 58179152e8dSKrzysztof Kozlowski */ 58228b62b14SKrzysztof Kozlowski static int s5p_aes_rx(struct s5p_aes_dev *dev/*, bool *set_dma*/) 583a49e490cSVladimir Zapolskiy { 58428b62b14SKrzysztof Kozlowski int ret = 0; 585a49e490cSVladimir Zapolskiy 586a49e490cSVladimir Zapolskiy s5p_unset_indata(dev); 587a49e490cSVladimir Zapolskiy 588a49e490cSVladimir Zapolskiy if (!sg_is_last(dev->sg_src)) { 58928b62b14SKrzysztof Kozlowski ret = s5p_set_indata(dev, sg_next(dev->sg_src)); 59028b62b14SKrzysztof Kozlowski if (!ret) 59128b62b14SKrzysztof Kozlowski ret = 1; 592a49e490cSVladimir Zapolskiy } 593a49e490cSVladimir Zapolskiy 59479152e8dSKrzysztof Kozlowski return ret; 595a49e490cSVladimir Zapolskiy } 596a49e490cSVladimir Zapolskiy 597c2afad6cSKamil Konieczny static inline u32 s5p_hash_read(struct s5p_aes_dev *dd, u32 offset) 598c2afad6cSKamil Konieczny { 599c2afad6cSKamil Konieczny return __raw_readl(dd->io_hash_base + offset); 600c2afad6cSKamil Konieczny } 601c2afad6cSKamil Konieczny 602c2afad6cSKamil Konieczny static inline void s5p_hash_write(struct s5p_aes_dev *dd, 603c2afad6cSKamil Konieczny u32 offset, u32 value) 604c2afad6cSKamil Konieczny { 605c2afad6cSKamil Konieczny __raw_writel(value, dd->io_hash_base + offset); 606c2afad6cSKamil Konieczny } 607c2afad6cSKamil Konieczny 608c2afad6cSKamil Konieczny /** 609c2afad6cSKamil Konieczny * s5p_set_dma_hashdata() - start DMA with sg 610c2afad6cSKamil Konieczny * @dev: device 611c2afad6cSKamil Konieczny * @sg: scatterlist ready to DMA transmit 612c2afad6cSKamil Konieczny */ 613c2afad6cSKamil Konieczny static void s5p_set_dma_hashdata(struct s5p_aes_dev *dev, 6146584eacbSKrzysztof Kozlowski const struct scatterlist *sg) 615c2afad6cSKamil Konieczny { 616c2afad6cSKamil Konieczny dev->hash_sg_cnt--; 617c2afad6cSKamil Konieczny SSS_WRITE(dev, FCHRDMAS, sg_dma_address(sg)); 618c2afad6cSKamil Konieczny SSS_WRITE(dev, FCHRDMAL, sg_dma_len(sg)); /* DMA starts */ 619c2afad6cSKamil Konieczny } 620c2afad6cSKamil Konieczny 621c2afad6cSKamil Konieczny /** 622c2afad6cSKamil Konieczny * s5p_hash_rx() - get next hash_sg_iter 623c2afad6cSKamil Konieczny * @dev: device 624c2afad6cSKamil Konieczny * 625c2afad6cSKamil Konieczny * Return: 626c2afad6cSKamil Konieczny * 2 if there is no more data and it is UPDATE op 627c2afad6cSKamil Konieczny * 1 if new receiving (input) data is ready and can be written to device 628c2afad6cSKamil Konieczny * 0 if there is no more data and it is FINAL op 629c2afad6cSKamil Konieczny */ 630c2afad6cSKamil Konieczny static int s5p_hash_rx(struct s5p_aes_dev *dev) 631c2afad6cSKamil Konieczny { 632c2afad6cSKamil Konieczny if (dev->hash_sg_cnt > 0) { 633c2afad6cSKamil Konieczny dev->hash_sg_iter = sg_next(dev->hash_sg_iter); 634c2afad6cSKamil Konieczny return 1; 635c2afad6cSKamil Konieczny } 636c2afad6cSKamil Konieczny 637c2afad6cSKamil Konieczny set_bit(HASH_FLAGS_DMA_READY, &dev->hash_flags); 638c2afad6cSKamil Konieczny if (test_bit(HASH_FLAGS_FINAL, &dev->hash_flags)) 639c2afad6cSKamil Konieczny return 0; 640c2afad6cSKamil Konieczny 641c2afad6cSKamil Konieczny return 2; 642c2afad6cSKamil Konieczny } 643c2afad6cSKamil Konieczny 644a49e490cSVladimir Zapolskiy static irqreturn_t s5p_aes_interrupt(int irq, void *dev_id) 645a49e490cSVladimir Zapolskiy { 646a49e490cSVladimir Zapolskiy struct platform_device *pdev = dev_id; 647a49e490cSVladimir Zapolskiy struct s5p_aes_dev *dev = platform_get_drvdata(pdev); 6485842cd44SChristoph Manszewski struct ablkcipher_request *req; 64928b62b14SKrzysztof Kozlowski int err_dma_tx = 0; 65028b62b14SKrzysztof Kozlowski int err_dma_rx = 0; 651c2afad6cSKamil Konieczny int err_dma_hx = 0; 65228b62b14SKrzysztof Kozlowski bool tx_end = false; 653c2afad6cSKamil Konieczny bool hx_end = false; 6545318c53dSKrzysztof Kozlowski unsigned long flags; 655b1b4416fSChristoph Manszewski u32 status, st_bits; 65628b62b14SKrzysztof Kozlowski int err; 657a49e490cSVladimir Zapolskiy 658a49e490cSVladimir Zapolskiy spin_lock_irqsave(&dev->lock, flags); 659a49e490cSVladimir Zapolskiy 66028b62b14SKrzysztof Kozlowski /* 66128b62b14SKrzysztof Kozlowski * Handle rx or tx interrupt. If there is still data (scatterlist did not 66228b62b14SKrzysztof Kozlowski * reach end), then map next scatterlist entry. 66328b62b14SKrzysztof Kozlowski * In case of such mapping error, s5p_aes_complete() should be called. 66428b62b14SKrzysztof Kozlowski * 66528b62b14SKrzysztof Kozlowski * If there is no more data in tx scatter list, call s5p_aes_complete() 66628b62b14SKrzysztof Kozlowski * and schedule new tasklet. 667c2afad6cSKamil Konieczny * 668c2afad6cSKamil Konieczny * Handle hx interrupt. If there is still data map next entry. 66928b62b14SKrzysztof Kozlowski */ 670a49e490cSVladimir Zapolskiy status = SSS_READ(dev, FCINTSTAT); 671a49e490cSVladimir Zapolskiy if (status & SSS_FCINTSTAT_BRDMAINT) 67228b62b14SKrzysztof Kozlowski err_dma_rx = s5p_aes_rx(dev); 67328b62b14SKrzysztof Kozlowski 67428b62b14SKrzysztof Kozlowski if (status & SSS_FCINTSTAT_BTDMAINT) { 67528b62b14SKrzysztof Kozlowski if (sg_is_last(dev->sg_dst)) 67628b62b14SKrzysztof Kozlowski tx_end = true; 67728b62b14SKrzysztof Kozlowski err_dma_tx = s5p_aes_tx(dev); 67828b62b14SKrzysztof Kozlowski } 679a49e490cSVladimir Zapolskiy 680c2afad6cSKamil Konieczny if (status & SSS_FCINTSTAT_HRDMAINT) 681c2afad6cSKamil Konieczny err_dma_hx = s5p_hash_rx(dev); 682c2afad6cSKamil Konieczny 683c2afad6cSKamil Konieczny st_bits = status & (SSS_FCINTSTAT_BRDMAINT | SSS_FCINTSTAT_BTDMAINT | 684c2afad6cSKamil Konieczny SSS_FCINTSTAT_HRDMAINT); 685c2afad6cSKamil Konieczny /* clear DMA bits */ 686c2afad6cSKamil Konieczny SSS_WRITE(dev, FCINTPEND, st_bits); 687c2afad6cSKamil Konieczny 688c2afad6cSKamil Konieczny /* clear HASH irq bits */ 689c2afad6cSKamil Konieczny if (status & (SSS_FCINTSTAT_HDONEINT | SSS_FCINTSTAT_HPARTINT)) { 690c2afad6cSKamil Konieczny /* cannot have both HPART and HDONE */ 691c2afad6cSKamil Konieczny if (status & SSS_FCINTSTAT_HPARTINT) 692c2afad6cSKamil Konieczny st_bits = SSS_HASH_STATUS_PARTIAL_DONE; 693c2afad6cSKamil Konieczny 694c2afad6cSKamil Konieczny if (status & SSS_FCINTSTAT_HDONEINT) 695c2afad6cSKamil Konieczny st_bits = SSS_HASH_STATUS_MSG_DONE; 696c2afad6cSKamil Konieczny 697c2afad6cSKamil Konieczny set_bit(HASH_FLAGS_OUTPUT_READY, &dev->hash_flags); 698c2afad6cSKamil Konieczny s5p_hash_write(dev, SSS_REG_HASH_STATUS, st_bits); 699c2afad6cSKamil Konieczny hx_end = true; 700c2afad6cSKamil Konieczny /* when DONE or PART, do not handle HASH DMA */ 701c2afad6cSKamil Konieczny err_dma_hx = 0; 702c2afad6cSKamil Konieczny } 703a49e490cSVladimir Zapolskiy 70428b62b14SKrzysztof Kozlowski if (err_dma_rx < 0) { 70528b62b14SKrzysztof Kozlowski err = err_dma_rx; 70628b62b14SKrzysztof Kozlowski goto error; 70728b62b14SKrzysztof Kozlowski } 70828b62b14SKrzysztof Kozlowski if (err_dma_tx < 0) { 70928b62b14SKrzysztof Kozlowski err = err_dma_tx; 71028b62b14SKrzysztof Kozlowski goto error; 71128b62b14SKrzysztof Kozlowski } 71228b62b14SKrzysztof Kozlowski 71328b62b14SKrzysztof Kozlowski if (tx_end) { 71428b62b14SKrzysztof Kozlowski s5p_sg_done(dev); 715c2afad6cSKamil Konieczny if (err_dma_hx == 1) 716c2afad6cSKamil Konieczny s5p_set_dma_hashdata(dev, dev->hash_sg_iter); 71728b62b14SKrzysztof Kozlowski 71828b62b14SKrzysztof Kozlowski spin_unlock_irqrestore(&dev->lock, flags); 71928b62b14SKrzysztof Kozlowski 7205842cd44SChristoph Manszewski s5p_aes_complete(dev->req, 0); 72142d5c176SKrzysztof Kozlowski /* Device is still busy */ 72228b62b14SKrzysztof Kozlowski tasklet_schedule(&dev->tasklet); 72328b62b14SKrzysztof Kozlowski } else { 72479152e8dSKrzysztof Kozlowski /* 72528b62b14SKrzysztof Kozlowski * Writing length of DMA block (either receiving or 72628b62b14SKrzysztof Kozlowski * transmitting) will start the operation immediately, so this 72728b62b14SKrzysztof Kozlowski * should be done at the end (even after clearing pending 72828b62b14SKrzysztof Kozlowski * interrupts to not miss the interrupt). 72979152e8dSKrzysztof Kozlowski */ 73028b62b14SKrzysztof Kozlowski if (err_dma_tx == 1) 73179152e8dSKrzysztof Kozlowski s5p_set_dma_outdata(dev, dev->sg_dst); 73228b62b14SKrzysztof Kozlowski if (err_dma_rx == 1) 73379152e8dSKrzysztof Kozlowski s5p_set_dma_indata(dev, dev->sg_src); 734c2afad6cSKamil Konieczny if (err_dma_hx == 1) 735c2afad6cSKamil Konieczny s5p_set_dma_hashdata(dev, dev->hash_sg_iter); 73679152e8dSKrzysztof Kozlowski 737a49e490cSVladimir Zapolskiy spin_unlock_irqrestore(&dev->lock, flags); 73828b62b14SKrzysztof Kozlowski } 73928b62b14SKrzysztof Kozlowski 740c2afad6cSKamil Konieczny goto hash_irq_end; 74128b62b14SKrzysztof Kozlowski 74228b62b14SKrzysztof Kozlowski error: 74328b62b14SKrzysztof Kozlowski s5p_sg_done(dev); 74442d5c176SKrzysztof Kozlowski dev->busy = false; 7455842cd44SChristoph Manszewski req = dev->req; 746c2afad6cSKamil Konieczny if (err_dma_hx == 1) 747c2afad6cSKamil Konieczny s5p_set_dma_hashdata(dev, dev->hash_sg_iter); 748c2afad6cSKamil Konieczny 74928b62b14SKrzysztof Kozlowski spin_unlock_irqrestore(&dev->lock, flags); 7505842cd44SChristoph Manszewski s5p_aes_complete(req, err); 751a49e490cSVladimir Zapolskiy 752c2afad6cSKamil Konieczny hash_irq_end: 753c2afad6cSKamil Konieczny /* 754c2afad6cSKamil Konieczny * Note about else if: 755c2afad6cSKamil Konieczny * when hash_sg_iter reaches end and its UPDATE op, 756c2afad6cSKamil Konieczny * issue SSS_HASH_PAUSE and wait for HPART irq 757c2afad6cSKamil Konieczny */ 758c2afad6cSKamil Konieczny if (hx_end) 759c2afad6cSKamil Konieczny tasklet_schedule(&dev->hash_tasklet); 760c2afad6cSKamil Konieczny else if (err_dma_hx == 2) 761c2afad6cSKamil Konieczny s5p_hash_write(dev, SSS_REG_HASH_CTRL_PAUSE, 762c2afad6cSKamil Konieczny SSS_HASH_PAUSE); 763c2afad6cSKamil Konieczny 764a49e490cSVladimir Zapolskiy return IRQ_HANDLED; 765a49e490cSVladimir Zapolskiy } 766a49e490cSVladimir Zapolskiy 767c2afad6cSKamil Konieczny /** 768c2afad6cSKamil Konieczny * s5p_hash_read_msg() - read message or IV from HW 769c2afad6cSKamil Konieczny * @req: AHASH request 770c2afad6cSKamil Konieczny */ 771c2afad6cSKamil Konieczny static void s5p_hash_read_msg(struct ahash_request *req) 772c2afad6cSKamil Konieczny { 773c2afad6cSKamil Konieczny struct s5p_hash_reqctx *ctx = ahash_request_ctx(req); 774c2afad6cSKamil Konieczny struct s5p_aes_dev *dd = ctx->dd; 775c2afad6cSKamil Konieczny u32 *hash = (u32 *)ctx->digest; 776c2afad6cSKamil Konieczny unsigned int i; 777c2afad6cSKamil Konieczny 778c2afad6cSKamil Konieczny for (i = 0; i < ctx->nregs; i++) 779c2afad6cSKamil Konieczny hash[i] = s5p_hash_read(dd, SSS_REG_HASH_OUT(i)); 780c2afad6cSKamil Konieczny } 781c2afad6cSKamil Konieczny 782c2afad6cSKamil Konieczny /** 783c2afad6cSKamil Konieczny * s5p_hash_write_ctx_iv() - write IV for next partial/finup op. 784c2afad6cSKamil Konieczny * @dd: device 785c2afad6cSKamil Konieczny * @ctx: request context 786c2afad6cSKamil Konieczny */ 787c2afad6cSKamil Konieczny static void s5p_hash_write_ctx_iv(struct s5p_aes_dev *dd, 7886584eacbSKrzysztof Kozlowski const struct s5p_hash_reqctx *ctx) 789c2afad6cSKamil Konieczny { 7906584eacbSKrzysztof Kozlowski const u32 *hash = (const u32 *)ctx->digest; 791c2afad6cSKamil Konieczny unsigned int i; 792c2afad6cSKamil Konieczny 793c2afad6cSKamil Konieczny for (i = 0; i < ctx->nregs; i++) 794c2afad6cSKamil Konieczny s5p_hash_write(dd, SSS_REG_HASH_IV(i), hash[i]); 795c2afad6cSKamil Konieczny } 796c2afad6cSKamil Konieczny 797c2afad6cSKamil Konieczny /** 798c2afad6cSKamil Konieczny * s5p_hash_write_iv() - write IV for next partial/finup op. 799c2afad6cSKamil Konieczny * @req: AHASH request 800c2afad6cSKamil Konieczny */ 801c2afad6cSKamil Konieczny static void s5p_hash_write_iv(struct ahash_request *req) 802c2afad6cSKamil Konieczny { 803c2afad6cSKamil Konieczny struct s5p_hash_reqctx *ctx = ahash_request_ctx(req); 804c2afad6cSKamil Konieczny 805c2afad6cSKamil Konieczny s5p_hash_write_ctx_iv(ctx->dd, ctx); 806c2afad6cSKamil Konieczny } 807c2afad6cSKamil Konieczny 808c2afad6cSKamil Konieczny /** 809c2afad6cSKamil Konieczny * s5p_hash_copy_result() - copy digest into req->result 810c2afad6cSKamil Konieczny * @req: AHASH request 811c2afad6cSKamil Konieczny */ 812c2afad6cSKamil Konieczny static void s5p_hash_copy_result(struct ahash_request *req) 813c2afad6cSKamil Konieczny { 8146584eacbSKrzysztof Kozlowski const struct s5p_hash_reqctx *ctx = ahash_request_ctx(req); 815c2afad6cSKamil Konieczny 816c2afad6cSKamil Konieczny if (!req->result) 817c2afad6cSKamil Konieczny return; 818c2afad6cSKamil Konieczny 819c2afad6cSKamil Konieczny memcpy(req->result, ctx->digest, ctx->nregs * HASH_REG_SIZEOF); 820c2afad6cSKamil Konieczny } 821c2afad6cSKamil Konieczny 822c2afad6cSKamil Konieczny /** 823c2afad6cSKamil Konieczny * s5p_hash_dma_flush() - flush HASH DMA 824c2afad6cSKamil Konieczny * @dev: secss device 825c2afad6cSKamil Konieczny */ 826c2afad6cSKamil Konieczny static void s5p_hash_dma_flush(struct s5p_aes_dev *dev) 827c2afad6cSKamil Konieczny { 828c2afad6cSKamil Konieczny SSS_WRITE(dev, FCHRDMAC, SSS_FCHRDMAC_FLUSH); 829c2afad6cSKamil Konieczny } 830c2afad6cSKamil Konieczny 831c2afad6cSKamil Konieczny /** 832c2afad6cSKamil Konieczny * s5p_hash_dma_enable() - enable DMA mode for HASH 833c2afad6cSKamil Konieczny * @dev: secss device 834c2afad6cSKamil Konieczny * 835c2afad6cSKamil Konieczny * enable DMA mode for HASH 836c2afad6cSKamil Konieczny */ 837c2afad6cSKamil Konieczny static void s5p_hash_dma_enable(struct s5p_aes_dev *dev) 838c2afad6cSKamil Konieczny { 839c2afad6cSKamil Konieczny s5p_hash_write(dev, SSS_REG_HASH_CTRL_FIFO, SSS_HASH_FIFO_MODE_DMA); 840c2afad6cSKamil Konieczny } 841c2afad6cSKamil Konieczny 842c2afad6cSKamil Konieczny /** 843c2afad6cSKamil Konieczny * s5p_hash_irq_disable() - disable irq HASH signals 844c2afad6cSKamil Konieczny * @dev: secss device 845c2afad6cSKamil Konieczny * @flags: bitfield with irq's to be disabled 846c2afad6cSKamil Konieczny */ 847c2afad6cSKamil Konieczny static void s5p_hash_irq_disable(struct s5p_aes_dev *dev, u32 flags) 848c2afad6cSKamil Konieczny { 849c2afad6cSKamil Konieczny SSS_WRITE(dev, FCINTENCLR, flags); 850c2afad6cSKamil Konieczny } 851c2afad6cSKamil Konieczny 852c2afad6cSKamil Konieczny /** 853c2afad6cSKamil Konieczny * s5p_hash_irq_enable() - enable irq signals 854c2afad6cSKamil Konieczny * @dev: secss device 855c2afad6cSKamil Konieczny * @flags: bitfield with irq's to be enabled 856c2afad6cSKamil Konieczny */ 857c2afad6cSKamil Konieczny static void s5p_hash_irq_enable(struct s5p_aes_dev *dev, int flags) 858c2afad6cSKamil Konieczny { 859c2afad6cSKamil Konieczny SSS_WRITE(dev, FCINTENSET, flags); 860c2afad6cSKamil Konieczny } 861c2afad6cSKamil Konieczny 862c2afad6cSKamil Konieczny /** 863c2afad6cSKamil Konieczny * s5p_hash_set_flow() - set flow inside SecSS AES/DES with/without HASH 864c2afad6cSKamil Konieczny * @dev: secss device 865c2afad6cSKamil Konieczny * @hashflow: HASH stream flow with/without crypto AES/DES 866c2afad6cSKamil Konieczny */ 867c2afad6cSKamil Konieczny static void s5p_hash_set_flow(struct s5p_aes_dev *dev, u32 hashflow) 868c2afad6cSKamil Konieczny { 869c2afad6cSKamil Konieczny unsigned long flags; 870c2afad6cSKamil Konieczny u32 flow; 871c2afad6cSKamil Konieczny 872c2afad6cSKamil Konieczny spin_lock_irqsave(&dev->lock, flags); 873c2afad6cSKamil Konieczny 874c2afad6cSKamil Konieczny flow = SSS_READ(dev, FCFIFOCTRL); 875c2afad6cSKamil Konieczny flow &= ~SSS_HASHIN_MASK; 876c2afad6cSKamil Konieczny flow |= hashflow; 877c2afad6cSKamil Konieczny SSS_WRITE(dev, FCFIFOCTRL, flow); 878c2afad6cSKamil Konieczny 879c2afad6cSKamil Konieczny spin_unlock_irqrestore(&dev->lock, flags); 880c2afad6cSKamil Konieczny } 881c2afad6cSKamil Konieczny 882c2afad6cSKamil Konieczny /** 883c2afad6cSKamil Konieczny * s5p_ahash_dma_init() - enable DMA and set HASH flow inside SecSS 884c2afad6cSKamil Konieczny * @dev: secss device 885c2afad6cSKamil Konieczny * @hashflow: HASH stream flow with/without AES/DES 886c2afad6cSKamil Konieczny * 887c2afad6cSKamil Konieczny * flush HASH DMA and enable DMA, set HASH stream flow inside SecSS HW, 888c2afad6cSKamil Konieczny * enable HASH irq's HRDMA, HDONE, HPART 889c2afad6cSKamil Konieczny */ 890c2afad6cSKamil Konieczny static void s5p_ahash_dma_init(struct s5p_aes_dev *dev, u32 hashflow) 891c2afad6cSKamil Konieczny { 892c2afad6cSKamil Konieczny s5p_hash_irq_disable(dev, SSS_FCINTENCLR_HRDMAINTENCLR | 893c2afad6cSKamil Konieczny SSS_FCINTENCLR_HDONEINTENCLR | 894c2afad6cSKamil Konieczny SSS_FCINTENCLR_HPARTINTENCLR); 895c2afad6cSKamil Konieczny s5p_hash_dma_flush(dev); 896c2afad6cSKamil Konieczny 897c2afad6cSKamil Konieczny s5p_hash_dma_enable(dev); 898c2afad6cSKamil Konieczny s5p_hash_set_flow(dev, hashflow & SSS_HASHIN_MASK); 899c2afad6cSKamil Konieczny s5p_hash_irq_enable(dev, SSS_FCINTENSET_HRDMAINTENSET | 900c2afad6cSKamil Konieczny SSS_FCINTENSET_HDONEINTENSET | 901c2afad6cSKamil Konieczny SSS_FCINTENSET_HPARTINTENSET); 902c2afad6cSKamil Konieczny } 903c2afad6cSKamil Konieczny 904c2afad6cSKamil Konieczny /** 905c2afad6cSKamil Konieczny * s5p_hash_write_ctrl() - prepare HASH block in SecSS for processing 906c2afad6cSKamil Konieczny * @dd: secss device 907c2afad6cSKamil Konieczny * @length: length for request 908c2afad6cSKamil Konieczny * @final: true if final op 909c2afad6cSKamil Konieczny * 910c2afad6cSKamil Konieczny * Prepare SSS HASH block for processing bytes in DMA mode. If it is called 911c2afad6cSKamil Konieczny * after previous updates, fill up IV words. For final, calculate and set 912c2afad6cSKamil Konieczny * lengths for HASH so SecSS can finalize hash. For partial, set SSS HASH 913c2afad6cSKamil Konieczny * length as 2^63 so it will be never reached and set to zero prelow and 914c2afad6cSKamil Konieczny * prehigh. 915c2afad6cSKamil Konieczny * 916c2afad6cSKamil Konieczny * This function does not start DMA transfer. 917c2afad6cSKamil Konieczny */ 918c2afad6cSKamil Konieczny static void s5p_hash_write_ctrl(struct s5p_aes_dev *dd, size_t length, 919c2afad6cSKamil Konieczny bool final) 920c2afad6cSKamil Konieczny { 921c2afad6cSKamil Konieczny struct s5p_hash_reqctx *ctx = ahash_request_ctx(dd->hash_req); 922c2afad6cSKamil Konieczny u32 prelow, prehigh, low, high; 923c2afad6cSKamil Konieczny u32 configflags, swapflags; 924c2afad6cSKamil Konieczny u64 tmplen; 925c2afad6cSKamil Konieczny 926c2afad6cSKamil Konieczny configflags = ctx->engine | SSS_HASH_INIT_BIT; 927c2afad6cSKamil Konieczny 928c2afad6cSKamil Konieczny if (likely(ctx->digcnt)) { 929c2afad6cSKamil Konieczny s5p_hash_write_ctx_iv(dd, ctx); 930c2afad6cSKamil Konieczny configflags |= SSS_HASH_USER_IV_EN; 931c2afad6cSKamil Konieczny } 932c2afad6cSKamil Konieczny 933c2afad6cSKamil Konieczny if (final) { 934c2afad6cSKamil Konieczny /* number of bytes for last part */ 935c2afad6cSKamil Konieczny low = length; 936c2afad6cSKamil Konieczny high = 0; 937c2afad6cSKamil Konieczny /* total number of bits prev hashed */ 938c2afad6cSKamil Konieczny tmplen = ctx->digcnt * 8; 939c2afad6cSKamil Konieczny prelow = (u32)tmplen; 940c2afad6cSKamil Konieczny prehigh = (u32)(tmplen >> 32); 941c2afad6cSKamil Konieczny } else { 942c2afad6cSKamil Konieczny prelow = 0; 943c2afad6cSKamil Konieczny prehigh = 0; 944c2afad6cSKamil Konieczny low = 0; 945c2afad6cSKamil Konieczny high = BIT(31); 946c2afad6cSKamil Konieczny } 947c2afad6cSKamil Konieczny 948c2afad6cSKamil Konieczny swapflags = SSS_HASH_BYTESWAP_DI | SSS_HASH_BYTESWAP_DO | 949c2afad6cSKamil Konieczny SSS_HASH_BYTESWAP_IV | SSS_HASH_BYTESWAP_KEY; 950c2afad6cSKamil Konieczny 951c2afad6cSKamil Konieczny s5p_hash_write(dd, SSS_REG_HASH_MSG_SIZE_LOW, low); 952c2afad6cSKamil Konieczny s5p_hash_write(dd, SSS_REG_HASH_MSG_SIZE_HIGH, high); 953c2afad6cSKamil Konieczny s5p_hash_write(dd, SSS_REG_HASH_PRE_MSG_SIZE_LOW, prelow); 954c2afad6cSKamil Konieczny s5p_hash_write(dd, SSS_REG_HASH_PRE_MSG_SIZE_HIGH, prehigh); 955c2afad6cSKamil Konieczny 956c2afad6cSKamil Konieczny s5p_hash_write(dd, SSS_REG_HASH_CTRL_SWAP, swapflags); 957c2afad6cSKamil Konieczny s5p_hash_write(dd, SSS_REG_HASH_CTRL, configflags); 958c2afad6cSKamil Konieczny } 959c2afad6cSKamil Konieczny 960c2afad6cSKamil Konieczny /** 961c2afad6cSKamil Konieczny * s5p_hash_xmit_dma() - start DMA hash processing 962c2afad6cSKamil Konieczny * @dd: secss device 963c2afad6cSKamil Konieczny * @length: length for request 964c2afad6cSKamil Konieczny * @final: true if final op 965c2afad6cSKamil Konieczny * 966c2afad6cSKamil Konieczny * Update digcnt here, as it is needed for finup/final op. 967c2afad6cSKamil Konieczny */ 968c2afad6cSKamil Konieczny static int s5p_hash_xmit_dma(struct s5p_aes_dev *dd, size_t length, 969c2afad6cSKamil Konieczny bool final) 970c2afad6cSKamil Konieczny { 971c2afad6cSKamil Konieczny struct s5p_hash_reqctx *ctx = ahash_request_ctx(dd->hash_req); 972c2afad6cSKamil Konieczny unsigned int cnt; 973c2afad6cSKamil Konieczny 974c2afad6cSKamil Konieczny cnt = dma_map_sg(dd->dev, ctx->sg, ctx->sg_len, DMA_TO_DEVICE); 975c2afad6cSKamil Konieczny if (!cnt) { 976c2afad6cSKamil Konieczny dev_err(dd->dev, "dma_map_sg error\n"); 977c2afad6cSKamil Konieczny ctx->error = true; 978c2afad6cSKamil Konieczny return -EINVAL; 979c2afad6cSKamil Konieczny } 980c2afad6cSKamil Konieczny 981c2afad6cSKamil Konieczny set_bit(HASH_FLAGS_DMA_ACTIVE, &dd->hash_flags); 982c2afad6cSKamil Konieczny dd->hash_sg_iter = ctx->sg; 983c2afad6cSKamil Konieczny dd->hash_sg_cnt = cnt; 984c2afad6cSKamil Konieczny s5p_hash_write_ctrl(dd, length, final); 985c2afad6cSKamil Konieczny ctx->digcnt += length; 986c2afad6cSKamil Konieczny ctx->total -= length; 987c2afad6cSKamil Konieczny 988c2afad6cSKamil Konieczny /* catch last interrupt */ 989c2afad6cSKamil Konieczny if (final) 990c2afad6cSKamil Konieczny set_bit(HASH_FLAGS_FINAL, &dd->hash_flags); 991c2afad6cSKamil Konieczny 992c2afad6cSKamil Konieczny s5p_set_dma_hashdata(dd, dd->hash_sg_iter); /* DMA starts */ 993c2afad6cSKamil Konieczny 994c2afad6cSKamil Konieczny return -EINPROGRESS; 995c2afad6cSKamil Konieczny } 996c2afad6cSKamil Konieczny 997c2afad6cSKamil Konieczny /** 998c2afad6cSKamil Konieczny * s5p_hash_copy_sgs() - copy request's bytes into new buffer 999c2afad6cSKamil Konieczny * @ctx: request context 1000c2afad6cSKamil Konieczny * @sg: source scatterlist request 1001c2afad6cSKamil Konieczny * @new_len: number of bytes to process from sg 1002c2afad6cSKamil Konieczny * 1003c2afad6cSKamil Konieczny * Allocate new buffer, copy data for HASH into it. If there was xmit_buf 1004c2afad6cSKamil Konieczny * filled, copy it first, then copy data from sg into it. Prepare one sgl[0] 1005c2afad6cSKamil Konieczny * with allocated buffer. 1006c2afad6cSKamil Konieczny * 1007c2afad6cSKamil Konieczny * Set bit in dd->hash_flag so we can free it after irq ends processing. 1008c2afad6cSKamil Konieczny */ 1009c2afad6cSKamil Konieczny static int s5p_hash_copy_sgs(struct s5p_hash_reqctx *ctx, 1010c2afad6cSKamil Konieczny struct scatterlist *sg, unsigned int new_len) 1011c2afad6cSKamil Konieczny { 1012c2afad6cSKamil Konieczny unsigned int pages, len; 1013c2afad6cSKamil Konieczny void *buf; 1014c2afad6cSKamil Konieczny 1015c2afad6cSKamil Konieczny len = new_len + ctx->bufcnt; 1016c2afad6cSKamil Konieczny pages = get_order(len); 1017c2afad6cSKamil Konieczny 1018c2afad6cSKamil Konieczny buf = (void *)__get_free_pages(GFP_ATOMIC, pages); 1019c2afad6cSKamil Konieczny if (!buf) { 1020c2afad6cSKamil Konieczny dev_err(ctx->dd->dev, "alloc pages for unaligned case.\n"); 1021c2afad6cSKamil Konieczny ctx->error = true; 1022c2afad6cSKamil Konieczny return -ENOMEM; 1023c2afad6cSKamil Konieczny } 1024c2afad6cSKamil Konieczny 1025c2afad6cSKamil Konieczny if (ctx->bufcnt) 1026c2afad6cSKamil Konieczny memcpy(buf, ctx->dd->xmit_buf, ctx->bufcnt); 1027c2afad6cSKamil Konieczny 1028c2afad6cSKamil Konieczny scatterwalk_map_and_copy(buf + ctx->bufcnt, sg, ctx->skip, 1029c2afad6cSKamil Konieczny new_len, 0); 1030c2afad6cSKamil Konieczny sg_init_table(ctx->sgl, 1); 1031c2afad6cSKamil Konieczny sg_set_buf(ctx->sgl, buf, len); 1032c2afad6cSKamil Konieczny ctx->sg = ctx->sgl; 1033c2afad6cSKamil Konieczny ctx->sg_len = 1; 1034c2afad6cSKamil Konieczny ctx->bufcnt = 0; 1035c2afad6cSKamil Konieczny ctx->skip = 0; 1036c2afad6cSKamil Konieczny set_bit(HASH_FLAGS_SGS_COPIED, &ctx->dd->hash_flags); 1037c2afad6cSKamil Konieczny 1038c2afad6cSKamil Konieczny return 0; 1039c2afad6cSKamil Konieczny } 1040c2afad6cSKamil Konieczny 1041c2afad6cSKamil Konieczny /** 1042c2afad6cSKamil Konieczny * s5p_hash_copy_sg_lists() - copy sg list and make fixes in copy 1043c2afad6cSKamil Konieczny * @ctx: request context 1044c2afad6cSKamil Konieczny * @sg: source scatterlist request 1045c2afad6cSKamil Konieczny * @new_len: number of bytes to process from sg 1046c2afad6cSKamil Konieczny * 1047c2afad6cSKamil Konieczny * Allocate new scatterlist table, copy data for HASH into it. If there was 1048c2afad6cSKamil Konieczny * xmit_buf filled, prepare it first, then copy page, length and offset from 1049c2afad6cSKamil Konieczny * source sg into it, adjusting begin and/or end for skip offset and 1050c2afad6cSKamil Konieczny * hash_later value. 1051c2afad6cSKamil Konieczny * 1052c2afad6cSKamil Konieczny * Resulting sg table will be assigned to ctx->sg. Set flag so we can free 1053c2afad6cSKamil Konieczny * it after irq ends processing. 1054c2afad6cSKamil Konieczny */ 1055c2afad6cSKamil Konieczny static int s5p_hash_copy_sg_lists(struct s5p_hash_reqctx *ctx, 1056c2afad6cSKamil Konieczny struct scatterlist *sg, unsigned int new_len) 1057c2afad6cSKamil Konieczny { 1058c2afad6cSKamil Konieczny unsigned int skip = ctx->skip, n = sg_nents(sg); 1059c2afad6cSKamil Konieczny struct scatterlist *tmp; 1060c2afad6cSKamil Konieczny unsigned int len; 1061c2afad6cSKamil Konieczny 1062c2afad6cSKamil Konieczny if (ctx->bufcnt) 1063c2afad6cSKamil Konieczny n++; 1064c2afad6cSKamil Konieczny 1065c2afad6cSKamil Konieczny ctx->sg = kmalloc_array(n, sizeof(*sg), GFP_KERNEL); 1066c2afad6cSKamil Konieczny if (!ctx->sg) { 1067c2afad6cSKamil Konieczny ctx->error = true; 1068c2afad6cSKamil Konieczny return -ENOMEM; 1069c2afad6cSKamil Konieczny } 1070c2afad6cSKamil Konieczny 1071c2afad6cSKamil Konieczny sg_init_table(ctx->sg, n); 1072c2afad6cSKamil Konieczny 1073c2afad6cSKamil Konieczny tmp = ctx->sg; 1074c2afad6cSKamil Konieczny 1075c2afad6cSKamil Konieczny ctx->sg_len = 0; 1076c2afad6cSKamil Konieczny 1077c2afad6cSKamil Konieczny if (ctx->bufcnt) { 1078c2afad6cSKamil Konieczny sg_set_buf(tmp, ctx->dd->xmit_buf, ctx->bufcnt); 1079c2afad6cSKamil Konieczny tmp = sg_next(tmp); 1080c2afad6cSKamil Konieczny ctx->sg_len++; 1081c2afad6cSKamil Konieczny } 1082c2afad6cSKamil Konieczny 1083c2afad6cSKamil Konieczny while (sg && skip >= sg->length) { 1084c2afad6cSKamil Konieczny skip -= sg->length; 1085c2afad6cSKamil Konieczny sg = sg_next(sg); 1086c2afad6cSKamil Konieczny } 1087c2afad6cSKamil Konieczny 1088c2afad6cSKamil Konieczny while (sg && new_len) { 1089c2afad6cSKamil Konieczny len = sg->length - skip; 1090c2afad6cSKamil Konieczny if (new_len < len) 1091c2afad6cSKamil Konieczny len = new_len; 1092c2afad6cSKamil Konieczny 1093c2afad6cSKamil Konieczny new_len -= len; 1094c2afad6cSKamil Konieczny sg_set_page(tmp, sg_page(sg), len, sg->offset + skip); 1095c2afad6cSKamil Konieczny skip = 0; 1096c2afad6cSKamil Konieczny if (new_len <= 0) 1097c2afad6cSKamil Konieczny sg_mark_end(tmp); 1098c2afad6cSKamil Konieczny 1099c2afad6cSKamil Konieczny tmp = sg_next(tmp); 1100c2afad6cSKamil Konieczny ctx->sg_len++; 1101c2afad6cSKamil Konieczny sg = sg_next(sg); 1102c2afad6cSKamil Konieczny } 1103c2afad6cSKamil Konieczny 1104c2afad6cSKamil Konieczny set_bit(HASH_FLAGS_SGS_ALLOCED, &ctx->dd->hash_flags); 1105c2afad6cSKamil Konieczny 1106c2afad6cSKamil Konieczny return 0; 1107c2afad6cSKamil Konieczny } 1108c2afad6cSKamil Konieczny 1109c2afad6cSKamil Konieczny /** 1110c2afad6cSKamil Konieczny * s5p_hash_prepare_sgs() - prepare sg for processing 1111c2afad6cSKamil Konieczny * @ctx: request context 1112c2afad6cSKamil Konieczny * @sg: source scatterlist request 1113c2afad6cSKamil Konieczny * @nbytes: number of bytes to process from sg 1114c2afad6cSKamil Konieczny * @final: final flag 1115c2afad6cSKamil Konieczny * 1116c2afad6cSKamil Konieczny * Check two conditions: (1) if buffers in sg have len aligned data, and (2) 1117c2afad6cSKamil Konieczny * sg table have good aligned elements (list_ok). If one of this checks fails, 1118c2afad6cSKamil Konieczny * then either (1) allocates new buffer for data with s5p_hash_copy_sgs, copy 1119c2afad6cSKamil Konieczny * data into this buffer and prepare request in sgl, or (2) allocates new sg 1120c2afad6cSKamil Konieczny * table and prepare sg elements. 1121c2afad6cSKamil Konieczny * 1122c2afad6cSKamil Konieczny * For digest or finup all conditions can be good, and we may not need any 1123c2afad6cSKamil Konieczny * fixes. 1124c2afad6cSKamil Konieczny */ 1125c2afad6cSKamil Konieczny static int s5p_hash_prepare_sgs(struct s5p_hash_reqctx *ctx, 1126c2afad6cSKamil Konieczny struct scatterlist *sg, 1127c2afad6cSKamil Konieczny unsigned int new_len, bool final) 1128c2afad6cSKamil Konieczny { 1129c2afad6cSKamil Konieczny unsigned int skip = ctx->skip, nbytes = new_len, n = 0; 1130c2afad6cSKamil Konieczny bool aligned = true, list_ok = true; 1131c2afad6cSKamil Konieczny struct scatterlist *sg_tmp = sg; 1132c2afad6cSKamil Konieczny 1133c2afad6cSKamil Konieczny if (!sg || !sg->length || !new_len) 1134c2afad6cSKamil Konieczny return 0; 1135c2afad6cSKamil Konieczny 1136c2afad6cSKamil Konieczny if (skip || !final) 1137c2afad6cSKamil Konieczny list_ok = false; 1138c2afad6cSKamil Konieczny 1139c2afad6cSKamil Konieczny while (nbytes > 0 && sg_tmp) { 1140c2afad6cSKamil Konieczny n++; 1141c2afad6cSKamil Konieczny if (skip >= sg_tmp->length) { 1142c2afad6cSKamil Konieczny skip -= sg_tmp->length; 1143c2afad6cSKamil Konieczny if (!sg_tmp->length) { 1144c2afad6cSKamil Konieczny aligned = false; 1145c2afad6cSKamil Konieczny break; 1146c2afad6cSKamil Konieczny } 1147c2afad6cSKamil Konieczny } else { 1148c2afad6cSKamil Konieczny if (!IS_ALIGNED(sg_tmp->length - skip, BUFLEN)) { 1149c2afad6cSKamil Konieczny aligned = false; 1150c2afad6cSKamil Konieczny break; 1151c2afad6cSKamil Konieczny } 1152c2afad6cSKamil Konieczny 1153c2afad6cSKamil Konieczny if (nbytes < sg_tmp->length - skip) { 1154c2afad6cSKamil Konieczny list_ok = false; 1155c2afad6cSKamil Konieczny break; 1156c2afad6cSKamil Konieczny } 1157c2afad6cSKamil Konieczny 1158c2afad6cSKamil Konieczny nbytes -= sg_tmp->length - skip; 1159c2afad6cSKamil Konieczny skip = 0; 1160c2afad6cSKamil Konieczny } 1161c2afad6cSKamil Konieczny 1162c2afad6cSKamil Konieczny sg_tmp = sg_next(sg_tmp); 1163c2afad6cSKamil Konieczny } 1164c2afad6cSKamil Konieczny 1165c2afad6cSKamil Konieczny if (!aligned) 1166c2afad6cSKamil Konieczny return s5p_hash_copy_sgs(ctx, sg, new_len); 1167c2afad6cSKamil Konieczny else if (!list_ok) 1168c2afad6cSKamil Konieczny return s5p_hash_copy_sg_lists(ctx, sg, new_len); 1169c2afad6cSKamil Konieczny 1170c2afad6cSKamil Konieczny /* 1171c2afad6cSKamil Konieczny * Have aligned data from previous operation and/or current 1172c2afad6cSKamil Konieczny * Note: will enter here only if (digest or finup) and aligned 1173c2afad6cSKamil Konieczny */ 1174c2afad6cSKamil Konieczny if (ctx->bufcnt) { 1175c2afad6cSKamil Konieczny ctx->sg_len = n; 1176c2afad6cSKamil Konieczny sg_init_table(ctx->sgl, 2); 1177c2afad6cSKamil Konieczny sg_set_buf(ctx->sgl, ctx->dd->xmit_buf, ctx->bufcnt); 1178c2afad6cSKamil Konieczny sg_chain(ctx->sgl, 2, sg); 1179c2afad6cSKamil Konieczny ctx->sg = ctx->sgl; 1180c2afad6cSKamil Konieczny ctx->sg_len++; 1181c2afad6cSKamil Konieczny } else { 1182c2afad6cSKamil Konieczny ctx->sg = sg; 1183c2afad6cSKamil Konieczny ctx->sg_len = n; 1184c2afad6cSKamil Konieczny } 1185c2afad6cSKamil Konieczny 1186c2afad6cSKamil Konieczny return 0; 1187c2afad6cSKamil Konieczny } 1188c2afad6cSKamil Konieczny 1189c2afad6cSKamil Konieczny /** 1190c2afad6cSKamil Konieczny * s5p_hash_prepare_request() - prepare request for processing 1191c2afad6cSKamil Konieczny * @req: AHASH request 1192c2afad6cSKamil Konieczny * @update: true if UPDATE op 1193c2afad6cSKamil Konieczny * 1194c2afad6cSKamil Konieczny * Note 1: we can have update flag _and_ final flag at the same time. 1195c2afad6cSKamil Konieczny * Note 2: we enter here when digcnt > BUFLEN (=HASH_BLOCK_SIZE) or 1196c2afad6cSKamil Konieczny * either req->nbytes or ctx->bufcnt + req->nbytes is > BUFLEN or 1197c2afad6cSKamil Konieczny * we have final op 1198c2afad6cSKamil Konieczny */ 1199c2afad6cSKamil Konieczny static int s5p_hash_prepare_request(struct ahash_request *req, bool update) 1200c2afad6cSKamil Konieczny { 1201c2afad6cSKamil Konieczny struct s5p_hash_reqctx *ctx = ahash_request_ctx(req); 1202c2afad6cSKamil Konieczny bool final = ctx->finup; 1203c2afad6cSKamil Konieczny int xmit_len, hash_later, nbytes; 1204c2afad6cSKamil Konieczny int ret; 1205c2afad6cSKamil Konieczny 1206c2afad6cSKamil Konieczny if (update) 1207c2afad6cSKamil Konieczny nbytes = req->nbytes; 1208c2afad6cSKamil Konieczny else 1209c2afad6cSKamil Konieczny nbytes = 0; 1210c2afad6cSKamil Konieczny 1211c2afad6cSKamil Konieczny ctx->total = nbytes + ctx->bufcnt; 1212c2afad6cSKamil Konieczny if (!ctx->total) 1213c2afad6cSKamil Konieczny return 0; 1214c2afad6cSKamil Konieczny 1215c2afad6cSKamil Konieczny if (nbytes && (!IS_ALIGNED(ctx->bufcnt, BUFLEN))) { 1216c2afad6cSKamil Konieczny /* bytes left from previous request, so fill up to BUFLEN */ 1217c2afad6cSKamil Konieczny int len = BUFLEN - ctx->bufcnt % BUFLEN; 1218c2afad6cSKamil Konieczny 1219c2afad6cSKamil Konieczny if (len > nbytes) 1220c2afad6cSKamil Konieczny len = nbytes; 1221c2afad6cSKamil Konieczny 1222c2afad6cSKamil Konieczny scatterwalk_map_and_copy(ctx->buffer + ctx->bufcnt, req->src, 1223c2afad6cSKamil Konieczny 0, len, 0); 1224c2afad6cSKamil Konieczny ctx->bufcnt += len; 1225c2afad6cSKamil Konieczny nbytes -= len; 1226c2afad6cSKamil Konieczny ctx->skip = len; 1227c2afad6cSKamil Konieczny } else { 1228c2afad6cSKamil Konieczny ctx->skip = 0; 1229c2afad6cSKamil Konieczny } 1230c2afad6cSKamil Konieczny 1231c2afad6cSKamil Konieczny if (ctx->bufcnt) 1232c2afad6cSKamil Konieczny memcpy(ctx->dd->xmit_buf, ctx->buffer, ctx->bufcnt); 1233c2afad6cSKamil Konieczny 1234c2afad6cSKamil Konieczny xmit_len = ctx->total; 1235c2afad6cSKamil Konieczny if (final) { 1236c2afad6cSKamil Konieczny hash_later = 0; 1237c2afad6cSKamil Konieczny } else { 1238c2afad6cSKamil Konieczny if (IS_ALIGNED(xmit_len, BUFLEN)) 1239c2afad6cSKamil Konieczny xmit_len -= BUFLEN; 1240c2afad6cSKamil Konieczny else 1241c2afad6cSKamil Konieczny xmit_len -= xmit_len & (BUFLEN - 1); 1242c2afad6cSKamil Konieczny 1243c2afad6cSKamil Konieczny hash_later = ctx->total - xmit_len; 1244c2afad6cSKamil Konieczny /* copy hash_later bytes from end of req->src */ 1245c2afad6cSKamil Konieczny /* previous bytes are in xmit_buf, so no overwrite */ 1246c2afad6cSKamil Konieczny scatterwalk_map_and_copy(ctx->buffer, req->src, 1247c2afad6cSKamil Konieczny req->nbytes - hash_later, 1248c2afad6cSKamil Konieczny hash_later, 0); 1249c2afad6cSKamil Konieczny } 1250c2afad6cSKamil Konieczny 1251c2afad6cSKamil Konieczny if (xmit_len > BUFLEN) { 1252c2afad6cSKamil Konieczny ret = s5p_hash_prepare_sgs(ctx, req->src, nbytes - hash_later, 1253c2afad6cSKamil Konieczny final); 1254c2afad6cSKamil Konieczny if (ret) 1255c2afad6cSKamil Konieczny return ret; 1256c2afad6cSKamil Konieczny } else { 1257c2afad6cSKamil Konieczny /* have buffered data only */ 1258c2afad6cSKamil Konieczny if (unlikely(!ctx->bufcnt)) { 1259c2afad6cSKamil Konieczny /* first update didn't fill up buffer */ 1260c2afad6cSKamil Konieczny scatterwalk_map_and_copy(ctx->dd->xmit_buf, req->src, 1261c2afad6cSKamil Konieczny 0, xmit_len, 0); 1262c2afad6cSKamil Konieczny } 1263c2afad6cSKamil Konieczny 1264c2afad6cSKamil Konieczny sg_init_table(ctx->sgl, 1); 1265c2afad6cSKamil Konieczny sg_set_buf(ctx->sgl, ctx->dd->xmit_buf, xmit_len); 1266c2afad6cSKamil Konieczny 1267c2afad6cSKamil Konieczny ctx->sg = ctx->sgl; 1268c2afad6cSKamil Konieczny ctx->sg_len = 1; 1269c2afad6cSKamil Konieczny } 1270c2afad6cSKamil Konieczny 1271c2afad6cSKamil Konieczny ctx->bufcnt = hash_later; 1272c2afad6cSKamil Konieczny if (!final) 1273c2afad6cSKamil Konieczny ctx->total = xmit_len; 1274c2afad6cSKamil Konieczny 1275c2afad6cSKamil Konieczny return 0; 1276c2afad6cSKamil Konieczny } 1277c2afad6cSKamil Konieczny 1278c2afad6cSKamil Konieczny /** 1279c2afad6cSKamil Konieczny * s5p_hash_update_dma_stop() - unmap DMA 1280c2afad6cSKamil Konieczny * @dd: secss device 1281c2afad6cSKamil Konieczny * 1282c2afad6cSKamil Konieczny * Unmap scatterlist ctx->sg. 1283c2afad6cSKamil Konieczny */ 1284c2afad6cSKamil Konieczny static void s5p_hash_update_dma_stop(struct s5p_aes_dev *dd) 1285c2afad6cSKamil Konieczny { 12866584eacbSKrzysztof Kozlowski const struct s5p_hash_reqctx *ctx = ahash_request_ctx(dd->hash_req); 1287c2afad6cSKamil Konieczny 1288c2afad6cSKamil Konieczny dma_unmap_sg(dd->dev, ctx->sg, ctx->sg_len, DMA_TO_DEVICE); 1289c2afad6cSKamil Konieczny clear_bit(HASH_FLAGS_DMA_ACTIVE, &dd->hash_flags); 1290c2afad6cSKamil Konieczny } 1291c2afad6cSKamil Konieczny 1292c2afad6cSKamil Konieczny /** 1293c2afad6cSKamil Konieczny * s5p_hash_finish() - copy calculated digest to crypto layer 1294c2afad6cSKamil Konieczny * @req: AHASH request 1295c2afad6cSKamil Konieczny */ 1296c2afad6cSKamil Konieczny static void s5p_hash_finish(struct ahash_request *req) 1297c2afad6cSKamil Konieczny { 1298c2afad6cSKamil Konieczny struct s5p_hash_reqctx *ctx = ahash_request_ctx(req); 1299c2afad6cSKamil Konieczny struct s5p_aes_dev *dd = ctx->dd; 1300c2afad6cSKamil Konieczny 1301c2afad6cSKamil Konieczny if (ctx->digcnt) 1302c2afad6cSKamil Konieczny s5p_hash_copy_result(req); 1303c2afad6cSKamil Konieczny 1304c2afad6cSKamil Konieczny dev_dbg(dd->dev, "hash_finish digcnt: %lld\n", ctx->digcnt); 1305c2afad6cSKamil Konieczny } 1306c2afad6cSKamil Konieczny 1307c2afad6cSKamil Konieczny /** 1308c2afad6cSKamil Konieczny * s5p_hash_finish_req() - finish request 1309c2afad6cSKamil Konieczny * @req: AHASH request 1310c2afad6cSKamil Konieczny * @err: error 1311c2afad6cSKamil Konieczny */ 1312c2afad6cSKamil Konieczny static void s5p_hash_finish_req(struct ahash_request *req, int err) 1313c2afad6cSKamil Konieczny { 1314c2afad6cSKamil Konieczny struct s5p_hash_reqctx *ctx = ahash_request_ctx(req); 1315c2afad6cSKamil Konieczny struct s5p_aes_dev *dd = ctx->dd; 1316c2afad6cSKamil Konieczny unsigned long flags; 1317c2afad6cSKamil Konieczny 1318c2afad6cSKamil Konieczny if (test_bit(HASH_FLAGS_SGS_COPIED, &dd->hash_flags)) 1319c2afad6cSKamil Konieczny free_pages((unsigned long)sg_virt(ctx->sg), 1320c2afad6cSKamil Konieczny get_order(ctx->sg->length)); 1321c2afad6cSKamil Konieczny 1322c2afad6cSKamil Konieczny if (test_bit(HASH_FLAGS_SGS_ALLOCED, &dd->hash_flags)) 1323c2afad6cSKamil Konieczny kfree(ctx->sg); 1324c2afad6cSKamil Konieczny 1325c2afad6cSKamil Konieczny ctx->sg = NULL; 1326c2afad6cSKamil Konieczny dd->hash_flags &= ~(BIT(HASH_FLAGS_SGS_ALLOCED) | 1327c2afad6cSKamil Konieczny BIT(HASH_FLAGS_SGS_COPIED)); 1328c2afad6cSKamil Konieczny 1329c2afad6cSKamil Konieczny if (!err && !ctx->error) { 1330c2afad6cSKamil Konieczny s5p_hash_read_msg(req); 1331c2afad6cSKamil Konieczny if (test_bit(HASH_FLAGS_FINAL, &dd->hash_flags)) 1332c2afad6cSKamil Konieczny s5p_hash_finish(req); 1333c2afad6cSKamil Konieczny } else { 1334c2afad6cSKamil Konieczny ctx->error = true; 1335c2afad6cSKamil Konieczny } 1336c2afad6cSKamil Konieczny 1337c2afad6cSKamil Konieczny spin_lock_irqsave(&dd->hash_lock, flags); 1338c2afad6cSKamil Konieczny dd->hash_flags &= ~(BIT(HASH_FLAGS_BUSY) | BIT(HASH_FLAGS_FINAL) | 1339c2afad6cSKamil Konieczny BIT(HASH_FLAGS_DMA_READY) | 1340c2afad6cSKamil Konieczny BIT(HASH_FLAGS_OUTPUT_READY)); 1341c2afad6cSKamil Konieczny spin_unlock_irqrestore(&dd->hash_lock, flags); 1342c2afad6cSKamil Konieczny 1343c2afad6cSKamil Konieczny if (req->base.complete) 1344c2afad6cSKamil Konieczny req->base.complete(&req->base, err); 1345c2afad6cSKamil Konieczny } 1346c2afad6cSKamil Konieczny 1347c2afad6cSKamil Konieczny /** 1348c2afad6cSKamil Konieczny * s5p_hash_handle_queue() - handle hash queue 1349c2afad6cSKamil Konieczny * @dd: device s5p_aes_dev 1350c2afad6cSKamil Konieczny * @req: AHASH request 1351c2afad6cSKamil Konieczny * 1352c2afad6cSKamil Konieczny * If req!=NULL enqueue it on dd->queue, if FLAGS_BUSY is not set on the 1353c2afad6cSKamil Konieczny * device then processes the first request from the dd->queue 1354c2afad6cSKamil Konieczny * 1355c2afad6cSKamil Konieczny * Returns: see s5p_hash_final below. 1356c2afad6cSKamil Konieczny */ 1357c2afad6cSKamil Konieczny static int s5p_hash_handle_queue(struct s5p_aes_dev *dd, 1358c2afad6cSKamil Konieczny struct ahash_request *req) 1359c2afad6cSKamil Konieczny { 1360c2afad6cSKamil Konieczny struct crypto_async_request *async_req, *backlog; 1361c2afad6cSKamil Konieczny struct s5p_hash_reqctx *ctx; 1362c2afad6cSKamil Konieczny unsigned long flags; 1363c2afad6cSKamil Konieczny int err = 0, ret = 0; 1364c2afad6cSKamil Konieczny 1365c2afad6cSKamil Konieczny retry: 1366c2afad6cSKamil Konieczny spin_lock_irqsave(&dd->hash_lock, flags); 1367c2afad6cSKamil Konieczny if (req) 1368c2afad6cSKamil Konieczny ret = ahash_enqueue_request(&dd->hash_queue, req); 1369c2afad6cSKamil Konieczny 1370c2afad6cSKamil Konieczny if (test_bit(HASH_FLAGS_BUSY, &dd->hash_flags)) { 1371c2afad6cSKamil Konieczny spin_unlock_irqrestore(&dd->hash_lock, flags); 1372c2afad6cSKamil Konieczny return ret; 1373c2afad6cSKamil Konieczny } 1374c2afad6cSKamil Konieczny 1375c2afad6cSKamil Konieczny backlog = crypto_get_backlog(&dd->hash_queue); 1376c2afad6cSKamil Konieczny async_req = crypto_dequeue_request(&dd->hash_queue); 1377c2afad6cSKamil Konieczny if (async_req) 1378c2afad6cSKamil Konieczny set_bit(HASH_FLAGS_BUSY, &dd->hash_flags); 1379c2afad6cSKamil Konieczny 1380c2afad6cSKamil Konieczny spin_unlock_irqrestore(&dd->hash_lock, flags); 1381c2afad6cSKamil Konieczny 1382c2afad6cSKamil Konieczny if (!async_req) 1383c2afad6cSKamil Konieczny return ret; 1384c2afad6cSKamil Konieczny 1385c2afad6cSKamil Konieczny if (backlog) 1386c2afad6cSKamil Konieczny backlog->complete(backlog, -EINPROGRESS); 1387c2afad6cSKamil Konieczny 1388c2afad6cSKamil Konieczny req = ahash_request_cast(async_req); 1389c2afad6cSKamil Konieczny dd->hash_req = req; 1390c2afad6cSKamil Konieczny ctx = ahash_request_ctx(req); 1391c2afad6cSKamil Konieczny 1392c2afad6cSKamil Konieczny err = s5p_hash_prepare_request(req, ctx->op_update); 1393c2afad6cSKamil Konieczny if (err || !ctx->total) 1394c2afad6cSKamil Konieczny goto out; 1395c2afad6cSKamil Konieczny 1396c2afad6cSKamil Konieczny dev_dbg(dd->dev, "handling new req, op_update: %u, nbytes: %d\n", 1397c2afad6cSKamil Konieczny ctx->op_update, req->nbytes); 1398c2afad6cSKamil Konieczny 1399c2afad6cSKamil Konieczny s5p_ahash_dma_init(dd, SSS_HASHIN_INDEPENDENT); 1400c2afad6cSKamil Konieczny if (ctx->digcnt) 1401c2afad6cSKamil Konieczny s5p_hash_write_iv(req); /* restore hash IV */ 1402c2afad6cSKamil Konieczny 1403c2afad6cSKamil Konieczny if (ctx->op_update) { /* HASH_OP_UPDATE */ 1404c2afad6cSKamil Konieczny err = s5p_hash_xmit_dma(dd, ctx->total, ctx->finup); 1405c2afad6cSKamil Konieczny if (err != -EINPROGRESS && ctx->finup && !ctx->error) 1406c2afad6cSKamil Konieczny /* no final() after finup() */ 1407c2afad6cSKamil Konieczny err = s5p_hash_xmit_dma(dd, ctx->total, true); 1408c2afad6cSKamil Konieczny } else { /* HASH_OP_FINAL */ 1409c2afad6cSKamil Konieczny err = s5p_hash_xmit_dma(dd, ctx->total, true); 1410c2afad6cSKamil Konieczny } 1411c2afad6cSKamil Konieczny out: 1412c2afad6cSKamil Konieczny if (err != -EINPROGRESS) { 1413c2afad6cSKamil Konieczny /* hash_tasklet_cb will not finish it, so do it here */ 1414c2afad6cSKamil Konieczny s5p_hash_finish_req(req, err); 1415c2afad6cSKamil Konieczny req = NULL; 1416c2afad6cSKamil Konieczny 1417c2afad6cSKamil Konieczny /* 1418c2afad6cSKamil Konieczny * Execute next request immediately if there is anything 1419c2afad6cSKamil Konieczny * in queue. 1420c2afad6cSKamil Konieczny */ 1421c2afad6cSKamil Konieczny goto retry; 1422c2afad6cSKamil Konieczny } 1423c2afad6cSKamil Konieczny 1424c2afad6cSKamil Konieczny return ret; 1425c2afad6cSKamil Konieczny } 1426c2afad6cSKamil Konieczny 1427c2afad6cSKamil Konieczny /** 1428c2afad6cSKamil Konieczny * s5p_hash_tasklet_cb() - hash tasklet 1429c2afad6cSKamil Konieczny * @data: ptr to s5p_aes_dev 1430c2afad6cSKamil Konieczny */ 1431c2afad6cSKamil Konieczny static void s5p_hash_tasklet_cb(unsigned long data) 1432c2afad6cSKamil Konieczny { 1433c2afad6cSKamil Konieczny struct s5p_aes_dev *dd = (struct s5p_aes_dev *)data; 1434c2afad6cSKamil Konieczny 1435c2afad6cSKamil Konieczny if (!test_bit(HASH_FLAGS_BUSY, &dd->hash_flags)) { 1436c2afad6cSKamil Konieczny s5p_hash_handle_queue(dd, NULL); 1437c2afad6cSKamil Konieczny return; 1438c2afad6cSKamil Konieczny } 1439c2afad6cSKamil Konieczny 1440c2afad6cSKamil Konieczny if (test_bit(HASH_FLAGS_DMA_READY, &dd->hash_flags)) { 1441c2afad6cSKamil Konieczny if (test_and_clear_bit(HASH_FLAGS_DMA_ACTIVE, 1442c2afad6cSKamil Konieczny &dd->hash_flags)) { 1443c2afad6cSKamil Konieczny s5p_hash_update_dma_stop(dd); 1444c2afad6cSKamil Konieczny } 1445c2afad6cSKamil Konieczny 1446c2afad6cSKamil Konieczny if (test_and_clear_bit(HASH_FLAGS_OUTPUT_READY, 1447c2afad6cSKamil Konieczny &dd->hash_flags)) { 1448c2afad6cSKamil Konieczny /* hash or semi-hash ready */ 1449c2afad6cSKamil Konieczny clear_bit(HASH_FLAGS_DMA_READY, &dd->hash_flags); 1450c2afad6cSKamil Konieczny goto finish; 1451c2afad6cSKamil Konieczny } 1452c2afad6cSKamil Konieczny } 1453c2afad6cSKamil Konieczny 1454c2afad6cSKamil Konieczny return; 1455c2afad6cSKamil Konieczny 1456c2afad6cSKamil Konieczny finish: 1457c2afad6cSKamil Konieczny /* finish curent request */ 1458c2afad6cSKamil Konieczny s5p_hash_finish_req(dd->hash_req, 0); 1459c2afad6cSKamil Konieczny 1460c2afad6cSKamil Konieczny /* If we are not busy, process next req */ 1461c2afad6cSKamil Konieczny if (!test_bit(HASH_FLAGS_BUSY, &dd->hash_flags)) 1462c2afad6cSKamil Konieczny s5p_hash_handle_queue(dd, NULL); 1463c2afad6cSKamil Konieczny } 1464c2afad6cSKamil Konieczny 1465c2afad6cSKamil Konieczny /** 1466c2afad6cSKamil Konieczny * s5p_hash_enqueue() - enqueue request 1467c2afad6cSKamil Konieczny * @req: AHASH request 1468c2afad6cSKamil Konieczny * @op: operation UPDATE (true) or FINAL (false) 1469c2afad6cSKamil Konieczny * 1470c2afad6cSKamil Konieczny * Returns: see s5p_hash_final below. 1471c2afad6cSKamil Konieczny */ 1472c2afad6cSKamil Konieczny static int s5p_hash_enqueue(struct ahash_request *req, bool op) 1473c2afad6cSKamil Konieczny { 1474c2afad6cSKamil Konieczny struct s5p_hash_reqctx *ctx = ahash_request_ctx(req); 1475c2afad6cSKamil Konieczny struct s5p_hash_ctx *tctx = crypto_tfm_ctx(req->base.tfm); 1476c2afad6cSKamil Konieczny 1477c2afad6cSKamil Konieczny ctx->op_update = op; 1478c2afad6cSKamil Konieczny 1479c2afad6cSKamil Konieczny return s5p_hash_handle_queue(tctx->dd, req); 1480c2afad6cSKamil Konieczny } 1481c2afad6cSKamil Konieczny 1482c2afad6cSKamil Konieczny /** 1483c2afad6cSKamil Konieczny * s5p_hash_update() - process the hash input data 1484c2afad6cSKamil Konieczny * @req: AHASH request 1485c2afad6cSKamil Konieczny * 1486c2afad6cSKamil Konieczny * If request will fit in buffer, copy it and return immediately 1487c2afad6cSKamil Konieczny * else enqueue it with OP_UPDATE. 1488c2afad6cSKamil Konieczny * 1489c2afad6cSKamil Konieczny * Returns: see s5p_hash_final below. 1490c2afad6cSKamil Konieczny */ 1491c2afad6cSKamil Konieczny static int s5p_hash_update(struct ahash_request *req) 1492c2afad6cSKamil Konieczny { 1493c2afad6cSKamil Konieczny struct s5p_hash_reqctx *ctx = ahash_request_ctx(req); 1494c2afad6cSKamil Konieczny 1495c2afad6cSKamil Konieczny if (!req->nbytes) 1496c2afad6cSKamil Konieczny return 0; 1497c2afad6cSKamil Konieczny 1498c2afad6cSKamil Konieczny if (ctx->bufcnt + req->nbytes <= BUFLEN) { 1499c2afad6cSKamil Konieczny scatterwalk_map_and_copy(ctx->buffer + ctx->bufcnt, req->src, 1500c2afad6cSKamil Konieczny 0, req->nbytes, 0); 1501c2afad6cSKamil Konieczny ctx->bufcnt += req->nbytes; 1502c2afad6cSKamil Konieczny return 0; 1503c2afad6cSKamil Konieczny } 1504c2afad6cSKamil Konieczny 1505c2afad6cSKamil Konieczny return s5p_hash_enqueue(req, true); /* HASH_OP_UPDATE */ 1506c2afad6cSKamil Konieczny } 1507c2afad6cSKamil Konieczny 1508c2afad6cSKamil Konieczny /** 1509c2afad6cSKamil Konieczny * s5p_hash_shash_digest() - calculate shash digest 1510c2afad6cSKamil Konieczny * @tfm: crypto transformation 1511c2afad6cSKamil Konieczny * @flags: tfm flags 1512c2afad6cSKamil Konieczny * @data: input data 1513c2afad6cSKamil Konieczny * @len: length of data 1514c2afad6cSKamil Konieczny * @out: output buffer 1515c2afad6cSKamil Konieczny */ 1516c2afad6cSKamil Konieczny static int s5p_hash_shash_digest(struct crypto_shash *tfm, u32 flags, 1517c2afad6cSKamil Konieczny const u8 *data, unsigned int len, u8 *out) 1518c2afad6cSKamil Konieczny { 1519c2afad6cSKamil Konieczny SHASH_DESC_ON_STACK(shash, tfm); 1520c2afad6cSKamil Konieczny 1521c2afad6cSKamil Konieczny shash->tfm = tfm; 1522c2afad6cSKamil Konieczny shash->flags = flags & ~CRYPTO_TFM_REQ_MAY_SLEEP; 1523c2afad6cSKamil Konieczny 1524c2afad6cSKamil Konieczny return crypto_shash_digest(shash, data, len, out); 1525c2afad6cSKamil Konieczny } 1526c2afad6cSKamil Konieczny 1527c2afad6cSKamil Konieczny /** 1528c2afad6cSKamil Konieczny * s5p_hash_final_shash() - calculate shash digest 1529c2afad6cSKamil Konieczny * @req: AHASH request 1530c2afad6cSKamil Konieczny */ 1531c2afad6cSKamil Konieczny static int s5p_hash_final_shash(struct ahash_request *req) 1532c2afad6cSKamil Konieczny { 1533c2afad6cSKamil Konieczny struct s5p_hash_ctx *tctx = crypto_tfm_ctx(req->base.tfm); 1534c2afad6cSKamil Konieczny struct s5p_hash_reqctx *ctx = ahash_request_ctx(req); 1535c2afad6cSKamil Konieczny 1536c2afad6cSKamil Konieczny return s5p_hash_shash_digest(tctx->fallback, req->base.flags, 1537c2afad6cSKamil Konieczny ctx->buffer, ctx->bufcnt, req->result); 1538c2afad6cSKamil Konieczny } 1539c2afad6cSKamil Konieczny 1540c2afad6cSKamil Konieczny /** 1541c2afad6cSKamil Konieczny * s5p_hash_final() - close up hash and calculate digest 1542c2afad6cSKamil Konieczny * @req: AHASH request 1543c2afad6cSKamil Konieczny * 1544c2afad6cSKamil Konieczny * Note: in final req->src do not have any data, and req->nbytes can be 1545c2afad6cSKamil Konieczny * non-zero. 1546c2afad6cSKamil Konieczny * 1547c2afad6cSKamil Konieczny * If there were no input data processed yet and the buffered hash data is 1548c2afad6cSKamil Konieczny * less than BUFLEN (64) then calculate the final hash immediately by using 1549c2afad6cSKamil Konieczny * SW algorithm fallback. 1550c2afad6cSKamil Konieczny * 1551c2afad6cSKamil Konieczny * Otherwise enqueues the current AHASH request with OP_FINAL operation op 1552c2afad6cSKamil Konieczny * and finalize hash message in HW. Note that if digcnt!=0 then there were 1553c2afad6cSKamil Konieczny * previous update op, so there are always some buffered bytes in ctx->buffer, 1554c2afad6cSKamil Konieczny * which means that ctx->bufcnt!=0 1555c2afad6cSKamil Konieczny * 1556c2afad6cSKamil Konieczny * Returns: 1557c2afad6cSKamil Konieczny * 0 if the request has been processed immediately, 1558c2afad6cSKamil Konieczny * -EINPROGRESS if the operation has been queued for later execution or is set 1559c2afad6cSKamil Konieczny * to processing by HW, 1560c2afad6cSKamil Konieczny * -EBUSY if queue is full and request should be resubmitted later, 1561c2afad6cSKamil Konieczny * other negative values denotes an error. 1562c2afad6cSKamil Konieczny */ 1563c2afad6cSKamil Konieczny static int s5p_hash_final(struct ahash_request *req) 1564c2afad6cSKamil Konieczny { 1565c2afad6cSKamil Konieczny struct s5p_hash_reqctx *ctx = ahash_request_ctx(req); 1566c2afad6cSKamil Konieczny 1567c2afad6cSKamil Konieczny ctx->finup = true; 1568c2afad6cSKamil Konieczny if (ctx->error) 1569c2afad6cSKamil Konieczny return -EINVAL; /* uncompleted hash is not needed */ 1570c2afad6cSKamil Konieczny 1571c2afad6cSKamil Konieczny if (!ctx->digcnt && ctx->bufcnt < BUFLEN) 1572c2afad6cSKamil Konieczny return s5p_hash_final_shash(req); 1573c2afad6cSKamil Konieczny 1574c2afad6cSKamil Konieczny return s5p_hash_enqueue(req, false); /* HASH_OP_FINAL */ 1575c2afad6cSKamil Konieczny } 1576c2afad6cSKamil Konieczny 1577c2afad6cSKamil Konieczny /** 1578c2afad6cSKamil Konieczny * s5p_hash_finup() - process last req->src and calculate digest 1579c2afad6cSKamil Konieczny * @req: AHASH request containing the last update data 1580c2afad6cSKamil Konieczny * 1581c2afad6cSKamil Konieczny * Return values: see s5p_hash_final above. 1582c2afad6cSKamil Konieczny */ 1583c2afad6cSKamil Konieczny static int s5p_hash_finup(struct ahash_request *req) 1584c2afad6cSKamil Konieczny { 1585c2afad6cSKamil Konieczny struct s5p_hash_reqctx *ctx = ahash_request_ctx(req); 1586c2afad6cSKamil Konieczny int err1, err2; 1587c2afad6cSKamil Konieczny 1588c2afad6cSKamil Konieczny ctx->finup = true; 1589c2afad6cSKamil Konieczny 1590c2afad6cSKamil Konieczny err1 = s5p_hash_update(req); 1591c2afad6cSKamil Konieczny if (err1 == -EINPROGRESS || err1 == -EBUSY) 1592c2afad6cSKamil Konieczny return err1; 1593c2afad6cSKamil Konieczny 1594c2afad6cSKamil Konieczny /* 1595c2afad6cSKamil Konieczny * final() has to be always called to cleanup resources even if 1596c2afad6cSKamil Konieczny * update() failed, except EINPROGRESS or calculate digest for small 1597c2afad6cSKamil Konieczny * size 1598c2afad6cSKamil Konieczny */ 1599c2afad6cSKamil Konieczny err2 = s5p_hash_final(req); 1600c2afad6cSKamil Konieczny 1601c2afad6cSKamil Konieczny return err1 ?: err2; 1602c2afad6cSKamil Konieczny } 1603c2afad6cSKamil Konieczny 1604c2afad6cSKamil Konieczny /** 1605c2afad6cSKamil Konieczny * s5p_hash_init() - initialize AHASH request contex 1606c2afad6cSKamil Konieczny * @req: AHASH request 1607c2afad6cSKamil Konieczny * 1608c2afad6cSKamil Konieczny * Init async hash request context. 1609c2afad6cSKamil Konieczny */ 1610c2afad6cSKamil Konieczny static int s5p_hash_init(struct ahash_request *req) 1611c2afad6cSKamil Konieczny { 1612c2afad6cSKamil Konieczny struct s5p_hash_reqctx *ctx = ahash_request_ctx(req); 1613c2afad6cSKamil Konieczny struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); 1614c2afad6cSKamil Konieczny struct s5p_hash_ctx *tctx = crypto_ahash_ctx(tfm); 1615c2afad6cSKamil Konieczny 1616c2afad6cSKamil Konieczny ctx->dd = tctx->dd; 1617c2afad6cSKamil Konieczny ctx->error = false; 1618c2afad6cSKamil Konieczny ctx->finup = false; 1619c2afad6cSKamil Konieczny ctx->bufcnt = 0; 1620c2afad6cSKamil Konieczny ctx->digcnt = 0; 1621c2afad6cSKamil Konieczny ctx->total = 0; 1622c2afad6cSKamil Konieczny ctx->skip = 0; 1623c2afad6cSKamil Konieczny 1624c2afad6cSKamil Konieczny dev_dbg(tctx->dd->dev, "init: digest size: %d\n", 1625c2afad6cSKamil Konieczny crypto_ahash_digestsize(tfm)); 1626c2afad6cSKamil Konieczny 1627c2afad6cSKamil Konieczny switch (crypto_ahash_digestsize(tfm)) { 1628c2afad6cSKamil Konieczny case MD5_DIGEST_SIZE: 1629c2afad6cSKamil Konieczny ctx->engine = SSS_HASH_ENGINE_MD5; 1630c2afad6cSKamil Konieczny ctx->nregs = HASH_MD5_MAX_REG; 1631c2afad6cSKamil Konieczny break; 1632c2afad6cSKamil Konieczny case SHA1_DIGEST_SIZE: 1633c2afad6cSKamil Konieczny ctx->engine = SSS_HASH_ENGINE_SHA1; 1634c2afad6cSKamil Konieczny ctx->nregs = HASH_SHA1_MAX_REG; 1635c2afad6cSKamil Konieczny break; 1636c2afad6cSKamil Konieczny case SHA256_DIGEST_SIZE: 1637c2afad6cSKamil Konieczny ctx->engine = SSS_HASH_ENGINE_SHA256; 1638c2afad6cSKamil Konieczny ctx->nregs = HASH_SHA256_MAX_REG; 1639c2afad6cSKamil Konieczny break; 1640c2afad6cSKamil Konieczny default: 1641c2afad6cSKamil Konieczny ctx->error = true; 1642c2afad6cSKamil Konieczny return -EINVAL; 1643c2afad6cSKamil Konieczny } 1644c2afad6cSKamil Konieczny 1645c2afad6cSKamil Konieczny return 0; 1646c2afad6cSKamil Konieczny } 1647c2afad6cSKamil Konieczny 1648c2afad6cSKamil Konieczny /** 1649c2afad6cSKamil Konieczny * s5p_hash_digest - calculate digest from req->src 1650c2afad6cSKamil Konieczny * @req: AHASH request 1651c2afad6cSKamil Konieczny * 1652c2afad6cSKamil Konieczny * Return values: see s5p_hash_final above. 1653c2afad6cSKamil Konieczny */ 1654c2afad6cSKamil Konieczny static int s5p_hash_digest(struct ahash_request *req) 1655c2afad6cSKamil Konieczny { 1656c2afad6cSKamil Konieczny return s5p_hash_init(req) ?: s5p_hash_finup(req); 1657c2afad6cSKamil Konieczny } 1658c2afad6cSKamil Konieczny 1659c2afad6cSKamil Konieczny /** 1660c2afad6cSKamil Konieczny * s5p_hash_cra_init_alg - init crypto alg transformation 1661c2afad6cSKamil Konieczny * @tfm: crypto transformation 1662c2afad6cSKamil Konieczny */ 1663c2afad6cSKamil Konieczny static int s5p_hash_cra_init_alg(struct crypto_tfm *tfm) 1664c2afad6cSKamil Konieczny { 1665c2afad6cSKamil Konieczny struct s5p_hash_ctx *tctx = crypto_tfm_ctx(tfm); 1666c2afad6cSKamil Konieczny const char *alg_name = crypto_tfm_alg_name(tfm); 1667c2afad6cSKamil Konieczny 1668c2afad6cSKamil Konieczny tctx->dd = s5p_dev; 1669c2afad6cSKamil Konieczny /* Allocate a fallback and abort if it failed. */ 1670c2afad6cSKamil Konieczny tctx->fallback = crypto_alloc_shash(alg_name, 0, 1671c2afad6cSKamil Konieczny CRYPTO_ALG_NEED_FALLBACK); 1672c2afad6cSKamil Konieczny if (IS_ERR(tctx->fallback)) { 1673c2afad6cSKamil Konieczny pr_err("fallback alloc fails for '%s'\n", alg_name); 1674c2afad6cSKamil Konieczny return PTR_ERR(tctx->fallback); 1675c2afad6cSKamil Konieczny } 1676c2afad6cSKamil Konieczny 1677c2afad6cSKamil Konieczny crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm), 1678c2afad6cSKamil Konieczny sizeof(struct s5p_hash_reqctx) + BUFLEN); 1679c2afad6cSKamil Konieczny 1680c2afad6cSKamil Konieczny return 0; 1681c2afad6cSKamil Konieczny } 1682c2afad6cSKamil Konieczny 1683c2afad6cSKamil Konieczny /** 1684c2afad6cSKamil Konieczny * s5p_hash_cra_init - init crypto tfm 1685c2afad6cSKamil Konieczny * @tfm: crypto transformation 1686c2afad6cSKamil Konieczny */ 1687c2afad6cSKamil Konieczny static int s5p_hash_cra_init(struct crypto_tfm *tfm) 1688c2afad6cSKamil Konieczny { 1689c2afad6cSKamil Konieczny return s5p_hash_cra_init_alg(tfm); 1690c2afad6cSKamil Konieczny } 1691c2afad6cSKamil Konieczny 1692c2afad6cSKamil Konieczny /** 1693c2afad6cSKamil Konieczny * s5p_hash_cra_exit - exit crypto tfm 1694c2afad6cSKamil Konieczny * @tfm: crypto transformation 1695c2afad6cSKamil Konieczny * 1696c2afad6cSKamil Konieczny * free allocated fallback 1697c2afad6cSKamil Konieczny */ 1698c2afad6cSKamil Konieczny static void s5p_hash_cra_exit(struct crypto_tfm *tfm) 1699c2afad6cSKamil Konieczny { 1700c2afad6cSKamil Konieczny struct s5p_hash_ctx *tctx = crypto_tfm_ctx(tfm); 1701c2afad6cSKamil Konieczny 1702c2afad6cSKamil Konieczny crypto_free_shash(tctx->fallback); 1703c2afad6cSKamil Konieczny tctx->fallback = NULL; 1704c2afad6cSKamil Konieczny } 1705c2afad6cSKamil Konieczny 1706c2afad6cSKamil Konieczny /** 1707c2afad6cSKamil Konieczny * s5p_hash_export - export hash state 1708c2afad6cSKamil Konieczny * @req: AHASH request 1709c2afad6cSKamil Konieczny * @out: buffer for exported state 1710c2afad6cSKamil Konieczny */ 1711c2afad6cSKamil Konieczny static int s5p_hash_export(struct ahash_request *req, void *out) 1712c2afad6cSKamil Konieczny { 17136584eacbSKrzysztof Kozlowski const struct s5p_hash_reqctx *ctx = ahash_request_ctx(req); 1714c2afad6cSKamil Konieczny 1715c2afad6cSKamil Konieczny memcpy(out, ctx, sizeof(*ctx) + ctx->bufcnt); 1716c2afad6cSKamil Konieczny 1717c2afad6cSKamil Konieczny return 0; 1718c2afad6cSKamil Konieczny } 1719c2afad6cSKamil Konieczny 1720c2afad6cSKamil Konieczny /** 1721c2afad6cSKamil Konieczny * s5p_hash_import - import hash state 1722c2afad6cSKamil Konieczny * @req: AHASH request 1723c2afad6cSKamil Konieczny * @in: buffer with state to be imported from 1724c2afad6cSKamil Konieczny */ 1725c2afad6cSKamil Konieczny static int s5p_hash_import(struct ahash_request *req, const void *in) 1726c2afad6cSKamil Konieczny { 1727c2afad6cSKamil Konieczny struct s5p_hash_reqctx *ctx = ahash_request_ctx(req); 1728c2afad6cSKamil Konieczny struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); 1729c2afad6cSKamil Konieczny struct s5p_hash_ctx *tctx = crypto_ahash_ctx(tfm); 1730c2afad6cSKamil Konieczny const struct s5p_hash_reqctx *ctx_in = in; 1731c2afad6cSKamil Konieczny 1732c2afad6cSKamil Konieczny memcpy(ctx, in, sizeof(*ctx) + BUFLEN); 1733c2afad6cSKamil Konieczny if (ctx_in->bufcnt > BUFLEN) { 1734c2afad6cSKamil Konieczny ctx->error = true; 1735c2afad6cSKamil Konieczny return -EINVAL; 1736c2afad6cSKamil Konieczny } 1737c2afad6cSKamil Konieczny 1738c2afad6cSKamil Konieczny ctx->dd = tctx->dd; 1739c2afad6cSKamil Konieczny ctx->error = false; 1740c2afad6cSKamil Konieczny 1741c2afad6cSKamil Konieczny return 0; 1742c2afad6cSKamil Konieczny } 1743c2afad6cSKamil Konieczny 1744c2afad6cSKamil Konieczny static struct ahash_alg algs_sha1_md5_sha256[] = { 1745c2afad6cSKamil Konieczny { 1746c2afad6cSKamil Konieczny .init = s5p_hash_init, 1747c2afad6cSKamil Konieczny .update = s5p_hash_update, 1748c2afad6cSKamil Konieczny .final = s5p_hash_final, 1749c2afad6cSKamil Konieczny .finup = s5p_hash_finup, 1750c2afad6cSKamil Konieczny .digest = s5p_hash_digest, 1751c2afad6cSKamil Konieczny .export = s5p_hash_export, 1752c2afad6cSKamil Konieczny .import = s5p_hash_import, 1753c2afad6cSKamil Konieczny .halg.statesize = sizeof(struct s5p_hash_reqctx) + BUFLEN, 1754c2afad6cSKamil Konieczny .halg.digestsize = SHA1_DIGEST_SIZE, 1755c2afad6cSKamil Konieczny .halg.base = { 1756c2afad6cSKamil Konieczny .cra_name = "sha1", 1757c2afad6cSKamil Konieczny .cra_driver_name = "exynos-sha1", 1758c2afad6cSKamil Konieczny .cra_priority = 100, 17596a38f622SEric Biggers .cra_flags = CRYPTO_ALG_KERN_DRIVER_ONLY | 1760c2afad6cSKamil Konieczny CRYPTO_ALG_ASYNC | 1761c2afad6cSKamil Konieczny CRYPTO_ALG_NEED_FALLBACK, 1762c2afad6cSKamil Konieczny .cra_blocksize = HASH_BLOCK_SIZE, 1763c2afad6cSKamil Konieczny .cra_ctxsize = sizeof(struct s5p_hash_ctx), 1764c2afad6cSKamil Konieczny .cra_alignmask = SSS_HASH_DMA_ALIGN_MASK, 1765c2afad6cSKamil Konieczny .cra_module = THIS_MODULE, 1766c2afad6cSKamil Konieczny .cra_init = s5p_hash_cra_init, 1767c2afad6cSKamil Konieczny .cra_exit = s5p_hash_cra_exit, 1768c2afad6cSKamil Konieczny } 1769c2afad6cSKamil Konieczny }, 1770c2afad6cSKamil Konieczny { 1771c2afad6cSKamil Konieczny .init = s5p_hash_init, 1772c2afad6cSKamil Konieczny .update = s5p_hash_update, 1773c2afad6cSKamil Konieczny .final = s5p_hash_final, 1774c2afad6cSKamil Konieczny .finup = s5p_hash_finup, 1775c2afad6cSKamil Konieczny .digest = s5p_hash_digest, 1776c2afad6cSKamil Konieczny .export = s5p_hash_export, 1777c2afad6cSKamil Konieczny .import = s5p_hash_import, 1778c2afad6cSKamil Konieczny .halg.statesize = sizeof(struct s5p_hash_reqctx) + BUFLEN, 1779c2afad6cSKamil Konieczny .halg.digestsize = MD5_DIGEST_SIZE, 1780c2afad6cSKamil Konieczny .halg.base = { 1781c2afad6cSKamil Konieczny .cra_name = "md5", 1782c2afad6cSKamil Konieczny .cra_driver_name = "exynos-md5", 1783c2afad6cSKamil Konieczny .cra_priority = 100, 17846a38f622SEric Biggers .cra_flags = CRYPTO_ALG_KERN_DRIVER_ONLY | 1785c2afad6cSKamil Konieczny CRYPTO_ALG_ASYNC | 1786c2afad6cSKamil Konieczny CRYPTO_ALG_NEED_FALLBACK, 1787c2afad6cSKamil Konieczny .cra_blocksize = HASH_BLOCK_SIZE, 1788c2afad6cSKamil Konieczny .cra_ctxsize = sizeof(struct s5p_hash_ctx), 1789c2afad6cSKamil Konieczny .cra_alignmask = SSS_HASH_DMA_ALIGN_MASK, 1790c2afad6cSKamil Konieczny .cra_module = THIS_MODULE, 1791c2afad6cSKamil Konieczny .cra_init = s5p_hash_cra_init, 1792c2afad6cSKamil Konieczny .cra_exit = s5p_hash_cra_exit, 1793c2afad6cSKamil Konieczny } 1794c2afad6cSKamil Konieczny }, 1795c2afad6cSKamil Konieczny { 1796c2afad6cSKamil Konieczny .init = s5p_hash_init, 1797c2afad6cSKamil Konieczny .update = s5p_hash_update, 1798c2afad6cSKamil Konieczny .final = s5p_hash_final, 1799c2afad6cSKamil Konieczny .finup = s5p_hash_finup, 1800c2afad6cSKamil Konieczny .digest = s5p_hash_digest, 1801c2afad6cSKamil Konieczny .export = s5p_hash_export, 1802c2afad6cSKamil Konieczny .import = s5p_hash_import, 1803c2afad6cSKamil Konieczny .halg.statesize = sizeof(struct s5p_hash_reqctx) + BUFLEN, 1804c2afad6cSKamil Konieczny .halg.digestsize = SHA256_DIGEST_SIZE, 1805c2afad6cSKamil Konieczny .halg.base = { 1806c2afad6cSKamil Konieczny .cra_name = "sha256", 1807c2afad6cSKamil Konieczny .cra_driver_name = "exynos-sha256", 1808c2afad6cSKamil Konieczny .cra_priority = 100, 18096a38f622SEric Biggers .cra_flags = CRYPTO_ALG_KERN_DRIVER_ONLY | 1810c2afad6cSKamil Konieczny CRYPTO_ALG_ASYNC | 1811c2afad6cSKamil Konieczny CRYPTO_ALG_NEED_FALLBACK, 1812c2afad6cSKamil Konieczny .cra_blocksize = HASH_BLOCK_SIZE, 1813c2afad6cSKamil Konieczny .cra_ctxsize = sizeof(struct s5p_hash_ctx), 1814c2afad6cSKamil Konieczny .cra_alignmask = SSS_HASH_DMA_ALIGN_MASK, 1815c2afad6cSKamil Konieczny .cra_module = THIS_MODULE, 1816c2afad6cSKamil Konieczny .cra_init = s5p_hash_cra_init, 1817c2afad6cSKamil Konieczny .cra_exit = s5p_hash_cra_exit, 1818c2afad6cSKamil Konieczny } 1819c2afad6cSKamil Konieczny } 1820c2afad6cSKamil Konieczny 1821c2afad6cSKamil Konieczny }; 1822c2afad6cSKamil Konieczny 1823a49e490cSVladimir Zapolskiy static void s5p_set_aes(struct s5p_aes_dev *dev, 1824cdf640a6SChristoph Manszewski const u8 *key, const u8 *iv, const u8 *ctr, 18256584eacbSKrzysztof Kozlowski unsigned int keylen) 1826a49e490cSVladimir Zapolskiy { 1827a49e490cSVladimir Zapolskiy void __iomem *keystart; 1828a49e490cSVladimir Zapolskiy 18298f9702aaSNaveen Krishna Chatradhi if (iv) 1830ef5c73b3SKrzysztof Kozlowski memcpy_toio(dev->aes_ioaddr + SSS_REG_AES_IV_DATA(0), iv, 1831ef5c73b3SKrzysztof Kozlowski AES_BLOCK_SIZE); 1832a49e490cSVladimir Zapolskiy 1833cdf640a6SChristoph Manszewski if (ctr) 1834ef5c73b3SKrzysztof Kozlowski memcpy_toio(dev->aes_ioaddr + SSS_REG_AES_CNT_DATA(0), ctr, 1835ef5c73b3SKrzysztof Kozlowski AES_BLOCK_SIZE); 1836cdf640a6SChristoph Manszewski 1837a49e490cSVladimir Zapolskiy if (keylen == AES_KEYSIZE_256) 183889245107SNaveen Krishna Chatradhi keystart = dev->aes_ioaddr + SSS_REG_AES_KEY_DATA(0); 1839a49e490cSVladimir Zapolskiy else if (keylen == AES_KEYSIZE_192) 184089245107SNaveen Krishna Chatradhi keystart = dev->aes_ioaddr + SSS_REG_AES_KEY_DATA(2); 1841a49e490cSVladimir Zapolskiy else 184289245107SNaveen Krishna Chatradhi keystart = dev->aes_ioaddr + SSS_REG_AES_KEY_DATA(4); 1843a49e490cSVladimir Zapolskiy 18441e3012d0SKrzysztof Koz?owski memcpy_toio(keystart, key, keylen); 1845a49e490cSVladimir Zapolskiy } 1846a49e490cSVladimir Zapolskiy 18479e4a1100SKrzysztof Kozlowski static bool s5p_is_sg_aligned(struct scatterlist *sg) 18489e4a1100SKrzysztof Kozlowski { 18499e4a1100SKrzysztof Kozlowski while (sg) { 1850d1497977SMarek Szyprowski if (!IS_ALIGNED(sg->length, AES_BLOCK_SIZE)) 18519e4a1100SKrzysztof Kozlowski return false; 18529e4a1100SKrzysztof Kozlowski sg = sg_next(sg); 18539e4a1100SKrzysztof Kozlowski } 18549e4a1100SKrzysztof Kozlowski 18559e4a1100SKrzysztof Kozlowski return true; 18569e4a1100SKrzysztof Kozlowski } 18579e4a1100SKrzysztof Kozlowski 18589e4a1100SKrzysztof Kozlowski static int s5p_set_indata_start(struct s5p_aes_dev *dev, 18599e4a1100SKrzysztof Kozlowski struct ablkcipher_request *req) 18609e4a1100SKrzysztof Kozlowski { 18619e4a1100SKrzysztof Kozlowski struct scatterlist *sg; 18629e4a1100SKrzysztof Kozlowski int err; 18639e4a1100SKrzysztof Kozlowski 18649e4a1100SKrzysztof Kozlowski dev->sg_src_cpy = NULL; 18659e4a1100SKrzysztof Kozlowski sg = req->src; 18669e4a1100SKrzysztof Kozlowski if (!s5p_is_sg_aligned(sg)) { 18679e4a1100SKrzysztof Kozlowski dev_dbg(dev->dev, 18689e4a1100SKrzysztof Kozlowski "At least one unaligned source scatter list, making a copy\n"); 18699e4a1100SKrzysztof Kozlowski err = s5p_make_sg_cpy(dev, sg, &dev->sg_src_cpy); 18709e4a1100SKrzysztof Kozlowski if (err) 18719e4a1100SKrzysztof Kozlowski return err; 18729e4a1100SKrzysztof Kozlowski 18739e4a1100SKrzysztof Kozlowski sg = dev->sg_src_cpy; 18749e4a1100SKrzysztof Kozlowski } 18759e4a1100SKrzysztof Kozlowski 18769e4a1100SKrzysztof Kozlowski err = s5p_set_indata(dev, sg); 18779e4a1100SKrzysztof Kozlowski if (err) { 18789e4a1100SKrzysztof Kozlowski s5p_free_sg_cpy(dev, &dev->sg_src_cpy); 18799e4a1100SKrzysztof Kozlowski return err; 18809e4a1100SKrzysztof Kozlowski } 18819e4a1100SKrzysztof Kozlowski 18829e4a1100SKrzysztof Kozlowski return 0; 18839e4a1100SKrzysztof Kozlowski } 18849e4a1100SKrzysztof Kozlowski 18859e4a1100SKrzysztof Kozlowski static int s5p_set_outdata_start(struct s5p_aes_dev *dev, 18869e4a1100SKrzysztof Kozlowski struct ablkcipher_request *req) 18879e4a1100SKrzysztof Kozlowski { 18889e4a1100SKrzysztof Kozlowski struct scatterlist *sg; 18899e4a1100SKrzysztof Kozlowski int err; 18909e4a1100SKrzysztof Kozlowski 18919e4a1100SKrzysztof Kozlowski dev->sg_dst_cpy = NULL; 18929e4a1100SKrzysztof Kozlowski sg = req->dst; 18939e4a1100SKrzysztof Kozlowski if (!s5p_is_sg_aligned(sg)) { 18949e4a1100SKrzysztof Kozlowski dev_dbg(dev->dev, 18959e4a1100SKrzysztof Kozlowski "At least one unaligned dest scatter list, making a copy\n"); 18969e4a1100SKrzysztof Kozlowski err = s5p_make_sg_cpy(dev, sg, &dev->sg_dst_cpy); 18979e4a1100SKrzysztof Kozlowski if (err) 18989e4a1100SKrzysztof Kozlowski return err; 18999e4a1100SKrzysztof Kozlowski 19009e4a1100SKrzysztof Kozlowski sg = dev->sg_dst_cpy; 19019e4a1100SKrzysztof Kozlowski } 19029e4a1100SKrzysztof Kozlowski 19039e4a1100SKrzysztof Kozlowski err = s5p_set_outdata(dev, sg); 19049e4a1100SKrzysztof Kozlowski if (err) { 19059e4a1100SKrzysztof Kozlowski s5p_free_sg_cpy(dev, &dev->sg_dst_cpy); 19069e4a1100SKrzysztof Kozlowski return err; 19079e4a1100SKrzysztof Kozlowski } 19089e4a1100SKrzysztof Kozlowski 19099e4a1100SKrzysztof Kozlowski return 0; 19109e4a1100SKrzysztof Kozlowski } 19119e4a1100SKrzysztof Kozlowski 1912a49e490cSVladimir Zapolskiy static void s5p_aes_crypt_start(struct s5p_aes_dev *dev, unsigned long mode) 1913a49e490cSVladimir Zapolskiy { 1914a49e490cSVladimir Zapolskiy struct ablkcipher_request *req = dev->req; 1915b1b4416fSChristoph Manszewski u32 aes_control; 1916a49e490cSVladimir Zapolskiy unsigned long flags; 19175318c53dSKrzysztof Kozlowski int err; 1918cdf640a6SChristoph Manszewski u8 *iv, *ctr; 1919a49e490cSVladimir Zapolskiy 1920cdf640a6SChristoph Manszewski /* This sets bit [13:12] to 00, which selects 128-bit counter */ 1921a49e490cSVladimir Zapolskiy aes_control = SSS_AES_KEY_CHANGE_MODE; 1922a49e490cSVladimir Zapolskiy if (mode & FLAGS_AES_DECRYPT) 1923a49e490cSVladimir Zapolskiy aes_control |= SSS_AES_MODE_DECRYPT; 1924a49e490cSVladimir Zapolskiy 1925c927b080SKamil Konieczny if ((mode & FLAGS_AES_MODE_MASK) == FLAGS_AES_CBC) { 1926a49e490cSVladimir Zapolskiy aes_control |= SSS_AES_CHAIN_MODE_CBC; 1927c927b080SKamil Konieczny iv = req->info; 1928cdf640a6SChristoph Manszewski ctr = NULL; 1929c927b080SKamil Konieczny } else if ((mode & FLAGS_AES_MODE_MASK) == FLAGS_AES_CTR) { 1930a49e490cSVladimir Zapolskiy aes_control |= SSS_AES_CHAIN_MODE_CTR; 1931cdf640a6SChristoph Manszewski iv = NULL; 1932cdf640a6SChristoph Manszewski ctr = req->info; 1933c927b080SKamil Konieczny } else { 1934c927b080SKamil Konieczny iv = NULL; /* AES_ECB */ 1935cdf640a6SChristoph Manszewski ctr = NULL; 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); 1967cdf640a6SChristoph Manszewski s5p_set_aes(dev, dev->ctx->aes_key, iv, ctr, 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); 19865842cd44SChristoph Manszewski s5p_aes_complete(req, 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); 2027b1b4416fSChristoph Manszewski return err; 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 return err; 2036a49e490cSVladimir Zapolskiy } 2037a49e490cSVladimir Zapolskiy 2038a49e490cSVladimir Zapolskiy static int s5p_aes_crypt(struct ablkcipher_request *req, unsigned long mode) 2039a49e490cSVladimir Zapolskiy { 2040a49e490cSVladimir Zapolskiy struct crypto_ablkcipher *tfm = crypto_ablkcipher_reqtfm(req); 2041a49e490cSVladimir Zapolskiy struct s5p_aes_reqctx *reqctx = ablkcipher_request_ctx(req); 20425318c53dSKrzysztof Kozlowski struct s5p_aes_ctx *ctx = crypto_ablkcipher_ctx(tfm); 2043a49e490cSVladimir Zapolskiy struct s5p_aes_dev *dev = ctx->dev; 2044a49e490cSVladimir Zapolskiy 2045cdf640a6SChristoph Manszewski if (!IS_ALIGNED(req->nbytes, AES_BLOCK_SIZE) && 2046cdf640a6SChristoph Manszewski ((mode & FLAGS_AES_MODE_MASK) != FLAGS_AES_CTR)) { 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, 2057b1b4416fSChristoph Manszewski const u8 *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 2093cdf640a6SChristoph Manszewski static int s5p_aes_ctr_crypt(struct ablkcipher_request *req) 2094cdf640a6SChristoph Manszewski { 2095cdf640a6SChristoph Manszewski return s5p_aes_crypt(req, FLAGS_AES_CTR); 2096cdf640a6SChristoph Manszewski } 2097cdf640a6SChristoph Manszewski 2098a49e490cSVladimir Zapolskiy static int s5p_aes_cra_init(struct crypto_tfm *tfm) 2099a49e490cSVladimir Zapolskiy { 2100a49e490cSVladimir Zapolskiy struct s5p_aes_ctx *ctx = crypto_tfm_ctx(tfm); 2101a49e490cSVladimir Zapolskiy 2102a49e490cSVladimir Zapolskiy ctx->dev = s5p_dev; 2103a49e490cSVladimir Zapolskiy tfm->crt_ablkcipher.reqsize = sizeof(struct s5p_aes_reqctx); 2104a49e490cSVladimir Zapolskiy 2105a49e490cSVladimir Zapolskiy return 0; 2106a49e490cSVladimir Zapolskiy } 2107a49e490cSVladimir Zapolskiy 2108a49e490cSVladimir Zapolskiy static struct crypto_alg algs[] = { 2109a49e490cSVladimir Zapolskiy { 2110a49e490cSVladimir Zapolskiy .cra_name = "ecb(aes)", 2111a49e490cSVladimir Zapolskiy .cra_driver_name = "ecb-aes-s5p", 2112a49e490cSVladimir Zapolskiy .cra_priority = 100, 2113a49e490cSVladimir Zapolskiy .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | 2114d912bb76SNikos Mavrogiannopoulos CRYPTO_ALG_ASYNC | 2115d912bb76SNikos Mavrogiannopoulos CRYPTO_ALG_KERN_DRIVER_ONLY, 2116a49e490cSVladimir Zapolskiy .cra_blocksize = AES_BLOCK_SIZE, 2117a49e490cSVladimir Zapolskiy .cra_ctxsize = sizeof(struct s5p_aes_ctx), 2118a49e490cSVladimir Zapolskiy .cra_alignmask = 0x0f, 2119a49e490cSVladimir Zapolskiy .cra_type = &crypto_ablkcipher_type, 2120a49e490cSVladimir Zapolskiy .cra_module = THIS_MODULE, 2121a49e490cSVladimir Zapolskiy .cra_init = s5p_aes_cra_init, 2122a49e490cSVladimir Zapolskiy .cra_u.ablkcipher = { 2123a49e490cSVladimir Zapolskiy .min_keysize = AES_MIN_KEY_SIZE, 2124a49e490cSVladimir Zapolskiy .max_keysize = AES_MAX_KEY_SIZE, 2125a49e490cSVladimir Zapolskiy .setkey = s5p_aes_setkey, 2126a49e490cSVladimir Zapolskiy .encrypt = s5p_aes_ecb_encrypt, 2127a49e490cSVladimir Zapolskiy .decrypt = s5p_aes_ecb_decrypt, 2128a49e490cSVladimir Zapolskiy } 2129a49e490cSVladimir Zapolskiy }, 2130a49e490cSVladimir Zapolskiy { 2131a49e490cSVladimir Zapolskiy .cra_name = "cbc(aes)", 2132a49e490cSVladimir Zapolskiy .cra_driver_name = "cbc-aes-s5p", 2133a49e490cSVladimir Zapolskiy .cra_priority = 100, 2134a49e490cSVladimir Zapolskiy .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | 2135d912bb76SNikos Mavrogiannopoulos CRYPTO_ALG_ASYNC | 2136d912bb76SNikos Mavrogiannopoulos CRYPTO_ALG_KERN_DRIVER_ONLY, 2137a49e490cSVladimir Zapolskiy .cra_blocksize = AES_BLOCK_SIZE, 2138a49e490cSVladimir Zapolskiy .cra_ctxsize = sizeof(struct s5p_aes_ctx), 2139a49e490cSVladimir Zapolskiy .cra_alignmask = 0x0f, 2140a49e490cSVladimir Zapolskiy .cra_type = &crypto_ablkcipher_type, 2141a49e490cSVladimir Zapolskiy .cra_module = THIS_MODULE, 2142a49e490cSVladimir Zapolskiy .cra_init = s5p_aes_cra_init, 2143a49e490cSVladimir Zapolskiy .cra_u.ablkcipher = { 2144a49e490cSVladimir Zapolskiy .min_keysize = AES_MIN_KEY_SIZE, 2145a49e490cSVladimir Zapolskiy .max_keysize = AES_MAX_KEY_SIZE, 2146a49e490cSVladimir Zapolskiy .ivsize = AES_BLOCK_SIZE, 2147a49e490cSVladimir Zapolskiy .setkey = s5p_aes_setkey, 2148a49e490cSVladimir Zapolskiy .encrypt = s5p_aes_cbc_encrypt, 2149a49e490cSVladimir Zapolskiy .decrypt = s5p_aes_cbc_decrypt, 2150a49e490cSVladimir Zapolskiy } 2151a49e490cSVladimir Zapolskiy }, 2152cdf640a6SChristoph Manszewski { 2153cdf640a6SChristoph Manszewski .cra_name = "ctr(aes)", 2154cdf640a6SChristoph Manszewski .cra_driver_name = "ctr-aes-s5p", 2155cdf640a6SChristoph Manszewski .cra_priority = 100, 2156cdf640a6SChristoph Manszewski .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | 2157cdf640a6SChristoph Manszewski CRYPTO_ALG_ASYNC | 2158cdf640a6SChristoph Manszewski CRYPTO_ALG_KERN_DRIVER_ONLY, 2159cdf640a6SChristoph Manszewski .cra_blocksize = AES_BLOCK_SIZE, 2160cdf640a6SChristoph Manszewski .cra_ctxsize = sizeof(struct s5p_aes_ctx), 2161cdf640a6SChristoph Manszewski .cra_alignmask = 0x0f, 2162cdf640a6SChristoph Manszewski .cra_type = &crypto_ablkcipher_type, 2163cdf640a6SChristoph Manszewski .cra_module = THIS_MODULE, 2164cdf640a6SChristoph Manszewski .cra_init = s5p_aes_cra_init, 2165cdf640a6SChristoph Manszewski .cra_u.ablkcipher = { 2166cdf640a6SChristoph Manszewski .min_keysize = AES_MIN_KEY_SIZE, 2167cdf640a6SChristoph Manszewski .max_keysize = AES_MAX_KEY_SIZE, 2168cdf640a6SChristoph Manszewski .ivsize = AES_BLOCK_SIZE, 2169cdf640a6SChristoph Manszewski .setkey = s5p_aes_setkey, 2170cdf640a6SChristoph Manszewski .encrypt = s5p_aes_ctr_crypt, 2171cdf640a6SChristoph Manszewski .decrypt = s5p_aes_ctr_crypt, 2172cdf640a6SChristoph Manszewski } 2173cdf640a6SChristoph Manszewski }, 2174a49e490cSVladimir Zapolskiy }; 2175a49e490cSVladimir Zapolskiy 2176a49e490cSVladimir Zapolskiy static int s5p_aes_probe(struct platform_device *pdev) 2177a49e490cSVladimir Zapolskiy { 2178a49e490cSVladimir Zapolskiy struct device *dev = &pdev->dev; 21795318c53dSKrzysztof Kozlowski int i, j, err = -ENODEV; 21806584eacbSKrzysztof Kozlowski const struct samsung_aes_variant *variant; 21815318c53dSKrzysztof Kozlowski struct s5p_aes_dev *pdata; 21825318c53dSKrzysztof Kozlowski struct resource *res; 2183c2afad6cSKamil Konieczny unsigned int hash_i; 2184a49e490cSVladimir Zapolskiy 2185a49e490cSVladimir Zapolskiy if (s5p_dev) 2186a49e490cSVladimir Zapolskiy return -EEXIST; 2187a49e490cSVladimir Zapolskiy 2188a49e490cSVladimir Zapolskiy pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); 2189a49e490cSVladimir Zapolskiy if (!pdata) 2190a49e490cSVladimir Zapolskiy return -ENOMEM; 2191a49e490cSVladimir Zapolskiy 2192c2afad6cSKamil Konieczny variant = find_s5p_sss_version(pdev); 21930fdefe2cSJingoo Han res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 2194c2afad6cSKamil Konieczny 2195c2afad6cSKamil Konieczny /* 2196c2afad6cSKamil Konieczny * Note: HASH and PRNG uses the same registers in secss, avoid 2197c2afad6cSKamil Konieczny * overwrite each other. This will drop HASH when CONFIG_EXYNOS_RNG 2198c2afad6cSKamil Konieczny * is enabled in config. We need larger size for HASH registers in 2199c2afad6cSKamil Konieczny * secss, current describe only AES/DES 2200c2afad6cSKamil Konieczny */ 2201c2afad6cSKamil Konieczny if (IS_ENABLED(CONFIG_CRYPTO_DEV_EXYNOS_HASH)) { 2202c2afad6cSKamil Konieczny if (variant == &exynos_aes_data) { 2203c2afad6cSKamil Konieczny res->end += 0x300; 2204c2afad6cSKamil Konieczny pdata->use_hash = true; 2205c2afad6cSKamil Konieczny } 2206c2afad6cSKamil Konieczny } 2207c2afad6cSKamil Konieczny 2208c2afad6cSKamil Konieczny pdata->res = res; 2209c2afad6cSKamil Konieczny pdata->ioaddr = devm_ioremap_resource(&pdev->dev, res); 2210c2afad6cSKamil Konieczny if (IS_ERR(pdata->ioaddr)) { 2211c2afad6cSKamil Konieczny if (!pdata->use_hash) 2212c2afad6cSKamil Konieczny return PTR_ERR(pdata->ioaddr); 2213c2afad6cSKamil Konieczny /* try AES without HASH */ 2214c2afad6cSKamil Konieczny res->end -= 0x300; 2215c2afad6cSKamil Konieczny pdata->use_hash = false; 22160fdefe2cSJingoo Han pdata->ioaddr = devm_ioremap_resource(&pdev->dev, res); 22170fdefe2cSJingoo Han if (IS_ERR(pdata->ioaddr)) 22180fdefe2cSJingoo Han return PTR_ERR(pdata->ioaddr); 2219c2afad6cSKamil Konieczny } 222089245107SNaveen Krishna Chatradhi 22215c22ba66SJingoo Han pdata->clk = devm_clk_get(dev, "secss"); 2222a49e490cSVladimir Zapolskiy if (IS_ERR(pdata->clk)) { 2223a49e490cSVladimir Zapolskiy dev_err(dev, "failed to find secss clock source\n"); 2224a49e490cSVladimir Zapolskiy return -ENOENT; 2225a49e490cSVladimir Zapolskiy } 2226a49e490cSVladimir Zapolskiy 2227c1eb7ef2SNaveen Krishna Chatradhi err = clk_prepare_enable(pdata->clk); 2228c1eb7ef2SNaveen Krishna Chatradhi if (err < 0) { 2229c1eb7ef2SNaveen Krishna Chatradhi dev_err(dev, "Enabling SSS clk failed, err %d\n", err); 2230c1eb7ef2SNaveen Krishna Chatradhi return err; 2231c1eb7ef2SNaveen Krishna Chatradhi } 2232a49e490cSVladimir Zapolskiy 2233a49e490cSVladimir Zapolskiy spin_lock_init(&pdata->lock); 2234c2afad6cSKamil Konieczny spin_lock_init(&pdata->hash_lock); 2235a49e490cSVladimir Zapolskiy 223689245107SNaveen Krishna Chatradhi pdata->aes_ioaddr = pdata->ioaddr + variant->aes_offset; 2237c2afad6cSKamil Konieczny pdata->io_hash_base = pdata->ioaddr + variant->hash_offset; 223889245107SNaveen Krishna Chatradhi 223996fc70b6SNaveen Krishna Chatradhi pdata->irq_fc = platform_get_irq(pdev, 0); 2240a49e490cSVladimir Zapolskiy if (pdata->irq_fc < 0) { 2241a49e490cSVladimir Zapolskiy err = pdata->irq_fc; 2242a49e490cSVladimir Zapolskiy dev_warn(dev, "feed control interrupt is not available.\n"); 2243a49e490cSVladimir Zapolskiy goto err_irq; 2244a49e490cSVladimir Zapolskiy } 224507de4bc8SKrzysztof Kozlowski err = devm_request_threaded_irq(dev, pdata->irq_fc, NULL, 224607de4bc8SKrzysztof Kozlowski s5p_aes_interrupt, IRQF_ONESHOT, 224707de4bc8SKrzysztof Kozlowski pdev->name, pdev); 2248a49e490cSVladimir Zapolskiy if (err < 0) { 2249a49e490cSVladimir Zapolskiy dev_warn(dev, "feed control interrupt is not available.\n"); 2250a49e490cSVladimir Zapolskiy goto err_irq; 2251a49e490cSVladimir Zapolskiy } 2252a49e490cSVladimir Zapolskiy 2253dc5e3f19SNaveen Krishna Chatradhi pdata->busy = false; 2254a49e490cSVladimir Zapolskiy pdata->dev = dev; 2255a49e490cSVladimir Zapolskiy platform_set_drvdata(pdev, pdata); 2256a49e490cSVladimir Zapolskiy s5p_dev = pdata; 2257a49e490cSVladimir Zapolskiy 2258a49e490cSVladimir Zapolskiy tasklet_init(&pdata->tasklet, s5p_tasklet_cb, (unsigned long)pdata); 2259a49e490cSVladimir Zapolskiy crypto_init_queue(&pdata->queue, CRYPTO_QUEUE_LEN); 2260a49e490cSVladimir Zapolskiy 2261a49e490cSVladimir Zapolskiy for (i = 0; i < ARRAY_SIZE(algs); i++) { 2262a49e490cSVladimir Zapolskiy err = crypto_register_alg(&algs[i]); 2263a49e490cSVladimir Zapolskiy if (err) 2264a49e490cSVladimir Zapolskiy goto err_algs; 2265a49e490cSVladimir Zapolskiy } 2266a49e490cSVladimir Zapolskiy 2267c2afad6cSKamil Konieczny if (pdata->use_hash) { 2268c2afad6cSKamil Konieczny tasklet_init(&pdata->hash_tasklet, s5p_hash_tasklet_cb, 2269c2afad6cSKamil Konieczny (unsigned long)pdata); 2270c2afad6cSKamil Konieczny crypto_init_queue(&pdata->hash_queue, SSS_HASH_QUEUE_LENGTH); 2271c2afad6cSKamil Konieczny 2272c2afad6cSKamil Konieczny for (hash_i = 0; hash_i < ARRAY_SIZE(algs_sha1_md5_sha256); 2273c2afad6cSKamil Konieczny hash_i++) { 2274c2afad6cSKamil Konieczny struct ahash_alg *alg; 2275c2afad6cSKamil Konieczny 2276c2afad6cSKamil Konieczny alg = &algs_sha1_md5_sha256[hash_i]; 2277c2afad6cSKamil Konieczny err = crypto_register_ahash(alg); 2278c2afad6cSKamil Konieczny if (err) { 2279c2afad6cSKamil Konieczny dev_err(dev, "can't register '%s': %d\n", 2280c2afad6cSKamil Konieczny alg->halg.base.cra_driver_name, err); 2281c2afad6cSKamil Konieczny goto err_hash; 2282c2afad6cSKamil Konieczny } 2283c2afad6cSKamil Konieczny } 2284c2afad6cSKamil Konieczny } 2285c2afad6cSKamil Konieczny 2286313becd1SKrzysztof Koz?owski dev_info(dev, "s5p-sss driver registered\n"); 2287a49e490cSVladimir Zapolskiy 2288a49e490cSVladimir Zapolskiy return 0; 2289a49e490cSVladimir Zapolskiy 2290c2afad6cSKamil Konieczny err_hash: 2291c2afad6cSKamil Konieczny for (j = hash_i - 1; j >= 0; j--) 2292c2afad6cSKamil Konieczny crypto_unregister_ahash(&algs_sha1_md5_sha256[j]); 2293c2afad6cSKamil Konieczny 2294c2afad6cSKamil Konieczny tasklet_kill(&pdata->hash_tasklet); 2295c2afad6cSKamil Konieczny res->end -= 0x300; 2296c2afad6cSKamil Konieczny 2297a49e490cSVladimir Zapolskiy err_algs: 2298c2afad6cSKamil Konieczny if (i < ARRAY_SIZE(algs)) 2299c2afad6cSKamil Konieczny dev_err(dev, "can't register '%s': %d\n", algs[i].cra_name, 2300c2afad6cSKamil Konieczny err); 2301a49e490cSVladimir Zapolskiy 2302a49e490cSVladimir Zapolskiy for (j = 0; j < i; j++) 2303a49e490cSVladimir Zapolskiy crypto_unregister_alg(&algs[j]); 2304a49e490cSVladimir Zapolskiy 2305a49e490cSVladimir Zapolskiy tasklet_kill(&pdata->tasklet); 2306a49e490cSVladimir Zapolskiy 2307a49e490cSVladimir Zapolskiy err_irq: 2308c1eb7ef2SNaveen Krishna Chatradhi clk_disable_unprepare(pdata->clk); 2309a49e490cSVladimir Zapolskiy 2310a49e490cSVladimir Zapolskiy s5p_dev = NULL; 2311a49e490cSVladimir Zapolskiy 2312a49e490cSVladimir Zapolskiy return err; 2313a49e490cSVladimir Zapolskiy } 2314a49e490cSVladimir Zapolskiy 2315a49e490cSVladimir Zapolskiy static int s5p_aes_remove(struct platform_device *pdev) 2316a49e490cSVladimir Zapolskiy { 2317a49e490cSVladimir Zapolskiy struct s5p_aes_dev *pdata = platform_get_drvdata(pdev); 2318a49e490cSVladimir Zapolskiy int i; 2319a49e490cSVladimir Zapolskiy 2320a49e490cSVladimir Zapolskiy if (!pdata) 2321a49e490cSVladimir Zapolskiy return -ENODEV; 2322a49e490cSVladimir Zapolskiy 2323a49e490cSVladimir Zapolskiy for (i = 0; i < ARRAY_SIZE(algs); i++) 2324a49e490cSVladimir Zapolskiy crypto_unregister_alg(&algs[i]); 2325a49e490cSVladimir Zapolskiy 2326a49e490cSVladimir Zapolskiy tasklet_kill(&pdata->tasklet); 2327c2afad6cSKamil Konieczny if (pdata->use_hash) { 2328c2afad6cSKamil Konieczny for (i = ARRAY_SIZE(algs_sha1_md5_sha256) - 1; i >= 0; i--) 2329c2afad6cSKamil Konieczny crypto_unregister_ahash(&algs_sha1_md5_sha256[i]); 2330c2afad6cSKamil Konieczny 2331c2afad6cSKamil Konieczny pdata->res->end -= 0x300; 2332c2afad6cSKamil Konieczny tasklet_kill(&pdata->hash_tasklet); 2333c2afad6cSKamil Konieczny pdata->use_hash = false; 2334c2afad6cSKamil Konieczny } 2335a49e490cSVladimir Zapolskiy 2336c1eb7ef2SNaveen Krishna Chatradhi clk_disable_unprepare(pdata->clk); 2337a49e490cSVladimir Zapolskiy s5p_dev = NULL; 2338a49e490cSVladimir Zapolskiy 2339a49e490cSVladimir Zapolskiy return 0; 2340a49e490cSVladimir Zapolskiy } 2341a49e490cSVladimir Zapolskiy 2342a49e490cSVladimir Zapolskiy static struct platform_driver s5p_aes_crypto = { 2343a49e490cSVladimir Zapolskiy .probe = s5p_aes_probe, 2344a49e490cSVladimir Zapolskiy .remove = s5p_aes_remove, 2345a49e490cSVladimir Zapolskiy .driver = { 2346a49e490cSVladimir Zapolskiy .name = "s5p-secss", 23476b9f16e6SNaveen Krishna Chatradhi .of_match_table = s5p_sss_dt_match, 2348a49e490cSVladimir Zapolskiy }, 2349a49e490cSVladimir Zapolskiy }; 2350a49e490cSVladimir Zapolskiy 2351741e8c2dSAxel Lin module_platform_driver(s5p_aes_crypto); 2352a49e490cSVladimir Zapolskiy 2353a49e490cSVladimir Zapolskiy MODULE_DESCRIPTION("S5PV210 AES hw acceleration support."); 2354a49e490cSVladimir Zapolskiy MODULE_LICENSE("GPL v2"); 2355a49e490cSVladimir Zapolskiy MODULE_AUTHOR("Vladimir Zapolskiy <vzapolskiy@gmail.com>"); 2356c2afad6cSKamil Konieczny MODULE_AUTHOR("Kamil Konieczny <k.konieczny@partner.samsung.com>"); 2357