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