Staging: vme: Pull common VME interrupt handling into core code
authorMartyn Welch <martyn.welch@gefanuc.com>
Thu, 29 Oct 2009 16:34:54 +0000 (16:34 +0000)
committerGreg Kroah-Hartman <gregkh@suse.de>
Fri, 11 Dec 2009 20:23:17 +0000 (12:23 -0800)
Currently the VME callback infrastructure is replicated in each VME driver.
Move this common code into the VME core. Rename functions to fit in better
with naming of other VME functions.

Signed-off-by: Martyn Welch <martyn.welch@gefanuc.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
drivers/staging/vme/bridges/vme_ca91cx42.c
drivers/staging/vme/bridges/vme_tsi148.c
drivers/staging/vme/vme.c
drivers/staging/vme/vme.h
drivers/staging/vme/vme_api.txt
drivers/staging/vme/vme_bridge.h

index 2810d80fa0e690bec5729eedd0ee9686fad6386e..74d54bb3f8e6f122780439054354ce26ab67010a 100644 (file)
@@ -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];
-       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;
 
@@ -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;
index 4d20125adcddf736f1af37b523763ae8e67d6783..5b5c73ec103e49d68fbacd29cdbb12cb14f73d76 100644 (file)
@@ -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);
-       }
-
-       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;
 
@@ -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;
index 24743078a4af124d784d705cd4ec0ed0382f11e9..241929f99265b9cc65ca71bd8ff0b0b6b51c0297 100644 (file)
@@ -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
index 6206e91d19926e3c6e066cc9b479bf3abb422532..f999f6a83c722cd0033daf5189d629303fc78962 100644 (file)
@@ -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 *);
index 591eba5c903640ff8d07561ae7f305054d50583e..36b7a3c8421f4adfaaafd61f0e0c7704f46556ae 100644 (file)
@@ -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
index e43cc19103b32b4294880c215e55bc281fc435a2..851fa92559f6aac10e43588b348d9ea3ee4582a0 100644 (file)
@@ -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 *);