blob: 1ddb7a3e0cc7a6edd7e48297fa22a18e004c1a12 [file] [log] [blame]
Rohit Vaswanid0fb4182012-03-19 18:07:59 -07001/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
12
13#include <linux/kernel.h>
14#include <linux/interrupt.h>
15#include <linux/reboot.h>
16#include <linux/workqueue.h>
17#include <linux/io.h>
18#include <linux/jiffies.h>
19#include <linux/stringify.h>
20#include <linux/delay.h>
21#include <linux/module.h>
22#include <linux/miscdevice.h>
23#include <linux/fs.h>
24
25#include <mach/irqs.h>
26#include <mach/scm.h>
27#include <mach/peripheral-loader.h>
28#include <mach/subsystem_restart.h>
29#include <mach/subsystem_notif.h>
30#include <mach/socinfo.h>
31
32#include "smd_private.h"
33#include "modem_notifier.h"
34#include "ramdump.h"
35
36static struct gss_8064_data {
37 struct miscdevice gss_dev;
38 void *pil_handle;
39 void *gss_ramdump_dev;
40 void *smem_ramdump_dev;
41} gss_data;
42
43static int crash_shutdown;
44
45static void gss_fatal_fn(struct work_struct *work)
46{
47 uint32_t panic_smsm_states = SMSM_RESET | SMSM_SYSTEM_DOWNLOAD;
48 uint32_t reset_smsm_states = SMSM_SYSTEM_REBOOT_USR |
49 SMSM_SYSTEM_PWRDWN_USR;
50 uint32_t gss_state;
51
52 pr_err("Watchdog bite received from GSS!\n");
53
54 gss_state = smsm_get_state(SMSM_MODEM_STATE);
55
56 if (gss_state & panic_smsm_states) {
57
58 pr_err("GSS SMSM state changed to SMSM_RESET.\n"
59 "Probable err_fatal on the GSS. "
60 "Calling subsystem restart...\n");
61 subsystem_restart("gss");
62
63 } else if (gss_state & reset_smsm_states) {
64
65 pr_err("%s: User-invoked system reset/powerdown. "
66 "Resetting the SoC now.\n",
67 __func__);
68 kernel_restart(NULL);
69 } else {
70 /* TODO: Bus unlock code/sequence goes _here_ */
71 subsystem_restart("gss");
72 }
73}
74
75static DECLARE_WORK(gss_fatal_work, gss_fatal_fn);
76
77static void smsm_state_cb(void *data, uint32_t old_state, uint32_t new_state)
78{
79 /* Ignore if we're the one that set SMSM_RESET */
80 if (crash_shutdown)
81 return;
82
83 if (new_state & SMSM_RESET) {
84 pr_err("GSS SMSM state changed to SMSM_RESET.\n"
85 "Probable err_fatal on the GSS. "
86 "Calling subsystem restart...\n");
87 subsystem_restart("gss");
88 }
89}
90
91#define Q6_FW_WDOG_ENABLE 0x08882024
92#define Q6_SW_WDOG_ENABLE 0x08982024
93static int gss_shutdown(const struct subsys_data *subsys)
94{
95 pil_force_shutdown("gss");
96 disable_irq_nosync(GSS_A5_WDOG_EXPIRED);
97
98 return 0;
99}
100
101static int gss_powerup(const struct subsys_data *subsys)
102{
103 pil_force_boot("gss");
104 enable_irq(GSS_A5_WDOG_EXPIRED);
105 return 0;
106}
107
108void gss_crash_shutdown(const struct subsys_data *subsys)
109{
110 crash_shutdown = 1;
111 smsm_reset_modem(SMSM_RESET);
112}
113
114/* FIXME: Get address, size from PIL */
115static struct ramdump_segment gss_segments[] = {
116 {0x89D00000 - 0x89000000}
117};
118
119static struct ramdump_segment smem_segments[] = {
120 {0x80000000, 0x00200000},
121};
122
123static int gss_ramdump(int enable,
124 const struct subsys_data *crashed_subsys)
125{
126 int ret = 0;
127
128 if (enable) {
129 ret = do_ramdump(gss_data.gss_ramdump_dev, gss_segments,
130 ARRAY_SIZE(gss_segments));
131
132 if (ret < 0) {
133 pr_err("Unable to dump gss memory (rc = %d).\n",
134 ret);
135 goto out;
136 }
137
138 ret = do_ramdump(gss_data.smem_ramdump_dev, smem_segments,
139 ARRAY_SIZE(smem_segments));
140
141 if (ret < 0) {
142 pr_err("Unable to dump smem memory (rc = %d).\n", ret);
143 goto out;
144 }
145 }
146
147out:
148 return ret;
149}
150
151static irqreturn_t gss_wdog_bite_irq(int irq, void *dev_id)
152{
153 schedule_work(&gss_fatal_work);
154 disable_irq_nosync(GSS_A5_WDOG_EXPIRED);
155
156 return IRQ_HANDLED;
157}
158
159static struct subsys_data gss_8064 = {
160 .name = "gss",
161 .shutdown = gss_shutdown,
162 .powerup = gss_powerup,
163 .ramdump = gss_ramdump,
164 .crash_shutdown = gss_crash_shutdown
165};
166
167static int gss_subsystem_restart_init(void)
168{
169 return ssr_register_subsystem(&gss_8064);
170}
171
172static int gss_open(struct inode *inode, struct file *filep)
173{
174 void *ret;
175 gss_data.pil_handle = ret = pil_get("gss");
176 if (!ret)
177 pr_debug("%s - pil_get returned NULL\n", __func__);
178 return 0;
179}
180
181static int gss_release(struct inode *inode, struct file *filep)
182{
183 pil_put(gss_data.pil_handle);
184 pr_debug("%s pil_put called on GSS\n", __func__);
185 return 0;
186}
187
188const struct file_operations gss_file_ops = {
189 .open = gss_open,
190 .release = gss_release,
191};
192
193static int __init gss_8064_init(void)
194{
195 int ret;
196
197 if (!cpu_is_apq8064())
198 return -ENODEV;
199
200 ret = smsm_state_cb_register(SMSM_MODEM_STATE, SMSM_RESET,
201 smsm_state_cb, 0);
202
203 if (ret < 0)
204 pr_err("%s: Unable to register SMSM callback! (%d)\n",
205 __func__, ret);
206
207 ret = request_irq(GSS_A5_WDOG_EXPIRED, gss_wdog_bite_irq,
208 IRQF_TRIGGER_RISING, "gss_a5_wdog", NULL);
209
210 if (ret < 0) {
211 pr_err("%s: Unable to request gss watchdog IRQ. (%d)\n",
212 __func__, ret);
213 disable_irq_nosync(GSS_A5_WDOG_EXPIRED);
214 goto out;
215 }
216
217 ret = gss_subsystem_restart_init();
218
219 if (ret < 0) {
220 pr_err("%s: Unable to reg with subsystem restart. (%d)\n",
221 __func__, ret);
222 goto out;
223 }
224
225 gss_data.gss_dev.minor = MISC_DYNAMIC_MINOR;
226 gss_data.gss_dev.name = "gss";
227 gss_data.gss_dev.fops = &gss_file_ops;
228 ret = misc_register(&gss_data.gss_dev);
229
230 if (ret) {
231 pr_err("%s: misc_registers failed for %s (%d)", __func__,
232 gss_data.gss_dev.name, ret);
233 goto out;
234 }
235
236 gss_data.gss_ramdump_dev = create_ramdump_device("gss");
237
238 if (!gss_data.gss_ramdump_dev) {
239 pr_err("%s: Unable to create gss ramdump device. (%d)\n",
240 __func__, -ENOMEM);
241 ret = -ENOMEM;
242 goto out;
243 }
244
245 gss_data.smem_ramdump_dev = create_ramdump_device("smem");
246
247 if (!gss_data.smem_ramdump_dev) {
248 pr_err("%s: Unable to create smem ramdump device. (%d)\n",
249 __func__, -ENOMEM);
250 ret = -ENOMEM;
251 goto out;
252 }
253
254 pr_info("%s: gss fatal driver init'ed.\n", __func__);
255out:
256 return ret;
257}
258
259module_init(gss_8064_init);