diff --git a/drivers/soc/qcom/qcom_wdt_core.c b/drivers/soc/qcom/qcom_wdt_core.c index 3e6b0f58aff0..bcb9a85f4e25 100644 --- a/drivers/soc/qcom/qcom_wdt_core.c +++ b/drivers/soc/qcom/qcom_wdt_core.c @@ -310,6 +310,8 @@ int qcom_wdt_pet_suspend(struct device *dev) wdog_dd->freeze_in_progress = true; spin_unlock(&wdog_dd->freeze_lock); del_timer_sync(&wdog_dd->pet_timer); + if (wdog_dd->user_pet_enabled) + del_timer_sync(&wdog_dd->user_pet_timer); return 0; } EXPORT_SYMBOL(qcom_wdt_pet_suspend); @@ -329,6 +331,11 @@ int qcom_wdt_pet_resume(struct device *dev) spin_lock(&wdog_dd->freeze_lock); wdog_dd->pet_timer.expires = jiffies + delay_time; add_timer(&wdog_dd->pet_timer); + if (wdog_dd->user_pet_enabled) { + delay_time = msecs_to_jiffies(wdog_dd->bark_time + 3 * 1000); + wdog_dd->user_pet_timer.expires = jiffies + delay_time; + add_timer(&wdog_dd->user_pet_timer); + } wdog_dd->freeze_in_progress = false; spin_unlock(&wdog_dd->freeze_lock); return 0; @@ -419,6 +426,8 @@ static void qcom_wdt_disable(struct msm_watchdog_data *wdog_dd) qcom_wdt_unregister_die_notifier(wdog_dd); unregister_restart_handler(&wdog_dd->restart_blk); del_timer_sync(&wdog_dd->pet_timer); + if (wdog_dd->user_pet_enabled) + del_timer_sync(&wdog_dd->user_pet_timer); wdog_dd->ops->disable_wdt(wdog_dd); dev_err(wdog_dd->dev, "QCOM Apps Watchdog deactivated\n"); } @@ -522,6 +531,8 @@ static ssize_t qcom_wdt_user_pet_enabled_set(struct device *dev, { struct msm_watchdog_data *wdog_dd = dev_get_drvdata(dev); int ret; + unsigned long delay_time = 0; + bool already_enabled = wdog_dd->user_pet_enabled; ret = strtobool(buf, &wdog_dd->user_pet_enabled); if (ret) { @@ -529,6 +540,12 @@ static ssize_t qcom_wdt_user_pet_enabled_set(struct device *dev, return ret; } + delay_time = msecs_to_jiffies(wdog_dd->bark_time + 3 * 1000); + if (wdog_dd->user_pet_enabled) + mod_timer(&wdog_dd->user_pet_timer, jiffies + delay_time); + else if (already_enabled) + del_timer_sync(&wdog_dd->user_pet_timer); + __qcom_wdt_user_pet(wdog_dd); return count; @@ -589,6 +606,15 @@ static void qcom_wdt_pet_task_wakeup(struct timer_list *t) wdog_dd->timer_fired = sched_clock(); wake_up(&wdog_dd->pet_complete); } +static void qcom_wdt_user_pet_bite(struct timer_list *t) +{ + struct msm_watchdog_data *wdog_dd = + from_timer(wdog_dd, t, user_pet_timer); + if (!wdog_dd->user_pet_complete) { + dev_info(wdog_dd->dev, "QCOM Apps Watchdog user pet timeout!\n"); + qcom_wdt_trigger_bite(); + } +} static __ref int qcom_wdt_kthread(void *arg) { @@ -690,6 +716,8 @@ int qcom_wdt_remove(struct platform_device *pdev) irq_dispose_mapping(wdog_dd->bark_irq); dev_info(wdog_dd->dev, "QCOM Apps Watchdog Exit - Deactivated\n"); del_timer_sync(&wdog_dd->pet_timer); + if (wdog_dd->user_pet_enabled) + del_timer_sync(&wdog_dd->user_pet_timer); wdog_dd->timer_expired = true; wdog_dd->user_pet_complete = true; kthread_stop(wdog_dd->watchdog_task); @@ -833,6 +861,7 @@ static int qcom_wdt_init(struct msm_watchdog_data *wdog_dd, timer_setup(&wdog_dd->pet_timer, qcom_wdt_pet_task_wakeup, 0); wdog_dd->pet_timer.expires = jiffies + delay_time; add_timer(&wdog_dd->pet_timer); + timer_setup(&wdog_dd->user_pet_timer, qcom_wdt_user_pet_bite, 0); val = BIT(EN); if (wdog_dd->wakeup_irq_enable) val |= BIT(UNMASKED_INT_EN); diff --git a/include/soc/qcom/watchdog.h b/include/soc/qcom/watchdog.h index cf2548fb9a18..64840dd4a681 100644 --- a/include/soc/qcom/watchdog.h +++ b/include/soc/qcom/watchdog.h @@ -151,6 +151,7 @@ struct msm_watchdog_data { struct qcom_irq_info ipi_counts[WDOG_NR_IPI]; unsigned int tot_irq_count[NR_CPUS]; atomic_t irq_counts_running; + struct timer_list user_pet_timer; }; extern void qcom_wdt_trigger_bite(void);