Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

MIPS: crypto: Add crc32 and crc32c hw accelerated module

This module registers crc32 and crc32c algorithms that use the
optional CRC32[bhwd] and CRC32C[bhwd] instructions in MIPSr6 cores.

Signed-off-by: Marcin Nowakowski <marcin.nowakowski@mips.com>
Signed-off-by: James Hogan <jhogan@kernel.org>
Cc: Ralf Baechle <ralf@linux-mips.org>
Cc: "David S. Miller" <davem@davemloft.net>
Cc: linux-mips@linux-mips.org
Cc: linux-crypto@vger.kernel.org
Acked-by: Herbert Xu <herbert@gondor.apana.org.au>
Patchwork: https://patchwork.linux-mips.org/patch/18601/
[jhogan@kernel.org: Add CRYPTO_ALG_OPTIONAL_KEY flag on Eric Biggers'
suggestion, due to commit a208fa8f3303 ("crypto: hash - annotate
algorithms taking optional key") in v4.16-rc1]

authored by

Marcin Nowakowski and committed by
James Hogan
4a5dc51e 256211f2

+370
+4
arch/mips/Kconfig
··· 2028 2028 select CPU_HAS_RIXI 2029 2029 select HAVE_ARCH_BITREVERSE 2030 2030 select MIPS_ASID_BITS_VARIABLE 2031 + select MIPS_CRC_SUPPORT 2031 2032 select MIPS_SPRAM 2032 2033 2033 2034 config EVA ··· 2500 2499 default 8 2501 2500 2502 2501 config MIPS_ASID_BITS_VARIABLE 2502 + bool 2503 + 2504 + config MIPS_CRC_SUPPORT 2503 2505 bool 2504 2506 2505 2507 #
+3
arch/mips/Makefile
··· 222 222 xpa-cflags-$(micromips-ase) += -mmicromips -Wa$(comma)-fatal-warnings 223 223 toolchain-xpa := $(call cc-option-yn,$(xpa-cflags-y) -mxpa) 224 224 cflags-$(toolchain-xpa) += -DTOOLCHAIN_SUPPORTS_XPA 225 + toolchain-crc := $(call cc-option-yn,$(mips-cflags) -Wa$(comma)-mcrc) 226 + cflags-$(toolchain-crc) += -DTOOLCHAIN_SUPPORTS_CRC 225 227 226 228 # 227 229 # Firmware support ··· 332 330 # See arch/mips/Kbuild for content of core part of the kernel 333 331 core-y += arch/mips/ 334 332 333 + drivers-$(CONFIG_MIPS_CRC_SUPPORT) += arch/mips/crypto/ 335 334 drivers-$(CONFIG_OPROFILE) += arch/mips/oprofile/ 336 335 337 336 # suspend and hibernation support
+6
arch/mips/crypto/Makefile
··· 1 + # SPDX-License-Identifier: GPL-2.0 2 + # 3 + # Makefile for MIPS crypto files.. 4 + # 5 + 6 + obj-$(CONFIG_CRYPTO_CRC32_MIPS) += crc32-mips.o
+348
arch/mips/crypto/crc32-mips.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * crc32-mips.c - CRC32 and CRC32C using optional MIPSr6 instructions 4 + * 5 + * Module based on arm64/crypto/crc32-arm.c 6 + * 7 + * Copyright (C) 2014 Linaro Ltd <yazen.ghannam@linaro.org> 8 + * Copyright (C) 2018 MIPS Tech, LLC 9 + */ 10 + 11 + #include <linux/unaligned/access_ok.h> 12 + #include <linux/cpufeature.h> 13 + #include <linux/init.h> 14 + #include <linux/kernel.h> 15 + #include <linux/module.h> 16 + #include <linux/string.h> 17 + #include <asm/mipsregs.h> 18 + 19 + #include <crypto/internal/hash.h> 20 + 21 + enum crc_op_size { 22 + b, h, w, d, 23 + }; 24 + 25 + enum crc_type { 26 + crc32, 27 + crc32c, 28 + }; 29 + 30 + #ifndef TOOLCHAIN_SUPPORTS_CRC 31 + #define _ASM_MACRO_CRC32(OP, SZ, TYPE) \ 32 + _ASM_MACRO_3R(OP, rt, rs, rt2, \ 33 + ".ifnc \\rt, \\rt2\n\t" \ 34 + ".error \"invalid operands \\\"" #OP " \\rt,\\rs,\\rt2\\\"\"\n\t" \ 35 + ".endif\n\t" \ 36 + _ASM_INSN_IF_MIPS(0x7c00000f | (__rt << 16) | (__rs << 21) | \ 37 + ((SZ) << 6) | ((TYPE) << 8)) \ 38 + _ASM_INSN32_IF_MM(0x00000030 | (__rs << 16) | (__rt << 21) | \ 39 + ((SZ) << 14) | ((TYPE) << 3))) 40 + _ASM_MACRO_CRC32(crc32b, 0, 0); 41 + _ASM_MACRO_CRC32(crc32h, 1, 0); 42 + _ASM_MACRO_CRC32(crc32w, 2, 0); 43 + _ASM_MACRO_CRC32(crc32d, 3, 0); 44 + _ASM_MACRO_CRC32(crc32cb, 0, 1); 45 + _ASM_MACRO_CRC32(crc32ch, 1, 1); 46 + _ASM_MACRO_CRC32(crc32cw, 2, 1); 47 + _ASM_MACRO_CRC32(crc32cd, 3, 1); 48 + #define _ASM_SET_CRC "" 49 + #else /* !TOOLCHAIN_SUPPORTS_CRC */ 50 + #define _ASM_SET_CRC ".set\tcrc\n\t" 51 + #endif 52 + 53 + #define _CRC32(crc, value, size, type) \ 54 + do { \ 55 + __asm__ __volatile__( \ 56 + ".set push\n\t" \ 57 + _ASM_SET_CRC \ 58 + #type #size " %0, %1, %0\n\t" \ 59 + ".set pop" \ 60 + : "+r" (crc) \ 61 + : "r" (value)); \ 62 + } while (0) 63 + 64 + #define CRC32(crc, value, size) \ 65 + _CRC32(crc, value, size, crc32) 66 + 67 + #define CRC32C(crc, value, size) \ 68 + _CRC32(crc, value, size, crc32c) 69 + 70 + static u32 crc32_mips_le_hw(u32 crc_, const u8 *p, unsigned int len) 71 + { 72 + u32 crc = crc_; 73 + 74 + #ifdef CONFIG_64BIT 75 + while (len >= sizeof(u64)) { 76 + u64 value = get_unaligned_le64(p); 77 + 78 + CRC32(crc, value, d); 79 + p += sizeof(u64); 80 + len -= sizeof(u64); 81 + } 82 + 83 + if (len & sizeof(u32)) { 84 + #else /* !CONFIG_64BIT */ 85 + while (len >= sizeof(u32)) { 86 + #endif 87 + u32 value = get_unaligned_le32(p); 88 + 89 + CRC32(crc, value, w); 90 + p += sizeof(u32); 91 + len -= sizeof(u32); 92 + } 93 + 94 + if (len & sizeof(u16)) { 95 + u16 value = get_unaligned_le16(p); 96 + 97 + CRC32(crc, value, h); 98 + p += sizeof(u16); 99 + } 100 + 101 + if (len & sizeof(u8)) { 102 + u8 value = *p++; 103 + 104 + CRC32(crc, value, b); 105 + } 106 + 107 + return crc; 108 + } 109 + 110 + static u32 crc32c_mips_le_hw(u32 crc_, const u8 *p, unsigned int len) 111 + { 112 + u32 crc = crc_; 113 + 114 + #ifdef CONFIG_64BIT 115 + while (len >= sizeof(u64)) { 116 + u64 value = get_unaligned_le64(p); 117 + 118 + CRC32C(crc, value, d); 119 + p += sizeof(u64); 120 + len -= sizeof(u64); 121 + } 122 + 123 + if (len & sizeof(u32)) { 124 + #else /* !CONFIG_64BIT */ 125 + while (len >= sizeof(u32)) { 126 + #endif 127 + u32 value = get_unaligned_le32(p); 128 + 129 + CRC32C(crc, value, w); 130 + p += sizeof(u32); 131 + len -= sizeof(u32); 132 + } 133 + 134 + if (len & sizeof(u16)) { 135 + u16 value = get_unaligned_le16(p); 136 + 137 + CRC32C(crc, value, h); 138 + p += sizeof(u16); 139 + } 140 + 141 + if (len & sizeof(u8)) { 142 + u8 value = *p++; 143 + 144 + CRC32C(crc, value, b); 145 + } 146 + return crc; 147 + } 148 + 149 + #define CHKSUM_BLOCK_SIZE 1 150 + #define CHKSUM_DIGEST_SIZE 4 151 + 152 + struct chksum_ctx { 153 + u32 key; 154 + }; 155 + 156 + struct chksum_desc_ctx { 157 + u32 crc; 158 + }; 159 + 160 + static int chksum_init(struct shash_desc *desc) 161 + { 162 + struct chksum_ctx *mctx = crypto_shash_ctx(desc->tfm); 163 + struct chksum_desc_ctx *ctx = shash_desc_ctx(desc); 164 + 165 + ctx->crc = mctx->key; 166 + 167 + return 0; 168 + } 169 + 170 + /* 171 + * Setting the seed allows arbitrary accumulators and flexible XOR policy 172 + * If your algorithm starts with ~0, then XOR with ~0 before you set 173 + * the seed. 174 + */ 175 + static int chksum_setkey(struct crypto_shash *tfm, const u8 *key, 176 + unsigned int keylen) 177 + { 178 + struct chksum_ctx *mctx = crypto_shash_ctx(tfm); 179 + 180 + if (keylen != sizeof(mctx->key)) { 181 + crypto_shash_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN); 182 + return -EINVAL; 183 + } 184 + mctx->key = get_unaligned_le32(key); 185 + return 0; 186 + } 187 + 188 + static int chksum_update(struct shash_desc *desc, const u8 *data, 189 + unsigned int length) 190 + { 191 + struct chksum_desc_ctx *ctx = shash_desc_ctx(desc); 192 + 193 + ctx->crc = crc32_mips_le_hw(ctx->crc, data, length); 194 + return 0; 195 + } 196 + 197 + static int chksumc_update(struct shash_desc *desc, const u8 *data, 198 + unsigned int length) 199 + { 200 + struct chksum_desc_ctx *ctx = shash_desc_ctx(desc); 201 + 202 + ctx->crc = crc32c_mips_le_hw(ctx->crc, data, length); 203 + return 0; 204 + } 205 + 206 + static int chksum_final(struct shash_desc *desc, u8 *out) 207 + { 208 + struct chksum_desc_ctx *ctx = shash_desc_ctx(desc); 209 + 210 + put_unaligned_le32(ctx->crc, out); 211 + return 0; 212 + } 213 + 214 + static int chksumc_final(struct shash_desc *desc, u8 *out) 215 + { 216 + struct chksum_desc_ctx *ctx = shash_desc_ctx(desc); 217 + 218 + put_unaligned_le32(~ctx->crc, out); 219 + return 0; 220 + } 221 + 222 + static int __chksum_finup(u32 crc, const u8 *data, unsigned int len, u8 *out) 223 + { 224 + put_unaligned_le32(crc32_mips_le_hw(crc, data, len), out); 225 + return 0; 226 + } 227 + 228 + static int __chksumc_finup(u32 crc, const u8 *data, unsigned int len, u8 *out) 229 + { 230 + put_unaligned_le32(~crc32c_mips_le_hw(crc, data, len), out); 231 + return 0; 232 + } 233 + 234 + static int chksum_finup(struct shash_desc *desc, const u8 *data, 235 + unsigned int len, u8 *out) 236 + { 237 + struct chksum_desc_ctx *ctx = shash_desc_ctx(desc); 238 + 239 + return __chksum_finup(ctx->crc, data, len, out); 240 + } 241 + 242 + static int chksumc_finup(struct shash_desc *desc, const u8 *data, 243 + unsigned int len, u8 *out) 244 + { 245 + struct chksum_desc_ctx *ctx = shash_desc_ctx(desc); 246 + 247 + return __chksumc_finup(ctx->crc, data, len, out); 248 + } 249 + 250 + static int chksum_digest(struct shash_desc *desc, const u8 *data, 251 + unsigned int length, u8 *out) 252 + { 253 + struct chksum_ctx *mctx = crypto_shash_ctx(desc->tfm); 254 + 255 + return __chksum_finup(mctx->key, data, length, out); 256 + } 257 + 258 + static int chksumc_digest(struct shash_desc *desc, const u8 *data, 259 + unsigned int length, u8 *out) 260 + { 261 + struct chksum_ctx *mctx = crypto_shash_ctx(desc->tfm); 262 + 263 + return __chksumc_finup(mctx->key, data, length, out); 264 + } 265 + 266 + static int chksum_cra_init(struct crypto_tfm *tfm) 267 + { 268 + struct chksum_ctx *mctx = crypto_tfm_ctx(tfm); 269 + 270 + mctx->key = ~0; 271 + return 0; 272 + } 273 + 274 + static struct shash_alg crc32_alg = { 275 + .digestsize = CHKSUM_DIGEST_SIZE, 276 + .setkey = chksum_setkey, 277 + .init = chksum_init, 278 + .update = chksum_update, 279 + .final = chksum_final, 280 + .finup = chksum_finup, 281 + .digest = chksum_digest, 282 + .descsize = sizeof(struct chksum_desc_ctx), 283 + .base = { 284 + .cra_name = "crc32", 285 + .cra_driver_name = "crc32-mips-hw", 286 + .cra_priority = 300, 287 + .cra_flags = CRYPTO_ALG_OPTIONAL_KEY, 288 + .cra_blocksize = CHKSUM_BLOCK_SIZE, 289 + .cra_alignmask = 0, 290 + .cra_ctxsize = sizeof(struct chksum_ctx), 291 + .cra_module = THIS_MODULE, 292 + .cra_init = chksum_cra_init, 293 + } 294 + }; 295 + 296 + static struct shash_alg crc32c_alg = { 297 + .digestsize = CHKSUM_DIGEST_SIZE, 298 + .setkey = chksum_setkey, 299 + .init = chksum_init, 300 + .update = chksumc_update, 301 + .final = chksumc_final, 302 + .finup = chksumc_finup, 303 + .digest = chksumc_digest, 304 + .descsize = sizeof(struct chksum_desc_ctx), 305 + .base = { 306 + .cra_name = "crc32c", 307 + .cra_driver_name = "crc32c-mips-hw", 308 + .cra_priority = 300, 309 + .cra_flags = CRYPTO_ALG_OPTIONAL_KEY, 310 + .cra_blocksize = CHKSUM_BLOCK_SIZE, 311 + .cra_alignmask = 0, 312 + .cra_ctxsize = sizeof(struct chksum_ctx), 313 + .cra_module = THIS_MODULE, 314 + .cra_init = chksum_cra_init, 315 + } 316 + }; 317 + 318 + static int __init crc32_mod_init(void) 319 + { 320 + int err; 321 + 322 + err = crypto_register_shash(&crc32_alg); 323 + 324 + if (err) 325 + return err; 326 + 327 + err = crypto_register_shash(&crc32c_alg); 328 + 329 + if (err) { 330 + crypto_unregister_shash(&crc32_alg); 331 + return err; 332 + } 333 + 334 + return 0; 335 + } 336 + 337 + static void __exit crc32_mod_exit(void) 338 + { 339 + crypto_unregister_shash(&crc32_alg); 340 + crypto_unregister_shash(&crc32c_alg); 341 + } 342 + 343 + MODULE_AUTHOR("Marcin Nowakowski <marcin.nowakowski@mips.com"); 344 + MODULE_DESCRIPTION("CRC32 and CRC32C using optional MIPS instructions"); 345 + MODULE_LICENSE("GPL v2"); 346 + 347 + module_cpu_feature_match(MIPS_CRC32, crc32_mod_init); 348 + module_exit(crc32_mod_exit);
+9
crypto/Kconfig
··· 496 496 which will enable any routine to use the CRC-32-IEEE 802.3 checksum 497 497 and gain better performance as compared with the table implementation. 498 498 499 + config CRYPTO_CRC32_MIPS 500 + tristate "CRC32c and CRC32 CRC algorithm (MIPS)" 501 + depends on MIPS_CRC_SUPPORT 502 + select CRYPTO_HASH 503 + help 504 + CRC32c and CRC32 CRC algorithms implemented using mips crypto 505 + instructions, when available. 506 + 507 + 499 508 config CRYPTO_CRCT10DIF 500 509 tristate "CRCT10DIF algorithm" 501 510 select CRYPTO_HASH