staticbool __read_mostly passthrough;
module_param(passthrough, bool, S_IRUGO);
MODULE_PARM_DESC(passthrough, "Option to specify how to export PCI topology to guest:\n"\ " 0 - (default) Hide the true PCI topology and makes the frontend\n"\ " there is a single PCI bus with only the exported devices on it.\n"\ " For example, a device at 03:05.0 will be re-assigned to 00:00.0\n"\ " while second device at 02:1a.1 will be re-assigned to 00:01.1.\n"\ " 1 - Passthrough provides a real view of the PCI topology to the\n"\ " frontend (for example, a device at 06:01.b will still appear at\n"\ " 06:01.b to the frontend). This is similar to how Xen 2.0.x\n"\ " exposed PCI devices to its driver domains. This may be required\n"\ " for drivers which depend on finding their hardware in certain\n"\ " bus/slot locations.");
staticint xen_pcibk_attach(struct xen_pcibk_device *pdev)
{ int err = 0; int gnt_ref;
evtchn_port_t remote_evtchn; char *magic = NULL;
mutex_lock(&pdev->dev_lock); /* Make sure we only do this setup once */ if (xenbus_read_driver_state(pdev->xdev->nodename) !=
XenbusStateInitialised) goto out;
/* Wait for frontend to state that it has published the configuration */ if (xenbus_read_driver_state(pdev->xdev->otherend) !=
XenbusStateInitialised) goto out;
staticint xen_pcibk_export_device(struct xen_pcibk_device *pdev, int domain, int bus, int slot, int func, int devid)
{ struct pci_dev *dev; int err = 0;
dev_dbg(&pdev->xdev->dev, "exporting dom %x bus %x slot %x func %x\n",
domain, bus, slot, func);
err = xen_pcibk_add_pci_dev(pdev, dev, devid,
xen_pcibk_publish_pci_dev); if (err) goto out;
dev_info(&dev->dev, "registering for %d\n", pdev->xdev->otherend_id); if (xen_register_device_domain_owner(dev,
pdev->xdev->otherend_id) != 0) {
dev_err(&dev->dev, "Stealing ownership from dom%d.\n",
xen_find_device_domain_owner(dev));
xen_unregister_device_domain_owner(dev);
xen_register_device_domain_owner(dev, pdev->xdev->otherend_id);
}
/* TODO: It'd be nice to export a bridge and have all of its children * get exported with it. This may be best done in xend (which will * have to calculate resource usage anyway) but we probably want to * put something in here to ensure that if a bridge gets given to a * driver domain, that all devices under that bridge are not given * to other driver domains (as he who controls the bridge can disable * it and stop the other devices from working).
*/
out: return err;
}
staticint xen_pcibk_remove_device(struct xen_pcibk_device *pdev, int domain, int bus, int slot, int func)
{ int err = 0; struct pci_dev *dev;
dev_dbg(&pdev->xdev->dev, "removing dom %x bus %x slot %x func %x\n",
domain, bus, slot, func);
dev = xen_pcibk_get_pci_dev(pdev, domain, bus, PCI_DEVFN(slot, func)); if (!dev) {
err = -EINVAL;
dev_dbg(&pdev->xdev->dev, "Couldn't locate PCI device " "(%04x:%02x:%02x.%d)! not owned by this domain\n",
domain, bus, slot, func); goto out;
}
dev_dbg(&dev->dev, "unregistering for %d\n", pdev->xdev->otherend_id);
xen_unregister_device_domain_owner(dev);
/* N.B. This ends up calling pcistub_put_pci_dev which ends up
* doing the FLR. */
xen_pcibk_release_pci_dev(pdev, dev, true/* use the lock. */);
out: return err;
}
staticint xen_pcibk_publish_pci_root(struct xen_pcibk_device *pdev, unsignedint domain, unsignedint bus)
{ unsignedint d, b; int i, root_num, len, err; char str[64];
/* Verify that we haven't already published this pci root */ for (i = 0; i < root_num; i++) {
len = snprintf(str, sizeof(str), "root-%d", i); if (unlikely(len >= (sizeof(str) - 1))) {
err = -ENOMEM; goto out;
}
/* TODO: If at some point we implement support for pci * root hot-remove on pcifront side, we'll need to * remove unnecessary xenstore nodes of pci roots here.
*/
break;
default: break;
}
}
if (state != XenbusStateReconfiguring) /* Make sure we only reconfigure once. */ goto out;
err = xenbus_switch_state(pdev->xdev, XenbusStateReconfigured); if (err) {
xenbus_dev_fatal(pdev->xdev, err, "Error switching to reconfigured state!"); goto out;
}
dev_dbg(&xdev->dev, "fe state changed %d\n", fe_state);
switch (fe_state) { case XenbusStateInitialised:
xen_pcibk_attach(pdev); break;
case XenbusStateReconfiguring:
xen_pcibk_reconfigure(pdev, XenbusStateReconfiguring); break;
case XenbusStateConnected: /* pcifront switched its state from reconfiguring to connected. * Then switch to connected state.
*/
xenbus_switch_state(xdev, XenbusStateConnected); break;
case XenbusStateClosing:
xen_pcibk_disconnect(pdev);
xenbus_switch_state(xdev, XenbusStateClosing); break;
case XenbusStateClosed:
xen_pcibk_disconnect(pdev);
xenbus_switch_state(xdev, XenbusStateClosed); if (xenbus_dev_is_online(xdev)) break;
fallthrough; /* if not online */ case XenbusStateUnknown:
dev_dbg(&xdev->dev, "frontend is gone! unregister device\n");
device_unregister(&xdev->dev); break;
default: break;
}
}
staticint xen_pcibk_setup_backend(struct xen_pcibk_device *pdev)
{ /* Get configuration from xend (if available now) */ int domain, bus, slot, func; int err = 0; int i, num_devs; char dev_str[64]; char state_str[64];
mutex_lock(&pdev->dev_lock); /* It's possible we could get the call to setup twice, so make sure * we're not already connected.
*/ if (xenbus_read_driver_state(pdev->xdev->nodename) !=
XenbusStateInitWait) goto out;
dev_dbg(&pdev->xdev->dev, "getting be setup\n");
err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename, "num_devs", "%d",
&num_devs); if (err != 1) { if (err >= 0)
err = -EINVAL;
xenbus_dev_fatal(pdev->xdev, err, "Error reading number of devices"); goto out;
}
for (i = 0; i < num_devs; i++) { int l = snprintf(dev_str, sizeof(dev_str), "dev-%d", i); if (unlikely(l >= (sizeof(dev_str) - 1))) {
err = -ENOMEM;
xenbus_dev_fatal(pdev->xdev, err, "String overflow while reading " "configuration"); goto out;
}
switch (xenbus_read_driver_state(pdev->xdev->nodename)) { case XenbusStateInitWait:
xen_pcibk_setup_backend(pdev); break;
case XenbusStateInitialised: /* * We typically move to Initialised when the first device was * added. Hence subsequent devices getting added may need * reconfiguring.
*/
xen_pcibk_reconfigure(pdev, XenbusStateInitialised); break;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.