1 /*******************************************************************************
2 Copyright (C) Marvell International Ltd. and its affiliates
4 This software file (the "File") is owned and distributed by Marvell
5 International Ltd. and/or its affiliates ("Marvell") under the following
6 alternative licensing terms. Once you have made an election to distribute the
7 File under one of the following license alternatives, please (i) delete this
8 introductory statement regarding license alternatives, (ii) delete the two
9 license alternatives that you have not elected to use and (iii) preserve the
10 Marvell copyright notice above.
13 ********************************************************************************
14 Marvell GPL License Option
16 If you received this File from Marvell, you may opt to use, redistribute and/or
17 modify this File in accordance with the terms and conditions of the General
18 Public License Version 2, June 1991 (the "GPL License"), a copy of which is
19 available along with the File in the license.txt file or by writing to the Free
20 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
21 on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
23 THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
24 WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
25 DISCLAIMED. The GPL License provides additional details about this warranty
27 *******************************************************************************/
29 #ifndef AUTOCONF_INCLUDED
30 #include <linux/config.h>
32 #include <linux/module.h>
33 #include <linux/init.h>
34 #include <linux/list.h>
35 #include <linux/slab.h>
36 #include <linux/sched.h>
37 #include <linux/wait.h>
38 #include <linux/crypto.h>
40 #include <linux/skbuff.h>
41 #include <linux/random.h>
42 #include <linux/platform_device.h>
43 #include <asm/scatterlist.h>
44 #include <linux/spinlock.h>
45 #include "ctrlEnv/sys/mvSysCesa.h"
46 #include "cesa/mvCesa.h" /* moved here before cryptodev.h due to include dependencies */
47 #include <cryptodev.h>
49 #include <plat/mv_cesa.h>
50 #include <linux/mbus.h>
53 #include "cesa/mvMD5.h"
54 #include "cesa/mvSHA1.h"
56 #include "cesa/mvCesaRegs.h"
57 #include "cesa/AES/mvAes.h"
58 #include "cesa/mvLru.h"
63 module_param(debug, int, 1);
64 MODULE_PARM_DESC(debug, "Enable debug");
66 #define dprintk(a...) if (debug) { printk(a); } else
75 #define WINDOW_BASE(i) 0xA00 + (i << 3)
76 #define WINDOW_CTRL(i) 0xA04 + (i << 3)
78 /* interrupt handling */
79 #undef CESA_OCF_POLLING
80 #undef CESA_OCF_TASKLET
82 #if defined(CESA_OCF_POLLING) && defined(CESA_OCF_TASKLET)
83 #error "don't use both tasklet and polling mode"
86 extern int cesaReqResources;
87 /* support for spliting action into 2 actions */
88 #define CESA_OCF_SPLIT
91 #define CESA_OCF_MAX_SES 128
92 #define CESA_Q_SIZE 64
96 struct cesa_ocf_data {
100 #define auth_tn_decrypt encrypt_tn_auth
105 /* fragment workaround sessions */
106 short frag_wa_encrypt;
107 short frag_wa_decrypt;
111 /* CESA device data */
115 struct mv_cesa_platform_data *plat_data;
119 #define DIGEST_BUF_SIZE 32
120 struct cesa_ocf_process {
121 MV_CESA_COMMAND cesa_cmd;
122 MV_CESA_MBUF cesa_mbuf;
123 MV_BUF_INFO cesa_bufs[MV_CESA_MAX_MBUF_FRAGS];
124 char digest[DIGEST_BUF_SIZE];
130 /* global variables */
131 static int32_t cesa_ocf_id = -1;
132 static struct cesa_ocf_data *cesa_ocf_sessions[CESA_OCF_MAX_SES];
133 static spinlock_t cesa_lock;
134 static struct cesa_dev cesa_device;
137 static int cesa_ocf_process (device_t, struct cryptop *, int);
138 static int cesa_ocf_newsession (device_t, u_int32_t *, struct cryptoini *);
139 static int cesa_ocf_freesession (device_t, u_int64_t);
140 static void cesa_callback (unsigned long);
141 static irqreturn_t cesa_interrupt_handler (int, void *);
142 #ifdef CESA_OCF_POLLING
143 static void cesa_interrupt_polling(void);
145 #ifdef CESA_OCF_TASKLET
146 static struct tasklet_struct cesa_ocf_tasklet;
149 static struct timeval tt_start;
150 static struct timeval tt_end;
153 * dummy device structure
157 softc_device_decl sc_dev;
160 static device_method_t mv_cesa_methods = {
161 /* crypto device methods */
162 DEVMETHOD(cryptodev_newsession, cesa_ocf_newsession),
163 DEVMETHOD(cryptodev_freesession,cesa_ocf_freesession),
164 DEVMETHOD(cryptodev_process, cesa_ocf_process),
165 DEVMETHOD(cryptodev_kprocess, NULL),
170 /* Add debug Trace */
171 #undef CESA_OCF_TRACE_DEBUG
172 #ifdef CESA_OCF_TRACE_DEBUG
174 #define MV_CESA_USE_TIMER_ID 0
178 int type; /* 0 - isrEmpty, 1 - cesaReadyGet, 2 - cesaAction */
184 MV_CESA_REQ* pReqReady;
185 MV_CESA_REQ* pReqEmpty;
186 MV_CESA_REQ* pReqProcess;
187 } MV_CESA_TEST_TRACE;
189 #define MV_CESA_TEST_TRACE_SIZE 50
191 static int cesaTestTraceIdx = 0;
192 static MV_CESA_TEST_TRACE cesaTestTrace[MV_CESA_TEST_TRACE_SIZE];
194 static void cesaTestTraceAdd(int type)
196 cesaTestTrace[cesaTestTraceIdx].type = type;
197 cesaTestTrace[cesaTestTraceIdx].realCause = MV_REG_READ(MV_CESA_ISR_CAUSE_REG);
198 //cesaTestTrace[cesaTestTraceIdx].idmaCause = MV_REG_READ(IDMA_CAUSE_REG);
199 cesaTestTrace[cesaTestTraceIdx].resources = cesaReqResources;
200 cesaTestTrace[cesaTestTraceIdx].pReqReady = pCesaReqReady;
201 cesaTestTrace[cesaTestTraceIdx].pReqEmpty = pCesaReqEmpty;
202 cesaTestTrace[cesaTestTraceIdx].pReqProcess = pCesaReqProcess;
203 cesaTestTrace[cesaTestTraceIdx].timeStamp = mvCntmrRead(MV_CESA_USE_TIMER_ID);
205 if(cesaTestTraceIdx == MV_CESA_TEST_TRACE_SIZE)
206 cesaTestTraceIdx = 0;
209 #else /* CESA_OCF_TRACE_DEBUG */
211 #define cesaTestTraceAdd(x)
213 #endif /* CESA_OCF_TRACE_DEBUG */
216 get_usec(unsigned int start)
219 do_gettimeofday (&tt_start);
223 do_gettimeofday (&tt_end);
224 tt_end.tv_sec -= tt_start.tv_sec;
225 tt_end.tv_usec -= tt_start.tv_usec;
226 if (tt_end.tv_usec < 0) {
227 tt_end.tv_usec += 1000 * 1000;
231 printk("time taken is %d\n", (unsigned int)(tt_end.tv_usec + tt_end.tv_sec * 1000000));
232 return (tt_end.tv_usec + tt_end.tv_sec * 1000000);
237 * check that the crp action match the current session
240 ocf_check_action(struct cryptop *crp, struct cesa_ocf_data *cesa_ocf_cur_ses) {
242 int encrypt = 0, decrypt = 0, auth = 0;
243 struct cryptodesc *crd;
245 /* Go through crypto descriptors, processing as we go */
246 for (crd = crp->crp_desc; crd; crd = crd->crd_next, count++) {
248 printk("%s,%d: session mode is not supported.\n", __FILE__, __LINE__);
252 /* Encryption /Decryption */
253 if(crd->crd_alg == cesa_ocf_cur_ses->cipher_alg) {
254 /* check that the action is compatible with session */
255 if(encrypt || decrypt) {
256 printk("%s,%d: session mode is not supported.\n", __FILE__, __LINE__);
260 if(crd->crd_flags & CRD_F_ENCRYPT) { /* encrypt */
261 if( (count == 2) && (cesa_ocf_cur_ses->encrypt_tn_auth) ) {
262 printk("%s,%d: sequence isn't supported by this session.\n", __FILE__, __LINE__);
268 if( (count == 2) && !(cesa_ocf_cur_ses->auth_tn_decrypt) ) {
269 printk("%s,%d: sequence isn't supported by this session.\n", __FILE__, __LINE__);
277 else if(crd->crd_alg == cesa_ocf_cur_ses->auth_alg) {
278 /* check that the action is compatible with session */
280 printk("%s,%d: session mode is not supported.\n", __FILE__, __LINE__);
283 if( (count == 2) && (decrypt) && (cesa_ocf_cur_ses->auth_tn_decrypt)) {
284 printk("%s,%d: sequence isn't supported by this session.\n", __FILE__, __LINE__);
287 if( (count == 2) && (encrypt) && !(cesa_ocf_cur_ses->encrypt_tn_auth)) {
288 printk("%s,%d: sequence isn't supported by this session.\n", __FILE__, __LINE__);
294 printk("%s,%d: Alg isn't supported by this session.\n", __FILE__, __LINE__);
307 cesa_ocf_process(device_t dev, struct cryptop *crp, int hint)
309 struct cesa_ocf_process *cesa_ocf_cmd = NULL;
310 struct cesa_ocf_process *cesa_ocf_cmd_wa = NULL;
311 MV_CESA_COMMAND *cesa_cmd;
312 struct cryptodesc *crd;
313 struct cesa_ocf_data *cesa_ocf_cur_ses;
314 int sid = 0, temp_len = 0, i;
315 int encrypt = 0, decrypt = 0, auth = 0;
317 struct sk_buff *skb = NULL;
318 struct uio *uiop = NULL;
320 MV_BUF_INFO *p_buf_info;
321 MV_CESA_MBUF *p_mbuf_info;
324 dprintk("%s()\n", __FUNCTION__);
326 if( cesaReqResources <= 1 ) {
327 dprintk("%s,%d: ERESTART\n", __FILE__, __LINE__);
334 printk("%s,%d: EINVAL\n", __FILE__, __LINE__);
338 if (crp->crp_desc == NULL || crp->crp_buf == NULL ) {
339 printk("%s,%d: EINVAL\n", __FILE__, __LINE__);
340 crp->crp_etype = EINVAL;
344 sid = crp->crp_sid & 0xffffffff;
345 if ((sid >= CESA_OCF_MAX_SES) || (cesa_ocf_sessions[sid] == NULL)) {
346 crp->crp_etype = ENOENT;
347 printk("%s,%d: ENOENT session %d \n", __FILE__, __LINE__, sid);
352 sid = crp->crp_sid & 0xffffffff;
354 cesa_ocf_cur_ses = cesa_ocf_sessions[sid];
357 if(ocf_check_action(crp, cesa_ocf_cur_ses)){
362 /* malloc a new cesa process */
363 cesa_ocf_cmd = kmalloc(sizeof(struct cesa_ocf_process), GFP_ATOMIC);
365 if (cesa_ocf_cmd == NULL) {
366 printk("%s,%d: ENOBUFS \n", __FILE__, __LINE__);
369 memset(cesa_ocf_cmd, 0, sizeof(struct cesa_ocf_process));
371 /* init cesa_process */
372 cesa_ocf_cmd->crp = crp;
373 /* always call callback */
374 cesa_ocf_cmd->need_cb = 1;
376 /* init cesa_cmd for usage of the HALs */
377 cesa_cmd = &cesa_ocf_cmd->cesa_cmd;
378 cesa_cmd->pReqPrv = (void *)cesa_ocf_cmd;
379 cesa_cmd->sessionId = cesa_ocf_cur_ses->sid_encrypt; /* defualt use encrypt */
381 /* prepare src buffer */
382 /* we send the entire buffer to the HAL, even if only part of it should be encrypt/auth. */
383 /* if not using seesions for both encrypt and auth, then it will be wiser to to copy only */
384 /* from skip to crd_len. */
385 p_buf_info = cesa_ocf_cmd->cesa_bufs;
386 p_mbuf_info = &cesa_ocf_cmd->cesa_mbuf;
388 p_buf_info += 2; /* save 2 first buffers for IV and digest -
389 we won't append them to the end since, they
390 might be places in an unaligned addresses. */
392 p_mbuf_info->pFrags = p_buf_info;
396 if (crp->crp_flags & CRYPTO_F_SKBUF) {
398 dprintk("%s,%d: handle SKB.\n", __FILE__, __LINE__);
399 skb = (struct sk_buff *) crp->crp_buf;
401 if (skb_shinfo(skb)->nr_frags >= (MV_CESA_MAX_MBUF_FRAGS - 1)) {
402 printk("%s,%d: %d nr_frags > MV_CESA_MAX_MBUF_FRAGS", __FILE__, __LINE__, skb_shinfo(skb)->nr_frags);
406 p_mbuf_info->mbufSize = skb->len;
408 /* first skb fragment */
409 p_buf_info->bufSize = skb_headlen(skb);
410 p_buf_info->bufVirtPtr = skb->data;
413 /* now handle all other skb fragments */
414 for ( i = 0; i < skb_shinfo(skb)->nr_frags; i++ ) {
415 skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
416 p_buf_info->bufSize = frag->size;
417 p_buf_info->bufVirtPtr = page_address(frag->page) + frag->page_offset;
420 p_mbuf_info->numFrags = skb_shinfo(skb)->nr_frags + 1;
423 else if(crp->crp_flags & CRYPTO_F_IOV) {
425 dprintk("%s,%d: handle UIO.\n", __FILE__, __LINE__);
426 uiop = (struct uio *) crp->crp_buf;
428 if (uiop->uio_iovcnt > (MV_CESA_MAX_MBUF_FRAGS - 1)) {
429 printk("%s,%d: %d uio_iovcnt > MV_CESA_MAX_MBUF_FRAGS \n", __FILE__, __LINE__, uiop->uio_iovcnt);
433 p_mbuf_info->mbufSize = crp->crp_ilen;
434 p_mbuf_info->numFrags = uiop->uio_iovcnt;
435 for(i = 0; i < uiop->uio_iovcnt; i++) {
436 p_buf_info->bufVirtPtr = uiop->uio_iov[i].iov_base;
437 p_buf_info->bufSize = uiop->uio_iov[i].iov_len;
438 temp_len += p_buf_info->bufSize;
439 dprintk("%s,%d: buf %x-> addr %x, size %x \n"
440 , __FILE__, __LINE__, i, (unsigned int)p_buf_info->bufVirtPtr, p_buf_info->bufSize);
447 dprintk("%s,%d: handle CONTIG.\n", __FILE__, __LINE__);
448 p_mbuf_info->numFrags = 1;
449 p_mbuf_info->mbufSize = crp->crp_ilen;
450 p_buf_info->bufVirtPtr = crp->crp_buf;
451 p_buf_info->bufSize = crp->crp_ilen;
452 temp_len = crp->crp_ilen;
456 /* Support up to 64K why? cause! */
457 if(crp->crp_ilen > 64*1024) {
458 printk("%s,%d: buf too big %x \n", __FILE__, __LINE__, crp->crp_ilen);
462 if( temp_len != crp->crp_ilen ) {
463 printk("%s,%d: warning size don't match.(%x %x) \n", __FILE__, __LINE__, temp_len, crp->crp_ilen);
466 cesa_cmd->pSrc = p_mbuf_info;
467 cesa_cmd->pDst = p_mbuf_info;
469 /* restore p_buf_info to point to first available buf */
470 p_buf_info = cesa_ocf_cmd->cesa_bufs;
474 /* Go through crypto descriptors, processing as we go */
475 for (crd = crp->crp_desc; crd; crd = crd->crd_next) {
477 /* Encryption /Decryption */
478 if(crd->crd_alg == cesa_ocf_cur_ses->cipher_alg) {
480 dprintk("%s,%d: cipher", __FILE__, __LINE__);
482 cesa_cmd->cryptoOffset = crd->crd_skip;
483 cesa_cmd->cryptoLength = crd->crd_len;
485 if(crd->crd_flags & CRD_F_ENCRYPT) { /* encrypt */
486 dprintk(" encrypt \n");
490 if (crd->crd_flags & CRD_F_IV_EXPLICIT) { /* IV from USER */
491 dprintk("%s,%d: IV from USER (offset %x) \n", __FILE__, __LINE__, crd->crd_inject);
492 cesa_cmd->ivFromUser = 1;
496 * do we have to copy the IV back to the buffer ?
498 if ((crd->crd_flags & CRD_F_IV_PRESENT) == 0) {
499 dprintk("%s,%d: copy the IV back to the buffer\n", __FILE__, __LINE__);
500 cesa_cmd->ivOffset = crd->crd_inject;
501 crypto_copy_bits_back(crp->crp_buf, crd->crd_inject, ivp, cesa_ocf_cur_ses->ivlen);
504 dprintk("%s,%d: don't copy the IV back to the buffer \n", __FILE__, __LINE__);
505 p_mbuf_info->numFrags++;
506 p_mbuf_info->mbufSize += cesa_ocf_cur_ses->ivlen;
507 p_mbuf_info->pFrags = p_buf_info;
509 p_buf_info->bufVirtPtr = ivp;
510 p_buf_info->bufSize = cesa_ocf_cur_ses->ivlen;
514 cesa_cmd->ivOffset = 0;
515 cesa_cmd->cryptoOffset += cesa_ocf_cur_ses->ivlen;
517 cesa_cmd->macOffset += cesa_ocf_cur_ses->ivlen;
518 cesa_cmd->digestOffset += cesa_ocf_cur_ses->ivlen;
522 else { /* random IV */
523 dprintk("%s,%d: random IV \n", __FILE__, __LINE__);
524 cesa_cmd->ivFromUser = 0;
527 * do we have to copy the IV back to the buffer ?
529 /* in this mode the HAL will always copy the IV */
530 /* given by the session to the ivOffset */
531 if ((crd->crd_flags & CRD_F_IV_PRESENT) == 0) {
532 cesa_cmd->ivOffset = crd->crd_inject;
535 /* if IV isn't copy, then how will the user know which IV did we use??? */
536 printk("%s,%d: EINVAL\n", __FILE__, __LINE__);
542 dprintk(" decrypt \n");
544 cesa_cmd->sessionId = cesa_ocf_cur_ses->sid_decrypt;
547 if (crd->crd_flags & CRD_F_IV_EXPLICIT) {
548 dprintk("%s,%d: IV from USER \n", __FILE__, __LINE__);
549 /* append the IV buf to the mbuf */
550 cesa_cmd->ivFromUser = 1;
551 p_mbuf_info->numFrags++;
552 p_mbuf_info->mbufSize += cesa_ocf_cur_ses->ivlen;
553 p_mbuf_info->pFrags = p_buf_info;
555 p_buf_info->bufVirtPtr = crd->crd_iv;
556 p_buf_info->bufSize = cesa_ocf_cur_ses->ivlen;
560 cesa_cmd->ivOffset = 0;
561 cesa_cmd->cryptoOffset += cesa_ocf_cur_ses->ivlen;
563 cesa_cmd->macOffset += cesa_ocf_cur_ses->ivlen;
564 cesa_cmd->digestOffset += cesa_ocf_cur_ses->ivlen;
568 dprintk("%s,%d: IV inside the buffer \n", __FILE__, __LINE__);
569 cesa_cmd->ivFromUser = 0;
570 cesa_cmd->ivOffset = crd->crd_inject;
576 else if(crd->crd_alg == cesa_ocf_cur_ses->auth_alg) {
577 dprintk("%s,%d: Authentication \n", __FILE__, __LINE__);
579 cesa_cmd->macOffset = crd->crd_skip;
580 cesa_cmd->macLength = crd->crd_len;
583 cesa_cmd->digestOffset = crd->crd_inject;
586 printk("%s,%d: Alg isn't supported by this session.\n", __FILE__, __LINE__);
592 dprintk("%s,%d: Sending Action: \n", __FILE__, __LINE__);
593 dprintk("%s,%d: IV from user: %d. IV offset %x \n", __FILE__, __LINE__, cesa_cmd->ivFromUser, cesa_cmd->ivOffset);
594 dprintk("%s,%d: crypt offset %x len %x \n", __FILE__, __LINE__, cesa_cmd->cryptoOffset, cesa_cmd->cryptoLength);
595 dprintk("%s,%d: Auth offset %x len %x \n", __FILE__, __LINE__, cesa_cmd->macOffset, cesa_cmd->macLength);
596 dprintk("%s,%d: set digest in offset %x . \n", __FILE__, __LINE__, cesa_cmd->digestOffset);
598 mvCesaDebugMbuf("SRC BUFFER", cesa_cmd->pSrc, 0, cesa_cmd->pSrc->mbufSize);
602 /* send action to HAL */
603 spin_lock_irqsave(&cesa_lock, flags);
604 status = mvCesaAction(cesa_cmd);
605 spin_unlock_irqrestore(&cesa_lock, flags);
607 /* action not allowed */
608 if(status == MV_NOT_ALLOWED) {
609 #ifdef CESA_OCF_SPLIT
610 /* if both encrypt and auth try to split */
611 if(auth && (encrypt || decrypt)) {
612 MV_CESA_COMMAND *cesa_cmd_wa;
614 /* malloc a new cesa process and init it */
615 cesa_ocf_cmd_wa = kmalloc(sizeof(struct cesa_ocf_process), GFP_ATOMIC);
617 if (cesa_ocf_cmd_wa == NULL) {
618 printk("%s,%d: ENOBUFS \n", __FILE__, __LINE__);
621 memcpy(cesa_ocf_cmd_wa, cesa_ocf_cmd, sizeof(struct cesa_ocf_process));
622 cesa_cmd_wa = &cesa_ocf_cmd_wa->cesa_cmd;
623 cesa_cmd_wa->pReqPrv = (void *)cesa_ocf_cmd_wa;
624 cesa_ocf_cmd_wa->need_cb = 0;
626 /* break requests to two operation, first operation completion won't call callback */
627 if((decrypt) && (cesa_ocf_cur_ses->auth_tn_decrypt)) {
628 cesa_cmd_wa->sessionId = cesa_ocf_cur_ses->frag_wa_auth;
629 cesa_cmd->sessionId = cesa_ocf_cur_ses->frag_wa_decrypt;
631 else if((decrypt) && !(cesa_ocf_cur_ses->auth_tn_decrypt)) {
632 cesa_cmd_wa->sessionId = cesa_ocf_cur_ses->frag_wa_decrypt;
633 cesa_cmd->sessionId = cesa_ocf_cur_ses->frag_wa_auth;
635 else if((encrypt) && (cesa_ocf_cur_ses->encrypt_tn_auth)) {
636 cesa_cmd_wa->sessionId = cesa_ocf_cur_ses->frag_wa_encrypt;
637 cesa_cmd->sessionId = cesa_ocf_cur_ses->frag_wa_auth;
639 else if((encrypt) && !(cesa_ocf_cur_ses->encrypt_tn_auth)){
640 cesa_cmd_wa->sessionId = cesa_ocf_cur_ses->frag_wa_auth;
641 cesa_cmd->sessionId = cesa_ocf_cur_ses->frag_wa_encrypt;
644 printk("%s,%d: Unsupporterd fragment wa mode \n", __FILE__, __LINE__);
648 /* send the 2 actions to the HAL */
649 spin_lock_irqsave(&cesa_lock, flags);
650 status = mvCesaAction(cesa_cmd_wa);
651 spin_unlock_irqrestore(&cesa_lock, flags);
653 if((status != MV_NO_MORE) && (status != MV_OK)) {
654 printk("%s,%d: cesa action failed, status = 0x%x\n", __FILE__, __LINE__, status);
657 spin_lock_irqsave(&cesa_lock, flags);
658 status = mvCesaAction(cesa_cmd);
659 spin_unlock_irqrestore(&cesa_lock, flags);
662 /* action not allowed and can't split */
670 /* Hal Q is full, send again. This should never happen */
671 if(status == MV_NO_RESOURCE) {
672 printk("%s,%d: cesa no more resources \n", __FILE__, __LINE__);
676 kfree(cesa_ocf_cmd_wa);
679 else if((status != MV_NO_MORE) && (status != MV_OK)) {
680 printk("%s,%d: cesa action failed, status = 0x%x\n", __FILE__, __LINE__, status);
685 #ifdef CESA_OCF_POLLING
686 cesa_interrupt_polling();
692 crp->crp_etype = EINVAL;
696 kfree(cesa_ocf_cmd_wa);
704 cesa_callback(unsigned long dummy)
706 struct cesa_ocf_process *cesa_ocf_cmd = NULL;
707 struct cryptop *crp = NULL;
708 MV_CESA_RESULT result[MV_CESA_MAX_CHAN];
712 dprintk("%s()\n", __FUNCTION__);
714 #ifdef CESA_OCF_TASKLET
715 disable_irq(cesa_device.irq);
719 /* Get Ready requests */
720 spin_lock(&cesa_lock);
721 status = mvCesaReadyGet(&result[res_idx]);
722 spin_unlock(&cesa_lock);
726 if(status != MV_OK) {
727 #ifdef CESA_OCF_POLLING
728 if(status == MV_BUSY) { /* Fragment */
729 cesa_interrupt_polling();
739 for(i = 0; i < res_idx; i++) {
741 if(!result[i].pReqPrv) {
742 printk("%s,%d: warning private is NULL\n", __FILE__, __LINE__);
746 cesa_ocf_cmd = result[i].pReqPrv;
747 crp = cesa_ocf_cmd->crp;
749 // ignore HMAC error.
750 //if(result->retCode)
751 // crp->crp_etype = EIO;
753 #if defined(CESA_OCF_POLLING)
754 if(!cesa_ocf_cmd->need_cb){
755 cesa_interrupt_polling();
758 if(cesa_ocf_cmd->need_cb) {
760 mvCesaDebugMbuf("DST BUFFER", cesa_ocf_cmd->cesa_cmd.pDst, 0, cesa_ocf_cmd->cesa_cmd.pDst->mbufSize);
766 #ifdef CESA_OCF_TASKLET
767 enable_irq(cesa_device.irq);
775 #ifdef CESA_OCF_POLLING
777 cesa_interrupt_polling(void)
781 dprintk("%s()\n", __FUNCTION__);
783 /* Read cause register */
785 cause = MV_REG_READ(MV_CESA_ISR_CAUSE_REG);
786 cause &= MV_CESA_CAUSE_ACC_DMA_ALL_MASK;
788 } while (cause == 0);
790 /* clear interrupts */
791 MV_REG_WRITE(MV_CESA_ISR_CAUSE_REG, 0);
801 * cesa Interrupt polling routine.
804 cesa_interrupt_handler(int irq, void *arg)
808 dprintk("%s()\n", __FUNCTION__);
812 /* Read cause register */
813 cause = MV_REG_READ(MV_CESA_ISR_CAUSE_REG);
815 if( (cause & MV_CESA_CAUSE_ACC_DMA_ALL_MASK) == 0)
817 /* Empty interrupt */
818 dprintk("%s,%d: cesaTestReadyIsr: cause=0x%x\n", __FILE__, __LINE__, cause);
822 /* clear interrupts */
823 MV_REG_WRITE(MV_CESA_ISR_CAUSE_REG, 0);
826 #ifdef CESA_OCF_TASKLET
827 tasklet_hi_schedule(&cesa_ocf_tasklet);
838 /*cesa_ocf_newsession(void *arg, u_int32_t *sid, struct cryptoini *cri)*/
839 cesa_ocf_newsession(device_t dev, u_int32_t *sid, struct cryptoini *cri)
842 u32 count = 0, auth = 0, encrypt =0;
843 struct cesa_ocf_data *cesa_ocf_cur_ses;
844 MV_CESA_OPEN_SESSION cesa_session;
845 MV_CESA_OPEN_SESSION *cesa_ses = &cesa_session;
848 dprintk("%s()\n", __FUNCTION__);
849 if (sid == NULL || cri == NULL) {
850 printk("%s,%d: EINVAL\n", __FILE__, __LINE__);
854 /* leave first empty like in other implementations */
855 for (i = 1; i < CESA_OCF_MAX_SES; i++) {
856 if (cesa_ocf_sessions[i] == NULL)
860 if(i >= CESA_OCF_MAX_SES) {
861 printk("%s,%d: no more sessions \n", __FILE__, __LINE__);
865 cesa_ocf_sessions[i] = (struct cesa_ocf_data *) kmalloc(sizeof(struct cesa_ocf_data), GFP_ATOMIC);
866 if (cesa_ocf_sessions[i] == NULL) {
867 cesa_ocf_freesession(NULL, i);
868 printk("%s,%d: ENOBUFS \n", __FILE__, __LINE__);
871 dprintk("%s,%d: new session %d \n", __FILE__, __LINE__, i);
874 cesa_ocf_cur_ses = cesa_ocf_sessions[i];
875 memset(cesa_ocf_cur_ses, 0, sizeof(struct cesa_ocf_data));
876 cesa_ocf_cur_ses->sid_encrypt = -1;
877 cesa_ocf_cur_ses->sid_decrypt = -1;
878 cesa_ocf_cur_ses->frag_wa_encrypt = -1;
879 cesa_ocf_cur_ses->frag_wa_decrypt = -1;
880 cesa_ocf_cur_ses->frag_wa_auth = -1;
882 /* init the session */
883 memset(cesa_ses, 0, sizeof(MV_CESA_OPEN_SESSION));
887 printk("%s,%d: don't support more then 2 operations\n", __FILE__, __LINE__);
890 switch (cri->cri_alg) {
892 dprintk("%s,%d: (%d) AES CBC \n", __FILE__, __LINE__, count);
893 cesa_ocf_cur_ses->cipher_alg = cri->cri_alg;
894 cesa_ocf_cur_ses->ivlen = MV_CESA_AES_BLOCK_SIZE;
895 cesa_ses->cryptoAlgorithm = MV_CESA_CRYPTO_AES;
896 cesa_ses->cryptoMode = MV_CESA_CRYPTO_CBC;
897 if(cri->cri_klen/8 > MV_CESA_MAX_CRYPTO_KEY_LENGTH) {
898 printk("%s,%d: CRYPTO key too long.\n", __FILE__, __LINE__);
901 memcpy(cesa_ses->cryptoKey, cri->cri_key, cri->cri_klen/8);
902 dprintk("%s,%d: key length %d \n", __FILE__, __LINE__, cri->cri_klen/8);
903 cesa_ses->cryptoKeyLength = cri->cri_klen/8;
906 case CRYPTO_3DES_CBC:
907 dprintk("%s,%d: (%d) 3DES CBC \n", __FILE__, __LINE__, count);
908 cesa_ocf_cur_ses->cipher_alg = cri->cri_alg;
909 cesa_ocf_cur_ses->ivlen = MV_CESA_3DES_BLOCK_SIZE;
910 cesa_ses->cryptoAlgorithm = MV_CESA_CRYPTO_3DES;
911 cesa_ses->cryptoMode = MV_CESA_CRYPTO_CBC;
912 if(cri->cri_klen/8 > MV_CESA_MAX_CRYPTO_KEY_LENGTH) {
913 printk("%s,%d: CRYPTO key too long.\n", __FILE__, __LINE__);
916 memcpy(cesa_ses->cryptoKey, cri->cri_key, cri->cri_klen/8);
917 cesa_ses->cryptoKeyLength = cri->cri_klen/8;
921 dprintk("%s,%d: (%d) DES CBC \n", __FILE__, __LINE__, count);
922 cesa_ocf_cur_ses->cipher_alg = cri->cri_alg;
923 cesa_ocf_cur_ses->ivlen = MV_CESA_DES_BLOCK_SIZE;
924 cesa_ses->cryptoAlgorithm = MV_CESA_CRYPTO_DES;
925 cesa_ses->cryptoMode = MV_CESA_CRYPTO_CBC;
926 if(cri->cri_klen/8 > MV_CESA_MAX_CRYPTO_KEY_LENGTH) {
927 printk("%s,%d: CRYPTO key too long.\n", __FILE__, __LINE__);
930 memcpy(cesa_ses->cryptoKey, cri->cri_key, cri->cri_klen/8);
931 cesa_ses->cryptoKeyLength = cri->cri_klen/8;
935 case CRYPTO_MD5_HMAC:
936 dprintk("%s,%d: (%d) %sMD5 CBC \n", __FILE__, __LINE__, count, (cri->cri_alg != CRYPTO_MD5)? "H-":" ");
937 cesa_ocf_cur_ses->auth_alg = cri->cri_alg;
938 cesa_ocf_cur_ses->digestlen = (cri->cri_alg == CRYPTO_MD5)? MV_CESA_MD5_DIGEST_SIZE : 12;
939 cesa_ses->macMode = (cri->cri_alg == CRYPTO_MD5)? MV_CESA_MAC_MD5 : MV_CESA_MAC_HMAC_MD5;
940 if(cri->cri_klen/8 > MV_CESA_MAX_CRYPTO_KEY_LENGTH) {
941 printk("%s,%d: MAC key too long. \n", __FILE__, __LINE__);
944 cesa_ses->macKeyLength = cri->cri_klen/8;
945 memcpy(cesa_ses->macKey, cri->cri_key, cri->cri_klen/8);
946 cesa_ses->digestSize = cesa_ocf_cur_ses->digestlen;
950 case CRYPTO_SHA1_HMAC:
951 dprintk("%s,%d: (%d) %sSHA1 CBC \n", __FILE__, __LINE__, count, (cri->cri_alg != CRYPTO_SHA1)? "H-":" ");
952 cesa_ocf_cur_ses->auth_alg = cri->cri_alg;
953 cesa_ocf_cur_ses->digestlen = (cri->cri_alg == CRYPTO_SHA1)? MV_CESA_SHA1_DIGEST_SIZE : 12;
954 cesa_ses->macMode = (cri->cri_alg == CRYPTO_SHA1)? MV_CESA_MAC_SHA1 : MV_CESA_MAC_HMAC_SHA1;
955 if(cri->cri_klen/8 > MV_CESA_MAX_CRYPTO_KEY_LENGTH) {
956 printk("%s,%d: MAC key too long. \n", __FILE__, __LINE__);
959 cesa_ses->macKeyLength = cri->cri_klen/8;
960 memcpy(cesa_ses->macKey, cri->cri_key, cri->cri_klen/8);
961 cesa_ses->digestSize = cesa_ocf_cur_ses->digestlen;
965 printk("%s,%d: unknown algo 0x%x\n", __FILE__, __LINE__, cri->cri_alg);
972 if((encrypt > 2) || (auth > 2)) {
973 printk("%s,%d: session mode is not supported.\n", __FILE__, __LINE__);
976 /* create new sessions in HAL */
978 cesa_ses->operation = MV_CESA_CRYPTO_ONLY;
979 /* encrypt session */
981 cesa_ses->operation = MV_CESA_MAC_THEN_CRYPTO;
984 cesa_ses->operation = MV_CESA_CRYPTO_THEN_MAC;
985 cesa_ocf_cur_ses->encrypt_tn_auth = 1;
988 cesa_ses->operation = MV_CESA_CRYPTO_ONLY;
990 cesa_ses->direction = MV_CESA_DIR_ENCODE;
991 status = mvCesaSessionOpen(cesa_ses, &cesa_ocf_cur_ses->sid_encrypt);
992 if(status != MV_OK) {
993 printk("%s,%d: Can't open new session - status = 0x%x\n", __FILE__, __LINE__, status);
996 /* decrypt session */
997 if( cesa_ses->operation == MV_CESA_MAC_THEN_CRYPTO ) {
998 cesa_ses->operation = MV_CESA_CRYPTO_THEN_MAC;
1000 else if( cesa_ses->operation == MV_CESA_CRYPTO_THEN_MAC ) {
1001 cesa_ses->operation = MV_CESA_MAC_THEN_CRYPTO;
1003 cesa_ses->direction = MV_CESA_DIR_DECODE;
1004 status = mvCesaSessionOpen(cesa_ses, &cesa_ocf_cur_ses->sid_decrypt);
1005 if(status != MV_OK) {
1006 printk("%s,%d: Can't open new session - status = 0x%x\n", __FILE__, __LINE__, status);
1010 /* preapre one action sessions for case we will need to split an action */
1011 #ifdef CESA_OCF_SPLIT
1012 if(( cesa_ses->operation == MV_CESA_MAC_THEN_CRYPTO ) ||
1013 ( cesa_ses->operation == MV_CESA_CRYPTO_THEN_MAC )) {
1014 /* open one session for encode and one for decode */
1015 cesa_ses->operation = MV_CESA_CRYPTO_ONLY;
1016 cesa_ses->direction = MV_CESA_DIR_ENCODE;
1017 status = mvCesaSessionOpen(cesa_ses, &cesa_ocf_cur_ses->frag_wa_encrypt);
1018 if(status != MV_OK) {
1019 printk("%s,%d: Can't open new session - status = 0x%x\n", __FILE__, __LINE__, status);
1023 cesa_ses->direction = MV_CESA_DIR_DECODE;
1024 status = mvCesaSessionOpen(cesa_ses, &cesa_ocf_cur_ses->frag_wa_decrypt);
1025 if(status != MV_OK) {
1026 printk("%s,%d: Can't open new session - status = 0x%x\n", __FILE__, __LINE__, status);
1029 /* open one session for auth */
1030 cesa_ses->operation = MV_CESA_MAC_ONLY;
1031 cesa_ses->direction = MV_CESA_DIR_ENCODE;
1032 status = mvCesaSessionOpen(cesa_ses, &cesa_ocf_cur_ses->frag_wa_auth);
1033 if(status != MV_OK) {
1034 printk("%s,%d: Can't open new session - status = 0x%x\n", __FILE__, __LINE__, status);
1040 else { /* only auth */
1041 cesa_ses->operation = MV_CESA_MAC_ONLY;
1042 cesa_ses->direction = MV_CESA_DIR_ENCODE;
1043 status = mvCesaSessionOpen(cesa_ses, &cesa_ocf_cur_ses->sid_encrypt);
1044 if(status != MV_OK) {
1045 printk("%s,%d: Can't open new session - status = 0x%x\n", __FILE__, __LINE__, status);
1052 cesa_ocf_freesession(NULL, *sid);
1062 cesa_ocf_freesession(device_t dev, u_int64_t tid)
1064 struct cesa_ocf_data *cesa_ocf_cur_ses;
1065 u_int32_t sid = CRYPTO_SESID2LID(tid);
1066 //unsigned long flags;
1068 dprintk("%s() %d \n", __FUNCTION__, sid);
1069 if ( (sid >= CESA_OCF_MAX_SES) || (cesa_ocf_sessions[sid] == NULL) ) {
1070 printk("%s,%d: EINVAL can't free session %d \n", __FILE__, __LINE__, sid);
1074 /* Silently accept and return */
1078 /* release session from HAL */
1079 cesa_ocf_cur_ses = cesa_ocf_sessions[sid];
1080 if (cesa_ocf_cur_ses->sid_encrypt != -1) {
1081 mvCesaSessionClose(cesa_ocf_cur_ses->sid_encrypt);
1083 if (cesa_ocf_cur_ses->sid_decrypt != -1) {
1084 mvCesaSessionClose(cesa_ocf_cur_ses->sid_decrypt);
1086 if (cesa_ocf_cur_ses->frag_wa_encrypt != -1) {
1087 mvCesaSessionClose(cesa_ocf_cur_ses->frag_wa_encrypt);
1089 if (cesa_ocf_cur_ses->frag_wa_decrypt != -1) {
1090 mvCesaSessionClose(cesa_ocf_cur_ses->frag_wa_decrypt);
1092 if (cesa_ocf_cur_ses->frag_wa_auth != -1) {
1093 mvCesaSessionClose(cesa_ocf_cur_ses->frag_wa_auth);
1096 kfree(cesa_ocf_cur_ses);
1097 cesa_ocf_sessions[sid] = NULL;
1103 /* TDMA Window setup */
1106 setup_tdma_mbus_windows(struct cesa_dev *dev)
1110 for (i = 0; i < 4; i++) {
1111 writel(0, dev->reg + WINDOW_BASE(i));
1112 writel(0, dev->reg + WINDOW_CTRL(i));
1115 for (i = 0; i < dev->plat_data->dram->num_cs; i++) {
1116 struct mbus_dram_window *cs = dev->plat_data->dram->cs + i;
1118 ((cs->size - 1) & 0xffff0000) |
1119 (cs->mbus_attr << 8) |
1120 (dev->plat_data->dram->mbus_dram_target_id << 4) | 1,
1121 dev->reg + WINDOW_CTRL(i)
1123 writel(cs->base, dev->reg + WINDOW_BASE(i));
1128 * our driver startup and shutdown routines
1131 mv_cesa_ocf_init(struct platform_device *pdev)
1133 #if defined(CONFIG_MV78200) || defined(CONFIG_MV632X)
1134 if (MV_FALSE == mvSocUnitIsMappedToThisCpu(CESA))
1136 dprintk("CESA is not mapped to this CPU\n");
1141 dprintk("%s\n", __FUNCTION__);
1142 memset(&mv_cesa_dev, 0, sizeof(mv_cesa_dev));
1143 softc_device_init(&mv_cesa_dev, "MV CESA", 0, mv_cesa_methods);
1144 cesa_ocf_id = crypto_get_driverid(softc_get_device(&mv_cesa_dev),CRYPTOCAP_F_HARDWARE);
1146 if (cesa_ocf_id < 0)
1147 panic("MV CESA crypto device cannot initialize!");
1149 dprintk("%s,%d: cesa ocf device id is %d \n", __FILE__, __LINE__, cesa_ocf_id);
1151 /* CESA unit is auto power on off */
1153 if (MV_FALSE == mvCtrlPwrClckGet(CESA_UNIT_ID,0))
1155 printk("\nWarning CESA %d is Powered Off\n",0);
1160 memset(&cesa_device, 0, sizeof(struct cesa_dev));
1161 /* Get the IRQ, and crypto memory regions */
1163 struct resource *res;
1164 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "sram");
1169 cesa_device.sram = ioremap(res->start, res->end - res->start + 1);
1170 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs");
1173 iounmap(cesa_device.sram);
1176 cesa_device.reg = ioremap(res->start, res->end - res->start + 1);
1177 cesa_device.irq = platform_get_irq(pdev, 0);
1178 cesa_device.plat_data = pdev->dev.platform_data;
1179 setup_tdma_mbus_windows(&cesa_device);
1184 if( MV_OK != mvCesaInit(CESA_OCF_MAX_SES*5, CESA_Q_SIZE, cesa_device.reg,
1186 printk("%s,%d: mvCesaInit Failed. \n", __FILE__, __LINE__);
1190 /* clear and unmask Int */
1191 MV_REG_WRITE( MV_CESA_ISR_CAUSE_REG, 0);
1192 #ifndef CESA_OCF_POLLING
1193 MV_REG_WRITE( MV_CESA_ISR_MASK_REG, MV_CESA_CAUSE_ACC_DMA_MASK);
1195 #ifdef CESA_OCF_TASKLET
1196 tasklet_init(&cesa_ocf_tasklet, cesa_callback, (unsigned int) 0);
1198 /* register interrupt */
1199 if( request_irq( cesa_device.irq, cesa_interrupt_handler,
1200 (IRQF_DISABLED) , "cesa", &cesa_ocf_id) < 0) {
1201 printk("%s,%d: cannot assign irq %x\n", __FILE__, __LINE__, cesa_device.reg);
1206 memset(cesa_ocf_sessions, 0, sizeof(struct cesa_ocf_data *) * CESA_OCF_MAX_SES);
1208 #define REGISTER(alg) \
1209 crypto_register(cesa_ocf_id, alg, 0,0)
1210 REGISTER(CRYPTO_AES_CBC);
1211 REGISTER(CRYPTO_DES_CBC);
1212 REGISTER(CRYPTO_3DES_CBC);
1213 REGISTER(CRYPTO_MD5);
1214 REGISTER(CRYPTO_MD5_HMAC);
1215 REGISTER(CRYPTO_SHA1);
1216 REGISTER(CRYPTO_SHA1_HMAC);
1223 mv_cesa_ocf_exit(struct platform_device *pdev)
1225 dprintk("%s()\n", __FUNCTION__);
1227 crypto_unregister_all(cesa_ocf_id);
1229 iounmap(cesa_device.reg);
1230 iounmap(cesa_device.sram);
1231 free_irq(cesa_device.irq, NULL);
1233 /* mask and clear Int */
1234 MV_REG_WRITE( MV_CESA_ISR_MASK_REG, 0);
1235 MV_REG_WRITE( MV_CESA_ISR_CAUSE_REG, 0);
1238 if( MV_OK != mvCesaFinish() ) {
1239 printk("%s,%d: mvCesaFinish Failed. \n", __FILE__, __LINE__);
1245 void cesa_ocf_debug(void)
1248 #ifdef CESA_OCF_TRACE_DEBUG
1251 j = cesaTestTraceIdx;
1252 mvOsPrintf("No Type rCause iCause Proc Isr Res Time pReady pProc pEmpty\n");
1253 for(i=0; i<MV_CESA_TEST_TRACE_SIZE; i++)
1255 mvOsPrintf("%02d. %d 0x%04x 0x%04x 0x%02x 0x%02x %02d 0x%06x %p %p %p\n",
1256 j, cesaTestTrace[j].type, cesaTestTrace[j].realCause,
1257 cesaTestTrace[j].idmaCause,
1258 cesaTestTrace[j].resources, cesaTestTrace[j].timeStamp,
1259 cesaTestTrace[j].pReqReady, cesaTestTrace[j].pReqProcess, cesaTestTrace[j].pReqEmpty);
1261 if(j == MV_CESA_TEST_TRACE_SIZE)
1269 static struct platform_driver marvell_cesa = {
1270 .probe = mv_cesa_ocf_init,
1271 .remove = mv_cesa_ocf_exit,
1273 .owner = THIS_MODULE,
1274 .name = "mv_crypto",
1278 MODULE_ALIAS("platform:mv_crypto");
1280 static int __init mv_cesa_init(void)
1282 return platform_driver_register(&marvell_cesa);
1285 module_init(mv_cesa_init);
1287 static void __exit mv_cesa_exit(void)
1289 platform_driver_unregister(&marvell_cesa);
1292 module_exit(mv_cesa_exit);
1294 MODULE_LICENSE("GPL");
1295 MODULE_AUTHOR("Ronen Shitrit");
1296 MODULE_DESCRIPTION("OCF module for Orion CESA crypto");