18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * crc32-mips.c - CRC32 and CRC32C using optional MIPSr6 instructions
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Module based on arm64/crypto/crc32-arm.c
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * Copyright (C) 2014 Linaro Ltd <yazen.ghannam@linaro.org>
88c2ecf20Sopenharmony_ci * Copyright (C) 2018 MIPS Tech, LLC
98c2ecf20Sopenharmony_ci */
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci#include <linux/unaligned/access_ok.h>
128c2ecf20Sopenharmony_ci#include <linux/cpufeature.h>
138c2ecf20Sopenharmony_ci#include <linux/init.h>
148c2ecf20Sopenharmony_ci#include <linux/kernel.h>
158c2ecf20Sopenharmony_ci#include <linux/module.h>
168c2ecf20Sopenharmony_ci#include <linux/string.h>
178c2ecf20Sopenharmony_ci#include <asm/mipsregs.h>
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci#include <crypto/internal/hash.h>
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_cienum crc_op_size {
228c2ecf20Sopenharmony_ci	b, h, w, d,
238c2ecf20Sopenharmony_ci};
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_cienum crc_type {
268c2ecf20Sopenharmony_ci	crc32,
278c2ecf20Sopenharmony_ci	crc32c,
288c2ecf20Sopenharmony_ci};
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci#ifndef TOOLCHAIN_SUPPORTS_CRC
318c2ecf20Sopenharmony_ci#define _ASM_MACRO_CRC32(OP, SZ, TYPE)					  \
328c2ecf20Sopenharmony_ci_ASM_MACRO_3R(OP, rt, rs, rt2,						  \
338c2ecf20Sopenharmony_ci	".ifnc	\\rt, \\rt2\n\t"					  \
348c2ecf20Sopenharmony_ci	".error	\"invalid operands \\\"" #OP " \\rt,\\rs,\\rt2\\\"\"\n\t" \
358c2ecf20Sopenharmony_ci	".endif\n\t"							  \
368c2ecf20Sopenharmony_ci	_ASM_INSN_IF_MIPS(0x7c00000f | (__rt << 16) | (__rs << 21) |	  \
378c2ecf20Sopenharmony_ci			  ((SZ) <<  6) | ((TYPE) << 8))			  \
388c2ecf20Sopenharmony_ci	_ASM_INSN32_IF_MM(0x00000030 | (__rs << 16) | (__rt << 21) |	  \
398c2ecf20Sopenharmony_ci			  ((SZ) << 14) | ((TYPE) << 3)))
408c2ecf20Sopenharmony_ci_ASM_MACRO_CRC32(crc32b,  0, 0);
418c2ecf20Sopenharmony_ci_ASM_MACRO_CRC32(crc32h,  1, 0);
428c2ecf20Sopenharmony_ci_ASM_MACRO_CRC32(crc32w,  2, 0);
438c2ecf20Sopenharmony_ci_ASM_MACRO_CRC32(crc32d,  3, 0);
448c2ecf20Sopenharmony_ci_ASM_MACRO_CRC32(crc32cb, 0, 1);
458c2ecf20Sopenharmony_ci_ASM_MACRO_CRC32(crc32ch, 1, 1);
468c2ecf20Sopenharmony_ci_ASM_MACRO_CRC32(crc32cw, 2, 1);
478c2ecf20Sopenharmony_ci_ASM_MACRO_CRC32(crc32cd, 3, 1);
488c2ecf20Sopenharmony_ci#define _ASM_SET_CRC ""
498c2ecf20Sopenharmony_ci#else /* !TOOLCHAIN_SUPPORTS_CRC */
508c2ecf20Sopenharmony_ci#define _ASM_SET_CRC ".set\tcrc\n\t"
518c2ecf20Sopenharmony_ci#endif
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci#define _CRC32(crc, value, size, type)		\
548c2ecf20Sopenharmony_cido {						\
558c2ecf20Sopenharmony_ci	__asm__ __volatile__(			\
568c2ecf20Sopenharmony_ci		".set	push\n\t"		\
578c2ecf20Sopenharmony_ci		_ASM_SET_CRC			\
588c2ecf20Sopenharmony_ci		#type #size "	%0, %1, %0\n\t"	\
598c2ecf20Sopenharmony_ci		".set	pop"			\
608c2ecf20Sopenharmony_ci		: "+r" (crc)			\
618c2ecf20Sopenharmony_ci		: "r" (value));			\
628c2ecf20Sopenharmony_ci} while (0)
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ci#define CRC32(crc, value, size) \
658c2ecf20Sopenharmony_ci	_CRC32(crc, value, size, crc32)
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ci#define CRC32C(crc, value, size) \
688c2ecf20Sopenharmony_ci	_CRC32(crc, value, size, crc32c)
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_cistatic u32 crc32_mips_le_hw(u32 crc_, const u8 *p, unsigned int len)
718c2ecf20Sopenharmony_ci{
728c2ecf20Sopenharmony_ci	u32 crc = crc_;
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci#ifdef CONFIG_64BIT
758c2ecf20Sopenharmony_ci	while (len >= sizeof(u64)) {
768c2ecf20Sopenharmony_ci		u64 value = get_unaligned_le64(p);
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci		CRC32(crc, value, d);
798c2ecf20Sopenharmony_ci		p += sizeof(u64);
808c2ecf20Sopenharmony_ci		len -= sizeof(u64);
818c2ecf20Sopenharmony_ci	}
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci	if (len & sizeof(u32)) {
848c2ecf20Sopenharmony_ci#else /* !CONFIG_64BIT */
858c2ecf20Sopenharmony_ci	while (len >= sizeof(u32)) {
868c2ecf20Sopenharmony_ci#endif
878c2ecf20Sopenharmony_ci		u32 value = get_unaligned_le32(p);
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci		CRC32(crc, value, w);
908c2ecf20Sopenharmony_ci		p += sizeof(u32);
918c2ecf20Sopenharmony_ci		len -= sizeof(u32);
928c2ecf20Sopenharmony_ci	}
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci	if (len & sizeof(u16)) {
958c2ecf20Sopenharmony_ci		u16 value = get_unaligned_le16(p);
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ci		CRC32(crc, value, h);
988c2ecf20Sopenharmony_ci		p += sizeof(u16);
998c2ecf20Sopenharmony_ci	}
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci	if (len & sizeof(u8)) {
1028c2ecf20Sopenharmony_ci		u8 value = *p++;
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_ci		CRC32(crc, value, b);
1058c2ecf20Sopenharmony_ci	}
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ci	return crc;
1088c2ecf20Sopenharmony_ci}
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_cistatic u32 crc32c_mips_le_hw(u32 crc_, const u8 *p, unsigned int len)
1118c2ecf20Sopenharmony_ci{
1128c2ecf20Sopenharmony_ci	u32 crc = crc_;
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ci#ifdef CONFIG_64BIT
1158c2ecf20Sopenharmony_ci	while (len >= sizeof(u64)) {
1168c2ecf20Sopenharmony_ci		u64 value = get_unaligned_le64(p);
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci		CRC32C(crc, value, d);
1198c2ecf20Sopenharmony_ci		p += sizeof(u64);
1208c2ecf20Sopenharmony_ci		len -= sizeof(u64);
1218c2ecf20Sopenharmony_ci	}
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ci	if (len & sizeof(u32)) {
1248c2ecf20Sopenharmony_ci#else /* !CONFIG_64BIT */
1258c2ecf20Sopenharmony_ci	while (len >= sizeof(u32)) {
1268c2ecf20Sopenharmony_ci#endif
1278c2ecf20Sopenharmony_ci		u32 value = get_unaligned_le32(p);
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_ci		CRC32C(crc, value, w);
1308c2ecf20Sopenharmony_ci		p += sizeof(u32);
1318c2ecf20Sopenharmony_ci		len -= sizeof(u32);
1328c2ecf20Sopenharmony_ci	}
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_ci	if (len & sizeof(u16)) {
1358c2ecf20Sopenharmony_ci		u16 value = get_unaligned_le16(p);
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_ci		CRC32C(crc, value, h);
1388c2ecf20Sopenharmony_ci		p += sizeof(u16);
1398c2ecf20Sopenharmony_ci	}
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_ci	if (len & sizeof(u8)) {
1428c2ecf20Sopenharmony_ci		u8 value = *p++;
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ci		CRC32C(crc, value, b);
1458c2ecf20Sopenharmony_ci	}
1468c2ecf20Sopenharmony_ci	return crc;
1478c2ecf20Sopenharmony_ci}
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_ci#define CHKSUM_BLOCK_SIZE	1
1508c2ecf20Sopenharmony_ci#define CHKSUM_DIGEST_SIZE	4
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_cistruct chksum_ctx {
1538c2ecf20Sopenharmony_ci	u32 key;
1548c2ecf20Sopenharmony_ci};
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_cistruct chksum_desc_ctx {
1578c2ecf20Sopenharmony_ci	u32 crc;
1588c2ecf20Sopenharmony_ci};
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_cistatic int chksum_init(struct shash_desc *desc)
1618c2ecf20Sopenharmony_ci{
1628c2ecf20Sopenharmony_ci	struct chksum_ctx *mctx = crypto_shash_ctx(desc->tfm);
1638c2ecf20Sopenharmony_ci	struct chksum_desc_ctx *ctx = shash_desc_ctx(desc);
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_ci	ctx->crc = mctx->key;
1668c2ecf20Sopenharmony_ci
1678c2ecf20Sopenharmony_ci	return 0;
1688c2ecf20Sopenharmony_ci}
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_ci/*
1718c2ecf20Sopenharmony_ci * Setting the seed allows arbitrary accumulators and flexible XOR policy
1728c2ecf20Sopenharmony_ci * If your algorithm starts with ~0, then XOR with ~0 before you set
1738c2ecf20Sopenharmony_ci * the seed.
1748c2ecf20Sopenharmony_ci */
1758c2ecf20Sopenharmony_cistatic int chksum_setkey(struct crypto_shash *tfm, const u8 *key,
1768c2ecf20Sopenharmony_ci			 unsigned int keylen)
1778c2ecf20Sopenharmony_ci{
1788c2ecf20Sopenharmony_ci	struct chksum_ctx *mctx = crypto_shash_ctx(tfm);
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_ci	if (keylen != sizeof(mctx->key))
1818c2ecf20Sopenharmony_ci		return -EINVAL;
1828c2ecf20Sopenharmony_ci	mctx->key = get_unaligned_le32(key);
1838c2ecf20Sopenharmony_ci	return 0;
1848c2ecf20Sopenharmony_ci}
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_cistatic int chksum_update(struct shash_desc *desc, const u8 *data,
1878c2ecf20Sopenharmony_ci			 unsigned int length)
1888c2ecf20Sopenharmony_ci{
1898c2ecf20Sopenharmony_ci	struct chksum_desc_ctx *ctx = shash_desc_ctx(desc);
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_ci	ctx->crc = crc32_mips_le_hw(ctx->crc, data, length);
1928c2ecf20Sopenharmony_ci	return 0;
1938c2ecf20Sopenharmony_ci}
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_cistatic int chksumc_update(struct shash_desc *desc, const u8 *data,
1968c2ecf20Sopenharmony_ci			 unsigned int length)
1978c2ecf20Sopenharmony_ci{
1988c2ecf20Sopenharmony_ci	struct chksum_desc_ctx *ctx = shash_desc_ctx(desc);
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_ci	ctx->crc = crc32c_mips_le_hw(ctx->crc, data, length);
2018c2ecf20Sopenharmony_ci	return 0;
2028c2ecf20Sopenharmony_ci}
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_cistatic int chksum_final(struct shash_desc *desc, u8 *out)
2058c2ecf20Sopenharmony_ci{
2068c2ecf20Sopenharmony_ci	struct chksum_desc_ctx *ctx = shash_desc_ctx(desc);
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_ci	put_unaligned_le32(ctx->crc, out);
2098c2ecf20Sopenharmony_ci	return 0;
2108c2ecf20Sopenharmony_ci}
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_cistatic int chksumc_final(struct shash_desc *desc, u8 *out)
2138c2ecf20Sopenharmony_ci{
2148c2ecf20Sopenharmony_ci	struct chksum_desc_ctx *ctx = shash_desc_ctx(desc);
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_ci	put_unaligned_le32(~ctx->crc, out);
2178c2ecf20Sopenharmony_ci	return 0;
2188c2ecf20Sopenharmony_ci}
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_cistatic int __chksum_finup(u32 crc, const u8 *data, unsigned int len, u8 *out)
2218c2ecf20Sopenharmony_ci{
2228c2ecf20Sopenharmony_ci	put_unaligned_le32(crc32_mips_le_hw(crc, data, len), out);
2238c2ecf20Sopenharmony_ci	return 0;
2248c2ecf20Sopenharmony_ci}
2258c2ecf20Sopenharmony_ci
2268c2ecf20Sopenharmony_cistatic int __chksumc_finup(u32 crc, const u8 *data, unsigned int len, u8 *out)
2278c2ecf20Sopenharmony_ci{
2288c2ecf20Sopenharmony_ci	put_unaligned_le32(~crc32c_mips_le_hw(crc, data, len), out);
2298c2ecf20Sopenharmony_ci	return 0;
2308c2ecf20Sopenharmony_ci}
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_cistatic int chksum_finup(struct shash_desc *desc, const u8 *data,
2338c2ecf20Sopenharmony_ci			unsigned int len, u8 *out)
2348c2ecf20Sopenharmony_ci{
2358c2ecf20Sopenharmony_ci	struct chksum_desc_ctx *ctx = shash_desc_ctx(desc);
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ci	return __chksum_finup(ctx->crc, data, len, out);
2388c2ecf20Sopenharmony_ci}
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_cistatic int chksumc_finup(struct shash_desc *desc, const u8 *data,
2418c2ecf20Sopenharmony_ci			unsigned int len, u8 *out)
2428c2ecf20Sopenharmony_ci{
2438c2ecf20Sopenharmony_ci	struct chksum_desc_ctx *ctx = shash_desc_ctx(desc);
2448c2ecf20Sopenharmony_ci
2458c2ecf20Sopenharmony_ci	return __chksumc_finup(ctx->crc, data, len, out);
2468c2ecf20Sopenharmony_ci}
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_cistatic int chksum_digest(struct shash_desc *desc, const u8 *data,
2498c2ecf20Sopenharmony_ci			 unsigned int length, u8 *out)
2508c2ecf20Sopenharmony_ci{
2518c2ecf20Sopenharmony_ci	struct chksum_ctx *mctx = crypto_shash_ctx(desc->tfm);
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_ci	return __chksum_finup(mctx->key, data, length, out);
2548c2ecf20Sopenharmony_ci}
2558c2ecf20Sopenharmony_ci
2568c2ecf20Sopenharmony_cistatic int chksumc_digest(struct shash_desc *desc, const u8 *data,
2578c2ecf20Sopenharmony_ci			 unsigned int length, u8 *out)
2588c2ecf20Sopenharmony_ci{
2598c2ecf20Sopenharmony_ci	struct chksum_ctx *mctx = crypto_shash_ctx(desc->tfm);
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_ci	return __chksumc_finup(mctx->key, data, length, out);
2628c2ecf20Sopenharmony_ci}
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_cistatic int chksum_cra_init(struct crypto_tfm *tfm)
2658c2ecf20Sopenharmony_ci{
2668c2ecf20Sopenharmony_ci	struct chksum_ctx *mctx = crypto_tfm_ctx(tfm);
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_ci	mctx->key = ~0;
2698c2ecf20Sopenharmony_ci	return 0;
2708c2ecf20Sopenharmony_ci}
2718c2ecf20Sopenharmony_ci
2728c2ecf20Sopenharmony_cistatic struct shash_alg crc32_alg = {
2738c2ecf20Sopenharmony_ci	.digestsize		=	CHKSUM_DIGEST_SIZE,
2748c2ecf20Sopenharmony_ci	.setkey			=	chksum_setkey,
2758c2ecf20Sopenharmony_ci	.init			=	chksum_init,
2768c2ecf20Sopenharmony_ci	.update			=	chksum_update,
2778c2ecf20Sopenharmony_ci	.final			=	chksum_final,
2788c2ecf20Sopenharmony_ci	.finup			=	chksum_finup,
2798c2ecf20Sopenharmony_ci	.digest			=	chksum_digest,
2808c2ecf20Sopenharmony_ci	.descsize		=	sizeof(struct chksum_desc_ctx),
2818c2ecf20Sopenharmony_ci	.base			=	{
2828c2ecf20Sopenharmony_ci		.cra_name		=	"crc32",
2838c2ecf20Sopenharmony_ci		.cra_driver_name	=	"crc32-mips-hw",
2848c2ecf20Sopenharmony_ci		.cra_priority		=	300,
2858c2ecf20Sopenharmony_ci		.cra_flags		=	CRYPTO_ALG_OPTIONAL_KEY,
2868c2ecf20Sopenharmony_ci		.cra_blocksize		=	CHKSUM_BLOCK_SIZE,
2878c2ecf20Sopenharmony_ci		.cra_alignmask		=	0,
2888c2ecf20Sopenharmony_ci		.cra_ctxsize		=	sizeof(struct chksum_ctx),
2898c2ecf20Sopenharmony_ci		.cra_module		=	THIS_MODULE,
2908c2ecf20Sopenharmony_ci		.cra_init		=	chksum_cra_init,
2918c2ecf20Sopenharmony_ci	}
2928c2ecf20Sopenharmony_ci};
2938c2ecf20Sopenharmony_ci
2948c2ecf20Sopenharmony_cistatic struct shash_alg crc32c_alg = {
2958c2ecf20Sopenharmony_ci	.digestsize		=	CHKSUM_DIGEST_SIZE,
2968c2ecf20Sopenharmony_ci	.setkey			=	chksum_setkey,
2978c2ecf20Sopenharmony_ci	.init			=	chksum_init,
2988c2ecf20Sopenharmony_ci	.update			=	chksumc_update,
2998c2ecf20Sopenharmony_ci	.final			=	chksumc_final,
3008c2ecf20Sopenharmony_ci	.finup			=	chksumc_finup,
3018c2ecf20Sopenharmony_ci	.digest			=	chksumc_digest,
3028c2ecf20Sopenharmony_ci	.descsize		=	sizeof(struct chksum_desc_ctx),
3038c2ecf20Sopenharmony_ci	.base			=	{
3048c2ecf20Sopenharmony_ci		.cra_name		=	"crc32c",
3058c2ecf20Sopenharmony_ci		.cra_driver_name	=	"crc32c-mips-hw",
3068c2ecf20Sopenharmony_ci		.cra_priority		=	300,
3078c2ecf20Sopenharmony_ci		.cra_flags		=	CRYPTO_ALG_OPTIONAL_KEY,
3088c2ecf20Sopenharmony_ci		.cra_blocksize		=	CHKSUM_BLOCK_SIZE,
3098c2ecf20Sopenharmony_ci		.cra_alignmask		=	0,
3108c2ecf20Sopenharmony_ci		.cra_ctxsize		=	sizeof(struct chksum_ctx),
3118c2ecf20Sopenharmony_ci		.cra_module		=	THIS_MODULE,
3128c2ecf20Sopenharmony_ci		.cra_init		=	chksum_cra_init,
3138c2ecf20Sopenharmony_ci	}
3148c2ecf20Sopenharmony_ci};
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_cistatic int __init crc32_mod_init(void)
3178c2ecf20Sopenharmony_ci{
3188c2ecf20Sopenharmony_ci	int err;
3198c2ecf20Sopenharmony_ci
3208c2ecf20Sopenharmony_ci	err = crypto_register_shash(&crc32_alg);
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_ci	if (err)
3238c2ecf20Sopenharmony_ci		return err;
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_ci	err = crypto_register_shash(&crc32c_alg);
3268c2ecf20Sopenharmony_ci
3278c2ecf20Sopenharmony_ci	if (err) {
3288c2ecf20Sopenharmony_ci		crypto_unregister_shash(&crc32_alg);
3298c2ecf20Sopenharmony_ci		return err;
3308c2ecf20Sopenharmony_ci	}
3318c2ecf20Sopenharmony_ci
3328c2ecf20Sopenharmony_ci	return 0;
3338c2ecf20Sopenharmony_ci}
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_cistatic void __exit crc32_mod_exit(void)
3368c2ecf20Sopenharmony_ci{
3378c2ecf20Sopenharmony_ci	crypto_unregister_shash(&crc32_alg);
3388c2ecf20Sopenharmony_ci	crypto_unregister_shash(&crc32c_alg);
3398c2ecf20Sopenharmony_ci}
3408c2ecf20Sopenharmony_ci
3418c2ecf20Sopenharmony_ciMODULE_AUTHOR("Marcin Nowakowski <marcin.nowakowski@mips.com");
3428c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("CRC32 and CRC32C using optional MIPS instructions");
3438c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2");
3448c2ecf20Sopenharmony_ci
3458c2ecf20Sopenharmony_cimodule_cpu_feature_match(MIPS_CRC32, crc32_mod_init);
3468c2ecf20Sopenharmony_cimodule_exit(crc32_mod_exit);
347