diff --git a/drivers/staging/vme/bridges/vme_ca91cx42.c b/drivers/staging/vme/bridges/vme_ca91cx42.c index 2810d80fa0e6..74d54bb3f8e6 100644 --- a/drivers/staging/vme/bridges/vme_ca91cx42.c +++ b/drivers/staging/vme/bridges/vme_ca91cx42.c @@ -53,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"; @@ -157,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); } @@ -234,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); @@ -281,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]; + + if (state == 0) + tmp &= ~CA91CX42_LINT_VIRQ[level]; + else + 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); - 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; @@ -1064,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); @@ -1181,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; diff --git a/drivers/staging/vme/bridges/vme_tsi148.c b/drivers/staging/vme/bridges/vme_tsi148.c index 4d20125adcdd..5b5c73ec103e 100644 --- a/drivers/staging/vme/bridges/vme_tsi148.c +++ b/drivers/staging/vme/bridges/vme_tsi148.c @@ -77,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"; @@ -251,8 +249,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)) { @@ -265,15 +261,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); } @@ -353,6 +341,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, @@ -432,55 +422,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); @@ -489,22 +439,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); + if (sync != 0) { + pdev = container_of(tsi148_bridge->parent, + struct pci_dev, dev); - synchronize_irq(pdev->irq); + 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); + + tmp = ioread32be(tsi148_bridge->base + TSI148_LCSR_INTEN); + tmp |= TSI148_LCSR_INTEN_IRQEN[level - 1]; + iowrite32be(tmp, tsi148_bridge->base + TSI148_LCSR_INTEN); } - - tsi148_bridge->irq[level - 1].callback[statid].func = NULL; - tsi148_bridge->irq[level - 1].callback[statid].priv_data = NULL; - - mutex_unlock(&(vme_irq)); } /* * 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; @@ -2333,7 +2289,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); @@ -2481,9 +2436,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; diff --git a/drivers/staging/vme/vme.c b/drivers/staging/vme/vme.c index 24743078a4af..241929f99265 100644 --- a/drivers/staging/vme/vme.c +++ b/drivers/staging/vme/vme.c @@ -974,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) { @@ -987,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; @@ -1011,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; @@ -1039,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 diff --git a/drivers/staging/vme/vme.h b/drivers/staging/vme/vme.h index 6206e91d1992..f999f6a83c72 100644 --- a/drivers/staging/vme/vme.h +++ b/drivers/staging/vme/vme.h @@ -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..36b7a3c8421f 100644 --- a/drivers/staging/vme/vme_api.txt +++ b/drivers/staging/vme/vme_api.txt @@ -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 *);