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
crc32_mips_le_hw(u32 crc_,const u8 * p,unsigned int len)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_ctxsize = sizeof(struct chksum_ctx),
2944a5dc51eSMarcin Nowakowski .cra_module = THIS_MODULE,
2954a5dc51eSMarcin Nowakowski .cra_init = chksum_cra_init,
2964a5dc51eSMarcin Nowakowski }
2974a5dc51eSMarcin Nowakowski };
2984a5dc51eSMarcin Nowakowski
2994a5dc51eSMarcin Nowakowski static struct shash_alg crc32c_alg = {
3004a5dc51eSMarcin Nowakowski .digestsize = CHKSUM_DIGEST_SIZE,
3014a5dc51eSMarcin Nowakowski .setkey = chksum_setkey,
3024a5dc51eSMarcin Nowakowski .init = chksum_init,
3034a5dc51eSMarcin Nowakowski .update = chksumc_update,
3044a5dc51eSMarcin Nowakowski .final = chksumc_final,
3054a5dc51eSMarcin Nowakowski .finup = chksumc_finup,
3064a5dc51eSMarcin Nowakowski .digest = chksumc_digest,
3074a5dc51eSMarcin Nowakowski .descsize = sizeof(struct chksum_desc_ctx),
3084a5dc51eSMarcin Nowakowski .base = {
3094a5dc51eSMarcin Nowakowski .cra_name = "crc32c",
3104a5dc51eSMarcin Nowakowski .cra_driver_name = "crc32c-mips-hw",
3114a5dc51eSMarcin Nowakowski .cra_priority = 300,
3124a5dc51eSMarcin Nowakowski .cra_flags = CRYPTO_ALG_OPTIONAL_KEY,
3134a5dc51eSMarcin Nowakowski .cra_blocksize = CHKSUM_BLOCK_SIZE,
3144a5dc51eSMarcin Nowakowski .cra_ctxsize = sizeof(struct chksum_ctx),
3154a5dc51eSMarcin Nowakowski .cra_module = THIS_MODULE,
3164a5dc51eSMarcin Nowakowski .cra_init = chksum_cra_init,
3174a5dc51eSMarcin Nowakowski }
3184a5dc51eSMarcin Nowakowski };
3194a5dc51eSMarcin Nowakowski
3204a5dc51eSMarcin Nowakowski static int __init crc32_mod_init(void)
3214a5dc51eSMarcin Nowakowski {
3224a5dc51eSMarcin Nowakowski int err;
3234a5dc51eSMarcin Nowakowski
3244a5dc51eSMarcin Nowakowski err = crypto_register_shash(&crc32_alg);
3254a5dc51eSMarcin Nowakowski
3264a5dc51eSMarcin Nowakowski if (err)
3274a5dc51eSMarcin Nowakowski return err;
3284a5dc51eSMarcin Nowakowski
3294a5dc51eSMarcin Nowakowski err = crypto_register_shash(&crc32c_alg);
3304a5dc51eSMarcin Nowakowski
3314a5dc51eSMarcin Nowakowski if (err) {
3324a5dc51eSMarcin Nowakowski crypto_unregister_shash(&crc32_alg);
3334a5dc51eSMarcin Nowakowski return err;
3344a5dc51eSMarcin Nowakowski }
3354a5dc51eSMarcin Nowakowski
3364a5dc51eSMarcin Nowakowski return 0;
3374a5dc51eSMarcin Nowakowski }
3384a5dc51eSMarcin Nowakowski
3394a5dc51eSMarcin Nowakowski static void __exit crc32_mod_exit(void)
3404a5dc51eSMarcin Nowakowski {
3414a5dc51eSMarcin Nowakowski crypto_unregister_shash(&crc32_alg);
3424a5dc51eSMarcin Nowakowski crypto_unregister_shash(&crc32c_alg);
3434a5dc51eSMarcin Nowakowski }
3444a5dc51eSMarcin Nowakowski
3454a5dc51eSMarcin Nowakowski MODULE_AUTHOR("Marcin Nowakowski <marcin.nowakowski@mips.com");
3464a5dc51eSMarcin Nowakowski MODULE_DESCRIPTION("CRC32 and CRC32C using optional MIPS instructions");
3474a5dc51eSMarcin Nowakowski MODULE_LICENSE("GPL v2");
3484a5dc51eSMarcin Nowakowski
3494a5dc51eSMarcin Nowakowski module_cpu_feature_match(MIPS_CRC32, crc32_mod_init);
3504a5dc51eSMarcin Nowakowski module_exit(crc32_mod_exit);
351