1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27#include <linux/config.h>
28#include <linux/init.h>
29#include <linux/types.h>
30#include <linux/slab.h>
31#include <linux/mm.h>
32#include <linux/spinlock.h>
33#include <linux/string.h>
34#include <linux/dma-mapping.h>
35#include <linux/init.h>
36#include <asm/io.h>
37#include <asm/prom.h>
38#include <asm/iommu.h>
39#include <asm/pci-bridge.h>
40#include <asm/machdep.h>
41#include <asm/bitops.h>
42
43#define DBG(...)
44
45#ifdef CONFIG_IOMMU_VMERGE
46static int novmerge = 0;
47#else
48static int novmerge = 1;
49#endif
50
51static int __init setup_iommu(char *str)
52{
53 if (!strcmp(str, "novmerge"))
54 novmerge = 1;
55 else if (!strcmp(str, "vmerge"))
56 novmerge = 0;
57 return 1;
58}
59
60__setup("iommu=", setup_iommu);
61
62static unsigned long iommu_range_alloc(struct iommu_table *tbl, unsigned long npages,
63 unsigned long *handle)
64{
65 unsigned long n, end, i, start;
66 unsigned long limit;
67 int largealloc = npages > 15;
68 int pass = 0;
69
70
71
72
73 if (unlikely(npages) == 0) {
74 if (printk_ratelimit())
75 WARN_ON(1);
76 return DMA_ERROR_CODE;
77 }
78
79 if (handle && *handle)
80 start = *handle;
81 else
82 start = largealloc ? tbl->it_largehint : tbl->it_hint;
83
84
85 limit = largealloc ? tbl->it_mapsize : tbl->it_halfpoint;
86
87 if (largealloc && start < tbl->it_halfpoint)
88 start = tbl->it_halfpoint;
89
90
91
92
93
94 if (start >= limit)
95 start = largealloc ? tbl->it_largehint : tbl->it_hint;
96
97 again:
98
99 n = find_next_zero_bit(tbl->it_map, limit, start);
100 end = n + npages;
101
102 if (unlikely(end >= limit)) {
103 if (likely(pass < 2)) {
104
105
106
107 start = (largealloc ^ pass) ? tbl->it_halfpoint : 0;
108 limit = pass ? tbl->it_mapsize : limit;
109 pass++;
110 goto again;
111 } else {
112
113 return DMA_ERROR_CODE;
114 }
115 }
116
117 for (i = n; i < end; i++)
118 if (test_bit(i, tbl->it_map)) {
119 start = i+1;
120 goto again;
121 }
122
123 for (i = n; i < end; i++)
124 __set_bit(i, tbl->it_map);
125
126
127 if (largealloc) {
128
129 tbl->it_largehint = end;
130 } else {
131
132 tbl->it_hint = (end + tbl->it_blocksize - 1) &
133 ~(tbl->it_blocksize - 1);
134 }
135
136
137 if (handle)
138 *handle = end;
139
140 return n;
141}
142
143static dma_addr_t iommu_alloc(struct iommu_table *tbl, void *page,
144 unsigned int npages, enum dma_data_direction direction)
145{
146 unsigned long entry, flags;
147 dma_addr_t ret = DMA_ERROR_CODE;
148
149 spin_lock_irqsave(&(tbl->it_lock), flags);
150
151 entry = iommu_range_alloc(tbl, npages, NULL);
152
153 if (unlikely(entry == DMA_ERROR_CODE)) {
154 spin_unlock_irqrestore(&(tbl->it_lock), flags);
155 return DMA_ERROR_CODE;
156 }
157
158 entry += tbl->it_offset;
159 ret = entry << PAGE_SHIFT;
160
161
162 ppc_md.tce_build(tbl, entry, npages, (unsigned long)page & PAGE_MASK,
163 direction);
164
165
166
167 if (ppc_md.tce_flush)
168 ppc_md.tce_flush(tbl);
169
170 spin_unlock_irqrestore(&(tbl->it_lock), flags);
171
172
173 mb();
174
175 return ret;
176}
177
178static void __iommu_free(struct iommu_table *tbl, dma_addr_t dma_addr,
179 unsigned int npages)
180{
181 unsigned long entry, free_entry;
182 unsigned long i;
183
184 entry = dma_addr >> PAGE_SHIFT;
185 free_entry = entry - tbl->it_offset;
186
187 if (((free_entry + npages) > tbl->it_mapsize) ||
188 (entry < tbl->it_offset)) {
189 if (printk_ratelimit()) {
190 printk(KERN_INFO "iommu_free: invalid entry\n");
191 printk(KERN_INFO "\tentry = 0x%lx\n", entry);
192 printk(KERN_INFO "\tdma_addr = 0x%lx\n", (u64)dma_addr);
193 printk(KERN_INFO "\tTable = 0x%lx\n", (u64)tbl);
194 printk(KERN_INFO "\tbus# = 0x%lx\n", (u64)tbl->it_busno);
195 printk(KERN_INFO "\tmapsize = 0x%lx\n", (u64)tbl->it_mapsize);
196 printk(KERN_INFO "\tstartOff = 0x%lx\n", (u64)tbl->it_offset);
197 printk(KERN_INFO "\tindex = 0x%lx\n", (u64)tbl->it_index);
198 WARN_ON(1);
199 }
200 return;
201 }
202
203 ppc_md.tce_free(tbl, entry, npages);
204
205 for (i = 0; i < npages; i++)
206 __clear_bit(free_entry+i, tbl->it_map);
207}
208
209static void iommu_free(struct iommu_table *tbl, dma_addr_t dma_addr,
210 unsigned int npages)
211{
212 unsigned long flags;
213
214 spin_lock_irqsave(&(tbl->it_lock), flags);
215
216 __iommu_free(tbl, dma_addr, npages);
217
218
219
220
221
222 if (ppc_md.tce_flush)
223 ppc_md.tce_flush(tbl);
224
225 spin_unlock_irqrestore(&(tbl->it_lock), flags);
226}
227
228int iommu_map_sg(struct device *dev, struct iommu_table *tbl,
229 struct scatterlist *sglist, int nelems,
230 enum dma_data_direction direction)
231{
232 dma_addr_t dma_next, dma_addr;
233 unsigned long flags;
234 struct scatterlist *s, *outs, *segstart;
235 int outcount;
236 unsigned long handle;
237
238 BUG_ON(direction == DMA_NONE);
239
240 if ((nelems == 0) || !tbl)
241 return 0;
242
243 outs = s = segstart = &sglist[0];
244 outcount = 1;
245 handle = 0;
246
247
248 outs->dma_length = 0;
249
250 DBG("mapping %d elements:\n", nelems);
251
252 spin_lock_irqsave(&(tbl->it_lock), flags);
253
254 for (s = outs; nelems; nelems--, s++) {
255 unsigned long vaddr, npages, entry, slen;
256
257 slen = s->length;
258
259 if (slen == 0) {
260 dma_next = 0;
261 continue;
262 }
263
264 vaddr = (unsigned long)page_address(s->page) + s->offset;
265 npages = PAGE_ALIGN(vaddr + slen) - (vaddr & PAGE_MASK);
266 npages >>= PAGE_SHIFT;
267 entry = iommu_range_alloc(tbl, npages, &handle);
268
269 DBG(" - vaddr: %lx, size: %lx\n", vaddr, slen);
270
271
272 if (unlikely(entry == DMA_ERROR_CODE)) {
273 if (printk_ratelimit())
274 printk(KERN_INFO "iommu_alloc failed, tbl %p vaddr %lx"
275 " npages %lx\n", tbl, vaddr, npages);
276 goto failure;
277 }
278
279
280 entry += tbl->it_offset;
281 dma_addr = entry << PAGE_SHIFT;
282 dma_addr |= s->offset;
283
284 DBG(" - %lx pages, entry: %lx, dma_addr: %lx\n",
285 npages, entry, dma_addr);
286
287
288 ppc_md.tce_build(tbl, entry, npages, vaddr & PAGE_MASK, direction);
289
290
291 if (segstart != s) {
292 DBG(" - trying merge...\n");
293
294
295
296 if (novmerge || (dma_addr != dma_next)) {
297
298 segstart = s;
299 outcount++; outs++;
300 DBG(" can't merge, new segment.\n");
301 } else {
302 outs->dma_length += s->length;
303 DBG(" merged, new len: %lx\n", outs->dma_length);
304 }
305 }
306
307 if (segstart == s) {
308
309 DBG(" - filling new segment.\n");
310 outs->dma_address = dma_addr;
311 outs->dma_length = slen;
312 }
313
314
315 dma_next = dma_addr + slen;
316
317 DBG(" - dma next is: %lx\n", dma_next);
318 }
319
320
321 if (ppc_md.tce_flush)
322 ppc_md.tce_flush(tbl);
323
324 spin_unlock_irqrestore(&(tbl->it_lock), flags);
325
326
327 mb();
328
329 DBG("mapped %d elements:\n", outcount);
330
331
332
333
334 if (outcount < nelems) {
335 outs++;
336 outs->dma_address = DMA_ERROR_CODE;
337 outs->dma_length = 0;
338 }
339 return outcount;
340
341 failure:
342 for (s = &sglist[0]; s <= outs; s++) {
343 if (s->dma_length != 0) {
344 unsigned long vaddr, npages;
345
346 vaddr = s->dma_address & PAGE_MASK;
347 npages = (PAGE_ALIGN(s->dma_address + s->dma_length) - vaddr)
348 >> PAGE_SHIFT;
349 __iommu_free(tbl, vaddr, npages);
350 }
351 }
352 spin_unlock_irqrestore(&(tbl->it_lock), flags);
353 return 0;
354}
355
356
357void iommu_unmap_sg(struct iommu_table *tbl, struct scatterlist *sglist,
358 int nelems, enum dma_data_direction direction)
359{
360 unsigned long flags;
361
362 BUG_ON(direction == DMA_NONE);
363
364 if (!tbl)
365 return;
366
367 spin_lock_irqsave(&(tbl->it_lock), flags);
368
369 while (nelems--) {
370 unsigned int npages;
371 dma_addr_t dma_handle = sglist->dma_address;
372
373 if (sglist->dma_length == 0)
374 break;
375 npages = (PAGE_ALIGN(dma_handle + sglist->dma_length)
376 - (dma_handle & PAGE_MASK)) >> PAGE_SHIFT;
377 __iommu_free(tbl, dma_handle, npages);
378 sglist++;
379 }
380
381
382
383
384
385 if (ppc_md.tce_flush)
386 ppc_md.tce_flush(tbl);
387
388 spin_unlock_irqrestore(&(tbl->it_lock), flags);
389}
390
391
392
393
394
395struct iommu_table *iommu_init_table(struct iommu_table *tbl)
396{
397 unsigned long sz;
398 static int welcomed = 0;
399
400
401 tbl->it_mapsize = (tbl->it_size << PAGE_SHIFT) / tbl->it_entrysize;
402
403
404 tbl->it_halfpoint = tbl->it_mapsize * 3 / 4;
405
406
407 sz = (tbl->it_mapsize + 7) >> 3;
408
409 tbl->it_map = (unsigned long *)__get_free_pages(GFP_ATOMIC, get_order(sz));
410 if (!tbl->it_map)
411 panic("iommu_init_table: Can't allocate %ld bytes\n", sz);
412
413 memset(tbl->it_map, 0, sz);
414
415 tbl->it_hint = 0;
416 tbl->it_largehint = tbl->it_halfpoint;
417 spin_lock_init(&tbl->it_lock);
418
419 if (!welcomed) {
420 printk(KERN_INFO "IOMMU table initialized, virtual merging %s\n",
421 novmerge ? "disabled" : "enabled");
422 welcomed = 1;
423 }
424
425 return tbl;
426}
427
428
429
430
431
432
433
434dma_addr_t iommu_map_single(struct iommu_table *tbl, void *vaddr,
435 size_t size, enum dma_data_direction direction)
436{
437 dma_addr_t dma_handle = DMA_ERROR_CODE;
438 unsigned long uaddr;
439 unsigned int npages;
440
441 BUG_ON(direction == DMA_NONE);
442
443 uaddr = (unsigned long)vaddr;
444 npages = PAGE_ALIGN(uaddr + size) - (uaddr & PAGE_MASK);
445 npages >>= PAGE_SHIFT;
446
447 if (tbl) {
448 dma_handle = iommu_alloc(tbl, vaddr, npages, direction);
449 if (dma_handle == DMA_ERROR_CODE) {
450 if (printk_ratelimit()) {
451 printk(KERN_INFO "iommu_alloc failed, "
452 "tbl %p vaddr %p npages %d\n",
453 tbl, vaddr, npages);
454 }
455 } else
456 dma_handle |= (uaddr & ~PAGE_MASK);
457 }
458
459 return dma_handle;
460}
461
462void iommu_unmap_single(struct iommu_table *tbl, dma_addr_t dma_handle,
463 size_t size, enum dma_data_direction direction)
464{
465 BUG_ON(direction == DMA_NONE);
466
467 if (tbl)
468 iommu_free(tbl, dma_handle, (PAGE_ALIGN(dma_handle + size) -
469 (dma_handle & PAGE_MASK)) >> PAGE_SHIFT);
470}
471
472
473
474
475
476void *iommu_alloc_consistent(struct iommu_table *tbl, size_t size,
477 dma_addr_t *dma_handle)
478{
479 void *ret = NULL;
480 dma_addr_t mapping;
481 unsigned int npages, order;
482
483 size = PAGE_ALIGN(size);
484 npages = size >> PAGE_SHIFT;
485 order = get_order(size);
486
487
488
489
490
491
492 if (order >= IOMAP_MAX_ORDER) {
493 printk("iommu_alloc_consistent size too large: 0x%lx\n", size);
494 return NULL;
495 }
496
497 if (!tbl)
498 return NULL;
499
500
501 ret = (void *)__get_free_pages(GFP_ATOMIC, order);
502 if (!ret)
503 return NULL;
504 memset(ret, 0, size);
505
506
507 mapping = iommu_alloc(tbl, ret, npages, DMA_BIDIRECTIONAL);
508 if (mapping == DMA_ERROR_CODE) {
509 free_pages((unsigned long)ret, order);
510 ret = NULL;
511 } else
512 *dma_handle = mapping;
513 return ret;
514}
515
516void iommu_free_consistent(struct iommu_table *tbl, size_t size,
517 void *vaddr, dma_addr_t dma_handle)
518{
519 unsigned int npages;
520
521 if (tbl) {
522 size = PAGE_ALIGN(size);
523 npages = size >> PAGE_SHIFT;
524 iommu_free(tbl, dma_handle, npages);
525 free_pages((unsigned long)vaddr, get_order(size));
526 }
527}
528