[POWERPC] Add an optional device_node pointer to the irq_host
[powerpc.git] / arch / powerpc / kernel / irq.c
index 0a76989..79b4512 100644 (file)
@@ -272,7 +272,7 @@ void do_IRQ(struct pt_regs *regs)
        struct thread_info *curtp, *irqtp;
 #endif
 
-        irq_enter();
+       irq_enter();
 
 #ifdef CONFIG_DEBUG_STACKOVERFLOW
        /* Debugging check for stack overflow: is there less than 2KB free? */
@@ -321,7 +321,7 @@ void do_IRQ(struct pt_regs *regs)
                /* That's not SMP safe ... but who cares ? */
                ppc_spurious_interrupts++;
 
-        irq_exit();
+       irq_exit();
        set_irq_regs(old_regs);
 
 #ifdef CONFIG_PPC_ISERIES
@@ -336,7 +336,8 @@ void do_IRQ(struct pt_regs *regs)
 
 void __init init_IRQ(void)
 {
-       ppc_md.init_IRQ();
+       if (ppc_md.init_IRQ)
+               ppc_md.init_IRQ();
 #ifdef CONFIG_PPC64
        irq_ctx_init();
 #endif
@@ -417,7 +418,8 @@ irq_hw_number_t virq_to_hw(unsigned int virq)
 }
 EXPORT_SYMBOL_GPL(virq_to_hw);
 
-struct irq_host *irq_alloc_host(unsigned int revmap_type,
+__init_refok struct irq_host *irq_alloc_host(struct device_node *of_node,
+                               unsigned int revmap_type,
                                unsigned int revmap_arg,
                                struct irq_host_ops *ops,
                                irq_hw_number_t inval_irq)
@@ -445,6 +447,7 @@ struct irq_host *irq_alloc_host(unsigned int revmap_type,
        host->revmap_type = revmap_type;
        host->inval_irq = inval_irq;
        host->ops = ops;
+       host->of_node = of_node;
 
        spin_lock_irqsave(&irq_big_lock, flags);
 
@@ -596,6 +599,49 @@ static void irq_radix_rdunlock(unsigned long flags)
        local_irq_restore(flags);
 }
 
+static int irq_setup_virq(struct irq_host *host, unsigned int virq,
+                           irq_hw_number_t hwirq)
+{
+       /* Clear IRQ_NOREQUEST flag */
+       get_irq_desc(virq)->status &= ~IRQ_NOREQUEST;
+
+       /* map it */
+       smp_wmb();
+       irq_map[virq].hwirq = hwirq;
+       smp_mb();
+
+       if (host->ops->map(host, virq, hwirq)) {
+               pr_debug("irq: -> mapping failed, freeing\n");
+               irq_free_virt(virq, 1);
+               return -1;
+       }
+
+       return 0;
+}
+
+unsigned int irq_create_direct_mapping(struct irq_host *host)
+{
+       unsigned int virq;
+
+       if (host == NULL)
+               host = irq_default_host;
+
+       BUG_ON(host == NULL);
+       WARN_ON(host->revmap_type != IRQ_HOST_MAP_NOMAP);
+
+       virq = irq_alloc_virt(host, 1, 0);
+       if (virq == NO_IRQ) {
+               pr_debug("irq: create_direct virq allocation failed\n");
+               return NO_IRQ;
+       }
+
+       pr_debug("irq: create_direct obtained virq %d\n", virq);
+
+       if (irq_setup_virq(host, virq, virq))
+               return NO_IRQ;
+
+       return virq;
+}
 
 unsigned int irq_create_mapping(struct irq_host *host,
                                irq_hw_number_t hwirq)
@@ -644,18 +690,9 @@ unsigned int irq_create_mapping(struct irq_host *host,
        }
        pr_debug("irq: -> obtained virq %d\n", virq);
 
-       /* Clear IRQ_NOREQUEST flag */
-       get_irq_desc(virq)->status &= ~IRQ_NOREQUEST;
-
-       /* map it */
-       smp_wmb();
-       irq_map[virq].hwirq = hwirq;
-       smp_mb();
-       if (host->ops->map(host, virq, hwirq)) {
-               pr_debug("irq: -> mapping failed, freeing\n");
-               irq_free_virt(virq, 1);
+       if (irq_setup_virq(host, virq, hwirq))
                return NO_IRQ;
-       }
+
        return virq;
 }
 EXPORT_SYMBOL_GPL(irq_create_mapping);