linux 2.6.16.38 w/ vs2.0.3-rc1
[linux-2.6.git] / kernel / irq / manage.c
index c2f92f1..97d5559 100644 (file)
@@ -1,12 +1,12 @@
 /*
  * linux/kernel/irq/manage.c
  *
- * Copyright (C) 1992, 1998-2006 Linus Torvalds, Ingo Molnar
- * Copyright (C) 2005-2006 Thomas Gleixner
+ * Copyright (C) 1992, 1998-2004 Linus Torvalds, Ingo Molnar
  *
  * This file contains driver APIs to the irq subsystem.
  */
 
+#include <linux/config.h>
 #include <linux/irq.h>
 #include <linux/module.h>
 #include <linux/random.h>
 
 #ifdef CONFIG_SMP
 
+cpumask_t irq_affinity[NR_IRQS] = { [0 ... NR_IRQS-1] = CPU_MASK_ALL };
+
+#if defined (CONFIG_GENERIC_PENDING_IRQ) || defined (CONFIG_IRQBALANCE)
+cpumask_t __cacheline_aligned pending_irq_cpumask[NR_IRQS];
+#endif
+
 /**
  *     synchronize_irq - wait for pending IRQ handlers (on other CPUs)
  *     @irq: interrupt number to wait for
@@ -36,6 +42,7 @@ void synchronize_irq(unsigned int irq)
        while (desc->status & IRQ_INPROGRESS)
                cpu_relax();
 }
+
 EXPORT_SYMBOL(synchronize_irq);
 
 #endif
@@ -53,7 +60,7 @@ EXPORT_SYMBOL(synchronize_irq);
  */
 void disable_irq_nosync(unsigned int irq)
 {
-       struct irq_desc *desc = irq_desc + irq;
+       irq_desc_t *desc = irq_desc + irq;
        unsigned long flags;
 
        if (irq >= NR_IRQS)
@@ -62,10 +69,11 @@ void disable_irq_nosync(unsigned int irq)
        spin_lock_irqsave(&desc->lock, flags);
        if (!desc->depth++) {
                desc->status |= IRQ_DISABLED;
-               desc->chip->disable(irq);
+               desc->handler->disable(irq);
        }
        spin_unlock_irqrestore(&desc->lock, flags);
 }
+
 EXPORT_SYMBOL(disable_irq_nosync);
 
 /**
@@ -82,7 +90,7 @@ EXPORT_SYMBOL(disable_irq_nosync);
  */
 void disable_irq(unsigned int irq)
 {
-       struct irq_desc *desc = irq_desc + irq;
+       irq_desc_t *desc = irq_desc + irq;
 
        if (irq >= NR_IRQS)
                return;
@@ -91,6 +99,7 @@ void disable_irq(unsigned int irq)
        if (desc->action)
                synchronize_irq(irq);
 }
+
 EXPORT_SYMBOL(disable_irq);
 
 /**
@@ -105,7 +114,7 @@ EXPORT_SYMBOL(disable_irq);
  */
 void enable_irq(unsigned int irq)
 {
-       struct irq_desc *desc = irq_desc + irq;
+       irq_desc_t *desc = irq_desc + irq;
        unsigned long flags;
 
        if (irq >= NR_IRQS)
@@ -114,15 +123,17 @@ void enable_irq(unsigned int irq)
        spin_lock_irqsave(&desc->lock, flags);
        switch (desc->depth) {
        case 0:
-               printk(KERN_WARNING "Unbalanced enable for IRQ %d\n", irq);
                WARN_ON(1);
                break;
        case 1: {
                unsigned int status = desc->status & ~IRQ_DISABLED;
 
-               /* Prevent probing on this irq: */
-               desc->status = status | IRQ_NOPROBE;
-               check_irq_resend(desc, irq);
+               desc->status = status;
+               if ((status & (IRQ_PENDING | IRQ_REPLAY)) == IRQ_PENDING) {
+                       desc->status = status | IRQ_REPLAY;
+                       hw_resend_irq(desc->handler,irq);
+               }
+               desc->handler->enable(irq);
                /* fall-through */
        }
        default:
@@ -130,52 +141,8 @@ void enable_irq(unsigned int irq)
        }
        spin_unlock_irqrestore(&desc->lock, flags);
 }
-EXPORT_SYMBOL(enable_irq);
 
-/**
- *     set_irq_wake - control irq power management wakeup
- *     @irq:   interrupt to control
- *     @on:    enable/disable power management wakeup
- *
- *     Enable/disable power management wakeup mode, which is
- *     disabled by default.  Enables and disables must match,
- *     just as they match for non-wakeup mode support.
- *
- *     Wakeup mode lets this IRQ wake the system from sleep
- *     states like "suspend to RAM".
- */
-int set_irq_wake(unsigned int irq, unsigned int on)
-{
-       struct irq_desc *desc = irq_desc + irq;
-       unsigned long flags;
-       int ret = -ENXIO;
-       int (*set_wake)(unsigned, unsigned) = desc->chip->set_wake;
-
-       /* wakeup-capable irqs can be shared between drivers that
-        * don't need to have the same sleep mode behaviors.
-        */
-       spin_lock_irqsave(&desc->lock, flags);
-       if (on) {
-               if (desc->wake_depth++ == 0)
-                       desc->status |= IRQ_WAKEUP;
-               else
-                       set_wake = NULL;
-       } else {
-               if (desc->wake_depth == 0) {
-                       printk(KERN_WARNING "Unbalanced IRQ %d "
-                                       "wake disable\n", irq);
-                       WARN_ON(1);
-               } else if (--desc->wake_depth == 0)
-                       desc->status &= ~IRQ_WAKEUP;
-               else
-                       set_wake = NULL;
-       }
-       if (set_wake)
-               ret = desc->chip->set_wake(irq, on);
-       spin_unlock_irqrestore(&desc->lock, flags);
-       return ret;
-}
-EXPORT_SYMBOL(set_irq_wake);
+EXPORT_SYMBOL(enable_irq);
 
 /*
  * Internal function that tells the architecture code whether a
@@ -186,33 +153,22 @@ int can_request_irq(unsigned int irq, unsigned long irqflags)
 {
        struct irqaction *action;
 
-       if (irq >= NR_IRQS || irq_desc[irq].status & IRQ_NOREQUEST)
+       if (irq >= NR_IRQS)
                return 0;
 
        action = irq_desc[irq].action;
        if (action)
-               if (irqflags & action->flags & IRQF_SHARED)
+               if (irqflags & action->flags & SA_SHIRQ)
                        action = NULL;
 
        return !action;
 }
 
-void compat_irq_chip_set_default_handler(struct irq_desc *desc)
-{
-       /*
-        * If the architecture still has not overriden
-        * the flow handler then zap the default. This
-        * should catch incorrect flow-type setting.
-        */
-       if (desc->handle_irq == &handle_bad_irq)
-               desc->handle_irq = NULL;
-}
-
 /*
  * Internal function to register an irqaction - typically used to
  * allocate special interrupts that are part of the architecture.
  */
-int setup_irq(unsigned int irq, struct irqaction *new)
+int setup_irq(unsigned int irq, struct irqaction * new)
 {
        struct irq_desc *desc = irq_desc + irq;
        struct irqaction *old, **p;
@@ -222,14 +178,14 @@ int setup_irq(unsigned int irq, struct irqaction *new)
        if (irq >= NR_IRQS)
                return -EINVAL;
 
-       if (desc->chip == &no_irq_chip)
+       if (desc->handler == &no_irq_type)
                return -ENOSYS;
        /*
         * Some drivers like serial.c use request_irq() heavily,
         * so we have to be careful not to interfere with a
         * running system.
         */
-       if (new->flags & IRQF_SAMPLE_RANDOM) {
+       if (new->flags & SA_SAMPLE_RANDOM) {
                /*
                 * This function might sleep, we want to call it first,
                 * outside of the atomic block.
@@ -244,26 +200,14 @@ int setup_irq(unsigned int irq, struct irqaction *new)
        /*
         * The following block of code has to be executed atomically
         */
-       spin_lock_irqsave(&desc->lock, flags);
+       spin_lock_irqsave(&desc->lock,flags);
        p = &desc->action;
-       old = *p;
-       if (old) {
-               /*
-                * Can't share interrupts unless both agree to and are
-                * the same type (level, edge, polarity). So both flag
-                * fields must have IRQF_SHARED set and the bits which
-                * set the trigger type must match.
-                */
-               if (!((old->flags & new->flags) & IRQF_SHARED) ||
-                   ((old->flags ^ new->flags) & IRQF_TRIGGER_MASK))
-                       goto mismatch;
-
-#if defined(CONFIG_IRQ_PER_CPU)
-               /* All handlers must agree on per-cpuness */
-               if ((old->flags & IRQF_PERCPU) !=
-                   (new->flags & IRQF_PERCPU))
-                       goto mismatch;
-#endif
+       if ((old = *p) != NULL) {
+               /* Can't share interrupts unless both agree to */
+               if (!(old->flags & new->flags & SA_SHIRQ)) {
+                       spin_unlock_irqrestore(&desc->lock,flags);
+                       return -EBUSY;
+               }
 
                /* add new interrupt at end of irq queue */
                do {
@@ -274,45 +218,17 @@ int setup_irq(unsigned int irq, struct irqaction *new)
        }
 
        *p = new;
-#if defined(CONFIG_IRQ_PER_CPU)
-       if (new->flags & IRQF_PERCPU)
-               desc->status |= IRQ_PER_CPU;
-#endif
+
        if (!shared) {
-               irq_chip_set_defaults(desc->chip);
-
-               /* Setup the type (level, edge polarity) if configured: */
-               if (new->flags & IRQF_TRIGGER_MASK) {
-                       if (desc->chip && desc->chip->set_type)
-                               desc->chip->set_type(irq,
-                                               new->flags & IRQF_TRIGGER_MASK);
-                       else
-                               /*
-                                * IRQF_TRIGGER_* but the PIC does not support
-                                * multiple flow-types?
-                                */
-                               printk(KERN_WARNING "No IRQF_TRIGGER set_type "
-                                      "function for IRQ %d (%s)\n", irq,
-                                      desc->chip ? desc->chip->name :
-                                      "unknown");
-               } else
-                       compat_irq_chip_set_default_handler(desc);
-
-               desc->status &= ~(IRQ_AUTODETECT | IRQ_WAITING |
-                                 IRQ_INPROGRESS);
-
-               if (!(desc->status & IRQ_NOAUTOEN)) {
-                       desc->depth = 0;
-                       desc->status &= ~IRQ_DISABLED;
-                       if (desc->chip->startup)
-                               desc->chip->startup(irq);
-                       else
-                               desc->chip->enable(irq);
-               } else
-                       /* Undo nested disables: */
-                       desc->depth = 1;
+               desc->depth = 0;
+               desc->status &= ~(IRQ_DISABLED | IRQ_AUTODETECT |
+                                 IRQ_WAITING | IRQ_INPROGRESS);
+               if (desc->handler->startup)
+                       desc->handler->startup(irq);
+               else
+                       desc->handler->enable(irq);
        }
-       spin_unlock_irqrestore(&desc->lock, flags);
+       spin_unlock_irqrestore(&desc->lock,flags);
 
        new->irq = irq;
        register_irq_proc(irq);
@@ -320,14 +236,6 @@ int setup_irq(unsigned int irq, struct irqaction *new)
        register_handler_proc(irq, new);
 
        return 0;
-
-mismatch:
-       spin_unlock_irqrestore(&desc->lock, flags);
-       if (!(new->flags & IRQF_PROBE_SHARED)) {
-               printk(KERN_ERR "IRQ handler type mismatch for IRQ %d\n", irq);
-               dump_stack();
-       }
-       return -EBUSY;
 }
 
 /**
@@ -354,10 +262,10 @@ void free_irq(unsigned int irq, void *dev_id)
                return;
 
        desc = irq_desc + irq;
-       spin_lock_irqsave(&desc->lock, flags);
+       spin_lock_irqsave(&desc->lock,flags);
        p = &desc->action;
        for (;;) {
-               struct irqaction *action = *p;
+               struct irqaction * action = *p;
 
                if (action) {
                        struct irqaction **pp = p;
@@ -371,18 +279,18 @@ void free_irq(unsigned int irq, void *dev_id)
 
                        /* Currently used only by UML, might disappear one day.*/
 #ifdef CONFIG_IRQ_RELEASE_METHOD
-                       if (desc->chip->release)
-                               desc->chip->release(irq, dev_id);
+                       if (desc->handler->release)
+                               desc->handler->release(irq, dev_id);
 #endif
 
                        if (!desc->action) {
                                desc->status |= IRQ_DISABLED;
-                               if (desc->chip->shutdown)
-                                       desc->chip->shutdown(irq);
+                               if (desc->handler->shutdown)
+                                       desc->handler->shutdown(irq);
                                else
-                                       desc->chip->disable(irq);
+                                       desc->handler->disable(irq);
                        }
-                       spin_unlock_irqrestore(&desc->lock, flags);
+                       spin_unlock_irqrestore(&desc->lock,flags);
                        unregister_handler_proc(irq, action);
 
                        /* Make sure it's not being used on another CPU */
@@ -390,11 +298,12 @@ void free_irq(unsigned int irq, void *dev_id)
                        kfree(action);
                        return;
                }
-               printk(KERN_ERR "Trying to free already-free IRQ %d\n", irq);
-               spin_unlock_irqrestore(&desc->lock, flags);
+               printk(KERN_ERR "Trying to free free IRQ%d\n",irq);
+               spin_unlock_irqrestore(&desc->lock,flags);
                return;
        }
 }
+
 EXPORT_SYMBOL(free_irq);
 
 /**
@@ -421,36 +330,28 @@ EXPORT_SYMBOL(free_irq);
  *
  *     Flags:
  *
- *     IRQF_SHARED             Interrupt is shared
- *     IRQF_DISABLED   Disable local interrupts while processing
- *     IRQF_SAMPLE_RANDOM      The interrupt can be used for entropy
+ *     SA_SHIRQ                Interrupt is shared
+ *     SA_INTERRUPT            Disable local interrupts while processing
+ *     SA_SAMPLE_RANDOM        The interrupt can be used for entropy
  *
  */
 int request_irq(unsigned int irq,
                irqreturn_t (*handler)(int, void *, struct pt_regs *),
-               unsigned long irqflags, const char *devname, void *dev_id)
+               unsigned long irqflags, const char * devname, void *dev_id)
 {
-       struct irqaction *action;
+       struct irqaction * action;
        int retval;
 
-#ifdef CONFIG_LOCKDEP
-       /*
-        * Lockdep wants atomic interrupt handlers:
-        */
-       irqflags |= SA_INTERRUPT;
-#endif
        /*
         * Sanity-check: shared interrupts must pass in a real dev-ID,
         * otherwise we'll have trouble later trying to figure out
         * which interrupt is which (messes up the interrupt freeing
         * logic etc).
         */
-       if ((irqflags & IRQF_SHARED) && !dev_id)
+       if ((irqflags & SA_SHIRQ) && !dev_id)
                return -EINVAL;
        if (irq >= NR_IRQS)
                return -EINVAL;
-       if (irq_desc[irq].status & IRQ_NOREQUEST)
-               return -EINVAL;
        if (!handler)
                return -EINVAL;
 
@@ -473,5 +374,6 @@ int request_irq(unsigned int irq,
 
        return retval;
 }
+
 EXPORT_SYMBOL(request_irq);