nfsd4: fail when delegreturn gets a non-delegation stateid
[safe/jmp/linux-2.6] / kernel / irq / manage.c
index c0b4d4d..291f036 100644 (file)
@@ -15,9 +15,8 @@
 
 #include "internals.h"
 
-#ifdef CONFIG_SMP
-
-cpumask_t irq_default_affinity = CPU_MASK_ALL;
+#if defined(CONFIG_SMP) && defined(CONFIG_GENERIC_HARDIRQS)
+cpumask_var_t irq_default_affinity;
 
 /**
  *     synchronize_irq - wait for pending IRQ handlers (on other CPUs)
@@ -31,7 +30,7 @@ cpumask_t irq_default_affinity = CPU_MASK_ALL;
  */
 void synchronize_irq(unsigned int irq)
 {
-       struct irq_desc *desc = __irq_to_desc(irq);
+       struct irq_desc *desc = irq_to_desc(irq);
        unsigned int status;
 
        if (!desc)
@@ -79,28 +78,30 @@ int irq_can_set_affinity(unsigned int irq)
  *     @cpumask:       cpumask
  *
  */
-int irq_set_affinity(unsigned int irq, cpumask_t cpumask)
+int irq_set_affinity(unsigned int irq, const struct cpumask *cpumask)
 {
        struct irq_desc *desc = irq_to_desc(irq);
+       unsigned long flags;
 
        if (!desc->chip->set_affinity)
                return -EINVAL;
 
-       set_balance_irq_affinity(irq, cpumask);
+       spin_lock_irqsave(&desc->lock, flags);
 
 #ifdef CONFIG_GENERIC_PENDING_IRQ
-       if (desc->status & IRQ_MOVE_PCNTXT) {
-               unsigned long flags;
-
-               spin_lock_irqsave(&desc->lock, flags);
+       if (desc->status & IRQ_MOVE_PCNTXT || desc->status & IRQ_DISABLED) {
+               cpumask_copy(&desc->affinity, cpumask);
                desc->chip->set_affinity(irq, cpumask);
-               spin_unlock_irqrestore(&desc->lock, flags);
-       } else
-               set_pending_irq(irq, cpumask);
+       } else {
+               desc->status |= IRQ_MOVE_PENDING;
+               cpumask_copy(&desc->pending_mask, cpumask);
+       }
 #else
-       desc->affinity = cpumask;
+       cpumask_copy(&desc->affinity, cpumask);
        desc->chip->set_affinity(irq, cpumask);
 #endif
+       desc->status |= IRQ_AFFINITY_SET;
+       spin_unlock_irqrestore(&desc->lock, flags);
        return 0;
 }
 
@@ -108,25 +109,57 @@ int irq_set_affinity(unsigned int irq, cpumask_t cpumask)
 /*
  * Generic version of the affinity autoselector.
  */
-int irq_select_affinity(unsigned int irq)
+int do_irq_select_affinity(unsigned int irq, struct irq_desc *desc)
 {
-       cpumask_t mask;
-       struct irq_desc *desc;
-
        if (!irq_can_set_affinity(irq))
                return 0;
 
-       cpus_and(mask, cpu_online_map, irq_default_affinity);
+       /*
+        * Preserve an userspace affinity setup, but make sure that
+        * one of the targets is online.
+        */
+       if (desc->status & (IRQ_AFFINITY_SET | IRQ_NO_BALANCING)) {
+               if (cpumask_any_and(&desc->affinity, cpu_online_mask)
+                   < nr_cpu_ids)
+                       goto set_affinity;
+               else
+                       desc->status &= ~IRQ_AFFINITY_SET;
+       }
 
-       desc = irq_to_desc(irq);
-       desc->affinity = mask;
-       desc->chip->set_affinity(irq, mask);
+       cpumask_and(&desc->affinity, cpu_online_mask, irq_default_affinity);
+set_affinity:
+       desc->chip->set_affinity(irq, &desc->affinity);
 
-       set_balance_irq_affinity(irq, mask);
        return 0;
 }
+#else
+static inline int do_irq_select_affinity(unsigned int irq, struct irq_desc *d)
+{
+       return irq_select_affinity(irq);
+}
 #endif
 
+/*
+ * Called when affinity is set via /proc/irq
+ */
+int irq_select_affinity_usr(unsigned int irq)
+{
+       struct irq_desc *desc = irq_to_desc(irq);
+       unsigned long flags;
+       int ret;
+
+       spin_lock_irqsave(&desc->lock, flags);
+       ret = do_irq_select_affinity(irq, desc);
+       spin_unlock_irqrestore(&desc->lock, flags);
+
+       return ret;
+}
+
+#else
+static inline int do_irq_select_affinity(int irq, struct irq_desc *desc)
+{
+       return 0;
+}
 #endif
 
 /**
@@ -142,10 +175,9 @@ int irq_select_affinity(unsigned int irq)
  */
 void disable_irq_nosync(unsigned int irq)
 {
-       struct irq_desc *desc;
+       struct irq_desc *desc = irq_to_desc(irq);
        unsigned long flags;
 
-       desc = __irq_to_desc(irq);
        if (!desc)
                return;
 
@@ -172,9 +204,8 @@ EXPORT_SYMBOL(disable_irq_nosync);
  */
 void disable_irq(unsigned int irq)
 {
-       struct irq_desc *desc;
+       struct irq_desc *desc = irq_to_desc(irq);
 
-       desc = __irq_to_desc(irq);
        if (!desc)
                return;
 
@@ -215,10 +246,9 @@ static void __enable_irq(struct irq_desc *desc, unsigned int irq)
  */
 void enable_irq(unsigned int irq)
 {
-       struct irq_desc *desc;
+       struct irq_desc *desc = irq_to_desc(irq);
        unsigned long flags;
 
-       desc = __irq_to_desc(irq);
        if (!desc)
                return;
 
@@ -293,10 +323,9 @@ EXPORT_SYMBOL(set_irq_wake);
  */
 int can_request_irq(unsigned int irq, unsigned long irqflags)
 {
-       struct irq_desc *desc;
+       struct irq_desc *desc = irq_to_desc(irq);
        struct irqaction *action;
 
-       desc = __irq_to_desc(irq);
        if (!desc)
                return 0;
 
@@ -333,21 +362,23 @@ int __irq_set_trigger(struct irq_desc *desc, unsigned int irq,
                 * IRQF_TRIGGER_* but the PIC does not support multiple
                 * flow-types?
                 */
-               pr_warning("No set_type function for IRQ %d (%s)\n", irq,
+               pr_debug("No set_type function for IRQ %d (%s)\n", irq,
                                chip ? (chip->name ? : "unknown") : "unknown");
                return 0;
        }
 
-       ret = chip->set_type(irq, flags & IRQF_TRIGGER_MASK);
+       /* caller masked out all except trigger mode flags */
+       ret = chip->set_type(irq, flags);
 
        if (ret)
                pr_err("setting trigger mode %d for irq %u failed (%pF)\n",
-                               (int)(flags & IRQF_TRIGGER_MASK),
-                               irq, chip->set_type);
+                               (int)flags, irq, chip->set_type);
        else {
+               if (flags & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH))
+                       flags |= IRQ_LEVEL;
                /* note that IRQF_TRIGGER_MASK == IRQ_TYPE_SENSE_MASK */
-               desc->status &= ~IRQ_TYPE_SENSE_MASK;
-               desc->status |= flags & IRQ_TYPE_SENSE_MASK;
+               desc->status &= ~(IRQ_LEVEL | IRQ_TYPE_SENSE_MASK);
+               desc->status |= flags;
        }
 
        return ret;
@@ -357,16 +388,15 @@ int __irq_set_trigger(struct irq_desc *desc, unsigned int irq,
  * 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)
+static int
+__setup_irq(unsigned int irq, struct irq_desc * desc, struct irqaction *new)
 {
-       struct irq_desc *desc;
        struct irqaction *old, **p;
        const char *old_name = NULL;
        unsigned long flags;
        int shared = 0;
        int ret;
 
-       desc = __irq_to_desc(irq);
        if (!desc)
                return -EINVAL;
 
@@ -428,7 +458,8 @@ int setup_irq(unsigned int irq, struct irqaction *new)
 
                /* Setup the type (level, edge polarity) if configured: */
                if (new->flags & IRQF_TRIGGER_MASK) {
-                       ret = __irq_set_trigger(desc, irq, new->flags);
+                       ret = __irq_set_trigger(desc, irq,
+                                       new->flags & IRQF_TRIGGER_MASK);
 
                        if (ret) {
                                spin_unlock_irqrestore(&desc->lock, flags);
@@ -452,8 +483,12 @@ int setup_irq(unsigned int irq, struct irqaction *new)
                        /* Undo nested disables: */
                        desc->depth = 1;
 
+               /* Exclude IRQ from balancing if requested */
+               if (new->flags & IRQF_NOBALANCING)
+                       desc->status |= IRQ_NO_BALANCING;
+
                /* Set default affinity mask once everything is setup */
-               irq_select_affinity(irq);
+               do_irq_select_affinity(irq, desc);
 
        } else if ((new->flags & IRQF_TRIGGER_MASK)
                        && (new->flags & IRQF_TRIGGER_MASK)
@@ -466,10 +501,6 @@ int setup_irq(unsigned int irq, struct irqaction *new)
 
        *p = new;
 
-       /* Exclude IRQ from balancing */
-       if (new->flags & IRQF_NOBALANCING)
-               desc->status |= IRQ_NO_BALANCING;
-
        /* Reset broken irq detection when installing new handler */
        desc->irq_count = 0;
        desc->irqs_unhandled = 0;
@@ -506,6 +537,20 @@ mismatch:
 }
 
 /**
+ *     setup_irq - setup an interrupt
+ *     @irq: Interrupt line to setup
+ *     @act: irqaction for the interrupt
+ *
+ * Used to statically setup interrupts in the early boot process.
+ */
+int setup_irq(unsigned int irq, struct irqaction *act)
+{
+       struct irq_desc *desc = irq_to_desc(irq);
+
+       return __setup_irq(irq, desc, act);
+}
+
+/**
  *     free_irq - free an interrupt
  *     @irq: Interrupt line to free
  *     @dev_id: Device identity to free
@@ -521,13 +566,12 @@ mismatch:
  */
 void free_irq(unsigned int irq, void *dev_id)
 {
-       struct irq_desc *desc;
+       struct irq_desc *desc = irq_to_desc(irq);
        struct irqaction **p;
        unsigned long flags;
 
        WARN_ON(in_interrupt());
 
-       desc = __irq_to_desc(irq);
        if (!desc)
                return;
 
@@ -626,8 +670,20 @@ int request_irq(unsigned int irq, irq_handler_t handler,
                unsigned long irqflags, const char *devname, void *dev_id)
 {
        struct irqaction *action;
-       int retval;
        struct irq_desc *desc;
+       int retval;
+
+       /*
+        * handle_IRQ_event() always ignores IRQF_DISABLED except for
+        * the _first_ irqaction (sigh).  That can cause oopsing, but
+        * the behavior is classified as "will not fix" so we need to
+        * start nudging drivers away from using that idiom.
+        */
+       if ((irqflags & (IRQF_SHARED|IRQF_DISABLED))
+                       == (IRQF_SHARED|IRQF_DISABLED))
+               pr_warning("IRQ %d/%s: IRQF_DISABLED is not "
+                               "guaranteed on shared IRQs\n",
+                               irq, devname);
 
 #ifdef CONFIG_LOCKDEP
        /*
@@ -644,7 +700,7 @@ int request_irq(unsigned int irq, irq_handler_t handler,
        if ((irqflags & IRQF_SHARED) && !dev_id)
                return -EINVAL;
 
-       desc = __irq_to_desc(irq);
+       desc = irq_to_desc(irq);
        if (!desc)
                return -EINVAL;
 
@@ -664,7 +720,7 @@ int request_irq(unsigned int irq, irq_handler_t handler,
        action->next = NULL;
        action->dev_id = dev_id;
 
-       retval = setup_irq(irq, action);
+       retval = __setup_irq(irq, desc, action);
        if (retval)
                kfree(action);