• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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