]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - kernel/irq/manage.c
genirq: Expose default irq affinity mask (take 3)
[linux-2.6-omap-h63xx.git] / kernel / irq / manage.c
index 1f314221d534be091d809628b39f12ccba4e997e..469814e9b9ee630b5d3050293b87390c1762d603 100644 (file)
 #include <linux/module.h>
 #include <linux/random.h>
 #include <linux/interrupt.h>
+#include <linux/slab.h>
 
 #include "internals.h"
 
 #ifdef CONFIG_SMP
 
+cpumask_t irq_default_affinity = CPU_MASK_ALL;
+
 /**
  *     synchronize_irq - wait for pending IRQ handlers (on other CPUs)
  *     @irq: interrupt number to wait for
@@ -94,6 +97,27 @@ int irq_set_affinity(unsigned int irq, cpumask_t cpumask)
        return 0;
 }
 
+#ifndef CONFIG_AUTO_IRQ_AFFINITY
+/*
+ * Generic version of the affinity autoselector.
+ */
+int irq_select_affinity(unsigned int irq)
+{
+       cpumask_t mask;
+
+       if (!irq_can_set_affinity(irq))
+               return 0;
+
+       cpus_and(mask, cpu_online_map, irq_default_affinity);
+
+       irq_desc[irq].affinity = mask;
+       irq_desc[irq].chip->set_affinity(irq, mask);
+
+       set_balance_irq_affinity(irq, mask);
+       return 0;
+}
+#endif
+
 #endif
 
 /**
@@ -149,6 +173,26 @@ void disable_irq(unsigned int irq)
 }
 EXPORT_SYMBOL(disable_irq);
 
+static void __enable_irq(struct irq_desc *desc, unsigned int irq)
+{
+       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);
+               /* fall-through */
+       }
+       default:
+               desc->depth--;
+       }
+}
+
 /**
  *     enable_irq - enable handling of an irq
  *     @irq: Interrupt to enable
@@ -168,22 +212,7 @@ void enable_irq(unsigned int irq)
                return;
 
        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);
-               /* fall-through */
-       }
-       default:
-               desc->depth--;
-       }
+       __enable_irq(desc, irq);
        spin_unlock_irqrestore(&desc->lock, flags);
 }
 EXPORT_SYMBOL(enable_irq);
@@ -364,7 +393,7 @@ int setup_irq(unsigned int irq, struct irqaction *new)
                        compat_irq_chip_set_default_handler(desc);
 
                desc->status &= ~(IRQ_AUTODETECT | IRQ_WAITING |
-                                 IRQ_INPROGRESS);
+                                 IRQ_INPROGRESS | IRQ_SPURIOUS_DISABLED);
 
                if (!(desc->status & IRQ_NOAUTOEN)) {
                        desc->depth = 0;
@@ -376,10 +405,23 @@ int setup_irq(unsigned int irq, struct irqaction *new)
                } else
                        /* Undo nested disables: */
                        desc->depth = 1;
+
+               /* Set default affinity mask once everything is setup */
+               irq_select_affinity(irq);
        }
        /* Reset broken irq detection when installing new handler */
        desc->irq_count = 0;
        desc->irqs_unhandled = 0;
+
+       /*
+        * Check whether we disabled the irq via the spurious handler
+        * before. Reenable it and give it another chance.
+        */
+       if (shared && (desc->status & IRQ_SPURIOUS_DISABLED)) {
+               desc->status &= ~IRQ_SPURIOUS_DISABLED;
+               __enable_irq(desc, irq);
+       }
+
        spin_unlock_irqrestore(&desc->lock, flags);
 
        new->irq = irq;
@@ -479,6 +521,9 @@ void free_irq(unsigned int irq, void *dev_id)
                        return;
                }
                printk(KERN_ERR "Trying to free already-free IRQ %d\n", irq);
+#ifdef CONFIG_DEBUG_SHIRQ
+               dump_stack();
+#endif
                spin_unlock_irqrestore(&desc->lock, flags);
                return;
        }
@@ -552,8 +597,6 @@ int request_irq(unsigned int irq, irq_handler_t handler,
        action->next = NULL;
        action->dev_id = dev_id;
 
-       select_smp_affinity(irq);
-
 #ifdef CONFIG_DEBUG_SHIRQ
        if (irqflags & IRQF_SHARED) {
                /*