On 07/22/2015 05:38 PM, John Ferlan wrote:
On 07/17/2015 02:43 PM, Laine Stump wrote:
> This controller can be connected (at domain startup time only - not
> hotpluggable) only to a port on the pcie root complex ("pcie-root" in
> libvirt config), hence the new connect type
> VIR_PCI_CONNECT_TYPE_PCIE_ROOT. It provides a hotpluggable port that
> will accept any PCI or PCIe device.
>
> New attributes must be added to the controller <target> subelement for
> this - chassis and port are guest-visible option values that will be
> set by libvirt with values derived from the controller's index and pci
> address information.
> ---
> docs/formatdomain.html.in | 35 ++++++++++++++++++--
> docs/schemas/domaincommon.rng | 15 ++++++++-
> src/conf/domain_addr.c | 10 ++++--
> src/conf/domain_addr.h | 5 ++-
> src/conf/domain_conf.c | 37 ++++++++++++++++++++--
> src/conf/domain_conf.h | 7 +++-
> src/qemu/qemu_command.c | 1 +
> .../qemuxml2argv-pcie-root-port.xml | 36 +++++++++++++++++++++
> tests/qemuxml2xmltest.c | 1 +
> 9 files changed, 138 insertions(+), 9 deletions(-)
> create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-pcie-root-port.xml
>
Feels like two things happening in this patch - adding pcie-root and
adding chassis/port attributes. Are they separable - if so this patch
should be further split into two if only to aid bisection
Not really. You can't test chassis/port without having a controller type
that they are used with.
> diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in
> index ae0d66a..dcbca75 100644
> --- a/docs/formatdomain.html.in
> +++ b/docs/formatdomain.html.in
> @@ -3024,10 +3024,11 @@
> <p>
> PCI controllers have an optional <code>model</code> attribute
with
> possible values <code>pci-root</code>,
<code>pcie-root</code>,
> - <code>pci-bridge</code>, or
<code>dmi-to-pci-bridge</code>.
> + <code>pcie-root-port</code>, <code>pci-bridge</code>,
> + or <code>dmi-to-pci-bridge</code>.
> (pci-root and pci-bridge <span class="since">since
1.0.5</span>,
> pcie-root and dmi-to-pci-bridge <span class="since">since
> - 1.1.2</span>)
> + 1.1.2</span>, pcie-root-port <span class="since">since
1.3.0</span>)
1.2.18
> The root controllers (<code>pci-root</code> and
<code>pcie-root</code>)
> have an optional <code>pcihole64</code> element specifying how
big
> (in kilobytes, or in the unit specified by
<code>pcihole64</code>'s
> @@ -3070,6 +3071,25 @@
> (normally libvirt automatically sets this to the same value as
> the index attribute of the pci controller).
> </dd>
> + <dt><code>chassis</code></dt>
> + <dd>
> + pcie-root-port controllers can also have
> + a <code>chassis</code> attribute in
> + the <code><model></code> subelement, which is used
to
> + control QEMU's "chassis" option for the device (normally
> + libvirt automatically sets this to the same value as the index
> + attribute of the pci controller).
> + </dd>
> + <dt><code>port</code></dt>
> + <dd>
> + pcie-root-port controllers can also have a <code>port</code>
> + attribute in the <code><model></code> subelement,
which
> + is used to control QEMU's "port" option for the device
> + (normally libvirt automatically sets this based on the PCI
> + address where the root port is connected using the formula
> + (slot << 3) + function (although this could change in
> + the future).
> + </dd>
I see from the code that this is printed as a hex number - something we
should perhaps document here.
I always just figured "a number is a number, and it will be converted as
appropriate". I see that bus/slot in PCI addresses are documented as "a
hex number", but they have a different type in the RNG which forces
input as a hex number (with leading 0x). Interestingly, the parser
doesn't enforce that (I think the RNG should lighten up and the parser
should stay the same).
> </dl>
> <p>
> For machine types which provide an implicit PCI bus, the pci-root
> @@ -3116,6 +3136,17 @@
> auto-determined by libvirt will be placed on this pci-bridge
> device. (<span class="since">since 1.1.2</span>).
> </p>
> + <p>
> + Domains with an implicit pcie-root can also add controllers
> + with <code>model='pcie-root-port'</code>. This is a simple
type of
> + bridge device that can connect only to one of the 31 slots on
> + the pcie-root bus on its upstream side, and makes a single
> + (PCIe, hotpluggable) port (at slot='0') available on the
> + downstream side. This controller can be used to provide a single
> + slot to later hotplug a PCIe device (but is not itself
> + hotpluggable - it must be in the configuration when the domain
> + is started). (<span class="since">since 1.3.0</span>)
1.2.18
Seems to me we should state in some way that it's only supported on q35
machine for qemu 1.2.2 and beyond (where 1.2.2 is the patch 8 comment)
If added to other machine types, I assume it's ignored...
There will be an error because there won't be any bus to plug it into.
If qemu came up with another machinetype that had a pcie-root and a
device called ioh3420, we *would* automatically support it.
Also, I'm not sure about the "qemu 1.2.2" statement. From my point of
view "it's in the versions that it's in". I suppose I can add that
though.
> + </p>
> <pre>
> ...
> <devices>
> diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng
> index 1b1f592..0efa0f0 100644
> --- a/docs/schemas/domaincommon.rng
> +++ b/docs/schemas/domaincommon.rng
> @@ -1739,6 +1739,8 @@
> <value>pci-bridge</value>
> <!-- implementations of 'dmi-to-pci-bridge' -->
> <value>i82801b11-bridge</value>
> + <!-- implementations of 'pcie-root-port' -->
> + <value>ioh3420</value>
> </choice>
> </attribute>
> <empty/>
> @@ -1751,7 +1753,17 @@
> <ref name='uint8range'/>
> </attribute>
> </optional>
> - <empty/>
> + <optional>
> + <attribute name="chassis">
> + <ref name='uint8range'/>
> + </attribute>
> + </optional>
> + <optional>
> + <attribute name="port">
> + <ref name='uint8range'/>
> + </attribute>
> + </optional>
> + <empty/>
Similar to chassisNr - defined in domain_conf.h as 'int's, so limiting
in RNG to 0 to 255 inclusive doesn't seem right.
But it *is* right. The registers in the emulated hardware that hold
these values are 8 bits, but the struct in libvirt needs to have an int
so that (internally only) it can hold -1 to indicate "unspecified". I've
added a check on the parsed values to assure that these are all 0 - 255
only.
Unless of course it is right in which case domain_conf needs changes...
The parser needs to check limits, and it now does.
FWIW: A change to the .xml in this patch and the .args file in the
following patch to change the port to 0x11a "failed" schematest, but
passed libvirt's other tests
Not any more :-)
> </element>
> </optional>
> <!-- *-root controllers have an optional element
"pcihole64"-->
> @@ -1774,6 +1786,7 @@
> <choice>
> <value>pci-bridge</value>
> <value>dmi-to-pci-bridge</value>
> + <value>pcie-root-port</value>
> </choice>
> </attribute>
> </group>
> diff --git a/src/conf/domain_addr.c b/src/conf/domain_addr.c
> index bc09279..fba0eff 100644
> --- a/src/conf/domain_addr.c
> +++ b/src/conf/domain_addr.c
> @@ -183,9 +183,9 @@ virDomainPCIAddressBusSetModel(virDomainPCIAddressBusPtr bus,
> case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT:
> /* slots 1 - 31, no hotplug, PCIe only unless the address was
> * specified in user config *and* the particular device being
> - * attached also allows it
> + * attached also allows it.
> */
> - bus->flags = VIR_PCI_CONNECT_TYPE_PCIE;
> + bus->flags = VIR_PCI_CONNECT_TYPE_PCIE | VIR_PCI_CONNECT_TYPE_PCIE_ROOT;
> bus->minSlot = 1;
> bus->maxSlot = VIR_PCI_ADDRESS_SLOT_LAST;
> break;
> @@ -196,6 +196,12 @@ virDomainPCIAddressBusSetModel(virDomainPCIAddressBusPtr bus,
> bus->minSlot = 1;
> bus->maxSlot = VIR_PCI_ADDRESS_SLOT_LAST;
> break;
> + case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT_PORT:
> + /* provides one slot which is pcie and hotpluggable */
> + bus->flags = VIR_PCI_CONNECT_TYPE_PCIE | VIR_PCI_CONNECT_HOTPLUGGABLE;
> + bus->minSlot = 0;
> + bus->maxSlot = 0;
> + break;
> default:
> virReportError(VIR_ERR_INTERNAL_ERROR,
> _("Invalid PCI controller model %d"), model);
> diff --git a/src/conf/domain_addr.h b/src/conf/domain_addr.h
> index dcfd2e5..2a0ff96 100644
> --- a/src/conf/domain_addr.h
> +++ b/src/conf/domain_addr.h
> @@ -39,6 +39,8 @@ typedef enum {
> /* PCI devices can connect to this bus */
> VIR_PCI_CONNECT_TYPE_PCIE = 1 << 3,
> /* PCI Express devices can connect to this bus */
> + VIR_PCI_CONNECT_TYPE_PCIE_ROOT = 1 << 4,
> + /* for devices that can only connect to pcie-root (i.e. root-port) */
> } virDomainPCIConnectFlags;
>
> typedef struct {
> @@ -70,7 +72,8 @@ typedef virDomainPCIAddressSet *virDomainPCIAddressSetPtr;
> * allowed, e.g. PCI, PCIe, switch
> */
> # define VIR_PCI_CONNECT_TYPES_MASK \
> - (VIR_PCI_CONNECT_TYPE_PCI | VIR_PCI_CONNECT_TYPE_PCIE)
> + (VIR_PCI_CONNECT_TYPE_PCI | VIR_PCI_CONNECT_TYPE_PCIE | \
> + VIR_PCI_CONNECT_TYPE_PCIE_ROOT)
>
> /* combination of all bits that could be used to connect a normal
> * endpoint device (i.e. excluding the connection possible between an
> diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
> index 17526d4..e02c861 100644
> --- a/src/conf/domain_conf.c
> +++ b/src/conf/domain_conf.c
> @@ -324,7 +324,8 @@ VIR_ENUM_IMPL(virDomainControllerModelPCI,
VIR_DOMAIN_CONTROLLER_MODEL_PCI_LAST,
> "pci-root",
> "pcie-root",
> "pci-bridge",
> - "dmi-to-pci-bridge")
> + "dmi-to-pci-bridge",
> + "pcie-root-port")
>
> VIR_ENUM_IMPL(virDomainControllerModelSCSI, VIR_DOMAIN_CONTROLLER_MODEL_SCSI_LAST,
> "auto",
> @@ -1545,6 +1546,8 @@ virDomainControllerDefNew(virDomainControllerType type)
> break;
> case VIR_DOMAIN_CONTROLLER_TYPE_PCI:
> def->opts.pciopts.chassisNr = -1;
> + def->opts.pciopts.chassis = -1;
> + def->opts.pciopts.port = -1;
> break;
> case VIR_DOMAIN_CONTROLLER_TYPE_IDE:
> case VIR_DOMAIN_CONTROLLER_TYPE_FDC:
> @@ -7641,6 +7644,8 @@ virDomainControllerDefParseXML(xmlNodePtr node,
> char *max_sectors = NULL;
> char *guestModel = NULL;
> char *chassisNr = NULL;
> + char *chassis = NULL;
> + char *port = NULL;
> xmlNodePtr saved = ctxt->node;
> int rc;
>
> @@ -7692,6 +7697,10 @@ virDomainControllerDefParseXML(xmlNodePtr node,
> } else if (xmlStrEqual(cur->name, BAD_CAST "target")) {
> if (!chassisNr)
> chassisNr = virXMLPropString(cur, "chassisNr");
> + if (!chassis)
> + chassis = virXMLPropString(cur, "chassis");
> + if (!port)
> + port = virXMLPropString(cur, "port");
Similar to earlier comments - RNG doesn't allow multiple entries, so is
it necessary to check !chassis and !port? E.G. if they're already
found, then it probably should be an error or at least documented only
the first is consumed.
Since the RNG isn't always referenced, we need to do *something*. I've
actually changed it to have a "processedTarget" boolean that is set when
<target> has been seen once. If it's seen again, an error will be logged.
Also if there is supposed to be a range, it needs to be checked here.
See above.
That is the RNG expects 0 to 255 inclusive, but that's not
handled here.
> }
> }
> cur = cur->next;
> @@ -7811,6 +7820,20 @@ virDomainControllerDefParseXML(xmlNodePtr node,
> chassisNr);
> goto error;
> }
> + if (chassis && virStrToLong_i(chassis, NULL, 0,
> + &def->opts.pciopts.chassis) < 0) {
> + virReportError(VIR_ERR_XML_ERROR,
> + _("Invalid chassis '%s' in PCI
controller"),
> + chassis);
> + goto error;
> + }
> + if (port && virStrToLong_i(port, NULL, 0,
> + &def->opts.pciopts.port) < 0) {
> + virReportError(VIR_ERR_XML_ERROR,
> + _("Invalid port '%s' in PCI
controller"),
> + port);
> + goto error;
> + }
> break;
>
> default:
> @@ -7838,6 +7861,8 @@ virDomainControllerDefParseXML(xmlNodePtr node,
> VIR_FREE(max_sectors);
> VIR_FREE(guestModel);
> VIR_FREE(chassisNr);
> + VIR_FREE(chassis);
> + VIR_FREE(port);
>
> return def;
>
> @@ -18889,7 +18914,9 @@ virDomainControllerDefFormat(virBufferPtr buf,
> pcihole64 = true;
> if (def->opts.pciopts.type)
> pciModel = true;
> - if (def->opts.pciopts.chassisNr != -1)
> + if (def->opts.pciopts.chassisNr != -1 ||
> + def->opts.pciopts.chassis != -1 ||
> + def->opts.pciopts.port != -1)
> pciTarget = true;
> break;
>
> @@ -18914,6 +18941,12 @@ virDomainControllerDefFormat(virBufferPtr buf,
> if (def->opts.pciopts.chassisNr != -1)
> virBufferAsprintf(buf, " chassisNr='%d'",
> def->opts.pciopts.chassisNr);
> + if (def->opts.pciopts.chassis != -1)
> + virBufferAsprintf(buf, " chassis='%d'",
> + def->opts.pciopts.chassis);
> + if (def->opts.pciopts.port != -1)
> + virBufferAsprintf(buf, " port='0x%x'",
> + def->opts.pciopts.port);
OH... And this is what I get for not reading ahead... So now my previous
comments are unfounded... <sigh>
Which comments are those? There was a comment in a previous patch about
not needing the boolean "pciTarget" that wasn't valid, but your comments
about the range were certainly valid.
Also I see that ports is saved as a hex value - that's something we
should document in formatdomain and I noted above.
ACK as I trust you can handle the nits and range checks that may be
necessary.
John