From 41fb5d4634c17c042e0a3b2be0e8db85d2a083ad Mon Sep 17 00:00:00 2001 From: Olivier Martin Date: Mon, 16 Feb 2015 10:23:42 +0000 Subject: [PATCH] ArmPkg/ArmGic: Use the GIC Redistributor instead of GIC Distributor for GICv3 GICv3 controller with no GICv2 legacy support must use the GIC Redistributor registers instead of the GIC Distributor registers for some operations (eg: enable/disable interrupts). Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Olivier Martin Tested-by: Ard Biesheuvel Reviewed-by: Ard Biesheuvel git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@16874 6f19259b-4bc3-4df7-8a09-765794883524 --- ArmPkg/Drivers/ArmGic/ArmGicLib.c | 68 +++++++++++++++++++---- ArmPkg/Drivers/ArmGic/ArmGicNonSecLib.c | 11 +++- ArmPkg/Drivers/ArmGic/GicV2/ArmGicV2Dxe.c | 8 +-- ArmPkg/Drivers/ArmGic/GicV3/ArmGicV3Dxe.c | 31 ++++------- ArmPkg/Drivers/ArmGic/GicV3/ArmGicV3Lib.h | 4 +- ArmPkg/Include/Library/ArmGicLib.h | 3 + 6 files changed, 87 insertions(+), 38 deletions(-) diff --git a/ArmPkg/Drivers/ArmGic/ArmGicLib.c b/ArmPkg/Drivers/ArmGic/ArmGicLib.c index 1e213019fe..7c53e39793 100644 --- a/ArmPkg/Drivers/ArmGic/ArmGicLib.c +++ b/ArmPkg/Drivers/ArmGic/ArmGicLib.c @@ -172,53 +172,99 @@ VOID EFIAPI ArmGicEnableInterrupt ( IN UINTN GicDistributorBase, + IN UINTN GicRedistributorBase, IN UINTN Source ) { - UINT32 RegOffset; - UINTN RegShift; + UINT32 RegOffset; + UINTN RegShift; + ARM_GIC_ARCH_REVISION Revision; + UINTN GicCpuRedistributorBase; // Calculate enable register offset and bit position RegOffset = Source / 32; RegShift = Source % 32; - // Write set-enable register - MmioWrite32 (GicDistributorBase + ARM_GIC_ICDISER + (4 * RegOffset), 1 << RegShift); + Revision = ArmGicGetSupportedArchRevision (); + if (Revision == ARM_GIC_ARCH_REVISION_2) { + // Write set-enable register + MmioWrite32 (GicDistributorBase + ARM_GIC_ICDISER + (4 * RegOffset), 1 << RegShift); + } else { + GicCpuRedistributorBase = GicGetCpuRedistributorBase (GicRedistributorBase, Revision); + if (GicCpuRedistributorBase == 0) { + ASSERT_EFI_ERROR (EFI_NOT_FOUND); + return; + } + + // Write set-enable register + MmioWrite32 (GicCpuRedistributorBase + ARM_GICR_CTLR_FRAME_SIZE + ARM_GICR_ISENABLER + (4 * RegOffset), 1 << RegShift); + } } VOID EFIAPI ArmGicDisableInterrupt ( IN UINTN GicDistributorBase, + IN UINTN GicRedistributorBase, IN UINTN Source ) { - UINT32 RegOffset; - UINTN RegShift; + UINT32 RegOffset; + UINTN RegShift; + ARM_GIC_ARCH_REVISION Revision; + UINTN GicCpuRedistributorBase; // Calculate enable register offset and bit position RegOffset = Source / 32; RegShift = Source % 32; - // Write clear-enable register - MmioWrite32 (GicDistributorBase + ARM_GIC_ICDICER + (4 * RegOffset), 1 << RegShift); + Revision = ArmGicGetSupportedArchRevision (); + if (Revision == ARM_GIC_ARCH_REVISION_2) { + // Write clear-enable register + MmioWrite32 (GicDistributorBase + ARM_GIC_ICDICER + (4 * RegOffset), 1 << RegShift); + } else { + GicCpuRedistributorBase = GicGetCpuRedistributorBase (GicRedistributorBase, Revision); + if (GicCpuRedistributorBase == 0) { + return; + } + + // Write clear-enable register + MmioWrite32 (GicCpuRedistributorBase + ARM_GICR_CTLR_FRAME_SIZE + ARM_GICR_ICENABLER + (4 * RegOffset), 1 << RegShift); + } } BOOLEAN EFIAPI ArmGicIsInterruptEnabled ( IN UINTN GicDistributorBase, + IN UINTN GicRedistributorBase, IN UINTN Source ) { - UINT32 RegOffset; - UINTN RegShift; + UINT32 RegOffset; + UINTN RegShift; + ARM_GIC_ARCH_REVISION Revision; + UINTN GicCpuRedistributorBase; + UINT32 Interrupts; // Calculate enable register offset and bit position RegOffset = Source / 32; RegShift = Source % 32; - return ((MmioRead32 (GicDistributorBase + ARM_GIC_ICDISER + (4 * RegOffset)) & (1 << RegShift)) != 0); + Revision = ArmGicGetSupportedArchRevision (); + if (Revision == ARM_GIC_ARCH_REVISION_2) { + Interrupts = ((MmioRead32 (GicDistributorBase + ARM_GIC_ICDISER + (4 * RegOffset)) & (1 << RegShift)) != 0); + } else { + GicCpuRedistributorBase = GicGetCpuRedistributorBase (GicRedistributorBase, Revision); + if (GicCpuRedistributorBase == 0) { + return 0; + } + + // Read set-enable register + Interrupts = MmioRead32 (GicCpuRedistributorBase + ARM_GICR_CTLR_FRAME_SIZE + ARM_GICR_ISENABLER + (4 * RegOffset)); + } + + return ((Interrupts & (1 << RegShift)) != 0); } VOID diff --git a/ArmPkg/Drivers/ArmGic/ArmGicNonSecLib.c b/ArmPkg/Drivers/ArmGic/ArmGicNonSecLib.c index 06367f9d77..e2538f1798 100644 --- a/ArmPkg/Drivers/ArmGic/ArmGicNonSecLib.c +++ b/ArmPkg/Drivers/ArmGic/ArmGicNonSecLib.c @@ -1,6 +1,6 @@ /** @file * -* Copyright (c) 2011-2014, ARM Limited. All rights reserved. +* Copyright (c) 2011-2015, ARM Limited. All rights reserved. * * This program and the accompanying materials * are licensed and made available under the terms and conditions of the BSD License @@ -22,9 +22,16 @@ ArmGicEnableDistributor ( IN INTN GicDistributorBase ) { + ARM_GIC_ARCH_REVISION Revision; + /* * Enable GIC distributor in Non-Secure world. * Note: The ICDDCR register is banked when Security extensions are implemented */ - MmioWrite32 (GicDistributorBase + ARM_GIC_ICDDCR, 0x1); + Revision = ArmGicGetSupportedArchRevision (); + if (Revision == ARM_GIC_ARCH_REVISION_2) { + MmioWrite32 (GicDistributorBase + ARM_GIC_ICDDCR, 0x1); + } else { + MmioWrite32 (GicDistributorBase + ARM_GIC_ICDDCR, 0x2); + } } diff --git a/ArmPkg/Drivers/ArmGic/GicV2/ArmGicV2Dxe.c b/ArmPkg/Drivers/ArmGic/GicV2/ArmGicV2Dxe.c index f37e95ede9..743c534e04 100644 --- a/ArmPkg/Drivers/ArmGic/GicV2/ArmGicV2Dxe.c +++ b/ArmPkg/Drivers/ArmGic/GicV2/ArmGicV2Dxe.c @@ -2,7 +2,7 @@ Copyright (c) 2009, Hewlett-Packard Company. All rights reserved.
Portions copyright (c) 2010, Apple Inc. All rights reserved.
-Portions copyright (c) 2011-2014, ARM Ltd. All rights reserved.
+Portions copyright (c) 2011-2015, ARM Ltd. All rights reserved.
This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License @@ -54,7 +54,7 @@ GicV2EnableInterruptSource ( return EFI_UNSUPPORTED; } - ArmGicEnableInterrupt (mGicDistributorBase, Source); + ArmGicEnableInterrupt (mGicDistributorBase, 0, Source); return EFI_SUCCESS; } @@ -81,7 +81,7 @@ GicV2DisableInterruptSource ( return EFI_UNSUPPORTED; } - ArmGicDisableInterrupt (mGicDistributorBase, Source); + ArmGicDisableInterrupt (mGicDistributorBase, 0, Source); return EFI_SUCCESS; } @@ -110,7 +110,7 @@ GicV2GetInterruptSourceState ( return EFI_UNSUPPORTED; } - *InterruptState = ArmGicIsInterruptEnabled (mGicDistributorBase, Source); + *InterruptState = ArmGicIsInterruptEnabled (mGicDistributorBase, 0, Source); return EFI_SUCCESS; } diff --git a/ArmPkg/Drivers/ArmGic/GicV3/ArmGicV3Dxe.c b/ArmPkg/Drivers/ArmGic/GicV3/ArmGicV3Dxe.c index 51212811e3..e94e015e1f 100644 --- a/ArmPkg/Drivers/ArmGic/GicV3/ArmGicV3Dxe.c +++ b/ArmPkg/Drivers/ArmGic/GicV3/ArmGicV3Dxe.c @@ -44,7 +44,7 @@ GicV3EnableInterruptSource ( return EFI_UNSUPPORTED; } - ArmGicEnableInterrupt (mGicDistributorBase, Source); + ArmGicEnableInterrupt (mGicDistributorBase, mGicRedistributorsBase, Source); return EFI_SUCCESS; } @@ -71,7 +71,7 @@ GicV3DisableInterruptSource ( return EFI_UNSUPPORTED; } - ArmGicDisableInterrupt (mGicDistributorBase, Source); + ArmGicDisableInterrupt (mGicDistributorBase, mGicRedistributorsBase, Source); return EFI_SUCCESS; } @@ -100,7 +100,7 @@ GicV3GetInterruptSourceState ( return EFI_UNSUPPORTED; } - *InterruptState = ArmGicIsInterruptEnabled (mGicDistributorBase, Source); + *InterruptState = ArmGicIsInterruptEnabled (mGicDistributorBase, mGicRedistributorsBase, Source); return EFI_SUCCESS; } @@ -239,7 +239,8 @@ GicV3DxeInitialize ( UINTN Index; UINT32 RegOffset; UINTN RegShift; - UINT32 CpuTarget; + UINT64 CpuTarget; + UINT64 MpId; // Make sure the Interrupt Controller Protocol is not already installed in the system. ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL, &gHardwareInterruptProtocolGuid); @@ -265,22 +266,12 @@ GicV3DxeInitialize ( // Targets the interrupts to the Primary Cpu // - // Only Primary CPU will run this code. We can identify our GIC CPU ID by reading - // the GIC Distributor Target register. The 8 first GICD_ITARGETSRn are banked to each - // connected CPU. These 8 registers hold the CPU targets fields for interrupts 0-31. - // More Info in the GIC Specification about "Interrupt Processor Targets Registers" - // - // Read the first Interrupt Processor Targets Register (that corresponds to the 4 - // first SGIs) - CpuTarget = MmioRead32 (mGicDistributorBase + ARM_GIC_ICDIPTR); - - // The CPU target is a bit field mapping each CPU to a GIC CPU Interface. This value - // is 0 when we run on a uniprocessor platform. - if (CpuTarget != 0) { - // The 8 first Interrupt Processor Targets Registers are read-only - for (Index = 8; Index < (mGicNumInterrupts / 4); Index++) { - MmioWrite32 (mGicDistributorBase + ARM_GIC_ICDIPTR + (Index * 4), CpuTarget); - } + MpId = ArmReadMpidr (); + CpuTarget = MpId & (ARM_CORE_AFF0 | ARM_CORE_AFF1 | ARM_CORE_AFF2 | ARM_CORE_AFF3); + + // Route the SPIs to the primary CPU. SPIs start at the INTID 32 + for (Index = 0; Index < (mGicNumInterrupts - 32); Index++) { + MmioWrite32 (mGicDistributorBase + ARM_GICD_IROUTER + (Index * 8), CpuTarget | ARM_GICD_IROUTER_IRM); } // Set binary point reg to 0x7 (no preemption) diff --git a/ArmPkg/Drivers/ArmGic/GicV3/ArmGicV3Lib.h b/ArmPkg/Drivers/ArmGic/GicV3/ArmGicV3Lib.h index ac4bb2f77f..794e8788a6 100644 --- a/ArmPkg/Drivers/ArmGic/GicV3/ArmGicV3Lib.h +++ b/ArmPkg/Drivers/ArmGic/GicV3/ArmGicV3Lib.h @@ -1,6 +1,6 @@ /** @file * -* Copyright (c) 2014, ARM Limited. All rights reserved. +* Copyright (c) 2014-2015, ARM Limited. All rights reserved. * * This program and the accompanying materials are licensed and made available * under the terms and conditions of the BSD License which accompanies this @@ -17,6 +17,8 @@ #define ICC_SRE_EL2_SRE (1 << 0) +#define ARM_GICD_IROUTER_IRM BIT31 + UINT32 EFIAPI ArmGicV3GetControlSystemRegisterEnable ( diff --git a/ArmPkg/Include/Library/ArmGicLib.h b/ArmPkg/Include/Library/ArmGicLib.h index 6cd93a1f54..2ab99772d1 100644 --- a/ArmPkg/Include/Library/ArmGicLib.h +++ b/ArmPkg/Include/Library/ArmGicLib.h @@ -208,6 +208,7 @@ VOID EFIAPI ArmGicEnableInterrupt ( IN UINTN GicDistributorBase, + IN UINTN GicRedistributorBase, IN UINTN Source ); @@ -215,6 +216,7 @@ VOID EFIAPI ArmGicDisableInterrupt ( IN UINTN GicDistributorBase, + IN UINTN GicRedistributorBase, IN UINTN Source ); @@ -222,6 +224,7 @@ BOOLEAN EFIAPI ArmGicIsInterruptEnabled ( IN UINTN GicDistributorBase, + IN UINTN GicRedistributorBase, IN UINTN Source ); -- 2.39.2