Index: arch/i386/conf/GENERIC.MPACPI
===================================================================
RCS file: /cvsroot/src/sys/arch/i386/conf/GENERIC.MPACPI,v
retrieving revision 1.48
diff -d -p -u -r1.48 GENERIC.MPACPI
--- arch/i386/conf/GENERIC.MPACPI	7 Oct 2005 15:59:49 -0000	1.48
+++ arch/i386/conf/GENERIC.MPACPI	4 Dec 2005 11:19:49 -0000
@@ -290,6 +290,7 @@ ioapic* at mainbus?
 options 	MPACPI		# configure CPUs and APICs using ACPI
 				# (acpi at mainbus must also be enabled)
 #options 	MPACPI_SCANPCI	# find PCI roots using MPACPI
+options 	LAPIC_TIMER_IS_BUGGERED	# enable if kernel can't keep time
 
 acpi0 		at mainbus0
 
Index: arch/x86/x86/lapic.c
===================================================================
RCS file: /cvsroot/src/sys/arch/x86/x86/lapic.c,v
retrieving revision 1.12
diff -d -p -u -r1.12 lapic.c
--- arch/x86/x86/lapic.c	29 May 2005 21:36:40 -0000	1.12
+++ arch/x86/x86/lapic.c	4 Dec 2005 11:19:50 -0000
@@ -257,6 +257,85 @@ lapic_clockintr(void *arg, struct intrfr
 #endif
 			cc_microset(ci);
 		}
+#ifdef LAPIC_TIMER_IS_BUGGERED
+		/*
+		 * Some MP systems have been observed to not have a
+		 * stable local APIC timer interrupt.  We count the
+		 * number of TSC cycles since the last call to
+		 * lapic_clockintr(), and if it has been longer than
+		 * expected we add in some extract time for hardclock()
+		 * to add in when it computes the next value of the
+		 * system "time" variable.  Note that we don't skip
+		 * time backwards - early arrivals to lapic_clockintr()
+		 * have only been observed sporadically, and we'll
+		 * soon catch up.
+		 */
+		if (
+#if defined(MULTIPROCESSOR)
+		    CPU_IS_PRIMARY(ci) &&
+#endif
+		    1) {
+			/* Fix up broken APIC timers here too */
+			uint64_t tsc;
+			int64_t extra_tsc;
+			static uint64_t last_tsc = 0;
+			static uint64_t tsc_per_hz = 0;
+			static int timer_calc_count = 0;
+			static int remaining_tsc = 0;
+			extern int fix_hardware_bugs_us;
+
+			tsc = rdtsc();
+			if (__predict_false(time.tv_sec == 0)) {
+				if (tsc_per_hz == 0)
+					tsc_per_hz = ci->ci_tsc_freq / hz;
+				/* do nothing else to while time settles... */
+			} else if (__predict_false(timer_calc_count <= hz * 60)) {
+				uint64_t total_tsc;
+				static uint64_t start_tsc;
+
+				/*
+				 * For the next 60 seconds after we book, work
+				 * out the lowest elapsed TSC value over a
+				 * second, and use this as the best estimate of
+				 * the CPU frequency.
+				 *
+				 * XXX - is first 60 secs long enough?
+				 */
+				if (timer_calc_count == 0)
+					start_tsc = tsc;
+				else if (timer_calc_count % hz == 0) {
+					total_tsc = tsc - start_tsc;
+					if (total_tsc < ci->ci_tsc_freq) {
+						ci->ci_tsc_freq = total_tsc;
+						tsc_per_hz =
+						    ci->ci_tsc_freq / hz;
+					}
+					start_tsc = tsc;
+				}
+				timer_calc_count++;
+			} else {
+				/* we're initialised */
+				extra_tsc = (tsc - last_tsc) - tsc_per_hz;
+
+				/* Don't go backwards */
+				if (extra_tsc > 0) {
+					/*
+					 * XXX for the divides, use reciprocal
+					 *     multiplies?
+					 */
+					fix_hardware_bugs_us =
+					    extra_tsc * 1000000 /
+					    (ci->ci_tsc_freq);
+					remaining_tsc = extra_tsc -
+					    (fix_hardware_bugs_us *
+					    ci->ci_tsc_freq) / 1000000;
+				} else {
+					fix_hardware_bugs_us = 0;
+				}
+			}
+			last_tsc = tsc;
+		}
+#endif /* LAPIC_TIMER_IS_BUGGERED */
 	}
 #endif
 
Index: kern/kern_clock.c
===================================================================
RCS file: /cvsroot/src/sys/kern/kern_clock.c,v
retrieving revision 1.95
diff -d -p -u -r1.95 kern_clock.c
--- kern/kern_clock.c	12 Sep 2005 16:21:31 -0000	1.95
+++ kern/kern_clock.c	4 Dec 2005 11:19:51 -0000
@@ -341,6 +341,12 @@ int	shifthz;
 #endif
 
 /*
+ * Some hardware may not call hardclock() at a fixeded interval and may
+ * provide an external adjustment to help with timekeeping.
+ */
+int fix_hardware_bugs_us = 0;
+
+/*
  * We might want ldd to load the both words from time at once.
  * To succeed we need to be quadword aligned.
  * The sparc already does that, and that it has worked so far is a fluke.
@@ -519,6 +525,7 @@ hardclock(struct clockframe *frame)
 	 */
 	hardclock_ticks++;
 	delta = tick;
+	delta += fix_hardware_bugs_us;
 
 #ifndef NTP
 	if (tickfix) {
