Reviewed-by: Jordan Justen <jordan.l.jus...@intel.com>

On 2015-05-05 07:21:34, Laszlo Ersek wrote:
> 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

------------------------------------------------------------------------------
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