xref: /linux/arch/mips/crypto/crc32-mips.c (revision 9cf52f7b)
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