xref: /openbmc/linux/arch/powerpc/crypto/crct10dif-vpmsum_glue.c (revision 75bf465f0bc33e9b776a46d6a1b9b990f5fb7c37)
1*2874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2b01df1c1SDaniel Axtens /*
3b01df1c1SDaniel Axtens  * Calculate a CRC T10-DIF with vpmsum acceleration
4b01df1c1SDaniel Axtens  *
5b01df1c1SDaniel Axtens  * Copyright 2017, Daniel Axtens, IBM Corporation.
6b01df1c1SDaniel Axtens  * [based on crc32c-vpmsum_glue.c]
7b01df1c1SDaniel Axtens  */
8b01df1c1SDaniel Axtens 
9b01df1c1SDaniel Axtens #include <linux/crc-t10dif.h>
10b01df1c1SDaniel Axtens #include <crypto/internal/hash.h>
11626ddb2fSEric Biggers #include <crypto/internal/simd.h>
12b01df1c1SDaniel Axtens #include <linux/init.h>
13b01df1c1SDaniel Axtens #include <linux/module.h>
14b01df1c1SDaniel Axtens #include <linux/string.h>
15b01df1c1SDaniel Axtens #include <linux/kernel.h>
16b01df1c1SDaniel Axtens #include <linux/cpufeature.h>
17626ddb2fSEric Biggers #include <asm/simd.h>
18b01df1c1SDaniel Axtens #include <asm/switch_to.h>
19b01df1c1SDaniel Axtens 
20b01df1c1SDaniel Axtens #define VMX_ALIGN		16
21b01df1c1SDaniel Axtens #define VMX_ALIGN_MASK		(VMX_ALIGN-1)
22b01df1c1SDaniel Axtens 
23b01df1c1SDaniel Axtens #define VECTOR_BREAKPOINT	64
24b01df1c1SDaniel Axtens 
25b01df1c1SDaniel Axtens u32 __crct10dif_vpmsum(u32 crc, unsigned char const *p, size_t len);
26b01df1c1SDaniel Axtens 
crct10dif_vpmsum(u16 crci,unsigned char const * p,size_t len)27b01df1c1SDaniel Axtens static u16 crct10dif_vpmsum(u16 crci, unsigned char const *p, size_t len)
28b01df1c1SDaniel Axtens {
29b01df1c1SDaniel Axtens 	unsigned int prealign;
30b01df1c1SDaniel Axtens 	unsigned int tail;
31b01df1c1SDaniel Axtens 	u32 crc = crci;
32b01df1c1SDaniel Axtens 
33626ddb2fSEric Biggers 	if (len < (VECTOR_BREAKPOINT + VMX_ALIGN) || !crypto_simd_usable())
34b01df1c1SDaniel Axtens 		return crc_t10dif_generic(crc, p, len);
35b01df1c1SDaniel Axtens 
36b01df1c1SDaniel Axtens 	if ((unsigned long)p & VMX_ALIGN_MASK) {
37b01df1c1SDaniel Axtens 		prealign = VMX_ALIGN - ((unsigned long)p & VMX_ALIGN_MASK);
38b01df1c1SDaniel Axtens 		crc = crc_t10dif_generic(crc, p, prealign);
39b01df1c1SDaniel Axtens 		len -= prealign;
40b01df1c1SDaniel Axtens 		p += prealign;
41b01df1c1SDaniel Axtens 	}
42b01df1c1SDaniel Axtens 
43b01df1c1SDaniel Axtens 	if (len & ~VMX_ALIGN_MASK) {
44b01df1c1SDaniel Axtens 		crc <<= 16;
450f89f6e1SMichael Ellerman 		preempt_disable();
46b01df1c1SDaniel Axtens 		pagefault_disable();
47b01df1c1SDaniel Axtens 		enable_kernel_altivec();
48b01df1c1SDaniel Axtens 		crc = __crct10dif_vpmsum(crc, p, len & ~VMX_ALIGN_MASK);
490f89f6e1SMichael Ellerman 		disable_kernel_altivec();
50b01df1c1SDaniel Axtens 		pagefault_enable();
510f89f6e1SMichael Ellerman 		preempt_enable();
52b01df1c1SDaniel Axtens 		crc >>= 16;
53b01df1c1SDaniel Axtens 	}
54b01df1c1SDaniel Axtens 
55b01df1c1SDaniel Axtens 	tail = len & VMX_ALIGN_MASK;
56b01df1c1SDaniel Axtens 	if (tail) {
57b01df1c1SDaniel Axtens 		p += len & ~VMX_ALIGN_MASK;
58b01df1c1SDaniel Axtens 		crc = crc_t10dif_generic(crc, p, tail);
59b01df1c1SDaniel Axtens 	}
60b01df1c1SDaniel Axtens 
61b01df1c1SDaniel Axtens 	return crc & 0xffff;
62b01df1c1SDaniel Axtens }
63b01df1c1SDaniel Axtens 
crct10dif_vpmsum_init(struct shash_desc * desc)64b01df1c1SDaniel Axtens static int crct10dif_vpmsum_init(struct shash_desc *desc)
65b01df1c1SDaniel Axtens {
66b01df1c1SDaniel Axtens 	u16 *crc = shash_desc_ctx(desc);
67b01df1c1SDaniel Axtens 
68b01df1c1SDaniel Axtens 	*crc = 0;
69b01df1c1SDaniel Axtens 	return 0;
70b01df1c1SDaniel Axtens }
71b01df1c1SDaniel Axtens 
crct10dif_vpmsum_update(struct shash_desc * desc,const u8 * data,unsigned int length)72b01df1c1SDaniel Axtens static int crct10dif_vpmsum_update(struct shash_desc *desc, const u8 *data,
73b01df1c1SDaniel Axtens 			    unsigned int length)
74b01df1c1SDaniel Axtens {
75b01df1c1SDaniel Axtens 	u16 *crc = shash_desc_ctx(desc);
76b01df1c1SDaniel Axtens 
77b01df1c1SDaniel Axtens 	*crc = crct10dif_vpmsum(*crc, data, length);
78b01df1c1SDaniel Axtens 
79b01df1c1SDaniel Axtens 	return 0;
80b01df1c1SDaniel Axtens }
81b01df1c1SDaniel Axtens 
82b01df1c1SDaniel Axtens 
crct10dif_vpmsum_final(struct shash_desc * desc,u8 * out)83b01df1c1SDaniel Axtens static int crct10dif_vpmsum_final(struct shash_desc *desc, u8 *out)
84b01df1c1SDaniel Axtens {
85b01df1c1SDaniel Axtens 	u16 *crcp = shash_desc_ctx(desc);
86b01df1c1SDaniel Axtens 
87b01df1c1SDaniel Axtens 	*(u16 *)out = *crcp;
88b01df1c1SDaniel Axtens 	return 0;
89b01df1c1SDaniel Axtens }
90b01df1c1SDaniel Axtens 
91b01df1c1SDaniel Axtens static struct shash_alg alg = {
92b01df1c1SDaniel Axtens 	.init		= crct10dif_vpmsum_init,
93b01df1c1SDaniel Axtens 	.update		= crct10dif_vpmsum_update,
94b01df1c1SDaniel Axtens 	.final		= crct10dif_vpmsum_final,
95b01df1c1SDaniel Axtens 	.descsize	= CRC_T10DIF_DIGEST_SIZE,
96b01df1c1SDaniel Axtens 	.digestsize	= CRC_T10DIF_DIGEST_SIZE,
97b01df1c1SDaniel Axtens 	.base		= {
98b01df1c1SDaniel Axtens 		.cra_name		= "crct10dif",
99b01df1c1SDaniel Axtens 		.cra_driver_name	= "crct10dif-vpmsum",
100b01df1c1SDaniel Axtens 		.cra_priority		= 200,
101b01df1c1SDaniel Axtens 		.cra_blocksize		= CRC_T10DIF_BLOCK_SIZE,
102b01df1c1SDaniel Axtens 		.cra_module		= THIS_MODULE,
103b01df1c1SDaniel Axtens 	}
104b01df1c1SDaniel Axtens };
105b01df1c1SDaniel Axtens 
crct10dif_vpmsum_mod_init(void)106b01df1c1SDaniel Axtens static int __init crct10dif_vpmsum_mod_init(void)
107b01df1c1SDaniel Axtens {
108b01df1c1SDaniel Axtens 	if (!cpu_has_feature(CPU_FTR_ARCH_207S))
109b01df1c1SDaniel Axtens 		return -ENODEV;
110b01df1c1SDaniel Axtens 
111b01df1c1SDaniel Axtens 	return crypto_register_shash(&alg);
112b01df1c1SDaniel Axtens }
113b01df1c1SDaniel Axtens 
crct10dif_vpmsum_mod_fini(void)114b01df1c1SDaniel Axtens static void __exit crct10dif_vpmsum_mod_fini(void)
115b01df1c1SDaniel Axtens {
116b01df1c1SDaniel Axtens 	crypto_unregister_shash(&alg);
117b01df1c1SDaniel Axtens }
118b01df1c1SDaniel Axtens 
119b01df1c1SDaniel Axtens module_cpu_feature_match(PPC_MODULE_FEATURE_VEC_CRYPTO, crct10dif_vpmsum_mod_init);
120b01df1c1SDaniel Axtens module_exit(crct10dif_vpmsum_mod_fini);
121b01df1c1SDaniel Axtens 
122b01df1c1SDaniel Axtens MODULE_AUTHOR("Daniel Axtens <dja@axtens.net>");
123b01df1c1SDaniel Axtens MODULE_DESCRIPTION("CRCT10DIF using vector polynomial multiply-sum instructions");
124b01df1c1SDaniel Axtens MODULE_LICENSE("GPL");
125b01df1c1SDaniel Axtens MODULE_ALIAS_CRYPTO("crct10dif");
126b01df1c1SDaniel Axtens MODULE_ALIAS_CRYPTO("crct10dif-vpmsum");
127