summaryrefslogtreecommitdiffstats
path: root/DynamicTablesPkg
diff options
context:
space:
mode:
authorArd Biesheuvel <ardb@kernel.org>2024-11-14 12:43:16 +0100
committerArd Biesheuvel <workofard@gmail.com>2024-11-23 16:39:46 +0100
commita6f1433e9598bfb7948d9af6b817e521d299a57d (patch)
treebd188a3cee55ead74683132e5c587bf912e00190 /DynamicTablesPkg
parent0d129450c2c436e047f8ee929db63224e643cc30 (diff)
downloadedk2-a6f1433e9598bfb7948d9af6b817e521d299a57d.tar.gz
DynamicTablesPkg/ArmGicCParser: Parse VGIC interrupt for all CPUs
There are two issues in the GIC FDT parsing code: - the GICC Flags 'Enabled' bit is overwritten when parsing the VGIC Maintenance Interrupt, whose trigger type occupies another bit in the same field; - only the first CPU's Flags field is updated. This breaks both SMP boot and KVM support on Linux, given that the boot CPU is disabled in the MADT, and the VGIC maintenance interrupt is set to 0x0 on all others. Fix this, by OR'ing the trigger type into the field, and by iterating over all discovered CPUs. Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
Diffstat (limited to 'DynamicTablesPkg')
-rw-r--r--DynamicTablesPkg/Library/FdtHwInfoParserLib/Arm/Gic/ArmGicCParser.c32
1 files changed, 21 insertions, 11 deletions
diff --git a/DynamicTablesPkg/Library/FdtHwInfoParserLib/Arm/Gic/ArmGicCParser.c b/DynamicTablesPkg/Library/FdtHwInfoParserLib/Arm/Gic/ArmGicCParser.c
index 3955219146..f74e5d5fef 100644
--- a/DynamicTablesPkg/Library/FdtHwInfoParserLib/Arm/Gic/ArmGicCParser.c
+++ b/DynamicTablesPkg/Library/FdtHwInfoParserLib/Arm/Gic/ArmGicCParser.c
@@ -167,7 +167,8 @@ CpusNodeParser (
IN CONST VOID *Fdt,
IN INT32 CpusNode,
IN UINT32 GicVersion,
- OUT CM_OBJ_DESCRIPTOR **NewGicCmObjDesc
+ OUT CM_OBJ_DESCRIPTOR **NewGicCmObjDesc,
+ OUT UINTN *CpuCount
)
{
EFI_STATUS Status;
@@ -202,6 +203,8 @@ CpusNodeParser (
return EFI_NOT_FOUND;
}
+ *CpuCount = CpuNodeCount;
+
// Allocate memory for CpuNodeCount CM_ARM_GICC_INFO structures.
GicCInfoBufferSize = CpuNodeCount * sizeof (CM_ARM_GICC_INFO);
GicCInfoBuffer = AllocateZeroPool (GicCInfoBufferSize);
@@ -280,6 +283,7 @@ EFIAPI
GicCIntcNodeParser (
IN CONST VOID *Fdt,
IN INT32 GicIntcNode,
+ IN UINTN CpuCount,
IN OUT CM_OBJ_DESCRIPTOR *GicCCmObjDesc
)
{
@@ -289,6 +293,8 @@ GicCIntcNodeParser (
CONST UINT8 *Data;
INT32 DataSize;
+ UINT32 MaintenanceInterrupt;
+ UINT32 Flags;
if (GicCCmObjDesc == NULL) {
ASSERT (0);
@@ -308,14 +314,17 @@ GicCIntcNodeParser (
// but it is assumed that only one Gic is available.
Data = fdt_getprop (Fdt, GicIntcNode, "interrupts", &DataSize);
if ((Data != NULL) && (DataSize == (IntCells * sizeof (UINT32)))) {
- GicCInfo = (CM_ARM_GICC_INFO *)GicCCmObjDesc->Data;
- GicCInfo->VGICMaintenanceInterrupt =
- FdtGetInterruptId ((CONST UINT32 *)Data);
- GicCInfo->Flags = DT_IRQ_IS_EDGE_TRIGGERED (
- fdt32_to_cpu (((UINT32 *)Data)[IRQ_FLAGS_OFFSET])
- ) ?
- EFI_ACPI_6_3_VGIC_MAINTENANCE_INTERRUPT_MODE_FLAGS :
- 0;
+ MaintenanceInterrupt = FdtGetInterruptId ((CONST UINT32 *)Data);
+ Flags = DT_IRQ_IS_EDGE_TRIGGERED (
+ fdt32_to_cpu (((UINT32 *)Data)[IRQ_FLAGS_OFFSET])
+ ) ?
+ EFI_ACPI_6_3_VGIC_MAINTENANCE_INTERRUPT_MODE_FLAGS :
+ 0;
+ for (GicCInfo = (CM_ARM_GICC_INFO *)GicCCmObjDesc->Data; CpuCount--; GicCInfo++) {
+ GicCInfo->VGICMaintenanceInterrupt = MaintenanceInterrupt;
+ GicCInfo->Flags |= Flags;
+ }
+
return Status;
} else if (DataSize < 0) {
// This property is optional and was not found. Just return.
@@ -816,6 +825,7 @@ ArmGicCInfoParser (
UINT32 GicVersion;
CM_OBJ_DESCRIPTOR *NewCmObjDesc;
VOID *Fdt;
+ UINTN CpuCount;
if (FdtParserHandle == NULL) {
ASSERT (0);
@@ -846,7 +856,7 @@ ArmGicCInfoParser (
// Parse the "cpus" nodes and its children "cpu" nodes,
// and create a CM_OBJ_DESCRIPTOR.
- Status = CpusNodeParser (Fdt, FdtBranch, GicVersion, &NewCmObjDesc);
+ Status = CpusNodeParser (Fdt, FdtBranch, GicVersion, &NewCmObjDesc, &CpuCount);
if (EFI_ERROR (Status)) {
ASSERT (0);
return Status;
@@ -878,7 +888,7 @@ ArmGicCInfoParser (
}
// Parse the Gic information common to Gic v2 and v3.
- Status = GicCIntcNodeParser (Fdt, IntcNode, NewCmObjDesc);
+ Status = GicCIntcNodeParser (Fdt, IntcNode, CpuCount, NewCmObjDesc);
if (EFI_ERROR (Status)) {
ASSERT (0);
goto exit_handler;