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 #include <linux/version.h>
30 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38) && !defined(AUTOCONF_INCLUDED)
31 #include <linux/config.h>
33 #include <linux/module.h>
34 #include <linux/init.h>
35 #include <linux/list.h>
36 #include <linux/slab.h>
37 #include <linux/sched.h>
38 #include <linux/wait.h>
39 #include <linux/crypto.h>
41 #include <linux/skbuff.h>
42 #include <linux/random.h>
43 #include <linux/platform_device.h>
44 #include <asm/scatterlist.h>
45 #include <linux/spinlock.h>
46 #include "ctrlEnv/sys/mvSysCesa.h"
47 #include "cesa/mvCesa.h" /* moved here before cryptodev.h due to include dependencies */
48 #include <cryptodev.h>
50 #include <plat/mv_cesa.h>
51 #include <linux/mbus.h>
54 #include "cesa/mvMD5.h"
55 #include "cesa/mvSHA1.h"
57 #include "cesa/mvCesaRegs.h"
58 #include "cesa/AES/mvAes.h"
59 #include "cesa/mvLru.h"
64 module_param(debug, int, 1);
65 MODULE_PARM_DESC(debug, "Enable debug");
67 #define dprintk(a...) if (debug) { printk(a); } else
76 #define WINDOW_BASE(i) 0xA00 + (i << 3)
77 #define WINDOW_CTRL(i) 0xA04 + (i << 3)
79 /* interrupt handling */
80 #undef CESA_OCF_POLLING
81 #undef CESA_OCF_TASKLET
83 #if defined(CESA_OCF_POLLING) && defined(CESA_OCF_TASKLET)
84 #error "don't use both tasklet and polling mode"
87 extern int cesaReqResources;
88 /* support for spliting action into 2 actions */
89 #define CESA_OCF_SPLIT
92 #define CESA_OCF_MAX_SES 128
93 #define CESA_Q_SIZE 64
95 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3,2,0)
96 #define FRAG_PAGE(f) (f).p
98 #define FRAG_PAGE(f) (f)
101 /* data structures */
102 struct cesa_ocf_data {
106 #define auth_tn_decrypt encrypt_tn_auth
111 /* fragment workaround sessions */
112 short frag_wa_encrypt;
113 short frag_wa_decrypt;
117 /* CESA device data */
121 struct mv_cesa_platform_data *plat_data;
125 #define DIGEST_BUF_SIZE 32
126 struct cesa_ocf_process {
127 MV_CESA_COMMAND cesa_cmd;
128 MV_CESA_MBUF cesa_mbuf;
129 MV_BUF_INFO cesa_bufs[MV_CESA_MAX_MBUF_FRAGS];
130 char digest[DIGEST_BUF_SIZE];
136 /* global variables */
137 static int32_t cesa_ocf_id = -1;
138 static struct cesa_ocf_data *cesa_ocf_sessions[CESA_OCF_MAX_SES];
139 static spinlock_t cesa_lock;
140 static struct cesa_dev cesa_device;
143 static int cesa_ocf_process (device_t, struct cryptop *, int);
144 static int cesa_ocf_newsession (device_t, u_int32_t *, struct cryptoini *);
145 static int cesa_ocf_freesession (device_t, u_int64_t);
146 static void cesa_callback (unsigned long);
147 static irqreturn_t cesa_interrupt_handler (int, void *);
148 #ifdef CESA_OCF_POLLING
149 static void cesa_interrupt_polling(void);
151 #ifdef CESA_OCF_TASKLET
152 static struct tasklet_struct cesa_ocf_tasklet;
155 static struct timeval tt_start;
156 static struct timeval tt_end;
159 * dummy device structure
163 softc_device_decl sc_dev;
166 static device_method_t mv_cesa_methods = {
167 /* crypto device methods */
168 DEVMETHOD(cryptodev_newsession, cesa_ocf_newsession),
169 DEVMETHOD(cryptodev_freesession,cesa_ocf_freesession),
170 DEVMETHOD(cryptodev_process, cesa_ocf_process),
171 DEVMETHOD(cryptodev_kprocess, NULL),
176 /* Add debug Trace */
177 #undef CESA_OCF_TRACE_DEBUG
178 #ifdef CESA_OCF_TRACE_DEBUG
180 #define MV_CESA_USE_TIMER_ID 0
184 int type; /* 0 - isrEmpty, 1 - cesaReadyGet, 2 - cesaAction */
190 MV_CESA_REQ* pReqReady;
191 MV_CESA_REQ* pReqEmpty;
192 MV_CESA_REQ* pReqProcess;
193 } MV_CESA_TEST_TRACE;
195 #define MV_CESA_TEST_TRACE_SIZE 50
197 static int cesaTestTraceIdx = 0;
198 static MV_CESA_TEST_TRACE cesaTestTrace[MV_CESA_TEST_TRACE_SIZE];
200 static void cesaTestTraceAdd(int type)
202 cesaTestTrace[cesaTestTraceIdx].type = type;
203 cesaTestTrace[cesaTestTraceIdx].realCause = MV_REG_READ(MV_CESA_ISR_CAUSE_REG);
204 //cesaTestTrace[cesaTestTraceIdx].idmaCause = MV_REG_READ(IDMA_CAUSE_REG);
205 cesaTestTrace[cesaTestTraceIdx].resources = cesaReqResources;
206 cesaTestTrace[cesaTestTraceIdx].pReqReady = pCesaReqReady;
207 cesaTestTrace[cesaTestTraceIdx].pReqEmpty = pCesaReqEmpty;
208 cesaTestTrace[cesaTestTraceIdx].pReqProcess = pCesaReqProcess;
209 cesaTestTrace[cesaTestTraceIdx].timeStamp = mvCntmrRead(MV_CESA_USE_TIMER_ID);
211 if(cesaTestTraceIdx == MV_CESA_TEST_TRACE_SIZE)
212 cesaTestTraceIdx = 0;
215 #else /* CESA_OCF_TRACE_DEBUG */
217 #define cesaTestTraceAdd(x)
219 #endif /* CESA_OCF_TRACE_DEBUG */
222 get_usec(unsigned int start)
225 do_gettimeofday (&tt_start);
229 do_gettimeofday (&tt_end);
230 tt_end.tv_sec -= tt_start.tv_sec;
231 tt_end.tv_usec -= tt_start.tv_usec;
232 if (tt_end.tv_usec < 0) {
233 tt_end.tv_usec += 1000 * 1000;
237 printk("time taken is %d\n", (unsigned int)(tt_end.tv_usec + tt_end.tv_sec * 1000000));
238 return (tt_end.tv_usec + tt_end.tv_sec * 1000000);
243 * check that the crp action match the current session
246 ocf_check_action(struct cryptop *crp, struct cesa_ocf_data *cesa_ocf_cur_ses) {
248 int encrypt = 0, decrypt = 0, auth = 0;
249 struct cryptodesc *crd;
251 /* Go through crypto descriptors, processing as we go */
252 for (crd = crp->crp_desc; crd; crd = crd->crd_next, count++) {
254 printk("%s,%d: session mode is not supported.\n", __FILE__, __LINE__);
258 /* Encryption /Decryption */
259 if(crd->crd_alg == cesa_ocf_cur_ses->cipher_alg) {
260 /* check that the action is compatible with session */
261 if(encrypt || decrypt) {
262 printk("%s,%d: session mode is not supported.\n", __FILE__, __LINE__);
266 if(crd->crd_flags & CRD_F_ENCRYPT) { /* encrypt */
267 if( (count == 2) && (cesa_ocf_cur_ses->encrypt_tn_auth) ) {
268 printk("%s,%d: sequence isn't supported by this session.\n", __FILE__, __LINE__);
274 if( (count == 2) && !(cesa_ocf_cur_ses->auth_tn_decrypt) ) {
275 printk("%s,%d: sequence isn't supported by this session.\n", __FILE__, __LINE__);
283 else if(crd->crd_alg == cesa_ocf_cur_ses->auth_alg) {
284 /* check that the action is compatible with session */
286 printk("%s,%d: session mode is not supported.\n", __FILE__, __LINE__);
289 if( (count == 2) && (decrypt) && (cesa_ocf_cur_ses->auth_tn_decrypt)) {
290 printk("%s,%d: sequence isn't supported by this session.\n", __FILE__, __LINE__);
293 if( (count == 2) && (encrypt) && !(cesa_ocf_cur_ses->encrypt_tn_auth)) {
294 printk("%s,%d: sequence isn't supported by this session.\n", __FILE__, __LINE__);
300 printk("%s,%d: Alg isn't supported by this session.\n", __FILE__, __LINE__);
313 cesa_ocf_process(device_t dev, struct cryptop *crp, int hint)
315 struct cesa_ocf_process *cesa_ocf_cmd = NULL;
316 struct cesa_ocf_process *cesa_ocf_cmd_wa = NULL;
317 MV_CESA_COMMAND *cesa_cmd;
318 struct cryptodesc *crd;
319 struct cesa_ocf_data *cesa_ocf_cur_ses;
320 int sid = 0, temp_len = 0, i;
321 int encrypt = 0, decrypt = 0, auth = 0;
323 struct sk_buff *skb = NULL;
324 struct uio *uiop = NULL;
326 MV_BUF_INFO *p_buf_info;
327 MV_CESA_MBUF *p_mbuf_info;
330 dprintk("%s()\n", __FUNCTION__);
332 if( cesaReqResources <= 1 ) {
333 dprintk("%s,%d: ERESTART\n", __FILE__, __LINE__);
340 printk("%s,%d: EINVAL\n", __FILE__, __LINE__);
344 if (crp->crp_desc == NULL || crp->crp_buf == NULL ) {
345 printk("%s,%d: EINVAL\n", __FILE__, __LINE__);
346 crp->crp_etype = EINVAL;
350 sid = crp->crp_sid & 0xffffffff;
351 if ((sid >= CESA_OCF_MAX_SES) || (cesa_ocf_sessions[sid] == NULL)) {
352 crp->crp_etype = ENOENT;
353 printk("%s,%d: ENOENT session %d \n", __FILE__, __LINE__, sid);
358 sid = crp->crp_sid & 0xffffffff;
360 cesa_ocf_cur_ses = cesa_ocf_sessions[sid];
363 if(ocf_check_action(crp, cesa_ocf_cur_ses)){
368 /* malloc a new cesa process */
369 cesa_ocf_cmd = kmalloc(sizeof(struct cesa_ocf_process), GFP_ATOMIC);
371 if (cesa_ocf_cmd == NULL) {
372 printk("%s,%d: ENOBUFS \n", __FILE__, __LINE__);
375 memset(cesa_ocf_cmd, 0, sizeof(struct cesa_ocf_process));
377 /* init cesa_process */
378 cesa_ocf_cmd->crp = crp;
379 /* always call callback */
380 cesa_ocf_cmd->need_cb = 1;
382 /* init cesa_cmd for usage of the HALs */
383 cesa_cmd = &cesa_ocf_cmd->cesa_cmd;
384 cesa_cmd->pReqPrv = (void *)cesa_ocf_cmd;
385 cesa_cmd->sessionId = cesa_ocf_cur_ses->sid_encrypt; /* defualt use encrypt */
387 /* prepare src buffer */
388 /* we send the entire buffer to the HAL, even if only part of it should be encrypt/auth. */
389 /* if not using seesions for both encrypt and auth, then it will be wiser to to copy only */
390 /* from skip to crd_len. */
391 p_buf_info = cesa_ocf_cmd->cesa_bufs;
392 p_mbuf_info = &cesa_ocf_cmd->cesa_mbuf;
394 p_buf_info += 2; /* save 2 first buffers for IV and digest -
395 we won't append them to the end since, they
396 might be places in an unaligned addresses. */
398 p_mbuf_info->pFrags = p_buf_info;
402 if (crp->crp_flags & CRYPTO_F_SKBUF) {
404 dprintk("%s,%d: handle SKB.\n", __FILE__, __LINE__);
405 skb = (struct sk_buff *) crp->crp_buf;
407 if (skb_shinfo(skb)->nr_frags >= (MV_CESA_MAX_MBUF_FRAGS - 1)) {
408 printk("%s,%d: %d nr_frags > MV_CESA_MAX_MBUF_FRAGS", __FILE__, __LINE__, skb_shinfo(skb)->nr_frags);
412 p_mbuf_info->mbufSize = skb->len;
414 /* first skb fragment */
415 p_buf_info->bufSize = skb_headlen(skb);
416 p_buf_info->bufVirtPtr = skb->data;
419 /* now handle all other skb fragments */
420 for ( i = 0; i < skb_shinfo(skb)->nr_frags; i++ ) {
421 skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
422 p_buf_info->bufSize = frag->size;
423 p_buf_info->bufVirtPtr = page_address(FRAG_PAGE(frag->page)) + frag->page_offset;
426 p_mbuf_info->numFrags = skb_shinfo(skb)->nr_frags + 1;
429 else if(crp->crp_flags & CRYPTO_F_IOV) {
431 dprintk("%s,%d: handle UIO.\n", __FILE__, __LINE__);
432 uiop = (struct uio *) crp->crp_buf;
434 if (uiop->uio_iovcnt > (MV_CESA_MAX_MBUF_FRAGS - 1)) {
435 printk("%s,%d: %d uio_iovcnt > MV_CESA_MAX_MBUF_FRAGS \n", __FILE__, __LINE__, uiop->uio_iovcnt);
439 p_mbuf_info->mbufSize = crp->crp_ilen;
440 p_mbuf_info->numFrags = uiop->uio_iovcnt;
441 for(i = 0; i < uiop->uio_iovcnt; i++) {
442 p_buf_info->bufVirtPtr = uiop->uio_iov[i].iov_base;
443 p_buf_info->bufSize = uiop->uio_iov[i].iov_len;
444 temp_len += p_buf_info->bufSize;
445 dprintk("%s,%d: buf %x-> addr %x, size %x \n"
446 , __FILE__, __LINE__, i, (unsigned int)p_buf_info->bufVirtPtr, p_buf_info->bufSize);
453 dprintk("%s,%d: handle CONTIG.\n", __FILE__, __LINE__);
454 p_mbuf_info->numFrags = 1;
455 p_mbuf_info->mbufSize = crp->crp_ilen;
456 p_buf_info->bufVirtPtr = crp->crp_buf;
457 p_buf_info->bufSize = crp->crp_ilen;
458 temp_len = crp->crp_ilen;
462 /* Support up to 64K why? cause! */
463 if(crp->crp_ilen > 64*1024) {
464 printk("%s,%d: buf too big %x \n", __FILE__, __LINE__, crp->crp_ilen);
468 if( temp_len != crp->crp_ilen ) {
469 printk("%s,%d: warning size don't match.(%x %x) \n", __FILE__, __LINE__, temp_len, crp->crp_ilen);
472 cesa_cmd->pSrc = p_mbuf_info;
473 cesa_cmd->pDst = p_mbuf_info;
475 /* restore p_buf_info to point to first available buf */
476 p_buf_info = cesa_ocf_cmd->cesa_bufs;
480 /* Go through crypto descriptors, processing as we go */
481 for (crd = crp->crp_desc; crd; crd = crd->crd_next) {
483 /* Encryption /Decryption */
484 if(crd->crd_alg == cesa_ocf_cur_ses->cipher_alg) {
486 dprintk("%s,%d: cipher", __FILE__, __LINE__);
488 cesa_cmd->cryptoOffset = crd->crd_skip;
489 cesa_cmd->cryptoLength = crd->crd_len;
491 if(crd->crd_flags & CRD_F_ENCRYPT) { /* encrypt */
492 dprintk(" encrypt \n");
496 if (crd->crd_flags & CRD_F_IV_EXPLICIT) { /* IV from USER */
497 dprintk("%s,%d: IV from USER (offset %x) \n", __FILE__, __LINE__, crd->crd_inject);
498 cesa_cmd->ivFromUser = 1;
502 * do we have to copy the IV back to the buffer ?
504 if ((crd->crd_flags & CRD_F_IV_PRESENT) == 0) {
505 dprintk("%s,%d: copy the IV back to the buffer\n", __FILE__, __LINE__);
506 cesa_cmd->ivOffset = crd->crd_inject;
507 crypto_copyback(crp->crp_flags, crp->crp_buf, crd->crd_inject, cesa_ocf_cur_ses->ivlen, ivp);
510 dprintk("%s,%d: don't copy the IV back to the buffer \n", __FILE__, __LINE__);
511 p_mbuf_info->numFrags++;
512 p_mbuf_info->mbufSize += cesa_ocf_cur_ses->ivlen;
513 p_mbuf_info->pFrags = p_buf_info;
515 p_buf_info->bufVirtPtr = ivp;
516 p_buf_info->bufSize = cesa_ocf_cur_ses->ivlen;
520 cesa_cmd->ivOffset = 0;
521 cesa_cmd->cryptoOffset += cesa_ocf_cur_ses->ivlen;
523 cesa_cmd->macOffset += cesa_ocf_cur_ses->ivlen;
524 cesa_cmd->digestOffset += cesa_ocf_cur_ses->ivlen;
528 else { /* random IV */
529 dprintk("%s,%d: random IV \n", __FILE__, __LINE__);
530 cesa_cmd->ivFromUser = 0;
533 * do we have to copy the IV back to the buffer ?
535 /* in this mode the HAL will always copy the IV */
536 /* given by the session to the ivOffset */
537 if ((crd->crd_flags & CRD_F_IV_PRESENT) == 0) {
538 cesa_cmd->ivOffset = crd->crd_inject;
541 /* if IV isn't copy, then how will the user know which IV did we use??? */
542 printk("%s,%d: EINVAL\n", __FILE__, __LINE__);
548 dprintk(" decrypt \n");
550 cesa_cmd->sessionId = cesa_ocf_cur_ses->sid_decrypt;
553 if (crd->crd_flags & CRD_F_IV_EXPLICIT) {
554 dprintk("%s,%d: IV from USER \n", __FILE__, __LINE__);
555 /* append the IV buf to the mbuf */
556 cesa_cmd->ivFromUser = 1;
557 p_mbuf_info->numFrags++;
558 p_mbuf_info->mbufSize += cesa_ocf_cur_ses->ivlen;
559 p_mbuf_info->pFrags = p_buf_info;
561 p_buf_info->bufVirtPtr = crd->crd_iv;
562 p_buf_info->bufSize = cesa_ocf_cur_ses->ivlen;
566 cesa_cmd->ivOffset = 0;
567 cesa_cmd->cryptoOffset += cesa_ocf_cur_ses->ivlen;
569 cesa_cmd->macOffset += cesa_ocf_cur_ses->ivlen;
570 cesa_cmd->digestOffset += cesa_ocf_cur_ses->ivlen;
574 dprintk("%s,%d: IV inside the buffer \n", __FILE__, __LINE__);
575 cesa_cmd->ivFromUser = 0;
576 cesa_cmd->ivOffset = crd->crd_inject;
582 else if(crd->crd_alg == cesa_ocf_cur_ses->auth_alg) {
583 dprintk("%s,%d: Authentication \n", __FILE__, __LINE__);
585 cesa_cmd->macOffset = crd->crd_skip;
586 cesa_cmd->macLength = crd->crd_len;
589 cesa_cmd->digestOffset = crd->crd_inject;
592 printk("%s,%d: Alg isn't supported by this session.\n", __FILE__, __LINE__);
598 dprintk("%s,%d: Sending Action: \n", __FILE__, __LINE__);
599 dprintk("%s,%d: IV from user: %d. IV offset %x \n", __FILE__, __LINE__, cesa_cmd->ivFromUser, cesa_cmd->ivOffset);
600 dprintk("%s,%d: crypt offset %x len %x \n", __FILE__, __LINE__, cesa_cmd->cryptoOffset, cesa_cmd->cryptoLength);
601 dprintk("%s,%d: Auth offset %x len %x \n", __FILE__, __LINE__, cesa_cmd->macOffset, cesa_cmd->macLength);
602 dprintk("%s,%d: set digest in offset %x . \n", __FILE__, __LINE__, cesa_cmd->digestOffset);
604 mvCesaDebugMbuf("SRC BUFFER", cesa_cmd->pSrc, 0, cesa_cmd->pSrc->mbufSize);
608 /* send action to HAL */
609 spin_lock_irqsave(&cesa_lock, flags);
610 status = mvCesaAction(cesa_cmd);
611 spin_unlock_irqrestore(&cesa_lock, flags);
613 /* action not allowed */
614 if(status == MV_NOT_ALLOWED) {
615 #ifdef CESA_OCF_SPLIT
616 /* if both encrypt and auth try to split */
617 if(auth && (encrypt || decrypt)) {
618 MV_CESA_COMMAND *cesa_cmd_wa;
620 /* malloc a new cesa process and init it */
621 cesa_ocf_cmd_wa = kmalloc(sizeof(struct cesa_ocf_process), GFP_ATOMIC);
623 if (cesa_ocf_cmd_wa == NULL) {
624 printk("%s,%d: ENOBUFS \n", __FILE__, __LINE__);
627 memcpy(cesa_ocf_cmd_wa, cesa_ocf_cmd, sizeof(struct cesa_ocf_process));
628 cesa_cmd_wa = &cesa_ocf_cmd_wa->cesa_cmd;
629 cesa_cmd_wa->pReqPrv = (void *)cesa_ocf_cmd_wa;
630 cesa_ocf_cmd_wa->need_cb = 0;
632 /* break requests to two operation, first operation completion won't call callback */
633 if((decrypt) && (cesa_ocf_cur_ses->auth_tn_decrypt)) {
634 cesa_cmd_wa->sessionId = cesa_ocf_cur_ses->frag_wa_auth;
635 cesa_cmd->sessionId = cesa_ocf_cur_ses->frag_wa_decrypt;
637 else if((decrypt) && !(cesa_ocf_cur_ses->auth_tn_decrypt)) {
638 cesa_cmd_wa->sessionId = cesa_ocf_cur_ses->frag_wa_decrypt;
639 cesa_cmd->sessionId = cesa_ocf_cur_ses->frag_wa_auth;
641 else if((encrypt) && (cesa_ocf_cur_ses->encrypt_tn_auth)) {
642 cesa_cmd_wa->sessionId = cesa_ocf_cur_ses->frag_wa_encrypt;
643 cesa_cmd->sessionId = cesa_ocf_cur_ses->frag_wa_auth;
645 else if((encrypt) && !(cesa_ocf_cur_ses->encrypt_tn_auth)){
646 cesa_cmd_wa->sessionId = cesa_ocf_cur_ses->frag_wa_auth;
647 cesa_cmd->sessionId = cesa_ocf_cur_ses->frag_wa_encrypt;
650 printk("%s,%d: Unsupporterd fragment wa mode \n", __FILE__, __LINE__);
654 /* send the 2 actions to the HAL */
655 spin_lock_irqsave(&cesa_lock, flags);
656 status = mvCesaAction(cesa_cmd_wa);
657 spin_unlock_irqrestore(&cesa_lock, flags);
659 if((status != MV_NO_MORE) && (status != MV_OK)) {
660 printk("%s,%d: cesa action failed, status = 0x%x\n", __FILE__, __LINE__, status);
663 spin_lock_irqsave(&cesa_lock, flags);
664 status = mvCesaAction(cesa_cmd);
665 spin_unlock_irqrestore(&cesa_lock, flags);
668 /* action not allowed and can't split */
676 /* Hal Q is full, send again. This should never happen */
677 if(status == MV_NO_RESOURCE) {
678 printk("%s,%d: cesa no more resources \n", __FILE__, __LINE__);
682 kfree(cesa_ocf_cmd_wa);
685 else if((status != MV_NO_MORE) && (status != MV_OK)) {
686 printk("%s,%d: cesa action failed, status = 0x%x\n", __FILE__, __LINE__, status);
691 #ifdef CESA_OCF_POLLING
692 cesa_interrupt_polling();
698 crp->crp_etype = EINVAL;
702 kfree(cesa_ocf_cmd_wa);
710 cesa_callback(unsigned long dummy)
712 struct cesa_ocf_process *cesa_ocf_cmd = NULL;
713 struct cryptop *crp = NULL;
714 MV_CESA_RESULT result[MV_CESA_MAX_CHAN];
718 dprintk("%s()\n", __FUNCTION__);
720 #ifdef CESA_OCF_TASKLET
721 disable_irq(cesa_device.irq);
725 /* Get Ready requests */
726 spin_lock(&cesa_lock);
727 status = mvCesaReadyGet(&result[res_idx]);
728 spin_unlock(&cesa_lock);
732 if(status != MV_OK) {
733 #ifdef CESA_OCF_POLLING
734 if(status == MV_BUSY) { /* Fragment */
735 cesa_interrupt_polling();
745 for(i = 0; i < res_idx; i++) {
747 if(!result[i].pReqPrv) {
748 printk("%s,%d: warning private is NULL\n", __FILE__, __LINE__);
752 cesa_ocf_cmd = result[i].pReqPrv;
753 crp = cesa_ocf_cmd->crp;
755 // ignore HMAC error.
756 //if(result->retCode)
757 // crp->crp_etype = EIO;
759 #if defined(CESA_OCF_POLLING)
760 if(!cesa_ocf_cmd->need_cb){
761 cesa_interrupt_polling();
764 if(cesa_ocf_cmd->need_cb) {
766 mvCesaDebugMbuf("DST BUFFER", cesa_ocf_cmd->cesa_cmd.pDst, 0, cesa_ocf_cmd->cesa_cmd.pDst->mbufSize);
772 #ifdef CESA_OCF_TASKLET
773 enable_irq(cesa_device.irq);
781 #ifdef CESA_OCF_POLLING
783 cesa_interrupt_polling(void)
787 dprintk("%s()\n", __FUNCTION__);
789 /* Read cause register */
791 cause = MV_REG_READ(MV_CESA_ISR_CAUSE_REG);
792 cause &= MV_CESA_CAUSE_ACC_DMA_ALL_MASK;
794 } while (cause == 0);
796 /* clear interrupts */
797 MV_REG_WRITE(MV_CESA_ISR_CAUSE_REG, 0);
807 * cesa Interrupt polling routine.
810 cesa_interrupt_handler(int irq, void *arg)
814 dprintk("%s()\n", __FUNCTION__);
818 /* Read cause register */
819 cause = MV_REG_READ(MV_CESA_ISR_CAUSE_REG);
821 if( (cause & MV_CESA_CAUSE_ACC_DMA_ALL_MASK) == 0)
823 /* Empty interrupt */
824 dprintk("%s,%d: cesaTestReadyIsr: cause=0x%x\n", __FILE__, __LINE__, cause);
828 /* clear interrupts */
829 MV_REG_WRITE(MV_CESA_ISR_CAUSE_REG, 0);
832 #ifdef CESA_OCF_TASKLET
833 tasklet_hi_schedule(&cesa_ocf_tasklet);
844 /*cesa_ocf_newsession(void *arg, u_int32_t *sid, struct cryptoini *cri)*/
845 cesa_ocf_newsession(device_t dev, u_int32_t *sid, struct cryptoini *cri)
848 u32 count = 0, auth = 0, encrypt =0;
849 struct cesa_ocf_data *cesa_ocf_cur_ses;
850 MV_CESA_OPEN_SESSION cesa_session;
851 MV_CESA_OPEN_SESSION *cesa_ses = &cesa_session;
854 dprintk("%s()\n", __FUNCTION__);
855 if (sid == NULL || cri == NULL) {
856 printk("%s,%d: EINVAL\n", __FILE__, __LINE__);
860 /* leave first empty like in other implementations */
861 for (i = 1; i < CESA_OCF_MAX_SES; i++) {
862 if (cesa_ocf_sessions[i] == NULL)
866 if(i >= CESA_OCF_MAX_SES) {
867 printk("%s,%d: no more sessions \n", __FILE__, __LINE__);
871 cesa_ocf_sessions[i] = (struct cesa_ocf_data *) kmalloc(sizeof(struct cesa_ocf_data), GFP_ATOMIC);
872 if (cesa_ocf_sessions[i] == NULL) {
873 cesa_ocf_freesession(NULL, i);
874 printk("%s,%d: ENOBUFS \n", __FILE__, __LINE__);
877 dprintk("%s,%d: new session %d \n", __FILE__, __LINE__, i);
880 cesa_ocf_cur_ses = cesa_ocf_sessions[i];
881 memset(cesa_ocf_cur_ses, 0, sizeof(struct cesa_ocf_data));
882 cesa_ocf_cur_ses->sid_encrypt = -1;
883 cesa_ocf_cur_ses->sid_decrypt = -1;
884 cesa_ocf_cur_ses->frag_wa_encrypt = -1;
885 cesa_ocf_cur_ses->frag_wa_decrypt = -1;
886 cesa_ocf_cur_ses->frag_wa_auth = -1;
888 /* init the session */
889 memset(cesa_ses, 0, sizeof(MV_CESA_OPEN_SESSION));
893 printk("%s,%d: don't support more then 2 operations\n", __FILE__, __LINE__);
896 switch (cri->cri_alg) {
898 dprintk("%s,%d: (%d) AES CBC \n", __FILE__, __LINE__, count);
899 cesa_ocf_cur_ses->cipher_alg = cri->cri_alg;
900 cesa_ocf_cur_ses->ivlen = MV_CESA_AES_BLOCK_SIZE;
901 cesa_ses->cryptoAlgorithm = MV_CESA_CRYPTO_AES;
902 cesa_ses->cryptoMode = MV_CESA_CRYPTO_CBC;
903 if(cri->cri_klen/8 > MV_CESA_MAX_CRYPTO_KEY_LENGTH) {
904 printk("%s,%d: CRYPTO key too long.\n", __FILE__, __LINE__);
907 memcpy(cesa_ses->cryptoKey, cri->cri_key, cri->cri_klen/8);
908 dprintk("%s,%d: key length %d \n", __FILE__, __LINE__, cri->cri_klen/8);
909 cesa_ses->cryptoKeyLength = cri->cri_klen/8;
912 case CRYPTO_3DES_CBC:
913 dprintk("%s,%d: (%d) 3DES CBC \n", __FILE__, __LINE__, count);
914 cesa_ocf_cur_ses->cipher_alg = cri->cri_alg;
915 cesa_ocf_cur_ses->ivlen = MV_CESA_3DES_BLOCK_SIZE;
916 cesa_ses->cryptoAlgorithm = MV_CESA_CRYPTO_3DES;
917 cesa_ses->cryptoMode = MV_CESA_CRYPTO_CBC;
918 if(cri->cri_klen/8 > MV_CESA_MAX_CRYPTO_KEY_LENGTH) {
919 printk("%s,%d: CRYPTO key too long.\n", __FILE__, __LINE__);
922 memcpy(cesa_ses->cryptoKey, cri->cri_key, cri->cri_klen/8);
923 cesa_ses->cryptoKeyLength = cri->cri_klen/8;
927 dprintk("%s,%d: (%d) DES CBC \n", __FILE__, __LINE__, count);
928 cesa_ocf_cur_ses->cipher_alg = cri->cri_alg;
929 cesa_ocf_cur_ses->ivlen = MV_CESA_DES_BLOCK_SIZE;
930 cesa_ses->cryptoAlgorithm = MV_CESA_CRYPTO_DES;
931 cesa_ses->cryptoMode = MV_CESA_CRYPTO_CBC;
932 if(cri->cri_klen/8 > MV_CESA_MAX_CRYPTO_KEY_LENGTH) {
933 printk("%s,%d: CRYPTO key too long.\n", __FILE__, __LINE__);
936 memcpy(cesa_ses->cryptoKey, cri->cri_key, cri->cri_klen/8);
937 cesa_ses->cryptoKeyLength = cri->cri_klen/8;
941 case CRYPTO_MD5_HMAC:
942 dprintk("%s,%d: (%d) %sMD5 CBC \n", __FILE__, __LINE__, count, (cri->cri_alg != CRYPTO_MD5)? "H-":" ");
943 cesa_ocf_cur_ses->auth_alg = cri->cri_alg;
944 cesa_ocf_cur_ses->digestlen = (cri->cri_alg == CRYPTO_MD5)? MV_CESA_MD5_DIGEST_SIZE : 12;
945 cesa_ses->macMode = (cri->cri_alg == CRYPTO_MD5)? MV_CESA_MAC_MD5 : MV_CESA_MAC_HMAC_MD5;
946 if(cri->cri_klen/8 > MV_CESA_MAX_CRYPTO_KEY_LENGTH) {
947 printk("%s,%d: MAC key too long. \n", __FILE__, __LINE__);
950 cesa_ses->macKeyLength = cri->cri_klen/8;
951 memcpy(cesa_ses->macKey, cri->cri_key, cri->cri_klen/8);
952 cesa_ses->digestSize = cesa_ocf_cur_ses->digestlen;
956 case CRYPTO_SHA1_HMAC:
957 dprintk("%s,%d: (%d) %sSHA1 CBC \n", __FILE__, __LINE__, count, (cri->cri_alg != CRYPTO_SHA1)? "H-":" ");
958 cesa_ocf_cur_ses->auth_alg = cri->cri_alg;
959 cesa_ocf_cur_ses->digestlen = (cri->cri_alg == CRYPTO_SHA1)? MV_CESA_SHA1_DIGEST_SIZE : 12;
960 cesa_ses->macMode = (cri->cri_alg == CRYPTO_SHA1)? MV_CESA_MAC_SHA1 : MV_CESA_MAC_HMAC_SHA1;
961 if(cri->cri_klen/8 > MV_CESA_MAX_CRYPTO_KEY_LENGTH) {
962 printk("%s,%d: MAC key too long. \n", __FILE__, __LINE__);
965 cesa_ses->macKeyLength = cri->cri_klen/8;
966 memcpy(cesa_ses->macKey, cri->cri_key, cri->cri_klen/8);
967 cesa_ses->digestSize = cesa_ocf_cur_ses->digestlen;
971 printk("%s,%d: unknown algo 0x%x\n", __FILE__, __LINE__, cri->cri_alg);
978 if((encrypt > 2) || (auth > 2)) {
979 printk("%s,%d: session mode is not supported.\n", __FILE__, __LINE__);
982 /* create new sessions in HAL */
984 cesa_ses->operation = MV_CESA_CRYPTO_ONLY;
985 /* encrypt session */
987 cesa_ses->operation = MV_CESA_MAC_THEN_CRYPTO;
990 cesa_ses->operation = MV_CESA_CRYPTO_THEN_MAC;
991 cesa_ocf_cur_ses->encrypt_tn_auth = 1;
994 cesa_ses->operation = MV_CESA_CRYPTO_ONLY;
996 cesa_ses->direction = MV_CESA_DIR_ENCODE;
997 status = mvCesaSessionOpen(cesa_ses, &cesa_ocf_cur_ses->sid_encrypt);
998 if(status != MV_OK) {
999 printk("%s,%d: Can't open new session - status = 0x%x\n", __FILE__, __LINE__, status);
1002 /* decrypt session */
1003 if( cesa_ses->operation == MV_CESA_MAC_THEN_CRYPTO ) {
1004 cesa_ses->operation = MV_CESA_CRYPTO_THEN_MAC;
1006 else if( cesa_ses->operation == MV_CESA_CRYPTO_THEN_MAC ) {
1007 cesa_ses->operation = MV_CESA_MAC_THEN_CRYPTO;
1009 cesa_ses->direction = MV_CESA_DIR_DECODE;
1010 status = mvCesaSessionOpen(cesa_ses, &cesa_ocf_cur_ses->sid_decrypt);
1011 if(status != MV_OK) {
1012 printk("%s,%d: Can't open new session - status = 0x%x\n", __FILE__, __LINE__, status);
1016 /* preapre one action sessions for case we will need to split an action */
1017 #ifdef CESA_OCF_SPLIT
1018 if(( cesa_ses->operation == MV_CESA_MAC_THEN_CRYPTO ) ||
1019 ( cesa_ses->operation == MV_CESA_CRYPTO_THEN_MAC )) {
1020 /* open one session for encode and one for decode */
1021 cesa_ses->operation = MV_CESA_CRYPTO_ONLY;
1022 cesa_ses->direction = MV_CESA_DIR_ENCODE;
1023 status = mvCesaSessionOpen(cesa_ses, &cesa_ocf_cur_ses->frag_wa_encrypt);
1024 if(status != MV_OK) {
1025 printk("%s,%d: Can't open new session - status = 0x%x\n", __FILE__, __LINE__, status);
1029 cesa_ses->direction = MV_CESA_DIR_DECODE;
1030 status = mvCesaSessionOpen(cesa_ses, &cesa_ocf_cur_ses->frag_wa_decrypt);
1031 if(status != MV_OK) {
1032 printk("%s,%d: Can't open new session - status = 0x%x\n", __FILE__, __LINE__, status);
1035 /* open one session for auth */
1036 cesa_ses->operation = MV_CESA_MAC_ONLY;
1037 cesa_ses->direction = MV_CESA_DIR_ENCODE;
1038 status = mvCesaSessionOpen(cesa_ses, &cesa_ocf_cur_ses->frag_wa_auth);
1039 if(status != MV_OK) {
1040 printk("%s,%d: Can't open new session - status = 0x%x\n", __FILE__, __LINE__, status);
1046 else { /* only auth */
1047 cesa_ses->operation = MV_CESA_MAC_ONLY;
1048 cesa_ses->direction = MV_CESA_DIR_ENCODE;
1049 status = mvCesaSessionOpen(cesa_ses, &cesa_ocf_cur_ses->sid_encrypt);
1050 if(status != MV_OK) {
1051 printk("%s,%d: Can't open new session - status = 0x%x\n", __FILE__, __LINE__, status);
1058 cesa_ocf_freesession(NULL, *sid);
1068 cesa_ocf_freesession(device_t dev, u_int64_t tid)
1070 struct cesa_ocf_data *cesa_ocf_cur_ses;
1071 u_int32_t sid = CRYPTO_SESID2LID(tid);
1072 //unsigned long flags;
1074 dprintk("%s() %d \n", __FUNCTION__, sid);
1075 if ( (sid >= CESA_OCF_MAX_SES) || (cesa_ocf_sessions[sid] == NULL) ) {
1076 printk("%s,%d: EINVAL can't free session %d \n", __FILE__, __LINE__, sid);
1080 /* Silently accept and return */
1084 /* release session from HAL */
1085 cesa_ocf_cur_ses = cesa_ocf_sessions[sid];
1086 if (cesa_ocf_cur_ses->sid_encrypt != -1) {
1087 mvCesaSessionClose(cesa_ocf_cur_ses->sid_encrypt);
1089 if (cesa_ocf_cur_ses->sid_decrypt != -1) {
1090 mvCesaSessionClose(cesa_ocf_cur_ses->sid_decrypt);
1092 if (cesa_ocf_cur_ses->frag_wa_encrypt != -1) {
1093 mvCesaSessionClose(cesa_ocf_cur_ses->frag_wa_encrypt);
1095 if (cesa_ocf_cur_ses->frag_wa_decrypt != -1) {
1096 mvCesaSessionClose(cesa_ocf_cur_ses->frag_wa_decrypt);
1098 if (cesa_ocf_cur_ses->frag_wa_auth != -1) {
1099 mvCesaSessionClose(cesa_ocf_cur_ses->frag_wa_auth);
1102 kfree(cesa_ocf_cur_ses);
1103 cesa_ocf_sessions[sid] = NULL;
1109 /* TDMA Window setup */
1112 setup_tdma_mbus_windows(struct cesa_dev *dev)
1116 for (i = 0; i < 4; i++) {
1117 writel(0, dev->reg + WINDOW_BASE(i));
1118 writel(0, dev->reg + WINDOW_CTRL(i));
1121 for (i = 0; i < dev->plat_data->dram->num_cs; i++) {
1122 struct mbus_dram_window *cs = dev->plat_data->dram->cs + i;
1124 ((cs->size - 1) & 0xffff0000) |
1125 (cs->mbus_attr << 8) |
1126 (dev->plat_data->dram->mbus_dram_target_id << 4) | 1,
1127 dev->reg + WINDOW_CTRL(i)
1129 writel(cs->base, dev->reg + WINDOW_BASE(i));
1134 * our driver startup and shutdown routines
1137 mv_cesa_ocf_init(struct platform_device *pdev)
1139 #if defined(CONFIG_MV78200) || defined(CONFIG_MV632X)
1140 if (MV_FALSE == mvSocUnitIsMappedToThisCpu(CESA))
1142 dprintk("CESA is not mapped to this CPU\n");
1147 dprintk("%s\n", __FUNCTION__);
1148 memset(&mv_cesa_dev, 0, sizeof(mv_cesa_dev));
1149 softc_device_init(&mv_cesa_dev, "MV CESA", 0, mv_cesa_methods);
1150 cesa_ocf_id = crypto_get_driverid(softc_get_device(&mv_cesa_dev),CRYPTOCAP_F_HARDWARE);
1152 if (cesa_ocf_id < 0)
1153 panic("MV CESA crypto device cannot initialize!");
1155 dprintk("%s,%d: cesa ocf device id is %d \n", __FILE__, __LINE__, cesa_ocf_id);
1157 /* CESA unit is auto power on off */
1159 if (MV_FALSE == mvCtrlPwrClckGet(CESA_UNIT_ID,0))
1161 printk("\nWarning CESA %d is Powered Off\n",0);
1166 memset(&cesa_device, 0, sizeof(struct cesa_dev));
1167 /* Get the IRQ, and crypto memory regions */
1169 struct resource *res;
1170 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "sram");
1175 cesa_device.sram = ioremap(res->start, res->end - res->start + 1);
1176 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs");
1179 iounmap(cesa_device.sram);
1182 cesa_device.reg = ioremap(res->start, res->end - res->start + 1);
1183 cesa_device.irq = platform_get_irq(pdev, 0);
1184 cesa_device.plat_data = pdev->dev.platform_data;
1185 setup_tdma_mbus_windows(&cesa_device);
1190 if( MV_OK != mvCesaInit(CESA_OCF_MAX_SES*5, CESA_Q_SIZE, cesa_device.reg,
1192 printk("%s,%d: mvCesaInit Failed. \n", __FILE__, __LINE__);
1196 /* clear and unmask Int */
1197 MV_REG_WRITE( MV_CESA_ISR_CAUSE_REG, 0);
1198 #ifndef CESA_OCF_POLLING
1199 MV_REG_WRITE( MV_CESA_ISR_MASK_REG, MV_CESA_CAUSE_ACC_DMA_MASK);
1201 #ifdef CESA_OCF_TASKLET
1202 tasklet_init(&cesa_ocf_tasklet, cesa_callback, (unsigned int) 0);
1204 /* register interrupt */
1205 if( request_irq( cesa_device.irq, cesa_interrupt_handler,
1206 0, "cesa", &cesa_ocf_id) < 0) {
1207 printk("%s,%d: cannot assign irq %x\n", __FILE__, __LINE__, cesa_device.reg);
1212 memset(cesa_ocf_sessions, 0, sizeof(struct cesa_ocf_data *) * CESA_OCF_MAX_SES);
1214 #define REGISTER(alg) \
1215 crypto_register(cesa_ocf_id, alg, 0,0)
1216 REGISTER(CRYPTO_AES_CBC);
1217 REGISTER(CRYPTO_DES_CBC);
1218 REGISTER(CRYPTO_3DES_CBC);
1219 REGISTER(CRYPTO_MD5);
1220 REGISTER(CRYPTO_MD5_HMAC);
1221 REGISTER(CRYPTO_SHA1);
1222 REGISTER(CRYPTO_SHA1_HMAC);
1229 mv_cesa_ocf_exit(struct platform_device *pdev)
1231 dprintk("%s()\n", __FUNCTION__);
1233 crypto_unregister_all(cesa_ocf_id);
1235 iounmap(cesa_device.reg);
1236 iounmap(cesa_device.sram);
1237 free_irq(cesa_device.irq, NULL);
1239 /* mask and clear Int */
1240 MV_REG_WRITE( MV_CESA_ISR_MASK_REG, 0);
1241 MV_REG_WRITE( MV_CESA_ISR_CAUSE_REG, 0);
1244 if( MV_OK != mvCesaFinish() ) {
1245 printk("%s,%d: mvCesaFinish Failed. \n", __FILE__, __LINE__);
1251 void cesa_ocf_debug(void)
1254 #ifdef CESA_OCF_TRACE_DEBUG
1257 j = cesaTestTraceIdx;
1258 mvOsPrintf("No Type rCause iCause Proc Isr Res Time pReady pProc pEmpty\n");
1259 for(i=0; i<MV_CESA_TEST_TRACE_SIZE; i++)
1261 mvOsPrintf("%02d. %d 0x%04x 0x%04x 0x%02x 0x%02x %02d 0x%06x %p %p %p\n",
1262 j, cesaTestTrace[j].type, cesaTestTrace[j].realCause,
1263 cesaTestTrace[j].idmaCause,
1264 cesaTestTrace[j].resources, cesaTestTrace[j].timeStamp,
1265 cesaTestTrace[j].pReqReady, cesaTestTrace[j].pReqProcess, cesaTestTrace[j].pReqEmpty);
1267 if(j == MV_CESA_TEST_TRACE_SIZE)
1275 static struct platform_driver marvell_cesa = {
1276 .probe = mv_cesa_ocf_init,
1277 .remove = mv_cesa_ocf_exit,
1279 .owner = THIS_MODULE,
1280 .name = "mv_crypto",
1284 MODULE_ALIAS("platform:mv_crypto");
1286 static int __init mv_cesa_init(void)
1288 return platform_driver_register(&marvell_cesa);
1291 module_init(mv_cesa_init);
1293 static void __exit mv_cesa_exit(void)
1295 platform_driver_unregister(&marvell_cesa);
1298 module_exit(mv_cesa_exit);
1300 MODULE_LICENSE("GPL");
1301 MODULE_AUTHOR("Ronen Shitrit");
1302 MODULE_DESCRIPTION("OCF module for Orion CESA crypto");