[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


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.