blob: 126f8e0aefc1d1778822cccd58e7ed624c10ea16 [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>
Rohit Vaswani974fd9e2012-05-29 17:17:11 -070026#include <mach/msm_smsm.h>
Rohit Vaswanid0fb4182012-03-19 18:07:59 -070027#include <mach/scm.h>
28#include <mach/peripheral-loader.h>
29#include <mach/subsystem_restart.h>
30#include <mach/subsystem_notif.h>
31#include <mach/socinfo.h>
32
33#include "smd_private.h"
34#include "modem_notifier.h"
35#include "ramdump.h"
36
37static struct gss_8064_data {
38 struct miscdevice gss_dev;
39 void *pil_handle;
40 void *gss_ramdump_dev;
41 void *smem_ramdump_dev;
42} gss_data;
43
44static int crash_shutdown;
45
Rohit Vaswani974fd9e2012-05-29 17:17:11 -070046#define MAX_SSR_REASON_LEN 81U
47
48static void log_gss_sfr(void)
49{
50 u32 size;
51 char *smem_reason, reason[MAX_SSR_REASON_LEN];
52
53 smem_reason = smem_get_entry(SMEM_SSR_REASON_MSS0, &size);
54 if (!smem_reason || !size) {
55 pr_err("GSS subsystem failure reason: (unknown, smem_get_entry failed).\n");
56 return;
57 }
58 if (!smem_reason[0]) {
59 pr_err("GSS subsystem failure reason: (unknown, init string found).\n");
60 return;
61 }
62
63 size = min(size, MAX_SSR_REASON_LEN-1);
64 memcpy(reason, smem_reason, size);
65 reason[size] = '\0';
66 pr_err("GSS subsystem failure reason: %s.\n", reason);
67
68 smem_reason[0] = '\0';
69 wmb();
70}
71
Rohit Vaswanid0fb4182012-03-19 18:07:59 -070072static void gss_fatal_fn(struct work_struct *work)
73{
74 uint32_t panic_smsm_states = SMSM_RESET | SMSM_SYSTEM_DOWNLOAD;
75 uint32_t reset_smsm_states = SMSM_SYSTEM_REBOOT_USR |
76 SMSM_SYSTEM_PWRDWN_USR;
77 uint32_t gss_state;
78
79 pr_err("Watchdog bite received from GSS!\n");
80
81 gss_state = smsm_get_state(SMSM_MODEM_STATE);
82
83 if (gss_state & panic_smsm_states) {
84
85 pr_err("GSS SMSM state changed to SMSM_RESET.\n"
86 "Probable err_fatal on the GSS. "
87 "Calling subsystem restart...\n");
Rohit Vaswani974fd9e2012-05-29 17:17:11 -070088 log_gss_sfr();
Rohit Vaswanid0fb4182012-03-19 18:07:59 -070089 subsystem_restart("gss");
90
91 } else if (gss_state & reset_smsm_states) {
92
93 pr_err("%s: User-invoked system reset/powerdown. "
94 "Resetting the SoC now.\n",
95 __func__);
96 kernel_restart(NULL);
97 } else {
98 /* TODO: Bus unlock code/sequence goes _here_ */
Rohit Vaswani974fd9e2012-05-29 17:17:11 -070099 log_gss_sfr();
Rohit Vaswanid0fb4182012-03-19 18:07:59 -0700100 subsystem_restart("gss");
101 }
102}
103
104static DECLARE_WORK(gss_fatal_work, gss_fatal_fn);
105
106static void smsm_state_cb(void *data, uint32_t old_state, uint32_t new_state)
107{
108 /* Ignore if we're the one that set SMSM_RESET */
109 if (crash_shutdown)
110 return;
111
112 if (new_state & SMSM_RESET) {
113 pr_err("GSS SMSM state changed to SMSM_RESET.\n"
114 "Probable err_fatal on the GSS. "
115 "Calling subsystem restart...\n");
Rohit Vaswani974fd9e2012-05-29 17:17:11 -0700116 log_gss_sfr();
Rohit Vaswanid0fb4182012-03-19 18:07:59 -0700117 subsystem_restart("gss");
118 }
119}
120
121#define Q6_FW_WDOG_ENABLE 0x08882024
122#define Q6_SW_WDOG_ENABLE 0x08982024
123static int gss_shutdown(const struct subsys_data *subsys)
124{
125 pil_force_shutdown("gss");
126 disable_irq_nosync(GSS_A5_WDOG_EXPIRED);
127
128 return 0;
129}
130
131static int gss_powerup(const struct subsys_data *subsys)
132{
133 pil_force_boot("gss");
134 enable_irq(GSS_A5_WDOG_EXPIRED);
135 return 0;
136}
137
138void gss_crash_shutdown(const struct subsys_data *subsys)
139{
140 crash_shutdown = 1;
141 smsm_reset_modem(SMSM_RESET);
142}
143
144/* FIXME: Get address, size from PIL */
145static struct ramdump_segment gss_segments[] = {
Rohit Vaswani3e7503f2012-03-29 17:46:13 -0700146 {0x89000000, 0x00D00000}
Rohit Vaswanid0fb4182012-03-19 18:07:59 -0700147};
148
149static struct ramdump_segment smem_segments[] = {
150 {0x80000000, 0x00200000},
151};
152
153static int gss_ramdump(int enable,
154 const struct subsys_data *crashed_subsys)
155{
156 int ret = 0;
157
158 if (enable) {
159 ret = do_ramdump(gss_data.gss_ramdump_dev, gss_segments,
160 ARRAY_SIZE(gss_segments));
161
162 if (ret < 0) {
163 pr_err("Unable to dump gss memory (rc = %d).\n",
164 ret);
165 goto out;
166 }
167
168 ret = do_ramdump(gss_data.smem_ramdump_dev, smem_segments,
169 ARRAY_SIZE(smem_segments));
170
171 if (ret < 0) {
172 pr_err("Unable to dump smem memory (rc = %d).\n", ret);
173 goto out;
174 }
175 }
176
177out:
178 return ret;
179}
180
181static irqreturn_t gss_wdog_bite_irq(int irq, void *dev_id)
182{
183 schedule_work(&gss_fatal_work);
184 disable_irq_nosync(GSS_A5_WDOG_EXPIRED);
185
186 return IRQ_HANDLED;
187}
188
189static struct subsys_data gss_8064 = {
190 .name = "gss",
191 .shutdown = gss_shutdown,
192 .powerup = gss_powerup,
193 .ramdump = gss_ramdump,
194 .crash_shutdown = gss_crash_shutdown
195};
196
197static int gss_subsystem_restart_init(void)
198{
199 return ssr_register_subsystem(&gss_8064);
200}
201
202static int gss_open(struct inode *inode, struct file *filep)
203{
204 void *ret;
205 gss_data.pil_handle = ret = pil_get("gss");
206 if (!ret)
207 pr_debug("%s - pil_get returned NULL\n", __func__);
208 return 0;
209}
210
211static int gss_release(struct inode *inode, struct file *filep)
212{
213 pil_put(gss_data.pil_handle);
214 pr_debug("%s pil_put called on GSS\n", __func__);
215 return 0;
216}
217
218const struct file_operations gss_file_ops = {
219 .open = gss_open,
220 .release = gss_release,
221};
222
223static int __init gss_8064_init(void)
224{
225 int ret;
226
227 if (!cpu_is_apq8064())
228 return -ENODEV;
229
230 ret = smsm_state_cb_register(SMSM_MODEM_STATE, SMSM_RESET,
231 smsm_state_cb, 0);
232
233 if (ret < 0)
234 pr_err("%s: Unable to register SMSM callback! (%d)\n",
235 __func__, ret);
236
237 ret = request_irq(GSS_A5_WDOG_EXPIRED, gss_wdog_bite_irq,
238 IRQF_TRIGGER_RISING, "gss_a5_wdog", NULL);
239
240 if (ret < 0) {
241 pr_err("%s: Unable to request gss watchdog IRQ. (%d)\n",
242 __func__, ret);
243 disable_irq_nosync(GSS_A5_WDOG_EXPIRED);
244 goto out;
245 }
246
247 ret = gss_subsystem_restart_init();
248
249 if (ret < 0) {
250 pr_err("%s: Unable to reg with subsystem restart. (%d)\n",
251 __func__, ret);
252 goto out;
253 }
254
255 gss_data.gss_dev.minor = MISC_DYNAMIC_MINOR;
256 gss_data.gss_dev.name = "gss";
257 gss_data.gss_dev.fops = &gss_file_ops;
258 ret = misc_register(&gss_data.gss_dev);
259
260 if (ret) {
261 pr_err("%s: misc_registers failed for %s (%d)", __func__,
262 gss_data.gss_dev.name, ret);
263 goto out;
264 }
265
266 gss_data.gss_ramdump_dev = create_ramdump_device("gss");
267
268 if (!gss_data.gss_ramdump_dev) {
269 pr_err("%s: Unable to create gss ramdump device. (%d)\n",
270 __func__, -ENOMEM);
271 ret = -ENOMEM;
272 goto out;
273 }
274
275 gss_data.smem_ramdump_dev = create_ramdump_device("smem");
276
277 if (!gss_data.smem_ramdump_dev) {
278 pr_err("%s: Unable to create smem ramdump device. (%d)\n",
279 __func__, -ENOMEM);
280 ret = -ENOMEM;
281 goto out;
282 }
283
284 pr_info("%s: gss fatal driver init'ed.\n", __func__);
285out:
286 return ret;
287}
288
289module_init(gss_8064_init);