/[VMELinux]/driver/ca91c042.c
ViewVC logotype

Contents of /driver/ca91c042.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.8 - (show annotations)
Fri May 14 21:47:37 2004 UTC (14 years, 11 months ago) by jhuggins
Branch: MAIN
CVS Tags: License_change_back_to_GPL_May_2004, HEAD
Changes since 1.7: +30 -59 lines
File MIME type: text/plain
Changed license back to GPL.
Revised copyright year and contact information.
1 // ====================================================================
2 // These VMELinux tools provide Linux access to the VMEbus via the
3 // Tundra Universe PCI/VME bridge.
4 // Copyright (C) 1997-2004 John Huggins and Michael Wyrick
5 //
6 // This program is free software; you can redistribute it and/or modify
7 // it under the terms of the GNU General Public License as published by
8 // the Free Software Foundation; either version 2 of the License, or
9 // (at your option) any later version.
10 //
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
15 //
16 // You should have received a copy of the GNU General Public License
17 // along with this program; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 //
20 // Contact the VMELinux project manager with questions at john@johnhuggins.com
21 // ====================================================================
22 //
23 // This software consists of voluntary contributions made by many
24 // individuals on behalf of the VMELinux Project. For more
25 // information on the VMELinux Project, please see
26 // <http://www.vmelinux.org/>.
27 //
28
29 //------------------------------------------------------------------------------
30 // Title: Tundra Universe PCI-VME Kernel Driver
31 // $Date: 2004/05/14 21:47:37 $
32 // $Author: jhuggins $
33 // $Revision: 1.8 $
34 // Initial programmer: Michael Wyrick
35 // language: GCC 2.95 and 3.0
36 //------------------------------------------------------------------------------
37 // Purpose: Provide a Kernel Driver to Linux for the Universe I and II
38 // Universe model number ca91c042
39 // Docs:
40 // This driver supports:
41 // Universe
42 // Universe II
43 // Universe II B
44 // Universe II D
45 //-----------------------------------------------------------------------------
46 #define MODULE
47
48 static char Version[] = "vmelinux-1.3-development";
49
50 #include <linux/config.h>
51 #include <linux/version.h>
52
53 #ifdef CONFIG_MODVERSIONS
54 #define MODVERSIONS
55 #include <linux/modversions.h>
56 #endif
57
58 #include <linux/module.h>
59 #include <linux/types.h>
60 #include <linux/errno.h>
61 #include <linux/proc_fs.h>
62 #include <linux/pci.h>
63 #include <linux/poll.h>
64 #include <asm/io.h>
65 #include <asm/uaccess.h>
66
67 #include "ca91c042.h"
68
69 //----------------------------------------------------------------------------
70 // Prototypes
71 //----------------------------------------------------------------------------
72 static int uni_open(struct inode *, struct file *);
73 static int uni_release(struct inode *, struct file *);
74 static ssize_t uni_read(struct file *,char *, size_t, loff_t *);
75 static ssize_t uni_write(struct file *,const char *, size_t, loff_t *);
76 static unsigned int uni_poll(struct file *, poll_table *);
77 static int uni_ioctl(struct inode *, struct file *, unsigned int, unsigned long);
78 static long long uni_llseek(struct file *,loff_t,int);
79 //static int uni_mmap(struct inode *inode,struct file *file,struct vm_area_struct *vma);
80 //static int uni_select(struct inode *inode,struct file *file,int mode, select_table *table);
81 static int uni_procinfo(char *, char **, off_t, int, int *,void *);
82
83 //----------------------------------------------------------------------------
84 // Types
85 //----------------------------------------------------------------------------
86 static struct proc_dir_entry *uni_procdir;
87
88 static struct file_operations uni_fops =
89 {
90 llseek: uni_llseek,
91 read: uni_read,
92 write: uni_write,
93 poll: uni_poll, // uni_poll
94 ioctl: uni_ioctl,
95 open: uni_open,
96 release: uni_release
97 };
98
99 static int aCTL[] = {LSI0_CTL, LSI1_CTL, LSI2_CTL, LSI3_CTL,
100 LSI4_CTL, LSI5_CTL, LSI6_CTL, LSI7_CTL};
101
102 static int aBS[] = {LSI0_BS, LSI1_BS, LSI2_BS, LSI3_BS,
103 LSI4_BS, LSI5_BS, LSI6_BS, LSI7_BS};
104
105 static int aBD[] = {LSI0_BD, LSI1_BD, LSI2_BD, LSI3_BD,
106 LSI4_BD, LSI5_BD, LSI6_BD, LSI7_BD};
107
108 static int aTO[] = {LSI0_TO, LSI1_TO, LSI2_TO, LSI3_TO,
109 LSI4_TO, LSI5_TO, LSI6_TO, LSI7_TO};
110
111 //----------------------------------------------------------------------------
112 // Vars and Defines
113 //----------------------------------------------------------------------------
114 #define UNI_MAJOR 221
115 #define MAX_MINOR 8
116 #define CONTROL_MINOR 8
117
118 #define MODE_UNDEFINED 0
119 #define MODE_PROGRAMMED 1
120 #define MODE_DMA 2
121
122 #define DMATYPE_SINGLE 1
123 #define DMATYPE_LLIST 2
124
125 #define UNIVERSEI 0
126 #define UNIVERSEII 1
127 #define UNIVERSEIIB 2
128 #define UNIVERSEUNK 5
129 #define UNIVERSEIIFUNC ((ChipType == UNIVERSEII) || (ChipType == UNIVERSEIIB))
130 static int ChipType = UNIVERSEUNK;
131
132 static int OkToWrite[MAX_MINOR + 1]; // Can I write to the Hardware
133
134 static int opened[MAX_MINOR + 1];
135 static int mode[MAX_MINOR + 1]; // DMA or Programmed I/O
136
137 static unsigned long DMA[MAX_MINOR + 1]; // DMA Control Reg
138
139 static int status;
140 static int DMAType = 0;
141 static int irq = 0;
142 static char *baseaddr = 0;
143 static char *image_ba[MAX_MINOR+1]; // Base PCI Address
144
145 static unsigned int image_ptr[MAX_MINOR+1];
146 static unsigned int image_va[MAX_MINOR+1];
147
148 // Hold the VME Irq Handlers
149 static TirqHandler vmeirqs[7] = {NULL,NULL,NULL,NULL,NULL,NULL,NULL};
150 static short vmeirqbit[7] = {IRQ_VIRQ1, IRQ_VIRQ2, IRQ_VIRQ3, IRQ_VIRQ4,
151 IRQ_VIRQ5, IRQ_VIRQ6, IRQ_VIRQ7};
152 static int vmevec[7] = {V1_STATID, V2_STATID, V3_STATID, V4_STATID,
153 V5_STATID, V6_STATID, V7_STATID};
154
155 // Status Vars
156 static unsigned int reads = 0;
157 static unsigned int writes = 0;
158 static unsigned int ioctls = 0;
159
160 static TDMAcallback DMACallBackFunc = NULL;
161 static void *debugptr = NULL;
162
163 // Timers
164 struct timer_list DMA_timer; // This is a timer for returning status
165
166 //----------------------------------------------------------------------------
167 // uni_procinfo()
168 //----------------------------------------------------------------------------
169 static int uni_procinfo(char *buf, char **start, off_t fpos, int lenght, int *eof, void *data)
170 {
171 char *p;
172 unsigned int temp1,temp2,x;
173
174 p = buf;
175 p += sprintf(p,"Universe driver %s, ChipType ",Version);
176 switch (ChipType) {
177 case UNIVERSEI : p+= sprintf(p,"Universe I\n"); break;
178 case UNIVERSEII : p+= sprintf(p,"Universe II\n"); break;
179 case UNIVERSEIIB : p+= sprintf(p,"Universe II B/D\n"); break;
180 default: p+= sprintf(p,"Unknown Universe\n"); break;
181 }
182
183 p += sprintf(p," baseaddr = %08X\n",(int)baseaddr);
184 p += sprintf(p," Stats reads = %i writes = %i ioctls = %i\n",
185 reads,writes,ioctls);
186
187 for (x=0;x<8;x+=2) {
188 temp1 = readl(baseaddr+aCTL[x]);
189 temp2 = readl(baseaddr+aCTL[x+1]);
190 p += sprintf(p," LSI%i_CTL = %08X LSI%i_CTL = %08X\n",x,temp1,x+1,temp2);
191 temp1 = readl(baseaddr+aBS[x]);
192 temp2 = readl(baseaddr+aBS[x+1]);
193 p += sprintf(p," LSI%i_BS = %08X LSI%i_BS = %08X\n",x,temp1,x+1,temp2);
194 temp1 = readl(baseaddr+aBD[x]);
195 temp2 = readl(baseaddr+aBD[x+1]);
196 p += sprintf(p," LSI%i_BD = %08X LSI%i_BD = %08X\n",x,temp1,x+1,temp2);
197 temp1 = readl(baseaddr+aTO[x]);
198 temp2 = readl(baseaddr+aTO[x+1]);
199 p += sprintf(p," LSI%i_TO = %08X LSI%i_TO = %08X\n",x,temp1,x+1,temp2);
200 }
201
202 for (x=0;x<8;x+=2)
203 p += sprintf(p," image_va%i = %08X image_va%i = %08X\n",
204 x,image_va[x],x+1,image_va[x+1]);
205 p += sprintf(p,"\nDriver Program Status:\n");
206
207 for (x=0;x<8;x+=2)
208 p += sprintf(p," DMACTL %i = %08lX DMACTL %i = %08lX\n",
209 x,DMA[x],x+1,DMA[x+1]);
210 for (x=0;x<8;x+=2)
211 p += sprintf(p," OkToWrite %i = %1X OkToWrite %i = %1X\n",
212 x,OkToWrite[x],x+1,OkToWrite[x+1]);
213 for (x=0;x<8;x+=2)
214 p += sprintf(p," Mode %i = %1X Mode %i = %1X\n",
215 x,mode[x],x+1,mode[x+1]);
216
217 p += sprintf(p,"\n");
218
219 temp1 = 0;
220 p += sprintf(p, "VMEIrqs Assigned: ");
221 for (x=0;x<7;x++) {
222 if (vmeirqs[x] != NULL) {
223 p += sprintf(p, "%i ",x+1);
224 temp1++;
225 }
226 }
227 if (temp1 == 0)
228 p += sprintf(p, "none\n");
229 else
230 p += sprintf(p,"\n");
231
232 *eof = 1;
233 return p - buf;
234 }
235
236 //----------------------------------------------------------------------------
237 // register_proc()
238 //----------------------------------------------------------------------------
239 static void register_proc()
240 {
241 uni_procdir = create_proc_entry("ca91c042", S_IFREG | S_IRUGO, 0);
242 uni_procdir->read_proc = uni_procinfo;
243 }
244
245 //----------------------------------------------------------------------------
246 // unregister_proc()
247 //----------------------------------------------------------------------------
248 static void unregister_proc()
249 {
250 remove_proc_entry("ca91c042",0);
251 }
252
253 //----------------------------------------------------------------------------
254 //
255 // uni_poll()
256 //
257 //----------------------------------------------------------------------------
258 static unsigned int uni_poll(struct file* file, poll_table* wait)
259 {
260 return 0;
261 }
262
263 //----------------------------------------------------------------------------
264 //
265 // uni_open()
266 //
267 //----------------------------------------------------------------------------
268 static int uni_open(struct inode *inode,struct file *file)
269 {
270 unsigned int minor = MINOR(inode->i_rdev);
271
272 if (minor > MAX_MINOR) {
273 return(-ENODEV);
274 }
275
276 if (minor == CONTROL_MINOR) {
277 opened[minor]++;
278 return(0);
279 }
280
281 if (!opened[minor]) {
282 opened[minor] = 1;
283 return(0);
284 } else
285 return(-EBUSY);
286 }
287
288 //----------------------------------------------------------------------------
289 //
290 // uni_release()
291 //
292 //----------------------------------------------------------------------------
293 static int uni_release(struct inode *inode,struct file *file)
294 {
295 unsigned int minor = MINOR(inode->i_rdev);
296
297 opened[minor]--;
298
299 return 0;
300 }
301
302 //----------------------------------------------------------------------------
303 //
304 // uni_lseek()
305 //
306 //----------------------------------------------------------------------------
307 static long long uni_llseek(struct file *file,loff_t offset,int whence)
308 {
309 unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev);
310 unsigned int toffset,base,paddr;
311
312 if (whence == SEEK_SET) {
313 if (minor == CONTROL_MINOR) {
314 image_ptr[minor] = offset;
315 } else {
316 toffset = readl(baseaddr+aTO[minor]);
317 base = readl(baseaddr+aBS[minor]);
318 paddr = offset-toffset;
319 image_ptr[minor] = (int)(image_ba[minor]+(paddr-base));
320 }
321 return 0;
322 } else if (whence == SEEK_CUR) {
323 image_ptr[minor] += offset;
324 return 0;
325 } else
326 return -1;
327 }
328
329 //----------------------------------------------------------------------------
330 //
331 // uni_read()
332 //
333 //----------------------------------------------------------------------------
334 static ssize_t uni_read(struct file *file, char *buf, size_t count, loff_t *ppos)
335 {
336 int x = 0;
337 unsigned int v,numt,remain,tmp;
338 char *temp = buf;
339 unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev);
340 int p;
341
342 unsigned char vc;
343 unsigned short vs;
344 unsigned int vl;
345
346 char *DMA_Buffer;
347 unsigned int DMA_Buffer_Size = 0,
348 order = 0,
349 a_size = 0,
350 dma_align = 0,
351 timeout = 0;
352 int val = 0,
353 pci = 0,
354 vme = 0,
355 okcount = 0;
356
357 if (minor == CONTROL_MINOR) {
358 p = (int)image_ptr[minor];
359 v = readl(baseaddr+p);
360 __copy_to_user(temp,&v,4);
361 } else {
362 reads++;
363 if (OkToWrite[minor]) {
364 if (mode[minor] == MODE_PROGRAMMED) {
365 numt = count;
366 remain = count;
367
368 // Calc the number of longs we need
369 numt = count / 4;
370 remain = count % 4;
371 for (x=0;x<numt;x++) {
372 vl = readl(image_ptr[minor]);
373
374 // Lets Check for a Bus Error
375 tmp = readl(baseaddr+PCI_CSR);
376 if (tmp & 0x08000000) {
377 writel(tmp,baseaddr+PCI_CSR);
378 return(okcount);
379 } else
380 okcount += 4;
381
382 __copy_to_user(temp,&vl,4);
383 image_ptr[minor]+=4;
384 temp+=4;
385 }
386
387 // Calc the number of Words we need
388 numt = remain / 2;
389 remain = remain % 2;
390 for (x=0;x<numt;x++) {
391 vs = readw(image_ptr[minor]);
392
393 // Lets Check for a Bus Error
394 tmp = readl(baseaddr+PCI_CSR);
395 if (tmp & 0x08000000) {
396 writel(tmp,baseaddr+PCI_CSR);
397 return(okcount);
398 } else
399 okcount += 2;
400
401 __copy_to_user(temp,&vs,2);
402 image_ptr[minor]+=2;
403 temp+=2;
404 }
405
406 for (x=0;x<remain;x++) {
407 vc = readb(image_ptr[minor]);
408
409 // Lets Check for a Bus Error
410 tmp = readl(baseaddr+PCI_CSR);
411 if (tmp & 0x08000000) {
412 writel(tmp,baseaddr+PCI_CSR);
413 return(okcount);
414 } else
415 okcount++;
416
417 __copy_to_user(temp,&vc,1);
418 image_ptr[minor]+=1;
419 temp+=1;
420 }
421
422 } else if (mode[minor] == MODE_DMA) {
423 // ------------------------------------------------------------------
424 //
425 // ------------------------------------------------------------------
426 // Wait for DMA to finish, This needs to be changed
427 val = readl(baseaddr+DGCS);
428 while ((val & 0x00008000) && (timeout++ < 1000000))
429 val = readl(baseaddr+DGCS);
430
431 // VME Address
432 vme = image_va[minor] + (image_ptr[minor] - (unsigned int)image_ba[minor]);
433 dma_align = vme % 8;
434
435 // Setup DMA Buffer to read data into
436 DMA_Buffer_Size = count + ((int)image_ptr % 8) + dma_align;
437 a_size = PAGE_SIZE;
438 while (a_size < DMA_Buffer_Size) {
439 order++;
440 a_size <<= 1;
441 }
442 DMA_Buffer = (char *)__get_dma_pages(GFP_KERNEL,order);
443
444 // PCI Address
445 pci = virt_to_bus(DMA_Buffer) + dma_align;
446
447 // Setup DMA regs
448 writel(DMA[minor],baseaddr+DCTL); // Setup Control Reg
449 writel(count,baseaddr+DTBC); // Count
450 writel(pci,baseaddr+DLA); // PCI Address
451 writel(vme,baseaddr+DVA); // VME Address
452
453 // Start DMA
454 writel(0x80006F00,baseaddr+DGCS); // GO
455
456 // Wait for DMA to finish, This needs to be changed
457 val = readl(baseaddr+DGCS);
458 while ((val & 0x00008000) && (timeout++ < 100000))
459 val = readl(baseaddr+DGCS);
460
461 if (timeout == 100000)
462 printk("<<ca91c042 DMA Timed out>>\n");
463
464 if (! (val & 0x00000800)) { // An Error Happened
465 count -= readl(baseaddr+DTBC);
466 }
467
468 image_ptr[minor] += count;
469
470 // Copy pages to User Memory
471 __copy_to_user(temp,DMA_Buffer+dma_align,count);
472
473 free_pages((unsigned long)DMA_Buffer,order);
474 } // end of MODE_DMA
475 } // end of OKtoWrite
476 }
477 *ppos += count;
478 return(count);
479 }
480
481 //----------------------------------------------------------------------------
482 //
483 // uni_write()
484 //
485 //----------------------------------------------------------------------------
486 static ssize_t uni_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
487 {
488 int x,p;
489 unsigned int numt,remain,tmp;
490 char *temp = (char *)buf;
491 unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev);
492
493 unsigned char vc;
494 unsigned short vs;
495 unsigned int vl;
496
497 char *DMA_Buffer;
498 unsigned int DMA_Buffer_Size = 0,
499 order = 0,
500 a_size = 0,
501 dma_align = 0,
502 timeout = 0;
503 int val,
504 pci = 0,
505 vme = 0,
506 okcount = 0;
507
508 writes++;
509 if (minor == CONTROL_MINOR) {
510 __copy_from_user(&vl,temp,4);
511 p = (int)image_ptr[minor];
512 writel(vl,baseaddr+p);
513 } else {
514 if (OkToWrite[minor]) {
515 if (mode[minor] == MODE_PROGRAMMED) {
516 // Calc the number of longs we need
517 numt = count;
518 remain = count;
519
520 numt = count / 4;
521 remain = count % 4;
522 for (x=0;x<numt;x++) {
523 __copy_from_user(&vl,temp,4);
524 writel(vl,image_ptr[minor]);
525
526 // Lets Check for a Bus Error
527 tmp = readl(baseaddr+PCI_CSR);
528 if (tmp & 0x08000000) {
529 writel(tmp,baseaddr+PCI_CSR);
530 return(okcount);
531 } else
532 okcount += 4;
533
534 image_ptr[minor]+=4;
535 temp+=4;
536 }
537
538 // Calc the number of Words we need
539 numt = remain / 2;
540 remain = remain % 2;
541
542 for (x=0;x<numt;x++) {
543 __copy_from_user(&vs,temp,2);
544 writew(vs,image_ptr[minor]);
545
546 // Lets Check for a Bus Error
547 tmp = readl(baseaddr+PCI_CSR);
548 if (tmp & 0x08000000) {
549 writel(tmp,baseaddr+PCI_CSR);
550 return(okcount);
551 } else
552 okcount += 2;
553
554 image_ptr[minor]+=2;
555 temp+=2;
556 }
557
558 for (x=0;x<remain;x++) {
559 __copy_from_user(&vc,temp,1);
560 writeb(vc,image_ptr[minor]);
561
562 // Lets Check for a Bus Error
563 tmp = readl(baseaddr+PCI_CSR);
564 if (tmp & 0x08000000) {
565 writel(tmp,baseaddr+PCI_CSR);
566 return(okcount);
567 } else
568 okcount += 2;
569
570 image_ptr[minor]+=1;
571 temp+=1;
572 }
573
574 // Lets Check for a Bus Error
575 tmp = readl(baseaddr+PCI_CSR);
576 if (tmp & 0x08000000) { // S_TA is Set
577 writel(0x08000000,baseaddr+PCI_CSR);
578 count = 0;
579 }
580
581 } else if (mode[minor] == MODE_DMA) {
582 // ------------------------------------------------------------------
583 //
584 // ------------------------------------------------------------------
585 // Wait for DMA to finish, This needs to be changed
586 val = readl(baseaddr+DGCS);
587 while ((val & 0x00008000) && (timeout++ < 100000))
588 val = readl(baseaddr+DGCS);
589
590 // Setup DMA Buffer to write data into
591 // VME Address
592 vme = image_va[minor] + (image_ptr[minor] - (unsigned int)image_ba[minor]);
593 dma_align = vme % 8;
594
595 DMA_Buffer_Size = count + ((int)image_ptr % 8) + dma_align;
596 a_size = PAGE_SIZE;
597 while (a_size < DMA_Buffer_Size) {
598 order++;
599 a_size <<= 1;
600 }
601 DMA_Buffer = (char *)__get_dma_pages(GFP_KERNEL,order);
602
603 // Copy User Memory into buffer
604 __copy_from_user(DMA_Buffer + dma_align,temp,count);
605
606 // PCI Address
607 pci = virt_to_bus(DMA_Buffer) + dma_align;
608
609 // Setup DMA regs
610 writel(DMA[minor]|0x80000000,baseaddr+DCTL); // Setup Control Reg
611 writel(count,baseaddr+DTBC); // Count
612 writel(pci,baseaddr+DLA); // PCI Address
613 writel(vme,baseaddr+DVA); // VME Address
614
615 // Start DMA
616 writel(0x80006F00,baseaddr+DGCS); // GO
617
618 // Wait for DMA to finish, This needs to be changed
619 val = readl(baseaddr+DGCS);
620 while ((val & 0x00008000) && (timeout++ < 100000))
621 val = readl(baseaddr+DGCS);
622
623 if (timeout == 100000)
624 printk("<<ca91c042 DMA Timed out>>\n");
625
626 if (! (val & 0x00000800)) { // An Error Happened
627 // The Universe Seems to return an invalid value in DTBC on
628 // Bus Errors during DMA, so invalidate the count
629 count = 0;
630 }
631 image_ptr[minor] += count;
632
633 free_pages((unsigned long)DMA_Buffer,order);
634 } // end of MODE_DMA
635 } //OKtoWrite
636 }
637 *ppos += count;
638 return(count);
639 }
640
641 //----------------------------------------------------------------------------
642 // uni_ioctl()
643 //----------------------------------------------------------------------------
644 static int uni_ioctl(struct inode *inode,struct file *file,unsigned int cmd, unsigned long arg)
645 {
646 unsigned int minor = MINOR(inode->i_rdev);
647 unsigned int sizetomap = 0, to = 0, bs = 0;
648
649 ioctls++;
650 switch (cmd) {
651 case IOCTL_SET_CTL:
652 writel(arg,baseaddr+aCTL[minor]);
653
654 // Lets compute and save the DMA CTL Register
655 DMA[minor] = arg & 0x00FFFF00;
656 break;
657
658 case IOCTL_SET_MODE:
659 mode[minor] = arg;
660 break;
661
662 // Lets Map the VME Bus to the PCI Bus
663 //
664 // << NOTE >> BD Must already be set before you call this!!!!
665 //
666 //
667 case IOCTL_SET_BS:
668 writel(arg,baseaddr+aBS[minor]);
669 if (image_ba[minor])
670 iounmap(image_ba[minor]);
671
672 // This uses the BD Register to Find the size of the Image Mapping
673 sizetomap = readl(baseaddr+aBD[minor]);
674 sizetomap -= arg;
675
676 image_ba[minor] = (char *)ioremap(arg,sizetomap);
677 if (!image_ba[minor]) {
678 OkToWrite[minor] = 0;
679 return -1;
680 }
681 image_ptr[minor] = (int)image_ba[minor];
682 OkToWrite[minor] = 1;
683
684 // Calculate the VME Address
685 bs = readl(baseaddr+aBS[minor]);
686 to = readl(baseaddr+aTO[minor]);
687 image_va[minor] = bs + to;
688 break;
689
690 case IOCTL_SET_BD:
691 writel(arg,baseaddr+aBD[minor]);
692 break;
693 case IOCTL_SET_TO:
694 writel(arg,baseaddr+aTO[minor]);
695
696 // Calculate the VME Address
697 bs = readl(baseaddr+aBS[minor]);
698 to = readl(baseaddr+aTO[minor]);
699 image_va[minor] = bs + to;
700 break;
701 default:
702 if (cmd < 0x1000) { // This is a Register value so write to it.
703 writel(arg,baseaddr+cmd);
704 }
705 break;
706 }
707 return(0);
708 }
709
710 //-----------------------------------------------------------------------------
711 // Function : PrintCmdPacketList
712 // Inputs : TDMA_Cmd_Packet* cpl (PCI Phys Address)
713 // Outputs : void
714 // Description:
715 // Remarks :
716 // History :
717 //-----------------------------------------------------------------------------
718 void PrintCmdPacketList(TDMA_Cmd_Packet* cpl)
719 {
720 TDMA_Cmd_Packet *p = bus_to_virt((int)cpl);
721 char buff[100];
722 int x = 0;
723 int done = 0;
724
725 while (!done && (x < 10)) {
726 x++;
727 sprintf(buff,"<ca91c042> (%i) dctl=%08X, dtbc=%08X\n",x,p->dctl,p->dtbc);
728 printk(buff);
729 sprintf(buff,"<ca91c042> dlv=%08X, dva=%08X\n",p->dlv,p->dva);
730 printk(buff);
731 sprintf(buff,"<ca91c042> dcpp=%08X\n",p->dcpp);
732 printk(buff);
733 done = (p->dcpp & 0x00000001);
734 p = bus_to_virt((int)(TDMA_Cmd_Packet*)(p->dcpp & 0xFFFFFFF8)); // Next in Line Please
735 }
736 }
737
738 //-----------------------------------------------------------------------------
739 // Function : void DMA_status
740 // Inputs : unsigned long __data
741 // Outputs : static
742 // Description:
743 // Remarks :
744 // History :
745 //-----------------------------------------------------------------------------
746 static void DMA_status(unsigned long __data)
747 {
748 printk("<<ca91c042>> DMA Timed out\n");
749
750 if (DMACallBackFunc)
751 DMACallBackFunc(1);
752 DMACallBackFunc = NULL;
753 }
754
755 //-----------------------------------------------------------------------------
756 // Function : DMA_irq_handler
757 // Inputs : void
758 // Outputs : void
759 // Description:
760 // Remarks :
761 // History :
762 //-----------------------------------------------------------------------------
763 void DMA_irq_handler(void)
764 {
765 int val;
766 int cbv=0;
767 char buf[100];
768 TDMA_Cmd_Packet *cpl;
769
770 del_timer(&DMA_timer); // Cancel DMA Time Out
771
772 val = readl(baseaddr+DGCS);
773
774 if (!(val & 0x00000800)) {
775 sprintf(buf,"<<ca91c042>> DMA Error in DMA_irq_handler DGCS=%08X\n",val);
776 printk(buf);
777 val = readl(baseaddr+DCPP);
778 sprintf(buf,"<<ca91c042>> DCPP=%08X\n",val);
779 printk(buf);
780 val = readl(baseaddr+DCTL);
781 sprintf(buf,"<<ca91c042>> DCTL=%08X\n",val);
782 printk(buf);
783 val = readl(baseaddr+DTBC);
784 sprintf(buf,"<<ca91c042>> DTBC=%08X\n",val);
785 printk(buf);
786 val = readl(baseaddr+DLA);
787 sprintf(buf,"<<ca91c042>> DLA=%08X\n",val);
788 printk(buf);
789 val = readl(baseaddr+DVA);
790 sprintf(buf,"<<ca91c042>> DVA=%08X\n",val);
791 printk(buf);
792
793 if (DMAType == DMATYPE_LLIST) {
794 printk("<<ca91c042>> CmdPacketList sent to DMARead\n");
795 PrintCmdPacketList(debugptr);
796
797 printk("<<ca91c042>> CmdPacketList as seen by DCPP\n");
798 cpl = (TDMA_Cmd_Packet*)readl(baseaddr+DCPP); // Command Packet Pointer
799 cpl = (TDMA_Cmd_Packet*)((int)cpl & ~0x03);
800
801 PrintCmdPacketList(cpl);
802 }
803 cbv = 1; // Call Back value is set to 1 to show error condition
804 }
805
806 if (DMACallBackFunc)
807 DMACallBackFunc(cbv);
808
809 // We are done with the Call Back so clear it
810 DMACallBackFunc = NULL;
811 }
812
813 //-----------------------------------------------------------------------------
814 // Function : LERR_irq_handler
815 // Inputs : void
816 // Outputs : void
817 // Description:
818 // Remarks :
819 // History :
820 //-----------------------------------------------------------------------------
821 void LERR_irq_handler(void)
822 {
823 int val;
824 char buf[100];
825 TDMA_Cmd_Packet *cpl;
826
827 del_timer(&DMA_timer); // Cancel DMA Time Out
828
829 val = readl(baseaddr+DGCS);
830
831 if (!(val & 0x00000800)) {
832 sprintf(buf,"<<ca91c042>> LERR_irq_handler DMA Read Error DGCS=%08X\n",val);
833 printk(buf);
834
835 if (DMAType == DMATYPE_LLIST) {
836 cpl = (TDMA_Cmd_Packet*)readl(baseaddr+DCPP); // Command Packet Pointer
837 cpl = (TDMA_Cmd_Packet*)((int)cpl & ~0x03);
838 PrintCmdPacketList(cpl);
839
840 sprintf(buf,"<<ca91c042>> DMAReadCallBack Request of cmdpack=0x%08X\n",(int)cpl);
841 printk(buf);
842 }
843 }
844
845 if (DMACallBackFunc)
846 DMACallBackFunc(1);
847 DMACallBackFunc = NULL;
848 }
849
850 //-----------------------------------------------------------------------------
851 // Function : VERR_irq_handler
852 // Inputs : void
853 // Outputs : void
854 // Description:
855 // Remarks :
856 // History :
857 //-----------------------------------------------------------------------------
858 void VERR_irq_handler(void)
859 {
860 int val;
861 char buf[100];
862 TDMA_Cmd_Packet *cpl;
863
864 del_timer(&DMA_timer); // Cancel DMA Time Out
865
866 val = readl(baseaddr+DGCS);
867
868 if (!(val & 0x00000800)) {
869 sprintf(buf,"<<ca91c042>> VERR_irq_handler DMA Read Error DGCS=%08X\n",val);
870 printk(buf);
871
872 if (DMAType == DMATYPE_LLIST) {
873 cpl = (TDMA_Cmd_Packet*)readl(baseaddr+DCPP); // Command Packet Pointer
874 cpl = (TDMA_Cmd_Packet*)((int)cpl & ~0x03);
875
876 PrintCmdPacketList(cpl);
877
878 sprintf(buf,"<<ca91c042>> DMAReadCallBack Request of cmdpack=0x%08X\n",(int)cpl);
879 printk(buf);
880 }
881 }
882
883 if (DMACallBackFunc)
884 DMACallBackFunc(1);
885 DMACallBackFunc = NULL;
886 }
887
888 //-----------------------------------------------------------------------------
889 // Function : irq_handler
890 // Inputs : int irq, void *dev_id, struct pt_regs *regs
891 // Outputs : void
892 // Description:
893 // Remarks :
894 // History :
895 //-----------------------------------------------------------------------------
896 static void irq_handler(int irq, void *dev_id, struct pt_regs *regs)
897 {
898 long stat, enable, i, vector;
899
900 enable = readl(baseaddr+LINT_EN);
901 stat = readl(baseaddr+LINT_STAT);
902
903 if (stat & 0x0100)
904 DMA_irq_handler();
905 if (stat & 0x0200)
906 LERR_irq_handler();
907 if (stat & 0x0400)
908 VERR_irq_handler();
909
910 for (i=0;i<7;i++) {
911 vector = readl(baseaddr+vmevec[i]);
912 if (stat & vmeirqbit[i] & enable) {
913 if (vmeirqs[i] != NULL) {
914 vmeirqs[i](i+1, vector, dev_id, regs);
915 }
916 }
917 }
918
919 writel(stat, baseaddr+LINT_STAT); // Clear all pending ints
920 }
921
922 //-----------------------------------------------------------------------------
923 // Function : cleanup_module
924 // Inputs : void
925 // Outputs : void
926 // Description:
927 // Remarks :
928 // History :
929 //-----------------------------------------------------------------------------
930 void cleanup_module(void)
931 {
932 int x;
933 int pcivector;
934
935 writel(0,baseaddr+LINT_EN); // Turn off Ints
936 pcivector = readl(baseaddr+PCI_MISC1) & 0x000000FF;
937 free_irq(pcivector,NULL); // Free Vector
938
939 for (x=1;x<MAX_MINOR+1;x++) {
940 if (image_ba[x])
941 iounmap(image_ba[x]);
942 }
943 iounmap(baseaddr);
944 unregister_proc();
945 unregister_chrdev(UNI_MAJOR, "uni");
946 }
947
948 //----------------------------------------------------------------------------
949 // init_module()
950 //----------------------------------------------------------------------------
951 int init_module(void)
952 {
953 int x, result;
954 unsigned int temp, ba;
955 char vstr[80];
956
957 struct pci_dev *uni_pci_dev = NULL;
958
959 sprintf(vstr,"Tundra Universe PCI-VME Bridge Driver %s\n",Version);
960 printk(vstr);
961 printk(" Copyright 1997-2002, Michael J. Wyrick\n");
962
963 if ((uni_pci_dev = pci_find_device(PCI_VENDOR_ID_TUNDRA,
964 PCI_DEVICE_ID_TUNDRA_CA91C042,
965 uni_pci_dev))) {
966 printk(" Universe device found.");
967
968 // Lets turn Latency off
969 pci_write_config_dword(uni_pci_dev, PCI_MISC0, 0);
970
971 // Display PCI Registers
972 pci_read_config_dword(uni_pci_dev, PCI_CSR, &status);
973 printk(" Vendor = %04X Device = %04X Status = %08X\n",
974 uni_pci_dev->vendor,uni_pci_dev->device,status);
975
976 // Setup Universe Config Space
977 // This is a 4k wide memory area that need to be mapped into the kernel
978 // virtual memory space so we can access it.
979 pci_write_config_dword(uni_pci_dev, PCI_BS, CONFIG_REG_SPACE);
980 pci_read_config_dword(uni_pci_dev, PCI_BS, &ba);
981 baseaddr = (char *)ioremap(ba,4096);
982 if (!baseaddr) {
983 printk(" vremap failed to map Universe to Kernel Space.\r");
984 return 1;
985 }
986
987 // Check to see if the Mapping Worked out
988 temp = readl(baseaddr);
989 printk(" Read via mapping, PCI_ID = %08X\n",temp);
990 if (temp != 0x000010E3) {
991 printk(" Universe Chip Failed to Return PCI_ID in Memory Map.\n");
992 return 1;
993 }
994
995 printk(" Class = %08X\n",readl(baseaddr+PCI_CLASS));
996 printk(" Misc0 = %08X\n",readl(baseaddr+PCI_MISC0));
997
998 // Determine What Chip We have
999 temp = readl(baseaddr + PCI_CLASS);
1000 ChipType = temp & 0x000000FF;
1001 switch (ChipType) {
1002 case UNIVERSEI : printk(" Found Universe I\n"); break;
1003 case UNIVERSEII : printk(" Found Universe II\n"); break;
1004 case UNIVERSEIIB : printk(" Found Universe IIB/D\n"); break;
1005 default : printk(" Unknown Universe\n"); break;
1006 }
1007
1008 // OK, Every this is ok so lets turn off the windows
1009 writel(0x00800000,baseaddr+LSI0_CTL);
1010 writel(0x00800000,baseaddr+LSI1_CTL);
1011 writel(0x00800000,baseaddr+LSI2_CTL);
1012 writel(0x00800000,baseaddr+LSI3_CTL);
1013
1014 // Write to Misc Register
1015 // Set VME Bus Time-out
1016 // Arbitration Mode
1017 // DTACK Enable
1018 writel(0x15060000,baseaddr+MISC_CTL);
1019
1020 if (UNIVERSEIIFUNC) {
1021 printk(" U2SPEC = %08X\n", readl(baseaddr+U2SPEC));
1022 }
1023
1024 // Lets turn off interrupts
1025 writel(0x00000000,baseaddr+LINT_EN); // Disable interrupts in the Universe first
1026 writel(0x0000FFFF,baseaddr+LINT_STAT); // Clear Any Pending Interrupts
1027
1028 pci_read_config_dword(uni_pci_dev, PCI_INTERRUPT_LINE, &irq);
1029 irq &= 0x000000FF; // Only a byte in size
1030 result = request_irq(irq, irq_handler, SA_INTERRUPT, "VMEBus (ca91c042)", NULL);
1031 if (result) {
1032 printk(" ca91c042: can't get assigned pci irq vector %02X\n", irq);
1033 } else {
1034 writel(0x0000, baseaddr+LINT_MAP0); // Map all ints to 0
1035 writel(0x0000, baseaddr+LINT_MAP1); // Map all ints to 0
1036 }
1037
1038 } else {
1039 printk(" Universe device not found on PCI Bus.\n");
1040 return 1;
1041 }
1042
1043 if (register_chrdev(UNI_MAJOR, "uni", &uni_fops)) {
1044 printk(" Error getting Major Number for Drivers\n");
1045 iounmap(baseaddr);
1046 return(1);
1047 } else {
1048 printk(" Tundra Loaded.\n");
1049 }
1050
1051 register_proc();
1052
1053 for (x=0;x<MAX_MINOR+1;x++) {
1054 image_ba[x] = 0; // Not defined
1055 image_ptr[x] = 0; // Not defined
1056 opened[x] = 0; // Closed
1057 OkToWrite[x] = 0; // Not OK
1058 mode[x] = MODE_UNDEFINED; // Undefined
1059 }
1060
1061 // Setup the DMA Timer
1062 init_timer(&DMA_timer);
1063 DMA_timer.function = DMA_status;
1064
1065 // Enable DMA Interrupts
1066 writel(0x0700, baseaddr+LINT_EN);
1067
1068 return 0;
1069 }
1070
1071 //-----------------------------------------------------------------------------
1072 //
1073 // Public Interface
1074 //
1075 //-----------------------------------------------------------------------------
1076 //-----------------------------------------------------------------------------
1077 // Function : Universe_BaseAddr
1078 // Inputs : void
1079 // Outputs : char*
1080 // Description: Returns the Base Address of the Universe
1081 // Remarks : Used for direct access to the Universe for unsupported functions
1082 // History :
1083 //-----------------------------------------------------------------------------
1084 char* Universe_BaseAddr(void)
1085 {
1086 return baseaddr;
1087 }
1088
1089 //-----------------------------------------------------------------------------
1090 // Function : Universe_IRQ
1091 // Inputs : void
1092 // Outputs : int
1093 // Description: Returns the PCI IRQ that the Universe is on
1094 // Remarks : Used mostly for Status and Debugging
1095 // History :
1096 //-----------------------------------------------------------------------------
1097 int Universe_IRQ(void)
1098 {
1099 return irq;
1100 }
1101
1102 //-----------------------------------------------------------------------------
1103 // Function : enable_vmeirq
1104 // Inputs : int irq
1105 // Outputs : int
1106 // Description: Enable a VME IRQ
1107 // Remarks :
1108 // History :
1109 //-----------------------------------------------------------------------------
1110 void enable_vmeirq(unsigned int irq)
1111 {
1112 int enable;
1113
1114 enable = readl(baseaddr+LINT_EN);
1115 enable |= vmeirqbit[irq-1];
1116 writel(enable, baseaddr+LINT_EN);
1117 }
1118
1119 //-----------------------------------------------------------------------------
1120 // Function : disable_vmeirq
1121 // Inputs : unsigned int irq
1122 // Outputs : void
1123 // Description: Disable a VME IRQ
1124 // Remarks :
1125 // History :
1126 //-----------------------------------------------------------------------------
1127 void disable_vmeirq(unsigned int irq)
1128 {
1129 int enable;
1130
1131 enable = readl(baseaddr+LINT_EN);
1132 enable &= ~vmeirqbit[irq-1];
1133 writel(enable, baseaddr+LINT_EN);
1134 }
1135
1136 //-----------------------------------------------------------------------------
1137 // Function : request_vmeirq
1138 // Inputs : unsigned int irq, TirqHandler handler
1139 // Outputs : int, 0 if successful
1140 // Description: assign a handler to a vme interrupt
1141 // Remarks : uses a simple check to see if the interrupt is free, then
1142 // assigns a handler for the Interrupt
1143 // History :
1144 //-----------------------------------------------------------------------------
1145 int request_vmeirq(unsigned int irq, TirqHandler handler)
1146 {
1147 if ((irq >= 1) && (irq <= 7)) {
1148 if (vmeirqs[irq-1] == NULL) {
1149 vmeirqs[irq-1] = handler;
1150 return 0;
1151 }
1152 }
1153 return -1; // IRQ is already assigned or invalid
1154 }
1155
1156 //-----------------------------------------------------------------------------
1157 // Function : free_vmeirq
1158 // Inputs : unsigned int irq
1159 // Outputs : void
1160 // Description: release the vmeirq
1161 // Remarks : This does not check that a module is freeing an interrupt it
1162 // owns. It is up to the programmer to make sure he knows what
1163 // what he is doing
1164 // History :
1165 //-----------------------------------------------------------------------------
1166 void free_vmeirq(unsigned int irq)
1167 {
1168 if ((irq >= 1) && (irq <= 7))
1169 vmeirqs[irq-1] = NULL;
1170 }
1171
1172 //-----------------------------------------------------------------------------
1173 // Function : mapvme
1174 // Inputs : unsigned int pci - PCI Address of Image Map (See howto)
1175 // unsigned int vme - VME Address of Image (See howto)
1176 // unsigned int size - Size of Image
1177 // int image - Image Number to Use (See howto)
1178 // int ctl - VME Address Space (See howto)
1179 // Outputs : char*
1180 // Description:
1181 // Remarks :
1182 // History :
1183 //-----------------------------------------------------------------------------
1184 char* mapvme(unsigned int pci,unsigned int vme, unsigned int size,
1185 int image, int ctl)
1186 {
1187 char *ptr;
1188 unsigned int to;
1189
1190 if ((image >=0) && (image <=3)) {
1191 if ((pci >= 0xB0000000) && (pci <= 0xE0000000)) {
1192 to = vme-pci;
1193 // Setup the Mapping in the Universe
1194 writel(pci, baseaddr + aBS[image]);
1195 writel(pci + size, baseaddr + aBD[image]);
1196 writel(to, baseaddr + aTO[image]);
1197 writel(ctl | 0x80000000, baseaddr + aCTL[image]);
1198
1199 // Get the Virtual address of the PCI Address map
1200 ptr = (char *)ioremap(pci,size);
1201 if (ptr == NULL) {
1202 printk("<ca91c042> ioremap failed in mapvme\n");
1203 return NULL;
1204 } else {
1205 return ptr; // Everything went ok, return the address pointer
1206 }
1207 }
1208 }
1209 return NULL;
1210 }
1211
1212 //-----------------------------------------------------------------------------
1213 // Function : unmapvme
1214 // Inputs : char *ptr, int image
1215 // Outputs : void
1216 // Description:
1217 // Remarks :
1218 // History :
1219 //-----------------------------------------------------------------------------
1220 void unmapvme(char *ptr, int image)
1221 {
1222 if ((image >= 0) && (image <=3)) {
1223 // Clear the Mapping in the Universe
1224 writel(0x00000000, baseaddr + aCTL[image]);
1225 writel(0x00000000, baseaddr + aBS[image]);
1226 writel(0x00000000, baseaddr + aBD[image]);
1227 writel(0x00000000, baseaddr + aTO[image]);
1228 }
1229
1230 // Clear Mapping of PCI Memory
1231 iounmap(ptr);
1232 }
1233
1234 //-----------------------------------------------------------------------------
1235 // Function : VME_DMA
1236 // Inputs : unsigned int pci - PCI Address of Image Map (See howto)
1237 // unsigned int vme - VME Address of Image (See howto)
1238 // unsigned int count - Size of Image
1239 // int image - Image Number to Use (See howto)
1240 // int ctl - VME Address Space (See howto)
1241 // Outputs : void
1242 // Description:
1243 // Remarks : This is Like the CMD Packet Version but will do only one transfer
1244 // History :
1245 //-----------------------------------------------------------------------------
1246 void VME_DMA(void* pci, void* vme, unsigned int count, int ctl, TDMAcallback cback)
1247 {
1248 #ifdef __DEBUG__
1249 char buf[256];
1250 sprintf(buf,"<<ca91c042>> DMA Request of virtpci=0x%08X vme=0x%08X cnt=%i ctl=0x%08X\n",
1251 pci,vme,count,ctl);
1252 printk(buf);
1253 #endif
1254
1255 // Setup the DMA Transfer in the Universe
1256 writel(ctl, baseaddr + DCTL);
1257 writel(count, baseaddr + DTBC);
1258 writel(virt_to_bus(pci), baseaddr + DLA);
1259 writel((int)vme, baseaddr + DVA);
1260
1261 // We need to build a timer to timeout DMA access
1262 DMA_timer.expires = jiffies + DMATIMEOUT;
1263 add_timer(&DMA_timer);
1264
1265 // Setup CallBack Function
1266 DMACallBackFunc = cback;
1267
1268 // Start the Transfer,
1269 // Interrupt on Stop,Halt,Done,LERR,VERR,Prot Error
1270 DMAType = DMATYPE_SINGLE;
1271 writel(0x80216F6F,baseaddr+DGCS);
1272
1273 // We are now all setup, so lets return to the calling function so it can
1274 // sleep or what ever until the DMA is done
1275 }
1276
1277 //-----------------------------------------------------------------------------
1278 // Function : VME_DMA_LinkedList
1279 // Inputs : void* CmdPacketList,TDMAcallback cback
1280 // Outputs : int
1281 // Description:
1282 // Remarks : CmdPacketList is a Phys Address
1283 // History :
1284 //-----------------------------------------------------------------------------
1285 void VME_DMA_LinkedList(void* CmdPacketList,TDMAcallback cback)
1286 {
1287 debugptr = CmdPacketList;
1288
1289 // Setup a DMA Transfer and once the Transfer is complete call cback
1290 writel(0x08316F00,baseaddr+DGCS);
1291 writel(0x00000000,baseaddr+DTBC);
1292 writel((int)CmdPacketList,baseaddr+DCPP); // Command Packet Pointer
1293
1294 // We need to build a timer to timeout DMA access
1295 DMA_timer.expires = jiffies + DMATIMEOUT;
1296 add_timer(&DMA_timer);
1297
1298 // Setup CallBack Function
1299 DMACallBackFunc = cback;
1300
1301 // Start the Transfer,
1302 // Interrupt on Stop,Halt,Done,LERR,VERR,Prot Error
1303 DMAType = DMATYPE_LLIST;
1304 writel(0x88216F6F,baseaddr+DGCS);
1305
1306 // We are now all setup, so lets return to the calling function so it can
1307 // sleep or what ever until the DMA is done
1308 }
1309
1310 //-----------------------------------------------------------------------------
1311 // Function : VME_Bus_Error
1312 // Inputs :
1313 // Outputs :
1314 // Description: Returns 1 if a Bus Error is Pending
1315 // Remarks :
1316 // History : 10/30/2000 mjw Started
1317 //-------------------------------------------------------------------------mjw-
1318 int VME_Bus_Error(void)
1319 {
1320 int pci_csr;
1321
1322 pci_csr = readl(baseaddr+PCI_CSR); // Check for Bus Error
1323 writel(pci_csr,baseaddr+PCI_CSR); // Clear the Error
1324 return((pci_csr & 0x08000000) ? 1 : 0);
1325 }
1326

  ViewVC Help
Powered by ViewVC 1.2-dev