blob: 6d58d6b9ed575e3e8920c239eedb2441fc062be2 [file] [log] [blame]
Vikram Mulukutlac850fd82016-10-14 16:13:24 -07001/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
Satyajit Desai5255cea2016-08-04 16:02:50 -07002 *
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/module.h>
14#include <linux/kernel.h>
15#include <linux/io.h>
16#include <linux/delay.h>
17#include <linux/slab.h>
18#include <linux/jiffies.h>
19#include <linux/kthread.h>
20#include <linux/mutex.h>
21#include <linux/sched.h>
22#include <linux/interrupt.h>
23#include <linux/irq.h>
24#include <linux/percpu.h>
25#include <linux/of.h>
26#include <linux/cpu.h>
27#include <linux/cpu_pm.h>
28#include <linux/platform_device.h>
29#include <linux/wait.h>
30#include <soc/qcom/scm.h>
31#include <soc/qcom/memory_dump.h>
Lingutla Chandrasekharbe48b072017-09-25 19:07:12 +053032#include <soc/qcom/minidump.h>
Satyajit Desai5255cea2016-08-04 16:02:50 -070033#include <soc/qcom/watchdog.h>
Satyajit Desaia4852262017-04-26 10:01:20 -070034#include <linux/dma-mapping.h>
Satyajit Desai5255cea2016-08-04 16:02:50 -070035
36#define MODULE_NAME "msm_watchdog"
37#define WDT0_ACCSCSSNBARK_INT 0
38#define TCSR_WDT_CFG 0x30
39#define WDT0_RST 0x04
40#define WDT0_EN 0x08
41#define WDT0_STS 0x0C
42#define WDT0_BARK_TIME 0x10
43#define WDT0_BITE_TIME 0x14
44
45#define WDOG_ABSENT 0
46
47#define EN 0
48#define UNMASKED_INT_EN 1
49
50#define MASK_SIZE 32
51#define SCM_SET_REGSAVE_CMD 0x2
52#define SCM_SVC_SEC_WDOG_DIS 0x7
53#define MAX_CPU_CTX_SIZE 2048
Channagoud Kadabi9236f882017-10-16 14:46:09 -070054#define MAX_CPU_SCANDUMP_SIZE 0x10100
Satyajit Desai5255cea2016-08-04 16:02:50 -070055
56static struct msm_watchdog_data *wdog_data;
57
58static int cpu_idle_pc_state[NR_CPUS];
59
60/*
61 * user_pet_enable:
62 * Require userspace to write to a sysfs file every pet_time milliseconds.
63 * Disabled by default on boot.
64 */
65struct msm_watchdog_data {
66 unsigned int __iomem phys_base;
67 size_t size;
68 void __iomem *base;
69 void __iomem *wdog_absent_base;
70 struct device *dev;
71 unsigned int pet_time;
72 unsigned int bark_time;
73 unsigned int bark_irq;
74 unsigned int bite_irq;
75 bool do_ipi_ping;
76 bool wakeup_irq_enable;
77 unsigned long long last_pet;
78 unsigned int min_slack_ticks;
79 unsigned long long min_slack_ns;
80 void *scm_regsave;
81 cpumask_t alive_mask;
82 struct mutex disable_lock;
83 bool irq_ppi;
84 struct msm_watchdog_data __percpu **wdog_cpu_dd;
85 struct notifier_block panic_blk;
86
87 bool enabled;
88 bool user_pet_enabled;
89
90 struct task_struct *watchdog_task;
91 struct timer_list pet_timer;
92 wait_queue_head_t pet_complete;
93
94 bool timer_expired;
95 bool user_pet_complete;
96};
97
98/*
99 * On the kernel command line specify
100 * watchdog_v2.enable=1 to enable the watchdog
101 * By default watchdog is turned on
102 */
103static int enable = 1;
104module_param(enable, int, 0);
105
106/*
107 * On the kernel command line specify
108 * watchdog_v2.WDT_HZ=<clock val in HZ> to set Watchdog
109 * ticks. By default it is set to 32765.
110 */
111static long WDT_HZ = 32765;
112module_param(WDT_HZ, long, 0);
113
114/*
115 * On the kernel command line specify
116 * watchdog_v2.ipi_opt_en=1 to enable the watchdog ipi ping
117 * optimization. By default it is turned off
118 */
119static int ipi_opt_en;
120module_param(ipi_opt_en, int, 0);
121
122static void dump_cpu_alive_mask(struct msm_watchdog_data *wdog_dd)
123{
124 static char alive_mask_buf[MASK_SIZE];
125
126 scnprintf(alive_mask_buf, MASK_SIZE, "%*pb1", cpumask_pr_args(
127 &wdog_dd->alive_mask));
128 dev_info(wdog_dd->dev, "cpu alive mask from last pet %s\n",
129 alive_mask_buf);
130}
131
132static int msm_watchdog_suspend(struct device *dev)
133{
134 struct msm_watchdog_data *wdog_dd =
135 (struct msm_watchdog_data *)dev_get_drvdata(dev);
136 if (!enable)
137 return 0;
138 __raw_writel(1, wdog_dd->base + WDT0_RST);
139 if (wdog_dd->wakeup_irq_enable) {
Sarangdhar Joshi1a00b602015-06-25 16:09:34 -0700140 /* Make sure register write is complete before proceeding */
141 mb();
Satyajit Desai5255cea2016-08-04 16:02:50 -0700142 wdog_dd->last_pet = sched_clock();
143 return 0;
144 }
145 __raw_writel(0, wdog_dd->base + WDT0_EN);
146 /* Make sure watchdog is suspended before setting enable */
147 mb();
148 wdog_dd->enabled = false;
149 wdog_dd->last_pet = sched_clock();
150 return 0;
151}
152
153static int msm_watchdog_resume(struct device *dev)
154{
155 struct msm_watchdog_data *wdog_dd =
156 (struct msm_watchdog_data *)dev_get_drvdata(dev);
Sarangdhar Joshi1a00b602015-06-25 16:09:34 -0700157 if (!enable)
Satyajit Desai5255cea2016-08-04 16:02:50 -0700158 return 0;
Sarangdhar Joshi1a00b602015-06-25 16:09:34 -0700159 if (wdog_dd->wakeup_irq_enable) {
160 __raw_writel(1, wdog_dd->base + WDT0_RST);
161 /* Make sure register write is complete before proceeding */
162 mb();
163 wdog_dd->last_pet = sched_clock();
164 return 0;
165 }
Satyajit Desai5255cea2016-08-04 16:02:50 -0700166 __raw_writel(1, wdog_dd->base + WDT0_EN);
167 __raw_writel(1, wdog_dd->base + WDT0_RST);
168 /* Make sure watchdog is reset before setting enable */
169 mb();
170 wdog_dd->enabled = true;
171 wdog_dd->last_pet = sched_clock();
172 return 0;
173}
174
175static int panic_wdog_handler(struct notifier_block *this,
176 unsigned long event, void *ptr)
177{
178 struct msm_watchdog_data *wdog_dd = container_of(this,
179 struct msm_watchdog_data, panic_blk);
180 if (panic_timeout == 0) {
181 __raw_writel(0, wdog_dd->base + WDT0_EN);
182 /* Make sure watchdog is enabled before notifying the caller */
183 mb();
184 } else {
185 __raw_writel(WDT_HZ * (panic_timeout + 10),
186 wdog_dd->base + WDT0_BARK_TIME);
187 __raw_writel(WDT_HZ * (panic_timeout + 10),
188 wdog_dd->base + WDT0_BITE_TIME);
189 __raw_writel(1, wdog_dd->base + WDT0_RST);
190 }
191 return NOTIFY_DONE;
192}
193
194static void wdog_disable(struct msm_watchdog_data *wdog_dd)
195{
196 __raw_writel(0, wdog_dd->base + WDT0_EN);
197 /* Make sure watchdog is disabled before proceeding */
198 mb();
199 if (wdog_dd->irq_ppi) {
200 disable_percpu_irq(wdog_dd->bark_irq);
201 free_percpu_irq(wdog_dd->bark_irq, wdog_dd->wdog_cpu_dd);
202 } else
203 devm_free_irq(wdog_dd->dev, wdog_dd->bark_irq, wdog_dd);
204 enable = 0;
205 /*Ensure all cpus see update to enable*/
206 smp_mb();
207 atomic_notifier_chain_unregister(&panic_notifier_list,
208 &wdog_dd->panic_blk);
209 del_timer_sync(&wdog_dd->pet_timer);
210 /* may be suspended after the first write above */
211 __raw_writel(0, wdog_dd->base + WDT0_EN);
212 /* Make sure watchdog is disabled before setting enable */
213 mb();
214 wdog_dd->enabled = false;
215 pr_info("MSM Apps Watchdog deactivated.\n");
216}
217
218static ssize_t wdog_disable_get(struct device *dev,
219 struct device_attribute *attr, char *buf)
220{
221 int ret;
222 struct msm_watchdog_data *wdog_dd = dev_get_drvdata(dev);
223
224 mutex_lock(&wdog_dd->disable_lock);
225 ret = snprintf(buf, PAGE_SIZE, "%d\n", enable == 0 ? 1 : 0);
226 mutex_unlock(&wdog_dd->disable_lock);
227 return ret;
228}
229
230static ssize_t wdog_disable_set(struct device *dev,
231 struct device_attribute *attr,
232 const char *buf, size_t count)
233{
234 int ret;
235 u8 disable;
236 struct msm_watchdog_data *wdog_dd = dev_get_drvdata(dev);
237
238 ret = kstrtou8(buf, 10, &disable);
239 if (ret) {
240 dev_err(wdog_dd->dev, "invalid user input\n");
241 return ret;
242 }
243 if (disable == 1) {
244 mutex_lock(&wdog_dd->disable_lock);
245 if (enable == 0) {
246 pr_info("MSM Apps Watchdog already disabled\n");
247 mutex_unlock(&wdog_dd->disable_lock);
248 return count;
249 }
250 disable = 1;
251 if (!is_scm_armv8()) {
252 ret = scm_call(SCM_SVC_BOOT, SCM_SVC_SEC_WDOG_DIS,
253 &disable, sizeof(disable), NULL, 0);
254 } else {
255 struct scm_desc desc = {0};
256
257 desc.args[0] = 1;
258 desc.arginfo = SCM_ARGS(1);
259 ret = scm_call2(SCM_SIP_FNID(SCM_SVC_BOOT,
260 SCM_SVC_SEC_WDOG_DIS), &desc);
261 }
262 if (ret) {
263 dev_err(wdog_dd->dev,
264 "Failed to deactivate secure wdog\n");
265 mutex_unlock(&wdog_dd->disable_lock);
266 return -EIO;
267 }
268 wdog_disable(wdog_dd);
269 mutex_unlock(&wdog_dd->disable_lock);
270 } else {
271 pr_err("invalid operation, only disable = 1 supported\n");
272 return -EINVAL;
273 }
274 return count;
275}
276
277static DEVICE_ATTR(disable, S_IWUSR | S_IRUSR, wdog_disable_get,
278 wdog_disable_set);
279
280/*
281 * Userspace Watchdog Support:
282 * Write 1 to the "user_pet_enabled" file to enable hw support for a
283 * userspace watchdog.
284 * Userspace is required to pet the watchdog by continuing to write 1
285 * to this file in the expected interval.
286 * Userspace may disable this requirement by writing 0 to this same
287 * file.
288 */
289static void __wdog_user_pet(struct msm_watchdog_data *wdog_dd)
290{
291 wdog_dd->user_pet_complete = true;
292 wake_up(&wdog_dd->pet_complete);
293}
294
295static ssize_t wdog_user_pet_enabled_get(struct device *dev,
296 struct device_attribute *attr, char *buf)
297{
298 int ret;
299 struct msm_watchdog_data *wdog_dd = dev_get_drvdata(dev);
300
301 ret = snprintf(buf, PAGE_SIZE, "%d\n",
302 wdog_dd->user_pet_enabled);
303 return ret;
304}
305
306static ssize_t wdog_user_pet_enabled_set(struct device *dev,
307 struct device_attribute *attr,
308 const char *buf, size_t count)
309{
310 int ret;
311 struct msm_watchdog_data *wdog_dd = dev_get_drvdata(dev);
312
313 ret = strtobool(buf, &wdog_dd->user_pet_enabled);
314 if (ret) {
315 dev_err(wdog_dd->dev, "invalid user input\n");
316 return ret;
317 }
318
319 __wdog_user_pet(wdog_dd);
320
321 return count;
322}
323
324static DEVICE_ATTR(user_pet_enabled, S_IWUSR | S_IRUSR,
325 wdog_user_pet_enabled_get, wdog_user_pet_enabled_set);
326
327static ssize_t wdog_pet_time_get(struct device *dev,
328 struct device_attribute *attr, char *buf)
329{
330 int ret;
331 struct msm_watchdog_data *wdog_dd = dev_get_drvdata(dev);
332
333 ret = snprintf(buf, PAGE_SIZE, "%d\n", wdog_dd->pet_time);
334 return ret;
335}
336
337static DEVICE_ATTR(pet_time, S_IRUSR, wdog_pet_time_get, NULL);
338
339static void pet_watchdog(struct msm_watchdog_data *wdog_dd)
340{
341 int slack, i, count, prev_count = 0;
342 unsigned long long time_ns;
343 unsigned long long slack_ns;
344 unsigned long long bark_time_ns = wdog_dd->bark_time * 1000000ULL;
345
346 for (i = 0; i < 2; i++) {
347 count = (__raw_readl(wdog_dd->base + WDT0_STS) >> 1) & 0xFFFFF;
348 if (count != prev_count) {
349 prev_count = count;
350 i = 0;
351 }
352 }
353 slack = ((wdog_dd->bark_time * WDT_HZ) / 1000) - count;
354 if (slack < wdog_dd->min_slack_ticks)
355 wdog_dd->min_slack_ticks = slack;
356 __raw_writel(1, wdog_dd->base + WDT0_RST);
357 time_ns = sched_clock();
358 slack_ns = (wdog_dd->last_pet + bark_time_ns) - time_ns;
359 if (slack_ns < wdog_dd->min_slack_ns)
360 wdog_dd->min_slack_ns = slack_ns;
361 wdog_dd->last_pet = time_ns;
362}
363
364static void keep_alive_response(void *info)
365{
366 int cpu = smp_processor_id();
367 struct msm_watchdog_data *wdog_dd = (struct msm_watchdog_data *)info;
368
369 cpumask_set_cpu(cpu, &wdog_dd->alive_mask);
370 /* Make sure alive mask is cleared and set in order */
371 smp_mb();
372}
373
374/*
375 * If this function does not return, it implies one of the
376 * other cpu's is not responsive.
377 */
378static void ping_other_cpus(struct msm_watchdog_data *wdog_dd)
379{
380 int cpu;
381
382 cpumask_clear(&wdog_dd->alive_mask);
383 /* Make sure alive mask is cleared and set in order */
384 smp_mb();
385 for_each_cpu(cpu, cpu_online_mask) {
Olav Haugand584e822016-08-18 16:47:02 -0700386 if (!cpu_idle_pc_state[cpu] && !cpu_isolated(cpu))
Satyajit Desai5255cea2016-08-04 16:02:50 -0700387 smp_call_function_single(cpu, keep_alive_response,
388 wdog_dd, 1);
389 }
390}
391
392static void pet_task_wakeup(unsigned long data)
393{
394 struct msm_watchdog_data *wdog_dd =
395 (struct msm_watchdog_data *)data;
396 wdog_dd->timer_expired = true;
397 wake_up(&wdog_dd->pet_complete);
398}
399
400static __ref int watchdog_kthread(void *arg)
401{
402 struct msm_watchdog_data *wdog_dd =
403 (struct msm_watchdog_data *)arg;
404 unsigned long delay_time = 0;
405 struct sched_param param = {.sched_priority = MAX_RT_PRIO-1};
406
407 sched_setscheduler(current, SCHED_FIFO, &param);
408 while (!kthread_should_stop()) {
409 while (wait_event_interruptible(
410 wdog_dd->pet_complete,
411 wdog_dd->timer_expired) != 0)
412 ;
413
414 if (wdog_dd->do_ipi_ping)
415 ping_other_cpus(wdog_dd);
416
417 while (wait_event_interruptible(
418 wdog_dd->pet_complete,
419 wdog_dd->user_pet_complete) != 0)
420 ;
421
422 wdog_dd->timer_expired = false;
423 wdog_dd->user_pet_complete = !wdog_dd->user_pet_enabled;
424
425 if (enable) {
426 delay_time = msecs_to_jiffies(wdog_dd->pet_time);
427 pet_watchdog(wdog_dd);
428 }
429 /* Check again before scheduling
430 * Could have been changed on other cpu
431 */
432 mod_timer(&wdog_dd->pet_timer, jiffies + delay_time);
433 }
434 return 0;
435}
436
437static int wdog_cpu_pm_notify(struct notifier_block *self,
438 unsigned long action, void *v)
439{
440 int cpu;
441
442 cpu = raw_smp_processor_id();
443
444 switch (action) {
445 case CPU_PM_ENTER:
446 cpu_idle_pc_state[cpu] = 1;
447 break;
448 case CPU_PM_ENTER_FAILED:
449 case CPU_PM_EXIT:
450 cpu_idle_pc_state[cpu] = 0;
451 break;
452 }
453
454 return NOTIFY_OK;
455}
456
457static struct notifier_block wdog_cpu_pm_nb = {
458 .notifier_call = wdog_cpu_pm_notify,
459};
460
461static int msm_watchdog_remove(struct platform_device *pdev)
462{
463 struct msm_watchdog_data *wdog_dd =
464 (struct msm_watchdog_data *)platform_get_drvdata(pdev);
465
466 if (ipi_opt_en)
467 cpu_pm_unregister_notifier(&wdog_cpu_pm_nb);
468
469 mutex_lock(&wdog_dd->disable_lock);
470 if (enable)
471 wdog_disable(wdog_dd);
472
473 mutex_unlock(&wdog_dd->disable_lock);
474 device_remove_file(wdog_dd->dev, &dev_attr_disable);
475 if (wdog_dd->irq_ppi)
476 free_percpu(wdog_dd->wdog_cpu_dd);
477 dev_info(wdog_dd->dev, "MSM Watchdog Exit - Deactivated\n");
478 del_timer_sync(&wdog_dd->pet_timer);
479 kthread_stop(wdog_dd->watchdog_task);
480 kfree(wdog_dd);
481 return 0;
482}
483
484void msm_trigger_wdog_bite(void)
485{
486 if (!wdog_data)
487 return;
488 pr_info("Causing a watchdog bite!");
489 __raw_writel(1, wdog_data->base + WDT0_BITE_TIME);
490 /* Mke sure bite time is written before we reset */
491 mb();
492 __raw_writel(1, wdog_data->base + WDT0_RST);
493 /* Make sure we wait only after reset */
494 mb();
495 /* Delay to make sure bite occurs */
496 mdelay(10000);
497 pr_err("Wdog - STS: 0x%x, CTL: 0x%x, BARK TIME: 0x%x, BITE TIME: 0x%x",
498 __raw_readl(wdog_data->base + WDT0_STS),
499 __raw_readl(wdog_data->base + WDT0_EN),
500 __raw_readl(wdog_data->base + WDT0_BARK_TIME),
501 __raw_readl(wdog_data->base + WDT0_BITE_TIME));
502}
503
504static irqreturn_t wdog_bark_handler(int irq, void *dev_id)
505{
506 struct msm_watchdog_data *wdog_dd = (struct msm_watchdog_data *)dev_id;
507 unsigned long nanosec_rem;
508 unsigned long long t = sched_clock();
509
510 nanosec_rem = do_div(t, 1000000000);
511 dev_info(wdog_dd->dev, "Watchdog bark! Now = %lu.%06lu\n",
512 (unsigned long) t, nanosec_rem / 1000);
513
514 nanosec_rem = do_div(wdog_dd->last_pet, 1000000000);
515 dev_info(wdog_dd->dev, "Watchdog last pet at %lu.%06lu\n",
516 (unsigned long) wdog_dd->last_pet, nanosec_rem / 1000);
517 if (wdog_dd->do_ipi_ping)
518 dump_cpu_alive_mask(wdog_dd);
519 msm_trigger_wdog_bite();
520 panic("Failed to cause a watchdog bite! - Falling back to kernel panic!");
521 return IRQ_HANDLED;
522}
523
524static irqreturn_t wdog_ppi_bark(int irq, void *dev_id)
525{
526 struct msm_watchdog_data *wdog_dd =
527 *(struct msm_watchdog_data **)(dev_id);
528 return wdog_bark_handler(irq, wdog_dd);
529}
530
531static void configure_bark_dump(struct msm_watchdog_data *wdog_dd)
532{
533 int ret;
534 struct msm_dump_entry dump_entry;
535 struct msm_dump_data *cpu_data;
536 int cpu;
537 void *cpu_buf;
538
539 cpu_data = kzalloc(sizeof(struct msm_dump_data) *
540 num_present_cpus(), GFP_KERNEL);
541 if (!cpu_data)
542 goto out0;
543
544 cpu_buf = kzalloc(MAX_CPU_CTX_SIZE * num_present_cpus(),
545 GFP_KERNEL);
546 if (!cpu_buf)
547 goto out1;
548
549 for_each_cpu(cpu, cpu_present_mask) {
550 cpu_data[cpu].addr = virt_to_phys(cpu_buf +
551 cpu * MAX_CPU_CTX_SIZE);
552 cpu_data[cpu].len = MAX_CPU_CTX_SIZE;
Lingutla Chandrasekharbe48b072017-09-25 19:07:12 +0530553 snprintf(cpu_data[cpu].name, sizeof(cpu_data[cpu].name),
554 "KCPU_CTX%d", cpu);
Satyajit Desai5255cea2016-08-04 16:02:50 -0700555 dump_entry.id = MSM_DUMP_DATA_CPU_CTX + cpu;
556 dump_entry.addr = virt_to_phys(&cpu_data[cpu]);
557 ret = msm_dump_data_register(MSM_DUMP_TABLE_APPS,
558 &dump_entry);
559 /*
560 * Don't free the buffers in case of error since
561 * registration may have succeeded for some cpus.
562 */
563 if (ret)
564 pr_err("cpu %d reg dump setup failed\n", cpu);
565 }
566
567 return;
568out1:
569 kfree(cpu_data);
570out0:
571 return;
572}
573
Satyajit Desaia4852262017-04-26 10:01:20 -0700574static void configure_scandump(struct msm_watchdog_data *wdog_dd)
575{
576 int ret;
577 struct msm_dump_entry dump_entry;
578 struct msm_dump_data *cpu_data;
579 int cpu;
580 static dma_addr_t dump_addr;
581 static void *dump_vaddr;
582
583 for_each_cpu(cpu, cpu_present_mask) {
584 cpu_data = devm_kzalloc(wdog_dd->dev,
585 sizeof(struct msm_dump_data),
586 GFP_KERNEL);
587 if (!cpu_data)
588 continue;
589
590 dump_vaddr = (void *) dma_alloc_coherent(wdog_dd->dev,
591 MAX_CPU_SCANDUMP_SIZE,
592 &dump_addr,
593 GFP_KERNEL);
594 if (!dump_vaddr) {
595 dev_err(wdog_dd->dev, "Couldn't get memory for dump\n");
596 continue;
597 }
598 memset(dump_vaddr, 0x0, MAX_CPU_SCANDUMP_SIZE);
599
600 cpu_data->addr = dump_addr;
601 cpu_data->len = MAX_CPU_SCANDUMP_SIZE;
Lingutla Chandrasekharbe48b072017-09-25 19:07:12 +0530602 snprintf(cpu_data->name, sizeof(cpu_data->name),
603 "KSCANDUMP%d", cpu);
Satyajit Desaia4852262017-04-26 10:01:20 -0700604 dump_entry.id = MSM_DUMP_DATA_SCANDUMP_PER_CPU + cpu;
605 dump_entry.addr = virt_to_phys(cpu_data);
606 ret = msm_dump_data_register(MSM_DUMP_TABLE_APPS,
607 &dump_entry);
608 if (ret) {
609 dev_err(wdog_dd->dev, "Dump setup failed, id = %d\n",
610 MSM_DUMP_DATA_SCANDUMP_PER_CPU + cpu);
611 dma_free_coherent(wdog_dd->dev, MAX_CPU_SCANDUMP_SIZE,
612 dump_vaddr,
613 dump_addr);
614 devm_kfree(wdog_dd->dev, cpu_data);
615 }
616 }
617}
618
Satyajit Desai5255cea2016-08-04 16:02:50 -0700619static int init_watchdog_sysfs(struct msm_watchdog_data *wdog_dd)
620{
621 int error = 0;
622
623 error |= device_create_file(wdog_dd->dev, &dev_attr_disable);
624
625 if (of_property_read_bool(wdog_dd->dev->of_node,
626 "qcom,userspace-watchdog")) {
627 error |= device_create_file(wdog_dd->dev, &dev_attr_pet_time);
628 error |= device_create_file(wdog_dd->dev,
629 &dev_attr_user_pet_enabled);
630 }
631
632 if (error)
633 dev_err(wdog_dd->dev, "cannot create sysfs attribute\n");
634
635 return error;
636}
637
638static void init_watchdog_data(struct msm_watchdog_data *wdog_dd)
639{
640 unsigned long delay_time;
641 uint32_t val;
642 u64 timeout;
643 int ret;
644
645 /*
646 * Disable the watchdog for cluster 1 so that cluster 0 watchdog will
647 * be mapped to the entire sub-system.
648 */
649 if (wdog_dd->wdog_absent_base)
650 __raw_writel(2, wdog_dd->wdog_absent_base + WDOG_ABSENT);
651
652 if (wdog_dd->irq_ppi) {
653 wdog_dd->wdog_cpu_dd = alloc_percpu(struct msm_watchdog_data *);
654 if (!wdog_dd->wdog_cpu_dd) {
655 dev_err(wdog_dd->dev, "fail to allocate cpu data\n");
656 return;
657 }
658 *raw_cpu_ptr(wdog_dd->wdog_cpu_dd) = wdog_dd;
659 ret = request_percpu_irq(wdog_dd->bark_irq, wdog_ppi_bark,
660 "apps_wdog_bark",
661 wdog_dd->wdog_cpu_dd);
662 if (ret) {
663 dev_err(wdog_dd->dev, "failed to request bark irq\n");
664 free_percpu(wdog_dd->wdog_cpu_dd);
665 return;
666 }
667 } else {
668 ret = devm_request_irq(wdog_dd->dev, wdog_dd->bark_irq,
669 wdog_bark_handler, IRQF_TRIGGER_RISING,
670 "apps_wdog_bark", wdog_dd);
671 if (ret) {
672 dev_err(wdog_dd->dev, "failed to request bark irq\n");
673 return;
674 }
675 }
676 delay_time = msecs_to_jiffies(wdog_dd->pet_time);
677 wdog_dd->min_slack_ticks = UINT_MAX;
678 wdog_dd->min_slack_ns = ULLONG_MAX;
Satyajit Desaia4852262017-04-26 10:01:20 -0700679 configure_scandump(wdog_dd);
Satyajit Desai5255cea2016-08-04 16:02:50 -0700680 configure_bark_dump(wdog_dd);
681 timeout = (wdog_dd->bark_time * WDT_HZ)/1000;
682 __raw_writel(timeout, wdog_dd->base + WDT0_BARK_TIME);
683 __raw_writel(timeout + 3*WDT_HZ, wdog_dd->base + WDT0_BITE_TIME);
684
685 wdog_dd->panic_blk.notifier_call = panic_wdog_handler;
686 atomic_notifier_chain_register(&panic_notifier_list,
687 &wdog_dd->panic_blk);
688 mutex_init(&wdog_dd->disable_lock);
689 init_waitqueue_head(&wdog_dd->pet_complete);
690 wdog_dd->timer_expired = false;
691 wdog_dd->user_pet_complete = true;
692 wdog_dd->user_pet_enabled = false;
693 wake_up_process(wdog_dd->watchdog_task);
Vikram Mulukutlac850fd82016-10-14 16:13:24 -0700694 init_timer_deferrable(&wdog_dd->pet_timer);
Satyajit Desai5255cea2016-08-04 16:02:50 -0700695 wdog_dd->pet_timer.data = (unsigned long)wdog_dd;
696 wdog_dd->pet_timer.function = pet_task_wakeup;
697 wdog_dd->pet_timer.expires = jiffies + delay_time;
698 add_timer(&wdog_dd->pet_timer);
699
700 val = BIT(EN);
701 if (wdog_dd->wakeup_irq_enable)
702 val |= BIT(UNMASKED_INT_EN);
703 __raw_writel(val, wdog_dd->base + WDT0_EN);
704 __raw_writel(1, wdog_dd->base + WDT0_RST);
705 wdog_dd->last_pet = sched_clock();
706 wdog_dd->enabled = true;
707
708 init_watchdog_sysfs(wdog_dd);
709
710 if (wdog_dd->irq_ppi)
711 enable_percpu_irq(wdog_dd->bark_irq, 0);
712 if (ipi_opt_en)
713 cpu_pm_register_notifier(&wdog_cpu_pm_nb);
714 dev_info(wdog_dd->dev, "MSM Watchdog Initialized\n");
715}
716
717static const struct of_device_id msm_wdog_match_table[] = {
718 { .compatible = "qcom,msm-watchdog" },
719 {}
720};
721
722static void dump_pdata(struct msm_watchdog_data *pdata)
723{
724 dev_dbg(pdata->dev, "wdog bark_time %d", pdata->bark_time);
725 dev_dbg(pdata->dev, "wdog pet_time %d", pdata->pet_time);
726 dev_dbg(pdata->dev, "wdog perform ipi ping %d", pdata->do_ipi_ping);
727 dev_dbg(pdata->dev, "wdog base address is 0x%lx\n", (unsigned long)
728 pdata->base);
729}
730
731static int msm_wdog_dt_to_pdata(struct platform_device *pdev,
732 struct msm_watchdog_data *pdata)
733{
734 struct device_node *node = pdev->dev.of_node;
735 struct resource *res;
736 int ret;
737
738 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "wdt-base");
739 if (!res)
740 return -ENODEV;
741 pdata->size = resource_size(res);
742 pdata->phys_base = res->start;
743 if (unlikely(!(devm_request_mem_region(&pdev->dev, pdata->phys_base,
744 pdata->size, "msm-watchdog")))) {
745
746 dev_err(&pdev->dev, "%s cannot reserve watchdog region\n",
747 __func__);
748 return -ENXIO;
749 }
750 pdata->base = devm_ioremap(&pdev->dev, pdata->phys_base,
751 pdata->size);
752 if (!pdata->base) {
753 dev_err(&pdev->dev, "%s cannot map wdog register space\n",
754 __func__);
755 return -ENXIO;
756 }
757
758 res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
759 "wdt-absent-base");
760 if (res) {
761 pdata->wdog_absent_base = devm_ioremap(&pdev->dev, res->start,
762 resource_size(res));
763 if (!pdata->wdog_absent_base) {
764 dev_err(&pdev->dev,
765 "cannot map wdog absent register space\n");
766 return -ENXIO;
767 }
768 } else {
769 dev_info(&pdev->dev, "wdog absent resource not present\n");
770 }
771
772 pdata->bark_irq = platform_get_irq(pdev, 0);
773 pdata->bite_irq = platform_get_irq(pdev, 1);
774 ret = of_property_read_u32(node, "qcom,bark-time", &pdata->bark_time);
775 if (ret) {
776 dev_err(&pdev->dev, "reading bark time failed\n");
777 return -ENXIO;
778 }
779 ret = of_property_read_u32(node, "qcom,pet-time", &pdata->pet_time);
780 if (ret) {
781 dev_err(&pdev->dev, "reading pet time failed\n");
782 return -ENXIO;
783 }
784 pdata->do_ipi_ping = of_property_read_bool(node, "qcom,ipi-ping");
785 if (!pdata->bark_time) {
786 dev_err(&pdev->dev, "%s watchdog bark time not setup\n",
787 __func__);
788 return -ENXIO;
789 }
790 if (!pdata->pet_time) {
791 dev_err(&pdev->dev, "%s watchdog pet time not setup\n",
792 __func__);
793 return -ENXIO;
794 }
795 pdata->wakeup_irq_enable = of_property_read_bool(node,
796 "qcom,wakeup-enable");
797
798 pdata->irq_ppi = irq_is_percpu(pdata->bark_irq);
799 dump_pdata(pdata);
800 return 0;
801}
802
803static int msm_watchdog_probe(struct platform_device *pdev)
804{
805 int ret;
806 struct msm_watchdog_data *wdog_dd;
Lingutla Chandrasekharbe48b072017-09-25 19:07:12 +0530807 struct md_region md_entry;
Satyajit Desai5255cea2016-08-04 16:02:50 -0700808
809 if (!pdev->dev.of_node || !enable)
810 return -ENODEV;
811 wdog_dd = kzalloc(sizeof(struct msm_watchdog_data), GFP_KERNEL);
812 if (!wdog_dd)
813 return -EIO;
814 ret = msm_wdog_dt_to_pdata(pdev, wdog_dd);
815 if (ret)
816 goto err;
817
818 wdog_data = wdog_dd;
819 wdog_dd->dev = &pdev->dev;
820 platform_set_drvdata(pdev, wdog_dd);
821 cpumask_clear(&wdog_dd->alive_mask);
822 wdog_dd->watchdog_task = kthread_create(watchdog_kthread, wdog_dd,
823 "msm_watchdog");
824 if (IS_ERR(wdog_dd->watchdog_task)) {
825 ret = PTR_ERR(wdog_dd->watchdog_task);
826 goto err;
827 }
828 init_watchdog_data(wdog_dd);
Lingutla Chandrasekharbe48b072017-09-25 19:07:12 +0530829
830 /* Add wdog info to minidump table */
831 strlcpy(md_entry.name, "KWDOGDATA", sizeof(md_entry.name));
832 md_entry.virt_addr = (uintptr_t)wdog_dd;
833 md_entry.phys_addr = virt_to_phys(wdog_dd);
834 md_entry.size = sizeof(*wdog_dd);
835 if (msm_minidump_add_region(&md_entry))
836 pr_info("Failed to add Watchdog data in Minidump\n");
837
Satyajit Desai5255cea2016-08-04 16:02:50 -0700838 return 0;
839err:
840 kzfree(wdog_dd);
841 return ret;
842}
843
844static const struct dev_pm_ops msm_watchdog_dev_pm_ops = {
845 .suspend_noirq = msm_watchdog_suspend,
846 .resume_noirq = msm_watchdog_resume,
847};
848
849static struct platform_driver msm_watchdog_driver = {
850 .probe = msm_watchdog_probe,
851 .remove = msm_watchdog_remove,
852 .driver = {
853 .name = MODULE_NAME,
854 .owner = THIS_MODULE,
855 .pm = &msm_watchdog_dev_pm_ops,
856 .of_match_table = msm_wdog_match_table,
857 },
858};
859
860static int init_watchdog(void)
861{
862 return platform_driver_register(&msm_watchdog_driver);
863}
864
865pure_initcall(init_watchdog);
866MODULE_DESCRIPTION("MSM Watchdog Driver");
867MODULE_LICENSE("GPL v2");