diff --git a/drivers/soc/qcom/watchdog_v2.c b/drivers/soc/qcom/watchdog_v2.c index 761259842393..6bef39edc003 100644 --- a/drivers/soc/qcom/watchdog_v2.c +++ b/drivers/soc/qcom/watchdog_v2.c @@ -14,9 +14,9 @@ #include #include #include -#include #include #include +#include #include #include #include @@ -48,7 +48,6 @@ #define SCM_SVC_SEC_WDOG_DIS 0x7 #define MAX_CPU_CTX_SIZE 2048 -static struct workqueue_struct *wdog_wq; static struct msm_watchdog_data *wdog_data; static int cpu_idle_pc_state[NR_CPUS]; @@ -71,12 +70,13 @@ struct msm_watchdog_data { void *scm_regsave; cpumask_t alive_mask; struct mutex disable_lock; - struct work_struct init_dogwork_struct; - struct delayed_work dogwork_struct; bool irq_ppi; struct msm_watchdog_data __percpu **wdog_cpu_dd; struct notifier_block panic_blk; bool enabled; + struct task_struct *watchdog_task; + struct timer_list pet_timer; + struct completion pet_complete; }; /* @@ -103,9 +103,6 @@ module_param(WDT_HZ, long, 0); static int ipi_opt_en; module_param(ipi_opt_en, int, 0); -static void pet_watchdog_work(struct work_struct *work); -static void init_watchdog_work(struct work_struct *work); - static void dump_cpu_alive_mask(struct msm_watchdog_data *wdog_dd) { static char alive_mask_buf[MASK_SIZE]; @@ -178,7 +175,7 @@ static void wdog_disable(struct msm_watchdog_data *wdog_dd) smp_mb(); atomic_notifier_chain_unregister(&panic_notifier_list, &wdog_dd->panic_blk); - cancel_delayed_work_sync(&wdog_dd->dogwork_struct); + del_timer_sync(&wdog_dd->pet_timer); /* may be suspended after the first write above */ __raw_writel(0, wdog_dd->base + WDT0_EN); mb(); @@ -186,20 +183,6 @@ static void wdog_disable(struct msm_watchdog_data *wdog_dd) pr_info("MSM Apps Watchdog deactivated.\n"); } -struct wdog_disable_work_data { - struct work_struct work; - struct completion complete; - struct msm_watchdog_data *wdog_dd; -}; - -static void wdog_disable_work(struct work_struct *work) -{ - struct wdog_disable_work_data *work_data = - container_of(work, struct wdog_disable_work_data, work); - wdog_disable(work_data->wdog_dd); - complete(&work_data->complete); -} - static ssize_t wdog_disable_get(struct device *dev, struct device_attribute *attr, char *buf) { @@ -218,7 +201,6 @@ static ssize_t wdog_disable_set(struct device *dev, { int ret; u8 disable; - struct wdog_disable_work_data work_data; struct msm_watchdog_data *wdog_dd = dev_get_drvdata(dev); ret = kstrtou8(buf, 10, &disable); @@ -250,11 +232,7 @@ static ssize_t wdog_disable_set(struct device *dev, mutex_unlock(&wdog_dd->disable_lock); return -EIO; } - work_data.wdog_dd = wdog_dd; - init_completion(&work_data.complete); - INIT_WORK_ONSTACK(&work_data.work, wdog_disable_work); - queue_work(wdog_wq, &work_data.work); - wait_for_completion(&work_data.complete); + wdog_disable(wdog_dd); mutex_unlock(&wdog_dd->disable_lock); } else { pr_err("invalid operation, only disable = 1 supported\n"); @@ -315,24 +293,37 @@ static void ping_other_cpus(struct msm_watchdog_data *wdog_dd) } } -static void pet_watchdog_work(struct work_struct *work) +static void pet_task_wakeup(unsigned long data) { + struct msm_watchdog_data *wdog_dd = + (struct msm_watchdog_data *)data; + complete(&wdog_dd->pet_complete); +} + +static __ref int watchdog_kthread(void *arg) +{ + struct msm_watchdog_data *wdog_dd = + (struct msm_watchdog_data *)arg; unsigned long delay_time = 0; - struct delayed_work *delayed_work = to_delayed_work(work); - struct msm_watchdog_data *wdog_dd = container_of(delayed_work, - struct msm_watchdog_data, - dogwork_struct); - delay_time = msecs_to_jiffies(wdog_dd->pet_time); - if (enable) { - if (wdog_dd->do_ipi_ping) - ping_other_cpus(wdog_dd); - pet_watchdog(wdog_dd); + struct sched_param param = {.sched_priority = MAX_RT_PRIO-1}; + + sched_setscheduler(current, SCHED_FIFO, ¶m); + while (!kthread_should_stop()) { + while (wait_for_completion_interruptible( + &wdog_dd->pet_complete) != 0) + ; + reinit_completion(&wdog_dd->pet_complete); + if (enable) { + delay_time = msecs_to_jiffies(wdog_dd->pet_time); + if (wdog_dd->do_ipi_ping) + ping_other_cpus(wdog_dd); + pet_watchdog(wdog_dd); + } + /* Check again before scheduling * + * Could have been changed on other cpu */ + mod_timer(&wdog_dd->pet_timer, jiffies + delay_time); } - /* Check again before scheduling * - * Could have been changed on other cpu */ - if (enable) - queue_delayed_work(wdog_wq, - &wdog_dd->dogwork_struct, delay_time); + return 0; } static int wdog_cpu_pm_notify(struct notifier_block *self, @@ -361,7 +352,6 @@ static struct notifier_block wdog_cpu_pm_nb = { static int msm_watchdog_remove(struct platform_device *pdev) { - struct wdog_disable_work_data work_data; struct msm_watchdog_data *wdog_dd = (struct msm_watchdog_data *)platform_get_drvdata(pdev); @@ -370,18 +360,15 @@ static int msm_watchdog_remove(struct platform_device *pdev) mutex_lock(&wdog_dd->disable_lock); if (enable) { - work_data.wdog_dd = wdog_dd; - init_completion(&work_data.complete); - INIT_WORK_ONSTACK(&work_data.work, wdog_disable_work); - queue_work(wdog_wq, &work_data.work); - wait_for_completion(&work_data.complete); + wdog_disable(wdog_dd); } mutex_unlock(&wdog_dd->disable_lock); device_remove_file(wdog_dd->dev, &dev_attr_disable); if (wdog_dd->irq_ppi) free_percpu(wdog_dd->wdog_cpu_dd); printk(KERN_INFO "MSM Watchdog Exit - Deactivated\n"); - destroy_workqueue(wdog_wq); + del_timer_sync(&wdog_dd->pet_timer); + kthread_stop(wdog_dd->watchdog_task); kfree(wdog_dd); return 0; } @@ -396,7 +383,7 @@ void msm_trigger_wdog_bite(void) __raw_writel(1, wdog_data->base + WDT0_RST); mb(); /* Delay to make sure bite occurs */ - mdelay(2000); + mdelay(10000); pr_err("Wdog - STS: 0x%x, CTL: 0x%x, BARK TIME: 0x%x, BITE TIME: 0x%x", __raw_readl(wdog_data->base + WDT0_STS), __raw_readl(wdog_data->base + WDT0_EN), @@ -533,11 +520,8 @@ out0: } -static void init_watchdog_work(struct work_struct *work) +static void init_watchdog_data(struct msm_watchdog_data *wdog_dd) { - struct msm_watchdog_data *wdog_dd = container_of(work, - struct msm_watchdog_data, - init_dogwork_struct); unsigned long delay_time; uint32_t val; int error; @@ -587,8 +571,14 @@ static void init_watchdog_work(struct work_struct *work) atomic_notifier_chain_register(&panic_notifier_list, &wdog_dd->panic_blk); mutex_init(&wdog_dd->disable_lock); - queue_delayed_work(wdog_wq, &wdog_dd->dogwork_struct, - delay_time); + init_completion(&wdog_dd->pet_complete); + wake_up_process(wdog_dd->watchdog_task); + init_timer(&wdog_dd->pet_timer); + wdog_dd->pet_timer.data = (unsigned long)wdog_dd; + wdog_dd->pet_timer.function = pet_task_wakeup; + wdog_dd->pet_timer.expires = jiffies + delay_time; + add_timer(&wdog_dd->pet_timer); + val = BIT(EN); if (wdog_dd->wakeup_irq_enable) val |= BIT(UNMASKED_INT_EN); @@ -698,12 +688,6 @@ static int msm_watchdog_probe(struct platform_device *pdev) int ret; struct msm_watchdog_data *wdog_dd; - wdog_wq = alloc_workqueue("wdog", WQ_HIGHPRI, 0); - if (!wdog_wq) { - pr_err("Failed to allocate watchdog workqueue\n"); - return -EIO; - } - if (!pdev->dev.of_node || !enable) return -ENODEV; wdog_dd = kzalloc(sizeof(struct msm_watchdog_data), GFP_KERNEL); @@ -717,12 +701,15 @@ static int msm_watchdog_probe(struct platform_device *pdev) wdog_dd->dev = &pdev->dev; platform_set_drvdata(pdev, wdog_dd); cpumask_clear(&wdog_dd->alive_mask); - INIT_WORK(&wdog_dd->init_dogwork_struct, init_watchdog_work); - INIT_DELAYED_WORK(&wdog_dd->dogwork_struct, pet_watchdog_work); - queue_work(wdog_wq, &wdog_dd->init_dogwork_struct); + wdog_dd->watchdog_task = kthread_create(watchdog_kthread, wdog_dd, + "msm_watchdog"); + if (IS_ERR(wdog_dd->watchdog_task)) { + ret = PTR_ERR(wdog_dd->watchdog_task); + goto err; + } + init_watchdog_data(wdog_dd); return 0; err: - destroy_workqueue(wdog_wq); kzfree(wdog_dd); return ret; }