| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1 | /* | 
 | 2 |  * arch/sh/mm/consistent.c | 
 | 3 |  * | 
 | 4 |  * Copyright (C) 2004  Paul Mundt | 
 | 5 |  * | 
 | 6 |  * This file is subject to the terms and conditions of the GNU General Public | 
 | 7 |  * License.  See the file "COPYING" in the main directory of this archive | 
 | 8 |  * for more details. | 
 | 9 |  */ | 
 | 10 | #include <linux/mm.h> | 
 | 11 | #include <linux/dma-mapping.h> | 
 | 12 | #include <asm/io.h> | 
 | 13 |  | 
| Al Viro | 6dae2c2 | 2005-10-21 03:21:38 -0400 | [diff] [blame] | 14 | void *consistent_alloc(gfp_t gfp, size_t size, dma_addr_t *handle) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 15 | { | 
 | 16 | 	struct page *page, *end, *free; | 
 | 17 | 	void *ret; | 
 | 18 | 	int order; | 
 | 19 |  | 
 | 20 | 	size = PAGE_ALIGN(size); | 
 | 21 | 	order = get_order(size); | 
 | 22 |  | 
 | 23 | 	page = alloc_pages(gfp, order); | 
 | 24 | 	if (!page) | 
 | 25 | 		return NULL; | 
 | 26 |  | 
 | 27 | 	ret = page_address(page); | 
 | 28 | 	*handle = virt_to_phys(ret); | 
 | 29 |  | 
 | 30 | 	/* | 
 | 31 | 	 * We must flush the cache before we pass it on to the device | 
 | 32 | 	 */ | 
 | 33 | 	dma_cache_wback_inv(ret, size); | 
 | 34 |  | 
 | 35 | 	page = virt_to_page(ret); | 
 | 36 | 	free = page + (size >> PAGE_SHIFT); | 
 | 37 | 	end  = page + (1 << order); | 
 | 38 |  | 
 | 39 | 	while (++page < end) { | 
 | 40 | 		set_page_count(page, 1); | 
 | 41 |  | 
 | 42 | 		/* Free any unused pages */ | 
 | 43 | 		if (page >= free) { | 
 | 44 | 			__free_page(page); | 
 | 45 | 		} | 
 | 46 | 	} | 
 | 47 |  | 
 | 48 | 	return P2SEGADDR(ret); | 
 | 49 | } | 
 | 50 |  | 
 | 51 | void consistent_free(void *vaddr, size_t size) | 
 | 52 | { | 
 | 53 | 	unsigned long addr = P1SEGADDR((unsigned long)vaddr); | 
 | 54 | 	struct page *page=virt_to_page(addr); | 
 | 55 | 	int num_pages=(size+PAGE_SIZE-1) >> PAGE_SHIFT; | 
 | 56 | 	int i; | 
 | 57 |  | 
 | 58 | 	for(i=0;i<num_pages;i++) { | 
 | 59 | 		__free_page((page+i)); | 
 | 60 | 	} | 
 | 61 | } | 
 | 62 |  | 
 | 63 | void consistent_sync(void *vaddr, size_t size, int direction) | 
 | 64 | { | 
 | 65 | 	void * p1addr = (void*) P1SEGADDR((unsigned long)vaddr); | 
 | 66 |  | 
 | 67 | 	switch (direction) { | 
 | 68 | 	case DMA_FROM_DEVICE:		/* invalidate only */ | 
 | 69 | 		dma_cache_inv(p1addr, size); | 
 | 70 | 		break; | 
 | 71 | 	case DMA_TO_DEVICE:		/* writeback only */ | 
 | 72 | 		dma_cache_wback(p1addr, size); | 
 | 73 | 		break; | 
 | 74 | 	case DMA_BIDIRECTIONAL:		/* writeback and invalidate */ | 
 | 75 | 		dma_cache_wback_inv(p1addr, size); | 
 | 76 | 		break; | 
 | 77 | 	default: | 
 | 78 | 		BUG(); | 
 | 79 | 	} | 
 | 80 | } | 
 | 81 |  | 
 | 82 | EXPORT_SYMBOL(consistent_alloc); | 
 | 83 | EXPORT_SYMBOL(consistent_free); | 
 | 84 | EXPORT_SYMBOL(consistent_sync); | 
 | 85 |  |