diff options
author | David S. Miller <davem@davemloft.net> | 2012-08-22 23:47:36 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2012-08-22 23:47:36 -0400 |
commit | 442a7c40b1dac78588abfe8ed4c97e4bb8b36e73 (patch) | |
tree | 011ab920ea2f5868c01efa91531959d2b26e6368 | |
parent | 9bf4852d3d195f771503d5be547ac940b0b3472a (diff) |
sparc64: Add CRC32C driver making use of the new crc32c opcode.
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | arch/sparc/crypto/Makefile | 4 | ||||
-rw-r--r-- | arch/sparc/crypto/crc32c_asm.S | 29 | ||||
-rw-r--r-- | arch/sparc/crypto/crc32c_glue.c | 177 | ||||
-rw-r--r-- | crypto/Kconfig | 9 |
4 files changed, 219 insertions, 0 deletions
diff --git a/arch/sparc/crypto/Makefile b/arch/sparc/crypto/Makefile index 5034324fdd46..c6ca94181f45 100644 --- a/arch/sparc/crypto/Makefile +++ b/arch/sparc/crypto/Makefile | |||
@@ -9,9 +9,13 @@ obj-$(CONFIG_CRYPTO_MD5_SPARC64) += md5-sparc64.o | |||
9 | 9 | ||
10 | obj-$(CONFIG_CRYPTO_AES_SPARC64) += aes-sparc64.o | 10 | obj-$(CONFIG_CRYPTO_AES_SPARC64) += aes-sparc64.o |
11 | 11 | ||
12 | obj-$(CONFIG_CRYPTO_CRC32C_SPARC64) += crc32c-sparc64.o | ||
13 | |||
12 | sha1-sparc64-y := sha1_asm.o sha1_glue.o | 14 | sha1-sparc64-y := sha1_asm.o sha1_glue.o |
13 | sha256-sparc64-y := sha256_asm.o sha256_glue.o | 15 | sha256-sparc64-y := sha256_asm.o sha256_glue.o |
14 | sha512-sparc64-y := sha512_asm.o sha512_glue.o | 16 | sha512-sparc64-y := sha512_asm.o sha512_glue.o |
15 | md5-sparc64-y := md5_asm.o md5_glue.o | 17 | md5-sparc64-y := md5_asm.o md5_glue.o |
16 | 18 | ||
17 | aes-sparc64-y := aes_asm.o aes_glue.o | 19 | aes-sparc64-y := aes_asm.o aes_glue.o |
20 | |||
21 | crc32c-sparc64-y := crc32c_asm.o crc32c_glue.o | ||
diff --git a/arch/sparc/crypto/crc32c_asm.S b/arch/sparc/crypto/crc32c_asm.S new file mode 100644 index 000000000000..cb479ec72433 --- /dev/null +++ b/arch/sparc/crypto/crc32c_asm.S | |||
@@ -0,0 +1,29 @@ | |||
1 | #include <linux/linkage.h> | ||
2 | #include <asm/visasm.h> | ||
3 | #include <asm/asi.h> | ||
4 | |||
5 | #define F3F(x,y,z) (((x)<<30)|((y)<<19)|((z)<<5)) | ||
6 | |||
7 | #define FPD_ENCODE(x) (((x) >> 5) | ((x) & ~(0x20))) | ||
8 | |||
9 | #define RS1(x) (FPD_ENCODE(x) << 14) | ||
10 | #define RS2(x) (FPD_ENCODE(x) << 0) | ||
11 | #define RD(x) (FPD_ENCODE(x) << 25) | ||
12 | |||
13 | #define CRC32C(a,b,c) \ | ||
14 | .word (F3F(2,0x36,0x147)|RS1(a)|RS2(b)|RD(c)); | ||
15 | |||
16 | ENTRY(crc32c_sparc64) | ||
17 | /* %o0=crc32p, %o1=data_ptr, %o2=len */ | ||
18 | VISEntryHalf | ||
19 | lda [%o0] ASI_PL, %f1 | ||
20 | 1: ldd [%o1], %f2 | ||
21 | CRC32C(0,2,0) | ||
22 | subcc %o2, 8, %o2 | ||
23 | bne,pt %icc, 1b | ||
24 | add %o1, 0x8, %o1 | ||
25 | sta %f1, [%o0] ASI_PL | ||
26 | VISExitHalf | ||
27 | 2: retl | ||
28 | nop | ||
29 | ENDPROC(crc32c_sparc64) | ||
diff --git a/arch/sparc/crypto/crc32c_glue.c b/arch/sparc/crypto/crc32c_glue.c new file mode 100644 index 000000000000..ec31cdb20a14 --- /dev/null +++ b/arch/sparc/crypto/crc32c_glue.c | |||
@@ -0,0 +1,177 @@ | |||
1 | /* Glue code for CRC32C optimized for sparc64 crypto opcodes. | ||
2 | * | ||
3 | * This is based largely upon arch/x86/crypto/crc32c-intel.c | ||
4 | * | ||
5 | * Copyright (C) 2008 Intel Corporation | ||
6 | * Authors: Austin Zhang <austin_zhang@linux.intel.com> | ||
7 | * Kent Liu <kent.liu@intel.com> | ||
8 | */ | ||
9 | |||
10 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
11 | |||
12 | #include <linux/init.h> | ||
13 | #include <linux/module.h> | ||
14 | #include <linux/string.h> | ||
15 | #include <linux/kernel.h> | ||
16 | #include <linux/crc32.h> | ||
17 | |||
18 | #include <crypto/internal/hash.h> | ||
19 | |||
20 | #include <asm/pstate.h> | ||
21 | #include <asm/elf.h> | ||
22 | |||
23 | /* | ||
24 | * Setting the seed allows arbitrary accumulators and flexible XOR policy | ||
25 | * If your algorithm starts with ~0, then XOR with ~0 before you set | ||
26 | * the seed. | ||
27 | */ | ||
28 | static int crc32c_sparc64_setkey(struct crypto_shash *hash, const u8 *key, | ||
29 | unsigned int keylen) | ||
30 | { | ||
31 | u32 *mctx = crypto_shash_ctx(hash); | ||
32 | |||
33 | if (keylen != sizeof(u32)) { | ||
34 | crypto_shash_set_flags(hash, CRYPTO_TFM_RES_BAD_KEY_LEN); | ||
35 | return -EINVAL; | ||
36 | } | ||
37 | *(__le32 *)mctx = le32_to_cpup((__le32 *)key); | ||
38 | return 0; | ||
39 | } | ||
40 | |||
41 | static int crc32c_sparc64_init(struct shash_desc *desc) | ||
42 | { | ||
43 | u32 *mctx = crypto_shash_ctx(desc->tfm); | ||
44 | u32 *crcp = shash_desc_ctx(desc); | ||
45 | |||
46 | *crcp = *mctx; | ||
47 | |||
48 | return 0; | ||
49 | } | ||
50 | |||
51 | extern void crc32c_sparc64(u32 *crcp, const u64 *data, unsigned int len); | ||
52 | |||
53 | static void crc32c_compute(u32 *crcp, const u64 *data, unsigned int len) | ||
54 | { | ||
55 | unsigned int asm_len; | ||
56 | |||
57 | asm_len = len & ~7U; | ||
58 | if (asm_len) { | ||
59 | crc32c_sparc64(crcp, data, asm_len); | ||
60 | data += asm_len / 8; | ||
61 | len -= asm_len; | ||
62 | } | ||
63 | if (len) | ||
64 | *crcp = __crc32c_le(*crcp, (const unsigned char *) data, len); | ||
65 | } | ||
66 | |||
67 | static int crc32c_sparc64_update(struct shash_desc *desc, const u8 *data, | ||
68 | unsigned int len) | ||
69 | { | ||
70 | u32 *crcp = shash_desc_ctx(desc); | ||
71 | |||
72 | crc32c_compute(crcp, (const u64 *) data, len); | ||
73 | |||
74 | return 0; | ||
75 | } | ||
76 | |||
77 | static int __crc32c_sparc64_finup(u32 *crcp, const u8 *data, unsigned int len, | ||
78 | u8 *out) | ||
79 | { | ||
80 | u32 tmp = *crcp; | ||
81 | |||
82 | crc32c_compute(&tmp, (const u64 *) data, len); | ||
83 | |||
84 | *(__le32 *) out = ~cpu_to_le32(tmp); | ||
85 | return 0; | ||
86 | } | ||
87 | |||
88 | static int crc32c_sparc64_finup(struct shash_desc *desc, const u8 *data, | ||
89 | unsigned int len, u8 *out) | ||
90 | { | ||
91 | return __crc32c_sparc64_finup(shash_desc_ctx(desc), data, len, out); | ||
92 | } | ||
93 | |||
94 | static int crc32c_sparc64_final(struct shash_desc *desc, u8 *out) | ||
95 | { | ||
96 | u32 *crcp = shash_desc_ctx(desc); | ||
97 | |||
98 | *(__le32 *) out = ~cpu_to_le32p(crcp); | ||
99 | return 0; | ||
100 | } | ||
101 | |||
102 | static int crc32c_sparc64_digest(struct shash_desc *desc, const u8 *data, | ||
103 | unsigned int len, u8 *out) | ||
104 | { | ||
105 | return __crc32c_sparc64_finup(crypto_shash_ctx(desc->tfm), data, len, | ||
106 | out); | ||
107 | } | ||
108 | |||
109 | static int crc32c_sparc64_cra_init(struct crypto_tfm *tfm) | ||
110 | { | ||
111 | u32 *key = crypto_tfm_ctx(tfm); | ||
112 | |||
113 | *key = ~0; | ||
114 | |||
115 | return 0; | ||
116 | } | ||
117 | |||
118 | #define CHKSUM_BLOCK_SIZE 1 | ||
119 | #define CHKSUM_DIGEST_SIZE 4 | ||
120 | |||
121 | static struct shash_alg alg = { | ||
122 | .setkey = crc32c_sparc64_setkey, | ||
123 | .init = crc32c_sparc64_init, | ||
124 | .update = crc32c_sparc64_update, | ||
125 | .final = crc32c_sparc64_final, | ||
126 | .finup = crc32c_sparc64_finup, | ||
127 | .digest = crc32c_sparc64_digest, | ||
128 | .descsize = sizeof(u32), | ||
129 | .digestsize = CHKSUM_DIGEST_SIZE, | ||
130 | .base = { | ||
131 | .cra_name = "crc32c", | ||
132 | .cra_driver_name = "crc32c-sparc64", | ||
133 | .cra_priority = 150, | ||
134 | .cra_blocksize = CHKSUM_BLOCK_SIZE, | ||
135 | .cra_ctxsize = sizeof(u32), | ||
136 | .cra_alignmask = 7, | ||
137 | .cra_module = THIS_MODULE, | ||
138 | .cra_init = crc32c_sparc64_cra_init, | ||
139 | } | ||
140 | }; | ||
141 | |||
142 | static bool __init sparc64_has_crc32c_opcode(void) | ||
143 | { | ||
144 | unsigned long cfr; | ||
145 | |||
146 | if (!(sparc64_elf_hwcap & HWCAP_SPARC_CRYPTO)) | ||
147 | return false; | ||
148 | |||
149 | __asm__ __volatile__("rd %%asr26, %0" : "=r" (cfr)); | ||
150 | if (!(cfr & CFR_CRC32C)) | ||
151 | return false; | ||
152 | |||
153 | return true; | ||
154 | } | ||
155 | |||
156 | static int __init crc32c_sparc64_mod_init(void) | ||
157 | { | ||
158 | if (sparc64_has_crc32c_opcode()) { | ||
159 | pr_info("Using sparc64 crc32c opcode optimized CRC32C implementation\n"); | ||
160 | return crypto_register_shash(&alg); | ||
161 | } | ||
162 | pr_info("sparc64 crc32c opcode not available.\n"); | ||
163 | return -ENODEV; | ||
164 | } | ||
165 | |||
166 | static void __exit crc32c_sparc64_mod_fini(void) | ||
167 | { | ||
168 | crypto_unregister_shash(&alg); | ||
169 | } | ||
170 | |||
171 | module_init(crc32c_sparc64_mod_init); | ||
172 | module_exit(crc32c_sparc64_mod_fini); | ||
173 | |||
174 | MODULE_LICENSE("GPL"); | ||
175 | MODULE_DESCRIPTION("CRC32c (Castagnoli), sparc64 crc32c opcode accelerated"); | ||
176 | |||
177 | MODULE_ALIAS("crc32c"); | ||
diff --git a/crypto/Kconfig b/crypto/Kconfig index 49f867b2025d..83993ea84cce 100644 --- a/crypto/Kconfig +++ b/crypto/Kconfig | |||
@@ -336,6 +336,15 @@ config CRYPTO_CRC32C_INTEL | |||
336 | gain performance compared with software implementation. | 336 | gain performance compared with software implementation. |
337 | Module will be crc32c-intel. | 337 | Module will be crc32c-intel. |
338 | 338 | ||
339 | config CRYPTO_CRC32C_SPARC64 | ||
340 | tristate "CRC32c CRC algorithm (SPARC64)" | ||
341 | depends on SPARC64 | ||
342 | select CRYPTO_HASH | ||
343 | select CRC32 | ||
344 | help | ||
345 | CRC32c CRC algorithm implemented using sparc64 crypto instructions, | ||
346 | when available. | ||
347 | |||
339 | config CRYPTO_GHASH | 348 | config CRYPTO_GHASH |
340 | tristate "GHASH digest algorithm" | 349 | tristate "GHASH digest algorithm" |
341 | select CRYPTO_GF128MUL | 350 | select CRYPTO_GF128MUL |