]> git.proxmox.com Git - mirror_edk2.git/blobdiff - ArmPkg/Drivers/ArmGic/ArmGicLib.c
ArmPkg: Add support for GICv4
[mirror_edk2.git] / ArmPkg / Drivers / ArmGic / ArmGicLib.c
index 0087399fb1dba0e697f7a6ccd6f7432a59311ac6..0be5b14b4f6eba74903739d03912e73fdeb0e4e7 100644 (file)
@@ -1,6 +1,6 @@
 /** @file\r
 *\r
-*  Copyright (c) 2011-2017, ARM Limited. All rights reserved.\r
+*  Copyright (c) 2011-2018, 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
 #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
@@ -54,12 +64,11 @@ GicGetCpuRedistributorBase (
   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
+  UINT64 TypeRegister;\r
 \r
   MpId = ArmReadMpidr ();\r
   // Define CPU affinity as:\r
@@ -68,27 +77,30 @@ GicGetCpuRedistributorBase (
   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:\r
-    //   Redistributor control frame + SGI Control & Generation frame\r
-    GicRedistributorGranularity = ARM_GICR_CTLR_FRAME_SIZE\r
-                                  + 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
-    GicCpuRedistributorBase += 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