aboutsummaryrefslogtreecommitdiffstats
path: root/tools/power/cpupower/utils/helpers/cpuid.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/power/cpupower/utils/helpers/cpuid.c')
-rw-r--r--tools/power/cpupower/utils/helpers/cpuid.c176
1 files changed, 176 insertions, 0 deletions
diff --git a/tools/power/cpupower/utils/helpers/cpuid.c b/tools/power/cpupower/utils/helpers/cpuid.c
new file mode 100644
index 000000000000..906895d21cce
--- /dev/null
+++ b/tools/power/cpupower/utils/helpers/cpuid.c
@@ -0,0 +1,176 @@
1#include <stdio.h>
2#include <errno.h>
3#include <string.h>
4#include <unistd.h>
5#include <stdlib.h>
6
7#include "helpers/helpers.h"
8
9static const char *cpu_vendor_table[X86_VENDOR_MAX] = {
10 "Unknown", "GenuineIntel", "AuthenticAMD",
11};
12
13#if defined(__i386__) || defined(__x86_64__)
14
15/* from gcc */
16#include <cpuid.h>
17
18/*
19 * CPUID functions returning a single datum
20 *
21 * Define unsigned int cpuid_e[abcd]x(unsigned int op)
22 */
23#define cpuid_func(reg) \
24 unsigned int cpuid_##reg(unsigned int op) \
25 { \
26 unsigned int eax, ebx, ecx, edx; \
27 __cpuid(op, eax, ebx, ecx, edx); \
28 return reg; \
29 }
30cpuid_func(eax);
31cpuid_func(ebx);
32cpuid_func(ecx);
33cpuid_func(edx);
34
35#endif /* defined(__i386__) || defined(__x86_64__) */
36
37/* get_cpu_info
38 *
39 * Extract CPU vendor, family, model, stepping info from /proc/cpuinfo
40 *
41 * Returns 0 on success or a negativ error code
42 *
43 * TBD: Should there be a cpuid alternative for this if /proc is not mounted?
44 */
45int get_cpu_info(unsigned int cpu, struct cpupower_cpu_info *cpu_info)
46{
47 FILE *fp;
48 char value[64];
49 unsigned int proc, x;
50 unsigned int unknown = 0xffffff;
51 unsigned int cpuid_level, ext_cpuid_level;
52
53 int ret = -EINVAL;
54
55 cpu_info->vendor = X86_VENDOR_UNKNOWN;
56 cpu_info->family = unknown;
57 cpu_info->model = unknown;
58 cpu_info->stepping = unknown;
59 cpu_info->caps = 0;
60
61 fp = fopen("/proc/cpuinfo", "r");
62 if (!fp)
63 return -EIO;
64
65 while (!feof(fp)) {
66 if (!fgets(value, 64, fp))
67 continue;
68 value[63 - 1] = '\0';
69
70 if (!strncmp(value, "processor\t: ", 12))
71 sscanf(value, "processor\t: %u", &proc);
72
73 if (proc != cpu)
74 continue;
75
76 /* Get CPU vendor */
77 if (!strncmp(value, "vendor_id", 9)) {
78 for (x = 1; x < X86_VENDOR_MAX; x++) {
79 if (strstr(value, cpu_vendor_table[x]))
80 cpu_info->vendor = x;
81 }
82 /* Get CPU family, etc. */
83 } else if (!strncmp(value, "cpu family\t: ", 13)) {
84 sscanf(value, "cpu family\t: %u",
85 &cpu_info->family);
86 } else if (!strncmp(value, "model\t\t: ", 9)) {
87 sscanf(value, "model\t\t: %u",
88 &cpu_info->model);
89 } else if (!strncmp(value, "stepping\t: ", 10)) {
90 sscanf(value, "stepping\t: %u",
91 &cpu_info->stepping);
92
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) {
98 ret = -EINVAL;
99 goto out;
100 }
101
102 ret = 0;
103 goto out;
104 }
105 }
106 ret = -ENODEV;
107out:
108 fclose(fp);
109 /* Get some useful CPU capabilities from cpuid */
110 if (cpu_info->vendor != X86_VENDOR_AMD &&
111 cpu_info->vendor != X86_VENDOR_INTEL)
112 return ret;
113
114 cpuid_level = cpuid_eax(0);
115 ext_cpuid_level = cpuid_eax(0x80000000);
116
117 /* Invariant TSC */
118 if (ext_cpuid_level >= 0x80000007 &&
119 (cpuid_edx(0x80000007) & (1 << 8)))
120 cpu_info->caps |= CPUPOWER_CAP_INV_TSC;
121
122 /* Aperf/Mperf registers support */
123 if (cpuid_level >= 6 && (cpuid_ecx(6) & 0x1))
124 cpu_info->caps |= CPUPOWER_CAP_APERF;
125
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;
131 }
132
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;
137 }
138
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;
143
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
149 */
150 case 0x1E: /* Core i7 and i5 Processor
151 * Clarksfield, Lynnfield, Jasper Forest
152 */
153 case 0x1F: /* Core i7 and i5 Processor - Nehalem */
154 case 0x25: /* Westmere Client
155 * Clarkdale, Arrandale
156 */
157 case 0x2C: /* Westmere EP - Gulftown */
158 cpu_info->caps |= CPUPOWER_CAP_HAS_TURBO_RATIO;
159 case 0x2A: /* SNB */
160 case 0x2D: /* SNB Xeon */
161 cpu_info->caps |= CPUPOWER_CAP_HAS_TURBO_RATIO;
162 cpu_info->caps |= CPUPOWER_CAP_IS_SNB;
163 break;
164 case 0x2E: /* Nehalem-EX Xeon - Beckton */
165 case 0x2F: /* Westmere-EX Xeon - Eagleton */
166 default:
167 break;
168 }
169 }
170 }
171
172 /* printf("ID: %u - Extid: 0x%x - Caps: 0x%llx\n",
173 cpuid_level, ext_cpuid_level, cpu_info->caps);
174 */
175 return ret;
176}