summaryrefslogtreecommitdiff
path: root/drivers/staging/vme
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/staging/vme')
-rw-r--r--drivers/staging/vme/TODO2
-rw-r--r--drivers/staging/vme/bridges/vme_ca91cx42.c82
-rw-r--r--drivers/staging/vme/bridges/vme_tsi148.c161
-rw-r--r--drivers/staging/vme/devices/vme_user.c3
-rw-r--r--drivers/staging/vme/vme.c101
-rw-r--r--drivers/staging/vme/vme.h8
-rw-r--r--drivers/staging/vme/vme_api.txt8
-rw-r--r--drivers/staging/vme/vme_bridge.h9
8 files changed, 165 insertions, 209 deletions
diff --git a/drivers/staging/vme/TODO b/drivers/staging/vme/TODO
index adc5fca42afd..2201ff6f74d1 100644
--- a/drivers/staging/vme/TODO
+++ b/drivers/staging/vme/TODO
@@ -11,7 +11,7 @@ The current DMA resource Allocation provides no means of selecting the
suitability of a DMA controller based on it's supported modes of operation, as
opposed to the resource allocation mechanisms for master and slave windows:
- struct vme_resource *vme_request_dma(struct device *dev);
+ struct vme_resource *vme_dma_request(struct device *dev);
As opposed to:
diff --git a/drivers/staging/vme/bridges/vme_ca91cx42.c b/drivers/staging/vme/bridges/vme_ca91cx42.c
index e139eaeaa174..1cf3e91db59d 100644
--- a/drivers/staging/vme/bridges/vme_ca91cx42.c
+++ b/drivers/staging/vme/bridges/vme_ca91cx42.c
@@ -15,7 +15,6 @@
* option) any later version.
*/
-#include <linux/version.h>
#include <linux/module.h>
#include <linux/mm.h>
#include <linux/types.h>
@@ -54,9 +53,6 @@ struct mutex vme_int; /*
* Only one VME interrupt can be
* generated at a time, provide locking
*/
-struct mutex vme_irq; /* Locking for VME irq callback configuration */
-
-
static char driver_name[] = "vme_ca91cx42";
@@ -158,23 +154,13 @@ static u32 ca91cx42_LERR_irqhandler(void)
static u32 ca91cx42_VIRQ_irqhandler(int stat)
{
int vec, i, serviced = 0;
- void (*call)(int, int, void *);
- void *priv_data;
for (i = 7; i > 0; i--) {
if (stat & (1 << i)) {
vec = ioread32(ca91cx42_bridge->base +
CA91CX42_V_STATID[i]) & 0xff;
- call = ca91cx42_bridge->irq[i - 1].callback[vec].func;
- priv_data =
- ca91cx42_bridge->irq[i - 1].callback[vec].priv_data;
-
- if (call != NULL)
- call(i, vec, priv_data);
- else
- printk("Spurilous VME interrupt, level:%x, "
- "vector:%x\n", i, vec);
+ vme_irq_handler(ca91cx42_bridge, i, vec);
serviced |= (1 << i);
}
@@ -235,6 +221,8 @@ static int ca91cx42_irq_init(struct vme_bridge *bridge)
/* Initialise list for VME bus errors */
INIT_LIST_HEAD(&(bridge->vme_errors));
+ mutex_init(&(bridge->irq_mtx));
+
/* Disable interrupts from PCI to VME */
iowrite32(0, bridge->base + VINT_EN);
@@ -282,66 +270,31 @@ static void ca91cx42_irq_exit(struct pci_dev *pdev)
/*
* Set up an VME interrupt
*/
-int ca91cx42_request_irq(int level, int statid,
- void (*callback)(int level, int vector, void *priv_data),
- void *priv_data)
+void ca91cx42_irq_set(int level, int state, int sync)
+
{
+ struct pci_dev *pdev;
u32 tmp;
- mutex_lock(&(vme_irq));
-
- if (ca91cx42_bridge->irq[level - 1].callback[statid].func) {
- mutex_unlock(&(vme_irq));
- printk("VME Interrupt already taken\n");
- return -EBUSY;
- }
-
-
- ca91cx42_bridge->irq[level - 1].count++;
- ca91cx42_bridge->irq[level - 1].callback[statid].priv_data = priv_data;
- ca91cx42_bridge->irq[level - 1].callback[statid].func = callback;
-
/* Enable IRQ level */
tmp = ioread32(ca91cx42_bridge->base + LINT_EN);
- tmp |= CA91CX42_LINT_VIRQ[level];
- iowrite32(tmp, ca91cx42_bridge->base + LINT_EN);
-
- mutex_unlock(&(vme_irq));
-
- return 0;
-}
-/*
- * Free VME interrupt
- */
-void ca91cx42_free_irq(int level, int statid)
-{
- u32 tmp;
- struct pci_dev *pdev;
-
- mutex_lock(&(vme_irq));
-
- ca91cx42_bridge->irq[level - 1].count--;
-
- /* Disable IRQ level if no more interrupts attached at this level*/
- if (ca91cx42_bridge->irq[level - 1].count == 0) {
- tmp = ioread32(ca91cx42_bridge->base + LINT_EN);
+ if (state == 0)
tmp &= ~CA91CX42_LINT_VIRQ[level];
- iowrite32(tmp, ca91cx42_bridge->base + LINT_EN);
+ else
+ tmp |= CA91CX42_LINT_VIRQ[level];
+
+ iowrite32(tmp, ca91cx42_bridge->base + LINT_EN);
+ if ((state == 0) && (sync != 0)) {
pdev = container_of(ca91cx42_bridge->parent, struct pci_dev,
dev);
synchronize_irq(pdev->irq);
}
-
- ca91cx42_bridge->irq[level - 1].callback[statid].func = NULL;
- ca91cx42_bridge->irq[level - 1].callback[statid].priv_data = NULL;
-
- mutex_unlock(&(vme_irq));
}
-int ca91cx42_generate_irq(int level, int statid)
+int ca91cx42_irq_generate(int level, int statid)
{
u32 tmp;
@@ -1065,7 +1018,6 @@ static int ca91cx42_probe(struct pci_dev *pdev, const struct pci_device_id *id)
init_waitqueue_head(&dma_queue);
init_waitqueue_head(&iack_queue);
mutex_init(&(vme_int));
- mutex_init(&(vme_irq));
mutex_init(&(vme_rmw));
ca91cx42_bridge->parent = &(pdev->dev);
@@ -1182,9 +1134,8 @@ static int ca91cx42_probe(struct pci_dev *pdev, const struct pci_device_id *id)
ca91cx42_bridge->dma_list_exec = ca91cx42_dma_list_exec;
ca91cx42_bridge->dma_list_empty = ca91cx42_dma_list_empty;
#endif
- ca91cx42_bridge->request_irq = ca91cx42_request_irq;
- ca91cx42_bridge->free_irq = ca91cx42_free_irq;
- ca91cx42_bridge->generate_irq = ca91cx42_generate_irq;
+ ca91cx42_bridge->irq_set = ca91cx42_irq_set;
+ ca91cx42_bridge->irq_generate = ca91cx42_irq_generate;
#if 0
ca91cx42_bridge->lm_set = ca91cx42_lm_set;
ca91cx42_bridge->lm_get = ca91cx42_lm_get;
@@ -1220,7 +1171,9 @@ static int ca91cx42_probe(struct pci_dev *pdev, const struct pci_device_id *id)
vme_unregister_bridge(ca91cx42_bridge);
err_reg:
ca91cx42_crcsr_exit(pdev);
+#if 0
err_crcsr:
+#endif
err_lm:
/* resources are stored in link list */
list_for_each(pos, &(ca91cx42_bridge->lm_resources)) {
@@ -1275,7 +1228,6 @@ void ca91cx42_remove(struct pci_dev *pdev)
struct vme_slave_resource *slave_image;
struct vme_dma_resource *dma_ctrlr;
struct vme_lm_resource *lm;
- int i;
/* Turn off Ints */
iowrite32(0, ca91cx42_bridge->base + LINT_EN);
diff --git a/drivers/staging/vme/bridges/vme_tsi148.c b/drivers/staging/vme/bridges/vme_tsi148.c
index 00fe0803c21c..89a7dccb934f 100644
--- a/drivers/staging/vme/bridges/vme_tsi148.c
+++ b/drivers/staging/vme/bridges/vme_tsi148.c
@@ -13,7 +13,6 @@
* option) any later version.
*/
-#include <linux/version.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/mm.h>
@@ -78,8 +77,6 @@ struct mutex vme_int; /*
* Only one VME interrupt can be
* generated at a time, provide locking
*/
-struct mutex vme_irq; /* Locking for VME irq callback configuration */
-
static char driver_name[] = "vme_tsi148";
@@ -240,7 +237,6 @@ static u32 tsi148_VERR_irqhandler(void)
*/
static u32 tsi148_IACK_irqhandler(void)
{
- printk("tsi148_IACK_irqhandler\n");
wake_up(&iack_queue);
return TSI148_LCSR_INTC_IACKC;
@@ -252,8 +248,6 @@ static u32 tsi148_IACK_irqhandler(void)
static u32 tsi148_VIRQ_irqhandler(u32 stat)
{
int vec, i, serviced = 0;
- void (*call)(int, int, void *);
- void *priv_data;
for (i = 7; i > 0; i--) {
if (stat & (1 << i)) {
@@ -266,15 +260,7 @@ static u32 tsi148_VIRQ_irqhandler(u32 stat)
vec = ioread8(tsi148_bridge->base +
TSI148_LCSR_VIACK[i] + 3);
- call = tsi148_bridge->irq[i - 1].callback[vec].func;
- priv_data =
- tsi148_bridge->irq[i-1].callback[vec].priv_data;
-
- if (call != NULL)
- call(i, vec, priv_data);
- else
- printk("Spurilous VME interrupt, level:%x, "
- "vector:%x\n", i, vec);
+ vme_irq_handler(tsi148_bridge, i, vec);
serviced |= (1 << i);
}
@@ -354,6 +340,8 @@ static int tsi148_irq_init(struct vme_bridge *bridge)
/* Initialise list for VME bus errors */
INIT_LIST_HEAD(&(bridge->vme_errors));
+ mutex_init(&(bridge->irq_mtx));
+
result = request_irq(pdev->irq,
tsi148_irqhandler,
IRQF_SHARED,
@@ -433,55 +421,15 @@ int tsi148_iack_received(void)
}
/*
- * Set up an VME interrupt
+ * Configure VME interrupt
*/
-int tsi148_request_irq(int level, int statid,
- void (*callback)(int level, int vector, void *priv_data),
- void *priv_data)
+void tsi148_irq_set(int level, int state, int sync)
{
- u32 tmp;
-
- mutex_lock(&(vme_irq));
-
- if(tsi148_bridge->irq[level - 1].callback[statid].func) {
- mutex_unlock(&(vme_irq));
- printk("VME Interrupt already taken\n");
- return -EBUSY;
- }
-
-
- tsi148_bridge->irq[level - 1].count++;
- tsi148_bridge->irq[level - 1].callback[statid].priv_data = priv_data;
- tsi148_bridge->irq[level - 1].callback[statid].func = callback;
-
- /* Enable IRQ level */
- tmp = ioread32be(tsi148_bridge->base + TSI148_LCSR_INTEO);
- tmp |= TSI148_LCSR_INTEO_IRQEO[level - 1];
- iowrite32be(tmp, tsi148_bridge->base + TSI148_LCSR_INTEO);
-
- tmp = ioread32be(tsi148_bridge->base + TSI148_LCSR_INTEN);
- tmp |= TSI148_LCSR_INTEN_IRQEN[level - 1];
- iowrite32be(tmp, tsi148_bridge->base + TSI148_LCSR_INTEN);
-
- mutex_unlock(&(vme_irq));
-
- return 0;
-}
-
-/*
- * Free VME interrupt
- */
-void tsi148_free_irq(int level, int statid)
-{
- u32 tmp;
struct pci_dev *pdev;
+ u32 tmp;
- mutex_lock(&(vme_irq));
-
- tsi148_bridge->irq[level - 1].count--;
-
- /* Disable IRQ level if no more interrupts attached at this level*/
- if (tsi148_bridge->irq[level - 1].count == 0) {
+ /* We need to do the ordering differently for enabling and disabling */
+ if (state == 0) {
tmp = ioread32be(tsi148_bridge->base + TSI148_LCSR_INTEN);
tmp &= ~TSI148_LCSR_INTEN_IRQEN[level - 1];
iowrite32be(tmp, tsi148_bridge->base + TSI148_LCSR_INTEN);
@@ -490,22 +438,28 @@ void tsi148_free_irq(int level, int statid)
tmp &= ~TSI148_LCSR_INTEO_IRQEO[level - 1];
iowrite32be(tmp, tsi148_bridge->base + TSI148_LCSR_INTEO);
- pdev = container_of(tsi148_bridge->parent, struct pci_dev, dev);
-
- synchronize_irq(pdev->irq);
- }
+ if (sync != 0) {
+ pdev = container_of(tsi148_bridge->parent,
+ struct pci_dev, dev);
- tsi148_bridge->irq[level - 1].callback[statid].func = NULL;
- tsi148_bridge->irq[level - 1].callback[statid].priv_data = NULL;
+ synchronize_irq(pdev->irq);
+ }
+ } else {
+ tmp = ioread32be(tsi148_bridge->base + TSI148_LCSR_INTEO);
+ tmp |= TSI148_LCSR_INTEO_IRQEO[level - 1];
+ iowrite32be(tmp, tsi148_bridge->base + TSI148_LCSR_INTEO);
- mutex_unlock(&(vme_irq));
+ tmp = ioread32be(tsi148_bridge->base + TSI148_LCSR_INTEN);
+ tmp |= TSI148_LCSR_INTEN_IRQEN[level - 1];
+ iowrite32be(tmp, tsi148_bridge->base + TSI148_LCSR_INTEN);
+ }
}
/*
* Generate a VME bus interrupt at the requested level & vector. Wait for
* interrupt to be acked.
*/
-int tsi148_generate_irq(int level, int statid)
+int tsi148_irq_generate(int level, int statid)
{
u32 tmp;
@@ -891,7 +845,7 @@ static int tsi148_alloc_resource(struct vme_master_resource *image,
image->pci_resource.start);
/* If the existing size is OK, return */
- if (existing_size == (size - 1))
+ if ((size != 0) && (existing_size == (size - 1)))
return 0;
if (existing_size != 0) {
@@ -903,6 +857,11 @@ static int tsi148_alloc_resource(struct vme_master_resource *image,
memset(&(image->pci_resource), 0, sizeof(struct resource));
}
+ /* Exit here if size is zero */
+ if (size == 0) {
+ return 0;
+ }
+
if (image->pci_resource.name == NULL) {
image->pci_resource.name = kmalloc(VMENAMSIZ+3, GFP_KERNEL);
if (image->pci_resource.name == NULL) {
@@ -981,12 +940,13 @@ int tsi148_master_set( struct vme_master_resource *image, int enabled,
/* Verify input data */
if (vme_base & 0xFFFF) {
- printk("Invalid VME Window alignment\n");
+ printk(KERN_ERR "Invalid VME Window alignment\n");
retval = -EINVAL;
goto err_window;
}
- if (size < 0x10000) {
- printk("Invalid VME Window size\n");
+
+ if ((size == 0) && (enabled != 0)) {
+ printk(KERN_ERR "Size must be non-zero for enabled windows\n");
retval = -EINVAL;
goto err_window;
}
@@ -994,26 +954,31 @@ int tsi148_master_set( struct vme_master_resource *image, int enabled,
spin_lock(&(image->lock));
/* Let's allocate the resource here rather than further up the stack as
- * it avoids pushing loads of bus dependant stuff up the stack
+ * it avoids pushing loads of bus dependant stuff up the stack. If size
+ * is zero, any existing resource will be freed.
*/
retval = tsi148_alloc_resource(image, size);
if (retval) {
spin_unlock(&(image->lock));
- printk(KERN_ERR "Unable to allocate memory for resource "
- "name\n");
- retval = -ENOMEM;
+ printk(KERN_ERR "Unable to allocate memory for "
+ "resource\n");
goto err_res;
}
- pci_base = (unsigned long long)image->pci_resource.start;
-
+ if (size == 0) {
+ pci_base = 0;
+ pci_bound = 0;
+ vme_offset = 0;
+ } else {
+ pci_base = (unsigned long long)image->pci_resource.start;
- /*
- * Bound address is a valid address for the window, adjust
- * according to window granularity.
- */
- pci_bound = pci_base + (size - 0x10000);
- vme_offset = vme_base - pci_base;
+ /*
+ * Bound address is a valid address for the window, adjust
+ * according to window granularity.
+ */
+ pci_bound = pci_base + (size - 0x10000);
+ vme_offset = vme_base - pci_base;
+ }
/* Convert 64-bit variables to 2x 32-bit variables */
reg_split(pci_base, &pci_base_high, &pci_base_low);
@@ -1022,19 +987,19 @@ int tsi148_master_set( struct vme_master_resource *image, int enabled,
if (pci_base_low & 0xFFFF) {
spin_unlock(&(image->lock));
- printk("Invalid PCI base alignment\n");
+ printk(KERN_ERR "Invalid PCI base alignment\n");
retval = -EINVAL;
goto err_gran;
}
if (pci_bound_low & 0xFFFF) {
spin_unlock(&(image->lock));
- printk("Invalid PCI bound alignment\n");
+ printk(KERN_ERR "Invalid PCI bound alignment\n");
retval = -EINVAL;
goto err_gran;
}
if (vme_offset_low & 0xFFFF) {
spin_unlock(&(image->lock));
- printk("Invalid VME Offset alignment\n");
+ printk(KERN_ERR "Invalid VME Offset alignment\n");
retval = -EINVAL;
goto err_gran;
}
@@ -1094,7 +1059,8 @@ int tsi148_master_set( struct vme_master_resource *image, int enabled,
temp_ctl |= TSI148_LCSR_OTAT_TM_2eSST;
}
if (cycle & VME_2eSSTB) {
- printk("Currently not setting Broadcast Select Registers\n");
+ printk(KERN_WARNING "Currently not setting Broadcast Select "
+ "Registers\n");
temp_ctl &= ~TSI148_LCSR_OTAT_TM_M;
temp_ctl |= TSI148_LCSR_OTAT_TM_2eSSTB;
}
@@ -1110,7 +1076,7 @@ int tsi148_master_set( struct vme_master_resource *image, int enabled,
break;
default:
spin_unlock(&(image->lock));
- printk("Invalid data width\n");
+ printk(KERN_ERR "Invalid data width\n");
retval = -EINVAL;
goto err_dwidth;
}
@@ -1147,7 +1113,7 @@ int tsi148_master_set( struct vme_master_resource *image, int enabled,
break;
default:
spin_unlock(&(image->lock));
- printk("Invalid address space\n");
+ printk(KERN_ERR "Invalid address space\n");
retval = -EINVAL;
goto err_aspace;
break;
@@ -2154,7 +2120,7 @@ int tsi148_lm_detach(struct vme_lm_resource *lm, int monitor)
iowrite32be(tmp, tsi148_bridge->base + TSI148_LCSR_INTEO);
iowrite32be(TSI148_LCSR_INTC_LMC[monitor],
- tsi148_bridge->base + TSI148_LCSR_INTEO);
+ tsi148_bridge->base + TSI148_LCSR_INTC);
/* Detach callback */
lm_callback[monitor] = NULL;
@@ -2334,7 +2300,6 @@ static int tsi148_probe(struct pci_dev *pdev, const struct pci_device_id *id)
init_waitqueue_head(&dma_queue[1]);
init_waitqueue_head(&iack_queue);
mutex_init(&(vme_int));
- mutex_init(&(vme_irq));
mutex_init(&(vme_rmw));
tsi148_bridge->parent = &(pdev->dev);
@@ -2482,9 +2447,8 @@ static int tsi148_probe(struct pci_dev *pdev, const struct pci_device_id *id)
tsi148_bridge->dma_list_add = tsi148_dma_list_add;
tsi148_bridge->dma_list_exec = tsi148_dma_list_exec;
tsi148_bridge->dma_list_empty = tsi148_dma_list_empty;
- tsi148_bridge->request_irq = tsi148_request_irq;
- tsi148_bridge->free_irq = tsi148_free_irq;
- tsi148_bridge->generate_irq = tsi148_generate_irq;
+ tsi148_bridge->irq_set = tsi148_irq_set;
+ tsi148_bridge->irq_generate = tsi148_irq_generate;
tsi148_bridge->lm_set = tsi148_lm_set;
tsi148_bridge->lm_get = tsi148_lm_get;
tsi148_bridge->lm_attach = tsi148_lm_attach;
@@ -2617,13 +2581,6 @@ static void tsi148_remove(struct pci_dev *pdev)
}
/*
- * Disable and clear all interrupts.
- */
- iowrite32be(0x0, tsi148_bridge->base + TSI148_LCSR_INTEO);
- iowrite32be(0xFFFFFFFF, tsi148_bridge->base + TSI148_LCSR_INTC);
- iowrite32be(0xFFFFFFFF, tsi148_bridge->base + TSI148_LCSR_INTEN);
-
- /*
* Map all Interrupts to PCI INTA
*/
iowrite32be(0x0, tsi148_bridge->base + TSI148_LCSR_INTM1);
diff --git a/drivers/staging/vme/devices/vme_user.c b/drivers/staging/vme/devices/vme_user.c
index 78912883d153..e228942ee081 100644
--- a/drivers/staging/vme/devices/vme_user.c
+++ b/drivers/staging/vme/devices/vme_user.c
@@ -31,7 +31,6 @@
#include <linux/spinlock.h>
#include <linux/syscalls.h>
#include <linux/types.h>
-#include <linux/version.h>
#include <asm/io.h>
#include <asm/uaccess.h>
@@ -625,7 +624,7 @@ err_nocard:
static int __init vme_user_probe(struct device *dev, int cur_bus, int cur_slot)
{
int i, err;
- char name[8];
+ char name[12];
/* Save pointer to the bridge device */
if (vme_user_bridge != NULL) {
diff --git a/drivers/staging/vme/vme.c b/drivers/staging/vme/vme.c
index 477a1adfd0e9..994fdb9b2127 100644
--- a/drivers/staging/vme/vme.c
+++ b/drivers/staging/vme/vme.c
@@ -13,7 +13,6 @@
* option) any later version.
*/
-#include <linux/version.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/mm.h>
@@ -644,7 +643,7 @@ EXPORT_SYMBOL(vme_master_free);
* Request a DMA controller with specific attributes, return some unique
* identifier.
*/
-struct vme_resource *vme_request_dma(struct device *dev)
+struct vme_resource *vme_dma_request(struct device *dev)
{
struct vme_bridge *bridge;
struct list_head *dma_pos = NULL;
@@ -705,7 +704,7 @@ err_ctrlr:
err_bus:
return NULL;
}
-EXPORT_SYMBOL(vme_request_dma);
+EXPORT_SYMBOL(vme_dma_request);
/*
* Start new list
@@ -880,7 +879,7 @@ int vme_dma_list_add(struct vme_dma_list *list, struct vme_dma_attr *src,
return -EINVAL;
}
- if (mutex_trylock(&(list->mtx))) {
+ if (!mutex_trylock(&(list->mtx))) {
printk("Link List already submitted\n");
return -EINVAL;
}
@@ -923,7 +922,7 @@ int vme_dma_list_free(struct vme_dma_list *list)
return -EINVAL;
}
- if (mutex_trylock(&(list->mtx))) {
+ if (!mutex_trylock(&(list->mtx))) {
printk("Link List in use\n");
return -EINVAL;
}
@@ -956,7 +955,7 @@ int vme_dma_free(struct vme_resource *resource)
ctrlr = list_entry(resource->entry, struct vme_dma_resource, list);
- if (mutex_trylock(&(ctrlr->mtx))) {
+ if (!mutex_trylock(&(ctrlr->mtx))) {
printk("Resource busy, can't free\n");
return -EBUSY;
}
@@ -975,7 +974,23 @@ int vme_dma_free(struct vme_resource *resource)
}
EXPORT_SYMBOL(vme_dma_free);
-int vme_request_irq(struct device *dev, int level, int statid,
+void vme_irq_handler(struct vme_bridge *bridge, int level, int statid)
+{
+ void (*call)(int, int, void *);
+ void *priv_data;
+
+ call = bridge->irq[level - 1].callback[statid].func;
+ priv_data = bridge->irq[level - 1].callback[statid].priv_data;
+
+ if (call != NULL)
+ call(level, statid, priv_data);
+ else
+ printk(KERN_WARNING "Spurilous VME interrupt, level:%x, "
+ "vector:%x\n", level, statid);
+}
+EXPORT_SYMBOL(vme_irq_handler);
+
+int vme_irq_request(struct device *dev, int level, int statid,
void (*callback)(int level, int vector, void *priv_data),
void *priv_data)
{
@@ -988,20 +1003,37 @@ int vme_request_irq(struct device *dev, int level, int statid,
}
if((level < 1) || (level > 7)) {
- printk(KERN_WARNING "Invalid interrupt level\n");
+ printk(KERN_ERR "Invalid interrupt level\n");
return -EINVAL;
}
- if (bridge->request_irq == NULL) {
- printk("Registering interrupts not supported\n");
+ if (bridge->irq_set == NULL) {
+ printk(KERN_ERR "Configuring interrupts not supported\n");
return -EINVAL;
}
- return bridge->request_irq(level, statid, callback, priv_data);
+ mutex_lock(&(bridge->irq_mtx));
+
+ if (bridge->irq[level - 1].callback[statid].func) {
+ mutex_unlock(&(bridge->irq_mtx));
+ printk(KERN_WARNING "VME Interrupt already taken\n");
+ return -EBUSY;
+ }
+
+ bridge->irq[level - 1].count++;
+ bridge->irq[level - 1].callback[statid].priv_data = priv_data;
+ bridge->irq[level - 1].callback[statid].func = callback;
+
+ /* Enable IRQ level */
+ bridge->irq_set(level, 1, 1);
+
+ mutex_unlock(&(bridge->irq_mtx));
+
+ return 0;
}
-EXPORT_SYMBOL(vme_request_irq);
+EXPORT_SYMBOL(vme_irq_request);
-void vme_free_irq(struct device *dev, int level, int statid)
+void vme_irq_free(struct device *dev, int level, int statid)
{
struct vme_bridge *bridge;
@@ -1012,20 +1044,31 @@ void vme_free_irq(struct device *dev, int level, int statid)
}
if((level < 1) || (level > 7)) {
- printk(KERN_WARNING "Invalid interrupt level\n");
+ printk(KERN_ERR "Invalid interrupt level\n");
return;
}
- if (bridge->free_irq == NULL) {
- printk("Freeing interrupts not supported\n");
+ if (bridge->irq_set == NULL) {
+ printk(KERN_ERR "Configuring interrupts not supported\n");
return;
}
- bridge->free_irq(level, statid);
+ mutex_lock(&(bridge->irq_mtx));
+
+ bridge->irq[level - 1].count--;
+
+ /* Disable IRQ level if no more interrupts attached at this level*/
+ if (bridge->irq[level - 1].count == 0)
+ bridge->irq_set(level, 0, 1);
+
+ bridge->irq[level - 1].callback[statid].func = NULL;
+ bridge->irq[level - 1].callback[statid].priv_data = NULL;
+
+ mutex_unlock(&(bridge->irq_mtx));
}
-EXPORT_SYMBOL(vme_free_irq);
+EXPORT_SYMBOL(vme_irq_free);
-int vme_generate_irq(struct device *dev, int level, int statid)
+int vme_irq_generate(struct device *dev, int level, int statid)
{
struct vme_bridge *bridge;
@@ -1040,14 +1083,14 @@ int vme_generate_irq(struct device *dev, int level, int statid)
return -EINVAL;
}
- if (bridge->generate_irq == NULL) {
+ if (bridge->irq_generate == NULL) {
printk("Interrupt generation not supported\n");
return -EINVAL;
}
- return bridge->generate_irq(level, statid);
+ return bridge->irq_generate(level, statid);
}
-EXPORT_SYMBOL(vme_generate_irq);
+EXPORT_SYMBOL(vme_irq_generate);
/*
* Request the location monitor, return resource or NULL
@@ -1148,7 +1191,7 @@ int vme_lm_set(struct vme_resource *resource, unsigned long long lm_base,
/* XXX Check parameters */
- return lm->parent->lm_set(lm, lm_base, aspace, cycle);
+ return bridge->lm_set(lm, lm_base, aspace, cycle);
}
EXPORT_SYMBOL(vme_lm_set);
@@ -1228,16 +1271,18 @@ void vme_lm_free(struct vme_resource *resource)
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;
- }
+ mutex_lock(&(lm->mtx));
- /* XXX Check to see that there aren't any callbacks still attached */
+ /* XXX
+ * Check to see that there aren't any callbacks still attached, if
+ * there are we should probably be detaching them!
+ */
lm->locked = 0;
mutex_unlock(&(lm->mtx));
+
+ kfree(resource);
}
EXPORT_SYMBOL(vme_lm_free);
diff --git a/drivers/staging/vme/vme.h b/drivers/staging/vme/vme.h
index 6206e91d1992..97dc22e34caf 100644
--- a/drivers/staging/vme/vme.h
+++ b/drivers/staging/vme/vme.h
@@ -123,7 +123,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_request_dma(struct device *);
+struct vme_resource *vme_dma_request(struct device *);
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);
@@ -136,10 +136,10 @@ 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_request_irq(struct device *, int, int,
+int vme_irq_request(struct device *, int, int,
void (*callback)(int, int, void *), void *);
-void vme_free_irq(struct device *, int, int);
-int vme_generate_irq(struct device *, int, int);
+void vme_irq_free(struct device *, int, int);
+int vme_irq_generate(struct device *, int, int);
struct vme_resource * vme_lm_request(struct device *);
int vme_lm_count(struct vme_resource *);
diff --git a/drivers/staging/vme/vme_api.txt b/drivers/staging/vme/vme_api.txt
index 591eba5c9036..a5c1b1cd5fcc 100644
--- a/drivers/staging/vme/vme_api.txt
+++ b/drivers/staging/vme/vme_api.txt
@@ -77,7 +77,7 @@ driver in question:
struct vme_resource * vme_slave_request(struct device *dev,
vme_address_t aspace, vme_cycle_t cycle);
- struct vme_resource *vme_request_dma(struct device *dev);
+ struct vme_resource *vme_dma_request(struct device *dev);
For slave windows these attributes are split into those of type 'vme_address_t'
and 'vme_cycle_t'. Master windows add a further set of attributes 'vme_cycle_t'.
@@ -290,10 +290,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_request_irq(struct device *dev, int level, int statid,
+ int vme_irq_request(struct device *dev, int level, int statid,
void (*callback)(int, int, void *), void *priv);
- void vme_free_irq(struct device *dev, int level, int statid);
+ void vme_irq_free(struct device *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:
@@ -307,7 +307,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_generate_irq(struct device *dev, int level, int statid);
+ int vme_irq_generate(struct device *dev, int level, int statid);
Location monitors
diff --git a/drivers/staging/vme/vme_bridge.h b/drivers/staging/vme/vme_bridge.h
index e43cc19103b3..851fa92559f6 100644
--- a/drivers/staging/vme/vme_bridge.h
+++ b/drivers/staging/vme/vme_bridge.h
@@ -120,6 +120,8 @@ struct vme_bridge {
/* Interrupt callbacks */
struct vme_irq irq[7];
+ /* Locking for VME irq callback configuration */
+ struct mutex irq_mtx;
/* Slave Functions */
int (*slave_get) (struct vme_slave_resource *, int *,
@@ -149,9 +151,8 @@ struct vme_bridge {
int (*dma_list_empty) (struct vme_dma_list *);
/* Interrupt Functions */
- int (*request_irq) (int, int, void (*cback)(int, int, void*), void *);
- void (*free_irq) (int, int);
- int (*generate_irq) (int, int);
+ void (*irq_set) (int, int, int);
+ int (*irq_generate) (int, int);
/* Location monitor functions */
int (*lm_set) (struct vme_lm_resource *, unsigned long long,
@@ -175,6 +176,8 @@ struct vme_bridge {
#endif
};
+void vme_irq_handler(struct vme_bridge *, int, int);
+
int vme_register_bridge (struct vme_bridge *);
void vme_unregister_bridge (struct vme_bridge *);