]> code.ossystems Code Review - openembedded-core.git/blob
945778b943f4df957b1d95b812fbf03b5cf6edc5
[openembedded-core.git] /
1 From 07365182b998af3dc2b79e822b8e21a3f50262c4 Mon Sep 17 00:00:00 2001
2 From: Hiroshi DOYU <Hiroshi.DOYU@nokia.com>
3 Date: Wed, 28 Jan 2009 21:32:08 +0200
4 Subject: [PATCH] omap iommu: simple virtual address space management
5
6 This patch provides a device drivers, which has a omap iommu, with
7 address mapping APIs between device virtual address(iommu), physical
8 address and MPU virtual address.
9
10 There are 4 possible patterns for iommu virtual address(iova/da) mapping.
11
12     |iova/                        mapping               iommu_          page
13     | da        pa      va      (d)-(p)-(v)             function        type
14   ---------------------------------------------------------------------------
15   1 | c         c       c        1 - 1 - 1        _kmap() / _kunmap()   s
16   2 | c         c,a     c        1 - 1 - 1      _kmalloc()/ _kfree()    s
17   3 | c         d       c        1 - n - 1        _vmap() / _vunmap()   s
18   4 | c         d,a     c        1 - n - 1      _vmalloc()/ _vfree()    n*
19
20     'iova':     device iommu virtual address
21     'da':       alias of 'iova'
22     'pa':       physical address
23     'va':       mpu virtual address
24
25     'c':        contiguous memory area
26     'd':        dicontiguous memory area
27     'a':        anonymous memory allocation
28     '()':       optional feature
29
30     'n':        a normal page(4KB) size is used.
31     's':        multiple iommu superpage(16MB, 1MB, 64KB, 4KB) size is used.
32
33     '*':        not yet, but feasible.
34
35 Signed-off-by: Hiroshi DOYU <Hiroshi.DOYU@nokia.com>
36 ---
37  arch/arm/include/asm/io.h               |    6 +
38  arch/arm/mm/ioremap.c                   |   11 +
39  arch/arm/plat-omap/include/mach/iovmm.h |   94 ++++
40  arch/arm/plat-omap/iovmm.c              |  891 +++++++++++++++++++++++++++++++
41  4 files changed, 1002 insertions(+), 0 deletions(-)
42  create mode 100644 arch/arm/plat-omap/include/mach/iovmm.h
43  create mode 100644 arch/arm/plat-omap/iovmm.c
44
45 diff --git a/arch/arm/include/asm/io.h b/arch/arm/include/asm/io.h
46 index d2a59cf..cbdadfe 100644
47 --- a/arch/arm/include/asm/io.h
48 +++ b/arch/arm/include/asm/io.h
49 @@ -75,6 +75,12 @@ extern void __iomem * __arm_ioremap(unsigned long, size_t, unsigned int);
50  extern void __iounmap(volatile void __iomem *addr);
51  
52  /*
53 + * external interface to remap single page with appropriate type
54 + */
55 +extern int ioremap_page(unsigned long virt, unsigned long phys,
56 +                       unsigned int mtype);
57 +
58 +/*
59   * Bad read/write accesses...
60   */
61  extern void __readwrite_bug(const char *fn);
62 diff --git a/arch/arm/mm/ioremap.c b/arch/arm/mm/ioremap.c
63 index 9f88dd3..8441351 100644
64 --- a/arch/arm/mm/ioremap.c
65 +++ b/arch/arm/mm/ioremap.c
66 @@ -110,6 +110,17 @@ static int remap_area_pages(unsigned long start, unsigned long pfn,
67         return err;
68  }
69  
70 +int ioremap_page(unsigned long virt, unsigned long phys, unsigned int mtype)
71 +{
72 +       const struct mem_type *type;
73 +
74 +       type = get_mem_type(mtype);
75 +       if (!type)
76 +               return -EINVAL;
77 +
78 +       return remap_area_pages(virt, __phys_to_pfn(phys), PAGE_SIZE, type);
79 +}
80 +EXPORT_SYMBOL(ioremap_page);
81  
82  void __check_kvm_seq(struct mm_struct *mm)
83  {
84 diff --git a/arch/arm/plat-omap/include/mach/iovmm.h b/arch/arm/plat-omap/include/mach/iovmm.h
85 new file mode 100644
86 index 0000000..bdc7ce5
87 --- /dev/null
88 +++ b/arch/arm/plat-omap/include/mach/iovmm.h
89 @@ -0,0 +1,94 @@
90 +/*
91 + * omap iommu: simple virtual address space management
92 + *
93 + * Copyright (C) 2008-2009 Nokia Corporation
94 + *
95 + * Written by Hiroshi DOYU <Hiroshi.DOYU@nokia.com>
96 + *
97 + * This program is free software; you can redistribute it and/or modify
98 + * it under the terms of the GNU General Public License version 2 as
99 + * published by the Free Software Foundation.
100 + */
101 +
102 +#ifndef __IOMMU_MMAP_H
103 +#define __IOMMU_MMAP_H
104 +
105 +struct iovm_struct {
106 +       struct iommu            *iommu; /* iommu object which this belongs to */
107 +       u32                     da_start; /* area definition */
108 +       u32                     da_end;
109 +       u32                     flags; /* IOVMF_: see below */
110 +       struct list_head        list; /* linked in ascending order */
111 +       const struct sg_table   *sgt; /* keep 'page' <-> 'da' mapping */
112 +       void                    *va; /* mpu side mapped address */
113 +};
114 +
115 +/*
116 + * IOVMF_FLAGS: attribute for iommu virtual memory area(iovma)
117 + *
118 + * lower 16 bit is used for h/w and upper 16 bit is for s/w.
119 + */
120 +#define IOVMF_SW_SHIFT         16
121 +#define IOVMF_HW_SIZE          (1 << IOVMF_SW_SHIFT)
122 +#define IOVMF_HW_MASK          (IOVMF_HW_SIZE - 1)
123 +#define IOVMF_SW_MASK          (~IOVMF_HW_MASK)UL
124 +
125 +/*
126 + * iovma: h/w flags derived from cam and ram attribute
127 + */
128 +#define IOVMF_CAM_MASK         (~((1 << 10) - 1))
129 +#define IOVMF_RAM_MASK         (~IOVMF_CAM_MASK)
130 +
131 +#define IOVMF_PGSZ_MASK                (3 << 0)
132 +#define IOVMF_PGSZ_1M          MMU_CAM_PGSZ_1M
133 +#define IOVMF_PGSZ_64K         MMU_CAM_PGSZ_64K
134 +#define IOVMF_PGSZ_4K          MMU_CAM_PGSZ_4K
135 +#define IOVMF_PGSZ_16M         MMU_CAM_PGSZ_16M
136 +
137 +#define IOVMF_ENDIAN_MASK      (1 << 9)
138 +#define IOVMF_ENDIAN_BIG       MMU_RAM_ENDIAN_BIG
139 +#define IOVMF_ENDIAN_LITTLE    MMU_RAM_ENDIAN_LITTLE
140 +
141 +#define IOVMF_ELSZ_MASK                (3 << 7)
142 +#define IOVMF_ELSZ_8           MMU_RAM_ELSZ_8
143 +#define IOVMF_ELSZ_16          MMU_RAM_ELSZ_16
144 +#define IOVMF_ELSZ_32          MMU_RAM_ELSZ_32
145 +#define IOVMF_ELSZ_NONE                MMU_RAM_ELSZ_NONE
146 +
147 +#define IOVMF_MIXED_MASK       (1 << 6)
148 +#define IOVMF_MIXED            MMU_RAM_MIXED
149 +
150 +/*
151 + * iovma: s/w flags, used for mapping and umapping internally.
152 + */
153 +#define IOVMF_MMIO             (1 << IOVMF_SW_SHIFT)
154 +#define IOVMF_ALLOC            (2 << IOVMF_SW_SHIFT)
155 +#define IOVMF_ALLOC_MASK       (3 << IOVMF_SW_SHIFT)
156 +
157 +/* "superpages" is supported just with physically linear pages */
158 +#define IOVMF_DISCONT          (1 << (2 + IOVMF_SW_SHIFT))
159 +#define IOVMF_LINEAR           (2 << (2 + IOVMF_SW_SHIFT))
160 +#define IOVMF_LINEAR_MASK      (3 << (2 + IOVMF_SW_SHIFT))
161 +
162 +#define IOVMF_DA_FIXED         (1 << (4 + IOVMF_SW_SHIFT))
163 +#define IOVMF_DA_ANON          (2 << (4 + IOVMF_SW_SHIFT))
164 +#define IOVMF_DA_MASK          (3 << (4 + IOVMF_SW_SHIFT))
165 +
166 +
167 +extern struct iovm_struct *find_iovm_area(struct iommu *obj, u32 da);
168 +extern u32 iommu_vmap(struct iommu *obj, u32 da,
169 +                       const struct sg_table *sgt, u32 flags);
170 +extern struct sg_table *iommu_vunmap(struct iommu *obj, u32 da);
171 +extern u32 iommu_vmalloc(struct iommu *obj, u32 da, size_t bytes,
172 +                          u32 flags);
173 +extern void iommu_vfree(struct iommu *obj, const u32 da);
174 +extern u32 iommu_kmap(struct iommu *obj, u32 da, u32 pa, size_t bytes,
175 +                       u32 flags);
176 +extern void iommu_kunmap(struct iommu *obj, u32 da);
177 +extern u32 iommu_kmalloc(struct iommu *obj, u32 da, size_t bytes,
178 +                          u32 flags);
179 +extern void iommu_kfree(struct iommu *obj, u32 da);
180 +
181 +extern void *da_to_va(struct iommu *obj, u32 da);
182 +
183 +#endif /* __IOMMU_MMAP_H */
184 diff --git a/arch/arm/plat-omap/iovmm.c b/arch/arm/plat-omap/iovmm.c
185 new file mode 100644
186 index 0000000..6726d10
187 --- /dev/null
188 +++ b/arch/arm/plat-omap/iovmm.c
189 @@ -0,0 +1,891 @@
190 +/*
191 + * omap iommu: simple virtual address space management
192 + *
193 + * Copyright (C) 2008-2009 Nokia Corporation
194 + *
195 + * Written by Hiroshi DOYU <Hiroshi.DOYU@nokia.com>
196 + *
197 + * This program is free software; you can redistribute it and/or modify
198 + * it under the terms of the GNU General Public License version 2 as
199 + * published by the Free Software Foundation.
200 + */
201 +
202 +#include <linux/err.h>
203 +#include <linux/vmalloc.h>
204 +#include <linux/device.h>
205 +#include <linux/scatterlist.h>
206 +
207 +#include <asm/io.h>
208 +#include <asm/cacheflush.h>
209 +
210 +#include <mach/iommu.h>
211 +#include <mach/iovmm.h>
212 +
213 +#include "iopgtable.h"
214 +
215 +/*
216 + * A device driver needs to create address mappings between:
217 + *
218 + * - iommu/device address
219 + * - physical address
220 + * - mpu virtual address
221 + *
222 + * There are 4 possible patterns for them:
223 + *
224 + *    |iova/                     mapping               iommu_          page
225 + *    | da     pa      va      (d)-(p)-(v)             function        type
226 + *  ---------------------------------------------------------------------------
227 + *  1 | c      c       c        1 - 1 - 1        _kmap() / _kunmap()   s
228 + *  2 | c      c,a     c        1 - 1 - 1      _kmalloc()/ _kfree()    s
229 + *  3 | c      d       c        1 - n - 1        _vmap() / _vunmap()   s
230 + *  4 | c      d,a     c        1 - n - 1      _vmalloc()/ _vfree()    n*
231 + *
232 + *
233 + *     'iova': device iommu virtual address
234 + *     'da':   alias of 'iova'
235 + *     'pa':   physical address
236 + *     'va':   mpu virtual address
237 + *
238 + *     'c':    contiguous memory area
239 + *     'd':    dicontiguous memory area
240 + *     'a':    anonymous memory allocation
241 + *     '()':   optional feature
242 + *
243 + *     'n':    a normal page(4KB) size is used.
244 + *     's':    multiple iommu superpage(16MB, 1MB, 64KB, 4KB) size is used.
245 + *
246 + *     '*':    not yet, but feasible.
247 + */
248 +
249 +static struct kmem_cache *iovm_area_cachep;
250 +
251 +/* return total bytes of sg buffers */
252 +static size_t sgtable_len(const struct sg_table *sgt)
253 +{
254 +       unsigned int i, total = 0;
255 +       struct scatterlist *sg;
256 +
257 +       if (!sgt)
258 +               return 0;
259 +
260 +       for_each_sg(sgt->sgl, sg, sgt->nents, i) {
261 +               size_t bytes;
262 +
263 +               bytes = sg_dma_len(sg);
264 +
265 +               if (!iopgsz_ok(bytes)) {
266 +                       pr_err("%s: sg[%d] not iommu pagesize(%x)\n",
267 +                              __func__, i, bytes);
268 +                       return 0;
269 +               }
270 +
271 +               total += bytes;
272 +       }
273 +
274 +       return total;
275 +}
276 +#define sgtable_ok(x)  (!!sgtable_len(x))
277 +
278 +/*
279 + * calculate the optimal number sg elements from total bytes based on
280 + * iommu superpages
281 + */
282 +static unsigned int sgtable_nents(size_t bytes)
283 +{
284 +       int i;
285 +       unsigned int nr_entries;
286 +       const unsigned long pagesize[] = { SZ_16M, SZ_1M, SZ_64K, SZ_4K, };
287 +
288 +       if (!IS_ALIGNED(bytes, PAGE_SIZE)) {
289 +               pr_err("%s: wrong size %08x\n", __func__, bytes);
290 +               return 0;
291 +       }
292 +
293 +       nr_entries = 0;
294 +       for (i = 0; i < ARRAY_SIZE(pagesize); i++) {
295 +               if (bytes >= pagesize[i]) {
296 +                       nr_entries += (bytes / pagesize[i]);
297 +                       bytes %= pagesize[i];
298 +               }
299 +       }
300 +       BUG_ON(bytes);
301 +
302 +       return nr_entries;
303 +}
304 +
305 +/* allocate and initialize sg_table header(a kind of 'superblock') */
306 +static struct sg_table *sgtable_alloc(const size_t bytes, u32 flags)
307 +{
308 +       unsigned int nr_entries;
309 +       int err;
310 +       struct sg_table *sgt;
311 +
312 +       if (!bytes)
313 +               return ERR_PTR(-EINVAL);
314 +
315 +       if (!IS_ALIGNED(bytes, PAGE_SIZE))
316 +               return ERR_PTR(-EINVAL);
317 +
318 +       /* FIXME: IOVMF_DA_FIXED should support 'superpages' */
319 +       if ((flags & IOVMF_LINEAR) && (flags & IOVMF_DA_ANON)) {
320 +               nr_entries = sgtable_nents(bytes);
321 +               if (!nr_entries)
322 +                       return ERR_PTR(-EINVAL);
323 +       } else
324 +               nr_entries =  bytes / PAGE_SIZE;
325 +
326 +       sgt = kzalloc(sizeof(*sgt), GFP_KERNEL);
327 +       if (!sgt)
328 +               return ERR_PTR(-ENOMEM);
329 +
330 +       err = sg_alloc_table(sgt, nr_entries, GFP_KERNEL);
331 +       if (err)
332 +               return ERR_PTR(err);
333 +
334 +       pr_debug("%s: sgt:%p(%d entries)\n", __func__, sgt, nr_entries);
335 +
336 +       return sgt;
337 +}
338 +
339 +/* free sg_table header(a kind of superblock) */
340 +static void sgtable_free(struct sg_table *sgt)
341 +{
342 +       if (!sgt)
343 +               return;
344 +
345 +       sg_free_table(sgt);
346 +       kfree(sgt);
347 +
348 +       pr_debug("%s: sgt:%p\n", __func__, sgt);
349 +}
350 +
351 +/* map 'sglist' to a contiguous mpu virtual area and return 'va' */
352 +static void *vmap_sg(const struct sg_table *sgt)
353 +{
354 +       u32 va;
355 +       size_t total;
356 +       unsigned int i;
357 +       struct scatterlist *sg;
358 +       struct vm_struct *new;
359 +
360 +       total = sgtable_len(sgt);
361 +       if (!total)
362 +               return ERR_PTR(-EINVAL);
363 +
364 +       new = __get_vm_area(total, VM_IOREMAP, VMALLOC_START, VMALLOC_END);
365 +       if (!new)
366 +               return ERR_PTR(-ENOMEM);
367 +       va = (u32)new->addr;
368 +
369 +       for_each_sg(sgt->sgl, sg, sgt->nents, i) {
370 +               size_t bytes;
371 +               u32 pa;
372 +               int err;
373 +
374 +               pa = sg_phys(sg);
375 +               bytes = sg_dma_len(sg);
376 +
377 +               BUG_ON(bytes != PAGE_SIZE);
378 +
379 +               err = ioremap_page(va,  pa, MT_DEVICE);
380 +               if (err)
381 +                       goto err_out;
382 +
383 +               va += bytes;
384 +       }
385 +
386 +       flush_cache_vmap(new->addr, total);
387 +       return new->addr;
388 +
389 +err_out:
390 +       WARN_ON(1); /* FIXME: cleanup some mpu mappings */
391 +       vunmap(new->addr);
392 +       return ERR_PTR(-EAGAIN);
393 +}
394 +
395 +static inline void vunmap_sg(const void *va)
396 +{
397 +       vunmap(va);
398 +}
399 +
400 +static struct iovm_struct *__find_iovm_area(struct iommu *obj, const u32 da)
401 +{
402 +       struct iovm_struct *tmp;
403 +
404 +       list_for_each_entry(tmp, &obj->mmap, list) {
405 +               if ((da >= tmp->da_start) && (da < tmp->da_end)) {
406 +                       size_t len;
407 +
408 +                       len = tmp->da_end - tmp->da_start;
409 +
410 +                       dev_dbg(obj->dev, "%s: %08x-%08x-%08x(%x) %08x\n",
411 +                               __func__, tmp->da_start, da, tmp->da_end, len,
412 +                               tmp->flags);
413 +
414 +                       return tmp;
415 +               }
416 +       }
417 +
418 +       return NULL;
419 +}
420 +
421 +/**
422 + * find_iovm_area  -  find iovma which includes @da
423 + * @da:                iommu device virtual address
424 + *
425 + * Find the existing iovma starting at @da
426 + */
427 +struct iovm_struct *find_iovm_area(struct iommu *obj, u32 da)
428 +{
429 +       struct iovm_struct *area;
430 +
431 +       mutex_lock(&obj->mmap_lock);
432 +       area = __find_iovm_area(obj, da);
433 +       mutex_unlock(&obj->mmap_lock);
434 +
435 +       return area;
436 +}
437 +EXPORT_SYMBOL_GPL(find_iovm_area);
438 +
439 +/*
440 + * This finds the hole(area) which fits the requested address and len
441 + * in iovmas mmap, and returns the new allocated iovma.
442 + */
443 +static struct iovm_struct *alloc_iovm_area(struct iommu *obj, u32 da,
444 +                                          size_t bytes, u32 flags)
445 +{
446 +       struct iovm_struct *new, *tmp;
447 +       u32 start, prev_end, alignement;
448 +
449 +       if (!obj || !bytes)
450 +               return ERR_PTR(-EINVAL);
451 +
452 +       start = da;
453 +       alignement = PAGE_SIZE;
454 +
455 +       if (flags & IOVMF_DA_ANON) {
456 +               /*
457 +                * Reserve the first page for NULL
458 +                */
459 +               start = PAGE_SIZE;
460 +               if (flags & IOVMF_LINEAR)
461 +                       alignement = iopgsz_max(bytes);
462 +               start = roundup(start, alignement);
463 +       }
464 +
465 +       tmp = NULL;
466 +       if (list_empty(&obj->mmap))
467 +               goto found;
468 +
469 +       prev_end = 0;
470 +       list_for_each_entry(tmp, &obj->mmap, list) {
471 +
472 +               if ((prev_end <= start) && (start + bytes < tmp->da_start))
473 +                       goto found;
474 +
475 +               if (flags & IOVMF_DA_ANON)
476 +                       start = roundup(tmp->da_end, alignement);
477 +
478 +               prev_end = tmp->da_end;
479 +       }
480 +
481 +       if ((start >= prev_end) && (ULONG_MAX - start >= bytes))
482 +               goto found;
483 +
484 +       dev_dbg(obj->dev, "%s: no space to fit %08x(%x) flags: %08x\n",
485 +               __func__, da, bytes, flags);
486 +
487 +       return ERR_PTR(-EINVAL);
488 +
489 +found:
490 +       new = kmem_cache_zalloc(iovm_area_cachep, GFP_KERNEL);
491 +       if (!new)
492 +               return ERR_PTR(-ENOMEM);
493 +
494 +       new->iommu = obj;
495 +       new->da_start = start;
496 +       new->da_end = start + bytes;
497 +       new->flags = flags;
498 +
499 +       /*
500 +        * keep ascending order of iovmas
501 +        */
502 +       if (tmp)
503 +               list_add_tail(&new->list, &tmp->list);
504 +       else
505 +               list_add(&new->list, &obj->mmap);
506 +
507 +       dev_dbg(obj->dev, "%s: found %08x-%08x-%08x(%x) %08x\n",
508 +               __func__, new->da_start, start, new->da_end, bytes, flags);
509 +
510 +       return new;
511 +}
512 +
513 +static void free_iovm_area(struct iommu *obj, struct iovm_struct *area)
514 +{
515 +       size_t bytes;
516 +
517 +       BUG_ON(!obj || !area);
518 +
519 +       bytes = area->da_end - area->da_start;
520 +
521 +       dev_dbg(obj->dev, "%s: %08x-%08x(%x) %08x\n",
522 +               __func__, area->da_start, area->da_end, bytes, area->flags);
523 +
524 +       list_del(&area->list);
525 +       kmem_cache_free(iovm_area_cachep, area);
526 +}
527 +
528 +/**
529 + * da_to_va - convert (d) to (v)
530 + * @obj:       objective iommu
531 + * @da:                iommu device virtual address
532 + * @va:                mpu virtual address
533 + *
534 + * Returns mpu virtual addr which corresponds to a given device virtual addr
535 + */
536 +void *da_to_va(struct iommu *obj, u32 da)
537 +{
538 +       void *va = NULL;
539 +       struct iovm_struct *area;
540 +
541 +       mutex_lock(&obj->mmap_lock);
542 +
543 +       area = __find_iovm_area(obj, da);
544 +       if (!area) {
545 +               dev_warn(obj->dev, "%s: no da area(%08x)\n", __func__, da);
546 +               goto out;
547 +       }
548 +       va = area->va;
549 +       mutex_unlock(&obj->mmap_lock);
550 +out:
551 +       return va;
552 +}
553 +EXPORT_SYMBOL_GPL(da_to_va);
554 +
555 +static void sgtable_fill_vmalloc(struct sg_table *sgt, void *_va)
556 +{
557 +       unsigned int i;
558 +       struct scatterlist *sg;
559 +       void *va = _va;
560 +       void *va_end;
561 +
562 +       for_each_sg(sgt->sgl, sg, sgt->nents, i) {
563 +               struct page *pg;
564 +               const size_t bytes = PAGE_SIZE;
565 +
566 +               /*
567 +                * iommu 'superpage' isn't supported with 'iommu_vmalloc()'
568 +                */
569 +               pg = vmalloc_to_page(va);
570 +               BUG_ON(!pg);
571 +               sg_set_page(sg, pg, bytes, 0);
572 +
573 +               va += bytes;
574 +       }
575 +
576 +       va_end = _va + PAGE_SIZE * i;
577 +       flush_cache_vmap(_va, va_end);
578 +}
579 +
580 +static inline void sgtable_drain_vmalloc(struct sg_table *sgt)
581 +{
582 +       /*
583 +        * Actually this is not necessary at all, just exists for
584 +        * consistency of the code readibility.
585 +        */
586 +       BUG_ON(!sgt);
587 +}
588 +
589 +static void sgtable_fill_kmalloc(struct sg_table *sgt, u32 pa, size_t len)
590 +{
591 +       unsigned int i;
592 +       struct scatterlist *sg;
593 +       void *va;
594 +
595 +       va = phys_to_virt(pa);
596 +
597 +       for_each_sg(sgt->sgl, sg, sgt->nents, i) {
598 +               size_t bytes;
599 +
600 +               bytes = iopgsz_max(len);
601 +
602 +               BUG_ON(!iopgsz_ok(bytes));
603 +
604 +               sg_set_buf(sg, phys_to_virt(pa), bytes);
605 +               /*
606 +                * 'pa' is cotinuous(linear).
607 +                */
608 +               pa += bytes;
609 +               len -= bytes;
610 +       }
611 +       BUG_ON(len);
612 +
613 +       clean_dcache_area(va, len);
614 +}
615 +
616 +static inline void sgtable_drain_kmalloc(struct sg_table *sgt)
617 +{
618 +       /*
619 +        * Actually this is not necessary at all, just exists for
620 +        * consistency of the code readibility
621 +        */
622 +       BUG_ON(!sgt);
623 +}
624 +
625 +/* create 'da' <-> 'pa' mapping from 'sgt' */
626 +static int map_iovm_area(struct iommu *obj, struct iovm_struct *new,
627 +                        const struct sg_table *sgt, u32 flags)
628 +{
629 +       int err;
630 +       unsigned int i, j;
631 +       struct scatterlist *sg;
632 +       u32 da = new->da_start;
633 +
634 +       if (!obj || !new || !sgt)
635 +               return -EINVAL;
636 +
637 +       BUG_ON(!sgtable_ok(sgt));
638 +
639 +       for_each_sg(sgt->sgl, sg, sgt->nents, i) {
640 +               u32 pa;
641 +               int pgsz;
642 +               size_t bytes;
643 +               struct iotlb_entry e;
644 +
645 +               pa = sg_phys(sg);
646 +               bytes = sg_dma_len(sg);
647 +
648 +               flags &= ~IOVMF_PGSZ_MASK;
649 +               pgsz = bytes_to_iopgsz(bytes);
650 +               if (pgsz < 0)
651 +                       goto err_out;
652 +               flags |= pgsz;
653 +
654 +               pr_debug("%s: [%d] %08x %08x(%x)\n", __func__,
655 +                        i, da, pa, bytes);
656 +
657 +               iotlb_init_entry(&e, da, pa, flags);
658 +               err = iopgtable_store_entry(obj, &e);
659 +               if (err)
660 +                       goto err_out;
661 +
662 +               da += bytes;
663 +       }
664 +       return 0;
665 +
666 +err_out:
667 +       da = new->da_start;
668 +
669 +       for_each_sg(sgt->sgl, sg, i, j) {
670 +               size_t bytes;
671 +
672 +               bytes = iopgtable_clear_entry(obj, da);
673 +
674 +               BUG_ON(!iopgsz_ok(bytes));
675 +
676 +               da += bytes;
677 +       }
678 +       return err;
679 +}
680 +
681 +/* release 'da' <-> 'pa' mapping */
682 +static void unmap_iovm_area(struct iommu *obj, struct iovm_struct *area)
683 +{
684 +       u32 start;
685 +       size_t total = area->da_end - area->da_start;
686 +
687 +       BUG_ON((!total) || !IS_ALIGNED(total, PAGE_SIZE));
688 +
689 +       start = area->da_start;
690 +       while (total > 0) {
691 +               size_t bytes;
692 +
693 +               bytes = iopgtable_clear_entry(obj, start);
694 +               if (bytes == 0)
695 +                       bytes = PAGE_SIZE;
696 +               else
697 +                       dev_dbg(obj->dev, "%s: unmap %08x(%x) %08x\n",
698 +                               __func__, start, bytes, area->flags);
699 +
700 +               BUG_ON(!IS_ALIGNED(bytes, PAGE_SIZE));
701 +
702 +               total -= bytes;
703 +               start += bytes;
704 +       }
705 +       BUG_ON(total);
706 +}
707 +
708 +/* template function for all unmapping */
709 +static struct sg_table *unmap_vm_area(struct iommu *obj, const u32 da,
710 +                                     void (*fn)(const void *), u32 flags)
711 +{
712 +       struct sg_table *sgt = NULL;
713 +       struct iovm_struct *area;
714 +
715 +       BUG_ON(in_interrupt());
716 +
717 +       if (!IS_ALIGNED(da, PAGE_SIZE)) {
718 +               dev_err(obj->dev, "%s: alignment err(%08x)\n", __func__, da);
719 +               return NULL;
720 +       }
721 +
722 +       mutex_lock(&obj->mmap_lock);
723 +
724 +       area = __find_iovm_area(obj, da);
725 +       if (!area) {
726 +               dev_err(obj->dev, "%s: no da area(%08x)\n", __func__, da);
727 +               goto out;
728 +       }
729 +
730 +       if ((area->flags & flags) != flags) {
731 +               dev_err(obj->dev, "%s: wrong flags(%08x)\n", __func__,
732 +                       area->flags);
733 +               goto out;
734 +       }
735 +       sgt = (struct sg_table *)area->sgt;
736 +
737 +       unmap_iovm_area(obj, area);
738 +
739 +       fn(area->va);
740 +
741 +       dev_dbg(obj->dev, "%s: %08x-%08x-%08x(%x) %08x\n", __func__,
742 +               area->da_start, da, area->da_end,
743 +               area->da_end - area->da_start, area->flags);
744 +
745 +       free_iovm_area(obj, area);
746 +out:
747 +       mutex_unlock(&obj->mmap_lock);
748 +
749 +       return sgt;
750 +}
751 +
752 +static u32 map_iommu_region(struct iommu *obj, u32 da,
753 +             const struct sg_table *sgt, void *va, size_t bytes, u32 flags)
754 +{
755 +       int err = -ENOMEM;
756 +       struct iovm_struct *new;
757 +
758 +       mutex_lock(&obj->mmap_lock);
759 +
760 +       new = alloc_iovm_area(obj, da, bytes, flags);
761 +       if (IS_ERR(new)) {
762 +               err = PTR_ERR(new);
763 +               goto err_alloc_iovma;
764 +       }
765 +       new->va = va;
766 +       new->sgt = sgt;
767 +
768 +       if (map_iovm_area(obj, new, sgt, new->flags))
769 +               goto err_map;
770 +
771 +       mutex_unlock(&obj->mmap_lock);
772 +
773 +       dev_dbg(obj->dev, "%s: da:%08x(%x) flags:%08x va:%p\n",
774 +               __func__, new->da_start, bytes, new->flags, va);
775 +
776 +       return new->da_start;
777 +
778 +err_map:
779 +       free_iovm_area(obj, new);
780 +err_alloc_iovma:
781 +       mutex_unlock(&obj->mmap_lock);
782 +       return err;
783 +}
784 +
785 +static inline u32 __iommu_vmap(struct iommu *obj, u32 da,
786 +                const struct sg_table *sgt, void *va, size_t bytes, u32 flags)
787 +{
788 +       return map_iommu_region(obj, da, sgt, va, bytes, flags);
789 +}
790 +
791 +/**
792 + * iommu_vmap  -  (d)-(p)-(v) address mapper
793 + * @obj:       objective iommu
794 + * @sgt:       address of scatter gather table
795 + * @flags:     iovma and page property
796 + *
797 + * Creates 1-n-1 mapping with given @sgt and returns @da.
798 + * All @sgt element must be io page size aligned.
799 + */
800 +u32 iommu_vmap(struct iommu *obj, u32 da, const struct sg_table *sgt,
801 +                u32 flags)
802 +{
803 +       size_t bytes;
804 +       void *va;
805 +
806 +       if (!obj || !obj->dev || !sgt)
807 +               return -EINVAL;
808 +
809 +       bytes = sgtable_len(sgt);
810 +       if (!bytes)
811 +               return -EINVAL;
812 +       bytes = PAGE_ALIGN(bytes);
813 +
814 +       va = vmap_sg(sgt);
815 +       if (IS_ERR(va))
816 +               return PTR_ERR(va);
817 +
818 +       flags &= IOVMF_HW_MASK;
819 +       flags |= IOVMF_DISCONT;
820 +       flags |= IOVMF_MMIO;
821 +       flags |= (da ? IOVMF_DA_FIXED : IOVMF_DA_ANON);
822 +
823 +       da = __iommu_vmap(obj, da, sgt, va, bytes, flags);
824 +       if (IS_ERR_VALUE(da))
825 +               vunmap_sg(va);
826 +
827 +       return da;
828 +}
829 +EXPORT_SYMBOL_GPL(iommu_vmap);
830 +
831 +/**
832 + * iommu_vunmap  -  release virtual mapping obtained by 'iommu_vmap()'
833 + * @obj:       objective iommu
834 + * @da:                iommu device virtual address
835 + *
836 + * Free the iommu virtually contiguous memory area starting at
837 + * @da, which was returned by 'iommu_vmap()'.
838 + */
839 +struct sg_table *iommu_vunmap(struct iommu *obj, u32 da)
840 +{
841 +       struct sg_table *sgt;
842 +       /*
843 +        * 'sgt' is allocated before 'iommu_vmalloc()' is called.
844 +        * Just returns 'sgt' to the caller to free
845 +        */
846 +       sgt = unmap_vm_area(obj, da, vunmap_sg, IOVMF_DISCONT | IOVMF_MMIO);
847 +       if (!sgt)
848 +               dev_err(obj->dev, "%s: No sgt\n", __func__);
849 +       return sgt;
850 +}
851 +EXPORT_SYMBOL_GPL(iommu_vunmap);
852 +
853 +/**
854 + * iommu_vmalloc  -  (d)-(p)-(v) address allocator and mapper
855 + * @obj:       objective iommu
856 + * @da:                contiguous iommu virtual memory
857 + * @bytes:     allocation size
858 + * @flags:     iovma and page property
859 + *
860 + * Allocate @bytes linearly and creates 1-n-1 mapping and returns
861 + * @da again, which might be adjusted if 'IOVMF_DA_ANON' is set.
862 + */
863 +u32 iommu_vmalloc(struct iommu *obj, u32 da, size_t bytes, u32 flags)
864 +{
865 +       void *va;
866 +       struct sg_table *sgt;
867 +
868 +       if (!obj || !obj->dev || !bytes)
869 +               return -EINVAL;
870 +
871 +       bytes = PAGE_ALIGN(bytes);
872 +
873 +       va = vmalloc(bytes);
874 +       if (!va)
875 +               return -ENOMEM;
876 +
877 +       sgt = sgtable_alloc(bytes, flags);
878 +       if (IS_ERR(sgt)) {
879 +               da = PTR_ERR(sgt);
880 +               goto err_sgt_alloc;
881 +       }
882 +       sgtable_fill_vmalloc(sgt, va);
883 +
884 +       flags &= IOVMF_HW_MASK;
885 +       flags |= IOVMF_DISCONT;
886 +       flags |= IOVMF_ALLOC;
887 +       flags |= (da ? IOVMF_DA_FIXED : IOVMF_DA_ANON);
888 +
889 +       da = __iommu_vmap(obj, da, sgt, va, bytes, flags);
890 +       if (IS_ERR_VALUE(da))
891 +               goto err_iommu_vmap;
892 +
893 +       return da;
894 +
895 +err_iommu_vmap:
896 +       sgtable_drain_vmalloc(sgt);
897 +       sgtable_free(sgt);
898 +err_sgt_alloc:
899 +       vfree(va);
900 +       return da;
901 +}
902 +EXPORT_SYMBOL_GPL(iommu_vmalloc);
903 +
904 +/**
905 + * iommu_vfree  -  release memory allocated by 'iommu_vmalloc()'
906 + * @obj:       objective iommu
907 + * @da:                iommu device virtual address
908 + *
909 + * Frees the iommu virtually continuous memory area starting at
910 + * @da, as obtained from 'iommu_vmalloc()'.
911 + */
912 +void iommu_vfree(struct iommu *obj, const u32 da)
913 +{
914 +       struct sg_table *sgt;
915 +
916 +       sgt = unmap_vm_area(obj, da, vfree, IOVMF_DISCONT | IOVMF_ALLOC);
917 +       if (!sgt)
918 +               dev_err(obj->dev, "%s: No sgt\n", __func__);
919 +       sgtable_free(sgt);
920 +}
921 +EXPORT_SYMBOL_GPL(iommu_vfree);
922 +
923 +static u32 __iommu_kmap(struct iommu *obj, u32 da, u32 pa, void *va,
924 +                         size_t bytes, u32 flags)
925 +{
926 +       struct sg_table *sgt;
927 +
928 +       sgt = sgtable_alloc(bytes, flags);
929 +       if (IS_ERR(sgt))
930 +               return PTR_ERR(sgt);
931 +
932 +       sgtable_fill_kmalloc(sgt, pa, bytes);
933 +
934 +       da = map_iommu_region(obj, da, sgt, va, bytes, flags);
935 +       if (IS_ERR_VALUE(da)) {
936 +               sgtable_drain_kmalloc(sgt);
937 +               sgtable_free(sgt);
938 +       }
939 +
940 +       return da;
941 +}
942 +
943 +/**
944 + * iommu_kmap  -  (d)-(p)-(v) address mapper
945 + * @obj:       objective iommu
946 + * @da:                contiguous iommu virtual memory
947 + * @pa:                contiguous physical memory
948 + * @flags:     iovma and page property
949 + *
950 + * Creates 1-1-1 mapping and returns @da again, which can be
951 + * adjusted if 'IOVMF_DA_ANON' is set.
952 + */
953 +u32 iommu_kmap(struct iommu *obj, u32 da, u32 pa, size_t bytes,
954 +                u32 flags)
955 +{
956 +       void *va;
957 +
958 +       if (!obj || !obj->dev || !bytes)
959 +               return -EINVAL;
960 +
961 +       bytes = PAGE_ALIGN(bytes);
962 +
963 +       va = ioremap(pa, bytes);
964 +       if (!va)
965 +               return -ENOMEM;
966 +
967 +       flags &= IOVMF_HW_MASK;
968 +       flags |= IOVMF_LINEAR;
969 +       flags |= IOVMF_MMIO;
970 +       flags |= (da ? IOVMF_DA_FIXED : IOVMF_DA_ANON);
971 +
972 +       da = __iommu_kmap(obj, da, pa, va, bytes, flags);
973 +       if (IS_ERR_VALUE(da))
974 +               iounmap(va);
975 +
976 +       return da;
977 +}
978 +EXPORT_SYMBOL_GPL(iommu_kmap);
979 +
980 +/**
981 + * iommu_kunmap  -  release virtual mapping obtained by 'iommu_kmap()'
982 + * @obj:       objective iommu
983 + * @da:                iommu device virtual address
984 + *
985 + * Frees the iommu virtually contiguous memory area starting at
986 + * @da, which was passed to and was returned by'iommu_kmap()'.
987 + */
988 +void iommu_kunmap(struct iommu *obj, u32 da)
989 +{
990 +       struct sg_table *sgt;
991 +
992 +       sgt = unmap_vm_area(obj, da, __iounmap, IOVMF_LINEAR | IOVMF_MMIO);
993 +       if (!sgt)
994 +               dev_err(obj->dev, "%s: No sgt\n", __func__);
995 +       sgtable_free(sgt);
996 +}
997 +EXPORT_SYMBOL_GPL(iommu_kunmap);
998 +
999 +/**
1000 + * iommu_kmalloc  -  (d)-(p)-(v) address allocator and mapper
1001 + * @obj:       objective iommu
1002 + * @da:                contiguous iommu virtual memory
1003 + * @bytes:     bytes for allocation
1004 + * @flags:     iovma and page property
1005 + *
1006 + * Allocate @bytes linearly and creates 1-1-1 mapping and returns
1007 + * @da again, which might be adjusted if 'IOVMF_DA_ANON' is set.
1008 + */
1009 +u32 iommu_kmalloc(struct iommu *obj, u32 da, size_t bytes, u32 flags)
1010 +{
1011 +       void *va;
1012 +       u32 pa;
1013 +
1014 +       if (!obj || !obj->dev || !bytes)
1015 +               return -EINVAL;
1016 +
1017 +       bytes = PAGE_ALIGN(bytes);
1018 +
1019 +       va = kmalloc(bytes, GFP_KERNEL | GFP_DMA);
1020 +       if (!va)
1021 +               return -ENOMEM;
1022 +       pa = virt_to_phys(va);
1023 +
1024 +       flags &= IOVMF_HW_MASK;
1025 +       flags |= IOVMF_LINEAR;
1026 +       flags |= IOVMF_ALLOC;
1027 +       flags |= (da ? IOVMF_DA_FIXED : IOVMF_DA_ANON);
1028 +
1029 +       da = __iommu_kmap(obj, da, pa, va, bytes, flags);
1030 +       if (IS_ERR_VALUE(da))
1031 +               kfree(va);
1032 +
1033 +       return da;
1034 +}
1035 +EXPORT_SYMBOL_GPL(iommu_kmalloc);
1036 +
1037 +/**
1038 + * iommu_kfree  -  release virtual mapping obtained by 'iommu_kmalloc()'
1039 + * @obj:       objective iommu
1040 + * @da:                iommu device virtual address
1041 + *
1042 + * Frees the iommu virtually contiguous memory area starting at
1043 + * @da, which was passed to and was returned by'iommu_kmalloc()'.
1044 + */
1045 +void iommu_kfree(struct iommu *obj, u32 da)
1046 +{
1047 +       struct sg_table *sgt;
1048 +
1049 +       sgt = unmap_vm_area(obj, da, kfree, IOVMF_LINEAR | IOVMF_ALLOC);
1050 +       if (!sgt)
1051 +               dev_err(obj->dev, "%s: No sgt\n", __func__);
1052 +       sgtable_free(sgt);
1053 +}
1054 +EXPORT_SYMBOL_GPL(iommu_kfree);
1055 +
1056 +
1057 +static int __init iovmm_init(void)
1058 +{
1059 +       const unsigned long flags = SLAB_HWCACHE_ALIGN;
1060 +       struct kmem_cache *p;
1061 +
1062 +       p = kmem_cache_create("iovm_area_cache", sizeof(struct iovm_struct), 0,
1063 +                             flags, NULL);
1064 +       if (!p)
1065 +               return -ENOMEM;
1066 +       iovm_area_cachep = p;
1067 +
1068 +       return 0;
1069 +}
1070 +module_init(iovmm_init);
1071 +
1072 +static void __exit iovmm_exit(void)
1073 +{
1074 +       kmem_cache_destroy(iovm_area_cachep);
1075 +}
1076 +module_exit(iovmm_exit);
1077 +
1078 +MODULE_DESCRIPTION("omap iommu: simple virtual address space management");
1079 +MODULE_AUTHOR("Hiroshi DOYU <Hiroshi.DOYU@nokia.com>");
1080 +MODULE_LICENSE("GPL v2");
1081 -- 
1082 1.5.6.5
1083