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