aboutsummaryrefslogtreecommitdiffstats
path: root/tools/power/cpupower/utils
diff options
context:
space:
mode:
authorDominik Brodowski <linux@dominikbrodowski.net>2011-03-30 10:30:11 -0400
committerDominik Brodowski <linux@dominikbrodowski.net>2011-07-29 12:35:36 -0400
commit7fe2f6399a84760a9af8896ac152728250f82adb (patch)
treefa4bf236359b8d6d9f8d6ff823ddd3e839da5768 /tools/power/cpupower/utils
parent02f8c6aee8df3cdc935e9bdd4f2d020306035dbe (diff)
cpupowerutils - cpufrequtils extended with quite some features
CPU power consumption vs performance tuning is no longer limited to CPU frequency switching anymore: deep sleep states, traditional dynamic frequency scaling and hidden turbo/boost frequencies are tied close together and depend on each other. The first two exist on different architectures like PPC, Itanium and ARM, the latter (so far) only on X86. On X86 the APU (CPU+GPU) will only run most efficiently if CPU and GPU has proper power management in place. Users and Developers want to have *one* tool to get an overview what their system supports and to monitor and debug CPU power management in detail. The tool should compile and work on as many architectures as possible. Once this tool stabilizes a bit, it is intended to replace the Intel-specific tools in tools/power/x86 Signed-off-by: Dominik Brodowski <linux@dominikbrodowski.net>
Diffstat (limited to 'tools/power/cpupower/utils')
-rw-r--r--tools/power/cpupower/utils/builtin.h18
-rw-r--r--tools/power/cpupower/utils/cpufreq-info.c665
-rw-r--r--tools/power/cpupower/utils/cpufreq-set.c357
-rw-r--r--tools/power/cpupower/utils/cpuidle-info.c245
-rw-r--r--tools/power/cpupower/utils/cpupower-info.c154
-rw-r--r--tools/power/cpupower/utils/cpupower-set.c153
-rw-r--r--tools/power/cpupower/utils/cpupower.c201
-rw-r--r--tools/power/cpupower/utils/helpers/amd.c137
-rw-r--r--tools/power/cpupower/utils/helpers/bitmask.c290
-rw-r--r--tools/power/cpupower/utils/helpers/bitmask.h33
-rw-r--r--tools/power/cpupower/utils/helpers/cpuid.c145
-rw-r--r--tools/power/cpupower/utils/helpers/helpers.h180
-rw-r--r--tools/power/cpupower/utils/helpers/misc.c34
-rw-r--r--tools/power/cpupower/utils/helpers/msr.c122
-rw-r--r--tools/power/cpupower/utils/helpers/pci.c44
-rw-r--r--tools/power/cpupower/utils/helpers/sysfs.c350
-rw-r--r--tools/power/cpupower/utils/helpers/sysfs.h23
-rw-r--r--tools/power/cpupower/utils/helpers/topology.c108
-rw-r--r--tools/power/cpupower/utils/idle_monitor/amd_fam14h_idle.c340
-rw-r--r--tools/power/cpupower/utils/idle_monitor/cpuidle_sysfs.c185
-rw-r--r--tools/power/cpupower/utils/idle_monitor/cpupower-monitor.c446
-rw-r--r--tools/power/cpupower/utils/idle_monitor/cpupower-monitor.h68
-rw-r--r--tools/power/cpupower/utils/idle_monitor/idle_monitors.def7
-rw-r--r--tools/power/cpupower/utils/idle_monitor/idle_monitors.h18
-rw-r--r--tools/power/cpupower/utils/idle_monitor/mperf_monitor.c258
-rw-r--r--tools/power/cpupower/utils/idle_monitor/nhm_idle.c212
-rw-r--r--tools/power/cpupower/utils/idle_monitor/snb_idle.c189
27 files changed, 4982 insertions, 0 deletions
diff --git a/tools/power/cpupower/utils/builtin.h b/tools/power/cpupower/utils/builtin.h
new file mode 100644
index 00000000000..c870ffba521
--- /dev/null
+++ b/tools/power/cpupower/utils/builtin.h
@@ -0,0 +1,18 @@
1#ifndef BUILTIN_H
2#define BUILTIN_H
3
4extern int cmd_set(int argc, const char **argv);
5extern int cmd_info(int argc, const char **argv);
6extern int cmd_freq_set(int argc, const char **argv);
7extern int cmd_freq_info(int argc, const char **argv);
8extern int cmd_idle_info(int argc, const char **argv);
9extern int cmd_monitor(int argc, const char **argv);
10
11extern void set_help(void);
12extern void info_help(void);
13extern void freq_set_help(void);
14extern void freq_info_help(void);
15extern void idle_info_help(void);
16extern void monitor_help(void);
17
18#endif
diff --git a/tools/power/cpupower/utils/cpufreq-info.c b/tools/power/cpupower/utils/cpufreq-info.c
new file mode 100644
index 00000000000..eaa8be06edf
--- /dev/null
+++ b/tools/power/cpupower/utils/cpufreq-info.c
@@ -0,0 +1,665 @@
1/*
2 * (C) 2004-2009 Dominik Brodowski <linux@dominikbrodowski.de>
3 *
4 * Licensed under the terms of the GNU GPL License version 2.
5 */
6
7
8#include <unistd.h>
9#include <stdio.h>
10#include <errno.h>
11#include <stdlib.h>
12#include <string.h>
13
14#include <getopt.h>
15
16#include "cpufreq.h"
17#include "helpers/helpers.h"
18#include "helpers/bitmask.h"
19
20#define LINE_LEN 10
21
22static unsigned int count_cpus(void)
23{
24 FILE *fp;
25 char value[LINE_LEN];
26 unsigned int ret = 0;
27 unsigned int cpunr = 0;
28
29 fp = fopen("/proc/stat", "r");
30 if(!fp) {
31 printf(_("Couldn't count the number of CPUs (%s: %s), assuming 1\n"), "/proc/stat", strerror(errno));
32 return 1;
33 }
34
35 while (!feof(fp)) {
36 if (!fgets(value, LINE_LEN, fp))
37 continue;
38 value[LINE_LEN - 1] = '\0';
39 if (strlen(value) < (LINE_LEN - 2))
40 continue;
41 if (strstr(value, "cpu "))
42 continue;
43 if (sscanf(value, "cpu%d ", &cpunr) != 1)
44 continue;
45 if (cpunr > ret)
46 ret = cpunr;
47 }
48 fclose(fp);
49
50 /* cpu count starts from 0, on error return 1 (UP) */
51 return (ret+1);
52}
53
54
55static void proc_cpufreq_output(void)
56{
57 unsigned int cpu, nr_cpus;
58 struct cpufreq_policy *policy;
59 unsigned int min_pctg = 0;
60 unsigned int max_pctg = 0;
61 unsigned long min, max;
62
63 printf(_(" minimum CPU frequency - maximum CPU frequency - governor\n"));
64
65 nr_cpus = count_cpus();
66 for (cpu=0; cpu < nr_cpus; cpu++) {
67 policy = cpufreq_get_policy(cpu);
68 if (!policy)
69 continue;
70
71 if (cpufreq_get_hardware_limits(cpu, &min, &max)) {
72 max = 0;
73 } else {
74 min_pctg = (policy->min * 100) / max;
75 max_pctg = (policy->max * 100) / max;
76 }
77 printf("CPU%3d %9lu kHz (%3d %%) - %9lu kHz (%3d %%) - %s\n",
78 cpu , policy->min, max ? min_pctg : 0, policy->max, max ? max_pctg : 0, policy->governor);
79
80 cpufreq_put_policy(policy);
81 }
82}
83
84static void print_speed(unsigned long speed)
85{
86 unsigned long tmp;
87
88 if (speed > 1000000) {
89 tmp = speed % 10000;
90 if (tmp >= 5000)
91 speed += 10000;
92 printf ("%u.%02u GHz", ((unsigned int) speed/1000000),
93 ((unsigned int) (speed%1000000)/10000));
94 } else if (speed > 100000) {
95 tmp = speed % 1000;
96 if (tmp >= 500)
97 speed += 1000;
98 printf ("%u MHz", ((unsigned int) speed / 1000));
99 } else if (speed > 1000) {
100 tmp = speed % 100;
101 if (tmp >= 50)
102 speed += 100;
103 printf ("%u.%01u MHz", ((unsigned int) speed/1000),
104 ((unsigned int) (speed%1000)/100));
105 } else
106 printf ("%lu kHz", speed);
107
108 return;
109}
110
111static void print_duration(unsigned long duration)
112{
113 unsigned long tmp;
114
115 if (duration > 1000000) {
116 tmp = duration % 10000;
117 if (tmp >= 5000)
118 duration += 10000;
119 printf ("%u.%02u ms", ((unsigned int) duration/1000000),
120 ((unsigned int) (duration%1000000)/10000));
121 } else if (duration > 100000) {
122 tmp = duration % 1000;
123 if (tmp >= 500)
124 duration += 1000;
125 printf ("%u us", ((unsigned int) duration / 1000));
126 } else if (duration > 1000) {
127 tmp = duration % 100;
128 if (tmp >= 50)
129 duration += 100;
130 printf ("%u.%01u us", ((unsigned int) duration/1000),
131 ((unsigned int) (duration%1000)/100));
132 } else
133 printf ("%lu ns", duration);
134
135 return;
136}
137
138/* --boost / -b */
139
140static int get_boost_mode(unsigned int cpu) {
141 int support, active, b_states = 0, ret, pstate_no, i;
142 /* ToDo: Make this more global */
143 unsigned long pstates[MAX_HW_PSTATES] = {0,};
144
145 if (cpupower_cpu_info.vendor != X86_VENDOR_AMD &&
146 cpupower_cpu_info.vendor != X86_VENDOR_INTEL)
147 return 0;
148
149 ret = cpufreq_has_boost_support(cpu, &support, &active, &b_states);
150 if (ret) {
151 printf(_("Error while evaluating Boost Capabilities"
152 " on CPU %d -- are you root?\n"), cpu);
153 return ret;
154 }
155 /* P state changes via MSR are identified via cpuid 80000007
156 on Intel and AMD, but we assume boost capable machines can do that
157 if (cpuid_eax(0x80000000) >= 0x80000007
158 && (cpuid_edx(0x80000007) & (1 << 7)))
159 */
160
161 printf(_(" boost state support: \n"));
162
163 printf(_(" Supported: %s\n"), support ? _("yes") : _("no"));
164 printf(_(" Active: %s\n"), active ? _("yes") : _("no"));
165
166 /* ToDo: Only works for AMD for now... */
167
168 if (cpupower_cpu_info.vendor == X86_VENDOR_AMD &&
169 cpupower_cpu_info.family >= 0x10) {
170 ret = decode_pstates(cpu, cpupower_cpu_info.family, b_states,
171 pstates, &pstate_no);
172 if (ret)
173 return ret;
174 } else
175 return 0;
176
177 printf(_(" Boost States: %d\n"), b_states);
178 printf(_(" Total States: %d\n"), pstate_no);
179 for (i = 0; i < pstate_no; i++) {
180 if (i < b_states)
181 printf(_(" Pstate-Pb%d: %luMHz (boost state)\n"),
182 i, pstates[i]);
183 else
184 printf(_(" Pstate-P%d: %luMHz\n"),
185 i - b_states, pstates[i]);
186 }
187 return 0;
188}
189
190static void debug_output_one(unsigned int cpu)
191{
192 char *driver;
193 struct cpufreq_affected_cpus *cpus;
194 struct cpufreq_available_frequencies *freqs;
195 unsigned long min, max, freq_kernel, freq_hardware;
196 unsigned long total_trans, latency;
197 unsigned long long total_time;
198 struct cpufreq_policy *policy;
199 struct cpufreq_available_governors * governors;
200 struct cpufreq_stats *stats;
201
202 if (cpufreq_cpu_exists(cpu)) {
203 return;
204 }
205
206 freq_kernel = cpufreq_get_freq_kernel(cpu);
207 freq_hardware = cpufreq_get_freq_hardware(cpu);
208
209 driver = cpufreq_get_driver(cpu);
210 if (!driver) {
211 printf(_(" no or unknown cpufreq driver is active on this CPU\n"));
212 } else {
213 printf(_(" driver: %s\n"), driver);
214 cpufreq_put_driver(driver);
215 }
216
217 cpus = cpufreq_get_related_cpus(cpu);
218 if (cpus) {
219 printf(_(" CPUs which run at the same hardware frequency: "));
220 while (cpus->next) {
221 printf("%d ", cpus->cpu);
222 cpus = cpus->next;
223 }
224 printf("%d\n", cpus->cpu);
225 cpufreq_put_related_cpus(cpus);
226 }
227
228 cpus = cpufreq_get_affected_cpus(cpu);
229 if (cpus) {
230 printf(_(" CPUs which need to have their frequency coordinated by software: "));
231 while (cpus->next) {
232 printf("%d ", cpus->cpu);
233 cpus = cpus->next;
234 }
235 printf("%d\n", cpus->cpu);
236 cpufreq_put_affected_cpus(cpus);
237 }
238
239 latency = cpufreq_get_transition_latency(cpu);
240 if (latency) {
241 printf(_(" maximum transition latency: "));
242 print_duration(latency);
243 printf(".\n");
244 }
245
246 if (!(cpufreq_get_hardware_limits(cpu, &min, &max))) {
247 printf(_(" hardware limits: "));
248 print_speed(min);
249 printf(" - ");
250 print_speed(max);
251 printf("\n");
252 }
253
254 freqs = cpufreq_get_available_frequencies(cpu);
255 if (freqs) {
256 printf(_(" available frequency steps: "));
257 while (freqs->next) {
258 print_speed(freqs->frequency);
259 printf(", ");
260 freqs = freqs->next;
261 }
262 print_speed(freqs->frequency);
263 printf("\n");
264 cpufreq_put_available_frequencies(freqs);
265 }
266
267 governors = cpufreq_get_available_governors(cpu);
268 if (governors) {
269 printf(_(" available cpufreq governors: "));
270 while (governors->next) {
271 printf("%s, ", governors->governor);
272 governors = governors->next;
273 }
274 printf("%s\n", governors->governor);
275 cpufreq_put_available_governors(governors);
276 }
277
278 policy = cpufreq_get_policy(cpu);
279 if (policy) {
280 printf(_(" current policy: frequency should be within "));
281 print_speed(policy->min);
282 printf(_(" and "));
283 print_speed(policy->max);
284
285 printf(".\n ");
286 printf(_("The governor \"%s\" may"
287 " decide which speed to use\n within this range.\n"),
288 policy->governor);
289 cpufreq_put_policy(policy);
290 }
291
292 if (freq_kernel || freq_hardware) {
293 printf(_(" current CPU frequency is "));
294 if (freq_hardware) {
295 print_speed(freq_hardware);
296 printf(_(" (asserted by call to hardware)"));
297 }
298 else
299 print_speed(freq_kernel);
300 printf(".\n");
301 }
302 stats = cpufreq_get_stats(cpu, &total_time);
303 if (stats) {
304 printf(_(" cpufreq stats: "));
305 while (stats) {
306 print_speed(stats->frequency);
307 printf(":%.2f%%", (100.0 * stats->time_in_state) / total_time);
308 stats = stats->next;
309 if (stats)
310 printf(", ");
311 }
312 cpufreq_put_stats(stats);
313 total_trans = cpufreq_get_transitions(cpu);
314 if (total_trans)
315 printf(" (%lu)\n", total_trans);
316 else
317 printf("\n");
318 }
319 get_boost_mode(cpu);
320
321}
322
323/* --freq / -f */
324
325static int get_freq_kernel(unsigned int cpu, unsigned int human) {
326 unsigned long freq = cpufreq_get_freq_kernel(cpu);
327 if (!freq)
328 return -EINVAL;
329 if (human) {
330 print_speed(freq);
331 printf("\n");
332 } else
333 printf("%lu\n", freq);
334 return 0;
335}
336
337
338/* --hwfreq / -w */
339
340static int get_freq_hardware(unsigned int cpu, unsigned int human) {
341 unsigned long freq = cpufreq_get_freq_hardware(cpu);
342 if (!freq)
343 return -EINVAL;
344 if (human) {
345 print_speed(freq);
346 printf("\n");
347 } else
348 printf("%lu\n", freq);
349 return 0;
350}
351
352/* --hwlimits / -l */
353
354static int get_hardware_limits(unsigned int cpu) {
355 unsigned long min, max;
356 if (cpufreq_get_hardware_limits(cpu, &min, &max))
357 return -EINVAL;
358 printf("%lu %lu\n", min, max);
359 return 0;
360}
361
362/* --driver / -d */
363
364static int get_driver(unsigned int cpu) {
365 char *driver = cpufreq_get_driver(cpu);
366 if (!driver)
367 return -EINVAL;
368 printf("%s\n", driver);
369 cpufreq_put_driver(driver);
370 return 0;
371}
372
373/* --policy / -p */
374
375static int get_policy(unsigned int cpu) {
376 struct cpufreq_policy *policy = cpufreq_get_policy(cpu);
377 if (!policy)
378 return -EINVAL;
379 printf("%lu %lu %s\n", policy->min, policy->max, policy->governor);
380 cpufreq_put_policy(policy);
381 return 0;
382}
383
384/* --governors / -g */
385
386static int get_available_governors(unsigned int cpu) {
387 struct cpufreq_available_governors *governors = cpufreq_get_available_governors(cpu);
388 if (!governors)
389 return -EINVAL;
390
391 while (governors->next) {
392 printf("%s ", governors->governor);
393 governors = governors->next;
394 }
395 printf("%s\n", governors->governor);
396 cpufreq_put_available_governors(governors);
397 return 0;
398}
399
400
401/* --affected-cpus / -a */
402
403static int get_affected_cpus(unsigned int cpu) {
404 struct cpufreq_affected_cpus *cpus = cpufreq_get_affected_cpus(cpu);
405 if (!cpus)
406 return -EINVAL;
407
408 while (cpus->next) {
409 printf("%d ", cpus->cpu);
410 cpus = cpus->next;
411 }
412 printf("%d\n", cpus->cpu);
413 cpufreq_put_affected_cpus(cpus);
414 return 0;
415}
416
417/* --related-cpus / -r */
418
419static int get_related_cpus(unsigned int cpu) {
420 struct cpufreq_affected_cpus *cpus = cpufreq_get_related_cpus(cpu);
421 if (!cpus)
422 return -EINVAL;
423
424 while (cpus->next) {
425 printf("%d ", cpus->cpu);
426 cpus = cpus->next;
427 }
428 printf("%d\n", cpus->cpu);
429 cpufreq_put_related_cpus(cpus);
430 return 0;
431}
432
433/* --stats / -s */
434
435static int get_freq_stats(unsigned int cpu, unsigned int human) {
436 unsigned long total_trans = cpufreq_get_transitions(cpu);
437 unsigned long long total_time;
438 struct cpufreq_stats *stats = cpufreq_get_stats(cpu, &total_time);
439 while (stats) {
440 if (human) {
441 print_speed(stats->frequency);
442 printf(":%.2f%%", (100.0 * stats->time_in_state) / total_time);
443 }
444 else
445 printf("%lu:%llu", stats->frequency, stats->time_in_state);
446 stats = stats->next;
447 if (stats)
448 printf(", ");
449 }
450 cpufreq_put_stats(stats);
451 if (total_trans)
452 printf(" (%lu)\n", total_trans);
453 return 0;
454}
455
456/* --latency / -y */
457
458static int get_latency(unsigned int cpu, unsigned int human) {
459 unsigned long latency = cpufreq_get_transition_latency(cpu);
460 if (!latency)
461 return -EINVAL;
462
463 if (human) {
464 print_duration(latency);
465 printf("\n");
466 } else
467 printf("%lu\n", latency);
468 return 0;
469}
470
471void freq_info_help(void) {
472 printf(_("Usage: cpupower freqinfo [options]\n"));
473 printf(_("Options:\n"));
474 printf(_(" -e, --debug Prints out debug information [default]\n"));
475 printf(_(" -f, --freq Get frequency the CPU currently runs at, according\n"
476 " to the cpufreq core *\n"));
477 printf(_(" -w, --hwfreq Get frequency the CPU currently runs at, by reading\n"
478 " it from hardware (only available to root) *\n"));
479 printf(_(" -l, --hwlimits Determine the minimum and maximum CPU frequency allowed *\n"));
480 printf(_(" -d, --driver Determines the used cpufreq kernel driver *\n"));
481 printf(_(" -p, --policy Gets the currently used cpufreq policy *\n"));
482 printf(_(" -g, --governors Determines available cpufreq governors *\n"));
483 printf(_(" -r, --related-cpus Determines which CPUs run at the same hardware frequency *\n"));
484 printf(_(" -a, --affected-cpus Determines which CPUs need to have their frequency\n"
485 " coordinated by software *\n"));
486 printf(_(" -s, --stats Shows cpufreq statistics if available\n"));
487 printf(_(" -y, --latency Determines the maximum latency on CPU frequency changes *\n"));
488 printf(_(" -b, --boost Checks for turbo or boost modes *\n"));
489 printf(_(" -o, --proc Prints out information like provided by the /proc/cpufreq\n"
490 " interface in 2.4. and early 2.6. kernels\n"));
491 printf(_(" -m, --human human-readable output for the -f, -w, -s and -y parameters\n"));
492 printf(_(" -h, --help Prints out this screen\n"));
493
494 printf("\n");
495 printf(_("If no argument is given, full output about\n"
496 "cpufreq is printed which is useful e.g. for reporting bugs.\n\n"));
497 printf(_("By default info of CPU 0 is shown which can be overridden \n"
498 "with the cpupower --cpu main command option.\n"));
499}
500
501static struct option info_opts[] = {
502 { .name="debug", .has_arg=no_argument, .flag=NULL, .val='e'},
503 { .name="boost", .has_arg=no_argument, .flag=NULL, .val='b'},
504 { .name="freq", .has_arg=no_argument, .flag=NULL, .val='f'},
505 { .name="hwfreq", .has_arg=no_argument, .flag=NULL, .val='w'},
506 { .name="hwlimits", .has_arg=no_argument, .flag=NULL, .val='l'},
507 { .name="driver", .has_arg=no_argument, .flag=NULL, .val='d'},
508 { .name="policy", .has_arg=no_argument, .flag=NULL, .val='p'},
509 { .name="governors", .has_arg=no_argument, .flag=NULL, .val='g'},
510 { .name="related-cpus", .has_arg=no_argument, .flag=NULL, .val='r'},
511 { .name="affected-cpus",.has_arg=no_argument, .flag=NULL, .val='a'},
512 { .name="stats", .has_arg=no_argument, .flag=NULL, .val='s'},
513 { .name="latency", .has_arg=no_argument, .flag=NULL, .val='y'},
514 { .name="proc", .has_arg=no_argument, .flag=NULL, .val='o'},
515 { .name="human", .has_arg=no_argument, .flag=NULL, .val='m'},
516 { .name="help", .has_arg=no_argument, .flag=NULL, .val='h'},
517 { },
518};
519
520int cmd_freq_info(int argc, char **argv)
521{
522 extern char *optarg;
523 extern int optind, opterr, optopt;
524 int ret = 0, cont = 1;
525 unsigned int cpu = 0;
526 unsigned int human = 0;
527 int output_param = 0;
528
529 do {
530 ret = getopt_long(argc, argv, "hoefwldpgrasmyb", info_opts, NULL);
531 switch (ret) {
532 case '?':
533 output_param = '?';
534 cont = 0;
535 break;
536 case 'h':
537 output_param = 'h';
538 cont = 0;
539 break;
540 case -1:
541 cont = 0;
542 break;
543 case 'b':
544 case 'o':
545 case 'a':
546 case 'r':
547 case 'g':
548 case 'p':
549 case 'd':
550 case 'l':
551 case 'w':
552 case 'f':
553 case 'e':
554 case 's':
555 case 'y':
556 if (output_param) {
557 output_param = -1;
558 cont = 0;
559 break;
560 }
561 output_param = ret;
562 break;
563 case 'm':
564 if (human) {
565 output_param = -1;
566 cont = 0;
567 break;
568 }
569 human = 1;
570 break;
571 default:
572 fprintf(stderr, "invalid or unknown argument\n");
573 return EXIT_FAILURE;
574 }
575 } while(cont);
576
577 switch (output_param) {
578 case 'o':
579 if (!bitmask_isallclear(cpus_chosen)) {
580 printf(_("The argument passed to this tool can't be "
581 "combined with passing a --cpu argument\n"));
582 return -EINVAL;
583 }
584 break;
585 case 0:
586 output_param = 'e';
587 }
588
589 ret = 0;
590
591 /* Default is: show output of CPU 0 only */
592 if (bitmask_isallclear(cpus_chosen))
593 bitmask_setbit(cpus_chosen, 0);
594
595 switch (output_param) {
596 case -1:
597 printf(_("You can't specify more than one --cpu parameter and/or\n"
598 "more than one output-specific argument\n"));
599 return -EINVAL;
600 case '?':
601 printf(_("invalid or unknown argument\n"));
602 freq_info_help();
603 return -EINVAL;
604 case 'h':
605 freq_info_help();
606 return EXIT_SUCCESS;
607 case 'o':
608 proc_cpufreq_output();
609 return EXIT_SUCCESS;
610 }
611
612 for (cpu = bitmask_first(cpus_chosen);
613 cpu <= bitmask_last(cpus_chosen); cpu++) {
614
615 if (!bitmask_isbitset(cpus_chosen, cpu))
616 continue;
617 if (cpufreq_cpu_exists(cpu)) {
618 printf(_("couldn't analyze CPU %d as it doesn't seem to be present\n"), cpu);
619 continue;
620 }
621 printf(_("analyzing CPU %d:\n"), cpu);
622
623 switch (output_param) {
624 case 'b':
625 get_boost_mode(cpu);
626 break;
627 case 'e':
628 debug_output_one(cpu);
629 break;
630 case 'a':
631 ret = get_affected_cpus(cpu);
632 break;
633 case 'r':
634 ret = get_related_cpus(cpu);
635 break;
636 case 'g':
637 ret = get_available_governors(cpu);
638 break;
639 case 'p':
640 ret = get_policy(cpu);
641 break;
642 case 'd':
643 ret = get_driver(cpu);
644 break;
645 case 'l':
646 ret = get_hardware_limits(cpu);
647 break;
648 case 'w':
649 ret = get_freq_hardware(cpu, human);
650 break;
651 case 'f':
652 ret = get_freq_kernel(cpu, human);
653 break;
654 case 's':
655 ret = get_freq_stats(cpu, human);
656 break;
657 case 'y':
658 ret = get_latency(cpu, human);
659 break;
660 }
661 if (ret)
662 return (ret);
663 }
664 return ret;
665}
diff --git a/tools/power/cpupower/utils/cpufreq-set.c b/tools/power/cpupower/utils/cpufreq-set.c
new file mode 100644
index 00000000000..d415b6b52a0
--- /dev/null
+++ b/tools/power/cpupower/utils/cpufreq-set.c
@@ -0,0 +1,357 @@
1/*
2 * (C) 2004-2009 Dominik Brodowski <linux@dominikbrodowski.de>
3 *
4 * Licensed under the terms of the GNU GPL License version 2.
5 */
6
7
8#include <unistd.h>
9#include <stdio.h>
10#include <errno.h>
11#include <stdlib.h>
12#include <limits.h>
13#include <string.h>
14#include <ctype.h>
15
16#include <getopt.h>
17
18#include "cpufreq.h"
19#include "helpers/helpers.h"
20
21#define NORM_FREQ_LEN 32
22
23void freq_set_help(void)
24{
25 printf(_("Usage: cpupower frequency-set [options]\n"));
26 printf(_("Options:\n"));
27 printf(_(" -d FREQ, --min FREQ new minimum CPU frequency the governor may select\n"));
28 printf(_(" -u FREQ, --max FREQ new maximum CPU frequency the governor may select\n"));
29 printf(_(" -g GOV, --governor GOV new cpufreq governor\n"));
30 printf(_(" -f FREQ, --freq FREQ specific frequency to be set. Requires userspace\n"
31 " governor to be available and loaded\n"));
32 printf(_(" -r, --related Switches all hardware-related CPUs\n"));
33 printf(_(" -h, --help Prints out this screen\n"));
34 printf("\n");
35 printf(_("Notes:\n"
36 "1. Omitting the -c or --cpu argument is equivalent to setting it to \"all\"\n"));
37 printf(_("2. The -f FREQ, --freq FREQ parameter cannot be combined with any other parameter\n"
38 " except the -c CPU, --cpu CPU parameter\n"
39 "3. FREQuencies can be passed in Hz, kHz (default), MHz, GHz, or THz\n"
40 " by postfixing the value with the wanted unit name, without any space\n"
41 " (FREQuency in kHz =^ Hz * 0.001 =^ MHz * 1000 =^ GHz * 1000000).\n"));
42
43}
44
45static struct option set_opts[] = {
46 { .name="min", .has_arg=required_argument, .flag=NULL, .val='d'},
47 { .name="max", .has_arg=required_argument, .flag=NULL, .val='u'},
48 { .name="governor", .has_arg=required_argument, .flag=NULL, .val='g'},
49 { .name="freq", .has_arg=required_argument, .flag=NULL, .val='f'},
50 { .name="help", .has_arg=no_argument, .flag=NULL, .val='h'},
51 { .name="related", .has_arg=no_argument, .flag=NULL, .val='r'},
52 { },
53};
54
55static void print_error(void)
56{
57 printf(_("Error setting new values. Common errors:\n"
58 "- Do you have proper administration rights? (super-user?)\n"
59 "- Is the governor you requested available and modprobed?\n"
60 "- Trying to set an invalid policy?\n"
61 "- Trying to set a specific frequency, but userspace governor is not available,\n"
62 " for example because of hardware which cannot be set to a specific frequency\n"
63 " or because the userspace governor isn't loaded?\n"));
64};
65
66struct freq_units {
67 char* str_unit;
68 int power_of_ten;
69};
70
71const struct freq_units def_units[] = {
72 {"hz", -3},
73 {"khz", 0}, /* default */
74 {"mhz", 3},
75 {"ghz", 6},
76 {"thz", 9},
77 {NULL, 0}
78};
79
80static void print_unknown_arg(void)
81{
82 printf(_("invalid or unknown argument\n"));
83 freq_set_help();
84}
85
86static unsigned long string_to_frequency(const char *str)
87{
88 char normalized[NORM_FREQ_LEN];
89 const struct freq_units *unit;
90 const char *scan;
91 char *end;
92 unsigned long freq;
93 int power = 0, match_count = 0, i, cp, pad;
94
95 while (*str == '0')
96 str++;
97
98 for (scan = str; isdigit(*scan) || *scan == '.'; scan++) {
99 if (*scan == '.' && match_count == 0)
100 match_count = 1;
101 else if (*scan == '.' && match_count == 1)
102 return 0;
103 }
104
105 if (*scan) {
106 match_count = 0;
107 for (unit = def_units; unit->str_unit; unit++) {
108 for (i = 0;
109 scan[i] && tolower(scan[i]) == unit->str_unit[i];
110 ++i)
111 continue;
112 if (scan[i])
113 continue;
114 match_count++;
115 power = unit->power_of_ten;
116 }
117 if (match_count != 1)
118 return 0;
119 }
120
121 /* count the number of digits to be copied */
122 for (cp = 0; isdigit(str[cp]); cp++)
123 continue;
124
125 if (str[cp] == '.') {
126 while (power > -1 && isdigit(str[cp+1]))
127 cp++, power--;
128 }
129 if (power >= -1) /* not enough => pad */
130 pad = power + 1;
131 else /* to much => strip */
132 pad = 0, cp += power + 1;
133 /* check bounds */
134 if (cp <= 0 || cp + pad > NORM_FREQ_LEN - 1)
135 return 0;
136
137 /* copy digits */
138 for (i = 0; i < cp; i++, str++) {
139 if (*str == '.')
140 str++;
141 normalized[i] = *str;
142 }
143 /* and pad */
144 for (; i < cp + pad; i++)
145 normalized[i] = '0';
146
147 /* round up, down ? */
148 match_count = (normalized[i-1] >= '5');
149 /* and drop the decimal part */
150 normalized[i-1] = 0; /* cp > 0 && pad >= 0 ==> i > 0 */
151
152 /* final conversion (and applying rounding) */
153 errno = 0;
154 freq = strtoul(normalized, &end, 10);
155 if (errno)
156 return 0;
157 else {
158 if (match_count && freq != ULONG_MAX)
159 freq++;
160 return freq;
161 }
162}
163
164static int do_new_policy(unsigned int cpu, struct cpufreq_policy *new_pol)
165{
166 struct cpufreq_policy *cur_pol = cpufreq_get_policy(cpu);
167 int ret;
168
169 if (!cur_pol) {
170 printf(_("wrong, unknown or unhandled CPU?\n"));
171 return -EINVAL;
172 }
173
174 if (!new_pol->min)
175 new_pol->min = cur_pol->min;
176
177 if (!new_pol->max)
178 new_pol->max = cur_pol->max;
179
180 if (!new_pol->governor)
181 new_pol->governor = cur_pol->governor;
182
183 ret = cpufreq_set_policy(cpu, new_pol);
184
185 cpufreq_put_policy(cur_pol);
186
187 return ret;
188}
189
190
191static int do_one_cpu(unsigned int cpu, struct cpufreq_policy *new_pol,
192 unsigned long freq, unsigned int pc)
193{
194 switch (pc) {
195 case 0:
196 return cpufreq_set_frequency(cpu, freq);
197
198 case 1:
199 /* if only one value of a policy is to be changed, we can
200 * use a "fast path".
201 */
202 if (new_pol->min)
203 return cpufreq_modify_policy_min(cpu, new_pol->min);
204 else if (new_pol->max)
205 return cpufreq_modify_policy_max(cpu, new_pol->max);
206 else if (new_pol->governor)
207 return cpufreq_modify_policy_governor(cpu, new_pol->governor);
208
209 default:
210 /* slow path */
211 return do_new_policy(cpu, new_pol);
212 }
213}
214
215int cmd_freq_set(int argc, char **argv)
216{
217 extern char *optarg;
218 extern int optind, opterr, optopt;
219 int ret = 0, cont = 1;
220 int double_parm = 0, related = 0, policychange = 0;
221 unsigned long freq = 0;
222 char gov[20];
223 unsigned int cpu;
224
225 struct cpufreq_policy new_pol = {
226 .min = 0,
227 .max = 0,
228 .governor = NULL,
229 };
230
231 /* parameter parsing */
232 do {
233 ret = getopt_long(argc, argv, "d:u:g:f:hr", set_opts, NULL);
234 switch (ret) {
235 case '?':
236 print_unknown_arg();
237 return -EINVAL;
238 case 'h':
239 freq_set_help();
240 return 0;
241 case -1:
242 cont = 0;
243 break;
244 case 'r':
245 if (related)
246 double_parm++;
247 related++;
248 break;
249 case 'd':
250 if (new_pol.min)
251 double_parm++;
252 policychange++;
253 new_pol.min = string_to_frequency(optarg);
254 if (new_pol.min == 0) {
255 print_unknown_arg();
256 return -EINVAL;
257 }
258 break;
259 case 'u':
260 if (new_pol.max)
261 double_parm++;
262 policychange++;
263 new_pol.max = string_to_frequency(optarg);
264 if (new_pol.max == 0) {
265 print_unknown_arg();
266 return -EINVAL;
267 }
268 break;
269 case 'f':
270 if (freq)
271 double_parm++;
272 freq = string_to_frequency(optarg);
273 if (freq == 0) {
274 print_unknown_arg();
275 return -EINVAL;
276 }
277 break;
278 case 'g':
279 if (new_pol.governor)
280 double_parm++;
281 policychange++;
282 if ((strlen(optarg) < 3) || (strlen(optarg) > 18)) {
283 print_unknown_arg();
284 return -EINVAL;
285 }
286 if ((sscanf(optarg, "%s", gov)) != 1) {
287 print_unknown_arg();
288 return -EINVAL;
289 }
290 new_pol.governor = gov;
291 break;
292 }
293 } while(cont);
294
295 /* parameter checking */
296 if (double_parm) {
297 printf("the same parameter was passed more than once\n");
298 return -EINVAL;
299 }
300
301 if (freq && policychange) {
302 printf(_("the -f/--freq parameter cannot be combined with -d/--min, -u/--max or\n"
303 "-g/--governor parameters\n"));
304 return -EINVAL;
305 }
306
307 if (!freq && !policychange) {
308 printf(_("At least one parameter out of -f/--freq, -d/--min, -u/--max, and\n"
309 "-g/--governor must be passed\n"));
310 return -EINVAL;
311 }
312
313 /* Default is: set all CPUs */
314 if (bitmask_isallclear(cpus_chosen))
315 bitmask_setall(cpus_chosen);
316
317 /* Also set frequency settings for related CPUs if -r is passed */
318 if (related) {
319 for (cpu = bitmask_first(cpus_chosen);
320 cpu <= bitmask_last(cpus_chosen); cpu++) {
321 struct cpufreq_affected_cpus *cpus;
322
323 if (!bitmask_isbitset(cpus_chosen, cpu) ||
324 cpufreq_cpu_exists(cpu))
325 continue;
326
327 cpus = cpufreq_get_related_cpus(cpu);
328 if (!cpus)
329 break;
330 while (cpus->next) {
331 bitmask_setbit(cpus_chosen, cpus->cpu);
332 cpus = cpus->next;
333 }
334 cpufreq_put_related_cpus(cpus);
335 }
336 }
337
338
339 /* loop over CPUs */
340 for (cpu = bitmask_first(cpus_chosen);
341 cpu <= bitmask_last(cpus_chosen); cpu++) {
342
343 if (!bitmask_isbitset(cpus_chosen, cpu) ||
344 cpufreq_cpu_exists(cpu))
345 continue;
346
347 printf(_("Setting cpu: %d\n"), cpu);
348 ret = do_one_cpu(cpu, &new_pol, freq, policychange);
349 if (ret)
350 break;
351 }
352
353 if (ret)
354 print_error();
355
356 return ret;
357}
diff --git a/tools/power/cpupower/utils/cpuidle-info.c b/tools/power/cpupower/utils/cpuidle-info.c
new file mode 100644
index 00000000000..635468224e7
--- /dev/null
+++ b/tools/power/cpupower/utils/cpuidle-info.c
@@ -0,0 +1,245 @@
1/*
2 * (C) 2004-2009 Dominik Brodowski <linux@dominikbrodowski.de>
3 * (C) 2010 Thomas Renninger <trenn@suse.de>
4 *
5 * Licensed under the terms of the GNU GPL License version 2.
6 */
7
8
9#include <unistd.h>
10#include <stdio.h>
11#include <errno.h>
12#include <stdlib.h>
13#include <string.h>
14#include <getopt.h>
15#include <cpufreq.h>
16
17#include "helpers/helpers.h"
18#include "helpers/sysfs.h"
19#include "helpers/bitmask.h"
20
21#define LINE_LEN 10
22
23static void cpuidle_cpu_output(unsigned int cpu, int verbose)
24{
25 int idlestates, idlestate;
26 char *tmp;
27
28 printf(_ ("Analyzing CPU %d:\n"), cpu);
29
30 idlestates = sysfs_get_idlestate_count(cpu);
31 if (idlestates == 0) {
32 printf(_("CPU %u: No idle states\n"), cpu);
33 return;
34 }
35 else if (idlestates <= 0) {
36 printf(_("CPU %u: Can't read idle state info\n"), cpu);
37 return;
38 }
39 tmp = sysfs_get_idlestate_name(cpu, idlestates - 1);
40 if (!tmp) {
41 printf(_("Could not determine max idle state %u\n"),
42 idlestates - 1);
43 return;
44 }
45
46 printf(_("Number of idle states: %d\n"), idlestates);
47
48 printf(_("Available idle states:"));
49 for (idlestate = 1; idlestate < idlestates; idlestate++) {
50 tmp = sysfs_get_idlestate_name(cpu, idlestate);
51 if (!tmp)
52 continue;
53 printf(" %s", tmp);
54 free(tmp);
55 }
56 printf("\n");
57
58 if (!verbose)
59 return;
60
61 for (idlestate = 1; idlestate < idlestates; idlestate++) {
62 tmp = sysfs_get_idlestate_name(cpu, idlestate);
63 if (!tmp)
64 continue;
65 printf("%s:\n", tmp);
66 free(tmp);
67
68 tmp = sysfs_get_idlestate_desc(cpu, idlestate);
69 if (!tmp)
70 continue;
71 printf(_("Flags/Description: %s\n"), tmp);
72 free(tmp);
73
74 printf(_("Latency: %lu\n"),
75 sysfs_get_idlestate_latency(cpu, idlestate));
76 printf(_("Usage: %lu\n"),
77 sysfs_get_idlestate_usage(cpu, idlestate));
78 printf(_("Duration: %llu\n"),
79 sysfs_get_idlestate_time(cpu, idlestate));
80 }
81 printf("\n");
82}
83
84static void cpuidle_general_output(void)
85{
86 char *tmp;
87
88 tmp = sysfs_get_cpuidle_driver();
89 if (!tmp) {
90 printf(_("Could not determine cpuidle driver\n"));
91 return;
92 }
93
94 printf(_("CPUidle driver: %s\n"), tmp);
95 free (tmp);
96
97 tmp = sysfs_get_cpuidle_governor();
98 if (!tmp) {
99 printf(_("Could not determine cpuidle governor\n"));
100 return;
101 }
102
103 printf(_("CPUidle governor: %s\n"), tmp);
104 free (tmp);
105}
106
107static void proc_cpuidle_cpu_output(unsigned int cpu)
108{
109 long max_allowed_cstate = 2000000000;
110 int cstates, cstate;
111
112 cstates = sysfs_get_idlestate_count(cpu);
113 if (cstates == 0) {
114 /*
115 * Go on and print same useless info as you'd see with
116 * cat /proc/acpi/processor/../power
117 * printf(_("CPU %u: No C-states available\n"), cpu);
118 * return;
119 */
120 }
121 else if (cstates <= 0) {
122 printf(_("CPU %u: Can't read C-state info\n"), cpu);
123 return;
124 }
125 /* printf("Cstates: %d\n", cstates); */
126
127 printf(_("active state: C0\n"));
128 printf(_("max_cstate: C%u\n"), cstates-1);
129 printf(_("maximum allowed latency: %lu usec\n"), max_allowed_cstate);
130 printf(_("states:\t\n"));
131 for (cstate = 1; cstate < cstates; cstate++) {
132 printf(_(" C%d: "
133 "type[C%d] "), cstate, cstate);
134 printf(_("promotion[--] demotion[--] "));
135 printf(_("latency[%03lu] "),
136 sysfs_get_idlestate_latency(cpu, cstate));
137 printf(_("usage[%08lu] "),
138 sysfs_get_idlestate_usage(cpu, cstate));
139 printf(_("duration[%020Lu] \n"),
140 sysfs_get_idlestate_time(cpu, cstate));
141 }
142}
143
144/* --freq / -f */
145
146void idle_info_help(void) {
147 printf(_ ("Usage: cpupower idleinfo [options]\n"));
148 printf(_ ("Options:\n"));
149 printf(_ (" -s, --silent Only show general C-state information\n"));
150 printf(_ (" -o, --proc Prints out information like provided by the /proc/acpi/processor/*/power\n"
151 " interface in older kernels\n"));
152 printf(_ (" -h, --help Prints out this screen\n"));
153
154 printf("\n");
155}
156
157static struct option info_opts[] = {
158 { .name="silent", .has_arg=no_argument, .flag=NULL, .val='s'},
159 { .name="proc", .has_arg=no_argument, .flag=NULL, .val='o'},
160 { .name="help", .has_arg=no_argument, .flag=NULL, .val='h'},
161 { },
162};
163
164static inline void cpuidle_exit(int fail)
165{
166 idle_info_help();
167 exit(EXIT_FAILURE);
168}
169
170int cmd_idle_info(int argc, char **argv)
171{
172 extern char *optarg;
173 extern int optind, opterr, optopt;
174 int ret = 0, cont = 1, output_param = 0, verbose = 1;
175 unsigned int cpu = 0;
176
177 do {
178 ret = getopt_long(argc, argv, "hos", info_opts, NULL);
179 if (ret == -1)
180 break;
181 switch (ret) {
182 case '?':
183 output_param = '?';
184 cont = 0;
185 break;
186 case 'h':
187 output_param = 'h';
188 cont = 0;
189 break;
190 case 's':
191 verbose = 0;
192 break;
193 case -1:
194 cont = 0;
195 break;
196 case 'o':
197 if (output_param) {
198 output_param = -1;
199 cont = 0;
200 break;
201 }
202 output_param = ret;
203 break;
204 }
205 } while(cont);
206
207 switch (output_param) {
208 case -1:
209 printf(_("You can't specify more than one "
210 "output-specific argument\n"));
211 cpuidle_exit(EXIT_FAILURE);
212 case '?':
213 printf(_("invalid or unknown argument\n"));
214 cpuidle_exit(EXIT_FAILURE);
215 case 'h':
216 cpuidle_exit(EXIT_SUCCESS);
217 }
218
219 /* Default is: show output of CPU 0 only */
220 if (bitmask_isallclear(cpus_chosen))
221 bitmask_setbit(cpus_chosen, 0);
222
223 if (output_param == 0)
224 cpuidle_general_output();
225
226 for (cpu = bitmask_first(cpus_chosen);
227 cpu <= bitmask_last(cpus_chosen); cpu++) {
228
229 if (!bitmask_isbitset(cpus_chosen, cpu) ||
230 cpufreq_cpu_exists(cpu))
231 continue;
232
233 switch (output_param) {
234
235 case 'o':
236 proc_cpuidle_cpu_output(cpu);
237 break;
238 case 0:
239 printf("\n");
240 cpuidle_cpu_output(cpu, verbose);
241 break;
242 }
243 }
244 return (EXIT_SUCCESS);
245}
diff --git a/tools/power/cpupower/utils/cpupower-info.c b/tools/power/cpupower/utils/cpupower-info.c
new file mode 100644
index 00000000000..7add04ccbad
--- /dev/null
+++ b/tools/power/cpupower/utils/cpupower-info.c
@@ -0,0 +1,154 @@
1/*
2 * (C) 2011 Thomas Renninger <trenn@suse.de>, Novell Inc.
3 *
4 * Licensed under the terms of the GNU GPL License version 2.
5 */
6
7
8#include <unistd.h>
9#include <stdio.h>
10#include <stdlib.h>
11#include <errno.h>
12#include <string.h>
13#include <getopt.h>
14
15#include <cpufreq.h>
16#include "helpers/helpers.h"
17#include "helpers/sysfs.h"
18
19void info_help(void)
20{
21 printf(_("Usage: cpupower info [ -b ] [ -m ] [ -s ]\n"));
22 printf(_("Options:\n"));
23 printf(_(" -b, --perf-bias Gets CPU's power vs performance policy on some\n"
24 " Intel models [0-15], see manpage for details\n"));
25 printf(_(" -m, --sched-mc Gets the kernel's multi core scheduler policy.\n"));
26 printf(_(" -s, --sched-smt Gets the kernel's thread sibling scheduler policy.\n"));
27 printf(_(" -h, --help Prints out this screen\n"));
28 printf(_("\nPassing no option will show all info, by default only on core 0\n"));
29 printf("\n");
30}
31
32static struct option set_opts[] = {
33 { .name="perf-bias", .has_arg=optional_argument, .flag=NULL, .val='b'},
34 { .name="sched-mc", .has_arg=optional_argument, .flag=NULL, .val='m'},
35 { .name="sched-smt", .has_arg=optional_argument, .flag=NULL, .val='s'},
36 { .name="help", .has_arg=no_argument, .flag=NULL, .val='h'},
37 { },
38};
39
40static void print_wrong_arg_exit(void)
41{
42 printf(_("invalid or unknown argument\n"));
43 info_help();
44 exit(EXIT_FAILURE);
45}
46
47int cmd_info(int argc, char **argv)
48{
49 extern char *optarg;
50 extern int optind, opterr, optopt;
51 unsigned int cpu;
52
53 union {
54 struct {
55 int sched_mc:1;
56 int sched_smt:1;
57 int perf_bias:1;
58 };
59 int params;
60
61 } params = {};
62 int ret = 0;
63
64 setlocale(LC_ALL, "");
65 textdomain (PACKAGE);
66
67 /* parameter parsing */
68 while ((ret = getopt_long(argc, argv, "msbh", set_opts, NULL)) != -1) {
69 switch (ret) {
70 case 'h':
71 info_help();
72 return 0;
73 case 'b':
74 if (params.perf_bias)
75 print_wrong_arg_exit();
76 params.perf_bias = 1;
77 break;
78 case 'm':
79 if (params.sched_mc)
80 print_wrong_arg_exit();
81 params.sched_mc = 1;
82 break;
83 case 's':
84 if (params.sched_smt)
85 print_wrong_arg_exit();
86 params.sched_smt = 1;
87 break;
88 default:
89 print_wrong_arg_exit();
90 }
91 };
92
93 if (!params.params)
94 params.params = 0x7;
95
96 /* Default is: show output of CPU 0 only */
97 if (bitmask_isallclear(cpus_chosen))
98 bitmask_setbit(cpus_chosen, 0);
99
100 if (params.sched_mc) {
101 ret = sysfs_get_sched("mc");
102 printf(_("System's multi core scheduler setting: "));
103 if (ret < 0)
104 /* if sysfs file is missing it's: errno == ENOENT */
105 printf(_("not supported\n"));
106 else
107 printf("%d\n", ret);
108 }
109 if (params.sched_smt) {
110 ret = sysfs_get_sched("smt");
111 printf(_("System's thread sibling scheduler setting: "));
112 if (ret < 0)
113 /* if sysfs file is missing it's: errno == ENOENT */
114 printf(_("not supported\n"));
115 else
116 printf("%d\n", ret);
117 }
118
119 /* Add more per cpu options here */
120 if (!params.perf_bias)
121 return ret;
122
123 if (params.perf_bias) {
124 if (!run_as_root) {
125 params.perf_bias = 0;
126 printf (_("Intel's performance bias setting needs root privileges\n"));
127 } else if (!(cpupower_cpu_info.caps & CPUPOWER_CAP_PERF_BIAS)) {
128 printf(_("System does not support Intel's performance"
129 " bias setting\n"));
130 params.perf_bias = 0;
131 }
132 }
133
134 /* loop over CPUs */
135 for (cpu = bitmask_first(cpus_chosen);
136 cpu <= bitmask_last(cpus_chosen); cpu++) {
137
138 if (!bitmask_isbitset(cpus_chosen, cpu) ||
139 cpufreq_cpu_exists(cpu))
140 continue;
141
142 printf(_("analyzing CPU %d:\n"), cpu);
143
144 if (params.perf_bias) {
145 ret = msr_intel_get_perf_bias(cpu);
146 if (ret < 0) {
147 printf(_("Could not read perf-bias value\n"));
148 break;
149 } else
150 printf(_("perf-bias: %d\n"), ret);
151 }
152 }
153 return ret;
154}
diff --git a/tools/power/cpupower/utils/cpupower-set.c b/tools/power/cpupower/utils/cpupower-set.c
new file mode 100644
index 00000000000..3f807bc7a56
--- /dev/null
+++ b/tools/power/cpupower/utils/cpupower-set.c
@@ -0,0 +1,153 @@
1/*
2 * (C) 2011 Thomas Renninger <trenn@suse.de>, Novell Inc.
3 *
4 * Licensed under the terms of the GNU GPL License version 2.
5 */
6
7
8#include <unistd.h>
9#include <stdio.h>
10#include <stdlib.h>
11#include <errno.h>
12#include <string.h>
13#include <getopt.h>
14
15#include <cpufreq.h>
16#include "helpers/helpers.h"
17#include "helpers/sysfs.h"
18#include "helpers/bitmask.h"
19
20void set_help(void)
21{
22 printf(_("Usage: cpupower set [ -b val ] [ -m val ] [ -s val ]\n"));
23 printf(_("Options:\n"));
24 printf(_(" -b, --perf-bias [VAL] Sets CPU's power vs performance policy on some\n"
25 " Intel models [0-15], see manpage for details\n"));
26 printf(_(" -m, --sched-mc [VAL] Sets the kernel's multi core scheduler policy.\n"));
27 printf(_(" -s, --sched-smt [VAL] Sets the kernel's thread sibling scheduler policy.\n"));
28 printf(_(" -h, --help Prints out this screen\n"));
29 printf("\n");
30}
31
32static struct option set_opts[] = {
33 { .name="perf-bias", .has_arg=optional_argument, .flag=NULL, .val='b'},
34 { .name="sched-mc", .has_arg=optional_argument, .flag=NULL, .val='m'},
35 { .name="sched-smt", .has_arg=optional_argument, .flag=NULL, .val='s'},
36 { .name="help", .has_arg=no_argument, .flag=NULL, .val='h'},
37 { },
38};
39
40static void print_wrong_arg_exit(void)
41{
42 printf(_("invalid or unknown argument\n"));
43 set_help();
44 exit(EXIT_FAILURE);
45}
46
47int cmd_set(int argc, char **argv)
48{
49 extern char *optarg;
50 extern int optind, opterr, optopt;
51 unsigned int cpu;
52
53 union {
54 struct {
55 int sched_mc:1;
56 int sched_smt:1;
57 int perf_bias:1;
58 };
59 int params;
60
61 } params;
62 int sched_mc = 0, sched_smt = 0, perf_bias = 0;
63 int ret = 0;
64
65 setlocale(LC_ALL, "");
66 textdomain (PACKAGE);
67
68 params.params = 0;
69 /* parameter parsing */
70 while ((ret = getopt_long(argc, argv, "m:s:b:h", set_opts, NULL)) != -1) {
71 switch (ret) {
72 case 'h':
73 set_help();
74 return 0;
75 case 'b':
76 if (params.perf_bias)
77 print_wrong_arg_exit();
78 perf_bias = atoi(optarg);
79 if (perf_bias < 0 || perf_bias > 15) {
80 printf(_("--perf-bias param out "
81 "of range [0-%d]\n"), 15);
82 print_wrong_arg_exit();
83 }
84 params.perf_bias = 1;
85 break;
86 case 'm':
87 if (params.sched_mc)
88 print_wrong_arg_exit();
89 sched_mc = atoi(optarg);
90 if (sched_mc < 0 || sched_mc > 2) {
91 printf(_("--sched-mc param out "
92 "of range [0-%d]\n"), 2);
93 print_wrong_arg_exit();
94 }
95 params.sched_mc = 1;
96 break;
97 case 's':
98 if (params.sched_smt)
99 print_wrong_arg_exit();
100 sched_smt = atoi(optarg);
101 if (sched_smt < 0 || sched_smt > 2) {
102 printf(_("--sched-smt param out "
103 "of range [0-%d]\n"), 2);
104 print_wrong_arg_exit();
105 }
106 params.sched_smt = 1;
107 break;
108 default:
109 print_wrong_arg_exit();
110 }
111 };
112
113 if (!params.params) {
114 set_help();
115 return -EINVAL;
116 }
117
118 if (params.sched_mc) {
119 ret = sysfs_set_sched("mc", sched_mc);
120 if (ret)
121 fprintf(stderr, _("Error setting sched-mc %s\n"),
122 (ret == -ENODEV) ? "not supported" : "");
123 }
124 if (params.sched_smt) {
125 ret = sysfs_set_sched("smt", sched_smt);
126 if (ret)
127 fprintf(stderr, _("Error setting sched-smt %s\n"),
128 (ret == -ENODEV) ? "not supported" : "");
129 }
130
131 /* Default is: set all CPUs */
132 if (bitmask_isallclear(cpus_chosen))
133 bitmask_setall(cpus_chosen);
134
135 /* loop over CPUs */
136 for (cpu = bitmask_first(cpus_chosen);
137 cpu <= bitmask_last(cpus_chosen); cpu++) {
138
139 if (!bitmask_isbitset(cpus_chosen, cpu) ||
140 cpufreq_cpu_exists(cpu))
141 continue;
142
143 if (params.perf_bias) {
144 ret = msr_intel_set_perf_bias(cpu, perf_bias);
145 if (ret) {
146 fprintf(stderr, _("Error setting perf-bias "
147 "value on CPU %d\n"), cpu);
148 break;
149 }
150 }
151 }
152 return ret;
153}
diff --git a/tools/power/cpupower/utils/cpupower.c b/tools/power/cpupower/utils/cpupower.c
new file mode 100644
index 00000000000..b048e559535
--- /dev/null
+++ b/tools/power/cpupower/utils/cpupower.c
@@ -0,0 +1,201 @@
1/*
2 * (C) 2010,2011 Thomas Renninger <trenn@suse.de>, Novell Inc.
3 *
4 * Licensed under the terms of the GNU GPL License version 2.
5 *
6 * Ideas taken over from the perf userspace tool (included in the Linus
7 * kernel git repo): subcommand builtins and param parsing.
8 */
9
10#include <stdio.h>
11#include <stdlib.h>
12#include <string.h>
13#include <unistd.h>
14
15#include "builtin.h"
16#include "helpers/helpers.h"
17#include "helpers/bitmask.h"
18
19struct cmd_struct {
20 const char *cmd;
21 int (*main)(int, const char **);
22 void (*usage)(void);
23 int needs_root;
24};
25
26#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
27
28int cmd_help(int argc, const char **argv);
29
30/* Global cpu_info object available for all binaries
31 * Info only retrieved from CPU 0
32 *
33 * Values will be zero/unknown on non X86 archs
34 */
35struct cpupower_cpu_info cpupower_cpu_info;
36int run_as_root;
37/* Affected cpus chosen by -c/--cpu param */
38struct bitmask *cpus_chosen;
39
40#ifdef DEBUG
41int be_verbose;
42#endif
43
44static void print_help(void);
45
46static struct cmd_struct commands[] = {
47 { "frequency-info", cmd_freq_info, freq_info_help, 0 },
48 { "frequency-set", cmd_freq_set, freq_set_help, 1 },
49 { "idle-info", cmd_idle_info, idle_info_help, 0 },
50 { "set", cmd_set, set_help, 1 },
51 { "info", cmd_info, info_help, 0 },
52 { "monitor", cmd_monitor, monitor_help, 0 },
53 { "help", cmd_help, print_help, 0 },
54 // { "bench", cmd_bench, NULL, 1 },
55};
56
57int cmd_help(int argc, const char **argv)
58{
59 unsigned int i;
60
61 if (argc > 1) {
62 for (i = 0; i < ARRAY_SIZE(commands); i++) {
63 struct cmd_struct *p = commands + i;
64 if (strcmp(p->cmd, argv[1]))
65 continue;
66 if (p->usage) {
67 p->usage();
68 return EXIT_SUCCESS;
69 }
70 }
71 }
72 print_help();
73 if (argc == 1)
74 return EXIT_SUCCESS; /* cpupower help */
75 return EXIT_FAILURE;
76}
77
78static void print_help(void)
79{
80 unsigned int i;
81
82#ifdef DEBUG
83 printf(_("cpupower [ -d ][ -c cpulist ] subcommand [ARGS]\n"));
84 printf(_(" -d, --debug May increase output (stderr) on some subcommands\n"));
85#else
86 printf(_("cpupower [ -c cpulist ] subcommand [ARGS]\n"));
87#endif
88 printf(_("cpupower --version\n"));
89 printf(_("Supported subcommands are:\n"));
90 for (i = 0; i < ARRAY_SIZE(commands); i++)
91 printf("\t%s\n", commands[i].cmd);
92 printf(_("\nSome subcommands can make use of the -c cpulist option.\n"));
93 printf(_("Look at the general cpupower manpage how to use it\n"));
94 printf(_("and read up the subcommand's manpage whether it is supported.\n"));
95 printf(_("\nUse cpupower help subcommand for getting help for above subcommands.\n"));
96}
97
98static void print_version(void) {
99 printf(PACKAGE " " VERSION "\n");
100 printf(_("Report errors and bugs to %s, please.\n"), PACKAGE_BUGREPORT);
101}
102
103static void handle_options(int *argc, const char ***argv)
104{
105 int ret, x, new_argc = 0;
106
107 if (*argc < 1)
108 return;
109
110 for (x = 0; x < *argc && ((*argv)[x])[0] == '-'; x++) {
111 const char *param = (*argv)[x];
112 if (!strcmp(param, "-h") || !strcmp(param, "--help")){
113 print_help();
114 exit(EXIT_SUCCESS);
115 } else if (!strcmp(param, "-c") || !strcmp(param, "--cpu")){
116 if (*argc < 2) {
117 print_help();
118 exit(EXIT_FAILURE);
119 }
120 if (!strcmp((*argv)[x+1], "all"))
121 bitmask_setall(cpus_chosen);
122 else {
123 ret = bitmask_parselist(
124 (*argv)[x+1], cpus_chosen);
125 if (ret < 0) {
126 fprintf(stderr, _("Error parsing cpu "
127 "list\n"));
128 exit(EXIT_FAILURE);
129 }
130 }
131 x += 1;
132 /* Cut out param: cpupower -c 1 info -> cpupower info */
133 new_argc += 2;
134 continue;
135 } else if (!strcmp(param, "-v") || !strcmp(param, "--version")){
136 print_version();
137 exit(EXIT_SUCCESS);
138#ifdef DEBUG
139 } else if (!strcmp(param, "-d") || !strcmp(param, "--debug")){
140 be_verbose = 1;
141 new_argc ++;
142 continue;
143#endif
144 } else {
145 fprintf(stderr, "Unknown option: %s\n", param);
146 print_help();
147 exit(EXIT_FAILURE);
148 }
149 }
150 *argc -= new_argc;
151 *argv += new_argc;
152}
153
154int main(int argc, const char *argv[])
155{
156 const char *cmd;
157 unsigned int i, ret;
158
159 cpus_chosen = bitmask_alloc(sysconf(_SC_NPROCESSORS_CONF));
160
161 argc--;
162 argv += 1;
163
164 handle_options(&argc, &argv);
165
166 cmd = argv[0];
167
168 if (argc < 1) {
169 print_help();
170 return EXIT_FAILURE;
171 }
172
173 setlocale(LC_ALL, "");
174 textdomain (PACKAGE);
175
176 /* Turn "perf cmd --help" into "perf help cmd" */
177 if (argc > 1 && !strcmp(argv[1], "--help")) {
178 argv[1] = argv[0];
179 argv[0] = cmd = "help";
180 }
181
182 get_cpu_info(0, &cpupower_cpu_info);
183 run_as_root = !getuid();
184
185 for (i = 0; i < ARRAY_SIZE(commands); i++) {
186 struct cmd_struct *p = commands + i;
187 if (strcmp(p->cmd, cmd))
188 continue;
189 if (!run_as_root && p->needs_root) {
190 fprintf(stderr, _("Subcommand %s needs root "
191 "privileges\n"), cmd);
192 return EXIT_FAILURE;
193 }
194 ret = p->main(argc, argv);
195 if (cpus_chosen)
196 bitmask_free(cpus_chosen);
197 return ret;
198 }
199 print_help();
200 return EXIT_FAILURE;
201}
diff --git a/tools/power/cpupower/utils/helpers/amd.c b/tools/power/cpupower/utils/helpers/amd.c
new file mode 100644
index 00000000000..5e44e31fc7f
--- /dev/null
+++ b/tools/power/cpupower/utils/helpers/amd.c
@@ -0,0 +1,137 @@
1#if defined(__i386__) || defined(__x86_64__)
2#include <unistd.h>
3#include <errno.h>
4#include <stdio.h>
5#include <stdint.h>
6
7#include <pci/pci.h>
8
9#include "helpers/helpers.h"
10
11#define MSR_AMD_PSTATE_STATUS 0xc0010063
12#define MSR_AMD_PSTATE 0xc0010064
13#define MSR_AMD_PSTATE_LIMIT 0xc0010061
14
15union msr_pstate {
16 struct {
17 unsigned fid:6;
18 unsigned did:3;
19 unsigned vid:7;
20 unsigned res1:6;
21 unsigned nbdid:1;
22 unsigned res2:2;
23 unsigned nbvid:7;
24 unsigned iddval:8;
25 unsigned idddiv:2;
26 unsigned res3:21;
27 unsigned en:1;
28 } bits;
29 unsigned long long val;
30};
31
32static int get_did(int family, union msr_pstate pstate)
33{
34 int t;
35
36 if (family == 0x12)
37 t = pstate.val & 0xf;
38 else
39 t = pstate.bits.did;
40
41 return t;
42}
43
44static int get_cof(int family, union msr_pstate pstate)
45{
46 int t;
47 int fid, did;
48
49 did = get_did(family, pstate);
50
51 t = 0x10;
52 fid = pstate.bits.fid;
53 if (family == 0x11)
54 t = 0x8;
55
56 return ((100 * (fid + t)) >> did);
57 }
58
59/* Needs:
60 * cpu -> the cpu that gets evaluated
61 * cpu_family -> The cpu's family (0x10, 0x12,...)
62 * boots_states -> how much boost states the machines support
63 *
64 * Fills up:
65 * pstates -> a pointer to an array of size MAX_HW_PSTATES
66 * must be initialized with zeros.
67 * All available HW pstates (including boost states)
68 * no -> amount of pstates above array got filled up with
69 *
70 * returns zero on success, -1 on failure
71 */
72int decode_pstates(unsigned int cpu, unsigned int cpu_family,
73 int boost_states, unsigned long *pstates, int *no)
74{
75 int i, psmax, pscur;
76 union msr_pstate pstate;
77 unsigned long long val;
78
79 /* Only read out frequencies from HW when CPU might be boostable
80 to keep the code as short and clean as possible.
81 Otherwise frequencies are exported via ACPI tables.
82 */
83 if (cpu_family < 0x10 || cpu_family == 0x14)
84 return -1;
85
86 if (read_msr(cpu, MSR_AMD_PSTATE_LIMIT, &val))
87 return -1;
88
89 psmax = (val >> 4) & 0x7;
90
91 if (read_msr(cpu, MSR_AMD_PSTATE_STATUS, &val))
92 return -1;
93
94 pscur = val & 0x7;
95
96 pscur += boost_states;
97 psmax += boost_states;
98 for (i=0; i<=psmax; i++) {
99 if (i >= MAX_HW_PSTATES) {
100 fprintf(stderr, "HW pstates [%d] exceeding max [%d]\n",
101 psmax, MAX_HW_PSTATES);
102 return -1;
103 }
104 if (read_msr(cpu, MSR_AMD_PSTATE + i, &pstate.val))
105 return -1;
106 pstates[i] = get_cof(cpu_family, pstate);
107 }
108 *no = i;
109 return 0;
110}
111
112int amd_pci_get_num_boost_states(int *active, int *states)
113{
114 struct pci_access *pci_acc;
115 int vendor_id = 0x1022;
116 int boost_dev_ids[4] = {0x1204, 0x1604, 0x1704, 0};
117 struct pci_dev *device;
118 uint8_t val = 0;
119
120 *active = *states = 0;
121
122 device = pci_acc_init(&pci_acc, vendor_id, boost_dev_ids);
123
124 if (device == NULL)
125 return -ENODEV;
126
127 val = pci_read_byte(device, 0x15c);
128 if (val & 3)
129 *active = 1;
130 else
131 *active = 0;
132 *states = (val >> 2) & 7;
133
134 pci_cleanup(pci_acc);
135 return 0;
136}
137#endif /* defined(__i386__) || defined(__x86_64__) */
diff --git a/tools/power/cpupower/utils/helpers/bitmask.c b/tools/power/cpupower/utils/helpers/bitmask.c
new file mode 100644
index 00000000000..60f4d69bb20
--- /dev/null
+++ b/tools/power/cpupower/utils/helpers/bitmask.c
@@ -0,0 +1,290 @@
1#include <stdio.h>
2#include <stdlib.h>
3#include <string.h>
4
5#include <helpers/bitmask.h>
6
7/* How many bits in an unsigned long */
8#define bitsperlong (8 * sizeof(unsigned long))
9
10/* howmany(a,b) : how many elements of size b needed to hold all of a */
11#define howmany(x,y) (((x)+((y)-1))/(y))
12
13/* How many longs in mask of n bits */
14#define longsperbits(n) howmany(n, bitsperlong)
15
16#define max(a,b) ((a) > (b) ? (a) : (b))
17
18/*
19 * Allocate and free `struct bitmask *`
20 */
21
22/* Allocate a new `struct bitmask` with a size of n bits */
23struct bitmask *bitmask_alloc(unsigned int n)
24{
25 struct bitmask *bmp;
26
27 bmp = malloc(sizeof(*bmp));
28 if (bmp == 0)
29 return 0;
30 bmp->size = n;
31 bmp->maskp = calloc(longsperbits(n), sizeof(unsigned long));
32 if (bmp->maskp == 0) {
33 free(bmp);
34 return 0;
35 }
36 return bmp;
37}
38
39/* Free `struct bitmask` */
40void bitmask_free(struct bitmask *bmp)
41{
42 if (bmp == 0)
43 return;
44 free(bmp->maskp);
45 bmp->maskp = (unsigned long *)0xdeadcdef; /* double free tripwire */
46 free(bmp);
47}
48
49/*
50 * The routines _getbit() and _setbit() are the only
51 * routines that actually understand the layout of bmp->maskp[].
52 *
53 * On little endian architectures, this could simply be an array of
54 * bytes. But the kernel layout of bitmasks _is_ visible to userspace
55 * via the sched_(set/get)affinity calls in Linux 2.6, and on big
56 * endian architectures, it is painfully obvious that this is an
57 * array of unsigned longs.
58 */
59
60/* Return the value (0 or 1) of bit n in bitmask bmp */
61static unsigned int _getbit(const struct bitmask *bmp, unsigned int n)
62{
63 if (n < bmp->size)
64 return (bmp->maskp[n/bitsperlong] >> (n % bitsperlong)) & 1;
65 else
66 return 0;
67}
68
69/* Set bit n in bitmask bmp to value v (0 or 1) */
70static void _setbit(struct bitmask *bmp, unsigned int n, unsigned int v)
71{
72 if (n < bmp->size) {
73 if (v)
74 bmp->maskp[n/bitsperlong] |= 1UL << (n % bitsperlong);
75 else
76 bmp->maskp[n/bitsperlong] &= ~(1UL << (n % bitsperlong));
77 }
78}
79
80/*
81 * When parsing bitmask lists, only allow numbers, separated by one
82 * of the allowed next characters.
83 *
84 * The parameter 'sret' is the return from a sscanf "%u%c". It is
85 * -1 if the sscanf input string was empty. It is 0 if the first
86 * character in the sscanf input string was not a decimal number.
87 * It is 1 if the unsigned number matching the "%u" was the end of the
88 * input string. It is 2 if one or more additional characters followed
89 * the matched unsigned number. If it is 2, then 'nextc' is the first
90 * character following the number. The parameter 'ok_next_chars'
91 * is the nul-terminated list of allowed next characters.
92 *
93 * The mask term just scanned was ok if and only if either the numbers
94 * matching the %u were all of the input or if the next character in
95 * the input past the numbers was one of the allowed next characters.
96 */
97static int scan_was_ok(int sret, char nextc, const char *ok_next_chars)
98{
99 return sret == 1 ||
100 (sret == 2 && strchr(ok_next_chars, nextc) != NULL);
101}
102
103static const char *nexttoken(const char *q, int sep)
104{
105 if (q)
106 q = strchr(q, sep);
107 if (q)
108 q++;
109 return q;
110}
111
112/* Set a single bit i in bitmask */
113struct bitmask *bitmask_setbit(struct bitmask *bmp, unsigned int i)
114{
115 _setbit(bmp, i, 1);
116 return bmp;
117}
118
119/* Set all bits in bitmask: bmp = ~0 */
120struct bitmask *bitmask_setall(struct bitmask *bmp)
121{
122 unsigned int i;
123 for (i = 0; i < bmp->size; i++)
124 _setbit(bmp, i, 1);
125 return bmp;
126}
127
128/* Clear all bits in bitmask: bmp = 0 */
129struct bitmask *bitmask_clearall(struct bitmask *bmp)
130{
131 unsigned int i;
132 for (i = 0; i < bmp->size; i++)
133 _setbit(bmp, i, 0);
134 return bmp;
135}
136
137/* True if all bits are clear */
138int bitmask_isallclear(const struct bitmask *bmp)
139{
140 unsigned int i;
141 for (i = 0; i < bmp->size; i++)
142 if (_getbit(bmp, i))
143 return 0;
144 return 1;
145}
146
147/* True if specified bit i is set */
148int bitmask_isbitset(const struct bitmask *bmp, unsigned int i)
149{
150 return _getbit(bmp, i);
151}
152
153/* Number of lowest set bit (min) */
154unsigned int bitmask_first(const struct bitmask *bmp)
155{
156 return bitmask_next(bmp, 0);
157}
158
159/* Number of highest set bit (max) */
160unsigned int bitmask_last(const struct bitmask *bmp)
161{
162 unsigned int i;
163 unsigned int m = bmp->size;
164 for (i = 0; i < bmp->size; i++)
165 if (_getbit(bmp, i))
166 m = i;
167 return m;
168}
169
170/* Number of next set bit at or above given bit i */
171unsigned int bitmask_next(const struct bitmask *bmp, unsigned int i)
172{
173 unsigned int n;
174 for (n = i; n < bmp->size; n++)
175 if (_getbit(bmp, n))
176 break;
177 return n;
178}
179
180/*
181 * Parses a comma-separated list of numbers and ranges of numbers,
182 * with optional ':%u' strides modifying ranges, into provided bitmask.
183 * Some examples of input lists and their equivalent simple list:
184 * Input Equivalent to
185 * 0-3 0,1,2,3
186 * 0-7:2 0,2,4,6
187 * 1,3,5-7 1,3,5,6,7
188 * 0-3:2,8-15:4 0,2,8,12
189 */
190int bitmask_parselist(const char *buf, struct bitmask *bmp)
191{
192 const char *p, *q;
193
194 bitmask_clearall(bmp);
195
196 q = buf;
197 while (p = q, q = nexttoken(q, ','), p) {
198 unsigned int a; /* begin of range */
199 unsigned int b; /* end of range */
200 unsigned int s; /* stride */
201 const char *c1, *c2; /* next tokens after '-' or ',' */
202 char nextc; /* char after sscanf %u match */
203 int sret; /* sscanf return (number of matches) */
204
205 sret = sscanf(p, "%u%c", &a, &nextc);
206 if (!scan_was_ok(sret, nextc, ",-"))
207 goto err;
208 b = a;
209 s = 1;
210 c1 = nexttoken(p, '-');
211 c2 = nexttoken(p, ',');
212 if (c1 != NULL && (c2 == NULL || c1 < c2)) {
213 sret = sscanf(c1, "%u%c", &b, &nextc);
214 if (!scan_was_ok(sret, nextc, ",:"))
215 goto err;
216 c1 = nexttoken(c1, ':');
217 if (c1 != NULL && (c2 == NULL || c1 < c2)) {
218 sret = sscanf(c1, "%u%c", &s, &nextc);
219 if (!scan_was_ok(sret, nextc, ","))
220 goto err;
221 }
222 }
223 if (!(a <= b))
224 goto err;
225 if (b >= bmp->size)
226 goto err;
227 while (a <= b) {
228 _setbit(bmp, a, 1);
229 a += s;
230 }
231 }
232 return 0;
233err:
234 bitmask_clearall(bmp);
235 return -1;
236}
237
238/*
239 * emit(buf, buflen, rbot, rtop, len)
240 *
241 * Helper routine for bitmask_displaylist(). Write decimal number
242 * or range to buf+len, suppressing output past buf+buflen, with optional
243 * comma-prefix. Return len of what would be written to buf, if it
244 * all fit.
245 */
246
247static inline int emit(char *buf, int buflen, int rbot, int rtop, int len)
248{
249 if (len > 0)
250 len += snprintf(buf + len, max(buflen - len, 0), ",");
251 if (rbot == rtop)
252 len += snprintf(buf + len, max(buflen - len, 0), "%d", rbot);
253 else
254 len += snprintf(buf + len, max(buflen - len, 0), "%d-%d", rbot, rtop);
255 return len;
256}
257
258/*
259 * Write decimal list representation of bmp to buf.
260 *
261 * Output format is a comma-separated list of decimal numbers and
262 * ranges. Consecutively set bits are shown as two hyphen-separated
263 * decimal numbers, the smallest and largest bit numbers set in
264 * the range. Output format is compatible with the format
265 * accepted as input by bitmap_parselist().
266 *
267 * The return value is the number of characters which would be
268 * generated for the given input, excluding the trailing '\0', as
269 * per ISO C99.
270 */
271
272int bitmask_displaylist(char *buf, int buflen, const struct bitmask *bmp)
273{
274 int len = 0;
275 /* current bit is 'cur', most recently seen range is [rbot, rtop] */
276 unsigned int cur, rbot, rtop;
277
278 if (buflen > 0)
279 *buf = 0;
280 rbot = cur = bitmask_first(bmp);
281 while (cur < bmp->size) {
282 rtop = cur;
283 cur = bitmask_next(bmp, cur+1);
284 if (cur >= bmp->size || cur > rtop + 1) {
285 len = emit(buf, buflen, rbot, rtop, len);
286 rbot = cur;
287 }
288 }
289 return len;
290}
diff --git a/tools/power/cpupower/utils/helpers/bitmask.h b/tools/power/cpupower/utils/helpers/bitmask.h
new file mode 100644
index 00000000000..eb289df4105
--- /dev/null
+++ b/tools/power/cpupower/utils/helpers/bitmask.h
@@ -0,0 +1,33 @@
1#ifndef __CPUPOWER_BITMASK__
2#define __CPUPOWER_BITMASK__
3
4/* Taken over from libbitmask, a project initiated from sgi:
5 * Url: http://oss.sgi.com/projects/cpusets/
6 * Unfortunately it's not very widespread, therefore relevant parts are
7 * pasted here.
8 */
9
10struct bitmask {
11 unsigned int size;
12 unsigned long *maskp;
13};
14
15struct bitmask *bitmask_alloc(unsigned int n);
16void bitmask_free(struct bitmask *bmp);
17
18struct bitmask *bitmask_setbit(struct bitmask *bmp, unsigned int i);
19struct bitmask *bitmask_setall(struct bitmask *bmp);
20struct bitmask *bitmask_clearall(struct bitmask *bmp);
21
22unsigned int bitmask_first(const struct bitmask *bmp);
23unsigned int bitmask_next(const struct bitmask *bmp, unsigned int i);
24unsigned int bitmask_last(const struct bitmask *bmp);
25int bitmask_isallclear(const struct bitmask *bmp);
26int bitmask_isbitset(const struct bitmask *bmp, unsigned int i);
27
28int bitmask_parselist(const char *buf, struct bitmask *bmp);
29int bitmask_displaylist(char *buf, int len, const struct bitmask *bmp);
30
31
32
33#endif /*__CPUPOWER_BITMASK__ */
diff --git a/tools/power/cpupower/utils/helpers/cpuid.c b/tools/power/cpupower/utils/helpers/cpuid.c
new file mode 100644
index 00000000000..71021f3bb69
--- /dev/null
+++ b/tools/power/cpupower/utils/helpers/cpuid.c
@@ -0,0 +1,145 @@
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 }
87 else if (!strncmp(value, "model\t\t: ", 9)) {
88 sscanf(value, "model\t\t: %u",
89 &cpu_info->model);
90 }
91 else if (!strncmp(value, "stepping\t: ", 10)) {
92 sscanf(value, "stepping\t: %u",
93 &cpu_info->stepping);
94
95 /* Exit -> all values must have been set */
96 if (cpu_info->vendor == X86_VENDOR_UNKNOWN ||
97 cpu_info->family == unknown ||
98 cpu_info->model == unknown ||
99 cpu_info->stepping == unknown) {
100 ret = -EINVAL;
101 goto out;
102 }
103
104 ret = 0;
105 goto out;
106 }
107 }
108 ret = -ENODEV;
109out:
110 fclose(fp);
111 /* Get some useful CPU capabilities from cpuid */
112 if (cpu_info->vendor != X86_VENDOR_AMD &&
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 Boost state enable/disable register */
129 if (cpu_info->vendor == X86_VENDOR_AMD) {
130 if (ext_cpuid_level >= 0x80000007 &&
131 (cpuid_edx(0x80000007) & (1 << 9)))
132 cpu_info->caps |= CPUPOWER_CAP_AMD_CBP;
133 }
134
135 /* Intel's perf-bias MSR support */
136 if (cpu_info->vendor == X86_VENDOR_INTEL) {
137 if (cpuid_level >= 6 && (cpuid_ecx(6) & (1 << 3)))
138 cpu_info->caps |= CPUPOWER_CAP_PERF_BIAS;
139 }
140
141 /* printf("ID: %u - Extid: 0x%x - Caps: 0x%llx\n",
142 cpuid_level, ext_cpuid_level, cpu_info->caps);
143 */
144 return ret;
145}
diff --git a/tools/power/cpupower/utils/helpers/helpers.h b/tools/power/cpupower/utils/helpers/helpers.h
new file mode 100644
index 00000000000..a487dadb4cf
--- /dev/null
+++ b/tools/power/cpupower/utils/helpers/helpers.h
@@ -0,0 +1,180 @@
1/*
2 * (C) 2010,2011 Thomas Renninger <trenn@suse.de>, Novell Inc.
3 *
4 * Licensed under the terms of the GNU GPL License version 2.
5 *
6 * Miscellaneous helpers which do not fit or are worth
7 * to put into separate headers
8 */
9
10#ifndef __CPUPOWERUTILS_HELPERS__
11#define __CPUPOWERUTILS_HELPERS__
12
13#include <libintl.h>
14#include <locale.h>
15
16#include "helpers/bitmask.h"
17
18/* Internationalization ****************************/
19#define _(String) gettext(String)
20#ifndef gettext_noop
21#define gettext_noop(String) String
22#endif
23#define N_(String) gettext_noop (String)
24/* Internationalization ****************************/
25
26extern int run_as_root;
27extern struct bitmask *cpus_chosen;
28
29/* Global verbose (-d) stuff *********************************/
30/*
31 * define DEBUG via global Makefile variable
32 * Debug output is sent to stderr, do:
33 * cpupower monitor 2>/tmp/debug
34 * to split debug output away from normal output
35*/
36#ifdef DEBUG
37extern int be_verbose;
38
39#define dprint(fmt, ...) { \
40 if (be_verbose) { \
41 fprintf(stderr, "%s: " fmt, \
42 __FUNCTION__, ##__VA_ARGS__); \
43 } \
44 }
45#else
46static inline void dprint(const char *fmt, ...) { }
47#endif
48extern int be_verbose;
49/* Global verbose (-v) stuff *********************************/
50
51/* cpuid and cpuinfo helpers **************************/
52enum cpupower_cpu_vendor {X86_VENDOR_UNKNOWN = 0, X86_VENDOR_INTEL,
53 X86_VENDOR_AMD, X86_VENDOR_MAX};
54
55#define CPUPOWER_CAP_INV_TSC 0x00000001
56#define CPUPOWER_CAP_APERF 0x00000002
57#define CPUPOWER_CAP_AMD_CBP 0x00000004
58#define CPUPOWER_CAP_PERF_BIAS 0x00000008
59
60#define MAX_HW_PSTATES 10
61
62struct cpupower_cpu_info {
63 enum cpupower_cpu_vendor vendor;
64 unsigned int family;
65 unsigned int model;
66 unsigned int stepping;
67 /* CPU capabilities read out from cpuid */
68 unsigned long long caps;
69};
70
71/* get_cpu_info
72 *
73 * Extract CPU vendor, family, model, stepping info from /proc/cpuinfo
74 *
75 * Returns 0 on success or a negativ error code
76 * Only used on x86, below global's struct values are zero/unknown on
77 * other archs
78 */
79extern int get_cpu_info(unsigned int cpu, struct cpupower_cpu_info *cpu_info);
80extern struct cpupower_cpu_info cpupower_cpu_info;
81/* cpuid and cpuinfo helpers **************************/
82
83
84/* CPU topology/hierarchy parsing ******************/
85struct cpupower_topology {
86 /* Amount of CPU cores, packages and threads per core in the system */
87 unsigned int cores;
88 unsigned int pkgs;
89 unsigned int threads; /* per core */
90
91 /* Array gets mallocated with cores entries, holding per core info */
92 struct {
93 int pkg;
94 int core;
95 int cpu;
96 } *core_info;
97};
98
99extern int get_cpu_topology(struct cpupower_topology *cpu_top);
100extern void cpu_topology_release(struct cpupower_topology cpu_top);
101/* CPU topology/hierarchy parsing ******************/
102
103/* X86 ONLY ****************************************/
104#if defined(__i386__) || defined(__x86_64__)
105
106#include <pci/pci.h>
107
108/* Read/Write msr ****************************/
109extern int read_msr(int cpu, unsigned int idx, unsigned long long *val);
110extern int write_msr(int cpu, unsigned int idx, unsigned long long val);
111
112extern int msr_intel_set_perf_bias(unsigned int cpu, unsigned int val);
113extern int msr_intel_get_perf_bias(unsigned int cpu);
114
115extern int msr_intel_has_boost_support(unsigned int cpu);
116extern int msr_intel_boost_is_active(unsigned int cpu);
117
118/* Read/Write msr ****************************/
119
120/* PCI stuff ****************************/
121extern int amd_pci_get_num_boost_states(int *active, int *states);
122extern struct pci_dev *pci_acc_init(struct pci_access **pacc, int vendor_id,
123 int *dev_ids);
124
125/* PCI stuff ****************************/
126
127/* AMD HW pstate decoding **************************/
128
129extern int decode_pstates(unsigned int cpu, unsigned int cpu_family,
130 int boost_states, unsigned long *pstates, int *no);
131
132/* AMD HW pstate decoding **************************/
133
134extern int cpufreq_has_boost_support(unsigned int cpu, int *support,
135 int *active, int * states);
136/*
137 * CPUID functions returning a single datum
138 */
139unsigned int cpuid_eax(unsigned int op);
140unsigned int cpuid_ebx(unsigned int op);
141unsigned int cpuid_ecx(unsigned int op);
142unsigned int cpuid_edx(unsigned int op);
143
144/* cpuid and cpuinfo helpers **************************/
145/* X86 ONLY ********************************************/
146#else
147static inline int decode_pstates(unsigned int cpu, unsigned int cpu_family,
148 int boost_states, unsigned long *pstates,
149 int *no)
150{ return -1; };
151
152static inline int read_msr(int cpu, unsigned int idx, unsigned long long *val)
153{ return -1; };
154static inline int write_msr(int cpu, unsigned int idx, unsigned long long val)
155{ return -1; };
156static inline int msr_intel_set_perf_bias(unsigned int cpu, unsigned int val)
157{ return -1; };
158static inline int msr_intel_get_perf_bias(unsigned int cpu)
159{ return -1; };
160
161static inline int msr_intel_has_boost_support(unsigned int cpu)
162{ return -1; };
163static inline int msr_intel_boost_is_active(unsigned int cpu)
164{ return -1; };
165
166/* Read/Write msr ****************************/
167
168static inline int cpufreq_has_boost_support(unsigned int cpu, int *support,
169 int *active, int * states)
170{ return -1; }
171
172/* cpuid and cpuinfo helpers **************************/
173
174static inline unsigned int cpuid_eax(unsigned int op) { return 0; };
175static inline unsigned int cpuid_ebx(unsigned int op) { return 0; };
176static inline unsigned int cpuid_ecx(unsigned int op) { return 0; };
177static inline unsigned int cpuid_edx(unsigned int op) { return 0; };
178#endif /* defined(__i386__) || defined(__x86_64__) */
179
180#endif /* __CPUPOWERUTILS_HELPERS__ */
diff --git a/tools/power/cpupower/utils/helpers/misc.c b/tools/power/cpupower/utils/helpers/misc.c
new file mode 100644
index 00000000000..c1566e93e0e
--- /dev/null
+++ b/tools/power/cpupower/utils/helpers/misc.c
@@ -0,0 +1,34 @@
1#if defined(__i386__) || defined(__x86_64__)
2
3#include "helpers/helpers.h"
4
5int cpufreq_has_boost_support(unsigned int cpu, int *support, int *active, int * states)
6{
7 struct cpupower_cpu_info cpu_info;
8 int ret;
9
10 *support = *active = *states = 0;
11
12 ret = get_cpu_info(0, &cpu_info);
13 if (ret)
14 return ret;
15
16 if (cpupower_cpu_info.caps & CPUPOWER_CAP_AMD_CBP) {
17 *support = 1;
18 amd_pci_get_num_boost_states(active, states);
19 if (ret <= 0)
20 return ret;
21 *support = 1;
22 } else if (cpupower_cpu_info.vendor == X86_VENDOR_INTEL) {
23 ret = msr_intel_has_boost_support(cpu);
24 if (ret <= 0)
25 return ret;
26 *support = ret;
27 ret = msr_intel_boost_is_active(cpu);
28 if (ret <= 0)
29 return ret;
30 *active = ret;
31 }
32 return 0;
33}
34#endif /* #if defined(__i386__) || defined(__x86_64__) */
diff --git a/tools/power/cpupower/utils/helpers/msr.c b/tools/power/cpupower/utils/helpers/msr.c
new file mode 100644
index 00000000000..93d48bd56e5
--- /dev/null
+++ b/tools/power/cpupower/utils/helpers/msr.c
@@ -0,0 +1,122 @@
1#if defined(__i386__) || defined(__x86_64__)
2
3#include <fcntl.h>
4#include <stdio.h>
5#include <unistd.h>
6#include <stdint.h>
7
8#include "helpers/helpers.h"
9
10/* Intel specific MSRs */
11#define MSR_IA32_PERF_STATUS 0x198
12#define MSR_IA32_MISC_ENABLES 0x1a0
13#define MSR_IA32_ENERGY_PERF_BIAS 0x1b0
14
15/*
16 * read_msr
17 *
18 * Will return 0 on success and -1 on failure.
19 * Possible errno values could be:
20 * EFAULT -If the read/write did not fully complete
21 * EIO -If the CPU does not support MSRs
22 * ENXIO -If the CPU does not exist
23 */
24
25int read_msr(int cpu, unsigned int idx, unsigned long long *val)
26{
27 int fd;
28 char msr_file_name[64];
29
30 sprintf(msr_file_name, "/dev/cpu/%d/msr", cpu);
31 fd = open(msr_file_name, O_RDONLY);
32 if (fd < 0)
33 return -1;
34 if (lseek(fd, idx, SEEK_CUR) == -1)
35 goto err;
36 if (read(fd, val, sizeof *val) != sizeof *val)
37 goto err;
38 close(fd);
39 return 0;
40 err:
41 close(fd);
42 return -1;
43}
44
45/*
46 * write_msr
47 *
48 * Will return 0 on success and -1 on failure.
49 * Possible errno values could be:
50 * EFAULT -If the read/write did not fully complete
51 * EIO -If the CPU does not support MSRs
52 * ENXIO -If the CPU does not exist
53 */
54int write_msr(int cpu, unsigned int idx, unsigned long long val)
55{
56 int fd;
57 char msr_file_name[64];
58
59 sprintf(msr_file_name, "/dev/cpu/%d/msr", cpu);
60 fd = open(msr_file_name, O_WRONLY);
61 if (fd < 0)
62 return -1;
63 if (lseek(fd, idx, SEEK_CUR) == -1)
64 goto err;
65 if (write(fd, &val, sizeof val) != sizeof val)
66 goto err;
67 close(fd);
68 return 0;
69 err:
70 close(fd);
71 return -1;
72}
73
74int msr_intel_has_boost_support(unsigned int cpu)
75{
76 unsigned long long misc_enables;
77 int ret;
78
79 ret = read_msr(cpu, MSR_IA32_MISC_ENABLES, &misc_enables);
80 if (ret)
81 return ret;
82 return (misc_enables >> 38) & 0x1;
83}
84
85int msr_intel_boost_is_active(unsigned int cpu)
86{
87 unsigned long long perf_status;
88 int ret;
89
90 ret = read_msr(cpu, MSR_IA32_PERF_STATUS, &perf_status);
91 if (ret)
92 return ret;
93 return (perf_status >> 32) & 0x1;
94}
95
96int msr_intel_get_perf_bias(unsigned int cpu)
97{
98 unsigned long long val;
99 int ret;
100
101 if (!(cpupower_cpu_info.caps & CPUPOWER_CAP_PERF_BIAS))
102 return -1;
103
104 ret = read_msr(cpu, MSR_IA32_ENERGY_PERF_BIAS, &val);
105 if (ret)
106 return ret;
107 return val;
108}
109
110int msr_intel_set_perf_bias(unsigned int cpu, unsigned int val)
111{
112 int ret;
113
114 if (!(cpupower_cpu_info.caps & CPUPOWER_CAP_PERF_BIAS))
115 return -1;
116
117 ret = write_msr(cpu, MSR_IA32_ENERGY_PERF_BIAS, val);
118 if (ret)
119 return ret;
120 return 0;
121}
122#endif
diff --git a/tools/power/cpupower/utils/helpers/pci.c b/tools/power/cpupower/utils/helpers/pci.c
new file mode 100644
index 00000000000..8dcc9381371
--- /dev/null
+++ b/tools/power/cpupower/utils/helpers/pci.c
@@ -0,0 +1,44 @@
1#if defined(__i386__) || defined(__x86_64__)
2
3#include <helpers/helpers.h>
4
5/*
6 * pci_acc_init
7 *
8 * PCI access helper function depending on libpci
9 *
10 * **pacc : if a valid pci_dev is returned
11 * *pacc must be passed to pci_acc_cleanup to free it
12 *
13 * vendor_id : the pci vendor id matching the pci device to access
14 * dev_ids : device ids matching the pci device to access
15 *
16 * Returns :
17 * struct pci_dev which can be used with pci_{read,write}_* functions
18 * to access the PCI config space of matching pci devices
19 */
20struct pci_dev *pci_acc_init(struct pci_access **pacc, int vendor_id,
21 int *dev_ids)
22{
23 struct pci_filter filter_nb_link = { -1, -1, -1, -1, vendor_id, 0};
24 struct pci_dev *device;
25 unsigned int i;
26
27 *pacc = pci_alloc();
28 if (*pacc == NULL)
29 return NULL;
30
31 pci_init(*pacc);
32 pci_scan_bus(*pacc);
33
34 for (i = 0; dev_ids[i] != 0; i++) {
35 filter_nb_link.device = dev_ids[i];
36 for (device=(*pacc)->devices; device; device = device->next) {
37 if (pci_filter_match(&filter_nb_link, device))
38 return device;
39 }
40 }
41 pci_cleanup(*pacc);
42 return NULL;
43}
44#endif /* defined(__i386__) || defined(__x86_64__) */
diff --git a/tools/power/cpupower/utils/helpers/sysfs.c b/tools/power/cpupower/utils/helpers/sysfs.c
new file mode 100644
index 00000000000..0c534e79652
--- /dev/null
+++ b/tools/power/cpupower/utils/helpers/sysfs.c
@@ -0,0 +1,350 @@
1/*
2 * (C) 2004-2009 Dominik Brodowski <linux@dominikbrodowski.de>
3 * (C) 2011 Thomas Renninger <trenn@novell.com> Novell Inc.
4 *
5 * Licensed under the terms of the GNU GPL License version 2.
6 */
7
8#include <stdio.h>
9#include <errno.h>
10#include <stdlib.h>
11#include <string.h>
12#include <sys/types.h>
13#include <sys/stat.h>
14#include <fcntl.h>
15#include <unistd.h>
16
17#include "helpers/sysfs.h"
18
19unsigned int sysfs_read_file(const char *path, char *buf, size_t buflen)
20{
21 int fd;
22 size_t numread;
23
24 if ( ( fd = open(path, O_RDONLY) ) == -1 )
25 return 0;
26
27 numread = read(fd, buf, buflen - 1);
28 if ( numread < 1 )
29 {
30 close(fd);
31 return 0;
32 }
33
34 buf[numread] = '\0';
35 close(fd);
36
37 return numread;
38}
39
40static unsigned int sysfs_write_file(const char *path,
41 const char *value, size_t len)
42{
43 int fd;
44 size_t numwrite;
45
46 if ( ( fd = open(path, O_WRONLY) ) == -1 )
47 return 0;
48
49 numwrite = write(fd, value, len);
50 if ( numwrite < 1 )
51 {
52 close(fd);
53 return 0;
54 }
55 close(fd);
56 return numwrite;
57}
58
59/* CPUidle idlestate specific /sys/devices/system/cpu/cpuX/cpuidle/ access */
60
61/*
62 * helper function to read file from /sys into given buffer
63 * fname is a relative path under "cpuX/cpuidle/stateX/" dir
64 * cstates starting with 0, C0 is not counted as cstate.
65 * This means if you want C1 info, pass 0 as idlestate param
66 */
67unsigned int sysfs_idlestate_read_file(unsigned int cpu, unsigned int idlestate,
68 const char *fname, char *buf, size_t buflen)
69{
70 char path[SYSFS_PATH_MAX];
71 int fd;
72 size_t numread;
73
74 snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/cpuidle/state%u/%s",
75 cpu, idlestate, fname);
76
77 if ( ( fd = open(path, O_RDONLY) ) == -1 )
78 return 0;
79
80 numread = read(fd, buf, buflen - 1);
81 if ( numread < 1 )
82 {
83 close(fd);
84 return 0;
85 }
86
87 buf[numread] = '\0';
88 close(fd);
89
90 return numread;
91}
92
93/* read access to files which contain one numeric value */
94
95enum idlestate_value {
96 IDLESTATE_USAGE,
97 IDLESTATE_POWER,
98 IDLESTATE_LATENCY,
99 IDLESTATE_TIME,
100 MAX_IDLESTATE_VALUE_FILES
101};
102
103static const char *idlestate_value_files[MAX_IDLESTATE_VALUE_FILES] = {
104 [IDLESTATE_USAGE] = "usage",
105 [IDLESTATE_POWER] = "power",
106 [IDLESTATE_LATENCY] = "latency",
107 [IDLESTATE_TIME] = "time",
108};
109
110static unsigned long long sysfs_idlestate_get_one_value(unsigned int cpu,
111 unsigned int idlestate,
112 enum idlestate_value which)
113{
114 unsigned long long value;
115 unsigned int len;
116 char linebuf[MAX_LINE_LEN];
117 char *endp;
118
119 if ( which >= MAX_IDLESTATE_VALUE_FILES )
120 return 0;
121
122 if ( ( len = sysfs_idlestate_read_file(cpu, idlestate,
123 idlestate_value_files[which],
124 linebuf, sizeof(linebuf))) == 0 )
125 {
126 return 0;
127 }
128
129 value = strtoull(linebuf, &endp, 0);
130
131 if ( endp == linebuf || errno == ERANGE )
132 return 0;
133
134 return value;
135}
136
137/* read access to files which contain one string */
138
139enum idlestate_string {
140 IDLESTATE_DESC,
141 IDLESTATE_NAME,
142 MAX_IDLESTATE_STRING_FILES
143};
144
145static const char *idlestate_string_files[MAX_IDLESTATE_STRING_FILES] = {
146 [IDLESTATE_DESC] = "desc",
147 [IDLESTATE_NAME] = "name",
148};
149
150
151static char * sysfs_idlestate_get_one_string(unsigned int cpu,
152 unsigned int idlestate,
153 enum idlestate_string which)
154{
155 char linebuf[MAX_LINE_LEN];
156 char *result;
157 unsigned int len;
158
159 if (which >= MAX_IDLESTATE_STRING_FILES)
160 return NULL;
161
162 if ( ( len = sysfs_idlestate_read_file(cpu, idlestate,
163 idlestate_string_files[which],
164 linebuf, sizeof(linebuf))) == 0 )
165 return NULL;
166
167 if ( ( result = strdup(linebuf) ) == NULL )
168 return NULL;
169
170 if (result[strlen(result) - 1] == '\n')
171 result[strlen(result) - 1] = '\0';
172
173 return result;
174}
175
176unsigned long sysfs_get_idlestate_latency(unsigned int cpu, unsigned int idlestate)
177{
178 return sysfs_idlestate_get_one_value(cpu, idlestate, IDLESTATE_LATENCY);
179}
180
181unsigned long sysfs_get_idlestate_usage(unsigned int cpu, unsigned int idlestate)
182{
183 return sysfs_idlestate_get_one_value(cpu, idlestate, IDLESTATE_USAGE);
184}
185
186unsigned long long sysfs_get_idlestate_time(unsigned int cpu, unsigned int idlestate)
187{
188 return sysfs_idlestate_get_one_value(cpu, idlestate, IDLESTATE_TIME);
189}
190
191char * sysfs_get_idlestate_name(unsigned int cpu, unsigned int idlestate)
192{
193 return sysfs_idlestate_get_one_string(cpu, idlestate, IDLESTATE_NAME);
194}
195
196char * sysfs_get_idlestate_desc(unsigned int cpu, unsigned int idlestate)
197{
198 return sysfs_idlestate_get_one_string(cpu, idlestate, IDLESTATE_DESC);
199}
200
201/*
202 * Returns number of supported C-states of CPU core cpu
203 * Negativ in error case
204 * Zero if cpuidle does not export any C-states
205 */
206int sysfs_get_idlestate_count(unsigned int cpu)
207{
208 char file[SYSFS_PATH_MAX];
209 struct stat statbuf;
210 int idlestates = 1;
211
212
213 snprintf(file, SYSFS_PATH_MAX, PATH_TO_CPU "cpuidle");
214 if ( stat(file, &statbuf) != 0 || !S_ISDIR(statbuf.st_mode))
215 return -ENODEV;
216
217 snprintf(file, SYSFS_PATH_MAX, PATH_TO_CPU "cpu%u/cpuidle/state0", cpu);
218 if ( stat(file, &statbuf) != 0 || !S_ISDIR(statbuf.st_mode))
219 return 0;
220
221 while(stat(file, &statbuf) == 0 && S_ISDIR(statbuf.st_mode)) {
222 snprintf(file, SYSFS_PATH_MAX, PATH_TO_CPU
223 "cpu%u/cpuidle/state%d", cpu, idlestates);
224 idlestates++;
225 }
226 idlestates--;
227 return idlestates;
228}
229
230/* CPUidle general /sys/devices/system/cpu/cpuidle/ sysfs access ********/
231
232/*
233 * helper function to read file from /sys into given buffer
234 * fname is a relative path under "cpu/cpuidle/" dir
235 */
236static unsigned int sysfs_cpuidle_read_file(const char *fname, char *buf,
237 size_t buflen)
238{
239 char path[SYSFS_PATH_MAX];
240
241 snprintf(path, sizeof(path), PATH_TO_CPU "cpuidle/%s", fname);
242
243 return sysfs_read_file(path, buf, buflen);
244}
245
246
247
248/* read access to files which contain one string */
249
250enum cpuidle_string {
251 CPUIDLE_GOVERNOR,
252 CPUIDLE_GOVERNOR_RO,
253 CPUIDLE_DRIVER,
254 MAX_CPUIDLE_STRING_FILES
255};
256
257static const char *cpuidle_string_files[MAX_CPUIDLE_STRING_FILES] = {
258 [CPUIDLE_GOVERNOR] = "current_governor",
259 [CPUIDLE_GOVERNOR_RO] = "current_governor_ro",
260 [CPUIDLE_DRIVER] = "current_driver",
261};
262
263
264static char * sysfs_cpuidle_get_one_string(enum cpuidle_string which)
265{
266 char linebuf[MAX_LINE_LEN];
267 char *result;
268 unsigned int len;
269
270 if (which >= MAX_CPUIDLE_STRING_FILES)
271 return NULL;
272
273 if ( ( len = sysfs_cpuidle_read_file(cpuidle_string_files[which],
274 linebuf, sizeof(linebuf))) == 0 )
275 return NULL;
276
277 if ( ( result = strdup(linebuf) ) == NULL )
278 return NULL;
279
280 if (result[strlen(result) - 1] == '\n')
281 result[strlen(result) - 1] = '\0';
282
283 return result;
284}
285
286char * sysfs_get_cpuidle_governor(void)
287{
288 char *tmp = sysfs_cpuidle_get_one_string(CPUIDLE_GOVERNOR_RO);
289 if (!tmp)
290 return sysfs_cpuidle_get_one_string(CPUIDLE_GOVERNOR);
291 else
292 return tmp;
293}
294
295char * sysfs_get_cpuidle_driver(void)
296{
297 return sysfs_cpuidle_get_one_string(CPUIDLE_DRIVER);
298}
299/* CPUidle idlestate specific /sys/devices/system/cpu/cpuX/cpuidle/ access */
300
301/*
302 * Get sched_mc or sched_smt settings
303 * Pass "mc" or "smt" as argument
304 *
305 * Returns negative value on failure
306 */
307int sysfs_get_sched(const char* smt_mc)
308{
309 unsigned long value;
310 char linebuf[MAX_LINE_LEN];
311 char *endp;
312 char path[SYSFS_PATH_MAX];
313
314 if (strcmp("mc", smt_mc) && strcmp("smt", smt_mc))
315 return -EINVAL;
316
317 snprintf(path, sizeof(path), PATH_TO_CPU "sched_%s_power_savings", smt_mc);
318 if (sysfs_read_file(path, linebuf, MAX_LINE_LEN) == 0 )
319 return -1;
320 value = strtoul(linebuf, &endp, 0);
321 if ( endp == linebuf || errno == ERANGE )
322 return -1;
323 return value;
324}
325
326/*
327 * Get sched_mc or sched_smt settings
328 * Pass "mc" or "smt" as argument
329 *
330 * Returns negative value on failure
331 */
332int sysfs_set_sched(const char* smt_mc, int val)
333{
334 char linebuf[MAX_LINE_LEN];
335 char path[SYSFS_PATH_MAX];
336 struct stat statbuf;
337
338 if (strcmp("mc", smt_mc) && strcmp("smt", smt_mc))
339 return -EINVAL;
340
341 snprintf(path, sizeof(path), PATH_TO_CPU "sched_%s_power_savings", smt_mc);
342 sprintf(linebuf, "%d", val);
343
344 if ( stat(path, &statbuf) != 0 )
345 return -ENODEV;
346
347 if (sysfs_write_file(path, linebuf, MAX_LINE_LEN) == 0 )
348 return -1;
349 return 0;
350}
diff --git a/tools/power/cpupower/utils/helpers/sysfs.h b/tools/power/cpupower/utils/helpers/sysfs.h
new file mode 100644
index 00000000000..5d02d2fc70e
--- /dev/null
+++ b/tools/power/cpupower/utils/helpers/sysfs.h
@@ -0,0 +1,23 @@
1#ifndef __CPUPOWER_HELPERS_SYSFS_H__
2#define __CPUPOWER_HELPERS_SYSFS_H__
3
4#define PATH_TO_CPU "/sys/devices/system/cpu/"
5#define MAX_LINE_LEN 255
6#define SYSFS_PATH_MAX 255
7
8extern unsigned int sysfs_read_file(const char *path, char *buf, size_t buflen);
9
10extern unsigned long sysfs_get_idlestate_latency(unsigned int cpu, unsigned int idlestate);
11extern unsigned long sysfs_get_idlestate_usage(unsigned int cpu, unsigned int idlestate);
12extern unsigned long long sysfs_get_idlestate_time(unsigned int cpu, unsigned int idlestate);
13extern char * sysfs_get_idlestate_name(unsigned int cpu, unsigned int idlestate);
14extern char * sysfs_get_idlestate_desc(unsigned int cpu, unsigned int idlestate);
15extern int sysfs_get_idlestate_count(unsigned int cpu);
16
17extern char * sysfs_get_cpuidle_governor(void);
18extern char * sysfs_get_cpuidle_driver(void);
19
20extern int sysfs_get_sched(const char* smt_mc);
21extern int sysfs_set_sched(const char* smt_mc, int val);
22
23#endif /* __CPUPOWER_HELPERS_SYSFS_H__ */
diff --git a/tools/power/cpupower/utils/helpers/topology.c b/tools/power/cpupower/utils/helpers/topology.c
new file mode 100644
index 00000000000..5ad842b956b
--- /dev/null
+++ b/tools/power/cpupower/utils/helpers/topology.c
@@ -0,0 +1,108 @@
1/*
2 * (C) 2010,2011 Thomas Renninger <trenn@suse.de>, Novell Inc.
3 *
4 * Licensed under the terms of the GNU GPL License version 2.
5 *
6 * ToDo: Needs to be done more properly for AMD/Intel specifics
7 */
8
9/* Helper struct for qsort, must be in sync with cpupower_topology.cpu_info */
10/* Be careful: Need to pass unsigned to the sort, so that offlined cores are
11 in the end, but double check for -1 for offlined cpus at other places */
12
13#include <stdlib.h>
14#include <stdio.h>
15#include <unistd.h>
16#include <errno.h>
17#include <fcntl.h>
18
19#include <helpers/helpers.h>
20#include <helpers/sysfs.h>
21
22/* returns -1 on failure, 0 on success */
23int sysfs_topology_read_file(unsigned int cpu, const char *fname)
24{
25 unsigned long value;
26 char linebuf[MAX_LINE_LEN];
27 char *endp;
28 char path[SYSFS_PATH_MAX];
29
30 snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/topology/%s",
31 cpu, fname);
32 if (sysfs_read_file(path, linebuf, MAX_LINE_LEN) == 0 )
33 return -1;
34 value = strtoul(linebuf, &endp, 0);
35 if ( endp == linebuf || errno == ERANGE )
36 return -1;
37 return value;
38}
39
40struct cpuid_core_info {
41 unsigned int pkg;
42 unsigned int thread;
43 unsigned int cpu;
44};
45
46static int __compare(const void *t1, const void *t2)
47{
48 struct cpuid_core_info *top1 = (struct cpuid_core_info *)t1;
49 struct cpuid_core_info *top2 = (struct cpuid_core_info *)t2;
50 if (top1->pkg < top2->pkg)
51 return -1;
52 else if (top1->pkg > top2->pkg)
53 return 1;
54 else if (top1->thread < top2->thread)
55 return -1;
56 else if (top1->thread > top2->thread)
57 return 1;
58 else if (top1->cpu < top2->cpu)
59 return -1;
60 else if (top1->cpu > top2->cpu)
61 return 1;
62 else
63 return 0;
64}
65
66/*
67 * Returns amount of cpus, negative on error, cpu_top must be
68 * passed to cpu_topology_release to free resources
69 *
70 * Array is sorted after ->pkg, ->core, then ->cpu
71 */
72int get_cpu_topology(struct cpupower_topology *cpu_top)
73{
74 int cpu, cpus = sysconf(_SC_NPROCESSORS_CONF);
75
76 cpu_top->core_info = malloc(sizeof(struct cpupower_topology) * cpus);
77 if (cpu_top->core_info == NULL)
78 return -ENOMEM;
79 cpu_top->pkgs = cpu_top->cores = 0;
80 for (cpu = 0; cpu < cpus; cpu++) {
81 cpu_top->core_info[cpu].pkg =
82 sysfs_topology_read_file(cpu, "physical_package_id");
83 if ((int)cpu_top->core_info[cpu].pkg != -1 &&
84 cpu_top->core_info[cpu].pkg > cpu_top->pkgs)
85 cpu_top->pkgs = cpu_top->core_info[cpu].pkg;
86 cpu_top->core_info[cpu].core =
87 sysfs_topology_read_file(cpu, "core_id");
88 cpu_top->core_info[cpu].cpu = cpu;
89 }
90 cpu_top->pkgs++;
91
92 qsort(cpu_top->core_info, cpus, sizeof(struct cpuid_core_info),
93 __compare);
94
95 /* Intel's cores count is not consecutively numbered, there may
96 * be a core_id of 3, but none of 2. Assume there always is 0
97 * Get amount of cores by counting duplicates in a package
98 for (cpu = 0; cpu_top->core_info[cpu].pkg = 0 && cpu < cpus; cpu++) {
99 if (cpu_top->core_info[cpu].core == 0)
100 cpu_top->cores++;
101 */
102 return cpus;
103}
104
105void cpu_topology_release(struct cpupower_topology cpu_top)
106{
107 free(cpu_top.core_info);
108}
diff --git a/tools/power/cpupower/utils/idle_monitor/amd_fam14h_idle.c b/tools/power/cpupower/utils/idle_monitor/amd_fam14h_idle.c
new file mode 100644
index 00000000000..3de94322dfb
--- /dev/null
+++ b/tools/power/cpupower/utils/idle_monitor/amd_fam14h_idle.c
@@ -0,0 +1,340 @@
1/*
2 * (C) 2010,2011 Thomas Renninger <trenn@suse.de>, Novell Inc.
3 *
4 * Licensed under the terms of the GNU GPL License version 2.
5 *
6 * PCI initialization based on example code from:
7 * Andreas Herrmann <andreas.herrmann3@amd.com>
8 */
9
10#if defined(__i386__) || defined(__x86_64__)
11
12#include <stdio.h>
13#include <stdlib.h>
14#include <stdint.h>
15#include <time.h>
16#include <string.h>
17
18#include <pci/pci.h>
19
20#include "idle_monitor/cpupower-monitor.h"
21#include "helpers/helpers.h"
22
23/******** PCI parts could go into own file and get shared ***************/
24
25#define PCI_NON_PC0_OFFSET 0xb0
26#define PCI_PC1_OFFSET 0xb4
27#define PCI_PC6_OFFSET 0xb8
28
29#define PCI_MONITOR_ENABLE_REG 0xe0
30
31#define PCI_NON_PC0_ENABLE_BIT 0
32#define PCI_PC1_ENABLE_BIT 1
33#define PCI_PC6_ENABLE_BIT 2
34
35#define PCI_NBP1_STAT_OFFSET 0x98
36#define PCI_NBP1_ACTIVE_BIT 2
37#define PCI_NBP1_ENTERED_BIT 1
38
39#define PCI_NBP1_CAP_OFFSET 0x90
40#define PCI_NBP1_CAPABLE_BIT 31
41
42#define OVERFLOW_MS 343597 /* 32 bit register filled at 12500 HZ
43 (1 tick per 80ns) */
44
45enum amd_fam14h_states {NON_PC0 = 0, PC1, PC6, NBP1,
46 AMD_FAM14H_STATE_NUM};
47
48static int fam14h_get_count_percent(unsigned int self_id, double *percent,
49 unsigned int cpu);
50static int fam14h_nbp1_count(unsigned int id, unsigned long long *count,
51 unsigned int cpu);
52
53static cstate_t amd_fam14h_cstates[AMD_FAM14H_STATE_NUM] = {
54 {
55 .name = "!PC0",
56 .desc = N_("Package in sleep state (PC1 or deeper)"),
57 .id = NON_PC0,
58 .range = RANGE_PACKAGE,
59 .get_count_percent = fam14h_get_count_percent,
60 },
61 {
62 .name = "PC1",
63 .desc = N_("Processor Package C1"),
64 .id = PC1,
65 .range = RANGE_PACKAGE,
66 .get_count_percent = fam14h_get_count_percent,
67 },
68 {
69 .name = "PC6",
70 .desc = N_("Processor Package C6"),
71 .id = PC6,
72 .range = RANGE_PACKAGE,
73 .get_count_percent = fam14h_get_count_percent,
74 },
75 {
76 .name = "NBP1",
77 .desc = N_("North Bridge P1 boolean counter (returns 0 or 1)"),
78 .id = NBP1,
79 .range = RANGE_PACKAGE,
80 .get_count = fam14h_nbp1_count,
81 },
82};
83
84static struct pci_access *pci_acc;
85static int pci_vendor_id = 0x1022;
86static int pci_dev_ids[2] = {0x1716, 0};
87static struct pci_dev *amd_fam14h_pci_dev;
88
89static int nbp1_entered;
90
91struct timespec start_time;
92static unsigned long long timediff;
93
94#ifdef DEBUG
95struct timespec dbg_time;
96long dbg_timediff;
97#endif
98
99static unsigned long long *previous_count[AMD_FAM14H_STATE_NUM];
100static unsigned long long *current_count[AMD_FAM14H_STATE_NUM];
101
102static int amd_fam14h_get_pci_info(struct cstate *state,
103 unsigned int *pci_offset,
104 unsigned int *enable_bit,
105 unsigned int cpu)
106{
107 switch(state->id) {
108 case NON_PC0:
109 *enable_bit = PCI_NON_PC0_ENABLE_BIT;
110 *pci_offset = PCI_NON_PC0_OFFSET;
111 break;
112 case PC1:
113 *enable_bit = PCI_PC1_ENABLE_BIT;
114 *pci_offset = PCI_PC1_OFFSET;
115 break;
116 case PC6:
117 *enable_bit = PCI_PC6_ENABLE_BIT;
118 *pci_offset = PCI_PC6_OFFSET;
119 break;
120 case NBP1:
121 *enable_bit = PCI_NBP1_ENTERED_BIT;
122 *pci_offset = PCI_NBP1_STAT_OFFSET;
123 break;
124 default:
125 return -1;
126 };
127 return 0;
128}
129
130static int amd_fam14h_init(cstate_t *state, unsigned int cpu)
131{
132 int enable_bit, pci_offset, ret;
133 uint32_t val;
134
135 ret = amd_fam14h_get_pci_info(state, &pci_offset, &enable_bit, cpu);
136 if (ret)
137 return ret;
138
139 /* NBP1 needs extra treating -> write 1 to D18F6x98 bit 1 for init */
140 if (state->id == NBP1) {
141 val = pci_read_long(amd_fam14h_pci_dev, pci_offset);
142 val |= 1 << enable_bit;
143 val = pci_write_long(amd_fam14h_pci_dev, pci_offset, val);
144 return ret;
145 }
146
147 /* Enable monitor */
148 val = pci_read_long(amd_fam14h_pci_dev, PCI_MONITOR_ENABLE_REG);
149 dprint("Init %s: read at offset: 0x%x val: %u\n", state->name,
150 PCI_MONITOR_ENABLE_REG, (unsigned int) val);
151 val |= 1 << enable_bit;
152 pci_write_long(amd_fam14h_pci_dev, PCI_MONITOR_ENABLE_REG, val);
153
154 dprint("Init %s: offset: 0x%x enable_bit: %d - val: %u (%u)\n",
155 state->name, PCI_MONITOR_ENABLE_REG, enable_bit,
156 (unsigned int) val, cpu);
157
158 /* Set counter to zero */
159 pci_write_long(amd_fam14h_pci_dev, pci_offset, 0);
160 previous_count[state->id][cpu] = 0;
161
162 return 0;
163}
164
165static int amd_fam14h_disable(cstate_t *state, unsigned int cpu)
166{
167 int enable_bit, pci_offset, ret;
168 uint32_t val;
169
170 ret = amd_fam14h_get_pci_info(state, &pci_offset, &enable_bit, cpu);
171 if (ret)
172 return ret;
173
174 val = pci_read_long(amd_fam14h_pci_dev, pci_offset);
175 dprint("%s: offset: 0x%x %u\n", state->name, pci_offset, val);
176 if (state->id == NBP1) {
177 /* was the bit whether NBP1 got entered set? */
178 nbp1_entered = (val & (1 << PCI_NBP1_ACTIVE_BIT)) |
179 (val & (1 << PCI_NBP1_ENTERED_BIT));
180
181 dprint("NBP1 was %sentered - 0x%x - enable_bit: "
182 "%d - pci_offset: 0x%x\n",
183 nbp1_entered ? "" : "not ",
184 val, enable_bit, pci_offset);
185 return ret;
186 }
187 current_count[state->id][cpu] = val;
188
189 dprint("%s: Current - %llu (%u)\n", state->name,
190 current_count[state->id][cpu], cpu);
191 dprint("%s: Previous - %llu (%u)\n", state->name,
192 previous_count[state->id][cpu], cpu);
193
194 val = pci_read_long(amd_fam14h_pci_dev, PCI_MONITOR_ENABLE_REG);
195 val &= ~(1 << enable_bit);
196 pci_write_long(amd_fam14h_pci_dev, PCI_MONITOR_ENABLE_REG, val);
197
198 return 0;
199}
200
201static int fam14h_nbp1_count(unsigned int id, unsigned long long *count,
202 unsigned int cpu)
203{
204 if (id == NBP1) {
205 if (nbp1_entered)
206 *count = 1;
207 else
208 *count = 0;
209 return 0;
210 }
211 return -1;
212}
213static int fam14h_get_count_percent(unsigned int id, double *percent,
214 unsigned int cpu)
215{
216 unsigned long diff;
217
218 if (id >= AMD_FAM14H_STATE_NUM)
219 return -1;
220 /* residency count in 80ns -> divide through 12.5 to get us residency */
221 diff = current_count[id][cpu] - previous_count[id][cpu];
222
223 if (timediff == 0)
224 *percent = 0.0;
225 else
226 *percent = 100.0 * diff / timediff / 12.5;
227
228 dprint("Timediff: %llu - res~: %lu us - percent: %.2f %%\n",
229 timediff, diff * 10 / 125, *percent);
230
231 return 0;
232}
233
234static int amd_fam14h_start(void)
235{
236 int num, cpu;
237 clock_gettime(CLOCK_REALTIME, &start_time);
238 for (num = 0; num < AMD_FAM14H_STATE_NUM; num++) {
239 for (cpu = 0; cpu < cpu_count; cpu++) {
240 amd_fam14h_init(&amd_fam14h_cstates[num], cpu);
241 }
242 }
243#ifdef DEBUG
244 clock_gettime(CLOCK_REALTIME, &dbg_time);
245 dbg_timediff = timespec_diff_us(start_time, dbg_time);
246 dprint("Enabling counters took: %lu us\n",
247 dbg_timediff);
248#endif
249 return 0;
250}
251
252static int amd_fam14h_stop(void)
253{
254 int num, cpu;
255 struct timespec end_time;
256
257 clock_gettime(CLOCK_REALTIME, &end_time);
258
259 for (num = 0; num < AMD_FAM14H_STATE_NUM; num++) {
260 for (cpu = 0; cpu < cpu_count; cpu++) {
261 amd_fam14h_disable(&amd_fam14h_cstates[num], cpu);
262 }
263 }
264#ifdef DEBUG
265 clock_gettime(CLOCK_REALTIME, &dbg_time);
266 dbg_timediff = timespec_diff_us(end_time, dbg_time);
267 dprint("Disabling counters took: %lu ns\n", dbg_timediff);
268#endif
269 timediff = timespec_diff_us(start_time, end_time);
270 if (timediff / 1000 > OVERFLOW_MS)
271 print_overflow_err((unsigned int)timediff / 1000000,
272 OVERFLOW_MS / 1000);
273
274 return 0;
275}
276
277static int is_nbp1_capable(void)
278{
279 uint32_t val;
280 val = pci_read_long(amd_fam14h_pci_dev, PCI_NBP1_CAP_OFFSET);
281 return val & (1 << 31);
282}
283
284struct cpuidle_monitor* amd_fam14h_register(void) {
285
286 int num;
287
288 if (cpupower_cpu_info.vendor != X86_VENDOR_AMD)
289 return NULL;
290
291 if (cpupower_cpu_info.family == 0x14) {
292 if (cpu_count <= 0 || cpu_count > 2) {
293 fprintf(stderr, "AMD fam14h: Invalid cpu count: %d\n",
294 cpu_count);
295 return NULL;
296 }
297 } else
298 return NULL;
299
300 /* We do not alloc for nbp1 machine wide counter */
301 for (num = 0; num < AMD_FAM14H_STATE_NUM - 1; num++) {
302 previous_count[num] = calloc (cpu_count,
303 sizeof(unsigned long long));
304 current_count[num] = calloc (cpu_count,
305 sizeof(unsigned long long));
306 }
307
308 amd_fam14h_pci_dev = pci_acc_init(&pci_acc, pci_vendor_id, pci_dev_ids);
309 if (amd_fam14h_pci_dev == NULL || pci_acc == NULL)
310 return NULL;
311
312 if (!is_nbp1_capable())
313 amd_fam14h_monitor.hw_states_num = AMD_FAM14H_STATE_NUM - 1;
314
315 amd_fam14h_monitor.name_len = strlen(amd_fam14h_monitor.name);
316 return &amd_fam14h_monitor;
317}
318
319static void amd_fam14h_unregister(void)
320{
321 int num;
322 for (num = 0; num < AMD_FAM14H_STATE_NUM - 1; num++) {
323 free(previous_count[num]);
324 free(current_count[num]);
325 }
326 pci_cleanup(pci_acc);
327}
328
329struct cpuidle_monitor amd_fam14h_monitor = {
330 .name = "Ontario",
331 .hw_states = amd_fam14h_cstates,
332 .hw_states_num = AMD_FAM14H_STATE_NUM,
333 .start = amd_fam14h_start,
334 .stop = amd_fam14h_stop,
335 .do_register = amd_fam14h_register,
336 .unregister = amd_fam14h_unregister,
337 .needs_root = 1,
338 .overflow_s = OVERFLOW_MS / 1000,
339};
340#endif /* #if defined(__i386__) || defined(__x86_64__) */
diff --git a/tools/power/cpupower/utils/idle_monitor/cpuidle_sysfs.c b/tools/power/cpupower/utils/idle_monitor/cpuidle_sysfs.c
new file mode 100644
index 00000000000..63f6d670517
--- /dev/null
+++ b/tools/power/cpupower/utils/idle_monitor/cpuidle_sysfs.c
@@ -0,0 +1,185 @@
1/*
2 * (C) 2010,2011 Thomas Renninger <trenn@suse.de>, Novell Inc
3 *
4 * Licensed under the terms of the GNU GPL License version 2.
5 *
6 */
7
8#include <stdio.h>
9#include <stdlib.h>
10#include <stdint.h>
11#include <string.h>
12#include <limits.h>
13
14#include "helpers/sysfs.h"
15#include "helpers/helpers.h"
16#include "idle_monitor/cpupower-monitor.h"
17
18#define CPUIDLE_STATES_MAX 10
19static cstate_t cpuidle_cstates[CPUIDLE_STATES_MAX];
20struct cpuidle_monitor cpuidle_sysfs_monitor;
21
22static unsigned long long **previous_count;
23static unsigned long long **current_count;
24struct timespec start_time;
25static unsigned long long timediff;
26
27static int cpuidle_get_count_percent(unsigned int id, double *percent,
28 unsigned int cpu)
29{
30 unsigned long long statediff = current_count[cpu][id]
31 - previous_count[cpu][id];
32 dprint("%s: - diff: %llu - percent: %f (%u)\n",
33 cpuidle_cstates[id].name, timediff, *percent, cpu);
34
35 if (timediff == 0)
36 *percent = 0.0;
37 else
38 *percent = ((100.0 * statediff) / timediff);
39
40 dprint("%s: - timediff: %llu - statediff: %llu - percent: %f (%u)\n",
41 cpuidle_cstates[id].name, timediff, statediff, *percent, cpu);
42
43 return 0;
44}
45
46static int cpuidle_start(void)
47{
48 int cpu, state;
49 clock_gettime(CLOCK_REALTIME, &start_time);
50 for (cpu = 0; cpu < cpu_count; cpu++) {
51 for (state = 0; state < cpuidle_sysfs_monitor.hw_states_num;
52 state++) {
53 previous_count[cpu][state] =
54 sysfs_get_idlestate_time(cpu, state);
55 dprint("CPU %d - State: %d - Val: %llu\n",
56 cpu, state, previous_count[cpu][state]);
57 }
58
59 };
60 return 0;
61}
62
63static int cpuidle_stop(void)
64{
65 int cpu, state;
66 struct timespec end_time;
67 clock_gettime(CLOCK_REALTIME, &end_time);
68 timediff = timespec_diff_us(start_time, end_time);
69
70 for (cpu = 0; cpu < cpu_count; cpu++) {
71 for (state = 0; state < cpuidle_sysfs_monitor.hw_states_num;
72 state++) {
73 current_count[cpu][state] =
74 sysfs_get_idlestate_time(cpu, state);
75 dprint("CPU %d - State: %d - Val: %llu\n",
76 cpu, state, previous_count[cpu][state]);
77 }
78 };
79 return 0;
80}
81
82void fix_up_intel_idle_driver_name(char *tmp, int num)
83{
84 /* fix up cpuidle name for intel idle driver */
85 if (!strncmp(tmp, "NHM-", 4)) {
86 switch(num) {
87 case 1: strcpy(tmp, "C1");
88 break;
89 case 2: strcpy(tmp, "C3");
90 break;
91 case 3: strcpy(tmp, "C6");
92 break;
93 }
94 } else if (!strncmp(tmp, "SNB-", 4)) {
95 switch(num) {
96 case 1: strcpy(tmp, "C1");
97 break;
98 case 2: strcpy(tmp, "C3");
99 break;
100 case 3: strcpy(tmp, "C6");
101 break;
102 case 4: strcpy(tmp, "C7");
103 break;
104 }
105 } else if (!strncmp(tmp, "ATM-", 4)) {
106 switch(num) {
107 case 1: strcpy(tmp, "C1");
108 break;
109 case 2: strcpy(tmp, "C2");
110 break;
111 case 3: strcpy(tmp, "C4");
112 break;
113 case 4: strcpy(tmp, "C6");
114 break;
115 }
116 }
117}
118
119static struct cpuidle_monitor* cpuidle_register(void)
120{
121 int num;
122 char *tmp;
123
124 /* Assume idle state count is the same for all CPUs */
125 cpuidle_sysfs_monitor.hw_states_num = sysfs_get_idlestate_count(0);
126
127 if (cpuidle_sysfs_monitor.hw_states_num == 0)
128 return NULL;
129
130 for (num = 0; num < cpuidle_sysfs_monitor.hw_states_num; num ++) {
131 tmp = sysfs_get_idlestate_name(0, num);
132 if (tmp == NULL)
133 continue;
134
135 fix_up_intel_idle_driver_name(tmp, num);
136 strncpy(cpuidle_cstates[num].name, tmp, CSTATE_NAME_LEN - 1);
137 free(tmp);
138
139 tmp = sysfs_get_idlestate_desc(0, num);
140 if (tmp == NULL)
141 continue;
142 strncpy(cpuidle_cstates[num].desc, tmp, CSTATE_DESC_LEN - 1);
143 free(tmp);
144
145 cpuidle_cstates[num].range = RANGE_THREAD;
146 cpuidle_cstates[num].id = num;
147 cpuidle_cstates[num].get_count_percent = cpuidle_get_count_percent;
148 };
149
150 /* Free this at program termination */
151 previous_count = malloc(sizeof (long long*) * cpu_count);
152 current_count = malloc(sizeof (long long*) * cpu_count);
153 for (num = 0; num < cpu_count; num++) {
154 previous_count[num] = malloc (sizeof(long long) *
155 cpuidle_sysfs_monitor.hw_states_num);
156 current_count[num] = malloc (sizeof(long long) *
157 cpuidle_sysfs_monitor.hw_states_num);
158 }
159
160 cpuidle_sysfs_monitor.name_len = strlen(cpuidle_sysfs_monitor.name);
161 return &cpuidle_sysfs_monitor;
162}
163
164void cpuidle_unregister(void)
165{
166 int num;
167
168 for (num = 0; num < cpu_count; num++) {
169 free(previous_count[num]);
170 free(current_count[num]);
171 }
172 free(previous_count);
173 free(current_count);
174}
175
176struct cpuidle_monitor cpuidle_sysfs_monitor = {
177 .name = "Idle_Stats",
178 .hw_states = cpuidle_cstates,
179 .start = cpuidle_start,
180 .stop = cpuidle_stop,
181 .do_register = cpuidle_register,
182 .unregister = cpuidle_unregister,
183 .needs_root = 0,
184 .overflow_s = UINT_MAX,
185};
diff --git a/tools/power/cpupower/utils/idle_monitor/cpupower-monitor.c b/tools/power/cpupower/utils/idle_monitor/cpupower-monitor.c
new file mode 100644
index 00000000000..3e96e79de3c
--- /dev/null
+++ b/tools/power/cpupower/utils/idle_monitor/cpupower-monitor.c
@@ -0,0 +1,446 @@
1/*
2 * (C) 2010,2011 Thomas Renninger <trenn@suse.de>, Novell Inc.
3 *
4 * Licensed under the terms of the GNU GPL License version 2.
5 *
6 * Output format inspired by Len Brown's <lenb@kernel.org> turbostat tool.
7 *
8 */
9
10
11#include <stdio.h>
12#include <unistd.h>
13#include <stdlib.h>
14#include <string.h>
15#include <time.h>
16#include <signal.h>
17#include <sys/types.h>
18#include <sys/wait.h>
19#include <libgen.h>
20
21#include "idle_monitor/cpupower-monitor.h"
22#include "idle_monitor/idle_monitors.h"
23#include "helpers/helpers.h"
24
25/* Define pointers to all monitors. */
26#define DEF(x) & x ## _monitor ,
27struct cpuidle_monitor * all_monitors[] = {
28#include "idle_monitors.def"
290
30};
31
32static struct cpuidle_monitor *monitors[MONITORS_MAX];
33static unsigned int avail_monitors;
34
35static char *progname;
36
37enum operation_mode_e { list = 1, show, show_all };
38static int mode;
39static int interval = 1;
40static char *show_monitors_param;
41static struct cpupower_topology cpu_top;
42
43/* ToDo: Document this in the manpage */
44static char range_abbr[RANGE_MAX] = { 'T', 'C', 'P', 'M', };
45
46long long timespec_diff_us(struct timespec start, struct timespec end)
47{
48 struct timespec temp;
49 if ((end.tv_nsec - start.tv_nsec) < 0) {
50 temp.tv_sec = end.tv_sec - start.tv_sec - 1;
51 temp.tv_nsec = 1000000000 + end.tv_nsec - start.tv_nsec;
52 } else {
53 temp.tv_sec = end.tv_sec - start.tv_sec;
54 temp.tv_nsec = end.tv_nsec - start.tv_nsec;
55 }
56 return (temp.tv_sec * 1000000) + (temp.tv_nsec / 1000);
57}
58
59void monitor_help(void)
60{
61 printf(_("cpupower monitor: [-m <mon1>,[<mon2>],.. ] command\n"));
62 printf(_("cpupower monitor: [-m <mon1>,[<mon2>],.. ] [ -i interval_sec ]\n"));
63 printf(_("cpupower monitor: -l\n"));
64 printf(_("\t command: pass an arbitrary command to measure specific workload\n"));
65 printf(_("\t -i: time intervall to measure for in seconds (default 1)\n"));
66 printf(_("\t -l: list available CPU sleep monitors (for use with -m)\n"));
67 printf(_("\t -m: show specific CPU sleep monitors only (in same order)\n"));
68 printf(_("\t -h: print this help\n"));
69 printf("\n");
70 printf(_("only one of: -l, -m are allowed\nIf none of them is passed,"));
71 printf(_(" all supported monitors are shown\n"));
72}
73
74void print_n_spaces(int n)
75{
76 int x;
77 for (x = 0; x < n; x++)
78 printf(" ");
79}
80
81/* size of s must be at least n + 1 */
82int fill_string_with_spaces(char *s, int n)
83{
84 int len = strlen(s);
85 if (len > n)
86 return -1;
87 for (; len < n; len++)
88 s[len] = ' ';
89 s[len] = '\0';
90 return 0;
91}
92
93void print_header(int topology_depth)
94{
95 int unsigned mon;
96 int state, need_len, pr_mon_len;
97 cstate_t s;
98 char buf[128] = "";
99 int percent_width = 4;
100
101 fill_string_with_spaces(buf, topology_depth * 5 - 1);
102 printf("%s|", buf);
103
104 for (mon = 0; mon < avail_monitors; mon++) {
105 pr_mon_len = 0;
106 need_len = monitors[mon]->hw_states_num * (percent_width + 3)
107 - 1;
108 if (mon != 0) {
109 printf("|| ");
110 need_len --;
111 }
112 sprintf(buf, "%s", monitors[mon]->name);
113 fill_string_with_spaces(buf, need_len);
114 printf("%s", buf);
115 }
116 printf("\n");
117
118 if (topology_depth > 2)
119 printf("PKG |");
120 if (topology_depth > 1)
121 printf("CORE|");
122 if (topology_depth > 0)
123 printf("CPU |");
124
125 for (mon = 0; mon < avail_monitors; mon++) {
126 if (mon != 0)
127 printf("|| ");
128 else
129 printf(" ");
130 for (state = 0; state < monitors[mon]->hw_states_num; state++) {
131 if (state != 0)
132 printf(" | ");
133 s = monitors[mon]->hw_states[state];
134 sprintf(buf, "%s", s.name);
135 fill_string_with_spaces(buf, percent_width);
136 printf("%s", buf);
137 }
138 printf(" ");
139 }
140 printf("\n");
141}
142
143
144void print_results(int topology_depth, int cpu)
145{
146 unsigned int mon;
147 int state, ret;
148 double percent;
149 unsigned long long result;
150 cstate_t s;
151
152 if (topology_depth > 2)
153 printf("%4d|", cpu_top.core_info[cpu].pkg);
154 if (topology_depth > 1)
155 printf("%4d|", cpu_top.core_info[cpu].core);
156 if (topology_depth > 0)
157 printf("%4d|", cpu_top.core_info[cpu].cpu);
158
159 for (mon = 0; mon < avail_monitors; mon++) {
160 if (mon != 0)
161 printf("||");
162
163 for (state = 0; state < monitors[mon]->hw_states_num; state++) {
164 if (state != 0)
165 printf("|");
166
167 s = monitors[mon]->hw_states[state];
168
169 if (s.get_count_percent) {
170 ret = s.get_count_percent(s.id, &percent,
171 cpu_top.core_info[cpu].cpu);
172 if (ret) {
173 printf("******");
174 } else if (percent >= 100.0)
175 printf("%6.1f", percent);
176 else
177 printf("%6.2f", percent);
178 }
179 else if (s.get_count) {
180 ret = s.get_count(s.id, &result,
181 cpu_top.core_info[cpu].cpu);
182 if (ret) {
183 printf("******");
184 } else
185 printf("%6llu", result);
186 }
187 else {
188 printf(_("Monitor %s, Counter %s has no count "
189 "function. Implementation error\n"),
190 monitors[mon]->name, s.name);
191 exit (EXIT_FAILURE);
192 }
193 }
194 }
195 /* cpu offline */
196 if (cpu_top.core_info[cpu].pkg == -1 ||
197 cpu_top.core_info[cpu].core == -1) {
198 printf(_(" *is offline\n"));
199 return;
200 } else
201 printf("\n");
202}
203
204
205/* param: string passed by -m param (The list of monitors to show)
206 *
207 * Monitors must have been registered already, matching monitors
208 * are picked out and available monitors array is overridden
209 * with matching ones
210 *
211 * Monitors get sorted in the same order the user passes them
212*/
213
214static void parse_monitor_param(char* param)
215{
216 unsigned int num;
217 int mon, hits = 0;
218 char *tmp = param, *token;
219 struct cpuidle_monitor *tmp_mons[MONITORS_MAX];
220
221
222 for (mon = 0; mon < MONITORS_MAX;mon++, tmp = NULL) {
223 token = strtok(tmp, ",");
224 if (token == NULL)
225 break;
226 if (strlen(token) >= MONITOR_NAME_LEN) {
227 printf(_("%s: max monitor name length"
228 " (%d) exceeded\n"), token, MONITOR_NAME_LEN);
229 continue;
230 }
231
232 for (num = 0; num < avail_monitors; num++) {
233 if (!strcmp(monitors[num]->name, token)) {
234 dprint("Found requested monitor: %s\n", token);
235 tmp_mons[hits] = monitors[num];
236 hits++;
237 }
238 }
239 }
240 if (hits == 0) {
241 printf(_("No matching monitor found in %s, "
242 "try -l option\n"), param);
243 monitor_help();
244 exit(EXIT_FAILURE);
245 }
246 /* Override detected/registerd monitors array with requested one */
247 memcpy(monitors, tmp_mons, sizeof(struct cpuidle_monitor*) * MONITORS_MAX);
248 avail_monitors = hits;
249}
250
251void list_monitors(void) {
252 unsigned int mon;
253 int state;
254 cstate_t s;
255
256 for (mon = 0; mon < avail_monitors; mon++) {
257 printf(_("Monitor \"%s\" (%d states) - Might overflow after %u "
258 "s\n"), monitors[mon]->name, monitors[mon]->hw_states_num,
259 monitors[mon]->overflow_s);
260
261 for (state = 0; state < monitors[mon]->hw_states_num; state++) {
262 s = monitors[mon]->hw_states[state];
263 /*
264 * ToDo show more state capabilities:
265 * percent, time (granlarity)
266 */
267 printf("%s\t[%c] -> %s\n", s.name, range_abbr[s.range],
268 gettext(s.desc));
269 }
270 }
271}
272
273int fork_it(char **argv)
274{
275 int status;
276 unsigned int num;
277 unsigned long long timediff;
278 pid_t child_pid;
279 struct timespec start, end;
280
281 child_pid = fork();
282 clock_gettime(CLOCK_REALTIME, &start);
283
284 for (num = 0; num < avail_monitors; num++)
285 monitors[num]->start();
286
287 if (!child_pid) {
288 /* child */
289 execvp(argv[0], argv);
290 } else {
291 /* parent */
292 if (child_pid == -1) {
293 perror("fork");
294 exit(1);
295 }
296
297 signal(SIGINT, SIG_IGN);
298 signal(SIGQUIT, SIG_IGN);
299 if (waitpid(child_pid, &status, 0) == -1) {
300 perror("wait");
301 exit(1);
302 }
303 }
304 clock_gettime(CLOCK_REALTIME, &end);
305 for (num = 0; num < avail_monitors; num++)
306 monitors[num]->stop();
307
308 timediff = timespec_diff_us(start, end);
309 if (WIFEXITED(status))
310 printf(_("%s took %.5f seconds and exited with status %d\n"),
311 argv[0], timediff / (1000.0 * 1000), WEXITSTATUS(status));
312 return 0;
313}
314
315int do_interval_measure(int i)
316{
317 unsigned int num;
318
319 for (num = 0; num < avail_monitors; num++) {
320 dprint("HW C-state residency monitor: %s - States: %d\n",
321 monitors[num]->name, monitors[num]->hw_states_num);
322 monitors[num]->start();
323 }
324 sleep(i);
325 for (num = 0; num < avail_monitors; num++) {
326 monitors[num]->stop();
327 }
328 return 0;
329}
330
331static void cmdline(int argc, char *argv[])
332{
333 int opt;
334 progname = basename(argv[0]);
335
336 while ((opt = getopt(argc, argv, "+hli:m:")) != -1) {
337 switch (opt) {
338 case 'h':
339 monitor_help();
340 exit(EXIT_SUCCESS);
341 case 'l':
342 if (mode) {
343 monitor_help();
344 exit(EXIT_FAILURE);
345 }
346 mode = list;
347 break;
348 case 'i':
349 /* only allow -i with -m or no option */
350 if (mode && mode != show) {
351 monitor_help();
352 exit(EXIT_FAILURE);
353 }
354 interval = atoi(optarg);
355 break;
356 case 'm':
357 if (mode) {
358 monitor_help();
359 exit(EXIT_FAILURE);
360 }
361 mode = show;
362 show_monitors_param = optarg;
363 break;
364 default:
365 monitor_help();
366 exit(EXIT_FAILURE);
367 }
368 }
369 if (!mode)
370 mode = show_all;
371}
372
373int cmd_monitor(int argc, char **argv)
374{
375 unsigned int num;
376 struct cpuidle_monitor *test_mon;
377 int cpu;
378
379 cmdline(argc, argv);
380 cpu_count = get_cpu_topology(&cpu_top);
381 if (cpu_count < 0) {
382 printf(_("Cannot read number of available processors\n"));
383 return EXIT_FAILURE;
384 }
385
386 dprint("System has up to %d CPU cores\n", cpu_count);
387
388 for (num = 0; all_monitors[num]; num++) {
389 dprint("Try to register: %s\n", all_monitors[num]->name);
390 test_mon = all_monitors[num]->do_register();
391 if (test_mon) {
392 if (test_mon->needs_root && !run_as_root) {
393 fprintf(stderr, _("Available monitor %s needs "
394 "root access\n"), test_mon->name);
395 continue;
396 }
397 monitors[avail_monitors] = test_mon;
398 dprint("%s registered\n", all_monitors[num]->name);
399 avail_monitors++;
400 }
401 }
402
403 if (avail_monitors == 0) {
404 printf(_("No HW Cstate monitors found\n"));
405 return 1;
406 }
407
408 if (mode == list) {
409 list_monitors();
410 exit(EXIT_SUCCESS);
411 }
412
413 if (mode == show)
414 parse_monitor_param(show_monitors_param);
415
416 dprint("Packages: %d - Cores: %d - CPUs: %d\n",
417 cpu_top.pkgs, cpu_top.cores, cpu_count);
418
419 /*
420 * if any params left, it must be a command to fork
421 */
422 if (argc - optind)
423 fork_it(argv + optind);
424 else
425 do_interval_measure(interval);
426
427 /* ToDo: Topology parsing needs fixing first to do
428 this more generically */
429 if (cpu_top.pkgs > 1)
430 print_header(3);
431 else
432 print_header(1);
433
434 for (cpu = 0; cpu < cpu_count; cpu++) {
435 if (cpu_top.pkgs > 1)
436 print_results(3, cpu);
437 else
438 print_results(1, cpu);
439 }
440
441 for (num = 0; num < avail_monitors; num++) {
442 monitors[num]->unregister();
443 }
444 cpu_topology_release(cpu_top);
445 return 0;
446}
diff --git a/tools/power/cpupower/utils/idle_monitor/cpupower-monitor.h b/tools/power/cpupower/utils/idle_monitor/cpupower-monitor.h
new file mode 100644
index 00000000000..9312ee1f2db
--- /dev/null
+++ b/tools/power/cpupower/utils/idle_monitor/cpupower-monitor.h
@@ -0,0 +1,68 @@
1/*
2 * (C) 2010,2011 Thomas Renninger <trenn@suse.de>, Novell Inc.
3 *
4 * Licensed under the terms of the GNU GPL License version 2.
5 *
6 */
7
8#ifndef __CPUIDLE_INFO_HW__
9#define __CPUIDLE_INFO_HW__
10
11#include <stdarg.h>
12#include <time.h>
13
14#include "idle_monitor/idle_monitors.h"
15
16#define MONITORS_MAX 20
17#define MONITOR_NAME_LEN 20
18#define CSTATE_NAME_LEN 5
19#define CSTATE_DESC_LEN 60
20
21int cpu_count;
22
23/* Hard to define the right names ...: */
24enum power_range_e {
25 RANGE_THREAD, /* Lowest in topology hierarcy, AMD: core, Intel: thread
26 kernel sysfs: cpu */
27 RANGE_CORE, /* AMD: unit, Intel: core, kernel_sysfs: core_id */
28 RANGE_PACKAGE, /* Package, processor socket */
29 RANGE_MACHINE, /* Machine, platform wide */
30 RANGE_MAX };
31
32typedef struct cstate {
33 int id;
34 enum power_range_e range;
35 char name[CSTATE_NAME_LEN];
36 char desc[CSTATE_DESC_LEN];
37
38 /* either provide a percentage or a general count */
39 int (*get_count_percent)(unsigned int self_id, double *percent,
40 unsigned int cpu);
41 int (*get_count)(unsigned int self_id, unsigned long long *count,
42 unsigned int cpu);
43} cstate_t;
44
45struct cpuidle_monitor {
46 /* Name must not contain whitespaces */
47 char name[MONITOR_NAME_LEN];
48 int name_len;
49 int hw_states_num;
50 cstate_t *hw_states;
51 int (*start) (void);
52 int (*stop) (void);
53 struct cpuidle_monitor* (*do_register) (void);
54 void (*unregister)(void);
55 unsigned int overflow_s;
56 int needs_root;
57};
58
59extern long long timespec_diff_us(struct timespec start, struct timespec end);
60
61#define print_overflow_err(mes, ov) \
62{ \
63 fprintf(stderr, gettext("Measure took %u seconds, but registers could " \
64 "overflow at %u seconds, results " \
65 "could be inaccurate\n"), mes, ov); \
66}
67
68#endif /* __CPUIDLE_INFO_HW__ */
diff --git a/tools/power/cpupower/utils/idle_monitor/idle_monitors.def b/tools/power/cpupower/utils/idle_monitor/idle_monitors.def
new file mode 100644
index 00000000000..e3f8d9b2b18
--- /dev/null
+++ b/tools/power/cpupower/utils/idle_monitor/idle_monitors.def
@@ -0,0 +1,7 @@
1#if defined(__i386__) || defined(__x86_64__)
2DEF(amd_fam14h)
3DEF(intel_nhm)
4DEF(intel_snb)
5DEF(mperf)
6#endif
7DEF(cpuidle_sysfs)
diff --git a/tools/power/cpupower/utils/idle_monitor/idle_monitors.h b/tools/power/cpupower/utils/idle_monitor/idle_monitors.h
new file mode 100644
index 00000000000..4fcdeb1e07e
--- /dev/null
+++ b/tools/power/cpupower/utils/idle_monitor/idle_monitors.h
@@ -0,0 +1,18 @@
1/*
2 * (C) 2010,2011 Thomas Renninger <trenn@suse.de>, Novell Inc.
3 *
4 * Licensed under the terms of the GNU GPL License version 2.
5 *
6 * Based on the idea from Michael Matz <matz@suse.de>
7 *
8 */
9
10#ifndef _CPUIDLE_IDLE_MONITORS_H_
11#define _CPUIDLE_IDLE_MONITORS_H_
12
13#define DEF(x) extern struct cpuidle_monitor x ##_monitor;
14#include "idle_monitors.def"
15#undef DEF
16extern struct cpuidle_monitor *all_monitors[];
17
18#endif /* _CPUIDLE_IDLE_MONITORS_H_ */
diff --git a/tools/power/cpupower/utils/idle_monitor/mperf_monitor.c b/tools/power/cpupower/utils/idle_monitor/mperf_monitor.c
new file mode 100644
index 00000000000..f8545e40e23
--- /dev/null
+++ b/tools/power/cpupower/utils/idle_monitor/mperf_monitor.c
@@ -0,0 +1,258 @@
1/*
2 * (C) 2010,2011 Thomas Renninger <trenn@suse.de>, Novell Inc.
3 *
4 * Licensed under the terms of the GNU GPL License version 2.
5 */
6
7#if defined(__i386__) || defined(__x86_64__)
8
9#include <stdio.h>
10#include <stdint.h>
11#include <stdlib.h>
12#include <string.h>
13#include <limits.h>
14
15#include <cpufreq.h>
16
17#include "helpers/helpers.h"
18#include "idle_monitor/cpupower-monitor.h"
19
20#define MSR_APERF 0xE8
21#define MSR_MPERF 0xE7
22
23#define MSR_TSC 0x10
24
25enum mperf_id { C0 = 0, Cx, AVG_FREQ, MPERF_CSTATE_COUNT };
26
27static int mperf_get_count_percent(unsigned int self_id, double *percent,
28 unsigned int cpu);
29static int mperf_get_count_freq(unsigned int id, unsigned long long *count,
30 unsigned int cpu);
31
32static cstate_t mperf_cstates[MPERF_CSTATE_COUNT] = {
33 {
34 .name = "C0",
35 .desc = N_("Processor Core not idle"),
36 .id = C0,
37 .range = RANGE_THREAD,
38 .get_count_percent = mperf_get_count_percent,
39 },
40 {
41 .name = "Cx",
42 .desc = N_("Processor Core in an idle state"),
43 .id = Cx,
44 .range = RANGE_THREAD,
45 .get_count_percent = mperf_get_count_percent,
46 },
47
48 {
49 .name = "Freq",
50 .desc = N_("Average Frequency (including boost) in MHz"),
51 .id = AVG_FREQ,
52 .range = RANGE_THREAD,
53 .get_count = mperf_get_count_freq,
54 },
55};
56
57static unsigned long long tsc_at_measure_start;
58static unsigned long long tsc_at_measure_end;
59static unsigned long max_frequency;
60static unsigned long long *mperf_previous_count;
61static unsigned long long *aperf_previous_count;
62static unsigned long long *mperf_current_count;
63static unsigned long long *aperf_current_count;
64/* valid flag for all CPUs. If a MSR read failed it will be zero */
65static int *is_valid;
66
67static int mperf_get_tsc(unsigned long long *tsc)
68{
69 return read_msr(0, MSR_TSC, tsc);
70}
71
72static int mperf_init_stats(unsigned int cpu)
73{
74 unsigned long long val;
75 int ret;
76
77 ret = read_msr(cpu, MSR_APERF, &val);
78 aperf_previous_count[cpu] = val;
79 ret |= read_msr(cpu, MSR_MPERF, &val);
80 mperf_previous_count[cpu] = val;
81 is_valid[cpu] = !ret;
82
83 return 0;
84}
85
86static int mperf_measure_stats(unsigned int cpu)
87{
88 unsigned long long val;
89 int ret;
90
91 ret = read_msr(cpu, MSR_APERF, &val);
92 aperf_current_count[cpu] = val;
93 ret |= read_msr(cpu, MSR_MPERF, &val);
94 mperf_current_count[cpu] = val;
95 is_valid[cpu] = !ret;
96
97 return 0;
98}
99
100/*
101 * get_average_perf()
102 *
103 * Returns the average performance (also considers boosted frequencies)
104 *
105 * Input:
106 * aperf_diff: Difference of the aperf register over a time period
107 * mperf_diff: Difference of the mperf register over the same time period
108 * max_freq: Maximum frequency (P0)
109 *
110 * Returns:
111 * Average performance over the time period
112 */
113static unsigned long get_average_perf(unsigned long long aperf_diff,
114 unsigned long long mperf_diff)
115{
116 unsigned int perf_percent = 0;
117 if (((unsigned long)(-1) / 100) < aperf_diff) {
118 int shift_count = 7;
119 aperf_diff >>= shift_count;
120 mperf_diff >>= shift_count;
121 }
122 perf_percent = (aperf_diff * 100) / mperf_diff;
123 return (max_frequency * perf_percent) / 100;
124}
125
126static int mperf_get_count_percent(unsigned int id, double *percent,
127 unsigned int cpu)
128{
129 unsigned long long aperf_diff, mperf_diff, tsc_diff;
130
131 if (!is_valid[cpu])
132 return -1;
133
134 if (id != C0 && id != Cx)
135 return -1;
136
137 mperf_diff = mperf_current_count[cpu] - mperf_previous_count[cpu];
138 aperf_diff = aperf_current_count[cpu] - aperf_previous_count[cpu];
139 tsc_diff = tsc_at_measure_end - tsc_at_measure_start;
140
141 *percent = 100.0 * mperf_diff / tsc_diff;
142 dprint("%s: mperf_diff: %llu, tsc_diff: %llu\n",
143 mperf_cstates[id].name, mperf_diff, tsc_diff);
144
145 if (id == Cx)
146 *percent = 100.0 - *percent;
147
148 dprint("%s: previous: %llu - current: %llu - (%u)\n", mperf_cstates[id].name,
149 mperf_diff, aperf_diff, cpu);
150 dprint("%s: %f\n", mperf_cstates[id].name, *percent);
151 return 0;
152}
153
154static int mperf_get_count_freq(unsigned int id, unsigned long long *count,
155 unsigned int cpu)
156{
157 unsigned long long aperf_diff, mperf_diff;
158
159 if (id != AVG_FREQ)
160 return 1;
161
162 if (!is_valid[cpu])
163 return -1;
164
165 mperf_diff = mperf_current_count[cpu] - mperf_previous_count[cpu];
166 aperf_diff = aperf_current_count[cpu] - aperf_previous_count[cpu];
167
168 /* Return MHz for now, might want to return KHz if column width is more
169 generic */
170 *count = get_average_perf(aperf_diff, mperf_diff) / 1000;
171 dprint("%s: %llu\n", mperf_cstates[id].name, *count);
172
173 return 0;
174}
175
176static int mperf_start(void)
177{
178 int cpu;
179 unsigned long long dbg;
180
181 mperf_get_tsc(&tsc_at_measure_start);
182
183 for (cpu = 0; cpu < cpu_count; cpu++)
184 mperf_init_stats(cpu);
185
186 mperf_get_tsc(&dbg);
187 dprint("TSC diff: %llu\n", dbg - tsc_at_measure_start);
188 return 0;
189}
190
191static int mperf_stop(void)
192{
193 unsigned long long dbg;
194 int cpu;
195
196 mperf_get_tsc(&tsc_at_measure_end);
197
198 for (cpu = 0; cpu < cpu_count; cpu++)
199 mperf_measure_stats(cpu);
200
201 mperf_get_tsc(&dbg);
202 dprint("TSC diff: %llu\n", dbg - tsc_at_measure_end);
203
204 return 0;
205}
206
207struct cpuidle_monitor mperf_monitor;
208
209struct cpuidle_monitor* mperf_register(void) {
210
211 unsigned long min;
212
213 if (!(cpupower_cpu_info.caps & CPUPOWER_CAP_APERF))
214 return NULL;
215
216 /* Assume min/max all the same on all cores */
217 if (cpufreq_get_hardware_limits(0, &min, &max_frequency)) {
218 dprint("Cannot retrieve max freq from cpufreq kernel "
219 "subsystem\n");
220 return NULL;
221 }
222
223 /* Free this at program termination */
224 is_valid = calloc(cpu_count, sizeof (int));
225 mperf_previous_count = calloc (cpu_count,
226 sizeof(unsigned long long));
227 aperf_previous_count = calloc (cpu_count,
228 sizeof(unsigned long long));
229 mperf_current_count = calloc (cpu_count,
230 sizeof(unsigned long long));
231 aperf_current_count = calloc (cpu_count,
232 sizeof(unsigned long long));
233
234 mperf_monitor.name_len = strlen(mperf_monitor.name);
235 return &mperf_monitor;
236}
237
238void mperf_unregister(void) {
239 free(mperf_previous_count);
240 free(aperf_previous_count);
241 free(mperf_current_count);
242 free(aperf_current_count);
243 free(is_valid);
244}
245
246struct cpuidle_monitor mperf_monitor = {
247 .name = "Mperf",
248 .hw_states_num = MPERF_CSTATE_COUNT,
249 .hw_states = mperf_cstates,
250 .start = mperf_start,
251 .stop = mperf_stop,
252 .do_register = mperf_register,
253 .unregister = mperf_unregister,
254 .needs_root = 1,
255 .overflow_s = 922000000 /* 922337203 seconds TSC overflow
256 at 20GHz */
257};
258#endif /* #if defined(__i386__) || defined(__x86_64__) */
diff --git a/tools/power/cpupower/utils/idle_monitor/nhm_idle.c b/tools/power/cpupower/utils/idle_monitor/nhm_idle.c
new file mode 100644
index 00000000000..6424b6dd3fa
--- /dev/null
+++ b/tools/power/cpupower/utils/idle_monitor/nhm_idle.c
@@ -0,0 +1,212 @@
1/*
2 * (C) 2010,2011 Thomas Renninger <trenn@suse.de>, Novell Inc.
3 *
4 * Licensed under the terms of the GNU GPL License version 2.
5 *
6 * Based on Len Brown's <lenb@kernel.org> turbostat tool.
7 */
8
9#if defined(__i386__) || defined(__x86_64__)
10
11#include <stdio.h>
12#include <stdint.h>
13#include <stdlib.h>
14#include <string.h>
15
16#include "helpers/helpers.h"
17#include "idle_monitor/cpupower-monitor.h"
18
19#define MSR_PKG_C3_RESIDENCY 0x3F8
20#define MSR_PKG_C6_RESIDENCY 0x3F9
21#define MSR_CORE_C3_RESIDENCY 0x3FC
22#define MSR_CORE_C6_RESIDENCY 0x3FD
23
24#define MSR_TSC 0x10
25
26#define NHM_CSTATE_COUNT 4
27
28enum intel_nhm_id { C3 = 0, C6, PC3, PC6, TSC = 0xFFFF };
29
30static int nhm_get_count_percent(unsigned int self_id, double *percent,
31 unsigned int cpu);
32
33static cstate_t nhm_cstates[NHM_CSTATE_COUNT] = {
34 {
35 .name = "C3",
36 .desc = N_("Processor Core C3"),
37 .id = C3,
38 .range = RANGE_CORE,
39 .get_count_percent = nhm_get_count_percent,
40 },
41 {
42 .name = "C6",
43 .desc = N_("Processor Core C6"),
44 .id = C6,
45 .range = RANGE_CORE,
46 .get_count_percent = nhm_get_count_percent,
47 },
48
49 {
50 .name = "PC3",
51 .desc = N_("Processor Package C3"),
52 .id = PC3,
53 .range = RANGE_PACKAGE,
54 .get_count_percent = nhm_get_count_percent,
55 },
56 {
57 .name = "PC6",
58 .desc = N_("Processor Package C6"),
59 .id = PC6,
60 .range = RANGE_PACKAGE,
61 .get_count_percent = nhm_get_count_percent,
62 },
63};
64
65static unsigned long long tsc_at_measure_start;
66static unsigned long long tsc_at_measure_end;
67static unsigned long long *previous_count[NHM_CSTATE_COUNT];
68static unsigned long long *current_count[NHM_CSTATE_COUNT];
69/* valid flag for all CPUs. If a MSR read failed it will be zero */
70static int *is_valid;
71
72static int nhm_get_count(enum intel_nhm_id id, unsigned long long *val, unsigned int cpu)
73{
74 int msr;
75
76 switch(id) {
77 case C3:
78 msr = MSR_CORE_C3_RESIDENCY;
79 break;
80 case C6:
81 msr = MSR_CORE_C6_RESIDENCY;
82 break;
83 case PC3:
84 msr = MSR_PKG_C3_RESIDENCY;
85 break;
86 case PC6:
87 msr = MSR_PKG_C6_RESIDENCY;
88 break;
89 case TSC:
90 msr = MSR_TSC;
91 break;
92 default:
93 return -1;
94 };
95 if (read_msr(cpu, msr, val))
96 return -1;
97
98 return 0;
99}
100
101static int nhm_get_count_percent(unsigned int id, double *percent,
102 unsigned int cpu)
103{
104 *percent = 0.0;
105
106 if (!is_valid[cpu])
107 return -1;
108
109 *percent = (100.0 * (current_count[id][cpu] - previous_count[id][cpu])) /
110 (tsc_at_measure_end - tsc_at_measure_start);
111
112 dprint("%s: previous: %llu - current: %llu - (%u)\n", nhm_cstates[id].name,
113 previous_count[id][cpu], current_count[id][cpu],
114 cpu);
115
116 dprint("%s: tsc_diff: %llu - count_diff: %llu - percent: %2.f (%u)\n",
117 nhm_cstates[id].name,
118 (unsigned long long) tsc_at_measure_end - tsc_at_measure_start,
119 current_count[id][cpu] - previous_count[id][cpu],
120 *percent, cpu);
121
122 return 0;
123}
124
125static int nhm_start(void)
126{
127 int num, cpu;
128 unsigned long long dbg, val;
129
130 nhm_get_count(TSC, &tsc_at_measure_start, 0);
131
132 for (num = 0; num < NHM_CSTATE_COUNT; num++) {
133 for (cpu = 0; cpu < cpu_count; cpu++) {
134 is_valid[cpu] = !nhm_get_count(num, &val, cpu);
135 previous_count[num][cpu] = val;
136 }
137 }
138 nhm_get_count(TSC, &dbg, 0);
139 dprint("TSC diff: %llu\n", dbg - tsc_at_measure_start);
140 return 0;
141}
142
143static int nhm_stop(void)
144{
145 unsigned long long val;
146 unsigned long long dbg;
147 int num, cpu;
148
149 nhm_get_count(TSC, &tsc_at_measure_end, 0);
150
151 for (num = 0; num < NHM_CSTATE_COUNT; num++) {
152 for (cpu = 0; cpu < cpu_count; cpu++) {
153 is_valid[cpu] = !nhm_get_count(num, &val, cpu);
154 current_count[num][cpu] = val;
155 }
156 }
157 nhm_get_count(TSC, &dbg, 0);
158 dprint("TSC diff: %llu\n", dbg - tsc_at_measure_end);
159
160 return 0;
161}
162
163struct cpuidle_monitor intel_nhm_monitor;
164
165struct cpuidle_monitor* intel_nhm_register(void) {
166 int num;
167
168 if (cpupower_cpu_info.vendor != X86_VENDOR_INTEL)
169 return NULL;
170
171 if (!(cpupower_cpu_info.caps & CPUPOWER_CAP_INV_TSC))
172 return NULL;
173
174 if (!(cpupower_cpu_info.caps & CPUPOWER_CAP_APERF))
175 return NULL;
176
177 /* Free this at program termination */
178 is_valid = calloc(cpu_count, sizeof (int));
179 for (num = 0; num < NHM_CSTATE_COUNT; num++) {
180 previous_count[num] = calloc (cpu_count,
181 sizeof(unsigned long long));
182 current_count[num] = calloc (cpu_count,
183 sizeof(unsigned long long));
184 }
185
186 intel_nhm_monitor.name_len = strlen(intel_nhm_monitor.name);
187 return &intel_nhm_monitor;
188}
189
190void intel_nhm_unregister(void) {
191 int num;
192
193 for (num = 0; num < NHM_CSTATE_COUNT; num++) {
194 free(previous_count[num]);
195 free(current_count[num]);
196 }
197 free(is_valid);
198}
199
200struct cpuidle_monitor intel_nhm_monitor = {
201 .name = "Nehalem",
202 .hw_states_num = NHM_CSTATE_COUNT,
203 .hw_states = nhm_cstates,
204 .start = nhm_start,
205 .stop = nhm_stop,
206 .do_register = intel_nhm_register,
207 .unregister = intel_nhm_unregister,
208 .needs_root = 1,
209 .overflow_s = 922000000 /* 922337203 seconds TSC overflow
210 at 20GHz */
211};
212#endif
diff --git a/tools/power/cpupower/utils/idle_monitor/snb_idle.c b/tools/power/cpupower/utils/idle_monitor/snb_idle.c
new file mode 100644
index 00000000000..8cc80a5b530
--- /dev/null
+++ b/tools/power/cpupower/utils/idle_monitor/snb_idle.c
@@ -0,0 +1,189 @@
1/*
2 * (C) 2010,2011 Thomas Renninger <trenn@suse.de>, Novell Inc.
3 *
4 * Licensed under the terms of the GNU GPL License version 2.
5 *
6 * Based on Len Brown's <lenb@kernel.org> turbostat tool.
7 */
8
9#if defined(__i386__) || defined(__x86_64__)
10
11#include <stdio.h>
12#include <stdint.h>
13#include <stdlib.h>
14#include <string.h>
15
16#include "helpers/helpers.h"
17#include "idle_monitor/cpupower-monitor.h"
18
19#define MSR_PKG_C2_RESIDENCY 0x60D
20#define MSR_PKG_C7_RESIDENCY 0x3FA
21#define MSR_CORE_C7_RESIDENCY 0x3FE
22
23#define MSR_TSC 0x10
24
25enum intel_snb_id { C7 = 0, PC2, PC7, SNB_CSTATE_COUNT, TSC = 0xFFFF };
26
27static int snb_get_count_percent(unsigned int self_id, double *percent,
28 unsigned int cpu);
29
30static cstate_t snb_cstates[SNB_CSTATE_COUNT] = {
31 {
32 .name = "C7",
33 .desc = N_("Processor Core C7"),
34 .id = C7,
35 .range = RANGE_CORE,
36 .get_count_percent = snb_get_count_percent,
37 },
38 {
39 .name = "PC2",
40 .desc = N_("Processor Package C2"),
41 .id = PC2,
42 .range = RANGE_PACKAGE,
43 .get_count_percent = snb_get_count_percent,
44 },
45 {
46 .name = "PC7",
47 .desc = N_("Processor Package C7"),
48 .id = PC7,
49 .range = RANGE_PACKAGE,
50 .get_count_percent = snb_get_count_percent,
51 },
52};
53
54static unsigned long long tsc_at_measure_start;
55static unsigned long long tsc_at_measure_end;
56static unsigned long long *previous_count[SNB_CSTATE_COUNT];
57static unsigned long long *current_count[SNB_CSTATE_COUNT];
58/* valid flag for all CPUs. If a MSR read failed it will be zero */
59static int *is_valid;
60
61static int snb_get_count(enum intel_snb_id id, unsigned long long *val, unsigned int cpu)
62{
63 int msr;
64
65 switch(id) {
66 case C7:
67 msr = MSR_CORE_C7_RESIDENCY;
68 break;
69 case PC2:
70 msr = MSR_PKG_C2_RESIDENCY;
71 break;
72 case PC7:
73 msr = MSR_PKG_C7_RESIDENCY;
74 break;
75 case TSC:
76 msr = MSR_TSC;
77 break;
78 default:
79 return -1;
80 };
81 if (read_msr(cpu, msr, val))
82 return -1;
83 return 0;
84}
85
86static int snb_get_count_percent(unsigned int id, double *percent,
87 unsigned int cpu)
88{
89 *percent = 0.0;
90
91 if (!is_valid[cpu])
92 return -1;
93
94 *percent = (100.0 * (current_count[id][cpu] - previous_count[id][cpu])) /
95 (tsc_at_measure_end - tsc_at_measure_start);
96
97 dprint("%s: previous: %llu - current: %llu - (%u)\n", snb_cstates[id].name,
98 previous_count[id][cpu], current_count[id][cpu],
99 cpu);
100
101 dprint("%s: tsc_diff: %llu - count_diff: %llu - percent: %2.f (%u)\n",
102 snb_cstates[id].name,
103 (unsigned long long) tsc_at_measure_end - tsc_at_measure_start,
104 current_count[id][cpu]
105 - previous_count[id][cpu],
106 *percent, cpu);
107
108 return 0;
109}
110
111static int snb_start(void)
112{
113 int num, cpu;
114 unsigned long long val;
115
116 for (num = 0; num < SNB_CSTATE_COUNT; num++) {
117 for (cpu = 0; cpu < cpu_count; cpu++) {
118 snb_get_count(num, &val, cpu);
119 previous_count[num][cpu] = val;
120 }
121 }
122 snb_get_count(TSC, &tsc_at_measure_start, 0);
123 return 0;
124}
125
126static int snb_stop(void)
127{
128 unsigned long long val;
129 int num, cpu;
130
131 snb_get_count(TSC, &tsc_at_measure_end, 0);
132
133 for (num = 0; num < SNB_CSTATE_COUNT; num++) {
134 for (cpu = 0; cpu < cpu_count; cpu++) {
135 is_valid[cpu] = !snb_get_count(num, &val, cpu);
136 current_count[num][cpu] = val;
137 }
138 }
139 return 0;
140}
141
142struct cpuidle_monitor intel_snb_monitor;
143
144static struct cpuidle_monitor* snb_register(void) {
145
146 int num;
147
148 if (cpupower_cpu_info.vendor != X86_VENDOR_INTEL
149 || cpupower_cpu_info.family != 6)
150 return NULL;
151
152 if (cpupower_cpu_info.model != 0x2A
153 && cpupower_cpu_info.model != 0x2D)
154 return NULL;
155
156 is_valid = calloc(cpu_count, sizeof (int));
157 for (num = 0; num < SNB_CSTATE_COUNT; num++) {
158 previous_count[num] = calloc (cpu_count,
159 sizeof(unsigned long long));
160 current_count[num] = calloc (cpu_count,
161 sizeof(unsigned long long));
162 }
163 intel_snb_monitor.name_len = strlen(intel_snb_monitor.name);
164 return &intel_snb_monitor;
165}
166
167void snb_unregister(void)
168{
169 int num;
170 free(is_valid);
171 for (num = 0; num < SNB_CSTATE_COUNT; num++) {
172 free(previous_count[num]);
173 free(current_count[num]);
174 }
175}
176
177struct cpuidle_monitor intel_snb_monitor = {
178 .name = "SandyBridge",
179 .hw_states = snb_cstates,
180 .hw_states_num = SNB_CSTATE_COUNT,
181 .start = snb_start,
182 .stop = snb_stop,
183 .do_register = snb_register,
184 .unregister = snb_unregister,
185 .needs_root = 1,
186 .overflow_s = 922000000 /* 922337203 seconds TSC overflow
187 at 20GHz */
188};
189#endif /* defined(__i386__) || defined(__x86_64__) */