1 /*
2 * Copyright 2008, Intel Corporation
3 *
4 * This file is part of PowerTOP
5 *
6 * This program file is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; version 2 of the License.
9 *
10 * This program is distributed in the hope that it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program in a file named COPYING; if not, write to the
17 * Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301 USA
20 *
21 * Authors:
22 * Arjan van de Ven <arjan@linux.intel.com>
23 */
24
25 #include <unistd.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <stdint.h>
30 #include <sys/types.h>
31 #include <dirent.h>
32 #include <ctype.h>
33
34 #include "powertop.h"
35
36 #ifdef __i386
37
38
39 /*
40 * Perform a CPU ID operation; with various registers set
41 */
cpuid(unsigned int * eax,unsigned int * ebx,unsigned int * ecx,unsigned int * edx)42 static void cpuid( unsigned int *eax,
43 unsigned int *ebx,
44 unsigned int *ecx,
45 unsigned int *edx)
46 {
47 /* call the cpuid instruction with the registers as input and output
48 * modification by Dwokfur based on Sam Hocevar's discussion on
49 * how to make Assemly code PIC compatible:
50 * http://sam.zoy.org/blog/2007-04-13-shlib-with-non-pic-code-have-inline-assembly-and-pic-mix-well
51 */
52 __asm__("pushl %%ebx \n\t" /* save %ebx */
53 "cpuid \n\t"
54 "movl %%ebx, %1 \n\t" /* save what cpuid just put in %ebx */
55 "popl %%ebx \n\t" /* restore the old %ebx */
56 : "=a" (*eax),
57 "=r" (*ebx),
58 "=c" (*ecx),
59 "=d" (*edx)
60 : "0" (*eax),
61 "1" (*ebx),
62 "2" (*ecx),
63 "3" (*edx)
64 );
65 }
66
67 #endif
68
69
print_intel_cstates(void)70 void print_intel_cstates(void)
71 {
72 #ifdef __i386__
73
74 int bios_table[8];
75 int bioscount = 0;
76 DIR *cpudir;
77 DIR *dir;
78 struct dirent *entry;
79 FILE *file = NULL;
80 char line[4096];
81 char filename[128], *f;
82 int len, i;
83 unsigned int eax, ebx, ecx, edx;
84
85 memset(bios_table, 0, sizeof(bios_table));
86
87
88 cpudir = opendir("/sys/devices/system/cpu");
89 if (!cpudir)
90 return;
91
92 /* Loop over cpuN entries */
93 while ((entry = readdir(cpudir))) {
94 if (strlen(entry->d_name) < 3)
95 continue;
96
97 if (!isdigit(entry->d_name[3]))
98 continue;
99
100 len = sprintf(filename, "/sys/devices/system/cpu/%s/cpuidle",
101 entry->d_name);
102
103 dir = opendir(filename);
104 if (!dir)
105 return;
106
107 /* For each C-state, there is a stateX directory which
108 * contains a 'usage' and a 'time' (duration) file */
109 while ((entry = readdir(dir))) {
110 if (strlen(entry->d_name) < 3)
111 continue;
112 sprintf(filename + len, "/%s/desc", entry->d_name);
113 file = fopen(filename, "r");
114 if (file) {
115
116 memset(line, 0, 4096);
117 f = fgets(line, 4096, file);
118 fclose(file);
119 if (f == NULL)
120 break;
121
122 f = strstr(line, "MWAIT ");
123 if (f) {
124 f += 6;
125 bios_table[(strtoull(f, NULL, 16)>>4) + 1]++;
126 bioscount++;
127 }
128 }
129 }
130 closedir(dir);
131
132 }
133 closedir(cpudir);
134 if (!bioscount)
135 return;
136
137 eax = 5;
138 ebx = 0; ecx = 0; edx = 0;
139 cpuid(&eax, &ebx, &ecx, &edx);
140 if (!edx || ((ecx&1) == 0))
141 return;
142
143 printf(_("Your CPU supports the following C-states : "));
144 i = 0;
145 while (edx) {
146 if (edx&7)
147 printf("C%i ", i);
148 edx = edx >> 4;
149 i++;
150 }
151 printf("\n");
152 printf(_("Your BIOS reports the following C-states : "));
153 for (i = 0; i < 8; i++)
154 if (bios_table[i])
155 printf("C%i ", i);
156 printf("\n");
157 #endif
158 }
159