diff options
Diffstat (limited to 'arch/sh/mm/consistent.c')
| -rw-r--r-- | arch/sh/mm/consistent.c | 77 |
1 files changed, 42 insertions, 35 deletions
diff --git a/arch/sh/mm/consistent.c b/arch/sh/mm/consistent.c index 64b8f7f96f9..b81d9dbf9fe 100644 --- a/arch/sh/mm/consistent.c +++ b/arch/sh/mm/consistent.c @@ -10,84 +10,91 @@ * for more details. */ #include <linux/mm.h> +#include <linux/init.h> #include <linux/platform_device.h> #include <linux/dma-mapping.h> +#include <linux/dma-debug.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/gfp.h> #include <asm/cacheflush.h> #include <asm/addrspace.h> -#include <asm/io.h> - -struct dma_coherent_mem { - void *virt_base; - u32 device_base; - int size; - int flags; - unsigned long *bitmap; -}; - -void *dma_alloc_coherent(struct device *dev, size_t size, - dma_addr_t *dma_handle, gfp_t gfp) + +#define PREALLOC_DMA_DEBUG_ENTRIES 4096 + +struct dma_map_ops *dma_ops; +EXPORT_SYMBOL(dma_ops); + +static int __init dma_init(void) +{ + dma_debug_init(PREALLOC_DMA_DEBUG_ENTRIES); + return 0; +} +fs_initcall(dma_init); + +void *dma_generic_alloc_coherent(struct device *dev, size_t size, + dma_addr_t *dma_handle, gfp_t gfp, + struct dma_attrs *attrs) { void *ret, *ret_nocache; int order = get_order(size); - if (dma_alloc_from_coherent(dev, size, dma_handle, &ret)) - return ret; + gfp |= __GFP_ZERO; ret = (void *)__get_free_pages(gfp, order); if (!ret) return NULL; - memset(ret, 0, size); /* * Pages from the page allocator may have data present in * cache. So flush the cache before using uncached memory. */ dma_cache_sync(dev, ret, size, DMA_BIDIRECTIONAL); - ret_nocache = ioremap_nocache(virt_to_phys(ret), size); + ret_nocache = (void __force *)ioremap_nocache(virt_to_phys(ret), size); if (!ret_nocache) { free_pages((unsigned long)ret, order); return NULL; } + split_page(pfn_to_page(virt_to_phys(ret) >> PAGE_SHIFT), order); + *dma_handle = virt_to_phys(ret); + return ret_nocache; } -EXPORT_SYMBOL(dma_alloc_coherent); -void dma_free_coherent(struct device *dev, size_t size, - void *vaddr, dma_addr_t dma_handle) +void dma_generic_free_coherent(struct device *dev, size_t size, + void *vaddr, dma_addr_t dma_handle, + struct dma_attrs *attrs) { - struct dma_coherent_mem *mem = dev ? dev->dma_mem : NULL; int order = get_order(size); + unsigned long pfn = dma_handle >> PAGE_SHIFT; + int k; - if (!dma_release_from_coherent(dev, order, vaddr)) { - WARN_ON(irqs_disabled()); /* for portability */ - BUG_ON(mem && mem->flags & DMA_MEMORY_EXCLUSIVE); - free_pages((unsigned long)phys_to_virt(dma_handle), order); - iounmap(vaddr); - } + for (k = 0; k < (1 << order); k++) + __free_pages(pfn_to_page(pfn + k), 0); + + iounmap(vaddr); } -EXPORT_SYMBOL(dma_free_coherent); void dma_cache_sync(struct device *dev, void *vaddr, size_t size, enum dma_data_direction direction) { -#ifdef CONFIG_CPU_SH5 - void *p1addr = vaddr; -#else - void *p1addr = (void*) P1SEGADDR((unsigned long)vaddr); -#endif + void *addr; + + addr = __in_29bit_mode() ? + (void *)CAC_ADDR((unsigned long)vaddr) : vaddr; switch (direction) { case DMA_FROM_DEVICE: /* invalidate only */ - __flush_invalidate_region(p1addr, size); + __flush_invalidate_region(addr, size); break; case DMA_TO_DEVICE: /* writeback only */ - __flush_wback_region(p1addr, size); + __flush_wback_region(addr, size); break; case DMA_BIDIRECTIONAL: /* writeback and invalidate */ - __flush_purge_region(p1addr, size); + __flush_purge_region(addr, size); break; default: BUG(); |
