[PATCH] ppc64 iSeries: irq simple cleanups
[linux-2.6.git] / arch / ppc64 / kernel / XmPciLpEvent.c
1 /*
2  * File XmPciLpEvent.c created by Wayne Holm on Mon Jan 15 2001.
3  *
4  * This module handles PCI interrupt events sent by the iSeries Hypervisor.
5  */
6 #include <linux/config.h>
7 #include <linux/pci.h>
8 #include <linux/init.h>
9 #include <linux/threads.h>
10 #include <linux/smp.h>
11 #include <linux/param.h>
12 #include <linux/string.h>
13 #include <linux/bootmem.h>
14 #include <linux/ide.h>
15
16 #include <asm/iSeries/HvTypes.h>
17 #include <asm/iSeries/HvLpEvent.h>
18 #include <asm/iSeries/HvCallPci.h>
19 #include <asm/iSeries/iSeries_irq.h>
20 #include <asm/ppcdebug.h>
21
22 static long Pci_Interrupt_Count;
23 static long Pci_Event_Count;
24
25 enum XmPciLpEvent_Subtype {
26         XmPciLpEvent_BusCreated         = 0,    // PHB has been created
27         XmPciLpEvent_BusError           = 1,    // PHB has failed
28         XmPciLpEvent_BusFailed          = 2,    // Msg to Secondary, Primary failed bus
29         XmPciLpEvent_NodeFailed         = 4,    // Multi-adapter bridge has failed
30         XmPciLpEvent_NodeRecovered      = 5,    // Multi-adapter bridge has recovered
31         XmPciLpEvent_BusRecovered       = 12,   // PHB has been recovered
32         XmPciLpEvent_UnQuiesceBus       = 18,   // Secondary bus unqiescing
33         XmPciLpEvent_BridgeError        = 21,   // Bridge Error
34         XmPciLpEvent_SlotInterrupt      = 22    // Slot interrupt
35 };
36
37 struct XmPciLpEvent_BusInterrupt {
38         HvBusNumber     busNumber;
39         HvSubBusNumber  subBusNumber;
40 };
41
42 struct XmPciLpEvent_NodeInterrupt {
43         HvBusNumber     busNumber;
44         HvSubBusNumber  subBusNumber;
45         HvAgentId       deviceId;
46 };
47
48 struct XmPciLpEvent {
49         struct HvLpEvent hvLpEvent;
50
51         union {
52                 u64 alignData;                  // Align on an 8-byte boundary
53
54                 struct {
55                         u32             fisr;
56                         HvBusNumber     busNumber;
57                         HvSubBusNumber  subBusNumber;
58                         HvAgentId       deviceId;
59                 } slotInterrupt;
60
61                 struct XmPciLpEvent_BusInterrupt busFailed;
62                 struct XmPciLpEvent_BusInterrupt busRecovered;
63                 struct XmPciLpEvent_BusInterrupt busCreated;
64
65                 struct XmPciLpEvent_NodeInterrupt nodeFailed;
66                 struct XmPciLpEvent_NodeInterrupt nodeRecovered;
67
68         } eventData;
69
70 };
71
72 static void intReceived(struct XmPciLpEvent *eventParm,
73                 struct pt_regs *regsParm)
74 {
75         int irq;
76
77         ++Pci_Interrupt_Count;
78 #if 0
79         PPCDBG(PPCDBG_BUSWALK, "PCI: XmPciLpEvent.c: intReceived\n");
80 #endif
81
82         switch (eventParm->hvLpEvent.xSubtype) {
83         case XmPciLpEvent_SlotInterrupt:
84                 irq = eventParm->hvLpEvent.xCorrelationToken;
85                 /* Dispatch the interrupt handlers for this irq */
86                 ppc_irq_dispatch_handler(regsParm, irq);
87                 HvCallPci_eoi(eventParm->eventData.slotInterrupt.busNumber,
88                         eventParm->eventData.slotInterrupt.subBusNumber,
89                         eventParm->eventData.slotInterrupt.deviceId);
90                 break;
91                 /* Ignore error recovery events for now */
92         case XmPciLpEvent_BusCreated:
93                 printk(KERN_INFO "XmPciLpEvent.c: system bus %d created\n",
94                         eventParm->eventData.busCreated.busNumber);
95                 break;
96         case XmPciLpEvent_BusError:
97         case XmPciLpEvent_BusFailed:
98                 printk(KERN_INFO "XmPciLpEvent.c: system bus %d failed\n",
99                         eventParm->eventData.busFailed.busNumber);
100                 break;
101         case XmPciLpEvent_BusRecovered:
102         case XmPciLpEvent_UnQuiesceBus:
103                 printk(KERN_INFO "XmPciLpEvent.c: system bus %d recovered\n",
104                         eventParm->eventData.busRecovered.busNumber);
105                 break;
106         case XmPciLpEvent_NodeFailed:
107         case XmPciLpEvent_BridgeError:
108                 printk(KERN_INFO
109                         "XmPciLpEvent.c: multi-adapter bridge %d/%d/%d failed\n",
110                         eventParm->eventData.nodeFailed.busNumber,
111                         eventParm->eventData.nodeFailed.subBusNumber,
112                         eventParm->eventData.nodeFailed.deviceId);
113                 break;
114         case XmPciLpEvent_NodeRecovered:
115                 printk(KERN_INFO
116                         "XmPciLpEvent.c: multi-adapter bridge %d/%d/%d recovered\n",
117                         eventParm->eventData.nodeRecovered.busNumber,
118                         eventParm->eventData.nodeRecovered.subBusNumber,
119                         eventParm->eventData.nodeRecovered.deviceId);
120                 break;
121         default:
122                 printk(KERN_ERR
123                         "XmPciLpEvent.c: unrecognized event subtype 0x%x\n",
124                         eventParm->hvLpEvent.xSubtype);
125                 break;
126         }
127 }
128
129 static void XmPciLpEvent_handler(struct HvLpEvent *eventParm,
130                 struct pt_regs *regsParm)
131 {
132 #ifdef CONFIG_PCI
133 #if 0
134         PPCDBG(PPCDBG_BUSWALK, "XmPciLpEvent_handler, type 0x%x\n",
135                         eventParm->xType);
136 #endif
137         ++Pci_Event_Count;
138
139         if (eventParm && (eventParm->xType == HvLpEvent_Type_PciIo)) {
140                 switch (eventParm->xFlags.xFunction) {
141                 case HvLpEvent_Function_Int:
142                         intReceived((struct XmPciLpEvent *)eventParm, regsParm);
143                         break;
144                 case HvLpEvent_Function_Ack:
145                         printk(KERN_ERR
146                                 "XmPciLpEvent.c: unexpected ack received\n");
147                         break;
148                 default:
149                         printk(KERN_ERR
150                                 "XmPciLpEvent.c: unexpected event function %d\n",
151                                 (int)eventParm->xFlags.xFunction);
152                         break;
153                 }
154         } else if (eventParm)
155                 printk(KERN_ERR
156                         "XmPciLpEvent.c: Unrecognized PCI event type 0x%x\n",
157                         (int)eventParm->xType);
158         else
159                 printk(KERN_ERR "XmPciLpEvent.c: NULL event received\n");
160 #endif
161 }
162
163 /* This should be called sometime prior to buswalk (init_IRQ would be good) */
164 int XmPciLpEvent_init()
165 {
166         int xRc;
167
168         PPCDBG(PPCDBG_BUSWALK,
169                         "XmPciLpEvent_init, Register Event type 0x%04X\n",
170                         HvLpEvent_Type_PciIo);
171
172         xRc = HvLpEvent_registerHandler(HvLpEvent_Type_PciIo,
173                         &XmPciLpEvent_handler);
174         if (xRc == 0) {
175                 xRc = HvLpEvent_openPath(HvLpEvent_Type_PciIo, 0);
176                 if (xRc != 0)
177                         printk(KERN_ERR "XmPciLpEvent.c: open event path "
178                                         "failed with rc 0x%x\n", xRc);
179         } else
180                 printk(KERN_ERR "XmPciLpEvent.c: register handler "
181                                 "failed with rc 0x%x\n", xRc);
182         return xRc;
183 }