WARNING - OLD ARCHIVES

This is an archived copy of the Xen.org mailing list, which we have preserved to ensure that existing links to archives are not broken. The live archive, which contains the latest emails, can be found at http://lists.xen.org/
   
 
 
Xen 
 
Home Products Support Community News
 
   
 

xen-changelog

[Xen-changelog] [linux-2.6.18-xen] Xen paravirtualised PCI hotplug.

To: xen-changelog@xxxxxxxxxxxxxxxxxxx
Subject: [Xen-changelog] [linux-2.6.18-xen] Xen paravirtualised PCI hotplug.
From: "Xen patchbot-linux-2.6.18-xen" <patchbot-linux-2.6.18-xen@xxxxxxxxxxxxxxxxxxx>
Date: Mon, 25 Feb 2008 05:10:11 -0800
Delivery-date: Mon, 25 Feb 2008 05:10:13 -0800
Envelope-to: www-data@xxxxxxxxxxxxxxxxxx
List-help: <mailto:xen-changelog-request@lists.xensource.com?subject=help>
List-id: BK change log <xen-changelog.lists.xensource.com>
List-post: <mailto:xen-changelog@lists.xensource.com>
List-subscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-changelog>, <mailto:xen-changelog-request@lists.xensource.com?subject=subscribe>
List-unsubscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-changelog>, <mailto:xen-changelog-request@lists.xensource.com?subject=unsubscribe>
Reply-to: xen-devel@xxxxxxxxxxxxxxxxxxx
Sender: xen-changelog-bounces@xxxxxxxxxxxxxxxxxxx
# 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

<Prev in Thread] Current Thread [Next in Thread>
  • [Xen-changelog] [linux-2.6.18-xen] Xen paravirtualised PCI hotplug., Xen patchbot-linux-2.6.18-xen <=