blob: 0832c8ffa318f238cb7d63c6c59cedcffc21adf9 [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);
Rohit Vaswanid0fb4182012-03-19 18:07:59 -0700184
185 return IRQ_HANDLED;
186}
187
188static struct subsys_data gss_8064 = {
189 .name = "gss",
190 .shutdown = gss_shutdown,
191 .powerup = gss_powerup,
192 .ramdump = gss_ramdump,
193 .crash_shutdown = gss_crash_shutdown
194};
195
196static int gss_subsystem_restart_init(void)
197{
198 return ssr_register_subsystem(&gss_8064);
199}
200
201static int gss_open(struct inode *inode, struct file *filep)
202{
203 void *ret;
204 gss_data.pil_handle = ret = pil_get("gss");
205 if (!ret)
206 pr_debug("%s - pil_get returned NULL\n", __func__);
207 return 0;
208}
209
210static int gss_release(struct inode *inode, struct file *filep)
211{
212 pil_put(gss_data.pil_handle);
213 pr_debug("%s pil_put called on GSS\n", __func__);
214 return 0;
215}
216
217const struct file_operations gss_file_ops = {
218 .open = gss_open,
219 .release = gss_release,
220};
221
222static int __init gss_8064_init(void)
223{
224 int ret;
225
226 if (!cpu_is_apq8064())
227 return -ENODEV;
228
229 ret = smsm_state_cb_register(SMSM_MODEM_STATE, SMSM_RESET,
230 smsm_state_cb, 0);
231
232 if (ret < 0)
233 pr_err("%s: Unable to register SMSM callback! (%d)\n",
234 __func__, ret);
235
236 ret = request_irq(GSS_A5_WDOG_EXPIRED, gss_wdog_bite_irq,
237 IRQF_TRIGGER_RISING, "gss_a5_wdog", NULL);
238
239 if (ret < 0) {
240 pr_err("%s: Unable to request gss watchdog IRQ. (%d)\n",
241 __func__, ret);
242 disable_irq_nosync(GSS_A5_WDOG_EXPIRED);
243 goto out;
244 }
245
246 ret = gss_subsystem_restart_init();
247
248 if (ret < 0) {
249 pr_err("%s: Unable to reg with subsystem restart. (%d)\n",
250 __func__, ret);
251 goto out;
252 }
253
254 gss_data.gss_dev.minor = MISC_DYNAMIC_MINOR;
255 gss_data.gss_dev.name = "gss";
256 gss_data.gss_dev.fops = &gss_file_ops;
257 ret = misc_register(&gss_data.gss_dev);
258
259 if (ret) {
260 pr_err("%s: misc_registers failed for %s (%d)", __func__,
261 gss_data.gss_dev.name, ret);
262 goto out;
263 }
264
265 gss_data.gss_ramdump_dev = create_ramdump_device("gss");
266
267 if (!gss_data.gss_ramdump_dev) {
268 pr_err("%s: Unable to create gss ramdump device. (%d)\n",
269 __func__, -ENOMEM);
270 ret = -ENOMEM;
271 goto out;
272 }
273
274 gss_data.smem_ramdump_dev = create_ramdump_device("smem");
275
276 if (!gss_data.smem_ramdump_dev) {
277 pr_err("%s: Unable to create smem ramdump device. (%d)\n",
278 __func__, -ENOMEM);
279 ret = -ENOMEM;
280 goto out;
281 }
282
283 pr_info("%s: gss fatal driver init'ed.\n", __func__);
284out:
285 return ret;
286}
287
288module_init(gss_8064_init);