diff options
Diffstat (limited to 'drivers/staging/vme')
-rw-r--r-- | drivers/staging/vme/boards/vme_vmivme7805.c | 4 | ||||
-rw-r--r-- | drivers/staging/vme/bridges/vme_ca91cx42.c | 43 | ||||
-rw-r--r-- | drivers/staging/vme/bridges/vme_tsi148.c | 26 | ||||
-rw-r--r-- | drivers/staging/vme/devices/vme_user.c | 122 | ||||
-rw-r--r-- | drivers/staging/vme/devices/vme_user.h | 8 | ||||
-rw-r--r-- | drivers/staging/vme/vme.c | 349 | ||||
-rw-r--r-- | drivers/staging/vme/vme.h | 52 | ||||
-rw-r--r-- | drivers/staging/vme/vme_api.txt | 90 | ||||
-rw-r--r-- | drivers/staging/vme/vme_bridge.h | 17 |
9 files changed, 413 insertions, 298 deletions
diff --git a/drivers/staging/vme/boards/vme_vmivme7805.c b/drivers/staging/vme/boards/vme_vmivme7805.c index 80eaa0c..8e05bb4 100644 --- a/drivers/staging/vme/boards/vme_vmivme7805.c +++ b/drivers/staging/vme/boards/vme_vmivme7805.c @@ -27,9 +27,9 @@ static void __exit vmic_exit(void); /** Base address to access FPGA register */ static void *vmic_base; -static char driver_name[] = "vmivme_7805"; +static const char driver_name[] = "vmivme_7805"; -static struct pci_device_id vmic_ids[] = { +static DEFINE_PCI_DEVICE_TABLE(vmic_ids) = { { PCI_DEVICE(PCI_VENDOR_ID_VMIC, PCI_DEVICE_ID_VTIMR) }, { }, }; diff --git a/drivers/staging/vme/bridges/vme_ca91cx42.c b/drivers/staging/vme/bridges/vme_ca91cx42.c index a400728..0e4feac 100644 --- a/drivers/staging/vme/bridges/vme_ca91cx42.c +++ b/drivers/staging/vme/bridges/vme_ca91cx42.c @@ -42,7 +42,7 @@ static void __exit ca91cx42_exit(void); /* Module parameters */ static int geoid; -static char driver_name[] = "vme_ca91cx42"; +static const char driver_name[] = "vme_ca91cx42"; static DEFINE_PCI_DEVICE_TABLE(ca91cx42_ids) = { { PCI_DEVICE(PCI_VENDOR_ID_TUNDRA, PCI_DEVICE_ID_TUNDRA_CA91C142) }, @@ -190,7 +190,7 @@ static irqreturn_t ca91cx42_irqhandler(int irq, void *ptr) serviced |= ca91cx42_VIRQ_irqhandler(ca91cx42_bridge, stat); /* Clear serviced interrupts */ - iowrite32(stat, bridge->base + LINT_STAT); + iowrite32(serviced, bridge->base + LINT_STAT); return IRQ_HANDLED; } @@ -256,6 +256,18 @@ static void ca91cx42_irq_exit(struct ca91cx42_driver *bridge, free_irq(pdev->irq, pdev); } +static int ca91cx42_iack_received(struct ca91cx42_driver *bridge, int level) +{ + u32 tmp; + + tmp = ioread32(bridge->base + LINT_STAT); + + if (tmp & (1 << level)) + return 0; + else + return 1; +} + /* * Set up an VME interrupt */ @@ -311,7 +323,8 @@ static int ca91cx42_irq_generate(struct vme_bridge *ca91cx42_bridge, int level, iowrite32(tmp, bridge->base + VINT_EN); /* Wait for IACK */ - wait_event_interruptible(bridge->iack_queue, 0); + wait_event_interruptible(bridge->iack_queue, + ca91cx42_iack_received(bridge, level)); /* Return interrupt to low state */ tmp = ioread32(bridge->base + VINT_EN); @@ -1487,6 +1500,28 @@ static int ca91cx42_slot_get(struct vme_bridge *ca91cx42_bridge) } +void *ca91cx42_alloc_consistent(struct device *parent, size_t size, + dma_addr_t *dma) +{ + struct pci_dev *pdev; + + /* Find pci_dev container of dev */ + pdev = container_of(parent, struct pci_dev, dev); + + return pci_alloc_consistent(pdev, size, dma); +} + +void ca91cx42_free_consistent(struct device *parent, size_t size, void *vaddr, + dma_addr_t dma) +{ + struct pci_dev *pdev; + + /* Find pci_dev container of dev */ + pdev = container_of(parent, struct pci_dev, dev); + + pci_free_consistent(pdev, size, vaddr, dma); +} + static int __init ca91cx42_init(void) { return pci_register_driver(&ca91cx42_driver); @@ -1756,6 +1791,8 @@ static int ca91cx42_probe(struct pci_dev *pdev, const struct pci_device_id *id) ca91cx42_bridge->lm_attach = ca91cx42_lm_attach; ca91cx42_bridge->lm_detach = ca91cx42_lm_detach; ca91cx42_bridge->slot_get = ca91cx42_slot_get; + ca91cx42_bridge->alloc_consistent = ca91cx42_alloc_consistent; + ca91cx42_bridge->free_consistent = ca91cx42_free_consistent; data = ioread32(ca91cx42_device->base + MISC_CTL); dev_info(&pdev->dev, "Board is%s the VME system controller\n", diff --git a/drivers/staging/vme/bridges/vme_tsi148.c b/drivers/staging/vme/bridges/vme_tsi148.c index 106aa9d..6c1167c 100644 --- a/drivers/staging/vme/bridges/vme_tsi148.c +++ b/drivers/staging/vme/bridges/vme_tsi148.c @@ -44,7 +44,7 @@ static void __exit tsi148_exit(void); static int err_chk; static int geoid; -static char driver_name[] = "vme_tsi148"; +static const char driver_name[] = "vme_tsi148"; static DEFINE_PCI_DEVICE_TABLE(tsi148_ids) = { { PCI_DEVICE(PCI_VENDOR_ID_TUNDRA, PCI_DEVICE_ID_TUNDRA_TSI148) }, @@ -2114,6 +2114,28 @@ static int tsi148_slot_get(struct vme_bridge *tsi148_bridge) return (int)slot; } +void *tsi148_alloc_consistent(struct device *parent, size_t size, + dma_addr_t *dma) +{ + struct pci_dev *pdev; + + /* Find pci_dev container of dev */ + pdev = container_of(parent, struct pci_dev, dev); + + return pci_alloc_consistent(pdev, size, dma); +} + +void tsi148_free_consistent(struct device *parent, size_t size, void *vaddr, + dma_addr_t dma) +{ + struct pci_dev *pdev; + + /* Find pci_dev container of dev */ + pdev = container_of(parent, struct pci_dev, dev); + + pci_free_consistent(pdev, size, vaddr, dma); +} + static int __init tsi148_init(void) { return pci_register_driver(&tsi148_driver); @@ -2443,6 +2465,8 @@ static int tsi148_probe(struct pci_dev *pdev, const struct pci_device_id *id) tsi148_bridge->lm_attach = tsi148_lm_attach; tsi148_bridge->lm_detach = tsi148_lm_detach; tsi148_bridge->slot_get = tsi148_slot_get; + tsi148_bridge->alloc_consistent = tsi148_alloc_consistent; + tsi148_bridge->free_consistent = tsi148_free_consistent; data = ioread32be(tsi148_device->base + TSI148_LCSR_VSTAT); dev_info(&pdev->dev, "Board is%s the VME system controller\n", diff --git a/drivers/staging/vme/devices/vme_user.c b/drivers/staging/vme/devices/vme_user.c index a571173..7dcd162 100644 --- a/drivers/staging/vme/devices/vme_user.c +++ b/drivers/staging/vme/devices/vme_user.c @@ -41,9 +41,9 @@ #include "vme_user.h" static DEFINE_MUTEX(vme_user_mutex); -static char driver_name[] = "vme_user"; +static const char driver_name[] = "vme_user"; -static int bus[USER_BUS_MAX]; +static int bus[VME_USER_BUS_MAX]; static unsigned int bus_num; /* Currently Documentation/devices.txt defines the following for VME: @@ -91,7 +91,7 @@ static unsigned int bus_num; /* * Structure to handle image related parameters. */ -typedef struct { +struct image_desc { void *kern_buf; /* Buffer address in kernel space */ dma_addr_t pci_buf; /* Buffer address in PCI address space */ unsigned long long size_buf; /* Buffer size */ @@ -99,10 +99,10 @@ typedef struct { struct device *device; /* Sysfs device */ struct vme_resource *resource; /* VME resource */ int users; /* Number of current users */ -} image_desc_t; -static image_desc_t image[VME_DEVS]; +}; +static struct image_desc image[VME_DEVS]; -typedef struct { +struct driver_stats { unsigned long reads; unsigned long writes; unsigned long ioctls; @@ -111,12 +111,12 @@ typedef struct { unsigned long dmaErrors; unsigned long timeouts; unsigned long external; -} driver_stats_t; -static driver_stats_t statistics; +}; +static struct driver_stats statistics; static struct cdev *vme_user_cdev; /* Character device */ static struct class *vme_user_sysfs_class; /* Sysfs class */ -static struct device *vme_user_bridge; /* Pointer to bridge device */ +static struct vme_dev *vme_user_bridge; /* Pointer to user device */ static const int type[VME_DEVS] = { MASTER_MINOR, MASTER_MINOR, @@ -135,10 +135,11 @@ static ssize_t vme_user_write(struct file *, const char __user *, size_t, static loff_t vme_user_llseek(struct file *, loff_t, int); static long vme_user_unlocked_ioctl(struct file *, unsigned int, unsigned long); -static int __devinit vme_user_probe(struct device *, int, int); -static int __devexit vme_user_remove(struct device *, int, int); +static int vme_user_match(struct vme_dev *); +static int __devinit vme_user_probe(struct vme_dev *); +static int __devexit vme_user_remove(struct vme_dev *); -static struct file_operations vme_user_fops = { +static const struct file_operations vme_user_fops = { .open = vme_user_open, .release = vme_user_release, .read = vme_user_read, @@ -168,8 +169,8 @@ static int vme_user_open(struct inode *inode, struct file *file) unsigned int minor = MINOR(inode->i_rdev); down(&image[minor].sem); - /* Only allow device to be opened if a resource is allocated */ - if (image[minor].resource == NULL) { + /* Allow device to be opened if a resource is needed and allocated. */ + if (minor < CONTROL_MINOR && image[minor].resource == NULL) { printk(KERN_ERR "No resources allocated for device\n"); err = -EINVAL; goto err_res; @@ -321,6 +322,9 @@ static ssize_t vme_user_read(struct file *file, char __user *buf, size_t count, size_t image_size; size_t okcount; + if (minor == CONTROL_MINOR) + return 0; + down(&image[minor].sem); /* XXX Do we *really* want this helper - we can use vme_*_get ? */ @@ -365,6 +369,9 @@ static ssize_t vme_user_write(struct file *file, const char __user *buf, size_t image_size; size_t okcount; + if (minor == CONTROL_MINOR) + return 0; + down(&image[minor].sem); image_size = vme_get_size(image[minor].resource); @@ -406,6 +413,9 @@ static loff_t vme_user_llseek(struct file *file, loff_t off, int whence) unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev); size_t image_size; + if (minor == CONTROL_MINOR) + return -EINVAL; + down(&image[minor].sem); image_size = vme_get_size(image[minor].resource); @@ -452,6 +462,7 @@ static int vme_user_ioctl(struct inode *inode, struct file *file, { struct vme_master master; struct vme_slave slave; + struct vme_irq_id irq_req; unsigned long copied; unsigned int minor = MINOR(inode->i_rdev); int retval; @@ -462,6 +473,21 @@ static int vme_user_ioctl(struct inode *inode, struct file *file, switch (type[minor]) { case CONTROL_MINOR: + switch (cmd) { + case VME_IRQ_GEN: + copied = copy_from_user(&irq_req, (char *)arg, + sizeof(struct vme_irq_id)); + if (copied != 0) { + printk(KERN_WARNING "Partial copy from userspace\n"); + return -EFAULT; + } + + retval = vme_irq_generate(vme_user_bridge, + irq_req.level, + irq_req.statid); + + return retval; + } break; case MASTER_MINOR: switch (cmd) { @@ -595,6 +621,7 @@ static void buf_unalloc(int num) static struct vme_driver vme_user_driver = { .name = driver_name, + .match = vme_user_match, .probe = vme_user_probe, .remove = __devexit_p(vme_user_remove), }; @@ -603,8 +630,6 @@ static struct vme_driver vme_user_driver = { static int __init vme_user_init(void) { int retval = 0; - int i; - struct vme_device_id *ids; printk(KERN_INFO "VME User Space Access Driver\n"); @@ -618,56 +643,42 @@ static int __init vme_user_init(void) /* Let's start by supporting one bus, we can support more than one * in future revisions if that ever becomes necessary. */ - if (bus_num > USER_BUS_MAX) { + if (bus_num > VME_USER_BUS_MAX) { printk(KERN_ERR "%s: Driver only able to handle %d buses\n", - driver_name, USER_BUS_MAX); - bus_num = USER_BUS_MAX; + driver_name, VME_USER_BUS_MAX); + bus_num = VME_USER_BUS_MAX; } - - /* Dynamically create the bind table based on module parameters */ - ids = kmalloc(sizeof(struct vme_device_id) * (bus_num + 1), GFP_KERNEL); - if (ids == NULL) { - printk(KERN_ERR "%s: Unable to allocate ID table\n", - driver_name); - retval = -ENOMEM; - goto err_id; - } - - memset(ids, 0, (sizeof(struct vme_device_id) * (bus_num + 1))); - - for (i = 0; i < bus_num; i++) { - ids[i].bus = bus[i]; - /* - * We register the driver against the slot occupied by *this* - * card, since it's really a low level way of controlling - * the VME bridge - */ - ids[i].slot = VME_SLOT_CURRENT; - } - - vme_user_driver.bind_table = ids; - - retval = vme_register_driver(&vme_user_driver); + /* + * Here we just register the maximum number of devices we can and + * leave vme_user_match() to allow only 1 to go through to probe(). + * This way, if we later want to allow multiple user access devices, + * we just change the code in vme_user_match(). + */ + retval = vme_register_driver(&vme_user_driver, VME_MAX_SLOTS); if (retval != 0) goto err_reg; return retval; err_reg: - kfree(ids); -err_id: err_nocard: return retval; } +static int vme_user_match(struct vme_dev *vdev) +{ + if (vdev->num >= VME_USER_BUS_MAX) + return 0; + return 1; +} + /* * In this simple access driver, the old behaviour is being preserved as much * as practical. We will therefore reserve the buffers and request the images * here so that we don't have to do it later. */ -static int __devinit vme_user_probe(struct device *dev, int cur_bus, - int cur_slot) +static int __devinit vme_user_probe(struct vme_dev *vdev) { int i, err; char name[12]; @@ -679,7 +690,7 @@ static int __devinit vme_user_probe(struct device *dev, int cur_bus, err = -EINVAL; goto err_dev; } - vme_user_bridge = dev; + vme_user_bridge = vdev; /* Initialise descriptors */ for (i = 0; i < VME_DEVS; i++) { @@ -773,6 +784,7 @@ static int __devinit vme_user_probe(struct device *dev, int cur_bus, /* Add sysfs Entries */ for (i = 0; i < VME_DEVS; i++) { + int num; switch (type[i]) { case MASTER_MINOR: sprintf(name, "bus/vme/m%%d"); @@ -789,10 +801,9 @@ static int __devinit vme_user_probe(struct device *dev, int cur_bus, break; } - image[i].device = - device_create(vme_user_sysfs_class, NULL, - MKDEV(VME_MAJOR, i), NULL, name, - (type[i] == SLAVE_MINOR) ? i - (MASTER_MAX + 1) : i); + num = (type[i] == SLAVE_MINOR) ? i - (MASTER_MAX + 1) : i; + image[i].device = device_create(vme_user_sysfs_class, NULL, + MKDEV(VME_MAJOR, i), NULL, name, num); if (IS_ERR(image[i].device)) { printk(KERN_INFO "%s: Error creating sysfs device\n", driver_name); @@ -842,8 +853,7 @@ err_dev: return err; } -static int __devexit vme_user_remove(struct device *dev, int cur_bus, - int cur_slot) +static int __devexit vme_user_remove(struct vme_dev *dev) { int i; @@ -875,8 +885,6 @@ static int __devexit vme_user_remove(struct device *dev, int cur_bus, static void __exit vme_user_exit(void) { vme_unregister_driver(&vme_user_driver); - - kfree(vme_user_driver.bind_table); } diff --git a/drivers/staging/vme/devices/vme_user.h b/drivers/staging/vme/devices/vme_user.h index ede77d7..d85a1e9 100644 --- a/drivers/staging/vme/devices/vme_user.h +++ b/drivers/staging/vme/devices/vme_user.h @@ -1,7 +1,7 @@ #ifndef _VME_USER_H_ #define _VME_USER_H_ -#define USER_BUS_MAX 1 +#define VME_USER_BUS_MAX 1 /* * VMEbus Master Window Configuration Structure @@ -43,10 +43,16 @@ struct vme_slave { #endif }; +struct vme_irq_id { + __u8 level; + __u8 statid; +}; + #define VME_GET_SLAVE _IOR(VME_IOC_MAGIC, 1, struct vme_slave) #define VME_SET_SLAVE _IOW(VME_IOC_MAGIC, 2, struct vme_slave) #define VME_GET_MASTER _IOR(VME_IOC_MAGIC, 3, struct vme_master) #define VME_SET_MASTER _IOW(VME_IOC_MAGIC, 4, struct vme_master) +#define VME_IRQ_GEN _IOW(VME_IOC_MAGIC, 5, struct vme_irq_id) #endif /* _VME_USER_H_ */ diff --git a/drivers/staging/vme/vme.c b/drivers/staging/vme/vme.c index c078ce3..b04b468 100644 --- a/drivers/staging/vme/vme.c +++ b/drivers/staging/vme/vme.c @@ -34,20 +34,17 @@ #include "vme.h" #include "vme_bridge.h" -/* Bitmask and mutex to keep track of bridge numbers */ +/* Bitmask and list of registered buses both protected by common mutex */ static unsigned int vme_bus_numbers; -static DEFINE_MUTEX(vme_bus_num_mtx); +static LIST_HEAD(vme_bus_list); +static DEFINE_MUTEX(vme_buses_lock); static void __exit vme_exit(void); static int __init vme_init(void); - -/* - * Find the bridge resource associated with a specific device resource - */ -static struct vme_bridge *dev_to_bridge(struct device *dev) +static struct vme_dev *dev_to_vme_dev(struct device *dev) { - return dev->platform_data; + return container_of(dev, struct vme_dev, dev); } /* @@ -83,15 +80,11 @@ static struct vme_bridge *find_bridge(struct vme_resource *resource) /* * Allocate a contiguous block of memory for use by the driver. This is used to * create the buffers for the slave windows. - * - * XXX VME bridges could be available on buses other than PCI. At the momment - * this framework only supports PCI devices. */ void *vme_alloc_consistent(struct vme_resource *resource, size_t size, dma_addr_t *dma) { struct vme_bridge *bridge; - struct pci_dev *pdev; if (resource == NULL) { printk(KERN_ERR "No resource\n"); @@ -104,28 +97,29 @@ void *vme_alloc_consistent(struct vme_resource *resource, size_t size, return NULL; } - /* Find pci_dev container of dev */ if (bridge->parent == NULL) { - printk(KERN_ERR "Dev entry NULL\n"); + printk(KERN_ERR "Dev entry NULL for" + " bridge %s\n", bridge->name); return NULL; } - pdev = container_of(bridge->parent, struct pci_dev, dev); - return pci_alloc_consistent(pdev, size, dma); + if (bridge->alloc_consistent == NULL) { + printk(KERN_ERR "alloc_consistent not supported by" + " bridge %s\n", bridge->name); + return NULL; + } + + return bridge->alloc_consistent(bridge->parent, size, dma); } EXPORT_SYMBOL(vme_alloc_consistent); /* * Free previously allocated contiguous block of memory. - * - * XXX VME bridges could be available on buses other than PCI. At the momment - * this framework only supports PCI devices. */ void vme_free_consistent(struct vme_resource *resource, size_t size, void *vaddr, dma_addr_t dma) { struct vme_bridge *bridge; - struct pci_dev *pdev; if (resource == NULL) { printk(KERN_ERR "No resource\n"); @@ -138,10 +132,19 @@ void vme_free_consistent(struct vme_resource *resource, size_t size, return; } - /* Find pci_dev container of dev */ - pdev = container_of(bridge->parent, struct pci_dev, dev); + if (bridge->parent == NULL) { + printk(KERN_ERR "Dev entry NULL for" + " bridge %s\n", bridge->name); + return; + } + + if (bridge->free_consistent == NULL) { + printk(KERN_ERR "free_consistent not supported by" + " bridge %s\n", bridge->name); + return; + } - pci_free_consistent(pdev, size, vaddr, dma); + bridge->free_consistent(bridge->parent, size, vaddr, dma); } EXPORT_SYMBOL(vme_free_consistent); @@ -229,7 +232,7 @@ static int vme_check_window(vme_address_t aspace, unsigned long long vme_base, * Request a slave image with specific attributes, return some unique * identifier. */ -struct vme_resource *vme_slave_request(struct device *dev, +struct vme_resource *vme_slave_request(struct vme_dev *vdev, vme_address_t address, vme_cycle_t cycle) { struct vme_bridge *bridge; @@ -238,7 +241,7 @@ struct vme_resource *vme_slave_request(struct device *dev, struct vme_slave_resource *slave_image = NULL; struct vme_resource *resource = NULL; - bridge = dev_to_bridge(dev); + bridge = vdev->bridge; if (bridge == NULL) { printk(KERN_ERR "Can't find VME bus\n"); goto err_bus; @@ -385,7 +388,7 @@ EXPORT_SYMBOL(vme_slave_free); * Request a master image with specific attributes, return some unique * identifier. */ -struct vme_resource *vme_master_request(struct device *dev, +struct vme_resource *vme_master_request(struct vme_dev *vdev, vme_address_t address, vme_cycle_t cycle, vme_width_t dwidth) { struct vme_bridge *bridge; @@ -394,7 +397,7 @@ struct vme_resource *vme_master_request(struct device *dev, struct vme_master_resource *master_image = NULL; struct vme_resource *resource = NULL; - bridge = dev_to_bridge(dev); + bridge = vdev->bridge; if (bridge == NULL) { printk(KERN_ERR "Can't find VME bus\n"); goto err_bus; @@ -643,7 +646,8 @@ EXPORT_SYMBOL(vme_master_free); * Request a DMA controller with specific attributes, return some unique * identifier. */ -struct vme_resource *vme_dma_request(struct device *dev, vme_dma_route_t route) +struct vme_resource *vme_dma_request(struct vme_dev *vdev, + vme_dma_route_t route) { struct vme_bridge *bridge; struct list_head *dma_pos = NULL; @@ -654,7 +658,7 @@ struct vme_resource *vme_dma_request(struct device *dev, vme_dma_route_t route) /* XXX Not checking resource attributes */ printk(KERN_ERR "No VME resource Attribute tests done\n"); - bridge = dev_to_bridge(dev); + bridge = vdev->bridge; if (bridge == NULL) { printk(KERN_ERR "Can't find VME bus\n"); goto err_bus; @@ -987,13 +991,13 @@ void vme_irq_handler(struct vme_bridge *bridge, int level, int statid) } EXPORT_SYMBOL(vme_irq_handler); -int vme_irq_request(struct device *dev, int level, int statid, +int vme_irq_request(struct vme_dev *vdev, int level, int statid, void (*callback)(int, int, void *), void *priv_data) { struct vme_bridge *bridge; - bridge = dev_to_bridge(dev); + bridge = vdev->bridge; if (bridge == NULL) { printk(KERN_ERR "Can't find VME bus\n"); return -EINVAL; @@ -1030,11 +1034,11 @@ int vme_irq_request(struct device *dev, int level, int statid, } EXPORT_SYMBOL(vme_irq_request); -void vme_irq_free(struct device *dev, int level, int statid) +void vme_irq_free(struct vme_dev *vdev, int level, int statid) { struct vme_bridge *bridge; - bridge = dev_to_bridge(dev); + bridge = vdev->bridge; if (bridge == NULL) { printk(KERN_ERR "Can't find VME bus\n"); return; @@ -1065,11 +1069,11 @@ void vme_irq_free(struct device *dev, int level, int statid) } EXPORT_SYMBOL(vme_irq_free); -int vme_irq_generate(struct device *dev, int level, int statid) +int vme_irq_generate(struct vme_dev *vdev, int level, int statid) { struct vme_bridge *bridge; - bridge = dev_to_bridge(dev); + bridge = vdev->bridge; if (bridge == NULL) { printk(KERN_ERR "Can't find VME bus\n"); return -EINVAL; @@ -1092,7 +1096,7 @@ EXPORT_SYMBOL(vme_irq_generate); /* * Request the location monitor, return resource or NULL */ -struct vme_resource *vme_lm_request(struct device *dev) +struct vme_resource *vme_lm_request(struct vme_dev *vdev) { struct vme_bridge *bridge; struct list_head *lm_pos = NULL; @@ -1100,7 +1104,7 @@ struct vme_resource *vme_lm_request(struct device *dev) struct vme_lm_resource *lm = NULL; struct vme_resource *resource = NULL; - bridge = dev_to_bridge(dev); + bridge = vdev->bridge; if (bridge == NULL) { printk(KERN_ERR "Can't find VME bus\n"); goto err_bus; @@ -1281,11 +1285,11 @@ void vme_lm_free(struct vme_resource *resource) } EXPORT_SYMBOL(vme_lm_free); -int vme_slot_get(struct device *bus) +int vme_slot_get(struct vme_dev *vdev) { struct vme_bridge *bridge; - bridge = dev_to_bridge(bus); + bridge = vdev->bridge; if (bridge == NULL) { printk(KERN_ERR "Can't find VME bus\n"); return -EINVAL; @@ -1303,207 +1307,212 @@ EXPORT_SYMBOL(vme_slot_get); /* - Bridge Registration --------------------------------------------------- */ -static int vme_alloc_bus_num(void) +static int vme_add_bus(struct vme_bridge *bridge) { int i; + int ret = -1; - mutex_lock(&vme_bus_num_mtx); + mutex_lock(&vme_buses_lock); for (i = 0; i < sizeof(vme_bus_numbers) * 8; i++) { - if (((vme_bus_numbers >> i) & 0x1) == 0) { - vme_bus_numbers |= (0x1 << i); + if ((vme_bus_numbers & (1 << i)) == 0) { + vme_bus_numbers |= (1 << i); + bridge->num = i; + INIT_LIST_HEAD(&bridge->devices); + list_add_tail(&bridge->bus_list, &vme_bus_list); + ret = 0; break; } } - mutex_unlock(&vme_bus_num_mtx); + mutex_unlock(&vme_buses_lock); - return i; + return ret; } -static void vme_free_bus_num(int bus) +static void vme_remove_bus(struct vme_bridge *bridge) { - mutex_lock(&vme_bus_num_mtx); - vme_bus_numbers &= ~(0x1 << bus); - mutex_unlock(&vme_bus_num_mtx); + struct vme_dev *vdev; + struct vme_dev *tmp; + + mutex_lock(&vme_buses_lock); + vme_bus_numbers &= ~(1 << bridge->num); + list_for_each_entry_safe(vdev, tmp, &bridge->devices, bridge_list) { + list_del(&vdev->drv_list); + list_del(&vdev->bridge_list); + device_unregister(&vdev->dev); + } + list_del(&bridge->bus_list); + mutex_unlock(&vme_buses_lock); } -int vme_register_bridge(struct vme_bridge *bridge) +static void vme_dev_release(struct device *dev) { - struct device *dev; - int retval; - int i; + kfree(dev_to_vme_dev(dev)); +} - bridge->num = vme_alloc_bus_num(); +int vme_register_bridge(struct vme_bridge *bridge) +{ + return vme_add_bus(bridge); +} +EXPORT_SYMBOL(vme_register_bridge); - /* This creates 32 vme "slot" devices. This equates to a slot for each - * ID available in a system conforming to the ANSI/VITA 1-1994 - * specification. - */ - for (i = 0; i < VME_SLOTS_MAX; i++) { - dev = &bridge->dev[i]; - memset(dev, 0, sizeof(struct device)); +void vme_unregister_bridge(struct vme_bridge *bridge) +{ + vme_remove_bus(bridge); +} +EXPORT_SYMBOL(vme_unregister_bridge); - dev->parent = bridge->parent; - dev->bus = &vme_bus_type; - /* - * We save a pointer to the bridge in platform_data so that we - * can get to it later. We keep driver_data for use by the - * driver that binds against the slot - */ - dev->platform_data = bridge; - dev_set_name(dev, "vme-%x.%x", bridge->num, i + 1); +/* - Driver Registration --------------------------------------------------- */ - retval = device_register(dev); - if (retval) +static int __vme_register_driver_bus(struct vme_driver *drv, + struct vme_bridge *bridge, unsigned int ndevs) +{ + int err; + unsigned int i; + struct vme_dev *vdev; + struct vme_dev *tmp; + + for (i = 0; i < ndevs; i++) { + vdev = kzalloc(sizeof(struct vme_dev), GFP_KERNEL); + if (!vdev) { + err = -ENOMEM; + goto err_devalloc; + } + vdev->num = i; + vdev->bridge = bridge; + vdev->dev.platform_data = drv; + vdev->dev.release = vme_dev_release; + vdev->dev.parent = bridge->parent; + vdev->dev.bus = &vme_bus_type; + dev_set_name(&vdev->dev, "%s.%u-%u", drv->name, bridge->num, + vdev->num); + + err = device_register(&vdev->dev); + if (err) goto err_reg; - } - return retval; + if (vdev->dev.platform_data) { + list_add_tail(&vdev->drv_list, &drv->devices); + list_add_tail(&vdev->bridge_list, &bridge->devices); + } else + device_unregister(&vdev->dev); + } + return 0; err_reg: - while (--i >= 0) { - dev = &bridge->dev[i]; - device_unregister(dev); - } - vme_free_bus_num(bridge->num); - return retval; + kfree(vdev); +err_devalloc: + list_for_each_entry_safe(vdev, tmp, &drv->devices, drv_list) { + list_del(&vdev->drv_list); + list_del(&vdev->bridge_list); + device_unregister(&vdev->dev); + } + return err; } -EXPORT_SYMBOL(vme_register_bridge); -void vme_unregister_bridge(struct vme_bridge *bridge) +static int __vme_register_driver(struct vme_driver *drv, unsigned int ndevs) { - int i; - struct device *dev; - + struct vme_bridge *bridge; + int err = 0; - for (i = 0; i < VME_SLOTS_MAX; i++) { - dev = &bridge->dev[i]; - device_unregister(dev); + mutex_lock(&vme_buses_lock); + list_for_each_entry(bridge, &vme_bus_list, bus_list) { + /* + * This cannot cause trouble as we already have vme_buses_lock + * and if the bridge is removed, it will have to go through + * vme_unregister_bridge() to do it (which calls remove() on + * the bridge which in turn tries to acquire vme_buses_lock and + * will have to wait). The probe() called after device + * registration in __vme_register_driver below will also fail + * as the bridge is being removed (since the probe() calls + * vme_bridge_get()). + */ + err = __vme_register_driver_bus(drv, bridge, ndevs); + if (err) + break; } - vme_free_bus_num(bridge->num); + mutex_unlock(&vme_buses_lock); + return err; } -EXPORT_SYMBOL(vme_unregister_bridge); - -/* - Driver Registration --------------------------------------------------- */ - -int vme_register_driver(struct vme_driver *drv) +int vme_register_driver(struct vme_driver *drv, unsigned int ndevs) { + int err; + drv->driver.name = drv->name; drv->driver.bus = &vme_bus_type; + INIT_LIST_HEAD(&drv->devices); + + err = driver_register(&drv->driver); + if (err) + return err; - return driver_register(&drv->driver); + err = __vme_register_driver(drv, ndevs); + if (err) + driver_unregister(&drv->driver); + + return err; } EXPORT_SYMBOL(vme_register_driver); void vme_unregister_driver(struct vme_driver *drv) { - driver_unregister(&drv->driver); -} -EXPORT_SYMBOL(vme_unregister_driver); - -/* - Bus Registration ------------------------------------------------------ */ - -static int vme_calc_slot(struct device *dev) -{ - struct vme_bridge *bridge; - int num; - - bridge = dev_to_bridge(dev); - - /* Determine slot number */ - num = 0; - while (num < VME_SLOTS_MAX) { - if (&bridge->dev[num] == dev) - break; + struct vme_dev *dev, *dev_tmp; - num++; + mutex_lock(&vme_buses_lock); + list_for_each_entry_safe(dev, dev_tmp, &drv->devices, drv_list) { + list_del(&dev->drv_list); + list_del(&dev->bridge_list); + device_unregister(&dev->dev); } - if (num == VME_SLOTS_MAX) { - dev_err(dev, "Failed to identify slot\n"); - num = 0; - goto err_dev; - } - num++; + mutex_unlock(&vme_buses_lock); -err_dev: - return num; + driver_unregister(&drv->driver); } +EXPORT_SYMBOL(vme_unregister_driver); -static struct vme_driver *dev_to_vme_driver(struct device *dev) -{ - if (dev->driver == NULL) - printk(KERN_ERR "Bugger dev->driver is NULL\n"); - - return container_of(dev->driver, struct vme_driver, driver); -} +/* - Bus Registration ------------------------------------------------------ */ static int vme_bus_match(struct device *dev, struct device_driver *drv) { - struct vme_bridge *bridge; - struct vme_driver *driver; - int i, num; + struct vme_driver *vme_drv; - bridge = dev_to_bridge(dev); - driver = container_of(drv, struct vme_driver, driver); + vme_drv = container_of(drv, struct vme_driver, driver); - num = vme_calc_slot(dev); - if (!num) - goto err_dev; - - if (driver->bind_table == NULL) { - dev_err(dev, "Bind table NULL\n"); - goto err_table; - } + if (dev->platform_data == vme_drv) { + struct vme_dev *vdev = dev_to_vme_dev(dev); - i = 0; - while ((driver->bind_table[i].bus != 0) || - (driver->bind_table[i].slot != 0)) { + if (vme_drv->match && vme_drv->match(vdev)) + return 1; - if (bridge->num == driver->bind_table[i].bus) { - if (num == driver->bind_table[i].slot) - return 1; - - if (driver->bind_table[i].slot == VME_SLOT_ALL) - return 1; - - if ((driver->bind_table[i].slot == VME_SLOT_CURRENT) && - (num == vme_slot_get(dev))) - return 1; - } - i++; + dev->platform_data = NULL; } - -err_dev: -err_table: return 0; } static int vme_bus_probe(struct device *dev) { - struct vme_bridge *bridge; - struct vme_driver *driver; int retval = -ENODEV; + struct vme_driver *driver; + struct vme_dev *vdev = dev_to_vme_dev(dev); - driver = dev_to_vme_driver(dev); - bridge = dev_to_bridge(dev); + driver = dev->platform_data; if (driver->probe != NULL) - retval = driver->probe(dev, bridge->num, vme_calc_slot(dev)); + retval = driver->probe(vdev); return retval; } static int vme_bus_remove(struct device *dev) { - struct vme_bridge *bridge; - struct vme_driver *driver; int retval = -ENODEV; + struct vme_driver *driver; + struct vme_dev *vdev = dev_to_vme_dev(dev); - driver = dev_to_vme_driver(dev); - bridge = dev_to_bridge(dev); + driver = dev->platform_data; if (driver->remove != NULL) - retval = driver->remove(dev, bridge->num, vme_calc_slot(dev)); + retval = driver->remove(vdev); return retval; } diff --git a/drivers/staging/vme/vme.h b/drivers/staging/vme/vme.h index 48768ca..e3828ba 100644 --- a/drivers/staging/vme/vme.h +++ b/drivers/staging/vme/vme.h @@ -88,22 +88,38 @@ struct vme_resource { extern struct bus_type vme_bus_type; +/* VME_MAX_BRIDGES comes from the type of vme_bus_numbers */ +#define VME_MAX_BRIDGES (sizeof(unsigned int)*8) +#define VME_MAX_SLOTS 32 + #define VME_SLOT_CURRENT -1 #define VME_SLOT_ALL -2 -struct vme_device_id { - int bus; - int slot; +/** + * Structure representing a VME device + * @id: The ID of the device (currently the bus and slot number) + * @bridge: Pointer to the bridge device this device is on + * @dev: Internal device structure + * @drv_list: List of devices (per driver) + * @bridge_list: List of devices (per bridge) + */ +struct vme_dev { + int num; + struct vme_bridge *bridge; + struct device dev; + struct list_head drv_list; + struct list_head bridge_list; }; struct vme_driver { struct list_head node; - char *name; - const struct vme_device_id *bind_table; - int (*probe) (struct device *, int, int); - int (*remove) (struct device *, int, int); - void (*shutdown) (void); - struct device_driver driver; + const char *name; + int (*match)(struct vme_dev *); + int (*probe)(struct vme_dev *); + int (*remove)(struct vme_dev *); + void (*shutdown)(void); + struct device_driver driver; + struct list_head devices; }; void *vme_alloc_consistent(struct vme_resource *, size_t, dma_addr_t *); @@ -112,7 +128,7 @@ void vme_free_consistent(struct vme_resource *, size_t, void *, size_t vme_get_size(struct vme_resource *); -struct vme_resource *vme_slave_request(struct device *, vme_address_t, +struct vme_resource *vme_slave_request(struct vme_dev *, vme_address_t, vme_cycle_t); int vme_slave_set(struct vme_resource *, int, unsigned long long, unsigned long long, dma_addr_t, vme_address_t, vme_cycle_t); @@ -120,7 +136,7 @@ int vme_slave_get(struct vme_resource *, int *, unsigned long long *, unsigned long long *, dma_addr_t *, vme_address_t *, vme_cycle_t *); void vme_slave_free(struct vme_resource *); -struct vme_resource *vme_master_request(struct device *, vme_address_t, +struct vme_resource *vme_master_request(struct vme_dev *, vme_address_t, vme_cycle_t, vme_width_t); int vme_master_set(struct vme_resource *, int, unsigned long long, unsigned long long, vme_address_t, vme_cycle_t, vme_width_t); @@ -132,7 +148,7 @@ unsigned int vme_master_rmw(struct vme_resource *, unsigned int, unsigned int, unsigned int, loff_t); void vme_master_free(struct vme_resource *); -struct vme_resource *vme_dma_request(struct device *, vme_dma_route_t); +struct vme_resource *vme_dma_request(struct vme_dev *, vme_dma_route_t); struct vme_dma_list *vme_new_dma_list(struct vme_resource *); struct vme_dma_attr *vme_dma_pattern_attribute(u32, vme_pattern_t); struct vme_dma_attr *vme_dma_pci_attribute(dma_addr_t); @@ -145,12 +161,12 @@ int vme_dma_list_exec(struct vme_dma_list *); int vme_dma_list_free(struct vme_dma_list *); int vme_dma_free(struct vme_resource *); -int vme_irq_request(struct device *, int, int, +int vme_irq_request(struct vme_dev *, int, int, void (*callback)(int, int, void *), void *); -void vme_irq_free(struct device *, int, int); -int vme_irq_generate(struct device *, int, int); +void vme_irq_free(struct vme_dev *, int, int); +int vme_irq_generate(struct vme_dev *, int, int); -struct vme_resource * vme_lm_request(struct device *); +struct vme_resource * vme_lm_request(struct vme_dev *); int vme_lm_count(struct vme_resource *); int vme_lm_set(struct vme_resource *, unsigned long long, vme_address_t, vme_cycle_t); @@ -160,9 +176,9 @@ int vme_lm_attach(struct vme_resource *, int, void (*callback)(int)); int vme_lm_detach(struct vme_resource *, int); void vme_lm_free(struct vme_resource *); -int vme_slot_get(struct device *); +int vme_slot_get(struct vme_dev *); -int vme_register_driver(struct vme_driver *); +int vme_register_driver(struct vme_driver *, unsigned int); void vme_unregister_driver(struct vme_driver *); diff --git a/drivers/staging/vme/vme_api.txt b/drivers/staging/vme/vme_api.txt index 4910e92..e8ff215 100644 --- a/drivers/staging/vme/vme_api.txt +++ b/drivers/staging/vme/vme_api.txt @@ -18,37 +18,49 @@ registration function. The structure is as follows: struct vme_driver { struct list_head node; - char *name; - const struct vme_device_id *bind_table; - int (*probe) (struct device *, int, int); - int (*remove) (struct device *, int, int); - void (*shutdown) (void); - struct device_driver driver; + const char *name; + int (*match)(struct vme_dev *); + int (*probe)(struct vme_dev *); + int (*remove)(struct vme_dev *); + void (*shutdown)(void); + struct device_driver driver; + struct list_head devices; + unsigned int ndev; }; -At the minimum, the '.name', '.probe' and '.bind_table' elements of this -structure should be correctly set. The '.name' element is a pointer to a string -holding the device driver's name. The '.probe' element should contain a pointer -to the probe routine. - -The arguments of the probe routine are as follows: - - probe(struct device *dev, int bus, int slot); - -The '.bind_table' is a pointer to an array of type 'vme_device_id': - - struct vme_device_id { - int bus; - int slot; +At the minimum, the '.name', '.match' and '.probe' elements of this structure +should be correctly set. The '.name' element is a pointer to a string holding +the device driver's name. + +The '.match' function allows controlling the number of devices that need to +be registered. The match function should return 1 if a device should be +probed and 0 otherwise. This example match function (from vme_user.c) limits +the number of devices probed to one: + + #define USER_BUS_MAX 1 + ... + static int vme_user_match(struct vme_dev *vdev) + { + if (vdev->id.num >= USER_BUS_MAX) + return 0; + return 1; + } + +The '.probe' element should contain a pointer to the probe routine. The +probe routine is passed a 'struct vme_dev' pointer as an argument. The +'struct vme_dev' structure looks like the following: + + struct vme_dev { + int num; + struct vme_bridge *bridge; + struct device dev; + struct list_head drv_list; + struct list_head bridge_list; }; -Each structure in this array should provide a bus and slot number where the core -should probe, using the driver's probe routine, for a device on the specified -VME bus. - -The VME subsystem supports a single VME driver per 'slot'. There are considered -to be 32 slots per bus, one for each slot-ID as defined in the ANSI/VITA 1-1994 -specification and are analogious to the physical slots on the VME backplane. +Here, the 'num' field refers to the sequential device ID for this specific +driver. The bridge number (or bus number) can be accessed using +dev->bridge->num. A function is also provided to unregister the driver from the VME core and is usually called from the device driver's exit routine: @@ -59,9 +71,11 @@ usually called from the device driver's exit routine: Resource management =================== -Once a driver has registered with the VME core the provided probe routine will -be called for each of the bus/slot combination that becomes valid as VME buses -are themselves registered. The probe routine is passed a pointer to the devices +Once a driver has registered with the VME core the provided match routine will +be called the number of times specified during the registration. If a match +succeeds, a non-zero value should be returned. A zero return value indicates +failure. For all successful matches, the probe routine of the corresponding +driver is called. The probe routine is passed a pointer to the devices device structure. This pointer should be saved, it will be required for requesting VME resources. @@ -71,13 +85,13 @@ specific window or DMA channel (which may be used by a different driver) this driver allows a resource to be assigned based on the required attributes of the driver in question: - struct vme_resource * vme_master_request(struct device *dev, + struct vme_resource * vme_master_request(struct vme_dev *dev, vme_address_t aspace, vme_cycle_t cycle, vme_width_t width); - struct vme_resource * vme_slave_request(struct device *dev, + struct vme_resource * vme_slave_request(struct vme_dev *dev, vme_address_t aspace, vme_cycle_t cycle); - struct vme_resource *vme_dma_request(struct device *dev, + struct vme_resource *vme_dma_request(struct vme_dev *dev, vme_dma_route_t route); For slave windows these attributes are split into those of type 'vme_address_t' @@ -301,10 +315,10 @@ status ID combination. Any given combination can only be assigned a single callback function. A void pointer parameter is provided, the value of which is passed to the callback function, the use of this pointer is user undefined: - int vme_irq_request(struct device *dev, int level, int statid, + int vme_irq_request(struct vme_dev *dev, int level, int statid, void (*callback)(int, int, void *), void *priv); - void vme_irq_free(struct device *dev, int level, int statid); + void vme_irq_free(struct vme_dev *dev, int level, int statid); The callback parameters are as follows. Care must be taken in writing a callback function, callback functions run in interrupt context: @@ -318,7 +332,7 @@ Interrupt Generation The following function can be used to generate a VME interrupt at a given VME level and VME status ID: - int vme_irq_generate(struct device *dev, int level, int statid); + int vme_irq_generate(struct vme_dev *dev, int level, int statid); Location monitors @@ -334,7 +348,7 @@ Location Monitor Management The following functions are provided to request the use of a block of location monitors and to free them after they are no longer required: - struct vme_resource * vme_lm_request(struct device *dev); + struct vme_resource * vme_lm_request(struct vme_dev *dev); void vme_lm_free(struct vme_resource * res); @@ -380,4 +394,4 @@ Slot Detection This function returns the slot ID of the provided bridge. - int vme_slot_get(struct device *dev); + int vme_slot_get(struct vme_dev *dev); diff --git a/drivers/staging/vme/vme_bridge.h b/drivers/staging/vme/vme_bridge.h index 4c6ec31..c2deda2 100644 --- a/drivers/staging/vme/vme_bridge.h +++ b/drivers/staging/vme/vme_bridge.h @@ -2,7 +2,6 @@ #define _VME_BRIDGE_H_ #define VME_CRCSR_BUF_SIZE (508*1024) -#define VME_SLOTS_MAX 32 /* * Resource structures */ @@ -98,8 +97,6 @@ struct vme_irq { /* This structure stores all the information about one bridge * The structure should be dynamically allocated by the driver and one instance * of the structure should be present for each VME chip present in the system. - * - * Currently we assume that all chips are PCI-based */ struct vme_bridge { char name[VMENAMSIZ]; @@ -110,14 +107,12 @@ struct vme_bridge { struct list_head lm_resources; struct list_head vme_errors; /* List for errors generated on VME */ + struct list_head devices; /* List of devices on this bridge */ /* Bridge Info - XXX Move to private structure? */ - struct device *parent; /* Generic device struct (pdev->dev for PCI) */ + struct device *parent; /* Parent device (eg. pdev->dev for PCI) */ void *driver_priv; /* Private pointer for the bridge driver */ - - struct device dev[VME_SLOTS_MAX]; /* Device registered with - * device model on VME bus - */ + struct list_head bus_list; /* list of VME buses */ /* Interrupt callbacks */ struct vme_irq irq[7]; @@ -165,6 +160,12 @@ struct vme_bridge { /* CR/CSR space functions */ int (*slot_get) (struct vme_bridge *); + + /* Bridge parent interface */ + void *(*alloc_consistent)(struct device *dev, size_t size, + dma_addr_t *dma); + void (*free_consistent)(struct device *dev, size_t size, + void *vaddr, dma_addr_t dma); }; void vme_irq_handler(struct vme_bridge *, int, int); |