4 * DSP-BIOS Bridge driver support functions for TI OMAP processors.
6 * Implements upper edge DSP exception handling (DEH) functions.
8 * Copyright (C) 2005-2006 Texas Instruments, Inc.
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.
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.
19 /* ----------------------------------- Host OS */
20 #include <dspbridge/host_os.h>
22 /* ----------------------------------- DSP/BIOS Bridge */
23 #include <dspbridge/std.h>
24 #include <dspbridge/dbdefs.h>
26 /* ----------------------------------- Trace & Debug */
27 #include <dspbridge/dbc.h>
29 /* ----------------------------------- OS Adaptation Layer */
30 #include <dspbridge/cfg.h>
31 #include <dspbridge/clk.h>
32 #include <dspbridge/ntfy.h>
33 #include <dspbridge/drv.h>
35 /* ----------------------------------- Link Driver */
36 #include <dspbridge/dspdeh.h>
38 /* ----------------------------------- Platform Manager */
39 #include <dspbridge/dev.h>
40 #include <dspbridge/dspapi.h>
41 #include <dspbridge/wdt.h>
43 /* ------------------------------------ Hardware Abstraction Layer */
47 /* ----------------------------------- This */
48 #include "mmu_fault.h"
51 #include "_tiomap_pwr.h"
52 #include <dspbridge/io_sm.h>
55 static struct hw_mmu_map_attrs_t map_attrs
= { HW_LITTLE_ENDIAN
,
60 static void *dummy_va_addr
;
62 int bridge_deh_create(struct deh_mgr
**ret_deh_mgr
,
63 struct dev_object
*hdev_obj
)
66 struct deh_mgr
*deh_mgr
;
67 struct bridge_dev_context
*hbridge_context
= NULL
;
69 /* Message manager will be created when a file is loaded, since
70 * size of message buffer in shared memory is configurable in
72 /* Get Bridge context info. */
73 dev_get_bridge_context(hdev_obj
, &hbridge_context
);
74 DBC_ASSERT(hbridge_context
);
76 /* Allocate IO manager object: */
77 deh_mgr
= kzalloc(sizeof(struct deh_mgr
), GFP_KERNEL
);
83 /* Create an NTFY object to manage notifications */
84 deh_mgr
->ntfy_obj
= kmalloc(sizeof(struct ntfy_object
), GFP_KERNEL
);
85 if (deh_mgr
->ntfy_obj
) {
86 ntfy_init(deh_mgr
->ntfy_obj
);
92 /* Create a MMUfault DPC */
93 tasklet_init(&deh_mgr
->dpc_tasklet
, mmu_fault_dpc
, (u32
) deh_mgr
);
95 /* Fill in context structure */
96 deh_mgr
->hbridge_context
= hbridge_context
;
97 deh_mgr
->err_info
.dw_err_mask
= 0L;
98 deh_mgr
->err_info
.dw_val1
= 0L;
99 deh_mgr
->err_info
.dw_val2
= 0L;
100 deh_mgr
->err_info
.dw_val3
= 0L;
102 /* Install ISR function for DSP MMU fault */
103 if ((request_irq(INT_DSP_MMU_IRQ
, mmu_fault_isr
, 0,
104 "DspBridge\tiommu fault",
105 (void *)deh_mgr
)) == 0)
111 if (DSP_FAILED(status
)) {
112 /* If create failed, cleanup */
113 bridge_deh_destroy(deh_mgr
);
117 *ret_deh_mgr
= deh_mgr
;
122 int bridge_deh_destroy(struct deh_mgr
*deh_mgr
)
127 /* Release dummy VA buffer */
128 bridge_deh_release_dummy_mem();
129 /* If notification object exists, delete it */
130 if (deh_mgr
->ntfy_obj
) {
131 ntfy_delete(deh_mgr
->ntfy_obj
);
132 kfree(deh_mgr
->ntfy_obj
);
134 /* Disable DSP MMU fault */
135 free_irq(INT_DSP_MMU_IRQ
, deh_mgr
);
137 /* Free DPC object */
138 tasklet_kill(&deh_mgr
->dpc_tasklet
);
140 /* Deallocate the DEH manager object */
146 int bridge_deh_register_notify(struct deh_mgr
*deh_mgr
, u32 event_mask
,
148 struct dsp_notification
*hnotification
)
156 status
= ntfy_register(deh_mgr
->ntfy_obj
, hnotification
,
157 event_mask
, notify_type
);
159 status
= ntfy_unregister(deh_mgr
->ntfy_obj
, hnotification
);
164 void bridge_deh_notify(struct deh_mgr
*deh_mgr
, u32 ulEventMask
, u32 dwErrInfo
)
166 struct bridge_dev_context
*dev_context
;
168 u32 hw_mmu_max_tlb_count
= 31;
169 struct cfg_hostres
*resources
;
170 hw_status hw_status_obj
;
175 dev_info(bridge
, "%s: device exception\n", __func__
);
176 dev_context
= (struct bridge_dev_context
*)deh_mgr
->hbridge_context
;
177 resources
= dev_context
->resources
;
179 switch (ulEventMask
) {
181 /* reset err_info structure before use */
182 deh_mgr
->err_info
.dw_err_mask
= DSP_SYSERROR
;
183 deh_mgr
->err_info
.dw_val1
= 0L;
184 deh_mgr
->err_info
.dw_val2
= 0L;
185 deh_mgr
->err_info
.dw_val3
= 0L;
186 deh_mgr
->err_info
.dw_val1
= dwErrInfo
;
187 dev_err(bridge
, "%s: %s, err_info = 0x%x\n",
188 __func__
, "DSP_SYSERROR", dwErrInfo
);
189 dump_dl_modules(dev_context
);
190 dump_dsp_stack(dev_context
);
193 /* MMU fault routine should have set err info structure. */
194 deh_mgr
->err_info
.dw_err_mask
= DSP_MMUFAULT
;
195 dev_err(bridge
, "%s: %s, err_info = 0x%x\n",
196 __func__
, "DSP_MMUFAULT", dwErrInfo
);
197 dev_info(bridge
, "%s: %s, high=0x%x, low=0x%x, "
198 "fault=0x%x\n", __func__
, "DSP_MMUFAULT",
199 (unsigned int) deh_mgr
->err_info
.dw_val1
,
200 (unsigned int) deh_mgr
->err_info
.dw_val2
,
201 (unsigned int) fault_addr
);
202 dummy_va_addr
= (void*)__get_free_page(GFP_ATOMIC
);
203 dev_context
= (struct bridge_dev_context
*)
204 deh_mgr
->hbridge_context
;
206 print_dsp_trace_buffer(dev_context
);
207 dump_dl_modules(dev_context
);
210 * Reset the dynamic mmu index to fixed count if it exceeds
211 * 31. So that the dynmmuindex is always between the range of
212 * standard/fixed entries and 31.
214 if (dev_context
->num_tlb_entries
>
215 hw_mmu_max_tlb_count
) {
216 dev_context
->num_tlb_entries
=
217 dev_context
->fixed_tlb_entries
;
219 if (DSP_SUCCEEDED(status
)) {
221 hw_mmu_tlb_add(resources
->dw_dmmu_base
,
222 virt_to_phys(dummy_va_addr
), fault_addr
,
224 &map_attrs
, HW_SET
, HW_SET
);
227 dsp_clk_enable(DSP_CLK_GPT8
);
229 dsp_gpt_wait_overflow(DSP_CLK_GPT8
, 0xfffffffe);
231 /* Clear MMU interrupt */
232 hw_mmu_event_ack(resources
->dw_dmmu_base
,
233 HW_MMU_TRANSLATION_FAULT
);
234 dump_dsp_stack(deh_mgr
->hbridge_context
);
235 dsp_clk_disable(DSP_CLK_GPT8
);
237 #ifdef CONFIG_BRIDGE_NTFY_PWRERR
239 /* reset err_info structure before use */
240 deh_mgr
->err_info
.dw_err_mask
= DSP_PWRERROR
;
241 deh_mgr
->err_info
.dw_val1
= 0L;
242 deh_mgr
->err_info
.dw_val2
= 0L;
243 deh_mgr
->err_info
.dw_val3
= 0L;
244 deh_mgr
->err_info
.dw_val1
= dwErrInfo
;
245 dev_err(bridge
, "%s: %s, err_info = 0x%x\n",
246 __func__
, "DSP_PWRERROR", dwErrInfo
);
248 #endif /* CONFIG_BRIDGE_NTFY_PWRERR */
249 case DSP_WDTOVERFLOW
:
250 deh_mgr
->err_info
.dw_err_mask
= DSP_WDTOVERFLOW
;
251 deh_mgr
->err_info
.dw_val1
= 0L;
252 deh_mgr
->err_info
.dw_val2
= 0L;
253 deh_mgr
->err_info
.dw_val3
= 0L;
254 dev_err(bridge
, "%s: DSP_WDTOVERFLOW\n", __func__
);
257 dev_dbg(bridge
, "%s: Unknown Error, err_info = 0x%x\n",
258 __func__
, dwErrInfo
);
262 /* Filter subsequent notifications when an error occurs */
263 if (dev_context
->dw_brd_state
!= BRD_ERROR
) {
264 ntfy_notify(deh_mgr
->ntfy_obj
, ulEventMask
);
265 #ifdef CONFIG_BRIDGE_RECOVERY
266 bridge_recover_schedule();
270 /* Set the Board state as ERROR */
271 dev_context
->dw_brd_state
= BRD_ERROR
;
272 /* Disable all the clocks that were enabled by DSP */
273 dsp_clock_disable_all(dev_context
->dsp_per_clks
);
275 * Avoid the subsequent WDT if it happens once,
276 * also if fatal error occurs.
278 dsp_wdt_enable(false);
281 int bridge_deh_get_info(struct deh_mgr
*deh_mgr
,
282 struct dsp_errorinfo
*pErrInfo
)
284 DBC_REQUIRE(deh_mgr
);
285 DBC_REQUIRE(pErrInfo
);
290 /* Copy DEH error info structure to PROC error info structure. */
291 pErrInfo
->dw_err_mask
= deh_mgr
->err_info
.dw_err_mask
;
292 pErrInfo
->dw_val1
= deh_mgr
->err_info
.dw_val1
;
293 pErrInfo
->dw_val2
= deh_mgr
->err_info
.dw_val2
;
294 pErrInfo
->dw_val3
= deh_mgr
->err_info
.dw_val3
;
299 void bridge_deh_release_dummy_mem(void)
301 free_page((unsigned long)dummy_va_addr
);
302 dummy_va_addr
= NULL
;