soc: wdog: Ensure missing user watchdog pet can trigger bite

The user watchdog was waiting the hardware watchdog bite by
stop petting it. But in the cpu suspend scenarios, the auto petting
by hardware prevent the expected watchdog bite. So add a new user pet
timer to explicitly trigger the watchdog bite by software when the user
watchdog petting is not happenned before timeout.

Change-Id: I71b1139192baa960ae00f7a27c630aedaf5a3ffa
Signed-off-by: Maria Yu <aiquny@codeaurora.org>
This commit is contained in:
Maria Yu 2021-05-20 11:17:34 +08:00
parent 618050e287
commit 63e8c7c206
2 changed files with 30 additions and 0 deletions

View File

@ -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);

View File

@ -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);