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 <ler...@redhat.com>
---
 OvmfPkg/Library/QemuBootOrderLib/QemuBootOrderLib.c | 118 +++++++++++++++-----
 1 file changed, 92 insertions(+), 26 deletions(-)

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


------------------------------------------------------------------------------
One dashboard for servers and applications across Physical-Virtual-Cloud 
Widest out-of-the-box monitoring support with 50+ applications
Performance metrics, stats and reports that give you Actionable Insights
Deep dive visibility with transaction tracing using APM Insight.
http://ad.doubleclick.net/ddm/clk/290420510;117567292;y
_______________________________________________
edk2-devel mailing list
edk2-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/edk2-devel

Reply via email to