]> nv-tegra.nvidia Code Review - linux-2.6.git/blob - arch/sh/mm/consistent.c
Merge branch 'merge' of git://git.kernel.org/pub/scm/linux/kernel/git/paulus/powerpc
[linux-2.6.git] / arch / sh / mm / consistent.c
1 /*
2  * arch/sh/mm/consistent.c
3  *
4  * Copyright (C) 2004 - 2007  Paul Mundt
5  *
6  * Declared coherent memory functions based on arch/x86/kernel/pci-dma_32.c
7  *
8  * This file is subject to the terms and conditions of the GNU General Public
9  * License.  See the file "COPYING" in the main directory of this archive
10  * for more details.
11  */
12 #include <linux/mm.h>
13 #include <linux/platform_device.h>
14 #include <linux/dma-mapping.h>
15 #include <asm/cacheflush.h>
16 #include <asm/addrspace.h>
17 #include <asm/io.h>
18
19 struct dma_coherent_mem {
20         void            *virt_base;
21         u32             device_base;
22         int             size;
23         int             flags;
24         unsigned long   *bitmap;
25 };
26
27 void *dma_alloc_coherent(struct device *dev, size_t size,
28                            dma_addr_t *dma_handle, gfp_t gfp)
29 {
30         void *ret, *ret_nocache;
31         int order = get_order(size);
32
33         if (dma_alloc_from_coherent(dev, size, dma_handle, &ret))
34                 return ret;
35
36         ret = (void *)__get_free_pages(gfp, order);
37         if (!ret)
38                 return NULL;
39
40         memset(ret, 0, size);
41         /*
42          * Pages from the page allocator may have data present in
43          * cache. So flush the cache before using uncached memory.
44          */
45         dma_cache_sync(dev, ret, size, DMA_BIDIRECTIONAL);
46
47         ret_nocache = ioremap_nocache(virt_to_phys(ret), size);
48         if (!ret_nocache) {
49                 free_pages((unsigned long)ret, order);
50                 return NULL;
51         }
52
53         *dma_handle = virt_to_phys(ret);
54         return ret_nocache;
55 }
56 EXPORT_SYMBOL(dma_alloc_coherent);
57
58 void dma_free_coherent(struct device *dev, size_t size,
59                          void *vaddr, dma_addr_t dma_handle)
60 {
61         struct dma_coherent_mem *mem = dev ? dev->dma_mem : NULL;
62         int order = get_order(size);
63
64         if (!dma_release_from_coherent(dev, order, vaddr)) {
65                 WARN_ON(irqs_disabled());       /* for portability */
66                 BUG_ON(mem && mem->flags & DMA_MEMORY_EXCLUSIVE);
67                 free_pages((unsigned long)phys_to_virt(dma_handle), order);
68                 iounmap(vaddr);
69         }
70 }
71 EXPORT_SYMBOL(dma_free_coherent);
72
73 void dma_cache_sync(struct device *dev, void *vaddr, size_t size,
74                     enum dma_data_direction direction)
75 {
76 #ifdef CONFIG_CPU_SH5
77         void *p1addr = vaddr;
78 #else
79         void *p1addr = (void*) P1SEGADDR((unsigned long)vaddr);
80 #endif
81
82         switch (direction) {
83         case DMA_FROM_DEVICE:           /* invalidate only */
84                 __flush_invalidate_region(p1addr, size);
85                 break;
86         case DMA_TO_DEVICE:             /* writeback only */
87                 __flush_wback_region(p1addr, size);
88                 break;
89         case DMA_BIDIRECTIONAL:         /* writeback and invalidate */
90                 __flush_purge_region(p1addr, size);
91                 break;
92         default:
93                 BUG();
94         }
95 }
96 EXPORT_SYMBOL(dma_cache_sync);
97
98 int platform_resource_setup_memory(struct platform_device *pdev,
99                                    char *name, unsigned long memsize)
100 {
101         struct resource *r;
102         dma_addr_t dma_handle;
103         void *buf;
104
105         r = pdev->resource + pdev->num_resources - 1;
106         if (r->flags) {
107                 pr_warning("%s: unable to find empty space for resource\n",
108                         name);
109                 return -EINVAL;
110         }
111
112         buf = dma_alloc_coherent(NULL, memsize, &dma_handle, GFP_KERNEL);
113         if (!buf) {
114                 pr_warning("%s: unable to allocate memory\n", name);
115                 return -ENOMEM;
116         }
117
118         memset(buf, 0, memsize);
119
120         r->flags = IORESOURCE_MEM;
121         r->start = dma_handle;
122         r->end = r->start + memsize - 1;
123         r->name = name;
124         return 0;
125 }