]>
Commit | Line | Data |
---|---|---|
b2441318 | 1 | // SPDX-License-Identifier: GPL-2.0 |
7fe2f639 DB |
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", | |
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 | */ | |
d0e4a193 | 46 | int get_cpu_info(struct cpupower_cpu_info *cpu_info) |
7fe2f639 DB |
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 | ||
2cd005ca | 71 | if (!strncmp(value, "processor\t: ", 12)) |
7fe2f639 | 72 | sscanf(value, "processor\t: %u", &proc); |
2cd005ca | 73 | |
d0e4a193 | 74 | if (proc != (unsigned int)base_cpu) |
7fe2f639 DB |
75 | continue; |
76 | ||
77 | /* Get CPU vendor */ | |
2cd005ca | 78 | if (!strncmp(value, "vendor_id", 9)) { |
7fe2f639 DB |
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. */ | |
2cd005ca | 84 | } else if (!strncmp(value, "cpu family\t: ", 13)) { |
7fe2f639 DB |
85 | sscanf(value, "cpu family\t: %u", |
86 | &cpu_info->family); | |
2cd005ca | 87 | } else if (!strncmp(value, "model\t\t: ", 9)) { |
7fe2f639 DB |
88 | sscanf(value, "model\t\t: %u", |
89 | &cpu_info->model); | |
2cd005ca | 90 | } else if (!strncmp(value, "stepping\t: ", 10)) { |
7fe2f639 DB |
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_INTEL) | |
113 | return ret; | |
114 | ||
115 | cpuid_level = cpuid_eax(0); | |
116 | ext_cpuid_level = cpuid_eax(0x80000000); | |
117 | ||
118 | /* Invariant TSC */ | |
119 | if (ext_cpuid_level >= 0x80000007 && | |
120 | (cpuid_edx(0x80000007) & (1 << 8))) | |
121 | cpu_info->caps |= CPUPOWER_CAP_INV_TSC; | |
122 | ||
123 | /* Aperf/Mperf registers support */ | |
124 | if (cpuid_level >= 6 && (cpuid_ecx(6) & 0x1)) | |
125 | cpu_info->caps |= CPUPOWER_CAP_APERF; | |
126 | ||
127 | /* AMD Boost state enable/disable register */ | |
128 | if (cpu_info->vendor == X86_VENDOR_AMD) { | |
129 | if (ext_cpuid_level >= 0x80000007 && | |
130 | (cpuid_edx(0x80000007) & (1 << 9))) | |
131 | cpu_info->caps |= CPUPOWER_CAP_AMD_CBP; | |
132 | } | |
133 | ||
029e9f73 TR |
134 | if (cpu_info->vendor == X86_VENDOR_INTEL) { |
135 | if (cpuid_level >= 6 && | |
136 | (cpuid_eax(6) & (1 << 1))) | |
137 | cpu_info->caps |= CPUPOWER_CAP_INTEL_IDA; | |
138 | } | |
139 | ||
7fe2f639 | 140 | if (cpu_info->vendor == X86_VENDOR_INTEL) { |
8fb2e440 | 141 | /* Intel's perf-bias MSR support */ |
7fe2f639 DB |
142 | if (cpuid_level >= 6 && (cpuid_ecx(6) & (1 << 3))) |
143 | cpu_info->caps |= CPUPOWER_CAP_PERF_BIAS; | |
8fb2e440 TR |
144 | |
145 | /* Intel's Turbo Ratio Limit support */ | |
146 | if (cpu_info->family == 6) { | |
147 | switch (cpu_info->model) { | |
148 | case 0x1A: /* Core i7, Xeon 5500 series | |
149 | * Bloomfield, Gainstown NHM-EP | |
150 | */ | |
151 | case 0x1E: /* Core i7 and i5 Processor | |
152 | * Clarksfield, Lynnfield, Jasper Forest | |
153 | */ | |
154 | case 0x1F: /* Core i7 and i5 Processor - Nehalem */ | |
155 | case 0x25: /* Westmere Client | |
156 | * Clarkdale, Arrandale | |
157 | */ | |
158 | case 0x2C: /* Westmere EP - Gulftown */ | |
159 | cpu_info->caps |= CPUPOWER_CAP_HAS_TURBO_RATIO; | |
4cca0457 | 160 | break; |
8fb2e440 TR |
161 | case 0x2A: /* SNB */ |
162 | case 0x2D: /* SNB Xeon */ | |
8d219e36 TR |
163 | case 0x3A: /* IVB */ |
164 | case 0x3E: /* IVB Xeon */ | |
8fb2e440 TR |
165 | cpu_info->caps |= CPUPOWER_CAP_HAS_TURBO_RATIO; |
166 | cpu_info->caps |= CPUPOWER_CAP_IS_SNB; | |
167 | break; | |
168 | case 0x2E: /* Nehalem-EX Xeon - Beckton */ | |
169 | case 0x2F: /* Westmere-EX Xeon - Eagleton */ | |
170 | default: | |
171 | break; | |
172 | } | |
173 | } | |
7fe2f639 DB |
174 | } |
175 | ||
176 | /* printf("ID: %u - Extid: 0x%x - Caps: 0x%llx\n", | |
177 | cpuid_level, ext_cpuid_level, cpu_info->caps); | |
178 | */ | |
179 | return ret; | |
180 | } |