diff options
author | Ard Biesheuvel <ardb@kernel.org> | 2024-11-14 12:43:16 +0100 |
---|---|---|
committer | Ard Biesheuvel <workofard@gmail.com> | 2024-11-23 16:39:46 +0100 |
commit | a6f1433e9598bfb7948d9af6b817e521d299a57d (patch) | |
tree | bd188a3cee55ead74683132e5c587bf912e00190 /DynamicTablesPkg | |
parent | 0d129450c2c436e047f8ee929db63224e643cc30 (diff) | |
download | edk2-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.c | 32 |
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;
|