Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/tools/power/cpupower/utils/helpers/cpuid.c
26299 views
1
// SPDX-License-Identifier: GPL-2.0
2
#include <stdio.h>
3
#include <errno.h>
4
#include <string.h>
5
#include <unistd.h>
6
#include <stdlib.h>
7
8
#include "helpers/helpers.h"
9
10
static const char *cpu_vendor_table[X86_VENDOR_MAX] = {
11
"Unknown", "GenuineIntel", "AuthenticAMD", "HygonGenuine",
12
};
13
14
#if defined(__i386__) || defined(__x86_64__)
15
16
/* from gcc */
17
#include <cpuid.h>
18
19
/*
20
* CPUID functions returning a single datum
21
*
22
* Define unsigned int cpuid_e[abcd]x(unsigned int op)
23
*/
24
#define cpuid_func(reg) \
25
unsigned int cpuid_##reg(unsigned int op) \
26
{ \
27
unsigned int eax, ebx, ecx, edx; \
28
__cpuid(op, eax, ebx, ecx, edx); \
29
return reg; \
30
}
31
cpuid_func(eax);
32
cpuid_func(ebx);
33
cpuid_func(ecx);
34
cpuid_func(edx);
35
36
#endif /* defined(__i386__) || defined(__x86_64__) */
37
38
/* get_cpu_info
39
*
40
* Extract CPU vendor, family, model, stepping info from /proc/cpuinfo
41
*
42
* Returns 0 on success or a negativ error code
43
*
44
* TBD: Should there be a cpuid alternative for this if /proc is not mounted?
45
*/
46
int get_cpu_info(struct cpupower_cpu_info *cpu_info)
47
{
48
FILE *fp;
49
char value[64];
50
unsigned int proc, x;
51
unsigned int unknown = 0xffffff;
52
unsigned int cpuid_level, ext_cpuid_level;
53
54
int ret = -EINVAL;
55
56
cpu_info->vendor = X86_VENDOR_UNKNOWN;
57
cpu_info->family = unknown;
58
cpu_info->model = unknown;
59
cpu_info->stepping = unknown;
60
cpu_info->caps = 0;
61
62
fp = fopen("/proc/cpuinfo", "r");
63
if (!fp)
64
return -EIO;
65
66
while (!feof(fp)) {
67
if (!fgets(value, 64, fp))
68
continue;
69
value[63 - 1] = '\0';
70
71
if (!strncmp(value, "processor\t: ", 12))
72
sscanf(value, "processor\t: %u", &proc);
73
74
if (proc != (unsigned int)base_cpu)
75
continue;
76
77
/* Get CPU vendor */
78
if (!strncmp(value, "vendor_id", 9)) {
79
for (x = 1; x < X86_VENDOR_MAX; x++) {
80
if (strstr(value, cpu_vendor_table[x]))
81
cpu_info->vendor = x;
82
}
83
/* Get CPU family, etc. */
84
} else if (!strncmp(value, "cpu family\t: ", 13)) {
85
sscanf(value, "cpu family\t: %u",
86
&cpu_info->family);
87
} else if (!strncmp(value, "model\t\t: ", 9)) {
88
sscanf(value, "model\t\t: %u",
89
&cpu_info->model);
90
} else if (!strncmp(value, "stepping\t: ", 10)) {
91
sscanf(value, "stepping\t: %u",
92
&cpu_info->stepping);
93
94
/* Exit -> all values must have been set */
95
if (cpu_info->vendor == X86_VENDOR_UNKNOWN ||
96
cpu_info->family == unknown ||
97
cpu_info->model == unknown ||
98
cpu_info->stepping == unknown) {
99
ret = -EINVAL;
100
goto out;
101
}
102
103
ret = 0;
104
goto out;
105
}
106
}
107
ret = -ENODEV;
108
out:
109
fclose(fp);
110
/* Get some useful CPU capabilities from cpuid */
111
if (cpu_info->vendor != X86_VENDOR_AMD &&
112
cpu_info->vendor != X86_VENDOR_HYGON &&
113
cpu_info->vendor != X86_VENDOR_INTEL)
114
return ret;
115
116
cpuid_level = cpuid_eax(0);
117
ext_cpuid_level = cpuid_eax(0x80000000);
118
119
/* Invariant TSC */
120
if (ext_cpuid_level >= 0x80000007 &&
121
(cpuid_edx(0x80000007) & (1 << 8)))
122
cpu_info->caps |= CPUPOWER_CAP_INV_TSC;
123
124
/* Aperf/Mperf registers support */
125
if (cpuid_level >= 6 && (cpuid_ecx(6) & 0x1))
126
cpu_info->caps |= CPUPOWER_CAP_APERF;
127
128
/* AMD or Hygon Boost state enable/disable register */
129
if (cpu_info->vendor == X86_VENDOR_AMD ||
130
cpu_info->vendor == X86_VENDOR_HYGON) {
131
if (ext_cpuid_level >= 0x80000007) {
132
if (cpuid_edx(0x80000007) & (1 << 9)) {
133
cpu_info->caps |= CPUPOWER_CAP_AMD_CPB;
134
135
if (cpu_info->family >= 0x17)
136
cpu_info->caps |= CPUPOWER_CAP_AMD_CPB_MSR;
137
}
138
139
if ((cpuid_edx(0x80000007) & (1 << 7)) &&
140
cpu_info->family != 0x14) {
141
/* HW pstate was not implemented in family 0x14 */
142
cpu_info->caps |= CPUPOWER_CAP_AMD_HW_PSTATE;
143
144
if (cpu_info->family >= 0x17)
145
cpu_info->caps |= CPUPOWER_CAP_AMD_PSTATEDEF;
146
}
147
}
148
149
if (ext_cpuid_level >= 0x80000008 &&
150
cpuid_ebx(0x80000008) & (1 << 4))
151
cpu_info->caps |= CPUPOWER_CAP_AMD_RDPRU;
152
153
if (cpupower_amd_pstate_enabled()) {
154
cpu_info->caps |= CPUPOWER_CAP_AMD_PSTATE;
155
156
/*
157
* If AMD P-State is enabled, the firmware will treat
158
* AMD P-State function as high priority.
159
*/
160
cpu_info->caps &= ~CPUPOWER_CAP_AMD_CPB;
161
cpu_info->caps &= ~CPUPOWER_CAP_AMD_CPB_MSR;
162
cpu_info->caps &= ~CPUPOWER_CAP_AMD_HW_PSTATE;
163
cpu_info->caps &= ~CPUPOWER_CAP_AMD_PSTATEDEF;
164
}
165
}
166
167
if (cpu_info->vendor == X86_VENDOR_INTEL) {
168
if (cpuid_level >= 6 &&
169
(cpuid_eax(6) & (1 << 1)))
170
cpu_info->caps |= CPUPOWER_CAP_INTEL_IDA;
171
}
172
173
if (cpu_info->vendor == X86_VENDOR_INTEL) {
174
/* Intel's perf-bias MSR support */
175
if (cpuid_level >= 6 && (cpuid_ecx(6) & (1 << 3)))
176
cpu_info->caps |= CPUPOWER_CAP_PERF_BIAS;
177
178
/* Intel's Turbo Ratio Limit support */
179
if (cpu_info->family == 6) {
180
switch (cpu_info->model) {
181
case 0x1A: /* Core i7, Xeon 5500 series
182
* Bloomfield, Gainstown NHM-EP
183
*/
184
case 0x1E: /* Core i7 and i5 Processor
185
* Clarksfield, Lynnfield, Jasper Forest
186
*/
187
case 0x1F: /* Core i7 and i5 Processor - Nehalem */
188
case 0x25: /* Westmere Client
189
* Clarkdale, Arrandale
190
*/
191
case 0x2C: /* Westmere EP - Gulftown */
192
cpu_info->caps |= CPUPOWER_CAP_HAS_TURBO_RATIO;
193
break;
194
case 0x2A: /* SNB */
195
case 0x2D: /* SNB Xeon */
196
case 0x3A: /* IVB */
197
case 0x3E: /* IVB Xeon */
198
cpu_info->caps |= CPUPOWER_CAP_HAS_TURBO_RATIO;
199
cpu_info->caps |= CPUPOWER_CAP_IS_SNB;
200
break;
201
case 0x2E: /* Nehalem-EX Xeon - Beckton */
202
case 0x2F: /* Westmere-EX Xeon - Eagleton */
203
default:
204
break;
205
}
206
}
207
}
208
209
/* printf("ID: %u - Extid: 0x%x - Caps: 0x%llx\n",
210
cpuid_level, ext_cpuid_level, cpu_info->caps);
211
*/
212
return ret;
213
}
214
215