MOXA linux-2.6.x / linux-2.6.9-uc0 from sdlinux-moxaart.tgz
[linux-2.6.9-moxart.git] / drivers / char / mxhwenp / faraday / mxhw_crypto_engine.c
blob6a6a2ff6d7d186aa58374e515b2b334247dd0708
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>
16 #include "mxhw_crypto_engine.h"
18 /* memory and register information */
19 #define CPE_WMAC_BASE 0x90F00000 /* physical base address */
20 #define REGS_SIZE 0x90 /* physical area */
21 static void *base=NULL; /* base address of the io memory assigned to the engine */
22 #define REGWRL(off,v) writel(v,base+off)
23 #define REGRDL(off) readl(base+off)
25 #define PERFORM_WAIT_TIME 50
26 #define MAX_WAIT_TIMES 200
28 #ifdef IRQUSED
29 #define IRQ_WMAC 29 /* trq number */
30 wait_queue_head_t dmawq; /* a waiting queue that the engine wakes up the dispatcher */
31 static u32 IRQ_INT_FLAG=0;
32 #endif
34 #ifdef DEBUG
35 static void
36 read_registers(u32 a, u32 b)
38 if (a==0 && b==0) b = REGS_SIZE;
40 mdelay(200);
41 printk("\n-------------- addresses --------------%d\n", 0);
42 for (; a < b; a+=4)
43 printk("0x%02x = 0x%08x\n", a, REGRDL(a));
44 printk("\n-------------- addresses --------------%d\n", 9);
45 mdelay(200);
47 #else
48 #define read_registers(a,b)
49 #endif
51 int
52 mxhw_crypto_engine_dma_malloc(IOMBUF *mbuf, u32 size)
54 IOMBUF_OFFS(mbuf) = 0;
55 IOMBUF_SIZE(mbuf) = size; /* memory space for data */
56 IOMBUF_VIRT(mbuf) = consistent_alloc( GFP_DMA|GFP_KERNEL, size,
57 &(IOMBUF_PHYS(mbuf)));
58 if (IOMBUF_VIRT(mbuf)==NULL)
59 return 1;
60 return 0;
63 void
64 mxhw_crypto_engine_dma_mfree(IOMBUF *mbuf)
66 if (mbuf && IOMBUF_VIRT(mbuf))
67 consistent_free((u32 *)IOMBUF_VIRT(mbuf), IOMBUF_SIZE(mbuf)+IOMBUF_OFFS(mbuf), IOMBUF_PHYS(mbuf));
70 typedef struct _CTXPARAM
72 u32 algo;
73 u32 ctrl;
74 u32 blen;
75 u32 klen;
76 } CTXPARAM;
78 static CTXPARAM CtxParams[] =
80 {MXCIPHER_ALGO_DES, _BIT_RW_MXCIPHER_ALGO_DES, 8, 8},
81 {MXCIPHER_ALGO_3DES, _BIT_RW_MXCIPHER_ALGO_3DES, 8, 24},
82 {MXCIPHER_ALGO_AES128, _BIT_RW_MXCIPHER_ALGO_AES128, 16, 16},
83 {MXCIPHER_ALGO_AES192, _BIT_RW_MXCIPHER_ALGO_AES192, 16, 24},
84 {MXCIPHER_ALGO_AES256, _BIT_RW_MXCIPHER_ALGO_AES256, 16, 32}
87 static u32 CtxParams_Size=(sizeof(CtxParams)/sizeof(CtxParams[0]));
89 #if 1
90 #define SWAP32(v) ((v>>24)|((v&0x00ff0000)>>8)|((v&0x0000ff00)<<8)|(v<<24))
91 #else
92 #define SWAP32(v) v
93 #endif
95 static void
96 swap(u8 *data, u32 len)
98 u32 i, v;
100 for (i=0; i < len; i+=4, data += 4)
102 v = *(u32*) data;
103 *(u32*)data = SWAP32(v);
107 #define mswap32(data,l) \
109 u32 i, v, len=l>>2; \
110 u32 *d = (u32*) data; \
111 for (i=0; i < len; i++, d++) \
113 v = *d; \
114 *d = SWAP32(v); \
119 mxhw_crypto_engine_register(CIPHER *info, u32 *ctrl)
121 u32 i;
123 if (info->mode==MXCIPHER_MODE_ECB) *ctrl = _BIT_RW_MXCIPHER_MODE_ECB;
124 else if (info->mode==MXCIPHER_MODE_CBC) *ctrl = _BIT_RW_MXCIPHER_MODE_CBC;
125 else if (info->mode==MXCIPHER_MODE_CTR) *ctrl = _BIT_RW_MXCIPHER_MODE_CTR;
126 else if (info->mode==MXCIPHER_MODE_OFB) *ctrl = _BIT_RW_MXCIPHER_MODE_OFB;
127 else if (info->mode==MXCIPHER_MODE_CFB)
129 if (info->bits!=8)
130 return -1;
131 *ctrl = _BIT_RW_MXCIPHER_MODE_CFB;
133 else
134 return -1;
136 *ctrl |= (info->type==0)? _BIT_RW_MXCIPHER_TYPE_DEC:_BIT_RW_MXCIPHER_TYPE_ENC;
138 info->blen = info->klen = 0;
139 for (i=0; i < CtxParams_Size;i++)
141 if (info->algo==CtxParams[i].algo)
143 info->blen = CtxParams[i].blen;
144 info->klen = CtxParams[i].klen;
145 *ctrl |= CtxParams[i].ctrl;
146 swap(info->keys, info->klen);
147 return 0;
150 return -2;
153 void
154 mxhw_crypto_engine_unregister(u32 ctrl)
156 (void) ctrl;
159 #define IRQ_LEVEL LEVEL
160 #define IRQ_ACTIVE L_ACTIVE
161 #define INTRPT_ENBL_BIT 1
162 #define INTRPT_DSBL_BIT 0
164 /* Note:
165 1. IOMBUF_DLEN(imbuf) covers the IV if there is
166 2. remember to set IOMBUF_DLEN(ombuf) = IOMBUF_DLEN(imbuf)
169 mxhw_crypto_engine_perform(u32 ctrl, CIPHER *info, IOMBUF *imbuf, IOMBUF *ombuf, u32 *exited)
171 u_long offs;
172 u32 tmpv,dlen;
173 u8 *ivec;
174 int i,num=0;
176 if (info->mode!=MXCIPHER_MODE_ECB)
177 dlen = IOMBUF_DLEN(imbuf)-info->blen;
178 else
180 dlen = IOMBUF_DLEN(imbuf);
181 if (info->mode!=MXCIPHER_MODE_CFB && dlen%info->blen)
182 return 1;
185 DBG(KERN_INFO "mxhw_engine: engine_perform = %d %d 0x%x\n", 11, info->type, ctrl);
187 /* step 0: disable all interrupts: stop, err, done */
188 REGWRL(_REG_WO_INTRPT_CLEAR, 1);
190 /* step 1: set cipher control */
191 REGWRL(_REG_RW_MXCIPHER_CTRL, ctrl);
193 /* step 2: set IVs if there are, 4 bytes each */
194 if (info->mode!=MXCIPHER_MODE_ECB)
196 dlen = IOMBUF_DLEN(imbuf)-info->blen;
197 ivec = IOMBUF_DATA(imbuf)+dlen;
198 for (i=0,offs=_REG_RW_MXCIPHER_IVIN0; i < info->blen; i+=4, offs+=4)
200 tmpv = *(u32*)(ivec+i);
201 tmpv = SWAP32(tmpv);
202 REGWRL(offs,tmpv);
206 /* step 3: set keys, 4 bytes each, swap already */
207 for (i=0,offs=_REG_RW_MXCIPHER_KEY0; i < info->klen; i+=4, offs+=4)
208 REGWRL(offs,*(u32*)(info->keys+i));
210 /* step 4: set DMA controls */
211 REGWRL( _REG_RW_DMA_ADDR_SURC, IOMBUF_PHYS(imbuf));
212 REGWRL( _REG_RW_DMA_ADDR_DEST, IOMBUF_PHYS(ombuf));
213 REGWRL( _REG_RW_DMA_DATA_SIZE, dlen);
215 /* step 5: enable transfer done */
216 REGWRL(_REG_RW_INTRPT_ENBL, INTRPT_ENBL_BIT);
218 DBG(KERN_INFO "mxhw_engine: engine_perform = %d\n", 66);
220 /* step 6: enable DMA engine */
221 REGWRL(_REG_RW_DMA_ENGN_CTRL, _BIT_RW_DMA_ENGN_ENBL);
222 //read_registers(_REG_RW_DMA_ENGN_CTRL,0x70);
224 /* step 7: wait for data of the size is transferred. if it waits for
225 a stop at DMA, the data might not be completely transferred */
226 #ifdef IRQUSED
227 DBG(KERN_INFO "mxhw_engine: interrupt = %d %d\n", 77, dlen);
228 #if 0
229 wait_event_interruptible(&dmawq, (REGRDL(_REG_RO_INTRPT_POST)&_BIT_RO_INTRPT_DONE)!=0);
230 #else
231 while(IRQ_INT_FLAG==0 && num++ < MAX_WAIT_TIMES)
233 udelay(PERFORM_WAIT_TIME); // current->state = TASK_INTERRUPTIBLE; schedule_timeout(HZ);
234 if (IRQ_INT_FLAG!=0)
235 break;
237 #endif
238 IRQ_INT_FLAG=0;
240 #else
241 DBG(KERN_INFO "mxhw_engine: poll =%d %d\n", 77, dlen);
243 while(num++ < MAX_WAIT_TIMES)
245 udelay(PERFORM_WAIT_TIME);
246 if ((REGRDL(_REG_RO_INTRPT_POST)&_BIT_RO_INTRPT_DONE)!=0)
247 break;
249 #endif
250 /* set output length */
251 IOMBUF_DLEN(ombuf) = IOMBUF_DLEN(imbuf);
253 if (num >= MAX_WAIT_TIMES)
255 printk("mxhw_engine: timeout!! data length= %d\n",dlen);
256 return 2;
259 /* step 8: get IVs if there are, 4 bytes each */
260 if (info->mode != MXCIPHER_MODE_ECB)
262 ivec = IOMBUF_DATA(ombuf)+dlen;
263 for (i=0,offs=_REG_RO_MXCIPHER_IVOUT0; i < info->blen; i+=4, offs+=4)
265 tmpv = REGRDL(offs);
266 *(u32*)(ivec+i) = SWAP32(tmpv);
269 return 0;
272 #ifdef IRQUSED
273 /* hw interrupt notifies a complete of packet,
274 this interrupt handler represents no process, so can't sleep,
275 no kmalloc, current->pid, copy_from_user, ..., and etc
277 static void
278 mxhw_crypto_engine_interrupt(int irq, void *dev_id, struct pt_regs *regs_base)
280 // printk(KERN_INFO "mxhw_crypto_engine_interrupt irq = %d\n", irq);
282 /* check if it is what the engine says */
283 if (IRQ_INT_FLAG==0 && (REGRDL(_REG_RO_INTRPT_POST)&_BIT_RO_INTRPT_DONE)!=0)
285 wake_up_interruptible(&dmawq);
286 REGWRL(_REG_WO_INTRPT_CLEAR, 1);
287 IRQ_INT_FLAG=1;
290 #endif
292 int
293 mxhw_crypto_engine_up(void)
295 /* get the base mapping address to the engine */
296 if ((base=(void*)ioremap_nocache(CPE_WMAC_BASE, REGS_SIZE))==NULL)
298 printk("Fail to io map\n");
299 return -EFAULT;
301 memset_io(base, 0, REGS_SIZE);
303 /* set initial FIFO configuration for the crypto engine */
304 REGWRL(_REG_RW_IOFIFO_THRD, 0x101);
306 #ifdef IRQUSED
307 /* set up interrupt mechanism */
308 cpe_int_set_irq(IRQ_WMAC, LEVEL, H_ACTIVE);
309 if (request_irq(IRQ_WMAC, (void*) mxhw_crypto_engine_interrupt, SA_INTERRUPT,
310 "mxcrypto", NULL)!=0)
311 { /* it return -EBUSY */
312 printk("Some other device may take this line of IRQ\n");
313 return 2;
315 /* bring up the waiting queue for engine and the dispatcher */
316 init_waitqueue_head(&dmawq);
317 printk("setup IRQ\n");
318 #endif
319 return 0;
322 void
323 mxhw_crypto_engine_down(void)
325 REGWRL(_REG_RW_DMA_ENGN_CTRL,_BIT_RW_DMA_ENGN_DSBL);
326 #ifdef IRQUSED
327 /* the thread might sleep on waiting for DMA */
328 wake_up_interruptible(&dmawq);
329 free_irq(IRQ_WMAC, NULL);
330 unregister_chrdev(CRYPTO_MAJOR, CRYPTO_DEVNAME);
331 #endif
332 /* free up memory */
333 if (base) iounmap(base);
334 /* disable DMA and security engines */