merge of '178eac00dc5aa8338d42e8e203633bec7817bbf6'
[vuplus_openembedded] / packages / linux / linux-rp-2.6.24 / tosa / 0002-Modify-dma_alloc_coherent-on-ARM-so-that-it-supports.patch
1 From 8e95f90487d2fb46fd862744ddb34f47c30b0c5a Mon Sep 17 00:00:00 2001
2 From: Ian Molton <spyro@f2s.com>
3 Date: Fri, 4 Jan 2008 18:27:50 +0000
4 Subject: [PATCH 02/64] Modify dma_alloc_coherent on ARM so that it supports device local DMA.
5
6 ---
7  arch/arm/mm/consistent.c      |  125 +++++++++++++++++++++++++++++++++++++++++
8  include/asm-arm/dma-mapping.h |   37 +++++++------
9  2 files changed, 145 insertions(+), 17 deletions(-)
10
11 diff --git a/arch/arm/mm/consistent.c b/arch/arm/mm/consistent.c
12 index 333a82a..3da0f94 100644
13 --- a/arch/arm/mm/consistent.c
14 +++ b/arch/arm/mm/consistent.c
15 @@ -3,6 +3,8 @@
16   *
17   *  Copyright (C) 2000-2004 Russell King
18   *
19 + *  Device local coherent memory support added by Ian Molton (spyro@f2s.com)
20 + *
21   * This program is free software; you can redistribute it and/or modify
22   * it under the terms of the GNU General Public License version 2 as
23   * published by the Free Software Foundation.
24 @@ -20,6 +22,7 @@
25  
26  #include <asm/memory.h>
27  #include <asm/cacheflush.h>
28 +#include <asm/io.h>
29  #include <asm/tlbflush.h>
30  #include <asm/sizes.h>
31  
32 @@ -35,6 +38,13 @@
33  #define CONSISTENT_PTE_INDEX(x) (((unsigned long)(x) - CONSISTENT_BASE) >> PGDIR_SHIFT)
34  #define NUM_CONSISTENT_PTES (CONSISTENT_DMA_SIZE >> PGDIR_SHIFT)
35  
36 +struct dma_coherent_mem {
37 +       void            *virt_base;
38 +       u32             device_base;
39 +       int             size;
40 +       int             flags;
41 +       unsigned long   *bitmap;
42 +};
43  
44  /*
45   * These are the page tables (2MB each) covering uncached, DMA consistent allocations
46 @@ -153,6 +163,13 @@ __dma_alloc(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp,
47         unsigned long order;
48         u64 mask = ISA_DMA_THRESHOLD, limit;
49  
50 +       /* Following is a work-around (a.k.a. hack) to prevent pages
51 +        * with __GFP_COMP being passed to split_page() which cannot
52 +        * handle them.  The real problem is that this flag probably
53 +        * should be 0 on ARM as it is not supported on this
54 +        * platform--see CONFIG_HUGETLB_PAGE. */
55 +       gfp &= ~(__GFP_COMP);
56 +
57         if (!consistent_pte[0]) {
58                 printk(KERN_ERR "%s: not initialised\n", __func__);
59                 dump_stack();
60 @@ -160,6 +177,26 @@ __dma_alloc(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp,
61         }
62  
63         if (dev) {
64 +
65 +               if (dev->dma_mem) {
66 +                       unsigned long flags;
67 +                       int pgnum;
68 +                       void *ret;
69 +
70 +                       spin_lock_irqsave(&consistent_lock, flags);
71 +                       pgnum = bitmap_find_free_region(dev->dma_mem->bitmap,
72 +                                                      dev->dma_mem->size,
73 +                                                      get_order(size));
74 +                       spin_unlock_irqrestore(&consistent_lock, flags);
75 +
76 +                       if (pgnum >= 0) {
77 +                               *handle = dev->dma_mem->device_base + (pgnum << PAGE_SHIFT);
78 +                               ret = dev->dma_mem->virt_base + (pgnum << PAGE_SHIFT);
79 +                               memset(ret, 0, size);
80 +                               return ret;
81 +                       }
82 +               }
83 +
84                 mask = dev->coherent_dma_mask;
85  
86                 /*
87 @@ -177,6 +214,9 @@ __dma_alloc(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp,
88                                  mask, (unsigned long long)ISA_DMA_THRESHOLD);
89                         goto no_page;
90                 }
91 +
92 +               if (dev->dma_mem && dev->dma_mem->flags & DMA_MEMORY_EXCLUSIVE)
93 +                       return NULL;
94         }
95  
96         /*
97 @@ -359,6 +399,8 @@ void dma_free_coherent(struct device *dev, size_t size, void *cpu_addr, dma_addr
98         pte_t *ptep;
99         int idx;
100         u32 off;
101 +       struct dma_coherent_mem *mem = dev ? dev->dma_mem : NULL;
102 +       unsigned long order;
103  
104         WARN_ON(irqs_disabled());
105  
106 @@ -368,6 +410,15 @@ void dma_free_coherent(struct device *dev, size_t size, void *cpu_addr, dma_addr
107         }
108  
109         size = PAGE_ALIGN(size);
110 +       order = get_order(size);
111 +
112 +       /* What if mem is valid and the range is not? */
113 +       if (mem && cpu_addr >= mem->virt_base && cpu_addr < (mem->virt_base + (mem->size << PAGE_SHIFT))) {
114 +               int page = (cpu_addr - mem->virt_base) >> PAGE_SHIFT;
115 +
116 +               bitmap_release_region(mem->bitmap, page, order);
117 +               return;
118 +       }
119  
120         spin_lock_irqsave(&consistent_lock, flags);
121         c = vm_region_find(&consistent_head, (unsigned long)cpu_addr);
122 @@ -437,6 +488,80 @@ void dma_free_coherent(struct device *dev, size_t size, void *cpu_addr, dma_addr
123  }
124  EXPORT_SYMBOL(dma_free_coherent);
125  
126 +int dma_declare_coherent_memory(struct device *dev, dma_addr_t bus_addr,
127 +                               dma_addr_t device_addr, size_t size, int flags)
128 +{
129 +       void __iomem *mem_base;
130 +       int pages = size >> PAGE_SHIFT;
131 +       int bitmap_size = (pages + 31)/32;
132 +
133 +       if ((flags & (DMA_MEMORY_MAP | DMA_MEMORY_IO)) == 0)
134 +               goto out;
135 +       if (!size)
136 +               goto out;
137 +       if (dev->dma_mem)
138 +               goto out;
139 +
140 +       /* FIXME: this routine just ignores DMA_MEMORY_INCLUDES_CHILDREN */
141 +       mem_base = ioremap_nocache(bus_addr, size);
142 +       if (!mem_base)
143 +               goto out;
144 +
145 +       dev->dma_mem = kzalloc(sizeof(struct dma_coherent_mem), GFP_KERNEL);
146 +       if (!dev->dma_mem)
147 +               goto out;
148 +       memset(dev->dma_mem, 0, sizeof(struct dma_coherent_mem));
149 +       dev->dma_mem->bitmap = kzalloc(bitmap_size, GFP_KERNEL);
150 +       if (!dev->dma_mem->bitmap)
151 +               goto free1_out;
152 +
153 +       dev->dma_mem->virt_base = mem_base;
154 +       dev->dma_mem->device_base = device_addr;
155 +       dev->dma_mem->size = pages;
156 +       dev->dma_mem->flags = flags;
157 +
158 +       if (flags & DMA_MEMORY_MAP)
159 +               return DMA_MEMORY_MAP;
160 +
161 +       return DMA_MEMORY_IO;
162 +
163 + free1_out:
164 +       kfree(dev->dma_mem->bitmap);
165 + out:
166 +       return 0;
167 +}
168 +EXPORT_SYMBOL(dma_declare_coherent_memory);
169 +
170 +void dma_release_declared_memory(struct device *dev)
171 +{
172 +       struct dma_coherent_mem *mem = dev->dma_mem;
173 +
174 +       if (!mem)
175 +               return;
176 +       dev->dma_mem = NULL;
177 +       kfree(mem->bitmap);
178 +       kfree(mem);
179 +}
180 +EXPORT_SYMBOL(dma_release_declared_memory);
181 +
182 +void *dma_mark_declared_memory_occupied(struct device *dev,
183 +                                       dma_addr_t device_addr, size_t size)
184 +{
185 +       struct dma_coherent_mem *mem = dev->dma_mem;
186 +       int pages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT;
187 +       int pos, err;
188 +
189 +       if (!mem)
190 +               return ERR_PTR(-EINVAL);
191 +
192 +       pos = (device_addr - mem->device_base) >> PAGE_SHIFT;
193 +       err = bitmap_allocate_region(mem->bitmap, pos, get_order(pages));
194 +       if (err != 0)
195 +               return ERR_PTR(err);
196 +       return mem->virt_base + (pos << PAGE_SHIFT);
197 +}
198 +EXPORT_SYMBOL(dma_mark_declared_memory_occupied);
199 +
200  /*
201   * Initialise the consistent memory allocation.
202   */
203 diff --git a/include/asm-arm/dma-mapping.h b/include/asm-arm/dma-mapping.h
204 index e99406a..f18ba05 100644
205 --- a/include/asm-arm/dma-mapping.h
206 +++ b/include/asm-arm/dma-mapping.h
207 @@ -7,6 +7,19 @@
208  
209  #include <linux/scatterlist.h>
210  
211 +#define ARCH_HAS_DMA_DECLARE_COHERENT_MEMORY
212 +extern int
213 +dma_declare_coherent_memory(struct device *dev, dma_addr_t bus_addr,
214 +                            dma_addr_t device_addr, size_t size, int flags);
215 +
216 +extern void
217 +dma_release_declared_memory(struct device *dev);
218 +
219 +extern void *
220 +dma_mark_declared_memory_occupied(struct device *dev,
221 +                                  dma_addr_t device_addr, size_t size);
222 +
223 +
224  /*
225   * DMA-consistent mapping functions.  These allocate/free a region of
226   * uncached, unwrite-buffered mapped memory space for use with DMA
227 @@ -433,23 +446,13 @@ extern int dmabounce_register_dev(struct device *, unsigned long, unsigned long)
228   */
229  extern void dmabounce_unregister_dev(struct device *);
230  
231 -/**
232 - * dma_needs_bounce
233 - *
234 - * @dev: valid struct device pointer
235 - * @dma_handle: dma_handle of unbounced buffer
236 - * @size: size of region being mapped
237 - *
238 - * Platforms that utilize the dmabounce mechanism must implement
239 - * this function.
240 - *
241 - * The dmabounce routines call this function whenever a dma-mapping
242 - * is requested to determine whether a given buffer needs to be bounced
243 - * or not. The function must return 0 if the buffer is OK for
244 - * DMA access and 1 if the buffer needs to be bounced.
245 - *
246 - */
247 -extern int dma_needs_bounce(struct device*, dma_addr_t, size_t);
248 +typedef int (*dmabounce_check)(struct device *dev, dma_addr_t dma, size_t size, void *data);
249 +extern int dmabounce_register_checker(dmabounce_check, void *data);
250 +extern void dmabounce_remove_checker(dmabounce_check, void *data);
251 +#ifdef CONFIG_PLATFORM_DMABOUNCE
252 +extern int platform_dma_needs_bounce(struct device *dev, dma_addr_t dma, size_t size, void *data);
253 +#endif
254 +
255  #endif /* CONFIG_DMABOUNCE */
256  
257  #endif /* __KERNEL__ */
258 -- 
259 1.5.3.8
260