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; isig, 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; isig, "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; isig, "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; /* @@ -559,11 +558,6 @@ cpuidentify(void) wrmsr(0x10, 0); } - /* - * 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. @@ -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<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;