aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/staging/vme/vme.c
diff options
context:
space:
mode:
authorMartyn Welch <martyn.welch@gefanuc.com>2009-08-11 17:44:56 +0100
committerGreg Kroah-Hartman <gregkh@suse.de>2009-09-15 12:02:11 -0700
commit42fb503122d8cd428b5b1078bd473847ca2b206c (patch)
treead3ed37190f00556b30e489c863753eabedbba3a /drivers/staging/vme/vme.c
parent400822fec46ce69d2ba7692689a1689653f7b847 (diff)
downloadkernel_samsung_smdk4412-42fb503122d8cd428b5b1078bd473847ca2b206c.zip
kernel_samsung_smdk4412-42fb503122d8cd428b5b1078bd473847ca2b206c.tar.gz
kernel_samsung_smdk4412-42fb503122d8cd428b5b1078bd473847ca2b206c.tar.bz2
Staging: vme: add VME Location Monitor management mechanism
Extend the image and DMA channel resource management methods to control the location monitor resource. The location monitor should be controlled as it can only be used at a single location at a time. Signed-off-by: Martyn Welch <martyn.welch@gefanuc.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/staging/vme/vme.c')
-rw-r--r--drivers/staging/vme/vme.c170
1 files changed, 144 insertions, 26 deletions
diff --git a/drivers/staging/vme/vme.c b/drivers/staging/vme/vme.c
index 07b254a..477a1ad 100644
--- a/drivers/staging/vme/vme.c
+++ b/drivers/staging/vme/vme.c
@@ -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;
@@ -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;