Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * arch/sh/mm/consistent.c | |
3 | * | |
8a7bcf0d | 4 | * Copyright (C) 2004 - 2007 Paul Mundt |
1da177e4 LT |
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> | |
26ff6c11 PM |
12 | #include <asm/cacheflush.h> |
13 | #include <asm/addrspace.h> | |
1da177e4 LT |
14 | #include <asm/io.h> |
15 | ||
6dae2c23 | 16 | void *consistent_alloc(gfp_t gfp, size_t size, dma_addr_t *handle) |
1da177e4 LT |
17 | { |
18 | struct page *page, *end, *free; | |
8a7bcf0d | 19 | void *ret, *vp; |
1da177e4 LT |
20 | int order; |
21 | ||
22 | size = PAGE_ALIGN(size); | |
23 | order = get_order(size); | |
24 | ||
25 | page = alloc_pages(gfp, order); | |
26 | if (!page) | |
27 | return NULL; | |
8dfcc9ba | 28 | split_page(page, order); |
1da177e4 LT |
29 | |
30 | ret = page_address(page); | |
31 | *handle = virt_to_phys(ret); | |
32 | ||
8a7bcf0d PM |
33 | vp = ioremap_nocache(*handle, size); |
34 | if (!vp) { | |
35 | free_pages((unsigned long)ret, order); | |
36 | return NULL; | |
37 | } | |
38 | ||
39 | memset(vp, 0, size); | |
40 | ||
1da177e4 LT |
41 | /* |
42 | * We must flush the cache before we pass it on to the device | |
43 | */ | |
8a7bcf0d | 44 | dma_cache_sync(NULL, ret, size, DMA_BIDIRECTIONAL); |
1da177e4 LT |
45 | |
46 | page = virt_to_page(ret); | |
47 | free = page + (size >> PAGE_SHIFT); | |
48 | end = page + (1 << order); | |
49 | ||
50 | while (++page < end) { | |
1da177e4 LT |
51 | /* Free any unused pages */ |
52 | if (page >= free) { | |
53 | __free_page(page); | |
54 | } | |
55 | } | |
56 | ||
8a7bcf0d | 57 | return vp; |
1da177e4 | 58 | } |
8a7bcf0d | 59 | EXPORT_SYMBOL(consistent_alloc); |
1da177e4 | 60 | |
8a7bcf0d | 61 | void consistent_free(void *vaddr, size_t size, dma_addr_t dma_handle) |
1da177e4 | 62 | { |
8a7bcf0d PM |
63 | struct page *page; |
64 | unsigned long addr; | |
1da177e4 | 65 | |
8a7bcf0d PM |
66 | addr = (unsigned long)phys_to_virt((unsigned long)dma_handle); |
67 | page = virt_to_page(addr); | |
68 | ||
69 | free_pages(addr, get_order(size)); | |
70 | ||
71 | iounmap(vaddr); | |
1da177e4 | 72 | } |
8a7bcf0d | 73 | EXPORT_SYMBOL(consistent_free); |
1da177e4 LT |
74 | |
75 | void consistent_sync(void *vaddr, size_t size, int direction) | |
76 | { | |
8a7bcf0d PM |
77 | #ifdef CONFIG_CPU_SH5 |
78 | void *p1addr = vaddr; | |
79 | #else | |
80 | void *p1addr = (void*) P1SEGADDR((unsigned long)vaddr); | |
81 | #endif | |
1da177e4 LT |
82 | |
83 | switch (direction) { | |
84 | case DMA_FROM_DEVICE: /* invalidate only */ | |
622a9edd | 85 | __flush_invalidate_region(p1addr, size); |
1da177e4 LT |
86 | break; |
87 | case DMA_TO_DEVICE: /* writeback only */ | |
622a9edd | 88 | __flush_wback_region(p1addr, size); |
1da177e4 LT |
89 | break; |
90 | case DMA_BIDIRECTIONAL: /* writeback and invalidate */ | |
622a9edd | 91 | __flush_purge_region(p1addr, size); |
1da177e4 LT |
92 | break; |
93 | default: | |
94 | BUG(); | |
95 | } | |
96 | } | |
1da177e4 | 97 | EXPORT_SYMBOL(consistent_sync); |