diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index c7fc6e60a9..6c404983e5 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -1177,8 +1177,7 @@ void qemuDomainPCIAddressSetFree(qemuDomainPCIAddressSetPtr addrs)
}
-int qemuDomainPCIAddressSetNextAddr(qemuDomainPCIAddressSetPtr addrs,
- virDomainDeviceInfoPtr dev)
+static int qemuDomainPCIAddressGetNextSlot(qemuDomainPCIAddressSetPtr addrs)
{
int i;
int iteration;
@@ -1205,20 +1204,10 @@ int qemuDomainPCIAddressSetNextAddr(qemuDomainPCIAddressSetPtr addrs,
continue;
}
- VIR_DEBUG("Allocating PCI addr %s", addr);
+ VIR_DEBUG("Found free PCI addr %s", addr);
VIR_FREE(addr);
- if (qemuDomainPCIAddressReserveSlot(addrs, i) < 0)
- return -1;
-
- dev->type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI;
- dev->addr.pci = maybe.addr.pci;
-
- addrs->nextslot = i + 1;
- if (QEMU_PCI_ADDRESS_LAST_SLOT < addrs->nextslot)
- addrs->nextslot = 0;
-
- return 0;
+ return i;
}
qemuReportError(VIR_ERR_INTERNAL_ERROR,
@@ -1226,6 +1215,38 @@ int qemuDomainPCIAddressSetNextAddr(qemuDomainPCIAddressSetPtr addrs,
return -1;
}
+int qemuDomainPCIAddressSetNextAddr(qemuDomainPCIAddressSetPtr addrs,
+ virDomainDeviceInfoPtr dev)
+{
+ int slot = qemuDomainPCIAddressGetNextSlot(addrs);
+
+ if (slot < 0)
+ return -1;
+
+ if (qemuDomainPCIAddressReserveSlot(addrs, slot) < 0)
+ return -1;
+
+ dev->type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI;
+ dev->addr.pci.bus = 0;
+ dev->addr.pci.domain = 0;
+ dev->addr.pci.slot = slot;
+ dev->addr.pci.function = 0;
+
+ addrs->nextslot = slot + 1;
+ if (QEMU_PCI_ADDRESS_LAST_SLOT < addrs->nextslot)
+ addrs->nextslot = 0;
+
+ return 0;
+}
+
+
+#define IS_USB2_CONTROLLER(ctrl) \
+ (((ctrl)->type == VIR_DOMAIN_CONTROLLER_TYPE_USB) && \
+ ((ctrl)->model == VIR_DOMAIN_CONTROLLER_MODEL_USB_ICH9_EHCI1 || \
+ (ctrl)->model == VIR_DOMAIN_CONTROLLER_MODEL_USB_ICH9_UHCI1 || \
+ (ctrl)->model == VIR_DOMAIN_CONTROLLER_MODEL_USB_ICH9_UHCI2 || \
+ (ctrl)->model == VIR_DOMAIN_CONTROLLER_MODEL_USB_ICH9_UHCI3))
+
/*
* This assigns static PCI slots to all configured devices.
* The ordering here is chosen to match the ordering used
@@ -1261,7 +1282,7 @@ int qemuDomainPCIAddressSetNextAddr(qemuDomainPCIAddressSetPtr addrs,
int
qemuAssignDevicePCISlots(virDomainDefPtr def, qemuDomainPCIAddressSetPtr addrs)
{
- int i;
+ size_t i, j;
bool reservedIDE = false;
bool reservedUSB = false;
int function;
@@ -1405,7 +1426,7 @@ qemuAssignDevicePCISlots(virDomainDefPtr def, qemuDomainPCIAddressSetPtr addrs)
goto error;
}
- /* Disk controllers (SCSI only for now) */
+ /* Device controllers (SCSI, USB, but not IDE, FDC or CCID) */
for (i = 0; i < def->ncontrollers ; i++) {
/* FDC lives behind the ISA bridge; CCID is a usb device */
if (def->controllers[i]->type == VIR_DOMAIN_CONTROLLER_TYPE_FDC ||
@@ -1422,8 +1443,58 @@ qemuAssignDevicePCISlots(virDomainDefPtr def, qemuDomainPCIAddressSetPtr addrs)
continue;
if (def->controllers[i]->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE)
continue;
- if (qemuDomainPCIAddressSetNextAddr(addrs, &def->controllers[i]->info) < 0)
- goto error;
+
+ /* USB2 needs special handling to put all companions in the same slot */
+ if (IS_USB2_CONTROLLER(def->controllers[i])) {
+ virDomainDevicePCIAddress addr = { 0, 0, 0, 0, false };
+ for (j = 0 ; j < i ; j++) {
+ if (IS_USB2_CONTROLLER(def->controllers[j]) &&
+ def->controllers[j]->idx == def->controllers[i]->idx) {
+ addr = def->controllers[j]->info.addr.pci;
+ break;
+ }
+ }
+
+ switch (def->controllers[i]->model) {
+ case VIR_DOMAIN_CONTROLLER_MODEL_USB_ICH9_EHCI1:
+ addr.function = 7;
+ break;
+ case VIR_DOMAIN_CONTROLLER_MODEL_USB_ICH9_UHCI1:
+ addr.function = 0;
+ addr.multi = VIR_DOMAIN_DEVICE_ADDRESS_PCI_MULTI_ON;
+ break;
+ case VIR_DOMAIN_CONTROLLER_MODEL_USB_ICH9_UHCI2:
+ addr.function = 1;
+ break;
+ case VIR_DOMAIN_CONTROLLER_MODEL_USB_ICH9_UHCI3:
+ addr.function = 2;
+ break;
+ }
+
+ if (addr.slot == 0) {
+ /* This is the first part of the controller, so need
+ * to find a free slot & then reserve a function */
+ int slot = qemuDomainPCIAddressGetNextSlot(addrs);
+ if (slot < 0)
+ goto error;
+
+ addr.slot = slot;
+ addrs->nextslot = addr.slot + 1;
+ if (QEMU_PCI_ADDRESS_LAST_SLOT < addrs->nextslot)
+ addrs->nextslot = 0;
+ }
+ /* Finally we can reserve the slot+function */
+ if (qemuDomainPCIAddressReserveFunction(addrs,
+ addr.slot,
+ addr.function) < 0)
+ goto error;
+
+ def->controllers[i]->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI;
+ def->controllers[i]->info.addr.pci = addr;
+ } else {
+ if (qemuDomainPCIAddressSetNextAddr(addrs, &def->controllers[i]->info) < 0)
+ goto error;
+ }
}
/* Disks (VirtIO only for now) */
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-usb-ich9-ehci-addr.args b/tests/qemuxml2argvdata/qemuxml2argv-usb-ich9-ehci-addr.args
index babd4f804a..cf070a1741 100644
--- a/tests/qemuxml2argvdata/qemuxml2argv-usb-ich9-ehci-addr.args
+++ b/tests/qemuxml2argvdata/qemuxml2argv-usb-ich9-ehci-addr.args
@@ -2,5 +2,16 @@ LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test /usr/bin/qemu -S \
-M pc -m 214 -smp 1 -nographic -nodefconfig -nodefaults \
-chardev socket,id=charmonitor,path=/tmp/test-monitor,server,nowait \
-mon chardev=charmonitor,id=monitor,mode=readline -no-acpi -boot c \
--device ich9-usb-ehci1,id=usb,bus=pci.0,addr=0x4.0x7 \
--device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x3
+-device ich9-usb-ehci1,id=usb,bus=pci.0,addr=0x3.0x7 \
+-device ich9-usb-uhci1,masterbus=usb.0,firstport=0,bus=pci.0,multifunction=on,addr=0x3 \
+-device ich9-usb-uhci3,masterbus=usb.0,firstport=4,bus=pci.0,addr=0x3.0x2 \
+-device ich9-usb-uhci2,masterbus=usb.0,firstport=2,bus=pci.0,addr=0x3.0x1 \
+-device ich9-usb-ehci1,id=usb1,bus=pci.0,addr=0x4.0x7 \
+-device ich9-usb-uhci1,masterbus=usb1.0,firstport=0,bus=pci.0,multifunction=on,addr=0x4 \
+-device ich9-usb-uhci3,masterbus=usb1.0,firstport=4,bus=pci.0,addr=0x4.0x2 \
+-device ich9-usb-uhci2,masterbus=usb1.0,firstport=2,bus=pci.0,addr=0x4.0x1 \
+-device ich9-usb-ehci1,id=usb2,bus=pci.0,addr=0x5.0x7 \
+-device ich9-usb-uhci1,masterbus=usb2.0,firstport=0,bus=pci.0,multifunction=on,addr=0x5 \
+-device ich9-usb-uhci3,masterbus=usb2.0,firstport=4,bus=pci.0,addr=0x5.0x2 \
+-device ich9-usb-uhci2,masterbus=usb2.0,firstport=2,bus=pci.0,addr=0x5.0x1 \
+-device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x6
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-usb-ich9-ehci-addr.xml b/tests/qemuxml2argvdata/qemuxml2argv-usb-ich9-ehci-addr.xml
index aa6c092f3e..bf35b5548b 100644
--- a/tests/qemuxml2argvdata/qemuxml2argv-usb-ich9-ehci-addr.xml
+++ b/tests/qemuxml2argvdata/qemuxml2argv-usb-ich9-ehci-addr.xml
@@ -10,8 +10,43 @@
/usr/bin/qemu
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-usb-ich9-ehci-addr.xml b/tests/qemuxml2xmloutdata/qemuxml2xmlout-usb-ich9-ehci-addr.xml
new file mode 100644
index 0000000000..e7592e995a
--- /dev/null
+++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-usb-ich9-ehci-addr.xml
@@ -0,0 +1,49 @@
+
+ QEMUGuest1
+ c7a5fdbd-edaf-9455-926a-d65c16db1809
+ 219136
+ 219136
+ 1
+
+ hvm
+
+
+
+ destroy
+ restart
+ destroy
+
+ /usr/bin/qemu
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/qemuxml2xmltest.c b/tests/qemuxml2xmltest.c
index 42e4d9df58..70c1e4de2a 100644
--- a/tests/qemuxml2xmltest.c
+++ b/tests/qemuxml2xmltest.c
@@ -222,6 +222,7 @@ mymain(void)
DO_TEST_DIFFERENT("serial-target-port-auto");
DO_TEST_DIFFERENT("graphics-listen-network2");
DO_TEST_DIFFERENT("graphics-spice-timeout");
+ DO_TEST_DIFFERENT("usb-ich9-ehci-addr");
DO_TEST_DIFFERENT("metadata");