summaryrefslogtreecommitdiffstats
path: root/drivers/staging/ccree
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/staging/ccree')
-rw-r--r--drivers/staging/ccree/Documentation/devicetree/bindings/crypto/arm-cryptocell.txt27
-rw-r--r--drivers/staging/ccree/Kconfig43
-rw-r--r--drivers/staging/ccree/Makefile3
-rw-r--r--drivers/staging/ccree/TODO30
-rw-r--r--drivers/staging/ccree/cc_bitops.h62
-rw-r--r--drivers/staging/ccree/cc_crypto_ctx.h299
-rw-r--r--drivers/staging/ccree/cc_hal.h30
-rw-r--r--drivers/staging/ccree/cc_hw_queue_defs.h603
-rw-r--r--drivers/staging/ccree/cc_lli_defs.h57
-rw-r--r--drivers/staging/ccree/cc_pal_log.h188
-rw-r--r--drivers/staging/ccree/cc_pal_log_plat.h33
-rw-r--r--drivers/staging/ccree/cc_pal_types.h97
-rw-r--r--drivers/staging/ccree/cc_pal_types_plat.h29
-rw-r--r--drivers/staging/ccree/cc_regs.h106
-rw-r--r--drivers/staging/ccree/dx_crys_kernel.h180
-rw-r--r--drivers/staging/ccree/dx_env.h224
-rw-r--r--drivers/staging/ccree/dx_host.h155
-rw-r--r--drivers/staging/ccree/dx_reg_base_host.h34
-rw-r--r--drivers/staging/ccree/dx_reg_common.h26
-rw-r--r--drivers/staging/ccree/hash_defs.h78
-rw-r--r--drivers/staging/ccree/hw_queue_defs_plat.h43
-rw-r--r--drivers/staging/ccree/ssi_aead.c2832
-rw-r--r--drivers/staging/ccree/ssi_aead.h120
-rw-r--r--drivers/staging/ccree/ssi_buffer_mgr.c1873
-rw-r--r--drivers/staging/ccree/ssi_buffer_mgr.h105
-rw-r--r--drivers/staging/ccree/ssi_cipher.c1503
-rw-r--r--drivers/staging/ccree/ssi_cipher.h89
-rw-r--r--drivers/staging/ccree/ssi_config.h61
-rw-r--r--drivers/staging/ccree/ssi_driver.c556
-rw-r--r--drivers/staging/ccree/ssi_driver.h228
-rw-r--r--drivers/staging/ccree/ssi_fips.c65
-rw-r--r--drivers/staging/ccree/ssi_fips.h70
-rw-r--r--drivers/staging/ccree/ssi_fips_data.h315
-rw-r--r--drivers/staging/ccree/ssi_fips_ext.c96
-rw-r--r--drivers/staging/ccree/ssi_fips_ll.c1681
-rw-r--r--drivers/staging/ccree/ssi_fips_local.c369
-rw-r--r--drivers/staging/ccree/ssi_fips_local.h77
-rw-r--r--drivers/staging/ccree/ssi_hash.c2742
-rw-r--r--drivers/staging/ccree/ssi_hash.h101
-rw-r--r--drivers/staging/ccree/ssi_ivgen.c301
-rw-r--r--drivers/staging/ccree/ssi_ivgen.h72
-rw-r--r--drivers/staging/ccree/ssi_pm.c150
-rw-r--r--drivers/staging/ccree/ssi_pm.h46
-rw-r--r--drivers/staging/ccree/ssi_pm_ext.c60
-rw-r--r--drivers/staging/ccree/ssi_pm_ext.h33
-rw-r--r--drivers/staging/ccree/ssi_request_mgr.c713
-rw-r--r--drivers/staging/ccree/ssi_request_mgr.h60
-rw-r--r--drivers/staging/ccree/ssi_sram_mgr.c138
-rw-r--r--drivers/staging/ccree/ssi_sram_mgr.h80
-rw-r--r--drivers/staging/ccree/ssi_sysfs.c439
-rw-r--r--drivers/staging/ccree/ssi_sysfs.h54
51 files changed, 17376 insertions, 0 deletions
diff --git a/drivers/staging/ccree/Documentation/devicetree/bindings/crypto/arm-cryptocell.txt b/drivers/staging/ccree/Documentation/devicetree/bindings/crypto/arm-cryptocell.txt
new file mode 100644
index 0000000..2ea6517
--- /dev/null
+++ b/drivers/staging/ccree/Documentation/devicetree/bindings/crypto/arm-cryptocell.txt
@@ -0,0 +1,27 @@
+Arm TrustZone CryptoCell cryptographic accelerators
+
+Required properties:
+- compatible: must be "arm,cryptocell-712-ree".
+- reg: shall contain base register location and length.
+ Typically length is 0x10000.
+- interrupts: shall contain the interrupt for the device.
+
+Optional properties:
+- interrupt-parent: can designate the interrupt controller the
+ device interrupt is connected to, if needed.
+- clocks: may contain the clock handling the device, if needed.
+- power-domains: may contain a reference to the PM domain, if applicable.
+
+
+Examples:
+
+Zynq FPGA device
+----------------
+
+ arm_cc7x: arm_cc7x@80000000 {
+ compatible = "arm,cryptocell-712-ree";
+ interrupt-parent = <&intc>;
+ interrupts = < 0 30 4 >;
+ reg = < 0x80000000 0x10000 >;
+ };
+
diff --git a/drivers/staging/ccree/Kconfig b/drivers/staging/ccree/Kconfig
new file mode 100644
index 0000000..ae62704
--- /dev/null
+++ b/drivers/staging/ccree/Kconfig
@@ -0,0 +1,43 @@
+config CRYPTO_DEV_CCREE
+ tristate "Support for ARM TrustZone CryptoCell C7XX family of Crypto accelerators"
+ depends on CRYPTO_HW && OF && HAS_DMA
+ default n
+ select CRYPTO_HASH
+ select CRYPTO_BLKCIPHER
+ select CRYPTO_DES
+ select CRYPTO_AEAD
+ select CRYPTO_AUTHENC
+ select CRYPTO_SHA1
+ select CRYPTO_MD5
+ select CRYPTO_SHA256
+ select CRYPTO_SHA512
+ select CRYPTO_HMAC
+ select CRYPTO_AES
+ select CRYPTO_CBC
+ select CRYPTO_ECB
+ select CRYPTO_CTR
+ select CRYPTO_XTS
+ help
+ Say 'Y' to enable a driver for the Arm TrustZone CryptoCell
+ C7xx. Currently only the CryptoCell 712 REE is supported.
+ Choose this if you wish to use hardware acceleration of
+ cryptographic operations on the system REE.
+ If unsure say Y.
+
+config CCREE_FIPS_SUPPORT
+ bool "Turn on CryptoCell 7XX REE FIPS mode support"
+ depends on CRYPTO_DEV_CCREE
+ default n
+ help
+ Say 'Y' to enable support for FIPS compliant mode by the
+ CCREE driver.
+ If unsure say N.
+
+config CCREE_DISABLE_COHERENT_DMA_OPS
+ bool "Disable Coherent DMA operations for the CCREE driver"
+ depends on CRYPTO_DEV_CCREE
+ default n
+ help
+ Say 'Y' to disable the use of coherent DMA operations by the
+ CCREE driver for debugging purposes.
+ If unsure say N.
diff --git a/drivers/staging/ccree/Makefile b/drivers/staging/ccree/Makefile
new file mode 100644
index 0000000..44f3e3e
--- /dev/null
+++ b/drivers/staging/ccree/Makefile
@@ -0,0 +1,3 @@
+obj-$(CONFIG_CRYPTO_DEV_CCREE) := ccree.o
+ccree-y := ssi_driver.o ssi_sysfs.o ssi_buffer_mgr.o ssi_request_mgr.o ssi_cipher.o ssi_hash.o ssi_aead.o ssi_ivgen.o ssi_sram_mgr.o ssi_pm.o ssi_pm_ext.o
+ccree-$(CCREE_FIPS_SUPPORT) += ssi_fips.o ssi_fips_ll.o ssi_fips_ext.o ssi_fips_local.o
diff --git a/drivers/staging/ccree/TODO b/drivers/staging/ccree/TODO
new file mode 100644
index 0000000..c9f5754
--- /dev/null
+++ b/drivers/staging/ccree/TODO
@@ -0,0 +1,30 @@
+
+
+*************************************************************************
+* *
+* Arm Trust Zone CryptoCell REE Linux driver upstreaming TODO items *
+* *
+*************************************************************************
+
+ccree specific items
+a.k.a stuff fixing for this driver to move out of staging
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+1. Move to using Crypto Engine to handle backlog queueing.
+2. Remove synchronous algorithm support leftovers.
+3. Separate platform specific code for FIPS and power management into separate platform modules.
+4. Drop legacy kernel support code.
+5. Move most (all?) #ifdef CONFIG into inline functions.
+6. Remove all unused definitions.
+7. Re-factor to accomediate newer/older HW revisions besides the 712.
+8. Handle the many checkpatch errors.
+9. Implement ahash import/export correctly.
+10. Go through a proper review of DT bindings and sysfs ABI
+11. Sort out FIPS mode: bake tests into testmgr, sort out behaviour on error,
+ figure if 3DES weak key check is needed
+
+Kernel infrastructure items
+a.k.a stuff we either neither need to fix in the kernel or understand what we're doing wrong
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+1. ahash import/export context has a PAGE_SIZE/8 size limit. We need more.
+2. Crypto Engine seems to be built for HW with hardware queue depth of 1, we have 600++.
diff --git a/drivers/staging/ccree/cc_bitops.h b/drivers/staging/ccree/cc_bitops.h
new file mode 100644
index 0000000..3a39565
--- /dev/null
+++ b/drivers/staging/ccree/cc_bitops.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2012-2017 ARM Limited or its affiliates.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*!
+ * \file cc_bitops.h
+ * Bit fields operations macros.
+ */
+#ifndef _CC_BITOPS_H_
+#define _CC_BITOPS_H_
+
+#define BITMASK(mask_size) (((mask_size) < 32) ? \
+ ((1UL << (mask_size)) - 1) : 0xFFFFFFFFUL)
+#define BITMASK_AT(mask_size, mask_offset) (BITMASK(mask_size) << (mask_offset))
+
+#define BITFIELD_GET(word, bit_offset, bit_size) \
+ (((word) >> (bit_offset)) & BITMASK(bit_size))
+#define BITFIELD_SET(word, bit_offset, bit_size, new_val) do { \
+ word = ((word) & ~BITMASK_AT(bit_size, bit_offset)) | \
+ (((new_val) & BITMASK(bit_size)) << (bit_offset)); \
+} while (0)
+
+/* Is val aligned to "align" ("align" must be power of 2) */
+#ifndef IS_ALIGNED
+#define IS_ALIGNED(val, align) \
+ (((uintptr_t)(val) & ((align) - 1)) == 0)
+#endif
+
+#define SWAP_ENDIAN(word) \
+ (((word) >> 24) | (((word) & 0x00FF0000) >> 8) | \
+ (((word) & 0x0000FF00) << 8) | (((word) & 0x000000FF) << 24))
+
+#ifdef BIG__ENDIAN
+#define SWAP_TO_LE(word) SWAP_ENDIAN(word)
+#define SWAP_TO_BE(word) word
+#else
+#define SWAP_TO_LE(word) word
+#define SWAP_TO_BE(word) SWAP_ENDIAN(word)
+#endif
+
+
+
+/* Is val a multiple of "mult" ("mult" must be power of 2) */
+#define IS_MULT(val, mult) \
+ (((val) & ((mult) - 1)) == 0)
+
+#define IS_NULL_ADDR(adr) \
+ (!(adr))
+
+#endif /*_CC_BITOPS_H_*/
diff --git a/drivers/staging/ccree/cc_crypto_ctx.h b/drivers/staging/ccree/cc_crypto_ctx.h
new file mode 100644
index 0000000..9e10b26
--- /dev/null
+++ b/drivers/staging/ccree/cc_crypto_ctx.h
@@ -0,0 +1,299 @@
+/*
+ * Copyright (C) 2012-2017 ARM Limited or its affiliates.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _CC_CRYPTO_CTX_H_
+#define _CC_CRYPTO_CTX_H_
+
+#ifdef __KERNEL__
+#include <linux/types.h>
+#define INT32_MAX 0x7FFFFFFFL
+#else
+#include <stdint.h>
+#endif
+
+
+#ifndef max
+#define max(a, b) ((a) > (b) ? (a) : (b))
+#define min(a, b) ((a) < (b) ? (a) : (b))
+#endif
+
+/* context size */
+#ifndef CC_CTX_SIZE_LOG2
+#if (CC_SUPPORT_SHA > 256)
+#define CC_CTX_SIZE_LOG2 8
+#else
+#define CC_CTX_SIZE_LOG2 7
+#endif
+#endif
+#define CC_CTX_SIZE (1<<CC_CTX_SIZE_LOG2)
+#define CC_DRV_CTX_SIZE_WORDS (CC_CTX_SIZE >> 2)
+
+#define CC_DRV_DES_IV_SIZE 8
+#define CC_DRV_DES_BLOCK_SIZE 8
+
+#define CC_DRV_DES_ONE_KEY_SIZE 8
+#define CC_DRV_DES_DOUBLE_KEY_SIZE 16
+#define CC_DRV_DES_TRIPLE_KEY_SIZE 24
+#define CC_DRV_DES_KEY_SIZE_MAX CC_DRV_DES_TRIPLE_KEY_SIZE
+
+#define CC_AES_IV_SIZE 16
+#define CC_AES_IV_SIZE_WORDS (CC_AES_IV_SIZE >> 2)
+
+#define CC_AES_BLOCK_SIZE 16
+#define CC_AES_BLOCK_SIZE_WORDS 4
+
+#define CC_AES_128_BIT_KEY_SIZE 16
+#define CC_AES_128_BIT_KEY_SIZE_WORDS (CC_AES_128_BIT_KEY_SIZE >> 2)
+#define CC_AES_192_BIT_KEY_SIZE 24
+#define CC_AES_192_BIT_KEY_SIZE_WORDS (CC_AES_192_BIT_KEY_SIZE >> 2)
+#define CC_AES_256_BIT_KEY_SIZE 32
+#define CC_AES_256_BIT_KEY_SIZE_WORDS (CC_AES_256_BIT_KEY_SIZE >> 2)
+#define CC_AES_KEY_SIZE_MAX CC_AES_256_BIT_KEY_SIZE
+#define CC_AES_KEY_SIZE_WORDS_MAX (CC_AES_KEY_SIZE_MAX >> 2)
+
+#define CC_MD5_DIGEST_SIZE 16
+#define CC_SHA1_DIGEST_SIZE 20
+#define CC_SHA224_DIGEST_SIZE 28
+#define CC_SHA256_DIGEST_SIZE 32
+#define CC_SHA256_DIGEST_SIZE_IN_WORDS 8
+#define CC_SHA384_DIGEST_SIZE 48
+#define CC_SHA512_DIGEST_SIZE 64
+
+#define CC_SHA1_BLOCK_SIZE 64
+#define CC_SHA1_BLOCK_SIZE_IN_WORDS 16
+#define CC_MD5_BLOCK_SIZE 64
+#define CC_MD5_BLOCK_SIZE_IN_WORDS 16
+#define CC_SHA224_BLOCK_SIZE 64
+#define CC_SHA256_BLOCK_SIZE 64
+#define CC_SHA256_BLOCK_SIZE_IN_WORDS 16
+#define CC_SHA1_224_256_BLOCK_SIZE 64
+#define CC_SHA384_BLOCK_SIZE 128
+#define CC_SHA512_BLOCK_SIZE 128
+
+#if (CC_SUPPORT_SHA > 256)
+#define CC_DIGEST_SIZE_MAX CC_SHA512_DIGEST_SIZE
+#define CC_HASH_BLOCK_SIZE_MAX CC_SHA512_BLOCK_SIZE /*1024b*/
+#else /* Only up to SHA256 */
+#define CC_DIGEST_SIZE_MAX CC_SHA256_DIGEST_SIZE
+#define CC_HASH_BLOCK_SIZE_MAX CC_SHA256_BLOCK_SIZE /*512b*/
+#endif
+
+#define CC_HMAC_BLOCK_SIZE_MAX CC_HASH_BLOCK_SIZE_MAX
+
+#define CC_MULTI2_SYSTEM_KEY_SIZE 32
+#define CC_MULTI2_DATA_KEY_SIZE 8
+#define CC_MULTI2_SYSTEM_N_DATA_KEY_SIZE (CC_MULTI2_SYSTEM_KEY_SIZE + CC_MULTI2_DATA_KEY_SIZE)
+#define CC_MULTI2_BLOCK_SIZE 8
+#define CC_MULTI2_IV_SIZE 8
+#define CC_MULTI2_MIN_NUM_ROUNDS 8
+#define CC_MULTI2_MAX_NUM_ROUNDS 128
+
+
+#define CC_DRV_ALG_MAX_BLOCK_SIZE CC_HASH_BLOCK_SIZE_MAX
+
+
+enum drv_engine_type {
+ DRV_ENGINE_NULL = 0,
+ DRV_ENGINE_AES = 1,
+ DRV_ENGINE_DES = 2,
+ DRV_ENGINE_HASH = 3,
+ DRV_ENGINE_RC4 = 4,
+ DRV_ENGINE_DOUT = 5,
+ DRV_ENGINE_RESERVE32B = INT32_MAX,
+};
+
+enum drv_crypto_alg {
+ DRV_CRYPTO_ALG_NULL = -1,
+ DRV_CRYPTO_ALG_AES = 0,
+ DRV_CRYPTO_ALG_DES = 1,
+ DRV_CRYPTO_ALG_HASH = 2,
+ DRV_CRYPTO_ALG_C2 = 3,
+ DRV_CRYPTO_ALG_HMAC = 4,
+ DRV_CRYPTO_ALG_AEAD = 5,
+ DRV_CRYPTO_ALG_BYPASS = 6,
+ DRV_CRYPTO_ALG_NUM = 7,
+ DRV_CRYPTO_ALG_RESERVE32B = INT32_MAX
+};
+
+enum drv_crypto_direction {
+ DRV_CRYPTO_DIRECTION_NULL = -1,
+ DRV_CRYPTO_DIRECTION_ENCRYPT = 0,
+ DRV_CRYPTO_DIRECTION_DECRYPT = 1,
+ DRV_CRYPTO_DIRECTION_DECRYPT_ENCRYPT = 3,
+ DRV_CRYPTO_DIRECTION_RESERVE32B = INT32_MAX
+};
+
+enum drv_cipher_mode {
+ DRV_CIPHER_NULL_MODE = -1,
+ DRV_CIPHER_ECB = 0,
+ DRV_CIPHER_CBC = 1,
+ DRV_CIPHER_CTR = 2,
+ DRV_CIPHER_CBC_MAC = 3,
+ DRV_CIPHER_XTS = 4,
+ DRV_CIPHER_XCBC_MAC = 5,
+ DRV_CIPHER_OFB = 6,
+ DRV_CIPHER_CMAC = 7,
+ DRV_CIPHER_CCM = 8,
+ DRV_CIPHER_CBC_CTS = 11,
+ DRV_CIPHER_GCTR = 12,
+ DRV_CIPHER_ESSIV = 13,
+ DRV_CIPHER_BITLOCKER = 14,
+ DRV_CIPHER_RESERVE32B = INT32_MAX
+};
+
+enum drv_hash_mode {
+ DRV_HASH_NULL = -1,
+ DRV_HASH_SHA1 = 0,
+ DRV_HASH_SHA256 = 1,
+ DRV_HASH_SHA224 = 2,
+ DRV_HASH_SHA512 = 3,
+ DRV_HASH_SHA384 = 4,
+ DRV_HASH_MD5 = 5,
+ DRV_HASH_CBC_MAC = 6,
+ DRV_HASH_XCBC_MAC = 7,
+ DRV_HASH_CMAC = 8,
+ DRV_HASH_MODE_NUM = 9,
+ DRV_HASH_RESERVE32B = INT32_MAX
+};
+
+enum drv_hash_hw_mode {
+ DRV_HASH_HW_MD5 = 0,
+ DRV_HASH_HW_SHA1 = 1,
+ DRV_HASH_HW_SHA256 = 2,
+ DRV_HASH_HW_SHA224 = 10,
+ DRV_HASH_HW_SHA512 = 4,
+ DRV_HASH_HW_SHA384 = 12,
+ DRV_HASH_HW_GHASH = 6,
+ DRV_HASH_HW_RESERVE32B = INT32_MAX
+};
+
+enum drv_multi2_mode {
+ DRV_MULTI2_NULL = -1,
+ DRV_MULTI2_ECB = 0,
+ DRV_MULTI2_CBC = 1,
+ DRV_MULTI2_OFB = 2,
+ DRV_MULTI2_RESERVE32B = INT32_MAX
+};
+
+
+/* drv_crypto_key_type[1:0] is mapped to cipher_do[1:0] */
+/* drv_crypto_key_type[2] is mapped to cipher_config2 */
+enum drv_crypto_key_type {
+ DRV_NULL_KEY = -1,
+ DRV_USER_KEY = 0, /* 0x000 */
+ DRV_ROOT_KEY = 1, /* 0x001 */
+ DRV_PROVISIONING_KEY = 2, /* 0x010 */
+ DRV_SESSION_KEY = 3, /* 0x011 */
+ DRV_APPLET_KEY = 4, /* NA */
+ DRV_PLATFORM_KEY = 5, /* 0x101 */
+ DRV_CUSTOMER_KEY = 6, /* 0x110 */
+ DRV_END_OF_KEYS = INT32_MAX,
+};
+
+enum drv_crypto_padding_type {
+ DRV_PADDING_NONE = 0,
+ DRV_PADDING_PKCS7 = 1,
+ DRV_PADDING_RESERVE32B = INT32_MAX
+};
+
+/*******************************************************************/
+/***************** DESCRIPTOR BASED CONTEXTS ***********************/
+/*******************************************************************/
+
+ /* Generic context ("super-class") */
+struct drv_ctx_generic {
+ enum drv_crypto_alg alg;
+} __attribute__((__may_alias__));
+
+
+struct drv_ctx_hash {
+ enum drv_crypto_alg alg; /* DRV_CRYPTO_ALG_HASH */
+ enum drv_hash_mode mode;
+ uint8_t digest[CC_DIGEST_SIZE_MAX];
+ /* reserve to end of allocated context size */
+ uint8_t reserved[CC_CTX_SIZE - 2 * sizeof(uint32_t) -
+ CC_DIGEST_SIZE_MAX];
+};
+
+/* !!!! drv_ctx_hmac should have the same structure as drv_ctx_hash except
+ k0, k0_size fields */
+struct drv_ctx_hmac {
+ enum drv_crypto_alg alg; /* DRV_CRYPTO_ALG_HMAC */
+ enum drv_hash_mode mode;
+ uint8_t digest[CC_DIGEST_SIZE_MAX];
+ uint32_t k0[CC_HMAC_BLOCK_SIZE_MAX/sizeof(uint32_t)];
+ uint32_t k0_size;
+ /* reserve to end of allocated context size */
+ uint8_t reserved[CC_CTX_SIZE - 3 * sizeof(uint32_t) -
+ CC_DIGEST_SIZE_MAX - CC_HMAC_BLOCK_SIZE_MAX];
+};
+
+struct drv_ctx_cipher {
+ enum drv_crypto_alg alg; /* DRV_CRYPTO_ALG_AES */
+ enum drv_cipher_mode mode;
+ enum drv_crypto_direction direction;
+ enum drv_crypto_key_type crypto_key_type;
+ enum drv_crypto_padding_type padding_type;
+ uint32_t key_size; /* numeric value in bytes */
+ uint32_t data_unit_size; /* required for XTS */
+ /* block_state is the AES engine block state.
+ * It is used by the host to pass IV or counter at initialization.
+ * It is used by SeP for intermediate block chaining state and for
+ * returning MAC algorithms results. */
+ uint8_t block_state[CC_AES_BLOCK_SIZE];
+ uint8_t key[CC_AES_KEY_SIZE_MAX];
+ uint8_t xex_key[CC_AES_KEY_SIZE_MAX];
+ /* reserve to end of allocated context size */
+ uint32_t reserved[CC_DRV_CTX_SIZE_WORDS - 7 -
+ CC_AES_BLOCK_SIZE/sizeof(uint32_t) - 2 *
+ (CC_AES_KEY_SIZE_MAX/sizeof(uint32_t))];
+};
+
+/* authentication and encryption with associated data class */
+struct drv_ctx_aead {
+ enum drv_crypto_alg alg; /* DRV_CRYPTO_ALG_AES */
+ enum drv_cipher_mode mode;
+ enum drv_crypto_direction direction;
+ uint32_t key_size; /* numeric value in bytes */
+ uint32_t nonce_size; /* nonce size (octets) */
+ uint32_t header_size; /* finit additional data size (octets) */
+ uint32_t text_size; /* finit text data size (octets) */
+ uint32_t tag_size; /* mac size, element of {4, 6, 8, 10, 12, 14, 16} */
+ /* block_state1/2 is the AES engine block state */
+ uint8_t block_state[CC_AES_BLOCK_SIZE];
+ uint8_t mac_state[CC_AES_BLOCK_SIZE]; /* MAC result */
+ uint8_t nonce[CC_AES_BLOCK_SIZE]; /* nonce buffer */
+ uint8_t key[CC_AES_KEY_SIZE_MAX];
+ /* reserve to end of allocated context size */
+ uint32_t reserved[CC_DRV_CTX_SIZE_WORDS - 8 -
+ 3 * (CC_AES_BLOCK_SIZE/sizeof(uint32_t)) -
+ CC_AES_KEY_SIZE_MAX/sizeof(uint32_t)];
+};
+
+/*******************************************************************/
+/***************** MESSAGE BASED CONTEXTS **************************/
+/*******************************************************************/
+
+
+/* Get the address of a @member within a given @ctx address
+ @ctx: The context address
+ @type: Type of context structure
+ @member: Associated context field */
+#define GET_CTX_FIELD_ADDR(ctx, type, member) (ctx + offsetof(type, member))
+
+#endif /* _CC_CRYPTO_CTX_H_ */
+
diff --git a/drivers/staging/ccree/cc_hal.h b/drivers/staging/ccree/cc_hal.h
new file mode 100644
index 0000000..75a0ce3
--- /dev/null
+++ b/drivers/staging/ccree/cc_hal.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2012-2017 ARM Limited or its affiliates.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* pseudo cc_hal.h for cc7x_perf_test_driver (to be able to include code from CC drivers) */
+
+#ifndef __CC_HAL_H__
+#define __CC_HAL_H__
+
+#include <linux/io.h>
+
+#define READ_REGISTER(_addr) ioread32((_addr))
+#define WRITE_REGISTER(_addr, _data) iowrite32((_data), (_addr))
+
+#define CC_HAL_WRITE_REGISTER(offset, val) WRITE_REGISTER(cc_base + offset, val)
+#define CC_HAL_READ_REGISTER(offset) READ_REGISTER(cc_base + offset)
+
+#endif
diff --git a/drivers/staging/ccree/cc_hw_queue_defs.h b/drivers/staging/ccree/cc_hw_queue_defs.h
new file mode 100644
index 0000000..fbaf1b6
--- /dev/null
+++ b/drivers/staging/ccree/cc_hw_queue_defs.h
@@ -0,0 +1,603 @@
+/*
+ * Copyright (C) 2012-2017 ARM Limited or its affiliates.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __CC_HW_QUEUE_DEFS_H__
+#define __CC_HW_QUEUE_DEFS_H__
+
+#include "cc_pal_log.h"
+#include "cc_regs.h"
+#include "dx_crys_kernel.h"
+
+#ifdef __KERNEL__
+#include <linux/types.h>
+#define UINT32_MAX 0xFFFFFFFFL
+#define INT32_MAX 0x7FFFFFFFL
+#define UINT16_MAX 0xFFFFL
+#else
+#include <stdint.h>
+#endif
+
+/******************************************************************************
+* DEFINITIONS
+******************************************************************************/
+
+
+/* Dma AXI Secure bit */
+#define AXI_SECURE 0
+#define AXI_NOT_SECURE 1
+
+#define HW_DESC_SIZE_WORDS 6
+#define HW_QUEUE_SLOTS_MAX 15 /* Max. available slots in HW queue */
+
+#define _HW_DESC_MONITOR_KICK 0x7FFFC00
+
+/******************************************************************************
+* TYPE DEFINITIONS
+******************************************************************************/
+
+typedef struct HwDesc {
+ uint32_t word[HW_DESC_SIZE_WORDS];
+} HwDesc_s;
+
+typedef enum DescDirection {
+ DESC_DIRECTION_ILLEGAL = -1,
+ DESC_DIRECTION_ENCRYPT_ENCRYPT = 0,
+ DESC_DIRECTION_DECRYPT_DECRYPT = 1,
+ DESC_DIRECTION_DECRYPT_ENCRYPT = 3,
+ DESC_DIRECTION_END = INT32_MAX,
+}DescDirection_t;
+
+typedef enum DmaMode {
+ DMA_MODE_NULL = -1,
+ NO_DMA = 0,
+ DMA_SRAM = 1,
+ DMA_DLLI = 2,
+ DMA_MLLI = 3,
+ DmaMode_OPTIONTS,
+ DmaMode_END = INT32_MAX,
+}DmaMode_t;
+
+typedef enum FlowMode {
+ FLOW_MODE_NULL = -1,
+ /* data flows */
+ BYPASS = 0,
+ DIN_AES_DOUT = 1,
+ AES_to_HASH = 2,
+ AES_and_HASH = 3,
+ DIN_DES_DOUT = 4,
+ DES_to_HASH = 5,
+ DES_and_HASH = 6,
+ DIN_HASH = 7,
+ DIN_HASH_and_BYPASS = 8,
+ AESMAC_and_BYPASS = 9,
+ AES_to_HASH_and_DOUT = 10,
+ DIN_RC4_DOUT = 11,
+ DES_to_HASH_and_DOUT = 12,
+ AES_to_AES_to_HASH_and_DOUT = 13,
+ AES_to_AES_to_HASH = 14,
+ AES_to_HASH_and_AES = 15,
+ DIN_MULTI2_DOUT = 16,
+ DIN_AES_AESMAC = 17,
+ HASH_to_DOUT = 18,
+ /* setup flows */
+ S_DIN_to_AES = 32,
+ S_DIN_to_AES2 = 33,
+ S_DIN_to_DES = 34,
+ S_DIN_to_RC4 = 35,
+ S_DIN_to_MULTI2 = 36,
+ S_DIN_to_HASH = 37,
+ S_AES_to_DOUT = 38,
+ S_AES2_to_DOUT = 39,
+ S_RC4_to_DOUT = 41,
+ S_DES_to_DOUT = 42,
+ S_HASH_to_DOUT = 43,
+ SET_FLOW_ID = 44,
+ FlowMode_OPTIONTS,
+ FlowMode_END = INT32_MAX,
+}FlowMode_t;
+
+typedef enum TunnelOp {
+ TUNNEL_OP_INVALID = -1,
+ TUNNEL_OFF = 0,
+ TUNNEL_ON = 1,
+ TunnelOp_OPTIONS,
+ TunnelOp_END = INT32_MAX,
+} TunnelOp_t;
+
+typedef enum SetupOp {
+ SETUP_LOAD_NOP = 0,
+ SETUP_LOAD_STATE0 = 1,
+ SETUP_LOAD_STATE1 = 2,
+ SETUP_LOAD_STATE2 = 3,
+ SETUP_LOAD_KEY0 = 4,
+ SETUP_LOAD_XEX_KEY = 5,
+ SETUP_WRITE_STATE0 = 8,
+ SETUP_WRITE_STATE1 = 9,
+ SETUP_WRITE_STATE2 = 10,
+ SETUP_WRITE_STATE3 = 11,
+ setupOp_OPTIONTS,
+ setupOp_END = INT32_MAX,
+}SetupOp_t;
+
+enum AesMacSelector {
+ AES_SK = 1,
+ AES_CMAC_INIT = 2,
+ AES_CMAC_SIZE0 = 3,
+ AesMacEnd = INT32_MAX,
+};
+
+#define HW_KEY_MASK_CIPHER_DO 0x3
+#define HW_KEY_SHIFT_CIPHER_CFG2 2
+
+
+/* HwCryptoKey[1:0] is mapped to cipher_do[1:0] */
+/* HwCryptoKey[2:3] is mapped to cipher_config2[1:0] */
+typedef enum HwCryptoKey {
+ USER_KEY = 0, /* 0x0000 */
+ ROOT_KEY = 1, /* 0x0001 */
+ PROVISIONING_KEY = 2, /* 0x0010 */ /* ==KCP */
+ SESSION_KEY = 3, /* 0x0011 */
+ RESERVED_KEY = 4, /* NA */
+ PLATFORM_KEY = 5, /* 0x0101 */
+ CUSTOMER_KEY = 6, /* 0x0110 */
+ KFDE0_KEY = 7, /* 0x0111 */
+ KFDE1_KEY = 9, /* 0x1001 */
+ KFDE2_KEY = 10, /* 0x1010 */
+ KFDE3_KEY = 11, /* 0x1011 */
+ END_OF_KEYS = INT32_MAX,
+}HwCryptoKey_t;
+
+typedef enum HwAesKeySize {
+ AES_128_KEY = 0,
+ AES_192_KEY = 1,
+ AES_256_KEY = 2,
+ END_OF_AES_KEYS = INT32_MAX,
+}HwAesKeySize_t;
+
+typedef enum HwDesKeySize {
+ DES_ONE_KEY = 0,
+ DES_TWO_KEYS = 1,
+ DES_THREE_KEYS = 2,
+ END_OF_DES_KEYS = INT32_MAX,
+}HwDesKeySize_t;
+
+/*****************************/
+/* Descriptor packing macros */
+/*****************************/
+
+#define GET_HW_Q_DESC_WORD_IDX(descWordIdx) (CC_REG_OFFSET(CRY_KERNEL, DSCRPTR_QUEUE_WORD ## descWordIdx) )
+
+#define HW_DESC_INIT(pDesc) do { \
+ (pDesc)->word[0] = 0; \
+ (pDesc)->word[1] = 0; \
+ (pDesc)->word[2] = 0; \
+ (pDesc)->word[3] = 0; \
+ (pDesc)->word[4] = 0; \
+ (pDesc)->word[5] = 0; \
+} while (0)
+
+/* HW descriptor debug functions */
+int createDetailedDump(HwDesc_s *pDesc);
+void descriptor_log(HwDesc_s *desc);
+
+#if defined(HW_DESCRIPTOR_LOG) || defined(HW_DESC_DUMP_HOST_BUF)
+#define LOG_HW_DESC(pDesc) descriptor_log(pDesc)
+#else
+#define LOG_HW_DESC(pDesc)
+#endif
+
+#if (CC_PAL_MAX_LOG_LEVEL >= CC_PAL_LOG_LEVEL_TRACE) || defined(OEMFW_LOG)
+
+#ifdef UART_PRINTF
+#define CREATE_DETAILED_DUMP(pDesc) createDetailedDump(pDesc)
+#else
+#define CREATE_DETAILED_DUMP(pDesc)
+#endif
+
+#define HW_DESC_DUMP(pDesc) do { \
+ CC_PAL_LOG_TRACE("\n---------------------------------------------------\n"); \
+ CREATE_DETAILED_DUMP(pDesc); \
+ CC_PAL_LOG_TRACE("0x%08X, ", (unsigned int)(pDesc)->word[0]); \
+ CC_PAL_LOG_TRACE("0x%08X, ", (unsigned int)(pDesc)->word[1]); \
+ CC_PAL_LOG_TRACE("0x%08X, ", (unsigned int)(pDesc)->word[2]); \
+ CC_PAL_LOG_TRACE("0x%08X, ", (unsigned int)(pDesc)->word[3]); \
+ CC_PAL_LOG_TRACE("0x%08X, ", (unsigned int)(pDesc)->word[4]); \
+ CC_PAL_LOG_TRACE("0x%08X\n", (unsigned int)(pDesc)->word[5]); \
+ CC_PAL_LOG_TRACE("---------------------------------------------------\n\n"); \
+} while (0)
+
+#else
+#define HW_DESC_DUMP(pDesc) do {} while (0)
+#endif
+
+
+/*!
+ * This macro indicates the end of current HW descriptors flow and release the HW engines.
+ *
+ * \param pDesc pointer HW descriptor struct
+ */
+#define HW_DESC_SET_QUEUE_LAST_IND(pDesc) \
+ do { \
+ CC_REG_FLD_SET(CRY_KERNEL, DSCRPTR_QUEUE_WORD3, QUEUE_LAST_IND, (pDesc)->word[3], 1); \
+ } while (0)
+
+/*!
+ * This macro signs the end of HW descriptors flow by asking for completion ack, and release the HW engines
+ *
+ * \param pDesc pointer HW descriptor struct
+ */
+#define HW_DESC_SET_ACK_LAST(pDesc) \
+ do { \
+ CC_REG_FLD_SET(CRY_KERNEL, DSCRPTR_QUEUE_WORD3, QUEUE_LAST_IND, (pDesc)->word[3], 1); \
+ CC_REG_FLD_SET(CRY_KERNEL, DSCRPTR_QUEUE_WORD4, ACK_NEEDED, (pDesc)->word[4], 1); \
+ } while (0)
+
+
+#define MSB64(_addr) (sizeof(_addr) == 4 ? 0 : ((_addr) >> 32)&UINT16_MAX)
+
+/*!
+ * This macro sets the DIN field of a HW descriptors
+ *
+ * \param pDesc pointer HW descriptor struct
+ * \param dmaMode The DMA mode: NO_DMA, SRAM, DLLI, MLLI, CONSTANT
+ * \param dinAdr DIN address
+ * \param dinSize Data size in bytes
+ * \param axiNs AXI secure bit
+ */
+#define HW_DESC_SET_DIN_TYPE(pDesc, dmaMode, dinAdr, dinSize, axiNs) \
+ do { \
+ CC_REG_FLD_SET(CRY_KERNEL, DSCRPTR_QUEUE_WORD0, VALUE, (pDesc)->word[0], (dinAdr)&UINT32_MAX ); \
+ CC_REG_FLD_SET(CRY_KERNEL, DSCRPTR_QUEUE_WORD5, DIN_ADDR_HIGH, (pDesc)->word[5], MSB64(dinAdr) ); \
+ CC_REG_FLD_SET(CRY_KERNEL, DSCRPTR_QUEUE_WORD1, DIN_DMA_MODE, (pDesc)->word[1], (dmaMode)); \
+ CC_REG_FLD_SET(CRY_KERNEL, DSCRPTR_QUEUE_WORD1, DIN_SIZE, (pDesc)->word[1], (dinSize)); \
+ CC_REG_FLD_SET(CRY_KERNEL, DSCRPTR_QUEUE_WORD1, NS_BIT, (pDesc)->word[1], (axiNs)); \
+ } while (0)
+
+
+/*!
+ * This macro sets the DIN field of a HW descriptors to NO DMA mode. Used for NOP descriptor, register patches and
+ * other special modes
+ *
+ * \param pDesc pointer HW descriptor struct
+ * \param dinAdr DIN address
+ * \param dinSize Data size in bytes
+ */
+#define HW_DESC_SET_DIN_NO_DMA(pDesc, dinAdr, dinSize) \
+ do { \
+ CC_REG_FLD_SET(CRY_KERNEL, DSCRPTR_QUEUE_WORD0, VALUE, (pDesc)->word[0], (uint32_t)(dinAdr)); \
+ CC_REG_FLD_SET(CRY_KERNEL, DSCRPTR_QUEUE_WORD1, DIN_SIZE, (pDesc)->word[1], (dinSize)); \
+ } while (0)
+
+/*!
+ * This macro sets the DIN field of a HW descriptors to SRAM mode.
+ * Note: No need to check SRAM alignment since host requests do not use SRAM and
+ * adaptor will enforce alignment check.
+ *
+ * \param pDesc pointer HW descriptor struct
+ * \param dinAdr DIN address
+ * \param dinSize Data size in bytes
+ */
+#define HW_DESC_SET_DIN_SRAM(pDesc, dinAdr, dinSize) \
+ do { \
+ CC_REG_FLD_SET(CRY_KERNEL, DSCRPTR_QUEUE_WORD0, VALUE, (pDesc)->word[0], (uint32_t)(dinAdr)); \
+ CC_REG_FLD_SET(CRY_KERNEL, DSCRPTR_QUEUE_WORD1, DIN_DMA_MODE, (pDesc)->word[1], DMA_SRAM); \
+ CC_REG_FLD_SET(CRY_KERNEL, DSCRPTR_QUEUE_WORD1, DIN_SIZE, (pDesc)->word[1], (dinSize)); \
+ } while (0)
+
+/*! This macro sets the DIN field of a HW descriptors to CONST mode
+ *
+ * \param pDesc pointer HW descriptor struct
+ * \param val DIN const value
+ * \param dinSize Data size in bytes
+ */
+#define HW_DESC_SET_DIN_CONST(pDesc, val, dinSize) \
+ do { \
+ CC_REG_FLD_SET(CRY_KERNEL, DSCRPTR_QUEUE_WORD0, VALUE, (pDesc)->word[0], (uint32_t)(val)); \
+ CC_REG_FLD_SET(CRY_KERNEL, DSCRPTR_QUEUE_WORD1, DIN_CONST_VALUE, (pDesc)->word[1], 1); \
+ CC_REG_FLD_SET(CRY_KERNEL, DSCRPTR_QUEUE_WORD1, DIN_DMA_MODE, (pDesc)->word[1], DMA_SRAM); \
+ CC_REG_FLD_SET(CRY_KERNEL, DSCRPTR_QUEUE_WORD1, DIN_SIZE, (pDesc)->word[1], (dinSize)); \
+ } while (0)
+
+/*!
+ * This macro sets the DIN not last input data indicator
+ *
+ * \param pDesc pointer HW descriptor struct
+ */
+#define HW_DESC_SET_DIN_NOT_LAST_INDICATION(pDesc) \
+ do { \
+ CC_REG_FLD_SET(CRY_KERNEL, DSCRPTR_QUEUE_WORD1, NOT_LAST, (pDesc)->word[1], 1); \
+ } while (0)
+
+/*!
+ * This macro sets the DOUT field of a HW descriptors
+ *
+ * \param pDesc pointer HW descriptor struct
+ * \param dmaMode The DMA mode: NO_DMA, SRAM, DLLI, MLLI, CONSTANT
+ * \param doutAdr DOUT address
+ * \param doutSize Data size in bytes
+ * \param axiNs AXI secure bit
+ */
+#define HW_DESC_SET_DOUT_TYPE(pDesc, dmaMode, doutAdr, doutSize, axiNs) \
+ do { \
+ CC_REG_FLD_SET(CRY_KERNEL, DSCRPTR_QUEUE_WORD2, VALUE, (pDesc)->word[2], (doutAdr)&UINT32_MAX ); \
+ CC_REG_FLD_SET(CRY_KERNEL, DSCRPTR_QUEUE_WORD5, DOUT_ADDR_HIGH, (pDesc)->word[5], MSB64(doutAdr) ); \
+ CC_REG_FLD_SET(CRY_KERNEL, DSCRPTR_QUEUE_WORD3, DOUT_DMA_MODE, (pDesc)->word[3], (dmaMode)); \
+ CC_REG_FLD_SET(CRY_KERNEL, DSCRPTR_QUEUE_WORD3, DOUT_SIZE, (pDesc)->word[3], (doutSize)); \
+ CC_REG_FLD_SET(CRY_KERNEL, DSCRPTR_QUEUE_WORD3, NS_BIT, (pDesc)->word[3], (axiNs)); \
+ } while (0)
+
+/*!
+ * This macro sets the DOUT field of a HW descriptors to DLLI type
+ * The LAST INDICATION is provided by the user
+ *
+ * \param pDesc pointer HW descriptor struct
+ * \param doutAdr DOUT address
+ * \param doutSize Data size in bytes
+ * \param lastInd The last indication bit
+ * \param axiNs AXI secure bit
+ */
+#define HW_DESC_SET_DOUT_DLLI(pDesc, doutAdr, doutSize, axiNs ,lastInd) \
+ do { \
+ CC_REG_FLD_SET(CRY_KERNEL, DSCRPTR_QUEUE_WORD2, VALUE, (pDesc)->word[2], (doutAdr)&UINT32_MAX ); \
+ CC_REG_FLD_SET(CRY_KERNEL, DSCRPTR_QUEUE_WORD5, DOUT_ADDR_HIGH, (pDesc)->word[5], MSB64(doutAdr) ); \
+ CC_REG_FLD_SET(CRY_KERNEL, DSCRPTR_QUEUE_WORD3, DOUT_DMA_MODE, (pDesc)->word[3], DMA_DLLI); \
+ CC_REG_FLD_SET(CRY_KERNEL, DSCRPTR_QUEUE_WORD3, DOUT_SIZE, (pDesc)->word[3], (doutSize)); \
+ CC_REG_FLD_SET(CRY_KERNEL, DSCRPTR_QUEUE_WORD3, DOUT_LAST_IND, (pDesc)->word[3], lastInd); \
+ CC_REG_FLD_SET(CRY_KERNEL, DSCRPTR_QUEUE_WORD3, NS_BIT, (pDesc)->word[3], (axiNs)); \
+ } while (0)
+
+/*!
+ * This macro sets the DOUT field of a HW descriptors to DLLI type
+ * The LAST INDICATION is provided by the user
+ *
+ * \param pDesc pointer HW descriptor struct
+ * \param doutAdr DOUT address
+ * \param doutSize Data size in bytes
+ * \param lastInd The last indication bit
+ * \param axiNs AXI secure bit
+ */
+#define HW_DESC_SET_DOUT_MLLI(pDesc, doutAdr, doutSize, axiNs ,lastInd) \
+ do { \
+ CC_REG_FLD_SET(CRY_KERNEL, DSCRPTR_QUEUE_WORD2, VALUE, (pDesc)->word[2], (doutAdr)&UINT32_MAX ); \
+ CC_REG_FLD_SET(CRY_KERNEL, DSCRPTR_QUEUE_WORD5, DOUT_ADDR_HIGH, (pDesc)->word[5], MSB64(doutAdr) ); \
+ CC_REG_FLD_SET(CRY_KERNEL, DSCRPTR_QUEUE_WORD3, DOUT_DMA_MODE, (pDesc)->word[3], DMA_MLLI); \
+ CC_REG_FLD_SET(CRY_KERNEL, DSCRPTR_QUEUE_WORD3, DOUT_SIZE, (pDesc)->word[3], (doutSize)); \
+ CC_REG_FLD_SET(CRY_KERNEL, DSCRPTR_QUEUE_WORD3, DOUT_LAST_IND, (pDesc)->word[3], lastInd); \
+ CC_REG_FLD_SET(CRY_KERNEL, DSCRPTR_QUEUE_WORD3, NS_BIT, (pDesc)->word[3], (axiNs)); \
+ } while (0)
+
+/*!
+ * This macro sets the DOUT field of a HW descriptors to NO DMA mode. Used for NOP descriptor, register patches and
+ * other special modes
+ *
+ * \param pDesc pointer HW descriptor struct
+ * \param doutAdr DOUT address
+ * \param doutSize Data size in bytes
+ * \param registerWriteEnable Enables a write operation to a register
+ */
+#define HW_DESC_SET_DOUT_NO_DMA(pDesc, doutAdr, doutSize, registerWriteEnable) \
+ do { \
+ CC_REG_FLD_SET(CRY_KERNEL, DSCRPTR_QUEUE_WORD2, VALUE, (pDesc)->word[2], (uint32_t)(doutAdr)); \
+ CC_REG_FLD_SET(CRY_KERNEL, DSCRPTR_QUEUE_WORD3, DOUT_SIZE, (pDesc)->word[3], (doutSize)); \
+ CC_REG_FLD_SET(CRY_KERNEL, DSCRPTR_QUEUE_WORD3, DOUT_LAST_IND, (pDesc)->word[3], (registerWriteEnable)); \
+ } while (0)
+
+/*!
+ * This macro sets the word for the XOR operation.
+ *
+ * \param pDesc pointer HW descriptor struct
+ * \param xorVal xor data value
+ */
+#define HW_DESC_SET_XOR_VAL(pDesc, xorVal) \
+ do { \
+ CC_REG_FLD_SET(CRY_KERNEL, DSCRPTR_QUEUE_WORD2, VALUE, (pDesc)->word[2], (uint32_t)(xorVal)); \
+ } while (0)
+
+/*!
+ * This macro sets the XOR indicator bit in the descriptor
+ *
+ * \param pDesc pointer HW descriptor struct
+ */
+#define HW_DESC_SET_XOR_ACTIVE(pDesc) \
+ do { \
+ CC_REG_FLD_SET(CRY_KERNEL, DSCRPTR_QUEUE_WORD3, HASH_XOR_BIT, (pDesc)->word[3], 1); \
+ } while (0)
+
+/*!
+ * This macro selects the AES engine instead of HASH engine when setting up combined mode with AES XCBC MAC
+ *
+ * \param pDesc pointer HW descriptor struct
+ */
+#define HW_DESC_SET_AES_NOT_HASH_MODE(pDesc) \
+ do { \
+ CC_REG_FLD_SET(CRY_KERNEL, DSCRPTR_QUEUE_WORD4, AES_SEL_N_HASH, (pDesc)->word[4], 1); \
+ } while (0)
+
+/*!
+ * This macro sets the DOUT field of a HW descriptors to SRAM mode
+ * Note: No need to check SRAM alignment since host requests do not use SRAM and
+ * adaptor will enforce alignment check.
+ *
+ * \param pDesc pointer HW descriptor struct
+ * \param doutAdr DOUT address
+ * \param doutSize Data size in bytes
+ */
+#define HW_DESC_SET_DOUT_SRAM(pDesc, doutAdr, doutSize) \
+ do { \
+ CC_REG_FLD_SET(CRY_KERNEL, DSCRPTR_QUEUE_WORD2, VALUE, (pDesc)->word[2], (uint32_t)(doutAdr)); \
+ CC_REG_FLD_SET(CRY_KERNEL, DSCRPTR_QUEUE_WORD3, DOUT_DMA_MODE, (pDesc)->word[3], DMA_SRAM); \
+ CC_REG_FLD_SET(CRY_KERNEL, DSCRPTR_QUEUE_WORD3, DOUT_SIZE, (pDesc)->word[3], (doutSize)); \
+ } while (0)
+
+
+/*!
+ * This macro sets the data unit size for XEX mode in data_out_addr[15:0]
+ *
+ * \param pDesc pointer HW descriptor struct
+ * \param dataUnitSize data unit size for XEX mode
+ */
+#define HW_DESC_SET_XEX_DATA_UNIT_SIZE(pDesc, dataUnitSize) \
+ do { \
+ CC_REG_FLD_SET(CRY_KERNEL, DSCRPTR_QUEUE_WORD2, VALUE, (pDesc)->word[2], (uint32_t)(dataUnitSize)); \
+ } while (0)
+
+/*!
+ * This macro sets the number of rounds for Multi2 in data_out_addr[15:0]
+ *
+ * \param pDesc pointer HW descriptor struct
+ * \param numRounds number of rounds for Multi2
+*/
+#define HW_DESC_SET_MULTI2_NUM_ROUNDS(pDesc, numRounds) \
+ do { \
+ CC_REG_FLD_SET(CRY_KERNEL, DSCRPTR_QUEUE_WORD2, VALUE, (pDesc)->word[2], (uint32_t)(numRounds)); \
+ } while (0)
+
+/*!
+ * This macro sets the flow mode.
+ *
+ * \param pDesc pointer HW descriptor struct
+ * \param flowMode Any one of the modes defined in [CC7x-DESC]
+*/
+
+#define HW_DESC_SET_FLOW_MODE(pDesc, flowMode) \
+ do { \
+ CC_REG_FLD_SET(CRY_KERNEL, DSCRPTR_QUEUE_WORD4, DATA_FLOW_MODE, (pDesc)->word[4], (flowMode)); \
+ } while (0)
+
+/*!
+ * This macro sets the cipher mode.
+ *
+ * \param pDesc pointer HW descriptor struct
+ * \param cipherMode Any one of the modes defined in [CC7x-DESC]
+*/
+#define HW_DESC_SET_CIPHER_MODE(pDesc, cipherMode) \
+ do { \
+ CC_REG_FLD_SET(CRY_KERNEL, DSCRPTR_QUEUE_WORD4, CIPHER_MODE, (pDesc)->word[4], (cipherMode)); \
+ } while (0)
+
+/*!
+ * This macro sets the cipher configuration fields.
+ *
+ * \param pDesc pointer HW descriptor struct
+ * \param cipherConfig Any one of the modes defined in [CC7x-DESC]
+*/
+#define HW_DESC_SET_CIPHER_CONFIG0(pDesc, cipherConfig) \
+ do { \
+ CC_REG_FLD_SET(CRY_KERNEL, DSCRPTR_QUEUE_WORD4, CIPHER_CONF0, (pDesc)->word[4], (cipherConfig)); \
+ } while (0)
+
+/*!
+ * This macro sets the cipher configuration fields.
+ *
+ * \param pDesc pointer HW descriptor struct
+ * \param cipherConfig Any one of the modes defined in [CC7x-DESC]
+*/
+#define HW_DESC_SET_CIPHER_CONFIG1(pDesc, cipherConfig) \
+ do { \
+ CC_REG_FLD_SET(CRY_KERNEL, DSCRPTR_QUEUE_WORD4, CIPHER_CONF1, (pDesc)->word[4], (cipherConfig)); \
+ } while (0)
+
+/*!
+ * This macro sets HW key configuration fields.
+ *
+ * \param pDesc pointer HW descriptor struct
+ * \param hwKey The hw key number as in enun HwCryptoKey
+*/
+#define HW_DESC_SET_HW_CRYPTO_KEY(pDesc, hwKey) \
+ do { \
+ CC_REG_FLD_SET(CRY_KERNEL, DSCRPTR_QUEUE_WORD4, CIPHER_DO, (pDesc)->word[4], (hwKey)&HW_KEY_MASK_CIPHER_DO); \
+ CC_REG_FLD_SET(CRY_KERNEL, DSCRPTR_QUEUE_WORD4, CIPHER_CONF2, (pDesc)->word[4], (hwKey>>HW_KEY_SHIFT_CIPHER_CFG2)); \
+ } while (0)
+
+/*!
+ * This macro changes the bytes order of all setup-finalize descriptosets.
+ *
+ * \param pDesc pointer HW descriptor struct
+ * \param swapConfig Any one of the modes defined in [CC7x-DESC]
+*/
+#define HW_DESC_SET_BYTES_SWAP(pDesc, swapConfig) \
+ do { \
+ CC_REG_FLD_SET(CRY_KERNEL, DSCRPTR_QUEUE_WORD4, BYTES_SWAP, (pDesc)->word[4], (swapConfig)); \
+ } while (0)
+
+/*!
+ * This macro sets the CMAC_SIZE0 mode.
+ *
+ * \param pDesc pointer HW descriptor struct
+*/
+#define HW_DESC_SET_CMAC_SIZE0_MODE(pDesc) \
+ do { \
+ CC_REG_FLD_SET(CRY_KERNEL, DSCRPTR_QUEUE_WORD4, CMAC_SIZE0, (pDesc)->word[4], 0x1); \
+ } while (0)
+
+/*!
+ * This macro sets the key size for AES engine.
+ *
+ * \param pDesc pointer HW descriptor struct
+ * \param keySize key size in bytes (NOT size code)
+*/
+#define HW_DESC_SET_KEY_SIZE_AES(pDesc, keySize) \
+ do { \
+ CC_REG_FLD_SET(CRY_KERNEL, DSCRPTR_QUEUE_WORD4, KEY_SIZE, (pDesc)->word[4], ((keySize) >> 3) - 2); \
+ } while (0)
+
+/*!
+ * This macro sets the key size for DES engine.
+ *
+ * \param pDesc pointer HW descriptor struct
+ * \param keySize key size in bytes (NOT size code)
+*/
+#define HW_DESC_SET_KEY_SIZE_DES(pDesc, keySize) \
+ do { \
+ CC_REG_FLD_SET(CRY_KERNEL, DSCRPTR_QUEUE_WORD4, KEY_SIZE, (pDesc)->word[4], ((keySize) >> 3) - 1); \
+ } while (0)
+
+/*!
+ * This macro sets the descriptor's setup mode
+ *
+ * \param pDesc pointer HW descriptor struct
+ * \param setupMode Any one of the setup modes defined in [CC7x-DESC]
+*/
+#define HW_DESC_SET_SETUP_MODE(pDesc, setupMode) \
+ do { \
+ CC_REG_FLD_SET(CRY_KERNEL, DSCRPTR_QUEUE_WORD4, SETUP_OPERATION, (pDesc)->word[4], (setupMode)); \
+ } while (0)
+
+/*!
+ * This macro sets the descriptor's cipher do
+ *
+ * \param pDesc pointer HW descriptor struct
+ * \param cipherDo Any one of the cipher do defined in [CC7x-DESC]
+*/
+#define HW_DESC_SET_CIPHER_DO(pDesc, cipherDo) \
+ do { \
+ CC_REG_FLD_SET(CRY_KERNEL, DSCRPTR_QUEUE_WORD4, CIPHER_DO, (pDesc)->word[4], (cipherDo)&HW_KEY_MASK_CIPHER_DO); \
+ } while (0)
+
+/*!
+ * This macro sets the DIN field of a HW descriptors to star/stop monitor descriptor.
+ * Used for performance measurements and debug purposes.
+ *
+ * \param pDesc pointer HW descriptor struct
+ */
+#define HW_DESC_SET_DIN_MONITOR_CNTR(pDesc) \
+ do { \
+ CC_REG_FLD_SET(CRY_KERNEL, DSCRPTR_MEASURE_CNTR, VALUE, (pDesc)->word[1], _HW_DESC_MONITOR_KICK); \
+ } while (0)
+
+
+
+#endif /*__CC_HW_QUEUE_DEFS_H__*/
diff --git a/drivers/staging/ccree/cc_lli_defs.h b/drivers/staging/ccree/cc_lli_defs.h
new file mode 100644
index 0000000..697f1ed
--- /dev/null
+++ b/drivers/staging/ccree/cc_lli_defs.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2012-2017 ARM Limited or its affiliates.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _CC_LLI_DEFS_H_
+#define _CC_LLI_DEFS_H_
+#ifdef __KERNEL__
+#include <linux/types.h>
+#else
+#include <stdint.h>
+#endif
+#include "cc_bitops.h"
+
+/* Max DLLI size */
+#define DLLI_SIZE_BIT_SIZE 0x18 // DX_DSCRPTR_QUEUE_WORD1_DIN_SIZE_BIT_SIZE
+
+#define CC_MAX_MLLI_ENTRY_SIZE 0x10000
+
+#define MSB64(_addr) (sizeof(_addr) == 4 ? 0 : ((_addr) >> 32)&UINT16_MAX)
+
+#define LLI_SET_ADDR(lli_p, addr) \
+ BITFIELD_SET(((uint32_t *)(lli_p))[LLI_WORD0_OFFSET], LLI_LADDR_BIT_OFFSET, LLI_LADDR_BIT_SIZE, (addr & UINT32_MAX)); \
+ BITFIELD_SET(((uint32_t *)(lli_p))[LLI_WORD1_OFFSET], LLI_HADDR_BIT_OFFSET, LLI_HADDR_BIT_SIZE, MSB64(addr));
+
+#define LLI_SET_SIZE(lli_p, size) \
+ BITFIELD_SET(((uint32_t *)(lli_p))[LLI_WORD1_OFFSET], LLI_SIZE_BIT_OFFSET, LLI_SIZE_BIT_SIZE, size)
+
+/* Size of entry */
+#define LLI_ENTRY_WORD_SIZE 2
+#define LLI_ENTRY_BYTE_SIZE (LLI_ENTRY_WORD_SIZE * sizeof(uint32_t))
+
+/* Word0[31:0] = ADDR[31:0] */
+#define LLI_WORD0_OFFSET 0
+#define LLI_LADDR_BIT_OFFSET 0
+#define LLI_LADDR_BIT_SIZE 32
+/* Word1[31:16] = ADDR[47:32]; Word1[15:0] = SIZE */
+#define LLI_WORD1_OFFSET 1
+#define LLI_SIZE_BIT_OFFSET 0
+#define LLI_SIZE_BIT_SIZE 16
+#define LLI_HADDR_BIT_OFFSET 16
+#define LLI_HADDR_BIT_SIZE 16
+
+
+#endif /*_CC_LLI_DEFS_H_*/
diff --git a/drivers/staging/ccree/cc_pal_log.h b/drivers/staging/ccree/cc_pal_log.h
new file mode 100644
index 0000000..e5f5a87
--- /dev/null
+++ b/drivers/staging/ccree/cc_pal_log.h
@@ -0,0 +1,188 @@
+/*
+ * Copyright (C) 2012-2017 ARM Limited or its affiliates.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _CC_PAL_LOG_H_
+#define _CC_PAL_LOG_H_
+
+#include "cc_pal_types.h"
+#include "cc_pal_log_plat.h"
+
+/*!
+@file
+@brief This file contains the PAL layer log definitions, by default the log is disabled.
+@defgroup cc_pal_log CryptoCell PAL logging APIs and definitions
+@{
+@ingroup cc_pal
+*/
+
+/* PAL log levels (to be used in CC_PAL_logLevel) */
+/*! PAL log level - disabled. */
+#define CC_PAL_LOG_LEVEL_NULL (-1) /*!< \internal Disable logging */
+/*! PAL log level - error. */
+#define CC_PAL_LOG_LEVEL_ERR 0
+/*! PAL log level - warning. */
+#define CC_PAL_LOG_LEVEL_WARN 1
+/*! PAL log level - info. */
+#define CC_PAL_LOG_LEVEL_INFO 2
+/*! PAL log level - debug. */
+#define CC_PAL_LOG_LEVEL_DEBUG 3
+/*! PAL log level - trace. */
+#define CC_PAL_LOG_LEVEL_TRACE 4
+/*! PAL log level - data. */
+#define CC_PAL_LOG_LEVEL_DATA 5
+
+#ifndef CC_PAL_LOG_CUR_COMPONENT
+/* Setting default component mask in case caller did not define */
+/* (a mask that is always on for every log mask value but full masking) */
+/*! Default log debugged component.*/
+#define CC_PAL_LOG_CUR_COMPONENT 0xFFFFFFFF
+#endif
+#ifndef CC_PAL_LOG_CUR_COMPONENT_NAME
+/*! Default log debugged component.*/
+#define CC_PAL_LOG_CUR_COMPONENT_NAME "CC"
+#endif
+
+/* Select compile time log level (default if not explicitly specified by caller) */
+#ifndef CC_PAL_MAX_LOG_LEVEL /* Can be overriden by external definition of this constant */
+#ifdef DEBUG
+/*! Default debug log level (when debug is set to on).*/
+#define CC_PAL_MAX_LOG_LEVEL CC_PAL_LOG_LEVEL_ERR /*CC_PAL_LOG_LEVEL_DEBUG*/
+#else /* Disable logging */
+/*! Default debug log level (when debug is set to on).*/
+#define CC_PAL_MAX_LOG_LEVEL CC_PAL_LOG_LEVEL_NULL
+#endif
+#endif /*CC_PAL_MAX_LOG_LEVEL*/
+/*! Evaluate CC_PAL_MAX_LOG_LEVEL in case provided by caller */
+#define __CC_PAL_LOG_LEVEL_EVAL(level) level
+/*! Maximal log level defintion.*/
+#define _CC_PAL_MAX_LOG_LEVEL __CC_PAL_LOG_LEVEL_EVAL(CC_PAL_MAX_LOG_LEVEL)
+
+
+#ifdef ARM_DSM
+/*! Log init function. */
+#define CC_PalLogInit() do {} while (0)
+/*! Log set level function - sets the level of logging in case of debug. */
+#define CC_PalLogLevelSet(setLevel) do {} while (0)
+/*! Log set mask function - sets the component masking in case of debug. */
+#define CC_PalLogMaskSet(setMask) do {} while (0)
+#else
+#if _CC_PAL_MAX_LOG_LEVEL > CC_PAL_LOG_LEVEL_NULL
+/*! Log init function. */
+void CC_PalLogInit(void);
+/*! Log set level function - sets the level of logging in case of debug. */
+void CC_PalLogLevelSet(int setLevel);
+/*! Log set mask function - sets the component masking in case of debug. */
+void CC_PalLogMaskSet(uint32_t setMask);
+/*! Global variable for log level */
+extern int CC_PAL_logLevel;
+/*! Global variable for log mask */
+extern uint32_t CC_PAL_logMask;
+#else /* No log */
+/*! Log init function. */
+static inline void CC_PalLogInit(void) {}
+/*! Log set level function - sets the level of logging in case of debug. */
+static inline void CC_PalLogLevelSet(int setLevel) {CC_UNUSED_PARAM(setLevel);}
+/*! Log set mask function - sets the component masking in case of debug. */
+static inline void CC_PalLogMaskSet(uint32_t setMask) {CC_UNUSED_PARAM(setMask);}
+#endif
+#endif
+
+/*! Filter logging based on logMask and dispatch to platform specific logging mechanism. */
+#define _CC_PAL_LOG(level, format, ...) \
+ if (CC_PAL_logMask & CC_PAL_LOG_CUR_COMPONENT) \
+ __CC_PAL_LOG_PLAT(CC_PAL_LOG_LEVEL_ ## level, "%s:%s: " format, CC_PAL_LOG_CUR_COMPONENT_NAME, __func__, ##__VA_ARGS__)
+
+#if (_CC_PAL_MAX_LOG_LEVEL >= CC_PAL_LOG_LEVEL_ERR)
+/*! Log messages according to log level.*/
+#define CC_PAL_LOG_ERR(format, ... ) \
+ _CC_PAL_LOG(ERR, format, ##__VA_ARGS__)
+#else
+/*! Log messages according to log level.*/
+#define CC_PAL_LOG_ERR( ... ) do {} while (0)
+#endif
+
+#if (_CC_PAL_MAX_LOG_LEVEL >= CC_PAL_LOG_LEVEL_WARN)
+/*! Log messages according to log level.*/
+#define CC_PAL_LOG_WARN(format, ... ) \
+ if (CC_PAL_logLevel >= CC_PAL_LOG_LEVEL_WARN) \
+ _CC_PAL_LOG(WARN, format, ##__VA_ARGS__)
+#else
+/*! Log messages according to log level.*/
+#define CC_PAL_LOG_WARN( ... ) do {} while (0)
+#endif
+
+#if (_CC_PAL_MAX_LOG_LEVEL >= CC_PAL_LOG_LEVEL_INFO)
+/*! Log messages according to log level.*/
+#define CC_PAL_LOG_INFO(format, ... ) \
+ if (CC_PAL_logLevel >= CC_PAL_LOG_LEVEL_INFO) \
+ _CC_PAL_LOG(INFO, format, ##__VA_ARGS__)
+#else
+/*! Log messages according to log level.*/
+#define CC_PAL_LOG_INFO( ... ) do {} while (0)
+#endif
+
+#if (_CC_PAL_MAX_LOG_LEVEL >= CC_PAL_LOG_LEVEL_DEBUG)
+/*! Log messages according to log level.*/
+#define CC_PAL_LOG_DEBUG(format, ... ) \
+ if (CC_PAL_logLevel >= CC_PAL_LOG_LEVEL_DEBUG) \
+ _CC_PAL_LOG(DEBUG, format, ##__VA_ARGS__)
+
+/*! Log message buffer.*/
+#define CC_PAL_LOG_DUMP_BUF(msg, buf, size) \
+ do { \
+ int i; \
+ uint8_t *pData = (uint8_t*)buf; \
+ \
+ PRINTF("%s (%d):\n", msg, size); \
+ for (i = 0; i < size; i++) { \
+ PRINTF("0x%02X ", pData[i]); \
+ if ((i & 0xF) == 0xF) { \
+ PRINTF("\n"); \
+ } \
+ } \
+ PRINTF("\n"); \
+ } while (0)
+#else
+/*! Log debug messages.*/
+#define CC_PAL_LOG_DEBUG( ... ) do {} while (0)
+/*! Log debug buffer.*/
+#define CC_PAL_LOG_DUMP_BUF(msg, buf, size) do {} while (0)
+#endif
+
+#if (_CC_PAL_MAX_LOG_LEVEL >= CC_PAL_LOG_LEVEL_TRACE)
+/*! Log debug trace.*/
+#define CC_PAL_LOG_TRACE(format, ... ) \
+ if (CC_PAL_logLevel >= CC_PAL_LOG_LEVEL_TRACE) \
+ _CC_PAL_LOG(TRACE, format, ##__VA_ARGS__)
+#else
+/*! Log debug trace.*/
+#define CC_PAL_LOG_TRACE(...) do {} while (0)
+#endif
+
+#if (_CC_PAL_MAX_LOG_LEVEL >= CC_PAL_LOG_LEVEL_TRACE)
+/*! Log debug data.*/
+#define CC_PAL_LOG_DATA(format, ...) \
+ if (CC_PAL_logLevel >= CC_PAL_LOG_LEVEL_TRACE) \
+ _CC_PAL_LOG(DATA, format, ##__VA_ARGS__)
+#else
+/*! Log debug data.*/
+#define CC_PAL_LOG_DATA( ...) do {} while (0)
+#endif
+/**
+@}
+ */
+
+#endif /*_CC_PAL_LOG_H_*/
diff --git a/drivers/staging/ccree/cc_pal_log_plat.h b/drivers/staging/ccree/cc_pal_log_plat.h
new file mode 100644
index 0000000..a05a200
--- /dev/null
+++ b/drivers/staging/ccree/cc_pal_log_plat.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2012-2017 ARM Limited or its affiliates.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* Dummy pal_log_plat for test driver in kernel */
+
+#ifndef _SSI_PAL_LOG_PLAT_H_
+#define _SSI_PAL_LOG_PLAT_H_
+
+#if defined(DEBUG)
+
+#define __CC_PAL_LOG_PLAT(level, format, ...) printk(level "cc7x_test::" format , ##__VA_ARGS__)
+
+#else /* Disable all prints */
+
+#define __CC_PAL_LOG_PLAT(...) do {} while (0)
+
+#endif
+
+#endif /*_SASI_PAL_LOG_PLAT_H_*/
+
diff --git a/drivers/staging/ccree/cc_pal_types.h b/drivers/staging/ccree/cc_pal_types.h
new file mode 100644
index 0000000..9b59bbb
--- /dev/null
+++ b/drivers/staging/ccree/cc_pal_types.h
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2012-2017 ARM Limited or its affiliates.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef CC_PAL_TYPES_H
+#define CC_PAL_TYPES_H
+
+/*!
+@file
+@brief This file contains platform-dependent definitions and types.
+@defgroup cc_pal_types CryptoCell PAL platform dependant types
+@{
+@ingroup cc_pal
+
+*/
+
+#include "cc_pal_types_plat.h"
+
+/*! Boolean definition.*/
+typedef enum {
+ /*! Boolean false definition.*/
+ CC_FALSE = 0,
+ /*! Boolean true definition.*/
+ CC_TRUE = 1
+} CCBool;
+
+/*! Success definition. */
+#define CC_SUCCESS 0UL
+/*! Failure definition. */
+#define CC_FAIL 1UL
+
+/*! Defintion of 1KB in bytes. */
+#define CC_1K_SIZE_IN_BYTES 1024
+/*! Defintion of number of bits in a byte. */
+#define CC_BITS_IN_BYTE 8
+/*! Defintion of number of bits in a 32bits word. */
+#define CC_BITS_IN_32BIT_WORD 32
+/*! Defintion of number of bytes in a 32bits word. */
+#define CC_32BIT_WORD_SIZE (sizeof(uint32_t))
+
+/*! Success (OK) defintion. */
+#define CC_OK 0
+
+/*! Macro that handles unused parameters in the code (to avoid compilation warnings). */
+#define CC_UNUSED_PARAM(prm) ((void)prm)
+
+/*! Maximal uint32 value.*/
+#define CC_MAX_UINT32_VAL (0xFFFFFFFF)
+
+
+/* Minimum and Maximum macros */
+#ifdef min
+/*! Definition for minimum. */
+#define CC_MIN(a,b) min( a , b )
+#else
+/*! Definition for minimum. */
+#define CC_MIN( a , b ) ( ( (a) < (b) ) ? (a) : (b) )
+#endif
+
+#ifdef max
+/*! Definition for maximum. */
+#define CC_MAX(a,b) max( a , b )
+#else
+/*! Definition for maximum. */
+#define CC_MAX( a , b ) ( ( (a) > (b) ) ? (a) : (b) )
+#endif
+
+/*! Macro that calculates number of full bytes from bits (i.e. 7 bits are 1 byte). */
+#define CALC_FULL_BYTES(numBits) ((numBits)/CC_BITS_IN_BYTE + (((numBits) & (CC_BITS_IN_BYTE-1)) > 0))
+/*! Macro that calculates number of full 32bits words from bits (i.e. 31 bits are 1 word). */
+#define CALC_FULL_32BIT_WORDS(numBits) ((numBits)/CC_BITS_IN_32BIT_WORD + (((numBits) & (CC_BITS_IN_32BIT_WORD-1)) > 0))
+/*! Macro that calculates number of full 32bits words from bytes (i.e. 3 bytes are 1 word). */
+#define CALC_32BIT_WORDS_FROM_BYTES(sizeBytes) ((sizeBytes)/CC_32BIT_WORD_SIZE + (((sizeBytes) & (CC_32BIT_WORD_SIZE-1)) > 0))
+/*! Macro that round up bits to 32bits words. */
+#define ROUNDUP_BITS_TO_32BIT_WORD(numBits) (CALC_FULL_32BIT_WORDS(numBits) * CC_BITS_IN_32BIT_WORD)
+/*! Macro that round up bits to bytes. */
+#define ROUNDUP_BITS_TO_BYTES(numBits) (CALC_FULL_BYTES(numBits) * CC_BITS_IN_BYTE)
+/*! Macro that round up bytes to 32bits words. */
+#define ROUNDUP_BYTES_TO_32BIT_WORD(sizeBytes) (CALC_32BIT_WORDS_FROM_BYTES(sizeBytes) * CC_32BIT_WORD_SIZE)
+
+
+/**
+@}
+ */
+#endif
diff --git a/drivers/staging/ccree/cc_pal_types_plat.h b/drivers/staging/ccree/cc_pal_types_plat.h
new file mode 100644
index 0000000..6e42112
--- /dev/null
+++ b/drivers/staging/ccree/cc_pal_types_plat.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2012-2017 ARM Limited or its affiliates.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef SSI_PAL_TYPES_PLAT_H
+#define SSI_PAL_TYPES_PLAT_H
+/* Linux kernel types */
+
+#include <linux/types.h>
+
+#ifndef NULL /* Missing in Linux kernel */
+#define NULL (0x0L)
+#endif
+
+
+#endif /*SSI_PAL_TYPES_PLAT_H*/
diff --git a/drivers/staging/ccree/cc_regs.h b/drivers/staging/ccree/cc_regs.h
new file mode 100644
index 0000000..963f814
--- /dev/null
+++ b/drivers/staging/ccree/cc_regs.h
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2012-2017 ARM Limited or its affiliates.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+/*!
+ * @file
+ * @brief This file contains macro definitions for accessing ARM TrustZone CryptoCell register space.
+ */
+
+#ifndef _CC_REGS_H_
+#define _CC_REGS_H_
+
+#include "cc_bitops.h"
+
+/* Register Offset macro */
+#define CC_REG_OFFSET(unit_name, reg_name) \
+ (DX_BASE_ ## unit_name + DX_ ## reg_name ## _REG_OFFSET)
+
+#define CC_REG_BIT_SHIFT(reg_name, field_name) \
+ (DX_ ## reg_name ## _ ## field_name ## _BIT_SHIFT)
+
+/* Register Offset macros (from registers base address in host) */
+#include "dx_reg_base_host.h"
+
+/* Read-Modify-Write a field of a register */
+#define MODIFY_REGISTER_FLD(unitName, regName, fldName, fldVal) \
+do { \
+ uint32_t regVal; \
+ regVal = READ_REGISTER(CC_REG_ADDR(unitName, regName)); \
+ CC_REG_FLD_SET(unitName, regName, fldName, regVal, fldVal); \
+ WRITE_REGISTER(CC_REG_ADDR(unitName, regName), regVal); \
+} while (0)
+
+/* Registers address macros for ENV registers (development FPGA only) */
+#ifdef DX_BASE_ENV_REGS
+
+/* This offset should be added to mapping address of DX_BASE_ENV_REGS */
+#define CC_ENV_REG_OFFSET(reg_name) (DX_ENV_ ## reg_name ## _REG_OFFSET)
+
+#endif /*DX_BASE_ENV_REGS*/
+
+/*! Bit fields get */
+#define CC_REG_FLD_GET(unit_name, reg_name, fld_name, reg_val) \
+ (DX_ ## reg_name ## _ ## fld_name ## _BIT_SIZE == 0x20 ? \
+ reg_val /*!< \internal Optimization for 32b fields */ : \
+ BITFIELD_GET(reg_val, DX_ ## reg_name ## _ ## fld_name ## _BIT_SHIFT, \
+ DX_ ## reg_name ## _ ## fld_name ## _BIT_SIZE))
+
+/*! Bit fields access */
+#define CC_REG_FLD_GET2(unit_name, reg_name, fld_name, reg_val) \
+ (CC_ ## reg_name ## _ ## fld_name ## _BIT_SIZE == 0x20 ? \
+ reg_val /*!< \internal Optimization for 32b fields */ : \
+ BITFIELD_GET(reg_val, CC_ ## reg_name ## _ ## fld_name ## _BIT_SHIFT, \
+ CC_ ## reg_name ## _ ## fld_name ## _BIT_SIZE))
+
+/* yael TBD !!! - *
+* all HW includes should start with CC_ and not DX_ !! */
+
+
+/*! Bit fields set */
+#define CC_REG_FLD_SET( \
+ unit_name, reg_name, fld_name, reg_shadow_var, new_fld_val) \
+do { \
+ if (DX_ ## reg_name ## _ ## fld_name ## _BIT_SIZE == 0x20) \
+ reg_shadow_var = new_fld_val; /*!< \internal Optimization for 32b fields */\
+ else \
+ BITFIELD_SET(reg_shadow_var, \
+ DX_ ## reg_name ## _ ## fld_name ## _BIT_SHIFT, \
+ DX_ ## reg_name ## _ ## fld_name ## _BIT_SIZE, \
+ new_fld_val); \
+} while (0)
+
+/*! Bit fields set */
+#define CC_REG_FLD_SET2( \
+ unit_name, reg_name, fld_name, reg_shadow_var, new_fld_val) \
+do { \
+ if (CC_ ## reg_name ## _ ## fld_name ## _BIT_SIZE == 0x20) \
+ reg_shadow_var = new_fld_val; /*!< \internal Optimization for 32b fields */\
+ else \
+ BITFIELD_SET(reg_shadow_var, \
+ CC_ ## reg_name ## _ ## fld_name ## _BIT_SHIFT, \
+ CC_ ## reg_name ## _ ## fld_name ## _BIT_SIZE, \
+ new_fld_val); \
+} while (0)
+
+/* Usage example:
+ uint32_t reg_shadow = READ_REGISTER(CC_REG_ADDR(CRY_KERNEL,AES_CONTROL));
+ CC_REG_FLD_SET(CRY_KERNEL,AES_CONTROL,NK_KEY0,reg_shadow, 3);
+ CC_REG_FLD_SET(CRY_KERNEL,AES_CONTROL,NK_KEY1,reg_shadow, 1);
+ WRITE_REGISTER(CC_REG_ADDR(CRY_KERNEL,AES_CONTROL), reg_shadow);
+ */
+
+#endif /*_CC_REGS_H_*/
diff --git a/drivers/staging/ccree/dx_crys_kernel.h b/drivers/staging/ccree/dx_crys_kernel.h
new file mode 100644
index 0000000..703469c
--- /dev/null
+++ b/drivers/staging/ccree/dx_crys_kernel.h
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) 2012-2017 ARM Limited or its affiliates.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __DX_CRYS_KERNEL_H__
+#define __DX_CRYS_KERNEL_H__
+
+// --------------------------------------
+// BLOCK: DSCRPTR
+// --------------------------------------
+#define DX_DSCRPTR_COMPLETION_COUNTER_REG_OFFSET 0xE00UL
+#define DX_DSCRPTR_COMPLETION_COUNTER_COMPLETION_COUNTER_BIT_SHIFT 0x0UL
+#define DX_DSCRPTR_COMPLETION_COUNTER_COMPLETION_COUNTER_BIT_SIZE 0x6UL
+#define DX_DSCRPTR_COMPLETION_COUNTER_OVERFLOW_COUNTER_BIT_SHIFT 0x6UL
+#define DX_DSCRPTR_COMPLETION_COUNTER_OVERFLOW_COUNTER_BIT_SIZE 0x1UL
+#define DX_DSCRPTR_SW_RESET_REG_OFFSET 0xE40UL
+#define DX_DSCRPTR_SW_RESET_VALUE_BIT_SHIFT 0x0UL
+#define DX_DSCRPTR_SW_RESET_VALUE_BIT_SIZE 0x1UL
+#define DX_DSCRPTR_QUEUE_SRAM_SIZE_REG_OFFSET 0xE60UL
+#define DX_DSCRPTR_QUEUE_SRAM_SIZE_NUM_OF_DSCRPTR_BIT_SHIFT 0x0UL
+#define DX_DSCRPTR_QUEUE_SRAM_SIZE_NUM_OF_DSCRPTR_BIT_SIZE 0xAUL
+#define DX_DSCRPTR_QUEUE_SRAM_SIZE_DSCRPTR_SRAM_SIZE_BIT_SHIFT 0xAUL
+#define DX_DSCRPTR_QUEUE_SRAM_SIZE_DSCRPTR_SRAM_SIZE_BIT_SIZE 0xCUL
+#define DX_DSCRPTR_QUEUE_SRAM_SIZE_SRAM_SIZE_BIT_SHIFT 0x16UL
+#define DX_DSCRPTR_QUEUE_SRAM_SIZE_SRAM_SIZE_BIT_SIZE 0x3UL
+#define DX_DSCRPTR_SINGLE_ADDR_EN_REG_OFFSET 0xE64UL
+#define DX_DSCRPTR_SINGLE_ADDR_EN_VALUE_BIT_SHIFT 0x0UL
+#define DX_DSCRPTR_SINGLE_ADDR_EN_VALUE_BIT_SIZE 0x1UL
+#define DX_DSCRPTR_MEASURE_CNTR_REG_OFFSET 0xE68UL
+#define DX_DSCRPTR_MEASURE_CNTR_VALUE_BIT_SHIFT 0x0UL
+#define DX_DSCRPTR_MEASURE_CNTR_VALUE_BIT_SIZE 0x20UL
+#define DX_DSCRPTR_QUEUE_WORD0_REG_OFFSET 0xE80UL
+#define DX_DSCRPTR_QUEUE_WORD0_VALUE_BIT_SHIFT 0x0UL
+#define DX_DSCRPTR_QUEUE_WORD0_VALUE_BIT_SIZE 0x20UL
+#define DX_DSCRPTR_QUEUE_WORD1_REG_OFFSET 0xE84UL
+#define DX_DSCRPTR_QUEUE_WORD1_DIN_DMA_MODE_BIT_SHIFT 0x0UL
+#define DX_DSCRPTR_QUEUE_WORD1_DIN_DMA_MODE_BIT_SIZE 0x2UL
+#define DX_DSCRPTR_QUEUE_WORD1_DIN_SIZE_BIT_SHIFT 0x2UL
+#define DX_DSCRPTR_QUEUE_WORD1_DIN_SIZE_BIT_SIZE 0x18UL
+#define DX_DSCRPTR_QUEUE_WORD1_NS_BIT_BIT_SHIFT 0x1AUL
+#define DX_DSCRPTR_QUEUE_WORD1_NS_BIT_BIT_SIZE 0x1UL
+#define DX_DSCRPTR_QUEUE_WORD1_DIN_CONST_VALUE_BIT_SHIFT 0x1BUL
+#define DX_DSCRPTR_QUEUE_WORD1_DIN_CONST_VALUE_BIT_SIZE 0x1UL
+#define DX_DSCRPTR_QUEUE_WORD1_NOT_LAST_BIT_SHIFT 0x1CUL
+#define DX_DSCRPTR_QUEUE_WORD1_NOT_LAST_BIT_SIZE 0x1UL
+#define DX_DSCRPTR_QUEUE_WORD1_LOCK_QUEUE_BIT_SHIFT 0x1DUL
+#define DX_DSCRPTR_QUEUE_WORD1_LOCK_QUEUE_BIT_SIZE 0x1UL
+#define DX_DSCRPTR_QUEUE_WORD1_NOT_USED_BIT_SHIFT 0x1EUL
+#define DX_DSCRPTR_QUEUE_WORD1_NOT_USED_BIT_SIZE 0x2UL
+#define DX_DSCRPTR_QUEUE_WORD2_REG_OFFSET 0xE88UL
+#define DX_DSCRPTR_QUEUE_WORD2_VALUE_BIT_SHIFT 0x0UL
+#define DX_DSCRPTR_QUEUE_WORD2_VALUE_BIT_SIZE 0x20UL
+#define DX_DSCRPTR_QUEUE_WORD3_REG_OFFSET 0xE8CUL
+#define DX_DSCRPTR_QUEUE_WORD3_DOUT_DMA_MODE_BIT_SHIFT 0x0UL
+#define DX_DSCRPTR_QUEUE_WORD3_DOUT_DMA_MODE_BIT_SIZE 0x2UL
+#define DX_DSCRPTR_QUEUE_WORD3_DOUT_SIZE_BIT_SHIFT 0x2UL
+#define DX_DSCRPTR_QUEUE_WORD3_DOUT_SIZE_BIT_SIZE 0x18UL
+#define DX_DSCRPTR_QUEUE_WORD3_NS_BIT_BIT_SHIFT 0x1AUL
+#define DX_DSCRPTR_QUEUE_WORD3_NS_BIT_BIT_SIZE 0x1UL
+#define DX_DSCRPTR_QUEUE_WORD3_DOUT_LAST_IND_BIT_SHIFT 0x1BUL
+#define DX_DSCRPTR_QUEUE_WORD3_DOUT_LAST_IND_BIT_SIZE 0x1UL
+#define DX_DSCRPTR_QUEUE_WORD3_HASH_XOR_BIT_BIT_SHIFT 0x1DUL
+#define DX_DSCRPTR_QUEUE_WORD3_HASH_XOR_BIT_BIT_SIZE 0x1UL
+#define DX_DSCRPTR_QUEUE_WORD3_NOT_USED_BIT_SHIFT 0x1EUL
+#define DX_DSCRPTR_QUEUE_WORD3_NOT_USED_BIT_SIZE 0x1UL
+#define DX_DSCRPTR_QUEUE_WORD3_QUEUE_LAST_IND_BIT_SHIFT 0x1FUL
+#define DX_DSCRPTR_QUEUE_WORD3_QUEUE_LAST_IND_BIT_SIZE 0x1UL
+#define DX_DSCRPTR_QUEUE_WORD4_REG_OFFSET 0xE90UL
+#define DX_DSCRPTR_QUEUE_WORD4_DATA_FLOW_MODE_BIT_SHIFT 0x0UL
+#define DX_DSCRPTR_QUEUE_WORD4_DATA_FLOW_MODE_BIT_SIZE 0x6UL
+#define DX_DSCRPTR_QUEUE_WORD4_AES_SEL_N_HASH_BIT_SHIFT 0x6UL
+#define DX_DSCRPTR_QUEUE_WORD4_AES_SEL_N_HASH_BIT_SIZE 0x1UL
+#define DX_DSCRPTR_QUEUE_WORD4_AES_XOR_CRYPTO_KEY_BIT_SHIFT 0x7UL
+#define DX_DSCRPTR_QUEUE_WORD4_AES_XOR_CRYPTO_KEY_BIT_SIZE 0x1UL
+#define DX_DSCRPTR_QUEUE_WORD4_ACK_NEEDED_BIT_SHIFT 0x8UL
+#define DX_DSCRPTR_QUEUE_WORD4_ACK_NEEDED_BIT_SIZE 0x2UL
+#define DX_DSCRPTR_QUEUE_WORD4_CIPHER_MODE_BIT_SHIFT 0xAUL
+#define DX_DSCRPTR_QUEUE_WORD4_CIPHER_MODE_BIT_SIZE 0x4UL
+#define DX_DSCRPTR_QUEUE_WORD4_CMAC_SIZE0_BIT_SHIFT 0xEUL
+#define DX_DSCRPTR_QUEUE_WORD4_CMAC_SIZE0_BIT_SIZE 0x1UL
+#define DX_DSCRPTR_QUEUE_WORD4_CIPHER_DO_BIT_SHIFT 0xFUL
+#define DX_DSCRPTR_QUEUE_WORD4_CIPHER_DO_BIT_SIZE 0x2UL
+#define DX_DSCRPTR_QUEUE_WORD4_CIPHER_CONF0_BIT_SHIFT 0x11UL
+#define DX_DSCRPTR_QUEUE_WORD4_CIPHER_CONF0_BIT_SIZE 0x2UL
+#define DX_DSCRPTR_QUEUE_WORD4_CIPHER_CONF1_BIT_SHIFT 0x13UL
+#define DX_DSCRPTR_QUEUE_WORD4_CIPHER_CONF1_BIT_SIZE 0x1UL
+#define DX_DSCRPTR_QUEUE_WORD4_CIPHER_CONF2_BIT_SHIFT 0x14UL
+#define DX_DSCRPTR_QUEUE_WORD4_CIPHER_CONF2_BIT_SIZE 0x2UL
+#define DX_DSCRPTR_QUEUE_WORD4_KEY_SIZE_BIT_SHIFT 0x16UL
+#define DX_DSCRPTR_QUEUE_WORD4_KEY_SIZE_BIT_SIZE 0x2UL
+#define DX_DSCRPTR_QUEUE_WORD4_SETUP_OPERATION_BIT_SHIFT 0x18UL
+#define DX_DSCRPTR_QUEUE_WORD4_SETUP_OPERATION_BIT_SIZE 0x4UL
+#define DX_DSCRPTR_QUEUE_WORD4_DIN_SRAM_ENDIANNESS_BIT_SHIFT 0x1CUL
+#define DX_DSCRPTR_QUEUE_WORD4_DIN_SRAM_ENDIANNESS_BIT_SIZE 0x1UL
+#define DX_DSCRPTR_QUEUE_WORD4_DOUT_SRAM_ENDIANNESS_BIT_SHIFT 0x1DUL
+#define DX_DSCRPTR_QUEUE_WORD4_DOUT_SRAM_ENDIANNESS_BIT_SIZE 0x1UL
+#define DX_DSCRPTR_QUEUE_WORD4_WORD_SWAP_BIT_SHIFT 0x1EUL
+#define DX_DSCRPTR_QUEUE_WORD4_WORD_SWAP_BIT_SIZE 0x1UL
+#define DX_DSCRPTR_QUEUE_WORD4_BYTES_SWAP_BIT_SHIFT 0x1FUL
+#define DX_DSCRPTR_QUEUE_WORD4_BYTES_SWAP_BIT_SIZE 0x1UL
+#define DX_DSCRPTR_QUEUE_WORD5_REG_OFFSET 0xE94UL
+#define DX_DSCRPTR_QUEUE_WORD5_DIN_ADDR_HIGH_BIT_SHIFT 0x0UL
+#define DX_DSCRPTR_QUEUE_WORD5_DIN_ADDR_HIGH_BIT_SIZE 0x10UL
+#define DX_DSCRPTR_QUEUE_WORD5_DOUT_ADDR_HIGH_BIT_SHIFT 0x10UL
+#define DX_DSCRPTR_QUEUE_WORD5_DOUT_ADDR_HIGH_BIT_SIZE 0x10UL
+#define DX_DSCRPTR_QUEUE_WATERMARK_REG_OFFSET 0xE98UL
+#define DX_DSCRPTR_QUEUE_WATERMARK_VALUE_BIT_SHIFT 0x0UL
+#define DX_DSCRPTR_QUEUE_WATERMARK_VALUE_BIT_SIZE 0xAUL
+#define DX_DSCRPTR_QUEUE_CONTENT_REG_OFFSET 0xE9CUL
+#define DX_DSCRPTR_QUEUE_CONTENT_VALUE_BIT_SHIFT 0x0UL
+#define DX_DSCRPTR_QUEUE_CONTENT_VALUE_BIT_SIZE 0xAUL
+// --------------------------------------
+// BLOCK: AXI_P
+// --------------------------------------
+#define DX_AXIM_MON_INFLIGHT_REG_OFFSET 0xB00UL
+#define DX_AXIM_MON_INFLIGHT_VALUE_BIT_SHIFT 0x0UL
+#define DX_AXIM_MON_INFLIGHT_VALUE_BIT_SIZE 0x8UL
+#define DX_AXIM_MON_INFLIGHTLAST_REG_OFFSET 0xB40UL
+#define DX_AXIM_MON_INFLIGHTLAST_VALUE_BIT_SHIFT 0x0UL
+#define DX_AXIM_MON_INFLIGHTLAST_VALUE_BIT_SIZE 0x8UL
+#define DX_AXIM_MON_COMP_REG_OFFSET 0xB80UL
+#define DX_AXIM_MON_COMP_VALUE_BIT_SHIFT 0x0UL
+#define DX_AXIM_MON_COMP_VALUE_BIT_SIZE 0x10UL
+#define DX_AXIM_MON_ERR_REG_OFFSET 0xBC4UL
+#define DX_AXIM_MON_ERR_BRESP_BIT_SHIFT 0x0UL
+#define DX_AXIM_MON_ERR_BRESP_BIT_SIZE 0x2UL
+#define DX_AXIM_MON_ERR_BID_BIT_SHIFT 0x2UL
+#define DX_AXIM_MON_ERR_BID_BIT_SIZE 0x4UL
+#define DX_AXIM_MON_ERR_RRESP_BIT_SHIFT 0x10UL
+#define DX_AXIM_MON_ERR_RRESP_BIT_SIZE 0x2UL
+#define DX_AXIM_MON_ERR_RID_BIT_SHIFT 0x12UL
+#define DX_AXIM_MON_ERR_RID_BIT_SIZE 0x4UL
+#define DX_AXIM_CFG_REG_OFFSET 0xBE8UL
+#define DX_AXIM_CFG_BRESPMASK_BIT_SHIFT 0x4UL
+#define DX_AXIM_CFG_BRESPMASK_BIT_SIZE 0x1UL
+#define DX_AXIM_CFG_RRESPMASK_BIT_SHIFT 0x5UL
+#define DX_AXIM_CFG_RRESPMASK_BIT_SIZE 0x1UL
+#define DX_AXIM_CFG_INFLTMASK_BIT_SHIFT 0x6UL
+#define DX_AXIM_CFG_INFLTMASK_BIT_SIZE 0x1UL
+#define DX_AXIM_CFG_COMPMASK_BIT_SHIFT 0x7UL
+#define DX_AXIM_CFG_COMPMASK_BIT_SIZE 0x1UL
+#define DX_AXIM_ACE_CONST_REG_OFFSET 0xBECUL
+#define DX_AXIM_ACE_CONST_ARDOMAIN_BIT_SHIFT 0x0UL
+#define DX_AXIM_ACE_CONST_ARDOMAIN_BIT_SIZE 0x2UL
+#define DX_AXIM_ACE_CONST_AWDOMAIN_BIT_SHIFT 0x2UL
+#define DX_AXIM_ACE_CONST_AWDOMAIN_BIT_SIZE 0x2UL
+#define DX_AXIM_ACE_CONST_ARBAR_BIT_SHIFT 0x4UL
+#define DX_AXIM_ACE_CONST_ARBAR_BIT_SIZE 0x2UL
+#define DX_AXIM_ACE_CONST_AWBAR_BIT_SHIFT 0x6UL
+#define DX_AXIM_ACE_CONST_AWBAR_BIT_SIZE 0x2UL
+#define DX_AXIM_ACE_CONST_ARSNOOP_BIT_SHIFT 0x8UL
+#define DX_AXIM_ACE_CONST_ARSNOOP_BIT_SIZE 0x4UL
+#define DX_AXIM_ACE_CONST_AWSNOOP_NOT_ALIGNED_BIT_SHIFT 0xCUL
+#define DX_AXIM_ACE_CONST_AWSNOOP_NOT_ALIGNED_BIT_SIZE 0x3UL
+#define DX_AXIM_ACE_CONST_AWSNOOP_ALIGNED_BIT_SHIFT 0xFUL
+#define DX_AXIM_ACE_CONST_AWSNOOP_ALIGNED_BIT_SIZE 0x3UL
+#define DX_AXIM_ACE_CONST_AWADDR_NOT_MASKED_BIT_SHIFT 0x12UL
+#define DX_AXIM_ACE_CONST_AWADDR_NOT_MASKED_BIT_SIZE 0x7UL
+#define DX_AXIM_ACE_CONST_AWLEN_VAL_BIT_SHIFT 0x19UL
+#define DX_AXIM_ACE_CONST_AWLEN_VAL_BIT_SIZE 0x4UL
+#define DX_AXIM_CACHE_PARAMS_REG_OFFSET 0xBF0UL
+#define DX_AXIM_CACHE_PARAMS_AWCACHE_LAST_BIT_SHIFT 0x0UL
+#define DX_AXIM_CACHE_PARAMS_AWCACHE_LAST_BIT_SIZE 0x4UL
+#define DX_AXIM_CACHE_PARAMS_AWCACHE_BIT_SHIFT 0x4UL
+#define DX_AXIM_CACHE_PARAMS_AWCACHE_BIT_SIZE 0x4UL
+#define DX_AXIM_CACHE_PARAMS_ARCACHE_BIT_SHIFT 0x8UL
+#define DX_AXIM_CACHE_PARAMS_ARCACHE_BIT_SIZE 0x4UL
+#endif // __DX_CRYS_KERNEL_H__
diff --git a/drivers/staging/ccree/dx_env.h b/drivers/staging/ccree/dx_env.h
new file mode 100644
index 0000000..0804060
--- /dev/null
+++ b/drivers/staging/ccree/dx_env.h
@@ -0,0 +1,224 @@
+/*
+ * Copyright (C) 2012-2017 ARM Limited or its affiliates.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __DX_ENV_H__
+#define __DX_ENV_H__
+
+// --------------------------------------
+// BLOCK: FPGA_ENV_REGS
+// --------------------------------------
+#define DX_ENV_PKA_DEBUG_MODE_REG_OFFSET 0x024UL
+#define DX_ENV_PKA_DEBUG_MODE_VALUE_BIT_SHIFT 0x0UL
+#define DX_ENV_PKA_DEBUG_MODE_VALUE_BIT_SIZE 0x1UL
+#define DX_ENV_SCAN_MODE_REG_OFFSET 0x030UL
+#define DX_ENV_SCAN_MODE_VALUE_BIT_SHIFT 0x0UL
+#define DX_ENV_SCAN_MODE_VALUE_BIT_SIZE 0x1UL
+#define DX_ENV_CC_ALLOW_SCAN_REG_OFFSET 0x034UL
+#define DX_ENV_CC_ALLOW_SCAN_VALUE_BIT_SHIFT 0x0UL
+#define DX_ENV_CC_ALLOW_SCAN_VALUE_BIT_SIZE 0x1UL
+#define DX_ENV_CC_HOST_INT_REG_OFFSET 0x0A0UL
+#define DX_ENV_CC_HOST_INT_VALUE_BIT_SHIFT 0x0UL
+#define DX_ENV_CC_HOST_INT_VALUE_BIT_SIZE 0x1UL
+#define DX_ENV_CC_PUB_HOST_INT_REG_OFFSET 0x0A4UL
+#define DX_ENV_CC_PUB_HOST_INT_VALUE_BIT_SHIFT 0x0UL
+#define DX_ENV_CC_PUB_HOST_INT_VALUE_BIT_SIZE 0x1UL
+#define DX_ENV_CC_RST_N_REG_OFFSET 0x0A8UL
+#define DX_ENV_CC_RST_N_VALUE_BIT_SHIFT 0x0UL
+#define DX_ENV_CC_RST_N_VALUE_BIT_SIZE 0x1UL
+#define DX_ENV_RST_OVERRIDE_REG_OFFSET 0x0ACUL
+#define DX_ENV_RST_OVERRIDE_VALUE_BIT_SHIFT 0x0UL
+#define DX_ENV_RST_OVERRIDE_VALUE_BIT_SIZE 0x1UL
+#define DX_ENV_CC_POR_N_ADDR_REG_OFFSET 0x0E0UL
+#define DX_ENV_CC_POR_N_ADDR_VALUE_BIT_SHIFT 0x0UL
+#define DX_ENV_CC_POR_N_ADDR_VALUE_BIT_SIZE 0x1UL
+#define DX_ENV_CC_COLD_RST_REG_OFFSET 0x0FCUL
+#define DX_ENV_CC_COLD_RST_VALUE_BIT_SHIFT 0x0UL
+#define DX_ENV_CC_COLD_RST_VALUE_BIT_SIZE 0x1UL
+#define DX_ENV_DUMMY_ADDR_REG_OFFSET 0x108UL
+#define DX_ENV_DUMMY_ADDR_VALUE_BIT_SHIFT 0x0UL
+#define DX_ENV_DUMMY_ADDR_VALUE_BIT_SIZE 0x20UL
+#define DX_ENV_COUNTER_CLR_REG_OFFSET 0x118UL
+#define DX_ENV_COUNTER_CLR_VALUE_BIT_SHIFT 0x0UL
+#define DX_ENV_COUNTER_CLR_VALUE_BIT_SIZE 0x1UL
+#define DX_ENV_COUNTER_RD_REG_OFFSET 0x11CUL
+#define DX_ENV_COUNTER_RD_VALUE_BIT_SHIFT 0x0UL
+#define DX_ENV_COUNTER_RD_VALUE_BIT_SIZE 0x20UL
+#define DX_ENV_RNG_DEBUG_ENABLE_REG_OFFSET 0x430UL
+#define DX_ENV_RNG_DEBUG_ENABLE_VALUE_BIT_SHIFT 0x0UL
+#define DX_ENV_RNG_DEBUG_ENABLE_VALUE_BIT_SIZE 0x1UL
+#define DX_ENV_CC_LCS_REG_OFFSET 0x43CUL
+#define DX_ENV_CC_LCS_VALUE_BIT_SHIFT 0x0UL
+#define DX_ENV_CC_LCS_VALUE_BIT_SIZE 0x8UL
+#define DX_ENV_CC_IS_CM_DM_SECURE_RMA_REG_OFFSET 0x440UL
+#define DX_ENV_CC_IS_CM_DM_SECURE_RMA_IS_CM_BIT_SHIFT 0x0UL
+#define DX_ENV_CC_IS_CM_DM_SECURE_RMA_IS_CM_BIT_SIZE 0x1UL
+#define DX_ENV_CC_IS_CM_DM_SECURE_RMA_IS_DM_BIT_SHIFT 0x1UL
+#define DX_ENV_CC_IS_CM_DM_SECURE_RMA_IS_DM_BIT_SIZE 0x1UL
+#define DX_ENV_CC_IS_CM_DM_SECURE_RMA_IS_SECURE_BIT_SHIFT 0x2UL
+#define DX_ENV_CC_IS_CM_DM_SECURE_RMA_IS_SECURE_BIT_SIZE 0x1UL
+#define DX_ENV_CC_IS_CM_DM_SECURE_RMA_IS_RMA_BIT_SHIFT 0x3UL
+#define DX_ENV_CC_IS_CM_DM_SECURE_RMA_IS_RMA_BIT_SIZE 0x1UL
+#define DX_ENV_DCU_EN_REG_OFFSET 0x444UL
+#define DX_ENV_DCU_EN_VALUE_BIT_SHIFT 0x0UL
+#define DX_ENV_DCU_EN_VALUE_BIT_SIZE 0x20UL
+#define DX_ENV_CC_LCS_IS_VALID_REG_OFFSET 0x448UL
+#define DX_ENV_CC_LCS_IS_VALID_VALUE_BIT_SHIFT 0x0UL
+#define DX_ENV_CC_LCS_IS_VALID_VALUE_BIT_SIZE 0x1UL
+#define DX_ENV_POWER_DOWN_REG_OFFSET 0x478UL
+#define DX_ENV_POWER_DOWN_VALUE_BIT_SHIFT 0x0UL
+#define DX_ENV_POWER_DOWN_VALUE_BIT_SIZE 0x20UL
+#define DX_ENV_DCU_H_EN_REG_OFFSET 0x484UL
+#define DX_ENV_DCU_H_EN_VALUE_BIT_SHIFT 0x0UL
+#define DX_ENV_DCU_H_EN_VALUE_BIT_SIZE 0x20UL
+#define DX_ENV_VERSION_REG_OFFSET 0x488UL
+#define DX_ENV_VERSION_VALUE_BIT_SHIFT 0x0UL
+#define DX_ENV_VERSION_VALUE_BIT_SIZE 0x20UL
+#define DX_ENV_ROSC_WRITE_REG_OFFSET 0x48CUL
+#define DX_ENV_ROSC_WRITE_VALUE_BIT_SHIFT 0x0UL
+#define DX_ENV_ROSC_WRITE_VALUE_BIT_SIZE 0x1UL
+#define DX_ENV_ROSC_ADDR_REG_OFFSET 0x490UL
+#define DX_ENV_ROSC_ADDR_VALUE_BIT_SHIFT 0x0UL
+#define DX_ENV_ROSC_ADDR_VALUE_BIT_SIZE 0x8UL
+#define DX_ENV_RESET_SESSION_KEY_REG_OFFSET 0x494UL
+#define DX_ENV_RESET_SESSION_KEY_VALUE_BIT_SHIFT 0x0UL
+#define DX_ENV_RESET_SESSION_KEY_VALUE_BIT_SIZE 0x1UL
+#define DX_ENV_SESSION_KEY_0_REG_OFFSET 0x4A0UL
+#define DX_ENV_SESSION_KEY_0_VALUE_BIT_SHIFT 0x0UL
+#define DX_ENV_SESSION_KEY_0_VALUE_BIT_SIZE 0x20UL
+#define DX_ENV_SESSION_KEY_1_REG_OFFSET 0x4A4UL
+#define DX_ENV_SESSION_KEY_1_VALUE_BIT_SHIFT 0x0UL
+#define DX_ENV_SESSION_KEY_1_VALUE_BIT_SIZE 0x20UL
+#define DX_ENV_SESSION_KEY_2_REG_OFFSET 0x4A8UL
+#define DX_ENV_SESSION_KEY_2_VALUE_BIT_SHIFT 0x0UL
+#define DX_ENV_SESSION_KEY_2_VALUE_BIT_SIZE 0x20UL
+#define DX_ENV_SESSION_KEY_3_REG_OFFSET 0x4ACUL
+#define DX_ENV_SESSION_KEY_3_VALUE_BIT_SHIFT 0x0UL
+#define DX_ENV_SESSION_KEY_3_VALUE_BIT_SIZE 0x20UL
+#define DX_ENV_SESSION_KEY_VALID_REG_OFFSET 0x4B0UL
+#define DX_ENV_SESSION_KEY_VALID_VALUE_BIT_SHIFT 0x0UL
+#define DX_ENV_SESSION_KEY_VALID_VALUE_BIT_SIZE 0x1UL
+#define DX_ENV_SPIDEN_REG_OFFSET 0x4D0UL
+#define DX_ENV_SPIDEN_VALUE_BIT_SHIFT 0x0UL
+#define DX_ENV_SPIDEN_VALUE_BIT_SIZE 0x1UL
+#define DX_ENV_AXIM_USER_PARAMS_REG_OFFSET 0x600UL
+#define DX_ENV_AXIM_USER_PARAMS_ARUSER_BIT_SHIFT 0x0UL
+#define DX_ENV_AXIM_USER_PARAMS_ARUSER_BIT_SIZE 0x5UL
+#define DX_ENV_AXIM_USER_PARAMS_AWUSER_BIT_SHIFT 0x5UL
+#define DX_ENV_AXIM_USER_PARAMS_AWUSER_BIT_SIZE 0x5UL
+#define DX_ENV_SECURITY_MODE_OVERRIDE_REG_OFFSET 0x604UL
+#define DX_ENV_SECURITY_MODE_OVERRIDE_AWPROT_NS_BIT_BIT_SHIFT 0x0UL
+#define DX_ENV_SECURITY_MODE_OVERRIDE_AWPROT_NS_BIT_BIT_SIZE 0x1UL
+#define DX_ENV_SECURITY_MODE_OVERRIDE_AWPROT_NS_OVERRIDE_BIT_SHIFT 0x1UL
+#define DX_ENV_SECURITY_MODE_OVERRIDE_AWPROT_NS_OVERRIDE_BIT_SIZE 0x1UL
+#define DX_ENV_SECURITY_MODE_OVERRIDE_ARPROT_NS_BIT_BIT_SHIFT 0x2UL
+#define DX_ENV_SECURITY_MODE_OVERRIDE_ARPROT_NS_BIT_BIT_SIZE 0x1UL
+#define DX_ENV_SECURITY_MODE_OVERRIDE_ARPROT_NS_OVERRIDE_BIT_SHIFT 0x3UL
+#define DX_ENV_SECURITY_MODE_OVERRIDE_ARPROT_NS_OVERRIDE_BIT_SIZE 0x1UL
+#define DX_ENV_AO_CC_KPLT_0_REG_OFFSET 0x620UL
+#define DX_ENV_AO_CC_KPLT_0_VALUE_BIT_SHIFT 0x0UL
+#define DX_ENV_AO_CC_KPLT_0_VALUE_BIT_SIZE 0x20UL
+#define DX_ENV_AO_CC_KPLT_1_REG_OFFSET 0x624UL
+#define DX_ENV_AO_CC_KPLT_1_VALUE_BIT_SHIFT 0x0UL
+#define DX_ENV_AO_CC_KPLT_1_VALUE_BIT_SIZE 0x20UL
+#define DX_ENV_AO_CC_KPLT_2_REG_OFFSET 0x628UL
+#define DX_ENV_AO_CC_KPLT_2_VALUE_BIT_SHIFT 0x0UL
+#define DX_ENV_AO_CC_KPLT_2_VALUE_BIT_SIZE 0x20UL
+#define DX_ENV_AO_CC_KPLT_3_REG_OFFSET 0x62CUL
+#define DX_ENV_AO_CC_KPLT_3_VALUE_BIT_SHIFT 0x0UL
+#define DX_ENV_AO_CC_KPLT_3_VALUE_BIT_SIZE 0x20UL
+#define DX_ENV_AO_CC_KCST_0_REG_OFFSET 0x630UL
+#define DX_ENV_AO_CC_KCST_0_VALUE_BIT_SHIFT 0x0UL
+#define DX_ENV_AO_CC_KCST_0_VALUE_BIT_SIZE 0x20UL
+#define DX_ENV_AO_CC_KCST_1_REG_OFFSET 0x634UL
+#define DX_ENV_AO_CC_KCST_1_VALUE_BIT_SHIFT 0x0UL
+#define DX_ENV_AO_CC_KCST_1_VALUE_BIT_SIZE 0x20UL
+#define DX_ENV_AO_CC_KCST_2_REG_OFFSET 0x638UL
+#define DX_ENV_AO_CC_KCST_2_VALUE_BIT_SHIFT 0x0UL
+#define DX_ENV_AO_CC_KCST_2_VALUE_BIT_SIZE 0x20UL
+#define DX_ENV_AO_CC_KCST_3_REG_OFFSET 0x63CUL
+#define DX_ENV_AO_CC_KCST_3_VALUE_BIT_SHIFT 0x0UL
+#define DX_ENV_AO_CC_KCST_3_VALUE_BIT_SIZE 0x20UL
+#define DX_ENV_APB_FIPS_ADDR_REG_OFFSET 0x650UL
+#define DX_ENV_APB_FIPS_ADDR_VALUE_BIT_SHIFT 0x0UL
+#define DX_ENV_APB_FIPS_ADDR_VALUE_BIT_SIZE 0xCUL
+#define DX_ENV_APB_FIPS_VAL_REG_OFFSET 0x654UL
+#define DX_ENV_APB_FIPS_VAL_VALUE_BIT_SHIFT 0x0UL
+#define DX_ENV_APB_FIPS_VAL_VALUE_BIT_SIZE 0x20UL
+#define DX_ENV_APB_FIPS_MASK_REG_OFFSET 0x658UL
+#define DX_ENV_APB_FIPS_MASK_VALUE_BIT_SHIFT 0x0UL
+#define DX_ENV_APB_FIPS_MASK_VALUE_BIT_SIZE 0x20UL
+#define DX_ENV_APB_FIPS_CNT_REG_OFFSET 0x65CUL
+#define DX_ENV_APB_FIPS_CNT_VALUE_BIT_SHIFT 0x0UL
+#define DX_ENV_APB_FIPS_CNT_VALUE_BIT_SIZE 0x20UL
+#define DX_ENV_APB_FIPS_NEW_ADDR_REG_OFFSET 0x660UL
+#define DX_ENV_APB_FIPS_NEW_ADDR_VALUE_BIT_SHIFT 0x0UL
+#define DX_ENV_APB_FIPS_NEW_ADDR_VALUE_BIT_SIZE 0xCUL
+#define DX_ENV_APB_FIPS_NEW_VAL_REG_OFFSET 0x664UL
+#define DX_ENV_APB_FIPS_NEW_VAL_VALUE_BIT_SHIFT 0x0UL
+#define DX_ENV_APB_FIPS_NEW_VAL_VALUE_BIT_SIZE 0x20UL
+#define DX_ENV_APBP_FIPS_ADDR_REG_OFFSET 0x670UL
+#define DX_ENV_APBP_FIPS_ADDR_VALUE_BIT_SHIFT 0x0UL
+#define DX_ENV_APBP_FIPS_ADDR_VALUE_BIT_SIZE 0xCUL
+#define DX_ENV_APBP_FIPS_VAL_REG_OFFSET 0x674UL
+#define DX_ENV_APBP_FIPS_VAL_VALUE_BIT_SHIFT 0x0UL
+#define DX_ENV_APBP_FIPS_VAL_VALUE_BIT_SIZE 0x20UL
+#define DX_ENV_APBP_FIPS_MASK_REG_OFFSET 0x678UL
+#define DX_ENV_APBP_FIPS_MASK_VALUE_BIT_SHIFT 0x0UL
+#define DX_ENV_APBP_FIPS_MASK_VALUE_BIT_SIZE 0x20UL
+#define DX_ENV_APBP_FIPS_CNT_REG_OFFSET 0x67CUL
+#define DX_ENV_APBP_FIPS_CNT_VALUE_BIT_SHIFT 0x0UL
+#define DX_ENV_APBP_FIPS_CNT_VALUE_BIT_SIZE 0x20UL
+#define DX_ENV_APBP_FIPS_NEW_ADDR_REG_OFFSET 0x680UL
+#define DX_ENV_APBP_FIPS_NEW_ADDR_VALUE_BIT_SHIFT 0x0UL
+#define DX_ENV_APBP_FIPS_NEW_ADDR_VALUE_BIT_SIZE 0xCUL
+#define DX_ENV_APBP_FIPS_NEW_VAL_REG_OFFSET 0x684UL
+#define DX_ENV_APBP_FIPS_NEW_VAL_VALUE_BIT_SHIFT 0x0UL
+#define DX_ENV_APBP_FIPS_NEW_VAL_VALUE_BIT_SIZE 0x20UL
+#define DX_ENV_CC_POWERDOWN_EN_REG_OFFSET 0x690UL
+#define DX_ENV_CC_POWERDOWN_EN_VALUE_BIT_SHIFT 0x0UL
+#define DX_ENV_CC_POWERDOWN_EN_VALUE_BIT_SIZE 0x1UL
+#define DX_ENV_CC_POWERDOWN_RST_EN_REG_OFFSET 0x694UL
+#define DX_ENV_CC_POWERDOWN_RST_EN_VALUE_BIT_SHIFT 0x0UL
+#define DX_ENV_CC_POWERDOWN_RST_EN_VALUE_BIT_SIZE 0x1UL
+#define DX_ENV_POWERDOWN_RST_CNTR_REG_OFFSET 0x698UL
+#define DX_ENV_POWERDOWN_RST_CNTR_VALUE_BIT_SHIFT 0x0UL
+#define DX_ENV_POWERDOWN_RST_CNTR_VALUE_BIT_SIZE 0x20UL
+#define DX_ENV_POWERDOWN_EN_DEBUG_REG_OFFSET 0x69CUL
+#define DX_ENV_POWERDOWN_EN_DEBUG_VALUE_BIT_SHIFT 0x0UL
+#define DX_ENV_POWERDOWN_EN_DEBUG_VALUE_BIT_SIZE 0x1UL
+// --------------------------------------
+// BLOCK: ENV_CC_MEMORIES
+// --------------------------------------
+#define DX_ENV_FUSE_READY_REG_OFFSET 0x000UL
+#define DX_ENV_FUSE_READY_VALUE_BIT_SHIFT 0x0UL
+#define DX_ENV_FUSE_READY_VALUE_BIT_SIZE 0x1UL
+#define DX_ENV_PERF_RAM_MASTER_REG_OFFSET 0x0ECUL
+#define DX_ENV_PERF_RAM_MASTER_VALUE_BIT_SHIFT 0x0UL
+#define DX_ENV_PERF_RAM_MASTER_VALUE_BIT_SIZE 0x1UL
+#define DX_ENV_PERF_RAM_ADDR_HIGH4_REG_OFFSET 0x0F0UL
+#define DX_ENV_PERF_RAM_ADDR_HIGH4_VALUE_BIT_SHIFT 0x0UL
+#define DX_ENV_PERF_RAM_ADDR_HIGH4_VALUE_BIT_SIZE 0x2UL
+#define DX_ENV_FUSES_RAM_REG_OFFSET 0x3ECUL
+#define DX_ENV_FUSES_RAM_VALUE_BIT_SHIFT 0x0UL
+#define DX_ENV_FUSES_RAM_VALUE_BIT_SIZE 0x20UL
+// --------------------------------------
+// BLOCK: ENV_PERF_RAM_BASE
+// --------------------------------------
+#define DX_ENV_PERF_RAM_BASE_REG_OFFSET 0x000UL
+#define DX_ENV_PERF_RAM_BASE_VALUE_BIT_SHIFT 0x0UL
+#define DX_ENV_PERF_RAM_BASE_VALUE_BIT_SIZE 0x20UL
+
+#endif /*__DX_ENV_H__*/
diff --git a/drivers/staging/ccree/dx_host.h b/drivers/staging/ccree/dx_host.h
new file mode 100644
index 0000000..4e42e74
--- /dev/null
+++ b/drivers/staging/ccree/dx_host.h
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2012-2017 ARM Limited or its affiliates.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __DX_HOST_H__
+#define __DX_HOST_H__
+
+// --------------------------------------
+// BLOCK: HOST_P
+// --------------------------------------
+#define DX_HOST_IRR_REG_OFFSET 0xA00UL
+#define DX_HOST_IRR_DSCRPTR_COMPLETION_LOW_INT_BIT_SHIFT 0x2UL
+#define DX_HOST_IRR_DSCRPTR_COMPLETION_LOW_INT_BIT_SIZE 0x1UL
+#define DX_HOST_IRR_AXI_ERR_INT_BIT_SHIFT 0x8UL
+#define DX_HOST_IRR_AXI_ERR_INT_BIT_SIZE 0x1UL
+#define DX_HOST_IRR_GPR0_BIT_SHIFT 0xBUL
+#define DX_HOST_IRR_GPR0_BIT_SIZE 0x1UL
+#define DX_HOST_IRR_DSCRPTR_WATERMARK_INT_BIT_SHIFT 0x13UL
+#define DX_HOST_IRR_DSCRPTR_WATERMARK_INT_BIT_SIZE 0x1UL
+#define DX_HOST_IRR_AXIM_COMP_INT_BIT_SHIFT 0x17UL
+#define DX_HOST_IRR_AXIM_COMP_INT_BIT_SIZE 0x1UL
+#define DX_HOST_IMR_REG_OFFSET 0xA04UL
+#define DX_HOST_IMR_NOT_USED_MASK_BIT_SHIFT 0x1UL
+#define DX_HOST_IMR_NOT_USED_MASK_BIT_SIZE 0x1UL
+#define DX_HOST_IMR_DSCRPTR_COMPLETION_MASK_BIT_SHIFT 0x2UL
+#define DX_HOST_IMR_DSCRPTR_COMPLETION_MASK_BIT_SIZE 0x1UL
+#define DX_HOST_IMR_AXI_ERR_MASK_BIT_SHIFT 0x8UL
+#define DX_HOST_IMR_AXI_ERR_MASK_BIT_SIZE 0x1UL
+#define DX_HOST_IMR_GPR0_BIT_SHIFT 0xBUL
+#define DX_HOST_IMR_GPR0_BIT_SIZE 0x1UL
+#define DX_HOST_IMR_DSCRPTR_WATERMARK_MASK0_BIT_SHIFT 0x13UL
+#define DX_HOST_IMR_DSCRPTR_WATERMARK_MASK0_BIT_SIZE 0x1UL
+#define DX_HOST_IMR_AXIM_COMP_INT_MASK_BIT_SHIFT 0x17UL
+#define DX_HOST_IMR_AXIM_COMP_INT_MASK_BIT_SIZE 0x1UL
+#define DX_HOST_ICR_REG_OFFSET 0xA08UL
+#define DX_HOST_ICR_DSCRPTR_COMPLETION_BIT_SHIFT 0x2UL
+#define DX_HOST_ICR_DSCRPTR_COMPLETION_BIT_SIZE 0x1UL
+#define DX_HOST_ICR_AXI_ERR_CLEAR_BIT_SHIFT 0x8UL
+#define DX_HOST_ICR_AXI_ERR_CLEAR_BIT_SIZE 0x1UL
+#define DX_HOST_ICR_GPR_INT_CLEAR_BIT_SHIFT 0xBUL
+#define DX_HOST_ICR_GPR_INT_CLEAR_BIT_SIZE 0x1UL
+#define DX_HOST_ICR_DSCRPTR_WATERMARK_QUEUE0_CLEAR_BIT_SHIFT 0x13UL
+#define DX_HOST_ICR_DSCRPTR_WATERMARK_QUEUE0_CLEAR_BIT_SIZE 0x1UL
+#define DX_HOST_ICR_AXIM_COMP_INT_CLEAR_BIT_SHIFT 0x17UL
+#define DX_HOST_ICR_AXIM_COMP_INT_CLEAR_BIT_SIZE 0x1UL
+#define DX_HOST_SIGNATURE_REG_OFFSET 0xA24UL
+#define DX_HOST_SIGNATURE_VALUE_BIT_SHIFT 0x0UL
+#define DX_HOST_SIGNATURE_VALUE_BIT_SIZE 0x20UL
+#define DX_HOST_BOOT_REG_OFFSET 0xA28UL
+#define DX_HOST_BOOT_SYNTHESIS_CONFIG_BIT_SHIFT 0x0UL
+#define DX_HOST_BOOT_SYNTHESIS_CONFIG_BIT_SIZE 0x1UL
+#define DX_HOST_BOOT_LARGE_RKEK_LOCAL_BIT_SHIFT 0x1UL
+#define DX_HOST_BOOT_LARGE_RKEK_LOCAL_BIT_SIZE 0x1UL
+#define DX_HOST_BOOT_HASH_IN_FUSES_LOCAL_BIT_SHIFT 0x2UL
+#define DX_HOST_BOOT_HASH_IN_FUSES_LOCAL_BIT_SIZE 0x1UL
+#define DX_HOST_BOOT_EXT_MEM_SECURED_LOCAL_BIT_SHIFT 0x3UL
+#define DX_HOST_BOOT_EXT_MEM_SECURED_LOCAL_BIT_SIZE 0x1UL
+#define DX_HOST_BOOT_RKEK_ECC_EXISTS_LOCAL_N_BIT_SHIFT 0x5UL
+#define DX_HOST_BOOT_RKEK_ECC_EXISTS_LOCAL_N_BIT_SIZE 0x1UL
+#define DX_HOST_BOOT_SRAM_SIZE_LOCAL_BIT_SHIFT 0x6UL
+#define DX_HOST_BOOT_SRAM_SIZE_LOCAL_BIT_SIZE 0x3UL
+#define DX_HOST_BOOT_DSCRPTR_EXISTS_LOCAL_BIT_SHIFT 0x9UL
+#define DX_HOST_BOOT_DSCRPTR_EXISTS_LOCAL_BIT_SIZE 0x1UL
+#define DX_HOST_BOOT_PAU_EXISTS_LOCAL_BIT_SHIFT 0xAUL
+#define DX_HOST_BOOT_PAU_EXISTS_LOCAL_BIT_SIZE 0x1UL
+#define DX_HOST_BOOT_RNG_EXISTS_LOCAL_BIT_SHIFT 0xBUL
+#define DX_HOST_BOOT_RNG_EXISTS_LOCAL_BIT_SIZE 0x1UL
+#define DX_HOST_BOOT_PKA_EXISTS_LOCAL_BIT_SHIFT 0xCUL
+#define DX_HOST_BOOT_PKA_EXISTS_LOCAL_BIT_SIZE 0x1UL
+#define DX_HOST_BOOT_RC4_EXISTS_LOCAL_BIT_SHIFT 0xDUL
+#define DX_HOST_BOOT_RC4_EXISTS_LOCAL_BIT_SIZE 0x1UL
+#define DX_HOST_BOOT_SHA_512_PRSNT_LOCAL_BIT_SHIFT 0xEUL
+#define DX_HOST_BOOT_SHA_512_PRSNT_LOCAL_BIT_SIZE 0x1UL
+#define DX_HOST_BOOT_SHA_256_PRSNT_LOCAL_BIT_SHIFT 0xFUL
+#define DX_HOST_BOOT_SHA_256_PRSNT_LOCAL_BIT_SIZE 0x1UL
+#define DX_HOST_BOOT_MD5_PRSNT_LOCAL_BIT_SHIFT 0x10UL
+#define DX_HOST_BOOT_MD5_PRSNT_LOCAL_BIT_SIZE 0x1UL
+#define DX_HOST_BOOT_HASH_EXISTS_LOCAL_BIT_SHIFT 0x11UL
+#define DX_HOST_BOOT_HASH_EXISTS_LOCAL_BIT_SIZE 0x1UL
+#define DX_HOST_BOOT_C2_EXISTS_LOCAL_BIT_SHIFT 0x12UL
+#define DX_HOST_BOOT_C2_EXISTS_LOCAL_BIT_SIZE 0x1UL
+#define DX_HOST_BOOT_DES_EXISTS_LOCAL_BIT_SHIFT 0x13UL
+#define DX_HOST_BOOT_DES_EXISTS_LOCAL_BIT_SIZE 0x1UL
+#define DX_HOST_BOOT_AES_XCBC_MAC_EXISTS_LOCAL_BIT_SHIFT 0x14UL
+#define DX_HOST_BOOT_AES_XCBC_MAC_EXISTS_LOCAL_BIT_SIZE 0x1UL
+#define DX_HOST_BOOT_AES_CMAC_EXISTS_LOCAL_BIT_SHIFT 0x15UL
+#define DX_HOST_BOOT_AES_CMAC_EXISTS_LOCAL_BIT_SIZE 0x1UL
+#define DX_HOST_BOOT_AES_CCM_EXISTS_LOCAL_BIT_SHIFT 0x16UL
+#define DX_HOST_BOOT_AES_CCM_EXISTS_LOCAL_BIT_SIZE 0x1UL
+#define DX_HOST_BOOT_AES_XEX_HW_T_CALC_LOCAL_BIT_SHIFT 0x17UL
+#define DX_HOST_BOOT_AES_XEX_HW_T_CALC_LOCAL_BIT_SIZE 0x1UL
+#define DX_HOST_BOOT_AES_XEX_EXISTS_LOCAL_BIT_SHIFT 0x18UL
+#define DX_HOST_BOOT_AES_XEX_EXISTS_LOCAL_BIT_SIZE 0x1UL
+#define DX_HOST_BOOT_CTR_EXISTS_LOCAL_BIT_SHIFT 0x19UL
+#define DX_HOST_BOOT_CTR_EXISTS_LOCAL_BIT_SIZE 0x1UL
+#define DX_HOST_BOOT_AES_DIN_BYTE_RESOLUTION_LOCAL_BIT_SHIFT 0x1AUL
+#define DX_HOST_BOOT_AES_DIN_BYTE_RESOLUTION_LOCAL_BIT_SIZE 0x1UL
+#define DX_HOST_BOOT_TUNNELING_ENB_LOCAL_BIT_SHIFT 0x1BUL
+#define DX_HOST_BOOT_TUNNELING_ENB_LOCAL_BIT_SIZE 0x1UL
+#define DX_HOST_BOOT_SUPPORT_256_192_KEY_LOCAL_BIT_SHIFT 0x1CUL
+#define DX_HOST_BOOT_SUPPORT_256_192_KEY_LOCAL_BIT_SIZE 0x1UL
+#define DX_HOST_BOOT_ONLY_ENCRYPT_LOCAL_BIT_SHIFT 0x1DUL
+#define DX_HOST_BOOT_ONLY_ENCRYPT_LOCAL_BIT_SIZE 0x1UL
+#define DX_HOST_BOOT_AES_EXISTS_LOCAL_BIT_SHIFT 0x1EUL
+#define DX_HOST_BOOT_AES_EXISTS_LOCAL_BIT_SIZE 0x1UL
+#define DX_HOST_VERSION_REG_OFFSET 0xA40UL
+#define DX_HOST_VERSION_VALUE_BIT_SHIFT 0x0UL
+#define DX_HOST_VERSION_VALUE_BIT_SIZE 0x20UL
+#define DX_HOST_KFDE0_VALID_REG_OFFSET 0xA60UL
+#define DX_HOST_KFDE0_VALID_VALUE_BIT_SHIFT 0x0UL
+#define DX_HOST_KFDE0_VALID_VALUE_BIT_SIZE 0x1UL
+#define DX_HOST_KFDE1_VALID_REG_OFFSET 0xA64UL
+#define DX_HOST_KFDE1_VALID_VALUE_BIT_SHIFT 0x0UL
+#define DX_HOST_KFDE1_VALID_VALUE_BIT_SIZE 0x1UL
+#define DX_HOST_KFDE2_VALID_REG_OFFSET 0xA68UL
+#define DX_HOST_KFDE2_VALID_VALUE_BIT_SHIFT 0x0UL
+#define DX_HOST_KFDE2_VALID_VALUE_BIT_SIZE 0x1UL
+#define DX_HOST_KFDE3_VALID_REG_OFFSET 0xA6CUL
+#define DX_HOST_KFDE3_VALID_VALUE_BIT_SHIFT 0x0UL
+#define DX_HOST_KFDE3_VALID_VALUE_BIT_SIZE 0x1UL
+#define DX_HOST_GPR0_REG_OFFSET 0xA70UL
+#define DX_HOST_GPR0_VALUE_BIT_SHIFT 0x0UL
+#define DX_HOST_GPR0_VALUE_BIT_SIZE 0x20UL
+#define DX_GPR_HOST_REG_OFFSET 0xA74UL
+#define DX_GPR_HOST_VALUE_BIT_SHIFT 0x0UL
+#define DX_GPR_HOST_VALUE_BIT_SIZE 0x20UL
+#define DX_HOST_POWER_DOWN_EN_REG_OFFSET 0xA78UL
+#define DX_HOST_POWER_DOWN_EN_VALUE_BIT_SHIFT 0x0UL
+#define DX_HOST_POWER_DOWN_EN_VALUE_BIT_SIZE 0x1UL
+// --------------------------------------
+// BLOCK: HOST_SRAM
+// --------------------------------------
+#define DX_SRAM_DATA_REG_OFFSET 0xF00UL
+#define DX_SRAM_DATA_VALUE_BIT_SHIFT 0x0UL
+#define DX_SRAM_DATA_VALUE_BIT_SIZE 0x20UL
+#define DX_SRAM_ADDR_REG_OFFSET 0xF04UL
+#define DX_SRAM_ADDR_VALUE_BIT_SHIFT 0x0UL
+#define DX_SRAM_ADDR_VALUE_BIT_SIZE 0xFUL
+#define DX_SRAM_DATA_READY_REG_OFFSET 0xF08UL
+#define DX_SRAM_DATA_READY_VALUE_BIT_SHIFT 0x0UL
+#define DX_SRAM_DATA_READY_VALUE_BIT_SIZE 0x1UL
+
+#endif //__DX_HOST_H__
diff --git a/drivers/staging/ccree/dx_reg_base_host.h b/drivers/staging/ccree/dx_reg_base_host.h
new file mode 100644
index 0000000..58dafe0
--- /dev/null
+++ b/drivers/staging/ccree/dx_reg_base_host.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2012-2017 ARM Limited or its affiliates.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __DX_REG_BASE_HOST_H__
+#define __DX_REG_BASE_HOST_H__
+
+/* Identify platform: Xilinx Zynq7000 ZC706 */
+#define DX_PLAT_ZYNQ7000 1
+#define DX_PLAT_ZYNQ7000_ZC706 1
+
+#define DX_BASE_CC 0x80000000
+
+#define DX_BASE_ENV_REGS 0x40008000
+#define DX_BASE_ENV_CC_MEMORIES 0x40008000
+#define DX_BASE_ENV_PERF_RAM 0x40009000
+
+#define DX_BASE_HOST_RGF 0x0UL
+#define DX_BASE_CRY_KERNEL 0x0UL
+#define DX_BASE_ROM 0x40000000
+
+#endif /*__DX_REG_BASE_HOST_H__*/
diff --git a/drivers/staging/ccree/dx_reg_common.h b/drivers/staging/ccree/dx_reg_common.h
new file mode 100644
index 0000000..4ffed38
--- /dev/null
+++ b/drivers/staging/ccree/dx_reg_common.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2012-2017 ARM Limited or its affiliates.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __DX_REG_COMMON_H__
+#define __DX_REG_COMMON_H__
+
+#define DX_DEV_SIGNATURE 0xDCC71200UL
+
+#define CC_HW_VERSION 0xef840015UL
+
+#define DX_DEV_SHA_MAX 512
+
+#endif /*__DX_REG_COMMON_H__*/
diff --git a/drivers/staging/ccree/hash_defs.h b/drivers/staging/ccree/hash_defs.h
new file mode 100644
index 0000000..5ab0861
--- /dev/null
+++ b/drivers/staging/ccree/hash_defs.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2012-2017 ARM Limited or its affiliates.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _HASH_DEFS_H__
+#define _HASH_DEFS_H__
+
+#include "cc_crypto_ctx.h"
+
+/* this files provides definitions required for hash engine drivers */
+#ifndef CC_CONFIG_HASH_SHA_512_SUPPORTED
+#define SEP_HASH_LENGTH_WORDS 2
+#else
+#define SEP_HASH_LENGTH_WORDS 4
+#endif
+
+#ifdef BIG__ENDIAN
+#define OPAD_CURRENT_LENGTH 0x40000000, 0x00000000 , 0x00000000, 0x00000000
+#define HASH_LARVAL_MD5 0x76543210, 0xFEDCBA98, 0x89ABCDEF, 0x01234567
+#define HASH_LARVAL_SHA1 0xF0E1D2C3, 0x76543210, 0xFEDCBA98, 0x89ABCDEF, 0x01234567
+#define HASH_LARVAL_SHA224 0XA44FFABE, 0XA78FF964, 0X11155868, 0X310BC0FF, 0X39590EF7, 0X17DD7030, 0X07D57C36, 0XD89E05C1
+#define HASH_LARVAL_SHA256 0X19CDE05B, 0XABD9831F, 0X8C68059B, 0X7F520E51, 0X3AF54FA5, 0X72F36E3C, 0X85AE67BB, 0X67E6096A
+#define HASH_LARVAL_SHA384 0X1D48B547, 0XA44FFABE, 0X0D2E0CDB, 0XA78FF964, 0X874AB48E, 0X11155868, 0X67263367, 0X310BC0FF, 0XD8EC2F15, 0X39590EF7, 0X5A015991, 0X17DD7030, 0X2A299A62, 0X07D57C36, 0X5D9DBBCB, 0XD89E05C1
+#define HASH_LARVAL_SHA512 0X19CDE05B, 0X79217E13, 0XABD9831F, 0X6BBD41FB, 0X8C68059B, 0X1F6C3E2B, 0X7F520E51, 0XD182E6AD, 0X3AF54FA5, 0XF1361D5F, 0X72F36E3C, 0X2BF894FE, 0X85AE67BB, 0X3BA7CA84, 0X67E6096A, 0X08C9BCF3
+#else
+#define OPAD_CURRENT_LENGTH 0x00000040, 0x00000000, 0x00000000, 0x00000000
+#define HASH_LARVAL_MD5 0x10325476, 0x98BADCFE, 0xEFCDAB89, 0x67452301
+#define HASH_LARVAL_SHA1 0xC3D2E1F0, 0x10325476, 0x98BADCFE, 0xEFCDAB89, 0x67452301
+#define HASH_LARVAL_SHA224 0xbefa4fa4, 0x64f98fa7, 0x68581511, 0xffc00b31, 0xf70e5939, 0x3070dd17, 0x367cd507, 0xc1059ed8
+#define HASH_LARVAL_SHA256 0x5be0cd19, 0x1f83d9ab, 0x9b05688c, 0x510e527f, 0xa54ff53a, 0x3c6ef372, 0xbb67ae85, 0x6a09e667
+#define HASH_LARVAL_SHA384 0X47B5481D, 0XBEFA4FA4, 0XDB0C2E0D, 0X64F98FA7, 0X8EB44A87, 0X68581511, 0X67332667, 0XFFC00B31, 0X152FECD8, 0XF70E5939, 0X9159015A, 0X3070DD17, 0X629A292A, 0X367CD507, 0XCBBB9D5D, 0XC1059ED8
+#define HASH_LARVAL_SHA512 0x5be0cd19, 0x137e2179, 0x1f83d9ab, 0xfb41bd6b, 0x9b05688c, 0x2b3e6c1f, 0x510e527f, 0xade682d1, 0xa54ff53a, 0x5f1d36f1, 0x3c6ef372, 0xfe94f82b, 0xbb67ae85, 0x84caa73b, 0x6a09e667, 0xf3bcc908
+#endif
+
+enum HashConfig1Padding {
+ HASH_PADDING_DISABLED = 0,
+ HASH_PADDING_ENABLED = 1,
+ HASH_DIGEST_RESULT_LITTLE_ENDIAN = 2,
+ HASH_CONFIG1_PADDING_RESERVE32 = INT32_MAX,
+};
+
+enum HashCipherDoPadding {
+ DO_NOT_PAD = 0,
+ DO_PAD = 1,
+ HASH_CIPHER_DO_PADDING_RESERVE32 = INT32_MAX,
+};
+
+typedef struct SepHashPrivateContext {
+ /* The current length is placed at the end of the context buffer because the hash
+ context is used for all HMAC operations as well. HMAC context includes a 64 bytes
+ K0 field. The size of struct drv_ctx_hash reserved field is 88/184 bytes depend if t
+ he SHA512 is supported ( in this case teh context size is 256 bytes).
+ The size of struct drv_ctx_hash reseved field is 20 or 52 depend if the SHA512 is supported.
+ This means that this structure size (without the reserved field can be up to 20 bytes ,
+ in case sha512 is not suppported it is 20 bytes (SEP_HASH_LENGTH_WORDS define to 2 ) and in the other
+ case it is 28 (SEP_HASH_LENGTH_WORDS define to 4) */
+ uint32_t reserved[(sizeof(struct drv_ctx_hash)/sizeof(uint32_t)) - SEP_HASH_LENGTH_WORDS - 3];
+ uint32_t CurrentDigestedLength[SEP_HASH_LENGTH_WORDS];
+ uint32_t KeyType;
+ uint32_t dataCompleted;
+ uint32_t hmacFinalization;
+ /* no space left */
+} SepHashPrivateContext_s;
+
+#endif /*_HASH_DEFS_H__*/
+
diff --git a/drivers/staging/ccree/hw_queue_defs_plat.h b/drivers/staging/ccree/hw_queue_defs_plat.h
new file mode 100644
index 0000000..aee02cc
--- /dev/null
+++ b/drivers/staging/ccree/hw_queue_defs_plat.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2012-2017 ARM Limited or its affiliates.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __HW_QUEUE_DEFS_PLAT_H__
+#define __HW_QUEUE_DEFS_PLAT_H__
+
+
+/*****************************/
+/* Descriptor packing macros */
+/*****************************/
+
+#define HW_QUEUE_FREE_SLOTS_GET() (CC_HAL_READ_REGISTER(CC_REG_OFFSET(CRY_KERNEL, DSCRPTR_QUEUE_CONTENT)) & HW_QUEUE_SLOTS_MAX)
+
+#define HW_QUEUE_POLL_QUEUE_UNTIL_FREE_SLOTS(seqLen) \
+ do { \
+ } while (HW_QUEUE_FREE_SLOTS_GET() < (seqLen))
+
+#define HW_DESC_PUSH_TO_QUEUE(pDesc) do { \
+ LOG_HW_DESC(pDesc); \
+ HW_DESC_DUMP(pDesc); \
+ CC_HAL_WRITE_REGISTER(GET_HW_Q_DESC_WORD_IDX(0), (pDesc)->word[0]); \
+ CC_HAL_WRITE_REGISTER(GET_HW_Q_DESC_WORD_IDX(1), (pDesc)->word[1]); \
+ CC_HAL_WRITE_REGISTER(GET_HW_Q_DESC_WORD_IDX(2), (pDesc)->word[2]); \
+ CC_HAL_WRITE_REGISTER(GET_HW_Q_DESC_WORD_IDX(3), (pDesc)->word[3]); \
+ CC_HAL_WRITE_REGISTER(GET_HW_Q_DESC_WORD_IDX(4), (pDesc)->word[4]); \
+ wmb(); \
+ CC_HAL_WRITE_REGISTER(GET_HW_Q_DESC_WORD_IDX(5), (pDesc)->word[5]); \
+} while (0)
+
+#endif /*__HW_QUEUE_DEFS_PLAT_H__*/
diff --git a/drivers/staging/ccree/ssi_aead.c b/drivers/staging/ccree/ssi_aead.c
new file mode 100644
index 0000000..0382917
--- /dev/null
+++ b/drivers/staging/ccree/ssi_aead.c
@@ -0,0 +1,2832 @@
+/*
+ * Copyright (C) 2012-2017 ARM Limited or its affiliates.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <crypto/algapi.h>
+#include <crypto/internal/skcipher.h>
+#include <crypto/internal/hash.h>
+#include <crypto/internal/aead.h>
+#include <crypto/sha.h>
+#include <crypto/ctr.h>
+#include <crypto/authenc.h>
+#include <crypto/aes.h>
+#include <crypto/des.h>
+#include <linux/rtnetlink.h>
+#include <linux/version.h>
+#include "ssi_config.h"
+#include "ssi_driver.h"
+#include "ssi_buffer_mgr.h"
+#include "ssi_aead.h"
+#include "ssi_request_mgr.h"
+#include "ssi_hash.h"
+#include "ssi_sysfs.h"
+#include "ssi_sram_mgr.h"
+#include "ssi_fips_local.h"
+
+#define template_aead template_u.aead
+
+#define MAX_AEAD_SETKEY_SEQ 12
+#define MAX_AEAD_PROCESS_SEQ 23
+
+#define MAX_HMAC_DIGEST_SIZE (SHA256_DIGEST_SIZE)
+#define MAX_HMAC_BLOCK_SIZE (SHA256_BLOCK_SIZE)
+
+#define AES_CCM_RFC4309_NONCE_SIZE 3
+#define MAX_NONCE_SIZE CTR_RFC3686_NONCE_SIZE
+
+
+/* Value of each ICV_CMP byte (of 8) in case of success */
+#define ICV_VERIF_OK 0x01
+
+struct ssi_aead_handle {
+ ssi_sram_addr_t sram_workspace_addr;
+ struct list_head aead_list;
+};
+
+struct ssi_aead_ctx {
+ struct ssi_drvdata *drvdata;
+ uint8_t ctr_nonce[MAX_NONCE_SIZE]; /* used for ctr3686 iv and aes ccm */
+ uint8_t *enckey;
+ dma_addr_t enckey_dma_addr;
+ union {
+ struct {
+ uint8_t *padded_authkey;
+ uint8_t *ipad_opad; /* IPAD, OPAD*/
+ dma_addr_t padded_authkey_dma_addr;
+ dma_addr_t ipad_opad_dma_addr;
+ } hmac;
+ struct {
+ uint8_t *xcbc_keys; /* K1,K2,K3 */
+ dma_addr_t xcbc_keys_dma_addr;
+ } xcbc;
+ } auth_state;
+ unsigned int enc_keylen;
+ unsigned int auth_keylen;
+ unsigned int authsize; /* Actual (reduced?) size of the MAC/ICv */
+ enum drv_cipher_mode cipher_mode;
+ enum FlowMode flow_mode;
+ enum drv_hash_mode auth_mode;
+};
+
+static inline bool valid_assoclen(struct aead_request *req)
+{
+ return ((req->assoclen == 16) || (req->assoclen == 20));
+}
+
+static void ssi_aead_exit(struct crypto_aead *tfm)
+{
+ struct device *dev = NULL;
+ struct ssi_aead_ctx *ctx = crypto_aead_ctx(tfm);
+
+ SSI_LOG_DEBUG("Clearing context @%p for %s\n",
+ crypto_aead_ctx(tfm), crypto_tfm_alg_name(&(tfm->base)));
+
+ dev = &ctx->drvdata->plat_dev->dev;
+ /* Unmap enckey buffer */
+ if (ctx->enckey != NULL) {
+ SSI_RESTORE_DMA_ADDR_TO_48BIT(ctx->enckey_dma_addr);
+ dma_free_coherent(dev, AES_MAX_KEY_SIZE, ctx->enckey, ctx->enckey_dma_addr);
+ SSI_LOG_DEBUG("Freed enckey DMA buffer enckey_dma_addr=0x%llX\n",
+ (unsigned long long)ctx->enckey_dma_addr);
+ ctx->enckey_dma_addr = 0;
+ ctx->enckey = NULL;
+ }
+
+ if (ctx->auth_mode == DRV_HASH_XCBC_MAC) { /* XCBC authetication */
+ if (ctx->auth_state.xcbc.xcbc_keys != NULL) {
+ SSI_RESTORE_DMA_ADDR_TO_48BIT(
+ ctx->auth_state.xcbc.xcbc_keys_dma_addr);
+ dma_free_coherent(dev, CC_AES_128_BIT_KEY_SIZE * 3,
+ ctx->auth_state.xcbc.xcbc_keys,
+ ctx->auth_state.xcbc.xcbc_keys_dma_addr);
+ }
+ SSI_LOG_DEBUG("Freed xcbc_keys DMA buffer xcbc_keys_dma_addr=0x%llX\n",
+ (unsigned long long)ctx->auth_state.xcbc.xcbc_keys_dma_addr);
+ ctx->auth_state.xcbc.xcbc_keys_dma_addr = 0;
+ ctx->auth_state.xcbc.xcbc_keys = NULL;
+ } else if (ctx->auth_mode != DRV_HASH_NULL) { /* HMAC auth. */
+ if (ctx->auth_state.hmac.ipad_opad != NULL) {
+ SSI_RESTORE_DMA_ADDR_TO_48BIT(
+ ctx->auth_state.hmac.ipad_opad_dma_addr);
+ dma_free_coherent(dev, 2 * MAX_HMAC_DIGEST_SIZE,
+ ctx->auth_state.hmac.ipad_opad,
+ ctx->auth_state.hmac.ipad_opad_dma_addr);
+ SSI_LOG_DEBUG("Freed ipad_opad DMA buffer ipad_opad_dma_addr=0x%llX\n",
+ (unsigned long long)ctx->auth_state.hmac.ipad_opad_dma_addr);
+ ctx->auth_state.hmac.ipad_opad_dma_addr = 0;
+ ctx->auth_state.hmac.ipad_opad = NULL;
+ }
+ if (ctx->auth_state.hmac.padded_authkey != NULL) {
+ SSI_RESTORE_DMA_ADDR_TO_48BIT(
+ ctx->auth_state.hmac.padded_authkey_dma_addr);
+ dma_free_coherent(dev, MAX_HMAC_BLOCK_SIZE,
+ ctx->auth_state.hmac.padded_authkey,
+ ctx->auth_state.hmac.padded_authkey_dma_addr);
+ SSI_LOG_DEBUG("Freed padded_authkey DMA buffer padded_authkey_dma_addr=0x%llX\n",
+ (unsigned long long)ctx->auth_state.hmac.padded_authkey_dma_addr);
+ ctx->auth_state.hmac.padded_authkey_dma_addr = 0;
+ ctx->auth_state.hmac.padded_authkey = NULL;
+ }
+ }
+}
+
+static int ssi_aead_init(struct crypto_aead *tfm)
+{
+ struct device *dev;
+ struct aead_alg *alg = crypto_aead_alg(tfm);
+ struct ssi_aead_ctx *ctx = crypto_aead_ctx(tfm);
+ struct ssi_crypto_alg *ssi_alg =
+ container_of(alg, struct ssi_crypto_alg, aead_alg);
+ SSI_LOG_DEBUG("Initializing context @%p for %s\n", ctx, crypto_tfm_alg_name(&(tfm->base)));
+
+ CHECK_AND_RETURN_UPON_FIPS_ERROR();
+
+ /* Initialize modes in instance */
+ ctx->cipher_mode = ssi_alg->cipher_mode;
+ ctx->flow_mode = ssi_alg->flow_mode;
+ ctx->auth_mode = ssi_alg->auth_mode;
+ ctx->drvdata = ssi_alg->drvdata;
+ dev = &ctx->drvdata->plat_dev->dev;
+ crypto_aead_set_reqsize(tfm,sizeof(struct aead_req_ctx));
+
+ /* Allocate key buffer, cache line aligned */
+ ctx->enckey = dma_alloc_coherent(dev, AES_MAX_KEY_SIZE,
+ &ctx->enckey_dma_addr, GFP_KERNEL);
+ if (ctx->enckey == NULL) {
+ SSI_LOG_ERR("Failed allocating key buffer\n");
+ goto init_failed;
+ }
+ SSI_UPDATE_DMA_ADDR_TO_48BIT(ctx->enckey_dma_addr, AES_MAX_KEY_SIZE);
+ SSI_LOG_DEBUG("Allocated enckey buffer in context ctx->enckey=@%p\n", ctx->enckey);
+
+ /* Set default authlen value */
+
+ if (ctx->auth_mode == DRV_HASH_XCBC_MAC) { /* XCBC authetication */
+ /* Allocate dma-coherent buffer for XCBC's K1+K2+K3 */
+ /* (and temporary for user key - up to 256b) */
+ ctx->auth_state.xcbc.xcbc_keys = dma_alloc_coherent(dev,
+ CC_AES_128_BIT_KEY_SIZE * 3,
+ &ctx->auth_state.xcbc.xcbc_keys_dma_addr, GFP_KERNEL);
+ if (ctx->auth_state.xcbc.xcbc_keys == NULL) {
+ SSI_LOG_ERR("Failed allocating buffer for XCBC keys\n");
+ goto init_failed;
+ }
+ SSI_UPDATE_DMA_ADDR_TO_48BIT(
+ ctx->auth_state.xcbc.xcbc_keys_dma_addr,
+ CC_AES_128_BIT_KEY_SIZE * 3);
+ } else if (ctx->auth_mode != DRV_HASH_NULL) { /* HMAC authentication */
+ /* Allocate dma-coherent buffer for IPAD + OPAD */
+ ctx->auth_state.hmac.ipad_opad = dma_alloc_coherent(dev,
+ 2 * MAX_HMAC_DIGEST_SIZE,
+ &ctx->auth_state.hmac.ipad_opad_dma_addr, GFP_KERNEL);
+ if (ctx->auth_state.hmac.ipad_opad == NULL) {
+ SSI_LOG_ERR("Failed allocating IPAD/OPAD buffer\n");
+ goto init_failed;
+ }
+ SSI_UPDATE_DMA_ADDR_TO_48BIT(
+ ctx->auth_state.hmac.ipad_opad_dma_addr,
+ 2 * MAX_HMAC_DIGEST_SIZE);
+ SSI_LOG_DEBUG("Allocated authkey buffer in context ctx->authkey=@%p\n",
+ ctx->auth_state.hmac.ipad_opad);
+
+ ctx->auth_state.hmac.padded_authkey = dma_alloc_coherent(dev,
+ MAX_HMAC_BLOCK_SIZE,
+ &ctx->auth_state.hmac.padded_authkey_dma_addr, GFP_KERNEL);
+ if (ctx->auth_state.hmac.padded_authkey == NULL) {
+ SSI_LOG_ERR("failed to allocate padded_authkey\n");
+ goto init_failed;
+ }
+ SSI_UPDATE_DMA_ADDR_TO_48BIT(
+ ctx->auth_state.hmac.padded_authkey_dma_addr,
+ MAX_HMAC_BLOCK_SIZE);
+ } else {
+ ctx->auth_state.hmac.ipad_opad = NULL;
+ ctx->auth_state.hmac.padded_authkey = NULL;
+ }
+
+ return 0;
+
+init_failed:
+ ssi_aead_exit(tfm);
+ return -ENOMEM;
+}
+
+
+static void ssi_aead_complete(struct device *dev, void *ssi_req, void __iomem *cc_base)
+{
+ struct aead_request *areq = (struct aead_request *)ssi_req;
+ struct aead_req_ctx *areq_ctx = aead_request_ctx(areq);
+ struct crypto_aead *tfm = crypto_aead_reqtfm(ssi_req);
+ struct ssi_aead_ctx *ctx = crypto_aead_ctx(tfm);
+ int err = 0;
+ DECL_CYCLE_COUNT_RESOURCES;
+
+ START_CYCLE_COUNT();
+
+ ssi_buffer_mgr_unmap_aead_request(dev, areq);
+
+ /* Restore ordinary iv pointer */
+ areq->iv = areq_ctx->backup_iv;
+
+ if (areq_ctx->gen_ctx.op_type == DRV_CRYPTO_DIRECTION_DECRYPT) {
+ if (memcmp(areq_ctx->mac_buf, areq_ctx->icv_virt_addr,
+ ctx->authsize) != 0) {
+ SSI_LOG_DEBUG("Payload authentication failure, "
+ "(auth-size=%d, cipher=%d).\n",
+ ctx->authsize, ctx->cipher_mode);
+ /* In case of payload authentication failure, MUST NOT
+ revealed the decrypted message --> zero its memory. */
+ ssi_buffer_mgr_zero_sgl(areq->dst, areq_ctx->cryptlen);
+ err = -EBADMSG;
+ }
+ } else { /*ENCRYPT*/
+ if (unlikely(areq_ctx->is_icv_fragmented == true))
+ ssi_buffer_mgr_copy_scatterlist_portion(
+ areq_ctx->mac_buf, areq_ctx->dstSgl, areq->cryptlen+areq_ctx->dstOffset,
+ areq->cryptlen+areq_ctx->dstOffset + ctx->authsize, SSI_SG_FROM_BUF);
+
+ /* If an IV was generated, copy it back to the user provided buffer. */
+ if (areq_ctx->backup_giv != NULL) {
+ if (ctx->cipher_mode == DRV_CIPHER_CTR) {
+ memcpy(areq_ctx->backup_giv, areq_ctx->ctr_iv + CTR_RFC3686_NONCE_SIZE, CTR_RFC3686_IV_SIZE);
+ } else if (ctx->cipher_mode == DRV_CIPHER_CCM) {
+ memcpy(areq_ctx->backup_giv, areq_ctx->ctr_iv + CCM_BLOCK_IV_OFFSET, CCM_BLOCK_IV_SIZE);
+ }
+ }
+ }
+
+ END_CYCLE_COUNT(STAT_OP_TYPE_GENERIC, STAT_PHASE_4);
+ aead_request_complete(areq, err);
+}
+
+static int xcbc_setkey(HwDesc_s *desc, struct ssi_aead_ctx *ctx)
+{
+ /* Load the AES key */
+ HW_DESC_INIT(&desc[0]);
+ /* We are using for the source/user key the same buffer as for the output keys,
+ because after this key loading it is not needed anymore */
+ HW_DESC_SET_DIN_TYPE(&desc[0], DMA_DLLI, ctx->auth_state.xcbc.xcbc_keys_dma_addr, ctx->auth_keylen, NS_BIT);
+ HW_DESC_SET_CIPHER_MODE(&desc[0], DRV_CIPHER_ECB);
+ HW_DESC_SET_CIPHER_CONFIG0(&desc[0], DRV_CRYPTO_DIRECTION_ENCRYPT);
+ HW_DESC_SET_KEY_SIZE_AES(&desc[0], ctx->auth_keylen);
+ HW_DESC_SET_FLOW_MODE(&desc[0], S_DIN_to_AES);
+ HW_DESC_SET_SETUP_MODE(&desc[0], SETUP_LOAD_KEY0);
+
+ HW_DESC_INIT(&desc[1]);
+ HW_DESC_SET_DIN_CONST(&desc[1], 0x01010101, CC_AES_128_BIT_KEY_SIZE);
+ HW_DESC_SET_FLOW_MODE(&desc[1], DIN_AES_DOUT);
+ HW_DESC_SET_DOUT_DLLI(&desc[1], ctx->auth_state.xcbc.xcbc_keys_dma_addr, AES_KEYSIZE_128, NS_BIT, 0);
+
+ HW_DESC_INIT(&desc[2]);
+ HW_DESC_SET_DIN_CONST(&desc[2], 0x02020202, CC_AES_128_BIT_KEY_SIZE);
+ HW_DESC_SET_FLOW_MODE(&desc[2], DIN_AES_DOUT);
+ HW_DESC_SET_DOUT_DLLI(&desc[2], (ctx->auth_state.xcbc.xcbc_keys_dma_addr
+ + AES_KEYSIZE_128),
+ AES_KEYSIZE_128, NS_BIT, 0);
+
+ HW_DESC_INIT(&desc[3]);
+ HW_DESC_SET_DIN_CONST(&desc[3], 0x03030303, CC_AES_128_BIT_KEY_SIZE);
+ HW_DESC_SET_FLOW_MODE(&desc[3], DIN_AES_DOUT);
+ HW_DESC_SET_DOUT_DLLI(&desc[3], (ctx->auth_state.xcbc.xcbc_keys_dma_addr
+ + 2 * AES_KEYSIZE_128),
+ AES_KEYSIZE_128, NS_BIT, 0);
+
+ return 4;
+}
+
+static int hmac_setkey(HwDesc_s *desc, struct ssi_aead_ctx *ctx)
+{
+ unsigned int hmacPadConst[2] = { HMAC_IPAD_CONST, HMAC_OPAD_CONST };
+ unsigned int digest_ofs = 0;
+ unsigned int hash_mode = (ctx->auth_mode == DRV_HASH_SHA1) ?
+ DRV_HASH_HW_SHA1 : DRV_HASH_HW_SHA256;
+ unsigned int digest_size = (ctx->auth_mode == DRV_HASH_SHA1) ?
+ CC_SHA1_DIGEST_SIZE : CC_SHA256_DIGEST_SIZE;
+
+ int idx = 0;
+ int i;
+
+ /* calc derived HMAC key */
+ for (i = 0; i < 2; i++) {
+ /* Load hash initial state */
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_CIPHER_MODE(&desc[idx], hash_mode);
+ HW_DESC_SET_DIN_SRAM(&desc[idx],
+ ssi_ahash_get_larval_digest_sram_addr(
+ ctx->drvdata, ctx->auth_mode),
+ digest_size);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], S_DIN_to_HASH);
+ HW_DESC_SET_SETUP_MODE(&desc[idx], SETUP_LOAD_STATE0);
+ idx++;
+
+ /* Load the hash current length*/
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_CIPHER_MODE(&desc[idx], hash_mode);
+ HW_DESC_SET_DIN_CONST(&desc[idx], 0, HASH_LEN_SIZE);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], S_DIN_to_HASH);
+ HW_DESC_SET_SETUP_MODE(&desc[idx], SETUP_LOAD_KEY0);
+ idx++;
+
+ /* Prepare ipad key */
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_XOR_VAL(&desc[idx], hmacPadConst[i]);
+ HW_DESC_SET_CIPHER_MODE(&desc[idx], hash_mode);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], S_DIN_to_HASH);
+ HW_DESC_SET_SETUP_MODE(&desc[idx], SETUP_LOAD_STATE1);
+ idx++;
+
+ /* Perform HASH update */
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_DIN_TYPE(&desc[idx], DMA_DLLI,
+ ctx->auth_state.hmac.padded_authkey_dma_addr,
+ SHA256_BLOCK_SIZE, NS_BIT);
+ HW_DESC_SET_CIPHER_MODE(&desc[idx], hash_mode);
+ HW_DESC_SET_XOR_ACTIVE(&desc[idx]);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], DIN_HASH);
+ idx++;
+
+ /* Get the digset */
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_CIPHER_MODE(&desc[idx], hash_mode);
+ HW_DESC_SET_DOUT_DLLI(&desc[idx],
+ (ctx->auth_state.hmac.ipad_opad_dma_addr +
+ digest_ofs),
+ digest_size, NS_BIT, 0);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], S_HASH_to_DOUT);
+ HW_DESC_SET_SETUP_MODE(&desc[idx], SETUP_WRITE_STATE0);
+ HW_DESC_SET_CIPHER_CONFIG1(&desc[idx], HASH_PADDING_DISABLED);
+ idx++;
+
+ digest_ofs += digest_size;
+ }
+
+ return idx;
+}
+
+static int validate_keys_sizes(struct ssi_aead_ctx *ctx)
+{
+ SSI_LOG_DEBUG("enc_keylen=%u authkeylen=%u\n",
+ ctx->enc_keylen, ctx->auth_keylen);
+
+ switch (ctx->auth_mode) {
+ case DRV_HASH_SHA1:
+ case DRV_HASH_SHA256:
+ break;
+ case DRV_HASH_XCBC_MAC:
+ if ((ctx->auth_keylen != AES_KEYSIZE_128) &&
+ (ctx->auth_keylen != AES_KEYSIZE_192) &&
+ (ctx->auth_keylen != AES_KEYSIZE_256))
+ return -ENOTSUPP;
+ break;
+ case DRV_HASH_NULL: /* Not authenc (e.g., CCM) - no auth_key) */
+ if (ctx->auth_keylen > 0)
+ return -EINVAL;
+ break;
+ default:
+ SSI_LOG_ERR("Invalid auth_mode=%d\n", ctx->auth_mode);
+ return -EINVAL;
+ }
+ /* Check cipher key size */
+ if (unlikely(ctx->flow_mode == S_DIN_to_DES)) {
+ if (ctx->enc_keylen != DES3_EDE_KEY_SIZE) {
+ SSI_LOG_ERR("Invalid cipher(3DES) key size: %u\n",
+ ctx->enc_keylen);
+ return -EINVAL;
+ }
+ } else { /* Default assumed to be AES ciphers */
+ if ((ctx->enc_keylen != AES_KEYSIZE_128) &&
+ (ctx->enc_keylen != AES_KEYSIZE_192) &&
+ (ctx->enc_keylen != AES_KEYSIZE_256)) {
+ SSI_LOG_ERR("Invalid cipher(AES) key size: %u\n",
+ ctx->enc_keylen);
+ return -EINVAL;
+ }
+ }
+
+ return 0; /* All tests of keys sizes passed */
+}
+/*This function prepers the user key so it can pass to the hmac processing
+ (copy to intenral buffer or hash in case of key longer than block */
+static int
+ssi_get_plain_hmac_key(struct crypto_aead *tfm, const u8 *key, unsigned int keylen)
+{
+ dma_addr_t key_dma_addr = 0;
+ struct ssi_aead_ctx *ctx = crypto_aead_ctx(tfm);
+ struct device *dev = &ctx->drvdata->plat_dev->dev;
+ uint32_t larval_addr = ssi_ahash_get_larval_digest_sram_addr(
+ ctx->drvdata, ctx->auth_mode);
+ struct ssi_crypto_req ssi_req = {};
+ unsigned int blocksize;
+ unsigned int digestsize;
+ unsigned int hashmode;
+ unsigned int idx = 0;
+ int rc = 0;
+ HwDesc_s desc[MAX_AEAD_SETKEY_SEQ];
+ dma_addr_t padded_authkey_dma_addr =
+ ctx->auth_state.hmac.padded_authkey_dma_addr;
+
+ switch (ctx->auth_mode) { /* auth_key required and >0 */
+ case DRV_HASH_SHA1:
+ blocksize = SHA1_BLOCK_SIZE;
+ digestsize = SHA1_DIGEST_SIZE;
+ hashmode = DRV_HASH_HW_SHA1;
+ break;
+ case DRV_HASH_SHA256:
+ default:
+ blocksize = SHA256_BLOCK_SIZE;
+ digestsize = SHA256_DIGEST_SIZE;
+ hashmode = DRV_HASH_HW_SHA256;
+ }
+
+ if (likely(keylen != 0)) {
+ key_dma_addr = dma_map_single(dev, (void *)key, keylen, DMA_TO_DEVICE);
+ if (unlikely(dma_mapping_error(dev, key_dma_addr))) {
+ SSI_LOG_ERR("Mapping key va=0x%p len=%u for"
+ " DMA failed\n", key, keylen);
+ return -ENOMEM;
+ }
+ SSI_UPDATE_DMA_ADDR_TO_48BIT(key_dma_addr, keylen);
+ if (keylen > blocksize) {
+ /* Load hash initial state */
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_CIPHER_MODE(&desc[idx], hashmode);
+ HW_DESC_SET_DIN_SRAM(&desc[idx], larval_addr, digestsize);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], S_DIN_to_HASH);
+ HW_DESC_SET_SETUP_MODE(&desc[idx], SETUP_LOAD_STATE0);
+ idx++;
+
+ /* Load the hash current length*/
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_CIPHER_MODE(&desc[idx], hashmode);
+ HW_DESC_SET_DIN_CONST(&desc[idx], 0, HASH_LEN_SIZE);
+ HW_DESC_SET_CIPHER_CONFIG1(&desc[idx], HASH_PADDING_ENABLED);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], S_DIN_to_HASH);
+ HW_DESC_SET_SETUP_MODE(&desc[idx], SETUP_LOAD_KEY0);
+ idx++;
+
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_DIN_TYPE(&desc[idx], DMA_DLLI,
+ key_dma_addr,
+ keylen, NS_BIT);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], DIN_HASH);
+ idx++;
+
+ /* Get hashed key */
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_CIPHER_MODE(&desc[idx], hashmode);
+ HW_DESC_SET_DOUT_DLLI(&desc[idx],
+ padded_authkey_dma_addr,
+ digestsize,
+ NS_BIT, 0);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], S_HASH_to_DOUT);
+ HW_DESC_SET_SETUP_MODE(&desc[idx], SETUP_WRITE_STATE0);
+ HW_DESC_SET_CIPHER_CONFIG1(&desc[idx],
+ HASH_PADDING_DISABLED);
+ HW_DESC_SET_CIPHER_CONFIG0(&desc[idx],
+ HASH_DIGEST_RESULT_LITTLE_ENDIAN);
+ idx++;
+
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_DIN_CONST(&desc[idx], 0, (blocksize - digestsize));
+ HW_DESC_SET_FLOW_MODE(&desc[idx], BYPASS);
+ HW_DESC_SET_DOUT_DLLI(&desc[idx],
+ (padded_authkey_dma_addr + digestsize),
+ (blocksize - digestsize),
+ NS_BIT, 0);
+ idx++;
+ } else {
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_DIN_TYPE(&desc[idx], DMA_DLLI,
+ key_dma_addr,
+ keylen, NS_BIT);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], BYPASS);
+ HW_DESC_SET_DOUT_DLLI(&desc[idx],
+ (padded_authkey_dma_addr),
+ keylen, NS_BIT, 0);
+ idx++;
+
+ if ((blocksize - keylen) != 0) {
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_DIN_CONST(&desc[idx], 0,
+ (blocksize - keylen));
+ HW_DESC_SET_FLOW_MODE(&desc[idx], BYPASS);
+ HW_DESC_SET_DOUT_DLLI(&desc[idx],
+ (padded_authkey_dma_addr + keylen),
+ (blocksize - keylen),
+ NS_BIT, 0);
+ idx++;
+ }
+ }
+ } else {
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_DIN_CONST(&desc[idx], 0,
+ (blocksize - keylen));
+ HW_DESC_SET_FLOW_MODE(&desc[idx], BYPASS);
+ HW_DESC_SET_DOUT_DLLI(&desc[idx],
+ padded_authkey_dma_addr,
+ blocksize,
+ NS_BIT, 0);
+ idx++;
+ }
+
+#ifdef ENABLE_CYCLE_COUNT
+ ssi_req.op_type = STAT_OP_TYPE_SETKEY;
+#endif
+
+ rc = send_request(ctx->drvdata, &ssi_req, desc, idx, 0);
+ if (unlikely(rc != 0))
+ SSI_LOG_ERR("send_request() failed (rc=%d)\n", rc);
+
+ if (likely(key_dma_addr != 0)) {
+ SSI_RESTORE_DMA_ADDR_TO_48BIT(key_dma_addr);
+ dma_unmap_single(dev, key_dma_addr, keylen, DMA_TO_DEVICE);
+ }
+
+ return rc;
+}
+
+
+static int
+ssi_aead_setkey(struct crypto_aead *tfm, const u8 *key, unsigned int keylen)
+{
+ struct ssi_aead_ctx *ctx = crypto_aead_ctx(tfm);
+ struct rtattr *rta = (struct rtattr *)key;
+ struct ssi_crypto_req ssi_req = {};
+ struct crypto_authenc_key_param *param;
+ HwDesc_s desc[MAX_AEAD_SETKEY_SEQ];
+ int seq_len = 0, rc = -EINVAL;
+ DECL_CYCLE_COUNT_RESOURCES;
+
+ SSI_LOG_DEBUG("Setting key in context @%p for %s. key=%p keylen=%u\n",
+ ctx, crypto_tfm_alg_name(crypto_aead_tfm(tfm)), key, keylen);
+
+ CHECK_AND_RETURN_UPON_FIPS_ERROR();
+ /* STAT_PHASE_0: Init and sanity checks */
+ START_CYCLE_COUNT();
+
+ if (ctx->auth_mode != DRV_HASH_NULL) { /* authenc() alg. */
+ if (!RTA_OK(rta, keylen))
+ goto badkey;
+ if (rta->rta_type != CRYPTO_AUTHENC_KEYA_PARAM)
+ goto badkey;
+ if (RTA_PAYLOAD(rta) < sizeof(*param))
+ goto badkey;
+ param = RTA_DATA(rta);
+ ctx->enc_keylen = be32_to_cpu(param->enckeylen);
+ key += RTA_ALIGN(rta->rta_len);
+ keylen -= RTA_ALIGN(rta->rta_len);
+ if (keylen < ctx->enc_keylen)
+ goto badkey;
+ ctx->auth_keylen = keylen - ctx->enc_keylen;
+
+ if (ctx->cipher_mode == DRV_CIPHER_CTR) {
+ /* the nonce is stored in bytes at end of key */
+ if (ctx->enc_keylen <
+ (AES_MIN_KEY_SIZE + CTR_RFC3686_NONCE_SIZE))
+ goto badkey;
+ /* Copy nonce from last 4 bytes in CTR key to
+ * first 4 bytes in CTR IV */
+ memcpy(ctx->ctr_nonce, key + ctx->auth_keylen + ctx->enc_keylen -
+ CTR_RFC3686_NONCE_SIZE, CTR_RFC3686_NONCE_SIZE);
+ /* Set CTR key size */
+ ctx->enc_keylen -= CTR_RFC3686_NONCE_SIZE;
+ }
+ } else { /* non-authenc - has just one key */
+ ctx->enc_keylen = keylen;
+ ctx->auth_keylen = 0;
+ }
+
+ rc = validate_keys_sizes(ctx);
+ if (unlikely(rc != 0))
+ goto badkey;
+
+ END_CYCLE_COUNT(STAT_OP_TYPE_SETKEY, STAT_PHASE_0);
+ /* STAT_PHASE_1: Copy key to ctx */
+ START_CYCLE_COUNT();
+
+ /* Get key material */
+ memcpy(ctx->enckey, key + ctx->auth_keylen, ctx->enc_keylen);
+ if (ctx->enc_keylen == 24)
+ memset(ctx->enckey + 24, 0, CC_AES_KEY_SIZE_MAX - 24);
+ if (ctx->auth_mode == DRV_HASH_XCBC_MAC) {
+ memcpy(ctx->auth_state.xcbc.xcbc_keys, key, ctx->auth_keylen);
+ } else if (ctx->auth_mode != DRV_HASH_NULL) { /* HMAC */
+ rc = ssi_get_plain_hmac_key(tfm, key, ctx->auth_keylen);
+ if (rc != 0)
+ goto badkey;
+ }
+
+ END_CYCLE_COUNT(STAT_OP_TYPE_SETKEY, STAT_PHASE_1);
+
+ /* STAT_PHASE_2: Create sequence */
+ START_CYCLE_COUNT();
+
+ switch (ctx->auth_mode) {
+ case DRV_HASH_SHA1:
+ case DRV_HASH_SHA256:
+ seq_len = hmac_setkey(desc, ctx);
+ break;
+ case DRV_HASH_XCBC_MAC:
+ seq_len = xcbc_setkey(desc, ctx);
+ break;
+ case DRV_HASH_NULL: /* non-authenc modes, e.g., CCM */
+ break; /* No auth. key setup */
+ default:
+ SSI_LOG_ERR("Unsupported authenc (%d)\n", ctx->auth_mode);
+ rc = -ENOTSUPP;
+ goto badkey;
+ }
+
+ END_CYCLE_COUNT(STAT_OP_TYPE_SETKEY, STAT_PHASE_2);
+
+ /* STAT_PHASE_3: Submit sequence to HW */
+ START_CYCLE_COUNT();
+
+ if (seq_len > 0) { /* For CCM there is no sequence to setup the key */
+#ifdef ENABLE_CYCLE_COUNT
+ ssi_req.op_type = STAT_OP_TYPE_SETKEY;
+#endif
+ rc = send_request(ctx->drvdata, &ssi_req, desc, seq_len, 0);
+ if (unlikely(rc != 0)) {
+ SSI_LOG_ERR("send_request() failed (rc=%d)\n", rc);
+ goto setkey_error;
+ }
+ }
+
+ /* Update STAT_PHASE_3 */
+ END_CYCLE_COUNT(STAT_OP_TYPE_SETKEY, STAT_PHASE_3);
+ return rc;
+
+badkey:
+ crypto_aead_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN);
+
+setkey_error:
+ return rc;
+}
+
+#if SSI_CC_HAS_AES_CCM
+static int ssi_rfc4309_ccm_setkey(struct crypto_aead *tfm, const u8 *key, unsigned int keylen)
+{
+ struct ssi_aead_ctx *ctx = crypto_aead_ctx(tfm);
+ int rc = 0;
+
+ if (keylen < 3)
+ return -EINVAL;
+
+ keylen -= 3;
+ memcpy(ctx->ctr_nonce, key + keylen, 3);
+
+ rc = ssi_aead_setkey(tfm, key, keylen);
+
+ return rc;
+}
+#endif /*SSI_CC_HAS_AES_CCM*/
+
+static int ssi_aead_setauthsize(
+ struct crypto_aead *authenc,
+ unsigned int authsize)
+{
+ struct ssi_aead_ctx *ctx = crypto_aead_ctx(authenc);
+
+ CHECK_AND_RETURN_UPON_FIPS_ERROR();
+ /* Unsupported auth. sizes */
+ if ((authsize == 0) ||
+ (authsize >crypto_aead_maxauthsize(authenc))) {
+ return -ENOTSUPP;
+ }
+
+ ctx->authsize = authsize;
+ SSI_LOG_DEBUG("authlen=%d\n", ctx->authsize);
+
+ return 0;
+}
+
+#if SSI_CC_HAS_AES_CCM
+static int ssi_rfc4309_ccm_setauthsize(struct crypto_aead *authenc,
+ unsigned int authsize)
+{
+ switch (authsize) {
+ case 8:
+ case 12:
+ case 16:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return ssi_aead_setauthsize(authenc, authsize);
+}
+
+static int ssi_ccm_setauthsize(struct crypto_aead *authenc,
+ unsigned int authsize)
+{
+ switch (authsize) {
+ case 4:
+ case 6:
+ case 8:
+ case 10:
+ case 12:
+ case 14:
+ case 16:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return ssi_aead_setauthsize(authenc, authsize);
+}
+#endif /*SSI_CC_HAS_AES_CCM*/
+
+static inline void
+ssi_aead_create_assoc_desc(
+ struct aead_request *areq,
+ unsigned int flow_mode,
+ HwDesc_s desc[],
+ unsigned int *seq_size)
+{
+ struct crypto_aead *tfm = crypto_aead_reqtfm(areq);
+ struct ssi_aead_ctx *ctx = crypto_aead_ctx(tfm);
+ struct aead_req_ctx *areq_ctx = aead_request_ctx(areq);
+ enum ssi_req_dma_buf_type assoc_dma_type = areq_ctx->assoc_buff_type;
+ unsigned int idx = *seq_size;
+
+ switch (assoc_dma_type) {
+ case SSI_DMA_BUF_DLLI:
+ SSI_LOG_DEBUG("ASSOC buffer type DLLI\n");
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_DIN_TYPE(&desc[idx], DMA_DLLI,
+ sg_dma_address(areq->src),
+ areq->assoclen, NS_BIT);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], flow_mode);
+ if (ctx->auth_mode == DRV_HASH_XCBC_MAC && (areq_ctx->cryptlen > 0) )
+ HW_DESC_SET_DIN_NOT_LAST_INDICATION(&desc[idx]);
+ break;
+ case SSI_DMA_BUF_MLLI:
+ SSI_LOG_DEBUG("ASSOC buffer type MLLI\n");
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_DIN_TYPE(&desc[idx], DMA_MLLI,
+ areq_ctx->assoc.sram_addr,
+ areq_ctx->assoc.mlli_nents,
+ NS_BIT);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], flow_mode);
+ if (ctx->auth_mode == DRV_HASH_XCBC_MAC && (areq_ctx->cryptlen > 0) )
+ HW_DESC_SET_DIN_NOT_LAST_INDICATION(&desc[idx]);
+ break;
+ case SSI_DMA_BUF_NULL:
+ default:
+ SSI_LOG_ERR("Invalid ASSOC buffer type\n");
+ }
+
+ *seq_size = (++idx);
+}
+
+static inline void
+ssi_aead_process_authenc_data_desc(
+ struct aead_request *areq,
+ unsigned int flow_mode,
+ HwDesc_s desc[],
+ unsigned int *seq_size,
+ int direct)
+{
+ struct aead_req_ctx *areq_ctx = aead_request_ctx(areq);
+ enum ssi_req_dma_buf_type data_dma_type = areq_ctx->data_buff_type;
+ unsigned int idx = *seq_size;
+
+ switch (data_dma_type) {
+ case SSI_DMA_BUF_DLLI:
+ {
+ struct scatterlist *cipher =
+ (direct == DRV_CRYPTO_DIRECTION_ENCRYPT) ?
+ areq_ctx->dstSgl : areq_ctx->srcSgl;
+
+ unsigned int offset =
+ (direct == DRV_CRYPTO_DIRECTION_ENCRYPT) ?
+ areq_ctx->dstOffset : areq_ctx->srcOffset;
+ SSI_LOG_DEBUG("AUTHENC: SRC/DST buffer type DLLI\n");
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_DIN_TYPE(&desc[idx], DMA_DLLI,
+ (sg_dma_address(cipher)+ offset), areq_ctx->cryptlen,
+ NS_BIT);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], flow_mode);
+ break;
+ }
+ case SSI_DMA_BUF_MLLI:
+ {
+ /* DOUBLE-PASS flow (as default)
+ * assoc. + iv + data -compact in one table
+ * if assoclen is ZERO only IV perform */
+ ssi_sram_addr_t mlli_addr = areq_ctx->assoc.sram_addr;
+ uint32_t mlli_nents = areq_ctx->assoc.mlli_nents;
+
+ if (likely(areq_ctx->is_single_pass == true)) {
+ if (direct == DRV_CRYPTO_DIRECTION_ENCRYPT){
+ mlli_addr = areq_ctx->dst.sram_addr;
+ mlli_nents = areq_ctx->dst.mlli_nents;
+ } else {
+ mlli_addr = areq_ctx->src.sram_addr;
+ mlli_nents = areq_ctx->src.mlli_nents;
+ }
+ }
+
+ SSI_LOG_DEBUG("AUTHENC: SRC/DST buffer type MLLI\n");
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_DIN_TYPE(&desc[idx], DMA_MLLI,
+ mlli_addr, mlli_nents, NS_BIT);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], flow_mode);
+ break;
+ }
+ case SSI_DMA_BUF_NULL:
+ default:
+ SSI_LOG_ERR("AUTHENC: Invalid SRC/DST buffer type\n");
+ }
+
+ *seq_size = (++idx);
+}
+
+static inline void
+ssi_aead_process_cipher_data_desc(
+ struct aead_request *areq,
+ unsigned int flow_mode,
+ HwDesc_s desc[],
+ unsigned int *seq_size)
+{
+ unsigned int idx = *seq_size;
+ struct aead_req_ctx *areq_ctx = aead_request_ctx(areq);
+ enum ssi_req_dma_buf_type data_dma_type = areq_ctx->data_buff_type;
+
+ if (areq_ctx->cryptlen == 0)
+ return; /*null processing*/
+
+ switch (data_dma_type) {
+ case SSI_DMA_BUF_DLLI:
+ SSI_LOG_DEBUG("CIPHER: SRC/DST buffer type DLLI\n");
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_DIN_TYPE(&desc[idx], DMA_DLLI,
+ (sg_dma_address(areq_ctx->srcSgl)+areq_ctx->srcOffset),
+ areq_ctx->cryptlen, NS_BIT);
+ HW_DESC_SET_DOUT_DLLI(&desc[idx],
+ (sg_dma_address(areq_ctx->dstSgl)+areq_ctx->dstOffset),
+ areq_ctx->cryptlen, NS_BIT, 0);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], flow_mode);
+ break;
+ case SSI_DMA_BUF_MLLI:
+ SSI_LOG_DEBUG("CIPHER: SRC/DST buffer type MLLI\n");
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_DIN_TYPE(&desc[idx], DMA_MLLI,
+ areq_ctx->src.sram_addr,
+ areq_ctx->src.mlli_nents, NS_BIT);
+ HW_DESC_SET_DOUT_MLLI(&desc[idx],
+ areq_ctx->dst.sram_addr,
+ areq_ctx->dst.mlli_nents, NS_BIT, 0);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], flow_mode);
+ break;
+ case SSI_DMA_BUF_NULL:
+ default:
+ SSI_LOG_ERR("CIPHER: Invalid SRC/DST buffer type\n");
+ }
+
+ *seq_size = (++idx);
+}
+
+static inline void ssi_aead_process_digest_result_desc(
+ struct aead_request *req,
+ HwDesc_s desc[],
+ unsigned int *seq_size)
+{
+ struct crypto_aead *tfm = crypto_aead_reqtfm(req);
+ struct ssi_aead_ctx *ctx = crypto_aead_ctx(tfm);
+ struct aead_req_ctx *req_ctx = aead_request_ctx(req);
+ unsigned int idx = *seq_size;
+ unsigned int hash_mode = (ctx->auth_mode == DRV_HASH_SHA1) ?
+ DRV_HASH_HW_SHA1 : DRV_HASH_HW_SHA256;
+ int direct = req_ctx->gen_ctx.op_type;
+
+ /* Get final ICV result */
+ if (direct == DRV_CRYPTO_DIRECTION_ENCRYPT) {
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], S_HASH_to_DOUT);
+ HW_DESC_SET_SETUP_MODE(&desc[idx], SETUP_WRITE_STATE0);
+ HW_DESC_SET_DOUT_DLLI(&desc[idx], req_ctx->icv_dma_addr,
+ ctx->authsize, NS_BIT, 1);
+ HW_DESC_SET_QUEUE_LAST_IND(&desc[idx]);
+ if (ctx->auth_mode == DRV_HASH_XCBC_MAC) {
+ HW_DESC_SET_AES_NOT_HASH_MODE(&desc[idx]);
+ HW_DESC_SET_CIPHER_MODE(&desc[idx], DRV_CIPHER_XCBC_MAC);
+ } else {
+ HW_DESC_SET_CIPHER_CONFIG0(&desc[idx],
+ HASH_DIGEST_RESULT_LITTLE_ENDIAN);
+ HW_DESC_SET_CIPHER_MODE(&desc[idx], hash_mode);
+ }
+ } else { /*Decrypt*/
+ /* Get ICV out from hardware */
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_SETUP_MODE(&desc[idx], SETUP_WRITE_STATE0);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], S_HASH_to_DOUT);
+ HW_DESC_SET_DOUT_DLLI(&desc[idx], req_ctx->mac_buf_dma_addr,
+ ctx->authsize, NS_BIT, 1);
+ HW_DESC_SET_QUEUE_LAST_IND(&desc[idx]);
+ HW_DESC_SET_CIPHER_CONFIG0(&desc[idx], HASH_DIGEST_RESULT_LITTLE_ENDIAN);
+ HW_DESC_SET_CIPHER_CONFIG1(&desc[idx], HASH_PADDING_DISABLED);
+ if (ctx->auth_mode == DRV_HASH_XCBC_MAC) {
+ HW_DESC_SET_CIPHER_MODE(&desc[idx], DRV_CIPHER_XCBC_MAC);
+ HW_DESC_SET_AES_NOT_HASH_MODE(&desc[idx]);
+ } else {
+ HW_DESC_SET_CIPHER_MODE(&desc[idx], hash_mode);
+ }
+ }
+
+ *seq_size = (++idx);
+}
+
+static inline void ssi_aead_setup_cipher_desc(
+ struct aead_request *req,
+ HwDesc_s desc[],
+ unsigned int *seq_size)
+{
+ struct crypto_aead *tfm = crypto_aead_reqtfm(req);
+ struct ssi_aead_ctx *ctx = crypto_aead_ctx(tfm);
+ struct aead_req_ctx *req_ctx = aead_request_ctx(req);
+ unsigned int hw_iv_size = req_ctx->hw_iv_size;
+ unsigned int idx = *seq_size;
+ int direct = req_ctx->gen_ctx.op_type;
+
+ /* Setup cipher state */
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_CIPHER_CONFIG0(&desc[idx], direct);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], ctx->flow_mode);
+ HW_DESC_SET_DIN_TYPE(&desc[idx], DMA_DLLI,
+ req_ctx->gen_ctx.iv_dma_addr, hw_iv_size, NS_BIT);
+ if (ctx->cipher_mode == DRV_CIPHER_CTR) {
+ HW_DESC_SET_SETUP_MODE(&desc[idx], SETUP_LOAD_STATE1);
+ } else {
+ HW_DESC_SET_SETUP_MODE(&desc[idx], SETUP_LOAD_STATE0);
+ }
+ HW_DESC_SET_CIPHER_MODE(&desc[idx], ctx->cipher_mode);
+ idx++;
+
+ /* Setup enc. key */
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_CIPHER_CONFIG0(&desc[idx], direct);
+ HW_DESC_SET_SETUP_MODE(&desc[idx], SETUP_LOAD_KEY0);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], ctx->flow_mode);
+ if (ctx->flow_mode == S_DIN_to_AES) {
+ HW_DESC_SET_DIN_TYPE(&desc[idx], DMA_DLLI, ctx->enckey_dma_addr,
+ ((ctx->enc_keylen == 24) ?
+ CC_AES_KEY_SIZE_MAX : ctx->enc_keylen), NS_BIT);
+ HW_DESC_SET_KEY_SIZE_AES(&desc[idx], ctx->enc_keylen);
+ } else {
+ HW_DESC_SET_DIN_TYPE(&desc[idx], DMA_DLLI, ctx->enckey_dma_addr,
+ ctx->enc_keylen, NS_BIT);
+ HW_DESC_SET_KEY_SIZE_DES(&desc[idx], ctx->enc_keylen);
+ }
+ HW_DESC_SET_CIPHER_MODE(&desc[idx], ctx->cipher_mode);
+ idx++;
+
+ *seq_size = idx;
+}
+
+static inline void ssi_aead_process_cipher(
+ struct aead_request *req,
+ HwDesc_s desc[],
+ unsigned int *seq_size,
+ unsigned int data_flow_mode)
+{
+ struct aead_req_ctx *req_ctx = aead_request_ctx(req);
+ int direct = req_ctx->gen_ctx.op_type;
+ unsigned int idx = *seq_size;
+
+ if (req_ctx->cryptlen == 0)
+ return; /*null processing*/
+
+ ssi_aead_setup_cipher_desc(req, desc, &idx);
+ ssi_aead_process_cipher_data_desc(req, data_flow_mode, desc, &idx);
+ if (direct == DRV_CRYPTO_DIRECTION_ENCRYPT) {
+ /* We must wait for DMA to write all cipher */
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_DIN_NO_DMA(&desc[idx], 0, 0xfffff0);
+ HW_DESC_SET_DOUT_NO_DMA(&desc[idx], 0, 0, 1);
+ idx++;
+ }
+
+ *seq_size = idx;
+}
+
+static inline void ssi_aead_hmac_setup_digest_desc(
+ struct aead_request *req,
+ HwDesc_s desc[],
+ unsigned int *seq_size)
+{
+ struct crypto_aead *tfm = crypto_aead_reqtfm(req);
+ struct ssi_aead_ctx *ctx = crypto_aead_ctx(tfm);
+ unsigned int hash_mode = (ctx->auth_mode == DRV_HASH_SHA1) ?
+ DRV_HASH_HW_SHA1 : DRV_HASH_HW_SHA256;
+ unsigned int digest_size = (ctx->auth_mode == DRV_HASH_SHA1) ?
+ CC_SHA1_DIGEST_SIZE : CC_SHA256_DIGEST_SIZE;
+ unsigned int idx = *seq_size;
+
+ /* Loading hash ipad xor key state */
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_CIPHER_MODE(&desc[idx], hash_mode);
+ HW_DESC_SET_DIN_TYPE(&desc[idx], DMA_DLLI,
+ ctx->auth_state.hmac.ipad_opad_dma_addr,
+ digest_size, NS_BIT);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], S_DIN_to_HASH);
+ HW_DESC_SET_SETUP_MODE(&desc[idx], SETUP_LOAD_STATE0);
+ idx++;
+
+ /* Load init. digest len (64 bytes) */
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_CIPHER_MODE(&desc[idx], hash_mode);
+ HW_DESC_SET_DIN_SRAM(&desc[idx],
+ ssi_ahash_get_initial_digest_len_sram_addr(ctx->drvdata, hash_mode),
+ HASH_LEN_SIZE);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], S_DIN_to_HASH);
+ HW_DESC_SET_SETUP_MODE(&desc[idx], SETUP_LOAD_KEY0);
+ idx++;
+
+ *seq_size = idx;
+}
+
+static inline void ssi_aead_xcbc_setup_digest_desc(
+ struct aead_request *req,
+ HwDesc_s desc[],
+ unsigned int *seq_size)
+{
+ struct crypto_aead *tfm = crypto_aead_reqtfm(req);
+ struct ssi_aead_ctx *ctx = crypto_aead_ctx(tfm);
+ unsigned int idx = *seq_size;
+
+ /* Loading MAC state */
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_DIN_CONST(&desc[idx], 0, CC_AES_BLOCK_SIZE);
+ HW_DESC_SET_SETUP_MODE(&desc[idx], SETUP_LOAD_STATE0);
+ HW_DESC_SET_CIPHER_MODE(&desc[idx], DRV_CIPHER_XCBC_MAC);
+ HW_DESC_SET_CIPHER_CONFIG0(&desc[idx], DESC_DIRECTION_ENCRYPT_ENCRYPT);
+ HW_DESC_SET_KEY_SIZE_AES(&desc[idx], CC_AES_128_BIT_KEY_SIZE);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], S_DIN_to_HASH);
+ HW_DESC_SET_AES_NOT_HASH_MODE(&desc[idx]);
+ idx++;
+
+ /* Setup XCBC MAC K1 */
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_DIN_TYPE(&desc[idx], DMA_DLLI,
+ ctx->auth_state.xcbc.xcbc_keys_dma_addr,
+ AES_KEYSIZE_128, NS_BIT);
+ HW_DESC_SET_SETUP_MODE(&desc[idx], SETUP_LOAD_KEY0);
+ HW_DESC_SET_CIPHER_MODE(&desc[idx], DRV_CIPHER_XCBC_MAC);
+ HW_DESC_SET_CIPHER_CONFIG0(&desc[idx], DESC_DIRECTION_ENCRYPT_ENCRYPT);
+ HW_DESC_SET_KEY_SIZE_AES(&desc[idx], CC_AES_128_BIT_KEY_SIZE);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], S_DIN_to_HASH);
+ HW_DESC_SET_AES_NOT_HASH_MODE(&desc[idx]);
+ idx++;
+
+ /* Setup XCBC MAC K2 */
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_DIN_TYPE(&desc[idx], DMA_DLLI,
+ (ctx->auth_state.xcbc.xcbc_keys_dma_addr +
+ AES_KEYSIZE_128),
+ AES_KEYSIZE_128, NS_BIT);
+ HW_DESC_SET_SETUP_MODE(&desc[idx], SETUP_LOAD_STATE1);
+ HW_DESC_SET_CIPHER_MODE(&desc[idx], DRV_CIPHER_XCBC_MAC);
+ HW_DESC_SET_CIPHER_CONFIG0(&desc[idx], DESC_DIRECTION_ENCRYPT_ENCRYPT);
+ HW_DESC_SET_KEY_SIZE_AES(&desc[idx], CC_AES_128_BIT_KEY_SIZE);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], S_DIN_to_HASH);
+ HW_DESC_SET_AES_NOT_HASH_MODE(&desc[idx]);
+ idx++;
+
+ /* Setup XCBC MAC K3 */
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_DIN_TYPE(&desc[idx], DMA_DLLI,
+ (ctx->auth_state.xcbc.xcbc_keys_dma_addr +
+ 2 * AES_KEYSIZE_128),
+ AES_KEYSIZE_128, NS_BIT);
+ HW_DESC_SET_SETUP_MODE(&desc[idx], SETUP_LOAD_STATE2);
+ HW_DESC_SET_CIPHER_MODE(&desc[idx], DRV_CIPHER_XCBC_MAC);
+ HW_DESC_SET_CIPHER_CONFIG0(&desc[idx], DESC_DIRECTION_ENCRYPT_ENCRYPT);
+ HW_DESC_SET_KEY_SIZE_AES(&desc[idx], CC_AES_128_BIT_KEY_SIZE);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], S_DIN_to_HASH);
+ HW_DESC_SET_AES_NOT_HASH_MODE(&desc[idx]);
+ idx++;
+
+ *seq_size = idx;
+}
+
+static inline void ssi_aead_process_digest_header_desc(
+ struct aead_request *req,
+ HwDesc_s desc[],
+ unsigned int *seq_size)
+{
+ unsigned int idx = *seq_size;
+ /* Hash associated data */
+ if (req->assoclen > 0)
+ ssi_aead_create_assoc_desc(req, DIN_HASH, desc, &idx);
+
+ /* Hash IV */
+ *seq_size = idx;
+}
+
+static inline void ssi_aead_process_digest_scheme_desc(
+ struct aead_request *req,
+ HwDesc_s desc[],
+ unsigned int *seq_size)
+{
+ struct crypto_aead *tfm = crypto_aead_reqtfm(req);
+ struct ssi_aead_ctx *ctx = crypto_aead_ctx(tfm);
+ struct ssi_aead_handle *aead_handle = ctx->drvdata->aead_handle;
+ unsigned int hash_mode = (ctx->auth_mode == DRV_HASH_SHA1) ?
+ DRV_HASH_HW_SHA1 : DRV_HASH_HW_SHA256;
+ unsigned int digest_size = (ctx->auth_mode == DRV_HASH_SHA1) ?
+ CC_SHA1_DIGEST_SIZE : CC_SHA256_DIGEST_SIZE;
+ unsigned int idx = *seq_size;
+
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_CIPHER_MODE(&desc[idx], hash_mode);
+ HW_DESC_SET_DOUT_SRAM(&desc[idx], aead_handle->sram_workspace_addr,
+ HASH_LEN_SIZE);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], S_HASH_to_DOUT);
+ HW_DESC_SET_SETUP_MODE(&desc[idx], SETUP_WRITE_STATE1);
+ HW_DESC_SET_CIPHER_DO(&desc[idx], DO_PAD);
+ idx++;
+
+ /* Get final ICV result */
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_DOUT_SRAM(&desc[idx], aead_handle->sram_workspace_addr,
+ digest_size);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], S_HASH_to_DOUT);
+ HW_DESC_SET_SETUP_MODE(&desc[idx], SETUP_WRITE_STATE0);
+ HW_DESC_SET_CIPHER_CONFIG0(&desc[idx], HASH_DIGEST_RESULT_LITTLE_ENDIAN);
+ HW_DESC_SET_CIPHER_MODE(&desc[idx], hash_mode);
+ idx++;
+
+ /* Loading hash opad xor key state */
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_CIPHER_MODE(&desc[idx], hash_mode);
+ HW_DESC_SET_DIN_TYPE(&desc[idx], DMA_DLLI,
+ (ctx->auth_state.hmac.ipad_opad_dma_addr + digest_size),
+ digest_size, NS_BIT);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], S_DIN_to_HASH);
+ HW_DESC_SET_SETUP_MODE(&desc[idx], SETUP_LOAD_STATE0);
+ idx++;
+
+ /* Load init. digest len (64 bytes) */
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_CIPHER_MODE(&desc[idx], hash_mode);
+ HW_DESC_SET_DIN_SRAM(&desc[idx],
+ ssi_ahash_get_initial_digest_len_sram_addr(ctx->drvdata, hash_mode),
+ HASH_LEN_SIZE);
+ HW_DESC_SET_CIPHER_CONFIG1(&desc[idx], HASH_PADDING_ENABLED);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], S_DIN_to_HASH);
+ HW_DESC_SET_SETUP_MODE(&desc[idx], SETUP_LOAD_KEY0);
+ idx++;
+
+ /* Perform HASH update */
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_DIN_SRAM(&desc[idx], aead_handle->sram_workspace_addr,
+ digest_size);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], DIN_HASH);
+ idx++;
+
+ *seq_size = idx;
+}
+
+static inline void ssi_aead_load_mlli_to_sram(
+ struct aead_request *req,
+ HwDesc_s desc[],
+ unsigned int *seq_size)
+{
+ struct aead_req_ctx *req_ctx = aead_request_ctx(req);
+ struct crypto_aead *tfm = crypto_aead_reqtfm(req);
+ struct ssi_aead_ctx *ctx = crypto_aead_ctx(tfm);
+
+ if (unlikely(
+ (req_ctx->assoc_buff_type == SSI_DMA_BUF_MLLI) ||
+ (req_ctx->data_buff_type == SSI_DMA_BUF_MLLI) ||
+ (req_ctx->is_single_pass == false))) {
+ SSI_LOG_DEBUG("Copy-to-sram: mlli_dma=%08x, mlli_size=%u\n",
+ (unsigned int)ctx->drvdata->mlli_sram_addr,
+ req_ctx->mlli_params.mlli_len);
+ /* Copy MLLI table host-to-sram */
+ HW_DESC_INIT(&desc[*seq_size]);
+ HW_DESC_SET_DIN_TYPE(&desc[*seq_size], DMA_DLLI,
+ req_ctx->mlli_params.mlli_dma_addr,
+ req_ctx->mlli_params.mlli_len, NS_BIT);
+ HW_DESC_SET_DOUT_SRAM(&desc[*seq_size],
+ ctx->drvdata->mlli_sram_addr,
+ req_ctx->mlli_params.mlli_len);
+ HW_DESC_SET_FLOW_MODE(&desc[*seq_size], BYPASS);
+ (*seq_size)++;
+ }
+}
+
+static inline enum FlowMode ssi_aead_get_data_flow_mode(
+ enum drv_crypto_direction direct,
+ enum FlowMode setup_flow_mode,
+ bool is_single_pass)
+{
+ enum FlowMode data_flow_mode;
+
+ if (direct == DRV_CRYPTO_DIRECTION_ENCRYPT) {
+ if (setup_flow_mode == S_DIN_to_AES)
+ data_flow_mode = likely(is_single_pass) ?
+ AES_to_HASH_and_DOUT : DIN_AES_DOUT;
+ else
+ data_flow_mode = likely(is_single_pass) ?
+ DES_to_HASH_and_DOUT : DIN_DES_DOUT;
+ } else { /* Decrypt */
+ if (setup_flow_mode == S_DIN_to_AES)
+ data_flow_mode = likely(is_single_pass) ?
+ AES_and_HASH : DIN_AES_DOUT;
+ else
+ data_flow_mode = likely(is_single_pass) ?
+ DES_and_HASH : DIN_DES_DOUT;
+ }
+
+ return data_flow_mode;
+}
+
+static inline void ssi_aead_hmac_authenc(
+ struct aead_request *req,
+ HwDesc_s desc[],
+ unsigned int *seq_size)
+{
+ struct crypto_aead *tfm = crypto_aead_reqtfm(req);
+ struct ssi_aead_ctx *ctx = crypto_aead_ctx(tfm);
+ struct aead_req_ctx *req_ctx = aead_request_ctx(req);
+ int direct = req_ctx->gen_ctx.op_type;
+ unsigned int data_flow_mode = ssi_aead_get_data_flow_mode(
+ direct, ctx->flow_mode, req_ctx->is_single_pass);
+
+ if (req_ctx->is_single_pass == true) {
+ /**
+ * Single-pass flow
+ */
+ ssi_aead_hmac_setup_digest_desc(req, desc, seq_size);
+ ssi_aead_setup_cipher_desc(req, desc, seq_size);
+ ssi_aead_process_digest_header_desc(req, desc, seq_size);
+ ssi_aead_process_cipher_data_desc(req, data_flow_mode, desc, seq_size);
+ ssi_aead_process_digest_scheme_desc(req, desc, seq_size);
+ ssi_aead_process_digest_result_desc(req, desc, seq_size);
+ return;
+ }
+
+ /**
+ * Double-pass flow
+ * Fallback for unsupported single-pass modes,
+ * i.e. using assoc. data of non-word-multiple */
+ if (direct == DRV_CRYPTO_DIRECTION_ENCRYPT) {
+ /* encrypt first.. */
+ ssi_aead_process_cipher(req, desc, seq_size, data_flow_mode);
+ /* authenc after..*/
+ ssi_aead_hmac_setup_digest_desc(req, desc, seq_size);
+ ssi_aead_process_authenc_data_desc(req, DIN_HASH, desc, seq_size, direct);
+ ssi_aead_process_digest_scheme_desc(req, desc, seq_size);
+ ssi_aead_process_digest_result_desc(req, desc, seq_size);
+
+ } else { /*DECRYPT*/
+ /* authenc first..*/
+ ssi_aead_hmac_setup_digest_desc(req, desc, seq_size);
+ ssi_aead_process_authenc_data_desc(req, DIN_HASH, desc, seq_size, direct);
+ ssi_aead_process_digest_scheme_desc(req, desc, seq_size);
+ /* decrypt after.. */
+ ssi_aead_process_cipher(req, desc, seq_size, data_flow_mode);
+ /* read the digest result with setting the completion bit
+ must be after the cipher operation */
+ ssi_aead_process_digest_result_desc(req, desc, seq_size);
+ }
+}
+
+static inline void
+ssi_aead_xcbc_authenc(
+ struct aead_request *req,
+ HwDesc_s desc[],
+ unsigned int *seq_size)
+{
+ struct crypto_aead *tfm = crypto_aead_reqtfm(req);
+ struct ssi_aead_ctx *ctx = crypto_aead_ctx(tfm);
+ struct aead_req_ctx *req_ctx = aead_request_ctx(req);
+ int direct = req_ctx->gen_ctx.op_type;
+ unsigned int data_flow_mode = ssi_aead_get_data_flow_mode(
+ direct, ctx->flow_mode, req_ctx->is_single_pass);
+
+ if (req_ctx->is_single_pass == true) {
+ /**
+ * Single-pass flow
+ */
+ ssi_aead_xcbc_setup_digest_desc(req, desc, seq_size);
+ ssi_aead_setup_cipher_desc(req, desc, seq_size);
+ ssi_aead_process_digest_header_desc(req, desc, seq_size);
+ ssi_aead_process_cipher_data_desc(req, data_flow_mode, desc, seq_size);
+ ssi_aead_process_digest_result_desc(req, desc, seq_size);
+ return;
+ }
+
+ /**
+ * Double-pass flow
+ * Fallback for unsupported single-pass modes,
+ * i.e. using assoc. data of non-word-multiple */
+ if (direct == DRV_CRYPTO_DIRECTION_ENCRYPT) {
+ /* encrypt first.. */
+ ssi_aead_process_cipher(req, desc, seq_size, data_flow_mode);
+ /* authenc after.. */
+ ssi_aead_xcbc_setup_digest_desc(req, desc, seq_size);
+ ssi_aead_process_authenc_data_desc(req, DIN_HASH, desc, seq_size, direct);
+ ssi_aead_process_digest_result_desc(req, desc, seq_size);
+ } else { /*DECRYPT*/
+ /* authenc first.. */
+ ssi_aead_xcbc_setup_digest_desc(req, desc, seq_size);
+ ssi_aead_process_authenc_data_desc(req, DIN_HASH, desc, seq_size, direct);
+ /* decrypt after..*/
+ ssi_aead_process_cipher(req, desc, seq_size, data_flow_mode);
+ /* read the digest result with setting the completion bit
+ must be after the cipher operation */
+ ssi_aead_process_digest_result_desc(req, desc, seq_size);
+ }
+}
+
+static int validate_data_size(struct ssi_aead_ctx *ctx,
+ enum drv_crypto_direction direct, struct aead_request *req)
+{
+ struct aead_req_ctx *areq_ctx = aead_request_ctx(req);
+ unsigned int assoclen = req->assoclen;
+ unsigned int cipherlen = (direct == DRV_CRYPTO_DIRECTION_DECRYPT) ?
+ (req->cryptlen - ctx->authsize) : req->cryptlen;
+
+ if (unlikely((direct == DRV_CRYPTO_DIRECTION_DECRYPT) &&
+ (req->cryptlen < ctx->authsize)))
+ goto data_size_err;
+
+ areq_ctx->is_single_pass = true; /*defaulted to fast flow*/
+
+ switch (ctx->flow_mode) {
+ case S_DIN_to_AES:
+ if (unlikely((ctx->cipher_mode == DRV_CIPHER_CBC) &&
+ !IS_ALIGNED(cipherlen, AES_BLOCK_SIZE)))
+ goto data_size_err;
+ if (ctx->cipher_mode == DRV_CIPHER_CCM)
+ break;
+ if (ctx->cipher_mode == DRV_CIPHER_GCTR)
+ {
+ if (areq_ctx->plaintext_authenticate_only == true)
+ areq_ctx->is_single_pass = false;
+ break;
+ }
+
+ if (!IS_ALIGNED(assoclen, sizeof(uint32_t)))
+ areq_ctx->is_single_pass = false;
+
+ if ((ctx->cipher_mode == DRV_CIPHER_CTR) &&
+ !IS_ALIGNED(cipherlen, sizeof(uint32_t)))
+ areq_ctx->is_single_pass = false;
+
+ break;
+ case S_DIN_to_DES:
+ if (unlikely(!IS_ALIGNED(cipherlen, DES_BLOCK_SIZE)))
+ goto data_size_err;
+ if (unlikely(!IS_ALIGNED(assoclen, DES_BLOCK_SIZE)))
+ areq_ctx->is_single_pass = false;
+ break;
+ default:
+ SSI_LOG_ERR("Unexpected flow mode (%d)\n", ctx->flow_mode);
+ goto data_size_err;
+ }
+
+ return 0;
+
+data_size_err:
+ return -EINVAL;
+}
+
+#if SSI_CC_HAS_AES_CCM
+static unsigned int format_ccm_a0(uint8_t *pA0Buff, uint32_t headerSize)
+{
+ unsigned int len = 0;
+ if ( headerSize == 0 ) {
+ return 0;
+ }
+ if ( headerSize < ((1UL << 16) - (1UL << 8) )) {
+ len = 2;
+
+ pA0Buff[0] = (headerSize >> 8) & 0xFF;
+ pA0Buff[1] = headerSize & 0xFF;
+ } else {
+ len = 6;
+
+ pA0Buff[0] = 0xFF;
+ pA0Buff[1] = 0xFE;
+ pA0Buff[2] = (headerSize >> 24) & 0xFF;
+ pA0Buff[3] = (headerSize >> 16) & 0xFF;
+ pA0Buff[4] = (headerSize >> 8) & 0xFF;
+ pA0Buff[5] = headerSize & 0xFF;
+ }
+
+ return len;
+}
+
+static int set_msg_len(u8 *block, unsigned int msglen, unsigned int csize)
+{
+ __be32 data;
+
+ memset(block, 0, csize);
+ block += csize;
+
+ if (csize >= 4)
+ csize = 4;
+ else if (msglen > (1 << (8 * csize)))
+ return -EOVERFLOW;
+
+ data = cpu_to_be32(msglen);
+ memcpy(block - csize, (u8 *)&data + 4 - csize, csize);
+
+ return 0;
+}
+
+static inline int ssi_aead_ccm(
+ struct aead_request *req,
+ HwDesc_s desc[],
+ unsigned int *seq_size)
+{
+ struct crypto_aead *tfm = crypto_aead_reqtfm(req);
+ struct ssi_aead_ctx *ctx = crypto_aead_ctx(tfm);
+ struct aead_req_ctx *req_ctx = aead_request_ctx(req);
+ unsigned int idx = *seq_size;
+ unsigned int cipher_flow_mode;
+ dma_addr_t mac_result;
+
+
+ if (req_ctx->gen_ctx.op_type == DRV_CRYPTO_DIRECTION_DECRYPT) {
+ cipher_flow_mode = AES_to_HASH_and_DOUT;
+ mac_result = req_ctx->mac_buf_dma_addr;
+ } else { /* Encrypt */
+ cipher_flow_mode = AES_and_HASH;
+ mac_result = req_ctx->icv_dma_addr;
+ }
+
+ /* load key */
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_CIPHER_MODE(&desc[idx], DRV_CIPHER_CTR);
+ HW_DESC_SET_DIN_TYPE(&desc[idx], DMA_DLLI, ctx->enckey_dma_addr,
+ ((ctx->enc_keylen == 24) ?
+ CC_AES_KEY_SIZE_MAX : ctx->enc_keylen),
+ NS_BIT);
+ HW_DESC_SET_KEY_SIZE_AES(&desc[idx], ctx->enc_keylen);
+ HW_DESC_SET_SETUP_MODE(&desc[idx], SETUP_LOAD_KEY0);
+ HW_DESC_SET_CIPHER_CONFIG0(&desc[idx], DESC_DIRECTION_ENCRYPT_ENCRYPT);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], S_DIN_to_AES);
+ idx++;
+
+ /* load ctr state */
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_CIPHER_MODE(&desc[idx], DRV_CIPHER_CTR);
+ HW_DESC_SET_KEY_SIZE_AES(&desc[idx], ctx->enc_keylen);
+ HW_DESC_SET_DIN_TYPE(&desc[idx], DMA_DLLI,
+ req_ctx->gen_ctx.iv_dma_addr,
+ AES_BLOCK_SIZE, NS_BIT);
+ HW_DESC_SET_CIPHER_CONFIG0(&desc[idx], DESC_DIRECTION_ENCRYPT_ENCRYPT);
+ HW_DESC_SET_SETUP_MODE(&desc[idx], SETUP_LOAD_STATE1);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], S_DIN_to_AES);
+ idx++;
+
+ /* load MAC key */
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_CIPHER_MODE(&desc[idx], DRV_CIPHER_CBC_MAC);
+ HW_DESC_SET_DIN_TYPE(&desc[idx], DMA_DLLI, ctx->enckey_dma_addr,
+ ((ctx->enc_keylen == 24) ?
+ CC_AES_KEY_SIZE_MAX : ctx->enc_keylen),
+ NS_BIT);
+ HW_DESC_SET_KEY_SIZE_AES(&desc[idx], ctx->enc_keylen);
+ HW_DESC_SET_SETUP_MODE(&desc[idx], SETUP_LOAD_KEY0);
+ HW_DESC_SET_CIPHER_CONFIG0(&desc[idx], DESC_DIRECTION_ENCRYPT_ENCRYPT);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], S_DIN_to_HASH);
+ HW_DESC_SET_AES_NOT_HASH_MODE(&desc[idx]);
+ idx++;
+
+ /* load MAC state */
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_CIPHER_MODE(&desc[idx], DRV_CIPHER_CBC_MAC);
+ HW_DESC_SET_KEY_SIZE_AES(&desc[idx], ctx->enc_keylen);
+ HW_DESC_SET_DIN_TYPE(&desc[idx], DMA_DLLI,
+ req_ctx->mac_buf_dma_addr,
+ AES_BLOCK_SIZE, NS_BIT);
+ HW_DESC_SET_CIPHER_CONFIG0(&desc[idx], DESC_DIRECTION_ENCRYPT_ENCRYPT);
+ HW_DESC_SET_SETUP_MODE(&desc[idx], SETUP_LOAD_STATE0);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], S_DIN_to_HASH);
+ HW_DESC_SET_AES_NOT_HASH_MODE(&desc[idx]);
+ idx++;
+
+
+ /* process assoc data */
+ if (req->assoclen > 0) {
+ ssi_aead_create_assoc_desc(req, DIN_HASH, desc, &idx);
+ } else {
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_DIN_TYPE(&desc[idx], DMA_DLLI,
+ sg_dma_address(&req_ctx->ccm_adata_sg),
+ AES_BLOCK_SIZE + req_ctx->ccm_hdr_size,
+ NS_BIT);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], DIN_HASH);
+ idx++;
+ }
+
+ /* process the cipher */
+ if (req_ctx->cryptlen != 0) {
+ ssi_aead_process_cipher_data_desc(req, cipher_flow_mode, desc, &idx);
+ }
+
+ /* Read temporal MAC */
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_CIPHER_MODE(&desc[idx], DRV_CIPHER_CBC_MAC);
+ HW_DESC_SET_DOUT_DLLI(&desc[idx], req_ctx->mac_buf_dma_addr,
+ ctx->authsize, NS_BIT, 0);
+ HW_DESC_SET_SETUP_MODE(&desc[idx], SETUP_WRITE_STATE0);
+ HW_DESC_SET_CIPHER_CONFIG0(&desc[idx], HASH_DIGEST_RESULT_LITTLE_ENDIAN);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], S_HASH_to_DOUT);
+ HW_DESC_SET_AES_NOT_HASH_MODE(&desc[idx]);
+ idx++;
+
+ /* load AES-CTR state (for last MAC calculation)*/
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_CIPHER_MODE(&desc[idx], DRV_CIPHER_CTR);
+ HW_DESC_SET_CIPHER_CONFIG0(&desc[idx], DRV_CRYPTO_DIRECTION_ENCRYPT);
+ HW_DESC_SET_DIN_TYPE(&desc[idx], DMA_DLLI,
+ req_ctx->ccm_iv0_dma_addr ,
+ AES_BLOCK_SIZE, NS_BIT);
+ HW_DESC_SET_KEY_SIZE_AES(&desc[idx], ctx->enc_keylen);
+ HW_DESC_SET_SETUP_MODE(&desc[idx], SETUP_LOAD_STATE1);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], S_DIN_to_AES);
+ idx++;
+
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_DIN_NO_DMA(&desc[idx], 0, 0xfffff0);
+ HW_DESC_SET_DOUT_NO_DMA(&desc[idx], 0, 0, 1);
+ idx++;
+
+ /* encrypt the "T" value and store MAC in mac_state */
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_DIN_TYPE(&desc[idx], DMA_DLLI,
+ req_ctx->mac_buf_dma_addr , ctx->authsize, NS_BIT);
+ HW_DESC_SET_DOUT_DLLI(&desc[idx], mac_result , ctx->authsize, NS_BIT, 1);
+ HW_DESC_SET_QUEUE_LAST_IND(&desc[idx]);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], DIN_AES_DOUT);
+ idx++;
+
+ *seq_size = idx;
+ return 0;
+}
+
+static int config_ccm_adata(struct aead_request *req) {
+ struct crypto_aead *tfm = crypto_aead_reqtfm(req);
+ struct ssi_aead_ctx *ctx = crypto_aead_ctx(tfm);
+ struct aead_req_ctx *req_ctx = aead_request_ctx(req);
+ //unsigned int size_of_a = 0, rem_a_size = 0;
+ unsigned int lp = req->iv[0];
+ /* Note: The code assume that req->iv[0] already contains the value of L' of RFC3610 */
+ unsigned int l = lp + 1; /* This is L' of RFC 3610. */
+ unsigned int m = ctx->authsize; /* This is M' of RFC 3610. */
+ uint8_t *b0 = req_ctx->ccm_config + CCM_B0_OFFSET;
+ uint8_t *a0 = req_ctx->ccm_config + CCM_A0_OFFSET;
+ uint8_t *ctr_count_0 = req_ctx->ccm_config + CCM_CTR_COUNT_0_OFFSET;
+ unsigned int cryptlen = (req_ctx->gen_ctx.op_type ==
+ DRV_CRYPTO_DIRECTION_ENCRYPT) ?
+ req->cryptlen :
+ (req->cryptlen - ctx->authsize);
+ int rc;
+ memset(req_ctx->mac_buf, 0, AES_BLOCK_SIZE);
+ memset(req_ctx->ccm_config, 0, AES_BLOCK_SIZE*3);
+
+ /* taken from crypto/ccm.c */
+ /* 2 <= L <= 8, so 1 <= L' <= 7. */
+ if (2 > l || l > 8) {
+ SSI_LOG_ERR("illegal iv value %X\n",req->iv[0]);
+ return -EINVAL;
+ }
+ memcpy(b0, req->iv, AES_BLOCK_SIZE);
+
+ /* format control info per RFC 3610 and
+ * NIST Special Publication 800-38C
+ */
+ *b0 |= (8 * ((m - 2) / 2));
+ if (req->assoclen > 0)
+ *b0 |= 64; /* Enable bit 6 if Adata exists. */
+
+ rc = set_msg_len(b0 + 16 - l, cryptlen, l); /* Write L'. */
+ if (rc != 0) {
+ return rc;
+ }
+ /* END of "taken from crypto/ccm.c" */
+
+ /* l(a) - size of associated data. */
+ req_ctx->ccm_hdr_size = format_ccm_a0 (a0, req->assoclen);
+
+ memset(req->iv + 15 - req->iv[0], 0, req->iv[0] + 1);
+ req->iv [15] = 1;
+
+ memcpy(ctr_count_0, req->iv, AES_BLOCK_SIZE) ;
+ ctr_count_0[15] = 0;
+
+ return 0;
+}
+
+static void ssi_rfc4309_ccm_process(struct aead_request *req)
+{
+ struct crypto_aead *tfm = crypto_aead_reqtfm(req);
+ struct ssi_aead_ctx *ctx = crypto_aead_ctx(tfm);
+ struct aead_req_ctx *areq_ctx = aead_request_ctx(req);
+
+ /* L' */
+ memset(areq_ctx->ctr_iv, 0, AES_BLOCK_SIZE);
+ areq_ctx->ctr_iv[0] = 3; /* For RFC 4309, always use 4 bytes for message length (at most 2^32-1 bytes). */
+
+ /* In RFC 4309 there is an 11-bytes nonce+IV part, that we build here. */
+ memcpy(areq_ctx->ctr_iv + CCM_BLOCK_NONCE_OFFSET, ctx->ctr_nonce, CCM_BLOCK_NONCE_SIZE);
+ memcpy(areq_ctx->ctr_iv + CCM_BLOCK_IV_OFFSET, req->iv, CCM_BLOCK_IV_SIZE);
+ req->iv = areq_ctx->ctr_iv;
+ req->assoclen -= CCM_BLOCK_IV_SIZE;
+}
+#endif /*SSI_CC_HAS_AES_CCM*/
+
+#if SSI_CC_HAS_AES_GCM
+
+static inline void ssi_aead_gcm_setup_ghash_desc(
+ struct aead_request *req,
+ HwDesc_s desc[],
+ unsigned int *seq_size)
+{
+ struct crypto_aead *tfm = crypto_aead_reqtfm(req);
+ struct ssi_aead_ctx *ctx = crypto_aead_ctx(tfm);
+ struct aead_req_ctx *req_ctx = aead_request_ctx(req);
+ unsigned int idx = *seq_size;
+
+ /* load key to AES*/
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_CIPHER_MODE(&desc[idx], DRV_CIPHER_ECB);
+ HW_DESC_SET_CIPHER_CONFIG0(&desc[idx], DRV_CRYPTO_DIRECTION_ENCRYPT);
+ HW_DESC_SET_DIN_TYPE(&desc[idx], DMA_DLLI, ctx->enckey_dma_addr,
+ ctx->enc_keylen, NS_BIT);
+ HW_DESC_SET_KEY_SIZE_AES(&desc[idx], ctx->enc_keylen);
+ HW_DESC_SET_SETUP_MODE(&desc[idx], SETUP_LOAD_KEY0);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], S_DIN_to_AES);
+ idx++;
+
+ /* process one zero block to generate hkey */
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_DIN_CONST(&desc[idx], 0x0, AES_BLOCK_SIZE);
+ HW_DESC_SET_DOUT_DLLI(&desc[idx],
+ req_ctx->hkey_dma_addr,
+ AES_BLOCK_SIZE,
+ NS_BIT, 0);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], DIN_AES_DOUT);
+ idx++;
+
+ /* Memory Barrier */
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_DIN_NO_DMA(&desc[idx], 0, 0xfffff0);
+ HW_DESC_SET_DOUT_NO_DMA(&desc[idx], 0, 0, 1);
+ idx++;
+
+ /* Load GHASH subkey */
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_DIN_TYPE(&desc[idx], DMA_DLLI,
+ req_ctx->hkey_dma_addr,
+ AES_BLOCK_SIZE, NS_BIT);
+ HW_DESC_SET_DOUT_NO_DMA(&desc[idx], 0, 0, 1);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], S_DIN_to_HASH);
+ HW_DESC_SET_AES_NOT_HASH_MODE(&desc[idx]);
+ HW_DESC_SET_CIPHER_MODE(&desc[idx], DRV_HASH_HW_GHASH);
+ HW_DESC_SET_CIPHER_CONFIG1(&desc[idx], HASH_PADDING_ENABLED);
+ HW_DESC_SET_SETUP_MODE(&desc[idx], SETUP_LOAD_KEY0);
+ idx++;
+
+ /* Configure Hash Engine to work with GHASH.
+ Since it was not possible to extend HASH submodes to add GHASH,
+ The following command is necessary in order to select GHASH (according to HW designers)*/
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_DIN_NO_DMA(&desc[idx], 0, 0xfffff0);
+ HW_DESC_SET_DOUT_NO_DMA(&desc[idx], 0, 0, 1);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], S_DIN_to_HASH);
+ HW_DESC_SET_AES_NOT_HASH_MODE(&desc[idx]);
+ HW_DESC_SET_CIPHER_MODE(&desc[idx], DRV_HASH_HW_GHASH);
+ HW_DESC_SET_CIPHER_DO(&desc[idx], 1); //1=AES_SK RKEK
+ HW_DESC_SET_CIPHER_CONFIG0(&desc[idx], DRV_CRYPTO_DIRECTION_ENCRYPT);
+ HW_DESC_SET_CIPHER_CONFIG1(&desc[idx], HASH_PADDING_ENABLED);
+ HW_DESC_SET_SETUP_MODE(&desc[idx], SETUP_LOAD_KEY0);
+ idx++;
+
+ /* Load GHASH initial STATE (which is 0). (for any hash there is an initial state) */
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_DIN_CONST(&desc[idx], 0x0, AES_BLOCK_SIZE);
+ HW_DESC_SET_DOUT_NO_DMA(&desc[idx], 0, 0, 1);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], S_DIN_to_HASH);
+ HW_DESC_SET_AES_NOT_HASH_MODE(&desc[idx]);
+ HW_DESC_SET_CIPHER_MODE(&desc[idx], DRV_HASH_HW_GHASH);
+ HW_DESC_SET_CIPHER_CONFIG1(&desc[idx], HASH_PADDING_ENABLED);
+ HW_DESC_SET_SETUP_MODE(&desc[idx], SETUP_LOAD_STATE0);
+ idx++;
+
+ *seq_size = idx;
+}
+
+static inline void ssi_aead_gcm_setup_gctr_desc(
+ struct aead_request *req,
+ HwDesc_s desc[],
+ unsigned int *seq_size)
+{
+ struct crypto_aead *tfm = crypto_aead_reqtfm(req);
+ struct ssi_aead_ctx *ctx = crypto_aead_ctx(tfm);
+ struct aead_req_ctx *req_ctx = aead_request_ctx(req);
+ unsigned int idx = *seq_size;
+
+ /* load key to AES*/
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_CIPHER_MODE(&desc[idx], DRV_CIPHER_GCTR);
+ HW_DESC_SET_CIPHER_CONFIG0(&desc[idx], DRV_CRYPTO_DIRECTION_ENCRYPT);
+ HW_DESC_SET_DIN_TYPE(&desc[idx], DMA_DLLI, ctx->enckey_dma_addr,
+ ctx->enc_keylen, NS_BIT);
+ HW_DESC_SET_KEY_SIZE_AES(&desc[idx], ctx->enc_keylen);
+ HW_DESC_SET_SETUP_MODE(&desc[idx], SETUP_LOAD_KEY0);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], S_DIN_to_AES);
+ idx++;
+
+ if ((req_ctx->cryptlen != 0) && (req_ctx->plaintext_authenticate_only==false)){
+ /* load AES/CTR initial CTR value inc by 2*/
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_CIPHER_MODE(&desc[idx], DRV_CIPHER_GCTR);
+ HW_DESC_SET_KEY_SIZE_AES(&desc[idx], ctx->enc_keylen);
+ HW_DESC_SET_DIN_TYPE(&desc[idx], DMA_DLLI,
+ req_ctx->gcm_iv_inc2_dma_addr,
+ AES_BLOCK_SIZE, NS_BIT);
+ HW_DESC_SET_CIPHER_CONFIG0(&desc[idx], DRV_CRYPTO_DIRECTION_ENCRYPT);
+ HW_DESC_SET_SETUP_MODE(&desc[idx], SETUP_LOAD_STATE1);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], S_DIN_to_AES);
+ idx++;
+ }
+
+ *seq_size = idx;
+}
+
+static inline void ssi_aead_process_gcm_result_desc(
+ struct aead_request *req,
+ HwDesc_s desc[],
+ unsigned int *seq_size)
+{
+ struct crypto_aead *tfm = crypto_aead_reqtfm(req);
+ struct ssi_aead_ctx *ctx = crypto_aead_ctx(tfm);
+ struct aead_req_ctx *req_ctx = aead_request_ctx(req);
+ dma_addr_t mac_result;
+ unsigned int idx = *seq_size;
+
+ if (req_ctx->gen_ctx.op_type == DRV_CRYPTO_DIRECTION_DECRYPT) {
+ mac_result = req_ctx->mac_buf_dma_addr;
+ } else { /* Encrypt */
+ mac_result = req_ctx->icv_dma_addr;
+ }
+
+ /* process(ghash) gcm_block_len */
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_DIN_TYPE(&desc[idx], DMA_DLLI,
+ req_ctx->gcm_block_len_dma_addr,
+ AES_BLOCK_SIZE, NS_BIT);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], DIN_HASH);
+ idx++;
+
+ /* Store GHASH state after GHASH(Associated Data + Cipher +LenBlock) */
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_CIPHER_MODE(&desc[idx], DRV_HASH_HW_GHASH);
+ HW_DESC_SET_DIN_NO_DMA(&desc[idx], 0, 0xfffff0);
+ HW_DESC_SET_DOUT_DLLI(&desc[idx], req_ctx->mac_buf_dma_addr,
+ AES_BLOCK_SIZE, NS_BIT, 0);
+ HW_DESC_SET_SETUP_MODE(&desc[idx], SETUP_WRITE_STATE0);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], S_HASH_to_DOUT);
+ HW_DESC_SET_AES_NOT_HASH_MODE(&desc[idx]);
+
+ idx++;
+
+ /* load AES/CTR initial CTR value inc by 1*/
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_CIPHER_MODE(&desc[idx], DRV_CIPHER_GCTR);
+ HW_DESC_SET_KEY_SIZE_AES(&desc[idx], ctx->enc_keylen);
+ HW_DESC_SET_DIN_TYPE(&desc[idx], DMA_DLLI,
+ req_ctx->gcm_iv_inc1_dma_addr,
+ AES_BLOCK_SIZE, NS_BIT);
+ HW_DESC_SET_CIPHER_CONFIG0(&desc[idx], DRV_CRYPTO_DIRECTION_ENCRYPT);
+ HW_DESC_SET_SETUP_MODE(&desc[idx], SETUP_LOAD_STATE1);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], S_DIN_to_AES);
+ idx++;
+
+ /* Memory Barrier */
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_DIN_NO_DMA(&desc[idx], 0, 0xfffff0);
+ HW_DESC_SET_DOUT_NO_DMA(&desc[idx], 0, 0, 1);
+ idx++;
+
+ /* process GCTR on stored GHASH and store MAC in mac_state*/
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_CIPHER_MODE(&desc[idx], DRV_CIPHER_GCTR);
+ HW_DESC_SET_DIN_TYPE(&desc[idx], DMA_DLLI,
+ req_ctx->mac_buf_dma_addr,
+ AES_BLOCK_SIZE, NS_BIT);
+ HW_DESC_SET_DOUT_DLLI(&desc[idx], mac_result, ctx->authsize, NS_BIT, 1);
+ HW_DESC_SET_QUEUE_LAST_IND(&desc[idx]);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], DIN_AES_DOUT);
+ idx++;
+
+ *seq_size = idx;
+}
+
+static inline int ssi_aead_gcm(
+ struct aead_request *req,
+ HwDesc_s desc[],
+ unsigned int *seq_size)
+{
+ struct aead_req_ctx *req_ctx = aead_request_ctx(req);
+ unsigned int idx = *seq_size;
+ unsigned int cipher_flow_mode;
+
+ if (req_ctx->gen_ctx.op_type == DRV_CRYPTO_DIRECTION_DECRYPT) {
+ cipher_flow_mode = AES_and_HASH;
+ } else { /* Encrypt */
+ cipher_flow_mode = AES_to_HASH_and_DOUT;
+ }
+
+
+ //in RFC4543 no data to encrypt. just copy data from src to dest.
+ if (req_ctx->plaintext_authenticate_only==true){
+ ssi_aead_process_cipher_data_desc(req, BYPASS, desc, seq_size);
+ ssi_aead_gcm_setup_ghash_desc(req, desc, seq_size);
+ /* process(ghash) assoc data */
+ ssi_aead_create_assoc_desc(req, DIN_HASH, desc, seq_size);
+ ssi_aead_gcm_setup_gctr_desc(req, desc, seq_size);
+ ssi_aead_process_gcm_result_desc(req, desc, seq_size);
+ idx = *seq_size;
+ return 0;
+ }
+
+ // for gcm and rfc4106.
+ ssi_aead_gcm_setup_ghash_desc(req, desc, seq_size);
+ /* process(ghash) assoc data */
+ if (req->assoclen > 0)
+ ssi_aead_create_assoc_desc(req, DIN_HASH, desc, seq_size);
+ ssi_aead_gcm_setup_gctr_desc(req, desc, seq_size);
+ /* process(gctr+ghash) */
+ if (req_ctx->cryptlen != 0)
+ ssi_aead_process_cipher_data_desc(req, cipher_flow_mode, desc, seq_size);
+ ssi_aead_process_gcm_result_desc(req, desc, seq_size);
+
+ idx = *seq_size;
+ return 0;
+}
+
+#ifdef CC_DEBUG
+static inline void ssi_aead_dump_gcm(
+ const char* title,
+ struct aead_request *req)
+{
+ struct crypto_aead *tfm = crypto_aead_reqtfm(req);
+ struct ssi_aead_ctx *ctx = crypto_aead_ctx(tfm);
+ struct aead_req_ctx *req_ctx = aead_request_ctx(req);
+
+ if (ctx->cipher_mode != DRV_CIPHER_GCTR)
+ return;
+
+ if (title != NULL) {
+ SSI_LOG_DEBUG("----------------------------------------------------------------------------------");
+ SSI_LOG_DEBUG("%s\n", title);
+ }
+
+ SSI_LOG_DEBUG("cipher_mode %d, authsize %d, enc_keylen %d, assoclen %d, cryptlen %d \n", \
+ ctx->cipher_mode, ctx->authsize, ctx->enc_keylen, req->assoclen, req_ctx->cryptlen );
+
+ if ( ctx->enckey != NULL ) {
+ dump_byte_array("mac key",ctx->enckey, 16);
+ }
+
+ dump_byte_array("req->iv",req->iv, AES_BLOCK_SIZE);
+
+ dump_byte_array("gcm_iv_inc1",req_ctx->gcm_iv_inc1, AES_BLOCK_SIZE);
+
+ dump_byte_array("gcm_iv_inc2",req_ctx->gcm_iv_inc2, AES_BLOCK_SIZE);
+
+ dump_byte_array("hkey",req_ctx->hkey, AES_BLOCK_SIZE);
+
+ dump_byte_array("mac_buf",req_ctx->mac_buf, AES_BLOCK_SIZE);
+
+ dump_byte_array("gcm_len_block",req_ctx->gcm_len_block.lenA, AES_BLOCK_SIZE);
+
+ if (req->src!=NULL && req->cryptlen) {
+ dump_byte_array("req->src",sg_virt(req->src), req->cryptlen+req->assoclen);
+ }
+
+ if (req->dst!=NULL) {
+ dump_byte_array("req->dst",sg_virt(req->dst), req->cryptlen+ctx->authsize+req->assoclen);
+ }
+}
+#endif
+
+static int config_gcm_context(struct aead_request *req) {
+ struct crypto_aead *tfm = crypto_aead_reqtfm(req);
+ struct ssi_aead_ctx *ctx = crypto_aead_ctx(tfm);
+ struct aead_req_ctx *req_ctx = aead_request_ctx(req);
+
+ unsigned int cryptlen = (req_ctx->gen_ctx.op_type ==
+ DRV_CRYPTO_DIRECTION_ENCRYPT) ?
+ req->cryptlen :
+ (req->cryptlen - ctx->authsize);
+ __be32 counter = cpu_to_be32(2);
+
+ SSI_LOG_DEBUG("config_gcm_context() cryptlen = %d, req->assoclen = %d ctx->authsize = %d \n", cryptlen, req->assoclen, ctx->authsize);
+
+ memset(req_ctx->hkey, 0, AES_BLOCK_SIZE);
+
+ memset(req_ctx->mac_buf, 0, AES_BLOCK_SIZE);
+
+ memcpy(req->iv + 12, &counter, 4);
+ memcpy(req_ctx->gcm_iv_inc2, req->iv, 16);
+
+ counter = cpu_to_be32(1);
+ memcpy(req->iv + 12, &counter, 4);
+ memcpy(req_ctx->gcm_iv_inc1, req->iv, 16);
+
+
+ if (req_ctx->plaintext_authenticate_only == false)
+ {
+ __be64 temp64;
+ temp64 = cpu_to_be64(req->assoclen * 8);
+ memcpy ( &req_ctx->gcm_len_block.lenA , &temp64, sizeof(temp64) );
+ temp64 = cpu_to_be64(cryptlen * 8);
+ memcpy ( &req_ctx->gcm_len_block.lenC , &temp64, 8 );
+ }
+ else { //rfc4543=> all data(AAD,IV,Plain) are considered additional data that is nothing is encrypted.
+ __be64 temp64;
+ temp64 = cpu_to_be64((req->assoclen+GCM_BLOCK_RFC4_IV_SIZE+cryptlen) * 8);
+ memcpy ( &req_ctx->gcm_len_block.lenA , &temp64, sizeof(temp64) );
+ temp64 = 0;
+ memcpy ( &req_ctx->gcm_len_block.lenC , &temp64, 8 );
+ }
+
+ return 0;
+}
+
+static void ssi_rfc4_gcm_process(struct aead_request *req)
+{
+ struct crypto_aead *tfm = crypto_aead_reqtfm(req);
+ struct ssi_aead_ctx *ctx = crypto_aead_ctx(tfm);
+ struct aead_req_ctx *areq_ctx = aead_request_ctx(req);
+
+ memcpy(areq_ctx->ctr_iv + GCM_BLOCK_RFC4_NONCE_OFFSET, ctx->ctr_nonce, GCM_BLOCK_RFC4_NONCE_SIZE);
+ memcpy(areq_ctx->ctr_iv + GCM_BLOCK_RFC4_IV_OFFSET, req->iv, GCM_BLOCK_RFC4_IV_SIZE);
+ req->iv = areq_ctx->ctr_iv;
+ req->assoclen -= GCM_BLOCK_RFC4_IV_SIZE;
+}
+
+
+#endif /*SSI_CC_HAS_AES_GCM*/
+
+static int ssi_aead_process(struct aead_request *req, enum drv_crypto_direction direct)
+{
+ int rc = 0;
+ int seq_len = 0;
+ HwDesc_s desc[MAX_AEAD_PROCESS_SEQ];
+ struct crypto_aead *tfm = crypto_aead_reqtfm(req);
+ struct ssi_aead_ctx *ctx = crypto_aead_ctx(tfm);
+ struct aead_req_ctx *areq_ctx = aead_request_ctx(req);
+ struct device *dev = &ctx->drvdata->plat_dev->dev;
+ struct ssi_crypto_req ssi_req = {};
+
+ DECL_CYCLE_COUNT_RESOURCES;
+
+ SSI_LOG_DEBUG("%s context=%p req=%p iv=%p src=%p src_ofs=%d dst=%p dst_ofs=%d cryptolen=%d\n",
+ ((direct==DRV_CRYPTO_DIRECTION_ENCRYPT)?"Encrypt":"Decrypt"), ctx, req, req->iv,
+ sg_virt(req->src), req->src->offset, sg_virt(req->dst), req->dst->offset, req->cryptlen);
+ CHECK_AND_RETURN_UPON_FIPS_ERROR();
+
+ /* STAT_PHASE_0: Init and sanity checks */
+ START_CYCLE_COUNT();
+
+ /* Check data length according to mode */
+ if (unlikely(validate_data_size(ctx, direct, req) != 0)) {
+ SSI_LOG_ERR("Unsupported crypt/assoc len %d/%d.\n",
+ req->cryptlen, req->assoclen);
+ crypto_aead_set_flags(tfm, CRYPTO_TFM_RES_BAD_BLOCK_LEN);
+ return -EINVAL;
+ }
+
+ /* Setup DX request structure */
+ ssi_req.user_cb = (void *)ssi_aead_complete;
+ ssi_req.user_arg = (void *)req;
+
+#ifdef ENABLE_CYCLE_COUNT
+ ssi_req.op_type = (direct == DRV_CRYPTO_DIRECTION_DECRYPT) ?
+ STAT_OP_TYPE_DECODE : STAT_OP_TYPE_ENCODE;
+#endif
+ /* Setup request context */
+ areq_ctx->gen_ctx.op_type = direct;
+ areq_ctx->req_authsize = ctx->authsize;
+ areq_ctx->cipher_mode = ctx->cipher_mode;
+
+ END_CYCLE_COUNT(ssi_req.op_type, STAT_PHASE_0);
+
+ /* STAT_PHASE_1: Map buffers */
+ START_CYCLE_COUNT();
+
+ if (ctx->cipher_mode == DRV_CIPHER_CTR) {
+ /* Build CTR IV - Copy nonce from last 4 bytes in
+ * CTR key to first 4 bytes in CTR IV */
+ memcpy(areq_ctx->ctr_iv, ctx->ctr_nonce, CTR_RFC3686_NONCE_SIZE);
+ if (areq_ctx->backup_giv == NULL) /*User none-generated IV*/
+ memcpy(areq_ctx->ctr_iv + CTR_RFC3686_NONCE_SIZE,
+ req->iv, CTR_RFC3686_IV_SIZE);
+ /* Initialize counter portion of counter block */
+ *(__be32 *)(areq_ctx->ctr_iv + CTR_RFC3686_NONCE_SIZE +
+ CTR_RFC3686_IV_SIZE) = cpu_to_be32(1);
+
+ /* Replace with counter iv */
+ req->iv = areq_ctx->ctr_iv;
+ areq_ctx->hw_iv_size = CTR_RFC3686_BLOCK_SIZE;
+ } else if ((ctx->cipher_mode == DRV_CIPHER_CCM) ||
+ (ctx->cipher_mode == DRV_CIPHER_GCTR) ) {
+ areq_ctx->hw_iv_size = AES_BLOCK_SIZE;
+ if (areq_ctx->ctr_iv != req->iv) {
+ memcpy(areq_ctx->ctr_iv, req->iv, crypto_aead_ivsize(tfm));
+ req->iv = areq_ctx->ctr_iv;
+ }
+ } else {
+ areq_ctx->hw_iv_size = crypto_aead_ivsize(tfm);
+ }
+
+#if SSI_CC_HAS_AES_CCM
+ if (ctx->cipher_mode == DRV_CIPHER_CCM) {
+ rc = config_ccm_adata(req);
+ if (unlikely(rc != 0)) {
+ SSI_LOG_ERR("config_ccm_adata() returned with a failure %d!", rc);
+ goto exit;
+ }
+ } else {
+ areq_ctx->ccm_hdr_size = ccm_header_size_null;
+ }
+#else
+ areq_ctx->ccm_hdr_size = ccm_header_size_null;
+#endif /*SSI_CC_HAS_AES_CCM*/
+
+#if SSI_CC_HAS_AES_GCM
+ if (ctx->cipher_mode == DRV_CIPHER_GCTR) {
+ rc = config_gcm_context(req);
+ if (unlikely(rc != 0)) {
+ SSI_LOG_ERR("config_gcm_context() returned with a failure %d!", rc);
+ goto exit;
+ }
+ }
+#endif /*SSI_CC_HAS_AES_GCM*/
+
+ rc = ssi_buffer_mgr_map_aead_request(ctx->drvdata, req);
+ if (unlikely(rc != 0)) {
+ SSI_LOG_ERR("map_request() failed\n");
+ goto exit;
+ }
+
+ /* do we need to generate IV? */
+ if (areq_ctx->backup_giv != NULL) {
+
+ /* set the DMA mapped IV address*/
+ if (ctx->cipher_mode == DRV_CIPHER_CTR) {
+ ssi_req.ivgen_dma_addr[0] = areq_ctx->gen_ctx.iv_dma_addr + CTR_RFC3686_NONCE_SIZE;
+ ssi_req.ivgen_dma_addr_len = 1;
+ } else if (ctx->cipher_mode == DRV_CIPHER_CCM) {
+ /* In ccm, the IV needs to exist both inside B0 and inside the counter.
+ It is also copied to iv_dma_addr for other reasons (like returning
+ it to the user).
+ So, using 3 (identical) IV outputs. */
+ ssi_req.ivgen_dma_addr[0] = areq_ctx->gen_ctx.iv_dma_addr + CCM_BLOCK_IV_OFFSET;
+ ssi_req.ivgen_dma_addr[1] = sg_dma_address(&areq_ctx->ccm_adata_sg) + CCM_B0_OFFSET + CCM_BLOCK_IV_OFFSET;
+ ssi_req.ivgen_dma_addr[2] = sg_dma_address(&areq_ctx->ccm_adata_sg) + CCM_CTR_COUNT_0_OFFSET + CCM_BLOCK_IV_OFFSET;
+ ssi_req.ivgen_dma_addr_len = 3;
+ } else {
+ ssi_req.ivgen_dma_addr[0] = areq_ctx->gen_ctx.iv_dma_addr;
+ ssi_req.ivgen_dma_addr_len = 1;
+ }
+
+ /* set the IV size (8/16 B long)*/
+ ssi_req.ivgen_size = crypto_aead_ivsize(tfm);
+ }
+
+ END_CYCLE_COUNT(ssi_req.op_type, STAT_PHASE_1);
+
+ /* STAT_PHASE_2: Create sequence */
+ START_CYCLE_COUNT();
+
+ /* Load MLLI tables to SRAM if necessary */
+ ssi_aead_load_mlli_to_sram(req, desc, &seq_len);
+
+ /*TODO: move seq len by reference */
+ switch (ctx->auth_mode) {
+ case DRV_HASH_SHA1:
+ case DRV_HASH_SHA256:
+ ssi_aead_hmac_authenc(req, desc, &seq_len);
+ break;
+ case DRV_HASH_XCBC_MAC:
+ ssi_aead_xcbc_authenc(req, desc, &seq_len);
+ break;
+#if ( SSI_CC_HAS_AES_CCM || SSI_CC_HAS_AES_GCM )
+ case DRV_HASH_NULL:
+#if SSI_CC_HAS_AES_CCM
+ if (ctx->cipher_mode == DRV_CIPHER_CCM) {
+ ssi_aead_ccm(req, desc, &seq_len);
+ }
+#endif /*SSI_CC_HAS_AES_CCM*/
+#if SSI_CC_HAS_AES_GCM
+ if (ctx->cipher_mode == DRV_CIPHER_GCTR) {
+ ssi_aead_gcm(req, desc, &seq_len);
+ }
+#endif /*SSI_CC_HAS_AES_GCM*/
+ break;
+#endif
+ default:
+ SSI_LOG_ERR("Unsupported authenc (%d)\n", ctx->auth_mode);
+ ssi_buffer_mgr_unmap_aead_request(dev, req);
+ rc = -ENOTSUPP;
+ goto exit;
+ }
+
+ END_CYCLE_COUNT(ssi_req.op_type, STAT_PHASE_2);
+
+ /* STAT_PHASE_3: Lock HW and push sequence */
+ START_CYCLE_COUNT();
+
+ rc = send_request(ctx->drvdata, &ssi_req, desc, seq_len, 1);
+
+ if (unlikely(rc != -EINPROGRESS)) {
+ SSI_LOG_ERR("send_request() failed (rc=%d)\n", rc);
+ ssi_buffer_mgr_unmap_aead_request(dev, req);
+ }
+
+
+ END_CYCLE_COUNT(ssi_req.op_type, STAT_PHASE_3);
+exit:
+ return rc;
+}
+
+static int ssi_aead_encrypt(struct aead_request *req)
+{
+ struct aead_req_ctx *areq_ctx = aead_request_ctx(req);
+ int rc;
+
+ /* No generated IV required */
+ areq_ctx->backup_iv = req->iv;
+ areq_ctx->backup_giv = NULL;
+ areq_ctx->is_gcm4543 = false;
+
+ areq_ctx->plaintext_authenticate_only = false;
+
+ rc = ssi_aead_process(req, DRV_CRYPTO_DIRECTION_ENCRYPT);
+ if (rc != -EINPROGRESS)
+ req->iv = areq_ctx->backup_iv;
+
+ return rc;
+}
+
+#if SSI_CC_HAS_AES_CCM
+static int ssi_rfc4309_ccm_encrypt(struct aead_request *req)
+{
+ /* Very similar to ssi_aead_encrypt() above. */
+
+ struct aead_req_ctx *areq_ctx = aead_request_ctx(req);
+ int rc = -EINVAL;
+
+ if (!valid_assoclen(req)) {
+ SSI_LOG_ERR("invalid Assoclen:%u\n", req->assoclen );
+ goto out;
+ }
+
+ /* No generated IV required */
+ areq_ctx->backup_iv = req->iv;
+ areq_ctx->backup_giv = NULL;
+ areq_ctx->is_gcm4543 = true;
+
+ ssi_rfc4309_ccm_process(req);
+
+ rc = ssi_aead_process(req, DRV_CRYPTO_DIRECTION_ENCRYPT);
+ if (rc != -EINPROGRESS)
+ req->iv = areq_ctx->backup_iv;
+out:
+ return rc;
+}
+#endif /* SSI_CC_HAS_AES_CCM */
+
+static int ssi_aead_decrypt(struct aead_request *req)
+{
+ struct aead_req_ctx *areq_ctx = aead_request_ctx(req);
+ int rc;
+
+ /* No generated IV required */
+ areq_ctx->backup_iv = req->iv;
+ areq_ctx->backup_giv = NULL;
+ areq_ctx->is_gcm4543 = false;
+
+ areq_ctx->plaintext_authenticate_only = false;
+
+ rc = ssi_aead_process(req, DRV_CRYPTO_DIRECTION_DECRYPT);
+ if (rc != -EINPROGRESS)
+ req->iv = areq_ctx->backup_iv;
+
+ return rc;
+
+}
+
+#if SSI_CC_HAS_AES_CCM
+static int ssi_rfc4309_ccm_decrypt(struct aead_request *req)
+{
+ /* Very similar to ssi_aead_decrypt() above. */
+
+ struct aead_req_ctx *areq_ctx = aead_request_ctx(req);
+ int rc = -EINVAL;
+
+ if (!valid_assoclen(req)) {
+ SSI_LOG_ERR("invalid Assoclen:%u\n", req->assoclen);
+ goto out;
+ }
+
+ /* No generated IV required */
+ areq_ctx->backup_iv = req->iv;
+ areq_ctx->backup_giv = NULL;
+
+ areq_ctx->is_gcm4543 = true;
+ ssi_rfc4309_ccm_process(req);
+
+ rc = ssi_aead_process(req, DRV_CRYPTO_DIRECTION_DECRYPT);
+ if (rc != -EINPROGRESS)
+ req->iv = areq_ctx->backup_iv;
+
+out:
+ return rc;
+}
+#endif /* SSI_CC_HAS_AES_CCM */
+
+#if SSI_CC_HAS_AES_GCM
+
+static int ssi_rfc4106_gcm_setkey(struct crypto_aead *tfm, const u8 *key, unsigned int keylen)
+{
+ struct ssi_aead_ctx *ctx = crypto_aead_ctx(tfm);
+ int rc = 0;
+
+ SSI_LOG_DEBUG("ssi_rfc4106_gcm_setkey() keylen %d, key %p \n", keylen, key );
+
+ if (keylen < 4)
+ return -EINVAL;
+
+ keylen -= 4;
+ memcpy(ctx->ctr_nonce, key + keylen, 4);
+
+ rc = ssi_aead_setkey(tfm, key, keylen);
+
+ return rc;
+}
+
+static int ssi_rfc4543_gcm_setkey(struct crypto_aead *tfm, const u8 *key, unsigned int keylen)
+{
+ struct ssi_aead_ctx *ctx = crypto_aead_ctx(tfm);
+ int rc = 0;
+
+ SSI_LOG_DEBUG("ssi_rfc4543_gcm_setkey() keylen %d, key %p \n", keylen, key );
+
+ if (keylen < 4)
+ return -EINVAL;
+
+ keylen -= 4;
+ memcpy(ctx->ctr_nonce, key + keylen, 4);
+
+ rc = ssi_aead_setkey(tfm, key, keylen);
+
+ return rc;
+}
+
+static int ssi_gcm_setauthsize(struct crypto_aead *authenc,
+ unsigned int authsize)
+{
+ switch (authsize) {
+ case 4:
+ case 8:
+ case 12:
+ case 13:
+ case 14:
+ case 15:
+ case 16:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return ssi_aead_setauthsize(authenc, authsize);
+}
+
+static int ssi_rfc4106_gcm_setauthsize(struct crypto_aead *authenc,
+ unsigned int authsize)
+{
+ SSI_LOG_DEBUG("ssi_rfc4106_gcm_setauthsize() authsize %d \n", authsize );
+
+ switch (authsize) {
+ case 8:
+ case 12:
+ case 16:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return ssi_aead_setauthsize(authenc, authsize);
+}
+
+static int ssi_rfc4543_gcm_setauthsize(struct crypto_aead *authenc,
+ unsigned int authsize)
+{
+ SSI_LOG_DEBUG("ssi_rfc4543_gcm_setauthsize() authsize %d \n", authsize );
+
+ if (authsize != 16)
+ return -EINVAL;
+
+ return ssi_aead_setauthsize(authenc, authsize);
+}
+
+static int ssi_rfc4106_gcm_encrypt(struct aead_request *req)
+{
+ /* Very similar to ssi_aead_encrypt() above. */
+
+ struct aead_req_ctx *areq_ctx = aead_request_ctx(req);
+ int rc = -EINVAL;
+
+ if (!valid_assoclen(req)) {
+ SSI_LOG_ERR("invalid Assoclen:%u\n", req->assoclen);
+ goto out;
+ }
+
+ /* No generated IV required */
+ areq_ctx->backup_iv = req->iv;
+ areq_ctx->backup_giv = NULL;
+
+ areq_ctx->plaintext_authenticate_only = false;
+
+ ssi_rfc4_gcm_process(req);
+ areq_ctx->is_gcm4543 = true;
+
+ rc = ssi_aead_process(req, DRV_CRYPTO_DIRECTION_ENCRYPT);
+ if (rc != -EINPROGRESS)
+ req->iv = areq_ctx->backup_iv;
+out:
+ return rc;
+}
+
+static int ssi_rfc4543_gcm_encrypt(struct aead_request *req)
+{
+ /* Very similar to ssi_aead_encrypt() above. */
+
+ struct aead_req_ctx *areq_ctx = aead_request_ctx(req);
+ int rc;
+
+ //plaintext is not encryped with rfc4543
+ areq_ctx->plaintext_authenticate_only = true;
+
+ /* No generated IV required */
+ areq_ctx->backup_iv = req->iv;
+ areq_ctx->backup_giv = NULL;
+
+ ssi_rfc4_gcm_process(req);
+ areq_ctx->is_gcm4543 = true;
+
+ rc = ssi_aead_process(req, DRV_CRYPTO_DIRECTION_ENCRYPT);
+ if (rc != -EINPROGRESS)
+ req->iv = areq_ctx->backup_iv;
+
+ return rc;
+}
+
+static int ssi_rfc4106_gcm_decrypt(struct aead_request *req)
+{
+ /* Very similar to ssi_aead_decrypt() above. */
+
+ struct aead_req_ctx *areq_ctx = aead_request_ctx(req);
+ int rc = -EINVAL;
+
+ if (!valid_assoclen(req)) {
+ SSI_LOG_ERR("invalid Assoclen:%u\n", req->assoclen);
+ goto out;
+ }
+
+ /* No generated IV required */
+ areq_ctx->backup_iv = req->iv;
+ areq_ctx->backup_giv = NULL;
+
+ areq_ctx->plaintext_authenticate_only = false;
+
+ ssi_rfc4_gcm_process(req);
+ areq_ctx->is_gcm4543 = true;
+
+ rc = ssi_aead_process(req, DRV_CRYPTO_DIRECTION_DECRYPT);
+ if (rc != -EINPROGRESS)
+ req->iv = areq_ctx->backup_iv;
+out:
+ return rc;
+}
+
+static int ssi_rfc4543_gcm_decrypt(struct aead_request *req)
+{
+ /* Very similar to ssi_aead_decrypt() above. */
+
+ struct aead_req_ctx *areq_ctx = aead_request_ctx(req);
+ int rc;
+
+ //plaintext is not decryped with rfc4543
+ areq_ctx->plaintext_authenticate_only = true;
+
+ /* No generated IV required */
+ areq_ctx->backup_iv = req->iv;
+ areq_ctx->backup_giv = NULL;
+
+ ssi_rfc4_gcm_process(req);
+ areq_ctx->is_gcm4543 = true;
+
+ rc = ssi_aead_process(req, DRV_CRYPTO_DIRECTION_DECRYPT);
+ if (rc != -EINPROGRESS)
+ req->iv = areq_ctx->backup_iv;
+
+ return rc;
+}
+#endif /* SSI_CC_HAS_AES_GCM */
+
+/* DX Block aead alg */
+static struct ssi_alg_template aead_algs[] = {
+ {
+ .name = "authenc(hmac(sha1),cbc(aes))",
+ .driver_name = "authenc-hmac-sha1-cbc-aes-dx",
+ .blocksize = AES_BLOCK_SIZE,
+ .type = CRYPTO_ALG_TYPE_AEAD,
+ .template_aead = {
+ .setkey = ssi_aead_setkey,
+ .setauthsize = ssi_aead_setauthsize,
+ .encrypt = ssi_aead_encrypt,
+ .decrypt = ssi_aead_decrypt,
+ .init = ssi_aead_init,
+ .exit = ssi_aead_exit,
+ .ivsize = AES_BLOCK_SIZE,
+ .maxauthsize = SHA1_DIGEST_SIZE,
+ },
+ .cipher_mode = DRV_CIPHER_CBC,
+ .flow_mode = S_DIN_to_AES,
+ .auth_mode = DRV_HASH_SHA1,
+ },
+ {
+ .name = "authenc(hmac(sha1),cbc(des3_ede))",
+ .driver_name = "authenc-hmac-sha1-cbc-des3-dx",
+ .blocksize = DES3_EDE_BLOCK_SIZE,
+ .type = CRYPTO_ALG_TYPE_AEAD,
+ .template_aead = {
+ .setkey = ssi_aead_setkey,
+ .setauthsize = ssi_aead_setauthsize,
+ .encrypt = ssi_aead_encrypt,
+ .decrypt = ssi_aead_decrypt,
+ .init = ssi_aead_init,
+ .exit = ssi_aead_exit,
+ .ivsize = DES3_EDE_BLOCK_SIZE,
+ .maxauthsize = SHA1_DIGEST_SIZE,
+ },
+ .cipher_mode = DRV_CIPHER_CBC,
+ .flow_mode = S_DIN_to_DES,
+ .auth_mode = DRV_HASH_SHA1,
+ },
+ {
+ .name = "authenc(hmac(sha256),cbc(aes))",
+ .driver_name = "authenc-hmac-sha256-cbc-aes-dx",
+ .blocksize = AES_BLOCK_SIZE,
+ .type = CRYPTO_ALG_TYPE_AEAD,
+ .template_aead = {
+ .setkey = ssi_aead_setkey,
+ .setauthsize = ssi_aead_setauthsize,
+ .encrypt = ssi_aead_encrypt,
+ .decrypt = ssi_aead_decrypt,
+ .init = ssi_aead_init,
+ .exit = ssi_aead_exit,
+ .ivsize = AES_BLOCK_SIZE,
+ .maxauthsize = SHA256_DIGEST_SIZE,
+ },
+ .cipher_mode = DRV_CIPHER_CBC,
+ .flow_mode = S_DIN_to_AES,
+ .auth_mode = DRV_HASH_SHA256,
+ },
+ {
+ .name = "authenc(hmac(sha256),cbc(des3_ede))",
+ .driver_name = "authenc-hmac-sha256-cbc-des3-dx",
+ .blocksize = DES3_EDE_BLOCK_SIZE,
+ .type = CRYPTO_ALG_TYPE_AEAD,
+ .template_aead = {
+ .setkey = ssi_aead_setkey,
+ .setauthsize = ssi_aead_setauthsize,
+ .encrypt = ssi_aead_encrypt,
+ .decrypt = ssi_aead_decrypt,
+ .init = ssi_aead_init,
+ .exit = ssi_aead_exit,
+ .ivsize = DES3_EDE_BLOCK_SIZE,
+ .maxauthsize = SHA256_DIGEST_SIZE,
+ },
+ .cipher_mode = DRV_CIPHER_CBC,
+ .flow_mode = S_DIN_to_DES,
+ .auth_mode = DRV_HASH_SHA256,
+ },
+ {
+ .name = "authenc(xcbc(aes),cbc(aes))",
+ .driver_name = "authenc-xcbc-aes-cbc-aes-dx",
+ .blocksize = AES_BLOCK_SIZE,
+ .type = CRYPTO_ALG_TYPE_AEAD,
+ .template_aead = {
+ .setkey = ssi_aead_setkey,
+ .setauthsize = ssi_aead_setauthsize,
+ .encrypt = ssi_aead_encrypt,
+ .decrypt = ssi_aead_decrypt,
+ .init = ssi_aead_init,
+ .exit = ssi_aead_exit,
+ .ivsize = AES_BLOCK_SIZE,
+ .maxauthsize = AES_BLOCK_SIZE,
+ },
+ .cipher_mode = DRV_CIPHER_CBC,
+ .flow_mode = S_DIN_to_AES,
+ .auth_mode = DRV_HASH_XCBC_MAC,
+ },
+ {
+ .name = "authenc(hmac(sha1),rfc3686(ctr(aes)))",
+ .driver_name = "authenc-hmac-sha1-rfc3686-ctr-aes-dx",
+ .blocksize = 1,
+ .type = CRYPTO_ALG_TYPE_AEAD,
+ .template_aead = {
+ .setkey = ssi_aead_setkey,
+ .setauthsize = ssi_aead_setauthsize,
+ .encrypt = ssi_aead_encrypt,
+ .decrypt = ssi_aead_decrypt,
+ .init = ssi_aead_init,
+ .exit = ssi_aead_exit,
+ .ivsize = CTR_RFC3686_IV_SIZE,
+ .maxauthsize = SHA1_DIGEST_SIZE,
+ },
+ .cipher_mode = DRV_CIPHER_CTR,
+ .flow_mode = S_DIN_to_AES,
+ .auth_mode = DRV_HASH_SHA1,
+ },
+ {
+ .name = "authenc(hmac(sha256),rfc3686(ctr(aes)))",
+ .driver_name = "authenc-hmac-sha256-rfc3686-ctr-aes-dx",
+ .blocksize = 1,
+ .type = CRYPTO_ALG_TYPE_AEAD,
+ .template_aead = {
+ .setkey = ssi_aead_setkey,
+ .setauthsize = ssi_aead_setauthsize,
+ .encrypt = ssi_aead_encrypt,
+ .decrypt = ssi_aead_decrypt,
+ .init = ssi_aead_init,
+ .exit = ssi_aead_exit,
+ .ivsize = CTR_RFC3686_IV_SIZE,
+ .maxauthsize = SHA256_DIGEST_SIZE,
+ },
+ .cipher_mode = DRV_CIPHER_CTR,
+ .flow_mode = S_DIN_to_AES,
+ .auth_mode = DRV_HASH_SHA256,
+ },
+ {
+ .name = "authenc(xcbc(aes),rfc3686(ctr(aes)))",
+ .driver_name = "authenc-xcbc-aes-rfc3686-ctr-aes-dx",
+ .blocksize = 1,
+ .type = CRYPTO_ALG_TYPE_AEAD,
+ .template_aead = {
+ .setkey = ssi_aead_setkey,
+ .setauthsize = ssi_aead_setauthsize,
+ .encrypt = ssi_aead_encrypt,
+ .decrypt = ssi_aead_decrypt,
+ .init = ssi_aead_init,
+ .exit = ssi_aead_exit,
+ .ivsize = CTR_RFC3686_IV_SIZE,
+ .maxauthsize = AES_BLOCK_SIZE,
+ },
+ .cipher_mode = DRV_CIPHER_CTR,
+ .flow_mode = S_DIN_to_AES,
+ .auth_mode = DRV_HASH_XCBC_MAC,
+ },
+#if SSI_CC_HAS_AES_CCM
+ {
+ .name = "ccm(aes)",
+ .driver_name = "ccm-aes-dx",
+ .blocksize = 1,
+ .type = CRYPTO_ALG_TYPE_AEAD,
+ .template_aead = {
+ .setkey = ssi_aead_setkey,
+ .setauthsize = ssi_ccm_setauthsize,
+ .encrypt = ssi_aead_encrypt,
+ .decrypt = ssi_aead_decrypt,
+ .init = ssi_aead_init,
+ .exit = ssi_aead_exit,
+ .ivsize = AES_BLOCK_SIZE,
+ .maxauthsize = AES_BLOCK_SIZE,
+ },
+ .cipher_mode = DRV_CIPHER_CCM,
+ .flow_mode = S_DIN_to_AES,
+ .auth_mode = DRV_HASH_NULL,
+ },
+ {
+ .name = "rfc4309(ccm(aes))",
+ .driver_name = "rfc4309-ccm-aes-dx",
+ .blocksize = 1,
+ .type = CRYPTO_ALG_TYPE_AEAD,
+ .template_aead = {
+ .setkey = ssi_rfc4309_ccm_setkey,
+ .setauthsize = ssi_rfc4309_ccm_setauthsize,
+ .encrypt = ssi_rfc4309_ccm_encrypt,
+ .decrypt = ssi_rfc4309_ccm_decrypt,
+ .init = ssi_aead_init,
+ .exit = ssi_aead_exit,
+ .ivsize = CCM_BLOCK_IV_SIZE,
+ .maxauthsize = AES_BLOCK_SIZE,
+ },
+ .cipher_mode = DRV_CIPHER_CCM,
+ .flow_mode = S_DIN_to_AES,
+ .auth_mode = DRV_HASH_NULL,
+ },
+#endif /*SSI_CC_HAS_AES_CCM*/
+#if SSI_CC_HAS_AES_GCM
+ {
+ .name = "gcm(aes)",
+ .driver_name = "gcm-aes-dx",
+ .blocksize = 1,
+ .type = CRYPTO_ALG_TYPE_AEAD,
+ .template_aead = {
+ .setkey = ssi_aead_setkey,
+ .setauthsize = ssi_gcm_setauthsize,
+ .encrypt = ssi_aead_encrypt,
+ .decrypt = ssi_aead_decrypt,
+ .init = ssi_aead_init,
+ .exit = ssi_aead_exit,
+ .ivsize = 12,
+ .maxauthsize = AES_BLOCK_SIZE,
+ },
+ .cipher_mode = DRV_CIPHER_GCTR,
+ .flow_mode = S_DIN_to_AES,
+ .auth_mode = DRV_HASH_NULL,
+ },
+ {
+ .name = "rfc4106(gcm(aes))",
+ .driver_name = "rfc4106-gcm-aes-dx",
+ .blocksize = 1,
+ .type = CRYPTO_ALG_TYPE_AEAD,
+ .template_aead = {
+ .setkey = ssi_rfc4106_gcm_setkey,
+ .setauthsize = ssi_rfc4106_gcm_setauthsize,
+ .encrypt = ssi_rfc4106_gcm_encrypt,
+ .decrypt = ssi_rfc4106_gcm_decrypt,
+ .init = ssi_aead_init,
+ .exit = ssi_aead_exit,
+ .ivsize = GCM_BLOCK_RFC4_IV_SIZE,
+ .maxauthsize = AES_BLOCK_SIZE,
+ },
+ .cipher_mode = DRV_CIPHER_GCTR,
+ .flow_mode = S_DIN_to_AES,
+ .auth_mode = DRV_HASH_NULL,
+ },
+ {
+ .name = "rfc4543(gcm(aes))",
+ .driver_name = "rfc4543-gcm-aes-dx",
+ .blocksize = 1,
+ .type = CRYPTO_ALG_TYPE_AEAD,
+ .template_aead = {
+ .setkey = ssi_rfc4543_gcm_setkey,
+ .setauthsize = ssi_rfc4543_gcm_setauthsize,
+ .encrypt = ssi_rfc4543_gcm_encrypt,
+ .decrypt = ssi_rfc4543_gcm_decrypt,
+ .init = ssi_aead_init,
+ .exit = ssi_aead_exit,
+ .ivsize = GCM_BLOCK_RFC4_IV_SIZE,
+ .maxauthsize = AES_BLOCK_SIZE,
+ },
+ .cipher_mode = DRV_CIPHER_GCTR,
+ .flow_mode = S_DIN_to_AES,
+ .auth_mode = DRV_HASH_NULL,
+ },
+#endif /*SSI_CC_HAS_AES_GCM*/
+};
+
+static struct ssi_crypto_alg *ssi_aead_create_alg(struct ssi_alg_template *template)
+{
+ struct ssi_crypto_alg *t_alg;
+ struct aead_alg *alg;
+
+ t_alg = kzalloc(sizeof(struct ssi_crypto_alg), GFP_KERNEL);
+ if (!t_alg) {
+ SSI_LOG_ERR("failed to allocate t_alg\n");
+ return ERR_PTR(-ENOMEM);
+ }
+ alg = &template->template_aead;
+
+ snprintf(alg->base.cra_name, CRYPTO_MAX_ALG_NAME, "%s", template->name);
+ snprintf(alg->base.cra_driver_name, CRYPTO_MAX_ALG_NAME, "%s",
+ template->driver_name);
+ alg->base.cra_module = THIS_MODULE;
+ alg->base.cra_priority = SSI_CRA_PRIO;
+
+ alg->base.cra_ctxsize = sizeof(struct ssi_aead_ctx);
+ alg->base.cra_flags = CRYPTO_ALG_ASYNC | CRYPTO_ALG_KERN_DRIVER_ONLY |
+ template->type;
+ alg->init = ssi_aead_init;
+ alg->exit = ssi_aead_exit;
+
+ t_alg->aead_alg = *alg;
+
+ t_alg->cipher_mode = template->cipher_mode;
+ t_alg->flow_mode = template->flow_mode;
+ t_alg->auth_mode = template->auth_mode;
+
+ return t_alg;
+}
+
+int ssi_aead_free(struct ssi_drvdata *drvdata)
+{
+ struct ssi_crypto_alg *t_alg, *n;
+ struct ssi_aead_handle *aead_handle =
+ (struct ssi_aead_handle *)drvdata->aead_handle;
+
+ if (aead_handle != NULL) {
+ /* Remove registered algs */
+ list_for_each_entry_safe(t_alg, n, &aead_handle->aead_list, entry) {
+ crypto_unregister_aead(&t_alg->aead_alg);
+ list_del(&t_alg->entry);
+ kfree(t_alg);
+ }
+ kfree(aead_handle);
+ drvdata->aead_handle = NULL;
+ }
+
+ return 0;
+}
+
+int ssi_aead_alloc(struct ssi_drvdata *drvdata)
+{
+ struct ssi_aead_handle *aead_handle;
+ struct ssi_crypto_alg *t_alg;
+ int rc = -ENOMEM;
+ int alg;
+
+ aead_handle = kmalloc(sizeof(struct ssi_aead_handle), GFP_KERNEL);
+ if (aead_handle == NULL) {
+ rc = -ENOMEM;
+ goto fail0;
+ }
+
+ drvdata->aead_handle = aead_handle;
+
+ aead_handle->sram_workspace_addr = ssi_sram_mgr_alloc(
+ drvdata, MAX_HMAC_DIGEST_SIZE);
+ if (aead_handle->sram_workspace_addr == NULL_SRAM_ADDR) {
+ SSI_LOG_ERR("SRAM pool exhausted\n");
+ rc = -ENOMEM;
+ goto fail1;
+ }
+
+ INIT_LIST_HEAD(&aead_handle->aead_list);
+
+ /* Linux crypto */
+ for (alg = 0; alg < ARRAY_SIZE(aead_algs); alg++) {
+ t_alg = ssi_aead_create_alg(&aead_algs[alg]);
+ if (IS_ERR(t_alg)) {
+ rc = PTR_ERR(t_alg);
+ SSI_LOG_ERR("%s alg allocation failed\n",
+ aead_algs[alg].driver_name);
+ goto fail1;
+ }
+ t_alg->drvdata = drvdata;
+ rc = crypto_register_aead(&t_alg->aead_alg);
+ if (unlikely(rc != 0)) {
+ SSI_LOG_ERR("%s alg registration failed\n",
+ t_alg->aead_alg.base.cra_driver_name);
+ goto fail2;
+ } else {
+ list_add_tail(&t_alg->entry, &aead_handle->aead_list);
+ SSI_LOG_DEBUG("Registered %s\n", t_alg->aead_alg.base.cra_driver_name);
+ }
+ }
+
+ return 0;
+
+fail2:
+ kfree(t_alg);
+fail1:
+ ssi_aead_free(drvdata);
+fail0:
+ return rc;
+}
+
+
+
diff --git a/drivers/staging/ccree/ssi_aead.h b/drivers/staging/ccree/ssi_aead.h
new file mode 100644
index 0000000..fe88c9e
--- /dev/null
+++ b/drivers/staging/ccree/ssi_aead.h
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2012-2017 ARM Limited or its affiliates.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* \file ssi_aead.h
+ ARM CryptoCell AEAD Crypto API
+ */
+
+#ifndef __SSI_AEAD_H__
+#define __SSI_AEAD_H__
+
+#include <linux/kernel.h>
+#include <crypto/algapi.h>
+#include <crypto/ctr.h>
+
+
+/* mac_cmp - HW writes 8 B but all bytes hold the same value */
+#define ICV_CMP_SIZE 8
+#define CCM_CONFIG_BUF_SIZE (AES_BLOCK_SIZE*3)
+#define MAX_MAC_SIZE MAX(SHA256_DIGEST_SIZE, AES_BLOCK_SIZE)
+
+
+/* defines for AES GCM configuration buffer */
+#define GCM_BLOCK_LEN_SIZE 8
+
+#define GCM_BLOCK_RFC4_IV_OFFSET 4
+#define GCM_BLOCK_RFC4_IV_SIZE 8 /* IV size for rfc's */
+#define GCM_BLOCK_RFC4_NONCE_OFFSET 0
+#define GCM_BLOCK_RFC4_NONCE_SIZE 4
+
+
+
+/* Offsets into AES CCM configuration buffer */
+#define CCM_B0_OFFSET 0
+#define CCM_A0_OFFSET 16
+#define CCM_CTR_COUNT_0_OFFSET 32
+/* CCM B0 and CTR_COUNT constants. */
+#define CCM_BLOCK_NONCE_OFFSET 1 /* Nonce offset inside B0 and CTR_COUNT */
+#define CCM_BLOCK_NONCE_SIZE 3 /* Nonce size inside B0 and CTR_COUNT */
+#define CCM_BLOCK_IV_OFFSET 4 /* IV offset inside B0 and CTR_COUNT */
+#define CCM_BLOCK_IV_SIZE 8 /* IV size inside B0 and CTR_COUNT */
+
+enum aead_ccm_header_size {
+ ccm_header_size_null = -1,
+ ccm_header_size_zero = 0,
+ ccm_header_size_2 = 2,
+ ccm_header_size_6 = 6,
+ ccm_header_size_max = INT32_MAX
+};
+
+struct aead_req_ctx {
+ /* Allocate cache line although only 4 bytes are needed to
+ * assure next field falls @ cache line
+ * Used for both: digest HW compare and CCM/GCM MAC value */
+ uint8_t mac_buf[MAX_MAC_SIZE] ____cacheline_aligned;
+ uint8_t ctr_iv[AES_BLOCK_SIZE] ____cacheline_aligned;
+
+ //used in gcm
+ uint8_t gcm_iv_inc1[AES_BLOCK_SIZE] ____cacheline_aligned;
+ uint8_t gcm_iv_inc2[AES_BLOCK_SIZE] ____cacheline_aligned;
+ uint8_t hkey[AES_BLOCK_SIZE] ____cacheline_aligned;
+ struct {
+ uint8_t lenA[GCM_BLOCK_LEN_SIZE] ____cacheline_aligned;
+ uint8_t lenC[GCM_BLOCK_LEN_SIZE] ;
+ } gcm_len_block;
+
+ uint8_t ccm_config[CCM_CONFIG_BUF_SIZE] ____cacheline_aligned;
+ unsigned int hw_iv_size ____cacheline_aligned; /*HW actual size input*/
+ uint8_t backup_mac[MAX_MAC_SIZE]; /*used to prevent cache coherence problem*/
+ uint8_t *backup_iv; /*store iv for generated IV flow*/
+ uint8_t *backup_giv; /*store iv for rfc3686(ctr) flow*/
+ dma_addr_t mac_buf_dma_addr; /* internal ICV DMA buffer */
+ dma_addr_t ccm_iv0_dma_addr; /* buffer for internal ccm configurations */
+ dma_addr_t icv_dma_addr; /* Phys. address of ICV */
+
+ //used in gcm
+ dma_addr_t gcm_iv_inc1_dma_addr; /* buffer for internal gcm configurations */
+ dma_addr_t gcm_iv_inc2_dma_addr; /* buffer for internal gcm configurations */
+ dma_addr_t hkey_dma_addr; /* Phys. address of hkey */
+ dma_addr_t gcm_block_len_dma_addr; /* Phys. address of gcm block len */
+ bool is_gcm4543;
+
+ uint8_t *icv_virt_addr; /* Virt. address of ICV */
+ struct async_gen_req_ctx gen_ctx;
+ struct ssi_mlli assoc;
+ struct ssi_mlli src;
+ struct ssi_mlli dst;
+ struct scatterlist* srcSgl;
+ struct scatterlist* dstSgl;
+ unsigned int srcOffset;
+ unsigned int dstOffset;
+ enum ssi_req_dma_buf_type assoc_buff_type;
+ enum ssi_req_dma_buf_type data_buff_type;
+ struct mlli_params mlli_params;
+ unsigned int cryptlen;
+ struct scatterlist ccm_adata_sg;
+ enum aead_ccm_header_size ccm_hdr_size;
+ unsigned int req_authsize;
+ enum drv_cipher_mode cipher_mode;
+ bool is_icv_fragmented;
+ bool is_single_pass;
+ bool plaintext_authenticate_only; //for gcm_rfc4543
+};
+
+int ssi_aead_alloc(struct ssi_drvdata *drvdata);
+int ssi_aead_free(struct ssi_drvdata *drvdata);
+
+#endif /*__SSI_AEAD_H__*/
diff --git a/drivers/staging/ccree/ssi_buffer_mgr.c b/drivers/staging/ccree/ssi_buffer_mgr.c
new file mode 100644
index 0000000..038e2ff
--- /dev/null
+++ b/drivers/staging/ccree/ssi_buffer_mgr.c
@@ -0,0 +1,1873 @@
+/*
+ * Copyright (C) 2012-2017 ARM Limited or its affiliates.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/crypto.h>
+#include <linux/version.h>
+#include <crypto/algapi.h>
+#include <crypto/internal/aead.h>
+#include <crypto/hash.h>
+#include <crypto/authenc.h>
+#include <crypto/scatterwalk.h>
+#include <linux/dmapool.h>
+#include <linux/dma-mapping.h>
+#include <linux/crypto.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include "ssi_buffer_mgr.h"
+#include "cc_lli_defs.h"
+#include "ssi_cipher.h"
+#include "ssi_hash.h"
+#include "ssi_aead.h"
+
+#define LLI_MAX_NUM_OF_DATA_ENTRIES 128
+#define LLI_MAX_NUM_OF_ASSOC_DATA_ENTRIES 4
+#define MLLI_TABLE_MIN_ALIGNMENT 4 /*Force the MLLI table to be align to uint32 */
+#define MAX_NUM_OF_BUFFERS_IN_MLLI 4
+#define MAX_NUM_OF_TOTAL_MLLI_ENTRIES (2*LLI_MAX_NUM_OF_DATA_ENTRIES + \
+ LLI_MAX_NUM_OF_ASSOC_DATA_ENTRIES )
+
+#ifdef CC_DEBUG
+#define DUMP_SGL(sg) \
+ while (sg) { \
+ SSI_LOG_DEBUG("page=%lu offset=%u length=%u (dma_len=%u) " \
+ "dma_addr=%08x\n", (sg)->page_link, (sg)->offset, \
+ (sg)->length, sg_dma_len(sg), (sg)->dma_address); \
+ (sg) = sg_next(sg); \
+ }
+#define DUMP_MLLI_TABLE(mlli_p, nents) \
+ do { \
+ SSI_LOG_DEBUG("mlli=%pK nents=%u\n", (mlli_p), (nents)); \
+ while((nents)--) { \
+ SSI_LOG_DEBUG("addr=0x%08X size=0x%08X\n", \
+ (mlli_p)[LLI_WORD0_OFFSET], \
+ (mlli_p)[LLI_WORD1_OFFSET]); \
+ (mlli_p) += LLI_ENTRY_WORD_SIZE; \
+ } \
+ } while (0)
+#define GET_DMA_BUFFER_TYPE(buff_type) ( \
+ ((buff_type) == SSI_DMA_BUF_NULL) ? "BUF_NULL" : \
+ ((buff_type) == SSI_DMA_BUF_DLLI) ? "BUF_DLLI" : \
+ ((buff_type) == SSI_DMA_BUF_MLLI) ? "BUF_MLLI" : "BUF_INVALID")
+#else
+#define DX_BUFFER_MGR_DUMP_SGL(sg)
+#define DX_BUFFER_MGR_DUMP_MLLI_TABLE(mlli_p, nents)
+#define GET_DMA_BUFFER_TYPE(buff_type)
+#endif
+
+
+enum dma_buffer_type {
+ DMA_NULL_TYPE = -1,
+ DMA_SGL_TYPE = 1,
+ DMA_BUFF_TYPE = 2,
+};
+
+struct buff_mgr_handle {
+ struct dma_pool *mlli_buffs_pool;
+};
+
+union buffer_array_entry {
+ struct scatterlist *sgl;
+ dma_addr_t buffer_dma;
+};
+
+struct buffer_array {
+ unsigned int num_of_buffers;
+ union buffer_array_entry entry[MAX_NUM_OF_BUFFERS_IN_MLLI];
+ unsigned int offset[MAX_NUM_OF_BUFFERS_IN_MLLI];
+ int nents[MAX_NUM_OF_BUFFERS_IN_MLLI];
+ int total_data_len[MAX_NUM_OF_BUFFERS_IN_MLLI];
+ enum dma_buffer_type type[MAX_NUM_OF_BUFFERS_IN_MLLI];
+ bool is_last[MAX_NUM_OF_BUFFERS_IN_MLLI];
+ uint32_t * mlli_nents[MAX_NUM_OF_BUFFERS_IN_MLLI];
+};
+
+#ifdef CC_DMA_48BIT_SIM
+dma_addr_t ssi_buff_mgr_update_dma_addr(dma_addr_t orig_addr, uint32_t data_len)
+{
+ dma_addr_t tmp_dma_addr;
+#ifdef CC_DMA_48BIT_SIM_FULL
+ /* With this code all addresses will be switched to 48 bits. */
+ /* The if condition protects from double expention */
+ if((((orig_addr >> 16) & 0xFFFF) != 0xFFFF) &&
+ (data_len <= CC_MAX_MLLI_ENTRY_SIZE)) {
+#else
+ if((!(((orig_addr >> 16) & 0xFF) % 2)) &&
+ (data_len <= CC_MAX_MLLI_ENTRY_SIZE)) {
+#endif
+ tmp_dma_addr = ((orig_addr<<16) | 0xFFFF0000 |
+ (orig_addr & UINT16_MAX));
+ SSI_LOG_DEBUG("MAP DMA: orig address=0x%llX "
+ "dma_address=0x%llX\n",
+ orig_addr, tmp_dma_addr);
+ return tmp_dma_addr;
+ }
+ return orig_addr;
+}
+
+dma_addr_t ssi_buff_mgr_restore_dma_addr(dma_addr_t orig_addr)
+{
+ dma_addr_t tmp_dma_addr;
+#ifdef CC_DMA_48BIT_SIM_FULL
+ /* With this code all addresses will be restored from 48 bits. */
+ /* The if condition protects from double restoring */
+ if((orig_addr >> 32) & 0xFFFF ) {
+#else
+ if(((orig_addr >> 32) & 0xFFFF) &&
+ !(((orig_addr >> 32) & 0xFF) % 2) ) {
+#endif
+ /*return high 16 bits*/
+ tmp_dma_addr = ((orig_addr >> 16));
+ /*clean the 0xFFFF in the lower bits (set in the add expansion)*/
+ tmp_dma_addr &= 0xFFFF0000;
+ /* Set the original 16 bits */
+ tmp_dma_addr |= (orig_addr & UINT16_MAX);
+ SSI_LOG_DEBUG("Release DMA: orig address=0x%llX "
+ "dma_address=0x%llX\n",
+ orig_addr, tmp_dma_addr);
+ return tmp_dma_addr;
+ }
+ return orig_addr;
+}
+#endif
+/**
+ * ssi_buffer_mgr_get_sgl_nents() - Get scatterlist number of entries.
+ *
+ * @sg_list: SG list
+ * @nbytes: [IN] Total SGL data bytes.
+ * @lbytes: [OUT] Returns the amount of bytes at the last entry
+ */
+static unsigned int ssi_buffer_mgr_get_sgl_nents(
+ struct scatterlist *sg_list, unsigned int nbytes, uint32_t *lbytes, bool *is_chained)
+{
+ unsigned int nents = 0;
+ while (nbytes != 0) {
+ if (sg_is_chain(sg_list)) {
+ SSI_LOG_ERR("Unexpected chanined entry "
+ "in sg (entry =0x%X) \n", nents);
+ BUG();
+ }
+ if (sg_list->length != 0) {
+ nents++;
+ /* get the number of bytes in the last entry */
+ *lbytes = nbytes;
+ nbytes -= ( sg_list->length > nbytes ) ? nbytes : sg_list->length;
+ sg_list = sg_next(sg_list);
+ } else {
+ sg_list = (struct scatterlist *)sg_page(sg_list);
+ if (is_chained != NULL) {
+ *is_chained = true;
+ }
+ }
+ }
+ SSI_LOG_DEBUG("nents %d last bytes %d\n",nents, *lbytes);
+ return nents;
+}
+
+/**
+ * ssi_buffer_mgr_zero_sgl() - Zero scatter scatter list data.
+ *
+ * @sgl:
+ */
+void ssi_buffer_mgr_zero_sgl(struct scatterlist *sgl, uint32_t data_len)
+{
+ struct scatterlist *current_sg = sgl;
+ int sg_index = 0;
+
+ while (sg_index <= data_len) {
+ if (current_sg == NULL) {
+ /* reached the end of the sgl --> just return back */
+ return;
+ }
+ memset(sg_virt(current_sg), 0, current_sg->length);
+ sg_index += current_sg->length;
+ current_sg = sg_next(current_sg);
+ }
+}
+
+/**
+ * ssi_buffer_mgr_copy_scatterlist_portion() - Copy scatter list data,
+ * from to_skip to end, to dest and vice versa
+ *
+ * @dest:
+ * @sg:
+ * @to_skip:
+ * @end:
+ * @direct:
+ */
+void ssi_buffer_mgr_copy_scatterlist_portion(
+ u8 *dest, struct scatterlist *sg,
+ uint32_t to_skip, uint32_t end,
+ enum ssi_sg_cpy_direct direct)
+{
+ uint32_t nents, lbytes;
+
+ nents = ssi_buffer_mgr_get_sgl_nents(sg, end, &lbytes, NULL);
+ sg_copy_buffer(sg, nents, (void *)dest, (end - to_skip), 0, (direct == SSI_SG_TO_BUF));
+}
+
+static inline int ssi_buffer_mgr_render_buff_to_mlli(
+ dma_addr_t buff_dma, uint32_t buff_size, uint32_t *curr_nents,
+ uint32_t **mlli_entry_pp)
+{
+ uint32_t *mlli_entry_p = *mlli_entry_pp;
+ uint32_t new_nents;;
+
+ /* Verify there is no memory overflow*/
+ new_nents = (*curr_nents + buff_size/CC_MAX_MLLI_ENTRY_SIZE + 1);
+ if (new_nents > MAX_NUM_OF_TOTAL_MLLI_ENTRIES ) {
+ return -ENOMEM;
+ }
+
+ /*handle buffer longer than 64 kbytes */
+ while (buff_size > CC_MAX_MLLI_ENTRY_SIZE ) {
+ SSI_UPDATE_DMA_ADDR_TO_48BIT(buff_dma, CC_MAX_MLLI_ENTRY_SIZE);
+ LLI_SET_ADDR(mlli_entry_p,buff_dma);
+ LLI_SET_SIZE(mlli_entry_p, CC_MAX_MLLI_ENTRY_SIZE);
+ SSI_LOG_DEBUG("entry[%d]: single_buff=0x%08X size=%08X\n",*curr_nents,
+ mlli_entry_p[LLI_WORD0_OFFSET],
+ mlli_entry_p[LLI_WORD1_OFFSET]);
+ SSI_RESTORE_DMA_ADDR_TO_48BIT(buff_dma);
+ buff_dma += CC_MAX_MLLI_ENTRY_SIZE;
+ buff_size -= CC_MAX_MLLI_ENTRY_SIZE;
+ mlli_entry_p = mlli_entry_p + 2;
+ (*curr_nents)++;
+ }
+ /*Last entry */
+ SSI_UPDATE_DMA_ADDR_TO_48BIT(buff_dma, buff_size);
+ LLI_SET_ADDR(mlli_entry_p,buff_dma);
+ LLI_SET_SIZE(mlli_entry_p, buff_size);
+ SSI_LOG_DEBUG("entry[%d]: single_buff=0x%08X size=%08X\n",*curr_nents,
+ mlli_entry_p[LLI_WORD0_OFFSET],
+ mlli_entry_p[LLI_WORD1_OFFSET]);
+ mlli_entry_p = mlli_entry_p + 2;
+ *mlli_entry_pp = mlli_entry_p;
+ (*curr_nents)++;
+ return 0;
+}
+
+
+static inline int ssi_buffer_mgr_render_scatterlist_to_mlli(
+ struct scatterlist *sgl, uint32_t sgl_data_len, uint32_t sglOffset, uint32_t *curr_nents,
+ uint32_t **mlli_entry_pp)
+{
+ struct scatterlist *curr_sgl = sgl;
+ uint32_t *mlli_entry_p = *mlli_entry_pp;
+ int32_t rc = 0;
+
+ for ( ; (curr_sgl != NULL) && (sgl_data_len != 0);
+ curr_sgl = sg_next(curr_sgl)) {
+ uint32_t entry_data_len =
+ (sgl_data_len > sg_dma_len(curr_sgl) - sglOffset) ?
+ sg_dma_len(curr_sgl) - sglOffset : sgl_data_len ;
+ sgl_data_len -= entry_data_len;
+ rc = ssi_buffer_mgr_render_buff_to_mlli(
+ sg_dma_address(curr_sgl) + sglOffset, entry_data_len, curr_nents,
+ &mlli_entry_p);
+ if(rc != 0) {
+ return rc;
+ }
+ sglOffset=0;
+ }
+ *mlli_entry_pp = mlli_entry_p;
+ return 0;
+}
+
+static int ssi_buffer_mgr_generate_mlli(
+ struct device *dev,
+ struct buffer_array *sg_data,
+ struct mlli_params *mlli_params)
+{
+ uint32_t *mlli_p;
+ uint32_t total_nents = 0,prev_total_nents = 0;
+ int rc = 0, i;
+
+ SSI_LOG_DEBUG("NUM of SG's = %d\n", sg_data->num_of_buffers);
+
+ /* Allocate memory from the pointed pool */
+ mlli_params->mlli_virt_addr = dma_pool_alloc(
+ mlli_params->curr_pool, GFP_KERNEL,
+ &(mlli_params->mlli_dma_addr));
+ if (unlikely(mlli_params->mlli_virt_addr == NULL)) {
+ SSI_LOG_ERR("dma_pool_alloc() failed\n");
+ rc =-ENOMEM;
+ goto build_mlli_exit;
+ }
+ SSI_UPDATE_DMA_ADDR_TO_48BIT(mlli_params->mlli_dma_addr,
+ (MAX_NUM_OF_TOTAL_MLLI_ENTRIES*
+ LLI_ENTRY_BYTE_SIZE));
+ /* Point to start of MLLI */
+ mlli_p = (uint32_t *)mlli_params->mlli_virt_addr;
+ /* go over all SG's and link it to one MLLI table */
+ for (i = 0; i < sg_data->num_of_buffers; i++) {
+ if (sg_data->type[i] == DMA_SGL_TYPE)
+ rc = ssi_buffer_mgr_render_scatterlist_to_mlli(
+ sg_data->entry[i].sgl,
+ sg_data->total_data_len[i], sg_data->offset[i], &total_nents,
+ &mlli_p);
+ else /*DMA_BUFF_TYPE*/
+ rc = ssi_buffer_mgr_render_buff_to_mlli(
+ sg_data->entry[i].buffer_dma,
+ sg_data->total_data_len[i], &total_nents,
+ &mlli_p);
+ if(rc != 0) {
+ return rc;
+ }
+
+ /* set last bit in the current table */
+ if (sg_data->mlli_nents[i] != NULL) {
+ /*Calculate the current MLLI table length for the
+ length field in the descriptor*/
+ *(sg_data->mlli_nents[i]) +=
+ (total_nents - prev_total_nents);
+ prev_total_nents = total_nents;
+ }
+ }
+
+ /* Set MLLI size for the bypass operation */
+ mlli_params->mlli_len = (total_nents * LLI_ENTRY_BYTE_SIZE);
+
+ SSI_LOG_DEBUG("MLLI params: "
+ "virt_addr=%pK dma_addr=0x%llX mlli_len=0x%X\n",
+ mlli_params->mlli_virt_addr,
+ (unsigned long long)mlli_params->mlli_dma_addr,
+ mlli_params->mlli_len);
+
+build_mlli_exit:
+ return rc;
+}
+
+static inline void ssi_buffer_mgr_add_buffer_entry(
+ struct buffer_array *sgl_data,
+ dma_addr_t buffer_dma, unsigned int buffer_len,
+ bool is_last_entry, uint32_t *mlli_nents)
+{
+ unsigned int index = sgl_data->num_of_buffers;
+
+ SSI_LOG_DEBUG("index=%u single_buff=0x%llX "
+ "buffer_len=0x%08X is_last=%d\n",
+ index, (unsigned long long)buffer_dma, buffer_len, is_last_entry);
+ sgl_data->nents[index] = 1;
+ sgl_data->entry[index].buffer_dma = buffer_dma;
+ sgl_data->offset[index] = 0;
+ sgl_data->total_data_len[index] = buffer_len;
+ sgl_data->type[index] = DMA_BUFF_TYPE;
+ sgl_data->is_last[index] = is_last_entry;
+ sgl_data->mlli_nents[index] = mlli_nents;
+ if (sgl_data->mlli_nents[index] != NULL)
+ *sgl_data->mlli_nents[index] = 0;
+ sgl_data->num_of_buffers++;
+}
+
+static inline void ssi_buffer_mgr_add_scatterlist_entry(
+ struct buffer_array *sgl_data,
+ unsigned int nents,
+ struct scatterlist *sgl,
+ unsigned int data_len,
+ unsigned int data_offset,
+ bool is_last_table,
+ uint32_t *mlli_nents)
+{
+ unsigned int index = sgl_data->num_of_buffers;
+
+ SSI_LOG_DEBUG("index=%u nents=%u sgl=%pK data_len=0x%08X is_last=%d\n",
+ index, nents, sgl, data_len, is_last_table);
+ sgl_data->nents[index] = nents;
+ sgl_data->entry[index].sgl = sgl;
+ sgl_data->offset[index] = data_offset;
+ sgl_data->total_data_len[index] = data_len;
+ sgl_data->type[index] = DMA_SGL_TYPE;
+ sgl_data->is_last[index] = is_last_table;
+ sgl_data->mlli_nents[index] = mlli_nents;
+ if (sgl_data->mlli_nents[index] != NULL)
+ *sgl_data->mlli_nents[index] = 0;
+ sgl_data->num_of_buffers++;
+}
+
+static int
+ssi_buffer_mgr_dma_map_sg(struct device *dev, struct scatterlist *sg, uint32_t nents,
+ enum dma_data_direction direction)
+{
+ uint32_t i , j;
+ struct scatterlist *l_sg = sg;
+ for (i = 0; i < nents; i++) {
+ if (l_sg == NULL) {
+ break;
+ }
+ if (unlikely(dma_map_sg(dev, l_sg, 1, direction) != 1)){
+ SSI_LOG_ERR("dma_map_page() sg buffer failed\n");
+ goto err;
+ }
+ l_sg = sg_next(l_sg);
+ }
+ return nents;
+
+err:
+ /* Restore mapped parts */
+ for (j = 0; j < i; j++) {
+ if (sg == NULL) {
+ break;
+ }
+ dma_unmap_sg(dev,sg,1,direction);
+ sg = sg_next(sg);
+ }
+ return 0;
+}
+
+static int ssi_buffer_mgr_map_scatterlist(
+ struct device *dev, struct scatterlist *sg,
+ unsigned int nbytes, int direction,
+ uint32_t *nents, uint32_t max_sg_nents,
+ uint32_t *lbytes, uint32_t *mapped_nents)
+{
+ bool is_chained = false;
+
+ if (sg_is_last(sg)) {
+ /* One entry only case -set to DLLI */
+ if (unlikely(dma_map_sg(dev, sg, 1, direction) != 1)) {
+ SSI_LOG_ERR("dma_map_sg() single buffer failed\n");
+ return -ENOMEM;
+ }
+ SSI_LOG_DEBUG("Mapped sg: dma_address=0x%llX "
+ "page_link=0x%08lX addr=%pK offset=%u "
+ "length=%u\n",
+ (unsigned long long)sg_dma_address(sg),
+ sg->page_link,
+ sg_virt(sg),
+ sg->offset, sg->length);
+ *lbytes = nbytes;
+ *nents = 1;
+ *mapped_nents = 1;
+ SSI_UPDATE_DMA_ADDR_TO_48BIT(sg_dma_address(sg), sg_dma_len(sg));
+ } else { /*sg_is_last*/
+ *nents = ssi_buffer_mgr_get_sgl_nents(sg, nbytes, lbytes,
+ &is_chained);
+ if (*nents > max_sg_nents) {
+ *nents = 0;
+ SSI_LOG_ERR("Too many fragments. current %d max %d\n",
+ *nents, max_sg_nents);
+ return -ENOMEM;
+ }
+ if (!is_chained) {
+ /* In case of mmu the number of mapped nents might
+ be changed from the original sgl nents */
+ *mapped_nents = dma_map_sg(dev, sg, *nents, direction);
+ if (unlikely(*mapped_nents == 0)){
+ *nents = 0;
+ SSI_LOG_ERR("dma_map_sg() sg buffer failed\n");
+ return -ENOMEM;
+ }
+ } else {
+ /*In this case the driver maps entry by entry so it
+ must have the same nents before and after map */
+ *mapped_nents = ssi_buffer_mgr_dma_map_sg(dev,
+ sg,
+ *nents,
+ direction);
+ if (unlikely(*mapped_nents != *nents)){
+ *nents = *mapped_nents;
+ SSI_LOG_ERR("dma_map_sg() sg buffer failed\n");
+ return -ENOMEM;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static inline int
+ssi_aead_handle_config_buf(struct device *dev,
+ struct aead_req_ctx *areq_ctx,
+ uint8_t* config_data,
+ struct buffer_array *sg_data,
+ unsigned int assoclen)
+{
+ SSI_LOG_DEBUG(" handle additional data config set to DLLI \n");
+ /* create sg for the current buffer */
+ sg_init_one(&areq_ctx->ccm_adata_sg, config_data, AES_BLOCK_SIZE + areq_ctx->ccm_hdr_size);
+ if (unlikely(dma_map_sg(dev, &areq_ctx->ccm_adata_sg, 1,
+ DMA_TO_DEVICE) != 1)) {
+ SSI_LOG_ERR("dma_map_sg() "
+ "config buffer failed\n");
+ return -ENOMEM;
+ }
+ SSI_LOG_DEBUG("Mapped curr_buff: dma_address=0x%llX "
+ "page_link=0x%08lX addr=%pK "
+ "offset=%u length=%u\n",
+ (unsigned long long)sg_dma_address(&areq_ctx->ccm_adata_sg),
+ areq_ctx->ccm_adata_sg.page_link,
+ sg_virt(&areq_ctx->ccm_adata_sg),
+ areq_ctx->ccm_adata_sg.offset,
+ areq_ctx->ccm_adata_sg.length);
+ /* prepare for case of MLLI */
+ if (assoclen > 0) {
+ ssi_buffer_mgr_add_scatterlist_entry(sg_data, 1,
+ &areq_ctx->ccm_adata_sg,
+ (AES_BLOCK_SIZE +
+ areq_ctx->ccm_hdr_size), 0,
+ false, NULL);
+ }
+ return 0;
+}
+
+
+static inline int ssi_ahash_handle_curr_buf(struct device *dev,
+ struct ahash_req_ctx *areq_ctx,
+ uint8_t* curr_buff,
+ uint32_t curr_buff_cnt,
+ struct buffer_array *sg_data)
+{
+ SSI_LOG_DEBUG(" handle curr buff %x set to DLLI \n", curr_buff_cnt);
+ /* create sg for the current buffer */
+ sg_init_one(areq_ctx->buff_sg,curr_buff, curr_buff_cnt);
+ if (unlikely(dma_map_sg(dev, areq_ctx->buff_sg, 1,
+ DMA_TO_DEVICE) != 1)) {
+ SSI_LOG_ERR("dma_map_sg() "
+ "src buffer failed\n");
+ return -ENOMEM;
+ }
+ SSI_LOG_DEBUG("Mapped curr_buff: dma_address=0x%llX "
+ "page_link=0x%08lX addr=%pK "
+ "offset=%u length=%u\n",
+ (unsigned long long)sg_dma_address(areq_ctx->buff_sg),
+ areq_ctx->buff_sg->page_link,
+ sg_virt(areq_ctx->buff_sg),
+ areq_ctx->buff_sg->offset,
+ areq_ctx->buff_sg->length);
+ areq_ctx->data_dma_buf_type = SSI_DMA_BUF_DLLI;
+ areq_ctx->curr_sg = areq_ctx->buff_sg;
+ areq_ctx->in_nents = 0;
+ /* prepare for case of MLLI */
+ ssi_buffer_mgr_add_scatterlist_entry(sg_data, 1, areq_ctx->buff_sg,
+ curr_buff_cnt, 0, false, NULL);
+ return 0;
+}
+
+void ssi_buffer_mgr_unmap_blkcipher_request(
+ struct device *dev,
+ void *ctx,
+ unsigned int ivsize,
+ struct scatterlist *src,
+ struct scatterlist *dst)
+{
+ struct blkcipher_req_ctx *req_ctx = (struct blkcipher_req_ctx *)ctx;
+
+ if (likely(req_ctx->gen_ctx.iv_dma_addr != 0)) {
+ SSI_LOG_DEBUG("Unmapped iv: iv_dma_addr=0x%llX iv_size=%u\n",
+ (unsigned long long)req_ctx->gen_ctx.iv_dma_addr,
+ ivsize);
+ SSI_RESTORE_DMA_ADDR_TO_48BIT(req_ctx->gen_ctx.iv_dma_addr);
+ dma_unmap_single(dev, req_ctx->gen_ctx.iv_dma_addr,
+ ivsize,
+ req_ctx->is_giv ? DMA_BIDIRECTIONAL :
+ DMA_TO_DEVICE);
+ }
+ /* Release pool */
+ if (req_ctx->dma_buf_type == SSI_DMA_BUF_MLLI) {
+ SSI_RESTORE_DMA_ADDR_TO_48BIT(req_ctx->mlli_params.mlli_dma_addr);
+ dma_pool_free(req_ctx->mlli_params.curr_pool,
+ req_ctx->mlli_params.mlli_virt_addr,
+ req_ctx->mlli_params.mlli_dma_addr);
+ }
+
+ SSI_RESTORE_DMA_ADDR_TO_48BIT(sg_dma_address(src));
+ dma_unmap_sg(dev, src, req_ctx->in_nents,
+ DMA_BIDIRECTIONAL);
+ SSI_LOG_DEBUG("Unmapped req->src=%pK\n",
+ sg_virt(src));
+
+ if (src != dst) {
+ SSI_RESTORE_DMA_ADDR_TO_48BIT(sg_dma_address(dst));
+ dma_unmap_sg(dev, dst, req_ctx->out_nents,
+ DMA_BIDIRECTIONAL);
+ SSI_LOG_DEBUG("Unmapped req->dst=%pK\n",
+ sg_virt(dst));
+ }
+}
+
+int ssi_buffer_mgr_map_blkcipher_request(
+ struct ssi_drvdata *drvdata,
+ void *ctx,
+ unsigned int ivsize,
+ unsigned int nbytes,
+ void *info,
+ struct scatterlist *src,
+ struct scatterlist *dst)
+{
+ struct blkcipher_req_ctx *req_ctx = (struct blkcipher_req_ctx *)ctx;
+ struct mlli_params *mlli_params = &req_ctx->mlli_params;
+ struct buff_mgr_handle *buff_mgr = drvdata->buff_mgr_handle;
+ struct device *dev = &drvdata->plat_dev->dev;
+ struct buffer_array sg_data;
+ uint32_t dummy = 0;
+ int rc = 0;
+ uint32_t mapped_nents = 0;
+
+ req_ctx->dma_buf_type = SSI_DMA_BUF_DLLI;
+ mlli_params->curr_pool = NULL;
+ sg_data.num_of_buffers = 0;
+
+ /* Map IV buffer */
+ if (likely(ivsize != 0) ) {
+ dump_byte_array("iv", (uint8_t *)info, ivsize);
+ req_ctx->gen_ctx.iv_dma_addr =
+ dma_map_single(dev, (void *)info,
+ ivsize,
+ req_ctx->is_giv ? DMA_BIDIRECTIONAL:
+ DMA_TO_DEVICE);
+ if (unlikely(dma_mapping_error(dev,
+ req_ctx->gen_ctx.iv_dma_addr))) {
+ SSI_LOG_ERR("Mapping iv %u B at va=%pK "
+ "for DMA failed\n", ivsize, info);
+ return -ENOMEM;
+ }
+ SSI_UPDATE_DMA_ADDR_TO_48BIT(req_ctx->gen_ctx.iv_dma_addr,
+ ivsize);
+ SSI_LOG_DEBUG("Mapped iv %u B at va=%pK to dma=0x%llX\n",
+ ivsize, info,
+ (unsigned long long)req_ctx->gen_ctx.iv_dma_addr);
+ } else
+ req_ctx->gen_ctx.iv_dma_addr = 0;
+
+ /* Map the src SGL */
+ rc = ssi_buffer_mgr_map_scatterlist(dev, src,
+ nbytes, DMA_BIDIRECTIONAL, &req_ctx->in_nents,
+ LLI_MAX_NUM_OF_DATA_ENTRIES, &dummy, &mapped_nents);
+ if (unlikely(rc != 0)) {
+ rc = -ENOMEM;
+ goto ablkcipher_exit;
+ }
+ if (mapped_nents > 1)
+ req_ctx->dma_buf_type = SSI_DMA_BUF_MLLI;
+
+ if (unlikely(src == dst)) {
+ /* Handle inplace operation */
+ if (unlikely(req_ctx->dma_buf_type == SSI_DMA_BUF_MLLI)) {
+ req_ctx->out_nents = 0;
+ ssi_buffer_mgr_add_scatterlist_entry(&sg_data,
+ req_ctx->in_nents, src,
+ nbytes, 0, true, &req_ctx->in_mlli_nents);
+ }
+ } else {
+ /* Map the dst sg */
+ if (unlikely(ssi_buffer_mgr_map_scatterlist(
+ dev,dst, nbytes,
+ DMA_BIDIRECTIONAL, &req_ctx->out_nents,
+ LLI_MAX_NUM_OF_DATA_ENTRIES, &dummy,
+ &mapped_nents))){
+ rc = -ENOMEM;
+ goto ablkcipher_exit;
+ }
+ if (mapped_nents > 1)
+ req_ctx->dma_buf_type = SSI_DMA_BUF_MLLI;
+
+ if (unlikely((req_ctx->dma_buf_type == SSI_DMA_BUF_MLLI))) {
+ ssi_buffer_mgr_add_scatterlist_entry(&sg_data,
+ req_ctx->in_nents, src,
+ nbytes, 0, true,
+ &req_ctx->in_mlli_nents);
+ ssi_buffer_mgr_add_scatterlist_entry(&sg_data,
+ req_ctx->out_nents, dst,
+ nbytes, 0, true,
+ &req_ctx->out_mlli_nents);
+ }
+ }
+
+ if (unlikely(req_ctx->dma_buf_type == SSI_DMA_BUF_MLLI)) {
+ mlli_params->curr_pool = buff_mgr->mlli_buffs_pool;
+ rc = ssi_buffer_mgr_generate_mlli(dev, &sg_data, mlli_params);
+ if (unlikely(rc!= 0))
+ goto ablkcipher_exit;
+
+ }
+
+ SSI_LOG_DEBUG("areq_ctx->dma_buf_type = %s\n",
+ GET_DMA_BUFFER_TYPE(req_ctx->dma_buf_type));
+
+ return 0;
+
+ablkcipher_exit:
+ ssi_buffer_mgr_unmap_blkcipher_request(dev, req_ctx, ivsize, src, dst);
+ return rc;
+}
+
+void ssi_buffer_mgr_unmap_aead_request(
+ struct device *dev, struct aead_request *req)
+{
+ struct aead_req_ctx *areq_ctx = aead_request_ctx(req);
+ unsigned int hw_iv_size = areq_ctx->hw_iv_size;
+ struct crypto_aead *tfm = crypto_aead_reqtfm(req);
+ uint32_t dummy;
+ bool chained;
+ uint32_t size_to_unmap = 0;
+
+ if (areq_ctx->mac_buf_dma_addr != 0) {
+ SSI_RESTORE_DMA_ADDR_TO_48BIT(areq_ctx->mac_buf_dma_addr);
+ dma_unmap_single(dev, areq_ctx->mac_buf_dma_addr,
+ MAX_MAC_SIZE, DMA_BIDIRECTIONAL);
+ }
+
+#if SSI_CC_HAS_AES_GCM
+ if (areq_ctx->cipher_mode == DRV_CIPHER_GCTR) {
+ if (areq_ctx->hkey_dma_addr != 0) {
+ SSI_RESTORE_DMA_ADDR_TO_48BIT(areq_ctx->hkey_dma_addr);
+ dma_unmap_single(dev, areq_ctx->hkey_dma_addr,
+ AES_BLOCK_SIZE, DMA_BIDIRECTIONAL);
+ }
+
+ if (areq_ctx->gcm_block_len_dma_addr != 0) {
+ SSI_RESTORE_DMA_ADDR_TO_48BIT(areq_ctx->gcm_block_len_dma_addr);
+ dma_unmap_single(dev, areq_ctx->gcm_block_len_dma_addr,
+ AES_BLOCK_SIZE, DMA_TO_DEVICE);
+ }
+
+ if (areq_ctx->gcm_iv_inc1_dma_addr != 0) {
+ SSI_RESTORE_DMA_ADDR_TO_48BIT(areq_ctx->gcm_iv_inc1_dma_addr);
+ dma_unmap_single(dev, areq_ctx->gcm_iv_inc1_dma_addr,
+ AES_BLOCK_SIZE, DMA_TO_DEVICE);
+ }
+
+ if (areq_ctx->gcm_iv_inc2_dma_addr != 0) {
+ SSI_RESTORE_DMA_ADDR_TO_48BIT(areq_ctx->gcm_iv_inc2_dma_addr);
+ dma_unmap_single(dev, areq_ctx->gcm_iv_inc2_dma_addr,
+ AES_BLOCK_SIZE, DMA_TO_DEVICE);
+ }
+ }
+#endif
+
+ if (areq_ctx->ccm_hdr_size != ccm_header_size_null) {
+ if (areq_ctx->ccm_iv0_dma_addr != 0) {
+ SSI_RESTORE_DMA_ADDR_TO_48BIT(areq_ctx->ccm_iv0_dma_addr);
+ dma_unmap_single(dev, areq_ctx->ccm_iv0_dma_addr,
+ AES_BLOCK_SIZE, DMA_TO_DEVICE);
+ }
+
+ dma_unmap_sg(dev, &areq_ctx->ccm_adata_sg, 1, DMA_TO_DEVICE);
+ }
+ if (areq_ctx->gen_ctx.iv_dma_addr != 0) {
+ SSI_RESTORE_DMA_ADDR_TO_48BIT(areq_ctx->gen_ctx.iv_dma_addr);
+ dma_unmap_single(dev, areq_ctx->gen_ctx.iv_dma_addr,
+ hw_iv_size, DMA_BIDIRECTIONAL);
+ }
+
+ /*In case a pool was set, a table was
+ allocated and should be released */
+ if (areq_ctx->mlli_params.curr_pool != NULL) {
+ SSI_LOG_DEBUG("free MLLI buffer: dma=0x%08llX virt=%pK\n",
+ (unsigned long long)areq_ctx->mlli_params.mlli_dma_addr,
+ areq_ctx->mlli_params.mlli_virt_addr);
+ SSI_RESTORE_DMA_ADDR_TO_48BIT(areq_ctx->mlli_params.mlli_dma_addr);
+ dma_pool_free(areq_ctx->mlli_params.curr_pool,
+ areq_ctx->mlli_params.mlli_virt_addr,
+ areq_ctx->mlli_params.mlli_dma_addr);
+ }
+
+ SSI_LOG_DEBUG("Unmapping src sgl: req->src=%pK areq_ctx->src.nents=%u areq_ctx->assoc.nents=%u assoclen:%u cryptlen=%u\n", sg_virt(req->src),areq_ctx->src.nents,areq_ctx->assoc.nents,req->assoclen,req->cryptlen);
+ SSI_RESTORE_DMA_ADDR_TO_48BIT(sg_dma_address(req->src));
+ size_to_unmap = req->assoclen+req->cryptlen;
+ if(areq_ctx->gen_ctx.op_type == DRV_CRYPTO_DIRECTION_ENCRYPT){
+ size_to_unmap += areq_ctx->req_authsize;
+ }
+ if (areq_ctx->is_gcm4543)
+ size_to_unmap += crypto_aead_ivsize(tfm);
+
+ dma_unmap_sg(dev, req->src, ssi_buffer_mgr_get_sgl_nents(req->src,size_to_unmap,&dummy,&chained) , DMA_BIDIRECTIONAL);
+ if (unlikely(req->src != req->dst)) {
+ SSI_LOG_DEBUG("Unmapping dst sgl: req->dst=%pK\n",
+ sg_virt(req->dst));
+ SSI_RESTORE_DMA_ADDR_TO_48BIT(sg_dma_address(req->dst));
+ dma_unmap_sg(dev, req->dst, ssi_buffer_mgr_get_sgl_nents(req->dst,size_to_unmap,&dummy,&chained),
+ DMA_BIDIRECTIONAL);
+ }
+#if DX_HAS_ACP
+ if ((areq_ctx->gen_ctx.op_type == DRV_CRYPTO_DIRECTION_DECRYPT) &&
+ likely(req->src == req->dst))
+ {
+ uint32_t size_to_skip = req->assoclen;
+ if (areq_ctx->is_gcm4543) {
+ size_to_skip += crypto_aead_ivsize(tfm);
+ }
+ /* copy mac to a temporary location to deal with possible
+ data memory overriding that caused by cache coherence problem. */
+ ssi_buffer_mgr_copy_scatterlist_portion(
+ areq_ctx->backup_mac, req->src,
+ size_to_skip+ req->cryptlen - areq_ctx->req_authsize,
+ size_to_skip+ req->cryptlen, SSI_SG_FROM_BUF);
+ }
+#endif
+}
+
+static inline int ssi_buffer_mgr_get_aead_icv_nents(
+ struct scatterlist *sgl,
+ unsigned int sgl_nents,
+ unsigned int authsize,
+ uint32_t last_entry_data_size,
+ bool *is_icv_fragmented)
+{
+ unsigned int icv_max_size = 0;
+ unsigned int icv_required_size = authsize > last_entry_data_size ? (authsize - last_entry_data_size) : authsize;
+ unsigned int nents;
+ unsigned int i;
+
+ if (sgl_nents < MAX_ICV_NENTS_SUPPORTED) {
+ *is_icv_fragmented = false;
+ return 0;
+ }
+
+ for( i = 0 ; i < (sgl_nents - MAX_ICV_NENTS_SUPPORTED) ; i++) {
+ if (sgl == NULL) {
+ break;
+ }
+ sgl = sg_next(sgl);
+ }
+
+ if (sgl != NULL) {
+ icv_max_size = sgl->length;
+ }
+
+ if (last_entry_data_size > authsize) {
+ nents = 0; /* ICV attached to data in last entry (not fragmented!) */
+ *is_icv_fragmented = false;
+ } else if (last_entry_data_size == authsize) {
+ nents = 1; /* ICV placed in whole last entry (not fragmented!) */
+ *is_icv_fragmented = false;
+ } else if (icv_max_size > icv_required_size) {
+ nents = 1;
+ *is_icv_fragmented = true;
+ } else if (icv_max_size == icv_required_size) {
+ nents = 2;
+ *is_icv_fragmented = true;
+ } else {
+ SSI_LOG_ERR("Unsupported num. of ICV fragments (> %d)\n",
+ MAX_ICV_NENTS_SUPPORTED);
+ nents = -1; /*unsupported*/
+ }
+ SSI_LOG_DEBUG("is_frag=%s icv_nents=%u\n",
+ (*is_icv_fragmented ? "true" : "false"), nents);
+
+ return nents;
+}
+
+static inline int ssi_buffer_mgr_aead_chain_iv(
+ struct ssi_drvdata *drvdata,
+ struct aead_request *req,
+ struct buffer_array *sg_data,
+ bool is_last, bool do_chain)
+{
+ struct aead_req_ctx *areq_ctx = aead_request_ctx(req);
+ unsigned int hw_iv_size = areq_ctx->hw_iv_size;
+ struct device *dev = &drvdata->plat_dev->dev;
+ int rc = 0;
+
+ if (unlikely(req->iv == NULL)) {
+ areq_ctx->gen_ctx.iv_dma_addr = 0;
+ goto chain_iv_exit;
+ }
+
+ areq_ctx->gen_ctx.iv_dma_addr = dma_map_single(dev, req->iv,
+ hw_iv_size, DMA_BIDIRECTIONAL);
+ if (unlikely(dma_mapping_error(dev, areq_ctx->gen_ctx.iv_dma_addr))) {
+ SSI_LOG_ERR("Mapping iv %u B at va=%pK for DMA failed\n",
+ hw_iv_size, req->iv);
+ rc = -ENOMEM;
+ goto chain_iv_exit;
+ }
+ SSI_UPDATE_DMA_ADDR_TO_48BIT(areq_ctx->gen_ctx.iv_dma_addr, hw_iv_size);
+
+ SSI_LOG_DEBUG("Mapped iv %u B at va=%pK to dma=0x%llX\n",
+ hw_iv_size, req->iv,
+ (unsigned long long)areq_ctx->gen_ctx.iv_dma_addr);
+ if (do_chain == true && areq_ctx->plaintext_authenticate_only == true){ // TODO: what about CTR?? ask Ron
+ struct crypto_aead *tfm = crypto_aead_reqtfm(req);
+ unsigned int iv_size_to_authenc = crypto_aead_ivsize(tfm);
+ unsigned int iv_ofs = GCM_BLOCK_RFC4_IV_OFFSET;
+ /* Chain to given list */
+ ssi_buffer_mgr_add_buffer_entry(
+ sg_data, areq_ctx->gen_ctx.iv_dma_addr + iv_ofs,
+ iv_size_to_authenc, is_last,
+ &areq_ctx->assoc.mlli_nents);
+ areq_ctx->assoc_buff_type = SSI_DMA_BUF_MLLI;
+ }
+
+chain_iv_exit:
+ return rc;
+}
+
+static inline int ssi_buffer_mgr_aead_chain_assoc(
+ struct ssi_drvdata *drvdata,
+ struct aead_request *req,
+ struct buffer_array *sg_data,
+ bool is_last, bool do_chain)
+{
+ struct aead_req_ctx *areq_ctx = aead_request_ctx(req);
+ int rc = 0;
+ uint32_t mapped_nents = 0;
+ struct scatterlist *current_sg = req->src;
+ struct crypto_aead *tfm = crypto_aead_reqtfm(req);
+ unsigned int sg_index = 0;
+ uint32_t size_of_assoc = req->assoclen;
+
+ if (areq_ctx->is_gcm4543) {
+ size_of_assoc += crypto_aead_ivsize(tfm);
+ }
+
+ if (sg_data == NULL) {
+ rc = -EINVAL;
+ goto chain_assoc_exit;
+ }
+
+ if (unlikely(req->assoclen == 0)) {
+ areq_ctx->assoc_buff_type = SSI_DMA_BUF_NULL;
+ areq_ctx->assoc.nents = 0;
+ areq_ctx->assoc.mlli_nents = 0;
+ SSI_LOG_DEBUG("Chain assoc of length 0: buff_type=%s nents=%u\n",
+ GET_DMA_BUFFER_TYPE(areq_ctx->assoc_buff_type),
+ areq_ctx->assoc.nents);
+ goto chain_assoc_exit;
+ }
+
+ //iterate over the sgl to see how many entries are for associated data
+ //it is assumed that if we reach here , the sgl is already mapped
+ sg_index = current_sg->length;
+ if (sg_index > size_of_assoc) { //the first entry in the scatter list contains all the associated data
+ mapped_nents++;
+ }
+ else{
+ while (sg_index <= size_of_assoc) {
+ current_sg = sg_next(current_sg);
+ //if have reached the end of the sgl, then this is unexpected
+ if (current_sg == NULL) {
+ SSI_LOG_ERR("reached end of sg list. unexpected \n");
+ BUG();
+ }
+ sg_index += current_sg->length;
+ mapped_nents++;
+ }
+ }
+ if (unlikely(mapped_nents > LLI_MAX_NUM_OF_ASSOC_DATA_ENTRIES)) {
+ SSI_LOG_ERR("Too many fragments. current %d max %d\n",
+ mapped_nents, LLI_MAX_NUM_OF_ASSOC_DATA_ENTRIES);
+ return -ENOMEM;
+ }
+ areq_ctx->assoc.nents = mapped_nents;
+
+ /* in CCM case we have additional entry for
+ * ccm header configurations */
+ if (areq_ctx->ccm_hdr_size != ccm_header_size_null) {
+ if (unlikely((mapped_nents + 1) >
+ LLI_MAX_NUM_OF_ASSOC_DATA_ENTRIES)) {
+
+ SSI_LOG_ERR("CCM case.Too many fragments. "
+ "Current %d max %d\n",
+ (areq_ctx->assoc.nents + 1),
+ LLI_MAX_NUM_OF_ASSOC_DATA_ENTRIES);
+ rc = -ENOMEM;
+ goto chain_assoc_exit;
+ }
+ }
+
+ if (likely(mapped_nents == 1) &&
+ (areq_ctx->ccm_hdr_size == ccm_header_size_null))
+ areq_ctx->assoc_buff_type = SSI_DMA_BUF_DLLI;
+ else
+ areq_ctx->assoc_buff_type = SSI_DMA_BUF_MLLI;
+
+ if (unlikely((do_chain == true) ||
+ (areq_ctx->assoc_buff_type == SSI_DMA_BUF_MLLI))) {
+
+ SSI_LOG_DEBUG("Chain assoc: buff_type=%s nents=%u\n",
+ GET_DMA_BUFFER_TYPE(areq_ctx->assoc_buff_type),
+ areq_ctx->assoc.nents);
+ ssi_buffer_mgr_add_scatterlist_entry(
+ sg_data, areq_ctx->assoc.nents,
+ req->src, req->assoclen, 0, is_last,
+ &areq_ctx->assoc.mlli_nents);
+ areq_ctx->assoc_buff_type = SSI_DMA_BUF_MLLI;
+ }
+
+chain_assoc_exit:
+ return rc;
+}
+
+static inline void ssi_buffer_mgr_prepare_aead_data_dlli(
+ struct aead_request *req,
+ uint32_t *src_last_bytes, uint32_t *dst_last_bytes)
+{
+ struct aead_req_ctx *areq_ctx = aead_request_ctx(req);
+ enum drv_crypto_direction direct = areq_ctx->gen_ctx.op_type;
+ unsigned int authsize = areq_ctx->req_authsize;
+
+ areq_ctx->is_icv_fragmented = false;
+ if (likely(req->src == req->dst)) {
+ /*INPLACE*/
+ areq_ctx->icv_dma_addr = sg_dma_address(
+ areq_ctx->srcSgl)+
+ (*src_last_bytes - authsize);
+ areq_ctx->icv_virt_addr = sg_virt(
+ areq_ctx->srcSgl) +
+ (*src_last_bytes - authsize);
+ } else if (direct == DRV_CRYPTO_DIRECTION_DECRYPT) {
+ /*NON-INPLACE and DECRYPT*/
+ areq_ctx->icv_dma_addr = sg_dma_address(
+ areq_ctx->srcSgl) +
+ (*src_last_bytes - authsize);
+ areq_ctx->icv_virt_addr = sg_virt(
+ areq_ctx->srcSgl) +
+ (*src_last_bytes - authsize);
+ } else {
+ /*NON-INPLACE and ENCRYPT*/
+ areq_ctx->icv_dma_addr = sg_dma_address(
+ areq_ctx->dstSgl) +
+ (*dst_last_bytes - authsize);
+ areq_ctx->icv_virt_addr = sg_virt(
+ areq_ctx->dstSgl)+
+ (*dst_last_bytes - authsize);
+ }
+}
+
+static inline int ssi_buffer_mgr_prepare_aead_data_mlli(
+ struct ssi_drvdata *drvdata,
+ struct aead_request *req,
+ struct buffer_array *sg_data,
+ uint32_t *src_last_bytes, uint32_t *dst_last_bytes,
+ bool is_last_table)
+{
+ struct aead_req_ctx *areq_ctx = aead_request_ctx(req);
+ enum drv_crypto_direction direct = areq_ctx->gen_ctx.op_type;
+ unsigned int authsize = areq_ctx->req_authsize;
+ int rc = 0, icv_nents;
+ struct crypto_aead *tfm = crypto_aead_reqtfm(req);
+
+ if (likely(req->src == req->dst)) {
+ /*INPLACE*/
+ ssi_buffer_mgr_add_scatterlist_entry(sg_data,
+ areq_ctx->src.nents, areq_ctx->srcSgl,
+ areq_ctx->cryptlen,areq_ctx->srcOffset, is_last_table,
+ &areq_ctx->src.mlli_nents);
+
+ icv_nents = ssi_buffer_mgr_get_aead_icv_nents(areq_ctx->srcSgl,
+ areq_ctx->src.nents, authsize, *src_last_bytes,
+ &areq_ctx->is_icv_fragmented);
+ if (unlikely(icv_nents < 0)) {
+ rc = -ENOTSUPP;
+ goto prepare_data_mlli_exit;
+ }
+
+ if (unlikely(areq_ctx->is_icv_fragmented == true)) {
+ /* Backup happens only when ICV is fragmented, ICV
+ verification is made by CPU compare in order to simplify
+ MAC verification upon request completion */
+ if (direct == DRV_CRYPTO_DIRECTION_DECRYPT) {
+#if !DX_HAS_ACP
+ /* In ACP platform we already copying ICV
+ for any INPLACE-DECRYPT operation, hence
+ we must neglect this code. */
+ uint32_t size_to_skip = req->assoclen;
+ if (areq_ctx->is_gcm4543) {
+ size_to_skip += crypto_aead_ivsize(tfm);
+ }
+ ssi_buffer_mgr_copy_scatterlist_portion(
+ areq_ctx->backup_mac, req->src,
+ size_to_skip+ req->cryptlen - areq_ctx->req_authsize,
+ size_to_skip+ req->cryptlen, SSI_SG_TO_BUF);
+#endif
+ areq_ctx->icv_virt_addr = areq_ctx->backup_mac;
+ } else {
+ areq_ctx->icv_virt_addr = areq_ctx->mac_buf;
+ areq_ctx->icv_dma_addr = areq_ctx->mac_buf_dma_addr;
+ }
+ } else { /* Contig. ICV */
+ /*Should hanlde if the sg is not contig.*/
+ areq_ctx->icv_dma_addr = sg_dma_address(
+ &areq_ctx->srcSgl[areq_ctx->src.nents - 1]) +
+ (*src_last_bytes - authsize);
+ areq_ctx->icv_virt_addr = sg_virt(
+ &areq_ctx->srcSgl[areq_ctx->src.nents - 1]) +
+ (*src_last_bytes - authsize);
+ }
+
+ } else if (direct == DRV_CRYPTO_DIRECTION_DECRYPT) {
+ /*NON-INPLACE and DECRYPT*/
+ ssi_buffer_mgr_add_scatterlist_entry(sg_data,
+ areq_ctx->src.nents, areq_ctx->srcSgl,
+ areq_ctx->cryptlen, areq_ctx->srcOffset,is_last_table,
+ &areq_ctx->src.mlli_nents);
+ ssi_buffer_mgr_add_scatterlist_entry(sg_data,
+ areq_ctx->dst.nents, areq_ctx->dstSgl,
+ areq_ctx->cryptlen,areq_ctx->dstOffset, is_last_table,
+ &areq_ctx->dst.mlli_nents);
+
+ icv_nents = ssi_buffer_mgr_get_aead_icv_nents(areq_ctx->srcSgl,
+ areq_ctx->src.nents, authsize, *src_last_bytes,
+ &areq_ctx->is_icv_fragmented);
+ if (unlikely(icv_nents < 0)) {
+ rc = -ENOTSUPP;
+ goto prepare_data_mlli_exit;
+ }
+
+ if (unlikely(areq_ctx->is_icv_fragmented == true)) {
+ /* Backup happens only when ICV is fragmented, ICV
+ verification is made by CPU compare in order to simplify
+ MAC verification upon request completion */
+ uint32_t size_to_skip = req->assoclen;
+ if (areq_ctx->is_gcm4543) {
+ size_to_skip += crypto_aead_ivsize(tfm);
+ }
+ ssi_buffer_mgr_copy_scatterlist_portion(
+ areq_ctx->backup_mac, req->src,
+ size_to_skip+ req->cryptlen - areq_ctx->req_authsize,
+ size_to_skip+ req->cryptlen, SSI_SG_TO_BUF);
+ areq_ctx->icv_virt_addr = areq_ctx->backup_mac;
+ } else { /* Contig. ICV */
+ /*Should hanlde if the sg is not contig.*/
+ areq_ctx->icv_dma_addr = sg_dma_address(
+ &areq_ctx->srcSgl[areq_ctx->src.nents - 1]) +
+ (*src_last_bytes - authsize);
+ areq_ctx->icv_virt_addr = sg_virt(
+ &areq_ctx->srcSgl[areq_ctx->src.nents - 1]) +
+ (*src_last_bytes - authsize);
+ }
+
+ } else {
+ /*NON-INPLACE and ENCRYPT*/
+ ssi_buffer_mgr_add_scatterlist_entry(sg_data,
+ areq_ctx->dst.nents, areq_ctx->dstSgl,
+ areq_ctx->cryptlen,areq_ctx->dstOffset, is_last_table,
+ &areq_ctx->dst.mlli_nents);
+ ssi_buffer_mgr_add_scatterlist_entry(sg_data,
+ areq_ctx->src.nents, areq_ctx->srcSgl,
+ areq_ctx->cryptlen, areq_ctx->srcOffset,is_last_table,
+ &areq_ctx->src.mlli_nents);
+
+ icv_nents = ssi_buffer_mgr_get_aead_icv_nents(areq_ctx->dstSgl,
+ areq_ctx->dst.nents, authsize, *dst_last_bytes,
+ &areq_ctx->is_icv_fragmented);
+ if (unlikely(icv_nents < 0)) {
+ rc = -ENOTSUPP;
+ goto prepare_data_mlli_exit;
+ }
+
+ if (likely(areq_ctx->is_icv_fragmented == false)) {
+ /* Contig. ICV */
+ areq_ctx->icv_dma_addr = sg_dma_address(
+ &areq_ctx->dstSgl[areq_ctx->dst.nents - 1]) +
+ (*dst_last_bytes - authsize);
+ areq_ctx->icv_virt_addr = sg_virt(
+ &areq_ctx->dstSgl[areq_ctx->dst.nents - 1]) +
+ (*dst_last_bytes - authsize);
+ } else {
+ areq_ctx->icv_dma_addr = areq_ctx->mac_buf_dma_addr;
+ areq_ctx->icv_virt_addr = areq_ctx->mac_buf;
+ }
+ }
+
+prepare_data_mlli_exit:
+ return rc;
+}
+
+static inline int ssi_buffer_mgr_aead_chain_data(
+ struct ssi_drvdata *drvdata,
+ struct aead_request *req,
+ struct buffer_array *sg_data,
+ bool is_last_table, bool do_chain)
+{
+ struct aead_req_ctx *areq_ctx = aead_request_ctx(req);
+ struct device *dev = &drvdata->plat_dev->dev;
+ enum drv_crypto_direction direct = areq_ctx->gen_ctx.op_type;
+ unsigned int authsize = areq_ctx->req_authsize;
+ int src_last_bytes = 0, dst_last_bytes = 0;
+ int rc = 0;
+ uint32_t src_mapped_nents = 0, dst_mapped_nents = 0;
+ uint32_t offset = 0;
+ unsigned int size_for_map = req->assoclen +req->cryptlen; /*non-inplace mode*/
+ struct crypto_aead *tfm = crypto_aead_reqtfm(req);
+ uint32_t sg_index = 0;
+ bool chained = false;
+ bool is_gcm4543 = areq_ctx->is_gcm4543;
+ uint32_t size_to_skip = req->assoclen;
+ if (is_gcm4543) {
+ size_to_skip += crypto_aead_ivsize(tfm);
+ }
+ offset = size_to_skip;
+
+ if (sg_data == NULL) {
+ rc = -EINVAL;
+ goto chain_data_exit;
+ }
+ areq_ctx->srcSgl = req->src;
+ areq_ctx->dstSgl = req->dst;
+
+ if (is_gcm4543) {
+ size_for_map += crypto_aead_ivsize(tfm);
+ }
+
+ size_for_map += (direct == DRV_CRYPTO_DIRECTION_ENCRYPT) ? authsize:0;
+ src_mapped_nents = ssi_buffer_mgr_get_sgl_nents(req->src,size_for_map,&src_last_bytes, &chained);
+ sg_index = areq_ctx->srcSgl->length;
+ //check where the data starts
+ while (sg_index <= size_to_skip) {
+ offset -= areq_ctx->srcSgl->length;
+ areq_ctx->srcSgl = sg_next(areq_ctx->srcSgl);
+ //if have reached the end of the sgl, then this is unexpected
+ if (areq_ctx->srcSgl == NULL) {
+ SSI_LOG_ERR("reached end of sg list. unexpected \n");
+ BUG();
+ }
+ sg_index += areq_ctx->srcSgl->length;
+ src_mapped_nents--;
+ }
+ if (unlikely(src_mapped_nents > LLI_MAX_NUM_OF_DATA_ENTRIES))
+ {
+ SSI_LOG_ERR("Too many fragments. current %d max %d\n",
+ src_mapped_nents, LLI_MAX_NUM_OF_DATA_ENTRIES);
+ return -ENOMEM;
+ }
+
+ areq_ctx->src.nents = src_mapped_nents;
+
+ areq_ctx->srcOffset = offset;
+
+ if (req->src != req->dst) {
+ size_for_map = req->assoclen +req->cryptlen;
+ size_for_map += (direct == DRV_CRYPTO_DIRECTION_ENCRYPT) ? authsize : 0;
+ if (is_gcm4543) {
+ size_for_map += crypto_aead_ivsize(tfm);
+ }
+
+ rc = ssi_buffer_mgr_map_scatterlist(dev, req->dst, size_for_map,
+ DMA_BIDIRECTIONAL, &(areq_ctx->dst.nents),
+ LLI_MAX_NUM_OF_DATA_ENTRIES, &dst_last_bytes,
+ &dst_mapped_nents);
+ if (unlikely(rc != 0)) {
+ rc = -ENOMEM;
+ goto chain_data_exit;
+ }
+ }
+
+ dst_mapped_nents = ssi_buffer_mgr_get_sgl_nents(req->dst,size_for_map,&dst_last_bytes, &chained);
+ sg_index = areq_ctx->dstSgl->length;
+ offset = size_to_skip;
+
+ //check where the data starts
+ while (sg_index <= size_to_skip) {
+
+ offset -= areq_ctx->dstSgl->length;
+ areq_ctx->dstSgl = sg_next(areq_ctx->dstSgl);
+ //if have reached the end of the sgl, then this is unexpected
+ if (areq_ctx->dstSgl == NULL) {
+ SSI_LOG_ERR("reached end of sg list. unexpected \n");
+ BUG();
+ }
+ sg_index += areq_ctx->dstSgl->length;
+ dst_mapped_nents--;
+ }
+ if (unlikely(dst_mapped_nents > LLI_MAX_NUM_OF_DATA_ENTRIES))
+ {
+ SSI_LOG_ERR("Too many fragments. current %d max %d\n",
+ dst_mapped_nents, LLI_MAX_NUM_OF_DATA_ENTRIES);
+ return -ENOMEM;
+ }
+ areq_ctx->dst.nents = dst_mapped_nents;
+ areq_ctx->dstOffset = offset;
+ if ((src_mapped_nents > 1) ||
+ (dst_mapped_nents > 1) ||
+ (do_chain == true)) {
+ areq_ctx->data_buff_type = SSI_DMA_BUF_MLLI;
+ rc = ssi_buffer_mgr_prepare_aead_data_mlli(drvdata, req, sg_data,
+ &src_last_bytes, &dst_last_bytes, is_last_table);
+ } else {
+ areq_ctx->data_buff_type = SSI_DMA_BUF_DLLI;
+ ssi_buffer_mgr_prepare_aead_data_dlli(
+ req, &src_last_bytes, &dst_last_bytes);
+ }
+
+chain_data_exit:
+ return rc;
+}
+
+static void ssi_buffer_mgr_update_aead_mlli_nents( struct ssi_drvdata *drvdata,
+ struct aead_request *req)
+{
+ struct aead_req_ctx *areq_ctx = aead_request_ctx(req);
+ uint32_t curr_mlli_size = 0;
+
+ if (areq_ctx->assoc_buff_type == SSI_DMA_BUF_MLLI) {
+ areq_ctx->assoc.sram_addr = drvdata->mlli_sram_addr;
+ curr_mlli_size = areq_ctx->assoc.mlli_nents *
+ LLI_ENTRY_BYTE_SIZE;
+ }
+
+ if (areq_ctx->data_buff_type == SSI_DMA_BUF_MLLI) {
+ /*Inplace case dst nents equal to src nents*/
+ if (req->src == req->dst) {
+ areq_ctx->dst.mlli_nents = areq_ctx->src.mlli_nents;
+ areq_ctx->src.sram_addr = drvdata->mlli_sram_addr +
+ curr_mlli_size;
+ areq_ctx->dst.sram_addr = areq_ctx->src.sram_addr;
+ if (areq_ctx->is_single_pass == false)
+ areq_ctx->assoc.mlli_nents +=
+ areq_ctx->src.mlli_nents;
+ } else {
+ if (areq_ctx->gen_ctx.op_type ==
+ DRV_CRYPTO_DIRECTION_DECRYPT) {
+ areq_ctx->src.sram_addr =
+ drvdata->mlli_sram_addr +
+ curr_mlli_size;
+ areq_ctx->dst.sram_addr =
+ areq_ctx->src.sram_addr +
+ areq_ctx->src.mlli_nents *
+ LLI_ENTRY_BYTE_SIZE;
+ if (areq_ctx->is_single_pass == false)
+ areq_ctx->assoc.mlli_nents +=
+ areq_ctx->src.mlli_nents;
+ } else {
+ areq_ctx->dst.sram_addr =
+ drvdata->mlli_sram_addr +
+ curr_mlli_size;
+ areq_ctx->src.sram_addr =
+ areq_ctx->dst.sram_addr +
+ areq_ctx->dst.mlli_nents *
+ LLI_ENTRY_BYTE_SIZE;
+ if (areq_ctx->is_single_pass == false)
+ areq_ctx->assoc.mlli_nents +=
+ areq_ctx->dst.mlli_nents;
+ }
+ }
+ }
+}
+
+int ssi_buffer_mgr_map_aead_request(
+ struct ssi_drvdata *drvdata, struct aead_request *req)
+{
+ struct aead_req_ctx *areq_ctx = aead_request_ctx(req);
+ struct mlli_params *mlli_params = &areq_ctx->mlli_params;
+ struct device *dev = &drvdata->plat_dev->dev;
+ struct buffer_array sg_data;
+ unsigned int authsize = areq_ctx->req_authsize;
+ struct buff_mgr_handle *buff_mgr = drvdata->buff_mgr_handle;
+ int rc = 0;
+ struct crypto_aead *tfm = crypto_aead_reqtfm(req);
+ bool is_gcm4543 = areq_ctx->is_gcm4543;
+
+ uint32_t mapped_nents = 0;
+ uint32_t dummy = 0; /*used for the assoc data fragments */
+ uint32_t size_to_map = 0;
+
+ mlli_params->curr_pool = NULL;
+ sg_data.num_of_buffers = 0;
+
+#if DX_HAS_ACP
+ if ((areq_ctx->gen_ctx.op_type == DRV_CRYPTO_DIRECTION_DECRYPT) &&
+ likely(req->src == req->dst))
+ {
+ uint32_t size_to_skip = req->assoclen;
+ if (is_gcm4543) {
+ size_to_skip += crypto_aead_ivsize(tfm);
+ }
+ /* copy mac to a temporary location to deal with possible
+ data memory overriding that caused by cache coherence problem. */
+ ssi_buffer_mgr_copy_scatterlist_portion(
+ areq_ctx->backup_mac, req->src,
+ size_to_skip+ req->cryptlen - areq_ctx->req_authsize,
+ size_to_skip+ req->cryptlen, SSI_SG_TO_BUF);
+ }
+#endif
+
+ /* cacluate the size for cipher remove ICV in decrypt*/
+ areq_ctx->cryptlen = (areq_ctx->gen_ctx.op_type ==
+ DRV_CRYPTO_DIRECTION_ENCRYPT) ?
+ req->cryptlen :
+ (req->cryptlen - authsize);
+
+ areq_ctx->mac_buf_dma_addr = dma_map_single(dev,
+ areq_ctx->mac_buf, MAX_MAC_SIZE, DMA_BIDIRECTIONAL);
+ if (unlikely(dma_mapping_error(dev, areq_ctx->mac_buf_dma_addr))) {
+ SSI_LOG_ERR("Mapping mac_buf %u B at va=%pK for DMA failed\n",
+ MAX_MAC_SIZE, areq_ctx->mac_buf);
+ rc = -ENOMEM;
+ goto aead_map_failure;
+ }
+ SSI_UPDATE_DMA_ADDR_TO_48BIT(areq_ctx->mac_buf_dma_addr, MAX_MAC_SIZE);
+
+ if (areq_ctx->ccm_hdr_size != ccm_header_size_null) {
+ areq_ctx->ccm_iv0_dma_addr = dma_map_single(dev,
+ (areq_ctx->ccm_config + CCM_CTR_COUNT_0_OFFSET),
+ AES_BLOCK_SIZE, DMA_TO_DEVICE);
+
+ if (unlikely(dma_mapping_error(dev, areq_ctx->ccm_iv0_dma_addr))) {
+ SSI_LOG_ERR("Mapping mac_buf %u B at va=%pK "
+ "for DMA failed\n", AES_BLOCK_SIZE,
+ (areq_ctx->ccm_config + CCM_CTR_COUNT_0_OFFSET));
+ areq_ctx->ccm_iv0_dma_addr = 0;
+ rc = -ENOMEM;
+ goto aead_map_failure;
+ }
+ SSI_UPDATE_DMA_ADDR_TO_48BIT(areq_ctx->ccm_iv0_dma_addr,
+ AES_BLOCK_SIZE);
+ if (ssi_aead_handle_config_buf(dev, areq_ctx,
+ areq_ctx->ccm_config, &sg_data, req->assoclen) != 0) {
+ rc = -ENOMEM;
+ goto aead_map_failure;
+ }
+ }
+
+#if SSI_CC_HAS_AES_GCM
+ if (areq_ctx->cipher_mode == DRV_CIPHER_GCTR) {
+ areq_ctx->hkey_dma_addr = dma_map_single(dev,
+ areq_ctx->hkey, AES_BLOCK_SIZE, DMA_BIDIRECTIONAL);
+ if (unlikely(dma_mapping_error(dev, areq_ctx->hkey_dma_addr))) {
+ SSI_LOG_ERR("Mapping hkey %u B at va=%pK for DMA failed\n",
+ AES_BLOCK_SIZE, areq_ctx->hkey);
+ rc = -ENOMEM;
+ goto aead_map_failure;
+ }
+ SSI_UPDATE_DMA_ADDR_TO_48BIT(areq_ctx->hkey_dma_addr, AES_BLOCK_SIZE);
+
+ areq_ctx->gcm_block_len_dma_addr = dma_map_single(dev,
+ &areq_ctx->gcm_len_block, AES_BLOCK_SIZE, DMA_TO_DEVICE);
+ if (unlikely(dma_mapping_error(dev, areq_ctx->gcm_block_len_dma_addr))) {
+ SSI_LOG_ERR("Mapping gcm_len_block %u B at va=%pK for DMA failed\n",
+ AES_BLOCK_SIZE, &areq_ctx->gcm_len_block);
+ rc = -ENOMEM;
+ goto aead_map_failure;
+ }
+ SSI_UPDATE_DMA_ADDR_TO_48BIT(areq_ctx->gcm_block_len_dma_addr, AES_BLOCK_SIZE);
+
+ areq_ctx->gcm_iv_inc1_dma_addr = dma_map_single(dev,
+ areq_ctx->gcm_iv_inc1,
+ AES_BLOCK_SIZE, DMA_TO_DEVICE);
+
+ if (unlikely(dma_mapping_error(dev, areq_ctx->gcm_iv_inc1_dma_addr))) {
+ SSI_LOG_ERR("Mapping gcm_iv_inc1 %u B at va=%pK "
+ "for DMA failed\n", AES_BLOCK_SIZE,
+ (areq_ctx->gcm_iv_inc1));
+ areq_ctx->gcm_iv_inc1_dma_addr = 0;
+ rc = -ENOMEM;
+ goto aead_map_failure;
+ }
+ SSI_UPDATE_DMA_ADDR_TO_48BIT(areq_ctx->gcm_iv_inc1_dma_addr,
+ AES_BLOCK_SIZE);
+
+ areq_ctx->gcm_iv_inc2_dma_addr = dma_map_single(dev,
+ areq_ctx->gcm_iv_inc2,
+ AES_BLOCK_SIZE, DMA_TO_DEVICE);
+
+ if (unlikely(dma_mapping_error(dev, areq_ctx->gcm_iv_inc2_dma_addr))) {
+ SSI_LOG_ERR("Mapping gcm_iv_inc2 %u B at va=%pK "
+ "for DMA failed\n", AES_BLOCK_SIZE,
+ (areq_ctx->gcm_iv_inc2));
+ areq_ctx->gcm_iv_inc2_dma_addr = 0;
+ rc = -ENOMEM;
+ goto aead_map_failure;
+ }
+ SSI_UPDATE_DMA_ADDR_TO_48BIT(areq_ctx->gcm_iv_inc2_dma_addr,
+ AES_BLOCK_SIZE);
+ }
+#endif /*SSI_CC_HAS_AES_GCM*/
+
+ size_to_map = req->cryptlen + req->assoclen;
+ if (areq_ctx->gen_ctx.op_type == DRV_CRYPTO_DIRECTION_ENCRYPT) {
+ size_to_map += authsize;
+ }
+ if (is_gcm4543)
+ size_to_map += crypto_aead_ivsize(tfm);
+ rc = ssi_buffer_mgr_map_scatterlist(dev, req->src,
+ size_to_map, DMA_BIDIRECTIONAL, &(areq_ctx->src.nents),
+ LLI_MAX_NUM_OF_ASSOC_DATA_ENTRIES+LLI_MAX_NUM_OF_DATA_ENTRIES, &dummy, &mapped_nents);
+ if (unlikely(rc != 0)) {
+ rc = -ENOMEM;
+ goto aead_map_failure;
+ }
+
+ if (likely(areq_ctx->is_single_pass == true)) {
+ /*
+ * Create MLLI table for:
+ * (1) Assoc. data
+ * (2) Src/Dst SGLs
+ * Note: IV is contg. buffer (not an SGL)
+ */
+ rc = ssi_buffer_mgr_aead_chain_assoc(drvdata, req, &sg_data, true, false);
+ if (unlikely(rc != 0))
+ goto aead_map_failure;
+ rc = ssi_buffer_mgr_aead_chain_iv(drvdata, req, &sg_data, true, false);
+ if (unlikely(rc != 0))
+ goto aead_map_failure;
+ rc = ssi_buffer_mgr_aead_chain_data(drvdata, req, &sg_data, true, false);
+ if (unlikely(rc != 0))
+ goto aead_map_failure;
+ } else { /* DOUBLE-PASS flow */
+ /*
+ * Prepare MLLI table(s) in this order:
+ *
+ * If ENCRYPT/DECRYPT (inplace):
+ * (1) MLLI table for assoc
+ * (2) IV entry (chained right after end of assoc)
+ * (3) MLLI for src/dst (inplace operation)
+ *
+ * If ENCRYPT (non-inplace)
+ * (1) MLLI table for assoc
+ * (2) IV entry (chained right after end of assoc)
+ * (3) MLLI for dst
+ * (4) MLLI for src
+ *
+ * If DECRYPT (non-inplace)
+ * (1) MLLI table for assoc
+ * (2) IV entry (chained right after end of assoc)
+ * (3) MLLI for src
+ * (4) MLLI for dst
+ */
+ rc = ssi_buffer_mgr_aead_chain_assoc(drvdata, req, &sg_data, false, true);
+ if (unlikely(rc != 0))
+ goto aead_map_failure;
+ rc = ssi_buffer_mgr_aead_chain_iv(drvdata, req, &sg_data, false, true);
+ if (unlikely(rc != 0))
+ goto aead_map_failure;
+ rc = ssi_buffer_mgr_aead_chain_data(drvdata, req, &sg_data, true, true);
+ if (unlikely(rc != 0))
+ goto aead_map_failure;
+ }
+
+ /* Mlli support -start building the MLLI according to the above results */
+ if (unlikely(
+ (areq_ctx->assoc_buff_type == SSI_DMA_BUF_MLLI) ||
+ (areq_ctx->data_buff_type == SSI_DMA_BUF_MLLI))) {
+
+ mlli_params->curr_pool = buff_mgr->mlli_buffs_pool;
+ rc = ssi_buffer_mgr_generate_mlli(dev, &sg_data, mlli_params);
+ if (unlikely(rc != 0)) {
+ goto aead_map_failure;
+ }
+
+ ssi_buffer_mgr_update_aead_mlli_nents(drvdata, req);
+ SSI_LOG_DEBUG("assoc params mn %d\n",areq_ctx->assoc.mlli_nents);
+ SSI_LOG_DEBUG("src params mn %d\n",areq_ctx->src.mlli_nents);
+ SSI_LOG_DEBUG("dst params mn %d\n",areq_ctx->dst.mlli_nents);
+ }
+ return 0;
+
+aead_map_failure:
+ ssi_buffer_mgr_unmap_aead_request(dev, req);
+ return rc;
+}
+
+int ssi_buffer_mgr_map_hash_request_final(
+ struct ssi_drvdata *drvdata, void *ctx, struct scatterlist *src, unsigned int nbytes, bool do_update)
+{
+ struct ahash_req_ctx *areq_ctx = (struct ahash_req_ctx *)ctx;
+ struct device *dev = &drvdata->plat_dev->dev;
+ uint8_t* curr_buff = areq_ctx->buff_index ? areq_ctx->buff1 :
+ areq_ctx->buff0;
+ uint32_t *curr_buff_cnt = areq_ctx->buff_index ? &areq_ctx->buff1_cnt :
+ &areq_ctx->buff0_cnt;
+ struct mlli_params *mlli_params = &areq_ctx->mlli_params;
+ struct buffer_array sg_data;
+ struct buff_mgr_handle *buff_mgr = drvdata->buff_mgr_handle;
+ uint32_t dummy = 0;
+ uint32_t mapped_nents = 0;
+
+ SSI_LOG_DEBUG(" final params : curr_buff=%pK "
+ "curr_buff_cnt=0x%X nbytes = 0x%X "
+ "src=%pK curr_index=%u\n",
+ curr_buff, *curr_buff_cnt, nbytes,
+ src, areq_ctx->buff_index);
+ /* Init the type of the dma buffer */
+ areq_ctx->data_dma_buf_type = SSI_DMA_BUF_NULL;
+ mlli_params->curr_pool = NULL;
+ sg_data.num_of_buffers = 0;
+ areq_ctx->in_nents = 0;
+
+ if (unlikely(nbytes == 0 && *curr_buff_cnt == 0)) {
+ /* nothing to do */
+ return 0;
+ }
+
+ /*TODO: copy data in case that buffer is enough for operation */
+ /* map the previous buffer */
+ if (*curr_buff_cnt != 0 ) {
+ if (ssi_ahash_handle_curr_buf(dev, areq_ctx, curr_buff,
+ *curr_buff_cnt, &sg_data) != 0) {
+ return -ENOMEM;
+ }
+ }
+
+ if (src && (nbytes > 0) && do_update) {
+ if ( unlikely( ssi_buffer_mgr_map_scatterlist( dev,src,
+ nbytes,
+ DMA_TO_DEVICE,
+ &areq_ctx->in_nents,
+ LLI_MAX_NUM_OF_DATA_ENTRIES,
+ &dummy, &mapped_nents))){
+ goto unmap_curr_buff;
+ }
+ if ( src && (mapped_nents == 1)
+ && (areq_ctx->data_dma_buf_type == SSI_DMA_BUF_NULL) ) {
+ memcpy(areq_ctx->buff_sg,src,
+ sizeof(struct scatterlist));
+ areq_ctx->buff_sg->length = nbytes;
+ areq_ctx->curr_sg = areq_ctx->buff_sg;
+ areq_ctx->data_dma_buf_type = SSI_DMA_BUF_DLLI;
+ } else {
+ areq_ctx->data_dma_buf_type = SSI_DMA_BUF_MLLI;
+ }
+
+ }
+
+ /*build mlli */
+ if (unlikely(areq_ctx->data_dma_buf_type == SSI_DMA_BUF_MLLI)) {
+ mlli_params->curr_pool = buff_mgr->mlli_buffs_pool;
+ /* add the src data to the sg_data */
+ ssi_buffer_mgr_add_scatterlist_entry(&sg_data,
+ areq_ctx->in_nents,
+ src,
+ nbytes, 0,
+ true, &areq_ctx->mlli_nents);
+ if (unlikely(ssi_buffer_mgr_generate_mlli(dev, &sg_data,
+ mlli_params) != 0)) {
+ goto fail_unmap_din;
+ }
+ }
+ /* change the buffer index for the unmap function */
+ areq_ctx->buff_index = (areq_ctx->buff_index^1);
+ SSI_LOG_DEBUG("areq_ctx->data_dma_buf_type = %s\n",
+ GET_DMA_BUFFER_TYPE(areq_ctx->data_dma_buf_type));
+ return 0;
+
+fail_unmap_din:
+ dma_unmap_sg(dev, src, areq_ctx->in_nents, DMA_TO_DEVICE);
+
+unmap_curr_buff:
+ if (*curr_buff_cnt != 0 ) {
+ dma_unmap_sg(dev, areq_ctx->buff_sg, 1, DMA_TO_DEVICE);
+ }
+ return -ENOMEM;
+}
+
+int ssi_buffer_mgr_map_hash_request_update(
+ struct ssi_drvdata *drvdata, void *ctx, struct scatterlist *src, unsigned int nbytes, unsigned int block_size)
+{
+ struct ahash_req_ctx *areq_ctx = (struct ahash_req_ctx *)ctx;
+ struct device *dev = &drvdata->plat_dev->dev;
+ uint8_t* curr_buff = areq_ctx->buff_index ? areq_ctx->buff1 :
+ areq_ctx->buff0;
+ uint32_t *curr_buff_cnt = areq_ctx->buff_index ? &areq_ctx->buff1_cnt :
+ &areq_ctx->buff0_cnt;
+ uint8_t* next_buff = areq_ctx->buff_index ? areq_ctx->buff0 :
+ areq_ctx->buff1;
+ uint32_t *next_buff_cnt = areq_ctx->buff_index ? &areq_ctx->buff0_cnt :
+ &areq_ctx->buff1_cnt;
+ struct mlli_params *mlli_params = &areq_ctx->mlli_params;
+ unsigned int update_data_len;
+ uint32_t total_in_len = nbytes + *curr_buff_cnt;
+ struct buffer_array sg_data;
+ struct buff_mgr_handle *buff_mgr = drvdata->buff_mgr_handle;
+ unsigned int swap_index = 0;
+ uint32_t dummy = 0;
+ uint32_t mapped_nents = 0;
+
+ SSI_LOG_DEBUG(" update params : curr_buff=%pK "
+ "curr_buff_cnt=0x%X nbytes=0x%X "
+ "src=%pK curr_index=%u \n",
+ curr_buff, *curr_buff_cnt, nbytes,
+ src, areq_ctx->buff_index);
+ /* Init the type of the dma buffer */
+ areq_ctx->data_dma_buf_type = SSI_DMA_BUF_NULL;
+ mlli_params->curr_pool = NULL;
+ areq_ctx->curr_sg = NULL;
+ sg_data.num_of_buffers = 0;
+ areq_ctx->in_nents = 0;
+
+ if (unlikely(total_in_len < block_size)) {
+ SSI_LOG_DEBUG(" less than one block: curr_buff=%pK "
+ "*curr_buff_cnt=0x%X copy_to=%pK\n",
+ curr_buff, *curr_buff_cnt,
+ &curr_buff[*curr_buff_cnt]);
+ areq_ctx->in_nents =
+ ssi_buffer_mgr_get_sgl_nents(src,
+ nbytes,
+ &dummy, NULL);
+ sg_copy_to_buffer(src, areq_ctx->in_nents,
+ &curr_buff[*curr_buff_cnt], nbytes);
+ *curr_buff_cnt += nbytes;
+ return 1;
+ }
+
+ /* Calculate the residue size*/
+ *next_buff_cnt = total_in_len & (block_size - 1);
+ /* update data len */
+ update_data_len = total_in_len - *next_buff_cnt;
+
+ SSI_LOG_DEBUG(" temp length : *next_buff_cnt=0x%X "
+ "update_data_len=0x%X\n",
+ *next_buff_cnt, update_data_len);
+
+ /* Copy the new residue to next buffer */
+ if (*next_buff_cnt != 0) {
+ SSI_LOG_DEBUG(" handle residue: next buff %pK skip data %u"
+ " residue %u \n", next_buff,
+ (update_data_len - *curr_buff_cnt),
+ *next_buff_cnt);
+ ssi_buffer_mgr_copy_scatterlist_portion(next_buff, src,
+ (update_data_len -*curr_buff_cnt),
+ nbytes,SSI_SG_TO_BUF);
+ /* change the buffer index for next operation */
+ swap_index = 1;
+ }
+
+ if (*curr_buff_cnt != 0) {
+ if (ssi_ahash_handle_curr_buf(dev, areq_ctx, curr_buff,
+ *curr_buff_cnt, &sg_data) != 0) {
+ return -ENOMEM;
+ }
+ /* change the buffer index for next operation */
+ swap_index = 1;
+ }
+
+ if ( update_data_len > *curr_buff_cnt ) {
+ if ( unlikely( ssi_buffer_mgr_map_scatterlist( dev,src,
+ (update_data_len -*curr_buff_cnt),
+ DMA_TO_DEVICE,
+ &areq_ctx->in_nents,
+ LLI_MAX_NUM_OF_DATA_ENTRIES,
+ &dummy, &mapped_nents))){
+ goto unmap_curr_buff;
+ }
+ if ( (mapped_nents == 1)
+ && (areq_ctx->data_dma_buf_type == SSI_DMA_BUF_NULL) ) {
+ /* only one entry in the SG and no previous data */
+ memcpy(areq_ctx->buff_sg,src,
+ sizeof(struct scatterlist));
+ areq_ctx->buff_sg->length = update_data_len;
+ areq_ctx->data_dma_buf_type = SSI_DMA_BUF_DLLI;
+ areq_ctx->curr_sg = areq_ctx->buff_sg;
+ } else {
+ areq_ctx->data_dma_buf_type = SSI_DMA_BUF_MLLI;
+ }
+ }
+
+ if (unlikely(areq_ctx->data_dma_buf_type == SSI_DMA_BUF_MLLI)) {
+ mlli_params->curr_pool = buff_mgr->mlli_buffs_pool;
+ /* add the src data to the sg_data */
+ ssi_buffer_mgr_add_scatterlist_entry(&sg_data,
+ areq_ctx->in_nents,
+ src,
+ (update_data_len - *curr_buff_cnt), 0,
+ true, &areq_ctx->mlli_nents);
+ if (unlikely(ssi_buffer_mgr_generate_mlli(dev, &sg_data,
+ mlli_params) != 0)) {
+ goto fail_unmap_din;
+ }
+
+ }
+ areq_ctx->buff_index = (areq_ctx->buff_index^swap_index);
+
+ return 0;
+
+fail_unmap_din:
+ dma_unmap_sg(dev, src, areq_ctx->in_nents, DMA_TO_DEVICE);
+
+unmap_curr_buff:
+ if (*curr_buff_cnt != 0 ) {
+ dma_unmap_sg(dev, areq_ctx->buff_sg, 1, DMA_TO_DEVICE);
+ }
+ return -ENOMEM;
+}
+
+void ssi_buffer_mgr_unmap_hash_request(
+ struct device *dev, void *ctx, struct scatterlist *src, bool do_revert)
+{
+ struct ahash_req_ctx *areq_ctx = (struct ahash_req_ctx *)ctx;
+ uint32_t *prev_len = areq_ctx->buff_index ? &areq_ctx->buff0_cnt :
+ &areq_ctx->buff1_cnt;
+
+ /*In case a pool was set, a table was
+ allocated and should be released */
+ if (areq_ctx->mlli_params.curr_pool != NULL) {
+ SSI_LOG_DEBUG("free MLLI buffer: dma=0x%llX virt=%pK\n",
+ (unsigned long long)areq_ctx->mlli_params.mlli_dma_addr,
+ areq_ctx->mlli_params.mlli_virt_addr);
+ SSI_RESTORE_DMA_ADDR_TO_48BIT(areq_ctx->mlli_params.mlli_dma_addr);
+ dma_pool_free(areq_ctx->mlli_params.curr_pool,
+ areq_ctx->mlli_params.mlli_virt_addr,
+ areq_ctx->mlli_params.mlli_dma_addr);
+ }
+
+ if ((src) && likely(areq_ctx->in_nents != 0)) {
+ SSI_LOG_DEBUG("Unmapped sg src: virt=%pK dma=0x%llX len=0x%X\n",
+ sg_virt(src),
+ (unsigned long long)sg_dma_address(src),
+ sg_dma_len(src));
+ SSI_RESTORE_DMA_ADDR_TO_48BIT(sg_dma_address(src));
+ dma_unmap_sg(dev, src,
+ areq_ctx->in_nents, DMA_TO_DEVICE);
+ }
+
+ if (*prev_len != 0) {
+ SSI_LOG_DEBUG("Unmapped buffer: areq_ctx->buff_sg=%pK"
+ "dma=0x%llX len 0x%X\n",
+ sg_virt(areq_ctx->buff_sg),
+ (unsigned long long)sg_dma_address(areq_ctx->buff_sg),
+ sg_dma_len(areq_ctx->buff_sg));
+ dma_unmap_sg(dev, areq_ctx->buff_sg, 1, DMA_TO_DEVICE);
+ if (!do_revert) {
+ /* clean the previous data length for update operation */
+ *prev_len = 0;
+ } else {
+ areq_ctx->buff_index ^= 1;
+ }
+ }
+}
+
+int ssi_buffer_mgr_init(struct ssi_drvdata *drvdata)
+{
+ struct buff_mgr_handle *buff_mgr_handle;
+ struct device *dev = &drvdata->plat_dev->dev;
+
+ buff_mgr_handle = (struct buff_mgr_handle *)
+ kmalloc(sizeof(struct buff_mgr_handle), GFP_KERNEL);
+ if (buff_mgr_handle == NULL)
+ return -ENOMEM;
+
+ drvdata->buff_mgr_handle = buff_mgr_handle;
+
+ buff_mgr_handle->mlli_buffs_pool = dma_pool_create(
+ "dx_single_mlli_tables", dev,
+ MAX_NUM_OF_TOTAL_MLLI_ENTRIES *
+ LLI_ENTRY_BYTE_SIZE,
+ MLLI_TABLE_MIN_ALIGNMENT, 0);
+
+ if (unlikely(buff_mgr_handle->mlli_buffs_pool == NULL))
+ goto error;
+
+ return 0;
+
+error:
+ ssi_buffer_mgr_fini(drvdata);
+ return -ENOMEM;
+}
+
+int ssi_buffer_mgr_fini(struct ssi_drvdata *drvdata)
+{
+ struct buff_mgr_handle *buff_mgr_handle = drvdata->buff_mgr_handle;
+
+ if (buff_mgr_handle != NULL) {
+ dma_pool_destroy(buff_mgr_handle->mlli_buffs_pool);
+ kfree(drvdata->buff_mgr_handle);
+ drvdata->buff_mgr_handle = NULL;
+
+ }
+ return 0;
+}
+
diff --git a/drivers/staging/ccree/ssi_buffer_mgr.h b/drivers/staging/ccree/ssi_buffer_mgr.h
new file mode 100644
index 0000000..5f4b032
--- /dev/null
+++ b/drivers/staging/ccree/ssi_buffer_mgr.h
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2012-2017 ARM Limited or its affiliates.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* \file buffer_mgr.h
+ Buffer Manager
+ */
+
+#ifndef __SSI_BUFFER_MGR_H__
+#define __SSI_BUFFER_MGR_H__
+
+#include <crypto/algapi.h>
+
+#include "ssi_config.h"
+#include "ssi_driver.h"
+
+
+enum ssi_req_dma_buf_type {
+ SSI_DMA_BUF_NULL = 0,
+ SSI_DMA_BUF_DLLI,
+ SSI_DMA_BUF_MLLI
+};
+
+enum ssi_sg_cpy_direct {
+ SSI_SG_TO_BUF = 0,
+ SSI_SG_FROM_BUF = 1
+};
+
+struct ssi_mlli {
+ ssi_sram_addr_t sram_addr;
+ unsigned int nents; //sg nents
+ unsigned int mlli_nents; //mlli nents might be different than the above
+};
+
+struct mlli_params {
+ struct dma_pool *curr_pool;
+ uint8_t *mlli_virt_addr;
+ dma_addr_t mlli_dma_addr;
+ uint32_t mlli_len;
+};
+
+int ssi_buffer_mgr_init(struct ssi_drvdata *drvdata);
+
+int ssi_buffer_mgr_fini(struct ssi_drvdata *drvdata);
+
+int ssi_buffer_mgr_map_blkcipher_request(
+ struct ssi_drvdata *drvdata,
+ void *ctx,
+ unsigned int ivsize,
+ unsigned int nbytes,
+ void *info,
+ struct scatterlist *src,
+ struct scatterlist *dst);
+
+void ssi_buffer_mgr_unmap_blkcipher_request(
+ struct device *dev,
+ void *ctx,
+ unsigned int ivsize,
+ struct scatterlist *src,
+ struct scatterlist *dst);
+
+int ssi_buffer_mgr_map_aead_request(struct ssi_drvdata *drvdata, struct aead_request *req);
+
+void ssi_buffer_mgr_unmap_aead_request(struct device *dev, struct aead_request *req);
+
+int ssi_buffer_mgr_map_hash_request_final(struct ssi_drvdata *drvdata, void *ctx, struct scatterlist *src, unsigned int nbytes, bool do_update);
+
+int ssi_buffer_mgr_map_hash_request_update(struct ssi_drvdata *drvdata, void *ctx, struct scatterlist *src, unsigned int nbytes, unsigned int block_size);
+
+void ssi_buffer_mgr_unmap_hash_request(struct device *dev, void *ctx, struct scatterlist *src, bool do_revert);
+
+void ssi_buffer_mgr_copy_scatterlist_portion(u8 *dest, struct scatterlist *sg, uint32_t to_skip, uint32_t end, enum ssi_sg_cpy_direct direct);
+
+void ssi_buffer_mgr_zero_sgl(struct scatterlist *sgl, uint32_t data_len);
+
+
+#ifdef CC_DMA_48BIT_SIM
+dma_addr_t ssi_buff_mgr_update_dma_addr(dma_addr_t orig_addr, uint32_t data_len);
+dma_addr_t ssi_buff_mgr_restore_dma_addr(dma_addr_t orig_addr);
+
+#define SSI_UPDATE_DMA_ADDR_TO_48BIT(addr,size) addr = \
+ ssi_buff_mgr_update_dma_addr(addr,size)
+#define SSI_RESTORE_DMA_ADDR_TO_48BIT(addr) addr = \
+ ssi_buff_mgr_restore_dma_addr(addr)
+#else
+
+#define SSI_UPDATE_DMA_ADDR_TO_48BIT(addr,size) addr = addr
+#define SSI_RESTORE_DMA_ADDR_TO_48BIT(addr) addr = addr
+
+#endif
+
+#endif /*__BUFFER_MGR_H__*/
+
diff --git a/drivers/staging/ccree/ssi_cipher.c b/drivers/staging/ccree/ssi_cipher.c
new file mode 100644
index 0000000..664ed7e
--- /dev/null
+++ b/drivers/staging/ccree/ssi_cipher.c
@@ -0,0 +1,1503 @@
+/*
+ * Copyright (C) 2012-2017 ARM Limited or its affiliates.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/semaphore.h>
+#include <crypto/algapi.h>
+#include <crypto/internal/skcipher.h>
+#include <crypto/aes.h>
+#include <crypto/ctr.h>
+#include <crypto/des.h>
+
+#include "ssi_config.h"
+#include "ssi_driver.h"
+#include "cc_lli_defs.h"
+#include "ssi_buffer_mgr.h"
+#include "ssi_cipher.h"
+#include "ssi_request_mgr.h"
+#include "ssi_sysfs.h"
+#include "ssi_fips_local.h"
+
+#define MAX_ABLKCIPHER_SEQ_LEN 6
+
+#define template_ablkcipher template_u.ablkcipher
+#define template_sblkcipher template_u.blkcipher
+
+#define SSI_MIN_AES_XTS_SIZE 0x10
+#define SSI_MAX_AES_XTS_SIZE 0x2000
+struct ssi_blkcipher_handle {
+ struct list_head blkcipher_alg_list;
+};
+
+struct cc_user_key_info {
+ uint8_t *key;
+ dma_addr_t key_dma_addr;
+};
+struct cc_hw_key_info {
+ enum HwCryptoKey key1_slot;
+ enum HwCryptoKey key2_slot;
+};
+
+struct ssi_ablkcipher_ctx {
+ struct ssi_drvdata *drvdata;
+ int keylen;
+ int key_round_number;
+ int cipher_mode;
+ int flow_mode;
+ unsigned int flags;
+ struct blkcipher_req_ctx *sync_ctx;
+ struct cc_user_key_info user;
+ struct cc_hw_key_info hw;
+ struct crypto_shash *shash_tfm;
+};
+
+static void ssi_ablkcipher_complete(struct device *dev, void *ssi_req, void __iomem *cc_base);
+
+
+static int validate_keys_sizes(struct ssi_ablkcipher_ctx *ctx_p, uint32_t size) {
+ switch (ctx_p->flow_mode){
+ case S_DIN_to_AES:
+ switch (size){
+ case CC_AES_128_BIT_KEY_SIZE:
+ case CC_AES_192_BIT_KEY_SIZE:
+ if (likely((ctx_p->cipher_mode != DRV_CIPHER_XTS) &&
+ (ctx_p->cipher_mode != DRV_CIPHER_ESSIV) &&
+ (ctx_p->cipher_mode != DRV_CIPHER_BITLOCKER)))
+ return 0;
+ break;
+ case CC_AES_256_BIT_KEY_SIZE:
+ return 0;
+ case (CC_AES_192_BIT_KEY_SIZE*2):
+ case (CC_AES_256_BIT_KEY_SIZE*2):
+ if (likely((ctx_p->cipher_mode == DRV_CIPHER_XTS) ||
+ (ctx_p->cipher_mode == DRV_CIPHER_ESSIV) ||
+ (ctx_p->cipher_mode == DRV_CIPHER_BITLOCKER)))
+ return 0;
+ break;
+ default:
+ break;
+ }
+ case S_DIN_to_DES:
+ if (likely(size == DES3_EDE_KEY_SIZE ||
+ size == DES_KEY_SIZE))
+ return 0;
+ break;
+#if SSI_CC_HAS_MULTI2
+ case S_DIN_to_MULTI2:
+ if (likely(size == CC_MULTI2_SYSTEM_N_DATA_KEY_SIZE))
+ return 0;
+ break;
+#endif
+ default:
+ break;
+
+ }
+ return -EINVAL;
+}
+
+
+static int validate_data_size(struct ssi_ablkcipher_ctx *ctx_p, unsigned int size) {
+ switch (ctx_p->flow_mode){
+ case S_DIN_to_AES:
+ switch (ctx_p->cipher_mode){
+ case DRV_CIPHER_XTS:
+ if ((size >= SSI_MIN_AES_XTS_SIZE) &&
+ (size <= SSI_MAX_AES_XTS_SIZE) &&
+ IS_ALIGNED(size, AES_BLOCK_SIZE))
+ return 0;
+ break;
+ case DRV_CIPHER_CBC_CTS:
+ if (likely(size >= AES_BLOCK_SIZE))
+ return 0;
+ break;
+ case DRV_CIPHER_OFB:
+ case DRV_CIPHER_CTR:
+ return 0;
+ case DRV_CIPHER_ECB:
+ case DRV_CIPHER_CBC:
+ case DRV_CIPHER_ESSIV:
+ case DRV_CIPHER_BITLOCKER:
+ if (likely(IS_ALIGNED(size, AES_BLOCK_SIZE)))
+ return 0;
+ break;
+ default:
+ break;
+ }
+ break;
+ case S_DIN_to_DES:
+ if (likely(IS_ALIGNED(size, DES_BLOCK_SIZE)))
+ return 0;
+ break;
+#if SSI_CC_HAS_MULTI2
+ case S_DIN_to_MULTI2:
+ switch (ctx_p->cipher_mode) {
+ case DRV_MULTI2_CBC:
+ if (likely(IS_ALIGNED(size, CC_MULTI2_BLOCK_SIZE)))
+ return 0;
+ break;
+ case DRV_MULTI2_OFB:
+ return 0;
+ default:
+ break;
+ }
+ break;
+#endif /*SSI_CC_HAS_MULTI2*/
+ default:
+ break;
+
+ }
+ return -EINVAL;
+}
+
+static unsigned int get_max_keysize(struct crypto_tfm *tfm)
+{
+ struct ssi_crypto_alg *ssi_alg = container_of(tfm->__crt_alg, struct ssi_crypto_alg, crypto_alg);
+
+ if ((ssi_alg->crypto_alg.cra_flags & CRYPTO_ALG_TYPE_MASK) == CRYPTO_ALG_TYPE_ABLKCIPHER) {
+ return ssi_alg->crypto_alg.cra_ablkcipher.max_keysize;
+ }
+
+ if ((ssi_alg->crypto_alg.cra_flags & CRYPTO_ALG_TYPE_MASK) == CRYPTO_ALG_TYPE_BLKCIPHER) {
+ return ssi_alg->crypto_alg.cra_blkcipher.max_keysize;
+ }
+
+ return 0;
+}
+
+static int ssi_blkcipher_init(struct crypto_tfm *tfm)
+{
+ struct ssi_ablkcipher_ctx *ctx_p = crypto_tfm_ctx(tfm);
+ struct crypto_alg *alg = tfm->__crt_alg;
+ struct ssi_crypto_alg *ssi_alg =
+ container_of(alg, struct ssi_crypto_alg, crypto_alg);
+ struct device *dev;
+ int rc = 0;
+ unsigned int max_key_buf_size = get_max_keysize(tfm);
+
+ SSI_LOG_DEBUG("Initializing context @%p for %s\n", ctx_p,
+ crypto_tfm_alg_name(tfm));
+
+ CHECK_AND_RETURN_UPON_FIPS_ERROR();
+ ctx_p->cipher_mode = ssi_alg->cipher_mode;
+ ctx_p->flow_mode = ssi_alg->flow_mode;
+ ctx_p->drvdata = ssi_alg->drvdata;
+ dev = &ctx_p->drvdata->plat_dev->dev;
+
+ /* Allocate key buffer, cache line aligned */
+ ctx_p->user.key = kmalloc(max_key_buf_size, GFP_KERNEL|GFP_DMA);
+ if (!ctx_p->user.key) {
+ SSI_LOG_ERR("Allocating key buffer in context failed\n");
+ rc = -ENOMEM;
+ }
+ SSI_LOG_DEBUG("Allocated key buffer in context. key=@%p\n",
+ ctx_p->user.key);
+
+ /* Map key buffer */
+ ctx_p->user.key_dma_addr = dma_map_single(dev, (void *)ctx_p->user.key,
+ max_key_buf_size, DMA_TO_DEVICE);
+ if (dma_mapping_error(dev, ctx_p->user.key_dma_addr)) {
+ SSI_LOG_ERR("Mapping Key %u B at va=%pK for DMA failed\n",
+ max_key_buf_size, ctx_p->user.key);
+ return -ENOMEM;
+ }
+ SSI_UPDATE_DMA_ADDR_TO_48BIT(ctx_p->user.key_dma_addr, max_key_buf_size);
+ SSI_LOG_DEBUG("Mapped key %u B at va=%pK to dma=0x%llX\n",
+ max_key_buf_size, ctx_p->user.key,
+ (unsigned long long)ctx_p->user.key_dma_addr);
+
+ if (ctx_p->cipher_mode == DRV_CIPHER_ESSIV) {
+ /* Alloc hash tfm for essiv */
+ ctx_p->shash_tfm = crypto_alloc_shash("sha256-generic", 0, 0);
+ if (IS_ERR(ctx_p->shash_tfm)) {
+ SSI_LOG_ERR("Error allocating hash tfm for ESSIV.\n");
+ return PTR_ERR(ctx_p->shash_tfm);
+ }
+ }
+
+ return rc;
+}
+
+static void ssi_blkcipher_exit(struct crypto_tfm *tfm)
+{
+ struct ssi_ablkcipher_ctx *ctx_p = crypto_tfm_ctx(tfm);
+ struct device *dev = &ctx_p->drvdata->plat_dev->dev;
+ unsigned int max_key_buf_size = get_max_keysize(tfm);
+
+ SSI_LOG_DEBUG("Clearing context @%p for %s\n",
+ crypto_tfm_ctx(tfm), crypto_tfm_alg_name(tfm));
+
+ if (ctx_p->cipher_mode == DRV_CIPHER_ESSIV) {
+ /* Free hash tfm for essiv */
+ crypto_free_shash(ctx_p->shash_tfm);
+ ctx_p->shash_tfm = NULL;
+ }
+
+ /* Unmap key buffer */
+ SSI_RESTORE_DMA_ADDR_TO_48BIT(ctx_p->user.key_dma_addr);
+ dma_unmap_single(dev, ctx_p->user.key_dma_addr, max_key_buf_size,
+ DMA_TO_DEVICE);
+ SSI_LOG_DEBUG("Unmapped key buffer key_dma_addr=0x%llX\n",
+ (unsigned long long)ctx_p->user.key_dma_addr);
+
+ /* Free key buffer in context */
+ kfree(ctx_p->user.key);
+ SSI_LOG_DEBUG("Free key buffer in context. key=@%p\n", ctx_p->user.key);
+}
+
+
+typedef struct tdes_keys{
+ u8 key1[DES_KEY_SIZE];
+ u8 key2[DES_KEY_SIZE];
+ u8 key3[DES_KEY_SIZE];
+}tdes_keys_t;
+
+static const u8 zero_buff[] = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0};
+
+/* The function verifies that tdes keys are not weak.*/
+static int ssi_fips_verify_3des_keys(const u8 *key, unsigned int keylen)
+{
+#ifdef CCREE_FIPS_SUPPORT
+ tdes_keys_t *tdes_key = (tdes_keys_t*)key;
+
+ /* verify key1 != key2 and key3 != key2*/
+ if (unlikely( (memcmp((u8*)tdes_key->key1, (u8*)tdes_key->key2, sizeof(tdes_key->key1)) == 0) ||
+ (memcmp((u8*)tdes_key->key3, (u8*)tdes_key->key2, sizeof(tdes_key->key3)) == 0) )) {
+ return -ENOEXEC;
+ }
+#endif /* CCREE_FIPS_SUPPORT */
+
+ return 0;
+}
+
+/* The function verifies that xts keys are not weak.*/
+static int ssi_fips_verify_xts_keys(const u8 *key, unsigned int keylen)
+{
+#ifdef CCREE_FIPS_SUPPORT
+ /* Weak key is define as key that its first half (128/256 lsb) equals its second half (128/256 msb) */
+ int singleKeySize = keylen >> 1;
+
+ if (unlikely(memcmp(key, &key[singleKeySize], singleKeySize) == 0)) {
+ return -ENOEXEC;
+ }
+#endif /* CCREE_FIPS_SUPPORT */
+
+ return 0;
+}
+
+static enum HwCryptoKey hw_key_to_cc_hw_key(int slot_num)
+{
+ switch (slot_num) {
+ case 0:
+ return KFDE0_KEY;
+ case 1:
+ return KFDE1_KEY;
+ case 2:
+ return KFDE2_KEY;
+ case 3:
+ return KFDE3_KEY;
+ }
+ return END_OF_KEYS;
+}
+
+static int ssi_blkcipher_setkey(struct crypto_tfm *tfm,
+ const u8 *key,
+ unsigned int keylen)
+{
+ struct ssi_ablkcipher_ctx *ctx_p = crypto_tfm_ctx(tfm);
+ struct device *dev = &ctx_p->drvdata->plat_dev->dev;
+ u32 tmp[DES_EXPKEY_WORDS];
+ unsigned int max_key_buf_size = get_max_keysize(tfm);
+ DECL_CYCLE_COUNT_RESOURCES;
+
+ SSI_LOG_DEBUG("Setting key in context @%p for %s. keylen=%u\n",
+ ctx_p, crypto_tfm_alg_name(tfm), keylen);
+ dump_byte_array("key", (uint8_t *)key, keylen);
+
+ CHECK_AND_RETURN_UPON_FIPS_ERROR();
+
+ SSI_LOG_DEBUG("ssi_blkcipher_setkey: after FIPS check");
+
+ /* STAT_PHASE_0: Init and sanity checks */
+ START_CYCLE_COUNT();
+
+#if SSI_CC_HAS_MULTI2
+ /*last byte of key buffer is round number and should not be a part of key size*/
+ if (ctx_p->flow_mode == S_DIN_to_MULTI2) {
+ keylen -=1;
+ }
+#endif /*SSI_CC_HAS_MULTI2*/
+
+ if (unlikely(validate_keys_sizes(ctx_p,keylen) != 0)) {
+ SSI_LOG_ERR("Unsupported key size %d.\n", keylen);
+ crypto_tfm_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN);
+ return -EINVAL;
+ }
+
+ if (ssi_is_hw_key(tfm)) {
+ /* setting HW key slots */
+ struct arm_hw_key_info *hki = (struct arm_hw_key_info*)key;
+
+ if (unlikely(ctx_p->flow_mode != S_DIN_to_AES)) {
+ SSI_LOG_ERR("HW key not supported for non-AES flows\n");
+ return -EINVAL;
+ }
+
+ ctx_p->hw.key1_slot = hw_key_to_cc_hw_key(hki->hw_key1);
+ if (unlikely(ctx_p->hw.key1_slot == END_OF_KEYS)) {
+ SSI_LOG_ERR("Unsupported hw key1 number (%d)\n", hki->hw_key1);
+ return -EINVAL;
+ }
+
+ if ((ctx_p->cipher_mode == DRV_CIPHER_XTS) ||
+ (ctx_p->cipher_mode == DRV_CIPHER_ESSIV) ||
+ (ctx_p->cipher_mode == DRV_CIPHER_BITLOCKER)) {
+ if (unlikely(hki->hw_key1 == hki->hw_key2)) {
+ SSI_LOG_ERR("Illegal hw key numbers (%d,%d)\n", hki->hw_key1, hki->hw_key2);
+ return -EINVAL;
+ }
+ ctx_p->hw.key2_slot = hw_key_to_cc_hw_key(hki->hw_key2);
+ if (unlikely(ctx_p->hw.key2_slot == END_OF_KEYS)) {
+ SSI_LOG_ERR("Unsupported hw key2 number (%d)\n", hki->hw_key2);
+ return -EINVAL;
+ }
+ }
+
+ ctx_p->keylen = keylen;
+ END_CYCLE_COUNT(STAT_OP_TYPE_SETKEY, STAT_PHASE_0);
+ SSI_LOG_DEBUG("ssi_blkcipher_setkey: ssi_is_hw_key ret 0");
+
+ return 0;
+ }
+
+ // verify weak keys
+ if (ctx_p->flow_mode == S_DIN_to_DES) {
+ if (unlikely(!des_ekey(tmp, key)) &&
+ (crypto_tfm_get_flags(tfm) & CRYPTO_TFM_REQ_WEAK_KEY)) {
+ tfm->crt_flags |= CRYPTO_TFM_RES_WEAK_KEY;
+ SSI_LOG_DEBUG("ssi_blkcipher_setkey: weak DES key");
+ return -EINVAL;
+ }
+ }
+ if ((ctx_p->cipher_mode == DRV_CIPHER_XTS) &&
+ ssi_fips_verify_xts_keys(key, keylen) != 0) {
+ SSI_LOG_DEBUG("ssi_blkcipher_setkey: weak XTS key");
+ return -EINVAL;
+ }
+ if ((ctx_p->flow_mode == S_DIN_to_DES) &&
+ (keylen == DES3_EDE_KEY_SIZE) &&
+ ssi_fips_verify_3des_keys(key, keylen) != 0) {
+ SSI_LOG_DEBUG("ssi_blkcipher_setkey: weak 3DES key");
+ return -EINVAL;
+ }
+
+
+ END_CYCLE_COUNT(STAT_OP_TYPE_SETKEY, STAT_PHASE_0);
+
+ /* STAT_PHASE_1: Copy key to ctx */
+ START_CYCLE_COUNT();
+ SSI_RESTORE_DMA_ADDR_TO_48BIT(ctx_p->user.key_dma_addr);
+ dma_sync_single_for_cpu(dev, ctx_p->user.key_dma_addr,
+ max_key_buf_size, DMA_TO_DEVICE);
+#if SSI_CC_HAS_MULTI2
+ if (ctx_p->flow_mode == S_DIN_to_MULTI2) {
+ memcpy(ctx_p->user.key, key, CC_MULTI2_SYSTEM_N_DATA_KEY_SIZE);
+ ctx_p->key_round_number = key[CC_MULTI2_SYSTEM_N_DATA_KEY_SIZE];
+ if (ctx_p->key_round_number < CC_MULTI2_MIN_NUM_ROUNDS ||
+ ctx_p->key_round_number > CC_MULTI2_MAX_NUM_ROUNDS) {
+ crypto_tfm_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN);
+ SSI_LOG_DEBUG("ssi_blkcipher_setkey: SSI_CC_HAS_MULTI2 einval");
+ return -EINVAL;
+ }
+ } else
+#endif /*SSI_CC_HAS_MULTI2*/
+ {
+ memcpy(ctx_p->user.key, key, keylen);
+ if (keylen == 24)
+ memset(ctx_p->user.key + 24, 0, CC_AES_KEY_SIZE_MAX - 24);
+
+ if (ctx_p->cipher_mode == DRV_CIPHER_ESSIV) {
+ /* sha256 for key2 - use sw implementation */
+ int key_len = keylen >> 1;
+ int err;
+ SHASH_DESC_ON_STACK(desc, ctx_p->shash_tfm);
+ desc->tfm = ctx_p->shash_tfm;
+
+ err = crypto_shash_digest(desc, ctx_p->user.key, key_len, ctx_p->user.key + key_len);
+ if (err) {
+ SSI_LOG_ERR("Failed to hash ESSIV key.\n");
+ return err;
+ }
+ }
+ }
+ dma_sync_single_for_device(dev, ctx_p->user.key_dma_addr,
+ max_key_buf_size, DMA_TO_DEVICE);
+ SSI_UPDATE_DMA_ADDR_TO_48BIT(ctx_p->user.key_dma_addr ,max_key_buf_size);
+ ctx_p->keylen = keylen;
+
+ END_CYCLE_COUNT(STAT_OP_TYPE_SETKEY, STAT_PHASE_1);
+
+ SSI_LOG_DEBUG("ssi_blkcipher_setkey: return safely");
+ return 0;
+}
+
+static inline void
+ssi_blkcipher_create_setup_desc(
+ struct crypto_tfm *tfm,
+ struct blkcipher_req_ctx *req_ctx,
+ unsigned int ivsize,
+ unsigned int nbytes,
+ HwDesc_s desc[],
+ unsigned int *seq_size)
+{
+ struct ssi_ablkcipher_ctx *ctx_p = crypto_tfm_ctx(tfm);
+ int cipher_mode = ctx_p->cipher_mode;
+ int flow_mode = ctx_p->flow_mode;
+ int direction = req_ctx->gen_ctx.op_type;
+ dma_addr_t key_dma_addr = ctx_p->user.key_dma_addr;
+ unsigned int key_len = ctx_p->keylen;
+ dma_addr_t iv_dma_addr = req_ctx->gen_ctx.iv_dma_addr;
+ unsigned int du_size = nbytes;
+
+ struct ssi_crypto_alg *ssi_alg = container_of(tfm->__crt_alg, struct ssi_crypto_alg, crypto_alg);
+
+ if ((ssi_alg->crypto_alg.cra_flags & CRYPTO_ALG_BULK_MASK) == CRYPTO_ALG_BULK_DU_512)
+ du_size = 512;
+ if ((ssi_alg->crypto_alg.cra_flags & CRYPTO_ALG_BULK_MASK) == CRYPTO_ALG_BULK_DU_4096)
+ du_size = 4096;
+
+ switch (cipher_mode) {
+ case DRV_CIPHER_CBC:
+ case DRV_CIPHER_CBC_CTS:
+ case DRV_CIPHER_CTR:
+ case DRV_CIPHER_OFB:
+ /* Load cipher state */
+ HW_DESC_INIT(&desc[*seq_size]);
+ HW_DESC_SET_DIN_TYPE(&desc[*seq_size], DMA_DLLI,
+ iv_dma_addr, ivsize,
+ NS_BIT);
+ HW_DESC_SET_CIPHER_CONFIG0(&desc[*seq_size], direction);
+ HW_DESC_SET_FLOW_MODE(&desc[*seq_size], flow_mode);
+ HW_DESC_SET_CIPHER_MODE(&desc[*seq_size], cipher_mode);
+ if ((cipher_mode == DRV_CIPHER_CTR) ||
+ (cipher_mode == DRV_CIPHER_OFB) ) {
+ HW_DESC_SET_SETUP_MODE(&desc[*seq_size],
+ SETUP_LOAD_STATE1);
+ } else {
+ HW_DESC_SET_SETUP_MODE(&desc[*seq_size],
+ SETUP_LOAD_STATE0);
+ }
+ (*seq_size)++;
+ /*FALLTHROUGH*/
+ case DRV_CIPHER_ECB:
+ /* Load key */
+ HW_DESC_INIT(&desc[*seq_size]);
+ HW_DESC_SET_CIPHER_MODE(&desc[*seq_size], cipher_mode);
+ HW_DESC_SET_CIPHER_CONFIG0(&desc[*seq_size], direction);
+ if (flow_mode == S_DIN_to_AES) {
+
+ if (ssi_is_hw_key(tfm)) {
+ HW_DESC_SET_HW_CRYPTO_KEY(&desc[*seq_size], ctx_p->hw.key1_slot);
+ } else {
+ HW_DESC_SET_DIN_TYPE(&desc[*seq_size], DMA_DLLI,
+ key_dma_addr,
+ ((key_len == 24) ? AES_MAX_KEY_SIZE : key_len),
+ NS_BIT);
+ }
+ HW_DESC_SET_KEY_SIZE_AES(&desc[*seq_size], key_len);
+ } else {
+ /*des*/
+ HW_DESC_SET_DIN_TYPE(&desc[*seq_size], DMA_DLLI,
+ key_dma_addr, key_len,
+ NS_BIT);
+ HW_DESC_SET_KEY_SIZE_DES(&desc[*seq_size], key_len);
+ }
+ HW_DESC_SET_FLOW_MODE(&desc[*seq_size], flow_mode);
+ HW_DESC_SET_SETUP_MODE(&desc[*seq_size], SETUP_LOAD_KEY0);
+ (*seq_size)++;
+ break;
+ case DRV_CIPHER_XTS:
+ case DRV_CIPHER_ESSIV:
+ case DRV_CIPHER_BITLOCKER:
+ /* Load AES key */
+ HW_DESC_INIT(&desc[*seq_size]);
+ HW_DESC_SET_CIPHER_MODE(&desc[*seq_size], cipher_mode);
+ HW_DESC_SET_CIPHER_CONFIG0(&desc[*seq_size], direction);
+ if (ssi_is_hw_key(tfm)) {
+ HW_DESC_SET_HW_CRYPTO_KEY(&desc[*seq_size], ctx_p->hw.key1_slot);
+ } else {
+ HW_DESC_SET_DIN_TYPE(&desc[*seq_size], DMA_DLLI,
+ key_dma_addr, key_len/2,
+ NS_BIT);
+ }
+ HW_DESC_SET_KEY_SIZE_AES(&desc[*seq_size], key_len/2);
+ HW_DESC_SET_FLOW_MODE(&desc[*seq_size], flow_mode);
+ HW_DESC_SET_SETUP_MODE(&desc[*seq_size], SETUP_LOAD_KEY0);
+ (*seq_size)++;
+
+ /* load XEX key */
+ HW_DESC_INIT(&desc[*seq_size]);
+ HW_DESC_SET_CIPHER_MODE(&desc[*seq_size], cipher_mode);
+ HW_DESC_SET_CIPHER_CONFIG0(&desc[*seq_size], direction);
+ if (ssi_is_hw_key(tfm)) {
+ HW_DESC_SET_HW_CRYPTO_KEY(&desc[*seq_size], ctx_p->hw.key2_slot);
+ } else {
+ HW_DESC_SET_DIN_TYPE(&desc[*seq_size], DMA_DLLI,
+ (key_dma_addr+key_len/2), key_len/2,
+ NS_BIT);
+ }
+ HW_DESC_SET_XEX_DATA_UNIT_SIZE(&desc[*seq_size], du_size);
+ HW_DESC_SET_FLOW_MODE(&desc[*seq_size], S_DIN_to_AES2);
+ HW_DESC_SET_KEY_SIZE_AES(&desc[*seq_size], key_len/2);
+ HW_DESC_SET_SETUP_MODE(&desc[*seq_size], SETUP_LOAD_XEX_KEY);
+ (*seq_size)++;
+
+ /* Set state */
+ HW_DESC_INIT(&desc[*seq_size]);
+ HW_DESC_SET_SETUP_MODE(&desc[*seq_size], SETUP_LOAD_STATE1);
+ HW_DESC_SET_CIPHER_MODE(&desc[*seq_size], cipher_mode);
+ HW_DESC_SET_CIPHER_CONFIG0(&desc[*seq_size], direction);
+ HW_DESC_SET_KEY_SIZE_AES(&desc[*seq_size], key_len/2);
+ HW_DESC_SET_FLOW_MODE(&desc[*seq_size], flow_mode);
+ HW_DESC_SET_DIN_TYPE(&desc[*seq_size], DMA_DLLI,
+ iv_dma_addr, CC_AES_BLOCK_SIZE,
+ NS_BIT);
+ (*seq_size)++;
+ break;
+ default:
+ SSI_LOG_ERR("Unsupported cipher mode (%d)\n", cipher_mode);
+ BUG();
+ }
+}
+
+#if SSI_CC_HAS_MULTI2
+static inline void ssi_blkcipher_create_multi2_setup_desc(
+ struct crypto_tfm *tfm,
+ struct blkcipher_req_ctx *req_ctx,
+ unsigned int ivsize,
+ HwDesc_s desc[],
+ unsigned int *seq_size)
+{
+ struct ssi_ablkcipher_ctx *ctx_p = crypto_tfm_ctx(tfm);
+
+ int direction = req_ctx->gen_ctx.op_type;
+ /* Load system key */
+ HW_DESC_INIT(&desc[*seq_size]);
+ HW_DESC_SET_CIPHER_MODE(&desc[*seq_size], ctx_p->cipher_mode);
+ HW_DESC_SET_CIPHER_CONFIG0(&desc[*seq_size], direction);
+ HW_DESC_SET_DIN_TYPE(&desc[*seq_size], DMA_DLLI, ctx_p->user.key_dma_addr,
+ CC_MULTI2_SYSTEM_KEY_SIZE,
+ NS_BIT);
+ HW_DESC_SET_FLOW_MODE(&desc[*seq_size], ctx_p->flow_mode);
+ HW_DESC_SET_SETUP_MODE(&desc[*seq_size], SETUP_LOAD_KEY0);
+ (*seq_size)++;
+
+ /* load data key */
+ HW_DESC_INIT(&desc[*seq_size]);
+ HW_DESC_SET_DIN_TYPE(&desc[*seq_size], DMA_DLLI,
+ (ctx_p->user.key_dma_addr +
+ CC_MULTI2_SYSTEM_KEY_SIZE),
+ CC_MULTI2_DATA_KEY_SIZE, NS_BIT);
+ HW_DESC_SET_MULTI2_NUM_ROUNDS(&desc[*seq_size],
+ ctx_p->key_round_number);
+ HW_DESC_SET_FLOW_MODE(&desc[*seq_size], ctx_p->flow_mode);
+ HW_DESC_SET_CIPHER_MODE(&desc[*seq_size], ctx_p->cipher_mode);
+ HW_DESC_SET_CIPHER_CONFIG0(&desc[*seq_size], direction);
+ HW_DESC_SET_SETUP_MODE(&desc[*seq_size], SETUP_LOAD_STATE0 );
+ (*seq_size)++;
+
+
+ /* Set state */
+ HW_DESC_INIT(&desc[*seq_size]);
+ HW_DESC_SET_DIN_TYPE(&desc[*seq_size], DMA_DLLI,
+ req_ctx->gen_ctx.iv_dma_addr,
+ ivsize, NS_BIT);
+ HW_DESC_SET_CIPHER_CONFIG0(&desc[*seq_size], direction);
+ HW_DESC_SET_FLOW_MODE(&desc[*seq_size], ctx_p->flow_mode);
+ HW_DESC_SET_CIPHER_MODE(&desc[*seq_size], ctx_p->cipher_mode);
+ HW_DESC_SET_SETUP_MODE(&desc[*seq_size], SETUP_LOAD_STATE1);
+ (*seq_size)++;
+
+}
+#endif /*SSI_CC_HAS_MULTI2*/
+
+static inline void
+ssi_blkcipher_create_data_desc(
+ struct crypto_tfm *tfm,
+ struct blkcipher_req_ctx *req_ctx,
+ struct scatterlist *dst, struct scatterlist *src,
+ unsigned int nbytes,
+ void *areq,
+ HwDesc_s desc[],
+ unsigned int *seq_size)
+{
+ struct ssi_ablkcipher_ctx *ctx_p = crypto_tfm_ctx(tfm);
+ unsigned int flow_mode = ctx_p->flow_mode;
+
+ switch (ctx_p->flow_mode) {
+ case S_DIN_to_AES:
+ flow_mode = DIN_AES_DOUT;
+ break;
+ case S_DIN_to_DES:
+ flow_mode = DIN_DES_DOUT;
+ break;
+#if SSI_CC_HAS_MULTI2
+ case S_DIN_to_MULTI2:
+ flow_mode = DIN_MULTI2_DOUT;
+ break;
+#endif /*SSI_CC_HAS_MULTI2*/
+ default:
+ SSI_LOG_ERR("invalid flow mode, flow_mode = %d \n", flow_mode);
+ return;
+ }
+ /* Process */
+ if (likely(req_ctx->dma_buf_type == SSI_DMA_BUF_DLLI)){
+ SSI_LOG_DEBUG(" data params addr 0x%llX length 0x%X \n",
+ (unsigned long long)sg_dma_address(src),
+ nbytes);
+ SSI_LOG_DEBUG(" data params addr 0x%llX length 0x%X \n",
+ (unsigned long long)sg_dma_address(dst),
+ nbytes);
+ HW_DESC_INIT(&desc[*seq_size]);
+ HW_DESC_SET_DIN_TYPE(&desc[*seq_size], DMA_DLLI,
+ sg_dma_address(src),
+ nbytes, NS_BIT);
+ HW_DESC_SET_DOUT_DLLI(&desc[*seq_size],
+ sg_dma_address(dst),
+ nbytes,
+ NS_BIT, (areq == NULL)? 0:1);
+ if (areq != NULL) {
+ HW_DESC_SET_QUEUE_LAST_IND(&desc[*seq_size]);
+ }
+ HW_DESC_SET_FLOW_MODE(&desc[*seq_size], flow_mode);
+ (*seq_size)++;
+ } else {
+ /* bypass */
+ SSI_LOG_DEBUG(" bypass params addr 0x%llX "
+ "length 0x%X addr 0x%08X\n",
+ (unsigned long long)req_ctx->mlli_params.mlli_dma_addr,
+ req_ctx->mlli_params.mlli_len,
+ (unsigned int)ctx_p->drvdata->mlli_sram_addr);
+ HW_DESC_INIT(&desc[*seq_size]);
+ HW_DESC_SET_DIN_TYPE(&desc[*seq_size], DMA_DLLI,
+ req_ctx->mlli_params.mlli_dma_addr,
+ req_ctx->mlli_params.mlli_len,
+ NS_BIT);
+ HW_DESC_SET_DOUT_SRAM(&desc[*seq_size],
+ ctx_p->drvdata->mlli_sram_addr,
+ req_ctx->mlli_params.mlli_len);
+ HW_DESC_SET_FLOW_MODE(&desc[*seq_size], BYPASS);
+ (*seq_size)++;
+
+ HW_DESC_INIT(&desc[*seq_size]);
+ HW_DESC_SET_DIN_TYPE(&desc[*seq_size], DMA_MLLI,
+ ctx_p->drvdata->mlli_sram_addr,
+ req_ctx->in_mlli_nents, NS_BIT);
+ if (req_ctx->out_nents == 0) {
+ SSI_LOG_DEBUG(" din/dout params addr 0x%08X "
+ "addr 0x%08X\n",
+ (unsigned int)ctx_p->drvdata->mlli_sram_addr,
+ (unsigned int)ctx_p->drvdata->mlli_sram_addr);
+ HW_DESC_SET_DOUT_MLLI(&desc[*seq_size],
+ ctx_p->drvdata->mlli_sram_addr,
+ req_ctx->in_mlli_nents,
+ NS_BIT,(areq == NULL)? 0:1);
+ } else {
+ SSI_LOG_DEBUG(" din/dout params "
+ "addr 0x%08X addr 0x%08X\n",
+ (unsigned int)ctx_p->drvdata->mlli_sram_addr,
+ (unsigned int)ctx_p->drvdata->mlli_sram_addr +
+ (uint32_t)LLI_ENTRY_BYTE_SIZE *
+ req_ctx->in_nents);
+ HW_DESC_SET_DOUT_MLLI(&desc[*seq_size],
+ (ctx_p->drvdata->mlli_sram_addr +
+ LLI_ENTRY_BYTE_SIZE *
+ req_ctx->in_mlli_nents),
+ req_ctx->out_mlli_nents, NS_BIT,(areq == NULL)? 0:1);
+ }
+ if (areq != NULL) {
+ HW_DESC_SET_QUEUE_LAST_IND(&desc[*seq_size]);
+ }
+ HW_DESC_SET_FLOW_MODE(&desc[*seq_size], flow_mode);
+ (*seq_size)++;
+ }
+}
+
+static int ssi_blkcipher_complete(struct device *dev,
+ struct ssi_ablkcipher_ctx *ctx_p,
+ struct blkcipher_req_ctx *req_ctx,
+ struct scatterlist *dst, struct scatterlist *src,
+ void *info, //req info
+ unsigned int ivsize,
+ void *areq,
+ void __iomem *cc_base)
+{
+ int completion_error = 0;
+ uint32_t inflight_counter;
+ DECL_CYCLE_COUNT_RESOURCES;
+
+ START_CYCLE_COUNT();
+ ssi_buffer_mgr_unmap_blkcipher_request(dev, req_ctx, ivsize, src, dst);
+ info = req_ctx->backup_info;
+ END_CYCLE_COUNT(STAT_OP_TYPE_GENERIC, STAT_PHASE_4);
+
+
+ /*Set the inflight couter value to local variable*/
+ inflight_counter = ctx_p->drvdata->inflight_counter;
+ /*Decrease the inflight counter*/
+ if(ctx_p->flow_mode == BYPASS && ctx_p->drvdata->inflight_counter > 0)
+ ctx_p->drvdata->inflight_counter--;
+
+ if(areq){
+ ablkcipher_request_complete(areq, completion_error);
+ return 0;
+ }
+ return completion_error;
+}
+
+static int ssi_blkcipher_process(
+ struct crypto_tfm *tfm,
+ struct blkcipher_req_ctx *req_ctx,
+ struct scatterlist *dst, struct scatterlist *src,
+ unsigned int nbytes,
+ void *info, //req info
+ unsigned int ivsize,
+ void *areq,
+ enum drv_crypto_direction direction)
+{
+ struct ssi_ablkcipher_ctx *ctx_p = crypto_tfm_ctx(tfm);
+ struct device *dev = &ctx_p->drvdata->plat_dev->dev;
+ HwDesc_s desc[MAX_ABLKCIPHER_SEQ_LEN];
+ struct ssi_crypto_req ssi_req = {};
+ int rc, seq_len = 0,cts_restore_flag = 0;
+ DECL_CYCLE_COUNT_RESOURCES;
+
+ SSI_LOG_DEBUG("%s areq=%p info=%p nbytes=%d\n",
+ ((direction==DRV_CRYPTO_DIRECTION_ENCRYPT)?"Encrypt":"Decrypt"),
+ areq, info, nbytes);
+
+ CHECK_AND_RETURN_UPON_FIPS_ERROR();
+ /* STAT_PHASE_0: Init and sanity checks */
+ START_CYCLE_COUNT();
+
+ /* TODO: check data length according to mode */
+ if (unlikely(validate_data_size(ctx_p, nbytes))) {
+ SSI_LOG_ERR("Unsupported data size %d.\n", nbytes);
+ crypto_tfm_set_flags(tfm, CRYPTO_TFM_RES_BAD_BLOCK_LEN);
+ return -EINVAL;
+ }
+ if (nbytes == 0) {
+ /* No data to process is valid */
+ return 0;
+ }
+ /*For CTS in case of data size aligned to 16 use CBC mode*/
+ if (((nbytes % AES_BLOCK_SIZE) == 0) && (ctx_p->cipher_mode == DRV_CIPHER_CBC_CTS)){
+
+ ctx_p->cipher_mode = DRV_CIPHER_CBC;
+ cts_restore_flag = 1;
+ }
+
+ /* Setup DX request structure */
+ ssi_req.user_cb = (void *)ssi_ablkcipher_complete;
+ ssi_req.user_arg = (void *)areq;
+
+#ifdef ENABLE_CYCLE_COUNT
+ ssi_req.op_type = (direction == DRV_CRYPTO_DIRECTION_DECRYPT) ?
+ STAT_OP_TYPE_DECODE : STAT_OP_TYPE_ENCODE;
+
+#endif
+
+ /* Setup request context */
+ req_ctx->gen_ctx.op_type = direction;
+
+ END_CYCLE_COUNT(ssi_req.op_type, STAT_PHASE_0);
+
+ /* STAT_PHASE_1: Map buffers */
+ START_CYCLE_COUNT();
+
+ rc = ssi_buffer_mgr_map_blkcipher_request(ctx_p->drvdata, req_ctx, ivsize, nbytes, info, src, dst);
+ if (unlikely(rc != 0)) {
+ SSI_LOG_ERR("map_request() failed\n");
+ goto exit_process;
+ }
+
+ END_CYCLE_COUNT(ssi_req.op_type, STAT_PHASE_1);
+
+ /* STAT_PHASE_2: Create sequence */
+ START_CYCLE_COUNT();
+
+ /* Setup processing */
+#if SSI_CC_HAS_MULTI2
+ if (ctx_p->flow_mode == S_DIN_to_MULTI2) {
+ ssi_blkcipher_create_multi2_setup_desc(tfm,
+ req_ctx,
+ ivsize,
+ desc,
+ &seq_len);
+ } else
+#endif /*SSI_CC_HAS_MULTI2*/
+ {
+ ssi_blkcipher_create_setup_desc(tfm,
+ req_ctx,
+ ivsize,
+ nbytes,
+ desc,
+ &seq_len);
+ }
+ /* Data processing */
+ ssi_blkcipher_create_data_desc(tfm,
+ req_ctx,
+ dst, src,
+ nbytes,
+ areq,
+ desc, &seq_len);
+
+ /* do we need to generate IV? */
+ if (req_ctx->is_giv == true) {
+ ssi_req.ivgen_dma_addr[0] = req_ctx->gen_ctx.iv_dma_addr;
+ ssi_req.ivgen_dma_addr_len = 1;
+ /* set the IV size (8/16 B long)*/
+ ssi_req.ivgen_size = ivsize;
+ }
+ END_CYCLE_COUNT(ssi_req.op_type, STAT_PHASE_2);
+
+ /* STAT_PHASE_3: Lock HW and push sequence */
+ START_CYCLE_COUNT();
+
+ rc = send_request(ctx_p->drvdata, &ssi_req, desc, seq_len, (areq == NULL)? 0:1);
+ if(areq != NULL) {
+ if (unlikely(rc != -EINPROGRESS)) {
+ /* Failed to send the request or request completed synchronously */
+ ssi_buffer_mgr_unmap_blkcipher_request(dev, req_ctx, ivsize, src, dst);
+ }
+
+ END_CYCLE_COUNT(ssi_req.op_type, STAT_PHASE_3);
+ } else {
+ if (rc != 0) {
+ ssi_buffer_mgr_unmap_blkcipher_request(dev, req_ctx, ivsize, src, dst);
+ END_CYCLE_COUNT(ssi_req.op_type, STAT_PHASE_3);
+ } else {
+ END_CYCLE_COUNT(ssi_req.op_type, STAT_PHASE_3);
+ rc = ssi_blkcipher_complete(dev, ctx_p, req_ctx, dst, src, info, ivsize, NULL, ctx_p->drvdata->cc_base);
+ }
+ }
+
+exit_process:
+ if (cts_restore_flag != 0)
+ ctx_p->cipher_mode = DRV_CIPHER_CBC_CTS;
+
+ return rc;
+}
+
+static void ssi_ablkcipher_complete(struct device *dev, void *ssi_req, void __iomem *cc_base)
+{
+ struct ablkcipher_request *areq = (struct ablkcipher_request *)ssi_req;
+ struct blkcipher_req_ctx *req_ctx = ablkcipher_request_ctx(areq);
+ struct crypto_ablkcipher *tfm = crypto_ablkcipher_reqtfm(areq);
+ struct ssi_ablkcipher_ctx *ctx_p = crypto_ablkcipher_ctx(tfm);
+ unsigned int ivsize = crypto_ablkcipher_ivsize(tfm);
+
+ CHECK_AND_RETURN_VOID_UPON_FIPS_ERROR();
+
+ ssi_blkcipher_complete(dev, ctx_p, req_ctx, areq->dst, areq->src, areq->info, ivsize, areq, cc_base);
+}
+
+
+
+static int ssi_sblkcipher_init(struct crypto_tfm *tfm)
+{
+ struct ssi_ablkcipher_ctx *ctx_p = crypto_tfm_ctx(tfm);
+
+ /* Allocate sync ctx buffer */
+ ctx_p->sync_ctx = kmalloc(sizeof(struct blkcipher_req_ctx), GFP_KERNEL|GFP_DMA);
+ if (!ctx_p->sync_ctx) {
+ SSI_LOG_ERR("Allocating sync ctx buffer in context failed\n");
+ return -ENOMEM;
+ }
+ SSI_LOG_DEBUG("Allocated sync ctx buffer in context ctx_p->sync_ctx=@%p\n",
+ ctx_p->sync_ctx);
+
+ return ssi_blkcipher_init(tfm);
+}
+
+
+static void ssi_sblkcipher_exit(struct crypto_tfm *tfm)
+{
+ struct ssi_ablkcipher_ctx *ctx_p = crypto_tfm_ctx(tfm);
+
+ kfree(ctx_p->sync_ctx);
+ SSI_LOG_DEBUG("Free sync ctx buffer in context ctx_p->sync_ctx=@%p\n", ctx_p->sync_ctx);
+
+ ssi_blkcipher_exit(tfm);
+}
+
+#ifdef SYNC_ALGS
+static int ssi_sblkcipher_encrypt(struct blkcipher_desc *desc,
+ struct scatterlist *dst, struct scatterlist *src,
+ unsigned int nbytes)
+{
+ struct crypto_blkcipher *blk_tfm = desc->tfm;
+ struct crypto_tfm *tfm = crypto_blkcipher_tfm(blk_tfm);
+ struct ssi_ablkcipher_ctx *ctx_p = crypto_tfm_ctx(tfm);
+ struct blkcipher_req_ctx *req_ctx = ctx_p->sync_ctx;
+ unsigned int ivsize = crypto_blkcipher_ivsize(blk_tfm);
+
+ req_ctx->backup_info = desc->info;
+ req_ctx->is_giv = false;
+
+ return ssi_blkcipher_process(tfm, req_ctx, dst, src, nbytes, desc->info, ivsize, NULL, DRV_CRYPTO_DIRECTION_ENCRYPT);
+}
+
+static int ssi_sblkcipher_decrypt(struct blkcipher_desc *desc,
+ struct scatterlist *dst, struct scatterlist *src,
+ unsigned int nbytes)
+{
+ struct crypto_blkcipher *blk_tfm = desc->tfm;
+ struct crypto_tfm *tfm = crypto_blkcipher_tfm(blk_tfm);
+ struct ssi_ablkcipher_ctx *ctx_p = crypto_tfm_ctx(tfm);
+ struct blkcipher_req_ctx *req_ctx = ctx_p->sync_ctx;
+ unsigned int ivsize = crypto_blkcipher_ivsize(blk_tfm);
+
+ req_ctx->backup_info = desc->info;
+ req_ctx->is_giv = false;
+
+ return ssi_blkcipher_process(tfm, req_ctx, dst, src, nbytes, desc->info, ivsize, NULL, DRV_CRYPTO_DIRECTION_DECRYPT);
+}
+#endif
+
+/* Async wrap functions */
+
+static int ssi_ablkcipher_init(struct crypto_tfm *tfm)
+{
+ struct ablkcipher_tfm *ablktfm = &tfm->crt_ablkcipher;
+
+ ablktfm->reqsize = sizeof(struct blkcipher_req_ctx);
+
+ return ssi_blkcipher_init(tfm);
+}
+
+
+static int ssi_ablkcipher_setkey(struct crypto_ablkcipher *tfm,
+ const u8 *key,
+ unsigned int keylen)
+{
+ return ssi_blkcipher_setkey(crypto_ablkcipher_tfm(tfm), key, keylen);
+}
+
+static int ssi_ablkcipher_encrypt(struct ablkcipher_request *req)
+{
+ struct crypto_ablkcipher *ablk_tfm = crypto_ablkcipher_reqtfm(req);
+ struct crypto_tfm *tfm = crypto_ablkcipher_tfm(ablk_tfm);
+ struct blkcipher_req_ctx *req_ctx = ablkcipher_request_ctx(req);
+ unsigned int ivsize = crypto_ablkcipher_ivsize(ablk_tfm);
+
+ req_ctx->backup_info = req->info;
+ req_ctx->is_giv = false;
+
+ return ssi_blkcipher_process(tfm, req_ctx, req->dst, req->src, req->nbytes, req->info, ivsize, (void *)req, DRV_CRYPTO_DIRECTION_ENCRYPT);
+}
+
+static int ssi_ablkcipher_decrypt(struct ablkcipher_request *req)
+{
+ struct crypto_ablkcipher *ablk_tfm = crypto_ablkcipher_reqtfm(req);
+ struct crypto_tfm *tfm = crypto_ablkcipher_tfm(ablk_tfm);
+ struct blkcipher_req_ctx *req_ctx = ablkcipher_request_ctx(req);
+ unsigned int ivsize = crypto_ablkcipher_ivsize(ablk_tfm);
+
+ req_ctx->backup_info = req->info;
+ req_ctx->is_giv = false;
+ return ssi_blkcipher_process(tfm, req_ctx, req->dst, req->src, req->nbytes, req->info, ivsize, (void *)req, DRV_CRYPTO_DIRECTION_DECRYPT);
+}
+
+
+/* DX Block cipher alg */
+static struct ssi_alg_template blkcipher_algs[] = {
+/* Async template */
+#if SSI_CC_HAS_AES_XTS
+ {
+ .name = "xts(aes)",
+ .driver_name = "xts-aes-dx",
+ .blocksize = AES_BLOCK_SIZE,
+ .type = CRYPTO_ALG_TYPE_ABLKCIPHER,
+ .template_ablkcipher = {
+ .setkey = ssi_ablkcipher_setkey,
+ .encrypt = ssi_ablkcipher_encrypt,
+ .decrypt = ssi_ablkcipher_decrypt,
+ .min_keysize = AES_MIN_KEY_SIZE * 2,
+ .max_keysize = AES_MAX_KEY_SIZE * 2,
+ .ivsize = AES_BLOCK_SIZE,
+ .geniv = "eseqiv",
+ },
+ .cipher_mode = DRV_CIPHER_XTS,
+ .flow_mode = S_DIN_to_AES,
+ .synchronous = false,
+ },
+ {
+ .name = "xts(aes)",
+ .driver_name = "xts-aes-du512-dx",
+ .blocksize = AES_BLOCK_SIZE,
+ .type = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_BULK_DU_512,
+ .template_ablkcipher = {
+ .setkey = ssi_ablkcipher_setkey,
+ .encrypt = ssi_ablkcipher_encrypt,
+ .decrypt = ssi_ablkcipher_decrypt,
+ .min_keysize = AES_MIN_KEY_SIZE * 2,
+ .max_keysize = AES_MAX_KEY_SIZE * 2,
+ .ivsize = AES_BLOCK_SIZE,
+ },
+ .cipher_mode = DRV_CIPHER_XTS,
+ .flow_mode = S_DIN_to_AES,
+ .synchronous = false,
+ },
+ {
+ .name = "xts(aes)",
+ .driver_name = "xts-aes-du4096-dx",
+ .blocksize = AES_BLOCK_SIZE,
+ .type = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_BULK_DU_4096,
+ .template_ablkcipher = {
+ .setkey = ssi_ablkcipher_setkey,
+ .encrypt = ssi_ablkcipher_encrypt,
+ .decrypt = ssi_ablkcipher_decrypt,
+ .min_keysize = AES_MIN_KEY_SIZE * 2,
+ .max_keysize = AES_MAX_KEY_SIZE * 2,
+ .ivsize = AES_BLOCK_SIZE,
+ },
+ .cipher_mode = DRV_CIPHER_XTS,
+ .flow_mode = S_DIN_to_AES,
+ .synchronous = false,
+ },
+#endif /*SSI_CC_HAS_AES_XTS*/
+#if SSI_CC_HAS_AES_ESSIV
+ {
+ .name = "essiv(aes)",
+ .driver_name = "essiv-aes-dx",
+ .blocksize = AES_BLOCK_SIZE,
+ .type = CRYPTO_ALG_TYPE_ABLKCIPHER,
+ .template_ablkcipher = {
+ .setkey = ssi_ablkcipher_setkey,
+ .encrypt = ssi_ablkcipher_encrypt,
+ .decrypt = ssi_ablkcipher_decrypt,
+ .min_keysize = AES_MIN_KEY_SIZE * 2,
+ .max_keysize = AES_MAX_KEY_SIZE * 2,
+ .ivsize = AES_BLOCK_SIZE,
+ },
+ .cipher_mode = DRV_CIPHER_ESSIV,
+ .flow_mode = S_DIN_to_AES,
+ .synchronous = false,
+ },
+ {
+ .name = "essiv(aes)",
+ .driver_name = "essiv-aes-du512-dx",
+ .blocksize = AES_BLOCK_SIZE,
+ .type = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_BULK_DU_512,
+ .template_ablkcipher = {
+ .setkey = ssi_ablkcipher_setkey,
+ .encrypt = ssi_ablkcipher_encrypt,
+ .decrypt = ssi_ablkcipher_decrypt,
+ .min_keysize = AES_MIN_KEY_SIZE * 2,
+ .max_keysize = AES_MAX_KEY_SIZE * 2,
+ .ivsize = AES_BLOCK_SIZE,
+ },
+ .cipher_mode = DRV_CIPHER_ESSIV,
+ .flow_mode = S_DIN_to_AES,
+ .synchronous = false,
+ },
+ {
+ .name = "essiv(aes)",
+ .driver_name = "essiv-aes-du4096-dx",
+ .blocksize = AES_BLOCK_SIZE,
+ .type = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_BULK_DU_4096,
+ .template_ablkcipher = {
+ .setkey = ssi_ablkcipher_setkey,
+ .encrypt = ssi_ablkcipher_encrypt,
+ .decrypt = ssi_ablkcipher_decrypt,
+ .min_keysize = AES_MIN_KEY_SIZE * 2,
+ .max_keysize = AES_MAX_KEY_SIZE * 2,
+ .ivsize = AES_BLOCK_SIZE,
+ },
+ .cipher_mode = DRV_CIPHER_ESSIV,
+ .flow_mode = S_DIN_to_AES,
+ .synchronous = false,
+ },
+#endif /*SSI_CC_HAS_AES_ESSIV*/
+#if SSI_CC_HAS_AES_BITLOCKER
+ {
+ .name = "bitlocker(aes)",
+ .driver_name = "bitlocker-aes-dx",
+ .blocksize = AES_BLOCK_SIZE,
+ .type = CRYPTO_ALG_TYPE_ABLKCIPHER,
+ .template_ablkcipher = {
+ .setkey = ssi_ablkcipher_setkey,
+ .encrypt = ssi_ablkcipher_encrypt,
+ .decrypt = ssi_ablkcipher_decrypt,
+ .min_keysize = AES_MIN_KEY_SIZE * 2,
+ .max_keysize = AES_MAX_KEY_SIZE * 2,
+ .ivsize = AES_BLOCK_SIZE,
+ },
+ .cipher_mode = DRV_CIPHER_BITLOCKER,
+ .flow_mode = S_DIN_to_AES,
+ .synchronous = false,
+ },
+ {
+ .name = "bitlocker(aes)",
+ .driver_name = "bitlocker-aes-du512-dx",
+ .blocksize = AES_BLOCK_SIZE,
+ .type = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_BULK_DU_512,
+ .template_ablkcipher = {
+ .setkey = ssi_ablkcipher_setkey,
+ .encrypt = ssi_ablkcipher_encrypt,
+ .decrypt = ssi_ablkcipher_decrypt,
+ .min_keysize = AES_MIN_KEY_SIZE * 2,
+ .max_keysize = AES_MAX_KEY_SIZE * 2,
+ .ivsize = AES_BLOCK_SIZE,
+ },
+ .cipher_mode = DRV_CIPHER_BITLOCKER,
+ .flow_mode = S_DIN_to_AES,
+ .synchronous = false,
+ },
+ {
+ .name = "bitlocker(aes)",
+ .driver_name = "bitlocker-aes-du4096-dx",
+ .blocksize = AES_BLOCK_SIZE,
+ .type = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_BULK_DU_4096,
+ .template_ablkcipher = {
+ .setkey = ssi_ablkcipher_setkey,
+ .encrypt = ssi_ablkcipher_encrypt,
+ .decrypt = ssi_ablkcipher_decrypt,
+ .min_keysize = AES_MIN_KEY_SIZE * 2,
+ .max_keysize = AES_MAX_KEY_SIZE * 2,
+ .ivsize = AES_BLOCK_SIZE,
+ },
+ .cipher_mode = DRV_CIPHER_BITLOCKER,
+ .flow_mode = S_DIN_to_AES,
+ .synchronous = false,
+ },
+#endif /*SSI_CC_HAS_AES_BITLOCKER*/
+ {
+ .name = "ecb(aes)",
+ .driver_name = "ecb-aes-dx",
+ .blocksize = AES_BLOCK_SIZE,
+ .type = CRYPTO_ALG_TYPE_ABLKCIPHER,
+ .template_ablkcipher = {
+ .setkey = ssi_ablkcipher_setkey,
+ .encrypt = ssi_ablkcipher_encrypt,
+ .decrypt = ssi_ablkcipher_decrypt,
+ .min_keysize = AES_MIN_KEY_SIZE,
+ .max_keysize = AES_MAX_KEY_SIZE,
+ .ivsize = 0,
+ },
+ .cipher_mode = DRV_CIPHER_ECB,
+ .flow_mode = S_DIN_to_AES,
+ .synchronous = false,
+ },
+ {
+ .name = "cbc(aes)",
+ .driver_name = "cbc-aes-dx",
+ .blocksize = AES_BLOCK_SIZE,
+ .type = CRYPTO_ALG_TYPE_ABLKCIPHER,
+ .template_ablkcipher = {
+ .setkey = ssi_ablkcipher_setkey,
+ .encrypt = ssi_ablkcipher_encrypt,
+ .decrypt = ssi_ablkcipher_decrypt,
+ .min_keysize = AES_MIN_KEY_SIZE,
+ .max_keysize = AES_MAX_KEY_SIZE,
+ .ivsize = AES_BLOCK_SIZE,
+ },
+ .cipher_mode = DRV_CIPHER_CBC,
+ .flow_mode = S_DIN_to_AES,
+ .synchronous = false,
+ },
+ {
+ .name = "ofb(aes)",
+ .driver_name = "ofb-aes-dx",
+ .blocksize = AES_BLOCK_SIZE,
+ .type = CRYPTO_ALG_TYPE_ABLKCIPHER,
+ .template_ablkcipher = {
+ .setkey = ssi_ablkcipher_setkey,
+ .encrypt = ssi_ablkcipher_encrypt,
+ .decrypt = ssi_ablkcipher_decrypt,
+ .min_keysize = AES_MIN_KEY_SIZE,
+ .max_keysize = AES_MAX_KEY_SIZE,
+ .ivsize = AES_BLOCK_SIZE,
+ },
+ .cipher_mode = DRV_CIPHER_OFB,
+ .flow_mode = S_DIN_to_AES,
+ .synchronous = false,
+ },
+#if SSI_CC_HAS_AES_CTS
+ {
+ .name = "cts1(cbc(aes))",
+ .driver_name = "cts1-cbc-aes-dx",
+ .blocksize = AES_BLOCK_SIZE,
+ .type = CRYPTO_ALG_TYPE_ABLKCIPHER,
+ .template_ablkcipher = {
+ .setkey = ssi_ablkcipher_setkey,
+ .encrypt = ssi_ablkcipher_encrypt,
+ .decrypt = ssi_ablkcipher_decrypt,
+ .min_keysize = AES_MIN_KEY_SIZE,
+ .max_keysize = AES_MAX_KEY_SIZE,
+ .ivsize = AES_BLOCK_SIZE,
+ },
+ .cipher_mode = DRV_CIPHER_CBC_CTS,
+ .flow_mode = S_DIN_to_AES,
+ .synchronous = false,
+ },
+#endif
+ {
+ .name = "ctr(aes)",
+ .driver_name = "ctr-aes-dx",
+ .blocksize = 1,
+ .type = CRYPTO_ALG_TYPE_ABLKCIPHER,
+ .template_ablkcipher = {
+ .setkey = ssi_ablkcipher_setkey,
+ .encrypt = ssi_ablkcipher_encrypt,
+ .decrypt = ssi_ablkcipher_decrypt,
+ .min_keysize = AES_MIN_KEY_SIZE,
+ .max_keysize = AES_MAX_KEY_SIZE,
+ .ivsize = AES_BLOCK_SIZE,
+ },
+ .cipher_mode = DRV_CIPHER_CTR,
+ .flow_mode = S_DIN_to_AES,
+ .synchronous = false,
+ },
+ {
+ .name = "cbc(des3_ede)",
+ .driver_name = "cbc-3des-dx",
+ .blocksize = DES3_EDE_BLOCK_SIZE,
+ .type = CRYPTO_ALG_TYPE_ABLKCIPHER,
+ .template_ablkcipher = {
+ .setkey = ssi_ablkcipher_setkey,
+ .encrypt = ssi_ablkcipher_encrypt,
+ .decrypt = ssi_ablkcipher_decrypt,
+ .min_keysize = DES3_EDE_KEY_SIZE,
+ .max_keysize = DES3_EDE_KEY_SIZE,
+ .ivsize = DES3_EDE_BLOCK_SIZE,
+ },
+ .cipher_mode = DRV_CIPHER_CBC,
+ .flow_mode = S_DIN_to_DES,
+ .synchronous = false,
+ },
+ {
+ .name = "ecb(des3_ede)",
+ .driver_name = "ecb-3des-dx",
+ .blocksize = DES3_EDE_BLOCK_SIZE,
+ .type = CRYPTO_ALG_TYPE_ABLKCIPHER,
+ .template_ablkcipher = {
+ .setkey = ssi_ablkcipher_setkey,
+ .encrypt = ssi_ablkcipher_encrypt,
+ .decrypt = ssi_ablkcipher_decrypt,
+ .min_keysize = DES3_EDE_KEY_SIZE,
+ .max_keysize = DES3_EDE_KEY_SIZE,
+ .ivsize = 0,
+ },
+ .cipher_mode = DRV_CIPHER_ECB,
+ .flow_mode = S_DIN_to_DES,
+ .synchronous = false,
+ },
+ {
+ .name = "cbc(des)",
+ .driver_name = "cbc-des-dx",
+ .blocksize = DES_BLOCK_SIZE,
+ .type = CRYPTO_ALG_TYPE_ABLKCIPHER,
+ .template_ablkcipher = {
+ .setkey = ssi_ablkcipher_setkey,
+ .encrypt = ssi_ablkcipher_encrypt,
+ .decrypt = ssi_ablkcipher_decrypt,
+ .min_keysize = DES_KEY_SIZE,
+ .max_keysize = DES_KEY_SIZE,
+ .ivsize = DES_BLOCK_SIZE,
+ },
+ .cipher_mode = DRV_CIPHER_CBC,
+ .flow_mode = S_DIN_to_DES,
+ .synchronous = false,
+ },
+ {
+ .name = "ecb(des)",
+ .driver_name = "ecb-des-dx",
+ .blocksize = DES_BLOCK_SIZE,
+ .type = CRYPTO_ALG_TYPE_ABLKCIPHER,
+ .template_ablkcipher = {
+ .setkey = ssi_ablkcipher_setkey,
+ .encrypt = ssi_ablkcipher_encrypt,
+ .decrypt = ssi_ablkcipher_decrypt,
+ .min_keysize = DES_KEY_SIZE,
+ .max_keysize = DES_KEY_SIZE,
+ .ivsize = 0,
+ },
+ .cipher_mode = DRV_CIPHER_ECB,
+ .flow_mode = S_DIN_to_DES,
+ .synchronous = false,
+ },
+#if SSI_CC_HAS_MULTI2
+ {
+ .name = "cbc(multi2)",
+ .driver_name = "cbc-multi2-dx",
+ .blocksize = CC_MULTI2_BLOCK_SIZE,
+ .type = CRYPTO_ALG_TYPE_ABLKCIPHER,
+ .template_ablkcipher = {
+ .setkey = ssi_ablkcipher_setkey,
+ .encrypt = ssi_ablkcipher_encrypt,
+ .decrypt = ssi_ablkcipher_decrypt,
+ .min_keysize = CC_MULTI2_SYSTEM_N_DATA_KEY_SIZE + 1,
+ .max_keysize = CC_MULTI2_SYSTEM_N_DATA_KEY_SIZE + 1,
+ .ivsize = CC_MULTI2_IV_SIZE,
+ },
+ .cipher_mode = DRV_MULTI2_CBC,
+ .flow_mode = S_DIN_to_MULTI2,
+ .synchronous = false,
+ },
+ {
+ .name = "ofb(multi2)",
+ .driver_name = "ofb-multi2-dx",
+ .blocksize = 1,
+ .type = CRYPTO_ALG_TYPE_ABLKCIPHER,
+ .template_ablkcipher = {
+ .setkey = ssi_ablkcipher_setkey,
+ .encrypt = ssi_ablkcipher_encrypt,
+ .decrypt = ssi_ablkcipher_encrypt,
+ .min_keysize = CC_MULTI2_SYSTEM_N_DATA_KEY_SIZE + 1,
+ .max_keysize = CC_MULTI2_SYSTEM_N_DATA_KEY_SIZE + 1,
+ .ivsize = CC_MULTI2_IV_SIZE,
+ },
+ .cipher_mode = DRV_MULTI2_OFB,
+ .flow_mode = S_DIN_to_MULTI2,
+ .synchronous = false,
+ },
+#endif /*SSI_CC_HAS_MULTI2*/
+};
+
+static
+struct ssi_crypto_alg *ssi_ablkcipher_create_alg(struct ssi_alg_template *template)
+{
+ struct ssi_crypto_alg *t_alg;
+ struct crypto_alg *alg;
+
+ t_alg = kzalloc(sizeof(struct ssi_crypto_alg), GFP_KERNEL);
+ if (!t_alg) {
+ SSI_LOG_ERR("failed to allocate t_alg\n");
+ return ERR_PTR(-ENOMEM);
+ }
+
+ alg = &t_alg->crypto_alg;
+
+ snprintf(alg->cra_name, CRYPTO_MAX_ALG_NAME, "%s", template->name);
+ snprintf(alg->cra_driver_name, CRYPTO_MAX_ALG_NAME, "%s",
+ template->driver_name);
+ alg->cra_module = THIS_MODULE;
+ alg->cra_priority = SSI_CRA_PRIO;
+ alg->cra_blocksize = template->blocksize;
+ alg->cra_alignmask = 0;
+ alg->cra_ctxsize = sizeof(struct ssi_ablkcipher_ctx);
+
+ alg->cra_init = template->synchronous? ssi_sblkcipher_init:ssi_ablkcipher_init;
+ alg->cra_exit = template->synchronous? ssi_sblkcipher_exit:ssi_blkcipher_exit;
+ alg->cra_type = template->synchronous? &crypto_blkcipher_type:&crypto_ablkcipher_type;
+ if(template->synchronous) {
+ alg->cra_blkcipher = template->template_sblkcipher;
+ alg->cra_flags = CRYPTO_ALG_KERN_DRIVER_ONLY |
+ template->type;
+ } else {
+ alg->cra_ablkcipher = template->template_ablkcipher;
+ alg->cra_flags = CRYPTO_ALG_ASYNC | CRYPTO_ALG_KERN_DRIVER_ONLY |
+ template->type;
+ }
+
+ t_alg->cipher_mode = template->cipher_mode;
+ t_alg->flow_mode = template->flow_mode;
+
+ return t_alg;
+}
+
+int ssi_ablkcipher_free(struct ssi_drvdata *drvdata)
+{
+ struct ssi_crypto_alg *t_alg, *n;
+ struct ssi_blkcipher_handle *blkcipher_handle =
+ drvdata->blkcipher_handle;
+ struct device *dev;
+ dev = &drvdata->plat_dev->dev;
+
+ if (blkcipher_handle != NULL) {
+ /* Remove registered algs */
+ list_for_each_entry_safe(t_alg, n,
+ &blkcipher_handle->blkcipher_alg_list,
+ entry) {
+ crypto_unregister_alg(&t_alg->crypto_alg);
+ list_del(&t_alg->entry);
+ kfree(t_alg);
+ }
+ kfree(blkcipher_handle);
+ drvdata->blkcipher_handle = NULL;
+ }
+ return 0;
+}
+
+
+
+int ssi_ablkcipher_alloc(struct ssi_drvdata *drvdata)
+{
+ struct ssi_blkcipher_handle *ablkcipher_handle;
+ struct ssi_crypto_alg *t_alg;
+ int rc = -ENOMEM;
+ int alg;
+
+ ablkcipher_handle = kmalloc(sizeof(struct ssi_blkcipher_handle),
+ GFP_KERNEL);
+ if (ablkcipher_handle == NULL)
+ return -ENOMEM;
+
+ drvdata->blkcipher_handle = ablkcipher_handle;
+
+ INIT_LIST_HEAD(&ablkcipher_handle->blkcipher_alg_list);
+
+ /* Linux crypto */
+ SSI_LOG_DEBUG("Number of algorithms = %zu\n", ARRAY_SIZE(blkcipher_algs));
+ for (alg = 0; alg < ARRAY_SIZE(blkcipher_algs); alg++) {
+ SSI_LOG_DEBUG("creating %s\n", blkcipher_algs[alg].driver_name);
+ t_alg = ssi_ablkcipher_create_alg(&blkcipher_algs[alg]);
+ if (IS_ERR(t_alg)) {
+ rc = PTR_ERR(t_alg);
+ SSI_LOG_ERR("%s alg allocation failed\n",
+ blkcipher_algs[alg].driver_name);
+ goto fail0;
+ }
+ t_alg->drvdata = drvdata;
+
+ SSI_LOG_DEBUG("registering %s\n", blkcipher_algs[alg].driver_name);
+ rc = crypto_register_alg(&t_alg->crypto_alg);
+ SSI_LOG_DEBUG("%s alg registration rc = %x\n",
+ t_alg->crypto_alg.cra_driver_name, rc);
+ if (unlikely(rc != 0)) {
+ SSI_LOG_ERR("%s alg registration failed\n",
+ t_alg->crypto_alg.cra_driver_name);
+ kfree(t_alg);
+ goto fail0;
+ } else {
+ list_add_tail(&t_alg->entry,
+ &ablkcipher_handle->blkcipher_alg_list);
+ SSI_LOG_DEBUG("Registered %s\n",
+ t_alg->crypto_alg.cra_driver_name);
+ }
+ }
+ return 0;
+
+fail0:
+ ssi_ablkcipher_free(drvdata);
+ return rc;
+}
diff --git a/drivers/staging/ccree/ssi_cipher.h b/drivers/staging/ccree/ssi_cipher.h
new file mode 100644
index 0000000..ba4eb7c
--- /dev/null
+++ b/drivers/staging/ccree/ssi_cipher.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2012-2017 ARM Limited or its affiliates.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* \file ssi_cipher.h
+ ARM CryptoCell Cipher Crypto API
+ */
+
+#ifndef __SSI_CIPHER_H__
+#define __SSI_CIPHER_H__
+
+#include <linux/kernel.h>
+#include <crypto/algapi.h>
+#include "ssi_driver.h"
+#include "ssi_buffer_mgr.h"
+
+
+/* Crypto cipher flags */
+#define CC_CRYPTO_CIPHER_KEY_KFDE0 (1 << 0)
+#define CC_CRYPTO_CIPHER_KEY_KFDE1 (1 << 1)
+#define CC_CRYPTO_CIPHER_KEY_KFDE2 (1 << 2)
+#define CC_CRYPTO_CIPHER_KEY_KFDE3 (1 << 3)
+#define CC_CRYPTO_CIPHER_DU_SIZE_512B (1 << 4)
+
+#define CC_CRYPTO_CIPHER_KEY_KFDE_MASK (CC_CRYPTO_CIPHER_KEY_KFDE0 | CC_CRYPTO_CIPHER_KEY_KFDE1 | CC_CRYPTO_CIPHER_KEY_KFDE2 | CC_CRYPTO_CIPHER_KEY_KFDE3)
+
+
+struct blkcipher_req_ctx {
+ struct async_gen_req_ctx gen_ctx;
+ enum ssi_req_dma_buf_type dma_buf_type;
+ uint32_t in_nents;
+ uint32_t in_mlli_nents;
+ uint32_t out_nents;
+ uint32_t out_mlli_nents;
+ uint8_t *backup_info; /*store iv for generated IV flow*/
+ bool is_giv;
+ struct mlli_params mlli_params;
+};
+
+
+
+int ssi_ablkcipher_alloc(struct ssi_drvdata *drvdata);
+
+int ssi_ablkcipher_free(struct ssi_drvdata *drvdata);
+
+#ifndef CRYPTO_ALG_BULK_MASK
+
+#define CRYPTO_ALG_BULK_DU_512 0x00002000
+#define CRYPTO_ALG_BULK_DU_4096 0x00004000
+#define CRYPTO_ALG_BULK_MASK (CRYPTO_ALG_BULK_DU_512 |\
+ CRYPTO_ALG_BULK_DU_4096)
+#endif /* CRYPTO_ALG_BULK_MASK */
+
+
+#ifdef CRYPTO_TFM_REQ_HW_KEY
+
+static inline bool ssi_is_hw_key(struct crypto_tfm *tfm)
+{
+ return (crypto_tfm_get_flags(tfm) & CRYPTO_TFM_REQ_HW_KEY);
+}
+
+#else
+
+struct arm_hw_key_info {
+ int hw_key1;
+ int hw_key2;
+};
+
+static inline bool ssi_is_hw_key(struct crypto_tfm *tfm)
+{
+ return 0;
+}
+
+#endif /* CRYPTO_TFM_REQ_HW_KEY */
+
+
+#endif /*__SSI_CIPHER_H__*/
diff --git a/drivers/staging/ccree/ssi_config.h b/drivers/staging/ccree/ssi_config.h
new file mode 100644
index 0000000..d96a543
--- /dev/null
+++ b/drivers/staging/ccree/ssi_config.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2012-2017 ARM Limited or its affiliates.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* \file ssi_config.h
+ Definitions for ARM CryptoCell Linux Crypto Driver
+ */
+
+#ifndef __SSI_CONFIG_H__
+#define __SSI_CONFIG_H__
+
+#include <linux/version.h>
+
+#define DISABLE_COHERENT_DMA_OPS
+//#define FLUSH_CACHE_ALL
+//#define COMPLETION_DELAY
+//#define DX_DUMP_DESCS
+// #define DX_DUMP_BYTES
+// #define CC_DEBUG
+#define ENABLE_CC_SYSFS /* Enable sysfs interface for debugging REE driver */
+//#define ENABLE_CC_CYCLE_COUNT
+//#define DX_IRQ_DELAY 100000
+#define DMA_BIT_MASK_LEN 48 /* was 32 bit, but for juno's sake it was enlarged to 48 bit */
+
+#if defined ENABLE_CC_CYCLE_COUNT && defined ENABLE_CC_SYSFS
+#define CC_CYCLE_COUNT
+#endif
+
+
+#if defined (CONFIG_ARM64) // TODO currently only this mode was test on Juno (which is ARM64), need to enable coherent also.
+#define DISABLE_COHERENT_DMA_OPS
+#endif
+
+/* Define the CryptoCell DMA cache coherency signals configuration */
+#if defined (DISABLE_COHERENT_DMA_OPS)
+ /* Software Controlled Cache Coherency (SCCC) */
+ #define SSI_CACHE_PARAMS (0x000)
+ /* CC attached to NONE-ACP such as HPP/ACE/AMBA4.
+ * The customer is responsible to enable/disable this feature
+ * according to his platform type. */
+ #define DX_HAS_ACP 0
+#else
+ #define SSI_CACHE_PARAMS (0xEEE)
+ /* CC attached to ACP */
+ #define DX_HAS_ACP 1
+#endif
+
+#endif /*__DX_CONFIG_H__*/
+
diff --git a/drivers/staging/ccree/ssi_driver.c b/drivers/staging/ccree/ssi_driver.c
new file mode 100644
index 0000000..bc19adc
--- /dev/null
+++ b/drivers/staging/ccree/ssi_driver.c
@@ -0,0 +1,556 @@
+/*
+ * Copyright (C) 2012-2017 ARM Limited or its affiliates.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+#include <linux/crypto.h>
+#include <crypto/algapi.h>
+#include <crypto/aes.h>
+#include <crypto/sha.h>
+#include <crypto/aead.h>
+#include <crypto/authenc.h>
+#include <crypto/scatterwalk.h>
+#include <crypto/internal/skcipher.h>
+
+#include <linux/init.h>
+#include <linux/moduleparam.h>
+#include <linux/types.h>
+#include <linux/random.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/fcntl.h>
+#include <linux/poll.h>
+#include <linux/proc_fs.h>
+#include <linux/mutex.h>
+#include <linux/sysctl.h>
+#include <linux/fs.h>
+#include <linux/cdev.h>
+#include <linux/platform_device.h>
+#include <linux/mm.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmapool.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/pm.h>
+
+/* cache.h required for L1_CACHE_ALIGN() and cache_line_size() */
+#include <linux/cache.h>
+#include <linux/io.h>
+#include <linux/uaccess.h>
+#include <linux/pagemap.h>
+#include <linux/sched.h>
+#include <linux/random.h>
+#include <linux/of.h>
+
+#include "ssi_config.h"
+#include "ssi_driver.h"
+#include "ssi_request_mgr.h"
+#include "ssi_buffer_mgr.h"
+#include "ssi_sysfs.h"
+#include "ssi_cipher.h"
+#include "ssi_aead.h"
+#include "ssi_hash.h"
+#include "ssi_ivgen.h"
+#include "ssi_sram_mgr.h"
+#include "ssi_pm.h"
+#include "ssi_fips_local.h"
+
+
+#ifdef DX_DUMP_BYTES
+void dump_byte_array(const char *name, const uint8_t *the_array, unsigned long size)
+{
+ int i , line_offset = 0, ret = 0;
+ const uint8_t *cur_byte;
+ char line_buf[80];
+
+ if (the_array == NULL) {
+ SSI_LOG_ERR("cannot dump_byte_array - NULL pointer\n");
+ return;
+ }
+
+ ret = snprintf(line_buf, sizeof(line_buf), "%s[%lu]: ",
+ name, size);
+ if (ret < 0) {
+ SSI_LOG_ERR("snprintf returned %d . aborting buffer array dump\n",ret);
+ return;
+ }
+ line_offset = ret;
+ for (i = 0 , cur_byte = the_array;
+ (i < size) && (line_offset < sizeof(line_buf)); i++, cur_byte++) {
+ ret = snprintf(line_buf + line_offset,
+ sizeof(line_buf) - line_offset,
+ "0x%02X ", *cur_byte);
+ if (ret < 0) {
+ SSI_LOG_ERR("snprintf returned %d . aborting buffer array dump\n",ret);
+ return;
+ }
+ line_offset += ret;
+ if (line_offset > 75) { /* Cut before line end */
+ SSI_LOG_DEBUG("%s\n", line_buf);
+ line_offset = 0;
+ }
+ }
+
+ if (line_offset > 0) /* Dump remaining line */
+ SSI_LOG_DEBUG("%s\n", line_buf);
+}
+#endif
+
+static irqreturn_t cc_isr(int irq, void *dev_id)
+{
+ struct ssi_drvdata *drvdata = (struct ssi_drvdata *)dev_id;
+ void __iomem *cc_base = drvdata->cc_base;
+ uint32_t irr;
+ uint32_t imr;
+ DECL_CYCLE_COUNT_RESOURCES;
+
+ /* STAT_OP_TYPE_GENERIC STAT_PHASE_0: Interrupt */
+ START_CYCLE_COUNT();
+
+ /* read the interrupt status */
+ irr = CC_HAL_READ_REGISTER(CC_REG_OFFSET(HOST_RGF, HOST_IRR));
+ SSI_LOG_DEBUG("Got IRR=0x%08X\n", irr);
+ if (unlikely(irr == 0)) { /* Probably shared interrupt line */
+ SSI_LOG_ERR("Got interrupt with empty IRR\n");
+ return IRQ_NONE;
+ }
+ imr = CC_HAL_READ_REGISTER(CC_REG_OFFSET(HOST_RGF, HOST_IMR));
+
+ /* clear interrupt - must be before processing events */
+ CC_HAL_WRITE_REGISTER(CC_REG_OFFSET(HOST_RGF, HOST_ICR), irr);
+
+ drvdata->irq = irr;
+ /* Completion interrupt - most probable */
+ if (likely((irr & SSI_COMP_IRQ_MASK) != 0)) {
+ /* Mask AXI completion interrupt - will be unmasked in Deferred service handler */
+ CC_HAL_WRITE_REGISTER(CC_REG_OFFSET(HOST_RGF, HOST_IMR), imr | SSI_COMP_IRQ_MASK);
+ irr &= ~SSI_COMP_IRQ_MASK;
+ complete_request(drvdata);
+ }
+#ifdef CC_SUPPORT_FIPS
+ /* TEE FIPS interrupt */
+ if (likely((irr & SSI_GPR0_IRQ_MASK) != 0)) {
+ /* Mask interrupt - will be unmasked in Deferred service handler */
+ CC_HAL_WRITE_REGISTER(CC_REG_OFFSET(HOST_RGF, HOST_IMR), imr | SSI_GPR0_IRQ_MASK);
+ irr &= ~SSI_GPR0_IRQ_MASK;
+ fips_handler(drvdata);
+ }
+#endif
+ /* AXI error interrupt */
+ if (unlikely((irr & SSI_AXI_ERR_IRQ_MASK) != 0)) {
+ uint32_t axi_err;
+
+ /* Read the AXI error ID */
+ axi_err = CC_HAL_READ_REGISTER(CC_REG_OFFSET(CRY_KERNEL, AXIM_MON_ERR));
+ SSI_LOG_DEBUG("AXI completion error: axim_mon_err=0x%08X\n", axi_err);
+
+ irr &= ~SSI_AXI_ERR_IRQ_MASK;
+ }
+
+ if (unlikely(irr != 0)) {
+ SSI_LOG_DEBUG("IRR includes unknown cause bits (0x%08X)\n", irr);
+ /* Just warning */
+ }
+
+ END_CYCLE_COUNT(STAT_OP_TYPE_GENERIC, STAT_PHASE_0);
+ START_CYCLE_COUNT_AT(drvdata->isr_exit_cycles);
+
+ return IRQ_HANDLED;
+}
+
+int init_cc_regs(struct ssi_drvdata *drvdata, bool is_probe)
+{
+ unsigned int val;
+ void __iomem *cc_base = drvdata->cc_base;
+
+ /* Unmask all AXI interrupt sources AXI_CFG1 register */
+ val = CC_HAL_READ_REGISTER(CC_REG_OFFSET(CRY_KERNEL, AXIM_CFG));
+ CC_HAL_WRITE_REGISTER(CC_REG_OFFSET(CRY_KERNEL, AXIM_CFG), val & ~SSI_AXI_IRQ_MASK);
+ SSI_LOG_DEBUG("AXIM_CFG=0x%08X\n", CC_HAL_READ_REGISTER(CC_REG_OFFSET(CRY_KERNEL, AXIM_CFG)));
+
+ /* Clear all pending interrupts */
+ val = CC_HAL_READ_REGISTER(CC_REG_OFFSET(HOST_RGF, HOST_IRR));
+ SSI_LOG_DEBUG("IRR=0x%08X\n", val);
+ CC_HAL_WRITE_REGISTER(CC_REG_OFFSET(HOST_RGF, HOST_ICR), val);
+
+ /* Unmask relevant interrupt cause */
+ val = (~(SSI_COMP_IRQ_MASK | SSI_AXI_ERR_IRQ_MASK | SSI_GPR0_IRQ_MASK));
+ CC_HAL_WRITE_REGISTER(CC_REG_OFFSET(HOST_RGF, HOST_IMR), val);
+
+#ifdef DX_HOST_IRQ_TIMER_INIT_VAL_REG_OFFSET
+#ifdef DX_IRQ_DELAY
+ /* Set CC IRQ delay */
+ CC_HAL_WRITE_REGISTER(CC_REG_OFFSET(HOST_RGF, HOST_IRQ_TIMER_INIT_VAL),
+ DX_IRQ_DELAY);
+#endif
+ if (CC_HAL_READ_REGISTER(CC_REG_OFFSET(HOST_RGF, HOST_IRQ_TIMER_INIT_VAL)) > 0) {
+ SSI_LOG_DEBUG("irq_delay=%d CC cycles\n",
+ CC_HAL_READ_REGISTER(CC_REG_OFFSET(HOST_RGF, HOST_IRQ_TIMER_INIT_VAL)));
+ }
+#endif
+
+ val = CC_HAL_READ_REGISTER(CC_REG_OFFSET(CRY_KERNEL, AXIM_CACHE_PARAMS));
+ if (is_probe == true) {
+ SSI_LOG_INFO("Cache params previous: 0x%08X\n", val);
+ }
+ CC_HAL_WRITE_REGISTER(CC_REG_OFFSET(CRY_KERNEL, AXIM_CACHE_PARAMS), SSI_CACHE_PARAMS);
+ val = CC_HAL_READ_REGISTER(CC_REG_OFFSET(CRY_KERNEL, AXIM_CACHE_PARAMS));
+ if (is_probe == true) {
+ SSI_LOG_INFO("Cache params current: 0x%08X (expected: 0x%08X)\n", val, SSI_CACHE_PARAMS);
+ }
+
+ return 0;
+}
+
+static int init_cc_resources(struct platform_device *plat_dev)
+{
+ struct resource *req_mem_cc_regs = NULL;
+ void __iomem *cc_base = NULL;
+ bool irq_registered = false;
+ struct ssi_drvdata *new_drvdata = kzalloc(sizeof(struct ssi_drvdata), GFP_KERNEL);
+ uint32_t signature_val;
+ int rc = 0;
+
+ if (unlikely(new_drvdata == NULL)) {
+ SSI_LOG_ERR("Failed to allocate drvdata");
+ rc = -ENOMEM;
+ goto init_cc_res_err;
+ }
+
+ /*Initialize inflight counter used in dx_ablkcipher_secure_complete used for count of BYSPASS blocks operations*/
+ new_drvdata->inflight_counter = 0;
+
+ dev_set_drvdata(&plat_dev->dev, new_drvdata);
+ /* Get device resources */
+ /* First CC registers space */
+ new_drvdata->res_mem = platform_get_resource(plat_dev, IORESOURCE_MEM, 0);
+ if (unlikely(new_drvdata->res_mem == NULL)) {
+ SSI_LOG_ERR("Failed getting IO memory resource\n");
+ rc = -ENODEV;
+ goto init_cc_res_err;
+ }
+ SSI_LOG_DEBUG("Got MEM resource (%s): start=0x%llX end=0x%llX\n",
+ new_drvdata->res_mem->name,
+ (unsigned long long)new_drvdata->res_mem->start,
+ (unsigned long long)new_drvdata->res_mem->end);
+ /* Map registers space */
+ req_mem_cc_regs = request_mem_region(new_drvdata->res_mem->start, resource_size(new_drvdata->res_mem), "arm_cc7x_regs");
+ if (unlikely(req_mem_cc_regs == NULL)) {
+ SSI_LOG_ERR("Couldn't allocate registers memory region at "
+ "0x%08X\n", (unsigned int)new_drvdata->res_mem->start);
+ rc = -EBUSY;
+ goto init_cc_res_err;
+ }
+ cc_base = ioremap(new_drvdata->res_mem->start, resource_size(new_drvdata->res_mem));
+ if (unlikely(cc_base == NULL)) {
+ SSI_LOG_ERR("ioremap[CC](0x%08X,0x%08X) failed\n",
+ (unsigned int)new_drvdata->res_mem->start, (unsigned int)resource_size(new_drvdata->res_mem));
+ rc = -ENOMEM;
+ goto init_cc_res_err;
+ }
+ SSI_LOG_DEBUG("CC registers mapped from %pa to 0x%p\n", &new_drvdata->res_mem->start, cc_base);
+ new_drvdata->cc_base = cc_base;
+
+
+ /* Then IRQ */
+ new_drvdata->res_irq = platform_get_resource(plat_dev, IORESOURCE_IRQ, 0);
+ if (unlikely(new_drvdata->res_irq == NULL)) {
+ SSI_LOG_ERR("Failed getting IRQ resource\n");
+ rc = -ENODEV;
+ goto init_cc_res_err;
+ }
+ rc = request_irq(new_drvdata->res_irq->start, cc_isr,
+ IRQF_SHARED, "arm_cc7x", new_drvdata);
+ if (unlikely(rc != 0)) {
+ SSI_LOG_ERR("Could not register to interrupt %llu\n",
+ (unsigned long long)new_drvdata->res_irq->start);
+ goto init_cc_res_err;
+ }
+ init_completion(&new_drvdata->icache_setup_completion);
+
+ irq_registered = true;
+ SSI_LOG_DEBUG("Registered to IRQ (%s) %llu\n",
+ new_drvdata->res_irq->name,
+ (unsigned long long)new_drvdata->res_irq->start);
+
+ new_drvdata->plat_dev = plat_dev;
+
+ if(new_drvdata->plat_dev->dev.dma_mask == NULL)
+ {
+ new_drvdata->plat_dev->dev.dma_mask = & new_drvdata->plat_dev->dev.coherent_dma_mask;
+ }
+ if (!new_drvdata->plat_dev->dev.coherent_dma_mask)
+ {
+ new_drvdata->plat_dev->dev.coherent_dma_mask = DMA_BIT_MASK(DMA_BIT_MASK_LEN);
+ }
+
+ /* Verify correct mapping */
+ signature_val = CC_HAL_READ_REGISTER(CC_REG_OFFSET(HOST_RGF, HOST_SIGNATURE));
+ if (signature_val != DX_DEV_SIGNATURE) {
+ SSI_LOG_ERR("Invalid CC signature: SIGNATURE=0x%08X != expected=0x%08X\n",
+ signature_val, (uint32_t)DX_DEV_SIGNATURE);
+ rc = -EINVAL;
+ goto init_cc_res_err;
+ }
+ SSI_LOG_DEBUG("CC SIGNATURE=0x%08X\n", signature_val);
+
+ /* Display HW versions */
+ SSI_LOG(KERN_INFO, "ARM CryptoCell %s Driver: HW version 0x%08X, Driver version %s\n", SSI_DEV_NAME_STR,
+ CC_HAL_READ_REGISTER(CC_REG_OFFSET(HOST_RGF, HOST_VERSION)), DRV_MODULE_VERSION);
+
+ rc = init_cc_regs(new_drvdata, true);
+ if (unlikely(rc != 0)) {
+ SSI_LOG_ERR("init_cc_regs failed\n");
+ goto init_cc_res_err;
+ }
+
+#ifdef ENABLE_CC_SYSFS
+ rc = ssi_sysfs_init(&(plat_dev->dev.kobj), new_drvdata);
+ if (unlikely(rc != 0)) {
+ SSI_LOG_ERR("init_stat_db failed\n");
+ goto init_cc_res_err;
+ }
+#endif
+
+ rc = ssi_sram_mgr_init(new_drvdata);
+ if (unlikely(rc != 0)) {
+ SSI_LOG_ERR("ssi_sram_mgr_init failed\n");
+ goto init_cc_res_err;
+ }
+
+ new_drvdata->mlli_sram_addr =
+ ssi_sram_mgr_alloc(new_drvdata, MAX_MLLI_BUFF_SIZE);
+ if (unlikely(new_drvdata->mlli_sram_addr == NULL_SRAM_ADDR)) {
+ SSI_LOG_ERR("Failed to alloc MLLI Sram buffer\n");
+ rc = -ENOMEM;
+ goto init_cc_res_err;
+ }
+
+ rc = request_mgr_init(new_drvdata);
+ if (unlikely(rc != 0)) {
+ SSI_LOG_ERR("request_mgr_init failed\n");
+ goto init_cc_res_err;
+ }
+
+ rc = ssi_buffer_mgr_init(new_drvdata);
+ if (unlikely(rc != 0)) {
+ SSI_LOG_ERR("buffer_mgr_init failed\n");
+ goto init_cc_res_err;
+ }
+
+ rc = ssi_power_mgr_init(new_drvdata);
+ if (unlikely(rc != 0)) {
+ SSI_LOG_ERR("ssi_power_mgr_init failed\n");
+ goto init_cc_res_err;
+ }
+
+ rc = ssi_fips_init(new_drvdata);
+ if (unlikely(rc != 0)) {
+ SSI_LOG_ERR("SSI_FIPS_INIT failed 0x%x\n", rc);
+ goto init_cc_res_err;
+ }
+
+ rc = ssi_ivgen_init(new_drvdata);
+ if (unlikely(rc != 0)) {
+ SSI_LOG_ERR("ssi_ivgen_init failed\n");
+ goto init_cc_res_err;
+ }
+
+ /* Allocate crypto algs */
+ rc = ssi_ablkcipher_alloc(new_drvdata);
+ if (unlikely(rc != 0)) {
+ SSI_LOG_ERR("ssi_ablkcipher_alloc failed\n");
+ goto init_cc_res_err;
+ }
+
+ /* hash must be allocated before aead since hash exports APIs */
+ rc = ssi_hash_alloc(new_drvdata);
+ if (unlikely(rc != 0)) {
+ SSI_LOG_ERR("ssi_hash_alloc failed\n");
+ goto init_cc_res_err;
+ }
+
+ rc = ssi_aead_alloc(new_drvdata);
+ if (unlikely(rc != 0)) {
+ SSI_LOG_ERR("ssi_aead_alloc failed\n");
+ goto init_cc_res_err;
+ }
+
+ return 0;
+
+init_cc_res_err:
+ SSI_LOG_ERR("Freeing CC HW resources!\n");
+
+ if (new_drvdata != NULL) {
+ ssi_aead_free(new_drvdata);
+ ssi_hash_free(new_drvdata);
+ ssi_ablkcipher_free(new_drvdata);
+ ssi_ivgen_fini(new_drvdata);
+ ssi_power_mgr_fini(new_drvdata);
+ ssi_buffer_mgr_fini(new_drvdata);
+ request_mgr_fini(new_drvdata);
+ ssi_sram_mgr_fini(new_drvdata);
+ ssi_fips_fini(new_drvdata);
+#ifdef ENABLE_CC_SYSFS
+ ssi_sysfs_fini();
+#endif
+
+ if (req_mem_cc_regs != NULL) {
+ if (irq_registered) {
+ free_irq(new_drvdata->res_irq->start, new_drvdata);
+ new_drvdata->res_irq = NULL;
+ iounmap(cc_base);
+ new_drvdata->cc_base = NULL;
+ }
+ release_mem_region(new_drvdata->res_mem->start,
+ resource_size(new_drvdata->res_mem));
+ new_drvdata->res_mem = NULL;
+ }
+ kfree(new_drvdata);
+ dev_set_drvdata(&plat_dev->dev, NULL);
+ }
+
+ return rc;
+}
+
+void fini_cc_regs(struct ssi_drvdata *drvdata)
+{
+ /* Mask all interrupts */
+ WRITE_REGISTER(drvdata->cc_base +
+ CC_REG_OFFSET(HOST_RGF, HOST_IMR), 0xFFFFFFFF);
+
+}
+
+static void cleanup_cc_resources(struct platform_device *plat_dev)
+{
+ struct ssi_drvdata *drvdata =
+ (struct ssi_drvdata *)dev_get_drvdata(&plat_dev->dev);
+
+ ssi_aead_free(drvdata);
+ ssi_hash_free(drvdata);
+ ssi_ablkcipher_free(drvdata);
+ ssi_ivgen_fini(drvdata);
+ ssi_power_mgr_fini(drvdata);
+ ssi_buffer_mgr_fini(drvdata);
+ request_mgr_fini(drvdata);
+ ssi_sram_mgr_fini(drvdata);
+ ssi_fips_fini(drvdata);
+#ifdef ENABLE_CC_SYSFS
+ ssi_sysfs_fini();
+#endif
+
+ /* Mask all interrupts */
+ WRITE_REGISTER(drvdata->cc_base + CC_REG_OFFSET(HOST_RGF, HOST_IMR),
+ 0xFFFFFFFF);
+ free_irq(drvdata->res_irq->start, drvdata);
+ drvdata->res_irq = NULL;
+
+ fini_cc_regs(drvdata);
+
+ if (drvdata->cc_base != NULL) {
+ iounmap(drvdata->cc_base);
+ release_mem_region(drvdata->res_mem->start,
+ resource_size(drvdata->res_mem));
+ drvdata->cc_base = NULL;
+ drvdata->res_mem = NULL;
+ }
+
+ kfree(drvdata);
+ dev_set_drvdata(&plat_dev->dev, NULL);
+}
+
+static int cc7x_probe(struct platform_device *plat_dev)
+{
+ int rc;
+#if defined(CONFIG_ARM) && defined(CC_DEBUG)
+ uint32_t ctr, cacheline_size;
+
+ asm volatile("mrc p15, 0, %0, c0, c0, 1" : "=r" (ctr));
+ cacheline_size = 4 << ((ctr >> 16) & 0xf);
+ SSI_LOG_DEBUG("CP15(L1_CACHE_BYTES) = %u , Kconfig(L1_CACHE_BYTES) = %u\n",
+ cacheline_size, L1_CACHE_BYTES);
+
+ asm volatile("mrc p15, 0, %0, c0, c0, 0" : "=r" (ctr));
+ SSI_LOG_DEBUG("Main ID register (MIDR): Implementer 0x%02X, Arch 0x%01X,"
+ " Part 0x%03X, Rev r%dp%d\n",
+ (ctr>>24), (ctr>>16)&0xF, (ctr>>4)&0xFFF, (ctr>>20)&0xF, ctr&0xF);
+#endif
+
+ /* Map registers space */
+ rc = init_cc_resources(plat_dev);
+ if (rc != 0)
+ return rc;
+
+ SSI_LOG(KERN_INFO, "ARM cc7x_ree device initialized\n");
+
+ return 0;
+}
+
+static int cc7x_remove(struct platform_device *plat_dev)
+{
+ SSI_LOG_DEBUG("Releasing cc7x resources...\n");
+
+ cleanup_cc_resources(plat_dev);
+
+ SSI_LOG(KERN_INFO, "ARM cc7x_ree device terminated\n");
+#ifdef ENABLE_CYCLE_COUNT
+ display_all_stat_db();
+#endif
+
+ return 0;
+}
+#if defined (CONFIG_PM_RUNTIME) || defined (CONFIG_PM_SLEEP)
+static struct dev_pm_ops arm_cc7x_driver_pm = {
+ SET_RUNTIME_PM_OPS(ssi_power_mgr_runtime_suspend, ssi_power_mgr_runtime_resume, NULL)
+};
+#endif
+
+#if defined (CONFIG_PM_RUNTIME) || defined (CONFIG_PM_SLEEP)
+#define DX_DRIVER_RUNTIME_PM (&arm_cc7x_driver_pm)
+#else
+#define DX_DRIVER_RUNTIME_PM NULL
+#endif
+
+
+#ifdef CONFIG_OF
+static const struct of_device_id arm_cc7x_dev_of_match[] = {
+ {.compatible = "arm,cryptocell-712-ree"},
+ {}
+};
+MODULE_DEVICE_TABLE(of, arm_cc7x_dev_of_match);
+#endif
+
+static struct platform_driver cc7x_driver = {
+ .driver = {
+ .name = "cc7xree",
+#ifdef CONFIG_OF
+ .of_match_table = arm_cc7x_dev_of_match,
+#endif
+ .pm = DX_DRIVER_RUNTIME_PM,
+ },
+ .probe = cc7x_probe,
+ .remove = cc7x_remove,
+};
+module_platform_driver(cc7x_driver);
+
+/* Module description */
+MODULE_DESCRIPTION("ARM TrustZone CryptoCell REE Driver");
+MODULE_VERSION(DRV_MODULE_VERSION);
+MODULE_AUTHOR("ARM");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/ccree/ssi_driver.h b/drivers/staging/ccree/ssi_driver.h
new file mode 100644
index 0000000..891958b
--- /dev/null
+++ b/drivers/staging/ccree/ssi_driver.h
@@ -0,0 +1,228 @@
+/*
+ * Copyright (C) 2012-2017 ARM Limited or its affiliates.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* \file ssi_driver.h
+ ARM CryptoCell Linux Crypto Driver
+ */
+
+#ifndef __SSI_DRIVER_H__
+#define __SSI_DRIVER_H__
+
+#include "ssi_config.h"
+#ifdef COMP_IN_WQ
+#include <linux/workqueue.h>
+#else
+#include <linux/interrupt.h>
+#endif
+#include <linux/dma-mapping.h>
+#include <crypto/algapi.h>
+#include <crypto/internal/skcipher.h>
+#include <crypto/aes.h>
+#include <crypto/sha.h>
+#include <crypto/aead.h>
+#include <crypto/authenc.h>
+#include <crypto/hash.h>
+#include <linux/version.h>
+
+#ifndef INT32_MAX /* Missing in Linux kernel */
+#define INT32_MAX 0x7FFFFFFFL
+#endif
+
+/* Registers definitions from shared/hw/ree_include */
+#include "dx_reg_base_host.h"
+#include "dx_host.h"
+#define DX_CC_HOST_VIRT /* must be defined before including dx_cc_regs.h */
+#include "cc_hw_queue_defs.h"
+#include "cc_regs.h"
+#include "dx_reg_common.h"
+#include "cc_hal.h"
+#include "ssi_sram_mgr.h"
+#define CC_SUPPORT_SHA DX_DEV_SHA_MAX
+#include "cc_crypto_ctx.h"
+#include "ssi_sysfs.h"
+#include "hash_defs.h"
+#include "ssi_fips_local.h"
+
+#define DRV_MODULE_VERSION "3.0"
+
+#define SSI_DEV_NAME_STR "cc715ree"
+#define SSI_CC_HAS_AES_CCM 1
+#define SSI_CC_HAS_AES_GCM 1
+#define SSI_CC_HAS_AES_XTS 1
+#define SSI_CC_HAS_AES_ESSIV 1
+#define SSI_CC_HAS_AES_BITLOCKER 1
+#define SSI_CC_HAS_AES_CTS 1
+#define SSI_CC_HAS_MULTI2 0
+#define SSI_CC_HAS_CMAC 1
+
+#define SSI_AXI_IRQ_MASK ((1 << DX_AXIM_CFG_BRESPMASK_BIT_SHIFT) | (1 << DX_AXIM_CFG_RRESPMASK_BIT_SHIFT) | \
+ (1 << DX_AXIM_CFG_INFLTMASK_BIT_SHIFT) | (1 << DX_AXIM_CFG_COMPMASK_BIT_SHIFT))
+
+#define SSI_AXI_ERR_IRQ_MASK (1 << DX_HOST_IRR_AXI_ERR_INT_BIT_SHIFT)
+
+#define SSI_COMP_IRQ_MASK (1 << DX_HOST_IRR_AXIM_COMP_INT_BIT_SHIFT)
+
+/* TEE FIPS status interrupt */
+#define SSI_GPR0_IRQ_MASK (1 << DX_HOST_IRR_GPR0_BIT_SHIFT)
+
+#define SSI_CRA_PRIO 3000
+
+#define MIN_HW_QUEUE_SIZE 50 /* Minimum size required for proper function */
+
+#define MAX_REQUEST_QUEUE_SIZE 4096
+#define MAX_MLLI_BUFF_SIZE 2080
+#define MAX_ICV_NENTS_SUPPORTED 2
+
+/* Definitions for HW descriptors DIN/DOUT fields */
+#define NS_BIT 1
+#define AXI_ID 0
+/* AXI_ID is not actually the AXI ID of the transaction but the value of AXI_ID
+ field in the HW descriptor. The DMA engine +8 that value. */
+
+/* Logging macros */
+#define SSI_LOG(level, format, ...) \
+ printk(level "cc715ree::%s: " format , __func__, ##__VA_ARGS__)
+#define SSI_LOG_ERR(format, ...) SSI_LOG(KERN_ERR, format, ##__VA_ARGS__)
+#define SSI_LOG_WARNING(format, ...) SSI_LOG(KERN_WARNING, format, ##__VA_ARGS__)
+#define SSI_LOG_NOTICE(format, ...) SSI_LOG(KERN_NOTICE, format, ##__VA_ARGS__)
+#define SSI_LOG_INFO(format, ...) SSI_LOG(KERN_INFO, format, ##__VA_ARGS__)
+#ifdef CC_DEBUG
+#define SSI_LOG_DEBUG(format, ...) SSI_LOG(KERN_DEBUG, format, ##__VA_ARGS__)
+#else /* Debug log messages are removed at compile time for non-DEBUG config. */
+#define SSI_LOG_DEBUG(format, ...) do {} while (0)
+#endif
+
+#define MIN(a, b) (((a) < (b)) ? (a) : (b))
+#define MAX(a, b) (((a) > (b)) ? (a) : (b))
+
+#define SSI_MAX_IVGEN_DMA_ADDRESSES 3
+struct ssi_crypto_req {
+ void (*user_cb)(struct device *dev, void *req, void __iomem *cc_base);
+ void *user_arg;
+ dma_addr_t ivgen_dma_addr[SSI_MAX_IVGEN_DMA_ADDRESSES]; /* For the first 'ivgen_dma_addr_len' addresses of this array,
+ generated IV would be placed in it by send_request().
+ Same generated IV for all addresses! */
+ unsigned int ivgen_dma_addr_len; /* Amount of 'ivgen_dma_addr' elements to be filled. */
+ unsigned int ivgen_size; /* The generated IV size required, 8/16 B allowed. */
+ struct completion seq_compl; /* request completion */
+#ifdef ENABLE_CYCLE_COUNT
+ enum stat_op op_type;
+ cycles_t submit_cycle;
+ bool is_monitored_p;
+#endif
+};
+
+/**
+ * struct ssi_drvdata - driver private data context
+ * @cc_base: virt address of the CC registers
+ * @irq: device IRQ number
+ * @irq_mask: Interrupt mask shadow (1 for masked interrupts)
+ * @fw_ver: SeP loaded firmware version
+ */
+struct ssi_drvdata {
+ struct resource *res_mem;
+ struct resource *res_irq;
+ void __iomem *cc_base;
+#ifdef DX_BASE_ENV_REGS
+ void __iomem *env_base; /* ARM CryptoCell development FPGAs only */
+#endif
+ unsigned int irq;
+ uint32_t irq_mask;
+ uint32_t fw_ver;
+ /* Calibration time of start/stop
+ * monitor descriptors */
+ uint32_t monitor_null_cycles;
+ struct platform_device *plat_dev;
+ ssi_sram_addr_t mlli_sram_addr;
+ struct completion icache_setup_completion;
+ void *buff_mgr_handle;
+ void *hash_handle;
+ void *aead_handle;
+ void *blkcipher_handle;
+ void *request_mgr_handle;
+ void *fips_handle;
+ void *ivgen_handle;
+ void *sram_mgr_handle;
+
+#ifdef ENABLE_CYCLE_COUNT
+ cycles_t isr_exit_cycles; /* Save for isr-to-tasklet latency */
+#endif
+ uint32_t inflight_counter;
+
+};
+
+struct ssi_crypto_alg {
+ struct list_head entry;
+ int cipher_mode;
+ int flow_mode; /* Note: currently, refers to the cipher mode only. */
+ int auth_mode;
+ struct ssi_drvdata *drvdata;
+ struct crypto_alg crypto_alg;
+ struct aead_alg aead_alg;
+};
+
+struct ssi_alg_template {
+ char name[CRYPTO_MAX_ALG_NAME];
+ char driver_name[CRYPTO_MAX_ALG_NAME];
+ unsigned int blocksize;
+ u32 type;
+ union {
+ struct ablkcipher_alg ablkcipher;
+ struct aead_alg aead;
+ struct blkcipher_alg blkcipher;
+ struct cipher_alg cipher;
+ struct compress_alg compress;
+ } template_u;
+ int cipher_mode;
+ int flow_mode; /* Note: currently, refers to the cipher mode only. */
+ int auth_mode;
+ bool synchronous;
+ struct ssi_drvdata *drvdata;
+};
+
+struct async_gen_req_ctx {
+ dma_addr_t iv_dma_addr;
+ enum drv_crypto_direction op_type;
+};
+
+#ifdef DX_DUMP_BYTES
+void dump_byte_array(const char *name, const uint8_t *the_array, unsigned long size);
+#else
+#define dump_byte_array(name, array, size) do { \
+} while (0);
+#endif
+
+#ifdef ENABLE_CYCLE_COUNT
+#define DECL_CYCLE_COUNT_RESOURCES cycles_t _last_cycles_read
+#define START_CYCLE_COUNT() do { _last_cycles_read = get_cycles(); } while (0)
+#define END_CYCLE_COUNT(_stat_op_type, _stat_phase) update_host_stat(_stat_op_type, _stat_phase, get_cycles() - _last_cycles_read)
+#define GET_START_CYCLE_COUNT() _last_cycles_read
+#define START_CYCLE_COUNT_AT(_var) do { _var = get_cycles(); } while(0)
+#define END_CYCLE_COUNT_AT(_var, _stat_op_type, _stat_phase) update_host_stat(_stat_op_type, _stat_phase, get_cycles() - _var)
+#else
+#define DECL_CYCLE_COUNT_RESOURCES
+#define START_CYCLE_COUNT() do { } while (0)
+#define END_CYCLE_COUNT(_stat_op_type, _stat_phase) do { } while (0)
+#define GET_START_CYCLE_COUNT() 0
+#define START_CYCLE_COUNT_AT(_var) do { } while (0)
+#define END_CYCLE_COUNT_AT(_var, _stat_op_type, _stat_phase) do { } while (0)
+#endif /*ENABLE_CYCLE_COUNT*/
+
+int init_cc_regs(struct ssi_drvdata *drvdata, bool is_probe);
+void fini_cc_regs(struct ssi_drvdata *drvdata);
+
+#endif /*__SSI_DRIVER_H__*/
+
diff --git a/drivers/staging/ccree/ssi_fips.c b/drivers/staging/ccree/ssi_fips.c
new file mode 100644
index 0000000..50f7485
--- /dev/null
+++ b/drivers/staging/ccree/ssi_fips.c
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2012-2017 ARM Limited or its affiliates.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+/**************************************************************
+This file defines the driver FIPS APIs *
+***************************************************************/
+
+#include <linux/module.h>
+#include "ssi_fips.h"
+
+
+extern int ssi_fips_ext_get_state(ssi_fips_state_t *p_state);
+extern int ssi_fips_ext_get_error(ssi_fips_error_t *p_err);
+
+/*
+This function returns the REE FIPS state.
+It should be called by kernel module.
+*/
+int ssi_fips_get_state(ssi_fips_state_t *p_state)
+{
+ int rc = 0;
+
+ if (p_state == NULL) {
+ return -EINVAL;
+ }
+
+ rc = ssi_fips_ext_get_state(p_state);
+
+ return rc;
+}
+
+EXPORT_SYMBOL(ssi_fips_get_state);
+
+/*
+This function returns the REE FIPS error.
+It should be called by kernel module.
+*/
+int ssi_fips_get_error(ssi_fips_error_t *p_err)
+{
+ int rc = 0;
+
+ if (p_err == NULL) {
+ return -EINVAL;
+ }
+
+ rc = ssi_fips_ext_get_error(p_err);
+
+ return rc;
+}
+
+EXPORT_SYMBOL(ssi_fips_get_error);
diff --git a/drivers/staging/ccree/ssi_fips.h b/drivers/staging/ccree/ssi_fips.h
new file mode 100644
index 0000000..19bcdeb
--- /dev/null
+++ b/drivers/staging/ccree/ssi_fips.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2012-2017 ARM Limited or its affiliates.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __SSI_FIPS_H__
+#define __SSI_FIPS_H__
+
+
+#ifndef INT32_MAX /* Missing in Linux kernel */
+#define INT32_MAX 0x7FFFFFFFL
+#endif
+
+
+/*!
+@file
+@brief This file contains FIPS related defintions and APIs.
+*/
+
+typedef enum ssi_fips_state {
+ CC_FIPS_STATE_NOT_SUPPORTED = 0,
+ CC_FIPS_STATE_SUPPORTED,
+ CC_FIPS_STATE_ERROR,
+ CC_FIPS_STATE_RESERVE32B = INT32_MAX
+} ssi_fips_state_t;
+
+
+typedef enum ssi_fips_error {
+ CC_REE_FIPS_ERROR_OK = 0,
+ CC_REE_FIPS_ERROR_GENERAL,
+ CC_REE_FIPS_ERROR_FROM_TEE,
+ CC_REE_FIPS_ERROR_AES_ECB_PUT,
+ CC_REE_FIPS_ERROR_AES_CBC_PUT,
+ CC_REE_FIPS_ERROR_AES_OFB_PUT,
+ CC_REE_FIPS_ERROR_AES_CTR_PUT,
+ CC_REE_FIPS_ERROR_AES_CBC_CTS_PUT,
+ CC_REE_FIPS_ERROR_AES_XTS_PUT,
+ CC_REE_FIPS_ERROR_AES_CMAC_PUT,
+ CC_REE_FIPS_ERROR_AESCCM_PUT,
+ CC_REE_FIPS_ERROR_AESGCM_PUT,
+ CC_REE_FIPS_ERROR_DES_ECB_PUT,
+ CC_REE_FIPS_ERROR_DES_CBC_PUT,
+ CC_REE_FIPS_ERROR_SHA1_PUT,
+ CC_REE_FIPS_ERROR_SHA256_PUT,
+ CC_REE_FIPS_ERROR_SHA512_PUT,
+ CC_REE_FIPS_ERROR_HMAC_SHA1_PUT,
+ CC_REE_FIPS_ERROR_HMAC_SHA256_PUT,
+ CC_REE_FIPS_ERROR_HMAC_SHA512_PUT,
+ CC_REE_FIPS_ERROR_ROM_CHECKSUM,
+ CC_REE_FIPS_ERROR_RESERVE32B = INT32_MAX
+} ssi_fips_error_t;
+
+
+
+int ssi_fips_get_state(ssi_fips_state_t *p_state);
+int ssi_fips_get_error(ssi_fips_error_t *p_err);
+
+#endif /*__SSI_FIPS_H__*/
+
diff --git a/drivers/staging/ccree/ssi_fips_data.h b/drivers/staging/ccree/ssi_fips_data.h
new file mode 100644
index 0000000..3fddd8f
--- /dev/null
+++ b/drivers/staging/ccree/ssi_fips_data.h
@@ -0,0 +1,315 @@
+/*
+ * Copyright (C) 2012-2017 ARM Limited or its affiliates.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+The test vectors were taken from:
+
+* AES
+NIST Special Publication 800-38A 2001 Edition
+Recommendation for Block Cipher Modes of Operation
+http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf
+Appendix F: Example Vectors for Modes of Operation of the AES
+
+* AES CTS
+Advanced Encryption Standard (AES) Encryption for Kerberos 5
+February 2005
+https://tools.ietf.org/html/rfc3962#appendix-B
+B. Sample Test Vectors
+
+* AES XTS
+http://csrc.nist.gov/groups/STM/cavp/#08
+http://csrc.nist.gov/groups/STM/cavp/documents/aes/XTSTestVectors.zip
+
+* AES CMAC
+http://csrc.nist.gov/groups/STM/cavp/index.html#07
+http://csrc.nist.gov/groups/STM/cavp/documents/mac/cmactestvectors.zip
+
+* AES-CCM
+http://csrc.nist.gov/groups/STM/cavp/#07
+http://csrc.nist.gov/groups/STM/cavp/documents/mac/ccmtestvectors.zip
+
+* AES-GCM
+http://csrc.nist.gov/groups/STM/cavp/documents/mac/gcmtestvectors.zip
+
+* Triple-DES
+NIST Special Publication 800-67 January 2012
+Recommendation for the Triple Data Encryption Algorithm (TDEA) Block Cipher
+http://csrc.nist.gov/publications/nistpubs/800-67-Rev1/SP-800-67-Rev1.pdf
+APPENDIX B: EXAMPLE OF TDEA FORWARD AND INVERSE CIPHER OPERATIONS
+and
+http://csrc.nist.gov/groups/STM/cavp/#01
+http://csrc.nist.gov/groups/STM/cavp/documents/des/tdesmct_intermediate.zip
+
+* HASH
+http://csrc.nist.gov/groups/STM/cavp/#03
+http://csrc.nist.gov/groups/STM/cavp/documents/shs/shabytetestvectors.zip
+
+* HMAC
+http://csrc.nist.gov/groups/STM/cavp/#07
+http://csrc.nist.gov/groups/STM/cavp/documents/mac/hmactestvectors.zip
+
+*/
+
+/* NIST AES */
+#define AES_128_BIT_KEY_SIZE 16
+#define AES_192_BIT_KEY_SIZE 24
+#define AES_256_BIT_KEY_SIZE 32
+#define AES_512_BIT_KEY_SIZE 64
+
+#define NIST_AES_IV_SIZE 16
+
+#define NIST_AES_128_KEY { 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c }
+#define NIST_AES_192_KEY { 0x8e, 0x73, 0xb0, 0xf7, 0xda, 0x0e, 0x64, 0x52, 0xc8, 0x10, 0xf3, 0x2b, 0x80, 0x90, 0x79, 0xe5, \
+ 0x62, 0xf8, 0xea, 0xd2, 0x52, 0x2c, 0x6b, 0x7b }
+#define NIST_AES_256_KEY { 0x60, 0x3d, 0xeb, 0x10, 0x15, 0xca, 0x71, 0xbe, 0x2b, 0x73, 0xae, 0xf0, 0x85, 0x7d, 0x77, 0x81, \
+ 0x1f, 0x35, 0x2c, 0x07, 0x3b, 0x61, 0x08, 0xd7, 0x2d, 0x98, 0x10, 0xa3, 0x09, 0x14, 0xdf, 0xf4 }
+#define NIST_AES_VECTOR_SIZE 16
+#define NIST_AES_PLAIN_DATA { 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a }
+
+#define NIST_AES_ECB_IV { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }
+#define NIST_AES_128_ECB_CIPHER { 0x3a, 0xd7, 0x7b, 0xb4, 0x0d, 0x7a, 0x36, 0x60, 0xa8, 0x9e, 0xca, 0xf3, 0x24, 0x66, 0xef, 0x97 }
+#define NIST_AES_192_ECB_CIPHER { 0xbd, 0x33, 0x4f, 0x1d, 0x6e, 0x45, 0xf2, 0x5f, 0xf7, 0x12, 0xa2, 0x14, 0x57, 0x1f, 0xa5, 0xcc }
+#define NIST_AES_256_ECB_CIPHER { 0xf3, 0xee, 0xd1, 0xbd, 0xb5, 0xd2, 0xa0, 0x3c, 0x06, 0x4b, 0x5a, 0x7e, 0x3d, 0xb1, 0x81, 0xf8 }
+
+#define NIST_AES_CBC_IV { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }
+#define NIST_AES_128_CBC_CIPHER { 0x76, 0x49, 0xab, 0xac, 0x81, 0x19, 0xb2, 0x46, 0xce, 0xe9, 0x8e, 0x9b, 0x12, 0xe9, 0x19, 0x7d }
+#define NIST_AES_192_CBC_CIPHER { 0x4f, 0x02, 0x1d, 0xb2, 0x43, 0xbc, 0x63, 0x3d, 0x71, 0x78, 0x18, 0x3a, 0x9f, 0xa0, 0x71, 0xe8 }
+#define NIST_AES_256_CBC_CIPHER { 0xf5, 0x8c, 0x4c, 0x04, 0xd6, 0xe5, 0xf1, 0xba, 0x77, 0x9e, 0xab, 0xfb, 0x5f, 0x7b, 0xfb, 0xd6 }
+
+#define NIST_AES_OFB_IV { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }
+#define NIST_AES_128_OFB_CIPHER { 0x3b, 0x3f, 0xd9, 0x2e, 0xb7, 0x2d, 0xad, 0x20, 0x33, 0x34, 0x49, 0xf8, 0xe8, 0x3c, 0xfb, 0x4a }
+#define NIST_AES_192_OFB_CIPHER { 0xcd, 0xc8, 0x0d, 0x6f, 0xdd, 0xf1, 0x8c, 0xab, 0x34, 0xc2, 0x59, 0x09, 0xc9, 0x9a, 0x41, 0x74 }
+#define NIST_AES_256_OFB_CIPHER { 0xdc, 0x7e, 0x84, 0xbf, 0xda, 0x79, 0x16, 0x4b, 0x7e, 0xcd, 0x84, 0x86, 0x98, 0x5d, 0x38, 0x60 }
+
+#define NIST_AES_CTR_IV { 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff }
+#define NIST_AES_128_CTR_CIPHER { 0x87, 0x4d, 0x61, 0x91, 0xb6, 0x20, 0xe3, 0x26, 0x1b, 0xef, 0x68, 0x64, 0x99, 0x0d, 0xb6, 0xce }
+#define NIST_AES_192_CTR_CIPHER { 0x1a, 0xbc, 0x93, 0x24, 0x17, 0x52, 0x1c, 0xa2, 0x4f, 0x2b, 0x04, 0x59, 0xfe, 0x7e, 0x6e, 0x0b }
+#define NIST_AES_256_CTR_CIPHER { 0x60, 0x1e, 0xc3, 0x13, 0x77, 0x57, 0x89, 0xa5, 0xb7, 0xa7, 0xf5, 0x04, 0xbb, 0xf3, 0xd2, 0x28 }
+
+
+#define RFC3962_AES_128_KEY { 0x63, 0x68, 0x69, 0x63, 0x6b, 0x65, 0x6e, 0x20, 0x74, 0x65, 0x72, 0x69, 0x79, 0x61, 0x6b, 0x69 }
+#define RFC3962_AES_VECTOR_SIZE 17
+#define RFC3962_AES_PLAIN_DATA { 0x49, 0x20, 0x77, 0x6f, 0x75, 0x6c, 0x64, 0x20, 0x6c, 0x69, 0x6b, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20 }
+#define RFC3962_AES_CBC_CTS_IV { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }
+#define RFC3962_AES_128_CBC_CTS_CIPHER { 0xc6, 0x35, 0x35, 0x68, 0xf2, 0xbf, 0x8c, 0xb4, 0xd8, 0xa5, 0x80, 0x36, 0x2d, 0xa7, 0xff, 0x7f, 0x97 }
+
+
+#define NIST_AES_256_XTS_KEY { 0xa1, 0xb9, 0x0c, 0xba, 0x3f, 0x06, 0xac, 0x35, 0x3b, 0x2c, 0x34, 0x38, 0x76, 0x08, 0x17, 0x62, \
+ 0x09, 0x09, 0x23, 0x02, 0x6e, 0x91, 0x77, 0x18, 0x15, 0xf2, 0x9d, 0xab, 0x01, 0x93, 0x2f, 0x2f }
+#define NIST_AES_256_XTS_IV { 0x4f, 0xae, 0xf7, 0x11, 0x7c, 0xda, 0x59, 0xc6, 0x6e, 0x4b, 0x92, 0x01, 0x3e, 0x76, 0x8a, 0xd5 }
+#define NIST_AES_256_XTS_VECTOR_SIZE 16
+#define NIST_AES_256_XTS_PLAIN { 0xeb, 0xab, 0xce, 0x95, 0xb1, 0x4d, 0x3c, 0x8d, 0x6f, 0xb3, 0x50, 0x39, 0x07, 0x90, 0x31, 0x1c }
+#define NIST_AES_256_XTS_CIPHER { 0x77, 0x8a, 0xe8, 0xb4, 0x3c, 0xb9, 0x8d, 0x5a, 0x82, 0x50, 0x81, 0xd5, 0xbe, 0x47, 0x1c, 0x63 }
+
+#define NIST_AES_512_XTS_KEY { 0x1e, 0xa6, 0x61, 0xc5, 0x8d, 0x94, 0x3a, 0x0e, 0x48, 0x01, 0xe4, 0x2f, 0x4b, 0x09, 0x47, 0x14, \
+ 0x9e, 0x7f, 0x9f, 0x8e, 0x3e, 0x68, 0xd0, 0xc7, 0x50, 0x52, 0x10, 0xbd, 0x31, 0x1a, 0x0e, 0x7c, \
+ 0xd6, 0xe1, 0x3f, 0xfd, 0xf2, 0x41, 0x8d, 0x8d, 0x19, 0x11, 0xc0, 0x04, 0xcd, 0xa5, 0x8d, 0xa3, \
+ 0xd6, 0x19, 0xb7, 0xe2, 0xb9, 0x14, 0x1e, 0x58, 0x31, 0x8e, 0xea, 0x39, 0x2c, 0xf4, 0x1b, 0x08 }
+#define NIST_AES_512_XTS_IV { 0xad, 0xf8, 0xd9, 0x26, 0x27, 0x46, 0x4a, 0xd2, 0xf0, 0x42, 0x8e, 0x84, 0xa9, 0xf8, 0x75, 0x64, }
+#define NIST_AES_512_XTS_VECTOR_SIZE 32
+#define NIST_AES_512_XTS_PLAIN { 0x2e, 0xed, 0xea, 0x52, 0xcd, 0x82, 0x15, 0xe1, 0xac, 0xc6, 0x47, 0xe8, 0x10, 0xbb, 0xc3, 0x64, \
+ 0x2e, 0x87, 0x28, 0x7f, 0x8d, 0x2e, 0x57, 0xe3, 0x6c, 0x0a, 0x24, 0xfb, 0xc1, 0x2a, 0x20, 0x2e }
+#define NIST_AES_512_XTS_CIPHER { 0xcb, 0xaa, 0xd0, 0xe2, 0xf6, 0xce, 0xa3, 0xf5, 0x0b, 0x37, 0xf9, 0x34, 0xd4, 0x6a, 0x9b, 0x13, \
+ 0x0b, 0x9d, 0x54, 0xf0, 0x7e, 0x34, 0xf3, 0x6a, 0xf7, 0x93, 0xe8, 0x6f, 0x73, 0xc6, 0xd7, 0xdb }
+
+
+/* NIST AES-CMAC */
+#define NIST_AES_128_CMAC_KEY { 0x67, 0x08, 0xc9, 0x88, 0x7b, 0x84, 0x70, 0x84, 0xf1, 0x23, 0xd3, 0xdd, 0x9c, 0x3a, 0x81, 0x36 }
+#define NIST_AES_128_CMAC_PLAIN_DATA { 0xa8, 0xde, 0x55, 0x17, 0x0c, 0x6d, 0xc0, 0xd8, 0x0d, 0xe3, 0x2f, 0x50, 0x8b, 0xf4, 0x9b, 0x70 }
+#define NIST_AES_128_CMAC_MAC { 0xcf, 0xef, 0x9b, 0x78, 0x39, 0x84, 0x1f, 0xdb, 0xcc, 0xbb, 0x6c, 0x2c, 0xf2, 0x38, 0xf7 }
+#define NIST_AES_128_CMAC_VECTOR_SIZE 16
+#define NIST_AES_128_CMAC_OUTPUT_SIZE 15
+
+#define NIST_AES_192_CMAC_KEY { 0x20, 0x51, 0xaf, 0x34, 0x76, 0x2e, 0xbe, 0x55, 0x6f, 0x72, 0xa5, 0xc6, 0xed, 0xc7, 0x77, 0x1e, \
+ 0xb9, 0x24, 0x5f, 0xad, 0x76, 0xf0, 0x34, 0xbe }
+#define NIST_AES_192_CMAC_PLAIN_DATA { 0xae, 0x8e, 0x93, 0xc9, 0xc9, 0x91, 0xcf, 0x89, 0x6a, 0x49, 0x1a, 0x89, 0x07, 0xdf, 0x4e, 0x4b, \
+ 0xe5, 0x18, 0x6a, 0xe4, 0x96, 0xcd, 0x34, 0x0d, 0xc1, 0x9b, 0x23, 0x78, 0x21, 0xdb, 0x7b, 0x60 }
+#define NIST_AES_192_CMAC_MAC { 0x74, 0xf7, 0x46, 0x08, 0xc0, 0x4f, 0x0f, 0x4e, 0x47, 0xfa, 0x64, 0x04, 0x33, 0xb6, 0xe6, 0xfb }
+#define NIST_AES_192_CMAC_VECTOR_SIZE 32
+#define NIST_AES_192_CMAC_OUTPUT_SIZE 16
+
+#define NIST_AES_256_CMAC_KEY { 0x3a, 0x75, 0xa9, 0xd2, 0xbd, 0xb8, 0xc8, 0x04, 0xba, 0x4a, 0xb4, 0x98, 0x35, 0x73, 0xa6, 0xb2, \
+ 0x53, 0x16, 0x0d, 0xd9, 0x0f, 0x8e, 0xdd, 0xfb, 0x2f, 0xdc, 0x2a, 0xb1, 0x76, 0x04, 0xf5, 0xc5 }
+#define NIST_AES_256_CMAC_PLAIN_DATA { 0x42, 0xf3, 0x5d, 0x5a, 0xa5, 0x33, 0xa7, 0xa0, 0xa5, 0xf7, 0x4e, 0x14, 0x4f, 0x2a, 0x5f, 0x20 }
+#define NIST_AES_256_CMAC_MAC { 0xf1, 0x53, 0x2f, 0x87, 0x32, 0xd9, 0xf5, 0x90, 0x30, 0x07 }
+#define NIST_AES_256_CMAC_VECTOR_SIZE 16
+#define NIST_AES_256_CMAC_OUTPUT_SIZE 10
+
+
+/* NIST TDES */
+#define TDES_NUM_OF_KEYS 3
+#define NIST_TDES_VECTOR_SIZE 8
+#define NIST_TDES_IV_SIZE 8
+
+#define NIST_TDES_ECB_IV { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }
+
+#define NIST_TDES_ECB3_KEY { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, \
+ 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0x01, \
+ 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0x01, 0x23 }
+#define NIST_TDES_ECB3_PLAIN_DATA { 0x54, 0x68, 0x65, 0x20, 0x71, 0x75, 0x66, 0x63 }
+#define NIST_TDES_ECB3_CIPHER { 0xa8, 0x26, 0xfd, 0x8c, 0xe5, 0x3b, 0x85, 0x5f }
+
+#define NIST_TDES_CBC3_IV { 0xf8, 0xee, 0xe1, 0x35, 0x9c, 0x6e, 0x54, 0x40 }
+#define NIST_TDES_CBC3_KEY { 0xe9, 0xda, 0x37, 0xf8, 0xdc, 0x97, 0x6d, 0x5b, \
+ 0xb6, 0x8c, 0x04, 0xe3, 0xec, 0x98, 0x20, 0x15, \
+ 0xf4, 0x0e, 0x08, 0xb5, 0x97, 0x29, 0xf2, 0x8f }
+#define NIST_TDES_CBC3_PLAIN_DATA { 0x3b, 0xb7, 0xa7, 0xdb, 0xa3, 0xd5, 0x92, 0x91 }
+#define NIST_TDES_CBC3_CIPHER { 0x5b, 0x84, 0x24, 0xd2, 0x39, 0x3e, 0x55, 0xa2 }
+
+
+/* NIST AES-CCM */
+#define NIST_AESCCM_128_BIT_KEY_SIZE 16
+#define NIST_AESCCM_192_BIT_KEY_SIZE 24
+#define NIST_AESCCM_256_BIT_KEY_SIZE 32
+
+#define NIST_AESCCM_B0_VAL 0x79 /* L'[0:2]=1 , M'[3-5]=7 , Adata[6]=1, reserved[7]=0 */
+#define NIST_AESCCM_NONCE_SIZE 13
+#define NIST_AESCCM_IV_SIZE 16
+#define NIST_AESCCM_ADATA_SIZE 32
+#define NIST_AESCCM_TEXT_SIZE 16
+#define NIST_AESCCM_TAG_SIZE 16
+
+#define NIST_AESCCM_128_KEY { 0x70, 0x01, 0x0e, 0xd9, 0x0e, 0x61, 0x86, 0xec, 0xad, 0x41, 0xf0, 0xd3, 0xc7, 0xc4, 0x2f, 0xf8 }
+#define NIST_AESCCM_128_NONCE { 0xa5, 0xf4, 0xf4, 0x98, 0x6e, 0x98, 0x47, 0x29, 0x65, 0xf5, 0xab, 0xcc, 0x4b }
+#define NIST_AESCCM_128_ADATA { 0x3f, 0xec, 0x0e, 0x5c, 0xc2, 0x4d, 0x67, 0x13, 0x94, 0x37, 0xcb, 0xc8, 0x11, 0x24, 0x14, 0xfc, \
+ 0x8d, 0xac, 0xcd, 0x1a, 0x94, 0xb4, 0x9a, 0x4c, 0x76, 0xe2, 0xd3, 0x93, 0x03, 0x54, 0x73, 0x17 }
+#define NIST_AESCCM_128_PLAIN_TEXT { 0xbe, 0x32, 0x2f, 0x58, 0xef, 0xa7, 0xf8, 0xc6, 0x8a, 0x63, 0x5e, 0x0b, 0x9c, 0xce, 0x77, 0xf2 }
+#define NIST_AESCCM_128_CIPHER { 0x8e, 0x44, 0x25, 0xae, 0x57, 0x39, 0x74, 0xf0, 0xf0, 0x69, 0x3a, 0x18, 0x8b, 0x52, 0x58, 0x12 }
+#define NIST_AESCCM_128_MAC { 0xee, 0xf0, 0x8e, 0x3f, 0xb1, 0x5f, 0x42, 0x27, 0xe0, 0xd9, 0x89, 0xa4, 0xd5, 0x87, 0xa8, 0xcf }
+
+#define NIST_AESCCM_192_KEY { 0x68, 0x73, 0xf1, 0xc6, 0xc3, 0x09, 0x75, 0xaf, 0xf6, 0xf0, 0x84, 0x70, 0x26, 0x43, 0x21, 0x13, \
+ 0x0a, 0x6e, 0x59, 0x84, 0xad, 0xe3, 0x24, 0xe9 }
+#define NIST_AESCCM_192_NONCE { 0x7c, 0x4d, 0x2f, 0x7c, 0xec, 0x04, 0x36, 0x1f, 0x18, 0x7f, 0x07, 0x26, 0xd5 }
+#define NIST_AESCCM_192_ADATA { 0x77, 0x74, 0x3b, 0x5d, 0x83, 0xa0, 0x0d, 0x2c, 0x8d, 0x5f, 0x7e, 0x10, 0x78, 0x15, 0x31, 0xb4, \
+ 0x96, 0xe0, 0x9f, 0x3b, 0xc9, 0x29, 0x5d, 0x7a, 0xe9, 0x79, 0x9e, 0x64, 0x66, 0x8e, 0xf8, 0xc5 }
+#define NIST_AESCCM_192_PLAIN_TEXT { 0x50, 0x51, 0xa0, 0xb0, 0xb6, 0x76, 0x6c, 0xd6, 0xea, 0x29, 0xa6, 0x72, 0x76, 0x9d, 0x40, 0xfe }
+#define NIST_AESCCM_192_CIPHER { 0x0c, 0xe5, 0xac, 0x8d, 0x6b, 0x25, 0x6f, 0xb7, 0x58, 0x0b, 0xf6, 0xac, 0xc7, 0x64, 0x26, 0xaf }
+#define NIST_AESCCM_192_MAC { 0x40, 0xbc, 0xe5, 0x8f, 0xd4, 0xcd, 0x65, 0x48, 0xdf, 0x90, 0xa0, 0x33, 0x7c, 0x84, 0x20, 0x04 }
+
+#define NIST_AESCCM_256_KEY { 0xee, 0x8c, 0xe1, 0x87, 0x16, 0x97, 0x79, 0xd1, 0x3e, 0x44, 0x3d, 0x64, 0x28, 0xe3, 0x8b, 0x38, \
+ 0xb5, 0x5d, 0xfb, 0x90, 0xf0, 0x22, 0x8a, 0x8a, 0x4e, 0x62, 0xf8, 0xf5, 0x35, 0x80, 0x6e, 0x62 }
+#define NIST_AESCCM_256_NONCE { 0x12, 0x16, 0x42, 0xc4, 0x21, 0x8b, 0x39, 0x1c, 0x98, 0xe6, 0x26, 0x9c, 0x8a }
+#define NIST_AESCCM_256_ADATA { 0x71, 0x8d, 0x13, 0xe4, 0x75, 0x22, 0xac, 0x4c, 0xdf, 0x3f, 0x82, 0x80, 0x63, 0x98, 0x0b, 0x6d, \
+ 0x45, 0x2f, 0xcd, 0xcd, 0x6e, 0x1a, 0x19, 0x04, 0xbf, 0x87, 0xf5, 0x48, 0xa5, 0xfd, 0x5a, 0x05 }
+#define NIST_AESCCM_256_PLAIN_TEXT { 0xd1, 0x5f, 0x98, 0xf2, 0xc6, 0xd6, 0x70, 0xf5, 0x5c, 0x78, 0xa0, 0x66, 0x48, 0x33, 0x2b, 0xc9 }
+#define NIST_AESCCM_256_CIPHER { 0xcc, 0x17, 0xbf, 0x87, 0x94, 0xc8, 0x43, 0x45, 0x7d, 0x89, 0x93, 0x91, 0x89, 0x8e, 0xd2, 0x2a }
+#define NIST_AESCCM_256_MAC { 0x6f, 0x9d, 0x28, 0xfc, 0xb6, 0x42, 0x34, 0xe1, 0xcd, 0x79, 0x3c, 0x41, 0x44, 0xf1, 0xda, 0x50 }
+
+
+/* NIST AES-GCM */
+#define NIST_AESGCM_128_BIT_KEY_SIZE 16
+#define NIST_AESGCM_192_BIT_KEY_SIZE 24
+#define NIST_AESGCM_256_BIT_KEY_SIZE 32
+
+#define NIST_AESGCM_IV_SIZE 12
+#define NIST_AESGCM_ADATA_SIZE 16
+#define NIST_AESGCM_TEXT_SIZE 16
+#define NIST_AESGCM_TAG_SIZE 16
+
+#define NIST_AESGCM_128_KEY { 0x81, 0x6e, 0x39, 0x07, 0x04, 0x10, 0xcf, 0x21, 0x84, 0x90, 0x4d, 0xa0, 0x3e, 0xa5, 0x07, 0x5a }
+#define NIST_AESGCM_128_IV { 0x32, 0xc3, 0x67, 0xa3, 0x36, 0x26, 0x13, 0xb2, 0x7f, 0xc3, 0xe6, 0x7e }
+#define NIST_AESGCM_128_ADATA { 0xf2, 0xa3, 0x07, 0x28, 0xed, 0x87, 0x4e, 0xe0, 0x29, 0x83, 0xc2, 0x94, 0x43, 0x5d, 0x3c, 0x16 }
+#define NIST_AESGCM_128_PLAIN_TEXT { 0xec, 0xaf, 0xe9, 0x6c, 0x67, 0xa1, 0x64, 0x67, 0x44, 0xf1, 0xc8, 0x91, 0xf5, 0xe6, 0x94, 0x27 }
+#define NIST_AESGCM_128_CIPHER { 0x55, 0x2e, 0xbe, 0x01, 0x2e, 0x7b, 0xcf, 0x90, 0xfc, 0xef, 0x71, 0x2f, 0x83, 0x44, 0xe8, 0xf1 }
+#define NIST_AESGCM_128_MAC { 0xec, 0xaa, 0xe9, 0xfc, 0x68, 0x27, 0x6a, 0x45, 0xab, 0x0c, 0xa3, 0xcb, 0x9d, 0xd9, 0x53, 0x9f }
+
+#define NIST_AESGCM_192_KEY { 0x0c, 0x44, 0xd6, 0xc9, 0x28, 0xee, 0x11, 0x2c, 0xe6, 0x65, 0xfe, 0x54, 0x7e, 0xbd, 0x38, 0x72, \
+ 0x98, 0xa9, 0x54, 0xb4, 0x62, 0xf6, 0x95, 0xd8 }
+#define NIST_AESGCM_192_IV { 0x18, 0xb8, 0xf3, 0x20, 0xfe, 0xf4, 0xae, 0x8c, 0xcb, 0xe8, 0xf9, 0x52 }
+#define NIST_AESGCM_192_ADATA { 0x73, 0x41, 0xd4, 0x3f, 0x98, 0xcf, 0x38, 0x82, 0x21, 0x18, 0x09, 0x41, 0x97, 0x03, 0x76, 0xe8 }
+#define NIST_AESGCM_192_PLAIN_TEXT { 0x96, 0xad, 0x07, 0xf9, 0xb6, 0x28, 0xb6, 0x52, 0xcf, 0x86, 0xcb, 0x73, 0x17, 0x88, 0x6f, 0x51 }
+#define NIST_AESGCM_192_CIPHER { 0xa6, 0x64, 0x07, 0x81, 0x33, 0x40, 0x5e, 0xb9, 0x09, 0x4d, 0x36, 0xf7, 0xe0, 0x70, 0x19, 0x1f }
+#define NIST_AESGCM_192_MAC { 0xe8, 0xf9, 0xc3, 0x17, 0x84, 0x7c, 0xe3, 0xf3, 0xc2, 0x39, 0x94, 0xa4, 0x02, 0xf0, 0x65, 0x81 }
+
+#define NIST_AESGCM_256_KEY { 0x54, 0xe3, 0x52, 0xea, 0x1d, 0x84, 0xbf, 0xe6, 0x4a, 0x10, 0x11, 0x09, 0x61, 0x11, 0xfb, 0xe7, \
+ 0x66, 0x8a, 0xd2, 0x20, 0x3d, 0x90, 0x2a, 0x01, 0x45, 0x8c, 0x3b, 0xbd, 0x85, 0xbf, 0xce, 0x14 }
+#define NIST_AESGCM_256_IV { 0xdf, 0x7c, 0x3b, 0xca, 0x00, 0x39, 0x6d, 0x0c, 0x01, 0x84, 0x95, 0xd9 }
+#define NIST_AESGCM_256_ADATA { 0x7e, 0x96, 0x8d, 0x71, 0xb5, 0x0c, 0x1f, 0x11, 0xfd, 0x00, 0x1f, 0x3f, 0xef, 0x49, 0xd0, 0x45 }
+#define NIST_AESGCM_256_PLAIN_TEXT { 0x85, 0xfc, 0x3d, 0xfa, 0xd9, 0xb5, 0xa8, 0xd3, 0x25, 0x8e, 0x4f, 0xc4, 0x45, 0x71, 0xbd, 0x3b }
+#define NIST_AESGCM_256_CIPHER { 0x42, 0x6e, 0x0e, 0xfc, 0x69, 0x3b, 0x7b, 0xe1, 0xf3, 0x01, 0x8d, 0xb7, 0xdd, 0xbb, 0x7e, 0x4d }
+#define NIST_AESGCM_256_MAC { 0xee, 0x82, 0x57, 0x79, 0x5b, 0xe6, 0xa1, 0x16, 0x4d, 0x7e, 0x1d, 0x2d, 0x6c, 0xac, 0x77, 0xa7 }
+
+
+/* NIST HASH */
+#define NIST_SHA_MSG_SIZE 16
+
+#define NIST_SHA_1_MSG { 0x35, 0x52, 0x69, 0x4c, 0xdf, 0x66, 0x3f, 0xd9, 0x4b, 0x22, 0x47, 0x47, 0xac, 0x40, 0x6a, 0xaf }
+#define NIST_SHA_1_MD { 0xa1, 0x50, 0xde, 0x92, 0x74, 0x54, 0x20, 0x2d, 0x94, 0xe6, 0x56, 0xde, 0x4c, 0x7c, 0x0c, 0xa6, \
+ 0x91, 0xde, 0x95, 0x5d }
+
+#define NIST_SHA_256_MSG { 0x0a, 0x27, 0x84, 0x7c, 0xdc, 0x98, 0xbd, 0x6f, 0x62, 0x22, 0x0b, 0x04, 0x6e, 0xdd, 0x76, 0x2b }
+#define NIST_SHA_256_MD { 0x80, 0xc2, 0x5e, 0xc1, 0x60, 0x05, 0x87, 0xe7, 0xf2, 0x8b, 0x18, 0xb1, 0xb1, 0x8e, 0x3c, 0xdc, \
+ 0x89, 0x92, 0x8e, 0x39, 0xca, 0xb3, 0xbc, 0x25, 0xe4, 0xd4, 0xa4, 0xc1, 0x39, 0xbc, 0xed, 0xc4 }
+
+#define NIST_SHA_512_MSG { 0xcd, 0x67, 0xbd, 0x40, 0x54, 0xaa, 0xa3, 0xba, 0xa0, 0xdb, 0x17, 0x8c, 0xe2, 0x32, 0xfd, 0x5a }
+#define NIST_SHA_512_MD { 0x0d, 0x85, 0x21, 0xf8, 0xf2, 0xf3, 0x90, 0x03, 0x32, 0xd1, 0xa1, 0xa5, 0x5c, 0x60, 0xba, 0x81, \
+ 0xd0, 0x4d, 0x28, 0xdf, 0xe8, 0xc5, 0x04, 0xb6, 0x32, 0x8a, 0xe7, 0x87, 0x92, 0x5f, 0xe0, 0x18, \
+ 0x8f, 0x2b, 0xa9, 0x1c, 0x3a, 0x9f, 0x0c, 0x16, 0x53, 0xc4, 0xbf, 0x0a, 0xda, 0x35, 0x64, 0x55, \
+ 0xea, 0x36, 0xfd, 0x31, 0xf8, 0xe7, 0x3e, 0x39, 0x51, 0xca, 0xd4, 0xeb, 0xba, 0x8c, 0x6e, 0x04 }
+
+
+/* NIST HMAC */
+#define NIST_HMAC_MSG_SIZE 128
+
+#define NIST_HMAC_SHA1_KEY_SIZE 10
+#define NIST_HMAC_SHA1_KEY { 0x59, 0x78, 0x59, 0x28, 0xd7, 0x25, 0x16, 0xe3, 0x12, 0x72 }
+#define NIST_HMAC_SHA1_MSG { 0xa3, 0xce, 0x88, 0x99, 0xdf, 0x10, 0x22, 0xe8, 0xd2, 0xd5, 0x39, 0xb4, 0x7b, 0xf0, 0xe3, 0x09, \
+ 0xc6, 0x6f, 0x84, 0x09, 0x5e, 0x21, 0x43, 0x8e, 0xc3, 0x55, 0xbf, 0x11, 0x9c, 0xe5, 0xfd, 0xcb, \
+ 0x4e, 0x73, 0xa6, 0x19, 0xcd, 0xf3, 0x6f, 0x25, 0xb3, 0x69, 0xd8, 0xc3, 0x8f, 0xf4, 0x19, 0x99, \
+ 0x7f, 0x0c, 0x59, 0x83, 0x01, 0x08, 0x22, 0x36, 0x06, 0xe3, 0x12, 0x23, 0x48, 0x3f, 0xd3, 0x9e, \
+ 0xde, 0xaa, 0x4d, 0x3f, 0x0d, 0x21, 0x19, 0x88, 0x62, 0xd2, 0x39, 0xc9, 0xfd, 0x26, 0x07, 0x41, \
+ 0x30, 0xff, 0x6c, 0x86, 0x49, 0x3f, 0x52, 0x27, 0xab, 0x89, 0x5c, 0x8f, 0x24, 0x4b, 0xd4, 0x2c, \
+ 0x7a, 0xfc, 0xe5, 0xd1, 0x47, 0xa2, 0x0a, 0x59, 0x07, 0x98, 0xc6, 0x8e, 0x70, 0x8e, 0x96, 0x49, \
+ 0x02, 0xd1, 0x24, 0xda, 0xde, 0xcd, 0xbd, 0xa9, 0xdb, 0xd0, 0x05, 0x1e, 0xd7, 0x10, 0xe9, 0xbf }
+#define NIST_HMAC_SHA1_MD { 0x3c, 0x81, 0x62, 0x58, 0x9a, 0xaf, 0xae, 0xe0, 0x24, 0xfc, 0x9a, 0x5c, 0xa5, 0x0d, 0xd2, 0x33, \
+ 0x6f, 0xe3, 0xeb, 0x28 }
+
+#define NIST_HMAC_SHA256_KEY_SIZE 40
+#define NIST_HMAC_SHA256_KEY { 0x97, 0x79, 0xd9, 0x12, 0x06, 0x42, 0x79, 0x7f, 0x17, 0x47, 0x02, 0x5d, 0x5b, 0x22, 0xb7, 0xac, \
+ 0x60, 0x7c, 0xab, 0x08, 0xe1, 0x75, 0x8f, 0x2f, 0x3a, 0x46, 0xc8, 0xbe, 0x1e, 0x25, 0xc5, 0x3b, \
+ 0x8c, 0x6a, 0x8f, 0x58, 0xff, 0xef, 0xa1, 0x76 }
+#define NIST_HMAC_SHA256_MSG { 0xb1, 0x68, 0x9c, 0x25, 0x91, 0xea, 0xf3, 0xc9, 0xe6, 0x60, 0x70, 0xf8, 0xa7, 0x79, 0x54, 0xff, \
+ 0xb8, 0x17, 0x49, 0xf1, 0xb0, 0x03, 0x46, 0xf9, 0xdf, 0xe0, 0xb2, 0xee, 0x90, 0x5d, 0xcc, 0x28, \
+ 0x8b, 0xaf, 0x4a, 0x92, 0xde, 0x3f, 0x40, 0x01, 0xdd, 0x9f, 0x44, 0xc4, 0x68, 0xc3, 0xd0, 0x7d, \
+ 0x6c, 0x6e, 0xe8, 0x2f, 0xac, 0xea, 0xfc, 0x97, 0xc2, 0xfc, 0x0f, 0xc0, 0x60, 0x17, 0x19, 0xd2, \
+ 0xdc, 0xd0, 0xaa, 0x2a, 0xec, 0x92, 0xd1, 0xb0, 0xae, 0x93, 0x3c, 0x65, 0xeb, 0x06, 0xa0, 0x3c, \
+ 0x9c, 0x93, 0x5c, 0x2b, 0xad, 0x04, 0x59, 0x81, 0x02, 0x41, 0x34, 0x7a, 0xb8, 0x7e, 0x9f, 0x11, \
+ 0xad, 0xb3, 0x04, 0x15, 0x42, 0x4c, 0x6c, 0x7f, 0x5f, 0x22, 0xa0, 0x03, 0xb8, 0xab, 0x8d, 0xe5, \
+ 0x4f, 0x6d, 0xed, 0x0e, 0x3a, 0xb9, 0x24, 0x5f, 0xa7, 0x95, 0x68, 0x45, 0x1d, 0xfa, 0x25, 0x8e }
+#define NIST_HMAC_SHA256_MD { 0x76, 0x9f, 0x00, 0xd3, 0xe6, 0xa6, 0xcc, 0x1f, 0xb4, 0x26, 0xa1, 0x4a, 0x4f, 0x76, 0xc6, 0x46, \
+ 0x2e, 0x61, 0x49, 0x72, 0x6e, 0x0d, 0xee, 0x0e, 0xc0, 0xcf, 0x97, 0xa1, 0x66, 0x05, 0xac, 0x8b }
+
+#define NIST_HMAC_SHA512_KEY_SIZE 100
+#define NIST_HMAC_SHA512_KEY { 0x57, 0xc2, 0xeb, 0x67, 0x7b, 0x50, 0x93, 0xb9, 0xe8, 0x29, 0xea, 0x4b, 0xab, 0xb5, 0x0b, 0xde, \
+ 0x55, 0xd0, 0xad, 0x59, 0xfe, 0xc3, 0x4a, 0x61, 0x89, 0x73, 0x80, 0x2b, 0x2a, 0xd9, 0xb7, 0x8e, \
+ 0x26, 0xb2, 0x04, 0x5d, 0xda, 0x78, 0x4d, 0xf3, 0xff, 0x90, 0xae, 0x0f, 0x2c, 0xc5, 0x1c, 0xe3, \
+ 0x9c, 0xf5, 0x48, 0x67, 0x32, 0x0a, 0xc6, 0xf3, 0xba, 0x2c, 0x6f, 0x0d, 0x72, 0x36, 0x04, 0x80, \
+ 0xc9, 0x66, 0x14, 0xae, 0x66, 0x58, 0x1f, 0x26, 0x6c, 0x35, 0xfb, 0x79, 0xfd, 0x28, 0x77, 0x4a, \
+ 0xfd, 0x11, 0x3f, 0xa5, 0x18, 0x7e, 0xff, 0x92, 0x06, 0xd7, 0xcb, 0xe9, 0x0d, 0xd8, 0xbf, 0x67, \
+ 0xc8, 0x44, 0xe2, 0x02 }
+#define NIST_HMAC_SHA512_MSG { 0x24, 0x23, 0xdf, 0xf4, 0x8b, 0x31, 0x2b, 0xe8, 0x64, 0xcb, 0x34, 0x90, 0x64, 0x1f, 0x79, 0x3d, \
+ 0x2b, 0x9f, 0xb6, 0x8a, 0x77, 0x63, 0xb8, 0xe2, 0x98, 0xc8, 0x6f, 0x42, 0x24, 0x5e, 0x45, 0x40, \
+ 0xeb, 0x01, 0xae, 0x4d, 0x2d, 0x45, 0x00, 0x37, 0x0b, 0x18, 0x86, 0xf2, 0x3c, 0xa2, 0xcf, 0x97, \
+ 0x01, 0x70, 0x4c, 0xad, 0x5b, 0xd2, 0x1b, 0xa8, 0x7b, 0x81, 0x1d, 0xaf, 0x7a, 0x85, 0x4e, 0xa2, \
+ 0x4a, 0x56, 0x56, 0x5c, 0xed, 0x42, 0x5b, 0x35, 0xe4, 0x0e, 0x1a, 0xcb, 0xeb, 0xe0, 0x36, 0x03, \
+ 0xe3, 0x5d, 0xcf, 0x4a, 0x10, 0x0e, 0x57, 0x21, 0x84, 0x08, 0xa1, 0xd8, 0xdb, 0xcc, 0x3b, 0x99, \
+ 0x29, 0x6c, 0xfe, 0xa9, 0x31, 0xef, 0xe3, 0xeb, 0xd8, 0xf7, 0x19, 0xa6, 0xd9, 0xa1, 0x54, 0x87, \
+ 0xb9, 0xad, 0x67, 0xea, 0xfe, 0xdf, 0x15, 0x55, 0x9c, 0xa4, 0x24, 0x45, 0xb0, 0xf9, 0xb4, 0x2e }
+#define NIST_HMAC_SHA512_MD { 0x33, 0xc5, 0x11, 0xe9, 0xbc, 0x23, 0x07, 0xc6, 0x27, 0x58, 0xdf, 0x61, 0x12, 0x5a, 0x98, 0x0e, \
+ 0xe6, 0x4c, 0xef, 0xeb, 0xd9, 0x09, 0x31, 0xcb, 0x91, 0xc1, 0x37, 0x42, 0xd4, 0x71, 0x4c, 0x06, \
+ 0xde, 0x40, 0x03, 0xfa, 0xf3, 0xc4, 0x1c, 0x06, 0xae, 0xfc, 0x63, 0x8a, 0xd4, 0x7b, 0x21, 0x90, \
+ 0x6e, 0x6b, 0x10, 0x48, 0x16, 0xb7, 0x2d, 0xe6, 0x26, 0x9e, 0x04, 0x5a, 0x1f, 0x44, 0x29, 0xd4 }
+
diff --git a/drivers/staging/ccree/ssi_fips_ext.c b/drivers/staging/ccree/ssi_fips_ext.c
new file mode 100644
index 0000000..2ac432f
--- /dev/null
+++ b/drivers/staging/ccree/ssi_fips_ext.c
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2012-2017 ARM Limited or its affiliates.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**************************************************************
+This file defines the driver FIPS functions that should be
+implemented by the driver user. Current implementation is sample code only.
+***************************************************************/
+
+#include <linux/module.h>
+#include "ssi_fips_local.h"
+#include "ssi_driver.h"
+
+
+static bool tee_error;
+module_param(tee_error, bool, 0644);
+MODULE_PARM_DESC(tee_error, "Simulate TEE library failure flag: 0 - no error (default), 1 - TEE error occured ");
+
+static ssi_fips_state_t fips_state = CC_FIPS_STATE_NOT_SUPPORTED;
+static ssi_fips_error_t fips_error = CC_REE_FIPS_ERROR_OK;
+
+/*
+This function returns the FIPS REE state.
+The function should be implemented by the driver user, depends on where .
+the state value is stored.
+The reference code uses global variable.
+*/
+int ssi_fips_ext_get_state(ssi_fips_state_t *p_state)
+{
+ int rc = 0;
+
+ if (p_state == NULL) {
+ return -EINVAL;
+ }
+
+ *p_state = fips_state;
+
+ return rc;
+}
+
+/*
+This function returns the FIPS REE error.
+The function should be implemented by the driver user, depends on where .
+the error value is stored.
+The reference code uses global variable.
+*/
+int ssi_fips_ext_get_error(ssi_fips_error_t *p_err)
+{
+ int rc = 0;
+
+ if (p_err == NULL) {
+ return -EINVAL;
+ }
+
+ *p_err = fips_error;
+
+ return rc;
+}
+
+/*
+This function sets the FIPS REE state.
+The function should be implemented by the driver user, depends on where .
+the state value is stored.
+The reference code uses global variable.
+*/
+int ssi_fips_ext_set_state(ssi_fips_state_t state)
+{
+ fips_state = state;
+ return 0;
+}
+
+/*
+This function sets the FIPS REE error.
+The function should be implemented by the driver user, depends on where .
+the error value is stored.
+The reference code uses global variable.
+*/
+int ssi_fips_ext_set_error(ssi_fips_error_t err)
+{
+ fips_error = err;
+ return 0;
+}
+
+
diff --git a/drivers/staging/ccree/ssi_fips_ll.c b/drivers/staging/ccree/ssi_fips_ll.c
new file mode 100644
index 0000000..d573574
--- /dev/null
+++ b/drivers/staging/ccree/ssi_fips_ll.c
@@ -0,0 +1,1681 @@
+/*
+ * Copyright (C) 2012-2017 ARM Limited or its affiliates.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**************************************************************
+This file defines the driver FIPS Low Level implmentaion functions,
+that executes the KAT.
+***************************************************************/
+#include <linux/kernel.h>
+
+#include "ssi_driver.h"
+#include "ssi_fips_local.h"
+#include "ssi_fips_data.h"
+#include "cc_crypto_ctx.h"
+#include "ssi_hash.h"
+#include "ssi_request_mgr.h"
+
+
+static const uint32_t digest_len_init[] = {
+ 0x00000040, 0x00000000, 0x00000000, 0x00000000 };
+static const uint32_t sha1_init[] = {
+ SHA1_H4, SHA1_H3, SHA1_H2, SHA1_H1, SHA1_H0 };
+static const uint32_t sha256_init[] = {
+ SHA256_H7, SHA256_H6, SHA256_H5, SHA256_H4,
+ SHA256_H3, SHA256_H2, SHA256_H1, SHA256_H0 };
+#if (CC_SUPPORT_SHA > 256)
+static const uint32_t digest_len_sha512_init[] = {
+ 0x00000080, 0x00000000, 0x00000000, 0x00000000 };
+static const uint64_t sha512_init[] = {
+ SHA512_H7, SHA512_H6, SHA512_H5, SHA512_H4,
+ SHA512_H3, SHA512_H2, SHA512_H1, SHA512_H0 };
+#endif
+
+
+#define NIST_CIPHER_AES_MAX_VECTOR_SIZE 32
+
+struct fips_cipher_ctx {
+ uint8_t iv[CC_AES_IV_SIZE];
+ uint8_t key[AES_512_BIT_KEY_SIZE];
+ uint8_t din[NIST_CIPHER_AES_MAX_VECTOR_SIZE];
+ uint8_t dout[NIST_CIPHER_AES_MAX_VECTOR_SIZE];
+};
+
+typedef struct _FipsCipherData {
+ uint8_t isAes;
+ uint8_t key[AES_512_BIT_KEY_SIZE];
+ size_t keySize;
+ uint8_t iv[CC_AES_IV_SIZE];
+ enum drv_crypto_direction direction;
+ enum drv_cipher_mode oprMode;
+ uint8_t dataIn[NIST_CIPHER_AES_MAX_VECTOR_SIZE];
+ uint8_t dataOut[NIST_CIPHER_AES_MAX_VECTOR_SIZE];
+ size_t dataInSize;
+} FipsCipherData;
+
+
+struct fips_cmac_ctx {
+ uint8_t key[AES_256_BIT_KEY_SIZE];
+ uint8_t din[NIST_CIPHER_AES_MAX_VECTOR_SIZE];
+ uint8_t mac_res[CC_DIGEST_SIZE_MAX];
+};
+
+typedef struct _FipsCmacData {
+ enum drv_crypto_direction direction;
+ uint8_t key[AES_256_BIT_KEY_SIZE];
+ size_t key_size;
+ uint8_t data_in[NIST_CIPHER_AES_MAX_VECTOR_SIZE];
+ size_t data_in_size;
+ uint8_t mac_res[CC_DIGEST_SIZE_MAX];
+ size_t mac_res_size;
+} FipsCmacData;
+
+
+struct fips_hash_ctx {
+ uint8_t initial_digest[CC_DIGEST_SIZE_MAX];
+ uint8_t din[NIST_SHA_MSG_SIZE];
+ uint8_t mac_res[CC_DIGEST_SIZE_MAX];
+};
+
+typedef struct _FipsHashData {
+ enum drv_hash_mode hash_mode;
+ uint8_t data_in[NIST_SHA_MSG_SIZE];
+ size_t data_in_size;
+ uint8_t mac_res[CC_DIGEST_SIZE_MAX];
+} FipsHashData;
+
+
+/* note that the hmac key length must be equal or less than block size (block size is 64 up to sha256 and 128 for sha384/512) */
+struct fips_hmac_ctx {
+ uint8_t initial_digest[CC_DIGEST_SIZE_MAX];
+ uint8_t key[CC_HMAC_BLOCK_SIZE_MAX];
+ uint8_t k0[CC_HMAC_BLOCK_SIZE_MAX];
+ uint8_t digest_bytes_len[HASH_LEN_SIZE];
+ uint8_t tmp_digest[CC_DIGEST_SIZE_MAX];
+ uint8_t din[NIST_HMAC_MSG_SIZE];
+ uint8_t mac_res[CC_DIGEST_SIZE_MAX];
+};
+
+typedef struct _FipsHmacData {
+ enum drv_hash_mode hash_mode;
+ uint8_t key[CC_HMAC_BLOCK_SIZE_MAX];
+ size_t key_size;
+ uint8_t data_in[NIST_HMAC_MSG_SIZE];
+ size_t data_in_size;
+ uint8_t mac_res[CC_DIGEST_SIZE_MAX];
+} FipsHmacData;
+
+
+#define FIPS_CCM_B0_A0_ADATA_SIZE (NIST_AESCCM_IV_SIZE + NIST_AESCCM_IV_SIZE + NIST_AESCCM_ADATA_SIZE)
+
+struct fips_ccm_ctx {
+ uint8_t b0_a0_adata[FIPS_CCM_B0_A0_ADATA_SIZE];
+ uint8_t iv[NIST_AESCCM_IV_SIZE];
+ uint8_t ctr_cnt_0[NIST_AESCCM_IV_SIZE];
+ uint8_t key[CC_AES_KEY_SIZE_MAX];
+ uint8_t din[NIST_AESCCM_TEXT_SIZE];
+ uint8_t dout[NIST_AESCCM_TEXT_SIZE];
+ uint8_t mac_res[NIST_AESCCM_TAG_SIZE];
+};
+
+typedef struct _FipsCcmData {
+ enum drv_crypto_direction direction;
+ uint8_t key[CC_AES_KEY_SIZE_MAX];
+ size_t keySize;
+ uint8_t nonce[NIST_AESCCM_NONCE_SIZE];
+ uint8_t adata[NIST_AESCCM_ADATA_SIZE];
+ size_t adataSize;
+ uint8_t dataIn[NIST_AESCCM_TEXT_SIZE];
+ size_t dataInSize;
+ uint8_t dataOut[NIST_AESCCM_TEXT_SIZE];
+ uint8_t tagSize;
+ uint8_t macResOut[NIST_AESCCM_TAG_SIZE];
+} FipsCcmData;
+
+
+struct fips_gcm_ctx {
+ uint8_t adata[NIST_AESGCM_ADATA_SIZE];
+ uint8_t key[CC_AES_KEY_SIZE_MAX];
+ uint8_t hkey[CC_AES_KEY_SIZE_MAX];
+ uint8_t din[NIST_AESGCM_TEXT_SIZE];
+ uint8_t dout[NIST_AESGCM_TEXT_SIZE];
+ uint8_t mac_res[NIST_AESGCM_TAG_SIZE];
+ uint8_t len_block[AES_BLOCK_SIZE];
+ uint8_t iv_inc1[AES_BLOCK_SIZE];
+ uint8_t iv_inc2[AES_BLOCK_SIZE];
+};
+
+typedef struct _FipsGcmData {
+ enum drv_crypto_direction direction;
+ uint8_t key[CC_AES_KEY_SIZE_MAX];
+ size_t keySize;
+ uint8_t iv[NIST_AESGCM_IV_SIZE];
+ uint8_t adata[NIST_AESGCM_ADATA_SIZE];
+ size_t adataSize;
+ uint8_t dataIn[NIST_AESGCM_TEXT_SIZE];
+ size_t dataInSize;
+ uint8_t dataOut[NIST_AESGCM_TEXT_SIZE];
+ uint8_t tagSize;
+ uint8_t macResOut[NIST_AESGCM_TAG_SIZE];
+} FipsGcmData;
+
+
+typedef union _fips_ctx {
+ struct fips_cipher_ctx cipher;
+ struct fips_cmac_ctx cmac;
+ struct fips_hash_ctx hash;
+ struct fips_hmac_ctx hmac;
+ struct fips_ccm_ctx ccm;
+ struct fips_gcm_ctx gcm;
+} fips_ctx;
+
+
+/* test data tables */
+static const FipsCipherData FipsCipherDataTable[] = {
+ /* AES */
+ { 1, NIST_AES_128_KEY, CC_AES_128_BIT_KEY_SIZE, NIST_AES_ECB_IV, DRV_CRYPTO_DIRECTION_ENCRYPT, DRV_CIPHER_ECB, NIST_AES_PLAIN_DATA, NIST_AES_128_ECB_CIPHER, NIST_AES_VECTOR_SIZE },
+ { 1, NIST_AES_128_KEY, CC_AES_128_BIT_KEY_SIZE, NIST_AES_ECB_IV, DRV_CRYPTO_DIRECTION_DECRYPT, DRV_CIPHER_ECB, NIST_AES_128_ECB_CIPHER, NIST_AES_PLAIN_DATA, NIST_AES_VECTOR_SIZE },
+ { 1, NIST_AES_192_KEY, CC_AES_192_BIT_KEY_SIZE, NIST_AES_ECB_IV, DRV_CRYPTO_DIRECTION_ENCRYPT, DRV_CIPHER_ECB, NIST_AES_PLAIN_DATA, NIST_AES_192_ECB_CIPHER, NIST_AES_VECTOR_SIZE },
+ { 1, NIST_AES_192_KEY, CC_AES_192_BIT_KEY_SIZE, NIST_AES_ECB_IV, DRV_CRYPTO_DIRECTION_DECRYPT, DRV_CIPHER_ECB, NIST_AES_192_ECB_CIPHER, NIST_AES_PLAIN_DATA, NIST_AES_VECTOR_SIZE },
+ { 1, NIST_AES_256_KEY, CC_AES_256_BIT_KEY_SIZE, NIST_AES_ECB_IV, DRV_CRYPTO_DIRECTION_ENCRYPT, DRV_CIPHER_ECB, NIST_AES_PLAIN_DATA, NIST_AES_256_ECB_CIPHER, NIST_AES_VECTOR_SIZE },
+ { 1, NIST_AES_256_KEY, CC_AES_256_BIT_KEY_SIZE, NIST_AES_ECB_IV, DRV_CRYPTO_DIRECTION_DECRYPT, DRV_CIPHER_ECB, NIST_AES_256_ECB_CIPHER, NIST_AES_PLAIN_DATA, NIST_AES_VECTOR_SIZE },
+ { 1, NIST_AES_128_KEY, CC_AES_128_BIT_KEY_SIZE, NIST_AES_CBC_IV, DRV_CRYPTO_DIRECTION_ENCRYPT, DRV_CIPHER_CBC, NIST_AES_PLAIN_DATA, NIST_AES_128_CBC_CIPHER, NIST_AES_VECTOR_SIZE },
+ { 1, NIST_AES_128_KEY, CC_AES_128_BIT_KEY_SIZE, NIST_AES_CBC_IV, DRV_CRYPTO_DIRECTION_DECRYPT, DRV_CIPHER_CBC, NIST_AES_128_CBC_CIPHER, NIST_AES_PLAIN_DATA, NIST_AES_VECTOR_SIZE },
+ { 1, NIST_AES_192_KEY, CC_AES_192_BIT_KEY_SIZE, NIST_AES_CBC_IV, DRV_CRYPTO_DIRECTION_ENCRYPT, DRV_CIPHER_CBC, NIST_AES_PLAIN_DATA, NIST_AES_192_CBC_CIPHER, NIST_AES_VECTOR_SIZE },
+ { 1, NIST_AES_192_KEY, CC_AES_192_BIT_KEY_SIZE, NIST_AES_CBC_IV, DRV_CRYPTO_DIRECTION_DECRYPT, DRV_CIPHER_CBC, NIST_AES_192_CBC_CIPHER, NIST_AES_PLAIN_DATA, NIST_AES_VECTOR_SIZE },
+ { 1, NIST_AES_256_KEY, CC_AES_256_BIT_KEY_SIZE, NIST_AES_CBC_IV, DRV_CRYPTO_DIRECTION_ENCRYPT, DRV_CIPHER_CBC, NIST_AES_PLAIN_DATA, NIST_AES_256_CBC_CIPHER, NIST_AES_VECTOR_SIZE },
+ { 1, NIST_AES_256_KEY, CC_AES_256_BIT_KEY_SIZE, NIST_AES_CBC_IV, DRV_CRYPTO_DIRECTION_DECRYPT, DRV_CIPHER_CBC, NIST_AES_256_CBC_CIPHER, NIST_AES_PLAIN_DATA, NIST_AES_VECTOR_SIZE },
+ { 1, NIST_AES_128_KEY, CC_AES_128_BIT_KEY_SIZE, NIST_AES_OFB_IV, DRV_CRYPTO_DIRECTION_ENCRYPT, DRV_CIPHER_OFB, NIST_AES_PLAIN_DATA, NIST_AES_128_OFB_CIPHER, NIST_AES_VECTOR_SIZE },
+ { 1, NIST_AES_128_KEY, CC_AES_128_BIT_KEY_SIZE, NIST_AES_OFB_IV, DRV_CRYPTO_DIRECTION_ENCRYPT, DRV_CIPHER_OFB, NIST_AES_128_OFB_CIPHER, NIST_AES_PLAIN_DATA, NIST_AES_VECTOR_SIZE },
+ { 1, NIST_AES_192_KEY, CC_AES_192_BIT_KEY_SIZE, NIST_AES_OFB_IV, DRV_CRYPTO_DIRECTION_ENCRYPT, DRV_CIPHER_OFB, NIST_AES_PLAIN_DATA, NIST_AES_192_OFB_CIPHER, NIST_AES_VECTOR_SIZE },
+ { 1, NIST_AES_192_KEY, CC_AES_192_BIT_KEY_SIZE, NIST_AES_OFB_IV, DRV_CRYPTO_DIRECTION_DECRYPT, DRV_CIPHER_OFB, NIST_AES_192_OFB_CIPHER, NIST_AES_PLAIN_DATA, NIST_AES_VECTOR_SIZE },
+ { 1, NIST_AES_256_KEY, CC_AES_256_BIT_KEY_SIZE, NIST_AES_OFB_IV, DRV_CRYPTO_DIRECTION_ENCRYPT, DRV_CIPHER_OFB, NIST_AES_PLAIN_DATA, NIST_AES_256_OFB_CIPHER, NIST_AES_VECTOR_SIZE },
+ { 1, NIST_AES_256_KEY, CC_AES_256_BIT_KEY_SIZE, NIST_AES_OFB_IV, DRV_CRYPTO_DIRECTION_DECRYPT, DRV_CIPHER_OFB, NIST_AES_256_OFB_CIPHER, NIST_AES_PLAIN_DATA, NIST_AES_VECTOR_SIZE },
+ { 1, NIST_AES_128_KEY, CC_AES_128_BIT_KEY_SIZE, NIST_AES_CTR_IV, DRV_CRYPTO_DIRECTION_ENCRYPT, DRV_CIPHER_CTR, NIST_AES_PLAIN_DATA, NIST_AES_128_CTR_CIPHER, NIST_AES_VECTOR_SIZE },
+ { 1, NIST_AES_128_KEY, CC_AES_128_BIT_KEY_SIZE, NIST_AES_CTR_IV, DRV_CRYPTO_DIRECTION_DECRYPT, DRV_CIPHER_CTR, NIST_AES_128_CTR_CIPHER, NIST_AES_PLAIN_DATA, NIST_AES_VECTOR_SIZE },
+ { 1, NIST_AES_192_KEY, CC_AES_192_BIT_KEY_SIZE, NIST_AES_CTR_IV, DRV_CRYPTO_DIRECTION_ENCRYPT, DRV_CIPHER_CTR, NIST_AES_PLAIN_DATA, NIST_AES_192_CTR_CIPHER, NIST_AES_VECTOR_SIZE },
+ { 1, NIST_AES_192_KEY, CC_AES_192_BIT_KEY_SIZE, NIST_AES_CTR_IV, DRV_CRYPTO_DIRECTION_DECRYPT, DRV_CIPHER_CTR, NIST_AES_192_CTR_CIPHER, NIST_AES_PLAIN_DATA, NIST_AES_VECTOR_SIZE },
+ { 1, NIST_AES_256_KEY, CC_AES_256_BIT_KEY_SIZE, NIST_AES_CTR_IV, DRV_CRYPTO_DIRECTION_ENCRYPT, DRV_CIPHER_CTR, NIST_AES_PLAIN_DATA, NIST_AES_256_CTR_CIPHER, NIST_AES_VECTOR_SIZE },
+ { 1, NIST_AES_256_KEY, CC_AES_256_BIT_KEY_SIZE, NIST_AES_CTR_IV, DRV_CRYPTO_DIRECTION_DECRYPT, DRV_CIPHER_CTR, NIST_AES_256_CTR_CIPHER, NIST_AES_PLAIN_DATA, NIST_AES_VECTOR_SIZE },
+ { 1, RFC3962_AES_128_KEY, CC_AES_128_BIT_KEY_SIZE, RFC3962_AES_CBC_CTS_IV, DRV_CRYPTO_DIRECTION_ENCRYPT, DRV_CIPHER_CBC_CTS, RFC3962_AES_PLAIN_DATA, RFC3962_AES_128_CBC_CTS_CIPHER, RFC3962_AES_VECTOR_SIZE },
+ { 1, RFC3962_AES_128_KEY, CC_AES_128_BIT_KEY_SIZE, RFC3962_AES_CBC_CTS_IV, DRV_CRYPTO_DIRECTION_DECRYPT, DRV_CIPHER_CBC_CTS, RFC3962_AES_128_CBC_CTS_CIPHER, RFC3962_AES_PLAIN_DATA, RFC3962_AES_VECTOR_SIZE },
+ { 1, NIST_AES_256_XTS_KEY, CC_AES_256_BIT_KEY_SIZE, NIST_AES_256_XTS_IV, DRV_CRYPTO_DIRECTION_ENCRYPT, DRV_CIPHER_XTS, NIST_AES_256_XTS_PLAIN, NIST_AES_256_XTS_CIPHER, NIST_AES_256_XTS_VECTOR_SIZE },
+ { 1, NIST_AES_256_XTS_KEY, CC_AES_256_BIT_KEY_SIZE, NIST_AES_256_XTS_IV, DRV_CRYPTO_DIRECTION_DECRYPT, DRV_CIPHER_XTS, NIST_AES_256_XTS_CIPHER, NIST_AES_256_XTS_PLAIN, NIST_AES_256_XTS_VECTOR_SIZE },
+#if (CC_SUPPORT_SHA > 256)
+ { 1, NIST_AES_512_XTS_KEY, 2*CC_AES_256_BIT_KEY_SIZE, NIST_AES_512_XTS_IV, DRV_CRYPTO_DIRECTION_ENCRYPT, DRV_CIPHER_XTS, NIST_AES_512_XTS_PLAIN, NIST_AES_512_XTS_CIPHER, NIST_AES_512_XTS_VECTOR_SIZE },
+ { 1, NIST_AES_512_XTS_KEY, 2*CC_AES_256_BIT_KEY_SIZE, NIST_AES_512_XTS_IV, DRV_CRYPTO_DIRECTION_DECRYPT, DRV_CIPHER_XTS, NIST_AES_512_XTS_CIPHER, NIST_AES_512_XTS_PLAIN, NIST_AES_512_XTS_VECTOR_SIZE },
+#endif
+ /* DES */
+ { 0, NIST_TDES_ECB3_KEY, CC_DRV_DES_TRIPLE_KEY_SIZE, NIST_TDES_ECB_IV, DRV_CRYPTO_DIRECTION_ENCRYPT, DRV_CIPHER_ECB, NIST_TDES_ECB3_PLAIN_DATA, NIST_TDES_ECB3_CIPHER, NIST_TDES_VECTOR_SIZE },
+ { 0, NIST_TDES_ECB3_KEY, CC_DRV_DES_TRIPLE_KEY_SIZE, NIST_TDES_ECB_IV, DRV_CRYPTO_DIRECTION_DECRYPT, DRV_CIPHER_ECB, NIST_TDES_ECB3_CIPHER, NIST_TDES_ECB3_PLAIN_DATA, NIST_TDES_VECTOR_SIZE },
+ { 0, NIST_TDES_CBC3_KEY, CC_DRV_DES_TRIPLE_KEY_SIZE, NIST_TDES_CBC3_IV, DRV_CRYPTO_DIRECTION_ENCRYPT, DRV_CIPHER_CBC, NIST_TDES_CBC3_PLAIN_DATA, NIST_TDES_CBC3_CIPHER, NIST_TDES_VECTOR_SIZE },
+ { 0, NIST_TDES_CBC3_KEY, CC_DRV_DES_TRIPLE_KEY_SIZE, NIST_TDES_CBC3_IV, DRV_CRYPTO_DIRECTION_DECRYPT, DRV_CIPHER_CBC, NIST_TDES_CBC3_CIPHER, NIST_TDES_CBC3_PLAIN_DATA, NIST_TDES_VECTOR_SIZE },
+};
+#define FIPS_CIPHER_NUM_OF_TESTS (sizeof(FipsCipherDataTable) / sizeof(FipsCipherData))
+
+static const FipsCmacData FipsCmacDataTable[] = {
+ { DRV_CRYPTO_DIRECTION_ENCRYPT, NIST_AES_128_CMAC_KEY, AES_128_BIT_KEY_SIZE, NIST_AES_128_CMAC_PLAIN_DATA, NIST_AES_128_CMAC_VECTOR_SIZE, NIST_AES_128_CMAC_MAC, NIST_AES_128_CMAC_OUTPUT_SIZE },
+ { DRV_CRYPTO_DIRECTION_ENCRYPT, NIST_AES_192_CMAC_KEY, AES_192_BIT_KEY_SIZE, NIST_AES_192_CMAC_PLAIN_DATA, NIST_AES_192_CMAC_VECTOR_SIZE, NIST_AES_192_CMAC_MAC, NIST_AES_192_CMAC_OUTPUT_SIZE },
+ { DRV_CRYPTO_DIRECTION_ENCRYPT, NIST_AES_256_CMAC_KEY, AES_256_BIT_KEY_SIZE, NIST_AES_256_CMAC_PLAIN_DATA, NIST_AES_256_CMAC_VECTOR_SIZE, NIST_AES_256_CMAC_MAC, NIST_AES_256_CMAC_OUTPUT_SIZE },
+};
+#define FIPS_CMAC_NUM_OF_TESTS (sizeof(FipsCmacDataTable) / sizeof(FipsCmacData))
+
+static const FipsHashData FipsHashDataTable[] = {
+ { DRV_HASH_SHA1, NIST_SHA_1_MSG, NIST_SHA_MSG_SIZE, NIST_SHA_1_MD },
+ { DRV_HASH_SHA256, NIST_SHA_256_MSG, NIST_SHA_MSG_SIZE, NIST_SHA_256_MD },
+#if (CC_SUPPORT_SHA > 256)
+// { DRV_HASH_SHA512, NIST_SHA_512_MSG, NIST_SHA_MSG_SIZE, NIST_SHA_512_MD },
+#endif
+};
+#define FIPS_HASH_NUM_OF_TESTS (sizeof(FipsHashDataTable) / sizeof(FipsHashData))
+
+static const FipsHmacData FipsHmacDataTable[] = {
+ { DRV_HASH_SHA1, NIST_HMAC_SHA1_KEY, NIST_HMAC_SHA1_KEY_SIZE, NIST_HMAC_SHA1_MSG, NIST_HMAC_MSG_SIZE, NIST_HMAC_SHA1_MD },
+ { DRV_HASH_SHA256, NIST_HMAC_SHA256_KEY, NIST_HMAC_SHA256_KEY_SIZE, NIST_HMAC_SHA256_MSG, NIST_HMAC_MSG_SIZE, NIST_HMAC_SHA256_MD },
+#if (CC_SUPPORT_SHA > 256)
+// { DRV_HASH_SHA512, NIST_HMAC_SHA512_KEY, NIST_HMAC_SHA512_KEY_SIZE, NIST_HMAC_SHA512_MSG, NIST_HMAC_MSG_SIZE, NIST_HMAC_SHA512_MD },
+#endif
+};
+#define FIPS_HMAC_NUM_OF_TESTS (sizeof(FipsHmacDataTable) / sizeof(FipsHmacData))
+
+static const FipsCcmData FipsCcmDataTable[] = {
+ { DRV_CRYPTO_DIRECTION_ENCRYPT, NIST_AESCCM_128_KEY, NIST_AESCCM_128_BIT_KEY_SIZE, NIST_AESCCM_128_NONCE, NIST_AESCCM_128_ADATA, NIST_AESCCM_ADATA_SIZE, NIST_AESCCM_128_PLAIN_TEXT, NIST_AESCCM_TEXT_SIZE, NIST_AESCCM_128_CIPHER, NIST_AESCCM_TAG_SIZE, NIST_AESCCM_128_MAC },
+ { DRV_CRYPTO_DIRECTION_DECRYPT, NIST_AESCCM_128_KEY, NIST_AESCCM_128_BIT_KEY_SIZE, NIST_AESCCM_128_NONCE, NIST_AESCCM_128_ADATA, NIST_AESCCM_ADATA_SIZE, NIST_AESCCM_128_CIPHER, NIST_AESCCM_TEXT_SIZE, NIST_AESCCM_128_PLAIN_TEXT, NIST_AESCCM_TAG_SIZE, NIST_AESCCM_128_MAC },
+ { DRV_CRYPTO_DIRECTION_ENCRYPT, NIST_AESCCM_192_KEY, NIST_AESCCM_192_BIT_KEY_SIZE, NIST_AESCCM_192_NONCE, NIST_AESCCM_192_ADATA, NIST_AESCCM_ADATA_SIZE, NIST_AESCCM_192_PLAIN_TEXT, NIST_AESCCM_TEXT_SIZE, NIST_AESCCM_192_CIPHER, NIST_AESCCM_TAG_SIZE, NIST_AESCCM_192_MAC },
+ { DRV_CRYPTO_DIRECTION_DECRYPT, NIST_AESCCM_192_KEY, NIST_AESCCM_192_BIT_KEY_SIZE, NIST_AESCCM_192_NONCE, NIST_AESCCM_192_ADATA, NIST_AESCCM_ADATA_SIZE, NIST_AESCCM_192_CIPHER, NIST_AESCCM_TEXT_SIZE, NIST_AESCCM_192_PLAIN_TEXT, NIST_AESCCM_TAG_SIZE, NIST_AESCCM_192_MAC },
+ { DRV_CRYPTO_DIRECTION_ENCRYPT, NIST_AESCCM_256_KEY, NIST_AESCCM_256_BIT_KEY_SIZE, NIST_AESCCM_256_NONCE, NIST_AESCCM_256_ADATA, NIST_AESCCM_ADATA_SIZE, NIST_AESCCM_256_PLAIN_TEXT, NIST_AESCCM_TEXT_SIZE, NIST_AESCCM_256_CIPHER, NIST_AESCCM_TAG_SIZE, NIST_AESCCM_256_MAC },
+ { DRV_CRYPTO_DIRECTION_DECRYPT, NIST_AESCCM_256_KEY, NIST_AESCCM_256_BIT_KEY_SIZE, NIST_AESCCM_256_NONCE, NIST_AESCCM_256_ADATA, NIST_AESCCM_ADATA_SIZE, NIST_AESCCM_256_CIPHER, NIST_AESCCM_TEXT_SIZE, NIST_AESCCM_256_PLAIN_TEXT, NIST_AESCCM_TAG_SIZE, NIST_AESCCM_256_MAC },
+};
+#define FIPS_CCM_NUM_OF_TESTS (sizeof(FipsCcmDataTable) / sizeof(FipsCcmData))
+
+static const FipsGcmData FipsGcmDataTable[] = {
+ { DRV_CRYPTO_DIRECTION_ENCRYPT, NIST_AESGCM_128_KEY, NIST_AESGCM_128_BIT_KEY_SIZE, NIST_AESGCM_128_IV, NIST_AESGCM_128_ADATA, NIST_AESGCM_ADATA_SIZE, NIST_AESGCM_128_PLAIN_TEXT, NIST_AESGCM_TEXT_SIZE, NIST_AESGCM_128_CIPHER, NIST_AESGCM_TAG_SIZE, NIST_AESGCM_128_MAC },
+ { DRV_CRYPTO_DIRECTION_DECRYPT, NIST_AESGCM_128_KEY, NIST_AESGCM_128_BIT_KEY_SIZE, NIST_AESGCM_128_IV, NIST_AESGCM_128_ADATA, NIST_AESGCM_ADATA_SIZE, NIST_AESGCM_128_CIPHER, NIST_AESGCM_TEXT_SIZE, NIST_AESGCM_128_PLAIN_TEXT, NIST_AESGCM_TAG_SIZE, NIST_AESGCM_128_MAC },
+ { DRV_CRYPTO_DIRECTION_ENCRYPT, NIST_AESGCM_192_KEY, NIST_AESGCM_192_BIT_KEY_SIZE, NIST_AESGCM_192_IV, NIST_AESGCM_192_ADATA, NIST_AESGCM_ADATA_SIZE, NIST_AESGCM_192_PLAIN_TEXT, NIST_AESGCM_TEXT_SIZE, NIST_AESGCM_192_CIPHER, NIST_AESGCM_TAG_SIZE, NIST_AESGCM_192_MAC },
+ { DRV_CRYPTO_DIRECTION_DECRYPT, NIST_AESGCM_192_KEY, NIST_AESGCM_192_BIT_KEY_SIZE, NIST_AESGCM_192_IV, NIST_AESGCM_192_ADATA, NIST_AESGCM_ADATA_SIZE, NIST_AESGCM_192_CIPHER, NIST_AESGCM_TEXT_SIZE, NIST_AESGCM_192_PLAIN_TEXT, NIST_AESGCM_TAG_SIZE, NIST_AESGCM_192_MAC },
+ { DRV_CRYPTO_DIRECTION_ENCRYPT, NIST_AESGCM_256_KEY, NIST_AESGCM_256_BIT_KEY_SIZE, NIST_AESGCM_256_IV, NIST_AESGCM_256_ADATA, NIST_AESGCM_ADATA_SIZE, NIST_AESGCM_256_PLAIN_TEXT, NIST_AESGCM_TEXT_SIZE, NIST_AESGCM_256_CIPHER, NIST_AESGCM_TAG_SIZE, NIST_AESGCM_256_MAC },
+ { DRV_CRYPTO_DIRECTION_DECRYPT, NIST_AESGCM_256_KEY, NIST_AESGCM_256_BIT_KEY_SIZE, NIST_AESGCM_256_IV, NIST_AESGCM_256_ADATA, NIST_AESGCM_ADATA_SIZE, NIST_AESGCM_256_CIPHER, NIST_AESGCM_TEXT_SIZE, NIST_AESGCM_256_PLAIN_TEXT, NIST_AESGCM_TAG_SIZE, NIST_AESGCM_256_MAC },
+};
+#define FIPS_GCM_NUM_OF_TESTS (sizeof(FipsGcmDataTable) / sizeof(FipsGcmData))
+
+
+static inline ssi_fips_error_t
+FIPS_CipherToFipsError(enum drv_cipher_mode mode, bool is_aes)
+{
+ switch (mode)
+ {
+ case DRV_CIPHER_ECB:
+ return is_aes ? CC_REE_FIPS_ERROR_AES_ECB_PUT : CC_REE_FIPS_ERROR_DES_ECB_PUT ;
+ case DRV_CIPHER_CBC:
+ return is_aes ? CC_REE_FIPS_ERROR_AES_CBC_PUT : CC_REE_FIPS_ERROR_DES_CBC_PUT ;
+ case DRV_CIPHER_OFB:
+ return CC_REE_FIPS_ERROR_AES_OFB_PUT;
+ case DRV_CIPHER_CTR:
+ return CC_REE_FIPS_ERROR_AES_CTR_PUT;
+ case DRV_CIPHER_CBC_CTS:
+ return CC_REE_FIPS_ERROR_AES_CBC_CTS_PUT;
+ case DRV_CIPHER_XTS:
+ return CC_REE_FIPS_ERROR_AES_XTS_PUT;
+ default:
+ return CC_REE_FIPS_ERROR_GENERAL;
+ }
+
+ return CC_REE_FIPS_ERROR_GENERAL;
+}
+
+
+static inline int
+ssi_cipher_fips_run_test(struct ssi_drvdata *drvdata,
+ bool is_aes,
+ int cipher_mode,
+ int direction,
+ dma_addr_t key_dma_addr,
+ size_t key_len,
+ dma_addr_t iv_dma_addr,
+ size_t iv_len,
+ dma_addr_t din_dma_addr,
+ dma_addr_t dout_dma_addr,
+ size_t data_size)
+{
+ /* max number of descriptors used for the flow */
+ #define FIPS_CIPHER_MAX_SEQ_LEN 6
+
+ int rc;
+ struct ssi_crypto_req ssi_req = {0};
+ HwDesc_s desc[FIPS_CIPHER_MAX_SEQ_LEN];
+ int idx = 0;
+ int s_flow_mode = is_aes ? S_DIN_to_AES : S_DIN_to_DES;
+
+ /* create setup descriptors */
+ switch (cipher_mode) {
+ case DRV_CIPHER_CBC:
+ case DRV_CIPHER_CBC_CTS:
+ case DRV_CIPHER_CTR:
+ case DRV_CIPHER_OFB:
+ /* Load cipher state */
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_DIN_TYPE(&desc[idx], DMA_DLLI,
+ iv_dma_addr, iv_len, NS_BIT);
+ HW_DESC_SET_CIPHER_CONFIG0(&desc[idx], direction);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], s_flow_mode);
+ HW_DESC_SET_CIPHER_MODE(&desc[idx], cipher_mode);
+ if ((cipher_mode == DRV_CIPHER_CTR) ||
+ (cipher_mode == DRV_CIPHER_OFB) ) {
+ HW_DESC_SET_SETUP_MODE(&desc[idx], SETUP_LOAD_STATE1);
+ } else {
+ HW_DESC_SET_SETUP_MODE(&desc[idx], SETUP_LOAD_STATE0);
+ }
+ idx++;
+ /*FALLTHROUGH*/
+ case DRV_CIPHER_ECB:
+ /* Load key */
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_CIPHER_MODE(&desc[idx], cipher_mode);
+ HW_DESC_SET_CIPHER_CONFIG0(&desc[idx], direction);
+ if (is_aes) {
+ HW_DESC_SET_DIN_TYPE(&desc[idx], DMA_DLLI,
+ key_dma_addr,
+ ((key_len == 24) ? AES_MAX_KEY_SIZE : key_len),
+ NS_BIT);
+ HW_DESC_SET_KEY_SIZE_AES(&desc[idx], key_len);
+ } else {/*des*/
+ HW_DESC_SET_DIN_TYPE(&desc[idx], DMA_DLLI,
+ key_dma_addr, key_len,
+ NS_BIT);
+ HW_DESC_SET_KEY_SIZE_DES(&desc[idx], key_len);
+ }
+ HW_DESC_SET_FLOW_MODE(&desc[idx], s_flow_mode);
+ HW_DESC_SET_SETUP_MODE(&desc[idx], SETUP_LOAD_KEY0);
+ idx++;
+ break;
+ case DRV_CIPHER_XTS:
+ /* Load AES key */
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_CIPHER_MODE(&desc[idx], cipher_mode);
+ HW_DESC_SET_CIPHER_CONFIG0(&desc[idx], direction);
+ HW_DESC_SET_DIN_TYPE(&desc[idx], DMA_DLLI,
+ key_dma_addr, key_len/2, NS_BIT);
+ HW_DESC_SET_KEY_SIZE_AES(&desc[idx], key_len/2);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], s_flow_mode);
+ HW_DESC_SET_SETUP_MODE(&desc[idx], SETUP_LOAD_KEY0);
+ idx++;
+
+ /* load XEX key */
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_CIPHER_MODE(&desc[idx], cipher_mode);
+ HW_DESC_SET_CIPHER_CONFIG0(&desc[idx], direction);
+ HW_DESC_SET_DIN_TYPE(&desc[idx], DMA_DLLI,
+ (key_dma_addr+key_len/2), key_len/2, NS_BIT);
+ HW_DESC_SET_XEX_DATA_UNIT_SIZE(&desc[idx], data_size);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], s_flow_mode);
+ HW_DESC_SET_KEY_SIZE_AES(&desc[idx], key_len/2);
+ HW_DESC_SET_SETUP_MODE(&desc[idx], SETUP_LOAD_XEX_KEY);
+ idx++;
+
+ /* Set state */
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_SETUP_MODE(&desc[idx], SETUP_LOAD_STATE1);
+ HW_DESC_SET_CIPHER_MODE(&desc[idx], cipher_mode);
+ HW_DESC_SET_CIPHER_CONFIG0(&desc[idx], direction);
+ HW_DESC_SET_KEY_SIZE_AES(&desc[idx], key_len/2);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], s_flow_mode);
+ HW_DESC_SET_DIN_TYPE(&desc[idx], DMA_DLLI,
+ iv_dma_addr, CC_AES_BLOCK_SIZE, NS_BIT);
+ idx++;
+ break;
+ default:
+ FIPS_LOG("Unsupported cipher mode (%d)\n", cipher_mode);
+ BUG();
+ }
+
+ /* create data descriptor */
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_DIN_TYPE(&desc[idx], DMA_DLLI, din_dma_addr, data_size, NS_BIT);
+ HW_DESC_SET_DOUT_DLLI(&desc[idx], dout_dma_addr, data_size, NS_BIT, 0);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], is_aes ? DIN_AES_DOUT : DIN_DES_DOUT);
+ idx++;
+
+ /* perform the operation - Lock HW and push sequence */
+ BUG_ON(idx > FIPS_CIPHER_MAX_SEQ_LEN);
+ rc = send_request(drvdata, &ssi_req, desc, idx, false);
+
+ // send_request returns error just in some corner cases which should not appear in this flow.
+ return rc;
+}
+
+
+ssi_fips_error_t
+ssi_cipher_fips_power_up_tests(struct ssi_drvdata *drvdata, void *cpu_addr_buffer, dma_addr_t dma_coherent_buffer)
+{
+ ssi_fips_error_t error = CC_REE_FIPS_ERROR_OK;
+ size_t i;
+ struct fips_cipher_ctx *virt_ctx = (struct fips_cipher_ctx *)cpu_addr_buffer;
+
+ /* set the phisical pointers for iv, key, din, dout */
+ dma_addr_t iv_dma_addr = dma_coherent_buffer + offsetof(struct fips_cipher_ctx, iv);
+ dma_addr_t key_dma_addr = dma_coherent_buffer + offsetof(struct fips_cipher_ctx, key);
+ dma_addr_t din_dma_addr = dma_coherent_buffer + offsetof(struct fips_cipher_ctx, din);
+ dma_addr_t dout_dma_addr = dma_coherent_buffer + offsetof(struct fips_cipher_ctx, dout);
+
+ for (i = 0; i < FIPS_CIPHER_NUM_OF_TESTS; ++i)
+ {
+ FipsCipherData *cipherData = (FipsCipherData*)&FipsCipherDataTable[i];
+ int rc = 0;
+ size_t iv_size = cipherData->isAes ? NIST_AES_IV_SIZE : NIST_TDES_IV_SIZE ;
+
+ memset(cpu_addr_buffer, 0, sizeof(struct fips_cipher_ctx));
+
+ /* copy into the allocated buffer */
+ memcpy(virt_ctx->iv, cipherData->iv, iv_size);
+ memcpy(virt_ctx->key, cipherData->key, cipherData->keySize);
+ memcpy(virt_ctx->din, cipherData->dataIn, cipherData->dataInSize);
+
+ FIPS_DBG("ssi_cipher_fips_run_test - (i = %d) \n", i);
+ rc = ssi_cipher_fips_run_test(drvdata,
+ cipherData->isAes,
+ cipherData->oprMode,
+ cipherData->direction,
+ key_dma_addr,
+ cipherData->keySize,
+ iv_dma_addr,
+ iv_size,
+ din_dma_addr,
+ dout_dma_addr,
+ cipherData->dataInSize);
+ if (rc != 0)
+ {
+ FIPS_LOG("ssi_cipher_fips_run_test %d returned error - rc = %d \n", i, rc);
+ error = FIPS_CipherToFipsError(cipherData->oprMode, cipherData->isAes);
+ break;
+ }
+
+ /* compare actual dout to expected */
+ if (memcmp(virt_ctx->dout, cipherData->dataOut, cipherData->dataInSize) != 0)
+ {
+ FIPS_LOG("dout comparison error %d - oprMode=%d, isAes=%d\n", i, cipherData->oprMode, cipherData->isAes);
+ FIPS_LOG(" i expected received \n");
+ FIPS_LOG(" i 0x%08x 0x%08x (size=%d) \n", (size_t)cipherData->dataOut, (size_t)virt_ctx->dout, cipherData->dataInSize);
+ for (i = 0; i < cipherData->dataInSize; ++i)
+ {
+ FIPS_LOG(" %d 0x%02x 0x%02x \n", i, cipherData->dataOut[i], virt_ctx->dout[i]);
+ }
+
+ error = FIPS_CipherToFipsError(cipherData->oprMode, cipherData->isAes);
+ break;
+ }
+ }
+
+ return error;
+}
+
+
+static inline int
+ssi_cmac_fips_run_test(struct ssi_drvdata *drvdata,
+ dma_addr_t key_dma_addr,
+ size_t key_len,
+ dma_addr_t din_dma_addr,
+ size_t din_len,
+ dma_addr_t digest_dma_addr,
+ size_t digest_len)
+{
+ /* max number of descriptors used for the flow */
+ #define FIPS_CMAC_MAX_SEQ_LEN 4
+
+ int rc;
+ struct ssi_crypto_req ssi_req = {0};
+ HwDesc_s desc[FIPS_CMAC_MAX_SEQ_LEN];
+ int idx = 0;
+
+ /* Setup CMAC Key */
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_DIN_TYPE(&desc[idx], DMA_DLLI, key_dma_addr,
+ ((key_len == 24) ? AES_MAX_KEY_SIZE : key_len), NS_BIT);
+ HW_DESC_SET_SETUP_MODE(&desc[idx], SETUP_LOAD_KEY0);
+ HW_DESC_SET_CIPHER_MODE(&desc[idx], DRV_CIPHER_CMAC);
+ HW_DESC_SET_CIPHER_CONFIG0(&desc[idx], DESC_DIRECTION_ENCRYPT_ENCRYPT);
+ HW_DESC_SET_KEY_SIZE_AES(&desc[idx], key_len);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], S_DIN_to_AES);
+ idx++;
+
+ /* Load MAC state */
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_DIN_TYPE(&desc[idx], DMA_DLLI, digest_dma_addr, CC_AES_BLOCK_SIZE, NS_BIT);
+ HW_DESC_SET_SETUP_MODE(&desc[idx], SETUP_LOAD_STATE0);
+ HW_DESC_SET_CIPHER_MODE(&desc[idx], DRV_CIPHER_CMAC);
+ HW_DESC_SET_CIPHER_CONFIG0(&desc[idx], DESC_DIRECTION_ENCRYPT_ENCRYPT);
+ HW_DESC_SET_KEY_SIZE_AES(&desc[idx], key_len);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], S_DIN_to_AES);
+ idx++;
+
+
+ //ssi_hash_create_data_desc(state, ctx, DIN_AES_DOUT, desc, false, &idx);
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_DIN_TYPE(&desc[idx], DMA_DLLI,
+ din_dma_addr,
+ din_len, NS_BIT);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], DIN_AES_DOUT);
+ idx++;
+
+ /* Get final MAC result */
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_DOUT_DLLI(&desc[idx], digest_dma_addr, CC_AES_BLOCK_SIZE, NS_BIT, 0);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], S_AES_to_DOUT);
+ HW_DESC_SET_SETUP_MODE(&desc[idx], SETUP_WRITE_STATE0);
+ HW_DESC_SET_CIPHER_CONFIG0(&desc[idx], DESC_DIRECTION_ENCRYPT_ENCRYPT);
+ HW_DESC_SET_CIPHER_MODE(&desc[idx], DRV_CIPHER_CMAC);
+ idx++;
+
+ /* perform the operation - Lock HW and push sequence */
+ BUG_ON(idx > FIPS_CMAC_MAX_SEQ_LEN);
+ rc = send_request(drvdata, &ssi_req, desc, idx, false);
+
+ // send_request returns error just in some corner cases which should not appear in this flow.
+ return rc;
+}
+
+ssi_fips_error_t
+ssi_cmac_fips_power_up_tests(struct ssi_drvdata *drvdata, void *cpu_addr_buffer, dma_addr_t dma_coherent_buffer)
+{
+ ssi_fips_error_t error = CC_REE_FIPS_ERROR_OK;
+ size_t i;
+ struct fips_cmac_ctx *virt_ctx = (struct fips_cmac_ctx *)cpu_addr_buffer;
+
+ /* set the phisical pointers for key, din, dout */
+ dma_addr_t key_dma_addr = dma_coherent_buffer + offsetof(struct fips_cmac_ctx, key);
+ dma_addr_t din_dma_addr = dma_coherent_buffer + offsetof(struct fips_cmac_ctx, din);
+ dma_addr_t mac_res_dma_addr = dma_coherent_buffer + offsetof(struct fips_cmac_ctx, mac_res);
+
+ for (i = 0; i < FIPS_CMAC_NUM_OF_TESTS; ++i)
+ {
+ FipsCmacData *cmac_data = (FipsCmacData*)&FipsCmacDataTable[i];
+ int rc = 0;
+
+ memset(cpu_addr_buffer, 0, sizeof(struct fips_cmac_ctx));
+
+ /* copy into the allocated buffer */
+ memcpy(virt_ctx->key, cmac_data->key, cmac_data->key_size);
+ memcpy(virt_ctx->din, cmac_data->data_in, cmac_data->data_in_size);
+
+ BUG_ON(cmac_data->direction != DRV_CRYPTO_DIRECTION_ENCRYPT);
+
+ FIPS_DBG("ssi_cmac_fips_run_test - (i = %d) \n", i);
+ rc = ssi_cmac_fips_run_test(drvdata,
+ key_dma_addr,
+ cmac_data->key_size,
+ din_dma_addr,
+ cmac_data->data_in_size,
+ mac_res_dma_addr,
+ cmac_data->mac_res_size);
+ if (rc != 0)
+ {
+ FIPS_LOG("ssi_cmac_fips_run_test %d returned error - rc = %d \n", i, rc);
+ error = CC_REE_FIPS_ERROR_AES_CMAC_PUT;
+ break;
+ }
+
+ /* compare actual mac result to expected */
+ if (memcmp(virt_ctx->mac_res, cmac_data->mac_res, cmac_data->mac_res_size) != 0)
+ {
+ FIPS_LOG("comparison error %d - digest_size=%d \n", i, cmac_data->mac_res_size);
+ FIPS_LOG(" i expected received \n");
+ FIPS_LOG(" i 0x%08x 0x%08x \n", (size_t)cmac_data->mac_res, (size_t)virt_ctx->mac_res);
+ for (i = 0; i < cmac_data->mac_res_size; ++i)
+ {
+ FIPS_LOG(" %d 0x%02x 0x%02x \n", i, cmac_data->mac_res[i], virt_ctx->mac_res[i]);
+ }
+
+ error = CC_REE_FIPS_ERROR_AES_CMAC_PUT;
+ break;
+ }
+ }
+
+ return error;
+}
+
+
+static inline ssi_fips_error_t
+FIPS_HashToFipsError(enum drv_hash_mode hash_mode)
+{
+ switch (hash_mode) {
+ case DRV_HASH_SHA1:
+ return CC_REE_FIPS_ERROR_SHA1_PUT;
+ case DRV_HASH_SHA256:
+ return CC_REE_FIPS_ERROR_SHA256_PUT;
+#if (CC_SUPPORT_SHA > 256)
+ case DRV_HASH_SHA512:
+ return CC_REE_FIPS_ERROR_SHA512_PUT;
+#endif
+ default:
+ return CC_REE_FIPS_ERROR_GENERAL;
+ }
+
+ return CC_REE_FIPS_ERROR_GENERAL;
+}
+
+static inline int
+ssi_hash_fips_run_test(struct ssi_drvdata *drvdata,
+ dma_addr_t initial_digest_dma_addr,
+ dma_addr_t din_dma_addr,
+ size_t data_in_size,
+ dma_addr_t mac_res_dma_addr,
+ enum drv_hash_mode hash_mode,
+ enum drv_hash_hw_mode hw_mode,
+ int digest_size,
+ int inter_digestsize)
+{
+ /* max number of descriptors used for the flow */
+ #define FIPS_HASH_MAX_SEQ_LEN 4
+
+ int rc;
+ struct ssi_crypto_req ssi_req = {0};
+ HwDesc_s desc[FIPS_HASH_MAX_SEQ_LEN];
+ int idx = 0;
+
+ /* Load initial digest */
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_CIPHER_MODE(&desc[idx], hw_mode);
+ HW_DESC_SET_DIN_TYPE(&desc[idx], DMA_DLLI, initial_digest_dma_addr, inter_digestsize, NS_BIT);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], S_DIN_to_HASH);
+ HW_DESC_SET_SETUP_MODE(&desc[idx], SETUP_LOAD_STATE0);
+ idx++;
+
+ /* Load the hash current length */
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_CIPHER_MODE(&desc[idx], hw_mode);
+ HW_DESC_SET_DIN_CONST(&desc[idx], 0, HASH_LEN_SIZE);
+ HW_DESC_SET_CIPHER_CONFIG1(&desc[idx], HASH_PADDING_ENABLED);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], S_DIN_to_HASH);
+ HW_DESC_SET_SETUP_MODE(&desc[idx], SETUP_LOAD_KEY0);
+ idx++;
+
+ /* data descriptor */
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_DIN_TYPE(&desc[idx], DMA_DLLI, din_dma_addr, data_in_size, NS_BIT);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], DIN_HASH);
+ idx++;
+
+ /* Get final MAC result */
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_CIPHER_MODE(&desc[idx], hw_mode);
+ HW_DESC_SET_DOUT_DLLI(&desc[idx], mac_res_dma_addr, digest_size, NS_BIT, 0);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], S_HASH_to_DOUT);
+ HW_DESC_SET_SETUP_MODE(&desc[idx], SETUP_WRITE_STATE0);
+ HW_DESC_SET_CIPHER_CONFIG1(&desc[idx], HASH_PADDING_DISABLED);
+ if (unlikely((hash_mode == DRV_HASH_MD5) ||
+ (hash_mode == DRV_HASH_SHA384) ||
+ (hash_mode == DRV_HASH_SHA512))) {
+ HW_DESC_SET_BYTES_SWAP(&desc[idx], 1);
+ } else {
+ HW_DESC_SET_CIPHER_CONFIG0(&desc[idx], HASH_DIGEST_RESULT_LITTLE_ENDIAN);
+ }
+ idx++;
+
+ /* perform the operation - Lock HW and push sequence */
+ BUG_ON(idx > FIPS_HASH_MAX_SEQ_LEN);
+ rc = send_request(drvdata, &ssi_req, desc, idx, false);
+
+ return rc;
+}
+
+ssi_fips_error_t
+ssi_hash_fips_power_up_tests(struct ssi_drvdata *drvdata, void *cpu_addr_buffer, dma_addr_t dma_coherent_buffer)
+{
+ ssi_fips_error_t error = CC_REE_FIPS_ERROR_OK;
+ size_t i;
+ struct fips_hash_ctx *virt_ctx = (struct fips_hash_ctx *)cpu_addr_buffer;
+
+ /* set the phisical pointers for initial_digest, din, mac_res */
+ dma_addr_t initial_digest_dma_addr = dma_coherent_buffer + offsetof(struct fips_hash_ctx, initial_digest);
+ dma_addr_t din_dma_addr = dma_coherent_buffer + offsetof(struct fips_hash_ctx, din);
+ dma_addr_t mac_res_dma_addr = dma_coherent_buffer + offsetof(struct fips_hash_ctx, mac_res);
+
+ for (i = 0; i < FIPS_HASH_NUM_OF_TESTS; ++i)
+ {
+ FipsHashData *hash_data = (FipsHashData*)&FipsHashDataTable[i];
+ int rc = 0;
+ enum drv_hash_hw_mode hw_mode = 0;
+ int digest_size = 0;
+ int inter_digestsize = 0;
+
+ memset(cpu_addr_buffer, 0, sizeof(struct fips_hash_ctx));
+
+ switch (hash_data->hash_mode) {
+ case DRV_HASH_SHA1:
+ hw_mode = DRV_HASH_HW_SHA1;
+ digest_size = CC_SHA1_DIGEST_SIZE;
+ inter_digestsize = CC_SHA1_DIGEST_SIZE;
+ /* copy the initial digest into the allocated cache coherent buffer */
+ memcpy(virt_ctx->initial_digest, (void*)sha1_init, CC_SHA1_DIGEST_SIZE);
+ break;
+ case DRV_HASH_SHA256:
+ hw_mode = DRV_HASH_HW_SHA256;
+ digest_size = CC_SHA256_DIGEST_SIZE;
+ inter_digestsize = CC_SHA256_DIGEST_SIZE;
+ memcpy(virt_ctx->initial_digest, (void*)sha256_init, CC_SHA256_DIGEST_SIZE);
+ break;
+#if (CC_SUPPORT_SHA > 256)
+ case DRV_HASH_SHA512:
+ hw_mode = DRV_HASH_HW_SHA512;
+ digest_size = CC_SHA512_DIGEST_SIZE;
+ inter_digestsize = CC_SHA512_DIGEST_SIZE;
+ memcpy(virt_ctx->initial_digest, (void*)sha512_init, CC_SHA512_DIGEST_SIZE);
+ break;
+#endif
+ default:
+ error = FIPS_HashToFipsError(hash_data->hash_mode);
+ break;
+ }
+
+ /* copy the din data into the allocated buffer */
+ memcpy(virt_ctx->din, hash_data->data_in, hash_data->data_in_size);
+
+ /* run the test on HW */
+ FIPS_DBG("ssi_hash_fips_run_test - (i = %d) \n", i);
+ rc = ssi_hash_fips_run_test(drvdata,
+ initial_digest_dma_addr,
+ din_dma_addr,
+ hash_data->data_in_size,
+ mac_res_dma_addr,
+ hash_data->hash_mode,
+ hw_mode,
+ digest_size,
+ inter_digestsize);
+ if (rc != 0)
+ {
+ FIPS_LOG("ssi_hash_fips_run_test %d returned error - rc = %d \n", i, rc);
+ error = FIPS_HashToFipsError(hash_data->hash_mode);
+ break;
+ }
+
+ /* compare actual mac result to expected */
+ if (memcmp(virt_ctx->mac_res, hash_data->mac_res, digest_size) != 0)
+ {
+ FIPS_LOG("comparison error %d - hash_mode=%d digest_size=%d \n", i, hash_data->hash_mode, digest_size);
+ FIPS_LOG(" i expected received \n");
+ FIPS_LOG(" i 0x%08x 0x%08x \n", (size_t)hash_data->mac_res, (size_t)virt_ctx->mac_res);
+ for (i = 0; i < digest_size; ++i)
+ {
+ FIPS_LOG(" %d 0x%02x 0x%02x \n", i, hash_data->mac_res[i], virt_ctx->mac_res[i]);
+ }
+
+ error = FIPS_HashToFipsError(hash_data->hash_mode);
+ break;
+ }
+ }
+
+ return error;
+}
+
+
+static inline ssi_fips_error_t
+FIPS_HmacToFipsError(enum drv_hash_mode hash_mode)
+{
+ switch (hash_mode) {
+ case DRV_HASH_SHA1:
+ return CC_REE_FIPS_ERROR_HMAC_SHA1_PUT;
+ case DRV_HASH_SHA256:
+ return CC_REE_FIPS_ERROR_HMAC_SHA256_PUT;
+#if (CC_SUPPORT_SHA > 256)
+ case DRV_HASH_SHA512:
+ return CC_REE_FIPS_ERROR_HMAC_SHA512_PUT;
+#endif
+ default:
+ return CC_REE_FIPS_ERROR_GENERAL;
+ }
+
+ return CC_REE_FIPS_ERROR_GENERAL;
+}
+
+static inline int
+ssi_hmac_fips_run_test(struct ssi_drvdata *drvdata,
+ dma_addr_t initial_digest_dma_addr,
+ dma_addr_t key_dma_addr,
+ size_t key_size,
+ dma_addr_t din_dma_addr,
+ size_t data_in_size,
+ dma_addr_t mac_res_dma_addr,
+ enum drv_hash_mode hash_mode,
+ enum drv_hash_hw_mode hw_mode,
+ size_t digest_size,
+ size_t inter_digestsize,
+ size_t block_size,
+ dma_addr_t k0_dma_addr,
+ dma_addr_t tmp_digest_dma_addr,
+ dma_addr_t digest_bytes_len_dma_addr)
+{
+ /* The implemented flow is not the same as the one implemented in ssi_hash.c (setkey + digest flows).
+ In this flow, there is no need to store and reload some of the intermidiate results. */
+
+ /* max number of descriptors used for the flow */
+ #define FIPS_HMAC_MAX_SEQ_LEN 12
+
+ int rc;
+ struct ssi_crypto_req ssi_req = {0};
+ HwDesc_s desc[FIPS_HMAC_MAX_SEQ_LEN];
+ int idx = 0;
+ int i;
+ /* calc the hash opad first and ipad only afterwards (unlike the flow in ssi_hash.c) */
+ unsigned int hmacPadConst[2] = { HMAC_OPAD_CONST, HMAC_IPAD_CONST };
+
+ // assume (key_size <= block_size)
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_DIN_TYPE(&desc[idx], DMA_DLLI, key_dma_addr, key_size, NS_BIT);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], BYPASS);
+ HW_DESC_SET_DOUT_DLLI(&desc[idx], k0_dma_addr, key_size, NS_BIT, 0);
+ idx++;
+
+ // if needed, append Key with zeros to create K0
+ if ((block_size - key_size) != 0) {
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_DIN_CONST(&desc[idx], 0, (block_size - key_size));
+ HW_DESC_SET_FLOW_MODE(&desc[idx], BYPASS);
+ HW_DESC_SET_DOUT_DLLI(&desc[idx],
+ (k0_dma_addr + key_size), (block_size - key_size),
+ NS_BIT, 0);
+ idx++;
+ }
+
+ BUG_ON(idx > FIPS_HMAC_MAX_SEQ_LEN);
+ rc = send_request(drvdata, &ssi_req, desc, idx, 0);
+ if (unlikely(rc != 0)) {
+ SSI_LOG_ERR("send_request() failed (rc=%d)\n", rc);
+ return rc;
+ }
+ idx = 0;
+
+ /* calc derived HMAC key */
+ for (i = 0; i < 2; i++) {
+ /* Load hash initial state */
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_CIPHER_MODE(&desc[idx], hw_mode);
+ HW_DESC_SET_DIN_TYPE(&desc[idx], DMA_DLLI, initial_digest_dma_addr, inter_digestsize, NS_BIT);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], S_DIN_to_HASH);
+ HW_DESC_SET_SETUP_MODE(&desc[idx], SETUP_LOAD_STATE0);
+ idx++;
+
+
+ /* Load the hash current length*/
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_CIPHER_MODE(&desc[idx], hw_mode);
+ HW_DESC_SET_DIN_CONST(&desc[idx], 0, HASH_LEN_SIZE);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], S_DIN_to_HASH);
+ HW_DESC_SET_SETUP_MODE(&desc[idx], SETUP_LOAD_KEY0);
+ idx++;
+
+ /* Prepare opad/ipad key */
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_XOR_VAL(&desc[idx], hmacPadConst[i]);
+ HW_DESC_SET_CIPHER_MODE(&desc[idx], hw_mode);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], S_DIN_to_HASH);
+ HW_DESC_SET_SETUP_MODE(&desc[idx], SETUP_LOAD_STATE1);
+ idx++;
+
+ /* Perform HASH update */
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_DIN_TYPE(&desc[idx], DMA_DLLI,
+ k0_dma_addr,
+ block_size, NS_BIT);
+ HW_DESC_SET_CIPHER_MODE(&desc[idx],hw_mode);
+ HW_DESC_SET_XOR_ACTIVE(&desc[idx]);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], DIN_HASH);
+ idx++;
+
+ if (i == 0) {
+ /* First iteration - calc H(K0^opad) into tmp_digest_dma_addr */
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_CIPHER_MODE(&desc[idx], hw_mode);
+ HW_DESC_SET_DOUT_DLLI(&desc[idx],
+ tmp_digest_dma_addr,
+ inter_digestsize,
+ NS_BIT, 0);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], S_HASH_to_DOUT);
+ HW_DESC_SET_SETUP_MODE(&desc[idx], SETUP_WRITE_STATE0);
+ idx++;
+
+ // is this needed?? or continue with current descriptors??
+ BUG_ON(idx > FIPS_HMAC_MAX_SEQ_LEN);
+ rc = send_request(drvdata, &ssi_req, desc, idx, 0);
+ if (unlikely(rc != 0)) {
+ SSI_LOG_ERR("send_request() failed (rc=%d)\n", rc);
+ return rc;
+ }
+ idx = 0;
+ }
+ }
+
+ /* data descriptor */
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_DIN_TYPE(&desc[idx], DMA_DLLI,
+ din_dma_addr, data_in_size,
+ NS_BIT);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], DIN_HASH);
+ idx++;
+
+ /* HW last hash block padding (aka. "DO_PAD") */
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_CIPHER_MODE(&desc[idx], hw_mode);
+ HW_DESC_SET_DOUT_DLLI(&desc[idx], k0_dma_addr, HASH_LEN_SIZE, NS_BIT, 0);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], S_HASH_to_DOUT);
+ HW_DESC_SET_SETUP_MODE(&desc[idx], SETUP_WRITE_STATE1);
+ HW_DESC_SET_CIPHER_DO(&desc[idx], DO_PAD);
+ idx++;
+
+ /* store the hash digest result in the context */
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_CIPHER_MODE(&desc[idx], hw_mode);
+ HW_DESC_SET_DOUT_DLLI(&desc[idx], k0_dma_addr, digest_size, NS_BIT, 0);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], S_HASH_to_DOUT);
+ if (unlikely((hash_mode == DRV_HASH_MD5) ||
+ (hash_mode == DRV_HASH_SHA384) ||
+ (hash_mode == DRV_HASH_SHA512))) {
+ HW_DESC_SET_BYTES_SWAP(&desc[idx], 1);
+ } else {
+ HW_DESC_SET_CIPHER_CONFIG0(&desc[idx], HASH_DIGEST_RESULT_LITTLE_ENDIAN);
+ }
+ HW_DESC_SET_SETUP_MODE(&desc[idx], SETUP_WRITE_STATE0);
+ idx++;
+
+ /* at this point:
+ tmp_digest = H(o_key_pad)
+ k0 = H(i_key_pad || m)
+ */
+
+ /* Loading hash opad xor key state */
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_CIPHER_MODE(&desc[idx], hw_mode);
+ HW_DESC_SET_DIN_TYPE(&desc[idx], DMA_DLLI, tmp_digest_dma_addr, inter_digestsize, NS_BIT);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], S_DIN_to_HASH);
+ HW_DESC_SET_SETUP_MODE(&desc[idx], SETUP_LOAD_STATE0);
+ idx++;
+
+ /* Load the hash current length */
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_CIPHER_MODE(&desc[idx], hw_mode);
+ HW_DESC_SET_DIN_TYPE(&desc[idx], DMA_DLLI, digest_bytes_len_dma_addr, HASH_LEN_SIZE, NS_BIT);
+ HW_DESC_SET_CIPHER_CONFIG1(&desc[idx], HASH_PADDING_ENABLED);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], S_DIN_to_HASH);
+ HW_DESC_SET_SETUP_MODE(&desc[idx], SETUP_LOAD_KEY0);
+ idx++;
+
+ /* Memory Barrier: wait for IPAD/OPAD axi write to complete */
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_DIN_NO_DMA(&desc[idx], 0, 0xfffff0);
+ HW_DESC_SET_DOUT_NO_DMA(&desc[idx], 0, 0, 1);
+ idx++;
+
+ /* Perform HASH update */
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_DIN_TYPE(&desc[idx], DMA_DLLI, k0_dma_addr, digest_size, NS_BIT);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], DIN_HASH);
+ idx++;
+
+
+ /* Get final MAC result */
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_CIPHER_MODE(&desc[idx], hw_mode);
+ HW_DESC_SET_DOUT_DLLI(&desc[idx], mac_res_dma_addr, digest_size, NS_BIT, 0);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], S_HASH_to_DOUT);
+ HW_DESC_SET_SETUP_MODE(&desc[idx], SETUP_WRITE_STATE0);
+ HW_DESC_SET_CIPHER_CONFIG1(&desc[idx], HASH_PADDING_DISABLED);
+ if (unlikely((hash_mode == DRV_HASH_MD5) ||
+ (hash_mode == DRV_HASH_SHA384) ||
+ (hash_mode == DRV_HASH_SHA512))) {
+ HW_DESC_SET_BYTES_SWAP(&desc[idx], 1);
+ } else {
+ HW_DESC_SET_CIPHER_CONFIG0(&desc[idx], HASH_DIGEST_RESULT_LITTLE_ENDIAN);
+ }
+ idx++;
+
+ /* perform the operation - Lock HW and push sequence */
+ BUG_ON(idx > FIPS_HMAC_MAX_SEQ_LEN);
+ rc = send_request(drvdata, &ssi_req, desc, idx, false);
+
+ return rc;
+}
+
+ssi_fips_error_t
+ssi_hmac_fips_power_up_tests(struct ssi_drvdata *drvdata, void *cpu_addr_buffer, dma_addr_t dma_coherent_buffer)
+{
+ ssi_fips_error_t error = CC_REE_FIPS_ERROR_OK;
+ size_t i;
+ struct fips_hmac_ctx *virt_ctx = (struct fips_hmac_ctx *)cpu_addr_buffer;
+
+ /* set the phisical pointers */
+ dma_addr_t initial_digest_dma_addr = dma_coherent_buffer + offsetof(struct fips_hmac_ctx, initial_digest);
+ dma_addr_t key_dma_addr = dma_coherent_buffer + offsetof(struct fips_hmac_ctx, key);
+ dma_addr_t k0_dma_addr = dma_coherent_buffer + offsetof(struct fips_hmac_ctx, k0);
+ dma_addr_t tmp_digest_dma_addr = dma_coherent_buffer + offsetof(struct fips_hmac_ctx, tmp_digest);
+ dma_addr_t digest_bytes_len_dma_addr = dma_coherent_buffer + offsetof(struct fips_hmac_ctx, digest_bytes_len);
+ dma_addr_t din_dma_addr = dma_coherent_buffer + offsetof(struct fips_hmac_ctx, din);
+ dma_addr_t mac_res_dma_addr = dma_coherent_buffer + offsetof(struct fips_hmac_ctx, mac_res);
+
+ for (i = 0; i < FIPS_HMAC_NUM_OF_TESTS; ++i)
+ {
+ FipsHmacData *hmac_data = (FipsHmacData*)&FipsHmacDataTable[i];
+ int rc = 0;
+ enum drv_hash_hw_mode hw_mode = 0;
+ int digest_size = 0;
+ int block_size = 0;
+ int inter_digestsize = 0;
+
+ memset(cpu_addr_buffer, 0, sizeof(struct fips_hmac_ctx));
+
+ switch (hmac_data->hash_mode) {
+ case DRV_HASH_SHA1:
+ hw_mode = DRV_HASH_HW_SHA1;
+ digest_size = CC_SHA1_DIGEST_SIZE;
+ block_size = CC_SHA1_BLOCK_SIZE;
+ inter_digestsize = CC_SHA1_DIGEST_SIZE;
+ memcpy(virt_ctx->initial_digest, (void*)sha1_init, CC_SHA1_DIGEST_SIZE);
+ memcpy(virt_ctx->digest_bytes_len, digest_len_init, HASH_LEN_SIZE);
+ break;
+ case DRV_HASH_SHA256:
+ hw_mode = DRV_HASH_HW_SHA256;
+ digest_size = CC_SHA256_DIGEST_SIZE;
+ block_size = CC_SHA256_BLOCK_SIZE;
+ inter_digestsize = CC_SHA256_DIGEST_SIZE;
+ memcpy(virt_ctx->initial_digest, (void*)sha256_init, CC_SHA256_DIGEST_SIZE);
+ memcpy(virt_ctx->digest_bytes_len, digest_len_init, HASH_LEN_SIZE);
+ break;
+#if (CC_SUPPORT_SHA > 256)
+ case DRV_HASH_SHA512:
+ hw_mode = DRV_HASH_HW_SHA512;
+ digest_size = CC_SHA512_DIGEST_SIZE;
+ block_size = CC_SHA512_BLOCK_SIZE;
+ inter_digestsize = CC_SHA512_DIGEST_SIZE;
+ memcpy(virt_ctx->initial_digest, (void*)sha512_init, CC_SHA512_DIGEST_SIZE);
+ memcpy(virt_ctx->digest_bytes_len, digest_len_sha512_init, HASH_LEN_SIZE);
+ break;
+#endif
+ default:
+ error = FIPS_HmacToFipsError(hmac_data->hash_mode);
+ break;
+ }
+
+ /* copy into the allocated buffer */
+ memcpy(virt_ctx->key, hmac_data->key, hmac_data->key_size);
+ memcpy(virt_ctx->din, hmac_data->data_in, hmac_data->data_in_size);
+
+ /* run the test on HW */
+ FIPS_DBG("ssi_hmac_fips_run_test - (i = %d) \n", i);
+ rc = ssi_hmac_fips_run_test(drvdata,
+ initial_digest_dma_addr,
+ key_dma_addr,
+ hmac_data->key_size,
+ din_dma_addr,
+ hmac_data->data_in_size,
+ mac_res_dma_addr,
+ hmac_data->hash_mode,
+ hw_mode,
+ digest_size,
+ inter_digestsize,
+ block_size,
+ k0_dma_addr,
+ tmp_digest_dma_addr,
+ digest_bytes_len_dma_addr);
+ if (rc != 0)
+ {
+ FIPS_LOG("ssi_hmac_fips_run_test %d returned error - rc = %d \n", i, rc);
+ error = FIPS_HmacToFipsError(hmac_data->hash_mode);
+ break;
+ }
+
+ /* compare actual mac result to expected */
+ if (memcmp(virt_ctx->mac_res, hmac_data->mac_res, digest_size) != 0)
+ {
+ FIPS_LOG("comparison error %d - hash_mode=%d digest_size=%d \n", i, hmac_data->hash_mode, digest_size);
+ FIPS_LOG(" i expected received \n");
+ FIPS_LOG(" i 0x%08x 0x%08x \n", (size_t)hmac_data->mac_res, (size_t)virt_ctx->mac_res);
+ for (i = 0; i < digest_size; ++i)
+ {
+ FIPS_LOG(" %d 0x%02x 0x%02x \n", i, hmac_data->mac_res[i], virt_ctx->mac_res[i]);
+ }
+
+ error = FIPS_HmacToFipsError(hmac_data->hash_mode);
+ break;
+ }
+ }
+
+ return error;
+}
+
+
+static inline int
+ssi_ccm_fips_run_test(struct ssi_drvdata *drvdata,
+ enum drv_crypto_direction direction,
+ dma_addr_t key_dma_addr,
+ size_t key_size,
+ dma_addr_t iv_dma_addr,
+ dma_addr_t ctr_cnt_0_dma_addr,
+ dma_addr_t b0_a0_adata_dma_addr,
+ size_t b0_a0_adata_size,
+ dma_addr_t din_dma_addr,
+ size_t din_size,
+ dma_addr_t dout_dma_addr,
+ dma_addr_t mac_res_dma_addr)
+{
+ /* max number of descriptors used for the flow */
+ #define FIPS_CCM_MAX_SEQ_LEN 10
+
+ int rc;
+ struct ssi_crypto_req ssi_req = {0};
+ HwDesc_s desc[FIPS_CCM_MAX_SEQ_LEN];
+ unsigned int idx = 0;
+ unsigned int cipher_flow_mode;
+
+ if (direction == DRV_CRYPTO_DIRECTION_DECRYPT) {
+ cipher_flow_mode = AES_to_HASH_and_DOUT;
+ } else { /* Encrypt */
+ cipher_flow_mode = AES_and_HASH;
+ }
+
+ /* load key */
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_CIPHER_MODE(&desc[idx], DRV_CIPHER_CTR);
+ HW_DESC_SET_DIN_TYPE(&desc[idx], DMA_DLLI, key_dma_addr,
+ ((key_size == NIST_AESCCM_192_BIT_KEY_SIZE) ? CC_AES_KEY_SIZE_MAX : key_size),
+ NS_BIT);
+ HW_DESC_SET_KEY_SIZE_AES(&desc[idx], key_size);
+ HW_DESC_SET_SETUP_MODE(&desc[idx], SETUP_LOAD_KEY0);
+ HW_DESC_SET_CIPHER_CONFIG0(&desc[idx], DESC_DIRECTION_ENCRYPT_ENCRYPT);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], S_DIN_to_AES);
+ idx++;
+
+ /* load ctr state */
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_CIPHER_MODE(&desc[idx], DRV_CIPHER_CTR);
+ HW_DESC_SET_KEY_SIZE_AES(&desc[idx], key_size);
+ HW_DESC_SET_DIN_TYPE(&desc[idx], DMA_DLLI,
+ iv_dma_addr, AES_BLOCK_SIZE,
+ NS_BIT);
+ HW_DESC_SET_CIPHER_CONFIG0(&desc[idx], DESC_DIRECTION_ENCRYPT_ENCRYPT);
+ HW_DESC_SET_SETUP_MODE(&desc[idx], SETUP_LOAD_STATE1);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], S_DIN_to_AES);
+ idx++;
+
+ /* load MAC key */
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_CIPHER_MODE(&desc[idx], DRV_CIPHER_CBC_MAC);
+ HW_DESC_SET_DIN_TYPE(&desc[idx], DMA_DLLI, key_dma_addr,
+ ((key_size == NIST_AESCCM_192_BIT_KEY_SIZE) ? CC_AES_KEY_SIZE_MAX : key_size),
+ NS_BIT);
+ HW_DESC_SET_KEY_SIZE_AES(&desc[idx], key_size);
+ HW_DESC_SET_SETUP_MODE(&desc[idx], SETUP_LOAD_KEY0);
+ HW_DESC_SET_CIPHER_CONFIG0(&desc[idx], DESC_DIRECTION_ENCRYPT_ENCRYPT);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], S_DIN_to_HASH);
+ HW_DESC_SET_AES_NOT_HASH_MODE(&desc[idx]);
+ idx++;
+
+ /* load MAC state */
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_CIPHER_MODE(&desc[idx], DRV_CIPHER_CBC_MAC);
+ HW_DESC_SET_KEY_SIZE_AES(&desc[idx], key_size);
+ HW_DESC_SET_DIN_TYPE(&desc[idx], DMA_DLLI, mac_res_dma_addr, NIST_AESCCM_TAG_SIZE, NS_BIT);
+ HW_DESC_SET_CIPHER_CONFIG0(&desc[idx], DESC_DIRECTION_ENCRYPT_ENCRYPT);
+ HW_DESC_SET_SETUP_MODE(&desc[idx], SETUP_LOAD_STATE0);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], S_DIN_to_HASH);
+ HW_DESC_SET_AES_NOT_HASH_MODE(&desc[idx]);
+ idx++;
+
+ /* prcess assoc data */
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_DIN_TYPE(&desc[idx], DMA_DLLI, b0_a0_adata_dma_addr, b0_a0_adata_size, NS_BIT);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], DIN_HASH);
+ idx++;
+
+ /* process the cipher */
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_DIN_TYPE(&desc[idx], DMA_DLLI, din_dma_addr, din_size, NS_BIT);
+ HW_DESC_SET_DOUT_DLLI(&desc[idx], dout_dma_addr, din_size, NS_BIT, 0);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], cipher_flow_mode);
+ idx++;
+
+ /* Read temporal MAC */
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_CIPHER_MODE(&desc[idx], DRV_CIPHER_CBC_MAC);
+ HW_DESC_SET_DOUT_DLLI(&desc[idx], mac_res_dma_addr, NIST_AESCCM_TAG_SIZE, NS_BIT, 0);
+ HW_DESC_SET_SETUP_MODE(&desc[idx], SETUP_WRITE_STATE0);
+ HW_DESC_SET_CIPHER_CONFIG0(&desc[idx], HASH_DIGEST_RESULT_LITTLE_ENDIAN);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], S_HASH_to_DOUT);
+ HW_DESC_SET_AES_NOT_HASH_MODE(&desc[idx]);
+ idx++;
+
+ /* load AES-CTR state (for last MAC calculation)*/
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_CIPHER_MODE(&desc[idx], DRV_CIPHER_CTR);
+ HW_DESC_SET_CIPHER_CONFIG0(&desc[idx], DRV_CRYPTO_DIRECTION_ENCRYPT);
+ HW_DESC_SET_DIN_TYPE(&desc[idx], DMA_DLLI,
+ ctr_cnt_0_dma_addr,
+ AES_BLOCK_SIZE, NS_BIT);
+ HW_DESC_SET_KEY_SIZE_AES(&desc[idx], key_size);
+ HW_DESC_SET_SETUP_MODE(&desc[idx], SETUP_LOAD_STATE1);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], S_DIN_to_AES);
+ idx++;
+
+ /* Memory Barrier */
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_DIN_NO_DMA(&desc[idx], 0, 0xfffff0);
+ HW_DESC_SET_DOUT_NO_DMA(&desc[idx], 0, 0, 1);
+ idx++;
+
+ /* encrypt the "T" value and store MAC inplace */
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_DIN_TYPE(&desc[idx], DMA_DLLI, mac_res_dma_addr, NIST_AESCCM_TAG_SIZE, NS_BIT);
+ HW_DESC_SET_DOUT_DLLI(&desc[idx], mac_res_dma_addr, NIST_AESCCM_TAG_SIZE, NS_BIT, 0);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], DIN_AES_DOUT);
+ idx++;
+
+ /* perform the operation - Lock HW and push sequence */
+ BUG_ON(idx > FIPS_CCM_MAX_SEQ_LEN);
+ rc = send_request(drvdata, &ssi_req, desc, idx, false);
+
+ return rc;
+}
+
+ssi_fips_error_t
+ssi_ccm_fips_power_up_tests(struct ssi_drvdata *drvdata, void *cpu_addr_buffer, dma_addr_t dma_coherent_buffer)
+{
+ ssi_fips_error_t error = CC_REE_FIPS_ERROR_OK;
+ size_t i;
+ struct fips_ccm_ctx *virt_ctx = (struct fips_ccm_ctx *)cpu_addr_buffer;
+
+ /* set the phisical pointers */
+ dma_addr_t b0_a0_adata_dma_addr = dma_coherent_buffer + offsetof(struct fips_ccm_ctx, b0_a0_adata);
+ dma_addr_t iv_dma_addr = dma_coherent_buffer + offsetof(struct fips_ccm_ctx, iv);
+ dma_addr_t ctr_cnt_0_dma_addr = dma_coherent_buffer + offsetof(struct fips_ccm_ctx, ctr_cnt_0);
+ dma_addr_t key_dma_addr = dma_coherent_buffer + offsetof(struct fips_ccm_ctx, key);
+ dma_addr_t din_dma_addr = dma_coherent_buffer + offsetof(struct fips_ccm_ctx, din);
+ dma_addr_t dout_dma_addr = dma_coherent_buffer + offsetof(struct fips_ccm_ctx, dout);
+ dma_addr_t mac_res_dma_addr = dma_coherent_buffer + offsetof(struct fips_ccm_ctx, mac_res);
+
+ for (i = 0; i < FIPS_CCM_NUM_OF_TESTS; ++i)
+ {
+ FipsCcmData *ccmData = (FipsCcmData*)&FipsCcmDataTable[i];
+ int rc = 0;
+
+ memset(cpu_addr_buffer, 0, sizeof(struct fips_ccm_ctx));
+
+ /* copy the nonce, key, adata, din data into the allocated buffer */
+ memcpy(virt_ctx->key, ccmData->key, ccmData->keySize);
+ memcpy(virt_ctx->din, ccmData->dataIn, ccmData->dataInSize);
+ {
+ /* build B0 -- B0, nonce, l(m) */
+ __be16 data = cpu_to_be16(NIST_AESCCM_TEXT_SIZE);
+ virt_ctx->b0_a0_adata[0] = NIST_AESCCM_B0_VAL;
+ memcpy(virt_ctx->b0_a0_adata + 1, ccmData->nonce, NIST_AESCCM_NONCE_SIZE);
+ memcpy(virt_ctx->b0_a0_adata + 14, (u8 *)&data, sizeof(__be16));
+ /* build A0+ADATA */
+ virt_ctx->b0_a0_adata[NIST_AESCCM_IV_SIZE + 0] = (ccmData->adataSize >> 8) & 0xFF;
+ virt_ctx->b0_a0_adata[NIST_AESCCM_IV_SIZE + 1] = ccmData->adataSize & 0xFF;
+ memcpy(virt_ctx->b0_a0_adata + NIST_AESCCM_IV_SIZE + 2, ccmData->adata, ccmData->adataSize);
+ /* iv */
+ virt_ctx->iv[0] = 1; /* L' */
+ memcpy(virt_ctx->iv + 1, ccmData->nonce, NIST_AESCCM_NONCE_SIZE);
+ virt_ctx->iv[15] = 1;
+ /* ctr_count_0 */
+ memcpy(virt_ctx->ctr_cnt_0, virt_ctx->iv, NIST_AESCCM_IV_SIZE);
+ virt_ctx->ctr_cnt_0[15] = 0;
+ }
+
+ FIPS_DBG("ssi_ccm_fips_run_test - (i = %d) \n", i);
+ rc = ssi_ccm_fips_run_test(drvdata,
+ ccmData->direction,
+ key_dma_addr,
+ ccmData->keySize,
+ iv_dma_addr,
+ ctr_cnt_0_dma_addr,
+ b0_a0_adata_dma_addr,
+ FIPS_CCM_B0_A0_ADATA_SIZE,
+ din_dma_addr,
+ ccmData->dataInSize,
+ dout_dma_addr,
+ mac_res_dma_addr);
+ if (rc != 0)
+ {
+ FIPS_LOG("ssi_ccm_fips_run_test %d returned error - rc = %d \n", i, rc);
+ error = CC_REE_FIPS_ERROR_AESCCM_PUT;
+ break;
+ }
+
+ /* compare actual dout to expected */
+ if (memcmp(virt_ctx->dout, ccmData->dataOut, ccmData->dataInSize) != 0)
+ {
+ FIPS_LOG("dout comparison error %d - size=%d \n", i, ccmData->dataInSize);
+ error = CC_REE_FIPS_ERROR_AESCCM_PUT;
+ break;
+ }
+
+ /* compare actual mac result to expected */
+ if (memcmp(virt_ctx->mac_res, ccmData->macResOut, ccmData->tagSize) != 0)
+ {
+ FIPS_LOG("mac_res comparison error %d - mac_size=%d \n", i, ccmData->tagSize);
+ FIPS_LOG(" i expected received \n");
+ FIPS_LOG(" i 0x%08x 0x%08x \n", (size_t)ccmData->macResOut, (size_t)virt_ctx->mac_res);
+ for (i = 0; i < ccmData->tagSize; ++i)
+ {
+ FIPS_LOG(" %d 0x%02x 0x%02x \n", i, ccmData->macResOut[i], virt_ctx->mac_res[i]);
+ }
+
+ error = CC_REE_FIPS_ERROR_AESCCM_PUT;
+ break;
+ }
+ }
+
+ return error;
+}
+
+
+static inline int
+ssi_gcm_fips_run_test(struct ssi_drvdata *drvdata,
+ enum drv_crypto_direction direction,
+ dma_addr_t key_dma_addr,
+ size_t key_size,
+ dma_addr_t hkey_dma_addr,
+ dma_addr_t block_len_dma_addr,
+ dma_addr_t iv_inc1_dma_addr,
+ dma_addr_t iv_inc2_dma_addr,
+ dma_addr_t adata_dma_addr,
+ size_t adata_size,
+ dma_addr_t din_dma_addr,
+ size_t din_size,
+ dma_addr_t dout_dma_addr,
+ dma_addr_t mac_res_dma_addr)
+{
+ /* max number of descriptors used for the flow */
+ #define FIPS_GCM_MAX_SEQ_LEN 15
+
+ int rc;
+ struct ssi_crypto_req ssi_req = {0};
+ HwDesc_s desc[FIPS_GCM_MAX_SEQ_LEN];
+ unsigned int idx = 0;
+ unsigned int cipher_flow_mode;
+
+ if (direction == DRV_CRYPTO_DIRECTION_DECRYPT) {
+ cipher_flow_mode = AES_and_HASH;
+ } else { /* Encrypt */
+ cipher_flow_mode = AES_to_HASH_and_DOUT;
+ }
+
+///////////////////////////////// 1 ////////////////////////////////////
+// ssi_aead_gcm_setup_ghash_desc(req, desc, seq_size);
+///////////////////////////////// 1 ////////////////////////////////////
+
+ /* load key to AES*/
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_CIPHER_MODE(&desc[idx], DRV_CIPHER_ECB);
+ HW_DESC_SET_CIPHER_CONFIG0(&desc[idx], DRV_CRYPTO_DIRECTION_ENCRYPT);
+ HW_DESC_SET_DIN_TYPE(&desc[idx],
+ DMA_DLLI, key_dma_addr, key_size,
+ NS_BIT);
+ HW_DESC_SET_KEY_SIZE_AES(&desc[idx], key_size);
+ HW_DESC_SET_SETUP_MODE(&desc[idx], SETUP_LOAD_KEY0);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], S_DIN_to_AES);
+ idx++;
+
+ /* process one zero block to generate hkey */
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_DIN_CONST(&desc[idx], 0x0, AES_BLOCK_SIZE);
+ HW_DESC_SET_DOUT_DLLI(&desc[idx],
+ hkey_dma_addr, AES_BLOCK_SIZE,
+ NS_BIT, 0);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], DIN_AES_DOUT);
+ idx++;
+
+ /* Memory Barrier */
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_DIN_NO_DMA(&desc[idx], 0, 0xfffff0);
+ HW_DESC_SET_DOUT_NO_DMA(&desc[idx], 0, 0, 1);
+ idx++;
+
+ /* Load GHASH subkey */
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_DIN_TYPE(&desc[idx], DMA_DLLI,
+ hkey_dma_addr, AES_BLOCK_SIZE,
+ NS_BIT);
+ HW_DESC_SET_DOUT_NO_DMA(&desc[idx], 0, 0, 1);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], S_DIN_to_HASH);
+ HW_DESC_SET_AES_NOT_HASH_MODE(&desc[idx]);
+ HW_DESC_SET_CIPHER_MODE(&desc[idx], DRV_HASH_HW_GHASH);
+ HW_DESC_SET_CIPHER_CONFIG1(&desc[idx], HASH_PADDING_ENABLED);
+ HW_DESC_SET_SETUP_MODE(&desc[idx], SETUP_LOAD_KEY0);
+ idx++;
+
+ /* Configure Hash Engine to work with GHASH.
+ Since it was not possible to extend HASH submodes to add GHASH,
+ The following command is necessary in order to select GHASH (according to HW designers)*/
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_DIN_NO_DMA(&desc[idx], 0, 0xfffff0);
+ HW_DESC_SET_DOUT_NO_DMA(&desc[idx], 0, 0, 1);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], S_DIN_to_HASH);
+ HW_DESC_SET_AES_NOT_HASH_MODE(&desc[idx]);
+ HW_DESC_SET_CIPHER_MODE(&desc[idx], DRV_HASH_HW_GHASH);
+ HW_DESC_SET_CIPHER_DO(&desc[idx], 1); //1=AES_SK RKEK
+ HW_DESC_SET_CIPHER_CONFIG0(&desc[idx], DRV_CRYPTO_DIRECTION_ENCRYPT);
+ HW_DESC_SET_CIPHER_CONFIG1(&desc[idx], HASH_PADDING_ENABLED);
+ HW_DESC_SET_SETUP_MODE(&desc[idx], SETUP_LOAD_KEY0);
+ idx++;
+
+ /* Load GHASH initial STATE (which is 0). (for any hash there is an initial state) */
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_DIN_CONST(&desc[idx], 0x0, AES_BLOCK_SIZE);
+ HW_DESC_SET_DOUT_NO_DMA(&desc[idx], 0, 0, 1);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], S_DIN_to_HASH);
+ HW_DESC_SET_AES_NOT_HASH_MODE(&desc[idx]);
+ HW_DESC_SET_CIPHER_MODE(&desc[idx], DRV_HASH_HW_GHASH);
+ HW_DESC_SET_CIPHER_CONFIG1(&desc[idx], HASH_PADDING_ENABLED);
+ HW_DESC_SET_SETUP_MODE(&desc[idx], SETUP_LOAD_STATE0);
+ idx++;
+
+
+
+///////////////////////////////// 2 ////////////////////////////////////
+ /* prcess(ghash) assoc data */
+// if (req->assoclen > 0)
+// ssi_aead_create_assoc_desc(req, DIN_HASH, desc, seq_size);
+///////////////////////////////// 2 ////////////////////////////////////
+
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_DIN_TYPE(&desc[idx], DMA_DLLI,
+ adata_dma_addr, adata_size,
+ NS_BIT);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], DIN_HASH);
+ idx++;
+
+
+///////////////////////////////// 3 ////////////////////////////////////
+// ssi_aead_gcm_setup_gctr_desc(req, desc, seq_size);
+///////////////////////////////// 3 ////////////////////////////////////
+
+ /* load key to AES*/
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_CIPHER_MODE(&desc[idx], DRV_CIPHER_GCTR);
+ HW_DESC_SET_CIPHER_CONFIG0(&desc[idx], DRV_CRYPTO_DIRECTION_ENCRYPT);
+ HW_DESC_SET_DIN_TYPE(&desc[idx], DMA_DLLI,
+ key_dma_addr, key_size,
+ NS_BIT);
+ HW_DESC_SET_KEY_SIZE_AES(&desc[idx], key_size);
+ HW_DESC_SET_SETUP_MODE(&desc[idx], SETUP_LOAD_KEY0);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], S_DIN_to_AES);
+ idx++;
+
+ /* load AES/CTR initial CTR value inc by 2*/
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_CIPHER_MODE(&desc[idx], DRV_CIPHER_GCTR);
+ HW_DESC_SET_KEY_SIZE_AES(&desc[idx], key_size);
+ HW_DESC_SET_DIN_TYPE(&desc[idx], DMA_DLLI,
+ iv_inc2_dma_addr, AES_BLOCK_SIZE,
+ NS_BIT);
+ HW_DESC_SET_CIPHER_CONFIG0(&desc[idx], DRV_CRYPTO_DIRECTION_ENCRYPT);
+ HW_DESC_SET_SETUP_MODE(&desc[idx], SETUP_LOAD_STATE1);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], S_DIN_to_AES);
+ idx++;
+
+
+///////////////////////////////// 4 ////////////////////////////////////
+ /* process(gctr+ghash) */
+// if (req_ctx->cryptlen != 0)
+// ssi_aead_process_cipher_data_desc(req, cipher_flow_mode, desc, seq_size);
+///////////////////////////////// 4 ////////////////////////////////////
+
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_DIN_TYPE(&desc[idx], DMA_DLLI,
+ din_dma_addr, din_size,
+ NS_BIT);
+ HW_DESC_SET_DOUT_DLLI(&desc[idx],
+ dout_dma_addr, din_size,
+ NS_BIT, 0);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], cipher_flow_mode);
+ idx++;
+
+
+///////////////////////////////// 5 ////////////////////////////////////
+// ssi_aead_process_gcm_result_desc(req, desc, seq_size);
+///////////////////////////////// 5 ////////////////////////////////////
+
+ /* prcess(ghash) gcm_block_len */
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_DIN_TYPE(&desc[idx], DMA_DLLI,
+ block_len_dma_addr, AES_BLOCK_SIZE,
+ NS_BIT);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], DIN_HASH);
+ idx++;
+
+ /* Store GHASH state after GHASH(Associated Data + Cipher +LenBlock) */
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_CIPHER_MODE(&desc[idx], DRV_HASH_HW_GHASH);
+ HW_DESC_SET_DIN_NO_DMA(&desc[idx], 0, 0xfffff0);
+ HW_DESC_SET_DOUT_DLLI(&desc[idx],
+ mac_res_dma_addr, AES_BLOCK_SIZE,
+ NS_BIT, 0);
+ HW_DESC_SET_SETUP_MODE(&desc[idx], SETUP_WRITE_STATE0);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], S_HASH_to_DOUT);
+ HW_DESC_SET_AES_NOT_HASH_MODE(&desc[idx]);
+ idx++;
+
+ /* load AES/CTR initial CTR value inc by 1*/
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_CIPHER_MODE(&desc[idx], DRV_CIPHER_GCTR);
+ HW_DESC_SET_KEY_SIZE_AES(&desc[idx], key_size);
+ HW_DESC_SET_DIN_TYPE(&desc[idx], DMA_DLLI,
+ iv_inc1_dma_addr, AES_BLOCK_SIZE,
+ NS_BIT);
+ HW_DESC_SET_CIPHER_CONFIG0(&desc[idx], DRV_CRYPTO_DIRECTION_ENCRYPT);
+ HW_DESC_SET_SETUP_MODE(&desc[idx], SETUP_LOAD_STATE1);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], S_DIN_to_AES);
+ idx++;
+
+ /* Memory Barrier */
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_DIN_NO_DMA(&desc[idx], 0, 0xfffff0);
+ HW_DESC_SET_DOUT_NO_DMA(&desc[idx], 0, 0, 1);
+ idx++;
+
+ /* process GCTR on stored GHASH and store MAC inplace */
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_CIPHER_MODE(&desc[idx], DRV_CIPHER_GCTR);
+ HW_DESC_SET_DIN_TYPE(&desc[idx], DMA_DLLI,
+ mac_res_dma_addr, AES_BLOCK_SIZE,
+ NS_BIT);
+ HW_DESC_SET_DOUT_DLLI(&desc[idx],
+ mac_res_dma_addr, AES_BLOCK_SIZE,
+ NS_BIT, 0);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], DIN_AES_DOUT);
+ idx++;
+
+ /* perform the operation - Lock HW and push sequence */
+ BUG_ON(idx > FIPS_GCM_MAX_SEQ_LEN);
+ rc = send_request(drvdata, &ssi_req, desc, idx, false);
+
+ return rc;
+}
+
+ssi_fips_error_t
+ssi_gcm_fips_power_up_tests(struct ssi_drvdata *drvdata, void *cpu_addr_buffer, dma_addr_t dma_coherent_buffer)
+{
+ ssi_fips_error_t error = CC_REE_FIPS_ERROR_OK;
+ size_t i;
+ struct fips_gcm_ctx *virt_ctx = (struct fips_gcm_ctx *)cpu_addr_buffer;
+
+ /* set the phisical pointers */
+ dma_addr_t adata_dma_addr = dma_coherent_buffer + offsetof(struct fips_gcm_ctx, adata);
+ dma_addr_t key_dma_addr = dma_coherent_buffer + offsetof(struct fips_gcm_ctx, key);
+ dma_addr_t hkey_dma_addr = dma_coherent_buffer + offsetof(struct fips_gcm_ctx, hkey);
+ dma_addr_t din_dma_addr = dma_coherent_buffer + offsetof(struct fips_gcm_ctx, din);
+ dma_addr_t dout_dma_addr = dma_coherent_buffer + offsetof(struct fips_gcm_ctx, dout);
+ dma_addr_t mac_res_dma_addr = dma_coherent_buffer + offsetof(struct fips_gcm_ctx, mac_res);
+ dma_addr_t len_block_dma_addr = dma_coherent_buffer + offsetof(struct fips_gcm_ctx, len_block);
+ dma_addr_t iv_inc1_dma_addr = dma_coherent_buffer + offsetof(struct fips_gcm_ctx, iv_inc1);
+ dma_addr_t iv_inc2_dma_addr = dma_coherent_buffer + offsetof(struct fips_gcm_ctx, iv_inc2);
+
+ for (i = 0; i < FIPS_GCM_NUM_OF_TESTS; ++i)
+ {
+ FipsGcmData *gcmData = (FipsGcmData*)&FipsGcmDataTable[i];
+ int rc = 0;
+
+ memset(cpu_addr_buffer, 0, sizeof(struct fips_gcm_ctx));
+
+ /* copy the key, adata, din data - into the allocated buffer */
+ memcpy(virt_ctx->key, gcmData->key, gcmData->keySize);
+ memcpy(virt_ctx->adata, gcmData->adata, gcmData->adataSize);
+ memcpy(virt_ctx->din, gcmData->dataIn, gcmData->dataInSize);
+
+ /* len_block */
+ {
+ __be64 len_bits;
+ len_bits = cpu_to_be64(gcmData->adataSize * 8);
+ memcpy(virt_ctx->len_block, &len_bits, sizeof(len_bits));
+ len_bits = cpu_to_be64(gcmData->dataInSize * 8);
+ memcpy(virt_ctx->len_block + 8, &len_bits, sizeof(len_bits));
+ }
+ /* iv_inc1, iv_inc2 */
+ {
+ __be32 counter = cpu_to_be32(1);
+ memcpy(virt_ctx->iv_inc1, gcmData->iv, NIST_AESGCM_IV_SIZE);
+ memcpy(virt_ctx->iv_inc1 + NIST_AESGCM_IV_SIZE, &counter, sizeof(counter));
+ counter = cpu_to_be32(2);
+ memcpy(virt_ctx->iv_inc2, gcmData->iv, NIST_AESGCM_IV_SIZE);
+ memcpy(virt_ctx->iv_inc2 + NIST_AESGCM_IV_SIZE, &counter, sizeof(counter));
+ }
+
+ FIPS_DBG("ssi_gcm_fips_run_test - (i = %d) \n", i);
+ rc = ssi_gcm_fips_run_test(drvdata,
+ gcmData->direction,
+ key_dma_addr,
+ gcmData->keySize,
+ hkey_dma_addr,
+ len_block_dma_addr,
+ iv_inc1_dma_addr,
+ iv_inc2_dma_addr,
+ adata_dma_addr,
+ gcmData->adataSize,
+ din_dma_addr,
+ gcmData->dataInSize,
+ dout_dma_addr,
+ mac_res_dma_addr);
+ if (rc != 0)
+ {
+ FIPS_LOG("ssi_gcm_fips_run_test %d returned error - rc = %d \n", i, rc);
+ error = CC_REE_FIPS_ERROR_AESGCM_PUT;
+ break;
+ }
+
+ if (gcmData->direction == DRV_CRYPTO_DIRECTION_ENCRYPT) {
+ /* compare actual dout to expected */
+ if (memcmp(virt_ctx->dout, gcmData->dataOut, gcmData->dataInSize) != 0)
+ {
+ FIPS_LOG("dout comparison error %d - size=%d \n", i, gcmData->dataInSize);
+ FIPS_LOG(" i expected received \n");
+ FIPS_LOG(" i 0x%08x 0x%08x \n", (size_t)gcmData->dataOut, (size_t)virt_ctx->dout);
+ for (i = 0; i < gcmData->dataInSize; ++i)
+ {
+ FIPS_LOG(" %d 0x%02x 0x%02x \n", i, gcmData->dataOut[i], virt_ctx->dout[i]);
+ }
+
+ error = CC_REE_FIPS_ERROR_AESGCM_PUT;
+ break;
+ }
+ }
+
+ /* compare actual mac result to expected */
+ if (memcmp(virt_ctx->mac_res, gcmData->macResOut, gcmData->tagSize) != 0)
+ {
+ FIPS_LOG("mac_res comparison error %d - mac_size=%d \n", i, gcmData->tagSize);
+ FIPS_LOG(" i expected received \n");
+ FIPS_LOG(" i 0x%08x 0x%08x \n", (size_t)gcmData->macResOut, (size_t)virt_ctx->mac_res);
+ for (i = 0; i < gcmData->tagSize; ++i)
+ {
+ FIPS_LOG(" %d 0x%02x 0x%02x \n", i, gcmData->macResOut[i], virt_ctx->mac_res[i]);
+ }
+
+ error = CC_REE_FIPS_ERROR_AESGCM_PUT;
+ break;
+ }
+ }
+ return error;
+}
+
+
+size_t ssi_fips_max_mem_alloc_size(void)
+{
+ FIPS_DBG("sizeof(struct fips_cipher_ctx) %d \n", sizeof(struct fips_cipher_ctx));
+ FIPS_DBG("sizeof(struct fips_cmac_ctx) %d \n", sizeof(struct fips_cmac_ctx));
+ FIPS_DBG("sizeof(struct fips_hash_ctx) %d \n", sizeof(struct fips_hash_ctx));
+ FIPS_DBG("sizeof(struct fips_hmac_ctx) %d \n", sizeof(struct fips_hmac_ctx));
+ FIPS_DBG("sizeof(struct fips_ccm_ctx) %d \n", sizeof(struct fips_ccm_ctx));
+ FIPS_DBG("sizeof(struct fips_gcm_ctx) %d \n", sizeof(struct fips_gcm_ctx));
+
+ return sizeof(fips_ctx);
+}
+
diff --git a/drivers/staging/ccree/ssi_fips_local.c b/drivers/staging/ccree/ssi_fips_local.c
new file mode 100644
index 0000000..51b535a
--- /dev/null
+++ b/drivers/staging/ccree/ssi_fips_local.c
@@ -0,0 +1,369 @@
+/*
+ * Copyright (C) 2012-2017 ARM Limited or its affiliates.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**************************************************************
+This file defines the driver FIPS internal function, used by the driver itself.
+***************************************************************/
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <crypto/des.h>
+
+#include "ssi_config.h"
+#include "ssi_driver.h"
+#include "cc_hal.h"
+
+
+#define FIPS_POWER_UP_TEST_CIPHER 1
+#define FIPS_POWER_UP_TEST_CMAC 1
+#define FIPS_POWER_UP_TEST_HASH 1
+#define FIPS_POWER_UP_TEST_HMAC 1
+#define FIPS_POWER_UP_TEST_CCM 1
+#define FIPS_POWER_UP_TEST_GCM 1
+
+static bool ssi_fips_support = 1;
+module_param(ssi_fips_support, bool, 0644);
+MODULE_PARM_DESC(ssi_fips_support, "FIPS supported flag: 0 - off , 1 - on (default)");
+
+static void fips_dsr(unsigned long devarg);
+
+struct ssi_fips_handle {
+#ifdef COMP_IN_WQ
+ struct workqueue_struct *workq;
+ struct delayed_work fipswork;
+#else
+ struct tasklet_struct fipstask;
+#endif
+};
+
+
+extern int ssi_fips_get_state(ssi_fips_state_t *p_state);
+extern int ssi_fips_get_error(ssi_fips_error_t *p_err);
+extern int ssi_fips_ext_set_state(ssi_fips_state_t state);
+extern int ssi_fips_ext_set_error(ssi_fips_error_t err);
+
+/* FIPS power-up tests */
+extern ssi_fips_error_t ssi_cipher_fips_power_up_tests(struct ssi_drvdata *drvdata, void *cpu_addr_buffer, dma_addr_t dma_coherent_buffer);
+extern ssi_fips_error_t ssi_cmac_fips_power_up_tests(struct ssi_drvdata *drvdata, void *cpu_addr_buffer, dma_addr_t dma_coherent_buffer);
+extern ssi_fips_error_t ssi_hash_fips_power_up_tests(struct ssi_drvdata *drvdata, void *cpu_addr_buffer, dma_addr_t dma_coherent_buffer);
+extern ssi_fips_error_t ssi_hmac_fips_power_up_tests(struct ssi_drvdata *drvdata, void *cpu_addr_buffer, dma_addr_t dma_coherent_buffer);
+extern ssi_fips_error_t ssi_ccm_fips_power_up_tests(struct ssi_drvdata *drvdata, void *cpu_addr_buffer, dma_addr_t dma_coherent_buffer);
+extern ssi_fips_error_t ssi_gcm_fips_power_up_tests(struct ssi_drvdata *drvdata, void *cpu_addr_buffer, dma_addr_t dma_coherent_buffer);
+extern size_t ssi_fips_max_mem_alloc_size(void);
+
+
+/* The function called once at driver entry point to check whether TEE FIPS error occured.*/
+static enum ssi_fips_error ssi_fips_get_tee_error(struct ssi_drvdata *drvdata)
+{
+ uint32_t regVal;
+ void __iomem *cc_base = drvdata->cc_base;
+
+ regVal = CC_HAL_READ_REGISTER(CC_REG_OFFSET(HOST_RGF, GPR_HOST));
+ if (regVal == (CC_FIPS_SYNC_TEE_STATUS | CC_FIPS_SYNC_MODULE_OK)) {
+ return CC_REE_FIPS_ERROR_OK;
+ }
+ return CC_REE_FIPS_ERROR_FROM_TEE;
+}
+
+
+/*
+ This function should push the FIPS REE library status towards the TEE library.
+ By writing the error state to HOST_GPR0 register. The function is called from .
+ driver entry point so no need to protect by mutex.
+*/
+static void ssi_fips_update_tee_upon_ree_status(struct ssi_drvdata *drvdata, ssi_fips_error_t err)
+{
+ void __iomem *cc_base = drvdata->cc_base;
+ if (err == CC_REE_FIPS_ERROR_OK) {
+ CC_HAL_WRITE_REGISTER(CC_REG_OFFSET(HOST_RGF, HOST_GPR0), (CC_FIPS_SYNC_REE_STATUS|CC_FIPS_SYNC_MODULE_OK));
+ } else {
+ CC_HAL_WRITE_REGISTER(CC_REG_OFFSET(HOST_RGF, HOST_GPR0), (CC_FIPS_SYNC_REE_STATUS|CC_FIPS_SYNC_MODULE_ERROR));
+ }
+}
+
+
+
+void ssi_fips_fini(struct ssi_drvdata *drvdata)
+{
+ struct ssi_fips_handle *fips_h = drvdata->fips_handle;
+
+ if (fips_h == NULL)
+ return; /* Not allocated */
+
+#ifdef COMP_IN_WQ
+ if (fips_h->workq != NULL) {
+ flush_workqueue(fips_h->workq);
+ destroy_workqueue(fips_h->workq);
+ }
+#else
+ /* Kill tasklet */
+ tasklet_kill(&fips_h->fipstask);
+#endif
+ memset(fips_h, 0, sizeof(struct ssi_fips_handle));
+ kfree(fips_h);
+ drvdata->fips_handle = NULL;
+}
+
+void fips_handler(struct ssi_drvdata *drvdata)
+{
+ struct ssi_fips_handle *fips_handle_ptr =
+ drvdata->fips_handle;
+#ifdef COMP_IN_WQ
+ queue_delayed_work(fips_handle_ptr->workq, &fips_handle_ptr->fipswork, 0);
+#else
+ tasklet_schedule(&fips_handle_ptr->fipstask);
+#endif
+}
+
+
+
+#ifdef COMP_IN_WQ
+static void fips_wq_handler(struct work_struct *work)
+{
+ struct ssi_drvdata *drvdata =
+ container_of(work, struct ssi_drvdata, fipswork.work);
+
+ fips_dsr((unsigned long)drvdata);
+}
+#endif
+
+/* Deferred service handler, run as interrupt-fired tasklet */
+static void fips_dsr(unsigned long devarg)
+{
+ struct ssi_drvdata *drvdata = (struct ssi_drvdata *)devarg;
+ void __iomem *cc_base = drvdata->cc_base;
+ uint32_t irq;
+ uint32_t teeFipsError = 0;
+
+ irq = (drvdata->irq & (SSI_GPR0_IRQ_MASK));
+
+ if (irq & SSI_GPR0_IRQ_MASK) {
+ teeFipsError = CC_HAL_READ_REGISTER(CC_REG_OFFSET(HOST_RGF, GPR_HOST));
+ if (teeFipsError != (CC_FIPS_SYNC_TEE_STATUS | CC_FIPS_SYNC_MODULE_OK)) {
+ ssi_fips_set_error(drvdata, CC_REE_FIPS_ERROR_FROM_TEE);
+ }
+ }
+
+ /* after verifing that there is nothing to do, Unmask AXI completion interrupt */
+ CC_HAL_WRITE_REGISTER(CC_REG_OFFSET(HOST_RGF, HOST_IMR),
+ CC_HAL_READ_REGISTER(
+ CC_REG_OFFSET(HOST_RGF, HOST_IMR)) & ~irq);
+}
+
+
+ssi_fips_error_t cc_fips_run_power_up_tests(struct ssi_drvdata *drvdata)
+{
+ ssi_fips_error_t fips_error = CC_REE_FIPS_ERROR_OK;
+ void * cpu_addr_buffer = NULL;
+ dma_addr_t dma_handle;
+ size_t alloc_buff_size = ssi_fips_max_mem_alloc_size();
+ struct device *dev = &drvdata->plat_dev->dev;
+
+ // allocate memory using dma_alloc_coherent - for phisical, consecutive and cache coherent buffer (memory map is not needed)
+ // the return value is the virtual address - use it to copy data into the buffer
+ // the dma_handle is the returned phy address - use it in the HW descriptor
+ FIPS_DBG("dma_alloc_coherent \n");
+ cpu_addr_buffer = dma_alloc_coherent(dev, alloc_buff_size, &dma_handle, GFP_KERNEL);
+ if (cpu_addr_buffer == NULL) {
+ return CC_REE_FIPS_ERROR_GENERAL;
+ }
+ FIPS_DBG("allocated coherent buffer - addr 0x%08X , size = %d \n", (size_t)cpu_addr_buffer, alloc_buff_size);
+
+#if FIPS_POWER_UP_TEST_CIPHER
+ FIPS_DBG("ssi_cipher_fips_power_up_tests ...\n");
+ fips_error = ssi_cipher_fips_power_up_tests(drvdata, cpu_addr_buffer, dma_handle);
+ FIPS_DBG("ssi_cipher_fips_power_up_tests - done. (fips_error = %d) \n", fips_error);
+#endif
+#if FIPS_POWER_UP_TEST_CMAC
+ if (likely(fips_error == CC_REE_FIPS_ERROR_OK)) {
+ FIPS_DBG("ssi_cmac_fips_power_up_tests ...\n");
+ fips_error = ssi_cmac_fips_power_up_tests(drvdata, cpu_addr_buffer, dma_handle);
+ FIPS_DBG("ssi_cmac_fips_power_up_tests - done. (fips_error = %d) \n", fips_error);
+ }
+#endif
+#if FIPS_POWER_UP_TEST_HASH
+ if (likely(fips_error == CC_REE_FIPS_ERROR_OK)) {
+ FIPS_DBG("ssi_hash_fips_power_up_tests ...\n");
+ fips_error = ssi_hash_fips_power_up_tests(drvdata, cpu_addr_buffer, dma_handle);
+ FIPS_DBG("ssi_hash_fips_power_up_tests - done. (fips_error = %d) \n", fips_error);
+ }
+#endif
+#if FIPS_POWER_UP_TEST_HMAC
+ if (likely(fips_error == CC_REE_FIPS_ERROR_OK)) {
+ FIPS_DBG("ssi_hmac_fips_power_up_tests ...\n");
+ fips_error = ssi_hmac_fips_power_up_tests(drvdata, cpu_addr_buffer, dma_handle);
+ FIPS_DBG("ssi_hmac_fips_power_up_tests - done. (fips_error = %d) \n", fips_error);
+ }
+#endif
+#if FIPS_POWER_UP_TEST_CCM
+ if (likely(fips_error == CC_REE_FIPS_ERROR_OK)) {
+ FIPS_DBG("ssi_ccm_fips_power_up_tests ...\n");
+ fips_error = ssi_ccm_fips_power_up_tests(drvdata, cpu_addr_buffer, dma_handle);
+ FIPS_DBG("ssi_ccm_fips_power_up_tests - done. (fips_error = %d) \n", fips_error);
+ }
+#endif
+#if FIPS_POWER_UP_TEST_GCM
+ if (likely(fips_error == CC_REE_FIPS_ERROR_OK)) {
+ FIPS_DBG("ssi_gcm_fips_power_up_tests ...\n");
+ fips_error = ssi_gcm_fips_power_up_tests(drvdata, cpu_addr_buffer, dma_handle);
+ FIPS_DBG("ssi_gcm_fips_power_up_tests - done. (fips_error = %d) \n", fips_error);
+ }
+#endif
+ /* deallocate the buffer when all tests are done... */
+ FIPS_DBG("dma_free_coherent \n");
+ dma_free_coherent(dev, alloc_buff_size, cpu_addr_buffer, dma_handle);
+
+ return fips_error;
+}
+
+
+
+/* The function checks if FIPS supported and FIPS error exists.*
+* It should be used in every driver API.*/
+int ssi_fips_check_fips_error(void)
+{
+ ssi_fips_state_t fips_state;
+
+ if (ssi_fips_get_state(&fips_state) != 0) {
+ FIPS_LOG("ssi_fips_get_state FAILED, returning.. \n");
+ return -ENOEXEC;
+ }
+ if (fips_state == CC_FIPS_STATE_ERROR) {
+ FIPS_LOG("ssi_fips_get_state: fips_state is %d, returning.. \n", fips_state);
+ return -ENOEXEC;
+ }
+ return 0;
+}
+
+
+/* The function sets the REE FIPS state.*
+* It should be used while driver is being loaded .*/
+int ssi_fips_set_state(ssi_fips_state_t state)
+{
+ return ssi_fips_ext_set_state(state);
+}
+
+/* The function sets the REE FIPS error, and pushes the error to TEE library. *
+* It should be used when any of the KAT tests fails .*/
+int ssi_fips_set_error(struct ssi_drvdata *p_drvdata, ssi_fips_error_t err)
+{
+ int rc = 0;
+ ssi_fips_error_t current_err;
+
+ FIPS_LOG("ssi_fips_set_error - fips_error = %d \n", err);
+
+ // setting no error is not allowed
+ if (err == CC_REE_FIPS_ERROR_OK) {
+ return -ENOEXEC;
+ }
+ // If error exists, do not set new error
+ if (ssi_fips_get_error(&current_err) != 0) {
+ return -ENOEXEC;
+ }
+ if (current_err != CC_REE_FIPS_ERROR_OK) {
+ return -ENOEXEC;
+ }
+ // set REE internal error and state
+ rc = ssi_fips_ext_set_error(err);
+ if (rc != 0) {
+ return -ENOEXEC;
+ }
+ rc = ssi_fips_ext_set_state(CC_FIPS_STATE_ERROR);
+ if (rc != 0) {
+ return -ENOEXEC;
+ }
+
+ // push error towards TEE libraray, if it's not TEE error
+ if (err != CC_REE_FIPS_ERROR_FROM_TEE) {
+ ssi_fips_update_tee_upon_ree_status(p_drvdata, err);
+ }
+ return rc;
+}
+
+
+/* The function called once at driver entry point .*/
+int ssi_fips_init(struct ssi_drvdata *p_drvdata)
+{
+ ssi_fips_error_t rc = CC_REE_FIPS_ERROR_OK;
+ struct ssi_fips_handle *fips_h;
+
+ FIPS_DBG("CC FIPS code .. (fips=%d) \n", ssi_fips_support);
+
+ fips_h = kzalloc(sizeof(struct ssi_fips_handle),GFP_KERNEL);
+ if (fips_h == NULL) {
+ ssi_fips_set_error(p_drvdata, CC_REE_FIPS_ERROR_GENERAL);
+ return -ENOMEM;
+ }
+
+ p_drvdata->fips_handle = fips_h;
+
+#ifdef COMP_IN_WQ
+ SSI_LOG_DEBUG("Initializing fips workqueue\n");
+ fips_h->workq = create_singlethread_workqueue("arm_cc7x_fips_wq");
+ if (unlikely(fips_h->workq == NULL)) {
+ SSI_LOG_ERR("Failed creating fips work queue\n");
+ ssi_fips_set_error(p_drvdata, CC_REE_FIPS_ERROR_GENERAL);
+ rc = -ENOMEM;
+ goto ssi_fips_init_err;
+ }
+ INIT_DELAYED_WORK(&fips_h->fipswork, fips_wq_handler);
+#else
+ SSI_LOG_DEBUG("Initializing fips tasklet\n");
+ tasklet_init(&fips_h->fipstask, fips_dsr, (unsigned long)p_drvdata);
+#endif
+
+ /* init fips driver data */
+ rc = ssi_fips_set_state((ssi_fips_support == 0)? CC_FIPS_STATE_NOT_SUPPORTED : CC_FIPS_STATE_SUPPORTED);
+ if (unlikely(rc != 0)) {
+ ssi_fips_set_error(p_drvdata, CC_REE_FIPS_ERROR_GENERAL);
+ rc = -EAGAIN;
+ goto ssi_fips_init_err;
+ }
+
+ /* Run power up tests (before registration and operating the HW engines) */
+ FIPS_DBG("ssi_fips_get_tee_error \n");
+ rc = ssi_fips_get_tee_error(p_drvdata);
+ if (unlikely(rc != CC_REE_FIPS_ERROR_OK)) {
+ ssi_fips_set_error(p_drvdata, CC_REE_FIPS_ERROR_FROM_TEE);
+ rc = -EAGAIN;
+ goto ssi_fips_init_err;
+ }
+
+ FIPS_DBG("cc_fips_run_power_up_tests \n");
+ rc = cc_fips_run_power_up_tests(p_drvdata);
+ if (unlikely(rc != CC_REE_FIPS_ERROR_OK)) {
+ ssi_fips_set_error(p_drvdata, rc);
+ rc = -EAGAIN;
+ goto ssi_fips_init_err;
+ }
+ FIPS_LOG("cc_fips_run_power_up_tests - done ... fips_error = %d \n", rc);
+
+ /* when all tests passed, update TEE with fips OK status after power up tests */
+ ssi_fips_update_tee_upon_ree_status(p_drvdata, CC_REE_FIPS_ERROR_OK);
+
+ if (unlikely(rc != 0)) {
+ rc = -EAGAIN;
+ ssi_fips_set_error(p_drvdata, CC_REE_FIPS_ERROR_GENERAL);
+ goto ssi_fips_init_err;
+ }
+
+ return 0;
+
+ssi_fips_init_err:
+ ssi_fips_fini(p_drvdata);
+ return rc;
+}
+
diff --git a/drivers/staging/ccree/ssi_fips_local.h b/drivers/staging/ccree/ssi_fips_local.h
new file mode 100644
index 0000000..65997c1
--- /dev/null
+++ b/drivers/staging/ccree/ssi_fips_local.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2012-2017 ARM Limited or its affiliates.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __SSI_FIPS_LOCAL_H__
+#define __SSI_FIPS_LOCAL_H__
+
+
+#ifdef CONFIG_CCX7REE_FIPS_SUPPORT
+
+#include "ssi_fips.h"
+struct ssi_drvdata;
+
+// IG - how to make 1 file for TEE and REE
+typedef enum CC_FipsSyncStatus{
+ CC_FIPS_SYNC_MODULE_OK = 0x0,
+ CC_FIPS_SYNC_MODULE_ERROR = 0x1,
+ CC_FIPS_SYNC_REE_STATUS = 0x4,
+ CC_FIPS_SYNC_TEE_STATUS = 0x8,
+ CC_FIPS_SYNC_STATUS_RESERVE32B = INT32_MAX
+}CCFipsSyncStatus_t;
+
+
+#define CHECK_AND_RETURN_UPON_FIPS_ERROR() {\
+ if (ssi_fips_check_fips_error() != 0) {\
+ return -ENOEXEC;\
+ }\
+}
+#define CHECK_AND_RETURN_VOID_UPON_FIPS_ERROR() {\
+ if (ssi_fips_check_fips_error() != 0) {\
+ return;\
+ }\
+}
+#define SSI_FIPS_INIT(p_drvData) (ssi_fips_init(p_drvData))
+#define SSI_FIPS_FINI(p_drvData) (ssi_fips_fini(p_drvData))
+
+#define FIPS_LOG(...) SSI_LOG(KERN_INFO, __VA_ARGS__)
+#define FIPS_DBG(...) //SSI_LOG(KERN_INFO, __VA_ARGS__)
+
+/* FIPS functions */
+int ssi_fips_init(struct ssi_drvdata *p_drvdata);
+void ssi_fips_fini(struct ssi_drvdata *drvdata);
+int ssi_fips_check_fips_error(void);
+int ssi_fips_set_error(struct ssi_drvdata *p_drvdata, ssi_fips_error_t err);
+void fips_handler(struct ssi_drvdata *drvdata);
+
+#else /* CONFIG_CC7XXREE_FIPS_SUPPORT */
+
+#define CHECK_AND_RETURN_UPON_FIPS_ERROR()
+#define CHECK_AND_RETURN_VOID_UPON_FIPS_ERROR()
+
+static inline int ssi_fips_init(struct ssi_drvdata *p_drvdata)
+{
+ return 0;
+}
+
+static inline void ssi_fips_fini(struct ssi_drvdata *drvdata) {}
+
+void fips_handler(struct ssi_drvdata *drvdata);
+
+#endif /* CONFIG_CC7XXREE_FIPS_SUPPORT */
+
+
+#endif /*__SSI_FIPS_LOCAL_H__*/
+
diff --git a/drivers/staging/ccree/ssi_hash.c b/drivers/staging/ccree/ssi_hash.c
new file mode 100644
index 0000000..8ff5d4e
--- /dev/null
+++ b/drivers/staging/ccree/ssi_hash.c
@@ -0,0 +1,2742 @@
+/*
+ * Copyright (C) 2012-2017 ARM Limited or its affiliates.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <crypto/algapi.h>
+#include <crypto/hash.h>
+#include <crypto/sha.h>
+#include <crypto/md5.h>
+#include <crypto/internal/hash.h>
+
+#include "ssi_config.h"
+#include "ssi_driver.h"
+#include "ssi_request_mgr.h"
+#include "ssi_buffer_mgr.h"
+#include "ssi_sysfs.h"
+#include "ssi_hash.h"
+#include "ssi_sram_mgr.h"
+#include "ssi_fips_local.h"
+
+#define SSI_MAX_AHASH_SEQ_LEN 12
+#define SSI_MAX_HASH_OPAD_TMP_KEYS_SIZE MAX(SSI_MAX_HASH_BLCK_SIZE, 3 * AES_BLOCK_SIZE)
+
+struct ssi_hash_handle {
+ ssi_sram_addr_t digest_len_sram_addr; /* const value in SRAM*/
+ ssi_sram_addr_t larval_digest_sram_addr; /* const value in SRAM */
+ struct list_head hash_list;
+ struct completion init_comp;
+};
+
+static const uint32_t digest_len_init[] = {
+ 0x00000040, 0x00000000, 0x00000000, 0x00000000 };
+static const uint32_t md5_init[] = {
+ SHA1_H3, SHA1_H2, SHA1_H1, SHA1_H0 };
+static const uint32_t sha1_init[] = {
+ SHA1_H4, SHA1_H3, SHA1_H2, SHA1_H1, SHA1_H0 };
+static const uint32_t sha224_init[] = {
+ SHA224_H7, SHA224_H6, SHA224_H5, SHA224_H4,
+ SHA224_H3, SHA224_H2, SHA224_H1, SHA224_H0 };
+static const uint32_t sha256_init[] = {
+ SHA256_H7, SHA256_H6, SHA256_H5, SHA256_H4,
+ SHA256_H3, SHA256_H2, SHA256_H1, SHA256_H0 };
+#if (DX_DEV_SHA_MAX > 256)
+static const uint32_t digest_len_sha512_init[] = {
+ 0x00000080, 0x00000000, 0x00000000, 0x00000000 };
+static const uint64_t sha384_init[] = {
+ SHA384_H7, SHA384_H6, SHA384_H5, SHA384_H4,
+ SHA384_H3, SHA384_H2, SHA384_H1, SHA384_H0 };
+static const uint64_t sha512_init[] = {
+ SHA512_H7, SHA512_H6, SHA512_H5, SHA512_H4,
+ SHA512_H3, SHA512_H2, SHA512_H1, SHA512_H0 };
+#endif
+
+static void ssi_hash_create_xcbc_setup(
+ struct ahash_request *areq,
+ HwDesc_s desc[],
+ unsigned int *seq_size);
+
+static void ssi_hash_create_cmac_setup(struct ahash_request *areq,
+ HwDesc_s desc[],
+ unsigned int *seq_size);
+
+struct ssi_hash_alg {
+ struct list_head entry;
+ bool synchronize;
+ int hash_mode;
+ int hw_mode;
+ int inter_digestsize;
+ struct ssi_drvdata *drvdata;
+ union {
+ struct ahash_alg ahash_alg;
+ struct shash_alg shash_alg;
+ };
+};
+
+
+struct hash_key_req_ctx {
+ uint32_t keylen;
+ dma_addr_t key_dma_addr;
+};
+
+/* hash per-session context */
+struct ssi_hash_ctx {
+ struct ssi_drvdata *drvdata;
+ /* holds the origin digest; the digest after "setkey" if HMAC,*
+ the initial digest if HASH. */
+ uint8_t digest_buff[SSI_MAX_HASH_DIGEST_SIZE] ____cacheline_aligned;
+ uint8_t opad_tmp_keys_buff[SSI_MAX_HASH_OPAD_TMP_KEYS_SIZE] ____cacheline_aligned;
+ dma_addr_t opad_tmp_keys_dma_addr ____cacheline_aligned;
+ dma_addr_t digest_buff_dma_addr;
+ /* use for hmac with key large then mode block size */
+ struct hash_key_req_ctx key_params;
+ int hash_mode;
+ int hw_mode;
+ int inter_digestsize;
+ struct completion setkey_comp;
+ bool is_hmac;
+};
+
+static const struct crypto_type crypto_shash_type;
+
+static void ssi_hash_create_data_desc(
+ struct ahash_req_ctx *areq_ctx,
+ struct ssi_hash_ctx *ctx,
+ unsigned int flow_mode,HwDesc_s desc[],
+ bool is_not_last_data,
+ unsigned int *seq_size);
+
+static inline void ssi_set_hash_endianity(uint32_t mode, HwDesc_s *desc)
+{
+ if (unlikely((mode == DRV_HASH_MD5) ||
+ (mode == DRV_HASH_SHA384) ||
+ (mode == DRV_HASH_SHA512))) {
+ HW_DESC_SET_BYTES_SWAP(desc, 1);
+ } else {
+ HW_DESC_SET_CIPHER_CONFIG0(desc, HASH_DIGEST_RESULT_LITTLE_ENDIAN);
+ }
+}
+
+static int ssi_hash_map_result(struct device *dev,
+ struct ahash_req_ctx *state,
+ unsigned int digestsize)
+{
+ state->digest_result_dma_addr =
+ dma_map_single(dev, (void *)state->digest_result_buff,
+ digestsize,
+ DMA_BIDIRECTIONAL);
+ if (unlikely(dma_mapping_error(dev, state->digest_result_dma_addr))) {
+ SSI_LOG_ERR("Mapping digest result buffer %u B for DMA failed\n",
+ digestsize);
+ return -ENOMEM;
+ }
+ SSI_UPDATE_DMA_ADDR_TO_48BIT(state->digest_result_dma_addr,
+ digestsize);
+ SSI_LOG_DEBUG("Mapped digest result buffer %u B "
+ "at va=%pK to dma=0x%llX\n",
+ digestsize, state->digest_result_buff,
+ (unsigned long long)state->digest_result_dma_addr);
+
+ return 0;
+}
+
+static int ssi_hash_map_request(struct device *dev,
+ struct ahash_req_ctx *state,
+ struct ssi_hash_ctx *ctx)
+{
+ bool is_hmac = ctx->is_hmac;
+ ssi_sram_addr_t larval_digest_addr = ssi_ahash_get_larval_digest_sram_addr(
+ ctx->drvdata, ctx->hash_mode);
+ struct ssi_crypto_req ssi_req = {};
+ HwDesc_s desc;
+ int rc = -ENOMEM;
+
+ state->buff0 = kzalloc(SSI_MAX_HASH_BLCK_SIZE ,GFP_KERNEL|GFP_DMA);
+ if (!state->buff0) {
+ SSI_LOG_ERR("Allocating buff0 in context failed\n");
+ goto fail0;
+ }
+ state->buff1 = kzalloc(SSI_MAX_HASH_BLCK_SIZE ,GFP_KERNEL|GFP_DMA);
+ if (!state->buff1) {
+ SSI_LOG_ERR("Allocating buff1 in context failed\n");
+ goto fail_buff0;
+ }
+ state->digest_result_buff = kzalloc(SSI_MAX_HASH_DIGEST_SIZE ,GFP_KERNEL|GFP_DMA);
+ if (!state->digest_result_buff) {
+ SSI_LOG_ERR("Allocating digest_result_buff in context failed\n");
+ goto fail_buff1;
+ }
+ state->digest_buff = kzalloc(ctx->inter_digestsize, GFP_KERNEL|GFP_DMA);
+ if (!state->digest_buff) {
+ SSI_LOG_ERR("Allocating digest-buffer in context failed\n");
+ goto fail_digest_result_buff;
+ }
+
+ SSI_LOG_DEBUG("Allocated digest-buffer in context ctx->digest_buff=@%p\n", state->digest_buff);
+ if (ctx->hw_mode != DRV_CIPHER_XCBC_MAC) {
+ state->digest_bytes_len = kzalloc(HASH_LEN_SIZE, GFP_KERNEL|GFP_DMA);
+ if (!state->digest_bytes_len) {
+ SSI_LOG_ERR("Allocating digest-bytes-len in context failed\n");
+ goto fail1;
+ }
+ SSI_LOG_DEBUG("Allocated digest-bytes-len in context state->>digest_bytes_len=@%p\n", state->digest_bytes_len);
+ } else {
+ state->digest_bytes_len = NULL;
+ }
+
+ state->opad_digest_buff = kzalloc(ctx->inter_digestsize, GFP_KERNEL|GFP_DMA);
+ if (!state->opad_digest_buff) {
+ SSI_LOG_ERR("Allocating opad-digest-buffer in context failed\n");
+ goto fail2;
+ }
+ SSI_LOG_DEBUG("Allocated opad-digest-buffer in context state->digest_bytes_len=@%p\n", state->opad_digest_buff);
+
+ state->digest_buff_dma_addr = dma_map_single(dev, (void *)state->digest_buff, ctx->inter_digestsize, DMA_BIDIRECTIONAL);
+ if (dma_mapping_error(dev, state->digest_buff_dma_addr)) {
+ SSI_LOG_ERR("Mapping digest len %d B at va=%pK for DMA failed\n",
+ ctx->inter_digestsize, state->digest_buff);
+ goto fail3;
+ }
+ SSI_UPDATE_DMA_ADDR_TO_48BIT(state->digest_buff_dma_addr,
+ ctx->inter_digestsize);
+ SSI_LOG_DEBUG("Mapped digest %d B at va=%pK to dma=0x%llX\n",
+ ctx->inter_digestsize, state->digest_buff,
+ (unsigned long long)state->digest_buff_dma_addr);
+
+ if (is_hmac) {
+ SSI_RESTORE_DMA_ADDR_TO_48BIT(ctx->digest_buff_dma_addr);
+ dma_sync_single_for_cpu(dev, ctx->digest_buff_dma_addr, ctx->inter_digestsize, DMA_BIDIRECTIONAL);
+ SSI_UPDATE_DMA_ADDR_TO_48BIT(ctx->digest_buff_dma_addr,
+ ctx->inter_digestsize);
+ if ((ctx->hw_mode == DRV_CIPHER_XCBC_MAC) || (ctx->hw_mode == DRV_CIPHER_CMAC)) {
+ memset(state->digest_buff, 0, ctx->inter_digestsize);
+ } else { /*sha*/
+ memcpy(state->digest_buff, ctx->digest_buff, ctx->inter_digestsize);
+#if (DX_DEV_SHA_MAX > 256)
+ if (unlikely((ctx->hash_mode == DRV_HASH_SHA512) || (ctx->hash_mode == DRV_HASH_SHA384))) {
+ memcpy(state->digest_bytes_len, digest_len_sha512_init, HASH_LEN_SIZE);
+ } else {
+ memcpy(state->digest_bytes_len, digest_len_init, HASH_LEN_SIZE);
+ }
+#else
+ memcpy(state->digest_bytes_len, digest_len_init, HASH_LEN_SIZE);
+#endif
+ }
+ SSI_RESTORE_DMA_ADDR_TO_48BIT(state->digest_buff_dma_addr);
+ dma_sync_single_for_device(dev, state->digest_buff_dma_addr, ctx->inter_digestsize, DMA_BIDIRECTIONAL);
+ SSI_UPDATE_DMA_ADDR_TO_48BIT(state->digest_buff_dma_addr,
+ ctx->inter_digestsize);
+
+ if (ctx->hash_mode != DRV_HASH_NULL) {
+ SSI_RESTORE_DMA_ADDR_TO_48BIT(ctx->opad_tmp_keys_dma_addr);
+ dma_sync_single_for_cpu(dev, ctx->opad_tmp_keys_dma_addr, ctx->inter_digestsize, DMA_BIDIRECTIONAL);
+ memcpy(state->opad_digest_buff, ctx->opad_tmp_keys_buff, ctx->inter_digestsize);
+ SSI_UPDATE_DMA_ADDR_TO_48BIT(ctx->opad_tmp_keys_dma_addr,
+ ctx->inter_digestsize);
+ }
+ } else { /*hash*/
+ /* Copy the initial digests if hash flow. The SRAM contains the
+ initial digests in the expected order for all SHA* */
+ HW_DESC_INIT(&desc);
+ HW_DESC_SET_DIN_SRAM(&desc, larval_digest_addr, ctx->inter_digestsize);
+ HW_DESC_SET_DOUT_DLLI(&desc, state->digest_buff_dma_addr, ctx->inter_digestsize, NS_BIT, 0);
+ HW_DESC_SET_FLOW_MODE(&desc, BYPASS);
+
+ rc = send_request(ctx->drvdata, &ssi_req, &desc, 1, 0);
+ if (unlikely(rc != 0)) {
+ SSI_LOG_ERR("send_request() failed (rc=%d)\n", rc);
+ goto fail4;
+ }
+ }
+
+ if (ctx->hw_mode != DRV_CIPHER_XCBC_MAC) {
+ state->digest_bytes_len_dma_addr = dma_map_single(dev, (void *)state->digest_bytes_len, HASH_LEN_SIZE, DMA_BIDIRECTIONAL);
+ if (dma_mapping_error(dev, state->digest_bytes_len_dma_addr)) {
+ SSI_LOG_ERR("Mapping digest len %u B at va=%pK for DMA failed\n",
+ HASH_LEN_SIZE, state->digest_bytes_len);
+ goto fail4;
+ }
+ SSI_UPDATE_DMA_ADDR_TO_48BIT(state->digest_bytes_len_dma_addr,
+ HASH_LEN_SIZE);
+ SSI_LOG_DEBUG("Mapped digest len %u B at va=%pK to dma=0x%llX\n",
+ HASH_LEN_SIZE, state->digest_bytes_len,
+ (unsigned long long)state->digest_bytes_len_dma_addr);
+ } else {
+ state->digest_bytes_len_dma_addr = 0;
+ }
+
+ if (is_hmac && ctx->hash_mode != DRV_HASH_NULL) {
+ state->opad_digest_dma_addr = dma_map_single(dev, (void *)state->opad_digest_buff, ctx->inter_digestsize, DMA_BIDIRECTIONAL);
+ if (dma_mapping_error(dev, state->opad_digest_dma_addr)) {
+ SSI_LOG_ERR("Mapping opad digest %d B at va=%pK for DMA failed\n",
+ ctx->inter_digestsize, state->opad_digest_buff);
+ goto fail5;
+ }
+ SSI_UPDATE_DMA_ADDR_TO_48BIT(state->opad_digest_dma_addr,
+ ctx->inter_digestsize);
+ SSI_LOG_DEBUG("Mapped opad digest %d B at va=%pK to dma=0x%llX\n",
+ ctx->inter_digestsize, state->opad_digest_buff,
+ (unsigned long long)state->opad_digest_dma_addr);
+ } else {
+ state->opad_digest_dma_addr = 0;
+ }
+ state->buff0_cnt = 0;
+ state->buff1_cnt = 0;
+ state->buff_index = 0;
+ state->mlli_params.curr_pool = NULL;
+
+ return 0;
+
+fail5:
+ if (state->digest_bytes_len_dma_addr != 0) {
+ SSI_RESTORE_DMA_ADDR_TO_48BIT(state->digest_bytes_len_dma_addr);
+ dma_unmap_single(dev, state->digest_bytes_len_dma_addr, HASH_LEN_SIZE, DMA_BIDIRECTIONAL);
+ state->digest_bytes_len_dma_addr = 0;
+ }
+fail4:
+ if (state->digest_buff_dma_addr != 0) {
+ SSI_RESTORE_DMA_ADDR_TO_48BIT(state->digest_buff_dma_addr);
+ dma_unmap_single(dev, state->digest_buff_dma_addr, ctx->inter_digestsize, DMA_BIDIRECTIONAL);
+ state->digest_buff_dma_addr = 0;
+ }
+fail3:
+ kfree(state->opad_digest_buff);
+fail2:
+ kfree(state->digest_bytes_len);
+fail1:
+ kfree(state->digest_buff);
+fail_digest_result_buff:
+ if (state->digest_result_buff != NULL) {
+ kfree(state->digest_result_buff);
+ state->digest_result_buff = NULL;
+ }
+fail_buff1:
+ if (state->buff1 != NULL) {
+ kfree(state->buff1);
+ state->buff1 = NULL;
+ }
+fail_buff0:
+ if (state->buff0 != NULL) {
+ kfree(state->buff0);
+ state->buff0 = NULL;
+ }
+fail0:
+ return rc;
+}
+
+static void ssi_hash_unmap_request(struct device *dev,
+ struct ahash_req_ctx *state,
+ struct ssi_hash_ctx *ctx)
+{
+ if (state->digest_buff_dma_addr != 0) {
+ SSI_RESTORE_DMA_ADDR_TO_48BIT(state->digest_buff_dma_addr);
+ dma_unmap_single(dev, state->digest_buff_dma_addr,
+ ctx->inter_digestsize, DMA_BIDIRECTIONAL);
+ SSI_LOG_DEBUG("Unmapped digest-buffer: digest_buff_dma_addr=0x%llX\n",
+ (unsigned long long)state->digest_buff_dma_addr);
+ state->digest_buff_dma_addr = 0;
+ }
+ if (state->digest_bytes_len_dma_addr != 0) {
+ SSI_RESTORE_DMA_ADDR_TO_48BIT(state->digest_bytes_len_dma_addr);
+ dma_unmap_single(dev, state->digest_bytes_len_dma_addr,
+ HASH_LEN_SIZE, DMA_BIDIRECTIONAL);
+ SSI_LOG_DEBUG("Unmapped digest-bytes-len buffer: digest_bytes_len_dma_addr=0x%llX\n",
+ (unsigned long long)state->digest_bytes_len_dma_addr);
+ state->digest_bytes_len_dma_addr = 0;
+ }
+ if (state->opad_digest_dma_addr != 0) {
+ SSI_RESTORE_DMA_ADDR_TO_48BIT(state->opad_digest_dma_addr);
+ dma_unmap_single(dev, state->opad_digest_dma_addr,
+ ctx->inter_digestsize, DMA_BIDIRECTIONAL);
+ SSI_LOG_DEBUG("Unmapped opad-digest: opad_digest_dma_addr=0x%llX\n",
+ (unsigned long long)state->opad_digest_dma_addr);
+ state->opad_digest_dma_addr = 0;
+ }
+
+ kfree(state->opad_digest_buff);
+ kfree(state->digest_bytes_len);
+ kfree(state->digest_buff);
+ kfree(state->digest_result_buff);
+ kfree(state->buff1);
+ kfree(state->buff0);
+}
+
+static void ssi_hash_unmap_result(struct device *dev,
+ struct ahash_req_ctx *state,
+ unsigned int digestsize, u8 *result)
+{
+ if (state->digest_result_dma_addr != 0) {
+ SSI_RESTORE_DMA_ADDR_TO_48BIT(state->digest_result_dma_addr);
+ dma_unmap_single(dev,
+ state->digest_result_dma_addr,
+ digestsize,
+ DMA_BIDIRECTIONAL);
+ SSI_LOG_DEBUG("unmpa digest result buffer "
+ "va (%pK) pa (%llx) len %u\n",
+ state->digest_result_buff,
+ (unsigned long long)state->digest_result_dma_addr,
+ digestsize);
+ memcpy(result,
+ state->digest_result_buff,
+ digestsize);
+ }
+ state->digest_result_dma_addr = 0;
+}
+
+static void ssi_hash_update_complete(struct device *dev, void *ssi_req, void __iomem *cc_base)
+{
+ struct ahash_request *req = (struct ahash_request *)ssi_req;
+ struct ahash_req_ctx *state = ahash_request_ctx(req);
+
+ SSI_LOG_DEBUG("req=%pK\n", req);
+
+ ssi_buffer_mgr_unmap_hash_request(dev, state, req->src, false);
+ req->base.complete(&req->base, 0);
+}
+
+static void ssi_hash_digest_complete(struct device *dev, void *ssi_req, void __iomem *cc_base)
+{
+ struct ahash_request *req = (struct ahash_request *)ssi_req;
+ struct ahash_req_ctx *state = ahash_request_ctx(req);
+ struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+ struct ssi_hash_ctx *ctx = crypto_ahash_ctx(tfm);
+ uint32_t digestsize = crypto_ahash_digestsize(tfm);
+
+ SSI_LOG_DEBUG("req=%pK\n", req);
+
+ ssi_buffer_mgr_unmap_hash_request(dev, state, req->src, false);
+ ssi_hash_unmap_result(dev, state, digestsize, req->result);
+ ssi_hash_unmap_request(dev, state, ctx);
+ req->base.complete(&req->base, 0);
+}
+
+static void ssi_hash_complete(struct device *dev, void *ssi_req, void __iomem *cc_base)
+{
+ struct ahash_request *req = (struct ahash_request *)ssi_req;
+ struct ahash_req_ctx *state = ahash_request_ctx(req);
+ struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+ struct ssi_hash_ctx *ctx = crypto_ahash_ctx(tfm);
+ uint32_t digestsize = crypto_ahash_digestsize(tfm);
+
+ SSI_LOG_DEBUG("req=%pK\n", req);
+
+ ssi_buffer_mgr_unmap_hash_request(dev, state, req->src, false);
+ ssi_hash_unmap_result(dev, state, digestsize, req->result);
+ ssi_hash_unmap_request(dev, state, ctx);
+ req->base.complete(&req->base, 0);
+}
+
+static int ssi_hash_digest(struct ahash_req_ctx *state,
+ struct ssi_hash_ctx *ctx,
+ unsigned int digestsize,
+ struct scatterlist *src,
+ unsigned int nbytes, u8 *result,
+ void *async_req)
+{
+ struct device *dev = &ctx->drvdata->plat_dev->dev;
+ bool is_hmac = ctx->is_hmac;
+ struct ssi_crypto_req ssi_req = {};
+ HwDesc_s desc[SSI_MAX_AHASH_SEQ_LEN];
+ ssi_sram_addr_t larval_digest_addr = ssi_ahash_get_larval_digest_sram_addr(
+ ctx->drvdata, ctx->hash_mode);
+ int idx = 0;
+ int rc = 0;
+
+
+ SSI_LOG_DEBUG("===== %s-digest (%d) ====\n", is_hmac?"hmac":"hash", nbytes);
+
+ CHECK_AND_RETURN_UPON_FIPS_ERROR();
+
+ if (unlikely(ssi_hash_map_request(dev, state, ctx) != 0)) {
+ SSI_LOG_ERR("map_ahash_source() failed\n");
+ return -ENOMEM;
+ }
+
+ if (unlikely(ssi_hash_map_result(dev, state, digestsize) != 0)) {
+ SSI_LOG_ERR("map_ahash_digest() failed\n");
+ return -ENOMEM;
+ }
+
+ if (unlikely(ssi_buffer_mgr_map_hash_request_final(ctx->drvdata, state, src, nbytes, 1) != 0)) {
+ SSI_LOG_ERR("map_ahash_request_final() failed\n");
+ return -ENOMEM;
+ }
+
+ if (async_req) {
+ /* Setup DX request structure */
+ ssi_req.user_cb = (void *)ssi_hash_digest_complete;
+ ssi_req.user_arg = (void *)async_req;
+#ifdef ENABLE_CYCLE_COUNT
+ ssi_req.op_type = STAT_OP_TYPE_ENCODE; /* Use "Encode" stats */
+#endif
+ }
+
+ /* If HMAC then load hash IPAD xor key, if HASH then load initial digest */
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_CIPHER_MODE(&desc[idx], ctx->hw_mode);
+ if (is_hmac) {
+ HW_DESC_SET_DIN_TYPE(&desc[idx], DMA_DLLI, state->digest_buff_dma_addr, ctx->inter_digestsize, NS_BIT);
+ } else {
+ HW_DESC_SET_DIN_SRAM(&desc[idx], larval_digest_addr, ctx->inter_digestsize);
+ }
+ HW_DESC_SET_FLOW_MODE(&desc[idx], S_DIN_to_HASH);
+ HW_DESC_SET_SETUP_MODE(&desc[idx], SETUP_LOAD_STATE0);
+ idx++;
+
+ /* Load the hash current length */
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_CIPHER_MODE(&desc[idx], ctx->hw_mode);
+
+ if (is_hmac) {
+ HW_DESC_SET_DIN_TYPE(&desc[idx], DMA_DLLI, state->digest_bytes_len_dma_addr, HASH_LEN_SIZE, NS_BIT);
+ } else {
+ HW_DESC_SET_DIN_CONST(&desc[idx], 0, HASH_LEN_SIZE);
+ if (likely(nbytes != 0)) {
+ HW_DESC_SET_CIPHER_CONFIG1(&desc[idx], HASH_PADDING_ENABLED);
+ } else {
+ HW_DESC_SET_CIPHER_DO(&desc[idx], DO_PAD);
+ }
+ }
+ HW_DESC_SET_FLOW_MODE(&desc[idx], S_DIN_to_HASH);
+ HW_DESC_SET_SETUP_MODE(&desc[idx], SETUP_LOAD_KEY0);
+ idx++;
+
+ ssi_hash_create_data_desc(state, ctx, DIN_HASH, desc, false, &idx);
+
+ if (is_hmac) {
+ /* HW last hash block padding (aka. "DO_PAD") */
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_CIPHER_MODE(&desc[idx], ctx->hw_mode);
+ HW_DESC_SET_DOUT_DLLI(&desc[idx], state->digest_buff_dma_addr, HASH_LEN_SIZE, NS_BIT, 0);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], S_HASH_to_DOUT);
+ HW_DESC_SET_SETUP_MODE(&desc[idx], SETUP_WRITE_STATE1);
+ HW_DESC_SET_CIPHER_DO(&desc[idx], DO_PAD);
+ idx++;
+
+ /* store the hash digest result in the context */
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_CIPHER_MODE(&desc[idx], ctx->hw_mode);
+ HW_DESC_SET_DOUT_DLLI(&desc[idx], state->digest_buff_dma_addr, digestsize, NS_BIT, 0);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], S_HASH_to_DOUT);
+ ssi_set_hash_endianity(ctx->hash_mode, &desc[idx]);
+ HW_DESC_SET_SETUP_MODE(&desc[idx], SETUP_WRITE_STATE0);
+ idx++;
+
+ /* Loading hash opad xor key state */
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_CIPHER_MODE(&desc[idx], ctx->hw_mode);
+ HW_DESC_SET_DIN_TYPE(&desc[idx], DMA_DLLI, state->opad_digest_dma_addr, ctx->inter_digestsize, NS_BIT);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], S_DIN_to_HASH);
+ HW_DESC_SET_SETUP_MODE(&desc[idx], SETUP_LOAD_STATE0);
+ idx++;
+
+ /* Load the hash current length */
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_CIPHER_MODE(&desc[idx], ctx->hw_mode);
+ HW_DESC_SET_DIN_SRAM(&desc[idx], ssi_ahash_get_initial_digest_len_sram_addr(ctx->drvdata, ctx->hash_mode), HASH_LEN_SIZE);
+ HW_DESC_SET_CIPHER_CONFIG1(&desc[idx], HASH_PADDING_ENABLED);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], S_DIN_to_HASH);
+ HW_DESC_SET_SETUP_MODE(&desc[idx], SETUP_LOAD_KEY0);
+ idx++;
+
+ /* Memory Barrier: wait for IPAD/OPAD axi write to complete */
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_DIN_NO_DMA(&desc[idx], 0, 0xfffff0);
+ HW_DESC_SET_DOUT_NO_DMA(&desc[idx], 0, 0, 1);
+ idx++;
+
+ /* Perform HASH update */
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_DIN_TYPE(&desc[idx], DMA_DLLI, state->digest_buff_dma_addr, digestsize, NS_BIT);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], DIN_HASH);
+ idx++;
+ }
+
+ /* Get final MAC result */
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_CIPHER_MODE(&desc[idx], ctx->hw_mode);
+ HW_DESC_SET_DOUT_DLLI(&desc[idx], state->digest_result_dma_addr, digestsize, NS_BIT, async_req? 1:0); /*TODO*/
+ if (async_req) {
+ HW_DESC_SET_QUEUE_LAST_IND(&desc[idx]);
+ }
+ HW_DESC_SET_FLOW_MODE(&desc[idx], S_HASH_to_DOUT);
+ HW_DESC_SET_SETUP_MODE(&desc[idx], SETUP_WRITE_STATE0);
+ HW_DESC_SET_CIPHER_CONFIG1(&desc[idx], HASH_PADDING_DISABLED);
+ ssi_set_hash_endianity(ctx->hash_mode, &desc[idx]);
+ idx++;
+
+ if (async_req) {
+ rc = send_request(ctx->drvdata, &ssi_req, desc, idx, 1);
+ if (unlikely(rc != -EINPROGRESS)) {
+ SSI_LOG_ERR("send_request() failed (rc=%d)\n", rc);
+ ssi_buffer_mgr_unmap_hash_request(dev, state, src, true);
+ ssi_hash_unmap_result(dev, state, digestsize, result);
+ ssi_hash_unmap_request(dev, state, ctx);
+ }
+ } else {
+ rc = send_request(ctx->drvdata, &ssi_req, desc, idx, 0);
+ if (rc != 0) {
+ SSI_LOG_ERR("send_request() failed (rc=%d)\n", rc);
+ ssi_buffer_mgr_unmap_hash_request(dev, state, src, true);
+ } else {
+ ssi_buffer_mgr_unmap_hash_request(dev, state, src, false);
+ }
+ ssi_hash_unmap_result(dev, state, digestsize, result);
+ ssi_hash_unmap_request(dev, state, ctx);
+ }
+ return rc;
+}
+
+static int ssi_hash_update(struct ahash_req_ctx *state,
+ struct ssi_hash_ctx *ctx,
+ unsigned int block_size,
+ struct scatterlist *src,
+ unsigned int nbytes,
+ void *async_req)
+{
+ struct device *dev = &ctx->drvdata->plat_dev->dev;
+ struct ssi_crypto_req ssi_req = {};
+ HwDesc_s desc[SSI_MAX_AHASH_SEQ_LEN];
+ uint32_t idx = 0;
+ int rc;
+
+ SSI_LOG_DEBUG("===== %s-update (%d) ====\n", ctx->is_hmac ?
+ "hmac":"hash", nbytes);
+
+ CHECK_AND_RETURN_UPON_FIPS_ERROR();
+ if (nbytes == 0) {
+ /* no real updates required */
+ return 0;
+ }
+
+ if (unlikely(rc = ssi_buffer_mgr_map_hash_request_update(ctx->drvdata, state, src, nbytes, block_size))) {
+ if (rc == 1) {
+ SSI_LOG_DEBUG(" data size not require HW update %x\n",
+ nbytes);
+ /* No hardware updates are required */
+ return 0;
+ }
+ SSI_LOG_ERR("map_ahash_request_update() failed\n");
+ return -ENOMEM;
+ }
+
+ if (async_req) {
+ /* Setup DX request structure */
+ ssi_req.user_cb = (void *)ssi_hash_update_complete;
+ ssi_req.user_arg = async_req;
+#ifdef ENABLE_CYCLE_COUNT
+ ssi_req.op_type = STAT_OP_TYPE_ENCODE; /* Use "Encode" stats */
+#endif
+ }
+
+ /* Restore hash digest */
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_CIPHER_MODE(&desc[idx], ctx->hw_mode);
+ HW_DESC_SET_DIN_TYPE(&desc[idx], DMA_DLLI, state->digest_buff_dma_addr, ctx->inter_digestsize, NS_BIT);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], S_DIN_to_HASH);
+ HW_DESC_SET_SETUP_MODE(&desc[idx], SETUP_LOAD_STATE0);
+ idx++;
+ /* Restore hash current length */
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_CIPHER_MODE(&desc[idx], ctx->hw_mode);
+ HW_DESC_SET_DIN_TYPE(&desc[idx], DMA_DLLI, state->digest_bytes_len_dma_addr, HASH_LEN_SIZE, NS_BIT);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], S_DIN_to_HASH);
+ HW_DESC_SET_SETUP_MODE(&desc[idx], SETUP_LOAD_KEY0);
+ idx++;
+
+ ssi_hash_create_data_desc(state, ctx, DIN_HASH, desc, false, &idx);
+
+ /* store the hash digest result in context */
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_CIPHER_MODE(&desc[idx], ctx->hw_mode);
+ HW_DESC_SET_DOUT_DLLI(&desc[idx], state->digest_buff_dma_addr, ctx->inter_digestsize, NS_BIT, 0);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], S_HASH_to_DOUT);
+ HW_DESC_SET_SETUP_MODE(&desc[idx], SETUP_WRITE_STATE0);
+ idx++;
+
+ /* store current hash length in context */
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_CIPHER_MODE(&desc[idx], ctx->hw_mode);
+ HW_DESC_SET_DOUT_DLLI(&desc[idx], state->digest_bytes_len_dma_addr, HASH_LEN_SIZE, NS_BIT, async_req? 1:0);
+ if (async_req) {
+ HW_DESC_SET_QUEUE_LAST_IND(&desc[idx]);
+ }
+ HW_DESC_SET_FLOW_MODE(&desc[idx], S_HASH_to_DOUT);
+ HW_DESC_SET_SETUP_MODE(&desc[idx], SETUP_WRITE_STATE1);
+ idx++;
+
+ if (async_req) {
+ rc = send_request(ctx->drvdata, &ssi_req, desc, idx, 1);
+ if (unlikely(rc != -EINPROGRESS)) {
+ SSI_LOG_ERR("send_request() failed (rc=%d)\n", rc);
+ ssi_buffer_mgr_unmap_hash_request(dev, state, src, true);
+ }
+ } else {
+ rc = send_request(ctx->drvdata, &ssi_req, desc, idx, 0);
+ if (rc != 0) {
+ SSI_LOG_ERR("send_request() failed (rc=%d)\n", rc);
+ ssi_buffer_mgr_unmap_hash_request(dev, state, src, true);
+ } else {
+ ssi_buffer_mgr_unmap_hash_request(dev, state, src, false);
+ }
+ }
+ return rc;
+}
+
+static int ssi_hash_finup(struct ahash_req_ctx *state,
+ struct ssi_hash_ctx *ctx,
+ unsigned int digestsize,
+ struct scatterlist *src,
+ unsigned int nbytes,
+ u8 *result,
+ void *async_req)
+{
+ struct device *dev = &ctx->drvdata->plat_dev->dev;
+ bool is_hmac = ctx->is_hmac;
+ struct ssi_crypto_req ssi_req = {};
+ HwDesc_s desc[SSI_MAX_AHASH_SEQ_LEN];
+ int idx = 0;
+ int rc;
+
+ SSI_LOG_DEBUG("===== %s-finup (%d) ====\n", is_hmac?"hmac":"hash", nbytes);
+
+ CHECK_AND_RETURN_UPON_FIPS_ERROR();
+
+ if (unlikely(ssi_buffer_mgr_map_hash_request_final(ctx->drvdata, state, src , nbytes, 1) != 0)) {
+ SSI_LOG_ERR("map_ahash_request_final() failed\n");
+ return -ENOMEM;
+ }
+ if (unlikely(ssi_hash_map_result(dev, state, digestsize) != 0)) {
+ SSI_LOG_ERR("map_ahash_digest() failed\n");
+ return -ENOMEM;
+ }
+
+ if (async_req) {
+ /* Setup DX request structure */
+ ssi_req.user_cb = (void *)ssi_hash_complete;
+ ssi_req.user_arg = async_req;
+#ifdef ENABLE_CYCLE_COUNT
+ ssi_req.op_type = STAT_OP_TYPE_ENCODE; /* Use "Encode" stats */
+#endif
+ }
+
+ /* Restore hash digest */
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_CIPHER_MODE(&desc[idx], ctx->hw_mode);
+ HW_DESC_SET_DIN_TYPE(&desc[idx], DMA_DLLI, state->digest_buff_dma_addr, ctx->inter_digestsize, NS_BIT);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], S_DIN_to_HASH);
+ HW_DESC_SET_SETUP_MODE(&desc[idx], SETUP_LOAD_STATE0);
+ idx++;
+
+ /* Restore hash current length */
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_CIPHER_MODE(&desc[idx], ctx->hw_mode);
+ HW_DESC_SET_CIPHER_CONFIG1(&desc[idx], HASH_PADDING_ENABLED);
+ HW_DESC_SET_DIN_TYPE(&desc[idx], DMA_DLLI, state->digest_bytes_len_dma_addr, HASH_LEN_SIZE, NS_BIT);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], S_DIN_to_HASH);
+ HW_DESC_SET_SETUP_MODE(&desc[idx], SETUP_LOAD_KEY0);
+ idx++;
+
+ ssi_hash_create_data_desc(state, ctx, DIN_HASH, desc, false, &idx);
+
+ if (is_hmac) {
+ /* Store the hash digest result in the context */
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_CIPHER_MODE(&desc[idx], ctx->hw_mode);
+ HW_DESC_SET_DOUT_DLLI(&desc[idx], state->digest_buff_dma_addr, digestsize, NS_BIT, 0);
+ ssi_set_hash_endianity(ctx->hash_mode,&desc[idx]);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], S_HASH_to_DOUT);
+ HW_DESC_SET_SETUP_MODE(&desc[idx], SETUP_WRITE_STATE0);
+ idx++;
+
+ /* Loading hash OPAD xor key state */
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_CIPHER_MODE(&desc[idx], ctx->hw_mode);
+ HW_DESC_SET_DIN_TYPE(&desc[idx], DMA_DLLI, state->opad_digest_dma_addr, ctx->inter_digestsize, NS_BIT);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], S_DIN_to_HASH);
+ HW_DESC_SET_SETUP_MODE(&desc[idx], SETUP_LOAD_STATE0);
+ idx++;
+
+ /* Load the hash current length */
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_CIPHER_MODE(&desc[idx], ctx->hw_mode);
+ HW_DESC_SET_DIN_SRAM(&desc[idx], ssi_ahash_get_initial_digest_len_sram_addr(ctx->drvdata, ctx->hash_mode), HASH_LEN_SIZE);
+ HW_DESC_SET_CIPHER_CONFIG1(&desc[idx], HASH_PADDING_ENABLED);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], S_DIN_to_HASH);
+ HW_DESC_SET_SETUP_MODE(&desc[idx], SETUP_LOAD_KEY0);
+ idx++;
+
+ /* Memory Barrier: wait for IPAD/OPAD axi write to complete */
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_DIN_NO_DMA(&desc[idx], 0, 0xfffff0);
+ HW_DESC_SET_DOUT_NO_DMA(&desc[idx], 0, 0, 1);
+ idx++;
+
+ /* Perform HASH update on last digest */
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_DIN_TYPE(&desc[idx], DMA_DLLI, state->digest_buff_dma_addr, digestsize, NS_BIT);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], DIN_HASH);
+ idx++;
+ }
+
+ /* Get final MAC result */
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_DOUT_DLLI(&desc[idx], state->digest_result_dma_addr, digestsize, NS_BIT, async_req? 1:0); /*TODO*/
+ if (async_req) {
+ HW_DESC_SET_QUEUE_LAST_IND(&desc[idx]);
+ }
+ HW_DESC_SET_FLOW_MODE(&desc[idx], S_HASH_to_DOUT);
+ HW_DESC_SET_CIPHER_CONFIG1(&desc[idx], HASH_PADDING_DISABLED);
+ HW_DESC_SET_SETUP_MODE(&desc[idx], SETUP_WRITE_STATE0);
+ ssi_set_hash_endianity(ctx->hash_mode,&desc[idx]);
+ HW_DESC_SET_CIPHER_MODE(&desc[idx], ctx->hw_mode);
+ idx++;
+
+ if (async_req) {
+ rc = send_request(ctx->drvdata, &ssi_req, desc, idx, 1);
+ if (unlikely(rc != -EINPROGRESS)) {
+ SSI_LOG_ERR("send_request() failed (rc=%d)\n", rc);
+ ssi_buffer_mgr_unmap_hash_request(dev, state, src, true);
+ ssi_hash_unmap_result(dev, state, digestsize, result);
+ }
+ } else {
+ rc = send_request(ctx->drvdata, &ssi_req, desc, idx, 0);
+ if (rc != 0) {
+ SSI_LOG_ERR("send_request() failed (rc=%d)\n", rc);
+ ssi_buffer_mgr_unmap_hash_request(dev, state, src, true);
+ ssi_hash_unmap_result(dev, state, digestsize, result);
+ } else {
+ ssi_buffer_mgr_unmap_hash_request(dev, state, src, false);
+ ssi_hash_unmap_result(dev, state, digestsize, result);
+ ssi_hash_unmap_request(dev, state, ctx);
+ }
+ }
+ return rc;
+}
+
+static int ssi_hash_final(struct ahash_req_ctx *state,
+ struct ssi_hash_ctx *ctx,
+ unsigned int digestsize,
+ struct scatterlist *src,
+ unsigned int nbytes,
+ u8 *result,
+ void *async_req)
+{
+ struct device *dev = &ctx->drvdata->plat_dev->dev;
+ bool is_hmac = ctx->is_hmac;
+ struct ssi_crypto_req ssi_req = {};
+ HwDesc_s desc[SSI_MAX_AHASH_SEQ_LEN];
+ int idx = 0;
+ int rc;
+
+ SSI_LOG_DEBUG("===== %s-final (%d) ====\n", is_hmac?"hmac":"hash", nbytes);
+
+ CHECK_AND_RETURN_UPON_FIPS_ERROR();
+
+ if (unlikely(ssi_buffer_mgr_map_hash_request_final(ctx->drvdata, state, src, nbytes, 0) != 0)) {
+ SSI_LOG_ERR("map_ahash_request_final() failed\n");
+ return -ENOMEM;
+ }
+
+ if (unlikely(ssi_hash_map_result(dev, state, digestsize) != 0)) {
+ SSI_LOG_ERR("map_ahash_digest() failed\n");
+ return -ENOMEM;
+ }
+
+ if (async_req) {
+ /* Setup DX request structure */
+ ssi_req.user_cb = (void *)ssi_hash_complete;
+ ssi_req.user_arg = async_req;
+#ifdef ENABLE_CYCLE_COUNT
+ ssi_req.op_type = STAT_OP_TYPE_ENCODE; /* Use "Encode" stats */
+#endif
+ }
+
+ /* Restore hash digest */
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_CIPHER_MODE(&desc[idx], ctx->hw_mode);
+ HW_DESC_SET_DIN_TYPE(&desc[idx], DMA_DLLI, state->digest_buff_dma_addr, ctx->inter_digestsize, NS_BIT);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], S_DIN_to_HASH);
+ HW_DESC_SET_SETUP_MODE(&desc[idx], SETUP_LOAD_STATE0);
+ idx++;
+
+ /* Restore hash current length */
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_CIPHER_MODE(&desc[idx], ctx->hw_mode);
+ HW_DESC_SET_CIPHER_CONFIG1(&desc[idx], HASH_PADDING_DISABLED);
+ HW_DESC_SET_DIN_TYPE(&desc[idx], DMA_DLLI, state->digest_bytes_len_dma_addr, HASH_LEN_SIZE, NS_BIT);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], S_DIN_to_HASH);
+ HW_DESC_SET_SETUP_MODE(&desc[idx], SETUP_LOAD_KEY0);
+ idx++;
+
+ ssi_hash_create_data_desc(state, ctx, DIN_HASH, desc, false, &idx);
+
+ /* "DO-PAD" must be enabled only when writing current length to HW */
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_CIPHER_DO(&desc[idx], DO_PAD);
+ HW_DESC_SET_CIPHER_MODE(&desc[idx], ctx->hw_mode);
+ HW_DESC_SET_DOUT_DLLI(&desc[idx], state->digest_bytes_len_dma_addr, HASH_LEN_SIZE, NS_BIT, 0);
+ HW_DESC_SET_SETUP_MODE(&desc[idx], SETUP_WRITE_STATE1);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], S_HASH_to_DOUT);
+ idx++;
+
+ if (is_hmac) {
+ /* Store the hash digest result in the context */
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_CIPHER_MODE(&desc[idx], ctx->hw_mode);
+ HW_DESC_SET_DOUT_DLLI(&desc[idx], state->digest_buff_dma_addr, digestsize, NS_BIT, 0);
+ ssi_set_hash_endianity(ctx->hash_mode,&desc[idx]);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], S_HASH_to_DOUT);
+ HW_DESC_SET_SETUP_MODE(&desc[idx], SETUP_WRITE_STATE0);
+ idx++;
+
+ /* Loading hash OPAD xor key state */
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_CIPHER_MODE(&desc[idx], ctx->hw_mode);
+ HW_DESC_SET_DIN_TYPE(&desc[idx], DMA_DLLI, state->opad_digest_dma_addr, ctx->inter_digestsize, NS_BIT);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], S_DIN_to_HASH);
+ HW_DESC_SET_SETUP_MODE(&desc[idx], SETUP_LOAD_STATE0);
+ idx++;
+
+ /* Load the hash current length */
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_CIPHER_MODE(&desc[idx], ctx->hw_mode);
+ HW_DESC_SET_DIN_SRAM(&desc[idx], ssi_ahash_get_initial_digest_len_sram_addr(ctx->drvdata, ctx->hash_mode), HASH_LEN_SIZE);
+ HW_DESC_SET_CIPHER_CONFIG1(&desc[idx], HASH_PADDING_ENABLED);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], S_DIN_to_HASH);
+ HW_DESC_SET_SETUP_MODE(&desc[idx], SETUP_LOAD_KEY0);
+ idx++;
+
+ /* Memory Barrier: wait for IPAD/OPAD axi write to complete */
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_DIN_NO_DMA(&desc[idx], 0, 0xfffff0);
+ HW_DESC_SET_DOUT_NO_DMA(&desc[idx], 0, 0, 1);
+ idx++;
+
+ /* Perform HASH update on last digest */
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_DIN_TYPE(&desc[idx], DMA_DLLI, state->digest_buff_dma_addr, digestsize, NS_BIT);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], DIN_HASH);
+ idx++;
+ }
+
+ /* Get final MAC result */
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_DOUT_DLLI(&desc[idx], state->digest_result_dma_addr, digestsize, NS_BIT, async_req? 1:0);
+ if (async_req) {
+ HW_DESC_SET_QUEUE_LAST_IND(&desc[idx]);
+ }
+ HW_DESC_SET_FLOW_MODE(&desc[idx], S_HASH_to_DOUT);
+ HW_DESC_SET_CIPHER_CONFIG1(&desc[idx], HASH_PADDING_DISABLED);
+ HW_DESC_SET_SETUP_MODE(&desc[idx], SETUP_WRITE_STATE0);
+ ssi_set_hash_endianity(ctx->hash_mode,&desc[idx]);
+ HW_DESC_SET_CIPHER_MODE(&desc[idx], ctx->hw_mode);
+ idx++;
+
+ if (async_req) {
+ rc = send_request(ctx->drvdata, &ssi_req, desc, idx, 1);
+ if (unlikely(rc != -EINPROGRESS)) {
+ SSI_LOG_ERR("send_request() failed (rc=%d)\n", rc);
+ ssi_buffer_mgr_unmap_hash_request(dev, state, src, true);
+ ssi_hash_unmap_result(dev, state, digestsize, result);
+ }
+ } else {
+ rc = send_request(ctx->drvdata, &ssi_req, desc, idx, 0);
+ if (rc != 0) {
+ SSI_LOG_ERR("send_request() failed (rc=%d)\n", rc);
+ ssi_buffer_mgr_unmap_hash_request(dev, state, src, true);
+ ssi_hash_unmap_result(dev, state, digestsize, result);
+ } else {
+ ssi_buffer_mgr_unmap_hash_request(dev, state, src, false);
+ ssi_hash_unmap_result(dev, state, digestsize, result);
+ ssi_hash_unmap_request(dev, state, ctx);
+ }
+ }
+ return rc;
+}
+
+static int ssi_hash_init(struct ahash_req_ctx *state, struct ssi_hash_ctx *ctx)
+{
+ struct device *dev = &ctx->drvdata->plat_dev->dev;
+ state->xcbc_count = 0;
+
+ CHECK_AND_RETURN_UPON_FIPS_ERROR();
+ ssi_hash_map_request(dev, state, ctx);
+
+ return 0;
+}
+
+#ifdef EXPORT_FIXED
+static int ssi_hash_export(struct ssi_hash_ctx *ctx, void *out)
+{
+ CHECK_AND_RETURN_UPON_FIPS_ERROR();
+ memcpy(out, ctx, sizeof(struct ssi_hash_ctx));
+ return 0;
+}
+
+static int ssi_hash_import(struct ssi_hash_ctx *ctx, const void *in)
+{
+ CHECK_AND_RETURN_UPON_FIPS_ERROR();
+ memcpy(ctx, in, sizeof(struct ssi_hash_ctx));
+ return 0;
+}
+#endif
+
+static int ssi_hash_setkey(void *hash,
+ const u8 *key,
+ unsigned int keylen,
+ bool synchronize)
+{
+ unsigned int hmacPadConst[2] = { HMAC_IPAD_CONST, HMAC_OPAD_CONST };
+ struct ssi_crypto_req ssi_req = {};
+ struct ssi_hash_ctx *ctx = NULL;
+ int blocksize = 0;
+ int digestsize = 0;
+ int i, idx = 0, rc = 0;
+ HwDesc_s desc[SSI_MAX_AHASH_SEQ_LEN];
+ ssi_sram_addr_t larval_addr;
+
+ SSI_LOG_DEBUG("ssi_hash_setkey: start keylen: %d", keylen);
+
+ CHECK_AND_RETURN_UPON_FIPS_ERROR();
+ if (synchronize) {
+ ctx = crypto_shash_ctx(((struct crypto_shash *)hash));
+ blocksize = crypto_tfm_alg_blocksize(&((struct crypto_shash *)hash)->base);
+ digestsize = crypto_shash_digestsize(((struct crypto_shash *)hash));
+ } else {
+ ctx = crypto_ahash_ctx(((struct crypto_ahash *)hash));
+ blocksize = crypto_tfm_alg_blocksize(&((struct crypto_ahash *)hash)->base);
+ digestsize = crypto_ahash_digestsize(((struct crypto_ahash *)hash));
+ }
+
+ larval_addr = ssi_ahash_get_larval_digest_sram_addr(
+ ctx->drvdata, ctx->hash_mode);
+
+ /* The keylen value distinguishes HASH in case keylen is ZERO bytes,
+ any NON-ZERO value utilizes HMAC flow */
+ ctx->key_params.keylen = keylen;
+ ctx->key_params.key_dma_addr = 0;
+ ctx->is_hmac = true;
+
+ if (keylen != 0) {
+ ctx->key_params.key_dma_addr = dma_map_single(
+ &ctx->drvdata->plat_dev->dev,
+ (void *)key,
+ keylen, DMA_TO_DEVICE);
+ if (unlikely(dma_mapping_error(&ctx->drvdata->plat_dev->dev,
+ ctx->key_params.key_dma_addr))) {
+ SSI_LOG_ERR("Mapping key va=0x%p len=%u for"
+ " DMA failed\n", key, keylen);
+ return -ENOMEM;
+ }
+ SSI_UPDATE_DMA_ADDR_TO_48BIT(ctx->key_params.key_dma_addr, keylen);
+ SSI_LOG_DEBUG("mapping key-buffer: key_dma_addr=0x%llX "
+ "keylen=%u\n",
+ (unsigned long long)ctx->key_params.key_dma_addr,
+ ctx->key_params.keylen);
+
+ if (keylen > blocksize) {
+ /* Load hash initial state */
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_CIPHER_MODE(&desc[idx], ctx->hw_mode);
+ HW_DESC_SET_DIN_SRAM(&desc[idx], larval_addr,
+ ctx->inter_digestsize);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], S_DIN_to_HASH);
+ HW_DESC_SET_SETUP_MODE(&desc[idx], SETUP_LOAD_STATE0);
+ idx++;
+
+ /* Load the hash current length*/
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_CIPHER_MODE(&desc[idx], ctx->hw_mode);
+ HW_DESC_SET_DIN_CONST(&desc[idx], 0, HASH_LEN_SIZE);
+ HW_DESC_SET_CIPHER_CONFIG1(&desc[idx], HASH_PADDING_ENABLED);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], S_DIN_to_HASH);
+ HW_DESC_SET_SETUP_MODE(&desc[idx], SETUP_LOAD_KEY0);
+ idx++;
+
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_DIN_TYPE(&desc[idx], DMA_DLLI,
+ ctx->key_params.key_dma_addr,
+ keylen, NS_BIT);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], DIN_HASH);
+ idx++;
+
+ /* Get hashed key */
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_CIPHER_MODE(&desc[idx], ctx->hw_mode);
+ HW_DESC_SET_DOUT_DLLI(&desc[idx], ctx->opad_tmp_keys_dma_addr,
+ digestsize, NS_BIT, 0);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], S_HASH_to_DOUT);
+ HW_DESC_SET_SETUP_MODE(&desc[idx], SETUP_WRITE_STATE0);
+ HW_DESC_SET_CIPHER_CONFIG1(&desc[idx], HASH_PADDING_DISABLED);
+ ssi_set_hash_endianity(ctx->hash_mode,&desc[idx]);
+ idx++;
+
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_DIN_CONST(&desc[idx], 0, (blocksize - digestsize));
+ HW_DESC_SET_FLOW_MODE(&desc[idx], BYPASS);
+ HW_DESC_SET_DOUT_DLLI(&desc[idx],
+ (ctx->opad_tmp_keys_dma_addr + digestsize),
+ (blocksize - digestsize),
+ NS_BIT, 0);
+ idx++;
+ } else {
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_DIN_TYPE(&desc[idx], DMA_DLLI,
+ ctx->key_params.key_dma_addr,
+ keylen, NS_BIT);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], BYPASS);
+ HW_DESC_SET_DOUT_DLLI(&desc[idx],
+ (ctx->opad_tmp_keys_dma_addr),
+ keylen, NS_BIT, 0);
+ idx++;
+
+ if ((blocksize - keylen) != 0) {
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_DIN_CONST(&desc[idx], 0, (blocksize - keylen));
+ HW_DESC_SET_FLOW_MODE(&desc[idx], BYPASS);
+ HW_DESC_SET_DOUT_DLLI(&desc[idx],
+ (ctx->opad_tmp_keys_dma_addr + keylen),
+ (blocksize - keylen),
+ NS_BIT, 0);
+ idx++;
+ }
+ }
+ } else {
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_DIN_CONST(&desc[idx], 0, blocksize);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], BYPASS);
+ HW_DESC_SET_DOUT_DLLI(&desc[idx],
+ (ctx->opad_tmp_keys_dma_addr),
+ blocksize,
+ NS_BIT, 0);
+ idx++;
+ }
+
+ rc = send_request(ctx->drvdata, &ssi_req, desc, idx, 0);
+ if (unlikely(rc != 0)) {
+ SSI_LOG_ERR("send_request() failed (rc=%d)\n", rc);
+ goto out;
+ }
+
+ /* calc derived HMAC key */
+ for (idx = 0, i = 0; i < 2; i++) {
+ /* Load hash initial state */
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_CIPHER_MODE(&desc[idx], ctx->hw_mode);
+ HW_DESC_SET_DIN_SRAM(&desc[idx], larval_addr,
+ ctx->inter_digestsize);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], S_DIN_to_HASH);
+ HW_DESC_SET_SETUP_MODE(&desc[idx], SETUP_LOAD_STATE0);
+ idx++;
+
+ /* Load the hash current length*/
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_CIPHER_MODE(&desc[idx], ctx->hw_mode);
+ HW_DESC_SET_DIN_CONST(&desc[idx], 0, HASH_LEN_SIZE);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], S_DIN_to_HASH);
+ HW_DESC_SET_SETUP_MODE(&desc[idx], SETUP_LOAD_KEY0);
+ idx++;
+
+ /* Prepare ipad key */
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_XOR_VAL(&desc[idx], hmacPadConst[i]);
+ HW_DESC_SET_CIPHER_MODE(&desc[idx], ctx->hw_mode);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], S_DIN_to_HASH);
+ HW_DESC_SET_SETUP_MODE(&desc[idx], SETUP_LOAD_STATE1);
+ idx++;
+
+ /* Perform HASH update */
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_DIN_TYPE(&desc[idx], DMA_DLLI,
+ ctx->opad_tmp_keys_dma_addr,
+ blocksize, NS_BIT);
+ HW_DESC_SET_CIPHER_MODE(&desc[idx],ctx->hw_mode);
+ HW_DESC_SET_XOR_ACTIVE(&desc[idx]);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], DIN_HASH);
+ idx++;
+
+ /* Get the IPAD/OPAD xor key (Note, IPAD is the initial digest of the first HASH "update" state) */
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_CIPHER_MODE(&desc[idx], ctx->hw_mode);
+ if (i > 0) /* Not first iteration */
+ HW_DESC_SET_DOUT_DLLI(&desc[idx],
+ ctx->opad_tmp_keys_dma_addr,
+ ctx->inter_digestsize,
+ NS_BIT, 0);
+ else /* First iteration */
+ HW_DESC_SET_DOUT_DLLI(&desc[idx],
+ ctx->digest_buff_dma_addr,
+ ctx->inter_digestsize,
+ NS_BIT, 0);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], S_HASH_to_DOUT);
+ HW_DESC_SET_SETUP_MODE(&desc[idx], SETUP_WRITE_STATE0);
+ idx++;
+ }
+
+ rc = send_request(ctx->drvdata, &ssi_req, desc, idx, 0);
+
+out:
+ if (rc != 0) {
+ if (synchronize) {
+ crypto_shash_set_flags((struct crypto_shash *)hash, CRYPTO_TFM_RES_BAD_KEY_LEN);
+ } else {
+ crypto_ahash_set_flags((struct crypto_ahash *)hash, CRYPTO_TFM_RES_BAD_KEY_LEN);
+ }
+ }
+
+ if (ctx->key_params.key_dma_addr) {
+ SSI_RESTORE_DMA_ADDR_TO_48BIT(ctx->key_params.key_dma_addr);
+ dma_unmap_single(&ctx->drvdata->plat_dev->dev,
+ ctx->key_params.key_dma_addr,
+ ctx->key_params.keylen, DMA_TO_DEVICE);
+ SSI_LOG_DEBUG("Unmapped key-buffer: key_dma_addr=0x%llX keylen=%u\n",
+ (unsigned long long)ctx->key_params.key_dma_addr,
+ ctx->key_params.keylen);
+ }
+ return rc;
+}
+
+
+static int ssi_xcbc_setkey(struct crypto_ahash *ahash,
+ const u8 *key, unsigned int keylen)
+{
+ struct ssi_crypto_req ssi_req = {};
+ struct ssi_hash_ctx *ctx = crypto_ahash_ctx(ahash);
+ int idx = 0, rc = 0;
+ HwDesc_s desc[SSI_MAX_AHASH_SEQ_LEN];
+
+ SSI_LOG_DEBUG("===== setkey (%d) ====\n", keylen);
+ CHECK_AND_RETURN_UPON_FIPS_ERROR();
+
+ switch (keylen) {
+ case AES_KEYSIZE_128:
+ case AES_KEYSIZE_192:
+ case AES_KEYSIZE_256:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ctx->key_params.keylen = keylen;
+
+ ctx->key_params.key_dma_addr = dma_map_single(
+ &ctx->drvdata->plat_dev->dev,
+ (void *)key,
+ keylen, DMA_TO_DEVICE);
+ if (unlikely(dma_mapping_error(&ctx->drvdata->plat_dev->dev,
+ ctx->key_params.key_dma_addr))) {
+ SSI_LOG_ERR("Mapping key va=0x%p len=%u for"
+ " DMA failed\n", key, keylen);
+ return -ENOMEM;
+ }
+ SSI_UPDATE_DMA_ADDR_TO_48BIT(ctx->key_params.key_dma_addr, keylen);
+ SSI_LOG_DEBUG("mapping key-buffer: key_dma_addr=0x%llX "
+ "keylen=%u\n",
+ (unsigned long long)ctx->key_params.key_dma_addr,
+ ctx->key_params.keylen);
+
+ ctx->is_hmac = true;
+ /* 1. Load the AES key */
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_DIN_TYPE(&desc[idx], DMA_DLLI, ctx->key_params.key_dma_addr, keylen, NS_BIT);
+ HW_DESC_SET_CIPHER_MODE(&desc[idx], DRV_CIPHER_ECB);
+ HW_DESC_SET_CIPHER_CONFIG0(&desc[idx], DRV_CRYPTO_DIRECTION_ENCRYPT);
+ HW_DESC_SET_KEY_SIZE_AES(&desc[idx], keylen);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], S_DIN_to_AES);
+ HW_DESC_SET_SETUP_MODE(&desc[idx], SETUP_LOAD_KEY0);
+ idx++;
+
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_DIN_CONST(&desc[idx], 0x01010101, CC_AES_128_BIT_KEY_SIZE);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], DIN_AES_DOUT);
+ HW_DESC_SET_DOUT_DLLI(&desc[idx], (ctx->opad_tmp_keys_dma_addr +
+ XCBC_MAC_K1_OFFSET),
+ CC_AES_128_BIT_KEY_SIZE, NS_BIT, 0);
+ idx++;
+
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_DIN_CONST(&desc[idx], 0x02020202, CC_AES_128_BIT_KEY_SIZE);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], DIN_AES_DOUT);
+ HW_DESC_SET_DOUT_DLLI(&desc[idx], (ctx->opad_tmp_keys_dma_addr +
+ XCBC_MAC_K2_OFFSET),
+ CC_AES_128_BIT_KEY_SIZE, NS_BIT, 0);
+ idx++;
+
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_DIN_CONST(&desc[idx], 0x03030303, CC_AES_128_BIT_KEY_SIZE);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], DIN_AES_DOUT);
+ HW_DESC_SET_DOUT_DLLI(&desc[idx], (ctx->opad_tmp_keys_dma_addr +
+ XCBC_MAC_K3_OFFSET),
+ CC_AES_128_BIT_KEY_SIZE, NS_BIT, 0);
+ idx++;
+
+ rc = send_request(ctx->drvdata, &ssi_req, desc, idx, 0);
+
+ if (rc != 0)
+ crypto_ahash_set_flags(ahash, CRYPTO_TFM_RES_BAD_KEY_LEN);
+
+ SSI_RESTORE_DMA_ADDR_TO_48BIT(ctx->key_params.key_dma_addr);
+ dma_unmap_single(&ctx->drvdata->plat_dev->dev,
+ ctx->key_params.key_dma_addr,
+ ctx->key_params.keylen, DMA_TO_DEVICE);
+ SSI_LOG_DEBUG("Unmapped key-buffer: key_dma_addr=0x%llX keylen=%u\n",
+ (unsigned long long)ctx->key_params.key_dma_addr,
+ ctx->key_params.keylen);
+
+ return rc;
+}
+#if SSI_CC_HAS_CMAC
+static int ssi_cmac_setkey(struct crypto_ahash *ahash,
+ const u8 *key, unsigned int keylen)
+{
+ struct ssi_hash_ctx *ctx = crypto_ahash_ctx(ahash);
+ DECL_CYCLE_COUNT_RESOURCES;
+ SSI_LOG_DEBUG("===== setkey (%d) ====\n", keylen);
+ CHECK_AND_RETURN_UPON_FIPS_ERROR();
+
+ ctx->is_hmac = true;
+
+ switch (keylen) {
+ case AES_KEYSIZE_128:
+ case AES_KEYSIZE_192:
+ case AES_KEYSIZE_256:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ctx->key_params.keylen = keylen;
+
+ /* STAT_PHASE_1: Copy key to ctx */
+ START_CYCLE_COUNT();
+
+ SSI_RESTORE_DMA_ADDR_TO_48BIT(ctx->opad_tmp_keys_dma_addr);
+ dma_sync_single_for_cpu(&ctx->drvdata->plat_dev->dev,
+ ctx->opad_tmp_keys_dma_addr,
+ keylen, DMA_TO_DEVICE);
+
+ memcpy(ctx->opad_tmp_keys_buff, key, keylen);
+ if (keylen == 24)
+ memset(ctx->opad_tmp_keys_buff + 24, 0, CC_AES_KEY_SIZE_MAX - 24);
+
+ dma_sync_single_for_device(&ctx->drvdata->plat_dev->dev,
+ ctx->opad_tmp_keys_dma_addr,
+ keylen, DMA_TO_DEVICE);
+ SSI_UPDATE_DMA_ADDR_TO_48BIT(ctx->opad_tmp_keys_dma_addr, keylen);
+
+ ctx->key_params.keylen = keylen;
+
+ END_CYCLE_COUNT(STAT_OP_TYPE_SETKEY, STAT_PHASE_1);
+
+ return 0;
+}
+#endif
+
+static void ssi_hash_free_ctx(struct ssi_hash_ctx *ctx)
+{
+ struct device *dev = &ctx->drvdata->plat_dev->dev;
+
+ if (ctx->digest_buff_dma_addr != 0) {
+ SSI_RESTORE_DMA_ADDR_TO_48BIT(ctx->digest_buff_dma_addr);
+ dma_unmap_single(dev, ctx->digest_buff_dma_addr,
+ sizeof(ctx->digest_buff), DMA_BIDIRECTIONAL);
+ SSI_LOG_DEBUG("Unmapped digest-buffer: "
+ "digest_buff_dma_addr=0x%llX\n",
+ (unsigned long long)ctx->digest_buff_dma_addr);
+ ctx->digest_buff_dma_addr = 0;
+ }
+ if (ctx->opad_tmp_keys_dma_addr != 0) {
+ SSI_RESTORE_DMA_ADDR_TO_48BIT(ctx->opad_tmp_keys_dma_addr);
+ dma_unmap_single(dev, ctx->opad_tmp_keys_dma_addr,
+ sizeof(ctx->opad_tmp_keys_buff),
+ DMA_BIDIRECTIONAL);
+ SSI_LOG_DEBUG("Unmapped opad-digest: "
+ "opad_tmp_keys_dma_addr=0x%llX\n",
+ (unsigned long long)ctx->opad_tmp_keys_dma_addr);
+ ctx->opad_tmp_keys_dma_addr = 0;
+ }
+
+ ctx->key_params.keylen = 0;
+
+}
+
+
+static int ssi_hash_alloc_ctx(struct ssi_hash_ctx *ctx)
+{
+ struct device *dev = &ctx->drvdata->plat_dev->dev;
+
+ ctx->key_params.keylen = 0;
+
+ ctx->digest_buff_dma_addr = dma_map_single(dev, (void *)ctx->digest_buff, sizeof(ctx->digest_buff), DMA_BIDIRECTIONAL);
+ if (dma_mapping_error(dev, ctx->digest_buff_dma_addr)) {
+ SSI_LOG_ERR("Mapping digest len %zu B at va=%pK for DMA failed\n",
+ sizeof(ctx->digest_buff), ctx->digest_buff);
+ goto fail;
+ }
+ SSI_UPDATE_DMA_ADDR_TO_48BIT(ctx->digest_buff_dma_addr,
+ sizeof(ctx->digest_buff));
+ SSI_LOG_DEBUG("Mapped digest %zu B at va=%pK to dma=0x%llX\n",
+ sizeof(ctx->digest_buff), ctx->digest_buff,
+ (unsigned long long)ctx->digest_buff_dma_addr);
+
+ ctx->opad_tmp_keys_dma_addr = dma_map_single(dev, (void *)ctx->opad_tmp_keys_buff, sizeof(ctx->opad_tmp_keys_buff), DMA_BIDIRECTIONAL);
+ if (dma_mapping_error(dev, ctx->opad_tmp_keys_dma_addr)) {
+ SSI_LOG_ERR("Mapping opad digest %zu B at va=%pK for DMA failed\n",
+ sizeof(ctx->opad_tmp_keys_buff),
+ ctx->opad_tmp_keys_buff);
+ goto fail;
+ }
+ SSI_UPDATE_DMA_ADDR_TO_48BIT(ctx->opad_tmp_keys_dma_addr,
+ sizeof(ctx->opad_tmp_keys_buff));
+ SSI_LOG_DEBUG("Mapped opad_tmp_keys %zu B at va=%pK to dma=0x%llX\n",
+ sizeof(ctx->opad_tmp_keys_buff), ctx->opad_tmp_keys_buff,
+ (unsigned long long)ctx->opad_tmp_keys_dma_addr);
+
+ ctx->is_hmac = false;
+ return 0;
+
+fail:
+ ssi_hash_free_ctx(ctx);
+ return -ENOMEM;
+}
+
+static int ssi_shash_cra_init(struct crypto_tfm *tfm)
+{
+ struct ssi_hash_ctx *ctx = crypto_tfm_ctx(tfm);
+ struct shash_alg * shash_alg =
+ container_of(tfm->__crt_alg, struct shash_alg, base);
+ struct ssi_hash_alg *ssi_alg =
+ container_of(shash_alg, struct ssi_hash_alg, shash_alg);
+
+ CHECK_AND_RETURN_UPON_FIPS_ERROR();
+ ctx->hash_mode = ssi_alg->hash_mode;
+ ctx->hw_mode = ssi_alg->hw_mode;
+ ctx->inter_digestsize = ssi_alg->inter_digestsize;
+ ctx->drvdata = ssi_alg->drvdata;
+
+ return ssi_hash_alloc_ctx(ctx);
+}
+
+static int ssi_ahash_cra_init(struct crypto_tfm *tfm)
+{
+ struct ssi_hash_ctx *ctx = crypto_tfm_ctx(tfm);
+ struct hash_alg_common * hash_alg_common =
+ container_of(tfm->__crt_alg, struct hash_alg_common, base);
+ struct ahash_alg *ahash_alg =
+ container_of(hash_alg_common, struct ahash_alg, halg);
+ struct ssi_hash_alg *ssi_alg =
+ container_of(ahash_alg, struct ssi_hash_alg, ahash_alg);
+
+
+ CHECK_AND_RETURN_UPON_FIPS_ERROR();
+ crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm),
+ sizeof(struct ahash_req_ctx));
+
+ ctx->hash_mode = ssi_alg->hash_mode;
+ ctx->hw_mode = ssi_alg->hw_mode;
+ ctx->inter_digestsize = ssi_alg->inter_digestsize;
+ ctx->drvdata = ssi_alg->drvdata;
+
+ return ssi_hash_alloc_ctx(ctx);
+}
+
+static void ssi_hash_cra_exit(struct crypto_tfm *tfm)
+{
+ struct ssi_hash_ctx *ctx = crypto_tfm_ctx(tfm);
+
+ SSI_LOG_DEBUG("ssi_hash_cra_exit");
+ ssi_hash_free_ctx(ctx);
+}
+
+static int ssi_mac_update(struct ahash_request *req)
+{
+ struct ahash_req_ctx *state = ahash_request_ctx(req);
+ struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+ struct ssi_hash_ctx *ctx = crypto_ahash_ctx(tfm);
+ struct device *dev = &ctx->drvdata->plat_dev->dev;
+ unsigned int block_size = crypto_tfm_alg_blocksize(&tfm->base);
+ struct ssi_crypto_req ssi_req = {};
+ HwDesc_s desc[SSI_MAX_AHASH_SEQ_LEN];
+ int rc;
+ uint32_t idx = 0;
+
+ CHECK_AND_RETURN_UPON_FIPS_ERROR();
+ if (req->nbytes == 0) {
+ /* no real updates required */
+ return 0;
+ }
+
+ state->xcbc_count++;
+
+ if (unlikely(rc = ssi_buffer_mgr_map_hash_request_update(ctx->drvdata, state, req->src, req->nbytes, block_size))) {
+ if (rc == 1) {
+ SSI_LOG_DEBUG(" data size not require HW update %x\n",
+ req->nbytes);
+ /* No hardware updates are required */
+ return 0;
+ }
+ SSI_LOG_ERR("map_ahash_request_update() failed\n");
+ return -ENOMEM;
+ }
+
+ if (ctx->hw_mode == DRV_CIPHER_XCBC_MAC) {
+ ssi_hash_create_xcbc_setup(req, desc, &idx);
+ } else {
+ ssi_hash_create_cmac_setup(req, desc, &idx);
+ }
+
+ ssi_hash_create_data_desc(state, ctx, DIN_AES_DOUT, desc, true, &idx);
+
+ /* store the hash digest result in context */
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_CIPHER_MODE(&desc[idx], ctx->hw_mode);
+ HW_DESC_SET_DOUT_DLLI(&desc[idx], state->digest_buff_dma_addr, ctx->inter_digestsize, NS_BIT, 1);
+ HW_DESC_SET_QUEUE_LAST_IND(&desc[idx]);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], S_AES_to_DOUT);
+ HW_DESC_SET_SETUP_MODE(&desc[idx], SETUP_WRITE_STATE0);
+ idx++;
+
+ /* Setup DX request structure */
+ ssi_req.user_cb = (void *)ssi_hash_update_complete;
+ ssi_req.user_arg = (void *)req;
+#ifdef ENABLE_CYCLE_COUNT
+ ssi_req.op_type = STAT_OP_TYPE_ENCODE; /* Use "Encode" stats */
+#endif
+
+ rc = send_request(ctx->drvdata, &ssi_req, desc, idx, 1);
+ if (unlikely(rc != -EINPROGRESS)) {
+ SSI_LOG_ERR("send_request() failed (rc=%d)\n", rc);
+ ssi_buffer_mgr_unmap_hash_request(dev, state, req->src, true);
+ }
+ return rc;
+}
+
+static int ssi_mac_final(struct ahash_request *req)
+{
+ struct ahash_req_ctx *state = ahash_request_ctx(req);
+ struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+ struct ssi_hash_ctx *ctx = crypto_ahash_ctx(tfm);
+ struct device *dev = &ctx->drvdata->plat_dev->dev;
+ struct ssi_crypto_req ssi_req = {};
+ HwDesc_s desc[SSI_MAX_AHASH_SEQ_LEN];
+ int idx = 0;
+ int rc = 0;
+ uint32_t keySize, keyLen;
+ uint32_t digestsize = crypto_ahash_digestsize(tfm);
+
+ uint32_t rem_cnt = state->buff_index ? state->buff1_cnt :
+ state->buff0_cnt;
+
+
+ CHECK_AND_RETURN_UPON_FIPS_ERROR();
+ if (ctx->hw_mode == DRV_CIPHER_XCBC_MAC) {
+ keySize = CC_AES_128_BIT_KEY_SIZE;
+ keyLen = CC_AES_128_BIT_KEY_SIZE;
+ } else {
+ keySize = (ctx->key_params.keylen == 24) ? AES_MAX_KEY_SIZE : ctx->key_params.keylen;
+ keyLen = ctx->key_params.keylen;
+ }
+
+ SSI_LOG_DEBUG("===== final xcbc reminder (%d) ====\n", rem_cnt);
+
+ if (unlikely(ssi_buffer_mgr_map_hash_request_final(ctx->drvdata, state, req->src, req->nbytes, 0) != 0)) {
+ SSI_LOG_ERR("map_ahash_request_final() failed\n");
+ return -ENOMEM;
+ }
+
+ if (unlikely(ssi_hash_map_result(dev, state, digestsize) != 0)) {
+ SSI_LOG_ERR("map_ahash_digest() failed\n");
+ return -ENOMEM;
+ }
+
+ /* Setup DX request structure */
+ ssi_req.user_cb = (void *)ssi_hash_complete;
+ ssi_req.user_arg = (void *)req;
+#ifdef ENABLE_CYCLE_COUNT
+ ssi_req.op_type = STAT_OP_TYPE_ENCODE; /* Use "Encode" stats */
+#endif
+
+ if (state->xcbc_count && (rem_cnt == 0)) {
+ /* Load key for ECB decryption */
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_CIPHER_MODE(&desc[idx], DRV_CIPHER_ECB);
+ HW_DESC_SET_CIPHER_CONFIG0(&desc[idx], DRV_CRYPTO_DIRECTION_DECRYPT);
+ HW_DESC_SET_DIN_TYPE(&desc[idx], DMA_DLLI,
+ (ctx->opad_tmp_keys_dma_addr +
+ XCBC_MAC_K1_OFFSET),
+ keySize, NS_BIT);
+ HW_DESC_SET_KEY_SIZE_AES(&desc[idx], keyLen);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], S_DIN_to_AES);
+ HW_DESC_SET_SETUP_MODE(&desc[idx], SETUP_LOAD_KEY0);
+ idx++;
+
+
+ /* Initiate decryption of block state to previous block_state-XOR-M[n] */
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_DIN_TYPE(&desc[idx], DMA_DLLI, state->digest_buff_dma_addr, CC_AES_BLOCK_SIZE, NS_BIT);
+ HW_DESC_SET_DOUT_DLLI(&desc[idx], state->digest_buff_dma_addr, CC_AES_BLOCK_SIZE, NS_BIT,0);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], DIN_AES_DOUT);
+ idx++;
+
+ /* Memory Barrier: wait for axi write to complete */
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_DIN_NO_DMA(&desc[idx], 0, 0xfffff0);
+ HW_DESC_SET_DOUT_NO_DMA(&desc[idx], 0, 0, 1);
+ idx++;
+ }
+
+ if (ctx->hw_mode == DRV_CIPHER_XCBC_MAC) {
+ ssi_hash_create_xcbc_setup(req, desc, &idx);
+ } else {
+ ssi_hash_create_cmac_setup(req, desc, &idx);
+ }
+
+ if (state->xcbc_count == 0) {
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_CIPHER_MODE(&desc[idx], ctx->hw_mode);
+ HW_DESC_SET_KEY_SIZE_AES(&desc[idx], keyLen);
+ HW_DESC_SET_CMAC_SIZE0_MODE(&desc[idx]);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], S_DIN_to_AES);
+ idx++;
+ } else if (rem_cnt > 0) {
+ ssi_hash_create_data_desc(state, ctx, DIN_AES_DOUT, desc, false, &idx);
+ } else {
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_DIN_CONST(&desc[idx], 0x00, CC_AES_BLOCK_SIZE);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], DIN_AES_DOUT);
+ idx++;
+ }
+
+ /* Get final MAC result */
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_DOUT_DLLI(&desc[idx], state->digest_result_dma_addr, digestsize, NS_BIT, 1); /*TODO*/
+ HW_DESC_SET_QUEUE_LAST_IND(&desc[idx]);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], S_AES_to_DOUT);
+ HW_DESC_SET_SETUP_MODE(&desc[idx], SETUP_WRITE_STATE0);
+ HW_DESC_SET_CIPHER_MODE(&desc[idx], ctx->hw_mode);
+ idx++;
+
+ rc = send_request(ctx->drvdata, &ssi_req, desc, idx, 1);
+ if (unlikely(rc != -EINPROGRESS)) {
+ SSI_LOG_ERR("send_request() failed (rc=%d)\n", rc);
+ ssi_buffer_mgr_unmap_hash_request(dev, state, req->src, true);
+ ssi_hash_unmap_result(dev, state, digestsize, req->result);
+ }
+ return rc;
+}
+
+static int ssi_mac_finup(struct ahash_request *req)
+{
+ struct ahash_req_ctx *state = ahash_request_ctx(req);
+ struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+ struct ssi_hash_ctx *ctx = crypto_ahash_ctx(tfm);
+ struct device *dev = &ctx->drvdata->plat_dev->dev;
+ struct ssi_crypto_req ssi_req = {};
+ HwDesc_s desc[SSI_MAX_AHASH_SEQ_LEN];
+ int idx = 0;
+ int rc = 0;
+ uint32_t key_len = 0;
+ uint32_t digestsize = crypto_ahash_digestsize(tfm);
+
+ SSI_LOG_DEBUG("===== finup xcbc(%d) ====\n", req->nbytes);
+ CHECK_AND_RETURN_UPON_FIPS_ERROR();
+ if (state->xcbc_count > 0 && req->nbytes == 0) {
+ SSI_LOG_DEBUG("No data to update. Call to fdx_mac_final \n");
+ return ssi_mac_final(req);
+ }
+
+ if (unlikely(ssi_buffer_mgr_map_hash_request_final(ctx->drvdata, state, req->src, req->nbytes, 1) != 0)) {
+ SSI_LOG_ERR("map_ahash_request_final() failed\n");
+ return -ENOMEM;
+ }
+ if (unlikely(ssi_hash_map_result(dev, state, digestsize) != 0)) {
+ SSI_LOG_ERR("map_ahash_digest() failed\n");
+ return -ENOMEM;
+ }
+
+ /* Setup DX request structure */
+ ssi_req.user_cb = (void *)ssi_hash_complete;
+ ssi_req.user_arg = (void *)req;
+#ifdef ENABLE_CYCLE_COUNT
+ ssi_req.op_type = STAT_OP_TYPE_ENCODE; /* Use "Encode" stats */
+#endif
+
+ if (ctx->hw_mode == DRV_CIPHER_XCBC_MAC) {
+ key_len = CC_AES_128_BIT_KEY_SIZE;
+ ssi_hash_create_xcbc_setup(req, desc, &idx);
+ } else {
+ key_len = ctx->key_params.keylen;
+ ssi_hash_create_cmac_setup(req, desc, &idx);
+ }
+
+ if (req->nbytes == 0) {
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_CIPHER_MODE(&desc[idx], ctx->hw_mode);
+ HW_DESC_SET_KEY_SIZE_AES(&desc[idx], key_len);
+ HW_DESC_SET_CMAC_SIZE0_MODE(&desc[idx]);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], S_DIN_to_AES);
+ idx++;
+ } else {
+ ssi_hash_create_data_desc(state, ctx, DIN_AES_DOUT, desc, false, &idx);
+ }
+
+ /* Get final MAC result */
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_DOUT_DLLI(&desc[idx], state->digest_result_dma_addr, digestsize, NS_BIT, 1); /*TODO*/
+ HW_DESC_SET_QUEUE_LAST_IND(&desc[idx]);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], S_AES_to_DOUT);
+ HW_DESC_SET_SETUP_MODE(&desc[idx], SETUP_WRITE_STATE0);
+ HW_DESC_SET_CIPHER_MODE(&desc[idx], ctx->hw_mode);
+ idx++;
+
+ rc = send_request(ctx->drvdata, &ssi_req, desc, idx, 1);
+ if (unlikely(rc != -EINPROGRESS)) {
+ SSI_LOG_ERR("send_request() failed (rc=%d)\n", rc);
+ ssi_buffer_mgr_unmap_hash_request(dev, state, req->src, true);
+ ssi_hash_unmap_result(dev, state, digestsize, req->result);
+ }
+ return rc;
+}
+
+static int ssi_mac_digest(struct ahash_request *req)
+{
+ struct ahash_req_ctx *state = ahash_request_ctx(req);
+ struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+ struct ssi_hash_ctx *ctx = crypto_ahash_ctx(tfm);
+ struct device *dev = &ctx->drvdata->plat_dev->dev;
+ uint32_t digestsize = crypto_ahash_digestsize(tfm);
+ struct ssi_crypto_req ssi_req = {};
+ HwDesc_s desc[SSI_MAX_AHASH_SEQ_LEN];
+ uint32_t keyLen;
+ int idx = 0;
+ int rc;
+
+ SSI_LOG_DEBUG("===== -digest mac (%d) ====\n", req->nbytes);
+ CHECK_AND_RETURN_UPON_FIPS_ERROR();
+
+ if (unlikely(ssi_hash_map_request(dev, state, ctx) != 0)) {
+ SSI_LOG_ERR("map_ahash_source() failed\n");
+ return -ENOMEM;
+ }
+ if (unlikely(ssi_hash_map_result(dev, state, digestsize) != 0)) {
+ SSI_LOG_ERR("map_ahash_digest() failed\n");
+ return -ENOMEM;
+ }
+
+ if (unlikely(ssi_buffer_mgr_map_hash_request_final(ctx->drvdata, state, req->src, req->nbytes, 1) != 0)) {
+ SSI_LOG_ERR("map_ahash_request_final() failed\n");
+ return -ENOMEM;
+ }
+
+ /* Setup DX request structure */
+ ssi_req.user_cb = (void *)ssi_hash_digest_complete;
+ ssi_req.user_arg = (void *)req;
+#ifdef ENABLE_CYCLE_COUNT
+ ssi_req.op_type = STAT_OP_TYPE_ENCODE; /* Use "Encode" stats */
+#endif
+
+
+ if (ctx->hw_mode == DRV_CIPHER_XCBC_MAC) {
+ keyLen = CC_AES_128_BIT_KEY_SIZE;
+ ssi_hash_create_xcbc_setup(req, desc, &idx);
+ } else {
+ keyLen = ctx->key_params.keylen;
+ ssi_hash_create_cmac_setup(req, desc, &idx);
+ }
+
+ if (req->nbytes == 0) {
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_CIPHER_MODE(&desc[idx], ctx->hw_mode);
+ HW_DESC_SET_KEY_SIZE_AES(&desc[idx], keyLen);
+ HW_DESC_SET_CMAC_SIZE0_MODE(&desc[idx]);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], S_DIN_to_AES);
+ idx++;
+ } else {
+ ssi_hash_create_data_desc(state, ctx, DIN_AES_DOUT, desc, false, &idx);
+ }
+
+ /* Get final MAC result */
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_DOUT_DLLI(&desc[idx], state->digest_result_dma_addr, CC_AES_BLOCK_SIZE, NS_BIT,1);
+ HW_DESC_SET_QUEUE_LAST_IND(&desc[idx]);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], S_AES_to_DOUT);
+ HW_DESC_SET_SETUP_MODE(&desc[idx], SETUP_WRITE_STATE0);
+ HW_DESC_SET_CIPHER_CONFIG0(&desc[idx],DESC_DIRECTION_ENCRYPT_ENCRYPT);
+ HW_DESC_SET_CIPHER_MODE(&desc[idx], ctx->hw_mode);
+ idx++;
+
+ rc = send_request(ctx->drvdata, &ssi_req, desc, idx, 1);
+ if (unlikely(rc != -EINPROGRESS)) {
+ SSI_LOG_ERR("send_request() failed (rc=%d)\n", rc);
+ ssi_buffer_mgr_unmap_hash_request(dev, state, req->src, true);
+ ssi_hash_unmap_result(dev, state, digestsize, req->result);
+ ssi_hash_unmap_request(dev, state, ctx);
+ }
+ return rc;
+}
+
+//shash wrap functions
+#ifdef SYNC_ALGS
+static int ssi_shash_digest(struct shash_desc *desc,
+ const u8 *data, unsigned int len, u8 *out)
+{
+ struct ahash_req_ctx *state = shash_desc_ctx(desc);
+ struct crypto_shash *tfm = desc->tfm;
+ struct ssi_hash_ctx *ctx = crypto_shash_ctx(tfm);
+ uint32_t digestsize = crypto_shash_digestsize(tfm);
+ struct scatterlist src;
+
+ if (len == 0) {
+ return ssi_hash_digest(state, ctx, digestsize, NULL, 0, out, NULL);
+ }
+
+ /* sg_init_one may crash when len is 0 (depends on kernel configuration) */
+ sg_init_one(&src, (const void *)data, len);
+
+ return ssi_hash_digest(state, ctx, digestsize, &src, len, out, NULL);
+}
+
+static int ssi_shash_update(struct shash_desc *desc,
+ const u8 *data, unsigned int len)
+{
+ struct ahash_req_ctx *state = shash_desc_ctx(desc);
+ struct crypto_shash *tfm = desc->tfm;
+ struct ssi_hash_ctx *ctx = crypto_shash_ctx(tfm);
+ uint32_t blocksize = crypto_tfm_alg_blocksize(&tfm->base);
+ struct scatterlist src;
+
+ sg_init_one(&src, (const void *)data, len);
+
+ return ssi_hash_update(state, ctx, blocksize, &src, len, NULL);
+}
+
+static int ssi_shash_finup(struct shash_desc *desc,
+ const u8 *data, unsigned int len, u8 *out)
+{
+ struct ahash_req_ctx *state = shash_desc_ctx(desc);
+ struct crypto_shash *tfm = desc->tfm;
+ struct ssi_hash_ctx *ctx = crypto_shash_ctx(tfm);
+ uint32_t digestsize = crypto_shash_digestsize(tfm);
+ struct scatterlist src;
+
+ sg_init_one(&src, (const void *)data, len);
+
+ return ssi_hash_finup(state, ctx, digestsize, &src, len, out, NULL);
+}
+
+static int ssi_shash_final(struct shash_desc *desc, u8 *out)
+{
+ struct ahash_req_ctx *state = shash_desc_ctx(desc);
+ struct crypto_shash *tfm = desc->tfm;
+ struct ssi_hash_ctx *ctx = crypto_shash_ctx(tfm);
+ uint32_t digestsize = crypto_shash_digestsize(tfm);
+
+ return ssi_hash_final(state, ctx, digestsize, NULL, 0, out, NULL);
+}
+
+static int ssi_shash_init(struct shash_desc *desc)
+{
+ struct ahash_req_ctx *state = shash_desc_ctx(desc);
+ struct crypto_shash *tfm = desc->tfm;
+ struct ssi_hash_ctx *ctx = crypto_shash_ctx(tfm);
+
+ return ssi_hash_init(state, ctx);
+}
+
+#ifdef EXPORT_FIXED
+static int ssi_shash_export(struct shash_desc *desc, void *out)
+{
+ struct crypto_shash *tfm = desc->tfm;
+ struct ssi_hash_ctx *ctx = crypto_shash_ctx(tfm);
+
+ return ssi_hash_export(ctx, out);
+}
+
+static int ssi_shash_import(struct shash_desc *desc, const void *in)
+{
+ struct crypto_shash *tfm = desc->tfm;
+ struct ssi_hash_ctx *ctx = crypto_shash_ctx(tfm);
+
+ return ssi_hash_import(ctx, in);
+}
+#endif
+
+static int ssi_shash_setkey(struct crypto_shash *tfm,
+ const u8 *key, unsigned int keylen)
+{
+ return ssi_hash_setkey((void *) tfm, key, keylen, true);
+}
+
+#endif /* SYNC_ALGS */
+
+//ahash wrap functions
+static int ssi_ahash_digest(struct ahash_request *req)
+{
+ struct ahash_req_ctx *state = ahash_request_ctx(req);
+ struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+ struct ssi_hash_ctx *ctx = crypto_ahash_ctx(tfm);
+ uint32_t digestsize = crypto_ahash_digestsize(tfm);
+
+ return ssi_hash_digest(state, ctx, digestsize, req->src, req->nbytes, req->result, (void *)req);
+}
+
+static int ssi_ahash_update(struct ahash_request *req)
+{
+ struct ahash_req_ctx *state = ahash_request_ctx(req);
+ struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+ struct ssi_hash_ctx *ctx = crypto_ahash_ctx(tfm);
+ unsigned int block_size = crypto_tfm_alg_blocksize(&tfm->base);
+
+ return ssi_hash_update(state, ctx, block_size, req->src, req->nbytes, (void *)req);
+}
+
+static int ssi_ahash_finup(struct ahash_request *req)
+{
+ struct ahash_req_ctx *state = ahash_request_ctx(req);
+ struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+ struct ssi_hash_ctx *ctx = crypto_ahash_ctx(tfm);
+ uint32_t digestsize = crypto_ahash_digestsize(tfm);
+
+ return ssi_hash_finup(state, ctx, digestsize, req->src, req->nbytes, req->result, (void *)req);
+}
+
+static int ssi_ahash_final(struct ahash_request *req)
+{
+ struct ahash_req_ctx *state = ahash_request_ctx(req);
+ struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+ struct ssi_hash_ctx *ctx = crypto_ahash_ctx(tfm);
+ uint32_t digestsize = crypto_ahash_digestsize(tfm);
+
+ return ssi_hash_final(state, ctx, digestsize, req->src, req->nbytes, req->result, (void *)req);
+}
+
+static int ssi_ahash_init(struct ahash_request *req)
+{
+ struct ahash_req_ctx *state = ahash_request_ctx(req);
+ struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+ struct ssi_hash_ctx *ctx = crypto_ahash_ctx(tfm);
+
+ SSI_LOG_DEBUG("===== init (%d) ====\n", req->nbytes);
+
+ return ssi_hash_init(state, ctx);
+}
+
+#ifdef EXPORT_FIXED
+static int ssi_ahash_export(struct ahash_request *req, void *out)
+{
+ struct crypto_ahash *ahash = crypto_ahash_reqtfm(req);
+ struct ssi_hash_ctx *ctx = crypto_ahash_ctx(ahash);
+
+ return ssi_hash_export(ctx, out);
+}
+
+static int ssi_ahash_import(struct ahash_request *req, const void *in)
+{
+ struct crypto_ahash *ahash = crypto_ahash_reqtfm(req);
+ struct ssi_hash_ctx *ctx = crypto_ahash_ctx(ahash);
+
+ return ssi_hash_import(ctx, in);
+}
+#endif
+
+static int ssi_ahash_setkey(struct crypto_ahash *ahash,
+ const u8 *key, unsigned int keylen)
+{
+ return ssi_hash_setkey((void *) ahash, key, keylen, false);
+}
+
+struct ssi_hash_template {
+ char name[CRYPTO_MAX_ALG_NAME];
+ char driver_name[CRYPTO_MAX_ALG_NAME];
+ char hmac_name[CRYPTO_MAX_ALG_NAME];
+ char hmac_driver_name[CRYPTO_MAX_ALG_NAME];
+ unsigned int blocksize;
+ bool synchronize;
+ union {
+ struct ahash_alg template_ahash;
+ struct shash_alg template_shash;
+ };
+ int hash_mode;
+ int hw_mode;
+ int inter_digestsize;
+ struct ssi_drvdata *drvdata;
+};
+
+/* hash descriptors */
+static struct ssi_hash_template driver_hash[] = {
+ //Asynchronize hash template
+ {
+ .name = "sha1",
+ .driver_name = "sha1-dx",
+ .hmac_name = "hmac(sha1)",
+ .hmac_driver_name = "hmac-sha1-dx",
+ .blocksize = SHA1_BLOCK_SIZE,
+ .synchronize = false,
+ .template_ahash = {
+ .init = ssi_ahash_init,
+ .update = ssi_ahash_update,
+ .final = ssi_ahash_final,
+ .finup = ssi_ahash_finup,
+ .digest = ssi_ahash_digest,
+#ifdef EXPORT_FIXED
+ .export = ssi_ahash_export,
+ .import = ssi_ahash_import,
+#endif
+ .setkey = ssi_ahash_setkey,
+ .halg = {
+ .digestsize = SHA1_DIGEST_SIZE,
+ .statesize = sizeof(struct sha1_state),
+ },
+ },
+ .hash_mode = DRV_HASH_SHA1,
+ .hw_mode = DRV_HASH_HW_SHA1,
+ .inter_digestsize = SHA1_DIGEST_SIZE,
+ },
+ {
+ .name = "sha256",
+ .driver_name = "sha256-dx",
+ .hmac_name = "hmac(sha256)",
+ .hmac_driver_name = "hmac-sha256-dx",
+ .blocksize = SHA256_BLOCK_SIZE,
+ .synchronize = false,
+ .template_ahash = {
+ .init = ssi_ahash_init,
+ .update = ssi_ahash_update,
+ .final = ssi_ahash_final,
+ .finup = ssi_ahash_finup,
+ .digest = ssi_ahash_digest,
+#ifdef EXPORT_FIXED
+ .export = ssi_ahash_export,
+ .import = ssi_ahash_import,
+#endif
+ .setkey = ssi_ahash_setkey,
+ .halg = {
+ .digestsize = SHA256_DIGEST_SIZE,
+ .statesize = sizeof(struct sha256_state),
+ },
+ },
+ .hash_mode = DRV_HASH_SHA256,
+ .hw_mode = DRV_HASH_HW_SHA256,
+ .inter_digestsize = SHA256_DIGEST_SIZE,
+ },
+ {
+ .name = "sha224",
+ .driver_name = "sha224-dx",
+ .hmac_name = "hmac(sha224)",
+ .hmac_driver_name = "hmac-sha224-dx",
+ .blocksize = SHA224_BLOCK_SIZE,
+ .synchronize = false,
+ .template_ahash = {
+ .init = ssi_ahash_init,
+ .update = ssi_ahash_update,
+ .final = ssi_ahash_final,
+ .finup = ssi_ahash_finup,
+ .digest = ssi_ahash_digest,
+#ifdef EXPORT_FIXED
+ .export = ssi_ahash_export,
+ .import = ssi_ahash_import,
+#endif
+ .setkey = ssi_ahash_setkey,
+ .halg = {
+ .digestsize = SHA224_DIGEST_SIZE,
+ .statesize = sizeof(struct sha256_state),
+ },
+ },
+ .hash_mode = DRV_HASH_SHA224,
+ .hw_mode = DRV_HASH_HW_SHA256,
+ .inter_digestsize = SHA256_DIGEST_SIZE,
+ },
+#if (DX_DEV_SHA_MAX > 256)
+ {
+ .name = "sha384",
+ .driver_name = "sha384-dx",
+ .hmac_name = "hmac(sha384)",
+ .hmac_driver_name = "hmac-sha384-dx",
+ .blocksize = SHA384_BLOCK_SIZE,
+ .synchronize = false,
+ .template_ahash = {
+ .init = ssi_ahash_init,
+ .update = ssi_ahash_update,
+ .final = ssi_ahash_final,
+ .finup = ssi_ahash_finup,
+ .digest = ssi_ahash_digest,
+#ifdef EXPORT_FIXED
+ .export = ssi_ahash_export,
+ .import = ssi_ahash_import,
+#endif
+ .setkey = ssi_ahash_setkey,
+ .halg = {
+ .digestsize = SHA384_DIGEST_SIZE,
+ .statesize = sizeof(struct sha512_state),
+ },
+ },
+ .hash_mode = DRV_HASH_SHA384,
+ .hw_mode = DRV_HASH_HW_SHA512,
+ .inter_digestsize = SHA512_DIGEST_SIZE,
+ },
+ {
+ .name = "sha512",
+ .driver_name = "sha512-dx",
+ .hmac_name = "hmac(sha512)",
+ .hmac_driver_name = "hmac-sha512-dx",
+ .blocksize = SHA512_BLOCK_SIZE,
+ .synchronize = false,
+ .template_ahash = {
+ .init = ssi_ahash_init,
+ .update = ssi_ahash_update,
+ .final = ssi_ahash_final,
+ .finup = ssi_ahash_finup,
+ .digest = ssi_ahash_digest,
+#ifdef EXPORT_FIXED
+ .export = ssi_ahash_export,
+ .import = ssi_ahash_import,
+#endif
+ .setkey = ssi_ahash_setkey,
+ .halg = {
+ .digestsize = SHA512_DIGEST_SIZE,
+ .statesize = sizeof(struct sha512_state),
+ },
+ },
+ .hash_mode = DRV_HASH_SHA512,
+ .hw_mode = DRV_HASH_HW_SHA512,
+ .inter_digestsize = SHA512_DIGEST_SIZE,
+ },
+#endif
+ {
+ .name = "md5",
+ .driver_name = "md5-dx",
+ .hmac_name = "hmac(md5)",
+ .hmac_driver_name = "hmac-md5-dx",
+ .blocksize = MD5_HMAC_BLOCK_SIZE,
+ .synchronize = false,
+ .template_ahash = {
+ .init = ssi_ahash_init,
+ .update = ssi_ahash_update,
+ .final = ssi_ahash_final,
+ .finup = ssi_ahash_finup,
+ .digest = ssi_ahash_digest,
+#ifdef EXPORT_FIXED
+ .export = ssi_ahash_export,
+ .import = ssi_ahash_import,
+#endif
+ .setkey = ssi_ahash_setkey,
+ .halg = {
+ .digestsize = MD5_DIGEST_SIZE,
+ .statesize = sizeof(struct md5_state),
+ },
+ },
+ .hash_mode = DRV_HASH_MD5,
+ .hw_mode = DRV_HASH_HW_MD5,
+ .inter_digestsize = MD5_DIGEST_SIZE,
+ },
+ {
+ .name = "xcbc(aes)",
+ .driver_name = "xcbc-aes-dx",
+ .blocksize = AES_BLOCK_SIZE,
+ .synchronize = false,
+ .template_ahash = {
+ .init = ssi_ahash_init,
+ .update = ssi_mac_update,
+ .final = ssi_mac_final,
+ .finup = ssi_mac_finup,
+ .digest = ssi_mac_digest,
+ .setkey = ssi_xcbc_setkey,
+#ifdef EXPORT_FIXED
+ .export = ssi_ahash_export,
+ .import = ssi_ahash_import,
+#endif
+ .halg = {
+ .digestsize = AES_BLOCK_SIZE,
+ .statesize = sizeof(struct aeshash_state),
+ },
+ },
+ .hash_mode = DRV_HASH_NULL,
+ .hw_mode = DRV_CIPHER_XCBC_MAC,
+ .inter_digestsize = AES_BLOCK_SIZE,
+ },
+#if SSI_CC_HAS_CMAC
+ {
+ .name = "cmac(aes)",
+ .driver_name = "cmac-aes-dx",
+ .blocksize = AES_BLOCK_SIZE,
+ .synchronize = false,
+ .template_ahash = {
+ .init = ssi_ahash_init,
+ .update = ssi_mac_update,
+ .final = ssi_mac_final,
+ .finup = ssi_mac_finup,
+ .digest = ssi_mac_digest,
+ .setkey = ssi_cmac_setkey,
+#ifdef EXPORT_FIXED
+ .export = ssi_ahash_export,
+ .import = ssi_ahash_import,
+#endif
+ .halg = {
+ .digestsize = AES_BLOCK_SIZE,
+ .statesize = sizeof(struct aeshash_state),
+ },
+ },
+ .hash_mode = DRV_HASH_NULL,
+ .hw_mode = DRV_CIPHER_CMAC,
+ .inter_digestsize = AES_BLOCK_SIZE,
+ },
+#endif
+
+};
+
+static struct ssi_hash_alg *
+ssi_hash_create_alg(struct ssi_hash_template *template, bool keyed)
+{
+ struct ssi_hash_alg *t_crypto_alg;
+ struct crypto_alg *alg;
+
+ t_crypto_alg = kzalloc(sizeof(struct ssi_hash_alg), GFP_KERNEL);
+ if (!t_crypto_alg) {
+ SSI_LOG_ERR("failed to allocate t_alg\n");
+ return ERR_PTR(-ENOMEM);
+ }
+
+ t_crypto_alg->synchronize = template->synchronize;
+ if (template->synchronize) {
+ struct shash_alg *halg;
+ t_crypto_alg->shash_alg = template->template_shash;
+ halg = &t_crypto_alg->shash_alg;
+ alg = &halg->base;
+ if (!keyed) halg->setkey = NULL;
+ } else {
+ struct ahash_alg *halg;
+ t_crypto_alg->ahash_alg = template->template_ahash;
+ halg = &t_crypto_alg->ahash_alg;
+ alg = &halg->halg.base;
+ if (!keyed) halg->setkey = NULL;
+ }
+
+ if (keyed) {
+ snprintf(alg->cra_name, CRYPTO_MAX_ALG_NAME, "%s",
+ template->hmac_name);
+ snprintf(alg->cra_driver_name, CRYPTO_MAX_ALG_NAME, "%s",
+ template->hmac_driver_name);
+ } else {
+ snprintf(alg->cra_name, CRYPTO_MAX_ALG_NAME, "%s",
+ template->name);
+ snprintf(alg->cra_driver_name, CRYPTO_MAX_ALG_NAME, "%s",
+ template->driver_name);
+ }
+ alg->cra_module = THIS_MODULE;
+ alg->cra_ctxsize = sizeof(struct ssi_hash_ctx);
+ alg->cra_priority = SSI_CRA_PRIO;
+ alg->cra_blocksize = template->blocksize;
+ alg->cra_alignmask = 0;
+ alg->cra_exit = ssi_hash_cra_exit;
+
+ if (template->synchronize) {
+ alg->cra_init = ssi_shash_cra_init;
+ alg->cra_flags = CRYPTO_ALG_TYPE_SHASH |
+ CRYPTO_ALG_KERN_DRIVER_ONLY;
+ alg->cra_type = &crypto_shash_type;
+ } else {
+ alg->cra_init = ssi_ahash_cra_init;
+ alg->cra_flags = CRYPTO_ALG_ASYNC | CRYPTO_ALG_TYPE_AHASH |
+ CRYPTO_ALG_KERN_DRIVER_ONLY;
+ alg->cra_type = &crypto_ahash_type;
+ }
+
+ t_crypto_alg->hash_mode = template->hash_mode;
+ t_crypto_alg->hw_mode = template->hw_mode;
+ t_crypto_alg->inter_digestsize = template->inter_digestsize;
+
+ return t_crypto_alg;
+}
+
+int ssi_hash_init_sram_digest_consts(struct ssi_drvdata *drvdata)
+{
+ struct ssi_hash_handle *hash_handle = drvdata->hash_handle;
+ ssi_sram_addr_t sram_buff_ofs = hash_handle->digest_len_sram_addr;
+ unsigned int larval_seq_len = 0;
+ HwDesc_s larval_seq[CC_DIGEST_SIZE_MAX/sizeof(uint32_t)];
+ int rc = 0;
+#if (DX_DEV_SHA_MAX > 256)
+ int i;
+#endif
+
+ /* Copy-to-sram digest-len */
+ ssi_sram_mgr_const2sram_desc(digest_len_init, sram_buff_ofs,
+ ARRAY_SIZE(digest_len_init), larval_seq, &larval_seq_len);
+ rc = send_request_init(drvdata, larval_seq, larval_seq_len);
+ if (unlikely(rc != 0))
+ goto init_digest_const_err;
+
+ sram_buff_ofs += sizeof(digest_len_init);
+ larval_seq_len = 0;
+
+#if (DX_DEV_SHA_MAX > 256)
+ /* Copy-to-sram digest-len for sha384/512 */
+ ssi_sram_mgr_const2sram_desc(digest_len_sha512_init, sram_buff_ofs,
+ ARRAY_SIZE(digest_len_sha512_init), larval_seq, &larval_seq_len);
+ rc = send_request_init(drvdata, larval_seq, larval_seq_len);
+ if (unlikely(rc != 0))
+ goto init_digest_const_err;
+
+ sram_buff_ofs += sizeof(digest_len_sha512_init);
+ larval_seq_len = 0;
+#endif
+
+ /* The initial digests offset */
+ hash_handle->larval_digest_sram_addr = sram_buff_ofs;
+
+ /* Copy-to-sram initial SHA* digests */
+ ssi_sram_mgr_const2sram_desc(md5_init, sram_buff_ofs,
+ ARRAY_SIZE(md5_init), larval_seq, &larval_seq_len);
+ rc = send_request_init(drvdata, larval_seq, larval_seq_len);
+ if (unlikely(rc != 0))
+ goto init_digest_const_err;
+ sram_buff_ofs += sizeof(md5_init);
+ larval_seq_len = 0;
+
+ ssi_sram_mgr_const2sram_desc(sha1_init, sram_buff_ofs,
+ ARRAY_SIZE(sha1_init), larval_seq, &larval_seq_len);
+ rc = send_request_init(drvdata, larval_seq, larval_seq_len);
+ if (unlikely(rc != 0))
+ goto init_digest_const_err;
+ sram_buff_ofs += sizeof(sha1_init);
+ larval_seq_len = 0;
+
+ ssi_sram_mgr_const2sram_desc(sha224_init, sram_buff_ofs,
+ ARRAY_SIZE(sha224_init), larval_seq, &larval_seq_len);
+ rc = send_request_init(drvdata, larval_seq, larval_seq_len);
+ if (unlikely(rc != 0))
+ goto init_digest_const_err;
+ sram_buff_ofs += sizeof(sha224_init);
+ larval_seq_len = 0;
+
+ ssi_sram_mgr_const2sram_desc(sha256_init, sram_buff_ofs,
+ ARRAY_SIZE(sha256_init), larval_seq, &larval_seq_len);
+ rc = send_request_init(drvdata, larval_seq, larval_seq_len);
+ if (unlikely(rc != 0))
+ goto init_digest_const_err;
+ sram_buff_ofs += sizeof(sha256_init);
+ larval_seq_len = 0;
+
+#if (DX_DEV_SHA_MAX > 256)
+ /* We are forced to swap each double-word larval before copying to sram */
+ for (i = 0; i < ARRAY_SIZE(sha384_init); i++) {
+ const uint32_t const0 = ((uint32_t *)((uint64_t *)&sha384_init[i]))[1];
+ const uint32_t const1 = ((uint32_t *)((uint64_t *)&sha384_init[i]))[0];
+
+ ssi_sram_mgr_const2sram_desc(&const0, sram_buff_ofs, 1,
+ larval_seq, &larval_seq_len);
+ sram_buff_ofs += sizeof(uint32_t);
+ ssi_sram_mgr_const2sram_desc(&const1, sram_buff_ofs, 1,
+ larval_seq, &larval_seq_len);
+ sram_buff_ofs += sizeof(uint32_t);
+ }
+ rc = send_request_init(drvdata, larval_seq, larval_seq_len);
+ if (unlikely(rc != 0)) {
+ SSI_LOG_ERR("send_request() failed (rc = %d)\n", rc);
+ goto init_digest_const_err;
+ }
+ larval_seq_len = 0;
+
+ for (i = 0; i < ARRAY_SIZE(sha512_init); i++) {
+ const uint32_t const0 = ((uint32_t *)((uint64_t *)&sha512_init[i]))[1];
+ const uint32_t const1 = ((uint32_t *)((uint64_t *)&sha512_init[i]))[0];
+
+ ssi_sram_mgr_const2sram_desc(&const0, sram_buff_ofs, 1,
+ larval_seq, &larval_seq_len);
+ sram_buff_ofs += sizeof(uint32_t);
+ ssi_sram_mgr_const2sram_desc(&const1, sram_buff_ofs, 1,
+ larval_seq, &larval_seq_len);
+ sram_buff_ofs += sizeof(uint32_t);
+ }
+ rc = send_request_init(drvdata, larval_seq, larval_seq_len);
+ if (unlikely(rc != 0)) {
+ SSI_LOG_ERR("send_request() failed (rc = %d)\n", rc);
+ goto init_digest_const_err;
+ }
+#endif
+
+init_digest_const_err:
+ return rc;
+}
+
+int ssi_hash_alloc(struct ssi_drvdata *drvdata)
+{
+ struct ssi_hash_handle *hash_handle;
+ ssi_sram_addr_t sram_buff;
+ uint32_t sram_size_to_alloc;
+ int rc = 0;
+ int alg;
+
+ hash_handle = kzalloc(sizeof(struct ssi_hash_handle), GFP_KERNEL);
+ if (hash_handle == NULL) {
+ SSI_LOG_ERR("kzalloc failed to allocate %zu B\n",
+ sizeof(struct ssi_hash_handle));
+ rc = -ENOMEM;
+ goto fail;
+ }
+
+ drvdata->hash_handle = hash_handle;
+
+ sram_size_to_alloc = sizeof(digest_len_init) +
+#if (DX_DEV_SHA_MAX > 256)
+ sizeof(digest_len_sha512_init) +
+ sizeof(sha384_init) +
+ sizeof(sha512_init) +
+#endif
+ sizeof(md5_init) +
+ sizeof(sha1_init) +
+ sizeof(sha224_init) +
+ sizeof(sha256_init);
+
+ sram_buff = ssi_sram_mgr_alloc(drvdata, sram_size_to_alloc);
+ if (sram_buff == NULL_SRAM_ADDR) {
+ SSI_LOG_ERR("SRAM pool exhausted\n");
+ rc = -ENOMEM;
+ goto fail;
+ }
+
+ /* The initial digest-len offset */
+ hash_handle->digest_len_sram_addr = sram_buff;
+
+ /*must be set before the alg registration as it is being used there*/
+ rc = ssi_hash_init_sram_digest_consts(drvdata);
+ if (unlikely(rc != 0)) {
+ SSI_LOG_ERR("Init digest CONST failed (rc=%d)\n", rc);
+ goto fail;
+ }
+
+ INIT_LIST_HEAD(&hash_handle->hash_list);
+
+ /* ahash registration */
+ for (alg = 0; alg < ARRAY_SIZE(driver_hash); alg++) {
+ struct ssi_hash_alg *t_alg;
+
+ /* register hmac version */
+
+ if ((((struct ssi_hash_template)driver_hash[alg]).hw_mode != DRV_CIPHER_XCBC_MAC) &&
+ (((struct ssi_hash_template)driver_hash[alg]).hw_mode != DRV_CIPHER_CMAC)) {
+ t_alg = ssi_hash_create_alg(&driver_hash[alg], true);
+ if (IS_ERR(t_alg)) {
+ rc = PTR_ERR(t_alg);
+ SSI_LOG_ERR("%s alg allocation failed\n",
+ driver_hash[alg].driver_name);
+ goto fail;
+ }
+ t_alg->drvdata = drvdata;
+
+ if (t_alg->synchronize) {
+ rc = crypto_register_shash(&t_alg->shash_alg);
+ if (unlikely(rc != 0)) {
+ SSI_LOG_ERR("%s alg registration failed\n",
+ t_alg->shash_alg.base.cra_driver_name);
+ kfree(t_alg);
+ goto fail;
+ } else
+ list_add_tail(&t_alg->entry, &hash_handle->hash_list);
+ } else {
+ rc = crypto_register_ahash(&t_alg->ahash_alg);
+ if (unlikely(rc != 0)) {
+ SSI_LOG_ERR("%s alg registration failed\n",
+ t_alg->ahash_alg.halg.base.cra_driver_name);
+ kfree(t_alg);
+ goto fail;
+ } else
+ list_add_tail(&t_alg->entry, &hash_handle->hash_list);
+ }
+ }
+
+ /* register hash version */
+ t_alg = ssi_hash_create_alg(&driver_hash[alg], false);
+ if (IS_ERR(t_alg)) {
+ rc = PTR_ERR(t_alg);
+ SSI_LOG_ERR("%s alg allocation failed\n",
+ driver_hash[alg].driver_name);
+ goto fail;
+ }
+ t_alg->drvdata = drvdata;
+
+ if (t_alg->synchronize) {
+ rc = crypto_register_shash(&t_alg->shash_alg);
+ if (unlikely(rc != 0)) {
+ SSI_LOG_ERR("%s alg registration failed\n",
+ t_alg->shash_alg.base.cra_driver_name);
+ kfree(t_alg);
+ goto fail;
+ } else
+ list_add_tail(&t_alg->entry, &hash_handle->hash_list);
+
+ } else {
+ rc = crypto_register_ahash(&t_alg->ahash_alg);
+ if (unlikely(rc != 0)) {
+ SSI_LOG_ERR("%s alg registration failed\n",
+ t_alg->ahash_alg.halg.base.cra_driver_name);
+ kfree(t_alg);
+ goto fail;
+ } else
+ list_add_tail(&t_alg->entry, &hash_handle->hash_list);
+ }
+ }
+
+ return 0;
+
+fail:
+
+ if (drvdata->hash_handle != NULL) {
+ kfree(drvdata->hash_handle);
+ drvdata->hash_handle = NULL;
+ }
+ return rc;
+}
+
+int ssi_hash_free(struct ssi_drvdata *drvdata)
+{
+ struct ssi_hash_alg *t_hash_alg, *hash_n;
+ struct ssi_hash_handle *hash_handle = drvdata->hash_handle;
+
+ if (hash_handle != NULL) {
+
+ list_for_each_entry_safe(t_hash_alg, hash_n, &hash_handle->hash_list, entry) {
+ if (t_hash_alg->synchronize) {
+ crypto_unregister_shash(&t_hash_alg->shash_alg);
+ } else {
+ crypto_unregister_ahash(&t_hash_alg->ahash_alg);
+ }
+ list_del(&t_hash_alg->entry);
+ kfree(t_hash_alg);
+ }
+
+ kfree(hash_handle);
+ drvdata->hash_handle = NULL;
+ }
+ return 0;
+}
+
+static void ssi_hash_create_xcbc_setup(struct ahash_request *areq,
+ HwDesc_s desc[],
+ unsigned int *seq_size) {
+ unsigned int idx = *seq_size;
+ struct ahash_req_ctx *state = ahash_request_ctx(areq);
+ struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);
+ struct ssi_hash_ctx *ctx = crypto_ahash_ctx(tfm);
+
+ /* Setup XCBC MAC K1 */
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_DIN_TYPE(&desc[idx], DMA_DLLI, (ctx->opad_tmp_keys_dma_addr
+ + XCBC_MAC_K1_OFFSET),
+ CC_AES_128_BIT_KEY_SIZE, NS_BIT);
+ HW_DESC_SET_SETUP_MODE(&desc[idx], SETUP_LOAD_KEY0);
+ HW_DESC_SET_CIPHER_MODE(&desc[idx], DRV_CIPHER_XCBC_MAC);
+ HW_DESC_SET_CIPHER_CONFIG0(&desc[idx], DESC_DIRECTION_ENCRYPT_ENCRYPT);
+ HW_DESC_SET_KEY_SIZE_AES(&desc[idx], CC_AES_128_BIT_KEY_SIZE);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], S_DIN_to_AES);
+ idx++;
+
+ /* Setup XCBC MAC K2 */
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_DIN_TYPE(&desc[idx], DMA_DLLI, (ctx->opad_tmp_keys_dma_addr
+ + XCBC_MAC_K2_OFFSET),
+ CC_AES_128_BIT_KEY_SIZE, NS_BIT);
+ HW_DESC_SET_SETUP_MODE(&desc[idx], SETUP_LOAD_STATE1);
+ HW_DESC_SET_CIPHER_MODE(&desc[idx], DRV_CIPHER_XCBC_MAC);
+ HW_DESC_SET_CIPHER_CONFIG0(&desc[idx], DESC_DIRECTION_ENCRYPT_ENCRYPT);
+ HW_DESC_SET_KEY_SIZE_AES(&desc[idx], CC_AES_128_BIT_KEY_SIZE);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], S_DIN_to_AES);
+ idx++;
+
+ /* Setup XCBC MAC K3 */
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_DIN_TYPE(&desc[idx], DMA_DLLI, (ctx->opad_tmp_keys_dma_addr
+ + XCBC_MAC_K3_OFFSET),
+ CC_AES_128_BIT_KEY_SIZE, NS_BIT);
+ HW_DESC_SET_SETUP_MODE(&desc[idx], SETUP_LOAD_STATE2);
+ HW_DESC_SET_CIPHER_MODE(&desc[idx], DRV_CIPHER_XCBC_MAC);
+ HW_DESC_SET_CIPHER_CONFIG0(&desc[idx], DESC_DIRECTION_ENCRYPT_ENCRYPT);
+ HW_DESC_SET_KEY_SIZE_AES(&desc[idx], CC_AES_128_BIT_KEY_SIZE);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], S_DIN_to_AES);
+ idx++;
+
+ /* Loading MAC state */
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_DIN_TYPE(&desc[idx], DMA_DLLI, state->digest_buff_dma_addr, CC_AES_BLOCK_SIZE, NS_BIT);
+ HW_DESC_SET_SETUP_MODE(&desc[idx], SETUP_LOAD_STATE0);
+ HW_DESC_SET_CIPHER_MODE(&desc[idx], DRV_CIPHER_XCBC_MAC);
+ HW_DESC_SET_CIPHER_CONFIG0(&desc[idx], DESC_DIRECTION_ENCRYPT_ENCRYPT);
+ HW_DESC_SET_KEY_SIZE_AES(&desc[idx], CC_AES_128_BIT_KEY_SIZE);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], S_DIN_to_AES);
+ idx++;
+ *seq_size = idx;
+}
+
+static void ssi_hash_create_cmac_setup(struct ahash_request *areq,
+ HwDesc_s desc[],
+ unsigned int *seq_size)
+{
+ unsigned int idx = *seq_size;
+ struct ahash_req_ctx *state = ahash_request_ctx(areq);
+ struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);
+ struct ssi_hash_ctx *ctx = crypto_ahash_ctx(tfm);
+
+ /* Setup CMAC Key */
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_DIN_TYPE(&desc[idx], DMA_DLLI, ctx->opad_tmp_keys_dma_addr,
+ ((ctx->key_params.keylen == 24) ? AES_MAX_KEY_SIZE : ctx->key_params.keylen), NS_BIT);
+ HW_DESC_SET_SETUP_MODE(&desc[idx], SETUP_LOAD_KEY0);
+ HW_DESC_SET_CIPHER_MODE(&desc[idx], DRV_CIPHER_CMAC);
+ HW_DESC_SET_CIPHER_CONFIG0(&desc[idx], DESC_DIRECTION_ENCRYPT_ENCRYPT);
+ HW_DESC_SET_KEY_SIZE_AES(&desc[idx], ctx->key_params.keylen);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], S_DIN_to_AES);
+ idx++;
+
+ /* Load MAC state */
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_DIN_TYPE(&desc[idx], DMA_DLLI, state->digest_buff_dma_addr, CC_AES_BLOCK_SIZE, NS_BIT);
+ HW_DESC_SET_SETUP_MODE(&desc[idx], SETUP_LOAD_STATE0);
+ HW_DESC_SET_CIPHER_MODE(&desc[idx], DRV_CIPHER_CMAC);
+ HW_DESC_SET_CIPHER_CONFIG0(&desc[idx], DESC_DIRECTION_ENCRYPT_ENCRYPT);
+ HW_DESC_SET_KEY_SIZE_AES(&desc[idx], ctx->key_params.keylen);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], S_DIN_to_AES);
+ idx++;
+ *seq_size = idx;
+}
+
+static void ssi_hash_create_data_desc(struct ahash_req_ctx *areq_ctx,
+ struct ssi_hash_ctx *ctx,
+ unsigned int flow_mode,
+ HwDesc_s desc[],
+ bool is_not_last_data,
+ unsigned int *seq_size)
+{
+ unsigned int idx = *seq_size;
+
+ if (likely(areq_ctx->data_dma_buf_type == SSI_DMA_BUF_DLLI)) {
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_DIN_TYPE(&desc[idx], DMA_DLLI,
+ sg_dma_address(areq_ctx->curr_sg),
+ areq_ctx->curr_sg->length, NS_BIT);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], flow_mode);
+ idx++;
+ } else {
+ if (areq_ctx->data_dma_buf_type == SSI_DMA_BUF_NULL) {
+ SSI_LOG_DEBUG(" NULL mode\n");
+ /* nothing to build */
+ return;
+ }
+ /* bypass */
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_DIN_TYPE(&desc[idx], DMA_DLLI,
+ areq_ctx->mlli_params.mlli_dma_addr,
+ areq_ctx->mlli_params.mlli_len,
+ NS_BIT);
+ HW_DESC_SET_DOUT_SRAM(&desc[idx],
+ ctx->drvdata->mlli_sram_addr,
+ areq_ctx->mlli_params.mlli_len);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], BYPASS);
+ idx++;
+ /* process */
+ HW_DESC_INIT(&desc[idx]);
+ HW_DESC_SET_DIN_TYPE(&desc[idx], DMA_MLLI,
+ ctx->drvdata->mlli_sram_addr,
+ areq_ctx->mlli_nents,
+ NS_BIT);
+ HW_DESC_SET_FLOW_MODE(&desc[idx], flow_mode);
+ idx++;
+ }
+ if (is_not_last_data) {
+ HW_DESC_SET_DIN_NOT_LAST_INDICATION(&desc[idx-1]);
+ }
+ /* return updated desc sequence size */
+ *seq_size = idx;
+}
+
+/*!
+ * Gets the address of the initial digest in SRAM
+ * according to the given hash mode
+ *
+ * \param drvdata
+ * \param mode The Hash mode. Supported modes: MD5/SHA1/SHA224/SHA256
+ *
+ * \return uint32_t The address of the inital digest in SRAM
+ */
+ssi_sram_addr_t ssi_ahash_get_larval_digest_sram_addr(void *drvdata, uint32_t mode)
+{
+ struct ssi_drvdata *_drvdata = (struct ssi_drvdata *)drvdata;
+ struct ssi_hash_handle *hash_handle = _drvdata->hash_handle;
+
+ switch (mode) {
+ case DRV_HASH_NULL:
+ break; /*Ignore*/
+ case DRV_HASH_MD5:
+ return (hash_handle->larval_digest_sram_addr);
+ case DRV_HASH_SHA1:
+ return (hash_handle->larval_digest_sram_addr +
+ sizeof(md5_init));
+ case DRV_HASH_SHA224:
+ return (hash_handle->larval_digest_sram_addr +
+ sizeof(md5_init) +
+ sizeof(sha1_init));
+ case DRV_HASH_SHA256:
+ return (hash_handle->larval_digest_sram_addr +
+ sizeof(md5_init) +
+ sizeof(sha1_init) +
+ sizeof(sha224_init));
+#if (DX_DEV_SHA_MAX > 256)
+ case DRV_HASH_SHA384:
+ return (hash_handle->larval_digest_sram_addr +
+ sizeof(md5_init) +
+ sizeof(sha1_init) +
+ sizeof(sha224_init) +
+ sizeof(sha256_init));
+ case DRV_HASH_SHA512:
+ return (hash_handle->larval_digest_sram_addr +
+ sizeof(md5_init) +
+ sizeof(sha1_init) +
+ sizeof(sha224_init) +
+ sizeof(sha256_init) +
+ sizeof(sha384_init));
+#endif
+ default:
+ SSI_LOG_ERR("Invalid hash mode (%d)\n", mode);
+ }
+
+ /*This is valid wrong value to avoid kernel crash*/
+ return hash_handle->larval_digest_sram_addr;
+}
+
+ssi_sram_addr_t
+ssi_ahash_get_initial_digest_len_sram_addr(void *drvdata, uint32_t mode)
+{
+ struct ssi_drvdata *_drvdata = (struct ssi_drvdata *)drvdata;
+ struct ssi_hash_handle *hash_handle = _drvdata->hash_handle;
+ ssi_sram_addr_t digest_len_addr = hash_handle->digest_len_sram_addr;
+
+ switch (mode) {
+ case DRV_HASH_SHA1:
+ case DRV_HASH_SHA224:
+ case DRV_HASH_SHA256:
+ case DRV_HASH_MD5:
+ return digest_len_addr;
+#if (DX_DEV_SHA_MAX > 256)
+ case DRV_HASH_SHA384:
+ case DRV_HASH_SHA512:
+ return digest_len_addr + sizeof(digest_len_init);
+#endif
+ default:
+ return digest_len_addr; /*to avoid kernel crash*/
+ }
+}
+
diff --git a/drivers/staging/ccree/ssi_hash.h b/drivers/staging/ccree/ssi_hash.h
new file mode 100644
index 0000000..a2b076d3
--- /dev/null
+++ b/drivers/staging/ccree/ssi_hash.h
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2012-2017 ARM Limited or its affiliates.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* \file ssi_hash.h
+ ARM CryptoCell Hash Crypto API
+ */
+
+#ifndef __SSI_HASH_H__
+#define __SSI_HASH_H__
+
+#include "ssi_buffer_mgr.h"
+
+#define HMAC_IPAD_CONST 0x36363636
+#define HMAC_OPAD_CONST 0x5C5C5C5C
+#if (DX_DEV_SHA_MAX > 256)
+#define HASH_LEN_SIZE 16
+#define SSI_MAX_HASH_DIGEST_SIZE SHA512_DIGEST_SIZE
+#define SSI_MAX_HASH_BLCK_SIZE SHA512_BLOCK_SIZE
+#else
+#define HASH_LEN_SIZE 8
+#define SSI_MAX_HASH_DIGEST_SIZE SHA256_DIGEST_SIZE
+#define SSI_MAX_HASH_BLCK_SIZE SHA256_BLOCK_SIZE
+#endif
+
+#define XCBC_MAC_K1_OFFSET 0
+#define XCBC_MAC_K2_OFFSET 16
+#define XCBC_MAC_K3_OFFSET 32
+
+// this struct was taken from drivers/crypto/nx/nx-aes-xcbc.c and it is used for xcbc/cmac statesize
+struct aeshash_state {
+ u8 state[AES_BLOCK_SIZE];
+ unsigned int count;
+ u8 buffer[AES_BLOCK_SIZE];
+};
+
+/* ahash state */
+struct ahash_req_ctx {
+ uint8_t* buff0;
+ uint8_t* buff1;
+ uint8_t* digest_result_buff;
+ struct async_gen_req_ctx gen_ctx;
+ enum ssi_req_dma_buf_type data_dma_buf_type;
+ uint8_t *digest_buff;
+ uint8_t *opad_digest_buff;
+ uint8_t *digest_bytes_len;
+ dma_addr_t opad_digest_dma_addr;
+ dma_addr_t digest_buff_dma_addr;
+ dma_addr_t digest_bytes_len_dma_addr;
+ dma_addr_t digest_result_dma_addr;
+ uint32_t buff0_cnt;
+ uint32_t buff1_cnt;
+ uint32_t buff_index;
+ uint32_t xcbc_count; /* count xcbc update operatations */
+ struct scatterlist buff_sg[2];
+ struct scatterlist *curr_sg;
+ uint32_t in_nents;
+ uint32_t mlli_nents;
+ struct mlli_params mlli_params;
+};
+
+int ssi_hash_alloc(struct ssi_drvdata *drvdata);
+int ssi_hash_init_sram_digest_consts(struct ssi_drvdata *drvdata);
+int ssi_hash_free(struct ssi_drvdata *drvdata);
+
+/*!
+ * Gets the initial digest length
+ *
+ * \param drvdata
+ * \param mode The Hash mode. Supported modes: MD5/SHA1/SHA224/SHA256/SHA384/SHA512
+ *
+ * \return uint32_t returns the address of the initial digest length in SRAM
+ */
+ssi_sram_addr_t
+ssi_ahash_get_initial_digest_len_sram_addr(void *drvdata, uint32_t mode);
+
+/*!
+ * Gets the address of the initial digest in SRAM
+ * according to the given hash mode
+ *
+ * \param drvdata
+ * \param mode The Hash mode. Supported modes: MD5/SHA1/SHA224/SHA256/SHA384/SHA512
+ *
+ * \return uint32_t The address of the inital digest in SRAM
+ */
+ssi_sram_addr_t ssi_ahash_get_larval_digest_sram_addr(void *drvdata, uint32_t mode);
+
+#endif /*__SSI_HASH_H__*/
+
diff --git a/drivers/staging/ccree/ssi_ivgen.c b/drivers/staging/ccree/ssi_ivgen.c
new file mode 100644
index 0000000..f16f469
--- /dev/null
+++ b/drivers/staging/ccree/ssi_ivgen.c
@@ -0,0 +1,301 @@
+/*
+ * Copyright (C) 2012-2017 ARM Limited or its affiliates.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/platform_device.h>
+#include <crypto/ctr.h>
+#include "ssi_config.h"
+#include "ssi_driver.h"
+#include "ssi_ivgen.h"
+#include "ssi_request_mgr.h"
+#include "ssi_sram_mgr.h"
+#include "ssi_buffer_mgr.h"
+
+/* The max. size of pool *MUST* be <= SRAM total size */
+#define SSI_IVPOOL_SIZE 1024
+/* The first 32B fraction of pool are dedicated to the
+ next encryption "key" & "IV" for pool regeneration */
+#define SSI_IVPOOL_META_SIZE (CC_AES_IV_SIZE + AES_KEYSIZE_128)
+#define SSI_IVPOOL_GEN_SEQ_LEN 4
+
+/**
+ * struct ssi_ivgen_ctx -IV pool generation context
+ * @pool: the start address of the iv-pool resides in internal RAM
+ * @ctr_key_dma: address of pool's encryption key material in internal RAM
+ * @ctr_iv_dma: address of pool's counter iv in internal RAM
+ * @next_iv_ofs: the offset to the next available IV in pool
+ * @pool_meta: virt. address of the initial enc. key/IV
+ * @pool_meta_dma: phys. address of the initial enc. key/IV
+ */
+struct ssi_ivgen_ctx {
+ ssi_sram_addr_t pool;
+ ssi_sram_addr_t ctr_key;
+ ssi_sram_addr_t ctr_iv;
+ uint32_t next_iv_ofs;
+ uint8_t *pool_meta;
+ dma_addr_t pool_meta_dma;
+};
+
+/*!
+ * Generates SSI_IVPOOL_SIZE of random bytes by
+ * encrypting 0's using AES128-CTR.
+ *
+ * \param ivgen iv-pool context
+ * \param iv_seq IN/OUT array to the descriptors sequence
+ * \param iv_seq_len IN/OUT pointer to the sequence length
+ */
+static int ssi_ivgen_generate_pool(
+ struct ssi_ivgen_ctx *ivgen_ctx,
+ HwDesc_s iv_seq[],
+ unsigned int *iv_seq_len)
+{
+ unsigned int idx = *iv_seq_len;
+
+ if ( (*iv_seq_len + SSI_IVPOOL_GEN_SEQ_LEN) > SSI_IVPOOL_SEQ_LEN) {
+ /* The sequence will be longer than allowed */
+ return -EINVAL;
+ }
+ /* Setup key */
+ HW_DESC_INIT(&iv_seq[idx]);
+ HW_DESC_SET_DIN_SRAM(&iv_seq[idx], ivgen_ctx->ctr_key, AES_KEYSIZE_128);
+ HW_DESC_SET_SETUP_MODE(&iv_seq[idx], SETUP_LOAD_KEY0);
+ HW_DESC_SET_CIPHER_CONFIG0(&iv_seq[idx], DESC_DIRECTION_ENCRYPT_ENCRYPT);
+ HW_DESC_SET_FLOW_MODE(&iv_seq[idx], S_DIN_to_AES);
+ HW_DESC_SET_KEY_SIZE_AES(&iv_seq[idx], CC_AES_128_BIT_KEY_SIZE);
+ HW_DESC_SET_CIPHER_MODE(&iv_seq[idx], DRV_CIPHER_CTR);
+ idx++;
+
+ /* Setup cipher state */
+ HW_DESC_INIT(&iv_seq[idx]);
+ HW_DESC_SET_DIN_SRAM(&iv_seq[idx], ivgen_ctx->ctr_iv, CC_AES_IV_SIZE);
+ HW_DESC_SET_CIPHER_CONFIG0(&iv_seq[idx], DESC_DIRECTION_ENCRYPT_ENCRYPT);
+ HW_DESC_SET_FLOW_MODE(&iv_seq[idx], S_DIN_to_AES);
+ HW_DESC_SET_SETUP_MODE(&iv_seq[idx], SETUP_LOAD_STATE1);
+ HW_DESC_SET_KEY_SIZE_AES(&iv_seq[idx], CC_AES_128_BIT_KEY_SIZE);
+ HW_DESC_SET_CIPHER_MODE(&iv_seq[idx], DRV_CIPHER_CTR);
+ idx++;
+
+ /* Perform dummy encrypt to skip first block */
+ HW_DESC_INIT(&iv_seq[idx]);
+ HW_DESC_SET_DIN_CONST(&iv_seq[idx], 0, CC_AES_IV_SIZE);
+ HW_DESC_SET_DOUT_SRAM(&iv_seq[idx], ivgen_ctx->pool, CC_AES_IV_SIZE);
+ HW_DESC_SET_FLOW_MODE(&iv_seq[idx], DIN_AES_DOUT);
+ idx++;
+
+ /* Generate IV pool */
+ HW_DESC_INIT(&iv_seq[idx]);
+ HW_DESC_SET_DIN_CONST(&iv_seq[idx], 0, SSI_IVPOOL_SIZE);
+ HW_DESC_SET_DOUT_SRAM(&iv_seq[idx], ivgen_ctx->pool, SSI_IVPOOL_SIZE);
+ HW_DESC_SET_FLOW_MODE(&iv_seq[idx], DIN_AES_DOUT);
+ idx++;
+
+ *iv_seq_len = idx; /* Update sequence length */
+
+ /* queue ordering assures pool readiness */
+ ivgen_ctx->next_iv_ofs = SSI_IVPOOL_META_SIZE;
+
+ return 0;
+}
+
+/*!
+ * Generates the initial pool in SRAM.
+ * This function should be invoked when resuming DX driver.
+ *
+ * \param drvdata
+ *
+ * \return int Zero for success, negative value otherwise.
+ */
+int ssi_ivgen_init_sram_pool(struct ssi_drvdata *drvdata)
+{
+ struct ssi_ivgen_ctx *ivgen_ctx = drvdata->ivgen_handle;
+ HwDesc_s iv_seq[SSI_IVPOOL_SEQ_LEN];
+ unsigned int iv_seq_len = 0;
+ int rc;
+
+ /* Generate initial enc. key/iv */
+ get_random_bytes(ivgen_ctx->pool_meta, SSI_IVPOOL_META_SIZE);
+
+ /* The first 32B reserved for the enc. Key/IV */
+ ivgen_ctx->ctr_key = ivgen_ctx->pool;
+ ivgen_ctx->ctr_iv = ivgen_ctx->pool + AES_KEYSIZE_128;
+
+ /* Copy initial enc. key and IV to SRAM at a single descriptor */
+ HW_DESC_INIT(&iv_seq[iv_seq_len]);
+ HW_DESC_SET_DIN_TYPE(&iv_seq[iv_seq_len], DMA_DLLI,
+ ivgen_ctx->pool_meta_dma, SSI_IVPOOL_META_SIZE,
+ NS_BIT);
+ HW_DESC_SET_DOUT_SRAM(&iv_seq[iv_seq_len], ivgen_ctx->pool,
+ SSI_IVPOOL_META_SIZE);
+ HW_DESC_SET_FLOW_MODE(&iv_seq[iv_seq_len], BYPASS);
+ iv_seq_len++;
+
+ /* Generate initial pool */
+ rc = ssi_ivgen_generate_pool(ivgen_ctx, iv_seq, &iv_seq_len);
+ if (unlikely(rc != 0)) {
+ return rc;
+ }
+ /* Fire-and-forget */
+ return send_request_init(drvdata, iv_seq, iv_seq_len);
+}
+
+/*!
+ * Free iv-pool and ivgen context.
+ *
+ * \param drvdata
+ */
+void ssi_ivgen_fini(struct ssi_drvdata *drvdata)
+{
+ struct ssi_ivgen_ctx *ivgen_ctx = drvdata->ivgen_handle;
+ struct device *device = &(drvdata->plat_dev->dev);
+
+ if (ivgen_ctx == NULL)
+ return;
+
+ if (ivgen_ctx->pool_meta != NULL) {
+ memset(ivgen_ctx->pool_meta, 0, SSI_IVPOOL_META_SIZE);
+ SSI_RESTORE_DMA_ADDR_TO_48BIT(ivgen_ctx->pool_meta_dma);
+ dma_free_coherent(device, SSI_IVPOOL_META_SIZE,
+ ivgen_ctx->pool_meta, ivgen_ctx->pool_meta_dma);
+ }
+
+ ivgen_ctx->pool = NULL_SRAM_ADDR;
+
+ /* release "this" context */
+ kfree(ivgen_ctx);
+}
+
+/*!
+ * Allocates iv-pool and maps resources.
+ * This function generates the first IV pool.
+ *
+ * \param drvdata Driver's private context
+ *
+ * \return int Zero for success, negative value otherwise.
+ */
+int ssi_ivgen_init(struct ssi_drvdata *drvdata)
+{
+ struct ssi_ivgen_ctx *ivgen_ctx;
+ struct device *device = &drvdata->plat_dev->dev;
+ int rc;
+
+ /* Allocate "this" context */
+ drvdata->ivgen_handle = kzalloc(sizeof(struct ssi_ivgen_ctx), GFP_KERNEL);
+ if (!drvdata->ivgen_handle) {
+ SSI_LOG_ERR("Not enough memory to allocate IVGEN context "
+ "(%zu B)\n", sizeof(struct ssi_ivgen_ctx));
+ rc = -ENOMEM;
+ goto out;
+ }
+ ivgen_ctx = drvdata->ivgen_handle;
+
+ /* Allocate pool's header for intial enc. key/IV */
+ ivgen_ctx->pool_meta = dma_alloc_coherent(device, SSI_IVPOOL_META_SIZE,
+ &ivgen_ctx->pool_meta_dma, GFP_KERNEL);
+ if (!ivgen_ctx->pool_meta) {
+ SSI_LOG_ERR("Not enough memory to allocate DMA of pool_meta "
+ "(%u B)\n", SSI_IVPOOL_META_SIZE);
+ rc = -ENOMEM;
+ goto out;
+ }
+ SSI_UPDATE_DMA_ADDR_TO_48BIT(ivgen_ctx->pool_meta_dma,
+ SSI_IVPOOL_META_SIZE);
+ /* Allocate IV pool in SRAM */
+ ivgen_ctx->pool = ssi_sram_mgr_alloc(drvdata, SSI_IVPOOL_SIZE);
+ if (ivgen_ctx->pool == NULL_SRAM_ADDR) {
+ SSI_LOG_ERR("SRAM pool exhausted\n");
+ rc = -ENOMEM;
+ goto out;
+ }
+
+ return ssi_ivgen_init_sram_pool(drvdata);
+
+out:
+ ssi_ivgen_fini(drvdata);
+ return rc;
+}
+
+/*!
+ * Acquires 16 Bytes IV from the iv-pool
+ *
+ * \param drvdata Driver private context
+ * \param iv_out_dma Array of physical IV out addresses
+ * \param iv_out_dma_len Length of iv_out_dma array (additional elements of iv_out_dma array are ignore)
+ * \param iv_out_size May be 8 or 16 bytes long
+ * \param iv_seq IN/OUT array to the descriptors sequence
+ * \param iv_seq_len IN/OUT pointer to the sequence length
+ *
+ * \return int Zero for success, negative value otherwise.
+ */
+int ssi_ivgen_getiv(
+ struct ssi_drvdata *drvdata,
+ dma_addr_t iv_out_dma[],
+ unsigned int iv_out_dma_len,
+ unsigned int iv_out_size,
+ HwDesc_s iv_seq[],
+ unsigned int *iv_seq_len)
+{
+ struct ssi_ivgen_ctx *ivgen_ctx = drvdata->ivgen_handle;
+ unsigned int idx = *iv_seq_len;
+ unsigned int t;
+
+ if ((iv_out_size != CC_AES_IV_SIZE) &&
+ (iv_out_size != CTR_RFC3686_IV_SIZE)) {
+ return -EINVAL;
+ }
+ if ( (iv_out_dma_len + 1) > SSI_IVPOOL_SEQ_LEN) {
+ /* The sequence will be longer than allowed */
+ return -EINVAL;
+ }
+
+ //check that number of generated IV is limited to max dma address iv buffer size
+ if ( iv_out_dma_len > SSI_MAX_IVGEN_DMA_ADDRESSES) {
+ /* The sequence will be longer than allowed */
+ return -EINVAL;
+ }
+
+ for (t = 0; t < iv_out_dma_len; t++) {
+ /* Acquire IV from pool */
+ HW_DESC_INIT(&iv_seq[idx]);
+ HW_DESC_SET_DIN_SRAM(&iv_seq[idx],
+ ivgen_ctx->pool + ivgen_ctx->next_iv_ofs,
+ iv_out_size);
+ HW_DESC_SET_DOUT_DLLI(&iv_seq[idx], iv_out_dma[t],
+ iv_out_size, NS_BIT, 0);
+ HW_DESC_SET_FLOW_MODE(&iv_seq[idx], BYPASS);
+ idx++;
+ }
+
+ /* Bypass operation is proceeded by crypto sequence, hence must
+ * assure bypass-write-transaction by a memory barrier */
+ HW_DESC_INIT(&iv_seq[idx]);
+ HW_DESC_SET_DIN_NO_DMA(&iv_seq[idx], 0, 0xfffff0);
+ HW_DESC_SET_DOUT_NO_DMA(&iv_seq[idx], 0, 0, 1);
+ idx++;
+
+ *iv_seq_len = idx; /* update seq length */
+
+ /* Update iv index */
+ ivgen_ctx->next_iv_ofs += iv_out_size;
+
+ if ((SSI_IVPOOL_SIZE - ivgen_ctx->next_iv_ofs) < CC_AES_IV_SIZE) {
+ SSI_LOG_DEBUG("Pool exhausted, regenerating iv-pool\n");
+ /* pool is drained -regenerate it! */
+ return ssi_ivgen_generate_pool(ivgen_ctx, iv_seq, iv_seq_len);
+ }
+
+ return 0;
+}
+
+
diff --git a/drivers/staging/ccree/ssi_ivgen.h b/drivers/staging/ccree/ssi_ivgen.h
new file mode 100644
index 0000000..bc69cd8
--- /dev/null
+++ b/drivers/staging/ccree/ssi_ivgen.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2012-2017 ARM Limited or its affiliates.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __SSI_IVGEN_H__
+#define __SSI_IVGEN_H__
+
+#include "cc_hw_queue_defs.h"
+
+
+#define SSI_IVPOOL_SEQ_LEN 8
+
+/*!
+ * Allocates iv-pool and maps resources.
+ * This function generates the first IV pool.
+ *
+ * \param drvdata Driver's private context
+ *
+ * \return int Zero for success, negative value otherwise.
+ */
+int ssi_ivgen_init(struct ssi_drvdata *drvdata);
+
+/*!
+ * Free iv-pool and ivgen context.
+ *
+ * \param drvdata
+ */
+void ssi_ivgen_fini(struct ssi_drvdata *drvdata);
+
+/*!
+ * Generates the initial pool in SRAM.
+ * This function should be invoked when resuming DX driver.
+ *
+ * \param drvdata
+ *
+ * \return int Zero for success, negative value otherwise.
+ */
+int ssi_ivgen_init_sram_pool(struct ssi_drvdata *drvdata);
+
+/*!
+ * Acquires 16 Bytes IV from the iv-pool
+ *
+ * \param drvdata Driver private context
+ * \param iv_out_dma Array of physical IV out addresses
+ * \param iv_out_dma_len Length of iv_out_dma array (additional elements of iv_out_dma array are ignore)
+ * \param iv_out_size May be 8 or 16 bytes long
+ * \param iv_seq IN/OUT array to the descriptors sequence
+ * \param iv_seq_len IN/OUT pointer to the sequence length
+ *
+ * \return int Zero for success, negative value otherwise.
+ */
+int ssi_ivgen_getiv(
+ struct ssi_drvdata *drvdata,
+ dma_addr_t iv_out_dma[],
+ unsigned int iv_out_dma_len,
+ unsigned int iv_out_size,
+ HwDesc_s iv_seq[],
+ unsigned int *iv_seq_len);
+
+#endif /*__SSI_IVGEN_H__*/
diff --git a/drivers/staging/ccree/ssi_pm.c b/drivers/staging/ccree/ssi_pm.c
new file mode 100644
index 0000000..dd399f2
--- /dev/null
+++ b/drivers/staging/ccree/ssi_pm.c
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2012-2017 ARM Limited or its affiliates.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "ssi_config.h"
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <crypto/ctr.h>
+#include <linux/pm_runtime.h>
+#include "ssi_driver.h"
+#include "ssi_buffer_mgr.h"
+#include "ssi_request_mgr.h"
+#include "ssi_sram_mgr.h"
+#include "ssi_sysfs.h"
+#include "ssi_ivgen.h"
+#include "ssi_hash.h"
+#include "ssi_pm.h"
+#include "ssi_pm_ext.h"
+
+
+#if defined (CONFIG_PM_RUNTIME) || defined (CONFIG_PM_SLEEP)
+
+#define POWER_DOWN_ENABLE 0x01
+#define POWER_DOWN_DISABLE 0x00
+
+
+int ssi_power_mgr_runtime_suspend(struct device *dev)
+{
+ struct ssi_drvdata *drvdata =
+ (struct ssi_drvdata *)dev_get_drvdata(dev);
+ int rc;
+
+ SSI_LOG_DEBUG("ssi_power_mgr_runtime_suspend: set HOST_POWER_DOWN_EN\n");
+ WRITE_REGISTER(drvdata->cc_base + CC_REG_OFFSET(HOST_RGF, HOST_POWER_DOWN_EN), POWER_DOWN_ENABLE);
+ rc = ssi_request_mgr_runtime_suspend_queue(drvdata);
+ if (rc != 0) {
+ SSI_LOG_ERR("ssi_request_mgr_runtime_suspend_queue (%x)\n", rc);
+ return rc;
+ }
+ fini_cc_regs(drvdata);
+
+ /* Specific HW suspend code */
+ ssi_pm_ext_hw_suspend(dev);
+ return 0;
+}
+
+int ssi_power_mgr_runtime_resume(struct device *dev)
+{
+ int rc;
+ struct ssi_drvdata *drvdata =
+ (struct ssi_drvdata *)dev_get_drvdata(dev);
+
+ SSI_LOG_DEBUG("ssi_power_mgr_runtime_resume , unset HOST_POWER_DOWN_EN\n");
+ WRITE_REGISTER(drvdata->cc_base + CC_REG_OFFSET(HOST_RGF, HOST_POWER_DOWN_EN), POWER_DOWN_DISABLE);
+ /* Specific HW resume code */
+ ssi_pm_ext_hw_resume(dev);
+
+ rc = init_cc_regs(drvdata, false);
+ if (rc !=0) {
+ SSI_LOG_ERR("init_cc_regs (%x)\n",rc);
+ return rc;
+ }
+
+ rc = ssi_request_mgr_runtime_resume_queue(drvdata);
+ if (rc !=0) {
+ SSI_LOG_ERR("ssi_request_mgr_runtime_resume_queue (%x)\n",rc);
+ return rc;
+ }
+
+ /* must be after the queue resuming as it uses the HW queue*/
+ ssi_hash_init_sram_digest_consts(drvdata);
+
+ ssi_ivgen_init_sram_pool(drvdata);
+ return 0;
+}
+
+int ssi_power_mgr_runtime_get(struct device *dev)
+{
+ int rc = 0;
+
+ if (ssi_request_mgr_is_queue_runtime_suspend(
+ (struct ssi_drvdata *)dev_get_drvdata(dev))) {
+ rc = pm_runtime_get_sync(dev);
+ } else {
+ pm_runtime_get_noresume(dev);
+ }
+ return rc;
+}
+
+int ssi_power_mgr_runtime_put_suspend(struct device *dev)
+{
+ int rc = 0;
+
+ if (!ssi_request_mgr_is_queue_runtime_suspend(
+ (struct ssi_drvdata *)dev_get_drvdata(dev))) {
+ pm_runtime_mark_last_busy(dev);
+ rc = pm_runtime_put_autosuspend(dev);
+ }
+ else {
+ /* Something wrong happens*/
+ BUG();
+ }
+ return rc;
+
+}
+
+#endif
+
+
+
+int ssi_power_mgr_init(struct ssi_drvdata *drvdata)
+{
+ int rc = 0;
+#if defined (CONFIG_PM_RUNTIME) || defined (CONFIG_PM_SLEEP)
+ struct platform_device *plat_dev = drvdata->plat_dev;
+ /* must be before the enabling to avoid resdundent suspending */
+ pm_runtime_set_autosuspend_delay(&plat_dev->dev,SSI_SUSPEND_TIMEOUT);
+ pm_runtime_use_autosuspend(&plat_dev->dev);
+ /* activate the PM module */
+ rc = pm_runtime_set_active(&plat_dev->dev);
+ if (rc != 0)
+ return rc;
+ /* enable the PM module*/
+ pm_runtime_enable(&plat_dev->dev);
+#endif
+ return rc;
+}
+
+void ssi_power_mgr_fini(struct ssi_drvdata *drvdata)
+{
+#if defined (CONFIG_PM_RUNTIME) || defined (CONFIG_PM_SLEEP)
+ struct platform_device *plat_dev = drvdata->plat_dev;
+
+ pm_runtime_disable(&plat_dev->dev);
+#endif
+}
diff --git a/drivers/staging/ccree/ssi_pm.h b/drivers/staging/ccree/ssi_pm.h
new file mode 100644
index 0000000..516fc3f
--- /dev/null
+++ b/drivers/staging/ccree/ssi_pm.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2012-2017 ARM Limited or its affiliates.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* \file ssi_pm.h
+ */
+
+#ifndef __SSI_POWER_MGR_H__
+#define __SSI_POWER_MGR_H__
+
+
+#include "ssi_config.h"
+#include "ssi_driver.h"
+
+
+#define SSI_SUSPEND_TIMEOUT 3000
+
+
+int ssi_power_mgr_init(struct ssi_drvdata *drvdata);
+
+void ssi_power_mgr_fini(struct ssi_drvdata *drvdata);
+
+#if defined (CONFIG_PM_RUNTIME) || defined (CONFIG_PM_SLEEP)
+int ssi_power_mgr_runtime_suspend(struct device *dev);
+
+int ssi_power_mgr_runtime_resume(struct device *dev);
+
+int ssi_power_mgr_runtime_get(struct device *dev);
+
+int ssi_power_mgr_runtime_put_suspend(struct device *dev);
+#endif
+
+#endif /*__POWER_MGR_H__*/
+
diff --git a/drivers/staging/ccree/ssi_pm_ext.c b/drivers/staging/ccree/ssi_pm_ext.c
new file mode 100644
index 0000000..f86bbab
--- /dev/null
+++ b/drivers/staging/ccree/ssi_pm_ext.c
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2012-2017 ARM Limited or its affiliates.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "ssi_config.h"
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <crypto/ctr.h>
+#include <linux/pm_runtime.h>
+#include "ssi_driver.h"
+#include "ssi_sram_mgr.h"
+#include "ssi_pm_ext.h"
+
+/*
+This function should suspend the HW (if possiable), It should be implemented by
+the driver user.
+The reference code clears the internal SRAM to imitate lose of state.
+*/
+void ssi_pm_ext_hw_suspend(struct device *dev)
+{
+ struct ssi_drvdata *drvdata =
+ (struct ssi_drvdata *)dev_get_drvdata(dev);
+ unsigned int val;
+ void __iomem *cc_base = drvdata->cc_base;
+ unsigned int sram_addr = 0;
+
+ CC_HAL_WRITE_REGISTER(CC_REG_OFFSET(HOST_RGF, SRAM_ADDR), sram_addr);
+
+ for (;sram_addr < SSI_CC_SRAM_SIZE ; sram_addr+=4) {
+ CC_HAL_WRITE_REGISTER(CC_REG_OFFSET(HOST_RGF, SRAM_DATA), 0x0);
+
+ do {
+ val = CC_HAL_READ_REGISTER(CC_REG_OFFSET(HOST_RGF, SRAM_DATA_READY));
+ } while (!(val &0x1));
+ }
+}
+
+/*
+This function should resume the HW (if possiable).It should be implemented by
+the driver user.
+*/
+void ssi_pm_ext_hw_resume(struct device *dev)
+{
+ return;
+}
+
diff --git a/drivers/staging/ccree/ssi_pm_ext.h b/drivers/staging/ccree/ssi_pm_ext.h
new file mode 100644
index 0000000..b4e2795
--- /dev/null
+++ b/drivers/staging/ccree/ssi_pm_ext.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2012-2017 ARM Limited or its affiliates.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* \file ssi_pm_ext.h
+ */
+
+#ifndef __PM_EXT_H__
+#define __PM_EXT_H__
+
+
+#include "ssi_config.h"
+#include "ssi_driver.h"
+
+void ssi_pm_ext_hw_suspend(struct device *dev);
+
+void ssi_pm_ext_hw_resume(struct device *dev);
+
+
+#endif /*__POWER_MGR_H__*/
+
diff --git a/drivers/staging/ccree/ssi_request_mgr.c b/drivers/staging/ccree/ssi_request_mgr.c
new file mode 100644
index 0000000..522bd62
--- /dev/null
+++ b/drivers/staging/ccree/ssi_request_mgr.c
@@ -0,0 +1,713 @@
+/*
+ * Copyright (C) 2012-2017 ARM Limited or its affiliates.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "ssi_config.h"
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <crypto/ctr.h>
+#ifdef FLUSH_CACHE_ALL
+#include <asm/cacheflush.h>
+#endif
+#include <linux/pm_runtime.h>
+#include "ssi_driver.h"
+#include "ssi_buffer_mgr.h"
+#include "ssi_request_mgr.h"
+#include "ssi_sysfs.h"
+#include "ssi_ivgen.h"
+#include "ssi_pm.h"
+#include "ssi_fips.h"
+#include "ssi_fips_local.h"
+
+#define SSI_MAX_POLL_ITER 10
+
+#define AXIM_MON_BASE_OFFSET CC_REG_OFFSET(CRY_KERNEL, AXIM_MON_COMP)
+
+#ifdef CC_CYCLE_COUNT
+
+#define MONITOR_CNTR_BIT 0
+
+/**
+ * Monitor descriptor.
+ * Used to measure CC performance.
+ */
+#define INIT_CC_MONITOR_DESC(desc_p) \
+do { \
+ HW_DESC_INIT(desc_p); \
+ HW_DESC_SET_DIN_MONITOR_CNTR(desc_p); \
+} while (0)
+
+/**
+ * Try adding monitor descriptor BEFORE enqueuing sequence.
+ */
+#define CC_CYCLE_DESC_HEAD(cc_base_addr, desc_p, lock_p, is_monitored_p) \
+do { \
+ if (!test_and_set_bit(MONITOR_CNTR_BIT, (lock_p))) { \
+ enqueue_seq((cc_base_addr), (desc_p), 1); \
+ *(is_monitored_p) = true; \
+ } else { \
+ *(is_monitored_p) = false; \
+ } \
+} while (0)
+
+/**
+ * If CC_CYCLE_DESC_HEAD was successfully added:
+ * 1. Add memory barrier descriptor to ensure last AXI transaction.
+ * 2. Add monitor descriptor to sequence tail AFTER enqueuing sequence.
+ */
+#define CC_CYCLE_DESC_TAIL(cc_base_addr, desc_p, is_monitored) \
+do { \
+ if ((is_monitored) == true) { \
+ HwDesc_s barrier_desc; \
+ HW_DESC_INIT(&barrier_desc); \
+ HW_DESC_SET_DIN_NO_DMA(&barrier_desc, 0, 0xfffff0); \
+ HW_DESC_SET_DOUT_NO_DMA(&barrier_desc, 0, 0, 1); \
+ enqueue_seq((cc_base_addr), &barrier_desc, 1); \
+ enqueue_seq((cc_base_addr), (desc_p), 1); \
+ } \
+} while (0)
+
+/**
+ * Try reading CC monitor counter value upon sequence complete.
+ * Can only succeed if the lock_p is taken by the owner of the given request.
+ */
+#define END_CC_MONITOR_COUNT(cc_base_addr, stat_op_type, stat_phase, monitor_null_cycles, lock_p, is_monitored) \
+do { \
+ uint32_t elapsed_cycles; \
+ if ((is_monitored) == true) { \
+ elapsed_cycles = READ_REGISTER((cc_base_addr) + CC_REG_OFFSET(CRY_KERNEL, DSCRPTR_MEASURE_CNTR)); \
+ clear_bit(MONITOR_CNTR_BIT, (lock_p)); \
+ if (elapsed_cycles > 0) \
+ update_cc_stat(stat_op_type, stat_phase, (elapsed_cycles - monitor_null_cycles)); \
+ } \
+} while (0)
+
+#else /*CC_CYCLE_COUNT*/
+
+#define INIT_CC_MONITOR_DESC(desc_p) do { } while (0)
+#define CC_CYCLE_DESC_HEAD(cc_base_addr, desc_p, lock_p, is_monitored_p) do { } while (0)
+#define CC_CYCLE_DESC_TAIL(cc_base_addr, desc_p, is_monitored) do { } while (0)
+#define END_CC_MONITOR_COUNT(cc_base_addr, stat_op_type, stat_phase, monitor_null_cycles, lock_p, is_monitored) do { } while (0)
+#endif /*CC_CYCLE_COUNT*/
+
+
+struct ssi_request_mgr_handle {
+ /* Request manager resources */
+ unsigned int hw_queue_size; /* HW capability */
+ unsigned int min_free_hw_slots;
+ unsigned int max_used_sw_slots;
+ struct ssi_crypto_req req_queue[MAX_REQUEST_QUEUE_SIZE];
+ uint32_t req_queue_head;
+ uint32_t req_queue_tail;
+ uint32_t axi_completed;
+ uint32_t q_free_slots;
+ spinlock_t hw_lock;
+ HwDesc_s compl_desc;
+ uint8_t *dummy_comp_buff;
+ dma_addr_t dummy_comp_buff_dma;
+ HwDesc_s monitor_desc;
+ volatile unsigned long monitor_lock;
+#ifdef COMP_IN_WQ
+ struct workqueue_struct *workq;
+ struct delayed_work compwork;
+#else
+ struct tasklet_struct comptask;
+#endif
+#if defined (CONFIG_PM_RUNTIME) || defined (CONFIG_PM_SLEEP)
+ bool is_runtime_suspended;
+#endif
+};
+
+static void comp_handler(unsigned long devarg);
+#ifdef COMP_IN_WQ
+static void comp_work_handler(struct work_struct *work);
+#endif
+
+void request_mgr_fini(struct ssi_drvdata *drvdata)
+{
+ struct ssi_request_mgr_handle *req_mgr_h = drvdata->request_mgr_handle;
+
+ if (req_mgr_h == NULL)
+ return; /* Not allocated */
+
+ if (req_mgr_h->dummy_comp_buff_dma != 0) {
+ SSI_RESTORE_DMA_ADDR_TO_48BIT(req_mgr_h->dummy_comp_buff_dma);
+ dma_free_coherent(&drvdata->plat_dev->dev,
+ sizeof(uint32_t), req_mgr_h->dummy_comp_buff,
+ req_mgr_h->dummy_comp_buff_dma);
+ }
+
+ SSI_LOG_DEBUG("max_used_hw_slots=%d\n", (req_mgr_h->hw_queue_size -
+ req_mgr_h->min_free_hw_slots) );
+ SSI_LOG_DEBUG("max_used_sw_slots=%d\n", req_mgr_h->max_used_sw_slots);
+
+#ifdef COMP_IN_WQ
+ flush_workqueue(req_mgr_h->workq);
+ destroy_workqueue(req_mgr_h->workq);
+#else
+ /* Kill tasklet */
+ tasklet_kill(&req_mgr_h->comptask);
+#endif
+ memset(req_mgr_h, 0, sizeof(struct ssi_request_mgr_handle));
+ kfree(req_mgr_h);
+ drvdata->request_mgr_handle = NULL;
+}
+
+int request_mgr_init(struct ssi_drvdata *drvdata)
+{
+#ifdef CC_CYCLE_COUNT
+ HwDesc_s monitor_desc[2];
+ struct ssi_crypto_req monitor_req = {0};
+#endif
+ struct ssi_request_mgr_handle *req_mgr_h;
+ int rc = 0;
+
+ req_mgr_h = kzalloc(sizeof(struct ssi_request_mgr_handle),GFP_KERNEL);
+ if (req_mgr_h == NULL) {
+ rc = -ENOMEM;
+ goto req_mgr_init_err;
+ }
+
+ drvdata->request_mgr_handle = req_mgr_h;
+
+ spin_lock_init(&req_mgr_h->hw_lock);
+#ifdef COMP_IN_WQ
+ SSI_LOG_DEBUG("Initializing completion workqueue\n");
+ req_mgr_h->workq = create_singlethread_workqueue("arm_cc7x_wq");
+ if (unlikely(req_mgr_h->workq == NULL)) {
+ SSI_LOG_ERR("Failed creating work queue\n");
+ rc = -ENOMEM;
+ goto req_mgr_init_err;
+ }
+ INIT_DELAYED_WORK(&req_mgr_h->compwork, comp_work_handler);
+#else
+ SSI_LOG_DEBUG("Initializing completion tasklet\n");
+ tasklet_init(&req_mgr_h->comptask, comp_handler, (unsigned long)drvdata);
+#endif
+ req_mgr_h->hw_queue_size = READ_REGISTER(drvdata->cc_base +
+ CC_REG_OFFSET(CRY_KERNEL, DSCRPTR_QUEUE_SRAM_SIZE));
+ SSI_LOG_DEBUG("hw_queue_size=0x%08X\n", req_mgr_h->hw_queue_size);
+ if (req_mgr_h->hw_queue_size < MIN_HW_QUEUE_SIZE) {
+ SSI_LOG_ERR("Invalid HW queue size = %u (Min. required is %u)\n",
+ req_mgr_h->hw_queue_size, MIN_HW_QUEUE_SIZE);
+ rc = -ENOMEM;
+ goto req_mgr_init_err;
+ }
+ req_mgr_h->min_free_hw_slots = req_mgr_h->hw_queue_size;
+ req_mgr_h->max_used_sw_slots = 0;
+
+
+ /* Allocate DMA word for "dummy" completion descriptor use */
+ req_mgr_h->dummy_comp_buff = dma_alloc_coherent(&drvdata->plat_dev->dev,
+ sizeof(uint32_t), &req_mgr_h->dummy_comp_buff_dma, GFP_KERNEL);
+ if (!req_mgr_h->dummy_comp_buff) {
+ SSI_LOG_ERR("Not enough memory to allocate DMA (%zu) dropped "
+ "buffer\n", sizeof(uint32_t));
+ rc = -ENOMEM;
+ goto req_mgr_init_err;
+ }
+ SSI_UPDATE_DMA_ADDR_TO_48BIT(req_mgr_h->dummy_comp_buff_dma,
+ sizeof(uint32_t));
+
+ /* Init. "dummy" completion descriptor */
+ HW_DESC_INIT(&req_mgr_h->compl_desc);
+ HW_DESC_SET_DIN_CONST(&req_mgr_h->compl_desc, 0, sizeof(uint32_t));
+ HW_DESC_SET_DOUT_DLLI(&req_mgr_h->compl_desc,
+ req_mgr_h->dummy_comp_buff_dma,
+ sizeof(uint32_t), NS_BIT, 1);
+ HW_DESC_SET_FLOW_MODE(&req_mgr_h->compl_desc, BYPASS);
+ HW_DESC_SET_QUEUE_LAST_IND(&req_mgr_h->compl_desc);
+
+#ifdef CC_CYCLE_COUNT
+ /* For CC-HW cycle performance trace */
+ INIT_CC_MONITOR_DESC(&req_mgr_h->monitor_desc);
+ set_bit(MONITOR_CNTR_BIT, &req_mgr_h->monitor_lock);
+ monitor_desc[0] = req_mgr_h->monitor_desc;
+ monitor_desc[1] = req_mgr_h->monitor_desc;
+
+ rc = send_request(drvdata, &monitor_req, monitor_desc, 2, 0);
+ if (unlikely(rc != 0))
+ goto req_mgr_init_err;
+
+ drvdata->monitor_null_cycles = READ_REGISTER(drvdata->cc_base +
+ CC_REG_OFFSET(CRY_KERNEL, DSCRPTR_MEASURE_CNTR));
+ SSI_LOG_ERR("Calibration time=0x%08x\n", drvdata->monitor_null_cycles);
+
+ clear_bit(MONITOR_CNTR_BIT, &req_mgr_h->monitor_lock);
+#endif
+
+ return 0;
+
+req_mgr_init_err:
+ request_mgr_fini(drvdata);
+ return rc;
+}
+
+static inline void enqueue_seq(
+ void __iomem *cc_base,
+ HwDesc_s seq[], unsigned int seq_len)
+{
+ int i;
+
+ for (i = 0; i < seq_len; i++) {
+ writel_relaxed(seq[i].word[0], (volatile void __iomem *)(cc_base+CC_REG_OFFSET(CRY_KERNEL, DSCRPTR_QUEUE_WORD0)));
+ writel_relaxed(seq[i].word[1], (volatile void __iomem *)(cc_base+CC_REG_OFFSET(CRY_KERNEL, DSCRPTR_QUEUE_WORD0)));
+ writel_relaxed(seq[i].word[2], (volatile void __iomem *)(cc_base+CC_REG_OFFSET(CRY_KERNEL, DSCRPTR_QUEUE_WORD0)));
+ writel_relaxed(seq[i].word[3], (volatile void __iomem *)(cc_base+CC_REG_OFFSET(CRY_KERNEL, DSCRPTR_QUEUE_WORD0)));
+ writel_relaxed(seq[i].word[4], (volatile void __iomem *)(cc_base+CC_REG_OFFSET(CRY_KERNEL, DSCRPTR_QUEUE_WORD0)));
+ wmb();
+ writel_relaxed(seq[i].word[5], (volatile void __iomem *)(cc_base+CC_REG_OFFSET(CRY_KERNEL, DSCRPTR_QUEUE_WORD0)));
+#ifdef DX_DUMP_DESCS
+ SSI_LOG_DEBUG("desc[%02d]: 0x%08X 0x%08X 0x%08X 0x%08X 0x%08X 0x%08X\n", i,
+ seq[i].word[0], seq[i].word[1], seq[i].word[2], seq[i].word[3], seq[i].word[4], seq[i].word[5]);
+#endif
+ }
+}
+
+/*!
+ * Completion will take place if and only if user requested completion
+ * by setting "is_dout = 0" in send_request().
+ *
+ * \param dev
+ * \param dx_compl_h The completion event to signal
+ */
+static void request_mgr_complete(struct device *dev, void *dx_compl_h, void __iomem *cc_base)
+{
+ struct completion *this_compl = dx_compl_h;
+ complete(this_compl);
+}
+
+
+static inline int request_mgr_queues_status_check(
+ struct ssi_request_mgr_handle *req_mgr_h,
+ void __iomem *cc_base,
+ unsigned int total_seq_len)
+{
+ unsigned long poll_queue;
+
+ /* SW queue is checked only once as it will not
+ be chaned during the poll becasue the spinlock_bh
+ is held by the thread */
+ if (unlikely(((req_mgr_h->req_queue_head + 1) &
+ (MAX_REQUEST_QUEUE_SIZE - 1)) ==
+ req_mgr_h->req_queue_tail)) {
+ SSI_LOG_ERR("SW FIFO is full. req_queue_head=%d sw_fifo_len=%d\n",
+ req_mgr_h->req_queue_head, MAX_REQUEST_QUEUE_SIZE);
+ return -EBUSY;
+ }
+
+ if ((likely(req_mgr_h->q_free_slots >= total_seq_len)) ) {
+ return 0;
+ }
+ /* Wait for space in HW queue. Poll constant num of iterations. */
+ for (poll_queue =0; poll_queue < SSI_MAX_POLL_ITER ; poll_queue ++) {
+ req_mgr_h->q_free_slots =
+ CC_HAL_READ_REGISTER(
+ CC_REG_OFFSET(CRY_KERNEL,
+ DSCRPTR_QUEUE_CONTENT));
+ if (unlikely(req_mgr_h->q_free_slots <
+ req_mgr_h->min_free_hw_slots)) {
+ req_mgr_h->min_free_hw_slots = req_mgr_h->q_free_slots;
+ }
+
+ if (likely (req_mgr_h->q_free_slots >= total_seq_len)) {
+ /* If there is enough place return */
+ return 0;
+ }
+
+ SSI_LOG_DEBUG("HW FIFO is full. q_free_slots=%d total_seq_len=%d\n",
+ req_mgr_h->q_free_slots, total_seq_len);
+ }
+ /* No room in the HW queue try again later */
+ SSI_LOG_DEBUG("HW FIFO full, timeout. req_queue_head=%d "
+ "sw_fifo_len=%d q_free_slots=%d total_seq_len=%d\n",
+ req_mgr_h->req_queue_head,
+ MAX_REQUEST_QUEUE_SIZE,
+ req_mgr_h->q_free_slots,
+ total_seq_len);
+ return -EAGAIN;
+}
+
+/*!
+ * Enqueue caller request to crypto hardware.
+ *
+ * \param drvdata
+ * \param ssi_req The request to enqueue
+ * \param desc The crypto sequence
+ * \param len The crypto sequence length
+ * \param is_dout If "true": completion is handled by the caller
+ * If "false": this function adds a dummy descriptor completion
+ * and waits upon completion signal.
+ *
+ * \return int Returns -EINPROGRESS if "is_dout=true"; "0" if "is_dout=false"
+ */
+int send_request(
+ struct ssi_drvdata *drvdata, struct ssi_crypto_req *ssi_req,
+ HwDesc_s *desc, unsigned int len, bool is_dout)
+{
+ void __iomem *cc_base = drvdata->cc_base;
+ struct ssi_request_mgr_handle *req_mgr_h = drvdata->request_mgr_handle;
+ unsigned int used_sw_slots;
+ unsigned int iv_seq_len = 0;
+ unsigned int total_seq_len = len; /*initial sequence length*/
+ HwDesc_s iv_seq[SSI_IVPOOL_SEQ_LEN];
+ int rc;
+ unsigned int max_required_seq_len = (total_seq_len +
+ ((ssi_req->ivgen_dma_addr_len == 0) ? 0 :
+ SSI_IVPOOL_SEQ_LEN ) +
+ ((is_dout == 0 )? 1 : 0));
+ DECL_CYCLE_COUNT_RESOURCES;
+
+#if defined (CONFIG_PM_RUNTIME) || defined (CONFIG_PM_SLEEP)
+ rc = ssi_power_mgr_runtime_get(&drvdata->plat_dev->dev);
+ if (rc != 0) {
+ SSI_LOG_ERR("ssi_power_mgr_runtime_get returned %x\n",rc);
+ spin_unlock_bh(&req_mgr_h->hw_lock);
+ return rc;
+ }
+#endif
+
+ do {
+ spin_lock_bh(&req_mgr_h->hw_lock);
+
+ /* Check if there is enough place in the SW/HW queues
+ in case iv gen add the max size and in case of no dout add 1
+ for the internal completion descriptor */
+ rc = request_mgr_queues_status_check(req_mgr_h,
+ cc_base,
+ max_required_seq_len);
+ if (likely(rc == 0 ))
+ /* There is enough place in the queue */
+ break;
+ /* something wrong release the spinlock*/
+ spin_unlock_bh(&req_mgr_h->hw_lock);
+
+ if (rc != -EAGAIN) {
+ /* Any error other than HW queue full
+ (SW queue is full) */
+#if defined (CONFIG_PM_RUNTIME) || defined (CONFIG_PM_SLEEP)
+ ssi_power_mgr_runtime_put_suspend(&drvdata->plat_dev->dev);
+#endif
+ return rc;
+ }
+
+ /* HW queue is full - short sleep */
+ msleep(1);
+ } while (1);
+
+ /* Additional completion descriptor is needed incase caller did not
+ enabled any DLLI/MLLI DOUT bit in the given sequence */
+ if (!is_dout) {
+ init_completion(&ssi_req->seq_compl);
+ ssi_req->user_cb = request_mgr_complete;
+ ssi_req->user_arg = &(ssi_req->seq_compl);
+ total_seq_len++;
+ }
+
+ if (ssi_req->ivgen_dma_addr_len > 0) {
+ SSI_LOG_DEBUG("Acquire IV from pool into %d DMA addresses 0x%llX, 0x%llX, 0x%llX, IV-size=%u\n",
+ ssi_req->ivgen_dma_addr_len,
+ (unsigned long long)ssi_req->ivgen_dma_addr[0],
+ (unsigned long long)ssi_req->ivgen_dma_addr[1],
+ (unsigned long long)ssi_req->ivgen_dma_addr[2],
+ ssi_req->ivgen_size);
+
+ /* Acquire IV from pool */
+ rc = ssi_ivgen_getiv(drvdata, ssi_req->ivgen_dma_addr, ssi_req->ivgen_dma_addr_len,
+ ssi_req->ivgen_size, iv_seq, &iv_seq_len);
+
+ if (unlikely(rc != 0)) {
+ SSI_LOG_ERR("Failed to generate IV (rc=%d)\n", rc);
+ spin_unlock_bh(&req_mgr_h->hw_lock);
+#if defined (CONFIG_PM_RUNTIME) || defined (CONFIG_PM_SLEEP)
+ ssi_power_mgr_runtime_put_suspend(&drvdata->plat_dev->dev);
+#endif
+ return rc;
+ }
+
+ total_seq_len += iv_seq_len;
+ }
+
+ used_sw_slots = ((req_mgr_h->req_queue_head - req_mgr_h->req_queue_tail) & (MAX_REQUEST_QUEUE_SIZE-1));
+ if (unlikely(used_sw_slots > req_mgr_h->max_used_sw_slots)) {
+ req_mgr_h->max_used_sw_slots = used_sw_slots;
+ }
+
+ CC_CYCLE_DESC_HEAD(cc_base, &req_mgr_h->monitor_desc,
+ &req_mgr_h->monitor_lock, &ssi_req->is_monitored_p);
+
+ /* Enqueue request - must be locked with HW lock*/
+ req_mgr_h->req_queue[req_mgr_h->req_queue_head] = *ssi_req;
+ START_CYCLE_COUNT_AT(req_mgr_h->req_queue[req_mgr_h->req_queue_head].submit_cycle);
+ req_mgr_h->req_queue_head = (req_mgr_h->req_queue_head + 1) & (MAX_REQUEST_QUEUE_SIZE - 1);
+ /* TODO: Use circ_buf.h ? */
+
+ SSI_LOG_DEBUG("Enqueue request head=%u\n", req_mgr_h->req_queue_head);
+
+#ifdef FLUSH_CACHE_ALL
+ flush_cache_all();
+#endif
+
+ /* STAT_PHASE_4: Push sequence */
+ START_CYCLE_COUNT();
+ enqueue_seq(cc_base, iv_seq, iv_seq_len);
+ enqueue_seq(cc_base, desc, len);
+ enqueue_seq(cc_base, &req_mgr_h->compl_desc, (is_dout ? 0 : 1));
+ END_CYCLE_COUNT(ssi_req->op_type, STAT_PHASE_4);
+
+ CC_CYCLE_DESC_TAIL(cc_base, &req_mgr_h->monitor_desc, ssi_req->is_monitored_p);
+
+ if (unlikely(req_mgr_h->q_free_slots < total_seq_len)) {
+ /*This means that there was a problem with the resume*/
+ BUG();
+ }
+ /* Update the free slots in HW queue */
+ req_mgr_h->q_free_slots -= total_seq_len;
+
+ spin_unlock_bh(&req_mgr_h->hw_lock);
+
+ if (!is_dout) {
+ /* Wait upon sequence completion.
+ * Return "0" -Operation done successfully. */
+ return wait_for_completion_interruptible(&ssi_req->seq_compl);
+ } else {
+ /* Operation still in process */
+ return -EINPROGRESS;
+ }
+}
+
+
+/*!
+ * Enqueue caller request to crypto hardware during init process.
+ * assume this function is not called in middle of a flow,
+ * since we set QUEUE_LAST_IND flag in the last descriptor.
+ *
+ * \param drvdata
+ * \param desc The crypto sequence
+ * \param len The crypto sequence length
+ *
+ * \return int Returns "0" upon success
+ */
+int send_request_init(
+ struct ssi_drvdata *drvdata, HwDesc_s *desc, unsigned int len)
+{
+ void __iomem *cc_base = drvdata->cc_base;
+ struct ssi_request_mgr_handle *req_mgr_h = drvdata->request_mgr_handle;
+ unsigned int total_seq_len = len; /*initial sequence length*/
+ int rc = 0;
+
+ /* Wait for space in HW and SW FIFO. Poll for as much as FIFO_TIMEOUT. */
+ rc = request_mgr_queues_status_check(req_mgr_h, cc_base, total_seq_len);
+ if (unlikely(rc != 0 )) {
+ return rc;
+ }
+ HW_DESC_SET_QUEUE_LAST_IND(&desc[len-1]);
+
+ enqueue_seq(cc_base, desc, len);
+
+ /* Update the free slots in HW queue */
+ req_mgr_h->q_free_slots = CC_HAL_READ_REGISTER(
+ CC_REG_OFFSET(CRY_KERNEL,
+ DSCRPTR_QUEUE_CONTENT));
+
+ return 0;
+}
+
+
+void complete_request(struct ssi_drvdata *drvdata)
+{
+ struct ssi_request_mgr_handle *request_mgr_handle =
+ drvdata->request_mgr_handle;
+#ifdef COMP_IN_WQ
+ queue_delayed_work(request_mgr_handle->workq, &request_mgr_handle->compwork, 0);
+#else
+ tasklet_schedule(&request_mgr_handle->comptask);
+#endif
+}
+
+#ifdef COMP_IN_WQ
+static void comp_work_handler(struct work_struct *work)
+{
+ struct ssi_drvdata *drvdata =
+ container_of(work, struct ssi_drvdata, compwork.work);
+
+ comp_handler((unsigned long)drvdata);
+}
+#endif
+
+static void proc_completions(struct ssi_drvdata *drvdata)
+{
+ struct ssi_crypto_req *ssi_req;
+ struct platform_device *plat_dev = drvdata->plat_dev;
+ struct ssi_request_mgr_handle * request_mgr_handle =
+ drvdata->request_mgr_handle;
+#if defined (CONFIG_PM_RUNTIME) || defined (CONFIG_PM_SLEEP)
+ int rc = 0;
+#endif
+ DECL_CYCLE_COUNT_RESOURCES;
+
+ while(request_mgr_handle->axi_completed) {
+ request_mgr_handle->axi_completed--;
+
+ /* Dequeue request */
+ if (unlikely(request_mgr_handle->req_queue_head == request_mgr_handle->req_queue_tail)) {
+ SSI_LOG_ERR("Request queue is empty req_queue_head==req_queue_tail==%u\n", request_mgr_handle->req_queue_head);
+ BUG();
+ }
+
+ ssi_req = &request_mgr_handle->req_queue[request_mgr_handle->req_queue_tail];
+ END_CYCLE_COUNT_AT(ssi_req->submit_cycle, ssi_req->op_type, STAT_PHASE_5); /* Seq. Comp. */
+ END_CC_MONITOR_COUNT(drvdata->cc_base, ssi_req->op_type, STAT_PHASE_6,
+ drvdata->monitor_null_cycles, &request_mgr_handle->monitor_lock, ssi_req->is_monitored_p);
+
+#ifdef FLUSH_CACHE_ALL
+ flush_cache_all();
+#endif
+
+#ifdef COMPLETION_DELAY
+ /* Delay */
+ {
+ uint32_t axi_err;
+ int i;
+ SSI_LOG_INFO("Delay\n");
+ for (i=0;i<1000000;i++) {
+ axi_err = READ_REGISTER(drvdata->cc_base + CC_REG_OFFSET(CRY_KERNEL, AXIM_MON_ERR));
+ }
+ }
+#endif /* COMPLETION_DELAY */
+
+ if (likely(ssi_req->user_cb != NULL)) {
+ START_CYCLE_COUNT();
+ ssi_req->user_cb(&plat_dev->dev, ssi_req->user_arg, drvdata->cc_base);
+ END_CYCLE_COUNT(STAT_OP_TYPE_GENERIC, STAT_PHASE_3);
+ }
+ request_mgr_handle->req_queue_tail = (request_mgr_handle->req_queue_tail + 1) & (MAX_REQUEST_QUEUE_SIZE - 1);
+ SSI_LOG_DEBUG("Dequeue request tail=%u\n", request_mgr_handle->req_queue_tail);
+ SSI_LOG_DEBUG("Request completed. axi_completed=%d\n", request_mgr_handle->axi_completed);
+#if defined (CONFIG_PM_RUNTIME) || defined (CONFIG_PM_SLEEP)
+ rc = ssi_power_mgr_runtime_put_suspend(&plat_dev->dev);
+ if (rc != 0) {
+ SSI_LOG_ERR("Failed to set runtime suspension %d\n",rc);
+ }
+#endif
+ }
+}
+
+/* Deferred service handler, run as interrupt-fired tasklet */
+static void comp_handler(unsigned long devarg)
+{
+ struct ssi_drvdata *drvdata = (struct ssi_drvdata *)devarg;
+ void __iomem *cc_base = drvdata->cc_base;
+ struct ssi_request_mgr_handle * request_mgr_handle =
+ drvdata->request_mgr_handle;
+
+ uint32_t irq;
+
+ DECL_CYCLE_COUNT_RESOURCES;
+
+ START_CYCLE_COUNT();
+
+ irq = (drvdata->irq & SSI_COMP_IRQ_MASK);
+
+ if (irq & SSI_COMP_IRQ_MASK) {
+ /* To avoid the interrupt from firing as we unmask it, we clear it now */
+ CC_HAL_WRITE_REGISTER(CC_REG_OFFSET(HOST_RGF, HOST_ICR), SSI_COMP_IRQ_MASK);
+
+ /* Avoid race with above clear: Test completion counter once more */
+ request_mgr_handle->axi_completed += CC_REG_FLD_GET(CRY_KERNEL, AXIM_MON_COMP, VALUE,
+ CC_HAL_READ_REGISTER(AXIM_MON_BASE_OFFSET));
+
+ /* ISR-to-Tasklet latency */
+ if (request_mgr_handle->axi_completed) {
+ /* Only if actually reflects ISR-to-completion-handling latency, i.e.,
+ not duplicate as a result of interrupt after AXIM_MON_ERR clear, before end of loop */
+ END_CYCLE_COUNT_AT(drvdata->isr_exit_cycles, STAT_OP_TYPE_GENERIC, STAT_PHASE_1);
+ }
+
+ while (request_mgr_handle->axi_completed) {
+ do {
+ proc_completions(drvdata);
+ /* At this point (after proc_completions()), request_mgr_handle->axi_completed is always 0.
+ The following assignment was changed to = (previously was +=) to conform KW restrictions. */
+ request_mgr_handle->axi_completed = CC_REG_FLD_GET(CRY_KERNEL, AXIM_MON_COMP, VALUE,
+ CC_HAL_READ_REGISTER(AXIM_MON_BASE_OFFSET));
+ } while (request_mgr_handle->axi_completed > 0);
+
+ /* To avoid the interrupt from firing as we unmask it, we clear it now */
+ CC_HAL_WRITE_REGISTER(CC_REG_OFFSET(HOST_RGF, HOST_ICR), SSI_COMP_IRQ_MASK);
+
+ /* Avoid race with above clear: Test completion counter once more */
+ request_mgr_handle->axi_completed += CC_REG_FLD_GET(CRY_KERNEL, AXIM_MON_COMP, VALUE,
+ CC_HAL_READ_REGISTER(AXIM_MON_BASE_OFFSET));
+ }
+
+ }
+ /* after verifing that there is nothing to do, Unmask AXI completion interrupt */
+ CC_HAL_WRITE_REGISTER(CC_REG_OFFSET(HOST_RGF, HOST_IMR),
+ CC_HAL_READ_REGISTER(
+ CC_REG_OFFSET(HOST_RGF, HOST_IMR)) & ~irq);
+ END_CYCLE_COUNT(STAT_OP_TYPE_GENERIC, STAT_PHASE_2);
+}
+
+/*
+resume the queue configuration - no need to take the lock as this happens inside
+the spin lock protection
+*/
+#if defined (CONFIG_PM_RUNTIME) || defined (CONFIG_PM_SLEEP)
+int ssi_request_mgr_runtime_resume_queue(struct ssi_drvdata *drvdata)
+{
+ struct ssi_request_mgr_handle * request_mgr_handle = drvdata->request_mgr_handle;
+
+ spin_lock_bh(&request_mgr_handle->hw_lock);
+ request_mgr_handle->is_runtime_suspended = false;
+ spin_unlock_bh(&request_mgr_handle->hw_lock);
+
+ return 0 ;
+}
+
+/*
+suspend the queue configuration. Since it is used for the runtime suspend
+only verify that the queue can be suspended.
+*/
+int ssi_request_mgr_runtime_suspend_queue(struct ssi_drvdata *drvdata)
+{
+ struct ssi_request_mgr_handle * request_mgr_handle =
+ drvdata->request_mgr_handle;
+
+ /* lock the send_request */
+ spin_lock_bh(&request_mgr_handle->hw_lock);
+ if (request_mgr_handle->req_queue_head !=
+ request_mgr_handle->req_queue_tail) {
+ spin_unlock_bh(&request_mgr_handle->hw_lock);
+ return -EBUSY;
+ }
+ request_mgr_handle->is_runtime_suspended = true;
+ spin_unlock_bh(&request_mgr_handle->hw_lock);
+
+ return 0;
+}
+
+bool ssi_request_mgr_is_queue_runtime_suspend(struct ssi_drvdata *drvdata)
+{
+ struct ssi_request_mgr_handle * request_mgr_handle =
+ drvdata->request_mgr_handle;
+
+ return request_mgr_handle->is_runtime_suspended;
+}
+
+#endif
+
diff --git a/drivers/staging/ccree/ssi_request_mgr.h b/drivers/staging/ccree/ssi_request_mgr.h
new file mode 100644
index 0000000..c09339b
--- /dev/null
+++ b/drivers/staging/ccree/ssi_request_mgr.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2012-2017 ARM Limited or its affiliates.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* \file request_mgr.h
+ Request Manager
+ */
+
+#ifndef __REQUEST_MGR_H__
+#define __REQUEST_MGR_H__
+
+#include "cc_hw_queue_defs.h"
+
+int request_mgr_init(struct ssi_drvdata *drvdata);
+
+/*!
+ * Enqueue caller request to crypto hardware.
+ *
+ * \param drvdata
+ * \param ssi_req The request to enqueue
+ * \param desc The crypto sequence
+ * \param len The crypto sequence length
+ * \param is_dout If "true": completion is handled by the caller
+ * If "false": this function adds a dummy descriptor completion
+ * and waits upon completion signal.
+ *
+ * \return int Returns -EINPROGRESS if "is_dout=ture"; "0" if "is_dout=false"
+ */
+int send_request(
+ struct ssi_drvdata *drvdata, struct ssi_crypto_req *ssi_req,
+ HwDesc_s *desc, unsigned int len, bool is_dout);
+
+int send_request_init(
+ struct ssi_drvdata *drvdata, HwDesc_s *desc, unsigned int len);
+
+void complete_request(struct ssi_drvdata *drvdata);
+
+void request_mgr_fini(struct ssi_drvdata *drvdata);
+
+#if defined (CONFIG_PM_RUNTIME) || defined (CONFIG_PM_SLEEP)
+int ssi_request_mgr_runtime_resume_queue(struct ssi_drvdata *drvdata);
+
+int ssi_request_mgr_runtime_suspend_queue(struct ssi_drvdata *drvdata);
+
+bool ssi_request_mgr_is_queue_runtime_suspend(struct ssi_drvdata *drvdata);
+#endif
+
+#endif /*__REQUEST_MGR_H__*/
diff --git a/drivers/staging/ccree/ssi_sram_mgr.c b/drivers/staging/ccree/ssi_sram_mgr.c
new file mode 100644
index 0000000..50066e1
--- /dev/null
+++ b/drivers/staging/ccree/ssi_sram_mgr.c
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2012-2017 ARM Limited or its affiliates.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "ssi_driver.h"
+#include "ssi_sram_mgr.h"
+
+
+/**
+ * struct ssi_sram_mgr_ctx -Internal RAM context manager
+ * @sram_free_offset: the offset to the non-allocated area
+ */
+struct ssi_sram_mgr_ctx {
+ ssi_sram_addr_t sram_free_offset;
+};
+
+
+/**
+ * ssi_sram_mgr_fini() - Cleanup SRAM pool.
+ *
+ * @drvdata: Associated device driver context
+ */
+void ssi_sram_mgr_fini(struct ssi_drvdata *drvdata)
+{
+ struct ssi_sram_mgr_ctx *smgr_ctx = drvdata->sram_mgr_handle;
+
+ /* Free "this" context */
+ if (smgr_ctx != NULL) {
+ memset(smgr_ctx, 0, sizeof(struct ssi_sram_mgr_ctx));
+ kfree(smgr_ctx);
+ }
+}
+
+/**
+ * ssi_sram_mgr_init() - Initializes SRAM pool.
+ * The pool starts right at the beginning of SRAM.
+ * Returns zero for success, negative value otherwise.
+ *
+ * @drvdata: Associated device driver context
+ */
+int ssi_sram_mgr_init(struct ssi_drvdata *drvdata)
+{
+ struct ssi_sram_mgr_ctx *smgr_ctx;
+ int rc;
+
+ /* Allocate "this" context */
+ drvdata->sram_mgr_handle = kzalloc(
+ sizeof(struct ssi_sram_mgr_ctx), GFP_KERNEL);
+ if (!drvdata->sram_mgr_handle) {
+ SSI_LOG_ERR("Not enough memory to allocate SRAM_MGR ctx (%zu)\n",
+ sizeof(struct ssi_sram_mgr_ctx));
+ rc = -ENOMEM;
+ goto out;
+ }
+ smgr_ctx = drvdata->sram_mgr_handle;
+
+ /* Pool starts at start of SRAM */
+ smgr_ctx->sram_free_offset = 0;
+
+ return 0;
+
+out:
+ ssi_sram_mgr_fini(drvdata);
+ return rc;
+}
+
+/*!
+ * Allocated buffer from SRAM pool.
+ * Note: Caller is responsible to free the LAST allocated buffer.
+ * This function does not taking care of any fragmentation may occur
+ * by the order of calls to alloc/free.
+ *
+ * \param drvdata
+ * \param size The requested bytes to allocate
+ */
+ssi_sram_addr_t ssi_sram_mgr_alloc(struct ssi_drvdata *drvdata, uint32_t size)
+{
+ struct ssi_sram_mgr_ctx *smgr_ctx = drvdata->sram_mgr_handle;
+ ssi_sram_addr_t p;
+
+ if (unlikely((size & 0x3) != 0)) {
+ SSI_LOG_ERR("Requested buffer size (%u) is not multiple of 4",
+ size);
+ return NULL_SRAM_ADDR;
+ }
+ if (unlikely(size > (SSI_CC_SRAM_SIZE - smgr_ctx->sram_free_offset))) {
+ SSI_LOG_ERR("Not enough space to allocate %u B (at offset %llu)\n",
+ size, smgr_ctx->sram_free_offset);
+ return NULL_SRAM_ADDR;
+ }
+
+ p = smgr_ctx->sram_free_offset;
+ smgr_ctx->sram_free_offset += size;
+ SSI_LOG_DEBUG("Allocated %u B @ %u\n", size, (unsigned int)p);
+ return p;
+}
+
+/**
+ * ssi_sram_mgr_const2sram_desc() - Create const descriptors sequence to
+ * set values in given array into SRAM.
+ * Note: each const value can't exceed word size.
+ *
+ * @src: A pointer to array of words to set as consts.
+ * @dst: The target SRAM buffer to set into
+ * @nelements: The number of words in "src" array
+ * @seq: A pointer to the given IN/OUT descriptor sequence
+ * @seq_len: A pointer to the given IN/OUT sequence length
+ */
+void ssi_sram_mgr_const2sram_desc(
+ const uint32_t *src, ssi_sram_addr_t dst,
+ unsigned int nelement,
+ HwDesc_s *seq, unsigned int *seq_len)
+{
+ uint32_t i;
+ unsigned int idx = *seq_len;
+
+ for (i = 0; i < nelement; i++, idx++) {
+ HW_DESC_INIT(&seq[idx]);
+ HW_DESC_SET_DIN_CONST(&seq[idx], src[i], sizeof(uint32_t));
+ HW_DESC_SET_DOUT_SRAM(&seq[idx], dst + (i * sizeof(uint32_t)), sizeof(uint32_t));
+ HW_DESC_SET_FLOW_MODE(&seq[idx], BYPASS);
+ }
+
+ *seq_len = idx;
+}
+
diff --git a/drivers/staging/ccree/ssi_sram_mgr.h b/drivers/staging/ccree/ssi_sram_mgr.h
new file mode 100644
index 0000000..d71fbaf
--- /dev/null
+++ b/drivers/staging/ccree/ssi_sram_mgr.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2012-2017 ARM Limited or its affiliates.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __SSI_SRAM_MGR_H__
+#define __SSI_SRAM_MGR_H__
+
+
+#ifndef SSI_CC_SRAM_SIZE
+#define SSI_CC_SRAM_SIZE 4096
+#endif
+
+struct ssi_drvdata;
+
+/**
+ * Address (offset) within CC internal SRAM
+ */
+
+typedef uint64_t ssi_sram_addr_t;
+
+#define NULL_SRAM_ADDR ((ssi_sram_addr_t)-1)
+
+/*!
+ * Initializes SRAM pool.
+ * The first X bytes of SRAM are reserved for ROM usage, hence, pool
+ * starts right after X bytes.
+ *
+ * \param drvdata
+ *
+ * \return int Zero for success, negative value otherwise.
+ */
+int ssi_sram_mgr_init(struct ssi_drvdata *drvdata);
+
+/*!
+ * Uninits SRAM pool.
+ *
+ * \param drvdata
+ */
+void ssi_sram_mgr_fini(struct ssi_drvdata *drvdata);
+
+/*!
+ * Allocated buffer from SRAM pool.
+ * Note: Caller is responsible to free the LAST allocated buffer.
+ * This function does not taking care of any fragmentation may occur
+ * by the order of calls to alloc/free.
+ *
+ * \param drvdata
+ * \param size The requested bytes to allocate
+ */
+ssi_sram_addr_t ssi_sram_mgr_alloc(struct ssi_drvdata *drvdata, uint32_t size);
+
+/**
+ * ssi_sram_mgr_const2sram_desc() - Create const descriptors sequence to
+ * set values in given array into SRAM.
+ * Note: each const value can't exceed word size.
+ *
+ * @src: A pointer to array of words to set as consts.
+ * @dst: The target SRAM buffer to set into
+ * @nelements: The number of words in "src" array
+ * @seq: A pointer to the given IN/OUT descriptor sequence
+ * @seq_len: A pointer to the given IN/OUT sequence length
+ */
+void ssi_sram_mgr_const2sram_desc(
+ const uint32_t *src, ssi_sram_addr_t dst,
+ unsigned int nelement,
+ HwDesc_s *seq, unsigned int *seq_len);
+
+#endif /*__SSI_SRAM_MGR_H__*/
diff --git a/drivers/staging/ccree/ssi_sysfs.c b/drivers/staging/ccree/ssi_sysfs.c
new file mode 100644
index 0000000..7c514c1
--- /dev/null
+++ b/drivers/staging/ccree/ssi_sysfs.c
@@ -0,0 +1,439 @@
+/*
+ * Copyright (C) 2012-2017 ARM Limited or its affiliates.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/kernel.h>
+#include "ssi_config.h"
+#include "ssi_driver.h"
+#include "cc_crypto_ctx.h"
+#include "ssi_sysfs.h"
+
+#ifdef ENABLE_CC_SYSFS
+
+static struct ssi_drvdata *sys_get_drvdata(void);
+
+#ifdef CC_CYCLE_COUNT
+
+#include <asm/timex.h>
+
+struct stat_item {
+ unsigned int min;
+ unsigned int max;
+ cycles_t sum;
+ unsigned int count;
+};
+
+struct stat_name {
+ const char *op_type_name;
+ const char *stat_phase_name[MAX_STAT_PHASES];
+};
+
+static struct stat_name stat_name_db[MAX_STAT_OP_TYPES] =
+{
+ {
+ /* STAT_OP_TYPE_NULL */
+ .op_type_name = "NULL",
+ .stat_phase_name = {NULL},
+ },
+ {
+ .op_type_name = "Encode",
+ .stat_phase_name[STAT_PHASE_0] = "Init and sanity checks",
+ .stat_phase_name[STAT_PHASE_1] = "Map buffers",
+ .stat_phase_name[STAT_PHASE_2] = "Create sequence",
+ .stat_phase_name[STAT_PHASE_3] = "Send Request",
+ .stat_phase_name[STAT_PHASE_4] = "HW-Q push",
+ .stat_phase_name[STAT_PHASE_5] = "Sequence completion",
+ .stat_phase_name[STAT_PHASE_6] = "HW cycles",
+ },
+ { .op_type_name = "Decode",
+ .stat_phase_name[STAT_PHASE_0] = "Init and sanity checks",
+ .stat_phase_name[STAT_PHASE_1] = "Map buffers",
+ .stat_phase_name[STAT_PHASE_2] = "Create sequence",
+ .stat_phase_name[STAT_PHASE_3] = "Send Request",
+ .stat_phase_name[STAT_PHASE_4] = "HW-Q push",
+ .stat_phase_name[STAT_PHASE_5] = "Sequence completion",
+ .stat_phase_name[STAT_PHASE_6] = "HW cycles",
+ },
+ { .op_type_name = "Setkey",
+ .stat_phase_name[STAT_PHASE_0] = "Init and sanity checks",
+ .stat_phase_name[STAT_PHASE_1] = "Copy key to ctx",
+ .stat_phase_name[STAT_PHASE_2] = "Create sequence",
+ .stat_phase_name[STAT_PHASE_3] = "Send Request",
+ .stat_phase_name[STAT_PHASE_4] = "HW-Q push",
+ .stat_phase_name[STAT_PHASE_5] = "Sequence completion",
+ .stat_phase_name[STAT_PHASE_6] = "HW cycles",
+ },
+ {
+ .op_type_name = "Generic",
+ .stat_phase_name[STAT_PHASE_0] = "Interrupt",
+ .stat_phase_name[STAT_PHASE_1] = "ISR-to-Tasklet",
+ .stat_phase_name[STAT_PHASE_2] = "Tasklet start-to-end",
+ .stat_phase_name[STAT_PHASE_3] = "Tasklet:user_cb()",
+ .stat_phase_name[STAT_PHASE_4] = "Tasklet:dx_X_complete() - w/o X_complete()",
+ .stat_phase_name[STAT_PHASE_5] = "",
+ .stat_phase_name[STAT_PHASE_6] = "HW cycles",
+ }
+};
+
+/*
+ * Structure used to create a directory
+ * and its attributes in sysfs.
+ */
+struct sys_dir {
+ struct kobject *sys_dir_kobj;
+ struct attribute_group sys_dir_attr_group;
+ struct attribute **sys_dir_attr_list;
+ uint32_t num_of_attrs;
+ struct ssi_drvdata *drvdata; /* Associated driver context */
+};
+
+/* top level directory structures */
+struct sys_dir sys_top_dir;
+
+static DEFINE_SPINLOCK(stat_lock);
+
+/* List of DBs */
+static struct stat_item stat_host_db[MAX_STAT_OP_TYPES][MAX_STAT_PHASES];
+static struct stat_item stat_cc_db[MAX_STAT_OP_TYPES][MAX_STAT_PHASES];
+
+
+static void init_db(struct stat_item item[MAX_STAT_OP_TYPES][MAX_STAT_PHASES])
+{
+ unsigned int i, j;
+
+ /* Clear db */
+ for (i=0; i<MAX_STAT_OP_TYPES; i++) {
+ for (j=0; j<MAX_STAT_PHASES; j++) {
+ item[i][j].min = 0xFFFFFFFF;
+ item[i][j].max = 0;
+ item[i][j].sum = 0;
+ item[i][j].count = 0;
+ }
+ }
+}
+
+static void update_db(struct stat_item *item, unsigned int result)
+{
+ item->count++;
+ item->sum += result;
+ if (result < item->min)
+ item->min = result;
+ if (result > item->max )
+ item->max = result;
+}
+
+static void display_db(struct stat_item item[MAX_STAT_OP_TYPES][MAX_STAT_PHASES])
+{
+ unsigned int i, j;
+ uint64_t avg;
+
+ for (i=STAT_OP_TYPE_ENCODE; i<MAX_STAT_OP_TYPES; i++) {
+ for (j=0; j<MAX_STAT_PHASES; j++) {
+ if (item[i][j].count > 0) {
+ avg = (uint64_t)item[i][j].sum;
+ do_div(avg, item[i][j].count);
+ SSI_LOG_ERR("%s, %s: min=%d avg=%d max=%d sum=%lld count=%d\n",
+ stat_name_db[i].op_type_name, stat_name_db[i].stat_phase_name[j],
+ item[i][j].min, (int)avg, item[i][j].max, (long long)item[i][j].sum, item[i][j].count);
+ }
+ }
+ }
+}
+
+
+/**************************************
+ * Attributes show functions section *
+ **************************************/
+
+static ssize_t ssi_sys_stats_host_db_clear(struct kobject *kobj,
+ struct kobj_attribute *attr, const char *buf, size_t count)
+{
+ init_db(stat_host_db);
+ return count;
+}
+
+static ssize_t ssi_sys_stats_cc_db_clear(struct kobject *kobj,
+ struct kobj_attribute *attr, const char *buf, size_t count)
+{
+ init_db(stat_cc_db);
+ return count;
+}
+
+static ssize_t ssi_sys_stat_host_db_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ int i, j ;
+ char line[512];
+ uint32_t min_cyc, max_cyc;
+ uint64_t avg;
+ ssize_t buf_len, tmp_len=0;
+
+ buf_len = scnprintf(buf,PAGE_SIZE,
+ "phase\t\t\t\t\t\t\tmin[cy]\tavg[cy]\tmax[cy]\t#samples\n");
+ if ( buf_len <0 )/* scnprintf shouldn't return negative value according to its implementation*/
+ return buf_len;
+ for (i=STAT_OP_TYPE_ENCODE; i<MAX_STAT_OP_TYPES; i++) {
+ for (j=0; j<MAX_STAT_PHASES-1; j++) {
+ if (stat_host_db[i][j].count > 0) {
+ avg = (uint64_t)stat_host_db[i][j].sum;
+ do_div(avg, stat_host_db[i][j].count);
+ min_cyc = stat_host_db[i][j].min;
+ max_cyc = stat_host_db[i][j].max;
+ } else {
+ avg = min_cyc = max_cyc = 0;
+ }
+ tmp_len = scnprintf(line,512,
+ "%s::%s\t\t\t\t\t%6u\t%6u\t%6u\t%7u\n",
+ stat_name_db[i].op_type_name,
+ stat_name_db[i].stat_phase_name[j],
+ min_cyc, (unsigned int)avg, max_cyc,
+ stat_host_db[i][j].count);
+ if ( tmp_len <0 )/* scnprintf shouldn't return negative value according to its implementation*/
+ return buf_len;
+ if ( buf_len + tmp_len >= PAGE_SIZE)
+ return buf_len;
+ buf_len += tmp_len;
+ strncat(buf, line,512);
+ }
+ }
+ return buf_len;
+}
+
+static ssize_t ssi_sys_stat_cc_db_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ int i;
+ char line[256];
+ uint32_t min_cyc, max_cyc;
+ uint64_t avg;
+ ssize_t buf_len,tmp_len=0;
+
+ buf_len = scnprintf(buf,PAGE_SIZE,
+ "phase\tmin[cy]\tavg[cy]\tmax[cy]\t#samples\n");
+ if ( buf_len <0 )/* scnprintf shouldn't return negative value according to its implementation*/
+ return buf_len;
+ for (i=STAT_OP_TYPE_ENCODE; i<MAX_STAT_OP_TYPES; i++) {
+ if (stat_cc_db[i][STAT_PHASE_6].count > 0) {
+ avg = (uint64_t)stat_cc_db[i][STAT_PHASE_6].sum;
+ do_div(avg, stat_cc_db[i][STAT_PHASE_6].count);
+ min_cyc = stat_cc_db[i][STAT_PHASE_6].min;
+ max_cyc = stat_cc_db[i][STAT_PHASE_6].max;
+ } else {
+ avg = min_cyc = max_cyc = 0;
+ }
+ tmp_len = scnprintf(line,256,
+ "%s\t%6u\t%6u\t%6u\t%7u\n",
+ stat_name_db[i].op_type_name,
+ min_cyc,
+ (unsigned int)avg,
+ max_cyc,
+ stat_cc_db[i][STAT_PHASE_6].count);
+
+ if ( tmp_len < 0 )/* scnprintf shouldn't return negative value according to its implementation*/
+ return buf_len;
+
+ if ( buf_len + tmp_len >= PAGE_SIZE)
+ return buf_len;
+ buf_len += tmp_len;
+ strncat(buf, line,256);
+ }
+ return buf_len;
+}
+
+void update_host_stat(unsigned int op_type, unsigned int phase, cycles_t result)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&stat_lock, flags);
+ update_db(&(stat_host_db[op_type][phase]), (unsigned int)result);
+ spin_unlock_irqrestore(&stat_lock, flags);
+}
+
+void update_cc_stat(
+ unsigned int op_type,
+ unsigned int phase,
+ unsigned int elapsed_cycles)
+{
+ update_db(&(stat_cc_db[op_type][phase]), elapsed_cycles);
+}
+
+void display_all_stat_db(void)
+{
+ SSI_LOG_ERR("\n======= CYCLE COUNT STATS =======\n");
+ display_db(stat_host_db);
+ SSI_LOG_ERR("\n======= CC HW CYCLE COUNT STATS =======\n");
+ display_db(stat_cc_db);
+}
+#endif /*CC_CYCLE_COUNT*/
+
+
+
+static ssize_t ssi_sys_regdump_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ struct ssi_drvdata *drvdata = sys_get_drvdata();
+ uint32_t register_value;
+ void __iomem* cc_base = drvdata->cc_base;
+ int offset = 0;
+
+ register_value = CC_HAL_READ_REGISTER(CC_REG_OFFSET(HOST_RGF, HOST_SIGNATURE));
+ offset += scnprintf(buf + offset, PAGE_SIZE - offset, "%s \t(0x%lX)\t 0x%08X \n", "HOST_SIGNATURE ", DX_HOST_SIGNATURE_REG_OFFSET, register_value);
+ register_value = CC_HAL_READ_REGISTER(CC_REG_OFFSET(HOST_RGF, HOST_IRR));
+ offset += scnprintf(buf + offset, PAGE_SIZE - offset, "%s \t(0x%lX)\t 0x%08X \n", "HOST_IRR ", DX_HOST_IRR_REG_OFFSET, register_value);
+ register_value = CC_HAL_READ_REGISTER(CC_REG_OFFSET(HOST_RGF, HOST_POWER_DOWN_EN));
+ offset += scnprintf(buf + offset, PAGE_SIZE - offset, "%s \t(0x%lX)\t 0x%08X \n", "HOST_POWER_DOWN_EN ", DX_HOST_POWER_DOWN_EN_REG_OFFSET, register_value);
+ register_value = CC_HAL_READ_REGISTER(CC_REG_OFFSET(CRY_KERNEL, AXIM_MON_ERR));
+ offset += scnprintf(buf + offset, PAGE_SIZE - offset, "%s \t(0x%lX)\t 0x%08X \n", "AXIM_MON_ERR ", DX_AXIM_MON_ERR_REG_OFFSET, register_value);
+ register_value = CC_HAL_READ_REGISTER(CC_REG_OFFSET(CRY_KERNEL, DSCRPTR_QUEUE_CONTENT));
+ offset += scnprintf(buf + offset, PAGE_SIZE - offset, "%s \t(0x%lX)\t 0x%08X \n", "DSCRPTR_QUEUE_CONTENT", DX_DSCRPTR_QUEUE_CONTENT_REG_OFFSET, register_value);
+ return offset;
+}
+
+static ssize_t ssi_sys_help_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ char* help_str[]={
+ "cat reg_dump ", "Print several of CC register values",
+ #if defined CC_CYCLE_COUNT
+ "cat stats_host ", "Print host statistics",
+ "echo <number> > stats_host", "Clear host statistics database",
+ "cat stats_cc ", "Print CC statistics",
+ "echo <number> > stats_cc ", "Clear CC statistics database",
+ #endif
+ };
+ int i=0, offset = 0;
+
+ offset += scnprintf(buf + offset, PAGE_SIZE - offset, "Usage:\n");
+ for ( i = 0; i < ARRAY_SIZE(help_str); i+=2) {
+ offset += scnprintf(buf + offset, PAGE_SIZE - offset, "%s\t\t%s\n", help_str[i], help_str[i+1]);
+ }
+ return offset;
+}
+
+/********************************************************
+ * SYSFS objects *
+ ********************************************************/
+/*
+ * Structure used to create a directory
+ * and its attributes in sysfs.
+ */
+struct sys_dir {
+ struct kobject *sys_dir_kobj;
+ struct attribute_group sys_dir_attr_group;
+ struct attribute **sys_dir_attr_list;
+ uint32_t num_of_attrs;
+ struct ssi_drvdata *drvdata; /* Associated driver context */
+};
+
+/* top level directory structures */
+static struct sys_dir sys_top_dir;
+
+/* TOP LEVEL ATTRIBUTES */
+static struct kobj_attribute ssi_sys_top_level_attrs[] = {
+ __ATTR(dump_regs, 0444, ssi_sys_regdump_show, NULL),
+ __ATTR(help, 0444, ssi_sys_help_show, NULL),
+#if defined CC_CYCLE_COUNT
+ __ATTR(stats_host, 0664, ssi_sys_stat_host_db_show, ssi_sys_stats_host_db_clear),
+ __ATTR(stats_cc, 0664, ssi_sys_stat_cc_db_show, ssi_sys_stats_cc_db_clear),
+#endif
+
+};
+
+static struct ssi_drvdata *sys_get_drvdata(void)
+{
+ /* TODO: supporting multiple SeP devices would require avoiding
+ * global "top_dir" and finding associated "top_dir" by traversing
+ * up the tree to the kobject which matches one of the top_dir's */
+ return sys_top_dir.drvdata;
+}
+
+static int sys_init_dir(struct sys_dir *sys_dir, struct ssi_drvdata *drvdata,
+ struct kobject *parent_dir_kobj, const char *dir_name,
+ struct kobj_attribute *attrs, uint32_t num_of_attrs)
+{
+ int i;
+
+ memset(sys_dir, 0, sizeof(struct sys_dir));
+
+ sys_dir->drvdata = drvdata;
+
+ /* initialize directory kobject */
+ sys_dir->sys_dir_kobj =
+ kobject_create_and_add(dir_name, parent_dir_kobj);
+
+ if (!(sys_dir->sys_dir_kobj))
+ return -ENOMEM;
+ /* allocate memory for directory's attributes list */
+ sys_dir->sys_dir_attr_list =
+ kzalloc(sizeof(struct attribute *) * (num_of_attrs + 1),
+ GFP_KERNEL);
+
+ if (!(sys_dir->sys_dir_attr_list)) {
+ kobject_put(sys_dir->sys_dir_kobj);
+ return -ENOMEM;
+ }
+
+ sys_dir->num_of_attrs = num_of_attrs;
+
+ /* initialize attributes list */
+ for (i = 0; i < num_of_attrs; ++i)
+ sys_dir->sys_dir_attr_list[i] = &(attrs[i].attr);
+
+ /* last list entry should be NULL */
+ sys_dir->sys_dir_attr_list[num_of_attrs] = NULL;
+
+ sys_dir->sys_dir_attr_group.attrs = sys_dir->sys_dir_attr_list;
+
+ return sysfs_create_group(sys_dir->sys_dir_kobj,
+ &(sys_dir->sys_dir_attr_group));
+}
+
+static void sys_free_dir(struct sys_dir *sys_dir)
+{
+ if (!sys_dir)
+ return;
+
+ kfree(sys_dir->sys_dir_attr_list);
+
+ if (sys_dir->sys_dir_kobj != NULL)
+ kobject_put(sys_dir->sys_dir_kobj);
+}
+
+int ssi_sysfs_init(struct kobject *sys_dev_obj, struct ssi_drvdata *drvdata)
+{
+ int retval;
+
+#if defined CC_CYCLE_COUNT
+ /* Init. statistics */
+ init_db(stat_host_db);
+ init_db(stat_cc_db);
+#endif
+
+ SSI_LOG_ERR("setup sysfs under %s\n", sys_dev_obj->name);
+
+ /* Initialize top directory */
+ retval = sys_init_dir(&sys_top_dir, drvdata, sys_dev_obj,
+ "cc_info", ssi_sys_top_level_attrs,
+ ARRAY_SIZE(ssi_sys_top_level_attrs));
+ return retval;
+}
+
+void ssi_sysfs_fini(void)
+{
+ sys_free_dir(&sys_top_dir);
+}
+
+#endif /*ENABLE_CC_SYSFS*/
+
diff --git a/drivers/staging/ccree/ssi_sysfs.h b/drivers/staging/ccree/ssi_sysfs.h
new file mode 100644
index 0000000..baeac1d
--- /dev/null
+++ b/drivers/staging/ccree/ssi_sysfs.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2012-2017 ARM Limited or its affiliates.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* \file ssi_sysfs.h
+ ARM CryptoCell sysfs APIs
+ */
+
+#ifndef __SSI_SYSFS_H__
+#define __SSI_SYSFS_H__
+
+#include <asm/timex.h>
+
+/* forward declaration */
+struct ssi_drvdata;
+
+enum stat_phase {
+ STAT_PHASE_0 = 0,
+ STAT_PHASE_1,
+ STAT_PHASE_2,
+ STAT_PHASE_3,
+ STAT_PHASE_4,
+ STAT_PHASE_5,
+ STAT_PHASE_6,
+ MAX_STAT_PHASES,
+};
+enum stat_op {
+ STAT_OP_TYPE_NULL = 0,
+ STAT_OP_TYPE_ENCODE,
+ STAT_OP_TYPE_DECODE,
+ STAT_OP_TYPE_SETKEY,
+ STAT_OP_TYPE_GENERIC,
+ MAX_STAT_OP_TYPES,
+};
+
+int ssi_sysfs_init(struct kobject *sys_dev_obj, struct ssi_drvdata *drvdata);
+void ssi_sysfs_fini(void);
+void update_host_stat(unsigned int op_type, unsigned int phase, cycles_t result);
+void update_cc_stat(unsigned int op_type, unsigned int phase, unsigned int elapsed_cycles);
+void display_all_stat_db(void);
+
+#endif /*__SSI_SYSFS_H__*/
OpenPOWER on IntegriCloud