18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Accelerated GHASH implementation with Intel PCLMULQDQ-NI
48c2ecf20Sopenharmony_ci * instructions. This file contains glue code.
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci * Copyright (c) 2009 Intel Corp.
78c2ecf20Sopenharmony_ci *   Author: Huang Ying <ying.huang@intel.com>
88c2ecf20Sopenharmony_ci */
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#include <linux/err.h>
118c2ecf20Sopenharmony_ci#include <linux/module.h>
128c2ecf20Sopenharmony_ci#include <linux/init.h>
138c2ecf20Sopenharmony_ci#include <linux/kernel.h>
148c2ecf20Sopenharmony_ci#include <linux/crypto.h>
158c2ecf20Sopenharmony_ci#include <crypto/algapi.h>
168c2ecf20Sopenharmony_ci#include <crypto/cryptd.h>
178c2ecf20Sopenharmony_ci#include <crypto/gf128mul.h>
188c2ecf20Sopenharmony_ci#include <crypto/internal/hash.h>
198c2ecf20Sopenharmony_ci#include <crypto/internal/simd.h>
208c2ecf20Sopenharmony_ci#include <asm/cpu_device_id.h>
218c2ecf20Sopenharmony_ci#include <asm/simd.h>
228c2ecf20Sopenharmony_ci#include <asm/unaligned.h>
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci#define GHASH_BLOCK_SIZE	16
258c2ecf20Sopenharmony_ci#define GHASH_DIGEST_SIZE	16
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_civoid clmul_ghash_mul(char *dst, const u128 *shash);
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_civoid clmul_ghash_update(char *dst, const char *src, unsigned int srclen,
308c2ecf20Sopenharmony_ci			const u128 *shash);
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_cistruct ghash_async_ctx {
338c2ecf20Sopenharmony_ci	struct cryptd_ahash *cryptd_tfm;
348c2ecf20Sopenharmony_ci};
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_cistruct ghash_ctx {
378c2ecf20Sopenharmony_ci	u128 shash;
388c2ecf20Sopenharmony_ci};
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_cistruct ghash_desc_ctx {
418c2ecf20Sopenharmony_ci	u8 buffer[GHASH_BLOCK_SIZE];
428c2ecf20Sopenharmony_ci	u32 bytes;
438c2ecf20Sopenharmony_ci};
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_cistatic int ghash_init(struct shash_desc *desc)
468c2ecf20Sopenharmony_ci{
478c2ecf20Sopenharmony_ci	struct ghash_desc_ctx *dctx = shash_desc_ctx(desc);
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ci	memset(dctx, 0, sizeof(*dctx));
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ci	return 0;
528c2ecf20Sopenharmony_ci}
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_cistatic int ghash_setkey(struct crypto_shash *tfm,
558c2ecf20Sopenharmony_ci			const u8 *key, unsigned int keylen)
568c2ecf20Sopenharmony_ci{
578c2ecf20Sopenharmony_ci	struct ghash_ctx *ctx = crypto_shash_ctx(tfm);
588c2ecf20Sopenharmony_ci	u64 a, b;
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci	if (keylen != GHASH_BLOCK_SIZE)
618c2ecf20Sopenharmony_ci		return -EINVAL;
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci	/* perform multiplication by 'x' in GF(2^128) */
648c2ecf20Sopenharmony_ci	a = get_unaligned_be64(key);
658c2ecf20Sopenharmony_ci	b = get_unaligned_be64(key + 8);
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ci	ctx->shash.a = (b << 1) | (a >> 63);
688c2ecf20Sopenharmony_ci	ctx->shash.b = (a << 1) | (b >> 63);
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ci	if (a >> 63)
718c2ecf20Sopenharmony_ci		ctx->shash.b ^= ((u64)0xc2) << 56;
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci	return 0;
748c2ecf20Sopenharmony_ci}
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_cistatic int ghash_update(struct shash_desc *desc,
778c2ecf20Sopenharmony_ci			 const u8 *src, unsigned int srclen)
788c2ecf20Sopenharmony_ci{
798c2ecf20Sopenharmony_ci	struct ghash_desc_ctx *dctx = shash_desc_ctx(desc);
808c2ecf20Sopenharmony_ci	struct ghash_ctx *ctx = crypto_shash_ctx(desc->tfm);
818c2ecf20Sopenharmony_ci	u8 *dst = dctx->buffer;
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci	kernel_fpu_begin();
848c2ecf20Sopenharmony_ci	if (dctx->bytes) {
858c2ecf20Sopenharmony_ci		int n = min(srclen, dctx->bytes);
868c2ecf20Sopenharmony_ci		u8 *pos = dst + (GHASH_BLOCK_SIZE - dctx->bytes);
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci		dctx->bytes -= n;
898c2ecf20Sopenharmony_ci		srclen -= n;
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci		while (n--)
928c2ecf20Sopenharmony_ci			*pos++ ^= *src++;
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci		if (!dctx->bytes)
958c2ecf20Sopenharmony_ci			clmul_ghash_mul(dst, &ctx->shash);
968c2ecf20Sopenharmony_ci	}
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci	clmul_ghash_update(dst, src, srclen, &ctx->shash);
998c2ecf20Sopenharmony_ci	kernel_fpu_end();
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci	if (srclen & 0xf) {
1028c2ecf20Sopenharmony_ci		src += srclen - (srclen & 0xf);
1038c2ecf20Sopenharmony_ci		srclen &= 0xf;
1048c2ecf20Sopenharmony_ci		dctx->bytes = GHASH_BLOCK_SIZE - srclen;
1058c2ecf20Sopenharmony_ci		while (srclen--)
1068c2ecf20Sopenharmony_ci			*dst++ ^= *src++;
1078c2ecf20Sopenharmony_ci	}
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci	return 0;
1108c2ecf20Sopenharmony_ci}
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_cistatic void ghash_flush(struct ghash_ctx *ctx, struct ghash_desc_ctx *dctx)
1138c2ecf20Sopenharmony_ci{
1148c2ecf20Sopenharmony_ci	u8 *dst = dctx->buffer;
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ci	if (dctx->bytes) {
1178c2ecf20Sopenharmony_ci		u8 *tmp = dst + (GHASH_BLOCK_SIZE - dctx->bytes);
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_ci		while (dctx->bytes--)
1208c2ecf20Sopenharmony_ci			*tmp++ ^= 0;
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_ci		kernel_fpu_begin();
1238c2ecf20Sopenharmony_ci		clmul_ghash_mul(dst, &ctx->shash);
1248c2ecf20Sopenharmony_ci		kernel_fpu_end();
1258c2ecf20Sopenharmony_ci	}
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci	dctx->bytes = 0;
1288c2ecf20Sopenharmony_ci}
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_cistatic int ghash_final(struct shash_desc *desc, u8 *dst)
1318c2ecf20Sopenharmony_ci{
1328c2ecf20Sopenharmony_ci	struct ghash_desc_ctx *dctx = shash_desc_ctx(desc);
1338c2ecf20Sopenharmony_ci	struct ghash_ctx *ctx = crypto_shash_ctx(desc->tfm);
1348c2ecf20Sopenharmony_ci	u8 *buf = dctx->buffer;
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_ci	ghash_flush(ctx, dctx);
1378c2ecf20Sopenharmony_ci	memcpy(dst, buf, GHASH_BLOCK_SIZE);
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci	return 0;
1408c2ecf20Sopenharmony_ci}
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_cistatic struct shash_alg ghash_alg = {
1438c2ecf20Sopenharmony_ci	.digestsize	= GHASH_DIGEST_SIZE,
1448c2ecf20Sopenharmony_ci	.init		= ghash_init,
1458c2ecf20Sopenharmony_ci	.update		= ghash_update,
1468c2ecf20Sopenharmony_ci	.final		= ghash_final,
1478c2ecf20Sopenharmony_ci	.setkey		= ghash_setkey,
1488c2ecf20Sopenharmony_ci	.descsize	= sizeof(struct ghash_desc_ctx),
1498c2ecf20Sopenharmony_ci	.base		= {
1508c2ecf20Sopenharmony_ci		.cra_name		= "__ghash",
1518c2ecf20Sopenharmony_ci		.cra_driver_name	= "__ghash-pclmulqdqni",
1528c2ecf20Sopenharmony_ci		.cra_priority		= 0,
1538c2ecf20Sopenharmony_ci		.cra_flags		= CRYPTO_ALG_INTERNAL,
1548c2ecf20Sopenharmony_ci		.cra_blocksize		= GHASH_BLOCK_SIZE,
1558c2ecf20Sopenharmony_ci		.cra_ctxsize		= sizeof(struct ghash_ctx),
1568c2ecf20Sopenharmony_ci		.cra_module		= THIS_MODULE,
1578c2ecf20Sopenharmony_ci	},
1588c2ecf20Sopenharmony_ci};
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_cistatic int ghash_async_init(struct ahash_request *req)
1618c2ecf20Sopenharmony_ci{
1628c2ecf20Sopenharmony_ci	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
1638c2ecf20Sopenharmony_ci	struct ghash_async_ctx *ctx = crypto_ahash_ctx(tfm);
1648c2ecf20Sopenharmony_ci	struct ahash_request *cryptd_req = ahash_request_ctx(req);
1658c2ecf20Sopenharmony_ci	struct cryptd_ahash *cryptd_tfm = ctx->cryptd_tfm;
1668c2ecf20Sopenharmony_ci	struct shash_desc *desc = cryptd_shash_desc(cryptd_req);
1678c2ecf20Sopenharmony_ci	struct crypto_shash *child = cryptd_ahash_child(cryptd_tfm);
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_ci	desc->tfm = child;
1708c2ecf20Sopenharmony_ci	return crypto_shash_init(desc);
1718c2ecf20Sopenharmony_ci}
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_cistatic int ghash_async_update(struct ahash_request *req)
1748c2ecf20Sopenharmony_ci{
1758c2ecf20Sopenharmony_ci	struct ahash_request *cryptd_req = ahash_request_ctx(req);
1768c2ecf20Sopenharmony_ci	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
1778c2ecf20Sopenharmony_ci	struct ghash_async_ctx *ctx = crypto_ahash_ctx(tfm);
1788c2ecf20Sopenharmony_ci	struct cryptd_ahash *cryptd_tfm = ctx->cryptd_tfm;
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_ci	if (!crypto_simd_usable() ||
1818c2ecf20Sopenharmony_ci	    (in_atomic() && cryptd_ahash_queued(cryptd_tfm))) {
1828c2ecf20Sopenharmony_ci		memcpy(cryptd_req, req, sizeof(*req));
1838c2ecf20Sopenharmony_ci		ahash_request_set_tfm(cryptd_req, &cryptd_tfm->base);
1848c2ecf20Sopenharmony_ci		return crypto_ahash_update(cryptd_req);
1858c2ecf20Sopenharmony_ci	} else {
1868c2ecf20Sopenharmony_ci		struct shash_desc *desc = cryptd_shash_desc(cryptd_req);
1878c2ecf20Sopenharmony_ci		return shash_ahash_update(req, desc);
1888c2ecf20Sopenharmony_ci	}
1898c2ecf20Sopenharmony_ci}
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_cistatic int ghash_async_final(struct ahash_request *req)
1928c2ecf20Sopenharmony_ci{
1938c2ecf20Sopenharmony_ci	struct ahash_request *cryptd_req = ahash_request_ctx(req);
1948c2ecf20Sopenharmony_ci	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
1958c2ecf20Sopenharmony_ci	struct ghash_async_ctx *ctx = crypto_ahash_ctx(tfm);
1968c2ecf20Sopenharmony_ci	struct cryptd_ahash *cryptd_tfm = ctx->cryptd_tfm;
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_ci	if (!crypto_simd_usable() ||
1998c2ecf20Sopenharmony_ci	    (in_atomic() && cryptd_ahash_queued(cryptd_tfm))) {
2008c2ecf20Sopenharmony_ci		memcpy(cryptd_req, req, sizeof(*req));
2018c2ecf20Sopenharmony_ci		ahash_request_set_tfm(cryptd_req, &cryptd_tfm->base);
2028c2ecf20Sopenharmony_ci		return crypto_ahash_final(cryptd_req);
2038c2ecf20Sopenharmony_ci	} else {
2048c2ecf20Sopenharmony_ci		struct shash_desc *desc = cryptd_shash_desc(cryptd_req);
2058c2ecf20Sopenharmony_ci		return crypto_shash_final(desc, req->result);
2068c2ecf20Sopenharmony_ci	}
2078c2ecf20Sopenharmony_ci}
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_cistatic int ghash_async_import(struct ahash_request *req, const void *in)
2108c2ecf20Sopenharmony_ci{
2118c2ecf20Sopenharmony_ci	struct ahash_request *cryptd_req = ahash_request_ctx(req);
2128c2ecf20Sopenharmony_ci	struct shash_desc *desc = cryptd_shash_desc(cryptd_req);
2138c2ecf20Sopenharmony_ci	struct ghash_desc_ctx *dctx = shash_desc_ctx(desc);
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_ci	ghash_async_init(req);
2168c2ecf20Sopenharmony_ci	memcpy(dctx, in, sizeof(*dctx));
2178c2ecf20Sopenharmony_ci	return 0;
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_ci}
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_cistatic int ghash_async_export(struct ahash_request *req, void *out)
2228c2ecf20Sopenharmony_ci{
2238c2ecf20Sopenharmony_ci	struct ahash_request *cryptd_req = ahash_request_ctx(req);
2248c2ecf20Sopenharmony_ci	struct shash_desc *desc = cryptd_shash_desc(cryptd_req);
2258c2ecf20Sopenharmony_ci	struct ghash_desc_ctx *dctx = shash_desc_ctx(desc);
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_ci	memcpy(out, dctx, sizeof(*dctx));
2288c2ecf20Sopenharmony_ci	return 0;
2298c2ecf20Sopenharmony_ci
2308c2ecf20Sopenharmony_ci}
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_cistatic int ghash_async_digest(struct ahash_request *req)
2338c2ecf20Sopenharmony_ci{
2348c2ecf20Sopenharmony_ci	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
2358c2ecf20Sopenharmony_ci	struct ghash_async_ctx *ctx = crypto_ahash_ctx(tfm);
2368c2ecf20Sopenharmony_ci	struct ahash_request *cryptd_req = ahash_request_ctx(req);
2378c2ecf20Sopenharmony_ci	struct cryptd_ahash *cryptd_tfm = ctx->cryptd_tfm;
2388c2ecf20Sopenharmony_ci
2398c2ecf20Sopenharmony_ci	if (!crypto_simd_usable() ||
2408c2ecf20Sopenharmony_ci	    (in_atomic() && cryptd_ahash_queued(cryptd_tfm))) {
2418c2ecf20Sopenharmony_ci		memcpy(cryptd_req, req, sizeof(*req));
2428c2ecf20Sopenharmony_ci		ahash_request_set_tfm(cryptd_req, &cryptd_tfm->base);
2438c2ecf20Sopenharmony_ci		return crypto_ahash_digest(cryptd_req);
2448c2ecf20Sopenharmony_ci	} else {
2458c2ecf20Sopenharmony_ci		struct shash_desc *desc = cryptd_shash_desc(cryptd_req);
2468c2ecf20Sopenharmony_ci		struct crypto_shash *child = cryptd_ahash_child(cryptd_tfm);
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_ci		desc->tfm = child;
2498c2ecf20Sopenharmony_ci		return shash_ahash_digest(req, desc);
2508c2ecf20Sopenharmony_ci	}
2518c2ecf20Sopenharmony_ci}
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_cistatic int ghash_async_setkey(struct crypto_ahash *tfm, const u8 *key,
2548c2ecf20Sopenharmony_ci			      unsigned int keylen)
2558c2ecf20Sopenharmony_ci{
2568c2ecf20Sopenharmony_ci	struct ghash_async_ctx *ctx = crypto_ahash_ctx(tfm);
2578c2ecf20Sopenharmony_ci	struct crypto_ahash *child = &ctx->cryptd_tfm->base;
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_ci	crypto_ahash_clear_flags(child, CRYPTO_TFM_REQ_MASK);
2608c2ecf20Sopenharmony_ci	crypto_ahash_set_flags(child, crypto_ahash_get_flags(tfm)
2618c2ecf20Sopenharmony_ci			       & CRYPTO_TFM_REQ_MASK);
2628c2ecf20Sopenharmony_ci	return crypto_ahash_setkey(child, key, keylen);
2638c2ecf20Sopenharmony_ci}
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_cistatic int ghash_async_init_tfm(struct crypto_tfm *tfm)
2668c2ecf20Sopenharmony_ci{
2678c2ecf20Sopenharmony_ci	struct cryptd_ahash *cryptd_tfm;
2688c2ecf20Sopenharmony_ci	struct ghash_async_ctx *ctx = crypto_tfm_ctx(tfm);
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_ci	cryptd_tfm = cryptd_alloc_ahash("__ghash-pclmulqdqni",
2718c2ecf20Sopenharmony_ci					CRYPTO_ALG_INTERNAL,
2728c2ecf20Sopenharmony_ci					CRYPTO_ALG_INTERNAL);
2738c2ecf20Sopenharmony_ci	if (IS_ERR(cryptd_tfm))
2748c2ecf20Sopenharmony_ci		return PTR_ERR(cryptd_tfm);
2758c2ecf20Sopenharmony_ci	ctx->cryptd_tfm = cryptd_tfm;
2768c2ecf20Sopenharmony_ci	crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm),
2778c2ecf20Sopenharmony_ci				 sizeof(struct ahash_request) +
2788c2ecf20Sopenharmony_ci				 crypto_ahash_reqsize(&cryptd_tfm->base));
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_ci	return 0;
2818c2ecf20Sopenharmony_ci}
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_cistatic void ghash_async_exit_tfm(struct crypto_tfm *tfm)
2848c2ecf20Sopenharmony_ci{
2858c2ecf20Sopenharmony_ci	struct ghash_async_ctx *ctx = crypto_tfm_ctx(tfm);
2868c2ecf20Sopenharmony_ci
2878c2ecf20Sopenharmony_ci	cryptd_free_ahash(ctx->cryptd_tfm);
2888c2ecf20Sopenharmony_ci}
2898c2ecf20Sopenharmony_ci
2908c2ecf20Sopenharmony_cistatic struct ahash_alg ghash_async_alg = {
2918c2ecf20Sopenharmony_ci	.init		= ghash_async_init,
2928c2ecf20Sopenharmony_ci	.update		= ghash_async_update,
2938c2ecf20Sopenharmony_ci	.final		= ghash_async_final,
2948c2ecf20Sopenharmony_ci	.setkey		= ghash_async_setkey,
2958c2ecf20Sopenharmony_ci	.digest		= ghash_async_digest,
2968c2ecf20Sopenharmony_ci	.export		= ghash_async_export,
2978c2ecf20Sopenharmony_ci	.import		= ghash_async_import,
2988c2ecf20Sopenharmony_ci	.halg = {
2998c2ecf20Sopenharmony_ci		.digestsize	= GHASH_DIGEST_SIZE,
3008c2ecf20Sopenharmony_ci		.statesize = sizeof(struct ghash_desc_ctx),
3018c2ecf20Sopenharmony_ci		.base = {
3028c2ecf20Sopenharmony_ci			.cra_name		= "ghash",
3038c2ecf20Sopenharmony_ci			.cra_driver_name	= "ghash-clmulni",
3048c2ecf20Sopenharmony_ci			.cra_priority		= 400,
3058c2ecf20Sopenharmony_ci			.cra_ctxsize		= sizeof(struct ghash_async_ctx),
3068c2ecf20Sopenharmony_ci			.cra_flags		= CRYPTO_ALG_ASYNC,
3078c2ecf20Sopenharmony_ci			.cra_blocksize		= GHASH_BLOCK_SIZE,
3088c2ecf20Sopenharmony_ci			.cra_module		= THIS_MODULE,
3098c2ecf20Sopenharmony_ci			.cra_init		= ghash_async_init_tfm,
3108c2ecf20Sopenharmony_ci			.cra_exit		= ghash_async_exit_tfm,
3118c2ecf20Sopenharmony_ci		},
3128c2ecf20Sopenharmony_ci	},
3138c2ecf20Sopenharmony_ci};
3148c2ecf20Sopenharmony_ci
3158c2ecf20Sopenharmony_cistatic const struct x86_cpu_id pcmul_cpu_id[] = {
3168c2ecf20Sopenharmony_ci	X86_MATCH_FEATURE(X86_FEATURE_PCLMULQDQ, NULL), /* Pickle-Mickle-Duck */
3178c2ecf20Sopenharmony_ci	{}
3188c2ecf20Sopenharmony_ci};
3198c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(x86cpu, pcmul_cpu_id);
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_cistatic int __init ghash_pclmulqdqni_mod_init(void)
3228c2ecf20Sopenharmony_ci{
3238c2ecf20Sopenharmony_ci	int err;
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_ci	if (!x86_match_cpu(pcmul_cpu_id))
3268c2ecf20Sopenharmony_ci		return -ENODEV;
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_ci	err = crypto_register_shash(&ghash_alg);
3298c2ecf20Sopenharmony_ci	if (err)
3308c2ecf20Sopenharmony_ci		goto err_out;
3318c2ecf20Sopenharmony_ci	err = crypto_register_ahash(&ghash_async_alg);
3328c2ecf20Sopenharmony_ci	if (err)
3338c2ecf20Sopenharmony_ci		goto err_shash;
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_ci	return 0;
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_cierr_shash:
3388c2ecf20Sopenharmony_ci	crypto_unregister_shash(&ghash_alg);
3398c2ecf20Sopenharmony_cierr_out:
3408c2ecf20Sopenharmony_ci	return err;
3418c2ecf20Sopenharmony_ci}
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_cistatic void __exit ghash_pclmulqdqni_mod_exit(void)
3448c2ecf20Sopenharmony_ci{
3458c2ecf20Sopenharmony_ci	crypto_unregister_ahash(&ghash_async_alg);
3468c2ecf20Sopenharmony_ci	crypto_unregister_shash(&ghash_alg);
3478c2ecf20Sopenharmony_ci}
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_cimodule_init(ghash_pclmulqdqni_mod_init);
3508c2ecf20Sopenharmony_cimodule_exit(ghash_pclmulqdqni_mod_exit);
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
3538c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("GHASH hash function, accelerated by PCLMULQDQ-NI");
3548c2ecf20Sopenharmony_ciMODULE_ALIAS_CRYPTO("ghash");
355