Merge branch 'perf-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[safe/jmp/linux-2.6] / arch / powerpc / kernel / dma.c
index 41fdd48..6215062 100644 (file)
@@ -7,6 +7,8 @@
 
 #include <linux/device.h>
 #include <linux/dma-mapping.h>
+#include <linux/dma-debug.h>
+#include <linux/lmb.h>
 #include <asm/bug.h>
 #include <asm/abs_addr.h>
 
  * default the offset is PCI_DRAM_OFFSET.
  */
 
-static unsigned long get_dma_direct_offset(struct device *dev)
-{
-       if (dev)
-               return (unsigned long)dev->archdata.dma_data;
-
-       return PCI_DRAM_OFFSET;
-}
 
 void *dma_direct_alloc_coherent(struct device *dev, size_t size,
                                dma_addr_t *dma_handle, gfp_t flag)
 {
+       void *ret;
 #ifdef CONFIG_NOT_COHERENT_CACHE
-       return __dma_alloc_coherent(size, dma_handle, flag);
+       ret = __dma_alloc_coherent(dev, size, dma_handle, flag);
+       if (ret == NULL)
+               return NULL;
+       *dma_handle += get_dma_offset(dev);
+       return ret;
 #else
        struct page *page;
-       void *ret;
        int node = dev_to_node(dev);
 
        /* ignore region specifiers */
@@ -45,7 +44,7 @@ void *dma_direct_alloc_coherent(struct device *dev, size_t size,
                return NULL;
        ret = page_address(page);
        memset(ret, 0, size);
-       *dma_handle = virt_to_abs(ret) + get_dma_direct_offset(dev);
+       *dma_handle = virt_to_abs(ret) + get_dma_offset(dev);
 
        return ret;
 #endif
@@ -69,8 +68,9 @@ static int dma_direct_map_sg(struct device *dev, struct scatterlist *sgl,
        int i;
 
        for_each_sg(sgl, sg, nents, i) {
-               sg->dma_address = sg_phys(sg) + get_dma_direct_offset(dev);
+               sg->dma_address = sg_phys(sg) + get_dma_offset(dev);
                sg->dma_length = sg->length;
+               __dma_sync_page(sg_page(sg), sg->offset, sg->length, direction);
        }
 
        return nents;
@@ -85,11 +85,10 @@ static void dma_direct_unmap_sg(struct device *dev, struct scatterlist *sg,
 static int dma_direct_dma_supported(struct device *dev, u64 mask)
 {
 #ifdef CONFIG_PPC64
-       /* Could be improved to check for memory though it better be
-        * done via some global so platforms can set the limit in case
+       /* Could be improved so platforms can set the limit in case
         * they have limited DMA windows
         */
-       return mask >= DMA_32BIT_MASK;
+       return mask >= (lmb_end_of_DRAM() - 1);
 #else
        return 1;
 #endif
@@ -104,7 +103,7 @@ static inline dma_addr_t dma_direct_map_page(struct device *dev,
 {
        BUG_ON(dir == DMA_NONE);
        __dma_sync_page(page, offset, size, dir);
-       return page_to_phys(page) + offset + get_dma_direct_offset(dev);
+       return page_to_phys(page) + offset + get_dma_offset(dev);
 }
 
 static inline void dma_direct_unmap_page(struct device *dev,
@@ -115,7 +114,27 @@ static inline void dma_direct_unmap_page(struct device *dev,
 {
 }
 
-struct dma_mapping_ops dma_direct_ops = {
+#ifdef CONFIG_NOT_COHERENT_CACHE
+static inline void dma_direct_sync_sg(struct device *dev,
+               struct scatterlist *sgl, int nents,
+               enum dma_data_direction direction)
+{
+       struct scatterlist *sg;
+       int i;
+
+       for_each_sg(sgl, sg, nents, i)
+               __dma_sync_page(sg_page(sg), sg->offset, sg->length, direction);
+}
+
+static inline void dma_direct_sync_single_range(struct device *dev,
+               dma_addr_t dma_handle, unsigned long offset, size_t size,
+               enum dma_data_direction direction)
+{
+       __dma_sync(bus_to_virt(dma_handle+offset), size, direction);
+}
+#endif
+
+struct dma_map_ops dma_direct_ops = {
        .alloc_coherent = dma_direct_alloc_coherent,
        .free_coherent  = dma_direct_free_coherent,
        .map_sg         = dma_direct_map_sg,
@@ -123,5 +142,21 @@ struct dma_mapping_ops dma_direct_ops = {
        .dma_supported  = dma_direct_dma_supported,
        .map_page       = dma_direct_map_page,
        .unmap_page     = dma_direct_unmap_page,
+#ifdef CONFIG_NOT_COHERENT_CACHE
+       .sync_single_range_for_cpu      = dma_direct_sync_single_range,
+       .sync_single_range_for_device   = dma_direct_sync_single_range,
+       .sync_sg_for_cpu                = dma_direct_sync_sg,
+       .sync_sg_for_device             = dma_direct_sync_sg,
+#endif
 };
 EXPORT_SYMBOL(dma_direct_ops);
+
+#define PREALLOC_DMA_DEBUG_ENTRIES (1 << 16)
+
+static int __init dma_init(void)
+{
+       dma_debug_init(PREALLOC_DMA_DEBUG_ENTRIES);
+
+       return 0;
+}
+fs_initcall(dma_init);