blob: 40fa37e5bba5c785ce73d8eb4fc19fc3f3baa64f [file] [log] [blame]
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001/* Copyright (c) 2010-2011, 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
14#include <linux/module.h>
15#include <linux/kernel.h>
16#include <linux/init.h>
17#include <linux/io.h>
18#include <linux/delay.h>
19#include <linux/workqueue.h>
20#include <linux/pm.h>
21#include <linux/mfd/pmic8058.h>
22#include <linux/jiffies.h>
23#include <linux/suspend.h>
24#include <linux/interrupt.h>
25#include <mach/msm_iomap.h>
26#include <asm/mach-types.h>
27#include <mach/scm-io.h>
28#include <mach/scm.h>
29#include "msm_watchdog.h"
30
31#define TCSR_WDT_CFG 0x30
32
33#define WDT0_RST (MSM_TMR0_BASE + 0x38)
34#define WDT0_EN (MSM_TMR0_BASE + 0x40)
35#define WDT0_BARK_TIME (MSM_TMR0_BASE + 0x4C)
36#define WDT0_BITE_TIME (MSM_TMR0_BASE + 0x5C)
37
38/* Watchdog pet interval in ms */
39#define PET_DELAY 3000
40static unsigned long delay_time;
41static unsigned long long last_pet;
42
43/*
44 * On the kernel command line specify
45 * msm_watchdog.enable=1 to enable the watchdog
46 * By default watchdog is turned on
47 */
48static int enable = 1;
49module_param(enable, int, 0);
50
51/*
52 * If the watchdog is enabled at bootup (enable=1),
53 * the runtime_disable sysfs node at
54 * /sys/module/msm_watchdog/runtime_disable
55 * can be used to deactivate the watchdog.
56 * This is a one-time setting. The watchdog
57 * cannot be re-enabled once it is disabled.
58 */
59static int runtime_disable;
60static DEFINE_MUTEX(disable_lock);
61static int wdog_enable_set(const char *val, struct kernel_param *kp);
62module_param_call(runtime_disable, wdog_enable_set, param_get_int,
63 &runtime_disable, 0644);
64
65/*
66 * On the kernel command line specify msm_watchdog.appsbark=1 to handle
67 * watchdog barks in Linux. By default barks are processed by the secure side.
68 */
69static int appsbark;
70module_param(appsbark, int, 0);
71
72/*
73 * Use /sys/module/msm_watchdog/parameters/print_all_stacks
74 * to control whether stacks of all running
75 * processes are printed when a wdog bark is received.
76 */
77static int print_all_stacks = 1;
78module_param(print_all_stacks, int, S_IRUGO | S_IWUSR);
79
80/* Area for context dump in secure mode */
81static void *scm_regsave;
82
83static void pet_watchdog_work(struct work_struct *work);
84static void init_watchdog_work(struct work_struct *work);
85static DECLARE_DELAYED_WORK(dogwork_struct, pet_watchdog_work);
86static DECLARE_WORK(init_dogwork_struct, init_watchdog_work);
87
88static int msm_watchdog_suspend(void)
89{
90 __raw_writel(1, WDT0_RST);
91 __raw_writel(0, WDT0_EN);
92 mb();
93 return NOTIFY_DONE;
94}
95static int msm_watchdog_resume(void)
96{
97 __raw_writel(1, WDT0_EN);
98 __raw_writel(1, WDT0_RST);
99 return NOTIFY_DONE;
100}
101
102static int msm_watchdog_power_event(struct notifier_block *this,
103 unsigned long event, void *ptr)
104{
105 switch (event) {
106 case PM_POST_HIBERNATION:
107 case PM_POST_SUSPEND:
108 return msm_watchdog_resume();
109 case PM_HIBERNATION_PREPARE:
110 case PM_SUSPEND_PREPARE:
111 return msm_watchdog_suspend();
112 default:
113 return NOTIFY_DONE;
114 }
115}
116
117static int panic_wdog_handler(struct notifier_block *this,
118 unsigned long event, void *ptr)
119{
120 if (panic_timeout == 0) {
121 __raw_writel(0, WDT0_EN);
122 mb();
123 secure_writel(0, MSM_TCSR_BASE + TCSR_WDT_CFG);
124 } else {
125 __raw_writel(32768 * (panic_timeout + 4), WDT0_BARK_TIME);
126 __raw_writel(32768 * (panic_timeout + 4), WDT0_BITE_TIME);
127 __raw_writel(1, WDT0_RST);
128 }
129 return NOTIFY_DONE;
130}
131
132static struct notifier_block panic_blk = {
133 .notifier_call = panic_wdog_handler,
134};
135
136static struct notifier_block msm_watchdog_power_notifier = {
137 .notifier_call = msm_watchdog_power_event,
138};
139
140static int wdog_enable_set(const char *val, struct kernel_param *kp)
141{
142 int ret = 0;
143 int old_val = runtime_disable;
144
145 mutex_lock(&disable_lock);
146
147 if (!enable) {
148 printk(KERN_INFO "MSM Watchdog is not active.\n");
149 ret = -EINVAL;
150 goto done;
151 }
152
153 ret = param_set_int(val, kp);
154
155 if (ret)
156 goto done;
157
158 switch (runtime_disable) {
159
160 case 1:
161 if (!old_val) {
162 __raw_writel(0, WDT0_EN);
163 unregister_pm_notifier(&msm_watchdog_power_notifier);
164
165 /* may be suspended after the first write above */
166 __raw_writel(0, WDT0_EN);
167 mb();
168 secure_writel(0, MSM_TCSR_BASE + TCSR_WDT_CFG);
169 free_irq(WDT0_ACCSCSSNBARK_INT, 0);
170 enable = 0;
171 atomic_notifier_chain_unregister(&panic_notifier_list,
172 &panic_blk);
173 cancel_delayed_work(&dogwork_struct);
174 printk(KERN_INFO "MSM Watchdog deactivated.\n");
175 }
176 break;
177
178 default:
179 runtime_disable = old_val;
180 ret = -EINVAL;
181 break;
182
183 }
184
185done:
186 mutex_unlock(&disable_lock);
187 return ret;
188}
189
190void pet_watchdog(void)
191{
192 __raw_writel(1, WDT0_RST);
193 last_pet = sched_clock();
194}
195
196static void pet_watchdog_work(struct work_struct *work)
197{
198 pet_watchdog();
199
200 if (enable)
201 schedule_delayed_work_on(0, &dogwork_struct, delay_time);
202}
203
204static void __exit exit_watchdog(void)
205{
206 if (enable) {
207 __raw_writel(0, WDT0_EN);
208 unregister_pm_notifier(&msm_watchdog_power_notifier);
209 __raw_writel(0, WDT0_EN); /* In case we got suspended
210 * mid-exit */
211 mb();
212 secure_writel(0, MSM_TCSR_BASE + TCSR_WDT_CFG);
213 free_irq(WDT0_ACCSCSSNBARK_INT, 0);
214 enable = 0;
215 }
216 printk(KERN_INFO "MSM Watchdog Exit - Deactivated\n");
217}
218
219static irqreturn_t wdog_bark_handler(int irq, void *dev_id)
220{
221 unsigned long nanosec_rem;
222 unsigned long long t = sched_clock();
223 struct task_struct *tsk;
224
225 nanosec_rem = do_div(t, 1000000000);
226 printk(KERN_INFO "Watchdog bark! Now = %lu.%06lu\n", (unsigned long) t,
227 nanosec_rem / 1000);
228
229 nanosec_rem = do_div(last_pet, 1000000000);
230 printk(KERN_INFO "Watchdog last pet at %lu.%06lu\n", (unsigned long)
231 last_pet, nanosec_rem / 1000);
232
233 if (print_all_stacks) {
234
235 /* Suspend wdog until all stacks are printed */
236 msm_watchdog_suspend();
237
238 printk(KERN_INFO "Stack trace dump:\n");
239
240 for_each_process(tsk) {
241 printk(KERN_INFO "\nPID: %d, Name: %s\n",
242 tsk->pid, tsk->comm);
243 show_stack(tsk, NULL);
244 }
245
246 msm_watchdog_resume();
247 }
248
249 panic("Apps watchdog bark received!");
250 return IRQ_HANDLED;
251}
252
253#define SCM_SET_REGSAVE_CMD 0x2
254
255static void init_watchdog_work(struct work_struct *work)
256{
257 int ret;
258 struct {
259 unsigned addr;
260 int len;
261 } cmd_buf;
262
263 if (!enable) {
264 printk(KERN_INFO "MSM Watchdog Not Initialized\n");
265 return;
266 }
267
268 /* Must request irq before sending scm command */
269 ret = request_irq(WDT0_ACCSCSSNBARK_INT, wdog_bark_handler, 0,
270 "apps_wdog_bark", NULL);
271 if (ret)
272 return;
273
274#ifdef CONFIG_MSM_SCM
275 if (!appsbark) {
276 scm_regsave = (void *)__get_free_page(GFP_KERNEL);
277
278 if (scm_regsave) {
279 cmd_buf.addr = __pa(scm_regsave);
280 cmd_buf.len = PAGE_SIZE;
281
282 ret = scm_call(SCM_SVC_UTIL, SCM_SET_REGSAVE_CMD,
283 &cmd_buf, sizeof(cmd_buf), NULL, 0);
284 if (ret)
285 pr_err("Setting register save address failed.\n"
286 "Registers won't be dumped on a dog "
287 "bite\n");
288 } else
289 pr_err("Allocating register save space failed\n"
290 "Registers won't be dumped on a dog bite\n");
291 /*
292 * No need to bail if allocation fails. Simply don't
293 * send the command, and the secure side will reset
294 * without saving registers.
295 */
296 }
297#endif
298 secure_writel(1, MSM_TCSR_BASE + TCSR_WDT_CFG);
299 delay_time = msecs_to_jiffies(PET_DELAY);
300
301 /* 32768 ticks = 1 second */
302 if (machine_is_msm8960_sim()) {
303 __raw_writel(32768*8, WDT0_BARK_TIME);
304 __raw_writel(32768*10, WDT0_BITE_TIME);
305 } else {
306 __raw_writel(32768*4, WDT0_BARK_TIME);
307 __raw_writel(32768*5, WDT0_BITE_TIME);
308 }
309
310 ret = register_pm_notifier(&msm_watchdog_power_notifier);
311 if (ret) {
312 free_irq(WDT0_ACCSCSSNBARK_INT, NULL);
313 return;
314 }
315
316 schedule_delayed_work_on(0, &dogwork_struct, delay_time);
317
318 atomic_notifier_chain_register(&panic_notifier_list,
319 &panic_blk);
320
321 __raw_writel(1, WDT0_EN);
322 __raw_writel(1, WDT0_RST);
323 last_pet = sched_clock();
324
325 printk(KERN_INFO "MSM Watchdog Initialized\n");
326
327 return;
328}
329
330static int __init init_watchdog(void)
331{
332 schedule_work_on(0, &init_dogwork_struct);
333 return 0;
334}
335
336late_initcall(init_watchdog);
337module_exit(exit_watchdog);
338MODULE_DESCRIPTION("MSM Watchdog Driver");
339MODULE_VERSION("1.0");
340MODULE_LICENSE("GPL v2");