[libvirt] [PATCHv2 1/7] qemu: enable auto-allocate of all PCI addresses
Doug Goldstein
cardoe at gentoo.org
Sun Aug 4 21:01:48 UTC 2013
On Sat, Aug 3, 2013 at 9:01 PM, Laine Stump <laine at laine.org> wrote:
> Previous refactoring of the guest PCI address reservation/allocation
> code allowed for slot types other than basic PCI (e.g. PCI express,
> non-hotpluggable slots, etc) but would not auto-allocate a slot for a
> device that required any type other than a basic hot-pluggable
> PCI slot.
>
> This patch refactors the code to be aware of different slot types
> during auto-allocation of addresses as well - as long as there is an
> empty slot of the required type, it will be found and used.
>
> The piece that *wasn't* added is that we don't auto-create a new PCI
> bus when needed for anything except basic PCI devices. This is because
> there are multiple different types of controllers that can provide,
> for example, a PCI express slot (in addition to the pcie-root
> controller, these can also be found on a "root-port" or on a
> "downstream-switch-port"). Since we currently don't support any PCIe
> devices (except pending support for dmi-to-pci-bridge), we can defer
> any decision on what to do about this.
> ---
> src/qemu/qemu_command.c | 112 ++++++++++++++++++++++++++++++++++++++----------
> 1 file changed, 90 insertions(+), 22 deletions(-)
>
> diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
> index abc973a..cafc4bf 100644
> --- a/src/qemu/qemu_command.c
> +++ b/src/qemu/qemu_command.c
> @@ -1429,6 +1429,7 @@ struct _qemuDomainPCIAddressSet {
> qemuDomainPCIAddressBus *buses;
> size_t nbuses;
> virDevicePCIAddress lastaddr;
> + qemuDomainPCIConnectFlags lastFlags;
> bool dryRun; /* on a dry run, new buses are auto-added
> and addresses aren't saved in device infos */
> };
> @@ -1630,7 +1631,7 @@ qemuCollectPCIAddress(virDomainDefPtr def ATTRIBUTE_UNUSED,
> int ret = -1;
> virDevicePCIAddressPtr addr = &info->addr.pci;
> bool entireSlot;
> - /* FIXME: flags should be set according to the requirements of @device */
> + /* flags may be changed from default below */
> qemuDomainPCIConnectFlags flags = (QEMU_PCI_CONNECT_HOTPLUGGABLE |
> QEMU_PCI_CONNECT_TYPE_PCI);
>
> @@ -1644,28 +1645,60 @@ qemuCollectPCIAddress(virDomainDefPtr def ATTRIBUTE_UNUSED,
> return 0;
> }
>
> + /* Change flags according to differing requirements of different
> + * devices.
> + */
> + if (device->type == VIR_DOMAIN_DEVICE_CONTROLLER &&
> + device->data.controller->type == VIR_DOMAIN_CONTROLLER_TYPE_PCI) {
> + switch (device->data.controller->model) {
> + case VIR_DOMAIN_CONTROLLER_MODEL_PCI_BRIDGE:
> + /* pci-bridge needs a PCI slot, but it isn't
> + * hot-pluggable, so it doesn't need a hot-pluggable slot.
> + */
> + flags = QEMU_PCI_CONNECT_TYPE_PCI;
> + break;
> + default:
> + break;
> + }
> + }
> +
> /* Ignore implicit controllers on slot 0:0:1.0:
> * implicit IDE controller on 0:0:1.1 (no qemu command line)
> * implicit USB controller on 0:0:1.2 (-usb)
> *
> * If the machine does have a PCI bus, they will get reserved
> * in qemuAssignDevicePCISlots().
> - *
> - * FIXME: When we have support for a pcie-root controller at bus
> - * 0, we will no longer be able to skip checking of these devices,
> - * as they are PCI, and thus can't be connected to bus 0 if it is
> - * PCIe rather than PCI.
> + */
> +
> + /* These are the IDE and USB controllers in the PIIX3, hardcoded
> + * to bus 0 slot 1. They cannot be attached to a PCIe slot, only
> + * PCI.
> */
> if (device->type == VIR_DOMAIN_DEVICE_CONTROLLER && addr->domain == 0 &&
> addr->bus == 0 && addr->slot == 1) {
> virDomainControllerDefPtr cont = device->data.controller;
> - if (cont->type == VIR_DOMAIN_CONTROLLER_TYPE_IDE && cont->idx == 0 &&
> - addr->function == 1)
> - return 0;
> - if (cont->type == VIR_DOMAIN_CONTROLLER_TYPE_USB && cont->idx == 0 &&
> - (cont->model == VIR_DOMAIN_CONTROLLER_MODEL_USB_PIIX3_UHCI ||
> - cont->model == -1) && addr->function == 2)
> - return 0;
> +
> + if ((cont->type == VIR_DOMAIN_CONTROLLER_TYPE_IDE && cont->idx == 0 &&
> + addr->function == 1) ||
> + (cont->type == VIR_DOMAIN_CONTROLLER_TYPE_USB && cont->idx == 0 &&
> + (cont->model == VIR_DOMAIN_CONTROLLER_MODEL_USB_PIIX3_UHCI ||
> + cont->model == -1) && addr->function == 2)) {
> + /* Note the check for nbuses > 0 - if there are no PCI
> + * buses, we skip this check. This is a quirk required for
> + * some machinetypes such as s390, which pretend to have a
> + * PCI bus for long enough to generate the "-usb" on the
> + * commandline, but that don't really care if a PCI bus
> + * actually exists. */
> + if (addrs->nbuses > 0 &&
> + !(addrs->buses[0].flags & QEMU_PCI_CONNECT_TYPE_PCI)) {
> + virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> + _("Bus 0 must be PCI for integrated PIIX3 "
> + "USB or IDE controllers"));
> + return -1;
> + } else {
> + return 0;
> + }
> + }
Still very hacky but at least you improved it by providing a code
comment as to why and a sensible error message if the user gets in
this path. I'd still love to see us improve the situation so we didn't
have to play games like this to get -usb to be emitted for different
machine types.
> }
>
> entireSlot = (addr->function == 0 &&
> @@ -1695,8 +1728,7 @@ qemuDomainAssignPCIAddresses(virDomainDefPtr def,
> int nbuses = 0;
> size_t i;
> int rv;
> - qemuDomainPCIConnectFlags flags = (QEMU_PCI_CONNECT_HOTPLUGGABLE |
> - QEMU_PCI_CONNECT_TYPE_PCI);
> + qemuDomainPCIConnectFlags flags = QEMU_PCI_CONNECT_TYPE_PCI;
So just for my edification, we previously were saying that pci-bridge
devices were hotpluggable when in fact they are not? You could
probably add a code comment above the default flags to that effect,
but not strictly necessary.
>
> for (i = 0; i < def->ncontrollers; i++) {
> if (def->controllers[i]->type == VIR_DOMAIN_CONTROLLER_TYPE_PCI) {
> @@ -1941,7 +1973,11 @@ int qemuDomainPCIAddressEnsureAddr(qemuDomainPCIAddressSetPtr addrs,
> virDomainDeviceInfoPtr dev)
> {
> int ret = 0;
> - /* FIXME: flags should be set according to the particular device */
> + /* Flags should be set according to the particular device,
> + * but only the caller knows the type of device. Currently this
> + * function is only used for hot-plug, though, and hot-plug is
> + * only supported for standard PCI devices, so we can safely use
> + * the setting below */
> qemuDomainPCIConnectFlags flags = (QEMU_PCI_CONNECT_HOTPLUGGABLE |
> QEMU_PCI_CONNECT_TYPE_PCI);
>
> @@ -2005,7 +2041,13 @@ qemuDomainPCIAddressGetNextSlot(qemuDomainPCIAddressSetPtr addrs,
> virDevicePCIAddressPtr next_addr,
> qemuDomainPCIConnectFlags flags)
> {
> - virDevicePCIAddress a = addrs->lastaddr;
> + virDevicePCIAddress a = { 0, 0, 0, 0, false };
Again, me being nitpicky but maybe a comment that says start the
search from the top of the PCI addresses by settings this to all 0s
and then below the comment says that this is a fast out when the flags
match.
> +
> + /* Avoid re-scanning from start if we're searching for exactly the
> + * same type of slot as last time.
> + */
> + if (flags == addrs->lastFlags)
> + a = addrs->lastaddr;
>
> if (addrs->nbuses == 0) {
> virReportError(VIR_ERR_XML_ERROR, "%s", _("No PCI buses available"));
> @@ -2014,6 +2056,12 @@ qemuDomainPCIAddressGetNextSlot(qemuDomainPCIAddressSetPtr addrs,
>
> /* Start the search at the last used bus and slot */
> for (a.slot++; a.bus < addrs->nbuses; a.bus++) {
> + if (!qemuDomainPCIAddressFlagsCompatible(&a, addrs->buses[a.bus].flags,
> + flags, false)) {
> + VIR_DEBUG("PCI bus %.4x:%.2x is not compatible with the device",
> + a.domain, a.bus);
> + continue;
> + }
> for (; a.slot <= QEMU_PCI_ADDRESS_SLOT_LAST; a.slot++) {
> if (!qemuDomainPCIAddressSlotInUse(addrs, &a))
> goto success;
> @@ -2030,9 +2078,15 @@ qemuDomainPCIAddressGetNextSlot(qemuDomainPCIAddressSetPtr addrs,
> if (qemuDomainPCIAddressSetGrow(addrs, &a, flags) < 0)
> return -1;
> goto success;
> - } else {
> + } else if (flags == addrs->lastFlags) {
> /* Check the buses from 0 up to the last used one */
> for (a.bus = 0; a.bus <= addrs->lastaddr.bus; a.bus++) {
> + if (!qemuDomainPCIAddressFlagsCompatible(&a, addrs->buses[a.bus].flags,
> + flags, false)) {
> + VIR_DEBUG("PCI bus %.4x:%.2x is not compatible with the device",
> + a.domain, a.bus);
> + continue;
> + }
> for (a.slot = 1; a.slot <= QEMU_PCI_ADDRESS_SLOT_LAST; a.slot++) {
> if (!qemuDomainPCIAddressSlotInUse(addrs, &a))
> goto success;
> @@ -2072,6 +2126,7 @@ qemuDomainPCIAddressReserveNextSlot(qemuDomainPCIAddressSetPtr addrs,
> }
>
> addrs->lastaddr = addr;
> + addrs->lastFlags = flags;
> return 0;
> }
>
> @@ -2285,15 +2340,26 @@ qemuAssignDevicePCISlots(virDomainDefPtr def,
> goto error;
> }
>
> - flags = QEMU_PCI_CONNECT_HOTPLUGGABLE | QEMU_PCI_CONNECT_TYPE_PCI;
> -
> /* PCI controllers */
> for (i = 0; i < def->ncontrollers; i++) {
> if (def->controllers[i]->type == VIR_DOMAIN_CONTROLLER_TYPE_PCI) {
> - if (def->controllers[i]->model == VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT)
> - continue;
> if (def->controllers[i]->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE)
> continue;
> + switch (def->controllers[i]->model) {
> + case VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT:
> + /* pci-root is implicit in the machine,
> + * and needs no address */
> + continue;
> + case VIR_DOMAIN_CONTROLLER_MODEL_PCI_BRIDGE:
> + /* pci-bridge doesn't require hot-plug
> + * (although it does provide hot-plug in its slots)
> + */
> + flags = QEMU_PCI_CONNECT_TYPE_PCI;
> + break;
> + default:
> + flags = QEMU_PCI_CONNECT_HOTPLUGGABLE | QEMU_PCI_CONNECT_TYPE_PCI;
> + break;
> + }
> if (qemuDomainPCIAddressReserveNextSlot(addrs,
> &def->controllers[i]->info,
> flags) < 0)
> @@ -2301,6 +2367,8 @@ qemuAssignDevicePCISlots(virDomainDefPtr def,
> }
> }
>
> + flags = QEMU_PCI_CONNECT_HOTPLUGGABLE | QEMU_PCI_CONNECT_TYPE_PCI;
> +
> for (i = 0; i < def->nfss; i++) {
> if (def->fss[i]->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE)
> continue;
> --
> 1.7.11.7
>
> --
> libvir-list mailing list
> libvir-list at redhat.com
> https://www.redhat.com/mailman/listinfo/libvir-list
Overall looks good and I learned a bit about parts of libvirt I didn't
know much about. I had a few comment nitpicks but otherwise ACK from
me here.
--
Doug Goldstein
More information about the libvir-list
mailing list