]> git.proxmox.com Git - mirror_edk2.git/blame - ArmPkg/Drivers/ArmGic/ArmGicCommonDxe.c
ArmPkg/Gic: force GIC driver to run before CPU arch protocol driver
[mirror_edk2.git] / ArmPkg / Drivers / ArmGic / ArmGicCommonDxe.c
CommitLineData
69b5dc9f
OM
1/*++\r
2\r
b0393756 3Copyright (c) 2013-2017, ARM Ltd. All rights reserved.<BR>\r
69b5dc9f
OM
4\r
5This program and the accompanying materials\r
6are licensed and made available under the terms and conditions of the BSD License\r
7which accompanies this distribution. The full text of the license may be found at\r
8http://opensource.org/licenses/bsd-license.php\r
9\r
10THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12\r
13--*/\r
14\r
15#include "ArmGicDxe.h"\r
16\r
17VOID\r
18EFIAPI\r
19IrqInterruptHandler (\r
20 IN EFI_EXCEPTION_TYPE InterruptType,\r
21 IN EFI_SYSTEM_CONTEXT SystemContext\r
22 );\r
23\r
24VOID\r
25EFIAPI\r
26ExitBootServicesEvent (\r
27 IN EFI_EVENT Event,\r
28 IN VOID *Context\r
29 );\r
30\r
69b5dc9f 31// Making this global saves a few bytes in image size\r
69b5dc9f
OM
32EFI_HANDLE gHardwareInterruptHandle = NULL;\r
33\r
69b5dc9f 34// Notifications\r
69b5dc9f
OM
35EFI_EVENT EfiExitBootServicesEvent = (EFI_EVENT)NULL;\r
36\r
37// Maximum Number of Interrupts\r
38UINTN mGicNumInterrupts = 0;\r
39\r
40HARDWARE_INTERRUPT_HANDLER *gRegisteredInterruptHandlers = NULL;\r
41\r
8659306a
AB
42\r
43/**\r
44 Calculate GICD_ICFGRn base address and corresponding bit\r
45 field Int_config[1] of the GIC distributor register.\r
46\r
47 @param Source Hardware source of the interrupt.\r
48 @param RegAddress Corresponding GICD_ICFGRn base address.\r
49 @param Config1Bit Bit number of F Int_config[1] bit in the register.\r
50\r
51 @retval EFI_SUCCESS Source interrupt supported.\r
52 @retval EFI_UNSUPPORTED Source interrupt is not supported.\r
53**/\r
54EFI_STATUS\r
55GicGetDistributorIcfgBaseAndBit (\r
56 IN HARDWARE_INTERRUPT_SOURCE Source,\r
57 OUT UINTN *RegAddress,\r
58 OUT UINTN *Config1Bit\r
59 )\r
60{\r
61 UINTN RegIndex;\r
62 UINTN Field;\r
63\r
64 if (Source >= mGicNumInterrupts) {\r
65 ASSERT(Source < mGicNumInterrupts);\r
66 return EFI_UNSUPPORTED;\r
67 }\r
68\r
69 RegIndex = Source / ARM_GIC_ICDICFR_F_STRIDE; // NOTE: truncation is significant\r
70 Field = Source % ARM_GIC_ICDICFR_F_STRIDE;\r
71 *RegAddress = PcdGet64 (PcdGicDistributorBase)\r
72 + ARM_GIC_ICDICFR\r
73 + (ARM_GIC_ICDICFR_BYTES * RegIndex);\r
74 *Config1Bit = ((Field * ARM_GIC_ICDICFR_F_WIDTH)\r
75 + ARM_GIC_ICDICFR_F_CONFIG1_BIT);\r
76\r
77 return EFI_SUCCESS;\r
78}\r
79\r
80\r
81\r
0458b423
OM
82/**\r
83 Register Handler for the specified interrupt source.\r
84\r
85 @param This Instance pointer for this protocol\r
86 @param Source Hardware source of the interrupt\r
87 @param Handler Callback for interrupt. NULL to unregister\r
88\r
89 @retval EFI_SUCCESS Source was updated to support Handler.\r
90 @retval EFI_DEVICE_ERROR Hardware could not be programmed.\r
91\r
92**/\r
93EFI_STATUS\r
94EFIAPI\r
95RegisterInterruptSource (\r
96 IN EFI_HARDWARE_INTERRUPT_PROTOCOL *This,\r
97 IN HARDWARE_INTERRUPT_SOURCE Source,\r
98 IN HARDWARE_INTERRUPT_HANDLER Handler\r
99 )\r
100{\r
599f004b 101 if (Source >= mGicNumInterrupts) {\r
0458b423
OM
102 ASSERT(FALSE);\r
103 return EFI_UNSUPPORTED;\r
104 }\r
105\r
106 if ((Handler == NULL) && (gRegisteredInterruptHandlers[Source] == NULL)) {\r
107 return EFI_INVALID_PARAMETER;\r
108 }\r
109\r
110 if ((Handler != NULL) && (gRegisteredInterruptHandlers[Source] != NULL)) {\r
111 return EFI_ALREADY_STARTED;\r
112 }\r
113\r
114 gRegisteredInterruptHandlers[Source] = Handler;\r
115\r
116 // If the interrupt handler is unregistered then disable the interrupt\r
117 if (NULL == Handler){\r
118 return This->DisableInterruptSource (This, Source);\r
119 } else {\r
120 return This->EnableInterruptSource (This, Source);\r
121 }\r
122}\r
123\r
61a7b0ec
AB
124STATIC VOID *mCpuArchProtocolNotifyEventRegistration;\r
125\r
126STATIC\r
127VOID\r
128EFIAPI\r
129CpuArchEventProtocolNotify (\r
130 IN EFI_EVENT Event,\r
131 IN VOID *Context\r
132 )\r
133{\r
134 EFI_CPU_ARCH_PROTOCOL *Cpu;\r
135 EFI_STATUS Status;\r
136\r
137 // Get the CPU protocol that this driver requires.\r
138 Status = gBS->LocateProtocol (&gEfiCpuArchProtocolGuid, NULL, (VOID **)&Cpu);\r
139 if (EFI_ERROR (Status)) {\r
140 return;\r
141 }\r
142\r
143 // Unregister the default exception handler.\r
144 Status = Cpu->RegisterInterruptHandler (Cpu, ARM_ARCH_EXCEPTION_IRQ, NULL);\r
145 if (EFI_ERROR (Status)) {\r
146 DEBUG ((DEBUG_ERROR, "%a: Cpu->RegisterInterruptHandler() - %r\n",\r
147 __FUNCTION__, Status));\r
148 return;\r
149 }\r
150\r
151 // Register to receive interrupts\r
152 Status = Cpu->RegisterInterruptHandler (Cpu, ARM_ARCH_EXCEPTION_IRQ,\r
153 Context);\r
154 if (EFI_ERROR (Status)) {\r
155 DEBUG ((DEBUG_ERROR, "%a: Cpu->RegisterInterruptHandler() - %r\n",\r
156 __FUNCTION__, Status));\r
157 }\r
158\r
159 gBS->CloseEvent (Event);\r
160}\r
161\r
69b5dc9f
OM
162EFI_STATUS\r
163InstallAndRegisterInterruptService (\r
164 IN EFI_HARDWARE_INTERRUPT_PROTOCOL *InterruptProtocol,\r
8659306a 165 IN EFI_HARDWARE_INTERRUPT2_PROTOCOL *Interrupt2Protocol,\r
69b5dc9f
OM
166 IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler,\r
167 IN EFI_EVENT_NOTIFY ExitBootServicesEvent\r
168 )\r
169{\r
170 EFI_STATUS Status;\r
b0393756
EL
171 CONST UINTN RihArraySize =\r
172 (sizeof(HARDWARE_INTERRUPT_HANDLER) * mGicNumInterrupts);\r
69b5dc9f
OM
173\r
174 // Initialize the array for the Interrupt Handlers\r
b0393756 175 gRegisteredInterruptHandlers = AllocateZeroPool (RihArraySize);\r
69b5dc9f
OM
176 if (gRegisteredInterruptHandlers == NULL) {\r
177 return EFI_OUT_OF_RESOURCES;\r
178 }\r
179\r
180 Status = gBS->InstallMultipleProtocolInterfaces (\r
181 &gHardwareInterruptHandle,\r
b0393756
EL
182 &gHardwareInterruptProtocolGuid,\r
183 InterruptProtocol,\r
8659306a
AB
184 &gHardwareInterrupt2ProtocolGuid,\r
185 Interrupt2Protocol,\r
69b5dc9f
OM
186 NULL\r
187 );\r
188 if (EFI_ERROR (Status)) {\r
189 return Status;\r
190 }\r
191\r
61a7b0ec
AB
192 //\r
193 // Install the interrupt handler as soon as the CPU arch protocol appears.\r
194 //\r
195 EfiCreateProtocolNotifyEvent (\r
196 &gEfiCpuArchProtocolGuid,\r
197 TPL_CALLBACK,\r
198 CpuArchEventProtocolNotify,\r
199 InterruptHandler,\r
200 &mCpuArchProtocolNotifyEventRegistration);\r
69b5dc9f
OM
201\r
202 // Register for an ExitBootServicesEvent\r
b0393756
EL
203 Status = gBS->CreateEvent (\r
204 EVT_SIGNAL_EXIT_BOOT_SERVICES,\r
205 TPL_NOTIFY,\r
206 ExitBootServicesEvent,\r
207 NULL,\r
208 &EfiExitBootServicesEvent\r
209 );\r
69b5dc9f
OM
210\r
211 return Status;\r
212}\r