[ARM] make page_to_dma() highmem aware

If a machine class has a custom __virt_to_bus() implementation then it
must provide a __arch_page_to_dma() implementation as well which is
_not_ based on page_address() to support highmem.

This patch fixes existing __arch_page_to_dma() and provide a default
implementation otherwise.  The default implementation for highmem is
based on __pfn_to_bus() which is defined only when no custom
__virt_to_bus() is provided by the machine class.

That leaves only ebsa110 and footbridge which cannot support highmem
until they provide their own __arch_page_to_dma() implementation.
But highmem support on those legacy platforms with limited memory is
certainly not a priority.

Signed-off-by: Nicolas Pitre <nico@marvell.com>
diff --git a/arch/arm/common/dmabounce.c b/arch/arm/common/dmabounce.c
index f030f07..734ac91 100644
--- a/arch/arm/common/dmabounce.c
+++ b/arch/arm/common/dmabounce.c
@@ -25,6 +25,7 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/slab.h>
+#include <linux/page-flags.h>
 #include <linux/device.h>
 #include <linux/dma-mapping.h>
 #include <linux/dmapool.h>
@@ -349,6 +350,12 @@
 
 	BUG_ON(!valid_dma_direction(dir));
 
+	if (PageHighMem(page)) {
+		dev_err(dev, "DMA buffer bouncing of HIGHMEM pages "
+			     "is not supported\n");
+		return ~0;
+	}
+
 	return map_single(dev, page_address(page) + offset, size, dir);
 }
 EXPORT_SYMBOL(dma_map_page);
diff --git a/arch/arm/include/asm/dma-mapping.h b/arch/arm/include/asm/dma-mapping.h
index 59fa762..ff46dfa 100644
--- a/arch/arm/include/asm/dma-mapping.h
+++ b/arch/arm/include/asm/dma-mapping.h
@@ -15,10 +15,20 @@
  * must not be used by drivers.
  */
 #ifndef __arch_page_to_dma
+
+#if !defined(CONFIG_HIGHMEM)
 static inline dma_addr_t page_to_dma(struct device *dev, struct page *page)
 {
 	return (dma_addr_t)__virt_to_bus((unsigned long)page_address(page));
 }
+#elif defined(__pfn_to_bus)
+static inline dma_addr_t page_to_dma(struct device *dev, struct page *page)
+{
+	return (dma_addr_t)__pfn_to_bus(page_to_pfn(page));
+}
+#else
+#error "this machine class needs to define __arch_page_to_dma to use HIGHMEM"
+#endif
 
 static inline void *dma_to_virt(struct device *dev, dma_addr_t addr)
 {
diff --git a/arch/arm/include/asm/memory.h b/arch/arm/include/asm/memory.h
index ae472bc..85763db 100644
--- a/arch/arm/include/asm/memory.h
+++ b/arch/arm/include/asm/memory.h
@@ -188,6 +188,7 @@
 #ifndef __virt_to_bus
 #define __virt_to_bus	__virt_to_phys
 #define __bus_to_virt	__phys_to_virt
+#define __pfn_to_bus(x)	((x) << PAGE_SHIFT)
 #endif
 
 static inline __deprecated unsigned long virt_to_bus(void *x)
diff --git a/arch/arm/mach-iop13xx/include/mach/memory.h b/arch/arm/mach-iop13xx/include/mach/memory.h
index e012bf1..42ae29b 100644
--- a/arch/arm/mach-iop13xx/include/mach/memory.h
+++ b/arch/arm/mach-iop13xx/include/mach/memory.h
@@ -59,7 +59,10 @@
 	})
 
 #define __arch_page_to_dma(dev, page)					\
-	__arch_virt_to_dma(dev, page_address(page))
+	({								\
+		/* __is_lbus_virt() can never be true for RAM pages */	\
+		(dma_addr_t)page_to_phys(page);				\
+	})
 
 #endif /* CONFIG_ARCH_IOP13XX */
 #endif /* !ASSEMBLY */
diff --git a/arch/arm/mach-ks8695/include/mach/memory.h b/arch/arm/mach-ks8695/include/mach/memory.h
index 6d5887c..76e5308 100644
--- a/arch/arm/mach-ks8695/include/mach/memory.h
+++ b/arch/arm/mach-ks8695/include/mach/memory.h
@@ -35,7 +35,11 @@
 					__phys_to_virt(x) : __bus_to_virt(x)); })
 #define __arch_virt_to_dma(dev, x)	({ is_lbus_device(dev) ? \
 					(dma_addr_t)__virt_to_phys(x) : (dma_addr_t)__virt_to_bus(x); })
-#define __arch_page_to_dma(dev, x)	__arch_virt_to_dma(dev, page_address(x))
+#define __arch_page_to_dma(dev, x)	\
+	({ dma_addr_t __dma = page_to_phys(page); \
+	   if (!is_lbus_device(dev)) \
+		__dma = __dma - PHYS_OFFSET + KS8695_PCIMEM_PA; \
+	   __dma; })
 
 #endif
 
diff --git a/arch/arm/plat-omap/include/mach/memory.h b/arch/arm/plat-omap/include/mach/memory.h
index d6b5ca6..99ed564 100644
--- a/arch/arm/plat-omap/include/mach/memory.h
+++ b/arch/arm/plat-omap/include/mach/memory.h
@@ -61,9 +61,11 @@
 #define lbus_to_virt(x)		((x) - OMAP1510_LB_OFFSET + PAGE_OFFSET)
 #define is_lbus_device(dev)	(cpu_is_omap15xx() && dev && (strncmp(dev_name(dev), "ohci", 4) == 0))
 
-#define __arch_page_to_dma(dev, page)	({is_lbus_device(dev) ? \
-					(dma_addr_t)virt_to_lbus(page_address(page)) : \
-					(dma_addr_t)__virt_to_phys(page_address(page));})
+#define __arch_page_to_dma(dev, page)	\
+	({ dma_addr_t __dma = page_to_phys(page); \
+	   if (is_lbus_device(dev)) \
+		__dma = __dma - PHYS_OFFSET + OMAP1510_LB_OFFSET; \
+	   __dma; })
 
 #define __arch_dma_to_virt(dev, addr)	({ (void *) (is_lbus_device(dev) ? \
 						lbus_to_virt(addr) : \