locking, lockdep: Convert sprintf_symbol to %pS
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / drivers / staging / tidspbridge / core / ue_deh.c
1 /*
2 * ue_deh.c
3 *
4 * DSP-BIOS Bridge driver support functions for TI OMAP processors.
5 *
6 * Implements upper edge DSP exception handling (DEH) functions.
7 *
8 * Copyright (C) 2005-2006 Texas Instruments, Inc.
9 * Copyright (C) 2010 Felipe Contreras
10 *
11 * This package is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License version 2 as
13 * published by the Free Software Foundation.
14 *
15 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
17 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
18 */
19
20 #include <linux/kernel.h>
21 #include <linux/interrupt.h>
22 #include <plat/dmtimer.h>
23
24 #include <dspbridge/dbdefs.h>
25 #include <dspbridge/dspdeh.h>
26 #include <dspbridge/dev.h>
27 #include "_tiomap.h"
28 #include "_deh.h"
29
30 #include <dspbridge/io_sm.h>
31 #include <dspbridge/drv.h>
32 #include <dspbridge/wdt.h>
33
34 int bridge_deh_create(struct deh_mgr **ret_deh,
35 struct dev_object *hdev_obj)
36 {
37 int status;
38 struct deh_mgr *deh;
39 struct bridge_dev_context *hbridge_context = NULL;
40
41 /* Message manager will be created when a file is loaded, since
42 * size of message buffer in shared memory is configurable in
43 * the base image. */
44 /* Get Bridge context info. */
45 dev_get_bridge_context(hdev_obj, &hbridge_context);
46 /* Allocate IO manager object: */
47 deh = kzalloc(sizeof(*deh), GFP_KERNEL);
48 if (!deh) {
49 status = -ENOMEM;
50 goto err;
51 }
52
53 /* Create an NTFY object to manage notifications */
54 deh->ntfy_obj = kmalloc(sizeof(struct ntfy_object), GFP_KERNEL);
55 if (!deh->ntfy_obj) {
56 status = -ENOMEM;
57 goto err;
58 }
59 ntfy_init(deh->ntfy_obj);
60
61 /* Fill in context structure */
62 deh->hbridge_context = hbridge_context;
63
64 *ret_deh = deh;
65 return 0;
66
67 err:
68 bridge_deh_destroy(deh);
69 *ret_deh = NULL;
70 return status;
71 }
72
73 int bridge_deh_destroy(struct deh_mgr *deh)
74 {
75 if (!deh)
76 return -EFAULT;
77
78 /* If notification object exists, delete it */
79 if (deh->ntfy_obj) {
80 ntfy_delete(deh->ntfy_obj);
81 kfree(deh->ntfy_obj);
82 }
83
84 /* Deallocate the DEH manager object */
85 kfree(deh);
86
87 return 0;
88 }
89
90 int bridge_deh_register_notify(struct deh_mgr *deh, u32 event_mask,
91 u32 notify_type,
92 struct dsp_notification *hnotification)
93 {
94 if (!deh)
95 return -EFAULT;
96
97 if (event_mask)
98 return ntfy_register(deh->ntfy_obj, hnotification,
99 event_mask, notify_type);
100 else
101 return ntfy_unregister(deh->ntfy_obj, hnotification);
102 }
103
104 static inline const char *event_to_string(int event)
105 {
106 switch (event) {
107 case DSP_SYSERROR: return "DSP_SYSERROR"; break;
108 case DSP_MMUFAULT: return "DSP_MMUFAULT"; break;
109 case DSP_PWRERROR: return "DSP_PWRERROR"; break;
110 case DSP_WDTOVERFLOW: return "DSP_WDTOVERFLOW"; break;
111 default: return "unkown event"; break;
112 }
113 }
114
115 void bridge_deh_notify(struct deh_mgr *deh, int event, int info)
116 {
117 struct bridge_dev_context *dev_context;
118 const char *str = event_to_string(event);
119
120 if (!deh)
121 return;
122
123 dev_dbg(bridge, "%s: device exception", __func__);
124 dev_context = deh->hbridge_context;
125
126 switch (event) {
127 case DSP_SYSERROR:
128 dev_err(bridge, "%s: %s, info=0x%x", __func__,
129 str, info);
130 #ifdef CONFIG_TIDSPBRIDGE_BACKTRACE
131 dump_dl_modules(dev_context);
132 dump_dsp_stack(dev_context);
133 #endif
134 break;
135 case DSP_MMUFAULT:
136 dev_err(bridge, "%s: %s, addr=0x%x", __func__, str, info);
137 break;
138 default:
139 dev_err(bridge, "%s: %s", __func__, str);
140 break;
141 }
142
143 /* Filter subsequent notifications when an error occurs */
144 if (dev_context->dw_brd_state != BRD_ERROR) {
145 ntfy_notify(deh->ntfy_obj, event);
146 #ifdef CONFIG_TIDSPBRIDGE_RECOVERY
147 bridge_recover_schedule();
148 #endif
149 }
150
151 /* Set the Board state as ERROR */
152 dev_context->dw_brd_state = BRD_ERROR;
153 /* Disable all the clocks that were enabled by DSP */
154 dsp_clock_disable_all(dev_context->dsp_per_clks);
155 /*
156 * Avoid the subsequent WDT if it happens once,
157 * also if fatal error occurs.
158 */
159 dsp_wdt_enable(false);
160 }