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. 2350918f18cSKamil Konieczny * @clk_names: names of clocks needed to run SSS IP 23689245107SNaveen Krishna Chatradhi * 23789245107SNaveen Krishna Chatradhi * Specifies platform specific configuration of SSS module. 23889245107SNaveen Krishna Chatradhi * Note: A structure for driver specific platform data is used for future 23989245107SNaveen Krishna Chatradhi * expansion of its usage. 24089245107SNaveen Krishna Chatradhi */ 24189245107SNaveen Krishna Chatradhi struct samsung_aes_variant { 24289245107SNaveen Krishna Chatradhi unsigned int aes_offset; 243c2afad6cSKamil Konieczny unsigned int hash_offset; 2440918f18cSKamil Konieczny const char *clk_names[]; 24589245107SNaveen Krishna Chatradhi }; 24689245107SNaveen Krishna Chatradhi 247a49e490cSVladimir Zapolskiy struct s5p_aes_reqctx { 248a49e490cSVladimir Zapolskiy unsigned long mode; 249a49e490cSVladimir Zapolskiy }; 250a49e490cSVladimir Zapolskiy 251a49e490cSVladimir Zapolskiy struct s5p_aes_ctx { 252a49e490cSVladimir Zapolskiy struct s5p_aes_dev *dev; 253a49e490cSVladimir Zapolskiy 254b1b4416fSChristoph Manszewski u8 aes_key[AES_MAX_KEY_SIZE]; 255b1b4416fSChristoph Manszewski u8 nonce[CTR_RFC3686_NONCE_SIZE]; 256a49e490cSVladimir Zapolskiy int keylen; 257a49e490cSVladimir Zapolskiy }; 258a49e490cSVladimir Zapolskiy 259106d7334SKrzysztof Kozlowski /** 260106d7334SKrzysztof Kozlowski * struct s5p_aes_dev - Crypto device state container 261106d7334SKrzysztof Kozlowski * @dev: Associated device 262106d7334SKrzysztof Kozlowski * @clk: Clock for accessing hardware 263106d7334SKrzysztof Kozlowski * @ioaddr: Mapped IO memory region 264106d7334SKrzysztof Kozlowski * @aes_ioaddr: Per-varian offset for AES block IO memory 265106d7334SKrzysztof Kozlowski * @irq_fc: Feed control interrupt line 266106d7334SKrzysztof Kozlowski * @req: Crypto request currently handled by the device 267106d7334SKrzysztof Kozlowski * @ctx: Configuration for currently handled crypto request 268106d7334SKrzysztof Kozlowski * @sg_src: Scatter list with source data for currently handled block 269106d7334SKrzysztof Kozlowski * in device. This is DMA-mapped into device. 270106d7334SKrzysztof Kozlowski * @sg_dst: Scatter list with destination data for currently handled block 271106d7334SKrzysztof Kozlowski * in device. This is DMA-mapped into device. 272106d7334SKrzysztof Kozlowski * @sg_src_cpy: In case of unaligned access, copied scatter list 273106d7334SKrzysztof Kozlowski * with source data. 274106d7334SKrzysztof Kozlowski * @sg_dst_cpy: In case of unaligned access, copied scatter list 275106d7334SKrzysztof Kozlowski * with destination data. 276106d7334SKrzysztof Kozlowski * @tasklet: New request scheduling jib 277106d7334SKrzysztof Kozlowski * @queue: Crypto queue 278106d7334SKrzysztof Kozlowski * @busy: Indicates whether the device is currently handling some request 279106d7334SKrzysztof Kozlowski * thus it uses some of the fields from this state, like: 280106d7334SKrzysztof Kozlowski * req, ctx, sg_src/dst (and copies). This essentially 281106d7334SKrzysztof Kozlowski * protects against concurrent access to these fields. 282106d7334SKrzysztof Kozlowski * @lock: Lock for protecting both access to device hardware registers 283106d7334SKrzysztof Kozlowski * and fields related to current request (including the busy field). 284c2afad6cSKamil Konieczny * @res: Resources for hash. 285c2afad6cSKamil Konieczny * @io_hash_base: Per-variant offset for HASH block IO memory. 286c2afad6cSKamil Konieczny * @hash_lock: Lock for protecting hash_req, hash_queue and hash_flags 287c2afad6cSKamil Konieczny * variable. 288c2afad6cSKamil Konieczny * @hash_flags: Flags for current HASH op. 289c2afad6cSKamil Konieczny * @hash_queue: Async hash queue. 290c2afad6cSKamil Konieczny * @hash_tasklet: New HASH request scheduling job. 291c2afad6cSKamil Konieczny * @xmit_buf: Buffer for current HASH request transfer into SSS block. 292c2afad6cSKamil Konieczny * @hash_req: Current request sending to SSS HASH block. 293c2afad6cSKamil Konieczny * @hash_sg_iter: Scatterlist transferred through DMA into SSS HASH block. 294c2afad6cSKamil Konieczny * @hash_sg_cnt: Counter for hash_sg_iter. 295c2afad6cSKamil Konieczny * 296c2afad6cSKamil Konieczny * @use_hash: true if HASH algs enabled 297106d7334SKrzysztof Kozlowski */ 298a49e490cSVladimir Zapolskiy struct s5p_aes_dev { 299a49e490cSVladimir Zapolskiy struct device *dev; 300a49e490cSVladimir Zapolskiy struct clk *clk; 3010918f18cSKamil Konieczny struct clk *pclk; 302a49e490cSVladimir Zapolskiy void __iomem *ioaddr; 30389245107SNaveen Krishna Chatradhi void __iomem *aes_ioaddr; 304a49e490cSVladimir Zapolskiy int irq_fc; 305a49e490cSVladimir Zapolskiy 306a49e490cSVladimir Zapolskiy struct ablkcipher_request *req; 307a49e490cSVladimir Zapolskiy struct s5p_aes_ctx *ctx; 308a49e490cSVladimir Zapolskiy struct scatterlist *sg_src; 309a49e490cSVladimir Zapolskiy struct scatterlist *sg_dst; 310a49e490cSVladimir Zapolskiy 3119e4a1100SKrzysztof Kozlowski struct scatterlist *sg_src_cpy; 3129e4a1100SKrzysztof Kozlowski struct scatterlist *sg_dst_cpy; 3139e4a1100SKrzysztof Kozlowski 314a49e490cSVladimir Zapolskiy struct tasklet_struct tasklet; 315a49e490cSVladimir Zapolskiy struct crypto_queue queue; 316a49e490cSVladimir Zapolskiy bool busy; 317a49e490cSVladimir Zapolskiy spinlock_t lock; 318c2afad6cSKamil Konieczny 319c2afad6cSKamil Konieczny struct resource *res; 320c2afad6cSKamil Konieczny void __iomem *io_hash_base; 321c2afad6cSKamil Konieczny 322c2afad6cSKamil Konieczny spinlock_t hash_lock; /* protect hash_ vars */ 323c2afad6cSKamil Konieczny unsigned long hash_flags; 324c2afad6cSKamil Konieczny struct crypto_queue hash_queue; 325c2afad6cSKamil Konieczny struct tasklet_struct hash_tasklet; 326c2afad6cSKamil Konieczny 327c2afad6cSKamil Konieczny u8 xmit_buf[BUFLEN]; 328c2afad6cSKamil Konieczny struct ahash_request *hash_req; 329c2afad6cSKamil Konieczny struct scatterlist *hash_sg_iter; 330c2afad6cSKamil Konieczny unsigned int hash_sg_cnt; 331c2afad6cSKamil Konieczny 332c2afad6cSKamil Konieczny bool use_hash; 333a49e490cSVladimir Zapolskiy }; 334a49e490cSVladimir Zapolskiy 335c2afad6cSKamil Konieczny /** 336c2afad6cSKamil Konieczny * struct s5p_hash_reqctx - HASH request context 337c2afad6cSKamil Konieczny * @dd: Associated device 338c2afad6cSKamil Konieczny * @op_update: Current request operation (OP_UPDATE or OP_FINAL) 339c2afad6cSKamil Konieczny * @digcnt: Number of bytes processed by HW (without buffer[] ones) 340c2afad6cSKamil Konieczny * @digest: Digest message or IV for partial result 341c2afad6cSKamil Konieczny * @nregs: Number of HW registers for digest or IV read/write 342c2afad6cSKamil Konieczny * @engine: Bits for selecting type of HASH in SSS block 343c2afad6cSKamil Konieczny * @sg: sg for DMA transfer 344c2afad6cSKamil Konieczny * @sg_len: Length of sg for DMA transfer 345c2afad6cSKamil Konieczny * @sgl[]: sg for joining buffer and req->src scatterlist 346c2afad6cSKamil Konieczny * @skip: Skip offset in req->src for current op 347c2afad6cSKamil Konieczny * @total: Total number of bytes for current request 348c2afad6cSKamil Konieczny * @finup: Keep state for finup or final. 349c2afad6cSKamil Konieczny * @error: Keep track of error. 350c2afad6cSKamil Konieczny * @bufcnt: Number of bytes holded in buffer[] 351c2afad6cSKamil Konieczny * @buffer[]: For byte(s) from end of req->src in UPDATE op 352c2afad6cSKamil Konieczny */ 353c2afad6cSKamil Konieczny struct s5p_hash_reqctx { 354c2afad6cSKamil Konieczny struct s5p_aes_dev *dd; 355c2afad6cSKamil Konieczny bool op_update; 356c2afad6cSKamil Konieczny 357c2afad6cSKamil Konieczny u64 digcnt; 358c2afad6cSKamil Konieczny u8 digest[SHA256_DIGEST_SIZE]; 359c2afad6cSKamil Konieczny 360c2afad6cSKamil Konieczny unsigned int nregs; /* digest_size / sizeof(reg) */ 361c2afad6cSKamil Konieczny u32 engine; 362c2afad6cSKamil Konieczny 363c2afad6cSKamil Konieczny struct scatterlist *sg; 364c2afad6cSKamil Konieczny unsigned int sg_len; 365c2afad6cSKamil Konieczny struct scatterlist sgl[2]; 366c2afad6cSKamil Konieczny unsigned int skip; 367c2afad6cSKamil Konieczny unsigned int total; 368c2afad6cSKamil Konieczny bool finup; 369c2afad6cSKamil Konieczny bool error; 370c2afad6cSKamil Konieczny 371c2afad6cSKamil Konieczny u32 bufcnt; 372c2afad6cSKamil Konieczny u8 buffer[0]; 373c2afad6cSKamil Konieczny }; 374c2afad6cSKamil Konieczny 375c2afad6cSKamil Konieczny /** 376c2afad6cSKamil Konieczny * struct s5p_hash_ctx - HASH transformation context 377c2afad6cSKamil Konieczny * @dd: Associated device 378c2afad6cSKamil Konieczny * @flags: Bits for algorithm HASH. 379c2afad6cSKamil Konieczny * @fallback: Software transformation for zero message or size < BUFLEN. 380c2afad6cSKamil Konieczny */ 381c2afad6cSKamil Konieczny struct s5p_hash_ctx { 382c2afad6cSKamil Konieczny struct s5p_aes_dev *dd; 383c2afad6cSKamil Konieczny unsigned long flags; 384c2afad6cSKamil Konieczny struct crypto_shash *fallback; 385c2afad6cSKamil Konieczny }; 386a49e490cSVladimir Zapolskiy 38789245107SNaveen Krishna Chatradhi static const struct samsung_aes_variant s5p_aes_data = { 38889245107SNaveen Krishna Chatradhi .aes_offset = 0x4000, 389c2afad6cSKamil Konieczny .hash_offset = 0x6000, 3900918f18cSKamil Konieczny .clk_names = { "secss", }, 39189245107SNaveen Krishna Chatradhi }; 39289245107SNaveen Krishna Chatradhi 39389245107SNaveen Krishna Chatradhi static const struct samsung_aes_variant exynos_aes_data = { 39489245107SNaveen Krishna Chatradhi .aes_offset = 0x200, 395c2afad6cSKamil Konieczny .hash_offset = 0x400, 3960918f18cSKamil Konieczny .clk_names = { "secss", }, 3970918f18cSKamil Konieczny }; 3980918f18cSKamil Konieczny 3990918f18cSKamil Konieczny static const struct samsung_aes_variant exynos5433_slim_aes_data = { 4000918f18cSKamil Konieczny .aes_offset = 0x400, 4010918f18cSKamil Konieczny .hash_offset = 0x800, 4020918f18cSKamil Konieczny .clk_names = { "pclk", "aclk", }, 40389245107SNaveen Krishna Chatradhi }; 40489245107SNaveen Krishna Chatradhi 4056b9f16e6SNaveen Krishna Chatradhi static const struct of_device_id s5p_sss_dt_match[] = { 40689245107SNaveen Krishna Chatradhi { 40789245107SNaveen Krishna Chatradhi .compatible = "samsung,s5pv210-secss", 40889245107SNaveen Krishna Chatradhi .data = &s5p_aes_data, 40989245107SNaveen Krishna Chatradhi }, 41089245107SNaveen Krishna Chatradhi { 41189245107SNaveen Krishna Chatradhi .compatible = "samsung,exynos4210-secss", 41289245107SNaveen Krishna Chatradhi .data = &exynos_aes_data, 41389245107SNaveen Krishna Chatradhi }, 4140918f18cSKamil Konieczny { 4150918f18cSKamil Konieczny .compatible = "samsung,exynos5433-slim-sss", 4160918f18cSKamil Konieczny .data = &exynos5433_slim_aes_data, 4170918f18cSKamil Konieczny }, 4186b9f16e6SNaveen Krishna Chatradhi { }, 4196b9f16e6SNaveen Krishna Chatradhi }; 4206b9f16e6SNaveen Krishna Chatradhi MODULE_DEVICE_TABLE(of, s5p_sss_dt_match); 4216b9f16e6SNaveen Krishna Chatradhi 4226584eacbSKrzysztof Kozlowski static inline const struct samsung_aes_variant *find_s5p_sss_version 4236584eacbSKrzysztof Kozlowski (const struct platform_device *pdev) 42489245107SNaveen Krishna Chatradhi { 42589245107SNaveen Krishna Chatradhi if (IS_ENABLED(CONFIG_OF) && (pdev->dev.of_node)) { 42689245107SNaveen Krishna Chatradhi const struct of_device_id *match; 427313becd1SKrzysztof Koz?owski 42889245107SNaveen Krishna Chatradhi match = of_match_node(s5p_sss_dt_match, 42989245107SNaveen Krishna Chatradhi pdev->dev.of_node); 4306584eacbSKrzysztof Kozlowski return (const struct samsung_aes_variant *)match->data; 43189245107SNaveen Krishna Chatradhi } 4326584eacbSKrzysztof Kozlowski return (const struct samsung_aes_variant *) 43389245107SNaveen Krishna Chatradhi platform_get_device_id(pdev)->driver_data; 43489245107SNaveen Krishna Chatradhi } 43589245107SNaveen Krishna Chatradhi 436c2afad6cSKamil Konieczny static struct s5p_aes_dev *s5p_dev; 437c2afad6cSKamil Konieczny 4386584eacbSKrzysztof Kozlowski static void s5p_set_dma_indata(struct s5p_aes_dev *dev, 4396584eacbSKrzysztof Kozlowski const struct scatterlist *sg) 440a49e490cSVladimir Zapolskiy { 441a49e490cSVladimir Zapolskiy SSS_WRITE(dev, FCBRDMAS, sg_dma_address(sg)); 442a49e490cSVladimir Zapolskiy SSS_WRITE(dev, FCBRDMAL, sg_dma_len(sg)); 443a49e490cSVladimir Zapolskiy } 444a49e490cSVladimir Zapolskiy 4456584eacbSKrzysztof Kozlowski static void s5p_set_dma_outdata(struct s5p_aes_dev *dev, 4466584eacbSKrzysztof Kozlowski const struct scatterlist *sg) 447a49e490cSVladimir Zapolskiy { 448a49e490cSVladimir Zapolskiy SSS_WRITE(dev, FCBTDMAS, sg_dma_address(sg)); 449a49e490cSVladimir Zapolskiy SSS_WRITE(dev, FCBTDMAL, sg_dma_len(sg)); 450a49e490cSVladimir Zapolskiy } 451a49e490cSVladimir Zapolskiy 4529e4a1100SKrzysztof Kozlowski static void s5p_free_sg_cpy(struct s5p_aes_dev *dev, struct scatterlist **sg) 4539e4a1100SKrzysztof Kozlowski { 4549e4a1100SKrzysztof Kozlowski int len; 4559e4a1100SKrzysztof Kozlowski 4569e4a1100SKrzysztof Kozlowski if (!*sg) 4579e4a1100SKrzysztof Kozlowski return; 4589e4a1100SKrzysztof Kozlowski 4599e4a1100SKrzysztof Kozlowski len = ALIGN(dev->req->nbytes, AES_BLOCK_SIZE); 4609e4a1100SKrzysztof Kozlowski free_pages((unsigned long)sg_virt(*sg), get_order(len)); 4619e4a1100SKrzysztof Kozlowski 4629e4a1100SKrzysztof Kozlowski kfree(*sg); 4639e4a1100SKrzysztof Kozlowski *sg = NULL; 4649e4a1100SKrzysztof Kozlowski } 4659e4a1100SKrzysztof Kozlowski 4669e4a1100SKrzysztof Kozlowski static void s5p_sg_copy_buf(void *buf, struct scatterlist *sg, 4679e4a1100SKrzysztof Kozlowski unsigned int nbytes, int out) 4689e4a1100SKrzysztof Kozlowski { 4699e4a1100SKrzysztof Kozlowski struct scatter_walk walk; 4709e4a1100SKrzysztof Kozlowski 4719e4a1100SKrzysztof Kozlowski if (!nbytes) 4729e4a1100SKrzysztof Kozlowski return; 4739e4a1100SKrzysztof Kozlowski 4749e4a1100SKrzysztof Kozlowski scatterwalk_start(&walk, sg); 4759e4a1100SKrzysztof Kozlowski scatterwalk_copychunks(buf, &walk, nbytes, out); 4769e4a1100SKrzysztof Kozlowski scatterwalk_done(&walk, out, 0); 4779e4a1100SKrzysztof Kozlowski } 4789e4a1100SKrzysztof Kozlowski 47928b62b14SKrzysztof Kozlowski static void s5p_sg_done(struct s5p_aes_dev *dev) 480a49e490cSVladimir Zapolskiy { 481e8e3c1caSKamil Konieczny struct ablkcipher_request *req = dev->req; 482e8e3c1caSKamil Konieczny struct s5p_aes_reqctx *reqctx = ablkcipher_request_ctx(req); 483e8e3c1caSKamil Konieczny 4849e4a1100SKrzysztof Kozlowski if (dev->sg_dst_cpy) { 4859e4a1100SKrzysztof Kozlowski dev_dbg(dev->dev, 4869e4a1100SKrzysztof Kozlowski "Copying %d bytes of output data back to original place\n", 4879e4a1100SKrzysztof Kozlowski dev->req->nbytes); 4889e4a1100SKrzysztof Kozlowski s5p_sg_copy_buf(sg_virt(dev->sg_dst_cpy), dev->req->dst, 4899e4a1100SKrzysztof Kozlowski dev->req->nbytes, 1); 4909e4a1100SKrzysztof Kozlowski } 4919e4a1100SKrzysztof Kozlowski s5p_free_sg_cpy(dev, &dev->sg_src_cpy); 4929e4a1100SKrzysztof Kozlowski s5p_free_sg_cpy(dev, &dev->sg_dst_cpy); 493e8e3c1caSKamil Konieczny if (reqctx->mode & FLAGS_AES_CBC) 494e8e3c1caSKamil Konieczny memcpy_fromio(req->info, dev->aes_ioaddr + SSS_REG_AES_IV_DATA(0), AES_BLOCK_SIZE); 495e8e3c1caSKamil Konieczny 496e8e3c1caSKamil Konieczny else if (reqctx->mode & FLAGS_AES_CTR) 497e8e3c1caSKamil Konieczny memcpy_fromio(req->info, dev->aes_ioaddr + SSS_REG_AES_CNT_DATA(0), AES_BLOCK_SIZE); 49828b62b14SKrzysztof Kozlowski } 4999e4a1100SKrzysztof Kozlowski 50028b62b14SKrzysztof Kozlowski /* Calls the completion. Cannot be called with dev->lock hold. */ 5015842cd44SChristoph Manszewski static void s5p_aes_complete(struct ablkcipher_request *req, int err) 50228b62b14SKrzysztof Kozlowski { 5035842cd44SChristoph Manszewski req->base.complete(&req->base, err); 504a49e490cSVladimir Zapolskiy } 505a49e490cSVladimir Zapolskiy 506a49e490cSVladimir Zapolskiy static void s5p_unset_outdata(struct s5p_aes_dev *dev) 507a49e490cSVladimir Zapolskiy { 508a49e490cSVladimir Zapolskiy dma_unmap_sg(dev->dev, dev->sg_dst, 1, DMA_FROM_DEVICE); 509a49e490cSVladimir Zapolskiy } 510a49e490cSVladimir Zapolskiy 511a49e490cSVladimir Zapolskiy static void s5p_unset_indata(struct s5p_aes_dev *dev) 512a49e490cSVladimir Zapolskiy { 513a49e490cSVladimir Zapolskiy dma_unmap_sg(dev->dev, dev->sg_src, 1, DMA_TO_DEVICE); 514a49e490cSVladimir Zapolskiy } 515a49e490cSVladimir Zapolskiy 5169e4a1100SKrzysztof Kozlowski static int s5p_make_sg_cpy(struct s5p_aes_dev *dev, struct scatterlist *src, 5179e4a1100SKrzysztof Kozlowski struct scatterlist **dst) 5189e4a1100SKrzysztof Kozlowski { 5199e4a1100SKrzysztof Kozlowski void *pages; 5209e4a1100SKrzysztof Kozlowski int len; 5219e4a1100SKrzysztof Kozlowski 5229e4a1100SKrzysztof Kozlowski *dst = kmalloc(sizeof(**dst), GFP_ATOMIC); 5239e4a1100SKrzysztof Kozlowski if (!*dst) 5249e4a1100SKrzysztof Kozlowski return -ENOMEM; 5259e4a1100SKrzysztof Kozlowski 5269e4a1100SKrzysztof Kozlowski len = ALIGN(dev->req->nbytes, AES_BLOCK_SIZE); 5279e4a1100SKrzysztof Kozlowski pages = (void *)__get_free_pages(GFP_ATOMIC, get_order(len)); 5289e4a1100SKrzysztof Kozlowski if (!pages) { 5299e4a1100SKrzysztof Kozlowski kfree(*dst); 5309e4a1100SKrzysztof Kozlowski *dst = NULL; 5319e4a1100SKrzysztof Kozlowski return -ENOMEM; 5329e4a1100SKrzysztof Kozlowski } 5339e4a1100SKrzysztof Kozlowski 5349e4a1100SKrzysztof Kozlowski s5p_sg_copy_buf(pages, src, dev->req->nbytes, 0); 5359e4a1100SKrzysztof Kozlowski 5369e4a1100SKrzysztof Kozlowski sg_init_table(*dst, 1); 5379e4a1100SKrzysztof Kozlowski sg_set_buf(*dst, pages, len); 5389e4a1100SKrzysztof Kozlowski 5399e4a1100SKrzysztof Kozlowski return 0; 5409e4a1100SKrzysztof Kozlowski } 5419e4a1100SKrzysztof Kozlowski 542a49e490cSVladimir Zapolskiy static int s5p_set_outdata(struct s5p_aes_dev *dev, struct scatterlist *sg) 543a49e490cSVladimir Zapolskiy { 544b1b4416fSChristoph Manszewski if (!sg->length) 545b1b4416fSChristoph Manszewski return -EINVAL; 546a49e490cSVladimir Zapolskiy 547b1b4416fSChristoph Manszewski if (!dma_map_sg(dev->dev, sg, 1, DMA_FROM_DEVICE)) 548b1b4416fSChristoph Manszewski return -ENOMEM; 549a49e490cSVladimir Zapolskiy 550a49e490cSVladimir Zapolskiy dev->sg_dst = sg; 551a49e490cSVladimir Zapolskiy 552b1b4416fSChristoph Manszewski return 0; 553a49e490cSVladimir Zapolskiy } 554a49e490cSVladimir Zapolskiy 555a49e490cSVladimir Zapolskiy static int s5p_set_indata(struct s5p_aes_dev *dev, struct scatterlist *sg) 556a49e490cSVladimir Zapolskiy { 557b1b4416fSChristoph Manszewski if (!sg->length) 558b1b4416fSChristoph Manszewski return -EINVAL; 559a49e490cSVladimir Zapolskiy 560b1b4416fSChristoph Manszewski if (!dma_map_sg(dev->dev, sg, 1, DMA_TO_DEVICE)) 561b1b4416fSChristoph Manszewski return -ENOMEM; 562a49e490cSVladimir Zapolskiy 563a49e490cSVladimir Zapolskiy dev->sg_src = sg; 564a49e490cSVladimir Zapolskiy 565b1b4416fSChristoph Manszewski return 0; 566a49e490cSVladimir Zapolskiy } 567a49e490cSVladimir Zapolskiy 56879152e8dSKrzysztof Kozlowski /* 56928b62b14SKrzysztof Kozlowski * Returns -ERRNO on error (mapping of new data failed). 57028b62b14SKrzysztof Kozlowski * On success returns: 57128b62b14SKrzysztof Kozlowski * - 0 if there is no more data, 57228b62b14SKrzysztof Kozlowski * - 1 if new transmitting (output) data is ready and its address+length 57328b62b14SKrzysztof Kozlowski * have to be written to device (by calling s5p_set_dma_outdata()). 57479152e8dSKrzysztof Kozlowski */ 57528b62b14SKrzysztof Kozlowski static int s5p_aes_tx(struct s5p_aes_dev *dev) 576a49e490cSVladimir Zapolskiy { 57728b62b14SKrzysztof Kozlowski int ret = 0; 578a49e490cSVladimir Zapolskiy 579a49e490cSVladimir Zapolskiy s5p_unset_outdata(dev); 580a49e490cSVladimir Zapolskiy 581a49e490cSVladimir Zapolskiy if (!sg_is_last(dev->sg_dst)) { 58228b62b14SKrzysztof Kozlowski ret = s5p_set_outdata(dev, sg_next(dev->sg_dst)); 58328b62b14SKrzysztof Kozlowski if (!ret) 58428b62b14SKrzysztof Kozlowski ret = 1; 585dc5e3f19SNaveen Krishna Chatradhi } 58679152e8dSKrzysztof Kozlowski 58779152e8dSKrzysztof Kozlowski return ret; 588a49e490cSVladimir Zapolskiy } 589a49e490cSVladimir Zapolskiy 59079152e8dSKrzysztof Kozlowski /* 59128b62b14SKrzysztof Kozlowski * Returns -ERRNO on error (mapping of new data failed). 59228b62b14SKrzysztof Kozlowski * On success returns: 59328b62b14SKrzysztof Kozlowski * - 0 if there is no more data, 59428b62b14SKrzysztof Kozlowski * - 1 if new receiving (input) data is ready and its address+length 59528b62b14SKrzysztof Kozlowski * have to be written to device (by calling s5p_set_dma_indata()). 59679152e8dSKrzysztof Kozlowski */ 59728b62b14SKrzysztof Kozlowski static int s5p_aes_rx(struct s5p_aes_dev *dev/*, bool *set_dma*/) 598a49e490cSVladimir Zapolskiy { 59928b62b14SKrzysztof Kozlowski int ret = 0; 600a49e490cSVladimir Zapolskiy 601a49e490cSVladimir Zapolskiy s5p_unset_indata(dev); 602a49e490cSVladimir Zapolskiy 603a49e490cSVladimir Zapolskiy if (!sg_is_last(dev->sg_src)) { 60428b62b14SKrzysztof Kozlowski ret = s5p_set_indata(dev, sg_next(dev->sg_src)); 60528b62b14SKrzysztof Kozlowski if (!ret) 60628b62b14SKrzysztof Kozlowski ret = 1; 607a49e490cSVladimir Zapolskiy } 608a49e490cSVladimir Zapolskiy 60979152e8dSKrzysztof Kozlowski return ret; 610a49e490cSVladimir Zapolskiy } 611a49e490cSVladimir Zapolskiy 612c2afad6cSKamil Konieczny static inline u32 s5p_hash_read(struct s5p_aes_dev *dd, u32 offset) 613c2afad6cSKamil Konieczny { 614c2afad6cSKamil Konieczny return __raw_readl(dd->io_hash_base + offset); 615c2afad6cSKamil Konieczny } 616c2afad6cSKamil Konieczny 617c2afad6cSKamil Konieczny static inline void s5p_hash_write(struct s5p_aes_dev *dd, 618c2afad6cSKamil Konieczny u32 offset, u32 value) 619c2afad6cSKamil Konieczny { 620c2afad6cSKamil Konieczny __raw_writel(value, dd->io_hash_base + offset); 621c2afad6cSKamil Konieczny } 622c2afad6cSKamil Konieczny 623c2afad6cSKamil Konieczny /** 624c2afad6cSKamil Konieczny * s5p_set_dma_hashdata() - start DMA with sg 625c2afad6cSKamil Konieczny * @dev: device 626c2afad6cSKamil Konieczny * @sg: scatterlist ready to DMA transmit 627c2afad6cSKamil Konieczny */ 628c2afad6cSKamil Konieczny static void s5p_set_dma_hashdata(struct s5p_aes_dev *dev, 6296584eacbSKrzysztof Kozlowski const struct scatterlist *sg) 630c2afad6cSKamil Konieczny { 631c2afad6cSKamil Konieczny dev->hash_sg_cnt--; 632c2afad6cSKamil Konieczny SSS_WRITE(dev, FCHRDMAS, sg_dma_address(sg)); 633c2afad6cSKamil Konieczny SSS_WRITE(dev, FCHRDMAL, sg_dma_len(sg)); /* DMA starts */ 634c2afad6cSKamil Konieczny } 635c2afad6cSKamil Konieczny 636c2afad6cSKamil Konieczny /** 637c2afad6cSKamil Konieczny * s5p_hash_rx() - get next hash_sg_iter 638c2afad6cSKamil Konieczny * @dev: device 639c2afad6cSKamil Konieczny * 640c2afad6cSKamil Konieczny * Return: 641c2afad6cSKamil Konieczny * 2 if there is no more data and it is UPDATE op 642c2afad6cSKamil Konieczny * 1 if new receiving (input) data is ready and can be written to device 643c2afad6cSKamil Konieczny * 0 if there is no more data and it is FINAL op 644c2afad6cSKamil Konieczny */ 645c2afad6cSKamil Konieczny static int s5p_hash_rx(struct s5p_aes_dev *dev) 646c2afad6cSKamil Konieczny { 647c2afad6cSKamil Konieczny if (dev->hash_sg_cnt > 0) { 648c2afad6cSKamil Konieczny dev->hash_sg_iter = sg_next(dev->hash_sg_iter); 649c2afad6cSKamil Konieczny return 1; 650c2afad6cSKamil Konieczny } 651c2afad6cSKamil Konieczny 652c2afad6cSKamil Konieczny set_bit(HASH_FLAGS_DMA_READY, &dev->hash_flags); 653c2afad6cSKamil Konieczny if (test_bit(HASH_FLAGS_FINAL, &dev->hash_flags)) 654c2afad6cSKamil Konieczny return 0; 655c2afad6cSKamil Konieczny 656c2afad6cSKamil Konieczny return 2; 657c2afad6cSKamil Konieczny } 658c2afad6cSKamil Konieczny 659a49e490cSVladimir Zapolskiy static irqreturn_t s5p_aes_interrupt(int irq, void *dev_id) 660a49e490cSVladimir Zapolskiy { 661a49e490cSVladimir Zapolskiy struct platform_device *pdev = dev_id; 662a49e490cSVladimir Zapolskiy struct s5p_aes_dev *dev = platform_get_drvdata(pdev); 6635842cd44SChristoph Manszewski struct ablkcipher_request *req; 66428b62b14SKrzysztof Kozlowski int err_dma_tx = 0; 66528b62b14SKrzysztof Kozlowski int err_dma_rx = 0; 666c2afad6cSKamil Konieczny int err_dma_hx = 0; 66728b62b14SKrzysztof Kozlowski bool tx_end = false; 668c2afad6cSKamil Konieczny bool hx_end = false; 6695318c53dSKrzysztof Kozlowski unsigned long flags; 670b1b4416fSChristoph Manszewski u32 status, st_bits; 67128b62b14SKrzysztof Kozlowski int err; 672a49e490cSVladimir Zapolskiy 673a49e490cSVladimir Zapolskiy spin_lock_irqsave(&dev->lock, flags); 674a49e490cSVladimir Zapolskiy 67528b62b14SKrzysztof Kozlowski /* 67628b62b14SKrzysztof Kozlowski * Handle rx or tx interrupt. If there is still data (scatterlist did not 67728b62b14SKrzysztof Kozlowski * reach end), then map next scatterlist entry. 67828b62b14SKrzysztof Kozlowski * In case of such mapping error, s5p_aes_complete() should be called. 67928b62b14SKrzysztof Kozlowski * 68028b62b14SKrzysztof Kozlowski * If there is no more data in tx scatter list, call s5p_aes_complete() 68128b62b14SKrzysztof Kozlowski * and schedule new tasklet. 682c2afad6cSKamil Konieczny * 683c2afad6cSKamil Konieczny * Handle hx interrupt. If there is still data map next entry. 68428b62b14SKrzysztof Kozlowski */ 685a49e490cSVladimir Zapolskiy status = SSS_READ(dev, FCINTSTAT); 686a49e490cSVladimir Zapolskiy if (status & SSS_FCINTSTAT_BRDMAINT) 68728b62b14SKrzysztof Kozlowski err_dma_rx = s5p_aes_rx(dev); 68828b62b14SKrzysztof Kozlowski 68928b62b14SKrzysztof Kozlowski if (status & SSS_FCINTSTAT_BTDMAINT) { 69028b62b14SKrzysztof Kozlowski if (sg_is_last(dev->sg_dst)) 69128b62b14SKrzysztof Kozlowski tx_end = true; 69228b62b14SKrzysztof Kozlowski err_dma_tx = s5p_aes_tx(dev); 69328b62b14SKrzysztof Kozlowski } 694a49e490cSVladimir Zapolskiy 695c2afad6cSKamil Konieczny if (status & SSS_FCINTSTAT_HRDMAINT) 696c2afad6cSKamil Konieczny err_dma_hx = s5p_hash_rx(dev); 697c2afad6cSKamil Konieczny 698c2afad6cSKamil Konieczny st_bits = status & (SSS_FCINTSTAT_BRDMAINT | SSS_FCINTSTAT_BTDMAINT | 699c2afad6cSKamil Konieczny SSS_FCINTSTAT_HRDMAINT); 700c2afad6cSKamil Konieczny /* clear DMA bits */ 701c2afad6cSKamil Konieczny SSS_WRITE(dev, FCINTPEND, st_bits); 702c2afad6cSKamil Konieczny 703c2afad6cSKamil Konieczny /* clear HASH irq bits */ 704c2afad6cSKamil Konieczny if (status & (SSS_FCINTSTAT_HDONEINT | SSS_FCINTSTAT_HPARTINT)) { 705c2afad6cSKamil Konieczny /* cannot have both HPART and HDONE */ 706c2afad6cSKamil Konieczny if (status & SSS_FCINTSTAT_HPARTINT) 707c2afad6cSKamil Konieczny st_bits = SSS_HASH_STATUS_PARTIAL_DONE; 708c2afad6cSKamil Konieczny 709c2afad6cSKamil Konieczny if (status & SSS_FCINTSTAT_HDONEINT) 710c2afad6cSKamil Konieczny st_bits = SSS_HASH_STATUS_MSG_DONE; 711c2afad6cSKamil Konieczny 712c2afad6cSKamil Konieczny set_bit(HASH_FLAGS_OUTPUT_READY, &dev->hash_flags); 713c2afad6cSKamil Konieczny s5p_hash_write(dev, SSS_REG_HASH_STATUS, st_bits); 714c2afad6cSKamil Konieczny hx_end = true; 715c2afad6cSKamil Konieczny /* when DONE or PART, do not handle HASH DMA */ 716c2afad6cSKamil Konieczny err_dma_hx = 0; 717c2afad6cSKamil Konieczny } 718a49e490cSVladimir Zapolskiy 71928b62b14SKrzysztof Kozlowski if (err_dma_rx < 0) { 72028b62b14SKrzysztof Kozlowski err = err_dma_rx; 72128b62b14SKrzysztof Kozlowski goto error; 72228b62b14SKrzysztof Kozlowski } 72328b62b14SKrzysztof Kozlowski if (err_dma_tx < 0) { 72428b62b14SKrzysztof Kozlowski err = err_dma_tx; 72528b62b14SKrzysztof Kozlowski goto error; 72628b62b14SKrzysztof Kozlowski } 72728b62b14SKrzysztof Kozlowski 72828b62b14SKrzysztof Kozlowski if (tx_end) { 72928b62b14SKrzysztof Kozlowski s5p_sg_done(dev); 730c2afad6cSKamil Konieczny if (err_dma_hx == 1) 731c2afad6cSKamil Konieczny s5p_set_dma_hashdata(dev, dev->hash_sg_iter); 73228b62b14SKrzysztof Kozlowski 73328b62b14SKrzysztof Kozlowski spin_unlock_irqrestore(&dev->lock, flags); 73428b62b14SKrzysztof Kozlowski 7355842cd44SChristoph Manszewski s5p_aes_complete(dev->req, 0); 73642d5c176SKrzysztof Kozlowski /* Device is still busy */ 73728b62b14SKrzysztof Kozlowski tasklet_schedule(&dev->tasklet); 73828b62b14SKrzysztof Kozlowski } else { 73979152e8dSKrzysztof Kozlowski /* 74028b62b14SKrzysztof Kozlowski * Writing length of DMA block (either receiving or 74128b62b14SKrzysztof Kozlowski * transmitting) will start the operation immediately, so this 74228b62b14SKrzysztof Kozlowski * should be done at the end (even after clearing pending 74328b62b14SKrzysztof Kozlowski * interrupts to not miss the interrupt). 74479152e8dSKrzysztof Kozlowski */ 74528b62b14SKrzysztof Kozlowski if (err_dma_tx == 1) 74679152e8dSKrzysztof Kozlowski s5p_set_dma_outdata(dev, dev->sg_dst); 74728b62b14SKrzysztof Kozlowski if (err_dma_rx == 1) 74879152e8dSKrzysztof Kozlowski s5p_set_dma_indata(dev, dev->sg_src); 749c2afad6cSKamil Konieczny if (err_dma_hx == 1) 750c2afad6cSKamil Konieczny s5p_set_dma_hashdata(dev, dev->hash_sg_iter); 75179152e8dSKrzysztof Kozlowski 752a49e490cSVladimir Zapolskiy spin_unlock_irqrestore(&dev->lock, flags); 75328b62b14SKrzysztof Kozlowski } 75428b62b14SKrzysztof Kozlowski 755c2afad6cSKamil Konieczny goto hash_irq_end; 75628b62b14SKrzysztof Kozlowski 75728b62b14SKrzysztof Kozlowski error: 75828b62b14SKrzysztof Kozlowski s5p_sg_done(dev); 75942d5c176SKrzysztof Kozlowski dev->busy = false; 7605842cd44SChristoph Manszewski req = dev->req; 761c2afad6cSKamil Konieczny if (err_dma_hx == 1) 762c2afad6cSKamil Konieczny s5p_set_dma_hashdata(dev, dev->hash_sg_iter); 763c2afad6cSKamil Konieczny 76428b62b14SKrzysztof Kozlowski spin_unlock_irqrestore(&dev->lock, flags); 7655842cd44SChristoph Manszewski s5p_aes_complete(req, err); 766a49e490cSVladimir Zapolskiy 767c2afad6cSKamil Konieczny hash_irq_end: 768c2afad6cSKamil Konieczny /* 769c2afad6cSKamil Konieczny * Note about else if: 770c2afad6cSKamil Konieczny * when hash_sg_iter reaches end and its UPDATE op, 771c2afad6cSKamil Konieczny * issue SSS_HASH_PAUSE and wait for HPART irq 772c2afad6cSKamil Konieczny */ 773c2afad6cSKamil Konieczny if (hx_end) 774c2afad6cSKamil Konieczny tasklet_schedule(&dev->hash_tasklet); 775c2afad6cSKamil Konieczny else if (err_dma_hx == 2) 776c2afad6cSKamil Konieczny s5p_hash_write(dev, SSS_REG_HASH_CTRL_PAUSE, 777c2afad6cSKamil Konieczny SSS_HASH_PAUSE); 778c2afad6cSKamil Konieczny 779a49e490cSVladimir Zapolskiy return IRQ_HANDLED; 780a49e490cSVladimir Zapolskiy } 781a49e490cSVladimir Zapolskiy 782c2afad6cSKamil Konieczny /** 783c2afad6cSKamil Konieczny * s5p_hash_read_msg() - read message or IV from HW 784c2afad6cSKamil Konieczny * @req: AHASH request 785c2afad6cSKamil Konieczny */ 786c2afad6cSKamil Konieczny static void s5p_hash_read_msg(struct ahash_request *req) 787c2afad6cSKamil Konieczny { 788c2afad6cSKamil Konieczny struct s5p_hash_reqctx *ctx = ahash_request_ctx(req); 789c2afad6cSKamil Konieczny struct s5p_aes_dev *dd = ctx->dd; 790c2afad6cSKamil Konieczny u32 *hash = (u32 *)ctx->digest; 791c2afad6cSKamil Konieczny unsigned int i; 792c2afad6cSKamil Konieczny 793c2afad6cSKamil Konieczny for (i = 0; i < ctx->nregs; i++) 794c2afad6cSKamil Konieczny hash[i] = s5p_hash_read(dd, SSS_REG_HASH_OUT(i)); 795c2afad6cSKamil Konieczny } 796c2afad6cSKamil Konieczny 797c2afad6cSKamil Konieczny /** 798c2afad6cSKamil Konieczny * s5p_hash_write_ctx_iv() - write IV for next partial/finup op. 799c2afad6cSKamil Konieczny * @dd: device 800c2afad6cSKamil Konieczny * @ctx: request context 801c2afad6cSKamil Konieczny */ 802c2afad6cSKamil Konieczny static void s5p_hash_write_ctx_iv(struct s5p_aes_dev *dd, 8036584eacbSKrzysztof Kozlowski const struct s5p_hash_reqctx *ctx) 804c2afad6cSKamil Konieczny { 8056584eacbSKrzysztof Kozlowski const u32 *hash = (const u32 *)ctx->digest; 806c2afad6cSKamil Konieczny unsigned int i; 807c2afad6cSKamil Konieczny 808c2afad6cSKamil Konieczny for (i = 0; i < ctx->nregs; i++) 809c2afad6cSKamil Konieczny s5p_hash_write(dd, SSS_REG_HASH_IV(i), hash[i]); 810c2afad6cSKamil Konieczny } 811c2afad6cSKamil Konieczny 812c2afad6cSKamil Konieczny /** 813c2afad6cSKamil Konieczny * s5p_hash_write_iv() - write IV for next partial/finup op. 814c2afad6cSKamil Konieczny * @req: AHASH request 815c2afad6cSKamil Konieczny */ 816c2afad6cSKamil Konieczny static void s5p_hash_write_iv(struct ahash_request *req) 817c2afad6cSKamil Konieczny { 818c2afad6cSKamil Konieczny struct s5p_hash_reqctx *ctx = ahash_request_ctx(req); 819c2afad6cSKamil Konieczny 820c2afad6cSKamil Konieczny s5p_hash_write_ctx_iv(ctx->dd, ctx); 821c2afad6cSKamil Konieczny } 822c2afad6cSKamil Konieczny 823c2afad6cSKamil Konieczny /** 824c2afad6cSKamil Konieczny * s5p_hash_copy_result() - copy digest into req->result 825c2afad6cSKamil Konieczny * @req: AHASH request 826c2afad6cSKamil Konieczny */ 827c2afad6cSKamil Konieczny static void s5p_hash_copy_result(struct ahash_request *req) 828c2afad6cSKamil Konieczny { 8296584eacbSKrzysztof Kozlowski const struct s5p_hash_reqctx *ctx = ahash_request_ctx(req); 830c2afad6cSKamil Konieczny 831c2afad6cSKamil Konieczny if (!req->result) 832c2afad6cSKamil Konieczny return; 833c2afad6cSKamil Konieczny 834c2afad6cSKamil Konieczny memcpy(req->result, ctx->digest, ctx->nregs * HASH_REG_SIZEOF); 835c2afad6cSKamil Konieczny } 836c2afad6cSKamil Konieczny 837c2afad6cSKamil Konieczny /** 838c2afad6cSKamil Konieczny * s5p_hash_dma_flush() - flush HASH DMA 839c2afad6cSKamil Konieczny * @dev: secss device 840c2afad6cSKamil Konieczny */ 841c2afad6cSKamil Konieczny static void s5p_hash_dma_flush(struct s5p_aes_dev *dev) 842c2afad6cSKamil Konieczny { 843c2afad6cSKamil Konieczny SSS_WRITE(dev, FCHRDMAC, SSS_FCHRDMAC_FLUSH); 844c2afad6cSKamil Konieczny } 845c2afad6cSKamil Konieczny 846c2afad6cSKamil Konieczny /** 847c2afad6cSKamil Konieczny * s5p_hash_dma_enable() - enable DMA mode for HASH 848c2afad6cSKamil Konieczny * @dev: secss device 849c2afad6cSKamil Konieczny * 850c2afad6cSKamil Konieczny * enable DMA mode for HASH 851c2afad6cSKamil Konieczny */ 852c2afad6cSKamil Konieczny static void s5p_hash_dma_enable(struct s5p_aes_dev *dev) 853c2afad6cSKamil Konieczny { 854c2afad6cSKamil Konieczny s5p_hash_write(dev, SSS_REG_HASH_CTRL_FIFO, SSS_HASH_FIFO_MODE_DMA); 855c2afad6cSKamil Konieczny } 856c2afad6cSKamil Konieczny 857c2afad6cSKamil Konieczny /** 858c2afad6cSKamil Konieczny * s5p_hash_irq_disable() - disable irq HASH signals 859c2afad6cSKamil Konieczny * @dev: secss device 860c2afad6cSKamil Konieczny * @flags: bitfield with irq's to be disabled 861c2afad6cSKamil Konieczny */ 862c2afad6cSKamil Konieczny static void s5p_hash_irq_disable(struct s5p_aes_dev *dev, u32 flags) 863c2afad6cSKamil Konieczny { 864c2afad6cSKamil Konieczny SSS_WRITE(dev, FCINTENCLR, flags); 865c2afad6cSKamil Konieczny } 866c2afad6cSKamil Konieczny 867c2afad6cSKamil Konieczny /** 868c2afad6cSKamil Konieczny * s5p_hash_irq_enable() - enable irq signals 869c2afad6cSKamil Konieczny * @dev: secss device 870c2afad6cSKamil Konieczny * @flags: bitfield with irq's to be enabled 871c2afad6cSKamil Konieczny */ 872c2afad6cSKamil Konieczny static void s5p_hash_irq_enable(struct s5p_aes_dev *dev, int flags) 873c2afad6cSKamil Konieczny { 874c2afad6cSKamil Konieczny SSS_WRITE(dev, FCINTENSET, flags); 875c2afad6cSKamil Konieczny } 876c2afad6cSKamil Konieczny 877c2afad6cSKamil Konieczny /** 878c2afad6cSKamil Konieczny * s5p_hash_set_flow() - set flow inside SecSS AES/DES with/without HASH 879c2afad6cSKamil Konieczny * @dev: secss device 880c2afad6cSKamil Konieczny * @hashflow: HASH stream flow with/without crypto AES/DES 881c2afad6cSKamil Konieczny */ 882c2afad6cSKamil Konieczny static void s5p_hash_set_flow(struct s5p_aes_dev *dev, u32 hashflow) 883c2afad6cSKamil Konieczny { 884c2afad6cSKamil Konieczny unsigned long flags; 885c2afad6cSKamil Konieczny u32 flow; 886c2afad6cSKamil Konieczny 887c2afad6cSKamil Konieczny spin_lock_irqsave(&dev->lock, flags); 888c2afad6cSKamil Konieczny 889c2afad6cSKamil Konieczny flow = SSS_READ(dev, FCFIFOCTRL); 890c2afad6cSKamil Konieczny flow &= ~SSS_HASHIN_MASK; 891c2afad6cSKamil Konieczny flow |= hashflow; 892c2afad6cSKamil Konieczny SSS_WRITE(dev, FCFIFOCTRL, flow); 893c2afad6cSKamil Konieczny 894c2afad6cSKamil Konieczny spin_unlock_irqrestore(&dev->lock, flags); 895c2afad6cSKamil Konieczny } 896c2afad6cSKamil Konieczny 897c2afad6cSKamil Konieczny /** 898c2afad6cSKamil Konieczny * s5p_ahash_dma_init() - enable DMA and set HASH flow inside SecSS 899c2afad6cSKamil Konieczny * @dev: secss device 900c2afad6cSKamil Konieczny * @hashflow: HASH stream flow with/without AES/DES 901c2afad6cSKamil Konieczny * 902c2afad6cSKamil Konieczny * flush HASH DMA and enable DMA, set HASH stream flow inside SecSS HW, 903c2afad6cSKamil Konieczny * enable HASH irq's HRDMA, HDONE, HPART 904c2afad6cSKamil Konieczny */ 905c2afad6cSKamil Konieczny static void s5p_ahash_dma_init(struct s5p_aes_dev *dev, u32 hashflow) 906c2afad6cSKamil Konieczny { 907c2afad6cSKamil Konieczny s5p_hash_irq_disable(dev, SSS_FCINTENCLR_HRDMAINTENCLR | 908c2afad6cSKamil Konieczny SSS_FCINTENCLR_HDONEINTENCLR | 909c2afad6cSKamil Konieczny SSS_FCINTENCLR_HPARTINTENCLR); 910c2afad6cSKamil Konieczny s5p_hash_dma_flush(dev); 911c2afad6cSKamil Konieczny 912c2afad6cSKamil Konieczny s5p_hash_dma_enable(dev); 913c2afad6cSKamil Konieczny s5p_hash_set_flow(dev, hashflow & SSS_HASHIN_MASK); 914c2afad6cSKamil Konieczny s5p_hash_irq_enable(dev, SSS_FCINTENSET_HRDMAINTENSET | 915c2afad6cSKamil Konieczny SSS_FCINTENSET_HDONEINTENSET | 916c2afad6cSKamil Konieczny SSS_FCINTENSET_HPARTINTENSET); 917c2afad6cSKamil Konieczny } 918c2afad6cSKamil Konieczny 919c2afad6cSKamil Konieczny /** 920c2afad6cSKamil Konieczny * s5p_hash_write_ctrl() - prepare HASH block in SecSS for processing 921c2afad6cSKamil Konieczny * @dd: secss device 922c2afad6cSKamil Konieczny * @length: length for request 923c2afad6cSKamil Konieczny * @final: true if final op 924c2afad6cSKamil Konieczny * 925c2afad6cSKamil Konieczny * Prepare SSS HASH block for processing bytes in DMA mode. If it is called 926c2afad6cSKamil Konieczny * after previous updates, fill up IV words. For final, calculate and set 927c2afad6cSKamil Konieczny * lengths for HASH so SecSS can finalize hash. For partial, set SSS HASH 928c2afad6cSKamil Konieczny * length as 2^63 so it will be never reached and set to zero prelow and 929c2afad6cSKamil Konieczny * prehigh. 930c2afad6cSKamil Konieczny * 931c2afad6cSKamil Konieczny * This function does not start DMA transfer. 932c2afad6cSKamil Konieczny */ 933c2afad6cSKamil Konieczny static void s5p_hash_write_ctrl(struct s5p_aes_dev *dd, size_t length, 934c2afad6cSKamil Konieczny bool final) 935c2afad6cSKamil Konieczny { 936c2afad6cSKamil Konieczny struct s5p_hash_reqctx *ctx = ahash_request_ctx(dd->hash_req); 937c2afad6cSKamil Konieczny u32 prelow, prehigh, low, high; 938c2afad6cSKamil Konieczny u32 configflags, swapflags; 939c2afad6cSKamil Konieczny u64 tmplen; 940c2afad6cSKamil Konieczny 941c2afad6cSKamil Konieczny configflags = ctx->engine | SSS_HASH_INIT_BIT; 942c2afad6cSKamil Konieczny 943c2afad6cSKamil Konieczny if (likely(ctx->digcnt)) { 944c2afad6cSKamil Konieczny s5p_hash_write_ctx_iv(dd, ctx); 945c2afad6cSKamil Konieczny configflags |= SSS_HASH_USER_IV_EN; 946c2afad6cSKamil Konieczny } 947c2afad6cSKamil Konieczny 948c2afad6cSKamil Konieczny if (final) { 949c2afad6cSKamil Konieczny /* number of bytes for last part */ 950c2afad6cSKamil Konieczny low = length; 951c2afad6cSKamil Konieczny high = 0; 952c2afad6cSKamil Konieczny /* total number of bits prev hashed */ 953c2afad6cSKamil Konieczny tmplen = ctx->digcnt * 8; 954c2afad6cSKamil Konieczny prelow = (u32)tmplen; 955c2afad6cSKamil Konieczny prehigh = (u32)(tmplen >> 32); 956c2afad6cSKamil Konieczny } else { 957c2afad6cSKamil Konieczny prelow = 0; 958c2afad6cSKamil Konieczny prehigh = 0; 959c2afad6cSKamil Konieczny low = 0; 960c2afad6cSKamil Konieczny high = BIT(31); 961c2afad6cSKamil Konieczny } 962c2afad6cSKamil Konieczny 963c2afad6cSKamil Konieczny swapflags = SSS_HASH_BYTESWAP_DI | SSS_HASH_BYTESWAP_DO | 964c2afad6cSKamil Konieczny SSS_HASH_BYTESWAP_IV | SSS_HASH_BYTESWAP_KEY; 965c2afad6cSKamil Konieczny 966c2afad6cSKamil Konieczny s5p_hash_write(dd, SSS_REG_HASH_MSG_SIZE_LOW, low); 967c2afad6cSKamil Konieczny s5p_hash_write(dd, SSS_REG_HASH_MSG_SIZE_HIGH, high); 968c2afad6cSKamil Konieczny s5p_hash_write(dd, SSS_REG_HASH_PRE_MSG_SIZE_LOW, prelow); 969c2afad6cSKamil Konieczny s5p_hash_write(dd, SSS_REG_HASH_PRE_MSG_SIZE_HIGH, prehigh); 970c2afad6cSKamil Konieczny 971c2afad6cSKamil Konieczny s5p_hash_write(dd, SSS_REG_HASH_CTRL_SWAP, swapflags); 972c2afad6cSKamil Konieczny s5p_hash_write(dd, SSS_REG_HASH_CTRL, configflags); 973c2afad6cSKamil Konieczny } 974c2afad6cSKamil Konieczny 975c2afad6cSKamil Konieczny /** 976c2afad6cSKamil Konieczny * s5p_hash_xmit_dma() - start DMA hash processing 977c2afad6cSKamil Konieczny * @dd: secss device 978c2afad6cSKamil Konieczny * @length: length for request 979c2afad6cSKamil Konieczny * @final: true if final op 980c2afad6cSKamil Konieczny * 981c2afad6cSKamil Konieczny * Update digcnt here, as it is needed for finup/final op. 982c2afad6cSKamil Konieczny */ 983c2afad6cSKamil Konieczny static int s5p_hash_xmit_dma(struct s5p_aes_dev *dd, size_t length, 984c2afad6cSKamil Konieczny bool final) 985c2afad6cSKamil Konieczny { 986c2afad6cSKamil Konieczny struct s5p_hash_reqctx *ctx = ahash_request_ctx(dd->hash_req); 987c2afad6cSKamil Konieczny unsigned int cnt; 988c2afad6cSKamil Konieczny 989c2afad6cSKamil Konieczny cnt = dma_map_sg(dd->dev, ctx->sg, ctx->sg_len, DMA_TO_DEVICE); 990c2afad6cSKamil Konieczny if (!cnt) { 991c2afad6cSKamil Konieczny dev_err(dd->dev, "dma_map_sg error\n"); 992c2afad6cSKamil Konieczny ctx->error = true; 993c2afad6cSKamil Konieczny return -EINVAL; 994c2afad6cSKamil Konieczny } 995c2afad6cSKamil Konieczny 996c2afad6cSKamil Konieczny set_bit(HASH_FLAGS_DMA_ACTIVE, &dd->hash_flags); 997c2afad6cSKamil Konieczny dd->hash_sg_iter = ctx->sg; 998c2afad6cSKamil Konieczny dd->hash_sg_cnt = cnt; 999c2afad6cSKamil Konieczny s5p_hash_write_ctrl(dd, length, final); 1000c2afad6cSKamil Konieczny ctx->digcnt += length; 1001c2afad6cSKamil Konieczny ctx->total -= length; 1002c2afad6cSKamil Konieczny 1003c2afad6cSKamil Konieczny /* catch last interrupt */ 1004c2afad6cSKamil Konieczny if (final) 1005c2afad6cSKamil Konieczny set_bit(HASH_FLAGS_FINAL, &dd->hash_flags); 1006c2afad6cSKamil Konieczny 1007c2afad6cSKamil Konieczny s5p_set_dma_hashdata(dd, dd->hash_sg_iter); /* DMA starts */ 1008c2afad6cSKamil Konieczny 1009c2afad6cSKamil Konieczny return -EINPROGRESS; 1010c2afad6cSKamil Konieczny } 1011c2afad6cSKamil Konieczny 1012c2afad6cSKamil Konieczny /** 1013c2afad6cSKamil Konieczny * s5p_hash_copy_sgs() - copy request's bytes into new buffer 1014c2afad6cSKamil Konieczny * @ctx: request context 1015c2afad6cSKamil Konieczny * @sg: source scatterlist request 1016c2afad6cSKamil Konieczny * @new_len: number of bytes to process from sg 1017c2afad6cSKamil Konieczny * 1018c2afad6cSKamil Konieczny * Allocate new buffer, copy data for HASH into it. If there was xmit_buf 1019c2afad6cSKamil Konieczny * filled, copy it first, then copy data from sg into it. Prepare one sgl[0] 1020c2afad6cSKamil Konieczny * with allocated buffer. 1021c2afad6cSKamil Konieczny * 1022c2afad6cSKamil Konieczny * Set bit in dd->hash_flag so we can free it after irq ends processing. 1023c2afad6cSKamil Konieczny */ 1024c2afad6cSKamil Konieczny static int s5p_hash_copy_sgs(struct s5p_hash_reqctx *ctx, 1025c2afad6cSKamil Konieczny struct scatterlist *sg, unsigned int new_len) 1026c2afad6cSKamil Konieczny { 1027c2afad6cSKamil Konieczny unsigned int pages, len; 1028c2afad6cSKamil Konieczny void *buf; 1029c2afad6cSKamil Konieczny 1030c2afad6cSKamil Konieczny len = new_len + ctx->bufcnt; 1031c2afad6cSKamil Konieczny pages = get_order(len); 1032c2afad6cSKamil Konieczny 1033c2afad6cSKamil Konieczny buf = (void *)__get_free_pages(GFP_ATOMIC, pages); 1034c2afad6cSKamil Konieczny if (!buf) { 1035c2afad6cSKamil Konieczny dev_err(ctx->dd->dev, "alloc pages for unaligned case.\n"); 1036c2afad6cSKamil Konieczny ctx->error = true; 1037c2afad6cSKamil Konieczny return -ENOMEM; 1038c2afad6cSKamil Konieczny } 1039c2afad6cSKamil Konieczny 1040c2afad6cSKamil Konieczny if (ctx->bufcnt) 1041c2afad6cSKamil Konieczny memcpy(buf, ctx->dd->xmit_buf, ctx->bufcnt); 1042c2afad6cSKamil Konieczny 1043c2afad6cSKamil Konieczny scatterwalk_map_and_copy(buf + ctx->bufcnt, sg, ctx->skip, 1044c2afad6cSKamil Konieczny new_len, 0); 1045c2afad6cSKamil Konieczny sg_init_table(ctx->sgl, 1); 1046c2afad6cSKamil Konieczny sg_set_buf(ctx->sgl, buf, len); 1047c2afad6cSKamil Konieczny ctx->sg = ctx->sgl; 1048c2afad6cSKamil Konieczny ctx->sg_len = 1; 1049c2afad6cSKamil Konieczny ctx->bufcnt = 0; 1050c2afad6cSKamil Konieczny ctx->skip = 0; 1051c2afad6cSKamil Konieczny set_bit(HASH_FLAGS_SGS_COPIED, &ctx->dd->hash_flags); 1052c2afad6cSKamil Konieczny 1053c2afad6cSKamil Konieczny return 0; 1054c2afad6cSKamil Konieczny } 1055c2afad6cSKamil Konieczny 1056c2afad6cSKamil Konieczny /** 1057c2afad6cSKamil Konieczny * s5p_hash_copy_sg_lists() - copy sg list and make fixes in copy 1058c2afad6cSKamil Konieczny * @ctx: request context 1059c2afad6cSKamil Konieczny * @sg: source scatterlist request 1060c2afad6cSKamil Konieczny * @new_len: number of bytes to process from sg 1061c2afad6cSKamil Konieczny * 1062c2afad6cSKamil Konieczny * Allocate new scatterlist table, copy data for HASH into it. If there was 1063c2afad6cSKamil Konieczny * xmit_buf filled, prepare it first, then copy page, length and offset from 1064c2afad6cSKamil Konieczny * source sg into it, adjusting begin and/or end for skip offset and 1065c2afad6cSKamil Konieczny * hash_later value. 1066c2afad6cSKamil Konieczny * 1067c2afad6cSKamil Konieczny * Resulting sg table will be assigned to ctx->sg. Set flag so we can free 1068c2afad6cSKamil Konieczny * it after irq ends processing. 1069c2afad6cSKamil Konieczny */ 1070c2afad6cSKamil Konieczny static int s5p_hash_copy_sg_lists(struct s5p_hash_reqctx *ctx, 1071c2afad6cSKamil Konieczny struct scatterlist *sg, unsigned int new_len) 1072c2afad6cSKamil Konieczny { 1073c2afad6cSKamil Konieczny unsigned int skip = ctx->skip, n = sg_nents(sg); 1074c2afad6cSKamil Konieczny struct scatterlist *tmp; 1075c2afad6cSKamil Konieczny unsigned int len; 1076c2afad6cSKamil Konieczny 1077c2afad6cSKamil Konieczny if (ctx->bufcnt) 1078c2afad6cSKamil Konieczny n++; 1079c2afad6cSKamil Konieczny 1080c2afad6cSKamil Konieczny ctx->sg = kmalloc_array(n, sizeof(*sg), GFP_KERNEL); 1081c2afad6cSKamil Konieczny if (!ctx->sg) { 1082c2afad6cSKamil Konieczny ctx->error = true; 1083c2afad6cSKamil Konieczny return -ENOMEM; 1084c2afad6cSKamil Konieczny } 1085c2afad6cSKamil Konieczny 1086c2afad6cSKamil Konieczny sg_init_table(ctx->sg, n); 1087c2afad6cSKamil Konieczny 1088c2afad6cSKamil Konieczny tmp = ctx->sg; 1089c2afad6cSKamil Konieczny 1090c2afad6cSKamil Konieczny ctx->sg_len = 0; 1091c2afad6cSKamil Konieczny 1092c2afad6cSKamil Konieczny if (ctx->bufcnt) { 1093c2afad6cSKamil Konieczny sg_set_buf(tmp, ctx->dd->xmit_buf, ctx->bufcnt); 1094c2afad6cSKamil Konieczny tmp = sg_next(tmp); 1095c2afad6cSKamil Konieczny ctx->sg_len++; 1096c2afad6cSKamil Konieczny } 1097c2afad6cSKamil Konieczny 1098c2afad6cSKamil Konieczny while (sg && skip >= sg->length) { 1099c2afad6cSKamil Konieczny skip -= sg->length; 1100c2afad6cSKamil Konieczny sg = sg_next(sg); 1101c2afad6cSKamil Konieczny } 1102c2afad6cSKamil Konieczny 1103c2afad6cSKamil Konieczny while (sg && new_len) { 1104c2afad6cSKamil Konieczny len = sg->length - skip; 1105c2afad6cSKamil Konieczny if (new_len < len) 1106c2afad6cSKamil Konieczny len = new_len; 1107c2afad6cSKamil Konieczny 1108c2afad6cSKamil Konieczny new_len -= len; 1109c2afad6cSKamil Konieczny sg_set_page(tmp, sg_page(sg), len, sg->offset + skip); 1110c2afad6cSKamil Konieczny skip = 0; 1111c2afad6cSKamil Konieczny if (new_len <= 0) 1112c2afad6cSKamil Konieczny sg_mark_end(tmp); 1113c2afad6cSKamil Konieczny 1114c2afad6cSKamil Konieczny tmp = sg_next(tmp); 1115c2afad6cSKamil Konieczny ctx->sg_len++; 1116c2afad6cSKamil Konieczny sg = sg_next(sg); 1117c2afad6cSKamil Konieczny } 1118c2afad6cSKamil Konieczny 1119c2afad6cSKamil Konieczny set_bit(HASH_FLAGS_SGS_ALLOCED, &ctx->dd->hash_flags); 1120c2afad6cSKamil Konieczny 1121c2afad6cSKamil Konieczny return 0; 1122c2afad6cSKamil Konieczny } 1123c2afad6cSKamil Konieczny 1124c2afad6cSKamil Konieczny /** 1125c2afad6cSKamil Konieczny * s5p_hash_prepare_sgs() - prepare sg for processing 1126c2afad6cSKamil Konieczny * @ctx: request context 1127c2afad6cSKamil Konieczny * @sg: source scatterlist request 1128c2afad6cSKamil Konieczny * @nbytes: number of bytes to process from sg 1129c2afad6cSKamil Konieczny * @final: final flag 1130c2afad6cSKamil Konieczny * 1131c2afad6cSKamil Konieczny * Check two conditions: (1) if buffers in sg have len aligned data, and (2) 1132c2afad6cSKamil Konieczny * sg table have good aligned elements (list_ok). If one of this checks fails, 1133c2afad6cSKamil Konieczny * then either (1) allocates new buffer for data with s5p_hash_copy_sgs, copy 1134c2afad6cSKamil Konieczny * data into this buffer and prepare request in sgl, or (2) allocates new sg 1135c2afad6cSKamil Konieczny * table and prepare sg elements. 1136c2afad6cSKamil Konieczny * 1137c2afad6cSKamil Konieczny * For digest or finup all conditions can be good, and we may not need any 1138c2afad6cSKamil Konieczny * fixes. 1139c2afad6cSKamil Konieczny */ 1140c2afad6cSKamil Konieczny static int s5p_hash_prepare_sgs(struct s5p_hash_reqctx *ctx, 1141c2afad6cSKamil Konieczny struct scatterlist *sg, 1142c2afad6cSKamil Konieczny unsigned int new_len, bool final) 1143c2afad6cSKamil Konieczny { 1144c2afad6cSKamil Konieczny unsigned int skip = ctx->skip, nbytes = new_len, n = 0; 1145c2afad6cSKamil Konieczny bool aligned = true, list_ok = true; 1146c2afad6cSKamil Konieczny struct scatterlist *sg_tmp = sg; 1147c2afad6cSKamil Konieczny 1148c2afad6cSKamil Konieczny if (!sg || !sg->length || !new_len) 1149c2afad6cSKamil Konieczny return 0; 1150c2afad6cSKamil Konieczny 1151c2afad6cSKamil Konieczny if (skip || !final) 1152c2afad6cSKamil Konieczny list_ok = false; 1153c2afad6cSKamil Konieczny 1154c2afad6cSKamil Konieczny while (nbytes > 0 && sg_tmp) { 1155c2afad6cSKamil Konieczny n++; 1156c2afad6cSKamil Konieczny if (skip >= sg_tmp->length) { 1157c2afad6cSKamil Konieczny skip -= sg_tmp->length; 1158c2afad6cSKamil Konieczny if (!sg_tmp->length) { 1159c2afad6cSKamil Konieczny aligned = false; 1160c2afad6cSKamil Konieczny break; 1161c2afad6cSKamil Konieczny } 1162c2afad6cSKamil Konieczny } else { 1163c2afad6cSKamil Konieczny if (!IS_ALIGNED(sg_tmp->length - skip, BUFLEN)) { 1164c2afad6cSKamil Konieczny aligned = false; 1165c2afad6cSKamil Konieczny break; 1166c2afad6cSKamil Konieczny } 1167c2afad6cSKamil Konieczny 1168c2afad6cSKamil Konieczny if (nbytes < sg_tmp->length - skip) { 1169c2afad6cSKamil Konieczny list_ok = false; 1170c2afad6cSKamil Konieczny break; 1171c2afad6cSKamil Konieczny } 1172c2afad6cSKamil Konieczny 1173c2afad6cSKamil Konieczny nbytes -= sg_tmp->length - skip; 1174c2afad6cSKamil Konieczny skip = 0; 1175c2afad6cSKamil Konieczny } 1176c2afad6cSKamil Konieczny 1177c2afad6cSKamil Konieczny sg_tmp = sg_next(sg_tmp); 1178c2afad6cSKamil Konieczny } 1179c2afad6cSKamil Konieczny 1180c2afad6cSKamil Konieczny if (!aligned) 1181c2afad6cSKamil Konieczny return s5p_hash_copy_sgs(ctx, sg, new_len); 1182c2afad6cSKamil Konieczny else if (!list_ok) 1183c2afad6cSKamil Konieczny return s5p_hash_copy_sg_lists(ctx, sg, new_len); 1184c2afad6cSKamil Konieczny 1185c2afad6cSKamil Konieczny /* 1186c2afad6cSKamil Konieczny * Have aligned data from previous operation and/or current 1187c2afad6cSKamil Konieczny * Note: will enter here only if (digest or finup) and aligned 1188c2afad6cSKamil Konieczny */ 1189c2afad6cSKamil Konieczny if (ctx->bufcnt) { 1190c2afad6cSKamil Konieczny ctx->sg_len = n; 1191c2afad6cSKamil Konieczny sg_init_table(ctx->sgl, 2); 1192c2afad6cSKamil Konieczny sg_set_buf(ctx->sgl, ctx->dd->xmit_buf, ctx->bufcnt); 1193c2afad6cSKamil Konieczny sg_chain(ctx->sgl, 2, sg); 1194c2afad6cSKamil Konieczny ctx->sg = ctx->sgl; 1195c2afad6cSKamil Konieczny ctx->sg_len++; 1196c2afad6cSKamil Konieczny } else { 1197c2afad6cSKamil Konieczny ctx->sg = sg; 1198c2afad6cSKamil Konieczny ctx->sg_len = n; 1199c2afad6cSKamil Konieczny } 1200c2afad6cSKamil Konieczny 1201c2afad6cSKamil Konieczny return 0; 1202c2afad6cSKamil Konieczny } 1203c2afad6cSKamil Konieczny 1204c2afad6cSKamil Konieczny /** 1205c2afad6cSKamil Konieczny * s5p_hash_prepare_request() - prepare request for processing 1206c2afad6cSKamil Konieczny * @req: AHASH request 1207c2afad6cSKamil Konieczny * @update: true if UPDATE op 1208c2afad6cSKamil Konieczny * 1209c2afad6cSKamil Konieczny * Note 1: we can have update flag _and_ final flag at the same time. 1210c2afad6cSKamil Konieczny * Note 2: we enter here when digcnt > BUFLEN (=HASH_BLOCK_SIZE) or 1211c2afad6cSKamil Konieczny * either req->nbytes or ctx->bufcnt + req->nbytes is > BUFLEN or 1212c2afad6cSKamil Konieczny * we have final op 1213c2afad6cSKamil Konieczny */ 1214c2afad6cSKamil Konieczny static int s5p_hash_prepare_request(struct ahash_request *req, bool update) 1215c2afad6cSKamil Konieczny { 1216c2afad6cSKamil Konieczny struct s5p_hash_reqctx *ctx = ahash_request_ctx(req); 1217c2afad6cSKamil Konieczny bool final = ctx->finup; 1218c2afad6cSKamil Konieczny int xmit_len, hash_later, nbytes; 1219c2afad6cSKamil Konieczny int ret; 1220c2afad6cSKamil Konieczny 1221c2afad6cSKamil Konieczny if (update) 1222c2afad6cSKamil Konieczny nbytes = req->nbytes; 1223c2afad6cSKamil Konieczny else 1224c2afad6cSKamil Konieczny nbytes = 0; 1225c2afad6cSKamil Konieczny 1226c2afad6cSKamil Konieczny ctx->total = nbytes + ctx->bufcnt; 1227c2afad6cSKamil Konieczny if (!ctx->total) 1228c2afad6cSKamil Konieczny return 0; 1229c2afad6cSKamil Konieczny 1230c2afad6cSKamil Konieczny if (nbytes && (!IS_ALIGNED(ctx->bufcnt, BUFLEN))) { 1231c2afad6cSKamil Konieczny /* bytes left from previous request, so fill up to BUFLEN */ 1232c2afad6cSKamil Konieczny int len = BUFLEN - ctx->bufcnt % BUFLEN; 1233c2afad6cSKamil Konieczny 1234c2afad6cSKamil Konieczny if (len > nbytes) 1235c2afad6cSKamil Konieczny len = nbytes; 1236c2afad6cSKamil Konieczny 1237c2afad6cSKamil Konieczny scatterwalk_map_and_copy(ctx->buffer + ctx->bufcnt, req->src, 1238c2afad6cSKamil Konieczny 0, len, 0); 1239c2afad6cSKamil Konieczny ctx->bufcnt += len; 1240c2afad6cSKamil Konieczny nbytes -= len; 1241c2afad6cSKamil Konieczny ctx->skip = len; 1242c2afad6cSKamil Konieczny } else { 1243c2afad6cSKamil Konieczny ctx->skip = 0; 1244c2afad6cSKamil Konieczny } 1245c2afad6cSKamil Konieczny 1246c2afad6cSKamil Konieczny if (ctx->bufcnt) 1247c2afad6cSKamil Konieczny memcpy(ctx->dd->xmit_buf, ctx->buffer, ctx->bufcnt); 1248c2afad6cSKamil Konieczny 1249c2afad6cSKamil Konieczny xmit_len = ctx->total; 1250c2afad6cSKamil Konieczny if (final) { 1251c2afad6cSKamil Konieczny hash_later = 0; 1252c2afad6cSKamil Konieczny } else { 1253c2afad6cSKamil Konieczny if (IS_ALIGNED(xmit_len, BUFLEN)) 1254c2afad6cSKamil Konieczny xmit_len -= BUFLEN; 1255c2afad6cSKamil Konieczny else 1256c2afad6cSKamil Konieczny xmit_len -= xmit_len & (BUFLEN - 1); 1257c2afad6cSKamil Konieczny 1258c2afad6cSKamil Konieczny hash_later = ctx->total - xmit_len; 1259c2afad6cSKamil Konieczny /* copy hash_later bytes from end of req->src */ 1260c2afad6cSKamil Konieczny /* previous bytes are in xmit_buf, so no overwrite */ 1261c2afad6cSKamil Konieczny scatterwalk_map_and_copy(ctx->buffer, req->src, 1262c2afad6cSKamil Konieczny req->nbytes - hash_later, 1263c2afad6cSKamil Konieczny hash_later, 0); 1264c2afad6cSKamil Konieczny } 1265c2afad6cSKamil Konieczny 1266c2afad6cSKamil Konieczny if (xmit_len > BUFLEN) { 1267c2afad6cSKamil Konieczny ret = s5p_hash_prepare_sgs(ctx, req->src, nbytes - hash_later, 1268c2afad6cSKamil Konieczny final); 1269c2afad6cSKamil Konieczny if (ret) 1270c2afad6cSKamil Konieczny return ret; 1271c2afad6cSKamil Konieczny } else { 1272c2afad6cSKamil Konieczny /* have buffered data only */ 1273c2afad6cSKamil Konieczny if (unlikely(!ctx->bufcnt)) { 1274c2afad6cSKamil Konieczny /* first update didn't fill up buffer */ 1275c2afad6cSKamil Konieczny scatterwalk_map_and_copy(ctx->dd->xmit_buf, req->src, 1276c2afad6cSKamil Konieczny 0, xmit_len, 0); 1277c2afad6cSKamil Konieczny } 1278c2afad6cSKamil Konieczny 1279c2afad6cSKamil Konieczny sg_init_table(ctx->sgl, 1); 1280c2afad6cSKamil Konieczny sg_set_buf(ctx->sgl, ctx->dd->xmit_buf, xmit_len); 1281c2afad6cSKamil Konieczny 1282c2afad6cSKamil Konieczny ctx->sg = ctx->sgl; 1283c2afad6cSKamil Konieczny ctx->sg_len = 1; 1284c2afad6cSKamil Konieczny } 1285c2afad6cSKamil Konieczny 1286c2afad6cSKamil Konieczny ctx->bufcnt = hash_later; 1287c2afad6cSKamil Konieczny if (!final) 1288c2afad6cSKamil Konieczny ctx->total = xmit_len; 1289c2afad6cSKamil Konieczny 1290c2afad6cSKamil Konieczny return 0; 1291c2afad6cSKamil Konieczny } 1292c2afad6cSKamil Konieczny 1293c2afad6cSKamil Konieczny /** 1294c2afad6cSKamil Konieczny * s5p_hash_update_dma_stop() - unmap DMA 1295c2afad6cSKamil Konieczny * @dd: secss device 1296c2afad6cSKamil Konieczny * 1297c2afad6cSKamil Konieczny * Unmap scatterlist ctx->sg. 1298c2afad6cSKamil Konieczny */ 1299c2afad6cSKamil Konieczny static void s5p_hash_update_dma_stop(struct s5p_aes_dev *dd) 1300c2afad6cSKamil Konieczny { 13016584eacbSKrzysztof Kozlowski const struct s5p_hash_reqctx *ctx = ahash_request_ctx(dd->hash_req); 1302c2afad6cSKamil Konieczny 1303c2afad6cSKamil Konieczny dma_unmap_sg(dd->dev, ctx->sg, ctx->sg_len, DMA_TO_DEVICE); 1304c2afad6cSKamil Konieczny clear_bit(HASH_FLAGS_DMA_ACTIVE, &dd->hash_flags); 1305c2afad6cSKamil Konieczny } 1306c2afad6cSKamil Konieczny 1307c2afad6cSKamil Konieczny /** 1308c2afad6cSKamil Konieczny * s5p_hash_finish() - copy calculated digest to crypto layer 1309c2afad6cSKamil Konieczny * @req: AHASH request 1310c2afad6cSKamil Konieczny */ 1311c2afad6cSKamil Konieczny static void s5p_hash_finish(struct ahash_request *req) 1312c2afad6cSKamil Konieczny { 1313c2afad6cSKamil Konieczny struct s5p_hash_reqctx *ctx = ahash_request_ctx(req); 1314c2afad6cSKamil Konieczny struct s5p_aes_dev *dd = ctx->dd; 1315c2afad6cSKamil Konieczny 1316c2afad6cSKamil Konieczny if (ctx->digcnt) 1317c2afad6cSKamil Konieczny s5p_hash_copy_result(req); 1318c2afad6cSKamil Konieczny 1319c2afad6cSKamil Konieczny dev_dbg(dd->dev, "hash_finish digcnt: %lld\n", ctx->digcnt); 1320c2afad6cSKamil Konieczny } 1321c2afad6cSKamil Konieczny 1322c2afad6cSKamil Konieczny /** 1323c2afad6cSKamil Konieczny * s5p_hash_finish_req() - finish request 1324c2afad6cSKamil Konieczny * @req: AHASH request 1325c2afad6cSKamil Konieczny * @err: error 1326c2afad6cSKamil Konieczny */ 1327c2afad6cSKamil Konieczny static void s5p_hash_finish_req(struct ahash_request *req, int err) 1328c2afad6cSKamil Konieczny { 1329c2afad6cSKamil Konieczny struct s5p_hash_reqctx *ctx = ahash_request_ctx(req); 1330c2afad6cSKamil Konieczny struct s5p_aes_dev *dd = ctx->dd; 1331c2afad6cSKamil Konieczny unsigned long flags; 1332c2afad6cSKamil Konieczny 1333c2afad6cSKamil Konieczny if (test_bit(HASH_FLAGS_SGS_COPIED, &dd->hash_flags)) 1334c2afad6cSKamil Konieczny free_pages((unsigned long)sg_virt(ctx->sg), 1335c2afad6cSKamil Konieczny get_order(ctx->sg->length)); 1336c2afad6cSKamil Konieczny 1337c2afad6cSKamil Konieczny if (test_bit(HASH_FLAGS_SGS_ALLOCED, &dd->hash_flags)) 1338c2afad6cSKamil Konieczny kfree(ctx->sg); 1339c2afad6cSKamil Konieczny 1340c2afad6cSKamil Konieczny ctx->sg = NULL; 1341c2afad6cSKamil Konieczny dd->hash_flags &= ~(BIT(HASH_FLAGS_SGS_ALLOCED) | 1342c2afad6cSKamil Konieczny BIT(HASH_FLAGS_SGS_COPIED)); 1343c2afad6cSKamil Konieczny 1344c2afad6cSKamil Konieczny if (!err && !ctx->error) { 1345c2afad6cSKamil Konieczny s5p_hash_read_msg(req); 1346c2afad6cSKamil Konieczny if (test_bit(HASH_FLAGS_FINAL, &dd->hash_flags)) 1347c2afad6cSKamil Konieczny s5p_hash_finish(req); 1348c2afad6cSKamil Konieczny } else { 1349c2afad6cSKamil Konieczny ctx->error = true; 1350c2afad6cSKamil Konieczny } 1351c2afad6cSKamil Konieczny 1352c2afad6cSKamil Konieczny spin_lock_irqsave(&dd->hash_lock, flags); 1353c2afad6cSKamil Konieczny dd->hash_flags &= ~(BIT(HASH_FLAGS_BUSY) | BIT(HASH_FLAGS_FINAL) | 1354c2afad6cSKamil Konieczny BIT(HASH_FLAGS_DMA_READY) | 1355c2afad6cSKamil Konieczny BIT(HASH_FLAGS_OUTPUT_READY)); 1356c2afad6cSKamil Konieczny spin_unlock_irqrestore(&dd->hash_lock, flags); 1357c2afad6cSKamil Konieczny 1358c2afad6cSKamil Konieczny if (req->base.complete) 1359c2afad6cSKamil Konieczny req->base.complete(&req->base, err); 1360c2afad6cSKamil Konieczny } 1361c2afad6cSKamil Konieczny 1362c2afad6cSKamil Konieczny /** 1363c2afad6cSKamil Konieczny * s5p_hash_handle_queue() - handle hash queue 1364c2afad6cSKamil Konieczny * @dd: device s5p_aes_dev 1365c2afad6cSKamil Konieczny * @req: AHASH request 1366c2afad6cSKamil Konieczny * 1367c2afad6cSKamil Konieczny * If req!=NULL enqueue it on dd->queue, if FLAGS_BUSY is not set on the 1368c2afad6cSKamil Konieczny * device then processes the first request from the dd->queue 1369c2afad6cSKamil Konieczny * 1370c2afad6cSKamil Konieczny * Returns: see s5p_hash_final below. 1371c2afad6cSKamil Konieczny */ 1372c2afad6cSKamil Konieczny static int s5p_hash_handle_queue(struct s5p_aes_dev *dd, 1373c2afad6cSKamil Konieczny struct ahash_request *req) 1374c2afad6cSKamil Konieczny { 1375c2afad6cSKamil Konieczny struct crypto_async_request *async_req, *backlog; 1376c2afad6cSKamil Konieczny struct s5p_hash_reqctx *ctx; 1377c2afad6cSKamil Konieczny unsigned long flags; 1378c2afad6cSKamil Konieczny int err = 0, ret = 0; 1379c2afad6cSKamil Konieczny 1380c2afad6cSKamil Konieczny retry: 1381c2afad6cSKamil Konieczny spin_lock_irqsave(&dd->hash_lock, flags); 1382c2afad6cSKamil Konieczny if (req) 1383c2afad6cSKamil Konieczny ret = ahash_enqueue_request(&dd->hash_queue, req); 1384c2afad6cSKamil Konieczny 1385c2afad6cSKamil Konieczny if (test_bit(HASH_FLAGS_BUSY, &dd->hash_flags)) { 1386c2afad6cSKamil Konieczny spin_unlock_irqrestore(&dd->hash_lock, flags); 1387c2afad6cSKamil Konieczny return ret; 1388c2afad6cSKamil Konieczny } 1389c2afad6cSKamil Konieczny 1390c2afad6cSKamil Konieczny backlog = crypto_get_backlog(&dd->hash_queue); 1391c2afad6cSKamil Konieczny async_req = crypto_dequeue_request(&dd->hash_queue); 1392c2afad6cSKamil Konieczny if (async_req) 1393c2afad6cSKamil Konieczny set_bit(HASH_FLAGS_BUSY, &dd->hash_flags); 1394c2afad6cSKamil Konieczny 1395c2afad6cSKamil Konieczny spin_unlock_irqrestore(&dd->hash_lock, flags); 1396c2afad6cSKamil Konieczny 1397c2afad6cSKamil Konieczny if (!async_req) 1398c2afad6cSKamil Konieczny return ret; 1399c2afad6cSKamil Konieczny 1400c2afad6cSKamil Konieczny if (backlog) 1401c2afad6cSKamil Konieczny backlog->complete(backlog, -EINPROGRESS); 1402c2afad6cSKamil Konieczny 1403c2afad6cSKamil Konieczny req = ahash_request_cast(async_req); 1404c2afad6cSKamil Konieczny dd->hash_req = req; 1405c2afad6cSKamil Konieczny ctx = ahash_request_ctx(req); 1406c2afad6cSKamil Konieczny 1407c2afad6cSKamil Konieczny err = s5p_hash_prepare_request(req, ctx->op_update); 1408c2afad6cSKamil Konieczny if (err || !ctx->total) 1409c2afad6cSKamil Konieczny goto out; 1410c2afad6cSKamil Konieczny 1411c2afad6cSKamil Konieczny dev_dbg(dd->dev, "handling new req, op_update: %u, nbytes: %d\n", 1412c2afad6cSKamil Konieczny ctx->op_update, req->nbytes); 1413c2afad6cSKamil Konieczny 1414c2afad6cSKamil Konieczny s5p_ahash_dma_init(dd, SSS_HASHIN_INDEPENDENT); 1415c2afad6cSKamil Konieczny if (ctx->digcnt) 1416c2afad6cSKamil Konieczny s5p_hash_write_iv(req); /* restore hash IV */ 1417c2afad6cSKamil Konieczny 1418c2afad6cSKamil Konieczny if (ctx->op_update) { /* HASH_OP_UPDATE */ 1419c2afad6cSKamil Konieczny err = s5p_hash_xmit_dma(dd, ctx->total, ctx->finup); 1420c2afad6cSKamil Konieczny if (err != -EINPROGRESS && ctx->finup && !ctx->error) 1421c2afad6cSKamil Konieczny /* no final() after finup() */ 1422c2afad6cSKamil Konieczny err = s5p_hash_xmit_dma(dd, ctx->total, true); 1423c2afad6cSKamil Konieczny } else { /* HASH_OP_FINAL */ 1424c2afad6cSKamil Konieczny err = s5p_hash_xmit_dma(dd, ctx->total, true); 1425c2afad6cSKamil Konieczny } 1426c2afad6cSKamil Konieczny out: 1427c2afad6cSKamil Konieczny if (err != -EINPROGRESS) { 1428c2afad6cSKamil Konieczny /* hash_tasklet_cb will not finish it, so do it here */ 1429c2afad6cSKamil Konieczny s5p_hash_finish_req(req, err); 1430c2afad6cSKamil Konieczny req = NULL; 1431c2afad6cSKamil Konieczny 1432c2afad6cSKamil Konieczny /* 1433c2afad6cSKamil Konieczny * Execute next request immediately if there is anything 1434c2afad6cSKamil Konieczny * in queue. 1435c2afad6cSKamil Konieczny */ 1436c2afad6cSKamil Konieczny goto retry; 1437c2afad6cSKamil Konieczny } 1438c2afad6cSKamil Konieczny 1439c2afad6cSKamil Konieczny return ret; 1440c2afad6cSKamil Konieczny } 1441c2afad6cSKamil Konieczny 1442c2afad6cSKamil Konieczny /** 1443c2afad6cSKamil Konieczny * s5p_hash_tasklet_cb() - hash tasklet 1444c2afad6cSKamil Konieczny * @data: ptr to s5p_aes_dev 1445c2afad6cSKamil Konieczny */ 1446c2afad6cSKamil Konieczny static void s5p_hash_tasklet_cb(unsigned long data) 1447c2afad6cSKamil Konieczny { 1448c2afad6cSKamil Konieczny struct s5p_aes_dev *dd = (struct s5p_aes_dev *)data; 1449c2afad6cSKamil Konieczny 1450c2afad6cSKamil Konieczny if (!test_bit(HASH_FLAGS_BUSY, &dd->hash_flags)) { 1451c2afad6cSKamil Konieczny s5p_hash_handle_queue(dd, NULL); 1452c2afad6cSKamil Konieczny return; 1453c2afad6cSKamil Konieczny } 1454c2afad6cSKamil Konieczny 1455c2afad6cSKamil Konieczny if (test_bit(HASH_FLAGS_DMA_READY, &dd->hash_flags)) { 1456c2afad6cSKamil Konieczny if (test_and_clear_bit(HASH_FLAGS_DMA_ACTIVE, 1457c2afad6cSKamil Konieczny &dd->hash_flags)) { 1458c2afad6cSKamil Konieczny s5p_hash_update_dma_stop(dd); 1459c2afad6cSKamil Konieczny } 1460c2afad6cSKamil Konieczny 1461c2afad6cSKamil Konieczny if (test_and_clear_bit(HASH_FLAGS_OUTPUT_READY, 1462c2afad6cSKamil Konieczny &dd->hash_flags)) { 1463c2afad6cSKamil Konieczny /* hash or semi-hash ready */ 1464c2afad6cSKamil Konieczny clear_bit(HASH_FLAGS_DMA_READY, &dd->hash_flags); 1465c2afad6cSKamil Konieczny goto finish; 1466c2afad6cSKamil Konieczny } 1467c2afad6cSKamil Konieczny } 1468c2afad6cSKamil Konieczny 1469c2afad6cSKamil Konieczny return; 1470c2afad6cSKamil Konieczny 1471c2afad6cSKamil Konieczny finish: 1472c2afad6cSKamil Konieczny /* finish curent request */ 1473c2afad6cSKamil Konieczny s5p_hash_finish_req(dd->hash_req, 0); 1474c2afad6cSKamil Konieczny 1475c2afad6cSKamil Konieczny /* If we are not busy, process next req */ 1476c2afad6cSKamil Konieczny if (!test_bit(HASH_FLAGS_BUSY, &dd->hash_flags)) 1477c2afad6cSKamil Konieczny s5p_hash_handle_queue(dd, NULL); 1478c2afad6cSKamil Konieczny } 1479c2afad6cSKamil Konieczny 1480c2afad6cSKamil Konieczny /** 1481c2afad6cSKamil Konieczny * s5p_hash_enqueue() - enqueue request 1482c2afad6cSKamil Konieczny * @req: AHASH request 1483c2afad6cSKamil Konieczny * @op: operation UPDATE (true) or FINAL (false) 1484c2afad6cSKamil Konieczny * 1485c2afad6cSKamil Konieczny * Returns: see s5p_hash_final below. 1486c2afad6cSKamil Konieczny */ 1487c2afad6cSKamil Konieczny static int s5p_hash_enqueue(struct ahash_request *req, bool op) 1488c2afad6cSKamil Konieczny { 1489c2afad6cSKamil Konieczny struct s5p_hash_reqctx *ctx = ahash_request_ctx(req); 1490c2afad6cSKamil Konieczny struct s5p_hash_ctx *tctx = crypto_tfm_ctx(req->base.tfm); 1491c2afad6cSKamil Konieczny 1492c2afad6cSKamil Konieczny ctx->op_update = op; 1493c2afad6cSKamil Konieczny 1494c2afad6cSKamil Konieczny return s5p_hash_handle_queue(tctx->dd, req); 1495c2afad6cSKamil Konieczny } 1496c2afad6cSKamil Konieczny 1497c2afad6cSKamil Konieczny /** 1498c2afad6cSKamil Konieczny * s5p_hash_update() - process the hash input data 1499c2afad6cSKamil Konieczny * @req: AHASH request 1500c2afad6cSKamil Konieczny * 1501c2afad6cSKamil Konieczny * If request will fit in buffer, copy it and return immediately 1502c2afad6cSKamil Konieczny * else enqueue it with OP_UPDATE. 1503c2afad6cSKamil Konieczny * 1504c2afad6cSKamil Konieczny * Returns: see s5p_hash_final below. 1505c2afad6cSKamil Konieczny */ 1506c2afad6cSKamil Konieczny static int s5p_hash_update(struct ahash_request *req) 1507c2afad6cSKamil Konieczny { 1508c2afad6cSKamil Konieczny struct s5p_hash_reqctx *ctx = ahash_request_ctx(req); 1509c2afad6cSKamil Konieczny 1510c2afad6cSKamil Konieczny if (!req->nbytes) 1511c2afad6cSKamil Konieczny return 0; 1512c2afad6cSKamil Konieczny 1513c2afad6cSKamil Konieczny if (ctx->bufcnt + req->nbytes <= BUFLEN) { 1514c2afad6cSKamil Konieczny scatterwalk_map_and_copy(ctx->buffer + ctx->bufcnt, req->src, 1515c2afad6cSKamil Konieczny 0, req->nbytes, 0); 1516c2afad6cSKamil Konieczny ctx->bufcnt += req->nbytes; 1517c2afad6cSKamil Konieczny return 0; 1518c2afad6cSKamil Konieczny } 1519c2afad6cSKamil Konieczny 1520c2afad6cSKamil Konieczny return s5p_hash_enqueue(req, true); /* HASH_OP_UPDATE */ 1521c2afad6cSKamil Konieczny } 1522c2afad6cSKamil Konieczny 1523c2afad6cSKamil Konieczny /** 1524c2afad6cSKamil Konieczny * s5p_hash_shash_digest() - calculate shash digest 1525c2afad6cSKamil Konieczny * @tfm: crypto transformation 1526c2afad6cSKamil Konieczny * @flags: tfm flags 1527c2afad6cSKamil Konieczny * @data: input data 1528c2afad6cSKamil Konieczny * @len: length of data 1529c2afad6cSKamil Konieczny * @out: output buffer 1530c2afad6cSKamil Konieczny */ 1531c2afad6cSKamil Konieczny static int s5p_hash_shash_digest(struct crypto_shash *tfm, u32 flags, 1532c2afad6cSKamil Konieczny const u8 *data, unsigned int len, u8 *out) 1533c2afad6cSKamil Konieczny { 1534c2afad6cSKamil Konieczny SHASH_DESC_ON_STACK(shash, tfm); 1535c2afad6cSKamil Konieczny 1536c2afad6cSKamil Konieczny shash->tfm = tfm; 1537c2afad6cSKamil Konieczny shash->flags = flags & ~CRYPTO_TFM_REQ_MAY_SLEEP; 1538c2afad6cSKamil Konieczny 1539c2afad6cSKamil Konieczny return crypto_shash_digest(shash, data, len, out); 1540c2afad6cSKamil Konieczny } 1541c2afad6cSKamil Konieczny 1542c2afad6cSKamil Konieczny /** 1543c2afad6cSKamil Konieczny * s5p_hash_final_shash() - calculate shash digest 1544c2afad6cSKamil Konieczny * @req: AHASH request 1545c2afad6cSKamil Konieczny */ 1546c2afad6cSKamil Konieczny static int s5p_hash_final_shash(struct ahash_request *req) 1547c2afad6cSKamil Konieczny { 1548c2afad6cSKamil Konieczny struct s5p_hash_ctx *tctx = crypto_tfm_ctx(req->base.tfm); 1549c2afad6cSKamil Konieczny struct s5p_hash_reqctx *ctx = ahash_request_ctx(req); 1550c2afad6cSKamil Konieczny 1551c2afad6cSKamil Konieczny return s5p_hash_shash_digest(tctx->fallback, req->base.flags, 1552c2afad6cSKamil Konieczny ctx->buffer, ctx->bufcnt, req->result); 1553c2afad6cSKamil Konieczny } 1554c2afad6cSKamil Konieczny 1555c2afad6cSKamil Konieczny /** 1556c2afad6cSKamil Konieczny * s5p_hash_final() - close up hash and calculate digest 1557c2afad6cSKamil Konieczny * @req: AHASH request 1558c2afad6cSKamil Konieczny * 1559c2afad6cSKamil Konieczny * Note: in final req->src do not have any data, and req->nbytes can be 1560c2afad6cSKamil Konieczny * non-zero. 1561c2afad6cSKamil Konieczny * 1562c2afad6cSKamil Konieczny * If there were no input data processed yet and the buffered hash data is 1563c2afad6cSKamil Konieczny * less than BUFLEN (64) then calculate the final hash immediately by using 1564c2afad6cSKamil Konieczny * SW algorithm fallback. 1565c2afad6cSKamil Konieczny * 1566c2afad6cSKamil Konieczny * Otherwise enqueues the current AHASH request with OP_FINAL operation op 1567c2afad6cSKamil Konieczny * and finalize hash message in HW. Note that if digcnt!=0 then there were 1568c2afad6cSKamil Konieczny * previous update op, so there are always some buffered bytes in ctx->buffer, 1569c2afad6cSKamil Konieczny * which means that ctx->bufcnt!=0 1570c2afad6cSKamil Konieczny * 1571c2afad6cSKamil Konieczny * Returns: 1572c2afad6cSKamil Konieczny * 0 if the request has been processed immediately, 1573c2afad6cSKamil Konieczny * -EINPROGRESS if the operation has been queued for later execution or is set 1574c2afad6cSKamil Konieczny * to processing by HW, 1575c2afad6cSKamil Konieczny * -EBUSY if queue is full and request should be resubmitted later, 1576c2afad6cSKamil Konieczny * other negative values denotes an error. 1577c2afad6cSKamil Konieczny */ 1578c2afad6cSKamil Konieczny static int s5p_hash_final(struct ahash_request *req) 1579c2afad6cSKamil Konieczny { 1580c2afad6cSKamil Konieczny struct s5p_hash_reqctx *ctx = ahash_request_ctx(req); 1581c2afad6cSKamil Konieczny 1582c2afad6cSKamil Konieczny ctx->finup = true; 1583c2afad6cSKamil Konieczny if (ctx->error) 1584c2afad6cSKamil Konieczny return -EINVAL; /* uncompleted hash is not needed */ 1585c2afad6cSKamil Konieczny 1586c2afad6cSKamil Konieczny if (!ctx->digcnt && ctx->bufcnt < BUFLEN) 1587c2afad6cSKamil Konieczny return s5p_hash_final_shash(req); 1588c2afad6cSKamil Konieczny 1589c2afad6cSKamil Konieczny return s5p_hash_enqueue(req, false); /* HASH_OP_FINAL */ 1590c2afad6cSKamil Konieczny } 1591c2afad6cSKamil Konieczny 1592c2afad6cSKamil Konieczny /** 1593c2afad6cSKamil Konieczny * s5p_hash_finup() - process last req->src and calculate digest 1594c2afad6cSKamil Konieczny * @req: AHASH request containing the last update data 1595c2afad6cSKamil Konieczny * 1596c2afad6cSKamil Konieczny * Return values: see s5p_hash_final above. 1597c2afad6cSKamil Konieczny */ 1598c2afad6cSKamil Konieczny static int s5p_hash_finup(struct ahash_request *req) 1599c2afad6cSKamil Konieczny { 1600c2afad6cSKamil Konieczny struct s5p_hash_reqctx *ctx = ahash_request_ctx(req); 1601c2afad6cSKamil Konieczny int err1, err2; 1602c2afad6cSKamil Konieczny 1603c2afad6cSKamil Konieczny ctx->finup = true; 1604c2afad6cSKamil Konieczny 1605c2afad6cSKamil Konieczny err1 = s5p_hash_update(req); 1606c2afad6cSKamil Konieczny if (err1 == -EINPROGRESS || err1 == -EBUSY) 1607c2afad6cSKamil Konieczny return err1; 1608c2afad6cSKamil Konieczny 1609c2afad6cSKamil Konieczny /* 1610c2afad6cSKamil Konieczny * final() has to be always called to cleanup resources even if 1611c2afad6cSKamil Konieczny * update() failed, except EINPROGRESS or calculate digest for small 1612c2afad6cSKamil Konieczny * size 1613c2afad6cSKamil Konieczny */ 1614c2afad6cSKamil Konieczny err2 = s5p_hash_final(req); 1615c2afad6cSKamil Konieczny 1616c2afad6cSKamil Konieczny return err1 ?: err2; 1617c2afad6cSKamil Konieczny } 1618c2afad6cSKamil Konieczny 1619c2afad6cSKamil Konieczny /** 1620c2afad6cSKamil Konieczny * s5p_hash_init() - initialize AHASH request contex 1621c2afad6cSKamil Konieczny * @req: AHASH request 1622c2afad6cSKamil Konieczny * 1623c2afad6cSKamil Konieczny * Init async hash request context. 1624c2afad6cSKamil Konieczny */ 1625c2afad6cSKamil Konieczny static int s5p_hash_init(struct ahash_request *req) 1626c2afad6cSKamil Konieczny { 1627c2afad6cSKamil Konieczny struct s5p_hash_reqctx *ctx = ahash_request_ctx(req); 1628c2afad6cSKamil Konieczny struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); 1629c2afad6cSKamil Konieczny struct s5p_hash_ctx *tctx = crypto_ahash_ctx(tfm); 1630c2afad6cSKamil Konieczny 1631c2afad6cSKamil Konieczny ctx->dd = tctx->dd; 1632c2afad6cSKamil Konieczny ctx->error = false; 1633c2afad6cSKamil Konieczny ctx->finup = false; 1634c2afad6cSKamil Konieczny ctx->bufcnt = 0; 1635c2afad6cSKamil Konieczny ctx->digcnt = 0; 1636c2afad6cSKamil Konieczny ctx->total = 0; 1637c2afad6cSKamil Konieczny ctx->skip = 0; 1638c2afad6cSKamil Konieczny 1639c2afad6cSKamil Konieczny dev_dbg(tctx->dd->dev, "init: digest size: %d\n", 1640c2afad6cSKamil Konieczny crypto_ahash_digestsize(tfm)); 1641c2afad6cSKamil Konieczny 1642c2afad6cSKamil Konieczny switch (crypto_ahash_digestsize(tfm)) { 1643c2afad6cSKamil Konieczny case MD5_DIGEST_SIZE: 1644c2afad6cSKamil Konieczny ctx->engine = SSS_HASH_ENGINE_MD5; 1645c2afad6cSKamil Konieczny ctx->nregs = HASH_MD5_MAX_REG; 1646c2afad6cSKamil Konieczny break; 1647c2afad6cSKamil Konieczny case SHA1_DIGEST_SIZE: 1648c2afad6cSKamil Konieczny ctx->engine = SSS_HASH_ENGINE_SHA1; 1649c2afad6cSKamil Konieczny ctx->nregs = HASH_SHA1_MAX_REG; 1650c2afad6cSKamil Konieczny break; 1651c2afad6cSKamil Konieczny case SHA256_DIGEST_SIZE: 1652c2afad6cSKamil Konieczny ctx->engine = SSS_HASH_ENGINE_SHA256; 1653c2afad6cSKamil Konieczny ctx->nregs = HASH_SHA256_MAX_REG; 1654c2afad6cSKamil Konieczny break; 1655c2afad6cSKamil Konieczny default: 1656c2afad6cSKamil Konieczny ctx->error = true; 1657c2afad6cSKamil Konieczny return -EINVAL; 1658c2afad6cSKamil Konieczny } 1659c2afad6cSKamil Konieczny 1660c2afad6cSKamil Konieczny return 0; 1661c2afad6cSKamil Konieczny } 1662c2afad6cSKamil Konieczny 1663c2afad6cSKamil Konieczny /** 1664c2afad6cSKamil Konieczny * s5p_hash_digest - calculate digest from req->src 1665c2afad6cSKamil Konieczny * @req: AHASH request 1666c2afad6cSKamil Konieczny * 1667c2afad6cSKamil Konieczny * Return values: see s5p_hash_final above. 1668c2afad6cSKamil Konieczny */ 1669c2afad6cSKamil Konieczny static int s5p_hash_digest(struct ahash_request *req) 1670c2afad6cSKamil Konieczny { 1671c2afad6cSKamil Konieczny return s5p_hash_init(req) ?: s5p_hash_finup(req); 1672c2afad6cSKamil Konieczny } 1673c2afad6cSKamil Konieczny 1674c2afad6cSKamil Konieczny /** 1675c2afad6cSKamil Konieczny * s5p_hash_cra_init_alg - init crypto alg transformation 1676c2afad6cSKamil Konieczny * @tfm: crypto transformation 1677c2afad6cSKamil Konieczny */ 1678c2afad6cSKamil Konieczny static int s5p_hash_cra_init_alg(struct crypto_tfm *tfm) 1679c2afad6cSKamil Konieczny { 1680c2afad6cSKamil Konieczny struct s5p_hash_ctx *tctx = crypto_tfm_ctx(tfm); 1681c2afad6cSKamil Konieczny const char *alg_name = crypto_tfm_alg_name(tfm); 1682c2afad6cSKamil Konieczny 1683c2afad6cSKamil Konieczny tctx->dd = s5p_dev; 1684c2afad6cSKamil Konieczny /* Allocate a fallback and abort if it failed. */ 1685c2afad6cSKamil Konieczny tctx->fallback = crypto_alloc_shash(alg_name, 0, 1686c2afad6cSKamil Konieczny CRYPTO_ALG_NEED_FALLBACK); 1687c2afad6cSKamil Konieczny if (IS_ERR(tctx->fallback)) { 1688c2afad6cSKamil Konieczny pr_err("fallback alloc fails for '%s'\n", alg_name); 1689c2afad6cSKamil Konieczny return PTR_ERR(tctx->fallback); 1690c2afad6cSKamil Konieczny } 1691c2afad6cSKamil Konieczny 1692c2afad6cSKamil Konieczny crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm), 1693c2afad6cSKamil Konieczny sizeof(struct s5p_hash_reqctx) + BUFLEN); 1694c2afad6cSKamil Konieczny 1695c2afad6cSKamil Konieczny return 0; 1696c2afad6cSKamil Konieczny } 1697c2afad6cSKamil Konieczny 1698c2afad6cSKamil Konieczny /** 1699c2afad6cSKamil Konieczny * s5p_hash_cra_init - init crypto tfm 1700c2afad6cSKamil Konieczny * @tfm: crypto transformation 1701c2afad6cSKamil Konieczny */ 1702c2afad6cSKamil Konieczny static int s5p_hash_cra_init(struct crypto_tfm *tfm) 1703c2afad6cSKamil Konieczny { 1704c2afad6cSKamil Konieczny return s5p_hash_cra_init_alg(tfm); 1705c2afad6cSKamil Konieczny } 1706c2afad6cSKamil Konieczny 1707c2afad6cSKamil Konieczny /** 1708c2afad6cSKamil Konieczny * s5p_hash_cra_exit - exit crypto tfm 1709c2afad6cSKamil Konieczny * @tfm: crypto transformation 1710c2afad6cSKamil Konieczny * 1711c2afad6cSKamil Konieczny * free allocated fallback 1712c2afad6cSKamil Konieczny */ 1713c2afad6cSKamil Konieczny static void s5p_hash_cra_exit(struct crypto_tfm *tfm) 1714c2afad6cSKamil Konieczny { 1715c2afad6cSKamil Konieczny struct s5p_hash_ctx *tctx = crypto_tfm_ctx(tfm); 1716c2afad6cSKamil Konieczny 1717c2afad6cSKamil Konieczny crypto_free_shash(tctx->fallback); 1718c2afad6cSKamil Konieczny tctx->fallback = NULL; 1719c2afad6cSKamil Konieczny } 1720c2afad6cSKamil Konieczny 1721c2afad6cSKamil Konieczny /** 1722c2afad6cSKamil Konieczny * s5p_hash_export - export hash state 1723c2afad6cSKamil Konieczny * @req: AHASH request 1724c2afad6cSKamil Konieczny * @out: buffer for exported state 1725c2afad6cSKamil Konieczny */ 1726c2afad6cSKamil Konieczny static int s5p_hash_export(struct ahash_request *req, void *out) 1727c2afad6cSKamil Konieczny { 17286584eacbSKrzysztof Kozlowski const struct s5p_hash_reqctx *ctx = ahash_request_ctx(req); 1729c2afad6cSKamil Konieczny 1730c2afad6cSKamil Konieczny memcpy(out, ctx, sizeof(*ctx) + ctx->bufcnt); 1731c2afad6cSKamil Konieczny 1732c2afad6cSKamil Konieczny return 0; 1733c2afad6cSKamil Konieczny } 1734c2afad6cSKamil Konieczny 1735c2afad6cSKamil Konieczny /** 1736c2afad6cSKamil Konieczny * s5p_hash_import - import hash state 1737c2afad6cSKamil Konieczny * @req: AHASH request 1738c2afad6cSKamil Konieczny * @in: buffer with state to be imported from 1739c2afad6cSKamil Konieczny */ 1740c2afad6cSKamil Konieczny static int s5p_hash_import(struct ahash_request *req, const void *in) 1741c2afad6cSKamil Konieczny { 1742c2afad6cSKamil Konieczny struct s5p_hash_reqctx *ctx = ahash_request_ctx(req); 1743c2afad6cSKamil Konieczny struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); 1744c2afad6cSKamil Konieczny struct s5p_hash_ctx *tctx = crypto_ahash_ctx(tfm); 1745c2afad6cSKamil Konieczny const struct s5p_hash_reqctx *ctx_in = in; 1746c2afad6cSKamil Konieczny 1747c2afad6cSKamil Konieczny memcpy(ctx, in, sizeof(*ctx) + BUFLEN); 1748c2afad6cSKamil Konieczny if (ctx_in->bufcnt > BUFLEN) { 1749c2afad6cSKamil Konieczny ctx->error = true; 1750c2afad6cSKamil Konieczny return -EINVAL; 1751c2afad6cSKamil Konieczny } 1752c2afad6cSKamil Konieczny 1753c2afad6cSKamil Konieczny ctx->dd = tctx->dd; 1754c2afad6cSKamil Konieczny ctx->error = false; 1755c2afad6cSKamil Konieczny 1756c2afad6cSKamil Konieczny return 0; 1757c2afad6cSKamil Konieczny } 1758c2afad6cSKamil Konieczny 1759c2afad6cSKamil Konieczny static struct ahash_alg algs_sha1_md5_sha256[] = { 1760c2afad6cSKamil Konieczny { 1761c2afad6cSKamil Konieczny .init = s5p_hash_init, 1762c2afad6cSKamil Konieczny .update = s5p_hash_update, 1763c2afad6cSKamil Konieczny .final = s5p_hash_final, 1764c2afad6cSKamil Konieczny .finup = s5p_hash_finup, 1765c2afad6cSKamil Konieczny .digest = s5p_hash_digest, 1766c2afad6cSKamil Konieczny .export = s5p_hash_export, 1767c2afad6cSKamil Konieczny .import = s5p_hash_import, 1768c2afad6cSKamil Konieczny .halg.statesize = sizeof(struct s5p_hash_reqctx) + BUFLEN, 1769c2afad6cSKamil Konieczny .halg.digestsize = SHA1_DIGEST_SIZE, 1770c2afad6cSKamil Konieczny .halg.base = { 1771c2afad6cSKamil Konieczny .cra_name = "sha1", 1772c2afad6cSKamil Konieczny .cra_driver_name = "exynos-sha1", 1773c2afad6cSKamil Konieczny .cra_priority = 100, 17746a38f622SEric Biggers .cra_flags = CRYPTO_ALG_KERN_DRIVER_ONLY | 1775c2afad6cSKamil Konieczny CRYPTO_ALG_ASYNC | 1776c2afad6cSKamil Konieczny CRYPTO_ALG_NEED_FALLBACK, 1777c2afad6cSKamil Konieczny .cra_blocksize = HASH_BLOCK_SIZE, 1778c2afad6cSKamil Konieczny .cra_ctxsize = sizeof(struct s5p_hash_ctx), 1779c2afad6cSKamil Konieczny .cra_alignmask = SSS_HASH_DMA_ALIGN_MASK, 1780c2afad6cSKamil Konieczny .cra_module = THIS_MODULE, 1781c2afad6cSKamil Konieczny .cra_init = s5p_hash_cra_init, 1782c2afad6cSKamil Konieczny .cra_exit = s5p_hash_cra_exit, 1783c2afad6cSKamil Konieczny } 1784c2afad6cSKamil Konieczny }, 1785c2afad6cSKamil Konieczny { 1786c2afad6cSKamil Konieczny .init = s5p_hash_init, 1787c2afad6cSKamil Konieczny .update = s5p_hash_update, 1788c2afad6cSKamil Konieczny .final = s5p_hash_final, 1789c2afad6cSKamil Konieczny .finup = s5p_hash_finup, 1790c2afad6cSKamil Konieczny .digest = s5p_hash_digest, 1791c2afad6cSKamil Konieczny .export = s5p_hash_export, 1792c2afad6cSKamil Konieczny .import = s5p_hash_import, 1793c2afad6cSKamil Konieczny .halg.statesize = sizeof(struct s5p_hash_reqctx) + BUFLEN, 1794c2afad6cSKamil Konieczny .halg.digestsize = MD5_DIGEST_SIZE, 1795c2afad6cSKamil Konieczny .halg.base = { 1796c2afad6cSKamil Konieczny .cra_name = "md5", 1797c2afad6cSKamil Konieczny .cra_driver_name = "exynos-md5", 1798c2afad6cSKamil Konieczny .cra_priority = 100, 17996a38f622SEric Biggers .cra_flags = CRYPTO_ALG_KERN_DRIVER_ONLY | 1800c2afad6cSKamil Konieczny CRYPTO_ALG_ASYNC | 1801c2afad6cSKamil Konieczny CRYPTO_ALG_NEED_FALLBACK, 1802c2afad6cSKamil Konieczny .cra_blocksize = HASH_BLOCK_SIZE, 1803c2afad6cSKamil Konieczny .cra_ctxsize = sizeof(struct s5p_hash_ctx), 1804c2afad6cSKamil Konieczny .cra_alignmask = SSS_HASH_DMA_ALIGN_MASK, 1805c2afad6cSKamil Konieczny .cra_module = THIS_MODULE, 1806c2afad6cSKamil Konieczny .cra_init = s5p_hash_cra_init, 1807c2afad6cSKamil Konieczny .cra_exit = s5p_hash_cra_exit, 1808c2afad6cSKamil Konieczny } 1809c2afad6cSKamil Konieczny }, 1810c2afad6cSKamil Konieczny { 1811c2afad6cSKamil Konieczny .init = s5p_hash_init, 1812c2afad6cSKamil Konieczny .update = s5p_hash_update, 1813c2afad6cSKamil Konieczny .final = s5p_hash_final, 1814c2afad6cSKamil Konieczny .finup = s5p_hash_finup, 1815c2afad6cSKamil Konieczny .digest = s5p_hash_digest, 1816c2afad6cSKamil Konieczny .export = s5p_hash_export, 1817c2afad6cSKamil Konieczny .import = s5p_hash_import, 1818c2afad6cSKamil Konieczny .halg.statesize = sizeof(struct s5p_hash_reqctx) + BUFLEN, 1819c2afad6cSKamil Konieczny .halg.digestsize = SHA256_DIGEST_SIZE, 1820c2afad6cSKamil Konieczny .halg.base = { 1821c2afad6cSKamil Konieczny .cra_name = "sha256", 1822c2afad6cSKamil Konieczny .cra_driver_name = "exynos-sha256", 1823c2afad6cSKamil Konieczny .cra_priority = 100, 18246a38f622SEric Biggers .cra_flags = CRYPTO_ALG_KERN_DRIVER_ONLY | 1825c2afad6cSKamil Konieczny CRYPTO_ALG_ASYNC | 1826c2afad6cSKamil Konieczny CRYPTO_ALG_NEED_FALLBACK, 1827c2afad6cSKamil Konieczny .cra_blocksize = HASH_BLOCK_SIZE, 1828c2afad6cSKamil Konieczny .cra_ctxsize = sizeof(struct s5p_hash_ctx), 1829c2afad6cSKamil Konieczny .cra_alignmask = SSS_HASH_DMA_ALIGN_MASK, 1830c2afad6cSKamil Konieczny .cra_module = THIS_MODULE, 1831c2afad6cSKamil Konieczny .cra_init = s5p_hash_cra_init, 1832c2afad6cSKamil Konieczny .cra_exit = s5p_hash_cra_exit, 1833c2afad6cSKamil Konieczny } 1834c2afad6cSKamil Konieczny } 1835c2afad6cSKamil Konieczny 1836c2afad6cSKamil Konieczny }; 1837c2afad6cSKamil Konieczny 1838a49e490cSVladimir Zapolskiy static void s5p_set_aes(struct s5p_aes_dev *dev, 1839cdf640a6SChristoph Manszewski const u8 *key, const u8 *iv, const u8 *ctr, 18406584eacbSKrzysztof Kozlowski unsigned int keylen) 1841a49e490cSVladimir Zapolskiy { 1842a49e490cSVladimir Zapolskiy void __iomem *keystart; 1843a49e490cSVladimir Zapolskiy 18448f9702aaSNaveen Krishna Chatradhi if (iv) 1845ef5c73b3SKrzysztof Kozlowski memcpy_toio(dev->aes_ioaddr + SSS_REG_AES_IV_DATA(0), iv, 1846ef5c73b3SKrzysztof Kozlowski AES_BLOCK_SIZE); 1847a49e490cSVladimir Zapolskiy 1848cdf640a6SChristoph Manszewski if (ctr) 1849ef5c73b3SKrzysztof Kozlowski memcpy_toio(dev->aes_ioaddr + SSS_REG_AES_CNT_DATA(0), ctr, 1850ef5c73b3SKrzysztof Kozlowski AES_BLOCK_SIZE); 1851cdf640a6SChristoph Manszewski 1852a49e490cSVladimir Zapolskiy if (keylen == AES_KEYSIZE_256) 185389245107SNaveen Krishna Chatradhi keystart = dev->aes_ioaddr + SSS_REG_AES_KEY_DATA(0); 1854a49e490cSVladimir Zapolskiy else if (keylen == AES_KEYSIZE_192) 185589245107SNaveen Krishna Chatradhi keystart = dev->aes_ioaddr + SSS_REG_AES_KEY_DATA(2); 1856a49e490cSVladimir Zapolskiy else 185789245107SNaveen Krishna Chatradhi keystart = dev->aes_ioaddr + SSS_REG_AES_KEY_DATA(4); 1858a49e490cSVladimir Zapolskiy 18591e3012d0SKrzysztof Koz?owski memcpy_toio(keystart, key, keylen); 1860a49e490cSVladimir Zapolskiy } 1861a49e490cSVladimir Zapolskiy 18629e4a1100SKrzysztof Kozlowski static bool s5p_is_sg_aligned(struct scatterlist *sg) 18639e4a1100SKrzysztof Kozlowski { 18649e4a1100SKrzysztof Kozlowski while (sg) { 1865d1497977SMarek Szyprowski if (!IS_ALIGNED(sg->length, AES_BLOCK_SIZE)) 18669e4a1100SKrzysztof Kozlowski return false; 18679e4a1100SKrzysztof Kozlowski sg = sg_next(sg); 18689e4a1100SKrzysztof Kozlowski } 18699e4a1100SKrzysztof Kozlowski 18709e4a1100SKrzysztof Kozlowski return true; 18719e4a1100SKrzysztof Kozlowski } 18729e4a1100SKrzysztof Kozlowski 18739e4a1100SKrzysztof Kozlowski static int s5p_set_indata_start(struct s5p_aes_dev *dev, 18749e4a1100SKrzysztof Kozlowski struct ablkcipher_request *req) 18759e4a1100SKrzysztof Kozlowski { 18769e4a1100SKrzysztof Kozlowski struct scatterlist *sg; 18779e4a1100SKrzysztof Kozlowski int err; 18789e4a1100SKrzysztof Kozlowski 18799e4a1100SKrzysztof Kozlowski dev->sg_src_cpy = NULL; 18809e4a1100SKrzysztof Kozlowski sg = req->src; 18819e4a1100SKrzysztof Kozlowski if (!s5p_is_sg_aligned(sg)) { 18829e4a1100SKrzysztof Kozlowski dev_dbg(dev->dev, 18839e4a1100SKrzysztof Kozlowski "At least one unaligned source scatter list, making a copy\n"); 18849e4a1100SKrzysztof Kozlowski err = s5p_make_sg_cpy(dev, sg, &dev->sg_src_cpy); 18859e4a1100SKrzysztof Kozlowski if (err) 18869e4a1100SKrzysztof Kozlowski return err; 18879e4a1100SKrzysztof Kozlowski 18889e4a1100SKrzysztof Kozlowski sg = dev->sg_src_cpy; 18899e4a1100SKrzysztof Kozlowski } 18909e4a1100SKrzysztof Kozlowski 18919e4a1100SKrzysztof Kozlowski err = s5p_set_indata(dev, sg); 18929e4a1100SKrzysztof Kozlowski if (err) { 18939e4a1100SKrzysztof Kozlowski s5p_free_sg_cpy(dev, &dev->sg_src_cpy); 18949e4a1100SKrzysztof Kozlowski return err; 18959e4a1100SKrzysztof Kozlowski } 18969e4a1100SKrzysztof Kozlowski 18979e4a1100SKrzysztof Kozlowski return 0; 18989e4a1100SKrzysztof Kozlowski } 18999e4a1100SKrzysztof Kozlowski 19009e4a1100SKrzysztof Kozlowski static int s5p_set_outdata_start(struct s5p_aes_dev *dev, 19019e4a1100SKrzysztof Kozlowski struct ablkcipher_request *req) 19029e4a1100SKrzysztof Kozlowski { 19039e4a1100SKrzysztof Kozlowski struct scatterlist *sg; 19049e4a1100SKrzysztof Kozlowski int err; 19059e4a1100SKrzysztof Kozlowski 19069e4a1100SKrzysztof Kozlowski dev->sg_dst_cpy = NULL; 19079e4a1100SKrzysztof Kozlowski sg = req->dst; 19089e4a1100SKrzysztof Kozlowski if (!s5p_is_sg_aligned(sg)) { 19099e4a1100SKrzysztof Kozlowski dev_dbg(dev->dev, 19109e4a1100SKrzysztof Kozlowski "At least one unaligned dest scatter list, making a copy\n"); 19119e4a1100SKrzysztof Kozlowski err = s5p_make_sg_cpy(dev, sg, &dev->sg_dst_cpy); 19129e4a1100SKrzysztof Kozlowski if (err) 19139e4a1100SKrzysztof Kozlowski return err; 19149e4a1100SKrzysztof Kozlowski 19159e4a1100SKrzysztof Kozlowski sg = dev->sg_dst_cpy; 19169e4a1100SKrzysztof Kozlowski } 19179e4a1100SKrzysztof Kozlowski 19189e4a1100SKrzysztof Kozlowski err = s5p_set_outdata(dev, sg); 19199e4a1100SKrzysztof Kozlowski if (err) { 19209e4a1100SKrzysztof Kozlowski s5p_free_sg_cpy(dev, &dev->sg_dst_cpy); 19219e4a1100SKrzysztof Kozlowski return err; 19229e4a1100SKrzysztof Kozlowski } 19239e4a1100SKrzysztof Kozlowski 19249e4a1100SKrzysztof Kozlowski return 0; 19259e4a1100SKrzysztof Kozlowski } 19269e4a1100SKrzysztof Kozlowski 1927a49e490cSVladimir Zapolskiy static void s5p_aes_crypt_start(struct s5p_aes_dev *dev, unsigned long mode) 1928a49e490cSVladimir Zapolskiy { 1929a49e490cSVladimir Zapolskiy struct ablkcipher_request *req = dev->req; 1930b1b4416fSChristoph Manszewski u32 aes_control; 1931a49e490cSVladimir Zapolskiy unsigned long flags; 19325318c53dSKrzysztof Kozlowski int err; 1933cdf640a6SChristoph Manszewski u8 *iv, *ctr; 1934a49e490cSVladimir Zapolskiy 1935cdf640a6SChristoph Manszewski /* This sets bit [13:12] to 00, which selects 128-bit counter */ 1936a49e490cSVladimir Zapolskiy aes_control = SSS_AES_KEY_CHANGE_MODE; 1937a49e490cSVladimir Zapolskiy if (mode & FLAGS_AES_DECRYPT) 1938a49e490cSVladimir Zapolskiy aes_control |= SSS_AES_MODE_DECRYPT; 1939a49e490cSVladimir Zapolskiy 1940c927b080SKamil Konieczny if ((mode & FLAGS_AES_MODE_MASK) == FLAGS_AES_CBC) { 1941a49e490cSVladimir Zapolskiy aes_control |= SSS_AES_CHAIN_MODE_CBC; 1942c927b080SKamil Konieczny iv = req->info; 1943cdf640a6SChristoph Manszewski ctr = NULL; 1944c927b080SKamil Konieczny } else if ((mode & FLAGS_AES_MODE_MASK) == FLAGS_AES_CTR) { 1945a49e490cSVladimir Zapolskiy aes_control |= SSS_AES_CHAIN_MODE_CTR; 1946cdf640a6SChristoph Manszewski iv = NULL; 1947cdf640a6SChristoph Manszewski ctr = req->info; 1948c927b080SKamil Konieczny } else { 1949c927b080SKamil Konieczny iv = NULL; /* AES_ECB */ 1950cdf640a6SChristoph Manszewski ctr = NULL; 1951c927b080SKamil Konieczny } 1952a49e490cSVladimir Zapolskiy 1953a49e490cSVladimir Zapolskiy if (dev->ctx->keylen == AES_KEYSIZE_192) 1954a49e490cSVladimir Zapolskiy aes_control |= SSS_AES_KEY_SIZE_192; 1955a49e490cSVladimir Zapolskiy else if (dev->ctx->keylen == AES_KEYSIZE_256) 1956a49e490cSVladimir Zapolskiy aes_control |= SSS_AES_KEY_SIZE_256; 1957a49e490cSVladimir Zapolskiy 1958a49e490cSVladimir Zapolskiy aes_control |= SSS_AES_FIFO_MODE; 1959a49e490cSVladimir Zapolskiy 1960a49e490cSVladimir Zapolskiy /* as a variant it is possible to use byte swapping on DMA side */ 1961a49e490cSVladimir Zapolskiy aes_control |= SSS_AES_BYTESWAP_DI 1962a49e490cSVladimir Zapolskiy | SSS_AES_BYTESWAP_DO 1963a49e490cSVladimir Zapolskiy | SSS_AES_BYTESWAP_IV 1964a49e490cSVladimir Zapolskiy | SSS_AES_BYTESWAP_KEY 1965a49e490cSVladimir Zapolskiy | SSS_AES_BYTESWAP_CNT; 1966a49e490cSVladimir Zapolskiy 1967a49e490cSVladimir Zapolskiy spin_lock_irqsave(&dev->lock, flags); 1968a49e490cSVladimir Zapolskiy 1969a49e490cSVladimir Zapolskiy SSS_WRITE(dev, FCINTENCLR, 1970a49e490cSVladimir Zapolskiy SSS_FCINTENCLR_BTDMAINTENCLR | SSS_FCINTENCLR_BRDMAINTENCLR); 1971a49e490cSVladimir Zapolskiy SSS_WRITE(dev, FCFIFOCTRL, 0x00); 1972a49e490cSVladimir Zapolskiy 19739e4a1100SKrzysztof Kozlowski err = s5p_set_indata_start(dev, req); 1974a49e490cSVladimir Zapolskiy if (err) 1975a49e490cSVladimir Zapolskiy goto indata_error; 1976a49e490cSVladimir Zapolskiy 19779e4a1100SKrzysztof Kozlowski err = s5p_set_outdata_start(dev, req); 1978a49e490cSVladimir Zapolskiy if (err) 1979a49e490cSVladimir Zapolskiy goto outdata_error; 1980a49e490cSVladimir Zapolskiy 198189245107SNaveen Krishna Chatradhi SSS_AES_WRITE(dev, AES_CONTROL, aes_control); 1982cdf640a6SChristoph Manszewski s5p_set_aes(dev, dev->ctx->aes_key, iv, ctr, dev->ctx->keylen); 1983a49e490cSVladimir Zapolskiy 19849e4a1100SKrzysztof Kozlowski s5p_set_dma_indata(dev, dev->sg_src); 19859e4a1100SKrzysztof Kozlowski s5p_set_dma_outdata(dev, dev->sg_dst); 1986a49e490cSVladimir Zapolskiy 1987a49e490cSVladimir Zapolskiy SSS_WRITE(dev, FCINTENSET, 1988a49e490cSVladimir Zapolskiy SSS_FCINTENSET_BTDMAINTENSET | SSS_FCINTENSET_BRDMAINTENSET); 1989a49e490cSVladimir Zapolskiy 1990a49e490cSVladimir Zapolskiy spin_unlock_irqrestore(&dev->lock, flags); 1991a49e490cSVladimir Zapolskiy 1992a49e490cSVladimir Zapolskiy return; 1993a49e490cSVladimir Zapolskiy 1994a49e490cSVladimir Zapolskiy outdata_error: 1995a49e490cSVladimir Zapolskiy s5p_unset_indata(dev); 1996a49e490cSVladimir Zapolskiy 1997a49e490cSVladimir Zapolskiy indata_error: 199828b62b14SKrzysztof Kozlowski s5p_sg_done(dev); 199942d5c176SKrzysztof Kozlowski dev->busy = false; 2000a49e490cSVladimir Zapolskiy spin_unlock_irqrestore(&dev->lock, flags); 20015842cd44SChristoph Manszewski s5p_aes_complete(req, err); 2002a49e490cSVladimir Zapolskiy } 2003a49e490cSVladimir Zapolskiy 2004a49e490cSVladimir Zapolskiy static void s5p_tasklet_cb(unsigned long data) 2005a49e490cSVladimir Zapolskiy { 2006a49e490cSVladimir Zapolskiy struct s5p_aes_dev *dev = (struct s5p_aes_dev *)data; 2007a49e490cSVladimir Zapolskiy struct crypto_async_request *async_req, *backlog; 2008a49e490cSVladimir Zapolskiy struct s5p_aes_reqctx *reqctx; 2009a49e490cSVladimir Zapolskiy unsigned long flags; 2010a49e490cSVladimir Zapolskiy 2011a49e490cSVladimir Zapolskiy spin_lock_irqsave(&dev->lock, flags); 2012a49e490cSVladimir Zapolskiy backlog = crypto_get_backlog(&dev->queue); 2013a49e490cSVladimir Zapolskiy async_req = crypto_dequeue_request(&dev->queue); 2014a49e490cSVladimir Zapolskiy 2015dc5e3f19SNaveen Krishna Chatradhi if (!async_req) { 2016dc5e3f19SNaveen Krishna Chatradhi dev->busy = false; 2017dc5e3f19SNaveen Krishna Chatradhi spin_unlock_irqrestore(&dev->lock, flags); 2018a49e490cSVladimir Zapolskiy return; 2019dc5e3f19SNaveen Krishna Chatradhi } 2020dc5e3f19SNaveen Krishna Chatradhi spin_unlock_irqrestore(&dev->lock, flags); 2021a49e490cSVladimir Zapolskiy 2022a49e490cSVladimir Zapolskiy if (backlog) 2023a49e490cSVladimir Zapolskiy backlog->complete(backlog, -EINPROGRESS); 2024a49e490cSVladimir Zapolskiy 2025a49e490cSVladimir Zapolskiy dev->req = ablkcipher_request_cast(async_req); 2026a49e490cSVladimir Zapolskiy dev->ctx = crypto_tfm_ctx(dev->req->base.tfm); 2027a49e490cSVladimir Zapolskiy reqctx = ablkcipher_request_ctx(dev->req); 2028a49e490cSVladimir Zapolskiy 2029a49e490cSVladimir Zapolskiy s5p_aes_crypt_start(dev, reqctx->mode); 2030a49e490cSVladimir Zapolskiy } 2031a49e490cSVladimir Zapolskiy 2032a49e490cSVladimir Zapolskiy static int s5p_aes_handle_req(struct s5p_aes_dev *dev, 2033a49e490cSVladimir Zapolskiy struct ablkcipher_request *req) 2034a49e490cSVladimir Zapolskiy { 2035a49e490cSVladimir Zapolskiy unsigned long flags; 2036a49e490cSVladimir Zapolskiy int err; 2037a49e490cSVladimir Zapolskiy 2038a49e490cSVladimir Zapolskiy spin_lock_irqsave(&dev->lock, flags); 2039dc5e3f19SNaveen Krishna Chatradhi err = ablkcipher_enqueue_request(&dev->queue, req); 2040a49e490cSVladimir Zapolskiy if (dev->busy) { 2041a49e490cSVladimir Zapolskiy spin_unlock_irqrestore(&dev->lock, flags); 2042b1b4416fSChristoph Manszewski return err; 2043a49e490cSVladimir Zapolskiy } 2044a49e490cSVladimir Zapolskiy dev->busy = true; 2045a49e490cSVladimir Zapolskiy 2046a49e490cSVladimir Zapolskiy spin_unlock_irqrestore(&dev->lock, flags); 2047a49e490cSVladimir Zapolskiy 2048a49e490cSVladimir Zapolskiy tasklet_schedule(&dev->tasklet); 2049a49e490cSVladimir Zapolskiy 2050a49e490cSVladimir Zapolskiy return err; 2051a49e490cSVladimir Zapolskiy } 2052a49e490cSVladimir Zapolskiy 2053a49e490cSVladimir Zapolskiy static int s5p_aes_crypt(struct ablkcipher_request *req, unsigned long mode) 2054a49e490cSVladimir Zapolskiy { 2055a49e490cSVladimir Zapolskiy struct crypto_ablkcipher *tfm = crypto_ablkcipher_reqtfm(req); 2056a49e490cSVladimir Zapolskiy struct s5p_aes_reqctx *reqctx = ablkcipher_request_ctx(req); 20575318c53dSKrzysztof Kozlowski struct s5p_aes_ctx *ctx = crypto_ablkcipher_ctx(tfm); 2058a49e490cSVladimir Zapolskiy struct s5p_aes_dev *dev = ctx->dev; 2059a49e490cSVladimir Zapolskiy 2060cdf640a6SChristoph Manszewski if (!IS_ALIGNED(req->nbytes, AES_BLOCK_SIZE) && 2061cdf640a6SChristoph Manszewski ((mode & FLAGS_AES_MODE_MASK) != FLAGS_AES_CTR)) { 2062313becd1SKrzysztof Koz?owski dev_err(dev->dev, "request size is not exact amount of AES blocks\n"); 2063a49e490cSVladimir Zapolskiy return -EINVAL; 2064a49e490cSVladimir Zapolskiy } 2065a49e490cSVladimir Zapolskiy 2066a49e490cSVladimir Zapolskiy reqctx->mode = mode; 2067a49e490cSVladimir Zapolskiy 2068a49e490cSVladimir Zapolskiy return s5p_aes_handle_req(dev, req); 2069a49e490cSVladimir Zapolskiy } 2070a49e490cSVladimir Zapolskiy 2071a49e490cSVladimir Zapolskiy static int s5p_aes_setkey(struct crypto_ablkcipher *cipher, 2072b1b4416fSChristoph Manszewski const u8 *key, unsigned int keylen) 2073a49e490cSVladimir Zapolskiy { 2074a49e490cSVladimir Zapolskiy struct crypto_tfm *tfm = crypto_ablkcipher_tfm(cipher); 2075a49e490cSVladimir Zapolskiy struct s5p_aes_ctx *ctx = crypto_tfm_ctx(tfm); 2076a49e490cSVladimir Zapolskiy 2077a49e490cSVladimir Zapolskiy if (keylen != AES_KEYSIZE_128 && 2078a49e490cSVladimir Zapolskiy keylen != AES_KEYSIZE_192 && 2079a49e490cSVladimir Zapolskiy keylen != AES_KEYSIZE_256) 2080a49e490cSVladimir Zapolskiy return -EINVAL; 2081a49e490cSVladimir Zapolskiy 2082a49e490cSVladimir Zapolskiy memcpy(ctx->aes_key, key, keylen); 2083a49e490cSVladimir Zapolskiy ctx->keylen = keylen; 2084a49e490cSVladimir Zapolskiy 2085a49e490cSVladimir Zapolskiy return 0; 2086a49e490cSVladimir Zapolskiy } 2087a49e490cSVladimir Zapolskiy 2088a49e490cSVladimir Zapolskiy static int s5p_aes_ecb_encrypt(struct ablkcipher_request *req) 2089a49e490cSVladimir Zapolskiy { 2090a49e490cSVladimir Zapolskiy return s5p_aes_crypt(req, 0); 2091a49e490cSVladimir Zapolskiy } 2092a49e490cSVladimir Zapolskiy 2093a49e490cSVladimir Zapolskiy static int s5p_aes_ecb_decrypt(struct ablkcipher_request *req) 2094a49e490cSVladimir Zapolskiy { 2095a49e490cSVladimir Zapolskiy return s5p_aes_crypt(req, FLAGS_AES_DECRYPT); 2096a49e490cSVladimir Zapolskiy } 2097a49e490cSVladimir Zapolskiy 2098a49e490cSVladimir Zapolskiy static int s5p_aes_cbc_encrypt(struct ablkcipher_request *req) 2099a49e490cSVladimir Zapolskiy { 2100a49e490cSVladimir Zapolskiy return s5p_aes_crypt(req, FLAGS_AES_CBC); 2101a49e490cSVladimir Zapolskiy } 2102a49e490cSVladimir Zapolskiy 2103a49e490cSVladimir Zapolskiy static int s5p_aes_cbc_decrypt(struct ablkcipher_request *req) 2104a49e490cSVladimir Zapolskiy { 2105a49e490cSVladimir Zapolskiy return s5p_aes_crypt(req, FLAGS_AES_DECRYPT | FLAGS_AES_CBC); 2106a49e490cSVladimir Zapolskiy } 2107a49e490cSVladimir Zapolskiy 2108cdf640a6SChristoph Manszewski static int s5p_aes_ctr_crypt(struct ablkcipher_request *req) 2109cdf640a6SChristoph Manszewski { 2110cdf640a6SChristoph Manszewski return s5p_aes_crypt(req, FLAGS_AES_CTR); 2111cdf640a6SChristoph Manszewski } 2112cdf640a6SChristoph Manszewski 2113a49e490cSVladimir Zapolskiy static int s5p_aes_cra_init(struct crypto_tfm *tfm) 2114a49e490cSVladimir Zapolskiy { 2115a49e490cSVladimir Zapolskiy struct s5p_aes_ctx *ctx = crypto_tfm_ctx(tfm); 2116a49e490cSVladimir Zapolskiy 2117a49e490cSVladimir Zapolskiy ctx->dev = s5p_dev; 2118a49e490cSVladimir Zapolskiy tfm->crt_ablkcipher.reqsize = sizeof(struct s5p_aes_reqctx); 2119a49e490cSVladimir Zapolskiy 2120a49e490cSVladimir Zapolskiy return 0; 2121a49e490cSVladimir Zapolskiy } 2122a49e490cSVladimir Zapolskiy 2123a49e490cSVladimir Zapolskiy static struct crypto_alg algs[] = { 2124a49e490cSVladimir Zapolskiy { 2125a49e490cSVladimir Zapolskiy .cra_name = "ecb(aes)", 2126a49e490cSVladimir Zapolskiy .cra_driver_name = "ecb-aes-s5p", 2127a49e490cSVladimir Zapolskiy .cra_priority = 100, 2128a49e490cSVladimir Zapolskiy .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | 2129d912bb76SNikos Mavrogiannopoulos CRYPTO_ALG_ASYNC | 2130d912bb76SNikos Mavrogiannopoulos CRYPTO_ALG_KERN_DRIVER_ONLY, 2131a49e490cSVladimir Zapolskiy .cra_blocksize = AES_BLOCK_SIZE, 2132a49e490cSVladimir Zapolskiy .cra_ctxsize = sizeof(struct s5p_aes_ctx), 2133a49e490cSVladimir Zapolskiy .cra_alignmask = 0x0f, 2134a49e490cSVladimir Zapolskiy .cra_type = &crypto_ablkcipher_type, 2135a49e490cSVladimir Zapolskiy .cra_module = THIS_MODULE, 2136a49e490cSVladimir Zapolskiy .cra_init = s5p_aes_cra_init, 2137a49e490cSVladimir Zapolskiy .cra_u.ablkcipher = { 2138a49e490cSVladimir Zapolskiy .min_keysize = AES_MIN_KEY_SIZE, 2139a49e490cSVladimir Zapolskiy .max_keysize = AES_MAX_KEY_SIZE, 2140a49e490cSVladimir Zapolskiy .setkey = s5p_aes_setkey, 2141a49e490cSVladimir Zapolskiy .encrypt = s5p_aes_ecb_encrypt, 2142a49e490cSVladimir Zapolskiy .decrypt = s5p_aes_ecb_decrypt, 2143a49e490cSVladimir Zapolskiy } 2144a49e490cSVladimir Zapolskiy }, 2145a49e490cSVladimir Zapolskiy { 2146a49e490cSVladimir Zapolskiy .cra_name = "cbc(aes)", 2147a49e490cSVladimir Zapolskiy .cra_driver_name = "cbc-aes-s5p", 2148a49e490cSVladimir Zapolskiy .cra_priority = 100, 2149a49e490cSVladimir Zapolskiy .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | 2150d912bb76SNikos Mavrogiannopoulos CRYPTO_ALG_ASYNC | 2151d912bb76SNikos Mavrogiannopoulos CRYPTO_ALG_KERN_DRIVER_ONLY, 2152a49e490cSVladimir Zapolskiy .cra_blocksize = AES_BLOCK_SIZE, 2153a49e490cSVladimir Zapolskiy .cra_ctxsize = sizeof(struct s5p_aes_ctx), 2154a49e490cSVladimir Zapolskiy .cra_alignmask = 0x0f, 2155a49e490cSVladimir Zapolskiy .cra_type = &crypto_ablkcipher_type, 2156a49e490cSVladimir Zapolskiy .cra_module = THIS_MODULE, 2157a49e490cSVladimir Zapolskiy .cra_init = s5p_aes_cra_init, 2158a49e490cSVladimir Zapolskiy .cra_u.ablkcipher = { 2159a49e490cSVladimir Zapolskiy .min_keysize = AES_MIN_KEY_SIZE, 2160a49e490cSVladimir Zapolskiy .max_keysize = AES_MAX_KEY_SIZE, 2161a49e490cSVladimir Zapolskiy .ivsize = AES_BLOCK_SIZE, 2162a49e490cSVladimir Zapolskiy .setkey = s5p_aes_setkey, 2163a49e490cSVladimir Zapolskiy .encrypt = s5p_aes_cbc_encrypt, 2164a49e490cSVladimir Zapolskiy .decrypt = s5p_aes_cbc_decrypt, 2165a49e490cSVladimir Zapolskiy } 2166a49e490cSVladimir Zapolskiy }, 2167cdf640a6SChristoph Manszewski { 2168cdf640a6SChristoph Manszewski .cra_name = "ctr(aes)", 2169cdf640a6SChristoph Manszewski .cra_driver_name = "ctr-aes-s5p", 2170cdf640a6SChristoph Manszewski .cra_priority = 100, 2171cdf640a6SChristoph Manszewski .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | 2172cdf640a6SChristoph Manszewski CRYPTO_ALG_ASYNC | 2173cdf640a6SChristoph Manszewski CRYPTO_ALG_KERN_DRIVER_ONLY, 2174cdf640a6SChristoph Manszewski .cra_blocksize = AES_BLOCK_SIZE, 2175cdf640a6SChristoph Manszewski .cra_ctxsize = sizeof(struct s5p_aes_ctx), 2176cdf640a6SChristoph Manszewski .cra_alignmask = 0x0f, 2177cdf640a6SChristoph Manszewski .cra_type = &crypto_ablkcipher_type, 2178cdf640a6SChristoph Manszewski .cra_module = THIS_MODULE, 2179cdf640a6SChristoph Manszewski .cra_init = s5p_aes_cra_init, 2180cdf640a6SChristoph Manszewski .cra_u.ablkcipher = { 2181cdf640a6SChristoph Manszewski .min_keysize = AES_MIN_KEY_SIZE, 2182cdf640a6SChristoph Manszewski .max_keysize = AES_MAX_KEY_SIZE, 2183cdf640a6SChristoph Manszewski .ivsize = AES_BLOCK_SIZE, 2184cdf640a6SChristoph Manszewski .setkey = s5p_aes_setkey, 2185cdf640a6SChristoph Manszewski .encrypt = s5p_aes_ctr_crypt, 2186cdf640a6SChristoph Manszewski .decrypt = s5p_aes_ctr_crypt, 2187cdf640a6SChristoph Manszewski } 2188cdf640a6SChristoph Manszewski }, 2189a49e490cSVladimir Zapolskiy }; 2190a49e490cSVladimir Zapolskiy 2191a49e490cSVladimir Zapolskiy static int s5p_aes_probe(struct platform_device *pdev) 2192a49e490cSVladimir Zapolskiy { 2193a49e490cSVladimir Zapolskiy struct device *dev = &pdev->dev; 21945318c53dSKrzysztof Kozlowski int i, j, err = -ENODEV; 21956584eacbSKrzysztof Kozlowski const struct samsung_aes_variant *variant; 21965318c53dSKrzysztof Kozlowski struct s5p_aes_dev *pdata; 21975318c53dSKrzysztof Kozlowski struct resource *res; 2198c2afad6cSKamil Konieczny unsigned int hash_i; 2199a49e490cSVladimir Zapolskiy 2200a49e490cSVladimir Zapolskiy if (s5p_dev) 2201a49e490cSVladimir Zapolskiy return -EEXIST; 2202a49e490cSVladimir Zapolskiy 2203a49e490cSVladimir Zapolskiy pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); 2204a49e490cSVladimir Zapolskiy if (!pdata) 2205a49e490cSVladimir Zapolskiy return -ENOMEM; 2206a49e490cSVladimir Zapolskiy 2207c2afad6cSKamil Konieczny variant = find_s5p_sss_version(pdev); 22080fdefe2cSJingoo Han res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 2209c2afad6cSKamil Konieczny 2210c2afad6cSKamil Konieczny /* 2211c2afad6cSKamil Konieczny * Note: HASH and PRNG uses the same registers in secss, avoid 2212c2afad6cSKamil Konieczny * overwrite each other. This will drop HASH when CONFIG_EXYNOS_RNG 2213c2afad6cSKamil Konieczny * is enabled in config. We need larger size for HASH registers in 2214c2afad6cSKamil Konieczny * secss, current describe only AES/DES 2215c2afad6cSKamil Konieczny */ 2216c2afad6cSKamil Konieczny if (IS_ENABLED(CONFIG_CRYPTO_DEV_EXYNOS_HASH)) { 2217c2afad6cSKamil Konieczny if (variant == &exynos_aes_data) { 2218c2afad6cSKamil Konieczny res->end += 0x300; 2219c2afad6cSKamil Konieczny pdata->use_hash = true; 2220c2afad6cSKamil Konieczny } 2221c2afad6cSKamil Konieczny } 2222c2afad6cSKamil Konieczny 2223c2afad6cSKamil Konieczny pdata->res = res; 2224c2afad6cSKamil Konieczny pdata->ioaddr = devm_ioremap_resource(&pdev->dev, res); 2225c2afad6cSKamil Konieczny if (IS_ERR(pdata->ioaddr)) { 2226c2afad6cSKamil Konieczny if (!pdata->use_hash) 2227c2afad6cSKamil Konieczny return PTR_ERR(pdata->ioaddr); 2228c2afad6cSKamil Konieczny /* try AES without HASH */ 2229c2afad6cSKamil Konieczny res->end -= 0x300; 2230c2afad6cSKamil Konieczny pdata->use_hash = false; 22310fdefe2cSJingoo Han pdata->ioaddr = devm_ioremap_resource(&pdev->dev, res); 22320fdefe2cSJingoo Han if (IS_ERR(pdata->ioaddr)) 22330fdefe2cSJingoo Han return PTR_ERR(pdata->ioaddr); 2234c2afad6cSKamil Konieczny } 223589245107SNaveen Krishna Chatradhi 22360918f18cSKamil Konieczny pdata->clk = devm_clk_get(dev, variant->clk_names[0]); 2237a49e490cSVladimir Zapolskiy if (IS_ERR(pdata->clk)) { 22380918f18cSKamil Konieczny dev_err(dev, "failed to find secss clock %s\n", 22390918f18cSKamil Konieczny variant->clk_names[0]); 2240a49e490cSVladimir Zapolskiy return -ENOENT; 2241a49e490cSVladimir Zapolskiy } 2242a49e490cSVladimir Zapolskiy 2243c1eb7ef2SNaveen Krishna Chatradhi err = clk_prepare_enable(pdata->clk); 2244c1eb7ef2SNaveen Krishna Chatradhi if (err < 0) { 22450918f18cSKamil Konieczny dev_err(dev, "Enabling clock %s failed, err %d\n", 22460918f18cSKamil Konieczny variant->clk_names[0], err); 2247c1eb7ef2SNaveen Krishna Chatradhi return err; 2248c1eb7ef2SNaveen Krishna Chatradhi } 2249a49e490cSVladimir Zapolskiy 22500918f18cSKamil Konieczny if (variant->clk_names[1]) { 22510918f18cSKamil Konieczny pdata->pclk = devm_clk_get(dev, variant->clk_names[1]); 22520918f18cSKamil Konieczny if (IS_ERR(pdata->pclk)) { 22530918f18cSKamil Konieczny dev_err(dev, "failed to find clock %s\n", 22540918f18cSKamil Konieczny variant->clk_names[1]); 22550918f18cSKamil Konieczny err = -ENOENT; 22560918f18cSKamil Konieczny goto err_clk; 22570918f18cSKamil Konieczny } 22580918f18cSKamil Konieczny 22590918f18cSKamil Konieczny err = clk_prepare_enable(pdata->pclk); 22600918f18cSKamil Konieczny if (err < 0) { 22610918f18cSKamil Konieczny dev_err(dev, "Enabling clock %s failed, err %d\n", 22620918f18cSKamil Konieczny variant->clk_names[0], err); 22630918f18cSKamil Konieczny goto err_clk; 22640918f18cSKamil Konieczny } 22650918f18cSKamil Konieczny } else { 22660918f18cSKamil Konieczny pdata->pclk = NULL; 22670918f18cSKamil Konieczny } 22680918f18cSKamil Konieczny 2269a49e490cSVladimir Zapolskiy spin_lock_init(&pdata->lock); 2270c2afad6cSKamil Konieczny spin_lock_init(&pdata->hash_lock); 2271a49e490cSVladimir Zapolskiy 227289245107SNaveen Krishna Chatradhi pdata->aes_ioaddr = pdata->ioaddr + variant->aes_offset; 2273c2afad6cSKamil Konieczny pdata->io_hash_base = pdata->ioaddr + variant->hash_offset; 227489245107SNaveen Krishna Chatradhi 227596fc70b6SNaveen Krishna Chatradhi pdata->irq_fc = platform_get_irq(pdev, 0); 2276a49e490cSVladimir Zapolskiy if (pdata->irq_fc < 0) { 2277a49e490cSVladimir Zapolskiy err = pdata->irq_fc; 2278a49e490cSVladimir Zapolskiy dev_warn(dev, "feed control interrupt is not available.\n"); 2279a49e490cSVladimir Zapolskiy goto err_irq; 2280a49e490cSVladimir Zapolskiy } 228107de4bc8SKrzysztof Kozlowski err = devm_request_threaded_irq(dev, pdata->irq_fc, NULL, 228207de4bc8SKrzysztof Kozlowski s5p_aes_interrupt, IRQF_ONESHOT, 228307de4bc8SKrzysztof Kozlowski pdev->name, pdev); 2284a49e490cSVladimir Zapolskiy if (err < 0) { 2285a49e490cSVladimir Zapolskiy dev_warn(dev, "feed control interrupt is not available.\n"); 2286a49e490cSVladimir Zapolskiy goto err_irq; 2287a49e490cSVladimir Zapolskiy } 2288a49e490cSVladimir Zapolskiy 2289dc5e3f19SNaveen Krishna Chatradhi pdata->busy = false; 2290a49e490cSVladimir Zapolskiy pdata->dev = dev; 2291a49e490cSVladimir Zapolskiy platform_set_drvdata(pdev, pdata); 2292a49e490cSVladimir Zapolskiy s5p_dev = pdata; 2293a49e490cSVladimir Zapolskiy 2294a49e490cSVladimir Zapolskiy tasklet_init(&pdata->tasklet, s5p_tasklet_cb, (unsigned long)pdata); 2295a49e490cSVladimir Zapolskiy crypto_init_queue(&pdata->queue, CRYPTO_QUEUE_LEN); 2296a49e490cSVladimir Zapolskiy 2297a49e490cSVladimir Zapolskiy for (i = 0; i < ARRAY_SIZE(algs); i++) { 2298a49e490cSVladimir Zapolskiy err = crypto_register_alg(&algs[i]); 2299a49e490cSVladimir Zapolskiy if (err) 2300a49e490cSVladimir Zapolskiy goto err_algs; 2301a49e490cSVladimir Zapolskiy } 2302a49e490cSVladimir Zapolskiy 2303c2afad6cSKamil Konieczny if (pdata->use_hash) { 2304c2afad6cSKamil Konieczny tasklet_init(&pdata->hash_tasklet, s5p_hash_tasklet_cb, 2305c2afad6cSKamil Konieczny (unsigned long)pdata); 2306c2afad6cSKamil Konieczny crypto_init_queue(&pdata->hash_queue, SSS_HASH_QUEUE_LENGTH); 2307c2afad6cSKamil Konieczny 2308c2afad6cSKamil Konieczny for (hash_i = 0; hash_i < ARRAY_SIZE(algs_sha1_md5_sha256); 2309c2afad6cSKamil Konieczny hash_i++) { 2310c2afad6cSKamil Konieczny struct ahash_alg *alg; 2311c2afad6cSKamil Konieczny 2312c2afad6cSKamil Konieczny alg = &algs_sha1_md5_sha256[hash_i]; 2313c2afad6cSKamil Konieczny err = crypto_register_ahash(alg); 2314c2afad6cSKamil Konieczny if (err) { 2315c2afad6cSKamil Konieczny dev_err(dev, "can't register '%s': %d\n", 2316c2afad6cSKamil Konieczny alg->halg.base.cra_driver_name, err); 2317c2afad6cSKamil Konieczny goto err_hash; 2318c2afad6cSKamil Konieczny } 2319c2afad6cSKamil Konieczny } 2320c2afad6cSKamil Konieczny } 2321c2afad6cSKamil Konieczny 2322313becd1SKrzysztof Koz?owski dev_info(dev, "s5p-sss driver registered\n"); 2323a49e490cSVladimir Zapolskiy 2324a49e490cSVladimir Zapolskiy return 0; 2325a49e490cSVladimir Zapolskiy 2326c2afad6cSKamil Konieczny err_hash: 2327c2afad6cSKamil Konieczny for (j = hash_i - 1; j >= 0; j--) 2328c2afad6cSKamil Konieczny crypto_unregister_ahash(&algs_sha1_md5_sha256[j]); 2329c2afad6cSKamil Konieczny 2330c2afad6cSKamil Konieczny tasklet_kill(&pdata->hash_tasklet); 2331c2afad6cSKamil Konieczny res->end -= 0x300; 2332c2afad6cSKamil Konieczny 2333a49e490cSVladimir Zapolskiy err_algs: 2334c2afad6cSKamil Konieczny if (i < ARRAY_SIZE(algs)) 2335c2afad6cSKamil Konieczny dev_err(dev, "can't register '%s': %d\n", algs[i].cra_name, 2336c2afad6cSKamil Konieczny err); 2337a49e490cSVladimir Zapolskiy 2338a49e490cSVladimir Zapolskiy for (j = 0; j < i; j++) 2339a49e490cSVladimir Zapolskiy crypto_unregister_alg(&algs[j]); 2340a49e490cSVladimir Zapolskiy 2341a49e490cSVladimir Zapolskiy tasklet_kill(&pdata->tasklet); 2342a49e490cSVladimir Zapolskiy 2343a49e490cSVladimir Zapolskiy err_irq: 23440918f18cSKamil Konieczny if (pdata->pclk) 23450918f18cSKamil Konieczny clk_disable_unprepare(pdata->pclk); 2346a49e490cSVladimir Zapolskiy 23470918f18cSKamil Konieczny err_clk: 23480918f18cSKamil Konieczny clk_disable_unprepare(pdata->clk); 2349a49e490cSVladimir Zapolskiy s5p_dev = NULL; 2350a49e490cSVladimir Zapolskiy 2351a49e490cSVladimir Zapolskiy return err; 2352a49e490cSVladimir Zapolskiy } 2353a49e490cSVladimir Zapolskiy 2354a49e490cSVladimir Zapolskiy static int s5p_aes_remove(struct platform_device *pdev) 2355a49e490cSVladimir Zapolskiy { 2356a49e490cSVladimir Zapolskiy struct s5p_aes_dev *pdata = platform_get_drvdata(pdev); 2357a49e490cSVladimir Zapolskiy int i; 2358a49e490cSVladimir Zapolskiy 2359a49e490cSVladimir Zapolskiy if (!pdata) 2360a49e490cSVladimir Zapolskiy return -ENODEV; 2361a49e490cSVladimir Zapolskiy 2362a49e490cSVladimir Zapolskiy for (i = 0; i < ARRAY_SIZE(algs); i++) 2363a49e490cSVladimir Zapolskiy crypto_unregister_alg(&algs[i]); 2364a49e490cSVladimir Zapolskiy 2365a49e490cSVladimir Zapolskiy tasklet_kill(&pdata->tasklet); 2366c2afad6cSKamil Konieczny if (pdata->use_hash) { 2367c2afad6cSKamil Konieczny for (i = ARRAY_SIZE(algs_sha1_md5_sha256) - 1; i >= 0; i--) 2368c2afad6cSKamil Konieczny crypto_unregister_ahash(&algs_sha1_md5_sha256[i]); 2369c2afad6cSKamil Konieczny 2370c2afad6cSKamil Konieczny pdata->res->end -= 0x300; 2371c2afad6cSKamil Konieczny tasklet_kill(&pdata->hash_tasklet); 2372c2afad6cSKamil Konieczny pdata->use_hash = false; 2373c2afad6cSKamil Konieczny } 2374a49e490cSVladimir Zapolskiy 23750918f18cSKamil Konieczny if (pdata->pclk) 23760918f18cSKamil Konieczny clk_disable_unprepare(pdata->pclk); 23770918f18cSKamil Konieczny 2378c1eb7ef2SNaveen Krishna Chatradhi clk_disable_unprepare(pdata->clk); 2379a49e490cSVladimir Zapolskiy s5p_dev = NULL; 2380a49e490cSVladimir Zapolskiy 2381a49e490cSVladimir Zapolskiy return 0; 2382a49e490cSVladimir Zapolskiy } 2383a49e490cSVladimir Zapolskiy 2384a49e490cSVladimir Zapolskiy static struct platform_driver s5p_aes_crypto = { 2385a49e490cSVladimir Zapolskiy .probe = s5p_aes_probe, 2386a49e490cSVladimir Zapolskiy .remove = s5p_aes_remove, 2387a49e490cSVladimir Zapolskiy .driver = { 2388a49e490cSVladimir Zapolskiy .name = "s5p-secss", 23896b9f16e6SNaveen Krishna Chatradhi .of_match_table = s5p_sss_dt_match, 2390a49e490cSVladimir Zapolskiy }, 2391a49e490cSVladimir Zapolskiy }; 2392a49e490cSVladimir Zapolskiy 2393741e8c2dSAxel Lin module_platform_driver(s5p_aes_crypto); 2394a49e490cSVladimir Zapolskiy 2395a49e490cSVladimir Zapolskiy MODULE_DESCRIPTION("S5PV210 AES hw acceleration support."); 2396a49e490cSVladimir Zapolskiy MODULE_LICENSE("GPL v2"); 2397a49e490cSVladimir Zapolskiy MODULE_AUTHOR("Vladimir Zapolskiy <vzapolskiy@gmail.com>"); 2398c2afad6cSKamil Konieczny MODULE_AUTHOR("Kamil Konieczny <k.konieczny@partner.samsung.com>"); 2399