[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: Dan Hecht <dhecht@vmware.com>
Signed-off-by: Zachary Amsden <zach@vmware.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
diff --git a/arch/i386/kernel/vmi.c b/arch/i386/kernel/vmi.c
index bb5a7ab..8417f74 100644
--- a/arch/i386/kernel/vmi.c
+++ b/arch/i386/kernel/vmi.c
@@ -54,6 +54,7 @@
 static int disable_sep;
 static int disable_tsc;
 static int disable_mtrr;
+static int disable_noidle;
 
 /* Cached VMI operations */
 struct {
@@ -255,7 +256,6 @@
 }
 
 /* For NO_IDLE_HZ, we stop the clock when halting the kernel */
-#ifdef CONFIG_NO_IDLE_HZ
 static fastcall void vmi_safe_halt(void)
 {
 	int idle = vmi_stop_hz_timer();
@@ -266,7 +266,6 @@
 		local_irq_enable();
 	}
 }
-#endif
 
 #ifdef CONFIG_DEBUG_PAGE_TYPE
 
@@ -742,12 +741,7 @@
 		     (char *)paravirt_ops.save_fl);
 	patch_offset(&irq_save_disable_callout[IRQ_PATCH_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);
 	/* paravirt_ops.read_msr = vmi_rdmsr */
 	/* paravirt_ops.write_msr = vmi_wrmsr */
@@ -881,6 +875,12 @@
 #endif
 		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
@@ -914,9 +914,11 @@
 
 	local_irq_save(flags);
 	activate_vmi();
-#ifdef CONFIG_SMP
+
+#ifdef CONFIG_X86_IO_APIC
 	no_timer_check = 1;
 #endif
+
 	local_irq_restore(flags & X86_EFLAGS_IF);
 }
 
@@ -942,7 +944,8 @@
 	} else if (!strcmp(arg, "disable_mtrr")) {
 		clear_bit(X86_FEATURE_MTRR, boot_cpu_data.x86_capability);
 		disable_mtrr = 1;
-	}
+	} else if (!strcmp(arg, "disable_noidle"))
+		disable_noidle = 1;
 	return 0;
 }