]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blob - arch/arm/plat-omap/dsp/error.c
9ed00aeda4a432471ac761963c7f6e0c67356fd1
[linux-2.6-omap-h63xx.git] / arch / arm / plat-omap / dsp / error.c
1 /*
2  * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1)
3  *
4  * Copyright (C) 2002-2006 Nokia Corporation. All rights reserved.
5  *
6  * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * version 2 as published by the Free Software Foundation.
11  *
12  * This program is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20  * 02110-1301 USA
21  *
22  */
23
24 #include <linux/module.h>
25 #include <linux/fs.h>
26 #include <linux/poll.h>
27 #include <linux/sched.h>
28 #include <linux/interrupt.h>
29 #include <asm/uaccess.h>
30 #include "dsp_mbcmd.h"
31 #include "dsp.h"
32
33 /*
34  * value seen through read()
35  */
36 #define DSP_ERR_WDT     0x00000001
37 #define DSP_ERR_MMU     0x00000002
38 static unsigned long errval;
39
40 static DECLARE_WAIT_QUEUE_HEAD(err_wait_q);
41 static int errcnt;
42 static u16 wdtval;      /* FIXME: read through ioctl */
43 static u32 mmu_fadr;    /* FIXME: read through ioctl */
44
45 /*
46  * DSP error detection device file operations
47  */
48 static ssize_t dsp_err_read(struct file *file, char __user *buf, size_t count,
49                             loff_t *ppos)
50 {
51         unsigned long flags;
52         int status;
53
54         if (count < 4)
55                 return 0;
56
57         if (errcnt == 0) {
58                 long current_state;
59                 DECLARE_WAITQUEUE(wait, current);
60
61                 add_wait_queue(&err_wait_q, &wait);
62                 current_state = current->state;
63                 set_current_state(TASK_INTERRUPTIBLE);
64                 if (errcnt == 0)        /* last check */
65                         schedule();
66                 set_current_state(current_state);
67                 remove_wait_queue(&err_wait_q, &wait);
68                 if (signal_pending(current))
69                         return -EINTR;
70         }
71
72         local_irq_save(flags);
73         status = copy_to_user(buf, &errval, 4);
74         if (status) {
75                 local_irq_restore(flags);
76                 return -EFAULT;
77         }
78         errcnt = 0;
79         local_irq_restore(flags);
80
81         return 4;
82 }
83
84 static unsigned int dsp_err_poll(struct file *file, poll_table *wait)
85 {
86         unsigned int mask = 0;
87
88         poll_wait(file, &err_wait_q, wait);
89         if (errcnt != 0)
90                 mask |= POLLIN | POLLRDNORM;
91
92         return mask;
93 }
94
95 struct file_operations dsp_err_fops = {
96         .owner = THIS_MODULE,
97         .poll  = dsp_err_poll,
98         .read  = dsp_err_read,
99 };
100
101 /*
102  * set / clear functions
103  */
104
105 /* DSP MMU */
106 static void dsp_err_mmu_set(unsigned long arg)
107 {
108         disable_irq(INT_DSP_MMU);
109         mmu_fadr = (u32)arg;
110 }
111
112 static void dsp_err_mmu_clr(void)
113 {
114         enable_irq(INT_DSP_MMU);
115 }
116
117 /* WDT */
118 static void dsp_err_wdt_set(unsigned long arg)
119 {
120         wdtval = (u16)arg;
121 }
122
123 /*
124  * error code handler
125  */
126 static struct {
127         unsigned long val;
128         void (*set)(unsigned long arg);
129         void (*clr)(void);
130 } dsp_err_desc[ERRCODE_MAX] = {
131         [ERRCODE_MMU] = { DSP_ERR_MMU, dsp_err_mmu_set, dsp_err_mmu_clr },
132         [ERRCODE_WDT] = { DSP_ERR_WDT, dsp_err_wdt_set, NULL },
133 };
134
135 void dsp_err_set(enum errcode_e code, unsigned long arg)
136 {
137         if (dsp_err_desc[code].set != NULL)
138                 dsp_err_desc[code].set(arg);
139
140         errval |= dsp_err_desc[code].val;
141         errcnt++;
142         wake_up_interruptible(&err_wait_q);
143 }
144
145 void dsp_err_clear(enum errcode_e code)
146 {
147         errval &= ~dsp_err_desc[code].val;
148
149         if (dsp_err_desc[code].clr != NULL)
150                 dsp_err_desc[code].clr();
151 }
152
153 int dsp_err_isset(enum errcode_e code)
154 {
155         return (errval & dsp_err_desc[code].val) ? 1 : 0;
156 }
157
158 /*
159  * functions called from mailbox interrupt routine
160  */
161 static void mbx_err_wdt(u16 data)
162 {
163         dsp_err_set(DSP_ERR_WDT, (unsigned long)data);
164 }
165
166 #ifdef OLD_BINARY_SUPPORT
167 /* v3.3 obsolete */
168 void mbx_wdt(struct mbcmd *mb)
169 {
170         mbx_err_wdt(mb->data);
171 }
172 #endif
173
174 extern void mbx_err_ipbfull(void);
175 extern void mbx_err_fatal(u8 tid);
176
177 void mbx_err(struct mbcmd *mb)
178 {
179         u8 eid = mb->cmd_l;
180         char *eidnm = subcmd_name(mb);
181         u8 tid;
182
183         if (eidnm) {
184                 printk(KERN_WARNING
185                        "mbx: ERR from DSP (%s): 0x%04x\n", eidnm, mb->data);
186         } else {
187                 printk(KERN_WARNING
188                        "mbx: ERR from DSP (unknown EID=%02x): %04x\n",
189                        eid, mb->data);
190         }
191
192         switch (eid) {
193         case EID_IPBFULL:
194                 mbx_err_ipbfull();
195                 break;
196
197         case EID_FATAL:
198                 tid = mb->data & 0x00ff;
199                 mbx_err_fatal(tid);
200                 break;
201
202         case EID_WDT:
203                 mbx_err_wdt(mb->data);
204                 break;
205         }
206 }
207
208 /*
209  *
210  */
211 void dsp_err_start(void)
212 {
213         enum errcode_e i;
214
215         for (i = 0; i < ERRCODE_MAX; i++) {
216                 if (dsp_err_isset(i))
217                         dsp_err_clear(i);
218         }
219
220         errcnt = 0;
221 }
222
223 void dsp_err_stop(void)
224 {
225         wake_up_interruptible(&err_wait_q);
226 }