1
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
10static const char *cpu_vendor_table[X86_VENDOR_MAX] = {
11 "Unknown", "GenuineIntel", "AuthenticAMD", "HygonGenuine",
12};
13
14#if defined(__i386__) || defined(__x86_64__)
15
16
17#include <cpuid.h>
18
19
20
21
22
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 }
31cpuid_func(eax);
32cpuid_func(ebx);
33cpuid_func(ecx);
34cpuid_func(edx);
35
36#endif
37
38
39
40
41
42
43
44
45
46int 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
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
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
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;
108out:
109 fclose(fp);
110
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
120 if (ext_cpuid_level >= 0x80000007 &&
121 (cpuid_edx(0x80000007) & (1 << 8)))
122 cpu_info->caps |= CPUPOWER_CAP_INV_TSC;
123
124
125 if (cpuid_level >= 6 && (cpuid_ecx(6) & 0x1))
126 cpu_info->caps |= CPUPOWER_CAP_APERF;
127
128
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
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
158
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
175 if (cpuid_level >= 6 && (cpuid_ecx(6) & (1 << 3)))
176 cpu_info->caps |= CPUPOWER_CAP_PERF_BIAS;
177
178
179 if (cpu_info->family == 6) {
180 switch (cpu_info->model) {
181 case 0x1A:
182
183
184 case 0x1E:
185
186
187 case 0x1F:
188 case 0x25:
189
190
191 case 0x2C:
192 cpu_info->caps |= CPUPOWER_CAP_HAS_TURBO_RATIO;
193 break;
194 case 0x2A:
195 case 0x2D:
196 case 0x3A:
197 case 0x3E:
198 cpu_info->caps |= CPUPOWER_CAP_HAS_TURBO_RATIO;
199 cpu_info->caps |= CPUPOWER_CAP_IS_SNB;
200 break;
201 case 0x2E:
202 case 0x2F:
203 default:
204 break;
205 }
206 }
207 }
208
209
210
211
212 return ret;
213}
214