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