|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [PATCH] x86: increase NMI timer frequency if necessary
Since the performance counters used for the NMI watchdog count non-
halted cycles, they may count at a rate higher than cpu_khz. Thus the
watchdog tick may occur more frequently than invocations of the timer
if we don't account for the ratio between nominal and maximum CPU clock
speeds, which would be a problem in particular when "watchdog_timeout=1"
is in effect (for high enough ratios even larger timout values may pose
a problem).
Leverage the so far display-only data we collect on newer Intel and AMD
CPUs. On older CPUs we just have to (continue to) hope that the default
frequency of 1 Hz is okay(-ish) to use.
While adding the new variable, also move the (now adjacent) cpu_khz to
.data.ro_after_init.
Signed-off-by: Jan Beulich <jbeulich@xxxxxxxx>
---
This renders the "log" in the function names somewhat stale, but I don't
think this strictly warrants renaming the functions right away.
--- a/xen/arch/x86/cpu/amd.c
+++ b/xen/arch/x86/cpu/amd.c
@@ -657,12 +657,18 @@ void amd_log_freq(const struct cpuinfo_x
: (((v) & 0xff) * 25 * 8) / (((v) >> 8) &
0x3f))
if (idx && idx < h &&
!rdmsr_safe(0xC0010064 + idx, val) && (val >> 63) &&
- !rdmsr_safe(0xC0010064, hi) && (hi >> 63))
+ !rdmsr_safe(0xC0010064, hi) && (hi >> 63)) {
+ if (c == &boot_cpu_data)
+ cpu_max_mhz = FREQ(hi);
printk("CPU%u: %lu (%lu ... %lu) MHz\n",
smp_processor_id(), FREQ(val), FREQ(lo), FREQ(hi));
- else if (h && !rdmsr_safe(0xC0010064, hi) && (hi >> 63))
+ }
+ else if (h && !rdmsr_safe(0xC0010064, hi) && (hi >> 63)) {
+ if (c == &boot_cpu_data)
+ cpu_max_mhz = FREQ(hi);
printk("CPU%u: %lu ... %lu MHz\n",
smp_processor_id(), FREQ(lo), FREQ(hi));
+ }
else
printk("CPU%u: %lu MHz\n", smp_processor_id(), FREQ(lo));
#undef FREQ
--- a/xen/arch/x86/cpu/intel.c
+++ b/xen/arch/x86/cpu/intel.c
@@ -456,7 +456,11 @@ static void intel_log_freq(const struct
if ( eax )
printk(" base: %u MHz", eax);
if ( ebx )
+ {
+ if ( c == &boot_cpu_data )
+ cpu_max_mhz = ebx;
printk(" max: %u MHz", ebx);
+ }
printk("\n");
}
}
@@ -522,6 +526,8 @@ static void intel_log_freq(const struct
printk("CPU%u: ", smp_processor_id());
if ( min_ratio )
printk("%u ... ", (factor * min_ratio + 50) / 100);
+ if ( c == &boot_cpu_data && !cpu_max_mhz )
+ cpu_max_mhz = (factor * max_ratio + 50) / 100;
printk("%u MHz\n", (factor * max_ratio + 50) / 100);
}
--- a/xen/arch/x86/include/asm/time.h
+++ b/xen/arch/x86/include/asm/time.h
@@ -8,6 +8,8 @@ typedef u64 cycles_t;
extern bool disable_tsc_sync;
+extern unsigned int cpu_max_mhz;
+
static inline cycles_t get_cycles(void)
{
return rdtsc_ordered();
--- a/xen/arch/x86/nmi.c
+++ b/xen/arch/x86/nmi.c
@@ -213,10 +213,12 @@ void __init check_nmi_watchdog(void)
return;
}
+static unsigned int __ro_after_init timer_gap = MILLISECS(1000);
+
static void cf_check nmi_timer_fn(void *unused)
{
this_cpu(nmi_timer_ticks)++;
- set_timer(&this_cpu(nmi_timer), NOW() + MILLISECS(1000));
+ set_timer(&this_cpu(nmi_timer), NOW() + timer_gap);
}
void disable_lapic_nmi_watchdog(void)
@@ -477,8 +479,17 @@ bool watchdog_enabled(void)
int __init watchdog_setup(void)
{
+ unsigned long cpu_mhz = cpu_khz / 1000;
unsigned int cpu;
+ if ( cpu_max_mhz > cpu_mhz )
+ {
+ timer_gap = timer_gap * cpu_mhz / cpu_max_mhz;
+ /* To be on the safe side, bound to 1ms. */
+ if ( timer_gap < MILLISECS(1) )
+ timer_gap = MILLISECS(1);
+ }
+
/*
* Activate periodic heartbeats. We cannot do this earlier during
* setup because the timer infrastructure is not available.
--- a/xen/arch/x86/time.c
+++ b/xen/arch/x86/time.c
@@ -47,7 +47,9 @@
static char __initdata opt_clocksource[10];
string_param("clocksource", opt_clocksource);
-unsigned long __read_mostly cpu_khz; /* CPU clock frequency in kHz. */
+unsigned long __ro_after_init cpu_khz; /* CPU clock frequency in kHz. */
+unsigned int __ro_after_init cpu_max_mhz; /* CPU max (known) clkfreq in MHz. */
+
DEFINE_SPINLOCK(rtc_lock);
unsigned long pit0_ticks;
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |