a <controller type='pci'...> element can now have a "hotplug" attribute in the <target> subelement. This is intended to control whether or not the slot(s) of the controller support hotplugging/unplugging a device: <controller type='pci' model='pcie-root-port'> <target hotplug='off'/> </controller> The default value of hotplug is "on". Since support for configuring such an option is hypervisor-dependent (and will vary among different types of PCI controllers even on a single hypervisor), no validation is done in this patch - that validation will be done in the patch that wires support for the setting into the hypervisor. Signed-off-by: Laine Stump <laine@xxxxxxxxxx> --- docs/formatdomain.html.in | 11 ++++ docs/schemas/domaincommon.rng | 5 ++ src/conf/domain_conf.c | 20 +++++- src/conf/domain_conf.h | 1 + .../pcie-root-port-nohotplug.xml | 35 ++++++++++ .../pcie-root-port-nohotplug.xml | 64 +++++++++++++++++++ tests/qemuxml2xmltest.c | 7 ++ 7 files changed, 142 insertions(+), 1 deletion(-) create mode 100644 tests/qemuxml2argvdata/pcie-root-port-nohotplug.xml create mode 100644 tests/qemuxml2xmloutdata/pcie-root-port-nohotplug.xml diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in index fbffb16866..341f7c78dc 100644 --- a/docs/formatdomain.html.in +++ b/docs/formatdomain.html.in @@ -4706,6 +4706,17 @@ which is visible to the virtual machine. If set, port must be between 0 and 255. </dd> + <dt><code>hotplug</code></dt> + <dd> + pcie-root-port and pcie-switch-downstream-port controllers can + also have a <code>hotplug</code> attribute in + the <code><target></code> subelement, which is used to + disable hotplug/unplug of devices on a particular + controller. The default setting of <code>hotplug</code> + is <code>on</code>; it should be set to <code>off</code> to + disable hotplug/unplug of devices on a particular controller. + <span class="since">Since 6.3.0</span> + </dd> <dt><code>busNr</code></dt> <dd> pci-expander-bus and pcie-expander-bus controllers can have an diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng index dcf2e09db8..7db32ec5c0 100644 --- a/docs/schemas/domaincommon.rng +++ b/docs/schemas/domaincommon.rng @@ -2475,6 +2475,11 @@ <ref name='uint8'/> </attribute> </optional> + <optional> + <attribute name='hotplug'> + <ref name="virOnOff"/> + </attribute> + </optional> <optional> <element name='node'> <ref name='unsignedInt'/> diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 460f8064be..4c81579eaf 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -11035,6 +11035,7 @@ virDomainControllerDefParseXML(virDomainXMLOptionPtr xmlopt, g_autofree char *port = NULL; g_autofree char *busNr = NULL; g_autofree char *targetIndex = NULL; + g_autofree char *hotplug = NULL; g_autofree char *ioeventfd = NULL; g_autofree char *portsStr = NULL; g_autofree char *iothread = NULL; @@ -11106,6 +11107,7 @@ virDomainControllerDefParseXML(virDomainXMLOptionPtr xmlopt, chassis = virXMLPropString(cur, "chassis"); port = virXMLPropString(cur, "port"); busNr = virXMLPropString(cur, "busNr"); + hotplug = virXMLPropString(cur, "hotplug"); targetIndex = virXMLPropString(cur, "index"); processedTarget = true; } @@ -11342,6 +11344,17 @@ virDomainControllerDefParseXML(virDomainXMLOptionPtr xmlopt, } def->opts.pciopts.numaNode = numaNode; } + if (hotplug) { + int val = virTristateSwitchTypeFromString(hotplug); + + if (val <= 0) { + virReportError(VIR_ERR_XML_ERROR, + _("PCI controller unrecognized hotplug setting '%s'"), + hotplug); + goto error; + } + def->opts.pciopts.hotplug = val; + } break; case VIR_DOMAIN_CONTROLLER_TYPE_XENBUS: { g_autofree char *gntframes = virXMLPropString(node, "maxGrantFrames"); @@ -25333,7 +25346,8 @@ virDomainControllerDefFormat(virBufferPtr buf, def->opts.pciopts.port != -1 || def->opts.pciopts.busNr != -1 || def->opts.pciopts.targetIndex != -1 || - def->opts.pciopts.numaNode != -1) { + def->opts.pciopts.numaNode != -1 || + def->opts.pciopts.hotplug != VIR_TRISTATE_SWITCH_ABSENT) { virBufferAddLit(&childBuf, "<target"); if (def->opts.pciopts.chassisNr != -1) virBufferAsprintf(&childBuf, " chassisNr='%d'", @@ -25350,6 +25364,10 @@ virDomainControllerDefFormat(virBufferPtr buf, if (def->opts.pciopts.targetIndex != -1) virBufferAsprintf(&childBuf, " index='%d'", def->opts.pciopts.targetIndex); + if (def->opts.pciopts.hotplug != VIR_TRISTATE_SWITCH_ABSENT) { + virBufferAsprintf(&childBuf, " hotplug='%s'", + virTristateSwitchTypeToString(def->opts.pciopts.hotplug)); + } if (def->opts.pciopts.numaNode == -1) { virBufferAddLit(&childBuf, "/>\n"); } else { diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 2038b54c32..bd5aaeaef1 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -722,6 +722,7 @@ struct _virDomainPCIControllerOpts { * item in memory target config) -1 == unspecified */ int numaNode; + virTristateSwitch hotplug; /* 'off' to prevent hotplug/unplug, default 'on' */ }; struct _virDomainUSBControllerOpts { diff --git a/tests/qemuxml2argvdata/pcie-root-port-nohotplug.xml b/tests/qemuxml2argvdata/pcie-root-port-nohotplug.xml new file mode 100644 index 0000000000..8a01494470 --- /dev/null +++ b/tests/qemuxml2argvdata/pcie-root-port-nohotplug.xml @@ -0,0 +1,35 @@ +<domain type='qemu'> + <name>guest</name> + <uuid>11dbdcdd-4c3b-482b-8903-9bdb8c0a2774</uuid> + <memory unit='KiB'>2097152</memory> + <currentMemory unit='KiB'>2097152</currentMemory> + <vcpu placement='static'>2</vcpu> + <os> + <type arch='x86_64' machine='q35'>hvm</type> + </os> + <devices> + <emulator>/usr/bin/qemu-system-x86_64</emulator> + <controller type='pci' index='0' model='pcie-root'/> + <controller type='pci' index='1' model='pcie-root-port'/> + <controller type='pci' index='2' model='pcie-root-port'> + <target hotplug='off'/> + </controller> + <controller type='pci' index='3' model='pcie-root-port'> + <model name='ioh3420'/> + <target hotplug='off'/> + </controller> + <controller type='pci' index='4' model='pcie-switch-upstream-port'/> + <controller type='pci' index='5' model='pcie-switch-downstream-port'> + <target hotplug='off'/> + </controller> + <controller type='pci' index='6' model='pcie-switch-downstream-port'> + <target hotplug='on'/> + </controller> + <controller type='pci' index='7' model='pcie-switch-downstream-port'/> + <controller type='pci' index='8' model='pcie-switch-downstream-port'> + <model name='xio3130-downstream'/> + <target chassis='30' port='0x27'/> + </controller> + <memballoon model='none'/> + </devices> +</domain> diff --git a/tests/qemuxml2xmloutdata/pcie-root-port-nohotplug.xml b/tests/qemuxml2xmloutdata/pcie-root-port-nohotplug.xml new file mode 100644 index 0000000000..2ecb99728d --- /dev/null +++ b/tests/qemuxml2xmloutdata/pcie-root-port-nohotplug.xml @@ -0,0 +1,64 @@ +<domain type='qemu'> + <name>guest</name> + <uuid>11dbdcdd-4c3b-482b-8903-9bdb8c0a2774</uuid> + <memory unit='KiB'>2097152</memory> + <currentMemory unit='KiB'>2097152</currentMemory> + <vcpu placement='static'>2</vcpu> + <os> + <type arch='x86_64' machine='q35'>hvm</type> + <boot dev='hd'/> + </os> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <devices> + <emulator>/usr/bin/qemu-system-x86_64</emulator> + <controller type='pci' index='0' model='pcie-root'/> + <controller type='pci' index='1' model='pcie-root-port'> + <model name='pcie-root-port'/> + <target chassis='1' port='0x10'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0' multifunction='on'/> + </controller> + <controller type='pci' index='2' model='pcie-root-port'> + <model name='pcie-root-port'/> + <target chassis='2' port='0x11' hotplug='off'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x1'/> + </controller> + <controller type='pci' index='3' model='pcie-root-port'> + <model name='ioh3420'/> + <target chassis='3' port='0x12' hotplug='off'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x2'/> + </controller> + <controller type='pci' index='4' model='pcie-switch-upstream-port'> + <model name='x3130-upstream'/> + <address type='pci' domain='0x0000' bus='0x01' slot='0x00' function='0x0'/> + </controller> + <controller type='pci' index='5' model='pcie-switch-downstream-port'> + <model name='xio3130-downstream'/> + <target chassis='5' port='0x0' hotplug='off'/> + <address type='pci' domain='0x0000' bus='0x04' slot='0x00' function='0x0'/> + </controller> + <controller type='pci' index='6' model='pcie-switch-downstream-port'> + <model name='xio3130-downstream'/> + <target chassis='6' port='0x1' hotplug='on'/> + <address type='pci' domain='0x0000' bus='0x04' slot='0x01' function='0x0'/> + </controller> + <controller type='pci' index='7' model='pcie-switch-downstream-port'> + <model name='xio3130-downstream'/> + <target chassis='7' port='0x2'/> + <address type='pci' domain='0x0000' bus='0x04' slot='0x02' function='0x0'/> + </controller> + <controller type='pci' index='8' model='pcie-switch-downstream-port'> + <model name='xio3130-downstream'/> + <target chassis='30' port='0x27'/> + <address type='pci' domain='0x0000' bus='0x04' slot='0x03' function='0x0'/> + </controller> + <controller type='sata' index='0'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x1f' function='0x2'/> + </controller> + <input type='mouse' bus='ps2'/> + <input type='keyboard' bus='ps2'/> + <memballoon model='none'/> + </devices> +</domain> diff --git a/tests/qemuxml2xmltest.c b/tests/qemuxml2xmltest.c index b4c83fccca..4b40468d15 100644 --- a/tests/qemuxml2xmltest.c +++ b/tests/qemuxml2xmltest.c @@ -960,6 +960,13 @@ mymain(void) DO_TEST("pcie-root-port-model-ioh3420", QEMU_CAPS_DEVICE_IOH3420); + DO_TEST("pcie-root-port-nohotplug", + QEMU_CAPS_DEVICE_PCIE_ROOT_PORT, + QEMU_CAPS_DEVICE_IOH3420, + QEMU_CAPS_DEVICE_X3130_UPSTREAM, + QEMU_CAPS_DEVICE_XIO3130_DOWNSTREAM, + QEMU_CAPS_PCIE_ROOT_PORT_HOTPLUG); + DO_TEST("pcie-switch-upstream-port", QEMU_CAPS_DEVICE_IOH3420, QEMU_CAPS_DEVICE_X3130_UPSTREAM, -- 2.25.2