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