1/* 2 * Copyright (C) 2004-2006 Atmel Corporation 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License version 2 as 6 * published by the Free Software Foundation. 7 */ 8 9#include <linux/dma-mapping.h> 10#include <linux/gfp.h> 11 12#include <asm/addrspace.h> 13#include <asm/cacheflush.h> 14 15void dma_cache_sync(struct device *dev, void *vaddr, size_t size, int direction) 16{ 17 /* 18 * No need to sync an uncached area 19 */ 20 if (PXSEG(vaddr) == P2SEG) 21 return; 22 23 switch (direction) { 24 case DMA_FROM_DEVICE: /* invalidate only */ 25 invalidate_dcache_region(vaddr, size); 26 break; 27 case DMA_TO_DEVICE: /* writeback only */ 28 clean_dcache_region(vaddr, size); 29 break; 30 case DMA_BIDIRECTIONAL: /* writeback and invalidate */ 31 flush_dcache_region(vaddr, size); 32 break; 33 default: 34 BUG(); 35 } 36} 37EXPORT_SYMBOL(dma_cache_sync); 38 39static struct page *__dma_alloc(struct device *dev, size_t size, 40 dma_addr_t *handle, gfp_t gfp) 41{ 42 struct page *page, *free, *end; 43 int order; 44 45 gfp &= ~(__GFP_COMP); 46 47 size = PAGE_ALIGN(size); 48 order = get_order(size); 49 50 page = alloc_pages(gfp, order); 51 if (!page) 52 return NULL; 53 split_page(page, order); 54 55 /* 56 * When accessing physical memory with valid cache data, we 57 * get a cache hit even if the virtual memory region is marked 58 * as uncached. 59 * 60 * Since the memory is newly allocated, there is no point in 61 * doing a writeback. If the previous owner cares, he should 62 * have flushed the cache before releasing the memory. 63 */ 64 invalidate_dcache_region(phys_to_virt(page_to_phys(page)), size); 65 66 *handle = page_to_bus(page); 67 free = page + (size >> PAGE_SHIFT); 68 end = page + (1 << order); 69 70 /* 71 * Free any unused pages 72 */ 73 while (free < end) { 74 __free_page(free); 75 free++; 76 } 77 78 return page; 79} 80 81static void __dma_free(struct device *dev, size_t size, 82 struct page *page, dma_addr_t handle) 83{ 84 struct page *end = page + (PAGE_ALIGN(size) >> PAGE_SHIFT); 85 86 while (page < end) 87 __free_page(page++); 88} 89 90void *dma_alloc_coherent(struct device *dev, size_t size, 91 dma_addr_t *handle, gfp_t gfp) 92{ 93 struct page *page; 94 void *ret = NULL; 95 96 page = __dma_alloc(dev, size, handle, gfp); 97 if (page) 98 ret = phys_to_uncached(page_to_phys(page)); 99 100 return ret; 101} 102EXPORT_SYMBOL(dma_alloc_coherent); 103 104void dma_free_coherent(struct device *dev, size_t size, 105 void *cpu_addr, dma_addr_t handle) 106{ 107 void *addr = phys_to_cached(uncached_to_phys(cpu_addr)); 108 struct page *page; 109 110 pr_debug("dma_free_coherent addr %p (phys %08lx) size %u\n", 111 cpu_addr, (unsigned long)handle, (unsigned)size); 112 BUG_ON(!virt_addr_valid(addr)); 113 page = virt_to_page(addr); 114 __dma_free(dev, size, page, handle); 115} 116EXPORT_SYMBOL(dma_free_coherent); 117 118void *dma_alloc_writecombine(struct device *dev, size_t size, 119 dma_addr_t *handle, gfp_t gfp) 120{ 121 struct page *page; 122 dma_addr_t phys; 123 124 page = __dma_alloc(dev, size, handle, gfp); 125 if (!page) 126 return NULL; 127 128 phys = page_to_phys(page); 129 *handle = phys; 130 131 /* Now, map the page into P3 with write-combining turned on */ 132 return __ioremap(phys, size, _PAGE_BUFFER); 133} 134EXPORT_SYMBOL(dma_alloc_writecombine); 135 136void dma_free_writecombine(struct device *dev, size_t size, 137 void *cpu_addr, dma_addr_t handle) 138{ 139 struct page *page; 140 141 iounmap(cpu_addr); 142 143 page = phys_to_page(handle); 144 __dma_free(dev, size, page, handle); 145} 146EXPORT_SYMBOL(dma_free_writecombine); 147