Merge remote-tracking branch 'origin/dev/sumit-linux-3.10.96' into TOT-merge
[linux-3.10.git] / arch / arm / mm / dma-mapping.c
index 96bf7d6..ff01976 100644 (file)
@@ -434,7 +434,13 @@ void __init dma_contiguous_remap(void)
                map.type = MT_MEMORY;
 
                /*
-                * Clear previous low-memory mapping
+                * Clear previous low-memory mapping to ensure that the
+                * TLB does not see any conflicting entries, then flush
+                * the TLB of the old entries before creating new mappings.
+                *
+                * This ensures that any speculatively loaded TLB entries
+                * (even though they may be rare) can not cause any problems,
+                * and ensures that this code is architecturally compliant.
                 */
                for (addr = __phys_to_virt(start); addr < __phys_to_virt(end);
                     addr += PMD_SIZE)
@@ -1312,6 +1318,9 @@ static inline dma_addr_t __alloc_iova(struct dma_iommu_mapping *mapping,
        if (order > CONFIG_ARM_DMA_IOMMU_ALIGNMENT)
                order = CONFIG_ARM_DMA_IOMMU_ALIGNMENT;
 
+       if (mapping->alignment && order > get_order(mapping->alignment))
+               order = get_order(mapping->alignment);
+
        count = ((PAGE_ALIGN(size) >> PAGE_SHIFT) +
                 (1 << mapping->order) - 1) >> mapping->order;
 
@@ -1741,12 +1750,19 @@ static int arm_iommu_mmap_attrs(struct device *dev, struct vm_area_struct *vma,
        unsigned long uaddr = vma->vm_start;
        unsigned long usize = vma->vm_end - vma->vm_start;
        struct page **pages = __iommu_get_pages(cpu_addr, attrs);
+       unsigned long nr_pages = PAGE_ALIGN(size) >> PAGE_SHIFT;
+       unsigned long off = vma->vm_pgoff;
 
        vma->vm_page_prot = __get_dma_pgprot(attrs, vma->vm_page_prot);
 
        if (!pages)
                return -ENXIO;
 
+       if (off >= nr_pages || (usize >> PAGE_SHIFT) > nr_pages - off)
+               return -ENXIO;
+
+       pages += off;
+
        do {
                int ret = vm_insert_page(vma, uaddr, *pages++);
                if (ret) {
@@ -2391,13 +2407,6 @@ arm_iommu_create_mapping(struct bus_type *bus, dma_addr_t base, size_t size,
        struct dma_iommu_mapping *mapping;
        int err = -ENOMEM;
 
-       /*
-        * Upstream kernel is modified to remove order. To mimic the same
-        * behavior downstream, it is enough to keep order = 0.
-        * So, do not allow non zero order.
-        */
-       BUG_ON(order);
-
        if (!count)
                return ERR_PTR(-EINVAL);