[PATCH] ppc64 iSeries: remove XmPciLpEvent.c
[linux-2.6.git] / arch / ppc64 / kernel / iSeries_irq.c
index 41902e358e76a5ce9ecb7f0cb34a28122c7bb9fc..96a1f8cd67e775cd316c492a9d8110940ef7559e 100644 (file)
@@ -1,6 +1,7 @@
 /*
  * This module supports the iSeries PCI bus interrupt handling
  * Copyright (C) 20yy  <Robert L Holtorf> <IBM Corp>
+ * Copyright (C) 2004-2005 IBM Corporation
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -22,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>
 #include <linux/string.h>
 #include <linux/bootmem.h>
 #include <linux/ide.h>
-
 #include <linux/irq.h>
 #include <linux/spinlock.h>
-#include <asm/ppcdebug.h>
 
+#include <asm/ppcdebug.h>
+#include <asm/iSeries/HvTypes.h>
+#include <asm/iSeries/HvLpEvent.h>
 #include <asm/iSeries/HvCallPci.h>
 #include <asm/iSeries/HvCallXm.h>
 #include <asm/iSeries/iSeries_irq.h>
@@ -46,6 +49,169 @@ unsigned int virt_irq_to_real_map[NR_IRQS];
 /* Note: the pcnet32 driver assumes irq numbers < 2 aren't valid. :( */
 static int next_virtual_irq = 2;
 
+static long Pci_Interrupt_Count;
+static long Pci_Event_Count;
+
+enum XmPciLpEvent_Subtype {
+       XmPciLpEvent_BusCreated         = 0,    // PHB has been created
+       XmPciLpEvent_BusError           = 1,    // PHB has failed
+       XmPciLpEvent_BusFailed          = 2,    // Msg to Secondary, Primary failed bus
+       XmPciLpEvent_NodeFailed         = 4,    // Multi-adapter bridge has failed
+       XmPciLpEvent_NodeRecovered      = 5,    // Multi-adapter bridge has recovered
+       XmPciLpEvent_BusRecovered       = 12,   // PHB has been recovered
+       XmPciLpEvent_UnQuiesceBus       = 18,   // Secondary bus unqiescing
+       XmPciLpEvent_BridgeError        = 21,   // Bridge Error
+       XmPciLpEvent_SlotInterrupt      = 22    // Slot interrupt
+};
+
+struct XmPciLpEvent_BusInterrupt {
+       HvBusNumber     busNumber;
+       HvSubBusNumber  subBusNumber;
+};
+
+struct XmPciLpEvent_NodeInterrupt {
+       HvBusNumber     busNumber;
+       HvSubBusNumber  subBusNumber;
+       HvAgentId       deviceId;
+};
+
+struct XmPciLpEvent {
+       struct HvLpEvent hvLpEvent;
+
+       union {
+               u64 alignData;                  // Align on an 8-byte boundary
+
+               struct {
+                       u32             fisr;
+                       HvBusNumber     busNumber;
+                       HvSubBusNumber  subBusNumber;
+                       HvAgentId       deviceId;
+               } slotInterrupt;
+
+               struct XmPciLpEvent_BusInterrupt busFailed;
+               struct XmPciLpEvent_BusInterrupt busRecovered;
+               struct XmPciLpEvent_BusInterrupt busCreated;
+
+               struct XmPciLpEvent_NodeInterrupt nodeFailed;
+               struct XmPciLpEvent_NodeInterrupt nodeRecovered;
+
+       } eventData;
+
+};
+
+static void intReceived(struct XmPciLpEvent *eventParm,
+               struct pt_regs *regsParm)
+{
+       int irq;
+
+       ++Pci_Interrupt_Count;
+#if 0
+       PPCDBG(PPCDBG_BUSWALK, "PCI: XmPciLpEvent.c: intReceived\n");
+#endif
+
+       switch (eventParm->hvLpEvent.xSubtype) {
+       case XmPciLpEvent_SlotInterrupt:
+               irq = eventParm->hvLpEvent.xCorrelationToken;
+               /* Dispatch the interrupt handlers for this irq */
+               ppc_irq_dispatch_handler(regsParm, irq);
+               HvCallPci_eoi(eventParm->eventData.slotInterrupt.busNumber,
+                       eventParm->eventData.slotInterrupt.subBusNumber,
+                       eventParm->eventData.slotInterrupt.deviceId);
+               break;
+               /* Ignore error recovery events for now */
+       case XmPciLpEvent_BusCreated:
+               printk(KERN_INFO "XmPciLpEvent.c: system bus %d created\n",
+                       eventParm->eventData.busCreated.busNumber);
+               break;
+       case XmPciLpEvent_BusError:
+       case XmPciLpEvent_BusFailed:
+               printk(KERN_INFO "XmPciLpEvent.c: system bus %d failed\n",
+                       eventParm->eventData.busFailed.busNumber);
+               break;
+       case XmPciLpEvent_BusRecovered:
+       case XmPciLpEvent_UnQuiesceBus:
+               printk(KERN_INFO "XmPciLpEvent.c: system bus %d recovered\n",
+                       eventParm->eventData.busRecovered.busNumber);
+               break;
+       case XmPciLpEvent_NodeFailed:
+       case XmPciLpEvent_BridgeError:
+               printk(KERN_INFO
+                       "XmPciLpEvent.c: multi-adapter bridge %d/%d/%d failed\n",
+                       eventParm->eventData.nodeFailed.busNumber,
+                       eventParm->eventData.nodeFailed.subBusNumber,
+                       eventParm->eventData.nodeFailed.deviceId);
+               break;
+       case XmPciLpEvent_NodeRecovered:
+               printk(KERN_INFO
+                       "XmPciLpEvent.c: multi-adapter bridge %d/%d/%d recovered\n",
+                       eventParm->eventData.nodeRecovered.busNumber,
+                       eventParm->eventData.nodeRecovered.subBusNumber,
+                       eventParm->eventData.nodeRecovered.deviceId);
+               break;
+       default:
+               printk(KERN_ERR
+                       "XmPciLpEvent.c: unrecognized event subtype 0x%x\n",
+                       eventParm->hvLpEvent.xSubtype);
+               break;
+       }
+}
+
+static void XmPciLpEvent_handler(struct HvLpEvent *eventParm,
+               struct pt_regs *regsParm)
+{
+#ifdef CONFIG_PCI
+#if 0
+       PPCDBG(PPCDBG_BUSWALK, "XmPciLpEvent_handler, type 0x%x\n",
+                       eventParm->xType);
+#endif
+       ++Pci_Event_Count;
+
+       if (eventParm && (eventParm->xType == HvLpEvent_Type_PciIo)) {
+               switch (eventParm->xFlags.xFunction) {
+               case HvLpEvent_Function_Int:
+                       intReceived((struct XmPciLpEvent *)eventParm, regsParm);
+                       break;
+               case HvLpEvent_Function_Ack:
+                       printk(KERN_ERR
+                               "XmPciLpEvent.c: unexpected ack received\n");
+                       break;
+               default:
+                       printk(KERN_ERR
+                               "XmPciLpEvent.c: unexpected event function %d\n",
+                               (int)eventParm->xFlags.xFunction);
+                       break;
+               }
+       } else if (eventParm)
+               printk(KERN_ERR
+                       "XmPciLpEvent.c: Unrecognized PCI event type 0x%x\n",
+                       (int)eventParm->xType);
+       else
+               printk(KERN_ERR "XmPciLpEvent.c: NULL event received\n");
+#endif
+}
+
+/* This should be called sometime prior to buswalk (init_IRQ would be good) */
+int XmPciLpEvent_init()
+{
+       int xRc;
+
+       PPCDBG(PPCDBG_BUSWALK,
+                       "XmPciLpEvent_init, Register Event type 0x%04X\n",
+                       HvLpEvent_Type_PciIo);
+
+       xRc = HvLpEvent_registerHandler(HvLpEvent_Type_PciIo,
+                       &XmPciLpEvent_handler);
+       if (xRc == 0) {
+               xRc = HvLpEvent_openPath(HvLpEvent_Type_PciIo, 0);
+               if (xRc != 0)
+                       printk(KERN_ERR "XmPciLpEvent.c: open event path "
+                                       "failed with rc 0x%x\n", xRc);
+       } else
+               printk(KERN_ERR "XmPciLpEvent.c: register handler "
+                               "failed with rc 0x%x\n", xRc);
+       return xRc;
+}
+
 /* This is called by init_IRQ.  set in ppc_md.init_IRQ by iSeries_setup.c */
 void __init iSeries_init_IRQ(void)
 {