/* Name (_PSS, Package (0x04) { Package (0x06) { 0x00000898, 0x0001ADB0, 0x00000064, 0x00000009, 0xE0202A0E, 0x0000020E }, Package (0x06) { 0x000007D0, 0x00019C80, 0x00000064, 0x00000009, 0xE0202A8C, 0x0000028C }, Package (0x06) { 0x00000708, 0x00015C0C, 0x00000064, 0x00000009, 0xE0202B0A, 0x0000030A }, Package (0x06) { 0x000003E8, 0x0000BF68, 0x00000064, 0x00000009, 0xE0202C82, 0x00000482 } }) Name (_PPC, 0x00) } */ #include unsigned int vid_from_reg(uint8_t val) { /* fixme 6 bits */ val &= 0x1f; return (val == 0x1f ? 0 : 1550 - val * 25); } uint8_t vid_to_reg(uint32_t vid) { return (1550 - vid) / 25; } //uint8_t fidcodes[32] = { 0x0, 0x2, 0x4, 0x6, 0x8, 0xa, 0xc, 0xe, 0x10, // 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e, 0x20, 0x22, 0x24, 0x26, // 0x28, 0x2a //}; //from kernel /* Return a frequency in MHz, given an input fid */ static uint32_t fid_to_freq(uint32_t fid) { return 800 + (fid * 100); } uint8_t freq_to_fid(uint32_t freq) { // /* fix the odd fids */ // return fidcodes[(freq / 200) - 4]; return (freq - 800) / 100; } //from kernel #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) static inline unsigned int cpuid_eax(unsigned int op) { unsigned int eax; __asm__("cpuid":"=a"(eax) : "0"(op) : "bx", "cx", "dx"); return eax; } static inline unsigned int cpuid_ebx(unsigned int op) { unsigned int eax, ebx; __asm__("cpuid":"=a"(eax), "=b"(ebx) : "0"(op) : "cx", "dx"); return ebx; } static inline unsigned int cpuid_edx(unsigned int op) { unsigned int eax, edx; __asm__("cpuid":"=a"(eax), "=d"(edx) : "0"(op) : "bx", "cx"); return edx; } /* * $Id: rdmsr.c,v 1.16 2003/06/09 22:15:20 davej Exp $ * This file is part of x86info. * (C) 2001 Dave Jones. * * Licensed under the terms of the GNU GPL License version 2. * * Contributions by Arjan van de Ven & Philipp Rumpf. */ #include #include #include #include #include #include int read_msr(int cpu, unsigned int idx, unsigned long long *val) { char cpuname[16]; unsigned char buffer[8]; unsigned long lo, hi; int fh; static int nodriver = 0; if (nodriver == 1) return 0; sprintf(cpuname, "/dev/cpu/%d/msr", cpu); fh = open(cpuname, O_RDONLY); if (fh == -1) { // if (!silent) perror(cpuname); nodriver = 1; return (0); } lseek(fh, idx, SEEK_CUR); if (fh != -1) { if (read(fh, &buffer[0], 8) != 8) { close(fh); return (0); } lo = (*(unsigned long *) buffer); hi = (*(unsigned long *) (buffer + 4)); *val = hi; *val = (*val << 32) | lo; } close(fh); return (1); } #include #define MAXP 8 struct pstate { uint32_t freqMhz; uint32_t voltage; uint32_t tdp; }; struct cpuentry { uint32_t modelnr; uint8_t brandID; uint32_t cpuid; uint8_t maxFID; uint8_t startFID; uint8_t maxVID; uint8_t startVID; struct pstate pstates[MAXP]; }; /* generated entry for revF */ struct cpuentry entr[] = { {165, 0x2c, 0x20f32, 0xa, 0xa, 0x8, 0xa, {{1800, 1300, 1100}, {1000, 1100, 516}}}, {165, 0x2c, 0x20f32, 0xa, 0xa, 0x6, 0x8, {{1800, 1350, 1100}, {1000, 1100, 516}}}, {170, 0x2c, 0x20f32, 0xc, 0xc, 0x8, 0xa, {{2000, 1300, 1100}, {1800, 1300, 1056}, {1000, 1100, 514}}}, {170, 0x2c, 0x20f32, 0xc, 0xc, 0x6, 0x8, {{2000, 1350, 1100}, {1800, 1300, 1056}, {1000, 1100, 514}}}, {175, 0x2c, 0x20f32, 0xe, 0xe, 0x8, 0xa, {{2200, 1300, 1100}, {2000, 1300, 1056}, {1800, 1250, 891}, {1000, 1100, 490}}}, {175, 0x2c, 0x20f32, 0xe, 0xe, 0x6, 0x8, {{2200, 1350, 1100}, {2000, 1300, 1056}, {1800, 1250, 891}, {1000, 1100, 490}}}, {180, 0x2c, 0x20f32, 0x10, 0x10, 0x8, 0xa, {{2400, 1300, 1100}, {2200, 1300, 1056}, {2000, 1250, 891}, {1800, 1200, 748}, {1000, 1100, 466}}}, {180, 0x2c, 0x20f32, 0x10, 0x10, 0x6, 0x8, {{2400, 1350, 1100}, {2200, 1300, 1056}, {2000, 1250, 891}, {1800, 1200, 748}, {1000, 1100, 466}}}, }; void genpower(struct cpuentry *entr) { int i = 0; do { printf("P#%d freq %d [MHz] voltage %f [V] TDP %f [W]\n", i, entr->pstates[i].freqMhz, entr->pstates[i].voltage / 1000.0, entr->pstates[i].tdp / 10.0); i++; } while ((i < MAXP) && (entr->pstates[i].freqMhz != 0)); i = 0; /* Package (0x06) { 0x00000898, 0x0001ADB0, 0x00000064, 0x00000009, 0xE0202A0E, 0x0000020E }, */ printf(" Name (_PSS, Package (0x04) {"); do { /* bus latencies are hardcoded */ printf (" Package (0x06) { \n 0x%08x,\n0x%08x,\n0x00000064,\n0x00000007,\n", entr->pstates[i].freqMhz, entr->pstates[i].tdp * 100); printf("0x%08x,\n", 0); printf("0x%08x,\n", (vid_to_reg(entr->pstates[i].voltage) << 6) | freq_to_fid(entr->pstates[i].freqMhz) & 0x3f); i++; } while ((i < MAXP) && (entr->pstates[i].freqMhz != 0)); } struct cpu_data { uint8_t brandID; uint32_t cpuid; uint8_t maxFID; uint8_t startFID; uint8_t maxVID; uint8_t startVID; uint8_t pwrlmt; unsigned long long msr_fidvid; }; void get_cpuDATA(struct cpu_data *cpu) { int i; uint32_t brand; unsigned long long val = 0; if (read_msr(0, 0xC0010042, &val) != 1) { return; } printf("FID_VID_STATUS %lx ", val); cpu->msr_fidvid = val; cpu->startFID = (val >> 8) & 0x3f; cpu->maxFID = (val >> 16) & 0x3f; cpu->startVID = (val >> 40) & 0x3f; cpu->maxVID = (val >> 48) & 0x3f; cpu->cpuid = cpuid_eax(0x80000001); brand = cpuid_ebx(0x80000001); cpu->brandID = (brand >> 6) & 0x3f; if ((cpuid_edx(0x80000007) & 0x6) == 0x6) { /* pwrlmt is brand[8:6,14] */ cpu->pwrlmt = (((brand >> 6) & 0x7) << 1) | (brand >> 14); } else { cpu->pwrlmt = 0; } printf ("BrandID %x cpuid %x startFID %x maxFID %x startVID %x maxVID %x\n", cpu->brandID, cpu->cpuid, cpu->startFID, cpu->maxFID, cpu->startVID, cpu->maxVID); } /* units W * 10 */ unsigned int tdp(unsigned int pwrlmt, struct pstate *p, uint32_t freqMhzMAX, uint32_t voltageMAX) { //return (pwrlmt * (((unsigned long long) freqMHz) * 1000) * ( ((unsigned long long) voltage) * ((unsigned long long) voltage) /* fixme here need to follow Power = (PwrLmt * P[N] Frequency * (P[N] Voltage^2))/(P[0] Frequency* (P[0] Voltage^2)). */ return 420; } void gen_revF(void) { struct cpuentry entr_revF; struct cpu_data cpu; int i = 0, j; int cond = 0; uint8_t pstep; uint32_t startVoltage; uint32_t lowFreqMhz; if ((cpuid_eax(0x80000001) & 0xf0000) < 0x40000) { /* no revF or later */ return; } get_cpuDATA(&cpu); /* algo cannot be used */ if (cpu.pwrlmt == 0) return; /* construct the entry */ entr_revF.brandID = cpu.brandID; entr_revF.modelnr = 0xf; /* dummy */ entr_revF.brandID = cpu.brandID; entr_revF.cpuid = cpu.cpuid; entr_revF.startFID = cpu.startFID; entr_revF.startVID = cpu.startVID; entr_revF.maxVID = cpu.maxVID; entr_revF.maxFID = cpu.maxFID; pstep = (cpu.msr_fidvid >> 56) & 1; startVoltage = vid_from_reg(cpu.startVID); /* If MaxFID = 10_1010b and MaxVID != 00_0000b */ if ((entr_revF.maxFID == 0x2a) && (entr_revF.maxVID != 0)) { cond = 1; } /* first do the max */ entr_revF.pstates[0].voltage = vid_from_reg(cpu.maxVID + 2); if (cond) { entr_revF.pstates[0].freqMhz = fid_to_freq(cpu.startFID + 0xa); lowFreqMhz = fid_to_freq(0x2); } else { entr_revF.pstates[0].freqMhz = fid_to_freq(cpu.maxFID); lowFreqMhz = fid_to_freq(cpu.startFID); } /* intermediate states */ if ((cpu.msr_fidvid >> 61) & 0x1) { /* P1 first from max */ if (cpu.maxFID & 1) { entr_revF.pstates[1].freqMhz = fid_to_freq(cpu.maxFID - 1); } else { entr_revF.pstates[1].freqMhz = fid_to_freq(cpu.maxFID - 2); } if (cpu.maxVID & 1) { entr_revF.pstates[1].voltage = vid_from_reg(cpu.maxVID + 1); } else { entr_revF.pstates[1].voltage = vid_from_reg(cpu.maxVID + (1 << pstep)); } i = 1; do { i++; /* If P[N-1] VID + 2^PstateStep >= P[Min]: */ if ((entr_revF.pstates[i - 1].voltage - (25 << pstep)) < startVoltage) { entr_revF.pstates[i].voltage = entr_revF.pstates[i - 1].voltage; } else { entr_revF.pstates[i].voltage = entr_revF.pstates[i - 1].voltage - (25 << pstep); } entr_revF.pstates[i].freqMhz = entr_revF.pstates[i - 1].freqMhz - 200; /* P[N-1] FID - 00_0010b */ } while ((entr_revF.pstates[i].voltage > startVoltage) && (entr_revF.pstates[i].freqMhz - 800 > lowFreqMhz)); } /* min P state */ entr_revF.pstates[i].voltage = startVoltage; entr_revF.pstates[i].freqMhz = lowFreqMhz; /* calculate the TDP estimation */ for (j = 0; j <= i; j++) { entr_revF.pstates[j].tdp = tdp(cpu.pwrlmt, &entr_revF.pstates[j], fid_to_freq(entr_revF.maxFID), vid_from_reg(entr_revF.maxVID)); } } void gen_to_revE(void) { struct cpu_data cpu; int i; get_cpuDATA(&cpu); for (i = 0; i < ARRAY_SIZE(entr); i++) { if ((entr[i].cpuid == cpu.cpuid) && (entr[i].startFID == cpu.startFID) && (entr[i].maxFID == cpu.maxFID) && (entr[i].startVID == cpu.startVID) && (entr[i].maxVID == cpu.maxVID)) { printf("HIT %d\n", i); genpower(&entr[i]); } } } int main(void) { gen_to_revE(); gen_revF(); return 0; }