Merge tag 'arc-4.6-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/vgupta/arc
[linux-2.6-block.git] / arch / arc / mm / ioremap.c
index 739e65f355deac569d68e6fa6bff3d18bce73e3a..49b8abd1115c284251557bb745a612bed66c0e1b 100644 (file)
 #include <linux/slab.h>
 #include <linux/cache.h>
 
-void __iomem *ioremap(unsigned long paddr, unsigned long size)
+static inline bool arc_uncached_addr_space(phys_addr_t paddr)
 {
-       unsigned long end;
+       if (is_isa_arcompact()) {
+               if (paddr >= ARC_UNCACHED_ADDR_SPACE)
+                       return true;
+       } else if (paddr >= perip_base && paddr <= 0xFFFFFFFF) {
+               return true;
+       }
+
+       return false;
+}
+
+void __iomem *ioremap(phys_addr_t paddr, unsigned long size)
+{
+       phys_addr_t end;
 
        /* Don't allow wraparound or zero size */
        end = paddr + size - 1;
        if (!size || (end < paddr))
                return NULL;
 
-       /* If the region is h/w uncached, avoid MMU mappings */
-       if (paddr >= ARC_UNCACHED_ADDR_SPACE)
-               return (void __iomem *)paddr;
+       /*
+        * If the region is h/w uncached, MMU mapping can be elided as optim
+        * The cast to u32 is fine as this region can only be inside 4GB
+        */
+       if (arc_uncached_addr_space(paddr))
+               return (void __iomem *)(u32)paddr;
 
        return ioremap_prot(paddr, size, PAGE_KERNEL_NO_CACHE);
 }
@@ -41,9 +56,9 @@ EXPORT_SYMBOL(ioremap);
 void __iomem *ioremap_prot(phys_addr_t paddr, unsigned long size,
                           unsigned long flags)
 {
-       void __iomem *vaddr;
+       unsigned long vaddr;
        struct vm_struct *area;
-       unsigned long off, end;
+       phys_addr_t off, end;
        pgprot_t prot = __pgprot(flags);
 
        /* Don't allow wraparound, zero size */
@@ -70,9 +85,8 @@ void __iomem *ioremap_prot(phys_addr_t paddr, unsigned long size,
        if (!area)
                return NULL;
        area->phys_addr = paddr;
-       vaddr = (void __iomem *)area->addr;
-       if (ioremap_page_range((unsigned long)vaddr,
-                              (unsigned long)vaddr + size, paddr, prot)) {
+       vaddr = (unsigned long)area->addr;
+       if (ioremap_page_range(vaddr, vaddr + size, paddr, prot)) {
                vunmap((void __force *)vaddr);
                return NULL;
        }
@@ -83,7 +97,8 @@ EXPORT_SYMBOL(ioremap_prot);
 
 void iounmap(const void __iomem *addr)
 {
-       if (addr >= (void __force __iomem *)ARC_UNCACHED_ADDR_SPACE)
+       /* weird double cast to handle phys_addr_t > 32 bits */
+       if (arc_uncached_addr_space((phys_addr_t)(u32)addr))
                return;
 
        vfree((void *)(PAGE_MASK & (unsigned long __force)addr));