soc: qcom: watchdog_v2: Increase timeout for forced bites (again)
The amount of time we wait for a reset following an attempted forced watchdog bite was recently increased from 1ms to 2s. As it turns out, this is not enough when certain debug features (ex. cache dumping are enabled) as the secure software executing in EL3 may take close to 10 seconds to complete collection of dumps. Therefore, increase the wait to 10s. Change-Id: I98ae1bfa49eb236ca56b91dadb6c3a78ee962a74 Signed-off-by: Matt Wagantall <mattw@codeaurora.org>
This commit is contained in:
parent
5acff0a6d4
commit
ad0aa4184e
1 changed files with 54 additions and 67 deletions
|
@ -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>
|
||||
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue