Skip to content

Commit

Permalink
soc: qcom: Also dump watchdog data in bite cases
Browse files Browse the repository at this point in the history
Add a pet observer, set to expire every 13 seconds, to dump watchdog
data in case the bark irq cannot be received by the kernel. Here
are the current watchdog-related timers and their expiring times:

Timer        Expires   What it does
--------------------------------------------------------------
Pet:       9 seconds   Pets the watchdog, resetting all timers
Bark:     11 seconds   Sends IRQ to kernel to reset system
Observer: 13 seconds   Print watchdog data and wait for bite
Bite:     14 seconds   Sends FIQ to TZ to reset system

Pet observer design was based on:
commit 035a444803c1 ("soc: watchdog: Dump debugging info. before timeout")
from android-msm-bluecross-4.9.

Bug: 127696088
Change-Id: I915015e4983c73f61f3dc03c62b844c7157b1eac
Signed-off-by: Jonglin Lee <[email protected]>
  • Loading branch information
Jonglin Lee authored and dereference23 committed Jun 18, 2023
1 parent 16382e9 commit 4f51750
Showing 1 changed file with 67 additions and 15 deletions.
82 changes: 67 additions & 15 deletions drivers/soc/qcom/watchdog_v2.c
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ struct msm_watchdog_data {

struct task_struct *watchdog_task;
struct timer_list pet_timer;
struct timer_list pet_observer;
wait_queue_head_t pet_complete;

bool timer_expired;
Expand Down Expand Up @@ -228,6 +229,7 @@ static void wdog_disable(struct msm_watchdog_data *wdog_dd)
smp_mb();
atomic_notifier_chain_unregister(&panic_notifier_list,
&wdog_dd->panic_blk);
del_timer_sync(&wdog_dd->pet_observer);
del_timer_sync(&wdog_dd->pet_timer);
/* may be suspended after the first write above */
__raw_writel(0, wdog_dd->base + WDT0_EN);
Expand Down Expand Up @@ -357,12 +359,9 @@ static ssize_t wdog_pet_time_get(struct device *dev,

static DEVICE_ATTR(pet_time, 0400, wdog_pet_time_get, NULL);

static void pet_watchdog(struct msm_watchdog_data *wdog_dd)
static int get_wdog_sts(struct msm_watchdog_data *wdog_dd)
{
int slack, i, count, prev_count = 0;
unsigned long long time_ns;
unsigned long long slack_ns;
unsigned long long bark_time_ns = wdog_dd->bark_time * 1000000ULL;
int i, count, prev_count = 0;

for (i = 0; i < 2; i++) {
count = (__raw_readl(wdog_dd->base + WDT0_STS) >> 1) & 0xFFFFF;
Expand All @@ -371,6 +370,18 @@ static void pet_watchdog(struct msm_watchdog_data *wdog_dd)
i = 0;
}
}

return count;
}

static void pet_watchdog(struct msm_watchdog_data *wdog_dd)
{
int slack, count;
unsigned long long time_ns;
unsigned long long slack_ns;
unsigned long long bark_time_ns = wdog_dd->bark_time * 1000000ULL;

count = get_wdog_sts(wdog_dd);
slack = ((wdog_dd->bark_time * WDT_HZ) / 1000) - count;
if (slack < wdog_dd->min_slack_ticks)
wdog_dd->min_slack_ticks = slack;
Expand Down Expand Up @@ -413,6 +424,30 @@ static void ping_other_cpus(struct msm_watchdog_data *wdog_dd)
}
}

/* Set pet observer to expire 1 second before watchdog bite */
#define PET_OBSERVER_OFFSET_SECS (WDOG_BITE_OFFSET_IN_SECONDS - 1)

static void print_wdog_data(struct msm_watchdog_data *wdog_dd);

static void pet_observer_fn(unsigned long data)
{
struct msm_watchdog_data *wdog_dd =
(struct msm_watchdog_data *)data;
int wdog_counter = get_wdog_sts(wdog_dd) / WDT_HZ;
int observer_threshold = ((wdog_dd->bark_time / 1000) +
PET_OBSERVER_OFFSET_SECS);

if (wdog_counter < observer_threshold)
mod_timer(&wdog_dd->pet_observer, jiffies + msecs_to_jiffies(
(observer_threshold - wdog_counter) * 1000));
else {
pr_warn("MSM watchdog blocked for %d seconds\n", wdog_counter);
pr_warn("Print watchdog data:\n");
print_wdog_data(wdog_dd);
pr_warn("Watchdog will bite in 1 second.\n");
}
}

static void pet_task_wakeup(unsigned long data)
{
struct msm_watchdog_data *wdog_dd =
Expand Down Expand Up @@ -505,6 +540,7 @@ static int msm_watchdog_remove(struct platform_device *pdev)
if (wdog_dd->irq_ppi)
free_percpu(wdog_dd->wdog_cpu_dd);
dev_info(wdog_dd->dev, "MSM Watchdog Exit - Deactivated\n");
del_timer_sync(&wdog_dd->pet_observer);
del_timer_sync(&wdog_dd->pet_timer);
kthread_stop(wdog_dd->watchdog_task);
kfree(wdog_dd);
Expand All @@ -531,22 +567,18 @@ void msm_trigger_wdog_bite(void)
__raw_readl(wdog_data->base + WDT0_BITE_TIME));
}

static irqreturn_t wdog_bark_handler(int irq, void *dev_id)
static void print_wdog_data(struct msm_watchdog_data *wdog_dd)
{
struct msm_watchdog_data *wdog_dd = (struct msm_watchdog_data *)dev_id;
unsigned long long last_pet;
unsigned long nanosec_rem;
unsigned long long t = sched_clock();
struct task_struct *wdog_task;
int cpu;
struct cpumask *bark_affinity;

nanosec_rem = do_div(t, 1000000000);
dev_info(wdog_dd->dev, "Watchdog bark! Now = %lu.%06lu\n",
(unsigned long) t, nanosec_rem / 1000);

nanosec_rem = do_div(wdog_dd->last_pet, 1000000000);
last_pet = wdog_dd->last_pet;
nanosec_rem = do_div(last_pet, 1000000000);
dev_info(wdog_dd->dev, "Watchdog last pet at %lu.%06lu\n",
(unsigned long) wdog_dd->last_pet, nanosec_rem / 1000);
(unsigned long) last_pet, nanosec_rem / 1000);
if (wdog_dd->do_ipi_ping)
dump_cpu_alive_mask(wdog_dd);

Expand Down Expand Up @@ -591,7 +623,20 @@ static irqreturn_t wdog_bark_handler(int irq, void *dev_id)
/* Print watchdog bark IRQ affinity mask */
bark_affinity = irq_get_affinity_mask(wdog_dd->bark_irq);
dev_info(wdog_dd->dev, "Watchdog bark IRQ %d CPU affinity: %*pbl\n",
irq, cpumask_pr_args(bark_affinity));
wdog_dd->bark_irq, cpumask_pr_args(bark_affinity));
}

static irqreturn_t wdog_bark_handler(int irq, void *dev_id)
{
struct msm_watchdog_data *wdog_dd = (struct msm_watchdog_data *)dev_id;
unsigned long nanosec_rem;
unsigned long long t = sched_clock();

nanosec_rem = do_div(t, 1000000000);
dev_info(wdog_dd->dev, "Watchdog bark! Now = %lu.%06lu\n",
(unsigned long) t, nanosec_rem / 1000);

print_wdog_data(wdog_dd);

msm_trigger_wdog_bite();
panic("Failed to cause a watchdog bite! - Falling back to kernel panic!");
Expand Down Expand Up @@ -831,6 +876,13 @@ static void init_watchdog_data(struct msm_watchdog_data *wdog_dd)
if (!ipi_en)
cpu_pm_register_notifier(&wdog_cpu_pm_nb);
dev_info(wdog_dd->dev, "MSM Watchdog Initialized\n");

init_timer(&wdog_dd->pet_observer);
wdog_dd->pet_observer.data = (unsigned long)wdog_dd;
wdog_dd->pet_observer.function = pet_observer_fn;
wdog_dd->pet_observer.expires = msecs_to_jiffies(wdog_dd->bark_time +
PET_OBSERVER_OFFSET_SECS);
add_timer(&wdog_dd->pet_observer);
}

static const struct of_device_id msm_wdog_match_table[] = {
Expand Down

0 comments on commit 4f51750

Please sign in to comment.