162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Accelerated GHASH implementation with Intel PCLMULQDQ-NI
462306a36Sopenharmony_ci * instructions. This file contains glue code.
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * Copyright (c) 2009 Intel Corp.
762306a36Sopenharmony_ci *   Author: Huang Ying <ying.huang@intel.com>
862306a36Sopenharmony_ci */
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <linux/err.h>
1162306a36Sopenharmony_ci#include <linux/module.h>
1262306a36Sopenharmony_ci#include <linux/init.h>
1362306a36Sopenharmony_ci#include <linux/kernel.h>
1462306a36Sopenharmony_ci#include <linux/crypto.h>
1562306a36Sopenharmony_ci#include <crypto/algapi.h>
1662306a36Sopenharmony_ci#include <crypto/cryptd.h>
1762306a36Sopenharmony_ci#include <crypto/gf128mul.h>
1862306a36Sopenharmony_ci#include <crypto/internal/hash.h>
1962306a36Sopenharmony_ci#include <crypto/internal/simd.h>
2062306a36Sopenharmony_ci#include <asm/cpu_device_id.h>
2162306a36Sopenharmony_ci#include <asm/simd.h>
2262306a36Sopenharmony_ci#include <asm/unaligned.h>
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci#define GHASH_BLOCK_SIZE	16
2562306a36Sopenharmony_ci#define GHASH_DIGEST_SIZE	16
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_civoid clmul_ghash_mul(char *dst, const le128 *shash);
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_civoid clmul_ghash_update(char *dst, const char *src, unsigned int srclen,
3062306a36Sopenharmony_ci			const le128 *shash);
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_cistruct ghash_async_ctx {
3362306a36Sopenharmony_ci	struct cryptd_ahash *cryptd_tfm;
3462306a36Sopenharmony_ci};
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_cistruct ghash_ctx {
3762306a36Sopenharmony_ci	le128 shash;
3862306a36Sopenharmony_ci};
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_cistruct ghash_desc_ctx {
4162306a36Sopenharmony_ci	u8 buffer[GHASH_BLOCK_SIZE];
4262306a36Sopenharmony_ci	u32 bytes;
4362306a36Sopenharmony_ci};
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_cistatic int ghash_init(struct shash_desc *desc)
4662306a36Sopenharmony_ci{
4762306a36Sopenharmony_ci	struct ghash_desc_ctx *dctx = shash_desc_ctx(desc);
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci	memset(dctx, 0, sizeof(*dctx));
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci	return 0;
5262306a36Sopenharmony_ci}
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_cistatic int ghash_setkey(struct crypto_shash *tfm,
5562306a36Sopenharmony_ci			const u8 *key, unsigned int keylen)
5662306a36Sopenharmony_ci{
5762306a36Sopenharmony_ci	struct ghash_ctx *ctx = crypto_shash_ctx(tfm);
5862306a36Sopenharmony_ci	u64 a, b;
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci	if (keylen != GHASH_BLOCK_SIZE)
6162306a36Sopenharmony_ci		return -EINVAL;
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci	/*
6462306a36Sopenharmony_ci	 * GHASH maps bits to polynomial coefficients backwards, which makes it
6562306a36Sopenharmony_ci	 * hard to implement.  But it can be shown that the GHASH multiplication
6662306a36Sopenharmony_ci	 *
6762306a36Sopenharmony_ci	 *	D * K (mod x^128 + x^7 + x^2 + x + 1)
6862306a36Sopenharmony_ci	 *
6962306a36Sopenharmony_ci	 * (where D is a data block and K is the key) is equivalent to:
7062306a36Sopenharmony_ci	 *
7162306a36Sopenharmony_ci	 *	bitreflect(D) * bitreflect(K) * x^(-127)
7262306a36Sopenharmony_ci	 *		(mod x^128 + x^127 + x^126 + x^121 + 1)
7362306a36Sopenharmony_ci	 *
7462306a36Sopenharmony_ci	 * So, the code below precomputes:
7562306a36Sopenharmony_ci	 *
7662306a36Sopenharmony_ci	 *	bitreflect(K) * x^(-127) (mod x^128 + x^127 + x^126 + x^121 + 1)
7762306a36Sopenharmony_ci	 *
7862306a36Sopenharmony_ci	 * ... but in Montgomery form (so that Montgomery multiplication can be
7962306a36Sopenharmony_ci	 * used), i.e. with an extra x^128 factor, which means actually:
8062306a36Sopenharmony_ci	 *
8162306a36Sopenharmony_ci	 *	bitreflect(K) * x (mod x^128 + x^127 + x^126 + x^121 + 1)
8262306a36Sopenharmony_ci	 *
8362306a36Sopenharmony_ci	 * The within-a-byte part of bitreflect() cancels out GHASH's built-in
8462306a36Sopenharmony_ci	 * reflection, and thus bitreflect() is actually a byteswap.
8562306a36Sopenharmony_ci	 */
8662306a36Sopenharmony_ci	a = get_unaligned_be64(key);
8762306a36Sopenharmony_ci	b = get_unaligned_be64(key + 8);
8862306a36Sopenharmony_ci	ctx->shash.a = cpu_to_le64((a << 1) | (b >> 63));
8962306a36Sopenharmony_ci	ctx->shash.b = cpu_to_le64((b << 1) | (a >> 63));
9062306a36Sopenharmony_ci	if (a >> 63)
9162306a36Sopenharmony_ci		ctx->shash.a ^= cpu_to_le64((u64)0xc2 << 56);
9262306a36Sopenharmony_ci	return 0;
9362306a36Sopenharmony_ci}
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_cistatic int ghash_update(struct shash_desc *desc,
9662306a36Sopenharmony_ci			 const u8 *src, unsigned int srclen)
9762306a36Sopenharmony_ci{
9862306a36Sopenharmony_ci	struct ghash_desc_ctx *dctx = shash_desc_ctx(desc);
9962306a36Sopenharmony_ci	struct ghash_ctx *ctx = crypto_shash_ctx(desc->tfm);
10062306a36Sopenharmony_ci	u8 *dst = dctx->buffer;
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ci	kernel_fpu_begin();
10362306a36Sopenharmony_ci	if (dctx->bytes) {
10462306a36Sopenharmony_ci		int n = min(srclen, dctx->bytes);
10562306a36Sopenharmony_ci		u8 *pos = dst + (GHASH_BLOCK_SIZE - dctx->bytes);
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci		dctx->bytes -= n;
10862306a36Sopenharmony_ci		srclen -= n;
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci		while (n--)
11162306a36Sopenharmony_ci			*pos++ ^= *src++;
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci		if (!dctx->bytes)
11462306a36Sopenharmony_ci			clmul_ghash_mul(dst, &ctx->shash);
11562306a36Sopenharmony_ci	}
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci	clmul_ghash_update(dst, src, srclen, &ctx->shash);
11862306a36Sopenharmony_ci	kernel_fpu_end();
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci	if (srclen & 0xf) {
12162306a36Sopenharmony_ci		src += srclen - (srclen & 0xf);
12262306a36Sopenharmony_ci		srclen &= 0xf;
12362306a36Sopenharmony_ci		dctx->bytes = GHASH_BLOCK_SIZE - srclen;
12462306a36Sopenharmony_ci		while (srclen--)
12562306a36Sopenharmony_ci			*dst++ ^= *src++;
12662306a36Sopenharmony_ci	}
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci	return 0;
12962306a36Sopenharmony_ci}
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_cistatic void ghash_flush(struct ghash_ctx *ctx, struct ghash_desc_ctx *dctx)
13262306a36Sopenharmony_ci{
13362306a36Sopenharmony_ci	u8 *dst = dctx->buffer;
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci	if (dctx->bytes) {
13662306a36Sopenharmony_ci		u8 *tmp = dst + (GHASH_BLOCK_SIZE - dctx->bytes);
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci		while (dctx->bytes--)
13962306a36Sopenharmony_ci			*tmp++ ^= 0;
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci		kernel_fpu_begin();
14262306a36Sopenharmony_ci		clmul_ghash_mul(dst, &ctx->shash);
14362306a36Sopenharmony_ci		kernel_fpu_end();
14462306a36Sopenharmony_ci	}
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci	dctx->bytes = 0;
14762306a36Sopenharmony_ci}
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_cistatic int ghash_final(struct shash_desc *desc, u8 *dst)
15062306a36Sopenharmony_ci{
15162306a36Sopenharmony_ci	struct ghash_desc_ctx *dctx = shash_desc_ctx(desc);
15262306a36Sopenharmony_ci	struct ghash_ctx *ctx = crypto_shash_ctx(desc->tfm);
15362306a36Sopenharmony_ci	u8 *buf = dctx->buffer;
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci	ghash_flush(ctx, dctx);
15662306a36Sopenharmony_ci	memcpy(dst, buf, GHASH_BLOCK_SIZE);
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci	return 0;
15962306a36Sopenharmony_ci}
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_cistatic struct shash_alg ghash_alg = {
16262306a36Sopenharmony_ci	.digestsize	= GHASH_DIGEST_SIZE,
16362306a36Sopenharmony_ci	.init		= ghash_init,
16462306a36Sopenharmony_ci	.update		= ghash_update,
16562306a36Sopenharmony_ci	.final		= ghash_final,
16662306a36Sopenharmony_ci	.setkey		= ghash_setkey,
16762306a36Sopenharmony_ci	.descsize	= sizeof(struct ghash_desc_ctx),
16862306a36Sopenharmony_ci	.base		= {
16962306a36Sopenharmony_ci		.cra_name		= "__ghash",
17062306a36Sopenharmony_ci		.cra_driver_name	= "__ghash-pclmulqdqni",
17162306a36Sopenharmony_ci		.cra_priority		= 0,
17262306a36Sopenharmony_ci		.cra_flags		= CRYPTO_ALG_INTERNAL,
17362306a36Sopenharmony_ci		.cra_blocksize		= GHASH_BLOCK_SIZE,
17462306a36Sopenharmony_ci		.cra_ctxsize		= sizeof(struct ghash_ctx),
17562306a36Sopenharmony_ci		.cra_module		= THIS_MODULE,
17662306a36Sopenharmony_ci	},
17762306a36Sopenharmony_ci};
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_cistatic int ghash_async_init(struct ahash_request *req)
18062306a36Sopenharmony_ci{
18162306a36Sopenharmony_ci	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
18262306a36Sopenharmony_ci	struct ghash_async_ctx *ctx = crypto_ahash_ctx(tfm);
18362306a36Sopenharmony_ci	struct ahash_request *cryptd_req = ahash_request_ctx(req);
18462306a36Sopenharmony_ci	struct cryptd_ahash *cryptd_tfm = ctx->cryptd_tfm;
18562306a36Sopenharmony_ci	struct shash_desc *desc = cryptd_shash_desc(cryptd_req);
18662306a36Sopenharmony_ci	struct crypto_shash *child = cryptd_ahash_child(cryptd_tfm);
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci	desc->tfm = child;
18962306a36Sopenharmony_ci	return crypto_shash_init(desc);
19062306a36Sopenharmony_ci}
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_cistatic int ghash_async_update(struct ahash_request *req)
19362306a36Sopenharmony_ci{
19462306a36Sopenharmony_ci	struct ahash_request *cryptd_req = ahash_request_ctx(req);
19562306a36Sopenharmony_ci	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
19662306a36Sopenharmony_ci	struct ghash_async_ctx *ctx = crypto_ahash_ctx(tfm);
19762306a36Sopenharmony_ci	struct cryptd_ahash *cryptd_tfm = ctx->cryptd_tfm;
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci	if (!crypto_simd_usable() ||
20062306a36Sopenharmony_ci	    (in_atomic() && cryptd_ahash_queued(cryptd_tfm))) {
20162306a36Sopenharmony_ci		memcpy(cryptd_req, req, sizeof(*req));
20262306a36Sopenharmony_ci		ahash_request_set_tfm(cryptd_req, &cryptd_tfm->base);
20362306a36Sopenharmony_ci		return crypto_ahash_update(cryptd_req);
20462306a36Sopenharmony_ci	} else {
20562306a36Sopenharmony_ci		struct shash_desc *desc = cryptd_shash_desc(cryptd_req);
20662306a36Sopenharmony_ci		return shash_ahash_update(req, desc);
20762306a36Sopenharmony_ci	}
20862306a36Sopenharmony_ci}
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_cistatic int ghash_async_final(struct ahash_request *req)
21162306a36Sopenharmony_ci{
21262306a36Sopenharmony_ci	struct ahash_request *cryptd_req = ahash_request_ctx(req);
21362306a36Sopenharmony_ci	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
21462306a36Sopenharmony_ci	struct ghash_async_ctx *ctx = crypto_ahash_ctx(tfm);
21562306a36Sopenharmony_ci	struct cryptd_ahash *cryptd_tfm = ctx->cryptd_tfm;
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci	if (!crypto_simd_usable() ||
21862306a36Sopenharmony_ci	    (in_atomic() && cryptd_ahash_queued(cryptd_tfm))) {
21962306a36Sopenharmony_ci		memcpy(cryptd_req, req, sizeof(*req));
22062306a36Sopenharmony_ci		ahash_request_set_tfm(cryptd_req, &cryptd_tfm->base);
22162306a36Sopenharmony_ci		return crypto_ahash_final(cryptd_req);
22262306a36Sopenharmony_ci	} else {
22362306a36Sopenharmony_ci		struct shash_desc *desc = cryptd_shash_desc(cryptd_req);
22462306a36Sopenharmony_ci		return crypto_shash_final(desc, req->result);
22562306a36Sopenharmony_ci	}
22662306a36Sopenharmony_ci}
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_cistatic int ghash_async_import(struct ahash_request *req, const void *in)
22962306a36Sopenharmony_ci{
23062306a36Sopenharmony_ci	struct ahash_request *cryptd_req = ahash_request_ctx(req);
23162306a36Sopenharmony_ci	struct shash_desc *desc = cryptd_shash_desc(cryptd_req);
23262306a36Sopenharmony_ci	struct ghash_desc_ctx *dctx = shash_desc_ctx(desc);
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ci	ghash_async_init(req);
23562306a36Sopenharmony_ci	memcpy(dctx, in, sizeof(*dctx));
23662306a36Sopenharmony_ci	return 0;
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ci}
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_cistatic int ghash_async_export(struct ahash_request *req, void *out)
24162306a36Sopenharmony_ci{
24262306a36Sopenharmony_ci	struct ahash_request *cryptd_req = ahash_request_ctx(req);
24362306a36Sopenharmony_ci	struct shash_desc *desc = cryptd_shash_desc(cryptd_req);
24462306a36Sopenharmony_ci	struct ghash_desc_ctx *dctx = shash_desc_ctx(desc);
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_ci	memcpy(out, dctx, sizeof(*dctx));
24762306a36Sopenharmony_ci	return 0;
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci}
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_cistatic int ghash_async_digest(struct ahash_request *req)
25262306a36Sopenharmony_ci{
25362306a36Sopenharmony_ci	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
25462306a36Sopenharmony_ci	struct ghash_async_ctx *ctx = crypto_ahash_ctx(tfm);
25562306a36Sopenharmony_ci	struct ahash_request *cryptd_req = ahash_request_ctx(req);
25662306a36Sopenharmony_ci	struct cryptd_ahash *cryptd_tfm = ctx->cryptd_tfm;
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_ci	if (!crypto_simd_usable() ||
25962306a36Sopenharmony_ci	    (in_atomic() && cryptd_ahash_queued(cryptd_tfm))) {
26062306a36Sopenharmony_ci		memcpy(cryptd_req, req, sizeof(*req));
26162306a36Sopenharmony_ci		ahash_request_set_tfm(cryptd_req, &cryptd_tfm->base);
26262306a36Sopenharmony_ci		return crypto_ahash_digest(cryptd_req);
26362306a36Sopenharmony_ci	} else {
26462306a36Sopenharmony_ci		struct shash_desc *desc = cryptd_shash_desc(cryptd_req);
26562306a36Sopenharmony_ci		struct crypto_shash *child = cryptd_ahash_child(cryptd_tfm);
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci		desc->tfm = child;
26862306a36Sopenharmony_ci		return shash_ahash_digest(req, desc);
26962306a36Sopenharmony_ci	}
27062306a36Sopenharmony_ci}
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_cistatic int ghash_async_setkey(struct crypto_ahash *tfm, const u8 *key,
27362306a36Sopenharmony_ci			      unsigned int keylen)
27462306a36Sopenharmony_ci{
27562306a36Sopenharmony_ci	struct ghash_async_ctx *ctx = crypto_ahash_ctx(tfm);
27662306a36Sopenharmony_ci	struct crypto_ahash *child = &ctx->cryptd_tfm->base;
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci	crypto_ahash_clear_flags(child, CRYPTO_TFM_REQ_MASK);
27962306a36Sopenharmony_ci	crypto_ahash_set_flags(child, crypto_ahash_get_flags(tfm)
28062306a36Sopenharmony_ci			       & CRYPTO_TFM_REQ_MASK);
28162306a36Sopenharmony_ci	return crypto_ahash_setkey(child, key, keylen);
28262306a36Sopenharmony_ci}
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_cistatic int ghash_async_init_tfm(struct crypto_tfm *tfm)
28562306a36Sopenharmony_ci{
28662306a36Sopenharmony_ci	struct cryptd_ahash *cryptd_tfm;
28762306a36Sopenharmony_ci	struct ghash_async_ctx *ctx = crypto_tfm_ctx(tfm);
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci	cryptd_tfm = cryptd_alloc_ahash("__ghash-pclmulqdqni",
29062306a36Sopenharmony_ci					CRYPTO_ALG_INTERNAL,
29162306a36Sopenharmony_ci					CRYPTO_ALG_INTERNAL);
29262306a36Sopenharmony_ci	if (IS_ERR(cryptd_tfm))
29362306a36Sopenharmony_ci		return PTR_ERR(cryptd_tfm);
29462306a36Sopenharmony_ci	ctx->cryptd_tfm = cryptd_tfm;
29562306a36Sopenharmony_ci	crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm),
29662306a36Sopenharmony_ci				 sizeof(struct ahash_request) +
29762306a36Sopenharmony_ci				 crypto_ahash_reqsize(&cryptd_tfm->base));
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ci	return 0;
30062306a36Sopenharmony_ci}
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_cistatic void ghash_async_exit_tfm(struct crypto_tfm *tfm)
30362306a36Sopenharmony_ci{
30462306a36Sopenharmony_ci	struct ghash_async_ctx *ctx = crypto_tfm_ctx(tfm);
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_ci	cryptd_free_ahash(ctx->cryptd_tfm);
30762306a36Sopenharmony_ci}
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_cistatic struct ahash_alg ghash_async_alg = {
31062306a36Sopenharmony_ci	.init		= ghash_async_init,
31162306a36Sopenharmony_ci	.update		= ghash_async_update,
31262306a36Sopenharmony_ci	.final		= ghash_async_final,
31362306a36Sopenharmony_ci	.setkey		= ghash_async_setkey,
31462306a36Sopenharmony_ci	.digest		= ghash_async_digest,
31562306a36Sopenharmony_ci	.export		= ghash_async_export,
31662306a36Sopenharmony_ci	.import		= ghash_async_import,
31762306a36Sopenharmony_ci	.halg = {
31862306a36Sopenharmony_ci		.digestsize	= GHASH_DIGEST_SIZE,
31962306a36Sopenharmony_ci		.statesize = sizeof(struct ghash_desc_ctx),
32062306a36Sopenharmony_ci		.base = {
32162306a36Sopenharmony_ci			.cra_name		= "ghash",
32262306a36Sopenharmony_ci			.cra_driver_name	= "ghash-clmulni",
32362306a36Sopenharmony_ci			.cra_priority		= 400,
32462306a36Sopenharmony_ci			.cra_ctxsize		= sizeof(struct ghash_async_ctx),
32562306a36Sopenharmony_ci			.cra_flags		= CRYPTO_ALG_ASYNC,
32662306a36Sopenharmony_ci			.cra_blocksize		= GHASH_BLOCK_SIZE,
32762306a36Sopenharmony_ci			.cra_module		= THIS_MODULE,
32862306a36Sopenharmony_ci			.cra_init		= ghash_async_init_tfm,
32962306a36Sopenharmony_ci			.cra_exit		= ghash_async_exit_tfm,
33062306a36Sopenharmony_ci		},
33162306a36Sopenharmony_ci	},
33262306a36Sopenharmony_ci};
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_cistatic const struct x86_cpu_id pcmul_cpu_id[] = {
33562306a36Sopenharmony_ci	X86_MATCH_FEATURE(X86_FEATURE_PCLMULQDQ, NULL), /* Pickle-Mickle-Duck */
33662306a36Sopenharmony_ci	{}
33762306a36Sopenharmony_ci};
33862306a36Sopenharmony_ciMODULE_DEVICE_TABLE(x86cpu, pcmul_cpu_id);
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_cistatic int __init ghash_pclmulqdqni_mod_init(void)
34162306a36Sopenharmony_ci{
34262306a36Sopenharmony_ci	int err;
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_ci	if (!x86_match_cpu(pcmul_cpu_id))
34562306a36Sopenharmony_ci		return -ENODEV;
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_ci	err = crypto_register_shash(&ghash_alg);
34862306a36Sopenharmony_ci	if (err)
34962306a36Sopenharmony_ci		goto err_out;
35062306a36Sopenharmony_ci	err = crypto_register_ahash(&ghash_async_alg);
35162306a36Sopenharmony_ci	if (err)
35262306a36Sopenharmony_ci		goto err_shash;
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_ci	return 0;
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_cierr_shash:
35762306a36Sopenharmony_ci	crypto_unregister_shash(&ghash_alg);
35862306a36Sopenharmony_cierr_out:
35962306a36Sopenharmony_ci	return err;
36062306a36Sopenharmony_ci}
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_cistatic void __exit ghash_pclmulqdqni_mod_exit(void)
36362306a36Sopenharmony_ci{
36462306a36Sopenharmony_ci	crypto_unregister_ahash(&ghash_async_alg);
36562306a36Sopenharmony_ci	crypto_unregister_shash(&ghash_alg);
36662306a36Sopenharmony_ci}
36762306a36Sopenharmony_ci
36862306a36Sopenharmony_cimodule_init(ghash_pclmulqdqni_mod_init);
36962306a36Sopenharmony_cimodule_exit(ghash_pclmulqdqni_mod_exit);
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_ciMODULE_LICENSE("GPL");
37262306a36Sopenharmony_ciMODULE_DESCRIPTION("GHASH hash function, accelerated by PCLMULQDQ-NI");
37362306a36Sopenharmony_ciMODULE_ALIAS_CRYPTO("ghash");
374