pciWrite(dev, pos, &buf[0], sizeof(buf));
}
-typedef int (*pciIterPredicate)(virConnectPtr,
- virDomainObjPtr,
- pciDevice *,
- pciResetCheckFunc,
- pciDevice *);
+typedef int (*pciIterPredicate)(pciDevice *, pciDevice *);
/* Iterate over available PCI devices calling @predicate
* to compare each one to @dev.
*/
static int
pciIterDevices(virConnectPtr conn,
- virDomainObjPtr vm,
pciIterPredicate predicate,
pciDevice *dev,
- pciResetCheckFunc check,
pciDevice **matched)
{
DIR *dir;
while ((entry = readdir(dir))) {
unsigned domain, bus, slot, function;
- pciDevice *check_dev;
+ pciDevice *try;
/* Ignore '.' and '..' */
if (entry->d_name[0] == '.')
continue;
}
- check_dev = pciGetDevice(conn, domain, bus, slot, function);
- if (!check_dev) {
+ try = pciGetDevice(conn, domain, bus, slot, function);
+ if (!try) {
ret = -1;
break;
}
- if (predicate(conn, vm, dev, check, check_dev)) {
- VIR_DEBUG("%s %s: iter matched on %s", dev->id, dev->name, check_dev->name);
- *matched = check_dev;
+ if (predicate(try, dev)) {
+ VIR_DEBUG("%s %s: iter matched on %s", dev->id, dev->name, try->name);
+ *matched = try;
break;
}
- pciFreeDevice(conn, check_dev);
+ pciFreeDevice(conn, try);
}
closedir(dir);
return ret;
return 0;
}
-/* Check any devices other than the one supplied on the same domain/bus */
+/* Any devices other than the one supplied on the same domain/bus ? */
static int
-pciCheckSharesBus(virConnectPtr conn,
- virDomainObjPtr vm,
- pciDevice *dev,
- pciResetCheckFunc check,
- pciDevice *check_dev)
+pciSharesBus(pciDevice *a, pciDevice *b)
{
- if (check_dev->domain != dev->domain || check_dev->bus != dev->bus)
- return 0;
- if (check_dev->slot == dev->slot && check_dev->function == dev->function)
- return 0;
- if (check(conn, vm, check_dev))
- return 0;
- return 1;
+ return
+ a->domain == b->domain &&
+ a->bus == b->bus &&
+ (a->slot != b->slot ||
+ a->function != b->function);
}
-static pciDevice *
-pciBusCheckOtherDevices(virConnectPtr conn,
- virDomainObjPtr vm,
- pciDevice *dev,
- pciResetCheckFunc check)
+static int
+pciBusContainsOtherDevices(virConnectPtr conn, pciDevice *dev)
{
- pciDevice *conflict = NULL;
- pciIterDevices(conn, vm, pciCheckSharesBus, dev, check, &conflict);
- return conflict;
+ pciDevice *matched = NULL;
+ if (pciIterDevices(conn, pciSharesBus, dev, &matched) < 0)
+ return 1;
+ if (!matched)
+ return 0;
+ pciFreeDevice(conn, matched);
+ return 1;
}
-/* Is @check_dev the parent of @dev ? */
+/* Is @a the parent of @b ? */
static int
-pciIsParent(virConnectPtr conn ATTRIBUTE_UNUSED,
- virDomainObjPtr vm ATTRIBUTE_UNUSED,
- pciDevice *dev,
- pciResetCheckFunc check ATTRIBUTE_UNUSED,
- pciDevice *check_dev)
+pciIsParent(pciDevice *a, pciDevice *b)
{
uint16_t device_class;
uint8_t header_type, secondary, subordinate;
- if (check_dev->domain != dev->domain)
+ if (a->domain != b->domain)
return 0;
/* Is it a bridge? */
- device_class = pciRead16(check_dev, PCI_CLASS_DEVICE);
+ device_class = pciRead16(a, PCI_CLASS_DEVICE);
if (device_class != PCI_CLASS_BRIDGE_PCI)
return 0;
/* Is it a plane? */
- header_type = pciRead8(check_dev, PCI_HEADER_TYPE);
+ header_type = pciRead8(a, PCI_HEADER_TYPE);
if ((header_type & PCI_HEADER_TYPE_MASK) != PCI_HEADER_TYPE_BRIDGE)
return 0;
- secondary = pciRead8(check_dev, PCI_SECONDARY_BUS);
- subordinate = pciRead8(check_dev, PCI_SUBORDINATE_BUS);
+ secondary = pciRead8(a, PCI_SECONDARY_BUS);
+ subordinate = pciRead8(a, PCI_SUBORDINATE_BUS);
- VIR_DEBUG("%s %s: found parent device %s\n",
- dev->id, dev->name, check_dev->name);
+ VIR_DEBUG("%s %s: found parent device %s\n", b->id, b->name, a->name);
/* No, it's superman! */
- return (dev->bus >= secondary && dev->bus <= subordinate);
+ return (b->bus >= secondary && b->bus <= subordinate);
}
static pciDevice *
pciGetParentDevice(virConnectPtr conn, pciDevice *dev)
{
pciDevice *parent = NULL;
- pciIterDevices(conn, NULL, pciIsParent, dev, NULL, &parent);
+ pciIterDevices(conn, pciIsParent, dev, &parent);
return parent;
}
* devices behind a bus.
*/
static int
-pciTrySecondaryBusReset(virConnectPtr conn,
- virDomainObjPtr vm,
- pciDevice *dev,
- pciResetCheckFunc check)
+pciTrySecondaryBusReset(virConnectPtr conn, pciDevice *dev)
{
- pciDevice *parent, *conflict;
+ pciDevice *parent;
uint8_t config_space[PCI_CONF_LEN];
uint16_t ctl;
int ret = -1;
* In future, we could allow it so long as those devices
* are not in use by the host or other guests.
*/
- if ((conflict = pciBusCheckOtherDevices(conn, vm, dev, check))) {
+ if (pciBusContainsOtherDevices(conn, dev)) {
pciReportError(conn, VIR_ERR_NO_SUPPORT,
- _("Unable to reset %s using bus reset as this would cause %s to be reset"),
- dev->name, conflict->name);
- pciFreeDevice(conn, conflict);
+ _("Other devices on bus with %s, not doing bus reset"),
+ dev->name);
return -1;
}
}
int
-pciResetDevice(virConnectPtr conn,
- virDomainObjPtr vm,
- pciDevice *dev,
- pciResetCheckFunc check)
+pciResetDevice(virConnectPtr conn, pciDevice *dev)
{
int ret = -1;
if (!dev->initted && pciInitDevice(conn, dev) < 0)
return -1;
- /* Check that the device isn't owned by a running VM */
- if (!check(conn, vm, dev)) {
- pciReportError(conn, VIR_ERR_NO_SUPPORT,
- _("Unable to reset PCI device %s: device is in use"),
- dev->name);
- return -1;
- }
-
/* KVM will perform FLR when starting and stopping
* a guest, so there is no need for us to do it here.
*/
/* Bus reset is not an option with the root bus */
if (ret < 0 && dev->bus != 0)
- ret = pciTrySecondaryBusReset(conn, vm, dev, check);
+ ret = pciTrySecondaryBusReset(conn, dev);
if (ret < 0) {
virErrorPtr err = virGetLastError();
close(dev->fd);
VIR_FREE(dev);
}
-
-int
-pciDeviceEquals(virConnectPtr conn ATTRIBUTE_UNUSED,
- pciDevice *dev,
- unsigned domain,
- unsigned bus,
- unsigned slot,
- unsigned function)
-{
- return
- dev->domain == domain &&
- dev->bus == bus &&
- dev->slot == slot &&
- dev->function == function;
-}
return -1;
}
-static int
-qemuCheckPciHostDevice(virConnectPtr conn,
- virDomainObjPtr owner_vm,
- pciDevice *dev)
-{
- struct qemud_driver *driver = conn->privateData;
- int ret = 1, i;
-
- for (i = 0; i < driver->domains.count && ret; i++) {
- virDomainObjPtr vm = driver->domains.objs[i];
-
- if (vm == owner_vm)
- continue;
-
- virDomainObjLock(vm);
-
- if (virDomainIsActive(vm)) {
- int j;
-
- for (j = 0; j < vm->def->nhostdevs && ret; j++) {
- virDomainHostdevDefPtr hostdev = vm->def->hostdevs[j];
-
- if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS)
- continue;
- if (hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI)
- continue;
-
- if (pciDeviceEquals(conn, dev,
- hostdev->source.subsys.u.pci.domain,
- hostdev->source.subsys.u.pci.bus,
- hostdev->source.subsys.u.pci.slot,
- hostdev->source.subsys.u.pci.function))
- ret = 0;
- }
- }
-
- virDomainObjUnlock(vm);
- }
-
- return ret;
-}
-
-static int
-qemuPrepareHostDevices(virConnectPtr conn, virDomainObjPtr vm)
-{
- virDomainDefPtr def = vm->def;
+static int qemuPrepareHostDevices(virConnectPtr conn,
+ virDomainDefPtr def) {
int i;
/* We have to use 2 loops here. *All* devices must
if (!dev)
goto error;
- if (pciResetDevice(conn, vm, dev, qemuCheckPciHostDevice) < 0) {
+ if (pciResetDevice(conn, dev) < 0) {
pciFreeDevice(conn, dev);
goto error;
}
}
static void
-qemuDomainReAttachHostDevices(virConnectPtr conn, virDomainObjPtr vm)
+qemuDomainReAttachHostDevices(virConnectPtr conn, virDomainDefPtr def)
{
- virDomainDefPtr def = vm->def;
int i;
/* Again 2 loops; reset all the devices before re-attach */
continue;
}
- if (pciResetDevice(conn, vm, dev, qemuCheckPciHostDevice) < 0) {
+ if (pciResetDevice(conn, dev) < 0) {
virErrorPtr err = virGetLastError();
VIR_ERROR(_("Failed to reset PCI device: %s\n"),
err ? err->message : "");
if (qemuSetupCgroup(conn, driver, vm) < 0)
goto cleanup;
- if (qemuPrepareHostDevices(conn, vm) < 0)
+ if (qemuPrepareHostDevices(conn, vm->def) < 0)
goto cleanup;
if (VIR_ALLOC(vm->monitor_chr) < 0) {
VIR_WARN("Failed to restore all device ownership for %s",
vm->def->name);
- qemuDomainReAttachHostDevices(conn, vm);
+ qemuDomainReAttachHostDevices(conn, vm->def);
retry:
if ((ret = qemuRemoveCgroup(conn, driver, vm)) < 0) {
return -1;
if (pciDettachDevice(conn, pci) < 0 ||
- pciResetDevice(conn, vm, pci, qemuCheckPciHostDevice) < 0) {
+ pciResetDevice(conn, pci) < 0) {
pciFreeDevice(conn, pci);
return -1;
}
static int
qemudNodeDeviceReset (virNodeDevicePtr dev)
{
- struct qemud_driver *driver = dev->conn->privateData;
pciDevice *pci;
unsigned domain, bus, slot, function;
int ret = -1;
if (!pci)
return -1;
- qemuDriverLock(driver);
-
- if (pciResetDevice(dev->conn, NULL, pci, qemuCheckPciHostDevice) < 0)
+ if (pciResetDevice(dev->conn, pci) < 0)
goto out;
ret = 0;
out:
- qemuDriverUnlock(driver);
pciFreeDevice(dev->conn, pci);
return ret;
}