linux 2.6.16.38 w/ vs2.0.3-rc1
[linux-2.6.git] / arch / powerpc / platforms / iseries / irq.c
index e324468..be3fbfc 100644 (file)
@@ -23,6 +23,7 @@
  *   Created, December 13, 2000 by Wayne Holm
  * End Change Activity
  */
+#include <linux/config.h>
 #include <linux/pci.h>
 #include <linux/init.h>
 #include <linux/threads.h>
@@ -41,7 +42,6 @@
 #include <asm/iseries/it_lp_queue.h>
 
 #include "irq.h"
-#include "pci.h"
 #include "call_pci.h"
 
 #if defined(CONFIG_SMP)
@@ -162,6 +162,27 @@ static void pci_event_handler(struct HvLpEvent *event, struct pt_regs *regs)
                printk(KERN_ERR "pci_event_handler: NULL event received\n");
 }
 
+/*
+ * This is called by init_IRQ.  set in ppc_md.init_IRQ by iSeries_setup.c
+ * It must be called before the bus walk.
+ */
+void __init iSeries_init_IRQ(void)
+{
+       /* Register PCI event handler and open an event path */
+       int ret;
+
+       ret = HvLpEvent_registerHandler(HvLpEvent_Type_PciIo,
+                       &pci_event_handler);
+       if (ret == 0) {
+               ret = HvLpEvent_openPath(HvLpEvent_Type_PciIo, 0);
+               if (ret != 0)
+                       printk(KERN_ERR "iseries_init_IRQ: open event path "
+                                       "failed with rc 0x%x\n", ret);
+       } else
+               printk(KERN_ERR "iseries_init_IRQ: register handler "
+                               "failed with rc 0x%x\n", ret);
+}
+
 #define REAL_IRQ_TO_SUBBUS(irq)        (((irq) >> 14) & 0xff)
 #define REAL_IRQ_TO_BUS(irq)   ((((irq) >> 6) & 0xff) + 1)
 #define REAL_IRQ_TO_IDSEL(irq) ((((irq) >> 3) & 7) + 1)
@@ -175,7 +196,7 @@ static void iseries_enable_IRQ(unsigned int irq)
 {
        u32 bus, dev_id, function, mask;
        const u32 sub_bus = 0;
-       unsigned int rirq = (unsigned int)irq_map[irq].hwirq;
+       unsigned int rirq = virt_irq_to_real_map[irq];
 
        /* The IRQ has already been locked by the caller */
        bus = REAL_IRQ_TO_BUS(rirq);
@@ -192,7 +213,7 @@ static unsigned int iseries_startup_IRQ(unsigned int irq)
 {
        u32 bus, dev_id, function, mask;
        const u32 sub_bus = 0;
-       unsigned int rirq = (unsigned int)irq_map[irq].hwirq;
+       unsigned int rirq = virt_irq_to_real_map[irq];
 
        bus = REAL_IRQ_TO_BUS(rirq);
        function = REAL_IRQ_TO_FUNC(rirq);
@@ -220,9 +241,9 @@ void __init iSeries_activate_IRQs()
        for_each_irq (irq) {
                irq_desc_t *desc = get_irq_desc(irq);
 
-               if (desc && desc->chip && desc->chip->startup) {
+               if (desc && desc->handler && desc->handler->startup) {
                        spin_lock_irqsave(&desc->lock, flags);
-                       desc->chip->startup(irq);
+                       desc->handler->startup(irq);
                        spin_unlock_irqrestore(&desc->lock, flags);
                }
        }
@@ -233,7 +254,7 @@ static void iseries_shutdown_IRQ(unsigned int irq)
 {
        u32 bus, dev_id, function, mask;
        const u32 sub_bus = 0;
-       unsigned int rirq = (unsigned int)irq_map[irq].hwirq;
+       unsigned int rirq = virt_irq_to_real_map[irq];
 
        /* irq should be locked by the caller */
        bus = REAL_IRQ_TO_BUS(rirq);
@@ -256,7 +277,7 @@ static void iseries_disable_IRQ(unsigned int irq)
 {
        u32 bus, dev_id, function, mask;
        const u32 sub_bus = 0;
-       unsigned int rirq = (unsigned int)irq_map[irq].hwirq;
+       unsigned int rirq = virt_irq_to_real_map[irq];
 
        /* The IRQ has already been locked by the caller */
        bus = REAL_IRQ_TO_BUS(rirq);
@@ -270,19 +291,19 @@ static void iseries_disable_IRQ(unsigned int irq)
 
 static void iseries_end_IRQ(unsigned int irq)
 {
-       unsigned int rirq = (unsigned int)irq_map[irq].hwirq;
+       unsigned int rirq = virt_irq_to_real_map[irq];
 
        HvCallPci_eoi(REAL_IRQ_TO_BUS(rirq), REAL_IRQ_TO_SUBBUS(rirq),
                (REAL_IRQ_TO_IDSEL(rirq) << 4) + REAL_IRQ_TO_FUNC(rirq));
 }
 
-static struct irq_chip iseries_pic = {
-       .typename       = "iSeries irq controller",
-       .startup        = iseries_startup_IRQ,
-       .shutdown       = iseries_shutdown_IRQ,
-       .unmask         = iseries_enable_IRQ,
-       .mask           = iseries_disable_IRQ,
-       .eoi            = iseries_end_IRQ
+static hw_irq_controller iSeries_IRQ_handler = {
+       .typename = "iSeries irq controller",
+       .startup = iseries_startup_IRQ,
+       .shutdown = iseries_shutdown_IRQ,
+       .enable = iseries_enable_IRQ,
+       .disable = iseries_disable_IRQ,
+       .end = iseries_end_IRQ
 };
 
 /*
@@ -291,16 +312,19 @@ static struct irq_chip iseries_pic = {
  * Note that sub_bus is always 0 (at the moment at least).
  */
 int __init iSeries_allocate_IRQ(HvBusNumber bus,
-               HvSubBusNumber sub_bus, u32 bsubbus)
+               HvSubBusNumber sub_bus, HvAgentId dev_id)
 {
+       int virtirq;
        unsigned int realirq;
-       u8 idsel = ISERIES_GET_DEVICE_FROM_SUBBUS(bsubbus);
-       u8 function = ISERIES_GET_FUNCTION_FROM_SUBBUS(bsubbus);
+       u8 idsel = (dev_id >> 4);
+       u8 function = dev_id & 7;
 
        realirq = (((((sub_bus << 8) + (bus - 1)) << 3) + (idsel - 1)) << 3)
                + function;
+       virtirq = virt_irq_create_mapping(realirq);
 
-       return irq_create_mapping(NULL, realirq);
+       irq_desc[virtirq].handler = &iSeries_IRQ_handler;
+       return virtirq;
 }
 
 #endif /* CONFIG_PCI */
@@ -308,9 +332,10 @@ int __init iSeries_allocate_IRQ(HvBusNumber bus,
 /*
  * Get the next pending IRQ.
  */
-unsigned int iSeries_get_irq(struct pt_regs *regs)
+int iSeries_get_irq(struct pt_regs *regs)
 {
-       int irq = NO_IRQ_IGNORE;
+       /* -2 means ignore this interrupt */
+       int irq = -2;
 
 #ifdef CONFIG_SMP
        if (get_lppaca()->int_dword.fields.ipi_cnt) {
@@ -333,57 +358,9 @@ unsigned int iSeries_get_irq(struct pt_regs *regs)
                }
                spin_unlock(&pending_irqs_lock);
                if (irq >= NR_IRQS)
-                       irq = NO_IRQ_IGNORE;
+                       irq = -2;
        }
 #endif
 
        return irq;
 }
-
-static int iseries_irq_host_map(struct irq_host *h, unsigned int virq,
-                               irq_hw_number_t hw)
-{
-       set_irq_chip_and_handler(virq, &iseries_pic, handle_fasteoi_irq);
-
-       return 0;
-}
-
-static struct irq_host_ops iseries_irq_host_ops = {
-       .map = iseries_irq_host_map,
-};
-
-/*
- * This is called by init_IRQ.  set in ppc_md.init_IRQ by iSeries_setup.c
- * It must be called before the bus walk.
- */
-void __init iSeries_init_IRQ(void)
-{
-       /* Register PCI event handler and open an event path */
-       struct irq_host *host;
-       int ret;
-
-       /*
-        * The Hypervisor only allows us up to 256 interrupt
-        * sources (the irq number is passed in a u8).
-        */
-       irq_set_virq_count(256);
-
-       /* Create irq host. No need for a revmap since HV will give us
-        * back our virtual irq number
-        */
-       host = irq_alloc_host(IRQ_HOST_MAP_NOMAP, 0, &iseries_irq_host_ops, 0);
-       BUG_ON(host == NULL);
-       irq_set_default_host(host);
-
-       ret = HvLpEvent_registerHandler(HvLpEvent_Type_PciIo,
-                       &pci_event_handler);
-       if (ret == 0) {
-               ret = HvLpEvent_openPath(HvLpEvent_Type_PciIo, 0);
-               if (ret != 0)
-                       printk(KERN_ERR "iseries_init_IRQ: open event path "
-                                       "failed with rc 0x%x\n", ret);
-       } else
-               printk(KERN_ERR "iseries_init_IRQ: register handler "
-                               "failed with rc 0x%x\n", ret);
-}
-