NMI watchdog fixes / enhancements
cover NMI watchdog fixes / enhancements
This is basically a repost of the NNI watchdog series I sent out a few weeks ago. I just rebased things over latest trunk and fixed some warnings.
All patches are also available atgit://git.kiszka.org/xenomai.git nmi-wd-queue
Jan
PATCH 1/3 Update NMI watchdog for latest Intel CPUs
Add performance-counter NMI watchdog support for recent Intel CPUs. This should also fix potential overrun (corner) cases for P6-type CPUs as the current code incorrectly assumes that more than 31 bits are available as watchdog delay counter.
Refactor some dispatching paths at this chance.
---
include/asm-x86/bits/timer.h | 2 +- ksrc/arch/x86/nmi_32.c | 128 ++++++++++++++++++++++++++---------------- 2 files changed, 81 insertions(+), 49 deletions(-)
include/asm-x86/bits/timer.h +1 -1
@@ -37,7 +37,7 @@ static inline void xnarch_program_timer_shot(unsigned long delay)#ifdef CONFIG_XENO_HW_NMI_DEBUG_LATENCY {extern unsigned long rthal_maxlat_tsc; -if (delay <= (ULONG_MAX - rthal_maxlat_tsc)) +if (delay <= (LONG_MAX - rthal_maxlat_tsc))rthal_nmi_arm (delay + rthal_maxlat_tsc); }#endif /* CONFIG_XENO_HW_NMI_DEBUG_LATENCY */
ksrc/arch/x86/nmi_32.c +80 -48
233 lines not on this page · raw message
PATCH 2/3 NMI watchdog support for x86-64
In reply to Jan KiszkaNo need to lock the NMI away from x86-64 boxes, it just takes a bit refactoring.
NOTE: Whoever applies this to SVN, make sure to MOVE nmi_32.c to nmi.c!
---
include/asm-x86/hal.h | 2 +
include/asm-x86/hal_32.h | 2 -
ksrc/arch/x86/Kconfig | 4 ---
ksrc/arch/x86/Makefile | 4 +-
ksrc/arch/x86/hal-common.c | 49 +++++++++++++++++++++++++++++++++++++
ksrc/arch/x86/hal_32.c | 45 ----------------------------------
ksrc/arch/x86/{nmi_32.c => nmi.c} | 0
7 files changed, 53 insertions(+), 53 deletions(-)
rename ksrc/arch/x86/{nmi_32.c => nmi.c} (100%)include/asm-x86/hal.h +2 -0
@@ -69,6 +69,8 @@ typedef int (*compat_emutick_t)(unsigned long evt,extern enum rthal_ktimer_mode rthal_ktimer_saved_mode; +void rthal_latency_above_max (struct pt_regs *regs); +#ifdef __i386__#include "hal_32.h" #else
include/asm-x86/hal_32.h +0 -2
@@ -234,6 +234,4 @@ static inline void rthal_setup_oneshot_apic(int vector)long rthal_strncpy_from_user (char *dst,const char __user * src,long count); -void rthal_latency_above_max (struct pt_regs *regs); -#endif /* !_XENO_ASM_X86_HAL_32_H */
ksrc/arch/x86/Kconfig +0 -4
@@ -27,8 +27,6 @@ config XENO_HW_FPU Float-Point Unit on the x86 platform at the following URL: http://www.intel.com/design/intarch/techinfo/Pentium/fpu.htm -if !X86_64 - menu "NMI watchdog" config XENO_HW_NMI_DEBUG_LATENCY
@@ -59,8 +57,6 @@ config XENO_HW_NMI_DEBUG_LATENCY_MAX endmenu -endif - menu "SMI workaround" config XENO_HW_SMI_DETECT_DISABLE
ksrc/arch/x86/Makefile +2 -2
@@ -12,7 +12,7 @@ obj-$(CONFIG_XENOMAI) += xeno_hal.o xeno_hal-y := hal_$(X86_MODE).o hal-common.o usercopy_$(X86_MODE).o -xeno_hal-$(CONFIG_XENO_HW_NMI_DEBUG_LATENCY) += nmi_$(X86_MODE).o +xeno_hal-$(CONFIG_XENO_HW_NMI_DEBUG_LATENCY) += nmi.o xeno_hal-$(CONFIG_XENO_HW_SMI_DETECT) += smi.o
@@ -28,7 +28,7 @@ O_TARGET := built-in.o obj-y := hal_32.o hal-common.o -obj-$(CONFIG_XENO_HW_NMI_DEBUG_LATENCY) += nmi_32.o +obj-$(CONFIG_XENO_HW_NMI_DEBUG_LATENCY) += nmi.o obj-$(CONFIG_XENO_HW_SMI_DETECT) += smi.o
ksrc/arch/x86/hal-common.c +49 -0
55 lines not on this page · raw message
ksrc/arch/x86/hal_32.c +0 -45
51 lines not on this page · raw message
ksrc/arch/x86/nmi.c renamed from ksrc/arch/x86/nmi_32.c +0 -0
PATCH 3/3 Rework x86 NMI watchdog pass-through
In reply to Jan KiszkaCurrently, Xenomai's NMI watchdog handler assumes to be called only on watchdog events. Other reasons are considered spurious, and a TSC-based method is used to detect such conditions. This has several issues
- the return code of the Linux handler is ignored
- KGDB's NMI events (CPU roundups) are not passed through
- early_shot mechanism suffers from a signedness bug and misses too early shots
- printk from NMI can cause lock-ups, but we also support non-fatal reports (ipipe tracer active)
This patch therefore switches to the watchdog detection pattern that Linux uses: Check for the highest perfctr bit being zero for true timeouts. In case the watchdog did not time out, the Linux handler is invoked and its return code is properly forwarded. Finally, the early_shot reporting is dropped as it becomes pointless when KGDB is in use (and I suspect that patch 1 of this series fixes most of the original reasons).
---
ksrc/arch/x86/nmi.c | 95 ++++++++++++++++++++++---------------------------- 1 files changed, 42 insertions(+), 53 deletions(-)
ksrc/arch/x86/nmi.c +42 -53
@@ -65,13 +65,11 @@typedef union {struct {/* Xenomai watchdog data. */ -unsigned int flags; -unsigned long perfctr_msr;unsigned long long next_linux_check; +unsigned long perfctr_msr; +u64 perfctr_checkmask;unsigned int p4_cccr_val; - -unsigned early_shots; -unsigned long long tick_date; +unsigned int flags; };char __pad[SMP_CACHE_BYTES ]; }rthal_nmi_wd_t ____cacheline_aligned ;
@@ -82,6 +80,15 @@ static void (*rthal_nmi_emergency) (struct pt_regs *);#if LINUX_VERSION_CODE <KERNEL_VERSION (2 ,6 ,19 )#define MSR_ARCH_PERFMON_PERFCTR0 0xc1#define MSR_ARCH_PERFMON_PERFCTR1 0xc2 +union cpuid10_eax { +struct { +unsigned int version_id:8 ; +unsigned int num_counters:8 ; +unsigned int bit_width:8 ; +unsigned int mask_length:8 ; + } split; +unsigned int full; +};static void (*rthal_linux_nmi_tick) (struct pt_regs *);#if LINUX_VERSION_CODE <KERNEL_VERSION (2 ,6 ,0 )
@@ -105,28 +112,28 @@ static int (*rthal_linux_nmi_tick) (struct pt_regs *, unsigned);#endif /* Linux >= 2.6.19 */ #if LINUX_VERSION_CODE <KERNEL_VERSION (2 ,6 ,19 ) -#define CALL_LINUX_NMI rthal_linux_nmi_tick(regs) -#define NMI_RETURN return +#define CALL_LINUX_NMI ({ rthal_linux_nmi_tick(regs); 1; }) +#define NMI_RETURN (code) return static void rthal_nmi_watchdog_tick(struct pt_regs *regs)#else /* Linux >= 2.6.19 */ #define CALL_LINUX_NMI rthal_linux_nmi_tick(regs, reason) -#define NMI_RETURN return 1 +#define NMI_RETURN (code) return (code) static int rthal_nmi_watchdog_tick(struct pt_regs *regs, unsigned reason)#endif /* Linux >= 2.6.19 */ {int cpu =rthal_processor_id ();rthal_nmi_wd_t *wd = &rthal_nmi_wds[cpu];unsigned long long now; +u64 perfctr; -if (wd->flags &NMI_WD_ARMED ) { -if (rthal_rdtsc () - wd->tick_date < rthal_maxlat_tsc) { - ++wd->early_shots; - wd->next_linux_check = wd->tick_date + rthal_maxlat_tsc; - }else { -printk ("NMI early shots: %d\n" , wd->early_shots); -rthal_nmi_emergency (regs); - } - } +rdmsrl (wd->perfctr_msr, perfctr); + +if (perfctr & wd->perfctr_checkmask) +/* No watchdog tick, let Linux handle it. */ +NMI_RETURN (CALL_LINUX_NMI ); + +if (wd->flags &NMI_WD_ARMED ) +rthal_nmi_emergency (regs); now =rthal_rdtsc ();
@@ -162,36 +169,14 @@ static int rthal_nmi_watchdog_tick(struct pt_regs *regs, unsigned reason)else wrmsrl (wd->perfctr_msr, now - wd->next_linux_check); -NMI_RETURN ; +NMI_RETURN (1 ); } -#ifdef CONFIG_PROC_FS -static int earlyshots_read_proc (char *page, -char **start, -off_t off,int count,int *eof,void *data) -{ -int i, len =0 ; - -for_each_online_cpu (i) - len +=sprintf (page + len,"CPU#%d: %u\n" , - i, rthal_nmi_wds[i].early_shots); - len -= off; -if (len <= off + count) - *eof =1 ; - *start = page + off; -if (len > count) - len = count; -if (len <0 ) - len =0 ; - -return len; -} -#endif /* CONFIG_PROC_FS */ -int rthal_nmi_request (void (*emergency) (struct pt_regs *)) {unsigned long long next_linux_check;unsigned long perfctr_msr; +u64 perfctr_checkmask;unsigned int wd_flags =0 ;unsigned int p4_cccr_val =0 ;int i;
@@ -205,23 +190,30 @@ int rthal_nmi_request(void (*emergency) (struct pt_regs *))switch (boot_cpu_data.x86_vendor) {case X86_VENDOR_AMD : perfctr_msr =MSR_K7_PERFCTR0 ; + perfctr_checkmask =1UL <<47 ;break ;case X86_VENDOR_INTEL :if (cpu_has (&boot_cpu_data,X86_FEATURE_ARCH_PERFMON )) { +union cpuid10_eax eax; +if (boot_cpu_data.x86 ==6 && boot_cpu_data.x86_model ==14 ) perfctr_msr =MSR_ARCH_PERFMON_PERFCTR0 ;else perfctr_msr =MSR_ARCH_PERFMON_PERFCTR1 ; +cpuid (10 , &eax.full, &i, &i, &i); + perfctr_checkmask =1UL << (eax.split.bit_width -1 ); wd_flags =NMI_WD_P6_OR_LATER |NMI_WD_31BITS ; }else switch (boot_cpu_data.x86) {case 6 : perfctr_msr =MSR_P6_PERFCTR0 ; + perfctr_checkmask =1UL <<39 ; wd_flags =NMI_WD_P6_OR_LATER |NMI_WD_31BITS ;break ;case 15 : perfctr_msr =MSR_P4_IQ_COUNTER0 ; + perfctr_checkmask =1UL <<39 ; p4_cccr_val =P4_NMI_IQ_CCCR0 ;#ifdef CONFIG_SMP if (smp_num_siblings ==2 )
@@ -244,6 +236,7 @@ int rthal_nmi_request(void (*emergency) (struct pt_regs *)) wd->flags = wd_flags; wd->perfctr_msr = perfctr_msr; + wd->perfctr_checkmask = perfctr_checkmask; wd->p4_cccr_val = p4_cccr_val; wd->next_linux_check = next_linux_check; }
@@ -252,12 +245,6 @@ int rthal_nmi_request(void (*emergency) (struct pt_regs *))wmb (); nmi_watchdog_tick = &rthal_nmi_watchdog_tick; -#ifdef CONFIG_PROC_FS -rthal_add_proc_leaf ("nmi_early_shots" , - &earlyshots_read_proc, -NULL ,NULL , rthal_proc_root); -#endif /* CONFIG_PROC_FS */ -return 0 ; }
@@ -268,10 +255,6 @@ void rthal_nmi_release(void)if (!rthal_linux_nmi_tick)return ; -#ifdef CONFIG_PROC_FS -remove_proc_entry ("nmi_early_shots" , rthal_proc_root); -#endif /* CONFIG_PROC_FS */ -if (wd->flags &NMI_WD_31BITS )wrmsr (wd->perfctr_msr, (u32)(0 -RTHAL_CPU_FREQ ),0 );else
@@ -296,6 +279,10 @@ void rthal_nmi_arm(unsigned long delay)/* Protect from an interrupt handler calling rthal_nmi_arm. */ rthal_local_irq_save (flags); wd->flags &= ~NMI_WD_ARMED ; +/* +* Our watchdog must be declared unarmed before we triger the +* Linux watchdog NMI, entering rthal_nmi_watchdog_tick. +*/ wmb ();if (wd->flags &NMI_WD_31BITS )wrmsr (wd->perfctr_msr, (u32)-1 ,0 );
@@ -305,12 +292,14 @@ void rthal_nmi_arm(unsigned long delay)rthal_local_irq_restore (flags); } - wd->tick_date =rthal_rdtsc () + (delay - rthal_maxlat_tsc); -wmb ();if (wd->flags &NMI_WD_31BITS )wrmsr (wd->perfctr_msr, (u32)(0 - delay),0 );else wrmsrl (wd->perfctr_msr,0 - delay); +/* +* New perfctr must have been written before we can declare the +* watchdog armed (avoid race with previously programmed value). +*/ wmb (); wd->flags |=NMI_WD_ARMED ; }
Quoted 6 lines · Jan Kiszka
This is basically a repost of the NNI watchdog series I sent out a few weeks ago. I just rebased things over latest trunk and fixed some warnings.
All patches are also available at
git://git.kiszka.org/xenomai.gitnmi-wd-queue
That is a lot of stuff to review. I am afraid it is impossible to review everything, so the only thing we can rely on is testing, hence the next
question: have these patches been tested in every configuration (enabled, disabled, built-in, module, voluntary overrun)?
As for the 32nd bit issue, I am afraid it can not explain the spurious shots observed on some platfomrs (note that I implemented the early shot thing a bit in the dark: I never observed the spurious shots myself), that is because the nmi timer is programmed for durations between 100us and 10ms, which should be far from using the 32nd bit.
Signature · 1 line
Gilles.
Quoted 5 lines · Gilles Chanteperdrix
Quoted 4 lines · Jan Kiszka
This is basically a repost of the NNI watchdog series I sent out a few weeks ago. I just rebased things over latest trunk and fixed some warnings.
Quoted 7 lines
Quoted 2 lines
All patches are also available at
git://git.kiszka.org/xenomai.gitnmi-wd-queueThat is a lot of stuff to review. I am afraid it is impossible to review everything, so the only thing we can rely on is testing, hence the next
question: have these patches been tested in every configuration (enabled, disabled, built-in, module, voluntary overrun)?
In most configurations, but definitely not in all (they are too many).
This is a debugging tool, so first of all the disabled case must not cause harm, and I'm quite sure I haven't changed anything regarding this. Moreover, the enabled case was not working for many recent platforms anymore as we were lacking P6 support. So there shouldn't be much to loose.
Quoted 6 lines
As for the 32nd bit issue, I am afraid it can not explain the spurious shots observed on some platfomrs (note that I implemented the early shot thing a bit in the dark: I never observed the spurious shots myself), that is because the nmi timer is programmed for durations between 100us and 10ms, which should be far from using the 32nd bit.
Yes, the signedness issue that is fixed in patch 1 has likely nothing to do with the spurious invocations. But wherever they may still come from, patch 3 ensures that they are now properly ignored (ie. forwarded to the next handling instance).
Jan
Quoted 13 lines · Jan Kiszka
Quoted 11 lines · Gilles Chanteperdrix
Quoted 6 lines · Jan Kiszka
This is basically a repost of the NNI watchdog series I sent out a few weeks ago. I just rebased things over latest trunk and fixed some warnings.
All patches are also available at
git://git.kiszka.org/xenomai.gitnmi-wd-queueThat is a lot of stuff to review. I am afraid it is impossible to review everything, so the only thing we can rely on is testing, hence the next
question: have these patches been tested in every configuration (enabled, disabled, built-in, module, voluntary overrun)?
Quoted 7 lines
In most configurations, but definitely not in all (they are too many).
This is a debugging tool, so first of all the disabled case must not cause harm, and I'm quite sure I haven't changed anything regarding this. Moreover, the enabled case was not working for many recent platforms anymore as we were lacking P6 support. So there shouldn't be much to loose.
I disagree: the current version compiles in all configurations tested until now, and happened to work when enabled at some point in the past. I find it annoying, to say the least, when I want to test something on trunk, that some previous unrelated commit breaks a configuration because it was not tested. So, please test your patch. The configurations to test are not so numerous: disabled, enabled built-in with an overrun check, enabled in module with an overrun check, repeat for x86_64. That makes 6 configurations, not that much.
Signature · 1 line
Gilles.
Quoted 21 lines · Gilles Chanteperdrix
Quoted 12 lines · Jan Kiszka
Quoted 11 lines · Gilles Chanteperdrix
Quoted 6 lines · Jan Kiszka
This is basically a repost of the NNI watchdog series I sent out a few weeks ago. I just rebased things over latest trunk and fixed some warnings.
All patches are also available at
git://git.kiszka.org/xenomai.gitnmi-wd-queueThat is a lot of stuff to review. I am afraid it is impossible to review everything, so the only thing we can rely on is testing, hence the next
question: have these patches been tested in every configuration (enabled, disabled, built-in, module, voluntary overrun)?Quoted 7 lines
In most configurations, but definitely not in all (they are too many).
This is a debugging tool, so first of all the disabled case must not cause harm, and I'm quite sure I haven't changed anything regarding this. Moreover, the enabled case was not working for many recent platforms anymore as we were lacking P6 support. So there shouldn't be much to loose.
Quoted 8 lines
I disagree: the current version compiles in all configurations tested until now, and happened to work when enabled at some point in the past. I find it annoying, to say the least, when I want to test something on trunk, that some previous unrelated commit breaks a configuration because it was not tested. So, please test your patch. The configurations to test are not so numerous: disabled, enabled built-in with an overrun check, enabled in module with an overrun check, repeat for
x86_64. That makes 6 configurations, not that much.
The trivial ones have been tested, of course. But keep in mind that there are more variables (CPU types , kernel versions, interfering config settings, etc.) that create much more that 6 variants to be built and run.
Jan
Quoted 30 lines · Jan Kiszka
Quoted 20 lines · Gilles Chanteperdrix
Quoted 12 lines · Jan Kiszka
Quoted 11 lines · Gilles Chanteperdrix
Quoted 6 lines · Jan Kiszka
This is basically a repost of the NNI watchdog series I sent out a few weeks ago. I just rebased things over latest trunk and fixed some warnings.
All patches are also available at
git://git.kiszka.org/xenomai.gitnmi-wd-queueThat is a lot of stuff to review. I am afraid it is impossible to review everything, so the only thing we can rely on is testing, hence the next
question: have these patches been tested in every configuration (enabled, disabled, built-in, module, voluntary overrun)?Quoted 7 lines
In most configurations, but definitely not in all (they are too many).
This is a debugging tool, so first of all the disabled case must not cause harm, and I'm quite sure I haven't changed anything regarding this. Moreover, the enabled case was not working for many recent platforms anymore as we were lacking P6 support. So there shouldn't be much to loose.
Quoted 8 lines
I disagree: the current version compiles in all configurations tested until now, and happened to work when enabled at some point in the past. I find it annoying, to say the least, when I want to test something on trunk, that some previous unrelated commit breaks a configuration because it was not tested. So, please test your patch. The configurations to test are not so numerous: disabled, enabled built-in with an overrun check, enabled in module with an overrun check, repeat for
x86_64. That makes 6 configurations, not that much.
Quoted 4 lines
The trivial ones have been tested, of course. But keep in mind that there are more variables (CPU types , kernel versions, interfering config settings, etc.) that create much more that 6 variants to be built and run.
To give an example of untested scenarios: Current trunk does not build against 2.6.27 for x86-32 with NMI watchdog enabled (die_nmi gained another argument doe to unification with x86-64). Well, my patch does not change this picture yet (I once tested against 2.6.26 for 32-bit support). Will fix this as well.
Jan