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 (at) 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 */ 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 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