aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/staging/vme/bridges/vme_tsi148.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/staging/vme/bridges/vme_tsi148.c')
-rw-r--r--drivers/staging/vme/bridges/vme_tsi148.c161
1 files changed, 59 insertions, 102 deletions
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);