summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcinap_lenrek <cinap_lenrek@felloff.net>2021-01-17 21:21:12 +0100
committercinap_lenrek <cinap_lenrek@felloff.net>2021-01-17 21:21:12 +0100
commita05bab362f66ddd6fa65f2e7cda9eaaa0217ec08 (patch)
treeccd2fdef5230d2d5369619e6e7f84b389928ad3d
parent999e98b9b856ae4fc75b3ad33783488e33cdd426 (diff)
downloadplan9front-a05bab362f66ddd6fa65f2e7cda9eaaa0217ec08.tar.xz
pc, pc64: add minimal HPET driver to measure LAPIC and TSC frequencies
This adds the new function pointer PCArch.clockinit(), which is a timer dependent initialization routine. It also takes over the job of guesscpuhz(). This way, the architecture ident code can switch between different timers (i8253, HPET and XEN timer).
-rw-r--r--sys/src/9/pc/archacpi.c58
-rw-r--r--sys/src/9/pc/archgeneric.c36
-rw-r--r--sys/src/9/pc/dat.h2
-rw-r--r--sys/src/9/pc/devarch.c15
-rw-r--r--sys/src/9/pc/fns.h1
-rw-r--r--sys/src/9/pc/hpet.c126
-rw-r--r--sys/src/9/pc/i8253.c99
-rw-r--r--sys/src/9/pc/main.c3
-rw-r--r--sys/src/9/pc/pc2
-rw-r--r--sys/src/9/pc/squidboy.c2
-rw-r--r--sys/src/9/pc64/dat.h2
-rw-r--r--sys/src/9/pc64/fns.h1
-rw-r--r--sys/src/9/pc64/main.c3
-rw-r--r--sys/src/9/pc64/pc642
-rw-r--r--sys/src/9/pc64/squidboy.c2
-rw-r--r--sys/src/9/xen/archxen.c10
-rw-r--r--sys/src/9/xen/fns.h1
-rw-r--r--sys/src/9/xen/main.c2
-rw-r--r--sys/src/9/xen/xentimer.c2
19 files changed, 259 insertions, 110 deletions
diff --git a/sys/src/9/pc/archacpi.c b/sys/src/9/pc/archacpi.c
index 560dc93a9..01c911468 100644
--- a/sys/src/9/pc/archacpi.c
+++ b/sys/src/9/pc/archacpi.c
@@ -180,6 +180,20 @@ maptables(void)
}
}
+static Tbl*
+findtable(char sig[4])
+{
+ Tbl *t;
+ int i;
+
+ for(i=0; i<ntblmap; i++){
+ t = tblmap[i];
+ if(memcmp(t->sig, sig, 4) == 0)
+ return t;
+ }
+ return nil;
+}
+
static Apic*
findapic(int gsi, int *pintin)
{
@@ -569,13 +583,9 @@ acpiinit(void)
amlinit();
/* load DSDT */
- for(i=0; i<ntblmap; i++){
- t = tblmap[i];
- if(memcmp(t->sig, "DSDT", 4) == 0){
- amlintmask = (~0ULL) >> (t->rev <= 1)*32;
- amlload(t->data, tbldlen(t));
- break;
- }
+ if((t = findtable("DSDT")) != nil){
+ amlintmask = (~0ULL) >> (t->rev <= 1)*32;
+ amlload(t->data, tbldlen(t));
}
/* load SSDT, there can be multiple tables */
@@ -588,15 +598,10 @@ acpiinit(void)
/* set APIC mode */
amleval(amlwalk(amlroot, "_PIC"), "i", 1, nil);
- for(i=0; i<ntblmap; i++){
- t = tblmap[i];
- if(memcmp(t->sig, "APIC", 4) == 0)
- goto Foundapic;
- }
- panic("acpiinit: no MADT (APIC) table");
- return;
+ t = findtable("APIC");
+ if(t == nil)
+ panic("acpiinit: no MADT (APIC) table");
-Foundapic:
s = t->data;
e = s + tbldlen(t);
lapicbase = get32(s); s += 8;
@@ -708,16 +713,12 @@ acpireset(void)
{
uchar *p;
Tbl *t;
- int i;
/* stop application processors */
mpshutdown();
/* locate and write platform reset register */
- for(i=0; i < ntblmap; i++){
- t = tblmap[i];
- if(memcmp(t->sig, "FACP", 4) != 0)
- continue;
+ while((t = findtable("FACP")) != nil){
if(get32(t->len) <= 128)
break;
p = (uchar*)t;
@@ -735,6 +736,11 @@ acpireset(void)
static int identify(void);
extern int i8259irqno(int, int);
+extern void i8253init(void);
+
+extern int hpetprobe(uvlong);
+extern void hpetinit(void);
+extern uvlong hpetread(uvlong*);
PCArch archacpi = {
.id= "ACPI",
@@ -745,6 +751,7 @@ PCArch archacpi = {
.intrirqno= i8259irqno,
.intron= lapicintron,
.introff= lapicintroff,
+.clockinit= i8253init,
.fastclock= i8253read,
.timerset= lapictimerset,
};
@@ -782,6 +789,7 @@ identify(void)
{
uvlong pa;
char *cp;
+ Tbl *t;
if((cp = getconf("*acpi")) == nil)
return 1;
@@ -799,12 +807,20 @@ identify(void)
maptables();
addarchfile("acpitbls", 0444, readtbls, nil);
addarchfile("acpimem", 0600, readmem, writemem);
- if(strcmp(cp, "0") == 0)
+ if(strcmp(cp, "0") == 0 || findtable("APIC") == nil)
return 1;
if((cp = getconf("*nomp")) != nil && strcmp(cp, "0") != 0)
return 1;
+ if(getconf("*nohpet") == nil
+ && (t = findtable("HPET")) != nil
+ && ((uchar*)t)[40] == 0
+ && hpetprobe(get64((uchar*)t+44)) == 0){
+ archacpi.clockinit = hpetinit;
+ archacpi.fastclock = hpetread;
+ }
if(m->havetsc && getconf("*notsc") == nil)
archacpi.fastclock = tscticks;
+
return 0;
}
diff --git a/sys/src/9/pc/archgeneric.c b/sys/src/9/pc/archgeneric.c
index e51bf7ad7..dda06c196 100644
--- a/sys/src/9/pc/archgeneric.c
+++ b/sys/src/9/pc/archgeneric.c
@@ -40,6 +40,41 @@ archreset(void)
idle();
}
+void
+delay(int millisecs)
+{
+ millisecs *= m->loopconst;
+ if(millisecs <= 0)
+ millisecs = 1;
+ aamloop(millisecs);
+}
+
+void
+microdelay(int microsecs)
+{
+ microsecs *= m->loopconst;
+ microsecs /= 1000;
+ if(microsecs <= 0)
+ microsecs = 1;
+ aamloop(microsecs);
+}
+
+/*
+ * performance measurement ticks. must be low overhead.
+ * doesn't have to count over a second.
+ */
+ulong
+perfticks(void)
+{
+ uvlong x;
+
+ if(m->havetsc)
+ cycles(&x);
+ else
+ x = 0;
+ return x;
+}
+
PCArch archgeneric = {
.id= "generic",
.ident= 0,
@@ -53,6 +88,7 @@ PCArch archgeneric = {
.intron= i8259on,
.introff= i8259off,
+.clockinit= i8253init,
.clockenable= i8253enable,
.fastclock= i8253read,
.timerset= i8253timerset,
diff --git a/sys/src/9/pc/dat.h b/sys/src/9/pc/dat.h
index 6d1ff430e..ab9e4b1c7 100644
--- a/sys/src/9/pc/dat.h
+++ b/sys/src/9/pc/dat.h
@@ -229,6 +229,7 @@ struct Mach
int lastintr;
int loopconst;
+ int aalcycles;
int cpumhz;
uvlong cyclefreq; /* Frequency of user readable cycle counter */
@@ -289,6 +290,7 @@ struct PCArch
void (*introff)(void);
void (*intron)(void);
+ void (*clockinit)(void);
void (*clockenable)(void);
uvlong (*fastclock)(uvlong*);
void (*timerset)(uvlong);
diff --git a/sys/src/9/pc/devarch.c b/sys/src/9/pc/devarch.c
index 4058808f5..3276a7a97 100644
--- a/sys/src/9/pc/devarch.c
+++ b/sys/src/9/pc/devarch.c
@@ -461,8 +461,6 @@ static X86type x86sis[] =
{ -1, -1, 23, "unknown", }, /* total default */
};
-static X86type *cputype;
-
static void simplecycles(uvlong*);
void (*cycles)(uvlong*) = simplecycles;
void _cycles(uvlong*); /* in l.s */
@@ -547,6 +545,7 @@ cpuidentify(void)
|| (t->family == -1))
break;
+ m->aalcycles = t->aalcycles;
m->cpuidtype = t->name;
/*
@@ -560,11 +559,6 @@ cpuidentify(void)
}
/*
- * use i8253 to guess our cpu speed
- */
- guesscpuhz(t->aalcycles);
-
- /*
* If machine check exception, page size extensions or page global bit
* are supported enable them in CR4 and clear any other set extensions.
* If machine check was enabled clear out any lingering status.
@@ -690,7 +684,6 @@ cpuidentify(void)
fpuinit();
- cputype = t;
return t->family;
}
@@ -702,7 +695,7 @@ cputyperead(Chan*, void *a, long n, vlong offset)
mhz = (m->cpuhz+999999)/1000000;
- snprint(str, sizeof(str), "%s %lud\n", cputype->name, mhz);
+ snprint(str, sizeof(str), "%s %lud\n", m->cpuidtype, mhz);
return readstr(offset, a, n, str);
}
@@ -715,7 +708,7 @@ archctlread(Chan*, void *a, long nn, vlong offset)
p = buf = smalloc(READSTR);
ep = p + READSTR;
p = seprint(p, ep, "cpu %s %lud%s\n",
- cputype->name, (ulong)(m->cpuhz+999999)/1000000,
+ m->cpuidtype, (ulong)(m->cpuhz+999999)/1000000,
m->havepge ? " pge" : "");
p = seprint(p, ep, "pge %s\n", getcr4()&0x80 ? "on" : "off");
p = seprint(p, ep, "coherence ");
@@ -877,6 +870,8 @@ archinit(void)
arch->intrinit = knownarch[0]->intrinit;
if(arch->intrassign == nil)
arch->intrassign = knownarch[0]->intrassign;
+ if(arch->clockinit == nil)
+ arch->clockinit = knownarch[0]->clockinit;
}
/*
diff --git a/sys/src/9/pc/fns.h b/sys/src/9/pc/fns.h
index e19b6d3aa..436bb4817 100644
--- a/sys/src/9/pc/fns.h
+++ b/sys/src/9/pc/fns.h
@@ -51,7 +51,6 @@ ulong getcr3(void);
ulong getcr4(void);
u32int getdr6(void);
char* getconf(char*);
-void guesscpuhz(int);
void halt(void);
void mwait(void*);
int i8042auxcmd(int);
diff --git a/sys/src/9/pc/hpet.c b/sys/src/9/pc/hpet.c
new file mode 100644
index 000000000..dba90ce44
--- /dev/null
+++ b/sys/src/9/pc/hpet.c
@@ -0,0 +1,126 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+
+/*
+ * HPET timer
+ *
+ * The HPET timer is memory mapped which allows
+ * faster access compared to the classic i8253.
+ * This timer is not used to generate interrupts
+ * as we use the LAPIC timer for that.
+ * Its purpose is to measure the LAPIC timer
+ * and TSC frequencies.
+ */
+
+enum {
+ Cap = 0x00/4,
+ Period = 0x04/4,
+ Config = 0x10/4,
+ Isr = 0x20/4,
+ Ctrlo = 0xF0/4,
+ Ctrhi = 0xF4/4,
+};
+
+static struct {
+ Lock;
+ u32int *mmio;
+ uvlong last;
+ uvlong freq;
+} hpet;
+
+int
+hpetprobe(uvlong pa)
+{
+ u32int cap, period;
+ int mhz;
+
+ if((hpet.mmio = vmap(pa, 1024)) == nil)
+ return -1;
+ cap = hpet.mmio[Cap];
+ period = hpet.mmio[Period];
+ if(period == 0 || period > 0x05F4E100)
+ return -1;
+ hpet.freq = 1000000000000000ULL / period;
+ mhz = (hpet.freq + 500000) / 1000000;
+
+ print("HPET: %llux %.8ux %d MHz \n", pa, cap, mhz);
+
+ return 0;
+}
+
+static uvlong
+hpetcpufreq(void)
+{
+ u32int x, y;
+ uvlong a, b;
+ int loops;
+
+ ilock(&hpet);
+ for(loops = 1000;;loops += 1000){
+ cycles(&a);
+ x = hpet.mmio[Ctrlo];
+ aamloop(loops);
+ cycles(&b);
+ y = hpet.mmio[Ctrlo] - x;
+ if(y >= hpet.freq/HZ || loops >= 1000000)
+ break;
+ }
+ iunlock(&hpet);
+
+ if(m->havetsc && b > a){
+ b -= a;
+ m->cyclefreq = b * hpet.freq / y;
+ m->aalcycles = (b + loops-1) / loops;
+ return m->cyclefreq;
+ }
+ return (vlong)loops*m->aalcycles * hpet.freq / y;
+}
+
+void
+hpetinit(void)
+{
+ uvlong cpufreq;
+
+ if(m->machno != 0){
+ m->cpuhz = MACHP(0)->cpuhz;
+ m->cpumhz = MACHP(0)->cpumhz;
+ m->cyclefreq = MACHP(0)->cyclefreq;
+ m->loopconst = MACHP(0)->loopconst;
+ return;
+ }
+
+ /* start counting */
+ hpet.mmio[Config] |= 1;
+
+ /* measure loopconst for delay() and tsc frequencies */
+ cpufreq = hpetcpufreq();
+
+ m->loopconst = (cpufreq/1000)/m->aalcycles; /* AAM+LOOP's for 1 ms */
+ m->cpuhz = cpufreq;
+
+ /* round to the nearest megahz */
+ m->cpumhz = (cpufreq+500000)/1000000L;
+ if(m->cpumhz == 0)
+ m->cpumhz = 1;
+}
+
+uvlong
+hpetread(uvlong *hz)
+{
+ uvlong ticks;
+
+ if(hz != nil)
+ *hz = hpet.freq;
+
+ ilock(&hpet);
+ ticks = hpet.last;
+ ticks += hpet.mmio[Ctrlo] - (u32int)ticks;
+ hpet.last = ticks;
+ iunlock(&hpet);
+
+ return ticks;
+}
diff --git a/sys/src/9/pc/i8253.c b/sys/src/9/pc/i8253.c
index 586f2387b..a56c2ddc5 100644
--- a/sys/src/9/pc/i8253.c
+++ b/sys/src/9/pc/i8253.c
@@ -115,28 +115,11 @@ i8253reset(void)
iunlock(&i8253);
}
-void
-i8253init(void)
-{
- ioalloc(T0cntr, 4, 0, "i8253");
- ioalloc(T2ctl, 1, 0, "i8253.cntr2ctl");
-
- i8253reset();
-}
-
-void
-guesscpuhz(int aalcycles)
+static uvlong
+i8253cpufreq(void)
{
int loops, x, y;
- uvlong a, b, cpufreq;
-
- if(m->machno != 0){
- m->cpuhz = MACHP(0)->cpuhz;
- m->cpumhz = MACHP(0)->cpumhz;
- m->cyclefreq = MACHP(0)->cyclefreq;
- m->loopconst = MACHP(0)->loopconst;
- return;
- }
+ uvlong a, b;
ilock(&i8253);
for(loops = 1000;;loops += 1000) {
@@ -175,21 +158,38 @@ guesscpuhz(int aalcycles)
if(x == 0)
x = 1;
- /*
- * figure out clock frequency and a loop multiplier for delay().
- * n.b. counter goes up by 2*Freq
- */
- cpufreq = (vlong)loops*((aalcycles*2*Freq)/x);
- m->loopconst = (cpufreq/1000)/aalcycles; /* AAM+LOOP's for 1 ms */
-
- /* a == b means virtualbox has confused us */
if(m->havetsc && b > a){
b -= a;
- b *= 2*Freq;
- b /= x;
- m->cyclefreq = b;
- cpufreq = b;
+ m->cyclefreq = b * 2*Freq / x;
+ m->aalcycles = (b + loops-1) / loops;
+
+ return m->cyclefreq;
+ }
+
+ return (vlong)loops*m->aalcycles * 2*Freq / x;
+}
+
+void
+i8253init(void)
+{
+ uvlong cpufreq;
+
+ if(m->machno != 0){
+ m->cpuhz = MACHP(0)->cpuhz;
+ m->cpumhz = MACHP(0)->cpumhz;
+ m->cyclefreq = MACHP(0)->cyclefreq;
+ m->loopconst = MACHP(0)->loopconst;
+ return;
}
+
+ ioalloc(T0cntr, 4, 0, "i8253");
+ ioalloc(T2ctl, 1, 0, "i8253.cntr2ctl");
+
+ i8253reset();
+
+ cpufreq = i8253cpufreq();
+
+ m->loopconst = (cpufreq/1000)/m->aalcycles; /* AAM+LOOP's for 1 ms */
m->cpuhz = cpufreq;
/*
@@ -281,38 +281,3 @@ i8253read(uvlong *hz)
return ticks<<Tickshift;
}
-
-void
-delay(int millisecs)
-{
- millisecs *= m->loopconst;
- if(millisecs <= 0)
- millisecs = 1;
- aamloop(millisecs);
-}
-
-void
-microdelay(int microsecs)
-{
- microsecs *= m->loopconst;
- microsecs /= 1000;
- if(microsecs <= 0)
- microsecs = 1;
- aamloop(microsecs);
-}
-
-/*
- * performance measurement ticks. must be low overhead.
- * doesn't have to count over a second.
- */
-ulong
-perfticks(void)
-{
- uvlong x;
-
- if(m->havetsc)
- cycles(&x);
- else
- x = 0;
- return x;
-}
diff --git a/sys/src/9/pc/main.c b/sys/src/9/pc/main.c
index bb2e8ac7d..d59c200a1 100644
--- a/sys/src/9/pc/main.c
+++ b/sys/src/9/pc/main.c
@@ -31,10 +31,11 @@ main(void)
quotefmtinstall();
screeninit();
print("\nPlan 9\n");
- i8253init();
cpuidentify();
meminit0();
archinit();
+ if(arch->clockinit)
+ arch->clockinit();
meminit();
ramdiskinit();
confinit();
diff --git a/sys/src/9/pc/pc b/sys/src/9/pc/pc
index 1b45434b1..4d242b2ed 100644
--- a/sys/src/9/pc/pc
+++ b/sys/src/9/pc/pc
@@ -97,7 +97,7 @@ misc
pci pcipc
archgeneric devkbd i8259 i8253
- archacpi mp apic squidboy ec
+ archacpi mp apic squidboy ec hpet
archmp mp apic squidboy
mtrr
diff --git a/sys/src/9/pc/squidboy.c b/sys/src/9/pc/squidboy.c
index 7a3501221..6ffccd783 100644
--- a/sys/src/9/pc/squidboy.c
+++ b/sys/src/9/pc/squidboy.c
@@ -15,6 +15,8 @@ squidboy(Apic* apic)
machinit();
mmuinit();
cpuidentify();
+ if(arch->clockinit)
+ arch->clockinit();
cpuidprint();
syncclock();
active.machs[m->machno] = 1;
diff --git a/sys/src/9/pc64/dat.h b/sys/src/9/pc64/dat.h
index b597f8988..1d581f371 100644
--- a/sys/src/9/pc64/dat.h
+++ b/sys/src/9/pc64/dat.h
@@ -221,6 +221,7 @@ struct Mach
int lastintr;
int loopconst;
+ int aalcycles;
int cpumhz;
uvlong cyclefreq; /* Frequency of user readable cycle counter */
@@ -278,6 +279,7 @@ struct PCArch
void (*introff)(void);
void (*intron)(void);
+ void (*clockinit)(void);
void (*clockenable)(void);
uvlong (*fastclock)(uvlong*);
void (*timerset)(uvlong);
diff --git a/sys/src/9/pc64/fns.h b/sys/src/9/pc64/fns.h
index 90d831e3a..01a1959d3 100644
--- a/sys/src/9/pc64/fns.h
+++ b/sys/src/9/pc64/fns.h
@@ -52,7 +52,6 @@ u64int getcr4(void);
u64int getxcr0(void);
u64int getdr6(void);
char* getconf(char*);
-void guesscpuhz(int);
void halt(void);
void mwait(void*);
int i8042auxcmd(int);
diff --git a/sys/src/9/pc64/main.c b/sys/src/9/pc64/main.c
index e68220d5f..17a766137 100644
--- a/sys/src/9/pc64/main.c
+++ b/sys/src/9/pc64/main.c
@@ -183,10 +183,11 @@ main(void)
quotefmtinstall();
screeninit();
print("\nPlan 9\n");
- i8253init();
cpuidentify();
meminit0();
archinit();
+ if(arch->clockinit)
+ arch->clockinit();
meminit();
ramdiskinit();
confinit();
diff --git a/sys/src/9/pc64/pc64 b/sys/src/9/pc64/pc64
index ed3c76e7a..3250e9a45 100644
--- a/sys/src/9/pc64/pc64
+++ b/sys/src/9/pc64/pc64
@@ -94,7 +94,7 @@ link
misc
pci pcipc
archgeneric devkbd i8259 i8253
- archacpi mp apic squidboy ec
+ archacpi mp apic squidboy ec hpet
archmp mp apic squidboy
mtrr
diff --git a/sys/src/9/pc64/squidboy.c b/sys/src/9/pc64/squidboy.c
index dda4f257f..f7882820b 100644
--- a/sys/src/9/pc64/squidboy.c
+++ b/sys/src/9/pc64/squidboy.c
@@ -16,6 +16,8 @@ squidboy(Apic* apic)
machinit();
mmuinit();
cpuidentify();
+ if(arch->clockinit)
+ arch->clockinit();
cpuidprint();
syncclock();
active.machs[m->machno] = 1;
diff --git a/sys/src/9/xen/archxen.c b/sys/src/9/xen/archxen.c
index 6f3d1bfae..0e30e6591 100644
--- a/sys/src/9/xen/archxen.c
+++ b/sys/src/9/xen/archxen.c
@@ -52,10 +52,11 @@ shutdown(void)
HYPERVISOR_shutdown(1);
}
-int xenintrassign(Vctl *v);
-void xentimerenable(void);
-uvlong xentimerread(uvlong*);
-void xentimerset(uvlong);
+extern int xenintrassign(Vctl *v);
+extern void xentimerinit(void);
+extern void xentimerenable(void);
+extern uvlong xentimerread(uvlong*);
+extern void xentimerset(uvlong);
PCArch archxen = {
.id= "Xen",
@@ -63,6 +64,7 @@ PCArch archxen = {
.reset= shutdown,
.intrinit= intrinit,
.intrassign= xenintrassign,
+.clockinit= xentimerinit,
.clockenable= xentimerenable,
.fastclock= xentimerread,
.timerset= xentimerset,
diff --git a/sys/src/9/xen/fns.h b/sys/src/9/xen/fns.h
index 32a101935..3013d5f4a 100644
--- a/sys/src/9/xen/fns.h
+++ b/sys/src/9/xen/fns.h
@@ -27,7 +27,6 @@ void (*fprestore)(FPsave*);
void (*fpsave)(FPsave*);
ulong getcr4(void);
char* getconf(char*);
-void guesscpuhz(int);
void halt(void);
void mwait(void*);
void i8042reset(void);
diff --git a/sys/src/9/xen/main.c b/sys/src/9/xen/main.c
index 61bf5bf4c..32fac0679 100644
--- a/sys/src/9/xen/main.c
+++ b/sys/src/9/xen/main.c
@@ -76,6 +76,8 @@ main(void)
// meminit() is not for us
confinit();
archinit();
+ if(arch->clockinit)
+ arch->clockinit();
xinit();
trapinit();
printinit();
diff --git a/sys/src/9/xen/xentimer.c b/sys/src/9/xen/xentimer.c
index 4e6a2715e..eb480ffd0 100644
--- a/sys/src/9/xen/xentimer.c
+++ b/sys/src/9/xen/xentimer.c
@@ -34,7 +34,7 @@ getshadow(void)
/* just get it from the shared info */
void
-guesscpuhz(int) // XXX no arg!
+xentimerinit(void)
{
vcpu_time_info_t *t;