[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 f030f0775be7d11016d14ed4add82c16be38d254..734ac9135998d9efffb0a1b84c3a82416b31d325 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 59fa762e9c66f66d7cdde3f4a9beebc3e4faba92..ff46dfa68a97f99c3c3db8854dac35d31b062dbd 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 ae472bc376d3fee167ea761995cbed3f1dcc24ab..85763db87449f4f4c62947e30a2b6b0cf9a43e9e 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 e012bf13c95582d2a4a8b4fd5368dd2fa380097a..42ae29b288a1a93155da39ec4e823fca734fba2e 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 6d5887cf574286512c4321b668fdce3bc15d44cd..76e5308685a40e81e45dcc42c66312ef3e0f4d1f 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 d6b5ca6c7da20bf7790cd8497616aa1d6f4cc66f..99ed564d92774fe3d91e67f43a479ef6a21198d8 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) : \