#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);
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;
}
/* 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 */
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;
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;
}
}
/* 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);
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;
}
}
/* 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 */
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;
}
INIT_LIST_HEAD(&(dma_list->entries));
dma_list->parent = ctrlr;
- init_MUTEX(&(dma_list->sem));
+ mutex_init(&(dma_list->mtx));
return dma_list;
}
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;
}
return -EINVAL;
}
- down(&(list->sem));
+ mutex_lock(&(list->mtx));
retval = bridge->dma_list_exec(list);
- up(&(list->sem));
+ mutex_unlock(&(list->mtx));
return retval;
}
return -EINVAL;
}
- if (down_trylock(&(list->sem))) {
+ if (mutex_trylock(&(list->mtx))) {
printk("Link List in use\n");
return -EINVAL;
}
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;
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;
}
}
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;
{
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)
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++;
}