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