blob: 1d8195eb1843c5d92b486d5a0f01cc5a7ae1ef14 [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>
Swaminathan Sathappanb77c65e92011-09-30 18:36:09 -070025#include <linux/platform_device.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070026#include <asm/atomic.h>
27
28#include "../proc_comm.h"
29#include <mach/debug_mm.h>
30#include <mach/msm_subsystem_map.h>
31#include <mach/qdsp6v2/dsp_debug.h>
32
33static wait_queue_head_t dsp_wait;
34static int dsp_has_crashed;
35static int dsp_wait_count;
36
37static atomic_t dsp_crash_count = ATOMIC_INIT(0);
38dsp_state_cb cb_ptr;
39
40void q6audio_dsp_not_responding(void)
41{
42 if (cb_ptr)
43 cb_ptr(DSP_STATE_CRASHED);
44 if (atomic_add_return(1, &dsp_crash_count) != 1) {
45 pr_err("q6audio_dsp_not_responding() \
46 - parking additional crasher...\n");
47 for (;;)
48 msleep(1000);
49 }
50 if (dsp_wait_count) {
51 dsp_has_crashed = 1;
52 wake_up(&dsp_wait);
53
54 while (dsp_has_crashed != 2)
55 wait_event(dsp_wait, dsp_has_crashed == 2);
56 } else {
57 pr_err("q6audio_dsp_not_responding() - no waiter?\n");
58 }
59 if (cb_ptr)
60 cb_ptr(DSP_STATE_CRASH_DUMP_DONE);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070061}
62
63static int dsp_open(struct inode *inode, struct file *file)
64{
65 return 0;
66}
67
68#define DSP_NMI_ADDR 0x28800010
69
70static ssize_t dsp_write(struct file *file, const char __user *buf,
71 size_t count, loff_t *pos)
72{
73 char cmd[32];
74 void __iomem *ptr;
75 unsigned int flags = MSM_SUBSYSTEM_MAP_KADDR | MSM_SUBSYSTEM_MAP_CACHED;
76 struct msm_mapped_buffer *mem_buffer;
77
78 if (count >= sizeof(cmd))
79 return -EINVAL;
80 if (copy_from_user(cmd, buf, count))
81 return -EFAULT;
82 cmd[count] = 0;
83
84 if ((count > 1) && (cmd[count-1] == '\n'))
85 cmd[count-1] = 0;
86
87 if (!strcmp(cmd, "wait-for-crash")) {
88 while (!dsp_has_crashed) {
89 int res;
90 dsp_wait_count++;
91 res = wait_event_interruptible(dsp_wait,
92 dsp_has_crashed);
93 if (res < 0) {
94 dsp_wait_count--;
95 return res;
96 }
97 }
98 /* assert DSP NMI */
99 mem_buffer = msm_subsystem_map_buffer(DSP_NMI_ADDR, 0x16, flags,
100 NULL, 0);
101 if (IS_ERR((void *)mem_buffer)) {
102 pr_err("%s:map_buffer failed, error = %ld\n", __func__,
103 PTR_ERR((void *)mem_buffer));
104 return -ENOMEM;
105 }
106 ptr = mem_buffer->vaddr;
107 if (!ptr) {
108 pr_err("Unable to map DSP NMI\n");
109 return -EFAULT;
110 }
111 writel(0x1, (void *)ptr);
112 if (msm_subsystem_unmap_buffer(mem_buffer) < 0)
113 pr_err("%s:unmap buffer failed\n", __func__);
114 } else if (!strcmp(cmd, "boom")) {
115 q6audio_dsp_not_responding();
116 } else if (!strcmp(cmd, "continue-crash")) {
117 dsp_has_crashed = 2;
118 wake_up(&dsp_wait);
119 } else {
120 pr_err("[%s:%s] unknown dsp_debug command: %s\n", __MM_FILE__,
121 __func__, cmd);
122 }
123
124 return count;
125}
126
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700127static unsigned copy_ok_count;
Swaminathan Sathappanb77c65e92011-09-30 18:36:09 -0700128static uint32_t dsp_ram_size;
129static uint32_t dsp_ram_base;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700130
131static ssize_t dsp_read(struct file *file, char __user *buf,
132 size_t count, loff_t *pos)
133{
134 size_t actual = 0;
135 size_t mapsize = PAGE_SIZE;
136 unsigned addr;
137 void __iomem *ptr;
138 unsigned int flags = MSM_SUBSYSTEM_MAP_KADDR | MSM_SUBSYSTEM_MAP_CACHED;
139 struct msm_mapped_buffer *mem_buffer;
140
Swaminathan Sathappanb77c65e92011-09-30 18:36:09 -0700141 if ((dsp_ram_base == 0) || (dsp_ram_size == 0)) {
142 pr_err("[%s:%s] Memory Invalid or not initialized, Base = 0x%x,"
143 " size = 0x%x\n", __MM_FILE__,
144 __func__, dsp_ram_base, dsp_ram_size);
145 return -EINVAL;
146 }
147
148 if (*pos >= dsp_ram_size)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700149 return 0;
150
151 if (*pos & (PAGE_SIZE - 1))
152 return -EINVAL;
153
Swaminathan Sathappanb77c65e92011-09-30 18:36:09 -0700154 addr = (*pos + dsp_ram_base);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700155
156 /* don't blow up if we're unaligned */
157 if (addr & (PAGE_SIZE - 1))
158 mapsize *= 2;
159
160 while (count >= PAGE_SIZE) {
161 mem_buffer = msm_subsystem_map_buffer(addr, mapsize, flags,
162 NULL, 0);
163 if (IS_ERR((void *)mem_buffer)) {
164 pr_err("%s:map_buffer failed, error = %ld\n",
165 __func__, PTR_ERR((void *)mem_buffer));
166 return -ENOMEM;
167 }
168 ptr = mem_buffer->vaddr;
169 if (!ptr) {
170 pr_err("[%s:%s] map error @ %x\n", __MM_FILE__,
171 __func__, addr);
172 return -EFAULT;
173 }
174 if (copy_to_user(buf, ptr, PAGE_SIZE)) {
175 if (msm_subsystem_unmap_buffer(mem_buffer) < 0)
176 pr_err("%s: unmap buffer failed\n", __func__);
177 pr_err("[%s:%s] copy error @ %p\n", __MM_FILE__,
178 __func__, buf);
179 return -EFAULT;
180 }
181 copy_ok_count += PAGE_SIZE;
182 if (msm_subsystem_unmap_buffer(mem_buffer) < 0)
183 pr_err("%s: unmap buffer failed\n", __func__);
184 addr += PAGE_SIZE;
185 buf += PAGE_SIZE;
186 actual += PAGE_SIZE;
187 count -= PAGE_SIZE;
188 }
189
190 *pos += actual;
191 return actual;
192}
193
194static int dsp_release(struct inode *inode, struct file *file)
195{
196 return 0;
197}
198
199int dsp_debug_register(dsp_state_cb ptr)
200{
201 if (ptr == NULL)
202 return -EINVAL;
203 cb_ptr = ptr;
204
205 return 0;
206}
207
Swaminathan Sathappanb77c65e92011-09-30 18:36:09 -0700208static int dspcrashd_probe(struct platform_device *pdev)
209{
210 int rc = 0;
211 struct resource *res;
212 int *pdata;
213
214 pdata = pdev->dev.platform_data;
215 res = platform_get_resource_byname(pdev, IORESOURCE_DMA,
216 "msm_dspcrashd");
217 if (!res) {
218 pr_err("%s: failed to get resources for dspcrashd\n", __func__);
219 return -ENODEV;
220 }
221
222 dsp_ram_base = res->start;
223 dsp_ram_size = res->end - res->start;
224 pr_info("%s: Platform driver values: Base = 0x%x, Size = 0x%x,"
225 "pdata = 0x%x\n", __func__,
226 dsp_ram_base, dsp_ram_size, *pdata);
227 return rc;
228}
229
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700230static const struct file_operations dsp_fops = {
231 .owner = THIS_MODULE,
232 .open = dsp_open,
233 .read = dsp_read,
234 .write = dsp_write,
235 .release = dsp_release,
236};
237
238static struct miscdevice dsp_misc = {
239 .minor = MISC_DYNAMIC_MINOR,
240 .name = "dsp_debug",
241 .fops = &dsp_fops,
242};
243
Swaminathan Sathappanb77c65e92011-09-30 18:36:09 -0700244static struct platform_driver dspcrashd_driver = {
245 .probe = dspcrashd_probe,
246 .driver = { .name = "msm_dspcrashd"}
247};
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700248
249static int __init dsp_init(void)
250{
Swaminathan Sathappanb77c65e92011-09-30 18:36:09 -0700251 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700252 init_waitqueue_head(&dsp_wait);
Swaminathan Sathappanb77c65e92011-09-30 18:36:09 -0700253 rc = platform_driver_register(&dspcrashd_driver);
254 if (IS_ERR_VALUE(rc)) {
255 pr_err("%s: platform_driver_register for dspcrashd failed\n",
256 __func__);
257 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700258 return misc_register(&dsp_misc);
259}
260
Swaminathan Sathappanb77c65e92011-09-30 18:36:09 -0700261static int __exit dsp_exit(void)
262{
263 platform_driver_unregister(&dspcrashd_driver);
264 return 0;
265}
266
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700267device_initcall(dsp_init);