[ARM] make page_to_dma() highmem aware
authorNicolas Pitre <nico@cam.org>
Tue, 9 Sep 2008 19:54:13 +0000 (15:54 -0400)
committerNicolas Pitre <nico@cam.org>
Mon, 16 Mar 2009 01:01:21 +0000 (21:01 -0400)
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>
arch/arm/common/dmabounce.c
arch/arm/include/asm/dma-mapping.h
arch/arm/include/asm/memory.h
arch/arm/mach-iop13xx/include/mach/memory.h
arch/arm/mach-ks8695/include/mach/memory.h
arch/arm/plat-omap/include/mach/memory.h

index f030f07..734ac91 100644 (file)
@@ -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 @@ dma_addr_t dma_map_page(struct device *dev, struct page *page,
 
        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);
index 59fa762..ff46dfa 100644 (file)
  * 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)
 {
index ae472bc..85763db 100644 (file)
@@ -188,6 +188,7 @@ static inline void *phys_to_virt(unsigned long x)
 #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)
index e012bf1..42ae29b 100644 (file)
@@ -59,7 +59,10 @@ static inline unsigned long __lbus_to_virt(dma_addr_t x)
        })
 
 #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 */
index 6d5887c..76e5308 100644 (file)
@@ -35,7 +35,11 @@ extern struct bus_type platform_bus_type;
                                        __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
 
index d6b5ca6..99ed564 100644 (file)
 #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) : \