]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - drivers/pci/iov.c
Merge branches 'pci/aer', 'pci/hotplug', 'pci/misc', 'pci/msi', 'pci/resource' and...
[karo-tx-linux.git] / drivers / pci / iov.c
index ca400a9140de197249dfea5cadf48fd411c36496..31f31d460fc9de789d28d72365122224fa3b2551 100644 (file)
@@ -227,13 +227,18 @@ static void virtfn_remove(struct pci_dev *dev, int id, int reset)
 
 int __weak pcibios_sriov_enable(struct pci_dev *pdev, u16 num_vfs)
 {
-       return 0;
+       return 0;
+}
+
+int __weak pcibios_sriov_disable(struct pci_dev *pdev)
+{
+       return 0;
 }
 
 static int sriov_enable(struct pci_dev *dev, int nr_virtfn)
 {
        int rc;
-       int i, j;
+       int i;
        int nres;
        u16 initial;
        struct resource *res;
@@ -241,7 +246,6 @@ static int sriov_enable(struct pci_dev *dev, int nr_virtfn)
        struct pci_sriov *iov = dev->sriov;
        int bars = 0;
        int bus;
-       int retval;
 
        if (!nr_virtfn)
                return 0;
@@ -310,10 +314,10 @@ static int sriov_enable(struct pci_dev *dev, int nr_virtfn)
        if (nr_virtfn < initial)
                initial = nr_virtfn;
 
-       if ((retval = pcibios_sriov_enable(dev, initial))) {
-               dev_err(&dev->dev, "failure %d from pcibios_sriov_enable()\n",
-                       retval);
-               return retval;
+       rc = pcibios_sriov_enable(dev, initial);
+       if (rc) {
+               dev_err(&dev->dev, "failure %d from pcibios_sriov_enable()\n", rc);
+               goto err_pcibios;
        }
 
        for (i = 0; i < initial; i++) {
@@ -328,27 +332,24 @@ static int sriov_enable(struct pci_dev *dev, int nr_virtfn)
        return 0;
 
 failed:
-       for (j = 0; j < i; j++)
-               virtfn_remove(dev, j, 0);
+       while (i--)
+               virtfn_remove(dev, i, 0);
 
+       pcibios_sriov_disable(dev);
+err_pcibios:
        iov->ctrl &= ~(PCI_SRIOV_CTRL_VFE | PCI_SRIOV_CTRL_MSE);
        pci_cfg_access_lock(dev);
        pci_write_config_word(dev, iov->pos + PCI_SRIOV_CTRL, iov->ctrl);
-       pci_iov_set_numvfs(dev, 0);
        ssleep(1);
        pci_cfg_access_unlock(dev);
 
        if (iov->link != dev->devfn)
                sysfs_remove_link(&dev->dev.kobj, "dep_link");
 
+       pci_iov_set_numvfs(dev, 0);
        return rc;
 }
 
-int __weak pcibios_sriov_disable(struct pci_dev *pdev)
-{
-       return 0;
-}
-
 static void sriov_disable(struct pci_dev *dev)
 {
        int i;
@@ -428,8 +429,15 @@ found:
        nres = 0;
        for (i = 0; i < PCI_SRIOV_NUM_BARS; i++) {
                res = &dev->resource[i + PCI_IOV_RESOURCES];
-               bar64 = __pci_read_base(dev, pci_bar_unknown, res,
-                                       pos + PCI_SRIOV_BAR + i * 4);
+               /*
+                * If it is already FIXED, don't change it, something
+                * (perhaps EA or header fixups) wants it this way.
+                */
+               if (res->flags & IORESOURCE_PCI_FIXED)
+                       bar64 = (res->flags & IORESOURCE_MEM_64) ? 1 : 0;
+               else
+                       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)) {