+//\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
+STATIC\r
+RETURN_STATUS\r
+GetPciIoTranslation (\r
+ IN FDT_CLIENT_PROTOCOL *FdtClient,\r
+ IN INT32 Node,\r
+ OUT UINT64 *IoTranslation\r
+ )\r
+{\r
+ UINT32 RecordIdx;\r
+ CONST VOID *Prop;\r
+ UINT32 Len;\r
+ EFI_STATUS Status;\r
+ UINT64 IoBase;\r
+\r
+ //\r
+ // Iterate over "ranges".\r
+ //\r
+ Status = FdtClient->GetNodeProperty (FdtClient, Node, "ranges", &Prop, &Len);\r
+ if (EFI_ERROR (Status) || 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 RETURN_PROTOCOL_ERROR;\r
+ }\r
+\r
+ for (RecordIdx = 0; RecordIdx < Len / sizeof (DTB_PCI_HOST_RANGE_RECORD);\r
+ ++RecordIdx) {\r
+ CONST DTB_PCI_HOST_RANGE_RECORD *Record;\r
+ UINT32 Type;\r
+\r
+ Record = (CONST DTB_PCI_HOST_RANGE_RECORD *)Prop + RecordIdx;\r
+ Type = SwapBytes32 (Record->Type) & DTB_PCI_HOST_RANGE_TYPEMASK;\r
+ if (Type == DTB_PCI_HOST_RANGE_IO) {\r
+ IoBase = SwapBytes64 (Record->ChildBase);\r
+ *IoTranslation = SwapBytes64 (Record->CpuBase) - IoBase;\r
+\r
+ return RETURN_SUCCESS;\r
+ }\r
+ }\r
+ return RETURN_NOT_FOUND;\r
+}\r
+\r