Merge master.kernel.org:/pub/scm/linux/kernel/git/jejb/scsi-rc-fixes-2.6
[sfrench/cifs-2.6.git] / lib / devres.c
index 2a668dd7cac7cb81e6cc44e1ebe61e12225e3934..b1d336ce7f3d0c34f694844c8bd7dfd0f1dc687d 100644 (file)
@@ -274,21 +274,21 @@ int pcim_iomap_regions(struct pci_dev *pdev, u16 mask, const char *name)
 
                rc = pci_request_region(pdev, i, name);
                if (rc)
-                       goto err_region;
+                       goto err_inval;
 
                rc = -ENOMEM;
                if (!pcim_iomap(pdev, i, 0))
-                       goto err_iomap;
+                       goto err_region;
        }
 
        return 0;
 
- err_iomap:
-       pcim_iounmap(pdev, iomap[i]);
  err_region:
        pci_release_region(pdev, i);
  err_inval:
        while (--i >= 0) {
+               if (!(mask & (1 << i)))
+                       continue;
                pcim_iounmap(pdev, iomap[i]);
                pci_release_region(pdev, i);
        }
@@ -296,5 +296,31 @@ int pcim_iomap_regions(struct pci_dev *pdev, u16 mask, const char *name)
        return rc;
 }
 EXPORT_SYMBOL(pcim_iomap_regions);
+
+/**
+ * pcim_iounmap_regions - Unmap and release PCI BARs
+ * @pdev: PCI device to map IO resources for
+ * @mask: Mask of BARs to unmap and release
+ *
+ * Unamp and release regions specified by @mask.
+ */
+void pcim_iounmap_regions(struct pci_dev *pdev, u16 mask)
+{
+       void __iomem * const *iomap;
+       int i;
+
+       iomap = pcim_iomap_table(pdev);
+       if (!iomap)
+               return;
+
+       for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
+               if (!(mask & (1 << i)))
+                       continue;
+
+               pcim_iounmap(pdev, iomap[i]);
+               pci_release_region(pdev, i);
+       }
+}
+EXPORT_SYMBOL(pcim_iounmap_regions);
 #endif
 #endif