thanks to gorka for helping me debug this! for some reason the intel hz detection has reverted. i believe this same code was merged back in the codereview days. the intel application note (or whatever it's called) recommends that one detect the processor hz by reading the processor brand string. this code should work on almost any modern intel processor. Reference: /n/patches.lsub.org/patch/intelhz Date: Sat Jun 30 04:07:29 CES 2012 Signed-off-by: quanstro@quanstro.net --- /sys/src/nix/k10/archk10.c Thu Apr 12 12:26:27 2012 +++ /sys/src/nix/k10/archk10.c Fri Jun 29 21:28:50 2012 @@ -55,110 +55,67 @@ return 1; } +/* use intel brand string to discover hz */ +static vlong +intelbshz(void) +{ + char s[4*4*3+1], *p, *h; + int i, j; + u32int r[4]; + uvlong scale; + + p = s; + for(i = 0; i < 3; i++){ + if(!cpuidinfo(0x80000002+i, 0, r)) + return 0; + for(j = 0; j < 4; j++){ + memmove(p, r+j, 4); + p += 4; + } + } + *p = 0; + DBG("brandstring: %s\n", s); + + h = strstr(s, "Hz"); /* 3.07THz */ + if(h == nil || h-s < 5) + return 0; + h[2] = 0; + + scale = 1000; + switch(h[-1]){ + default: + return 0; + case 'T': + scale *= 1000; + case 'G': + scale *= 1000; + case 'M': + scale *= 1000; + } + + /* get rid of the fractional part */ + if(h[-4] == '.'){ + h[-4] = h[-5]; + h[-5] = ' '; + scale /= 100; + } + return atoi(h-5)*scale; +} + static vlong cpuidhz(u32int info[2][4]) { - int f, r; + int r; vlong hz; u64int msr; if(memcmp(&info[0][1], "GenuntelineI", 12) == 0){ switch(info[1][0] & 0x0fff3ff0){ default: - return 0; - case 0x00000f30: /* Xeon (MP), Pentium [4D] */ - case 0x00000f40: /* Xeon (MP), Pentium [4D] */ - case 0x00000f60: /* Xeon 7100, 5000 or above */ - msr = rdmsr(0x2c); - r = (msr>>16) & 0x07; - switch(r){ - default: - return 0; - case 0: - hz = 266666666666ll; - break; - case 1: - hz = 133333333333ll; - break; - case 2: - hz = 200000000000ll; - break; - case 3: - hz = 166666666666ll; - break; - case 4: - hz = 333333333333ll; - break; - } - - /* - * Hz is *1000 at this point. - * Do the scaling then round it. - * The manual is conflicting about - * the size of the msr field. - */ - hz = (((hz*(msr>>24))/100)+5)/10; - break; - case 0x00000690: /* Pentium M, Celeron M */ - case 0x000006d0: /* Pentium M, Celeron M */ - hz = ((rdmsr(0x2a)>>22) & 0x1f)*100 * 1000000ll; - break; - case 0x000006e0: /* Core Duo */ - case 0x000006f0: /* Core 2 Duo/Quad/Extreme */ - case 0x00010670: /* Core 2 Extreme */ - case 0x000006a0: /* i7 paurea... */ - /* - * Get the FSB frequemcy. - * If processor has Enhanced Intel Speedstep Technology - * then non-integer bus frequency ratios are possible. - */ - if(info[1][2] & 0x00000080){ - msr = rdmsr(0x198); - r = (msr>>40) & 0x1f; - } - else{ - msr = 0; - r = rdmsr(0x2a) & 0x1f; - } - f = rdmsr(0xcd) & 0x07; - switch(f){ - default: - return 0; - case 5: - hz = 100000000000ll; - break; - case 1: - hz = 133333333333ll; - break; - case 3: - hz = 166666666666ll; - break; - case 2: - hz = 200000000000ll; - break; - case 0: - hz = 266666666666ll; - break; - case 4: - hz = 333333333333ll; - break; - case 6: - hz = 400000000000ll; - break; - } - - /* - * Hz is *1000 at this point. - * Do the scaling then round it. - */ - if(msr & 0x0000400000000000ll) - hz = hz*r + hz/2; - else - hz = hz*r; - hz = ((hz/100)+5)/10; + hz = intelbshz(); break; } - DBG("cpuidhz: 0x2a: %#llux hz %lld\n", rdmsr(0x2a), hz); + DBG("cpuidhz: %#llux hz\n", hz); } else if(memcmp(&info[0][1], "AuthcAMDenti", 12) == 0){ switch(info[1][0] & 0x0fff0ff0){ @@ -185,42 +142,22 @@ return hz; } -void -cpuiddump(void) -{ - int i; - u32int info[4]; - - if(!DBGFLG) - return; - - if(m->ncpuinfos == 0 && cpuidinit() == 0) - return; - - for(i = 0; i < m->ncpuinfos; i++){ - cpuid(i, 0, info); - DBG("eax = %#8.8ux: %8.8ux %8.8ux %8.8ux %8.8ux\n", - i, info[0], info[1], info[2], info[3]); - } - for(i = 0; i < m->ncpuinfoe; i++){ - cpuid(0x80000000|i, 0, info); - DBG("eax = %#8.8ux: %8.8ux %8.8ux %8.8ux %8.8ux\n", - 0x80000000|i, info[0], info[1], info[2], info[3]); - } -} - vlong archhz(void) { vlong hz; u32int info[2][4]; - if(!cpuidinfo(0, 0, info[0]) || !cpuidinfo(1, 0, info[1])) + if(!cpuidinfo(0, 0, info[0]) || !cpuidinfo(1, 0, info[1])){ + print("cpuidinfo fails\n"); return 0; + } hz = cpuidhz(info); - if(hz != 0 || m->machno != 0) + if(hz != 0) return hz; + if(m->machno != 0) + return sys->machptr[0]->cpuhz; return i8254hz(info); }