Merge branch 'irq-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[platform/kernel/linux-starfive.git] / drivers / iommu / dma-iommu.c
index 13916fe..129c4ba 100644 (file)
@@ -206,12 +206,13 @@ static int cookie_init_hw_msi_region(struct iommu_dma_cookie *cookie,
        return 0;
 }
 
-static void iova_reserve_pci_windows(struct pci_dev *dev,
+static int iova_reserve_pci_windows(struct pci_dev *dev,
                struct iova_domain *iovad)
 {
        struct pci_host_bridge *bridge = pci_find_host_bridge(dev->bus);
        struct resource_entry *window;
        unsigned long lo, hi;
+       phys_addr_t start = 0, end;
 
        resource_list_for_each_entry(window, &bridge->windows) {
                if (resource_type(window->res) != IORESOURCE_MEM)
@@ -221,6 +222,31 @@ static void iova_reserve_pci_windows(struct pci_dev *dev,
                hi = iova_pfn(iovad, window->res->end - window->offset);
                reserve_iova(iovad, lo, hi);
        }
+
+       /* Get reserved DMA windows from host bridge */
+       resource_list_for_each_entry(window, &bridge->dma_ranges) {
+               end = window->res->start - window->offset;
+resv_iova:
+               if (end > start) {
+                       lo = iova_pfn(iovad, start);
+                       hi = iova_pfn(iovad, end);
+                       reserve_iova(iovad, lo, hi);
+               } else {
+                       /* dma_ranges list should be sorted */
+                       dev_err(&dev->dev, "Failed to reserve IOVA\n");
+                       return -EINVAL;
+               }
+
+               start = window->res->end - window->offset + 1;
+               /* If window is last entry */
+               if (window->node.next == &bridge->dma_ranges &&
+                   end != ~(dma_addr_t)0) {
+                       end = ~(dma_addr_t)0;
+                       goto resv_iova;
+               }
+       }
+
+       return 0;
 }
 
 static int iova_reserve_iommu_regions(struct device *dev,
@@ -232,8 +258,11 @@ static int iova_reserve_iommu_regions(struct device *dev,
        LIST_HEAD(resv_regions);
        int ret = 0;
 
-       if (dev_is_pci(dev))
-               iova_reserve_pci_windows(to_pci_dev(dev), iovad);
+       if (dev_is_pci(dev)) {
+               ret = iova_reserve_pci_windows(to_pci_dev(dev), iovad);
+               if (ret)
+                       return ret;
+       }
 
        iommu_get_resv_regions(dev, &resv_regions);
        list_for_each_entry(region, &resv_regions, list) {
@@ -619,17 +648,7 @@ out_free_pages:
 
 int iommu_dma_mmap(struct page **pages, size_t size, struct vm_area_struct *vma)
 {
-       unsigned long uaddr = vma->vm_start;
-       unsigned int i, count = PAGE_ALIGN(size) >> PAGE_SHIFT;
-       int ret = -ENXIO;
-
-       for (i = vma->vm_pgoff; i < count && uaddr < vma->vm_end; i++) {
-               ret = vm_insert_page(vma, uaddr, pages[i]);
-               if (ret)
-                       break;
-               uaddr += PAGE_SIZE;
-       }
-       return ret;
+       return vm_map_pages(vma, pages, PAGE_ALIGN(size) >> PAGE_SHIFT);
 }
 
 static dma_addr_t __iommu_dma_map(struct device *dev, phys_addr_t phys,