2 * VMEbus User access driver
4 * Author: Martyn Welch <martyn.welch@gefanuc.com>
5 * Copyright 2008 GE Fanuc Intelligent Platforms Embedded Systems, Inc.
8 * Tom Armistead and Ajit Prem
9 * Copyright 2004 Motorola Inc.
12 * This program is free software; you can redistribute it and/or modify it
13 * under the terms of the GNU General Public License as published by the
14 * Free Software Foundation; either version 2 of the License, or (at your
15 * option) any later version.
18 #include <linux/cdev.h>
19 #include <linux/delay.h>
20 #include <linux/device.h>
21 #include <linux/dma-mapping.h>
22 #include <linux/errno.h>
23 #include <linux/init.h>
24 #include <linux/ioctl.h>
25 #include <linux/kernel.h>
27 #include <linux/module.h>
28 #include <linux/pagemap.h>
29 #include <linux/pci.h>
30 #include <linux/semaphore.h>
31 #include <linux/spinlock.h>
32 #include <linux/syscalls.h>
33 #include <linux/types.h>
34 #include <linux/version.h>
37 #include <asm/uaccess.h>
42 /* Currently Documentation/devices.txt defines the following for VME:
45 * 0 = /dev/bus/vme/m0 First master image
46 * 1 = /dev/bus/vme/m1 Second master image
47 * 2 = /dev/bus/vme/m2 Third master image
48 * 3 = /dev/bus/vme/m3 Fourth master image
49 * 4 = /dev/bus/vme/s0 First slave image
50 * 5 = /dev/bus/vme/s1 Second slave image
51 * 6 = /dev/bus/vme/s2 Third slave image
52 * 7 = /dev/bus/vme/s3 Fourth slave image
53 * 8 = /dev/bus/vme/ctl Control
55 * It is expected that all VME bus drivers will use the
56 * same interface. For interface documentation see
57 * http://www.vmelinux.org/.
59 * However the VME driver at http://www.vmelinux.org/ is rather old and doesn't
60 * even support the tsi148 chipset (which has 8 master and 8 slave windows).
61 * We'll run with this or now as far as possible, however it probably makes
62 * sense to get rid of the old mappings and just do everything dynamically.
64 * So for now, we'll restrict the driver to providing 4 masters and 4 slaves as
65 * defined above and try to support at least some of the interface from
66 * http://www.vmelinux.org/ as an alternative drive can be written providing a
67 * saner interface later.
69 #define VME_MAJOR 221 /* VME Major Device Number */
70 #define VME_DEVS 9 /* Number of dev entries */
72 #define MASTER_MINOR 0
76 #define CONTROL_MINOR 8
78 #define PCI_BUF_SIZE 0x20000 /* Size of one slave image buffer */
81 * Structure to handle image related parameters.
84 void __iomem
*kern_buf
; /* Buffer address in kernel space */
85 dma_addr_t pci_buf
; /* Buffer address in PCI address space */
86 unsigned long long size_buf
; /* Buffer size */
87 struct semaphore sem
; /* Semaphore for locking image */
88 struct device
*device
; /* Sysfs device */
89 struct vme_resource
*resource
; /* VME resource */
90 int users
; /* Number of current users */
92 static image_desc_t image
[VME_DEVS
];
100 unsigned long dmaErrors
;
101 unsigned long timeouts
;
102 unsigned long external
;
104 static driver_stats_t statistics
;
106 struct cdev
*vme_user_cdev
; /* Character device */
107 struct class *vme_user_sysfs_class
; /* Sysfs class */
108 struct device
*vme_user_bridge
; /* Pointer to the bridge device */
110 static char driver_name
[] = "vme_user";
112 static const int type
[VME_DEVS
] = { MASTER_MINOR
, MASTER_MINOR
,
113 MASTER_MINOR
, MASTER_MINOR
,
114 SLAVE_MINOR
, SLAVE_MINOR
,
115 SLAVE_MINOR
, SLAVE_MINOR
,
120 static int vme_user_open(struct inode
*, struct file
*);
121 static int vme_user_release(struct inode
*, struct file
*);
122 static ssize_t
vme_user_read(struct file
*, char *, size_t, loff_t
*);
123 static ssize_t
vme_user_write(struct file
*, const char *, size_t, loff_t
*);
124 static loff_t
vme_user_llseek(struct file
*, loff_t
, int);
125 static int vme_user_ioctl(struct inode
*, struct file
*, unsigned int,
128 static int __init
vme_user_probe(struct device
*dev
);
130 static struct file_operations vme_user_fops
= {
131 .open
= vme_user_open
,
132 .release
= vme_user_release
,
133 .read
= vme_user_read
,
134 .write
= vme_user_write
,
135 .llseek
= vme_user_llseek
,
136 .ioctl
= vme_user_ioctl
,
141 * Reset all the statistic counters
143 static void reset_counters(void)
145 statistics
.reads
= 0;
146 statistics
.writes
= 0;
147 statistics
.ioctls
= 0;
149 statistics
.berrs
= 0;
150 statistics
.dmaErrors
= 0;
151 statistics
.timeouts
= 0;
154 void lmcall(int monitor
)
156 printk("Caught Location Monitor %d access\n", monitor
);
159 static void tests(void)
161 struct vme_resource
*dma_res
;
162 struct vme_dma_list
*dma_list
;
163 struct vme_dma_attr
*pattern_attr
, *vme_attr
;
168 printk("Running VME DMA test\n");
169 dma_res
= vme_request_dma(vme_user_bridge
);
170 dma_list
= vme_new_dma_list(dma_res
);
171 pattern_attr
= vme_dma_pattern_attribute(0x0,
172 VME_DMA_PATTERN_WORD
|
173 VME_DMA_PATTERN_INCREMENT
);
174 vme_attr
= vme_dma_vme_attribute(0x10000, VME_A32
,
176 retval
= vme_dma_list_add(dma_list
, pattern_attr
,
179 vme_dma_free_attribute(vme_attr
);
180 vme_attr
= vme_dma_vme_attribute(0x20000, VME_A32
,
182 retval
= vme_dma_list_add(dma_list
, pattern_attr
,
185 retval
= vme_dma_list_exec(dma_list
);
186 vme_dma_free_attribute(pattern_attr
);
187 vme_dma_free_attribute(vme_attr
);
188 vme_dma_list_free(dma_list
);
190 printk("Generating a VME interrupt\n");
191 vme_generate_irq(dma_res
, 0x3, 0xaa);
192 printk("Interrupt returned\n");
194 vme_dma_free(dma_res
);
197 data
= vme_master_rmw(image
[0].resource
, 0x80000000, 0x00000000,
199 printk("RMW returned 0x%8.8x\n", data
);
202 /* Location Monitor */
203 printk("vme_lm_set:%d\n", vme_lm_set(vme_user_bridge
, 0x60000, VME_A32
, VME_SCT
| VME_USER
| VME_DATA
));
204 printk("vme_lm_attach:%d\n", vme_lm_attach(vme_user_bridge
, 0, lmcall
));
206 printk("Board in VME slot:%d\n", vme_slot_get(vme_user_bridge
));
209 static int vme_user_open(struct inode
*inode
, struct file
*file
)
212 unsigned int minor
= MINOR(inode
->i_rdev
);
214 down(&image
[minor
].sem
);
215 /* Only allow device to be opened if a resource is allocated */
216 if (image
[minor
].resource
== NULL
) {
217 printk(KERN_ERR
"No resources allocated for device\n");
222 /* Increment user count */
223 image
[minor
].users
++;
225 up(&image
[minor
].sem
);
230 up(&image
[minor
].sem
);
235 static int vme_user_release(struct inode
*inode
, struct file
*file
)
237 unsigned int minor
= MINOR(inode
->i_rdev
);
239 down(&image
[minor
].sem
);
241 /* Decrement user count */
242 image
[minor
].users
--;
244 up(&image
[minor
].sem
);
250 * We are going ot alloc a page during init per window for small transfers.
251 * Small transfers will go VME -> buffer -> user space. Larger (more than a
252 * page) transfers will lock the user space buffer into memory and then
253 * transfer the data directly into the user space buffers.
255 static ssize_t
resource_to_user(int minor
, char __user
*buf
, size_t count
,
261 if (count
<= image
[minor
].size_buf
) {
262 /* We copy to kernel buffer */
263 copied
= vme_master_read(image
[minor
].resource
,
264 image
[minor
].kern_buf
, count
, *ppos
);
269 retval
= __copy_to_user(buf
, image
[minor
].kern_buf
,
270 (unsigned long)copied
);
272 copied
= (copied
- retval
);
273 printk("User copy failed\n");
278 /* XXX Need to write this */
279 printk("Currently don't support large transfers\n");
280 /* Map in pages from userspace */
282 /* Call vme_master_read to do the transfer */
290 * We are going ot alloc a page during init per window for small transfers.
291 * Small transfers will go user space -> buffer -> VME. Larger (more than a
292 * page) transfers will lock the user space buffer into memory and then
293 * transfer the data directly from the user space buffers out to VME.
295 static ssize_t
resource_from_user(unsigned int minor
, const char *buf
,
296 size_t count
, loff_t
*ppos
)
301 if (count
<= image
[minor
].size_buf
) {
302 retval
= __copy_from_user(image
[minor
].kern_buf
, buf
,
303 (unsigned long)count
);
305 copied
= (copied
- retval
);
309 copied
= vme_master_write(image
[minor
].resource
,
310 image
[minor
].kern_buf
, copied
, *ppos
);
312 /* XXX Need to write this */
313 printk("Currently don't support large transfers\n");
314 /* Map in pages from userspace */
316 /* Call vme_master_write to do the transfer */
323 static ssize_t
buffer_to_user(unsigned int minor
, char __user
*buf
,
324 size_t count
, loff_t
*ppos
)
326 void __iomem
*image_ptr
;
329 image_ptr
= image
[minor
].kern_buf
+ *ppos
;
331 retval
= __copy_to_user(buf
, image_ptr
, (unsigned long)count
);
333 retval
= (count
- retval
);
334 printk(KERN_WARNING
"Partial copy to userspace\n");
338 /* Return number of bytes successfully read */
342 static ssize_t
buffer_from_user(unsigned int minor
, const char *buf
,
343 size_t count
, loff_t
*ppos
)
345 void __iomem
*image_ptr
;
348 image_ptr
= image
[minor
].kern_buf
+ *ppos
;
350 retval
= __copy_from_user(image_ptr
, buf
, (unsigned long)count
);
352 retval
= (count
- retval
);
353 printk(KERN_WARNING
"Partial copy to userspace\n");
357 /* Return number of bytes successfully read */
361 static ssize_t
vme_user_read(struct file
*file
, char *buf
, size_t count
,
364 unsigned int minor
= MINOR(file
->f_dentry
->d_inode
->i_rdev
);
369 down(&image
[minor
].sem
);
371 /* XXX Do we *really* want this helper - we can use vme_*_get ? */
372 image_size
= vme_get_size(image
[minor
].resource
);
374 /* Ensure we are starting at a valid location */
375 if ((*ppos
< 0) || (*ppos
> (image_size
- 1))) {
376 up(&image
[minor
].sem
);
380 /* Ensure not reading past end of the image */
381 if (*ppos
+ count
> image_size
)
382 okcount
= image_size
- *ppos
;
386 switch (type
[minor
]){
388 retval
= resource_to_user(minor
, buf
, okcount
, ppos
);
391 retval
= buffer_to_user(minor
, buf
, okcount
, ppos
);
397 up(&image
[minor
].sem
);
405 static ssize_t
vme_user_write(struct file
*file
, const char *buf
, size_t count
,
408 unsigned int minor
= MINOR(file
->f_dentry
->d_inode
->i_rdev
);
413 down(&image
[minor
].sem
);
415 image_size
= vme_get_size(image
[minor
].resource
);
417 /* Ensure we are starting at a valid location */
418 if ((*ppos
< 0) || (*ppos
> (image_size
- 1))) {
419 up(&image
[minor
].sem
);
423 /* Ensure not reading past end of the image */
424 if (*ppos
+ count
> image_size
)
425 okcount
= image_size
- *ppos
;
429 switch (type
[minor
]){
431 retval
= resource_from_user(minor
, buf
, okcount
, ppos
);
434 retval
= buffer_from_user(minor
, buf
, okcount
, ppos
);
440 up(&image
[minor
].sem
);
448 static loff_t
vme_user_llseek(struct file
*file
, loff_t off
, int whence
)
450 printk(KERN_ERR
"Llseek currently incomplete\n");
454 static int vme_user_ioctl(struct inode
*inode
, struct file
*file
,
455 unsigned int cmd
, unsigned long arg
)
457 unsigned int minor
= MINOR(inode
->i_rdev
);
461 unsigned long copyRet
;
465 switch (type
[minor
]) {
474 copyRet
= copy_from_user(&slave
, (char *)arg
,
477 printk(KERN_WARNING
"Partial copy from "
482 return vme_slave_set(image
[minor
].resource
,
483 slave
.enable
, slave
.vme_addr
, slave
.size
,
484 image
[minor
].pci_buf
, slave
.aspace
,
492 ret_val
= vme_slave_get(minor
, &iRegs
);
494 copyRet
= copy_to_user((char *)arg
, &slave
,
497 printk(KERN_WARNING
"Partial copy to "
514 * Unallocate a previously allocated buffer
516 static void buf_unalloc (int num
)
518 if (image
[num
].kern_buf
) {
520 printk(KERN_DEBUG
"UniverseII:Releasing buffer at %p\n",
524 vme_free_consistent(image
[num
].resource
, image
[num
].size_buf
,
525 image
[num
].kern_buf
, image
[num
].pci_buf
);
527 image
[num
].kern_buf
= NULL
;
528 image
[num
].pci_buf
= 0;
529 image
[num
].size_buf
= 0;
533 printk(KERN_DEBUG
"UniverseII: Buffer not allocated\n");
538 static struct vme_driver vme_user_driver
= {
540 .probe
= vme_user_probe
,
545 * In this simple access driver, the old behaviour is being preserved as much
546 * as practical. We will therefore reserve the buffers and request the images
547 * here so that we don't have to do it later.
549 static int __init
vme_bridge_init(void)
552 printk(KERN_INFO
"VME User Space Access Driver\n");
553 printk("vme_user_driver:%p\n", &vme_user_driver
);
554 retval
= vme_register_driver(&vme_user_driver
);
555 printk("vme_register_driver returned %d\n", retval
);
560 * This structure gets passed a device, this should be the device created at
563 static int __init
vme_user_probe(struct device
*dev
)
568 printk("Running vme_user_probe()\n");
570 /* Pointer to the bridge device */
571 vme_user_bridge
= dev
;
573 /* Initialise descriptors */
574 for (i
= 0; i
< VME_DEVS
; i
++) {
575 image
[i
].kern_buf
= NULL
;
576 image
[i
].pci_buf
= 0;
577 init_MUTEX(&(image
[i
].sem
));
578 image
[i
].device
= NULL
;
579 image
[i
].resource
= NULL
;
583 /* Initialise statistics counters */
586 /* Assign major and minor numbers for the driver */
587 err
= register_chrdev_region(MKDEV(VME_MAJOR
, 0), VME_DEVS
,
590 printk(KERN_WARNING
"%s: Error getting Major Number %d for "
591 "driver.\n", driver_name
, VME_MAJOR
);
595 /* Register the driver as a char device */
596 vme_user_cdev
= cdev_alloc();
597 vme_user_cdev
->ops
= &vme_user_fops
;
598 vme_user_cdev
->owner
= THIS_MODULE
;
599 err
= cdev_add(vme_user_cdev
, MKDEV(VME_MAJOR
, 0), VME_DEVS
);
601 printk(KERN_WARNING
"%s: cdev_all failed\n", driver_name
);
605 /* Request slave resources and allocate buffers (128kB wide) */
606 for (i
= SLAVE_MINOR
; i
< (SLAVE_MAX
+ 1); i
++) {
607 /* XXX Need to properly request attributes */
608 image
[i
].resource
= vme_slave_request(vme_user_bridge
,
610 if (image
[i
].resource
== NULL
) {
611 printk(KERN_WARNING
"Unable to allocate slave "
615 image
[i
].size_buf
= PCI_BUF_SIZE
;
616 image
[i
].kern_buf
= vme_alloc_consistent(image
[i
].resource
,
617 image
[i
].size_buf
, &(image
[i
].pci_buf
));
618 if (image
[i
].kern_buf
== NULL
) {
619 printk(KERN_WARNING
"Unable to allocate memory for "
621 image
[i
].pci_buf
= 0;
622 vme_slave_free(image
[i
].resource
);
629 * Request master resources allocate page sized buffers for small
632 for (i
= MASTER_MINOR
; i
< (MASTER_MAX
+ 1); i
++) {
633 /* XXX Need to properly request attributes */
634 image
[i
].resource
= vme_master_request(vme_user_bridge
,
635 VME_A32
, VME_SCT
, VME_D32
);
636 if (image
[i
].resource
== NULL
) {
637 printk(KERN_WARNING
"Unable to allocate master "
641 image
[i
].size_buf
= PAGE_SIZE
;
642 image
[i
].kern_buf
= vme_alloc_consistent(image
[i
].resource
,
643 image
[i
].size_buf
, &(image
[i
].pci_buf
));
644 if (image
[i
].kern_buf
== NULL
) {
645 printk(KERN_WARNING
"Unable to allocate memory for "
647 image
[i
].pci_buf
= 0;
648 vme_master_free(image
[i
].resource
);
654 /* Setup some debug windows */
655 for (i
= SLAVE_MINOR
; i
< (SLAVE_MAX
+ 1); i
++) {
656 err
= vme_slave_set(image
[i
].resource
, 1, 0x4000*(i
-4),
657 0x4000, image
[i
].pci_buf
, VME_A16
,
658 VME_SCT
| VME_SUPER
| VME_USER
| VME_PROG
| VME_DATA
);
660 printk(KERN_WARNING
"Failed to configure window\n");
664 for (i
= MASTER_MINOR
; i
< (MASTER_MAX
+ 1); i
++) {
665 err
= vme_master_set(image
[i
].resource
, 1,
666 (0x10000 + (0x10000*i
)), 0x10000,
667 VME_A32
, VME_SCT
| VME_USER
| VME_DATA
, VME_D32
);
669 printk(KERN_WARNING
"Failed to configure window\n");
674 /* Create sysfs entries - on udev systems this creates the dev files */
675 vme_user_sysfs_class
= class_create(THIS_MODULE
, driver_name
);
676 if (IS_ERR(vme_user_sysfs_class
)) {
677 printk(KERN_ERR
"Error creating vme_user class.\n");
678 err
= PTR_ERR(vme_user_sysfs_class
);
682 /* Add sysfs Entries */
683 for (i
=0; i
<VME_DEVS
; i
++) {
686 sprintf(name
,"bus/vme/m%%d");
689 sprintf(name
,"bus/vme/ctl");
692 sprintf(name
,"bus/vme/s%%d");
701 device_create(vme_user_sysfs_class
, NULL
,
702 MKDEV(VME_MAJOR
, i
), NULL
, name
,
703 (type
[i
] == SLAVE_MINOR
)? i
- (MASTER_MAX
+ 1) : i
);
704 if (IS_ERR(image
[i
].device
)) {
705 printk("%s: Error creating sysfs device\n",
707 err
= PTR_ERR(image
[i
].device
);
719 /* Ensure counter set correcty to destroy all sysfs devices */
724 device_destroy(vme_user_sysfs_class
, MKDEV(VME_MAJOR
, i
));
726 class_destroy(vme_user_sysfs_class
);
728 /* Ensure counter set correcty to unalloc all slave buffers */
731 while (i
> SLAVE_MINOR
){
733 vme_slave_set(image
[i
].resource
, 0, 0, 0, 0, VME_A32
, 0);
734 vme_slave_free(image
[i
].resource
);
738 cdev_del(vme_user_cdev
);
740 unregister_chrdev_region(MKDEV(VME_MAJOR
, 0), VME_DEVS
);
745 static void __exit
vme_bridge_exit(void)
749 /* Remove sysfs Entries */
750 for(i
=0; i
<VME_DEVS
; i
++) {
751 device_destroy(vme_user_sysfs_class
, MKDEV(VME_MAJOR
, i
));
753 class_destroy(vme_user_sysfs_class
);
755 for (i
= SLAVE_MINOR
; i
< (SLAVE_MAX
+ 1); i
++) {
759 /* Unregister device driver */
760 cdev_del(vme_user_cdev
);
762 /* Unregiser the major and minor device numbers */
763 unregister_chrdev_region(MKDEV(VME_MAJOR
, 0), VME_DEVS
);
766 MODULE_DESCRIPTION("VME User Space Access Driver");
767 MODULE_AUTHOR("Martyn Welch <martyn.welch@gefanuc.com");
768 MODULE_LICENSE("GPL");
770 module_init(vme_bridge_init
);
771 module_exit(vme_bridge_exit
);