diff --git a/docs/formatdomain.rst b/docs/formatdomain.rst
index a02802a954..80aaf4b033 100644
--- a/docs/formatdomain.rst
+++ b/docs/formatdomain.rst
@@ -1847,6 +1847,9 @@ Hypervisors may allow certain CPU / machine features to be toggled on/off.
+
+
+
@@ -1942,6 +1945,32 @@ are:
passthrough Enable IOMMU mappings allowing PCI passthrough on, off; mode - optional string sync_pt or share_pt :since:`6.3.0`
=========== ============================================== =================================================== ==============
+``pci``
+ Various PCI bus related features of the hypervisor.
+
+ ==================== ========================================================================================================= ======= ==============
+ Feature Description Value Since
+ ==================== ========================================================================================================= ======= ==============
+ acpi-bridge-hotplug Enable ACPI based hotplug on the cold-plugged PCI bridges (pc) and pcie-root-ports (q35) (also see notes) on, off :since:`7.9.0`
+ ==================== ========================================================================================================= ======= ==============
+
+ Note: pc machine types (i440fx) have ACPI hotplug enabled by
+ default on cold plugged bridges (bridges that were present in the
+ VM's domain definition before it was started). Disabling ACPI
+ hotplug leaves only SHPC hotplug enabled; many OSes don't
+ support SHPC hotplug, so this may have the effect of completely
+ disabling hotplug.
+
+ On q35 machinetypes earlier than pc-q35-6.1 (regardless of the QEMU
+ binary version), ACPI hotplug for cold plugged bridges is disabled
+ by default, and native PCIe hotplug is enabled instead. Enabling
+ ACPI hotplug will disable native PCIe hotplug.
+
+ Starting with the pc-q35-6.1 machinetype, ACPI hotplug is enabled
+ on cold plugged bridges by default while native PCIe hotplug is
+ disabled. In this case, disabling ACPI hotplug will re-enable PCIe
+ native hotplug.
+
``pmu``
Depending on the ``state`` attribute (values ``on``, ``off``, default ``on``)
enable or disable the performance monitoring unit for the guest.
diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng
index ec5bd91740..6f33d1e774 100644
--- a/docs/schemas/domaincommon.rng
+++ b/docs/schemas/domaincommon.rng
@@ -6169,6 +6169,9 @@
+
+
+
@@ -6400,6 +6403,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index b8370f6950..5e89e65d5f 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -172,6 +172,7 @@ VIR_ENUM_IMPL(virDomainFeature,
"cfpc",
"sbbc",
"ibs",
+ "pci",
);
VIR_ENUM_IMPL(virDomainCapabilitiesPolicy,
@@ -212,6 +213,11 @@ VIR_ENUM_IMPL(virDomainXen,
"passthrough",
);
+VIR_ENUM_IMPL(virDomainPCI,
+ VIR_DOMAIN_PCI_LAST,
+ "acpi-bridge-hotplug",
+);
+
VIR_ENUM_IMPL(virDomainXenPassthroughMode,
VIR_DOMAIN_XEN_PASSTHROUGH_MODE_LAST,
"default",
@@ -17536,6 +17542,36 @@ virDomainFeaturesKVMDefParse(virDomainDef *def,
return 0;
}
+static int
+virDomainFeaturesPCIDefParse(virDomainDef *def,
+ xmlNodePtr node)
+{
+ def->features[VIR_DOMAIN_FEATURE_PCI] = VIR_TRISTATE_SWITCH_ON;
+
+ node = xmlFirstElementChild(node);
+ while (node) {
+ int feature;
+ virTristateSwitch value;
+
+ feature = virDomainPCITypeFromString((const char *)node->name);
+ if (feature < 0) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("unsupported PCI feature: %s"),
+ node->name);
+ return -1;
+ }
+
+ if (virXMLPropTristateSwitch(node, "state", VIR_XML_PROP_REQUIRED,
+ &value) < 0)
+ return -1;
+
+ def->pci_features[feature] = value;
+
+ node = xmlNextElementSibling(node);
+ }
+
+ return 0;
+}
static int
virDomainFeaturesXENDefParse(virDomainDef *def,
@@ -17835,6 +17871,10 @@ virDomainFeaturesDefParse(virDomainDef *def,
break;
}
+ case VIR_DOMAIN_FEATURE_PCI:
+ if (virDomainFeaturesPCIDefParse(def, nodes[i]) < 0)
+ return -1;
+
case VIR_DOMAIN_FEATURE_LAST:
break;
}
@@ -17843,7 +17883,6 @@ virDomainFeaturesDefParse(virDomainDef *def,
return 0;
}
-
static int
virDomainDefMaybeAddHostdevSCSIcontroller(virDomainDef *def)
{
@@ -21521,6 +21560,7 @@ virDomainDefFeaturesCheckABIStability(virDomainDef *src,
case VIR_DOMAIN_FEATURE_HTM:
case VIR_DOMAIN_FEATURE_NESTED_HV:
case VIR_DOMAIN_FEATURE_CCF_ASSIST:
+ case VIR_DOMAIN_FEATURE_PCI:
if (src->features[i] != dst->features[i]) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("State of feature '%s' differs: "
@@ -21777,6 +21817,29 @@ virDomainDefFeaturesCheckABIStability(virDomainDef *src,
}
}
+ /* pci */
+ if (src->features[VIR_DOMAIN_FEATURE_PCI] == VIR_TRISTATE_SWITCH_ON) {
+ for (i = 0; i < VIR_DOMAIN_PCI_LAST; i++) {
+ switch ((virDomainPCI) i) {
+ case VIR_DOMAIN_PCI_ACPI_BRIDGE_HOTPLUG:
+ if (src->pci_features[i] != dst->pci_features[i]) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("State of PCI feature '%s' differs: "
+ "source: '%s', destination: '%s'"),
+ virDomainPCITypeToString(i),
+ virTristateSwitchTypeToString(src->pci_features[i]),
+ virTristateSwitchTypeToString(dst->pci_features[i]));
+ return false;
+ }
+
+ break;
+
+ case VIR_DOMAIN_PCI_LAST:
+ break;
+ }
+ }
+ }
+
/* smm */
if (src->features[VIR_DOMAIN_FEATURE_SMM] == VIR_TRISTATE_SWITCH_ON) {
if (src->tseg_specified != dst->tseg_specified) {
@@ -27932,6 +27995,30 @@ virDomainDefFormatFeatures(virBuffer *buf,
virDomainIBSTypeToString(def->features[i]));
break;
+ case VIR_DOMAIN_FEATURE_PCI:
+ if (def->features[i] != VIR_TRISTATE_SWITCH_ON)
+ break;
+
+ virBufferAddLit(&childBuf, "\n");
+ virBufferAdjustIndent(&childBuf, 2);
+ for (j = 0; j < VIR_DOMAIN_PCI_LAST; j++) {
+ switch ((virDomainPCI) j) {
+ case VIR_DOMAIN_PCI_ACPI_BRIDGE_HOTPLUG:
+ if (def->pci_features[j] != VIR_TRISTATE_SWITCH_ABSENT)
+ virBufferAsprintf(&childBuf, "<%s state='%s'/>\n",
+ virDomainPCITypeToString(j),
+ virTristateSwitchTypeToString(
+ def->pci_features[j]));
+ break;
+
+ case VIR_DOMAIN_PCI_LAST:
+ break;
+ }
+ }
+ virBufferAdjustIndent(&childBuf, -2);
+ virBufferAddLit(&childBuf, "\n");
+ break;
+
case VIR_DOMAIN_FEATURE_LAST:
break;
}
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index c23c233184..79668d2293 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -2044,6 +2044,7 @@ typedef enum {
VIR_DOMAIN_FEATURE_CFPC,
VIR_DOMAIN_FEATURE_SBBC,
VIR_DOMAIN_FEATURE_IBS,
+ VIR_DOMAIN_FEATURE_PCI,
VIR_DOMAIN_FEATURE_LAST
} virDomainFeature;
@@ -2069,6 +2070,12 @@ typedef enum {
VIR_DOMAIN_HYPERV_LAST
} virDomainHyperv;
+typedef enum {
+ VIR_DOMAIN_PCI_ACPI_BRIDGE_HOTPLUG = 0,
+
+ VIR_DOMAIN_PCI_LAST
+} virDomainPCI;
+
typedef enum {
VIR_DOMAIN_KVM_HIDDEN = 0,
VIR_DOMAIN_KVM_DEDICATED,
@@ -2801,6 +2808,7 @@ struct _virDomainDef {
int features[VIR_DOMAIN_FEATURE_LAST];
int caps_features[VIR_DOMAIN_PROCES_CAPS_FEATURE_LAST];
int hyperv_features[VIR_DOMAIN_HYPERV_LAST];
+ int pci_features[VIR_DOMAIN_PCI_LAST];
int kvm_features[VIR_DOMAIN_KVM_LAST];
int msrs_features[VIR_DOMAIN_MSRS_LAST];
int xen_features[VIR_DOMAIN_XEN_LAST];
@@ -3925,6 +3933,7 @@ VIR_ENUM_DECL(virDomainGraphicsSpiceStreamingMode);
VIR_ENUM_DECL(virDomainGraphicsSpiceMouseMode);
VIR_ENUM_DECL(virDomainGraphicsVNCSharePolicy);
VIR_ENUM_DECL(virDomainHyperv);
+VIR_ENUM_DECL(virDomainPCI);
VIR_ENUM_DECL(virDomainKVM);
VIR_ENUM_DECL(virDomainXen);
VIR_ENUM_DECL(virDomainXenPassthroughMode);
diff --git a/src/qemu/qemu_validate.c b/src/qemu/qemu_validate.c
index c84508cb64..be609c9d39 100644
--- a/src/qemu/qemu_validate.c
+++ b/src/qemu/qemu_validate.c
@@ -173,6 +173,48 @@ qemuValidateDomainDefPSeriesFeature(const virDomainDef *def,
return 0;
}
+static int
+qemuValidateDomainDefPCIFeature(const virDomainDef *def,
+ virQEMUCaps *qemuCaps,
+ int feature)
+{
+ size_t i;
+ bool q35Dom = qemuDomainIsQ35(def);
+ bool q35cap = q35Dom && virQEMUCapsGet(qemuCaps,
+ QEMU_CAPS_ICH9_ACPI_HOTPLUG_BRIDGE);
+
+ if (def->features[feature] == VIR_TRISTATE_SWITCH_ABSENT)
+ return 0;
+
+ for (i = 0; i < VIR_DOMAIN_PCI_LAST; i++) {
+ if (def->pci_features[i] == VIR_TRISTATE_SWITCH_ABSENT)
+ continue;
+
+ switch ((virDomainPCI) i) {
+ case VIR_DOMAIN_PCI_ACPI_BRIDGE_HOTPLUG:
+ if (!ARCH_IS_X86(def->os.arch)) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("acpi-bridge-hotplug is not available "
+ "for architecture '%s'"),
+ virArchToString(def->os.arch));
+ return -1;
+ }
+ if (!q35cap &&
+ !virQEMUCapsGet(qemuCaps,
+ QEMU_CAPS_PIIX4_ACPI_HOTPLUG_BRIDGE)) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("acpi-bridge-hotplug is not available "
+ "with this QEMU binary"));
+ return -1;
+ }
+ break;
+
+ case VIR_DOMAIN_PCI_LAST:
+ break;
+ }
+ }
+ return 0;
+}
static int
qemuValidateDomainDefFeatures(const virDomainDef *def,
@@ -294,6 +336,10 @@ qemuValidateDomainDefFeatures(const virDomainDef *def,
}
break;
+ case VIR_DOMAIN_FEATURE_PCI:
+ if (qemuValidateDomainDefPCIFeature(def, qemuCaps, i) < 0)
+ return -1;
+ break;
case VIR_DOMAIN_FEATURE_SMM:
case VIR_DOMAIN_FEATURE_KVM:
case VIR_DOMAIN_FEATURE_XEN:
diff --git a/tests/qemuxml2argvdata/aarch64-acpi-hotplug-bridge-disable.xml b/tests/qemuxml2argvdata/aarch64-acpi-hotplug-bridge-disable.xml
new file mode 100644
index 0000000000..0d5f945bd7
--- /dev/null
+++ b/tests/qemuxml2argvdata/aarch64-acpi-hotplug-bridge-disable.xml
@@ -0,0 +1,33 @@
+
+ i440fx
+ 56f5055c-1b8d-490c-844a-ad646a1caaaa
+ 1048576
+ 1048576
+ 1
+
+ hvm
+
+
+
+
+
+
+
+
+ destroy
+ restart
+ destroy
+
+ /usr/bin/qemu-system-aarch64
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/qemuxml2argvdata/pc-i440fx-acpi-hotplug-bridge-disable.xml b/tests/qemuxml2argvdata/pc-i440fx-acpi-hotplug-bridge-disable.xml
new file mode 100644
index 0000000000..4482825858
--- /dev/null
+++ b/tests/qemuxml2argvdata/pc-i440fx-acpi-hotplug-bridge-disable.xml
@@ -0,0 +1,33 @@
+
+ i440fx
+ 56f5055c-1b8d-490c-844a-ad646a1caaaa
+ 1048576
+ 1048576
+ 1
+
+ hvm
+
+
+
+
+
+
+
+
+ destroy
+ restart
+ destroy
+
+ /usr/bin/qemu-system-x86_64
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/qemuxml2argvdata/pc-i440fx-acpi-hotplug-bridge-enable.xml b/tests/qemuxml2argvdata/pc-i440fx-acpi-hotplug-bridge-enable.xml
new file mode 100644
index 0000000000..8215ee0d50
--- /dev/null
+++ b/tests/qemuxml2argvdata/pc-i440fx-acpi-hotplug-bridge-enable.xml
@@ -0,0 +1,33 @@
+
+ i440fx
+ 56f5055c-1b8d-490c-844a-ad646a1caaaa
+ 1048576
+ 1048576
+ 1
+
+ hvm
+
+
+
+
+
+
+
+
+ destroy
+ restart
+ destroy
+
+ /usr/bin/qemu-system-x86_64
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/qemuxml2argvdata/q35-acpi-hotplug-bridge-disable.xml b/tests/qemuxml2argvdata/q35-acpi-hotplug-bridge-disable.xml
new file mode 100644
index 0000000000..2ef3a7231f
--- /dev/null
+++ b/tests/qemuxml2argvdata/q35-acpi-hotplug-bridge-disable.xml
@@ -0,0 +1,47 @@
+
+ q35
+ 56f5055c-1b8d-490c-844a-ad646a1caaaa
+ 1048576
+ 1048576
+ 1
+
+ hvm
+
+
+
+
+
+
+
+
+ destroy
+ restart
+ destroy
+
+ /usr/bin/qemu-system-x86_64
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/qemuxml2argvdata/q35-acpi-hotplug-bridge-enable.xml b/tests/qemuxml2argvdata/q35-acpi-hotplug-bridge-enable.xml
new file mode 100644
index 0000000000..2e1b31b0f8
--- /dev/null
+++ b/tests/qemuxml2argvdata/q35-acpi-hotplug-bridge-enable.xml
@@ -0,0 +1,47 @@
+
+ q35
+ 56f5055c-1b8d-490c-844a-ad646a1caaaa
+ 1048576
+ 1048576
+ 1
+
+ hvm
+
+
+
+
+
+
+
+
+ destroy
+ restart
+ destroy
+
+ /usr/bin/qemu-system-x86_64
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/qemuxml2xmloutdata/pc-i440fx-acpi-hotplug-bridge-disable.xml b/tests/qemuxml2xmloutdata/pc-i440fx-acpi-hotplug-bridge-disable.xml
new file mode 120000
index 0000000000..8154897401
--- /dev/null
+++ b/tests/qemuxml2xmloutdata/pc-i440fx-acpi-hotplug-bridge-disable.xml
@@ -0,0 +1 @@
+../qemuxml2argvdata/pc-i440fx-acpi-hotplug-bridge-disable.xml
\ No newline at end of file
diff --git a/tests/qemuxml2xmloutdata/pc-i440fx-acpi-hotplug-bridge-enable.xml b/tests/qemuxml2xmloutdata/pc-i440fx-acpi-hotplug-bridge-enable.xml
new file mode 120000
index 0000000000..6b9e5492f8
--- /dev/null
+++ b/tests/qemuxml2xmloutdata/pc-i440fx-acpi-hotplug-bridge-enable.xml
@@ -0,0 +1 @@
+../qemuxml2argvdata/pc-i440fx-acpi-hotplug-bridge-enable.xml
\ No newline at end of file
diff --git a/tests/qemuxml2xmloutdata/q35-acpi-hotplug-bridge-disable.xml b/tests/qemuxml2xmloutdata/q35-acpi-hotplug-bridge-disable.xml
new file mode 120000
index 0000000000..77719b1325
--- /dev/null
+++ b/tests/qemuxml2xmloutdata/q35-acpi-hotplug-bridge-disable.xml
@@ -0,0 +1 @@
+../qemuxml2argvdata/q35-acpi-hotplug-bridge-disable.xml
\ No newline at end of file
diff --git a/tests/qemuxml2xmloutdata/q35-acpi-hotplug-bridge-enable.xml b/tests/qemuxml2xmloutdata/q35-acpi-hotplug-bridge-enable.xml
new file mode 120000
index 0000000000..3cd8ee569e
--- /dev/null
+++ b/tests/qemuxml2xmloutdata/q35-acpi-hotplug-bridge-enable.xml
@@ -0,0 +1 @@
+../qemuxml2argvdata/q35-acpi-hotplug-bridge-enable.xml
\ No newline at end of file
diff --git a/tests/qemuxml2xmltest.c b/tests/qemuxml2xmltest.c
index 69363ef85c..2e622c002f 100644
--- a/tests/qemuxml2xmltest.c
+++ b/tests/qemuxml2xmltest.c
@@ -428,6 +428,20 @@ mymain(void)
QEMU_CAPS_PIIX4_ACPI_ROOT_PCI_HOTPLUG);
DO_TEST("pc-i440fx-acpi-root-hotplug-enable",
QEMU_CAPS_PIIX4_ACPI_ROOT_PCI_HOTPLUG);
+ DO_TEST("pc-i440fx-acpi-hotplug-bridge-disable",
+ QEMU_CAPS_PIIX4_ACPI_HOTPLUG_BRIDGE);
+ DO_TEST("pc-i440fx-acpi-hotplug-bridge-enable",
+ QEMU_CAPS_PIIX4_ACPI_HOTPLUG_BRIDGE);
+ DO_TEST("q35-acpi-hotplug-bridge-disable",
+ QEMU_CAPS_DEVICE_PCI_BRIDGE,
+ QEMU_CAPS_DEVICE_IOH3420,
+ QEMU_CAPS_DEVICE_DMI_TO_PCI_BRIDGE,
+ QEMU_CAPS_ICH9_ACPI_HOTPLUG_BRIDGE);
+ DO_TEST("q35-acpi-hotplug-bridge-enable",
+ QEMU_CAPS_DEVICE_PCI_BRIDGE,
+ QEMU_CAPS_DEVICE_IOH3420,
+ QEMU_CAPS_DEVICE_DMI_TO_PCI_BRIDGE,
+ QEMU_CAPS_ICH9_ACPI_HOTPLUG_BRIDGE);
DO_TEST("misc-disable-suspends",
QEMU_CAPS_PIIX_DISABLE_S3,
QEMU_CAPS_PIIX_DISABLE_S4);