staging: ti dspbridge: add core driver sources
[linux-2.6/linux-acpi-2.6/ibm-acpi-2.6.git] / drivers / staging / tidspbridge / core / ue_deh.c
blob64e936641182056cbf81658d116ec00e6d38d29e
1 /*
2 * ue_deh.c
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 */
44 #include <hw_defs.h>
45 #include <hw_mmu.h>
47 /* ----------------------------------- This */
48 #include "mmu_fault.h"
49 #include "_tiomap.h"
50 #include "_deh.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,
56 HW_ELEM_SIZE16BIT,
57 HW_MMU_CPUES
60 static void *dummy_va_addr;
62 int bridge_deh_create(struct deh_mgr **ret_deh_mgr,
63 struct dev_object *hdev_obj)
65 int status = 0;
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
71 * the base image. */
72 /* Get Bridge context info. */
73 dev_get_bridge_context(hdev_obj, &hbridge_context);
74 DBC_ASSERT(hbridge_context);
75 dummy_va_addr = NULL;
76 /* Allocate IO manager object: */
77 deh_mgr = kzalloc(sizeof(struct deh_mgr), GFP_KERNEL);
78 if (!deh_mgr) {
79 status = -ENOMEM;
80 goto leave;
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);
87 } else {
88 status = -ENOMEM;
89 goto err;
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)
106 status = 0;
107 else
108 status = -EPERM;
110 err:
111 if (DSP_FAILED(status)) {
112 /* If create failed, cleanup */
113 bridge_deh_destroy(deh_mgr);
114 deh_mgr = NULL;
116 leave:
117 *ret_deh_mgr = deh_mgr;
119 return status;
122 int bridge_deh_destroy(struct deh_mgr *deh_mgr)
124 if (!deh_mgr)
125 return -EFAULT;
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 */
141 kfree(deh_mgr);
143 return 0;
146 int bridge_deh_register_notify(struct deh_mgr *deh_mgr, u32 event_mask,
147 u32 notify_type,
148 struct dsp_notification *hnotification)
150 int status = 0;
152 if (!deh_mgr)
153 return -EFAULT;
155 if (event_mask)
156 status = ntfy_register(deh_mgr->ntfy_obj, hnotification,
157 event_mask, notify_type);
158 else
159 status = ntfy_unregister(deh_mgr->ntfy_obj, hnotification);
161 return status;
164 void bridge_deh_notify(struct deh_mgr *deh_mgr, u32 ulEventMask, u32 dwErrInfo)
166 struct bridge_dev_context *dev_context;
167 int status = 0;
168 u32 hw_mmu_max_tlb_count = 31;
169 struct cfg_hostres *resources;
170 hw_status hw_status_obj;
172 if (!deh_mgr)
173 return;
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) {
180 case DSP_SYSERROR:
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);
191 break;
192 case DSP_MMUFAULT:
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)) {
220 hw_status_obj =
221 hw_mmu_tlb_add(resources->dw_dmmu_base,
222 virt_to_phys(dummy_va_addr), fault_addr,
223 HW_PAGE_SIZE4KB, 1,
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);
236 break;
237 #ifdef CONFIG_BRIDGE_NTFY_PWRERR
238 case DSP_PWRERROR:
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);
247 break;
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__);
255 break;
256 default:
257 dev_dbg(bridge, "%s: Unknown Error, err_info = 0x%x\n",
258 __func__, dwErrInfo);
259 break;
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();
267 #endif
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);
287 if (!deh_mgr)
288 return -EFAULT;
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;
296 return 0;
299 void bridge_deh_release_dummy_mem(void)
301 free_page((unsigned long)dummy_va_addr);
302 dummy_va_addr = NULL;