aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/staging
diff options
context:
space:
mode:
authorFelipe Contreras <felipe.contreras@gmail.com>2010-11-10 13:10:20 -0500
committerOmar Ramirez Luna <omar.ramirez@ti.com>2010-11-10 19:34:43 -0500
commitf5bd96bbe320b9fe1c8132a1633e8582cd9d6245 (patch)
tree806f49035a0803211aa4c2daa910d2f412ff35c8 /drivers/staging
parent9d4f81a722863c42472541cb71981d09613775b3 (diff)
Revert "staging: tidspbridge - move all iommu related code to a new file"
This reverts commit f94378f9f9a897fc08e9d12733401ae52466e408. Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com> Signed-off-by: Omar Ramirez Luna <omar.ramirez@ti.com>
Diffstat (limited to 'drivers/staging')
-rw-r--r--drivers/staging/tidspbridge/Makefile2
-rw-r--r--drivers/staging/tidspbridge/core/_deh.h3
-rw-r--r--drivers/staging/tidspbridge/core/_tiomap.h27
-rw-r--r--drivers/staging/tidspbridge/core/dsp-mmu.c317
-rw-r--r--drivers/staging/tidspbridge/core/tiomap3430.c178
-rw-r--r--drivers/staging/tidspbridge/core/ue_deh.c86
-rw-r--r--drivers/staging/tidspbridge/include/dspbridge/dsp-mmu.h67
7 files changed, 289 insertions, 391 deletions
diff --git a/drivers/staging/tidspbridge/Makefile b/drivers/staging/tidspbridge/Makefile
index 37bd3bcc03a..1a091faac04 100644
--- a/drivers/staging/tidspbridge/Makefile
+++ b/drivers/staging/tidspbridge/Makefile
@@ -2,7 +2,7 @@ obj-$(CONFIG_TIDSPBRIDGE) += bridgedriver.o
2 2
3libgen = gen/gb.o gen/gs.o gen/gh.o gen/uuidutil.o 3libgen = gen/gb.o gen/gs.o gen/gh.o gen/uuidutil.o
4libcore = core/chnl_sm.o core/msg_sm.o core/io_sm.o core/tiomap3430.o \ 4libcore = core/chnl_sm.o core/msg_sm.o core/io_sm.o core/tiomap3430.o \
5 core/tiomap3430_pwr.o core/tiomap_io.o core/dsp-mmu.o \ 5 core/tiomap3430_pwr.o core/tiomap_io.o \
6 core/ue_deh.o core/wdt.o core/dsp-clock.o core/sync.o 6 core/ue_deh.o core/wdt.o core/dsp-clock.o core/sync.o
7libpmgr = pmgr/chnl.o pmgr/io.o pmgr/msg.o pmgr/cod.o pmgr/dev.o pmgr/dspapi.o \ 7libpmgr = pmgr/chnl.o pmgr/io.o pmgr/msg.o pmgr/cod.o pmgr/dev.o pmgr/dspapi.o \
8 pmgr/dmm.o pmgr/cmm.o pmgr/dbll.o 8 pmgr/dmm.o pmgr/cmm.o pmgr/dbll.o
diff --git a/drivers/staging/tidspbridge/core/_deh.h b/drivers/staging/tidspbridge/core/_deh.h
index 8ae263387a8..f1254f0aa03 100644
--- a/drivers/staging/tidspbridge/core/_deh.h
+++ b/drivers/staging/tidspbridge/core/_deh.h
@@ -27,6 +27,9 @@
27struct deh_mgr { 27struct deh_mgr {
28 struct bridge_dev_context *hbridge_context; /* Bridge context. */ 28 struct bridge_dev_context *hbridge_context; /* Bridge context. */
29 struct ntfy_object *ntfy_obj; /* NTFY object */ 29 struct ntfy_object *ntfy_obj; /* NTFY object */
30
31 /* MMU Fault DPC */
32 struct tasklet_struct dpc_tasklet;
30}; 33};
31 34
32int mmu_fault_isr(struct iommu *mmu); 35int mmu_fault_isr(struct iommu *mmu);
diff --git a/drivers/staging/tidspbridge/core/_tiomap.h b/drivers/staging/tidspbridge/core/_tiomap.h
index e0a801c1cb9..cd7ff8810a0 100644
--- a/drivers/staging/tidspbridge/core/_tiomap.h
+++ b/drivers/staging/tidspbridge/core/_tiomap.h
@@ -23,7 +23,8 @@
23#include <plat/clockdomain.h> 23#include <plat/clockdomain.h>
24#include <mach-omap2/prm-regbits-34xx.h> 24#include <mach-omap2/prm-regbits-34xx.h>
25#include <mach-omap2/cm-regbits-34xx.h> 25#include <mach-omap2/cm-regbits-34xx.h>
26#include <dspbridge/dsp-mmu.h> 26#include <plat/iommu.h>
27#include <plat/iovmm.h>
27#include <dspbridge/devdefs.h> 28#include <dspbridge/devdefs.h>
28#include <dspbridge/dspioctl.h> /* for bridge_ioctl_extproc defn */ 29#include <dspbridge/dspioctl.h> /* for bridge_ioctl_extproc defn */
29#include <dspbridge/sync.h> 30#include <dspbridge/sync.h>
@@ -379,4 +380,28 @@ extern s32 dsp_debug;
379 */ 380 */
380int sm_interrupt_dsp(struct bridge_dev_context *dev_context, u16 mb_val); 381int sm_interrupt_dsp(struct bridge_dev_context *dev_context, u16 mb_val);
381 382
383/**
384 * user_to_dsp_map() - maps user to dsp virtual address
385 * @mmu: Pointer to iommu handle.
386 * @uva: Virtual user space address.
387 * @da DSP address
388 * @size Buffer size to map.
389 * @usr_pgs struct page array pointer where the user pages will be stored
390 *
391 * This function maps a user space buffer into DSP virtual address.
392 *
393 */
394u32 user_to_dsp_map(struct iommu *mmu, u32 uva, u32 da, u32 size,
395 struct page **usr_pgs);
396
397/**
398 * user_to_dsp_unmap() - unmaps DSP virtual buffer.
399 * @mmu: Pointer to iommu handle.
400 * @da DSP address
401 *
402 * This function unmaps a user space buffer into DSP virtual address.
403 *
404 */
405int user_to_dsp_unmap(struct iommu *mmu, u32 da);
406
382#endif /* _TIOMAP_ */ 407#endif /* _TIOMAP_ */
diff --git a/drivers/staging/tidspbridge/core/dsp-mmu.c b/drivers/staging/tidspbridge/core/dsp-mmu.c
deleted file mode 100644
index 983c95adc8f..00000000000
--- a/drivers/staging/tidspbridge/core/dsp-mmu.c
+++ /dev/null
@@ -1,317 +0,0 @@
1/*
2 * dsp-mmu.c
3 *
4 * DSP-BIOS Bridge driver support functions for TI OMAP processors.
5 *
6 * DSP iommu.
7 *
8 * Copyright (C) 2010 Texas Instruments, Inc.
9 *
10 * This package is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 as
12 * published by the Free Software Foundation.
13 *
14 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
15 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
16 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
17 */
18
19#include <dspbridge/host_os.h>
20#include <plat/dmtimer.h>
21#include <dspbridge/dbdefs.h>
22#include <dspbridge/dev.h>
23#include <dspbridge/io_sm.h>
24#include <dspbridge/dspdeh.h>
25#include "_tiomap.h"
26
27#include <dspbridge/dsp-mmu.h>
28
29#define MMU_CNTL_TWL_EN (1 << 2)
30
31static struct tasklet_struct mmu_tasklet;
32
33#ifdef CONFIG_TIDSPBRIDGE_BACKTRACE
34static void mmu_fault_print_stack(struct bridge_dev_context *dev_context)
35{
36 void *dummy_addr;
37 u32 fa, tmp;
38 struct iotlb_entry e;
39 struct iommu *mmu = dev_context->dsp_mmu;
40 dummy_addr = (void *)__get_free_page(GFP_ATOMIC);
41
42 /*
43 * Before acking the MMU fault, let's make sure MMU can only
44 * access entry #0. Then add a new entry so that the DSP OS
45 * can continue in order to dump the stack.
46 */
47 tmp = iommu_read_reg(mmu, MMU_CNTL);
48 tmp &= ~MMU_CNTL_TWL_EN;
49 iommu_write_reg(mmu, tmp, MMU_CNTL);
50 fa = iommu_read_reg(mmu, MMU_FAULT_AD);
51 e.da = fa & PAGE_MASK;
52 e.pa = virt_to_phys(dummy_addr);
53 e.valid = 1;
54 e.prsvd = 1;
55 e.pgsz = IOVMF_PGSZ_4K & MMU_CAM_PGSZ_MASK;
56 e.endian = MMU_RAM_ENDIAN_LITTLE;
57 e.elsz = MMU_RAM_ELSZ_32;
58 e.mixed = 0;
59
60 load_iotlb_entry(mmu, &e);
61
62 dsp_clk_enable(DSP_CLK_GPT8);
63
64 dsp_gpt_wait_overflow(DSP_CLK_GPT8, 0xfffffffe);
65
66 /* Clear MMU interrupt */
67 tmp = iommu_read_reg(mmu, MMU_IRQSTATUS);
68 iommu_write_reg(mmu, tmp, MMU_IRQSTATUS);
69
70 dump_dsp_stack(dev_context);
71 dsp_clk_disable(DSP_CLK_GPT8);
72
73 iopgtable_clear_entry(mmu, fa);
74 free_page((unsigned long)dummy_addr);
75}
76#endif
77
78
79static void fault_tasklet(unsigned long data)
80{
81 struct iommu *mmu = (struct iommu *)data;
82 struct bridge_dev_context *dev_ctx;
83 struct deh_mgr *dm;
84 u32 fa;
85 dev_get_deh_mgr(dev_get_first(), &dm);
86 dev_get_bridge_context(dev_get_first(), &dev_ctx);
87
88 if (!dm || !dev_ctx)
89 return;
90
91 fa = iommu_read_reg(mmu, MMU_FAULT_AD);
92
93#ifdef CONFIG_TIDSPBRIDGE_BACKTRACE
94 print_dsp_trace_buffer(dev_ctx);
95 dump_dl_modules(dev_ctx);
96 mmu_fault_print_stack(dev_ctx);
97#endif
98
99 bridge_deh_notify(dm, DSP_MMUFAULT, fa);
100}
101
102/*
103 * ======== mmu_fault_isr ========
104 * ISR to be triggered by a DSP MMU fault interrupt.
105 */
106static int mmu_fault_callback(struct iommu *mmu)
107{
108 if (!mmu)
109 return -EPERM;
110
111 iommu_write_reg(mmu, 0, MMU_IRQENABLE);
112 tasklet_schedule(&mmu_tasklet);
113 return 0;
114}
115
116/**
117 * dsp_mmu_init() - initialize dsp_mmu module and returns a handle
118 *
119 * This function initialize dsp mmu module and returns a struct iommu
120 * handle to use it for dsp maps.
121 *
122 */
123struct iommu *dsp_mmu_init()
124{
125 struct iommu *mmu;
126
127 mmu = iommu_get("iva2");
128
129 if (!IS_ERR(mmu)) {
130 tasklet_init(&mmu_tasklet, fault_tasklet, (unsigned long)mmu);
131 mmu->isr = mmu_fault_callback;
132 }
133
134 return mmu;
135}
136
137/**
138 * dsp_mmu_exit() - destroy dsp mmu module
139 * @mmu: Pointer to iommu handle.
140 *
141 * This function destroys dsp mmu module.
142 *
143 */
144void dsp_mmu_exit(struct iommu *mmu)
145{
146 if (mmu)
147 iommu_put(mmu);
148 tasklet_kill(&mmu_tasklet);
149}
150
151/**
152 * user_va2_pa() - get physical address from userspace address.
153 * @mm: mm_struct Pointer of the process.
154 * @address: Virtual user space address.
155 *
156 */
157static u32 user_va2_pa(struct mm_struct *mm, u32 address)
158{
159 pgd_t *pgd;
160 pmd_t *pmd;
161 pte_t *ptep, pte;
162
163 pgd = pgd_offset(mm, address);
164 if (!(pgd_none(*pgd) || pgd_bad(*pgd))) {
165 pmd = pmd_offset(pgd, address);
166 if (!(pmd_none(*pmd) || pmd_bad(*pmd))) {
167 ptep = pte_offset_map(pmd, address);
168 if (ptep) {
169 pte = *ptep;
170 if (pte_present(pte))
171 return pte & PAGE_MASK;
172 }
173 }
174 }
175
176 return 0;
177}
178
179/**
180 * get_io_pages() - pin and get pages of io user's buffer.
181 * @mm: mm_struct Pointer of the process.
182 * @uva: Virtual user space address.
183 * @pages Pages to be pined.
184 * @usr_pgs struct page array pointer where the user pages will be stored
185 *
186 */
187static int get_io_pages(struct mm_struct *mm, u32 uva, unsigned pages,
188 struct page **usr_pgs)
189{
190 u32 pa;
191 int i;
192 struct page *pg;
193
194 for (i = 0; i < pages; i++) {
195 pa = user_va2_pa(mm, uva);
196
197 if (!pfn_valid(__phys_to_pfn(pa)))
198 break;
199
200 pg = phys_to_page(pa);
201 usr_pgs[i] = pg;
202 get_page(pg);
203 }
204 return i;
205}
206
207/**
208 * user_to_dsp_map() - maps user to dsp virtual address
209 * @mmu: Pointer to iommu handle.
210 * @uva: Virtual user space address.
211 * @da DSP address
212 * @size Buffer size to map.
213 * @usr_pgs struct page array pointer where the user pages will be stored
214 *
215 * This function maps a user space buffer into DSP virtual address.
216 *
217 */
218u32 user_to_dsp_map(struct iommu *mmu, u32 uva, u32 da, u32 size,
219 struct page **usr_pgs)
220{
221 int res, w;
222 unsigned pages;
223 int i;
224 struct vm_area_struct *vma;
225 struct mm_struct *mm = current->mm;
226 struct sg_table *sgt;
227 struct scatterlist *sg;
228
229 if (!size || !usr_pgs)
230 return -EINVAL;
231
232 pages = size / PG_SIZE4K;
233
234 down_read(&mm->mmap_sem);
235 vma = find_vma(mm, uva);
236 while (vma && (uva + size > vma->vm_end))
237 vma = find_vma(mm, vma->vm_end + 1);
238
239 if (!vma) {
240 pr_err("%s: Failed to get VMA region for 0x%x (%d)\n",
241 __func__, uva, size);
242 up_read(&mm->mmap_sem);
243 return -EINVAL;
244 }
245 if (vma->vm_flags & (VM_WRITE | VM_MAYWRITE))
246 w = 1;
247
248 if (vma->vm_flags & VM_IO)
249 i = get_io_pages(mm, uva, pages, usr_pgs);
250 else
251 i = get_user_pages(current, mm, uva, pages, w, 1,
252 usr_pgs, NULL);
253 up_read(&mm->mmap_sem);
254
255 if (i < 0)
256 return i;
257
258 if (i < pages) {
259 res = -EFAULT;
260 goto err_pages;
261 }
262
263 sgt = kzalloc(sizeof(*sgt), GFP_KERNEL);
264 if (!sgt) {
265 res = -ENOMEM;
266 goto err_pages;
267 }
268
269 res = sg_alloc_table(sgt, pages, GFP_KERNEL);
270
271 if (res < 0)
272 goto err_sg;
273
274 for_each_sg(sgt->sgl, sg, sgt->nents, i)
275 sg_set_page(sg, usr_pgs[i], PAGE_SIZE, 0);
276
277 da = iommu_vmap(mmu, da, sgt, IOVMF_ENDIAN_LITTLE | IOVMF_ELSZ_32);
278
279 if (!IS_ERR_VALUE(da))
280 return da;
281 res = (int)da;
282
283 sg_free_table(sgt);
284err_sg:
285 kfree(sgt);
286 i = pages;
287err_pages:
288 while (i--)
289 put_page(usr_pgs[i]);
290 return res;
291}
292
293/**
294 * user_to_dsp_unmap() - unmaps DSP virtual buffer.
295 * @mmu: Pointer to iommu handle.
296 * @da DSP address
297 *
298 * This function unmaps a user space buffer into DSP virtual address.
299 *
300 */
301int user_to_dsp_unmap(struct iommu *mmu, u32 da)
302{
303 unsigned i;
304 struct sg_table *sgt;
305 struct scatterlist *sg;
306
307 sgt = iommu_vunmap(mmu, da);
308 if (!sgt)
309 return -EFAULT;
310
311 for_each_sg(sgt->sgl, sg, sgt->nents, i)
312 put_page(sg_page(sg));
313 sg_free_table(sgt);
314 kfree(sgt);
315
316 return 0;
317}
diff --git a/drivers/staging/tidspbridge/core/tiomap3430.c b/drivers/staging/tidspbridge/core/tiomap3430.c
index 53b38b2b9ce..984a35a068e 100644
--- a/drivers/staging/tidspbridge/core/tiomap3430.c
+++ b/drivers/staging/tidspbridge/core/tiomap3430.c
@@ -53,6 +53,7 @@
53#include "_tiomap.h" 53#include "_tiomap.h"
54#include "_tiomap_pwr.h" 54#include "_tiomap_pwr.h"
55#include "tiomap_io.h" 55#include "tiomap_io.h"
56#include "_deh.h"
56 57
57/* Offset in shared mem to write to in order to synchronize start with DSP */ 58/* Offset in shared mem to write to in order to synchronize start with DSP */
58#define SHMSYNCOFFSET 4 /* GPP byte offset */ 59#define SHMSYNCOFFSET 4 /* GPP byte offset */
@@ -67,6 +68,7 @@
67#define MMU_SMALL_PAGE_MASK 0xFFFFF000 68#define MMU_SMALL_PAGE_MASK 0xFFFFF000
68#define OMAP3_IVA2_BOOTADDR_MASK 0xFFFFFC00 69#define OMAP3_IVA2_BOOTADDR_MASK 0xFFFFFC00
69#define PAGES_II_LVL_TABLE 512 70#define PAGES_II_LVL_TABLE 512
71#define PHYS_TO_PAGE(phys) pfn_to_page((phys) >> PAGE_SHIFT)
70 72
71/* 73/*
72 * This is a totally ugly layer violation, but needed until 74 * This is a totally ugly layer violation, but needed until
@@ -364,16 +366,17 @@ static int bridge_brd_start(struct bridge_dev_context *dev_ctxt,
364 OMAP3430_IVA2_MOD, OMAP2_RM_RSTCTRL); 366 OMAP3430_IVA2_MOD, OMAP2_RM_RSTCTRL);
365 mmu = dev_context->dsp_mmu; 367 mmu = dev_context->dsp_mmu;
366 if (mmu) 368 if (mmu)
367 dsp_mmu_exit(mmu); 369 iommu_put(mmu);
368 mmu = dsp_mmu_init(); 370 mmu = iommu_get("iva2");
369 if (IS_ERR(mmu)) { 371 if (IS_ERR(mmu)) {
370 dev_err(bridge, "dsp_mmu_init failed!\n"); 372 dev_err(bridge, "iommu_get failed!\n");
371 dev_context->dsp_mmu = NULL; 373 dev_context->dsp_mmu = NULL;
372 status = (int)mmu; 374 status = (int)mmu;
373 } 375 }
374 } 376 }
375 if (!status) { 377 if (!status) {
376 dev_context->dsp_mmu = mmu; 378 dev_context->dsp_mmu = mmu;
379 mmu->isr = mmu_fault_isr;
377 sm_sg = &dev_context->sh_s; 380 sm_sg = &dev_context->sh_s;
378 sg0_da = iommu_kmap(mmu, sm_sg->seg0_da, sm_sg->seg0_pa, 381 sg0_da = iommu_kmap(mmu, sm_sg->seg0_da, sm_sg->seg0_pa,
379 sm_sg->seg0_size, IOVMF_ENDIAN_LITTLE | IOVMF_ELSZ_32); 382 sm_sg->seg0_size, IOVMF_ENDIAN_LITTLE | IOVMF_ELSZ_32);
@@ -629,7 +632,7 @@ static int bridge_brd_stop(struct bridge_dev_context *dev_ctxt)
629 } 632 }
630 iommu_kunmap(dev_context->dsp_mmu, dev_context->sh_s.seg0_da); 633 iommu_kunmap(dev_context->dsp_mmu, dev_context->sh_s.seg0_da);
631 iommu_kunmap(dev_context->dsp_mmu, dev_context->sh_s.seg1_da); 634 iommu_kunmap(dev_context->dsp_mmu, dev_context->sh_s.seg1_da);
632 dsp_mmu_exit(dev_context->dsp_mmu); 635 iommu_put(dev_context->dsp_mmu);
633 dev_context->dsp_mmu = NULL; 636 dev_context->dsp_mmu = NULL;
634 } 637 }
635 /* Reset IVA IOMMU*/ 638 /* Reset IVA IOMMU*/
@@ -944,6 +947,173 @@ static int bridge_brd_mem_write(struct bridge_dev_context *dev_ctxt,
944} 947}
945 948
946/* 949/*
950 * ======== user_va2_pa ========
951 * Purpose:
952 * This function walks through the page tables to convert a userland
953 * virtual address to physical address
954 */
955static u32 user_va2_pa(struct mm_struct *mm, u32 address)
956{
957 pgd_t *pgd;
958 pmd_t *pmd;
959 pte_t *ptep, pte;
960
961 pgd = pgd_offset(mm, address);
962 if (!(pgd_none(*pgd) || pgd_bad(*pgd))) {
963 pmd = pmd_offset(pgd, address);
964 if (!(pmd_none(*pmd) || pmd_bad(*pmd))) {
965 ptep = pte_offset_map(pmd, address);
966 if (ptep) {
967 pte = *ptep;
968 if (pte_present(pte))
969 return pte & PAGE_MASK;
970 }
971 }
972 }
973
974 return 0;
975}
976
977/**
978 * get_io_pages() - pin and get pages of io user's buffer.
979 * @mm: mm_struct Pointer of the process.
980 * @uva: Virtual user space address.
981 * @pages Pages to be pined.
982 * @usr_pgs struct page array pointer where the user pages will be stored
983 *
984 */
985static int get_io_pages(struct mm_struct *mm, u32 uva, unsigned pages,
986 struct page **usr_pgs)
987{
988 u32 pa;
989 int i;
990 struct page *pg;
991
992 for (i = 0; i < pages; i++) {
993 pa = user_va2_pa(mm, uva);
994
995 if (!pfn_valid(__phys_to_pfn(pa)))
996 break;
997
998 pg = PHYS_TO_PAGE(pa);
999 usr_pgs[i] = pg;
1000 get_page(pg);
1001 }
1002 return i;
1003}
1004
1005/**
1006 * user_to_dsp_map() - maps user to dsp virtual address
1007 * @mmu: Pointer to iommu handle.
1008 * @uva: Virtual user space address.
1009 * @da DSP address
1010 * @size Buffer size to map.
1011 * @usr_pgs struct page array pointer where the user pages will be stored
1012 *
1013 * This function maps a user space buffer into DSP virtual address.
1014 *
1015 */
1016u32 user_to_dsp_map(struct iommu *mmu, u32 uva, u32 da, u32 size,
1017 struct page **usr_pgs)
1018{
1019 int res, w;
1020 unsigned pages, i;
1021 struct vm_area_struct *vma;
1022 struct mm_struct *mm = current->mm;
1023 struct sg_table *sgt;
1024 struct scatterlist *sg;
1025
1026 if (!size || !usr_pgs)
1027 return -EINVAL;
1028
1029 pages = size / PG_SIZE4K;
1030
1031 down_read(&mm->mmap_sem);
1032 vma = find_vma(mm, uva);
1033 while (vma && (uva + size > vma->vm_end))
1034 vma = find_vma(mm, vma->vm_end + 1);
1035
1036 if (!vma) {
1037 pr_err("%s: Failed to get VMA region for 0x%x (%d)\n",
1038 __func__, uva, size);
1039 up_read(&mm->mmap_sem);
1040 return -EINVAL;
1041 }
1042 if (vma->vm_flags & (VM_WRITE | VM_MAYWRITE))
1043 w = 1;
1044
1045 if (vma->vm_flags & VM_IO)
1046 i = get_io_pages(mm, uva, pages, usr_pgs);
1047 else
1048 i = get_user_pages(current, mm, uva, pages, w, 1,
1049 usr_pgs, NULL);
1050 up_read(&mm->mmap_sem);
1051
1052 if (i < 0)
1053 return i;
1054
1055 if (i < pages) {
1056 res = -EFAULT;
1057 goto err_pages;
1058 }
1059
1060 sgt = kzalloc(sizeof(*sgt), GFP_KERNEL);
1061 if (!sgt) {
1062 res = -ENOMEM;
1063 goto err_pages;
1064 }
1065
1066 res = sg_alloc_table(sgt, pages, GFP_KERNEL);
1067
1068 if (res < 0)
1069 goto err_sg;
1070
1071 for_each_sg(sgt->sgl, sg, sgt->nents, i)
1072 sg_set_page(sg, usr_pgs[i], PAGE_SIZE, 0);
1073
1074 da = iommu_vmap(mmu, da, sgt, IOVMF_ENDIAN_LITTLE | IOVMF_ELSZ_32);
1075
1076 if (!IS_ERR_VALUE(da))
1077 return da;
1078 res = (int)da;
1079
1080 sg_free_table(sgt);
1081err_sg:
1082 kfree(sgt);
1083 i = pages;
1084err_pages:
1085 while (i--)
1086 put_page(usr_pgs[i]);
1087 return res;
1088}
1089
1090/**
1091 * user_to_dsp_unmap() - unmaps DSP virtual buffer.
1092 * @mmu: Pointer to iommu handle.
1093 * @da DSP address
1094 *
1095 * This function unmaps a user space buffer into DSP virtual address.
1096 *
1097 */
1098int user_to_dsp_unmap(struct iommu *mmu, u32 da)
1099{
1100 unsigned i;
1101 struct sg_table *sgt;
1102 struct scatterlist *sg;
1103
1104 sgt = iommu_vunmap(mmu, da);
1105 if (!sgt)
1106 return -EFAULT;
1107
1108 for_each_sg(sgt->sgl, sg, sgt->nents, i)
1109 put_page(sg_page(sg));
1110 sg_free_table(sgt);
1111 kfree(sgt);
1112
1113 return 0;
1114}
1115
1116/*
947 * ======== wait_for_start ======== 1117 * ======== wait_for_start ========
948 * Wait for the singal from DSP that it has started, or time out. 1118 * Wait for the singal from DSP that it has started, or time out.
949 */ 1119 */
diff --git a/drivers/staging/tidspbridge/core/ue_deh.c b/drivers/staging/tidspbridge/core/ue_deh.c
index e24ea0c7391..2e1ac89644d 100644
--- a/drivers/staging/tidspbridge/core/ue_deh.c
+++ b/drivers/staging/tidspbridge/core/ue_deh.c
@@ -31,6 +31,32 @@
31#include <dspbridge/drv.h> 31#include <dspbridge/drv.h>
32#include <dspbridge/wdt.h> 32#include <dspbridge/wdt.h>
33 33
34#define MMU_CNTL_TWL_EN (1 << 2)
35
36static void mmu_fault_dpc(unsigned long data)
37{
38 struct deh_mgr *deh = (void *)data;
39
40 if (!deh)
41 return;
42
43 bridge_deh_notify(deh, DSP_MMUFAULT, 0);
44}
45
46int mmu_fault_isr(struct iommu *mmu)
47{
48 struct deh_mgr *dm;
49
50 dev_get_deh_mgr(dev_get_first(), &dm);
51
52 if (!dm)
53 return -EPERM;
54
55 iommu_write_reg(mmu, 0, MMU_IRQENABLE);
56 tasklet_schedule(&dm->dpc_tasklet);
57 return 0;
58}
59
34int bridge_deh_create(struct deh_mgr **ret_deh, 60int bridge_deh_create(struct deh_mgr **ret_deh,
35 struct dev_object *hdev_obj) 61 struct dev_object *hdev_obj)
36{ 62{
@@ -58,6 +84,9 @@ int bridge_deh_create(struct deh_mgr **ret_deh,
58 } 84 }
59 ntfy_init(deh->ntfy_obj); 85 ntfy_init(deh->ntfy_obj);
60 86
87 /* Create a MMUfault DPC */
88 tasklet_init(&deh->dpc_tasklet, mmu_fault_dpc, (u32) deh);
89
61 /* Fill in context structure */ 90 /* Fill in context structure */
62 deh->hbridge_context = hbridge_context; 91 deh->hbridge_context = hbridge_context;
63 92
@@ -81,6 +110,9 @@ int bridge_deh_destroy(struct deh_mgr *deh)
81 kfree(deh->ntfy_obj); 110 kfree(deh->ntfy_obj);
82 } 111 }
83 112
113 /* Free DPC object */
114 tasklet_kill(&deh->dpc_tasklet);
115
84 /* Deallocate the DEH manager object */ 116 /* Deallocate the DEH manager object */
85 kfree(deh); 117 kfree(deh);
86 118
@@ -101,6 +133,51 @@ int bridge_deh_register_notify(struct deh_mgr *deh, u32 event_mask,
101 return ntfy_unregister(deh->ntfy_obj, hnotification); 133 return ntfy_unregister(deh->ntfy_obj, hnotification);
102} 134}
103 135
136#ifdef CONFIG_TIDSPBRIDGE_BACKTRACE
137static void mmu_fault_print_stack(struct bridge_dev_context *dev_context)
138{
139 void *dummy_addr;
140 u32 fa, tmp;
141 struct iotlb_entry e;
142 struct iommu *mmu = dev_context->dsp_mmu;
143 dummy_addr = (void *)__get_free_page(GFP_ATOMIC);
144
145 /*
146 * Before acking the MMU fault, let's make sure MMU can only
147 * access entry #0. Then add a new entry so that the DSP OS
148 * can continue in order to dump the stack.
149 */
150 tmp = iommu_read_reg(mmu, MMU_CNTL);
151 tmp &= ~MMU_CNTL_TWL_EN;
152 iommu_write_reg(mmu, tmp, MMU_CNTL);
153 fa = iommu_read_reg(mmu, MMU_FAULT_AD);
154 e.da = fa & PAGE_MASK;
155 e.pa = virt_to_phys(dummy_addr);
156 e.valid = 1;
157 e.prsvd = 1;
158 e.pgsz = IOVMF_PGSZ_4K & MMU_CAM_PGSZ_MASK;
159 e.endian = MMU_RAM_ENDIAN_LITTLE;
160 e.elsz = MMU_RAM_ELSZ_32;
161 e.mixed = 0;
162
163 load_iotlb_entry(dev_context->dsp_mmu, &e);
164
165 dsp_clk_enable(DSP_CLK_GPT8);
166
167 dsp_gpt_wait_overflow(DSP_CLK_GPT8, 0xfffffffe);
168
169 /* Clear MMU interrupt */
170 tmp = iommu_read_reg(mmu, MMU_IRQSTATUS);
171 iommu_write_reg(mmu, tmp, MMU_IRQSTATUS);
172
173 dump_dsp_stack(dev_context);
174 dsp_clk_disable(DSP_CLK_GPT8);
175
176 iopgtable_clear_entry(mmu, fa);
177 free_page((unsigned long)dummy_addr);
178}
179#endif
180
104static inline const char *event_to_string(int event) 181static inline const char *event_to_string(int event)
105{ 182{
106 switch (event) { 183 switch (event) {
@@ -116,6 +193,7 @@ void bridge_deh_notify(struct deh_mgr *deh, int event, int info)
116{ 193{
117 struct bridge_dev_context *dev_context; 194 struct bridge_dev_context *dev_context;
118 const char *str = event_to_string(event); 195 const char *str = event_to_string(event);
196 u32 fa;
119 197
120 if (!deh) 198 if (!deh)
121 return; 199 return;
@@ -133,7 +211,13 @@ void bridge_deh_notify(struct deh_mgr *deh, int event, int info)
133#endif 211#endif
134 break; 212 break;
135 case DSP_MMUFAULT: 213 case DSP_MMUFAULT:
136 dev_err(bridge, "%s: %s, addr=0x%x", __func__, str, info); 214 fa = iommu_read_reg(dev_context->dsp_mmu, MMU_FAULT_AD);
215 dev_err(bridge, "%s: %s, addr=0x%x", __func__, str, fa);
216#ifdef CONFIG_TIDSPBRIDGE_BACKTRACE
217 print_dsp_trace_buffer(dev_context);
218 dump_dl_modules(dev_context);
219 mmu_fault_print_stack(dev_context);
220#endif
137 break; 221 break;
138 default: 222 default:
139 dev_err(bridge, "%s: %s", __func__, str); 223 dev_err(bridge, "%s: %s", __func__, str);
diff --git a/drivers/staging/tidspbridge/include/dspbridge/dsp-mmu.h b/drivers/staging/tidspbridge/include/dspbridge/dsp-mmu.h
deleted file mode 100644
index cb38d4cc073..00000000000
--- a/drivers/staging/tidspbridge/include/dspbridge/dsp-mmu.h
+++ /dev/null
@@ -1,67 +0,0 @@
1/*
2 * dsp-mmu.h
3 *
4 * DSP-BIOS Bridge driver support functions for TI OMAP processors.
5 *
6 * DSP iommu.
7 *
8 * Copyright (C) 2005-2010 Texas Instruments, Inc.
9 *
10 * This package is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 as
12 * published by the Free Software Foundation.
13 *
14 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
15 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
16 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
17 */
18
19#ifndef _DSP_MMU_
20#define _DSP_MMU_
21
22#include <plat/iommu.h>
23#include <plat/iovmm.h>
24
25/**
26 * dsp_mmu_init() - initialize dsp_mmu module and returns a handle
27 *
28 * This function initialize dsp mmu module and returns a struct iommu
29 * handle to use it for dsp maps.
30 *
31 */
32struct iommu *dsp_mmu_init(void);
33
34/**
35 * dsp_mmu_exit() - destroy dsp mmu module
36 * @mmu: Pointer to iommu handle.
37 *
38 * This function destroys dsp mmu module.
39 *
40 */
41void dsp_mmu_exit(struct iommu *mmu);
42
43/**
44 * user_to_dsp_map() - maps user to dsp virtual address
45 * @mmu: Pointer to iommu handle.
46 * @uva: Virtual user space address.
47 * @da DSP address
48 * @size Buffer size to map.
49 * @usr_pgs struct page array pointer where the user pages will be stored
50 *
51 * This function maps a user space buffer into DSP virtual address.
52 *
53 */
54u32 user_to_dsp_map(struct iommu *mmu, u32 uva, u32 da, u32 size,
55 struct page **usr_pgs);
56
57/**
58 * user_to_dsp_unmap() - unmaps DSP virtual buffer.
59 * @mmu: Pointer to iommu handle.
60 * @da DSP address
61 *
62 * This function unmaps a user space buffer into DSP virtual address.
63 *
64 */
65int user_to_dsp_unmap(struct iommu *mmu, u32 da);
66
67#endif