drivers/ata/pata_octeon_cf.c: delete double assignment
[pandora-kernel.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 }