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);
--
⑨