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(a)redhat.com>
---
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