]> git.proxmox.com Git - mirror_edk2.git/blob - ArmPkg/Drivers/ArmGic/ArmGicLib.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / ArmPkg / Drivers / ArmGic / ArmGicLib.c
1 /** @file
2 *
3 * Copyright (c) 2011-2021, Arm Limited. All rights reserved.
4 *
5 * SPDX-License-Identifier: BSD-2-Clause-Patent
6 *
7 **/
8
9 #include <Base.h>
10 #include <Library/ArmGicLib.h>
11 #include <Library/ArmLib.h>
12 #include <Library/DebugLib.h>
13 #include <Library/IoLib.h>
14 #include <Library/PcdLib.h>
15
16 // In GICv3, there are 2 x 64KB frames:
17 // Redistributor control frame + SGI Control & Generation frame
18 #define GIC_V3_REDISTRIBUTOR_GRANULARITY (ARM_GICR_CTLR_FRAME_SIZE \
19 + ARM_GICR_SGI_PPI_FRAME_SIZE)
20
21 // In GICv4, there are 2 additional 64KB frames:
22 // VLPI frame + Reserved page frame
23 #define GIC_V4_REDISTRIBUTOR_GRANULARITY (GIC_V3_REDISTRIBUTOR_GRANULARITY \
24 + ARM_GICR_SGI_VLPI_FRAME_SIZE \
25 + ARM_GICR_SGI_RESERVED_FRAME_SIZE)
26
27 #define ISENABLER_ADDRESS(base, offset) ((base) +\
28 ARM_GICR_CTLR_FRAME_SIZE + ARM_GICR_ISENABLER + 4 * (offset))
29
30 #define ICENABLER_ADDRESS(base, offset) ((base) +\
31 ARM_GICR_CTLR_FRAME_SIZE + ARM_GICR_ICENABLER + 4 * (offset))
32
33 #define IPRIORITY_ADDRESS(base, offset) ((base) +\
34 ARM_GICR_CTLR_FRAME_SIZE + ARM_GIC_ICDIPR + 4 * (offset))
35
36 /**
37 *
38 * Return whether the Source interrupt index refers to a shared interrupt (SPI)
39 */
40 STATIC
41 BOOLEAN
42 SourceIsSpi (
43 IN UINTN Source
44 )
45 {
46 return Source >= 32 && Source < 1020;
47 }
48
49 /**
50 * Return the base address of the GIC redistributor for the current CPU
51 *
52 * @param Revision GIC Revision. The GIC redistributor might have a different
53 * granularity following the GIC revision.
54 *
55 * @retval Base address of the associated GIC Redistributor
56 */
57 STATIC
58 UINTN
59 GicGetCpuRedistributorBase (
60 IN UINTN GicRedistributorBase,
61 IN ARM_GIC_ARCH_REVISION Revision
62 )
63 {
64 UINTN MpId;
65 UINTN CpuAffinity;
66 UINTN Affinity;
67 UINTN GicCpuRedistributorBase;
68 UINT64 TypeRegister;
69
70 MpId = ArmReadMpidr ();
71 // Define CPU affinity as:
72 // Affinity0[0:8], Affinity1[9:15], Affinity2[16:23], Affinity3[24:32]
73 // whereas Affinity3 is defined at [32:39] in MPIDR
74 CpuAffinity = (MpId & (ARM_CORE_AFF0 | ARM_CORE_AFF1 | ARM_CORE_AFF2)) |
75 ((MpId & ARM_CORE_AFF3) >> 8);
76
77 if (Revision < ARM_GIC_ARCH_REVISION_3) {
78 ASSERT_EFI_ERROR (EFI_UNSUPPORTED);
79 return 0;
80 }
81
82 GicCpuRedistributorBase = GicRedistributorBase;
83
84 do {
85 TypeRegister = MmioRead64 (GicCpuRedistributorBase + ARM_GICR_TYPER);
86 Affinity = ARM_GICR_TYPER_GET_AFFINITY (TypeRegister);
87 if (Affinity == CpuAffinity) {
88 return GicCpuRedistributorBase;
89 }
90
91 // Move to the next GIC Redistributor frame.
92 // The GIC specification does not forbid a mixture of redistributors
93 // with or without support for virtual LPIs, so we test Virtual LPIs
94 // Support (VLPIS) bit for each frame to decide the granularity.
95 // Note: The assumption here is that the redistributors are adjacent
96 // for all CPUs. However this may not be the case for NUMA systems.
97 GicCpuRedistributorBase += (((ARM_GICR_TYPER_VLPIS & TypeRegister) != 0)
98 ? GIC_V4_REDISTRIBUTOR_GRANULARITY
99 : GIC_V3_REDISTRIBUTOR_GRANULARITY);
100 } while ((TypeRegister & ARM_GICR_TYPER_LAST) == 0);
101
102 // The Redistributor has not been found for the current CPU
103 ASSERT_EFI_ERROR (EFI_NOT_FOUND);
104 return 0;
105 }
106
107 UINTN
108 EFIAPI
109 ArmGicGetInterfaceIdentification (
110 IN INTN GicInterruptInterfaceBase
111 )
112 {
113 // Read the GIC Identification Register
114 return MmioRead32 (GicInterruptInterfaceBase + ARM_GIC_ICCIIDR);
115 }
116
117 UINTN
118 EFIAPI
119 ArmGicGetMaxNumInterrupts (
120 IN INTN GicDistributorBase
121 )
122 {
123 UINTN ItLines;
124
125 ItLines = MmioRead32 (GicDistributorBase + ARM_GIC_ICDICTR) & 0x1F;
126
127 //
128 // Interrupt ID 1020-1023 are reserved.
129 //
130 return (ItLines == 0x1f) ? 1020 : 32 * (ItLines + 1);
131 }
132
133 VOID
134 EFIAPI
135 ArmGicSendSgiTo (
136 IN INTN GicDistributorBase,
137 IN INTN TargetListFilter,
138 IN INTN CPUTargetList,
139 IN INTN SgiId
140 )
141 {
142 MmioWrite32 (
143 GicDistributorBase + ARM_GIC_ICDSGIR,
144 ((TargetListFilter & 0x3) << 24) | ((CPUTargetList & 0xFF) << 16) | SgiId
145 );
146 }
147
148 /*
149 * Acknowledge and return the value of the Interrupt Acknowledge Register
150 *
151 * InterruptId is returned separately from the register value because in
152 * the GICv2 the register value contains the CpuId and InterruptId while
153 * in the GICv3 the register value is only the InterruptId.
154 *
155 * @param GicInterruptInterfaceBase Base Address of the GIC CPU Interface
156 * @param InterruptId InterruptId read from the Interrupt
157 * Acknowledge Register
158 *
159 * @retval value returned by the Interrupt Acknowledge Register
160 *
161 */
162 UINTN
163 EFIAPI
164 ArmGicAcknowledgeInterrupt (
165 IN UINTN GicInterruptInterfaceBase,
166 OUT UINTN *InterruptId
167 )
168 {
169 UINTN Value;
170 ARM_GIC_ARCH_REVISION Revision;
171
172 Revision = ArmGicGetSupportedArchRevision ();
173 if (Revision == ARM_GIC_ARCH_REVISION_2) {
174 Value = ArmGicV2AcknowledgeInterrupt (GicInterruptInterfaceBase);
175 // InterruptId is required for the caller to know if a valid or spurious
176 // interrupt has been read
177 ASSERT (InterruptId != NULL);
178 if (InterruptId != NULL) {
179 *InterruptId = Value & ARM_GIC_ICCIAR_ACKINTID;
180 }
181 } else if (Revision == ARM_GIC_ARCH_REVISION_3) {
182 Value = ArmGicV3AcknowledgeInterrupt ();
183 } else {
184 ASSERT_EFI_ERROR (EFI_UNSUPPORTED);
185 // Report Spurious interrupt which is what the above controllers would
186 // return if no interrupt was available
187 Value = 1023;
188 }
189
190 return Value;
191 }
192
193 VOID
194 EFIAPI
195 ArmGicEndOfInterrupt (
196 IN UINTN GicInterruptInterfaceBase,
197 IN UINTN Source
198 )
199 {
200 ARM_GIC_ARCH_REVISION Revision;
201
202 Revision = ArmGicGetSupportedArchRevision ();
203 if (Revision == ARM_GIC_ARCH_REVISION_2) {
204 ArmGicV2EndOfInterrupt (GicInterruptInterfaceBase, Source);
205 } else if (Revision == ARM_GIC_ARCH_REVISION_3) {
206 ArmGicV3EndOfInterrupt (Source);
207 } else {
208 ASSERT_EFI_ERROR (EFI_UNSUPPORTED);
209 }
210 }
211
212 VOID
213 EFIAPI
214 ArmGicSetInterruptPriority (
215 IN UINTN GicDistributorBase,
216 IN UINTN GicRedistributorBase,
217 IN UINTN Source,
218 IN UINTN Priority
219 )
220 {
221 UINT32 RegOffset;
222 UINTN RegShift;
223 ARM_GIC_ARCH_REVISION Revision;
224 UINTN GicCpuRedistributorBase;
225
226 // Calculate register offset and bit position
227 RegOffset = Source / 4;
228 RegShift = (Source % 4) * 8;
229
230 Revision = ArmGicGetSupportedArchRevision ();
231 if ((Revision == ARM_GIC_ARCH_REVISION_2) ||
232 FeaturePcdGet (PcdArmGicV3WithV2Legacy) ||
233 SourceIsSpi (Source))
234 {
235 MmioAndThenOr32 (
236 GicDistributorBase + ARM_GIC_ICDIPR + (4 * RegOffset),
237 ~(0xff << RegShift),
238 Priority << RegShift
239 );
240 } else {
241 GicCpuRedistributorBase = GicGetCpuRedistributorBase (
242 GicRedistributorBase,
243 Revision
244 );
245 if (GicCpuRedistributorBase == 0) {
246 return;
247 }
248
249 MmioAndThenOr32 (
250 IPRIORITY_ADDRESS (GicCpuRedistributorBase, RegOffset),
251 ~(0xff << RegShift),
252 Priority << RegShift
253 );
254 }
255 }
256
257 VOID
258 EFIAPI
259 ArmGicEnableInterrupt (
260 IN UINTN GicDistributorBase,
261 IN UINTN GicRedistributorBase,
262 IN UINTN Source
263 )
264 {
265 UINT32 RegOffset;
266 UINTN RegShift;
267 ARM_GIC_ARCH_REVISION Revision;
268 UINTN GicCpuRedistributorBase;
269
270 // Calculate enable register offset and bit position
271 RegOffset = Source / 32;
272 RegShift = Source % 32;
273
274 Revision = ArmGicGetSupportedArchRevision ();
275 if ((Revision == ARM_GIC_ARCH_REVISION_2) ||
276 FeaturePcdGet (PcdArmGicV3WithV2Legacy) ||
277 SourceIsSpi (Source))
278 {
279 // Write set-enable register
280 MmioWrite32 (
281 GicDistributorBase + ARM_GIC_ICDISER + (4 * RegOffset),
282 1 << RegShift
283 );
284 } else {
285 GicCpuRedistributorBase = GicGetCpuRedistributorBase (
286 GicRedistributorBase,
287 Revision
288 );
289 if (GicCpuRedistributorBase == 0) {
290 ASSERT_EFI_ERROR (EFI_NOT_FOUND);
291 return;
292 }
293
294 // Write set-enable register
295 MmioWrite32 (
296 ISENABLER_ADDRESS (GicCpuRedistributorBase, RegOffset),
297 1 << RegShift
298 );
299 }
300 }
301
302 VOID
303 EFIAPI
304 ArmGicDisableInterrupt (
305 IN UINTN GicDistributorBase,
306 IN UINTN GicRedistributorBase,
307 IN UINTN Source
308 )
309 {
310 UINT32 RegOffset;
311 UINTN RegShift;
312 ARM_GIC_ARCH_REVISION Revision;
313 UINTN GicCpuRedistributorBase;
314
315 // Calculate enable register offset and bit position
316 RegOffset = Source / 32;
317 RegShift = Source % 32;
318
319 Revision = ArmGicGetSupportedArchRevision ();
320 if ((Revision == ARM_GIC_ARCH_REVISION_2) ||
321 FeaturePcdGet (PcdArmGicV3WithV2Legacy) ||
322 SourceIsSpi (Source))
323 {
324 // Write clear-enable register
325 MmioWrite32 (
326 GicDistributorBase + ARM_GIC_ICDICER + (4 * RegOffset),
327 1 << RegShift
328 );
329 } else {
330 GicCpuRedistributorBase = GicGetCpuRedistributorBase (
331 GicRedistributorBase,
332 Revision
333 );
334 if (GicCpuRedistributorBase == 0) {
335 return;
336 }
337
338 // Write clear-enable register
339 MmioWrite32 (
340 ICENABLER_ADDRESS (GicCpuRedistributorBase, RegOffset),
341 1 << RegShift
342 );
343 }
344 }
345
346 BOOLEAN
347 EFIAPI
348 ArmGicIsInterruptEnabled (
349 IN UINTN GicDistributorBase,
350 IN UINTN GicRedistributorBase,
351 IN UINTN Source
352 )
353 {
354 UINT32 RegOffset;
355 UINTN RegShift;
356 ARM_GIC_ARCH_REVISION Revision;
357 UINTN GicCpuRedistributorBase;
358 UINT32 Interrupts;
359
360 // Calculate enable register offset and bit position
361 RegOffset = Source / 32;
362 RegShift = Source % 32;
363
364 Revision = ArmGicGetSupportedArchRevision ();
365 if ((Revision == ARM_GIC_ARCH_REVISION_2) ||
366 FeaturePcdGet (PcdArmGicV3WithV2Legacy) ||
367 SourceIsSpi (Source))
368 {
369 Interrupts = MmioRead32 (
370 GicDistributorBase + ARM_GIC_ICDISER + (4 * RegOffset)
371 );
372 } else {
373 GicCpuRedistributorBase = GicGetCpuRedistributorBase (
374 GicRedistributorBase,
375 Revision
376 );
377 if (GicCpuRedistributorBase == 0) {
378 return 0;
379 }
380
381 // Read set-enable register
382 Interrupts = MmioRead32 (
383 ISENABLER_ADDRESS (GicCpuRedistributorBase, RegOffset)
384 );
385 }
386
387 return ((Interrupts & (1 << RegShift)) != 0);
388 }
389
390 VOID
391 EFIAPI
392 ArmGicDisableDistributor (
393 IN INTN GicDistributorBase
394 )
395 {
396 // Disable Gic Distributor
397 MmioWrite32 (GicDistributorBase + ARM_GIC_ICDDCR, 0x0);
398 }
399
400 VOID
401 EFIAPI
402 ArmGicEnableInterruptInterface (
403 IN INTN GicInterruptInterfaceBase
404 )
405 {
406 ARM_GIC_ARCH_REVISION Revision;
407
408 Revision = ArmGicGetSupportedArchRevision ();
409 if (Revision == ARM_GIC_ARCH_REVISION_2) {
410 ArmGicV2EnableInterruptInterface (GicInterruptInterfaceBase);
411 } else if (Revision == ARM_GIC_ARCH_REVISION_3) {
412 ArmGicV3EnableInterruptInterface ();
413 } else {
414 ASSERT_EFI_ERROR (EFI_UNSUPPORTED);
415 }
416 }
417
418 VOID
419 EFIAPI
420 ArmGicDisableInterruptInterface (
421 IN INTN GicInterruptInterfaceBase
422 )
423 {
424 ARM_GIC_ARCH_REVISION Revision;
425
426 Revision = ArmGicGetSupportedArchRevision ();
427 if (Revision == ARM_GIC_ARCH_REVISION_2) {
428 ArmGicV2DisableInterruptInterface (GicInterruptInterfaceBase);
429 } else if (Revision == ARM_GIC_ARCH_REVISION_3) {
430 ArmGicV3DisableInterruptInterface ();
431 } else {
432 ASSERT_EFI_ERROR (EFI_UNSUPPORTED);
433 }
434 }