diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in
index c0a265a49f..33db6a5c20 100644
--- a/docs/formatdomain.html.in
+++ b/docs/formatdomain.html.in
@@ -3043,6 +3043,19 @@
are recent enough to support 64-bit PCI holes, unless this is disabled
(set to 0). Since 1.1.2 (QEMU only)
+
+ PCI controllers also have an optional
+ subelement <model>
with an attribute
+ name
. The name attribute holds the name of the
+ specific device that qemu is emulating (e.g. "i82801b11-bridge")
+ rather than simply the class of device ("dmi-to-pci-bridge",
+ "pci-bridge"), which is set in the controller element's
+ model attribute. In almost all cases, you should not
+ manually add a <model>
subelement to a
+ controller, nor should you modify one that is automatically
+ generated by libvirt. Since 1.2.19 (QEMU
+ only).
+
For machine types which provide an implicit PCI bus, the pci-root
controller with index=0 is auto-added and required to use PCI devices.
diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng
index 1120003518..a4c1c9b578 100644
--- a/docs/schemas/domaincommon.rng
+++ b/docs/schemas/domaincommon.rng
@@ -1731,6 +1731,19 @@
pci
+
+
+
+
+
+ pci-bridge
+
+ i82801b11-bridge
+
+
+
+
+
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index 18e626985c..b04f20503e 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -326,6 +326,12 @@ VIR_ENUM_IMPL(virDomainControllerModelPCI, VIR_DOMAIN_CONTROLLER_MODEL_PCI_LAST,
"pci-bridge",
"dmi-to-pci-bridge")
+VIR_ENUM_IMPL(virDomainControllerPCIModelName,
+ VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_LAST,
+ "none",
+ "pci-bridge",
+ "i82801b11-bridge")
+
VIR_ENUM_IMPL(virDomainControllerModelSCSI, VIR_DOMAIN_CONTROLLER_MODEL_SCSI_LAST,
"auto",
"buslogic",
@@ -7802,6 +7808,8 @@ virDomainControllerDefParseXML(xmlNodePtr node,
char *queues = NULL;
char *cmd_per_lun = NULL;
char *max_sectors = NULL;
+ bool processedModel = false;
+ char *modelName = NULL;
xmlNodePtr saved = ctxt->node;
int rc;
@@ -7845,6 +7853,15 @@ virDomainControllerDefParseXML(xmlNodePtr node,
queues = virXMLPropString(cur, "queues");
cmd_per_lun = virXMLPropString(cur, "cmd_per_lun");
max_sectors = virXMLPropString(cur, "max_sectors");
+ } else if (xmlStrEqual(cur->name, BAD_CAST "model")) {
+ if (processedModel) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("Multiple elements in "
+ "controller definition not allowed"));
+ goto error;
+ }
+ modelName = virXMLPropString(cur, "name");
+ processedModel = true;
}
}
cur = cur->next;
@@ -7953,6 +7970,15 @@ virDomainControllerDefParseXML(xmlNodePtr node,
def->opts.pciopts.pcihole64size = VIR_DIV_UP(bytes, 1024);
}
}
+ if (modelName &&
+ (def->opts.pciopts.modelName
+ = virDomainControllerPCIModelNameTypeFromString(modelName)) <= 0) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("Unknown PCI controller model name '%s'"),
+ modelName);
+ goto error;
+ }
+ break;
default:
break;
@@ -7977,6 +8003,7 @@ virDomainControllerDefParseXML(xmlNodePtr node,
VIR_FREE(queues);
VIR_FREE(cmd_per_lun);
VIR_FREE(max_sectors);
+ VIR_FREE(modelName);
return def;
@@ -18988,7 +19015,8 @@ virDomainControllerDefFormat(virBufferPtr buf,
{
const char *type = virDomainControllerTypeToString(def->type);
const char *model = NULL;
- bool pcihole64 = false;
+ const char *modelName = NULL;
+ bool pcihole64 = false, pciModel = false;
if (!type) {
virReportError(VIR_ERR_INTERNAL_ERROR,
@@ -19028,17 +19056,31 @@ virDomainControllerDefFormat(virBufferPtr buf,
case VIR_DOMAIN_CONTROLLER_TYPE_PCI:
if (def->opts.pciopts.pcihole64)
pcihole64 = true;
+ if (def->opts.pciopts.modelName != VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_NONE)
+ pciModel = true;
break;
default:
break;
}
- if (def->queues || def->cmd_per_lun || def->max_sectors ||
+ if (pciModel ||
+ def->queues || def->cmd_per_lun || def->max_sectors ||
virDomainDeviceInfoNeedsFormat(&def->info, flags) || pcihole64) {
virBufferAddLit(buf, ">\n");
virBufferAdjustIndent(buf, 2);
+ if (pciModel) {
+ modelName = virDomainControllerPCIModelNameTypeToString(def->opts.pciopts.modelName);
+ if (!modelName) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("unexpected model name value %d"),
+ def->opts.pciopts.modelName);
+ return -1;
+ }
+ virBufferAsprintf(buf, "\n", modelName);
+ }
+
if (def->queues || def->cmd_per_lun || def->max_sectors) {
virBufferAddLit(buf, "queues)
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index 698a4d245a..fa9937bdd0 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -756,6 +756,14 @@ typedef enum {
VIR_DOMAIN_CONTROLLER_MODEL_PCI_LAST
} virDomainControllerModelPCI;
+typedef enum {
+ VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_NONE,
+ VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_PCI_BRIDGE,
+ VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_I82801B11_BRIDGE,
+
+ VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_LAST
+} virDomainControllerPCIModelName;
+
typedef enum {
VIR_DOMAIN_CONTROLLER_MODEL_SCSI_AUTO,
VIR_DOMAIN_CONTROLLER_MODEL_SCSI_BUSLOGIC,
@@ -797,6 +805,13 @@ typedef virDomainPCIControllerOpts *virDomainPCIControllerOptsPtr;
struct _virDomainPCIControllerOpts {
bool pcihole64;
unsigned long pcihole64size;
+
+ /* the exact controller name is in the "model" subelement, e.g.:
+ *
+ *
+ * ...
+ */
+ int modelName; /* the exact name of the device in hypervisor */
};
/* Stores the virtual disk controller configuration */
@@ -2978,6 +2993,7 @@ VIR_ENUM_DECL(virDomainDiskDiscard)
VIR_ENUM_DECL(virDomainDiskMirrorState)
VIR_ENUM_DECL(virDomainController)
VIR_ENUM_DECL(virDomainControllerModelPCI)
+VIR_ENUM_DECL(virDomainControllerPCIModelName)
VIR_ENUM_DECL(virDomainControllerModelSCSI)
VIR_ENUM_DECL(virDomainControllerModelUSB)
VIR_ENUM_DECL(virDomainFS)
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index e5d8437adf..45f42f5020 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -192,6 +192,8 @@ virDomainControllerModelSCSITypeFromString;
virDomainControllerModelSCSITypeToString;
virDomainControllerModelUSBTypeFromString;
virDomainControllerModelUSBTypeToString;
+virDomainControllerPCIModelNameTypeFromString;
+virDomainControllerPCIModelNameTypeToString;
virDomainControllerRemove;
virDomainControllerTypeToString;
virDomainCpuPlacementModeTypeFromString;
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-q35.xml b/tests/qemuxml2argvdata/qemuxml2argv-q35.xml
index 05967a409c..132c15f452 100644
--- a/tests/qemuxml2argvdata/qemuxml2argv-q35.xml
+++ b/tests/qemuxml2argvdata/qemuxml2argv-q35.xml
@@ -20,8 +20,12 @@
-
-
+
+
+
+
+
+
diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-q35.xml b/tests/qemuxml2xmloutdata/qemuxml2xmlout-q35.xml
index 9dd41623ed..4d8fc5f739 100644
--- a/tests/qemuxml2xmloutdata/qemuxml2xmlout-q35.xml
+++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-q35.xml
@@ -20,8 +20,12 @@
-
-
+
+
+
+
+
+