2010-02-05 21:47:04 -05:00
/*
* HW NMI watchdog support
*
* started by Don Zickus , Copyright ( C ) 2010 Red Hat , Inc .
*
* Arch specific calls to support NMI watchdog
*
* Bits copied from original nmi . c file
*
*/
2010-05-13 09:12:39 +02:00
# include <asm/apic.h>
2010-02-05 21:47:04 -05:00
# include <linux/cpumask.h>
2010-05-07 17:11:48 -04:00
# include <linux/kdebug.h>
# include <linux/notifier.h>
# include <linux/kprobes.h>
2010-02-05 21:47:04 -05:00
# include <linux/nmi.h>
# include <linux/module.h>
/* For reliability, we're prepared to waste bits here. */
static DECLARE_BITMAP ( backtrace_mask , NR_CPUS ) __read_mostly ;
2010-02-12 17:19:19 -05:00
u64 hw_nmi_get_sample_period ( void )
{
2010-05-07 17:11:44 -04:00
return ( u64 ) ( cpu_khz ) * 1000 * 60 ;
2010-02-12 17:19:19 -05:00
}
2010-02-18 21:56:52 -05:00
# ifdef ARCH_HAS_NMI_WATCHDOG
2010-02-05 21:47:04 -05:00
void arch_trigger_all_cpu_backtrace ( void )
{
int i ;
cpumask_copy ( to_cpumask ( backtrace_mask ) , cpu_online_mask ) ;
printk ( KERN_INFO " sending NMI to all CPUs: \n " ) ;
apic - > send_IPI_all ( NMI_VECTOR ) ;
/* Wait for up to 10 seconds for all CPUs to do the backtrace */
for ( i = 0 ; i < 10 * 1000 ; i + + ) {
if ( cpumask_empty ( to_cpumask ( backtrace_mask ) ) )
break ;
mdelay ( 1 ) ;
}
}
2010-05-07 17:11:48 -04:00
static int __kprobes
arch_trigger_all_cpu_backtrace_handler ( struct notifier_block * self ,
unsigned long cmd , void * __args )
{
struct die_args * args = __args ;
struct pt_regs * regs ;
int cpu = smp_processor_id ( ) ;
switch ( cmd ) {
case DIE_NMI :
case DIE_NMI_IPI :
break ;
default :
return NOTIFY_DONE ;
}
regs = args - > regs ;
if ( cpumask_test_cpu ( cpu , to_cpumask ( backtrace_mask ) ) ) {
static arch_spinlock_t lock = __ARCH_SPIN_LOCK_UNLOCKED ;
arch_spin_lock ( & lock ) ;
printk ( KERN_WARNING " NMI backtrace for cpu %d \n " , cpu ) ;
show_regs ( regs ) ;
dump_stack ( ) ;
arch_spin_unlock ( & lock ) ;
cpumask_clear_cpu ( cpu , to_cpumask ( backtrace_mask ) ) ;
return NOTIFY_STOP ;
}
return NOTIFY_DONE ;
}
static __read_mostly struct notifier_block backtrace_notifier = {
. notifier_call = arch_trigger_all_cpu_backtrace_handler ,
. next = NULL ,
. priority = 1
} ;
static int __init register_trigger_all_cpu_backtrace ( void )
{
register_die_notifier ( & backtrace_notifier ) ;
return 0 ;
}
early_initcall ( register_trigger_all_cpu_backtrace ) ;
2010-02-18 21:56:52 -05:00
# endif
2010-02-05 21:47:04 -05:00
/* STUB calls to mimic old nmi_watchdog behaviour */
2010-02-12 17:19:19 -05:00
# if defined(CONFIG_X86_LOCAL_APIC)
2010-02-05 21:47:04 -05:00
unsigned int nmi_watchdog = NMI_NONE ;
EXPORT_SYMBOL ( nmi_watchdog ) ;
2010-02-12 17:19:19 -05:00
void acpi_nmi_enable ( void ) { return ; }
void acpi_nmi_disable ( void ) { return ; }
# endif
2010-02-05 21:47:04 -05:00
atomic_t nmi_active = ATOMIC_INIT ( 0 ) ; /* oprofile uses this */
EXPORT_SYMBOL ( nmi_active ) ;
int unknown_nmi_panic ;
void cpu_nmi_set_wd_enabled ( void ) { return ; }
void stop_apic_nmi_watchdog ( void * unused ) { return ; }
void setup_apic_nmi_watchdog ( void * unused ) { return ; }
int __init check_nmi_watchdog ( void ) { return 0 ; }