Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 24 Jun 2005 13:53:51 -0400
From:      John Baldwin <jhb@FreeBSD.org>
To:        Jens Schweikhardt <schweikh@schweikhardt.net>
Cc:        freebsd-current@FreeBSD.org
Subject:   Re: Timekeeping hosed by factor 3, high lapic[01] interrupt rates
Message-ID:  <200506241353.52383.jhb@FreeBSD.org>
In-Reply-To: <20050624165002.GA860@schweikhardt.net>
References:  <20050516113420.GA786@schweikhardt.net> <200506231714.40891.jhb@FreeBSD.org> <20050624165002.GA860@schweikhardt.net>

next in thread | previous in thread | raw e-mail | index | archive | help
On Friday 24 June 2005 12:50 pm, Jens Schweikhardt wrote:
> On Thu, Jun 23, 2005 at 05:14:39PM -0400, John Baldwin wrote:
> ...
> # Ok.  What timecounter does your UP kernel use, and does your UP kernel
> break # if you change the timecounter to i8254?
>
> The UP uses the TSC:
> $ sysctl -a|grep timec
> kern.timecounter.stepwarnings: 0
> kern.timecounter.nbinuptime: 136311
> kern.timecounter.nnanouptime: 0
> kern.timecounter.nmicrouptime: 664
> kern.timecounter.nbintime: 1273
> kern.timecounter.nnanotime: 36
> kern.timecounter.nmicrotime: 1237
> kern.timecounter.ngetbinuptime: 405
> kern.timecounter.ngetnanouptime: 29
> kern.timecounter.ngetmicrouptime: 2534
> kern.timecounter.ngetbintime: 0
> kern.timecounter.ngetnanotime: 0
> kern.timecounter.ngetmicrotime: 5
> kern.timecounter.nsetclock: 2
> kern.timecounter.hardware: TSC
> kern.timecounter.choice: TSC(800) i8254(0) dummy(-1000000)
> kern.timecounter.tick: 1
> kern.timecounter.smp_tsc: 0
>
> When I do
>
> $ sysctl kern.timecounter.hardware=i8254
>
> on the UP the time dilation by factor 3 starts and the lapic rate
> increases. So yes, that breaks the UP kernel.

Ok.  Can you try this untested patch?  It's mostly from phk and I haven't yet 
tested it locally to make sure it doesn't break things:

--- //depot/vendor/freebsd/src/sys/i386/isa/clock.c	2005/05/14 09:10:26
+++ //depot/user/jhb/acpipci/i386/isa/clock.c	2005/06/24 17:30:30
@@ -136,6 +136,7 @@
 static	u_char	timer2_state;
 
 static	unsigned i8254_get_timecount(struct timecounter *tc);
+static	unsigned i8254_simple_get_timecount(struct timecounter *tc);
 static	void	set_timer_freq(u_int freq, int intr_freq);
 
 static struct timecounter i8254_timecounter = {
@@ -532,10 +533,15 @@
 {
 	int new_timer0_max_count;
 
+	i8254_timecounter.tc_frequency = freq;
 	mtx_lock_spin(&clock_lock);
 	timer_freq = freq;
 	new_timer0_max_count = hardclock_max_count = TIMER_DIV(intr_freq);
-	if (new_timer0_max_count != timer0_max_count) {
+	if (using_lapic_timer) {
+		outb(TIMER_MODE, TIMER_SEL0 | TIMER_RATEGEN | TIMER_16BIT);
+		outb(TIMER_CNTR0, 0);
+		outb(TIMER_CNTR0, 0);
+	} else if (new_timer0_max_count != timer0_max_count) {
 		timer0_max_count = new_timer0_max_count;
 		outb(TIMER_MODE, TIMER_SEL0 | TIMER_RATEGEN | TIMER_16BIT);
 		outb(TIMER_CNTR0, timer0_max_count & 0xff);
@@ -548,11 +554,7 @@
 i8254_restore(void)
 {
 
-	mtx_lock_spin(&clock_lock);
-	outb(TIMER_MODE, TIMER_SEL0 | TIMER_RATEGEN | TIMER_16BIT);
-	outb(TIMER_CNTR0, timer0_max_count & 0xff);
-	outb(TIMER_CNTR0, timer0_max_count >> 8);
-	mtx_unlock_spin(&clock_lock);
+	set_timer_freq(timer_freq, hz);
 }
 
 static void
@@ -627,7 +629,6 @@
 	}
 
 	set_timer_freq(timer_freq, hz);
-	i8254_timecounter.tc_frequency = timer_freq;
 	tc_init(&i8254_timecounter);
 
 	init_TSC();
@@ -782,7 +783,8 @@
 	/*
 	 * If we aren't using the local APIC timer to drive the kernel
 	 * clocks, setup the interrupt handler for the 8254 timer 0 so
-	 * that it can drive hardclock().
+	 * that it can drive hardclock().  Otherwise, change the 8254
+	 * timecounter to user a simpler algorithm.
 	 */
 	if (!using_lapic_timer) {
 		intr_add_handler("clk", 0, (driver_intr_t *)clkintr, NULL,
@@ -791,6 +793,10 @@
 		if (i8254_intsrc != NULL)
 			i8254_pending =
 			    i8254_intsrc->is_pic->pic_source_pending;
+	} else {
+		i8254_timecounter.tc_get_timecount =
+		    i8254_simple_get_timecount;
+		set_timer_freq(timer_freq, hz);
 	}
 
 	/* Initialize RTC. */
@@ -858,10 +864,8 @@
 	 */
 	freq = timer_freq;
 	error = sysctl_handle_int(oidp, &freq, sizeof(freq), req);
-	if (error == 0 && req->newptr != NULL) {
+	if (error == 0 && req->newptr != NULL)
 		set_timer_freq(freq, hz);
-		i8254_timecounter.tc_frequency = freq;
-	}
 	return (error);
 }
 
@@ -869,6 +873,24 @@
     0, sizeof(u_int), sysctl_machdep_i8254_freq, "IU", "");
 
 static unsigned
+i8254_simple_get_timecount(struct timecounter *tc)
+{
+	u_int count;
+	u_int high, low;
+
+	mtx_lock_spin(&clock_lock);
+
+	/* Select timer0 and latch counter value. */
+	outb(TIMER_MODE, TIMER_SEL0 | TIMER_LATCH);
+
+	low = inb(TIMER_CNTR0);
+	high = inb(TIMER_CNTR0);
+	count = 0xffff - ((high << 8) | low);
+	mtx_unlock_spin(&clock_lock);
+	return (count);
+}
+
+static unsigned
 i8254_get_timecount(struct timecounter *tc)
 {
 	u_int count;

-- 
John Baldwin <jhb@FreeBSD.org>  <><  http://www.FreeBSD.org/~jhb/
"Power Users Use the Power to Serve"  =  http://www.FreeBSD.org



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200506241353.52383.jhb>