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] PCI: add SR-IOV API for Physical Func

To: xen-changelog@xxxxxxxxxxxxxxxxxxx
Subject: [Xen-changelog] [linux-2.6.18-xen] PCI: add SR-IOV API for Physical Function driver
From: "Xen patchbot-linux-2.6.18-xen" <patchbot-linux-2.6.18-xen@xxxxxxxxxxxxxxxxxxx>
Date: Wed, 18 Mar 2009 07:25:28 -0700
Delivery-date: Wed, 18 Mar 2009 07:27:21 -0700
Envelope-to: www-data@xxxxxxxxxxxxxxxxxxx
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/mailman/listinfo/xen-changelog>, <mailto:xen-changelog-request@lists.xensource.com?subject=subscribe>
List-unsubscribe: <http://lists.xensource.com/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 1237376410 0
# Node ID 64c8f9fbf6092322162aa62d326729ba745a48eb
# Parent  002e044dc979e4e4691226418e7875ebaa6e0267
PCI: add SR-IOV API for Physical Function driver

Add or remove the Virtual Function when the SR-IOV is enabled or
disabled by the device driver. This can happen anytime rather than
only at the device probe stage.

Signed-off-by: Yu Zhao <yu.zhao@xxxxxxxxx>
---
 drivers/pci/iov.c   |  297 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 drivers/pci/pci.h   |    2 
 include/linux/pci.h |   19 +++
 3 files changed, 317 insertions(+), 1 deletion(-)

diff -r 002e044dc979 -r 64c8f9fbf609 drivers/pci/iov.c
--- a/drivers/pci/iov.c Wed Mar 18 11:39:56 2009 +0000
+++ b/drivers/pci/iov.c Wed Mar 18 11:40:10 2009 +0000
@@ -13,6 +13,7 @@
 #include <linux/delay.h>
 #include "pci.h"
 
+#define VIRTFN_ID_LEN  16
 
 static inline u8 virtfn_bus(struct pci_dev *dev, int id)
 {
@@ -24,6 +25,267 @@ static inline u8 virtfn_devfn(struct pci
 {
        return (dev->devfn + dev->sriov->offset +
                dev->sriov->stride * id) & 0xff;
+}
+
+static struct pci_bus *virtfn_add_bus(struct pci_bus *bus, int busnr)
+{
+       struct pci_bus *child;
+
+       if (bus->number == busnr)
+               return bus;
+
+       child = pci_find_bus(pci_domain_nr(bus), busnr);
+       if (child)
+               return child;
+
+       child = pci_add_new_bus(bus, NULL, busnr);
+       if (!child)
+               return NULL;
+
+       child->subordinate = busnr;
+
+       return child;
+}
+
+static void virtfn_remove_bus(struct pci_bus *bus, int busnr)
+{
+       struct pci_bus *child;
+
+       if (bus->number == busnr)
+               return;
+
+       child = pci_find_bus(pci_domain_nr(bus), busnr);
+       BUG_ON(!child);
+
+       if (list_empty(&child->devices))
+               pci_remove_bus(child);
+}
+
+static int virtfn_add(struct pci_dev *dev, int id)
+{
+       int i;
+       int rc;
+       u64 size;
+       char buf[VIRTFN_ID_LEN];
+       struct pci_dev *virtfn;
+       struct resource *res;
+       struct pci_sriov *iov = dev->sriov;
+
+       virtfn = kzalloc(sizeof(struct pci_dev), GFP_KERNEL);
+       if (!virtfn)
+               return -ENOMEM;
+
+       mutex_lock(&iov->dev->sriov->lock);
+       virtfn->bus = virtfn_add_bus(dev->bus, virtfn_bus(dev, id));
+       if (!virtfn->bus) {
+               kfree(virtfn);
+               mutex_unlock(&iov->dev->sriov->lock);
+               return -ENOMEM;
+       }
+       virtfn->devfn = virtfn_devfn(dev, id);
+       virtfn->vendor = dev->vendor;
+       pci_read_config_word(dev, iov->pos + PCI_SRIOV_VF_DID, &virtfn->device);
+       pci_setup_device(virtfn);
+       virtfn->dev.parent = dev->dev.parent;
+
+       for (i = 0; i < PCI_SRIOV_NUM_BARS; i++) {
+               res = dev->resource + PCI_IOV_RESOURCES + i;
+               if (!res->parent)
+                       continue;
+               virtfn->resource[i].name = pci_name(virtfn);
+               virtfn->resource[i].flags = res->flags;
+               size = res->end - res->start + 1;
+               do_div(size, iov->total);
+               virtfn->resource[i].start = res->start + size * id;
+               virtfn->resource[i].end = virtfn->resource[i].start + size - 1;
+               rc = request_resource(res, &virtfn->resource[i]);
+               BUG_ON(rc);
+       }
+
+       pci_device_add(virtfn, virtfn->bus);
+       mutex_unlock(&iov->dev->sriov->lock);
+
+       virtfn->physfn = pci_dev_get(dev);
+       virtfn->is_virtfn = 1;
+
+       pci_bus_add_device(virtfn);
+       sprintf(buf, "virtfn%u", id);
+       rc = sysfs_create_link(&dev->dev.kobj, &virtfn->dev.kobj, buf);
+       if (rc)
+               goto failed1;
+       rc = sysfs_create_link(&virtfn->dev.kobj, &dev->dev.kobj, "physfn");
+       if (rc)
+               goto failed2;
+
+       kobject_uevent(&virtfn->dev.kobj, KOBJ_CHANGE);
+
+       return 0;
+
+failed2:
+       sysfs_remove_link(&dev->dev.kobj, buf);
+failed1:
+       pci_dev_put(dev);
+       mutex_lock(&iov->dev->sriov->lock);
+       pci_remove_bus_device(virtfn);
+       virtfn_remove_bus(dev->bus, virtfn_bus(dev, id));
+       mutex_unlock(&iov->dev->sriov->lock);
+
+       return rc;
+}
+
+static void virtfn_remove(struct pci_dev *dev, int id)
+{
+       char buf[VIRTFN_ID_LEN];
+       struct pci_bus *bus;
+       struct pci_dev *virtfn;
+       struct pci_sriov *iov = dev->sriov;
+
+       bus = pci_find_bus(pci_domain_nr(dev->bus), virtfn_bus(dev, id));
+       if (!bus)
+               return;
+
+       virtfn = pci_get_slot(bus, virtfn_devfn(dev, id));
+       if (!virtfn)
+               return;
+
+       pci_dev_put(virtfn);
+
+       sprintf(buf, "virtfn%u", id);
+       sysfs_remove_link(&dev->dev.kobj, buf);
+       sysfs_remove_link(&virtfn->dev.kobj, "physfn");
+
+       mutex_lock(&iov->dev->sriov->lock);
+       pci_remove_bus_device(virtfn);
+       virtfn_remove_bus(dev->bus, virtfn_bus(dev, id));
+       mutex_unlock(&iov->dev->sriov->lock);
+
+       pci_dev_put(dev);
+}
+
+static int sriov_enable(struct pci_dev *dev, int nr_virtfn)
+{
+       int rc;
+       int i, j;
+       int nres;
+       u16 offset, stride, initial;
+       struct resource *res;
+       struct pci_dev *pdev;
+       struct pci_sriov *iov = dev->sriov;
+
+       if (!nr_virtfn)
+               return 0;
+
+       if (iov->nr_virtfn)
+               return -EINVAL;
+
+       pci_read_config_word(dev, iov->pos + PCI_SRIOV_INITIAL_VF, &initial);
+       if (initial > iov->total ||
+           (!(iov->cap & PCI_SRIOV_CAP_VFM) && (initial != iov->total)))
+               return -EIO;
+
+       if (nr_virtfn < 0 || nr_virtfn > iov->total ||
+           (!(iov->cap & PCI_SRIOV_CAP_VFM) && (nr_virtfn > initial)))
+               return -EINVAL;
+
+       pci_write_config_word(dev, iov->pos + PCI_SRIOV_NUM_VF, nr_virtfn);
+       pci_read_config_word(dev, iov->pos + PCI_SRIOV_VF_OFFSET, &offset);
+       pci_read_config_word(dev, iov->pos + PCI_SRIOV_VF_STRIDE, &stride);
+       if (!offset || (nr_virtfn > 1 && !stride))
+               return -EIO;
+
+       nres = 0;
+       for (i = 0; i < PCI_SRIOV_NUM_BARS; i++) {
+               res = dev->resource + PCI_IOV_RESOURCES + i;
+               if (res->parent)
+                       nres++;
+       }
+       if (nres != iov->nres) {
+               dev_err(&dev->dev, "not enough MMIO resources for SR-IOV\n");
+               return -ENOMEM;
+       }
+
+       iov->offset = offset;
+       iov->stride = stride;
+
+       if (virtfn_bus(dev, nr_virtfn - 1) > dev->bus->subordinate) {
+               dev_err(&dev->dev, "SR-IOV: bus number out of range\n");
+               return -ENOMEM;
+       }
+
+       if (iov->link != dev->devfn) {
+               pdev = pci_get_slot(dev->bus, iov->link);
+               if (!pdev)
+                       return -ENODEV;
+
+               pci_dev_put(pdev);
+
+               if (!pdev->is_physfn)
+                       return -ENODEV;
+
+               rc = sysfs_create_link(&dev->dev.kobj,
+                                       &pdev->dev.kobj, "dep_link");
+               if (rc)
+                       return rc;
+       }
+
+       iov->ctrl |= PCI_SRIOV_CTRL_VFE | PCI_SRIOV_CTRL_MSE;
+       pci_block_user_cfg_access(dev);
+       pci_write_config_word(dev, iov->pos + PCI_SRIOV_CTRL, iov->ctrl);
+       msleep(100);
+       pci_unblock_user_cfg_access(dev);
+
+       iov->initial = initial;
+       if (nr_virtfn < initial)
+               initial = nr_virtfn;
+
+       for (i = 0; i < initial; i++) {
+               rc = virtfn_add(dev, i);
+               if (rc)
+                       goto failed;
+       }
+
+       kobject_uevent(&dev->dev.kobj, KOBJ_CHANGE);
+       iov->nr_virtfn = nr_virtfn;
+
+       return 0;
+
+failed:
+       for (j = 0; j < i; j++)
+               virtfn_remove(dev, j);
+
+       iov->ctrl &= ~(PCI_SRIOV_CTRL_VFE | PCI_SRIOV_CTRL_MSE);
+       pci_block_user_cfg_access(dev);
+       pci_write_config_word(dev, iov->pos + PCI_SRIOV_CTRL, iov->ctrl);
+       ssleep(1);
+       pci_unblock_user_cfg_access(dev);
+
+       if (iov->link != dev->devfn)
+               sysfs_remove_link(&dev->dev.kobj, "dep_link");
+
+       return rc;
+}
+
+static void sriov_disable(struct pci_dev *dev)
+{
+       int i;
+       struct pci_sriov *iov = dev->sriov;
+
+       if (!iov->nr_virtfn)
+               return;
+
+       for (i = 0; i < iov->nr_virtfn; i++)
+               virtfn_remove(dev, i);
+
+       iov->ctrl &= ~(PCI_SRIOV_CTRL_VFE | PCI_SRIOV_CTRL_MSE);
+       pci_block_user_cfg_access(dev);
+       pci_write_config_word(dev, iov->pos + PCI_SRIOV_CTRL, iov->ctrl);
+       ssleep(1);
+       pci_unblock_user_cfg_access(dev);
+
+       if (iov->link != dev->devfn)
+               sysfs_remove_link(&dev->dev.kobj, "dep_link");
+
+       iov->nr_virtfn = 0;
 }
 
 static int sriov_init(struct pci_dev *dev, int pos)
@@ -128,6 +390,8 @@ failed:
 
 static void sriov_release(struct pci_dev *dev)
 {
+       BUG_ON(dev->sriov->nr_virtfn);
+
        if (dev == dev->sriov->dev)
                mutex_destroy(&dev->sriov->lock);
        else
@@ -151,6 +415,7 @@ static void sriov_restore_state(struct p
                pci_update_resource(dev, i);
 
        pci_write_config_dword(dev, iov->pos + PCI_SRIOV_SYS_PGSIZE, iov->pgsz);
+       pci_write_config_word(dev, iov->pos + PCI_SRIOV_NUM_VF, iov->nr_virtfn);
        pci_write_config_word(dev, iov->pos + PCI_SRIOV_CTRL, iov->ctrl);
        if (iov->ctrl & PCI_SRIOV_CTRL_VFE)
                msleep(100);
@@ -238,3 +503,35 @@ int pci_iov_bus_range(struct pci_bus *bu
 
        return max ? max - bus->number : 0;
 }
+
+/**
+ * pci_enable_sriov - enable the SR-IOV capability
+ * @dev: the PCI device
+ *
+ * Returns 0 on success, or negative on failure.
+ */
+int pci_enable_sriov(struct pci_dev *dev, int nr_virtfn)
+{
+       might_sleep();
+
+       if (!dev->is_physfn)
+               return -ENODEV;
+
+       return sriov_enable(dev, nr_virtfn);
+}
+EXPORT_SYMBOL_GPL(pci_enable_sriov);
+
+/**
+ * pci_disable_sriov - disable the SR-IOV capability
+ * @dev: the PCI device
+ */
+void pci_disable_sriov(struct pci_dev *dev)
+{
+       might_sleep();
+
+       if (!dev->is_physfn)
+               return;
+
+       sriov_disable(dev);
+}
+EXPORT_SYMBOL_GPL(pci_disable_sriov);
diff -r 002e044dc979 -r 64c8f9fbf609 drivers/pci/pci.h
--- a/drivers/pci/pci.h Wed Mar 18 11:39:56 2009 +0000
+++ b/drivers/pci/pci.h Wed Mar 18 11:40:10 2009 +0000
@@ -141,6 +141,8 @@ struct pci_sriov {
        u32 cap;                /* SR-IOV Capabilities */
        u16 ctrl;               /* SR-IOV Control */
        u16 total;              /* total VFs associated with the PF */
+       u16 initial;            /* initial VFs associated with the PF */
+       u16 nr_virtfn;          /* number of VFs available */
        u16 offset;             /* first VF Routing ID offset */
        u16 stride;             /* following VF stride */
        u32 pgsz;               /* page size for BAR alignment */
diff -r 002e044dc979 -r 64c8f9fbf609 include/linux/pci.h
--- a/include/linux/pci.h       Wed Mar 18 11:39:56 2009 +0000
+++ b/include/linux/pci.h       Wed Mar 18 11:40:10 2009 +0000
@@ -199,6 +199,7 @@ struct pci_dev {
        unsigned int    msix_enabled:1;
        unsigned int    ari_enabled:1;  /* ARI forwarding */
        unsigned int    is_physfn:1;
+       unsigned int    is_virtfn:1;
 
        u32             saved_config_space[16]; /* config space saved at 
suspend time */
        struct hlist_head saved_cap_space;
@@ -206,7 +207,10 @@ struct pci_dev {
        int rom_attr_enabled;           /* has display of the rom attribute 
been enabled? */
        struct bin_attribute *res_attr[DEVICE_COUNT_RESOURCE]; /* sysfs file 
for resources */
 #ifdef CONFIG_PCI_IOV
-       struct pci_sriov *sriov;        /* SR-IOV capability related */
+       union {
+               struct pci_sriov *sriov;        /* SR-IOV capability related */
+               struct pci_dev *physfn; /* the PF this VF is associated with */
+       };
 #endif
 };
 
@@ -829,5 +833,18 @@ int pci_is_guestdev(struct pci_dev *dev)
 int pci_is_guestdev(struct pci_dev *dev);
 #endif /* CONFIG_PCI_GUESTDEV */
 
+#ifdef CONFIG_PCI_IOV
+extern int pci_enable_sriov(struct pci_dev *dev, int nr_virtfn);
+extern void pci_disable_sriov(struct pci_dev *dev);
+#else
+static inline int pci_enable_sriov(struct pci_dev *dev, int nr_virtfn)
+{
+       return -ENODEV;
+}
+static inline void pci_disable_sriov(struct pci_dev *dev)
+{
+}
+#endif
+
 #endif /* __KERNEL__ */
 #endif /* LINUX_PCI_H */

_______________________________________________
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] PCI: add SR-IOV API for Physical Function driver, Xen patchbot-linux-2.6.18-xen <=