diff options
Diffstat (limited to 'drivers/crypto/amcc/crypto4xx_alg.c')
-rw-r--r-- | drivers/crypto/amcc/crypto4xx_alg.c | 293 |
1 files changed, 293 insertions, 0 deletions
diff --git a/drivers/crypto/amcc/crypto4xx_alg.c b/drivers/crypto/amcc/crypto4xx_alg.c new file mode 100644 index 000000000000..61b6e1bec8c6 --- /dev/null +++ b/drivers/crypto/amcc/crypto4xx_alg.c | |||
@@ -0,0 +1,293 @@ | |||
1 | /** | ||
2 | * AMCC SoC PPC4xx Crypto Driver | ||
3 | * | ||
4 | * Copyright (c) 2008 Applied Micro Circuits Corporation. | ||
5 | * All rights reserved. James Hsiao <jhsiao@amcc.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2 of the License, or | ||
10 | * (at your option) any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * This file implements the Linux crypto algorithms. | ||
18 | */ | ||
19 | |||
20 | #include <linux/kernel.h> | ||
21 | #include <linux/interrupt.h> | ||
22 | #include <linux/spinlock_types.h> | ||
23 | #include <linux/scatterlist.h> | ||
24 | #include <linux/crypto.h> | ||
25 | #include <linux/hash.h> | ||
26 | #include <crypto/internal/hash.h> | ||
27 | #include <linux/dma-mapping.h> | ||
28 | #include <crypto/algapi.h> | ||
29 | #include <crypto/aes.h> | ||
30 | #include <crypto/sha.h> | ||
31 | #include "crypto4xx_reg_def.h" | ||
32 | #include "crypto4xx_sa.h" | ||
33 | #include "crypto4xx_core.h" | ||
34 | |||
35 | void set_dynamic_sa_command_0(struct dynamic_sa_ctl *sa, u32 save_h, | ||
36 | u32 save_iv, u32 ld_h, u32 ld_iv, u32 hdr_proc, | ||
37 | u32 h, u32 c, u32 pad_type, u32 op_grp, u32 op, | ||
38 | u32 dir) | ||
39 | { | ||
40 | sa->sa_command_0.w = 0; | ||
41 | sa->sa_command_0.bf.save_hash_state = save_h; | ||
42 | sa->sa_command_0.bf.save_iv = save_iv; | ||
43 | sa->sa_command_0.bf.load_hash_state = ld_h; | ||
44 | sa->sa_command_0.bf.load_iv = ld_iv; | ||
45 | sa->sa_command_0.bf.hdr_proc = hdr_proc; | ||
46 | sa->sa_command_0.bf.hash_alg = h; | ||
47 | sa->sa_command_0.bf.cipher_alg = c; | ||
48 | sa->sa_command_0.bf.pad_type = pad_type & 3; | ||
49 | sa->sa_command_0.bf.extend_pad = pad_type >> 2; | ||
50 | sa->sa_command_0.bf.op_group = op_grp; | ||
51 | sa->sa_command_0.bf.opcode = op; | ||
52 | sa->sa_command_0.bf.dir = dir; | ||
53 | } | ||
54 | |||
55 | void set_dynamic_sa_command_1(struct dynamic_sa_ctl *sa, u32 cm, u32 hmac_mc, | ||
56 | u32 cfb, u32 esn, u32 sn_mask, u32 mute, | ||
57 | u32 cp_pad, u32 cp_pay, u32 cp_hdr) | ||
58 | { | ||
59 | sa->sa_command_1.w = 0; | ||
60 | sa->sa_command_1.bf.crypto_mode31 = (cm & 4) >> 2; | ||
61 | sa->sa_command_1.bf.crypto_mode9_8 = cm & 3; | ||
62 | sa->sa_command_1.bf.feedback_mode = cfb, | ||
63 | sa->sa_command_1.bf.sa_rev = 1; | ||
64 | sa->sa_command_1.bf.extended_seq_num = esn; | ||
65 | sa->sa_command_1.bf.seq_num_mask = sn_mask; | ||
66 | sa->sa_command_1.bf.mutable_bit_proc = mute; | ||
67 | sa->sa_command_1.bf.copy_pad = cp_pad; | ||
68 | sa->sa_command_1.bf.copy_payload = cp_pay; | ||
69 | sa->sa_command_1.bf.copy_hdr = cp_hdr; | ||
70 | } | ||
71 | |||
72 | int crypto4xx_encrypt(struct ablkcipher_request *req) | ||
73 | { | ||
74 | struct crypto4xx_ctx *ctx = crypto_tfm_ctx(req->base.tfm); | ||
75 | |||
76 | ctx->direction = DIR_OUTBOUND; | ||
77 | ctx->hash_final = 0; | ||
78 | ctx->is_hash = 0; | ||
79 | ctx->pd_ctl = 0x1; | ||
80 | |||
81 | return crypto4xx_build_pd(&req->base, ctx, req->src, req->dst, | ||
82 | req->nbytes, req->info, | ||
83 | get_dynamic_sa_iv_size(ctx)); | ||
84 | } | ||
85 | |||
86 | int crypto4xx_decrypt(struct ablkcipher_request *req) | ||
87 | { | ||
88 | struct crypto4xx_ctx *ctx = crypto_tfm_ctx(req->base.tfm); | ||
89 | |||
90 | ctx->direction = DIR_INBOUND; | ||
91 | ctx->hash_final = 0; | ||
92 | ctx->is_hash = 0; | ||
93 | ctx->pd_ctl = 1; | ||
94 | |||
95 | return crypto4xx_build_pd(&req->base, ctx, req->src, req->dst, | ||
96 | req->nbytes, req->info, | ||
97 | get_dynamic_sa_iv_size(ctx)); | ||
98 | } | ||
99 | |||
100 | /** | ||
101 | * AES Functions | ||
102 | */ | ||
103 | static int crypto4xx_setkey_aes(struct crypto_ablkcipher *cipher, | ||
104 | const u8 *key, | ||
105 | unsigned int keylen, | ||
106 | unsigned char cm, | ||
107 | u8 fb) | ||
108 | { | ||
109 | struct crypto_tfm *tfm = crypto_ablkcipher_tfm(cipher); | ||
110 | struct crypto4xx_ctx *ctx = crypto_tfm_ctx(tfm); | ||
111 | struct dynamic_sa_ctl *sa; | ||
112 | int rc; | ||
113 | |||
114 | if (keylen != AES_KEYSIZE_256 && | ||
115 | keylen != AES_KEYSIZE_192 && keylen != AES_KEYSIZE_128) { | ||
116 | crypto_ablkcipher_set_flags(cipher, | ||
117 | CRYPTO_TFM_RES_BAD_KEY_LEN); | ||
118 | return -EINVAL; | ||
119 | } | ||
120 | |||
121 | /* Create SA */ | ||
122 | if (ctx->sa_in_dma_addr || ctx->sa_out_dma_addr) | ||
123 | crypto4xx_free_sa(ctx); | ||
124 | |||
125 | rc = crypto4xx_alloc_sa(ctx, SA_AES128_LEN + (keylen-16) / 4); | ||
126 | if (rc) | ||
127 | return rc; | ||
128 | |||
129 | if (ctx->state_record_dma_addr == 0) { | ||
130 | rc = crypto4xx_alloc_state_record(ctx); | ||
131 | if (rc) { | ||
132 | crypto4xx_free_sa(ctx); | ||
133 | return rc; | ||
134 | } | ||
135 | } | ||
136 | /* Setup SA */ | ||
137 | sa = (struct dynamic_sa_ctl *) ctx->sa_in; | ||
138 | ctx->hash_final = 0; | ||
139 | |||
140 | set_dynamic_sa_command_0(sa, SA_NOT_SAVE_HASH, SA_NOT_SAVE_IV, | ||
141 | SA_LOAD_HASH_FROM_SA, SA_LOAD_IV_FROM_STATE, | ||
142 | SA_NO_HEADER_PROC, SA_HASH_ALG_NULL, | ||
143 | SA_CIPHER_ALG_AES, SA_PAD_TYPE_ZERO, | ||
144 | SA_OP_GROUP_BASIC, SA_OPCODE_DECRYPT, | ||
145 | DIR_INBOUND); | ||
146 | |||
147 | set_dynamic_sa_command_1(sa, cm, SA_HASH_MODE_HASH, | ||
148 | fb, SA_EXTENDED_SN_OFF, | ||
149 | SA_SEQ_MASK_OFF, SA_MC_ENABLE, | ||
150 | SA_NOT_COPY_PAD, SA_NOT_COPY_PAYLOAD, | ||
151 | SA_NOT_COPY_HDR); | ||
152 | crypto4xx_memcpy_le(ctx->sa_in + get_dynamic_sa_offset_key_field(ctx), | ||
153 | key, keylen); | ||
154 | sa->sa_contents = SA_AES_CONTENTS | (keylen << 2); | ||
155 | sa->sa_command_1.bf.key_len = keylen >> 3; | ||
156 | ctx->is_hash = 0; | ||
157 | ctx->direction = DIR_INBOUND; | ||
158 | memcpy(ctx->sa_in + get_dynamic_sa_offset_state_ptr_field(ctx), | ||
159 | (void *)&ctx->state_record_dma_addr, 4); | ||
160 | ctx->offset_to_sr_ptr = get_dynamic_sa_offset_state_ptr_field(ctx); | ||
161 | |||
162 | memcpy(ctx->sa_out, ctx->sa_in, ctx->sa_len * 4); | ||
163 | sa = (struct dynamic_sa_ctl *) ctx->sa_out; | ||
164 | sa->sa_command_0.bf.dir = DIR_OUTBOUND; | ||
165 | |||
166 | return 0; | ||
167 | } | ||
168 | |||
169 | int crypto4xx_setkey_aes_cbc(struct crypto_ablkcipher *cipher, | ||
170 | const u8 *key, unsigned int keylen) | ||
171 | { | ||
172 | return crypto4xx_setkey_aes(cipher, key, keylen, CRYPTO_MODE_CBC, | ||
173 | CRYPTO_FEEDBACK_MODE_NO_FB); | ||
174 | } | ||
175 | |||
176 | /** | ||
177 | * HASH SHA1 Functions | ||
178 | */ | ||
179 | static int crypto4xx_hash_alg_init(struct crypto_tfm *tfm, | ||
180 | unsigned int sa_len, | ||
181 | unsigned char ha, | ||
182 | unsigned char hm) | ||
183 | { | ||
184 | struct crypto_alg *alg = tfm->__crt_alg; | ||
185 | struct crypto4xx_alg *my_alg = crypto_alg_to_crypto4xx_alg(alg); | ||
186 | struct crypto4xx_ctx *ctx = crypto_tfm_ctx(tfm); | ||
187 | struct dynamic_sa_ctl *sa; | ||
188 | struct dynamic_sa_hash160 *sa_in; | ||
189 | int rc; | ||
190 | |||
191 | ctx->dev = my_alg->dev; | ||
192 | ctx->is_hash = 1; | ||
193 | ctx->hash_final = 0; | ||
194 | |||
195 | /* Create SA */ | ||
196 | if (ctx->sa_in_dma_addr || ctx->sa_out_dma_addr) | ||
197 | crypto4xx_free_sa(ctx); | ||
198 | |||
199 | rc = crypto4xx_alloc_sa(ctx, sa_len); | ||
200 | if (rc) | ||
201 | return rc; | ||
202 | |||
203 | if (ctx->state_record_dma_addr == 0) { | ||
204 | crypto4xx_alloc_state_record(ctx); | ||
205 | if (!ctx->state_record_dma_addr) { | ||
206 | crypto4xx_free_sa(ctx); | ||
207 | return -ENOMEM; | ||
208 | } | ||
209 | } | ||
210 | |||
211 | tfm->crt_ahash.reqsize = sizeof(struct crypto4xx_ctx); | ||
212 | sa = (struct dynamic_sa_ctl *) ctx->sa_in; | ||
213 | set_dynamic_sa_command_0(sa, SA_SAVE_HASH, SA_NOT_SAVE_IV, | ||
214 | SA_NOT_LOAD_HASH, SA_LOAD_IV_FROM_SA, | ||
215 | SA_NO_HEADER_PROC, ha, SA_CIPHER_ALG_NULL, | ||
216 | SA_PAD_TYPE_ZERO, SA_OP_GROUP_BASIC, | ||
217 | SA_OPCODE_HASH, DIR_INBOUND); | ||
218 | set_dynamic_sa_command_1(sa, 0, SA_HASH_MODE_HASH, | ||
219 | CRYPTO_FEEDBACK_MODE_NO_FB, SA_EXTENDED_SN_OFF, | ||
220 | SA_SEQ_MASK_OFF, SA_MC_ENABLE, | ||
221 | SA_NOT_COPY_PAD, SA_NOT_COPY_PAYLOAD, | ||
222 | SA_NOT_COPY_HDR); | ||
223 | ctx->direction = DIR_INBOUND; | ||
224 | sa->sa_contents = SA_HASH160_CONTENTS; | ||
225 | sa_in = (struct dynamic_sa_hash160 *) ctx->sa_in; | ||
226 | /* Need to zero hash digest in SA */ | ||
227 | memset(sa_in->inner_digest, 0, sizeof(sa_in->inner_digest)); | ||
228 | memset(sa_in->outer_digest, 0, sizeof(sa_in->outer_digest)); | ||
229 | sa_in->state_ptr = ctx->state_record_dma_addr; | ||
230 | ctx->offset_to_sr_ptr = get_dynamic_sa_offset_state_ptr_field(ctx); | ||
231 | |||
232 | return 0; | ||
233 | } | ||
234 | |||
235 | int crypto4xx_hash_init(struct ahash_request *req) | ||
236 | { | ||
237 | struct crypto4xx_ctx *ctx = crypto_tfm_ctx(req->base.tfm); | ||
238 | int ds; | ||
239 | struct dynamic_sa_ctl *sa; | ||
240 | |||
241 | sa = (struct dynamic_sa_ctl *) ctx->sa_in; | ||
242 | ds = crypto_ahash_digestsize( | ||
243 | __crypto_ahash_cast(req->base.tfm)); | ||
244 | sa->sa_command_0.bf.digest_len = ds >> 2; | ||
245 | sa->sa_command_0.bf.load_hash_state = SA_LOAD_HASH_FROM_SA; | ||
246 | ctx->is_hash = 1; | ||
247 | ctx->direction = DIR_INBOUND; | ||
248 | |||
249 | return 0; | ||
250 | } | ||
251 | |||
252 | int crypto4xx_hash_update(struct ahash_request *req) | ||
253 | { | ||
254 | struct crypto4xx_ctx *ctx = crypto_tfm_ctx(req->base.tfm); | ||
255 | |||
256 | ctx->is_hash = 1; | ||
257 | ctx->hash_final = 0; | ||
258 | ctx->pd_ctl = 0x11; | ||
259 | ctx->direction = DIR_INBOUND; | ||
260 | |||
261 | return crypto4xx_build_pd(&req->base, ctx, req->src, | ||
262 | (struct scatterlist *) req->result, | ||
263 | req->nbytes, NULL, 0); | ||
264 | } | ||
265 | |||
266 | int crypto4xx_hash_final(struct ahash_request *req) | ||
267 | { | ||
268 | return 0; | ||
269 | } | ||
270 | |||
271 | int crypto4xx_hash_digest(struct ahash_request *req) | ||
272 | { | ||
273 | struct crypto4xx_ctx *ctx = crypto_tfm_ctx(req->base.tfm); | ||
274 | |||
275 | ctx->hash_final = 1; | ||
276 | ctx->pd_ctl = 0x11; | ||
277 | ctx->direction = DIR_INBOUND; | ||
278 | |||
279 | return crypto4xx_build_pd(&req->base, ctx, req->src, | ||
280 | (struct scatterlist *) req->result, | ||
281 | req->nbytes, NULL, 0); | ||
282 | } | ||
283 | |||
284 | /** | ||
285 | * SHA1 Algorithm | ||
286 | */ | ||
287 | int crypto4xx_sha1_alg_init(struct crypto_tfm *tfm) | ||
288 | { | ||
289 | return crypto4xx_hash_alg_init(tfm, SA_HASH160_LEN, SA_HASH_ALG_SHA1, | ||
290 | SA_HASH_MODE_HASH); | ||
291 | } | ||
292 | |||
293 | |||