ArmPkg/ArmGicLib: manage GICv3 SPI state at the distributor

Unlike SGIs and PPIs, which are private to the CPU and are managed at
the redistributor level (which is also a per-CPU construct), shared
interrupts (SPIs) are shared between all CPUs, and therefore managed at
the distributor level (just as on GICv2).

Reported-by: Narinder Dhillon <ndhillonv2@gmail.com>
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Reviewed-by: Leif Lindholm <leif.lindholm@linaro.org>
diff --git a/ArmPkg/Drivers/ArmGic/ArmGicLib.c b/ArmPkg/Drivers/ArmGic/ArmGicLib.c
index 248e896..73795ed 100644
--- a/ArmPkg/Drivers/ArmGic/ArmGicLib.c
+++ b/ArmPkg/Drivers/ArmGic/ArmGicLib.c
@@ -20,6 +20,19 @@
 #include <Library/PcdLib.h>

 

 /**

+ *

+ * 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

@@ -183,7 +196,9 @@
   RegShift = Source % 32;

 

   Revision = ArmGicGetSupportedArchRevision ();

-  if ((Revision == ARM_GIC_ARCH_REVISION_2) || FeaturePcdGet (PcdArmGicV3WithV2Legacy)) {

+  if ((Revision == ARM_GIC_ARCH_REVISION_2) ||

+      FeaturePcdGet (PcdArmGicV3WithV2Legacy) ||

+      SourceIsSpi (Source)) {

     // Write set-enable register

     MmioWrite32 (GicDistributorBase + ARM_GIC_ICDISER + (4 * RegOffset), 1 << RegShift);

   } else {

@@ -216,7 +231,9 @@
   RegShift = Source % 32;

 

   Revision = ArmGicGetSupportedArchRevision ();

-  if ((Revision == ARM_GIC_ARCH_REVISION_2) || FeaturePcdGet (PcdArmGicV3WithV2Legacy)) {

+  if ((Revision == ARM_GIC_ARCH_REVISION_2) ||

+      FeaturePcdGet (PcdArmGicV3WithV2Legacy) ||

+      SourceIsSpi (Source)) {

     // Write clear-enable register

     MmioWrite32 (GicDistributorBase + ARM_GIC_ICDICER + (4 * RegOffset), 1 << RegShift);

   } else {

@@ -249,7 +266,9 @@
   RegShift = Source % 32;

 

   Revision = ArmGicGetSupportedArchRevision ();

-  if ((Revision == ARM_GIC_ARCH_REVISION_2) || FeaturePcdGet (PcdArmGicV3WithV2Legacy)) {

+  if ((Revision == ARM_GIC_ARCH_REVISION_2) ||

+      FeaturePcdGet (PcdArmGicV3WithV2Legacy) ||

+      SourceIsSpi (Source)) {

     Interrupts = ((MmioRead32 (GicDistributorBase + ARM_GIC_ICDISER + (4 * RegOffset)) & (1 << RegShift)) != 0);

   } else {

     GicCpuRedistributorBase = GicGetCpuRedistributorBase (GicRedistributorBase, Revision);