Merge ../linux-2.6-x86
[safe/jmp/linux-2.6] / kernel / irq / chip.c
index d27b258..0af16ae 100644 (file)
@@ -11,6 +11,7 @@
  */
 
 #include <linux/irq.h>
+#include <linux/msi.h>
 #include <linux/module.h>
 #include <linux/interrupt.h>
 #include <linux/kernel_stat.h>
@@ -26,26 +27,26 @@ void dynamic_irq_init(unsigned int irq)
        struct irq_desc *desc;
        unsigned long flags;
 
-       if (irq >= NR_IRQS) {
-               printk(KERN_ERR "Trying to initialize invalid IRQ%d\n", irq);
-               WARN_ON(1);
+       desc = irq_to_desc(irq);
+       if (!desc) {
+               WARN(1, KERN_ERR "Trying to initialize invalid IRQ%d\n", irq);
                return;
        }
 
        /* Ensure we don't have left over values from a previous use of this irq */
-       desc = irq_desc + irq;
        spin_lock_irqsave(&desc->lock, flags);
        desc->status = IRQ_DISABLED;
        desc->chip = &no_irq_chip;
        desc->handle_irq = handle_bad_irq;
        desc->depth = 1;
+       desc->msi_desc = NULL;
        desc->handler_data = NULL;
        desc->chip_data = NULL;
        desc->action = NULL;
        desc->irq_count = 0;
        desc->irqs_unhandled = 0;
 #ifdef CONFIG_SMP
-       desc->affinity = CPU_MASK_ALL;
+       cpumask_setall(&desc->affinity);
 #endif
        spin_unlock_irqrestore(&desc->lock, flags);
 }
@@ -56,26 +57,27 @@ void dynamic_irq_init(unsigned int irq)
  */
 void dynamic_irq_cleanup(unsigned int irq)
 {
-       struct irq_desc *desc;
+       struct irq_desc *desc = irq_to_desc(irq);
        unsigned long flags;
 
-       if (irq >= NR_IRQS) {
-               printk(KERN_ERR "Trying to cleanup invalid IRQ%d\n", irq);
-               WARN_ON(1);
+       if (!desc) {
+               WARN(1, KERN_ERR "Trying to cleanup invalid IRQ%d\n", irq);
                return;
        }
 
-       desc = irq_desc + irq;
        spin_lock_irqsave(&desc->lock, flags);
        if (desc->action) {
                spin_unlock_irqrestore(&desc->lock, flags);
-               printk(KERN_ERR "Destroying IRQ%d without calling free_irq\n",
+               WARN(1, KERN_ERR "Destroying IRQ%d without calling free_irq\n",
                        irq);
-               WARN_ON(1);
                return;
        }
+       desc->msi_desc = NULL;
+       desc->handler_data = NULL;
+       desc->chip_data = NULL;
        desc->handle_irq = handle_bad_irq;
        desc->chip = &no_irq_chip;
+       desc->name = NULL;
        spin_unlock_irqrestore(&desc->lock, flags);
 }
 
@@ -87,19 +89,17 @@ void dynamic_irq_cleanup(unsigned int irq)
  */
 int set_irq_chip(unsigned int irq, struct irq_chip *chip)
 {
-       struct irq_desc *desc;
+       struct irq_desc *desc = irq_to_desc(irq);
        unsigned long flags;
 
-       if (irq >= NR_IRQS) {
-               printk(KERN_ERR "Trying to install chip for IRQ%d\n", irq);
-               WARN_ON(1);
+       if (!desc) {
+               WARN(1, KERN_ERR "Trying to install chip for IRQ%d\n", irq);
                return -EINVAL;
        }
 
        if (!chip)
                chip = &no_irq_chip;
 
-       desc = irq_desc + irq;
        spin_lock_irqsave(&desc->lock, flags);
        irq_chip_set_defaults(chip);
        desc->chip = chip;
@@ -110,27 +110,27 @@ int set_irq_chip(unsigned int irq, struct irq_chip *chip)
 EXPORT_SYMBOL(set_irq_chip);
 
 /**
- *     set_irq_type - set the irq type for an irq
+ *     set_irq_type - set the irq trigger type for an irq
  *     @irq:   irq number
- *     @type:  interrupt type - see include/linux/interrupt.h
+ *     @type:  IRQ_TYPE_{LEVEL,EDGE}_* value - see include/linux/irq.h
  */
 int set_irq_type(unsigned int irq, unsigned int type)
 {
-       struct irq_desc *desc;
+       struct irq_desc *desc = irq_to_desc(irq);
        unsigned long flags;
        int ret = -ENXIO;
 
-       if (irq >= NR_IRQS) {
+       if (!desc) {
                printk(KERN_ERR "Trying to set irq type for IRQ%d\n", irq);
                return -ENODEV;
        }
 
-       desc = irq_desc + irq;
-       if (desc->chip->set_type) {
-               spin_lock_irqsave(&desc->lock, flags);
-               ret = desc->chip->set_type(irq, type);
-               spin_unlock_irqrestore(&desc->lock, flags);
-       }
+       if (type == IRQ_TYPE_NONE)
+               return 0;
+
+       spin_lock_irqsave(&desc->lock, flags);
+       ret = __irq_set_trigger(desc, irq, type);
+       spin_unlock_irqrestore(&desc->lock, flags);
        return ret;
 }
 EXPORT_SYMBOL(set_irq_type);
@@ -144,16 +144,15 @@ EXPORT_SYMBOL(set_irq_type);
  */
 int set_irq_data(unsigned int irq, void *data)
 {
-       struct irq_desc *desc;
+       struct irq_desc *desc = irq_to_desc(irq);
        unsigned long flags;
 
-       if (irq >= NR_IRQS) {
+       if (!desc) {
                printk(KERN_ERR
                       "Trying to install controller data for IRQ%d\n", irq);
                return -EINVAL;
        }
 
-       desc = irq_desc + irq;
        spin_lock_irqsave(&desc->lock, flags);
        desc->handler_data = data;
        spin_unlock_irqrestore(&desc->lock, flags);
@@ -162,6 +161,32 @@ int set_irq_data(unsigned int irq, void *data)
 EXPORT_SYMBOL(set_irq_data);
 
 /**
+ *     set_irq_data - set irq type data for an irq
+ *     @irq:   Interrupt number
+ *     @entry: Pointer to MSI descriptor data
+ *
+ *     Set the hardware irq controller data for an irq
+ */
+int set_irq_msi(unsigned int irq, struct msi_desc *entry)
+{
+       struct irq_desc *desc = irq_to_desc(irq);
+       unsigned long flags;
+
+       if (!desc) {
+               printk(KERN_ERR
+                      "Trying to install msi data for IRQ%d\n", irq);
+               return -EINVAL;
+       }
+
+       spin_lock_irqsave(&desc->lock, flags);
+       desc->msi_desc = entry;
+       if (entry)
+               entry->irq = irq;
+       spin_unlock_irqrestore(&desc->lock, flags);
+       return 0;
+}
+
+/**
  *     set_irq_chip_data - set irq chip data for an irq
  *     @irq:   Interrupt number
  *     @data:  Pointer to chip specific data
@@ -170,10 +195,16 @@ EXPORT_SYMBOL(set_irq_data);
  */
 int set_irq_chip_data(unsigned int irq, void *data)
 {
-       struct irq_desc *desc = irq_desc + irq;
+       struct irq_desc *desc = irq_to_desc(irq);
        unsigned long flags;
 
-       if (irq >= NR_IRQS || !desc->chip) {
+       if (!desc) {
+               printk(KERN_ERR
+                      "Trying to install chip data for IRQ%d\n", irq);
+               return -EINVAL;
+       }
+
+       if (!desc->chip) {
                printk(KERN_ERR "BUG: bad set_irq_chip_data(IRQ#%d)\n", irq);
                return -EINVAL;
        }
@@ -191,7 +222,7 @@ EXPORT_SYMBOL(set_irq_chip_data);
  */
 static void default_enable(unsigned int irq)
 {
-       struct irq_desc *desc = irq_desc + irq;
+       struct irq_desc *desc = irq_to_desc(irq);
 
        desc->chip->unmask(irq);
        desc->status &= ~IRQ_MASKED;
@@ -202,10 +233,6 @@ static void default_enable(unsigned int irq)
  */
 static void default_disable(unsigned int irq)
 {
-       struct irq_desc *desc = irq_desc + irq;
-
-       if (!(desc->status & IRQ_DELAYED_DISABLE))
-               desc->chip->mask(irq);
 }
 
 /*
@@ -213,12 +240,24 @@ static void default_disable(unsigned int irq)
  */
 static unsigned int default_startup(unsigned int irq)
 {
-       irq_desc[irq].chip->enable(irq);
+       struct irq_desc *desc = irq_to_desc(irq);
 
+       desc->chip->enable(irq);
        return 0;
 }
 
 /*
+ * default shutdown function
+ */
+static void default_shutdown(unsigned int irq)
+{
+       struct irq_desc *desc = irq_to_desc(irq);
+
+       desc->chip->mask(irq);
+       desc->status |= IRQ_MASKED;
+}
+
+/*
  * Fixup enable/disable function pointers
  */
 void irq_chip_set_defaults(struct irq_chip *chip)
@@ -229,8 +268,15 @@ void irq_chip_set_defaults(struct irq_chip *chip)
                chip->disable = default_disable;
        if (!chip->startup)
                chip->startup = default_startup;
+       /*
+        * We use chip->disable, when the user provided its own. When
+        * we have default_disable set for chip->disable, then we need
+        * to use default_shutdown, otherwise the irq line is not
+        * disabled on free_irq():
+        */
        if (!chip->shutdown)
-               chip->shutdown = chip->disable;
+               chip->shutdown = chip->disable != default_disable ?
+                       chip->disable : default_shutdown;
        if (!chip->name)
                chip->name = chip->typename;
        if (!chip->end)
@@ -259,19 +305,18 @@ static inline void mask_ack_irq(struct irq_desc *desc, int irq)
  *     Note: The caller is expected to handle the ack, clear, mask and
  *     unmask issues if necessary.
  */
-void fastcall
+void
 handle_simple_irq(unsigned int irq, struct irq_desc *desc)
 {
        struct irqaction *action;
        irqreturn_t action_ret;
-       const unsigned int cpu = smp_processor_id();
 
        spin_lock(&desc->lock);
 
        if (unlikely(desc->status & IRQ_INPROGRESS))
                goto out_unlock;
        desc->status &= ~(IRQ_REPLAY | IRQ_WAITING);
-       kstat_cpu(cpu).irqs[irq]++;
+       kstat_incr_irqs_this_cpu(irq, desc);
 
        action = desc->action;
        if (unlikely(!action || (desc->status & IRQ_DISABLED)))
@@ -300,10 +345,9 @@ out_unlock:
  *     it after the associated handler has acknowledged the device, so the
  *     interrupt line is back to inactive.
  */
-void fastcall
+void
 handle_level_irq(unsigned int irq, struct irq_desc *desc)
 {
-       unsigned int cpu = smp_processor_id();
        struct irqaction *action;
        irqreturn_t action_ret;
 
@@ -313,20 +357,17 @@ handle_level_irq(unsigned int irq, struct irq_desc *desc)
        if (unlikely(desc->status & IRQ_INPROGRESS))
                goto out_unlock;
        desc->status &= ~(IRQ_REPLAY | IRQ_WAITING);
-       kstat_cpu(cpu).irqs[irq]++;
+       kstat_incr_irqs_this_cpu(irq, desc);
 
        /*
         * If its disabled or no action available
         * keep it masked and get out of here
         */
        action = desc->action;
-       if (unlikely(!action || (desc->status & IRQ_DISABLED))) {
-               desc->status |= IRQ_PENDING;
+       if (unlikely(!action || (desc->status & IRQ_DISABLED)))
                goto out_unlock;
-       }
 
        desc->status |= IRQ_INPROGRESS;
-       desc->status &= ~IRQ_PENDING;
        spin_unlock(&desc->lock);
 
        action_ret = handle_IRQ_event(irq, action);
@@ -351,10 +392,9 @@ out_unlock:
  *     for modern forms of interrupt handlers, which handle the flow
  *     details in hardware, transparently.
  */
-void fastcall
+void
 handle_fasteoi_irq(unsigned int irq, struct irq_desc *desc)
 {
-       unsigned int cpu = smp_processor_id();
        struct irqaction *action;
        irqreturn_t action_ret;
 
@@ -364,15 +404,17 @@ handle_fasteoi_irq(unsigned int irq, struct irq_desc *desc)
                goto out;
 
        desc->status &= ~(IRQ_REPLAY | IRQ_WAITING);
-       kstat_cpu(cpu).irqs[irq]++;
+       kstat_incr_irqs_this_cpu(irq, desc);
 
        /*
         * If its disabled or no action available
-        * keep it masked and get out of here
+        * then mask it and get out of here:
         */
        action = desc->action;
        if (unlikely(!action || (desc->status & IRQ_DISABLED))) {
                desc->status |= IRQ_PENDING;
+               if (desc->chip->mask)
+                       desc->chip->mask(irq);
                goto out;
        }
 
@@ -408,11 +450,9 @@ out:
  *     the handler was running. If all pending interrupts are handled, the
  *     loop is left.
  */
-void fastcall
+void
 handle_edge_irq(unsigned int irq, struct irq_desc *desc)
 {
-       const unsigned int cpu = smp_processor_id();
-
        spin_lock(&desc->lock);
 
        desc->status &= ~(IRQ_REPLAY | IRQ_WAITING);
@@ -428,8 +468,7 @@ handle_edge_irq(unsigned int irq, struct irq_desc *desc)
                mask_ack_irq(desc, irq);
                goto out_unlock;
        }
-
-       kstat_cpu(cpu).irqs[irq]++;
+       kstat_incr_irqs_this_cpu(irq, desc);
 
        /* Start handling the irq */
        desc->chip->ack(irq);
@@ -472,7 +511,6 @@ out_unlock:
        spin_unlock(&desc->lock);
 }
 
-#ifdef CONFIG_SMP
 /**
  *     handle_percpu_IRQ - Per CPU local irq handler
  *     @irq:   the interrupt number
@@ -480,12 +518,12 @@ out_unlock:
  *
  *     Per CPU interrupts on SMP machines without locking requirements
  */
-void fastcall
+void
 handle_percpu_irq(unsigned int irq, struct irq_desc *desc)
 {
        irqreturn_t action_ret;
 
-       kstat_this_cpu.irqs[irq]++;
+       kstat_incr_irqs_this_cpu(irq, desc);
 
        if (desc->chip->ack)
                desc->chip->ack(irq);
@@ -498,23 +536,19 @@ handle_percpu_irq(unsigned int irq, struct irq_desc *desc)
                desc->chip->eoi(irq);
 }
 
-#endif /* CONFIG_SMP */
-
 void
 __set_irq_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained,
                  const char *name)
 {
-       struct irq_desc *desc;
+       struct irq_desc *desc = irq_to_desc(irq);
        unsigned long flags;
 
-       if (irq >= NR_IRQS) {
+       if (!desc) {
                printk(KERN_ERR
                       "Trying to install type control for IRQ%d\n", irq);
                return;
        }
 
-       desc = irq_desc + irq;
-
        if (!handle)
                handle = handle_bad_irq;
        else if (desc->chip == &no_irq_chip) {
@@ -534,10 +568,8 @@ __set_irq_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained,
 
        /* Uninstall? */
        if (handle == handle_bad_irq) {
-               if (desc->chip != &no_irq_chip) {
-                       desc->chip->mask(irq);
-                       desc->chip->ack(irq);
-               }
+               if (desc->chip != &no_irq_chip)
+                       mask_ack_irq(desc, irq);
                desc->status |= IRQ_DISABLED;
                desc->depth = 1;
        }
@@ -548,7 +580,7 @@ __set_irq_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained,
                desc->status &= ~IRQ_DISABLED;
                desc->status |= IRQ_NOREQUEST | IRQ_NOPROBE;
                desc->depth = 0;
-               desc->chip->unmask(irq);
+               desc->chip->startup(irq);
        }
        spin_unlock_irqrestore(&desc->lock, flags);
 }
@@ -568,3 +600,33 @@ set_irq_chip_and_handler_name(unsigned int irq, struct irq_chip *chip,
        set_irq_chip(irq, chip);
        __set_irq_handler(irq, handle, 0, name);
 }
+
+void __init set_irq_noprobe(unsigned int irq)
+{
+       struct irq_desc *desc = irq_to_desc(irq);
+       unsigned long flags;
+
+       if (!desc) {
+               printk(KERN_ERR "Trying to mark IRQ%d non-probeable\n", irq);
+               return;
+       }
+
+       spin_lock_irqsave(&desc->lock, flags);
+       desc->status |= IRQ_NOPROBE;
+       spin_unlock_irqrestore(&desc->lock, flags);
+}
+
+void __init set_irq_probe(unsigned int irq)
+{
+       struct irq_desc *desc = irq_to_desc(irq);
+       unsigned long flags;
+
+       if (!desc) {
+               printk(KERN_ERR "Trying to mark IRQ%d probeable\n", irq);
+               return;
+       }
+
+       spin_lock_irqsave(&desc->lock, flags);
+       desc->status &= ~IRQ_NOPROBE;
+       spin_unlock_irqrestore(&desc->lock, flags);
+}