xref: /linux/arch/sh/mm/consistent.c (revision f3d9478b2ce468c3115b02ecae7e975990697f15)
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 
14 void *consistent_alloc(gfp_t gfp, size_t size, dma_addr_t *handle)
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 	split_page(page, order);
27 
28 	ret = page_address(page);
29 	*handle = virt_to_phys(ret);
30 
31 	/*
32 	 * We must flush the cache before we pass it on to the device
33 	 */
34 	dma_cache_wback_inv(ret, size);
35 
36 	page = virt_to_page(ret);
37 	free = page + (size >> PAGE_SHIFT);
38 	end  = page + (1 << order);
39 
40 	while (++page < end) {
41 		/* Free any unused pages */
42 		if (page >= free) {
43 			__free_page(page);
44 		}
45 	}
46 
47 	return P2SEGADDR(ret);
48 }
49 
50 void consistent_free(void *vaddr, size_t size)
51 {
52 	unsigned long addr = P1SEGADDR((unsigned long)vaddr);
53 	struct page *page=virt_to_page(addr);
54 	int num_pages=(size+PAGE_SIZE-1) >> PAGE_SHIFT;
55 	int i;
56 
57 	for(i=0;i<num_pages;i++) {
58 		__free_page((page+i));
59 	}
60 }
61 
62 void consistent_sync(void *vaddr, size_t size, int direction)
63 {
64 	void * p1addr = (void*) P1SEGADDR((unsigned long)vaddr);
65 
66 	switch (direction) {
67 	case DMA_FROM_DEVICE:		/* invalidate only */
68 		dma_cache_inv(p1addr, size);
69 		break;
70 	case DMA_TO_DEVICE:		/* writeback only */
71 		dma_cache_wback(p1addr, size);
72 		break;
73 	case DMA_BIDIRECTIONAL:		/* writeback and invalidate */
74 		dma_cache_wback_inv(p1addr, size);
75 		break;
76 	default:
77 		BUG();
78 	}
79 }
80 
81 EXPORT_SYMBOL(consistent_alloc);
82 EXPORT_SYMBOL(consistent_free);
83 EXPORT_SYMBOL(consistent_sync);
84 
85