]> 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-2018, 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 /**
34 *
35 * Return whether the Source interrupt index refers to a shared interrupt (SPI)
36 */
37 STATIC
38 BOOLEAN
39 SourceIsSpi (
40 IN UINTN Source
41 )
42 {
43 return Source >= 32 && Source < 1020;
44 }
45
46 /**
47 * Return the base address of the GIC redistributor for the current CPU
48 *
49 * @param Revision GIC Revision. The GIC redistributor might have a different
50 * granularity following the GIC revision.
51 *
52 * @retval Base address of the associated GIC Redistributor
53 */
54 STATIC
55 UINTN
56 GicGetCpuRedistributorBase (
57 IN UINTN GicRedistributorBase,
58 IN ARM_GIC_ARCH_REVISION Revision
59 )
60 {
61 UINTN MpId;
62 UINTN CpuAffinity;
63 UINTN Affinity;
64 UINTN GicCpuRedistributorBase;
65 UINT64 TypeRegister;
66
67 MpId = ArmReadMpidr ();
68 // Define CPU affinity as:
69 // Affinity0[0:8], Affinity1[9:15], Affinity2[16:23], Affinity3[24:32]
70 // whereas Affinity3 is defined at [32:39] in MPIDR
71 CpuAffinity = (MpId & (ARM_CORE_AFF0 | ARM_CORE_AFF1 | ARM_CORE_AFF2)) |
72 ((MpId & ARM_CORE_AFF3) >> 8);
73
74 if (Revision < ARM_GIC_ARCH_REVISION_3) {
75 ASSERT_EFI_ERROR (EFI_UNSUPPORTED);
76 return 0;
77 }
78
79 GicCpuRedistributorBase = GicRedistributorBase;
80
81 do {
82 TypeRegister = MmioRead64 (GicCpuRedistributorBase + ARM_GICR_TYPER);
83 Affinity = ARM_GICR_TYPER_GET_AFFINITY (TypeRegister);
84 if (Affinity == CpuAffinity) {
85 return GicCpuRedistributorBase;
86 }
87
88 // Move to the next GIC Redistributor frame.
89 // The GIC specification does not forbid a mixture of redistributors
90 // with or without support for virtual LPIs, so we test Virtual LPIs
91 // Support (VLPIS) bit for each frame to decide the granularity.
92 // Note: The assumption here is that the redistributors are adjacent
93 // for all CPUs. However this may not be the case for NUMA systems.
94 GicCpuRedistributorBase += (((ARM_GICR_TYPER_VLPIS & TypeRegister) != 0)
95 ? GIC_V4_REDISTRIBUTOR_GRANULARITY
96 : GIC_V3_REDISTRIBUTOR_GRANULARITY);
97 } while ((TypeRegister & ARM_GICR_TYPER_LAST) == 0);
98
99 // The Redistributor has not been found for the current CPU
100 ASSERT_EFI_ERROR (EFI_NOT_FOUND);
101 return 0;
102 }
103
104 UINTN
105 EFIAPI
106 ArmGicGetInterfaceIdentification (
107 IN INTN GicInterruptInterfaceBase
108 )
109 {
110 // Read the GIC Identification Register
111 return MmioRead32 (GicInterruptInterfaceBase + ARM_GIC_ICCIIDR);
112 }
113
114 UINTN
115 EFIAPI
116 ArmGicGetMaxNumInterrupts (
117 IN INTN GicDistributorBase
118 )
119 {
120 return 32 * ((MmioRead32 (GicDistributorBase + ARM_GIC_ICDICTR) & 0x1F) + 1);
121 }
122
123 VOID
124 EFIAPI
125 ArmGicSendSgiTo (
126 IN INTN GicDistributorBase,
127 IN INTN TargetListFilter,
128 IN INTN CPUTargetList,
129 IN INTN SgiId
130 )
131 {
132 MmioWrite32 (
133 GicDistributorBase + ARM_GIC_ICDSGIR,
134 ((TargetListFilter & 0x3) << 24) | ((CPUTargetList & 0xFF) << 16) | SgiId
135 );
136 }
137
138 /*
139 * Acknowledge and return the value of the Interrupt Acknowledge Register
140 *
141 * InterruptId is returned separately from the register value because in
142 * the GICv2 the register value contains the CpuId and InterruptId while
143 * in the GICv3 the register value is only the InterruptId.
144 *
145 * @param GicInterruptInterfaceBase Base Address of the GIC CPU Interface
146 * @param InterruptId InterruptId read from the Interrupt
147 * Acknowledge Register
148 *
149 * @retval value returned by the Interrupt Acknowledge Register
150 *
151 */
152 UINTN
153 EFIAPI
154 ArmGicAcknowledgeInterrupt (
155 IN UINTN GicInterruptInterfaceBase,
156 OUT UINTN *InterruptId
157 )
158 {
159 UINTN Value;
160 ARM_GIC_ARCH_REVISION Revision;
161
162 Revision = ArmGicGetSupportedArchRevision ();
163 if (Revision == ARM_GIC_ARCH_REVISION_2) {
164 Value = ArmGicV2AcknowledgeInterrupt (GicInterruptInterfaceBase);
165 // InterruptId is required for the caller to know if a valid or spurious
166 // interrupt has been read
167 ASSERT (InterruptId != NULL);
168 if (InterruptId != NULL) {
169 *InterruptId = Value & ARM_GIC_ICCIAR_ACKINTID;
170 }
171 } else if (Revision == ARM_GIC_ARCH_REVISION_3) {
172 Value = ArmGicV3AcknowledgeInterrupt ();
173 } else {
174 ASSERT_EFI_ERROR (EFI_UNSUPPORTED);
175 // Report Spurious interrupt which is what the above controllers would
176 // return if no interrupt was available
177 Value = 1023;
178 }
179
180 return Value;
181 }
182
183 VOID
184 EFIAPI
185 ArmGicEndOfInterrupt (
186 IN UINTN GicInterruptInterfaceBase,
187 IN UINTN Source
188 )
189 {
190 ARM_GIC_ARCH_REVISION Revision;
191
192 Revision = ArmGicGetSupportedArchRevision ();
193 if (Revision == ARM_GIC_ARCH_REVISION_2) {
194 ArmGicV2EndOfInterrupt (GicInterruptInterfaceBase, Source);
195 } else if (Revision == ARM_GIC_ARCH_REVISION_3) {
196 ArmGicV3EndOfInterrupt (Source);
197 } else {
198 ASSERT_EFI_ERROR (EFI_UNSUPPORTED);
199 }
200 }
201
202 VOID
203 EFIAPI
204 ArmGicEnableInterrupt (
205 IN UINTN GicDistributorBase,
206 IN UINTN GicRedistributorBase,
207 IN UINTN Source
208 )
209 {
210 UINT32 RegOffset;
211 UINTN RegShift;
212 ARM_GIC_ARCH_REVISION Revision;
213 UINTN GicCpuRedistributorBase;
214
215 // Calculate enable register offset and bit position
216 RegOffset = Source / 32;
217 RegShift = Source % 32;
218
219 Revision = ArmGicGetSupportedArchRevision ();
220 if ((Revision == ARM_GIC_ARCH_REVISION_2) ||
221 FeaturePcdGet (PcdArmGicV3WithV2Legacy) ||
222 SourceIsSpi (Source)) {
223 // Write set-enable register
224 MmioWrite32 (
225 GicDistributorBase + ARM_GIC_ICDISER + (4 * RegOffset),
226 1 << RegShift
227 );
228 } else {
229 GicCpuRedistributorBase = GicGetCpuRedistributorBase (
230 GicRedistributorBase,
231 Revision
232 );
233 if (GicCpuRedistributorBase == 0) {
234 ASSERT_EFI_ERROR (EFI_NOT_FOUND);
235 return;
236 }
237
238 // Write set-enable register
239 MmioWrite32 (
240 ISENABLER_ADDRESS(GicCpuRedistributorBase, RegOffset),
241 1 << RegShift
242 );
243 }
244 }
245
246 VOID
247 EFIAPI
248 ArmGicDisableInterrupt (
249 IN UINTN GicDistributorBase,
250 IN UINTN GicRedistributorBase,
251 IN UINTN Source
252 )
253 {
254 UINT32 RegOffset;
255 UINTN RegShift;
256 ARM_GIC_ARCH_REVISION Revision;
257 UINTN GicCpuRedistributorBase;
258
259 // Calculate enable register offset and bit position
260 RegOffset = Source / 32;
261 RegShift = Source % 32;
262
263 Revision = ArmGicGetSupportedArchRevision ();
264 if ((Revision == ARM_GIC_ARCH_REVISION_2) ||
265 FeaturePcdGet (PcdArmGicV3WithV2Legacy) ||
266 SourceIsSpi (Source)) {
267 // Write clear-enable register
268 MmioWrite32 (
269 GicDistributorBase + ARM_GIC_ICDICER + (4 * RegOffset),
270 1 << RegShift
271 );
272 } else {
273 GicCpuRedistributorBase = GicGetCpuRedistributorBase (
274 GicRedistributorBase,
275 Revision
276 );
277 if (GicCpuRedistributorBase == 0) {
278 return;
279 }
280
281 // Write clear-enable register
282 MmioWrite32 (
283 ICENABLER_ADDRESS(GicCpuRedistributorBase, RegOffset),
284 1 << RegShift
285 );
286 }
287 }
288
289 BOOLEAN
290 EFIAPI
291 ArmGicIsInterruptEnabled (
292 IN UINTN GicDistributorBase,
293 IN UINTN GicRedistributorBase,
294 IN UINTN Source
295 )
296 {
297 UINT32 RegOffset;
298 UINTN RegShift;
299 ARM_GIC_ARCH_REVISION Revision;
300 UINTN GicCpuRedistributorBase;
301 UINT32 Interrupts;
302
303 // Calculate enable register offset and bit position
304 RegOffset = Source / 32;
305 RegShift = Source % 32;
306
307 Revision = ArmGicGetSupportedArchRevision ();
308 if ((Revision == ARM_GIC_ARCH_REVISION_2) ||
309 FeaturePcdGet (PcdArmGicV3WithV2Legacy) ||
310 SourceIsSpi (Source)) {
311 Interrupts = ((MmioRead32 (
312 GicDistributorBase + ARM_GIC_ICDISER + (4 * RegOffset)
313 )
314 & (1 << RegShift)) != 0);
315 } else {
316 GicCpuRedistributorBase = GicGetCpuRedistributorBase (
317 GicRedistributorBase,
318 Revision
319 );
320 if (GicCpuRedistributorBase == 0) {
321 return 0;
322 }
323
324 // Read set-enable register
325 Interrupts = MmioRead32 (
326 ISENABLER_ADDRESS(GicCpuRedistributorBase, RegOffset)
327 );
328 }
329
330 return ((Interrupts & (1 << RegShift)) != 0);
331 }
332
333 VOID
334 EFIAPI
335 ArmGicDisableDistributor (
336 IN INTN GicDistributorBase
337 )
338 {
339 // Disable Gic Distributor
340 MmioWrite32 (GicDistributorBase + ARM_GIC_ICDDCR, 0x0);
341 }
342
343 VOID
344 EFIAPI
345 ArmGicEnableInterruptInterface (
346 IN INTN GicInterruptInterfaceBase
347 )
348 {
349 ARM_GIC_ARCH_REVISION Revision;
350
351 Revision = ArmGicGetSupportedArchRevision ();
352 if (Revision == ARM_GIC_ARCH_REVISION_2) {
353 ArmGicV2EnableInterruptInterface (GicInterruptInterfaceBase);
354 } else if (Revision == ARM_GIC_ARCH_REVISION_3) {
355 ArmGicV3EnableInterruptInterface ();
356 } else {
357 ASSERT_EFI_ERROR (EFI_UNSUPPORTED);
358 }
359 }
360
361 VOID
362 EFIAPI
363 ArmGicDisableInterruptInterface (
364 IN INTN GicInterruptInterfaceBase
365 )
366 {
367 ARM_GIC_ARCH_REVISION Revision;
368
369 Revision = ArmGicGetSupportedArchRevision ();
370 if (Revision == ARM_GIC_ARCH_REVISION_2) {
371 ArmGicV2DisableInterruptInterface (GicInterruptInterfaceBase);
372 } else if (Revision == ARM_GIC_ARCH_REVISION_3) {
373 ArmGicV3DisableInterruptInterface ();
374 } else {
375 ASSERT_EFI_ERROR (EFI_UNSUPPORTED);
376 }
377 }