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