int qemuUpdateActivePciHostdevs(struct qemud_driver *driver, virDomainDefPtr def) { virDomainHostdevDefPtr hostdev = NULL; int i; if (!def->nhostdevs) return 0; for (i = 0; i < def->nhostdevs; i++) { pciDevice *dev = NULL; hostdev = def->hostdevs[i]; if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) continue; if (hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI) continue; dev = pciGetDevice(hostdev->source.subsys.u.pci.domain, hostdev->source.subsys.u.pci.bus, hostdev->source.subsys.u.pci.slot, hostdev->source.subsys.u.pci.function); if (!dev) return -1; pciDeviceSetManaged(dev, hostdev->managed); pciDeviceSetUsedBy(dev, def->name); /* Setup the original states for the PCI device */ pciDeviceSetUnbindFromStub(dev, hostdev->origstates.states.pci.unbind_from_stub); pciDeviceSetRemoveSlot(dev, hostdev->origstates.states.pci.remove_slot); pciDeviceSetReprobe(dev, hostdev->origstates.states.pci.reprobe); if (pciDeviceListAdd(driver->activePciHostdevs, dev) < 0) { pciFreeDevice(dev); return -1; } } return 0; }
int qemuPrepareHostdevPCIDevices(struct qemud_driver *driver, const char *name, const unsigned char *uuid, virDomainHostdevDefPtr *hostdevs, int nhostdevs) { pciDeviceList *pcidevs; int last_processed_hostdev_vf = -1; int i; int ret = -1; if (!(pcidevs = qemuGetPciHostDeviceList(hostdevs, nhostdevs))) return -1; /* We have to use 9 loops here. *All* devices must * be detached before we reset any of them, because * in some cases you have to reset the whole PCI, * which impacts all devices on it. Also, all devices * must be reset before being marked as active. */ /* Loop 1: validate that non-managed device isn't in use, eg * by checking that device is either un-bound, or bound * to pci-stub.ko */ for (i = 0; i < pciDeviceListCount(pcidevs); i++) { pciDevice *dev = pciDeviceListGet(pcidevs, i); pciDevice *other; if (!pciDeviceIsAssignable(dev, !driver->relaxedACS)) { virReportError(VIR_ERR_OPERATION_INVALID, _("PCI device %s is not assignable"), pciDeviceGetName(dev)); goto cleanup; } /* The device is in use by other active domain if * the dev is in list driver->activePciHostdevs. */ if ((other = pciDeviceListFind(driver->activePciHostdevs, dev))) { const char *other_name = pciDeviceGetUsedBy(other); if (other_name) virReportError(VIR_ERR_OPERATION_INVALID, _("PCI device %s is in use by domain %s"), pciDeviceGetName(dev), other_name); else virReportError(VIR_ERR_OPERATION_INVALID, _("PCI device %s is already in use"), pciDeviceGetName(dev)); goto cleanup; } } /* Loop 2: detach managed devices */ for (i = 0; i < pciDeviceListCount(pcidevs); i++) { pciDevice *dev = pciDeviceListGet(pcidevs, i); if (pciDeviceGetManaged(dev) && pciDettachDevice(dev, driver->activePciHostdevs, NULL) < 0) goto reattachdevs; } /* Loop 3: Now that all the PCI hostdevs have been detached, we * can safely reset them */ for (i = 0; i < pciDeviceListCount(pcidevs); i++) { pciDevice *dev = pciDeviceListGet(pcidevs, i); if (pciResetDevice(dev, driver->activePciHostdevs, driver->inactivePciHostdevs) < 0) goto reattachdevs; } /* Loop 4: For SRIOV network devices, Now that we have detached the * the network device, set the netdev config */ for (i = 0; i < nhostdevs; i++) { virDomainHostdevDefPtr hostdev = hostdevs[i]; if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) continue; if (hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI) continue; if (hostdev->parent.type == VIR_DOMAIN_DEVICE_NET && hostdev->parent.data.net) { if (qemuDomainHostdevNetConfigReplace(hostdev, uuid, driver->stateDir) < 0) { goto resetvfnetconfig; } } last_processed_hostdev_vf = i; } /* Loop 5: Now mark all the devices as active */ for (i = 0; i < pciDeviceListCount(pcidevs); i++) { pciDevice *dev = pciDeviceListGet(pcidevs, i); if (pciDeviceListAdd(driver->activePciHostdevs, dev) < 0) goto inactivedevs; } /* Loop 6: Now remove the devices from inactive list. */ for (i = 0; i < pciDeviceListCount(pcidevs); i++) { pciDevice *dev = pciDeviceListGet(pcidevs, i); pciDeviceListDel(driver->inactivePciHostdevs, dev); } /* Loop 7: Now set the used_by_domain of the device in * driver->activePciHostdevs as domain name. */ for (i = 0; i < pciDeviceListCount(pcidevs); i++) { pciDevice *dev, *activeDev; dev = pciDeviceListGet(pcidevs, i); activeDev = pciDeviceListFind(driver->activePciHostdevs, dev); pciDeviceSetUsedBy(activeDev, name); } /* Loop 8: Now set the original states for hostdev def */ for (i = 0; i < nhostdevs; i++) { pciDevice *dev; pciDevice *pcidev; virDomainHostdevDefPtr hostdev = hostdevs[i]; if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) continue; if (hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI) continue; dev = pciGetDevice(hostdev->source.subsys.u.pci.domain, hostdev->source.subsys.u.pci.bus, hostdev->source.subsys.u.pci.slot, hostdev->source.subsys.u.pci.function); /* original states "unbind_from_stub", "remove_slot", * "reprobe" were already set by pciDettachDevice in * loop 2. */ if ((pcidev = pciDeviceListFind(pcidevs, dev))) { hostdev->origstates.states.pci.unbind_from_stub = pciDeviceGetUnbindFromStub(pcidev); hostdev->origstates.states.pci.remove_slot = pciDeviceGetRemoveSlot(pcidev); hostdev->origstates.states.pci.reprobe = pciDeviceGetReprobe(pcidev); } pciFreeDevice(dev); } /* Loop 9: Now steal all the devices from pcidevs */ while (pciDeviceListCount(pcidevs) > 0) pciDeviceListStealIndex(pcidevs, 0); ret = 0; goto cleanup; inactivedevs: /* Only steal all the devices from driver->activePciHostdevs. We will * free them in pciDeviceListFree(). */ while (pciDeviceListCount(pcidevs) > 0) { pciDevice *dev = pciDeviceListGet(pcidevs, 0); pciDeviceListSteal(driver->activePciHostdevs, dev); } resetvfnetconfig: for (i = 0; i < last_processed_hostdev_vf; i++) { virDomainHostdevDefPtr hostdev = hostdevs[i]; if (hostdev->parent.type == VIR_DOMAIN_DEVICE_NET && hostdev->parent.data.net) { qemuDomainHostdevNetConfigRestore(hostdev, driver->stateDir); } } reattachdevs: for (i = 0; i < pciDeviceListCount(pcidevs); i++) { pciDevice *dev = pciDeviceListGet(pcidevs, i); pciReAttachDevice(dev, driver->activePciHostdevs, NULL); } cleanup: pciDeviceListFree(pcidevs); return ret; }
int qemuPrepareHostdevPCIDevices(struct qemud_driver *driver, const char *name, virDomainHostdevDefPtr *hostdevs, int nhostdevs) { pciDeviceList *pcidevs; int i; int ret = -1; if (!(pcidevs = qemuGetPciHostDeviceList(hostdevs, nhostdevs))) return -1; /* We have to use 6 loops here. *All* devices must * be detached before we reset any of them, because * in some cases you have to reset the whole PCI, * which impacts all devices on it. Also, all devices * must be reset before being marked as active. */ /* Loop 1: validate that non-managed device isn't in use, eg * by checking that device is either un-bound, or bound * to pci-stub.ko */ for (i = 0; i < pciDeviceListCount(pcidevs); i++) { pciDevice *dev = pciDeviceListGet(pcidevs, i); pciDevice *other; if (!pciDeviceIsAssignable(dev, !driver->relaxedACS)) { qemuReportError(VIR_ERR_OPERATION_INVALID, _("PCI device %s is not assignable"), pciDeviceGetName(dev)); goto cleanup; } /* The device is in use by other active domain if * the dev is in list driver->activePciHostdevs. */ if ((other = pciDeviceListFind(driver->activePciHostdevs, dev))) { const char *other_name = pciDeviceGetUsedBy(other); if (other_name) qemuReportError(VIR_ERR_OPERATION_INVALID, _("PCI device %s is in use by domain %s"), pciDeviceGetName(dev), other_name); else qemuReportError(VIR_ERR_OPERATION_INVALID, _("PCI device %s is already in use"), pciDeviceGetName(dev)); goto cleanup; } } /* Loop 2: detach managed devices */ for (i = 0; i < pciDeviceListCount(pcidevs); i++) { pciDevice *dev = pciDeviceListGet(pcidevs, i); if (pciDeviceGetManaged(dev) && pciDettachDevice(dev, driver->activePciHostdevs) < 0) goto reattachdevs; } /* Loop 3: Now that all the PCI hostdevs have been detached, we * can safely reset them */ for (i = 0; i < pciDeviceListCount(pcidevs); i++) { pciDevice *dev = pciDeviceListGet(pcidevs, i); if (pciResetDevice(dev, driver->activePciHostdevs, pcidevs) < 0) goto reattachdevs; } /* Loop 4: Now mark all the devices as active */ for (i = 0; i < pciDeviceListCount(pcidevs); i++) { pciDevice *dev = pciDeviceListGet(pcidevs, i); if (pciDeviceListAdd(driver->activePciHostdevs, dev) < 0) { pciFreeDevice(dev); goto inactivedevs; } } /* Loop 5: Now set the used_by_domain of the device in * driver->activePciHostdevs as domain name. */ for (i = 0; i < pciDeviceListCount(pcidevs); i++) { pciDevice *dev, *activeDev; dev = pciDeviceListGet(pcidevs, i); activeDev = pciDeviceListFind(driver->activePciHostdevs, dev); pciDeviceSetUsedBy(activeDev, name); } /* Loop 6: Now steal all the devices from pcidevs */ while (pciDeviceListCount(pcidevs) > 0) { pciDevice *dev = pciDeviceListGet(pcidevs, 0); pciDeviceListSteal(pcidevs, dev); } ret = 0; goto cleanup; inactivedevs: /* Only steal all the devices from driver->activePciHostdevs. We will * free them in pciDeviceListFree(). */ while (pciDeviceListCount(pcidevs) > 0) { pciDevice *dev = pciDeviceListGet(pcidevs, 0); pciDeviceListSteal(driver->activePciHostdevs, dev); } reattachdevs: for (i = 0; i < pciDeviceListCount(pcidevs); i++) { pciDevice *dev = pciDeviceListGet(pcidevs, i); pciReAttachDevice(dev, driver->activePciHostdevs); } cleanup: pciDeviceListFree(pcidevs); return ret; }