7 #include "helpers/helpers.h"
9 static const char *cpu_vendor_table
[X86_VENDOR_MAX
] = {
10 "Unknown", "GenuineIntel", "AuthenticAMD",
13 #if defined(__i386__) || defined(__x86_64__)
19 * CPUID functions returning a single datum
21 * Define unsigned int cpuid_e[abcd]x(unsigned int op)
23 #define cpuid_func(reg) \
24 unsigned int cpuid_##reg(unsigned int op) \
26 unsigned int eax, ebx, ecx, edx; \
27 __cpuid(op, eax, ebx, ecx, edx); \
35 #endif /* defined(__i386__) || defined(__x86_64__) */
39 * Extract CPU vendor, family, model, stepping info from /proc/cpuinfo
41 * Returns 0 on success or a negativ error code
43 * TBD: Should there be a cpuid alternative for this if /proc is not mounted?
45 int get_cpu_info(unsigned int cpu
, struct cpupower_cpu_info
*cpu_info
)
50 unsigned int unknown
= 0xffffff;
51 unsigned int cpuid_level
, ext_cpuid_level
;
55 cpu_info
->vendor
= X86_VENDOR_UNKNOWN
;
56 cpu_info
->family
= unknown
;
57 cpu_info
->model
= unknown
;
58 cpu_info
->stepping
= unknown
;
61 fp
= fopen("/proc/cpuinfo", "r");
66 if (!fgets(value
, 64, fp
))
70 if (!strncmp(value
, "processor\t: ", 12))
71 sscanf(value
, "processor\t: %u", &proc
);
77 if (!strncmp(value
, "vendor_id", 9)) {
78 for (x
= 1; x
< X86_VENDOR_MAX
; x
++) {
79 if (strstr(value
, cpu_vendor_table
[x
]))
82 /* Get CPU family, etc. */
83 } else if (!strncmp(value
, "cpu family\t: ", 13)) {
84 sscanf(value
, "cpu family\t: %u",
86 } else if (!strncmp(value
, "model\t\t: ", 9)) {
87 sscanf(value
, "model\t\t: %u",
89 } else if (!strncmp(value
, "stepping\t: ", 10)) {
90 sscanf(value
, "stepping\t: %u",
93 /* Exit -> all values must have been set */
94 if (cpu_info
->vendor
== X86_VENDOR_UNKNOWN
||
95 cpu_info
->family
== unknown
||
96 cpu_info
->model
== unknown
||
97 cpu_info
->stepping
== unknown
) {
109 /* Get some useful CPU capabilities from cpuid */
110 if (cpu_info
->vendor
!= X86_VENDOR_AMD
&&
111 cpu_info
->vendor
!= X86_VENDOR_INTEL
)
114 cpuid_level
= cpuid_eax(0);
115 ext_cpuid_level
= cpuid_eax(0x80000000);
118 if (ext_cpuid_level
>= 0x80000007 &&
119 (cpuid_edx(0x80000007) & (1 << 8)))
120 cpu_info
->caps
|= CPUPOWER_CAP_INV_TSC
;
122 /* Aperf/Mperf registers support */
123 if (cpuid_level
>= 6 && (cpuid_ecx(6) & 0x1))
124 cpu_info
->caps
|= CPUPOWER_CAP_APERF
;
126 /* AMD Boost state enable/disable register */
127 if (cpu_info
->vendor
== X86_VENDOR_AMD
) {
128 if (ext_cpuid_level
>= 0x80000007 &&
129 (cpuid_edx(0x80000007) & (1 << 9)))
130 cpu_info
->caps
|= CPUPOWER_CAP_AMD_CBP
;
133 if (cpu_info
->vendor
== X86_VENDOR_INTEL
) {
134 if (cpuid_level
>= 6 &&
135 (cpuid_eax(6) & (1 << 1)))
136 cpu_info
->caps
|= CPUPOWER_CAP_INTEL_IDA
;
139 if (cpu_info
->vendor
== X86_VENDOR_INTEL
) {
140 /* Intel's perf-bias MSR support */
141 if (cpuid_level
>= 6 && (cpuid_ecx(6) & (1 << 3)))
142 cpu_info
->caps
|= CPUPOWER_CAP_PERF_BIAS
;
144 /* Intel's Turbo Ratio Limit support */
145 if (cpu_info
->family
== 6) {
146 switch (cpu_info
->model
) {
147 case 0x1A: /* Core i7, Xeon 5500 series
148 * Bloomfield, Gainstown NHM-EP
150 case 0x1E: /* Core i7 and i5 Processor
151 * Clarksfield, Lynnfield, Jasper Forest
153 case 0x1F: /* Core i7 and i5 Processor - Nehalem */
154 case 0x25: /* Westmere Client
155 * Clarkdale, Arrandale
157 case 0x2C: /* Westmere EP - Gulftown */
158 cpu_info
->caps
|= CPUPOWER_CAP_HAS_TURBO_RATIO
;
160 case 0x2D: /* SNB Xeon */
161 cpu_info
->caps
|= CPUPOWER_CAP_HAS_TURBO_RATIO
;
162 cpu_info
->caps
|= CPUPOWER_CAP_IS_SNB
;
164 case 0x2E: /* Nehalem-EX Xeon - Beckton */
165 case 0x2F: /* Westmere-EX Xeon - Eagleton */
172 /* printf("ID: %u - Extid: 0x%x - Caps: 0x%llx\n",
173 cpuid_level, ext_cpuid_level, cpu_info->caps);