TianoCore EDK2 master
Loading...
Searching...
No Matches
ArmGicLib.c
Go to the documentation of this file.
1
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
41BOOLEAN
43 IN UINTN Source
44 )
45{
46 return Source >= 32 && Source < 1020;
47}
48
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
114UINT32
115EFIAPI
117 IN UINTN GicInterruptInterfaceBase
118 )
119{
120 // Read the GIC Identification Register
121 return MmioRead32 (GicInterruptInterfaceBase + ARM_GIC_ICCIIDR);
122}
123
124UINTN
125EFIAPI
126ArmGicGetMaxNumInterrupts (
127 IN UINTN GicDistributorBase
128 )
129{
130 UINTN ItLines;
131
132 ItLines = MmioRead32 (GicDistributorBase + ARM_GIC_ICDICTR) & 0x1F;
133
134 //
135 // Interrupt ID 1020-1023 are reserved.
136 //
137 return (ItLines == 0x1f) ? 1020 : 32 * (ItLines + 1);
138}
139
140VOID
141EFIAPI
142ArmGicSendSgiTo (
143 IN UINTN GicDistributorBase,
144 IN UINT8 TargetListFilter,
145 IN UINT8 CPUTargetList,
146 IN UINT8 SgiId
147 )
148{
150 GicDistributorBase + ARM_GIC_ICDSGIR,
151 ((TargetListFilter & 0x3) << 24) |
152 ((CPUTargetList & 0xFF) << 16) |
153 (SgiId & 0xF)
154 );
155}
156
157/*
158 * Acknowledge and return the value of the Interrupt Acknowledge Register
159 *
160 * InterruptId is returned separately from the register value because in
161 * the GICv2 the register value contains the CpuId and InterruptId while
162 * in the GICv3 the register value is only the InterruptId.
163 *
164 * @param GicInterruptInterfaceBase Base Address of the GIC CPU Interface
165 * @param InterruptId InterruptId read from the Interrupt
166 * Acknowledge Register
167 *
168 * @retval value returned by the Interrupt Acknowledge Register
169 *
170 */
171UINTN
172EFIAPI
173ArmGicAcknowledgeInterrupt (
174 IN UINTN GicInterruptInterfaceBase,
175 OUT UINTN *InterruptId
176 )
177{
178 UINTN Value;
179 UINTN IntId;
180 ARM_GIC_ARCH_REVISION Revision;
181
182 ASSERT (InterruptId != NULL);
183 Revision = ArmGicGetSupportedArchRevision ();
184 if (Revision == ARM_GIC_ARCH_REVISION_2) {
185 Value = ArmGicV2AcknowledgeInterrupt (GicInterruptInterfaceBase);
186 IntId = Value & ARM_GIC_ICCIAR_ACKINTID;
187 } else if (Revision == ARM_GIC_ARCH_REVISION_3) {
188 Value = ArmGicV3AcknowledgeInterrupt ();
189 IntId = Value;
190 } else {
191 ASSERT_EFI_ERROR (EFI_UNSUPPORTED);
192 // Report Spurious interrupt which is what the above controllers would
193 // return if no interrupt was available
194 Value = 1023;
195 }
196
197 if (InterruptId != NULL) {
198 // InterruptId is required for the caller to know if a valid or spurious
199 // interrupt has been read
200 *InterruptId = IntId;
201 }
202
203 return Value;
204}
205
206VOID
207EFIAPI
208ArmGicEndOfInterrupt (
209 IN UINTN GicInterruptInterfaceBase,
210 IN UINTN Source
211 )
212{
213 ARM_GIC_ARCH_REVISION Revision;
214
215 Revision = ArmGicGetSupportedArchRevision ();
216 if (Revision == ARM_GIC_ARCH_REVISION_2) {
217 ArmGicV2EndOfInterrupt (GicInterruptInterfaceBase, Source);
218 } else if (Revision == ARM_GIC_ARCH_REVISION_3) {
219 ArmGicV3EndOfInterrupt (Source);
220 } else {
221 ASSERT_EFI_ERROR (EFI_UNSUPPORTED);
222 }
223}
224
225VOID
226EFIAPI
227ArmGicSetInterruptPriority (
228 IN UINTN GicDistributorBase,
229 IN UINTN GicRedistributorBase,
230 IN UINTN Source,
231 IN UINT32 Priority
232 )
233{
234 UINT32 RegOffset;
235 UINT8 RegShift;
236 ARM_GIC_ARCH_REVISION Revision;
237 UINTN GicCpuRedistributorBase;
238
239 // Calculate register offset and bit position
240 RegOffset = (UINT32)(Source / 4);
241 RegShift = (UINT8)((Source % 4) * 8);
242
243 Revision = ArmGicGetSupportedArchRevision ();
244 if ((Revision == ARM_GIC_ARCH_REVISION_2) ||
245 FeaturePcdGet (PcdArmGicV3WithV2Legacy) ||
246 SourceIsSpi (Source))
247 {
249 GicDistributorBase + ARM_GIC_ICDIPR + (4 * RegOffset),
250 ~(0xff << RegShift),
251 Priority << RegShift
252 );
253 } else {
254 GicCpuRedistributorBase = GicGetCpuRedistributorBase (
255 GicRedistributorBase,
256 Revision
257 );
258 if (GicCpuRedistributorBase == 0) {
259 return;
260 }
261
263 IPRIORITY_ADDRESS (GicCpuRedistributorBase, RegOffset),
264 ~(0xff << RegShift),
265 Priority << RegShift
266 );
267 }
268}
269
270VOID
271EFIAPI
272ArmGicEnableInterrupt (
273 IN UINTN GicDistributorBase,
274 IN UINTN GicRedistributorBase,
275 IN UINTN Source
276 )
277{
278 UINT32 RegOffset;
279 UINT8 RegShift;
280 ARM_GIC_ARCH_REVISION Revision;
281 UINTN GicCpuRedistributorBase;
282
283 // Calculate enable register offset and bit position
284 RegOffset = (UINT32)(Source / 32);
285 RegShift = (UINT8)(Source % 32);
286
287 Revision = ArmGicGetSupportedArchRevision ();
288 if ((Revision == ARM_GIC_ARCH_REVISION_2) ||
289 FeaturePcdGet (PcdArmGicV3WithV2Legacy) ||
290 SourceIsSpi (Source))
291 {
292 // Write set-enable register
294 GicDistributorBase + ARM_GIC_ICDISER + (4 * RegOffset),
295 1 << RegShift
296 );
297 } else {
298 GicCpuRedistributorBase = GicGetCpuRedistributorBase (
299 GicRedistributorBase,
300 Revision
301 );
302 if (GicCpuRedistributorBase == 0) {
303 ASSERT_EFI_ERROR (EFI_NOT_FOUND);
304 return;
305 }
306
307 // Write set-enable register
309 ISENABLER_ADDRESS (GicCpuRedistributorBase, RegOffset),
310 1 << RegShift
311 );
312 }
313}
314
315VOID
316EFIAPI
317ArmGicDisableInterrupt (
318 IN UINTN GicDistributorBase,
319 IN UINTN GicRedistributorBase,
320 IN UINTN Source
321 )
322{
323 UINT32 RegOffset;
324 UINT8 RegShift;
325 ARM_GIC_ARCH_REVISION Revision;
326 UINTN GicCpuRedistributorBase;
327
328 // Calculate enable register offset and bit position
329 RegOffset = (UINT32)(Source / 32);
330 RegShift = (UINT8)(Source % 32);
331
332 Revision = ArmGicGetSupportedArchRevision ();
333 if ((Revision == ARM_GIC_ARCH_REVISION_2) ||
334 FeaturePcdGet (PcdArmGicV3WithV2Legacy) ||
335 SourceIsSpi (Source))
336 {
337 // Write clear-enable register
339 GicDistributorBase + ARM_GIC_ICDICER + (4 * RegOffset),
340 1 << RegShift
341 );
342 } else {
343 GicCpuRedistributorBase = GicGetCpuRedistributorBase (
344 GicRedistributorBase,
345 Revision
346 );
347 if (GicCpuRedistributorBase == 0) {
348 return;
349 }
350
351 // Write clear-enable register
353 ICENABLER_ADDRESS (GicCpuRedistributorBase, RegOffset),
354 1 << RegShift
355 );
356 }
357}
358
359BOOLEAN
360EFIAPI
361ArmGicIsInterruptEnabled (
362 IN UINTN GicDistributorBase,
363 IN UINTN GicRedistributorBase,
364 IN UINTN Source
365 )
366{
367 UINT32 RegOffset;
368 UINT8 RegShift;
369 ARM_GIC_ARCH_REVISION Revision;
370 UINTN GicCpuRedistributorBase;
371 UINT32 Interrupts;
372
373 // Calculate enable register offset and bit position
374 RegOffset = (UINT32)(Source / 32);
375 RegShift = (UINT8)(Source % 32);
376
377 Revision = ArmGicGetSupportedArchRevision ();
378 if ((Revision == ARM_GIC_ARCH_REVISION_2) ||
379 FeaturePcdGet (PcdArmGicV3WithV2Legacy) ||
380 SourceIsSpi (Source))
381 {
382 Interrupts = MmioRead32 (
383 GicDistributorBase + ARM_GIC_ICDISER + (4 * RegOffset)
384 );
385 } else {
386 GicCpuRedistributorBase = GicGetCpuRedistributorBase (
387 GicRedistributorBase,
388 Revision
389 );
390 if (GicCpuRedistributorBase == 0) {
391 return 0;
392 }
393
394 // Read set-enable register
395 Interrupts = MmioRead32 (
396 ISENABLER_ADDRESS (GicCpuRedistributorBase, RegOffset)
397 );
398 }
399
400 return ((Interrupts & (1 << RegShift)) != 0);
401}
402
403VOID
404EFIAPI
405ArmGicDisableDistributor (
406 IN UINTN GicDistributorBase
407 )
408{
409 // Disable Gic Distributor
410 MmioWrite32 (GicDistributorBase + ARM_GIC_ICDDCR, 0x0);
411}
412
413VOID
414EFIAPI
415ArmGicEnableInterruptInterface (
416 IN UINTN GicInterruptInterfaceBase
417 )
418{
419 ARM_GIC_ARCH_REVISION Revision;
420
421 Revision = ArmGicGetSupportedArchRevision ();
422 if (Revision == ARM_GIC_ARCH_REVISION_2) {
423 ArmGicV2EnableInterruptInterface (GicInterruptInterfaceBase);
424 } else if (Revision == ARM_GIC_ARCH_REVISION_3) {
425 ArmGicV3EnableInterruptInterface ();
426 } else {
427 ASSERT_EFI_ERROR (EFI_UNSUPPORTED);
428 }
429}
430
431VOID
432EFIAPI
433ArmGicDisableInterruptInterface (
434 IN UINTN GicInterruptInterfaceBase
435 )
436{
437 ARM_GIC_ARCH_REVISION Revision;
438
439 Revision = ArmGicGetSupportedArchRevision ();
440 if (Revision == ARM_GIC_ARCH_REVISION_2) {
441 ArmGicV2DisableInterruptInterface (GicInterruptInterfaceBase);
442 } else if (Revision == ARM_GIC_ARCH_REVISION_3) {
443 ArmGicV3DisableInterruptInterface ();
444 } else {
445 ASSERT_EFI_ERROR (EFI_UNSUPPORTED);
446 }
447}
UINT64 UINTN
UINT32 EFIAPI ArmGicGetInterfaceIdentification(IN UINTN GicInterruptInterfaceBase)
Definition: ArmGicLib.c:116
STATIC UINTN GicGetCpuRedistributorBase(IN UINTN GicRedistributorBase, IN ARM_GIC_ARCH_REVISION Revision)
Definition: ArmGicLib.c:59
STATIC BOOLEAN SourceIsSpi(IN UINTN Source)
Definition: ArmGicLib.c:42
UINT64 EFIAPI MmioRead64(IN UINTN Address)
Definition: IoLib.c:355
UINT32 EFIAPI MmioRead32(IN UINTN Address)
Definition: IoLib.c:262
UINT32 EFIAPI MmioAndThenOr32(IN UINTN Address, IN UINT32 AndData, IN UINT32 OrData)
Definition: IoHighLevel.c:1845
UINT32 EFIAPI MmioWrite32(IN UINTN Address, IN UINT32 Value)
Definition: IoLib.c:309
#define NULL
Definition: Base.h:319
#define STATIC
Definition: Base.h:264
#define IN
Definition: Base.h:279
#define OUT
Definition: Base.h:284
#define ASSERT_EFI_ERROR(StatusParameter)
Definition: DebugLib.h:462
#define FeaturePcdGet(TokenName)
Definition: PcdLib.h:50