ArmPkg/ArmGic: Disentangle v2 and v3 versions of IRQ en/disable APIs

ArmGicLib is agnostic about the difference between v2 and v3, but its
APIs are only called from code that is either v2-specific or
v3-specific. That makes the generic interface kind of pointless, and we
can just merge this code into the callers.

Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
This commit is contained in:
Ard Biesheuvel 2025-01-16 16:19:08 +01:00 committed by mergify[bot]
parent a4928a0cfc
commit 4e874fcf09
5 changed files with 303 additions and 333 deletions

View File

@ -13,97 +13,6 @@
#include <Library/IoLib.h>
#include <Library/PcdLib.h>
// In GICv3, there are 2 x 64KB frames:
// Redistributor control frame + SGI Control & Generation frame
#define GIC_V3_REDISTRIBUTOR_GRANULARITY (ARM_GICR_CTLR_FRAME_SIZE \
+ ARM_GICR_SGI_PPI_FRAME_SIZE)
// In GICv4, there are 2 additional 64KB frames:
// VLPI frame + Reserved page frame
#define GIC_V4_REDISTRIBUTOR_GRANULARITY (GIC_V3_REDISTRIBUTOR_GRANULARITY \
+ ARM_GICR_SGI_VLPI_FRAME_SIZE \
+ ARM_GICR_SGI_RESERVED_FRAME_SIZE)
#define ISENABLER_ADDRESS(base, offset) ((base) +\
ARM_GICR_CTLR_FRAME_SIZE + ARM_GICR_ISENABLER + 4 * (offset))
#define ICENABLER_ADDRESS(base, offset) ((base) +\
ARM_GICR_CTLR_FRAME_SIZE + ARM_GICR_ICENABLER + 4 * (offset))
#define IPRIORITY_ADDRESS(base, offset) ((base) +\
ARM_GICR_CTLR_FRAME_SIZE + ARM_GIC_ICDIPR + 4 * (offset))
/**
*
* Return whether the Source interrupt index refers to a shared interrupt (SPI)
*/
STATIC
BOOLEAN
SourceIsSpi (
IN UINTN Source
)
{
return Source >= 32 && Source < 1020;
}
/**
* Return the base address of the GIC redistributor for the current CPU
*
* @param Revision GIC Revision. The GIC redistributor might have a different
* granularity following the GIC revision.
*
* @retval Base address of the associated GIC Redistributor
*/
STATIC
UINTN
GicGetCpuRedistributorBase (
IN UINTN GicRedistributorBase,
IN ARM_GIC_ARCH_REVISION Revision
)
{
UINTN MpId;
UINTN CpuAffinity;
UINTN Affinity;
UINTN GicCpuRedistributorBase;
UINT64 TypeRegister;
MpId = ArmReadMpidr ();
// Define CPU affinity as:
// Affinity0[0:8], Affinity1[9:15], Affinity2[16:23], Affinity3[24:32]
// whereas Affinity3 is defined at [32:39] in MPIDR
CpuAffinity = (MpId & (ARM_CORE_AFF0 | ARM_CORE_AFF1 | ARM_CORE_AFF2)) |
((MpId & ARM_CORE_AFF3) >> 8);
if (Revision < ARM_GIC_ARCH_REVISION_3) {
ASSERT_EFI_ERROR (EFI_UNSUPPORTED);
return 0;
}
GicCpuRedistributorBase = GicRedistributorBase;
do {
TypeRegister = MmioRead64 (GicCpuRedistributorBase + ARM_GICR_TYPER);
Affinity = ARM_GICR_TYPER_GET_AFFINITY (TypeRegister);
if (Affinity == CpuAffinity) {
return GicCpuRedistributorBase;
}
// Move to the next GIC Redistributor frame.
// The GIC specification does not forbid a mixture of redistributors
// with or without support for virtual LPIs, so we test Virtual LPIs
// Support (VLPIS) bit for each frame to decide the granularity.
// Note: The assumption here is that the redistributors are adjacent
// for all CPUs. However this may not be the case for NUMA systems.
GicCpuRedistributorBase += (((ARM_GICR_TYPER_VLPIS & TypeRegister) != 0)
? GIC_V4_REDISTRIBUTOR_GRANULARITY
: GIC_V3_REDISTRIBUTOR_GRANULARITY);
} while ((TypeRegister & ARM_GICR_TYPER_LAST) == 0);
// The Redistributor has not been found for the current CPU
ASSERT_EFI_ERROR (EFI_NOT_FOUND);
return 0;
}
/**
Return the GIC CPU Interrupt Interface ID.
@ -137,180 +46,6 @@ ArmGicGetMaxNumInterrupts (
return (ItLines == 0x1f) ? 1020 : 32 * (ItLines + 1);
}
VOID
EFIAPI
ArmGicSetInterruptPriority (
IN UINTN GicDistributorBase,
IN UINTN GicRedistributorBase,
IN UINTN Source,
IN UINT32 Priority
)
{
UINT32 RegOffset;
UINT8 RegShift;
ARM_GIC_ARCH_REVISION Revision;
UINTN GicCpuRedistributorBase;
// Calculate register offset and bit position
RegOffset = (UINT32)(Source / 4);
RegShift = (UINT8)((Source % 4) * 8);
Revision = ArmGicGetSupportedArchRevision ();
if ((Revision == ARM_GIC_ARCH_REVISION_2) ||
SourceIsSpi (Source))
{
MmioAndThenOr32 (
GicDistributorBase + ARM_GIC_ICDIPR + (4 * RegOffset),
~(0xff << RegShift),
Priority << RegShift
);
} else {
GicCpuRedistributorBase = GicGetCpuRedistributorBase (
GicRedistributorBase,
Revision
);
if (GicCpuRedistributorBase == 0) {
return;
}
MmioAndThenOr32 (
IPRIORITY_ADDRESS (GicCpuRedistributorBase, RegOffset),
~(0xff << RegShift),
Priority << RegShift
);
}
}
VOID
EFIAPI
ArmGicEnableInterrupt (
IN UINTN GicDistributorBase,
IN UINTN GicRedistributorBase,
IN UINTN Source
)
{
UINT32 RegOffset;
UINT8 RegShift;
ARM_GIC_ARCH_REVISION Revision;
UINTN GicCpuRedistributorBase;
// Calculate enable register offset and bit position
RegOffset = (UINT32)(Source / 32);
RegShift = (UINT8)(Source % 32);
Revision = ArmGicGetSupportedArchRevision ();
if ((Revision == ARM_GIC_ARCH_REVISION_2) ||
SourceIsSpi (Source))
{
// 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 (
ISENABLER_ADDRESS (GicCpuRedistributorBase, RegOffset),
1 << RegShift
);
}
}
VOID
EFIAPI
ArmGicDisableInterrupt (
IN UINTN GicDistributorBase,
IN UINTN GicRedistributorBase,
IN UINTN Source
)
{
UINT32 RegOffset;
UINT8 RegShift;
ARM_GIC_ARCH_REVISION Revision;
UINTN GicCpuRedistributorBase;
// Calculate enable register offset and bit position
RegOffset = (UINT32)(Source / 32);
RegShift = (UINT8)(Source % 32);
Revision = ArmGicGetSupportedArchRevision ();
if ((Revision == ARM_GIC_ARCH_REVISION_2) ||
SourceIsSpi (Source))
{
// 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 (
ICENABLER_ADDRESS (GicCpuRedistributorBase, RegOffset),
1 << RegShift
);
}
}
BOOLEAN
EFIAPI
ArmGicIsInterruptEnabled (
IN UINTN GicDistributorBase,
IN UINTN GicRedistributorBase,
IN UINTN Source
)
{
UINT32 RegOffset;
UINT8 RegShift;
ARM_GIC_ARCH_REVISION Revision;
UINTN GicCpuRedistributorBase;
UINT32 Interrupts;
// Calculate enable register offset and bit position
RegOffset = (UINT32)(Source / 32);
RegShift = (UINT8)(Source % 32);
Revision = ArmGicGetSupportedArchRevision ();
if ((Revision == ARM_GIC_ARCH_REVISION_2) ||
SourceIsSpi (Source))
{
Interrupts = MmioRead32 (
GicDistributorBase + ARM_GIC_ICDISER + (4 * RegOffset)
);
} else {
GicCpuRedistributorBase = GicGetCpuRedistributorBase (
GicRedistributorBase,
Revision
);
if (GicCpuRedistributorBase == 0) {
return 0;
}
// Read set-enable register
Interrupts = MmioRead32 (
ISENABLER_ADDRESS (GicCpuRedistributorBase, RegOffset)
);
}
return ((Interrupts & (1 << RegShift)) != 0);
}
VOID
EFIAPI
ArmGicDisableDistributor (

View File

@ -28,6 +28,73 @@ extern EFI_HARDWARE_INTERRUPT2_PROTOCOL gHardwareInterrupt2V2Protocol;
STATIC UINTN mGicInterruptInterfaceBase;
STATIC UINTN mGicDistributorBase;
STATIC
VOID
ArmGicEnableInterrupt (
IN UINTN GicDistributorBase,
IN UINTN GicRedistributorBase,
IN UINTN Source
)
{
UINT32 RegOffset;
UINT8 RegShift;
// Calculate enable register offset and bit position
RegOffset = (UINT32)(Source / 32);
RegShift = (UINT8)(Source % 32);
// Write set-enable register
MmioWrite32 (
GicDistributorBase + ARM_GIC_ICDISER + (4 * RegOffset),
1 << RegShift
);
}
STATIC
VOID
ArmGicDisableInterrupt (
IN UINTN GicDistributorBase,
IN UINTN GicRedistributorBase,
IN UINTN Source
)
{
UINT32 RegOffset;
UINT8 RegShift;
// Calculate enable register offset and bit position
RegOffset = (UINT32)(Source / 32);
RegShift = (UINT8)(Source % 32);
// Write clear-enable register
MmioWrite32 (
GicDistributorBase + ARM_GIC_ICDICER + (4 * RegOffset),
1 << RegShift
);
}
STATIC
BOOLEAN
ArmGicIsInterruptEnabled (
IN UINTN GicDistributorBase,
IN UINTN GicRedistributorBase,
IN UINTN Source
)
{
UINT32 RegOffset;
UINT8 RegShift;
UINT32 Interrupts;
// Calculate enable register offset and bit position
RegOffset = (UINT32)(Source / 32);
RegShift = (UINT8)(Source % 32);
Interrupts = MmioRead32 (
GicDistributorBase + ARM_GIC_ICDISER + (4 * RegOffset)
);
return ((Interrupts & (1 << RegShift)) != 0);
}
/**
Enable interrupt source Source.

View File

@ -1,35 +0,0 @@
/** @file
*
* Copyright (c) 2011-2023, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-2-Clause-Patent
*
**/
#include <Uefi.h>
#include <Library/IoLib.h>
#include <Library/ArmGicLib.h>
VOID
EFIAPI
ArmGicV2EnableInterruptInterface (
IN UINTN GicInterruptInterfaceBase
)
{
/*
* Enable the CPU interface in Non-Secure world
* Note: The ICCICR register is banked when Security extensions are implemented
*/
MmioWrite32 (GicInterruptInterfaceBase + ARM_GIC_ICCICR, 0x1);
}
VOID
EFIAPI
ArmGicV2DisableInterruptInterface (
IN UINTN GicInterruptInterfaceBase
)
{
// Disable Gic Interface
MmioWrite32 (GicInterruptInterfaceBase + ARM_GIC_ICCICR, 0x0);
MmioWrite32 (GicInterruptInterfaceBase + ARM_GIC_ICCPMR, 0x0);
}

View File

@ -12,12 +12,248 @@
#define ARM_GIC_DEFAULT_PRIORITY 0x80
// In GICv3, there are 2 x 64KB frames:
// Redistributor control frame + SGI Control & Generation frame
#define GIC_V3_REDISTRIBUTOR_GRANULARITY (ARM_GICR_CTLR_FRAME_SIZE \
+ ARM_GICR_SGI_PPI_FRAME_SIZE)
// In GICv4, there are 2 additional 64KB frames:
// VLPI frame + Reserved page frame
#define GIC_V4_REDISTRIBUTOR_GRANULARITY (GIC_V3_REDISTRIBUTOR_GRANULARITY \
+ ARM_GICR_SGI_VLPI_FRAME_SIZE \
+ ARM_GICR_SGI_RESERVED_FRAME_SIZE)
#define ISENABLER_ADDRESS(base, offset) ((base) +\
ARM_GICR_CTLR_FRAME_SIZE + ARM_GICR_ISENABLER + 4 * (offset))
#define ICENABLER_ADDRESS(base, offset) ((base) +\
ARM_GICR_CTLR_FRAME_SIZE + ARM_GICR_ICENABLER + 4 * (offset))
#define IPRIORITY_ADDRESS(base, offset) ((base) +\
ARM_GICR_CTLR_FRAME_SIZE + ARM_GIC_ICDIPR + 4 * (offset))
extern EFI_HARDWARE_INTERRUPT_PROTOCOL gHardwareInterruptV3Protocol;
extern EFI_HARDWARE_INTERRUPT2_PROTOCOL gHardwareInterrupt2V3Protocol;
STATIC UINTN mGicDistributorBase;
STATIC UINTN mGicRedistributorsBase;
/**
*
* Return whether the Source interrupt index refers to a shared interrupt (SPI)
*/
STATIC
BOOLEAN
SourceIsSpi (
IN UINTN Source
)
{
return Source >= 32 && Source < 1020;
}
/**
* Return the base address of the GIC redistributor for the current CPU
*
* @retval Base address of the associated GIC Redistributor
*/
STATIC
UINTN
GicGetCpuRedistributorBase (
IN UINTN GicRedistributorBase
)
{
UINTN MpId;
UINTN CpuAffinity;
UINTN Affinity;
UINTN GicCpuRedistributorBase;
UINT64 TypeRegister;
MpId = ArmReadMpidr ();
// Define CPU affinity as:
// Affinity0[0:8], Affinity1[9:15], Affinity2[16:23], Affinity3[24:32]
// whereas Affinity3 is defined at [32:39] in MPIDR
CpuAffinity = (MpId & (ARM_CORE_AFF0 | ARM_CORE_AFF1 | ARM_CORE_AFF2)) |
((MpId & ARM_CORE_AFF3) >> 8);
GicCpuRedistributorBase = GicRedistributorBase;
do {
TypeRegister = MmioRead64 (GicCpuRedistributorBase + ARM_GICR_TYPER);
Affinity = ARM_GICR_TYPER_GET_AFFINITY (TypeRegister);
if (Affinity == CpuAffinity) {
return GicCpuRedistributorBase;
}
// Move to the next GIC Redistributor frame.
// The GIC specification does not forbid a mixture of redistributors
// with or without support for virtual LPIs, so we test Virtual LPIs
// Support (VLPIS) bit for each frame to decide the granularity.
// Note: The assumption here is that the redistributors are adjacent
// for all CPUs. However this may not be the case for NUMA systems.
GicCpuRedistributorBase += (((ARM_GICR_TYPER_VLPIS & TypeRegister) != 0)
? GIC_V4_REDISTRIBUTOR_GRANULARITY
: GIC_V3_REDISTRIBUTOR_GRANULARITY);
} while ((TypeRegister & ARM_GICR_TYPER_LAST) == 0);
// The Redistributor has not been found for the current CPU
ASSERT_EFI_ERROR (EFI_NOT_FOUND);
return 0;
}
STATIC
VOID
ArmGicSetInterruptPriority (
IN UINTN GicDistributorBase,
IN UINTN GicRedistributorBase,
IN UINTN Source,
IN UINT32 Priority
)
{
UINT32 RegOffset;
UINT8 RegShift;
UINTN GicCpuRedistributorBase;
// Calculate register offset and bit position
RegOffset = (UINT32)(Source / 4);
RegShift = (UINT8)((Source % 4) * 8);
if (SourceIsSpi (Source)) {
MmioAndThenOr32 (
GicDistributorBase + ARM_GIC_ICDIPR + (4 * RegOffset),
~(0xff << RegShift),
Priority << RegShift
);
} else {
GicCpuRedistributorBase = GicGetCpuRedistributorBase (
GicRedistributorBase
);
if (GicCpuRedistributorBase == 0) {
return;
}
MmioAndThenOr32 (
IPRIORITY_ADDRESS (GicCpuRedistributorBase, RegOffset),
~(0xff << RegShift),
Priority << RegShift
);
}
}
STATIC
VOID
ArmGicEnableInterrupt (
IN UINTN GicDistributorBase,
IN UINTN GicRedistributorBase,
IN UINTN Source
)
{
UINT32 RegOffset;
UINT8 RegShift;
UINTN GicCpuRedistributorBase;
// Calculate enable register offset and bit position
RegOffset = (UINT32)(Source / 32);
RegShift = (UINT8)(Source % 32);
if (SourceIsSpi (Source)) {
// Write set-enable register
MmioWrite32 (
GicDistributorBase + ARM_GIC_ICDISER + (4 * RegOffset),
1 << RegShift
);
} else {
GicCpuRedistributorBase = GicGetCpuRedistributorBase (
GicRedistributorBase
);
if (GicCpuRedistributorBase == 0) {
ASSERT_EFI_ERROR (EFI_NOT_FOUND);
return;
}
// Write set-enable register
MmioWrite32 (
ISENABLER_ADDRESS (GicCpuRedistributorBase, RegOffset),
1 << RegShift
);
}
}
STATIC
VOID
ArmGicDisableInterrupt (
IN UINTN GicDistributorBase,
IN UINTN GicRedistributorBase,
IN UINTN Source
)
{
UINT32 RegOffset;
UINT8 RegShift;
UINTN GicCpuRedistributorBase;
// Calculate enable register offset and bit position
RegOffset = (UINT32)(Source / 32);
RegShift = (UINT8)(Source % 32);
if (SourceIsSpi (Source)) {
// Write clear-enable register
MmioWrite32 (
GicDistributorBase + ARM_GIC_ICDICER + (4 * RegOffset),
1 << RegShift
);
} else {
GicCpuRedistributorBase = GicGetCpuRedistributorBase (
GicRedistributorBase
);
if (GicCpuRedistributorBase == 0) {
return;
}
// Write clear-enable register
MmioWrite32 (
ICENABLER_ADDRESS (GicCpuRedistributorBase, RegOffset),
1 << RegShift
);
}
}
STATIC
BOOLEAN
ArmGicIsInterruptEnabled (
IN UINTN GicDistributorBase,
IN UINTN GicRedistributorBase,
IN UINTN Source
)
{
UINT32 RegOffset;
UINT8 RegShift;
UINTN GicCpuRedistributorBase;
UINT32 Interrupts;
// Calculate enable register offset and bit position
RegOffset = (UINT32)(Source / 32);
RegShift = (UINT8)(Source % 32);
if (SourceIsSpi (Source)) {
Interrupts = MmioRead32 (
GicDistributorBase + ARM_GIC_ICDISER + (4 * RegOffset)
);
} else {
GicCpuRedistributorBase = GicGetCpuRedistributorBase (
GicRedistributorBase
);
if (GicCpuRedistributorBase == 0) {
return 0;
}
// Read set-enable register
Interrupts = MmioRead32 (
ISENABLER_ADDRESS (GicCpuRedistributorBase, RegOffset)
);
}
return ((Interrupts & (1 << RegShift)) != 0);
}
/**
Enable interrupt source Source.

View File

@ -158,39 +158,6 @@ ArmGicSetPriorityMask (
IN INTN PriorityMask
);
VOID
EFIAPI
ArmGicSetInterruptPriority (
IN UINTN GicDistributorBase,
IN UINTN GicRedistributorBase,
IN UINTN Source,
IN UINT32 Priority
);
VOID
EFIAPI
ArmGicEnableInterrupt (
IN UINTN GicDistributorBase,
IN UINTN GicRedistributorBase,
IN UINTN Source
);
VOID
EFIAPI
ArmGicDisableInterrupt (
IN UINTN GicDistributorBase,
IN UINTN GicRedistributorBase,
IN UINTN Source
);
BOOLEAN
EFIAPI
ArmGicIsInterruptEnabled (
IN UINTN GicDistributorBase,
IN UINTN GicRedistributorBase,
IN UINTN Source
);
// GIC revision 2 specific declarations
// Interrupts from 1020 to 1023 are considered as special interrupts