diff options
author | cinap_lenrek <cinap_lenrek@felloff.net> | 2021-01-17 21:21:12 +0100 |
---|---|---|
committer | cinap_lenrek <cinap_lenrek@felloff.net> | 2021-01-17 21:21:12 +0100 |
commit | a05bab362f66ddd6fa65f2e7cda9eaaa0217ec08 (patch) | |
tree | ccd2fdef5230d2d5369619e6e7f84b389928ad3d /sys | |
parent | 999e98b9b856ae4fc75b3ad33783488e33cdd426 (diff) |
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).
Diffstat (limited to 'sys')
-rw-r--r-- | sys/src/9/pc/archacpi.c | 58 | ||||
-rw-r--r-- | sys/src/9/pc/archgeneric.c | 36 | ||||
-rw-r--r-- | sys/src/9/pc/dat.h | 2 | ||||
-rw-r--r-- | sys/src/9/pc/devarch.c | 15 | ||||
-rw-r--r-- | sys/src/9/pc/fns.h | 1 | ||||
-rw-r--r-- | sys/src/9/pc/hpet.c | 126 | ||||
-rw-r--r-- | sys/src/9/pc/i8253.c | 99 | ||||
-rw-r--r-- | sys/src/9/pc/main.c | 3 | ||||
-rw-r--r-- | sys/src/9/pc/pc | 2 | ||||
-rw-r--r-- | sys/src/9/pc/squidboy.c | 2 | ||||
-rw-r--r-- | sys/src/9/pc64/dat.h | 2 | ||||
-rw-r--r-- | sys/src/9/pc64/fns.h | 1 | ||||
-rw-r--r-- | sys/src/9/pc64/main.c | 3 | ||||
-rw-r--r-- | sys/src/9/pc64/pc64 | 2 | ||||
-rw-r--r-- | sys/src/9/pc64/squidboy.c | 2 | ||||
-rw-r--r-- | sys/src/9/xen/archxen.c | 10 | ||||
-rw-r--r-- | sys/src/9/xen/fns.h | 1 | ||||
-rw-r--r-- | sys/src/9/xen/main.c | 2 | ||||
-rw-r--r-- | sys/src/9/xen/xentimer.c | 2 |
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; |