ocf-linux: version bump to 20110720
[15.05/openwrt.git] / target / linux / generic / files / crypto / ocf / kirkwood / cesa_ocf_drv.c
1 /*******************************************************************************
2 Copyright (C) Marvell International Ltd. and its affiliates
3
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.
11
12
13 ********************************************************************************
14 Marvell GPL License Option
15
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.
22
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
26 disclaimer.
27 *******************************************************************************/
28
29 #include <linux/version.h>
30 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38) && !defined(AUTOCONF_INCLUDED)
31 #include <linux/config.h>
32 #endif
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>
40 #include <linux/mm.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>
49 #include <uio.h>
50 #include <plat/mv_cesa.h>
51 #include <linux/mbus.h>
52 #include "mvDebug.h"
53
54 #include "cesa/mvMD5.h"
55 #include "cesa/mvSHA1.h"
56
57 #include "cesa/mvCesaRegs.h"
58 #include "cesa/AES/mvAes.h"
59 #include "cesa/mvLru.h"
60
61 #undef  RT_DEBUG
62 #ifdef RT_DEBUG
63 static int debug = 1;
64 module_param(debug, int, 1);
65 MODULE_PARM_DESC(debug, "Enable debug");
66 #undef dprintk
67 #define dprintk(a...)   if (debug) { printk(a); } else
68 #else
69 static int debug = 0;
70 #undef dprintk
71 #define dprintk(a...)
72 #endif
73
74
75 /* TDMA Regs */
76 #define WINDOW_BASE(i) 0xA00 + (i << 3)
77 #define WINDOW_CTRL(i) 0xA04 + (i << 3)
78
79 /* interrupt handling */
80 #undef CESA_OCF_POLLING
81 #undef CESA_OCF_TASKLET
82
83 #if defined(CESA_OCF_POLLING) && defined(CESA_OCF_TASKLET)
84 #error "don't use both tasklet and polling mode"
85 #endif
86
87 extern int cesaReqResources;
88 /* support for spliting action into 2 actions */
89 #define CESA_OCF_SPLIT
90
91 /* general defines */
92 #define CESA_OCF_MAX_SES 128
93 #define CESA_Q_SIZE      64
94
95
96 /* data structures */
97 struct cesa_ocf_data {
98         int                                      cipher_alg;
99         int                                      auth_alg;
100         int                                      encrypt_tn_auth;
101 #define  auth_tn_decrypt  encrypt_tn_auth
102         int                                      ivlen;
103         int                                      digestlen;
104         short                                    sid_encrypt;
105         short                                    sid_decrypt;
106         /* fragment workaround sessions */
107         short                                    frag_wa_encrypt;
108         short                                    frag_wa_decrypt;
109         short                                    frag_wa_auth;
110 };
111
112 /* CESA device data */
113 struct cesa_dev {
114         void __iomem *sram;
115         void __iomem *reg;
116         struct mv_cesa_platform_data *plat_data;
117         int irq;
118 };
119
120 #define DIGEST_BUF_SIZE 32
121 struct cesa_ocf_process {
122         MV_CESA_COMMAND                         cesa_cmd;
123         MV_CESA_MBUF                            cesa_mbuf;      
124         MV_BUF_INFO                             cesa_bufs[MV_CESA_MAX_MBUF_FRAGS];
125         char                                    digest[DIGEST_BUF_SIZE];
126         int                                     digest_len;
127         struct cryptop                          *crp;
128         int                                     need_cb;
129 };
130
131 /* global variables */
132 static int32_t                  cesa_ocf_id             = -1;
133 static struct cesa_ocf_data     *cesa_ocf_sessions[CESA_OCF_MAX_SES];
134 static spinlock_t               cesa_lock;
135 static struct cesa_dev cesa_device;
136
137 /* static APIs */
138 static int              cesa_ocf_process        (device_t, struct cryptop *, int);
139 static int              cesa_ocf_newsession     (device_t, u_int32_t *, struct cryptoini *);
140 static int              cesa_ocf_freesession    (device_t, u_int64_t);
141 static void             cesa_callback           (unsigned long);
142 static irqreturn_t      cesa_interrupt_handler  (int, void *);
143 #ifdef CESA_OCF_POLLING
144 static void cesa_interrupt_polling(void);
145 #endif
146 #ifdef CESA_OCF_TASKLET
147 static struct tasklet_struct cesa_ocf_tasklet;
148 #endif
149
150 static struct timeval          tt_start;
151 static struct timeval          tt_end;
152
153 /*
154  * dummy device structure
155  */
156
157 static struct {
158         softc_device_decl       sc_dev;
159 } mv_cesa_dev;
160
161 static device_method_t mv_cesa_methods = {
162         /* crypto device methods */
163         DEVMETHOD(cryptodev_newsession, cesa_ocf_newsession),
164         DEVMETHOD(cryptodev_freesession,cesa_ocf_freesession),
165         DEVMETHOD(cryptodev_process,    cesa_ocf_process),
166         DEVMETHOD(cryptodev_kprocess,   NULL),
167 };
168
169
170
171 /* Add debug Trace */
172 #undef CESA_OCF_TRACE_DEBUG
173 #ifdef CESA_OCF_TRACE_DEBUG
174
175 #define MV_CESA_USE_TIMER_ID    0
176
177 typedef struct
178 {
179     int             type;       /* 0 - isrEmpty, 1 - cesaReadyGet, 2 - cesaAction */
180     MV_U32          timeStamp;
181     MV_U32          cause;
182     MV_U32          realCause;
183     MV_U32          dmaCause;
184     int             resources;
185     MV_CESA_REQ*    pReqReady;
186     MV_CESA_REQ*    pReqEmpty;
187     MV_CESA_REQ*    pReqProcess;
188 } MV_CESA_TEST_TRACE;
189
190 #define MV_CESA_TEST_TRACE_SIZE      50
191
192 static int cesaTestTraceIdx = 0;
193 static MV_CESA_TEST_TRACE    cesaTestTrace[MV_CESA_TEST_TRACE_SIZE];
194
195 static void cesaTestTraceAdd(int type)
196 {
197     cesaTestTrace[cesaTestTraceIdx].type = type;
198     cesaTestTrace[cesaTestTraceIdx].realCause = MV_REG_READ(MV_CESA_ISR_CAUSE_REG);
199     //cesaTestTrace[cesaTestTraceIdx].idmaCause = MV_REG_READ(IDMA_CAUSE_REG);
200     cesaTestTrace[cesaTestTraceIdx].resources = cesaReqResources;
201     cesaTestTrace[cesaTestTraceIdx].pReqReady = pCesaReqReady;
202     cesaTestTrace[cesaTestTraceIdx].pReqEmpty = pCesaReqEmpty;
203     cesaTestTrace[cesaTestTraceIdx].pReqProcess = pCesaReqProcess;
204     cesaTestTrace[cesaTestTraceIdx].timeStamp = mvCntmrRead(MV_CESA_USE_TIMER_ID);
205     cesaTestTraceIdx++;
206     if(cesaTestTraceIdx == MV_CESA_TEST_TRACE_SIZE)
207         cesaTestTraceIdx = 0;
208 }
209
210 #else /* CESA_OCF_TRACE_DEBUG */
211
212 #define cesaTestTraceAdd(x)
213
214 #endif /* CESA_OCF_TRACE_DEBUG */
215
216 unsigned int
217 get_usec(unsigned int start)
218 {
219         if(start) {
220                 do_gettimeofday (&tt_start);
221                 return 0;
222         }
223         else {
224                 do_gettimeofday (&tt_end);
225                 tt_end.tv_sec -= tt_start.tv_sec;
226                 tt_end.tv_usec -= tt_start.tv_usec;
227                 if (tt_end.tv_usec < 0) {
228                         tt_end.tv_usec += 1000 * 1000;
229                         tt_end.tv_sec -= 1;
230                 }
231         }
232         printk("time taken is  %d\n", (unsigned int)(tt_end.tv_usec + tt_end.tv_sec * 1000000));
233         return (tt_end.tv_usec + tt_end.tv_sec * 1000000);
234 }
235
236 #ifdef RT_DEBUG
237 /* 
238  * check that the crp action match the current session
239  */
240 static int 
241 ocf_check_action(struct cryptop *crp, struct cesa_ocf_data *cesa_ocf_cur_ses) {
242         int count = 0;
243         int encrypt = 0, decrypt = 0, auth = 0;
244         struct cryptodesc *crd;
245
246         /* Go through crypto descriptors, processing as we go */
247         for (crd = crp->crp_desc; crd; crd = crd->crd_next, count++) {
248                 if(count > 2) {
249                         printk("%s,%d: session mode is not supported.\n", __FILE__, __LINE__);
250                         return 1;
251                 }
252                 
253                 /* Encryption /Decryption */
254                 if(crd->crd_alg == cesa_ocf_cur_ses->cipher_alg) {
255                         /* check that the action is compatible with session */
256                         if(encrypt || decrypt) {
257                                 printk("%s,%d: session mode is not supported.\n", __FILE__, __LINE__);
258                                 return 1;
259                         }
260
261                         if(crd->crd_flags & CRD_F_ENCRYPT) { /* encrypt */
262                                 if( (count == 2) && (cesa_ocf_cur_ses->encrypt_tn_auth) ) {
263                                         printk("%s,%d: sequence isn't supported by this session.\n", __FILE__, __LINE__);
264                                         return 1;
265                                 }
266                                 encrypt++;
267                         }
268                         else {                                  /* decrypt */
269                                 if( (count == 2) && !(cesa_ocf_cur_ses->auth_tn_decrypt) ) {
270                                         printk("%s,%d: sequence isn't supported by this session.\n", __FILE__, __LINE__);
271                                         return 1;
272                                 }
273                                 decrypt++;
274                         }
275
276                 }
277                 /* Authentication */
278                 else if(crd->crd_alg == cesa_ocf_cur_ses->auth_alg) {
279                         /* check that the action is compatible with session */
280                         if(auth) {
281                                 printk("%s,%d: session mode is not supported.\n", __FILE__, __LINE__);
282                                 return 1;
283                         }
284                         if( (count == 2) && (decrypt) && (cesa_ocf_cur_ses->auth_tn_decrypt)) {
285                                 printk("%s,%d: sequence isn't supported by this session.\n", __FILE__, __LINE__);
286                                 return 1;
287                         }
288                         if( (count == 2) && (encrypt) && !(cesa_ocf_cur_ses->encrypt_tn_auth)) {
289                                 printk("%s,%d: sequence isn't supported by this session.\n", __FILE__, __LINE__);
290                                 return 1;
291                         }
292                         auth++;
293                 } 
294                 else {
295                         printk("%s,%d: Alg isn't supported by this session.\n", __FILE__, __LINE__);
296                         return 1;
297                 }
298         }
299         return 0;
300
301 }
302 #endif
303
304 /*
305  * Process a request.
306  */
307 static int 
308 cesa_ocf_process(device_t dev, struct cryptop *crp, int hint)
309 {
310         struct cesa_ocf_process *cesa_ocf_cmd = NULL;
311         struct cesa_ocf_process *cesa_ocf_cmd_wa = NULL;
312         MV_CESA_COMMAND *cesa_cmd;
313         struct cryptodesc *crd;
314         struct cesa_ocf_data *cesa_ocf_cur_ses;
315         int sid = 0, temp_len = 0, i;
316         int encrypt = 0, decrypt = 0, auth = 0;
317         int  status;
318         struct sk_buff *skb = NULL;
319         struct uio *uiop = NULL;
320         unsigned char *ivp;
321         MV_BUF_INFO *p_buf_info;        
322         MV_CESA_MBUF *p_mbuf_info;
323         unsigned long flags;
324
325         dprintk("%s()\n", __FUNCTION__);
326
327         if( cesaReqResources <= 1 ) {
328                 dprintk("%s,%d: ERESTART\n", __FILE__, __LINE__);
329                 return ERESTART;
330         }
331
332 #ifdef RT_DEBUG
333         /* Sanity check */
334         if (crp == NULL) {
335                 printk("%s,%d: EINVAL\n", __FILE__, __LINE__);
336                 return EINVAL;
337         }
338
339         if (crp->crp_desc == NULL || crp->crp_buf == NULL ) {
340                 printk("%s,%d: EINVAL\n", __FILE__, __LINE__);
341                 crp->crp_etype = EINVAL;
342                 return EINVAL;
343         }
344
345         sid = crp->crp_sid & 0xffffffff;
346         if ((sid >= CESA_OCF_MAX_SES) || (cesa_ocf_sessions[sid] == NULL)) {
347                 crp->crp_etype = ENOENT;
348                 printk("%s,%d: ENOENT session %d \n", __FILE__, __LINE__, sid);
349                 return EINVAL;
350         }
351 #endif
352
353         sid = crp->crp_sid & 0xffffffff;
354         crp->crp_etype = 0;
355         cesa_ocf_cur_ses = cesa_ocf_sessions[sid];
356
357 #ifdef RT_DEBUG
358         if(ocf_check_action(crp, cesa_ocf_cur_ses)){
359                 goto p_error;
360         }
361 #endif
362
363         /* malloc a new  cesa process */        
364         cesa_ocf_cmd = kmalloc(sizeof(struct cesa_ocf_process), GFP_ATOMIC);
365         
366         if (cesa_ocf_cmd == NULL) {
367                 printk("%s,%d: ENOBUFS \n", __FILE__, __LINE__);
368                 goto p_error;
369         }
370         memset(cesa_ocf_cmd, 0, sizeof(struct cesa_ocf_process));
371
372         /* init cesa_process */
373         cesa_ocf_cmd->crp = crp;
374         /* always call callback */
375         cesa_ocf_cmd->need_cb = 1;
376
377         /* init cesa_cmd for usage of the HALs */
378         cesa_cmd = &cesa_ocf_cmd->cesa_cmd;
379         cesa_cmd->pReqPrv = (void *)cesa_ocf_cmd;
380         cesa_cmd->sessionId = cesa_ocf_cur_ses->sid_encrypt; /* defualt use encrypt */
381
382         /* prepare src buffer   */
383         /* we send the entire buffer to the HAL, even if only part of it should be encrypt/auth.  */
384         /* if not using seesions for both encrypt and auth, then it will be wiser to to copy only */
385         /* from skip to crd_len.                                                                  */
386         p_buf_info = cesa_ocf_cmd->cesa_bufs;   
387         p_mbuf_info = &cesa_ocf_cmd->cesa_mbuf;
388
389         p_buf_info += 2; /* save 2 first buffers for IV and digest - 
390                             we won't append them to the end since, they 
391                             might be places in an unaligned addresses. */
392         
393         p_mbuf_info->pFrags = p_buf_info;
394         temp_len = 0;
395
396         /* handle SKB */
397         if (crp->crp_flags & CRYPTO_F_SKBUF) {
398                 
399                 dprintk("%s,%d: handle SKB.\n", __FILE__, __LINE__);
400                 skb = (struct sk_buff *) crp->crp_buf;
401
402                 if (skb_shinfo(skb)->nr_frags >= (MV_CESA_MAX_MBUF_FRAGS - 1)) {
403                         printk("%s,%d: %d nr_frags > MV_CESA_MAX_MBUF_FRAGS", __FILE__, __LINE__, skb_shinfo(skb)->nr_frags);
404                         goto p_error;
405                 }
406
407                 p_mbuf_info->mbufSize = skb->len;
408                 temp_len = skb->len;
409                 /* first skb fragment */
410                 p_buf_info->bufSize = skb_headlen(skb);
411                 p_buf_info->bufVirtPtr = skb->data;
412                 p_buf_info++;
413
414                 /* now handle all other skb fragments */
415                 for ( i = 0; i < skb_shinfo(skb)->nr_frags; i++ ) {
416                         skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
417                         p_buf_info->bufSize = frag->size;
418                         p_buf_info->bufVirtPtr = page_address(frag->page) + frag->page_offset;
419                         p_buf_info++;
420                 }
421                 p_mbuf_info->numFrags = skb_shinfo(skb)->nr_frags + 1;
422         }
423         /* handle UIO */
424         else if(crp->crp_flags & CRYPTO_F_IOV) {
425         
426                 dprintk("%s,%d: handle UIO.\n", __FILE__, __LINE__);
427                 uiop = (struct uio *) crp->crp_buf;
428
429                 if (uiop->uio_iovcnt > (MV_CESA_MAX_MBUF_FRAGS - 1)) {
430                         printk("%s,%d: %d uio_iovcnt > MV_CESA_MAX_MBUF_FRAGS \n", __FILE__, __LINE__, uiop->uio_iovcnt);
431                         goto p_error;
432                 }
433
434                 p_mbuf_info->mbufSize = crp->crp_ilen;
435                 p_mbuf_info->numFrags = uiop->uio_iovcnt;
436                 for(i = 0; i < uiop->uio_iovcnt; i++) {
437                         p_buf_info->bufVirtPtr = uiop->uio_iov[i].iov_base;
438                         p_buf_info->bufSize = uiop->uio_iov[i].iov_len;
439                         temp_len += p_buf_info->bufSize;
440                         dprintk("%s,%d: buf %x-> addr %x, size %x \n"
441                                 , __FILE__, __LINE__, i, (unsigned int)p_buf_info->bufVirtPtr, p_buf_info->bufSize);
442                         p_buf_info++;                   
443                 }
444
445         }
446         /* handle CONTIG */
447         else {
448                 dprintk("%s,%d: handle CONTIG.\n", __FILE__, __LINE__); 
449                 p_mbuf_info->numFrags = 1;
450                 p_mbuf_info->mbufSize = crp->crp_ilen;
451                 p_buf_info->bufVirtPtr = crp->crp_buf;
452                 p_buf_info->bufSize = crp->crp_ilen;
453                 temp_len = crp->crp_ilen;
454                 p_buf_info++;
455         }
456         
457         /* Support up to 64K why? cause! */
458         if(crp->crp_ilen > 64*1024) {
459                 printk("%s,%d: buf too big %x \n", __FILE__, __LINE__, crp->crp_ilen);
460                 goto p_error;
461         }
462
463         if( temp_len != crp->crp_ilen ) {
464                 printk("%s,%d: warning size don't match.(%x %x) \n", __FILE__, __LINE__, temp_len, crp->crp_ilen);
465         }       
466
467         cesa_cmd->pSrc = p_mbuf_info;
468         cesa_cmd->pDst = p_mbuf_info;
469         
470         /* restore p_buf_info to point to first available buf */
471         p_buf_info = cesa_ocf_cmd->cesa_bufs;   
472         p_buf_info += 1; 
473
474
475         /* Go through crypto descriptors, processing as we go */
476         for (crd = crp->crp_desc; crd; crd = crd->crd_next) {
477                 
478                 /* Encryption /Decryption */
479                 if(crd->crd_alg == cesa_ocf_cur_ses->cipher_alg) {
480
481                         dprintk("%s,%d: cipher", __FILE__, __LINE__);
482
483                         cesa_cmd->cryptoOffset = crd->crd_skip;
484                         cesa_cmd->cryptoLength = crd->crd_len;
485
486                         if(crd->crd_flags & CRD_F_ENCRYPT) { /* encrypt */
487                                 dprintk(" encrypt \n");
488                                 encrypt++;
489
490                                 /* handle IV */
491                                 if (crd->crd_flags & CRD_F_IV_EXPLICIT) {  /* IV from USER */
492                                         dprintk("%s,%d: IV from USER (offset %x) \n", __FILE__, __LINE__, crd->crd_inject);
493                                         cesa_cmd->ivFromUser = 1;
494                                         ivp = crd->crd_iv;
495
496                                         /*
497                                          * do we have to copy the IV back to the buffer ?
498                                          */
499                                         if ((crd->crd_flags & CRD_F_IV_PRESENT) == 0) {
500                                                 dprintk("%s,%d: copy the IV back to the buffer\n", __FILE__, __LINE__);
501                                                 cesa_cmd->ivOffset = crd->crd_inject;
502                                                 crypto_copyback(crp->crp_flags, crp->crp_buf, crd->crd_inject, cesa_ocf_cur_ses->ivlen, ivp);
503                                         }
504                                         else {
505                                                 dprintk("%s,%d: don't copy the IV back to the buffer \n", __FILE__, __LINE__);
506                                                 p_mbuf_info->numFrags++;
507                                                 p_mbuf_info->mbufSize += cesa_ocf_cur_ses->ivlen; 
508                                                 p_mbuf_info->pFrags = p_buf_info;
509
510                                                 p_buf_info->bufVirtPtr = ivp;
511                                                 p_buf_info->bufSize = cesa_ocf_cur_ses->ivlen; 
512                                                 p_buf_info--;
513
514                                                 /* offsets */
515                                                 cesa_cmd->ivOffset = 0;
516                                                 cesa_cmd->cryptoOffset += cesa_ocf_cur_ses->ivlen;
517                                                 if(auth) {
518                                                         cesa_cmd->macOffset += cesa_ocf_cur_ses->ivlen;
519                                                         cesa_cmd->digestOffset += cesa_ocf_cur_ses->ivlen; 
520                                                 }       
521                                         }
522                                 }
523                                 else {                                  /* random IV */
524                                         dprintk("%s,%d: random IV \n", __FILE__, __LINE__);
525                                         cesa_cmd->ivFromUser = 0;
526
527                                         /*
528                                          * do we have to copy the IV back to the buffer ?
529                                          */
530                                         /* in this mode the HAL will always copy the IV */
531                                         /* given by the session to the ivOffset         */
532                                         if ((crd->crd_flags & CRD_F_IV_PRESENT) == 0) {
533                                                 cesa_cmd->ivOffset = crd->crd_inject;
534                                         } 
535                                         else {
536                                                 /* if IV isn't copy, then how will the user know which IV did we use??? */
537                                                 printk("%s,%d: EINVAL\n", __FILE__, __LINE__);
538                                                 goto p_error; 
539                                         }
540                                 }
541                         }
542                         else {                                  /* decrypt */
543                                 dprintk(" decrypt \n");
544                                 decrypt++;
545                                 cesa_cmd->sessionId = cesa_ocf_cur_ses->sid_decrypt;
546
547                                 /* handle IV */
548                                 if (crd->crd_flags & CRD_F_IV_EXPLICIT) {
549                                         dprintk("%s,%d: IV from USER \n", __FILE__, __LINE__);
550                                         /* append the IV buf to the mbuf */
551                                         cesa_cmd->ivFromUser = 1;       
552                                         p_mbuf_info->numFrags++;
553                                         p_mbuf_info->mbufSize += cesa_ocf_cur_ses->ivlen; 
554                                         p_mbuf_info->pFrags = p_buf_info;
555
556                                         p_buf_info->bufVirtPtr = crd->crd_iv;
557                                         p_buf_info->bufSize = cesa_ocf_cur_ses->ivlen; 
558                                         p_buf_info--;
559
560                                         /* offsets */
561                                         cesa_cmd->ivOffset = 0;
562                                         cesa_cmd->cryptoOffset += cesa_ocf_cur_ses->ivlen;
563                                         if(auth) {
564                                                 cesa_cmd->macOffset += cesa_ocf_cur_ses->ivlen;
565                                                 cesa_cmd->digestOffset += cesa_ocf_cur_ses->ivlen; 
566                                         }
567                                 }
568                                 else {
569                                         dprintk("%s,%d: IV inside the buffer \n", __FILE__, __LINE__);
570                                         cesa_cmd->ivFromUser = 0;
571                                         cesa_cmd->ivOffset = crd->crd_inject;
572                                 }
573                         }
574
575                 }
576                 /* Authentication */
577                 else if(crd->crd_alg == cesa_ocf_cur_ses->auth_alg) {
578                         dprintk("%s,%d:  Authentication \n", __FILE__, __LINE__);
579                         auth++;
580                         cesa_cmd->macOffset = crd->crd_skip;
581                         cesa_cmd->macLength = crd->crd_len;
582
583                         /* digest + mac */
584                         cesa_cmd->digestOffset = crd->crd_inject;
585                 } 
586                 else {
587                         printk("%s,%d: Alg isn't supported by this session.\n", __FILE__, __LINE__);
588                         goto p_error;
589                 }
590         }
591
592         dprintk("\n");
593         dprintk("%s,%d: Sending Action: \n", __FILE__, __LINE__);
594         dprintk("%s,%d: IV from user: %d. IV offset %x \n",  __FILE__, __LINE__, cesa_cmd->ivFromUser, cesa_cmd->ivOffset);
595         dprintk("%s,%d: crypt offset %x len %x \n", __FILE__, __LINE__, cesa_cmd->cryptoOffset, cesa_cmd->cryptoLength);
596         dprintk("%s,%d: Auth offset %x len %x \n", __FILE__, __LINE__, cesa_cmd->macOffset, cesa_cmd->macLength);
597         dprintk("%s,%d: set digest in offset %x . \n", __FILE__, __LINE__, cesa_cmd->digestOffset);
598         if(debug) {
599                 mvCesaDebugMbuf("SRC BUFFER", cesa_cmd->pSrc, 0, cesa_cmd->pSrc->mbufSize);
600         }
601
602
603         /* send action to HAL */
604         spin_lock_irqsave(&cesa_lock, flags);
605         status = mvCesaAction(cesa_cmd);
606         spin_unlock_irqrestore(&cesa_lock, flags);
607
608         /* action not allowed */
609         if(status == MV_NOT_ALLOWED) {
610 #ifdef CESA_OCF_SPLIT
611                 /* if both encrypt and auth try to split */
612                 if(auth && (encrypt || decrypt)) {
613                         MV_CESA_COMMAND *cesa_cmd_wa;
614
615                         /* malloc a new cesa process and init it */     
616                         cesa_ocf_cmd_wa = kmalloc(sizeof(struct cesa_ocf_process), GFP_ATOMIC);
617         
618                         if (cesa_ocf_cmd_wa == NULL) {
619                                 printk("%s,%d: ENOBUFS \n", __FILE__, __LINE__);
620                                 goto p_error;
621                         }
622                         memcpy(cesa_ocf_cmd_wa, cesa_ocf_cmd, sizeof(struct cesa_ocf_process));
623                         cesa_cmd_wa = &cesa_ocf_cmd_wa->cesa_cmd;
624                         cesa_cmd_wa->pReqPrv = (void *)cesa_ocf_cmd_wa;
625                         cesa_ocf_cmd_wa->need_cb = 0;
626
627                         /* break requests to two operation, first operation completion won't call callback */
628                         if((decrypt) && (cesa_ocf_cur_ses->auth_tn_decrypt)) {
629                                 cesa_cmd_wa->sessionId = cesa_ocf_cur_ses->frag_wa_auth;
630                                 cesa_cmd->sessionId = cesa_ocf_cur_ses->frag_wa_decrypt;
631                         }
632                         else if((decrypt) && !(cesa_ocf_cur_ses->auth_tn_decrypt)) {
633                                 cesa_cmd_wa->sessionId = cesa_ocf_cur_ses->frag_wa_decrypt;
634                                 cesa_cmd->sessionId = cesa_ocf_cur_ses->frag_wa_auth;
635                         }
636                         else if((encrypt) && (cesa_ocf_cur_ses->encrypt_tn_auth)) {
637                                 cesa_cmd_wa->sessionId = cesa_ocf_cur_ses->frag_wa_encrypt;
638                                 cesa_cmd->sessionId = cesa_ocf_cur_ses->frag_wa_auth;
639                         }
640                         else if((encrypt) && !(cesa_ocf_cur_ses->encrypt_tn_auth)){
641                                 cesa_cmd_wa->sessionId = cesa_ocf_cur_ses->frag_wa_auth;
642                                 cesa_cmd->sessionId = cesa_ocf_cur_ses->frag_wa_encrypt;
643                         }
644                         else {
645                                 printk("%s,%d: Unsupporterd fragment wa mode \n", __FILE__, __LINE__);
646                                 goto p_error;
647                         }
648
649                         /* send the 2 actions to the HAL */
650                         spin_lock_irqsave(&cesa_lock, flags);
651                         status = mvCesaAction(cesa_cmd_wa);
652                         spin_unlock_irqrestore(&cesa_lock, flags);
653
654                         if((status != MV_NO_MORE) && (status != MV_OK)) {
655                                 printk("%s,%d: cesa action failed, status = 0x%x\n", __FILE__, __LINE__, status);
656                                 goto p_error;
657                         }
658                         spin_lock_irqsave(&cesa_lock, flags);
659                         status = mvCesaAction(cesa_cmd);
660                         spin_unlock_irqrestore(&cesa_lock, flags);
661
662                 }
663                 /* action not allowed and can't split */
664                 else 
665 #endif
666                 {
667                         goto p_error;
668                 }
669         }
670
671         /* Hal Q is full, send again. This should never happen */
672         if(status == MV_NO_RESOURCE) {
673                 printk("%s,%d: cesa no more resources \n", __FILE__, __LINE__);
674                 if(cesa_ocf_cmd)
675                         kfree(cesa_ocf_cmd);
676                 if(cesa_ocf_cmd_wa)
677                         kfree(cesa_ocf_cmd_wa);
678                 return ERESTART;
679         } 
680         else if((status != MV_NO_MORE) && (status != MV_OK)) {
681                 printk("%s,%d: cesa action failed, status = 0x%x\n", __FILE__, __LINE__, status);
682                 goto p_error;
683         }
684
685
686 #ifdef CESA_OCF_POLLING
687         cesa_interrupt_polling();
688 #endif
689         cesaTestTraceAdd(5);
690
691         return 0;
692 p_error:
693         crp->crp_etype = EINVAL;
694         if(cesa_ocf_cmd)
695                 kfree(cesa_ocf_cmd);
696         if(cesa_ocf_cmd_wa)
697                 kfree(cesa_ocf_cmd_wa);
698         return EINVAL;
699 }
700
701 /*
702  * cesa callback. 
703  */
704 static void
705 cesa_callback(unsigned long dummy)
706 {
707         struct cesa_ocf_process *cesa_ocf_cmd = NULL;
708         struct cryptop          *crp = NULL;
709         MV_CESA_RESULT          result[MV_CESA_MAX_CHAN];
710         int                     res_idx = 0,i;
711         MV_STATUS               status;
712
713         dprintk("%s()\n", __FUNCTION__);
714
715 #ifdef CESA_OCF_TASKLET
716         disable_irq(cesa_device.irq);
717 #endif
718     while(MV_TRUE) {
719         
720                  /* Get Ready requests */
721                 spin_lock(&cesa_lock);
722                 status = mvCesaReadyGet(&result[res_idx]);
723                 spin_unlock(&cesa_lock);
724
725                 cesaTestTraceAdd(2);    
726
727                     if(status != MV_OK) {
728 #ifdef CESA_OCF_POLLING
729                         if(status == MV_BUSY) { /* Fragment */
730                                 cesa_interrupt_polling();
731                                 return;
732                         }
733 #endif
734                     break;
735             }
736                 res_idx++;
737                     break;
738             }
739         
740         for(i = 0; i < res_idx; i++) {
741
742                 if(!result[i].pReqPrv) {
743                         printk("%s,%d: warning private is NULL\n", __FILE__, __LINE__);
744                         break;
745                 }
746
747                 cesa_ocf_cmd = result[i].pReqPrv;
748                 crp = cesa_ocf_cmd->crp; 
749
750                 // ignore HMAC error.
751                 //if(result->retCode)
752                 //      crp->crp_etype = EIO;   
753         
754 #if  defined(CESA_OCF_POLLING) 
755                 if(!cesa_ocf_cmd->need_cb){
756                         cesa_interrupt_polling();
757                 }       
758 #endif
759                 if(cesa_ocf_cmd->need_cb) {
760                         if(debug) {
761                                 mvCesaDebugMbuf("DST BUFFER", cesa_ocf_cmd->cesa_cmd.pDst, 0, cesa_ocf_cmd->cesa_cmd.pDst->mbufSize);
762                         }
763                         crypto_done(crp);
764                 }
765                 kfree(cesa_ocf_cmd);
766         }
767 #ifdef CESA_OCF_TASKLET
768         enable_irq(cesa_device.irq);
769 #endif
770
771         cesaTestTraceAdd(3);
772
773         return;
774 }
775
776 #ifdef CESA_OCF_POLLING
777 static void
778 cesa_interrupt_polling(void)
779 {
780         u32                     cause;
781
782         dprintk("%s()\n", __FUNCTION__);
783
784         /* Read cause register */
785         do {
786                 cause = MV_REG_READ(MV_CESA_ISR_CAUSE_REG);
787                 cause &= MV_CESA_CAUSE_ACC_DMA_ALL_MASK;
788
789         } while (cause == 0);
790                 
791         /* clear interrupts */
792         MV_REG_WRITE(MV_CESA_ISR_CAUSE_REG, 0);
793
794         cesa_callback(0);
795
796         return;
797 }
798
799 #endif
800
801 /*
802  * cesa Interrupt polling routine.
803  */
804 static irqreturn_t
805 cesa_interrupt_handler(int irq, void *arg)
806 {
807         u32                     cause;
808
809         dprintk("%s()\n", __FUNCTION__);
810
811         cesaTestTraceAdd(0);
812
813         /* Read cause register */
814         cause = MV_REG_READ(MV_CESA_ISR_CAUSE_REG);
815
816         if( (cause & MV_CESA_CAUSE_ACC_DMA_ALL_MASK) == 0)
817         {
818         /* Empty interrupt */
819                 dprintk("%s,%d: cesaTestReadyIsr: cause=0x%x\n", __FILE__, __LINE__, cause);
820                 return IRQ_HANDLED;
821         }
822         
823         /* clear interrupts */
824         MV_REG_WRITE(MV_CESA_ISR_CAUSE_REG, 0);
825
826         cesaTestTraceAdd(1);
827 #ifdef CESA_OCF_TASKLET 
828         tasklet_hi_schedule(&cesa_ocf_tasklet);
829 #else
830         cesa_callback(0);
831 #endif
832         return IRQ_HANDLED;
833 }
834
835 /*
836  * Open a session.
837  */
838 static int 
839 /*cesa_ocf_newsession(void *arg, u_int32_t *sid, struct cryptoini *cri)*/
840 cesa_ocf_newsession(device_t dev, u_int32_t *sid, struct cryptoini *cri)
841 {
842         u32 status = 0, i;
843         u32 count = 0, auth = 0, encrypt =0;
844         struct cesa_ocf_data *cesa_ocf_cur_ses;
845         MV_CESA_OPEN_SESSION cesa_session;
846         MV_CESA_OPEN_SESSION *cesa_ses = &cesa_session;
847
848
849         dprintk("%s()\n", __FUNCTION__);
850         if (sid == NULL || cri == NULL) {
851                 printk("%s,%d: EINVAL\n", __FILE__, __LINE__);
852                 return EINVAL;
853         }
854
855         /* leave first empty like in other implementations */
856         for (i = 1; i < CESA_OCF_MAX_SES; i++) {
857                 if (cesa_ocf_sessions[i] == NULL)
858                         break;
859         }
860
861         if(i >= CESA_OCF_MAX_SES) {
862                 printk("%s,%d: no more sessions \n", __FILE__, __LINE__);
863                 return EINVAL;
864         }
865
866         cesa_ocf_sessions[i] = (struct cesa_ocf_data *) kmalloc(sizeof(struct cesa_ocf_data), GFP_ATOMIC);
867         if (cesa_ocf_sessions[i] == NULL) {
868                 cesa_ocf_freesession(NULL, i);
869                 printk("%s,%d: ENOBUFS \n", __FILE__, __LINE__);
870                 return ENOBUFS;
871         }
872         dprintk("%s,%d: new session %d \n", __FILE__, __LINE__, i);
873         
874         *sid = i;
875         cesa_ocf_cur_ses = cesa_ocf_sessions[i];
876         memset(cesa_ocf_cur_ses, 0, sizeof(struct cesa_ocf_data));
877         cesa_ocf_cur_ses->sid_encrypt = -1;
878         cesa_ocf_cur_ses->sid_decrypt = -1;
879         cesa_ocf_cur_ses->frag_wa_encrypt = -1;
880         cesa_ocf_cur_ses->frag_wa_decrypt = -1;
881         cesa_ocf_cur_ses->frag_wa_auth = -1;
882
883         /* init the session */  
884         memset(cesa_ses, 0, sizeof(MV_CESA_OPEN_SESSION));
885         count = 1;
886         while (cri) {   
887                 if(count > 2) {
888                         printk("%s,%d: don't support more then 2 operations\n", __FILE__, __LINE__);
889                         goto error;
890                 }
891                 switch (cri->cri_alg) {
892                 case CRYPTO_AES_CBC:
893                         dprintk("%s,%d: (%d) AES CBC \n", __FILE__, __LINE__, count);
894                         cesa_ocf_cur_ses->cipher_alg = cri->cri_alg;
895                         cesa_ocf_cur_ses->ivlen = MV_CESA_AES_BLOCK_SIZE;
896                         cesa_ses->cryptoAlgorithm = MV_CESA_CRYPTO_AES;
897                         cesa_ses->cryptoMode = MV_CESA_CRYPTO_CBC;
898                         if(cri->cri_klen/8 > MV_CESA_MAX_CRYPTO_KEY_LENGTH) {
899                                 printk("%s,%d: CRYPTO key too long.\n", __FILE__, __LINE__);
900                                 goto error;
901                         }
902                         memcpy(cesa_ses->cryptoKey, cri->cri_key, cri->cri_klen/8);
903                         dprintk("%s,%d: key length %d \n", __FILE__, __LINE__, cri->cri_klen/8);
904                         cesa_ses->cryptoKeyLength = cri->cri_klen/8;
905                         encrypt += count;
906                         break;
907                 case CRYPTO_3DES_CBC:
908                         dprintk("%s,%d: (%d) 3DES CBC \n", __FILE__, __LINE__, count);
909                         cesa_ocf_cur_ses->cipher_alg = cri->cri_alg;
910                         cesa_ocf_cur_ses->ivlen = MV_CESA_3DES_BLOCK_SIZE;
911                         cesa_ses->cryptoAlgorithm = MV_CESA_CRYPTO_3DES;
912                         cesa_ses->cryptoMode = MV_CESA_CRYPTO_CBC;
913                         if(cri->cri_klen/8 > MV_CESA_MAX_CRYPTO_KEY_LENGTH) {
914                                 printk("%s,%d: CRYPTO key too long.\n", __FILE__, __LINE__);
915                                 goto error;
916                         }
917                         memcpy(cesa_ses->cryptoKey, cri->cri_key, cri->cri_klen/8);
918                         cesa_ses->cryptoKeyLength = cri->cri_klen/8;
919                         encrypt += count;
920                         break;
921                 case CRYPTO_DES_CBC:
922                         dprintk("%s,%d: (%d) DES CBC \n", __FILE__, __LINE__, count);
923                         cesa_ocf_cur_ses->cipher_alg = cri->cri_alg;
924                         cesa_ocf_cur_ses->ivlen = MV_CESA_DES_BLOCK_SIZE;
925                         cesa_ses->cryptoAlgorithm = MV_CESA_CRYPTO_DES;
926                         cesa_ses->cryptoMode = MV_CESA_CRYPTO_CBC;
927                         if(cri->cri_klen/8 > MV_CESA_MAX_CRYPTO_KEY_LENGTH) {
928                                 printk("%s,%d: CRYPTO key too long.\n", __FILE__, __LINE__);
929                                 goto error;
930                         }
931                         memcpy(cesa_ses->cryptoKey, cri->cri_key, cri->cri_klen/8);
932                         cesa_ses->cryptoKeyLength = cri->cri_klen/8;
933                         encrypt += count;
934                         break;
935                 case CRYPTO_MD5:
936                 case CRYPTO_MD5_HMAC:
937                         dprintk("%s,%d: (%d) %sMD5 CBC \n", __FILE__, __LINE__, count, (cri->cri_alg != CRYPTO_MD5)? "H-":" ");
938                         cesa_ocf_cur_ses->auth_alg = cri->cri_alg;
939                         cesa_ocf_cur_ses->digestlen = (cri->cri_alg == CRYPTO_MD5)? MV_CESA_MD5_DIGEST_SIZE : 12;
940                         cesa_ses->macMode = (cri->cri_alg == CRYPTO_MD5)? MV_CESA_MAC_MD5 : MV_CESA_MAC_HMAC_MD5;
941                         if(cri->cri_klen/8 > MV_CESA_MAX_CRYPTO_KEY_LENGTH) {
942                                 printk("%s,%d: MAC key too long. \n", __FILE__, __LINE__);
943                                 goto error;
944                         }
945                         cesa_ses->macKeyLength = cri->cri_klen/8;
946                         memcpy(cesa_ses->macKey, cri->cri_key, cri->cri_klen/8);
947                         cesa_ses->digestSize = cesa_ocf_cur_ses->digestlen; 
948                         auth += count;
949                         break;
950                 case CRYPTO_SHA1:
951                 case CRYPTO_SHA1_HMAC:
952                         dprintk("%s,%d: (%d) %sSHA1 CBC \n", __FILE__, __LINE__, count, (cri->cri_alg != CRYPTO_SHA1)? "H-":" ");
953                         cesa_ocf_cur_ses->auth_alg = cri->cri_alg;
954                         cesa_ocf_cur_ses->digestlen = (cri->cri_alg == CRYPTO_SHA1)? MV_CESA_SHA1_DIGEST_SIZE : 12; 
955                         cesa_ses->macMode = (cri->cri_alg == CRYPTO_SHA1)? MV_CESA_MAC_SHA1 : MV_CESA_MAC_HMAC_SHA1;
956                         if(cri->cri_klen/8 > MV_CESA_MAX_CRYPTO_KEY_LENGTH) {
957                                 printk("%s,%d: MAC key too long. \n", __FILE__, __LINE__);
958                                 goto error;
959                         }
960                         cesa_ses->macKeyLength = cri->cri_klen/8;
961                         memcpy(cesa_ses->macKey, cri->cri_key, cri->cri_klen/8);
962                         cesa_ses->digestSize = cesa_ocf_cur_ses->digestlen;
963                         auth += count;
964                         break;
965                 default:
966                         printk("%s,%d: unknown algo 0x%x\n", __FILE__, __LINE__, cri->cri_alg);
967                         goto error;
968                 }
969                 cri = cri->cri_next;
970                 count++;
971         }
972
973         if((encrypt > 2) || (auth > 2)) {
974                 printk("%s,%d: session mode is not supported.\n", __FILE__, __LINE__);
975                 goto error;
976         }
977         /* create new sessions in HAL */
978         if(encrypt) {
979                 cesa_ses->operation = MV_CESA_CRYPTO_ONLY;
980                 /* encrypt session */
981                 if(auth == 1) {
982                         cesa_ses->operation = MV_CESA_MAC_THEN_CRYPTO;
983                 }
984                 else if(auth == 2) {
985                         cesa_ses->operation = MV_CESA_CRYPTO_THEN_MAC;
986                         cesa_ocf_cur_ses->encrypt_tn_auth = 1;
987                 }
988                 else {
989                         cesa_ses->operation = MV_CESA_CRYPTO_ONLY;
990                 }
991                 cesa_ses->direction = MV_CESA_DIR_ENCODE;
992                 status = mvCesaSessionOpen(cesa_ses, &cesa_ocf_cur_ses->sid_encrypt);
993                 if(status != MV_OK) {
994                         printk("%s,%d: Can't open new session - status = 0x%x\n", __FILE__, __LINE__, status);
995                         goto error;
996                 }       
997                 /* decrypt session */
998                 if( cesa_ses->operation == MV_CESA_MAC_THEN_CRYPTO ) {
999                         cesa_ses->operation = MV_CESA_CRYPTO_THEN_MAC;
1000                 }
1001                 else if( cesa_ses->operation == MV_CESA_CRYPTO_THEN_MAC ) {
1002                         cesa_ses->operation = MV_CESA_MAC_THEN_CRYPTO;
1003                 }
1004                 cesa_ses->direction = MV_CESA_DIR_DECODE;
1005                 status = mvCesaSessionOpen(cesa_ses, &cesa_ocf_cur_ses->sid_decrypt);
1006                 if(status != MV_OK) {
1007                         printk("%s,%d: Can't open new session - status = 0x%x\n", __FILE__, __LINE__, status);
1008                         goto error;
1009                 }
1010
1011                 /* preapre one action sessions for case we will need to split an action */
1012 #ifdef CESA_OCF_SPLIT
1013                 if(( cesa_ses->operation == MV_CESA_MAC_THEN_CRYPTO ) || 
1014                         ( cesa_ses->operation == MV_CESA_CRYPTO_THEN_MAC )) {
1015                         /* open one session for encode and one for decode */
1016                         cesa_ses->operation = MV_CESA_CRYPTO_ONLY;
1017                         cesa_ses->direction = MV_CESA_DIR_ENCODE;
1018                         status = mvCesaSessionOpen(cesa_ses, &cesa_ocf_cur_ses->frag_wa_encrypt);
1019                         if(status != MV_OK) {
1020                                 printk("%s,%d: Can't open new session - status = 0x%x\n", __FILE__, __LINE__, status);
1021                                 goto error;
1022                         }
1023
1024                         cesa_ses->direction = MV_CESA_DIR_DECODE;
1025                         status = mvCesaSessionOpen(cesa_ses, &cesa_ocf_cur_ses->frag_wa_decrypt);
1026                         if(status != MV_OK) {
1027                                 printk("%s,%d: Can't open new session - status = 0x%x\n", __FILE__, __LINE__, status);
1028                                 goto error;
1029                         }
1030                         /* open one session for auth */ 
1031                         cesa_ses->operation = MV_CESA_MAC_ONLY;
1032                         cesa_ses->direction = MV_CESA_DIR_ENCODE;
1033                         status = mvCesaSessionOpen(cesa_ses, &cesa_ocf_cur_ses->frag_wa_auth);
1034                         if(status != MV_OK) {
1035                                 printk("%s,%d: Can't open new session - status = 0x%x\n", __FILE__, __LINE__, status);
1036                                 goto error;
1037                         }
1038                 }
1039 #endif
1040         }
1041         else { /* only auth */
1042                 cesa_ses->operation = MV_CESA_MAC_ONLY;
1043                 cesa_ses->direction = MV_CESA_DIR_ENCODE;
1044                 status = mvCesaSessionOpen(cesa_ses, &cesa_ocf_cur_ses->sid_encrypt);
1045                 if(status != MV_OK) {
1046                         printk("%s,%d: Can't open new session - status = 0x%x\n", __FILE__, __LINE__, status);
1047                         goto error;
1048                 }
1049         }
1050         
1051         return 0;
1052 error:
1053         cesa_ocf_freesession(NULL, *sid);
1054         return EINVAL;  
1055
1056 }
1057
1058
1059 /*
1060  * Free a session.
1061  */
1062 static int
1063 cesa_ocf_freesession(device_t dev, u_int64_t tid)
1064 {
1065         struct cesa_ocf_data *cesa_ocf_cur_ses;
1066         u_int32_t sid = CRYPTO_SESID2LID(tid);
1067         //unsigned long flags;
1068
1069         dprintk("%s() %d \n", __FUNCTION__, sid);
1070         if ( (sid >= CESA_OCF_MAX_SES) || (cesa_ocf_sessions[sid] == NULL) ) {
1071                 printk("%s,%d: EINVAL can't free session %d \n", __FILE__, __LINE__, sid);
1072                 return(EINVAL);
1073         }
1074
1075         /* Silently accept and return */
1076         if (sid == 0)
1077                 return(0);
1078
1079         /* release session from HAL */
1080         cesa_ocf_cur_ses = cesa_ocf_sessions[sid];
1081         if (cesa_ocf_cur_ses->sid_encrypt != -1) {
1082                 mvCesaSessionClose(cesa_ocf_cur_ses->sid_encrypt);
1083         }
1084         if (cesa_ocf_cur_ses->sid_decrypt != -1) {
1085                 mvCesaSessionClose(cesa_ocf_cur_ses->sid_decrypt);
1086         }
1087         if (cesa_ocf_cur_ses->frag_wa_encrypt != -1) {
1088                 mvCesaSessionClose(cesa_ocf_cur_ses->frag_wa_encrypt);
1089         }
1090         if (cesa_ocf_cur_ses->frag_wa_decrypt != -1) {
1091                 mvCesaSessionClose(cesa_ocf_cur_ses->frag_wa_decrypt);
1092         }
1093         if (cesa_ocf_cur_ses->frag_wa_auth != -1) {
1094                 mvCesaSessionClose(cesa_ocf_cur_ses->frag_wa_auth);
1095         }
1096
1097         kfree(cesa_ocf_cur_ses);
1098         cesa_ocf_sessions[sid] = NULL;
1099
1100         return 0;
1101 }
1102
1103
1104 /* TDMA Window setup */
1105
1106 static void __init
1107 setup_tdma_mbus_windows(struct cesa_dev *dev)
1108 {
1109     int i;
1110     
1111     for (i = 0; i < 4; i++) {
1112         writel(0, dev->reg + WINDOW_BASE(i));
1113         writel(0, dev->reg + WINDOW_CTRL(i));
1114     }
1115     
1116     for (i = 0; i < dev->plat_data->dram->num_cs; i++) {
1117         struct mbus_dram_window *cs = dev->plat_data->dram->cs + i;
1118         writel(
1119             ((cs->size - 1) & 0xffff0000) |
1120             (cs->mbus_attr << 8) |
1121             (dev->plat_data->dram->mbus_dram_target_id << 4) | 1,
1122             dev->reg + WINDOW_CTRL(i)
1123         );
1124         writel(cs->base, dev->reg + WINDOW_BASE(i));
1125     }
1126 }
1127                                         
1128 /*
1129  * our driver startup and shutdown routines
1130  */
1131 static int
1132 mv_cesa_ocf_init(struct platform_device *pdev)
1133 {
1134 #if defined(CONFIG_MV78200) || defined(CONFIG_MV632X)
1135         if (MV_FALSE == mvSocUnitIsMappedToThisCpu(CESA))
1136         {
1137                 dprintk("CESA is not mapped to this CPU\n");
1138                 return -ENODEV;
1139         }               
1140 #endif
1141
1142         dprintk("%s\n", __FUNCTION__);
1143         memset(&mv_cesa_dev, 0, sizeof(mv_cesa_dev));
1144         softc_device_init(&mv_cesa_dev, "MV CESA", 0, mv_cesa_methods);
1145         cesa_ocf_id = crypto_get_driverid(softc_get_device(&mv_cesa_dev),CRYPTOCAP_F_HARDWARE);
1146
1147         if (cesa_ocf_id < 0)
1148                 panic("MV CESA crypto device cannot initialize!");
1149
1150         dprintk("%s,%d: cesa ocf device id is %d \n", __FILE__, __LINE__, cesa_ocf_id);
1151
1152         /* CESA unit is auto power on off */
1153 #if 0
1154         if (MV_FALSE == mvCtrlPwrClckGet(CESA_UNIT_ID,0))
1155         {
1156                 printk("\nWarning CESA %d is Powered Off\n",0);
1157                 return EINVAL;
1158         }
1159 #endif
1160
1161         memset(&cesa_device, 0, sizeof(struct cesa_dev));
1162         /* Get the IRQ, and crypto memory regions */
1163         {
1164                 struct resource *res;
1165                 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "sram");
1166                 
1167                 if (!res)
1168                         return -ENXIO;
1169                 
1170                 cesa_device.sram = ioremap(res->start, res->end - res->start + 1);
1171                 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs");
1172                 
1173                 if (!res) {
1174                         iounmap(cesa_device.sram);
1175                         return -ENXIO;
1176                 }
1177                 cesa_device.reg = ioremap(res->start, res->end - res->start + 1);
1178                 cesa_device.irq = platform_get_irq(pdev, 0);
1179                 cesa_device.plat_data = pdev->dev.platform_data;
1180                 setup_tdma_mbus_windows(&cesa_device);  
1181                 
1182         }
1183         
1184         
1185         if( MV_OK != mvCesaInit(CESA_OCF_MAX_SES*5, CESA_Q_SIZE, cesa_device.reg,
1186                                 NULL) ) {
1187                 printk("%s,%d: mvCesaInit Failed. \n", __FILE__, __LINE__);
1188                 return EINVAL;
1189         }
1190
1191         /* clear and unmask Int */
1192         MV_REG_WRITE( MV_CESA_ISR_CAUSE_REG, 0);
1193 #ifndef CESA_OCF_POLLING
1194     MV_REG_WRITE( MV_CESA_ISR_MASK_REG, MV_CESA_CAUSE_ACC_DMA_MASK);
1195 #endif
1196 #ifdef CESA_OCF_TASKLET
1197         tasklet_init(&cesa_ocf_tasklet, cesa_callback, (unsigned int) 0);
1198 #endif
1199         /* register interrupt */
1200         if( request_irq( cesa_device.irq, cesa_interrupt_handler,
1201                              (IRQF_DISABLED) , "cesa", &cesa_ocf_id) < 0) {
1202                 printk("%s,%d: cannot assign irq %x\n", __FILE__, __LINE__, cesa_device.reg);
1203                 return EINVAL;
1204         }
1205
1206
1207         memset(cesa_ocf_sessions, 0, sizeof(struct cesa_ocf_data *) * CESA_OCF_MAX_SES);
1208
1209 #define REGISTER(alg) \
1210         crypto_register(cesa_ocf_id, alg, 0,0)
1211         REGISTER(CRYPTO_AES_CBC);
1212         REGISTER(CRYPTO_DES_CBC);
1213         REGISTER(CRYPTO_3DES_CBC);
1214         REGISTER(CRYPTO_MD5);
1215         REGISTER(CRYPTO_MD5_HMAC);
1216         REGISTER(CRYPTO_SHA1);
1217         REGISTER(CRYPTO_SHA1_HMAC);
1218 #undef REGISTER
1219
1220         return 0;
1221 }
1222
1223 static void
1224 mv_cesa_ocf_exit(struct platform_device *pdev)
1225 {
1226         dprintk("%s()\n", __FUNCTION__);
1227
1228         crypto_unregister_all(cesa_ocf_id);
1229         cesa_ocf_id = -1;
1230         iounmap(cesa_device.reg);
1231         iounmap(cesa_device.sram);
1232         free_irq(cesa_device.irq, NULL);
1233         
1234         /* mask and clear Int */
1235         MV_REG_WRITE( MV_CESA_ISR_MASK_REG, 0);
1236         MV_REG_WRITE( MV_CESA_ISR_CAUSE_REG, 0);
1237         
1238
1239         if( MV_OK != mvCesaFinish() ) {
1240                 printk("%s,%d: mvCesaFinish Failed. \n", __FILE__, __LINE__);
1241                 return;
1242         }
1243 }
1244
1245
1246 void cesa_ocf_debug(void)
1247 {
1248
1249 #ifdef CESA_OCF_TRACE_DEBUG
1250     {
1251         int i, j;
1252         j = cesaTestTraceIdx;
1253         mvOsPrintf("No  Type   rCause   iCause   Proc   Isr   Res     Time     pReady    pProc    pEmpty\n");
1254         for(i=0; i<MV_CESA_TEST_TRACE_SIZE; i++)
1255         {
1256             mvOsPrintf("%02d.  %d   0x%04x   0x%04x   0x%02x   0x%02x   %02d   0x%06x  %p  %p  %p\n",
1257                 j, cesaTestTrace[j].type, cesaTestTrace[j].realCause,
1258                 cesaTestTrace[j].idmaCause, 
1259                 cesaTestTrace[j].resources, cesaTestTrace[j].timeStamp,
1260                 cesaTestTrace[j].pReqReady, cesaTestTrace[j].pReqProcess, cesaTestTrace[j].pReqEmpty);
1261             j++;
1262             if(j == MV_CESA_TEST_TRACE_SIZE)
1263                 j = 0;
1264         }
1265     }
1266 #endif
1267
1268 }
1269
1270 static struct platform_driver marvell_cesa = {
1271         .probe          = mv_cesa_ocf_init,
1272         .remove         = mv_cesa_ocf_exit,
1273         .driver         = {
1274                 .owner  = THIS_MODULE,
1275                 .name   = "mv_crypto",
1276         },
1277 };
1278
1279 MODULE_ALIAS("platform:mv_crypto");
1280
1281 static int __init mv_cesa_init(void)
1282 {
1283         return platform_driver_register(&marvell_cesa);
1284 }
1285
1286 module_init(mv_cesa_init);
1287
1288 static void __exit mv_cesa_exit(void)
1289 {
1290         platform_driver_unregister(&marvell_cesa);
1291 }
1292
1293 module_exit(mv_cesa_exit);
1294
1295 MODULE_LICENSE("GPL");
1296 MODULE_AUTHOR("Ronen Shitrit");
1297 MODULE_DESCRIPTION("OCF module for Orion CESA crypto");