1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23#include <stdio.h>
24#include <unistd.h>
25#include <sys/types.h>
26#include <sys/stat.h>
27#include <sys/resource.h>
28#include <fcntl.h>
29#include <signal.h>
30#include <sys/time.h>
31#include <stdlib.h>
32#include <string.h>
33
34unsigned int verbose;
35unsigned int read_only;
36char *progname;
37unsigned long long new_bias;
38int cpu = -1;
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64void usage(void)
65{
66 printf("%s: [-c cpu] [-v] "
67 "(-r | 'performance' | 'normal' | 'powersave' | n)\n",
68 progname);
69 exit(1);
70}
71
72#define MSR_IA32_ENERGY_PERF_BIAS 0x000001b0
73
74#define BIAS_PERFORMANCE 0
75#define BIAS_BALANCE 6
76#define BIAS_POWERSAVE 15
77
78void cmdline(int argc, char **argv)
79{
80 int opt;
81
82 progname = argv[0];
83
84 while ((opt = getopt(argc, argv, "+rvc:")) != -1) {
85 switch (opt) {
86 case 'c':
87 cpu = atoi(optarg);
88 break;
89 case 'r':
90 read_only = 1;
91 break;
92 case 'v':
93 verbose++;
94 break;
95 default:
96 usage();
97 }
98 }
99
100 if (read_only && (argc > optind))
101 usage();
102
103
104
105
106 if (!read_only) {
107
108 if (argc != optind + 1) {
109 printf("must supply -r or policy param\n");
110 usage();
111 }
112
113 if (!strcmp("performance", argv[optind])) {
114 new_bias = BIAS_PERFORMANCE;
115 } else if (!strcmp("normal", argv[optind])) {
116 new_bias = BIAS_BALANCE;
117 } else if (!strcmp("powersave", argv[optind])) {
118 new_bias = BIAS_POWERSAVE;
119 } else {
120 char *endptr;
121
122 new_bias = strtoull(argv[optind], &endptr, 0);
123 if (endptr == argv[optind] ||
124 new_bias > BIAS_POWERSAVE) {
125 fprintf(stderr, "invalid value: %s\n",
126 argv[optind]);
127 usage();
128 }
129 }
130 }
131}
132
133
134
135
136
137void validate_cpuid(void)
138{
139 unsigned int eax, ebx, ecx, edx, max_level;
140 unsigned int fms, family, model, stepping;
141
142 eax = ebx = ecx = edx = 0;
143
144 asm("cpuid" : "=a" (max_level), "=b" (ebx), "=c" (ecx),
145 "=d" (edx) : "a" (0));
146
147 if (ebx != 0x756e6547 || edx != 0x49656e69 || ecx != 0x6c65746e) {
148 if (verbose)
149 fprintf(stderr, "%.4s%.4s%.4s != GenuineIntel",
150 (char *)&ebx, (char *)&edx, (char *)&ecx);
151 exit(1);
152 }
153
154 asm("cpuid" : "=a" (fms), "=c" (ecx), "=d" (edx) : "a" (1) : "ebx");
155 family = (fms >> 8) & 0xf;
156 model = (fms >> 4) & 0xf;
157 stepping = fms & 0xf;
158 if (family == 6 || family == 0xf)
159 model += ((fms >> 16) & 0xf) << 4;
160
161 if (verbose > 1)
162 printf("CPUID %d levels family:model:stepping "
163 "0x%x:%x:%x (%d:%d:%d)\n", max_level,
164 family, model, stepping, family, model, stepping);
165
166 if (!(edx & (1 << 5))) {
167 if (verbose)
168 printf("CPUID: no MSR\n");
169 exit(1);
170 }
171
172
173
174
175
176 asm("cpuid" : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx) : "a" (6));
177 if (verbose)
178 printf("CPUID.06H.ECX: 0x%x\n", ecx);
179 if (!(ecx & (1 << 3))) {
180 if (verbose)
181 printf("CPUID: No MSR_IA32_ENERGY_PERF_BIAS\n");
182 exit(1);
183 }
184 return;
185}
186
187unsigned long long get_msr(int cpu, int offset)
188{
189 unsigned long long msr;
190 char msr_path[32];
191 int retval;
192 int fd;
193
194 sprintf(msr_path, "/dev/cpu/%d/msr", cpu);
195 fd = open(msr_path, O_RDONLY);
196 if (fd < 0) {
197 printf("Try \"# modprobe msr\"\n");
198 perror(msr_path);
199 exit(1);
200 }
201
202 retval = pread(fd, &msr, sizeof msr, offset);
203
204 if (retval != sizeof msr) {
205 printf("pread cpu%d 0x%x = %d\n", cpu, offset, retval);
206 exit(-2);
207 }
208 close(fd);
209 return msr;
210}
211
212unsigned long long put_msr(int cpu, unsigned long long new_msr, int offset)
213{
214 unsigned long long old_msr;
215 char msr_path[32];
216 int retval;
217 int fd;
218
219 sprintf(msr_path, "/dev/cpu/%d/msr", cpu);
220 fd = open(msr_path, O_RDWR);
221 if (fd < 0) {
222 perror(msr_path);
223 exit(1);
224 }
225
226 retval = pread(fd, &old_msr, sizeof old_msr, offset);
227 if (retval != sizeof old_msr) {
228 perror("pwrite");
229 printf("pread cpu%d 0x%x = %d\n", cpu, offset, retval);
230 exit(-2);
231 }
232
233 retval = pwrite(fd, &new_msr, sizeof new_msr, offset);
234 if (retval != sizeof new_msr) {
235 perror("pwrite");
236 printf("pwrite cpu%d 0x%x = %d\n", cpu, offset, retval);
237 exit(-2);
238 }
239
240 close(fd);
241
242 return old_msr;
243}
244
245void print_msr(int cpu)
246{
247 printf("cpu%d: 0x%016llx\n",
248 cpu, get_msr(cpu, MSR_IA32_ENERGY_PERF_BIAS));
249}
250
251void update_msr(int cpu)
252{
253 unsigned long long previous_msr;
254
255 previous_msr = put_msr(cpu, new_bias, MSR_IA32_ENERGY_PERF_BIAS);
256
257 if (verbose)
258 printf("cpu%d msr0x%x 0x%016llx -> 0x%016llx\n",
259 cpu, MSR_IA32_ENERGY_PERF_BIAS, previous_msr, new_bias);
260
261 return;
262}
263
264char *proc_stat = "/proc/stat";
265
266
267
268void for_every_cpu(void (func)(int))
269{
270 FILE *fp;
271 int retval;
272
273 fp = fopen(proc_stat, "r");
274 if (fp == NULL) {
275 perror(proc_stat);
276 exit(1);
277 }
278
279 retval = fscanf(fp, "cpu %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d\n");
280 if (retval != 0) {
281 perror("/proc/stat format");
282 exit(1);
283 }
284
285 while (1) {
286 int cpu;
287
288 retval = fscanf(fp,
289 "cpu%u %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d\n",
290 &cpu);
291 if (retval != 1)
292 break;
293
294 func(cpu);
295 }
296 fclose(fp);
297}
298
299int main(int argc, char **argv)
300{
301 cmdline(argc, argv);
302
303 if (verbose > 1)
304 printf("x86_energy_perf_policy Nov 24, 2010"
305 " - Len Brown <lenb@kernel.org>\n");
306 if (verbose > 1 && !read_only)
307 printf("new_bias %lld\n", new_bias);
308
309 validate_cpuid();
310
311 if (cpu != -1) {
312 if (read_only)
313 print_msr(cpu);
314 else
315 update_msr(cpu);
316 } else {
317 if (read_only)
318 for_every_cpu(print_msr);
319 else
320 for_every_cpu(update_msr);
321 }
322
323 return 0;
324}
325