<html>
  <head>
    <meta content="text/html; charset=utf-8" http-equiv="Content-Type">
  </head>
  <body bgcolor="#FFFFFF" text="#000000">
    <div class="moz-cite-prefix">On 10/13/2016 01:43 PM, Laine Stump
      wrote:<br>
    </div>
    <blockquote
      cite="mid:d9c5386d-1d01-a4dc-944a-b7fee729d679@laine.org"
      type="cite">On 10/11/2016 05:34 AM, Andrea Bolognani wrote:
      <br>
      <blockquote type="cite">On Mon, 2016-10-10 at 15:43 -0400, Laine
        Stump wrote:
        <br>
        <blockquote type="cite">
          <blockquote type="cite">
            <blockquote type="cite">3) Although it is strongly
              discouraged, it is legal for a pci-bridge
              <br>
                     to be directly plugged into pcie-root, and we don't
              want to
              <br>
                     auto-add a dmi-to-pci-bridge if there is already a
              pci-bridge
              <br>
                     that's been forced directly into pcie-root.
              Finally, although I
              <br>
                     fail to see the utility of it, it is legal to have
              something like
              <br>
                     this in the xml:
              <br>
                           <controller type='pci' model='pcie-root'
              index='0'/>
              <br>
                       <controller type='pci' model='pci-bridge'
              index='2'/>
              <br>
                         and that will lead to an automatically added
              dmi-to-pci-bridge at
              <br>
                     index=1 (to give the unaddressed pci-bridge a
              proper place to plug
              <br>
                     in):
              <br>
                           <controller type='pci'
              model='dmi-to-pci-bridge' index='1'/>
              <br>
                         (for example, see the existing test case
              <br>
                     "usb-controller-default-q35"). This is handled in
              <br>
                     qemuDomainPCIAddressSetCreate() when it's adding in
              controllers to
              <br>
                     fill holes in the indexes.
              <br>
            </blockquote>
              I wonder how this "feature" came to be... It seems to be
            the
            <br>
            reason for quite a bit of convoluted code down below, which
            <br>
            we could avoid if this had never worked at all. As is so
            <br>
            often the case, too late for that :(
            <br>
          </blockquote>
            Maybe not. The only place I ever saw that was in the above
          test case,
          <br>
          and another named "usb-controller-explicit-q35", and the
          author of both
          <br>
          of those tests was (wait for it!), no, not Albert Einstein. 
          Andrea
          <br>
          Bolognani!
          <br>
        </blockquote>
        Oh, *that* guy! It's always *that* guy, isn't it? :P
        <br>
        <br>
        <blockquote type="cite">The only reason it worked in the past
          was because we always
          <br>
          automatically added the dmi-to-pci-bridge very early in the
          post-parse
          <br>
          processing. This implies that any saved config anywhere will
          already
          <br>
          have the necessary dmi-to-pci-bridge at index='1', so we only
          need to
          <br>
          preserve the behavior for new domain definitions that have a
          pci-bridge
          <br>
          at index='2' but nothing at index='1'.
          <br>
            Since you're the only person documented to have ever created
          a config
          <br>
          like that, and it would only be problematic if someone tried
          to create
          <br>
          another new config, maybe we should just stop accidentally
          supporting it
          <br>
          and count it as a bug that's being fixed. What's your opinion?
          <br>
        </blockquote>
        Given the evidence you're presenting, I'm all for getting
        <br>
        rid of it, especially since it will make the code below
        <br>
        much simpler and hence more maintainable.
        <br>
        <br>
        Considering how critical that part of libvirt is, anything
        <br>
        we can do to make it leaner and meaner is going to be a huge
        <br>
        win in the long run.
        <br>
      </blockquote>
      <br>
      I'm looking back through the code and wondering how to simplify it
      - it may be that the alternate method I had initially used (which
      failed that one test) is just as complicated as what I have now;
      unfortunately I didn't save it.
      <br>
    </blockquote>
    <br>
    Okay, now I've reminded myself of what I did. Basically everything
    necessary for that is the changes to qemuDomainPCIAddressSetCreate()
    dealing with "lowest*Bridge" (see the patch excerpt below). I would
    still need to patch this function even if we didn't support
    "auto-adding dmi-to-pci-bridge when a pci-bridge is present in the
    config", but it would be slightly simpler.<br>
    <br>
    I'll split it into a separate patch so that it's more apparent, and
    we can decide based on that.<br>
    <br>
    <br>
    <div class="moz-cite-prefix">On 09/20/2016 03:14 PM, Laine Stump
      wrote:<br>
    </div>
    <blockquote
      cite="mid:1474398864-9039-16-git-send-email-laine@laine.org"
      type="cite">
      <pre wrap="">diff --git a/src/qemu/qemu_domain_address.c b/src/qemu/qemu_domain_address.c
index 1ff80e3..a9c4c32 100644
--- a/src/qemu/qemu_domain_address.c
+++ b/src/qemu/qemu_domain_address.c
@@ -797,6 +797,11 @@ qemuDomainPCIAddressSetCreate(virDomainDefPtr def,
 {
     virDomainPCIAddressSetPtr addrs;
     size_t i;
+    bool hasPCIeRoot = false;
+    int lowestDMIToPCIBridge = nbuses;
+    int lowestUnaddressedPCIBridge = nbuses;
+    int lowestAddressedPCIBridge = nbuses;
+    virDomainControllerModelPCI defaultModel;
 
     if ((addrs = virDomainPCIAddressSetAlloc(nbuses)) == NULL)
         return NULL;
@@ -804,38 +809,84 @@ qemuDomainPCIAddressSetCreate(virDomainDefPtr def,
     addrs->nbuses = nbuses;
     addrs->dryRun = dryRun;
 
-    /* As a safety measure, set default model='pci-root' for first pci
-     * controller and 'pci-bridge' for all subsequent. After setting
-     * those defaults, then scan the config and set the actual model
-     * for all addrs[idx]->bus that already have a corresponding
-     * controller in the config.
-     *
-     */
-    if (nbuses > 0)
-        virDomainPCIAddressBusSetModel(&addrs->buses[0],
-                                       VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT);
-    for (i = 1; i < nbuses; i++) {
-        virDomainPCIAddressBusSetModel(&addrs->buses[i],
-                                       VIR_DOMAIN_CONTROLLER_MODEL_PCI_BRIDGE);
-    }
-
     for (i = 0; i < def->ncontrollers; i++) {
-        size_t idx = def->controllers[i]->idx;
+        virDomainControllerDefPtr cont = def->controllers[i];
+        size_t idx = cont->idx;
 
-        if (def->controllers[i]->type != VIR_DOMAIN_CONTROLLER_TYPE_PCI)
+        if (cont->type != VIR_DOMAIN_CONTROLLER_TYPE_PCI)
             continue;
 
         if (idx >= addrs->nbuses) {
             virReportError(VIR_ERR_INTERNAL_ERROR,
                            _("Inappropriate new pci controller index %zu "
-                             "not found in addrs"), idx);
+                             "exceeds addrs array length"), idx);
             goto error;
         }
 
-        if (virDomainPCIAddressBusSetModel(&addrs->buses[idx],
-                                           def->controllers[i]->model) < 0)
+        if (virDomainPCIAddressBusSetModel(&addrs->buses[idx], cont->model) < 0)
             goto error;
+
+        /* we'll use all this info later to determine if we need
+         * to add a dmi-to-pci-bridge due to unaddressed pci-bridge controllers
+         */
+        if (cont->model == VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT) {
+            hasPCIeRoot = true;
+        } else if (cont->model ==
+                   VIR_DOMAIN_CONTROLLER_MODEL_DMI_TO_PCI_BRIDGE) {
+            if (lowestDMIToPCIBridge > idx)
+                lowestDMIToPCIBridge = idx;
+        } else if (cont->model == VIR_DOMAIN_CONTROLLER_MODEL_PCI_BRIDGE) {
+            if (virDeviceInfoPCIAddressWanted(&cont->info)) {
+                if (lowestUnaddressedPCIBridge > idx)
+                    lowestUnaddressedPCIBridge = idx;
+            } else {
+                if (lowestAddressedPCIBridge > idx)
+                    lowestAddressedPCIBridge = idx;
+            }
         }
+    }
+
+    if (nbuses > 0 && !addrs->buses[0].model) {
+        if (virDomainPCIAddressBusSetModel(&addrs->buses[0],
+                                           VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT) < 0)
+            goto error;
+    }
+
+    /* Now fill in a reasonable model for all the buses in the set
+     * that don't yet have a corresponding controller in the domain
+     * config.  In the rare (and actually fairly idiotic, but still
+     * allowed for some reason) case that a domain has 1) a pcie-root
+     * at index 0, 2) <b class="moz-txt-star"><span class="moz-txt-tag">*</span>no<span class="moz-txt-tag">*</span></b> dmi-to-pci-bridge (or pci-bridge that was
+     * manually addressed to sit directly on pcie-root), and 3) does
+     * have an unaddressed pci-bridge at an index > 1, then we need to
+     * add a dmi-to-pci-bridge.
+     */
+
+    if (!hasPCIeRoot)
+        defaultModel = VIR_DOMAIN_CONTROLLER_MODEL_PCI_BRIDGE;
+
+    else if (lowestUnaddressedPCIBridge < MIN(lowestAddressedPCIBridge,
+                                              lowestDMIToPCIBridge))
+        defaultModel = VIR_DOMAIN_CONTROLLER_MODEL_DMI_TO_PCI_BRIDGE;
+    else
+        defaultModel = VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT_PORT;
+
+    for (i = 1; i < addrs->nbuses; i++) {
+
+        if (addrs->buses[i].model)
+            continue;
+
+        if (virDomainPCIAddressBusSetModel(&addrs->buses[i], defaultModel) < 0)
+            goto error;
+
+        VIR_DEBUG("Auto-adding <controller type='pci' model='%s' index='%zu'/>",
+                  virDomainControllerModelPCITypeToString(defaultModel), i);
+        /* only add a single dmi-to-pci-bridge, then add pcie-root-port
+         * for any other unspecified controller indexes.
+         */
+        if (hasPCIeRoot)
+            defaultModel = VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT_PORT;
+    }</pre>
    </blockquote>
    <p><br>
    </p>
    <br>
  </body>
</html>