Initial commit
[wrt350n-kernel.git] / arch / cris / arch-v32 / drivers / cryptocop.c
blob9fb58202be99b8d54d729c161dba9983cc29352d
1 /*
2 * Stream co-processor driver for the ETRAX FS
4 * Copyright (C) 2003-2007 Axis Communications AB
5 */
7 #include <linux/init.h>
8 #include <linux/sched.h>
9 #include <linux/module.h>
10 #include <linux/slab.h>
11 #include <linux/string.h>
12 #include <linux/fs.h>
13 #include <linux/mm.h>
14 #include <linux/spinlock.h>
15 #include <linux/stddef.h>
17 #include <asm/uaccess.h>
18 #include <asm/io.h>
19 #include <asm/atomic.h>
21 #include <linux/list.h>
22 #include <linux/interrupt.h>
24 #include <asm/signal.h>
25 #include <asm/irq.h>
27 #include <dma.h>
28 #include <hwregs/dma.h>
29 #include <hwregs/reg_map.h>
30 #include <hwregs/reg_rdwr.h>
31 #include <hwregs/intr_vect_defs.h>
33 #include <hwregs/strcop.h>
34 #include <hwregs/strcop_defs.h>
35 #include <cryptocop.h>
37 #ifdef CONFIG_ETRAXFS
38 #define IN_DMA 9
39 #define OUT_DMA 8
40 #define IN_DMA_INST regi_dma9
41 #define OUT_DMA_INST regi_dma8
42 #define DMA_IRQ DMA9_INTR_VECT
43 #else
44 #define IN_DMA 3
45 #define OUT_DMA 2
46 #define IN_DMA_INST regi_dma3
47 #define OUT_DMA_INST regi_dma2
48 #define DMA_IRQ DMA3_INTR_VECT
49 #endif
51 #define DESCR_ALLOC_PAD (31)
53 struct cryptocop_dma_desc {
54 char *free_buf; /* If non-null will be kfreed in free_cdesc() */
55 dma_descr_data *dma_descr;
57 unsigned char dma_descr_buf[sizeof(dma_descr_data) + DESCR_ALLOC_PAD];
59 unsigned int from_pool:1; /* If 1 'allocated' from the descriptor pool. */
60 struct cryptocop_dma_desc *next;
64 struct cryptocop_int_operation{
65 void *alloc_ptr;
66 cryptocop_session_id sid;
68 dma_descr_context ctx_out;
69 dma_descr_context ctx_in;
71 /* DMA descriptors allocated by driver. */
72 struct cryptocop_dma_desc *cdesc_out;
73 struct cryptocop_dma_desc *cdesc_in;
75 /* Strcop config to use. */
76 cryptocop_3des_mode tdes_mode;
77 cryptocop_csum_type csum_mode;
79 /* DMA descrs provided by consumer. */
80 dma_descr_data *ddesc_out;
81 dma_descr_data *ddesc_in;
85 struct cryptocop_tfrm_ctx {
86 cryptocop_tfrm_id tid;
87 unsigned int blocklength;
89 unsigned int start_ix;
91 struct cryptocop_tfrm_cfg *tcfg;
92 struct cryptocop_transform_ctx *tctx;
94 unsigned char previous_src;
95 unsigned char current_src;
97 /* Values to use in metadata out. */
98 unsigned char hash_conf;
99 unsigned char hash_mode;
100 unsigned char ciph_conf;
101 unsigned char cbcmode;
102 unsigned char decrypt;
104 unsigned int requires_padding:1;
105 unsigned int strict_block_length:1;
106 unsigned int active:1;
107 unsigned int done:1;
108 size_t consumed;
109 size_t produced;
111 /* Pad (input) descriptors to put in the DMA out list when the transform
112 * output is put on the DMA in list. */
113 struct cryptocop_dma_desc *pad_descs;
115 struct cryptocop_tfrm_ctx *prev_src;
116 struct cryptocop_tfrm_ctx *curr_src;
118 /* Mapping to HW. */
119 unsigned char unit_no;
123 struct cryptocop_private{
124 cryptocop_session_id sid;
125 struct cryptocop_private *next;
128 /* Session list. */
130 struct cryptocop_transform_ctx{
131 struct cryptocop_transform_init init;
132 unsigned char dec_key[CRYPTOCOP_MAX_KEY_LENGTH];
133 unsigned int dec_key_set:1;
135 struct cryptocop_transform_ctx *next;
139 struct cryptocop_session{
140 cryptocop_session_id sid;
142 struct cryptocop_transform_ctx *tfrm_ctx;
144 struct cryptocop_session *next;
147 /* Priority levels for jobs sent to the cryptocop. Checksum operations from
148 kernel have highest priority since TCPIP stack processing must not
149 be a bottleneck. */
150 typedef enum {
151 cryptocop_prio_kernel_csum = 0,
152 cryptocop_prio_kernel = 1,
153 cryptocop_prio_user = 2,
154 cryptocop_prio_no_prios = 3
155 } cryptocop_queue_priority;
157 struct cryptocop_prio_queue{
158 struct list_head jobs;
159 cryptocop_queue_priority prio;
162 struct cryptocop_prio_job{
163 struct list_head node;
164 cryptocop_queue_priority prio;
166 struct cryptocop_operation *oper;
167 struct cryptocop_int_operation *iop;
170 struct ioctl_job_cb_ctx {
171 unsigned int processed:1;
175 static struct cryptocop_session *cryptocop_sessions = NULL;
176 spinlock_t cryptocop_sessions_lock;
178 /* Next Session ID to assign. */
179 static cryptocop_session_id next_sid = 1;
181 /* Pad for checksum. */
182 static const char csum_zero_pad[1] = {0x00};
184 /* Trash buffer for mem2mem operations. */
185 #define MEM2MEM_DISCARD_BUF_LENGTH (512)
186 static unsigned char mem2mem_discard_buf[MEM2MEM_DISCARD_BUF_LENGTH];
188 /* Descriptor pool. */
189 /* FIXME Tweak this value. */
190 #define CRYPTOCOP_DESCRIPTOR_POOL_SIZE (100)
191 static struct cryptocop_dma_desc descr_pool[CRYPTOCOP_DESCRIPTOR_POOL_SIZE];
192 static struct cryptocop_dma_desc *descr_pool_free_list;
193 static int descr_pool_no_free;
194 static spinlock_t descr_pool_lock;
196 /* Lock to stop cryptocop to start processing of a new operation. The holder
197 of this lock MUST call cryptocop_start_job() after it is unlocked. */
198 spinlock_t cryptocop_process_lock;
200 static struct cryptocop_prio_queue cryptocop_job_queues[cryptocop_prio_no_prios];
201 static spinlock_t cryptocop_job_queue_lock;
202 static struct cryptocop_prio_job *cryptocop_running_job = NULL;
203 static spinlock_t running_job_lock;
205 /* The interrupt handler appends completed jobs to this list. The scehduled
206 * tasklet removes them upon sending the response to the crypto consumer. */
207 static struct list_head cryptocop_completed_jobs;
208 static spinlock_t cryptocop_completed_jobs_lock;
210 DECLARE_WAIT_QUEUE_HEAD(cryptocop_ioc_process_wq);
213 /** Local functions. **/
215 static int cryptocop_open(struct inode *, struct file *);
217 static int cryptocop_release(struct inode *, struct file *);
219 static int cryptocop_ioctl(struct inode *inode, struct file *file,
220 unsigned int cmd, unsigned long arg);
222 static void cryptocop_start_job(void);
224 static int cryptocop_job_queue_insert(cryptocop_queue_priority prio, struct cryptocop_operation *operation);
225 static int cryptocop_job_setup(struct cryptocop_prio_job **pj, struct cryptocop_operation *operation);
227 static int cryptocop_job_queue_init(void);
228 static void cryptocop_job_queue_close(void);
230 static int create_md5_pad(int alloc_flag, unsigned long long hashed_length, char **pad, size_t *pad_length);
232 static int create_sha1_pad(int alloc_flag, unsigned long long hashed_length, char **pad, size_t *pad_length);
234 static int transform_ok(struct cryptocop_transform_init *tinit);
236 static struct cryptocop_session *get_session(cryptocop_session_id sid);
238 static struct cryptocop_transform_ctx *get_transform_ctx(struct cryptocop_session *sess, cryptocop_tfrm_id tid);
240 static void delete_internal_operation(struct cryptocop_int_operation *iop);
242 static void get_aes_decrypt_key(unsigned char *dec_key, const unsigned char *key, unsigned int keylength);
244 static int init_stream_coprocessor(void);
246 static void __exit exit_stream_coprocessor(void);
248 /*#define LDEBUG*/
249 #ifdef LDEBUG
250 #define DEBUG(s) s
251 #define DEBUG_API(s) s
252 static void print_cryptocop_operation(struct cryptocop_operation *cop);
253 static void print_dma_descriptors(struct cryptocop_int_operation *iop);
254 static void print_strcop_crypto_op(struct strcop_crypto_op *cop);
255 static void print_lock_status(void);
256 static void print_user_dma_lists(struct cryptocop_dma_list_operation *dma_op);
257 #define assert(s) do{if (!(s)) panic(#s);} while(0);
258 #else
259 #define DEBUG(s)
260 #define DEBUG_API(s)
261 #define assert(s)
262 #endif
265 /* Transform constants. */
266 #define DES_BLOCK_LENGTH (8)
267 #define AES_BLOCK_LENGTH (16)
268 #define MD5_BLOCK_LENGTH (64)
269 #define SHA1_BLOCK_LENGTH (64)
270 #define CSUM_BLOCK_LENGTH (2)
271 #define MD5_STATE_LENGTH (16)
272 #define SHA1_STATE_LENGTH (20)
274 /* The device number. */
275 #define CRYPTOCOP_MAJOR (254)
276 #define CRYPTOCOP_MINOR (0)
280 const struct file_operations cryptocop_fops = {
281 .owner = THIS_MODULE,
282 .open = cryptocop_open,
283 .release = cryptocop_release,
284 .ioctl = cryptocop_ioctl
288 static void free_cdesc(struct cryptocop_dma_desc *cdesc)
290 DEBUG(printk("free_cdesc: cdesc 0x%p, from_pool=%d\n", cdesc, cdesc->from_pool));
291 kfree(cdesc->free_buf);
293 if (cdesc->from_pool) {
294 unsigned long int flags;
295 spin_lock_irqsave(&descr_pool_lock, flags);
296 cdesc->next = descr_pool_free_list;
297 descr_pool_free_list = cdesc;
298 ++descr_pool_no_free;
299 spin_unlock_irqrestore(&descr_pool_lock, flags);
300 } else {
301 kfree(cdesc);
306 static struct cryptocop_dma_desc *alloc_cdesc(int alloc_flag)
308 int use_pool = (alloc_flag & GFP_ATOMIC) ? 1 : 0;
309 struct cryptocop_dma_desc *cdesc;
311 if (use_pool) {
312 unsigned long int flags;
313 spin_lock_irqsave(&descr_pool_lock, flags);
314 if (!descr_pool_free_list) {
315 spin_unlock_irqrestore(&descr_pool_lock, flags);
316 DEBUG_API(printk("alloc_cdesc: pool is empty\n"));
317 return NULL;
319 cdesc = descr_pool_free_list;
320 descr_pool_free_list = descr_pool_free_list->next;
321 --descr_pool_no_free;
322 spin_unlock_irqrestore(&descr_pool_lock, flags);
323 cdesc->from_pool = 1;
324 } else {
325 cdesc = kmalloc(sizeof(struct cryptocop_dma_desc), alloc_flag);
326 if (!cdesc) {
327 DEBUG_API(printk("alloc_cdesc: kmalloc\n"));
328 return NULL;
330 cdesc->from_pool = 0;
332 cdesc->dma_descr = (dma_descr_data*)(((unsigned long int)cdesc + offsetof(struct cryptocop_dma_desc, dma_descr_buf) + DESCR_ALLOC_PAD) & ~0x0000001F);
334 cdesc->next = NULL;
336 cdesc->free_buf = NULL;
337 cdesc->dma_descr->out_eop = 0;
338 cdesc->dma_descr->in_eop = 0;
339 cdesc->dma_descr->intr = 0;
340 cdesc->dma_descr->eol = 0;
341 cdesc->dma_descr->wait = 0;
342 cdesc->dma_descr->buf = NULL;
343 cdesc->dma_descr->after = NULL;
345 DEBUG_API(printk("alloc_cdesc: return 0x%p, cdesc->dma_descr=0x%p, from_pool=%d\n", cdesc, cdesc->dma_descr, cdesc->from_pool));
346 return cdesc;
350 static void setup_descr_chain(struct cryptocop_dma_desc *cd)
352 DEBUG(printk("setup_descr_chain: entering\n"));
353 while (cd) {
354 if (cd->next) {
355 cd->dma_descr->next = (dma_descr_data*)virt_to_phys(cd->next->dma_descr);
356 } else {
357 cd->dma_descr->next = NULL;
359 cd = cd->next;
361 DEBUG(printk("setup_descr_chain: exit\n"));
365 /* Create a pad descriptor for the transform.
366 * Return -1 for error, 0 if pad created. */
367 static int create_pad_descriptor(struct cryptocop_tfrm_ctx *tc, struct cryptocop_dma_desc **pad_desc, int alloc_flag)
369 struct cryptocop_dma_desc *cdesc = NULL;
370 int error = 0;
371 struct strcop_meta_out mo = {
372 .ciphsel = src_none,
373 .hashsel = src_none,
374 .csumsel = src_none
376 char *pad;
377 size_t plen;
379 DEBUG(printk("create_pad_descriptor: start.\n"));
380 /* Setup pad descriptor. */
382 DEBUG(printk("create_pad_descriptor: setting up padding.\n"));
383 cdesc = alloc_cdesc(alloc_flag);
384 if (!cdesc){
385 DEBUG_API(printk("create_pad_descriptor: alloc pad desc\n"));
386 goto error_cleanup;
388 switch (tc->unit_no) {
389 case src_md5:
390 error = create_md5_pad(alloc_flag, tc->consumed, &pad, &plen);
391 if (error){
392 DEBUG_API(printk("create_pad_descriptor: create_md5_pad_failed\n"));
393 goto error_cleanup;
395 cdesc->free_buf = pad;
396 mo.hashsel = src_dma;
397 mo.hashconf = tc->hash_conf;
398 mo.hashmode = tc->hash_mode;
399 break;
400 case src_sha1:
401 error = create_sha1_pad(alloc_flag, tc->consumed, &pad, &plen);
402 if (error){
403 DEBUG_API(printk("create_pad_descriptor: create_sha1_pad_failed\n"));
404 goto error_cleanup;
406 cdesc->free_buf = pad;
407 mo.hashsel = src_dma;
408 mo.hashconf = tc->hash_conf;
409 mo.hashmode = tc->hash_mode;
410 break;
411 case src_csum:
412 if (tc->consumed % tc->blocklength){
413 pad = (char*)csum_zero_pad;
414 plen = 1;
415 } else {
416 pad = (char*)cdesc; /* Use any pointer. */
417 plen = 0;
419 mo.csumsel = src_dma;
420 break;
422 cdesc->dma_descr->wait = 1;
423 cdesc->dma_descr->out_eop = 1; /* Since this is a pad output is pushed. EOP is ok here since the padded unit is the only one active. */
424 cdesc->dma_descr->buf = (char*)virt_to_phys((char*)pad);
425 cdesc->dma_descr->after = cdesc->dma_descr->buf + plen;
427 cdesc->dma_descr->md = REG_TYPE_CONV(unsigned short int, struct strcop_meta_out, mo);
428 *pad_desc = cdesc;
430 return 0;
432 error_cleanup:
433 if (cdesc) free_cdesc(cdesc);
434 return -1;
438 static int setup_key_dl_desc(struct cryptocop_tfrm_ctx *tc, struct cryptocop_dma_desc **kd, int alloc_flag)
440 struct cryptocop_dma_desc *key_desc = alloc_cdesc(alloc_flag);
441 struct strcop_meta_out mo = {0};
443 DEBUG(printk("setup_key_dl_desc\n"));
445 if (!key_desc) {
446 DEBUG_API(printk("setup_key_dl_desc: failed descriptor allocation.\n"));
447 return -ENOMEM;
450 /* Download key. */
451 if ((tc->tctx->init.alg == cryptocop_alg_aes) && (tc->tcfg->flags & CRYPTOCOP_DECRYPT)) {
452 /* Precook the AES decrypt key. */
453 if (!tc->tctx->dec_key_set){
454 get_aes_decrypt_key(tc->tctx->dec_key, tc->tctx->init.key, tc->tctx->init.keylen);
455 tc->tctx->dec_key_set = 1;
457 key_desc->dma_descr->buf = (char*)virt_to_phys(tc->tctx->dec_key);
458 key_desc->dma_descr->after = key_desc->dma_descr->buf + tc->tctx->init.keylen/8;
459 } else {
460 key_desc->dma_descr->buf = (char*)virt_to_phys(tc->tctx->init.key);
461 key_desc->dma_descr->after = key_desc->dma_descr->buf + tc->tctx->init.keylen/8;
463 /* Setup metadata. */
464 mo.dlkey = 1;
465 switch (tc->tctx->init.keylen) {
466 case 64:
467 mo.decrypt = 0;
468 mo.hashmode = 0;
469 break;
470 case 128:
471 mo.decrypt = 0;
472 mo.hashmode = 1;
473 break;
474 case 192:
475 mo.decrypt = 1;
476 mo.hashmode = 0;
477 break;
478 case 256:
479 mo.decrypt = 1;
480 mo.hashmode = 1;
481 break;
482 default:
483 break;
485 mo.ciphsel = mo.hashsel = mo.csumsel = src_none;
486 key_desc->dma_descr->md = REG_TYPE_CONV(unsigned short int, struct strcop_meta_out, mo);
488 key_desc->dma_descr->out_eop = 1;
489 key_desc->dma_descr->wait = 1;
490 key_desc->dma_descr->intr = 0;
492 *kd = key_desc;
493 return 0;
496 static int setup_cipher_iv_desc(struct cryptocop_tfrm_ctx *tc, struct cryptocop_dma_desc **id, int alloc_flag)
498 struct cryptocop_dma_desc *iv_desc = alloc_cdesc(alloc_flag);
499 struct strcop_meta_out mo = {0};
501 DEBUG(printk("setup_cipher_iv_desc\n"));
503 if (!iv_desc) {
504 DEBUG_API(printk("setup_cipher_iv_desc: failed CBC IV descriptor allocation.\n"));
505 return -ENOMEM;
507 /* Download IV. */
508 iv_desc->dma_descr->buf = (char*)virt_to_phys(tc->tcfg->iv);
509 iv_desc->dma_descr->after = iv_desc->dma_descr->buf + tc->blocklength;
511 /* Setup metadata. */
512 mo.hashsel = mo.csumsel = src_none;
513 mo.ciphsel = src_dma;
514 mo.ciphconf = tc->ciph_conf;
515 mo.cbcmode = tc->cbcmode;
517 iv_desc->dma_descr->md = REG_TYPE_CONV(unsigned short int, struct strcop_meta_out, mo);
519 iv_desc->dma_descr->out_eop = 0;
520 iv_desc->dma_descr->wait = 1;
521 iv_desc->dma_descr->intr = 0;
523 *id = iv_desc;
524 return 0;
527 /* Map the ouput length of the transform to operation output starting on the inject index. */
528 static int create_input_descriptors(struct cryptocop_operation *operation, struct cryptocop_tfrm_ctx *tc, struct cryptocop_dma_desc **id, int alloc_flag)
530 int err = 0;
531 struct cryptocop_dma_desc head = {0};
532 struct cryptocop_dma_desc *outdesc = &head;
533 size_t iov_offset = 0;
534 size_t out_ix = 0;
535 int outiov_ix = 0;
536 struct strcop_meta_in mi = {0};
538 size_t out_length = tc->produced;
539 int rem_length;
540 int dlength;
542 assert(out_length != 0);
543 if (((tc->produced + tc->tcfg->inject_ix) > operation->tfrm_op.outlen) || (tc->produced && (operation->tfrm_op.outlen == 0))) {
544 DEBUG_API(printk("create_input_descriptors: operation outdata too small\n"));
545 return -EINVAL;
547 /* Traverse the out iovec until the result inject index is reached. */
548 while ((outiov_ix < operation->tfrm_op.outcount) && ((out_ix + operation->tfrm_op.outdata[outiov_ix].iov_len) <= tc->tcfg->inject_ix)){
549 out_ix += operation->tfrm_op.outdata[outiov_ix].iov_len;
550 outiov_ix++;
552 if (outiov_ix >= operation->tfrm_op.outcount){
553 DEBUG_API(printk("create_input_descriptors: operation outdata too small\n"));
554 return -EINVAL;
556 iov_offset = tc->tcfg->inject_ix - out_ix;
557 mi.dmasel = tc->unit_no;
559 /* Setup the output descriptors. */
560 while ((out_length > 0) && (outiov_ix < operation->tfrm_op.outcount)) {
561 outdesc->next = alloc_cdesc(alloc_flag);
562 if (!outdesc->next) {
563 DEBUG_API(printk("create_input_descriptors: alloc_cdesc\n"));
564 err = -ENOMEM;
565 goto error_cleanup;
567 outdesc = outdesc->next;
568 rem_length = operation->tfrm_op.outdata[outiov_ix].iov_len - iov_offset;
569 dlength = (out_length < rem_length) ? out_length : rem_length;
571 DEBUG(printk("create_input_descriptors:\n"
572 "outiov_ix=%d, rem_length=%d, dlength=%d\n"
573 "iov_offset=%d, outdata[outiov_ix].iov_len=%d\n"
574 "outcount=%d, outiov_ix=%d\n",
575 outiov_ix, rem_length, dlength, iov_offset, operation->tfrm_op.outdata[outiov_ix].iov_len, operation->tfrm_op.outcount, outiov_ix));
577 outdesc->dma_descr->buf = (char*)virt_to_phys(operation->tfrm_op.outdata[outiov_ix].iov_base + iov_offset);
578 outdesc->dma_descr->after = outdesc->dma_descr->buf + dlength;
579 outdesc->dma_descr->md = REG_TYPE_CONV(unsigned short int, struct strcop_meta_in, mi);
581 out_length -= dlength;
582 iov_offset += dlength;
583 if (iov_offset >= operation->tfrm_op.outdata[outiov_ix].iov_len) {
584 iov_offset = 0;
585 ++outiov_ix;
588 if (out_length > 0){
589 DEBUG_API(printk("create_input_descriptors: not enough room for output, %d remained\n", out_length));
590 err = -EINVAL;
591 goto error_cleanup;
593 /* Set sync in last descriptor. */
594 mi.sync = 1;
595 outdesc->dma_descr->md = REG_TYPE_CONV(unsigned short int, struct strcop_meta_in, mi);
597 *id = head.next;
598 return 0;
600 error_cleanup:
601 while (head.next) {
602 outdesc = head.next->next;
603 free_cdesc(head.next);
604 head.next = outdesc;
606 return err;
610 static int create_output_descriptors(struct cryptocop_operation *operation, int *iniov_ix, int *iniov_offset, size_t desc_len, struct cryptocop_dma_desc **current_out_cdesc, struct strcop_meta_out *meta_out, int alloc_flag)
612 while (desc_len != 0) {
613 struct cryptocop_dma_desc *cdesc;
614 int rem_length = operation->tfrm_op.indata[*iniov_ix].iov_len - *iniov_offset;
615 int dlength = (desc_len < rem_length) ? desc_len : rem_length;
617 cdesc = alloc_cdesc(alloc_flag);
618 if (!cdesc) {
619 DEBUG_API(printk("create_output_descriptors: alloc_cdesc\n"));
620 return -ENOMEM;
622 (*current_out_cdesc)->next = cdesc;
623 (*current_out_cdesc) = cdesc;
625 cdesc->free_buf = NULL;
627 cdesc->dma_descr->buf = (char*)virt_to_phys(operation->tfrm_op.indata[*iniov_ix].iov_base + *iniov_offset);
628 cdesc->dma_descr->after = cdesc->dma_descr->buf + dlength;
630 desc_len -= dlength;
631 *iniov_offset += dlength;
632 assert(desc_len >= 0);
633 if (*iniov_offset >= operation->tfrm_op.indata[*iniov_ix].iov_len) {
634 *iniov_offset = 0;
635 ++(*iniov_ix);
636 if (*iniov_ix > operation->tfrm_op.incount) {
637 DEBUG_API(printk("create_output_descriptors: not enough indata in operation."));
638 return -EINVAL;
641 cdesc->dma_descr->md = REG_TYPE_CONV(unsigned short int, struct strcop_meta_out, (*meta_out));
642 } /* while (desc_len != 0) */
643 /* Last DMA descriptor gets a 'wait' bit to signal expected change in metadata. */
644 (*current_out_cdesc)->dma_descr->wait = 1; /* This will set extraneous WAIT in some situations, e.g. when padding hashes and checksums. */
646 return 0;
650 static int append_input_descriptors(struct cryptocop_operation *operation, struct cryptocop_dma_desc **current_in_cdesc, struct cryptocop_dma_desc **current_out_cdesc, struct cryptocop_tfrm_ctx *tc, int alloc_flag)
652 DEBUG(printk("append_input_descriptors, tc=0x%p, unit_no=%d\n", tc, tc->unit_no));
653 if (tc->tcfg) {
654 int failed = 0;
655 struct cryptocop_dma_desc *idescs = NULL;
656 DEBUG(printk("append_input_descriptors: pushing output, consumed %d produced %d bytes.\n", tc->consumed, tc->produced));
657 if (tc->pad_descs) {
658 DEBUG(printk("append_input_descriptors: append pad descriptors to DMA out list.\n"));
659 while (tc->pad_descs) {
660 DEBUG(printk("append descriptor 0x%p\n", tc->pad_descs));
661 (*current_out_cdesc)->next = tc->pad_descs;
662 tc->pad_descs = tc->pad_descs->next;
663 (*current_out_cdesc) = (*current_out_cdesc)->next;
667 /* Setup and append output descriptors to DMA in list. */
668 if (tc->unit_no == src_dma){
669 /* mem2mem. Setup DMA in descriptors to discard all input prior to the requested mem2mem data. */
670 struct strcop_meta_in mi = {.sync = 0, .dmasel = src_dma};
671 unsigned int start_ix = tc->start_ix;
672 while (start_ix){
673 unsigned int desclen = start_ix < MEM2MEM_DISCARD_BUF_LENGTH ? start_ix : MEM2MEM_DISCARD_BUF_LENGTH;
674 (*current_in_cdesc)->next = alloc_cdesc(alloc_flag);
675 if (!(*current_in_cdesc)->next){
676 DEBUG_API(printk("append_input_descriptors: alloc_cdesc mem2mem discard failed\n"));
677 return -ENOMEM;
679 (*current_in_cdesc) = (*current_in_cdesc)->next;
680 (*current_in_cdesc)->dma_descr->buf = (char*)virt_to_phys(mem2mem_discard_buf);
681 (*current_in_cdesc)->dma_descr->after = (*current_in_cdesc)->dma_descr->buf + desclen;
682 (*current_in_cdesc)->dma_descr->md = REG_TYPE_CONV(unsigned short int, struct strcop_meta_in, mi);
683 start_ix -= desclen;
685 mi.sync = 1;
686 (*current_in_cdesc)->dma_descr->md = REG_TYPE_CONV(unsigned short int, struct strcop_meta_in, mi);
689 failed = create_input_descriptors(operation, tc, &idescs, alloc_flag);
690 if (failed){
691 DEBUG_API(printk("append_input_descriptors: output descriptor setup failed\n"));
692 return failed;
694 DEBUG(printk("append_input_descriptors: append output descriptors to DMA in list.\n"));
695 while (idescs) {
696 DEBUG(printk("append descriptor 0x%p\n", idescs));
697 (*current_in_cdesc)->next = idescs;
698 idescs = idescs->next;
699 (*current_in_cdesc) = (*current_in_cdesc)->next;
702 return 0;
707 static int cryptocop_setup_dma_list(struct cryptocop_operation *operation, struct cryptocop_int_operation **int_op, int alloc_flag)
709 struct cryptocop_session *sess;
710 struct cryptocop_transform_ctx *tctx;
712 struct cryptocop_tfrm_ctx digest_ctx = {
713 .previous_src = src_none,
714 .current_src = src_none,
715 .start_ix = 0,
716 .requires_padding = 1,
717 .strict_block_length = 0,
718 .hash_conf = 0,
719 .hash_mode = 0,
720 .ciph_conf = 0,
721 .cbcmode = 0,
722 .decrypt = 0,
723 .consumed = 0,
724 .produced = 0,
725 .pad_descs = NULL,
726 .active = 0,
727 .done = 0,
728 .prev_src = NULL,
729 .curr_src = NULL,
730 .tcfg = NULL};
731 struct cryptocop_tfrm_ctx cipher_ctx = {
732 .previous_src = src_none,
733 .current_src = src_none,
734 .start_ix = 0,
735 .requires_padding = 0,
736 .strict_block_length = 1,
737 .hash_conf = 0,
738 .hash_mode = 0,
739 .ciph_conf = 0,
740 .cbcmode = 0,
741 .decrypt = 0,
742 .consumed = 0,
743 .produced = 0,
744 .pad_descs = NULL,
745 .active = 0,
746 .done = 0,
747 .prev_src = NULL,
748 .curr_src = NULL,
749 .tcfg = NULL};
750 struct cryptocop_tfrm_ctx csum_ctx = {
751 .previous_src = src_none,
752 .current_src = src_none,
753 .start_ix = 0,
754 .blocklength = 2,
755 .requires_padding = 1,
756 .strict_block_length = 0,
757 .hash_conf = 0,
758 .hash_mode = 0,
759 .ciph_conf = 0,
760 .cbcmode = 0,
761 .decrypt = 0,
762 .consumed = 0,
763 .produced = 0,
764 .pad_descs = NULL,
765 .active = 0,
766 .done = 0,
767 .tcfg = NULL,
768 .prev_src = NULL,
769 .curr_src = NULL,
770 .unit_no = src_csum};
771 struct cryptocop_tfrm_cfg *tcfg = operation->tfrm_op.tfrm_cfg;
773 unsigned int indata_ix = 0;
775 /* iovec accounting. */
776 int iniov_ix = 0;
777 int iniov_offset = 0;
779 /* Operation descriptor cfg traversal pointer. */
780 struct cryptocop_desc *odsc;
782 int failed = 0;
783 /* List heads for allocated descriptors. */
784 struct cryptocop_dma_desc out_cdesc_head = {0};
785 struct cryptocop_dma_desc in_cdesc_head = {0};
787 struct cryptocop_dma_desc *current_out_cdesc = &out_cdesc_head;
788 struct cryptocop_dma_desc *current_in_cdesc = &in_cdesc_head;
790 struct cryptocop_tfrm_ctx *output_tc = NULL;
791 void *iop_alloc_ptr;
793 assert(operation != NULL);
794 assert(int_op != NULL);
796 DEBUG(printk("cryptocop_setup_dma_list: start\n"));
797 DEBUG(print_cryptocop_operation(operation));
799 sess = get_session(operation->sid);
800 if (!sess) {
801 DEBUG_API(printk("cryptocop_setup_dma_list: no session found for operation.\n"));
802 failed = -EINVAL;
803 goto error_cleanup;
805 iop_alloc_ptr = kmalloc(DESCR_ALLOC_PAD + sizeof(struct cryptocop_int_operation), alloc_flag);
806 if (!iop_alloc_ptr) {
807 DEBUG_API(printk("cryptocop_setup_dma_list: kmalloc cryptocop_int_operation\n"));
808 failed = -ENOMEM;
809 goto error_cleanup;
811 (*int_op) = (struct cryptocop_int_operation*)(((unsigned long int)(iop_alloc_ptr + DESCR_ALLOC_PAD + offsetof(struct cryptocop_int_operation, ctx_out)) & ~0x0000001F) - offsetof(struct cryptocop_int_operation, ctx_out));
812 DEBUG(memset((*int_op), 0xff, sizeof(struct cryptocop_int_operation)));
813 (*int_op)->alloc_ptr = iop_alloc_ptr;
814 DEBUG(printk("cryptocop_setup_dma_list: *int_op=0x%p, alloc_ptr=0x%p\n", *int_op, (*int_op)->alloc_ptr));
816 (*int_op)->sid = operation->sid;
817 (*int_op)->cdesc_out = NULL;
818 (*int_op)->cdesc_in = NULL;
819 (*int_op)->tdes_mode = cryptocop_3des_ede;
820 (*int_op)->csum_mode = cryptocop_csum_le;
821 (*int_op)->ddesc_out = NULL;
822 (*int_op)->ddesc_in = NULL;
824 /* Scan operation->tfrm_op.tfrm_cfg for bad configuration and set up the local contexts. */
825 if (!tcfg) {
826 DEBUG_API(printk("cryptocop_setup_dma_list: no configured transforms in operation.\n"));
827 failed = -EINVAL;
828 goto error_cleanup;
830 while (tcfg) {
831 tctx = get_transform_ctx(sess, tcfg->tid);
832 if (!tctx) {
833 DEBUG_API(printk("cryptocop_setup_dma_list: no transform id %d in session.\n", tcfg->tid));
834 failed = -EINVAL;
835 goto error_cleanup;
837 if (tcfg->inject_ix > operation->tfrm_op.outlen){
838 DEBUG_API(printk("cryptocop_setup_dma_list: transform id %d inject_ix (%d) > operation->tfrm_op.outlen(%d)", tcfg->tid, tcfg->inject_ix, operation->tfrm_op.outlen));
839 failed = -EINVAL;
840 goto error_cleanup;
842 switch (tctx->init.alg){
843 case cryptocop_alg_mem2mem:
844 if (cipher_ctx.tcfg != NULL){
845 DEBUG_API(printk("cryptocop_setup_dma_list: multiple ciphers in operation.\n"));
846 failed = -EINVAL;
847 goto error_cleanup;
849 /* mem2mem is handled as a NULL cipher. */
850 cipher_ctx.cbcmode = 0;
851 cipher_ctx.decrypt = 0;
852 cipher_ctx.blocklength = 1;
853 cipher_ctx.ciph_conf = 0;
854 cipher_ctx.unit_no = src_dma;
855 cipher_ctx.tcfg = tcfg;
856 cipher_ctx.tctx = tctx;
857 break;
858 case cryptocop_alg_des:
859 case cryptocop_alg_3des:
860 case cryptocop_alg_aes:
861 /* cipher */
862 if (cipher_ctx.tcfg != NULL){
863 DEBUG_API(printk("cryptocop_setup_dma_list: multiple ciphers in operation.\n"));
864 failed = -EINVAL;
865 goto error_cleanup;
867 cipher_ctx.tcfg = tcfg;
868 cipher_ctx.tctx = tctx;
869 if (cipher_ctx.tcfg->flags & CRYPTOCOP_DECRYPT){
870 cipher_ctx.decrypt = 1;
872 switch (tctx->init.cipher_mode) {
873 case cryptocop_cipher_mode_ecb:
874 cipher_ctx.cbcmode = 0;
875 break;
876 case cryptocop_cipher_mode_cbc:
877 cipher_ctx.cbcmode = 1;
878 break;
879 default:
880 DEBUG_API(printk("cryptocop_setup_dma_list: cipher_ctx, bad cipher mode==%d\n", tctx->init.cipher_mode));
881 failed = -EINVAL;
882 goto error_cleanup;
884 DEBUG(printk("cryptocop_setup_dma_list: cipher_ctx, set CBC mode==%d\n", cipher_ctx.cbcmode));
885 switch (tctx->init.alg){
886 case cryptocop_alg_des:
887 cipher_ctx.ciph_conf = 0;
888 cipher_ctx.unit_no = src_des;
889 cipher_ctx.blocklength = DES_BLOCK_LENGTH;
890 break;
891 case cryptocop_alg_3des:
892 cipher_ctx.ciph_conf = 1;
893 cipher_ctx.unit_no = src_des;
894 cipher_ctx.blocklength = DES_BLOCK_LENGTH;
895 break;
896 case cryptocop_alg_aes:
897 cipher_ctx.ciph_conf = 2;
898 cipher_ctx.unit_no = src_aes;
899 cipher_ctx.blocklength = AES_BLOCK_LENGTH;
900 break;
901 default:
902 panic("cryptocop_setup_dma_list: impossible algorithm %d\n", tctx->init.alg);
904 (*int_op)->tdes_mode = tctx->init.tdes_mode;
905 break;
906 case cryptocop_alg_md5:
907 case cryptocop_alg_sha1:
908 /* digest */
909 if (digest_ctx.tcfg != NULL){
910 DEBUG_API(printk("cryptocop_setup_dma_list: multiple digests in operation.\n"));
911 failed = -EINVAL;
912 goto error_cleanup;
914 digest_ctx.tcfg = tcfg;
915 digest_ctx.tctx = tctx;
916 digest_ctx.hash_mode = 0; /* Don't use explicit IV in this API. */
917 switch (tctx->init.alg){
918 case cryptocop_alg_md5:
919 digest_ctx.blocklength = MD5_BLOCK_LENGTH;
920 digest_ctx.unit_no = src_md5;
921 digest_ctx.hash_conf = 1; /* 1 => MD-5 */
922 break;
923 case cryptocop_alg_sha1:
924 digest_ctx.blocklength = SHA1_BLOCK_LENGTH;
925 digest_ctx.unit_no = src_sha1;
926 digest_ctx.hash_conf = 0; /* 0 => SHA-1 */
927 break;
928 default:
929 panic("cryptocop_setup_dma_list: impossible digest algorithm\n");
931 break;
932 case cryptocop_alg_csum:
933 /* digest */
934 if (csum_ctx.tcfg != NULL){
935 DEBUG_API(printk("cryptocop_setup_dma_list: multiple checksums in operation.\n"));
936 failed = -EINVAL;
937 goto error_cleanup;
939 (*int_op)->csum_mode = tctx->init.csum_mode;
940 csum_ctx.tcfg = tcfg;
941 csum_ctx.tctx = tctx;
942 break;
943 default:
944 /* no algorithm. */
945 DEBUG_API(printk("cryptocop_setup_dma_list: invalid algorithm %d specified in tfrm %d.\n", tctx->init.alg, tcfg->tid));
946 failed = -EINVAL;
947 goto error_cleanup;
949 tcfg = tcfg->next;
951 /* Download key if a cipher is used. */
952 if (cipher_ctx.tcfg && (cipher_ctx.tctx->init.alg != cryptocop_alg_mem2mem)){
953 struct cryptocop_dma_desc *key_desc = NULL;
955 failed = setup_key_dl_desc(&cipher_ctx, &key_desc, alloc_flag);
956 if (failed) {
957 DEBUG_API(printk("cryptocop_setup_dma_list: setup key dl\n"));
958 goto error_cleanup;
960 current_out_cdesc->next = key_desc;
961 current_out_cdesc = key_desc;
962 indata_ix += (unsigned int)(key_desc->dma_descr->after - key_desc->dma_descr->buf);
964 /* Download explicit IV if a cipher is used and CBC mode and explicit IV selected. */
965 if ((cipher_ctx.tctx->init.cipher_mode == cryptocop_cipher_mode_cbc) && (cipher_ctx.tcfg->flags & CRYPTOCOP_EXPLICIT_IV)) {
966 struct cryptocop_dma_desc *iv_desc = NULL;
968 DEBUG(printk("cryptocop_setup_dma_list: setup cipher CBC IV descriptor.\n"));
970 failed = setup_cipher_iv_desc(&cipher_ctx, &iv_desc, alloc_flag);
971 if (failed) {
972 DEBUG_API(printk("cryptocop_setup_dma_list: CBC IV descriptor.\n"));
973 goto error_cleanup;
975 current_out_cdesc->next = iv_desc;
976 current_out_cdesc = iv_desc;
977 indata_ix += (unsigned int)(iv_desc->dma_descr->after - iv_desc->dma_descr->buf);
981 /* Process descriptors. */
982 odsc = operation->tfrm_op.desc;
983 while (odsc) {
984 struct cryptocop_desc_cfg *dcfg = odsc->cfg;
985 struct strcop_meta_out meta_out = {0};
986 size_t desc_len = odsc->length;
987 int active_count, eop_needed_count;
989 output_tc = NULL;
991 DEBUG(printk("cryptocop_setup_dma_list: parsing an operation descriptor\n"));
993 while (dcfg) {
994 struct cryptocop_tfrm_ctx *tc = NULL;
996 DEBUG(printk("cryptocop_setup_dma_list: parsing an operation descriptor configuration.\n"));
997 /* Get the local context for the transform and mark it as the output unit if it produces output. */
998 if (digest_ctx.tcfg && (digest_ctx.tcfg->tid == dcfg->tid)){
999 tc = &digest_ctx;
1000 } else if (cipher_ctx.tcfg && (cipher_ctx.tcfg->tid == dcfg->tid)){
1001 tc = &cipher_ctx;
1002 } else if (csum_ctx.tcfg && (csum_ctx.tcfg->tid == dcfg->tid)){
1003 tc = &csum_ctx;
1005 if (!tc) {
1006 DEBUG_API(printk("cryptocop_setup_dma_list: invalid transform %d specified in descriptor.\n", dcfg->tid));
1007 failed = -EINVAL;
1008 goto error_cleanup;
1010 if (tc->done) {
1011 DEBUG_API(printk("cryptocop_setup_dma_list: completed transform %d reused.\n", dcfg->tid));
1012 failed = -EINVAL;
1013 goto error_cleanup;
1015 if (!tc->active) {
1016 tc->start_ix = indata_ix;
1017 tc->active = 1;
1020 tc->previous_src = tc->current_src;
1021 tc->prev_src = tc->curr_src;
1022 /* Map source unit id to DMA source config. */
1023 switch (dcfg->src){
1024 case cryptocop_source_dma:
1025 tc->current_src = src_dma;
1026 break;
1027 case cryptocop_source_des:
1028 tc->current_src = src_des;
1029 break;
1030 case cryptocop_source_3des:
1031 tc->current_src = src_des;
1032 break;
1033 case cryptocop_source_aes:
1034 tc->current_src = src_aes;
1035 break;
1036 case cryptocop_source_md5:
1037 case cryptocop_source_sha1:
1038 case cryptocop_source_csum:
1039 case cryptocop_source_none:
1040 default:
1041 /* We do not allow using accumulating style units (SHA-1, MD5, checksum) as sources to other units.
1043 DEBUG_API(printk("cryptocop_setup_dma_list: bad unit source configured %d.\n", dcfg->src));
1044 failed = -EINVAL;
1045 goto error_cleanup;
1047 if (tc->current_src != src_dma) {
1048 /* Find the unit we are sourcing from. */
1049 if (digest_ctx.unit_no == tc->current_src){
1050 tc->curr_src = &digest_ctx;
1051 } else if (cipher_ctx.unit_no == tc->current_src){
1052 tc->curr_src = &cipher_ctx;
1053 } else if (csum_ctx.unit_no == tc->current_src){
1054 tc->curr_src = &csum_ctx;
1056 if ((tc->curr_src == tc) && (tc->unit_no != src_dma)){
1057 DEBUG_API(printk("cryptocop_setup_dma_list: unit %d configured to source from itself.\n", tc->unit_no));
1058 failed = -EINVAL;
1059 goto error_cleanup;
1061 } else {
1062 tc->curr_src = NULL;
1065 /* Detect source switch. */
1066 DEBUG(printk("cryptocop_setup_dma_list: tc->active=%d tc->unit_no=%d tc->current_src=%d tc->previous_src=%d, tc->curr_src=0x%p, tc->prev_srv=0x%p\n", tc->active, tc->unit_no, tc->current_src, tc->previous_src, tc->curr_src, tc->prev_src));
1067 if (tc->active && (tc->current_src != tc->previous_src)) {
1068 /* Only allow source switch when both the old source unit and the new one have
1069 * no pending data to process (i.e. the consumed length must be a multiple of the
1070 * transform blocklength). */
1071 /* Note: if the src == NULL we are actually sourcing from DMA out. */
1072 if (((tc->prev_src != NULL) && (tc->prev_src->consumed % tc->prev_src->blocklength)) ||
1073 ((tc->curr_src != NULL) && (tc->curr_src->consumed % tc->curr_src->blocklength)))
1075 DEBUG_API(printk("cryptocop_setup_dma_list: can only disconnect from or connect to a unit on a multiple of the blocklength, old: cons=%d, prod=%d, block=%d, new: cons=%d prod=%d, block=%d.\n", tc->prev_src ? tc->prev_src->consumed : INT_MIN, tc->prev_src ? tc->prev_src->produced : INT_MIN, tc->prev_src ? tc->prev_src->blocklength : INT_MIN, tc->curr_src ? tc->curr_src->consumed : INT_MIN, tc->curr_src ? tc->curr_src->produced : INT_MIN, tc->curr_src ? tc->curr_src->blocklength : INT_MIN));
1076 failed = -EINVAL;
1077 goto error_cleanup;
1080 /* Detect unit deactivation. */
1081 if (dcfg->last) {
1082 /* Length check of this is handled below. */
1083 tc->done = 1;
1085 dcfg = dcfg->next;
1086 } /* while (dcfg) */
1087 DEBUG(printk("cryptocop_setup_dma_list: parsing operation descriptor configuration complete.\n"));
1089 if (cipher_ctx.active && (cipher_ctx.curr_src != NULL) && !cipher_ctx.curr_src->active){
1090 DEBUG_API(printk("cryptocop_setup_dma_list: cipher source from inactive unit %d\n", cipher_ctx.curr_src->unit_no));
1091 failed = -EINVAL;
1092 goto error_cleanup;
1094 if (digest_ctx.active && (digest_ctx.curr_src != NULL) && !digest_ctx.curr_src->active){
1095 DEBUG_API(printk("cryptocop_setup_dma_list: digest source from inactive unit %d\n", digest_ctx.curr_src->unit_no));
1096 failed = -EINVAL;
1097 goto error_cleanup;
1099 if (csum_ctx.active && (csum_ctx.curr_src != NULL) && !csum_ctx.curr_src->active){
1100 DEBUG_API(printk("cryptocop_setup_dma_list: cipher source from inactive unit %d\n", csum_ctx.curr_src->unit_no));
1101 failed = -EINVAL;
1102 goto error_cleanup;
1105 /* Update consumed and produced lengths.
1107 The consumed length accounting here is actually cheating. If a unit source from DMA (or any
1108 other unit that process data in blocks of one octet) it is correct, but if it source from a
1109 block processing unit, i.e. a cipher, it will be temporarily incorrect at some times. However
1110 since it is only allowed--by the HW--to change source to or from a block processing unit at times where that
1111 unit has processed an exact multiple of its block length the end result will be correct.
1112 Beware that if the source change restriction change this code will need to be (much) reworked.
1114 DEBUG(printk("cryptocop_setup_dma_list: desc->length=%d, desc_len=%d.\n", odsc->length, desc_len));
1116 if (csum_ctx.active) {
1117 csum_ctx.consumed += desc_len;
1118 if (csum_ctx.done) {
1119 csum_ctx.produced = 2;
1121 DEBUG(printk("cryptocop_setup_dma_list: csum_ctx producing: consumed=%d, produced=%d, blocklength=%d.\n", csum_ctx.consumed, csum_ctx.produced, csum_ctx.blocklength));
1123 if (digest_ctx.active) {
1124 digest_ctx.consumed += desc_len;
1125 if (digest_ctx.done) {
1126 if (digest_ctx.unit_no == src_md5) {
1127 digest_ctx.produced = MD5_STATE_LENGTH;
1128 } else {
1129 digest_ctx.produced = SHA1_STATE_LENGTH;
1132 DEBUG(printk("cryptocop_setup_dma_list: digest_ctx producing: consumed=%d, produced=%d, blocklength=%d.\n", digest_ctx.consumed, digest_ctx.produced, digest_ctx.blocklength));
1134 if (cipher_ctx.active) {
1135 /* Ciphers are allowed only to source from DMA out. That is filtered above. */
1136 assert(cipher_ctx.current_src == src_dma);
1137 cipher_ctx.consumed += desc_len;
1138 cipher_ctx.produced = cipher_ctx.blocklength * (cipher_ctx.consumed / cipher_ctx.blocklength);
1139 if (cipher_ctx.cbcmode && !(cipher_ctx.tcfg->flags & CRYPTOCOP_EXPLICIT_IV) && cipher_ctx.produced){
1140 cipher_ctx.produced -= cipher_ctx.blocklength; /* Compensate for CBC iv. */
1142 DEBUG(printk("cryptocop_setup_dma_list: cipher_ctx producing: consumed=%d, produced=%d, blocklength=%d.\n", cipher_ctx.consumed, cipher_ctx.produced, cipher_ctx.blocklength));
1145 /* Setup the DMA out descriptors. */
1146 /* Configure the metadata. */
1147 active_count = 0;
1148 eop_needed_count = 0;
1149 if (cipher_ctx.active) {
1150 ++active_count;
1151 if (cipher_ctx.unit_no == src_dma){
1152 /* mem2mem */
1153 meta_out.ciphsel = src_none;
1154 } else {
1155 meta_out.ciphsel = cipher_ctx.current_src;
1157 meta_out.ciphconf = cipher_ctx.ciph_conf;
1158 meta_out.cbcmode = cipher_ctx.cbcmode;
1159 meta_out.decrypt = cipher_ctx.decrypt;
1160 DEBUG(printk("set ciphsel=%d ciphconf=%d cbcmode=%d decrypt=%d\n", meta_out.ciphsel, meta_out.ciphconf, meta_out.cbcmode, meta_out.decrypt));
1161 if (cipher_ctx.done) ++eop_needed_count;
1162 } else {
1163 meta_out.ciphsel = src_none;
1166 if (digest_ctx.active) {
1167 ++active_count;
1168 meta_out.hashsel = digest_ctx.current_src;
1169 meta_out.hashconf = digest_ctx.hash_conf;
1170 meta_out.hashmode = 0; /* Explicit mode is not used here. */
1171 DEBUG(printk("set hashsel=%d hashconf=%d hashmode=%d\n", meta_out.hashsel, meta_out.hashconf, meta_out.hashmode));
1172 if (digest_ctx.done) {
1173 assert(digest_ctx.pad_descs == NULL);
1174 failed = create_pad_descriptor(&digest_ctx, &digest_ctx.pad_descs, alloc_flag);
1175 if (failed) {
1176 DEBUG_API(printk("cryptocop_setup_dma_list: failed digest pad creation.\n"));
1177 goto error_cleanup;
1180 } else {
1181 meta_out.hashsel = src_none;
1184 if (csum_ctx.active) {
1185 ++active_count;
1186 meta_out.csumsel = csum_ctx.current_src;
1187 if (csum_ctx.done) {
1188 assert(csum_ctx.pad_descs == NULL);
1189 failed = create_pad_descriptor(&csum_ctx, &csum_ctx.pad_descs, alloc_flag);
1190 if (failed) {
1191 DEBUG_API(printk("cryptocop_setup_dma_list: failed csum pad creation.\n"));
1192 goto error_cleanup;
1195 } else {
1196 meta_out.csumsel = src_none;
1198 DEBUG(printk("cryptocop_setup_dma_list: %d eop needed, %d active units\n", eop_needed_count, active_count));
1199 /* Setup DMA out descriptors for the indata. */
1200 failed = create_output_descriptors(operation, &iniov_ix, &iniov_offset, desc_len, &current_out_cdesc, &meta_out, alloc_flag);
1201 if (failed) {
1202 DEBUG_API(printk("cryptocop_setup_dma_list: create_output_descriptors %d\n", failed));
1203 goto error_cleanup;
1205 /* Setup out EOP. If there are active units that are not done here they cannot get an EOP
1206 * so we ust setup a zero length descriptor to DMA to signal EOP only to done units.
1207 * If there is a pad descriptor EOP for the padded unit will be EOPed by it.
1209 assert(active_count >= eop_needed_count);
1210 assert((eop_needed_count == 0) || (eop_needed_count == 1));
1211 if (eop_needed_count) {
1212 /* This means that the bulk operation (cipeher/m2m) is terminated. */
1213 if (active_count > 1) {
1214 /* Use zero length EOP descriptor. */
1215 struct cryptocop_dma_desc *ed = alloc_cdesc(alloc_flag);
1216 struct strcop_meta_out ed_mo = {0};
1217 if (!ed) {
1218 DEBUG_API(printk("cryptocop_setup_dma_list: alloc EOP descriptor for cipher\n"));
1219 failed = -ENOMEM;
1220 goto error_cleanup;
1223 assert(cipher_ctx.active && cipher_ctx.done);
1225 if (cipher_ctx.unit_no == src_dma){
1226 /* mem2mem */
1227 ed_mo.ciphsel = src_none;
1228 } else {
1229 ed_mo.ciphsel = cipher_ctx.current_src;
1231 ed_mo.ciphconf = cipher_ctx.ciph_conf;
1232 ed_mo.cbcmode = cipher_ctx.cbcmode;
1233 ed_mo.decrypt = cipher_ctx.decrypt;
1235 ed->free_buf = NULL;
1236 ed->dma_descr->wait = 1;
1237 ed->dma_descr->out_eop = 1;
1239 ed->dma_descr->buf = (char*)virt_to_phys(&ed); /* Use any valid physical address for zero length descriptor. */
1240 ed->dma_descr->after = ed->dma_descr->buf;
1241 ed->dma_descr->md = REG_TYPE_CONV(unsigned short int, struct strcop_meta_out, ed_mo);
1242 current_out_cdesc->next = ed;
1243 current_out_cdesc = ed;
1244 } else {
1245 /* Set EOP in the current out descriptor since the only active module is
1246 * the one needing the EOP. */
1248 current_out_cdesc->dma_descr->out_eop = 1;
1252 if (cipher_ctx.done && cipher_ctx.active) cipher_ctx.active = 0;
1253 if (digest_ctx.done && digest_ctx.active) digest_ctx.active = 0;
1254 if (csum_ctx.done && csum_ctx.active) csum_ctx.active = 0;
1255 indata_ix += odsc->length;
1256 odsc = odsc->next;
1257 } /* while (odsc) */ /* Process descriptors. */
1258 DEBUG(printk("cryptocop_setup_dma_list: done parsing operation descriptors\n"));
1259 if (cipher_ctx.tcfg && (cipher_ctx.active || !cipher_ctx.done)){
1260 DEBUG_API(printk("cryptocop_setup_dma_list: cipher operation not terminated.\n"));
1261 failed = -EINVAL;
1262 goto error_cleanup;
1264 if (digest_ctx.tcfg && (digest_ctx.active || !digest_ctx.done)){
1265 DEBUG_API(printk("cryptocop_setup_dma_list: digest operation not terminated.\n"));
1266 failed = -EINVAL;
1267 goto error_cleanup;
1269 if (csum_ctx.tcfg && (csum_ctx.active || !csum_ctx.done)){
1270 DEBUG_API(printk("cryptocop_setup_dma_list: csum operation not terminated.\n"));
1271 failed = -EINVAL;
1272 goto error_cleanup;
1275 failed = append_input_descriptors(operation, &current_in_cdesc, &current_out_cdesc, &cipher_ctx, alloc_flag);
1276 if (failed){
1277 DEBUG_API(printk("cryptocop_setup_dma_list: append_input_descriptors cipher_ctx %d\n", failed));
1278 goto error_cleanup;
1280 failed = append_input_descriptors(operation, &current_in_cdesc, &current_out_cdesc, &digest_ctx, alloc_flag);
1281 if (failed){
1282 DEBUG_API(printk("cryptocop_setup_dma_list: append_input_descriptors cipher_ctx %d\n", failed));
1283 goto error_cleanup;
1285 failed = append_input_descriptors(operation, &current_in_cdesc, &current_out_cdesc, &csum_ctx, alloc_flag);
1286 if (failed){
1287 DEBUG_API(printk("cryptocop_setup_dma_list: append_input_descriptors cipher_ctx %d\n", failed));
1288 goto error_cleanup;
1291 DEBUG(printk("cryptocop_setup_dma_list: int_op=0x%p, *int_op=0x%p\n", int_op, *int_op));
1292 (*int_op)->cdesc_out = out_cdesc_head.next;
1293 (*int_op)->cdesc_in = in_cdesc_head.next;
1294 DEBUG(printk("cryptocop_setup_dma_list: out_cdesc_head=0x%p in_cdesc_head=0x%p\n", (*int_op)->cdesc_out, (*int_op)->cdesc_in));
1296 setup_descr_chain(out_cdesc_head.next);
1297 setup_descr_chain(in_cdesc_head.next);
1299 /* Last but not least: mark the last DMA in descriptor for a INTR and EOL and the the
1300 * last DMA out descriptor for EOL.
1302 current_in_cdesc->dma_descr->intr = 1;
1303 current_in_cdesc->dma_descr->eol = 1;
1304 current_out_cdesc->dma_descr->eol = 1;
1306 /* Setup DMA contexts. */
1307 (*int_op)->ctx_out.next = NULL;
1308 (*int_op)->ctx_out.eol = 1;
1309 (*int_op)->ctx_out.intr = 0;
1310 (*int_op)->ctx_out.store_mode = 0;
1311 (*int_op)->ctx_out.en = 0;
1312 (*int_op)->ctx_out.dis = 0;
1313 (*int_op)->ctx_out.md0 = 0;
1314 (*int_op)->ctx_out.md1 = 0;
1315 (*int_op)->ctx_out.md2 = 0;
1316 (*int_op)->ctx_out.md3 = 0;
1317 (*int_op)->ctx_out.md4 = 0;
1318 (*int_op)->ctx_out.saved_data = (dma_descr_data*)virt_to_phys((*int_op)->cdesc_out->dma_descr);
1319 (*int_op)->ctx_out.saved_data_buf = (*int_op)->cdesc_out->dma_descr->buf; /* Already physical address. */
1321 (*int_op)->ctx_in.next = NULL;
1322 (*int_op)->ctx_in.eol = 1;
1323 (*int_op)->ctx_in.intr = 0;
1324 (*int_op)->ctx_in.store_mode = 0;
1325 (*int_op)->ctx_in.en = 0;
1326 (*int_op)->ctx_in.dis = 0;
1327 (*int_op)->ctx_in.md0 = 0;
1328 (*int_op)->ctx_in.md1 = 0;
1329 (*int_op)->ctx_in.md2 = 0;
1330 (*int_op)->ctx_in.md3 = 0;
1331 (*int_op)->ctx_in.md4 = 0;
1333 (*int_op)->ctx_in.saved_data = (dma_descr_data*)virt_to_phys((*int_op)->cdesc_in->dma_descr);
1334 (*int_op)->ctx_in.saved_data_buf = (*int_op)->cdesc_in->dma_descr->buf; /* Already physical address. */
1336 DEBUG(printk("cryptocop_setup_dma_list: done\n"));
1337 return 0;
1339 error_cleanup:
1341 /* Free all allocated resources. */
1342 struct cryptocop_dma_desc *tmp_cdesc;
1343 while (digest_ctx.pad_descs){
1344 tmp_cdesc = digest_ctx.pad_descs->next;
1345 free_cdesc(digest_ctx.pad_descs);
1346 digest_ctx.pad_descs = tmp_cdesc;
1348 while (csum_ctx.pad_descs){
1349 tmp_cdesc = csum_ctx.pad_descs->next;
1350 free_cdesc(csum_ctx.pad_descs);
1351 csum_ctx.pad_descs = tmp_cdesc;
1353 assert(cipher_ctx.pad_descs == NULL); /* The ciphers are never padded. */
1355 if (*int_op != NULL) delete_internal_operation(*int_op);
1357 DEBUG_API(printk("cryptocop_setup_dma_list: done with error %d\n", failed));
1358 return failed;
1362 static void delete_internal_operation(struct cryptocop_int_operation *iop)
1364 void *ptr = iop->alloc_ptr;
1365 struct cryptocop_dma_desc *cd = iop->cdesc_out;
1366 struct cryptocop_dma_desc *next;
1368 DEBUG(printk("delete_internal_operation: iop=0x%p, alloc_ptr=0x%p\n", iop, ptr));
1370 while (cd) {
1371 next = cd->next;
1372 free_cdesc(cd);
1373 cd = next;
1375 cd = iop->cdesc_in;
1376 while (cd) {
1377 next = cd->next;
1378 free_cdesc(cd);
1379 cd = next;
1381 kfree(ptr);
1384 #define MD5_MIN_PAD_LENGTH (9)
1385 #define MD5_PAD_LENGTH_FIELD_LENGTH (8)
1387 static int create_md5_pad(int alloc_flag, unsigned long long hashed_length, char **pad, size_t *pad_length)
1389 size_t padlen = MD5_BLOCK_LENGTH - (hashed_length % MD5_BLOCK_LENGTH);
1390 unsigned char *p;
1391 int i;
1392 unsigned long long int bit_length = hashed_length << 3;
1394 if (padlen < MD5_MIN_PAD_LENGTH) padlen += MD5_BLOCK_LENGTH;
1396 p = kmalloc(padlen, alloc_flag);
1397 if (!pad) return -ENOMEM;
1399 *p = 0x80;
1400 memset(p+1, 0, padlen - 1);
1402 DEBUG(printk("create_md5_pad: hashed_length=%lld bits == %lld bytes\n", bit_length, hashed_length));
1404 i = padlen - MD5_PAD_LENGTH_FIELD_LENGTH;
1405 while (bit_length != 0){
1406 p[i++] = bit_length % 0x100;
1407 bit_length >>= 8;
1410 *pad = (char*)p;
1411 *pad_length = padlen;
1413 return 0;
1416 #define SHA1_MIN_PAD_LENGTH (9)
1417 #define SHA1_PAD_LENGTH_FIELD_LENGTH (8)
1419 static int create_sha1_pad(int alloc_flag, unsigned long long hashed_length, char **pad, size_t *pad_length)
1421 size_t padlen = SHA1_BLOCK_LENGTH - (hashed_length % SHA1_BLOCK_LENGTH);
1422 unsigned char *p;
1423 int i;
1424 unsigned long long int bit_length = hashed_length << 3;
1426 if (padlen < SHA1_MIN_PAD_LENGTH) padlen += SHA1_BLOCK_LENGTH;
1428 p = kmalloc(padlen, alloc_flag);
1429 if (!pad) return -ENOMEM;
1431 *p = 0x80;
1432 memset(p+1, 0, padlen - 1);
1434 DEBUG(printk("create_sha1_pad: hashed_length=%lld bits == %lld bytes\n", bit_length, hashed_length));
1436 i = padlen - 1;
1437 while (bit_length != 0){
1438 p[i--] = bit_length % 0x100;
1439 bit_length >>= 8;
1442 *pad = (char*)p;
1443 *pad_length = padlen;
1445 return 0;
1449 static int transform_ok(struct cryptocop_transform_init *tinit)
1451 switch (tinit->alg){
1452 case cryptocop_alg_csum:
1453 switch (tinit->csum_mode){
1454 case cryptocop_csum_le:
1455 case cryptocop_csum_be:
1456 break;
1457 default:
1458 DEBUG_API(printk("transform_ok: Bad mode set for csum transform\n"));
1459 return -EINVAL;
1461 case cryptocop_alg_mem2mem:
1462 case cryptocop_alg_md5:
1463 case cryptocop_alg_sha1:
1464 if (tinit->keylen != 0) {
1465 DEBUG_API(printk("transform_ok: non-zero keylength, %d, for a digest/csum algorithm\n", tinit->keylen));
1466 return -EINVAL; /* This check is a bit strict. */
1468 break;
1469 case cryptocop_alg_des:
1470 if (tinit->keylen != 64) {
1471 DEBUG_API(printk("transform_ok: keylen %d invalid for DES\n", tinit->keylen));
1472 return -EINVAL;
1474 break;
1475 case cryptocop_alg_3des:
1476 if (tinit->keylen != 192) {
1477 DEBUG_API(printk("transform_ok: keylen %d invalid for 3DES\n", tinit->keylen));
1478 return -EINVAL;
1480 break;
1481 case cryptocop_alg_aes:
1482 if (tinit->keylen != 128 && tinit->keylen != 192 && tinit->keylen != 256) {
1483 DEBUG_API(printk("transform_ok: keylen %d invalid for AES\n", tinit->keylen));
1484 return -EINVAL;
1486 break;
1487 case cryptocop_no_alg:
1488 default:
1489 DEBUG_API(printk("transform_ok: no such algorithm %d\n", tinit->alg));
1490 return -EINVAL;
1493 switch (tinit->alg){
1494 case cryptocop_alg_des:
1495 case cryptocop_alg_3des:
1496 case cryptocop_alg_aes:
1497 if (tinit->cipher_mode != cryptocop_cipher_mode_ecb && tinit->cipher_mode != cryptocop_cipher_mode_cbc) return -EINVAL;
1498 default:
1499 break;
1501 return 0;
1505 int cryptocop_new_session(cryptocop_session_id *sid, struct cryptocop_transform_init *tinit, int alloc_flag)
1507 struct cryptocop_session *sess;
1508 struct cryptocop_transform_init *tfrm_in = tinit;
1509 struct cryptocop_transform_init *tmp_in;
1510 int no_tfrms = 0;
1511 int i;
1512 unsigned long int flags;
1514 init_stream_coprocessor(); /* For safety if we are called early */
1516 while (tfrm_in){
1517 int err;
1518 ++no_tfrms;
1519 if ((err = transform_ok(tfrm_in))) {
1520 DEBUG_API(printk("cryptocop_new_session, bad transform\n"));
1521 return err;
1523 tfrm_in = tfrm_in->next;
1525 if (0 == no_tfrms) {
1526 DEBUG_API(printk("cryptocop_new_session, no transforms specified\n"));
1527 return -EINVAL;
1530 sess = kmalloc(sizeof(struct cryptocop_session), alloc_flag);
1531 if (!sess){
1532 DEBUG_API(printk("cryptocop_new_session, kmalloc cryptocop_session\n"));
1533 return -ENOMEM;
1536 sess->tfrm_ctx = kmalloc(no_tfrms * sizeof(struct cryptocop_transform_ctx), alloc_flag);
1537 if (!sess->tfrm_ctx) {
1538 DEBUG_API(printk("cryptocop_new_session, kmalloc cryptocop_transform_ctx\n"));
1539 kfree(sess);
1540 return -ENOMEM;
1543 tfrm_in = tinit;
1544 for (i = 0; i < no_tfrms; i++){
1545 tmp_in = tfrm_in->next;
1546 while (tmp_in){
1547 if (tmp_in->tid == tfrm_in->tid) {
1548 DEBUG_API(printk("cryptocop_new_session, duplicate transform ids\n"));
1549 kfree(sess->tfrm_ctx);
1550 kfree(sess);
1551 return -EINVAL;
1553 tmp_in = tmp_in->next;
1555 memcpy(&sess->tfrm_ctx[i].init, tfrm_in, sizeof(struct cryptocop_transform_init));
1556 sess->tfrm_ctx[i].dec_key_set = 0;
1557 sess->tfrm_ctx[i].next = &sess->tfrm_ctx[i] + 1;
1559 tfrm_in = tfrm_in->next;
1561 sess->tfrm_ctx[i-1].next = NULL;
1563 spin_lock_irqsave(&cryptocop_sessions_lock, flags);
1564 sess->sid = next_sid;
1565 next_sid++;
1566 /* TODO If we are really paranoid we should do duplicate check to handle sid wraparound.
1567 * OTOH 2^64 is a really large number of session. */
1568 if (next_sid == 0) next_sid = 1;
1570 /* Prepend to session list. */
1571 sess->next = cryptocop_sessions;
1572 cryptocop_sessions = sess;
1573 spin_unlock_irqrestore(&cryptocop_sessions_lock, flags);
1574 *sid = sess->sid;
1575 return 0;
1579 int cryptocop_free_session(cryptocop_session_id sid)
1581 struct cryptocop_transform_ctx *tc;
1582 struct cryptocop_session *sess = NULL;
1583 struct cryptocop_session *psess = NULL;
1584 unsigned long int flags;
1585 int i;
1586 LIST_HEAD(remove_list);
1587 struct list_head *node, *tmp;
1588 struct cryptocop_prio_job *pj;
1590 DEBUG(printk("cryptocop_free_session: sid=%lld\n", sid));
1592 spin_lock_irqsave(&cryptocop_sessions_lock, flags);
1593 sess = cryptocop_sessions;
1594 while (sess && sess->sid != sid){
1595 psess = sess;
1596 sess = sess->next;
1598 if (sess){
1599 if (psess){
1600 psess->next = sess->next;
1601 } else {
1602 cryptocop_sessions = sess->next;
1605 spin_unlock_irqrestore(&cryptocop_sessions_lock, flags);
1607 if (!sess) return -EINVAL;
1609 /* Remove queued jobs. */
1610 spin_lock_irqsave(&cryptocop_job_queue_lock, flags);
1612 for (i = 0; i < cryptocop_prio_no_prios; i++){
1613 if (!list_empty(&(cryptocop_job_queues[i].jobs))){
1614 list_for_each_safe(node, tmp, &(cryptocop_job_queues[i].jobs)) {
1615 pj = list_entry(node, struct cryptocop_prio_job, node);
1616 if (pj->oper->sid == sid) {
1617 list_move_tail(node, &remove_list);
1622 spin_unlock_irqrestore(&cryptocop_job_queue_lock, flags);
1624 list_for_each_safe(node, tmp, &remove_list) {
1625 list_del(node);
1626 pj = list_entry(node, struct cryptocop_prio_job, node);
1627 pj->oper->operation_status = -EAGAIN; /* EAGAIN is not ideal for job/session terminated but it's the best choice I know of. */
1628 DEBUG(printk("cryptocop_free_session: pj=0x%p, pj->oper=0x%p, pj->iop=0x%p\n", pj, pj->oper, pj->iop));
1629 pj->oper->cb(pj->oper, pj->oper->cb_data);
1630 delete_internal_operation(pj->iop);
1631 kfree(pj);
1634 tc = sess->tfrm_ctx;
1635 /* Erase keying data. */
1636 while (tc){
1637 DEBUG(printk("cryptocop_free_session: memset keys, tfrm id=%d\n", tc->init.tid));
1638 memset(tc->init.key, 0xff, CRYPTOCOP_MAX_KEY_LENGTH);
1639 memset(tc->dec_key, 0xff, CRYPTOCOP_MAX_KEY_LENGTH);
1640 tc = tc->next;
1642 kfree(sess->tfrm_ctx);
1643 kfree(sess);
1645 return 0;
1648 static struct cryptocop_session *get_session(cryptocop_session_id sid)
1650 struct cryptocop_session *sess;
1651 unsigned long int flags;
1653 spin_lock_irqsave(&cryptocop_sessions_lock, flags);
1654 sess = cryptocop_sessions;
1655 while (sess && (sess->sid != sid)){
1656 sess = sess->next;
1658 spin_unlock_irqrestore(&cryptocop_sessions_lock, flags);
1660 return sess;
1663 static struct cryptocop_transform_ctx *get_transform_ctx(struct cryptocop_session *sess, cryptocop_tfrm_id tid)
1665 struct cryptocop_transform_ctx *tc = sess->tfrm_ctx;
1667 DEBUG(printk("get_transform_ctx, sess=0x%p, tid=%d\n", sess, tid));
1668 assert(sess != NULL);
1669 while (tc && tc->init.tid != tid){
1670 DEBUG(printk("tc=0x%p, tc->next=0x%p\n", tc, tc->next));
1671 tc = tc->next;
1673 DEBUG(printk("get_transform_ctx, returning tc=0x%p\n", tc));
1674 return tc;
1679 /* The AES s-transform matrix (s-box). */
1680 static const u8 aes_sbox[256] = {
1681 99, 124, 119, 123, 242, 107, 111, 197, 48, 1, 103, 43, 254, 215, 171, 118,
1682 202, 130, 201, 125, 250, 89, 71, 240, 173, 212, 162, 175, 156, 164, 114, 192,
1683 183, 253, 147, 38, 54, 63, 247, 204, 52, 165, 229, 241, 113, 216, 49, 21,
1684 4, 199, 35, 195, 24, 150, 5, 154, 7, 18, 128, 226, 235, 39, 178, 117,
1685 9, 131, 44, 26, 27, 110, 90, 160, 82, 59, 214, 179, 41, 227, 47, 132,
1686 83, 209, 0, 237, 32, 252, 177, 91, 106, 203, 190, 57, 74, 76, 88, 207,
1687 208, 239, 170, 251, 67, 77, 51, 133, 69, 249, 2, 127, 80, 60, 159, 168,
1688 81, 163, 64, 143, 146, 157, 56, 245, 188, 182, 218, 33, 16, 255, 243, 210,
1689 205, 12, 19, 236, 95, 151, 68, 23, 196, 167, 126, 61, 100, 93, 25, 115,
1690 96, 129, 79, 220, 34, 42, 144, 136, 70, 238, 184, 20, 222, 94, 11, 219,
1691 224, 50, 58, 10, 73, 6, 36, 92, 194, 211, 172, 98, 145, 149, 228, 121,
1692 231, 200, 55, 109, 141, 213, 78, 169, 108, 86, 244, 234, 101, 122, 174, 8,
1693 186, 120, 37, 46, 28, 166, 180, 198, 232, 221, 116, 31, 75, 189, 139, 138,
1694 112, 62, 181, 102, 72, 3, 246, 14, 97, 53, 87, 185, 134, 193, 29, 158,
1695 225, 248, 152, 17, 105, 217, 142, 148, 155, 30, 135, 233, 206, 85, 40, 223,
1696 140, 161, 137, 13, 191, 230, 66, 104, 65, 153, 45, 15, 176, 84, 187, 22
1699 /* AES has a 32 bit word round constants for each round in the
1700 * key schedule. round_constant[i] is really Rcon[i+1] in FIPS187.
1702 static u32 round_constant[11] = {
1703 0x01000000, 0x02000000, 0x04000000, 0x08000000,
1704 0x10000000, 0x20000000, 0x40000000, 0x80000000,
1705 0x1B000000, 0x36000000, 0x6C000000
1708 /* Apply the s-box to each of the four occtets in w. */
1709 static u32 aes_ks_subword(const u32 w)
1711 u8 bytes[4];
1713 *(u32*)(&bytes[0]) = w;
1714 bytes[0] = aes_sbox[bytes[0]];
1715 bytes[1] = aes_sbox[bytes[1]];
1716 bytes[2] = aes_sbox[bytes[2]];
1717 bytes[3] = aes_sbox[bytes[3]];
1718 return *(u32*)(&bytes[0]);
1721 /* The encrypt (forward) Rijndael key schedule algorithm pseudo code:
1722 * (Note that AES words are 32 bit long)
1724 * KeyExpansion(byte key[4*Nk], word w[Nb*(Nr+1)], Nk){
1725 * word temp
1726 * i = 0
1727 * while (i < Nk) {
1728 * w[i] = word(key[4*i, 4*i + 1, 4*i + 2, 4*i + 3])
1729 * i = i + 1
1731 * i = Nk
1733 * while (i < (Nb * (Nr + 1))) {
1734 * temp = w[i - 1]
1735 * if ((i mod Nk) == 0) {
1736 * temp = SubWord(RotWord(temp)) xor Rcon[i/Nk]
1738 * else if ((Nk > 6) && ((i mod Nk) == 4)) {
1739 * temp = SubWord(temp)
1741 * w[i] = w[i - Nk] xor temp
1743 * RotWord(t) does a 8 bit cyclic shift left on a 32 bit word.
1744 * SubWord(t) applies the AES s-box individually to each octet
1745 * in a 32 bit word.
1747 * For AES Nk can have the values 4, 6, and 8 (corresponding to
1748 * values for Nr of 10, 12, and 14). Nb is always 4.
1750 * To construct w[i], w[i - 1] and w[i - Nk] must be
1751 * available. Consequently we must keep a state of the last Nk words
1752 * to be able to create the last round keys.
1754 static void get_aes_decrypt_key(unsigned char *dec_key, const unsigned char *key, unsigned int keylength)
1756 u32 temp;
1757 u32 w_ring[8]; /* nk is max 8, use elements 0..(nk - 1) as a ringbuffer */
1758 u8 w_last_ix;
1759 int i;
1760 u8 nr, nk;
1762 switch (keylength){
1763 case 128:
1764 nk = 4;
1765 nr = 10;
1766 break;
1767 case 192:
1768 nk = 6;
1769 nr = 12;
1770 break;
1771 case 256:
1772 nk = 8;
1773 nr = 14;
1774 break;
1775 default:
1776 panic("stream co-processor: bad aes key length in get_aes_decrypt_key\n");
1779 /* Need to do host byte order correction here since key is byte oriented and the
1780 * kx algorithm is word (u32) oriented. */
1781 for (i = 0; i < nk; i+=1) {
1782 w_ring[i] = be32_to_cpu(*(u32*)&key[4*i]);
1785 i = (int)nk;
1786 w_last_ix = i - 1;
1787 while (i < (4 * (nr + 2))) {
1788 temp = w_ring[w_last_ix];
1789 if (!(i % nk)) {
1790 /* RotWord(temp) */
1791 temp = (temp << 8) | (temp >> 24);
1792 temp = aes_ks_subword(temp);
1793 temp ^= round_constant[i/nk - 1];
1794 } else if ((nk > 6) && ((i % nk) == 4)) {
1795 temp = aes_ks_subword(temp);
1797 w_last_ix = (w_last_ix + 1) % nk; /* This is the same as (i-Nk) mod Nk */
1798 temp ^= w_ring[w_last_ix];
1799 w_ring[w_last_ix] = temp;
1801 /* We need the round keys for round Nr+1 and Nr+2 (round key
1802 * Nr+2 is the round key beyond the last one used when
1803 * encrypting). Rounds are numbered starting from 0, Nr=10
1804 * implies 11 rounds are used in encryption/decryption.
1806 if (i >= (4 * nr)) {
1807 /* Need to do host byte order correction here, the key
1808 * is byte oriented. */
1809 *(u32*)dec_key = cpu_to_be32(temp);
1810 dec_key += 4;
1812 ++i;
1817 /**** Job/operation management. ****/
1819 int cryptocop_job_queue_insert_csum(struct cryptocop_operation *operation)
1821 return cryptocop_job_queue_insert(cryptocop_prio_kernel_csum, operation);
1824 int cryptocop_job_queue_insert_crypto(struct cryptocop_operation *operation)
1826 return cryptocop_job_queue_insert(cryptocop_prio_kernel, operation);
1829 int cryptocop_job_queue_insert_user_job(struct cryptocop_operation *operation)
1831 return cryptocop_job_queue_insert(cryptocop_prio_user, operation);
1834 static int cryptocop_job_queue_insert(cryptocop_queue_priority prio, struct cryptocop_operation *operation)
1836 int ret;
1837 struct cryptocop_prio_job *pj = NULL;
1838 unsigned long int flags;
1840 DEBUG(printk("cryptocop_job_queue_insert(%d, 0x%p)\n", prio, operation));
1842 if (!operation || !operation->cb){
1843 DEBUG_API(printk("cryptocop_job_queue_insert oper=0x%p, NULL operation or callback\n", operation));
1844 return -EINVAL;
1847 if ((ret = cryptocop_job_setup(&pj, operation)) != 0){
1848 DEBUG_API(printk("cryptocop_job_queue_insert: job setup failed\n"));
1849 return ret;
1851 assert(pj != NULL);
1853 spin_lock_irqsave(&cryptocop_job_queue_lock, flags);
1854 list_add_tail(&pj->node, &cryptocop_job_queues[prio].jobs);
1855 spin_unlock_irqrestore(&cryptocop_job_queue_lock, flags);
1857 /* Make sure a job is running */
1858 cryptocop_start_job();
1859 return 0;
1862 static void cryptocop_do_tasklet(unsigned long unused);
1863 DECLARE_TASKLET (cryptocop_tasklet, cryptocop_do_tasklet, 0);
1865 static void cryptocop_do_tasklet(unsigned long unused)
1867 struct list_head *node;
1868 struct cryptocop_prio_job *pj = NULL;
1869 unsigned long flags;
1871 DEBUG(printk("cryptocop_do_tasklet: entering\n"));
1873 do {
1874 spin_lock_irqsave(&cryptocop_completed_jobs_lock, flags);
1875 if (!list_empty(&cryptocop_completed_jobs)){
1876 node = cryptocop_completed_jobs.next;
1877 list_del(node);
1878 pj = list_entry(node, struct cryptocop_prio_job, node);
1879 } else {
1880 pj = NULL;
1882 spin_unlock_irqrestore(&cryptocop_completed_jobs_lock, flags);
1883 if (pj) {
1884 assert(pj->oper != NULL);
1886 /* Notify consumer of operation completeness. */
1887 DEBUG(printk("cryptocop_do_tasklet: callback 0x%p, data 0x%p\n", pj->oper->cb, pj->oper->cb_data));
1889 pj->oper->operation_status = 0; /* Job is completed. */
1890 pj->oper->cb(pj->oper, pj->oper->cb_data);
1891 delete_internal_operation(pj->iop);
1892 kfree(pj);
1894 } while (pj != NULL);
1896 DEBUG(printk("cryptocop_do_tasklet: exiting\n"));
1899 static irqreturn_t
1900 dma_done_interrupt(int irq, void *dev_id)
1902 struct cryptocop_prio_job *done_job;
1903 reg_dma_rw_ack_intr ack_intr = {
1904 .data = 1,
1907 REG_WR(dma, IN_DMA_INST, rw_ack_intr, ack_intr);
1909 DEBUG(printk("cryptocop DMA done\n"));
1911 spin_lock(&running_job_lock);
1912 if (cryptocop_running_job == NULL){
1913 printk("stream co-processor got interrupt when not busy\n");
1914 spin_unlock(&running_job_lock);
1915 return IRQ_HANDLED;
1917 done_job = cryptocop_running_job;
1918 cryptocop_running_job = NULL;
1919 spin_unlock(&running_job_lock);
1921 /* Start processing a job. */
1922 if (!spin_trylock(&cryptocop_process_lock)){
1923 DEBUG(printk("cryptocop irq handler, not starting a job\n"));
1924 } else {
1925 cryptocop_start_job();
1926 spin_unlock(&cryptocop_process_lock);
1929 done_job->oper->operation_status = 0; /* Job is completed. */
1930 if (done_job->oper->fast_callback){
1931 /* This operation wants callback from interrupt. */
1932 done_job->oper->cb(done_job->oper, done_job->oper->cb_data);
1933 delete_internal_operation(done_job->iop);
1934 kfree(done_job);
1935 } else {
1936 spin_lock(&cryptocop_completed_jobs_lock);
1937 list_add_tail(&(done_job->node), &cryptocop_completed_jobs);
1938 spin_unlock(&cryptocop_completed_jobs_lock);
1939 tasklet_schedule(&cryptocop_tasklet);
1942 DEBUG(printk("cryptocop leave irq handler\n"));
1943 return IRQ_HANDLED;
1947 /* Setup interrupts and DMA channels. */
1948 static int init_cryptocop(void)
1950 unsigned long flags;
1951 reg_dma_rw_cfg dma_cfg = {.en = 1};
1952 reg_dma_rw_intr_mask intr_mask_in = {.data = regk_dma_yes}; /* Only want descriptor interrupts from the DMA in channel. */
1953 reg_dma_rw_ack_intr ack_intr = {.data = 1,.in_eop = 1 };
1954 reg_strcop_rw_cfg strcop_cfg = {
1955 .ipend = regk_strcop_little,
1956 .td1 = regk_strcop_e,
1957 .td2 = regk_strcop_d,
1958 .td3 = regk_strcop_e,
1959 .ignore_sync = 0,
1960 .en = 1
1963 if (request_irq(DMA_IRQ, dma_done_interrupt, 0,
1964 "stream co-processor DMA", NULL))
1965 panic("request_irq stream co-processor irq dma9");
1967 (void)crisv32_request_dma(OUT_DMA, "strcop", DMA_PANIC_ON_ERROR,
1968 0, dma_strp);
1969 (void)crisv32_request_dma(IN_DMA, "strcop", DMA_PANIC_ON_ERROR,
1970 0, dma_strp);
1972 local_irq_save(flags);
1974 /* Reset and enable the cryptocop. */
1975 strcop_cfg.en = 0;
1976 REG_WR(strcop, regi_strcop, rw_cfg, strcop_cfg);
1977 strcop_cfg.en = 1;
1978 REG_WR(strcop, regi_strcop, rw_cfg, strcop_cfg);
1980 /* Enable DMAs. */
1981 REG_WR(dma, IN_DMA_INST, rw_cfg, dma_cfg); /* input DMA */
1982 REG_WR(dma, OUT_DMA_INST, rw_cfg, dma_cfg); /* output DMA */
1984 /* Set up wordsize = 4 for DMAs. */
1985 DMA_WR_CMD(OUT_DMA_INST, regk_dma_set_w_size4);
1986 DMA_WR_CMD(IN_DMA_INST, regk_dma_set_w_size4);
1988 /* Enable interrupts. */
1989 REG_WR(dma, IN_DMA_INST, rw_intr_mask, intr_mask_in);
1991 /* Clear intr ack. */
1992 REG_WR(dma, IN_DMA_INST, rw_ack_intr, ack_intr);
1994 local_irq_restore(flags);
1996 return 0;
1999 /* Free used cryptocop hw resources (interrupt and DMA channels). */
2000 static void release_cryptocop(void)
2002 unsigned long flags;
2003 reg_dma_rw_cfg dma_cfg = {.en = 0};
2004 reg_dma_rw_intr_mask intr_mask_in = {0};
2005 reg_dma_rw_ack_intr ack_intr = {.data = 1,.in_eop = 1 };
2007 local_irq_save(flags);
2009 /* Clear intr ack. */
2010 REG_WR(dma, IN_DMA_INST, rw_ack_intr, ack_intr);
2012 /* Disable DMAs. */
2013 REG_WR(dma, IN_DMA_INST, rw_cfg, dma_cfg); /* input DMA */
2014 REG_WR(dma, OUT_DMA_INST, rw_cfg, dma_cfg); /* output DMA */
2016 /* Disable interrupts. */
2017 REG_WR(dma, IN_DMA_INST, rw_intr_mask, intr_mask_in);
2019 local_irq_restore(flags);
2021 free_irq(DMA_IRQ, NULL);
2023 (void)crisv32_free_dma(OUT_DMA);
2024 (void)crisv32_free_dma(IN_DMA);
2028 /* Init job queue. */
2029 static int cryptocop_job_queue_init(void)
2031 int i;
2033 INIT_LIST_HEAD(&cryptocop_completed_jobs);
2035 for (i = 0; i < cryptocop_prio_no_prios; i++){
2036 cryptocop_job_queues[i].prio = (cryptocop_queue_priority)i;
2037 INIT_LIST_HEAD(&cryptocop_job_queues[i].jobs);
2039 return 0;
2043 static void cryptocop_job_queue_close(void)
2045 struct list_head *node, *tmp;
2046 struct cryptocop_prio_job *pj = NULL;
2047 unsigned long int process_flags, flags;
2048 int i;
2050 /* FIXME: This is as yet untested code. */
2052 /* Stop strcop from getting an operation to process while we are closing the
2053 module. */
2054 spin_lock_irqsave(&cryptocop_process_lock, process_flags);
2056 /* Empty the job queue. */
2057 for (i = 0; i < cryptocop_prio_no_prios; i++){
2058 if (!list_empty(&(cryptocop_job_queues[i].jobs))){
2059 list_for_each_safe(node, tmp, &(cryptocop_job_queues[i].jobs)) {
2060 pj = list_entry(node, struct cryptocop_prio_job, node);
2061 list_del(node);
2063 /* Call callback to notify consumer of job removal. */
2064 DEBUG(printk("cryptocop_job_queue_close: callback 0x%p, data 0x%p\n", pj->oper->cb, pj->oper->cb_data));
2065 pj->oper->operation_status = -EINTR; /* Job is terminated without completion. */
2066 pj->oper->cb(pj->oper, pj->oper->cb_data);
2068 delete_internal_operation(pj->iop);
2069 kfree(pj);
2073 spin_unlock_irqrestore(&cryptocop_process_lock, process_flags);
2075 /* Remove the running job, if any. */
2076 spin_lock_irqsave(&running_job_lock, flags);
2077 if (cryptocop_running_job){
2078 reg_strcop_rw_cfg rw_cfg;
2079 reg_dma_rw_cfg dma_out_cfg, dma_in_cfg;
2081 /* Stop DMA. */
2082 dma_out_cfg = REG_RD(dma, OUT_DMA_INST, rw_cfg);
2083 dma_out_cfg.en = regk_dma_no;
2084 REG_WR(dma, OUT_DMA_INST, rw_cfg, dma_out_cfg);
2086 dma_in_cfg = REG_RD(dma, IN_DMA_INST, rw_cfg);
2087 dma_in_cfg.en = regk_dma_no;
2088 REG_WR(dma, IN_DMA_INST, rw_cfg, dma_in_cfg);
2090 /* Disble the cryptocop. */
2091 rw_cfg = REG_RD(strcop, regi_strcop, rw_cfg);
2092 rw_cfg.en = 0;
2093 REG_WR(strcop, regi_strcop, rw_cfg, rw_cfg);
2095 pj = cryptocop_running_job;
2096 cryptocop_running_job = NULL;
2098 /* Call callback to notify consumer of job removal. */
2099 DEBUG(printk("cryptocop_job_queue_close: callback 0x%p, data 0x%p\n", pj->oper->cb, pj->oper->cb_data));
2100 pj->oper->operation_status = -EINTR; /* Job is terminated without completion. */
2101 pj->oper->cb(pj->oper, pj->oper->cb_data);
2103 delete_internal_operation(pj->iop);
2104 kfree(pj);
2106 spin_unlock_irqrestore(&running_job_lock, flags);
2108 /* Remove completed jobs, if any. */
2109 spin_lock_irqsave(&cryptocop_completed_jobs_lock, flags);
2111 list_for_each_safe(node, tmp, &cryptocop_completed_jobs) {
2112 pj = list_entry(node, struct cryptocop_prio_job, node);
2113 list_del(node);
2114 /* Call callback to notify consumer of job removal. */
2115 DEBUG(printk("cryptocop_job_queue_close: callback 0x%p, data 0x%p\n", pj->oper->cb, pj->oper->cb_data));
2116 pj->oper->operation_status = -EINTR; /* Job is terminated without completion. */
2117 pj->oper->cb(pj->oper, pj->oper->cb_data);
2119 delete_internal_operation(pj->iop);
2120 kfree(pj);
2122 spin_unlock_irqrestore(&cryptocop_completed_jobs_lock, flags);
2126 static void cryptocop_start_job(void)
2128 int i;
2129 struct cryptocop_prio_job *pj;
2130 unsigned long int flags;
2131 unsigned long int running_job_flags;
2132 reg_strcop_rw_cfg rw_cfg = {.en = 1, .ignore_sync = 0};
2134 DEBUG(printk("cryptocop_start_job: entering\n"));
2136 spin_lock_irqsave(&running_job_lock, running_job_flags);
2137 if (cryptocop_running_job != NULL){
2138 /* Already running. */
2139 DEBUG(printk("cryptocop_start_job: already running, exit\n"));
2140 spin_unlock_irqrestore(&running_job_lock, running_job_flags);
2141 return;
2143 spin_lock_irqsave(&cryptocop_job_queue_lock, flags);
2145 /* Check the queues in priority order. */
2146 for (i = cryptocop_prio_kernel_csum; (i < cryptocop_prio_no_prios) && list_empty(&cryptocop_job_queues[i].jobs); i++);
2147 if (i == cryptocop_prio_no_prios) {
2148 spin_unlock_irqrestore(&cryptocop_job_queue_lock, flags);
2149 spin_unlock_irqrestore(&running_job_lock, running_job_flags);
2150 DEBUG(printk("cryptocop_start_job: no jobs to run\n"));
2151 return; /* No jobs to run */
2153 DEBUG(printk("starting job for prio %d\n", i));
2155 /* TODO: Do not starve lower priority jobs. Let in a lower
2156 * prio job for every N-th processed higher prio job or some
2157 * other scheduling policy. This could reasonably be
2158 * tweakable since the optimal balance would depend on the
2159 * type of load on the system. */
2161 /* Pull the DMA lists from the job and start the DMA client. */
2162 pj = list_entry(cryptocop_job_queues[i].jobs.next, struct cryptocop_prio_job, node);
2163 list_del(&pj->node);
2164 spin_unlock_irqrestore(&cryptocop_job_queue_lock, flags);
2165 cryptocop_running_job = pj;
2167 /* Set config register (3DES and CSUM modes). */
2168 switch (pj->iop->tdes_mode){
2169 case cryptocop_3des_eee:
2170 rw_cfg.td1 = regk_strcop_e;
2171 rw_cfg.td2 = regk_strcop_e;
2172 rw_cfg.td3 = regk_strcop_e;
2173 break;
2174 case cryptocop_3des_eed:
2175 rw_cfg.td1 = regk_strcop_e;
2176 rw_cfg.td2 = regk_strcop_e;
2177 rw_cfg.td3 = regk_strcop_d;
2178 break;
2179 case cryptocop_3des_ede:
2180 rw_cfg.td1 = regk_strcop_e;
2181 rw_cfg.td2 = regk_strcop_d;
2182 rw_cfg.td3 = regk_strcop_e;
2183 break;
2184 case cryptocop_3des_edd:
2185 rw_cfg.td1 = regk_strcop_e;
2186 rw_cfg.td2 = regk_strcop_d;
2187 rw_cfg.td3 = regk_strcop_d;
2188 break;
2189 case cryptocop_3des_dee:
2190 rw_cfg.td1 = regk_strcop_d;
2191 rw_cfg.td2 = regk_strcop_e;
2192 rw_cfg.td3 = regk_strcop_e;
2193 break;
2194 case cryptocop_3des_ded:
2195 rw_cfg.td1 = regk_strcop_d;
2196 rw_cfg.td2 = regk_strcop_e;
2197 rw_cfg.td3 = regk_strcop_d;
2198 break;
2199 case cryptocop_3des_dde:
2200 rw_cfg.td1 = regk_strcop_d;
2201 rw_cfg.td2 = regk_strcop_d;
2202 rw_cfg.td3 = regk_strcop_e;
2203 break;
2204 case cryptocop_3des_ddd:
2205 rw_cfg.td1 = regk_strcop_d;
2206 rw_cfg.td2 = regk_strcop_d;
2207 rw_cfg.td3 = regk_strcop_d;
2208 break;
2209 default:
2210 DEBUG(printk("cryptocop_setup_dma_list: bad 3DES mode\n"));
2212 switch (pj->iop->csum_mode){
2213 case cryptocop_csum_le:
2214 rw_cfg.ipend = regk_strcop_little;
2215 break;
2216 case cryptocop_csum_be:
2217 rw_cfg.ipend = regk_strcop_big;
2218 break;
2219 default:
2220 DEBUG(printk("cryptocop_setup_dma_list: bad checksum mode\n"));
2222 REG_WR(strcop, regi_strcop, rw_cfg, rw_cfg);
2224 DEBUG(printk("cryptocop_start_job: starting DMA, new cryptocop_running_job=0x%p\n"
2225 "ctx_in: 0x%p, phys: 0x%p\n"
2226 "ctx_out: 0x%p, phys: 0x%p\n",
2228 &pj->iop->ctx_in, (char*)virt_to_phys(&pj->iop->ctx_in),
2229 &pj->iop->ctx_out, (char*)virt_to_phys(&pj->iop->ctx_out)));
2231 /* Start input DMA. */
2232 flush_dma_context(&pj->iop->ctx_in);
2233 DMA_START_CONTEXT(IN_DMA_INST, virt_to_phys(&pj->iop->ctx_in));
2235 /* Start output DMA. */
2236 DMA_START_CONTEXT(OUT_DMA_INST, virt_to_phys(&pj->iop->ctx_out));
2238 spin_unlock_irqrestore(&running_job_lock, running_job_flags);
2239 DEBUG(printk("cryptocop_start_job: exiting\n"));
2243 static int cryptocop_job_setup(struct cryptocop_prio_job **pj, struct cryptocop_operation *operation)
2245 int err;
2246 int alloc_flag = operation->in_interrupt ? GFP_ATOMIC : GFP_KERNEL;
2247 void *iop_alloc_ptr = NULL;
2249 *pj = kmalloc(sizeof (struct cryptocop_prio_job), alloc_flag);
2250 if (!*pj) return -ENOMEM;
2252 DEBUG(printk("cryptocop_job_setup: operation=0x%p\n", operation));
2254 (*pj)->oper = operation;
2255 DEBUG(printk("cryptocop_job_setup, cb=0x%p cb_data=0x%p\n", (*pj)->oper->cb, (*pj)->oper->cb_data));
2257 if (operation->use_dmalists) {
2258 DEBUG(print_user_dma_lists(&operation->list_op));
2259 if (!operation->list_op.inlist || !operation->list_op.outlist || !operation->list_op.out_data_buf || !operation->list_op.in_data_buf){
2260 DEBUG_API(printk("cryptocop_job_setup: bad indata (use_dmalists)\n"));
2261 kfree(*pj);
2262 return -EINVAL;
2264 iop_alloc_ptr = kmalloc(DESCR_ALLOC_PAD + sizeof(struct cryptocop_int_operation), alloc_flag);
2265 if (!iop_alloc_ptr) {
2266 DEBUG_API(printk("cryptocop_job_setup: kmalloc cryptocop_int_operation\n"));
2267 kfree(*pj);
2268 return -ENOMEM;
2270 (*pj)->iop = (struct cryptocop_int_operation*)(((unsigned long int)(iop_alloc_ptr + DESCR_ALLOC_PAD + offsetof(struct cryptocop_int_operation, ctx_out)) & ~0x0000001F) - offsetof(struct cryptocop_int_operation, ctx_out));
2271 DEBUG(memset((*pj)->iop, 0xff, sizeof(struct cryptocop_int_operation)));
2272 (*pj)->iop->alloc_ptr = iop_alloc_ptr;
2273 (*pj)->iop->sid = operation->sid;
2274 (*pj)->iop->cdesc_out = NULL;
2275 (*pj)->iop->cdesc_in = NULL;
2276 (*pj)->iop->tdes_mode = operation->list_op.tdes_mode;
2277 (*pj)->iop->csum_mode = operation->list_op.csum_mode;
2278 (*pj)->iop->ddesc_out = operation->list_op.outlist;
2279 (*pj)->iop->ddesc_in = operation->list_op.inlist;
2281 /* Setup DMA contexts. */
2282 (*pj)->iop->ctx_out.next = NULL;
2283 (*pj)->iop->ctx_out.eol = 1;
2284 (*pj)->iop->ctx_out.saved_data = operation->list_op.outlist;
2285 (*pj)->iop->ctx_out.saved_data_buf = operation->list_op.out_data_buf;
2287 (*pj)->iop->ctx_in.next = NULL;
2288 (*pj)->iop->ctx_in.eol = 1;
2289 (*pj)->iop->ctx_in.saved_data = operation->list_op.inlist;
2290 (*pj)->iop->ctx_in.saved_data_buf = operation->list_op.in_data_buf;
2291 } else {
2292 if ((err = cryptocop_setup_dma_list(operation, &(*pj)->iop, alloc_flag))) {
2293 DEBUG_API(printk("cryptocop_job_setup: cryptocop_setup_dma_list failed %d\n", err));
2294 kfree(*pj);
2295 return err;
2298 DEBUG(print_dma_descriptors((*pj)->iop));
2300 DEBUG(printk("cryptocop_job_setup, DMA list setup successful\n"));
2302 return 0;
2306 static int cryptocop_open(struct inode *inode, struct file *filp)
2308 int p = iminor(inode);
2310 if (p != CRYPTOCOP_MINOR) return -EINVAL;
2312 filp->private_data = NULL;
2313 return 0;
2317 static int cryptocop_release(struct inode *inode, struct file *filp)
2319 struct cryptocop_private *dev = filp->private_data;
2320 struct cryptocop_private *dev_next;
2322 while (dev){
2323 dev_next = dev->next;
2324 if (dev->sid != CRYPTOCOP_SESSION_ID_NONE) {
2325 (void)cryptocop_free_session(dev->sid);
2327 kfree(dev);
2328 dev = dev_next;
2331 return 0;
2335 static int cryptocop_ioctl_close_session(struct inode *inode, struct file *filp,
2336 unsigned int cmd, unsigned long arg)
2338 struct cryptocop_private *dev = filp->private_data;
2339 struct cryptocop_private *prev_dev = NULL;
2340 struct strcop_session_op *sess_op = (struct strcop_session_op *)arg;
2341 struct strcop_session_op sop;
2342 int err;
2344 DEBUG(printk("cryptocop_ioctl_close_session\n"));
2346 if (!access_ok(VERIFY_READ, sess_op, sizeof(struct strcop_session_op)))
2347 return -EFAULT;
2348 err = copy_from_user(&sop, sess_op, sizeof(struct strcop_session_op));
2349 if (err) return -EFAULT;
2351 while (dev && (dev->sid != sop.ses_id)) {
2352 prev_dev = dev;
2353 dev = dev->next;
2355 if (dev){
2356 if (prev_dev){
2357 prev_dev->next = dev->next;
2358 } else {
2359 filp->private_data = dev->next;
2361 err = cryptocop_free_session(dev->sid);
2362 if (err) return -EFAULT;
2363 } else {
2364 DEBUG_API(printk("cryptocop_ioctl_close_session: session %lld not found\n", sop.ses_id));
2365 return -EINVAL;
2367 return 0;
2371 static void ioctl_process_job_callback(struct cryptocop_operation *op, void*cb_data)
2373 struct ioctl_job_cb_ctx *jc = (struct ioctl_job_cb_ctx *)cb_data;
2375 DEBUG(printk("ioctl_process_job_callback: op=0x%p, cb_data=0x%p\n", op, cb_data));
2377 jc->processed = 1;
2378 wake_up(&cryptocop_ioc_process_wq);
2382 #define CRYPTOCOP_IOCTL_CIPHER_TID (1)
2383 #define CRYPTOCOP_IOCTL_DIGEST_TID (2)
2384 #define CRYPTOCOP_IOCTL_CSUM_TID (3)
2386 static size_t first_cfg_change_ix(struct strcop_crypto_op *crp_op)
2388 size_t ch_ix = 0;
2390 if (crp_op->do_cipher) ch_ix = crp_op->cipher_start;
2391 if (crp_op->do_digest && (crp_op->digest_start < ch_ix)) ch_ix = crp_op->digest_start;
2392 if (crp_op->do_csum && (crp_op->csum_start < ch_ix)) ch_ix = crp_op->csum_start;
2394 DEBUG(printk("first_cfg_change_ix: ix=%d\n", ch_ix));
2395 return ch_ix;
2399 static size_t next_cfg_change_ix(struct strcop_crypto_op *crp_op, size_t ix)
2401 size_t ch_ix = INT_MAX;
2402 size_t tmp_ix = 0;
2404 if (crp_op->do_cipher && ((crp_op->cipher_start + crp_op->cipher_len) > ix)){
2405 if (crp_op->cipher_start > ix) {
2406 ch_ix = crp_op->cipher_start;
2407 } else {
2408 ch_ix = crp_op->cipher_start + crp_op->cipher_len;
2411 if (crp_op->do_digest && ((crp_op->digest_start + crp_op->digest_len) > ix)){
2412 if (crp_op->digest_start > ix) {
2413 tmp_ix = crp_op->digest_start;
2414 } else {
2415 tmp_ix = crp_op->digest_start + crp_op->digest_len;
2417 if (tmp_ix < ch_ix) ch_ix = tmp_ix;
2419 if (crp_op->do_csum && ((crp_op->csum_start + crp_op->csum_len) > ix)){
2420 if (crp_op->csum_start > ix) {
2421 tmp_ix = crp_op->csum_start;
2422 } else {
2423 tmp_ix = crp_op->csum_start + crp_op->csum_len;
2425 if (tmp_ix < ch_ix) ch_ix = tmp_ix;
2427 if (ch_ix == INT_MAX) ch_ix = ix;
2428 DEBUG(printk("next_cfg_change_ix prev ix=%d, next ix=%d\n", ix, ch_ix));
2429 return ch_ix;
2433 /* Map map_length bytes from the pages starting on *pageix and *pageoffset to iovecs starting on *iovix.
2434 * Return -1 for ok, 0 for fail. */
2435 static int map_pages_to_iovec(struct iovec *iov, int iovlen, int *iovix, struct page **pages, int nopages, int *pageix, int *pageoffset, int map_length )
2437 int tmplen;
2439 assert(iov != NULL);
2440 assert(iovix != NULL);
2441 assert(pages != NULL);
2442 assert(pageix != NULL);
2443 assert(pageoffset != NULL);
2445 DEBUG(printk("map_pages_to_iovec, map_length=%d, iovlen=%d, *iovix=%d, nopages=%d, *pageix=%d, *pageoffset=%d\n", map_length, iovlen, *iovix, nopages, *pageix, *pageoffset));
2447 while (map_length > 0){
2448 DEBUG(printk("map_pages_to_iovec, map_length=%d, iovlen=%d, *iovix=%d, nopages=%d, *pageix=%d, *pageoffset=%d\n", map_length, iovlen, *iovix, nopages, *pageix, *pageoffset));
2449 if (*iovix >= iovlen){
2450 DEBUG_API(printk("map_page_to_iovec: *iovix=%d >= iovlen=%d\n", *iovix, iovlen));
2451 return 0;
2453 if (*pageix >= nopages){
2454 DEBUG_API(printk("map_page_to_iovec: *pageix=%d >= nopages=%d\n", *pageix, nopages));
2455 return 0;
2457 iov[*iovix].iov_base = (unsigned char*)page_address(pages[*pageix]) + *pageoffset;
2458 tmplen = PAGE_SIZE - *pageoffset;
2459 if (tmplen < map_length){
2460 (*pageoffset) = 0;
2461 (*pageix)++;
2462 } else {
2463 tmplen = map_length;
2464 (*pageoffset) += map_length;
2466 DEBUG(printk("mapping %d bytes from page %d (or %d) to iovec %d\n", tmplen, *pageix, *pageix-1, *iovix));
2467 iov[*iovix].iov_len = tmplen;
2468 map_length -= tmplen;
2469 (*iovix)++;
2471 DEBUG(printk("map_page_to_iovec, exit, *iovix=%d\n", *iovix));
2472 return -1;
2477 static int cryptocop_ioctl_process(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
2479 int i;
2480 struct cryptocop_private *dev = filp->private_data;
2481 struct strcop_crypto_op *crp_oper = (struct strcop_crypto_op *)arg;
2482 struct strcop_crypto_op oper = {0};
2483 int err = 0;
2484 struct cryptocop_operation *cop = NULL;
2486 struct ioctl_job_cb_ctx *jc = NULL;
2488 struct page **inpages = NULL;
2489 struct page **outpages = NULL;
2490 int noinpages = 0;
2491 int nooutpages = 0;
2493 struct cryptocop_desc descs[5]; /* Max 5 descriptors are needed, there are three transforms that
2494 * can get connected/disconnected on different places in the indata. */
2495 struct cryptocop_desc_cfg dcfgs[5*3];
2496 int desc_ix = 0;
2497 int dcfg_ix = 0;
2498 struct cryptocop_tfrm_cfg ciph_tcfg = {0};
2499 struct cryptocop_tfrm_cfg digest_tcfg = {0};
2500 struct cryptocop_tfrm_cfg csum_tcfg = {0};
2502 unsigned char *digest_result = NULL;
2503 int digest_length = 0;
2504 int cblocklen = 0;
2505 unsigned char csum_result[CSUM_BLOCK_LENGTH];
2506 struct cryptocop_session *sess;
2508 int iovlen = 0;
2509 int iovix = 0;
2510 int pageix = 0;
2511 int pageoffset = 0;
2513 size_t prev_ix = 0;
2514 size_t next_ix;
2516 int cipher_active, digest_active, csum_active;
2517 int end_digest, end_csum;
2518 int digest_done = 0;
2519 int cipher_done = 0;
2520 int csum_done = 0;
2522 DEBUG(printk("cryptocop_ioctl_process\n"));
2524 if (!access_ok(VERIFY_WRITE, crp_oper, sizeof(struct strcop_crypto_op))){
2525 DEBUG_API(printk("cryptocop_ioctl_process: !access_ok crp_oper!\n"));
2526 return -EFAULT;
2528 if (copy_from_user(&oper, crp_oper, sizeof(struct strcop_crypto_op))) {
2529 DEBUG_API(printk("cryptocop_ioctl_process: copy_from_user\n"));
2530 return -EFAULT;
2532 DEBUG(print_strcop_crypto_op(&oper));
2534 while (dev && dev->sid != oper.ses_id) dev = dev->next;
2535 if (!dev){
2536 DEBUG_API(printk("cryptocop_ioctl_process: session %lld not found\n", oper.ses_id));
2537 return -EINVAL;
2540 /* Check buffers. */
2541 if (((oper.indata + oper.inlen) < oper.indata) || ((oper.cipher_outdata + oper.cipher_outlen) < oper.cipher_outdata)){
2542 DEBUG_API(printk("cryptocop_ioctl_process: user buffers wrapped around, bad user!\n"));
2543 return -EINVAL;
2546 if (!access_ok(VERIFY_WRITE, oper.cipher_outdata, oper.cipher_outlen)){
2547 DEBUG_API(printk("cryptocop_ioctl_process: !access_ok out data!\n"));
2548 return -EFAULT;
2550 if (!access_ok(VERIFY_READ, oper.indata, oper.inlen)){
2551 DEBUG_API(printk("cryptocop_ioctl_process: !access_ok in data!\n"));
2552 return -EFAULT;
2555 cop = kmalloc(sizeof(struct cryptocop_operation), GFP_KERNEL);
2556 if (!cop) {
2557 DEBUG_API(printk("cryptocop_ioctl_process: kmalloc\n"));
2558 return -ENOMEM;
2560 jc = kmalloc(sizeof(struct ioctl_job_cb_ctx), GFP_KERNEL);
2561 if (!jc) {
2562 DEBUG_API(printk("cryptocop_ioctl_process: kmalloc\n"));
2563 err = -ENOMEM;
2564 goto error_cleanup;
2566 jc->processed = 0;
2568 cop->cb_data = jc;
2569 cop->cb = ioctl_process_job_callback;
2570 cop->operation_status = 0;
2571 cop->use_dmalists = 0;
2572 cop->in_interrupt = 0;
2573 cop->fast_callback = 0;
2574 cop->tfrm_op.tfrm_cfg = NULL;
2575 cop->tfrm_op.desc = NULL;
2576 cop->tfrm_op.indata = NULL;
2577 cop->tfrm_op.incount = 0;
2578 cop->tfrm_op.inlen = 0;
2579 cop->tfrm_op.outdata = NULL;
2580 cop->tfrm_op.outcount = 0;
2581 cop->tfrm_op.outlen = 0;
2583 sess = get_session(oper.ses_id);
2584 if (!sess){
2585 DEBUG_API(printk("cryptocop_ioctl_process: bad session id.\n"));
2586 kfree(cop);
2587 kfree(jc);
2588 return -EINVAL;
2591 if (oper.do_cipher) {
2592 unsigned int cipher_outlen = 0;
2593 struct cryptocop_transform_ctx *tc = get_transform_ctx(sess, CRYPTOCOP_IOCTL_CIPHER_TID);
2594 if (!tc) {
2595 DEBUG_API(printk("cryptocop_ioctl_process: no cipher transform in session.\n"));
2596 err = -EINVAL;
2597 goto error_cleanup;
2599 ciph_tcfg.tid = CRYPTOCOP_IOCTL_CIPHER_TID;
2600 ciph_tcfg.inject_ix = 0;
2601 ciph_tcfg.flags = 0;
2602 if ((oper.cipher_start < 0) || (oper.cipher_len <= 0) || (oper.cipher_start > oper.inlen) || ((oper.cipher_start + oper.cipher_len) > oper.inlen)){
2603 DEBUG_API(printk("cryptocop_ioctl_process: bad cipher length\n"));
2604 kfree(cop);
2605 kfree(jc);
2606 return -EINVAL;
2608 cblocklen = tc->init.alg == cryptocop_alg_aes ? AES_BLOCK_LENGTH : DES_BLOCK_LENGTH;
2609 if (oper.cipher_len % cblocklen) {
2610 kfree(cop);
2611 kfree(jc);
2612 DEBUG_API(printk("cryptocop_ioctl_process: cipher inlength not multiple of block length.\n"));
2613 return -EINVAL;
2615 cipher_outlen = oper.cipher_len;
2616 if (tc->init.cipher_mode == cryptocop_cipher_mode_cbc){
2617 if (oper.cipher_explicit) {
2618 ciph_tcfg.flags |= CRYPTOCOP_EXPLICIT_IV;
2619 memcpy(ciph_tcfg.iv, oper.cipher_iv, cblocklen);
2620 } else {
2621 cipher_outlen = oper.cipher_len - cblocklen;
2623 } else {
2624 if (oper.cipher_explicit){
2625 kfree(cop);
2626 kfree(jc);
2627 DEBUG_API(printk("cryptocop_ioctl_process: explicit_iv when not CBC mode\n"));
2628 return -EINVAL;
2631 if (oper.cipher_outlen != cipher_outlen) {
2632 kfree(cop);
2633 kfree(jc);
2634 DEBUG_API(printk("cryptocop_ioctl_process: cipher_outlen incorrect, should be %d not %d.\n", cipher_outlen, oper.cipher_outlen));
2635 return -EINVAL;
2638 if (oper.decrypt){
2639 ciph_tcfg.flags |= CRYPTOCOP_DECRYPT;
2640 } else {
2641 ciph_tcfg.flags |= CRYPTOCOP_ENCRYPT;
2643 ciph_tcfg.next = cop->tfrm_op.tfrm_cfg;
2644 cop->tfrm_op.tfrm_cfg = &ciph_tcfg;
2646 if (oper.do_digest){
2647 struct cryptocop_transform_ctx *tc = get_transform_ctx(sess, CRYPTOCOP_IOCTL_DIGEST_TID);
2648 if (!tc) {
2649 DEBUG_API(printk("cryptocop_ioctl_process: no digest transform in session.\n"));
2650 err = -EINVAL;
2651 goto error_cleanup;
2653 digest_length = tc->init.alg == cryptocop_alg_md5 ? 16 : 20;
2654 digest_result = kmalloc(digest_length, GFP_KERNEL);
2655 if (!digest_result) {
2656 DEBUG_API(printk("cryptocop_ioctl_process: kmalloc digest_result\n"));
2657 err = -EINVAL;
2658 goto error_cleanup;
2660 DEBUG(memset(digest_result, 0xff, digest_length));
2662 digest_tcfg.tid = CRYPTOCOP_IOCTL_DIGEST_TID;
2663 digest_tcfg.inject_ix = 0;
2664 ciph_tcfg.inject_ix += digest_length;
2665 if ((oper.digest_start < 0) || (oper.digest_len <= 0) || (oper.digest_start > oper.inlen) || ((oper.digest_start + oper.digest_len) > oper.inlen)){
2666 DEBUG_API(printk("cryptocop_ioctl_process: bad digest length\n"));
2667 err = -EINVAL;
2668 goto error_cleanup;
2671 digest_tcfg.next = cop->tfrm_op.tfrm_cfg;
2672 cop->tfrm_op.tfrm_cfg = &digest_tcfg;
2674 if (oper.do_csum){
2675 csum_tcfg.tid = CRYPTOCOP_IOCTL_CSUM_TID;
2676 csum_tcfg.inject_ix = digest_length;
2677 ciph_tcfg.inject_ix += 2;
2679 if ((oper.csum_start < 0) || (oper.csum_len <= 0) || (oper.csum_start > oper.inlen) || ((oper.csum_start + oper.csum_len) > oper.inlen)){
2680 DEBUG_API(printk("cryptocop_ioctl_process: bad csum length\n"));
2681 kfree(cop);
2682 kfree(jc);
2683 return -EINVAL;
2686 csum_tcfg.next = cop->tfrm_op.tfrm_cfg;
2687 cop->tfrm_op.tfrm_cfg = &csum_tcfg;
2690 prev_ix = first_cfg_change_ix(&oper);
2691 if (prev_ix > oper.inlen) {
2692 DEBUG_API(printk("cryptocop_ioctl_process: length mismatch\n"));
2693 nooutpages = noinpages = 0;
2694 err = -EINVAL;
2695 goto error_cleanup;
2697 DEBUG(printk("cryptocop_ioctl_process: inlen=%d, cipher_outlen=%d\n", oper.inlen, oper.cipher_outlen));
2699 /* Map user pages for in and out data of the operation. */
2700 noinpages = (((unsigned long int)(oper.indata + prev_ix) & ~PAGE_MASK) + oper.inlen - 1 - prev_ix + ~PAGE_MASK) >> PAGE_SHIFT;
2701 DEBUG(printk("cryptocop_ioctl_process: noinpages=%d\n", noinpages));
2702 inpages = kmalloc(noinpages * sizeof(struct page*), GFP_KERNEL);
2703 if (!inpages){
2704 DEBUG_API(printk("cryptocop_ioctl_process: kmalloc inpages\n"));
2705 nooutpages = noinpages = 0;
2706 err = -ENOMEM;
2707 goto error_cleanup;
2709 if (oper.do_cipher){
2710 nooutpages = (((unsigned long int)oper.cipher_outdata & ~PAGE_MASK) + oper.cipher_outlen - 1 + ~PAGE_MASK) >> PAGE_SHIFT;
2711 DEBUG(printk("cryptocop_ioctl_process: nooutpages=%d\n", nooutpages));
2712 outpages = kmalloc(nooutpages * sizeof(struct page*), GFP_KERNEL);
2713 if (!outpages){
2714 DEBUG_API(printk("cryptocop_ioctl_process: kmalloc outpages\n"));
2715 nooutpages = noinpages = 0;
2716 err = -ENOMEM;
2717 goto error_cleanup;
2721 /* Acquire the mm page semaphore. */
2722 down_read(&current->mm->mmap_sem);
2724 err = get_user_pages(current,
2725 current->mm,
2726 (unsigned long int)(oper.indata + prev_ix),
2727 noinpages,
2728 0, /* read access only for in data */
2729 0, /* no force */
2730 inpages,
2731 NULL);
2733 if (err < 0) {
2734 up_read(&current->mm->mmap_sem);
2735 nooutpages = noinpages = 0;
2736 DEBUG_API(printk("cryptocop_ioctl_process: get_user_pages indata\n"));
2737 goto error_cleanup;
2739 noinpages = err;
2740 if (oper.do_cipher){
2741 err = get_user_pages(current,
2742 current->mm,
2743 (unsigned long int)oper.cipher_outdata,
2744 nooutpages,
2745 1, /* write access for out data */
2746 0, /* no force */
2747 outpages,
2748 NULL);
2749 up_read(&current->mm->mmap_sem);
2750 if (err < 0) {
2751 nooutpages = 0;
2752 DEBUG_API(printk("cryptocop_ioctl_process: get_user_pages outdata\n"));
2753 goto error_cleanup;
2755 nooutpages = err;
2756 } else {
2757 up_read(&current->mm->mmap_sem);
2760 /* Add 6 to nooutpages to make room for possibly inserted buffers for storing digest and
2761 * csum output and splits when units are (dis-)connected. */
2762 cop->tfrm_op.indata = kmalloc((noinpages) * sizeof(struct iovec), GFP_KERNEL);
2763 cop->tfrm_op.outdata = kmalloc((6 + nooutpages) * sizeof(struct iovec), GFP_KERNEL);
2764 if (!cop->tfrm_op.indata || !cop->tfrm_op.outdata) {
2765 DEBUG_API(printk("cryptocop_ioctl_process: kmalloc iovecs\n"));
2766 err = -ENOMEM;
2767 goto error_cleanup;
2770 cop->tfrm_op.inlen = oper.inlen - prev_ix;
2771 cop->tfrm_op.outlen = 0;
2772 if (oper.do_cipher) cop->tfrm_op.outlen += oper.cipher_outlen;
2773 if (oper.do_digest) cop->tfrm_op.outlen += digest_length;
2774 if (oper.do_csum) cop->tfrm_op.outlen += 2;
2776 /* Setup the in iovecs. */
2777 cop->tfrm_op.incount = noinpages;
2778 if (noinpages > 1){
2779 size_t tmplen = cop->tfrm_op.inlen;
2781 cop->tfrm_op.indata[0].iov_len = PAGE_SIZE - ((unsigned long int)(oper.indata + prev_ix) & ~PAGE_MASK);
2782 cop->tfrm_op.indata[0].iov_base = (unsigned char*)page_address(inpages[0]) + ((unsigned long int)(oper.indata + prev_ix) & ~PAGE_MASK);
2783 tmplen -= cop->tfrm_op.indata[0].iov_len;
2784 for (i = 1; i<noinpages; i++){
2785 cop->tfrm_op.indata[i].iov_len = tmplen < PAGE_SIZE ? tmplen : PAGE_SIZE;
2786 cop->tfrm_op.indata[i].iov_base = (unsigned char*)page_address(inpages[i]);
2787 tmplen -= PAGE_SIZE;
2789 } else {
2790 cop->tfrm_op.indata[0].iov_len = oper.inlen - prev_ix;
2791 cop->tfrm_op.indata[0].iov_base = (unsigned char*)page_address(inpages[0]) + ((unsigned long int)(oper.indata + prev_ix) & ~PAGE_MASK);
2794 iovlen = nooutpages + 6;
2795 pageoffset = oper.do_cipher ? ((unsigned long int)oper.cipher_outdata & ~PAGE_MASK) : 0;
2797 next_ix = next_cfg_change_ix(&oper, prev_ix);
2798 if (prev_ix == next_ix){
2799 DEBUG_API(printk("cryptocop_ioctl_process: length configuration broken.\n"));
2800 err = -EINVAL; /* This should be impossible barring bugs. */
2801 goto error_cleanup;
2803 while (prev_ix != next_ix){
2804 end_digest = end_csum = cipher_active = digest_active = csum_active = 0;
2805 descs[desc_ix].cfg = NULL;
2806 descs[desc_ix].length = next_ix - prev_ix;
2808 if (oper.do_cipher && (oper.cipher_start < next_ix) && (prev_ix < (oper.cipher_start + oper.cipher_len))) {
2809 dcfgs[dcfg_ix].tid = CRYPTOCOP_IOCTL_CIPHER_TID;
2810 dcfgs[dcfg_ix].src = cryptocop_source_dma;
2811 cipher_active = 1;
2813 if (next_ix == (oper.cipher_start + oper.cipher_len)){
2814 cipher_done = 1;
2815 dcfgs[dcfg_ix].last = 1;
2816 } else {
2817 dcfgs[dcfg_ix].last = 0;
2819 dcfgs[dcfg_ix].next = descs[desc_ix].cfg;
2820 descs[desc_ix].cfg = &dcfgs[dcfg_ix];
2821 ++dcfg_ix;
2823 if (oper.do_digest && (oper.digest_start < next_ix) && (prev_ix < (oper.digest_start + oper.digest_len))) {
2824 digest_active = 1;
2825 dcfgs[dcfg_ix].tid = CRYPTOCOP_IOCTL_DIGEST_TID;
2826 dcfgs[dcfg_ix].src = cryptocop_source_dma;
2827 if (next_ix == (oper.digest_start + oper.digest_len)){
2828 assert(!digest_done);
2829 digest_done = 1;
2830 dcfgs[dcfg_ix].last = 1;
2831 } else {
2832 dcfgs[dcfg_ix].last = 0;
2834 dcfgs[dcfg_ix].next = descs[desc_ix].cfg;
2835 descs[desc_ix].cfg = &dcfgs[dcfg_ix];
2836 ++dcfg_ix;
2838 if (oper.do_csum && (oper.csum_start < next_ix) && (prev_ix < (oper.csum_start + oper.csum_len))){
2839 csum_active = 1;
2840 dcfgs[dcfg_ix].tid = CRYPTOCOP_IOCTL_CSUM_TID;
2841 dcfgs[dcfg_ix].src = cryptocop_source_dma;
2842 if (next_ix == (oper.csum_start + oper.csum_len)){
2843 csum_done = 1;
2844 dcfgs[dcfg_ix].last = 1;
2845 } else {
2846 dcfgs[dcfg_ix].last = 0;
2848 dcfgs[dcfg_ix].next = descs[desc_ix].cfg;
2849 descs[desc_ix].cfg = &dcfgs[dcfg_ix];
2850 ++dcfg_ix;
2852 if (!descs[desc_ix].cfg){
2853 DEBUG_API(printk("cryptocop_ioctl_process: data segment %d (%d to %d) had no active transforms\n", desc_ix, prev_ix, next_ix));
2854 err = -EINVAL;
2855 goto error_cleanup;
2857 descs[desc_ix].next = &(descs[desc_ix]) + 1;
2858 ++desc_ix;
2859 prev_ix = next_ix;
2860 next_ix = next_cfg_change_ix(&oper, prev_ix);
2862 if (desc_ix > 0){
2863 descs[desc_ix-1].next = NULL;
2864 } else {
2865 descs[0].next = NULL;
2867 if (oper.do_digest) {
2868 DEBUG(printk("cryptocop_ioctl_process: mapping %d byte digest output to iovec %d\n", digest_length, iovix));
2869 /* Add outdata iovec, length == <length of type of digest> */
2870 cop->tfrm_op.outdata[iovix].iov_base = digest_result;
2871 cop->tfrm_op.outdata[iovix].iov_len = digest_length;
2872 ++iovix;
2874 if (oper.do_csum) {
2875 /* Add outdata iovec, length == 2, the length of csum. */
2876 DEBUG(printk("cryptocop_ioctl_process: mapping 2 byte csum output to iovec %d\n", iovix));
2877 /* Add outdata iovec, length == <length of type of digest> */
2878 cop->tfrm_op.outdata[iovix].iov_base = csum_result;
2879 cop->tfrm_op.outdata[iovix].iov_len = 2;
2880 ++iovix;
2882 if (oper.do_cipher) {
2883 if (!map_pages_to_iovec(cop->tfrm_op.outdata, iovlen, &iovix, outpages, nooutpages, &pageix, &pageoffset, oper.cipher_outlen)){
2884 DEBUG_API(printk("cryptocop_ioctl_process: failed to map pages to iovec.\n"));
2885 err = -ENOSYS; /* This should be impossible barring bugs. */
2886 goto error_cleanup;
2889 DEBUG(printk("cryptocop_ioctl_process: setting cop->tfrm_op.outcount %d\n", iovix));
2890 cop->tfrm_op.outcount = iovix;
2891 assert(iovix <= (nooutpages + 6));
2893 cop->sid = oper.ses_id;
2894 cop->tfrm_op.desc = &descs[0];
2896 DEBUG(printk("cryptocop_ioctl_process: inserting job, cb_data=0x%p\n", cop->cb_data));
2898 if ((err = cryptocop_job_queue_insert_user_job(cop)) != 0) {
2899 DEBUG_API(printk("cryptocop_ioctl_process: insert job %d\n", err));
2900 err = -EINVAL;
2901 goto error_cleanup;
2904 DEBUG(printk("cryptocop_ioctl_process: begin wait for result\n"));
2906 wait_event(cryptocop_ioc_process_wq, (jc->processed != 0));
2907 DEBUG(printk("cryptocop_ioctl_process: end wait for result\n"));
2908 if (!jc->processed){
2909 printk(KERN_WARNING "cryptocop_ioctl_process: job not processed at completion\n");
2910 err = -EIO;
2911 goto error_cleanup;
2914 /* Job process done. Cipher output should already be correct in job so no post processing of outdata. */
2915 DEBUG(printk("cryptocop_ioctl_process: operation_status = %d\n", cop->operation_status));
2916 if (cop->operation_status == 0){
2917 if (oper.do_digest){
2918 DEBUG(printk("cryptocop_ioctl_process: copy %d bytes digest to user\n", digest_length));
2919 err = copy_to_user((unsigned char*)crp_oper + offsetof(struct strcop_crypto_op, digest), digest_result, digest_length);
2920 if (0 != err){
2921 DEBUG_API(printk("cryptocop_ioctl_process: copy_to_user, digest length %d, err %d\n", digest_length, err));
2922 err = -EFAULT;
2923 goto error_cleanup;
2926 if (oper.do_csum){
2927 DEBUG(printk("cryptocop_ioctl_process: copy 2 bytes checksum to user\n"));
2928 err = copy_to_user((unsigned char*)crp_oper + offsetof(struct strcop_crypto_op, csum), csum_result, 2);
2929 if (0 != err){
2930 DEBUG_API(printk("cryptocop_ioctl_process: copy_to_user, csum, err %d\n", err));
2931 err = -EFAULT;
2932 goto error_cleanup;
2935 err = 0;
2936 } else {
2937 DEBUG(printk("cryptocop_ioctl_process: returning err = operation_status = %d\n", cop->operation_status));
2938 err = cop->operation_status;
2941 error_cleanup:
2942 /* Release page caches. */
2943 for (i = 0; i < noinpages; i++){
2944 put_page(inpages[i]);
2946 for (i = 0; i < nooutpages; i++){
2947 int spdl_err;
2948 /* Mark output pages dirty. */
2949 spdl_err = set_page_dirty_lock(outpages[i]);
2950 DEBUG(if (spdl_err < 0)printk("cryptocop_ioctl_process: set_page_dirty_lock returned %d\n", spdl_err));
2952 for (i = 0; i < nooutpages; i++){
2953 put_page(outpages[i]);
2956 kfree(digest_result);
2957 kfree(inpages);
2958 kfree(outpages);
2959 if (cop){
2960 kfree(cop->tfrm_op.indata);
2961 kfree(cop->tfrm_op.outdata);
2962 kfree(cop);
2964 kfree(jc);
2966 DEBUG(print_lock_status());
2968 return err;
2972 static int cryptocop_ioctl_create_session(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
2974 cryptocop_session_id sid;
2975 int err;
2976 struct cryptocop_private *dev;
2977 struct strcop_session_op *sess_op = (struct strcop_session_op *)arg;
2978 struct strcop_session_op sop;
2979 struct cryptocop_transform_init *tis = NULL;
2980 struct cryptocop_transform_init ti_cipher = {0};
2981 struct cryptocop_transform_init ti_digest = {0};
2982 struct cryptocop_transform_init ti_csum = {0};
2984 if (!access_ok(VERIFY_WRITE, sess_op, sizeof(struct strcop_session_op)))
2985 return -EFAULT;
2986 err = copy_from_user(&sop, sess_op, sizeof(struct strcop_session_op));
2987 if (err) return -EFAULT;
2988 if (sop.cipher != cryptocop_cipher_none) {
2989 if (!access_ok(VERIFY_READ, sop.key, sop.keylen)) return -EFAULT;
2991 DEBUG(printk("cryptocop_ioctl_create_session, sess_op:\n"));
2993 DEBUG(printk("\tcipher:%d\n"
2994 "\tcipher_mode:%d\n"
2995 "\tdigest:%d\n"
2996 "\tcsum:%d\n",
2997 (int)sop.cipher,
2998 (int)sop.cmode,
2999 (int)sop.digest,
3000 (int)sop.csum));
3002 if (sop.cipher != cryptocop_cipher_none){
3003 /* Init the cipher. */
3004 switch (sop.cipher){
3005 case cryptocop_cipher_des:
3006 ti_cipher.alg = cryptocop_alg_des;
3007 break;
3008 case cryptocop_cipher_3des:
3009 ti_cipher.alg = cryptocop_alg_3des;
3010 break;
3011 case cryptocop_cipher_aes:
3012 ti_cipher.alg = cryptocop_alg_aes;
3013 break;
3014 default:
3015 DEBUG_API(printk("create session, bad cipher algorithm %d\n", sop.cipher));
3016 return -EINVAL;
3018 DEBUG(printk("setting cipher transform %d\n", ti_cipher.alg));
3019 copy_from_user(ti_cipher.key, sop.key, sop.keylen/8);
3020 ti_cipher.keylen = sop.keylen;
3021 switch (sop.cmode){
3022 case cryptocop_cipher_mode_cbc:
3023 case cryptocop_cipher_mode_ecb:
3024 ti_cipher.cipher_mode = sop.cmode;
3025 break;
3026 default:
3027 DEBUG_API(printk("create session, bad cipher mode %d\n", sop.cmode));
3028 return -EINVAL;
3030 DEBUG(printk("cryptocop_ioctl_create_session: setting CBC mode %d\n", ti_cipher.cipher_mode));
3031 switch (sop.des3_mode){
3032 case cryptocop_3des_eee:
3033 case cryptocop_3des_eed:
3034 case cryptocop_3des_ede:
3035 case cryptocop_3des_edd:
3036 case cryptocop_3des_dee:
3037 case cryptocop_3des_ded:
3038 case cryptocop_3des_dde:
3039 case cryptocop_3des_ddd:
3040 ti_cipher.tdes_mode = sop.des3_mode;
3041 break;
3042 default:
3043 DEBUG_API(printk("create session, bad 3DES mode %d\n", sop.des3_mode));
3044 return -EINVAL;
3046 ti_cipher.tid = CRYPTOCOP_IOCTL_CIPHER_TID;
3047 ti_cipher.next = tis;
3048 tis = &ti_cipher;
3049 } /* if (sop.cipher != cryptocop_cipher_none) */
3050 if (sop.digest != cryptocop_digest_none){
3051 DEBUG(printk("setting digest transform\n"));
3052 switch (sop.digest){
3053 case cryptocop_digest_md5:
3054 ti_digest.alg = cryptocop_alg_md5;
3055 break;
3056 case cryptocop_digest_sha1:
3057 ti_digest.alg = cryptocop_alg_sha1;
3058 break;
3059 default:
3060 DEBUG_API(printk("create session, bad digest algorithm %d\n", sop.digest));
3061 return -EINVAL;
3063 ti_digest.tid = CRYPTOCOP_IOCTL_DIGEST_TID;
3064 ti_digest.next = tis;
3065 tis = &ti_digest;
3066 } /* if (sop.digest != cryptocop_digest_none) */
3067 if (sop.csum != cryptocop_csum_none){
3068 DEBUG(printk("setting csum transform\n"));
3069 switch (sop.csum){
3070 case cryptocop_csum_le:
3071 case cryptocop_csum_be:
3072 ti_csum.csum_mode = sop.csum;
3073 break;
3074 default:
3075 DEBUG_API(printk("create session, bad checksum algorithm %d\n", sop.csum));
3076 return -EINVAL;
3078 ti_csum.alg = cryptocop_alg_csum;
3079 ti_csum.tid = CRYPTOCOP_IOCTL_CSUM_TID;
3080 ti_csum.next = tis;
3081 tis = &ti_csum;
3082 } /* (sop.csum != cryptocop_csum_none) */
3083 dev = kmalloc(sizeof(struct cryptocop_private), GFP_KERNEL);
3084 if (!dev){
3085 DEBUG_API(printk("create session, alloc dev\n"));
3086 return -ENOMEM;
3089 err = cryptocop_new_session(&sid, tis, GFP_KERNEL);
3090 DEBUG({ if (err) printk("create session, cryptocop_new_session %d\n", err);});
3092 if (err) {
3093 kfree(dev);
3094 return err;
3096 sess_op->ses_id = sid;
3097 dev->sid = sid;
3098 dev->next = filp->private_data;
3099 filp->private_data = dev;
3101 return 0;
3104 static int cryptocop_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
3106 int err = 0;
3107 if (_IOC_TYPE(cmd) != ETRAXCRYPTOCOP_IOCTYPE) {
3108 DEBUG_API(printk("cryptocop_ioctl: wrong type\n"));
3109 return -ENOTTY;
3111 if (_IOC_NR(cmd) > CRYPTOCOP_IO_MAXNR){
3112 return -ENOTTY;
3114 /* Access check of the argument. Some commands, e.g. create session and process op,
3115 needs additional checks. Those are handled in the command handling functions. */
3116 if (_IOC_DIR(cmd) & _IOC_READ)
3117 err = !access_ok(VERIFY_WRITE, (void *)arg, _IOC_SIZE(cmd));
3118 else if (_IOC_DIR(cmd) & _IOC_WRITE)
3119 err = !access_ok(VERIFY_READ, (void *)arg, _IOC_SIZE(cmd));
3120 if (err) return -EFAULT;
3122 switch (cmd) {
3123 case CRYPTOCOP_IO_CREATE_SESSION:
3124 return cryptocop_ioctl_create_session(inode, filp, cmd, arg);
3125 case CRYPTOCOP_IO_CLOSE_SESSION:
3126 return cryptocop_ioctl_close_session(inode, filp, cmd, arg);
3127 case CRYPTOCOP_IO_PROCESS_OP:
3128 return cryptocop_ioctl_process(inode, filp, cmd, arg);
3129 default:
3130 DEBUG_API(printk("cryptocop_ioctl: unknown command\n"));
3131 return -ENOTTY;
3133 return 0;
3137 #ifdef LDEBUG
3138 static void print_dma_descriptors(struct cryptocop_int_operation *iop)
3140 struct cryptocop_dma_desc *cdesc_out = iop->cdesc_out;
3141 struct cryptocop_dma_desc *cdesc_in = iop->cdesc_in;
3142 int i;
3144 printk("print_dma_descriptors start\n");
3146 printk("iop:\n");
3147 printk("\tsid: 0x%lld\n", iop->sid);
3149 printk("\tcdesc_out: 0x%p\n", iop->cdesc_out);
3150 printk("\tcdesc_in: 0x%p\n", iop->cdesc_in);
3151 printk("\tddesc_out: 0x%p\n", iop->ddesc_out);
3152 printk("\tddesc_in: 0x%p\n", iop->ddesc_in);
3154 printk("\niop->ctx_out: 0x%p phys: 0x%p\n", &iop->ctx_out, (char*)virt_to_phys(&iop->ctx_out));
3155 printk("\tnext: 0x%p\n"
3156 "\tsaved_data: 0x%p\n"
3157 "\tsaved_data_buf: 0x%p\n",
3158 iop->ctx_out.next,
3159 iop->ctx_out.saved_data,
3160 iop->ctx_out.saved_data_buf);
3162 printk("\niop->ctx_in: 0x%p phys: 0x%p\n", &iop->ctx_in, (char*)virt_to_phys(&iop->ctx_in));
3163 printk("\tnext: 0x%p\n"
3164 "\tsaved_data: 0x%p\n"
3165 "\tsaved_data_buf: 0x%p\n",
3166 iop->ctx_in.next,
3167 iop->ctx_in.saved_data,
3168 iop->ctx_in.saved_data_buf);
3170 i = 0;
3171 while (cdesc_out) {
3172 dma_descr_data *td;
3173 printk("cdesc_out %d, desc=0x%p\n", i, cdesc_out->dma_descr);
3174 printk("\n\tvirt_to_phys(desc): 0x%p\n", (char*)virt_to_phys(cdesc_out->dma_descr));
3175 td = cdesc_out->dma_descr;
3176 printk("\n\tbuf: 0x%p\n"
3177 "\tafter: 0x%p\n"
3178 "\tmd: 0x%04x\n"
3179 "\tnext: 0x%p\n",
3180 td->buf,
3181 td->after,
3182 td->md,
3183 td->next);
3184 printk("flags:\n"
3185 "\twait:\t%d\n"
3186 "\teol:\t%d\n"
3187 "\touteop:\t%d\n"
3188 "\tineop:\t%d\n"
3189 "\tintr:\t%d\n",
3190 td->wait,
3191 td->eol,
3192 td->out_eop,
3193 td->in_eop,
3194 td->intr);
3195 cdesc_out = cdesc_out->next;
3196 i++;
3198 i = 0;
3199 while (cdesc_in) {
3200 dma_descr_data *td;
3201 printk("cdesc_in %d, desc=0x%p\n", i, cdesc_in->dma_descr);
3202 printk("\n\tvirt_to_phys(desc): 0x%p\n", (char*)virt_to_phys(cdesc_in->dma_descr));
3203 td = cdesc_in->dma_descr;
3204 printk("\n\tbuf: 0x%p\n"
3205 "\tafter: 0x%p\n"
3206 "\tmd: 0x%04x\n"
3207 "\tnext: 0x%p\n",
3208 td->buf,
3209 td->after,
3210 td->md,
3211 td->next);
3212 printk("flags:\n"
3213 "\twait:\t%d\n"
3214 "\teol:\t%d\n"
3215 "\touteop:\t%d\n"
3216 "\tineop:\t%d\n"
3217 "\tintr:\t%d\n",
3218 td->wait,
3219 td->eol,
3220 td->out_eop,
3221 td->in_eop,
3222 td->intr);
3223 cdesc_in = cdesc_in->next;
3224 i++;
3227 printk("print_dma_descriptors end\n");
3231 static void print_strcop_crypto_op(struct strcop_crypto_op *cop)
3233 printk("print_strcop_crypto_op, 0x%p\n", cop);
3235 /* Indata. */
3236 printk("indata=0x%p\n"
3237 "inlen=%d\n"
3238 "do_cipher=%d\n"
3239 "decrypt=%d\n"
3240 "cipher_explicit=%d\n"
3241 "cipher_start=%d\n"
3242 "cipher_len=%d\n"
3243 "outdata=0x%p\n"
3244 "outlen=%d\n",
3245 cop->indata,
3246 cop->inlen,
3247 cop->do_cipher,
3248 cop->decrypt,
3249 cop->cipher_explicit,
3250 cop->cipher_start,
3251 cop->cipher_len,
3252 cop->cipher_outdata,
3253 cop->cipher_outlen);
3255 printk("do_digest=%d\n"
3256 "digest_start=%d\n"
3257 "digest_len=%d\n",
3258 cop->do_digest,
3259 cop->digest_start,
3260 cop->digest_len);
3262 printk("do_csum=%d\n"
3263 "csum_start=%d\n"
3264 "csum_len=%d\n",
3265 cop->do_csum,
3266 cop->csum_start,
3267 cop->csum_len);
3270 static void print_cryptocop_operation(struct cryptocop_operation *cop)
3272 struct cryptocop_desc *d;
3273 struct cryptocop_tfrm_cfg *tc;
3274 struct cryptocop_desc_cfg *dc;
3275 int i;
3277 printk("print_cryptocop_operation, cop=0x%p\n\n", cop);
3278 printk("sid: %lld\n", cop->sid);
3279 printk("operation_status=%d\n"
3280 "use_dmalists=%d\n"
3281 "in_interrupt=%d\n"
3282 "fast_callback=%d\n",
3283 cop->operation_status,
3284 cop->use_dmalists,
3285 cop->in_interrupt,
3286 cop->fast_callback);
3288 if (cop->use_dmalists){
3289 print_user_dma_lists(&cop->list_op);
3290 } else {
3291 printk("cop->tfrm_op\n"
3292 "tfrm_cfg=0x%p\n"
3293 "desc=0x%p\n"
3294 "indata=0x%p\n"
3295 "incount=%d\n"
3296 "inlen=%d\n"
3297 "outdata=0x%p\n"
3298 "outcount=%d\n"
3299 "outlen=%d\n\n",
3300 cop->tfrm_op.tfrm_cfg,
3301 cop->tfrm_op.desc,
3302 cop->tfrm_op.indata,
3303 cop->tfrm_op.incount,
3304 cop->tfrm_op.inlen,
3305 cop->tfrm_op.outdata,
3306 cop->tfrm_op.outcount,
3307 cop->tfrm_op.outlen);
3309 tc = cop->tfrm_op.tfrm_cfg;
3310 while (tc){
3311 printk("tfrm_cfg, 0x%p\n"
3312 "tid=%d\n"
3313 "flags=%d\n"
3314 "inject_ix=%d\n"
3315 "next=0x%p\n",
3317 tc->tid,
3318 tc->flags,
3319 tc->inject_ix,
3320 tc->next);
3321 tc = tc->next;
3323 d = cop->tfrm_op.desc;
3324 while (d){
3325 printk("\n======================desc, 0x%p\n"
3326 "length=%d\n"
3327 "cfg=0x%p\n"
3328 "next=0x%p\n",
3330 d->length,
3331 d->cfg,
3332 d->next);
3333 dc = d->cfg;
3334 while (dc){
3335 printk("=========desc_cfg, 0x%p\n"
3336 "tid=%d\n"
3337 "src=%d\n"
3338 "last=%d\n"
3339 "next=0x%p\n",
3341 dc->tid,
3342 dc->src,
3343 dc->last,
3344 dc->next);
3345 dc = dc->next;
3347 d = d->next;
3349 printk("\n====iniov\n");
3350 for (i = 0; i < cop->tfrm_op.incount; i++){
3351 printk("indata[%d]\n"
3352 "base=0x%p\n"
3353 "len=%d\n",
3355 cop->tfrm_op.indata[i].iov_base,
3356 cop->tfrm_op.indata[i].iov_len);
3358 printk("\n====outiov\n");
3359 for (i = 0; i < cop->tfrm_op.outcount; i++){
3360 printk("outdata[%d]\n"
3361 "base=0x%p\n"
3362 "len=%d\n",
3364 cop->tfrm_op.outdata[i].iov_base,
3365 cop->tfrm_op.outdata[i].iov_len);
3368 printk("------------end print_cryptocop_operation\n");
3372 static void print_user_dma_lists(struct cryptocop_dma_list_operation *dma_op)
3374 dma_descr_data *dd;
3375 int i;
3377 printk("print_user_dma_lists, dma_op=0x%p\n", dma_op);
3379 printk("out_data_buf = 0x%p, phys_to_virt(out_data_buf) = 0x%p\n", dma_op->out_data_buf, phys_to_virt((unsigned long int)dma_op->out_data_buf));
3380 printk("in_data_buf = 0x%p, phys_to_virt(in_data_buf) = 0x%p\n", dma_op->in_data_buf, phys_to_virt((unsigned long int)dma_op->in_data_buf));
3382 printk("##############outlist\n");
3383 dd = phys_to_virt((unsigned long int)dma_op->outlist);
3384 i = 0;
3385 while (dd != NULL) {
3386 printk("#%d phys_to_virt(desc) 0x%p\n", i, dd);
3387 printk("\n\tbuf: 0x%p\n"
3388 "\tafter: 0x%p\n"
3389 "\tmd: 0x%04x\n"
3390 "\tnext: 0x%p\n",
3391 dd->buf,
3392 dd->after,
3393 dd->md,
3394 dd->next);
3395 printk("flags:\n"
3396 "\twait:\t%d\n"
3397 "\teol:\t%d\n"
3398 "\touteop:\t%d\n"
3399 "\tineop:\t%d\n"
3400 "\tintr:\t%d\n",
3401 dd->wait,
3402 dd->eol,
3403 dd->out_eop,
3404 dd->in_eop,
3405 dd->intr);
3406 if (dd->eol)
3407 dd = NULL;
3408 else
3409 dd = phys_to_virt((unsigned long int)dd->next);
3410 ++i;
3413 printk("##############inlist\n");
3414 dd = phys_to_virt((unsigned long int)dma_op->inlist);
3415 i = 0;
3416 while (dd != NULL) {
3417 printk("#%d phys_to_virt(desc) 0x%p\n", i, dd);
3418 printk("\n\tbuf: 0x%p\n"
3419 "\tafter: 0x%p\n"
3420 "\tmd: 0x%04x\n"
3421 "\tnext: 0x%p\n",
3422 dd->buf,
3423 dd->after,
3424 dd->md,
3425 dd->next);
3426 printk("flags:\n"
3427 "\twait:\t%d\n"
3428 "\teol:\t%d\n"
3429 "\touteop:\t%d\n"
3430 "\tineop:\t%d\n"
3431 "\tintr:\t%d\n",
3432 dd->wait,
3433 dd->eol,
3434 dd->out_eop,
3435 dd->in_eop,
3436 dd->intr);
3437 if (dd->eol)
3438 dd = NULL;
3439 else
3440 dd = phys_to_virt((unsigned long int)dd->next);
3441 ++i;
3446 static void print_lock_status(void)
3448 printk("**********************print_lock_status\n");
3449 printk("cryptocop_completed_jobs_lock %d\n", spin_is_locked(&cryptocop_completed_jobs_lock));
3450 printk("cryptocop_job_queue_lock %d\n", spin_is_locked(&cryptocop_job_queue_lock));
3451 printk("descr_pool_lock %d\n", spin_is_locked(&descr_pool_lock));
3452 printk("cryptocop_sessions_lock %d\n", spin_is_locked(cryptocop_sessions_lock));
3453 printk("running_job_lock %d\n", spin_is_locked(running_job_lock));
3454 printk("cryptocop_process_lock %d\n", spin_is_locked(cryptocop_process_lock));
3456 #endif /* LDEBUG */
3459 static const char cryptocop_name[] = "ETRAX FS stream co-processor";
3461 static int init_stream_coprocessor(void)
3463 int err;
3464 int i;
3465 static int initialized = 0;
3467 if (initialized)
3468 return 0;
3470 initialized = 1;
3472 printk("ETRAX FS stream co-processor driver v0.01, (c) 2003 Axis Communications AB\n");
3474 err = register_chrdev(CRYPTOCOP_MAJOR, cryptocop_name, &cryptocop_fops);
3475 if (err < 0) {
3476 printk(KERN_ERR "stream co-processor: could not get major number.\n");
3477 return err;
3480 err = init_cryptocop();
3481 if (err) {
3482 (void)unregister_chrdev(CRYPTOCOP_MAJOR, cryptocop_name);
3483 return err;
3485 err = cryptocop_job_queue_init();
3486 if (err) {
3487 release_cryptocop();
3488 (void)unregister_chrdev(CRYPTOCOP_MAJOR, cryptocop_name);
3489 return err;
3491 /* Init the descriptor pool. */
3492 for (i = 0; i < CRYPTOCOP_DESCRIPTOR_POOL_SIZE - 1; i++) {
3493 descr_pool[i].from_pool = 1;
3494 descr_pool[i].next = &descr_pool[i + 1];
3496 descr_pool[i].from_pool = 1;
3497 descr_pool[i].next = NULL;
3498 descr_pool_free_list = &descr_pool[0];
3499 descr_pool_no_free = CRYPTOCOP_DESCRIPTOR_POOL_SIZE;
3501 spin_lock_init(&cryptocop_completed_jobs_lock);
3502 spin_lock_init(&cryptocop_job_queue_lock);
3503 spin_lock_init(&descr_pool_lock);
3504 spin_lock_init(&cryptocop_sessions_lock);
3505 spin_lock_init(&running_job_lock);
3506 spin_lock_init(&cryptocop_process_lock);
3508 cryptocop_sessions = NULL;
3509 next_sid = 1;
3511 cryptocop_running_job = NULL;
3513 printk("stream co-processor: init done.\n");
3514 return 0;
3517 static void __exit exit_stream_coprocessor(void)
3519 release_cryptocop();
3520 cryptocop_job_queue_close();
3523 module_init(init_stream_coprocessor);
3524 module_exit(exit_stream_coprocessor);