xref: /openbmc/linux/arch/mips/crypto/crc32-mips.c (revision 778aaefb)
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>
17*778aaefbSArnd 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
314a5dc51eSMarcin Nowakowski #define _ASM_MACRO_CRC32(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)))
404a5dc51eSMarcin Nowakowski _ASM_MACRO_CRC32(crc32b,  0, 0);
414a5dc51eSMarcin Nowakowski _ASM_MACRO_CRC32(crc32h,  1, 0);
424a5dc51eSMarcin Nowakowski _ASM_MACRO_CRC32(crc32w,  2, 0);
434a5dc51eSMarcin Nowakowski _ASM_MACRO_CRC32(crc32d,  3, 0);
444a5dc51eSMarcin Nowakowski _ASM_MACRO_CRC32(crc32cb, 0, 1);
454a5dc51eSMarcin Nowakowski _ASM_MACRO_CRC32(crc32ch, 1, 1);
464a5dc51eSMarcin Nowakowski _ASM_MACRO_CRC32(crc32cw, 2, 1);
474a5dc51eSMarcin Nowakowski _ASM_MACRO_CRC32(crc32cd, 3, 1);
484a5dc51eSMarcin Nowakowski #define _ASM_SET_CRC ""
494a5dc51eSMarcin Nowakowski #else /* !TOOLCHAIN_SUPPORTS_CRC */
504a5dc51eSMarcin Nowakowski #define _ASM_SET_CRC ".set\tcrc\n\t"
514a5dc51eSMarcin Nowakowski #endif
524a5dc51eSMarcin Nowakowski 
534a5dc51eSMarcin Nowakowski #define _CRC32(crc, value, size, type)		\
544a5dc51eSMarcin Nowakowski do {						\
554a5dc51eSMarcin Nowakowski 	__asm__ __volatile__(			\
564a5dc51eSMarcin Nowakowski 		".set	push\n\t"		\
574a5dc51eSMarcin Nowakowski 		_ASM_SET_CRC			\
584a5dc51eSMarcin Nowakowski 		#type #size "	%0, %1, %0\n\t"	\
594a5dc51eSMarcin Nowakowski 		".set	pop"			\
604a5dc51eSMarcin Nowakowski 		: "+r" (crc)			\
614a5dc51eSMarcin Nowakowski 		: "r" (value));			\
624a5dc51eSMarcin Nowakowski } while (0)
634a5dc51eSMarcin Nowakowski 
644a5dc51eSMarcin Nowakowski #define CRC32(crc, value, size) \
654a5dc51eSMarcin Nowakowski 	_CRC32(crc, value, size, crc32)
664a5dc51eSMarcin Nowakowski 
674a5dc51eSMarcin Nowakowski #define CRC32C(crc, value, size) \
684a5dc51eSMarcin Nowakowski 	_CRC32(crc, value, size, crc32c)
694a5dc51eSMarcin Nowakowski 
704a5dc51eSMarcin Nowakowski static u32 crc32_mips_le_hw(u32 crc_, const u8 *p, unsigned int len)
714a5dc51eSMarcin Nowakowski {
724a5dc51eSMarcin Nowakowski 	u32 crc = crc_;
734a5dc51eSMarcin Nowakowski 
744a5dc51eSMarcin Nowakowski #ifdef CONFIG_64BIT
754a5dc51eSMarcin Nowakowski 	while (len >= sizeof(u64)) {
764a5dc51eSMarcin Nowakowski 		u64 value = get_unaligned_le64(p);
774a5dc51eSMarcin Nowakowski 
784a5dc51eSMarcin Nowakowski 		CRC32(crc, value, d);
794a5dc51eSMarcin Nowakowski 		p += sizeof(u64);
804a5dc51eSMarcin Nowakowski 		len -= sizeof(u64);
814a5dc51eSMarcin Nowakowski 	}
824a5dc51eSMarcin Nowakowski 
834a5dc51eSMarcin Nowakowski 	if (len & sizeof(u32)) {
844a5dc51eSMarcin Nowakowski #else /* !CONFIG_64BIT */
854a5dc51eSMarcin Nowakowski 	while (len >= sizeof(u32)) {
864a5dc51eSMarcin Nowakowski #endif
874a5dc51eSMarcin Nowakowski 		u32 value = get_unaligned_le32(p);
884a5dc51eSMarcin Nowakowski 
894a5dc51eSMarcin Nowakowski 		CRC32(crc, value, w);
904a5dc51eSMarcin Nowakowski 		p += sizeof(u32);
914a5dc51eSMarcin Nowakowski 		len -= sizeof(u32);
924a5dc51eSMarcin Nowakowski 	}
934a5dc51eSMarcin Nowakowski 
944a5dc51eSMarcin Nowakowski 	if (len & sizeof(u16)) {
954a5dc51eSMarcin Nowakowski 		u16 value = get_unaligned_le16(p);
964a5dc51eSMarcin Nowakowski 
974a5dc51eSMarcin Nowakowski 		CRC32(crc, value, h);
984a5dc51eSMarcin Nowakowski 		p += sizeof(u16);
994a5dc51eSMarcin Nowakowski 	}
1004a5dc51eSMarcin Nowakowski 
1014a5dc51eSMarcin Nowakowski 	if (len & sizeof(u8)) {
1024a5dc51eSMarcin Nowakowski 		u8 value = *p++;
1034a5dc51eSMarcin Nowakowski 
1044a5dc51eSMarcin Nowakowski 		CRC32(crc, value, b);
1054a5dc51eSMarcin Nowakowski 	}
1064a5dc51eSMarcin Nowakowski 
1074a5dc51eSMarcin Nowakowski 	return crc;
1084a5dc51eSMarcin Nowakowski }
1094a5dc51eSMarcin Nowakowski 
1104a5dc51eSMarcin Nowakowski static u32 crc32c_mips_le_hw(u32 crc_, const u8 *p, unsigned int len)
1114a5dc51eSMarcin Nowakowski {
1124a5dc51eSMarcin Nowakowski 	u32 crc = crc_;
1134a5dc51eSMarcin Nowakowski 
1144a5dc51eSMarcin Nowakowski #ifdef CONFIG_64BIT
1154a5dc51eSMarcin Nowakowski 	while (len >= sizeof(u64)) {
1164a5dc51eSMarcin Nowakowski 		u64 value = get_unaligned_le64(p);
1174a5dc51eSMarcin Nowakowski 
1184a5dc51eSMarcin Nowakowski 		CRC32C(crc, value, d);
1194a5dc51eSMarcin Nowakowski 		p += sizeof(u64);
1204a5dc51eSMarcin Nowakowski 		len -= sizeof(u64);
1214a5dc51eSMarcin Nowakowski 	}
1224a5dc51eSMarcin Nowakowski 
1234a5dc51eSMarcin Nowakowski 	if (len & sizeof(u32)) {
1244a5dc51eSMarcin Nowakowski #else /* !CONFIG_64BIT */
1254a5dc51eSMarcin Nowakowski 	while (len >= sizeof(u32)) {
1264a5dc51eSMarcin Nowakowski #endif
1274a5dc51eSMarcin Nowakowski 		u32 value = get_unaligned_le32(p);
1284a5dc51eSMarcin Nowakowski 
1294a5dc51eSMarcin Nowakowski 		CRC32C(crc, value, w);
1304a5dc51eSMarcin Nowakowski 		p += sizeof(u32);
1314a5dc51eSMarcin Nowakowski 		len -= sizeof(u32);
1324a5dc51eSMarcin Nowakowski 	}
1334a5dc51eSMarcin Nowakowski 
1344a5dc51eSMarcin Nowakowski 	if (len & sizeof(u16)) {
1354a5dc51eSMarcin Nowakowski 		u16 value = get_unaligned_le16(p);
1364a5dc51eSMarcin Nowakowski 
1374a5dc51eSMarcin Nowakowski 		CRC32C(crc, value, h);
1384a5dc51eSMarcin Nowakowski 		p += sizeof(u16);
1394a5dc51eSMarcin Nowakowski 	}
1404a5dc51eSMarcin Nowakowski 
1414a5dc51eSMarcin Nowakowski 	if (len & sizeof(u8)) {
1424a5dc51eSMarcin Nowakowski 		u8 value = *p++;
1434a5dc51eSMarcin Nowakowski 
1444a5dc51eSMarcin Nowakowski 		CRC32C(crc, value, b);
1454a5dc51eSMarcin Nowakowski 	}
1464a5dc51eSMarcin Nowakowski 	return crc;
1474a5dc51eSMarcin Nowakowski }
1484a5dc51eSMarcin Nowakowski 
1494a5dc51eSMarcin Nowakowski #define CHKSUM_BLOCK_SIZE	1
1504a5dc51eSMarcin Nowakowski #define CHKSUM_DIGEST_SIZE	4
1514a5dc51eSMarcin Nowakowski 
1524a5dc51eSMarcin Nowakowski struct chksum_ctx {
1534a5dc51eSMarcin Nowakowski 	u32 key;
1544a5dc51eSMarcin Nowakowski };
1554a5dc51eSMarcin Nowakowski 
1564a5dc51eSMarcin Nowakowski struct chksum_desc_ctx {
1574a5dc51eSMarcin Nowakowski 	u32 crc;
1584a5dc51eSMarcin Nowakowski };
1594a5dc51eSMarcin Nowakowski 
1604a5dc51eSMarcin Nowakowski static int chksum_init(struct shash_desc *desc)
1614a5dc51eSMarcin Nowakowski {
1624a5dc51eSMarcin Nowakowski 	struct chksum_ctx *mctx = crypto_shash_ctx(desc->tfm);
1634a5dc51eSMarcin Nowakowski 	struct chksum_desc_ctx *ctx = shash_desc_ctx(desc);
1644a5dc51eSMarcin Nowakowski 
1654a5dc51eSMarcin Nowakowski 	ctx->crc = mctx->key;
1664a5dc51eSMarcin Nowakowski 
1674a5dc51eSMarcin Nowakowski 	return 0;
1684a5dc51eSMarcin Nowakowski }
1694a5dc51eSMarcin Nowakowski 
1704a5dc51eSMarcin Nowakowski /*
1714a5dc51eSMarcin Nowakowski  * Setting the seed allows arbitrary accumulators and flexible XOR policy
1724a5dc51eSMarcin Nowakowski  * If your algorithm starts with ~0, then XOR with ~0 before you set
1734a5dc51eSMarcin Nowakowski  * the seed.
1744a5dc51eSMarcin Nowakowski  */
1754a5dc51eSMarcin Nowakowski static int chksum_setkey(struct crypto_shash *tfm, const u8 *key,
1764a5dc51eSMarcin Nowakowski 			 unsigned int keylen)
1774a5dc51eSMarcin Nowakowski {
1784a5dc51eSMarcin Nowakowski 	struct chksum_ctx *mctx = crypto_shash_ctx(tfm);
1794a5dc51eSMarcin Nowakowski 
180674f368aSEric Biggers 	if (keylen != sizeof(mctx->key))
1814a5dc51eSMarcin Nowakowski 		return -EINVAL;
1824a5dc51eSMarcin Nowakowski 	mctx->key = get_unaligned_le32(key);
1834a5dc51eSMarcin Nowakowski 	return 0;
1844a5dc51eSMarcin Nowakowski }
1854a5dc51eSMarcin Nowakowski 
1864a5dc51eSMarcin Nowakowski static int chksum_update(struct shash_desc *desc, const u8 *data,
1874a5dc51eSMarcin Nowakowski 			 unsigned int length)
1884a5dc51eSMarcin Nowakowski {
1894a5dc51eSMarcin Nowakowski 	struct chksum_desc_ctx *ctx = shash_desc_ctx(desc);
1904a5dc51eSMarcin Nowakowski 
1914a5dc51eSMarcin Nowakowski 	ctx->crc = crc32_mips_le_hw(ctx->crc, data, length);
1924a5dc51eSMarcin Nowakowski 	return 0;
1934a5dc51eSMarcin Nowakowski }
1944a5dc51eSMarcin Nowakowski 
1954a5dc51eSMarcin Nowakowski static int chksumc_update(struct shash_desc *desc, const u8 *data,
1964a5dc51eSMarcin Nowakowski 			 unsigned int length)
1974a5dc51eSMarcin Nowakowski {
1984a5dc51eSMarcin Nowakowski 	struct chksum_desc_ctx *ctx = shash_desc_ctx(desc);
1994a5dc51eSMarcin Nowakowski 
2004a5dc51eSMarcin Nowakowski 	ctx->crc = crc32c_mips_le_hw(ctx->crc, data, length);
2014a5dc51eSMarcin Nowakowski 	return 0;
2024a5dc51eSMarcin Nowakowski }
2034a5dc51eSMarcin Nowakowski 
2044a5dc51eSMarcin Nowakowski static int chksum_final(struct shash_desc *desc, u8 *out)
2054a5dc51eSMarcin Nowakowski {
2064a5dc51eSMarcin Nowakowski 	struct chksum_desc_ctx *ctx = shash_desc_ctx(desc);
2074a5dc51eSMarcin Nowakowski 
2084a5dc51eSMarcin Nowakowski 	put_unaligned_le32(ctx->crc, out);
2094a5dc51eSMarcin Nowakowski 	return 0;
2104a5dc51eSMarcin Nowakowski }
2114a5dc51eSMarcin Nowakowski 
2124a5dc51eSMarcin Nowakowski static int chksumc_final(struct shash_desc *desc, u8 *out)
2134a5dc51eSMarcin Nowakowski {
2144a5dc51eSMarcin Nowakowski 	struct chksum_desc_ctx *ctx = shash_desc_ctx(desc);
2154a5dc51eSMarcin Nowakowski 
2164a5dc51eSMarcin Nowakowski 	put_unaligned_le32(~ctx->crc, out);
2174a5dc51eSMarcin Nowakowski 	return 0;
2184a5dc51eSMarcin Nowakowski }
2194a5dc51eSMarcin Nowakowski 
2204a5dc51eSMarcin Nowakowski static int __chksum_finup(u32 crc, const u8 *data, unsigned int len, u8 *out)
2214a5dc51eSMarcin Nowakowski {
2224a5dc51eSMarcin Nowakowski 	put_unaligned_le32(crc32_mips_le_hw(crc, data, len), out);
2234a5dc51eSMarcin Nowakowski 	return 0;
2244a5dc51eSMarcin Nowakowski }
2254a5dc51eSMarcin Nowakowski 
2264a5dc51eSMarcin Nowakowski static int __chksumc_finup(u32 crc, const u8 *data, unsigned int len, u8 *out)
2274a5dc51eSMarcin Nowakowski {
2284a5dc51eSMarcin Nowakowski 	put_unaligned_le32(~crc32c_mips_le_hw(crc, data, len), out);
2294a5dc51eSMarcin Nowakowski 	return 0;
2304a5dc51eSMarcin Nowakowski }
2314a5dc51eSMarcin Nowakowski 
2324a5dc51eSMarcin Nowakowski static int chksum_finup(struct shash_desc *desc, const u8 *data,
2334a5dc51eSMarcin Nowakowski 			unsigned int len, u8 *out)
2344a5dc51eSMarcin Nowakowski {
2354a5dc51eSMarcin Nowakowski 	struct chksum_desc_ctx *ctx = shash_desc_ctx(desc);
2364a5dc51eSMarcin Nowakowski 
2374a5dc51eSMarcin Nowakowski 	return __chksum_finup(ctx->crc, data, len, out);
2384a5dc51eSMarcin Nowakowski }
2394a5dc51eSMarcin Nowakowski 
2404a5dc51eSMarcin Nowakowski static int chksumc_finup(struct shash_desc *desc, const u8 *data,
2414a5dc51eSMarcin Nowakowski 			unsigned int len, u8 *out)
2424a5dc51eSMarcin Nowakowski {
2434a5dc51eSMarcin Nowakowski 	struct chksum_desc_ctx *ctx = shash_desc_ctx(desc);
2444a5dc51eSMarcin Nowakowski 
2454a5dc51eSMarcin Nowakowski 	return __chksumc_finup(ctx->crc, data, len, out);
2464a5dc51eSMarcin Nowakowski }
2474a5dc51eSMarcin Nowakowski 
2484a5dc51eSMarcin Nowakowski static int chksum_digest(struct shash_desc *desc, const u8 *data,
2494a5dc51eSMarcin Nowakowski 			 unsigned int length, u8 *out)
2504a5dc51eSMarcin Nowakowski {
2514a5dc51eSMarcin Nowakowski 	struct chksum_ctx *mctx = crypto_shash_ctx(desc->tfm);
2524a5dc51eSMarcin Nowakowski 
2534a5dc51eSMarcin Nowakowski 	return __chksum_finup(mctx->key, data, length, out);
2544a5dc51eSMarcin Nowakowski }
2554a5dc51eSMarcin Nowakowski 
2564a5dc51eSMarcin Nowakowski static int chksumc_digest(struct shash_desc *desc, const u8 *data,
2574a5dc51eSMarcin Nowakowski 			 unsigned int length, u8 *out)
2584a5dc51eSMarcin Nowakowski {
2594a5dc51eSMarcin Nowakowski 	struct chksum_ctx *mctx = crypto_shash_ctx(desc->tfm);
2604a5dc51eSMarcin Nowakowski 
2614a5dc51eSMarcin Nowakowski 	return __chksumc_finup(mctx->key, data, length, out);
2624a5dc51eSMarcin Nowakowski }
2634a5dc51eSMarcin Nowakowski 
2644a5dc51eSMarcin Nowakowski static int chksum_cra_init(struct crypto_tfm *tfm)
2654a5dc51eSMarcin Nowakowski {
2664a5dc51eSMarcin Nowakowski 	struct chksum_ctx *mctx = crypto_tfm_ctx(tfm);
2674a5dc51eSMarcin Nowakowski 
2684a5dc51eSMarcin Nowakowski 	mctx->key = ~0;
2694a5dc51eSMarcin Nowakowski 	return 0;
2704a5dc51eSMarcin Nowakowski }
2714a5dc51eSMarcin Nowakowski 
2724a5dc51eSMarcin Nowakowski static struct shash_alg crc32_alg = {
2734a5dc51eSMarcin Nowakowski 	.digestsize		=	CHKSUM_DIGEST_SIZE,
2744a5dc51eSMarcin Nowakowski 	.setkey			=	chksum_setkey,
2754a5dc51eSMarcin Nowakowski 	.init			=	chksum_init,
2764a5dc51eSMarcin Nowakowski 	.update			=	chksum_update,
2774a5dc51eSMarcin Nowakowski 	.final			=	chksum_final,
2784a5dc51eSMarcin Nowakowski 	.finup			=	chksum_finup,
2794a5dc51eSMarcin Nowakowski 	.digest			=	chksum_digest,
2804a5dc51eSMarcin Nowakowski 	.descsize		=	sizeof(struct chksum_desc_ctx),
2814a5dc51eSMarcin Nowakowski 	.base			=	{
2824a5dc51eSMarcin Nowakowski 		.cra_name		=	"crc32",
2834a5dc51eSMarcin Nowakowski 		.cra_driver_name	=	"crc32-mips-hw",
2844a5dc51eSMarcin Nowakowski 		.cra_priority		=	300,
2854a5dc51eSMarcin Nowakowski 		.cra_flags		=	CRYPTO_ALG_OPTIONAL_KEY,
2864a5dc51eSMarcin Nowakowski 		.cra_blocksize		=	CHKSUM_BLOCK_SIZE,
2874a5dc51eSMarcin Nowakowski 		.cra_alignmask		=	0,
2884a5dc51eSMarcin Nowakowski 		.cra_ctxsize		=	sizeof(struct chksum_ctx),
2894a5dc51eSMarcin Nowakowski 		.cra_module		=	THIS_MODULE,
2904a5dc51eSMarcin Nowakowski 		.cra_init		=	chksum_cra_init,
2914a5dc51eSMarcin Nowakowski 	}
2924a5dc51eSMarcin Nowakowski };
2934a5dc51eSMarcin Nowakowski 
2944a5dc51eSMarcin Nowakowski static struct shash_alg crc32c_alg = {
2954a5dc51eSMarcin Nowakowski 	.digestsize		=	CHKSUM_DIGEST_SIZE,
2964a5dc51eSMarcin Nowakowski 	.setkey			=	chksum_setkey,
2974a5dc51eSMarcin Nowakowski 	.init			=	chksum_init,
2984a5dc51eSMarcin Nowakowski 	.update			=	chksumc_update,
2994a5dc51eSMarcin Nowakowski 	.final			=	chksumc_final,
3004a5dc51eSMarcin Nowakowski 	.finup			=	chksumc_finup,
3014a5dc51eSMarcin Nowakowski 	.digest			=	chksumc_digest,
3024a5dc51eSMarcin Nowakowski 	.descsize		=	sizeof(struct chksum_desc_ctx),
3034a5dc51eSMarcin Nowakowski 	.base			=	{
3044a5dc51eSMarcin Nowakowski 		.cra_name		=	"crc32c",
3054a5dc51eSMarcin Nowakowski 		.cra_driver_name	=	"crc32c-mips-hw",
3064a5dc51eSMarcin Nowakowski 		.cra_priority		=	300,
3074a5dc51eSMarcin Nowakowski 		.cra_flags		=	CRYPTO_ALG_OPTIONAL_KEY,
3084a5dc51eSMarcin Nowakowski 		.cra_blocksize		=	CHKSUM_BLOCK_SIZE,
3094a5dc51eSMarcin Nowakowski 		.cra_alignmask		=	0,
3104a5dc51eSMarcin Nowakowski 		.cra_ctxsize		=	sizeof(struct chksum_ctx),
3114a5dc51eSMarcin Nowakowski 		.cra_module		=	THIS_MODULE,
3124a5dc51eSMarcin Nowakowski 		.cra_init		=	chksum_cra_init,
3134a5dc51eSMarcin Nowakowski 	}
3144a5dc51eSMarcin Nowakowski };
3154a5dc51eSMarcin Nowakowski 
3164a5dc51eSMarcin Nowakowski static int __init crc32_mod_init(void)
3174a5dc51eSMarcin Nowakowski {
3184a5dc51eSMarcin Nowakowski 	int err;
3194a5dc51eSMarcin Nowakowski 
3204a5dc51eSMarcin Nowakowski 	err = crypto_register_shash(&crc32_alg);
3214a5dc51eSMarcin Nowakowski 
3224a5dc51eSMarcin Nowakowski 	if (err)
3234a5dc51eSMarcin Nowakowski 		return err;
3244a5dc51eSMarcin Nowakowski 
3254a5dc51eSMarcin Nowakowski 	err = crypto_register_shash(&crc32c_alg);
3264a5dc51eSMarcin Nowakowski 
3274a5dc51eSMarcin Nowakowski 	if (err) {
3284a5dc51eSMarcin Nowakowski 		crypto_unregister_shash(&crc32_alg);
3294a5dc51eSMarcin Nowakowski 		return err;
3304a5dc51eSMarcin Nowakowski 	}
3314a5dc51eSMarcin Nowakowski 
3324a5dc51eSMarcin Nowakowski 	return 0;
3334a5dc51eSMarcin Nowakowski }
3344a5dc51eSMarcin Nowakowski 
3354a5dc51eSMarcin Nowakowski static void __exit crc32_mod_exit(void)
3364a5dc51eSMarcin Nowakowski {
3374a5dc51eSMarcin Nowakowski 	crypto_unregister_shash(&crc32_alg);
3384a5dc51eSMarcin Nowakowski 	crypto_unregister_shash(&crc32c_alg);
3394a5dc51eSMarcin Nowakowski }
3404a5dc51eSMarcin Nowakowski 
3414a5dc51eSMarcin Nowakowski MODULE_AUTHOR("Marcin Nowakowski <marcin.nowakowski@mips.com");
3424a5dc51eSMarcin Nowakowski MODULE_DESCRIPTION("CRC32 and CRC32C using optional MIPS instructions");
3434a5dc51eSMarcin Nowakowski MODULE_LICENSE("GPL v2");
3444a5dc51eSMarcin Nowakowski 
3454a5dc51eSMarcin Nowakowski module_cpu_feature_match(MIPS_CRC32, crc32_mod_init);
3464a5dc51eSMarcin Nowakowski module_exit(crc32_mod_exit);
347