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");