Linux Audio

Check our new training course

Loading...
v3.1
  1/*
  2 * Accelerated GHASH implementation with Intel PCLMULQDQ-NI
  3 * instructions. This file contains glue code.
  4 *
  5 * Copyright (c) 2009 Intel Corp.
  6 *   Author: Huang Ying <ying.huang@intel.com>
  7 *
  8 * This program is free software; you can redistribute it and/or modify it
  9 * under the terms of the GNU General Public License version 2 as published
 10 * by the Free Software Foundation.
 11 */
 12
 13#include <linux/err.h>
 14#include <linux/module.h>
 15#include <linux/init.h>
 16#include <linux/kernel.h>
 17#include <linux/crypto.h>
 18#include <crypto/algapi.h>
 19#include <crypto/cryptd.h>
 20#include <crypto/gf128mul.h>
 21#include <crypto/internal/hash.h>
 22#include <asm/i387.h>
 
 23
 24#define GHASH_BLOCK_SIZE	16
 25#define GHASH_DIGEST_SIZE	16
 26
 27void clmul_ghash_mul(char *dst, const be128 *shash);
 28
 29void clmul_ghash_update(char *dst, const char *src, unsigned int srclen,
 30			const be128 *shash);
 31
 32void clmul_ghash_setkey(be128 *shash, const u8 *key);
 33
 34struct ghash_async_ctx {
 35	struct cryptd_ahash *cryptd_tfm;
 36};
 37
 38struct ghash_ctx {
 39	be128 shash;
 40};
 41
 42struct ghash_desc_ctx {
 43	u8 buffer[GHASH_BLOCK_SIZE];
 44	u32 bytes;
 45};
 46
 47static int ghash_init(struct shash_desc *desc)
 48{
 49	struct ghash_desc_ctx *dctx = shash_desc_ctx(desc);
 50
 51	memset(dctx, 0, sizeof(*dctx));
 52
 53	return 0;
 54}
 55
 56static int ghash_setkey(struct crypto_shash *tfm,
 57			const u8 *key, unsigned int keylen)
 58{
 59	struct ghash_ctx *ctx = crypto_shash_ctx(tfm);
 
 
 60
 61	if (keylen != GHASH_BLOCK_SIZE) {
 62		crypto_shash_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN);
 63		return -EINVAL;
 64	}
 65
 66	clmul_ghash_setkey(&ctx->shash, key);
 
 
 
 
 
 
 
 
 67
 68	return 0;
 69}
 70
 71static int ghash_update(struct shash_desc *desc,
 72			 const u8 *src, unsigned int srclen)
 73{
 74	struct ghash_desc_ctx *dctx = shash_desc_ctx(desc);
 75	struct ghash_ctx *ctx = crypto_shash_ctx(desc->tfm);
 76	u8 *dst = dctx->buffer;
 77
 78	kernel_fpu_begin();
 79	if (dctx->bytes) {
 80		int n = min(srclen, dctx->bytes);
 81		u8 *pos = dst + (GHASH_BLOCK_SIZE - dctx->bytes);
 82
 83		dctx->bytes -= n;
 84		srclen -= n;
 85
 86		while (n--)
 87			*pos++ ^= *src++;
 88
 89		if (!dctx->bytes)
 90			clmul_ghash_mul(dst, &ctx->shash);
 91	}
 92
 93	clmul_ghash_update(dst, src, srclen, &ctx->shash);
 94	kernel_fpu_end();
 95
 96	if (srclen & 0xf) {
 97		src += srclen - (srclen & 0xf);
 98		srclen &= 0xf;
 99		dctx->bytes = GHASH_BLOCK_SIZE - srclen;
100		while (srclen--)
101			*dst++ ^= *src++;
102	}
103
104	return 0;
105}
106
107static void ghash_flush(struct ghash_ctx *ctx, struct ghash_desc_ctx *dctx)
108{
109	u8 *dst = dctx->buffer;
110
111	if (dctx->bytes) {
112		u8 *tmp = dst + (GHASH_BLOCK_SIZE - dctx->bytes);
113
114		while (dctx->bytes--)
115			*tmp++ ^= 0;
116
117		kernel_fpu_begin();
118		clmul_ghash_mul(dst, &ctx->shash);
119		kernel_fpu_end();
120	}
121
122	dctx->bytes = 0;
123}
124
125static int ghash_final(struct shash_desc *desc, u8 *dst)
126{
127	struct ghash_desc_ctx *dctx = shash_desc_ctx(desc);
128	struct ghash_ctx *ctx = crypto_shash_ctx(desc->tfm);
129	u8 *buf = dctx->buffer;
130
131	ghash_flush(ctx, dctx);
132	memcpy(dst, buf, GHASH_BLOCK_SIZE);
133
134	return 0;
135}
136
137static struct shash_alg ghash_alg = {
138	.digestsize	= GHASH_DIGEST_SIZE,
139	.init		= ghash_init,
140	.update		= ghash_update,
141	.final		= ghash_final,
142	.setkey		= ghash_setkey,
143	.descsize	= sizeof(struct ghash_desc_ctx),
144	.base		= {
145		.cra_name		= "__ghash",
146		.cra_driver_name	= "__ghash-pclmulqdqni",
147		.cra_priority		= 0,
148		.cra_flags		= CRYPTO_ALG_TYPE_SHASH,
 
149		.cra_blocksize		= GHASH_BLOCK_SIZE,
150		.cra_ctxsize		= sizeof(struct ghash_ctx),
151		.cra_module		= THIS_MODULE,
152		.cra_list		= LIST_HEAD_INIT(ghash_alg.base.cra_list),
153	},
154};
155
156static int ghash_async_init(struct ahash_request *req)
157{
158	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
159	struct ghash_async_ctx *ctx = crypto_ahash_ctx(tfm);
160	struct ahash_request *cryptd_req = ahash_request_ctx(req);
161	struct cryptd_ahash *cryptd_tfm = ctx->cryptd_tfm;
 
 
162
163	if (!irq_fpu_usable()) {
164		memcpy(cryptd_req, req, sizeof(*req));
165		ahash_request_set_tfm(cryptd_req, &cryptd_tfm->base);
166		return crypto_ahash_init(cryptd_req);
167	} else {
168		struct shash_desc *desc = cryptd_shash_desc(cryptd_req);
169		struct crypto_shash *child = cryptd_ahash_child(cryptd_tfm);
170
171		desc->tfm = child;
172		desc->flags = req->base.flags;
173		return crypto_shash_init(desc);
174	}
175}
176
177static int ghash_async_update(struct ahash_request *req)
178{
179	struct ahash_request *cryptd_req = ahash_request_ctx(req);
 
 
 
180
181	if (!irq_fpu_usable()) {
182		struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
183		struct ghash_async_ctx *ctx = crypto_ahash_ctx(tfm);
184		struct cryptd_ahash *cryptd_tfm = ctx->cryptd_tfm;
185
186		memcpy(cryptd_req, req, sizeof(*req));
187		ahash_request_set_tfm(cryptd_req, &cryptd_tfm->base);
188		return crypto_ahash_update(cryptd_req);
189	} else {
190		struct shash_desc *desc = cryptd_shash_desc(cryptd_req);
191		return shash_ahash_update(req, desc);
192	}
193}
194
195static int ghash_async_final(struct ahash_request *req)
196{
197	struct ahash_request *cryptd_req = ahash_request_ctx(req);
 
 
 
198
199	if (!irq_fpu_usable()) {
200		struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
201		struct ghash_async_ctx *ctx = crypto_ahash_ctx(tfm);
202		struct cryptd_ahash *cryptd_tfm = ctx->cryptd_tfm;
203
204		memcpy(cryptd_req, req, sizeof(*req));
205		ahash_request_set_tfm(cryptd_req, &cryptd_tfm->base);
206		return crypto_ahash_final(cryptd_req);
207	} else {
208		struct shash_desc *desc = cryptd_shash_desc(cryptd_req);
209		return crypto_shash_final(desc, req->result);
210	}
211}
212
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
213static int ghash_async_digest(struct ahash_request *req)
214{
215	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
216	struct ghash_async_ctx *ctx = crypto_ahash_ctx(tfm);
217	struct ahash_request *cryptd_req = ahash_request_ctx(req);
218	struct cryptd_ahash *cryptd_tfm = ctx->cryptd_tfm;
219
220	if (!irq_fpu_usable()) {
 
221		memcpy(cryptd_req, req, sizeof(*req));
222		ahash_request_set_tfm(cryptd_req, &cryptd_tfm->base);
223		return crypto_ahash_digest(cryptd_req);
224	} else {
225		struct shash_desc *desc = cryptd_shash_desc(cryptd_req);
226		struct crypto_shash *child = cryptd_ahash_child(cryptd_tfm);
227
228		desc->tfm = child;
229		desc->flags = req->base.flags;
230		return shash_ahash_digest(req, desc);
231	}
232}
233
234static int ghash_async_setkey(struct crypto_ahash *tfm, const u8 *key,
235			      unsigned int keylen)
236{
237	struct ghash_async_ctx *ctx = crypto_ahash_ctx(tfm);
238	struct crypto_ahash *child = &ctx->cryptd_tfm->base;
239	int err;
240
241	crypto_ahash_clear_flags(child, CRYPTO_TFM_REQ_MASK);
242	crypto_ahash_set_flags(child, crypto_ahash_get_flags(tfm)
243			       & CRYPTO_TFM_REQ_MASK);
244	err = crypto_ahash_setkey(child, key, keylen);
245	crypto_ahash_set_flags(tfm, crypto_ahash_get_flags(child)
246			       & CRYPTO_TFM_RES_MASK);
247
248	return err;
249}
250
251static int ghash_async_init_tfm(struct crypto_tfm *tfm)
252{
253	struct cryptd_ahash *cryptd_tfm;
254	struct ghash_async_ctx *ctx = crypto_tfm_ctx(tfm);
255
256	cryptd_tfm = cryptd_alloc_ahash("__ghash-pclmulqdqni", 0, 0);
 
 
257	if (IS_ERR(cryptd_tfm))
258		return PTR_ERR(cryptd_tfm);
259	ctx->cryptd_tfm = cryptd_tfm;
260	crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm),
261				 sizeof(struct ahash_request) +
262				 crypto_ahash_reqsize(&cryptd_tfm->base));
263
264	return 0;
265}
266
267static void ghash_async_exit_tfm(struct crypto_tfm *tfm)
268{
269	struct ghash_async_ctx *ctx = crypto_tfm_ctx(tfm);
270
271	cryptd_free_ahash(ctx->cryptd_tfm);
272}
273
274static struct ahash_alg ghash_async_alg = {
275	.init		= ghash_async_init,
276	.update		= ghash_async_update,
277	.final		= ghash_async_final,
278	.setkey		= ghash_async_setkey,
279	.digest		= ghash_async_digest,
 
 
280	.halg = {
281		.digestsize	= GHASH_DIGEST_SIZE,
 
282		.base = {
283			.cra_name		= "ghash",
284			.cra_driver_name	= "ghash-clmulni",
285			.cra_priority		= 400,
 
286			.cra_flags		= CRYPTO_ALG_TYPE_AHASH | CRYPTO_ALG_ASYNC,
287			.cra_blocksize		= GHASH_BLOCK_SIZE,
288			.cra_type		= &crypto_ahash_type,
289			.cra_module		= THIS_MODULE,
290			.cra_list		= LIST_HEAD_INIT(ghash_async_alg.halg.base.cra_list),
291			.cra_init		= ghash_async_init_tfm,
292			.cra_exit		= ghash_async_exit_tfm,
293		},
294	},
295};
296
 
 
 
 
 
 
297static int __init ghash_pclmulqdqni_mod_init(void)
298{
299	int err;
300
301	if (!cpu_has_pclmulqdq) {
302		printk(KERN_INFO "Intel PCLMULQDQ-NI instructions are not"
303		       " detected.\n");
304		return -ENODEV;
305	}
306
307	err = crypto_register_shash(&ghash_alg);
308	if (err)
309		goto err_out;
310	err = crypto_register_ahash(&ghash_async_alg);
311	if (err)
312		goto err_shash;
313
314	return 0;
315
316err_shash:
317	crypto_unregister_shash(&ghash_alg);
318err_out:
319	return err;
320}
321
322static void __exit ghash_pclmulqdqni_mod_exit(void)
323{
324	crypto_unregister_ahash(&ghash_async_alg);
325	crypto_unregister_shash(&ghash_alg);
326}
327
328module_init(ghash_pclmulqdqni_mod_init);
329module_exit(ghash_pclmulqdqni_mod_exit);
330
331MODULE_LICENSE("GPL");
332MODULE_DESCRIPTION("GHASH Message Digest Algorithm, "
333		   "acclerated by PCLMULQDQ-NI");
334MODULE_ALIAS("ghash");
v4.17
  1/*
  2 * Accelerated GHASH implementation with Intel PCLMULQDQ-NI
  3 * instructions. This file contains glue code.
  4 *
  5 * Copyright (c) 2009 Intel Corp.
  6 *   Author: Huang Ying <ying.huang@intel.com>
  7 *
  8 * This program is free software; you can redistribute it and/or modify it
  9 * under the terms of the GNU General Public License version 2 as published
 10 * by the Free Software Foundation.
 11 */
 12
 13#include <linux/err.h>
 14#include <linux/module.h>
 15#include <linux/init.h>
 16#include <linux/kernel.h>
 17#include <linux/crypto.h>
 18#include <crypto/algapi.h>
 19#include <crypto/cryptd.h>
 20#include <crypto/gf128mul.h>
 21#include <crypto/internal/hash.h>
 22#include <asm/fpu/api.h>
 23#include <asm/cpu_device_id.h>
 24
 25#define GHASH_BLOCK_SIZE	16
 26#define GHASH_DIGEST_SIZE	16
 27
 28void clmul_ghash_mul(char *dst, const u128 *shash);
 29
 30void clmul_ghash_update(char *dst, const char *src, unsigned int srclen,
 31			const u128 *shash);
 
 
 32
 33struct ghash_async_ctx {
 34	struct cryptd_ahash *cryptd_tfm;
 35};
 36
 37struct ghash_ctx {
 38	u128 shash;
 39};
 40
 41struct ghash_desc_ctx {
 42	u8 buffer[GHASH_BLOCK_SIZE];
 43	u32 bytes;
 44};
 45
 46static int ghash_init(struct shash_desc *desc)
 47{
 48	struct ghash_desc_ctx *dctx = shash_desc_ctx(desc);
 49
 50	memset(dctx, 0, sizeof(*dctx));
 51
 52	return 0;
 53}
 54
 55static int ghash_setkey(struct crypto_shash *tfm,
 56			const u8 *key, unsigned int keylen)
 57{
 58	struct ghash_ctx *ctx = crypto_shash_ctx(tfm);
 59	be128 *x = (be128 *)key;
 60	u64 a, b;
 61
 62	if (keylen != GHASH_BLOCK_SIZE) {
 63		crypto_shash_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN);
 64		return -EINVAL;
 65	}
 66
 67	/* perform multiplication by 'x' in GF(2^128) */
 68	a = be64_to_cpu(x->a);
 69	b = be64_to_cpu(x->b);
 70
 71	ctx->shash.a = (b << 1) | (a >> 63);
 72	ctx->shash.b = (a << 1) | (b >> 63);
 73
 74	if (a >> 63)
 75		ctx->shash.b ^= ((u64)0xc2) << 56;
 76
 77	return 0;
 78}
 79
 80static int ghash_update(struct shash_desc *desc,
 81			 const u8 *src, unsigned int srclen)
 82{
 83	struct ghash_desc_ctx *dctx = shash_desc_ctx(desc);
 84	struct ghash_ctx *ctx = crypto_shash_ctx(desc->tfm);
 85	u8 *dst = dctx->buffer;
 86
 87	kernel_fpu_begin();
 88	if (dctx->bytes) {
 89		int n = min(srclen, dctx->bytes);
 90		u8 *pos = dst + (GHASH_BLOCK_SIZE - dctx->bytes);
 91
 92		dctx->bytes -= n;
 93		srclen -= n;
 94
 95		while (n--)
 96			*pos++ ^= *src++;
 97
 98		if (!dctx->bytes)
 99			clmul_ghash_mul(dst, &ctx->shash);
100	}
101
102	clmul_ghash_update(dst, src, srclen, &ctx->shash);
103	kernel_fpu_end();
104
105	if (srclen & 0xf) {
106		src += srclen - (srclen & 0xf);
107		srclen &= 0xf;
108		dctx->bytes = GHASH_BLOCK_SIZE - srclen;
109		while (srclen--)
110			*dst++ ^= *src++;
111	}
112
113	return 0;
114}
115
116static void ghash_flush(struct ghash_ctx *ctx, struct ghash_desc_ctx *dctx)
117{
118	u8 *dst = dctx->buffer;
119
120	if (dctx->bytes) {
121		u8 *tmp = dst + (GHASH_BLOCK_SIZE - dctx->bytes);
122
123		while (dctx->bytes--)
124			*tmp++ ^= 0;
125
126		kernel_fpu_begin();
127		clmul_ghash_mul(dst, &ctx->shash);
128		kernel_fpu_end();
129	}
130
131	dctx->bytes = 0;
132}
133
134static int ghash_final(struct shash_desc *desc, u8 *dst)
135{
136	struct ghash_desc_ctx *dctx = shash_desc_ctx(desc);
137	struct ghash_ctx *ctx = crypto_shash_ctx(desc->tfm);
138	u8 *buf = dctx->buffer;
139
140	ghash_flush(ctx, dctx);
141	memcpy(dst, buf, GHASH_BLOCK_SIZE);
142
143	return 0;
144}
145
146static struct shash_alg ghash_alg = {
147	.digestsize	= GHASH_DIGEST_SIZE,
148	.init		= ghash_init,
149	.update		= ghash_update,
150	.final		= ghash_final,
151	.setkey		= ghash_setkey,
152	.descsize	= sizeof(struct ghash_desc_ctx),
153	.base		= {
154		.cra_name		= "__ghash",
155		.cra_driver_name	= "__ghash-pclmulqdqni",
156		.cra_priority		= 0,
157		.cra_flags		= CRYPTO_ALG_TYPE_SHASH |
158					  CRYPTO_ALG_INTERNAL,
159		.cra_blocksize		= GHASH_BLOCK_SIZE,
160		.cra_ctxsize		= sizeof(struct ghash_ctx),
161		.cra_module		= THIS_MODULE,
 
162	},
163};
164
165static int ghash_async_init(struct ahash_request *req)
166{
167	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
168	struct ghash_async_ctx *ctx = crypto_ahash_ctx(tfm);
169	struct ahash_request *cryptd_req = ahash_request_ctx(req);
170	struct cryptd_ahash *cryptd_tfm = ctx->cryptd_tfm;
171	struct shash_desc *desc = cryptd_shash_desc(cryptd_req);
172	struct crypto_shash *child = cryptd_ahash_child(cryptd_tfm);
173
174	desc->tfm = child;
175	desc->flags = req->base.flags;
176	return crypto_shash_init(desc);
 
 
 
 
 
 
 
 
 
177}
178
179static int ghash_async_update(struct ahash_request *req)
180{
181	struct ahash_request *cryptd_req = ahash_request_ctx(req);
182	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
183	struct ghash_async_ctx *ctx = crypto_ahash_ctx(tfm);
184	struct cryptd_ahash *cryptd_tfm = ctx->cryptd_tfm;
185
186	if (!irq_fpu_usable() ||
187	    (in_atomic() && cryptd_ahash_queued(cryptd_tfm))) {
 
 
 
188		memcpy(cryptd_req, req, sizeof(*req));
189		ahash_request_set_tfm(cryptd_req, &cryptd_tfm->base);
190		return crypto_ahash_update(cryptd_req);
191	} else {
192		struct shash_desc *desc = cryptd_shash_desc(cryptd_req);
193		return shash_ahash_update(req, desc);
194	}
195}
196
197static int ghash_async_final(struct ahash_request *req)
198{
199	struct ahash_request *cryptd_req = ahash_request_ctx(req);
200	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
201	struct ghash_async_ctx *ctx = crypto_ahash_ctx(tfm);
202	struct cryptd_ahash *cryptd_tfm = ctx->cryptd_tfm;
203
204	if (!irq_fpu_usable() ||
205	    (in_atomic() && cryptd_ahash_queued(cryptd_tfm))) {
 
 
 
206		memcpy(cryptd_req, req, sizeof(*req));
207		ahash_request_set_tfm(cryptd_req, &cryptd_tfm->base);
208		return crypto_ahash_final(cryptd_req);
209	} else {
210		struct shash_desc *desc = cryptd_shash_desc(cryptd_req);
211		return crypto_shash_final(desc, req->result);
212	}
213}
214
215static int ghash_async_import(struct ahash_request *req, const void *in)
216{
217	struct ahash_request *cryptd_req = ahash_request_ctx(req);
218	struct shash_desc *desc = cryptd_shash_desc(cryptd_req);
219	struct ghash_desc_ctx *dctx = shash_desc_ctx(desc);
220
221	ghash_async_init(req);
222	memcpy(dctx, in, sizeof(*dctx));
223	return 0;
224
225}
226
227static int ghash_async_export(struct ahash_request *req, void *out)
228{
229	struct ahash_request *cryptd_req = ahash_request_ctx(req);
230	struct shash_desc *desc = cryptd_shash_desc(cryptd_req);
231	struct ghash_desc_ctx *dctx = shash_desc_ctx(desc);
232
233	memcpy(out, dctx, sizeof(*dctx));
234	return 0;
235
236}
237
238static int ghash_async_digest(struct ahash_request *req)
239{
240	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
241	struct ghash_async_ctx *ctx = crypto_ahash_ctx(tfm);
242	struct ahash_request *cryptd_req = ahash_request_ctx(req);
243	struct cryptd_ahash *cryptd_tfm = ctx->cryptd_tfm;
244
245	if (!irq_fpu_usable() ||
246	    (in_atomic() && cryptd_ahash_queued(cryptd_tfm))) {
247		memcpy(cryptd_req, req, sizeof(*req));
248		ahash_request_set_tfm(cryptd_req, &cryptd_tfm->base);
249		return crypto_ahash_digest(cryptd_req);
250	} else {
251		struct shash_desc *desc = cryptd_shash_desc(cryptd_req);
252		struct crypto_shash *child = cryptd_ahash_child(cryptd_tfm);
253
254		desc->tfm = child;
255		desc->flags = req->base.flags;
256		return shash_ahash_digest(req, desc);
257	}
258}
259
260static int ghash_async_setkey(struct crypto_ahash *tfm, const u8 *key,
261			      unsigned int keylen)
262{
263	struct ghash_async_ctx *ctx = crypto_ahash_ctx(tfm);
264	struct crypto_ahash *child = &ctx->cryptd_tfm->base;
265	int err;
266
267	crypto_ahash_clear_flags(child, CRYPTO_TFM_REQ_MASK);
268	crypto_ahash_set_flags(child, crypto_ahash_get_flags(tfm)
269			       & CRYPTO_TFM_REQ_MASK);
270	err = crypto_ahash_setkey(child, key, keylen);
271	crypto_ahash_set_flags(tfm, crypto_ahash_get_flags(child)
272			       & CRYPTO_TFM_RES_MASK);
273
274	return err;
275}
276
277static int ghash_async_init_tfm(struct crypto_tfm *tfm)
278{
279	struct cryptd_ahash *cryptd_tfm;
280	struct ghash_async_ctx *ctx = crypto_tfm_ctx(tfm);
281
282	cryptd_tfm = cryptd_alloc_ahash("__ghash-pclmulqdqni",
283					CRYPTO_ALG_INTERNAL,
284					CRYPTO_ALG_INTERNAL);
285	if (IS_ERR(cryptd_tfm))
286		return PTR_ERR(cryptd_tfm);
287	ctx->cryptd_tfm = cryptd_tfm;
288	crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm),
289				 sizeof(struct ahash_request) +
290				 crypto_ahash_reqsize(&cryptd_tfm->base));
291
292	return 0;
293}
294
295static void ghash_async_exit_tfm(struct crypto_tfm *tfm)
296{
297	struct ghash_async_ctx *ctx = crypto_tfm_ctx(tfm);
298
299	cryptd_free_ahash(ctx->cryptd_tfm);
300}
301
302static struct ahash_alg ghash_async_alg = {
303	.init		= ghash_async_init,
304	.update		= ghash_async_update,
305	.final		= ghash_async_final,
306	.setkey		= ghash_async_setkey,
307	.digest		= ghash_async_digest,
308	.export		= ghash_async_export,
309	.import		= ghash_async_import,
310	.halg = {
311		.digestsize	= GHASH_DIGEST_SIZE,
312		.statesize = sizeof(struct ghash_desc_ctx),
313		.base = {
314			.cra_name		= "ghash",
315			.cra_driver_name	= "ghash-clmulni",
316			.cra_priority		= 400,
317			.cra_ctxsize		= sizeof(struct ghash_async_ctx),
318			.cra_flags		= CRYPTO_ALG_TYPE_AHASH | CRYPTO_ALG_ASYNC,
319			.cra_blocksize		= GHASH_BLOCK_SIZE,
320			.cra_type		= &crypto_ahash_type,
321			.cra_module		= THIS_MODULE,
 
322			.cra_init		= ghash_async_init_tfm,
323			.cra_exit		= ghash_async_exit_tfm,
324		},
325	},
326};
327
328static const struct x86_cpu_id pcmul_cpu_id[] = {
329	X86_FEATURE_MATCH(X86_FEATURE_PCLMULQDQ), /* Pickle-Mickle-Duck */
330	{}
331};
332MODULE_DEVICE_TABLE(x86cpu, pcmul_cpu_id);
333
334static int __init ghash_pclmulqdqni_mod_init(void)
335{
336	int err;
337
338	if (!x86_match_cpu(pcmul_cpu_id))
 
 
339		return -ENODEV;
 
340
341	err = crypto_register_shash(&ghash_alg);
342	if (err)
343		goto err_out;
344	err = crypto_register_ahash(&ghash_async_alg);
345	if (err)
346		goto err_shash;
347
348	return 0;
349
350err_shash:
351	crypto_unregister_shash(&ghash_alg);
352err_out:
353	return err;
354}
355
356static void __exit ghash_pclmulqdqni_mod_exit(void)
357{
358	crypto_unregister_ahash(&ghash_async_alg);
359	crypto_unregister_shash(&ghash_alg);
360}
361
362module_init(ghash_pclmulqdqni_mod_init);
363module_exit(ghash_pclmulqdqni_mod_exit);
364
365MODULE_LICENSE("GPL");
366MODULE_DESCRIPTION("GHASH Message Digest Algorithm, "
367		   "acclerated by PCLMULQDQ-NI");
368MODULE_ALIAS_CRYPTO("ghash");