xref: /minix/minix/kernel/watchdog.c (revision 2a404668)
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 
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 
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 
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 
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