]> git.proxmox.com Git - mirror_edk2.git/blobdiff - ArmPlatformPkg/ArmVirtualizationPkg/VirtFdtDxe/VirtFdtDxe.c
MdeModulePkg/UfsPciHcDxe: Fix EBC build error
[mirror_edk2.git] / ArmPlatformPkg / ArmVirtualizationPkg / VirtFdtDxe / VirtFdtDxe.c
index 751864d4db9cff1a33f3580bb0e88eeeafd568ec..c9a181a871b8cf2ca555553c649c383bdcc0ec74 100644 (file)
 #include <Library/DevicePathLib.h>\r
 #include <Library/PcdLib.h>\r
 #include <Library/DxeServicesLib.h>\r
+#include <Library/HobLib.h>\r
 #include <libfdt.h>\r
+#include <Library/XenIoMmioLib.h>\r
 \r
 #include <Guid/Fdt.h>\r
 #include <Guid/VirtioMmioTransport.h>\r
+#include <Guid/FdtHob.h>\r
 \r
 #pragma pack (1)\r
 typedef struct {\r
@@ -46,23 +49,29 @@ typedef enum {
   PropertyTypeTimer,\r
   PropertyTypePsci,\r
   PropertyTypeFwCfg,\r
+  PropertyTypePciHost,\r
+  PropertyTypeGicV3,\r
+  PropertyTypeXen,\r
 } PROPERTY_TYPE;\r
 \r
 typedef struct {\r
   PROPERTY_TYPE Type;\r
-  CHAR8         Compatible[20];\r
+  CHAR8         Compatible[32];\r
 } PROPERTY;\r
 \r
 STATIC CONST PROPERTY CompatibleProperties[] = {\r
-  { PropertyTypeGic,     "arm,cortex-a15-gic"  },\r
-  { PropertyTypeRtc,     "arm,pl031"           },\r
-  { PropertyTypeVirtio,  "virtio,mmio"         },\r
-  { PropertyTypeUart,    "arm,pl011"           },\r
-  { PropertyTypeTimer,   "arm,armv7-timer"     },\r
-  { PropertyTypeTimer,   "arm,armv8-timer"     },\r
-  { PropertyTypePsci,    "arm,psci-0.2"        },\r
-  { PropertyTypeFwCfg,   "qemu,fw-cfg-mmio"    },\r
-  { PropertyTypeUnknown, ""                    }\r
+  { PropertyTypeGic,     "arm,cortex-a15-gic"    },\r
+  { PropertyTypeRtc,     "arm,pl031"             },\r
+  { PropertyTypeVirtio,  "virtio,mmio"           },\r
+  { PropertyTypeUart,    "arm,pl011"             },\r
+  { PropertyTypeTimer,   "arm,armv7-timer"       },\r
+  { PropertyTypeTimer,   "arm,armv8-timer"       },\r
+  { PropertyTypePsci,    "arm,psci-0.2"          },\r
+  { PropertyTypeFwCfg,   "qemu,fw-cfg-mmio"      },\r
+  { PropertyTypePciHost, "pci-host-ecam-generic" },\r
+  { PropertyTypeGicV3,   "arm,gic-v3"            },\r
+  { PropertyTypeXen,     "xen,xen"               },\r
+  { PropertyTypeUnknown, ""                      }\r
 };\r
 \r
 typedef struct {\r
@@ -96,6 +105,176 @@ GetTypeFromNode (
   return PropertyTypeUnknown;\r
 }\r
 \r
+//\r
+// We expect the "ranges" property of "pci-host-ecam-generic" to consist of\r
+// records like this.\r
+//\r
+#pragma pack (1)\r
+typedef struct {\r
+  UINT32 Type;\r
+  UINT64 ChildBase;\r
+  UINT64 CpuBase;\r
+  UINT64 Size;\r
+} DTB_PCI_HOST_RANGE_RECORD;\r
+#pragma pack ()\r
+\r
+#define DTB_PCI_HOST_RANGE_RELOCATABLE  BIT31\r
+#define DTB_PCI_HOST_RANGE_PREFETCHABLE BIT30\r
+#define DTB_PCI_HOST_RANGE_ALIASED      BIT29\r
+#define DTB_PCI_HOST_RANGE_MMIO32       BIT25\r
+#define DTB_PCI_HOST_RANGE_MMIO64       (BIT25 | BIT24)\r
+#define DTB_PCI_HOST_RANGE_IO           BIT24\r
+#define DTB_PCI_HOST_RANGE_TYPEMASK     (BIT31 | BIT30 | BIT29 | BIT25 | BIT24)\r
+\r
+/**\r
+  Process the device tree node describing the generic PCI host controller.\r
+\r
+  param[in] DeviceTreeBase  Pointer to the device tree.\r
+\r
+  param[in] Node            Offset of the device tree node whose "compatible"\r
+                            property is "pci-host-ecam-generic".\r
+\r
+  param[in] RegProp         Pointer to the "reg" property of Node. The caller\r
+                            is responsible for ensuring that the size of the\r
+                            property is 4 UINT32 cells.\r
+\r
+  @retval EFI_SUCCESS         Parsing successful, properties parsed from Node\r
+                              have been stored in dynamic PCDs.\r
+\r
+  @retval EFI_PROTOCOL_ERROR  Parsing failed. PCDs are left unchanged.\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+ProcessPciHost (\r
+  IN CONST VOID *DeviceTreeBase,\r
+  IN INT32      Node,\r
+  IN CONST VOID *RegProp\r
+  )\r
+{\r
+  UINT64     ConfigBase, ConfigSize;\r
+  CONST VOID *Prop;\r
+  INT32      Len;\r
+  UINT32     BusMin, BusMax;\r
+  UINT32     RecordIdx;\r
+  UINT64     IoBase, IoSize, IoTranslation;\r
+  UINT64     MmioBase, MmioSize, MmioTranslation;\r
+\r
+  //\r
+  // Fetch the ECAM window.\r
+  //\r
+  ConfigBase = fdt64_to_cpu (((CONST UINT64 *)RegProp)[0]);\r
+  ConfigSize = fdt64_to_cpu (((CONST UINT64 *)RegProp)[1]);\r
+\r
+  //\r
+  // Fetch the bus range (note: inclusive).\r
+  //\r
+  Prop = fdt_getprop (DeviceTreeBase, Node, "bus-range", &Len);\r
+  if (Prop == NULL || Len != 2 * sizeof(UINT32)) {\r
+    DEBUG ((EFI_D_ERROR, "%a: 'bus-range' not found or invalid\n",\r
+      __FUNCTION__));\r
+    return EFI_PROTOCOL_ERROR;\r
+  }\r
+  BusMin = fdt32_to_cpu (((CONST UINT32 *)Prop)[0]);\r
+  BusMax = fdt32_to_cpu (((CONST UINT32 *)Prop)[1]);\r
+\r
+  //\r
+  // Sanity check: the config space must accommodate all 4K register bytes of\r
+  // all 8 functions of all 32 devices of all buses.\r
+  //\r
+  if (BusMax < BusMin || BusMax - BusMin == MAX_UINT32 ||\r
+      DivU64x32 (ConfigSize, SIZE_4KB * 8 * 32) < BusMax - BusMin + 1) {\r
+    DEBUG ((EFI_D_ERROR, "%a: invalid 'bus-range' and/or 'reg'\n",\r
+      __FUNCTION__));\r
+    return EFI_PROTOCOL_ERROR;\r
+  }\r
+\r
+  //\r
+  // Iterate over "ranges".\r
+  //\r
+  Prop = fdt_getprop (DeviceTreeBase, Node, "ranges", &Len);\r
+  if (Prop == NULL || Len == 0 ||\r
+      Len % sizeof (DTB_PCI_HOST_RANGE_RECORD) != 0) {\r
+    DEBUG ((EFI_D_ERROR, "%a: 'ranges' not found or invalid\n", __FUNCTION__));\r
+    return EFI_PROTOCOL_ERROR;\r
+  }\r
+\r
+  //\r
+  // IoBase, IoTranslation, MmioBase and MmioTranslation are initialized only\r
+  // in order to suppress '-Werror=maybe-uninitialized' warnings *incorrectly*\r
+  // emitted by some gcc versions.\r
+  //\r
+  IoBase = 0;\r
+  IoTranslation = 0;\r
+  MmioBase = 0;\r
+  MmioTranslation = 0;\r
+\r
+  //\r
+  // IoSize and MmioSize are initialized to zero because the logic below\r
+  // requires it.\r
+  //\r
+  IoSize = 0;\r
+  MmioSize = 0;\r
+  for (RecordIdx = 0; RecordIdx < Len / sizeof (DTB_PCI_HOST_RANGE_RECORD);\r
+       ++RecordIdx) {\r
+    CONST DTB_PCI_HOST_RANGE_RECORD *Record;\r
+\r
+    Record = (CONST DTB_PCI_HOST_RANGE_RECORD *)Prop + RecordIdx;\r
+    switch (fdt32_to_cpu (Record->Type) & DTB_PCI_HOST_RANGE_TYPEMASK) {\r
+    case DTB_PCI_HOST_RANGE_IO:\r
+      IoBase = fdt64_to_cpu (Record->ChildBase);\r
+      IoSize = fdt64_to_cpu (Record->Size);\r
+      IoTranslation = fdt64_to_cpu (Record->CpuBase) - IoBase;\r
+      break;\r
+\r
+    case DTB_PCI_HOST_RANGE_MMIO32:\r
+      MmioBase = fdt64_to_cpu (Record->ChildBase);\r
+      MmioSize = fdt64_to_cpu (Record->Size);\r
+      MmioTranslation = fdt64_to_cpu (Record->CpuBase) - MmioBase;\r
+\r
+      if (MmioBase > MAX_UINT32 || MmioSize > MAX_UINT32 ||\r
+          MmioBase + MmioSize > SIZE_4GB) {\r
+        DEBUG ((EFI_D_ERROR, "%a: MMIO32 space invalid\n", __FUNCTION__));\r
+        return EFI_PROTOCOL_ERROR;\r
+      }\r
+\r
+      if (MmioTranslation != 0) {\r
+        DEBUG ((EFI_D_ERROR, "%a: unsupported nonzero MMIO32 translation "\r
+          "0x%Lx\n", __FUNCTION__, MmioTranslation));\r
+        return EFI_UNSUPPORTED;\r
+      }\r
+\r
+      break;\r
+    }\r
+  }\r
+  if (IoSize == 0 || MmioSize == 0) {\r
+    DEBUG ((EFI_D_ERROR, "%a: %a space empty\n", __FUNCTION__,\r
+      (IoSize == 0) ? "IO" : "MMIO32"));\r
+    return EFI_PROTOCOL_ERROR;\r
+  }\r
+\r
+  PcdSet64 (PcdPciExpressBaseAddress, ConfigBase);\r
+\r
+  PcdSet32 (PcdPciBusMin, BusMin);\r
+  PcdSet32 (PcdPciBusMax, BusMax);\r
+\r
+  PcdSet64 (PcdPciIoBase,        IoBase);\r
+  PcdSet64 (PcdPciIoSize,        IoSize);\r
+  PcdSet64 (PcdPciIoTranslation, IoTranslation);\r
+\r
+  PcdSet32 (PcdPciMmio32Base, (UINT32)MmioBase);\r
+  PcdSet32 (PcdPciMmio32Size, (UINT32)MmioSize);\r
+\r
+  PcdSetBool (PcdPciDisableBusEnumeration, FALSE);\r
+\r
+  DEBUG ((EFI_D_INFO, "%a: Config[0x%Lx+0x%Lx) Bus[0x%x..0x%x] "\r
+    "Io[0x%Lx+0x%Lx)@0x%Lx Mem[0x%Lx+0x%Lx)@0x%Lx\n", __FUNCTION__, ConfigBase,\r
+    ConfigSize, BusMin, BusMax, IoBase, IoSize, IoTranslation, MmioBase,\r
+    MmioSize, MmioTranslation));\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
 EFI_STATUS\r
 EFIAPI\r
 InitializeVirtFdtDxe (\r
@@ -103,6 +282,7 @@ InitializeVirtFdtDxe (
   IN EFI_SYSTEM_TABLE     *SystemTable\r
   )\r
 {\r
+  VOID                           *Hob;\r
   VOID                           *DeviceTreeBase;\r
   INT32                          Node, Prev;\r
   INT32                          RtcNode;\r
@@ -114,7 +294,7 @@ InitializeVirtFdtDxe (
   VIRTIO_TRANSPORT_DEVICE_PATH   *DevicePath;\r
   EFI_HANDLE                     Handle;\r
   UINT64                         RegBase;\r
-  UINT64                         DistBase, CpuBase;\r
+  UINT64                         DistBase, CpuBase, RedistBase;\r
   CONST INTERRUPT_PROPERTY       *InterruptProp;\r
   INT32                          SecIntrNum, IntrNum, VirtIntrNum, HypIntrNum;\r
   CONST CHAR8                    *PsciMethod;\r
@@ -123,8 +303,11 @@ InitializeVirtFdtDxe (
   UINT64                         FwCfgDataAddress;\r
   UINT64                         FwCfgDataSize;\r
 \r
-  DeviceTreeBase = (VOID *)(UINTN)PcdGet64 (PcdDeviceTreeBaseAddress);\r
-  ASSERT (DeviceTreeBase != NULL);\r
+  Hob = GetFirstGuidHob(&gFdtHobGuid);\r
+  if (Hob == NULL || GET_GUID_HOB_DATA_SIZE (Hob) != sizeof (UINT64)) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+  DeviceTreeBase = (VOID *)(UINTN)*(UINT64 *)GET_GUID_HOB_DATA (Hob);\r
 \r
   if (fdt_check_header (DeviceTreeBase) != 0) {\r
     DEBUG ((EFI_D_ERROR, "%a: No DTB found @ 0x%p\n", __FUNCTION__, DeviceTreeBase));\r
@@ -167,6 +350,12 @@ InitializeVirtFdtDxe (
       (PropType == PropertyTypePsci));\r
 \r
     switch (PropType) {\r
+    case PropertyTypePciHost:\r
+      ASSERT (Len == 2 * sizeof (UINT64));\r
+      Status = ProcessPciHost (DeviceTreeBase, Node, RegProp);\r
+      ASSERT_EFI_ERROR (Status);\r
+      break;\r
+\r
     case PropertyTypeFwCfg:\r
       ASSERT (Len == 2 * sizeof (UINT64));\r
 \r
@@ -256,6 +445,36 @@ InitializeVirtFdtDxe (
       DEBUG ((EFI_D_INFO, "Found GIC @ 0x%Lx/0x%Lx\n", DistBase, CpuBase));\r
       break;\r
 \r
+    case PropertyTypeGicV3:\r
+      //\r
+      // The GIC v3 DT binding describes a series of at least 3 physical (base\r
+      // addresses, size) pairs: the distributor interface (GICD), at least one\r
+      // redistributor region (GICR) containing dedicated redistributor\r
+      // interfaces for all individual CPUs, and the CPU interface (GICC).\r
+      // Under virtualization, we assume that the first redistributor region\r
+      // listed covers the boot CPU. Also, our GICv3 driver only supports the\r
+      // system register CPU interface, so we can safely ignore the MMIO version\r
+      // which is listed after the sequence of redistributor interfaces.\r
+      // This means we are only interested in the first two memory regions\r
+      // supplied, and ignore everything else.\r
+      //\r
+      ASSERT (Len >= 32);\r
+\r
+      // RegProp[0..1] == { GICD base, GICD size }\r
+      DistBase = fdt64_to_cpu (((UINT64 *)RegProp)[0]);\r
+      ASSERT (DistBase < MAX_UINT32);\r
+\r
+      // RegProp[2..3] == { GICR base, GICR size }\r
+      RedistBase = fdt64_to_cpu (((UINT64 *)RegProp)[2]);\r
+      ASSERT (RedistBase < MAX_UINT32);\r
+\r
+      PcdSet32 (PcdGicDistributorBase, (UINT32)DistBase);\r
+      PcdSet32 (PcdGicRedistributorsBase, (UINT32)RedistBase);\r
+\r
+      DEBUG ((EFI_D_INFO, "Found GIC v3 (re)distributor @ 0x%Lx (0x%Lx)\n",\r
+        DistBase, RedistBase));\r
+      break;\r
+\r
     case PropertyTypeRtc:\r
       ASSERT (Len == 16);\r
 \r
@@ -274,7 +493,7 @@ InitializeVirtFdtDxe (
       //  hypervisor timers, in that order.\r
       //\r
       InterruptProp = fdt_getprop (DeviceTreeBase, Node, "interrupts", &Len);\r
-      ASSERT (Len == 48);\r
+      ASSERT (Len == 36 || Len == 48);\r
 \r
       SecIntrNum = fdt32_to_cpu (InterruptProp[0].Number)\r
                    + (InterruptProp[0].Type ? 16 : 0);\r
@@ -282,8 +501,8 @@ InitializeVirtFdtDxe (
                 + (InterruptProp[1].Type ? 16 : 0);\r
       VirtIntrNum = fdt32_to_cpu (InterruptProp[2].Number)\r
                     + (InterruptProp[2].Type ? 16 : 0);\r
-      HypIntrNum = fdt32_to_cpu (InterruptProp[3].Number)\r
-                   + (InterruptProp[3].Type ? 16 : 0);\r
+      HypIntrNum = Len < 48 ? 0 : fdt32_to_cpu (InterruptProp[3].Number)\r
+                                  + (InterruptProp[3].Type ? 16 : 0);\r
 \r
       DEBUG ((EFI_D_INFO, "Found Timer interrupts %d, %d, %d, %d\n",\r
         SecIntrNum, IntrNum, VirtIntrNum, HypIntrNum));\r
@@ -307,6 +526,26 @@ InitializeVirtFdtDxe (
       }\r
       break;\r
 \r
+    case PropertyTypeXen:\r
+      ASSERT (Len == 16);\r
+\r
+      //\r
+      // Retrieve the reg base from this node and wire it up to the\r
+      // MMIO flavor of the XenBus root device I/O protocol\r
+      //\r
+      RegBase = fdt64_to_cpu (((UINT64 *)RegProp)[0]);\r
+      Handle = NULL;\r
+      Status = XenIoMmioInstall (&Handle, RegBase);\r
+      if (EFI_ERROR (Status)) {\r
+        DEBUG ((EFI_D_ERROR, "%a: XenIoMmioInstall () failed on a new handle "\r
+          "(Status == %r)\n", __FUNCTION__, Status));\r
+        break;\r
+      }\r
+\r
+      DEBUG ((EFI_D_INFO, "Found Xen node with Grant table @ 0x%Lx\n", RegBase));\r
+\r
+      break;\r
+\r
     default:\r
       break;\r
     }\r