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 int bridge_deh_create(struct deh_mgr
**ret_deh_mgr
,
56 struct dev_object
*hdev_obj
)
59 struct deh_mgr
*deh_mgr
;
60 struct bridge_dev_context
*hbridge_context
= NULL
;
62 /* Message manager will be created when a file is loaded, since
63 * size of message buffer in shared memory is configurable in
65 /* Get Bridge context info. */
66 dev_get_bridge_context(hdev_obj
, &hbridge_context
);
67 /* Allocate IO manager object: */
68 deh_mgr
= kzalloc(sizeof(struct deh_mgr
), GFP_KERNEL
);
74 /* Create an NTFY object to manage notifications */
75 deh_mgr
->ntfy_obj
= kmalloc(sizeof(struct ntfy_object
), GFP_KERNEL
);
76 if (!deh_mgr
->ntfy_obj
) {
80 ntfy_init(deh_mgr
->ntfy_obj
);
82 /* Create a MMUfault DPC */
83 tasklet_init(&deh_mgr
->dpc_tasklet
, mmu_fault_dpc
, (u32
) deh_mgr
);
85 /* Fill in context structure */
86 deh_mgr
->hbridge_context
= hbridge_context
;
87 deh_mgr
->err_info
.dw_err_mask
= 0L;
88 deh_mgr
->err_info
.dw_val1
= 0L;
89 deh_mgr
->err_info
.dw_val2
= 0L;
90 deh_mgr
->err_info
.dw_val3
= 0L;
92 /* Install ISR function for DSP MMU fault */
93 status
= request_irq(INT_DSP_MMU_IRQ
, mmu_fault_isr
, 0,
94 "DspBridge\tiommu fault", deh_mgr
);
98 *ret_deh_mgr
= deh_mgr
;
102 bridge_deh_destroy(deh_mgr
);
107 int bridge_deh_destroy(struct deh_mgr
*deh_mgr
)
112 /* If notification object exists, delete it */
113 if (deh_mgr
->ntfy_obj
) {
114 ntfy_delete(deh_mgr
->ntfy_obj
);
115 kfree(deh_mgr
->ntfy_obj
);
117 /* Disable DSP MMU fault */
118 free_irq(INT_DSP_MMU_IRQ
, deh_mgr
);
120 /* Free DPC object */
121 tasklet_kill(&deh_mgr
->dpc_tasklet
);
123 /* Deallocate the DEH manager object */
129 int bridge_deh_register_notify(struct deh_mgr
*deh_mgr
, u32 event_mask
,
131 struct dsp_notification
*hnotification
)
137 return ntfy_register(deh_mgr
->ntfy_obj
, hnotification
,
138 event_mask
, notify_type
);
140 return ntfy_unregister(deh_mgr
->ntfy_obj
, hnotification
);
143 void bridge_deh_notify(struct deh_mgr
*deh_mgr
, u32 ulEventMask
, u32 dwErrInfo
)
145 struct bridge_dev_context
*dev_context
;
146 struct cfg_hostres
*resources
;
147 struct hw_mmu_map_attrs_t map_attrs
= {
148 .endianism
= HW_LITTLE_ENDIAN
,
149 .element_size
= HW_ELEM_SIZE16BIT
,
150 .mixed_size
= HW_MMU_CPUES
,
157 dev_info(bridge
, "%s: device exception\n", __func__
);
158 dev_context
= deh_mgr
->hbridge_context
;
159 resources
= dev_context
->resources
;
161 switch (ulEventMask
) {
163 /* reset err_info structure before use */
164 deh_mgr
->err_info
.dw_err_mask
= DSP_SYSERROR
;
165 deh_mgr
->err_info
.dw_val1
= 0L;
166 deh_mgr
->err_info
.dw_val2
= 0L;
167 deh_mgr
->err_info
.dw_val3
= 0L;
168 deh_mgr
->err_info
.dw_val1
= dwErrInfo
;
169 dev_err(bridge
, "%s: %s, err_info = 0x%x\n",
170 __func__
, "DSP_SYSERROR", dwErrInfo
);
171 dump_dl_modules(dev_context
);
172 dump_dsp_stack(dev_context
);
175 /* MMU fault routine should have set err info structure. */
176 deh_mgr
->err_info
.dw_err_mask
= DSP_MMUFAULT
;
177 dev_err(bridge
, "%s: %s, err_info = 0x%x\n",
178 __func__
, "DSP_MMUFAULT", dwErrInfo
);
179 dev_info(bridge
, "%s: %s, high=0x%x, low=0x%x, "
180 "fault=0x%x\n", __func__
, "DSP_MMUFAULT",
181 (unsigned int) deh_mgr
->err_info
.dw_val1
,
182 (unsigned int) deh_mgr
->err_info
.dw_val2
,
183 (unsigned int) fault_addr
);
184 dummy_va_addr
= (void*)__get_free_page(GFP_ATOMIC
);
186 print_dsp_trace_buffer(dev_context
);
187 dump_dl_modules(dev_context
);
189 hw_mmu_tlb_add(resources
->dw_dmmu_base
,
190 virt_to_phys(dummy_va_addr
), fault_addr
,
192 &map_attrs
, HW_SET
, HW_SET
);
194 dsp_clk_enable(DSP_CLK_GPT8
);
196 dsp_gpt_wait_overflow(DSP_CLK_GPT8
, 0xfffffffe);
198 /* Clear MMU interrupt */
199 hw_mmu_event_ack(resources
->dw_dmmu_base
,
200 HW_MMU_TRANSLATION_FAULT
);
201 dump_dsp_stack(dev_context
);
202 dsp_clk_disable(DSP_CLK_GPT8
);
204 hw_mmu_disable(resources
->dw_dmmu_base
);
205 free_page((unsigned long)dummy_va_addr
);
207 #ifdef CONFIG_BRIDGE_NTFY_PWRERR
209 /* reset err_info structure before use */
210 deh_mgr
->err_info
.dw_err_mask
= DSP_PWRERROR
;
211 deh_mgr
->err_info
.dw_val1
= 0L;
212 deh_mgr
->err_info
.dw_val2
= 0L;
213 deh_mgr
->err_info
.dw_val3
= 0L;
214 deh_mgr
->err_info
.dw_val1
= dwErrInfo
;
215 dev_err(bridge
, "%s: %s, err_info = 0x%x\n",
216 __func__
, "DSP_PWRERROR", dwErrInfo
);
218 #endif /* CONFIG_BRIDGE_NTFY_PWRERR */
219 case DSP_WDTOVERFLOW
:
220 deh_mgr
->err_info
.dw_err_mask
= DSP_WDTOVERFLOW
;
221 deh_mgr
->err_info
.dw_val1
= 0L;
222 deh_mgr
->err_info
.dw_val2
= 0L;
223 deh_mgr
->err_info
.dw_val3
= 0L;
224 dev_err(bridge
, "%s: DSP_WDTOVERFLOW\n", __func__
);
227 dev_dbg(bridge
, "%s: Unknown Error, err_info = 0x%x\n",
228 __func__
, dwErrInfo
);
232 /* Filter subsequent notifications when an error occurs */
233 if (dev_context
->dw_brd_state
!= BRD_ERROR
) {
234 ntfy_notify(deh_mgr
->ntfy_obj
, ulEventMask
);
235 #ifdef CONFIG_BRIDGE_RECOVERY
236 bridge_recover_schedule();
240 /* Set the Board state as ERROR */
241 dev_context
->dw_brd_state
= BRD_ERROR
;
242 /* Disable all the clocks that were enabled by DSP */
243 dsp_clock_disable_all(dev_context
->dsp_per_clks
);
245 * Avoid the subsequent WDT if it happens once,
246 * also if fatal error occurs.
248 dsp_wdt_enable(false);
251 int bridge_deh_get_info(struct deh_mgr
*deh_mgr
,
252 struct dsp_errorinfo
*pErrInfo
)
257 /* Copy DEH error info structure to PROC error info structure. */
258 pErrInfo
->dw_err_mask
= deh_mgr
->err_info
.dw_err_mask
;
259 pErrInfo
->dw_val1
= deh_mgr
->err_info
.dw_val1
;
260 pErrInfo
->dw_val2
= deh_mgr
->err_info
.dw_val2
;
261 pErrInfo
->dw_val3
= deh_mgr
->err_info
.dw_val3
;