From f421258d5bf883b68b1cdaa299a8a1da3eb92e0f Mon Sep 17 00:00:00 2001 From: Aaro Koskinen Date: Sun, 21 Dec 2014 22:53:58 +0200 Subject: MIPS: OCTEON: add crypto helper functions Add crypto helper functions which are needed for kernel level usage. The code for these has been extracted from the EdgeRouter Pro GPL tarball. While at it, also delete duplicate definitions of the functions. Signed-off-by: Aaro Koskinen Signed-off-by: Herbert Xu --- arch/mips/cavium-octeon/Makefile | 1 + arch/mips/cavium-octeon/crypto/Makefile | 5 ++ arch/mips/cavium-octeon/crypto/octeon-crypto.c | 66 ++++++++++++++++++++++++++ arch/mips/cavium-octeon/crypto/octeon-crypto.h | 17 +++++++ arch/mips/include/asm/octeon/octeon.h | 5 -- 5 files changed, 89 insertions(+), 5 deletions(-) create mode 100644 arch/mips/cavium-octeon/crypto/Makefile create mode 100644 arch/mips/cavium-octeon/crypto/octeon-crypto.c create mode 100644 arch/mips/cavium-octeon/crypto/octeon-crypto.h (limited to 'arch/mips') diff --git a/arch/mips/cavium-octeon/Makefile b/arch/mips/cavium-octeon/Makefile index 42f5f1a4b40a..69a8a8dabc2b 100644 --- a/arch/mips/cavium-octeon/Makefile +++ b/arch/mips/cavium-octeon/Makefile @@ -16,6 +16,7 @@ obj-y := cpu.o setup.o octeon-platform.o octeon-irq.o csrc-octeon.o obj-y += dma-octeon.o obj-y += octeon-memcpy.o obj-y += executive/ +obj-y += crypto/ obj-$(CONFIG_MTD) += flash_setup.o obj-$(CONFIG_SMP) += smp.o diff --git a/arch/mips/cavium-octeon/crypto/Makefile b/arch/mips/cavium-octeon/crypto/Makefile new file mode 100644 index 000000000000..739b80366c25 --- /dev/null +++ b/arch/mips/cavium-octeon/crypto/Makefile @@ -0,0 +1,5 @@ +# +# OCTEON-specific crypto modules. +# + +obj-y += octeon-crypto.o diff --git a/arch/mips/cavium-octeon/crypto/octeon-crypto.c b/arch/mips/cavium-octeon/crypto/octeon-crypto.c new file mode 100644 index 000000000000..7c82ff463b65 --- /dev/null +++ b/arch/mips/cavium-octeon/crypto/octeon-crypto.c @@ -0,0 +1,66 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2004-2012 Cavium Networks + */ + +#include +#include +#include + +#include "octeon-crypto.h" + +/** + * Enable access to Octeon's COP2 crypto hardware for kernel use. Wrap any + * crypto operations in calls to octeon_crypto_enable/disable in order to make + * sure the state of COP2 isn't corrupted if userspace is also performing + * hardware crypto operations. Allocate the state parameter on the stack. + * Preemption must be disabled to prevent context switches. + * + * @state: Pointer to state structure to store current COP2 state in. + * + * Returns: Flags to be passed to octeon_crypto_disable() + */ +unsigned long octeon_crypto_enable(struct octeon_cop2_state *state) +{ + int status; + unsigned long flags; + + local_irq_save(flags); + status = read_c0_status(); + write_c0_status(status | ST0_CU2); + if (KSTK_STATUS(current) & ST0_CU2) { + octeon_cop2_save(&(current->thread.cp2)); + KSTK_STATUS(current) &= ~ST0_CU2; + status &= ~ST0_CU2; + } else if (status & ST0_CU2) { + octeon_cop2_save(state); + } + local_irq_restore(flags); + return status & ST0_CU2; +} +EXPORT_SYMBOL_GPL(octeon_crypto_enable); + +/** + * Disable access to Octeon's COP2 crypto hardware in the kernel. This must be + * called after an octeon_crypto_enable() before any context switch or return to + * userspace. + * + * @state: Pointer to COP2 state to restore + * @flags: Return value from octeon_crypto_enable() + */ +void octeon_crypto_disable(struct octeon_cop2_state *state, + unsigned long crypto_flags) +{ + unsigned long flags; + + local_irq_save(flags); + if (crypto_flags & ST0_CU2) + octeon_cop2_restore(state); + else + write_c0_status(read_c0_status() & ~ST0_CU2); + local_irq_restore(flags); +} +EXPORT_SYMBOL_GPL(octeon_crypto_disable); diff --git a/arch/mips/cavium-octeon/crypto/octeon-crypto.h b/arch/mips/cavium-octeon/crypto/octeon-crypto.h new file mode 100644 index 000000000000..5ca86d4ead52 --- /dev/null +++ b/arch/mips/cavium-octeon/crypto/octeon-crypto.h @@ -0,0 +1,17 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2012-2013 Cavium Inc., All Rights Reserved. + */ +#ifndef __LINUX_OCTEON_CRYPTO_H +#define __LINUX_OCTEON_CRYPTO_H + +#include + +extern unsigned long octeon_crypto_enable(struct octeon_cop2_state *state); +extern void octeon_crypto_disable(struct octeon_cop2_state *state, + unsigned long flags); + +#endif /* __LINUX_OCTEON_CRYPTO_H */ diff --git a/arch/mips/include/asm/octeon/octeon.h b/arch/mips/include/asm/octeon/octeon.h index d781f9e66884..6dfefd2d5cdf 100644 --- a/arch/mips/include/asm/octeon/octeon.h +++ b/arch/mips/include/asm/octeon/octeon.h @@ -44,11 +44,6 @@ extern int octeon_get_boot_num_arguments(void); extern const char *octeon_get_boot_argument(int arg); extern void octeon_hal_setup_reserved32(void); extern void octeon_user_io_init(void); -struct octeon_cop2_state; -extern unsigned long octeon_crypto_enable(struct octeon_cop2_state *state); -extern void octeon_crypto_disable(struct octeon_cop2_state *state, - unsigned long flags); -extern asmlinkage void octeon_cop2_restore(struct octeon_cop2_state *task); extern void octeon_init_cvmcount(void); extern void octeon_setup_delays(void); -- cgit v1.2.3 From 1e585ef51c3fdcf296d2ce5cb8c9e74b1a36cfb4 Mon Sep 17 00:00:00 2001 From: Aaro Koskinen Date: Sun, 21 Dec 2014 22:53:59 +0200 Subject: crypto: octeon - add instruction definitions for MD5 Add instruction definitions for MD5. Based on information extracted from EdgeRouter Pro GPL source tarball. Signed-off-by: Aaro Koskinen Signed-off-by: Herbert Xu --- arch/mips/cavium-octeon/crypto/octeon-crypto.h | 56 ++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) (limited to 'arch/mips') diff --git a/arch/mips/cavium-octeon/crypto/octeon-crypto.h b/arch/mips/cavium-octeon/crypto/octeon-crypto.h index 5ca86d4ead52..3f65bc6ccb83 100644 --- a/arch/mips/cavium-octeon/crypto/octeon-crypto.h +++ b/arch/mips/cavium-octeon/crypto/octeon-crypto.h @@ -4,14 +4,70 @@ * for more details. * * Copyright (C) 2012-2013 Cavium Inc., All Rights Reserved. + * + * MD5 instruction definitions added by Aaro Koskinen . + * */ #ifndef __LINUX_OCTEON_CRYPTO_H #define __LINUX_OCTEON_CRYPTO_H #include +#include extern unsigned long octeon_crypto_enable(struct octeon_cop2_state *state); extern void octeon_crypto_disable(struct octeon_cop2_state *state, unsigned long flags); +/* + * Macros needed to implement MD5: + */ + +/* + * The index can be 0-1. + */ +#define write_octeon_64bit_hash_dword(value, index) \ +do { \ + __asm__ __volatile__ ( \ + "dmtc2 %[rt],0x0048+" STR(index) \ + : \ + : [rt] "d" (value)); \ +} while (0) + +/* + * The index can be 0-1. + */ +#define read_octeon_64bit_hash_dword(index) \ +({ \ + u64 __value; \ + \ + __asm__ __volatile__ ( \ + "dmfc2 %[rt],0x0048+" STR(index) \ + : [rt] "=d" (__value) \ + : ); \ + \ + __value; \ +}) + +/* + * The index can be 0-6. + */ +#define write_octeon_64bit_block_dword(value, index) \ +do { \ + __asm__ __volatile__ ( \ + "dmtc2 %[rt],0x0040+" STR(index) \ + : \ + : [rt] "d" (value)); \ +} while (0) + +/* + * The value is the final block dword (64-bit). + */ +#define octeon_md5_start(value) \ +do { \ + __asm__ __volatile__ ( \ + "dmtc2 %[rt],0x4047" \ + : \ + : [rt] "d" (value)); \ +} while (0) + #endif /* __LINUX_OCTEON_CRYPTO_H */ -- cgit v1.2.3 From 011f3c6cbb97859860e451f2a75767cd4c1ffc03 Mon Sep 17 00:00:00 2001 From: Aaro Koskinen Date: Sun, 21 Dec 2014 22:54:00 +0200 Subject: MIPS: OCTEON: reintroduce crypto features check Reintroduce run-time check for crypto features. The old one was deleted because it was unreliable, now decide the crypto availability on early boot when the model string is constructed. Signed-off-by: Aaro Koskinen Signed-off-by: Herbert Xu --- arch/mips/cavium-octeon/executive/octeon-model.c | 6 ++++++ arch/mips/include/asm/octeon/octeon-feature.h | 17 +++++++++++++++-- 2 files changed, 21 insertions(+), 2 deletions(-) (limited to 'arch/mips') diff --git a/arch/mips/cavium-octeon/executive/octeon-model.c b/arch/mips/cavium-octeon/executive/octeon-model.c index e15b049b3bd7..b2104bd9ab3b 100644 --- a/arch/mips/cavium-octeon/executive/octeon-model.c +++ b/arch/mips/cavium-octeon/executive/octeon-model.c @@ -27,6 +27,9 @@ #include +enum octeon_feature_bits __octeon_feature_bits __read_mostly; +EXPORT_SYMBOL_GPL(__octeon_feature_bits); + /** * Read a byte of fuse data * @byte_addr: address to read @@ -103,6 +106,9 @@ static const char *__init octeon_model_get_string_buffer(uint32_t chip_id, else suffix = "NSP"; + if (!fus_dat2.s.nocrypto) + __octeon_feature_bits |= OCTEON_HAS_CRYPTO; + /* * Assume pass number is encoded using <5:3><2:0>. Exceptions * will be fixed later. diff --git a/arch/mips/include/asm/octeon/octeon-feature.h b/arch/mips/include/asm/octeon/octeon-feature.h index c4fe81f47f53..8ebd3f579b84 100644 --- a/arch/mips/include/asm/octeon/octeon-feature.h +++ b/arch/mips/include/asm/octeon/octeon-feature.h @@ -46,8 +46,6 @@ enum octeon_feature { OCTEON_FEATURE_SAAD, /* Does this Octeon support the ZIP offload engine? */ OCTEON_FEATURE_ZIP, - /* Does this Octeon support crypto acceleration using COP2? */ - OCTEON_FEATURE_CRYPTO, OCTEON_FEATURE_DORM_CRYPTO, /* Does this Octeon support PCI express? */ OCTEON_FEATURE_PCIE, @@ -86,6 +84,21 @@ enum octeon_feature { OCTEON_MAX_FEATURE }; +enum octeon_feature_bits { + OCTEON_HAS_CRYPTO = 0x0001, /* Crypto acceleration using COP2 */ +}; +extern enum octeon_feature_bits __octeon_feature_bits; + +/** + * octeon_has_crypto() - Check if this OCTEON has crypto acceleration support. + * + * Returns: Non-zero if the feature exists. Zero if the feature does not exist. + */ +static inline int octeon_has_crypto(void) +{ + return __octeon_feature_bits & OCTEON_HAS_CRYPTO; +} + /** * Determine if the current Octeon supports a specific feature. These * checks have been optimized to be fairly quick, but they should still -- cgit v1.2.3 From 1953c22f53747035b28c36dbb337ac3c10902644 Mon Sep 17 00:00:00 2001 From: Aaro Koskinen Date: Sun, 21 Dec 2014 22:54:01 +0200 Subject: crypto: octeon - add MD5 module Add OCTEON MD5 module. Signed-off-by: Aaro Koskinen Signed-off-by: Herbert Xu --- arch/mips/cavium-octeon/crypto/Makefile | 2 + arch/mips/cavium-octeon/crypto/octeon-crypto.h | 2 + arch/mips/cavium-octeon/crypto/octeon-md5.c | 216 +++++++++++++++++++++++++ 3 files changed, 220 insertions(+) create mode 100644 arch/mips/cavium-octeon/crypto/octeon-md5.c (limited to 'arch/mips') diff --git a/arch/mips/cavium-octeon/crypto/Makefile b/arch/mips/cavium-octeon/crypto/Makefile index 739b80366c25..a74f76d85a2f 100644 --- a/arch/mips/cavium-octeon/crypto/Makefile +++ b/arch/mips/cavium-octeon/crypto/Makefile @@ -3,3 +3,5 @@ # obj-y += octeon-crypto.o + +obj-$(CONFIG_CRYPTO_MD5_OCTEON) += octeon-md5.o diff --git a/arch/mips/cavium-octeon/crypto/octeon-crypto.h b/arch/mips/cavium-octeon/crypto/octeon-crypto.h index 3f65bc6ccb83..e2a4aece9c24 100644 --- a/arch/mips/cavium-octeon/crypto/octeon-crypto.h +++ b/arch/mips/cavium-octeon/crypto/octeon-crypto.h @@ -14,6 +14,8 @@ #include #include +#define OCTEON_CR_OPCODE_PRIORITY 300 + extern unsigned long octeon_crypto_enable(struct octeon_cop2_state *state); extern void octeon_crypto_disable(struct octeon_cop2_state *state, unsigned long flags); diff --git a/arch/mips/cavium-octeon/crypto/octeon-md5.c b/arch/mips/cavium-octeon/crypto/octeon-md5.c new file mode 100644 index 000000000000..b909881ba6c1 --- /dev/null +++ b/arch/mips/cavium-octeon/crypto/octeon-md5.c @@ -0,0 +1,216 @@ +/* + * Cryptographic API. + * + * MD5 Message Digest Algorithm (RFC1321). + * + * Adapted for OCTEON by Aaro Koskinen . + * + * Based on crypto/md5.c, which is: + * + * Derived from cryptoapi implementation, originally based on the + * public domain implementation written by Colin Plumb in 1993. + * + * Copyright (c) Cryptoapi developers. + * Copyright (c) 2002 James Morris + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "octeon-crypto.h" + +/* + * We pass everything as 64-bit. OCTEON can handle misaligned data. + */ + +static void octeon_md5_store_hash(struct md5_state *ctx) +{ + u64 *hash = (u64 *)ctx->hash; + + write_octeon_64bit_hash_dword(hash[0], 0); + write_octeon_64bit_hash_dword(hash[1], 1); +} + +static void octeon_md5_read_hash(struct md5_state *ctx) +{ + u64 *hash = (u64 *)ctx->hash; + + hash[0] = read_octeon_64bit_hash_dword(0); + hash[1] = read_octeon_64bit_hash_dword(1); +} + +static void octeon_md5_transform(const void *_block) +{ + const u64 *block = _block; + + write_octeon_64bit_block_dword(block[0], 0); + write_octeon_64bit_block_dword(block[1], 1); + write_octeon_64bit_block_dword(block[2], 2); + write_octeon_64bit_block_dword(block[3], 3); + write_octeon_64bit_block_dword(block[4], 4); + write_octeon_64bit_block_dword(block[5], 5); + write_octeon_64bit_block_dword(block[6], 6); + octeon_md5_start(block[7]); +} + +static int octeon_md5_init(struct shash_desc *desc) +{ + struct md5_state *mctx = shash_desc_ctx(desc); + + mctx->hash[0] = cpu_to_le32(0x67452301); + mctx->hash[1] = cpu_to_le32(0xefcdab89); + mctx->hash[2] = cpu_to_le32(0x98badcfe); + mctx->hash[3] = cpu_to_le32(0x10325476); + mctx->byte_count = 0; + + return 0; +} + +static int octeon_md5_update(struct shash_desc *desc, const u8 *data, + unsigned int len) +{ + struct md5_state *mctx = shash_desc_ctx(desc); + const u32 avail = sizeof(mctx->block) - (mctx->byte_count & 0x3f); + struct octeon_cop2_state state; + unsigned long flags; + + mctx->byte_count += len; + + if (avail > len) { + memcpy((char *)mctx->block + (sizeof(mctx->block) - avail), + data, len); + return 0; + } + + memcpy((char *)mctx->block + (sizeof(mctx->block) - avail), data, + avail); + + local_bh_disable(); + preempt_disable(); + flags = octeon_crypto_enable(&state); + octeon_md5_store_hash(mctx); + + octeon_md5_transform(mctx->block); + data += avail; + len -= avail; + + while (len >= sizeof(mctx->block)) { + octeon_md5_transform(data); + data += sizeof(mctx->block); + len -= sizeof(mctx->block); + } + + octeon_md5_read_hash(mctx); + octeon_crypto_disable(&state, flags); + preempt_enable(); + local_bh_enable(); + + memcpy(mctx->block, data, len); + + return 0; +} + +static int octeon_md5_final(struct shash_desc *desc, u8 *out) +{ + struct md5_state *mctx = shash_desc_ctx(desc); + const unsigned int offset = mctx->byte_count & 0x3f; + char *p = (char *)mctx->block + offset; + int padding = 56 - (offset + 1); + struct octeon_cop2_state state; + unsigned long flags; + + *p++ = 0x80; + + local_bh_disable(); + preempt_disable(); + flags = octeon_crypto_enable(&state); + octeon_md5_store_hash(mctx); + + if (padding < 0) { + memset(p, 0x00, padding + sizeof(u64)); + octeon_md5_transform(mctx->block); + p = (char *)mctx->block; + padding = 56; + } + + memset(p, 0, padding); + mctx->block[14] = cpu_to_le32(mctx->byte_count << 3); + mctx->block[15] = cpu_to_le32(mctx->byte_count >> 29); + octeon_md5_transform(mctx->block); + + octeon_md5_read_hash(mctx); + octeon_crypto_disable(&state, flags); + preempt_enable(); + local_bh_enable(); + + memcpy(out, mctx->hash, sizeof(mctx->hash)); + memset(mctx, 0, sizeof(*mctx)); + + return 0; +} + +static int octeon_md5_export(struct shash_desc *desc, void *out) +{ + struct md5_state *ctx = shash_desc_ctx(desc); + + memcpy(out, ctx, sizeof(*ctx)); + return 0; +} + +static int octeon_md5_import(struct shash_desc *desc, const void *in) +{ + struct md5_state *ctx = shash_desc_ctx(desc); + + memcpy(ctx, in, sizeof(*ctx)); + return 0; +} + +static struct shash_alg alg = { + .digestsize = MD5_DIGEST_SIZE, + .init = octeon_md5_init, + .update = octeon_md5_update, + .final = octeon_md5_final, + .export = octeon_md5_export, + .import = octeon_md5_import, + .descsize = sizeof(struct md5_state), + .statesize = sizeof(struct md5_state), + .base = { + .cra_name = "md5", + .cra_driver_name= "octeon-md5", + .cra_priority = OCTEON_CR_OPCODE_PRIORITY, + .cra_flags = CRYPTO_ALG_TYPE_SHASH, + .cra_blocksize = MD5_HMAC_BLOCK_SIZE, + .cra_module = THIS_MODULE, + } +}; + +static int __init md5_mod_init(void) +{ + if (!octeon_has_crypto()) + return -ENOTSUPP; + return crypto_register_shash(&alg); +} + +static void __exit md5_mod_fini(void) +{ + crypto_unregister_shash(&alg); +} + +module_init(md5_mod_init); +module_exit(md5_mod_fini); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("MD5 Message Digest Algorithm (OCTEON)"); +MODULE_AUTHOR("Aaro Koskinen "); -- cgit v1.2.3