MOXA linux-2.6.x / linux-2.6.9-uc0 from sdlinux-moxaart.tgz
[linux-2.6.9-moxart.git] / drivers / char / cipher / mxhw_crypto_engine.c
blob36d1c91c17af665a700705b25c5228309d0b8311
1 #include <linux/config.h>
2 #include <linux/kernel.h>
3 #include <linux/sched.h>
4 #include <linux/types.h>
5 #include <linux/slab.h>
6 #include <linux/delay.h>
7 #include <asm/system.h>
8 #include <asm/io.h> // readl, writel
9 #include <asm/irq.h>
11 #include <asm/arch/irq.h>
12 #include <asm/arch/cpe/cpe.h> //All register definition
13 #include <asm/arch/cpe_int.h> //Interrupt definition
14 #include <asm/arch/cpe/a320c.h>
15 #include <asm-generic/errno-base.h>
17 #include "mxhw_crypto_engine.h"
19 /* memory and register information */
20 #define CPE_WMAC_BASE 0x90F00000 /* physical base address */
21 #define REGS_SIZE 0x90 /* physical area */
22 static void *base=NULL; /* base address of the io memory assigned to the engine */
23 #define REGWRL(off,v) writel(v,base+off)
24 #define REGRDL(off) readl(base+off)
26 #define PERFORM_WAIT_TIME 50
27 #define MAX_WAIT_TIMES 200
29 #ifdef IRQUSED
30 #define IRQ_WMAC 29 /* trq number */
31 wait_queue_head_t dmawq; /* a waiting queue that the engine wakes up the dispatcher */
32 static u32 IRQ_INT_FLAG=0;
33 #endif
35 #ifdef DEBUG
36 static void
37 read_registers(u32 a, u32 b)
39 if (a==0 && b==0) b = REGS_SIZE;
41 mdelay(200);
42 printk("\n-------------- addresses --------------%d\n", 0);
43 for (; a < b; a+=4)
44 printk("0x%02x = 0x%08x\n", a, REGRDL(a));
45 printk("\n-------------- addresses --------------%d\n", 9);
46 mdelay(200);
48 #else
49 #define read_registers(a,b)
50 #endif
52 int
53 mxhw_crypto_engine_dma_malloc(IOMBUF *mbuf, u32 size)
55 IOMBUF_OFFS(mbuf) = 0;
56 IOMBUF_SIZE(mbuf) = size; /* memory space for data */
57 /*===prince delete
58 IOMBUF_VIRT(mbuf) = consistent_alloc( GFP_DMA|GFP_KERNEL, size,
59 &(IOMBUF_PHYS(mbuf)));
60 ================*/
61 //prince add begin
62 IOMBUF_VIRT(mbuf) = dma_alloc_coherent(NULL, size,&(IOMBUF_PHYS(mbuf)), GFP_DMA|GFP_KERNEL);
64 //prince add end
65 if (IOMBUF_VIRT(mbuf)==NULL)
66 return 1;
67 return 0;
70 void
71 mxhw_crypto_engine_dma_mfree(IOMBUF *mbuf)
73 if (mbuf && IOMBUF_VIRT(mbuf))
74 /*====prince delete
75 consistent_free((u32 *)IOMBUF_VIRT(mbuf), IOMBUF_SIZE(mbuf)+IOMBUF_OFFS(mbuf), IOMBUF_PHYS(mbuf));
76 =================*/
77 //prince add begin
78 dma_free_coherent(NULL, IOMBUF_SIZE(mbuf)+IOMBUF_OFFS(mbuf),(u32 *)IOMBUF_VIRT(mbuf),IOMBUF_PHYS(mbuf));
79 //prince add end
82 typedef struct _CTXPARAM
84 u32 algo;
85 u32 ctrl;
86 u32 blen;
87 u32 klen;
88 } CTXPARAM;
90 static CTXPARAM CtxParams[] =
92 {MXCIPHER_ALGO_DES, _BIT_RW_MXCIPHER_ALGO_DES, 8, 8},
93 {MXCIPHER_ALGO_3DES, _BIT_RW_MXCIPHER_ALGO_3DES, 8, 24},
94 {MXCIPHER_ALGO_AES128, _BIT_RW_MXCIPHER_ALGO_AES128, 16, 16},
95 {MXCIPHER_ALGO_AES192, _BIT_RW_MXCIPHER_ALGO_AES192, 16, 24},
96 {MXCIPHER_ALGO_AES256, _BIT_RW_MXCIPHER_ALGO_AES256, 16, 32}
99 static u32 CtxParams_Size=(sizeof(CtxParams)/sizeof(CtxParams[0]));
101 #if 1
102 #define SWAP32(v) ((v>>24)|((v&0x00ff0000)>>8)|((v&0x0000ff00)<<8)|(v<<24))
103 #else
104 #define SWAP32(v) v
105 #endif
107 static void
108 swap(u8 *data, u32 len)
110 u32 i, v;
112 for (i=0; i < len; i+=4, data += 4)
114 v = *(u32*) data;
115 *(u32*)data = SWAP32(v);
119 #define mswap32(data,l) \
121 u32 i, v, len=l>>2; \
122 u32 *d = (u32*) data; \
123 for (i=0; i < len; i++, d++) \
125 v = *d; \
126 *d = SWAP32(v); \
131 mxhw_crypto_engine_register(CIPHER *info, u32 *ctrl)
133 u32 i;
135 if (info->mode==MXCIPHER_MODE_ECB) *ctrl = _BIT_RW_MXCIPHER_MODE_ECB;
136 else if (info->mode==MXCIPHER_MODE_CBC) *ctrl = _BIT_RW_MXCIPHER_MODE_CBC;
137 else if (info->mode==MXCIPHER_MODE_CTR) *ctrl = _BIT_RW_MXCIPHER_MODE_CTR;
138 else if (info->mode==MXCIPHER_MODE_OFB) *ctrl = _BIT_RW_MXCIPHER_MODE_OFB;
139 else if (info->mode==MXCIPHER_MODE_CFB)
141 if (info->bits!=8)
142 return -1;
143 *ctrl = _BIT_RW_MXCIPHER_MODE_CFB;
145 else
146 return -1;
148 *ctrl |= (info->type==0)? _BIT_RW_MXCIPHER_TYPE_DEC:_BIT_RW_MXCIPHER_TYPE_ENC;
150 info->blen = info->klen = 0;
151 for (i=0; i < CtxParams_Size;i++)
153 if (info->algo==CtxParams[i].algo)
155 info->blen = CtxParams[i].blen;
156 info->klen = CtxParams[i].klen;
157 *ctrl |= CtxParams[i].ctrl;
158 swap(info->keys, info->klen);
159 return 0;
162 return -2;
165 void
166 mxhw_crypto_engine_unregister(u32 ctrl)
168 (void) ctrl;
171 #define IRQ_LEVEL LEVEL
172 #define IRQ_ACTIVE L_ACTIVE
173 #define INTRPT_ENBL_BIT 1
174 #define INTRPT_DSBL_BIT 0
176 /* Note:
177 1. IOMBUF_DLEN(imbuf) covers the IV if there is
178 2. remember to set IOMBUF_DLEN(ombuf) = IOMBUF_DLEN(imbuf)
181 mxhw_crypto_engine_perform(u32 ctrl, CIPHER *info, IOMBUF *imbuf, IOMBUF *ombuf, u32 *exited)
183 u_long offs;
184 u32 tmpv,dlen;
185 u8 *ivec;
186 int i,num=0;
188 if (info->mode!=MXCIPHER_MODE_ECB)
189 dlen = IOMBUF_DLEN(imbuf)-info->blen;
190 else
192 dlen = IOMBUF_DLEN(imbuf);
193 if (info->mode!=MXCIPHER_MODE_CFB && dlen%info->blen)
194 return 1;
197 DBG(KERN_INFO "mxhw_engine: engine_perform = %d %d 0x%x\n", 11, info->type, ctrl);
199 /* step 0: disable all interrupts: stop, err, done */
200 REGWRL(_REG_WO_INTRPT_CLEAR, 1);
202 /* step 1: set cipher control */
203 REGWRL(_REG_RW_MXCIPHER_CTRL, ctrl);
205 /* step 2: set IVs if there are, 4 bytes each */
206 if (info->mode!=MXCIPHER_MODE_ECB)
208 dlen = IOMBUF_DLEN(imbuf)-info->blen;
209 ivec = IOMBUF_DATA(imbuf)+dlen;
210 for (i=0,offs=_REG_RW_MXCIPHER_IVIN0; i < info->blen; i+=4, offs+=4)
212 tmpv = *(u32*)(ivec+i);
213 tmpv = SWAP32(tmpv);
214 REGWRL(offs,tmpv);
218 /* step 3: set keys, 4 bytes each, swap already */
219 for (i=0,offs=_REG_RW_MXCIPHER_KEY0; i < info->klen; i+=4, offs+=4)
220 REGWRL(offs,*(u32*)(info->keys+i));
222 /* step 4: set DMA controls */
223 REGWRL( _REG_RW_DMA_ADDR_SURC, IOMBUF_PHYS(imbuf));
224 REGWRL( _REG_RW_DMA_ADDR_DEST, IOMBUF_PHYS(ombuf));
225 REGWRL( _REG_RW_DMA_DATA_SIZE, dlen);
227 /* step 5: enable transfer done */
228 REGWRL(_REG_RW_INTRPT_ENBL, INTRPT_ENBL_BIT);
230 DBG(KERN_INFO "mxhw_engine: engine_perform = %d\n", 66);
232 /* step 6: enable DMA engine */
233 REGWRL(_REG_RW_DMA_ENGN_CTRL, _BIT_RW_DMA_ENGN_ENBL);
234 //read_registers(_REG_RW_DMA_ENGN_CTRL,0x70);
236 /* step 7: wait for data of the size is transferred. if it waits for
237 a stop at DMA, the data might not be completely transferred */
238 #ifdef IRQUSED
239 DBG(KERN_INFO "mxhw_engine: interrupt = %d %d\n", 77, dlen);
240 #if 0
241 wait_event_interruptible(&dmawq, (REGRDL(_REG_RO_INTRPT_POST)&_BIT_RO_INTRPT_DONE)!=0);
242 #else
243 while(IRQ_INT_FLAG==0 && num++ < MAX_WAIT_TIMES)
245 udelay(PERFORM_WAIT_TIME); // current->state = TASK_INTERRUPTIBLE; schedule_timeout(HZ);
246 if (IRQ_INT_FLAG!=0)
247 break;
249 #endif
250 IRQ_INT_FLAG=0;
252 #else
253 DBG(KERN_INFO "mxhw_engine: poll =%d %d\n", 77, dlen);
255 while(num++ < MAX_WAIT_TIMES)
257 udelay(PERFORM_WAIT_TIME);
258 if ((REGRDL(_REG_RO_INTRPT_POST)&_BIT_RO_INTRPT_DONE)!=0)
259 break;
261 #endif
262 /* set output length */
263 IOMBUF_DLEN(ombuf) = IOMBUF_DLEN(imbuf);
265 if (num >= MAX_WAIT_TIMES)
267 printk("mxhw_engine: timeout!! data length= %d\n",dlen);
268 return 2;
271 /* step 8: get IVs if there are, 4 bytes each */
272 if (info->mode != MXCIPHER_MODE_ECB)
274 ivec = IOMBUF_DATA(ombuf)+dlen;
275 for (i=0,offs=_REG_RO_MXCIPHER_IVOUT0; i < info->blen; i+=4, offs+=4)
277 tmpv = REGRDL(offs);
278 *(u32*)(ivec+i) = SWAP32(tmpv);
281 return 0;
284 #ifdef IRQUSED
285 /* hw interrupt notifies a complete of packet,
286 this interrupt handler represents no process, so can't sleep,
287 no kmalloc, current->pid, copy_from_user, ..., and etc
289 static void
290 mxhw_crypto_engine_interrupt(int irq, void *dev_id, struct pt_regs *regs_base)
292 // printk(KERN_INFO "mxhw_crypto_engine_interrupt irq = %d\n", irq);
294 /* check if it is what the engine says */
295 if (IRQ_INT_FLAG==0 && (REGRDL(_REG_RO_INTRPT_POST)&_BIT_RO_INTRPT_DONE)!=0)
297 wake_up_interruptible(&dmawq);
298 REGWRL(_REG_WO_INTRPT_CLEAR, 1);
299 IRQ_INT_FLAG=1;
302 #endif
304 int
305 mxhw_crypto_engine_up(void)
307 /* get the base mapping address to the engine */
308 if ((base=(void*)ioremap_nocache(CPE_WMAC_BASE, REGS_SIZE))==NULL)
310 printk("Fail to io map\n");
311 return -EFAULT;
313 memset_io(base, 0, REGS_SIZE);
315 /* set initial FIFO configuration for the crypto engine */
316 REGWRL(_REG_RW_IOFIFO_THRD, 0x101);
318 #ifdef IRQUSED
319 /* set up interrupt mechanism */
320 cpe_int_set_irq(IRQ_WMAC, LEVEL, H_ACTIVE);
321 if (request_irq(IRQ_WMAC, (void*) mxhw_crypto_engine_interrupt, SA_INTERRUPT,
322 "mxcrypto", NULL)!=0)
323 { /* it return -EBUSY */
324 printk("Some other device may take this line of IRQ\n");
325 return 2;
327 /* bring up the waiting queue for engine and the dispatcher */
328 init_waitqueue_head(&dmawq);
329 printk("setup IRQ\n");
330 #endif
331 return 0;
334 void
335 mxhw_crypto_engine_down(void)
337 REGWRL(_REG_RW_DMA_ENGN_CTRL,_BIT_RW_DMA_ENGN_DSBL);
338 #ifdef IRQUSED
339 /* the thread might sleep on waiting for DMA */
340 wake_up_interruptible(&dmawq);
341 free_irq(IRQ_WMAC, NULL);
342 unregister_chrdev(CRYPTO_MAJOR, CRYPTO_DEVNAME);
343 #endif
344 /* free up memory */
345 if (base) iounmap(base);
346 /* disable DMA and security engines */