mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2025-02-22 03:12:22 +00:00
qemu: extract common PCI handling functions
Move sharable PCI handling functions to domain_addr.[ch], and change theirs prefix from 'qemu' to 'vir': - virDomainPCIAddressAsString; - virDomainPCIAddressBusSetModel; - virDomainPCIAddressEnsureAddr; - virDomainPCIAddressFlagsCompatible; - virDomainPCIAddressGetNextSlot; - virDomainPCIAddressReleaseSlot; - virDomainPCIAddressReserveAddr; - virDomainPCIAddressReserveNextSlot; - virDomainPCIAddressReserveSlot; - virDomainPCIAddressSetFree; - virDomainPCIAddressSetGrow; - virDomainPCIAddressSlotInUse; - virDomainPCIAddressValidate; The only change here is function names, the implementation itself stays untouched. Extract common allocation code from DomainPCIAddressSetCreate into virDomainPCIAddressSetAlloc.
This commit is contained in:
parent
c453f2d076
commit
353cf3707a
@ -14,6 +14,7 @@ src/bhyve/bhyve_process.c
|
||||
src/conf/capabilities.c
|
||||
src/conf/cpu_conf.c
|
||||
src/conf/device_conf.c
|
||||
src/conf/domain_addr.c
|
||||
src/conf/domain_conf.c
|
||||
src/conf/domain_event.c
|
||||
src/conf/interface_conf.c
|
||||
|
@ -247,7 +247,7 @@ NETDEV_CONF_SOURCES = \
|
||||
# Domain driver generic impl APIs
|
||||
DOMAIN_CONF_SOURCES = \
|
||||
conf/capabilities.c conf/capabilities.h \
|
||||
conf/domain_addr.h \
|
||||
conf/domain_addr.c conf/domain_addr.h \
|
||||
conf/domain_conf.c conf/domain_conf.h \
|
||||
conf/domain_audit.c conf/domain_audit.h \
|
||||
conf/domain_nwfilter.c conf/domain_nwfilter.h \
|
||||
|
566
src/conf/domain_addr.c
Normal file
566
src/conf/domain_addr.c
Normal file
@ -0,0 +1,566 @@
|
||||
/*
|
||||
* domain_addr.c: helper APIs for managing domain device addresses
|
||||
*
|
||||
* Copyright (C) 2006-2014 Red Hat, Inc.
|
||||
* Copyright (C) 2006 Daniel P. Berrange
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Author: Daniel P. Berrange <berrange@redhat.com>
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include "viralloc.h"
|
||||
#include "virlog.h"
|
||||
#include "virstring.h"
|
||||
#include "domain_addr.h"
|
||||
|
||||
#define VIR_FROM_THIS VIR_FROM_DOMAIN
|
||||
|
||||
VIR_LOG_INIT("conf.domain_addr");
|
||||
|
||||
bool
|
||||
virDomainPCIAddressFlagsCompatible(virDevicePCIAddressPtr addr,
|
||||
const char *addrStr,
|
||||
virDomainPCIConnectFlags busFlags,
|
||||
virDomainPCIConnectFlags devFlags,
|
||||
bool reportError,
|
||||
bool fromConfig)
|
||||
{
|
||||
virErrorNumber errType = (fromConfig
|
||||
? VIR_ERR_XML_ERROR : VIR_ERR_INTERNAL_ERROR);
|
||||
virDomainPCIConnectFlags flagsMatchMask = VIR_PCI_CONNECT_TYPES_MASK;
|
||||
|
||||
if (fromConfig)
|
||||
flagsMatchMask |= VIR_PCI_CONNECT_TYPE_EITHER_IF_CONFIG;
|
||||
|
||||
/* If this bus doesn't allow the type of connection (PCI
|
||||
* vs. PCIe) required by the device, or if the device requires
|
||||
* hot-plug and this bus doesn't have it, return false.
|
||||
*/
|
||||
if (!(devFlags & busFlags & flagsMatchMask)) {
|
||||
if (reportError) {
|
||||
if (devFlags & VIR_PCI_CONNECT_TYPE_PCI) {
|
||||
virReportError(errType,
|
||||
_("PCI bus is not compatible with the device "
|
||||
"at %s. Device requires a standard PCI slot, "
|
||||
"which is not provided by bus %.4x:%.2x"),
|
||||
addrStr, addr->domain, addr->bus);
|
||||
} else if (devFlags & VIR_PCI_CONNECT_TYPE_PCIE) {
|
||||
virReportError(errType,
|
||||
_("PCI bus is not compatible with the device "
|
||||
"at %s. Device requires a PCI Express slot, "
|
||||
"which is not provided by bus %.4x:%.2x"),
|
||||
addrStr, addr->domain, addr->bus);
|
||||
} else {
|
||||
/* this should never happen. If it does, there is a
|
||||
* bug in the code that sets the flag bits for devices.
|
||||
*/
|
||||
virReportError(errType,
|
||||
_("The device information for %s has no PCI "
|
||||
"connection types listed"), addrStr);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if ((devFlags & VIR_PCI_CONNECT_HOTPLUGGABLE) &&
|
||||
!(busFlags & VIR_PCI_CONNECT_HOTPLUGGABLE)) {
|
||||
if (reportError) {
|
||||
virReportError(errType,
|
||||
_("PCI bus is not compatible with the device "
|
||||
"at %s. Device requires hot-plug capability, "
|
||||
"which is not provided by bus %.4x:%.2x"),
|
||||
addrStr, addr->domain, addr->bus);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/* Verify that the address is in bounds for the chosen bus, and
|
||||
* that the bus is of the correct type for the device (via
|
||||
* comparing the flags).
|
||||
*/
|
||||
bool
|
||||
virDomainPCIAddressValidate(virDomainPCIAddressSetPtr addrs,
|
||||
virDevicePCIAddressPtr addr,
|
||||
const char *addrStr,
|
||||
virDomainPCIConnectFlags flags,
|
||||
bool fromConfig)
|
||||
{
|
||||
virDomainPCIAddressBusPtr bus;
|
||||
virErrorNumber errType = (fromConfig
|
||||
? VIR_ERR_XML_ERROR : VIR_ERR_INTERNAL_ERROR);
|
||||
|
||||
if (addrs->nbuses == 0) {
|
||||
virReportError(errType, "%s", _("No PCI buses available"));
|
||||
return false;
|
||||
}
|
||||
if (addr->domain != 0) {
|
||||
virReportError(errType,
|
||||
_("Invalid PCI address %s. "
|
||||
"Only PCI domain 0 is available"),
|
||||
addrStr);
|
||||
return false;
|
||||
}
|
||||
if (addr->bus >= addrs->nbuses) {
|
||||
virReportError(errType,
|
||||
_("Invalid PCI address %s. "
|
||||
"Only PCI buses up to %zu are available"),
|
||||
addrStr, addrs->nbuses - 1);
|
||||
return false;
|
||||
}
|
||||
|
||||
bus = &addrs->buses[addr->bus];
|
||||
|
||||
/* assure that at least one of the requested connection types is
|
||||
* provided by this bus
|
||||
*/
|
||||
if (!virDomainPCIAddressFlagsCompatible(addr, addrStr, bus->flags,
|
||||
flags, true, fromConfig))
|
||||
return false;
|
||||
|
||||
/* some "buses" are really just a single port */
|
||||
if (bus->minSlot && addr->slot < bus->minSlot) {
|
||||
virReportError(errType,
|
||||
_("Invalid PCI address %s. slot must be >= %zu"),
|
||||
addrStr, bus->minSlot);
|
||||
return false;
|
||||
}
|
||||
if (addr->slot > bus->maxSlot) {
|
||||
virReportError(errType,
|
||||
_("Invalid PCI address %s. slot must be <= %zu"),
|
||||
addrStr, bus->maxSlot);
|
||||
return false;
|
||||
}
|
||||
if (addr->function > VIR_PCI_ADDRESS_FUNCTION_LAST) {
|
||||
virReportError(errType,
|
||||
_("Invalid PCI address %s. function must be <= %u"),
|
||||
addrStr, VIR_PCI_ADDRESS_FUNCTION_LAST);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
virDomainPCIAddressBusSetModel(virDomainPCIAddressBusPtr bus,
|
||||
virDomainControllerModelPCI model)
|
||||
{
|
||||
switch (model) {
|
||||
case VIR_DOMAIN_CONTROLLER_MODEL_PCI_BRIDGE:
|
||||
case VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT:
|
||||
bus->flags = (VIR_PCI_CONNECT_HOTPLUGGABLE |
|
||||
VIR_PCI_CONNECT_TYPE_PCI);
|
||||
bus->minSlot = 1;
|
||||
bus->maxSlot = VIR_PCI_ADDRESS_SLOT_LAST;
|
||||
break;
|
||||
case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT:
|
||||
/* slots 1 - 31, no hotplug, PCIe only unless the address was
|
||||
* specified in user config *and* the particular device being
|
||||
* attached also allows it
|
||||
*/
|
||||
bus->flags = (VIR_PCI_CONNECT_TYPE_PCIE |
|
||||
VIR_PCI_CONNECT_TYPE_EITHER_IF_CONFIG);
|
||||
bus->minSlot = 1;
|
||||
bus->maxSlot = VIR_PCI_ADDRESS_SLOT_LAST;
|
||||
break;
|
||||
case VIR_DOMAIN_CONTROLLER_MODEL_DMI_TO_PCI_BRIDGE:
|
||||
/* slots 1 - 31, standard PCI slots,
|
||||
* but *not* hot-pluggable */
|
||||
bus->flags = VIR_PCI_CONNECT_TYPE_PCI;
|
||||
bus->minSlot = 1;
|
||||
bus->maxSlot = VIR_PCI_ADDRESS_SLOT_LAST;
|
||||
break;
|
||||
default:
|
||||
virReportError(VIR_ERR_INTERNAL_ERROR,
|
||||
_("Invalid PCI controller model %d"), model);
|
||||
return -1;
|
||||
}
|
||||
|
||||
bus->model = model;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Ensure addr fits in the address set, by expanding it if needed.
|
||||
* This will only grow if the flags say that we need a normal
|
||||
* hot-pluggable PCI slot. If we need a different type of slot, it
|
||||
* will fail.
|
||||
*
|
||||
* Return value:
|
||||
* -1 = OOM
|
||||
* 0 = no action performed
|
||||
* >0 = number of buses added
|
||||
*/
|
||||
int
|
||||
virDomainPCIAddressSetGrow(virDomainPCIAddressSetPtr addrs,
|
||||
virDevicePCIAddressPtr addr,
|
||||
virDomainPCIConnectFlags flags)
|
||||
{
|
||||
int add;
|
||||
size_t i;
|
||||
|
||||
add = addr->bus - addrs->nbuses + 1;
|
||||
i = addrs->nbuses;
|
||||
if (add <= 0)
|
||||
return 0;
|
||||
|
||||
/* auto-grow only works when we're adding plain PCI devices */
|
||||
if (!(flags & VIR_PCI_CONNECT_TYPE_PCI)) {
|
||||
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
||||
_("Cannot automatically add a new PCI bus for a "
|
||||
"device requiring a slot other than standard PCI."));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (VIR_EXPAND_N(addrs->buses, addrs->nbuses, add) < 0)
|
||||
return -1;
|
||||
|
||||
for (; i < addrs->nbuses; i++) {
|
||||
/* Any time we auto-add a bus, we will want a multi-slot
|
||||
* bus. Currently the only type of bus we will auto-add is a
|
||||
* pci-bridge, which is hot-pluggable and provides standard
|
||||
* PCI slots.
|
||||
*/
|
||||
virDomainPCIAddressBusSetModel(&addrs->buses[i],
|
||||
VIR_DOMAIN_CONTROLLER_MODEL_PCI_BRIDGE);
|
||||
}
|
||||
return add;
|
||||
}
|
||||
|
||||
|
||||
char *
|
||||
virDomainPCIAddressAsString(virDevicePCIAddressPtr addr)
|
||||
{
|
||||
char *str;
|
||||
|
||||
ignore_value(virAsprintf(&str, "%.4x:%.2x:%.2x.%.1x",
|
||||
addr->domain,
|
||||
addr->bus,
|
||||
addr->slot,
|
||||
addr->function));
|
||||
return str;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Check if the PCI slot is used by another device.
|
||||
*/
|
||||
bool
|
||||
virDomainPCIAddressSlotInUse(virDomainPCIAddressSetPtr addrs,
|
||||
virDevicePCIAddressPtr addr)
|
||||
{
|
||||
return !!addrs->buses[addr->bus].slots[addr->slot];
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Reserve a slot (or just one function) for a device. If
|
||||
* reserveEntireSlot is true, all functions for the slot are reserved,
|
||||
* otherwise only one. If fromConfig is true, the address being
|
||||
* requested came directly from the config and errors should be worded
|
||||
* appropriately. If fromConfig is false, the address was
|
||||
* automatically created by libvirt, so it is an internal error (not
|
||||
* XML).
|
||||
*/
|
||||
int
|
||||
virDomainPCIAddressReserveAddr(virDomainPCIAddressSetPtr addrs,
|
||||
virDevicePCIAddressPtr addr,
|
||||
virDomainPCIConnectFlags flags,
|
||||
bool reserveEntireSlot,
|
||||
bool fromConfig)
|
||||
{
|
||||
int ret = -1;
|
||||
char *addrStr = NULL;
|
||||
virDomainPCIAddressBusPtr bus;
|
||||
virErrorNumber errType = (fromConfig
|
||||
? VIR_ERR_XML_ERROR : VIR_ERR_INTERNAL_ERROR);
|
||||
|
||||
if (!(addrStr = virDomainPCIAddressAsString(addr)))
|
||||
goto cleanup;
|
||||
|
||||
/* Add an extra bus if necessary */
|
||||
if (addrs->dryRun && virDomainPCIAddressSetGrow(addrs, addr, flags) < 0)
|
||||
goto cleanup;
|
||||
/* Check that the requested bus exists, is the correct type, and we
|
||||
* are asking for a valid slot
|
||||
*/
|
||||
if (!virDomainPCIAddressValidate(addrs, addr, addrStr, flags, fromConfig))
|
||||
goto cleanup;
|
||||
|
||||
bus = &addrs->buses[addr->bus];
|
||||
|
||||
if (reserveEntireSlot) {
|
||||
if (bus->slots[addr->slot]) {
|
||||
virReportError(errType,
|
||||
_("Attempted double use of PCI slot %s "
|
||||
"(may need \"multifunction='on'\" for "
|
||||
"device on function 0)"), addrStr);
|
||||
goto cleanup;
|
||||
}
|
||||
bus->slots[addr->slot] = 0xFF; /* reserve all functions of slot */
|
||||
VIR_DEBUG("Reserving PCI slot %s (multifunction='off')", addrStr);
|
||||
} else {
|
||||
if (bus->slots[addr->slot] & (1 << addr->function)) {
|
||||
if (addr->function == 0) {
|
||||
virReportError(errType,
|
||||
_("Attempted double use of PCI Address %s"),
|
||||
addrStr);
|
||||
} else {
|
||||
virReportError(errType,
|
||||
_("Attempted double use of PCI Address %s "
|
||||
"(may need \"multifunction='on'\" "
|
||||
"for device on function 0)"), addrStr);
|
||||
}
|
||||
goto cleanup;
|
||||
}
|
||||
bus->slots[addr->slot] |= (1 << addr->function);
|
||||
VIR_DEBUG("Reserving PCI address %s", addrStr);
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
cleanup:
|
||||
VIR_FREE(addrStr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
virDomainPCIAddressReserveSlot(virDomainPCIAddressSetPtr addrs,
|
||||
virDevicePCIAddressPtr addr,
|
||||
virDomainPCIConnectFlags flags)
|
||||
{
|
||||
return virDomainPCIAddressReserveAddr(addrs, addr, flags, true, false);
|
||||
}
|
||||
|
||||
int
|
||||
virDomainPCIAddressEnsureAddr(virDomainPCIAddressSetPtr addrs,
|
||||
virDomainDeviceInfoPtr dev)
|
||||
{
|
||||
int ret = -1;
|
||||
char *addrStr = NULL;
|
||||
/* 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 */
|
||||
virDomainPCIConnectFlags flags = (VIR_PCI_CONNECT_HOTPLUGGABLE |
|
||||
VIR_PCI_CONNECT_TYPE_PCI);
|
||||
|
||||
if (!(addrStr = virDomainPCIAddressAsString(&dev->addr.pci)))
|
||||
goto cleanup;
|
||||
|
||||
if (dev->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) {
|
||||
/* We do not support hotplug multi-function PCI device now, so we should
|
||||
* reserve the whole slot. The function of the PCI device must be 0.
|
||||
*/
|
||||
if (dev->addr.pci.function != 0) {
|
||||
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
||||
_("Only PCI device addresses with function=0"
|
||||
" are supported"));
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (!virDomainPCIAddressValidate(addrs, &dev->addr.pci,
|
||||
addrStr, flags, true))
|
||||
goto cleanup;
|
||||
|
||||
ret = virDomainPCIAddressReserveSlot(addrs, &dev->addr.pci, flags);
|
||||
} else {
|
||||
ret = virDomainPCIAddressReserveNextSlot(addrs, dev, flags);
|
||||
}
|
||||
|
||||
cleanup:
|
||||
VIR_FREE(addrStr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
virDomainPCIAddressReleaseAddr(virDomainPCIAddressSetPtr addrs,
|
||||
virDevicePCIAddressPtr addr)
|
||||
{
|
||||
addrs->buses[addr->bus].slots[addr->slot] &= ~(1 << addr->function);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
virDomainPCIAddressReleaseSlot(virDomainPCIAddressSetPtr addrs,
|
||||
virDevicePCIAddressPtr addr)
|
||||
{
|
||||
/* permit any kind of connection type in validation, since we
|
||||
* already had it, and are giving it back.
|
||||
*/
|
||||
virDomainPCIConnectFlags flags = VIR_PCI_CONNECT_TYPES_MASK;
|
||||
int ret = -1;
|
||||
char *addrStr = NULL;
|
||||
|
||||
if (!(addrStr = virDomainPCIAddressAsString(addr)))
|
||||
goto cleanup;
|
||||
|
||||
if (!virDomainPCIAddressValidate(addrs, addr, addrStr, flags, false))
|
||||
goto cleanup;
|
||||
|
||||
addrs->buses[addr->bus].slots[addr->slot] = 0;
|
||||
ret = 0;
|
||||
cleanup:
|
||||
VIR_FREE(addrStr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
virDomainPCIAddressSetPtr
|
||||
virDomainPCIAddressSetAlloc(unsigned int nbuses)
|
||||
{
|
||||
virDomainPCIAddressSetPtr addrs;
|
||||
|
||||
if (VIR_ALLOC(addrs) < 0)
|
||||
goto error;
|
||||
|
||||
if (VIR_ALLOC_N(addrs->buses, nbuses) < 0)
|
||||
goto error;
|
||||
|
||||
addrs->nbuses = nbuses;
|
||||
return addrs;
|
||||
|
||||
error:
|
||||
virDomainPCIAddressSetFree(addrs);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
virDomainPCIAddressSetFree(virDomainPCIAddressSetPtr addrs)
|
||||
{
|
||||
if (!addrs)
|
||||
return;
|
||||
|
||||
VIR_FREE(addrs->buses);
|
||||
VIR_FREE(addrs);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
virDomainPCIAddressGetNextSlot(virDomainPCIAddressSetPtr addrs,
|
||||
virDevicePCIAddressPtr next_addr,
|
||||
virDomainPCIConnectFlags flags)
|
||||
{
|
||||
/* default to starting the search for a free slot from
|
||||
* 0000:00:00.0
|
||||
*/
|
||||
virDevicePCIAddress a = { 0, 0, 0, 0, false };
|
||||
char *addrStr = NULL;
|
||||
|
||||
/* except if this search is for the exact same type of device as
|
||||
* last time, continue the search from the previous match
|
||||
*/
|
||||
if (flags == addrs->lastFlags)
|
||||
a = addrs->lastaddr;
|
||||
|
||||
if (addrs->nbuses == 0) {
|
||||
virReportError(VIR_ERR_XML_ERROR, "%s", _("No PCI buses available"));
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Start the search at the last used bus and slot */
|
||||
for (a.slot++; a.bus < addrs->nbuses; a.bus++) {
|
||||
if (!(addrStr = virDomainPCIAddressAsString(&a)))
|
||||
goto error;
|
||||
if (!virDomainPCIAddressFlagsCompatible(&a, addrStr,
|
||||
addrs->buses[a.bus].flags,
|
||||
flags, false, false)) {
|
||||
VIR_FREE(addrStr);
|
||||
VIR_DEBUG("PCI bus %.4x:%.2x is not compatible with the device",
|
||||
a.domain, a.bus);
|
||||
continue;
|
||||
}
|
||||
for (; a.slot <= VIR_PCI_ADDRESS_SLOT_LAST; a.slot++) {
|
||||
if (!virDomainPCIAddressSlotInUse(addrs, &a))
|
||||
goto success;
|
||||
|
||||
VIR_DEBUG("PCI slot %.4x:%.2x:%.2x already in use",
|
||||
a.domain, a.bus, a.slot);
|
||||
}
|
||||
a.slot = 1;
|
||||
VIR_FREE(addrStr);
|
||||
}
|
||||
|
||||
/* There were no free slots after the last used one */
|
||||
if (addrs->dryRun) {
|
||||
/* a is already set to the first new bus and slot 1 */
|
||||
if (virDomainPCIAddressSetGrow(addrs, &a, flags) < 0)
|
||||
goto error;
|
||||
goto success;
|
||||
} 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++) {
|
||||
addrStr = NULL;
|
||||
if (!(addrStr = virDomainPCIAddressAsString(&a)))
|
||||
goto error;
|
||||
if (!virDomainPCIAddressFlagsCompatible(&a, addrStr,
|
||||
addrs->buses[a.bus].flags,
|
||||
flags, false, false)) {
|
||||
VIR_DEBUG("PCI bus %.4x:%.2x is not compatible with the device",
|
||||
a.domain, a.bus);
|
||||
continue;
|
||||
}
|
||||
for (a.slot = 1; a.slot <= VIR_PCI_ADDRESS_SLOT_LAST; a.slot++) {
|
||||
if (!virDomainPCIAddressSlotInUse(addrs, &a))
|
||||
goto success;
|
||||
|
||||
VIR_DEBUG("PCI slot %.4x:%.2x:%.2x already in use",
|
||||
a.domain, a.bus, a.slot);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
virReportError(VIR_ERR_INTERNAL_ERROR,
|
||||
"%s", _("No more available PCI slots"));
|
||||
error:
|
||||
VIR_FREE(addrStr);
|
||||
return -1;
|
||||
|
||||
success:
|
||||
VIR_DEBUG("Found free PCI slot %.4x:%.2x:%.2x",
|
||||
a.domain, a.bus, a.slot);
|
||||
*next_addr = a;
|
||||
VIR_FREE(addrStr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
virDomainPCIAddressReserveNextSlot(virDomainPCIAddressSetPtr addrs,
|
||||
virDomainDeviceInfoPtr dev,
|
||||
virDomainPCIConnectFlags flags)
|
||||
{
|
||||
virDevicePCIAddress addr;
|
||||
if (virDomainPCIAddressGetNextSlot(addrs, &addr, flags) < 0)
|
||||
return -1;
|
||||
|
||||
if (virDomainPCIAddressReserveSlot(addrs, &addr, flags) < 0)
|
||||
return -1;
|
||||
|
||||
if (!addrs->dryRun) {
|
||||
dev->type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI;
|
||||
dev->addr.pci = addr;
|
||||
}
|
||||
|
||||
addrs->lastaddr = addr;
|
||||
addrs->lastFlags = flags;
|
||||
return 0;
|
||||
}
|
@ -76,4 +76,74 @@ typedef virDomainPCIAddressSet *virDomainPCIAddressSetPtr;
|
||||
# define VIR_PCI_CONNECT_TYPES_MASK \
|
||||
(VIR_PCI_CONNECT_TYPE_PCI | VIR_PCI_CONNECT_TYPE_PCIE)
|
||||
|
||||
char *virDomainPCIAddressAsString(virDevicePCIAddressPtr addr)
|
||||
ATTRIBUTE_NONNULL(1);
|
||||
|
||||
virDomainPCIAddressSetPtr virDomainPCIAddressSetAlloc(unsigned int nbuses);
|
||||
|
||||
void virDomainPCIAddressSetFree(virDomainPCIAddressSetPtr addrs);
|
||||
|
||||
bool virDomainPCIAddressFlagsCompatible(virDevicePCIAddressPtr addr,
|
||||
const char *addrStr,
|
||||
virDomainPCIConnectFlags busFlags,
|
||||
virDomainPCIConnectFlags devFlags,
|
||||
bool reportError,
|
||||
bool fromConfig)
|
||||
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
|
||||
|
||||
bool virDomainPCIAddressValidate(virDomainPCIAddressSetPtr addrs,
|
||||
virDevicePCIAddressPtr addr,
|
||||
const char *addrStr,
|
||||
virDomainPCIConnectFlags flags,
|
||||
bool fromConfig)
|
||||
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3);
|
||||
|
||||
|
||||
int virDomainPCIAddressBusSetModel(virDomainPCIAddressBusPtr bus,
|
||||
virDomainControllerModelPCI model)
|
||||
ATTRIBUTE_NONNULL(1);
|
||||
|
||||
bool virDomainPCIAddressSlotInUse(virDomainPCIAddressSetPtr addrs,
|
||||
virDevicePCIAddressPtr addr)
|
||||
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
|
||||
|
||||
int virDomainPCIAddressSetGrow(virDomainPCIAddressSetPtr addrs,
|
||||
virDevicePCIAddressPtr addr,
|
||||
virDomainPCIConnectFlags flags)
|
||||
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
|
||||
|
||||
int virDomainPCIAddressReserveAddr(virDomainPCIAddressSetPtr addrs,
|
||||
virDevicePCIAddressPtr addr,
|
||||
virDomainPCIConnectFlags flags,
|
||||
bool reserveEntireSlot,
|
||||
bool fromConfig)
|
||||
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
|
||||
|
||||
int virDomainPCIAddressReserveSlot(virDomainPCIAddressSetPtr addrs,
|
||||
virDevicePCIAddressPtr addr,
|
||||
virDomainPCIConnectFlags flags)
|
||||
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
|
||||
|
||||
int virDomainPCIAddressEnsureAddr(virDomainPCIAddressSetPtr addrs,
|
||||
virDomainDeviceInfoPtr dev)
|
||||
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
|
||||
|
||||
int virDomainPCIAddressReleaseAddr(virDomainPCIAddressSetPtr addrs,
|
||||
virDevicePCIAddressPtr addr)
|
||||
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
|
||||
|
||||
int virDomainPCIAddressReleaseSlot(virDomainPCIAddressSetPtr addrs,
|
||||
virDevicePCIAddressPtr addr)
|
||||
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
|
||||
|
||||
int virDomainPCIAddressGetNextSlot(virDomainPCIAddressSetPtr addrs,
|
||||
virDevicePCIAddressPtr next_addr,
|
||||
virDomainPCIConnectFlags flags)
|
||||
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
|
||||
|
||||
int virDomainPCIAddressReserveNextSlot(virDomainPCIAddressSetPtr addrs,
|
||||
virDomainDeviceInfoPtr dev,
|
||||
virDomainPCIConnectFlags flags)
|
||||
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
|
||||
|
||||
#endif /* __DOMAIN_ADDR_H__ */
|
||||
|
@ -85,6 +85,23 @@ virDevicePCIAddressIsValid;
|
||||
virDevicePCIAddressParseXML;
|
||||
|
||||
|
||||
# conf/domain_addr.h
|
||||
virDomainPCIAddressAsString;
|
||||
virDomainPCIAddressBusSetModel;
|
||||
virDomainPCIAddressEnsureAddr;
|
||||
virDomainPCIAddressFlagsCompatible;
|
||||
virDomainPCIAddressGetNextSlot;
|
||||
virDomainPCIAddressReleaseSlot;
|
||||
virDomainPCIAddressReserveAddr;
|
||||
virDomainPCIAddressReserveNextSlot;
|
||||
virDomainPCIAddressReserveSlot;
|
||||
virDomainPCIAddressSetAlloc;
|
||||
virDomainPCIAddressSetFree;
|
||||
virDomainPCIAddressSetGrow;
|
||||
virDomainPCIAddressSlotInUse;
|
||||
virDomainPCIAddressValidate;
|
||||
|
||||
|
||||
# conf/domain_audit.h
|
||||
virDomainAuditCgroup;
|
||||
virDomainAuditCgroupMajor;
|
||||
|
@ -1445,232 +1445,6 @@ int qemuDomainAssignSpaprVIOAddresses(virDomainDefPtr def,
|
||||
}
|
||||
|
||||
|
||||
static bool
|
||||
qemuDomainPCIAddressFlagsCompatible(virDevicePCIAddressPtr addr,
|
||||
const char *addrStr,
|
||||
virDomainPCIConnectFlags busFlags,
|
||||
virDomainPCIConnectFlags devFlags,
|
||||
bool reportError,
|
||||
bool fromConfig)
|
||||
{
|
||||
virErrorNumber errType = (fromConfig
|
||||
? VIR_ERR_XML_ERROR : VIR_ERR_INTERNAL_ERROR);
|
||||
virDomainPCIConnectFlags flagsMatchMask = VIR_PCI_CONNECT_TYPES_MASK;
|
||||
|
||||
if (fromConfig)
|
||||
flagsMatchMask |= VIR_PCI_CONNECT_TYPE_EITHER_IF_CONFIG;
|
||||
|
||||
/* If this bus doesn't allow the type of connection (PCI
|
||||
* vs. PCIe) required by the device, or if the device requires
|
||||
* hot-plug and this bus doesn't have it, return false.
|
||||
*/
|
||||
if (!(devFlags & busFlags & flagsMatchMask)) {
|
||||
if (reportError) {
|
||||
if (devFlags & VIR_PCI_CONNECT_TYPE_PCI) {
|
||||
virReportError(errType,
|
||||
_("PCI bus is not compatible with the device "
|
||||
"at %s. Device requires a standard PCI slot, "
|
||||
"which is not provided by bus %.4x:%.2x"),
|
||||
addrStr, addr->domain, addr->bus);
|
||||
} else if (devFlags & VIR_PCI_CONNECT_TYPE_PCIE) {
|
||||
virReportError(errType,
|
||||
_("PCI bus is not compatible with the device "
|
||||
"at %s. Device requires a PCI Express slot, "
|
||||
"which is not provided by bus %.4x:%.2x"),
|
||||
addrStr, addr->domain, addr->bus);
|
||||
} else {
|
||||
/* this should never happen. If it does, there is a
|
||||
* bug in the code that sets the flag bits for devices.
|
||||
*/
|
||||
virReportError(errType,
|
||||
_("The device information for %s has no PCI "
|
||||
"connection types listed"), addrStr);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if ((devFlags & VIR_PCI_CONNECT_HOTPLUGGABLE) &&
|
||||
!(busFlags & VIR_PCI_CONNECT_HOTPLUGGABLE)) {
|
||||
if (reportError) {
|
||||
virReportError(errType,
|
||||
_("PCI bus is not compatible with the device "
|
||||
"at %s. Device requires hot-plug capability, "
|
||||
"which is not provided by bus %.4x:%.2x"),
|
||||
addrStr, addr->domain, addr->bus);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/* Verify that the address is in bounds for the chosen bus, and
|
||||
* that the bus is of the correct type for the device (via
|
||||
* comparing the flags).
|
||||
*/
|
||||
static bool
|
||||
qemuDomainPCIAddressValidate(virDomainPCIAddressSetPtr addrs,
|
||||
virDevicePCIAddressPtr addr,
|
||||
const char *addrStr,
|
||||
virDomainPCIConnectFlags flags,
|
||||
bool fromConfig)
|
||||
{
|
||||
virDomainPCIAddressBusPtr bus;
|
||||
virErrorNumber errType = (fromConfig
|
||||
? VIR_ERR_XML_ERROR : VIR_ERR_INTERNAL_ERROR);
|
||||
|
||||
if (addrs->nbuses == 0) {
|
||||
virReportError(errType, "%s", _("No PCI buses available"));
|
||||
return false;
|
||||
}
|
||||
if (addr->domain != 0) {
|
||||
virReportError(errType,
|
||||
_("Invalid PCI address %s. "
|
||||
"Only PCI domain 0 is available"),
|
||||
addrStr);
|
||||
return false;
|
||||
}
|
||||
if (addr->bus >= addrs->nbuses) {
|
||||
virReportError(errType,
|
||||
_("Invalid PCI address %s. "
|
||||
"Only PCI buses up to %zu are available"),
|
||||
addrStr, addrs->nbuses - 1);
|
||||
return false;
|
||||
}
|
||||
|
||||
bus = &addrs->buses[addr->bus];
|
||||
|
||||
/* assure that at least one of the requested connection types is
|
||||
* provided by this bus
|
||||
*/
|
||||
if (!qemuDomainPCIAddressFlagsCompatible(addr, addrStr, bus->flags,
|
||||
flags, true, fromConfig))
|
||||
return false;
|
||||
|
||||
/* some "buses" are really just a single port */
|
||||
if (bus->minSlot && addr->slot < bus->minSlot) {
|
||||
virReportError(errType,
|
||||
_("Invalid PCI address %s. slot must be >= %zu"),
|
||||
addrStr, bus->minSlot);
|
||||
return false;
|
||||
}
|
||||
if (addr->slot > bus->maxSlot) {
|
||||
virReportError(errType,
|
||||
_("Invalid PCI address %s. slot must be <= %zu"),
|
||||
addrStr, bus->maxSlot);
|
||||
return false;
|
||||
}
|
||||
if (addr->function > VIR_PCI_ADDRESS_FUNCTION_LAST) {
|
||||
virReportError(errType,
|
||||
_("Invalid PCI address %s. function must be <= %u"),
|
||||
addrStr, VIR_PCI_ADDRESS_FUNCTION_LAST);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
qemuDomainPCIAddressBusSetModel(virDomainPCIAddressBusPtr bus,
|
||||
virDomainControllerModelPCI model)
|
||||
{
|
||||
switch (model) {
|
||||
case VIR_DOMAIN_CONTROLLER_MODEL_PCI_BRIDGE:
|
||||
case VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT:
|
||||
bus->flags = (VIR_PCI_CONNECT_HOTPLUGGABLE |
|
||||
VIR_PCI_CONNECT_TYPE_PCI);
|
||||
bus->minSlot = 1;
|
||||
bus->maxSlot = VIR_PCI_ADDRESS_SLOT_LAST;
|
||||
break;
|
||||
case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT:
|
||||
/* slots 1 - 31, no hotplug, PCIe only unless the address was
|
||||
* specified in user config *and* the particular device being
|
||||
* attached also allows it
|
||||
*/
|
||||
bus->flags = (VIR_PCI_CONNECT_TYPE_PCIE |
|
||||
VIR_PCI_CONNECT_TYPE_EITHER_IF_CONFIG);
|
||||
bus->minSlot = 1;
|
||||
bus->maxSlot = VIR_PCI_ADDRESS_SLOT_LAST;
|
||||
break;
|
||||
case VIR_DOMAIN_CONTROLLER_MODEL_DMI_TO_PCI_BRIDGE:
|
||||
/* slots 1 - 31, standard PCI slots,
|
||||
* but *not* hot-pluggable */
|
||||
bus->flags = VIR_PCI_CONNECT_TYPE_PCI;
|
||||
bus->minSlot = 1;
|
||||
bus->maxSlot = VIR_PCI_ADDRESS_SLOT_LAST;
|
||||
break;
|
||||
default:
|
||||
virReportError(VIR_ERR_INTERNAL_ERROR,
|
||||
_("Invalid PCI controller model %d"), model);
|
||||
return -1;
|
||||
}
|
||||
|
||||
bus->model = model;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Ensure addr fits in the address set, by expanding it if needed.
|
||||
* This will only grow if the flags say that we need a normal
|
||||
* hot-pluggable PCI slot. If we need a different type of slot, it
|
||||
* will fail.
|
||||
*
|
||||
* Return value:
|
||||
* -1 = OOM
|
||||
* 0 = no action performed
|
||||
* >0 = number of buses added
|
||||
*/
|
||||
static int
|
||||
qemuDomainPCIAddressSetGrow(virDomainPCIAddressSetPtr addrs,
|
||||
virDevicePCIAddressPtr addr,
|
||||
virDomainPCIConnectFlags flags)
|
||||
{
|
||||
int add;
|
||||
size_t i;
|
||||
|
||||
add = addr->bus - addrs->nbuses + 1;
|
||||
i = addrs->nbuses;
|
||||
if (add <= 0)
|
||||
return 0;
|
||||
|
||||
/* auto-grow only works when we're adding plain PCI devices */
|
||||
if (!(flags & VIR_PCI_CONNECT_TYPE_PCI)) {
|
||||
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
||||
_("Cannot automatically add a new PCI bus for a "
|
||||
"device requiring a slot other than standard PCI."));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (VIR_EXPAND_N(addrs->buses, addrs->nbuses, add) < 0)
|
||||
return -1;
|
||||
|
||||
for (; i < addrs->nbuses; i++) {
|
||||
/* Any time we auto-add a bus, we will want a multi-slot
|
||||
* bus. Currently the only type of bus we will auto-add is a
|
||||
* pci-bridge, which is hot-pluggable and provides standard
|
||||
* PCI slots.
|
||||
*/
|
||||
qemuDomainPCIAddressBusSetModel(&addrs->buses[i],
|
||||
VIR_DOMAIN_CONTROLLER_MODEL_PCI_BRIDGE);
|
||||
}
|
||||
return add;
|
||||
}
|
||||
|
||||
|
||||
static char *
|
||||
qemuDomainPCIAddressAsString(virDevicePCIAddressPtr addr)
|
||||
{
|
||||
char *str;
|
||||
|
||||
ignore_value(virAsprintf(&str, "%.4x:%.2x:%.2x.%.1x",
|
||||
addr->domain,
|
||||
addr->bus,
|
||||
addr->slot,
|
||||
addr->function));
|
||||
return str;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
qemuCollectPCIAddress(virDomainDefPtr def ATTRIBUTE_UNUSED,
|
||||
virDomainDeviceDefPtr device,
|
||||
@ -1816,8 +1590,8 @@ qemuCollectPCIAddress(virDomainDefPtr def ATTRIBUTE_UNUSED,
|
||||
entireSlot = (addr->function == 0 &&
|
||||
addr->multi != VIR_DEVICE_ADDRESS_PCI_MULTI_ON);
|
||||
|
||||
if (qemuDomainPCIAddressReserveAddr(addrs, addr, flags,
|
||||
entireSlot, true) < 0)
|
||||
if (virDomainPCIAddressReserveAddr(addrs, addr, flags,
|
||||
entireSlot, true) < 0)
|
||||
goto cleanup;
|
||||
|
||||
ret = 0;
|
||||
@ -1872,7 +1646,7 @@ qemuDomainAssignPCIAddresses(virDomainDefPtr def,
|
||||
if (qemuAssignDevicePCISlots(def, qemuCaps, addrs) < 0)
|
||||
goto cleanup;
|
||||
/* Reserve 1 extra slot for a (potential) bridge */
|
||||
if (qemuDomainPCIAddressReserveNextSlot(addrs, &info, flags) < 0)
|
||||
if (virDomainPCIAddressReserveNextSlot(addrs, &info, flags) < 0)
|
||||
goto cleanup;
|
||||
|
||||
for (i = 1; i < addrs->nbuses; i++) {
|
||||
@ -1883,12 +1657,12 @@ qemuDomainAssignPCIAddresses(virDomainDefPtr def,
|
||||
i, bus->model)) < 0)
|
||||
goto cleanup;
|
||||
/* If we added a new bridge, we will need one more address */
|
||||
if (rv > 0 && qemuDomainPCIAddressReserveNextSlot(addrs, &info,
|
||||
flags) < 0)
|
||||
if (rv > 0 && virDomainPCIAddressReserveNextSlot(addrs, &info,
|
||||
flags) < 0)
|
||||
goto cleanup;
|
||||
}
|
||||
nbuses = addrs->nbuses;
|
||||
qemuDomainPCIAddressSetFree(addrs);
|
||||
virDomainPCIAddressSetFree(addrs);
|
||||
addrs = NULL;
|
||||
|
||||
} else if (max_idx > 0) {
|
||||
@ -1911,7 +1685,7 @@ qemuDomainAssignPCIAddresses(virDomainDefPtr def,
|
||||
priv = obj->privateData;
|
||||
if (addrs) {
|
||||
/* if this is the live domain object, we persist the PCI addresses*/
|
||||
qemuDomainPCIAddressSetFree(priv->pciaddrs);
|
||||
virDomainPCIAddressSetFree(priv->pciaddrs);
|
||||
priv->persistentAddrs = 1;
|
||||
priv->pciaddrs = addrs;
|
||||
addrs = NULL;
|
||||
@ -1923,7 +1697,7 @@ qemuDomainAssignPCIAddresses(virDomainDefPtr def,
|
||||
ret = 0;
|
||||
|
||||
cleanup:
|
||||
qemuDomainPCIAddressSetFree(addrs);
|
||||
virDomainPCIAddressSetFree(addrs);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -1958,11 +1732,8 @@ qemuDomainPCIAddressSetCreate(virDomainDefPtr def,
|
||||
virDomainPCIAddressSetPtr addrs;
|
||||
size_t i;
|
||||
|
||||
if (VIR_ALLOC(addrs) < 0)
|
||||
goto error;
|
||||
|
||||
if (VIR_ALLOC_N(addrs->buses, nbuses) < 0)
|
||||
goto error;
|
||||
if ((addrs = virDomainPCIAddressSetAlloc(nbuses)) == NULL)
|
||||
return NULL;
|
||||
|
||||
addrs->nbuses = nbuses;
|
||||
addrs->dryRun = dryRun;
|
||||
@ -1975,11 +1746,11 @@ qemuDomainPCIAddressSetCreate(virDomainDefPtr def,
|
||||
*
|
||||
*/
|
||||
if (nbuses > 0)
|
||||
qemuDomainPCIAddressBusSetModel(&addrs->buses[0],
|
||||
VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT);
|
||||
virDomainPCIAddressBusSetModel(&addrs->buses[0],
|
||||
VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT);
|
||||
for (i = 1; i < nbuses; i++) {
|
||||
qemuDomainPCIAddressBusSetModel(&addrs->buses[i],
|
||||
VIR_DOMAIN_CONTROLLER_MODEL_PCI_BRIDGE);
|
||||
virDomainPCIAddressBusSetModel(&addrs->buses[i],
|
||||
VIR_DOMAIN_CONTROLLER_MODEL_PCI_BRIDGE);
|
||||
}
|
||||
|
||||
for (i = 0; i < def->ncontrollers; i++) {
|
||||
@ -1995,8 +1766,8 @@ qemuDomainPCIAddressSetCreate(virDomainDefPtr def,
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (qemuDomainPCIAddressBusSetModel(&addrs->buses[idx],
|
||||
def->controllers[i]->model) < 0)
|
||||
if (virDomainPCIAddressBusSetModel(&addrs->buses[idx],
|
||||
def->controllers[i]->model) < 0)
|
||||
goto error;
|
||||
}
|
||||
|
||||
@ -2006,292 +1777,10 @@ qemuDomainPCIAddressSetCreate(virDomainDefPtr def,
|
||||
return addrs;
|
||||
|
||||
error:
|
||||
qemuDomainPCIAddressSetFree(addrs);
|
||||
virDomainPCIAddressSetFree(addrs);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if the PCI slot is used by another device.
|
||||
*/
|
||||
static bool qemuDomainPCIAddressSlotInUse(virDomainPCIAddressSetPtr addrs,
|
||||
virDevicePCIAddressPtr addr)
|
||||
{
|
||||
return !!addrs->buses[addr->bus].slots[addr->slot];
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Reserve a slot (or just one function) for a device. If
|
||||
* reserveEntireSlot is true, all functions for the slot are reserved,
|
||||
* otherwise only one. If fromConfig is true, the address being
|
||||
* requested came directly from the config and errors should be worded
|
||||
* appropriately. If fromConfig is false, the address was
|
||||
* automatically created by libvirt, so it is an internal error (not
|
||||
* XML).
|
||||
*/
|
||||
int
|
||||
qemuDomainPCIAddressReserveAddr(virDomainPCIAddressSetPtr addrs,
|
||||
virDevicePCIAddressPtr addr,
|
||||
virDomainPCIConnectFlags flags,
|
||||
bool reserveEntireSlot,
|
||||
bool fromConfig)
|
||||
{
|
||||
int ret = -1;
|
||||
char *addrStr = NULL;
|
||||
virDomainPCIAddressBusPtr bus;
|
||||
virErrorNumber errType = (fromConfig
|
||||
? VIR_ERR_XML_ERROR : VIR_ERR_INTERNAL_ERROR);
|
||||
|
||||
if (!(addrStr = qemuDomainPCIAddressAsString(addr)))
|
||||
goto cleanup;
|
||||
|
||||
/* Add an extra bus if necessary */
|
||||
if (addrs->dryRun && qemuDomainPCIAddressSetGrow(addrs, addr, flags) < 0)
|
||||
goto cleanup;
|
||||
/* Check that the requested bus exists, is the correct type, and we
|
||||
* are asking for a valid slot
|
||||
*/
|
||||
if (!qemuDomainPCIAddressValidate(addrs, addr, addrStr, flags, fromConfig))
|
||||
goto cleanup;
|
||||
|
||||
bus = &addrs->buses[addr->bus];
|
||||
|
||||
if (reserveEntireSlot) {
|
||||
if (bus->slots[addr->slot]) {
|
||||
virReportError(errType,
|
||||
_("Attempted double use of PCI slot %s "
|
||||
"(may need \"multifunction='on'\" for "
|
||||
"device on function 0)"), addrStr);
|
||||
goto cleanup;
|
||||
}
|
||||
bus->slots[addr->slot] = 0xFF; /* reserve all functions of slot */
|
||||
VIR_DEBUG("Reserving PCI slot %s (multifunction='off')", addrStr);
|
||||
} else {
|
||||
if (bus->slots[addr->slot] & (1 << addr->function)) {
|
||||
if (addr->function == 0) {
|
||||
virReportError(errType,
|
||||
_("Attempted double use of PCI Address %s"),
|
||||
addrStr);
|
||||
} else {
|
||||
virReportError(errType,
|
||||
_("Attempted double use of PCI Address %s "
|
||||
"(may need \"multifunction='on'\" "
|
||||
"for device on function 0)"), addrStr);
|
||||
}
|
||||
goto cleanup;
|
||||
}
|
||||
bus->slots[addr->slot] |= (1 << addr->function);
|
||||
VIR_DEBUG("Reserving PCI address %s", addrStr);
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
cleanup:
|
||||
VIR_FREE(addrStr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
qemuDomainPCIAddressReserveSlot(virDomainPCIAddressSetPtr addrs,
|
||||
virDevicePCIAddressPtr addr,
|
||||
virDomainPCIConnectFlags flags)
|
||||
{
|
||||
return qemuDomainPCIAddressReserveAddr(addrs, addr, flags, true, false);
|
||||
}
|
||||
|
||||
int qemuDomainPCIAddressEnsureAddr(virDomainPCIAddressSetPtr addrs,
|
||||
virDomainDeviceInfoPtr dev)
|
||||
{
|
||||
int ret = -1;
|
||||
char *addrStr = NULL;
|
||||
/* 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 */
|
||||
virDomainPCIConnectFlags flags = (VIR_PCI_CONNECT_HOTPLUGGABLE |
|
||||
VIR_PCI_CONNECT_TYPE_PCI);
|
||||
|
||||
if (!(addrStr = qemuDomainPCIAddressAsString(&dev->addr.pci)))
|
||||
goto cleanup;
|
||||
|
||||
if (dev->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) {
|
||||
/* We do not support hotplug multi-function PCI device now, so we should
|
||||
* reserve the whole slot. The function of the PCI device must be 0.
|
||||
*/
|
||||
if (dev->addr.pci.function != 0) {
|
||||
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
||||
_("Only PCI device addresses with function=0"
|
||||
" are supported"));
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (!qemuDomainPCIAddressValidate(addrs, &dev->addr.pci,
|
||||
addrStr, flags, true))
|
||||
goto cleanup;
|
||||
|
||||
ret = qemuDomainPCIAddressReserveSlot(addrs, &dev->addr.pci, flags);
|
||||
} else {
|
||||
ret = qemuDomainPCIAddressReserveNextSlot(addrs, dev, flags);
|
||||
}
|
||||
|
||||
cleanup:
|
||||
VIR_FREE(addrStr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int qemuDomainPCIAddressReleaseAddr(virDomainPCIAddressSetPtr addrs,
|
||||
virDevicePCIAddressPtr addr)
|
||||
{
|
||||
addrs->buses[addr->bus].slots[addr->slot] &= ~(1 << addr->function);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
qemuDomainPCIAddressReleaseSlot(virDomainPCIAddressSetPtr addrs,
|
||||
virDevicePCIAddressPtr addr)
|
||||
{
|
||||
/* permit any kind of connection type in validation, since we
|
||||
* already had it, and are giving it back.
|
||||
*/
|
||||
virDomainPCIConnectFlags flags = VIR_PCI_CONNECT_TYPES_MASK;
|
||||
int ret = -1;
|
||||
char *addrStr = NULL;
|
||||
|
||||
if (!(addrStr = qemuDomainPCIAddressAsString(addr)))
|
||||
goto cleanup;
|
||||
|
||||
if (!qemuDomainPCIAddressValidate(addrs, addr, addrStr, flags, false))
|
||||
goto cleanup;
|
||||
|
||||
addrs->buses[addr->bus].slots[addr->slot] = 0;
|
||||
ret = 0;
|
||||
cleanup:
|
||||
VIR_FREE(addrStr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void qemuDomainPCIAddressSetFree(virDomainPCIAddressSetPtr addrs)
|
||||
{
|
||||
if (!addrs)
|
||||
return;
|
||||
|
||||
VIR_FREE(addrs->buses);
|
||||
VIR_FREE(addrs);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
qemuDomainPCIAddressGetNextSlot(virDomainPCIAddressSetPtr addrs,
|
||||
virDevicePCIAddressPtr next_addr,
|
||||
virDomainPCIConnectFlags flags)
|
||||
{
|
||||
/* default to starting the search for a free slot from
|
||||
* 0000:00:00.0
|
||||
*/
|
||||
virDevicePCIAddress a = { 0, 0, 0, 0, false };
|
||||
char *addrStr = NULL;
|
||||
|
||||
/* except if this search is for the exact same type of device as
|
||||
* last time, continue the search from the previous match
|
||||
*/
|
||||
if (flags == addrs->lastFlags)
|
||||
a = addrs->lastaddr;
|
||||
|
||||
if (addrs->nbuses == 0) {
|
||||
virReportError(VIR_ERR_XML_ERROR, "%s", _("No PCI buses available"));
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Start the search at the last used bus and slot */
|
||||
for (a.slot++; a.bus < addrs->nbuses; a.bus++) {
|
||||
if (!(addrStr = qemuDomainPCIAddressAsString(&a)))
|
||||
goto error;
|
||||
if (!qemuDomainPCIAddressFlagsCompatible(&a, addrStr,
|
||||
addrs->buses[a.bus].flags,
|
||||
flags, false, false)) {
|
||||
VIR_FREE(addrStr);
|
||||
VIR_DEBUG("PCI bus %.4x:%.2x is not compatible with the device",
|
||||
a.domain, a.bus);
|
||||
continue;
|
||||
}
|
||||
for (; a.slot <= VIR_PCI_ADDRESS_SLOT_LAST; a.slot++) {
|
||||
if (!qemuDomainPCIAddressSlotInUse(addrs, &a))
|
||||
goto success;
|
||||
|
||||
VIR_DEBUG("PCI slot %.4x:%.2x:%.2x already in use",
|
||||
a.domain, a.bus, a.slot);
|
||||
}
|
||||
a.slot = 1;
|
||||
VIR_FREE(addrStr);
|
||||
}
|
||||
|
||||
/* There were no free slots after the last used one */
|
||||
if (addrs->dryRun) {
|
||||
/* a is already set to the first new bus and slot 1 */
|
||||
if (qemuDomainPCIAddressSetGrow(addrs, &a, flags) < 0)
|
||||
goto error;
|
||||
goto success;
|
||||
} 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++) {
|
||||
addrStr = NULL;
|
||||
if (!(addrStr = qemuDomainPCIAddressAsString(&a)))
|
||||
goto error;
|
||||
if (!qemuDomainPCIAddressFlagsCompatible(&a, addrStr,
|
||||
addrs->buses[a.bus].flags,
|
||||
flags, false, false)) {
|
||||
VIR_DEBUG("PCI bus %.4x:%.2x is not compatible with the device",
|
||||
a.domain, a.bus);
|
||||
continue;
|
||||
}
|
||||
for (a.slot = 1; a.slot <= VIR_PCI_ADDRESS_SLOT_LAST; a.slot++) {
|
||||
if (!qemuDomainPCIAddressSlotInUse(addrs, &a))
|
||||
goto success;
|
||||
|
||||
VIR_DEBUG("PCI slot %.4x:%.2x:%.2x already in use",
|
||||
a.domain, a.bus, a.slot);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
virReportError(VIR_ERR_INTERNAL_ERROR,
|
||||
"%s", _("No more available PCI slots"));
|
||||
error:
|
||||
VIR_FREE(addrStr);
|
||||
return -1;
|
||||
|
||||
success:
|
||||
VIR_DEBUG("Found free PCI slot %.4x:%.2x:%.2x",
|
||||
a.domain, a.bus, a.slot);
|
||||
*next_addr = a;
|
||||
VIR_FREE(addrStr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
qemuDomainPCIAddressReserveNextSlot(virDomainPCIAddressSetPtr addrs,
|
||||
virDomainDeviceInfoPtr dev,
|
||||
virDomainPCIConnectFlags flags)
|
||||
{
|
||||
virDevicePCIAddress addr;
|
||||
if (qemuDomainPCIAddressGetNextSlot(addrs, &addr, flags) < 0)
|
||||
return -1;
|
||||
|
||||
if (qemuDomainPCIAddressReserveSlot(addrs, &addr, flags) < 0)
|
||||
return -1;
|
||||
|
||||
if (!addrs->dryRun) {
|
||||
dev->type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI;
|
||||
dev->addr.pci = addr;
|
||||
}
|
||||
|
||||
addrs->lastaddr = addr;
|
||||
addrs->lastFlags = flags;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
qemuDomainReleaseDeviceAddress(virDomainObjPtr vm,
|
||||
@ -2311,8 +1800,8 @@ qemuDomainReleaseDeviceAddress(virDomainObjPtr vm,
|
||||
NULLSTR(devstr));
|
||||
else if (info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI &&
|
||||
virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE) &&
|
||||
qemuDomainPCIAddressReleaseSlot(priv->pciaddrs,
|
||||
&info->addr.pci) < 0)
|
||||
virDomainPCIAddressReleaseSlot(priv->pciaddrs,
|
||||
&info->addr.pci) < 0)
|
||||
VIR_WARN("Unable to release PCI address on %s",
|
||||
NULLSTR(devstr));
|
||||
}
|
||||
@ -2388,7 +1877,7 @@ qemuValidateDevicePCISlotsPIIX3(virDomainDefPtr def,
|
||||
if (addrs->nbuses) {
|
||||
memset(&tmp_addr, 0, sizeof(tmp_addr));
|
||||
tmp_addr.slot = 1;
|
||||
if (qemuDomainPCIAddressReserveSlot(addrs, &tmp_addr, flags) < 0)
|
||||
if (virDomainPCIAddressReserveSlot(addrs, &tmp_addr, flags) < 0)
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
@ -2404,17 +1893,17 @@ qemuValidateDevicePCISlotsPIIX3(virDomainDefPtr def,
|
||||
memset(&tmp_addr, 0, sizeof(tmp_addr));
|
||||
tmp_addr.slot = 2;
|
||||
|
||||
if (!(addrStr = qemuDomainPCIAddressAsString(&tmp_addr)))
|
||||
if (!(addrStr = virDomainPCIAddressAsString(&tmp_addr)))
|
||||
goto cleanup;
|
||||
if (!qemuDomainPCIAddressValidate(addrs, &tmp_addr,
|
||||
addrStr, flags, false))
|
||||
if (!virDomainPCIAddressValidate(addrs, &tmp_addr,
|
||||
addrStr, flags, false))
|
||||
goto cleanup;
|
||||
|
||||
if (qemuDomainPCIAddressSlotInUse(addrs, &tmp_addr)) {
|
||||
if (virDomainPCIAddressSlotInUse(addrs, &tmp_addr)) {
|
||||
if (qemuDeviceVideoUsable) {
|
||||
if (qemuDomainPCIAddressReserveNextSlot(addrs,
|
||||
&primaryVideo->info,
|
||||
flags) < 0)
|
||||
if (virDomainPCIAddressReserveNextSlot(addrs,
|
||||
&primaryVideo->info,
|
||||
flags) < 0)
|
||||
goto cleanup;
|
||||
} else {
|
||||
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
||||
@ -2423,7 +1912,7 @@ qemuValidateDevicePCISlotsPIIX3(virDomainDefPtr def,
|
||||
goto cleanup;
|
||||
}
|
||||
} else {
|
||||
if (qemuDomainPCIAddressReserveSlot(addrs, &tmp_addr, flags) < 0)
|
||||
if (virDomainPCIAddressReserveSlot(addrs, &tmp_addr, flags) < 0)
|
||||
goto cleanup;
|
||||
primaryVideo->info.addr.pci = tmp_addr;
|
||||
primaryVideo->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI;
|
||||
@ -2444,12 +1933,12 @@ qemuValidateDevicePCISlotsPIIX3(virDomainDefPtr def,
|
||||
memset(&tmp_addr, 0, sizeof(tmp_addr));
|
||||
tmp_addr.slot = 2;
|
||||
|
||||
if (qemuDomainPCIAddressSlotInUse(addrs, &tmp_addr)) {
|
||||
if (virDomainPCIAddressSlotInUse(addrs, &tmp_addr)) {
|
||||
VIR_DEBUG("PCI address 0:0:2.0 in use, future addition of a video"
|
||||
" device will not be possible without manual"
|
||||
" intervention");
|
||||
virResetLastError();
|
||||
} else if (qemuDomainPCIAddressReserveSlot(addrs, &tmp_addr, flags) < 0) {
|
||||
} else if (virDomainPCIAddressReserveSlot(addrs, &tmp_addr, flags) < 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
@ -2527,9 +2016,9 @@ qemuDomainValidateDevicePCISlotsQ35(virDomainDefPtr def,
|
||||
*/
|
||||
memset(&tmp_addr, 0, sizeof(tmp_addr));
|
||||
tmp_addr.slot = 0x1E;
|
||||
if (!qemuDomainPCIAddressSlotInUse(addrs, &tmp_addr)) {
|
||||
if (qemuDomainPCIAddressReserveAddr(addrs, &tmp_addr,
|
||||
flags, true, false) < 0)
|
||||
if (!virDomainPCIAddressSlotInUse(addrs, &tmp_addr)) {
|
||||
if (virDomainPCIAddressReserveAddr(addrs, &tmp_addr,
|
||||
flags, true, false) < 0)
|
||||
goto cleanup;
|
||||
def->controllers[i]->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI;
|
||||
def->controllers[i]->info.addr.pci.domain = 0;
|
||||
@ -2552,13 +2041,13 @@ qemuDomainValidateDevicePCISlotsQ35(virDomainDefPtr def,
|
||||
tmp_addr.slot = 0x1F;
|
||||
tmp_addr.function = 0;
|
||||
tmp_addr.multi = 1;
|
||||
if (qemuDomainPCIAddressReserveAddr(addrs, &tmp_addr, flags,
|
||||
false, false) < 0)
|
||||
if (virDomainPCIAddressReserveAddr(addrs, &tmp_addr, flags,
|
||||
false, false) < 0)
|
||||
goto cleanup;
|
||||
tmp_addr.function = 3;
|
||||
tmp_addr.multi = 0;
|
||||
if (qemuDomainPCIAddressReserveAddr(addrs, &tmp_addr, flags,
|
||||
false, false) < 0)
|
||||
if (virDomainPCIAddressReserveAddr(addrs, &tmp_addr, flags,
|
||||
false, false) < 0)
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
@ -2574,17 +2063,17 @@ qemuDomainValidateDevicePCISlotsQ35(virDomainDefPtr def,
|
||||
memset(&tmp_addr, 0, sizeof(tmp_addr));
|
||||
tmp_addr.slot = 1;
|
||||
|
||||
if (!(addrStr = qemuDomainPCIAddressAsString(&tmp_addr)))
|
||||
if (!(addrStr = virDomainPCIAddressAsString(&tmp_addr)))
|
||||
goto cleanup;
|
||||
if (!qemuDomainPCIAddressValidate(addrs, &tmp_addr,
|
||||
addrStr, flags, false))
|
||||
if (!virDomainPCIAddressValidate(addrs, &tmp_addr,
|
||||
addrStr, flags, false))
|
||||
goto cleanup;
|
||||
|
||||
if (qemuDomainPCIAddressSlotInUse(addrs, &tmp_addr)) {
|
||||
if (virDomainPCIAddressSlotInUse(addrs, &tmp_addr)) {
|
||||
if (qemuDeviceVideoUsable) {
|
||||
if (qemuDomainPCIAddressReserveNextSlot(addrs,
|
||||
&primaryVideo->info,
|
||||
flags) < 0)
|
||||
if (virDomainPCIAddressReserveNextSlot(addrs,
|
||||
&primaryVideo->info,
|
||||
flags) < 0)
|
||||
goto cleanup;
|
||||
} else {
|
||||
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
||||
@ -2593,7 +2082,7 @@ qemuDomainValidateDevicePCISlotsQ35(virDomainDefPtr def,
|
||||
goto cleanup;
|
||||
}
|
||||
} else {
|
||||
if (qemuDomainPCIAddressReserveSlot(addrs, &tmp_addr, flags) < 0)
|
||||
if (virDomainPCIAddressReserveSlot(addrs, &tmp_addr, flags) < 0)
|
||||
goto cleanup;
|
||||
primaryVideo->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI;
|
||||
primaryVideo->info.addr.pci = tmp_addr;
|
||||
@ -2614,12 +2103,12 @@ qemuDomainValidateDevicePCISlotsQ35(virDomainDefPtr def,
|
||||
memset(&tmp_addr, 0, sizeof(tmp_addr));
|
||||
tmp_addr.slot = 1;
|
||||
|
||||
if (qemuDomainPCIAddressSlotInUse(addrs, &tmp_addr)) {
|
||||
if (virDomainPCIAddressSlotInUse(addrs, &tmp_addr)) {
|
||||
VIR_DEBUG("PCI address 0:0:1.0 in use, future addition of a video"
|
||||
" device will not be possible without manual"
|
||||
" intervention");
|
||||
virResetLastError();
|
||||
} else if (qemuDomainPCIAddressReserveSlot(addrs, &tmp_addr, flags) < 0) {
|
||||
} else if (virDomainPCIAddressReserveSlot(addrs, &tmp_addr, flags) < 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
@ -2712,9 +2201,9 @@ qemuAssignDevicePCISlots(virDomainDefPtr def,
|
||||
flags = VIR_PCI_CONNECT_HOTPLUGGABLE | VIR_PCI_CONNECT_TYPE_PCI;
|
||||
break;
|
||||
}
|
||||
if (qemuDomainPCIAddressReserveNextSlot(addrs,
|
||||
&def->controllers[i]->info,
|
||||
flags) < 0)
|
||||
if (virDomainPCIAddressReserveNextSlot(addrs,
|
||||
&def->controllers[i]->info,
|
||||
flags) < 0)
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
@ -2727,8 +2216,8 @@ qemuAssignDevicePCISlots(virDomainDefPtr def,
|
||||
|
||||
/* Only support VirtIO-9p-pci so far. If that changes,
|
||||
* we might need to skip devices here */
|
||||
if (qemuDomainPCIAddressReserveNextSlot(addrs, &def->fss[i]->info,
|
||||
flags) < 0)
|
||||
if (virDomainPCIAddressReserveNextSlot(addrs, &def->fss[i]->info,
|
||||
flags) < 0)
|
||||
goto error;
|
||||
}
|
||||
|
||||
@ -2742,8 +2231,8 @@ qemuAssignDevicePCISlots(virDomainDefPtr def,
|
||||
(def->nets[i]->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE)) {
|
||||
continue;
|
||||
}
|
||||
if (qemuDomainPCIAddressReserveNextSlot(addrs, &def->nets[i]->info,
|
||||
flags) < 0)
|
||||
if (virDomainPCIAddressReserveNextSlot(addrs, &def->nets[i]->info,
|
||||
flags) < 0)
|
||||
goto error;
|
||||
}
|
||||
|
||||
@ -2756,8 +2245,8 @@ qemuAssignDevicePCISlots(virDomainDefPtr def,
|
||||
def->sounds[i]->model == VIR_DOMAIN_SOUND_MODEL_PCSPK)
|
||||
continue;
|
||||
|
||||
if (qemuDomainPCIAddressReserveNextSlot(addrs, &def->sounds[i]->info,
|
||||
flags) < 0)
|
||||
if (virDomainPCIAddressReserveNextSlot(addrs, &def->sounds[i]->info,
|
||||
flags) < 0)
|
||||
goto error;
|
||||
}
|
||||
|
||||
@ -2819,7 +2308,7 @@ qemuAssignDevicePCISlots(virDomainDefPtr def,
|
||||
if (addr.slot == 0) {
|
||||
/* This is the first part of the controller, so need
|
||||
* to find a free slot & then reserve a function */
|
||||
if (qemuDomainPCIAddressGetNextSlot(addrs, &tmp_addr, flags) < 0)
|
||||
if (virDomainPCIAddressGetNextSlot(addrs, &tmp_addr, flags) < 0)
|
||||
goto error;
|
||||
|
||||
addr.bus = tmp_addr.bus;
|
||||
@ -2830,16 +2319,16 @@ qemuAssignDevicePCISlots(virDomainDefPtr def,
|
||||
addrs->lastaddr.multi = 0;
|
||||
}
|
||||
/* Finally we can reserve the slot+function */
|
||||
if (qemuDomainPCIAddressReserveAddr(addrs, &addr, flags,
|
||||
false, false) < 0)
|
||||
if (virDomainPCIAddressReserveAddr(addrs, &addr, flags,
|
||||
false, false) < 0)
|
||||
goto error;
|
||||
|
||||
def->controllers[i]->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI;
|
||||
def->controllers[i]->info.addr.pci = addr;
|
||||
} else {
|
||||
if (qemuDomainPCIAddressReserveNextSlot(addrs,
|
||||
&def->controllers[i]->info,
|
||||
flags) < 0)
|
||||
if (virDomainPCIAddressReserveNextSlot(addrs,
|
||||
&def->controllers[i]->info,
|
||||
flags) < 0)
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
@ -2864,8 +2353,8 @@ qemuAssignDevicePCISlots(virDomainDefPtr def,
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (qemuDomainPCIAddressReserveNextSlot(addrs, &def->disks[i]->info,
|
||||
flags) < 0)
|
||||
if (virDomainPCIAddressReserveNextSlot(addrs, &def->disks[i]->info,
|
||||
flags) < 0)
|
||||
goto error;
|
||||
}
|
||||
|
||||
@ -2877,9 +2366,9 @@ qemuAssignDevicePCISlots(virDomainDefPtr def,
|
||||
def->hostdevs[i]->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI)
|
||||
continue;
|
||||
|
||||
if (qemuDomainPCIAddressReserveNextSlot(addrs,
|
||||
def->hostdevs[i]->info,
|
||||
flags) < 0)
|
||||
if (virDomainPCIAddressReserveNextSlot(addrs,
|
||||
def->hostdevs[i]->info,
|
||||
flags) < 0)
|
||||
goto error;
|
||||
}
|
||||
|
||||
@ -2887,9 +2376,9 @@ qemuAssignDevicePCISlots(virDomainDefPtr def,
|
||||
if (def->memballoon &&
|
||||
def->memballoon->model == VIR_DOMAIN_MEMBALLOON_MODEL_VIRTIO &&
|
||||
def->memballoon->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE) {
|
||||
if (qemuDomainPCIAddressReserveNextSlot(addrs,
|
||||
&def->memballoon->info,
|
||||
flags) < 0)
|
||||
if (virDomainPCIAddressReserveNextSlot(addrs,
|
||||
&def->memballoon->info,
|
||||
flags) < 0)
|
||||
goto error;
|
||||
}
|
||||
|
||||
@ -2897,8 +2386,8 @@ qemuAssignDevicePCISlots(virDomainDefPtr def,
|
||||
if (def->rng &&
|
||||
def->rng->model == VIR_DOMAIN_RNG_MODEL_VIRTIO &&
|
||||
def->rng->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE) {
|
||||
if (qemuDomainPCIAddressReserveNextSlot(addrs,
|
||||
&def->rng->info, flags) < 0)
|
||||
if (virDomainPCIAddressReserveNextSlot(addrs,
|
||||
&def->rng->info, flags) < 0)
|
||||
goto error;
|
||||
}
|
||||
|
||||
@ -2906,8 +2395,8 @@ qemuAssignDevicePCISlots(virDomainDefPtr def,
|
||||
if (def->watchdog &&
|
||||
def->watchdog->model != VIR_DOMAIN_WATCHDOG_MODEL_IB700 &&
|
||||
def->watchdog->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE) {
|
||||
if (qemuDomainPCIAddressReserveNextSlot(addrs, &def->watchdog->info,
|
||||
flags) < 0)
|
||||
if (virDomainPCIAddressReserveNextSlot(addrs, &def->watchdog->info,
|
||||
flags) < 0)
|
||||
goto error;
|
||||
}
|
||||
|
||||
@ -2915,8 +2404,8 @@ qemuAssignDevicePCISlots(virDomainDefPtr def,
|
||||
* assigned address. */
|
||||
if (def->nvideos > 0 &&
|
||||
def->videos[0]->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE) {
|
||||
if (qemuDomainPCIAddressReserveNextSlot(addrs, &def->videos[0]->info,
|
||||
flags) < 0)
|
||||
if (virDomainPCIAddressReserveNextSlot(addrs, &def->videos[0]->info,
|
||||
flags) < 0)
|
||||
goto error;
|
||||
}
|
||||
/* Further non-primary video cards which have to be qxl type */
|
||||
@ -2928,8 +2417,8 @@ qemuAssignDevicePCISlots(virDomainDefPtr def,
|
||||
}
|
||||
if (def->videos[i]->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE)
|
||||
continue;
|
||||
if (qemuDomainPCIAddressReserveNextSlot(addrs, &def->videos[i]->info,
|
||||
flags) < 0)
|
||||
if (virDomainPCIAddressReserveNextSlot(addrs, &def->videos[i]->info,
|
||||
flags) < 0)
|
||||
goto error;
|
||||
}
|
||||
for (i = 0; i < def->ninputs; i++) {
|
||||
@ -2976,7 +2465,7 @@ qemuBuildDeviceAddressStr(virBufferPtr buf,
|
||||
const char *contAlias = NULL;
|
||||
size_t i;
|
||||
|
||||
if (!(devStr = qemuDomainPCIAddressAsString(&info->addr.pci)))
|
||||
if (!(devStr = virDomainPCIAddressAsString(&info->addr.pci)))
|
||||
goto cleanup;
|
||||
for (i = 0; i < domainDef->ncontrollers; i++) {
|
||||
virDomainControllerDefPtr cont = domainDef->controllers[i];
|
||||
|
@ -242,23 +242,7 @@ int qemuDomainAssignPCIAddresses(virDomainDefPtr def,
|
||||
virDomainPCIAddressSetPtr qemuDomainPCIAddressSetCreate(virDomainDefPtr def,
|
||||
unsigned int nbuses,
|
||||
bool dryRun);
|
||||
int qemuDomainPCIAddressReserveSlot(virDomainPCIAddressSetPtr addrs,
|
||||
virDevicePCIAddressPtr addr,
|
||||
virDomainPCIConnectFlags flags);
|
||||
int qemuDomainPCIAddressReserveAddr(virDomainPCIAddressSetPtr addrs,
|
||||
virDevicePCIAddressPtr addr,
|
||||
virDomainPCIConnectFlags flags,
|
||||
bool reserveEntireSlot,
|
||||
bool fromConfig);
|
||||
int qemuDomainPCIAddressReserveNextSlot(virDomainPCIAddressSetPtr addrs,
|
||||
virDomainDeviceInfoPtr dev,
|
||||
virDomainPCIConnectFlags flags);
|
||||
int qemuDomainPCIAddressEnsureAddr(virDomainPCIAddressSetPtr addrs,
|
||||
virDomainDeviceInfoPtr dev);
|
||||
int qemuDomainPCIAddressReleaseAddr(virDomainPCIAddressSetPtr addrs,
|
||||
virDevicePCIAddressPtr addr);
|
||||
|
||||
void qemuDomainPCIAddressSetFree(virDomainPCIAddressSetPtr addrs);
|
||||
int qemuAssignDevicePCISlots(virDomainDefPtr def,
|
||||
virQEMUCapsPtr qemuCaps,
|
||||
virDomainPCIAddressSetPtr addrs);
|
||||
|
@ -34,6 +34,7 @@
|
||||
#include "cpu/cpu.h"
|
||||
#include "viruuid.h"
|
||||
#include "virfile.h"
|
||||
#include "domain_addr.h"
|
||||
#include "domain_event.h"
|
||||
#include "virtime.h"
|
||||
#include "virstoragefile.h"
|
||||
@ -245,7 +246,7 @@ qemuDomainObjPrivateFree(void *data)
|
||||
virObjectUnref(priv->qemuCaps);
|
||||
|
||||
virCgroupFree(&priv->cgroup);
|
||||
qemuDomainPCIAddressSetFree(priv->pciaddrs);
|
||||
virDomainPCIAddressSetFree(priv->pciaddrs);
|
||||
qemuDomainCCWAddressSetFree(priv->ccwaddrs);
|
||||
virDomainChrSourceDefFree(priv->monConfig);
|
||||
qemuDomainObjFreeJob(priv);
|
||||
|
@ -284,7 +284,7 @@ qemuDomainAttachVirtioDiskDevice(virConnectPtr conn,
|
||||
goto error;
|
||||
} else if (!disk->info.type ||
|
||||
disk->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) {
|
||||
if (qemuDomainPCIAddressEnsureAddr(priv->pciaddrs, &disk->info) < 0)
|
||||
if (virDomainPCIAddressEnsureAddr(priv->pciaddrs, &disk->info) < 0)
|
||||
goto error;
|
||||
}
|
||||
releaseaddr = true;
|
||||
@ -386,7 +386,7 @@ int qemuDomainAttachControllerDevice(virQEMUDriverPtr driver,
|
||||
|
||||
if (controller->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE ||
|
||||
controller->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) {
|
||||
if (qemuDomainPCIAddressEnsureAddr(priv->pciaddrs, &controller->info) < 0)
|
||||
if (virDomainPCIAddressEnsureAddr(priv->pciaddrs, &controller->info) < 0)
|
||||
goto cleanup;
|
||||
} else if (controller->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCW) {
|
||||
if (qemuDomainCCWAddressAssign(&controller->info, priv->ccwaddrs,
|
||||
@ -940,7 +940,7 @@ int qemuDomainAttachNetDevice(virConnectPtr conn,
|
||||
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
||||
_("virtio-s390 net device cannot be hotplugged."));
|
||||
else if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE) &&
|
||||
qemuDomainPCIAddressEnsureAddr(priv->pciaddrs, &net->info) < 0)
|
||||
virDomainPCIAddressEnsureAddr(priv->pciaddrs, &net->info) < 0)
|
||||
goto cleanup;
|
||||
|
||||
releaseaddr = true;
|
||||
@ -1230,7 +1230,7 @@ qemuDomainAttachHostPCIDevice(virQEMUDriverPtr driver,
|
||||
if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE)) {
|
||||
if (qemuAssignDeviceHostdevAlias(vm->def, hostdev, -1) < 0)
|
||||
goto error;
|
||||
if (qemuDomainPCIAddressEnsureAddr(priv->pciaddrs, hostdev->info) < 0)
|
||||
if (virDomainPCIAddressEnsureAddr(priv->pciaddrs, hostdev->info) < 0)
|
||||
goto error;
|
||||
releaseaddr = true;
|
||||
if (backend != VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO &&
|
||||
|
@ -4390,7 +4390,7 @@ void qemuProcessStop(virQEMUDriverPtr driver,
|
||||
virDomainDefClearDeviceAliases(vm->def);
|
||||
if (!priv->persistentAddrs) {
|
||||
virDomainDefClearPCIAddresses(vm->def);
|
||||
qemuDomainPCIAddressSetFree(priv->pciaddrs);
|
||||
virDomainPCIAddressSetFree(priv->pciaddrs);
|
||||
priv->pciaddrs = NULL;
|
||||
virDomainDefClearCCWAddresses(vm->def);
|
||||
qemuDomainCCWAddressSetFree(priv->ccwaddrs);
|
||||
|
Loading…
x
Reference in New Issue
Block a user