2003-09-04 04:36:45

by john stultz

[permalink] [raw]
Subject: [PATCH] linux-2.6.0-test4_cyclone-hpet-fix_A0

Andrew, All,
I probably should have been more active in reviewing the HPET code
before it went in, but I've been somewhat occupied with other bugs
recently. I'm excited to see someone else using my time-source
interface, however the HPET patch definitely pushes the interface beyond
its design (not a bad thing, just makes for some short term uglies).
Having multiple interrupt sources as well as time sources will generate
some work for 2.7 to clean it all up.

Anyway, the HPET changes made calibrate_tsc() static, which it probably
should be, but it broke the timer_cyclone code. This patch fixes it back
up by re-implementing calibrate_tsc() locally as it was done in
timer_hpet.c

Please apply.

thanks
-john


Also, while apparently unrelated, but touching code from the HPET patch,
I'm seeing some form of memory corruption on the 16way x440 which is
overwriting the wait_timer_tick pointer in apic.c I added some
initialized corruption pad variables around the pointer and they're
definitely being trampled. I'll have to look into it further tomorrow.



diff -Nru a/arch/i386/kernel/timers/timer_cyclone.c b/arch/i386/kernel/timers/timer_cyclone.c
--- a/arch/i386/kernel/timers/timer_cyclone.c Wed Sep 3 21:07:47 2003
+++ b/arch/i386/kernel/timers/timer_cyclone.c Wed Sep 3 21:07:47 2003
@@ -18,8 +18,9 @@
#include <asm/pgtable.h>
#include <asm/fixmap.h>

+#include "mach_timer.h"
+
extern spinlock_t i8253_lock;
-extern unsigned long calibrate_tsc(void);

/* Number of usecs that the last interrupt was delayed */
static int delay_at_last_interrupt;
@@ -132,6 +133,66 @@
/* convert to nanoseconds */
ret = base + ((this_offset - last_offset)&CYCLONE_TIMER_MASK);
return ret * (1000000000 / CYCLONE_TIMER_FREQ);
+}
+
+/* ------ Calibrate the TSC -------
+ * Return 2^32 * (1 / (TSC clocks per usec)) for do_fast_gettimeoffset().
+ * Too much 64-bit arithmetic here to do this cleanly in C, and for
+ * accuracy's sake we want to keep the overhead on the CTC speaker (channel 2)
+ * output busy loop as low as possible. We avoid reading the CTC registers
+ * directly because of the awkward 8-bit access mechanism of the 82C54
+ * device.
+ */
+
+#define CALIBRATE_TIME (5 * 1000020/HZ)
+
+static unsigned long __init calibrate_tsc(void)
+{
+ mach_prepare_counter();
+
+ {
+ unsigned long startlow, starthigh;
+ unsigned long endlow, endhigh;
+ unsigned long count;
+
+ rdtsc(startlow,starthigh);
+ mach_countup(&count);
+ rdtsc(endlow,endhigh);
+
+
+ /* Error: ECTCNEVERSET */
+ if (count <= 1)
+ goto bad_ctc;
+
+ /* 64-bit subtract - gcc just messes up with long longs */
+ __asm__("subl %2,%0\n\t"
+ "sbbl %3,%1"
+ :"=a" (endlow), "=d" (endhigh)
+ :"g" (startlow), "g" (starthigh),
+ "0" (endlow), "1" (endhigh));
+
+ /* Error: ECPUTOOFAST */
+ if (endhigh)
+ goto bad_ctc;
+
+ /* Error: ECPUTOOSLOW */
+ if (endlow <= CALIBRATE_TIME)
+ goto bad_ctc;
+
+ __asm__("divl %2"
+ :"=a" (endlow), "=d" (endhigh)
+ :"r" (endlow), "0" (0), "1" (CALIBRATE_TIME));
+
+ return endlow;
+ }
+
+ /*
+ * The CTC wasn't reliable: we got a hit on the very first read,
+ * or the CPU was so fast/slow that the quotient wouldn't fit in
+ * 32 bits..
+ */
+bad_ctc:
+ return 0;
}

static int __init init_cyclone(char* override)





2003-09-04 05:59:07

by Andrew Morton

[permalink] [raw]
Subject: Re: [PATCH] linux-2.6.0-test4_cyclone-hpet-fix_A0

john stultz <[email protected]> wrote:
>
> Andrew, All,
> I probably should have been more active in reviewing the HPET code
> before it went in, but I've been somewhat occupied with other bugs
> recently. I'm excited to see someone else using my time-source
> interface, however the HPET patch definitely pushes the interface beyond
> its design (not a bad thing, just makes for some short term uglies).
> Having multiple interrupt sources as well as time sources will generate
> some work for 2.7 to clean it all up.
>
> Anyway, the HPET changes made calibrate_tsc() static, which it probably
> should be, but it broke the timer_cyclone code. This patch fixes it back
> up by re-implementing calibrate_tsc() locally as it was done in
> timer_hpet.c

<stdrant>
Of course if some bozo had stuck this:

extern unsigned long calibrate_tsc(void);

in a header file rather than in a .c file (timer_cyclone.c), this problem
would not have occurred. Nevereverever put extern declarations in .c files!
</stdrant>


Can we not we avoid the cut-n-paste coding?

There is also timer_tsc.c:calibrate_tsc_hpet() which is almost the same as
timer_hpet.c:calibrate_tsc(). Seem to me that we could tweak
calibrate_tsc_hpet() a bit, unstaticalise timer_tsc.c:calibrate_tsc() and
have two functions rather than four?

>
> Also, while apparently unrelated, but touching code from the HPET patch,
> I'm seeing some form of memory corruption on the 16way x440 which is
> overwriting the wait_timer_tick pointer in apic.c I added some
> initialized corruption pad variables around the pointer and they're
> definitely being trampled. I'll have to look into it further tomorrow.

Hum. Please do this:

mnm:/usr/src/25> nm -n vmlinux|grep -3 wait_timer_tick
c043b360 D using_apic_timer
c043b380 d lapic_sysclass
c043b3e0 d device_lapic
c043b41c D wait_timer_tick
c043b420 D nmi_watchdog
c043b424 d nmi_hz
c043b440 d nmi_sysclass

It could be an overrun accessing device_lapic. There's a patch in -mm
which plays around with kobject.name although I can't immediately see why
it would cause this to happen. If the problem ocurs in -mm and not in
-linus then we need to be looking suspiciously at

kobject-unlimited-name-lengths.patch
and
kobject-unlimited-name-lengths-use-after-free-fix.patch


2003-09-04 07:17:20

by john stultz

[permalink] [raw]
Subject: Re: [PATCH] linux-2.6.0-test4_cyclone-hpet-fix_A0

On Wed, 2003-09-03 at 22:59, Andrew Morton wrote:
> john stultz <[email protected]> wrote:
> >
> > Andrew, All,
> > I probably should have been more active in reviewing the HPET code
> > before it went in, but I've been somewhat occupied with other bugs
> > recently. I'm excited to see someone else using my time-source
> > interface, however the HPET patch definitely pushes the interface beyond
> > its design (not a bad thing, just makes for some short term uglies).
> > Having multiple interrupt sources as well as time sources will generate
> > some work for 2.7 to clean it all up.
> >
> > Anyway, the HPET changes made calibrate_tsc() static, which it probably
> > should be, but it broke the timer_cyclone code. This patch fixes it back
> > up by re-implementing calibrate_tsc() locally as it was done in
> > timer_hpet.c
>
> <stdrant>
> Of course if some bozo had stuck this:
>
> extern unsigned long calibrate_tsc(void);
>
> in a header file rather than in a .c file (timer_cyclone.c), this problem
> would not have occurred. Nevereverever put extern declarations in .c files!
> </stdrant>

Yea, I'll fess up, I was the bozo (and probably still am). It was my
poor attempt at getting friend-like access to functions I really
shouldn't.

>
> Can we not we avoid the cut-n-paste coding?
>
> There is also timer_tsc.c:calibrate_tsc_hpet() which is almost the same as
> timer_hpet.c:calibrate_tsc(). Seem to me that we could tweak
> calibrate_tsc_hpet() a bit, unstaticalise timer_tsc.c:calibrate_tsc() and
> have two functions rather than four?

Yes, I was just being hesitant and trying to keep changes localized.
I'll try to take a more confident swing at it tomorrow.


> > Also, while apparently unrelated, but touching code from the HPET patch,
> > I'm seeing some form of memory corruption on the 16way x440 which is
> > overwriting the wait_timer_tick pointer in apic.c I added some
> > initialized corruption pad variables around the pointer and they're
> > definitely being trampled. I'll have to look into it further tomorrow.
>
> Hum. Please do this:
>
> mnm:/usr/src/25> nm -n vmlinux|grep -3 wait_timer_tick
> c043b360 D using_apic_timer
> c043b380 d lapic_sysclass
> c043b3e0 d device_lapic
> c043b41c D wait_timer_tick
> c043b420 D nmi_watchdog
> c043b424 d nmi_hz
> c043b440 d nmi_sysclass

[jstultz@elm3a16 cyclone-hpet-fix]$ nm -n vmlinux | grep -6 wait_timer_tick
c03977e0 D mp_bus_id_to_pci_bus
c0397860 D boot_cpu_physical_apicid
c0397864 D boot_cpu_logical_apicid
c0397868 D bios_cpu_apicid
c0397870 D using_apic_timer
c0397874 D corruption_pad1
c0397878 D wait_timer_tick
c039787c D corruption_pad2
c0397880 D nmi_watchdog
c0397884 d nmi_hz
c0397888 d nmi_print_lock
c03978a0 d ioapic_lock
c03978a4 D sis_apic_bug

I can send you the whole System.map if needed, but
mp_bus_id_to_pci_bus[] looks suspicious to me.


> It could be an overrun accessing device_lapic. There's a patch in -mm
> which plays around with kobject.name although I can't immediately see why
> it would cause this to happen. If the problem ocurs in -mm and not in
> -linus then we need to be looking suspiciously at
>
> kobject-unlimited-name-lengths.patch
> and
> kobject-unlimited-name-lengths-use-after-free-fix.patch

I was seeing this in 2.5.bk-current as of a few hours ago.


2003-09-04 14:51:18

by Martin J. Bligh

[permalink] [raw]
Subject: Re: [PATCH] linux-2.6.0-test4_cyclone-hpet-fix_A0

>> > Also, while apparently unrelated, but touching code from the HPET patch,
>> > I'm seeing some form of memory corruption on the 16way x440 which is
>> > overwriting the wait_timer_tick pointer in apic.c I added some
>> > initialized corruption pad variables around the pointer and they're
>> > definitely being trampled. I'll have to look into it further tomorrow.
>>
>> Hum. Please do this:
>>
>> mnm:/usr/src/25> nm -n vmlinux|grep -3 wait_timer_tick
>> c043b360 D using_apic_timer
>> c043b380 d lapic_sysclass
>> c043b3e0 d device_lapic
>> c043b41c D wait_timer_tick
>> c043b420 D nmi_watchdog
>> c043b424 d nmi_hz
>> c043b440 d nmi_sysclass
>
> [jstultz@elm3a16 cyclone-hpet-fix]$ nm -n vmlinux | grep -6 wait_timer_tick
> c03977e0 D mp_bus_id_to_pci_bus
> c0397860 D boot_cpu_physical_apicid
> c0397864 D boot_cpu_logical_apicid
> c0397868 D bios_cpu_apicid
> c0397870 D using_apic_timer
> c0397874 D corruption_pad1
> c0397878 D wait_timer_tick
> c039787c D corruption_pad2
> c0397880 D nmi_watchdog
> c0397884 d nmi_hz
> c0397888 d nmi_print_lock
> c03978a0 d ioapic_lock
> c03978a4 D sis_apic_bug
>
> I can send you the whole System.map if needed, but
> mp_bus_id_to_pci_bus[] looks suspicious to me.

Well, that looks like a reasonable aspersion to cast. Stick MAX_MP_BUSSES
to something silly like 4096, and see what happens. Is any of it > 32
not set to -1 anymore?

M.

2003-09-04 17:22:24

by Pallipadi, Venkatesh

[permalink] [raw]
Subject: RE: [PATCH] linux-2.6.0-test4_cyclone-hpet-fix_A0



> -----Original Message-----
> From: Andrew Morton [mailto:[email protected]]
>
> john stultz <[email protected]> wrote:
> >
> > Anyway, the HPET changes made calibrate_tsc() static, which
> it probably
> > should be, but it broke the timer_cyclone code. This patch
> fixes it back
> > up by re-implementing calibrate_tsc() locally as it was done in
> > timer_hpet.c
>
> <stdrant>
> Of course if some bozo had stuck this:
>
> extern unsigned long calibrate_tsc(void);
>
> in a header file rather than in a .c file (timer_cyclone.c),
> this problem
> would not have occurred. Nevereverever put extern
> declarations in .c files!
> </stdrant>


My fault. I should have atleast test compiled cyclone timer code.


> Can we not we avoid the cut-n-paste coding?
>
> There is also timer_tsc.c:calibrate_tsc_hpet() which is
> almost the same as
> timer_hpet.c:calibrate_tsc(). Seem to me that we could tweak
> calibrate_tsc_hpet() a bit, unstaticalise
> timer_tsc.c:calibrate_tsc() and
> have two functions rather than four?
>


How about the attached patch (against mm4), that moves all
calibrate tsc functions into a common file, avoiding the duplication.
This time I could successfully compile cyclone timer too :). However,
I had to do an unrelated one line change in fixmap (last chunk in
the patch) to compile for summit.


Thanks,
-Venkatesh


Attachments:
mm4-hpet-fix.patch (12.70 kB)
mm4-hpet-fix.patch

2003-09-04 18:03:17

by john stultz

[permalink] [raw]
Subject: RE: [PATCH] linux-2.6.0-test4_cyclone-hpet-fix_A0

On Thu, 2003-09-04 at 10:21, Pallipadi, Venkatesh wrote:

> > Can we not we avoid the cut-n-paste coding?
> >
> > There is also timer_tsc.c:calibrate_tsc_hpet() which is
> > almost the same as
> > timer_hpet.c:calibrate_tsc(). Seem to me that we could tweak
> > calibrate_tsc_hpet() a bit, unstaticalise
> > timer_tsc.c:calibrate_tsc() and
> > have two functions rather than four?
> >
>
>
> How about the attached patch (against mm4), that moves all
> calibrate tsc functions into a common file, avoiding the duplication.
> This time I could successfully compile cyclone timer too :). However,

Looks better, any reason calibrate_tsc and calibrate_tsc_hpet can't be
unified (it looks like the same basic code just talking to different
hardware)? I was planning on giving that a shot later today.

> I had to do an unrelated one line change in fixmap (last chunk in
> the patch) to compile for summit.

Is this just an -mm only thing (2.5 has _X86_CYCLONE_TIMER everywhere)?

thanks
-john




2003-09-04 18:23:51

by Pallipadi, Venkatesh

[permalink] [raw]
Subject: RE: [PATCH] linux-2.6.0-test4_cyclone-hpet-fix_A0



> -----Original Message-----
> From: john stultz [mailto:[email protected]]
> Sent: Thursday, September 04, 2003 10:54 AM
> To: Pallipadi, Venkatesh
> Cc: Andrew Morton; lkml
> Subject: RE: [PATCH] linux-2.6.0-test4_cyclone-hpet-fix_A0
>
>
> On Thu, 2003-09-04 at 10:21, Pallipadi, Venkatesh wrote:
>
> > How about the attached patch (against mm4), that moves all
> > calibrate tsc functions into a common file, avoiding the
> duplication.
> > This time I could successfully compile cyclone timer too
> :). However,
>
> Looks better, any reason calibrate_tsc and calibrate_tsc_hpet can't be
> unified (it looks like the same basic code just talking to different
> hardware)? I was planning on giving that a shot later today.


The best solution will be to unify calibrate_tsc and calibrate_tsc_hpet.
Only issue is, we need to switch between pit based mach_count* routines
and HPET based ones at runtime. As we want to use pit, even when HPET is

configured in and is not available in the hardware. So, "mach_timer.h"
mechanism may not work as is.


>
> > I had to do an unrelated one line change in fixmap (last chunk in
> > the patch) to compile for summit.
>
> Is this just an -mm only thing (2.5 has _X86_CYCLONE_TIMER
> everywhere)?

Yes. This seems to be mm4 only issue, coming from 4G-4G
patch and cyclone-fixmap-fix.patch


Thanks,
-Venkatesh

2003-09-04 18:23:40

by Andrew Morton

[permalink] [raw]
Subject: Re: [PATCH] linux-2.6.0-test4_cyclone-hpet-fix_A0

john stultz <[email protected]> wrote:
>
> > I had to do an unrelated one line change in fixmap (last chunk in
> > the patch) to compile for summit.
>
> Is this just an -mm only thing (2.5 has _X86_CYCLONE_TIMER everywhere)?

That's the 4G/4G patch doing this:

+#ifdef CONFIG_X86_CYCLONE
FIX_CYCLONE_TIMER, /*cyclone timer register*/
+ FIX_VSTACK_HOLE_2,
#endif

I was sent a patch which did:

FIX_TSS_0,
FIX_ENTRY_TRAMPOLINE_1,
FIX_ENTRY_TRAMPOLINE_0,
-#ifdef CONFIG_X86_SUMMIT
+#ifdef CONFIG_X86_CYCLONE
FIX_CYCLONE_TIMER, /*cyclone timer register*/
FIX_VSTACK_HOLE_2,

So I'll make that CONFIG_X86_CYCLONE_TIMER.


Here's an updated version of Venkatesh's patch against current -linus.
common.c needed asm/io.h



arch/i386/kernel/timers/Makefile | 2
arch/i386/kernel/timers/common.c | 139 ++++++++++++++++++++++++++++++++
arch/i386/kernel/timers/timer_cyclone.c | 1
arch/i386/kernel/timers/timer_hpet.c | 59 -------------
arch/i386/kernel/timers/timer_tsc.c | 115 --------------------------
include/asm-i386/fixmap.h | 0
include/asm-i386/timer.h | 2
7 files changed, 144 insertions(+), 174 deletions(-)

diff -puN /dev/null arch/i386/kernel/timers/common.c
--- /dev/null 2002-08-30 16:31:37.000000000 -0700
+++ 25-akpm/arch/i386/kernel/timers/common.c 2003-09-04 11:08:14.000000000 -0700
@@ -0,0 +1,139 @@
+/*
+ * Common functions used across the timers go here
+ */
+
+#include <linux/init.h>
+#include <linux/timex.h>
+#include <linux/errno.h>
+
+#include <asm/io.h>
+#include <asm/timer.h>
+#include <asm/hpet.h>
+
+#include "mach_timer.h"
+
+/* ------ Calibrate the TSC -------
+ * Return 2^32 * (1 / (TSC clocks per usec)) for do_fast_gettimeoffset().
+ * Too much 64-bit arithmetic here to do this cleanly in C, and for
+ * accuracy's sake we want to keep the overhead on the CTC speaker (channel 2)
+ * output busy loop as low as possible. We avoid reading the CTC registers
+ * directly because of the awkward 8-bit access mechanism of the 82C54
+ * device.
+ */
+
+#define CALIBRATE_TIME (5 * 1000020/HZ)
+
+unsigned long __init calibrate_tsc(void)
+{
+ mach_prepare_counter();
+
+ {
+ unsigned long startlow, starthigh;
+ unsigned long endlow, endhigh;
+ unsigned long count;
+
+ rdtsc(startlow,starthigh);
+ mach_countup(&count);
+ rdtsc(endlow,endhigh);
+
+
+ /* Error: ECTCNEVERSET */
+ if (count <= 1)
+ goto bad_ctc;
+
+ /* 64-bit subtract - gcc just messes up with long longs */
+ __asm__("subl %2,%0\n\t"
+ "sbbl %3,%1"
+ :"=a" (endlow), "=d" (endhigh)
+ :"g" (startlow), "g" (starthigh),
+ "0" (endlow), "1" (endhigh));
+
+ /* Error: ECPUTOOFAST */
+ if (endhigh)
+ goto bad_ctc;
+
+ /* Error: ECPUTOOSLOW */
+ if (endlow <= CALIBRATE_TIME)
+ goto bad_ctc;
+
+ __asm__("divl %2"
+ :"=a" (endlow), "=d" (endhigh)
+ :"r" (endlow), "0" (0), "1" (CALIBRATE_TIME));
+
+ return endlow;
+ }
+
+ /*
+ * The CTC wasn't reliable: we got a hit on the very first read,
+ * or the CPU was so fast/slow that the quotient wouldn't fit in
+ * 32 bits..
+ */
+bad_ctc:
+ return 0;
+}
+
+#ifdef CONFIG_HPET_TIMER
+/* ------ Calibrate the TSC using HPET -------
+ * Return 2^32 * (1 / (TSC clocks per usec)) for getting the CPU freq.
+ * Second output is parameter 1 (when non NULL)
+ * Set 2^32 * (1 / (tsc per HPET clk)) for delay_hpet().
+ * calibrate_tsc() calibrates the processor TSC by comparing
+ * it to the HPET timer of known frequency.
+ * Too much 64-bit arithmetic here to do this cleanly in C
+ */
+#define CALIBRATE_CNT_HPET (5 * hpet_tick)
+#define CALIBRATE_TIME_HPET (5 * KERNEL_TICK_USEC)
+
+unsigned long __init calibrate_tsc_hpet(unsigned long *tsc_hpet_quotient_ptr)
+{
+ unsigned long tsc_startlow, tsc_starthigh;
+ unsigned long tsc_endlow, tsc_endhigh;
+ unsigned long hpet_start, hpet_end;
+ unsigned long result, remain;
+
+ hpet_start = hpet_readl(HPET_COUNTER);
+ rdtsc(tsc_startlow, tsc_starthigh);
+ do {
+ hpet_end = hpet_readl(HPET_COUNTER);
+ } while ((hpet_end - hpet_start) < CALIBRATE_CNT_HPET);
+ rdtsc(tsc_endlow, tsc_endhigh);
+
+ /* 64-bit subtract - gcc just messes up with long longs */
+ __asm__("subl %2,%0\n\t"
+ "sbbl %3,%1"
+ :"=a" (tsc_endlow), "=d" (tsc_endhigh)
+ :"g" (tsc_startlow), "g" (tsc_starthigh),
+ "0" (tsc_endlow), "1" (tsc_endhigh));
+
+ /* Error: ECPUTOOFAST */
+ if (tsc_endhigh)
+ goto bad_calibration;
+
+ /* Error: ECPUTOOSLOW */
+ if (tsc_endlow <= CALIBRATE_TIME_HPET)
+ goto bad_calibration;
+
+ ASM_DIV64_REG(result, remain, tsc_endlow, 0, CALIBRATE_TIME_HPET);
+ if (remain > (tsc_endlow >> 1))
+ result++; /* rounding the result */
+
+ if (tsc_hpet_quotient_ptr) {
+ unsigned long tsc_hpet_quotient;
+
+ ASM_DIV64_REG(tsc_hpet_quotient, remain, tsc_endlow, 0,
+ CALIBRATE_CNT_HPET);
+ if (remain > (tsc_endlow >> 1))
+ tsc_hpet_quotient++; /* rounding the result */
+ *tsc_hpet_quotient_ptr = tsc_hpet_quotient;
+ }
+
+ return result;
+bad_calibration:
+ /*
+ * the CPU was so fast/slow that the quotient wouldn't fit in
+ * 32 bits..
+ */
+ return 0;
+}
+#endif
+
diff -puN arch/i386/kernel/timers/Makefile~calibrate_tsc-consolidation arch/i386/kernel/timers/Makefile
--- 25/arch/i386/kernel/timers/Makefile~calibrate_tsc-consolidation 2003-09-04 11:02:03.000000000 -0700
+++ 25-akpm/arch/i386/kernel/timers/Makefile 2003-09-04 11:02:03.000000000 -0700
@@ -2,7 +2,7 @@
# Makefile for x86 timers
#

-obj-y := timer.o timer_none.o timer_tsc.o timer_pit.o
+obj-y := timer.o timer_none.o timer_tsc.o timer_pit.o common.o

obj-$(CONFIG_X86_CYCLONE_TIMER) += timer_cyclone.o
obj-$(CONFIG_HPET_TIMER) += timer_hpet.o
diff -puN arch/i386/kernel/timers/timer_cyclone.c~calibrate_tsc-consolidation arch/i386/kernel/timers/timer_cyclone.c
--- 25/arch/i386/kernel/timers/timer_cyclone.c~calibrate_tsc-consolidation 2003-09-04 11:02:03.000000000 -0700
+++ 25-akpm/arch/i386/kernel/timers/timer_cyclone.c 2003-09-04 11:02:03.000000000 -0700
@@ -19,7 +19,6 @@
#include <asm/fixmap.h>

extern spinlock_t i8253_lock;
-extern unsigned long calibrate_tsc(void);

/* Number of usecs that the last interrupt was delayed */
static int delay_at_last_interrupt;
diff -puN arch/i386/kernel/timers/timer_hpet.c~calibrate_tsc-consolidation arch/i386/kernel/timers/timer_hpet.c
--- 25/arch/i386/kernel/timers/timer_hpet.c~calibrate_tsc-consolidation 2003-09-04 11:02:03.000000000 -0700
+++ 25-akpm/arch/i386/kernel/timers/timer_hpet.c 2003-09-04 11:02:03.000000000 -0700
@@ -131,63 +131,6 @@ void delay_hpet(unsigned long loops)
} while ((hpet_end - hpet_start) < (loops));
}

-/* ------ Calibrate the TSC -------
- * Return 2^32 * (1 / (TSC clocks per usec)) for getting the CPU freq.
- * Set 2^32 * (1 / (tsc per HPET clk)) for delay_hpet().
- * calibrate_tsc() calibrates the processor TSC by comparing
- * it to the HPET timer of known frequency.
- * Too much 64-bit arithmetic here to do this cleanly in C
- */
-#define CALIBRATE_CNT_HPET (5 * hpet_tick)
-#define CALIBRATE_TIME_HPET (5 * KERNEL_TICK_USEC)
-
-static unsigned long __init calibrate_tsc(void)
-{
- unsigned long tsc_startlow, tsc_starthigh;
- unsigned long tsc_endlow, tsc_endhigh;
- unsigned long hpet_start, hpet_end;
- unsigned long result, remain;
-
- hpet_start = hpet_readl(HPET_COUNTER);
- rdtsc(tsc_startlow, tsc_starthigh);
- do {
- hpet_end = hpet_readl(HPET_COUNTER);
- } while ((hpet_end - hpet_start) < CALIBRATE_CNT_HPET);
- rdtsc(tsc_endlow, tsc_endhigh);
-
- /* 64-bit subtract - gcc just messes up with long longs */
- __asm__("subl %2,%0\n\t"
- "sbbl %3,%1"
- :"=a" (tsc_endlow), "=d" (tsc_endhigh)
- :"g" (tsc_startlow), "g" (tsc_starthigh),
- "0" (tsc_endlow), "1" (tsc_endhigh));
-
- /* Error: ECPUTOOFAST */
- if (tsc_endhigh)
- goto bad_calibration;
-
- /* Error: ECPUTOOSLOW */
- if (tsc_endlow <= CALIBRATE_TIME_HPET)
- goto bad_calibration;
-
- ASM_DIV64_REG(result, remain, tsc_endlow, 0, CALIBRATE_TIME_HPET);
- if (remain > (tsc_endlow >> 1))
- result++; /* rounding the result */
-
- ASM_DIV64_REG(tsc_hpet_quotient, remain, tsc_endlow, 0,
- CALIBRATE_CNT_HPET);
- if (remain > (tsc_endlow >> 1))
- tsc_hpet_quotient++; /* rounding the result */
-
- return result;
-bad_calibration:
- /*
- * the CPU was so fast/slow that the quotient wouldn't fit in
- * 32 bits..
- */
- return 0;
-}
-
static int __init init_hpet(char* override)
{
unsigned long result, remain;
@@ -201,7 +144,7 @@ static int __init init_hpet(char* overri

printk("Using HPET for gettimeofday\n");
if (cpu_has_tsc) {
- unsigned long tsc_quotient = calibrate_tsc();
+ unsigned long tsc_quotient = calibrate_tsc_hpet(&tsc_hpet_quotient);
if (tsc_quotient) {
/* report CPU clock rate in Hz.
* The formula is (10^6 * 2^32) / (2^32 * 1 / (clocks/us)) =
diff -puN arch/i386/kernel/timers/timer_tsc.c~calibrate_tsc-consolidation arch/i386/kernel/timers/timer_tsc.c
--- 25/arch/i386/kernel/timers/timer_tsc.c~calibrate_tsc-consolidation 2003-09-04 11:02:03.000000000 -0700
+++ 25-akpm/arch/i386/kernel/timers/timer_tsc.c 2003-09-04 11:02:03.000000000 -0700
@@ -230,67 +230,6 @@ static void delay_tsc(unsigned long loop
} while ((now-bclock) < loops);
}

-/* ------ Calibrate the TSC -------
- * Return 2^32 * (1 / (TSC clocks per usec)) for do_fast_gettimeoffset().
- * Too much 64-bit arithmetic here to do this cleanly in C, and for
- * accuracy's sake we want to keep the overhead on the CTC speaker (channel 2)
- * output busy loop as low as possible. We avoid reading the CTC registers
- * directly because of the awkward 8-bit access mechanism of the 82C54
- * device.
- */
-
-#define CALIBRATE_TIME (5 * 1000020/HZ)
-
-static unsigned long __init calibrate_tsc(void)
-{
- mach_prepare_counter();
-
- {
- unsigned long startlow, starthigh;
- unsigned long endlow, endhigh;
- unsigned long count;
-
- rdtsc(startlow,starthigh);
- mach_countup(&count);
- rdtsc(endlow,endhigh);
-
- last_tsc_low = endlow;
-
- /* Error: ECTCNEVERSET */
- if (count <= 1)
- goto bad_ctc;
-
- /* 64-bit subtract - gcc just messes up with long longs */
- __asm__("subl %2,%0\n\t"
- "sbbl %3,%1"
- :"=a" (endlow), "=d" (endhigh)
- :"g" (startlow), "g" (starthigh),
- "0" (endlow), "1" (endhigh));
-
- /* Error: ECPUTOOFAST */
- if (endhigh)
- goto bad_ctc;
-
- /* Error: ECPUTOOSLOW */
- if (endlow <= CALIBRATE_TIME)
- goto bad_ctc;
-
- __asm__("divl %2"
- :"=a" (endlow), "=d" (endhigh)
- :"r" (endlow), "0" (0), "1" (CALIBRATE_TIME));
-
- return endlow;
- }
-
- /*
- * The CTC wasn't reliable: we got a hit on the very first read,
- * or the CPU was so fast/slow that the quotient wouldn't fit in
- * 32 bits..
- */
-bad_ctc:
- return 0;
-}
-
#ifdef CONFIG_HPET_TIMER
static void mark_offset_tsc_hpet(void)
{
@@ -339,58 +278,6 @@ static void mark_offset_tsc_hpet(void)
ASM_MUL64_REG(temp, delay_at_last_interrupt,
hpet_usec_quotient, delay_at_last_interrupt);
}
-
-/* ------ Calibrate the TSC based on HPET timer -------
- * Return 2^32 * (1 / (TSC clocks per usec)) for do_fast_gettimeoffset().
- * calibrate_tsc() calibrates the processor TSC by comparing
- * it to the HPET timer of known frequency.
- * Too much 64-bit arithmetic here to do this cleanly in C
- */
-
-#define CALIBRATE_CNT_HPET (5 * hpet_tick)
-#define CALIBRATE_TIME_HPET (5 * KERNEL_TICK_USEC)
-
-unsigned long __init calibrate_tsc_hpet(void)
-{
- unsigned long tsc_startlow, tsc_starthigh;
- unsigned long tsc_endlow, tsc_endhigh;
- unsigned long hpet_start, hpet_end;
- unsigned long result, remain;
-
- hpet_start = hpet_readl(HPET_COUNTER);
- rdtsc(tsc_startlow, tsc_starthigh);
- do {
- hpet_end = hpet_readl(HPET_COUNTER);
- } while ((hpet_end - hpet_start) < CALIBRATE_CNT_HPET);
- rdtsc(tsc_endlow, tsc_endhigh);
-
- /* 64-bit subtract - gcc just messes up with long longs */
- __asm__("subl %2,%0\n\t"
- "sbbl %3,%1"
- :"=a" (tsc_endlow), "=d" (tsc_endhigh)
- :"g" (tsc_startlow), "g" (tsc_starthigh),
- "0" (tsc_endlow), "1" (tsc_endhigh));
-
- /* Error: ECPUTOOFAST */
- if (tsc_endhigh)
- goto bad_calibration;
-
- /* Error: ECPUTOOSLOW */
- if (tsc_endlow <= CALIBRATE_TIME_HPET)
- goto bad_calibration;
-
- ASM_DIV64_REG(result, remain, tsc_endlow, 0, CALIBRATE_TIME_HPET);
- if (remain > (tsc_endlow >> 1))
- result++; /* rounding the result */
-
- return result;
-bad_calibration:
- /*
- * the CPU was so fast/slow that the quotient wouldn't fit in
- * 32 bits..
- */
- return 0;
-}
#endif

#ifdef CONFIG_CPU_FREQ
@@ -491,7 +378,7 @@ static int __init init_tsc(char* overrid
if (is_hpet_enabled()){
unsigned long result, remain;
printk("Using TSC for gettimeofday\n");
- tsc_quotient = calibrate_tsc_hpet();
+ tsc_quotient = calibrate_tsc_hpet(NULL);
timer_tsc.mark_offset = &mark_offset_tsc_hpet;
/*
* Math to calculate hpet to usec multiplier
diff -puN include/asm-i386/fixmap.h~calibrate_tsc-consolidation include/asm-i386/fixmap.h
diff -puN include/asm-i386/timer.h~calibrate_tsc-consolidation include/asm-i386/timer.h
--- 25/include/asm-i386/timer.h~calibrate_tsc-consolidation 2003-09-04 11:02:03.000000000 -0700
+++ 25-akpm/include/asm-i386/timer.h 2003-09-04 11:02:03.000000000 -0700
@@ -38,8 +38,10 @@ extern struct timer_opts timer_tsc;
extern struct timer_opts timer_cyclone;
#endif

+extern unsigned long calibrate_tsc(void);
#ifdef CONFIG_HPET_TIMER
extern struct timer_opts timer_hpet;
+extern unsigned long calibrate_tsc_hpet(unsigned long *tsc_hpet_quotient_ptr);
#endif

#endif

_