Home | History | Annotate | Download | only in src
      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