summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sys/src/9/pc/apm.c11
-rw-r--r--sys/src/9/pc/fns.h1
-rw-r--r--sys/src/9/pc/i8253.c91
3 files changed, 56 insertions, 47 deletions
diff --git a/sys/src/9/pc/apm.c b/sys/src/9/pc/apm.c
index 0ad1210d5..c0a0ce386 100644
--- a/sys/src/9/pc/apm.c
+++ b/sys/src/9/pc/apm.c
@@ -83,13 +83,22 @@ apmread(Chan*, void *a, long n, vlong off)
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;
}
diff --git a/sys/src/9/pc/fns.h b/sys/src/9/pc/fns.h
index e9e899f03..5024723b2 100644
--- a/sys/src/9/pc/fns.h
+++ b/sys/src/9/pc/fns.h
@@ -54,6 +54,7 @@ void i8250mouse(char*, int (*)(Queue*, int), int);
void i8250setmouseputc(char*, int (*)(Queue*, int));
void i8253enable(void);
void i8253init(void);
+void i8253reset(void);
uvlong i8253read(uvlong*);
void i8253timerset(uvlong);
int i8259disable(int);
diff --git a/sys/src/9/pc/i8253.c b/sys/src/9/pc/i8253.c
index 04af79edb..1ae22615f 100644
--- a/sys/src/9/pc/i8253.c
+++ b/sys/src/9/pc/i8253.c
@@ -62,24 +62,22 @@ struct I8253
{
Lock;
ulong period; /* current clock period */
- int enabled;
- uvlong hz;
ushort last; /* last value of clock 1 */
uvlong ticks; /* cumulative ticks of counter 1 */
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 @@ i8253init(void)
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 @@ guesscpuhz(int aalcycles)
* 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 @@ i8253timerset(uvlong next)
/* 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 @@ i8253clock(Ureg* ureg, void*)
void
i8253enable(void)
{
- i8253.enabled = 1;
- i8253.period = Freq/HZ;
intrenable(IrqCLOCK, i8253clock, 0, BUSUNKNOWN, "clock");
}
@@ -251,7 +250,7 @@ i8253read(uvlong *hz)
uvlong ticks;
if(hz)
- *hz = i8253.hz;
+ *hz = Freq<<Tickshift;
ilock(&i8253);
outb(Tmode, Latch2);