diff -urNp x-ref/arch/x86_64/kernel/apic.c x/arch/x86_64/kernel/apic.c
--- x-ref/arch/x86_64/kernel/apic.c	Thu Sep 26 04:14:10 2002
+++ x/arch/x86_64/kernel/apic.c	Fri Oct  4 05:39:08 2002
@@ -31,6 +31,8 @@
 #include <asm/pgalloc.h>
 #include <asm/timex.h>
 
+extern spinlock_t i8253_lock;
+
 /* Using APIC to generate smp_local_timer_interrupt? */
 int using_apic_timer = 0;
 
@@ -772,14 +774,18 @@ void setup_APIC_timer(void * data)
 		while (hpet_readl(HPET_COUNTER) <  trigger);
 	} else {
 		int c1, c2;
+		spin_lock(&i8253_lock);
 		outb_p(0x00, 0x43);
 		c2 = inb_p(0x40);
 		c2 |= inb_p(0x40) << 8;
+		spin_unlock(&i8253_lock);
 		do {
 			c1 = c2;
+			spin_lock(&i8253_lock);
 			outb_p(0x00, 0x43);
 			c2 = inb_p(0x40);
 			c2 |= inb_p(0x40) << 8;
+			spin_unlock(&i8253_lock);
 		} while (c2 - c1 < 300);
 	}
 
diff -urNp x-ref/arch/x86_64/kernel/smpboot.c x/arch/x86_64/kernel/smpboot.c
--- x-ref/arch/x86_64/kernel/smpboot.c	Fri Oct  4 05:38:19 2002
+++ x/arch/x86_64/kernel/smpboot.c	Fri Oct  4 05:39:08 2002
@@ -76,6 +76,8 @@ struct cpuinfo_x86 cpu_data[NR_CPUS] __c
 /* Set when the idlers are all forked */
 int smp_threads_ready;
 
+extern int last_tsc;
+
 /*
  * Setup routine for controlling SMP activation
  *
@@ -241,11 +243,15 @@ static void __init synchronize_tsc_bp (v
 		atomic_inc(&tsc_count_start);
 
 		rdtscll(tsc_values[smp_processor_id()]);
+
 		/*
 		 * We clear the TSC in the last loop:
 		 */
-		if (i == NR_LOOPS-1)
+
+		if (i == NR_LOOPS-1) {
 			write_tsc(0, 0);
+			last_tsc = 0;
+		}
 
 		/*
 		 * Wait for all APs to leave the synchronization point:
diff -urNp x-ref/arch/x86_64/kernel/time.c x/arch/x86_64/kernel/time.c
--- x-ref/arch/x86_64/kernel/time.c	Thu Sep 26 04:14:10 2002
+++ x/arch/x86_64/kernel/time.c	Fri Oct  4 05:41:45 2002
@@ -12,8 +12,6 @@
  *
  */
 
-#define HPET_BIOS_SUPPORT_WORKING
-
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/interrupt.h>
@@ -26,6 +24,7 @@
 
 extern rwlock_t xtime_lock;
 spinlock_t rtc_lock = SPIN_LOCK_UNLOCKED;
+spinlock_t i8253_lock = SPIN_LOCK_UNLOCKED;
 
 unsigned int cpu_khz;					/* TSC clocks / usec, not used here */
 unsigned long hpet_period;				/* fsecs / HPET clock */
@@ -39,24 +38,45 @@ unsigned long __wall_jiffies __section_w
 struct timeval __xtime __section_xtime;
 struct timezone __sys_tz __section_sys_tz;
 
+long last_tsc;
+spinlock_t last_tsc_lock = SPIN_LOCK_UNLOCKED;
+
+#ifdef CONFIG_SMP
+
+void safe_rdtscll(long *x)
+{
+	long temp;
+	unsigned long flags;
+
+	spin_lock_irqsave(&last_tsc_lock, flags);
+	rdtscll(temp);
+	if (last_tsc - temp < 0L) last_tsc = temp;
+	*x = last_tsc;
+	spin_unlock_irqrestore(&last_tsc_lock, flags);
+}
+
+static inline unsigned int __do_gettimeoffset(void)
+{
+	unsigned long t;
+	safe_rdtscll(&t);	
+	return ((t  - hpet.last_tsc) * hpet.tsc_quot) >> 32;
+}
+
+#else
+#define safe_rdtscll(x)	rdtscll(*(x))
+#define __do_gettimeoffset do_gettimeoffset
+#endif
+
 /*
  * do_gettimeoffset() returns microseconds since last timer interrupt was
- * triggered by hardware. A memory read of HPET is slower than a register read
- * of TSC, but much more reliable. It's also synchronized to the timer
- * interrupt. Note that do_gettimeoffset() may return more than hpet_tick, if a
- * timer interrupt has happened already, but hpet.trigger wasn't updated yet.
- * This is not a problem, because jiffies hasn't updated either. They are bound
- * together by xtime_lock.
+ * triggered by hardware. 
  */
 
-static spinlock_t time_offset_lock = SPIN_LOCK_UNLOCKED;
-static unsigned long timeoffset = 0;
-
 inline unsigned int do_gettimeoffset(void)
 {
 	unsigned long t;
 	rdtscll(t);	
-	return (t  - hpet.last_tsc) * (1000000L / HZ) / hpet.ticks + hpet.offset;
+	return ((t  - hpet.last_tsc) * hpet.tsc_quot) >> 32;
 }
 
 /*
@@ -67,20 +87,15 @@ inline unsigned int do_gettimeoffset(voi
 
 void do_gettimeofday(struct timeval *tv)
 {
-	unsigned long flags, t;
+	unsigned long flags;
  	unsigned int sec, usec;
 
 	read_lock_irqsave(&xtime_lock, flags);
-	spin_lock(&time_offset_lock);
 
 	sec = xtime.tv_sec;
-	usec = xtime.tv_usec;
+	usec = xtime.tv_usec
+		+ (jiffies - wall_jiffies) * tick + __do_gettimeoffset();
 
-	t = (jiffies - wall_jiffies) * (1000000L / HZ) + do_gettimeoffset();
-	if (t > timeoffset) timeoffset = t;
-	usec += timeoffset;
-
-	spin_unlock(&time_offset_lock);
 	read_unlock_irqrestore(&xtime_lock, flags);
 
 	tv->tv_sec = sec + usec / 1000000;
@@ -98,7 +113,7 @@ void do_settimeofday(struct timeval *tv)
 	write_lock_irq(&xtime_lock);
 	vxtime_lock();
 
-	tv->tv_usec -= do_gettimeoffset() +
+	tv->tv_usec -= __do_gettimeoffset() +
 		(jiffies - wall_jiffies) * tick;
 
 	while (tv->tv_usec < 0) {
@@ -201,15 +216,39 @@ static void timer_interrupt(int irq, voi
 	vxtime_lock();
 
 	{
-		unsigned long t;
+		long tsc, offset;
+		int delay;
+
+		if (hpet.address) {
+
+			delay = hpet_readl(HPET_COUNTER) + hpet_tick - hpet_readl(HPET_T0_CMP);
+
+		} else {
 
-		rdtscll(t);
-		hpet.offset = (t  - hpet.last_tsc) * (1000000L / HZ) / hpet.ticks + hpet.offset - 1000000L / HZ;
-		if (hpet.offset >= 1000000L / HZ)
-			hpet.offset = 0;
-		hpet.ticks = min_t(long, max_t(long, (t  - hpet.last_tsc) * (1000000L / HZ) / (1000000L / HZ - hpet.offset),
-				cpu_khz * 1000/HZ * 15 / 16), cpu_khz * 1000/HZ * 16 / 15); 
-		hpet.last_tsc = t;
+			spin_lock(&i8253_lock);
+			outb_p(0x00, 0x43);
+			delay = inb_p(0x40);
+			delay |= inb(0x40) << 8;
+			spin_unlock(&i8253_lock);
+			delay = LATCH - 1 - delay;
+		}
+
+		safe_rdtscll(&tsc);
+
+		offset = (((tsc - hpet.last_tsc) * hpet.tsc_quot) >> 32) - tick;
+
+		if (offset > tick) {
+			if (hpet_report_lost_ticks)
+				printk(KERN_WARNING "time.c: lost %ld ticks\n", offset / tick);
+			jiffies += offset / tick;
+			offset %= tick;
+		}
+
+		hpet.last_tsc = tsc - hpet.quot * delay / hpet.tsc_quot;
+
+
+		if ((((tsc - hpet.last_tsc) * hpet.tsc_quot) >> 32) < offset)
+			hpet.last_tsc = tsc - ((offset << 32) / hpet.tsc_quot) - 1;
 	}
 
 /*
@@ -337,12 +376,10 @@ static unsigned int __init hpet_calibrat
 static unsigned int __init pit_calibrate_tsc(void)
 {
 	unsigned long start, end;
-	unsigned long flags;
 
 	outb((inb(0x61) & ~0x02) | 0x01, 0x61);
 
-	__save_flags(flags);
-	__cli();
+	spin_lock_irq(&i8253_lock);
 
 	outb(0xb0, 0x43);
 	outb((1193182 / (1000 / 50)) & 0xff, 0x42);
@@ -352,7 +389,7 @@ static unsigned int __init pit_calibrate
 	while ((inb(0x61) & 0x20) == 0);
 	rdtscll(end);
 
-	__restore_flags(flags);
+	spin_unlock_irq(&i8253_lock);
 
 	return (end - start) / 50;
 }
@@ -411,9 +448,11 @@ static int hpet_init(void)
 
 void __init pit_init(void)
 {
+	spin_lock_irq(&i8253_lock);
 	outb_p(0x34, 0x43);		/* binary, mode 2, LSB/MSB, ch 0 */
 	outb_p(LATCH & 0xff, 0x40);	/* LSB */
 	outb_p(LATCH >> 8, 0x40);	/* MSB */
+	spin_unlock_irq(&i8253_lock);
 }
 
 int __init time_setup(char *str)
@@ -428,18 +467,50 @@ extern void __init config_acpi_tables(vo
 
 void __init time_init(void)
 {
+	char *timename;
+
+	config_acpi_tables();
+
+#ifdef HPET_HACK_ENABLE_DANGEROUS
+	if (!hpet.address) {
+		printk(KERN_WARNING "time.c: WARNING: Enabling HPET base manually!\n");
+		outl(0x800038a0, 0xcf8);
+		outl(0xff000001, 0xcfc);
+		outl(0x800038a0, 0xcf8);
+		hpet.address = inl(0xcfc) & 0xfffffffe;
+		printk(KERN_WARNING "time.c: WARNING: Enabled HPET at at %#lx.\n", hpet.address);
+	}
+#endif
+
+#ifndef CONFIG_HPET_TIMER
+        hpet.address = 0;
+#endif
+
+	write_lock(&xtime_lock);
 	xtime.tv_sec = get_cmos_time();
 	xtime.tv_usec = 0;
+	write_unlock(&xtime_lock);
 
-		printk(KERN_WARNING "time.c: HPET timer not found, precise timing unavailable.\n");
+	if (!hpet_init()) {
+		hpet.hz = (1000000000000000L + hpet_period / 2) / hpet_period;
+		cpu_khz = hpet_calibrate_tsc();
+		timename = "HPET";
+	} else {
 		pit_init();
-		printk(KERN_INFO "time.c: Using 1.1931816 MHz PIT timer.\n");
-		setup_irq(0, &irq0);
+		hpet.hz = 1193182;
 		cpu_khz = pit_calibrate_tsc();
-		printk(KERN_INFO "time.c: Detected %d.%03d MHz processor.\n",
-			cpu_khz / 1000, cpu_khz % 1000);
-	hpet.ticks = cpu_khz * (1000 / HZ);
-	rdtscll(hpet.last_tsc);
+		timename = "PIT";
+	}
+
+	hpet.quot = (1000000L << 32) / hpet.hz;
+	hpet.tsc_quot = (1000L << 32) / cpu_khz;
+	setup_irq(0, &irq0);
+
+	printk(KERN_INFO "time.c: Using %ld.%06ld MHz %s timer.\n",
+		hpet.hz / 1000000, hpet.hz % 1000000, timename);
+	printk(KERN_INFO "time.c: Detected %d.%03d MHz processor.\n",
+		cpu_khz / 1000, cpu_khz % 1000);
+
 }
 
 __setup("report_lost_ticks", time_setup);
diff -urNp x-ref/arch/x86_64/kernel/vsyscall.c x/arch/x86_64/kernel/vsyscall.c
--- x-ref/arch/x86_64/kernel/vsyscall.c	Thu Sep 26 04:14:10 2002
+++ x/arch/x86_64/kernel/vsyscall.c	Fri Oct  4 05:39:08 2002
@@ -50,7 +50,11 @@
 
 long __vxtime_sequence[2] __section_vxtime_sequence;
 
+#ifdef CONFIG_SMP
 #undef USE_VSYSCALL
+#else
+#define USE_VSYSCALL
+#endif
 
 #ifdef USE_VSYSCALL
 
@@ -67,7 +71,7 @@ static inline void do_vgettimeofday(stru
 		sec = __xtime.tv_sec;
 		usec = __xtime.tv_usec +
 			(__jiffies - __wall_jiffies) * (1000000 / HZ) +
-			(t  - __hpet.last_tsc) * (1000000 / HZ) / __hpet.ticks + __hpet.offset;
+				(((t  - __hpet.last_tsc) * __hpet.tsc_quot) >> 32);
 
 		rmb();
 	} while (sequence != __vxtime_sequence[0]);
diff -urNp x-ref/include/asm-x86_64/vsyscall.h x/include/asm-x86_64/vsyscall.h
--- x-ref/include/asm-x86_64/vsyscall.h	Wed Oct  2 08:12:13 2002
+++ x/include/asm-x86_64/vsyscall.h	Fri Oct  4 05:39:08 2002
@@ -23,13 +23,11 @@ enum vsyscall_num {
 #define __section_vxtime_sequence __attribute__ ((unused, __section__ (".vxtime_sequence"), aligned(16)))
 
 struct hpet_data {
-	long address;		/* base address */
-	unsigned long hz;	/* HPET clocks / sec */
-	int trigger;		/* value at last interrupt */
-	int last;
-	int offset;
-	unsigned long last_tsc;
-	long ticks;
+	long address;
+	long hz;
+	long last_tsc;
+	long quot;
+	long tsc_quot;
 };
 
 #define hpet_readl(a)           readl(fix_to_virt(FIX_HPET_BASE) + a)