1*7fe2f639SDominik Brodowski #include <stdio.h> 2*7fe2f639SDominik Brodowski #include <errno.h> 3*7fe2f639SDominik Brodowski #include <string.h> 4*7fe2f639SDominik Brodowski #include <unistd.h> 5*7fe2f639SDominik Brodowski #include <stdlib.h> 6*7fe2f639SDominik Brodowski 7*7fe2f639SDominik Brodowski #include "helpers/helpers.h" 8*7fe2f639SDominik Brodowski 9*7fe2f639SDominik Brodowski static const char *cpu_vendor_table[X86_VENDOR_MAX] = { 10*7fe2f639SDominik Brodowski "Unknown", "GenuineIntel", "AuthenticAMD", 11*7fe2f639SDominik Brodowski }; 12*7fe2f639SDominik Brodowski 13*7fe2f639SDominik Brodowski #if defined(__i386__) || defined(__x86_64__) 14*7fe2f639SDominik Brodowski 15*7fe2f639SDominik Brodowski /* from gcc */ 16*7fe2f639SDominik Brodowski #include <cpuid.h> 17*7fe2f639SDominik Brodowski 18*7fe2f639SDominik Brodowski /* 19*7fe2f639SDominik Brodowski * CPUID functions returning a single datum 20*7fe2f639SDominik Brodowski * 21*7fe2f639SDominik Brodowski * Define unsigned int cpuid_e[abcd]x(unsigned int op) 22*7fe2f639SDominik Brodowski */ 23*7fe2f639SDominik Brodowski #define cpuid_func(reg) \ 24*7fe2f639SDominik Brodowski unsigned int cpuid_##reg(unsigned int op) \ 25*7fe2f639SDominik Brodowski { \ 26*7fe2f639SDominik Brodowski unsigned int eax, ebx, ecx, edx; \ 27*7fe2f639SDominik Brodowski __cpuid(op, eax, ebx, ecx, edx); \ 28*7fe2f639SDominik Brodowski return reg; \ 29*7fe2f639SDominik Brodowski } 30*7fe2f639SDominik Brodowski cpuid_func(eax); 31*7fe2f639SDominik Brodowski cpuid_func(ebx); 32*7fe2f639SDominik Brodowski cpuid_func(ecx); 33*7fe2f639SDominik Brodowski cpuid_func(edx); 34*7fe2f639SDominik Brodowski 35*7fe2f639SDominik Brodowski #endif /* defined(__i386__) || defined(__x86_64__) */ 36*7fe2f639SDominik Brodowski 37*7fe2f639SDominik Brodowski /* get_cpu_info 38*7fe2f639SDominik Brodowski * 39*7fe2f639SDominik Brodowski * Extract CPU vendor, family, model, stepping info from /proc/cpuinfo 40*7fe2f639SDominik Brodowski * 41*7fe2f639SDominik Brodowski * Returns 0 on success or a negativ error code 42*7fe2f639SDominik Brodowski * 43*7fe2f639SDominik Brodowski * TBD: Should there be a cpuid alternative for this if /proc is not mounted? 44*7fe2f639SDominik Brodowski */ 45*7fe2f639SDominik Brodowski int get_cpu_info(unsigned int cpu, struct cpupower_cpu_info *cpu_info) 46*7fe2f639SDominik Brodowski { 47*7fe2f639SDominik Brodowski FILE *fp; 48*7fe2f639SDominik Brodowski char value[64]; 49*7fe2f639SDominik Brodowski unsigned int proc, x; 50*7fe2f639SDominik Brodowski unsigned int unknown = 0xffffff; 51*7fe2f639SDominik Brodowski unsigned int cpuid_level, ext_cpuid_level; 52*7fe2f639SDominik Brodowski 53*7fe2f639SDominik Brodowski int ret = -EINVAL; 54*7fe2f639SDominik Brodowski 55*7fe2f639SDominik Brodowski cpu_info->vendor = X86_VENDOR_UNKNOWN; 56*7fe2f639SDominik Brodowski cpu_info->family = unknown; 57*7fe2f639SDominik Brodowski cpu_info->model = unknown; 58*7fe2f639SDominik Brodowski cpu_info->stepping = unknown; 59*7fe2f639SDominik Brodowski cpu_info->caps = 0; 60*7fe2f639SDominik Brodowski 61*7fe2f639SDominik Brodowski fp = fopen("/proc/cpuinfo", "r"); 62*7fe2f639SDominik Brodowski if (!fp) 63*7fe2f639SDominik Brodowski return -EIO; 64*7fe2f639SDominik Brodowski 65*7fe2f639SDominik Brodowski while (!feof(fp)) { 66*7fe2f639SDominik Brodowski if (!fgets(value, 64, fp)) 67*7fe2f639SDominik Brodowski continue; 68*7fe2f639SDominik Brodowski value[63 - 1] = '\0'; 69*7fe2f639SDominik Brodowski 70*7fe2f639SDominik Brodowski if (!strncmp(value, "processor\t: ", 12)) { 71*7fe2f639SDominik Brodowski sscanf(value, "processor\t: %u", &proc); 72*7fe2f639SDominik Brodowski } 73*7fe2f639SDominik Brodowski if (proc != cpu) 74*7fe2f639SDominik Brodowski continue; 75*7fe2f639SDominik Brodowski 76*7fe2f639SDominik Brodowski /* Get CPU vendor */ 77*7fe2f639SDominik Brodowski if (!strncmp(value, "vendor_id", 9)) 78*7fe2f639SDominik Brodowski for (x = 1; x < X86_VENDOR_MAX; x++) { 79*7fe2f639SDominik Brodowski if (strstr(value, cpu_vendor_table[x])) 80*7fe2f639SDominik Brodowski cpu_info->vendor = x; 81*7fe2f639SDominik Brodowski } 82*7fe2f639SDominik Brodowski /* Get CPU family, etc. */ 83*7fe2f639SDominik Brodowski else if (!strncmp(value, "cpu family\t: ", 13)) { 84*7fe2f639SDominik Brodowski sscanf(value, "cpu family\t: %u", 85*7fe2f639SDominik Brodowski &cpu_info->family); 86*7fe2f639SDominik Brodowski } 87*7fe2f639SDominik Brodowski else if (!strncmp(value, "model\t\t: ", 9)) { 88*7fe2f639SDominik Brodowski sscanf(value, "model\t\t: %u", 89*7fe2f639SDominik Brodowski &cpu_info->model); 90*7fe2f639SDominik Brodowski } 91*7fe2f639SDominik Brodowski else if (!strncmp(value, "stepping\t: ", 10)) { 92*7fe2f639SDominik Brodowski sscanf(value, "stepping\t: %u", 93*7fe2f639SDominik Brodowski &cpu_info->stepping); 94*7fe2f639SDominik Brodowski 95*7fe2f639SDominik Brodowski /* Exit -> all values must have been set */ 96*7fe2f639SDominik Brodowski if (cpu_info->vendor == X86_VENDOR_UNKNOWN || 97*7fe2f639SDominik Brodowski cpu_info->family == unknown || 98*7fe2f639SDominik Brodowski cpu_info->model == unknown || 99*7fe2f639SDominik Brodowski cpu_info->stepping == unknown) { 100*7fe2f639SDominik Brodowski ret = -EINVAL; 101*7fe2f639SDominik Brodowski goto out; 102*7fe2f639SDominik Brodowski } 103*7fe2f639SDominik Brodowski 104*7fe2f639SDominik Brodowski ret = 0; 105*7fe2f639SDominik Brodowski goto out; 106*7fe2f639SDominik Brodowski } 107*7fe2f639SDominik Brodowski } 108*7fe2f639SDominik Brodowski ret = -ENODEV; 109*7fe2f639SDominik Brodowski out: 110*7fe2f639SDominik Brodowski fclose(fp); 111*7fe2f639SDominik Brodowski /* Get some useful CPU capabilities from cpuid */ 112*7fe2f639SDominik Brodowski if (cpu_info->vendor != X86_VENDOR_AMD && 113*7fe2f639SDominik Brodowski cpu_info->vendor != X86_VENDOR_INTEL) 114*7fe2f639SDominik Brodowski return ret; 115*7fe2f639SDominik Brodowski 116*7fe2f639SDominik Brodowski cpuid_level = cpuid_eax(0); 117*7fe2f639SDominik Brodowski ext_cpuid_level = cpuid_eax(0x80000000); 118*7fe2f639SDominik Brodowski 119*7fe2f639SDominik Brodowski /* Invariant TSC */ 120*7fe2f639SDominik Brodowski if (ext_cpuid_level >= 0x80000007 && 121*7fe2f639SDominik Brodowski (cpuid_edx(0x80000007) & (1 << 8))) 122*7fe2f639SDominik Brodowski cpu_info->caps |= CPUPOWER_CAP_INV_TSC; 123*7fe2f639SDominik Brodowski 124*7fe2f639SDominik Brodowski /* Aperf/Mperf registers support */ 125*7fe2f639SDominik Brodowski if (cpuid_level >= 6 && (cpuid_ecx(6) & 0x1)) 126*7fe2f639SDominik Brodowski cpu_info->caps |= CPUPOWER_CAP_APERF; 127*7fe2f639SDominik Brodowski 128*7fe2f639SDominik Brodowski /* AMD Boost state enable/disable register */ 129*7fe2f639SDominik Brodowski if (cpu_info->vendor == X86_VENDOR_AMD) { 130*7fe2f639SDominik Brodowski if (ext_cpuid_level >= 0x80000007 && 131*7fe2f639SDominik Brodowski (cpuid_edx(0x80000007) & (1 << 9))) 132*7fe2f639SDominik Brodowski cpu_info->caps |= CPUPOWER_CAP_AMD_CBP; 133*7fe2f639SDominik Brodowski } 134*7fe2f639SDominik Brodowski 135*7fe2f639SDominik Brodowski /* Intel's perf-bias MSR support */ 136*7fe2f639SDominik Brodowski if (cpu_info->vendor == X86_VENDOR_INTEL) { 137*7fe2f639SDominik Brodowski if (cpuid_level >= 6 && (cpuid_ecx(6) & (1 << 3))) 138*7fe2f639SDominik Brodowski cpu_info->caps |= CPUPOWER_CAP_PERF_BIAS; 139*7fe2f639SDominik Brodowski } 140*7fe2f639SDominik Brodowski 141*7fe2f639SDominik Brodowski /* printf("ID: %u - Extid: 0x%x - Caps: 0x%llx\n", 142*7fe2f639SDominik Brodowski cpuid_level, ext_cpuid_level, cpu_info->caps); 143*7fe2f639SDominik Brodowski */ 144*7fe2f639SDominik Brodowski return ret; 145*7fe2f639SDominik Brodowski } 146