Loading drivers/soc/qcom/watchdog_v2.c +53 −66 Original line number Original line Diff line number Diff line Loading @@ -14,9 +14,9 @@ #include <linux/kernel.h> #include <linux/kernel.h> #include <linux/io.h> #include <linux/io.h> #include <linux/delay.h> #include <linux/delay.h> #include <linux/workqueue.h> #include <linux/slab.h> #include <linux/slab.h> #include <linux/jiffies.h> #include <linux/jiffies.h> #include <linux/kthread.h> #include <linux/mutex.h> #include <linux/mutex.h> #include <linux/sched.h> #include <linux/sched.h> #include <linux/interrupt.h> #include <linux/interrupt.h> Loading Loading @@ -49,7 +49,6 @@ #define SCM_SVC_SEC_WDOG_DIS 0x7 #define SCM_SVC_SEC_WDOG_DIS 0x7 #define MAX_CPU_CTX_SIZE 2048 #define MAX_CPU_CTX_SIZE 2048 static struct workqueue_struct *wdog_wq; static struct msm_watchdog_data *wdog_data; static struct msm_watchdog_data *wdog_data; static int cpu_idle_pc_state[NR_CPUS]; static int cpu_idle_pc_state[NR_CPUS]; Loading @@ -72,12 +71,13 @@ struct msm_watchdog_data { void *scm_regsave; void *scm_regsave; cpumask_t alive_mask; cpumask_t alive_mask; struct mutex disable_lock; struct mutex disable_lock; struct work_struct init_dogwork_struct; struct delayed_work dogwork_struct; bool irq_ppi; bool irq_ppi; struct msm_watchdog_data __percpu **wdog_cpu_dd; struct msm_watchdog_data __percpu **wdog_cpu_dd; struct notifier_block panic_blk; struct notifier_block panic_blk; bool enabled; 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; static int ipi_opt_en; module_param(ipi_opt_en, int, 0); 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 void dump_cpu_alive_mask(struct msm_watchdog_data *wdog_dd) { { static char alive_mask_buf[MASK_SIZE]; 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(); smp_mb(); atomic_notifier_chain_unregister(&panic_notifier_list, atomic_notifier_chain_unregister(&panic_notifier_list, &wdog_dd->panic_blk); &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 */ /* may be suspended after the first write above */ __raw_writel(0, wdog_dd->base + WDT0_EN); __raw_writel(0, wdog_dd->base + WDT0_EN); mb(); mb(); Loading @@ -196,20 +193,6 @@ static void wdog_disable(struct msm_watchdog_data *wdog_dd) pr_info("MSM Apps Watchdog deactivated.\n"); 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, static ssize_t wdog_disable_get(struct device *dev, struct device_attribute *attr, char *buf) struct device_attribute *attr, char *buf) { { Loading @@ -228,7 +211,6 @@ static ssize_t wdog_disable_set(struct device *dev, { { int ret; int ret; u8 disable; u8 disable; struct wdog_disable_work_data work_data; struct msm_watchdog_data *wdog_dd = dev_get_drvdata(dev); struct msm_watchdog_data *wdog_dd = dev_get_drvdata(dev); ret = kstrtou8(buf, 10, &disable); 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); mutex_unlock(&wdog_dd->disable_lock); return -EIO; return -EIO; } } work_data.wdog_dd = wdog_dd; wdog_disable(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); mutex_unlock(&wdog_dd->disable_lock); mutex_unlock(&wdog_dd->disable_lock); } else { } else { pr_err("invalid operation, only disable = 1 supported\n"); 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; unsigned long delay_time; struct delayed_work *delayed_work = to_delayed_work(work); struct sched_param param = {.sched_priority = MAX_RT_PRIO-1}; struct msm_watchdog_data *wdog_dd = container_of(delayed_work, struct msm_watchdog_data, sched_setscheduler(current, SCHED_FIFO, ¶m); dogwork_struct); while (!kthread_should_stop()) { delay_time = msecs_to_jiffies(wdog_dd->pet_time); while (wait_for_completion_interruptible( &wdog_dd->pet_complete) != 0) ; reinit_completion(&wdog_dd->pet_complete); if (enable) { if (enable) { delay_time = msecs_to_jiffies(wdog_dd->pet_time); if (wdog_dd->do_ipi_ping) if (wdog_dd->do_ipi_ping) ping_other_cpus(wdog_dd); ping_other_cpus(wdog_dd); pet_watchdog(wdog_dd); pet_watchdog(wdog_dd); } } /* Check again before scheduling * /* Check again before scheduling * * Could have been changed on other cpu */ * Could have been changed on other cpu */ if (enable) mod_timer(&wdog_dd->pet_timer, jiffies + delay_time); queue_delayed_work(wdog_wq, } &wdog_dd->dogwork_struct, delay_time); return 0; } } static int wdog_cpu_pm_notify(struct notifier_block *self, 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) 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 *wdog_dd = (struct msm_watchdog_data *)platform_get_drvdata(pdev); (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); mutex_lock(&wdog_dd->disable_lock); if (enable) { if (enable) { work_data.wdog_dd = wdog_dd; wdog_disable(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); } } mutex_unlock(&wdog_dd->disable_lock); mutex_unlock(&wdog_dd->disable_lock); device_remove_file(wdog_dd->dev, &dev_attr_disable); device_remove_file(wdog_dd->dev, &dev_attr_disable); if (wdog_dd->irq_ppi) if (wdog_dd->irq_ppi) free_percpu(wdog_dd->wdog_cpu_dd); free_percpu(wdog_dd->wdog_cpu_dd); printk(KERN_INFO "MSM Watchdog Exit - Deactivated\n"); 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); kfree(wdog_dd); return 0; 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; unsigned long delay_time; uint32_t val; uint32_t val; int error; int error; Loading Loading @@ -586,8 +570,14 @@ static void init_watchdog_work(struct work_struct *work) atomic_notifier_chain_register(&panic_notifier_list, atomic_notifier_chain_register(&panic_notifier_list, &wdog_dd->panic_blk); &wdog_dd->panic_blk); mutex_init(&wdog_dd->disable_lock); mutex_init(&wdog_dd->disable_lock); queue_delayed_work(wdog_wq, &wdog_dd->dogwork_struct, init_completion(&wdog_dd->pet_complete); delay_time); 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); val = BIT(EN); if (wdog_dd->wakeup_irq_enable) if (wdog_dd->wakeup_irq_enable) val |= BIT(UNMASKED_INT_EN); val |= BIT(UNMASKED_INT_EN); Loading Loading @@ -697,12 +687,6 @@ static int msm_watchdog_probe(struct platform_device *pdev) int ret; int ret; struct msm_watchdog_data *wdog_dd; 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) if (!pdev->dev.of_node || !enable) return -ENODEV; return -ENODEV; wdog_dd = kzalloc(sizeof(struct msm_watchdog_data), GFP_KERNEL); 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; wdog_dd->dev = &pdev->dev; platform_set_drvdata(pdev, wdog_dd); platform_set_drvdata(pdev, wdog_dd); cpumask_clear(&wdog_dd->alive_mask); cpumask_clear(&wdog_dd->alive_mask); INIT_WORK(&wdog_dd->init_dogwork_struct, init_watchdog_work); wdog_dd->watchdog_task = kthread_create(watchdog_kthread, wdog_dd, INIT_DELAYED_WORK(&wdog_dd->dogwork_struct, pet_watchdog_work); "msm_watchdog"); queue_work(wdog_wq, &wdog_dd->init_dogwork_struct); if (IS_ERR(wdog_dd->watchdog_task)) { ret = PTR_ERR(wdog_dd->watchdog_task); goto err; } init_watchdog_data(wdog_dd); return 0; return 0; err: err: destroy_workqueue(wdog_wq); kzfree(wdog_dd); kzfree(wdog_dd); return ret; return ret; } } Loading Loading
drivers/soc/qcom/watchdog_v2.c +53 −66 Original line number Original line Diff line number Diff line Loading @@ -14,9 +14,9 @@ #include <linux/kernel.h> #include <linux/kernel.h> #include <linux/io.h> #include <linux/io.h> #include <linux/delay.h> #include <linux/delay.h> #include <linux/workqueue.h> #include <linux/slab.h> #include <linux/slab.h> #include <linux/jiffies.h> #include <linux/jiffies.h> #include <linux/kthread.h> #include <linux/mutex.h> #include <linux/mutex.h> #include <linux/sched.h> #include <linux/sched.h> #include <linux/interrupt.h> #include <linux/interrupt.h> Loading Loading @@ -49,7 +49,6 @@ #define SCM_SVC_SEC_WDOG_DIS 0x7 #define SCM_SVC_SEC_WDOG_DIS 0x7 #define MAX_CPU_CTX_SIZE 2048 #define MAX_CPU_CTX_SIZE 2048 static struct workqueue_struct *wdog_wq; static struct msm_watchdog_data *wdog_data; static struct msm_watchdog_data *wdog_data; static int cpu_idle_pc_state[NR_CPUS]; static int cpu_idle_pc_state[NR_CPUS]; Loading @@ -72,12 +71,13 @@ struct msm_watchdog_data { void *scm_regsave; void *scm_regsave; cpumask_t alive_mask; cpumask_t alive_mask; struct mutex disable_lock; struct mutex disable_lock; struct work_struct init_dogwork_struct; struct delayed_work dogwork_struct; bool irq_ppi; bool irq_ppi; struct msm_watchdog_data __percpu **wdog_cpu_dd; struct msm_watchdog_data __percpu **wdog_cpu_dd; struct notifier_block panic_blk; struct notifier_block panic_blk; bool enabled; 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; static int ipi_opt_en; module_param(ipi_opt_en, int, 0); 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 void dump_cpu_alive_mask(struct msm_watchdog_data *wdog_dd) { { static char alive_mask_buf[MASK_SIZE]; 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(); smp_mb(); atomic_notifier_chain_unregister(&panic_notifier_list, atomic_notifier_chain_unregister(&panic_notifier_list, &wdog_dd->panic_blk); &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 */ /* may be suspended after the first write above */ __raw_writel(0, wdog_dd->base + WDT0_EN); __raw_writel(0, wdog_dd->base + WDT0_EN); mb(); mb(); Loading @@ -196,20 +193,6 @@ static void wdog_disable(struct msm_watchdog_data *wdog_dd) pr_info("MSM Apps Watchdog deactivated.\n"); 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, static ssize_t wdog_disable_get(struct device *dev, struct device_attribute *attr, char *buf) struct device_attribute *attr, char *buf) { { Loading @@ -228,7 +211,6 @@ static ssize_t wdog_disable_set(struct device *dev, { { int ret; int ret; u8 disable; u8 disable; struct wdog_disable_work_data work_data; struct msm_watchdog_data *wdog_dd = dev_get_drvdata(dev); struct msm_watchdog_data *wdog_dd = dev_get_drvdata(dev); ret = kstrtou8(buf, 10, &disable); 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); mutex_unlock(&wdog_dd->disable_lock); return -EIO; return -EIO; } } work_data.wdog_dd = wdog_dd; wdog_disable(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); mutex_unlock(&wdog_dd->disable_lock); mutex_unlock(&wdog_dd->disable_lock); } else { } else { pr_err("invalid operation, only disable = 1 supported\n"); 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; unsigned long delay_time; struct delayed_work *delayed_work = to_delayed_work(work); struct sched_param param = {.sched_priority = MAX_RT_PRIO-1}; struct msm_watchdog_data *wdog_dd = container_of(delayed_work, struct msm_watchdog_data, sched_setscheduler(current, SCHED_FIFO, ¶m); dogwork_struct); while (!kthread_should_stop()) { delay_time = msecs_to_jiffies(wdog_dd->pet_time); while (wait_for_completion_interruptible( &wdog_dd->pet_complete) != 0) ; reinit_completion(&wdog_dd->pet_complete); if (enable) { if (enable) { delay_time = msecs_to_jiffies(wdog_dd->pet_time); if (wdog_dd->do_ipi_ping) if (wdog_dd->do_ipi_ping) ping_other_cpus(wdog_dd); ping_other_cpus(wdog_dd); pet_watchdog(wdog_dd); pet_watchdog(wdog_dd); } } /* Check again before scheduling * /* Check again before scheduling * * Could have been changed on other cpu */ * Could have been changed on other cpu */ if (enable) mod_timer(&wdog_dd->pet_timer, jiffies + delay_time); queue_delayed_work(wdog_wq, } &wdog_dd->dogwork_struct, delay_time); return 0; } } static int wdog_cpu_pm_notify(struct notifier_block *self, 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) 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 *wdog_dd = (struct msm_watchdog_data *)platform_get_drvdata(pdev); (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); mutex_lock(&wdog_dd->disable_lock); if (enable) { if (enable) { work_data.wdog_dd = wdog_dd; wdog_disable(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); } } mutex_unlock(&wdog_dd->disable_lock); mutex_unlock(&wdog_dd->disable_lock); device_remove_file(wdog_dd->dev, &dev_attr_disable); device_remove_file(wdog_dd->dev, &dev_attr_disable); if (wdog_dd->irq_ppi) if (wdog_dd->irq_ppi) free_percpu(wdog_dd->wdog_cpu_dd); free_percpu(wdog_dd->wdog_cpu_dd); printk(KERN_INFO "MSM Watchdog Exit - Deactivated\n"); 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); kfree(wdog_dd); return 0; 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; unsigned long delay_time; uint32_t val; uint32_t val; int error; int error; Loading Loading @@ -586,8 +570,14 @@ static void init_watchdog_work(struct work_struct *work) atomic_notifier_chain_register(&panic_notifier_list, atomic_notifier_chain_register(&panic_notifier_list, &wdog_dd->panic_blk); &wdog_dd->panic_blk); mutex_init(&wdog_dd->disable_lock); mutex_init(&wdog_dd->disable_lock); queue_delayed_work(wdog_wq, &wdog_dd->dogwork_struct, init_completion(&wdog_dd->pet_complete); delay_time); 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); val = BIT(EN); if (wdog_dd->wakeup_irq_enable) if (wdog_dd->wakeup_irq_enable) val |= BIT(UNMASKED_INT_EN); val |= BIT(UNMASKED_INT_EN); Loading Loading @@ -697,12 +687,6 @@ static int msm_watchdog_probe(struct platform_device *pdev) int ret; int ret; struct msm_watchdog_data *wdog_dd; 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) if (!pdev->dev.of_node || !enable) return -ENODEV; return -ENODEV; wdog_dd = kzalloc(sizeof(struct msm_watchdog_data), GFP_KERNEL); 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; wdog_dd->dev = &pdev->dev; platform_set_drvdata(pdev, wdog_dd); platform_set_drvdata(pdev, wdog_dd); cpumask_clear(&wdog_dd->alive_mask); cpumask_clear(&wdog_dd->alive_mask); INIT_WORK(&wdog_dd->init_dogwork_struct, init_watchdog_work); wdog_dd->watchdog_task = kthread_create(watchdog_kthread, wdog_dd, INIT_DELAYED_WORK(&wdog_dd->dogwork_struct, pet_watchdog_work); "msm_watchdog"); queue_work(wdog_wq, &wdog_dd->init_dogwork_struct); if (IS_ERR(wdog_dd->watchdog_task)) { ret = PTR_ERR(wdog_dd->watchdog_task); goto err; } init_watchdog_data(wdog_dd); return 0; return 0; err: err: destroy_workqueue(wdog_wq); kzfree(wdog_dd); kzfree(wdog_dd); return ret; return ret; } } Loading