PCI: Keep individual VF BAR size in struct pci_sriov
authorWei Yang <weiyang@linux.vnet.ibm.com>
Wed, 25 Mar 2015 08:23:44 +0000 (16:23 +0800)
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>
Tue, 31 Mar 2015 02:02:35 +0000 (13:02 +1100)
Currently we don't store the individual VF BAR size.  We calculate it when
needed by dividing the PF's IOV resource size (which contains space for
*all* the VFs) by total_VFs or by reading the BAR in the SR-IOV capability
again.

Keep the individual VF BAR size in struct pci_sriov.barsz[], add
pci_iov_resource_size() to retrieve it, and use that instead of doing the
division or reading the SR-IOV capability BAR.

[bhelgaas: rename to "barsz[]", simplify barsz[] index computation, remove
SR-IOV capability BAR sizing]
Signed-off-by: Wei Yang <weiyang@linux.vnet.ibm.com>
Acked-by: Bjorn Helgaas <bhelgaas@google.com>
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
drivers/pci/iov.c
drivers/pci/pci.h
include/linux/pci.h

index 05f9d97e4175ec9a50b2488f93c90bdc85170927..5bca0e1a279945307f6b484257eefd044e810152 100644 (file)
@@ -57,6 +57,14 @@ static void virtfn_remove_bus(struct pci_bus *physbus, struct pci_bus *virtbus)
                pci_remove_bus(virtbus);
 }
 
+resource_size_t pci_iov_resource_size(struct pci_dev *dev, int resno)
+{
+       if (!dev->is_physfn)
+               return 0;
+
+       return dev->sriov->barsz[resno - PCI_IOV_RESOURCES];
+}
+
 static int virtfn_add(struct pci_dev *dev, int id, int reset)
 {
        int i;
@@ -92,8 +100,7 @@ static int virtfn_add(struct pci_dev *dev, int id, int reset)
                        continue;
                virtfn->resource[i].name = pci_name(virtfn);
                virtfn->resource[i].flags = res->flags;
-               size = resource_size(res);
-               do_div(size, iov->total_VFs);
+               size = pci_iov_resource_size(dev, i + PCI_IOV_RESOURCES);
                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]);
@@ -311,7 +318,7 @@ static void sriov_disable(struct pci_dev *dev)
 
 static int sriov_init(struct pci_dev *dev, int pos)
 {
-       int i;
+       int i, bar64;
        int rc;
        int nres;
        u32 pgsz;
@@ -360,29 +367,29 @@ found:
        pgsz &= ~(pgsz - 1);
        pci_write_config_dword(dev, pos + PCI_SRIOV_SYS_PGSIZE, pgsz);
 
+       iov = kzalloc(sizeof(*iov), GFP_KERNEL);
+       if (!iov)
+               return -ENOMEM;
+
        nres = 0;
        for (i = 0; i < PCI_SRIOV_NUM_BARS; i++) {
                res = dev->resource + PCI_IOV_RESOURCES + i;
-               i += __pci_read_base(dev, pci_bar_unknown, res,
-                                    pos + PCI_SRIOV_BAR + i * 4);
+               bar64 = __pci_read_base(dev, pci_bar_unknown, res,
+                                       pos + PCI_SRIOV_BAR + i * 4);
                if (!res->flags)
                        continue;
                if (resource_size(res) & (PAGE_SIZE - 1)) {
                        rc = -EIO;
                        goto failed;
                }
+               iov->barsz[i] = resource_size(res);
                res->end = res->start + resource_size(res) * total - 1;
                dev_info(&dev->dev, "VF(n) BAR%d space: %pR (contains BAR%d for %d VFs)\n",
                         i, res, i, total);
+               i += bar64;
                nres++;
        }
 
-       iov = kzalloc(sizeof(*iov), GFP_KERNEL);
-       if (!iov) {
-               rc = -ENOMEM;
-               goto failed;
-       }
-
        iov->pos = pos;
        iov->nres = nres;
        iov->ctrl = ctrl;
@@ -414,6 +421,7 @@ failed:
                res->flags = 0;
        }
 
+       kfree(iov);
        return rc;
 }
 
@@ -510,14 +518,7 @@ int pci_iov_resource_bar(struct pci_dev *dev, int resno)
  */
 resource_size_t pci_sriov_resource_alignment(struct pci_dev *dev, int resno)
 {
-       struct resource tmp;
-       int reg = pci_iov_resource_bar(dev, resno);
-
-       if (!reg)
-               return 0;
-
-        __pci_read_base(dev, pci_bar_unknown, &tmp, reg);
-       return resource_alignment(&tmp);
+       return pci_iov_resource_size(dev, resno);
 }
 
 /**
index 4091f82239cdb86141bb3dfd34e583bff8b027db..57329645dd018a096b200064f93bbf37ab01a515 100644 (file)
@@ -247,6 +247,7 @@ struct pci_sriov {
        struct pci_dev *dev;    /* lowest numbered PF */
        struct pci_dev *self;   /* this PF */
        struct mutex lock;      /* lock for VF bus */
+       resource_size_t barsz[PCI_SRIOV_NUM_BARS];      /* VF BAR size */
 };
 
 #ifdef CONFIG_PCI_ATS
index 211e9da8a7d79df19261f2887f6d972ef11733b6..15596582e5757b8bcfbf4a45c4a43f13769550d6 100644 (file)
@@ -1675,6 +1675,7 @@ int pci_num_vf(struct pci_dev *dev);
 int pci_vfs_assigned(struct pci_dev *dev);
 int pci_sriov_set_totalvfs(struct pci_dev *dev, u16 numvfs);
 int pci_sriov_get_totalvfs(struct pci_dev *dev);
+resource_size_t pci_iov_resource_size(struct pci_dev *dev, int resno);
 #else
 static inline int pci_enable_sriov(struct pci_dev *dev, int nr_virtfn)
 { return -ENODEV; }
@@ -1686,6 +1687,8 @@ static inline int pci_sriov_set_totalvfs(struct pci_dev *dev, u16 numvfs)
 { return 0; }
 static inline int pci_sriov_get_totalvfs(struct pci_dev *dev)
 { return 0; }
+static inline resource_size_t pci_iov_resource_size(struct pci_dev *dev, int resno)
+{ return 0; }
 #endif
 
 #if defined(CONFIG_HOTPLUG_PCI) || defined(CONFIG_HOTPLUG_PCI_MODULE)