git: 9front

Download patch

ref: 80bbd5128298b2a5039bfdb4949551dd1e6376ad
parent: 4b8d6b808552c5e1c5a832aab06d14fddbe5032e
author: cinap_lenrek <cinap_lenrek@gmx.de>
date: Sun Sep 30 15:41:34 EDT 2012

guesscpuhz(), apm suspend

use fastclock timer (pit2) to measure cpufreq in guesscpuhz(). this
gives a bigger period minimizing the danger of overrun as pit2 runs
at the constant maximum period of 0x10000 ticks. also use smaller
loop increments (1000) and bigger maximum loop upper bound.

move the loops < ... check to the bottom of the loop so we get the
effective count *before* adding the next loop increment.

ilock() while doing measurements in guesscpuhz() to prevent accidents
with other processors reading fastclock or doing guesscpuhz()
in parralel.

export new i8253reset() function for apm to reset the timers after
a apm bios suspend.

--- a/sys/src/9/pc/apm.c
+++ b/sys/src/9/pc/apm.c
@@ -83,13 +83,22 @@
 static long
 apmwrite(Chan*, void *a, long n, vlong off)
 {
-	int s;
+	int s, needreset;
 	if(off || n != sizeof apmu)
 		error("write a Ureg");
 
 	memmove(&apmu, a, sizeof apmu);
+	needreset = apmu.ax==0x5307;	/* set power state */
 	s = splhi();
 	apmfarcall(APMCSEL, ebx, &apmu);
+	if(needreset){
+		/*
+		 * some BIOS disable the timers. have to
+		 * reset them after suspend.
+		 */
+		splhi();
+		i8253reset();
+	}
 	splx(s);
 	return n;
 }
--- a/sys/src/9/pc/fns.h
+++ b/sys/src/9/pc/fns.h
@@ -54,6 +54,7 @@
 void	i8250setmouseputc(char*, int (*)(Queue*, int));
 void	i8253enable(void);
 void	i8253init(void);
+void	i8253reset(void);
 uvlong	i8253read(uvlong*);
 void	i8253timerset(uvlong);
 int	i8259disable(int);
--- a/sys/src/9/pc/i8253.c
+++ b/sys/src/9/pc/i8253.c
@@ -62,8 +62,6 @@
 {
 	Lock;
 	ulong	period;		/* current clock period */
-	int	enabled;
-	uvlong	hz;
 
 	ushort	last;		/* last value of clock 1 */
 	uvlong	ticks;		/* cumulative ticks of counter 1 */
@@ -70,16 +68,16 @@
 
 	ulong	periodset;
 };
-I8253 i8253;
+static I8253 i8253;
 
 void
-i8253init(void)
+i8253reset(void)
 {
 	int loops, x;
 
-	ioalloc(T0cntr, 4, 0, "i8253");
-	ioalloc(T2ctl, 1, 0, "i8253.cntr2ctl");
+	ilock(&i8253);
 
+	i8253.last = 0;
 	i8253.period = Freq/HZ;
 
 	/*
@@ -113,19 +111,27 @@
 		x = inb(T0cntr);
 		x |= inb(T0cntr)<<8;
 	}
+
+	iunlock(&i8253);
 }
 
 void
+i8253init(void)
+{
+	ioalloc(T0cntr, 4, 0, "i8253");
+	ioalloc(T2ctl, 1, 0, "i8253.cntr2ctl");
+
+	i8253reset();
+}
+
+void
 guesscpuhz(int aalcycles)
 {
-	int loops, incr, x, y;
+	int loops, x, y;
 	uvlong a, b, cpufreq;
 
-	/* find biggest loop that doesn't wrap */
-	incr = 16000000/(aalcycles*HZ*2);
-	x = 2000;
-	for(loops = incr; loops < 64*1024; loops += incr) {
-	
+	ilock(&i8253);
+	for(loops = 1000;;loops += 1000) {
 		/*
 		 *  measure time for the loop
 		 *
@@ -138,57 +144,52 @@
 		 *  prefetch buffer.
 		 *
 		 */
-		outb(Tmode, Latch0);
+		outb(Tmode, Latch2);
 		cycles(&a);
-		x = inb(T0cntr);
-		x |= inb(T0cntr)<<8;
+		x = inb(T2cntr);
+		x |= inb(T2cntr)<<8;
 		aamloop(loops);
-		outb(Tmode, Latch0);
+		outb(Tmode, Latch2);
 		cycles(&b);
-		y = inb(T0cntr);
-		y |= inb(T0cntr)<<8;
+		y = inb(T2cntr);
+		y |= inb(T2cntr)<<8;
+
 		x -= y;
-	
 		if(x < 0)
-			x += Freq/HZ;
+			x += 0x10000;
 
-		if(x > Freq/(3*HZ))
+		if(x >= MaxPeriod || loops >= 1000000)
 			break;
 	}
+	iunlock(&i8253);
 
+	/* avoid division by zero on vmware 7 */
+	if(x == 0)
+		x = 1;
+
 	/*
  	 *  figure out clock frequency and a loop multiplier for delay().
 	 *  n.b. counter goes up by 2*Freq
 	 */
-	if(x == 0)
-		x = 1;			/* avoid division by zero on vmware 7 */
 	cpufreq = (vlong)loops*((aalcycles*2*Freq)/x);
 	m->loopconst = (cpufreq/1000)/aalcycles;	/* AAM+LOOP's for 1 ms */
 
-	if(m->havetsc && a != b){  /* a == b means virtualbox has confused us */
-		/* counter goes up by 2*Freq */
-		b = (b-a)<<1;
-		b *= Freq;
+	/* a == b means virtualbox has confused us */
+	if(m->havetsc && b > a){
+		b -= a;
+		b *= 2*Freq;
 		b /= x;
-
-		/*
-		 *  round to the nearest megahz
-		 */
-		m->cpumhz = (b+500000)/1000000L;
-		m->cpuhz = b;
 		m->cyclefreq = b;
-	} else {
-		/*
-		 *  add in possible 0.5% error and convert to MHz
-		 */
-		m->cpumhz = (cpufreq + cpufreq/200)/1000000;
-		m->cpuhz = cpufreq;
+		cpufreq = b;
 	}
+	m->cpuhz = cpufreq;
 
-	/* don't divide by zero in trap.c */
+	/*
+	 *  round to the nearest megahz
+	 */
+	m->cpumhz = (cpufreq+500000)/1000000L;
 	if(m->cpumhz == 0)
-		panic("guesscpuhz: zero m->cpumhz");
-	i8253.hz = Freq<<Tickshift;
+		m->cpumhz = 1;
 }
 
 void
@@ -216,7 +217,7 @@
 		/* load new value */
 		outb(Tmode, Load0|Square);
 		outb(T0cntr, period);		/* low byte */
-		outb(T0cntr, period >> 8);		/* high byte */
+		outb(T0cntr, period >> 8);	/* high byte */
 
 		/* remember period */
 		i8253.period = period;
@@ -234,8 +235,6 @@
 void
 i8253enable(void)
 {
-	i8253.enabled = 1;
-	i8253.period = Freq/HZ;
 	intrenable(IrqCLOCK, i8253clock, 0, BUSUNKNOWN, "clock");
 }
 
@@ -251,7 +250,7 @@
 	uvlong ticks;
 
 	if(hz)
-		*hz = i8253.hz;
+		*hz = Freq<<Tickshift;
 
 	ilock(&i8253);
 	outb(Tmode, Latch2);
--