14a5dc51eSMarcin Nowakowski // SPDX-License-Identifier: GPL-2.0 24a5dc51eSMarcin Nowakowski /* 34a5dc51eSMarcin Nowakowski * crc32-mips.c - CRC32 and CRC32C using optional MIPSr6 instructions 44a5dc51eSMarcin Nowakowski * 54a5dc51eSMarcin Nowakowski * Module based on arm64/crypto/crc32-arm.c 64a5dc51eSMarcin Nowakowski * 74a5dc51eSMarcin Nowakowski * Copyright (C) 2014 Linaro Ltd <yazen.ghannam@linaro.org> 84a5dc51eSMarcin Nowakowski * Copyright (C) 2018 MIPS Tech, LLC 94a5dc51eSMarcin Nowakowski */ 104a5dc51eSMarcin Nowakowski 114a5dc51eSMarcin Nowakowski #include <linux/cpufeature.h> 124a5dc51eSMarcin Nowakowski #include <linux/init.h> 134a5dc51eSMarcin Nowakowski #include <linux/kernel.h> 144a5dc51eSMarcin Nowakowski #include <linux/module.h> 154a5dc51eSMarcin Nowakowski #include <linux/string.h> 164a5dc51eSMarcin Nowakowski #include <asm/mipsregs.h> 17778aaefbSArnd Bergmann #include <asm/unaligned.h> 184a5dc51eSMarcin Nowakowski 194a5dc51eSMarcin Nowakowski #include <crypto/internal/hash.h> 204a5dc51eSMarcin Nowakowski 214a5dc51eSMarcin Nowakowski enum crc_op_size { 224a5dc51eSMarcin Nowakowski b, h, w, d, 234a5dc51eSMarcin Nowakowski }; 244a5dc51eSMarcin Nowakowski 254a5dc51eSMarcin Nowakowski enum crc_type { 264a5dc51eSMarcin Nowakowski crc32, 274a5dc51eSMarcin Nowakowski crc32c, 284a5dc51eSMarcin Nowakowski }; 294a5dc51eSMarcin Nowakowski 304a5dc51eSMarcin Nowakowski #ifndef TOOLCHAIN_SUPPORTS_CRC 31*41022effSPaul Cercueil #define _ASM_SET_CRC(OP, SZ, TYPE) \ 324a5dc51eSMarcin Nowakowski _ASM_MACRO_3R(OP, rt, rs, rt2, \ 334a5dc51eSMarcin Nowakowski ".ifnc \\rt, \\rt2\n\t" \ 344a5dc51eSMarcin Nowakowski ".error \"invalid operands \\\"" #OP " \\rt,\\rs,\\rt2\\\"\"\n\t" \ 354a5dc51eSMarcin Nowakowski ".endif\n\t" \ 364a5dc51eSMarcin Nowakowski _ASM_INSN_IF_MIPS(0x7c00000f | (__rt << 16) | (__rs << 21) | \ 374a5dc51eSMarcin Nowakowski ((SZ) << 6) | ((TYPE) << 8)) \ 384a5dc51eSMarcin Nowakowski _ASM_INSN32_IF_MM(0x00000030 | (__rs << 16) | (__rt << 21) | \ 394a5dc51eSMarcin Nowakowski ((SZ) << 14) | ((TYPE) << 3))) 40*41022effSPaul Cercueil #define _ASM_UNSET_CRC(op, SZ, TYPE) ".purgem " #op "\n\t" 414a5dc51eSMarcin Nowakowski #else /* !TOOLCHAIN_SUPPORTS_CRC */ 42*41022effSPaul Cercueil #define _ASM_SET_CRC(op, SZ, TYPE) ".set\tcrc\n\t" 43*41022effSPaul Cercueil #define _ASM_UNSET_CRC(op, SZ, TYPE) 444a5dc51eSMarcin Nowakowski #endif 454a5dc51eSMarcin Nowakowski 46*41022effSPaul Cercueil #define __CRC32(crc, value, op, SZ, TYPE) \ 474a5dc51eSMarcin Nowakowski do { \ 484a5dc51eSMarcin Nowakowski __asm__ __volatile__( \ 494a5dc51eSMarcin Nowakowski ".set push\n\t" \ 50*41022effSPaul Cercueil _ASM_SET_CRC(op, SZ, TYPE) \ 51*41022effSPaul Cercueil #op " %0, %1, %0\n\t" \ 52*41022effSPaul Cercueil _ASM_UNSET_CRC(op, SZ, TYPE) \ 534a5dc51eSMarcin Nowakowski ".set pop" \ 544a5dc51eSMarcin Nowakowski : "+r" (crc) \ 554a5dc51eSMarcin Nowakowski : "r" (value)); \ 564a5dc51eSMarcin Nowakowski } while (0) 574a5dc51eSMarcin Nowakowski 58*41022effSPaul Cercueil #define _CRC32_crc32b(crc, value) __CRC32(crc, value, crc32b, 0, 0) 59*41022effSPaul Cercueil #define _CRC32_crc32h(crc, value) __CRC32(crc, value, crc32h, 1, 0) 60*41022effSPaul Cercueil #define _CRC32_crc32w(crc, value) __CRC32(crc, value, crc32w, 2, 0) 61*41022effSPaul Cercueil #define _CRC32_crc32d(crc, value) __CRC32(crc, value, crc32d, 3, 0) 62*41022effSPaul Cercueil #define _CRC32_crc32cb(crc, value) __CRC32(crc, value, crc32cb, 0, 1) 63*41022effSPaul Cercueil #define _CRC32_crc32ch(crc, value) __CRC32(crc, value, crc32ch, 1, 1) 64*41022effSPaul Cercueil #define _CRC32_crc32cw(crc, value) __CRC32(crc, value, crc32cw, 2, 1) 65*41022effSPaul Cercueil #define _CRC32_crc32cd(crc, value) __CRC32(crc, value, crc32cd, 3, 1) 66*41022effSPaul Cercueil 67*41022effSPaul Cercueil #define _CRC32(crc, value, size, op) \ 68*41022effSPaul Cercueil _CRC32_##op##size(crc, value) 69*41022effSPaul Cercueil 704a5dc51eSMarcin Nowakowski #define CRC32(crc, value, size) \ 714a5dc51eSMarcin Nowakowski _CRC32(crc, value, size, crc32) 724a5dc51eSMarcin Nowakowski 734a5dc51eSMarcin Nowakowski #define CRC32C(crc, value, size) \ 744a5dc51eSMarcin Nowakowski _CRC32(crc, value, size, crc32c) 754a5dc51eSMarcin Nowakowski 764a5dc51eSMarcin Nowakowski static u32 crc32_mips_le_hw(u32 crc_, const u8 *p, unsigned int len) 774a5dc51eSMarcin Nowakowski { 784a5dc51eSMarcin Nowakowski u32 crc = crc_; 794a5dc51eSMarcin Nowakowski 804a5dc51eSMarcin Nowakowski #ifdef CONFIG_64BIT 814a5dc51eSMarcin Nowakowski while (len >= sizeof(u64)) { 824a5dc51eSMarcin Nowakowski u64 value = get_unaligned_le64(p); 834a5dc51eSMarcin Nowakowski 844a5dc51eSMarcin Nowakowski CRC32(crc, value, d); 854a5dc51eSMarcin Nowakowski p += sizeof(u64); 864a5dc51eSMarcin Nowakowski len -= sizeof(u64); 874a5dc51eSMarcin Nowakowski } 884a5dc51eSMarcin Nowakowski 894a5dc51eSMarcin Nowakowski if (len & sizeof(u32)) { 904a5dc51eSMarcin Nowakowski #else /* !CONFIG_64BIT */ 914a5dc51eSMarcin Nowakowski while (len >= sizeof(u32)) { 924a5dc51eSMarcin Nowakowski #endif 934a5dc51eSMarcin Nowakowski u32 value = get_unaligned_le32(p); 944a5dc51eSMarcin Nowakowski 954a5dc51eSMarcin Nowakowski CRC32(crc, value, w); 964a5dc51eSMarcin Nowakowski p += sizeof(u32); 974a5dc51eSMarcin Nowakowski len -= sizeof(u32); 984a5dc51eSMarcin Nowakowski } 994a5dc51eSMarcin Nowakowski 1004a5dc51eSMarcin Nowakowski if (len & sizeof(u16)) { 1014a5dc51eSMarcin Nowakowski u16 value = get_unaligned_le16(p); 1024a5dc51eSMarcin Nowakowski 1034a5dc51eSMarcin Nowakowski CRC32(crc, value, h); 1044a5dc51eSMarcin Nowakowski p += sizeof(u16); 1054a5dc51eSMarcin Nowakowski } 1064a5dc51eSMarcin Nowakowski 1074a5dc51eSMarcin Nowakowski if (len & sizeof(u8)) { 1084a5dc51eSMarcin Nowakowski u8 value = *p++; 1094a5dc51eSMarcin Nowakowski 1104a5dc51eSMarcin Nowakowski CRC32(crc, value, b); 1114a5dc51eSMarcin Nowakowski } 1124a5dc51eSMarcin Nowakowski 1134a5dc51eSMarcin Nowakowski return crc; 1144a5dc51eSMarcin Nowakowski } 1154a5dc51eSMarcin Nowakowski 1164a5dc51eSMarcin Nowakowski static u32 crc32c_mips_le_hw(u32 crc_, const u8 *p, unsigned int len) 1174a5dc51eSMarcin Nowakowski { 1184a5dc51eSMarcin Nowakowski u32 crc = crc_; 1194a5dc51eSMarcin Nowakowski 1204a5dc51eSMarcin Nowakowski #ifdef CONFIG_64BIT 1214a5dc51eSMarcin Nowakowski while (len >= sizeof(u64)) { 1224a5dc51eSMarcin Nowakowski u64 value = get_unaligned_le64(p); 1234a5dc51eSMarcin Nowakowski 1244a5dc51eSMarcin Nowakowski CRC32C(crc, value, d); 1254a5dc51eSMarcin Nowakowski p += sizeof(u64); 1264a5dc51eSMarcin Nowakowski len -= sizeof(u64); 1274a5dc51eSMarcin Nowakowski } 1284a5dc51eSMarcin Nowakowski 1294a5dc51eSMarcin Nowakowski if (len & sizeof(u32)) { 1304a5dc51eSMarcin Nowakowski #else /* !CONFIG_64BIT */ 1314a5dc51eSMarcin Nowakowski while (len >= sizeof(u32)) { 1324a5dc51eSMarcin Nowakowski #endif 1334a5dc51eSMarcin Nowakowski u32 value = get_unaligned_le32(p); 1344a5dc51eSMarcin Nowakowski 1354a5dc51eSMarcin Nowakowski CRC32C(crc, value, w); 1364a5dc51eSMarcin Nowakowski p += sizeof(u32); 1374a5dc51eSMarcin Nowakowski len -= sizeof(u32); 1384a5dc51eSMarcin Nowakowski } 1394a5dc51eSMarcin Nowakowski 1404a5dc51eSMarcin Nowakowski if (len & sizeof(u16)) { 1414a5dc51eSMarcin Nowakowski u16 value = get_unaligned_le16(p); 1424a5dc51eSMarcin Nowakowski 1434a5dc51eSMarcin Nowakowski CRC32C(crc, value, h); 1444a5dc51eSMarcin Nowakowski p += sizeof(u16); 1454a5dc51eSMarcin Nowakowski } 1464a5dc51eSMarcin Nowakowski 1474a5dc51eSMarcin Nowakowski if (len & sizeof(u8)) { 1484a5dc51eSMarcin Nowakowski u8 value = *p++; 1494a5dc51eSMarcin Nowakowski 1504a5dc51eSMarcin Nowakowski CRC32C(crc, value, b); 1514a5dc51eSMarcin Nowakowski } 1524a5dc51eSMarcin Nowakowski return crc; 1534a5dc51eSMarcin Nowakowski } 1544a5dc51eSMarcin Nowakowski 1554a5dc51eSMarcin Nowakowski #define CHKSUM_BLOCK_SIZE 1 1564a5dc51eSMarcin Nowakowski #define CHKSUM_DIGEST_SIZE 4 1574a5dc51eSMarcin Nowakowski 1584a5dc51eSMarcin Nowakowski struct chksum_ctx { 1594a5dc51eSMarcin Nowakowski u32 key; 1604a5dc51eSMarcin Nowakowski }; 1614a5dc51eSMarcin Nowakowski 1624a5dc51eSMarcin Nowakowski struct chksum_desc_ctx { 1634a5dc51eSMarcin Nowakowski u32 crc; 1644a5dc51eSMarcin Nowakowski }; 1654a5dc51eSMarcin Nowakowski 1664a5dc51eSMarcin Nowakowski static int chksum_init(struct shash_desc *desc) 1674a5dc51eSMarcin Nowakowski { 1684a5dc51eSMarcin Nowakowski struct chksum_ctx *mctx = crypto_shash_ctx(desc->tfm); 1694a5dc51eSMarcin Nowakowski struct chksum_desc_ctx *ctx = shash_desc_ctx(desc); 1704a5dc51eSMarcin Nowakowski 1714a5dc51eSMarcin Nowakowski ctx->crc = mctx->key; 1724a5dc51eSMarcin Nowakowski 1734a5dc51eSMarcin Nowakowski return 0; 1744a5dc51eSMarcin Nowakowski } 1754a5dc51eSMarcin Nowakowski 1764a5dc51eSMarcin Nowakowski /* 1774a5dc51eSMarcin Nowakowski * Setting the seed allows arbitrary accumulators and flexible XOR policy 1784a5dc51eSMarcin Nowakowski * If your algorithm starts with ~0, then XOR with ~0 before you set 1794a5dc51eSMarcin Nowakowski * the seed. 1804a5dc51eSMarcin Nowakowski */ 1814a5dc51eSMarcin Nowakowski static int chksum_setkey(struct crypto_shash *tfm, const u8 *key, 1824a5dc51eSMarcin Nowakowski unsigned int keylen) 1834a5dc51eSMarcin Nowakowski { 1844a5dc51eSMarcin Nowakowski struct chksum_ctx *mctx = crypto_shash_ctx(tfm); 1854a5dc51eSMarcin Nowakowski 186674f368aSEric Biggers if (keylen != sizeof(mctx->key)) 1874a5dc51eSMarcin Nowakowski return -EINVAL; 1884a5dc51eSMarcin Nowakowski mctx->key = get_unaligned_le32(key); 1894a5dc51eSMarcin Nowakowski return 0; 1904a5dc51eSMarcin Nowakowski } 1914a5dc51eSMarcin Nowakowski 1924a5dc51eSMarcin Nowakowski static int chksum_update(struct shash_desc *desc, const u8 *data, 1934a5dc51eSMarcin Nowakowski unsigned int length) 1944a5dc51eSMarcin Nowakowski { 1954a5dc51eSMarcin Nowakowski struct chksum_desc_ctx *ctx = shash_desc_ctx(desc); 1964a5dc51eSMarcin Nowakowski 1974a5dc51eSMarcin Nowakowski ctx->crc = crc32_mips_le_hw(ctx->crc, data, length); 1984a5dc51eSMarcin Nowakowski return 0; 1994a5dc51eSMarcin Nowakowski } 2004a5dc51eSMarcin Nowakowski 2014a5dc51eSMarcin Nowakowski static int chksumc_update(struct shash_desc *desc, const u8 *data, 2024a5dc51eSMarcin Nowakowski unsigned int length) 2034a5dc51eSMarcin Nowakowski { 2044a5dc51eSMarcin Nowakowski struct chksum_desc_ctx *ctx = shash_desc_ctx(desc); 2054a5dc51eSMarcin Nowakowski 2064a5dc51eSMarcin Nowakowski ctx->crc = crc32c_mips_le_hw(ctx->crc, data, length); 2074a5dc51eSMarcin Nowakowski return 0; 2084a5dc51eSMarcin Nowakowski } 2094a5dc51eSMarcin Nowakowski 2104a5dc51eSMarcin Nowakowski static int chksum_final(struct shash_desc *desc, u8 *out) 2114a5dc51eSMarcin Nowakowski { 2124a5dc51eSMarcin Nowakowski struct chksum_desc_ctx *ctx = shash_desc_ctx(desc); 2134a5dc51eSMarcin Nowakowski 2144a5dc51eSMarcin Nowakowski put_unaligned_le32(ctx->crc, out); 2154a5dc51eSMarcin Nowakowski return 0; 2164a5dc51eSMarcin Nowakowski } 2174a5dc51eSMarcin Nowakowski 2184a5dc51eSMarcin Nowakowski static int chksumc_final(struct shash_desc *desc, u8 *out) 2194a5dc51eSMarcin Nowakowski { 2204a5dc51eSMarcin Nowakowski struct chksum_desc_ctx *ctx = shash_desc_ctx(desc); 2214a5dc51eSMarcin Nowakowski 2224a5dc51eSMarcin Nowakowski put_unaligned_le32(~ctx->crc, out); 2234a5dc51eSMarcin Nowakowski return 0; 2244a5dc51eSMarcin Nowakowski } 2254a5dc51eSMarcin Nowakowski 2264a5dc51eSMarcin Nowakowski static int __chksum_finup(u32 crc, const u8 *data, unsigned int len, u8 *out) 2274a5dc51eSMarcin Nowakowski { 2284a5dc51eSMarcin Nowakowski put_unaligned_le32(crc32_mips_le_hw(crc, data, len), out); 2294a5dc51eSMarcin Nowakowski return 0; 2304a5dc51eSMarcin Nowakowski } 2314a5dc51eSMarcin Nowakowski 2324a5dc51eSMarcin Nowakowski static int __chksumc_finup(u32 crc, const u8 *data, unsigned int len, u8 *out) 2334a5dc51eSMarcin Nowakowski { 2344a5dc51eSMarcin Nowakowski put_unaligned_le32(~crc32c_mips_le_hw(crc, data, len), out); 2354a5dc51eSMarcin Nowakowski return 0; 2364a5dc51eSMarcin Nowakowski } 2374a5dc51eSMarcin Nowakowski 2384a5dc51eSMarcin Nowakowski static int chksum_finup(struct shash_desc *desc, const u8 *data, 2394a5dc51eSMarcin Nowakowski unsigned int len, u8 *out) 2404a5dc51eSMarcin Nowakowski { 2414a5dc51eSMarcin Nowakowski struct chksum_desc_ctx *ctx = shash_desc_ctx(desc); 2424a5dc51eSMarcin Nowakowski 2434a5dc51eSMarcin Nowakowski return __chksum_finup(ctx->crc, data, len, out); 2444a5dc51eSMarcin Nowakowski } 2454a5dc51eSMarcin Nowakowski 2464a5dc51eSMarcin Nowakowski static int chksumc_finup(struct shash_desc *desc, const u8 *data, 2474a5dc51eSMarcin Nowakowski unsigned int len, u8 *out) 2484a5dc51eSMarcin Nowakowski { 2494a5dc51eSMarcin Nowakowski struct chksum_desc_ctx *ctx = shash_desc_ctx(desc); 2504a5dc51eSMarcin Nowakowski 2514a5dc51eSMarcin Nowakowski return __chksumc_finup(ctx->crc, data, len, out); 2524a5dc51eSMarcin Nowakowski } 2534a5dc51eSMarcin Nowakowski 2544a5dc51eSMarcin Nowakowski static int chksum_digest(struct shash_desc *desc, const u8 *data, 2554a5dc51eSMarcin Nowakowski unsigned int length, u8 *out) 2564a5dc51eSMarcin Nowakowski { 2574a5dc51eSMarcin Nowakowski struct chksum_ctx *mctx = crypto_shash_ctx(desc->tfm); 2584a5dc51eSMarcin Nowakowski 2594a5dc51eSMarcin Nowakowski return __chksum_finup(mctx->key, data, length, out); 2604a5dc51eSMarcin Nowakowski } 2614a5dc51eSMarcin Nowakowski 2624a5dc51eSMarcin Nowakowski static int chksumc_digest(struct shash_desc *desc, const u8 *data, 2634a5dc51eSMarcin Nowakowski unsigned int length, u8 *out) 2644a5dc51eSMarcin Nowakowski { 2654a5dc51eSMarcin Nowakowski struct chksum_ctx *mctx = crypto_shash_ctx(desc->tfm); 2664a5dc51eSMarcin Nowakowski 2674a5dc51eSMarcin Nowakowski return __chksumc_finup(mctx->key, data, length, out); 2684a5dc51eSMarcin Nowakowski } 2694a5dc51eSMarcin Nowakowski 2704a5dc51eSMarcin Nowakowski static int chksum_cra_init(struct crypto_tfm *tfm) 2714a5dc51eSMarcin Nowakowski { 2724a5dc51eSMarcin Nowakowski struct chksum_ctx *mctx = crypto_tfm_ctx(tfm); 2734a5dc51eSMarcin Nowakowski 2744a5dc51eSMarcin Nowakowski mctx->key = ~0; 2754a5dc51eSMarcin Nowakowski return 0; 2764a5dc51eSMarcin Nowakowski } 2774a5dc51eSMarcin Nowakowski 2784a5dc51eSMarcin Nowakowski static struct shash_alg crc32_alg = { 2794a5dc51eSMarcin Nowakowski .digestsize = CHKSUM_DIGEST_SIZE, 2804a5dc51eSMarcin Nowakowski .setkey = chksum_setkey, 2814a5dc51eSMarcin Nowakowski .init = chksum_init, 2824a5dc51eSMarcin Nowakowski .update = chksum_update, 2834a5dc51eSMarcin Nowakowski .final = chksum_final, 2844a5dc51eSMarcin Nowakowski .finup = chksum_finup, 2854a5dc51eSMarcin Nowakowski .digest = chksum_digest, 2864a5dc51eSMarcin Nowakowski .descsize = sizeof(struct chksum_desc_ctx), 2874a5dc51eSMarcin Nowakowski .base = { 2884a5dc51eSMarcin Nowakowski .cra_name = "crc32", 2894a5dc51eSMarcin Nowakowski .cra_driver_name = "crc32-mips-hw", 2904a5dc51eSMarcin Nowakowski .cra_priority = 300, 2914a5dc51eSMarcin Nowakowski .cra_flags = CRYPTO_ALG_OPTIONAL_KEY, 2924a5dc51eSMarcin Nowakowski .cra_blocksize = CHKSUM_BLOCK_SIZE, 2934a5dc51eSMarcin Nowakowski .cra_alignmask = 0, 2944a5dc51eSMarcin Nowakowski .cra_ctxsize = sizeof(struct chksum_ctx), 2954a5dc51eSMarcin Nowakowski .cra_module = THIS_MODULE, 2964a5dc51eSMarcin Nowakowski .cra_init = chksum_cra_init, 2974a5dc51eSMarcin Nowakowski } 2984a5dc51eSMarcin Nowakowski }; 2994a5dc51eSMarcin Nowakowski 3004a5dc51eSMarcin Nowakowski static struct shash_alg crc32c_alg = { 3014a5dc51eSMarcin Nowakowski .digestsize = CHKSUM_DIGEST_SIZE, 3024a5dc51eSMarcin Nowakowski .setkey = chksum_setkey, 3034a5dc51eSMarcin Nowakowski .init = chksum_init, 3044a5dc51eSMarcin Nowakowski .update = chksumc_update, 3054a5dc51eSMarcin Nowakowski .final = chksumc_final, 3064a5dc51eSMarcin Nowakowski .finup = chksumc_finup, 3074a5dc51eSMarcin Nowakowski .digest = chksumc_digest, 3084a5dc51eSMarcin Nowakowski .descsize = sizeof(struct chksum_desc_ctx), 3094a5dc51eSMarcin Nowakowski .base = { 3104a5dc51eSMarcin Nowakowski .cra_name = "crc32c", 3114a5dc51eSMarcin Nowakowski .cra_driver_name = "crc32c-mips-hw", 3124a5dc51eSMarcin Nowakowski .cra_priority = 300, 3134a5dc51eSMarcin Nowakowski .cra_flags = CRYPTO_ALG_OPTIONAL_KEY, 3144a5dc51eSMarcin Nowakowski .cra_blocksize = CHKSUM_BLOCK_SIZE, 3154a5dc51eSMarcin Nowakowski .cra_alignmask = 0, 3164a5dc51eSMarcin Nowakowski .cra_ctxsize = sizeof(struct chksum_ctx), 3174a5dc51eSMarcin Nowakowski .cra_module = THIS_MODULE, 3184a5dc51eSMarcin Nowakowski .cra_init = chksum_cra_init, 3194a5dc51eSMarcin Nowakowski } 3204a5dc51eSMarcin Nowakowski }; 3214a5dc51eSMarcin Nowakowski 3224a5dc51eSMarcin Nowakowski static int __init crc32_mod_init(void) 3234a5dc51eSMarcin Nowakowski { 3244a5dc51eSMarcin Nowakowski int err; 3254a5dc51eSMarcin Nowakowski 3264a5dc51eSMarcin Nowakowski err = crypto_register_shash(&crc32_alg); 3274a5dc51eSMarcin Nowakowski 3284a5dc51eSMarcin Nowakowski if (err) 3294a5dc51eSMarcin Nowakowski return err; 3304a5dc51eSMarcin Nowakowski 3314a5dc51eSMarcin Nowakowski err = crypto_register_shash(&crc32c_alg); 3324a5dc51eSMarcin Nowakowski 3334a5dc51eSMarcin Nowakowski if (err) { 3344a5dc51eSMarcin Nowakowski crypto_unregister_shash(&crc32_alg); 3354a5dc51eSMarcin Nowakowski return err; 3364a5dc51eSMarcin Nowakowski } 3374a5dc51eSMarcin Nowakowski 3384a5dc51eSMarcin Nowakowski return 0; 3394a5dc51eSMarcin Nowakowski } 3404a5dc51eSMarcin Nowakowski 3414a5dc51eSMarcin Nowakowski static void __exit crc32_mod_exit(void) 3424a5dc51eSMarcin Nowakowski { 3434a5dc51eSMarcin Nowakowski crypto_unregister_shash(&crc32_alg); 3444a5dc51eSMarcin Nowakowski crypto_unregister_shash(&crc32c_alg); 3454a5dc51eSMarcin Nowakowski } 3464a5dc51eSMarcin Nowakowski 3474a5dc51eSMarcin Nowakowski MODULE_AUTHOR("Marcin Nowakowski <marcin.nowakowski@mips.com"); 3484a5dc51eSMarcin Nowakowski MODULE_DESCRIPTION("CRC32 and CRC32C using optional MIPS instructions"); 3494a5dc51eSMarcin Nowakowski MODULE_LICENSE("GPL v2"); 3504a5dc51eSMarcin Nowakowski 3514a5dc51eSMarcin Nowakowski module_cpu_feature_match(MIPS_CRC32, crc32_mod_init); 3524a5dc51eSMarcin Nowakowski module_exit(crc32_mod_exit); 353