[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] [linux-2.6.18-xen] Xen paravirtualised PCI hotplug.
# HG changeset patch # User Keir Fraser <keir.fraser@xxxxxxxxxx> # Date 1203674763 0 # Node ID 4b9f2293d7507bab5cd6952c2c97e7b3d057641a # Parent 5069c4f9481242082c52e58e1828c1a5a4bb9a65 Xen paravirtualised PCI hotplug. Signed-off-by: Yosuke Iwamatsu <y-iwamatsu@xxxxxxxxxxxxx> --- drivers/xen/pciback/controller.c | 6 drivers/xen/pciback/passthrough.c | 5 drivers/xen/pciback/pciback.h | 6 drivers/xen/pciback/slot.c | 8 drivers/xen/pciback/vpci.c | 14 + drivers/xen/pciback/xenbus.c | 380 ++++++++++++++++++++++++++++++-------- drivers/xen/pcifront/pci_op.c | 52 +++++ drivers/xen/pcifront/pcifront.h | 2 drivers/xen/pcifront/xenbus.c | 154 +++++++++++++++ include/xen/interface/io/xenbus.h | 9 10 files changed, 551 insertions(+), 85 deletions(-) diff -r 5069c4f94812 -r 4b9f2293d750 drivers/xen/pciback/controller.c --- a/drivers/xen/pciback/controller.c Thu Feb 21 10:22:27 2008 +0000 +++ b/drivers/xen/pciback/controller.c Fri Feb 22 10:06:03 2008 +0000 @@ -91,7 +91,8 @@ found: return dev; } -int pciback_add_pci_dev(struct pciback_device *pdev, struct pci_dev *dev) +int pciback_add_pci_dev(struct pciback_device *pdev, struct pci_dev *dev, + int devid, publish_pci_dev_cb publish_cb) { struct controller_dev_data *dev_data = pdev->pci_dev_data; struct controller_dev_entry *dev_entry; @@ -165,6 +166,9 @@ int pciback_add_pci_dev(struct pciback_d out: spin_unlock_irqrestore(&dev_data->lock, flags); + + /* TODO: Publish virtual domain:bus:slot.func here. */ + return ret; } diff -r 5069c4f94812 -r 4b9f2293d750 drivers/xen/pciback/passthrough.c --- a/drivers/xen/pciback/passthrough.c Thu Feb 21 10:22:27 2008 +0000 +++ b/drivers/xen/pciback/passthrough.c Fri Feb 22 10:06:03 2008 +0000 @@ -41,7 +41,8 @@ struct pci_dev *pciback_get_pci_dev(stru return dev; } -int pciback_add_pci_dev(struct pciback_device *pdev, struct pci_dev *dev) +int pciback_add_pci_dev(struct pciback_device *pdev, struct pci_dev *dev, + int devid, publish_pci_dev_cb publish_cb) { struct passthrough_dev_data *dev_data = pdev->pci_dev_data; struct pci_dev_entry *dev_entry; @@ -55,6 +56,8 @@ int pciback_add_pci_dev(struct pciback_d spin_lock_irqsave(&dev_data->lock, flags); list_add_tail(&dev_entry->list, &dev_data->dev_list); spin_unlock_irqrestore(&dev_data->lock, flags); + + /* TODO: Publish virtual domain:bus:slot.func here. */ return 0; } diff -r 5069c4f94812 -r 4b9f2293d750 drivers/xen/pciback/pciback.h --- a/drivers/xen/pciback/pciback.h Thu Feb 21 10:22:27 2008 +0000 +++ b/drivers/xen/pciback/pciback.h Fri Feb 22 10:06:03 2008 +0000 @@ -70,9 +70,13 @@ int pciback_config_write(struct pci_dev int pciback_config_write(struct pci_dev *dev, int offset, int size, u32 value); /* Handle requests for specific devices from the frontend */ +typedef int (*publish_pci_dev_cb) (struct pciback_device *pdev, + unsigned int domain, unsigned int bus, + unsigned int devfn, unsigned int devid); typedef int (*publish_pci_root_cb) (struct pciback_device * pdev, unsigned int domain, unsigned int bus); -int pciback_add_pci_dev(struct pciback_device *pdev, struct pci_dev *dev); +int pciback_add_pci_dev(struct pciback_device *pdev, struct pci_dev *dev, + int devid, publish_pci_dev_cb publish_cb); void pciback_release_pci_dev(struct pciback_device *pdev, struct pci_dev *dev); struct pci_dev *pciback_get_pci_dev(struct pciback_device *pdev, unsigned int domain, unsigned int bus, diff -r 5069c4f94812 -r 4b9f2293d750 drivers/xen/pciback/slot.c --- a/drivers/xen/pciback/slot.c Thu Feb 21 10:22:27 2008 +0000 +++ b/drivers/xen/pciback/slot.c Fri Feb 22 10:06:03 2008 +0000 @@ -44,7 +44,8 @@ struct pci_dev *pciback_get_pci_dev(stru return dev; } -int pciback_add_pci_dev(struct pciback_device *pdev, struct pci_dev *dev) +int pciback_add_pci_dev(struct pciback_device *pdev, struct pci_dev *dev, + int devid, publish_pci_dev_cb publish_cb) { int err = 0, slot, bus; struct slot_dev_data *slot_dev = pdev->pci_dev_data; @@ -77,6 +78,11 @@ int pciback_add_pci_dev(struct pciback_d unlock: spin_unlock_irqrestore(&slot_dev->lock, flags); + + /* Publish this device. */ + if(!err) + err = publish_cb(pdev, 0, 0, PCI_DEVFN(slot, 0), devid); + out: return err; } diff -r 5069c4f94812 -r 4b9f2293d750 drivers/xen/pciback/vpci.c --- a/drivers/xen/pciback/vpci.c Thu Feb 21 10:22:27 2008 +0000 +++ b/drivers/xen/pciback/vpci.c Fri Feb 22 10:06:03 2008 +0000 @@ -62,9 +62,10 @@ static inline int match_slot(struct pci_ return 0; } -int pciback_add_pci_dev(struct pciback_device *pdev, struct pci_dev *dev) -{ - int err = 0, slot; +int pciback_add_pci_dev(struct pciback_device *pdev, struct pci_dev *dev, + int devid, publish_pci_dev_cb publish_cb) +{ + int err = 0, slot, func; struct pci_dev_entry *t, *dev_entry; struct vpci_dev_data *vpci_dev = pdev->pci_dev_data; unsigned long flags; @@ -101,6 +102,7 @@ int pciback_add_pci_dev(struct pciback_d PCI_FUNC(dev->devfn)); list_add_tail(&dev_entry->list, &vpci_dev->dev_list[slot]); + func = PCI_FUNC(dev->devfn); goto unlock; } } @@ -114,6 +116,7 @@ int pciback_add_pci_dev(struct pciback_d pci_name(dev), slot); list_add_tail(&dev_entry->list, &vpci_dev->dev_list[slot]); + func = PCI_FUNC(dev->devfn); goto unlock; } } @@ -124,6 +127,11 @@ int pciback_add_pci_dev(struct pciback_d unlock: spin_unlock_irqrestore(&vpci_dev->lock, flags); + + /* Publish this device. */ + if(!err) + err = publish_cb(pdev, 0, 0, PCI_DEVFN(slot, func), devid); + out: return err; } diff -r 5069c4f94812 -r 4b9f2293d750 drivers/xen/pciback/xenbus.c --- a/drivers/xen/pciback/xenbus.c Thu Feb 21 10:22:27 2008 +0000 +++ b/drivers/xen/pciback/xenbus.c Fri Feb 22 10:06:03 2008 +0000 @@ -161,95 +161,31 @@ static int pciback_attach(struct pciback return err; } -static void pciback_frontend_changed(struct xenbus_device *xdev, - enum xenbus_state fe_state) -{ - struct pciback_device *pdev = xdev->dev.driver_data; - - dev_dbg(&xdev->dev, "fe state changed %d\n", fe_state); - - switch (fe_state) { - case XenbusStateInitialised: - pciback_attach(pdev); - break; - - case XenbusStateClosing: - xenbus_switch_state(xdev, XenbusStateClosing); - break; - - case XenbusStateUnknown: - case XenbusStateClosed: - dev_dbg(&xdev->dev, "frontend is gone! unregister device\n"); - device_unregister(&xdev->dev); - break; - - default: - break; - } -} - -static int pciback_publish_pci_root(struct pciback_device *pdev, - unsigned int domain, unsigned int bus) -{ - unsigned int d, b; - int i, root_num, len, err; +static int pciback_publish_pci_dev(struct pciback_device *pdev, + unsigned int domain, unsigned int bus, + unsigned int devfn, unsigned int devid) +{ + int err; + int len; char str[64]; - dev_dbg(&pdev->xdev->dev, "Publishing pci roots\n"); - - err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename, - "root_num", "%d", &root_num); - if (err == 0 || err == -ENOENT) - root_num = 0; - else if (err < 0) - goto out; - - /* 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; - } - - err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename, - str, "%x:%x", &d, &b); - if (err < 0) - goto out; - if (err != 2) { - err = -EINVAL; - goto out; - } - - if (d == domain && b == bus) { - err = 0; - goto out; - } - } - - len = snprintf(str, sizeof(str), "root-%d", root_num); + len = snprintf(str, sizeof(str), "vdev-%d", devid); if (unlikely(len >= (sizeof(str) - 1))) { err = -ENOMEM; goto out; } - dev_dbg(&pdev->xdev->dev, "writing root %d at %04x:%02x\n", - root_num, domain, bus); - err = xenbus_printf(XBT_NIL, pdev->xdev->nodename, str, - "%04x:%02x", domain, bus); - if (err) - goto out; - - err = xenbus_printf(XBT_NIL, pdev->xdev->nodename, - "root_num", "%d", (root_num + 1)); + "%04x:%02x:%02x.%02x", domain, bus, + PCI_SLOT(devfn), PCI_FUNC(devfn)); out: return err; } static int pciback_export_device(struct pciback_device *pdev, - int domain, int bus, int slot, int func) + int domain, int bus, int slot, int func, + int devid) { struct pci_dev *dev; int err = 0; @@ -268,7 +204,7 @@ static int pciback_export_device(struct goto out; } - err = pciback_add_pci_dev(pdev, dev); + err = pciback_add_pci_dev(pdev, dev, devid, pciback_publish_pci_dev); if (err) goto out; @@ -284,6 +220,278 @@ static int pciback_export_device(struct return err; } +static int pciback_remove_device(struct pciback_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 = pciback_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.%01x)! not owned by this domain\n", + domain, bus, slot, func); + goto out; + } + + pciback_release_pci_dev(pdev, dev); + + out: + return err; +} + +static int pciback_publish_pci_root(struct pciback_device *pdev, + unsigned int domain, unsigned int bus) +{ + unsigned int d, b; + int i, root_num, len, err; + char str[64]; + + dev_dbg(&pdev->xdev->dev, "Publishing pci roots\n"); + + err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename, + "root_num", "%d", &root_num); + if (err == 0 || err == -ENOENT) + root_num = 0; + else if (err < 0) + goto out; + + /* 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; + } + + err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename, + str, "%x:%x", &d, &b); + if (err < 0) + goto out; + if (err != 2) { + err = -EINVAL; + goto out; + } + + if (d == domain && b == bus) { + err = 0; + goto out; + } + } + + len = snprintf(str, sizeof(str), "root-%d", root_num); + if (unlikely(len >= (sizeof(str) - 1))) { + err = -ENOMEM; + goto out; + } + + dev_dbg(&pdev->xdev->dev, "writing root %d at %04x:%02x\n", + root_num, domain, bus); + + err = xenbus_printf(XBT_NIL, pdev->xdev->nodename, str, + "%04x:%02x", domain, bus); + if (err) + goto out; + + err = xenbus_printf(XBT_NIL, pdev->xdev->nodename, + "root_num", "%d", (root_num + 1)); + + out: + return err; +} + +static int pciback_reconfigure(struct pciback_device *pdev) +{ + int err = 0; + int num_devs; + int domain, bus, slot, func; + int substate; + int i, len; + char state_str[64]; + char dev_str[64]; + + spin_lock(&pdev->dev_lock); + + dev_dbg(&pdev->xdev->dev, "Reconfiguring device ...\n"); + + /* Make sure we only reconfigure once */ + if (xenbus_read_driver_state(pdev->xdev->nodename) != + XenbusStateReconfiguring) + goto out; + + 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++) { + len = snprintf(state_str, sizeof(state_str), "state-%d", i); + if (unlikely(len >= (sizeof(state_str) - 1))) { + err = -ENOMEM; + xenbus_dev_fatal(pdev->xdev, err, + "String overflow while reading " + "configuration"); + goto out; + } + err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename, state_str, + "%d", &substate); + if (err != 1) + substate = XenbusStateUnknown; + + switch (substate) { + /* case XenbusStateUnknown: */ + case XenbusStateInitialising: + dev_dbg(&pdev->xdev->dev, "Attaching dev-%d ...\n", i); + + len = snprintf(dev_str, sizeof(dev_str), "dev-%d", i); + if (unlikely(len >= (sizeof(dev_str) - 1))) { + err = -ENOMEM; + xenbus_dev_fatal(pdev->xdev, err, + "String overflow while " + "reading configuration"); + goto out; + } + err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename, + dev_str, "%x:%x:%x.%x", + &domain, &bus, &slot, &func); + if (err < 0) { + xenbus_dev_fatal(pdev->xdev, err, + "Error reading device " + "configuration"); + goto out; + } + if (err != 4) { + err = -EINVAL; + xenbus_dev_fatal(pdev->xdev, err, + "Error parsing pci device " + "configuration"); + goto out; + } + + err = pciback_export_device(pdev, domain, bus, slot, + func, i); + if (err) + goto out; + + /* TODO: if we are to support multiple pci roots + * (CONFIG_XEN_PCIDEV_BACKEND_PASS), publish newly + * added root here. + */ + + err = xenbus_printf(XBT_NIL, pdev->xdev->nodename, + state_str, "%d", + XenbusStateInitialised); + if (err) { + xenbus_dev_fatal(pdev->xdev, err, + "Error switching substate of " "dev-%d\n", i); + goto out; + } + break; + + case XenbusStateClosing: + dev_dbg(&pdev->xdev->dev, "Detaching dev-%d ...\n", i); + + len = snprintf(dev_str, sizeof(dev_str), "vdev-%d", i); + if (unlikely(len >= (sizeof(dev_str) - 1))) { + err = -ENOMEM; + xenbus_dev_fatal(pdev->xdev, err, + "String overflow while " + "reading configuration"); + goto out; + } + err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename, + dev_str, "%x:%x:%x.%x", + &domain, &bus, &slot, &func); + if (err < 0) { + xenbus_dev_fatal(pdev->xdev, err, + "Error reading device " + "configuration"); + goto out; + } + if (err != 4) { + err = -EINVAL; + xenbus_dev_fatal(pdev->xdev, err, + "Error parsing pci device " + "configuration"); + goto out; + } + + err = pciback_remove_device(pdev, domain, bus, slot, + func); + if(err) + goto out; + + /* TODO: if we are to support multiple pci roots + * (CONFIG_XEN_PCIDEV_BACKEND_PASS), remove unnecessary + * root here. + */ + break; + + default: + break; + } + } + + err = xenbus_switch_state(pdev->xdev, XenbusStateReconfigured); + if (err) { + xenbus_dev_fatal(pdev->xdev, err, + "Error switching to reconfigured state!"); + goto out; + } + + out: + spin_unlock(&pdev->dev_lock); + + return 0; +} + +static void pciback_frontend_changed(struct xenbus_device *xdev, + enum xenbus_state fe_state) +{ + struct pciback_device *pdev = xdev->dev.driver_data; + + dev_dbg(&xdev->dev, "fe state changed %d\n", fe_state); + + switch (fe_state) { + case XenbusStateInitialised: + pciback_attach(pdev); + break; + + case XenbusStateClosing: + xenbus_switch_state(xdev, XenbusStateClosed); + break; + + case XenbusStateUnknown: + case XenbusStateClosed: + dev_dbg(&xdev->dev, "frontend is gone! unregister device\n"); + device_unregister(&xdev->dev); + break; + + case XenbusStateReconfiguring: + pciback_reconfigure(pdev); + break; + + case XenbusStateConnected: + /* pcifront switched its state from reconfiguring to connected. + * Then switch to connected state. + */ + xenbus_switch_state(xdev, XenbusStateConnected); + break; + + default: + break; + } +} + static int pciback_setup_backend(struct pciback_device *pdev) { /* Get configuration from xend (if available now) */ @@ -291,6 +499,7 @@ static int pciback_setup_backend(struct int err = 0; int i, num_devs; char dev_str[64]; + char state_str[64]; spin_lock(&pdev->dev_lock); @@ -338,9 +547,26 @@ static int pciback_setup_backend(struct goto out; } - err = pciback_export_device(pdev, domain, bus, slot, func); + err = pciback_export_device(pdev, domain, bus, slot, func, i); if (err) goto out; + + /* Switch substate of this device. */ + l = snprintf(state_str, sizeof(state_str), "state-%d", i); + if (unlikely(l >= (sizeof(state_str) - 1))) { + err = -ENOMEM; + xenbus_dev_fatal(pdev->xdev, err, + "String overflow while reading " + "configuration"); + goto out; + } + err = xenbus_printf(XBT_NIL, pdev->xdev->nodename, state_str, + "%d", XenbusStateInitialised); + if (err) { + xenbus_dev_fatal(pdev->xdev, err, "Error switching " + "substate of dev-%d\n", i); + goto out; + } } err = pciback_publish_pci_roots(pdev, pciback_publish_pci_root); diff -r 5069c4f94812 -r 4b9f2293d750 drivers/xen/pcifront/pci_op.c --- a/drivers/xen/pcifront/pci_op.c Thu Feb 21 10:22:27 2008 +0000 +++ b/drivers/xen/pcifront/pci_op.c Fri Feb 22 10:06:03 2008 +0000 @@ -353,6 +353,58 @@ int pcifront_scan_root(struct pcifront_d return err; } +int pcifront_rescan_root(struct pcifront_device *pdev, + unsigned int domain, unsigned int bus) +{ + struct pci_bus *b; + struct pci_dev *d; + unsigned int devfn; + int err = 0; + +#ifndef CONFIG_PCI_DOMAINS + if (domain != 0) { + dev_err(&pdev->xdev->dev, + "PCI Root in non-zero PCI Domain! domain=%d\n", domain); + dev_err(&pdev->xdev->dev, + "Please compile with CONFIG_PCI_DOMAINS\n"); + err = -EINVAL; + goto err_out; + } +#endif + + dev_info(&pdev->xdev->dev, "Rescanning PCI Frontend Bus %04x:%02x\n", + domain, bus); + + b = pci_find_bus(domain, bus); + if(!b) + /* If the bus is unknown, create it. */ + return pcifront_scan_root(pdev, domain, bus); + + /* Rescan the bus for newly attached functions and add. + * We omit handling of PCI bridge attachment because pciback prevents + * bridges from being exported. + */ + for (devfn = 0; devfn < 0x100; devfn++) { + d = pci_get_slot(b, devfn); + if(d) { + /* Device is already known. */ + pci_dev_put(d); + continue; + } + + d = pci_scan_single_device(b, devfn); + if (d) { + dev_info(&pdev->xdev->dev, "New device on " + "%04x:%02x:%02x.%02x found.\n", domain, bus, + PCI_SLOT(devfn), PCI_FUNC(devfn)); + pci_bus_add_device(d); + } + } + + err_out: + return err; +} + static void free_root_bus_devs(struct pci_bus *bus) { struct pci_dev *dev; diff -r 5069c4f94812 -r 4b9f2293d750 drivers/xen/pcifront/pcifront.h --- a/drivers/xen/pcifront/pcifront.h Thu Feb 21 10:22:27 2008 +0000 +++ b/drivers/xen/pcifront/pcifront.h Fri Feb 22 10:06:03 2008 +0000 @@ -35,6 +35,8 @@ void pcifront_disconnect(struct pcifront int pcifront_scan_root(struct pcifront_device *pdev, unsigned int domain, unsigned int bus); +int pcifront_rescan_root(struct pcifront_device *pdev, + unsigned int domain, unsigned int bus); void pcifront_free_roots(struct pcifront_device *pdev); #endif /* __XEN_PCIFRONT_H__ */ diff -r 5069c4f94812 -r 4b9f2293d750 drivers/xen/pcifront/xenbus.c --- a/drivers/xen/pcifront/xenbus.c Thu Feb 21 10:22:27 2008 +0000 +++ b/drivers/xen/pcifront/xenbus.c Fri Feb 22 10:06:03 2008 +0000 @@ -214,6 +214,152 @@ static int pcifront_try_disconnect(struc return err; } +static int pcifront_attach_devices(struct pcifront_device *pdev) +{ + int err = -EFAULT; + int i, num_roots, len; + unsigned int domain, bus; + char str[64]; + + spin_lock(&pdev->dev_lock); + + if (xenbus_read_driver_state(pdev->xdev->nodename) != + XenbusStateReconfiguring) + goto out; + + err = xenbus_scanf(XBT_NIL, pdev->xdev->otherend, + "root_num", "%d", &num_roots); + if (err == -ENOENT) { + xenbus_dev_error(pdev->xdev, err, + "No PCI Roots found, trying 0000:00"); + err = pcifront_rescan_root(pdev, 0, 0); + num_roots = 0; + } else if (err != 1) { + if (err == 0) + err = -EINVAL; + xenbus_dev_fatal(pdev->xdev, err, + "Error reading number of PCI roots"); + goto out; + } + + for (i = 0; i < num_roots; i++) { + len = snprintf(str, sizeof(str), "root-%d", i); + if (unlikely(len >= (sizeof(str) - 1))) { + err = -ENOMEM; + goto out; + } + + err = xenbus_scanf(XBT_NIL, pdev->xdev->otherend, str, + "%x:%x", &domain, &bus); + if (err != 2) { + if (err >= 0) + err = -EINVAL; + xenbus_dev_fatal(pdev->xdev, err, + "Error reading PCI root %d", i); + goto out; + } + + err = pcifront_rescan_root(pdev, domain, bus); + if (err) { + xenbus_dev_fatal(pdev->xdev, err, + "Error scanning PCI root %04x:%02x", + domain, bus); + goto out; + } + } + + xenbus_switch_state(pdev->xdev, XenbusStateConnected); + + out: + spin_unlock(&pdev->dev_lock); + return err; +} + +static int pcifront_detach_devices(struct pcifront_device *pdev) +{ + int err; + int i, num_devs; + unsigned int domain, bus, slot, func; + struct pci_bus *pci_bus; + struct pci_dev *pci_dev; + char str[64]; + + spin_lock(&pdev->dev_lock); + + if (xenbus_read_driver_state(pdev->xdev->nodename) != + XenbusStateConnected) + goto out; + + err = xenbus_scanf(XBT_NIL, pdev->xdev->otherend, "num_devs", "%d", + &num_devs); + if (err != 1) { + if (err >= 0) + err = -EINVAL; + xenbus_dev_fatal(pdev->xdev, err, + "Error reading number of PCI devices"); + goto out; + } + + /* Find devices being detached and remove them. */ + for (i = 0; i < num_devs; i++) { + int l, state; + l = snprintf(str, sizeof(str), "state-%d", i); + if (unlikely(l >= (sizeof(str) - 1))) { + err = -ENOMEM; + goto out; + } + err = xenbus_scanf(XBT_NIL, pdev->xdev->otherend, str, "%d", + &state); + if (err != 1) + state = XenbusStateUnknown; + + if (state != XenbusStateClosing) + continue; + + /* Remove device. */ + l = snprintf(str, sizeof(str), "vdev-%d", i); + if (unlikely(l >= (sizeof(str) - 1))) { + err = -ENOMEM; + goto out; + } + err = xenbus_scanf(XBT_NIL, pdev->xdev->otherend, str, + "%x:%x:%x.%x", &domain, &bus, &slot, &func); + if (err != 4) { + if (err >= 0) + err = -EINVAL; + xenbus_dev_fatal(pdev->xdev, err, + "Error reading PCI root %d", i); + goto out; + } + + pci_bus = pci_find_bus(domain, bus); + if(!pci_bus) { + dev_dbg(&pdev->xdev->dev, "Cannot get bus %04x:%02x\n", + domain, bus); + continue; + } + pci_dev = pci_get_slot(pci_bus, PCI_DEVFN(slot, func)); + if(!pci_dev) { + dev_dbg(&pdev->xdev->dev, + "Cannot get PCI device %04x:%02x:%02x.%02x\n", + domain, bus, slot, func); + continue; + } + pci_remove_bus_device(pci_dev); + pci_dev_put(pci_dev); + + dev_dbg(&pdev->xdev->dev, + "PCI device %04x:%02x:%02x.%02x removed.\n", + domain, bus, slot, func); + } + + err = xenbus_switch_state(pdev->xdev, XenbusStateReconfiguring); + + out: + spin_unlock(&pdev->dev_lock); + return err; +} + static void pcifront_backend_changed(struct xenbus_device *xdev, enum xenbus_state be_state) { @@ -235,6 +381,14 @@ static void pcifront_backend_changed(str case XenbusStateConnected: pcifront_try_connect(pdev); + break; + + case XenbusStateReconfiguring: + pcifront_detach_devices(pdev); + break; + + case XenbusStateReconfigured: + pcifront_attach_devices(pdev); break; default: diff -r 5069c4f94812 -r 4b9f2293d750 include/xen/interface/io/xenbus.h --- a/include/xen/interface/io/xenbus.h Thu Feb 21 10:22:27 2008 +0000 +++ b/include/xen/interface/io/xenbus.h Fri Feb 22 10:06:03 2008 +0000 @@ -56,7 +56,14 @@ enum xenbus_state { */ XenbusStateClosing = 5, - XenbusStateClosed = 6 + XenbusStateClosed = 6, + + /* + * Reconfiguring: The device is being reconfigured. + */ + XenbusStateReconfiguring = 7, + + XenbusStateReconfigured = 8 }; typedef enum xenbus_state XenbusState; _______________________________________________ Xen-changelog mailing list Xen-changelog@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-changelog
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |