iommu/dma: Explicitly sort PCI DMA windows
[linux-2.6-microblaze.git] / drivers / iommu / dma-iommu.c
index 8e0ed40..f902515 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/iommu.h>
 #include <linux/iova.h>
 #include <linux/irq.h>
+#include <linux/list_sort.h>
 #include <linux/mm.h>
 #include <linux/mutex.h>
 #include <linux/pci.h>
@@ -414,6 +415,15 @@ static int cookie_init_hw_msi_region(struct iommu_dma_cookie *cookie,
        return 0;
 }
 
+static int iommu_dma_ranges_sort(void *priv, const struct list_head *a,
+               const struct list_head *b)
+{
+       struct resource_entry *res_a = list_entry(a, typeof(*res_a), node);
+       struct resource_entry *res_b = list_entry(b, typeof(*res_b), node);
+
+       return res_a->res->start > res_b->res->start;
+}
+
 static int iova_reserve_pci_windows(struct pci_dev *dev,
                struct iova_domain *iovad)
 {
@@ -432,6 +442,7 @@ static int iova_reserve_pci_windows(struct pci_dev *dev,
        }
 
        /* Get reserved DMA windows from host bridge */
+       list_sort(NULL, &bridge->dma_ranges, iommu_dma_ranges_sort);
        resource_list_for_each_entry(window, &bridge->dma_ranges) {
                end = window->res->start - window->offset;
 resv_iova:
@@ -440,7 +451,7 @@ resv_iova:
                        hi = iova_pfn(iovad, end);
                        reserve_iova(iovad, lo, hi);
                } else if (end < start) {
-                       /* dma_ranges list should be sorted */
+                       /* DMA ranges should be non-overlapping */
                        dev_err(&dev->dev,
                                "Failed to reserve IOVA [%pa-%pa]\n",
                                &start, &end);