Commit 7507ba34 authored by Zachary Amsden's avatar Zachary Amsden Committed by Linus Torvalds

[PATCH] vmi: timer fixes round two

Critical bugfixes for the VMI-Timer code.

1) Do not setup a one shot alarm if we are keeping the periodic alarm
   armed.  Additionally, since the periodic alarm can be run at a lower rate
   than HZ, let's fixup the guard to the no-idle-hz mode appropriately.  This
   fixes the bug where the no-idle-hz mode might have a higher interrupt rate
   than the non-idle case.

2) The interrupt handler can no longer adjust xtime due to nested lock
   acquisition.  Drop this.  We don't need to check for wallclock time at
   every tick, it can be done in userspace instead.

3) Add a bypass to disable noidle operation.  This is useful as a last
   minute workaround, or testing measure.

4) The code to skip the IO_APIC timer testing (no_timer_check) should be
   conditional on IO_APIC, not SMP, since UP kernels can have this configured
   in as well.
Signed-off-by: default avatarDan Hecht <dhecht@vmware.com>
Signed-off-by: default avatarZachary Amsden <zach@vmware.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 0dc952dc
...@@ -54,6 +54,7 @@ static int disable_pse; ...@@ -54,6 +54,7 @@ static int disable_pse;
static int disable_sep; static int disable_sep;
static int disable_tsc; static int disable_tsc;
static int disable_mtrr; static int disable_mtrr;
static int disable_noidle;
/* Cached VMI operations */ /* Cached VMI operations */
struct { struct {
...@@ -255,7 +256,6 @@ static void vmi_nop(void) ...@@ -255,7 +256,6 @@ static void vmi_nop(void)
} }
/* For NO_IDLE_HZ, we stop the clock when halting the kernel */ /* For NO_IDLE_HZ, we stop the clock when halting the kernel */
#ifdef CONFIG_NO_IDLE_HZ
static fastcall void vmi_safe_halt(void) static fastcall void vmi_safe_halt(void)
{ {
int idle = vmi_stop_hz_timer(); int idle = vmi_stop_hz_timer();
...@@ -266,7 +266,6 @@ static fastcall void vmi_safe_halt(void) ...@@ -266,7 +266,6 @@ static fastcall void vmi_safe_halt(void)
local_irq_enable(); local_irq_enable();
} }
} }
#endif
#ifdef CONFIG_DEBUG_PAGE_TYPE #ifdef CONFIG_DEBUG_PAGE_TYPE
...@@ -742,12 +741,7 @@ static inline int __init activate_vmi(void) ...@@ -742,12 +741,7 @@ static inline int __init activate_vmi(void)
(char *)paravirt_ops.save_fl); (char *)paravirt_ops.save_fl);
patch_offset(&irq_save_disable_callout[IRQ_PATCH_DISABLE], patch_offset(&irq_save_disable_callout[IRQ_PATCH_DISABLE],
(char *)paravirt_ops.irq_disable); (char *)paravirt_ops.irq_disable);
#ifndef CONFIG_NO_IDLE_HZ
para_fill(safe_halt, Halt);
#else
vmi_ops.halt = vmi_get_function(VMI_CALL_Halt);
paravirt_ops.safe_halt = vmi_safe_halt;
#endif
para_fill(wbinvd, WBINVD); para_fill(wbinvd, WBINVD);
/* paravirt_ops.read_msr = vmi_rdmsr */ /* paravirt_ops.read_msr = vmi_rdmsr */
/* paravirt_ops.write_msr = vmi_wrmsr */ /* paravirt_ops.write_msr = vmi_wrmsr */
...@@ -881,6 +875,12 @@ static inline int __init activate_vmi(void) ...@@ -881,6 +875,12 @@ static inline int __init activate_vmi(void)
#endif #endif
custom_sched_clock = vmi_sched_clock; custom_sched_clock = vmi_sched_clock;
} }
if (!disable_noidle)
para_fill(safe_halt, Halt);
else {
vmi_ops.halt = vmi_get_function(VMI_CALL_Halt);
paravirt_ops.safe_halt = vmi_safe_halt;
}
/* /*
* Alternative instruction rewriting doesn't happen soon enough * Alternative instruction rewriting doesn't happen soon enough
...@@ -914,9 +914,11 @@ void __init vmi_init(void) ...@@ -914,9 +914,11 @@ void __init vmi_init(void)
local_irq_save(flags); local_irq_save(flags);
activate_vmi(); activate_vmi();
#ifdef CONFIG_SMP
#ifdef CONFIG_X86_IO_APIC
no_timer_check = 1; no_timer_check = 1;
#endif #endif
local_irq_restore(flags & X86_EFLAGS_IF); local_irq_restore(flags & X86_EFLAGS_IF);
} }
...@@ -942,7 +944,8 @@ static int __init parse_vmi(char *arg) ...@@ -942,7 +944,8 @@ static int __init parse_vmi(char *arg)
} else if (!strcmp(arg, "disable_mtrr")) { } else if (!strcmp(arg, "disable_mtrr")) {
clear_bit(X86_FEATURE_MTRR, boot_cpu_data.x86_capability); clear_bit(X86_FEATURE_MTRR, boot_cpu_data.x86_capability);
disable_mtrr = 1; disable_mtrr = 1;
} } else if (!strcmp(arg, "disable_noidle"))
disable_noidle = 1;
return 0; return 0;
} }
......
...@@ -276,16 +276,13 @@ static void vmi_account_real_cycles(unsigned long long cur_real_cycles) ...@@ -276,16 +276,13 @@ static void vmi_account_real_cycles(unsigned long long cur_real_cycles)
cycles_not_accounted = cur_real_cycles - real_cycles_accounted_system; cycles_not_accounted = cur_real_cycles - real_cycles_accounted_system;
while (cycles_not_accounted >= cycles_per_jiffy) { while (cycles_not_accounted >= cycles_per_jiffy) {
/* systems wide jiffies and wallclock. */ /* systems wide jiffies. */
do_timer(1); do_timer(1);
cycles_not_accounted -= cycles_per_jiffy; cycles_not_accounted -= cycles_per_jiffy;
real_cycles_accounted_system += cycles_per_jiffy; real_cycles_accounted_system += cycles_per_jiffy;
} }
if (vmi_timer_ops.wallclock_updated())
update_xtime_from_wallclock();
write_sequnlock(&xtime_lock); write_sequnlock(&xtime_lock);
} }
...@@ -380,7 +377,6 @@ int vmi_stop_hz_timer(void) ...@@ -380,7 +377,6 @@ int vmi_stop_hz_timer(void)
unsigned long seq, next; unsigned long seq, next;
unsigned long long real_cycles_expiry; unsigned long long real_cycles_expiry;
int cpu = smp_processor_id(); int cpu = smp_processor_id();
int idle;
BUG_ON(!irqs_disabled()); BUG_ON(!irqs_disabled());
if (sysctl_hz_timer != 0) if (sysctl_hz_timer != 0)
...@@ -388,13 +384,13 @@ int vmi_stop_hz_timer(void) ...@@ -388,13 +384,13 @@ int vmi_stop_hz_timer(void)
cpu_set(cpu, nohz_cpu_mask); cpu_set(cpu, nohz_cpu_mask);
smp_mb(); smp_mb();
if (rcu_needs_cpu(cpu) || local_softirq_pending() || if (rcu_needs_cpu(cpu) || local_softirq_pending() ||
(next = next_timer_interrupt(), time_before_eq(next, jiffies))) { (next = next_timer_interrupt(),
time_before_eq(next, jiffies + HZ/CONFIG_VMI_ALARM_HZ))) {
cpu_clear(cpu, nohz_cpu_mask); cpu_clear(cpu, nohz_cpu_mask);
next = jiffies; return 0;
idle = 0; }
} else
idle = 1;
/* Convert jiffies to the real cycle counter. */ /* Convert jiffies to the real cycle counter. */
do { do {
...@@ -404,17 +400,13 @@ int vmi_stop_hz_timer(void) ...@@ -404,17 +400,13 @@ int vmi_stop_hz_timer(void)
} while (read_seqretry(&xtime_lock, seq)); } while (read_seqretry(&xtime_lock, seq));
/* This cpu is going idle. Disable the periodic alarm. */ /* This cpu is going idle. Disable the periodic alarm. */
if (idle) {
vmi_timer_ops.cancel_alarm(VMI_CYCLES_AVAILABLE); vmi_timer_ops.cancel_alarm(VMI_CYCLES_AVAILABLE);
per_cpu(idle_start_jiffies, cpu) = jiffies; per_cpu(idle_start_jiffies, cpu) = jiffies;
}
/* Set the real time alarm to expire at the next event. */ /* Set the real time alarm to expire at the next event. */
vmi_timer_ops.set_alarm( vmi_timer_ops.set_alarm(
VMI_ALARM_WIRING | VMI_ALARM_IS_ONESHOT | VMI_CYCLES_REAL, VMI_ALARM_WIRING | VMI_ALARM_IS_ONESHOT | VMI_CYCLES_REAL,
real_cycles_expiry, 0); real_cycles_expiry, 0);
return 1;
return idle;
} }
static void vmi_reenable_hz_timer(int cpu) static void vmi_reenable_hz_timer(int cpu)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment