Fixed a bug in the HardwareInterrupt handler that would blow the stack if you reenabl...
[mirror_edk2.git] / BeagleBoardPkg / InterruptDxe / HardwareInterrupt.c
CommitLineData
2ef2b01e
A
1/** @file\r
2 Template for Metronome Architecture Protocol driver of the ARM flavor\r
3\r
4 Copyright (c) 2008-2009, Apple Inc. All rights reserved.\r
5 \r
6 All rights reserved. This program and the accompanying materials\r
7 are licensed and made available under the terms and conditions of the BSD License\r
8 which accompanies this distribution. The full text of the license may be found at\r
9 http://opensource.org/licenses/bsd-license.php\r
10\r
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
13\r
14**/\r
15#include <PiDxe.h>\r
16\r
17#include <Library/BaseLib.h>\r
18#include <Library/DebugLib.h>\r
19#include <Library/BaseMemoryLib.h>\r
20#include <Library/UefiBootServicesTableLib.h>\r
21#include <Library/UefiLib.h>\r
22#include <Library/PcdLib.h>\r
23#include <Library/IoLib.h>\r
24\r
25#include <Protocol/Cpu.h>\r
26#include <Protocol/HardwareInterrupt.h>\r
27\r
28#include <Omap3530/Omap3530.h>\r
29\r
30//\r
31// Notifications\r
32//\r
33VOID *CpuProtocolNotificationToken = NULL;\r
34EFI_EVENT CpuProtocolNotificationEvent = (EFI_EVENT)NULL;\r
35EFI_EVENT EfiExitBootServicesEvent = (EFI_EVENT)NULL;\r
36\r
37\r
38HARDWARE_INTERRUPT_HANDLER gRegisteredInterruptHandlers[INT_NROF_VECTORS];\r
39\r
40/**\r
41 Shutdown our hardware\r
42 \r
43 DXE Core will disable interrupts and turn off the timer and disable interrupts\r
44 after all the event handlers have run.\r
45\r
46 @param[in] Event The Event that is being processed\r
47 @param[in] Context Event Context\r
48**/\r
49VOID\r
50EFIAPI\r
51ExitBootServicesEvent (\r
52 IN EFI_EVENT Event,\r
53 IN VOID *Context\r
54 )\r
55{\r
56 // Disable all interrupts\r
57 MmioWrite32(INTCPS_MIR(0), 0xFFFFFFFF);\r
58 MmioWrite32(INTCPS_MIR(1), 0xFFFFFFFF);\r
59 MmioWrite32(INTCPS_MIR(2), 0xFFFFFFFF);\r
60 MmioWrite32(INTCPS_CONTROL, INTCPS_CONTROL_NEWIRQAGR);\r
61}\r
62\r
63/**\r
64 Register Handler for the specified interrupt source.\r
65\r
66 @param This Instance pointer for this protocol\r
67 @param Source Hardware source of the interrupt\r
68 @param Handler Callback for interrupt. NULL to unregister\r
69\r
70 @retval EFI_SUCCESS Source was updated to support Handler.\r
71 @retval EFI_DEVICE_ERROR Hardware could not be programmed.\r
72\r
73**/\r
74EFI_STATUS\r
75EFIAPI\r
76RegisterInterruptSource (\r
77 IN EFI_HARDWARE_INTERRUPT_PROTOCOL *This,\r
78 IN HARDWARE_INTERRUPT_SOURCE Source,\r
79 IN HARDWARE_INTERRUPT_HANDLER Handler\r
80 )\r
81{\r
82 if (Source > MAX_VECTOR) {\r
83 ASSERT(FALSE);\r
84 return EFI_UNSUPPORTED;\r
85 } \r
86 \r
87 if ((Handler == NULL) && (gRegisteredInterruptHandlers[Source] == NULL)) {\r
88 return EFI_INVALID_PARAMETER;\r
89 }\r
90\r
91 if ((Handler != NULL) && (gRegisteredInterruptHandlers[Source] != NULL)) {\r
92 return EFI_ALREADY_STARTED;\r
93 }\r
94\r
95 gRegisteredInterruptHandlers[Source] = Handler;\r
2ef2b01e
A
96 return This->EnableInterruptSource(This, Source);\r
97}\r
98\r
99\r
100/**\r
101 Enable interrupt source Source.\r
102\r
103 @param This Instance pointer for this protocol\r
104 @param Source Hardware source of the interrupt\r
105\r
106 @retval EFI_SUCCESS Source interrupt enabled.\r
107 @retval EFI_DEVICE_ERROR Hardware could not be programmed.\r
108\r
109**/\r
110EFI_STATUS\r
111EFIAPI\r
112EnableInterruptSource (\r
113 IN EFI_HARDWARE_INTERRUPT_PROTOCOL *This,\r
114 IN HARDWARE_INTERRUPT_SOURCE Source\r
115 )\r
116{\r
117 UINTN Bank;\r
118 UINTN Bit;\r
119 \r
120 if (Source > MAX_VECTOR) {\r
121 ASSERT(FALSE);\r
122 return EFI_UNSUPPORTED;\r
123 }\r
124 \r
125 Bank = Source / 32;\r
126 Bit = 1UL << (Source % 32);\r
127 \r
128 MmioWrite32(INTCPS_MIR_CLEAR(Bank), Bit);\r
129 \r
130 return EFI_SUCCESS;\r
131}\r
132\r
133\r
134/**\r
135 Disable interrupt source Source.\r
136\r
137 @param This Instance pointer for this protocol\r
138 @param Source Hardware source of the interrupt\r
139\r
140 @retval EFI_SUCCESS Source interrupt disabled.\r
141 @retval EFI_DEVICE_ERROR Hardware could not be programmed.\r
142\r
143**/\r
144EFI_STATUS\r
145EFIAPI\r
146DisableInterruptSource(\r
147 IN EFI_HARDWARE_INTERRUPT_PROTOCOL *This,\r
148 IN HARDWARE_INTERRUPT_SOURCE Source\r
149 )\r
150{\r
151 UINTN Bank;\r
152 UINTN Bit;\r
153 \r
154 if (Source > MAX_VECTOR) {\r
155 ASSERT(FALSE);\r
156 return EFI_UNSUPPORTED;\r
157 }\r
158 \r
159 Bank = Source / 32;\r
160 Bit = 1UL << (Source % 32);\r
161 \r
162 MmioWrite32(INTCPS_MIR_SET(Bank), Bit);\r
163 \r
164 return EFI_SUCCESS;\r
165}\r
166\r
167\r
168\r
169/**\r
170 Return current state of interrupt source Source.\r
171\r
172 @param This Instance pointer for this protocol\r
173 @param Source Hardware source of the interrupt\r
174 @param InterruptState TRUE: source enabled, FALSE: source disabled.\r
175\r
176 @retval EFI_SUCCESS InterruptState is valid\r
177 @retval EFI_DEVICE_ERROR InterruptState is not valid\r
178\r
179**/\r
180EFI_STATUS\r
181EFIAPI\r
182GetInterruptSourceState (\r
183 IN EFI_HARDWARE_INTERRUPT_PROTOCOL *This,\r
184 IN HARDWARE_INTERRUPT_SOURCE Source,\r
185 IN BOOLEAN *InterruptState\r
186 )\r
187{\r
188 UINTN Bank;\r
189 UINTN Bit;\r
190 \r
191 if (InterruptState == NULL) {\r
192 return EFI_INVALID_PARAMETER;\r
193 }\r
194 \r
195 if (Source > MAX_VECTOR) {\r
196 ASSERT(FALSE);\r
197 return EFI_UNSUPPORTED;\r
198 }\r
199\r
200 Bank = Source / 32;\r
201 Bit = 1UL << (Source % 32);\r
202 \r
203 if ((MmioRead32(INTCPS_MIR(Bank)) & Bit) == Bit) {\r
204 *InterruptState = FALSE;\r
205 } else {\r
206 *InterruptState = TRUE;\r
207 }\r
208 \r
209 return EFI_SUCCESS;\r
210}\r
211\r
212\r
213\r
214/**\r
215 EFI_CPU_INTERRUPT_HANDLER that is called when a processor interrupt occurs.\r
216\r
217 @param InterruptType Defines the type of interrupt or exception that\r
218 occurred on the processor.This parameter is processor architecture specific.\r
219 @param SystemContext A pointer to the processor context when\r
220 the interrupt occurred on the processor.\r
221\r
222 @return None\r
223\r
224**/\r
225VOID\r
226EFIAPI\r
227IrqInterruptHandler (\r
228 IN EFI_EXCEPTION_TYPE InterruptType,\r
229 IN EFI_SYSTEM_CONTEXT SystemContext\r
230 )\r
231{\r
232 UINT32 Vector;\r
233 HARDWARE_INTERRUPT_HANDLER InterruptHandler;\r
234 \r
235 Vector = MmioRead32(INTCPS_SIR_IRQ) & INTCPS_SIR_IRQ_MASK;\r
236\r
d213712d
A
237 // Needed to prevent infinite nesting if Time Driver lowers TPL\r
238 MmioWrite32(INTCPS_CONTROL, INTCPS_CONTROL_NEWIRQAGR);\r
239\r
2ef2b01e
A
240 InterruptHandler = gRegisteredInterruptHandlers[Vector];\r
241 if (InterruptHandler != NULL) {\r
242 // Call the registered interrupt handler.\r
243 InterruptHandler(Vector, SystemContext);\r
244 }\r
245 \r
d213712d 246 // Needed to clear after running the handler\r
2ef2b01e
A
247 MmioWrite32(INTCPS_CONTROL, INTCPS_CONTROL_NEWIRQAGR);\r
248}\r
249\r
250//\r
251// Making this global saves a few bytes in image size\r
252//\r
253EFI_HANDLE gHardwareInterruptHandle = NULL;\r
254\r
255//\r
256// The protocol instance produced by this driver\r
257//\r
258EFI_HARDWARE_INTERRUPT_PROTOCOL gHardwareInterruptProtocol = {\r
259 RegisterInterruptSource,\r
260 EnableInterruptSource,\r
261 DisableInterruptSource,\r
262 GetInterruptSourceState\r
263};\r
264\r
265//\r
266// Notification routines\r
267//\r
268VOID\r
269CpuProtocolInstalledNotification (\r
270 IN EFI_EVENT Event,\r
271 IN VOID *Context\r
272 )\r
273{\r
274 EFI_STATUS Status;\r
275 EFI_CPU_ARCH_PROTOCOL *Cpu;\r
276 \r
277 //\r
278 // Get the cpu protocol that this driver requires.\r
279 //\r
280 Status = gBS->LocateProtocol(&gEfiCpuArchProtocolGuid, NULL, (VOID **)&Cpu);\r
281 ASSERT_EFI_ERROR(Status);\r
282\r
283 //\r
284 // Unregister the default exception handler.\r
285 //\r
286 Status = Cpu->RegisterInterruptHandler(Cpu, EXCEPT_ARM_IRQ, NULL);\r
287 ASSERT_EFI_ERROR(Status);\r
288\r
289 //\r
290 // Register to receive interrupts\r
291 //\r
292 Status = Cpu->RegisterInterruptHandler(Cpu, EXCEPT_ARM_IRQ, IrqInterruptHandler);\r
293 ASSERT_EFI_ERROR(Status);\r
294}\r
295\r
296/**\r
297 Initialize the state information for the CPU Architectural Protocol\r
298\r
299 @param ImageHandle of the loaded driver\r
300 @param SystemTable Pointer to the System Table\r
301\r
302 @retval EFI_SUCCESS Protocol registered\r
303 @retval EFI_OUT_OF_RESOURCES Cannot allocate protocol data structure\r
304 @retval EFI_DEVICE_ERROR Hardware problems\r
305\r
306**/\r
307EFI_STATUS\r
308InterruptDxeInitialize (\r
309 IN EFI_HANDLE ImageHandle,\r
310 IN EFI_SYSTEM_TABLE *SystemTable\r
311 )\r
312{\r
313 EFI_STATUS Status;\r
314\r
315 // Make sure the Interrupt Controller Protocol is not already installed in the system.\r
316 ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL, &gHardwareInterruptProtocolGuid);\r
317\r
318 // Make sure all interrupts are disabled by default.\r
319 MmioWrite32(INTCPS_MIR(0), 0xFFFFFFFF);\r
320 MmioWrite32(INTCPS_MIR(1), 0xFFFFFFFF);\r
321 MmioWrite32(INTCPS_MIR(2), 0xFFFFFFFF);\r
322 MmioWrite32(INTCPS_CONTROL, INTCPS_CONTROL_NEWIRQAGR);\r
323 \r
324 Status = gBS->InstallMultipleProtocolInterfaces(&gHardwareInterruptHandle,\r
325 &gHardwareInterruptProtocolGuid, &gHardwareInterruptProtocol,\r
326 NULL);\r
327 ASSERT_EFI_ERROR(Status);\r
328 \r
329 // Set up to be notified when the Cpu protocol is installed.\r
330 Status = gBS->CreateEvent(EVT_NOTIFY_SIGNAL, TPL_CALLBACK, CpuProtocolInstalledNotification, NULL, &CpuProtocolNotificationEvent); \r
331 ASSERT_EFI_ERROR(Status);\r
332\r
333 Status = gBS->RegisterProtocolNotify(&gEfiCpuArchProtocolGuid, CpuProtocolNotificationEvent, (VOID *)&CpuProtocolNotificationToken);\r
334 ASSERT_EFI_ERROR(Status);\r
335\r
336 // Register for an ExitBootServicesEvent\r
337 Status = gBS->CreateEvent(EVT_SIGNAL_EXIT_BOOT_SERVICES, TPL_NOTIFY, ExitBootServicesEvent, NULL, &EfiExitBootServicesEvent);\r
338 ASSERT_EFI_ERROR(Status);\r
339\r
340 return Status;\r
341}\r
342\r