1
0
mirror of https://gitlab.com/libvirt/libvirt.git synced 2024-12-23 21:34:54 +03:00

conf: permit auto-assignment of controller indexes

Hand-entering indexes for 20 PCI controllers is not as tedious as
manually determining and entering their PCI addresses, but it's still
annoying, and the algorithm for determining the proper index is
incredibly simple (in all cases except one) - just pick the lowest
unused index.

The one exception is USB2 controllers because multiple controllers in
the same group have the same index. For these we look to see if 1) the
most recently added USB controller is also a USB2 controller, and 2)
the group *that* controller belongs to doesn't yet have a controller
of the exact model we're just now adding - if both are true, the new
controller gets the same index, but in all other cases we just assign
the lowest unused index.

With this patch in place and combined with the automatic PCI address
assignment, we can define a PCIe switch with several ports like this:

  <controller type='pci' model='pcie-root-port'/>
  <controller type='pci' model='pcie-switch-upstream-port'/>
  <controller type='pci' model='pcie-switch-downstream-port'/>
  <controller type='pci' model='pcie-switch-downstream-port'/>
  <controller type='pci' model='pcie-switch-downstream-port'/>
  <controller type='pci' model='pcie-switch-downstream-port'/>
  <controller type='pci' model='pcie-switch-downstream-port'/>
  ...

These will each get a unique index, and PCI addresses that connect
them together appropriately with no pesky numbers required.
This commit is contained in:
Laine Stump 2016-05-10 13:14:32 -04:00
parent 808e16ff13
commit 4d100c7a41
11 changed files with 410 additions and 23 deletions

View File

@ -3041,8 +3041,11 @@
attribute <code>index</code> which is the decimal integer
describing in which order the bus controller is encountered (for
use in <code>controller</code> attributes of
<code>&lt;address&gt;</code> elements). Some controller types
have additional attributes that control specific features, such as:
<code>&lt;address&gt;</code> elements).
<span class="since">Since 1.3.5</span> the index is optional; if
not specified, it will be auto-assigned to be the lowest unused
index for the given controller type. Some controller types have
additional attributes that control specific features, such as:
</p>
<dl>

View File

@ -1704,9 +1704,11 @@
</define>
<define name="controller">
<element name="controller">
<optional>
<attribute name="index">
<ref name="unsignedInt"/>
</attribute>
</optional>
<interleave>
<optional>
<ref name="alias"/>

View File

@ -1647,9 +1647,11 @@ virDomainControllerDefNew(virDomainControllerType type)
return NULL;
def->type = type;
def->model = -1;
/* initialize anything that has a non-0 default */
def->model = -1;
def->idx = -1;
switch ((virDomainControllerType) def->type) {
case VIR_DOMAIN_CONTROLLER_TYPE_VIRTIO_SERIAL:
def->opts.vioserial.ports = -1;
@ -3585,7 +3587,7 @@ virDomainDefRejectDuplicateControllers(virDomainDefPtr def)
for (i = 0; i < def->ncontrollers; i++) {
cont = def->controllers[i];
if ((int) cont->idx > max_idx[cont->type])
if (cont->idx > max_idx[cont->type])
max_idx[cont->type] = cont->idx;
}
@ -4254,6 +4256,84 @@ virDomainDefRemoveOfflineVcpuPin(virDomainDefPtr def)
}
static void
virDomainAssignControllerIndexes(virDomainDefPtr def)
{
/* the index attribute of a controller is optional in the XML, but
* is required to be valid at any time after parse. When no index
* is provided for a controller, assign one automatically by
* looking at what indexes are already used for that controller
* type in the domain - the unindexed controller gets the lowest
* unused index.
*/
size_t outer;
for (outer = 0; outer < def->ncontrollers; outer++) {
virDomainControllerDefPtr cont = def->controllers[outer];
virDomainControllerDefPtr prev = NULL;
size_t inner;
if (cont->idx != -1)
continue;
if (outer > 0 && IS_USB2_CONTROLLER(cont)) {
/* USB2 controllers are the only exception to the simple
* "assign the lowest unused index". A group of USB2
* "companions" should all be at the same index as other
* USB2 controllers in the group, but only do this
* automatically if it appears to be the intent. To prove
* intent: the USB controller on the list just prior to
* this one must also be a USB2 controller, and there must
* not yet be a controller with the exact same model of
* this one and the same index as the previously added
* controller (e.g., if this controller is a UHCI1, then
* the previous controller must be an EHCI1 or a UHCI[23],
* and there must not already be a UHCI1 controller with
* the same index as the previous controller). If all of
* these are satisfied, set this controller to the same
* index as the previous controller.
*/
int prevIdx;
prevIdx = outer - 1;
while (prevIdx >= 0 &&
def->controllers[prevIdx]->type != VIR_DOMAIN_CONTROLLER_TYPE_USB)
prevIdx--;
if (prevIdx >= 0)
prev = def->controllers[prevIdx];
/* if the last USB controller isn't USB2, that breaks
* the chain, so we need a new index for this new
* controller
*/
if (prev && !IS_USB2_CONTROLLER(prev))
prev = NULL;
/* if prev != NULL, we've found a potential index to
* use. Make sure this index isn't already used by an
* existing USB2 controller of the same model as the new
* one.
*/
for (inner = 0; prev && inner < def->ncontrollers; inner++) {
if (def->controllers[inner]->type == VIR_DOMAIN_CONTROLLER_TYPE_USB &&
def->controllers[inner]->idx == prev->idx &&
def->controllers[inner]->model == cont->model) {
/* we already have a controller of this model with
* the proposed index, so we need to move to a new
* index for this controller
*/
prev = NULL;
}
}
if (prev)
cont->idx = prev->idx;
}
/* if none of the above applied, prev will be NULL */
if (!prev)
cont->idx = virDomainControllerFindUnusedIndex(def, cont->type);
}
}
#define UNSUPPORTED(FEATURE) (!((FEATURE) & xmlopt->config.features))
/**
* virDomainDefPostParseCheckFeatures:
@ -4422,6 +4502,11 @@ virDomainDefPostParse(virDomainDefPtr def,
.parseFlags = parseFlags,
};
/* this must be done before the hypervisor-specific callback,
* in case presence of a controller at a specific index is checked
*/
virDomainAssignControllerIndexes(def);
/* call the domain config callback */
if (xmlopt->config.domainPostParseCallback) {
ret = xmlopt->config.domainPostParseCallback(def, caps, parseFlags,
@ -7908,16 +7993,6 @@ virDomainControllerDefParseXML(xmlNodePtr node,
if (!(def = virDomainControllerDefNew(type)))
goto error;
idx = virXMLPropString(node, "index");
if (idx) {
if (virStrToLong_ui(idx, NULL, 10, &def->idx) < 0 ||
def->idx > INT_MAX) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("Cannot parse controller index %s"), idx);
goto error;
}
}
model = virXMLPropString(node, "model");
if (model) {
if ((def->model = virDomainControllerModelTypeFromString(def, model)) < 0) {
@ -7927,6 +8002,18 @@ virDomainControllerDefParseXML(xmlNodePtr node,
}
}
idx = virXMLPropString(node, "index");
if (idx) {
unsigned int idxVal;
if (virStrToLong_ui(idx, NULL, 10, &idxVal) < 0 ||
idxVal > INT_MAX) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("Cannot parse controller index %s"), idx);
goto error;
}
def->idx = idxVal;
}
cur = node->children;
while (cur != NULL) {
if (cur->type == XML_ELEMENT_NODE) {
@ -8075,7 +8162,7 @@ virDomainControllerDefParseXML(xmlNodePtr node,
"have an address"));
goto error;
}
if (def->idx != 0) {
if (def->idx > 0) {
virReportError(VIR_ERR_XML_ERROR, "%s",
_("pci-root and pcie-root controllers "
"should have index 0"));
@ -13672,6 +13759,14 @@ void virDomainControllerInsertPreAlloced(virDomainDefPtr def,
for (idx = (def->ncontrollers - 1); idx >= 0; idx--) {
current = def->controllers[idx];
if (current->type == controller->type) {
if (controller->idx == -1) {
/* If the new controller doesn't have an index set
* yet, put it just past this controller, which until
* now was the last controller of this type.
*/
insertAt = idx + 1;
break;
}
if (current->idx > controller->idx) {
/* If bus matches and current controller is after
* new controller, then new controller should go here
@ -16238,6 +16333,7 @@ virDomainDefParseXML(xmlDocPtr xml,
virDomainControllerDefPtr controller = virDomainControllerDefParseXML(nodes[i],
ctxt,
flags);
if (!controller)
goto error;
@ -19552,7 +19648,7 @@ virDomainControllerDefFormat(virBufferPtr buf,
}
virBufferAsprintf(buf,
"<controller type='%s' index='%u'",
"<controller type='%s' index='%d'",
type, def->idx);
if (model)

View File

@ -733,7 +733,7 @@ struct _virDomainUSBControllerOpts {
/* Stores the virtual disk controller configuration */
struct _virDomainControllerDef {
int type;
unsigned int idx;
int idx;
int model; /* -1 == undef */
unsigned int queues;
unsigned int cmd_per_lun;

View File

@ -1,7 +1,7 @@
/*
* qemu_driver.c: core driver methods for managing qemu guests
*
* Copyright (C) 2006-2015 Red Hat, Inc.
* Copyright (C) 2006-2016 Red Hat, Inc.
* Copyright (C) 2006 Daniel P. Berrange
*
* This library is free software; you can redistribute it and/or
@ -7827,7 +7827,8 @@ qemuDomainAttachDeviceConfig(virDomainDefPtr vmdef,
case VIR_DOMAIN_DEVICE_CONTROLLER:
controller = dev->data.controller;
if (virDomainControllerFind(vmdef, controller->type,
if (controller->idx != -1 &&
virDomainControllerFind(vmdef, controller->type,
controller->idx) >= 0) {
virReportError(VIR_ERR_OPERATION_INVALID, "%s",
_("Target already exists"));

View File

@ -425,6 +425,14 @@ int qemuDomainAttachControllerDevice(virQEMUDriverPtr driver,
return -1;
}
/* default idx would normally be set by virDomainDefPostParse(),
* which isn't called in the case of live attach of a single
* device.
*/
if (controller->idx == -1)
controller->idx = virDomainControllerFindUnusedIndex(vm->def,
controller->type);
if (virDomainControllerFind(vm->def, controller->type, controller->idx) >= 0) {
virReportError(VIR_ERR_OPERATION_FAILED,
_("target %s:%d already exists"),

View File

@ -0,0 +1,53 @@
LC_ALL=C \
PATH=/bin \
HOME=/home/test \
USER=test \
LOGNAME=test \
QEMU_AUDIO_DRV=none \
/usr/libexec/qemu-kvm \
-name q35-test \
-S \
-M q35 \
-m 2048 \
-smp 2 \
-uuid 11dbdcdd-4c3b-482b-8903-9bdb8c0a2774 \
-nographic \
-nodefaults \
-monitor unix:/tmp/lib/domain--1-q35-test/monitor.sock,server,nowait \
-no-acpi \
-boot c \
-device i82801b11-bridge,id=pci.1,bus=pcie.0,addr=0x1e \
-device pci-bridge,chassis_nr=2,id=pci.2,bus=pci.1,addr=0x0 \
-device ioh3420,port=0x10,chassis=3,id=pci.3,bus=pcie.0,addr=0x2 \
-device x3130-upstream,id=pci.4,bus=pci.3,addr=0x0 \
-device xio3130-downstream,port=0x0,chassis=5,id=pci.5,bus=pci.4,addr=0x0 \
-device xio3130-downstream,port=0x1,chassis=6,id=pci.6,bus=pci.4,addr=0x1 \
-device xio3130-downstream,port=0x2,chassis=7,id=pci.7,bus=pci.4,addr=0x2 \
-device xio3130-downstream,port=0x3,chassis=8,id=pci.8,bus=pci.4,addr=0x3 \
-device xio3130-downstream,port=0x4,chassis=9,id=pci.9,bus=pci.4,addr=0x4 \
-device xio3130-downstream,port=0x5,chassis=10,id=pci.10,bus=pci.4,addr=0x5 \
-device xio3130-downstream,port=0x6,chassis=11,id=pci.11,bus=pci.4,addr=0x6 \
-device xio3130-downstream,port=0x7,chassis=12,id=pci.12,bus=pci.4,addr=0x7 \
-device xio3130-downstream,port=0x8,chassis=13,id=pci.13,bus=pci.4,addr=0x8 \
-device xio3130-downstream,port=0x9,chassis=14,id=pci.14,bus=pci.4,addr=0x9 \
-device ich9-usb-ehci1,id=usb,bus=pcie.0,addr=0x1d.0x7 \
-device ich9-usb-uhci1,masterbus=usb.0,firstport=0,bus=pcie.0,multifunction=on,\
addr=0x1d \
-device ich9-usb-uhci2,masterbus=usb.0,firstport=2,bus=pcie.0,addr=0x1d.0x1 \
-device ich9-usb-uhci3,masterbus=usb.0,firstport=4,bus=pcie.0,addr=0x1d.0x2 \
-device ich9-usb-ehci1,id=usb1,bus=pcie.0,addr=0x1a.0x7 \
-device ich9-usb-uhci1,masterbus=usb1.0,firstport=0,bus=pcie.0,multifunction=on,\
addr=0x1a \
-device ich9-usb-uhci1,masterbus=usb2.0,firstport=0,bus=pci.2,multifunction=on,\
addr=0x1 \
-device ich9-usb-uhci2,masterbus=usb2.0,firstport=2,bus=pci.2,addr=0x1.0x1 \
-device ich9-usb-uhci3,masterbus=usb2.0,firstport=4,bus=pci.2,addr=0x1.0x2 \
-device ich9-usb-ehci1,id=usb2,bus=pci.2,addr=0x1.0x7 \
-device nec-usb-xhci,id=usb3,bus=pci.2,addr=0x2 \
-device ich9-usb-uhci1,masterbus=usb4.0,firstport=0,bus=pci.2,multifunction=on,\
addr=0x3 \
-device ich9-usb-uhci2,masterbus=usb4.0,firstport=2,bus=pci.2,addr=0x3.0x1 \
-device ich9-usb-uhci3,masterbus=usb4.0,firstport=4,bus=pci.2,addr=0x3.0x2 \
-device ich9-usb-ehci1,id=usb4,bus=pci.2,addr=0x3.0x7 \
-drive file=/dev/HostVG/QEMUGuest1,format=raw,if=none,id=drive-sata0-0-0 \
-device ide-drive,bus=ide.0,drive=drive-sata0-0-0,id=sata0-0-0

View File

@ -0,0 +1,54 @@
<domain type='qemu'>
<name>q35-test</name>
<uuid>11dbdcdd-4c3b-482b-8903-9bdb8c0a2774</uuid>
<memory unit='KiB'>2097152</memory>
<currentMemory unit='KiB'>2097152</currentMemory>
<vcpu placement='static' cpuset='0-1'>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/libexec/qemu-kvm</emulator>
<disk type='block' device='disk'>
<source dev='/dev/HostVG/QEMUGuest1'/>
<target dev='sda' bus='sata'/>
<address type='drive' controller='0' bus='0' target='0' unit='0'/>
</disk>
<controller type='pci' model='pcie-root'/>
<controller type='pci' model='dmi-to-pci-bridge'/>
<controller type='pci' model='pci-bridge'/>
<controller type='pci' model='pcie-root-port'/>
<controller type='pci' model='pcie-switch-upstream-port'/>
<controller type='pci' model='pcie-switch-downstream-port'/>
<controller type='pci' model='pcie-switch-downstream-port'/>
<controller type='pci' model='pcie-switch-downstream-port'/>
<controller type='pci' model='pcie-switch-downstream-port'/>
<controller type='pci' model='pcie-switch-downstream-port'/>
<controller type='pci' model='pcie-switch-downstream-port'/>
<controller type='pci' model='pcie-switch-downstream-port'/>
<controller type='pci' model='pcie-switch-downstream-port'/>
<controller type='pci' model='pcie-switch-downstream-port'/>
<controller type='pci' model='pcie-switch-downstream-port'/>
<controller type='usb' model='ich9-ehci1'/>
<controller type='usb' model='ich9-uhci1'/>
<controller type='usb' model='ich9-uhci2'/>
<controller type='usb' model='ich9-uhci3'/>
<controller type='usb' model='ich9-ehci1'/>
<controller type='usb' model='ich9-uhci1'/>
<controller type='usb' model='ich9-uhci1'/>
<controller type='usb' model='ich9-uhci2'/>
<controller type='usb' model='ich9-uhci3'/>
<controller type='usb' model='ich9-ehci1'/>
<controller type='usb' model='nec-xhci'/>
<controller type='usb' model='ich9-uhci1'/>
<controller type='usb' model='ich9-uhci2'/>
<controller type='usb' model='ich9-uhci3'/>
<controller type='usb' model='ich9-ehci1'/>
<memballoon model='none'/>
</devices>
</domain>

View File

@ -1574,6 +1574,15 @@ mymain(void)
QEMU_CAPS_ICH9_AHCI,
QEMU_CAPS_DEVICE_VIDEO_PRIMARY,
QEMU_CAPS_VGA_QXL, QEMU_CAPS_DEVICE_QXL);
DO_TEST("autoindex",
QEMU_CAPS_DEVICE_PCI_BRIDGE,
QEMU_CAPS_DEVICE_DMI_TO_PCI_BRIDGE,
QEMU_CAPS_DEVICE_IOH3420,
QEMU_CAPS_DEVICE_X3130_UPSTREAM,
QEMU_CAPS_DEVICE_XIO3130_DOWNSTREAM,
QEMU_CAPS_ICH9_AHCI,
QEMU_CAPS_PCI_MULTIFUNCTION, QEMU_CAPS_ICH9_USB_EHCI1,
QEMU_CAPS_NEC_USB_XHCI);
DO_TEST_PARSE_ERROR("q35-wrong-root",
QEMU_CAPS_DEVICE_PCI_BRIDGE,

View File

@ -0,0 +1,153 @@
<domain type='qemu'>
<name>q35-test</name>
<uuid>11dbdcdd-4c3b-482b-8903-9bdb8c0a2774</uuid>
<memory unit='KiB'>2097152</memory>
<currentMemory unit='KiB'>2097152</currentMemory>
<vcpu placement='static' cpuset='0-1'>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/libexec/qemu-kvm</emulator>
<disk type='block' device='disk'>
<source dev='/dev/HostVG/QEMUGuest1'/>
<target dev='sda' bus='sata'/>
<address type='drive' controller='0' bus='0' target='0' unit='0'/>
</disk>
<controller type='pci' index='0' model='pcie-root'/>
<controller type='pci' index='1' model='dmi-to-pci-bridge'>
<model name='i82801b11-bridge'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x1e' function='0x0'/>
</controller>
<controller type='pci' index='2' model='pci-bridge'>
<model name='pci-bridge'/>
<target chassisNr='2'/>
<address type='pci' domain='0x0000' bus='0x01' slot='0x00' function='0x0'/>
</controller>
<controller type='pci' index='3' model='pcie-root-port'>
<model name='ioh3420'/>
<target chassis='3' port='0x10'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/>
</controller>
<controller type='pci' index='4' model='pcie-switch-upstream-port'>
<model name='x3130-upstream'/>
<address type='pci' domain='0x0000' bus='0x03' slot='0x00' function='0x0'/>
</controller>
<controller type='pci' index='5' model='pcie-switch-downstream-port'>
<model name='xio3130-downstream'/>
<target chassis='5' port='0x0'/>
<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'/>
<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='8' port='0x3'/>
<address type='pci' domain='0x0000' bus='0x04' slot='0x03' function='0x0'/>
</controller>
<controller type='pci' index='9' model='pcie-switch-downstream-port'>
<model name='xio3130-downstream'/>
<target chassis='9' port='0x4'/>
<address type='pci' domain='0x0000' bus='0x04' slot='0x04' function='0x0'/>
</controller>
<controller type='pci' index='10' model='pcie-switch-downstream-port'>
<model name='xio3130-downstream'/>
<target chassis='10' port='0x5'/>
<address type='pci' domain='0x0000' bus='0x04' slot='0x05' function='0x0'/>
</controller>
<controller type='pci' index='11' model='pcie-switch-downstream-port'>
<model name='xio3130-downstream'/>
<target chassis='11' port='0x6'/>
<address type='pci' domain='0x0000' bus='0x04' slot='0x06' function='0x0'/>
</controller>
<controller type='pci' index='12' model='pcie-switch-downstream-port'>
<model name='xio3130-downstream'/>
<target chassis='12' port='0x7'/>
<address type='pci' domain='0x0000' bus='0x04' slot='0x07' function='0x0'/>
</controller>
<controller type='pci' index='13' model='pcie-switch-downstream-port'>
<model name='xio3130-downstream'/>
<target chassis='13' port='0x8'/>
<address type='pci' domain='0x0000' bus='0x04' slot='0x08' function='0x0'/>
</controller>
<controller type='pci' index='14' model='pcie-switch-downstream-port'>
<model name='xio3130-downstream'/>
<target chassis='14' port='0x9'/>
<address type='pci' domain='0x0000' bus='0x04' slot='0x09' function='0x0'/>
</controller>
<controller type='usb' index='0' model='ich9-ehci1'>
<address type='pci' domain='0x0000' bus='0x00' slot='0x1d' function='0x7'/>
</controller>
<controller type='usb' index='0' model='ich9-uhci1'>
<master startport='0'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x1d' function='0x0' multifunction='on'/>
</controller>
<controller type='usb' index='0' model='ich9-uhci2'>
<master startport='2'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x1d' function='0x1'/>
</controller>
<controller type='usb' index='0' model='ich9-uhci3'>
<master startport='4'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x1d' function='0x2'/>
</controller>
<controller type='usb' index='1' model='ich9-ehci1'>
<address type='pci' domain='0x0000' bus='0x00' slot='0x1a' function='0x7'/>
</controller>
<controller type='usb' index='1' model='ich9-uhci1'>
<master startport='0'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x1a' function='0x0' multifunction='on'/>
</controller>
<controller type='usb' index='2' model='ich9-uhci1'>
<master startport='0'/>
<address type='pci' domain='0x0000' bus='0x02' slot='0x01' function='0x0' multifunction='on'/>
</controller>
<controller type='usb' index='2' model='ich9-uhci2'>
<master startport='2'/>
<address type='pci' domain='0x0000' bus='0x02' slot='0x01' function='0x1'/>
</controller>
<controller type='usb' index='2' model='ich9-uhci3'>
<master startport='4'/>
<address type='pci' domain='0x0000' bus='0x02' slot='0x01' function='0x2'/>
</controller>
<controller type='usb' index='2' model='ich9-ehci1'>
<address type='pci' domain='0x0000' bus='0x02' slot='0x01' function='0x7'/>
</controller>
<controller type='usb' index='3' model='nec-xhci'>
<address type='pci' domain='0x0000' bus='0x02' slot='0x02' function='0x0'/>
</controller>
<controller type='usb' index='4' model='ich9-uhci1'>
<master startport='0'/>
<address type='pci' domain='0x0000' bus='0x02' slot='0x03' function='0x0' multifunction='on'/>
</controller>
<controller type='usb' index='4' model='ich9-uhci2'>
<master startport='2'/>
<address type='pci' domain='0x0000' bus='0x02' slot='0x03' function='0x1'/>
</controller>
<controller type='usb' index='4' model='ich9-uhci3'>
<master startport='4'/>
<address type='pci' domain='0x0000' bus='0x02' slot='0x03' function='0x2'/>
</controller>
<controller type='usb' index='4' model='ich9-ehci1'>
<address type='pci' domain='0x0000' bus='0x02' slot='0x03' function='0x7'/>
</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>

View File

@ -664,7 +664,15 @@ mymain(void)
QEMU_CAPS_DEVICE_X3130_UPSTREAM,
QEMU_CAPS_DEVICE_XIO3130_DOWNSTREAM,
QEMU_CAPS_DEVICE_PXB_PCIE);
DO_TEST_FULL("autoindex", WHEN_ACTIVE, GIC_NONE,
QEMU_CAPS_DEVICE_PCI_BRIDGE,
QEMU_CAPS_DEVICE_DMI_TO_PCI_BRIDGE,
QEMU_CAPS_DEVICE_IOH3420,
QEMU_CAPS_DEVICE_X3130_UPSTREAM,
QEMU_CAPS_DEVICE_XIO3130_DOWNSTREAM,
QEMU_CAPS_ICH9_AHCI,
QEMU_CAPS_PCI_MULTIFUNCTION, QEMU_CAPS_ICH9_USB_EHCI1,
QEMU_CAPS_NEC_USB_XHCI);
DO_TEST_FULL("hostdev-scsi-lsi", WHEN_ACTIVE, GIC_NONE,
QEMU_CAPS_VIRTIO_SCSI, QEMU_CAPS_SCSI_LSI,