]> git.proxmox.com Git - mirror_edk2.git/commitdiff
OvmfPkg: QemuBootOrderLib: parse OFW device path nodes of PCI bridges
authorLaszlo Ersek <lersek@redhat.com>
Fri, 8 May 2015 18:12:44 +0000 (18:12 +0000)
committerlersek <lersek@Edk2>
Fri, 8 May 2015 18:12:44 +0000 (18:12 +0000)
When the Q35 machine type(s) of QEMU are used with libvirt, libvirt tends
to place some devices behind PCI bridges. This is then reflected in the
"bootorder" fw_cfg file. For example:

  /pci@i0cf8/pci-bridge@1e/pci-bridge@1/scsi@5/disk@0,0
  /pci@i0cf8/pci-bridge@1e/pci-bridge@1/scsi@3/channel@0/disk@0,0

As yet QemuBootOrderLib doesn't support such OFW device paths.

Add code that translates a sequence of pci-bridge nodes.

In practice libvirt seems to insert two such nodes (*), hence increment
EXAMINED_OFW_NODES with the same number.

(* Background, paraphrasing Laine Stump's words:

When the machine type is Q35, we create a dmi-to-pci bridge coming off of
the pcie root controller, and a pci-to-pci bridge coming off of that, then
attach most devices to the pci-to-pci bridge. This is done because you
can't hotplug into pcie-root, can't (or at least shouldn't) plug a
pci-to-pci bridge into pcie-root (so the next one has to be
dmi-to-pci-bridge), and can't hotplug into dmi-to-pci-bridge (so you need
to have a pci-to-pci bridge).)

Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
Reviewed-by: Jordan Justen <jordan.l.justen@intel.com>
git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@17385 6f19259b-4bc3-4df7-8a09-765794883524

OvmfPkg/Library/QemuBootOrderLib/QemuBootOrderLib.c

index e63ad262247bbc4abd452d3e86d8d2ea9ebba20b..276d675f505d1539babae4ed940cfb24446de389 100644 (file)
 **/\r
 #define TRANSLATION_OUTPUT_SIZE 0x100\r
 \r
+/**\r
+  Output buffer size for OpenFirmware to UEFI device path fragment translation,\r
+  in CHAR16's, for a sequence of PCI bridges.\r
+**/\r
+#define BRIDGE_TRANSLATION_OUTPUT_SIZE 0x40\r
 \r
 /**\r
   Numbers of nodes in OpenFirmware device paths that are required and examined.\r
 **/\r
 #define REQUIRED_PCI_OFW_NODES  2\r
 #define REQUIRED_MMIO_OFW_NODES 1\r
-#define EXAMINED_OFW_NODES      4\r
+#define EXAMINED_OFW_NODES      6\r
 \r
 \r
 /**\r
@@ -581,6 +586,9 @@ TranslatePciOfwNodes (
   IN OUT  UINTN          *TranslatedSize\r
   )\r
 {\r
+  UINTN  FirstNonBridge;\r
+  CHAR16 Bridges[BRIDGE_TRANSLATION_OUTPUT_SIZE];\r
+  UINTN  BridgesLen;\r
   UINT64 PciDevFun[2];\r
   UINTN  NumEntries;\r
   UINTN  Written;\r
@@ -593,10 +601,63 @@ TranslatePciOfwNodes (
       ) {\r
     return RETURN_UNSUPPORTED;\r
   }\r
+\r
+  //\r
+  // Translate a sequence of PCI bridges. For each bridge, the OFW node is:\r
+  //\r
+  //   pci-bridge@1e[,0]\r
+  //              ^   ^\r
+  //              PCI slot & function on the parent, holding the bridge\r
+  //\r
+  // and the UEFI device path node is:\r
+  //\r
+  //   Pci(0x1E,0x0)\r
+  //\r
+  FirstNonBridge = 1;\r
+  Bridges[0] = L'\0';\r
+  BridgesLen = 0;\r
+  do {\r
+    UINT64 BridgeDevFun[2];\r
+    UINTN  BridgesFreeBytes;\r
+\r
+    if (!SubstringEq (OfwNode[FirstNonBridge].DriverName, "pci-bridge")) {\r
+      break;\r
+    }\r
+\r
+    BridgeDevFun[1] = 0;\r
+    NumEntries = sizeof BridgeDevFun / sizeof BridgeDevFun[0];\r
+    if (ParseUnitAddressHexList (OfwNode[FirstNonBridge].UnitAddress,\r
+          BridgeDevFun, &NumEntries) != RETURN_SUCCESS) {\r
+      return RETURN_UNSUPPORTED;\r
+    }\r
+\r
+    BridgesFreeBytes = sizeof Bridges - BridgesLen * sizeof Bridges[0];\r
+    Written = UnicodeSPrintAsciiFormat (Bridges + BridgesLen, BridgesFreeBytes,\r
+                "/Pci(0x%Lx,0x%Lx)", BridgeDevFun[0], BridgeDevFun[1]);\r
+    BridgesLen += Written;\r
+\r
+    //\r
+    // There's no way to differentiate between "completely used up without\r
+    // truncation" and "truncated", so treat the former as the latter.\r
+    //\r
+    if (BridgesLen + 1 == BRIDGE_TRANSLATION_OUTPUT_SIZE) {\r
+      return RETURN_UNSUPPORTED;\r
+    }\r
+\r
+    ++FirstNonBridge;\r
+  } while (FirstNonBridge < NumNodes);\r
+\r
+  if (FirstNonBridge == NumNodes) {\r
+    return RETURN_UNSUPPORTED;\r
+  }\r
+\r
+  //\r
+  // Parse the OFW nodes starting with the first non-bridge node.\r
+  //\r
   PciDevFun[1] = 0;\r
   NumEntries = sizeof (PciDevFun) / sizeof (PciDevFun[0]);\r
   if (ParseUnitAddressHexList (\r
-        OfwNode[1].UnitAddress,\r
+        OfwNode[FirstNonBridge].UnitAddress,\r
         PciDevFun,\r
         &NumEntries\r
         ) != RETURN_SUCCESS\r
@@ -604,10 +665,10 @@ TranslatePciOfwNodes (
     return RETURN_UNSUPPORTED;\r
   }\r
 \r
-  if (NumNodes >= 4 &&\r
-      SubstringEq (OfwNode[1].DriverName, "ide") &&\r
-      SubstringEq (OfwNode[2].DriverName, "drive") &&\r
-      SubstringEq (OfwNode[3].DriverName, "disk")\r
+  if (NumNodes >= FirstNonBridge + 3 &&\r
+      SubstringEq (OfwNode[FirstNonBridge + 0].DriverName, "ide") &&\r
+      SubstringEq (OfwNode[FirstNonBridge + 1].DriverName, "drive") &&\r
+      SubstringEq (OfwNode[FirstNonBridge + 2].DriverName, "disk")\r
       ) {\r
     //\r
     // OpenFirmware device path (IDE disk, IDE CD-ROM):\r
@@ -630,13 +691,13 @@ TranslatePciOfwNodes (
 \r
     NumEntries = 1;\r
     if (ParseUnitAddressHexList (\r
-          OfwNode[2].UnitAddress,\r
+          OfwNode[FirstNonBridge + 1].UnitAddress,\r
           &Secondary,\r
           &NumEntries\r
           ) != RETURN_SUCCESS ||\r
         Secondary > 1 ||\r
         ParseUnitAddressHexList (\r
-          OfwNode[3].UnitAddress,\r
+          OfwNode[FirstNonBridge + 2].UnitAddress,\r
           &Slave,\r
           &NumEntries // reuse after previous single-element call\r
           ) != RETURN_SUCCESS ||\r
@@ -648,16 +709,17 @@ TranslatePciOfwNodes (
     Written = UnicodeSPrintAsciiFormat (\r
       Translated,\r
       *TranslatedSize * sizeof (*Translated), // BufferSize in bytes\r
-      "PciRoot(0x0)/Pci(0x%Lx,0x%Lx)/Ata(%a,%a,0x0)",\r
+      "PciRoot(0x0)%s/Pci(0x%Lx,0x%Lx)/Ata(%a,%a,0x0)",\r
+      Bridges,\r
       PciDevFun[0],\r
       PciDevFun[1],\r
       Secondary ? "Secondary" : "Primary",\r
       Slave ? "Slave" : "Master"\r
       );\r
-  } else if (NumNodes >= 4 &&\r
-             SubstringEq (OfwNode[1].DriverName, "isa") &&\r
-             SubstringEq (OfwNode[2].DriverName, "fdc") &&\r
-             SubstringEq (OfwNode[3].DriverName, "floppy")\r
+  } else if (NumNodes >= FirstNonBridge + 3 &&\r
+             SubstringEq (OfwNode[FirstNonBridge + 0].DriverName, "isa") &&\r
+             SubstringEq (OfwNode[FirstNonBridge + 1].DriverName, "fdc") &&\r
+             SubstringEq (OfwNode[FirstNonBridge + 2].DriverName, "floppy")\r
              ) {\r
     //\r
     // OpenFirmware device path (floppy disk):\r
@@ -679,7 +741,7 @@ TranslatePciOfwNodes (
 \r
     NumEntries = 1;\r
     if (ParseUnitAddressHexList (\r
-          OfwNode[3].UnitAddress,\r
+          OfwNode[FirstNonBridge + 2].UnitAddress,\r
           &AcpiUid,\r
           &NumEntries\r
           ) != RETURN_SUCCESS ||\r
@@ -691,14 +753,15 @@ TranslatePciOfwNodes (
     Written = UnicodeSPrintAsciiFormat (\r
       Translated,\r
       *TranslatedSize * sizeof (*Translated), // BufferSize in bytes\r
-      "PciRoot(0x0)/Pci(0x%Lx,0x%Lx)/Floppy(0x%Lx)",\r
+      "PciRoot(0x0)%s/Pci(0x%Lx,0x%Lx)/Floppy(0x%Lx)",\r
+      Bridges,\r
       PciDevFun[0],\r
       PciDevFun[1],\r
       AcpiUid\r
       );\r
-  } else if (NumNodes >= 3 &&\r
-             SubstringEq (OfwNode[1].DriverName, "scsi") &&\r
-             SubstringEq (OfwNode[2].DriverName, "disk")\r
+  } else if (NumNodes >= FirstNonBridge + 2 &&\r
+             SubstringEq (OfwNode[FirstNonBridge + 0].DriverName, "scsi") &&\r
+             SubstringEq (OfwNode[FirstNonBridge + 1].DriverName, "disk")\r
              ) {\r
     //\r
     // OpenFirmware device path (virtio-blk disk):\r
@@ -718,14 +781,15 @@ TranslatePciOfwNodes (
     Written = UnicodeSPrintAsciiFormat (\r
       Translated,\r
       *TranslatedSize * sizeof (*Translated), // BufferSize in bytes\r
-      "PciRoot(0x0)/Pci(0x%Lx,0x%Lx)/HD(",\r
+      "PciRoot(0x0)%s/Pci(0x%Lx,0x%Lx)/HD(",\r
+      Bridges,\r
       PciDevFun[0],\r
       PciDevFun[1]\r
       );\r
-  } else if (NumNodes >= 4 &&\r
-             SubstringEq (OfwNode[1].DriverName, "scsi") &&\r
-             SubstringEq (OfwNode[2].DriverName, "channel") &&\r
-             SubstringEq (OfwNode[3].DriverName, "disk")\r
+  } else if (NumNodes >= FirstNonBridge + 3 &&\r
+             SubstringEq (OfwNode[FirstNonBridge + 0].DriverName, "scsi") &&\r
+             SubstringEq (OfwNode[FirstNonBridge + 1].DriverName, "channel") &&\r
+             SubstringEq (OfwNode[FirstNonBridge + 2].DriverName, "disk")\r
              ) {\r
     //\r
     // OpenFirmware device path (virtio-scsi disk):\r
@@ -750,7 +814,7 @@ TranslatePciOfwNodes (
     TargetLun[1] = 0;\r
     NumEntries = sizeof (TargetLun) / sizeof (TargetLun[0]);\r
     if (ParseUnitAddressHexList (\r
-          OfwNode[3].UnitAddress,\r
+          OfwNode[FirstNonBridge + 2].UnitAddress,\r
           TargetLun,\r
           &NumEntries\r
           ) != RETURN_SUCCESS\r
@@ -761,7 +825,8 @@ TranslatePciOfwNodes (
     Written = UnicodeSPrintAsciiFormat (\r
       Translated,\r
       *TranslatedSize * sizeof (*Translated), // BufferSize in bytes\r
-      "PciRoot(0x0)/Pci(0x%Lx,0x%Lx)/Scsi(0x%Lx,0x%Lx)",\r
+      "PciRoot(0x0)%s/Pci(0x%Lx,0x%Lx)/Scsi(0x%Lx,0x%Lx)",\r
+      Bridges,\r
       PciDevFun[0],\r
       PciDevFun[1],\r
       TargetLun[0],\r
@@ -784,7 +849,8 @@ TranslatePciOfwNodes (
     Written = UnicodeSPrintAsciiFormat (\r
       Translated,\r
       *TranslatedSize * sizeof (*Translated), // BufferSize in bytes\r
-      "PciRoot(0x0)/Pci(0x%Lx,0x%Lx)",\r
+      "PciRoot(0x0)%s/Pci(0x%Lx,0x%Lx)",\r
+      Bridges,\r
       PciDevFun[0],\r
       PciDevFun[1]\r
       );\r