/** @file\r
*\r
-* Copyright (c) 2011-2015, ARM Limited. All rights reserved.\r
+* Copyright (c) 2011-2021, Arm Limited. All rights reserved.\r
*\r
-* This program and the accompanying materials\r
-* are licensed and made available under the terms and conditions of the BSD License\r
-* which accompanies this distribution. The full text of the license may be found at\r
-* http://opensource.org/licenses/bsd-license.php\r
-*\r
-* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
-* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+* SPDX-License-Identifier: BSD-2-Clause-Patent\r
*\r
**/\r
\r
#include <Library/IoLib.h>\r
#include <Library/PcdLib.h>\r
\r
+// In GICv3, there are 2 x 64KB frames:\r
+// Redistributor control frame + SGI Control & Generation frame\r
+#define GIC_V3_REDISTRIBUTOR_GRANULARITY (ARM_GICR_CTLR_FRAME_SIZE \\r
+ + ARM_GICR_SGI_PPI_FRAME_SIZE)\r
+\r
+// In GICv4, there are 2 additional 64KB frames:\r
+// VLPI frame + Reserved page frame\r
+#define GIC_V4_REDISTRIBUTOR_GRANULARITY (GIC_V3_REDISTRIBUTOR_GRANULARITY \\r
+ + ARM_GICR_SGI_VLPI_FRAME_SIZE \\r
+ + ARM_GICR_SGI_RESERVED_FRAME_SIZE)\r
+\r
+#define ISENABLER_ADDRESS(base, offset) ((base) +\\r
+ ARM_GICR_CTLR_FRAME_SIZE + ARM_GICR_ISENABLER + 4 * (offset))\r
+\r
+#define ICENABLER_ADDRESS(base, offset) ((base) +\\r
+ ARM_GICR_CTLR_FRAME_SIZE + ARM_GICR_ICENABLER + 4 * (offset))\r
+\r
+#define IPRIORITY_ADDRESS(base, offset) ((base) +\\r
+ ARM_GICR_CTLR_FRAME_SIZE + ARM_GIC_ICDIPR + 4 * (offset))\r
+\r
+/**\r
+ *\r
+ * Return whether the Source interrupt index refers to a shared interrupt (SPI)\r
+ */\r
+STATIC\r
+BOOLEAN\r
+SourceIsSpi (\r
+ IN UINTN Source\r
+ )\r
+{\r
+ return Source >= 32 && Source < 1020;\r
+}\r
+\r
/**\r
* Return the base address of the GIC redistributor for the current CPU\r
*\r
STATIC\r
UINTN\r
GicGetCpuRedistributorBase (\r
- IN UINTN GicRedistributorBase,\r
- IN ARM_GIC_ARCH_REVISION Revision\r
+ IN UINTN GicRedistributorBase,\r
+ IN ARM_GIC_ARCH_REVISION Revision\r
)\r
{\r
- UINTN Index;\r
- UINTN MpId;\r
- UINTN CpuAffinity;\r
- UINTN Affinity;\r
- UINTN GicRedistributorGranularity;\r
- UINTN GicCpuRedistributorBase;\r
+ UINTN MpId;\r
+ UINTN CpuAffinity;\r
+ UINTN Affinity;\r
+ UINTN GicCpuRedistributorBase;\r
+ UINT64 TypeRegister;\r
\r
MpId = ArmReadMpidr ();\r
- // Define CPU affinity as Affinity0[0:8], Affinity1[9:15], Affinity2[16:23], Affinity3[24:32]\r
+ // Define CPU affinity as:\r
+ // Affinity0[0:8], Affinity1[9:15], Affinity2[16:23], Affinity3[24:32]\r
// whereas Affinity3 is defined at [32:39] in MPIDR\r
- CpuAffinity = (MpId & (ARM_CORE_AFF0 | ARM_CORE_AFF1 | ARM_CORE_AFF2)) | ((MpId & ARM_CORE_AFF3) >> 8);\r
+ CpuAffinity = (MpId & (ARM_CORE_AFF0 | ARM_CORE_AFF1 | ARM_CORE_AFF2)) |\r
+ ((MpId & ARM_CORE_AFF3) >> 8);\r
\r
- if (Revision == ARM_GIC_ARCH_REVISION_3) {\r
- // 2 x 64KB frame: Redistributor control frame + SGI Control & Generation frame\r
- GicRedistributorGranularity = ARM_GICR_CTLR_FRAME_SIZE + ARM_GICR_SGI_PPI_FRAME_SIZE;\r
- } else {\r
+ if (Revision < ARM_GIC_ARCH_REVISION_3) {\r
ASSERT_EFI_ERROR (EFI_UNSUPPORTED);\r
return 0;\r
}\r
\r
GicCpuRedistributorBase = GicRedistributorBase;\r
\r
- for (Index = 0; Index < PcdGet32 (PcdCoreCount); Index++) {\r
- Affinity = MmioRead64 (GicCpuRedistributorBase + ARM_GICR_TYPER) >> 32;\r
+ do {\r
+ TypeRegister = MmioRead64 (GicCpuRedistributorBase + ARM_GICR_TYPER);\r
+ Affinity = ARM_GICR_TYPER_GET_AFFINITY (TypeRegister);\r
if (Affinity == CpuAffinity) {\r
return GicCpuRedistributorBase;\r
}\r
\r
- // Move to the next GIC Redistributor frame\r
- GicRedistributorBase += GicRedistributorGranularity;\r
- }\r
+ // Move to the next GIC Redistributor frame.\r
+ // The GIC specification does not forbid a mixture of redistributors\r
+ // with or without support for virtual LPIs, so we test Virtual LPIs\r
+ // Support (VLPIS) bit for each frame to decide the granularity.\r
+ // Note: The assumption here is that the redistributors are adjacent\r
+ // for all CPUs. However this may not be the case for NUMA systems.\r
+ GicCpuRedistributorBase += (((ARM_GICR_TYPER_VLPIS & TypeRegister) != 0)\r
+ ? GIC_V4_REDISTRIBUTOR_GRANULARITY\r
+ : GIC_V3_REDISTRIBUTOR_GRANULARITY);\r
+ } while ((TypeRegister & ARM_GICR_TYPER_LAST) == 0);\r
\r
// The Redistributor has not been found for the current CPU\r
ASSERT_EFI_ERROR (EFI_NOT_FOUND);\r
UINTN\r
EFIAPI\r
ArmGicGetInterfaceIdentification (\r
- IN INTN GicInterruptInterfaceBase\r
+ IN INTN GicInterruptInterfaceBase\r
)\r
{\r
// Read the GIC Identification Register\r
UINTN\r
EFIAPI\r
ArmGicGetMaxNumInterrupts (\r
- IN INTN GicDistributorBase\r
+ IN INTN GicDistributorBase\r
)\r
{\r
- return 32 * ((MmioRead32 (GicDistributorBase + ARM_GIC_ICDICTR) & 0x1F) + 1);\r
+ UINTN ItLines;\r
+\r
+ ItLines = MmioRead32 (GicDistributorBase + ARM_GIC_ICDICTR) & 0x1F;\r
+\r
+ //\r
+ // Interrupt ID 1020-1023 are reserved.\r
+ //\r
+ return (ItLines == 0x1f) ? 1020 : 32 * (ItLines + 1);\r
}\r
\r
VOID\r
EFIAPI\r
ArmGicSendSgiTo (\r
- IN INTN GicDistributorBase,\r
- IN INTN TargetListFilter,\r
- IN INTN CPUTargetList,\r
- IN INTN SgiId\r
+ IN INTN GicDistributorBase,\r
+ IN INTN TargetListFilter,\r
+ IN INTN CPUTargetList,\r
+ IN INTN SgiId\r
)\r
{\r
- MmioWrite32 (GicDistributorBase + ARM_GIC_ICDSGIR, ((TargetListFilter & 0x3) << 24) | ((CPUTargetList & 0xFF) << 16) | SgiId);\r
+ MmioWrite32 (\r
+ GicDistributorBase + ARM_GIC_ICDSGIR,\r
+ ((TargetListFilter & 0x3) << 24) | ((CPUTargetList & 0xFF) << 16) | SgiId\r
+ );\r
}\r
\r
/*\r
* in the GICv3 the register value is only the InterruptId.\r
*\r
* @param GicInterruptInterfaceBase Base Address of the GIC CPU Interface\r
- * @param InterruptId InterruptId read from the Interrupt Acknowledge Register\r
+ * @param InterruptId InterruptId read from the Interrupt\r
+ * Acknowledge Register\r
*\r
* @retval value returned by the Interrupt Acknowledge Register\r
*\r
UINTN\r
EFIAPI\r
ArmGicAcknowledgeInterrupt (\r
- IN UINTN GicInterruptInterfaceBase,\r
- OUT UINTN *InterruptId\r
+ IN UINTN GicInterruptInterfaceBase,\r
+ OUT UINTN *InterruptId\r
)\r
{\r
- UINTN Value;\r
- ARM_GIC_ARCH_REVISION Revision;\r
+ UINTN Value;\r
+ ARM_GIC_ARCH_REVISION Revision;\r
\r
Revision = ArmGicGetSupportedArchRevision ();\r
if (Revision == ARM_GIC_ARCH_REVISION_2) {\r
VOID\r
EFIAPI\r
ArmGicEndOfInterrupt (\r
- IN UINTN GicInterruptInterfaceBase,\r
- IN UINTN Source\r
+ IN UINTN GicInterruptInterfaceBase,\r
+ IN UINTN Source\r
)\r
{\r
- ARM_GIC_ARCH_REVISION Revision;\r
+ ARM_GIC_ARCH_REVISION Revision;\r
\r
Revision = ArmGicGetSupportedArchRevision ();\r
if (Revision == ARM_GIC_ARCH_REVISION_2) {\r
}\r
}\r
\r
+VOID\r
+EFIAPI\r
+ArmGicSetInterruptPriority (\r
+ IN UINTN GicDistributorBase,\r
+ IN UINTN GicRedistributorBase,\r
+ IN UINTN Source,\r
+ IN UINTN Priority\r
+ )\r
+{\r
+ UINT32 RegOffset;\r
+ UINTN RegShift;\r
+ ARM_GIC_ARCH_REVISION Revision;\r
+ UINTN GicCpuRedistributorBase;\r
+\r
+ // Calculate register offset and bit position\r
+ RegOffset = Source / 4;\r
+ RegShift = (Source % 4) * 8;\r
+\r
+ Revision = ArmGicGetSupportedArchRevision ();\r
+ if ((Revision == ARM_GIC_ARCH_REVISION_2) ||\r
+ FeaturePcdGet (PcdArmGicV3WithV2Legacy) ||\r
+ SourceIsSpi (Source))\r
+ {\r
+ MmioAndThenOr32 (\r
+ GicDistributorBase + ARM_GIC_ICDIPR + (4 * RegOffset),\r
+ ~(0xff << RegShift),\r
+ Priority << RegShift\r
+ );\r
+ } else {\r
+ GicCpuRedistributorBase = GicGetCpuRedistributorBase (\r
+ GicRedistributorBase,\r
+ Revision\r
+ );\r
+ if (GicCpuRedistributorBase == 0) {\r
+ return;\r
+ }\r
+\r
+ MmioAndThenOr32 (\r
+ IPRIORITY_ADDRESS (GicCpuRedistributorBase, RegOffset),\r
+ ~(0xff << RegShift),\r
+ Priority << RegShift\r
+ );\r
+ }\r
+}\r
+\r
VOID\r
EFIAPI\r
ArmGicEnableInterrupt (\r
- IN UINTN GicDistributorBase,\r
- IN UINTN GicRedistributorBase,\r
- IN UINTN Source\r
+ IN UINTN GicDistributorBase,\r
+ IN UINTN GicRedistributorBase,\r
+ IN UINTN Source\r
)\r
{\r
- UINT32 RegOffset;\r
- UINTN RegShift;\r
- ARM_GIC_ARCH_REVISION Revision;\r
- UINTN GicCpuRedistributorBase;\r
+ UINT32 RegOffset;\r
+ UINTN RegShift;\r
+ ARM_GIC_ARCH_REVISION Revision;\r
+ UINTN GicCpuRedistributorBase;\r
\r
// Calculate enable register offset and bit position\r
RegOffset = Source / 32;\r
- RegShift = Source % 32;\r
+ RegShift = Source % 32;\r
\r
Revision = ArmGicGetSupportedArchRevision ();\r
- if ((Revision == ARM_GIC_ARCH_REVISION_2) || FeaturePcdGet (PcdArmGicV3WithV2Legacy)) {\r
+ if ((Revision == ARM_GIC_ARCH_REVISION_2) ||\r
+ FeaturePcdGet (PcdArmGicV3WithV2Legacy) ||\r
+ SourceIsSpi (Source))\r
+ {\r
// Write set-enable register\r
- MmioWrite32 (GicDistributorBase + ARM_GIC_ICDISER + (4 * RegOffset), 1 << RegShift);\r
+ MmioWrite32 (\r
+ GicDistributorBase + ARM_GIC_ICDISER + (4 * RegOffset),\r
+ 1 << RegShift\r
+ );\r
} else {\r
- GicCpuRedistributorBase = GicGetCpuRedistributorBase (GicRedistributorBase, Revision);\r
+ GicCpuRedistributorBase = GicGetCpuRedistributorBase (\r
+ GicRedistributorBase,\r
+ Revision\r
+ );\r
if (GicCpuRedistributorBase == 0) {\r
ASSERT_EFI_ERROR (EFI_NOT_FOUND);\r
return;\r
}\r
\r
// Write set-enable register\r
- MmioWrite32 (GicCpuRedistributorBase + ARM_GICR_CTLR_FRAME_SIZE + ARM_GICR_ISENABLER + (4 * RegOffset), 1 << RegShift);\r
+ MmioWrite32 (\r
+ ISENABLER_ADDRESS (GicCpuRedistributorBase, RegOffset),\r
+ 1 << RegShift\r
+ );\r
}\r
}\r
\r
VOID\r
EFIAPI\r
ArmGicDisableInterrupt (\r
- IN UINTN GicDistributorBase,\r
- IN UINTN GicRedistributorBase,\r
- IN UINTN Source\r
+ IN UINTN GicDistributorBase,\r
+ IN UINTN GicRedistributorBase,\r
+ IN UINTN Source\r
)\r
{\r
- UINT32 RegOffset;\r
- UINTN RegShift;\r
- ARM_GIC_ARCH_REVISION Revision;\r
- UINTN GicCpuRedistributorBase;\r
+ UINT32 RegOffset;\r
+ UINTN RegShift;\r
+ ARM_GIC_ARCH_REVISION Revision;\r
+ UINTN GicCpuRedistributorBase;\r
\r
// Calculate enable register offset and bit position\r
RegOffset = Source / 32;\r
- RegShift = Source % 32;\r
+ RegShift = Source % 32;\r
\r
Revision = ArmGicGetSupportedArchRevision ();\r
- if ((Revision == ARM_GIC_ARCH_REVISION_2) || FeaturePcdGet (PcdArmGicV3WithV2Legacy)) {\r
+ if ((Revision == ARM_GIC_ARCH_REVISION_2) ||\r
+ FeaturePcdGet (PcdArmGicV3WithV2Legacy) ||\r
+ SourceIsSpi (Source))\r
+ {\r
// Write clear-enable register\r
- MmioWrite32 (GicDistributorBase + ARM_GIC_ICDICER + (4 * RegOffset), 1 << RegShift);\r
+ MmioWrite32 (\r
+ GicDistributorBase + ARM_GIC_ICDICER + (4 * RegOffset),\r
+ 1 << RegShift\r
+ );\r
} else {\r
- GicCpuRedistributorBase = GicGetCpuRedistributorBase (GicRedistributorBase, Revision);\r
+ GicCpuRedistributorBase = GicGetCpuRedistributorBase (\r
+ GicRedistributorBase,\r
+ Revision\r
+ );\r
if (GicCpuRedistributorBase == 0) {\r
return;\r
}\r
\r
// Write clear-enable register\r
- MmioWrite32 (GicCpuRedistributorBase + ARM_GICR_CTLR_FRAME_SIZE + ARM_GICR_ICENABLER + (4 * RegOffset), 1 << RegShift);\r
+ MmioWrite32 (\r
+ ICENABLER_ADDRESS (GicCpuRedistributorBase, RegOffset),\r
+ 1 << RegShift\r
+ );\r
}\r
}\r
\r
BOOLEAN\r
EFIAPI\r
ArmGicIsInterruptEnabled (\r
- IN UINTN GicDistributorBase,\r
- IN UINTN GicRedistributorBase,\r
- IN UINTN Source\r
+ IN UINTN GicDistributorBase,\r
+ IN UINTN GicRedistributorBase,\r
+ IN UINTN Source\r
)\r
{\r
- UINT32 RegOffset;\r
- UINTN RegShift;\r
- ARM_GIC_ARCH_REVISION Revision;\r
- UINTN GicCpuRedistributorBase;\r
- UINT32 Interrupts;\r
+ UINT32 RegOffset;\r
+ UINTN RegShift;\r
+ ARM_GIC_ARCH_REVISION Revision;\r
+ UINTN GicCpuRedistributorBase;\r
+ UINT32 Interrupts;\r
\r
// Calculate enable register offset and bit position\r
RegOffset = Source / 32;\r
- RegShift = Source % 32;\r
+ RegShift = Source % 32;\r
\r
Revision = ArmGicGetSupportedArchRevision ();\r
- if ((Revision == ARM_GIC_ARCH_REVISION_2) || FeaturePcdGet (PcdArmGicV3WithV2Legacy)) {\r
- Interrupts = ((MmioRead32 (GicDistributorBase + ARM_GIC_ICDISER + (4 * RegOffset)) & (1 << RegShift)) != 0);\r
+ if ((Revision == ARM_GIC_ARCH_REVISION_2) ||\r
+ FeaturePcdGet (PcdArmGicV3WithV2Legacy) ||\r
+ SourceIsSpi (Source))\r
+ {\r
+ Interrupts = ((MmioRead32 (\r
+ GicDistributorBase + ARM_GIC_ICDISER + (4 * RegOffset)\r
+ )\r
+ & (1 << RegShift)) != 0);\r
} else {\r
- GicCpuRedistributorBase = GicGetCpuRedistributorBase (GicRedistributorBase, Revision);\r
+ GicCpuRedistributorBase = GicGetCpuRedistributorBase (\r
+ GicRedistributorBase,\r
+ Revision\r
+ );\r
if (GicCpuRedistributorBase == 0) {\r
return 0;\r
}\r
\r
// Read set-enable register\r
- Interrupts = MmioRead32 (GicCpuRedistributorBase + ARM_GICR_CTLR_FRAME_SIZE + ARM_GICR_ISENABLER + (4 * RegOffset));\r
+ Interrupts = MmioRead32 (\r
+ ISENABLER_ADDRESS (GicCpuRedistributorBase, RegOffset)\r
+ );\r
}\r
\r
return ((Interrupts & (1 << RegShift)) != 0);\r
VOID\r
EFIAPI\r
ArmGicDisableDistributor (\r
- IN INTN GicDistributorBase\r
+ IN INTN GicDistributorBase\r
)\r
{\r
// Disable Gic Distributor\r
VOID\r
EFIAPI\r
ArmGicEnableInterruptInterface (\r
- IN INTN GicInterruptInterfaceBase\r
+ IN INTN GicInterruptInterfaceBase\r
)\r
{\r
- ARM_GIC_ARCH_REVISION Revision;\r
+ ARM_GIC_ARCH_REVISION Revision;\r
\r
Revision = ArmGicGetSupportedArchRevision ();\r
if (Revision == ARM_GIC_ARCH_REVISION_2) {\r
VOID\r
EFIAPI\r
ArmGicDisableInterruptInterface (\r
- IN INTN GicInterruptInterfaceBase\r
+ IN INTN GicInterruptInterfaceBase\r
)\r
{\r
- ARM_GIC_ARCH_REVISION Revision;\r
+ ARM_GIC_ARCH_REVISION Revision;\r
\r
Revision = ArmGicGetSupportedArchRevision ();\r
if (Revision == ARM_GIC_ARCH_REVISION_2) {\r