]> git.proxmox.com Git - mirror_edk2.git/blob - ArmPkg/Drivers/ArmGic/GicV3/ArmGicV3Dxe.c
ArmPkg: Tidy GIC code before changes.
[mirror_edk2.git] / ArmPkg / Drivers / ArmGic / GicV3 / ArmGicV3Dxe.c
1 /** @file
2 *
3 * Copyright (c) 2011-2017, ARM Limited. All rights reserved.
4 *
5 * This program and the accompanying materials
6 * are licensed and made available under the terms and conditions of the BSD License
7 * which accompanies this distribution. The full text of the license may be found at
8 * http://opensource.org/licenses/bsd-license.php
9 *
10 * THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12 *
13 **/
14
15 #include <Library/ArmGicLib.h>
16
17 #include "ArmGicDxe.h"
18
19 #define ARM_GIC_DEFAULT_PRIORITY 0x80
20
21 extern EFI_HARDWARE_INTERRUPT_PROTOCOL gHardwareInterruptV3Protocol;
22
23 STATIC UINTN mGicDistributorBase;
24 STATIC UINTN mGicRedistributorsBase;
25
26 /**
27 Enable interrupt source Source.
28
29 @param This Instance pointer for this protocol
30 @param Source Hardware source of the interrupt
31
32 @retval EFI_SUCCESS Source interrupt enabled.
33 @retval EFI_DEVICE_ERROR Hardware could not be programmed.
34
35 **/
36 STATIC
37 EFI_STATUS
38 EFIAPI
39 GicV3EnableInterruptSource (
40 IN EFI_HARDWARE_INTERRUPT_PROTOCOL *This,
41 IN HARDWARE_INTERRUPT_SOURCE Source
42 )
43 {
44 if (Source >= mGicNumInterrupts) {
45 ASSERT(FALSE);
46 return EFI_UNSUPPORTED;
47 }
48
49 ArmGicEnableInterrupt (mGicDistributorBase, mGicRedistributorsBase, Source);
50
51 return EFI_SUCCESS;
52 }
53
54 /**
55 Disable interrupt source Source.
56
57 @param This Instance pointer for this protocol
58 @param Source Hardware source of the interrupt
59
60 @retval EFI_SUCCESS Source interrupt disabled.
61 @retval EFI_DEVICE_ERROR Hardware could not be programmed.
62
63 **/
64 STATIC
65 EFI_STATUS
66 EFIAPI
67 GicV3DisableInterruptSource (
68 IN EFI_HARDWARE_INTERRUPT_PROTOCOL *This,
69 IN HARDWARE_INTERRUPT_SOURCE Source
70 )
71 {
72 if (Source >= mGicNumInterrupts) {
73 ASSERT(FALSE);
74 return EFI_UNSUPPORTED;
75 }
76
77 ArmGicDisableInterrupt (mGicDistributorBase, mGicRedistributorsBase, Source);
78
79 return EFI_SUCCESS;
80 }
81
82 /**
83 Return current state of interrupt source Source.
84
85 @param This Instance pointer for this protocol
86 @param Source Hardware source of the interrupt
87 @param InterruptState TRUE: source enabled, FALSE: source disabled.
88
89 @retval EFI_SUCCESS InterruptState is valid
90 @retval EFI_DEVICE_ERROR InterruptState is not valid
91
92 **/
93 STATIC
94 EFI_STATUS
95 EFIAPI
96 GicV3GetInterruptSourceState (
97 IN EFI_HARDWARE_INTERRUPT_PROTOCOL *This,
98 IN HARDWARE_INTERRUPT_SOURCE Source,
99 IN BOOLEAN *InterruptState
100 )
101 {
102 if (Source >= mGicNumInterrupts) {
103 ASSERT(FALSE);
104 return EFI_UNSUPPORTED;
105 }
106
107 *InterruptState = ArmGicIsInterruptEnabled (
108 mGicDistributorBase,
109 mGicRedistributorsBase,
110 Source
111 );
112
113 return EFI_SUCCESS;
114 }
115
116 /**
117 Signal to the hardware that the End Of Interrupt state
118 has been reached.
119
120 @param This Instance pointer for this protocol
121 @param Source Hardware source of the interrupt
122
123 @retval EFI_SUCCESS Source interrupt EOI'ed.
124 @retval EFI_DEVICE_ERROR Hardware could not be programmed.
125
126 **/
127 STATIC
128 EFI_STATUS
129 EFIAPI
130 GicV3EndOfInterrupt (
131 IN EFI_HARDWARE_INTERRUPT_PROTOCOL *This,
132 IN HARDWARE_INTERRUPT_SOURCE Source
133 )
134 {
135 if (Source >= mGicNumInterrupts) {
136 ASSERT(FALSE);
137 return EFI_UNSUPPORTED;
138 }
139
140 ArmGicV3EndOfInterrupt (Source);
141 return EFI_SUCCESS;
142 }
143
144 /**
145 EFI_CPU_INTERRUPT_HANDLER that is called when a processor interrupt occurs.
146
147 @param InterruptType Defines the type of interrupt or exception that
148 occurred on the processor. This parameter is
149 processor architecture specific.
150 @param SystemContext A pointer to the processor context when
151 the interrupt occurred on the processor.
152
153 @return None
154
155 **/
156 STATIC
157 VOID
158 EFIAPI
159 GicV3IrqInterruptHandler (
160 IN EFI_EXCEPTION_TYPE InterruptType,
161 IN EFI_SYSTEM_CONTEXT SystemContext
162 )
163 {
164 UINT32 GicInterrupt;
165 HARDWARE_INTERRUPT_HANDLER InterruptHandler;
166
167 GicInterrupt = ArmGicV3AcknowledgeInterrupt ();
168
169 // Special Interrupts (ID1020-ID1023) have an Interrupt ID greater than the
170 // number of interrupt (ie: Spurious interrupt).
171 if ((GicInterrupt & ARM_GIC_ICCIAR_ACKINTID) >= mGicNumInterrupts) {
172 // The special interrupt do not need to be acknowledge
173 return;
174 }
175
176 InterruptHandler = gRegisteredInterruptHandlers[GicInterrupt];
177 if (InterruptHandler != NULL) {
178 // Call the registered interrupt handler.
179 InterruptHandler (GicInterrupt, SystemContext);
180 } else {
181 DEBUG ((DEBUG_ERROR, "Spurious GIC interrupt: 0x%x\n", GicInterrupt));
182 GicV3EndOfInterrupt (&gHardwareInterruptV3Protocol, GicInterrupt);
183 }
184 }
185
186 // The protocol instance produced by this driver
187 EFI_HARDWARE_INTERRUPT_PROTOCOL gHardwareInterruptV3Protocol = {
188 RegisterInterruptSource,
189 GicV3EnableInterruptSource,
190 GicV3DisableInterruptSource,
191 GicV3GetInterruptSourceState,
192 GicV3EndOfInterrupt
193 };
194
195 /**
196 Shutdown our hardware
197
198 DXE Core will disable interrupts and turn off the timer and disable interrupts
199 after all the event handlers have run.
200
201 @param[in] Event The Event that is being processed
202 @param[in] Context Event Context
203 **/
204 VOID
205 EFIAPI
206 GicV3ExitBootServicesEvent (
207 IN EFI_EVENT Event,
208 IN VOID *Context
209 )
210 {
211 UINTN Index;
212
213 // Acknowledge all pending interrupts
214 for (Index = 0; Index < mGicNumInterrupts; Index++) {
215 GicV3DisableInterruptSource (&gHardwareInterruptV3Protocol, Index);
216 }
217
218 for (Index = 0; Index < mGicNumInterrupts; Index++) {
219 GicV3EndOfInterrupt (&gHardwareInterruptV3Protocol, Index);
220 }
221
222 // Disable Gic Interface
223 ArmGicV3DisableInterruptInterface ();
224
225 // Disable Gic Distributor
226 ArmGicDisableDistributor (mGicDistributorBase);
227 }
228
229 /**
230 Initialize the state information for the CPU Architectural Protocol
231
232 @param ImageHandle of the loaded driver
233 @param SystemTable Pointer to the System Table
234
235 @retval EFI_SUCCESS Protocol registered
236 @retval EFI_OUT_OF_RESOURCES Cannot allocate protocol data structure
237 @retval EFI_DEVICE_ERROR Hardware problems
238
239 **/
240 EFI_STATUS
241 GicV3DxeInitialize (
242 IN EFI_HANDLE ImageHandle,
243 IN EFI_SYSTEM_TABLE *SystemTable
244 )
245 {
246 EFI_STATUS Status;
247 UINTN Index;
248 UINT32 RegOffset;
249 UINTN RegShift;
250 UINT64 CpuTarget;
251 UINT64 MpId;
252
253 // Make sure the Interrupt Controller Protocol is not already installed in
254 // the system.
255 ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL, &gHardwareInterruptProtocolGuid);
256
257 mGicDistributorBase = PcdGet64 (PcdGicDistributorBase);
258 mGicRedistributorsBase = PcdGet64 (PcdGicRedistributorsBase);
259 mGicNumInterrupts = ArmGicGetMaxNumInterrupts (mGicDistributorBase);
260
261 // We will be driving this GIC in native v3 mode, i.e., with Affinity
262 // Routing enabled. So ensure that the ARE bit is set.
263 if (!FeaturePcdGet (PcdArmGicV3WithV2Legacy)) {
264 MmioOr32 (mGicDistributorBase + ARM_GIC_ICDDCR, ARM_GIC_ICDDCR_ARE);
265 }
266
267 for (Index = 0; Index < mGicNumInterrupts; Index++) {
268 GicV3DisableInterruptSource (&gHardwareInterruptV3Protocol, Index);
269
270 // Set Priority
271 RegOffset = Index / 4;
272 RegShift = (Index % 4) * 8;
273 MmioAndThenOr32 (
274 mGicDistributorBase + ARM_GIC_ICDIPR + (4 * RegOffset),
275 ~(0xff << RegShift),
276 ARM_GIC_DEFAULT_PRIORITY << RegShift
277 );
278 }
279
280 // Targets the interrupts to the Primary Cpu
281
282 if (FeaturePcdGet (PcdArmGicV3WithV2Legacy)) {
283 // Only Primary CPU will run this code. We can identify our GIC CPU ID by
284 // reading the GIC Distributor Target register. The 8 first
285 // GICD_ITARGETSRn are banked to each connected CPU. These 8 registers
286 // hold the CPU targets fields for interrupts 0-31. More Info in the GIC
287 // Specification about "Interrupt Processor Targets Registers"
288
289 // Read the first Interrupt Processor Targets Register (that corresponds
290 // to the 4 first SGIs)
291 CpuTarget = MmioRead32 (mGicDistributorBase + ARM_GIC_ICDIPTR);
292
293 // The CPU target is a bit field mapping each CPU to a GIC CPU Interface.
294 // This value is 0 when we run on a uniprocessor platform.
295 if (CpuTarget != 0) {
296 // The 8 first Interrupt Processor Targets Registers are read-only
297 for (Index = 8; Index < (mGicNumInterrupts / 4); Index++) {
298 MmioWrite32 (
299 mGicDistributorBase + ARM_GIC_ICDIPTR + (Index * 4),
300 CpuTarget
301 );
302 }
303 }
304 } else {
305 MpId = ArmReadMpidr ();
306 CpuTarget = MpId &
307 (ARM_CORE_AFF0 | ARM_CORE_AFF1 | ARM_CORE_AFF2 | ARM_CORE_AFF3);
308
309 if ((MmioRead32 (
310 mGicDistributorBase + ARM_GIC_ICDDCR
311 ) & ARM_GIC_ICDDCR_DS) != 0) {
312
313 // If the Disable Security (DS) control bit is set, we are dealing with a
314 // GIC that has only one security state. In this case, let's assume we are
315 // executing in non-secure state (which is appropriate for DXE modules)
316 // and that no other firmware has performed any configuration on the GIC.
317 // This means we need to reconfigure all interrupts to non-secure Group 1
318 // first.
319
320 MmioWrite32 (
321 mGicRedistributorsBase + ARM_GICR_CTLR_FRAME_SIZE + ARM_GIC_ICDISR,
322 0xffffffff
323 );
324
325 for (Index = 32; Index < mGicNumInterrupts; Index += 32) {
326 MmioWrite32 (
327 mGicDistributorBase + ARM_GIC_ICDISR + Index / 8,
328 0xffffffff
329 );
330 }
331 }
332
333 // Route the SPIs to the primary CPU. SPIs start at the INTID 32
334 for (Index = 0; Index < (mGicNumInterrupts - 32); Index++) {
335 MmioWrite32 (
336 mGicDistributorBase + ARM_GICD_IROUTER + (Index * 8),
337 CpuTarget | ARM_GICD_IROUTER_IRM
338 );
339 }
340 }
341
342 // Set binary point reg to 0x7 (no preemption)
343 ArmGicV3SetBinaryPointer (0x7);
344
345 // Set priority mask reg to 0xff to allow all priorities through
346 ArmGicV3SetPriorityMask (0xff);
347
348 // Enable gic cpu interface
349 ArmGicV3EnableInterruptInterface ();
350
351 // Enable gic distributor
352 ArmGicEnableDistributor (mGicDistributorBase);
353
354 Status = InstallAndRegisterInterruptService (
355 &gHardwareInterruptV3Protocol,
356 GicV3IrqInterruptHandler,
357 GicV3ExitBootServicesEvent
358 );
359
360 return Status;
361 }