53 lines
		
	
	
		
			1.4 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			53 lines
		
	
	
		
			1.4 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  * This is arch independent NMI watchdog implementaion part. It is used to
 | |
|  * detect kernel lockups and help debugging. each architecture must add its own
 | |
|  * low level code that triggers periodic checks
 | |
|  */
 | |
| 
 | |
| #include "watchdog.h"
 | |
| 
 | |
| unsigned watchdog_local_timer_ticks = 0U;
 | |
| struct arch_watchdog *watchdog;
 | |
| int watchdog_enabled;
 | |
| 
 | |
| void nmi_watchdog_handler(struct nmi_frame * frame)
 | |
| {
 | |
| 	/* FIXME this should be CPU local */
 | |
| 	static unsigned no_ticks;
 | |
| 	static unsigned last_tick_count = (unsigned) -1;
 | |
| 
 | |
| 	/*
 | |
| 	 * when debugging on serial console, printing takes a lot of time some
 | |
| 	 * times while the kernel is certainly not locked up. We don't want to
 | |
| 	 * report a lockup in such situation
 | |
| 	 */
 | |
| 	if (serial_debug_active)
 | |
| 		goto reset_and_continue;
 | |
| 
 | |
| 	if (last_tick_count != watchdog_local_timer_ticks) {
 | |
| 		if (no_ticks == 1) {
 | |
| 			printf("watchdog : kernel unlocked\n");
 | |
| 			no_ticks = 0;
 | |
| 		}
 | |
| 		/* we are still ticking, everything seems good */
 | |
| 		last_tick_count = watchdog_local_timer_ticks;
 | |
| 		goto reset_and_continue;
 | |
| 	}
 | |
| 
 | |
| 	/*
 | |
| 	 * if watchdog_local_timer_ticks didn't changed since last time, give it
 | |
| 	 * some more time and only if it still dead, trigger the watchdog alarm
 | |
| 	 */
 | |
| 	if (++no_ticks < 10) {
 | |
| 		if (no_ticks == 1)
 | |
| 			printf("WARNING watchdog : possible kernel lockup\n");
 | |
| 		goto reset_and_continue;
 | |
| 	}
 | |
| 
 | |
| 	arch_watchdog_lockup(frame);
 | |
| 
 | |
| reset_and_continue:
 | |
| 	if (watchdog->reinit)
 | |
| 		watchdog->reinit(cpuid);
 | |
| }
 | 
