Loading drivers/soc/qcom/watchdog_v2.c +53 −66 Original line number Diff line number Diff line Loading @@ -14,9 +14,9 @@ #include <linux/kernel.h> #include <linux/io.h> #include <linux/delay.h> #include <linux/workqueue.h> #include <linux/slab.h> #include <linux/jiffies.h> #include <linux/kthread.h> #include <linux/mutex.h> #include <linux/sched.h> #include <linux/interrupt.h> Loading Loading @@ -49,7 +49,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]; Loading @@ -72,12 +71,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; }; /* Loading @@ -104,9 +104,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]; Loading Loading @@ -188,7 +185,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(); Loading @@ -196,20 +193,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) { Loading @@ -228,7 +211,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); Loading Loading @@ -260,11 +242,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"); Loading Loading @@ -325,24 +303,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; 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); 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 */ if (enable) queue_delayed_work(wdog_wq, &wdog_dd->dogwork_struct, delay_time); mod_timer(&wdog_dd->pet_timer, jiffies + delay_time); } return 0; } static int wdog_cpu_pm_notify(struct notifier_block *self, Loading Loading @@ -371,7 +362,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); Loading @@ -380,18 +370,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; } Loading Loading @@ -532,11 +519,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; Loading Loading @@ -586,8 +570,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); Loading Loading @@ -697,12 +687,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); Loading @@ -716,12 +700,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; } Loading Loading
drivers/soc/qcom/watchdog_v2.c +53 −66 Original line number Diff line number Diff line Loading @@ -14,9 +14,9 @@ #include <linux/kernel.h> #include <linux/io.h> #include <linux/delay.h> #include <linux/workqueue.h> #include <linux/slab.h> #include <linux/jiffies.h> #include <linux/kthread.h> #include <linux/mutex.h> #include <linux/sched.h> #include <linux/interrupt.h> Loading Loading @@ -49,7 +49,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]; Loading @@ -72,12 +71,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; }; /* Loading @@ -104,9 +104,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]; Loading Loading @@ -188,7 +185,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(); Loading @@ -196,20 +193,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) { Loading @@ -228,7 +211,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); Loading Loading @@ -260,11 +242,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"); Loading Loading @@ -325,24 +303,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; 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); 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 */ if (enable) queue_delayed_work(wdog_wq, &wdog_dd->dogwork_struct, delay_time); mod_timer(&wdog_dd->pet_timer, jiffies + delay_time); } return 0; } static int wdog_cpu_pm_notify(struct notifier_block *self, Loading Loading @@ -371,7 +362,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); Loading @@ -380,18 +370,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; } Loading Loading @@ -532,11 +519,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; Loading Loading @@ -586,8 +570,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); Loading Loading @@ -697,12 +687,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); Loading @@ -716,12 +700,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; } Loading