Path: blob/master/tools/power/cpupower/utils/helpers/cpuid.c
26299 views
// SPDX-License-Identifier: GPL-2.01#include <stdio.h>2#include <errno.h>3#include <string.h>4#include <unistd.h>5#include <stdlib.h>67#include "helpers/helpers.h"89static const char *cpu_vendor_table[X86_VENDOR_MAX] = {10"Unknown", "GenuineIntel", "AuthenticAMD", "HygonGenuine",11};1213#if defined(__i386__) || defined(__x86_64__)1415/* from gcc */16#include <cpuid.h>1718/*19* CPUID functions returning a single datum20*21* Define unsigned int cpuid_e[abcd]x(unsigned int op)22*/23#define cpuid_func(reg) \24unsigned int cpuid_##reg(unsigned int op) \25{ \26unsigned int eax, ebx, ecx, edx; \27__cpuid(op, eax, ebx, ecx, edx); \28return reg; \29}30cpuid_func(eax);31cpuid_func(ebx);32cpuid_func(ecx);33cpuid_func(edx);3435#endif /* defined(__i386__) || defined(__x86_64__) */3637/* get_cpu_info38*39* Extract CPU vendor, family, model, stepping info from /proc/cpuinfo40*41* Returns 0 on success or a negativ error code42*43* TBD: Should there be a cpuid alternative for this if /proc is not mounted?44*/45int get_cpu_info(struct cpupower_cpu_info *cpu_info)46{47FILE *fp;48char value[64];49unsigned int proc, x;50unsigned int unknown = 0xffffff;51unsigned int cpuid_level, ext_cpuid_level;5253int ret = -EINVAL;5455cpu_info->vendor = X86_VENDOR_UNKNOWN;56cpu_info->family = unknown;57cpu_info->model = unknown;58cpu_info->stepping = unknown;59cpu_info->caps = 0;6061fp = fopen("/proc/cpuinfo", "r");62if (!fp)63return -EIO;6465while (!feof(fp)) {66if (!fgets(value, 64, fp))67continue;68value[63 - 1] = '\0';6970if (!strncmp(value, "processor\t: ", 12))71sscanf(value, "processor\t: %u", &proc);7273if (proc != (unsigned int)base_cpu)74continue;7576/* Get CPU vendor */77if (!strncmp(value, "vendor_id", 9)) {78for (x = 1; x < X86_VENDOR_MAX; x++) {79if (strstr(value, cpu_vendor_table[x]))80cpu_info->vendor = x;81}82/* Get CPU family, etc. */83} else if (!strncmp(value, "cpu family\t: ", 13)) {84sscanf(value, "cpu family\t: %u",85&cpu_info->family);86} else if (!strncmp(value, "model\t\t: ", 9)) {87sscanf(value, "model\t\t: %u",88&cpu_info->model);89} else if (!strncmp(value, "stepping\t: ", 10)) {90sscanf(value, "stepping\t: %u",91&cpu_info->stepping);9293/* Exit -> all values must have been set */94if (cpu_info->vendor == X86_VENDOR_UNKNOWN ||95cpu_info->family == unknown ||96cpu_info->model == unknown ||97cpu_info->stepping == unknown) {98ret = -EINVAL;99goto out;100}101102ret = 0;103goto out;104}105}106ret = -ENODEV;107out:108fclose(fp);109/* Get some useful CPU capabilities from cpuid */110if (cpu_info->vendor != X86_VENDOR_AMD &&111cpu_info->vendor != X86_VENDOR_HYGON &&112cpu_info->vendor != X86_VENDOR_INTEL)113return ret;114115cpuid_level = cpuid_eax(0);116ext_cpuid_level = cpuid_eax(0x80000000);117118/* Invariant TSC */119if (ext_cpuid_level >= 0x80000007 &&120(cpuid_edx(0x80000007) & (1 << 8)))121cpu_info->caps |= CPUPOWER_CAP_INV_TSC;122123/* Aperf/Mperf registers support */124if (cpuid_level >= 6 && (cpuid_ecx(6) & 0x1))125cpu_info->caps |= CPUPOWER_CAP_APERF;126127/* AMD or Hygon Boost state enable/disable register */128if (cpu_info->vendor == X86_VENDOR_AMD ||129cpu_info->vendor == X86_VENDOR_HYGON) {130if (ext_cpuid_level >= 0x80000007) {131if (cpuid_edx(0x80000007) & (1 << 9)) {132cpu_info->caps |= CPUPOWER_CAP_AMD_CPB;133134if (cpu_info->family >= 0x17)135cpu_info->caps |= CPUPOWER_CAP_AMD_CPB_MSR;136}137138if ((cpuid_edx(0x80000007) & (1 << 7)) &&139cpu_info->family != 0x14) {140/* HW pstate was not implemented in family 0x14 */141cpu_info->caps |= CPUPOWER_CAP_AMD_HW_PSTATE;142143if (cpu_info->family >= 0x17)144cpu_info->caps |= CPUPOWER_CAP_AMD_PSTATEDEF;145}146}147148if (ext_cpuid_level >= 0x80000008 &&149cpuid_ebx(0x80000008) & (1 << 4))150cpu_info->caps |= CPUPOWER_CAP_AMD_RDPRU;151152if (cpupower_amd_pstate_enabled()) {153cpu_info->caps |= CPUPOWER_CAP_AMD_PSTATE;154155/*156* If AMD P-State is enabled, the firmware will treat157* AMD P-State function as high priority.158*/159cpu_info->caps &= ~CPUPOWER_CAP_AMD_CPB;160cpu_info->caps &= ~CPUPOWER_CAP_AMD_CPB_MSR;161cpu_info->caps &= ~CPUPOWER_CAP_AMD_HW_PSTATE;162cpu_info->caps &= ~CPUPOWER_CAP_AMD_PSTATEDEF;163}164}165166if (cpu_info->vendor == X86_VENDOR_INTEL) {167if (cpuid_level >= 6 &&168(cpuid_eax(6) & (1 << 1)))169cpu_info->caps |= CPUPOWER_CAP_INTEL_IDA;170}171172if (cpu_info->vendor == X86_VENDOR_INTEL) {173/* Intel's perf-bias MSR support */174if (cpuid_level >= 6 && (cpuid_ecx(6) & (1 << 3)))175cpu_info->caps |= CPUPOWER_CAP_PERF_BIAS;176177/* Intel's Turbo Ratio Limit support */178if (cpu_info->family == 6) {179switch (cpu_info->model) {180case 0x1A: /* Core i7, Xeon 5500 series181* Bloomfield, Gainstown NHM-EP182*/183case 0x1E: /* Core i7 and i5 Processor184* Clarksfield, Lynnfield, Jasper Forest185*/186case 0x1F: /* Core i7 and i5 Processor - Nehalem */187case 0x25: /* Westmere Client188* Clarkdale, Arrandale189*/190case 0x2C: /* Westmere EP - Gulftown */191cpu_info->caps |= CPUPOWER_CAP_HAS_TURBO_RATIO;192break;193case 0x2A: /* SNB */194case 0x2D: /* SNB Xeon */195case 0x3A: /* IVB */196case 0x3E: /* IVB Xeon */197cpu_info->caps |= CPUPOWER_CAP_HAS_TURBO_RATIO;198cpu_info->caps |= CPUPOWER_CAP_IS_SNB;199break;200case 0x2E: /* Nehalem-EX Xeon - Beckton */201case 0x2F: /* Westmere-EX Xeon - Eagleton */202default:203break;204}205}206}207208/* printf("ID: %u - Extid: 0x%x - Caps: 0x%llx\n",209cpuid_level, ext_cpuid_level, cpu_info->caps);210*/211return ret;212}213214215