]> Pileus Git - ~andy/linux/blobdiff - drivers/staging/vme/vme.c
ARM: 5712/1: SA1100: initialise spinlock in DMA code
[~andy/linux] / drivers / staging / vme / vme.c
index 8ee11925b19b38b2bc7c19329ce3257daad6fe08..477a1adfd0e90e84e8b42c66eb12c73e44dc5efe 100644 (file)
 #include <linux/device.h>
 #include <linux/dma-mapping.h>
 #include <linux/syscalls.h>
-#include <linux/semaphore.h>
+#include <linux/mutex.h>
 #include <linux/spinlock.h>
 
 #include "vme.h"
 #include "vme_bridge.h"
 
-/* Bitmask and semaphore to keep track of bridge numbers */
+/* Bitmask and mutex to keep track of bridge numbers */
 static unsigned int vme_bus_numbers;
-DECLARE_MUTEX(vme_bus_num_sem);
+DEFINE_MUTEX(vme_bus_num_mtx);
 
 static void __exit vme_exit (void);
 static int __init vme_init (void);
@@ -69,6 +69,10 @@ static struct vme_bridge *find_bridge(struct vme_resource *resource)
                return list_entry(resource->entry, struct vme_dma_resource,
                        list)->parent;
                break;
+       case VME_LM:
+               return list_entry(resource->entry, struct vme_lm_resource,
+                       list)->parent;
+               break;
        default:
                printk(KERN_ERR "Unknown resource type\n");
                return NULL;
@@ -251,17 +255,17 @@ struct vme_resource * vme_slave_request(struct device *dev,
                }
 
                /* Find an unlocked and compatible image */
-               down(&(slave_image->sem));
+               mutex_lock(&(slave_image->mtx));
                if(((slave_image->address_attr & address) == address) &&
                        ((slave_image->cycle_attr & cycle) == cycle) &&
                        (slave_image->locked == 0)) {
 
                        slave_image->locked = 1;
-                       up(&(slave_image->sem));
+                       mutex_unlock(&(slave_image->mtx));
                        allocated_image = slave_image;
                        break;
                }
-               up(&(slave_image->sem));
+               mutex_unlock(&(slave_image->mtx));
        }
 
        /* No free image */
@@ -280,9 +284,9 @@ struct vme_resource * vme_slave_request(struct device *dev,
 
 err_alloc:
        /* Unlock image */
-       down(&(slave_image->sem));
+       mutex_lock(&(slave_image->mtx));
        slave_image->locked = 0;
-       up(&(slave_image->sem));
+       mutex_unlock(&(slave_image->mtx));
 err_image:
 err_bus:
        return NULL;
@@ -338,7 +342,7 @@ int vme_slave_get (struct vme_resource *resource, int *enabled,
 
        image = list_entry(resource->entry, struct vme_slave_resource, list);
 
-       if (bridge->slave_set == NULL) {
+       if (bridge->slave_get == NULL) {
                printk("vme_slave_get not supported\n");
                return -EINVAL;
        }
@@ -365,12 +369,12 @@ void vme_slave_free(struct vme_resource *resource)
        }
 
        /* Unlock image */
-       down(&(slave_image->sem));
+       mutex_lock(&(slave_image->mtx));
        if (slave_image->locked == 0)
                printk(KERN_ERR "Image is already free\n");
 
        slave_image->locked = 0;
-       up(&(slave_image->sem));
+       mutex_unlock(&(slave_image->mtx));
 
        /* Free up resource memory */
        kfree(resource);
@@ -499,7 +503,7 @@ int vme_master_get (struct vme_resource *resource, int *enabled,
 
        image = list_entry(resource->entry, struct vme_master_resource, list);
 
-       if (bridge->master_set == NULL) {
+       if (bridge->master_get == NULL) {
                printk("vme_master_set not supported\n");
                return -EINVAL;
        }
@@ -668,14 +672,14 @@ struct vme_resource *vme_request_dma(struct device *dev)
                }
 
                /* Find an unlocked controller */
-               down(&(dma_ctrlr->sem));
+               mutex_lock(&(dma_ctrlr->mtx));
                if(dma_ctrlr->locked == 0) {
                        dma_ctrlr->locked = 1;
-                       up(&(dma_ctrlr->sem));
+                       mutex_unlock(&(dma_ctrlr->mtx));
                        allocated_ctrlr = dma_ctrlr;
                        break;
                }
-               up(&(dma_ctrlr->sem));
+               mutex_unlock(&(dma_ctrlr->mtx));
        }
 
        /* Check to see if we found a resource */
@@ -694,9 +698,9 @@ struct vme_resource *vme_request_dma(struct device *dev)
 
 err_alloc:
        /* Unlock image */
-       down(&(dma_ctrlr->sem));
+       mutex_lock(&(dma_ctrlr->mtx));
        dma_ctrlr->locked = 0;
-       up(&(dma_ctrlr->sem));
+       mutex_unlock(&(dma_ctrlr->mtx));
 err_ctrlr:
 err_bus:
        return NULL;
@@ -726,7 +730,7 @@ struct vme_dma_list *vme_new_dma_list(struct vme_resource *resource)
        }
        INIT_LIST_HEAD(&(dma_list->entries));
        dma_list->parent = ctrlr;
-       init_MUTEX(&(dma_list->sem));
+       mutex_init(&(dma_list->mtx));
 
        return dma_list;
 }
@@ -876,14 +880,14 @@ int vme_dma_list_add(struct vme_dma_list *list, struct vme_dma_attr *src,
                return -EINVAL;
        }
 
-       if (down_trylock(&(list->sem))) {
+       if (mutex_trylock(&(list->mtx))) {
                printk("Link List already submitted\n");
                return -EINVAL;
        }
 
        retval = bridge->dma_list_add(list, src, dest, count);
 
-       up(&(list->sem));
+       mutex_unlock(&(list->mtx));
 
        return retval;
 }
@@ -899,11 +903,11 @@ int vme_dma_list_exec(struct vme_dma_list *list)
                return -EINVAL;
        }
 
-       down(&(list->sem));
+       mutex_lock(&(list->mtx));
 
        retval = bridge->dma_list_exec(list);
 
-       up(&(list->sem));
+       mutex_unlock(&(list->mtx));
 
        return retval;
 }
@@ -919,7 +923,7 @@ int vme_dma_list_free(struct vme_dma_list *list)
                return -EINVAL;
        }
 
-       if (down_trylock(&(list->sem))) {
+       if (mutex_trylock(&(list->mtx))) {
                printk("Link List in use\n");
                return -EINVAL;
        }
@@ -931,10 +935,10 @@ int vme_dma_list_free(struct vme_dma_list *list)
        retval = bridge->dma_list_empty(list);
        if (retval) {
                printk("Unable to empty link-list entries\n");
-               up(&(list->sem));
+               mutex_unlock(&(list->mtx));
                return retval;
        }
-       up(&(list->sem));
+       mutex_unlock(&(list->mtx));
        kfree(list);
 
        return retval;
@@ -952,20 +956,20 @@ int vme_dma_free(struct vme_resource *resource)
 
        ctrlr = list_entry(resource->entry, struct vme_dma_resource, list);
 
-       if (down_trylock(&(ctrlr->sem))) {
+       if (mutex_trylock(&(ctrlr->mtx))) {
                printk("Resource busy, can't free\n");
                return -EBUSY;
        }
 
        if (!(list_empty(&(ctrlr->pending)) && list_empty(&(ctrlr->running)))) {
                printk("Resource still processing transfers\n");
-               up(&(ctrlr->sem));
+               mutex_unlock(&(ctrlr->mtx));
                return -EBUSY;
        }
 
        ctrlr->locked = 0;
 
-       up(&(ctrlr->sem));
+       mutex_unlock(&(ctrlr->mtx));
 
        return 0;
 }
@@ -1045,84 +1049,198 @@ int vme_generate_irq(struct device *dev, int level, int statid)
 }
 EXPORT_SYMBOL(vme_generate_irq);
 
-int vme_lm_set(struct device *dev, unsigned long long lm_base, vme_address_t aspace,
-       vme_cycle_t cycle)
+/*
+ * Request the location monitor, return resource or NULL
+ */
+struct vme_resource *vme_lm_request(struct device *dev)
 {
        struct vme_bridge *bridge;
+       struct list_head *lm_pos = NULL;
+       struct vme_lm_resource *allocated_lm = NULL;
+       struct vme_lm_resource *lm = NULL;
+       struct vme_resource *resource = NULL;
 
        bridge = dev_to_bridge(dev);
        if (bridge == NULL) {
                printk(KERN_ERR "Can't find VME bus\n");
+               goto err_bus;
+       }
+
+       /* Loop through DMA resources */
+       list_for_each(lm_pos, &(bridge->lm_resources)) {
+               lm = list_entry(lm_pos,
+                       struct vme_lm_resource, list);
+
+               if (lm == NULL) {
+                       printk(KERN_ERR "Registered NULL Location Monitor "
+                               "resource\n");
+                       continue;
+               }
+
+               /* Find an unlocked controller */
+               mutex_lock(&(lm->mtx));
+               if (lm->locked == 0) {
+                       lm->locked = 1;
+                       mutex_unlock(&(lm->mtx));
+                       allocated_lm = lm;
+                       break;
+               }
+               mutex_unlock(&(lm->mtx));
+       }
+
+       /* Check to see if we found a resource */
+       if (allocated_lm == NULL)
+               goto err_lm;
+
+       resource = kmalloc(sizeof(struct vme_resource), GFP_KERNEL);
+       if (resource == NULL) {
+               printk(KERN_ERR "Unable to allocate resource structure\n");
+               goto err_alloc;
+       }
+       resource->type = VME_LM;
+       resource->entry = &(allocated_lm->list);
+
+       return resource;
+
+err_alloc:
+       /* Unlock image */
+       mutex_lock(&(lm->mtx));
+       lm->locked = 0;
+       mutex_unlock(&(lm->mtx));
+err_lm:
+err_bus:
+       return NULL;
+}
+EXPORT_SYMBOL(vme_lm_request);
+
+int vme_lm_count(struct vme_resource *resource)
+{
+       struct vme_lm_resource *lm;
+
+       if (resource->type != VME_LM) {
+               printk(KERN_ERR "Not a Location Monitor resource\n");
                return -EINVAL;
        }
 
+       lm = list_entry(resource->entry, struct vme_lm_resource, list);
+
+       return lm->monitors;
+}
+EXPORT_SYMBOL(vme_lm_count);
+
+int vme_lm_set(struct vme_resource *resource, unsigned long long lm_base,
+       vme_address_t aspace, vme_cycle_t cycle)
+{
+       struct vme_bridge *bridge = find_bridge(resource);
+       struct vme_lm_resource *lm;
+
+       if (resource->type != VME_LM) {
+               printk(KERN_ERR "Not a Location Monitor resource\n");
+               return -EINVAL;
+       }
+
+       lm = list_entry(resource->entry, struct vme_lm_resource, list);
+
        if (bridge->lm_set == NULL) {
-               printk("vme_lm_set not supported\n");
+               printk(KERN_ERR "vme_lm_set not supported\n");
                return -EINVAL;
        }
 
-       return bridge->lm_set(lm_base, aspace, cycle);
+       /* XXX Check parameters */
+
+       return lm->parent->lm_set(lm, lm_base, aspace, cycle);
 }
 EXPORT_SYMBOL(vme_lm_set);
 
-int vme_lm_get(struct device *dev, unsigned long long *lm_base, vme_address_t *aspace,
-       vme_cycle_t *cycle)
+int vme_lm_get(struct vme_resource *resource, unsigned long long *lm_base,
+       vme_address_t *aspace, vme_cycle_t *cycle)
 {
-       struct vme_bridge *bridge;
+       struct vme_bridge *bridge = find_bridge(resource);
+       struct vme_lm_resource *lm;
 
-       bridge = dev_to_bridge(dev);
-       if (bridge == NULL) {
-               printk(KERN_ERR "Can't find VME bus\n");
+       if (resource->type != VME_LM) {
+               printk(KERN_ERR "Not a Location Monitor resource\n");
                return -EINVAL;
        }
 
+       lm = list_entry(resource->entry, struct vme_lm_resource, list);
+
        if (bridge->lm_get == NULL) {
-               printk("vme_lm_get not supported\n");
+               printk(KERN_ERR "vme_lm_get not supported\n");
                return -EINVAL;
        }
 
-       return bridge->lm_get(lm_base, aspace, cycle);
+       return bridge->lm_get(lm, lm_base, aspace, cycle);
 }
 EXPORT_SYMBOL(vme_lm_get);
 
-int vme_lm_attach(struct device *dev, int monitor, void (*callback)(int))
+int vme_lm_attach(struct vme_resource *resource, int monitor,
+       void (*callback)(int))
 {
-       struct vme_bridge *bridge;
+       struct vme_bridge *bridge = find_bridge(resource);
+       struct vme_lm_resource *lm;
 
-       bridge = dev_to_bridge(dev);
-       if (bridge == NULL) {
-               printk(KERN_ERR "Can't find VME bus\n");
+       if (resource->type != VME_LM) {
+               printk(KERN_ERR "Not a Location Monitor resource\n");
                return -EINVAL;
        }
 
+       lm = list_entry(resource->entry, struct vme_lm_resource, list);
+
        if (bridge->lm_attach == NULL) {
-               printk("vme_lm_attach not supported\n");
+               printk(KERN_ERR "vme_lm_attach not supported\n");
                return -EINVAL;
        }
 
-       return bridge->lm_attach(monitor, callback);
+       return bridge->lm_attach(lm, monitor, callback);
 }
 EXPORT_SYMBOL(vme_lm_attach);
 
-int vme_lm_detach(struct device *dev, int monitor)
+int vme_lm_detach(struct vme_resource *resource, int monitor)
 {
-       struct vme_bridge *bridge;
+       struct vme_bridge *bridge = find_bridge(resource);
+       struct vme_lm_resource *lm;
 
-       bridge = dev_to_bridge(dev);
-       if (bridge == NULL) {
-               printk(KERN_ERR "Can't find VME bus\n");
+       if (resource->type != VME_LM) {
+               printk(KERN_ERR "Not a Location Monitor resource\n");
                return -EINVAL;
        }
 
+       lm = list_entry(resource->entry, struct vme_lm_resource, list);
+
        if (bridge->lm_detach == NULL) {
-               printk("vme_lm_detach not supported\n");
+               printk(KERN_ERR "vme_lm_detach not supported\n");
                return -EINVAL;
        }
 
-       return bridge->lm_detach(monitor);
+       return bridge->lm_detach(lm, monitor);
 }
 EXPORT_SYMBOL(vme_lm_detach);
 
+void vme_lm_free(struct vme_resource *resource)
+{
+       struct vme_lm_resource *lm;
+
+       if (resource->type != VME_LM) {
+               printk(KERN_ERR "Not a Location Monitor resource\n");
+               return;
+       }
+
+       lm = list_entry(resource->entry, struct vme_lm_resource, list);
+
+       if (mutex_trylock(&(lm->mtx))) {
+               printk(KERN_ERR "Resource busy, can't free\n");
+               return;
+       }
+
+       /* XXX Check to see that there aren't any callbacks still attached */
+
+       lm->locked = 0;
+
+       mutex_unlock(&(lm->mtx));
+}
+EXPORT_SYMBOL(vme_lm_free);
+
 int vme_slot_get(struct device *bus)
 {
        struct vme_bridge *bridge;
@@ -1149,23 +1267,23 @@ static int vme_alloc_bus_num(void)
 {
        int i;
 
-       down(&vme_bus_num_sem);
+       mutex_lock(&vme_bus_num_mtx);
        for (i = 0; i < sizeof(vme_bus_numbers) * 8; i++) {
                if (((vme_bus_numbers >> i) & 0x1) == 0) {
                        vme_bus_numbers |= (0x1 << i);
                        break;
                }
        }
-       up(&vme_bus_num_sem);
+       mutex_unlock(&vme_bus_num_mtx);
 
        return i;
 }
 
 static void vme_free_bus_num(int bus)
 {
-       down(&vme_bus_num_sem);
+       mutex_lock(&vme_bus_num_mtx);
        vme_bus_numbers |= ~(0x1 << bus);
-       up(&vme_bus_num_sem);
+       mutex_unlock(&vme_bus_num_mtx);
 }
 
 int vme_register_bridge (struct vme_bridge *bridge)
@@ -1302,9 +1420,17 @@ static int vme_bus_match(struct device *dev, struct device_driver *drv)
        while((driver->bind_table[i].bus != 0) ||
                (driver->bind_table[i].slot != 0)) {
 
-               if ((bridge->num == driver->bind_table[i].bus) &&
-                       (num == driver->bind_table[i].slot))
-                       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++;
        }