blob: 922f8cd39cdcfe7d60d5cde68dce91e95918ccd6 [file] [log] [blame]
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001/* arch/arm/mach-msm/qdsp6/dsp_dump.c
2 *
3 * Copyright (C) 2009 Google, Inc.
4 * Author: Brian Swetland <swetland@google.com>
5 *
6 * This software is licensed under the terms of the GNU General Public
7 * License version 2, as published by the Free Software Foundation, and
8 * may be copied, distributed, and modified under those terms.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 */
16
17#include <linux/io.h>
18#include <linux/fs.h>
19#include <linux/module.h>
20#include <linux/miscdevice.h>
21#include <linux/uaccess.h>
22#include <linux/sched.h>
23#include <linux/wait.h>
24#include <linux/delay.h>
25#include <asm/atomic.h>
26
Steve Mucklef132c6c2012-06-06 18:30:57 -070027#include <mach/proc_comm.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070028#include <mach/debug_mm.h>
29
30static wait_queue_head_t dsp_wait;
31static int dsp_has_crashed;
32static int dsp_wait_count;
33
34static atomic_t dsp_crash_count = ATOMIC_INIT(0);
35
36void q6audio_dsp_not_responding(void)
37{
38
39 if (atomic_add_return(1, &dsp_crash_count) != 1) {
40 pr_err("q6audio_dsp_not_responding() - parking additional crasher...\n");
41 for (;;)
42 msleep(1000);
43 }
44 if (dsp_wait_count) {
45 dsp_has_crashed = 1;
46 wake_up(&dsp_wait);
47
48 while (dsp_has_crashed != 2)
49 wait_event(dsp_wait, dsp_has_crashed == 2);
50 } else {
51 pr_err("q6audio_dsp_not_responding() - no waiter?\n");
52 }
53 BUG();
54}
55
56static int dsp_open(struct inode *inode, struct file *file)
57{
58 return 0;
59}
60
61static ssize_t dsp_write(struct file *file, const char __user *buf,
62 size_t count, loff_t *pos)
63{
64 char cmd[32];
65
66 if (count >= sizeof(cmd))
67 return -EINVAL;
68 if (copy_from_user(cmd, buf, count))
69 return -EFAULT;
70 cmd[count] = 0;
71
72 if ((count > 1) && (cmd[count-1] == '\n'))
73 cmd[count-1] = 0;
74
75 if (!strcmp(cmd, "wait-for-crash")) {
76 while (!dsp_has_crashed) {
77 int res;
78 dsp_wait_count++;
79 res = wait_event_interruptible(dsp_wait, dsp_has_crashed);
80 if (res < 0) {
81 dsp_wait_count--;
82 return res;
83 }
84 }
85#if defined(CONFIG_MACH_MAHIMAHI)
86 /* assert DSP NMI */
87 msm_proc_comm(PCOM_CUSTOMER_CMD1, 0, 0);
88 msleep(250);
89#endif
90 } else if (!strcmp(cmd, "boom")) {
91 q6audio_dsp_not_responding();
92 } else if (!strcmp(cmd, "continue-crash")) {
93 dsp_has_crashed = 2;
94 wake_up(&dsp_wait);
95 } else {
96 pr_err("[%s:%s] unknown dsp_debug command: %s\n", __MM_FILE__,
97 __func__, cmd);
98 }
99
100 return count;
101}
102
103#define DSP_RAM_BASE 0x2E800000
104#define DSP_RAM_SIZE 0x01800000
105
106static unsigned copy_ok_count;
107
108static ssize_t dsp_read(struct file *file, char __user *buf,
109 size_t count, loff_t *pos)
110{
111 size_t actual = 0;
112 size_t mapsize = PAGE_SIZE;
113 unsigned addr;
114 void __iomem *ptr;
115
116 if (*pos >= DSP_RAM_SIZE)
117 return 0;
118
119 if (*pos & (PAGE_SIZE - 1))
120 return -EINVAL;
121
122 addr = (*pos + DSP_RAM_BASE);
123
124 /* don't blow up if we're unaligned */
125 if (addr & (PAGE_SIZE - 1))
126 mapsize *= 2;
127
128 while (count >= PAGE_SIZE) {
129 ptr = ioremap(addr, mapsize);
130 if (!ptr) {
131 pr_err("[%s:%s] map error @ %x\n", __MM_FILE__,
132 __func__, addr);
133 return -EFAULT;
134 }
135 if (copy_to_user(buf, ptr, PAGE_SIZE)) {
136 iounmap(ptr);
137 pr_err("[%s:%s] copy error @ %p\n", __MM_FILE__,
138 __func__, buf);
139 return -EFAULT;
140 }
141 copy_ok_count += PAGE_SIZE;
142 iounmap(ptr);
143 addr += PAGE_SIZE;
144 buf += PAGE_SIZE;
145 actual += PAGE_SIZE;
146 count -= PAGE_SIZE;
147 }
148
149 *pos += actual;
150 return actual;
151}
152
153static int dsp_release(struct inode *inode, struct file *file)
154{
155 return 0;
156}
157
158static const struct file_operations dsp_fops = {
159 .owner = THIS_MODULE,
160 .open = dsp_open,
161 .read = dsp_read,
162 .write = dsp_write,
163 .release = dsp_release,
164};
165
166static struct miscdevice dsp_misc = {
167 .minor = MISC_DYNAMIC_MINOR,
168 .name = "dsp_debug",
169 .fops = &dsp_fops,
170};
171
172
173static int __init dsp_init(void)
174{
175 init_waitqueue_head(&dsp_wait);
176 return misc_register(&dsp_misc);
177}
178
179device_initcall(dsp_init);