x86/IRQ: fix create_irq() after c/s 24068:6928172f7ded
authorJan Beulich <jbeulich@suse.com>
Fri, 4 Nov 2011 14:55:50 +0000 (15:55 +0100)
committerJan Beulich <jbeulich@suse.com>
Fri, 4 Nov 2011 14:55:50 +0000 (15:55 +0100)
init_one_irq_desc() must be called with interrupts enabled (as it may
call functions from the xmalloc() group). Rather than mis-using
vector_lock to also protect the finding of an unused IRQ, make this
lockless through using cmpxchg(), and obtain the lock only around the
actual assignment of the vector.

Also fold find_unassigned_irq() into its only caller.

It is, btw, questionable whether create_irq() calling
__assign_irq_vector() (rather than assign_irq_vector()) is actually
correct - desc->affinity appears to not get initialized properly in
this case.

Signed-off-by: Jan Beulich <jbeulich@suse.com>
Acked-by: Keir Fraser <keir@xen.org>
xen/arch/x86/irq.c
xen/include/asm-x86/irq.h

index 6875eb36bdb14c7375716961d08de830afd72513..ca80e9c0deb35c83b9c0ade1140e2377a0a85bc1 100644 (file)
@@ -151,16 +151,6 @@ int __init bind_irq_vector(int irq, int vector, const cpumask_t *cpu_mask)
     return ret;
 }
 
-static inline int find_unassigned_irq(void)
-{
-    int irq;
-
-    for (irq = nr_irqs_gsi; irq < nr_irqs; irq++)
-        if (irq_to_desc(irq)->arch.used == IRQ_UNUSED)
-            return irq;
-    return -ENOSPC;
-}
-
 /*
  * Dynamic irq allocate and deallocation for MSI
  */
@@ -170,19 +160,28 @@ int create_irq(void)
     int irq, ret;
     struct irq_desc *desc;
 
-    spin_lock_irqsave(&vector_lock, flags);
+    for (irq = nr_irqs_gsi; irq < nr_irqs; irq++)
+    {
+        desc = irq_to_desc(irq);
+        if (cmpxchg(&desc->arch.used, IRQ_UNUSED, IRQ_RESERVED) == IRQ_UNUSED)
+           break;
+    }
+
+    if (irq >= nr_irqs)
+         return -ENOSPC;
 
-    irq = find_unassigned_irq();
-    if (irq < 0)
-         goto out;
-    desc = irq_to_desc(irq);
     ret = init_one_irq_desc(desc);
     if (!ret)
+    {
+        spin_lock_irqsave(&vector_lock, flags);
         ret = __assign_irq_vector(irq, desc, TARGET_CPUS);
+        spin_unlock_irqrestore(&vector_lock, flags);
+    }
     if (ret < 0)
+    {
+        desc->arch.used = IRQ_UNUSED;
         irq = ret;
-out:
-     spin_unlock_irqrestore(&vector_lock, flags);
+    }
 
     return irq;
 }
index 975adafa7ae83735e1e88691b10b088ff1dbae45..3b654dc68480a461cecd71506ce05b87b46443ad 100644 (file)
@@ -39,12 +39,13 @@ struct irq_cfg {
         unsigned move_cleanup_count;
         vmask_t *used_vectors;
         u8 move_in_progress : 1;
-        u8 used: 1;
+        s8 used;
 };
 
 /* For use with irq_cfg.used */
 #define IRQ_UNUSED      (0)
 #define IRQ_USED        (1)
+#define IRQ_RESERVED    (-1)
 
 #define IRQ_VECTOR_UNASSIGNED (-1)