1 /*
2 * This is arch independent NMI watchdog implementation part. It is used to
3 * detect kernel lockups and help debugging. each architecture must add its own
4 * low level code that triggers periodic checks
5 */
6
7 #include "watchdog.h"
8 #include "arch/i386/glo.h"
9
10 unsigned watchdog_local_timer_ticks = 0U;
11 struct arch_watchdog *watchdog;
12 int watchdog_enabled;
13
lockup_check(struct nmi_frame * frame)14 static void lockup_check(struct nmi_frame * frame)
15 {
16 /* FIXME this should be CPU local */
17 static unsigned no_ticks;
18 static unsigned last_tick_count = (unsigned) -1;
19
20 /*
21 * when debugging on serial console, printing takes a lot of time some
22 * times while the kernel is certainly not locked up. We don't want to
23 * report a lockup in such situation
24 */
25 if (serial_debug_active)
26 return;
27
28 if (last_tick_count != watchdog_local_timer_ticks) {
29 if (no_ticks == 1) {
30 printf("watchdog : kernel unlocked\n");
31 no_ticks = 0;
32 }
33 /* we are still ticking, everything seems good */
34 last_tick_count = watchdog_local_timer_ticks;
35 return;
36 }
37
38 /*
39 * if watchdog_local_timer_ticks didn't changed since last time, give it
40 * some more time and only if it still dead, trigger the watchdog alarm
41 */
42 if (++no_ticks < 10) {
43 if (no_ticks == 1)
44 printf("WARNING watchdog : possible kernel lockup\n");
45 return;
46 }
47
48 /* if we get this far, the kernel is locked up */
49 arch_watchdog_lockup(frame);
50 }
51
nmi_watchdog_handler(struct nmi_frame * frame)52 void nmi_watchdog_handler(struct nmi_frame * frame)
53 {
54 #if SPROFILE
55 /*
56 * Do not check for lockups while profiling, it is extremely likely that
57 * a false positive is detected if the frequency is high
58 */
59 if (watchdog_enabled && !sprofiling)
60 lockup_check(frame);
61 if (sprofiling)
62 nmi_sprofile_handler(frame);
63
64 if ((watchdog_enabled || sprofiling) && watchdog->reinit)
65 watchdog->reinit(cpuid);
66 #else
67 if (watchdog_enabled) {
68 lockup_check(frame);
69 if (watchdog->reinit)
70 watchdog->reinit(cpuid);
71 }
72 #endif
73 }
74
nmi_watchdog_start_profiling(const unsigned freq)75 int nmi_watchdog_start_profiling(const unsigned freq)
76 {
77 int err;
78
79 /* if watchdog hasn't been enabled, we must enable it now */
80 if (!watchdog_enabled) {
81 if (arch_watchdog_init())
82 return ENODEV;
83 }
84
85 if (!watchdog->profile_init) {
86 printf("WARNING NMI watchdog profiling not supported\n");
87 nmi_watchdog_stop_profiling();
88 return ENODEV;
89 }
90
91 err = watchdog->profile_init(freq);
92 if (err != OK)
93 return err;
94
95 watchdog->resetval = watchdog->profile_resetval;
96
97 return OK;
98 }
99
nmi_watchdog_stop_profiling(void)100 void nmi_watchdog_stop_profiling(void)
101 {
102 /*
103 * if we do not rearm the NMI source, we are done, if we want to keep
104 * the watchdog running, we reset is to its normal value
105 */
106
107 if (watchdog)
108 watchdog->resetval = watchdog->watchdog_resetval;
109
110 if (!watchdog_enabled)
111 arch_watchdog_stop();
112 }
113