2016-12-14 15:06:24 -08:00
/*
* Detect hard lockups on a system
*
* started by Don Zickus , Copyright ( C ) 2010 Red Hat , Inc .
*
* Note : Most of this code is borrowed heavily from the original softlockup
* detector , so thanks to Ingo for the initial implementation .
* Some chunks also taken from the old x86 - specific nmi watchdog code , thanks
* to those contributors as well .
*/
# define pr_fmt(fmt) "NMI watchdog: " fmt
# include <linux/nmi.h>
# include <linux/module.h>
2017-02-08 18:51:35 +01:00
# include <linux/sched/debug.h>
2016-12-14 15:06:24 -08:00
# include <asm/irq_regs.h>
# include <linux/perf_event.h>
static DEFINE_PER_CPU ( bool , hard_watchdog_warn ) ;
static DEFINE_PER_CPU ( bool , watchdog_nmi_touch ) ;
static DEFINE_PER_CPU ( struct perf_event * , watchdog_ev ) ;
2017-09-12 21:37:04 +02:00
static struct cpumask dead_events_mask ;
2016-12-14 15:06:24 -08:00
static unsigned long hardlockup_allcpu_dumped ;
2017-09-12 21:37:21 +02:00
static unsigned int watchdog_cpus ;
2016-12-14 15:06:24 -08:00
2017-07-12 14:35:43 -07:00
void arch_touch_nmi_watchdog ( void )
2016-12-14 15:06:24 -08:00
{
/*
* Using __raw here because some code paths have
* preemption enabled . If preemption is enabled
* then interrupts should be enabled too , in which
* case we shouldn ' t have to worry about the watchdog
* going off .
*/
raw_cpu_write ( watchdog_nmi_touch , true ) ;
}
2017-07-12 14:35:43 -07:00
EXPORT_SYMBOL ( arch_touch_nmi_watchdog ) ;
2016-12-14 15:06:24 -08:00
2017-08-15 09:50:13 +02:00
# ifdef CONFIG_HARDLOCKUP_CHECK_TIMESTAMP
static DEFINE_PER_CPU ( ktime_t , last_timestamp ) ;
static DEFINE_PER_CPU ( unsigned int , nmi_rearmed ) ;
static ktime_t watchdog_hrtimer_sample_threshold __read_mostly ;
void watchdog_update_hrtimer_threshold ( u64 period )
{
/*
* The hrtimer runs with a period of ( watchdog_threshold * 2 ) / 5
*
* So it runs effectively with 2.5 times the rate of the NMI
* watchdog . That means the hrtimer should fire 2 - 3 times before
* the NMI watchdog expires . The NMI watchdog on x86 is based on
* unhalted CPU cycles , so if Turbo - Mode is enabled the CPU cycles
* might run way faster than expected and the NMI fires in a
* smaller period than the one deduced from the nominal CPU
* frequency . Depending on the Turbo - Mode factor this might be fast
* enough to get the NMI period smaller than the hrtimer watchdog
* period and trigger false positives .
*
* The sample threshold is used to check in the NMI handler whether
* the minimum time between two NMI samples has elapsed . That
* prevents false positives .
*
* Set this to 4 / 5 of the actual watchdog threshold period so the
* hrtimer is guaranteed to fire at least once within the real
* watchdog threshold .
*/
watchdog_hrtimer_sample_threshold = period * 2 ;
}
static bool watchdog_check_timestamp ( void )
{
ktime_t delta , now = ktime_get_mono_fast_ns ( ) ;
delta = now - __this_cpu_read ( last_timestamp ) ;
if ( delta < watchdog_hrtimer_sample_threshold ) {
/*
* If ktime is jiffies based , a stalled timer would prevent
* jiffies from being incremented and the filter would look
* at a stale timestamp and never trigger .
*/
if ( __this_cpu_inc_return ( nmi_rearmed ) < 10 )
return false ;
}
__this_cpu_write ( nmi_rearmed , 0 ) ;
__this_cpu_write ( last_timestamp , now ) ;
return true ;
}
# else
static inline bool watchdog_check_timestamp ( void )
{
return true ;
}
# endif
2016-12-14 15:06:24 -08:00
static struct perf_event_attr wd_hw_attr = {
. type = PERF_TYPE_HARDWARE ,
. config = PERF_COUNT_HW_CPU_CYCLES ,
. size = sizeof ( struct perf_event_attr ) ,
. pinned = 1 ,
. disabled = 1 ,
} ;
/* Callback function for perf event subsystem */
static void watchdog_overflow_callback ( struct perf_event * event ,
2017-09-12 21:37:05 +02:00
struct perf_sample_data * data ,
struct pt_regs * regs )
2016-12-14 15:06:24 -08:00
{
/* Ensure the watchdog never gets throttled */
event - > hw . interrupts = 0 ;
if ( __this_cpu_read ( watchdog_nmi_touch ) = = true ) {
__this_cpu_write ( watchdog_nmi_touch , false ) ;
return ;
}
2017-08-15 09:50:13 +02:00
if ( ! watchdog_check_timestamp ( ) )
return ;
2016-12-14 15:06:24 -08:00
/* check for a hardlockup
* This is done by making sure our timer interrupt
* is incrementing . The timer interrupt should have
* fired multiple times before we overflow ' d . If it hasn ' t
* then this is a good indication the cpu is stuck
*/
if ( is_hardlockup ( ) ) {
int this_cpu = smp_processor_id ( ) ;
/* only print hardlockups once */
if ( __this_cpu_read ( hard_watchdog_warn ) = = true )
return ;
pr_emerg ( " Watchdog detected hard LOCKUP on cpu %d " , this_cpu ) ;
print_modules ( ) ;
print_irqtrace_events ( current ) ;
if ( regs )
show_regs ( regs ) ;
else
dump_stack ( ) ;
/*
* Perform all - CPU dump only once to avoid multiple hardlockups
* generating interleaving traces
*/
if ( sysctl_hardlockup_all_cpu_backtrace & &
! test_and_set_bit ( 0 , & hardlockup_allcpu_dumped ) )
trigger_allbutself_cpu_backtrace ( ) ;
if ( hardlockup_panic )
nmi_panic ( regs , " Hard LOCKUP " ) ;
__this_cpu_write ( hard_watchdog_warn , true ) ;
return ;
}
__this_cpu_write ( hard_watchdog_warn , false ) ;
return ;
}
2017-09-12 21:37:18 +02:00
static int hardlockup_detector_event_create ( void )
{
unsigned int cpu = smp_processor_id ( ) ;
struct perf_event_attr * wd_attr ;
struct perf_event * evt ;
wd_attr = & wd_hw_attr ;
wd_attr - > sample_period = hw_nmi_get_sample_period ( watchdog_thresh ) ;
/* Try to register using hardware perf events */
evt = perf_event_create_kernel_counter ( wd_attr , cpu , NULL ,
watchdog_overflow_callback , NULL ) ;
if ( IS_ERR ( evt ) ) {
pr_info ( " Perf event create on CPU %d failed with %ld \n " , cpu ,
PTR_ERR ( evt ) ) ;
return PTR_ERR ( evt ) ;
}
this_cpu_write ( watchdog_ev , evt ) ;
return 0 ;
}
2017-09-12 21:37:20 +02:00
/**
* hardlockup_detector_perf_enable - Enable the local event
*/
void hardlockup_detector_perf_enable ( void )
{
if ( hardlockup_detector_event_create ( ) )
return ;
2017-09-12 21:37:21 +02:00
if ( ! watchdog_cpus + + )
pr_info ( " Enabled. Permanently consumes one hw-PMU counter. \n " ) ;
2017-09-12 21:37:20 +02:00
perf_event_enable ( this_cpu_read ( watchdog_ev ) ) ;
}
2017-09-12 21:37:04 +02:00
/**
* hardlockup_detector_perf_disable - Disable the local event
*/
void hardlockup_detector_perf_disable ( void )
2016-12-14 15:06:24 -08:00
{
2017-09-12 21:37:04 +02:00
struct perf_event * event = this_cpu_read ( watchdog_ev ) ;
2016-12-14 15:06:24 -08:00
if ( event ) {
perf_event_disable ( event ) ;
2017-09-12 21:37:04 +02:00
cpumask_set_cpu ( smp_processor_id ( ) , & dead_events_mask ) ;
2017-09-12 21:37:21 +02:00
watchdog_cpus - - ;
2016-12-14 15:06:24 -08:00
}
}
2017-09-12 21:36:55 +02:00
2017-09-12 21:37:04 +02:00
/**
* hardlockup_detector_perf_cleanup - Cleanup disabled events and destroy them
*
* Called from lockup_detector_cleanup ( ) . Serialized by the caller .
*/
void hardlockup_detector_perf_cleanup ( void )
{
int cpu ;
for_each_cpu ( cpu , & dead_events_mask ) {
2017-09-12 21:37:22 +02:00
struct perf_event * event = per_cpu ( watchdog_ev , cpu ) ;
2017-09-12 21:37:04 +02:00
2017-09-25 20:21:54 +02:00
/*
* Required because for_each_cpu ( ) reports unconditionally
* CPU0 as set on UP kernels . Sigh .
*/
if ( event )
perf_event_release_kernel ( event ) ;
2017-09-12 21:37:22 +02:00
per_cpu ( watchdog_ev , cpu ) = NULL ;
2017-09-12 21:37:04 +02:00
}
cpumask_clear ( & dead_events_mask ) ;
}
2017-09-12 21:36:55 +02:00
/**
* hardlockup_detector_perf_stop - Globally stop watchdog events
*
* Special interface for x86 to handle the perf HT bug .
*/
void __init hardlockup_detector_perf_stop ( void )
{
int cpu ;
lockdep_assert_cpus_held ( ) ;
for_each_online_cpu ( cpu ) {
struct perf_event * event = per_cpu ( watchdog_ev , cpu ) ;
if ( event )
perf_event_disable ( event ) ;
}
}
/**
* hardlockup_detector_perf_restart - Globally restart watchdog events
*
* Special interface for x86 to handle the perf HT bug .
*/
void __init hardlockup_detector_perf_restart ( void )
{
int cpu ;
lockdep_assert_cpus_held ( ) ;
if ( ! ( watchdog_enabled & NMI_WATCHDOG_ENABLED ) )
return ;
for_each_online_cpu ( cpu ) {
struct perf_event * event = per_cpu ( watchdog_ev , cpu ) ;
if ( event )
perf_event_enable ( event ) ;
}
}
2017-09-12 21:37:18 +02:00
/**
* hardlockup_detector_perf_init - Probe whether NMI event is available at all
*/
int __init hardlockup_detector_perf_init ( void )
{
int ret = hardlockup_detector_event_create ( ) ;
if ( ret ) {
2017-09-26 10:36:03 +01:00
pr_info ( " Perf NMI watchdog permanently disabled \n " ) ;
2017-09-12 21:37:18 +02:00
} else {
perf_event_release_kernel ( this_cpu_read ( watchdog_ev ) ) ;
this_cpu_write ( watchdog_ev , NULL ) ;
}
return ret ;
}