/* Private flags used internally by virDomainSaveStatus and
* virDomainLoadStatus. */
typedef enum {
- VIR_DOMAIN_XML_INTERNAL_STATUS = (1<<16), /* dump internal domain status information */
- VIR_DOMAIN_XML_INTERNAL_ACTUAL_NET = (1<<17), /* dump/parse <actual> element */
+ /* dump internal domain status information */
+ VIR_DOMAIN_XML_INTERNAL_STATUS = (1<<16),
+ /* dump/parse <actual> element */
+ VIR_DOMAIN_XML_INTERNAL_ACTUAL_NET = (1<<17),
+ /* dump/parse original states of host PCI device */
+ VIR_DOMAIN_XML_INTERNAL_PCI_ORIG_STATES = (1<<18),
} virDomainXMLInternalFlags;
VIR_ENUM_IMPL(virDomainTaint, VIR_DOMAIN_TAINT_LAST,
return ret;
}
+/* The internal XML for host PCI device's original states:
+ *
+ * <origstates>
+ * <unbind/>
+ * <removeslot/>
+ * <reprobe/>
+ * </origstates>
+ */
+static int
+virDomainHostdevSubsysPciOrigStatesDefParseXML(const xmlNodePtr node,
+ virDomainHostdevOrigStatesPtr def)
+{
+ xmlNodePtr cur;
+ cur = node->children;
+
+ while (cur != NULL) {
+ if (cur->type == XML_ELEMENT_NODE) {
+ if (xmlStrEqual(cur->name, BAD_CAST "unbind")) {
+ def->states.pci.unbind_from_stub = 1;
+ } else if (xmlStrEqual(cur->name, BAD_CAST "removeslot")) {
+ def->states.pci.remove_slot = 1;
+ } else if (xmlStrEqual(cur->name, BAD_CAST "reprobe")) {
+ def->states.pci.reprobe = 1;
+ } else {
+ virDomainReportError(VIR_ERR_INTERNAL_ERROR,
+ _("unsupported element '%s' of 'origstates'"),
+ cur->name);
+ return -1;
+ }
+ }
+ cur = cur->next;
+ }
+
+ return 0;
+}
static int
virDomainHostdevSubsysPciDefParseXML(const xmlNodePtr node,
virDomainHostdevDefPtr def,
unsigned int flags)
{
-
int ret = -1;
xmlNodePtr cur;
goto out;
}
def->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI;
+ } else if ((flags & VIR_DOMAIN_XML_INTERNAL_PCI_ORIG_STATES) &&
+ xmlStrEqual(cur->name, BAD_CAST "origstates")) {
+ virDomainHostdevOrigStatesPtr states = &def->origstates;
+ if (virDomainHostdevSubsysPciOrigStatesDefParseXML(cur, states) < 0)
+ goto out;
} else {
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
_("unknown pci source type '%s'"),
}
type = virDomainHostdevSubsysTypeToString(def->source.subsys.type);
- if (!type || (def->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB && def->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI) ) {
+ if (!type ||
+ (def->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB &&
+ def->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI)) {
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
_("unexpected hostdev type %d"),
def->source.subsys.type);
def->source.subsys.u.pci.bus,
def->source.subsys.u.pci.slot,
def->source.subsys.u.pci.function);
+
+ if ((flags & VIR_DOMAIN_XML_INTERNAL_PCI_ORIG_STATES) &&
+ (def->origstates.states.pci.unbind_from_stub ||
+ def->origstates.states.pci.remove_slot ||
+ def->origstates.states.pci.reprobe)) {
+ virBufferAddLit(buf, " <origstates>\n");
+ if (def->origstates.states.pci.unbind_from_stub)
+ virBufferAddLit(buf, " <unbind/>\n");
+ if (def->origstates.states.pci.remove_slot)
+ virBufferAddLit(buf, " <removeslot/>\n");
+ if (def->origstates.states.pci.reprobe)
+ virBufferAddLit(buf, " <reprobe/>\n");
+ virBufferAddLit(buf, " </origstates>\n");
+ }
}
virBufferAddLit(buf, " </source>\n");
VIR_DOMAIN_XML_UPDATE_CPU)
verify(((VIR_DOMAIN_XML_INTERNAL_STATUS |
- VIR_DOMAIN_XML_INTERNAL_ACTUAL_NET)
+ VIR_DOMAIN_XML_INTERNAL_ACTUAL_NET |
+ VIR_DOMAIN_XML_INTERNAL_PCI_ORIG_STATES)
& DUMPXML_FLAGS) == 0);
/* This internal version can accept VIR_DOMAIN_XML_INTERNAL_*,
virCheckFlags(DUMPXML_FLAGS |
VIR_DOMAIN_XML_INTERNAL_STATUS |
- VIR_DOMAIN_XML_INTERNAL_ACTUAL_NET,
+ VIR_DOMAIN_XML_INTERNAL_ACTUAL_NET |
+ VIR_DOMAIN_XML_INTERNAL_PCI_ORIG_STATES,
-1);
if (!(type = virDomainVirtTypeToString(def->virtType))) {
{
unsigned int flags = (VIR_DOMAIN_XML_SECURE |
VIR_DOMAIN_XML_INTERNAL_STATUS |
- VIR_DOMAIN_XML_INTERNAL_ACTUAL_NET);
+ VIR_DOMAIN_XML_INTERNAL_ACTUAL_NET |
+ VIR_DOMAIN_XML_INTERNAL_PCI_ORIG_STATES);
int ret = -1;
char *xml;
if (!(obj = virDomainObjParseFile(caps, statusFile, expectedVirtTypes,
VIR_DOMAIN_XML_INTERNAL_STATUS |
- VIR_DOMAIN_XML_INTERNAL_ACTUAL_NET)))
+ VIR_DOMAIN_XML_INTERNAL_ACTUAL_NET |
+ VIR_DOMAIN_XML_INTERNAL_PCI_ORIG_STATES)))
goto error;
virUUIDFormat(obj->def->uuid, uuidstr);
} master;
};
+typedef struct _virDomainHostdevOrigStates virDomainHostdevOrigStates;
+typedef virDomainHostdevOrigStates *virDomainHostdevOrigStatesPtr;
+struct _virDomainHostdevOrigStates {
+ union {
+ struct {
+ /* Does the device need to unbind from stub when
+ * reattaching to host?
+ */
+ unsigned int unbind_from_stub : 1;
+
+ /* Does it need to use remove_slot when reattaching
+ * the device to host?
+ */
+ unsigned int remove_slot : 1;
+
+ /* Does it need to reprobe driver for the device when
+ * reattaching to host?
+ */
+ unsigned int reprobe :1;
+ } pci;
+
+ /* Perhaps 'usb' in future */
+ } states;
+};
+
typedef struct _virDomainLeaseDef virDomainLeaseDef;
typedef virDomainLeaseDef *virDomainLeaseDefPtr;
struct _virDomainLeaseDef {
int bootIndex;
virDomainDeviceInfo info; /* Guest address */
int rombar; /* enum virDomainPciRombarMode */
+ virDomainHostdevOrigStates origstates;
};
enum virDomainRedirdevBus {
pciDeviceFileIterate;
pciDeviceGetManaged;
pciDeviceGetName;
+pciDeviceGetRemoveSlot;
+pciDeviceGetReprobe;
+pciDeviceGetUnbindFromStub;
pciDeviceGetUsedBy;
pciDeviceIsAssignable;
pciDeviceIsVirtualFunction;
pciDeviceNetName;
pciDeviceReAttachInit;
pciDeviceSetManaged;
+pciDeviceSetRemoveSlot;
+pciDeviceSetReprobe;
+pciDeviceSetUnbindFromStub;
pciDeviceSetUsedBy;
pciFreeDevice;
pciGetDevice;
int qemuUpdateActivePciHostdevs(struct qemud_driver *driver,
virDomainDefPtr def)
{
- pciDeviceList *pcidevs;
- int ret = -1;
+ virDomainHostdevDefPtr hostdev = NULL;
+ int i;
if (!def->nhostdevs)
return 0;
- if (!(pcidevs = qemuGetPciHostDeviceList(def->hostdevs, def->nhostdevs)))
- return -1;
+ 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);
- while (pciDeviceListCount(pcidevs) > 0) {
- pciDevice *dev = pciDeviceListGet(pcidevs, 0);
- pciDeviceListSteal(pcidevs, dev);
if (pciDeviceListAdd(driver->activePciHostdevs, dev) < 0) {
pciFreeDevice(dev);
- goto cleanup;
+ return -1;
}
}
- ret = 0;
-
-cleanup:
- pciDeviceListFree(pcidevs);
- return ret;
+ return 0;
}
-
-
int qemuPrepareHostdevPCIDevices(struct qemud_driver *driver,
const char *name,
virDomainHostdevDefPtr *hostdevs,
if (!(pcidevs = qemuGetPciHostDeviceList(hostdevs, nhostdevs)))
return -1;
- /* We have to use 6 loops here. *All* devices must
+ /* We have to use 7 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
pciDeviceSetUsedBy(activeDev, name);
}
- /* Loop 6: Now steal all the devices from pcidevs */
+ /* Loop 6: 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 7: Now steal all the devices from pcidevs */
while (pciDeviceListCount(pcidevs) > 0) {
pciDevice *dev = pciDeviceListGet(pcidevs, 0);
pciDeviceListSteal(pcidevs, dev);
return dev->managed;
}
+unsigned
+pciDeviceGetUnbindFromStub(pciDevice *dev)
+{
+ return dev->unbind_from_stub;
+}
+
+void
+pciDeviceSetUnbindFromStub(pciDevice *dev, unsigned unbind)
+{
+ dev->unbind_from_stub = !!unbind;
+}
+
+unsigned
+pciDeviceGetRemoveSlot(pciDevice *dev)
+{
+ return dev->remove_slot;
+}
+
+void
+pciDeviceSetRemoveSlot(pciDevice *dev, unsigned remove_slot)
+{
+ dev->remove_slot = !!remove_slot;
+}
+
+unsigned
+pciDeviceGetReprobe(pciDevice *dev)
+{
+ return dev->reprobe;
+}
+
+void
+pciDeviceSetReprobe(pciDevice *dev, unsigned reprobe)
+{
+ dev->reprobe = !!reprobe;
+}
+
void
pciDeviceSetUsedBy(pciDevice *dev, const char *name)
{
void pciDeviceSetUsedBy(pciDevice *dev,
const char *used_by);
const char *pciDeviceGetUsedBy(pciDevice *dev);
+unsigned pciDeviceGetUnbindFromStub(pciDevice *dev);
+void pciDeviceSetUnbindFromStub(pciDevice *dev,
+ unsigned unbind);
+unsigned pciDeviceGetRemoveSlot(pciDevice *dev);
+void pciDeviceSetRemoveSlot(pciDevice *dev,
+ unsigned remove_slot);
+unsigned pciDeviceGetReprobe(pciDevice *dev);
+void pciDeviceSetReprobe(pciDevice *dev,
+ unsigned reprobe);
void pciDeviceReAttachInit(pciDevice *dev);
pciDeviceList *pciDeviceListNew (void);