Release 4.14 arch/blackfin/kernel/nmi.c
/*
* Blackfin nmi_watchdog Driver
*
* Originally based on bfin_wdt.c
* Copyright 2010-2010 Analog Devices Inc.
* Graff Yang <graf.yang@analog.com>
*
* Enter bugs at http://blackfin.uclinux.org/
*
* Licensed under the GPL-2 or later.
*/
#include <linux/bitops.h>
#include <linux/hardirq.h>
#include <linux/syscore_ops.h>
#include <linux/pm.h>
#include <linux/nmi.h>
#include <linux/smp.h>
#include <linux/timer.h>
#include <linux/sched/debug.h>
#include <asm/blackfin.h>
#include <linux/atomic.h>
#include <asm/cacheflush.h>
#include <asm/bfin_watchdog.h>
#define DRV_NAME "nmi-wdt"
#define NMI_WDT_TIMEOUT 5
/* 5 seconds */
#define NMI_CHECK_TIMEOUT (4 * HZ)
/* 4 seconds in jiffies */
static int nmi_wdt_cpu = 1;
static unsigned int timeout = NMI_WDT_TIMEOUT;
static int nmi_active;
static unsigned short wdoga_ctl;
static unsigned int wdoga_cnt;
static struct corelock_slot saved_corelock;
static atomic_t nmi_touched[NR_CPUS];
static struct timer_list ntimer;
enum {
COREA_ENTER_NMI = 0,
COREA_EXIT_NMI,
COREB_EXIT_NMI,
NMI_EVENT_NR,
};
static unsigned long nmi_event __attribute__ ((__section__(".l2.bss")));
/* we are in nmi, non-atomic bit ops is safe */
static inline void set_nmi_event(int event)
{
__set_bit(event, &nmi_event);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Graf Yang | 18 | 100.00% | 1 | 100.00% |
Total | 18 | 100.00% | 1 | 100.00% |
static inline void wait_nmi_event(int event)
{
while (!test_bit(event, &nmi_event))
barrier();
__clear_bit(event, &nmi_event);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Graf Yang | 32 | 100.00% | 1 | 100.00% |
Total | 32 | 100.00% | 1 | 100.00% |
static inline void send_corea_nmi(void)
{
wdoga_ctl = bfin_read_WDOGA_CTL();
wdoga_cnt = bfin_read_WDOGA_CNT();
bfin_write_WDOGA_CTL(WDEN_DISABLE);
bfin_write_WDOGA_CNT(0);
bfin_write_WDOGA_CTL(WDEN_ENABLE | ICTL_NMI);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Graf Yang | 36 | 100.00% | 1 | 100.00% |
Total | 36 | 100.00% | 1 | 100.00% |
static inline void restore_corea_nmi(void)
{
bfin_write_WDOGA_CTL(WDEN_DISABLE);
bfin_write_WDOGA_CTL(WDOG_EXPIRED | WDEN_DISABLE | ICTL_NONE);
bfin_write_WDOGA_CNT(wdoga_cnt);
bfin_write_WDOGA_CTL(wdoga_ctl);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Graf Yang | 33 | 100.00% | 1 | 100.00% |
Total | 33 | 100.00% | 1 | 100.00% |
static inline void save_corelock(void)
{
saved_corelock = corelock;
corelock.lock = 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Graf Yang | 19 | 100.00% | 1 | 100.00% |
Total | 19 | 100.00% | 1 | 100.00% |
static inline void restore_corelock(void)
{
corelock = saved_corelock;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Graf Yang | 13 | 100.00% | 1 | 100.00% |
Total | 13 | 100.00% | 1 | 100.00% |
static inline void nmi_wdt_keepalive(void)
{
bfin_write_WDOGB_STAT(0);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Graf Yang | 14 | 100.00% | 1 | 100.00% |
Total | 14 | 100.00% | 1 | 100.00% |
static inline void nmi_wdt_stop(void)
{
bfin_write_WDOGB_CTL(WDEN_DISABLE);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Graf Yang | 14 | 100.00% | 1 | 100.00% |
Total | 14 | 100.00% | 1 | 100.00% |
/* before calling this function, you must stop the WDT */
static inline void nmi_wdt_clear(void)
{
/* clear TRO bit, disable event generation */
bfin_write_WDOGB_CTL(WDOG_EXPIRED | WDEN_DISABLE | ICTL_NONE);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Graf Yang | 19 | 100.00% | 1 | 100.00% |
Total | 19 | 100.00% | 1 | 100.00% |
static inline void nmi_wdt_start(void)
{
bfin_write_WDOGB_CTL(WDEN_ENABLE | ICTL_NMI);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Graf Yang | 16 | 100.00% | 1 | 100.00% |
Total | 16 | 100.00% | 1 | 100.00% |
static inline int nmi_wdt_running(void)
{
return ((bfin_read_WDOGB_CTL() & WDEN_MASK) != WDEN_DISABLE);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Graf Yang | 21 | 100.00% | 1 | 100.00% |
Total | 21 | 100.00% | 1 | 100.00% |
static inline int nmi_wdt_set_timeout(unsigned long t)
{
u32 cnt, max_t, sclk;
int run;
sclk = get_sclk();
max_t = -1 / sclk;
cnt = t * sclk;
if (t > max_t) {
pr_warning("NMI: timeout value is too large\n");
return -EINVAL;
}
run = nmi_wdt_running();
nmi_wdt_stop();
bfin_write_WDOGB_CNT(cnt);
if (run)
nmi_wdt_start();
timeout = t;
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Graf Yang | 83 | 100.00% | 1 | 100.00% |
Total | 83 | 100.00% | 1 | 100.00% |
int check_nmi_wdt_touched(void)
{
unsigned int this_cpu = smp_processor_id();
unsigned int cpu;
cpumask_t mask;
cpumask_copy(&mask, cpu_online_mask);
if (!atomic_read(&nmi_touched[this_cpu]))
return 0;
atomic_set(&nmi_touched[this_cpu], 0);
cpumask_clear_cpu(this_cpu, &mask);
for_each_cpu(cpu, &mask) {
invalidate_dcache_range((unsigned long)(&nmi_touched[cpu]),
(unsigned long)(&nmi_touched[cpu]));
if (!atomic_read(&nmi_touched[cpu]))
return 0;
atomic_set(&nmi_touched[cpu], 0);
}
return 1;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Graf Yang | 115 | 90.55% | 1 | 50.00% |
Motohiro Kosaki | 12 | 9.45% | 1 | 50.00% |
Total | 127 | 100.00% | 2 | 100.00% |
static void nmi_wdt_timer(unsigned long data)
{
if (check_nmi_wdt_touched())
nmi_wdt_keepalive();
mod_timer(&ntimer, jiffies + NMI_CHECK_TIMEOUT);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Graf Yang | 28 | 100.00% | 1 | 100.00% |
Total | 28 | 100.00% | 1 | 100.00% |
static int __init init_nmi_wdt(void)
{
nmi_wdt_set_timeout(timeout);
nmi_wdt_start();
nmi_active = true;
init_timer(&ntimer);
ntimer.function = nmi_wdt_timer;
ntimer.expires = jiffies + NMI_CHECK_TIMEOUT;
add_timer(&ntimer);
pr_info("nmi_wdt: initialized: timeout=%d sec\n", timeout);
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Graf Yang | 57 | 100.00% | 1 | 100.00% |
Total | 57 | 100.00% | 1 | 100.00% |
device_initcall(init_nmi_wdt);
void arch_touch_nmi_watchdog(void)
{
atomic_set(&nmi_touched[smp_processor_id()], 1);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Graf Yang | 18 | 94.74% | 1 | 50.00% |
Nicholas Piggin | 1 | 5.26% | 1 | 50.00% |
Total | 19 | 100.00% | 2 | 100.00% |
/* Suspend/resume support */
#ifdef CONFIG_PM
static int nmi_wdt_suspend(void)
{
nmi_wdt_stop();
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Graf Yang | 13 | 92.86% | 1 | 50.00% |
Rafael J. Wysocki | 1 | 7.14% | 1 | 50.00% |
Total | 14 | 100.00% | 2 | 100.00% |
static void nmi_wdt_resume(void)
{
if (nmi_active)
nmi_wdt_start();
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Graf Yang | 13 | 86.67% | 1 | 50.00% |
Rafael J. Wysocki | 2 | 13.33% | 1 | 50.00% |
Total | 15 | 100.00% | 2 | 100.00% |
static struct syscore_ops nmi_syscore_ops = {
.resume = nmi_wdt_resume,
.suspend = nmi_wdt_suspend,
};
static int __init init_nmi_wdt_syscore(void)
{
if (nmi_active)
register_syscore_ops(&nmi_syscore_ops);
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Graf Yang | 18 | 81.82% | 1 | 50.00% |
Rafael J. Wysocki | 4 | 18.18% | 1 | 50.00% |
Total | 22 | 100.00% | 2 | 100.00% |
late_initcall(init_nmi_wdt_syscore);
#endif /* CONFIG_PM */
asmlinkage notrace void do_nmi(struct pt_regs *fp)
{
unsigned int cpu = smp_processor_id();
nmi_enter();
cpu_pda[cpu].__nmi_count += 1;
if (cpu == nmi_wdt_cpu) {
/* CoreB goes here first */
/* reload the WDOG_STAT */
nmi_wdt_keepalive();
/* clear nmi interrupt for CoreB */
nmi_wdt_stop();
nmi_wdt_clear();
/* trigger NMI interrupt of CoreA */
send_corea_nmi();
/* waiting CoreB to enter NMI */
wait_nmi_event(COREA_ENTER_NMI);
/* recover WDOGA's settings */
restore_corea_nmi();
save_corelock();
/* corelock is save/cleared, CoreA is dummping messages */
wait_nmi_event(COREA_EXIT_NMI);
} else {
/* OK, CoreA entered NMI */
set_nmi_event(COREA_ENTER_NMI);
}
pr_emerg("\nNMI Watchdog detected LOCKUP, dump for CPU %d\n", cpu);
dump_bfin_process(fp);
dump_bfin_mem(fp);
show_regs(fp);
dump_bfin_trace_buffer();
show_stack(current, (unsigned long *)fp);
if (cpu == nmi_wdt_cpu) {
pr_emerg("This fault is not recoverable, sorry!\n");
/* CoreA dump finished, restore the corelock */
restore_corelock();
set_nmi_event(COREB_EXIT_NMI);
} else {
/* CoreB dump finished, notice the CoreA we are done */
set_nmi_event(COREA_EXIT_NMI);
/* synchronize with CoreA */
wait_nmi_event(COREB_EXIT_NMI);
}
nmi_exit();
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Graf Yang | 160 | 100.00% | 1 | 100.00% |
Total | 160 | 100.00% | 1 | 100.00% |
Overall Contributors
Person | Tokens | Prop | Commits | CommitProp |
Graf Yang | 890 | 96.95% | 2 | 28.57% |
Motohiro Kosaki | 12 | 1.31% | 1 | 14.29% |
Rafael J. Wysocki | 11 | 1.20% | 1 | 14.29% |
Ingo Molnar | 3 | 0.33% | 1 | 14.29% |
Nicholas Piggin | 1 | 0.11% | 1 | 14.29% |
Arun Sharma | 1 | 0.11% | 1 | 14.29% |
Total | 918 | 100.00% | 7 | 100.00% |
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.