Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > 89877e42827f16fa5f86b1df0c2860b1 > files > 2456

kernel-2.6.18-128.1.10.el5.src.rpm

From: Brian Maly <bmaly@redhat.com>
Date: Thu, 28 Aug 2008 15:30:00 -0400
Subject: [x86] hpet: consolidate assignment of hpet_period
Message-id: 48B6FCB8.9090900@redhat.com
O-Subject: Re: [RHEL5 patch] hpet: consolidate assignment of hpet_period
Bugzilla: 435726
RH-Acked-by: Alan Cox <alan@redhat.com>

Resolves BZ 435726

AMD Griffin RS780/SB700 platforms have spread spectrum capabilities. When
down spread is enabled,
the mean frequency of the HPET runs slower... 99.75 MHz instead of 100
MHz. The BIOS works around this issue by dynamically re-calculating
hpet_period (after spread spectrum is engaged) and storing this temporary
value in BIOS RAM during boot. A fake base address for the register is
generated by the BIOS which causes the kernel to read the dynamically
generated hpet_period from  BIOS RAM. Once the hpet_period is read, the
BIOS resets the register base address to the real address. Any reads of the
hpet_period register after this point will return the actual statically
coded period of 100MHz. In RHEL5 this causes timekeeping to skew badly.
hpet_period is read twice during boot, so on the first read we get the
actual hpet_period (the dynamically calculated one) and on the second read
we get the theoretical hpet_period (the statically coded one). This results
is that the timekeeping math uses an inaccurate value and returns an
inaccurate result. This patch resolves this issue by consolidating the
assignment of hpet_period to one point in the code, as we do upstream. With
the patch we only do only one read of hpet_period and use that value
throughout.

This patch has been tested on the affected hardware and resolves the issue.

Brian

Here is a followup patch. With this patch we will now have only a single
read of HPET_PERIOD register in i386, so as to be consistent with the
single read in x86_64 and the single read in Xen.

Brian

diff --git a/arch/i386/kernel/hpet.c b/arch/i386/kernel/hpet.c
index 17647a5..3f12168 100644
--- a/arch/i386/kernel/hpet.c
+++ b/arch/i386/kernel/hpet.c
@@ -12,6 +12,7 @@
 /* FSEC = 10^-15 NSEC = 10^-9 */
 #define FSEC_PER_NSEC	1000000
 
+extern unsigned long hpet_period;
 static void *hpet_ptr;
 
 static cycle_t read_hpet(void)
@@ -31,7 +32,6 @@ static struct clocksource clocksource_hpet = {
 
 static int __init init_hpet_clocksource(void)
 {
-	unsigned long hpet_period;
 	void __iomem* hpet_base;
 	u64 tmp;
 
@@ -43,9 +43,6 @@ static int __init init_hpet_clocksource(void)
 		(void __iomem*)ioremap_nocache(hpet_address, HPET_MMAP_SIZE);
 	hpet_ptr = hpet_base + HPET_COUNTER;
 
-	/* calculate the frequency: */
-	hpet_period = readl(hpet_base + HPET_PERIOD);
-
 	/*
 	 * hpet period is in femto seconds per cycle
 	 * so we need to convert this to ns/cyc units
diff --git a/arch/i386/kernel/time_hpet.c b/arch/i386/kernel/time_hpet.c
index 27210db..cf206c8 100644
--- a/arch/i386/kernel/time_hpet.c
+++ b/arch/i386/kernel/time_hpet.c
@@ -22,7 +22,7 @@
 #include <asm/hpet.h>
 #include <linux/hpet.h>
 
-static unsigned long hpet_period;	/* fsecs / HPET clock */
+unsigned long hpet_period;		/* fsecs / HPET clock */
 unsigned long hpet_tick;		/* hpet clks count per tick */
 unsigned long hpet_tick_real;		/* hpet clocks per interrupt */
 unsigned long hpet_address;		/* hpet memory map physical address */