REF: https://bugzilla.tianocore.org/show_bug.cgi?id=4466
This change provides additional functionalities to `ArmGicLib` to manipulate pending interrupt related status. The added functions include: - `ArmGicSetPendingInterrupt` - `ArmGicClearPendingInterrupt` - `ArmGicIsInterruptPending` Cc: Leif Lindholm <quic_llind...@quicinc.com> Cc: Ard Biesheuvel <ardb+tianoc...@kernel.org> Cc: Sami Mujawar <sami.muja...@arm.com> Signed-off-by: Kun Qin <ku...@microsoft.com> --- ArmPkg/Drivers/ArmGic/ArmGicLib.c | 162 ++++++++++++++++++++ ArmPkg/ArmPkg.ci.yaml | 2 + ArmPkg/Include/Library/ArmGicLib.h | 49 ++++++ 3 files changed, 213 insertions(+) diff --git a/ArmPkg/Drivers/ArmGic/ArmGicLib.c b/ArmPkg/Drivers/ArmGic/ArmGicLib.c index 830d822d2c05..3844dc05e2af 100644 --- a/ArmPkg/Drivers/ArmGic/ArmGicLib.c +++ b/ArmPkg/Drivers/ArmGic/ArmGicLib.c @@ -33,6 +33,12 @@ #define IPRIORITY_ADDRESS(base, offset) ((base) +\ ARM_GICR_CTLR_FRAME_SIZE + ARM_GIC_ICDIPR + 4 * (offset)) +#define ISPENDR_ADDRESS(base, offset) ((base) +\ + ARM_GICR_CTLR_FRAME_SIZE + ARM_GICR_ISPENDR + 4 * (offset)) + +#define ICPENDR_ADDRESS(base, offset) ((base) +\ + ARM_GICR_CTLR_FRAME_SIZE + ARM_GICR_ICPENDR + 4 * (offset)) + /** * * Return whether the Source interrupt index refers to a shared interrupt (SPI) @@ -440,6 +446,162 @@ ArmGicIsInterruptEnabled ( return ((Interrupts & (1 << RegShift)) != 0); } +/** + Set an interrupt to pending state from GIC. + + @param GicDistributorBase Base address of platform GIC Distributor. + @param GicRedistributorBase Base address of platform GIC Redistributor. + @param Source Interrupt source ID. +**/ +VOID +EFIAPI +ArmGicSetPendingInterrupt ( + IN UINTN GicDistributorBase, + IN UINTN GicRedistributorBase, + IN UINTN Source + ) +{ + UINT32 RegOffset; + UINTN RegShift; + ARM_GIC_ARCH_REVISION Revision; + UINTN GicCpuRedistributorBase; + + // Calculate enable register offset and bit position + RegOffset = (UINT32)(Source / 32); + RegShift = Source % 32; + + Revision = ArmGicGetSupportedArchRevision (); + if ((Revision == ARM_GIC_ARCH_REVISION_2) || + FeaturePcdGet (PcdArmGicV3WithV2Legacy) || + SourceIsSpi (Source)) + { + // Write set-pending register + MmioWrite32 ( + GicDistributorBase + ARM_GIC_ICDSPR + (4 * RegOffset), + 1 << RegShift + ); + } else { + GicCpuRedistributorBase = GicGetCpuRedistributorBase ( + GicRedistributorBase, + Revision + ); + if (GicCpuRedistributorBase == 0) { + ASSERT_EFI_ERROR (EFI_NOT_FOUND); + return; + } + + // Write set-enable register + MmioWrite32 ( + ISPENDR_ADDRESS (GicCpuRedistributorBase, RegOffset), + 1 << RegShift + ); + } +} + +/** + Clear a pending interrupt from GIC. + + @param GicDistributorBase Base address of platform GIC Distributor. + @param GicRedistributorBase Base address of platform GIC Redistributor. + @param Source Interrupt source ID. +**/ +VOID +EFIAPI +ArmGicClearPendingInterrupt ( + IN UINTN GicDistributorBase, + IN UINTN GicRedistributorBase, + IN UINTN Source + ) +{ + UINT32 RegOffset; + UINTN RegShift; + ARM_GIC_ARCH_REVISION Revision; + UINTN GicCpuRedistributorBase; + + // Calculate enable register offset and bit position + RegOffset = (UINT32)(Source / 32); + RegShift = Source % 32; + + Revision = ArmGicGetSupportedArchRevision (); + if ((Revision == ARM_GIC_ARCH_REVISION_2) || + FeaturePcdGet (PcdArmGicV3WithV2Legacy) || + SourceIsSpi (Source)) + { + // Write clear-enable register + MmioWrite32 ( + GicDistributorBase + ARM_GIC_ICDICPR + (4 * RegOffset), + 1 << RegShift + ); + } else { + GicCpuRedistributorBase = GicGetCpuRedistributorBase ( + GicRedistributorBase, + Revision + ); + if (GicCpuRedistributorBase == 0) { + return; + } + + // Write clear-enable register + MmioWrite32 ( + ICPENDR_ADDRESS (GicCpuRedistributorBase, RegOffset), + 1 << RegShift + ); + } +} + +/** + Check if an interrupt is pending in GIC. + + @param GicDistributorBase Base address of platform GIC Distributor. + @param GicRedistributorBase Base address of platform GIC Redistributor. + @param Source Interrupt source ID. + + @return BOOLEAN TRUE if the interrupt is pending, FALSE otherwise. +**/ +BOOLEAN +EFIAPI +ArmGicIsInterruptPending ( + IN UINTN GicDistributorBase, + IN UINTN GicRedistributorBase, + IN UINTN Source + ) +{ + UINT32 RegOffset; + UINTN RegShift; + ARM_GIC_ARCH_REVISION Revision; + UINTN GicCpuRedistributorBase; + UINT32 Interrupts; + + // Calculate enable register offset and bit position + RegOffset = (UINT32)(Source / 32); + RegShift = Source % 32; + + Revision = ArmGicGetSupportedArchRevision (); + if ((Revision == ARM_GIC_ARCH_REVISION_2) || + FeaturePcdGet (PcdArmGicV3WithV2Legacy) || + SourceIsSpi (Source)) + { + Interrupts = MmioRead32 ( + GicDistributorBase + ARM_GIC_ICDSPR + (4 * RegOffset) + ); + } else { + GicCpuRedistributorBase = GicGetCpuRedistributorBase ( + GicRedistributorBase, + Revision + ); + if (GicCpuRedistributorBase == 0) { + return 0; + } + + // Read set-enable register + Interrupts = MmioRead32 ( + ISPENDR_ADDRESS (GicCpuRedistributorBase, RegOffset) + ); + } + + return ((Interrupts & (1 << RegShift)) != 0); +} + VOID EFIAPI ArmGicDisableDistributor ( diff --git a/ArmPkg/ArmPkg.ci.yaml b/ArmPkg/ArmPkg.ci.yaml index 8a8f738437d5..06e31498cf79 100644 --- a/ArmPkg/ArmPkg.ci.yaml +++ b/ArmPkg/ArmPkg.ci.yaml @@ -154,11 +154,13 @@ "icdsgir", "icdspr", "icenabler", + "icpendr", "intid", "ipriority", "irouter", "isenabler", "ishst", + "ispendr", "istatus", "itargets", "lable", diff --git a/ArmPkg/Include/Library/ArmGicLib.h b/ArmPkg/Include/Library/ArmGicLib.h index 28d58f187d4f..83d52756d61a 100644 --- a/ArmPkg/Include/Library/ArmGicLib.h +++ b/ArmPkg/Include/Library/ArmGicLib.h @@ -78,6 +78,8 @@ // GIC SGI & PPI Redistributor frame #define ARM_GICR_ISENABLER 0x0100 // Interrupt Set-Enable Registers #define ARM_GICR_ICENABLER 0x0180 // Interrupt Clear-Enable Registers +#define ARM_GICR_ISPENDR 0x0200 // Interrupt Set-Pending Registers +#define ARM_GICR_ICPENDR 0x0280 // Interrupt Clear-Pending Registers // GIC Cpu interface #define ARM_GIC_ICCICR 0x00 // CPU Interface Control Register @@ -167,6 +169,53 @@ ArmGicDisableInterruptInterface ( IN UINTN GicInterruptInterfaceBase ); +/** + Set an interrupt to pending state from GIC. + + @param GicDistributorBase Base address of platform GIC Distributor. + @param GicRedistributorBase Base address of platform GIC Redistributor. + @param Source Interrupt source ID. +**/ +VOID +EFIAPI +ArmGicSetPendingInterrupt ( + IN UINTN GicDistributorBase, + IN UINTN GicRedistributorBase, + IN UINTN Source + ); + +/** + Clear a pending interrupt from GIC. + + @param GicDistributorBase Base address of platform GIC Distributor. + @param GicRedistributorBase Base address of platform GIC Redistributor. + @param Source Interrupt source ID. +**/ +VOID +EFIAPI +ArmGicClearPendingInterrupt ( + IN UINTN GicDistributorBase, + IN UINTN GicRedistributorBase, + IN UINTN Source + ); + +/** + Check if an interrupt is pending in GIC. + + @param GicDistributorBase Base address of platform GIC Distributor. + @param GicRedistributorBase Base address of platform GIC Redistributor. + @param Source Interrupt source ID. + + @return BOOLEAN TRUE if the interrupt is pending, FALSE otherwise. +**/ +BOOLEAN +EFIAPI +ArmGicIsInterruptPending ( + IN UINTN GicDistributorBase, + IN UINTN GicRedistributorBase, + IN UINTN Source + ); + VOID EFIAPI ArmGicEnableDistributor ( -- 2.41.0.windows.2 -=-=-=-=-=-=-=-=-=-=-=- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#107190): https://edk2.groups.io/g/devel/message/107190 Mute This Topic: https://groups.io/mt/100337225/21656 Group Owner: devel+ow...@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [arch...@mail-archive.com] -=-=-=-=-=-=-=-=-=-=-=-