diff options
Diffstat (limited to 'tools/power')
92 files changed, 21432 insertions, 0 deletions
diff --git a/tools/power/acpi/Makefile b/tools/power/acpi/Makefile new file mode 100644 index 00000000000..e5a3c4be2a1 --- /dev/null +++ b/tools/power/acpi/Makefile @@ -0,0 +1,156 @@ +# tools/power/acpi/Makefile - ACPI tool Makefile +# +# Copyright (c) 2013, Intel Corporation +#   Author: Lv Zheng <lv.zheng@intel.com> +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; version 2 +# of the License. + +OUTPUT=./ +ifeq ("$(origin O)", "command line") +	OUTPUT := $(O)/ +endif + +ifneq ($(OUTPUT),) +# check that the output directory actually exists +OUTDIR := $(shell cd $(OUTPUT) && /bin/pwd) +$(if $(OUTDIR),, $(error output directory "$(OUTPUT)" does not exist)) +endif + +SUBDIRS = tools/ec + +# --- CONFIGURATION BEGIN --- + +# Set the following to `true' to make a unstripped, unoptimized +# binary. Leave this set to `false' for production use. +DEBUG ?=	true + +# make the build silent. Set this to something else to make it noisy again. +V ?=		false + +# Prefix to the directories we're installing to +DESTDIR ?= + +# --- CONFIGURATION END --- + +# Directory definitions. These are default and most probably +# do not need to be changed. Please note that DESTDIR is +# added in front of any of them + +bindir ?=	/usr/bin +sbindir ?=	/usr/sbin +mandir ?=	/usr/man + +# Toolchain: what tools do we use, and what options do they need: + +INSTALL = /usr/bin/install -c +INSTALL_PROGRAM = ${INSTALL} +INSTALL_DATA  = ${INSTALL} -m 644 +INSTALL_SCRIPT = ${INSTALL_PROGRAM} + +# If you are running a cross compiler, you may want to set this +# to something more interesting, like "arm-linux-".  If you want +# to compile vs uClibc, that can be done here as well. +CROSS = #/usr/i386-linux-uclibc/usr/bin/i386-uclibc- +CC = $(CROSS)gcc +LD = $(CROSS)gcc +STRIP = $(CROSS)strip +HOSTCC = gcc + +# check if compiler option is supported +cc-supports = ${shell if $(CC) ${1} -S -o /dev/null -x c /dev/null > /dev/null 2>&1; then echo "$(1)"; fi;} + +# use '-Os' optimization if available, else use -O2 +OPTIMIZATION := $(call cc-supports,-Os,-O2) + +WARNINGS := -Wall +WARNINGS += $(call cc-supports,-Wstrict-prototypes) +WARNINGS += $(call cc-supports,-Wdeclaration-after-statement) + +KERNEL_INCLUDE := ../../../include +ACPICA_INCLUDE := ../../../drivers/acpi/acpica +CFLAGS += -D_LINUX -I$(KERNEL_INCLUDE) -I$(ACPICA_INCLUDE) +CFLAGS += $(WARNINGS) + +ifeq ($(strip $(V)),false) +	QUIET=@ +	ECHO=@echo +else +	QUIET= +	ECHO=@\# +endif +export QUIET ECHO + +# if DEBUG is enabled, then we do not strip or optimize +ifeq ($(strip $(DEBUG)),true) +	CFLAGS += -O1 -g -DDEBUG +	STRIPCMD = /bin/true -Since_we_are_debugging +else +	CFLAGS += $(OPTIMIZATION) -fomit-frame-pointer +	STRIPCMD = $(STRIP) -s --remove-section=.note --remove-section=.comment +endif + +# --- ACPIDUMP BEGIN --- + +vpath %.c \ +	../../../drivers/acpi/acpica\ +	tools/acpidump\ +	common\ +	os_specific/service_layers + +CFLAGS += -DACPI_DUMP_APP -Itools/acpidump + +DUMP_OBJS = \ +	apdump.o\ +	apfiles.o\ +	apmain.o\ +	osunixdir.o\ +	osunixmap.o\ +	tbprint.o\ +	tbxfroot.o\ +	utbuffer.o\ +	utexcep.o\ +	utmath.o\ +	utstring.o\ +	utxferror.o\ +	oslinuxtbl.o\ +	cmfsize.o\ +	getopt.o + +DUMP_OBJS := $(addprefix $(OUTPUT)tools/acpidump/,$(DUMP_OBJS)) + +$(OUTPUT)acpidump: $(DUMP_OBJS) +	$(ECHO) "  LD      " $@ +	$(QUIET) $(LD) $(CFLAGS) $(LDFLAGS) $(DUMP_OBJS) -L$(OUTPUT) -o $@ +	$(QUIET) $(STRIPCMD) $@ + +$(OUTPUT)tools/acpidump/%.o: %.c +	$(ECHO) "  CC      " $@ +	$(QUIET) $(CC) -c $(CFLAGS) -o $@ $< + +# --- ACPIDUMP END --- + +all: $(OUTPUT)acpidump +	echo $(OUTPUT) + +clean: +	-find $(OUTPUT) \( -not -type d \) -and \( -name '*~' -o -name '*.[oas]' \) -type f -print \ +	 | xargs rm -f +	-rm -f $(OUTPUT)acpidump + +install-tools: +	$(INSTALL) -d $(DESTDIR)${sbindir} +	$(INSTALL_PROGRAM) $(OUTPUT)acpidump $(DESTDIR)${sbindir} + +install-man: +	$(INSTALL_DATA) -D man/acpidump.8 $(DESTDIR)${mandir}/man8/acpidump.8 + +install: all install-tools install-man + +uninstall: +	- rm -f $(DESTDIR)${sbindir}/acpidump +	- rm -f $(DESTDIR)${mandir}/man8/acpidump.8 + +.PHONY: all utils install-tools install-man install uninstall clean diff --git a/tools/power/acpi/common/cmfsize.c b/tools/power/acpi/common/cmfsize.c new file mode 100644 index 00000000000..5140e5edae1 --- /dev/null +++ b/tools/power/acpi/common/cmfsize.c @@ -0,0 +1,101 @@ +/****************************************************************************** + * + * Module Name: cfsize - Common get file size function + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2014, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + *    notice, this list of conditions, and the following disclaimer, + *    without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + *    substantially similar to the "NO WARRANTY" disclaimer below + *    ("Disclaimer") and any redistribution must be conditioned upon + *    including a substantially similar Disclaimer requirement for further + *    binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + *    of any contributors may be used to endorse or promote products derived + *    from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include <acpi/acpi.h> +#include "accommon.h" +#include "acapps.h" +#include <stdio.h> + +#define _COMPONENT          ACPI_TOOLS +ACPI_MODULE_NAME("cmfsize") + +/******************************************************************************* + * + * FUNCTION:    cm_get_file_size + * + * PARAMETERS:  file                    - Open file descriptor + * + * RETURN:      File Size. On error, -1 (ACPI_UINT32_MAX) + * + * DESCRIPTION: Get the size of a file. Uses seek-to-EOF. File must be open. + *              Does not disturb the current file pointer. Uses perror for + *              error messages. + * + ******************************************************************************/ +u32 cm_get_file_size(FILE * file) +{ +	long file_size; +	long current_offset; + +	/* Save the current file pointer, seek to EOF to obtain file size */ + +	current_offset = ftell(file); +	if (current_offset < 0) { +		goto offset_error; +	} + +	if (fseek(file, 0, SEEK_END)) { +		goto seek_error; +	} + +	file_size = ftell(file); +	if (file_size < 0) { +		goto offset_error; +	} + +	/* Restore original file pointer */ + +	if (fseek(file, current_offset, SEEK_SET)) { +		goto seek_error; +	} + +	return ((u32)file_size); + +offset_error: +	perror("Could not get file offset"); +	return (ACPI_UINT32_MAX); + +seek_error: +	perror("Could not seek file"); +	return (ACPI_UINT32_MAX); +} diff --git a/tools/power/acpi/common/getopt.c b/tools/power/acpi/common/getopt.c new file mode 100644 index 00000000000..a302f52e4fd --- /dev/null +++ b/tools/power/acpi/common/getopt.c @@ -0,0 +1,239 @@ +/****************************************************************************** + * + * Module Name: getopt + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2014, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + *    notice, this list of conditions, and the following disclaimer, + *    without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + *    substantially similar to the "NO WARRANTY" disclaimer below + *    ("Disclaimer") and any redistribution must be conditioned upon + *    including a substantially similar Disclaimer requirement for further + *    binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + *    of any contributors may be used to endorse or promote products derived + *    from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +/* + * ACPICA getopt() implementation + * + * Option strings: + *    "f"       - Option has no arguments + *    "f:"      - Option requires an argument + *    "f^"      - Option has optional single-char sub-options + *    "f|"      - Option has required single-char sub-options + */ + +#include <stdio.h> +#include <string.h> +#include <acpi/acpi.h> +#include "accommon.h" +#include "acapps.h" + +#define ACPI_OPTION_ERROR(msg, badchar) \ +	if (acpi_gbl_opterr) {fprintf (stderr, "%s%c\n", msg, badchar);} + +int acpi_gbl_opterr = 1; +int acpi_gbl_optind = 1; +int acpi_gbl_sub_opt_char = 0; +char *acpi_gbl_optarg; + +static int current_char_ptr = 1; + +/******************************************************************************* + * + * FUNCTION:    acpi_getopt_argument + * + * PARAMETERS:  argc, argv          - from main + * + * RETURN:      0 if an argument was found, -1 otherwise. Sets acpi_gbl_Optarg + *              to point to the next argument. + * + * DESCRIPTION: Get the next argument. Used to obtain arguments for the + *              two-character options after the original call to acpi_getopt. + *              Note: Either the argument starts at the next character after + *              the option, or it is pointed to by the next argv entry. + *              (After call to acpi_getopt, we need to backup to the previous + *              argv entry). + * + ******************************************************************************/ + +int acpi_getopt_argument(int argc, char **argv) +{ +	acpi_gbl_optind--; +	current_char_ptr++; + +	if (argv[acpi_gbl_optind][(int)(current_char_ptr + 1)] != '\0') { +		acpi_gbl_optarg = +		    &argv[acpi_gbl_optind++][(int)(current_char_ptr + 1)]; +	} else if (++acpi_gbl_optind >= argc) { +		ACPI_OPTION_ERROR("Option requires an argument: -", 'v'); + +		current_char_ptr = 1; +		return (-1); +	} else { +		acpi_gbl_optarg = argv[acpi_gbl_optind++]; +	} + +	current_char_ptr = 1; +	return (0); +} + +/******************************************************************************* + * + * FUNCTION:    acpi_getopt + * + * PARAMETERS:  argc, argv          - from main + *              opts                - options info list + * + * RETURN:      Option character or EOF + * + * DESCRIPTION: Get the next option + * + ******************************************************************************/ + +int acpi_getopt(int argc, char **argv, char *opts) +{ +	int current_char; +	char *opts_ptr; + +	if (current_char_ptr == 1) { +		if (acpi_gbl_optind >= argc || +		    argv[acpi_gbl_optind][0] != '-' || +		    argv[acpi_gbl_optind][1] == '\0') { +			return (EOF); +		} else if (strcmp(argv[acpi_gbl_optind], "--") == 0) { +			acpi_gbl_optind++; +			return (EOF); +		} +	} + +	/* Get the option */ + +	current_char = argv[acpi_gbl_optind][current_char_ptr]; + +	/* Make sure that the option is legal */ + +	if (current_char == ':' || +	    (opts_ptr = strchr(opts, current_char)) == NULL) { +		ACPI_OPTION_ERROR("Illegal option: -", current_char); + +		if (argv[acpi_gbl_optind][++current_char_ptr] == '\0') { +			acpi_gbl_optind++; +			current_char_ptr = 1; +		} + +		return ('?'); +	} + +	/* Option requires an argument? */ + +	if (*++opts_ptr == ':') { +		if (argv[acpi_gbl_optind][(int)(current_char_ptr + 1)] != '\0') { +			acpi_gbl_optarg = +			    &argv[acpi_gbl_optind++][(int) +						     (current_char_ptr + 1)]; +		} else if (++acpi_gbl_optind >= argc) { +			ACPI_OPTION_ERROR("Option requires an argument: -", +					  current_char); + +			current_char_ptr = 1; +			return ('?'); +		} else { +			acpi_gbl_optarg = argv[acpi_gbl_optind++]; +		} + +		current_char_ptr = 1; +	} + +	/* Option has an optional argument? */ + +	else if (*opts_ptr == '+') { +		if (argv[acpi_gbl_optind][(int)(current_char_ptr + 1)] != '\0') { +			acpi_gbl_optarg = +			    &argv[acpi_gbl_optind++][(int) +						     (current_char_ptr + 1)]; +		} else if (++acpi_gbl_optind >= argc) { +			acpi_gbl_optarg = NULL; +		} else { +			acpi_gbl_optarg = argv[acpi_gbl_optind++]; +		} + +		current_char_ptr = 1; +	} + +	/* Option has optional single-char arguments? */ + +	else if (*opts_ptr == '^') { +		if (argv[acpi_gbl_optind][(int)(current_char_ptr + 1)] != '\0') { +			acpi_gbl_optarg = +			    &argv[acpi_gbl_optind][(int)(current_char_ptr + 1)]; +		} else { +			acpi_gbl_optarg = "^"; +		} + +		acpi_gbl_sub_opt_char = acpi_gbl_optarg[0]; +		acpi_gbl_optind++; +		current_char_ptr = 1; +	} + +	/* Option has a required single-char argument? */ + +	else if (*opts_ptr == '|') { +		if (argv[acpi_gbl_optind][(int)(current_char_ptr + 1)] != '\0') { +			acpi_gbl_optarg = +			    &argv[acpi_gbl_optind][(int)(current_char_ptr + 1)]; +		} else { +			ACPI_OPTION_ERROR +			    ("Option requires a single-character suboption: -", +			     current_char); + +			current_char_ptr = 1; +			return ('?'); +		} + +		acpi_gbl_sub_opt_char = acpi_gbl_optarg[0]; +		acpi_gbl_optind++; +		current_char_ptr = 1; +	} + +	/* Option with no arguments */ + +	else { +		if (argv[acpi_gbl_optind][++current_char_ptr] == '\0') { +			current_char_ptr = 1; +			acpi_gbl_optind++; +		} + +		acpi_gbl_optarg = NULL; +	} + +	return (current_char); +} diff --git a/tools/power/acpi/man/acpidump.8 b/tools/power/acpi/man/acpidump.8 new file mode 100644 index 00000000000..38f095d86b5 --- /dev/null +++ b/tools/power/acpi/man/acpidump.8 @@ -0,0 +1,120 @@ +.TH ACPIDUMP 8 +.SH NAME +acpidump \- dump a system's ACPI tables to an ASCII file + +.SH SYNOPSIS +.B acpidump +.RI [ options ] +.br + +.SH DESCRIPTION +.B acpidump +dumps the systems ACPI tables to an ASCII file appropriate for +attaching to a bug report. + +Subsequently, they can be processed by utilities in the ACPICA package. + +.SH OPTIONS +acpidump options are as follow: +.TP +.B Options +.TP +.B \-b +Dump tables to binary files +.TP +.B \-c +Dump customized tables +.TP +.B \-h \-? +This help message +.TP +.B \-o <File> +Redirect output to file +.TP +.B \-r <Address> +Dump tables from specified RSDP +.TP +.B \-s +Print table summaries only +.TP +.B \-v +Display version information +.TP +.B \-z +Verbose mode +.TP +.B Table Options +.TP +.B \-a <Address> +Get table via a physical address +.TP +.B \-f <BinaryFile> +Get table via a binary file +.TP +.B \-n <Signature> +Get table via a name/signature +.TP +Invocation without parameters dumps all available tables +.TP +Multiple mixed instances of -a, -f, and -n are supported + +.SH EXAMPLES + +.nf +# acpidump > acpidump.out + +$ acpixtract -a acpidump.out +        Acpi table [DSDT] -  15974 bytes written to DSDT.dat +        Acpi table [FACS] -     64 bytes written to FACS.dat +        Acpi table [FACP] -    116 bytes written to FACP.dat +        Acpi table [APIC] -    120 bytes written to APIC.dat +        Acpi table [MCFG] -     60 bytes written to MCFG.dat +        Acpi table [SSDT] -    444 bytes written to SSDT1.dat +        Acpi table [SSDT] -    439 bytes written to SSDT2.dat +        Acpi table [SSDT] -    439 bytes written to SSDT3.dat +        Acpi table [SSDT] -    439 bytes written to SSDT4.dat +        Acpi table [SSDT] -    439 bytes written to SSDT5.dat +        Acpi table [RSDT] -     76 bytes written to RSDT.dat +        Acpi table [RSDP] -     20 bytes written to RSDP.dat + +$ iasl -d *.dat +... +.fi +creates *.dsl, a human readable form which can be edited +and compiled using iasl. + + +.SH NOTES + +.B "acpidump " +must be run as root. + +.SH REFERENCES +ACPICA: https://acpica.org/ + +.SH FILES +.ta +.nf +/dev/mem +/sys/firmware/acpi/tables/* +/sys/firmware/acpi/tables/dynamic/* +/sys/firmware/efi/systab +.fi + +.SH AUTHOR +.TP +Original by: + Len Brown <len.brown@intel.com> +.TP +Written by: + Chao Guan <chao.guan@intel.com> +.TP +Updated by: + Bob Moore <robert.moore@intel.com> + Lv Zheng <lv.zheng@intel.com> + +.SH SEE ALSO +\&\fIacpixtract\fR\|(8), \fIiasl\fR\|(8). + +.SH COPYRIGHT +COPYRIGHT (c) 2013, Intel Corporation. diff --git a/tools/power/acpi/os_specific/service_layers/oslinuxtbl.c b/tools/power/acpi/os_specific/service_layers/oslinuxtbl.c new file mode 100644 index 00000000000..28c52008e85 --- /dev/null +++ b/tools/power/acpi/os_specific/service_layers/oslinuxtbl.c @@ -0,0 +1,1329 @@ +/****************************************************************************** + * + * Module Name: oslinuxtbl - Linux OSL for obtaining ACPI tables + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2014, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + *    notice, this list of conditions, and the following disclaimer, + *    without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + *    substantially similar to the "NO WARRANTY" disclaimer below + *    ("Disclaimer") and any redistribution must be conditioned upon + *    including a substantially similar Disclaimer requirement for further + *    binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + *    of any contributors may be used to endorse or promote products derived + *    from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpidump.h" + +#define _COMPONENT          ACPI_OS_SERVICES +ACPI_MODULE_NAME("oslinuxtbl") + +#ifndef PATH_MAX +#define PATH_MAX 256 +#endif +/* List of information about obtained ACPI tables */ +typedef struct osl_table_info { +	struct osl_table_info *next; +	u32 instance; +	char signature[ACPI_NAME_SIZE]; + +} osl_table_info; + +/* Local prototypes */ + +static acpi_status osl_table_initialize(void); + +static acpi_status +osl_table_name_from_file(char *filename, char *signature, u32 *instance); + +static acpi_status osl_add_table_to_list(char *signature, u32 instance); + +static acpi_status +osl_read_table_from_file(char *filename, +			 acpi_size file_offset, +			 char *signature, struct acpi_table_header **table); + +static acpi_status +osl_map_table(acpi_size address, +	      char *signature, struct acpi_table_header **table); + +static void osl_unmap_table(struct acpi_table_header *table); + +static acpi_physical_address osl_find_rsdp_via_efi(void); + +static acpi_status osl_load_rsdp(void); + +static acpi_status osl_list_customized_tables(char *directory); + +static acpi_status +osl_get_customized_table(char *pathname, +			 char *signature, +			 u32 instance, +			 struct acpi_table_header **table, +			 acpi_physical_address * address); + +static acpi_status osl_list_bios_tables(void); + +static acpi_status +osl_get_bios_table(char *signature, +		   u32 instance, +		   struct acpi_table_header **table, +		   acpi_physical_address * address); + +static acpi_status osl_get_last_status(acpi_status default_status); + +/* File locations */ + +#define DYNAMIC_TABLE_DIR   "/sys/firmware/acpi/tables/dynamic" +#define STATIC_TABLE_DIR    "/sys/firmware/acpi/tables" +#define EFI_SYSTAB          "/sys/firmware/efi/systab" + +/* Should we get dynamically loaded SSDTs from DYNAMIC_TABLE_DIR? */ + +u8 gbl_dump_dynamic_tables = TRUE; + +/* Initialization flags */ + +u8 gbl_table_list_initialized = FALSE; + +/* Local copies of main ACPI tables */ + +struct acpi_table_rsdp gbl_rsdp; +struct acpi_table_fadt *gbl_fadt = NULL; +struct acpi_table_rsdt *gbl_rsdt = NULL; +struct acpi_table_xsdt *gbl_xsdt = NULL; + +/* Table addresses */ + +acpi_physical_address gbl_fadt_address = 0; +acpi_physical_address gbl_rsdp_address = 0; + +/* Revision of RSD PTR */ + +u8 gbl_revision = 0; + +struct osl_table_info *gbl_table_list_head = NULL; +u32 gbl_table_count = 0; + +/****************************************************************************** + * + * FUNCTION:    osl_get_last_status + * + * PARAMETERS:  default_status  - Default error status to return + * + * RETURN:      Status; Converted from errno. + * + * DESCRIPTION: Get last errno and conver it to acpi_status. + * + *****************************************************************************/ + +static acpi_status osl_get_last_status(acpi_status default_status) +{ + +	switch (errno) { +	case EACCES: +	case EPERM: + +		return (AE_ACCESS); + +	case ENOENT: + +		return (AE_NOT_FOUND); + +	case ENOMEM: + +		return (AE_NO_MEMORY); + +	default: + +		return (default_status); +	} +} + +/****************************************************************************** + * + * FUNCTION:    acpi_os_get_table_by_address + * + * PARAMETERS:  address         - Physical address of the ACPI table + *              table           - Where a pointer to the table is returned + * + * RETURN:      Status; Table buffer is returned if AE_OK. + *              AE_NOT_FOUND: A valid table was not found at the address + * + * DESCRIPTION: Get an ACPI table via a physical memory address. + * + *****************************************************************************/ + +acpi_status +acpi_os_get_table_by_address(acpi_physical_address address, +			     struct acpi_table_header ** table) +{ +	u32 table_length; +	struct acpi_table_header *mapped_table; +	struct acpi_table_header *local_table = NULL; +	acpi_status status = AE_OK; + +	/* Get main ACPI tables from memory on first invocation of this function */ + +	status = osl_table_initialize(); +	if (ACPI_FAILURE(status)) { +		return (status); +	} + +	/* Map the table and validate it */ + +	status = osl_map_table(address, NULL, &mapped_table); +	if (ACPI_FAILURE(status)) { +		return (status); +	} + +	/* Copy table to local buffer and return it */ + +	table_length = ap_get_table_length(mapped_table); +	if (table_length == 0) { +		status = AE_BAD_HEADER; +		goto exit; +	} + +	local_table = calloc(1, table_length); +	if (!local_table) { +		status = AE_NO_MEMORY; +		goto exit; +	} + +	ACPI_MEMCPY(local_table, mapped_table, table_length); + +exit: +	osl_unmap_table(mapped_table); +	*table = local_table; +	return (status); +} + +/****************************************************************************** + * + * FUNCTION:    acpi_os_get_table_by_name + * + * PARAMETERS:  signature       - ACPI Signature for desired table. Must be + *                                a null terminated 4-character string. + *              instance        - Multiple table support for SSDT/UEFI (0...n) + *                                Must be 0 for other tables. + *              table           - Where a pointer to the table is returned + *              address         - Where the table physical address is returned + * + * RETURN:      Status; Table buffer and physical address returned if AE_OK. + *              AE_LIMIT: Instance is beyond valid limit + *              AE_NOT_FOUND: A table with the signature was not found + * + * NOTE:        Assumes the input signature is uppercase. + * + *****************************************************************************/ + +acpi_status +acpi_os_get_table_by_name(char *signature, +			  u32 instance, +			  struct acpi_table_header ** table, +			  acpi_physical_address * address) +{ +	acpi_status status; + +	/* Get main ACPI tables from memory on first invocation of this function */ + +	status = osl_table_initialize(); +	if (ACPI_FAILURE(status)) { +		return (status); +	} + +	/* Not a main ACPI table, attempt to extract it from the RSDT/XSDT */ + +	if (!gbl_dump_customized_tables) { + +		/* Attempt to get the table from the memory */ + +		status = +		    osl_get_bios_table(signature, instance, table, address); +	} else { +		/* Attempt to get the table from the static directory */ + +		status = osl_get_customized_table(STATIC_TABLE_DIR, signature, +						  instance, table, address); +	} + +	if (ACPI_FAILURE(status) && status == AE_LIMIT) { +		if (gbl_dump_dynamic_tables) { + +			/* Attempt to get a dynamic table */ + +			status = +			    osl_get_customized_table(DYNAMIC_TABLE_DIR, +						     signature, instance, table, +						     address); +		} +	} + +	return (status); +} + +/****************************************************************************** + * + * FUNCTION:    osl_add_table_to_list + * + * PARAMETERS:  signature       - Table signature + *              instance        - Table instance + * + * RETURN:      Status; Successfully added if AE_OK. + *              AE_NO_MEMORY: Memory allocation error + * + * DESCRIPTION: Insert a table structure into OSL table list. + * + *****************************************************************************/ + +static acpi_status osl_add_table_to_list(char *signature, u32 instance) +{ +	struct osl_table_info *new_info; +	struct osl_table_info *next; +	u32 next_instance = 0; +	u8 found = FALSE; + +	new_info = calloc(1, sizeof(struct osl_table_info)); +	if (!new_info) { +		return (AE_NO_MEMORY); +	} + +	ACPI_MOVE_NAME(new_info->signature, signature); + +	if (!gbl_table_list_head) { +		gbl_table_list_head = new_info; +	} else { +		next = gbl_table_list_head; +		while (1) { +			if (ACPI_COMPARE_NAME(next->signature, signature)) { +				if (next->instance == instance) { +					found = TRUE; +				} +				if (next->instance >= next_instance) { +					next_instance = next->instance + 1; +				} +			} + +			if (!next->next) { +				break; +			} +			next = next->next; +		} +		next->next = new_info; +	} + +	if (found) { +		if (instance) { +			fprintf(stderr, +				"%4.4s: Warning unmatched table instance %d, expected %d\n", +				signature, instance, next_instance); +		} +		instance = next_instance; +	} + +	new_info->instance = instance; +	gbl_table_count++; + +	return (AE_OK); +} + +/****************************************************************************** + * + * FUNCTION:    acpi_os_get_table_by_index + * + * PARAMETERS:  index           - Which table to get + *              table           - Where a pointer to the table is returned + *              instance        - Where a pointer to the table instance no. is + *                                returned + *              address         - Where the table physical address is returned + * + * RETURN:      Status; Table buffer and physical address returned if AE_OK. + *              AE_LIMIT: Index is beyond valid limit + * + * DESCRIPTION: Get an ACPI table via an index value (0 through n). Returns + *              AE_LIMIT when an invalid index is reached. Index is not + *              necessarily an index into the RSDT/XSDT. + * + *****************************************************************************/ + +acpi_status +acpi_os_get_table_by_index(u32 index, +			   struct acpi_table_header ** table, +			   u32 *instance, acpi_physical_address * address) +{ +	struct osl_table_info *info; +	acpi_status status; +	u32 i; + +	/* Get main ACPI tables from memory on first invocation of this function */ + +	status = osl_table_initialize(); +	if (ACPI_FAILURE(status)) { +		return (status); +	} + +	/* Validate Index */ + +	if (index >= gbl_table_count) { +		return (AE_LIMIT); +	} + +	/* Point to the table list entry specified by the Index argument */ + +	info = gbl_table_list_head; +	for (i = 0; i < index; i++) { +		info = info->next; +	} + +	/* Now we can just get the table via the signature */ + +	status = acpi_os_get_table_by_name(info->signature, info->instance, +					   table, address); + +	if (ACPI_SUCCESS(status)) { +		*instance = info->instance; +	} +	return (status); +} + +/****************************************************************************** + * + * FUNCTION:    osl_find_rsdp_via_efi + * + * PARAMETERS:  None + * + * RETURN:      RSDP address if found + * + * DESCRIPTION: Find RSDP address via EFI. + * + *****************************************************************************/ + +static acpi_physical_address osl_find_rsdp_via_efi(void) +{ +	FILE *file; +	char buffer[80]; +	unsigned long address = 0; + +	file = fopen(EFI_SYSTAB, "r"); +	if (file) { +		while (fgets(buffer, 80, file)) { +			if (sscanf(buffer, "ACPI20=0x%lx", &address) == 1) { +				break; +			} +		} +		fclose(file); +	} + +	return ((acpi_physical_address) (address)); +} + +/****************************************************************************** + * + * FUNCTION:    osl_load_rsdp + * + * PARAMETERS:  None + * + * RETURN:      Status + * + * DESCRIPTION: Scan and load RSDP. + * + *****************************************************************************/ + +static acpi_status osl_load_rsdp(void) +{ +	struct acpi_table_header *mapped_table; +	u8 *rsdp_address; +	acpi_physical_address rsdp_base; +	acpi_size rsdp_size; + +	/* Get RSDP from memory */ + +	rsdp_size = sizeof(struct acpi_table_rsdp); +	if (gbl_rsdp_base) { +		rsdp_base = gbl_rsdp_base; +	} else { +		rsdp_base = osl_find_rsdp_via_efi(); +	} + +	if (!rsdp_base) { +		rsdp_base = ACPI_HI_RSDP_WINDOW_BASE; +		rsdp_size = ACPI_HI_RSDP_WINDOW_SIZE; +	} + +	rsdp_address = acpi_os_map_memory(rsdp_base, rsdp_size); +	if (!rsdp_address) { +		return (osl_get_last_status(AE_BAD_ADDRESS)); +	} + +	/* Search low memory for the RSDP */ + +	mapped_table = ACPI_CAST_PTR(struct acpi_table_header, +				     acpi_tb_scan_memory_for_rsdp(rsdp_address, +								  rsdp_size)); +	if (!mapped_table) { +		acpi_os_unmap_memory(rsdp_address, rsdp_size); +		return (AE_NOT_FOUND); +	} + +	gbl_rsdp_address = +	    rsdp_base + (ACPI_CAST8(mapped_table) - rsdp_address); + +	ACPI_MEMCPY(&gbl_rsdp, mapped_table, sizeof(struct acpi_table_rsdp)); +	acpi_os_unmap_memory(rsdp_address, rsdp_size); + +	return (AE_OK); +} + +/****************************************************************************** + * + * FUNCTION:    osl_can_use_xsdt + * + * PARAMETERS:  None + * + * RETURN:      TRUE if XSDT is allowed to be used. + * + * DESCRIPTION: This function collects logic that can be used to determine if + *              XSDT should be used instead of RSDT. + * + *****************************************************************************/ + +static u8 osl_can_use_xsdt(void) +{ +	if (gbl_revision && !acpi_gbl_do_not_use_xsdt) { +		return (TRUE); +	} else { +		return (FALSE); +	} +} + +/****************************************************************************** + * + * FUNCTION:    osl_table_initialize + * + * PARAMETERS:  None + * + * RETURN:      Status + * + * DESCRIPTION: Initialize ACPI table data. Get and store main ACPI tables to + *              local variables. Main ACPI tables include RSDT, FADT, RSDT, + *              and/or XSDT. + * + *****************************************************************************/ + +static acpi_status osl_table_initialize(void) +{ +	acpi_status status; +	acpi_physical_address address; + +	if (gbl_table_list_initialized) { +		return (AE_OK); +	} + +	/* Get RSDP from memory */ + +	status = osl_load_rsdp(); +	if (ACPI_FAILURE(status)) { +		return (status); +	} + +	/* Get XSDT from memory */ + +	if (gbl_rsdp.revision && !gbl_do_not_dump_xsdt) { +		if (gbl_xsdt) { +			free(gbl_xsdt); +			gbl_xsdt = NULL; +		} + +		gbl_revision = 2; +		status = osl_get_bios_table(ACPI_SIG_XSDT, 0, +					    ACPI_CAST_PTR(struct +							  acpi_table_header *, +							  &gbl_xsdt), &address); +		if (ACPI_FAILURE(status)) { +			return (status); +		} +	} + +	/* Get RSDT from memory */ + +	if (gbl_rsdp.rsdt_physical_address) { +		if (gbl_rsdt) { +			free(gbl_rsdt); +			gbl_rsdt = NULL; +		} + +		status = osl_get_bios_table(ACPI_SIG_RSDT, 0, +					    ACPI_CAST_PTR(struct +							  acpi_table_header *, +							  &gbl_rsdt), &address); +		if (ACPI_FAILURE(status)) { +			return (status); +		} +	} + +	/* Get FADT from memory */ + +	if (gbl_fadt) { +		free(gbl_fadt); +		gbl_fadt = NULL; +	} + +	status = osl_get_bios_table(ACPI_SIG_FADT, 0, +				    ACPI_CAST_PTR(struct acpi_table_header *, +						  &gbl_fadt), +				    &gbl_fadt_address); +	if (ACPI_FAILURE(status)) { +		return (status); +	} + +	if (!gbl_dump_customized_tables) { + +		/* Add mandatory tables to global table list first */ + +		status = osl_add_table_to_list(ACPI_RSDP_NAME, 0); +		if (ACPI_FAILURE(status)) { +			return (status); +		} + +		status = osl_add_table_to_list(ACPI_SIG_RSDT, 0); +		if (ACPI_FAILURE(status)) { +			return (status); +		} + +		if (gbl_revision == 2) { +			status = osl_add_table_to_list(ACPI_SIG_XSDT, 0); +			if (ACPI_FAILURE(status)) { +				return (status); +			} +		} + +		status = osl_add_table_to_list(ACPI_SIG_DSDT, 0); +		if (ACPI_FAILURE(status)) { +			return (status); +		} + +		status = osl_add_table_to_list(ACPI_SIG_FACS, 0); +		if (ACPI_FAILURE(status)) { +			return (status); +		} + +		/* Add all tables found in the memory */ + +		status = osl_list_bios_tables(); +		if (ACPI_FAILURE(status)) { +			return (status); +		} +	} else { +		/* Add all tables found in the static directory */ + +		status = osl_list_customized_tables(STATIC_TABLE_DIR); +		if (ACPI_FAILURE(status)) { +			return (status); +		} +	} + +	if (gbl_dump_dynamic_tables) { + +		/* Add all dynamically loaded tables in the dynamic directory */ + +		status = osl_list_customized_tables(DYNAMIC_TABLE_DIR); +		if (ACPI_FAILURE(status)) { +			return (status); +		} +	} + +	gbl_table_list_initialized = TRUE; +	return (AE_OK); +} + +/****************************************************************************** + * + * FUNCTION:    osl_list_bios_tables + * + * PARAMETERS:  None + * + * RETURN:      Status; Table list is initialized if AE_OK. + * + * DESCRIPTION: Add ACPI tables to the table list from memory. + * + * NOTE:        This works on Linux as table customization does not modify the + *              addresses stored in RSDP/RSDT/XSDT/FADT. + * + *****************************************************************************/ + +static acpi_status osl_list_bios_tables(void) +{ +	struct acpi_table_header *mapped_table = NULL; +	u8 *table_data; +	u8 number_of_tables; +	u8 item_size; +	acpi_physical_address table_address = 0; +	acpi_status status = AE_OK; +	u32 i; + +	if (osl_can_use_xsdt()) { +		item_size = sizeof(u64); +		table_data = +		    ACPI_CAST8(gbl_xsdt) + sizeof(struct acpi_table_header); +		number_of_tables = +		    (u8)((gbl_xsdt->header.length - +			  sizeof(struct acpi_table_header)) +			 / item_size); +	} else {		/* Use RSDT if XSDT is not available */ + +		item_size = sizeof(u32); +		table_data = +		    ACPI_CAST8(gbl_rsdt) + sizeof(struct acpi_table_header); +		number_of_tables = +		    (u8)((gbl_rsdt->header.length - +			  sizeof(struct acpi_table_header)) +			 / item_size); +	} + +	/* Search RSDT/XSDT for the requested table */ + +	for (i = 0; i < number_of_tables; ++i, table_data += item_size) { +		if (osl_can_use_xsdt()) { +			table_address = +			    (acpi_physical_address) (*ACPI_CAST64(table_data)); +		} else { +			table_address = +			    (acpi_physical_address) (*ACPI_CAST32(table_data)); +		} + +		/* Skip NULL entries in RSDT/XSDT */ + +		if (!table_address) { +			continue; +		} + +		status = osl_map_table(table_address, NULL, &mapped_table); +		if (ACPI_FAILURE(status)) { +			return (status); +		} + +		osl_add_table_to_list(mapped_table->signature, 0); +		osl_unmap_table(mapped_table); +	} + +	return (AE_OK); +} + +/****************************************************************************** + * + * FUNCTION:    osl_get_bios_table + * + * PARAMETERS:  signature       - ACPI Signature for common table. Must be + *                                a null terminated 4-character string. + *              instance        - Multiple table support for SSDT/UEFI (0...n) + *                                Must be 0 for other tables. + *              table           - Where a pointer to the table is returned + *              address         - Where the table physical address is returned + * + * RETURN:      Status; Table buffer and physical address returned if AE_OK. + *              AE_LIMIT: Instance is beyond valid limit + *              AE_NOT_FOUND: A table with the signature was not found + * + * DESCRIPTION: Get a BIOS provided ACPI table + * + * NOTE:        Assumes the input signature is uppercase. + * + *****************************************************************************/ + +static acpi_status +osl_get_bios_table(char *signature, +		   u32 instance, +		   struct acpi_table_header **table, +		   acpi_physical_address * address) +{ +	struct acpi_table_header *local_table = NULL; +	struct acpi_table_header *mapped_table = NULL; +	u8 *table_data; +	u8 number_of_tables; +	u8 item_size; +	u32 current_instance = 0; +	acpi_physical_address table_address = 0; +	u32 table_length = 0; +	acpi_status status = AE_OK; +	u32 i; + +	/* Handle special tables whose addresses are not in RSDT/XSDT */ + +	if (ACPI_COMPARE_NAME(signature, ACPI_RSDP_NAME) || +	    ACPI_COMPARE_NAME(signature, ACPI_SIG_RSDT) || +	    ACPI_COMPARE_NAME(signature, ACPI_SIG_XSDT) || +	    ACPI_COMPARE_NAME(signature, ACPI_SIG_DSDT) || +	    ACPI_COMPARE_NAME(signature, ACPI_SIG_FACS)) { +		if (instance > 0) { +			return (AE_LIMIT); +		} + +		/* +		 * Get the appropriate address, either 32-bit or 64-bit. Be very +		 * careful about the FADT length and validate table addresses. +		 * Note: The 64-bit addresses have priority. +		 */ +		if (ACPI_COMPARE_NAME(signature, ACPI_SIG_DSDT)) { +			if ((gbl_fadt->header.length >= MIN_FADT_FOR_XDSDT) && +			    gbl_fadt->Xdsdt) { +				table_address = +				    (acpi_physical_address) gbl_fadt->Xdsdt; +			} else +			    if ((gbl_fadt->header.length >= MIN_FADT_FOR_DSDT) +				&& gbl_fadt->dsdt) { +				table_address = +				    (acpi_physical_address) gbl_fadt->dsdt; +			} +		} else if (ACPI_COMPARE_NAME(signature, ACPI_SIG_FACS)) { +			if ((gbl_fadt->header.length >= MIN_FADT_FOR_XFACS) && +			    gbl_fadt->Xfacs) { +				table_address = +				    (acpi_physical_address) gbl_fadt->Xfacs; +			} else +			    if ((gbl_fadt->header.length >= MIN_FADT_FOR_FACS) +				&& gbl_fadt->facs) { +				table_address = +				    (acpi_physical_address) gbl_fadt->facs; +			} +		} else if (ACPI_COMPARE_NAME(signature, ACPI_SIG_XSDT)) { +			if (!gbl_revision) { +				return (AE_BAD_SIGNATURE); +			} +			table_address = +			    (acpi_physical_address) gbl_rsdp. +			    xsdt_physical_address; +		} else if (ACPI_COMPARE_NAME(signature, ACPI_SIG_RSDT)) { +			table_address = +			    (acpi_physical_address) gbl_rsdp. +			    rsdt_physical_address; +		} else { +			table_address = +			    (acpi_physical_address) gbl_rsdp_address; +			signature = ACPI_SIG_RSDP; +		} + +		/* Now we can get the requested special table */ + +		status = osl_map_table(table_address, signature, &mapped_table); +		if (ACPI_FAILURE(status)) { +			return (status); +		} + +		table_length = ap_get_table_length(mapped_table); +	} else {		/* Case for a normal ACPI table */ + +		if (osl_can_use_xsdt()) { +			item_size = sizeof(u64); +			table_data = +			    ACPI_CAST8(gbl_xsdt) + +			    sizeof(struct acpi_table_header); +			number_of_tables = +			    (u8)((gbl_xsdt->header.length - +				  sizeof(struct acpi_table_header)) +				 / item_size); +		} else {	/* Use RSDT if XSDT is not available */ + +			item_size = sizeof(u32); +			table_data = +			    ACPI_CAST8(gbl_rsdt) + +			    sizeof(struct acpi_table_header); +			number_of_tables = +			    (u8)((gbl_rsdt->header.length - +				  sizeof(struct acpi_table_header)) +				 / item_size); +		} + +		/* Search RSDT/XSDT for the requested table */ + +		for (i = 0; i < number_of_tables; ++i, table_data += item_size) { +			if (osl_can_use_xsdt()) { +				table_address = +				    (acpi_physical_address) (*ACPI_CAST64 +							     (table_data)); +			} else { +				table_address = +				    (acpi_physical_address) (*ACPI_CAST32 +							     (table_data)); +			} + +			/* Skip NULL entries in RSDT/XSDT */ + +			if (!table_address) { +				continue; +			} + +			status = +			    osl_map_table(table_address, NULL, &mapped_table); +			if (ACPI_FAILURE(status)) { +				return (status); +			} +			table_length = mapped_table->length; + +			/* Does this table match the requested signature? */ + +			if (!ACPI_COMPARE_NAME +			    (mapped_table->signature, signature)) { +				osl_unmap_table(mapped_table); +				mapped_table = NULL; +				continue; +			} + +			/* Match table instance (for SSDT/UEFI tables) */ + +			if (current_instance != instance) { +				osl_unmap_table(mapped_table); +				mapped_table = NULL; +				current_instance++; +				continue; +			} + +			break; +		} +	} + +	if (!mapped_table) { +		return (AE_LIMIT); +	} + +	if (table_length == 0) { +		status = AE_BAD_HEADER; +		goto exit; +	} + +	/* Copy table to local buffer and return it */ + +	local_table = calloc(1, table_length); +	if (!local_table) { +		status = AE_NO_MEMORY; +		goto exit; +	} + +	ACPI_MEMCPY(local_table, mapped_table, table_length); +	*address = table_address; +	*table = local_table; + +exit: +	osl_unmap_table(mapped_table); +	return (status); +} + +/****************************************************************************** + * + * FUNCTION:    osl_list_customized_tables + * + * PARAMETERS:  directory           - Directory that contains the tables + * + * RETURN:      Status; Table list is initialized if AE_OK. + * + * DESCRIPTION: Add ACPI tables to the table list from a directory. + * + *****************************************************************************/ + +static acpi_status osl_list_customized_tables(char *directory) +{ +	void *table_dir; +	u32 instance; +	char temp_name[ACPI_NAME_SIZE]; +	char *filename; +	acpi_status status = AE_OK; + +	/* Open the requested directory */ + +	table_dir = acpi_os_open_directory(directory, "*", REQUEST_FILE_ONLY); +	if (!table_dir) { +		return (osl_get_last_status(AE_NOT_FOUND)); +	} + +	/* Examine all entries in this directory */ + +	while ((filename = acpi_os_get_next_filename(table_dir))) { + +		/* Extract table name and instance number */ + +		status = +		    osl_table_name_from_file(filename, temp_name, &instance); + +		/* Ignore meaningless files */ + +		if (ACPI_FAILURE(status)) { +			continue; +		} + +		/* Add new info node to global table list */ + +		status = osl_add_table_to_list(temp_name, instance); +		if (ACPI_FAILURE(status)) { +			break; +		} +	} + +	acpi_os_close_directory(table_dir); +	return (status); +} + +/****************************************************************************** + * + * FUNCTION:    osl_map_table + * + * PARAMETERS:  address             - Address of the table in memory + *              signature           - Optional ACPI Signature for desired table. + *                                    Null terminated 4-character string. + *              table               - Where a pointer to the mapped table is + *                                    returned + * + * RETURN:      Status; Mapped table is returned if AE_OK. + *              AE_NOT_FOUND: A valid table was not found at the address + * + * DESCRIPTION: Map entire ACPI table into caller's address space. + * + *****************************************************************************/ + +static acpi_status +osl_map_table(acpi_size address, +	      char *signature, struct acpi_table_header **table) +{ +	struct acpi_table_header *mapped_table; +	u32 length; + +	if (!address) { +		return (AE_BAD_ADDRESS); +	} + +	/* +	 * Map the header so we can get the table length. +	 * Use sizeof (struct acpi_table_header) as: +	 * 1. it is bigger than 24 to include RSDP->Length +	 * 2. it is smaller than sizeof (struct acpi_table_rsdp) +	 */ +	mapped_table = +	    acpi_os_map_memory(address, sizeof(struct acpi_table_header)); +	if (!mapped_table) { +		fprintf(stderr, "Could not map table header at 0x%8.8X%8.8X\n", +			ACPI_FORMAT_UINT64(address)); +		return (osl_get_last_status(AE_BAD_ADDRESS)); +	} + +	/* If specified, signature must match */ + +	if (signature) { +		if (ACPI_VALIDATE_RSDP_SIG(signature)) { +			if (!ACPI_VALIDATE_RSDP_SIG(mapped_table->signature)) { +				acpi_os_unmap_memory(mapped_table, +						     sizeof(struct +							    acpi_table_header)); +				return (AE_BAD_SIGNATURE); +			} +		} else +		    if (!ACPI_COMPARE_NAME(signature, mapped_table->signature)) +		{ +			acpi_os_unmap_memory(mapped_table, +					     sizeof(struct acpi_table_header)); +			return (AE_BAD_SIGNATURE); +		} +	} + +	/* Map the entire table */ + +	length = ap_get_table_length(mapped_table); +	acpi_os_unmap_memory(mapped_table, sizeof(struct acpi_table_header)); +	if (length == 0) { +		return (AE_BAD_HEADER); +	} + +	mapped_table = acpi_os_map_memory(address, length); +	if (!mapped_table) { +		fprintf(stderr, +			"Could not map table at 0x%8.8X%8.8X length %8.8X\n", +			ACPI_FORMAT_UINT64(address), length); +		return (osl_get_last_status(AE_INVALID_TABLE_LENGTH)); +	} + +	(void)ap_is_valid_checksum(mapped_table); + +	*table = mapped_table; +	return (AE_OK); +} + +/****************************************************************************** + * + * FUNCTION:    osl_unmap_table + * + * PARAMETERS:  table               - A pointer to the mapped table + * + * RETURN:      None + * + * DESCRIPTION: Unmap entire ACPI table. + * + *****************************************************************************/ + +static void osl_unmap_table(struct acpi_table_header *table) +{ +	if (table) { +		acpi_os_unmap_memory(table, ap_get_table_length(table)); +	} +} + +/****************************************************************************** + * + * FUNCTION:    osl_table_name_from_file + * + * PARAMETERS:  filename            - File that contains the desired table + *              signature           - Pointer to 4-character buffer to store + *                                    extracted table signature. + *              instance            - Pointer to integer to store extracted + *                                    table instance number. + * + * RETURN:      Status; Table name is extracted if AE_OK. + * + * DESCRIPTION: Extract table signature and instance number from a table file + *              name. + * + *****************************************************************************/ + +static acpi_status +osl_table_name_from_file(char *filename, char *signature, u32 *instance) +{ + +	/* Ignore meaningless files */ + +	if (strlen(filename) < ACPI_NAME_SIZE) { +		return (AE_BAD_SIGNATURE); +	} + +	/* Extract instance number */ + +	if (isdigit((int)filename[ACPI_NAME_SIZE])) { +		sscanf(&filename[ACPI_NAME_SIZE], "%d", instance); +	} else if (strlen(filename) != ACPI_NAME_SIZE) { +		return (AE_BAD_SIGNATURE); +	} else { +		*instance = 0; +	} + +	/* Extract signature */ + +	ACPI_MOVE_NAME(signature, filename); +	return (AE_OK); +} + +/****************************************************************************** + * + * FUNCTION:    osl_read_table_from_file + * + * PARAMETERS:  filename            - File that contains the desired table + *              file_offset         - Offset of the table in file + *              signature           - Optional ACPI Signature for desired table. + *                                    A null terminated 4-character string. + *              table               - Where a pointer to the table is returned + * + * RETURN:      Status; Table buffer is returned if AE_OK. + * + * DESCRIPTION: Read a ACPI table from a file. + * + *****************************************************************************/ + +static acpi_status +osl_read_table_from_file(char *filename, +			 acpi_size file_offset, +			 char *signature, struct acpi_table_header **table) +{ +	FILE *table_file; +	struct acpi_table_header header; +	struct acpi_table_header *local_table = NULL; +	u32 table_length; +	s32 count; +	acpi_status status = AE_OK; + +	/* Open the file */ + +	table_file = fopen(filename, "rb"); +	if (table_file == NULL) { +		fprintf(stderr, "Could not open table file: %s\n", filename); +		return (osl_get_last_status(AE_NOT_FOUND)); +	} + +	fseek(table_file, file_offset, SEEK_SET); + +	/* Read the Table header to get the table length */ + +	count = fread(&header, 1, sizeof(struct acpi_table_header), table_file); +	if (count != sizeof(struct acpi_table_header)) { +		fprintf(stderr, "Could not read table header: %s\n", filename); +		status = AE_BAD_HEADER; +		goto exit; +	} + +	/* If signature is specified, it must match the table */ + +	if (signature) { +		if (ACPI_VALIDATE_RSDP_SIG(signature)) { +			if (!ACPI_VALIDATE_RSDP_SIG(header.signature)) { +				fprintf(stderr, +					"Incorrect RSDP signature: found %8.8s\n", +					header.signature); +				status = AE_BAD_SIGNATURE; +				goto exit; +			} +		} else if (!ACPI_COMPARE_NAME(signature, header.signature)) { +			fprintf(stderr, +				"Incorrect signature: Expecting %4.4s, found %4.4s\n", +				signature, header.signature); +			status = AE_BAD_SIGNATURE; +			goto exit; +		} +	} + +	table_length = ap_get_table_length(&header); +	if (table_length == 0) { +		status = AE_BAD_HEADER; +		goto exit; +	} + +	/* Read the entire table into a local buffer */ + +	local_table = calloc(1, table_length); +	if (!local_table) { +		fprintf(stderr, +			"%4.4s: Could not allocate buffer for table of length %X\n", +			header.signature, table_length); +		status = AE_NO_MEMORY; +		goto exit; +	} + +	fseek(table_file, file_offset, SEEK_SET); + +	count = fread(local_table, 1, table_length, table_file); +	if (count != table_length) { +		fprintf(stderr, "%4.4s: Could not read table content\n", +			header.signature); +		status = AE_INVALID_TABLE_LENGTH; +		goto exit; +	} + +	/* Validate checksum */ + +	(void)ap_is_valid_checksum(local_table); + +exit: +	fclose(table_file); +	*table = local_table; +	return (status); +} + +/****************************************************************************** + * + * FUNCTION:    osl_get_customized_table + * + * PARAMETERS:  pathname        - Directory to find Linux customized table + *              signature       - ACPI Signature for desired table. Must be + *                                a null terminated 4-character string. + *              instance        - Multiple table support for SSDT/UEFI (0...n) + *                                Must be 0 for other tables. + *              table           - Where a pointer to the table is returned + *              address         - Where the table physical address is returned + * + * RETURN:      Status; Table buffer is returned if AE_OK. + *              AE_LIMIT: Instance is beyond valid limit + *              AE_NOT_FOUND: A table with the signature was not found + * + * DESCRIPTION: Get an OS customized table. + * + *****************************************************************************/ + +static acpi_status +osl_get_customized_table(char *pathname, +			 char *signature, +			 u32 instance, +			 struct acpi_table_header **table, +			 acpi_physical_address * address) +{ +	void *table_dir; +	u32 current_instance = 0; +	char temp_name[ACPI_NAME_SIZE]; +	char table_filename[PATH_MAX]; +	char *filename; +	acpi_status status; + +	/* Open the directory for customized tables */ + +	table_dir = acpi_os_open_directory(pathname, "*", REQUEST_FILE_ONLY); +	if (!table_dir) { +		return (osl_get_last_status(AE_NOT_FOUND)); +	} + +	/* Attempt to find the table in the directory */ + +	while ((filename = acpi_os_get_next_filename(table_dir))) { + +		/* Ignore meaningless files */ + +		if (!ACPI_COMPARE_NAME(filename, signature)) { +			continue; +		} + +		/* Extract table name and instance number */ + +		status = +		    osl_table_name_from_file(filename, temp_name, +					     ¤t_instance); + +		/* Ignore meaningless files */ + +		if (ACPI_FAILURE(status) || current_instance != instance) { +			continue; +		} + +		/* Create the table pathname */ + +		if (instance != 0) { +			sprintf(table_filename, "%s/%4.4s%d", pathname, +				temp_name, instance); +		} else { +			sprintf(table_filename, "%s/%4.4s", pathname, +				temp_name); +		} +		break; +	} + +	acpi_os_close_directory(table_dir); + +	if (!filename) { +		return (AE_LIMIT); +	} + +	/* There is no physical address saved for customized tables, use zero */ + +	*address = 0; +	status = osl_read_table_from_file(table_filename, 0, NULL, table); + +	return (status); +} diff --git a/tools/power/acpi/os_specific/service_layers/osunixdir.c b/tools/power/acpi/os_specific/service_layers/osunixdir.c new file mode 100644 index 00000000000..733f9e490fc --- /dev/null +++ b/tools/power/acpi/os_specific/service_layers/osunixdir.c @@ -0,0 +1,204 @@ +/****************************************************************************** + * + * Module Name: osunixdir - Unix directory access interfaces + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2014, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + *    notice, this list of conditions, and the following disclaimer, + *    without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + *    substantially similar to the "NO WARRANTY" disclaimer below + *    ("Disclaimer") and any redistribution must be conditioned upon + *    including a substantially similar Disclaimer requirement for further + *    binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + *    of any contributors may be used to endorse or promote products derived + *    from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include <acpi/acpi.h> + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <dirent.h> +#include <fnmatch.h> +#include <ctype.h> +#include <sys/stat.h> + +/* + * Allocated structure returned from os_open_directory + */ +typedef struct external_find_info { +	char *dir_pathname; +	DIR *dir_ptr; +	char temp_buffer[256]; +	char *wildcard_spec; +	char requested_file_type; + +} external_find_info; + +/******************************************************************************* + * + * FUNCTION:    acpi_os_open_directory + * + * PARAMETERS:  dir_pathname        - Full pathname to the directory + *              wildcard_spec       - string of the form "*.c", etc. + * + * RETURN:      A directory "handle" to be used in subsequent search operations. + *              NULL returned on failure. + * + * DESCRIPTION: Open a directory in preparation for a wildcard search + * + ******************************************************************************/ + +void *acpi_os_open_directory(char *dir_pathname, +			     char *wildcard_spec, char requested_file_type) +{ +	struct external_find_info *external_info; +	DIR *dir; + +	/* Allocate the info struct that will be returned to the caller */ + +	external_info = calloc(1, sizeof(struct external_find_info)); +	if (!external_info) { +		return (NULL); +	} + +	/* Get the directory stream */ + +	dir = opendir(dir_pathname); +	if (!dir) { +		fprintf(stderr, "Cannot open directory - %s\n", dir_pathname); +		free(external_info); +		return (NULL); +	} + +	/* Save the info in the return structure */ + +	external_info->wildcard_spec = wildcard_spec; +	external_info->requested_file_type = requested_file_type; +	external_info->dir_pathname = dir_pathname; +	external_info->dir_ptr = dir; +	return (external_info); +} + +/******************************************************************************* + * + * FUNCTION:    acpi_os_get_next_filename + * + * PARAMETERS:  dir_handle          - Created via acpi_os_open_directory + * + * RETURN:      Next filename matched. NULL if no more matches. + * + * DESCRIPTION: Get the next file in the directory that matches the wildcard + *              specification. + * + ******************************************************************************/ + +char *acpi_os_get_next_filename(void *dir_handle) +{ +	struct external_find_info *external_info = dir_handle; +	struct dirent *dir_entry; +	char *temp_str; +	int str_len; +	struct stat temp_stat; +	int err; + +	while ((dir_entry = readdir(external_info->dir_ptr))) { +		if (!fnmatch +		    (external_info->wildcard_spec, dir_entry->d_name, 0)) { +			if (dir_entry->d_name[0] == '.') { +				continue; +			} + +			str_len = strlen(dir_entry->d_name) + +			    strlen(external_info->dir_pathname) + 2; + +			temp_str = calloc(str_len, 1); +			if (!temp_str) { +				fprintf(stderr, +					"Could not allocate buffer for temporary string\n"); +				return (NULL); +			} + +			strcpy(temp_str, external_info->dir_pathname); +			strcat(temp_str, "/"); +			strcat(temp_str, dir_entry->d_name); + +			err = stat(temp_str, &temp_stat); +			if (err == -1) { +				fprintf(stderr, +					"Cannot stat file (should not happen) - %s\n", +					temp_str); +				free(temp_str); +				return (NULL); +			} + +			free(temp_str); + +			if ((S_ISDIR(temp_stat.st_mode) +			     && (external_info->requested_file_type == +				 REQUEST_DIR_ONLY)) +			    || ((!S_ISDIR(temp_stat.st_mode) +				 && external_info->requested_file_type == +				 REQUEST_FILE_ONLY))) { + +				/* copy to a temp buffer because dir_entry struct is on the stack */ + +				strcpy(external_info->temp_buffer, +				       dir_entry->d_name); +				return (external_info->temp_buffer); +			} +		} +	} + +	return (NULL); +} + +/******************************************************************************* + * + * FUNCTION:    acpi_os_close_directory + * + * PARAMETERS:  dir_handle          - Created via acpi_os_open_directory + * + * RETURN:      None. + * + * DESCRIPTION: Close the open directory and cleanup. + * + ******************************************************************************/ + +void acpi_os_close_directory(void *dir_handle) +{ +	struct external_find_info *external_info = dir_handle; + +	/* Close the directory and free allocations */ + +	closedir(external_info->dir_ptr); +	free(dir_handle); +} diff --git a/tools/power/acpi/os_specific/service_layers/osunixmap.c b/tools/power/acpi/os_specific/service_layers/osunixmap.c new file mode 100644 index 00000000000..99b47b6194a --- /dev/null +++ b/tools/power/acpi/os_specific/service_layers/osunixmap.c @@ -0,0 +1,151 @@ +/****************************************************************************** + * + * Module Name: osunixmap - Unix OSL for file mappings + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2014, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + *    notice, this list of conditions, and the following disclaimer, + *    without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + *    substantially similar to the "NO WARRANTY" disclaimer below + *    ("Disclaimer") and any redistribution must be conditioned upon + *    including a substantially similar Disclaimer requirement for further + *    binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + *    of any contributors may be used to endorse or promote products derived + *    from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpidump.h" +#include <unistd.h> +#include <sys/mman.h> +#ifdef _free_BSD +#include <sys/param.h> +#endif + +#define _COMPONENT          ACPI_OS_SERVICES +ACPI_MODULE_NAME("osunixmap") + +#ifndef O_BINARY +#define O_BINARY 0 +#endif +#ifdef _free_BSD +#define MMAP_FLAGS          MAP_SHARED +#else +#define MMAP_FLAGS          MAP_PRIVATE +#endif +#define SYSTEM_MEMORY       "/dev/mem" +/******************************************************************************* + * + * FUNCTION:    acpi_os_get_page_size + * + * PARAMETERS:  None + * + * RETURN:      Page size of the platform. + * + * DESCRIPTION: Obtain page size of the platform. + * + ******************************************************************************/ +static acpi_size acpi_os_get_page_size(void) +{ + +#ifdef PAGE_SIZE +	return PAGE_SIZE; +#else +	return sysconf(_SC_PAGESIZE); +#endif +} + +/****************************************************************************** + * + * FUNCTION:    acpi_os_map_memory + * + * PARAMETERS:  where               - Physical address of memory to be mapped + *              length              - How much memory to map + * + * RETURN:      Pointer to mapped memory. Null on error. + * + * DESCRIPTION: Map physical memory into local address space. + * + *****************************************************************************/ + +void *acpi_os_map_memory(acpi_physical_address where, acpi_size length) +{ +	u8 *mapped_memory; +	acpi_physical_address offset; +	acpi_size page_size; +	int fd; + +	fd = open(SYSTEM_MEMORY, O_RDONLY | O_BINARY); +	if (fd < 0) { +		fprintf(stderr, "Cannot open %s\n", SYSTEM_MEMORY); +		return (NULL); +	} + +	/* Align the offset to use mmap */ + +	page_size = acpi_os_get_page_size(); +	offset = where % page_size; + +	/* Map the table header to get the length of the full table */ + +	mapped_memory = mmap(NULL, (length + offset), PROT_READ, MMAP_FLAGS, +			     fd, (where - offset)); +	if (mapped_memory == MAP_FAILED) { +		fprintf(stderr, "Cannot map %s\n", SYSTEM_MEMORY); +		close(fd); +		return (NULL); +	} + +	close(fd); +	return (ACPI_CAST8(mapped_memory + offset)); +} + +/****************************************************************************** + * + * FUNCTION:    acpi_os_unmap_memory + * + * PARAMETERS:  where               - Logical address of memory to be unmapped + *              length              - How much memory to unmap + * + * RETURN:      None. + * + * DESCRIPTION: Delete a previously created mapping. Where and Length must + *              correspond to a previous mapping exactly. + * + *****************************************************************************/ + +void acpi_os_unmap_memory(void *where, acpi_size length) +{ +	acpi_physical_address offset; +	acpi_size page_size; + +	page_size = acpi_os_get_page_size(); +	offset = (acpi_physical_address) where % page_size; +	munmap((u8 *)where - offset, (length + offset)); +} diff --git a/tools/power/acpi/tools/acpidump/acpidump.h b/tools/power/acpi/tools/acpidump/acpidump.h new file mode 100644 index 00000000000..46f519597fe --- /dev/null +++ b/tools/power/acpi/tools/acpidump/acpidump.h @@ -0,0 +1,130 @@ +/****************************************************************************** + * + * Module Name: acpidump.h - Include file for acpi_dump utility + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2014, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + *    notice, this list of conditions, and the following disclaimer, + *    without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + *    substantially similar to the "NO WARRANTY" disclaimer below + *    ("Disclaimer") and any redistribution must be conditioned upon + *    including a substantially similar Disclaimer requirement for further + *    binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + *    of any contributors may be used to endorse or promote products derived + *    from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +/* + * Global variables. Defined in main.c only, externed in all other files + */ +#ifdef _DECLARE_GLOBALS +#define EXTERN +#define INIT_GLOBAL(a,b)        a=b +#define DEFINE_ACPI_GLOBALS     1 +#else +#define EXTERN                  extern +#define INIT_GLOBAL(a,b)        a +#endif + +#include <acpi/acpi.h> +#include "accommon.h" +#include "actables.h" + +#include <stdio.h> +#include <fcntl.h> +#include <errno.h> +#include <sys/stat.h> + +/* Globals */ + +EXTERN u8 INIT_GLOBAL(gbl_summary_mode, FALSE); +EXTERN u8 INIT_GLOBAL(gbl_verbose_mode, FALSE); +EXTERN u8 INIT_GLOBAL(gbl_binary_mode, FALSE); +EXTERN u8 INIT_GLOBAL(gbl_dump_customized_tables, FALSE); +EXTERN u8 INIT_GLOBAL(gbl_do_not_dump_xsdt, FALSE); +EXTERN FILE INIT_GLOBAL(*gbl_output_file, NULL); +EXTERN char INIT_GLOBAL(*gbl_output_filename, NULL); +EXTERN u64 INIT_GLOBAL(gbl_rsdp_base, 0); + +/* Globals required for use with ACPICA modules */ + +#ifdef _DECLARE_GLOBALS +u8 acpi_gbl_integer_byte_width = 8; +#endif + +/* Action table used to defer requested options */ + +struct ap_dump_action { +	char *argument; +	u32 to_be_done; +}; + +#define AP_MAX_ACTIONS              32 + +#define AP_DUMP_ALL_TABLES          0 +#define AP_DUMP_TABLE_BY_ADDRESS    1 +#define AP_DUMP_TABLE_BY_NAME       2 +#define AP_DUMP_TABLE_BY_FILE       3 + +#define AP_MAX_ACPI_FILES           256	/* Prevent infinite loops */ + +/* Minimum FADT sizes for various table addresses */ + +#define MIN_FADT_FOR_DSDT           (ACPI_FADT_OFFSET (dsdt) + sizeof (u32)) +#define MIN_FADT_FOR_FACS           (ACPI_FADT_OFFSET (facs) + sizeof (u32)) +#define MIN_FADT_FOR_XDSDT          (ACPI_FADT_OFFSET (Xdsdt) + sizeof (u64)) +#define MIN_FADT_FOR_XFACS          (ACPI_FADT_OFFSET (Xfacs) + sizeof (u64)) + +/* + * apdump - Table get/dump routines + */ +int ap_dump_table_from_file(char *pathname); + +int ap_dump_table_by_name(char *signature); + +int ap_dump_table_by_address(char *ascii_address); + +int ap_dump_all_tables(void); + +u8 ap_is_valid_header(struct acpi_table_header *table); + +u8 ap_is_valid_checksum(struct acpi_table_header *table); + +u32 ap_get_table_length(struct acpi_table_header *table); + +/* + * apfiles - File I/O utilities + */ +int ap_open_output_file(char *pathname); + +int ap_write_to_binary_file(struct acpi_table_header *table, u32 instance); + +struct acpi_table_header *ap_get_table_from_file(char *pathname, +						 u32 *file_size); diff --git a/tools/power/acpi/tools/acpidump/apdump.c b/tools/power/acpi/tools/acpidump/apdump.c new file mode 100644 index 00000000000..3cac1237836 --- /dev/null +++ b/tools/power/acpi/tools/acpidump/apdump.c @@ -0,0 +1,451 @@ +/****************************************************************************** + * + * Module Name: apdump - Dump routines for ACPI tables (acpidump) + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2014, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + *    notice, this list of conditions, and the following disclaimer, + *    without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + *    substantially similar to the "NO WARRANTY" disclaimer below + *    ("Disclaimer") and any redistribution must be conditioned upon + *    including a substantially similar Disclaimer requirement for further + *    binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + *    of any contributors may be used to endorse or promote products derived + *    from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpidump.h" + +/* Local prototypes */ + +static int +ap_dump_table_buffer(struct acpi_table_header *table, +		     u32 instance, acpi_physical_address address); + +/****************************************************************************** + * + * FUNCTION:    ap_is_valid_header + * + * PARAMETERS:  table               - Pointer to table to be validated + * + * RETURN:      TRUE if the header appears to be valid. FALSE otherwise + * + * DESCRIPTION: Check for a valid ACPI table header + * + ******************************************************************************/ + +u8 ap_is_valid_header(struct acpi_table_header *table) +{ + +	if (!ACPI_VALIDATE_RSDP_SIG(table->signature)) { + +		/* Make sure signature is all ASCII and a valid ACPI name */ + +		if (!acpi_ut_valid_acpi_name(table->signature)) { +			fprintf(stderr, +				"Table signature (0x%8.8X) is invalid\n", +				*(u32 *)table->signature); +			return (FALSE); +		} + +		/* Check for minimum table length */ + +		if (table->length < sizeof(struct acpi_table_header)) { +			fprintf(stderr, "Table length (0x%8.8X) is invalid\n", +				table->length); +			return (FALSE); +		} +	} + +	return (TRUE); +} + +/****************************************************************************** + * + * FUNCTION:    ap_is_valid_checksum + * + * PARAMETERS:  table               - Pointer to table to be validated + * + * RETURN:      TRUE if the checksum appears to be valid. FALSE otherwise. + * + * DESCRIPTION: Check for a valid ACPI table checksum. + * + ******************************************************************************/ + +u8 ap_is_valid_checksum(struct acpi_table_header *table) +{ +	acpi_status status; +	struct acpi_table_rsdp *rsdp; + +	if (ACPI_VALIDATE_RSDP_SIG(table->signature)) { +		/* +		 * Checksum for RSDP. +		 * Note: Other checksums are computed during the table dump. +		 */ +		rsdp = ACPI_CAST_PTR(struct acpi_table_rsdp, table); +		status = acpi_tb_validate_rsdp(rsdp); +	} else { +		status = acpi_tb_verify_checksum(table, table->length); +	} + +	if (ACPI_FAILURE(status)) { +		fprintf(stderr, "%4.4s: Warning: wrong checksum in table\n", +			table->signature); +	} + +	return (AE_OK); +} + +/****************************************************************************** + * + * FUNCTION:    ap_get_table_length + * + * PARAMETERS:  table               - Pointer to the table + * + * RETURN:      Table length + * + * DESCRIPTION: Obtain table length according to table signature. + * + ******************************************************************************/ + +u32 ap_get_table_length(struct acpi_table_header *table) +{ +	struct acpi_table_rsdp *rsdp; + +	/* Check if table is valid */ + +	if (!ap_is_valid_header(table)) { +		return (0); +	} + +	if (ACPI_VALIDATE_RSDP_SIG(table->signature)) { +		rsdp = ACPI_CAST_PTR(struct acpi_table_rsdp, table); +		return (rsdp->length); +	} + +	/* Normal ACPI table */ + +	return (table->length); +} + +/****************************************************************************** + * + * FUNCTION:    ap_dump_table_buffer + * + * PARAMETERS:  table               - ACPI table to be dumped + *              instance            - ACPI table instance no. to be dumped + *              address             - Physical address of the table + * + * RETURN:      None + * + * DESCRIPTION: Dump an ACPI table in standard ASCII hex format, with a + *              header that is compatible with the acpi_xtract utility. + * + ******************************************************************************/ + +static int +ap_dump_table_buffer(struct acpi_table_header *table, +		     u32 instance, acpi_physical_address address) +{ +	u32 table_length; + +	table_length = ap_get_table_length(table); + +	/* Print only the header if requested */ + +	if (gbl_summary_mode) { +		acpi_tb_print_table_header(address, table); +		return (0); +	} + +	/* Dump to binary file if requested */ + +	if (gbl_binary_mode) { +		return (ap_write_to_binary_file(table, instance)); +	} + +	/* +	 * Dump the table with header for use with acpixtract utility. +	 * Note: simplest to just always emit a 64-bit address. acpi_xtract +	 * utility can handle this. +	 */ +	printf("%4.4s @ 0x%8.8X%8.8X\n", table->signature, +	       ACPI_FORMAT_UINT64(address)); + +	acpi_ut_dump_buffer(ACPI_CAST_PTR(u8, table), table_length, +			    DB_BYTE_DISPLAY, 0); +	printf("\n"); +	return (0); +} + +/****************************************************************************** + * + * FUNCTION:    ap_dump_all_tables + * + * PARAMETERS:  None + * + * RETURN:      Status + * + * DESCRIPTION: Get all tables from the RSDT/XSDT (or at least all of the + *              tables that we can possibly get). + * + ******************************************************************************/ + +int ap_dump_all_tables(void) +{ +	struct acpi_table_header *table; +	u32 instance = 0; +	acpi_physical_address address; +	acpi_status status; +	int table_status; +	u32 i; + +	/* Get and dump all available ACPI tables */ + +	for (i = 0; i < AP_MAX_ACPI_FILES; i++) { +		status = +		    acpi_os_get_table_by_index(i, &table, &instance, &address); +		if (ACPI_FAILURE(status)) { + +			/* AE_LIMIT means that no more tables are available */ + +			if (status == AE_LIMIT) { +				return (0); +			} else if (i == 0) { +				fprintf(stderr, +					"Could not get ACPI tables, %s\n", +					acpi_format_exception(status)); +				return (-1); +			} else { +				fprintf(stderr, +					"Could not get ACPI table at index %u, %s\n", +					i, acpi_format_exception(status)); +				continue; +			} +		} + +		table_status = ap_dump_table_buffer(table, instance, address); +		free(table); + +		if (table_status) { +			break; +		} +	} + +	/* Something seriously bad happened if the loop terminates here */ + +	return (-1); +} + +/****************************************************************************** + * + * FUNCTION:    ap_dump_table_by_address + * + * PARAMETERS:  ascii_address       - Address for requested ACPI table + * + * RETURN:      Status + * + * DESCRIPTION: Get an ACPI table via a physical address and dump it. + * + ******************************************************************************/ + +int ap_dump_table_by_address(char *ascii_address) +{ +	acpi_physical_address address; +	struct acpi_table_header *table; +	acpi_status status; +	int table_status; +	u64 long_address; + +	/* Convert argument to an integer physical address */ + +	status = acpi_ut_strtoul64(ascii_address, 0, &long_address); +	if (ACPI_FAILURE(status)) { +		fprintf(stderr, "%s: Could not convert to a physical address\n", +			ascii_address); +		return (-1); +	} + +	address = (acpi_physical_address) long_address; +	status = acpi_os_get_table_by_address(address, &table); +	if (ACPI_FAILURE(status)) { +		fprintf(stderr, "Could not get table at 0x%8.8X%8.8X, %s\n", +			ACPI_FORMAT_UINT64(address), +			acpi_format_exception(status)); +		return (-1); +	} + +	table_status = ap_dump_table_buffer(table, 0, address); +	free(table); +	return (table_status); +} + +/****************************************************************************** + * + * FUNCTION:    ap_dump_table_by_name + * + * PARAMETERS:  signature           - Requested ACPI table signature + * + * RETURN:      Status + * + * DESCRIPTION: Get an ACPI table via a signature and dump it. Handles + *              multiple tables with the same signature (SSDTs). + * + ******************************************************************************/ + +int ap_dump_table_by_name(char *signature) +{ +	char local_signature[ACPI_NAME_SIZE + 1]; +	u32 instance; +	struct acpi_table_header *table; +	acpi_physical_address address; +	acpi_status status; +	int table_status; + +	if (strlen(signature) != ACPI_NAME_SIZE) { +		fprintf(stderr, +			"Invalid table signature [%s]: must be exactly 4 characters\n", +			signature); +		return (-1); +	} + +	/* Table signatures are expected to be uppercase */ + +	strcpy(local_signature, signature); +	acpi_ut_strupr(local_signature); + +	/* To be friendly, handle tables whose signatures do not match the name */ + +	if (ACPI_COMPARE_NAME(local_signature, "FADT")) { +		strcpy(local_signature, ACPI_SIG_FADT); +	} else if (ACPI_COMPARE_NAME(local_signature, "MADT")) { +		strcpy(local_signature, ACPI_SIG_MADT); +	} + +	/* Dump all instances of this signature (to handle multiple SSDTs) */ + +	for (instance = 0; instance < AP_MAX_ACPI_FILES; instance++) { +		status = acpi_os_get_table_by_name(local_signature, instance, +						   &table, &address); +		if (ACPI_FAILURE(status)) { + +			/* AE_LIMIT means that no more tables are available */ + +			if (status == AE_LIMIT) { +				return (0); +			} + +			fprintf(stderr, +				"Could not get ACPI table with signature [%s], %s\n", +				local_signature, acpi_format_exception(status)); +			return (-1); +		} + +		table_status = ap_dump_table_buffer(table, instance, address); +		free(table); + +		if (table_status) { +			break; +		} +	} + +	/* Something seriously bad happened if the loop terminates here */ + +	return (-1); +} + +/****************************************************************************** + * + * FUNCTION:    ap_dump_table_from_file + * + * PARAMETERS:  pathname            - File containing the binary ACPI table + * + * RETURN:      Status + * + * DESCRIPTION: Dump an ACPI table from a binary file + * + ******************************************************************************/ + +int ap_dump_table_from_file(char *pathname) +{ +	struct acpi_table_header *table; +	u32 file_size = 0; +	int table_status = -1; + +	/* Get the entire ACPI table from the file */ + +	table = ap_get_table_from_file(pathname, &file_size); +	if (!table) { +		return (-1); +	} + +	/* File must be at least as long as the table length */ + +	if (table->length > file_size) { +		fprintf(stderr, +			"Table length (0x%X) is too large for input file (0x%X) %s\n", +			table->length, file_size, pathname); +		goto exit; +	} + +	if (gbl_verbose_mode) { +		fprintf(stderr, +			"Input file:  %s contains table [%4.4s], 0x%X (%u) bytes\n", +			pathname, table->signature, file_size, file_size); +	} + +	table_status = ap_dump_table_buffer(table, 0, 0); + +exit: +	free(table); +	return (table_status); +} + +/****************************************************************************** + * + * FUNCTION:    acpi_os* print functions + * + * DESCRIPTION: Used for linkage with ACPICA modules + * + ******************************************************************************/ + +void ACPI_INTERNAL_VAR_XFACE acpi_os_printf(const char *fmt, ...) +{ +	va_list args; + +	va_start(args, fmt); +	vfprintf(stdout, fmt, args); +	va_end(args); +} + +void acpi_os_vprintf(const char *fmt, va_list args) +{ +	vfprintf(stdout, fmt, args); +} diff --git a/tools/power/acpi/tools/acpidump/apfiles.c b/tools/power/acpi/tools/acpidump/apfiles.c new file mode 100644 index 00000000000..4488accc010 --- /dev/null +++ b/tools/power/acpi/tools/acpidump/apfiles.c @@ -0,0 +1,228 @@ +/****************************************************************************** + * + * Module Name: apfiles - File-related functions for acpidump utility + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2014, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + *    notice, this list of conditions, and the following disclaimer, + *    without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + *    substantially similar to the "NO WARRANTY" disclaimer below + *    ("Disclaimer") and any redistribution must be conditioned upon + *    including a substantially similar Disclaimer requirement for further + *    binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + *    of any contributors may be used to endorse or promote products derived + *    from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include "acpidump.h" +#include "acapps.h" + +/****************************************************************************** + * + * FUNCTION:    ap_open_output_file + * + * PARAMETERS:  pathname            - Output filename + * + * RETURN:      Open file handle + * + * DESCRIPTION: Open a text output file for acpidump. Checks if file already + *              exists. + * + ******************************************************************************/ + +int ap_open_output_file(char *pathname) +{ +	struct stat stat_info; +	FILE *file; + +	/* If file exists, prompt for overwrite */ + +	if (!stat(pathname, &stat_info)) { +		fprintf(stderr, +			"Target path already exists, overwrite? [y|n] "); + +		if (getchar() != 'y') { +			return (-1); +		} +	} + +	/* Point stdout to the file */ + +	file = freopen(pathname, "w", stdout); +	if (!file) { +		perror("Could not open output file"); +		return (-1); +	} + +	/* Save the file and path */ + +	gbl_output_file = file; +	gbl_output_filename = pathname; +	return (0); +} + +/****************************************************************************** + * + * FUNCTION:    ap_write_to_binary_file + * + * PARAMETERS:  table               - ACPI table to be written + *              instance            - ACPI table instance no. to be written + * + * RETURN:      Status + * + * DESCRIPTION: Write an ACPI table to a binary file. Builds the output + *              filename from the table signature. + * + ******************************************************************************/ + +int ap_write_to_binary_file(struct acpi_table_header *table, u32 instance) +{ +	char filename[ACPI_NAME_SIZE + 16]; +	char instance_str[16]; +	FILE *file; +	size_t actual; +	u32 table_length; + +	/* Obtain table length */ + +	table_length = ap_get_table_length(table); + +	/* Construct lower-case filename from the table local signature */ + +	if (ACPI_VALIDATE_RSDP_SIG(table->signature)) { +		ACPI_MOVE_NAME(filename, ACPI_RSDP_NAME); +	} else { +		ACPI_MOVE_NAME(filename, table->signature); +	} +	filename[0] = (char)ACPI_TOLOWER(filename[0]); +	filename[1] = (char)ACPI_TOLOWER(filename[1]); +	filename[2] = (char)ACPI_TOLOWER(filename[2]); +	filename[3] = (char)ACPI_TOLOWER(filename[3]); +	filename[ACPI_NAME_SIZE] = 0; + +	/* Handle multiple SSDts - create different filenames for each */ + +	if (instance > 0) { +		sprintf(instance_str, "%u", instance); +		strcat(filename, instance_str); +	} + +	strcat(filename, ACPI_TABLE_FILE_SUFFIX); + +	if (gbl_verbose_mode) { +		fprintf(stderr, +			"Writing [%4.4s] to binary file: %s 0x%X (%u) bytes\n", +			table->signature, filename, table->length, +			table->length); +	} + +	/* Open the file and dump the entire table in binary mode */ + +	file = fopen(filename, "wb"); +	if (!file) { +		perror("Could not open output file"); +		return (-1); +	} + +	actual = fwrite(table, 1, table_length, file); +	if (actual != table_length) { +		perror("Error writing binary output file"); +		fclose(file); +		return (-1); +	} + +	fclose(file); +	return (0); +} + +/****************************************************************************** + * + * FUNCTION:    ap_get_table_from_file + * + * PARAMETERS:  pathname            - File containing the binary ACPI table + *              out_file_size       - Where the file size is returned + * + * RETURN:      Buffer containing the ACPI table. NULL on error. + * + * DESCRIPTION: Open a file and read it entirely into a new buffer + * + ******************************************************************************/ + +struct acpi_table_header *ap_get_table_from_file(char *pathname, +						 u32 *out_file_size) +{ +	struct acpi_table_header *buffer = NULL; +	FILE *file; +	u32 file_size; +	size_t actual; + +	/* Must use binary mode */ + +	file = fopen(pathname, "rb"); +	if (!file) { +		perror("Could not open input file"); +		return (NULL); +	} + +	/* Need file size to allocate a buffer */ + +	file_size = cm_get_file_size(file); +	if (file_size == ACPI_UINT32_MAX) { +		fprintf(stderr, +			"Could not get input file size: %s\n", pathname); +		goto cleanup; +	} + +	/* Allocate a buffer for the entire file */ + +	buffer = calloc(1, file_size); +	if (!buffer) { +		fprintf(stderr, +			"Could not allocate file buffer of size: %u\n", +			file_size); +		goto cleanup; +	} + +	/* Read the entire file */ + +	actual = fread(buffer, 1, file_size, file); +	if (actual != file_size) { +		fprintf(stderr, "Could not read input file: %s\n", pathname); +		free(buffer); +		buffer = NULL; +		goto cleanup; +	} + +	*out_file_size = file_size; + +cleanup: +	fclose(file); +	return (buffer); +} diff --git a/tools/power/acpi/tools/acpidump/apmain.c b/tools/power/acpi/tools/acpidump/apmain.c new file mode 100644 index 00000000000..51e8d638db1 --- /dev/null +++ b/tools/power/acpi/tools/acpidump/apmain.c @@ -0,0 +1,351 @@ +/****************************************************************************** + * + * Module Name: apmain - Main module for the acpidump utility + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2014, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + *    notice, this list of conditions, and the following disclaimer, + *    without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + *    substantially similar to the "NO WARRANTY" disclaimer below + *    ("Disclaimer") and any redistribution must be conditioned upon + *    including a substantially similar Disclaimer requirement for further + *    binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + *    of any contributors may be used to endorse or promote products derived + *    from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#define _DECLARE_GLOBALS +#include "acpidump.h" +#include "acapps.h" + +/* + * acpidump - A portable utility for obtaining system ACPI tables and dumping + * them in an ASCII hex format suitable for binary extraction via acpixtract. + * + * Obtaining the system ACPI tables is an OS-specific operation. + * + * This utility can be ported to any host operating system by providing a + * module containing system-specific versions of these interfaces: + * + *      acpi_os_get_table_by_address + *      acpi_os_get_table_by_index + *      acpi_os_get_table_by_name + * + * See the ACPICA Reference Guide for the exact definitions of these + * interfaces. Also, see these ACPICA source code modules for example + * implementations: + * + *      source/os_specific/service_layers/oswintbl.c + *      source/os_specific/service_layers/oslinuxtbl.c + */ + +/* Local prototypes */ + +static void ap_display_usage(void); + +static int ap_do_options(int argc, char **argv); + +static void ap_insert_action(char *argument, u32 to_be_done); + +/* Table for deferred actions from command line options */ + +struct ap_dump_action action_table[AP_MAX_ACTIONS]; +u32 current_action = 0; + +#define AP_UTILITY_NAME             "ACPI Binary Table Dump Utility" +#define AP_SUPPORTED_OPTIONS        "?a:bcf:hn:o:r:svxz" + +/****************************************************************************** + * + * FUNCTION:    ap_display_usage + * + * DESCRIPTION: Usage message for the acpi_dump utility + * + ******************************************************************************/ + +static void ap_display_usage(void) +{ + +	ACPI_USAGE_HEADER("acpidump [options]"); + +	ACPI_OPTION("-b", "Dump tables to binary files"); +	ACPI_OPTION("-c", "Dump customized tables"); +	ACPI_OPTION("-h -?", "This help message"); +	ACPI_OPTION("-o <File>", "Redirect output to file"); +	ACPI_OPTION("-r <Address>", "Dump tables from specified RSDP"); +	ACPI_OPTION("-s", "Print table summaries only"); +	ACPI_OPTION("-v", "Display version information"); +	ACPI_OPTION("-z", "Verbose mode"); + +	printf("\nTable Options:\n"); + +	ACPI_OPTION("-a <Address>", "Get table via a physical address"); +	ACPI_OPTION("-f <BinaryFile>", "Get table via a binary file"); +	ACPI_OPTION("-n <Signature>", "Get table via a name/signature"); +	ACPI_OPTION("-x", "Do not use but dump XSDT"); +	ACPI_OPTION("-x -x", "Do not use or dump XSDT"); + +	printf("\n" +	       "Invocation without parameters dumps all available tables\n" +	       "Multiple mixed instances of -a, -f, and -n are supported\n\n"); +} + +/****************************************************************************** + * + * FUNCTION:    ap_insert_action + * + * PARAMETERS:  argument            - Pointer to the argument for this action + *              to_be_done          - What to do to process this action + * + * RETURN:      None. Exits program if action table becomes full. + * + * DESCRIPTION: Add an action item to the action table + * + ******************************************************************************/ + +static void ap_insert_action(char *argument, u32 to_be_done) +{ + +	/* Insert action and check for table overflow */ + +	action_table[current_action].argument = argument; +	action_table[current_action].to_be_done = to_be_done; + +	current_action++; +	if (current_action > AP_MAX_ACTIONS) { +		fprintf(stderr, "Too many table options (max %u)\n", +			AP_MAX_ACTIONS); +		exit(-1); +	} +} + +/****************************************************************************** + * + * FUNCTION:    ap_do_options + * + * PARAMETERS:  argc/argv           - Standard argc/argv + * + * RETURN:      Status + * + * DESCRIPTION: Command line option processing. The main actions for getting + *              and dumping tables are deferred via the action table. + * + *****************************************************************************/ + +static int ap_do_options(int argc, char **argv) +{ +	int j; +	acpi_status status; + +	/* Command line options */ + +	while ((j = acpi_getopt(argc, argv, AP_SUPPORTED_OPTIONS)) != EOF) +		switch (j) { +			/* +			 * Global options +			 */ +		case 'b':	/* Dump all input tables to binary files */ + +			gbl_binary_mode = TRUE; +			continue; + +		case 'c':	/* Dump customized tables */ + +			gbl_dump_customized_tables = TRUE; +			continue; + +		case 'h': +		case '?': + +			ap_display_usage(); +			exit(0); + +		case 'o':	/* Redirect output to a single file */ + +			if (ap_open_output_file(acpi_gbl_optarg)) { +				exit(-1); +			} +			continue; + +		case 'r':	/* Dump tables from specified RSDP */ + +			status = +			    acpi_ut_strtoul64(acpi_gbl_optarg, 0, +					      &gbl_rsdp_base); +			if (ACPI_FAILURE(status)) { +				fprintf(stderr, +					"%s: Could not convert to a physical address\n", +					acpi_gbl_optarg); +				exit(-1); +			} +			continue; + +		case 's':	/* Print table summaries only */ + +			gbl_summary_mode = TRUE; +			continue; + +		case 'x':	/* Do not use XSDT */ + +			if (!acpi_gbl_do_not_use_xsdt) { +				acpi_gbl_do_not_use_xsdt = TRUE; +			} else { +				gbl_do_not_dump_xsdt = TRUE; +			} +			continue; + +		case 'v':	/* Revision/version */ + +			printf(ACPI_COMMON_SIGNON(AP_UTILITY_NAME)); +			exit(0); + +		case 'z':	/* Verbose mode */ + +			gbl_verbose_mode = TRUE; +			fprintf(stderr, ACPI_COMMON_SIGNON(AP_UTILITY_NAME)); +			continue; + +			/* +			 * Table options +			 */ +		case 'a':	/* Get table by physical address */ + +			ap_insert_action(acpi_gbl_optarg, +					 AP_DUMP_TABLE_BY_ADDRESS); +			break; + +		case 'f':	/* Get table from a file */ + +			ap_insert_action(acpi_gbl_optarg, +					 AP_DUMP_TABLE_BY_FILE); +			break; + +		case 'n':	/* Get table by input name (signature) */ + +			ap_insert_action(acpi_gbl_optarg, +					 AP_DUMP_TABLE_BY_NAME); +			break; + +		default: + +			ap_display_usage(); +			exit(-1); +		} + +	/* If there are no actions, this means "get/dump all tables" */ + +	if (current_action == 0) { +		ap_insert_action(NULL, AP_DUMP_ALL_TABLES); +	} + +	return (0); +} + +/****************************************************************************** + * + * FUNCTION:    main + * + * PARAMETERS:  argc/argv           - Standard argc/argv + * + * RETURN:      Status + * + * DESCRIPTION: C main function for acpidump utility + * + ******************************************************************************/ + +int ACPI_SYSTEM_XFACE main(int argc, char *argv[]) +{ +	int status = 0; +	struct ap_dump_action *action; +	u32 file_size; +	u32 i; + +	ACPI_DEBUG_INITIALIZE();	/* For debug version only */ + +	/* Process command line options */ + +	if (ap_do_options(argc, argv)) { +		return (-1); +	} + +	/* Get/dump ACPI table(s) as requested */ + +	for (i = 0; i < current_action; i++) { +		action = &action_table[i]; +		switch (action->to_be_done) { +		case AP_DUMP_ALL_TABLES: + +			status = ap_dump_all_tables(); +			break; + +		case AP_DUMP_TABLE_BY_ADDRESS: + +			status = ap_dump_table_by_address(action->argument); +			break; + +		case AP_DUMP_TABLE_BY_NAME: + +			status = ap_dump_table_by_name(action->argument); +			break; + +		case AP_DUMP_TABLE_BY_FILE: + +			status = ap_dump_table_from_file(action->argument); +			break; + +		default: + +			fprintf(stderr, +				"Internal error, invalid action: 0x%X\n", +				action->to_be_done); +			return (-1); +		} + +		if (status) { +			return (status); +		} +	} + +	if (gbl_output_file) { +		if (gbl_verbose_mode) { + +			/* Summary for the output file */ + +			file_size = cm_get_file_size(gbl_output_file); +			fprintf(stderr, +				"Output file %s contains 0x%X (%u) bytes\n\n", +				gbl_output_filename, file_size, file_size); +		} + +		fclose(gbl_output_file); +	} + +	return (status); +} diff --git a/tools/power/acpi/tools/ec/Makefile b/tools/power/acpi/tools/ec/Makefile new file mode 100644 index 00000000000..b7b0b929bd3 --- /dev/null +++ b/tools/power/acpi/tools/ec/Makefile @@ -0,0 +1,22 @@ +ec_access: ec_access.o +	$(ECHO) "  LD      " $@ +	$(QUIET) $(LD) $(CFLAGS) $(LDFLAGS) $< -o $@ +	$(QUIET) $(STRIPCMD) $@ + +%.o: %.c +	$(ECHO) "  CC      " $@ +	$(QUIET) $(CC) -c $(CFLAGS) -o $@ $< + +all: ec_access + +install: +	$(INSTALL) -d $(DESTDIR)${sbindir} +	$(INSTALL_PROGRAM) ec_access $(DESTDIR)${sbindir} + +uninstall: +	- rm -f $(DESTDIR)${sbindir}/ec_access + +clean: +	-rm -f $(OUTPUT)ec_access + +.PHONY: all install uninstall diff --git a/tools/power/acpi/tools/ec/ec_access.c b/tools/power/acpi/tools/ec/ec_access.c new file mode 100644 index 00000000000..6b8aaed44f2 --- /dev/null +++ b/tools/power/acpi/tools/ec/ec_access.c @@ -0,0 +1,238 @@ +/* + * ec_access.c + * + * Copyright (C) 2010 SUSE Linux Products GmbH + * Author: + *      Thomas Renninger <trenn@suse.de> + * + * This work is licensed under the terms of the GNU GPL, version 2. + */ + +#include <fcntl.h> +#include <err.h> +#include <stdio.h> +#include <stdlib.h> +#include <libgen.h> +#include <unistd.h> +#include <getopt.h> +#include <stdint.h> +#include <sys/types.h> +#include <sys/stat.h> + + +#define EC_SPACE_SIZE 256 +#define SYSFS_PATH "/sys/kernel/debug/ec/ec0/io" + +/* TBD/Enhancements: +   - Provide param for accessing different ECs (not supported by kernel yet) +*/ + +static int read_mode = -1; +static int sleep_time; +static int write_byte_offset = -1; +static int read_byte_offset = -1; +static uint8_t write_value = -1; + +void usage(char progname[], int exit_status) +{ +	printf("Usage:\n"); +	printf("1) %s -r [-s sleep]\n", basename(progname)); +	printf("2) %s -b byte_offset\n", basename(progname)); +	printf("3) %s -w byte_offset -v value\n\n", basename(progname)); + +	puts("\t-r [-s sleep]      : Dump EC registers"); +	puts("\t                     If sleep is given, sleep x seconds,"); +	puts("\t                     re-read EC registers and show changes"); +	puts("\t-b offset          : Read value at byte_offset (in hex)"); +	puts("\t-w offset -v value : Write value at byte_offset"); +	puts("\t-h                 : Print this help\n\n"); +	puts("Offsets and values are in hexadecimal number sytem."); +	puts("The offset and value must be between 0 and 0xff."); +	exit(exit_status); +} + +void parse_opts(int argc, char *argv[]) +{ +	int c; + +	while ((c = getopt(argc, argv, "rs:b:w:v:h")) != -1) { + +		switch (c) { +		case 'r': +			if (read_mode != -1) +				usage(argv[0], EXIT_FAILURE); +			read_mode = 1; +			break; +		case 's': +			if (read_mode != -1 && read_mode != 1) +				usage(argv[0], EXIT_FAILURE); + +			sleep_time = atoi(optarg); +			if (sleep_time <= 0) { +				sleep_time = 0; +				usage(argv[0], EXIT_FAILURE); +				printf("Bad sleep time: %s\n", optarg); +			} +			break; +		case 'b': +			if (read_mode != -1) +				usage(argv[0], EXIT_FAILURE); +			read_mode = 1; +			read_byte_offset = strtoul(optarg, NULL, 16); +			break; +		case 'w': +			if (read_mode != -1) +				usage(argv[0], EXIT_FAILURE); +			read_mode = 0; +			write_byte_offset = strtoul(optarg, NULL, 16); +			break; +		case 'v': +			write_value = strtoul(optarg, NULL, 16); +			break; +		case 'h': +			usage(argv[0], EXIT_SUCCESS); +		default: +			fprintf(stderr, "Unknown option!\n"); +			usage(argv[0], EXIT_FAILURE); +		} +	} +	if (read_mode == 0) { +		if (write_byte_offset < 0 || +		    write_byte_offset >= EC_SPACE_SIZE) { +			fprintf(stderr, "Wrong byte offset 0x%.2x, valid: " +				"[0-0x%.2x]\n", +				write_byte_offset, EC_SPACE_SIZE - 1); +			usage(argv[0], EXIT_FAILURE); +		} +		if (write_value < 0 || +		    write_value >= 255) { +			fprintf(stderr, "Wrong byte offset 0x%.2x, valid:" +				"[0-0xff]\n", write_byte_offset); +			usage(argv[0], EXIT_FAILURE); +		} +	} +	if (read_mode == 1 && read_byte_offset != -1) { +		if (read_byte_offset < -1 || +		    read_byte_offset >= EC_SPACE_SIZE) { +			fprintf(stderr, "Wrong byte offset 0x%.2x, valid: " +				"[0-0x%.2x]\n", +				read_byte_offset, EC_SPACE_SIZE - 1); +			usage(argv[0], EXIT_FAILURE); +		} +	} +	/* Add additional parameter checks here */ +} + +void dump_ec(int fd) +{ +	char buf[EC_SPACE_SIZE]; +	char buf2[EC_SPACE_SIZE]; +	int byte_off, bytes_read; + +	bytes_read = read(fd, buf, EC_SPACE_SIZE); + +	if (bytes_read == -1) +		err(EXIT_FAILURE, "Could not read from %s\n", SYSFS_PATH); + +	if (bytes_read != EC_SPACE_SIZE) +		fprintf(stderr, "Could only read %d bytes\n", bytes_read); + +	printf("     00  01  02  03  04  05  06  07  08  09  0A  0B  0C  0D  0E  0F"); +	for (byte_off = 0; byte_off < bytes_read; byte_off++) { +		if ((byte_off % 16) == 0) +			printf("\n%.2X: ", byte_off); +		printf(" %.2x ", (uint8_t)buf[byte_off]); +	} +	printf("\n"); + +	if (!sleep_time) +		return; + +	printf("\n"); +	lseek(fd, 0, SEEK_SET); +	sleep(sleep_time); + +	bytes_read = read(fd, buf2, EC_SPACE_SIZE); + +	if (bytes_read == -1) +		err(EXIT_FAILURE, "Could not read from %s\n", SYSFS_PATH); + +	if (bytes_read != EC_SPACE_SIZE) +		fprintf(stderr, "Could only read %d bytes\n", bytes_read); + +	printf("     00  01  02  03  04  05  06  07  08  09  0A  0B  0C  0D  0E  0F"); +	for (byte_off = 0; byte_off < bytes_read; byte_off++) { +		if ((byte_off % 16) == 0) +			printf("\n%.2X: ", byte_off); + +		if (buf[byte_off] == buf2[byte_off]) +			printf(" %.2x ", (uint8_t)buf2[byte_off]); +		else +			printf("*%.2x ", (uint8_t)buf2[byte_off]); +	} +	printf("\n"); +} + +void read_ec_val(int fd, int byte_offset) +{ +	uint8_t buf; +	int error; + +	error = lseek(fd, byte_offset, SEEK_SET); +	if (error != byte_offset) +		err(EXIT_FAILURE, "Cannot set offset to 0x%.2x", byte_offset); + +	error = read(fd, &buf, 1); +	if (error != 1) +		err(EXIT_FAILURE, "Could not read byte 0x%.2x from %s\n", +		    byte_offset, SYSFS_PATH); +	printf("0x%.2x\n", buf); +	return; +} + +void write_ec_val(int fd, int byte_offset, uint8_t value) +{ +	int error; + +	error = lseek(fd, byte_offset, SEEK_SET); +	if (error != byte_offset) +		err(EXIT_FAILURE, "Cannot set offset to 0x%.2x", byte_offset); + +	error = write(fd, &value, 1); +	if (error != 1) +		err(EXIT_FAILURE, "Cannot write value 0x%.2x to offset 0x%.2x", +		    value, byte_offset); +} + +int main(int argc, char *argv[]) +{ +	int file_mode = O_RDONLY; +	int fd; + +	parse_opts(argc, argv); + +	if (read_mode == 0) +		file_mode = O_WRONLY; +	else if (read_mode == 1) +		file_mode = O_RDONLY; +	else +		usage(argv[0], EXIT_FAILURE); + +	fd = open(SYSFS_PATH, file_mode); +	if (fd == -1) +		err(EXIT_FAILURE, "%s", SYSFS_PATH); + +	if (read_mode) +		if (read_byte_offset == -1) +			dump_ec(fd); +		else if (read_byte_offset < 0 || +			 read_byte_offset >= EC_SPACE_SIZE) +			usage(argv[0], EXIT_FAILURE); +		else +			read_ec_val(fd, read_byte_offset); +	else +		write_ec_val(fd, write_byte_offset, write_value); +	close(fd); + +	exit(EXIT_SUCCESS); +} diff --git a/tools/power/cpupower/.gitignore b/tools/power/cpupower/.gitignore new file mode 100644 index 00000000000..d42073f1260 --- /dev/null +++ b/tools/power/cpupower/.gitignore @@ -0,0 +1,29 @@ +.libs +libcpupower.so +libcpupower.so.0 +libcpupower.so.0.0.0 +build/ccdv +cpufreq-info +cpufreq-set +cpufreq-aperf +lib/.libs +lib/cpufreq.lo +lib/cpufreq.o +lib/proc.lo +lib/proc.o +lib/sysfs.lo +lib/sysfs.o +po/cpupowerutils.pot +po/*.gmo +utils/cpufreq-info.o +utils/cpufreq-set.o +utils/cpufreq-aperf.o +cpupower +bench/cpufreq-bench +debug/kernel/Module.symvers +debug/i386/centrino-decode +debug/i386/dump_psb +debug/i386/intel_gsic +debug/i386/powernow-k8-decode +debug/x86_64/centrino-decode +debug/x86_64/powernow-k8-decode diff --git a/tools/power/cpupower/Makefile b/tools/power/cpupower/Makefile new file mode 100644 index 00000000000..2e2ba2efa0d --- /dev/null +++ b/tools/power/cpupower/Makefile @@ -0,0 +1,310 @@ +# Makefile for cpupower +# +# Copyright (C) 2005,2006 Dominik Brodowski <linux@dominikbrodowski.net> +# +# Based largely on the Makefile for udev by: +# +# Copyright (C) 2003,2004 Greg Kroah-Hartman <greg@kroah.com> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +OUTPUT=./ +ifeq ("$(origin O)", "command line") +	OUTPUT := $(O)/ +endif + +ifneq ($(OUTPUT),) +# check that the output directory actually exists +OUTDIR := $(shell cd $(OUTPUT) && /bin/pwd) +$(if $(OUTDIR),, $(error output directory "$(OUTPUT)" does not exist)) +endif + +# --- CONFIGURATION BEGIN --- + +# Set the following to `true' to make a unstripped, unoptimized +# binary. Leave this set to `false' for production use. +DEBUG ?=	true + +# make the build silent. Set this to something else to make it noisy again. +V ?=		false + +# Internationalization support (output in different languages). +# Requires gettext. +NLS ?=		true + +# Set the following to 'true' to build/install the +# cpufreq-bench benchmarking tool +CPUFREQ_BENCH ?= true + +# Prefix to the directories we're installing to +DESTDIR ?= + +# --- CONFIGURATION END --- + + + +# Package-related definitions. Distributions can modify the version +# and _should_ modify the PACKAGE_BUGREPORT definition + +VERSION=			$(shell ./utils/version-gen.sh) +LIB_MAJ=			0.0.0 +LIB_MIN=			0 + +PACKAGE =			cpupower +PACKAGE_BUGREPORT =		linux-pm@vger.kernel.org +LANGUAGES = 			de fr it cs pt + + +# Directory definitions. These are default and most probably +# do not need to be changed. Please note that DESTDIR is +# added in front of any of them + +bindir ?=	/usr/bin +sbindir ?=	/usr/sbin +mandir ?=	/usr/man +includedir ?=	/usr/include +libdir ?=	/usr/lib +localedir ?=	/usr/share/locale +docdir ?=       /usr/share/doc/packages/cpupower +confdir ?=      /etc/ + +# Toolchain: what tools do we use, and what options do they need: + +CP = cp -fpR +INSTALL = /usr/bin/install -c +INSTALL_PROGRAM = ${INSTALL} +INSTALL_DATA  = ${INSTALL} -m 644 +INSTALL_SCRIPT = ${INSTALL_PROGRAM} + +# If you are running a cross compiler, you may want to set this +# to something more interesting, like "arm-linux-".  If you want +# to compile vs uClibc, that can be done here as well. +CROSS = #/usr/i386-linux-uclibc/usr/bin/i386-uclibc- +CC = $(CROSS)gcc +LD = $(CROSS)gcc +AR = $(CROSS)ar +STRIP = $(CROSS)strip +RANLIB = $(CROSS)ranlib +HOSTCC = gcc +MKDIR = mkdir + + +# Now we set up the build system +# + +# set up PWD so that older versions of make will work with our build. +PWD = $(shell pwd) + +GMO_FILES = ${shell for HLANG in ${LANGUAGES}; do echo $(OUTPUT)po/$$HLANG.gmo; done;} + +export CROSS CC AR STRIP RANLIB CFLAGS LDFLAGS LIB_OBJS + +# check if compiler option is supported +cc-supports = ${shell if $(CC) ${1} -S -o /dev/null -x c /dev/null > /dev/null 2>&1; then echo "$(1)"; fi;} + +# use '-Os' optimization if available, else use -O2 +OPTIMIZATION := $(call cc-supports,-Os,-O2) + +WARNINGS := -Wall -Wchar-subscripts -Wpointer-arith -Wsign-compare +WARNINGS += $(call cc-supports,-Wno-pointer-sign) +WARNINGS += $(call cc-supports,-Wdeclaration-after-statement) +WARNINGS += -Wshadow + +CFLAGS += -DVERSION=\"$(VERSION)\" -DPACKAGE=\"$(PACKAGE)\" \ +		-DPACKAGE_BUGREPORT=\"$(PACKAGE_BUGREPORT)\" -D_GNU_SOURCE + +UTIL_OBJS =  utils/helpers/amd.o utils/helpers/topology.o utils/helpers/msr.o \ +	utils/helpers/sysfs.o utils/helpers/misc.o utils/helpers/cpuid.o \ +	utils/helpers/pci.o utils/helpers/bitmask.o \ +	utils/idle_monitor/nhm_idle.o utils/idle_monitor/snb_idle.o \ +	utils/idle_monitor/hsw_ext_idle.o \ +	utils/idle_monitor/amd_fam14h_idle.o utils/idle_monitor/cpuidle_sysfs.o \ +	utils/idle_monitor/mperf_monitor.o utils/idle_monitor/cpupower-monitor.o \ +	utils/cpupower.o utils/cpufreq-info.o utils/cpufreq-set.o \ +	utils/cpupower-set.o utils/cpupower-info.o utils/cpuidle-info.o \ +	utils/cpuidle-set.o + +UTIL_SRC := $(UTIL_OBJS:.o=.c) + +UTIL_OBJS := $(addprefix $(OUTPUT),$(UTIL_OBJS)) + +UTIL_HEADERS = utils/helpers/helpers.h utils/idle_monitor/cpupower-monitor.h \ +	utils/helpers/bitmask.h \ +	utils/idle_monitor/idle_monitors.h utils/idle_monitor/idle_monitors.def + +LIB_HEADERS = 	lib/cpufreq.h lib/sysfs.h +LIB_SRC = 	lib/cpufreq.c lib/sysfs.c +LIB_OBJS = 	lib/cpufreq.o lib/sysfs.o +LIB_OBJS :=	$(addprefix $(OUTPUT),$(LIB_OBJS)) + +CFLAGS +=	-pipe + +ifeq ($(strip $(NLS)),true) +	INSTALL_NLS += install-gmo +	COMPILE_NLS += create-gmo +	CFLAGS += -DNLS +endif + +ifeq ($(strip $(CPUFREQ_BENCH)),true) +	INSTALL_BENCH += install-bench +	COMPILE_BENCH += compile-bench +endif + +CFLAGS += $(WARNINGS) + +ifeq ($(strip $(V)),false) +	QUIET=@ +	ECHO=@echo +else +	QUIET= +	ECHO=@\# +endif +export QUIET ECHO + +# if DEBUG is enabled, then we do not strip or optimize +ifeq ($(strip $(DEBUG)),true) +	CFLAGS += -O1 -g -DDEBUG +	STRIPCMD = /bin/true -Since_we_are_debugging +else +	CFLAGS += $(OPTIMIZATION) -fomit-frame-pointer +	STRIPCMD = $(STRIP) -s --remove-section=.note --remove-section=.comment +endif + + +# the actual make rules + +all: libcpupower $(OUTPUT)cpupower $(COMPILE_NLS) $(COMPILE_BENCH) + +$(OUTPUT)lib/%.o: $(LIB_SRC) $(LIB_HEADERS) +	$(ECHO) "  CC      " $@ +	$(QUIET) $(CC) $(CFLAGS) -fPIC -o $@ -c lib/$*.c + +$(OUTPUT)libcpupower.so.$(LIB_MAJ): $(LIB_OBJS) +	$(ECHO) "  LD      " $@ +	$(QUIET) $(CC) -shared $(CFLAGS) $(LDFLAGS) -o $@ \ +		-Wl,-soname,libcpupower.so.$(LIB_MIN) $(LIB_OBJS) +	@ln -sf $(@F) $(OUTPUT)libcpupower.so +	@ln -sf $(@F) $(OUTPUT)libcpupower.so.$(LIB_MIN) + +libcpupower: $(OUTPUT)libcpupower.so.$(LIB_MAJ) + +# Let all .o files depend on its .c file and all headers +# Might be worth to put this into utils/Makefile at some point of time +$(UTIL_OBJS): $(UTIL_HEADERS) + +$(OUTPUT)%.o: %.c +	$(ECHO) "  CC      " $@ +	$(QUIET) $(CC) $(CFLAGS) -I./lib -I ./utils -o $@ -c $*.c + +$(OUTPUT)cpupower: $(UTIL_OBJS) $(OUTPUT)libcpupower.so.$(LIB_MAJ) +	$(ECHO) "  CC      " $@ +	$(QUIET) $(CC) $(CFLAGS) $(LDFLAGS) $(UTIL_OBJS) -lcpupower -lrt -lpci -L$(OUTPUT) -o $@ +	$(QUIET) $(STRIPCMD) $@ + +$(OUTPUT)po/$(PACKAGE).pot: $(UTIL_SRC) +	$(ECHO) "  GETTEXT " $@ +	$(QUIET) xgettext --default-domain=$(PACKAGE) --add-comments \ +		--keyword=_ --keyword=N_ $(UTIL_SRC) -p $(@D) -o $(@F) + +$(OUTPUT)po/%.gmo: po/%.po +	$(ECHO) "  MSGFMT  " $@ +	$(QUIET) msgfmt -o $@ po/$*.po + +create-gmo: ${GMO_FILES} + +update-po: $(OUTPUT)po/$(PACKAGE).pot +	$(ECHO) "  MSGMRG  " $@ +	$(QUIET) @for HLANG in $(LANGUAGES); do \ +		echo -n "Updating $$HLANG "; \ +		if msgmerge po/$$HLANG.po $< -o \ +		   $(OUTPUT)po/$$HLANG.new.po; then \ +			mv -f $(OUTPUT)po/$$HLANG.new.po $(OUTPUT)po/$$HLANG.po; \ +		else \ +			echo "msgmerge for $$HLANG failed!"; \ +			rm -f $(OUTPUT)po/$$HLANG.new.po; \ +		fi; \ +	done; + +compile-bench: $(OUTPUT)libcpupower.so.$(LIB_MAJ) +	@V=$(V) confdir=$(confdir) $(MAKE) -C bench O=$(OUTPUT) + +# we compile into subdirectories. if the target directory is not the +# source directory, they might not exists. So we depend the various +# files onto their directories. +DIRECTORY_DEPS = $(LIB_OBJS) $(UTIL_OBJS) $(GMO_FILES) +$(DIRECTORY_DEPS): | $(sort $(dir $(DIRECTORY_DEPS))) + +# In the second step, we make a rule to actually create these directories +$(sort $(dir $(DIRECTORY_DEPS))): +	$(ECHO) "  MKDIR      " $@ +	$(QUIET) $(MKDIR) -p $@ 2>/dev/null + +clean: +	-find $(OUTPUT) \( -not -type d \) -and \( -name '*~' -o -name '*.[oas]' \) -type f -print \ +	 | xargs rm -f +	-rm -f $(OUTPUT)cpupower +	-rm -f $(OUTPUT)libcpupower.so* +	-rm -rf $(OUTPUT)po/*.gmo +	-rm -rf $(OUTPUT)po/*.pot +	$(MAKE) -C bench O=$(OUTPUT) clean + + +install-lib: +	$(INSTALL) -d $(DESTDIR)${libdir} +	$(CP) $(OUTPUT)libcpupower.so* $(DESTDIR)${libdir}/ +	$(INSTALL) -d $(DESTDIR)${includedir} +	$(INSTALL_DATA) lib/cpufreq.h $(DESTDIR)${includedir}/cpufreq.h + +install-tools: +	$(INSTALL) -d $(DESTDIR)${bindir} +	$(INSTALL_PROGRAM) $(OUTPUT)cpupower $(DESTDIR)${bindir} + +install-man: +	$(INSTALL_DATA) -D man/cpupower.1 $(DESTDIR)${mandir}/man1/cpupower.1 +	$(INSTALL_DATA) -D man/cpupower-frequency-set.1 $(DESTDIR)${mandir}/man1/cpupower-frequency-set.1 +	$(INSTALL_DATA) -D man/cpupower-frequency-info.1 $(DESTDIR)${mandir}/man1/cpupower-frequency-info.1 +	$(INSTALL_DATA) -D man/cpupower-idle-set.1 $(DESTDIR)${mandir}/man1/cpupower-idle-set.1 +	$(INSTALL_DATA) -D man/cpupower-idle-info.1 $(DESTDIR)${mandir}/man1/cpupower-idle-info.1 +	$(INSTALL_DATA) -D man/cpupower-set.1 $(DESTDIR)${mandir}/man1/cpupower-set.1 +	$(INSTALL_DATA) -D man/cpupower-info.1 $(DESTDIR)${mandir}/man1/cpupower-info.1 +	$(INSTALL_DATA) -D man/cpupower-monitor.1 $(DESTDIR)${mandir}/man1/cpupower-monitor.1 + +install-gmo: +	$(INSTALL) -d $(DESTDIR)${localedir} +	for HLANG in $(LANGUAGES); do \ +		echo '$(INSTALL_DATA) -D $(OUTPUT)po/$$HLANG.gmo $(DESTDIR)${localedir}/$$HLANG/LC_MESSAGES/cpupower.mo'; \ +		$(INSTALL_DATA) -D $(OUTPUT)po/$$HLANG.gmo $(DESTDIR)${localedir}/$$HLANG/LC_MESSAGES/cpupower.mo; \ +	done; + +install-bench: +	@#DESTDIR must be set from outside to survive +	@sbindir=$(sbindir) bindir=$(bindir) docdir=$(docdir) confdir=$(confdir) $(MAKE) -C bench O=$(OUTPUT) install + +install: all install-lib install-tools install-man $(INSTALL_NLS) $(INSTALL_BENCH) + +uninstall: +	- rm -f $(DESTDIR)${libdir}/libcpupower.* +	- rm -f $(DESTDIR)${includedir}/cpufreq.h +	- rm -f $(DESTDIR)${bindir}/utils/cpupower +	- rm -f $(DESTDIR)${mandir}/man1/cpupower.1 +	- rm -f $(DESTDIR)${mandir}/man1/cpupower-frequency-set.1 +	- rm -f $(DESTDIR)${mandir}/man1/cpupower-frequency-info.1 +	- rm -f $(DESTDIR)${mandir}/man1/cpupower-set.1 +	- rm -f $(DESTDIR)${mandir}/man1/cpupower-info.1 +	- rm -f $(DESTDIR)${mandir}/man1/cpupower-monitor.1 +	- for HLANG in $(LANGUAGES); do \ +		rm -f $(DESTDIR)${localedir}/$$HLANG/LC_MESSAGES/cpupower.mo; \ +	  done; + +.PHONY: all utils libcpupower update-po create-gmo install-lib install-tools install-man install-gmo install uninstall clean diff --git a/tools/power/cpupower/README b/tools/power/cpupower/README new file mode 100644 index 00000000000..1c68f47663b --- /dev/null +++ b/tools/power/cpupower/README @@ -0,0 +1,47 @@ +The cpupower package consists of the following elements: + +requirements +------------ + +On x86 pciutils is needed at runtime (-lpci). +For compilation pciutils-devel (pci/pci.h) and a gcc version +providing cpuid.h is needed. +For both it's not explicitly checked for (yet). + + +libcpupower +---------- + +"libcpupower" is a library which offers a unified access method for userspace +tools and programs to the cpufreq core and drivers in the Linux kernel. This +allows for code reduction in userspace tools, a clean implementation of +the interaction to the cpufreq core, and support for both the sysfs and proc +interfaces [depending on configuration, see below]. + + +compilation and installation +---------------------------- + +make +su +make install + +should suffice on most systems. It builds libcpupower to put in +/usr/lib; cpupower, cpufreq-bench_plot.sh to put in /usr/bin; and +cpufreq-bench to put in /usr/sbin. If you want to set up the paths +differently and/or want to configure the package to your specific +needs, you need to open "Makefile" with an editor of your choice and +edit the block marked CONFIGURATION. + + +THANKS +------ +Many thanks to Mattia Dongili who wrote the autotoolization and +libtoolization, the manpages and the italian language file for cpupower; +to Dave Jones for his feedback and his dump_psb tool; to Bruno Ducrot for his +powernow-k8-decode and intel_gsic tools as well as the french language file; +and to various others commenting on the previous (pre-)releases of  +cpupower. + + +        Dominik Brodowski diff --git a/tools/power/cpupower/ToDo b/tools/power/cpupower/ToDo new file mode 100644 index 00000000000..6e8b89f282e --- /dev/null +++ b/tools/power/cpupower/ToDo @@ -0,0 +1,10 @@ +ToDos sorted by priority: + +- Use bitmask functions to parse CPU topology more robust +  (current implementation has issues on AMD) +- Try to read out boost states and frequencies on Intel +- Somewhere saw the ability to read power consumption of +  RAM from HW on Intel SandyBridge -> another monitor? +- Add another c1e debug idle monitor +  -> Is by design racy with BIOS, but could be added +     with a --force option and some "be careful" messages diff --git a/tools/power/cpupower/bench/Makefile b/tools/power/cpupower/bench/Makefile new file mode 100644 index 00000000000..7ec7021a29c --- /dev/null +++ b/tools/power/cpupower/bench/Makefile @@ -0,0 +1,36 @@ +OUTPUT := ./ +ifeq ("$(origin O)", "command line") +ifneq ($(O),) +	OUTPUT := $(O)/ +endif +endif + +LIBS = -L../ -L$(OUTPUT) -lm -lcpupower + +OBJS = $(OUTPUT)main.o $(OUTPUT)parse.o $(OUTPUT)system.o $(OUTPUT)benchmark.o +CFLAGS += -D_GNU_SOURCE -I../lib -DDEFAULT_CONFIG_FILE=\"$(confdir)/cpufreq-bench.conf\" + +$(OUTPUT)%.o : %.c +	$(ECHO) "  CC      " $@ +	$(QUIET) $(CC) -c $(CFLAGS) $< -o $@ + +$(OUTPUT)cpufreq-bench: $(OBJS) +	$(ECHO) "  CC      " $@ +	$(QUIET) $(CC) -o $@ $(CFLAGS) $(OBJS) $(LIBS) + +all: $(OUTPUT)cpufreq-bench + +install: +	mkdir -p $(DESTDIR)/$(sbindir) +	mkdir -p $(DESTDIR)/$(bindir) +	mkdir -p $(DESTDIR)/$(docdir) +	mkdir -p $(DESTDIR)/$(confdir) +	install -m 755 $(OUTPUT)cpufreq-bench $(DESTDIR)/$(sbindir)/cpufreq-bench +	install -m 755 cpufreq-bench_plot.sh $(DESTDIR)/$(bindir)/cpufreq-bench_plot.sh +	install -m 644 README-BENCH $(DESTDIR)/$(docdir)/README-BENCH +	install -m 755 cpufreq-bench_script.sh $(DESTDIR)/$(docdir)/cpufreq-bench_script.sh +	install -m 644 example.cfg $(DESTDIR)/$(confdir)/cpufreq-bench.conf + +clean: +	rm -f $(OUTPUT)*.o +	rm -f $(OUTPUT)cpufreq-bench diff --git a/tools/power/cpupower/bench/README-BENCH b/tools/power/cpupower/bench/README-BENCH new file mode 100644 index 00000000000..8093ec73817 --- /dev/null +++ b/tools/power/cpupower/bench/README-BENCH @@ -0,0 +1,124 @@ +This is cpufreq-bench, a microbenchmark for the cpufreq framework. + +Purpose +======= + +What is this benchmark for: +  - Identify worst case performance loss when doing dynamic frequency +    scaling using Linux kernel governors +  - Identify average reaction time of a governor to CPU load changes +  - (Stress) Testing whether a cpufreq low level driver or governor works +    as expected +  - Identify cpufreq related performance regressions between kernels +  - Possibly Real time priority testing? -> what happens if there are +    processes with a higher prio than the governor's kernel thread +  - ... + +What this benchmark does *not* cover: +  - Power saving related regressions (In fact as better the performance +    throughput is, the worse the power savings will be, but the first should +    mostly count more...) +  - Real world (workloads) + + +Description +=========== + +cpufreq-bench helps to test the condition of a given cpufreq governor. +For that purpose, it compares the performance governor to a configured +powersave module. + + +How it works +============ +You can specify load (100% CPU load) and sleep (0% CPU load) times in us which +will be run X time in a row (cycles): + +         sleep=25000 +         load=25000 +         cycles=20 + +This part of the configuration file will create 25ms load/sleep turns, +repeated 20 times. + +Adding this: +         sleep_step=25000 +         load_step=25000 +         rounds=5 +Will increase load and sleep time by 25ms 5 times. +Together you get following test: +25ms  load/sleep time repeated 20 times (cycles). +50ms  load/sleep time repeated 20 times (cycles). +.. +100ms load/sleep time repeated 20 times (cycles). + +First it is calibrated how long a specific CPU intensive calculation +takes on this machine and needs to be run in a loop using the performance +governor. +Then the above test runs are processed using the performance governor +and the governor to test. The time the calculation really needed +with the dynamic freq scaling governor is compared with the time needed +on full performance and you get the overall performance loss. + + +Example of expected results with ondemand governor: + +This shows expected results of the first two test run rounds from +above config, you there have: + +100% CPU load (load) | 0 % CPU load (sleep)  | round +   25 ms             |    25 ms              |   1 +   50 ms             |    50 ms              |   2 + +For example if ondemand governor is configured to have a 50ms +sampling rate you get: + +In round 1, ondemand should have rather static 50% load and probably +won't ever switch up (as long as up_threshold is above). + +In round 2, if the ondemand sampling times exactly match the load/sleep +trigger of the cpufreq-bench, you will see no performance loss (compare with +below possible ondemand sample kick ins (1)): + +But if ondemand always kicks in in the middle of the load sleep cycles, it +will always see 50% loads and you get worst performance impact never +switching up (compare with below possible ondemand sample kick ins (2)):: + +      50     50   50   50ms ->time +load -----|     |-----|     |-----|     |-----| +          |     |     |     |     |     |     | +sleep     |-----|     |-----|     |-----|     |---- +    |-----|-----|-----|-----|-----|-----|-----|----  ondemand sampling (1) +         100    0    100    0    100    0    100     load seen by ondemand(%) +       |-----|-----|-----|-----|-----|-----|-----|--   ondemand sampling (2) +      50     50    50    50    50    50    50        load seen by ondemand(%) + +You can easily test all kind of load/sleep times and check whether your +governor in average behaves as expected. + + +ToDo +==== + +Provide a gnuplot utility script for easy generation of plots to present +the outcome nicely. + + +cpufreq-bench Command Usage +=========================== +-l, --load=<long int>           initial load time in us +-s, --sleep=<long int>          initial sleep time in us +-x, --load-step=<long int>      time to be added to load time, in us +-y, --sleep-step=<long int>     time to be added to sleep time, in us +-c, --cpu=<unsigned int>        CPU Number to use, starting at 0 +-p, --prio=<priority>           scheduler priority, HIGH, LOW or DEFAULT +-g, --governor=<governor>       cpufreq governor to test +-n, --cycles=<int>              load/sleep cycles to get an avarage value to compare +-r, --rounds<int>               load/sleep rounds +-f, --file=<configfile>         config file to use +-o, --output=<dir>              output dir, must exist +-v, --verbose                   verbose output on/off + +Due to the high priority, the application may not be responsible for some time. +After the benchmark, the logfile is saved in OUTPUTDIR/benchmark_TIMESTAMP.log + diff --git a/tools/power/cpupower/bench/benchmark.c b/tools/power/cpupower/bench/benchmark.c new file mode 100644 index 00000000000..81b1c48607d --- /dev/null +++ b/tools/power/cpupower/bench/benchmark.c @@ -0,0 +1,194 @@ +/*  cpufreq-bench CPUFreq microbenchmark + * + *  Copyright (C) 2008 Christian Kornacker <ckornacker@suse.de> + * + *  This program is free software; you can redistribute it and/or modify + *  it under the terms of the GNU General Public License as published by + *  the Free Software Foundation; either version 2 of the License, or + *  (at your option) any later version. + * + *  This program is distributed in the hope that it will be useful, + *  but WITHOUT ANY WARRANTY; without even the implied warranty of + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *  GNU General Public License for more details. + * + *  You should have received a copy of the GNU General Public License + *  along with this program; if not, write to the Free Software + *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include <stdio.h> +#include <unistd.h> +#include <math.h> + +#include "config.h" +#include "system.h" +#include "benchmark.h" + +/* Print out progress if we log into a file */ +#define show_progress(total_time, progress_time)	\ +if (config->output != stdout) {				\ +	fprintf(stdout, "Progress: %02lu %%\r",		\ +		(progress_time * 100) / total_time);	\ +	fflush(stdout);					\ +} + +/** + * compute how many rounds of calculation we should do + * to get the given load time + * + * @param load aimed load time in µs + * + * @retval rounds of calculation + **/ + +unsigned int calculate_timespace(long load, struct config *config) +{ +	int i; +	long long now, then; +	unsigned int estimated = GAUGECOUNT; +	unsigned int rounds = 0; +	unsigned int timed = 0; + +	if (config->verbose) +		printf("calibrating load of %lius, please wait...\n", load); + +	/* get the initial calculation time for a specific number of rounds */ +	now = get_time(); +	ROUNDS(estimated); +	then = get_time(); + +	timed = (unsigned int)(then - now); + +	/* approximation of the wanted load time by comparing with the +	 * initial calculation time */ +	for (i = 0; i < 4; i++) { +		rounds = (unsigned int)(load * estimated / timed); +		dprintf("calibrating with %u rounds\n", rounds); +		now = get_time(); +		ROUNDS(rounds); +		then = get_time(); + +		timed = (unsigned int)(then - now); +		estimated = rounds; +	} +	if (config->verbose) +		printf("calibration done\n"); + +	return estimated; +} + +/** + * benchmark + * generates a specific sleep an load time with the performance + * governor and compares the used time for same calculations done + * with the configured powersave governor + * + * @param config config values for the benchmark + * + **/ + +void start_benchmark(struct config *config) +{ +	unsigned int _round, cycle; +	long long now, then; +	long sleep_time = 0, load_time = 0; +	long performance_time = 0, powersave_time = 0; +	unsigned int calculations; +	unsigned long total_time = 0, progress_time = 0; + +	sleep_time = config->sleep; +	load_time = config->load; + +	/* For the progress bar */ +	for (_round = 1; _round <= config->rounds; _round++) +		total_time += _round * (config->sleep + config->load); +	total_time *= 2; /* powersave and performance cycles */ + +	for (_round = 0; _round < config->rounds; _round++) { +		performance_time = 0LL; +		powersave_time = 0LL; + +		show_progress(total_time, progress_time); + +		/* set the cpufreq governor to "performance" which disables +		 * P-State switching. */ +		if (set_cpufreq_governor("performance", config->cpu) != 0) +			return; + +		/* calibrate the calculation time. the resulting calculation +		 * _rounds should produce a load which matches the configured +		 * load time */ +		calculations = calculate_timespace(load_time, config); + +		if (config->verbose) +			printf("_round %i: doing %u cycles with %u calculations" +			       " for %lius\n", _round + 1, config->cycles, +			       calculations, load_time); + +		fprintf(config->output, "%u %li %li ", +			_round, load_time, sleep_time); + +		if (config->verbose) +			printf("avarage: %lius, rps:%li\n", +				load_time / calculations, +				1000000 * calculations / load_time); + +		/* do some sleep/load cycles with the performance governor */ +		for (cycle = 0; cycle < config->cycles; cycle++) { +			now = get_time(); +			usleep(sleep_time); +			ROUNDS(calculations); +			then = get_time(); +			performance_time += then - now - sleep_time; +			if (config->verbose) +				printf("performance cycle took %lius, " +					"sleep: %lius, " +					"load: %lius, rounds: %u\n", +					(long)(then - now), sleep_time, +					load_time, calculations); +		} +		fprintf(config->output, "%li ", +			performance_time / config->cycles); + +		progress_time += sleep_time + load_time; +		show_progress(total_time, progress_time); + +		/* set the powersave governor which activates P-State switching +		 * again */ +		if (set_cpufreq_governor(config->governor, config->cpu) != 0) +			return; + +		/* again, do some sleep/load cycles with the +		 * powersave governor */ +		for (cycle = 0; cycle < config->cycles; cycle++) { +			now = get_time(); +			usleep(sleep_time); +			ROUNDS(calculations); +			then = get_time(); +			powersave_time += then - now - sleep_time; +			if (config->verbose) +				printf("powersave cycle took %lius, " +					"sleep: %lius, " +					"load: %lius, rounds: %u\n", +					(long)(then - now), sleep_time, +					load_time, calculations); +		} + +		progress_time += sleep_time + load_time; + +		/* compare the avarage sleep/load cycles  */ +		fprintf(config->output, "%li ", +			powersave_time / config->cycles); +		fprintf(config->output, "%.3f\n", +			performance_time * 100.0 / powersave_time); +		fflush(config->output); + +		if (config->verbose) +			printf("performance is at %.2f%%\n", +				performance_time * 100.0 / powersave_time); + +		sleep_time += config->sleep_step; +		load_time += config->load_step; +	} +} diff --git a/tools/power/cpupower/bench/benchmark.h b/tools/power/cpupower/bench/benchmark.h new file mode 100644 index 00000000000..51d7f50ac2b --- /dev/null +++ b/tools/power/cpupower/bench/benchmark.h @@ -0,0 +1,29 @@ +/*  cpufreq-bench CPUFreq microbenchmark + * + *  Copyright (C) 2008 Christian Kornacker <ckornacker@suse.de> + * + *  This program is free software; you can redistribute it and/or modify + *  it under the terms of the GNU General Public License as published by + *  the Free Software Foundation; either version 2 of the License, or + *  (at your option) any later version. + * + *  This program is distributed in the hope that it will be useful, + *  but WITHOUT ANY WARRANTY; without even the implied warranty of + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *  GNU General Public License for more details. + * + *  You should have received a copy of the GNU General Public License + *  along with this program; if not, write to the Free Software + *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* load loop, this schould take about 1 to 2ms to complete */ +#define ROUNDS(x) {unsigned int rcnt;			       \ +		for (rcnt = 0; rcnt < x*1000; rcnt++) { \ +			(void)(((int)(pow(rcnt, rcnt) * \ +				      sqrt(rcnt*7230970)) ^ 7230716) ^ \ +				      (int)atan2(rcnt, rcnt));	       \ +		} }							\ + + +void start_benchmark(struct config *config); diff --git a/tools/power/cpupower/bench/config.h b/tools/power/cpupower/bench/config.h new file mode 100644 index 00000000000..ee6f258e533 --- /dev/null +++ b/tools/power/cpupower/bench/config.h @@ -0,0 +1,36 @@ +/*  cpufreq-bench CPUFreq microbenchmark + * + *  Copyright (C) 2008 Christian Kornacker <ckornacker@suse.de> + * + *  This program is free software; you can redistribute it and/or modify + *  it under the terms of the GNU General Public License as published by + *  the Free Software Foundation; either version 2 of the License, or + *  (at your option) any later version. + * + *  This program is distributed in the hope that it will be useful, + *  but WITHOUT ANY WARRANTY; without even the implied warranty of + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *  GNU General Public License for more details. + * + *  You should have received a copy of the GNU General Public License + *  along with this program; if not, write to the Free Software + *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* initial loop count for the load calibration */ +#define GAUGECOUNT	1500 + +/* default scheduling policy SCHED_OTHER */ +#define SCHEDULER	SCHED_OTHER + +#define PRIORITY_DEFAULT 0 +#define PRIORITY_HIGH	 sched_get_priority_max(SCHEDULER) +#define PRIORITY_LOW	 sched_get_priority_min(SCHEDULER) + +/* enable further debug messages */ +#ifdef DEBUG +#define dprintf printf +#else +#define dprintf(...) do { } while (0) +#endif + diff --git a/tools/power/cpupower/bench/cpufreq-bench_plot.sh b/tools/power/cpupower/bench/cpufreq-bench_plot.sh new file mode 100644 index 00000000000..410021a12f4 --- /dev/null +++ b/tools/power/cpupower/bench/cpufreq-bench_plot.sh @@ -0,0 +1,104 @@ +#!/bin/bash + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301, USA. + +# Author/Copyright(c): 2009, Thomas Renninger <trenn@suse.de>, Novell Inc. + +# Helper script to easily create nice plots of your cpufreq-bench results + +dir=`mktemp -d` +output_file="cpufreq-bench.png" +global_title="cpufreq-bench plot" +picture_type="jpeg" +file[0]="" + +function usage() +{ +    echo "cpufreq-bench_plot.sh [OPTIONS] logfile [measure_title] [logfile [measure_title]] ...]" +    echo +    echo "Options" +    echo "   -o output_file" +    echo "   -t global_title" +    echo "   -p picture_type [jpeg|gif|png|postscript|...]" +    exit 1 +} + +if [ $# -eq 0 ];then +	echo "No benchmark results file provided" +	echo +	usage +fi + +while getopts o:t:p: name ; do +    case $name in +	o) +	    output_file="$OPTARG".$picture_type +	    ;; +	t) +	    global_title="$OPTARG" +	    ;; +	p) +	    picture_type="$OPTARG" +	    ;; +        ?) +	    usage +	    ;; +    esac +done +shift $(($OPTIND -1)) + +plots=0 +while [ "$1" ];do +    if [ ! -f "$1" ];then +	echo "File $1 does not exist" +	usage +    fi +    file[$plots]="$1" +    title[$plots]="$2" +    # echo "File: ${file[$plots]} - ${title[plots]}" +    shift;shift +    plots=$((plots + 1)) +done + +echo "set terminal $picture_type"	>> $dir/plot_script.gpl +echo "set output \"$output_file\""	>> $dir/plot_script.gpl +echo "set title \"$global_title\""	>> $dir/plot_script.gpl +echo "set xlabel \"sleep/load time\""	>> $dir/plot_script.gpl +echo "set ylabel \"Performance (%)\""	>> $dir/plot_script.gpl + +for((plot=0;plot<$plots;plot++));do + +    # Sanity check +    ###### I am to dump to get this redirected to stderr/stdout in one awk call... ##### +    cat ${file[$plot]} |grep -v "^#" |awk '{if ($2 != $3) printf("Error in measure %d:Load time %s does not equal sleep time %s, plot will not be correct\n", $1, $2, $3); ERR=1}' +    ###### I am to dump to get this redirected in one awk call... ##### + +    # Parse out load time (which must be equal to sleep time for a plot), divide it by 1000 +    # to get ms and parse out the performance in percentage and write it to a temp file for plotting +    cat ${file[$plot]} |grep -v "^#" |awk '{printf "%lu %.1f\n",$2/1000, $6}' >$dir/data_$plot + +    if [ $plot -eq 0 ];then +	echo -n "plot " >> $dir/plot_script.gpl +    fi +    echo -n "\"$dir/data_$plot\" title \"${title[$plot]}\" with lines" >> $dir/plot_script.gpl +    if [ $(($plot + 1)) -ne $plots ];then +	echo -n ", " >> $dir/plot_script.gpl +    fi +done +echo >> $dir/plot_script.gpl + +gnuplot $dir/plot_script.gpl +rm -r $dir
\ No newline at end of file diff --git a/tools/power/cpupower/bench/cpufreq-bench_script.sh b/tools/power/cpupower/bench/cpufreq-bench_script.sh new file mode 100644 index 00000000000..de20d2a0687 --- /dev/null +++ b/tools/power/cpupower/bench/cpufreq-bench_script.sh @@ -0,0 +1,101 @@ +#!/bin/bash + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301, USA. + +# Author/Copyright(c): 2009, Thomas Renninger <trenn@suse.de>, Novell Inc. + +# Ondemand up_threshold and sampling rate test script for cpufreq-bench +# mircobenchmark. +# Modify the general variables at the top or extend or copy out parts +# if you want to test other things +# + +# Default with latest kernels is 95, before micro account patches +# it was 80, cmp. with git commit 808009131046b62ac434dbc796 +UP_THRESHOLD="60 80 95" +# Depending on the kernel and the HW sampling rate could be restricted +# and cannot be set that low... +# E.g. before git commit cef9615a853ebc4972084f7 one could only set +# min sampling rate of 80000 if CONFIG_HZ=250 +SAMPLING_RATE="20000 80000" + +function measure() +{ +    local -i up_threshold_set +    local -i sampling_rate_set + +    for up_threshold in $UP_THRESHOLD;do +	for sampling_rate in $SAMPLING_RATE;do +	    # Set values in sysfs +	    echo $up_threshold >/sys/devices/system/cpu/cpu0/cpufreq/ondemand/up_threshold +	    echo $sampling_rate >/sys/devices/system/cpu/cpu0/cpufreq/ondemand/sampling_rate +	    up_threshold_set=$(cat /sys/devices/system/cpu/cpu0/cpufreq/ondemand/up_threshold) +	    sampling_rate_set=$(cat /sys/devices/system/cpu/cpu0/cpufreq/ondemand/sampling_rate) + +	    # Verify set values in sysfs +	    if [ ${up_threshold_set} -eq ${up_threshold} ];then +		echo "up_threshold: $up_threshold, set in sysfs: ${up_threshold_set}" +	    else +		echo "WARNING: Tried to set up_threshold: $up_threshold, set in sysfs: ${up_threshold_set}" +	    fi +	    if [ ${sampling_rate_set} -eq ${sampling_rate} ];then +		echo "sampling_rate: $sampling_rate, set in sysfs: ${sampling_rate_set}" +	    else +		echo "WARNING: Tried to set sampling_rate: $sampling_rate, set in sysfs: ${sampling_rate_set}" +	    fi + +	    # Benchmark +	    cpufreq-bench -o /var/log/cpufreq-bench/up_threshold_${up_threshold}_sampling_rate_${sampling_rate} +	done +    done +} + +function create_plots() +{ +    local command + +    for up_threshold in $UP_THRESHOLD;do +	command="cpufreq-bench_plot.sh -o \"sampling_rate_${SAMPLING_RATE}_up_threshold_${up_threshold}\" -t \"Ondemand sampling_rate: ${SAMPLING_RATE} comparison - Up_threshold: $up_threshold %\"" +	for sampling_rate in $SAMPLING_RATE;do +	    command="${command} /var/log/cpufreq-bench/up_threshold_${up_threshold}_sampling_rate_${sampling_rate}/* \"sampling_rate = $sampling_rate\"" +	done +	echo $command +	eval "$command" +	echo +    done + +    for sampling_rate in $SAMPLING_RATE;do +	command="cpufreq-bench_plot.sh -o \"up_threshold_${UP_THRESHOLD}_sampling_rate_${sampling_rate}\" -t \"Ondemand up_threshold: ${UP_THRESHOLD} % comparison - sampling_rate: $sampling_rate\"" +	for up_threshold in $UP_THRESHOLD;do +	    command="${command} /var/log/cpufreq-bench/up_threshold_${up_threshold}_sampling_rate_${sampling_rate}/* \"up_threshold = $up_threshold\"" +	done +	echo $command +	eval "$command" +	echo +    done + +    command="cpufreq-bench_plot.sh -o \"up_threshold_${UP_THRESHOLD}_sampling_rate_${SAMPLING_RATE}\" -t \"Ondemand up_threshold: ${UP_THRESHOLD} and sampling_rate ${SAMPLING_RATE} comparison\"" +    for sampling_rate in $SAMPLING_RATE;do +	for up_threshold in $UP_THRESHOLD;do +	    command="${command} /var/log/cpufreq-bench/up_threshold_${up_threshold}_sampling_rate_${sampling_rate}/* \"up_threshold = $up_threshold - sampling_rate = $sampling_rate\"" +	done +    done +    echo "$command" +    eval "$command" +} + +measure +create_plots
\ No newline at end of file diff --git a/tools/power/cpupower/bench/example.cfg b/tools/power/cpupower/bench/example.cfg new file mode 100644 index 00000000000..f91f6436068 --- /dev/null +++ b/tools/power/cpupower/bench/example.cfg @@ -0,0 +1,11 @@ +sleep = 50000 +load = 50000 +cpu = 0 +priority = LOW +output = /var/log/cpufreq-bench +sleep_step = 50000 +load_step = 50000 +cycles = 20 +rounds = 40 +verbose = 0 +governor = ondemand diff --git a/tools/power/cpupower/bench/main.c b/tools/power/cpupower/bench/main.c new file mode 100644 index 00000000000..24910313a52 --- /dev/null +++ b/tools/power/cpupower/bench/main.c @@ -0,0 +1,202 @@ +/*  cpufreq-bench CPUFreq microbenchmark + * + *  Copyright (C) 2008 Christian Kornacker <ckornacker@suse.de> + * + *  This program is free software; you can redistribute it and/or modify + *  it under the terms of the GNU General Public License as published by + *  the Free Software Foundation; either version 2 of the License, or + *  (at your option) any later version. + * + *  This program is distributed in the hope that it will be useful, + *  but WITHOUT ANY WARRANTY; without even the implied warranty of + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *  GNU General Public License for more details. + * + *  You should have received a copy of the GNU General Public License + *  along with this program; if not, write to the Free Software + *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <getopt.h> +#include <errno.h> + +#include "config.h" +#include "system.h" +#include "benchmark.h" + +static struct option long_options[] = { +	{"output",	1,	0,	'o'}, +	{"sleep",	1,	0,	's'}, +	{"load",	1,	0,	'l'}, +	{"verbose",	0,	0,	'v'}, +	{"cpu",		1,	0,	'c'}, +	{"governor",	1,	0,	'g'}, +	{"prio",	1,	0,	'p'}, +	{"file",	1,	0,	'f'}, +	{"cycles",	1,	0,	'n'}, +	{"rounds",	1,	0,	'r'}, +	{"load-step",	1,	0,	'x'}, +	{"sleep-step",	1,	0,	'y'}, +	{"help",	0,	0,	'h'}, +	{0, 0, 0, 0} +}; + +/******************************************************************* + usage +*******************************************************************/ + +void usage() +{ +	printf("usage: ./bench\n"); +	printf("Options:\n"); +	printf(" -l, --load=<long int>\t\tinitial load time in us\n"); +	printf(" -s, --sleep=<long int>\t\tinitial sleep time in us\n"); +	printf(" -x, --load-step=<long int>\ttime to be added to load time, in us\n"); +	printf(" -y, --sleep-step=<long int>\ttime to be added to sleep time, in us\n"); +	printf(" -c, --cpu=<cpu #>\t\t\tCPU Nr. to use, starting at 0\n"); +	printf(" -p, --prio=<priority>\t\t\tscheduler priority, HIGH, LOW or DEFAULT\n"); +	printf(" -g, --governor=<governor>\t\tcpufreq governor to test\n"); +	printf(" -n, --cycles=<int>\t\t\tload/sleep cycles\n"); +	printf(" -r, --rounds<int>\t\t\tload/sleep rounds\n"); +	printf(" -f, --file=<configfile>\t\tconfig file to use\n"); +	printf(" -o, --output=<dir>\t\t\toutput path. Filename will be OUTPUTPATH/benchmark_TIMESTAMP.log\n"); +	printf(" -v, --verbose\t\t\t\tverbose output on/off\n"); +	printf(" -h, --help\t\t\t\tPrint this help screen\n"); +	exit(1); +} + +/******************************************************************* + main +*******************************************************************/ + +int main(int argc, char **argv) +{ +	int c; +	int option_index = 0; +	struct config *config = NULL; + +	config = prepare_default_config(); + +	if (config == NULL) +		return EXIT_FAILURE; + +	while (1) { +		c = getopt_long (argc, argv, "hg:o:s:l:vc:p:f:n:r:x:y:", +				long_options, &option_index); +		if (c == -1) +			break; + +		switch (c) { +		case 'o': +			if (config->output != NULL) +				fclose(config->output); + +			config->output = prepare_output(optarg); + +			if (config->output == NULL) +				return EXIT_FAILURE; + +			dprintf("user output path -> %s\n", optarg); +			break; +		case 's': +			sscanf(optarg, "%li", &config->sleep); +			dprintf("user sleep time -> %s\n", optarg); +			break; +		case 'l': +			sscanf(optarg, "%li", &config->load); +			dprintf("user load time -> %s\n", optarg); +			break; +		case 'c': +			sscanf(optarg, "%u", &config->cpu); +			dprintf("user cpu -> %s\n", optarg); +			break; +		case 'g': +			strncpy(config->governor, optarg, 14); +			dprintf("user governor -> %s\n", optarg); +			break; +		case 'p': +			if (string_to_prio(optarg) != SCHED_ERR) { +				config->prio = string_to_prio(optarg); +				dprintf("user prio -> %s\n", optarg); +			} else { +				if (config != NULL) { +					if (config->output != NULL) +						fclose(config->output); +					free(config); +				} +				usage(); +			} +			break; +		case 'n': +			sscanf(optarg, "%u", &config->cycles); +			dprintf("user cycles -> %s\n", optarg); +			break; +		case 'r': +			sscanf(optarg, "%u", &config->rounds); +			dprintf("user rounds -> %s\n", optarg); +			break; +		case 'x': +			sscanf(optarg, "%li", &config->load_step); +			dprintf("user load_step -> %s\n", optarg); +			break; +		case 'y': +			sscanf(optarg, "%li", &config->sleep_step); +			dprintf("user sleep_step -> %s\n", optarg); +			break; +		case 'f': +			if (prepare_config(optarg, config)) +				return EXIT_FAILURE; +			break; +		case 'v': +			config->verbose = 1; +			dprintf("verbose output enabled\n"); +			break; +		case 'h': +		case '?': +		default: +			if (config != NULL) { +				if (config->output != NULL) +					fclose(config->output); +				free(config); +			} +			usage(); +		} +	} + +	if (config->verbose) { +		printf("starting benchmark with parameters:\n"); +		printf("config:\n\t" +		       "sleep=%li\n\t" +		       "load=%li\n\t" +		       "sleep_step=%li\n\t" +		       "load_step=%li\n\t" +		       "cpu=%u\n\t" +		       "cycles=%u\n\t" +		       "rounds=%u\n\t" +		       "governor=%s\n\n", +		       config->sleep, +		       config->load, +		       config->sleep_step, +		       config->load_step, +		       config->cpu, +		       config->cycles, +		       config->rounds, +		       config->governor); +	} + +	prepare_user(config); +	prepare_system(config); +	start_benchmark(config); + +	if (config->output != stdout) +		fclose(config->output); + +	free(config); + +	return EXIT_SUCCESS; +} + diff --git a/tools/power/cpupower/bench/parse.c b/tools/power/cpupower/bench/parse.c new file mode 100644 index 00000000000..543bba14ae2 --- /dev/null +++ b/tools/power/cpupower/bench/parse.c @@ -0,0 +1,225 @@ +/*  cpufreq-bench CPUFreq microbenchmark + * + *  Copyright (C) 2008 Christian Kornacker <ckornacker@suse.de> + * + *  This program is free software; you can redistribute it and/or modify + *  it under the terms of the GNU General Public License as published by + *  the Free Software Foundation; either version 2 of the License, or + *  (at your option) any later version. + * + *  This program is distributed in the hope that it will be useful, + *  but WITHOUT ANY WARRANTY; without even the implied warranty of + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *  GNU General Public License for more details. + * + *  You should have received a copy of the GNU General Public License + *  along with this program; if not, write to the Free Software + *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> +#include <time.h> +#include <dirent.h> + +#include <sys/utsname.h> +#include <sys/types.h> +#include <sys/stat.h> + +#include "parse.h" +#include "config.h" + +/** + * converts priority string to priority + * + * @param str string that represents a scheduler priority + * + * @retval priority + * @retval SCHED_ERR when the priority doesn't exit + **/ + +enum sched_prio string_to_prio(const char *str) +{ +	if (strncasecmp("high", str, strlen(str)) == 0) +		return  SCHED_HIGH; +	else if (strncasecmp("default", str, strlen(str)) == 0) +		return SCHED_DEFAULT; +	else if (strncasecmp("low", str, strlen(str)) == 0) +		return SCHED_LOW; +	else +		return SCHED_ERR; +} + +/** + * create and open logfile + * + * @param dir directory in which the logfile should be created + * + * @retval logfile on success + * @retval NULL when the file can't be created + **/ + +FILE *prepare_output(const char *dirname) +{ +	FILE *output = NULL; +	int len; +	char *filename; +	struct utsname sysdata; +	DIR *dir; + +	dir = opendir(dirname); +	if (dir == NULL) { +		if (mkdir(dirname, 0755)) { +			perror("mkdir"); +			fprintf(stderr, "error: Cannot create dir %s\n", +				dirname); +			return NULL; +		} +	} + +	len = strlen(dirname) + 30; +	filename = malloc(sizeof(char) * len); + +	if (uname(&sysdata) == 0) { +		len += strlen(sysdata.nodename) + strlen(sysdata.release); +		filename = realloc(filename, sizeof(char) * len); + +		if (filename == NULL) { +			perror("realloc"); +			return NULL; +		} + +		snprintf(filename, len - 1, "%s/benchmark_%s_%s_%li.log", +			dirname, sysdata.nodename, sysdata.release, time(NULL)); +	} else { +		snprintf(filename, len - 1, "%s/benchmark_%li.log", +			dirname, time(NULL)); +	} + +	dprintf("logilename: %s\n", filename); + +	output = fopen(filename, "w+"); +	if (output == NULL) { +		perror("fopen"); +		fprintf(stderr, "error: unable to open logfile\n"); +	} + +	fprintf(stdout, "Logfile: %s\n", filename); + +	free(filename); +	fprintf(output, "#round load sleep performance powersave percentage\n"); +	return output; +} + +/** + * returns the default config + * + * @retval default config on success + * @retval NULL when the output file can't be created + **/ + +struct config *prepare_default_config() +{ +	struct config *config = malloc(sizeof(struct config)); + +	dprintf("loading defaults\n"); + +	config->sleep = 500000; +	config->load = 500000; +	config->sleep_step = 500000; +	config->load_step = 500000; +	config->cycles = 5; +	config->rounds = 50; +	config->cpu = 0; +	config->prio = SCHED_HIGH; +	config->verbose = 0; +	strncpy(config->governor, "ondemand", 8); + +	config->output = stdout; + +#ifdef DEFAULT_CONFIG_FILE +	if (prepare_config(DEFAULT_CONFIG_FILE, config)) +		return NULL; +#endif +	return config; +} + +/** + * parses config file and returns the config to the caller + * + * @param path config file name + * + * @retval 1 on error + * @retval 0 on success + **/ + +int prepare_config(const char *path, struct config *config) +{ +	size_t len = 0; +	char *opt, *val, *line = NULL; +	FILE *configfile = fopen(path, "r"); + +	if (config == NULL) { +		fprintf(stderr, "error: config is NULL\n"); +		return 1; +	} + +	if (configfile == NULL) { +		perror("fopen"); +		fprintf(stderr, "error: unable to read configfile\n"); +		free(config); +		return 1; +	} + +	while (getline(&line, &len, configfile) != -1) { +		if (line[0] == '#' || line[0] == ' ') +			continue; + +		sscanf(line, "%as = %as", &opt, &val); + +		dprintf("parsing: %s -> %s\n", opt, val); + +		if (strncmp("sleep", opt, strlen(opt)) == 0) +			sscanf(val, "%li", &config->sleep); + +		else if (strncmp("load", opt, strlen(opt)) == 0) +			sscanf(val, "%li", &config->load); + +		else if (strncmp("load_step", opt, strlen(opt)) == 0) +			sscanf(val, "%li", &config->load_step); + +		else if (strncmp("sleep_step", opt, strlen(opt)) == 0) +			sscanf(val, "%li", &config->sleep_step); + +		else if (strncmp("cycles", opt, strlen(opt)) == 0) +			sscanf(val, "%u", &config->cycles); + +		else if (strncmp("rounds", opt, strlen(opt)) == 0) +			sscanf(val, "%u", &config->rounds); + +		else if (strncmp("verbose", opt, strlen(opt)) == 0) +			sscanf(val, "%u", &config->verbose); + +		else if (strncmp("output", opt, strlen(opt)) == 0) +			config->output = prepare_output(val);  + +		else if (strncmp("cpu", opt, strlen(opt)) == 0) +			sscanf(val, "%u", &config->cpu); + +		else if (strncmp("governor", opt, 14) == 0) +			strncpy(config->governor, val, 14); + +		else if (strncmp("priority", opt, strlen(opt)) == 0) { +			if (string_to_prio(val) != SCHED_ERR) +				config->prio = string_to_prio(val); +		} +	} + +	free(line); +	free(opt); +	free(val); + +	return 0; +} diff --git a/tools/power/cpupower/bench/parse.h b/tools/power/cpupower/bench/parse.h new file mode 100644 index 00000000000..a8dc632d9ee --- /dev/null +++ b/tools/power/cpupower/bench/parse.h @@ -0,0 +1,53 @@ +/*  cpufreq-bench CPUFreq microbenchmark + * + *  Copyright (C) 2008 Christian Kornacker <ckornacker@suse.de> + * + *  This program is free software; you can redistribute it and/or modify + *  it under the terms of the GNU General Public License as published by + *  the Free Software Foundation; either version 2 of the License, or + *  (at your option) any later version. + * + *  This program is distributed in the hope that it will be useful, + *  but WITHOUT ANY WARRANTY; without even the implied warranty of + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *  GNU General Public License for more details. + * + *  You should have received a copy of the GNU General Public License + *  along with this program; if not, write to the Free Software + *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* struct that holds the required config parameters */ +struct config +{ +	long sleep;		/* sleep time in µs */ +	long load;		/* load time in µs */ +	long sleep_step;	/* time value which changes the +				 * sleep time after every round in µs */ +	long load_step;		/* time value which changes the +				 * load time after every round in µs */ +	unsigned int cycles;	/* calculation cycles with the same sleep/load time */ +	unsigned int rounds;	/* calculation rounds with iterated sleep/load time */ +	unsigned int cpu;	/* cpu for which the affinity is set */ +	char governor[15];	/* cpufreq governor */ +	enum sched_prio		/* possible scheduler priorities */ +	{ +		SCHED_ERR = -1, +		SCHED_HIGH, +		SCHED_DEFAULT, +		SCHED_LOW +	} prio; + +	unsigned int verbose;	/* verbose output */ +	FILE *output;		/* logfile */ +	char *output_filename;	/* logfile name, must be freed at the end +				   if output != NULL and output != stdout*/ +}; + +enum sched_prio string_to_prio(const char *str); + +FILE *prepare_output(const char *dir); + +int prepare_config(const char *path, struct config *config); +struct config *prepare_default_config(); + diff --git a/tools/power/cpupower/bench/system.c b/tools/power/cpupower/bench/system.c new file mode 100644 index 00000000000..f01e3f4be84 --- /dev/null +++ b/tools/power/cpupower/bench/system.c @@ -0,0 +1,191 @@ +/*  cpufreq-bench CPUFreq microbenchmark + * + *  Copyright (C) 2008 Christian Kornacker <ckornacker@suse.de> + * + *  This program is free software; you can redistribute it and/or modify + *  it under the terms of the GNU General Public License as published by + *  the Free Software Foundation; either version 2 of the License, or + *  (at your option) any later version. + * + *  This program is distributed in the hope that it will be useful, + *  but WITHOUT ANY WARRANTY; without even the implied warranty of + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *  GNU General Public License for more details. + * + *  You should have received a copy of the GNU General Public License + *  along with this program; if not, write to the Free Software + *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include <stdio.h> +#include <time.h> +#include <sys/time.h> +#include <sys/types.h> +#include <unistd.h> + +#include <sched.h> + +#include <cpufreq.h> + +#include "config.h" +#include "system.h" + +/** + * returns time since epoch in µs + * + * @retval time + **/ + +long long int get_time() +{ +	struct timeval now; + +	gettimeofday(&now, NULL); + +	return (long long int)(now.tv_sec * 1000000LL + now.tv_usec); +} + +/** + * sets the cpufreq governor + * + * @param governor cpufreq governor name + * @param cpu cpu for which the governor should be set + * + * @retval 0 on success + * @retval -1 when failed + **/ + +int set_cpufreq_governor(char *governor, unsigned int cpu) +{ + +	dprintf("set %s as cpufreq governor\n", governor); + +	if (cpufreq_cpu_exists(cpu) != 0) { +		perror("cpufreq_cpu_exists"); +		fprintf(stderr, "error: cpu %u does not exist\n", cpu); +		return -1; +	} + +	if (cpufreq_modify_policy_governor(cpu, governor) != 0) { +		perror("cpufreq_modify_policy_governor"); +		fprintf(stderr, "error: unable to set %s governor\n", governor); +		return -1; +	} + +	return 0; +} + +/** + * sets cpu affinity for the process + * + * @param cpu cpu# to which the affinity should be set + * + * @retval 0 on success + * @retval -1 when setting the affinity failed + **/ + +int set_cpu_affinity(unsigned int cpu) +{ +	cpu_set_t cpuset; + +	CPU_ZERO(&cpuset); +	CPU_SET(cpu, &cpuset); + +	dprintf("set affinity to cpu #%u\n", cpu); + +	if (sched_setaffinity(getpid(), sizeof(cpu_set_t), &cpuset) < 0) { +		perror("sched_setaffinity"); +		fprintf(stderr, "warning: unable to set cpu affinity\n"); +		return -1; +	} + +	return 0; +} + +/** + * sets the process priority parameter + * + * @param priority priority value + * + * @retval 0 on success + * @retval -1 when setting the priority failed + **/ + +int set_process_priority(int priority) +{ +	struct sched_param param; + +	dprintf("set scheduler priority to %i\n", priority); + +	param.sched_priority = priority; + +	if (sched_setscheduler(0, SCHEDULER, ¶m) < 0) { +		perror("sched_setscheduler"); +		fprintf(stderr, "warning: unable to set scheduler priority\n"); +		return -1; +	} + +	return 0; +} + +/** + * notifies the user that the benchmark may run some time + * + * @param config benchmark config values + * + **/ + +void prepare_user(const struct config *config) +{ +	unsigned long sleep_time = 0; +	unsigned long load_time = 0; +	unsigned int round; + +	for (round = 0; round < config->rounds; round++) { +		sleep_time +=  2 * config->cycles * +			(config->sleep + config->sleep_step * round); +		load_time += 2 * config->cycles * +			(config->load + config->load_step * round) + +			(config->load + config->load_step * round * 4); +	} + +	if (config->verbose || config->output != stdout) +		printf("approx. test duration: %im\n", +		       (int)((sleep_time + load_time) / 60000000)); +} + +/** + * sets up the cpu affinity and scheduler priority + * + * @param config benchmark config values + * + **/ + +void prepare_system(const struct config *config) +{ +	if (config->verbose) +		printf("set cpu affinity to cpu #%u\n", config->cpu); + +	set_cpu_affinity(config->cpu); + +	switch (config->prio) { +	case SCHED_HIGH: +		if (config->verbose) +			printf("high priority condition requested\n"); + +		set_process_priority(PRIORITY_HIGH); +		break; +	case SCHED_LOW: +		if (config->verbose) +			printf("low priority condition requested\n"); + +		set_process_priority(PRIORITY_LOW); +		break; +	default: +		if (config->verbose) +			printf("default priority condition requested\n"); + +		set_process_priority(PRIORITY_DEFAULT); +	} +} + diff --git a/tools/power/cpupower/bench/system.h b/tools/power/cpupower/bench/system.h new file mode 100644 index 00000000000..3a8c858b78f --- /dev/null +++ b/tools/power/cpupower/bench/system.h @@ -0,0 +1,29 @@ +/*  cpufreq-bench CPUFreq microbenchmark + * + *  Copyright (C) 2008 Christian Kornacker <ckornacker@suse.de> + * + *  This program is free software; you can redistribute it and/or modify + *  it under the terms of the GNU General Public License as published by + *  the Free Software Foundation; either version 2 of the License, or + *  (at your option) any later version. + * + *  This program is distributed in the hope that it will be useful, + *  but WITHOUT ANY WARRANTY; without even the implied warranty of + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *  GNU General Public License for more details. + * + *  You should have received a copy of the GNU General Public License + *  along with this program; if not, write to the Free Software + *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "parse.h" + +long long get_time(); + +int set_cpufreq_governor(char *governor, unsigned int cpu); +int set_cpu_affinity(unsigned int cpu); +int set_process_priority(int priority); + +void prepare_user(const struct config *config); +void prepare_system(const struct config *config); diff --git a/tools/power/cpupower/debug/i386/Makefile b/tools/power/cpupower/debug/i386/Makefile new file mode 100644 index 00000000000..c05cc0ac80c --- /dev/null +++ b/tools/power/cpupower/debug/i386/Makefile @@ -0,0 +1,41 @@ +OUTPUT=./ +ifeq ("$(origin O)", "command line") +	OUTPUT := $(O)/ +endif + +DESTDIR = +bindir  = /usr/bin + +INSTALL = /usr/bin/install + + +default: all + +$(OUTPUT)centrino-decode: centrino-decode.c +	$(CC) $(CFLAGS) -o $@ centrino-decode.c + +$(OUTPUT)dump_psb: dump_psb.c +	$(CC) $(CFLAGS) -o $@ dump_psb.c + +$(OUTPUT)intel_gsic: intel_gsic.c +	$(CC) $(CFLAGS) -o $@ -llrmi intel_gsic.c + +$(OUTPUT)powernow-k8-decode: powernow-k8-decode.c +	$(CC) $(CFLAGS) -o $@ powernow-k8-decode.c + +all: $(OUTPUT)centrino-decode $(OUTPUT)dump_psb $(OUTPUT)intel_gsic $(OUTPUT)powernow-k8-decode + +clean: +	rm -rf $(OUTPUT)centrino-decode +	rm -rf $(OUTPUT)dump_psb +	rm -rf $(OUTPUT)intel_gsic +	rm -rf $(OUTPUT)powernow-k8-decode + +install: +	$(INSTALL) -d $(DESTDIR)${bindir} +	$(INSTALL) $(OUTPUT)centrino-decode $(DESTDIR)${bindir} +	$(INSTALL) $(OUTPUT)powernow-k8-decode $(DESTDIR)${bindir} +	$(INSTALL) $(OUTPUT)dump_psb $(DESTDIR)${bindir} +	$(INSTALL) $(OUTPUT)intel_gsic $(DESTDIR)${bindir} + +.PHONY: all default clean install diff --git a/tools/power/cpupower/debug/i386/centrino-decode.c b/tools/power/cpupower/debug/i386/centrino-decode.c new file mode 100644 index 00000000000..7ef24cce492 --- /dev/null +++ b/tools/power/cpupower/debug/i386/centrino-decode.c @@ -0,0 +1,113 @@ +/* + *  (C) 2003 - 2004  Dominik Brodowski <linux@dominikbrodowski.de> + * + *  Licensed under the terms of the GNU GPL License version 2. + * + * Based on code found in + * linux/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c + * and originally developed by Jeremy Fitzhardinge. + * + * USAGE: simply run it to decode the current settings on CPU 0, + *	  or pass the CPU number as argument, or pass the MSR content + *	  as argument. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <unistd.h> +#include <errno.h> +#include <fcntl.h> + +#include <sys/types.h> +#include <sys/stat.h> + +#define MCPU	32 + +#define MSR_IA32_PERF_STATUS	0x198 + +static int rdmsr(unsigned int cpu, unsigned int msr, +		 unsigned int *lo, unsigned int *hi) +{ +	int fd; +	char file[20]; +	unsigned long long val; +	int retval = -1; + +	*lo = *hi = 0; + +	if (cpu > MCPU) +		goto err1; + +	sprintf(file, "/dev/cpu/%d/msr", cpu); +	fd = open(file, O_RDONLY); + +	if (fd < 0) +		goto err1; + +	if (lseek(fd, msr, SEEK_CUR) == -1) +		goto err2; + +	if (read(fd, &val, 8) != 8) +		goto err2; + +	*lo = (uint32_t )(val & 0xffffffffull); +	*hi = (uint32_t )(val>>32 & 0xffffffffull); + +	retval = 0; +err2: +	close(fd); +err1: +	return retval; +} + +static void decode (unsigned int msr) +{ +	unsigned int multiplier; +	unsigned int mv; + +	multiplier = ((msr >> 8) & 0xFF); + +	mv = (((msr & 0xFF) * 16) + 700); + +	printf("0x%x means multiplier %d @ %d mV\n", msr, multiplier, mv); +} + +static int decode_live(unsigned int cpu) +{ +	unsigned int lo, hi; +	int err; + +	err = rdmsr(cpu, MSR_IA32_PERF_STATUS, &lo, &hi); + +	if (err) { +		printf("can't get MSR_IA32_PERF_STATUS for cpu %d\n", cpu); +		printf("Possible trouble: you don't run an Enhanced SpeedStep capable cpu\n"); +		printf("or you are not root, or the msr driver is not present\n"); +		return 1; +	} + +	decode(lo); + +	return 0; +} + +int main (int argc, char **argv) +{ +	unsigned int cpu, mode = 0; + +	if (argc < 2) +		cpu = 0; +	else { +		cpu = strtoul(argv[1], NULL, 0); +		if (cpu >= MCPU) +			mode = 1; +	} + +	if (mode) +		decode(cpu); +	else +		decode_live(cpu); + +	return 0; +} diff --git a/tools/power/cpupower/debug/i386/dump_psb.c b/tools/power/cpupower/debug/i386/dump_psb.c new file mode 100644 index 00000000000..8d6a4751425 --- /dev/null +++ b/tools/power/cpupower/debug/i386/dump_psb.c @@ -0,0 +1,196 @@ +/* + * dump_psb. (c) 2004, Dave Jones, Red Hat Inc. + * Licensed under the GPL v2. + */ + +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#define _GNU_SOURCE +#include <getopt.h> + +#include <sys/mman.h> + +#define LEN (0x100000 - 0xc0000) +#define OFFSET (0xc0000) + +#ifndef __packed +#define __packed __attribute((packed)) +#endif + +static long relevant; + +static const int fid_to_mult[32] = { +	110, 115, 120, 125, 50, 55, 60, 65, +	70, 75, 80, 85, 90, 95, 100, 105, +	30, 190, 40, 200, 130, 135, 140, 210, +	150, 225, 160, 165, 170, 180, -1, -1, +}; + +static const int vid_to_voltage[32] = { +	2000, 1950, 1900, 1850, 1800, 1750, 1700, 1650, +	1600, 1550, 1500, 1450, 1400, 1350, 1300, 0, +	1275, 1250, 1225, 1200, 1175, 1150, 1125, 1100, +	1075, 1050, 1024, 1000, 975, 950, 925, 0, +}; + +struct psb_header { +	char signature[10]; +	u_char version; +	u_char flags; +	u_short settlingtime; +	u_char res1; +	u_char numpst; +} __packed; + +struct pst_header { +	u_int32_t cpuid; +	u_char fsb; +	u_char maxfid; +	u_char startvid; +	u_char numpstates; +} __packed; + +static u_int fsb; +static u_int sgtc; + +static int +decode_pst(char *p, int npstates) +{ +	int i; +	int freq, fid, vid; + +	for (i = 0; i < npstates; ++i) { +		fid = *p++; +		vid = *p++; +		freq = 100 * fid_to_mult[fid] * fsb; + +		printf("   %2d %8dkHz  FID %02x (%2d.%01d)  VID %02x (%4dmV)\n", +		       i, +		       freq, +		       fid, fid_to_mult[fid]/10, fid_to_mult[fid]%10, +		       vid, vid_to_voltage[vid]); +	} + +	return 0; +} + +static +void decode_psb(char *p, int numpst) +{ +	int i; +	struct psb_header *psb; +	struct pst_header *pst; + +	psb = (struct psb_header*) p; + +	if (psb->version != 0x12) +		return; + +	printf("PSB version: %hhx flags: %hhx settling time %hhuus res1 %hhx num pst %hhu\n", +			psb->version, +			psb->flags, +			psb->settlingtime, +			psb->res1, +			psb->numpst); +	sgtc = psb->settlingtime * 100; + +	if (sgtc < 10000) +		sgtc = 10000; + +	p = ((char *) psb) + sizeof(struct psb_header); + +	if (numpst < 0) +		numpst = psb->numpst; +	else +		printf("Overriding number of pst :%d\n", numpst); + +	for (i = 0; i < numpst; i++) { +		pst = (struct pst_header*) p; + +		if (relevant != 0) { +			if (relevant!= pst->cpuid) +				goto next_one; +		} + +		printf("  PST %d  cpuid %.3x fsb %hhu mfid %hhx svid %hhx numberstates %hhu\n", +				i+1, +				pst->cpuid, +				pst->fsb, +				pst->maxfid, +				pst->startvid, +				pst->numpstates); + +		fsb = pst->fsb; +		decode_pst(p + sizeof(struct pst_header), pst->numpstates); + +next_one: +		p += sizeof(struct pst_header) + 2*pst->numpstates; +	} + +} + +static struct option info_opts[] = { +	{.name = "numpst",	.has_arg=no_argument,	.flag=NULL, .val='n'}, +}; + +void print_help(void) +{ +	printf ("Usage: dump_psb [options]\n"); +	printf ("Options:\n"); +	printf ("  -n, --numpst     Set number of PST tables to scan\n"); +	printf ("  -r, --relevant   Only display PSTs relevant to cpuid N\n"); +} + +int +main(int argc, char *argv[]) +{ +	int fd; +	int numpst=-1; +	int ret=0, cont=1; +	char *mem = NULL; +	char *p; + +	do { +		ret = getopt_long(argc, argv, "hr:n:", info_opts, NULL); +		switch (ret){ +		case '?': +		case 'h': +			print_help(); +			cont = 0; +			break; +		case 'r': +			relevant = strtol(optarg, NULL, 16); +			break; +		case 'n': +			numpst = strtol(optarg, NULL, 10); +			break; +		case -1: +			cont = 0; +			break; +		} + +	} while(cont); + +	fd = open("/dev/mem", O_RDONLY); +	if (fd < 0) { +		printf ("Couldn't open /dev/mem. Are you root?\n"); +		exit(1); +	} + +	mem = mmap(mem, 0x100000 - 0xc0000, PROT_READ, MAP_SHARED, fd, 0xc0000); +	close(fd); + +	for (p = mem; p - mem < LEN; p+=16) { +		if (memcmp(p, "AMDK7PNOW!", 10) == 0) { +			decode_psb(p, numpst); +			break; +		} +	} + +	munmap(mem, LEN); +	return 0; +} diff --git a/tools/power/cpupower/debug/i386/intel_gsic.c b/tools/power/cpupower/debug/i386/intel_gsic.c new file mode 100644 index 00000000000..d032c826d42 --- /dev/null +++ b/tools/power/cpupower/debug/i386/intel_gsic.c @@ -0,0 +1,78 @@ +/* + *  (C) 2003  Bruno Ducrot + *  (C) 2004  Dominik Brodowski <linux@dominikbrodowski.de> + * + *  Licensed under the terms of the GNU GPL License version 2. + * + * Based on code found in + * linux/include/asm-i386/ist.h and linux/arch/i386/kernel/setup.c + * and originally developed by Andy Grover <andrew.grover@intel.com> + */ + +#include <stdio.h> +#include <string.h> +#include <lrmi.h> + +int main (void) +{ +	struct LRMI_regs	r; +	int			retval; + +	if (!LRMI_init()) +		return 0; + +	memset(&r, 0, sizeof(r)); + +	r.eax = 0x0000E980; +	r.edx = 0x47534943; + +	retval = LRMI_int(0x15, &r); + +	if (!retval) { +		printf("Failed!\n"); +		return 0; +	} +	if (r.eax == 0x47534943) { +		printf("BIOS supports GSIC call:\n"); +		printf("\tsignature: %c%c%c%c\n", +		       (r.eax >> 24) & 0xff, +		       (r.eax >> 16) & 0xff, +		       (r.eax >> 8) & 0xff, +		       (r.eax) & 0xff); +		printf("\tcommand port = 0x%.4x\n", +		       r.ebx & 0xffff); +		printf("\tcommand =      0x%.4x\n", +		       (r.ebx >> 16) & 0xffff); +		printf("\tevent port =   0x%.8x\n", r.ecx); +		printf("\tflags =        0x%.8x\n", r.edx); +		if (((r.ebx >> 16) & 0xffff) != 0x82) { +			printf("non-default command value. If speedstep-smi " +			       "doesn't work out of the box,\nyou may want to " +			       "try out the default value by passing " +			       "smi_cmd=0x82 to the module\n ON YOUR OWN " +			       "RISK.\n"); +		} +		if ((r.ebx & 0xffff) != 0xb2) { +			printf("non-default command port. If speedstep-smi " +			       "doesn't work out of the box,\nyou may want to " +			       "try out the default value by passing " +			       "smi_port=0x82 to the module\n ON YOUR OWN " +			       "RISK.\n"); +		} +	} else { +		printf("BIOS DOES NOT support GSIC call.  Dumping registers anyway:\n"); +		printf("eax = 0x%.8x\n", r.eax); +		printf("ebx = 0x%.8x\n", r.ebx); +		printf("ecx = 0x%.8x\n", r.ecx); +		printf("edx = 0x%.8x\n", r.edx); +		printf("Note also that some BIOS do not support the initial " +		       "GSIC call, but the newer\nspeedstep-smi driver may " +		       "work.\nFor this, you need to pass some arguments to " +		       "the speedstep-smi driver:\n"); +		printf("\tsmi_cmd=0x?? smi_port=0x?? smi_sig=1\n"); +		printf("\nUnfortunately, you have to know what exactly are " +		       "smi_cmd and smi_port, and this\nis system " +		       "dependant.\n"); +	} +	return 1; +} diff --git a/tools/power/cpupower/debug/i386/powernow-k8-decode.c b/tools/power/cpupower/debug/i386/powernow-k8-decode.c new file mode 100644 index 00000000000..638a6b3bfd9 --- /dev/null +++ b/tools/power/cpupower/debug/i386/powernow-k8-decode.c @@ -0,0 +1,96 @@ +/* + *  (C) 2004 Bruno Ducrot <ducrot@poupinou.org> + * + *  Licensed under the terms of the GNU GPL License version 2. + * + * Based on code found in + * linux/arch/i386/kernel/cpu/cpufreq/powernow-k8.c + * and originally developed by Paul Devriendt + */ + +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <unistd.h> +#include <errno.h> +#include <fcntl.h> + +#include <sys/types.h> +#include <sys/stat.h> + +#define MCPU 32 + +#define MSR_FIDVID_STATUS	0xc0010042 + +#define MSR_S_HI_CURRENT_VID	0x0000001f +#define MSR_S_LO_CURRENT_FID	0x0000003f + +static int get_fidvid(uint32_t cpu, uint32_t *fid, uint32_t *vid) +{ +	int err = 1; +	uint64_t msr = 0; +	int fd; +	char file[20]; + +	if (cpu > MCPU) +		goto out; + +	sprintf(file, "/dev/cpu/%d/msr", cpu); + +	fd = open(file, O_RDONLY); +	if (fd < 0) +		goto out; +	lseek(fd, MSR_FIDVID_STATUS, SEEK_CUR); +	if (read(fd, &msr, 8) != 8) +		goto err1; + +	*fid = ((uint32_t )(msr & 0xffffffffull)) & MSR_S_LO_CURRENT_FID; +	*vid = ((uint32_t )(msr>>32 & 0xffffffffull)) & MSR_S_HI_CURRENT_VID; +	err = 0; +err1: +	close(fd); +out: +	return err; +} + + +/* Return a frequency in MHz, given an input fid */ +static uint32_t find_freq_from_fid(uint32_t fid) +{ +	return 800 + (fid * 100); +} + +/* Return a voltage in miliVolts, given an input vid */ +static uint32_t find_millivolts_from_vid(uint32_t vid) +{ +	return 1550-vid*25; +} + +int main (int argc, char *argv[]) +{ +	int err; +	int cpu; +	uint32_t fid, vid; + +	if (argc < 2) +		cpu = 0; +	else +		cpu = strtoul(argv[1], NULL, 0); + +	err = get_fidvid(cpu, &fid, &vid); + +	if (err) { +		printf("can't get fid, vid from MSR\n"); +		printf("Possible trouble: you don't run a powernow-k8 capable cpu\n"); +		printf("or you are not root, or the msr driver is not present\n"); +		exit(1); +	} + +	 +	printf("cpu %d currently at %d MHz and %d mV\n", +			cpu, +			find_freq_from_fid(fid), +			find_millivolts_from_vid(vid)); +	 +	return 0; +} diff --git a/tools/power/cpupower/debug/kernel/Makefile b/tools/power/cpupower/debug/kernel/Makefile new file mode 100644 index 00000000000..96b146fe6f8 --- /dev/null +++ b/tools/power/cpupower/debug/kernel/Makefile @@ -0,0 +1,23 @@ +obj-m	:= + +KDIR	:= /lib/modules/$(shell uname -r)/build +PWD		:= $(shell pwd) +KMISC   := /lib/modules/$(shell uname -r)/cpufrequtils/ + +ifeq ("$(CONFIG_X86_TSC)", "y") +  obj-m	 += cpufreq-test_tsc.o +endif + +default: +	$(MAKE) -C $(KDIR) M=$(PWD) + +clean: +	- rm -rf *.o *.ko .tmp-versions .*.cmd .*.mod.* *.mod.c +	- rm -rf .tmp_versions* Module.symvers modules.order + +install: default +	install -d $(KMISC) +	install -m 644 -c *.ko $(KMISC) +	/sbin/depmod -a + +all:	default diff --git a/tools/power/cpupower/debug/kernel/cpufreq-test_tsc.c b/tools/power/cpupower/debug/kernel/cpufreq-test_tsc.c new file mode 100644 index 00000000000..5224ee5b392 --- /dev/null +++ b/tools/power/cpupower/debug/kernel/cpufreq-test_tsc.c @@ -0,0 +1,110 @@ +/* + * test module to check whether the TSC-based delay routine continues + * to work properly after cpufreq transitions. Needs ACPI to work + * properly. + * + * Based partly on the Power Management Timer (PMTMR) code to be found + * in arch/i386/kernel/timers/timer_pm.c on recent 2.6. kernels, especially + * code written by John Stultz. The read_pmtmr function was copied verbatim + * from that file. + * + * (C) 2004 Dominik Brodowski + * + * To use: + * 1.) pass clock=tsc to the kernel on your bootloader + * 2.) modprobe this module (it'll fail) + * 3.) change CPU frequency + * 4.) modprobe this module again + * 5.) if the third value, "diff_pmtmr", changes between 2. and 4., the + *     TSC-based delay routine on the Linux kernel does not correctly + *     handle the cpufreq transition. Please report this to + *     linux-pm@vger.kernel.org + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/acpi.h> +#include <asm/io.h> + +static int pm_tmr_ioport = 0; + +/*helper function to safely read acpi pm timesource*/ +static u32 read_pmtmr(void) +{ +	u32 v1=0,v2=0,v3=0; +	/* It has been reported that because of various broken +	 * chipsets (ICH4, PIIX4 and PIIX4E) where the ACPI PM time +	 * source is not latched, so you must read it multiple +	 * times to insure a safe value is read. +	 */ +	do { +		v1 = inl(pm_tmr_ioport); +		v2 = inl(pm_tmr_ioport); +		v3 = inl(pm_tmr_ioport); +	} while ((v1 > v2 && v1 < v3) || (v2 > v3 && v2 < v1) +		 || (v3 > v1 && v3 < v2)); + +	/* mask the output to 24 bits */ +	return (v2 & 0xFFFFFF); +} + +static int __init cpufreq_test_tsc(void) +{ +	u32 now, then, diff; +	u64 now_tsc, then_tsc, diff_tsc; +	int i; + +	/* the following code snipped is copied from arch/x86/kernel/acpi/boot.c +	   of Linux v2.6.25. */ + +	/* detect the location of the ACPI PM Timer */ +	if (acpi_gbl_FADT.header.revision >= FADT2_REVISION_ID) { +		/* FADT rev. 2 */ +		if (acpi_gbl_FADT.xpm_timer_block.space_id != +		    ACPI_ADR_SPACE_SYSTEM_IO) +			return 0; + +		pm_tmr_ioport = acpi_gbl_FADT.xpm_timer_block.address; +		/* +		 * "X" fields are optional extensions to the original V1.0 +		 * fields, so we must selectively expand V1.0 fields if the +		 * corresponding X field is zero. +	 	 */ +		if (!pm_tmr_ioport) +			pm_tmr_ioport = acpi_gbl_FADT.pm_timer_block; +	} else { +		/* FADT rev. 1 */ +		pm_tmr_ioport = acpi_gbl_FADT.pm_timer_block; +	} + +	printk(KERN_DEBUG "start--> \n"); +	then = read_pmtmr(); +        rdtscll(then_tsc); +	for (i=0;i<20;i++) { +		mdelay(100); +		now = read_pmtmr(); +		rdtscll(now_tsc); +		diff = (now - then) & 0xFFFFFF; +		diff_tsc = now_tsc - then_tsc; +		printk(KERN_DEBUG "t1: %08u t2: %08u diff_pmtmr: %08u diff_tsc: %016llu\n", then, now, diff, diff_tsc); +		then = now; +		then_tsc = now_tsc; +	} +	printk(KERN_DEBUG "<-- end \n"); +	return -ENODEV; +} + +static void __exit cpufreq_none(void) +{ +	return; +} + +module_init(cpufreq_test_tsc) +module_exit(cpufreq_none) + + +MODULE_AUTHOR("Dominik Brodowski"); +MODULE_DESCRIPTION("Verify the TSC cpufreq notifier working correctly -- needs ACPI-enabled system"); +MODULE_LICENSE ("GPL"); diff --git a/tools/power/cpupower/debug/x86_64/Makefile b/tools/power/cpupower/debug/x86_64/Makefile new file mode 100644 index 00000000000..1c521452671 --- /dev/null +++ b/tools/power/cpupower/debug/x86_64/Makefile @@ -0,0 +1,30 @@ +OUTPUT=./ +ifeq ("$(origin O)", "command line") +	OUTPUT := $(O)/ +endif + +DESTDIR = +bindir  = /usr/bin + +INSTALL = /usr/bin/install + + +default: all + +$(OUTPUT)centrino-decode: ../i386/centrino-decode.c +	$(CC) $(CFLAGS) -o $@ $< + +$(OUTPUT)powernow-k8-decode: ../i386/powernow-k8-decode.c +	$(CC) $(CFLAGS) -o $@ $< + +all: $(OUTPUT)centrino-decode $(OUTPUT)powernow-k8-decode + +clean: +	rm -rf $(OUTPUT)centrino-decode $(OUTPUT)powernow-k8-decode + +install: +	$(INSTALL) -d $(DESTDIR)${bindir} +	$(INSTALL) $(OUTPUT)centrino-decode $(DESTDIR)${bindir} +	$(INSTALL) $(OUTPUT)powernow-k8-decode $(DESTDIR)${bindir} + +.PHONY: all default clean install diff --git a/tools/power/cpupower/lib/cpufreq.c b/tools/power/cpupower/lib/cpufreq.c new file mode 100644 index 00000000000..d961101d1ce --- /dev/null +++ b/tools/power/cpupower/lib/cpufreq.c @@ -0,0 +1,208 @@ +/* + *  (C) 2004-2009  Dominik Brodowski <linux@dominikbrodowski.de> + * + *  Licensed under the terms of the GNU GPL License version 2. + */ + + +#include <stdio.h> +#include <errno.h> +#include <stdlib.h> +#include <string.h> + +#include "cpufreq.h" +#include "sysfs.h" + +int cpufreq_cpu_exists(unsigned int cpu) +{ +	return sysfs_cpu_exists(cpu); +} + +unsigned long cpufreq_get_freq_kernel(unsigned int cpu) +{ +	return sysfs_get_freq_kernel(cpu); +} + +unsigned long cpufreq_get_freq_hardware(unsigned int cpu) +{ +	return sysfs_get_freq_hardware(cpu); +} + +unsigned long cpufreq_get_transition_latency(unsigned int cpu) +{ +	return sysfs_get_freq_transition_latency(cpu); +} + +int cpufreq_get_hardware_limits(unsigned int cpu, +				unsigned long *min, +				unsigned long *max) +{ +	if ((!min) || (!max)) +		return -EINVAL; +	return sysfs_get_freq_hardware_limits(cpu, min, max); +} + +char *cpufreq_get_driver(unsigned int cpu) +{ +	return sysfs_get_freq_driver(cpu); +} + +void cpufreq_put_driver(char *ptr) +{ +	if (!ptr) +		return; +	free(ptr); +} + +struct cpufreq_policy *cpufreq_get_policy(unsigned int cpu) +{ +	return sysfs_get_freq_policy(cpu); +} + +void cpufreq_put_policy(struct cpufreq_policy *policy) +{ +	if ((!policy) || (!policy->governor)) +		return; + +	free(policy->governor); +	policy->governor = NULL; +	free(policy); +} + +struct cpufreq_available_governors *cpufreq_get_available_governors(unsigned +								int cpu) +{ +	return sysfs_get_freq_available_governors(cpu); +} + +void cpufreq_put_available_governors(struct cpufreq_available_governors *any) +{ +	struct cpufreq_available_governors *tmp, *next; + +	if (!any) +		return; + +	tmp = any->first; +	while (tmp) { +		next = tmp->next; +		if (tmp->governor) +			free(tmp->governor); +		free(tmp); +		tmp = next; +	} +} + + +struct cpufreq_available_frequencies +*cpufreq_get_available_frequencies(unsigned int cpu) +{ +	return sysfs_get_available_frequencies(cpu); +} + +void cpufreq_put_available_frequencies(struct cpufreq_available_frequencies +				*any) { +	struct cpufreq_available_frequencies *tmp, *next; + +	if (!any) +		return; + +	tmp = any->first; +	while (tmp) { +		next = tmp->next; +		free(tmp); +		tmp = next; +	} +} + + +struct cpufreq_affected_cpus *cpufreq_get_affected_cpus(unsigned int cpu) +{ +	return sysfs_get_freq_affected_cpus(cpu); +} + +void cpufreq_put_affected_cpus(struct cpufreq_affected_cpus *any) +{ +	struct cpufreq_affected_cpus *tmp, *next; + +	if (!any) +		return; + +	tmp = any->first; +	while (tmp) { +		next = tmp->next; +		free(tmp); +		tmp = next; +	} +} + + +struct cpufreq_affected_cpus *cpufreq_get_related_cpus(unsigned int cpu) +{ +	return sysfs_get_freq_related_cpus(cpu); +} + +void cpufreq_put_related_cpus(struct cpufreq_affected_cpus *any) +{ +	cpufreq_put_affected_cpus(any); +} + + +int cpufreq_set_policy(unsigned int cpu, struct cpufreq_policy *policy) +{ +	if (!policy || !(policy->governor)) +		return -EINVAL; + +	return sysfs_set_freq_policy(cpu, policy); +} + + +int cpufreq_modify_policy_min(unsigned int cpu, unsigned long min_freq) +{ +	return sysfs_modify_freq_policy_min(cpu, min_freq); +} + + +int cpufreq_modify_policy_max(unsigned int cpu, unsigned long max_freq) +{ +	return sysfs_modify_freq_policy_max(cpu, max_freq); +} + + +int cpufreq_modify_policy_governor(unsigned int cpu, char *governor) +{ +	if ((!governor) || (strlen(governor) > 19)) +		return -EINVAL; + +	return sysfs_modify_freq_policy_governor(cpu, governor); +} + +int cpufreq_set_frequency(unsigned int cpu, unsigned long target_frequency) +{ +	return sysfs_set_frequency(cpu, target_frequency); +} + +struct cpufreq_stats *cpufreq_get_stats(unsigned int cpu, +					unsigned long long *total_time) +{ +	return sysfs_get_freq_stats(cpu, total_time); +} + +void cpufreq_put_stats(struct cpufreq_stats *any) +{ +	struct cpufreq_stats *tmp, *next; + +	if (!any) +		return; + +	tmp = any->first; +	while (tmp) { +		next = tmp->next; +		free(tmp); +		tmp = next; +	} +} + +unsigned long cpufreq_get_transitions(unsigned int cpu) +{ +	return sysfs_get_freq_transitions(cpu); +} diff --git a/tools/power/cpupower/lib/cpufreq.h b/tools/power/cpupower/lib/cpufreq.h new file mode 100644 index 00000000000..3aae8e7a083 --- /dev/null +++ b/tools/power/cpupower/lib/cpufreq.h @@ -0,0 +1,223 @@ +/* + *  cpufreq.h - definitions for libcpufreq + * + *  Copyright (C) 2004-2009  Dominik Brodowski <linux@dominikbrodowski.de> + * + *  This program is free software; you can redistribute it and/or modify + *  it under the terms of the GNU General Public License as published by + *  the Free Software Foundation, version 2 of the License. + * + *  This program is distributed in the hope that it will be useful, + *  but WITHOUT ANY WARRANTY; without even the implied warranty of + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *  GNU General Public License for more details. + * + *  You should have received a copy of the GNU General Public License + *  along with this program; if not, write to the Free Software + *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + */ + +#ifndef _CPUFREQ_H +#define _CPUFREQ_H 1 + +struct cpufreq_policy { +	unsigned long min; +	unsigned long max; +	char *governor; +}; + +struct cpufreq_available_governors { +	char *governor; +	struct cpufreq_available_governors *next; +	struct cpufreq_available_governors *first; +}; + +struct cpufreq_available_frequencies { +	unsigned long frequency; +	struct cpufreq_available_frequencies *next; +	struct cpufreq_available_frequencies *first; +}; + + +struct cpufreq_affected_cpus { +	unsigned int cpu; +	struct cpufreq_affected_cpus *next; +	struct cpufreq_affected_cpus *first; +}; + +struct cpufreq_stats { +	unsigned long frequency; +	unsigned long long time_in_state; +	struct cpufreq_stats *next; +	struct cpufreq_stats *first; +}; + + + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * returns 0 if the specified CPU is present (it doesn't say + * whether it is online!), and an error value if not. + */ + +extern int cpufreq_cpu_exists(unsigned int cpu); + +/* determine current CPU frequency + * - _kernel variant means kernel's opinion of CPU frequency + * - _hardware variant means actual hardware CPU frequency, + *    which is only available to root. + * + * returns 0 on failure, else frequency in kHz. + */ + +extern unsigned long cpufreq_get_freq_kernel(unsigned int cpu); + +extern unsigned long cpufreq_get_freq_hardware(unsigned int cpu); + +#define cpufreq_get(cpu) cpufreq_get_freq_kernel(cpu); + + +/* determine CPU transition latency + * + * returns 0 on failure, else transition latency in 10^(-9) s = nanoseconds + */ +extern unsigned long cpufreq_get_transition_latency(unsigned int cpu); + + +/* determine hardware CPU frequency limits + * + * These may be limited further by thermal, energy or other + * considerations by cpufreq policy notifiers in the kernel. + */ + +extern int cpufreq_get_hardware_limits(unsigned int cpu, +				unsigned long *min, +				unsigned long *max); + + +/* determine CPUfreq driver used + * + * Remember to call cpufreq_put_driver when no longer needed + * to avoid memory leakage, please. + */ + +extern char *cpufreq_get_driver(unsigned int cpu); + +extern void cpufreq_put_driver(char *ptr); + + +/* determine CPUfreq policy currently used + * + * Remember to call cpufreq_put_policy when no longer needed + * to avoid memory leakage, please. + */ + + +extern struct cpufreq_policy *cpufreq_get_policy(unsigned int cpu); + +extern void cpufreq_put_policy(struct cpufreq_policy *policy); + + +/* determine CPUfreq governors currently available + * + * may be modified by modprobe'ing or rmmod'ing other governors. Please + * free allocated memory by calling cpufreq_put_available_governors + * after use. + */ + + +extern struct cpufreq_available_governors +*cpufreq_get_available_governors(unsigned int cpu); + +extern void cpufreq_put_available_governors( +	struct cpufreq_available_governors *first); + + +/* determine CPU frequency states available + * + * Only present on _some_ ->target() cpufreq drivers. For information purposes + * only. Please free allocated memory by calling + * cpufreq_put_available_frequencies after use. + */ + +extern struct cpufreq_available_frequencies +*cpufreq_get_available_frequencies(unsigned int cpu); + +extern void cpufreq_put_available_frequencies( +		struct cpufreq_available_frequencies *first); + + +/* determine affected CPUs + * + * Remember to call cpufreq_put_affected_cpus when no longer needed + * to avoid memory leakage, please. + */ + +extern struct cpufreq_affected_cpus *cpufreq_get_affected_cpus(unsigned +							int cpu); + +extern void cpufreq_put_affected_cpus(struct cpufreq_affected_cpus *first); + + +/* determine related CPUs + * + * Remember to call cpufreq_put_related_cpus when no longer needed + * to avoid memory leakage, please. + */ + +extern struct cpufreq_affected_cpus *cpufreq_get_related_cpus(unsigned +							int cpu); + +extern void cpufreq_put_related_cpus(struct cpufreq_affected_cpus *first); + + +/* determine stats for cpufreq subsystem + * + * This is not available in all kernel versions or configurations. + */ + +extern struct cpufreq_stats *cpufreq_get_stats(unsigned int cpu, +					unsigned long long *total_time); + +extern void cpufreq_put_stats(struct cpufreq_stats *stats); + +extern unsigned long cpufreq_get_transitions(unsigned int cpu); + + +/* set new cpufreq policy + * + * Tries to set the passed policy as new policy as close as possible, + * but results may differ depending e.g. on governors being available. + */ + +extern int cpufreq_set_policy(unsigned int cpu, struct cpufreq_policy *policy); + + +/* modify a policy by only changing min/max freq or governor + * + * Does not check whether result is what was intended. + */ + +extern int cpufreq_modify_policy_min(unsigned int cpu, unsigned long min_freq); +extern int cpufreq_modify_policy_max(unsigned int cpu, unsigned long max_freq); +extern int cpufreq_modify_policy_governor(unsigned int cpu, char *governor); + + +/* set a specific frequency + * + * Does only work if userspace governor can be used and no external + * interference (other calls to this function or to set/modify_policy) + * occurs. Also does not work on ->range() cpufreq drivers. + */ + +extern int cpufreq_set_frequency(unsigned int cpu, +				unsigned long target_frequency); + +#ifdef __cplusplus +} +#endif + +#endif /* _CPUFREQ_H */ diff --git a/tools/power/cpupower/lib/sysfs.c b/tools/power/cpupower/lib/sysfs.c new file mode 100644 index 00000000000..870713a75a8 --- /dev/null +++ b/tools/power/cpupower/lib/sysfs.c @@ -0,0 +1,672 @@ +/* + *  (C) 2004-2009  Dominik Brodowski <linux@dominikbrodowski.de> + * + *  Licensed under the terms of the GNU GPL License version 2. + */ + +#include <stdio.h> +#include <errno.h> +#include <stdlib.h> +#include <string.h> +#include <limits.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> + +#include "cpufreq.h" + +#define PATH_TO_CPU "/sys/devices/system/cpu/" +#define MAX_LINE_LEN 4096 +#define SYSFS_PATH_MAX 255 + + +static unsigned int sysfs_read_file(const char *path, char *buf, size_t buflen) +{ +	int fd; +	ssize_t numread; + +	fd = open(path, O_RDONLY); +	if (fd == -1) +		return 0; + +	numread = read(fd, buf, buflen - 1); +	if (numread < 1) { +		close(fd); +		return 0; +	} + +	buf[numread] = '\0'; +	close(fd); + +	return (unsigned int) numread; +} + + +/* CPUFREQ sysfs access **************************************************/ + +/* helper function to read file from /sys into given buffer */ +/* fname is a relative path under "cpuX/cpufreq" dir */ +static unsigned int sysfs_cpufreq_read_file(unsigned int cpu, const char *fname, +					    char *buf, size_t buflen) +{ +	char path[SYSFS_PATH_MAX]; + +	snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/cpufreq/%s", +			 cpu, fname); +	return sysfs_read_file(path, buf, buflen); +} + +/* helper function to write a new value to a /sys file */ +/* fname is a relative path under "cpuX/cpufreq" dir */ +static unsigned int sysfs_cpufreq_write_file(unsigned int cpu, +					     const char *fname, +					     const char *value, size_t len) +{ +	char path[SYSFS_PATH_MAX]; +	int fd; +	ssize_t numwrite; + +	snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/cpufreq/%s", +			 cpu, fname); + +	fd = open(path, O_WRONLY); +	if (fd == -1) +		return 0; + +	numwrite = write(fd, value, len); +	if (numwrite < 1) { +		close(fd); +		return 0; +	} + +	close(fd); + +	return (unsigned int) numwrite; +} + +/* read access to files which contain one numeric value */ + +enum cpufreq_value { +	CPUINFO_CUR_FREQ, +	CPUINFO_MIN_FREQ, +	CPUINFO_MAX_FREQ, +	CPUINFO_LATENCY, +	SCALING_CUR_FREQ, +	SCALING_MIN_FREQ, +	SCALING_MAX_FREQ, +	STATS_NUM_TRANSITIONS, +	MAX_CPUFREQ_VALUE_READ_FILES +}; + +static const char *cpufreq_value_files[MAX_CPUFREQ_VALUE_READ_FILES] = { +	[CPUINFO_CUR_FREQ] = "cpuinfo_cur_freq", +	[CPUINFO_MIN_FREQ] = "cpuinfo_min_freq", +	[CPUINFO_MAX_FREQ] = "cpuinfo_max_freq", +	[CPUINFO_LATENCY]  = "cpuinfo_transition_latency", +	[SCALING_CUR_FREQ] = "scaling_cur_freq", +	[SCALING_MIN_FREQ] = "scaling_min_freq", +	[SCALING_MAX_FREQ] = "scaling_max_freq", +	[STATS_NUM_TRANSITIONS] = "stats/total_trans" +}; + + +static unsigned long sysfs_cpufreq_get_one_value(unsigned int cpu, +						 enum cpufreq_value which) +{ +	unsigned long value; +	unsigned int len; +	char linebuf[MAX_LINE_LEN]; +	char *endp; + +	if (which >= MAX_CPUFREQ_VALUE_READ_FILES) +		return 0; + +	len = sysfs_cpufreq_read_file(cpu, cpufreq_value_files[which], +				linebuf, sizeof(linebuf)); + +	if (len == 0) +		return 0; + +	value = strtoul(linebuf, &endp, 0); + +	if (endp == linebuf || errno == ERANGE) +		return 0; + +	return value; +} + +/* read access to files which contain one string */ + +enum cpufreq_string { +	SCALING_DRIVER, +	SCALING_GOVERNOR, +	MAX_CPUFREQ_STRING_FILES +}; + +static const char *cpufreq_string_files[MAX_CPUFREQ_STRING_FILES] = { +	[SCALING_DRIVER] = "scaling_driver", +	[SCALING_GOVERNOR] = "scaling_governor", +}; + + +static char *sysfs_cpufreq_get_one_string(unsigned int cpu, +					   enum cpufreq_string which) +{ +	char linebuf[MAX_LINE_LEN]; +	char *result; +	unsigned int len; + +	if (which >= MAX_CPUFREQ_STRING_FILES) +		return NULL; + +	len = sysfs_cpufreq_read_file(cpu, cpufreq_string_files[which], +				linebuf, sizeof(linebuf)); +	if (len == 0) +		return NULL; + +	result = strdup(linebuf); +	if (result == NULL) +		return NULL; + +	if (result[strlen(result) - 1] == '\n') +		result[strlen(result) - 1] = '\0'; + +	return result; +} + +/* write access */ + +enum cpufreq_write { +	WRITE_SCALING_MIN_FREQ, +	WRITE_SCALING_MAX_FREQ, +	WRITE_SCALING_GOVERNOR, +	WRITE_SCALING_SET_SPEED, +	MAX_CPUFREQ_WRITE_FILES +}; + +static const char *cpufreq_write_files[MAX_CPUFREQ_WRITE_FILES] = { +	[WRITE_SCALING_MIN_FREQ] = "scaling_min_freq", +	[WRITE_SCALING_MAX_FREQ] = "scaling_max_freq", +	[WRITE_SCALING_GOVERNOR] = "scaling_governor", +	[WRITE_SCALING_SET_SPEED] = "scaling_setspeed", +}; + +static int sysfs_cpufreq_write_one_value(unsigned int cpu, +					 enum cpufreq_write which, +					 const char *new_value, size_t len) +{ +	if (which >= MAX_CPUFREQ_WRITE_FILES) +		return 0; + +	if (sysfs_cpufreq_write_file(cpu, cpufreq_write_files[which], +					new_value, len) != len) +		return -ENODEV; + +	return 0; +}; + +unsigned long sysfs_get_freq_kernel(unsigned int cpu) +{ +	return sysfs_cpufreq_get_one_value(cpu, SCALING_CUR_FREQ); +} + +unsigned long sysfs_get_freq_hardware(unsigned int cpu) +{ +	return sysfs_cpufreq_get_one_value(cpu, CPUINFO_CUR_FREQ); +} + +unsigned long sysfs_get_freq_transition_latency(unsigned int cpu) +{ +	return sysfs_cpufreq_get_one_value(cpu, CPUINFO_LATENCY); +} + +int sysfs_get_freq_hardware_limits(unsigned int cpu, +			      unsigned long *min, +			      unsigned long *max) +{ +	if ((!min) || (!max)) +		return -EINVAL; + +	*min = sysfs_cpufreq_get_one_value(cpu, CPUINFO_MIN_FREQ); +	if (!*min) +		return -ENODEV; + +	*max = sysfs_cpufreq_get_one_value(cpu, CPUINFO_MAX_FREQ); +	if (!*max) +		return -ENODEV; + +	return 0; +} + +char *sysfs_get_freq_driver(unsigned int cpu) +{ +	return sysfs_cpufreq_get_one_string(cpu, SCALING_DRIVER); +} + +struct cpufreq_policy *sysfs_get_freq_policy(unsigned int cpu) +{ +	struct cpufreq_policy *policy; + +	policy = malloc(sizeof(struct cpufreq_policy)); +	if (!policy) +		return NULL; + +	policy->governor = sysfs_cpufreq_get_one_string(cpu, SCALING_GOVERNOR); +	if (!policy->governor) { +		free(policy); +		return NULL; +	} +	policy->min = sysfs_cpufreq_get_one_value(cpu, SCALING_MIN_FREQ); +	policy->max = sysfs_cpufreq_get_one_value(cpu, SCALING_MAX_FREQ); +	if ((!policy->min) || (!policy->max)) { +		free(policy->governor); +		free(policy); +		return NULL; +	} + +	return policy; +} + +struct cpufreq_available_governors * +sysfs_get_freq_available_governors(unsigned int cpu) { +	struct cpufreq_available_governors *first = NULL; +	struct cpufreq_available_governors *current = NULL; +	char linebuf[MAX_LINE_LEN]; +	unsigned int pos, i; +	unsigned int len; + +	len = sysfs_cpufreq_read_file(cpu, "scaling_available_governors", +				linebuf, sizeof(linebuf)); +	if (len == 0) +		return NULL; + +	pos = 0; +	for (i = 0; i < len; i++) { +		if (linebuf[i] == ' ' || linebuf[i] == '\n') { +			if (i - pos < 2) +				continue; +			if (current) { +				current->next = malloc(sizeof(*current)); +				if (!current->next) +					goto error_out; +				current = current->next; +			} else { +				first = malloc(sizeof(*first)); +				if (!first) +					goto error_out; +				current = first; +			} +			current->first = first; +			current->next = NULL; + +			current->governor = malloc(i - pos + 1); +			if (!current->governor) +				goto error_out; + +			memcpy(current->governor, linebuf + pos, i - pos); +			current->governor[i - pos] = '\0'; +			pos = i + 1; +		} +	} + +	return first; + + error_out: +	while (first) { +		current = first->next; +		if (first->governor) +			free(first->governor); +		free(first); +		first = current; +	} +	return NULL; +} + + +struct cpufreq_available_frequencies * +sysfs_get_available_frequencies(unsigned int cpu) { +	struct cpufreq_available_frequencies *first = NULL; +	struct cpufreq_available_frequencies *current = NULL; +	char one_value[SYSFS_PATH_MAX]; +	char linebuf[MAX_LINE_LEN]; +	unsigned int pos, i; +	unsigned int len; + +	len = sysfs_cpufreq_read_file(cpu, "scaling_available_frequencies", +				linebuf, sizeof(linebuf)); +	if (len == 0) +		return NULL; + +	pos = 0; +	for (i = 0; i < len; i++) { +		if (linebuf[i] == ' ' || linebuf[i] == '\n') { +			if (i - pos < 2) +				continue; +			if (i - pos >= SYSFS_PATH_MAX) +				goto error_out; +			if (current) { +				current->next = malloc(sizeof(*current)); +				if (!current->next) +					goto error_out; +				current = current->next; +			} else { +				first = malloc(sizeof(*first)); +				if (!first) +					goto error_out; +				current = first; +			} +			current->first = first; +			current->next = NULL; + +			memcpy(one_value, linebuf + pos, i - pos); +			one_value[i - pos] = '\0'; +			if (sscanf(one_value, "%lu", ¤t->frequency) != 1) +				goto error_out; + +			pos = i + 1; +		} +	} + +	return first; + + error_out: +	while (first) { +		current = first->next; +		free(first); +		first = current; +	} +	return NULL; +} + +static struct cpufreq_affected_cpus *sysfs_get_cpu_list(unsigned int cpu, +							const char *file) +{ +	struct cpufreq_affected_cpus *first = NULL; +	struct cpufreq_affected_cpus *current = NULL; +	char one_value[SYSFS_PATH_MAX]; +	char linebuf[MAX_LINE_LEN]; +	unsigned int pos, i; +	unsigned int len; + +	len = sysfs_cpufreq_read_file(cpu, file, linebuf, sizeof(linebuf)); +	if (len == 0) +		return NULL; + +	pos = 0; +	for (i = 0; i < len; i++) { +		if (i == len || linebuf[i] == ' ' || linebuf[i] == '\n') { +			if (i - pos  < 1) +				continue; +			if (i - pos >= SYSFS_PATH_MAX) +				goto error_out; +			if (current) { +				current->next = malloc(sizeof(*current)); +				if (!current->next) +					goto error_out; +				current = current->next; +			} else { +				first = malloc(sizeof(*first)); +				if (!first) +					goto error_out; +				current = first; +			} +			current->first = first; +			current->next = NULL; + +			memcpy(one_value, linebuf + pos, i - pos); +			one_value[i - pos] = '\0'; + +			if (sscanf(one_value, "%u", ¤t->cpu) != 1) +				goto error_out; + +			pos = i + 1; +		} +	} + +	return first; + + error_out: +	while (first) { +		current = first->next; +		free(first); +		first = current; +	} +	return NULL; +} + +struct cpufreq_affected_cpus *sysfs_get_freq_affected_cpus(unsigned int cpu) +{ +	return sysfs_get_cpu_list(cpu, "affected_cpus"); +} + +struct cpufreq_affected_cpus *sysfs_get_freq_related_cpus(unsigned int cpu) +{ +	return sysfs_get_cpu_list(cpu, "related_cpus"); +} + +struct cpufreq_stats *sysfs_get_freq_stats(unsigned int cpu, +					unsigned long long *total_time) { +	struct cpufreq_stats *first = NULL; +	struct cpufreq_stats *current = NULL; +	char one_value[SYSFS_PATH_MAX]; +	char linebuf[MAX_LINE_LEN]; +	unsigned int pos, i; +	unsigned int len; + +	len = sysfs_cpufreq_read_file(cpu, "stats/time_in_state", +				linebuf, sizeof(linebuf)); +	if (len == 0) +		return NULL; + +	*total_time = 0; +	pos = 0; +	for (i = 0; i < len; i++) { +		if (i == strlen(linebuf) || linebuf[i] == '\n')	{ +			if (i - pos < 2) +				continue; +			if ((i - pos) >= SYSFS_PATH_MAX) +				goto error_out; +			if (current) { +				current->next = malloc(sizeof(*current)); +				if (!current->next) +					goto error_out; +				current = current->next; +			} else { +				first = malloc(sizeof(*first)); +				if (!first) +					goto error_out; +				current = first; +			} +			current->first = first; +			current->next = NULL; + +			memcpy(one_value, linebuf + pos, i - pos); +			one_value[i - pos] = '\0'; +			if (sscanf(one_value, "%lu %llu", +					¤t->frequency, +					¤t->time_in_state) != 2) +				goto error_out; + +			*total_time = *total_time + current->time_in_state; +			pos = i + 1; +		} +	} + +	return first; + + error_out: +	while (first) { +		current = first->next; +		free(first); +		first = current; +	} +	return NULL; +} + +unsigned long sysfs_get_freq_transitions(unsigned int cpu) +{ +	return sysfs_cpufreq_get_one_value(cpu, STATS_NUM_TRANSITIONS); +} + +static int verify_gov(char *new_gov, char *passed_gov) +{ +	unsigned int i, j = 0; + +	if (!passed_gov || (strlen(passed_gov) > 19)) +		return -EINVAL; + +	strncpy(new_gov, passed_gov, 20); +	for (i = 0; i < 20; i++) { +		if (j) { +			new_gov[i] = '\0'; +			continue; +		} +		if ((new_gov[i] >= 'a') && (new_gov[i] <= 'z')) +			continue; + +		if ((new_gov[i] >= 'A') && (new_gov[i] <= 'Z')) +			continue; + +		if (new_gov[i] == '-') +			continue; + +		if (new_gov[i] == '_') +			continue; + +		if (new_gov[i] == '\0') { +			j = 1; +			continue; +		} +		return -EINVAL; +	} +	new_gov[19] = '\0'; +	return 0; +} + +int sysfs_modify_freq_policy_governor(unsigned int cpu, char *governor) +{ +	char new_gov[SYSFS_PATH_MAX]; + +	if (!governor) +		return -EINVAL; + +	if (verify_gov(new_gov, governor)) +		return -EINVAL; + +	return sysfs_cpufreq_write_one_value(cpu, WRITE_SCALING_GOVERNOR, +					     new_gov, strlen(new_gov)); +}; + +int sysfs_modify_freq_policy_max(unsigned int cpu, unsigned long max_freq) +{ +	char value[SYSFS_PATH_MAX]; + +	snprintf(value, SYSFS_PATH_MAX, "%lu", max_freq); + +	return sysfs_cpufreq_write_one_value(cpu, WRITE_SCALING_MAX_FREQ, +					     value, strlen(value)); +}; + + +int sysfs_modify_freq_policy_min(unsigned int cpu, unsigned long min_freq) +{ +	char value[SYSFS_PATH_MAX]; + +	snprintf(value, SYSFS_PATH_MAX, "%lu", min_freq); + +	return sysfs_cpufreq_write_one_value(cpu, WRITE_SCALING_MIN_FREQ, +					     value, strlen(value)); +}; + + +int sysfs_set_freq_policy(unsigned int cpu, struct cpufreq_policy *policy) +{ +	char min[SYSFS_PATH_MAX]; +	char max[SYSFS_PATH_MAX]; +	char gov[SYSFS_PATH_MAX]; +	int ret; +	unsigned long old_min; +	int write_max_first; + +	if (!policy || !(policy->governor)) +		return -EINVAL; + +	if (policy->max < policy->min) +		return -EINVAL; + +	if (verify_gov(gov, policy->governor)) +		return -EINVAL; + +	snprintf(min, SYSFS_PATH_MAX, "%lu", policy->min); +	snprintf(max, SYSFS_PATH_MAX, "%lu", policy->max); + +	old_min = sysfs_cpufreq_get_one_value(cpu, SCALING_MIN_FREQ); +	write_max_first = (old_min && (policy->max < old_min) ? 0 : 1); + +	if (write_max_first) { +		ret = sysfs_cpufreq_write_one_value(cpu, WRITE_SCALING_MAX_FREQ, +						    max, strlen(max)); +		if (ret) +			return ret; +	} + +	ret = sysfs_cpufreq_write_one_value(cpu, WRITE_SCALING_MIN_FREQ, min, +					    strlen(min)); +	if (ret) +		return ret; + +	if (!write_max_first) { +		ret = sysfs_cpufreq_write_one_value(cpu, WRITE_SCALING_MAX_FREQ, +						    max, strlen(max)); +		if (ret) +			return ret; +	} + +	return sysfs_cpufreq_write_one_value(cpu, WRITE_SCALING_GOVERNOR, +					     gov, strlen(gov)); +} + +int sysfs_set_frequency(unsigned int cpu, unsigned long target_frequency) +{ +	struct cpufreq_policy *pol = sysfs_get_freq_policy(cpu); +	char userspace_gov[] = "userspace"; +	char freq[SYSFS_PATH_MAX]; +	int ret; + +	if (!pol) +		return -ENODEV; + +	if (strncmp(pol->governor, userspace_gov, 9) != 0) { +		ret = sysfs_modify_freq_policy_governor(cpu, userspace_gov); +		if (ret) { +			cpufreq_put_policy(pol); +			return ret; +		} +	} + +	cpufreq_put_policy(pol); + +	snprintf(freq, SYSFS_PATH_MAX, "%lu", target_frequency); + +	return sysfs_cpufreq_write_one_value(cpu, WRITE_SCALING_SET_SPEED, +					     freq, strlen(freq)); +} + +/* CPUFREQ sysfs access **************************************************/ + +/* General sysfs access **************************************************/ +int sysfs_cpu_exists(unsigned int cpu) +{ +	char file[SYSFS_PATH_MAX]; +	struct stat statbuf; + +	snprintf(file, SYSFS_PATH_MAX, PATH_TO_CPU "cpu%u/", cpu); + +	if (stat(file, &statbuf) != 0) +		return -ENOSYS; + +	return S_ISDIR(statbuf.st_mode) ? 0 : -ENOSYS; +} + +/* General sysfs access **************************************************/ diff --git a/tools/power/cpupower/lib/sysfs.h b/tools/power/cpupower/lib/sysfs.h new file mode 100644 index 00000000000..c76a5e0af50 --- /dev/null +++ b/tools/power/cpupower/lib/sysfs.h @@ -0,0 +1,31 @@ +/* General */ +extern unsigned int sysfs_cpu_exists(unsigned int cpu); + +/* CPUfreq */ +extern unsigned long sysfs_get_freq_kernel(unsigned int cpu); +extern unsigned long sysfs_get_freq_hardware(unsigned int cpu); +extern unsigned long sysfs_get_freq_transition_latency(unsigned int cpu); +extern int sysfs_get_freq_hardware_limits(unsigned int cpu, +					unsigned long *min, unsigned long *max); +extern char *sysfs_get_freq_driver(unsigned int cpu); +extern struct cpufreq_policy *sysfs_get_freq_policy(unsigned int cpu); +extern struct cpufreq_available_governors *sysfs_get_freq_available_governors( +	unsigned int cpu); +extern struct cpufreq_available_frequencies *sysfs_get_available_frequencies( +	unsigned int cpu); +extern struct cpufreq_affected_cpus *sysfs_get_freq_affected_cpus( +	unsigned int cpu); +extern struct cpufreq_affected_cpus *sysfs_get_freq_related_cpus( +	unsigned int cpu); +extern struct cpufreq_stats *sysfs_get_freq_stats(unsigned int cpu, +						unsigned long long *total_time); +extern unsigned long sysfs_get_freq_transitions(unsigned int cpu); +extern int sysfs_set_freq_policy(unsigned int cpu, +				struct cpufreq_policy *policy); +extern int sysfs_modify_freq_policy_min(unsigned int cpu, +					unsigned long min_freq); +extern int sysfs_modify_freq_policy_max(unsigned int cpu, +					unsigned long max_freq); +extern int sysfs_modify_freq_policy_governor(unsigned int cpu, char *governor); +extern int sysfs_set_frequency(unsigned int cpu, +			unsigned long target_frequency); diff --git a/tools/power/cpupower/man/cpupower-frequency-info.1 b/tools/power/cpupower/man/cpupower-frequency-info.1 new file mode 100644 index 00000000000..9c85a382e35 --- /dev/null +++ b/tools/power/cpupower/man/cpupower-frequency-info.1 @@ -0,0 +1,77 @@ +.TH "CPUPOWER\-FREQUENCY\-INFO" "1" "0.1" "" "cpupower Manual" +.SH "NAME" +.LP  +cpupower frequency\-info \- Utility to retrieve cpufreq kernel information +.SH "SYNTAX" +.LP  +cpupower [ \-c cpulist ] frequency\-info [\fIoptions\fP] +.SH "DESCRIPTION" +.LP  +A small tool which prints out cpufreq information helpful to developers and interested users. +.SH "OPTIONS" +.LP  +.TP   +\fB\-e\fR \fB\-\-debug\fR +Prints out debug information. +.TP   +\fB\-f\fR \fB\-\-freq\fR +Get frequency the CPU currently runs at, according to the cpufreq core. +.TP   +\fB\-w\fR \fB\-\-hwfreq\fR +Get frequency the CPU currently runs at, by reading it from hardware (only available to root). +.TP   +\fB\-l\fR \fB\-\-hwlimits\fR +Determine the minimum and maximum CPU frequency allowed. +.TP   +\fB\-d\fR \fB\-\-driver\fR +Determines the used cpufreq kernel driver. +.TP   +\fB\-p\fR \fB\-\-policy\fR +Gets the currently used cpufreq policy. +.TP   +\fB\-g\fR \fB\-\-governors\fR +Determines available cpufreq governors. +.TP   +\fB\-a\fR \fB\-\-related\-cpus\fR +Determines which CPUs run at the same hardware frequency. +.TP   +\fB\-a\fR \fB\-\-affected\-cpus\fR +Determines which CPUs need to have their frequency coordinated by software. +.TP   +\fB\-s\fR \fB\-\-stats\fR +Shows cpufreq statistics if available. +.TP   +\fB\-y\fR \fB\-\-latency\fR +Determines the maximum latency on CPU frequency changes. +.TP   +\fB\-o\fR \fB\-\-proc\fR +Prints out information like provided by the /proc/cpufreq interface in 2.4. and early 2.6. kernels. +.TP   +\fB\-m\fR \fB\-\-human\fR +human\-readable output for the \-f, \-w, \-s and \-y parameters. +.TP   +\fB\-n\fR \fB\-\-no-rounding\fR +Output frequencies and latencies without rounding off values. +.TP   +.SH "REMARKS" +.LP  +By default only values of core zero are displayed. How to display settings of +other cores is described in the cpupower(1) manpage in the \-\-cpu option section. +.LP  +You can't specify more than one of the output specific options \-o \-e \-a \-g \-p \-d \-l \-w \-f \-y. +.LP  +You also can't specify the \-o option combined with the \-c option. +.SH "FILES" +.nf  +\fI/sys/devices/system/cpu/cpu*/cpufreq/\fP   +\fI/proc/cpufreq\fP (deprecated)  +\fI/proc/sys/cpu/\fP (deprecated) +.fi  +.SH "AUTHORS" +.nf +Dominik Brodowski <linux@brodo.de> \- author  +Mattia Dongili<malattia@gmail.com> \- first autolibtoolization +.fi +.SH "SEE ALSO" +.LP  +cpupower\-frequency\-set(1), cpupower(1) diff --git a/tools/power/cpupower/man/cpupower-frequency-set.1 b/tools/power/cpupower/man/cpupower-frequency-set.1 new file mode 100644 index 00000000000..3eacc8d03d1 --- /dev/null +++ b/tools/power/cpupower/man/cpupower-frequency-set.1 @@ -0,0 +1,52 @@ +.TH "CPUPOWER\-FREQUENCY\-SET" "1" "0.1" "" "cpupower Manual" +.SH "NAME" +.LP  +cpupower frequency\-set \- A small tool which allows to modify cpufreq settings. +.SH "SYNTAX" +.LP  +cpupower [ \-c cpu ] frequency\-set [\fIoptions\fP] +.SH "DESCRIPTION" +.LP  +cpupower frequency\-set allows you to modify cpufreq settings without having to type e.g. "/sys/devices/system/cpu/cpu0/cpufreq/scaling_set_speed" all the time. +.SH "OPTIONS" +.LP  +.TP  +\fB\-d\fR \fB\-\-min\fR <FREQ> +new minimum CPU frequency the governor may select. +.TP  +\fB\-u\fR \fB\-\-max\fR <FREQ> +new maximum CPU frequency the governor may select. +.TP  +\fB\-g\fR \fB\-\-governor\fR <GOV> +new cpufreq governor. +.TP  +\fB\-f\fR \fB\-\-freq\fR <FREQ> +specific frequency to be set. Requires userspace governor to be available and loaded. +.TP  +\fB\-r\fR \fB\-\-related\fR +modify all hardware-related CPUs at the same time +.TP  +.SH "REMARKS" +.LP  +By default values are applied on all cores. How to modify single core +configurations is described in the cpupower(1) manpage in the \-\-cpu option section. +.LP  +The \-f FREQ, \-\-freq FREQ parameter cannot be combined with any other parameter. +.LP  +FREQuencies can be passed in Hz, kHz (default), MHz, GHz, or THz by postfixing the value with the wanted unit name, without any space (frequency in kHz =^ Hz * 0.001 =^ MHz * 1000 =^ GHz * 1000000). +.LP  +On Linux kernels up to 2.6.29, the \-r or \-\-related parameter is ignored. +.SH "FILES"  +.nf +\fI/sys/devices/system/cpu/cpu*/cpufreq/\fP   +\fI/proc/cpufreq\fP (deprecated)  +\fI/proc/sys/cpu/\fP (deprecated) +.fi  +.SH "AUTHORS" +.nf  +Dominik Brodowski <linux@brodo.de> \- author  +Mattia Dongili<malattia@gmail.com> \- first autolibtoolization +.fi +.SH "SEE ALSO" +.LP  +cpupower\-frequency\-info(1), cpupower(1) diff --git a/tools/power/cpupower/man/cpupower-idle-info.1 b/tools/power/cpupower/man/cpupower-idle-info.1 new file mode 100644 index 00000000000..7b3646adb92 --- /dev/null +++ b/tools/power/cpupower/man/cpupower-idle-info.1 @@ -0,0 +1,91 @@ +.TH "CPUPOWER-IDLE-INFO" "1" "0.1" "" "cpupower Manual" +.SH "NAME" +.LP +cpupower idle\-info \- Utility to retrieve cpu idle kernel information +.SH "SYNTAX" +.LP +cpupower [ \-c cpulist ] idle\-info [\fIoptions\fP] +.SH "DESCRIPTION" +.LP +A tool which prints out per cpu idle information helpful to developers and interested users. +.SH "OPTIONS" +.LP +.TP +\fB\-f\fR \fB\-\-silent\fR +Only print a summary of all available C-states in the system. +.TP +\fB\-e\fR \fB\-\-proc\fR +deprecated. +Prints out idle information in old /proc/acpi/processor/*/power format. This +interface has been removed from the kernel for quite some time, do not let +further code depend on this option, best do not use it. + +.SH IDLE\-INFO DESCRIPTIONS +CPU sleep state statistics and descriptions are retrieved from sysfs files, +exported by the cpuidle kernel subsystem. The kernel only updates these +statistics when it enters or leaves an idle state, therefore on a very idle or +a very busy system, these statistics may not be accurate. They still provide a +good overview about the usage and availability of processor sleep states on +the platform. + +Be aware that the sleep states as exported by the hardware or BIOS and used by +the Linux kernel may not exactly reflect the capabilities of the +processor. This often is the case on the X86 architecture when the acpi_idle +driver is used. It is also possible that the hardware overrules the kernel +requests, due to internal activity monitors or other reasons. +On recent X86 platforms it is often possible to read out hardware registers +which monitor the duration of sleep states the processor resided in. The +cpupower monitor tool (cpupower\-monitor(1)) can be used to show real sleep +state residencies. Please refer to the architecture specific description +section below. + +.SH IDLE\-INFO ARCHITECTURE SPECIFIC DESCRIPTIONS +.SS "X86" +POLL idle state + +If cpuidle is active, X86 platforms have one special idle state. +The POLL idle state is not a real idle state, it does not save any +power. Instead, a busy\-loop is executed doing nothing for a short period of +time. This state is used if the kernel knows that work has to be processed +very soon and entering any real hardware idle state may result in a slight +performance penalty. + +There exist two different cpuidle drivers on the X86 architecture platform: + +"acpi_idle" cpuidle driver + +The acpi_idle cpuidle driver retrieves available sleep states (C\-states) from +the ACPI BIOS tables (from the _CST ACPI function on recent platforms or from +the FADT BIOS table on older ones). +The C1 state is not retrieved from ACPI tables. If the C1 state is entered, +the kernel will call the hlt instruction (or mwait on Intel). + +"intel_idle" cpuidle driver + +In kernel 2.6.36 the intel_idle driver was introduced. +It only serves recent Intel CPUs (Nehalem, Westmere, Sandybridge, Atoms or +newer). On older Intel CPUs the acpi_idle driver is still used (if the BIOS +provides C\-state ACPI tables). +The intel_idle driver knows the sleep state capabilities of the processor and +ignores ACPI BIOS exported processor sleep states tables. + +.SH "REMARKS" +.LP +By default only values of core zero are displayed. How to display settings of +other cores is described in the cpupower(1) manpage in the \-\-cpu option +section. +.SH REFERENCES +http://www.acpi.info/spec.htm +.SH "FILES" +.nf +\fI/sys/devices/system/cpu/cpu*/cpuidle/state*\fP +\fI/sys/devices/system/cpu/cpuidle/*\fP +.fi +.SH "AUTHORS" +.nf +Thomas Renninger <trenn@suse.de> +.fi +.SH "SEE ALSO" +.LP +cpupower(1), cpupower\-monitor(1), cpupower\-info(1), cpupower\-set(1), +cpupower\-idle\-set(1) diff --git a/tools/power/cpupower/man/cpupower-idle-set.1 b/tools/power/cpupower/man/cpupower-idle-set.1 new file mode 100644 index 00000000000..3e6799d7a79 --- /dev/null +++ b/tools/power/cpupower/man/cpupower-idle-set.1 @@ -0,0 +1,77 @@ +.TH "CPUPOWER-IDLE-SET" "1" "0.1" "" "cpupower Manual" +.SH "NAME" +.LP +cpupower idle\-set \- Utility to set cpu idle state specific kernel options +.SH "SYNTAX" +.LP +cpupower [ \-c cpulist ] idle\-info [\fIoptions\fP] +.SH "DESCRIPTION" +.LP +The cpupower idle\-set subcommand allows to set cpu idle, also called cpu +sleep state, specific options offered by the kernel. One example is disabling +sleep states. This can be handy for power vs performance tuning. +.SH "OPTIONS" +.LP +.TP +\fB\-d\fR \fB\-\-disable\fR <STATE_NO> +Disable a specific processor sleep state. +.TP +\fB\-e\fR \fB\-\-enable\fR <STATE_NO> +Enable a specific processor sleep state. +.TP +\fB\-D\fR \fB\-\-disable-by-latency\fR <LATENCY> +Disable all idle states with a equal or higher latency than <LATENCY> +.TP +\fB\-E\fR \fB\-\-enable-all\fR +Enable all idle states if not enabled already. + +.SH "REMARKS" +.LP +Cpuidle Governors Policy on Disabling Sleep States + +.RS 4 +Depending on the used  cpuidle governor, implementing the kernel policy +how to choose sleep states, subsequent sleep states on this core, might get +disabled as well. + +There are two cpuidle governors ladder and menu. While the ladder +governor is always available, if CONFIG_CPU_IDLE is selected, the +menu governor additionally requires CONFIG_NO_HZ. + +The behavior and the effect of the disable variable depends on the +implementation of a particular governor. In the ladder governor, for +example, it is not coherent, i.e. if one is disabling a light state, +then all deeper states are disabled as well. Likewise, if one enables a +deep state but a lighter state still is disabled, then this has no effect. +.RE +.LP +Disabling the Lightest Sleep State may not have any Affect + +.RS 4 +If criteria are not met to enter deeper sleep states and the lightest sleep +state is chosen when idle, the kernel may still enter this sleep state, +irrespective of whether it is disabled or not. This is also reflected in +the usage count of the disabled sleep state when using the cpupower idle-info +command. +.RE +.LP +Selecting specific CPU Cores + +.RS 4 +By default processor sleep states of all CPU cores are set. Please refer +to the cpupower(1) manpage in the \-\-cpu option section how to disable +C-states of specific cores. +.RE +.SH "FILES" +.nf +\fI/sys/devices/system/cpu/cpu*/cpuidle/state*\fP +\fI/sys/devices/system/cpu/cpuidle/*\fP +.fi +.SH "AUTHORS" +.nf +Thomas Renninger <trenn@suse.de> +.fi +.SH "SEE ALSO" +.LP +cpupower(1), cpupower\-monitor(1), cpupower\-info(1), cpupower\-set(1), +cpupower\-idle\-info(1) diff --git a/tools/power/cpupower/man/cpupower-info.1 b/tools/power/cpupower/man/cpupower-info.1 new file mode 100644 index 00000000000..340bcd0be7d --- /dev/null +++ b/tools/power/cpupower/man/cpupower-info.1 @@ -0,0 +1,19 @@ +.TH CPUPOWER\-INFO "1" "22/02/2011" "" "cpupower Manual" +.SH NAME +cpupower\-info \- Shows processor power related kernel or hardware configurations +.SH SYNOPSIS +.ft B +.B cpupower info [ \-b ] + +.SH DESCRIPTION +\fBcpupower info \fP shows kernel configurations or processor hardware +registers affecting processor power saving policies. + +Some options are platform wide, some affect single cores. By default values +of core zero are displayed only. cpupower --cpu all cpuinfo will show the +settings of all cores, see cpupower(1) how to choose specific cores. + +.SH "SEE ALSO" +Options are described in detail in: + +cpupower(1), cpupower-set(1) diff --git a/tools/power/cpupower/man/cpupower-monitor.1 b/tools/power/cpupower/man/cpupower-monitor.1 new file mode 100644 index 00000000000..914cbb9d9cd --- /dev/null +++ b/tools/power/cpupower/man/cpupower-monitor.1 @@ -0,0 +1,198 @@ +.TH CPUPOWER\-MONITOR "1" "22/02/2011" "" "cpupower Manual" +.SH NAME +cpupower\-monitor \- Report processor frequency and idle statistics +.SH SYNOPSIS +.ft B +.B cpupower monitor +.RB "\-l" + +.B cpupower monitor +.RB [ -c ] [ "\-m <mon1>," [ "<mon2>,..." ] ] +.RB [ "\-i seconds" ] +.br +.B cpupower monitor +.RB [ -c ][ "\-m <mon1>," [ "<mon2>,..." ] ] +.RB command +.br +.SH DESCRIPTION +\fBcpupower-monitor \fP reports processor topology, frequency and idle power +state statistics. Either \fBcommand\fP is forked and +statistics are printed upon its completion, or statistics are printed periodically. + +\fBcpupower-monitor \fP implements independent processor sleep state and +frequency counters. Some are retrieved from kernel statistics, some are +directly reading out hardware registers. Use \-l to get an overview which are +supported on your system. + +.SH Options +.PP +\-l +.RS 4 +List available monitors on your system. Additional details about each monitor +are shown: +.RS 2 +.IP \(bu +The name in quotation marks which can be passed to the \-m parameter. +.IP \(bu +The number of different counters the monitor supports in brackets. +.IP \(bu +The amount of time in seconds the counters might overflow, due to +implementation constraints. +.IP \(bu +The name and a description of each counter and its processor hierarchy level +coverage in square brackets: +.RS 4 +.IP \(bu +[T] \-> Thread +.IP \(bu +[C] \-> Core +.IP \(bu +[P] \-> Processor Package (Socket) +.IP \(bu +[M] \-> Machine/Platform wide counter +.RE +.RE +.RE +.PP +\-m <mon1>,<mon2>,... +.RS 4 +Only display specific monitors. Use the monitor string(s) provided by \-l option. +.RE +.PP +\-i seconds +.RS 4 +Measure intervall. +.RE +.PP +\-c +.RS 4 +Schedule the process on every core before starting and ending measuring. +This could be needed for the Idle_Stats monitor when no other MSR based +monitor (has to be run on the core that is measured) is run in parallel. +This is to wake up the processors from deeper sleep states and let the +kernel re +-account its cpuidle (C-state) information before reading the +cpuidle timings from sysfs. +.RE +.PP +command +.RS 4 +Measure idle and frequency characteristics of an arbitrary command/workload. +The executable \fBcommand\fP is forked and upon its exit, statistics gathered since it was +forked are displayed. +.RE +.PP +\-v +.RS 4 +Increase verbosity if the binary was compiled with the DEBUG option set. +.RE + +.SH MONITOR DESCRIPTIONS +.SS "Idle_Stats" +Shows statistics of the cpuidle kernel subsystem. Values are retrieved from +/sys/devices/system/cpu/cpu*/cpuidle/state*/. +The kernel updates these values every time an idle state is entered or +left. Therefore there can be some inaccuracy when cores are in an idle +state for some time when the measure starts or ends. In worst case it can happen +that one core stayed in an idle state for the whole measure time and the idle +state usage time as exported by the kernel did not get updated. In this case +a state residency of 0 percent is shown while it was 100. + +.SS "Mperf" +The name comes from the aperf/mperf (average and maximum) MSR registers used +which are available on recent X86 processors. It shows the average frequency +(including boost frequencies). +The fact that on all recent hardware the mperf timer stops ticking in any idle +state it is also used to show C0 (processor is active) and Cx (processor is in +any sleep state) times. These counters do not have the inaccuracy restrictions +the "Idle_Stats" counters may show. +May work poorly on Linux-2.6.20 through 2.6.29, as the \fBacpi-cpufreq \fP +kernel frequency driver periodically cleared aperf/mperf registers in those +kernels. + +.SS "Nehalem" "SandyBridge" "HaswellExtended" +Intel Core and Package sleep state counters. +Threads (hyperthreaded cores) may not be able to enter deeper core states if +its sibling is utilized. +Deepest package sleep states may in reality show up as machine/platform wide +sleep states and can only be entered if all cores are idle. Look up Intel +manuals (some are provided in the References section) for further details. +The monitors are named after the CPU family where the sleep state capabilities +got introduced and may not match exactly the CPU name of the platform. +For example an IvyBridge processor has sleep state capabilities which got +introduced in Nehalem and SandyBridge processor families. +Thus on an IvyBridge processor one will get Nehalem and SandyBridge sleep +state monitors. +HaswellExtended extra package sleep state capabilities are available only in a +specific Haswell (family 0x45) and probably also other future processors. + +.SS "Fam_12h" "Fam_14h" +AMD laptop and desktop processor (family 12h and 14h) sleep state counters. +The registers are accessed via PCI and therefore can still be read out while +cores have been offlined. + +There is one special counter: NBP1 (North Bridge P1). +This one always returns 0 or 1, depending on whether the North Bridge P1 +power state got entered at least once during measure time. +Being able to enter NBP1 state also depends on graphics power management. +Therefore this counter can be used to verify whether the graphics' driver +power management is working as expected. + +.SH EXAMPLES + +cpupower monitor -l" may show: +.RS 4 +Monitor "Mperf" (3 states) \- Might overflow after 922000000 s + +   ... + +Monitor "Idle_Stats" (3 states) \- Might overflow after 4294967295 s + +   ... + +.RE +cpupower monitor \-m "Idle_Stats,Mperf" scp /tmp/test /nfs/tmp + +Monitor the scp command, show both Mperf and Idle_Stats states counter +statistics, but in exchanged order. + + + +.RE +Be careful that the typical command to fully utilize one CPU by doing: + +cpupower monitor cat /dev/zero >/dev/null + +Does not work as expected, because the measured output is redirected to +/dev/null. This could get workarounded by putting the line into an own, tiny +shell script. Hit CTRL\-c to terminate the command and get the measure output +displayed. + +.SH REFERENCES +"BIOS and Kernel Developer’s Guide (BKDG) for AMD Family 14h Processors" +http://support.amd.com/us/Processor_TechDocs/43170.pdf + +"Intel® Turbo Boost Technology +in Intel® Coreâ„¢ Microarchitecture (Nehalem) Based Processors" +http://download.intel.com/design/processor/applnots/320354.pdf + +"Intel® 64 and IA-32 Architectures Software Developer's Manual +Volume 3B: System Programming Guide" +http://www.intel.com/products/processor/manuals + +.SH FILES +.ta +.nf +/dev/cpu/*/msr +/sys/devices/system/cpu/cpu*/cpuidle/state*/. +.fi + +.SH "SEE ALSO" +powertop(8), msr(4), vmstat(8) +.PP +.SH AUTHORS +.nf +Written by Thomas Renninger <trenn@suse.de> + +Nehalem, SandyBridge monitors and command passing +based on turbostat.8 from Len Brown <len.brown@intel.com> diff --git a/tools/power/cpupower/man/cpupower-set.1 b/tools/power/cpupower/man/cpupower-set.1 new file mode 100644 index 00000000000..2bcc696f449 --- /dev/null +++ b/tools/power/cpupower/man/cpupower-set.1 @@ -0,0 +1,65 @@ +.TH CPUPOWER\-SET "1" "22/02/2011" "" "cpupower Manual" +.SH NAME +cpupower\-set \- Set processor power related kernel or hardware configurations +.SH SYNOPSIS +.ft B +.B cpupower set [ \-b VAL ] + + +.SH DESCRIPTION +\fBcpupower set \fP sets kernel configurations or directly accesses hardware +registers affecting processor power saving policies. + +Some options are platform wide, some affect single cores. By default values +are applied on all cores. How to modify single core configurations is +described in the cpupower(1) manpage in the \-\-cpu option section. Whether an +option affects the whole system or can be applied to individual cores is +described in the Options sections. + +Use \fBcpupower info \fP to read out current settings and whether they are +supported on the system at all. + +.SH Options +.PP +\-\-perf-bias, \-b +.RS 4 +Sets a register on supported Intel processore which allows software to convey +its policy for the relative importance of performance versus energy savings to +the  processor. + +The range of valid numbers is 0-15, where 0 is maximum +performance and 15 is maximum energy efficiency. + +The processor uses this information in model-specific ways +when it must select trade-offs between performance and +energy efficiency. + +This policy hint does not supersede Processor Performance states +(P-states) or CPU Idle power states (C-states), but allows +software to have influence where it would otherwise be unable +to express a preference. + +For example, this setting may tell the hardware how +aggressively or conservatively to control frequency +in the "turbo range" above the explicitly OS-controlled +P-state frequency range.  It may also tell the hardware +how aggressively it should enter the OS requested C-states. + +This option can be applied to individual cores only via the \-\-cpu option, +cpupower(1). + +Setting the performance bias value on one CPU can modify the setting on +related CPUs as well (for example all CPUs on one socket), because of +hardware restrictions. +Use \fBcpupower -c all info -b\fP to verify. + +This options needs the msr kernel driver (CONFIG_X86_MSR) loaded. +.RE + +.SH "SEE ALSO" +cpupower-info(1), cpupower-monitor(1), powertop(1) +.PP +.SH AUTHORS +.nf +\-\-perf\-bias parts written by Len Brown <len.brown@intel.com> +Thomas Renninger <trenn@suse.de> diff --git a/tools/power/cpupower/man/cpupower.1 b/tools/power/cpupower/man/cpupower.1 new file mode 100644 index 00000000000..baf741d06e8 --- /dev/null +++ b/tools/power/cpupower/man/cpupower.1 @@ -0,0 +1,72 @@ +.TH CPUPOWER "1" "07/03/2011" "" "cpupower Manual" +.SH NAME +cpupower \- Shows and sets processor power related values +.SH SYNOPSIS +.ft B +.B cpupower [ \-c cpulist ] <command> [ARGS] + +.B cpupower \-v|\-\-version + +.B cpupower \-h|\-\-help + +.SH DESCRIPTION +\fBcpupower \fP is a collection of tools to examine and tune power saving +related features of your processor. + +The manpages of the commands (cpupower\-<command>(1)) provide detailed +descriptions of supported features. Run \fBcpupower help\fP to get an overview +of supported commands. + +.SH Options +.PP +\-\-help, \-h +.RS 4 +Shows supported commands and general usage. +.RE +.PP +\-\-cpu cpulist,  \-c cpulist +.RS 4 +Only show or set values for specific cores. +This option is not supported by all commands, details can be found in the +manpages of the commands. + +Some commands access all cores (typically the *\-set commands), some only +the first core (typically the *\-info commands) by default. + +The syntax for <cpulist> is based on how the kernel exports CPU bitmasks via +sysfs files. Some examples: +.RS 4 +.TP 16 +Input +Equivalent to +.TP +all +all cores +.TP +0\-3 +0,1,2,3 +.TP +0\-7:2 +0,2,4,6 +.TP +1,3,5-7 +1,3,5,6,7 +.TP +0\-3:2,8\-15:4 +0,2,8,12	 +.RE +.RE +.PP +\-\-version,  \-v +.RS 4 +Print the package name and version number. + +.SH "SEE ALSO" +cpupower-set(1), cpupower-info(1), cpupower-idle(1), +cpupower-frequency-set(1), cpupower-frequency-info(1), cpupower-monitor(1), +powertop(1) +.PP +.SH AUTHORS +.nf +\-\-perf\-bias parts written by Len Brown <len.brown@intel.com> +Thomas Renninger <trenn@suse.de> diff --git a/tools/power/cpupower/po/cs.po b/tools/power/cpupower/po/cs.po new file mode 100644 index 00000000000..cb22c45c506 --- /dev/null +++ b/tools/power/cpupower/po/cs.po @@ -0,0 +1,944 @@ +# translation of cs.po to Czech +# Czech translation for cpufrequtils package +# Czech messages for cpufrequtils. +# Copyright (C) 2007 kavol +# This file is distributed under the same license as the cpufrequtils package. +# +# Karel Volný <kavol@seznam.cz>, 2007, 2008. +msgid "" +msgstr "" +"Project-Id-Version: cs\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2011-03-08 17:03+0100\n" +"PO-Revision-Date: 2008-06-11 16:26+0200\n" +"Last-Translator: Karel Volný <kavol@seznam.cz>\n" +"Language-Team: Czech <diskuze@lists.l10n.cz>\n" +"Language: cs\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms:  nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n" +"X-Generator: KBabel 1.11.4\n" + +#: utils/idle_monitor/nhm_idle.c:36 +msgid "Processor Core C3" +msgstr "" + +#: utils/idle_monitor/nhm_idle.c:43 +msgid "Processor Core C6" +msgstr "" + +#: utils/idle_monitor/nhm_idle.c:51 +msgid "Processor Package C3" +msgstr "" + +#: utils/idle_monitor/nhm_idle.c:58 utils/idle_monitor/amd_fam14h_idle.c:70 +msgid "Processor Package C6" +msgstr "" + +#: utils/idle_monitor/snb_idle.c:33 +msgid "Processor Core C7" +msgstr "" + +#: utils/idle_monitor/snb_idle.c:40 +msgid "Processor Package C2" +msgstr "" + +#: utils/idle_monitor/snb_idle.c:47 +msgid "Processor Package C7" +msgstr "" + +#: utils/idle_monitor/amd_fam14h_idle.c:56 +msgid "Package in sleep state (PC1 or deeper)" +msgstr "" + +#: utils/idle_monitor/amd_fam14h_idle.c:63 +msgid "Processor Package C1" +msgstr "" + +#: utils/idle_monitor/amd_fam14h_idle.c:77 +msgid "North Bridge P1 boolean counter (returns 0 or 1)" +msgstr "" + +#: utils/idle_monitor/mperf_monitor.c:35 +msgid "Processor Core not idle" +msgstr "" + +#: utils/idle_monitor/mperf_monitor.c:42 +msgid "Processor Core in an idle state" +msgstr "" + +#: utils/idle_monitor/mperf_monitor.c:50 +msgid "Average Frequency (including boost) in MHz" +msgstr "" + +#: utils/idle_monitor/cpupower-monitor.c:66 +#, c-format +msgid "" +"cpupower monitor: [-h] [ [-t] | [-l] | [-m <mon1>,[<mon2>] ] ] [-i " +"interval_sec | -c command ...]\n" +msgstr "" + +#: utils/idle_monitor/cpupower-monitor.c:69 +#, c-format +msgid "" +"cpupower monitor: [-v] [-h] [ [-t] | [-l] | [-m <mon1>,[<mon2>] ] ] [-i " +"interval_sec | -c command ...]\n" +msgstr "" + +#: utils/idle_monitor/cpupower-monitor.c:71 +#, c-format +msgid "\t -v: be more verbose\n" +msgstr "" + +#: utils/idle_monitor/cpupower-monitor.c:73 +#, c-format +msgid "\t -h: print this help\n" +msgstr "" + +#: utils/idle_monitor/cpupower-monitor.c:74 +#, c-format +msgid "\t -i: time intervall to measure for in seconds (default 1)\n" +msgstr "" + +#: utils/idle_monitor/cpupower-monitor.c:75 +#, c-format +msgid "\t -t: show CPU topology/hierarchy\n" +msgstr "" + +#: utils/idle_monitor/cpupower-monitor.c:76 +#, c-format +msgid "\t -l: list available CPU sleep monitors (for use with -m)\n" +msgstr "" + +#: utils/idle_monitor/cpupower-monitor.c:77 +#, c-format +msgid "\t -m: show specific CPU sleep monitors only (in same order)\n" +msgstr "" + +#: utils/idle_monitor/cpupower-monitor.c:79 +#, c-format +msgid "" +"only one of: -t, -l, -m are allowed\n" +"If none of them is passed," +msgstr "" + +#: utils/idle_monitor/cpupower-monitor.c:80 +#, c-format +msgid " all supported monitors are shown\n" +msgstr "" + +#: utils/idle_monitor/cpupower-monitor.c:197 +#, c-format +msgid "Monitor %s, Counter %s has no count function. Implementation error\n" +msgstr "" + +#: utils/idle_monitor/cpupower-monitor.c:207 +#, c-format +msgid " *is offline\n" +msgstr "" + +#: utils/idle_monitor/cpupower-monitor.c:236 +#, c-format +msgid "%s: max monitor name length (%d) exceeded\n" +msgstr "" + +#: utils/idle_monitor/cpupower-monitor.c:250 +#, c-format +msgid "No matching monitor found in %s, try -l option\n" +msgstr "" + +#: utils/idle_monitor/cpupower-monitor.c:266 +#, c-format +msgid "Monitor \"%s\" (%d states) - Might overflow after %u s\n" +msgstr "" + +#: utils/idle_monitor/cpupower-monitor.c:319 +#, c-format +msgid "%s took %.5f seconds and exited with status %d\n" +msgstr "" + +#: utils/idle_monitor/cpupower-monitor.c:406 +#, c-format +msgid "Cannot read number of available processors\n" +msgstr "" + +#: utils/idle_monitor/cpupower-monitor.c:417 +#, c-format +msgid "Available monitor %s needs root access\n" +msgstr "" + +#: utils/idle_monitor/cpupower-monitor.c:428 +#, c-format +msgid "No HW Cstate monitors found\n" +msgstr "" + +#: utils/cpupower.c:78 +#, c-format +msgid "cpupower [ -c cpulist ] subcommand [ARGS]\n" +msgstr "" + +#: utils/cpupower.c:79 +#, c-format +msgid "cpupower --version\n" +msgstr "" + +#: utils/cpupower.c:80 +#, c-format +msgid "Supported subcommands are:\n" +msgstr "" + +#: utils/cpupower.c:83 +#, c-format +msgid "" +"\n" +"Some subcommands can make use of the -c cpulist option.\n" +msgstr "" + +#: utils/cpupower.c:84 +#, c-format +msgid "Look at the general cpupower manpage how to use it\n" +msgstr "" + +#: utils/cpupower.c:85 +#, c-format +msgid "and read up the subcommand's manpage whether it is supported.\n" +msgstr "" + +#: utils/cpupower.c:86 +#, c-format +msgid "" +"\n" +"Use cpupower help subcommand for getting help for above subcommands.\n" +msgstr "" + +#: utils/cpupower.c:91 +#, c-format +msgid "Report errors and bugs to %s, please.\n" +msgstr "" +"Chyby v programu prosÃm hlaste na %s (anglicky).\n" +"Chyby v pÅ™ekladu prosÃm hlaste na kavol@seznam.cz (Äesky ;-)\n" + +#: utils/cpupower.c:114 +#, c-format +msgid "Error parsing cpu list\n" +msgstr "" + +#: utils/cpupower.c:172 +#, c-format +msgid "Subcommand %s needs root privileges\n" +msgstr "" + +#: utils/cpufreq-info.c:31 +#, c-format +msgid "Couldn't count the number of CPUs (%s: %s), assuming 1\n" +msgstr "Nelze zjistit poÄet CPU (%s: %s), pÅ™edpokládá se 1.\n" + +#: utils/cpufreq-info.c:63 +#, c-format +msgid "" +"          minimum CPU frequency  -  maximum CPU frequency  -  governor\n" +msgstr "" +"         minimálnà frekvence CPU - maximálnà frekvence CPU -  regulátor\n" + +#: utils/cpufreq-info.c:151 +#, c-format +msgid "Error while evaluating Boost Capabilities on CPU %d -- are you root?\n" +msgstr "" + +#. P state changes via MSR are identified via cpuid 80000007 +#. on Intel and AMD, but we assume boost capable machines can do that +#. if (cpuid_eax(0x80000000) >= 0x80000007 +#. && (cpuid_edx(0x80000007) & (1 << 7))) +#. +#: utils/cpufreq-info.c:161 +#, c-format +msgid "  boost state support: \n" +msgstr "" + +#: utils/cpufreq-info.c:163 +#, c-format +msgid "    Supported: %s\n" +msgstr "" + +#: utils/cpufreq-info.c:163 utils/cpufreq-info.c:164 +msgid "yes" +msgstr "" + +#: utils/cpufreq-info.c:163 utils/cpufreq-info.c:164 +msgid "no" +msgstr "" + +#: utils/cpufreq-info.c:164 +#, fuzzy, c-format +msgid "    Active: %s\n" +msgstr "  ovladaÄ: %s\n" + +#: utils/cpufreq-info.c:177 +#, c-format +msgid "    Boost States: %d\n" +msgstr "" + +#: utils/cpufreq-info.c:178 +#, c-format +msgid "    Total States: %d\n" +msgstr "" + +#: utils/cpufreq-info.c:181 +#, c-format +msgid "    Pstate-Pb%d: %luMHz (boost state)\n" +msgstr "" + +#: utils/cpufreq-info.c:184 +#, c-format +msgid "    Pstate-P%d:  %luMHz\n" +msgstr "" + +#: utils/cpufreq-info.c:211 +#, c-format +msgid "  no or unknown cpufreq driver is active on this CPU\n" +msgstr "  pro tento CPU nenà aktivnà žádný známý ovladaÄ cpufreq\n" + +#: utils/cpufreq-info.c:213 +#, c-format +msgid "  driver: %s\n" +msgstr "  ovladaÄ: %s\n" + +#: utils/cpufreq-info.c:219 +#, fuzzy, c-format +msgid "  CPUs which run at the same hardware frequency: " +msgstr "  CPU, které musà mÄ›nit frekvenci zároveň: " + +#: utils/cpufreq-info.c:230 +#, fuzzy, c-format +msgid "  CPUs which need to have their frequency coordinated by software: " +msgstr "  CPU, které musà mÄ›nit frekvenci zároveň: " + +#: utils/cpufreq-info.c:241 +#, c-format +msgid "  maximum transition latency: " +msgstr "" + +#: utils/cpufreq-info.c:247 +#, c-format +msgid "  hardware limits: " +msgstr "  hardwarové meze: " + +#: utils/cpufreq-info.c:256 +#, c-format +msgid "  available frequency steps: " +msgstr "  dostupné frekvence: " + +#: utils/cpufreq-info.c:269 +#, c-format +msgid "  available cpufreq governors: " +msgstr "  dostupné regulátory: " + +#: utils/cpufreq-info.c:280 +#, c-format +msgid "  current policy: frequency should be within " +msgstr "  souÄasná taktika: frekvence by mÄ›la být mezi " + +#: utils/cpufreq-info.c:282 +#, c-format +msgid " and " +msgstr " a " + +#: utils/cpufreq-info.c:286 +#, c-format +msgid "" +"The governor \"%s\" may decide which speed to use\n" +"                  within this range.\n" +msgstr "" +"  Regulátor \"%s\" může rozhodnout jakou frekvenci použÃt\n" +"                    v tÄ›chto mezÃch.\n" + +#: utils/cpufreq-info.c:293 +#, c-format +msgid "  current CPU frequency is " +msgstr "  souÄasná frekvence CPU je " + +#: utils/cpufreq-info.c:296 +#, c-format +msgid " (asserted by call to hardware)" +msgstr "  (zjiÅ¡tÄ›no hardwarovým volánÃm)" + +#: utils/cpufreq-info.c:304 +#, c-format +msgid "  cpufreq stats: " +msgstr "  statistika cpufreq: " + +#: utils/cpufreq-info.c:472 +#, fuzzy, c-format +msgid "Usage: cpupower freqinfo [options]\n" +msgstr "UžitÃ: cpufreq-info [pÅ™epÃnaÄe]\n" + +#: utils/cpufreq-info.c:473 utils/cpufreq-set.c:26 utils/cpupower-set.c:23 +#: utils/cpupower-info.c:22 utils/cpuidle-info.c:148 +#, c-format +msgid "Options:\n" +msgstr "PÅ™epÃnaÄe:\n" + +#: utils/cpufreq-info.c:474 +#, fuzzy, c-format +msgid "  -e, --debug          Prints out debug information [default]\n" +msgstr "  -e, --debug          VypÃÅ¡e ladicà informace\n" + +#: utils/cpufreq-info.c:475 +#, c-format +msgid "" +"  -f, --freq           Get frequency the CPU currently runs at, according\n" +"                       to the cpufreq core *\n" +msgstr "" +"  -f, --freq           Zjistà aktuálnà frekvenci, na které CPU běžÃ\n" +"                       podle cpufreq *\n" + +#: utils/cpufreq-info.c:477 +#, c-format +msgid "" +"  -w, --hwfreq         Get frequency the CPU currently runs at, by reading\n" +"                       it from hardware (only available to root) *\n" +msgstr "" +"  -w, --hwfreq         Zjistà aktuálnà frekvenci, na které CPU běžÃ\n" +"                       z hardware (dostupné jen uživateli root) *\n" + +#: utils/cpufreq-info.c:479 +#, c-format +msgid "" +"  -l, --hwlimits       Determine the minimum and maximum CPU frequency " +"allowed *\n" +msgstr "" +"  -l, --hwlimits       Zjistà minimálnà a maximálnà dostupnou frekvenci CPU " +"*\n" + +#: utils/cpufreq-info.c:480 +#, c-format +msgid "  -d, --driver         Determines the used cpufreq kernel driver *\n" +msgstr "  -d, --driver         Zjistà aktivnà ovladaÄ cpufreq *\n" + +#: utils/cpufreq-info.c:481 +#, c-format +msgid "  -p, --policy         Gets the currently used cpufreq policy *\n" +msgstr "  -p, --policy         Zjistà aktuálnà taktiku cpufreq *\n" + +#: utils/cpufreq-info.c:482 +#, c-format +msgid "  -g, --governors      Determines available cpufreq governors *\n" +msgstr "  -g, --governors      Zjistà dostupné regulátory cpufreq *\n" + +#: utils/cpufreq-info.c:483 +#, fuzzy, c-format +msgid "" +"  -r, --related-cpus   Determines which CPUs run at the same hardware " +"frequency *\n" +msgstr "" +"  -a, --affected-cpus  ZjistÃ, které CPU musà mÄ›nit frekvenci zároveň *\n" + +#: utils/cpufreq-info.c:484 +#, fuzzy, c-format +msgid "" +"  -a, --affected-cpus  Determines which CPUs need to have their frequency\n" +"                       coordinated by software *\n" +msgstr "" +"  -a, --affected-cpus  ZjistÃ, které CPU musà mÄ›nit frekvenci zároveň *\n" + +#: utils/cpufreq-info.c:486 +#, c-format +msgid "  -s, --stats          Shows cpufreq statistics if available\n" +msgstr "  -s, --stats          Zobrazà statistiku cpufreq, je-li dostupná\n" + +#: utils/cpufreq-info.c:487 +#, fuzzy, c-format +msgid "" +"  -y, --latency        Determines the maximum latency on CPU frequency " +"changes *\n" +msgstr "" +"  -l, --hwlimits       Zjistà minimálnà a maximálnà dostupnou frekvenci CPU " +"*\n" + +#: utils/cpufreq-info.c:488 +#, c-format +msgid "  -b, --boost          Checks for turbo or boost modes  *\n" +msgstr "" + +#: utils/cpufreq-info.c:489 +#, c-format +msgid "" +"  -o, --proc           Prints out information like provided by the /proc/" +"cpufreq\n" +"                       interface in 2.4. and early 2.6. kernels\n" +msgstr "" +"  -o, --proc           VypÃÅ¡e informace ve formátu, jaký použÃvalo rozhranÃ\n" +"                       /proc/cpufreq v kernelech Å™ady 2.4 a Äasné 2.6\n" + +#: utils/cpufreq-info.c:491 +#, fuzzy, c-format +msgid "" +"  -m, --human          human-readable output for the -f, -w, -s and -y " +"parameters\n" +msgstr "" +"  -m, --human          Výstup parametrů -f, -w a -s v „lidmi Äitelném“ " +"formátu\n" + +#: utils/cpufreq-info.c:492 utils/cpuidle-info.c:152 +#, c-format +msgid "  -h, --help           Prints out this screen\n" +msgstr "  -h, --help           VypÃÅ¡e tuto nápovÄ›du\n" + +#: utils/cpufreq-info.c:495 +#, c-format +msgid "" +"If no argument or only the -c, --cpu parameter is given, debug output about\n" +"cpufreq is printed which is useful e.g. for reporting bugs.\n" +msgstr "" +"NenÃ-li zadán žádný parametr nebo je-li zadán pouze pÅ™epÃnaÄ -c, --cpu, " +"jsou\n" +"vypsány ladicà informace, což může být užiteÄné napÅ™Ãklad pÅ™i hlášenà chyb.\n" + +#: utils/cpufreq-info.c:497 +#, c-format +msgid "" +"For the arguments marked with *, omitting the -c or --cpu argument is\n" +"equivalent to setting it to zero\n" +msgstr "" +"NenÃ-li pÅ™i použità pÅ™epÃnaÄů oznaÄených * zadán parametr -c nebo --cpu,\n" +"pÅ™edpokládá se jeho hodnota 0.\n" + +#: utils/cpufreq-info.c:580 +#, c-format +msgid "" +"The argument passed to this tool can't be combined with passing a --cpu " +"argument\n" +msgstr "Zadaný parametr nemůže být použit zároveň s pÅ™epÃnaÄem -c nebo --cpu\n" + +#: utils/cpufreq-info.c:596 +#, c-format +msgid "" +"You can't specify more than one --cpu parameter and/or\n" +"more than one output-specific argument\n" +msgstr "" +"Nelze zadat vÃce než jeden parametr -c nebo --cpu\n" +"anebo vÃce než jeden parametr urÄujÃcà výstup\n" + +#: utils/cpufreq-info.c:600 utils/cpufreq-set.c:82 utils/cpupower-set.c:42 +#: utils/cpupower-info.c:42 utils/cpuidle-info.c:213 +#, c-format +msgid "invalid or unknown argument\n" +msgstr "neplatný nebo neznámý parametr\n" + +#: utils/cpufreq-info.c:617 +#, c-format +msgid "couldn't analyze CPU %d as it doesn't seem to be present\n" +msgstr "nelze analyzovat CPU %d, vypadá to, že nenà pÅ™Ãtomen\n" + +#: utils/cpufreq-info.c:620 utils/cpupower-info.c:142 +#, c-format +msgid "analyzing CPU %d:\n" +msgstr "analyzuji CPU %d:\n" + +#: utils/cpufreq-set.c:25 +#, fuzzy, c-format +msgid "Usage: cpupower frequency-set [options]\n" +msgstr "UžitÃ: cpufreq-set [pÅ™epÃnaÄe]\n" + +#: utils/cpufreq-set.c:27 +#, c-format +msgid "" +"  -d FREQ, --min FREQ      new minimum CPU frequency the governor may " +"select\n" +msgstr "" +"  -d FREQ, --min FREQ      Nová nejnižšà frekvence, kterou může regulátor " +"vybrat\n" + +#: utils/cpufreq-set.c:28 +#, c-format +msgid "" +"  -u FREQ, --max FREQ      new maximum CPU frequency the governor may " +"select\n" +msgstr "" +"  -u FREQ, --max FREQ      Nová nejvyššà frekvence, kterou může regulátor " +"zvolit\n" + +#: utils/cpufreq-set.c:29 +#, c-format +msgid "  -g GOV, --governor GOV   new cpufreq governor\n" +msgstr "  -g GOV, --governors GOV  Nový regulátor cpufreq\n" + +#: utils/cpufreq-set.c:30 +#, c-format +msgid "" +"  -f FREQ, --freq FREQ     specific frequency to be set. Requires userspace\n" +"                           governor to be available and loaded\n" +msgstr "" +"  -f FREQ, --freq FREQ     Frekvence, která má být nastavena. Vyžaduje, aby " +"byl\n" +"                           v jádÅ™e nahrán regulátor ‚userspace‘.\n" + +#: utils/cpufreq-set.c:32 +#, c-format +msgid "  -r, --related            Switches all hardware-related CPUs\n" +msgstr "" + +#: utils/cpufreq-set.c:33 utils/cpupower-set.c:28 utils/cpupower-info.c:27 +#, fuzzy, c-format +msgid "  -h, --help               Prints out this screen\n" +msgstr "  -h, --help           VypÃÅ¡e tuto nápovÄ›du\n" + +#: utils/cpufreq-set.c:35 +#, fuzzy, c-format +msgid "" +"Notes:\n" +"1. Omitting the -c or --cpu argument is equivalent to setting it to \"all\"\n" +msgstr "" +"NenÃ-li pÅ™i použità pÅ™epÃnaÄů oznaÄených * zadán parametr -c nebo --cpu,\n" +"pÅ™edpokládá se jeho hodnota 0.\n" + +#: utils/cpufreq-set.c:37 +#, fuzzy, c-format +msgid "" +"2. The -f FREQ, --freq FREQ parameter cannot be combined with any other " +"parameter\n" +"   except the -c CPU, --cpu CPU parameter\n" +"3. FREQuencies can be passed in Hz, kHz (default), MHz, GHz, or THz\n" +"   by postfixing the value with the wanted unit name, without any space\n" +"   (FREQuency in kHz =^ Hz * 0.001 =^ MHz * 1000 =^ GHz * 1000000).\n" +msgstr "" +"Poznámky:\n" +"1. Vynechánà parametru -c nebo --cpu je ekvivalentnà jeho nastavenà na 0\n" +"2. PÅ™epÃnaÄ -f nebo --freq nemůže být použit zároveň s žádným jiným vyjma -" +"c\n" +"   nebo --cpu\n" +"3. Frekvence (FREQ) mohou být zadány v Hz, kHz (výchozÃ), MHz, GHz nebo THz\n" +"   pÅ™ipojenÃm názvu jednotky bez mezery mezi ÄÃslem a jednotkou\n" +"   (FREQ v kHz =^ Hz * 0,001 = ^ MHz * 1000 =^ GHz * 1000000)\n" + +#: utils/cpufreq-set.c:57 +#, c-format +msgid "" +"Error setting new values. Common errors:\n" +"- Do you have proper administration rights? (super-user?)\n" +"- Is the governor you requested available and modprobed?\n" +"- Trying to set an invalid policy?\n" +"- Trying to set a specific frequency, but userspace governor is not " +"available,\n" +"   for example because of hardware which cannot be set to a specific " +"frequency\n" +"   or because the userspace governor isn't loaded?\n" +msgstr "" +"Chyba pÅ™i nastavovánà nových hodnot. Obvyklé problémy:\n" +"- Máte patÅ™iÄná administrátorská práva? (root?)\n" +"- Je požadovaný regulátor dostupný v jádÅ™e? (modprobe?)\n" +"- SnažÃte se nastavit neplatnou taktiku?\n" +"- SnažÃte se nastavit urÄitou frekvenci, ale nenà dostupný\n" +"  regulátor ‚userspace‘, napÅ™Ãklad protože nenà nahrán v jádÅ™e,\n" +"  nebo nelze na tomto hardware nastavit urÄitou frekvenci?\n" + +#: utils/cpufreq-set.c:170 +#, c-format +msgid "wrong, unknown or unhandled CPU?\n" +msgstr "neznámý nebo nepodporovaný CPU?\n" + +#: utils/cpufreq-set.c:302 +#, c-format +msgid "" +"the -f/--freq parameter cannot be combined with -d/--min, -u/--max or\n" +"-g/--governor parameters\n" +msgstr "" +"pÅ™epÃnaÄ -f/--freq nemůže být použit zároveň\n" +"s pÅ™epÃnaÄem -d/--min, -u/--max nebo -g/--governor\n" + +#: utils/cpufreq-set.c:308 +#, c-format +msgid "" +"At least one parameter out of -f/--freq, -d/--min, -u/--max, and\n" +"-g/--governor must be passed\n" +msgstr "" +"Musà být zadán alespoň jeden pÅ™epÃnaÄ\n" +"-f/--freq, -d/--min, -u/--max nebo -g/--governor\n" + +#: utils/cpufreq-set.c:347 +#, c-format +msgid "Setting cpu: %d\n" +msgstr "" + +#: utils/cpupower-set.c:22 +#, c-format +msgid "Usage: cpupower set [ -b val ] [ -m val ] [ -s val ]\n" +msgstr "" + +#: utils/cpupower-set.c:24 +#, c-format +msgid "" +"  -b, --perf-bias [VAL]    Sets CPU's power vs performance policy on some\n" +"                           Intel models [0-15], see manpage for details\n" +msgstr "" + +#: utils/cpupower-set.c:26 +#, c-format +msgid "" +"  -m, --sched-mc  [VAL]    Sets the kernel's multi core scheduler policy.\n" +msgstr "" + +#: utils/cpupower-set.c:27 +#, c-format +msgid "" +"  -s, --sched-smt [VAL]    Sets the kernel's thread sibling scheduler " +"policy.\n" +msgstr "" + +#: utils/cpupower-set.c:80 +#, c-format +msgid "--perf-bias param out of range [0-%d]\n" +msgstr "" + +#: utils/cpupower-set.c:91 +#, c-format +msgid "--sched-mc param out of range [0-%d]\n" +msgstr "" + +#: utils/cpupower-set.c:102 +#, c-format +msgid "--sched-smt param out of range [0-%d]\n" +msgstr "" + +#: utils/cpupower-set.c:121 +#, c-format +msgid "Error setting sched-mc %s\n" +msgstr "" + +#: utils/cpupower-set.c:127 +#, c-format +msgid "Error setting sched-smt %s\n" +msgstr "" + +#: utils/cpupower-set.c:146 +#, c-format +msgid "Error setting perf-bias value on CPU %d\n" +msgstr "" + +#: utils/cpupower-info.c:21 +#, c-format +msgid "Usage: cpupower info [ -b ] [ -m ] [ -s ]\n" +msgstr "" + +#: utils/cpupower-info.c:23 +#, c-format +msgid "" +"  -b, --perf-bias    Gets CPU's power vs performance policy on some\n" +"                           Intel models [0-15], see manpage for details\n" +msgstr "" + +#: utils/cpupower-info.c:25 +#, fuzzy, c-format +msgid "  -m, --sched-mc     Gets the kernel's multi core scheduler policy.\n" +msgstr "  -p, --policy         Zjistà aktuálnà taktiku cpufreq *\n" + +#: utils/cpupower-info.c:26 +#, c-format +msgid "" +"  -s, --sched-smt    Gets the kernel's thread sibling scheduler policy.\n" +msgstr "" + +#: utils/cpupower-info.c:28 +#, c-format +msgid "" +"\n" +"Passing no option will show all info, by default only on core 0\n" +msgstr "" + +#: utils/cpupower-info.c:102 +#, c-format +msgid "System's multi core scheduler setting: " +msgstr "" + +#. if sysfs file is missing it's: errno == ENOENT +#: utils/cpupower-info.c:105 utils/cpupower-info.c:114 +#, c-format +msgid "not supported\n" +msgstr "" + +#: utils/cpupower-info.c:111 +#, c-format +msgid "System's thread sibling scheduler setting: " +msgstr "" + +#: utils/cpupower-info.c:126 +#, c-format +msgid "Intel's performance bias setting needs root privileges\n" +msgstr "" + +#: utils/cpupower-info.c:128 +#, c-format +msgid "System does not support Intel's performance bias setting\n" +msgstr "" + +#: utils/cpupower-info.c:147 +#, c-format +msgid "Could not read perf-bias value\n" +msgstr "" + +#: utils/cpupower-info.c:150 +#, c-format +msgid "perf-bias: %d\n" +msgstr "" + +#: utils/cpuidle-info.c:28 +#, fuzzy, c-format +msgid "Analyzing CPU %d:\n" +msgstr "analyzuji CPU %d:\n" + +#: utils/cpuidle-info.c:32 +#, c-format +msgid "CPU %u: No idle states\n" +msgstr "" + +#: utils/cpuidle-info.c:36 +#, c-format +msgid "CPU %u: Can't read idle state info\n" +msgstr "" + +#: utils/cpuidle-info.c:41 +#, c-format +msgid "Could not determine max idle state %u\n" +msgstr "" + +#: utils/cpuidle-info.c:46 +#, c-format +msgid "Number of idle states: %d\n" +msgstr "" + +#: utils/cpuidle-info.c:48 +#, fuzzy, c-format +msgid "Available idle states:" +msgstr "  dostupné frekvence: " + +#: utils/cpuidle-info.c:71 +#, c-format +msgid "Flags/Description: %s\n" +msgstr "" + +#: utils/cpuidle-info.c:74 +#, c-format +msgid "Latency: %lu\n" +msgstr "" + +#: utils/cpuidle-info.c:76 +#, c-format +msgid "Usage: %lu\n" +msgstr "" + +#: utils/cpuidle-info.c:78 +#, c-format +msgid "Duration: %llu\n" +msgstr "" + +#: utils/cpuidle-info.c:90 +#, c-format +msgid "Could not determine cpuidle driver\n" +msgstr "" + +#: utils/cpuidle-info.c:94 +#, fuzzy, c-format +msgid "CPUidle driver: %s\n" +msgstr "  ovladaÄ: %s\n" + +#: utils/cpuidle-info.c:99 +#, c-format +msgid "Could not determine cpuidle governor\n" +msgstr "" + +#: utils/cpuidle-info.c:103 +#, c-format +msgid "CPUidle governor: %s\n" +msgstr "" + +#: utils/cpuidle-info.c:122 +#, c-format +msgid "CPU %u: Can't read C-state info\n" +msgstr "" + +#. printf("Cstates: %d\n", cstates); +#: utils/cpuidle-info.c:127 +#, c-format +msgid "active state:            C0\n" +msgstr "" + +#: utils/cpuidle-info.c:128 +#, c-format +msgid "max_cstate:              C%u\n" +msgstr "" + +#: utils/cpuidle-info.c:129 +#, c-format +msgid "maximum allowed latency: %lu usec\n" +msgstr "" + +#: utils/cpuidle-info.c:130 +#, c-format +msgid "states:\t\n" +msgstr "" + +#: utils/cpuidle-info.c:132 +#, c-format +msgid "    C%d:                  type[C%d] " +msgstr "" + +#: utils/cpuidle-info.c:134 +#, c-format +msgid "promotion[--] demotion[--] " +msgstr "" + +#: utils/cpuidle-info.c:135 +#, c-format +msgid "latency[%03lu] " +msgstr "" + +#: utils/cpuidle-info.c:137 +#, c-format +msgid "usage[%08lu] " +msgstr "" + +#: utils/cpuidle-info.c:139 +#, c-format +msgid "duration[%020Lu] \n" +msgstr "" + +#: utils/cpuidle-info.c:147 +#, fuzzy, c-format +msgid "Usage: cpupower idleinfo [options]\n" +msgstr "UžitÃ: cpufreq-info [pÅ™epÃnaÄe]\n" + +#: utils/cpuidle-info.c:149 +#, fuzzy, c-format +msgid "  -s, --silent         Only show general C-state information\n" +msgstr "  -e, --debug          VypÃÅ¡e ladicà informace\n" + +#: utils/cpuidle-info.c:150 +#, fuzzy, c-format +msgid "" +"  -o, --proc           Prints out information like provided by the /proc/" +"acpi/processor/*/power\n" +"                       interface in older kernels\n" +msgstr "" +"  -o, --proc           VypÃÅ¡e informace ve formátu, jaký použÃvalo rozhranÃ\n" +"                       /proc/cpufreq v kernelech Å™ady 2.4 a Äasné 2.6\n" + +#: utils/cpuidle-info.c:209 +#, fuzzy, c-format +msgid "You can't specify more than one output-specific argument\n" +msgstr "" +"Nelze zadat vÃce než jeden parametr -c nebo --cpu\n" +"anebo vÃce než jeden parametr urÄujÃcà výstup\n" + +#~ msgid "" +#~ "  -c CPU, --cpu CPU    CPU number which information shall be determined " +#~ "about\n" +#~ msgstr "" +#~ "  -c CPU, --cpu CPU    ÄŒÃslo CPU, o kterém se majà zjistit informace\n" + +#~ msgid "" +#~ "  -c CPU, --cpu CPU        number of CPU where cpufreq settings shall be " +#~ "modified\n" +#~ msgstr "" +#~ "  -c CPU, --cpu CPU        ÄŒÃslo CPU pro který se má provést nastavenà " +#~ "cpufreq\n" diff --git a/tools/power/cpupower/po/de.po b/tools/power/cpupower/po/de.po new file mode 100644 index 00000000000..78c09e51663 --- /dev/null +++ b/tools/power/cpupower/po/de.po @@ -0,0 +1,961 @@ +# German translations for cpufrequtils package +# German messages for cpufrequtils. +# Copyright (C) 2004-2009 Dominik Brodowski <linux@dominikbrodowski.net> +# This file is distributed under the same license as the cpufrequtils package. +# +msgid "" +msgstr "" +"Project-Id-Version: cpufrequtils 006\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2011-03-08 17:03+0100\n" +"PO-Revision-Date: 2009-08-08 17:18+0100\n" +"Last-Translator:  <linux@dominikbrodowski.net>\n" +"Language-Team: NONE\n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=ISO-8859-1\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#: utils/idle_monitor/nhm_idle.c:36 +msgid "Processor Core C3" +msgstr "" + +#: utils/idle_monitor/nhm_idle.c:43 +msgid "Processor Core C6" +msgstr "" + +#: utils/idle_monitor/nhm_idle.c:51 +msgid "Processor Package C3" +msgstr "" + +#: utils/idle_monitor/nhm_idle.c:58 utils/idle_monitor/amd_fam14h_idle.c:70 +msgid "Processor Package C6" +msgstr "" + +#: utils/idle_monitor/snb_idle.c:33 +msgid "Processor Core C7" +msgstr "" + +#: utils/idle_monitor/snb_idle.c:40 +msgid "Processor Package C2" +msgstr "" + +#: utils/idle_monitor/snb_idle.c:47 +msgid "Processor Package C7" +msgstr "" + +#: utils/idle_monitor/amd_fam14h_idle.c:56 +msgid "Package in sleep state (PC1 or deeper)" +msgstr "" + +#: utils/idle_monitor/amd_fam14h_idle.c:63 +msgid "Processor Package C1" +msgstr "" + +#: utils/idle_monitor/amd_fam14h_idle.c:77 +msgid "North Bridge P1 boolean counter (returns 0 or 1)" +msgstr "" + +#: utils/idle_monitor/mperf_monitor.c:35 +msgid "Processor Core not idle" +msgstr "" + +#: utils/idle_monitor/mperf_monitor.c:42 +msgid "Processor Core in an idle state" +msgstr "" + +#: utils/idle_monitor/mperf_monitor.c:50 +msgid "Average Frequency (including boost) in MHz" +msgstr "" + +#: utils/idle_monitor/cpupower-monitor.c:66 +#, c-format +msgid "" +"cpupower monitor: [-h] [ [-t] | [-l] | [-m <mon1>,[<mon2>] ] ] [-i " +"interval_sec | -c command ...]\n" +msgstr "" + +#: utils/idle_monitor/cpupower-monitor.c:69 +#, c-format +msgid "" +"cpupower monitor: [-v] [-h] [ [-t] | [-l] | [-m <mon1>,[<mon2>] ] ] [-i " +"interval_sec | -c command ...]\n" +msgstr "" + +#: utils/idle_monitor/cpupower-monitor.c:71 +#, c-format +msgid "\t -v: be more verbose\n" +msgstr "" + +#: utils/idle_monitor/cpupower-monitor.c:73 +#, c-format +msgid "\t -h: print this help\n" +msgstr "" + +#: utils/idle_monitor/cpupower-monitor.c:74 +#, c-format +msgid "\t -i: time intervall to measure for in seconds (default 1)\n" +msgstr "" + +#: utils/idle_monitor/cpupower-monitor.c:75 +#, c-format +msgid "\t -t: show CPU topology/hierarchy\n" +msgstr "" + +#: utils/idle_monitor/cpupower-monitor.c:76 +#, c-format +msgid "\t -l: list available CPU sleep monitors (for use with -m)\n" +msgstr "" + +#: utils/idle_monitor/cpupower-monitor.c:77 +#, c-format +msgid "\t -m: show specific CPU sleep monitors only (in same order)\n" +msgstr "" + +#: utils/idle_monitor/cpupower-monitor.c:79 +#, c-format +msgid "" +"only one of: -t, -l, -m are allowed\n" +"If none of them is passed," +msgstr "" + +#: utils/idle_monitor/cpupower-monitor.c:80 +#, c-format +msgid " all supported monitors are shown\n" +msgstr "" + +#: utils/idle_monitor/cpupower-monitor.c:197 +#, c-format +msgid "Monitor %s, Counter %s has no count function. Implementation error\n" +msgstr "" + +#: utils/idle_monitor/cpupower-monitor.c:207 +#, c-format +msgid " *is offline\n" +msgstr "" + +#: utils/idle_monitor/cpupower-monitor.c:236 +#, c-format +msgid "%s: max monitor name length (%d) exceeded\n" +msgstr "" + +#: utils/idle_monitor/cpupower-monitor.c:250 +#, c-format +msgid "No matching monitor found in %s, try -l option\n" +msgstr "" + +#: utils/idle_monitor/cpupower-monitor.c:266 +#, c-format +msgid "Monitor \"%s\" (%d states) - Might overflow after %u s\n" +msgstr "" + +#: utils/idle_monitor/cpupower-monitor.c:319 +#, c-format +msgid "%s took %.5f seconds and exited with status %d\n" +msgstr "" + +#: utils/idle_monitor/cpupower-monitor.c:406 +#, c-format +msgid "Cannot read number of available processors\n" +msgstr "" + +#: utils/idle_monitor/cpupower-monitor.c:417 +#, c-format +msgid "Available monitor %s needs root access\n" +msgstr "" + +#: utils/idle_monitor/cpupower-monitor.c:428 +#, c-format +msgid "No HW Cstate monitors found\n" +msgstr "" + +#: utils/cpupower.c:78 +#, c-format +msgid "cpupower [ -c cpulist ] subcommand [ARGS]\n" +msgstr "" + +#: utils/cpupower.c:79 +#, c-format +msgid "cpupower --version\n" +msgstr "" + +#: utils/cpupower.c:80 +#, c-format +msgid "Supported subcommands are:\n" +msgstr "" + +#: utils/cpupower.c:83 +#, c-format +msgid "" +"\n" +"Some subcommands can make use of the -c cpulist option.\n" +msgstr "" + +#: utils/cpupower.c:84 +#, c-format +msgid "Look at the general cpupower manpage how to use it\n" +msgstr "" + +#: utils/cpupower.c:85 +#, c-format +msgid "and read up the subcommand's manpage whether it is supported.\n" +msgstr "" + +#: utils/cpupower.c:86 +#, c-format +msgid "" +"\n" +"Use cpupower help subcommand for getting help for above subcommands.\n" +msgstr "" + +#: utils/cpupower.c:91 +#, c-format +msgid "Report errors and bugs to %s, please.\n" +msgstr "Bitte melden Sie Fehler an %s.\n" + +#: utils/cpupower.c:114 +#, c-format +msgid "Error parsing cpu list\n" +msgstr "" + +#: utils/cpupower.c:172 +#, c-format +msgid "Subcommand %s needs root privileges\n" +msgstr "" + +#: utils/cpufreq-info.c:31 +#, c-format +msgid "Couldn't count the number of CPUs (%s: %s), assuming 1\n" +msgstr "" +"Konnte nicht die Anzahl der CPUs herausfinden (%s : %s), nehme daher 1 an.\n" + +#: utils/cpufreq-info.c:63 +#, c-format +msgid "" +"          minimum CPU frequency  -  maximum CPU frequency  -  governor\n" +msgstr "" +"          minimale CPU-Taktfreq. -  maximale CPU-Taktfreq. -  Regler  \n" + +#: utils/cpufreq-info.c:151 +#, c-format +msgid "Error while evaluating Boost Capabilities on CPU %d -- are you root?\n" +msgstr "" + +#. P state changes via MSR are identified via cpuid 80000007 +#. on Intel and AMD, but we assume boost capable machines can do that +#. if (cpuid_eax(0x80000000) >= 0x80000007 +#. && (cpuid_edx(0x80000007) & (1 << 7))) +#. +#: utils/cpufreq-info.c:161 +#, c-format +msgid "  boost state support: \n" +msgstr "" + +#: utils/cpufreq-info.c:163 +#, c-format +msgid "    Supported: %s\n" +msgstr "" + +#: utils/cpufreq-info.c:163 utils/cpufreq-info.c:164 +msgid "yes" +msgstr "" + +#: utils/cpufreq-info.c:163 utils/cpufreq-info.c:164 +msgid "no" +msgstr "" + +#: utils/cpufreq-info.c:164 +#, fuzzy, c-format +msgid "    Active: %s\n" +msgstr "  Treiber: %s\n" + +#: utils/cpufreq-info.c:177 +#, c-format +msgid "    Boost States: %d\n" +msgstr "" + +#: utils/cpufreq-info.c:178 +#, c-format +msgid "    Total States: %d\n" +msgstr "" + +#: utils/cpufreq-info.c:181 +#, c-format +msgid "    Pstate-Pb%d: %luMHz (boost state)\n" +msgstr "" + +#: utils/cpufreq-info.c:184 +#, c-format +msgid "    Pstate-P%d:  %luMHz\n" +msgstr "" + +#: utils/cpufreq-info.c:211 +#, c-format +msgid "  no or unknown cpufreq driver is active on this CPU\n" +msgstr "  kein oder nicht bestimmbarer cpufreq-Treiber aktiv\n" + +#: utils/cpufreq-info.c:213 +#, c-format +msgid "  driver: %s\n" +msgstr "  Treiber: %s\n" + +#: utils/cpufreq-info.c:219 +#, c-format +msgid "  CPUs which run at the same hardware frequency: " +msgstr "  Folgende CPUs laufen mit der gleichen Hardware-Taktfrequenz: " + +#: utils/cpufreq-info.c:230 +#, c-format +msgid "  CPUs which need to have their frequency coordinated by software: " +msgstr "  Die Taktfrequenz folgender CPUs werden per Software koordiniert: " + +#: utils/cpufreq-info.c:241 +#, c-format +msgid "  maximum transition latency: " +msgstr "  Maximale Dauer eines Taktfrequenzwechsels: " + +#: utils/cpufreq-info.c:247 +#, c-format +msgid "  hardware limits: " +msgstr "  Hardwarebedingte Grenzen der Taktfrequenz: " + +#: utils/cpufreq-info.c:256 +#, c-format +msgid "  available frequency steps: " +msgstr "  mögliche Taktfrequenzen: " + +#: utils/cpufreq-info.c:269 +#, c-format +msgid "  available cpufreq governors: " +msgstr "  mögliche Regler: " + +#: utils/cpufreq-info.c:280 +#, c-format +msgid "  current policy: frequency should be within " +msgstr "  momentane Taktik: die Frequenz soll innerhalb " + +#: utils/cpufreq-info.c:282 +#, c-format +msgid " and " +msgstr " und " + +#: utils/cpufreq-info.c:286 +#, c-format +msgid "" +"The governor \"%s\" may decide which speed to use\n" +"                  within this range.\n" +msgstr "" +"  liegen. Der Regler \"%s\" kann frei entscheiden,\n" +"                    welche Taktfrequenz innerhalb dieser Grenze verwendet " +"wird.\n" + +#: utils/cpufreq-info.c:293 +#, c-format +msgid "  current CPU frequency is " +msgstr "  momentane Taktfrequenz ist " + +#: utils/cpufreq-info.c:296 +#, c-format +msgid " (asserted by call to hardware)" +msgstr "  (verifiziert durch Nachfrage bei der Hardware)" + +#: utils/cpufreq-info.c:304 +#, c-format +msgid "  cpufreq stats: " +msgstr "  Statistik:" + +#: utils/cpufreq-info.c:472 +#, fuzzy, c-format +msgid "Usage: cpupower freqinfo [options]\n" +msgstr "Aufruf: cpufreq-info [Optionen]\n" + +#: utils/cpufreq-info.c:473 utils/cpufreq-set.c:26 utils/cpupower-set.c:23 +#: utils/cpupower-info.c:22 utils/cpuidle-info.c:148 +#, c-format +msgid "Options:\n" +msgstr "Optionen:\n" + +#: utils/cpufreq-info.c:474 +#, fuzzy, c-format +msgid "  -e, --debug          Prints out debug information [default]\n" +msgstr "" +"  -e, --debug          Erzeugt detaillierte Informationen, hilfreich\n" +"                       zum Aufspüren von Fehlern\n" + +#: utils/cpufreq-info.c:475 +#, c-format +msgid "" +"  -f, --freq           Get frequency the CPU currently runs at, according\n" +"                       to the cpufreq core *\n" +msgstr "" +"  -f, --freq           Findet die momentane CPU-Taktfrquenz heraus (nach\n" +"                       Meinung des Betriebssystems) *\n" + +#: utils/cpufreq-info.c:477 +#, c-format +msgid "" +"  -w, --hwfreq         Get frequency the CPU currently runs at, by reading\n" +"                       it from hardware (only available to root) *\n" +msgstr "" +"  -w, --hwfreq         Findet die momentane CPU-Taktfrequenz heraus\n" +"                       (verifiziert durch Nachfrage bei der Hardware)\n" +"                       [nur der Administrator kann dies tun] *\n" + +#: utils/cpufreq-info.c:479 +#, c-format +msgid "" +"  -l, --hwlimits       Determine the minimum and maximum CPU frequency " +"allowed *\n" +msgstr "" +"  -l, --hwlimits       Findet die minimale und maximale Taktfrequenz heraus " +"*\n" + +#: utils/cpufreq-info.c:480 +#, c-format +msgid "  -d, --driver         Determines the used cpufreq kernel driver *\n" +msgstr "  -d, --driver         Findet den momentanen Treiber heraus *\n" + +#: utils/cpufreq-info.c:481 +#, c-format +msgid "  -p, --policy         Gets the currently used cpufreq policy *\n" +msgstr "  -p, --policy         Findet die momentane Taktik heraus *\n" + +#: utils/cpufreq-info.c:482 +#, c-format +msgid "  -g, --governors      Determines available cpufreq governors *\n" +msgstr "  -g, --governors      Erzeugt eine Liste mit verfügbaren Reglern *\n" + +#: utils/cpufreq-info.c:483 +#, c-format +msgid "" +"  -r, --related-cpus   Determines which CPUs run at the same hardware " +"frequency *\n" +msgstr "" +"  -r, --related-cpus   Findet heraus, welche CPUs mit derselben " +"physikalischen\n" +"                       Taktfrequenz laufen *\n" + +#: utils/cpufreq-info.c:484 +#, c-format +msgid "" +"  -a, --affected-cpus  Determines which CPUs need to have their frequency\n" +"                       coordinated by software *\n" +msgstr "" +"  -a, --affected-cpus  Findet heraus, von welchen CPUs die Taktfrequenz " +"durch\n" +"                       Software koordiniert werden muss *\n" + +#: utils/cpufreq-info.c:486 +#, c-format +msgid "  -s, --stats          Shows cpufreq statistics if available\n" +msgstr "" +"  -s, --stats          Zeigt, sofern möglich, Statistiken über cpufreq an.\n" + +#: utils/cpufreq-info.c:487 +#, c-format +msgid "" +"  -y, --latency        Determines the maximum latency on CPU frequency " +"changes *\n" +msgstr "" +"  -y, --latency        Findet die maximale Dauer eines Taktfrequenzwechsels " +"heraus *\n" + +#: utils/cpufreq-info.c:488 +#, c-format +msgid "  -b, --boost          Checks for turbo or boost modes  *\n" +msgstr "" + +#: utils/cpufreq-info.c:489 +#, c-format +msgid "" +"  -o, --proc           Prints out information like provided by the /proc/" +"cpufreq\n" +"                       interface in 2.4. and early 2.6. kernels\n" +msgstr "" +"  -o, --proc           Erzeugt Informationen in einem ähnlichem Format zu " +"dem\n" +"                       der /proc/cpufreq-Datei in 2.4. und frühen 2.6.\n" +"                       Kernel-Versionen\n" + +#: utils/cpufreq-info.c:491 +#, c-format +msgid "" +"  -m, --human          human-readable output for the -f, -w, -s and -y " +"parameters\n" +msgstr "" +"  -m, --human          Formatiert Taktfrequenz- und Zeitdauerangaben in " +"besser\n" +"                       lesbarer Form (MHz, GHz; us, ms)\n" + +#: utils/cpufreq-info.c:492 utils/cpuidle-info.c:152 +#, c-format +msgid "  -h, --help           Prints out this screen\n" +msgstr "  -h, --help           Gibt diese Kurzübersicht aus\n" + +#: utils/cpufreq-info.c:495 +#, c-format +msgid "" +"If no argument or only the -c, --cpu parameter is given, debug output about\n" +"cpufreq is printed which is useful e.g. for reporting bugs.\n" +msgstr "" +"Sofern kein anderer Parameter als '-c, --cpu' angegeben wird, liefert " +"dieses\n" +"Programm Informationen, die z.B. zum Berichten von Fehlern nützlich sind.\n" + +#: utils/cpufreq-info.c:497 +#, c-format +msgid "" +"For the arguments marked with *, omitting the -c or --cpu argument is\n" +"equivalent to setting it to zero\n" +msgstr "" +"Bei den mit * markierten Parametern wird '--cpu 0' angenommen, soweit nicht\n" +"mittels -c oder --cpu etwas anderes angegeben wird\n" + +#: utils/cpufreq-info.c:580 +#, c-format +msgid "" +"The argument passed to this tool can't be combined with passing a --cpu " +"argument\n" +msgstr "Diese Option kann nicht mit der --cpu-Option kombiniert werden\n" + +#: utils/cpufreq-info.c:596 +#, c-format +msgid "" +"You can't specify more than one --cpu parameter and/or\n" +"more than one output-specific argument\n" +msgstr "" +"Man kann nicht mehr als einen --cpu-Parameter und/oder mehr als einen\n" +"informationsspezifischen Parameter gleichzeitig angeben\n" + +#: utils/cpufreq-info.c:600 utils/cpufreq-set.c:82 utils/cpupower-set.c:42 +#: utils/cpupower-info.c:42 utils/cpuidle-info.c:213 +#, c-format +msgid "invalid or unknown argument\n" +msgstr "unbekannter oder falscher Parameter\n" + +#: utils/cpufreq-info.c:617 +#, c-format +msgid "couldn't analyze CPU %d as it doesn't seem to be present\n" +msgstr "" +"Konnte nicht die CPU %d analysieren, da sie (scheinbar?) nicht existiert.\n" + +#: utils/cpufreq-info.c:620 utils/cpupower-info.c:142 +#, c-format +msgid "analyzing CPU %d:\n" +msgstr "analysiere CPU %d:\n" + +#: utils/cpufreq-set.c:25 +#, fuzzy, c-format +msgid "Usage: cpupower frequency-set [options]\n" +msgstr "Aufruf: cpufreq-set [Optionen]\n" + +#: utils/cpufreq-set.c:27 +#, c-format +msgid "" +"  -d FREQ, --min FREQ      new minimum CPU frequency the governor may " +"select\n" +msgstr "" +"  -d FREQ, --min FREQ      neue minimale Taktfrequenz, die der Regler\n" +"                           auswählen darf\n" + +#: utils/cpufreq-set.c:28 +#, c-format +msgid "" +"  -u FREQ, --max FREQ      new maximum CPU frequency the governor may " +"select\n" +msgstr "" +"  -u FREQ, --max FREQ      neue maximale Taktfrequenz, die der Regler\n" +"                           auswählen darf\n" + +#: utils/cpufreq-set.c:29 +#, c-format +msgid "  -g GOV, --governor GOV   new cpufreq governor\n" +msgstr "  -g GOV, --governors GOV  wechsle zu Regler GOV\n" + +#: utils/cpufreq-set.c:30 +#, c-format +msgid "" +"  -f FREQ, --freq FREQ     specific frequency to be set. Requires userspace\n" +"                           governor to be available and loaded\n" +msgstr "" +"  -f FREQ, --freq FREQ     setze exakte Taktfrequenz. Benötigt den Regler\n" +"                           'userspace'.\n" + +#: utils/cpufreq-set.c:32 +#, c-format +msgid "  -r, --related            Switches all hardware-related CPUs\n" +msgstr "" +"  -r, --related            Setze Werte für alle CPUs, deren Taktfrequenz\n" +"                           hardwarebedingt identisch ist.\n" + +#: utils/cpufreq-set.c:33 utils/cpupower-set.c:28 utils/cpupower-info.c:27 +#, c-format +msgid "  -h, --help               Prints out this screen\n" +msgstr "  -h, --help               Gibt diese Kurzübersicht aus\n" + +#: utils/cpufreq-set.c:35 +#, fuzzy, c-format +msgid "" +"Notes:\n" +"1. Omitting the -c or --cpu argument is equivalent to setting it to \"all\"\n" +msgstr "" +"Bei den mit * markierten Parametern wird '--cpu 0' angenommen, soweit nicht\n" +"mittels -c oder --cpu etwas anderes angegeben wird\n" + +#: utils/cpufreq-set.c:37 +#, fuzzy, c-format +msgid "" +"2. The -f FREQ, --freq FREQ parameter cannot be combined with any other " +"parameter\n" +"   except the -c CPU, --cpu CPU parameter\n" +"3. FREQuencies can be passed in Hz, kHz (default), MHz, GHz, or THz\n" +"   by postfixing the value with the wanted unit name, without any space\n" +"   (FREQuency in kHz =^ Hz * 0.001 =^ MHz * 1000 =^ GHz * 1000000).\n" +msgstr "" +"Hinweise:\n" +"1. Sofern kein -c oder --cpu-Parameter angegeben ist, wird '--cpu 0'\n" +"   angenommen\n" +"2. Der Parameter -f bzw. --freq kann mit keinem anderen als dem Parameter\n" +"   -c bzw. --cpu kombiniert werden\n" +"3. FREQuenzen können in Hz, kHz (Standard), MHz, GHz oder THz eingegeben\n" +"   werden, indem der Wert und unmittelbar anschließend (ohne Leerzeichen!)\n" +"   die Einheit angegeben werden. (Bsp: 1GHz )\n" +"   (FREQuenz in kHz =^ MHz * 1000 =^ GHz * 1000000).\n" + +#: utils/cpufreq-set.c:57 +#, c-format +msgid "" +"Error setting new values. Common errors:\n" +"- Do you have proper administration rights? (super-user?)\n" +"- Is the governor you requested available and modprobed?\n" +"- Trying to set an invalid policy?\n" +"- Trying to set a specific frequency, but userspace governor is not " +"available,\n" +"   for example because of hardware which cannot be set to a specific " +"frequency\n" +"   or because the userspace governor isn't loaded?\n" +msgstr "" +"Beim Einstellen ist ein Fehler aufgetreten. Typische Fehlerquellen sind:\n" +"- nicht ausreichende Rechte (Administrator)\n" +"- der Regler ist nicht verfügbar bzw. nicht geladen\n" +"- die angegebene Taktik ist inkorrekt\n" +"- eine spezifische Frequenz wurde angegeben, aber der Regler 'userspace'\n" +"  kann entweder hardwarebedingt nicht genutzt werden oder ist nicht geladen\n" + +#: utils/cpufreq-set.c:170 +#, c-format +msgid "wrong, unknown or unhandled CPU?\n" +msgstr "unbekannte oder nicht regelbare CPU\n" + +#: utils/cpufreq-set.c:302 +#, c-format +msgid "" +"the -f/--freq parameter cannot be combined with -d/--min, -u/--max or\n" +"-g/--governor parameters\n" +msgstr "" +"Der -f bzw. --freq-Parameter kann nicht mit den Parametern -d/--min, -u/--" +"max\n" +"oder -g/--governor kombiniert werden\n" + +#: utils/cpufreq-set.c:308 +#, c-format +msgid "" +"At least one parameter out of -f/--freq, -d/--min, -u/--max, and\n" +"-g/--governor must be passed\n" +msgstr "" +"Es muss mindestens ein Parameter aus -f/--freq, -d/--min, -u/--max oder\n" +"-g/--governor angegeben werden.\n" + +#: utils/cpufreq-set.c:347 +#, c-format +msgid "Setting cpu: %d\n" +msgstr "" + +#: utils/cpupower-set.c:22 +#, c-format +msgid "Usage: cpupower set [ -b val ] [ -m val ] [ -s val ]\n" +msgstr "" + +#: utils/cpupower-set.c:24 +#, c-format +msgid "" +"  -b, --perf-bias [VAL]    Sets CPU's power vs performance policy on some\n" +"                           Intel models [0-15], see manpage for details\n" +msgstr "" + +#: utils/cpupower-set.c:26 +#, c-format +msgid "" +"  -m, --sched-mc  [VAL]    Sets the kernel's multi core scheduler policy.\n" +msgstr "" + +#: utils/cpupower-set.c:27 +#, c-format +msgid "" +"  -s, --sched-smt [VAL]    Sets the kernel's thread sibling scheduler " +"policy.\n" +msgstr "" + +#: utils/cpupower-set.c:80 +#, c-format +msgid "--perf-bias param out of range [0-%d]\n" +msgstr "" + +#: utils/cpupower-set.c:91 +#, c-format +msgid "--sched-mc param out of range [0-%d]\n" +msgstr "" + +#: utils/cpupower-set.c:102 +#, c-format +msgid "--sched-smt param out of range [0-%d]\n" +msgstr "" + +#: utils/cpupower-set.c:121 +#, c-format +msgid "Error setting sched-mc %s\n" +msgstr "" + +#: utils/cpupower-set.c:127 +#, c-format +msgid "Error setting sched-smt %s\n" +msgstr "" + +#: utils/cpupower-set.c:146 +#, c-format +msgid "Error setting perf-bias value on CPU %d\n" +msgstr "" + +#: utils/cpupower-info.c:21 +#, c-format +msgid "Usage: cpupower info [ -b ] [ -m ] [ -s ]\n" +msgstr "" + +#: utils/cpupower-info.c:23 +#, c-format +msgid "" +"  -b, --perf-bias    Gets CPU's power vs performance policy on some\n" +"                           Intel models [0-15], see manpage for details\n" +msgstr "" + +#: utils/cpupower-info.c:25 +#, fuzzy, c-format +msgid "  -m, --sched-mc     Gets the kernel's multi core scheduler policy.\n" +msgstr "  -p, --policy         Findet die momentane Taktik heraus *\n" + +#: utils/cpupower-info.c:26 +#, c-format +msgid "" +"  -s, --sched-smt    Gets the kernel's thread sibling scheduler policy.\n" +msgstr "" + +#: utils/cpupower-info.c:28 +#, c-format +msgid "" +"\n" +"Passing no option will show all info, by default only on core 0\n" +msgstr "" + +#: utils/cpupower-info.c:102 +#, c-format +msgid "System's multi core scheduler setting: " +msgstr "" + +#. if sysfs file is missing it's: errno == ENOENT +#: utils/cpupower-info.c:105 utils/cpupower-info.c:114 +#, c-format +msgid "not supported\n" +msgstr "" + +#: utils/cpupower-info.c:111 +#, c-format +msgid "System's thread sibling scheduler setting: " +msgstr "" + +#: utils/cpupower-info.c:126 +#, c-format +msgid "Intel's performance bias setting needs root privileges\n" +msgstr "" + +#: utils/cpupower-info.c:128 +#, c-format +msgid "System does not support Intel's performance bias setting\n" +msgstr "" + +#: utils/cpupower-info.c:147 +#, c-format +msgid "Could not read perf-bias value\n" +msgstr "" + +#: utils/cpupower-info.c:150 +#, c-format +msgid "perf-bias: %d\n" +msgstr "" + +#: utils/cpuidle-info.c:28 +#, fuzzy, c-format +msgid "Analyzing CPU %d:\n" +msgstr "analysiere CPU %d:\n" + +#: utils/cpuidle-info.c:32 +#, c-format +msgid "CPU %u: No idle states\n" +msgstr "" + +#: utils/cpuidle-info.c:36 +#, c-format +msgid "CPU %u: Can't read idle state info\n" +msgstr "" + +#: utils/cpuidle-info.c:41 +#, c-format +msgid "Could not determine max idle state %u\n" +msgstr "" + +#: utils/cpuidle-info.c:46 +#, c-format +msgid "Number of idle states: %d\n" +msgstr "" + +#: utils/cpuidle-info.c:48 +#, fuzzy, c-format +msgid "Available idle states:" +msgstr "  mögliche Taktfrequenzen: " + +#: utils/cpuidle-info.c:71 +#, c-format +msgid "Flags/Description: %s\n" +msgstr "" + +#: utils/cpuidle-info.c:74 +#, c-format +msgid "Latency: %lu\n" +msgstr "" + +#: utils/cpuidle-info.c:76 +#, c-format +msgid "Usage: %lu\n" +msgstr "" + +#: utils/cpuidle-info.c:78 +#, c-format +msgid "Duration: %llu\n" +msgstr "" + +#: utils/cpuidle-info.c:90 +#, c-format +msgid "Could not determine cpuidle driver\n" +msgstr "" + +#: utils/cpuidle-info.c:94 +#, fuzzy, c-format +msgid "CPUidle driver: %s\n" +msgstr "  Treiber: %s\n" + +#: utils/cpuidle-info.c:99 +#, c-format +msgid "Could not determine cpuidle governor\n" +msgstr "" + +#: utils/cpuidle-info.c:103 +#, c-format +msgid "CPUidle governor: %s\n" +msgstr "" + +#: utils/cpuidle-info.c:122 +#, c-format +msgid "CPU %u: Can't read C-state info\n" +msgstr "" + +#. printf("Cstates: %d\n", cstates); +#: utils/cpuidle-info.c:127 +#, c-format +msgid "active state:            C0\n" +msgstr "" + +#: utils/cpuidle-info.c:128 +#, c-format +msgid "max_cstate:              C%u\n" +msgstr "" + +#: utils/cpuidle-info.c:129 +#, fuzzy, c-format +msgid "maximum allowed latency: %lu usec\n" +msgstr "  Maximale Dauer eines Taktfrequenzwechsels: " + +#: utils/cpuidle-info.c:130 +#, c-format +msgid "states:\t\n" +msgstr "" + +#: utils/cpuidle-info.c:132 +#, c-format +msgid "    C%d:                  type[C%d] " +msgstr "" + +#: utils/cpuidle-info.c:134 +#, c-format +msgid "promotion[--] demotion[--] " +msgstr "" + +#: utils/cpuidle-info.c:135 +#, c-format +msgid "latency[%03lu] " +msgstr "" + +#: utils/cpuidle-info.c:137 +#, c-format +msgid "usage[%08lu] " +msgstr "" + +#: utils/cpuidle-info.c:139 +#, c-format +msgid "duration[%020Lu] \n" +msgstr "" + +#: utils/cpuidle-info.c:147 +#, fuzzy, c-format +msgid "Usage: cpupower idleinfo [options]\n" +msgstr "Aufruf: cpufreq-info [Optionen]\n" + +#: utils/cpuidle-info.c:149 +#, fuzzy, c-format +msgid "  -s, --silent         Only show general C-state information\n" +msgstr "" +"  -e, --debug          Erzeugt detaillierte Informationen, hilfreich\n" +"                       zum Aufspüren von Fehlern\n" + +#: utils/cpuidle-info.c:150 +#, fuzzy, c-format +msgid "" +"  -o, --proc           Prints out information like provided by the /proc/" +"acpi/processor/*/power\n" +"                       interface in older kernels\n" +msgstr "" +"  -o, --proc           Erzeugt Informationen in einem ähnlichem Format zu " +"dem\n" +"                       der /proc/cpufreq-Datei in 2.4. und frühen 2.6.\n" +"                       Kernel-Versionen\n" + +#: utils/cpuidle-info.c:209 +#, fuzzy, c-format +msgid "You can't specify more than one output-specific argument\n" +msgstr "" +"Man kann nicht mehr als einen --cpu-Parameter und/oder mehr als einen\n" +"informationsspezifischen Parameter gleichzeitig angeben\n" + +#~ msgid "" +#~ "  -c CPU, --cpu CPU    CPU number which information shall be determined " +#~ "about\n" +#~ msgstr "" +#~ "  -c CPU, --cpu CPU    Nummer der CPU, über die Informationen " +#~ "herausgefunden werden sollen\n" + +#~ msgid "" +#~ "  -c CPU, --cpu CPU        number of CPU where cpufreq settings shall be " +#~ "modified\n" +#~ msgstr "" +#~ "  -c CPU, --cpu CPU        Nummer der CPU, deren Taktfrequenz-" +#~ "Einstellung\n" +#~ "                           werden soll\n" diff --git a/tools/power/cpupower/po/fr.po b/tools/power/cpupower/po/fr.po new file mode 100644 index 00000000000..245ad20a9bf --- /dev/null +++ b/tools/power/cpupower/po/fr.po @@ -0,0 +1,947 @@ +# French translations for cpufrequtils package +# Copyright (C) 2004 THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the cpufrequtils package. +# Ducrot Bruno <ducrot@poupinou.org>, 2004. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: cpufrequtils 0.1-pre2\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2011-03-08 17:03+0100\n" +"PO-Revision-Date: 2004-11-17 15:53+1000\n" +"Last-Translator: Bruno Ducrot <ducrot@poupinou.org>\n" +"Language-Team: NONE\n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=ISO-8859-1\n" +"Content-Transfer-Encoding: 8bit\n" + +#: utils/idle_monitor/nhm_idle.c:36 +msgid "Processor Core C3" +msgstr "" + +#: utils/idle_monitor/nhm_idle.c:43 +msgid "Processor Core C6" +msgstr "" + +#: utils/idle_monitor/nhm_idle.c:51 +msgid "Processor Package C3" +msgstr "" + +#: utils/idle_monitor/nhm_idle.c:58 utils/idle_monitor/amd_fam14h_idle.c:70 +msgid "Processor Package C6" +msgstr "" + +#: utils/idle_monitor/snb_idle.c:33 +msgid "Processor Core C7" +msgstr "" + +#: utils/idle_monitor/snb_idle.c:40 +msgid "Processor Package C2" +msgstr "" + +#: utils/idle_monitor/snb_idle.c:47 +msgid "Processor Package C7" +msgstr "" + +#: utils/idle_monitor/amd_fam14h_idle.c:56 +msgid "Package in sleep state (PC1 or deeper)" +msgstr "" + +#: utils/idle_monitor/amd_fam14h_idle.c:63 +msgid "Processor Package C1" +msgstr "" + +#: utils/idle_monitor/amd_fam14h_idle.c:77 +msgid "North Bridge P1 boolean counter (returns 0 or 1)" +msgstr "" + +#: utils/idle_monitor/mperf_monitor.c:35 +msgid "Processor Core not idle" +msgstr "" + +#: utils/idle_monitor/mperf_monitor.c:42 +msgid "Processor Core in an idle state" +msgstr "" + +#: utils/idle_monitor/mperf_monitor.c:50 +msgid "Average Frequency (including boost) in MHz" +msgstr "" + +#: utils/idle_monitor/cpupower-monitor.c:66 +#, c-format +msgid "" +"cpupower monitor: [-h] [ [-t] | [-l] | [-m <mon1>,[<mon2>] ] ] [-i " +"interval_sec | -c command ...]\n" +msgstr "" + +#: utils/idle_monitor/cpupower-monitor.c:69 +#, c-format +msgid "" +"cpupower monitor: [-v] [-h] [ [-t] | [-l] | [-m <mon1>,[<mon2>] ] ] [-i " +"interval_sec | -c command ...]\n" +msgstr "" + +#: utils/idle_monitor/cpupower-monitor.c:71 +#, c-format +msgid "\t -v: be more verbose\n" +msgstr "" + +#: utils/idle_monitor/cpupower-monitor.c:73 +#, c-format +msgid "\t -h: print this help\n" +msgstr "" + +#: utils/idle_monitor/cpupower-monitor.c:74 +#, c-format +msgid "\t -i: time intervall to measure for in seconds (default 1)\n" +msgstr "" + +#: utils/idle_monitor/cpupower-monitor.c:75 +#, c-format +msgid "\t -t: show CPU topology/hierarchy\n" +msgstr "" + +#: utils/idle_monitor/cpupower-monitor.c:76 +#, c-format +msgid "\t -l: list available CPU sleep monitors (for use with -m)\n" +msgstr "" + +#: utils/idle_monitor/cpupower-monitor.c:77 +#, c-format +msgid "\t -m: show specific CPU sleep monitors only (in same order)\n" +msgstr "" + +#: utils/idle_monitor/cpupower-monitor.c:79 +#, c-format +msgid "" +"only one of: -t, -l, -m are allowed\n" +"If none of them is passed," +msgstr "" + +#: utils/idle_monitor/cpupower-monitor.c:80 +#, c-format +msgid " all supported monitors are shown\n" +msgstr "" + +#: utils/idle_monitor/cpupower-monitor.c:197 +#, c-format +msgid "Monitor %s, Counter %s has no count function. Implementation error\n" +msgstr "" + +#: utils/idle_monitor/cpupower-monitor.c:207 +#, c-format +msgid " *is offline\n" +msgstr "" + +#: utils/idle_monitor/cpupower-monitor.c:236 +#, c-format +msgid "%s: max monitor name length (%d) exceeded\n" +msgstr "" + +#: utils/idle_monitor/cpupower-monitor.c:250 +#, c-format +msgid "No matching monitor found in %s, try -l option\n" +msgstr "" + +#: utils/idle_monitor/cpupower-monitor.c:266 +#, c-format +msgid "Monitor \"%s\" (%d states) - Might overflow after %u s\n" +msgstr "" + +#: utils/idle_monitor/cpupower-monitor.c:319 +#, c-format +msgid "%s took %.5f seconds and exited with status %d\n" +msgstr "" + +#: utils/idle_monitor/cpupower-monitor.c:406 +#, c-format +msgid "Cannot read number of available processors\n" +msgstr "" + +#: utils/idle_monitor/cpupower-monitor.c:417 +#, c-format +msgid "Available monitor %s needs root access\n" +msgstr "" + +#: utils/idle_monitor/cpupower-monitor.c:428 +#, c-format +msgid "No HW Cstate monitors found\n" +msgstr "" + +#: utils/cpupower.c:78 +#, c-format +msgid "cpupower [ -c cpulist ] subcommand [ARGS]\n" +msgstr "" + +#: utils/cpupower.c:79 +#, c-format +msgid "cpupower --version\n" +msgstr "" + +#: utils/cpupower.c:80 +#, c-format +msgid "Supported subcommands are:\n" +msgstr "" + +#: utils/cpupower.c:83 +#, c-format +msgid "" +"\n" +"Some subcommands can make use of the -c cpulist option.\n" +msgstr "" + +#: utils/cpupower.c:84 +#, c-format +msgid "Look at the general cpupower manpage how to use it\n" +msgstr "" + +#: utils/cpupower.c:85 +#, c-format +msgid "and read up the subcommand's manpage whether it is supported.\n" +msgstr "" + +#: utils/cpupower.c:86 +#, c-format +msgid "" +"\n" +"Use cpupower help subcommand for getting help for above subcommands.\n" +msgstr "" + +#: utils/cpupower.c:91 +#, c-format +msgid "Report errors and bugs to %s, please.\n" +msgstr "Veuillez rapportez les erreurs et les bogues à %s, s'il vous plait.\n" + +#: utils/cpupower.c:114 +#, c-format +msgid "Error parsing cpu list\n" +msgstr "" + +#: utils/cpupower.c:172 +#, c-format +msgid "Subcommand %s needs root privileges\n" +msgstr "" + +#: utils/cpufreq-info.c:31 +#, c-format +msgid "Couldn't count the number of CPUs (%s: %s), assuming 1\n" +msgstr "Détermination du nombre de CPUs (%s : %s) impossible.  Assume 1\n" + +#: utils/cpufreq-info.c:63 +#, c-format +msgid "" +"          minimum CPU frequency  -  maximum CPU frequency  -  governor\n" +msgstr "" +"         Fréquence CPU minimale - Fréquence CPU maximale  - régulateur\n" + +#: utils/cpufreq-info.c:151 +#, c-format +msgid "Error while evaluating Boost Capabilities on CPU %d -- are you root?\n" +msgstr "" + +#. P state changes via MSR are identified via cpuid 80000007 +#. on Intel and AMD, but we assume boost capable machines can do that +#. if (cpuid_eax(0x80000000) >= 0x80000007 +#. && (cpuid_edx(0x80000007) & (1 << 7))) +#. +#: utils/cpufreq-info.c:161 +#, c-format +msgid "  boost state support: \n" +msgstr "" + +#: utils/cpufreq-info.c:163 +#, c-format +msgid "    Supported: %s\n" +msgstr "" + +#: utils/cpufreq-info.c:163 utils/cpufreq-info.c:164 +msgid "yes" +msgstr "" + +#: utils/cpufreq-info.c:163 utils/cpufreq-info.c:164 +msgid "no" +msgstr "" + +#: utils/cpufreq-info.c:164 +#, fuzzy, c-format +msgid "    Active: %s\n" +msgstr "  pilote : %s\n" + +#: utils/cpufreq-info.c:177 +#, c-format +msgid "    Boost States: %d\n" +msgstr "" + +#: utils/cpufreq-info.c:178 +#, c-format +msgid "    Total States: %d\n" +msgstr "" + +#: utils/cpufreq-info.c:181 +#, c-format +msgid "    Pstate-Pb%d: %luMHz (boost state)\n" +msgstr "" + +#: utils/cpufreq-info.c:184 +#, c-format +msgid "    Pstate-P%d:  %luMHz\n" +msgstr "" + +#: utils/cpufreq-info.c:211 +#, c-format +msgid "  no or unknown cpufreq driver is active on this CPU\n" +msgstr "  pas de pilotes cpufreq reconnu pour ce CPU\n" + +#: utils/cpufreq-info.c:213 +#, c-format +msgid "  driver: %s\n" +msgstr "  pilote : %s\n" + +#: utils/cpufreq-info.c:219 +#, fuzzy, c-format +msgid "  CPUs which run at the same hardware frequency: " +msgstr "  CPUs qui doivent changer de fréquences en même temps : " + +#: utils/cpufreq-info.c:230 +#, fuzzy, c-format +msgid "  CPUs which need to have their frequency coordinated by software: " +msgstr "  CPUs qui doivent changer de fréquences en même temps : " + +#: utils/cpufreq-info.c:241 +#, c-format +msgid "  maximum transition latency: " +msgstr "" + +#: utils/cpufreq-info.c:247 +#, c-format +msgid "  hardware limits: " +msgstr "  limitation matérielle : " + +#: utils/cpufreq-info.c:256 +#, c-format +msgid "  available frequency steps: " +msgstr "  plage de fréquence : " + +#: utils/cpufreq-info.c:269 +#, c-format +msgid "  available cpufreq governors: " +msgstr "  régulateurs disponibles : " + +#: utils/cpufreq-info.c:280 +#, c-format +msgid "  current policy: frequency should be within " +msgstr "  tactique actuelle : la fréquence doit être comprise entre " + +#: utils/cpufreq-info.c:282 +#, c-format +msgid " and " +msgstr " et " + +#: utils/cpufreq-info.c:286 +#, c-format +msgid "" +"The governor \"%s\" may decide which speed to use\n" +"                  within this range.\n" +msgstr "" +"Le régulateur \"%s\" est libre de choisir la vitesse\n" +"                  dans cette plage de fréquences.\n" + +#: utils/cpufreq-info.c:293 +#, c-format +msgid "  current CPU frequency is " +msgstr "  la fréquence actuelle de ce CPU est " + +#: utils/cpufreq-info.c:296 +#, c-format +msgid " (asserted by call to hardware)" +msgstr " (vérifié par un appel direct du matériel)" + +#: utils/cpufreq-info.c:304 +#, c-format +msgid "  cpufreq stats: " +msgstr "  des statistique concernant cpufreq:" + +#: utils/cpufreq-info.c:472 +#, fuzzy, c-format +msgid "Usage: cpupower freqinfo [options]\n" +msgstr "Usage : cpufreq-info [options]\n" + +#: utils/cpufreq-info.c:473 utils/cpufreq-set.c:26 utils/cpupower-set.c:23 +#: utils/cpupower-info.c:22 utils/cpuidle-info.c:148 +#, c-format +msgid "Options:\n" +msgstr "Options :\n" + +#: utils/cpufreq-info.c:474 +#, fuzzy, c-format +msgid "  -e, --debug          Prints out debug information [default]\n" +msgstr "  -e, --debug          Afficher les informations de déboguage\n" + +#: utils/cpufreq-info.c:475 +#, c-format +msgid "" +"  -f, --freq           Get frequency the CPU currently runs at, according\n" +"                       to the cpufreq core *\n" +msgstr "" +"  -f, --freq           Obtenir la fréquence actuelle du CPU selon le point\n" +"                       de vue du coeur du système de cpufreq *\n" + +#: utils/cpufreq-info.c:477 +#, c-format +msgid "" +"  -w, --hwfreq         Get frequency the CPU currently runs at, by reading\n" +"                       it from hardware (only available to root) *\n" +msgstr "" +"  -w, --hwfreq         Obtenir la fréquence actuelle du CPU directement par\n" +"                       le matériel (doit être root) *\n" + +#: utils/cpufreq-info.c:479 +#, c-format +msgid "" +"  -l, --hwlimits       Determine the minimum and maximum CPU frequency " +"allowed *\n" +msgstr "" +"  -l, --hwlimits       Affiche les fréquences minimales et maximales du CPU " +"*\n" + +#: utils/cpufreq-info.c:480 +#, c-format +msgid "  -d, --driver         Determines the used cpufreq kernel driver *\n" +msgstr "  -d, --driver         Affiche le pilote cpufreq utilisé *\n" + +#: utils/cpufreq-info.c:481 +#, c-format +msgid "  -p, --policy         Gets the currently used cpufreq policy *\n" +msgstr "  -p, --policy         Affiche la tactique actuelle de cpufreq *\n" + +#: utils/cpufreq-info.c:482 +#, c-format +msgid "  -g, --governors      Determines available cpufreq governors *\n" +msgstr "" +"  -g, --governors      Affiche les régulateurs disponibles de cpufreq *\n" + +#: utils/cpufreq-info.c:483 +#, fuzzy, c-format +msgid "" +"  -r, --related-cpus   Determines which CPUs run at the same hardware " +"frequency *\n" +msgstr "" +"  -a, --affected-cpus   Affiche quels sont les CPUs qui doivent changer de\n" +"                        fréquences en même temps *\n" + +#: utils/cpufreq-info.c:484 +#, fuzzy, c-format +msgid "" +"  -a, --affected-cpus  Determines which CPUs need to have their frequency\n" +"                       coordinated by software *\n" +msgstr "" +"  -a, --affected-cpus   Affiche quels sont les CPUs qui doivent changer de\n" +"                        fréquences en même temps *\n" + +#: utils/cpufreq-info.c:486 +#, c-format +msgid "  -s, --stats          Shows cpufreq statistics if available\n" +msgstr "" +"  -s, --stats          Indique des statistiques concernant cpufreq, si\n" +"                       disponibles\n" + +#: utils/cpufreq-info.c:487 +#, fuzzy, c-format +msgid "" +"  -y, --latency        Determines the maximum latency on CPU frequency " +"changes *\n" +msgstr "" +"  -l, --hwlimits       Affiche les fréquences minimales et maximales du CPU " +"*\n" + +#: utils/cpufreq-info.c:488 +#, c-format +msgid "  -b, --boost          Checks for turbo or boost modes  *\n" +msgstr "" + +#: utils/cpufreq-info.c:489 +#, c-format +msgid "" +"  -o, --proc           Prints out information like provided by the /proc/" +"cpufreq\n" +"                       interface in 2.4. and early 2.6. kernels\n" +msgstr "" +"  -o, --proc           Affiche les informations en utilisant l'interface\n" +"                       fournie par /proc/cpufreq, présente dans les " +"versions\n" +"                       2.4 et les anciennes versions 2.6 du noyau\n" + +#: utils/cpufreq-info.c:491 +#, fuzzy, c-format +msgid "" +"  -m, --human          human-readable output for the -f, -w, -s and -y " +"parameters\n" +msgstr "" +"  -m, --human           affiche dans un format lisible pour un humain\n" +"                        pour les options -f, -w et -s (MHz, GHz)\n" + +#: utils/cpufreq-info.c:492 utils/cpuidle-info.c:152 +#, c-format +msgid "  -h, --help           Prints out this screen\n" +msgstr "  -h, --help           affiche l'aide-mémoire\n" + +#: utils/cpufreq-info.c:495 +#, c-format +msgid "" +"If no argument or only the -c, --cpu parameter is given, debug output about\n" +"cpufreq is printed which is useful e.g. for reporting bugs.\n" +msgstr "" +"Par défaut, les informations de déboguage seront affichées si aucun\n" +"argument, ou bien si seulement l'argument -c (--cpu) est donné, afin de\n" +"faciliter les rapports de bogues par exemple\n" + +#: utils/cpufreq-info.c:497 +#, c-format +msgid "" +"For the arguments marked with *, omitting the -c or --cpu argument is\n" +"equivalent to setting it to zero\n" +msgstr "Les arguments avec un * utiliseront le CPU 0 si -c (--cpu) est omis\n" + +#: utils/cpufreq-info.c:580 +#, c-format +msgid "" +"The argument passed to this tool can't be combined with passing a --cpu " +"argument\n" +msgstr "Cette option est incompatible avec --cpu\n" + +#: utils/cpufreq-info.c:596 +#, c-format +msgid "" +"You can't specify more than one --cpu parameter and/or\n" +"more than one output-specific argument\n" +msgstr "" +"On ne peut indiquer plus d'un paramètre --cpu, tout comme l'on ne peut\n" +"spécifier plus d'un argument de formatage\n" + +#: utils/cpufreq-info.c:600 utils/cpufreq-set.c:82 utils/cpupower-set.c:42 +#: utils/cpupower-info.c:42 utils/cpuidle-info.c:213 +#, c-format +msgid "invalid or unknown argument\n" +msgstr "option invalide\n" + +#: utils/cpufreq-info.c:617 +#, c-format +msgid "couldn't analyze CPU %d as it doesn't seem to be present\n" +msgstr "analyse du CPU %d impossible puisqu'il ne semble pas être présent\n" + +#: utils/cpufreq-info.c:620 utils/cpupower-info.c:142 +#, c-format +msgid "analyzing CPU %d:\n" +msgstr "analyse du CPU %d :\n" + +#: utils/cpufreq-set.c:25 +#, fuzzy, c-format +msgid "Usage: cpupower frequency-set [options]\n" +msgstr "Usage : cpufreq-set [options]\n" + +#: utils/cpufreq-set.c:27 +#, c-format +msgid "" +"  -d FREQ, --min FREQ      new minimum CPU frequency the governor may " +"select\n" +msgstr "" +"  -d FREQ, --min FREQ       nouvelle fréquence minimale du CPU à utiliser\n" +"                            par le régulateur\n" + +#: utils/cpufreq-set.c:28 +#, c-format +msgid "" +"  -u FREQ, --max FREQ      new maximum CPU frequency the governor may " +"select\n" +msgstr "" +"  -u FREQ, --max FREQ       nouvelle fréquence maximale du CPU à utiliser\n" +"                            par le régulateur\n" + +#: utils/cpufreq-set.c:29 +#, c-format +msgid "  -g GOV, --governor GOV   new cpufreq governor\n" +msgstr "  -g GOV, --governor GOV   active le régulateur GOV\n" + +#: utils/cpufreq-set.c:30 +#, c-format +msgid "" +"  -f FREQ, --freq FREQ     specific frequency to be set. Requires userspace\n" +"                           governor to be available and loaded\n" +msgstr "" +"  -f FREQ, --freq FREQ     fixe la fréquence du processeur à FREQ. Il faut\n" +"                           que le régulateur « userspace » soit disponible \n" +"                           et activé.\n" + +#: utils/cpufreq-set.c:32 +#, c-format +msgid "  -r, --related            Switches all hardware-related CPUs\n" +msgstr "" + +#: utils/cpufreq-set.c:33 utils/cpupower-set.c:28 utils/cpupower-info.c:27 +#, fuzzy, c-format +msgid "  -h, --help               Prints out this screen\n" +msgstr "  -h, --help           affiche l'aide-mémoire\n" + +#: utils/cpufreq-set.c:35 +#, fuzzy, c-format +msgid "" +"Notes:\n" +"1. Omitting the -c or --cpu argument is equivalent to setting it to \"all\"\n" +msgstr "Les arguments avec un * utiliseront le CPU 0 si -c (--cpu) est omis\n" + +#: utils/cpufreq-set.c:37 +#, fuzzy, c-format +msgid "" +"2. The -f FREQ, --freq FREQ parameter cannot be combined with any other " +"parameter\n" +"   except the -c CPU, --cpu CPU parameter\n" +"3. FREQuencies can be passed in Hz, kHz (default), MHz, GHz, or THz\n" +"   by postfixing the value with the wanted unit name, without any space\n" +"   (FREQuency in kHz =^ Hz * 0.001 =^ MHz * 1000 =^ GHz * 1000000).\n" +msgstr "" +"Remarque :\n" +"1. Le CPU numéro 0 sera utilisé par défaut si -c (ou --cpu) est omis ;\n" +"2. l'argument -f FREQ (ou --freq FREQ) ne peut être utilisé qu'avec --cpu ;\n" +"3. on pourra préciser l'unité des fréquences en postfixant sans aucune " +"espace\n" +"   les valeurs par hz, kHz (par défaut), MHz, GHz ou THz\n" +"   (kHz =^ Hz * 0.001 =^ MHz * 1000 =^ GHz * 1000000).\n" + +#: utils/cpufreq-set.c:57 +#, c-format +msgid "" +"Error setting new values. Common errors:\n" +"- Do you have proper administration rights? (super-user?)\n" +"- Is the governor you requested available and modprobed?\n" +"- Trying to set an invalid policy?\n" +"- Trying to set a specific frequency, but userspace governor is not " +"available,\n" +"   for example because of hardware which cannot be set to a specific " +"frequency\n" +"   or because the userspace governor isn't loaded?\n" +msgstr "" +"En ajustant les nouveaux paramètres, une erreur est apparue. Les sources\n" +"d'erreur typique sont :\n" +"- droit d'administration insuffisant (êtes-vous root ?) ;\n" +"- le régulateur choisi n'est pas disponible, ou bien n'est pas disponible " +"en\n" +"  tant que module noyau ;\n" +"- la tactique n'est pas disponible ;\n" +"- vous voulez utiliser l'option -f/--freq, mais le régulateur « userspace »\n" +"  n'est pas disponible, par exemple parce que le matériel ne le supporte\n" +"  pas, ou bien n'est tout simplement pas chargé.\n" + +#: utils/cpufreq-set.c:170 +#, c-format +msgid "wrong, unknown or unhandled CPU?\n" +msgstr "CPU inconnu ou non supporté ?\n" + +#: utils/cpufreq-set.c:302 +#, c-format +msgid "" +"the -f/--freq parameter cannot be combined with -d/--min, -u/--max or\n" +"-g/--governor parameters\n" +msgstr "" +"l'option -f/--freq est incompatible avec les options -d/--min, -u/--max et\n" +"-g/--governor\n" + +#: utils/cpufreq-set.c:308 +#, c-format +msgid "" +"At least one parameter out of -f/--freq, -d/--min, -u/--max, and\n" +"-g/--governor must be passed\n" +msgstr "" +"L'un de ces paramètres est obligatoire : -f/--freq, -d/--min, -u/--max et\n" +"-g/--governor\n" + +#: utils/cpufreq-set.c:347 +#, c-format +msgid "Setting cpu: %d\n" +msgstr "" + +#: utils/cpupower-set.c:22 +#, c-format +msgid "Usage: cpupower set [ -b val ] [ -m val ] [ -s val ]\n" +msgstr "" + +#: utils/cpupower-set.c:24 +#, c-format +msgid "" +"  -b, --perf-bias [VAL]    Sets CPU's power vs performance policy on some\n" +"                           Intel models [0-15], see manpage for details\n" +msgstr "" + +#: utils/cpupower-set.c:26 +#, c-format +msgid "" +"  -m, --sched-mc  [VAL]    Sets the kernel's multi core scheduler policy.\n" +msgstr "" + +#: utils/cpupower-set.c:27 +#, c-format +msgid "" +"  -s, --sched-smt [VAL]    Sets the kernel's thread sibling scheduler " +"policy.\n" +msgstr "" + +#: utils/cpupower-set.c:80 +#, c-format +msgid "--perf-bias param out of range [0-%d]\n" +msgstr "" + +#: utils/cpupower-set.c:91 +#, c-format +msgid "--sched-mc param out of range [0-%d]\n" +msgstr "" + +#: utils/cpupower-set.c:102 +#, c-format +msgid "--sched-smt param out of range [0-%d]\n" +msgstr "" + +#: utils/cpupower-set.c:121 +#, c-format +msgid "Error setting sched-mc %s\n" +msgstr "" + +#: utils/cpupower-set.c:127 +#, c-format +msgid "Error setting sched-smt %s\n" +msgstr "" + +#: utils/cpupower-set.c:146 +#, c-format +msgid "Error setting perf-bias value on CPU %d\n" +msgstr "" + +#: utils/cpupower-info.c:21 +#, c-format +msgid "Usage: cpupower info [ -b ] [ -m ] [ -s ]\n" +msgstr "" + +#: utils/cpupower-info.c:23 +#, c-format +msgid "" +"  -b, --perf-bias    Gets CPU's power vs performance policy on some\n" +"                           Intel models [0-15], see manpage for details\n" +msgstr "" + +#: utils/cpupower-info.c:25 +#, fuzzy, c-format +msgid "  -m, --sched-mc     Gets the kernel's multi core scheduler policy.\n" +msgstr "  -p, --policy         Affiche la tactique actuelle de cpufreq *\n" + +#: utils/cpupower-info.c:26 +#, c-format +msgid "" +"  -s, --sched-smt    Gets the kernel's thread sibling scheduler policy.\n" +msgstr "" + +#: utils/cpupower-info.c:28 +#, c-format +msgid "" +"\n" +"Passing no option will show all info, by default only on core 0\n" +msgstr "" + +#: utils/cpupower-info.c:102 +#, c-format +msgid "System's multi core scheduler setting: " +msgstr "" + +#. if sysfs file is missing it's: errno == ENOENT +#: utils/cpupower-info.c:105 utils/cpupower-info.c:114 +#, c-format +msgid "not supported\n" +msgstr "" + +#: utils/cpupower-info.c:111 +#, c-format +msgid "System's thread sibling scheduler setting: " +msgstr "" + +#: utils/cpupower-info.c:126 +#, c-format +msgid "Intel's performance bias setting needs root privileges\n" +msgstr "" + +#: utils/cpupower-info.c:128 +#, c-format +msgid "System does not support Intel's performance bias setting\n" +msgstr "" + +#: utils/cpupower-info.c:147 +#, c-format +msgid "Could not read perf-bias value\n" +msgstr "" + +#: utils/cpupower-info.c:150 +#, c-format +msgid "perf-bias: %d\n" +msgstr "" + +#: utils/cpuidle-info.c:28 +#, fuzzy, c-format +msgid "Analyzing CPU %d:\n" +msgstr "analyse du CPU %d :\n" + +#: utils/cpuidle-info.c:32 +#, c-format +msgid "CPU %u: No idle states\n" +msgstr "" + +#: utils/cpuidle-info.c:36 +#, c-format +msgid "CPU %u: Can't read idle state info\n" +msgstr "" + +#: utils/cpuidle-info.c:41 +#, c-format +msgid "Could not determine max idle state %u\n" +msgstr "" + +#: utils/cpuidle-info.c:46 +#, c-format +msgid "Number of idle states: %d\n" +msgstr "" + +#: utils/cpuidle-info.c:48 +#, fuzzy, c-format +msgid "Available idle states:" +msgstr "  plage de fréquence : " + +#: utils/cpuidle-info.c:71 +#, c-format +msgid "Flags/Description: %s\n" +msgstr "" + +#: utils/cpuidle-info.c:74 +#, c-format +msgid "Latency: %lu\n" +msgstr "" + +#: utils/cpuidle-info.c:76 +#, c-format +msgid "Usage: %lu\n" +msgstr "" + +#: utils/cpuidle-info.c:78 +#, c-format +msgid "Duration: %llu\n" +msgstr "" + +#: utils/cpuidle-info.c:90 +#, c-format +msgid "Could not determine cpuidle driver\n" +msgstr "" + +#: utils/cpuidle-info.c:94 +#, fuzzy, c-format +msgid "CPUidle driver: %s\n" +msgstr "  pilote : %s\n" + +#: utils/cpuidle-info.c:99 +#, c-format +msgid "Could not determine cpuidle governor\n" +msgstr "" + +#: utils/cpuidle-info.c:103 +#, c-format +msgid "CPUidle governor: %s\n" +msgstr "" + +#: utils/cpuidle-info.c:122 +#, c-format +msgid "CPU %u: Can't read C-state info\n" +msgstr "" + +#. printf("Cstates: %d\n", cstates); +#: utils/cpuidle-info.c:127 +#, c-format +msgid "active state:            C0\n" +msgstr "" + +#: utils/cpuidle-info.c:128 +#, c-format +msgid "max_cstate:              C%u\n" +msgstr "" + +#: utils/cpuidle-info.c:129 +#, c-format +msgid "maximum allowed latency: %lu usec\n" +msgstr "" + +#: utils/cpuidle-info.c:130 +#, c-format +msgid "states:\t\n" +msgstr "" + +#: utils/cpuidle-info.c:132 +#, c-format +msgid "    C%d:                  type[C%d] " +msgstr "" + +#: utils/cpuidle-info.c:134 +#, c-format +msgid "promotion[--] demotion[--] " +msgstr "" + +#: utils/cpuidle-info.c:135 +#, c-format +msgid "latency[%03lu] " +msgstr "" + +#: utils/cpuidle-info.c:137 +#, c-format +msgid "usage[%08lu] " +msgstr "" + +#: utils/cpuidle-info.c:139 +#, c-format +msgid "duration[%020Lu] \n" +msgstr "" + +#: utils/cpuidle-info.c:147 +#, fuzzy, c-format +msgid "Usage: cpupower idleinfo [options]\n" +msgstr "Usage : cpufreq-info [options]\n" + +#: utils/cpuidle-info.c:149 +#, fuzzy, c-format +msgid "  -s, --silent         Only show general C-state information\n" +msgstr "  -e, --debug          Afficher les informations de déboguage\n" + +#: utils/cpuidle-info.c:150 +#, fuzzy, c-format +msgid "" +"  -o, --proc           Prints out information like provided by the /proc/" +"acpi/processor/*/power\n" +"                       interface in older kernels\n" +msgstr "" +"  -o, --proc           Affiche les informations en utilisant l'interface\n" +"                       fournie par /proc/cpufreq, présente dans les " +"versions\n" +"                       2.4 et les anciennes versions 2.6 du noyau\n" + +#: utils/cpuidle-info.c:209 +#, fuzzy, c-format +msgid "You can't specify more than one output-specific argument\n" +msgstr "" +"On ne peut indiquer plus d'un paramètre --cpu, tout comme l'on ne peut\n" +"spécifier plus d'un argument de formatage\n" + +#~ msgid "" +#~ "  -c CPU, --cpu CPU    CPU number which information shall be determined " +#~ "about\n" +#~ msgstr "" +#~ "  -c CPU, --cpu CPU    Numéro du CPU pour lequel l'information sera " +#~ "affichée\n" + +#~ msgid "" +#~ "  -c CPU, --cpu CPU        number of CPU where cpufreq settings shall be " +#~ "modified\n" +#~ msgstr "" +#~ "  -c CPU, --cpu CPU        numéro du CPU à prendre en compte pour les\n" +#~ "                           changements\n" diff --git a/tools/power/cpupower/po/it.po b/tools/power/cpupower/po/it.po new file mode 100644 index 00000000000..f80c4ddb9bd --- /dev/null +++ b/tools/power/cpupower/po/it.po @@ -0,0 +1,961 @@ +# Italian translations for cpufrequtils package +# Copyright (C) 2004-2009 +# This file is distributed under the same license as the cpufrequtils package. +# Mattia Dongili <malattia@gmail.com>. +# +# +msgid "" +msgstr "" +"Project-Id-Version: cpufrequtils 0.3\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2011-03-08 17:03+0100\n" +"PO-Revision-Date: 2009-08-15 12:00+0900\n" +"Last-Translator: Mattia Dongili <malattia@gmail.com>\n" +"Language-Team: NONE\n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: utils/idle_monitor/nhm_idle.c:36 +msgid "Processor Core C3" +msgstr "" + +#: utils/idle_monitor/nhm_idle.c:43 +msgid "Processor Core C6" +msgstr "" + +#: utils/idle_monitor/nhm_idle.c:51 +msgid "Processor Package C3" +msgstr "" + +#: utils/idle_monitor/nhm_idle.c:58 utils/idle_monitor/amd_fam14h_idle.c:70 +msgid "Processor Package C6" +msgstr "" + +#: utils/idle_monitor/snb_idle.c:33 +msgid "Processor Core C7" +msgstr "" + +#: utils/idle_monitor/snb_idle.c:40 +msgid "Processor Package C2" +msgstr "" + +#: utils/idle_monitor/snb_idle.c:47 +msgid "Processor Package C7" +msgstr "" + +#: utils/idle_monitor/amd_fam14h_idle.c:56 +msgid "Package in sleep state (PC1 or deeper)" +msgstr "" + +#: utils/idle_monitor/amd_fam14h_idle.c:63 +msgid "Processor Package C1" +msgstr "" + +#: utils/idle_monitor/amd_fam14h_idle.c:77 +msgid "North Bridge P1 boolean counter (returns 0 or 1)" +msgstr "" + +#: utils/idle_monitor/mperf_monitor.c:35 +msgid "Processor Core not idle" +msgstr "" + +#: utils/idle_monitor/mperf_monitor.c:42 +msgid "Processor Core in an idle state" +msgstr "" + +#: utils/idle_monitor/mperf_monitor.c:50 +msgid "Average Frequency (including boost) in MHz" +msgstr "" + +#: utils/idle_monitor/cpupower-monitor.c:66 +#, c-format +msgid "" +"cpupower monitor: [-h] [ [-t] | [-l] | [-m <mon1>,[<mon2>] ] ] [-i " +"interval_sec | -c command ...]\n" +msgstr "" + +#: utils/idle_monitor/cpupower-monitor.c:69 +#, c-format +msgid "" +"cpupower monitor: [-v] [-h] [ [-t] | [-l] | [-m <mon1>,[<mon2>] ] ] [-i " +"interval_sec | -c command ...]\n" +msgstr "" + +#: utils/idle_monitor/cpupower-monitor.c:71 +#, c-format +msgid "\t -v: be more verbose\n" +msgstr "" + +#: utils/idle_monitor/cpupower-monitor.c:73 +#, c-format +msgid "\t -h: print this help\n" +msgstr "" + +#: utils/idle_monitor/cpupower-monitor.c:74 +#, c-format +msgid "\t -i: time intervall to measure for in seconds (default 1)\n" +msgstr "" + +#: utils/idle_monitor/cpupower-monitor.c:75 +#, c-format +msgid "\t -t: show CPU topology/hierarchy\n" +msgstr "" + +#: utils/idle_monitor/cpupower-monitor.c:76 +#, c-format +msgid "\t -l: list available CPU sleep monitors (for use with -m)\n" +msgstr "" + +#: utils/idle_monitor/cpupower-monitor.c:77 +#, c-format +msgid "\t -m: show specific CPU sleep monitors only (in same order)\n" +msgstr "" + +#: utils/idle_monitor/cpupower-monitor.c:79 +#, c-format +msgid "" +"only one of: -t, -l, -m are allowed\n" +"If none of them is passed," +msgstr "" + +#: utils/idle_monitor/cpupower-monitor.c:80 +#, c-format +msgid " all supported monitors are shown\n" +msgstr "" + +#: utils/idle_monitor/cpupower-monitor.c:197 +#, c-format +msgid "Monitor %s, Counter %s has no count function. Implementation error\n" +msgstr "" + +#: utils/idle_monitor/cpupower-monitor.c:207 +#, c-format +msgid " *is offline\n" +msgstr "" + +#: utils/idle_monitor/cpupower-monitor.c:236 +#, c-format +msgid "%s: max monitor name length (%d) exceeded\n" +msgstr "" + +#: utils/idle_monitor/cpupower-monitor.c:250 +#, c-format +msgid "No matching monitor found in %s, try -l option\n" +msgstr "" + +#: utils/idle_monitor/cpupower-monitor.c:266 +#, c-format +msgid "Monitor \"%s\" (%d states) - Might overflow after %u s\n" +msgstr "" + +#: utils/idle_monitor/cpupower-monitor.c:319 +#, c-format +msgid "%s took %.5f seconds and exited with status %d\n" +msgstr "" + +#: utils/idle_monitor/cpupower-monitor.c:406 +#, c-format +msgid "Cannot read number of available processors\n" +msgstr "" + +#: utils/idle_monitor/cpupower-monitor.c:417 +#, c-format +msgid "Available monitor %s needs root access\n" +msgstr "" + +#: utils/idle_monitor/cpupower-monitor.c:428 +#, c-format +msgid "No HW Cstate monitors found\n" +msgstr "" + +#: utils/cpupower.c:78 +#, c-format +msgid "cpupower [ -c cpulist ] subcommand [ARGS]\n" +msgstr "" + +#: utils/cpupower.c:79 +#, c-format +msgid "cpupower --version\n" +msgstr "" + +#: utils/cpupower.c:80 +#, c-format +msgid "Supported subcommands are:\n" +msgstr "" + +#: utils/cpupower.c:83 +#, c-format +msgid "" +"\n" +"Some subcommands can make use of the -c cpulist option.\n" +msgstr "" + +#: utils/cpupower.c:84 +#, c-format +msgid "Look at the general cpupower manpage how to use it\n" +msgstr "" + +#: utils/cpupower.c:85 +#, c-format +msgid "and read up the subcommand's manpage whether it is supported.\n" +msgstr "" + +#: utils/cpupower.c:86 +#, c-format +msgid "" +"\n" +"Use cpupower help subcommand for getting help for above subcommands.\n" +msgstr "" + +#: utils/cpupower.c:91 +#, c-format +msgid "Report errors and bugs to %s, please.\n" +msgstr "Per favore, comunicare errori e malfunzionamenti a %s.\n" + +#: utils/cpupower.c:114 +#, c-format +msgid "Error parsing cpu list\n" +msgstr "" + +#: utils/cpupower.c:172 +#, c-format +msgid "Subcommand %s needs root privileges\n" +msgstr "" + +#: utils/cpufreq-info.c:31 +#, c-format +msgid "Couldn't count the number of CPUs (%s: %s), assuming 1\n" +msgstr "Impossibile determinare il numero di CPU (%s: %s), assumo sia 1\n" + +#: utils/cpufreq-info.c:63 +#, c-format +msgid "" +"          minimum CPU frequency  -  maximum CPU frequency  -  governor\n" +msgstr "" +"          frequenza minima CPU   -  frequenza massima CPU  -  gestore\n" + +#: utils/cpufreq-info.c:151 +#, c-format +msgid "Error while evaluating Boost Capabilities on CPU %d -- are you root?\n" +msgstr "" + +#. P state changes via MSR are identified via cpuid 80000007 +#. on Intel and AMD, but we assume boost capable machines can do that +#. if (cpuid_eax(0x80000000) >= 0x80000007 +#. && (cpuid_edx(0x80000007) & (1 << 7))) +#. +#: utils/cpufreq-info.c:161 +#, c-format +msgid "  boost state support: \n" +msgstr "" + +#: utils/cpufreq-info.c:163 +#, c-format +msgid "    Supported: %s\n" +msgstr "" + +#: utils/cpufreq-info.c:163 utils/cpufreq-info.c:164 +msgid "yes" +msgstr "" + +#: utils/cpufreq-info.c:163 utils/cpufreq-info.c:164 +msgid "no" +msgstr "" + +#: utils/cpufreq-info.c:164 +#, fuzzy, c-format +msgid "    Active: %s\n" +msgstr "  modulo %s\n" + +#: utils/cpufreq-info.c:177 +#, c-format +msgid "    Boost States: %d\n" +msgstr "" + +#: utils/cpufreq-info.c:178 +#, c-format +msgid "    Total States: %d\n" +msgstr "" + +#: utils/cpufreq-info.c:181 +#, c-format +msgid "    Pstate-Pb%d: %luMHz (boost state)\n" +msgstr "" + +#: utils/cpufreq-info.c:184 +#, c-format +msgid "    Pstate-P%d:  %luMHz\n" +msgstr "" + +#: utils/cpufreq-info.c:211 +#, c-format +msgid "  no or unknown cpufreq driver is active on this CPU\n" +msgstr "  nessun modulo o modulo cpufreq sconosciuto per questa CPU\n" + +#: utils/cpufreq-info.c:213 +#, c-format +msgid "  driver: %s\n" +msgstr "  modulo %s\n" + +#: utils/cpufreq-info.c:219 +#, c-format +msgid "  CPUs which run at the same hardware frequency: " +msgstr "  CPU che operano alla stessa frequenza hardware: " + +#: utils/cpufreq-info.c:230 +#, c-format +msgid "  CPUs which need to have their frequency coordinated by software: " +msgstr "  CPU che è necessario siano coordinate dal software: " + +#: utils/cpufreq-info.c:241 +#, c-format +msgid "  maximum transition latency: " +msgstr "  latenza massima durante la transizione: " + +#: utils/cpufreq-info.c:247 +#, c-format +msgid "  hardware limits: " +msgstr "  limiti hardware: " + +#: utils/cpufreq-info.c:256 +#, c-format +msgid "  available frequency steps: " +msgstr "  frequenze disponibili: " + +#: utils/cpufreq-info.c:269 +#, c-format +msgid "  available cpufreq governors: " +msgstr "  gestori disponibili: " + +#: utils/cpufreq-info.c:280 +#, c-format +msgid "  current policy: frequency should be within " +msgstr "  gestore attuale: la frequenza deve mantenersi tra " + +#: utils/cpufreq-info.c:282 +#, c-format +msgid " and " +msgstr " e " + +#: utils/cpufreq-info.c:286 +#, c-format +msgid "" +"The governor \"%s\" may decide which speed to use\n" +"                  within this range.\n" +msgstr "" +" Il gestore \"%s\" può decidere quale velocità usare\n" +"                  in questo intervallo.\n" + +#: utils/cpufreq-info.c:293 +#, c-format +msgid "  current CPU frequency is " +msgstr "  la frequenza attuale della CPU è " + +#: utils/cpufreq-info.c:296 +#, c-format +msgid " (asserted by call to hardware)" +msgstr " (ottenuta da una chiamata diretta all'hardware)" + +#: utils/cpufreq-info.c:304 +#, c-format +msgid "  cpufreq stats: " +msgstr " statistiche cpufreq:" + +#: utils/cpufreq-info.c:472 +#, fuzzy, c-format +msgid "Usage: cpupower freqinfo [options]\n" +msgstr "Uso: cpufreq-info [opzioni]\n" + +#: utils/cpufreq-info.c:473 utils/cpufreq-set.c:26 utils/cpupower-set.c:23 +#: utils/cpupower-info.c:22 utils/cpuidle-info.c:148 +#, c-format +msgid "Options:\n" +msgstr "Opzioni:\n" + +#: utils/cpufreq-info.c:474 +#, fuzzy, c-format +msgid "  -e, --debug          Prints out debug information [default]\n" +msgstr "  -e, --debug          Mostra informazioni di debug\n" + +#: utils/cpufreq-info.c:475 +#, c-format +msgid "" +"  -f, --freq           Get frequency the CPU currently runs at, according\n" +"                       to the cpufreq core *\n" +msgstr "" +"  -f, --freq           Mostra la frequenza attuale della CPU secondo\n" +"                       il modulo cpufreq *\n" + +#: utils/cpufreq-info.c:477 +#, c-format +msgid "" +"  -w, --hwfreq         Get frequency the CPU currently runs at, by reading\n" +"                       it from hardware (only available to root) *\n" +msgstr "" +"  -w, --hwfreq         Mostra la frequenza attuale della CPU leggendola\n" +"                       dall'hardware (disponibile solo per l'utente root) *\n" + +#: utils/cpufreq-info.c:479 +#, c-format +msgid "" +"  -l, --hwlimits       Determine the minimum and maximum CPU frequency " +"allowed *\n" +msgstr "" +"  -l, --hwlimits       Determina le frequenze minima e massima possibili per " +"la CPU *\n" + +#: utils/cpufreq-info.c:480 +#, c-format +msgid "  -d, --driver         Determines the used cpufreq kernel driver *\n" +msgstr "" +"  -d, --driver         Determina il modulo cpufreq del kernel in uso *\n" + +#: utils/cpufreq-info.c:481 +#, c-format +msgid "  -p, --policy         Gets the currently used cpufreq policy *\n" +msgstr "" +"  -p, --policy         Mostra il gestore cpufreq attualmente in uso *\n" + +#: utils/cpufreq-info.c:482 +#, c-format +msgid "  -g, --governors      Determines available cpufreq governors *\n" +msgstr "  -g, --governors      Determina i gestori cpufreq disponibili *\n" + +#: utils/cpufreq-info.c:483 +#, c-format +msgid "" +"  -r, --related-cpus   Determines which CPUs run at the same hardware " +"frequency *\n" +msgstr "" +"  -r, --related-cpus   Determina quali CPU operano alla stessa frequenza *\n" + +#: utils/cpufreq-info.c:484 +#, c-format +msgid "" +"  -a, --affected-cpus  Determines which CPUs need to have their frequency\n" +"                       coordinated by software *\n" +msgstr "" +"  -a, --affected-cpus  Determina quali CPU devono avere la frequenza\n" +"                       coordinata dal software *\n" + +#: utils/cpufreq-info.c:486 +#, c-format +msgid "  -s, --stats          Shows cpufreq statistics if available\n" +msgstr "  -s, --stats          Mostra le statistiche se disponibili\n" + +#: utils/cpufreq-info.c:487 +#, c-format +msgid "" +"  -y, --latency        Determines the maximum latency on CPU frequency " +"changes *\n" +msgstr "" +"  -y, --latency        Determina la latenza massima durante i cambi di " +"frequenza *\n" + +#: utils/cpufreq-info.c:488 +#, c-format +msgid "  -b, --boost          Checks for turbo or boost modes  *\n" +msgstr "" + +#: utils/cpufreq-info.c:489 +#, c-format +msgid "" +"  -o, --proc           Prints out information like provided by the /proc/" +"cpufreq\n" +"                       interface in 2.4. and early 2.6. kernels\n" +msgstr "" +"  -o, --proc           Stampa le informazioni come se provenissero dalla\n" +"                       interfaccia cpufreq /proc/ presente nei kernel\n" +"                       2.4 ed i primi 2.6\n" + +#: utils/cpufreq-info.c:491 +#, c-format +msgid "" +"  -m, --human          human-readable output for the -f, -w, -s and -y " +"parameters\n" +msgstr "" +"  -m, --human          formatta l'output delle opzioni -f, -w, -s e -y in " +"maniera\n" +"                       leggibile da un essere umano\n" + +#: utils/cpufreq-info.c:492 utils/cpuidle-info.c:152 +#, c-format +msgid "  -h, --help           Prints out this screen\n" +msgstr "  -h, --help           Stampa questa schermata\n" + +#: utils/cpufreq-info.c:495 +#, c-format +msgid "" +"If no argument or only the -c, --cpu parameter is given, debug output about\n" +"cpufreq is printed which is useful e.g. for reporting bugs.\n" +msgstr "" +"Se non viene specificata nessuna opzione o viene specificata solo l'opzione -" +"c, --cpu,\n" +"le informazioni di debug per cpufreq saranno utili ad esempio a riportare i " +"bug.\n" + +#: utils/cpufreq-info.c:497 +#, c-format +msgid "" +"For the arguments marked with *, omitting the -c or --cpu argument is\n" +"equivalent to setting it to zero\n" +msgstr "" +"Per le opzioni segnalate con *, omettere l'opzione -c o --cpu è come " +"specificarla\n" +"con il valore 0\n" + +#: utils/cpufreq-info.c:580 +#, c-format +msgid "" +"The argument passed to this tool can't be combined with passing a --cpu " +"argument\n" +msgstr "" +"L'opzione specificata a questo programma non può essere combinata con --cpu\n" + +#: utils/cpufreq-info.c:596 +#, c-format +msgid "" +"You can't specify more than one --cpu parameter and/or\n" +"more than one output-specific argument\n" +msgstr "" +"Non è possibile specificare più di una volta l'opzione --cpu e/o\n" +"specificare più di un parametro di output specifico\n" + +#: utils/cpufreq-info.c:600 utils/cpufreq-set.c:82 utils/cpupower-set.c:42 +#: utils/cpupower-info.c:42 utils/cpuidle-info.c:213 +#, c-format +msgid "invalid or unknown argument\n" +msgstr "opzione sconosciuta o non valida\n" + +#: utils/cpufreq-info.c:617 +#, c-format +msgid "couldn't analyze CPU %d as it doesn't seem to be present\n" +msgstr "impossibile analizzare la CPU %d poiché non sembra essere presente\n" + +#: utils/cpufreq-info.c:620 utils/cpupower-info.c:142 +#, c-format +msgid "analyzing CPU %d:\n" +msgstr "analisi della CPU %d:\n" + +#: utils/cpufreq-set.c:25 +#, fuzzy, c-format +msgid "Usage: cpupower frequency-set [options]\n" +msgstr "Uso: cpufreq-set [opzioni]\n" + +#: utils/cpufreq-set.c:27 +#, c-format +msgid "" +"  -d FREQ, --min FREQ      new minimum CPU frequency the governor may " +"select\n" +msgstr "" +"  -d FREQ, --min FREQ      la nuova frequenza minima che il gestore cpufreq " +"può scegliere\n" + +#: utils/cpufreq-set.c:28 +#, c-format +msgid "" +"  -u FREQ, --max FREQ      new maximum CPU frequency the governor may " +"select\n" +msgstr "" +"  -u FREQ, --max FREQ      la nuova frequenza massima che il gestore cpufreq " +"può scegliere\n" + +#: utils/cpufreq-set.c:29 +#, c-format +msgid "  -g GOV, --governor GOV   new cpufreq governor\n" +msgstr "  -g GOV, --governor GOV   nuovo gestore cpufreq\n" + +#: utils/cpufreq-set.c:30 +#, c-format +msgid "" +"  -f FREQ, --freq FREQ     specific frequency to be set. Requires userspace\n" +"                           governor to be available and loaded\n" +msgstr "" +"  -f FREQ, --freq FREQ     specifica la frequenza a cui impostare la CPU.\n" +"                           È necessario che il gestore userspace sia " +"disponibile e caricato\n" + +#: utils/cpufreq-set.c:32 +#, c-format +msgid "  -r, --related            Switches all hardware-related CPUs\n" +msgstr "" +"  -r, --related            Modifica tutte le CPU coordinate dall'hardware\n" + +#: utils/cpufreq-set.c:33 utils/cpupower-set.c:28 utils/cpupower-info.c:27 +#, c-format +msgid "  -h, --help               Prints out this screen\n" +msgstr "  -h, --help               Stampa questa schermata\n" + +#: utils/cpufreq-set.c:35 +#, fuzzy, c-format +msgid "" +"Notes:\n" +"1. Omitting the -c or --cpu argument is equivalent to setting it to \"all\"\n" +msgstr "" +"Per le opzioni segnalate con *, omettere l'opzione -c o --cpu è come " +"specificarla\n" +"con il valore 0\n" + +#: utils/cpufreq-set.c:37 +#, fuzzy, c-format +msgid "" +"2. The -f FREQ, --freq FREQ parameter cannot be combined with any other " +"parameter\n" +"   except the -c CPU, --cpu CPU parameter\n" +"3. FREQuencies can be passed in Hz, kHz (default), MHz, GHz, or THz\n" +"   by postfixing the value with the wanted unit name, without any space\n" +"   (FREQuency in kHz =^ Hz * 0.001 =^ MHz * 1000 =^ GHz * 1000000).\n" +msgstr "" +"Note:\n" +"1. Omettere l'opzione -c o --cpu è equivalente a impostarlo a 0\n" +"2. l'opzione -f FREQ, --freq FREQ non può essere specificata con altre " +"opzioni\n" +"   ad eccezione dell'opzione -c CPU o --cpu CPU\n" +"3. le FREQuenze possono essere specuficate in  Hz, kHz (default), MHz, GHz, " +"or THz\n" +"   postponendo l'unità di misura al valore senza nessuno spazio fra loro\n" +"   (FREQuenza in kHz =^ Hz * 0.001 =^ MHz * 1000 =^ GHz * 1000000).\n" + +#: utils/cpufreq-set.c:57 +#, c-format +msgid "" +"Error setting new values. Common errors:\n" +"- Do you have proper administration rights? (super-user?)\n" +"- Is the governor you requested available and modprobed?\n" +"- Trying to set an invalid policy?\n" +"- Trying to set a specific frequency, but userspace governor is not " +"available,\n" +"   for example because of hardware which cannot be set to a specific " +"frequency\n" +"   or because the userspace governor isn't loaded?\n" +msgstr "" +"Si sono verificati degli errori impostando i nuovi valori.\n" +"Alcuni errori comuni possono essere:\n" +"- Hai i necessari diritti di amministrazione? (super-user?)\n" +"- Il gestore che hai richiesto è disponibile e caricato?\n" +"- Stai provando ad impostare una politica di gestione non valida?\n" +"- Stai provando a impostare una specifica frequenza ma il gestore\n" +"  userspace non è disponibile, per esempio a causa dell'hardware\n" +"  che non supporta frequenze fisse o a causa del fatto che\n" +"  il gestore userspace non è caricato?\n" + +#: utils/cpufreq-set.c:170 +#, c-format +msgid "wrong, unknown or unhandled CPU?\n" +msgstr "CPU errata, sconosciuta o non gestita?\n" + +#: utils/cpufreq-set.c:302 +#, c-format +msgid "" +"the -f/--freq parameter cannot be combined with -d/--min, -u/--max or\n" +"-g/--governor parameters\n" +msgstr "" +"l'opzione -f/--freq non può venire combinata con i parametri\n" +" -d/--min, -u/--max o -g/--governor\n" + +#: utils/cpufreq-set.c:308 +#, c-format +msgid "" +"At least one parameter out of -f/--freq, -d/--min, -u/--max, and\n" +"-g/--governor must be passed\n" +msgstr "" +"Almeno una delle opzioni -f/--freq, -d/--min, -u/--max, e -g/--governor\n" +"deve essere specificata\n" + +#: utils/cpufreq-set.c:347 +#, c-format +msgid "Setting cpu: %d\n" +msgstr "" + +#: utils/cpupower-set.c:22 +#, c-format +msgid "Usage: cpupower set [ -b val ] [ -m val ] [ -s val ]\n" +msgstr "" + +#: utils/cpupower-set.c:24 +#, c-format +msgid "" +"  -b, --perf-bias [VAL]    Sets CPU's power vs performance policy on some\n" +"                           Intel models [0-15], see manpage for details\n" +msgstr "" + +#: utils/cpupower-set.c:26 +#, c-format +msgid "" +"  -m, --sched-mc  [VAL]    Sets the kernel's multi core scheduler policy.\n" +msgstr "" + +#: utils/cpupower-set.c:27 +#, c-format +msgid "" +"  -s, --sched-smt [VAL]    Sets the kernel's thread sibling scheduler " +"policy.\n" +msgstr "" + +#: utils/cpupower-set.c:80 +#, c-format +msgid "--perf-bias param out of range [0-%d]\n" +msgstr "" + +#: utils/cpupower-set.c:91 +#, c-format +msgid "--sched-mc param out of range [0-%d]\n" +msgstr "" + +#: utils/cpupower-set.c:102 +#, c-format +msgid "--sched-smt param out of range [0-%d]\n" +msgstr "" + +#: utils/cpupower-set.c:121 +#, c-format +msgid "Error setting sched-mc %s\n" +msgstr "" + +#: utils/cpupower-set.c:127 +#, c-format +msgid "Error setting sched-smt %s\n" +msgstr "" + +#: utils/cpupower-set.c:146 +#, c-format +msgid "Error setting perf-bias value on CPU %d\n" +msgstr "" + +#: utils/cpupower-info.c:21 +#, c-format +msgid "Usage: cpupower info [ -b ] [ -m ] [ -s ]\n" +msgstr "" + +#: utils/cpupower-info.c:23 +#, c-format +msgid "" +"  -b, --perf-bias    Gets CPU's power vs performance policy on some\n" +"                           Intel models [0-15], see manpage for details\n" +msgstr "" + +#: utils/cpupower-info.c:25 +#, fuzzy, c-format +msgid "  -m, --sched-mc     Gets the kernel's multi core scheduler policy.\n" +msgstr "" +"  -p, --policy         Mostra il gestore cpufreq attualmente in uso *\n" + +#: utils/cpupower-info.c:26 +#, c-format +msgid "" +"  -s, --sched-smt    Gets the kernel's thread sibling scheduler policy.\n" +msgstr "" + +#: utils/cpupower-info.c:28 +#, c-format +msgid "" +"\n" +"Passing no option will show all info, by default only on core 0\n" +msgstr "" + +#: utils/cpupower-info.c:102 +#, c-format +msgid "System's multi core scheduler setting: " +msgstr "" + +#. if sysfs file is missing it's: errno == ENOENT +#: utils/cpupower-info.c:105 utils/cpupower-info.c:114 +#, c-format +msgid "not supported\n" +msgstr "" + +#: utils/cpupower-info.c:111 +#, c-format +msgid "System's thread sibling scheduler setting: " +msgstr "" + +#: utils/cpupower-info.c:126 +#, c-format +msgid "Intel's performance bias setting needs root privileges\n" +msgstr "" + +#: utils/cpupower-info.c:128 +#, c-format +msgid "System does not support Intel's performance bias setting\n" +msgstr "" + +#: utils/cpupower-info.c:147 +#, c-format +msgid "Could not read perf-bias value\n" +msgstr "" + +#: utils/cpupower-info.c:150 +#, c-format +msgid "perf-bias: %d\n" +msgstr "" + +#: utils/cpuidle-info.c:28 +#, fuzzy, c-format +msgid "Analyzing CPU %d:\n" +msgstr "analisi della CPU %d:\n" + +#: utils/cpuidle-info.c:32 +#, c-format +msgid "CPU %u: No idle states\n" +msgstr "" + +#: utils/cpuidle-info.c:36 +#, c-format +msgid "CPU %u: Can't read idle state info\n" +msgstr "" + +#: utils/cpuidle-info.c:41 +#, c-format +msgid "Could not determine max idle state %u\n" +msgstr "" + +#: utils/cpuidle-info.c:46 +#, c-format +msgid "Number of idle states: %d\n" +msgstr "" + +#: utils/cpuidle-info.c:48 +#, fuzzy, c-format +msgid "Available idle states:" +msgstr "  frequenze disponibili: " + +#: utils/cpuidle-info.c:71 +#, c-format +msgid "Flags/Description: %s\n" +msgstr "" + +#: utils/cpuidle-info.c:74 +#, c-format +msgid "Latency: %lu\n" +msgstr "" + +#: utils/cpuidle-info.c:76 +#, c-format +msgid "Usage: %lu\n" +msgstr "" + +#: utils/cpuidle-info.c:78 +#, c-format +msgid "Duration: %llu\n" +msgstr "" + +#: utils/cpuidle-info.c:90 +#, c-format +msgid "Could not determine cpuidle driver\n" +msgstr "" + +#: utils/cpuidle-info.c:94 +#, fuzzy, c-format +msgid "CPUidle driver: %s\n" +msgstr "  modulo %s\n" + +#: utils/cpuidle-info.c:99 +#, c-format +msgid "Could not determine cpuidle governor\n" +msgstr "" + +#: utils/cpuidle-info.c:103 +#, c-format +msgid "CPUidle governor: %s\n" +msgstr "" + +#: utils/cpuidle-info.c:122 +#, c-format +msgid "CPU %u: Can't read C-state info\n" +msgstr "" + +#. printf("Cstates: %d\n", cstates); +#: utils/cpuidle-info.c:127 +#, c-format +msgid "active state:            C0\n" +msgstr "" + +#: utils/cpuidle-info.c:128 +#, c-format +msgid "max_cstate:              C%u\n" +msgstr "" + +#: utils/cpuidle-info.c:129 +#, fuzzy, c-format +msgid "maximum allowed latency: %lu usec\n" +msgstr "  latenza massima durante la transizione: " + +#: utils/cpuidle-info.c:130 +#, c-format +msgid "states:\t\n" +msgstr "" + +#: utils/cpuidle-info.c:132 +#, c-format +msgid "    C%d:                  type[C%d] " +msgstr "" + +#: utils/cpuidle-info.c:134 +#, c-format +msgid "promotion[--] demotion[--] " +msgstr "" + +#: utils/cpuidle-info.c:135 +#, c-format +msgid "latency[%03lu] " +msgstr "" + +#: utils/cpuidle-info.c:137 +#, c-format +msgid "usage[%08lu] " +msgstr "" + +#: utils/cpuidle-info.c:139 +#, c-format +msgid "duration[%020Lu] \n" +msgstr "" + +#: utils/cpuidle-info.c:147 +#, fuzzy, c-format +msgid "Usage: cpupower idleinfo [options]\n" +msgstr "Uso: cpufreq-info [opzioni]\n" + +#: utils/cpuidle-info.c:149 +#, fuzzy, c-format +msgid "  -s, --silent         Only show general C-state information\n" +msgstr "  -e, --debug          Mostra informazioni di debug\n" + +#: utils/cpuidle-info.c:150 +#, fuzzy, c-format +msgid "" +"  -o, --proc           Prints out information like provided by the /proc/" +"acpi/processor/*/power\n" +"                       interface in older kernels\n" +msgstr "" +"  -o, --proc           Stampa le informazioni come se provenissero dalla\n" +"                       interfaccia cpufreq /proc/ presente nei kernel\n" +"                       2.4 ed i primi 2.6\n" + +#: utils/cpuidle-info.c:209 +#, fuzzy, c-format +msgid "You can't specify more than one output-specific argument\n" +msgstr "" +"Non è possibile specificare più di una volta l'opzione --cpu e/o\n" +"specificare più di un parametro di output specifico\n" + +#~ msgid "" +#~ "  -c CPU, --cpu CPU    CPU number which information shall be determined " +#~ "about\n" +#~ msgstr "" +#~ "  -c CPU, --cpu CPU    Numero di CPU per la quale ottenere le " +#~ "informazioni\n" + +#~ msgid "" +#~ "  -c CPU, --cpu CPU        number of CPU where cpufreq settings shall be " +#~ "modified\n" +#~ msgstr "" +#~ "  -c CPU, --cpu CPU        numero di CPU per la quale modificare le " +#~ "impostazioni\n" + +#, fuzzy +#~ msgid "  CPUs which coordinate software frequency requirements: " +#~ msgstr "" +#~ "  CPU per le quali e` necessario cambiare la frequenza " +#~ "contemporaneamente: " diff --git a/tools/power/cpupower/po/pt.po b/tools/power/cpupower/po/pt.po new file mode 100644 index 00000000000..990f5267ffe --- /dev/null +++ b/tools/power/cpupower/po/pt.po @@ -0,0 +1,957 @@ +# Brazilian Portuguese translations for cpufrequtils package +# Copyright (C) 2008 THE cpufrequtils'S COPYRIGHT HOLDER +# This file is distributed under the same license as the cpufrequtils package. +# Claudio Eduardo <claudioeddy@gmail.com>, 2009. +# +# +msgid "" +msgstr "" +"Project-Id-Version: cpufrequtils 004\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2011-03-08 17:03+0100\n" +"PO-Revision-Date: 2008-06-14 22:16-0400\n" +"Last-Translator: Claudio Eduardo <claudioeddy@gmail.com>\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: utils/idle_monitor/nhm_idle.c:36 +msgid "Processor Core C3" +msgstr "" + +#: utils/idle_monitor/nhm_idle.c:43 +msgid "Processor Core C6" +msgstr "" + +#: utils/idle_monitor/nhm_idle.c:51 +msgid "Processor Package C3" +msgstr "" + +#: utils/idle_monitor/nhm_idle.c:58 utils/idle_monitor/amd_fam14h_idle.c:70 +msgid "Processor Package C6" +msgstr "" + +#: utils/idle_monitor/snb_idle.c:33 +msgid "Processor Core C7" +msgstr "" + +#: utils/idle_monitor/snb_idle.c:40 +msgid "Processor Package C2" +msgstr "" + +#: utils/idle_monitor/snb_idle.c:47 +msgid "Processor Package C7" +msgstr "" + +#: utils/idle_monitor/amd_fam14h_idle.c:56 +msgid "Package in sleep state (PC1 or deeper)" +msgstr "" + +#: utils/idle_monitor/amd_fam14h_idle.c:63 +msgid "Processor Package C1" +msgstr "" + +#: utils/idle_monitor/amd_fam14h_idle.c:77 +msgid "North Bridge P1 boolean counter (returns 0 or 1)" +msgstr "" + +#: utils/idle_monitor/mperf_monitor.c:35 +msgid "Processor Core not idle" +msgstr "" + +#: utils/idle_monitor/mperf_monitor.c:42 +msgid "Processor Core in an idle state" +msgstr "" + +#: utils/idle_monitor/mperf_monitor.c:50 +msgid "Average Frequency (including boost) in MHz" +msgstr "" + +#: utils/idle_monitor/cpupower-monitor.c:66 +#, c-format +msgid "" +"cpupower monitor: [-h] [ [-t] | [-l] | [-m <mon1>,[<mon2>] ] ] [-i " +"interval_sec | -c command ...]\n" +msgstr "" + +#: utils/idle_monitor/cpupower-monitor.c:69 +#, c-format +msgid "" +"cpupower monitor: [-v] [-h] [ [-t] | [-l] | [-m <mon1>,[<mon2>] ] ] [-i " +"interval_sec | -c command ...]\n" +msgstr "" + +#: utils/idle_monitor/cpupower-monitor.c:71 +#, c-format +msgid "\t -v: be more verbose\n" +msgstr "" + +#: utils/idle_monitor/cpupower-monitor.c:73 +#, c-format +msgid "\t -h: print this help\n" +msgstr "" + +#: utils/idle_monitor/cpupower-monitor.c:74 +#, c-format +msgid "\t -i: time intervall to measure for in seconds (default 1)\n" +msgstr "" + +#: utils/idle_monitor/cpupower-monitor.c:75 +#, c-format +msgid "\t -t: show CPU topology/hierarchy\n" +msgstr "" + +#: utils/idle_monitor/cpupower-monitor.c:76 +#, c-format +msgid "\t -l: list available CPU sleep monitors (for use with -m)\n" +msgstr "" + +#: utils/idle_monitor/cpupower-monitor.c:77 +#, c-format +msgid "\t -m: show specific CPU sleep monitors only (in same order)\n" +msgstr "" + +#: utils/idle_monitor/cpupower-monitor.c:79 +#, c-format +msgid "" +"only one of: -t, -l, -m are allowed\n" +"If none of them is passed," +msgstr "" + +#: utils/idle_monitor/cpupower-monitor.c:80 +#, c-format +msgid " all supported monitors are shown\n" +msgstr "" + +#: utils/idle_monitor/cpupower-monitor.c:197 +#, c-format +msgid "Monitor %s, Counter %s has no count function. Implementation error\n" +msgstr "" + +#: utils/idle_monitor/cpupower-monitor.c:207 +#, c-format +msgid " *is offline\n" +msgstr "" + +#: utils/idle_monitor/cpupower-monitor.c:236 +#, c-format +msgid "%s: max monitor name length (%d) exceeded\n" +msgstr "" + +#: utils/idle_monitor/cpupower-monitor.c:250 +#, c-format +msgid "No matching monitor found in %s, try -l option\n" +msgstr "" + +#: utils/idle_monitor/cpupower-monitor.c:266 +#, c-format +msgid "Monitor \"%s\" (%d states) - Might overflow after %u s\n" +msgstr "" + +#: utils/idle_monitor/cpupower-monitor.c:319 +#, c-format +msgid "%s took %.5f seconds and exited with status %d\n" +msgstr "" + +#: utils/idle_monitor/cpupower-monitor.c:406 +#, c-format +msgid "Cannot read number of available processors\n" +msgstr "" + +#: utils/idle_monitor/cpupower-monitor.c:417 +#, c-format +msgid "Available monitor %s needs root access\n" +msgstr "" + +#: utils/idle_monitor/cpupower-monitor.c:428 +#, c-format +msgid "No HW Cstate monitors found\n" +msgstr "" + +#: utils/cpupower.c:78 +#, c-format +msgid "cpupower [ -c cpulist ] subcommand [ARGS]\n" +msgstr "" + +#: utils/cpupower.c:79 +#, c-format +msgid "cpupower --version\n" +msgstr "" + +#: utils/cpupower.c:80 +#, c-format +msgid "Supported subcommands are:\n" +msgstr "" + +#: utils/cpupower.c:83 +#, c-format +msgid "" +"\n" +"Some subcommands can make use of the -c cpulist option.\n" +msgstr "" + +#: utils/cpupower.c:84 +#, c-format +msgid "Look at the general cpupower manpage how to use it\n" +msgstr "" + +#: utils/cpupower.c:85 +#, c-format +msgid "and read up the subcommand's manpage whether it is supported.\n" +msgstr "" + +#: utils/cpupower.c:86 +#, c-format +msgid "" +"\n" +"Use cpupower help subcommand for getting help for above subcommands.\n" +msgstr "" + +#: utils/cpupower.c:91 +#, c-format +msgid "Report errors and bugs to %s, please.\n" +msgstr "Reporte erros e bugs para %s, por favor.\n" + +#: utils/cpupower.c:114 +#, c-format +msgid "Error parsing cpu list\n" +msgstr "" + +#: utils/cpupower.c:172 +#, c-format +msgid "Subcommand %s needs root privileges\n" +msgstr "" + +#: utils/cpufreq-info.c:31 +#, c-format +msgid "Couldn't count the number of CPUs (%s: %s), assuming 1\n" +msgstr "Não foi possÃvel contar o número de CPUs (%s: %s), assumindo 1\n" + +#: utils/cpufreq-info.c:63 +#, c-format +msgid "" +"          minimum CPU frequency  -  maximum CPU frequency  -  governor\n" +msgstr "" +"          frequência mÃnina do CPU  -  frequência máxima do CPU  -  " +"regulador\n" + +#: utils/cpufreq-info.c:151 +#, c-format +msgid "Error while evaluating Boost Capabilities on CPU %d -- are you root?\n" +msgstr "" + +#. P state changes via MSR are identified via cpuid 80000007 +#. on Intel and AMD, but we assume boost capable machines can do that +#. if (cpuid_eax(0x80000000) >= 0x80000007 +#. && (cpuid_edx(0x80000007) & (1 << 7))) +#. +#: utils/cpufreq-info.c:161 +#, c-format +msgid "  boost state support: \n" +msgstr "" + +#: utils/cpufreq-info.c:163 +#, c-format +msgid "    Supported: %s\n" +msgstr "" + +#: utils/cpufreq-info.c:163 utils/cpufreq-info.c:164 +msgid "yes" +msgstr "" + +#: utils/cpufreq-info.c:163 utils/cpufreq-info.c:164 +msgid "no" +msgstr "" + +#: utils/cpufreq-info.c:164 +#, fuzzy, c-format +msgid "    Active: %s\n" +msgstr "  driver: %s\n" + +#: utils/cpufreq-info.c:177 +#, c-format +msgid "    Boost States: %d\n" +msgstr "" + +#: utils/cpufreq-info.c:178 +#, c-format +msgid "    Total States: %d\n" +msgstr "" + +#: utils/cpufreq-info.c:181 +#, c-format +msgid "    Pstate-Pb%d: %luMHz (boost state)\n" +msgstr "" + +#: utils/cpufreq-info.c:184 +#, c-format +msgid "    Pstate-P%d:  %luMHz\n" +msgstr "" + +#: utils/cpufreq-info.c:211 +#, c-format +msgid "  no or unknown cpufreq driver is active on this CPU\n" +msgstr "  nenhum ou driver do cpufreq deconhecido está ativo nesse CPU\n" + +#: utils/cpufreq-info.c:213 +#, c-format +msgid "  driver: %s\n" +msgstr "  driver: %s\n" + +#: utils/cpufreq-info.c:219 +#, c-format +msgid "  CPUs which run at the same hardware frequency: " +msgstr "  CPUs que rodam na mesma frequência de hardware: " + +#: utils/cpufreq-info.c:230 +#, c-format +msgid "  CPUs which need to have their frequency coordinated by software: " +msgstr "  CPUs que precisam ter suas frequências coordenadas por software: " + +#: utils/cpufreq-info.c:241 +#, c-format +msgid "  maximum transition latency: " +msgstr "  maior latência de transição: " + +#: utils/cpufreq-info.c:247 +#, c-format +msgid "  hardware limits: " +msgstr "  limites do hardware: " + +#: utils/cpufreq-info.c:256 +#, c-format +msgid "  available frequency steps: " +msgstr "  nÃveis de frequência disponÃveis: " + +#: utils/cpufreq-info.c:269 +#, c-format +msgid "  available cpufreq governors: " +msgstr "  reguladores do cpufreq disponÃveis: " + +#: utils/cpufreq-info.c:280 +#, c-format +msgid "  current policy: frequency should be within " +msgstr "  polÃtica de frequência atual deve estar entre " + +#: utils/cpufreq-info.c:282 +#, c-format +msgid " and " +msgstr " e " + +#: utils/cpufreq-info.c:286 +#, c-format +msgid "" +"The governor \"%s\" may decide which speed to use\n" +"                  within this range.\n" +msgstr "" +"O regulador \"%s\" deve decidir qual velocidade usar\n" +"                  dentro desse limite.\n" + +#: utils/cpufreq-info.c:293 +#, c-format +msgid "  current CPU frequency is " +msgstr "  frequência atual do CPU é " + +#: utils/cpufreq-info.c:296 +#, c-format +msgid " (asserted by call to hardware)" +msgstr " (declarado por chamada ao hardware)" + +#: utils/cpufreq-info.c:304 +#, c-format +msgid "  cpufreq stats: " +msgstr "  status do cpufreq: " + +#: utils/cpufreq-info.c:472 +#, fuzzy, c-format +msgid "Usage: cpupower freqinfo [options]\n" +msgstr "Uso: cpufreq-info [opções]\n" + +#: utils/cpufreq-info.c:473 utils/cpufreq-set.c:26 utils/cpupower-set.c:23 +#: utils/cpupower-info.c:22 utils/cpuidle-info.c:148 +#, c-format +msgid "Options:\n" +msgstr "Opções:\n" + +#: utils/cpufreq-info.c:474 +#, fuzzy, c-format +msgid "  -e, --debug          Prints out debug information [default]\n" +msgstr "  -e, --debug          Mostra informação de debug\n" + +#: utils/cpufreq-info.c:475 +#, c-format +msgid "" +"  -f, --freq           Get frequency the CPU currently runs at, according\n" +"                       to the cpufreq core *\n" +msgstr "" +"  -f, --freq           Obtem a frequência na qual o CPU roda no momento, de " +"acordo\n" +"                       com o núcleo do cpufreq *\n" + +#: utils/cpufreq-info.c:477 +#, c-format +msgid "" +"  -w, --hwfreq         Get frequency the CPU currently runs at, by reading\n" +"                       it from hardware (only available to root) *\n" +msgstr "" +"  -w, --hwfreq         Obtem a frequência na qual o CPU está operando no " +"momento,\n" +"                       através de leitura no hardware (disponÃvel somente " +"para root) *\n" + +#: utils/cpufreq-info.c:479 +#, c-format +msgid "" +"  -l, --hwlimits       Determine the minimum and maximum CPU frequency " +"allowed *\n" +msgstr "" +"  -l, --hwlimits       Determina a frequência mÃnima e máxima do CPU " +"permitida *\n" + +#: utils/cpufreq-info.c:480 +#, c-format +msgid "  -d, --driver         Determines the used cpufreq kernel driver *\n" +msgstr "" +"  -d,  --driver         Determina o driver do kernel do cpufreq usado *\n" + +#: utils/cpufreq-info.c:481 +#, c-format +msgid "  -p, --policy         Gets the currently used cpufreq policy *\n" +msgstr "" +"--p, --policy         Obtem a polÃtica do cpufreq em uso no momento *\n" + +#: utils/cpufreq-info.c:482 +#, c-format +msgid "  -g, --governors      Determines available cpufreq governors *\n" +msgstr "" +"  -g, --governors      Determina reguladores do cpufreq disponÃveis *\n" + +#: utils/cpufreq-info.c:483 +#, c-format +msgid "" +"  -r, --related-cpus   Determines which CPUs run at the same hardware " +"frequency *\n" +msgstr "" +"  -r, --related-cpus   Determina quais CPUs rodam na mesma frequência de " +"hardware *\n" + +#: utils/cpufreq-info.c:484 +#, c-format +msgid "" +"  -a, --affected-cpus  Determines which CPUs need to have their frequency\n" +"                       coordinated by software *\n" +msgstr "" +"  -a, --affected-cpus  Determina quais CPUs precisam ter suas frequências\n" +"                       coordenadas por software *\n" + +#: utils/cpufreq-info.c:486 +#, c-format +msgid "  -s, --stats          Shows cpufreq statistics if available\n" +msgstr "  -s, --stats          Mostra estatÃsticas do cpufreq se disponÃveis\n" + +#: utils/cpufreq-info.c:487 +#, c-format +msgid "" +"  -y, --latency        Determines the maximum latency on CPU frequency " +"changes *\n" +msgstr "" +"  -y, --latency        Determina a latência máxima nas trocas de frequência " +"do CPU *\n" + +#: utils/cpufreq-info.c:488 +#, c-format +msgid "  -b, --boost          Checks for turbo or boost modes  *\n" +msgstr "" + +#: utils/cpufreq-info.c:489 +#, c-format +msgid "" +"  -o, --proc           Prints out information like provided by the /proc/" +"cpufreq\n" +"                       interface in 2.4. and early 2.6. kernels\n" +msgstr "" +"  -o, --proc           Mostra informação do tipo provida pela interface /" +"proc/cpufreq\n" +"                       em kernels 2.4. e mais recentes 2.6\n" + +#: utils/cpufreq-info.c:491 +#, c-format +msgid "" +"  -m, --human          human-readable output for the -f, -w, -s and -y " +"parameters\n" +msgstr "" +"  -m, --human          saÃda legÃvel para humanos para os parâmetros -f, -w, " +"-s e -y\n" + +#: utils/cpufreq-info.c:492 utils/cpuidle-info.c:152 +#, c-format +msgid "  -h, --help           Prints out this screen\n" +msgstr " -h, --help           Imprime essa tela\n" + +#: utils/cpufreq-info.c:495 +#, c-format +msgid "" +"If no argument or only the -c, --cpu parameter is given, debug output about\n" +"cpufreq is printed which is useful e.g. for reporting bugs.\n" +msgstr "" +"Se nenhum argumento ou somente o parâmetro -c, --cpu é dado, informação de " +"debug sobre\n" +"o cpufreq é mostrada, o que é útil por exemplo para reportar bugs.\n" + +#: utils/cpufreq-info.c:497 +#, c-format +msgid "" +"For the arguments marked with *, omitting the -c or --cpu argument is\n" +"equivalent to setting it to zero\n" +msgstr "" +"Para os argumentos marcados com *, omitir o argumento -c ou --cpu é\n" +"equivalente a setá-lo como zero\n" + +#: utils/cpufreq-info.c:580 +#, c-format +msgid "" +"The argument passed to this tool can't be combined with passing a --cpu " +"argument\n" +msgstr "" +"O argumento usado pra essa ferramenta não pode ser combinado com um " +"argumento --cpu\n" + +#: utils/cpufreq-info.c:596 +#, c-format +msgid "" +"You can't specify more than one --cpu parameter and/or\n" +"more than one output-specific argument\n" +msgstr "" +"Você não pode especificar mais do que um parâmetro --cpu e/ou\n" +"mais do que um argumento de saÃda especÃfico\n" + +#: utils/cpufreq-info.c:600 utils/cpufreq-set.c:82 utils/cpupower-set.c:42 +#: utils/cpupower-info.c:42 utils/cpuidle-info.c:213 +#, c-format +msgid "invalid or unknown argument\n" +msgstr "argumento inválido ou desconhecido\n" + +#: utils/cpufreq-info.c:617 +#, c-format +msgid "couldn't analyze CPU %d as it doesn't seem to be present\n" +msgstr "" +"não foi possÃvel analisar o CPU % já que o mesmo parece não estar presente\n" + +#: utils/cpufreq-info.c:620 utils/cpupower-info.c:142 +#, c-format +msgid "analyzing CPU %d:\n" +msgstr "analisando o CPU %d:\n" + +#: utils/cpufreq-set.c:25 +#, fuzzy, c-format +msgid "Usage: cpupower frequency-set [options]\n" +msgstr "Uso: cpufreq-set [opções]\n" + +#: utils/cpufreq-set.c:27 +#, c-format +msgid "" +"  -d FREQ, --min FREQ      new minimum CPU frequency the governor may " +"select\n" +msgstr "" +"  -d FREQ, --min FREQ      nova frequência mÃnima do CPU que o regulador " +"deve selecionar\n" + +#: utils/cpufreq-set.c:28 +#, c-format +msgid "" +"  -u FREQ, --max FREQ      new maximum CPU frequency the governor may " +"select\n" +msgstr "" +"  -u FREQ, --max FREQ      nova frequência máxima do CPU que o regulador " +"deve escolher\n" + +#: utils/cpufreq-set.c:29 +#, c-format +msgid "  -g GOV, --governor GOV   new cpufreq governor\n" +msgstr "  -g GOV, --governor GOV   novo regulador do cpufreq\n" + +#: utils/cpufreq-set.c:30 +#, c-format +msgid "" +"  -f FREQ, --freq FREQ     specific frequency to be set. Requires userspace\n" +"                           governor to be available and loaded\n" +msgstr "" +"  -f FREQ, --freq FREQ     frequência especÃfica para ser setada. Necessita " +"que o regulador em\n" +"                           nÃvel de usuário esteja disponÃvel e carregado\n" + +#: utils/cpufreq-set.c:32 +#, c-format +msgid "  -r, --related            Switches all hardware-related CPUs\n" +msgstr "" +"  -r, --related            Modifica todos os CPUs relacionados ao hardware\n" + +#: utils/cpufreq-set.c:33 utils/cpupower-set.c:28 utils/cpupower-info.c:27 +#, c-format +msgid "  -h, --help               Prints out this screen\n" +msgstr " -h, --help           Mostra essa tela\n" + +#: utils/cpufreq-set.c:35 +#, fuzzy, c-format +msgid "" +"Notes:\n" +"1. Omitting the -c or --cpu argument is equivalent to setting it to \"all\"\n" +msgstr "" +"Para os argumentos marcados com *, omitir o argumento -c ou --cpu é\n" +"equivalente a setá-lo como zero\n" + +#: utils/cpufreq-set.c:37 +#, fuzzy, c-format +msgid "" +"2. The -f FREQ, --freq FREQ parameter cannot be combined with any other " +"parameter\n" +"   except the -c CPU, --cpu CPU parameter\n" +"3. FREQuencies can be passed in Hz, kHz (default), MHz, GHz, or THz\n" +"   by postfixing the value with the wanted unit name, without any space\n" +"   (FREQuency in kHz =^ Hz * 0.001 =^ MHz * 1000 =^ GHz * 1000000).\n" +msgstr "" +"Notas:\n" +"1. Omitir o argumento -c or --cpu é equivalente a setá-lo como zero\n" +"2. O parâmetro -f FREQ, --freq FREQ não pode ser combinado com qualquer " +"outro parâmetro\n" +"   exceto com o parâmetro -c CPU, --cpu CPU\n" +"3. FREQuências podem ser usadas em Hz, kHz (padrão), MHz, GHz, o THz\n" +"   colocando o nome desejado da unidade após o valor, sem qualquer espaço\n" +"   (FREQuência em kHz =^ Hz * 0.001 =^ MHz * 1000 =^ GHz * 1000000).\n" + +#: utils/cpufreq-set.c:57 +#, c-format +msgid "" +"Error setting new values. Common errors:\n" +"- Do you have proper administration rights? (super-user?)\n" +"- Is the governor you requested available and modprobed?\n" +"- Trying to set an invalid policy?\n" +"- Trying to set a specific frequency, but userspace governor is not " +"available,\n" +"   for example because of hardware which cannot be set to a specific " +"frequency\n" +"   or because the userspace governor isn't loaded?\n" +msgstr "" +"Erro ao setar novos valores. Erros comuns:\n" +"- Você tem direitos administrativos necessários? (super-usuário?)\n" +"- O regulador que você requesitou está disponÃvel e foi \"modprobed\"?\n" +"- Tentando setar uma polÃtica inválida?\n" +"- Tentando setar uma frequência especÃfica, mas o regulador em nÃvel de " +"usuário não está disponÃvel,\n" +"   por exemplo devido ao hardware que não pode ser setado pra uma frequência " +"especÃfica\n" +"   ou porque o regulador em nÃvel de usuário não foi carregado?\n" + +#: utils/cpufreq-set.c:170 +#, c-format +msgid "wrong, unknown or unhandled CPU?\n" +msgstr "CPU errado, desconhecido ou inesperado?\n" + +#: utils/cpufreq-set.c:302 +#, c-format +msgid "" +"the -f/--freq parameter cannot be combined with -d/--min, -u/--max or\n" +"-g/--governor parameters\n" +msgstr "" +"o parâmetro -f/--freq não pode ser combinado com os parâmetros -d/--min, -" +"u/--max ou\n" +"-g/--governor\n" + +#: utils/cpufreq-set.c:308 +#, c-format +msgid "" +"At least one parameter out of -f/--freq, -d/--min, -u/--max, and\n" +"-g/--governor must be passed\n" +msgstr "" +"Pelo menos um parâmetro entre -f/--freq, -d/--min, -u/--max, e\n" +"-g/--governor deve ser usado\n" + +#: utils/cpufreq-set.c:347 +#, c-format +msgid "Setting cpu: %d\n" +msgstr "" + +#: utils/cpupower-set.c:22 +#, c-format +msgid "Usage: cpupower set [ -b val ] [ -m val ] [ -s val ]\n" +msgstr "" + +#: utils/cpupower-set.c:24 +#, c-format +msgid "" +"  -b, --perf-bias [VAL]    Sets CPU's power vs performance policy on some\n" +"                           Intel models [0-15], see manpage for details\n" +msgstr "" + +#: utils/cpupower-set.c:26 +#, c-format +msgid "" +"  -m, --sched-mc  [VAL]    Sets the kernel's multi core scheduler policy.\n" +msgstr "" + +#: utils/cpupower-set.c:27 +#, c-format +msgid "" +"  -s, --sched-smt [VAL]    Sets the kernel's thread sibling scheduler " +"policy.\n" +msgstr "" + +#: utils/cpupower-set.c:80 +#, c-format +msgid "--perf-bias param out of range [0-%d]\n" +msgstr "" + +#: utils/cpupower-set.c:91 +#, c-format +msgid "--sched-mc param out of range [0-%d]\n" +msgstr "" + +#: utils/cpupower-set.c:102 +#, c-format +msgid "--sched-smt param out of range [0-%d]\n" +msgstr "" + +#: utils/cpupower-set.c:121 +#, c-format +msgid "Error setting sched-mc %s\n" +msgstr "" + +#: utils/cpupower-set.c:127 +#, c-format +msgid "Error setting sched-smt %s\n" +msgstr "" + +#: utils/cpupower-set.c:146 +#, c-format +msgid "Error setting perf-bias value on CPU %d\n" +msgstr "" + +#: utils/cpupower-info.c:21 +#, c-format +msgid "Usage: cpupower info [ -b ] [ -m ] [ -s ]\n" +msgstr "" + +#: utils/cpupower-info.c:23 +#, c-format +msgid "" +"  -b, --perf-bias    Gets CPU's power vs performance policy on some\n" +"                           Intel models [0-15], see manpage for details\n" +msgstr "" + +#: utils/cpupower-info.c:25 +#, fuzzy, c-format +msgid "  -m, --sched-mc     Gets the kernel's multi core scheduler policy.\n" +msgstr "" +"--p, --policy         Obtem a polÃtica do cpufreq em uso no momento *\n" + +#: utils/cpupower-info.c:26 +#, c-format +msgid "" +"  -s, --sched-smt    Gets the kernel's thread sibling scheduler policy.\n" +msgstr "" + +#: utils/cpupower-info.c:28 +#, c-format +msgid "" +"\n" +"Passing no option will show all info, by default only on core 0\n" +msgstr "" + +#: utils/cpupower-info.c:102 +#, c-format +msgid "System's multi core scheduler setting: " +msgstr "" + +#. if sysfs file is missing it's: errno == ENOENT +#: utils/cpupower-info.c:105 utils/cpupower-info.c:114 +#, c-format +msgid "not supported\n" +msgstr "" + +#: utils/cpupower-info.c:111 +#, c-format +msgid "System's thread sibling scheduler setting: " +msgstr "" + +#: utils/cpupower-info.c:126 +#, c-format +msgid "Intel's performance bias setting needs root privileges\n" +msgstr "" + +#: utils/cpupower-info.c:128 +#, c-format +msgid "System does not support Intel's performance bias setting\n" +msgstr "" + +#: utils/cpupower-info.c:147 +#, c-format +msgid "Could not read perf-bias value\n" +msgstr "" + +#: utils/cpupower-info.c:150 +#, c-format +msgid "perf-bias: %d\n" +msgstr "" + +#: utils/cpuidle-info.c:28 +#, fuzzy, c-format +msgid "Analyzing CPU %d:\n" +msgstr "analisando o CPU %d:\n" + +#: utils/cpuidle-info.c:32 +#, c-format +msgid "CPU %u: No idle states\n" +msgstr "" + +#: utils/cpuidle-info.c:36 +#, c-format +msgid "CPU %u: Can't read idle state info\n" +msgstr "" + +#: utils/cpuidle-info.c:41 +#, c-format +msgid "Could not determine max idle state %u\n" +msgstr "" + +#: utils/cpuidle-info.c:46 +#, c-format +msgid "Number of idle states: %d\n" +msgstr "" + +#: utils/cpuidle-info.c:48 +#, fuzzy, c-format +msgid "Available idle states:" +msgstr "  nÃveis de frequência disponÃveis: " + +#: utils/cpuidle-info.c:71 +#, c-format +msgid "Flags/Description: %s\n" +msgstr "" + +#: utils/cpuidle-info.c:74 +#, c-format +msgid "Latency: %lu\n" +msgstr "" + +#: utils/cpuidle-info.c:76 +#, c-format +msgid "Usage: %lu\n" +msgstr "" + +#: utils/cpuidle-info.c:78 +#, c-format +msgid "Duration: %llu\n" +msgstr "" + +#: utils/cpuidle-info.c:90 +#, c-format +msgid "Could not determine cpuidle driver\n" +msgstr "" + +#: utils/cpuidle-info.c:94 +#, fuzzy, c-format +msgid "CPUidle driver: %s\n" +msgstr "  driver: %s\n" + +#: utils/cpuidle-info.c:99 +#, c-format +msgid "Could not determine cpuidle governor\n" +msgstr "" + +#: utils/cpuidle-info.c:103 +#, c-format +msgid "CPUidle governor: %s\n" +msgstr "" + +#: utils/cpuidle-info.c:122 +#, c-format +msgid "CPU %u: Can't read C-state info\n" +msgstr "" + +#. printf("Cstates: %d\n", cstates); +#: utils/cpuidle-info.c:127 +#, c-format +msgid "active state:            C0\n" +msgstr "" + +#: utils/cpuidle-info.c:128 +#, c-format +msgid "max_cstate:              C%u\n" +msgstr "" + +#: utils/cpuidle-info.c:129 +#, fuzzy, c-format +msgid "maximum allowed latency: %lu usec\n" +msgstr "  maior latência de transição: " + +#: utils/cpuidle-info.c:130 +#, c-format +msgid "states:\t\n" +msgstr "" + +#: utils/cpuidle-info.c:132 +#, c-format +msgid "    C%d:                  type[C%d] " +msgstr "" + +#: utils/cpuidle-info.c:134 +#, c-format +msgid "promotion[--] demotion[--] " +msgstr "" + +#: utils/cpuidle-info.c:135 +#, c-format +msgid "latency[%03lu] " +msgstr "" + +#: utils/cpuidle-info.c:137 +#, c-format +msgid "usage[%08lu] " +msgstr "" + +#: utils/cpuidle-info.c:139 +#, c-format +msgid "duration[%020Lu] \n" +msgstr "" + +#: utils/cpuidle-info.c:147 +#, fuzzy, c-format +msgid "Usage: cpupower idleinfo [options]\n" +msgstr "Uso: cpufreq-info [opções]\n" + +#: utils/cpuidle-info.c:149 +#, fuzzy, c-format +msgid "  -s, --silent         Only show general C-state information\n" +msgstr "  -e, --debug          Mostra informação de debug\n" + +#: utils/cpuidle-info.c:150 +#, fuzzy, c-format +msgid "" +"  -o, --proc           Prints out information like provided by the /proc/" +"acpi/processor/*/power\n" +"                       interface in older kernels\n" +msgstr "" +"  -o, --proc           Mostra informação do tipo provida pela interface /" +"proc/cpufreq\n" +"                       em kernels 2.4. e mais recentes 2.6\n" + +#: utils/cpuidle-info.c:209 +#, fuzzy, c-format +msgid "You can't specify more than one output-specific argument\n" +msgstr "" +"Você não pode especificar mais do que um parâmetro --cpu e/ou\n" +"mais do que um argumento de saÃda especÃfico\n" + +#~ msgid "" +#~ "  -c CPU, --cpu CPU    CPU number which information shall be determined " +#~ "about\n" +#~ msgstr "" +#~ "  -c CPU, --cpu CPU    número do CPU sobre o qual as inforções devem ser " +#~ "determinadas\n" + +#~ msgid "" +#~ "  -c CPU, --cpu CPU        number of CPU where cpufreq settings shall be " +#~ "modified\n" +#~ msgstr "" +#~ "  -c CPU, --cpu CPU        número do CPU onde as configurações do cpufreq " +#~ "vão ser modificadas\n" diff --git a/tools/power/cpupower/utils/builtin.h b/tools/power/cpupower/utils/builtin.h new file mode 100644 index 00000000000..2284c8ea4e2 --- /dev/null +++ b/tools/power/cpupower/utils/builtin.h @@ -0,0 +1,12 @@ +#ifndef BUILTIN_H +#define BUILTIN_H + +extern int cmd_set(int argc, const char **argv); +extern int cmd_info(int argc, const char **argv); +extern int cmd_freq_set(int argc, const char **argv); +extern int cmd_freq_info(int argc, const char **argv); +extern int cmd_idle_set(int argc, const char **argv); +extern int cmd_idle_info(int argc, const char **argv); +extern int cmd_monitor(int argc, const char **argv); + +#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..b4b90a97662 --- /dev/null +++ b/tools/power/cpupower/utils/cpufreq-info.c @@ -0,0 +1,698 @@ +/* + *  (C) 2004-2009  Dominik Brodowski <linux@dominikbrodowski.de> + * + *  Licensed under the terms of the GNU GPL License version 2. + */ + + +#include <unistd.h> +#include <stdio.h> +#include <errno.h> +#include <stdlib.h> +#include <string.h> + +#include <getopt.h> + +#include "cpufreq.h" +#include "helpers/helpers.h" +#include "helpers/bitmask.h" + +#define LINE_LEN 10 + +static unsigned int count_cpus(void) +{ +	FILE *fp; +	char value[LINE_LEN]; +	unsigned int ret = 0; +	unsigned int cpunr = 0; + +	fp = fopen("/proc/stat", "r"); +	if (!fp) { +		printf(_("Couldn't count the number of CPUs (%s: %s), assuming 1\n"), "/proc/stat", strerror(errno)); +		return 1; +	} + +	while (!feof(fp)) { +		if (!fgets(value, LINE_LEN, fp)) +			continue; +		value[LINE_LEN - 1] = '\0'; +		if (strlen(value) < (LINE_LEN - 2)) +			continue; +		if (strstr(value, "cpu ")) +			continue; +		if (sscanf(value, "cpu%d ", &cpunr) != 1) +			continue; +		if (cpunr > ret) +			ret = cpunr; +	} +	fclose(fp); + +	/* cpu count starts from 0, on error return 1 (UP) */ +	return ret + 1; +} + + +static void proc_cpufreq_output(void) +{ +	unsigned int cpu, nr_cpus; +	struct cpufreq_policy *policy; +	unsigned int min_pctg = 0; +	unsigned int max_pctg = 0; +	unsigned long min, max; + +	printf(_("          minimum CPU frequency  -  maximum CPU frequency  -  governor\n")); + +	nr_cpus = count_cpus(); +	for (cpu = 0; cpu < nr_cpus; cpu++) { +		policy = cpufreq_get_policy(cpu); +		if (!policy) +			continue; + +		if (cpufreq_get_hardware_limits(cpu, &min, &max)) { +			max = 0; +		} else { +			min_pctg = (policy->min * 100) / max; +			max_pctg = (policy->max * 100) / max; +		} +		printf("CPU%3d    %9lu kHz (%3d %%)  -  %9lu kHz (%3d %%)  -  %s\n", +			cpu , policy->min, max ? min_pctg : 0, policy->max, +			max ? max_pctg : 0, policy->governor); + +		cpufreq_put_policy(policy); +	} +} + +static int no_rounding; +static void print_speed(unsigned long speed) +{ +	unsigned long tmp; + +	if (no_rounding) { +		if (speed > 1000000) +			printf("%u.%06u GHz", ((unsigned int) speed/1000000), +				((unsigned int) speed%1000000)); +		else if (speed > 100000) +			printf("%u MHz", (unsigned int) speed); +		else if (speed > 1000) +			printf("%u.%03u MHz", ((unsigned int) speed/1000), +				(unsigned int) (speed%1000)); +		else +			printf("%lu kHz", speed); +	} else { +		if (speed > 1000000) { +			tmp = speed%10000; +			if (tmp >= 5000) +				speed += 10000; +			printf("%u.%02u GHz", ((unsigned int) speed/1000000), +				((unsigned int) (speed%1000000)/10000)); +		} else if (speed > 100000) { +			tmp = speed%1000; +			if (tmp >= 500) +				speed += 1000; +			printf("%u MHz", ((unsigned int) speed/1000)); +		} else if (speed > 1000) { +			tmp = speed%100; +			if (tmp >= 50) +				speed += 100; +			printf("%u.%01u MHz", ((unsigned int) speed/1000), +				((unsigned int) (speed%1000)/100)); +		} +	} + +	return; +} + +static void print_duration(unsigned long duration) +{ +	unsigned long tmp; + +	if (no_rounding) { +		if (duration > 1000000) +			printf("%u.%06u ms", ((unsigned int) duration/1000000), +				((unsigned int) duration%1000000)); +		else if (duration > 100000) +			printf("%u us", ((unsigned int) duration/1000)); +		else if (duration > 1000) +			printf("%u.%03u us", ((unsigned int) duration/1000), +				((unsigned int) duration%1000)); +		else +			printf("%lu ns", duration); +	} else { +		if (duration > 1000000) { +			tmp = duration%10000; +			if (tmp >= 5000) +				duration += 10000; +			printf("%u.%02u ms", ((unsigned int) duration/1000000), +				((unsigned int) (duration%1000000)/10000)); +		} else if (duration > 100000) { +			tmp = duration%1000; +			if (tmp >= 500) +				duration += 1000; +			printf("%u us", ((unsigned int) duration / 1000)); +		} else if (duration > 1000) { +			tmp = duration%100; +			if (tmp >= 50) +				duration += 100; +			printf("%u.%01u us", ((unsigned int) duration/1000), +				((unsigned int) (duration%1000)/100)); +		} else +			printf("%lu ns", duration); +	} +	return; +} + +/* --boost / -b */ + +static int get_boost_mode(unsigned int cpu) +{ +	int support, active, b_states = 0, ret, pstate_no, i; +	/* ToDo: Make this more global */ +	unsigned long pstates[MAX_HW_PSTATES] = {0,}; + +	if (cpupower_cpu_info.vendor != X86_VENDOR_AMD && +	    cpupower_cpu_info.vendor != X86_VENDOR_INTEL) +		return 0; + +	ret = cpufreq_has_boost_support(cpu, &support, &active, &b_states); +	if (ret) { +		printf(_("Error while evaluating Boost Capabilities" +				" on CPU %d -- are you root?\n"), cpu); +		return ret; +	} +	/* P state changes via MSR are identified via cpuid 80000007 +	   on Intel and AMD, but we assume boost capable machines can do that +	   if (cpuid_eax(0x80000000) >= 0x80000007 +	   && (cpuid_edx(0x80000007) & (1 << 7))) +	*/ + +	printf(_("  boost state support:\n")); + +	printf(_("    Supported: %s\n"), support ? _("yes") : _("no")); +	printf(_("    Active: %s\n"), active ? _("yes") : _("no")); + +	if (cpupower_cpu_info.vendor == X86_VENDOR_AMD && +	    cpupower_cpu_info.family >= 0x10) { +		ret = decode_pstates(cpu, cpupower_cpu_info.family, b_states, +				     pstates, &pstate_no); +		if (ret) +			return ret; + +		printf(_("    Boost States: %d\n"), b_states); +		printf(_("    Total States: %d\n"), pstate_no); +		for (i = 0; i < pstate_no; i++) { +			if (i < b_states) +				printf(_("    Pstate-Pb%d: %luMHz (boost state)" +					 "\n"), i, pstates[i]); +			else +				printf(_("    Pstate-P%d:  %luMHz\n"), +				       i - b_states, pstates[i]); +		} +	} else if (cpupower_cpu_info.caps & CPUPOWER_CAP_HAS_TURBO_RATIO) { +		double bclk; +		unsigned long long intel_turbo_ratio = 0; +		unsigned int ratio; + +		/* Any way to autodetect this ? */ +		if (cpupower_cpu_info.caps & CPUPOWER_CAP_IS_SNB) +			bclk = 100.00; +		else +			bclk = 133.33; +		intel_turbo_ratio = msr_intel_get_turbo_ratio(cpu); +		dprint ("    Ratio: 0x%llx - bclk: %f\n", +			intel_turbo_ratio, bclk); + +		ratio = (intel_turbo_ratio >> 24) & 0xFF; +		if (ratio) +			printf(_("    %.0f MHz max turbo 4 active cores\n"), +			       ratio * bclk); + +		ratio = (intel_turbo_ratio >> 16) & 0xFF; +		if (ratio) +			printf(_("    %.0f MHz max turbo 3 active cores\n"), +			       ratio * bclk); + +		ratio = (intel_turbo_ratio >> 8) & 0xFF; +		if (ratio) +			printf(_("    %.0f MHz max turbo 2 active cores\n"), +			       ratio * bclk); + +		ratio = (intel_turbo_ratio >> 0) & 0xFF; +		if (ratio) +			printf(_("    %.0f MHz max turbo 1 active cores\n"), +			       ratio * bclk); +	} +	return 0; +} + +static void debug_output_one(unsigned int cpu) +{ +	char *driver; +	struct cpufreq_affected_cpus *cpus; +	struct cpufreq_available_frequencies *freqs; +	unsigned long min, max, freq_kernel, freq_hardware; +	unsigned long total_trans, latency; +	unsigned long long total_time; +	struct cpufreq_policy *policy; +	struct cpufreq_available_governors *governors; +	struct cpufreq_stats *stats; + +	if (cpufreq_cpu_exists(cpu)) +		return; + +	freq_kernel = cpufreq_get_freq_kernel(cpu); +	freq_hardware = cpufreq_get_freq_hardware(cpu); + +	driver = cpufreq_get_driver(cpu); +	if (!driver) { +		printf(_("  no or unknown cpufreq driver is active on this CPU\n")); +	} else { +		printf(_("  driver: %s\n"), driver); +		cpufreq_put_driver(driver); +	} + +	cpus = cpufreq_get_related_cpus(cpu); +	if (cpus) { +		printf(_("  CPUs which run at the same hardware frequency: ")); +		while (cpus->next) { +			printf("%d ", cpus->cpu); +			cpus = cpus->next; +		} +		printf("%d\n", cpus->cpu); +		cpufreq_put_related_cpus(cpus); +	} + +	cpus = cpufreq_get_affected_cpus(cpu); +	if (cpus) { +		printf(_("  CPUs which need to have their frequency coordinated by software: ")); +		while (cpus->next) { +			printf("%d ", cpus->cpu); +			cpus = cpus->next; +		} +		printf("%d\n", cpus->cpu); +		cpufreq_put_affected_cpus(cpus); +	} + +	latency = cpufreq_get_transition_latency(cpu); +	if (latency) { +		printf(_("  maximum transition latency: ")); +		print_duration(latency); +		printf(".\n"); +	} + +	if (!(cpufreq_get_hardware_limits(cpu, &min, &max))) { +		printf(_("  hardware limits: ")); +		print_speed(min); +		printf(" - "); +		print_speed(max); +		printf("\n"); +	} + +	freqs = cpufreq_get_available_frequencies(cpu); +	if (freqs) { +		printf(_("  available frequency steps: ")); +		while (freqs->next) { +			print_speed(freqs->frequency); +			printf(", "); +			freqs = freqs->next; +		} +		print_speed(freqs->frequency); +		printf("\n"); +		cpufreq_put_available_frequencies(freqs); +	} + +	governors = cpufreq_get_available_governors(cpu); +	if (governors) { +		printf(_("  available cpufreq governors: ")); +		while (governors->next) { +			printf("%s, ", governors->governor); +			governors = governors->next; +		} +		printf("%s\n", governors->governor); +		cpufreq_put_available_governors(governors); +	} + +	policy = cpufreq_get_policy(cpu); +	if (policy) { +		printf(_("  current policy: frequency should be within ")); +		print_speed(policy->min); +		printf(_(" and ")); +		print_speed(policy->max); + +		printf(".\n                  "); +		printf(_("The governor \"%s\" may" +		       " decide which speed to use\n                  within this range.\n"), +		       policy->governor); +		cpufreq_put_policy(policy); +	} + +	if (freq_kernel || freq_hardware) { +		printf(_("  current CPU frequency is ")); +		if (freq_hardware) { +			print_speed(freq_hardware); +			printf(_(" (asserted by call to hardware)")); +		} else +			print_speed(freq_kernel); +		printf(".\n"); +	} +	stats = cpufreq_get_stats(cpu, &total_time); +	if (stats) { +		printf(_("  cpufreq stats: ")); +		while (stats) { +			print_speed(stats->frequency); +			printf(":%.2f%%", (100.0 * stats->time_in_state) / total_time); +			stats = stats->next; +			if (stats) +				printf(", "); +		} +		cpufreq_put_stats(stats); +		total_trans = cpufreq_get_transitions(cpu); +		if (total_trans) +			printf("  (%lu)\n", total_trans); +		else +			printf("\n"); +	} +	get_boost_mode(cpu); + +} + +/* --freq / -f */ + +static int get_freq_kernel(unsigned int cpu, unsigned int human) +{ +	unsigned long freq = cpufreq_get_freq_kernel(cpu); +	if (!freq) +		return -EINVAL; +	if (human) { +		print_speed(freq); +		printf("\n"); +	} else +		printf("%lu\n", freq); +	return 0; +} + + +/* --hwfreq / -w */ + +static int get_freq_hardware(unsigned int cpu, unsigned int human) +{ +	unsigned long freq = cpufreq_get_freq_hardware(cpu); +	if (!freq) +		return -EINVAL; +	if (human) { +		print_speed(freq); +		printf("\n"); +	} else +		printf("%lu\n", freq); +	return 0; +} + +/* --hwlimits / -l */ + +static int get_hardware_limits(unsigned int cpu) +{ +	unsigned long min, max; +	if (cpufreq_get_hardware_limits(cpu, &min, &max)) +		return -EINVAL; +	printf("%lu %lu\n", min, max); +	return 0; +} + +/* --driver / -d */ + +static int get_driver(unsigned int cpu) +{ +	char *driver = cpufreq_get_driver(cpu); +	if (!driver) +		return -EINVAL; +	printf("%s\n", driver); +	cpufreq_put_driver(driver); +	return 0; +} + +/* --policy / -p */ + +static int get_policy(unsigned int cpu) +{ +	struct cpufreq_policy *policy = cpufreq_get_policy(cpu); +	if (!policy) +		return -EINVAL; +	printf("%lu %lu %s\n", policy->min, policy->max, policy->governor); +	cpufreq_put_policy(policy); +	return 0; +} + +/* --governors / -g */ + +static int get_available_governors(unsigned int cpu) +{ +	struct cpufreq_available_governors *governors = +		cpufreq_get_available_governors(cpu); +	if (!governors) +		return -EINVAL; + +	while (governors->next) { +		printf("%s ", governors->governor); +		governors = governors->next; +	} +	printf("%s\n", governors->governor); +	cpufreq_put_available_governors(governors); +	return 0; +} + + +/* --affected-cpus  / -a */ + +static int get_affected_cpus(unsigned int cpu) +{ +	struct cpufreq_affected_cpus *cpus = cpufreq_get_affected_cpus(cpu); +	if (!cpus) +		return -EINVAL; + +	while (cpus->next) { +		printf("%d ", cpus->cpu); +		cpus = cpus->next; +	} +	printf("%d\n", cpus->cpu); +	cpufreq_put_affected_cpus(cpus); +	return 0; +} + +/* --related-cpus  / -r */ + +static int get_related_cpus(unsigned int cpu) +{ +	struct cpufreq_affected_cpus *cpus = cpufreq_get_related_cpus(cpu); +	if (!cpus) +		return -EINVAL; + +	while (cpus->next) { +		printf("%d ", cpus->cpu); +		cpus = cpus->next; +	} +	printf("%d\n", cpus->cpu); +	cpufreq_put_related_cpus(cpus); +	return 0; +} + +/* --stats / -s */ + +static int get_freq_stats(unsigned int cpu, unsigned int human) +{ +	unsigned long total_trans = cpufreq_get_transitions(cpu); +	unsigned long long total_time; +	struct cpufreq_stats *stats = cpufreq_get_stats(cpu, &total_time); +	while (stats) { +		if (human) { +			print_speed(stats->frequency); +			printf(":%.2f%%", +				(100.0 * stats->time_in_state) / total_time); +		} else +			printf("%lu:%llu", +				stats->frequency, stats->time_in_state); +		stats = stats->next; +		if (stats) +			printf(", "); +	} +	cpufreq_put_stats(stats); +	if (total_trans) +		printf("  (%lu)\n", total_trans); +	return 0; +} + +/* --latency / -y */ + +static int get_latency(unsigned int cpu, unsigned int human) +{ +	unsigned long latency = cpufreq_get_transition_latency(cpu); +	if (!latency) +		return -EINVAL; + +	if (human) { +		print_duration(latency); +		printf("\n"); +	} else +		printf("%lu\n", latency); +	return 0; +} + +static struct option info_opts[] = { +	{ .name = "debug",	.has_arg = no_argument,		.flag = NULL,	.val = 'e'}, +	{ .name = "boost",	.has_arg = no_argument,		.flag = NULL,	.val = 'b'}, +	{ .name = "freq",	.has_arg = no_argument,		.flag = NULL,	.val = 'f'}, +	{ .name = "hwfreq",	.has_arg = no_argument,		.flag = NULL,	.val = 'w'}, +	{ .name = "hwlimits",	.has_arg = no_argument,		.flag = NULL,	.val = 'l'}, +	{ .name = "driver",	.has_arg = no_argument,		.flag = NULL,	.val = 'd'}, +	{ .name = "policy",	.has_arg = no_argument,		.flag = NULL,	.val = 'p'}, +	{ .name = "governors",	.has_arg = no_argument,		.flag = NULL,	.val = 'g'}, +	{ .name = "related-cpus", .has_arg = no_argument,	.flag = NULL,	.val = 'r'}, +	{ .name = "affected-cpus",.has_arg = no_argument,	.flag = NULL,	.val = 'a'}, +	{ .name = "stats",	.has_arg = no_argument,		.flag = NULL,	.val = 's'}, +	{ .name = "latency",	.has_arg = no_argument,		.flag = NULL,	.val = 'y'}, +	{ .name = "proc",	.has_arg = no_argument,		.flag = NULL,	.val = 'o'}, +	{ .name = "human",	.has_arg = no_argument,		.flag = NULL,	.val = 'm'}, +	{ .name = "no-rounding", .has_arg = no_argument,	.flag = NULL,	.val = 'n'}, +	{ }, +}; + +int cmd_freq_info(int argc, char **argv) +{ +	extern char *optarg; +	extern int optind, opterr, optopt; +	int ret = 0, cont = 1; +	unsigned int cpu = 0; +	unsigned int human = 0; +	int output_param = 0; + +	do { +		ret = getopt_long(argc, argv, "oefwldpgrasmybn", info_opts, +				  NULL); +		switch (ret) { +		case '?': +			output_param = '?'; +			cont = 0; +			break; +		case -1: +			cont = 0; +			break; +		case 'b': +		case 'o': +		case 'a': +		case 'r': +		case 'g': +		case 'p': +		case 'd': +		case 'l': +		case 'w': +		case 'f': +		case 'e': +		case 's': +		case 'y': +			if (output_param) { +				output_param = -1; +				cont = 0; +				break; +			} +			output_param = ret; +			break; +		case 'm': +			if (human) { +				output_param = -1; +				cont = 0; +				break; +			} +			human = 1; +			break; +		case 'n': +			no_rounding = 1; +			break; +		default: +			fprintf(stderr, "invalid or unknown argument\n"); +			return EXIT_FAILURE; +		} +	} while (cont); + +	switch (output_param) { +	case 'o': +		if (!bitmask_isallclear(cpus_chosen)) { +			printf(_("The argument passed to this tool can't be " +				 "combined with passing a --cpu argument\n")); +			return -EINVAL; +		} +		break; +	case 0: +		output_param = 'e'; +	} + +	ret = 0; + +	/* Default is: show output of CPU 0 only */ +	if (bitmask_isallclear(cpus_chosen)) +		bitmask_setbit(cpus_chosen, 0); + +	switch (output_param) { +	case -1: +		printf(_("You can't specify more than one --cpu parameter and/or\n" +		       "more than one output-specific argument\n")); +		return -EINVAL; +	case '?': +		printf(_("invalid or unknown argument\n")); +		return -EINVAL; +	case 'o': +		proc_cpufreq_output(); +		return EXIT_SUCCESS; +	} + +	for (cpu = bitmask_first(cpus_chosen); +	     cpu <= bitmask_last(cpus_chosen); cpu++) { + +		if (!bitmask_isbitset(cpus_chosen, cpu)) +			continue; +		if (cpufreq_cpu_exists(cpu)) { +			printf(_("couldn't analyze CPU %d as it doesn't seem to be present\n"), cpu); +			continue; +		} +		printf(_("analyzing CPU %d:\n"), cpu); + +		switch (output_param) { +		case 'b': +			get_boost_mode(cpu); +			break; +		case 'e': +			debug_output_one(cpu); +			break; +		case 'a': +			ret = get_affected_cpus(cpu); +			break; +		case 'r': +			ret = get_related_cpus(cpu); +			break; +		case 'g': +			ret = get_available_governors(cpu); +			break; +		case 'p': +			ret = get_policy(cpu); +			break; +		case 'd': +			ret = get_driver(cpu); +			break; +		case 'l': +			ret = get_hardware_limits(cpu); +			break; +		case 'w': +			ret = get_freq_hardware(cpu, human); +			break; +		case 'f': +			ret = get_freq_kernel(cpu, human); +			break; +		case 's': +			ret = get_freq_stats(cpu, human); +			break; +		case 'y': +			ret = get_latency(cpu, human); +			break; +		} +		if (ret) +			return ret; +	} +	return ret; +} diff --git a/tools/power/cpupower/utils/cpufreq-set.c b/tools/power/cpupower/utils/cpufreq-set.c new file mode 100644 index 00000000000..a416de80c55 --- /dev/null +++ b/tools/power/cpupower/utils/cpufreq-set.c @@ -0,0 +1,331 @@ +/* + *  (C) 2004-2009  Dominik Brodowski <linux@dominikbrodowski.de> + * + *  Licensed under the terms of the GNU GPL License version 2. + */ + + +#include <unistd.h> +#include <stdio.h> +#include <errno.h> +#include <stdlib.h> +#include <limits.h> +#include <string.h> +#include <ctype.h> + +#include <getopt.h> + +#include "cpufreq.h" +#include "helpers/helpers.h" + +#define NORM_FREQ_LEN 32 + +static struct option set_opts[] = { +	{ .name = "min",	.has_arg = required_argument,	.flag = NULL,	.val = 'd'}, +	{ .name = "max",	.has_arg = required_argument,	.flag = NULL,	.val = 'u'}, +	{ .name = "governor",	.has_arg = required_argument,	.flag = NULL,	.val = 'g'}, +	{ .name = "freq",	.has_arg = required_argument,	.flag = NULL,	.val = 'f'}, +	{ .name = "related",	.has_arg = no_argument,		.flag = NULL,	.val='r'}, +	{ }, +}; + +static void print_error(void) +{ +	printf(_("Error setting new values. Common errors:\n" +			"- Do you have proper administration rights? (super-user?)\n" +			"- Is the governor you requested available and modprobed?\n" +			"- Trying to set an invalid policy?\n" +			"- Trying to set a specific frequency, but userspace governor is not available,\n" +			"   for example because of hardware which cannot be set to a specific frequency\n" +			"   or because the userspace governor isn't loaded?\n")); +}; + +struct freq_units { +	char		*str_unit; +	int		power_of_ten; +}; + +const struct freq_units def_units[] = { +	{"hz", -3}, +	{"khz", 0}, /* default */ +	{"mhz", 3}, +	{"ghz", 6}, +	{"thz", 9}, +	{NULL, 0} +}; + +static void print_unknown_arg(void) +{ +	printf(_("invalid or unknown argument\n")); +} + +static unsigned long string_to_frequency(const char *str) +{ +	char normalized[NORM_FREQ_LEN]; +	const struct freq_units *unit; +	const char *scan; +	char *end; +	unsigned long freq; +	int power = 0, match_count = 0, i, cp, pad; + +	while (*str == '0') +		str++; + +	for (scan = str; isdigit(*scan) || *scan == '.'; scan++) { +		if (*scan == '.' && match_count == 0) +			match_count = 1; +		else if (*scan == '.' && match_count == 1) +			return 0; +	} + +	if (*scan) { +		match_count = 0; +		for (unit = def_units; unit->str_unit; unit++) { +			for (i = 0; +			     scan[i] && tolower(scan[i]) == unit->str_unit[i]; +			     ++i) +				continue; +			if (scan[i]) +				continue; +			match_count++; +			power = unit->power_of_ten; +		} +		if (match_count != 1) +			return 0; +	} + +	/* count the number of digits to be copied */ +	for (cp = 0; isdigit(str[cp]); cp++) +		continue; + +	if (str[cp] == '.') { +		while (power > -1 && isdigit(str[cp+1])) +			cp++, power--; +	} +	if (power >= -1)	/* not enough => pad */ +		pad = power + 1; +	else			/* to much => strip */ +		pad = 0, cp += power + 1; +	/* check bounds */ +	if (cp <= 0 || cp + pad > NORM_FREQ_LEN - 1) +		return 0; + +	/* copy digits */ +	for (i = 0; i < cp; i++, str++) { +		if (*str == '.') +			str++; +		normalized[i] = *str; +	} +	/* and pad */ +	for (; i < cp + pad; i++) +		normalized[i] = '0'; + +	/* round up, down ? */ +	match_count = (normalized[i-1] >= '5'); +	/* and drop the decimal part */ +	normalized[i-1] = 0; /* cp > 0 && pad >= 0 ==> i > 0 */ + +	/* final conversion (and applying rounding) */ +	errno = 0; +	freq = strtoul(normalized, &end, 10); +	if (errno) +		return 0; +	else { +		if (match_count && freq != ULONG_MAX) +			freq++; +		return freq; +	} +} + +static int do_new_policy(unsigned int cpu, struct cpufreq_policy *new_pol) +{ +	struct cpufreq_policy *cur_pol = cpufreq_get_policy(cpu); +	int ret; + +	if (!cur_pol) { +		printf(_("wrong, unknown or unhandled CPU?\n")); +		return -EINVAL; +	} + +	if (!new_pol->min) +		new_pol->min = cur_pol->min; + +	if (!new_pol->max) +		new_pol->max = cur_pol->max; + +	if (!new_pol->governor) +		new_pol->governor = cur_pol->governor; + +	ret = cpufreq_set_policy(cpu, new_pol); + +	cpufreq_put_policy(cur_pol); + +	return ret; +} + + +static int do_one_cpu(unsigned int cpu, struct cpufreq_policy *new_pol, +		unsigned long freq, unsigned int pc) +{ +	switch (pc) { +	case 0: +		return cpufreq_set_frequency(cpu, freq); + +	case 1: +		/* if only one value of a policy is to be changed, we can +		 * use a "fast path". +		 */ +		if (new_pol->min) +			return cpufreq_modify_policy_min(cpu, new_pol->min); +		else if (new_pol->max) +			return cpufreq_modify_policy_max(cpu, new_pol->max); +		else if (new_pol->governor) +			return cpufreq_modify_policy_governor(cpu, +							new_pol->governor); + +	default: +		/* slow path */ +		return do_new_policy(cpu, new_pol); +	} +} + +int cmd_freq_set(int argc, char **argv) +{ +	extern char *optarg; +	extern int optind, opterr, optopt; +	int ret = 0, cont = 1; +	int double_parm = 0, related = 0, policychange = 0; +	unsigned long freq = 0; +	char gov[20]; +	unsigned int cpu; + +	struct cpufreq_policy new_pol = { +		.min = 0, +		.max = 0, +		.governor = NULL, +	}; + +	/* parameter parsing */ +	do { +		ret = getopt_long(argc, argv, "d:u:g:f:r", set_opts, NULL); +		switch (ret) { +		case '?': +			print_unknown_arg(); +			return -EINVAL; +		case -1: +			cont = 0; +			break; +		case 'r': +			if (related) +				double_parm++; +			related++; +			break; +		case 'd': +			if (new_pol.min) +				double_parm++; +			policychange++; +			new_pol.min = string_to_frequency(optarg); +			if (new_pol.min == 0) { +				print_unknown_arg(); +				return -EINVAL; +			} +			break; +		case 'u': +			if (new_pol.max) +				double_parm++; +			policychange++; +			new_pol.max = string_to_frequency(optarg); +			if (new_pol.max == 0) { +				print_unknown_arg(); +				return -EINVAL; +			} +			break; +		case 'f': +			if (freq) +				double_parm++; +			freq = string_to_frequency(optarg); +			if (freq == 0) { +				print_unknown_arg(); +				return -EINVAL; +			} +			break; +		case 'g': +			if (new_pol.governor) +				double_parm++; +			policychange++; +			if ((strlen(optarg) < 3) || (strlen(optarg) > 18)) { +				print_unknown_arg(); +				return -EINVAL; +			} +			if ((sscanf(optarg, "%19s", gov)) != 1) { +				print_unknown_arg(); +				return -EINVAL; +			} +			new_pol.governor = gov; +			break; +		} +	} while (cont); + +	/* parameter checking */ +	if (double_parm) { +		printf("the same parameter was passed more than once\n"); +		return -EINVAL; +	} + +	if (freq && policychange) { +		printf(_("the -f/--freq parameter cannot be combined with -d/--min, -u/--max or\n" +				"-g/--governor parameters\n")); +		return -EINVAL; +	} + +	if (!freq && !policychange) { +		printf(_("At least one parameter out of -f/--freq, -d/--min, -u/--max, and\n" +				"-g/--governor must be passed\n")); +		return -EINVAL; +	} + +	/* Default is: set all CPUs */ +	if (bitmask_isallclear(cpus_chosen)) +		bitmask_setall(cpus_chosen); + +	/* Also set frequency settings for related CPUs if -r is passed */ +	if (related) { +		for (cpu = bitmask_first(cpus_chosen); +		     cpu <= bitmask_last(cpus_chosen); cpu++) { +			struct cpufreq_affected_cpus *cpus; + +			if (!bitmask_isbitset(cpus_chosen, cpu) || +			    cpufreq_cpu_exists(cpu)) +				continue; + +			cpus = cpufreq_get_related_cpus(cpu); +			if (!cpus) +				break; +			while (cpus->next) { +				bitmask_setbit(cpus_chosen, cpus->cpu); +				cpus = cpus->next; +			} +			cpufreq_put_related_cpus(cpus); +		} +	} + + +	/* loop over CPUs */ +	for (cpu = bitmask_first(cpus_chosen); +	     cpu <= bitmask_last(cpus_chosen); cpu++) { + +		if (!bitmask_isbitset(cpus_chosen, cpu) || +		    cpufreq_cpu_exists(cpu)) +			continue; + +		printf(_("Setting cpu: %d\n"), cpu); +		ret = do_one_cpu(cpu, &new_pol, freq, policychange); +		if (ret) +			break; +	} + +	if (ret) +		print_error(); + +	return ret; +} diff --git a/tools/power/cpupower/utils/cpuidle-info.c b/tools/power/cpupower/utils/cpuidle-info.c new file mode 100644 index 00000000000..75e66de7e7a --- /dev/null +++ b/tools/power/cpupower/utils/cpuidle-info.c @@ -0,0 +1,208 @@ +/* + *  (C) 2004-2009  Dominik Brodowski <linux@dominikbrodowski.de> + *  (C) 2010       Thomas Renninger <trenn@suse.de> + * + *  Licensed under the terms of the GNU GPL License version 2. + */ + + +#include <unistd.h> +#include <stdio.h> +#include <errno.h> +#include <stdlib.h> +#include <string.h> +#include <getopt.h> +#include <cpufreq.h> + +#include "helpers/helpers.h" +#include "helpers/sysfs.h" +#include "helpers/bitmask.h" + +#define LINE_LEN 10 + +static void cpuidle_cpu_output(unsigned int cpu, int verbose) +{ +	unsigned int idlestates, idlestate; +	char *tmp; + +	printf(_ ("Analyzing CPU %d:\n"), cpu); + +	idlestates = sysfs_get_idlestate_count(cpu); +	if (idlestates == 0) { +		printf(_("CPU %u: No idle states\n"), cpu); +		return; +	} + +	printf(_("Number of idle states: %d\n"), idlestates); +	printf(_("Available idle states:")); +	for (idlestate = 0; idlestate < idlestates; idlestate++) { +		tmp = sysfs_get_idlestate_name(cpu, idlestate); +		if (!tmp) +			continue; +		printf(" %s", tmp); +		free(tmp); +	} +	printf("\n"); + +	if (!verbose) +		return; + +	for (idlestate = 0; idlestate < idlestates; idlestate++) { +		int disabled = sysfs_is_idlestate_disabled(cpu, idlestate); +		/* Disabled interface not supported on older kernels */ +		if (disabled < 0) +			disabled = 0; +		tmp = sysfs_get_idlestate_name(cpu, idlestate); +		if (!tmp) +			continue; +		printf("%s%s:\n", tmp, (disabled) ? " (DISABLED) " : ""); +		free(tmp); + +		tmp = sysfs_get_idlestate_desc(cpu, idlestate); +		if (!tmp) +			continue; +		printf(_("Flags/Description: %s\n"), tmp); +		free(tmp); + +		printf(_("Latency: %lu\n"), +		       sysfs_get_idlestate_latency(cpu, idlestate)); +		printf(_("Usage: %lu\n"), +		       sysfs_get_idlestate_usage(cpu, idlestate)); +		printf(_("Duration: %llu\n"), +		       sysfs_get_idlestate_time(cpu, idlestate)); +	} +	printf("\n"); +} + +static void cpuidle_general_output(void) +{ +	char *tmp; + +	tmp = sysfs_get_cpuidle_driver(); +	if (!tmp) { +		printf(_("Could not determine cpuidle driver\n")); +		return; +	} + +	printf(_("CPUidle driver: %s\n"), tmp); +	free(tmp); + +	tmp = sysfs_get_cpuidle_governor(); +	if (!tmp) { +		printf(_("Could not determine cpuidle governor\n")); +		return; +	} + +	printf(_("CPUidle governor: %s\n"), tmp); +	free(tmp); +} + +static void proc_cpuidle_cpu_output(unsigned int cpu) +{ +	long max_allowed_cstate = 2000000000; +	unsigned int cstate, cstates; + +	cstates = sysfs_get_idlestate_count(cpu); +	if (cstates == 0) { +		printf(_("CPU %u: No C-states info\n"), cpu); +		return; +	} + +	printf(_("active state:            C0\n")); +	printf(_("max_cstate:              C%u\n"), cstates-1); +	printf(_("maximum allowed latency: %lu usec\n"), max_allowed_cstate); +	printf(_("states:\t\n")); +	for (cstate = 1; cstate < cstates; cstate++) { +		printf(_("    C%d:                  " +			 "type[C%d] "), cstate, cstate); +		printf(_("promotion[--] demotion[--] ")); +		printf(_("latency[%03lu] "), +		       sysfs_get_idlestate_latency(cpu, cstate)); +		printf(_("usage[%08lu] "), +		       sysfs_get_idlestate_usage(cpu, cstate)); +		printf(_("duration[%020Lu] \n"), +		       sysfs_get_idlestate_time(cpu, cstate)); +	} +} + +static struct option info_opts[] = { +	{ .name = "silent",	.has_arg = no_argument,	.flag = NULL,	.val = 's'}, +	{ .name = "proc",	.has_arg = no_argument,	.flag = NULL,	.val = 'o'}, +	{ }, +}; + +static inline void cpuidle_exit(int fail) +{ +	exit(EXIT_FAILURE); +} + +int cmd_idle_info(int argc, char **argv) +{ +	extern char *optarg; +	extern int optind, opterr, optopt; +	int ret = 0, cont = 1, output_param = 0, verbose = 1; +	unsigned int cpu = 0; + +	do { +		ret = getopt_long(argc, argv, "os", info_opts, NULL); +		if (ret == -1) +			break; +		switch (ret) { +		case '?': +			output_param = '?'; +			cont = 0; +			break; +		case 's': +			verbose = 0; +			break; +		case -1: +			cont = 0; +			break; +		case 'o': +			if (output_param) { +				output_param = -1; +				cont = 0; +				break; +			} +			output_param = ret; +			break; +		} +	} while (cont); + +	switch (output_param) { +	case -1: +		printf(_("You can't specify more than one " +			 "output-specific argument\n")); +		cpuidle_exit(EXIT_FAILURE); +	case '?': +		printf(_("invalid or unknown argument\n")); +		cpuidle_exit(EXIT_FAILURE); +	} + +	/* Default is: show output of CPU 0 only */ +	if (bitmask_isallclear(cpus_chosen)) +		bitmask_setbit(cpus_chosen, 0); + +	if (output_param == 0) +		cpuidle_general_output(); + +	for (cpu = bitmask_first(cpus_chosen); +	     cpu <= bitmask_last(cpus_chosen); cpu++) { + +		if (!bitmask_isbitset(cpus_chosen, cpu) || +		    cpufreq_cpu_exists(cpu)) +			continue; + +		switch (output_param) { + +		case 'o': +			proc_cpuidle_cpu_output(cpu); +			break; +		case 0: +			printf("\n"); +			cpuidle_cpu_output(cpu, verbose); +			break; +		} +	} +	return EXIT_SUCCESS; +} diff --git a/tools/power/cpupower/utils/cpuidle-set.c b/tools/power/cpupower/utils/cpuidle-set.c new file mode 100644 index 00000000000..d45d8d775c0 --- /dev/null +++ b/tools/power/cpupower/utils/cpuidle-set.c @@ -0,0 +1,181 @@ +#include <unistd.h> +#include <stdio.h> +#include <errno.h> +#include <stdlib.h> +#include <limits.h> +#include <string.h> +#include <ctype.h> + +#include <getopt.h> + +#include "cpufreq.h" +#include "helpers/helpers.h" +#include "helpers/sysfs.h" + +static struct option info_opts[] = { +	{ .name = "disable", +	  .has_arg = required_argument,	.flag = NULL,	.val = 'd'}, +	{ .name = "enable", +	  .has_arg = required_argument,	.flag = NULL,	.val = 'e'}, +	{ .name = "disable-by-latency", +	  .has_arg = required_argument,	.flag = NULL,	.val = 'D'}, +	{ .name = "enable-all", +	  .has_arg = no_argument,	.flag = NULL,	.val = 'E'}, +	{ }, +}; + + +int cmd_idle_set(int argc, char **argv) +{ +	extern char *optarg; +	extern int optind, opterr, optopt; +	int ret = 0, cont = 1, param = 0, disabled; +	unsigned long long latency = 0, state_latency; +	unsigned int cpu = 0, idlestate = 0, idlestates = 0; +	char *endptr; + +	do { +		ret = getopt_long(argc, argv, "d:e:ED:", info_opts, NULL); +		if (ret == -1) +			break; +		switch (ret) { +		case '?': +			param = '?'; +			cont = 0; +			break; +		case 'd': +			if (param) { +				param = -1; +				cont = 0; +				break; +			} +			param = ret; +			idlestate = atoi(optarg); +			break; +		case 'e': +			if (param) { +				param = -1; +				cont = 0; +				break; +			} +			param = ret; +			idlestate = atoi(optarg); +			break; +		case 'D': +			if (param) { +				param = -1; +				cont = 0; +				break; +			} +			param = ret; +			latency = strtoull(optarg, &endptr, 10); +			if (*endptr != '\0') { +				printf(_("Bad latency value: %s\n"), optarg); +				exit(EXIT_FAILURE); +			} +			break; +		case 'E': +			if (param) { +				param = -1; +				cont = 0; +				break; +			} +			param = ret; +			break; +		case -1: +			cont = 0; +			break; +		} +	} while (cont); + +	switch (param) { +	case -1: +		printf(_("You can't specify more than one " +			 "output-specific argument\n")); +		exit(EXIT_FAILURE); +	case '?': +		printf(_("invalid or unknown argument\n")); +		exit(EXIT_FAILURE); +	} + +	/* Default is: set all CPUs */ +	if (bitmask_isallclear(cpus_chosen)) +		bitmask_setall(cpus_chosen); + +	for (cpu = bitmask_first(cpus_chosen); +	     cpu <= bitmask_last(cpus_chosen); cpu++) { + +		if (!bitmask_isbitset(cpus_chosen, cpu)) +			continue; + +		if (sysfs_is_cpu_online(cpu) != 1) +			continue; + +		idlestates = sysfs_get_idlestate_count(cpu); +		if (idlestates <= 0) +			continue; + +		switch (param) { +		case 'd': +			ret = sysfs_idlestate_disable(cpu, idlestate, 1); +			if (ret == 0) +		printf(_("Idlestate %u disabled on CPU %u\n"),  idlestate, cpu); +			else if (ret == -1) +		printf(_("Idlestate %u not available on CPU %u\n"), +		       idlestate, cpu); +			else if (ret == -2) +		printf(_("Idlestate disabling not supported by kernel\n")); +			else +		printf(_("Idlestate %u not disabled on CPU %u\n"), +		       idlestate, cpu); +			break; +		case 'e': +			ret = sysfs_idlestate_disable(cpu, idlestate, 0); +			if (ret == 0) +		printf(_("Idlestate %u enabled on CPU %u\n"),  idlestate, cpu); +			else if (ret == -1) +		printf(_("Idlestate %u not available on CPU %u\n"), +		       idlestate, cpu); +			else if (ret == -2) +		printf(_("Idlestate enabling not supported by kernel\n")); +			else +		printf(_("Idlestate %u not enabled on CPU %u\n"), +		       idlestate, cpu); +			break; +		case 'D': +			for (idlestate = 0; idlestate < idlestates; idlestate++) { +				disabled = sysfs_is_idlestate_disabled +					(cpu, idlestate); +				state_latency = sysfs_get_idlestate_latency +					(cpu, idlestate); +				printf("CPU: %u - idlestate %u - state_latency: %llu - latency: %llu\n", +				       cpu, idlestate, state_latency, latency); +				if (disabled == 1 || latency > state_latency) +					continue; +				ret = sysfs_idlestate_disable +					(cpu, idlestate, 1); +				if (ret == 0) +		printf(_("Idlestate %u disabled on CPU %u\n"), idlestate, cpu); +			} +			break; +		case 'E': +			for (idlestate = 0; idlestate < idlestates; idlestate++) { +				disabled = sysfs_is_idlestate_disabled +					(cpu, idlestate); +				if (disabled == 1) { +					ret = sysfs_idlestate_disable +						(cpu, idlestate, 0); +					if (ret == 0) +		printf(_("Idlestate %u enabled on CPU %u\n"), idlestate, cpu); +				} +			} +			break; +		default: +			/* Not reachable with proper args checking */ +			printf(_("Invalid or unknown argument\n")); +			exit(EXIT_FAILURE); +			break; +		} +	} +	return EXIT_SUCCESS; +} diff --git a/tools/power/cpupower/utils/cpupower-info.c b/tools/power/cpupower/utils/cpupower-info.c new file mode 100644 index 00000000000..136d979e958 --- /dev/null +++ b/tools/power/cpupower/utils/cpupower-info.c @@ -0,0 +1,103 @@ +/* + *  (C) 2011 Thomas Renninger <trenn@suse.de>, Novell Inc. + * + *  Licensed under the terms of the GNU GPL License version 2. + */ + + +#include <unistd.h> +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> +#include <string.h> +#include <getopt.h> + +#include <cpufreq.h> +#include "helpers/helpers.h" +#include "helpers/sysfs.h" + +static struct option set_opts[] = { +	{ .name = "perf-bias",	.has_arg = optional_argument,	.flag = NULL,	.val = 'b'}, +	{ }, +}; + +static void print_wrong_arg_exit(void) +{ +	printf(_("invalid or unknown argument\n")); +	exit(EXIT_FAILURE); +} + +int cmd_info(int argc, char **argv) +{ +	extern char *optarg; +	extern int optind, opterr, optopt; +	unsigned int cpu; + +	union { +		struct { +			int perf_bias:1; +		}; +		int params; +	} params = {}; +	int ret = 0; + +	setlocale(LC_ALL, ""); +	textdomain(PACKAGE); + +	/* parameter parsing */ +	while ((ret = getopt_long(argc, argv, "b", set_opts, NULL)) != -1) { +		switch (ret) { +		case 'b': +			if (params.perf_bias) +				print_wrong_arg_exit(); +			params.perf_bias = 1; +			break; +		default: +			print_wrong_arg_exit(); +		} +	}; + +	if (!params.params) +		params.params = 0x7; + +	/* Default is: show output of CPU 0 only */ +	if (bitmask_isallclear(cpus_chosen)) +		bitmask_setbit(cpus_chosen, 0); + +	/* Add more per cpu options here */ +	if (!params.perf_bias) +		return ret; + +	if (params.perf_bias) { +		if (!run_as_root) { +			params.perf_bias = 0; +			printf(_("Intel's performance bias setting needs root privileges\n")); +		} else if (!(cpupower_cpu_info.caps & CPUPOWER_CAP_PERF_BIAS)) { +			printf(_("System does not support Intel's performance" +				 " bias setting\n")); +			params.perf_bias = 0; +		} +	} + +	/* loop over CPUs */ +	for (cpu = bitmask_first(cpus_chosen); +	     cpu <= bitmask_last(cpus_chosen); cpu++) { + +		if (!bitmask_isbitset(cpus_chosen, cpu) || +		    cpufreq_cpu_exists(cpu)) +			continue; + +		printf(_("analyzing CPU %d:\n"), cpu); + +		if (params.perf_bias) { +			ret = msr_intel_get_perf_bias(cpu); +			if (ret < 0) { +				fprintf(stderr, +			_("Could not read perf-bias value[%d]\n"), ret); +				exit(EXIT_FAILURE); +			} else +				printf(_("perf-bias: %d\n"), ret); +		} +	} +	return 0; +} diff --git a/tools/power/cpupower/utils/cpupower-set.c b/tools/power/cpupower/utils/cpupower-set.c new file mode 100644 index 00000000000..573c75f8e3f --- /dev/null +++ b/tools/power/cpupower/utils/cpupower-set.c @@ -0,0 +1,95 @@ +/* + *  (C) 2011 Thomas Renninger <trenn@suse.de>, Novell Inc. + * + *  Licensed under the terms of the GNU GPL License version 2. + */ + + +#include <unistd.h> +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> +#include <string.h> +#include <getopt.h> + +#include <cpufreq.h> +#include "helpers/helpers.h" +#include "helpers/sysfs.h" +#include "helpers/bitmask.h" + +static struct option set_opts[] = { +	{ .name = "perf-bias",	.has_arg = required_argument,	.flag = NULL,	.val = 'b'}, +	{ }, +}; + +static void print_wrong_arg_exit(void) +{ +	printf(_("invalid or unknown argument\n")); +	exit(EXIT_FAILURE); +} + +int cmd_set(int argc, char **argv) +{ +	extern char *optarg; +	extern int optind, opterr, optopt; +	unsigned int cpu; + +	union { +		struct { +			int perf_bias:1; +		}; +		int params; +	} params; +	int perf_bias = 0; +	int ret = 0; + +	setlocale(LC_ALL, ""); +	textdomain(PACKAGE); + +	params.params = 0; +	/* parameter parsing */ +	while ((ret = getopt_long(argc, argv, "b:", +						set_opts, NULL)) != -1) { +		switch (ret) { +		case 'b': +			if (params.perf_bias) +				print_wrong_arg_exit(); +			perf_bias = atoi(optarg); +			if (perf_bias < 0 || perf_bias > 15) { +				printf(_("--perf-bias param out " +					 "of range [0-%d]\n"), 15); +				print_wrong_arg_exit(); +			} +			params.perf_bias = 1; +			break; +		default: +			print_wrong_arg_exit(); +		} +	}; + +	if (!params.params) +		print_wrong_arg_exit(); + +	/* Default is: set all CPUs */ +	if (bitmask_isallclear(cpus_chosen)) +		bitmask_setall(cpus_chosen); + +	/* loop over CPUs */ +	for (cpu = bitmask_first(cpus_chosen); +	     cpu <= bitmask_last(cpus_chosen); cpu++) { + +		if (!bitmask_isbitset(cpus_chosen, cpu) || +		    cpufreq_cpu_exists(cpu)) +			continue; + +		if (params.perf_bias) { +			ret = msr_intel_set_perf_bias(cpu, perf_bias); +			if (ret) { +				fprintf(stderr, _("Error setting perf-bias " +						  "value on CPU %d\n"), cpu); +				break; +			} +		} +	} +	return ret; +} diff --git a/tools/power/cpupower/utils/cpupower.c b/tools/power/cpupower/utils/cpupower.c new file mode 100644 index 00000000000..7cdcf88659c --- /dev/null +++ b/tools/power/cpupower/utils/cpupower.c @@ -0,0 +1,229 @@ +/* + *  (C) 2010,2011       Thomas Renninger <trenn@suse.de>, Novell Inc. + * + *  Licensed under the terms of the GNU GPL License version 2. + * + *  Ideas taken over from the perf userspace tool (included in the Linus + *  kernel git repo): subcommand builtins and param parsing. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/utsname.h> + +#include "builtin.h" +#include "helpers/helpers.h" +#include "helpers/bitmask.h" + +#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0])) + +static int cmd_help(int argc, const char **argv); + +/* Global cpu_info object available for all binaries + * Info only retrieved from CPU 0 + * + * Values will be zero/unknown on non X86 archs + */ +struct cpupower_cpu_info cpupower_cpu_info; +int run_as_root; +/* Affected cpus chosen by -c/--cpu param */ +struct bitmask *cpus_chosen; + +#ifdef DEBUG +int be_verbose; +#endif + +static void print_help(void); + +struct cmd_struct { +	const char *cmd; +	int (*main)(int, const char **); +	int needs_root; +}; + +static struct cmd_struct commands[] = { +	{ "frequency-info",	cmd_freq_info,	0	}, +	{ "frequency-set",	cmd_freq_set,	1	}, +	{ "idle-info",		cmd_idle_info,	0	}, +	{ "idle-set",		cmd_idle_set,	1	}, +	{ "set",		cmd_set,	1	}, +	{ "info",		cmd_info,	0	}, +	{ "monitor",		cmd_monitor,	0	}, +	{ "help",		cmd_help,	0	}, +	/*	{ "bench",	cmd_bench,	1	}, */ +}; + +static void print_help(void) +{ +	unsigned int i; + +#ifdef DEBUG +	printf(_("Usage:\tcpupower [-d|--debug] [-c|--cpu cpulist ] <command> [<args>]\n")); +#else +	printf(_("Usage:\tcpupower [-c|--cpu cpulist ] <command> [<args>]\n")); +#endif +	printf(_("Supported commands are:\n")); +	for (i = 0; i < ARRAY_SIZE(commands); i++) +		printf("\t%s\n", commands[i].cmd); +	printf(_("\nNot all commands can make use of the -c cpulist option.\n")); +	printf(_("\nUse 'cpupower help <command>' for getting help for above commands.\n")); +} + +static int print_man_page(const char *subpage) +{ +	int len; +	char *page; + +	len = 10; /* enough for "cpupower-" */ +	if (subpage != NULL) +		len += strlen(subpage); + +	page = malloc(len); +	if (!page) +		return -ENOMEM; + +	sprintf(page, "cpupower"); +	if ((subpage != NULL) && strcmp(subpage, "help")) { +		strcat(page, "-"); +		strcat(page, subpage); +	} + +	execlp("man", "man", page, NULL); + +	/* should not be reached */ +	return -EINVAL; +} + +static int cmd_help(int argc, const char **argv) +{ +	if (argc > 1) { +		print_man_page(argv[1]); /* exits within execlp() */ +		return EXIT_FAILURE; +	} + +	print_help(); +	return EXIT_SUCCESS; +} + +static void print_version(void) +{ +	printf(PACKAGE " " VERSION "\n"); +	printf(_("Report errors and bugs to %s, please.\n"), PACKAGE_BUGREPORT); +} + +static void handle_options(int *argc, const char ***argv) +{ +	int ret, x, new_argc = 0; + +	if (*argc < 1) +		return; + +	for (x = 0;  x < *argc && ((*argv)[x])[0] == '-'; x++) { +		const char *param = (*argv)[x]; +		if (!strcmp(param, "-h") || !strcmp(param, "--help")) { +			print_help(); +			exit(EXIT_SUCCESS); +		} else if (!strcmp(param, "-c") || !strcmp(param, "--cpu")) { +			if (*argc < 2) { +				print_help(); +				exit(EXIT_FAILURE); +			} +			if (!strcmp((*argv)[x+1], "all")) +				bitmask_setall(cpus_chosen); +			else { +				ret = bitmask_parselist( +						(*argv)[x+1], cpus_chosen); +				if (ret < 0) { +					fprintf(stderr, _("Error parsing cpu " +							  "list\n")); +					exit(EXIT_FAILURE); +				} +			} +			x += 1; +			/* Cut out param: cpupower -c 1 info -> cpupower info */ +			new_argc += 2; +			continue; +		} else if (!strcmp(param, "-v") || +			!strcmp(param, "--version")) { +			print_version(); +			exit(EXIT_SUCCESS); +#ifdef DEBUG +		} else if (!strcmp(param, "-d") || !strcmp(param, "--debug")) { +			be_verbose = 1; +			new_argc++; +			continue; +#endif +		} else { +			fprintf(stderr, "Unknown option: %s\n", param); +			print_help(); +			exit(EXIT_FAILURE); +		} +	} +	*argc -= new_argc; +	*argv += new_argc; +} + +int main(int argc, const char *argv[]) +{ +	const char *cmd; +	unsigned int i, ret; +	struct stat statbuf; +	struct utsname uts; + +	cpus_chosen = bitmask_alloc(sysconf(_SC_NPROCESSORS_CONF)); + +	argc--; +	argv += 1; + +	handle_options(&argc, &argv); + +	cmd = argv[0]; + +	if (argc < 1) { +		print_help(); +		return EXIT_FAILURE; +	} + +	setlocale(LC_ALL, ""); +	textdomain(PACKAGE); + +	/* Turn "perf cmd --help" into "perf help cmd" */ +	if (argc > 1 && !strcmp(argv[1], "--help")) { +		argv[1] = argv[0]; +		argv[0] = cmd = "help"; +	} + +	get_cpu_info(0, &cpupower_cpu_info); +	run_as_root = !getuid(); +	if (run_as_root) { +		ret = uname(&uts); +		if (!ret && !strcmp(uts.machine, "x86_64") && +		    stat("/dev/cpu/0/msr", &statbuf) != 0) { +			if (system("modprobe msr") == -1) +	fprintf(stderr, _("MSR access not available.\n")); +		} +	} +		 + +	for (i = 0; i < ARRAY_SIZE(commands); i++) { +		struct cmd_struct *p = commands + i; +		if (strcmp(p->cmd, cmd)) +			continue; +		if (!run_as_root && p->needs_root) { +			fprintf(stderr, _("Subcommand %s needs root " +					  "privileges\n"), cmd); +			return EXIT_FAILURE; +		} +		ret = p->main(argc, argv); +		if (cpus_chosen) +			bitmask_free(cpus_chosen); +		return ret; +	} +	print_help(); +	return EXIT_FAILURE; +} diff --git a/tools/power/cpupower/utils/helpers/amd.c b/tools/power/cpupower/utils/helpers/amd.c new file mode 100644 index 00000000000..6437ef39aee --- /dev/null +++ b/tools/power/cpupower/utils/helpers/amd.c @@ -0,0 +1,135 @@ +#if defined(__i386__) || defined(__x86_64__) +#include <unistd.h> +#include <errno.h> +#include <stdio.h> +#include <stdint.h> + +#include <pci/pci.h> + +#include "helpers/helpers.h" + +#define MSR_AMD_PSTATE_STATUS	0xc0010063 +#define MSR_AMD_PSTATE		0xc0010064 +#define MSR_AMD_PSTATE_LIMIT	0xc0010061 + +union msr_pstate { +	struct { +		unsigned fid:6; +		unsigned did:3; +		unsigned vid:7; +		unsigned res1:6; +		unsigned nbdid:1; +		unsigned res2:2; +		unsigned nbvid:7; +		unsigned iddval:8; +		unsigned idddiv:2; +		unsigned res3:21; +		unsigned en:1; +	} bits; +	unsigned long long val; +}; + +static int get_did(int family, union msr_pstate pstate) +{ +	int t; + +	if (family == 0x12) +		t = pstate.val & 0xf; +	else +		t = pstate.bits.did; + +	return t; +} + +static int get_cof(int family, union msr_pstate pstate) +{ +	int t; +	int fid, did; + +	did = get_did(family, pstate); + +	t = 0x10; +	fid = pstate.bits.fid; +	if (family == 0x11) +		t = 0x8; + +	return (100 * (fid + t)) >> did; +} + +/* Needs: + * cpu          -> the cpu that gets evaluated + * cpu_family   -> The cpu's family (0x10, 0x12,...) + * boots_states -> how much boost states the machines support + * + * Fills up: + * pstates -> a pointer to an array of size MAX_HW_PSTATES + *            must be initialized with zeros. + *            All available  HW pstates (including boost states) + * no      -> amount of pstates above array got filled up with + * + * returns zero on success, -1 on failure + */ +int decode_pstates(unsigned int cpu, unsigned int cpu_family, +		   int boost_states, unsigned long *pstates, int *no) +{ +	int i, psmax, pscur; +	union msr_pstate pstate; +	unsigned long long val; + +	/* Only read out frequencies from HW when CPU might be boostable +	   to keep the code as short and clean as possible. +	   Otherwise frequencies are exported via ACPI tables. +	*/ +	if (cpu_family < 0x10 || cpu_family == 0x14) +		return -1; + +	if (read_msr(cpu, MSR_AMD_PSTATE_LIMIT, &val)) +		return -1; + +	psmax = (val >> 4) & 0x7; + +	if (read_msr(cpu, MSR_AMD_PSTATE_STATUS, &val)) +		return -1; + +	pscur = val & 0x7; + +	pscur += boost_states; +	psmax += boost_states; +	for (i = 0; i <= psmax; i++) { +		if (i >= MAX_HW_PSTATES) { +			fprintf(stderr, "HW pstates [%d] exceeding max [%d]\n", +				psmax, MAX_HW_PSTATES); +			return -1; +		} +		if (read_msr(cpu, MSR_AMD_PSTATE + i, &pstate.val)) +			return -1; +		pstates[i] = get_cof(cpu_family, pstate); +	} +	*no = i; +	return 0; +} + +int amd_pci_get_num_boost_states(int *active, int *states) +{ +	struct pci_access *pci_acc; +	struct pci_dev *device; +	uint8_t val = 0; + +	*active = *states = 0; + +	device = pci_slot_func_init(&pci_acc, 0x18, 4); + +	if (device == NULL) +		return -ENODEV; + +	val = pci_read_byte(device, 0x15c); +	if (val & 3) +		*active = 1; +	else +		*active = 0; +	*states = (val >> 2) & 7; + +	pci_cleanup(pci_acc); +	return 0; +} +#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..5c074c60f90 --- /dev/null +++ b/tools/power/cpupower/utils/helpers/bitmask.c @@ -0,0 +1,292 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <helpers/bitmask.h> + +/* How many bits in an unsigned long */ +#define bitsperlong (8 * sizeof(unsigned long)) + +/* howmany(a,b) : how many elements of size b needed to hold all of a */ +#define howmany(x, y) (((x)+((y)-1))/(y)) + +/* How many longs in mask of n bits */ +#define longsperbits(n) howmany(n, bitsperlong) + +#define max(a, b) ((a) > (b) ? (a) : (b)) + +/* + * Allocate and free `struct bitmask *` + */ + +/* Allocate a new `struct bitmask` with a size of n bits */ +struct bitmask *bitmask_alloc(unsigned int n) +{ +	struct bitmask *bmp; + +	bmp = malloc(sizeof(*bmp)); +	if (bmp == 0) +		return 0; +	bmp->size = n; +	bmp->maskp = calloc(longsperbits(n), sizeof(unsigned long)); +	if (bmp->maskp == 0) { +		free(bmp); +		return 0; +	} +	return bmp; +} + +/* Free `struct bitmask` */ +void bitmask_free(struct bitmask *bmp) +{ +	if (bmp == 0) +		return; +	free(bmp->maskp); +	bmp->maskp = (unsigned long *)0xdeadcdef;  /* double free tripwire */ +	free(bmp); +} + +/* + * The routines _getbit() and _setbit() are the only + * routines that actually understand the layout of bmp->maskp[]. + * + * On little endian architectures, this could simply be an array of + * bytes.  But the kernel layout of bitmasks _is_ visible to userspace + * via the sched_(set/get)affinity calls in Linux 2.6, and on big + * endian architectures, it is painfully obvious that this is an + * array of unsigned longs. + */ + +/* Return the value (0 or 1) of bit n in bitmask bmp */ +static unsigned int _getbit(const struct bitmask *bmp, unsigned int n) +{ +	if (n < bmp->size) +		return (bmp->maskp[n/bitsperlong] >> (n % bitsperlong)) & 1; +	else +		return 0; +} + +/* Set bit n in bitmask bmp to value v (0 or 1) */ +static void _setbit(struct bitmask *bmp, unsigned int n, unsigned int v) +{ +	if (n < bmp->size) { +		if (v) +			bmp->maskp[n/bitsperlong] |= 1UL << (n % bitsperlong); +		else +			bmp->maskp[n/bitsperlong] &= +				~(1UL << (n % bitsperlong)); +	} +} + +/* + * When parsing bitmask lists, only allow numbers, separated by one + * of the allowed next characters. + * + * The parameter 'sret' is the return from a sscanf "%u%c".  It is + * -1 if the sscanf input string was empty.  It is 0 if the first + * character in the sscanf input string was not a decimal number. + * It is 1 if the unsigned number matching the "%u" was the end of the + * input string.  It is 2 if one or more additional characters followed + * the matched unsigned number.  If it is 2, then 'nextc' is the first + * character following the number.  The parameter 'ok_next_chars' + * is the nul-terminated list of allowed next characters. + * + * The mask term just scanned was ok if and only if either the numbers + * matching the %u were all of the input or if the next character in + * the input past the numbers was one of the allowed next characters. + */ +static int scan_was_ok(int sret, char nextc, const char *ok_next_chars) +{ +	return sret == 1 || +		(sret == 2 && strchr(ok_next_chars, nextc) != NULL); +} + +static const char *nexttoken(const char *q,  int sep) +{ +	if (q) +		q = strchr(q, sep); +	if (q) +		q++; +	return q; +} + +/* Set a single bit i in bitmask */ +struct bitmask *bitmask_setbit(struct bitmask *bmp, unsigned int i) +{ +	_setbit(bmp, i, 1); +	return bmp; +} + +/* Set all bits in bitmask: bmp = ~0 */ +struct bitmask *bitmask_setall(struct bitmask *bmp) +{ +	unsigned int i; +	for (i = 0; i < bmp->size; i++) +		_setbit(bmp, i, 1); +	return bmp; +} + +/* Clear all bits in bitmask: bmp = 0 */ +struct bitmask *bitmask_clearall(struct bitmask *bmp) +{ +	unsigned int i; +	for (i = 0; i < bmp->size; i++) +		_setbit(bmp, i, 0); +	return bmp; +} + +/* True if all bits are clear */ +int bitmask_isallclear(const struct bitmask *bmp) +{ +	unsigned int i; +	for (i = 0; i < bmp->size; i++) +		if (_getbit(bmp, i)) +			return 0; +	return 1; +} + +/* True if specified bit i is set */ +int bitmask_isbitset(const struct bitmask *bmp, unsigned int i) +{ +	return _getbit(bmp, i); +} + +/* Number of lowest set bit (min) */ +unsigned int bitmask_first(const struct bitmask *bmp) +{ +	return bitmask_next(bmp, 0); +} + +/* Number of highest set bit (max) */ +unsigned int bitmask_last(const struct bitmask *bmp) +{ +	unsigned int i; +	unsigned int m = bmp->size; +	for (i = 0; i < bmp->size; i++) +		if (_getbit(bmp, i)) +			m = i; +	return m; +} + +/* Number of next set bit at or above given bit i */ +unsigned int bitmask_next(const struct bitmask *bmp, unsigned int i) +{ +	unsigned int n; +	for (n = i; n < bmp->size; n++) +		if (_getbit(bmp, n)) +			break; +	return n; +} + +/* + * Parses a comma-separated list of numbers and ranges of numbers, + * with optional ':%u' strides modifying ranges, into provided bitmask. + * Some examples of input lists and their equivalent simple list: + *	Input		Equivalent to + *	0-3		0,1,2,3 + *	0-7:2		0,2,4,6 + *	1,3,5-7		1,3,5,6,7 + *	0-3:2,8-15:4	0,2,8,12 + */ +int bitmask_parselist(const char *buf, struct bitmask *bmp) +{ +	const char *p, *q; + +	bitmask_clearall(bmp); + +	q = buf; +	while (p = q, q = nexttoken(q, ','), p) { +		unsigned int a;		/* begin of range */ +		unsigned int b;		/* end of range */ +		unsigned int s;		/* stride */ +		const char *c1, *c2;	/* next tokens after '-' or ',' */ +		char nextc;		/* char after sscanf %u match */ +		int sret;		/* sscanf return (number of matches) */ + +		sret = sscanf(p, "%u%c", &a, &nextc); +		if (!scan_was_ok(sret, nextc, ",-")) +			goto err; +		b = a; +		s = 1; +		c1 = nexttoken(p, '-'); +		c2 = nexttoken(p, ','); +		if (c1 != NULL && (c2 == NULL || c1 < c2)) { +			sret = sscanf(c1, "%u%c", &b, &nextc); +			if (!scan_was_ok(sret, nextc, ",:")) +				goto err; +			c1 = nexttoken(c1, ':'); +			if (c1 != NULL && (c2 == NULL || c1 < c2)) { +				sret = sscanf(c1, "%u%c", &s, &nextc); +				if (!scan_was_ok(sret, nextc, ",")) +					goto err; +			} +		} +		if (!(a <= b)) +			goto err; +		if (b >= bmp->size) +			goto err; +		while (a <= b) { +			_setbit(bmp, a, 1); +			a += s; +		} +	} +	return 0; +err: +	bitmask_clearall(bmp); +	return -1; +} + +/* + * emit(buf, buflen, rbot, rtop, len) + * + * Helper routine for bitmask_displaylist().  Write decimal number + * or range to buf+len, suppressing output past buf+buflen, with optional + * comma-prefix.  Return len of what would be written to buf, if it + * all fit. + */ + +static inline int emit(char *buf, int buflen, int rbot, int rtop, int len) +{ +	if (len > 0) +		len += snprintf(buf + len, max(buflen - len, 0), ","); +	if (rbot == rtop) +		len += snprintf(buf + len, max(buflen - len, 0), "%d", rbot); +	else +		len += snprintf(buf + len, max(buflen - len, 0), "%d-%d", +				rbot, rtop); +	return len; +} + +/* + * Write decimal list representation of bmp to buf. + * + * Output format is a comma-separated list of decimal numbers and + * ranges.  Consecutively set bits are shown as two hyphen-separated + * decimal numbers, the smallest and largest bit numbers set in + * the range.  Output format is compatible with the format + * accepted as input by bitmap_parselist(). + * + * The return value is the number of characters which would be + * generated for the given input, excluding the trailing '\0', as + * per ISO C99. + */ + +int bitmask_displaylist(char *buf, int buflen, const struct bitmask *bmp) +{ +	int len = 0; +	/* current bit is 'cur', most recently seen range is [rbot, rtop] */ +	unsigned int cur, rbot, rtop; + +	if (buflen > 0) +		*buf = 0; +	rbot = cur = bitmask_first(bmp); +	while (cur < bmp->size) { +		rtop = cur; +		cur = bitmask_next(bmp, cur+1); +		if (cur >= bmp->size || cur > rtop + 1) { +			len = emit(buf, buflen, rbot, rtop, len); +			rbot = cur; +		} +	} +	return len; +} 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 @@ +#ifndef __CPUPOWER_BITMASK__ +#define __CPUPOWER_BITMASK__ + +/* Taken over from libbitmask, a project initiated from sgi: + * Url:            http://oss.sgi.com/projects/cpusets/ + * Unfortunately it's not very widespread, therefore relevant parts are + * pasted here. + */ + +struct bitmask { +	unsigned int size; +	unsigned long *maskp; +}; + +struct bitmask *bitmask_alloc(unsigned int n); +void bitmask_free(struct bitmask *bmp); + +struct bitmask *bitmask_setbit(struct bitmask *bmp, unsigned int i); +struct bitmask *bitmask_setall(struct bitmask *bmp); +struct bitmask *bitmask_clearall(struct bitmask *bmp); + +unsigned int bitmask_first(const struct bitmask *bmp); +unsigned int bitmask_next(const struct bitmask *bmp, unsigned int i); +unsigned int bitmask_last(const struct bitmask *bmp); +int bitmask_isallclear(const struct bitmask *bmp); +int bitmask_isbitset(const struct bitmask *bmp, unsigned int i); + +int bitmask_parselist(const char *buf, struct bitmask *bmp); +int bitmask_displaylist(char *buf, int len, const struct bitmask *bmp); + + + +#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..93b0aa74ca0 --- /dev/null +++ b/tools/power/cpupower/utils/helpers/cpuid.c @@ -0,0 +1,178 @@ +#include <stdio.h> +#include <errno.h> +#include <string.h> +#include <unistd.h> +#include <stdlib.h> + +#include "helpers/helpers.h" + +static const char *cpu_vendor_table[X86_VENDOR_MAX] = { +	"Unknown", "GenuineIntel", "AuthenticAMD", +}; + +#if defined(__i386__) || defined(__x86_64__) + +/* from gcc */ +#include <cpuid.h> + +/* + * CPUID functions returning a single datum + * + * Define unsigned int cpuid_e[abcd]x(unsigned int op) + */ +#define cpuid_func(reg)					\ +	unsigned int cpuid_##reg(unsigned int op)	\ +	{						\ +	unsigned int eax, ebx, ecx, edx;		\ +	__cpuid(op, eax, ebx, ecx, edx);		\ +	return reg;					\ +	} +cpuid_func(eax); +cpuid_func(ebx); +cpuid_func(ecx); +cpuid_func(edx); + +#endif /* defined(__i386__) || defined(__x86_64__) */ + +/* get_cpu_info + * + * Extract CPU vendor, family, model, stepping info from /proc/cpuinfo + * + * Returns 0 on success or a negativ error code + * + * TBD: Should there be a cpuid alternative for this if /proc is not mounted? + */ +int get_cpu_info(unsigned int cpu, struct cpupower_cpu_info *cpu_info) +{ +	FILE *fp; +	char value[64]; +	unsigned int proc, x; +	unsigned int unknown = 0xffffff; +	unsigned int cpuid_level, ext_cpuid_level; + +	int ret = -EINVAL; + +	cpu_info->vendor		= X86_VENDOR_UNKNOWN; +	cpu_info->family		= unknown; +	cpu_info->model			= unknown; +	cpu_info->stepping		= unknown; +	cpu_info->caps			= 0; + +	fp = fopen("/proc/cpuinfo", "r"); +	if (!fp) +		return -EIO; + +	while (!feof(fp)) { +		if (!fgets(value, 64, fp)) +			continue; +		value[63 - 1] = '\0'; + +		if (!strncmp(value, "processor\t: ", 12)) +			sscanf(value, "processor\t: %u", &proc); + +		if (proc != cpu) +			continue; + +		/* Get CPU vendor */ +		if (!strncmp(value, "vendor_id", 9)) { +			for (x = 1; x < X86_VENDOR_MAX; x++) { +				if (strstr(value, cpu_vendor_table[x])) +					cpu_info->vendor = x; +			} +		/* Get CPU family, etc. */ +		} else if (!strncmp(value, "cpu family\t: ", 13)) { +			sscanf(value, "cpu family\t: %u", +			       &cpu_info->family); +		} else if (!strncmp(value, "model\t\t: ", 9)) { +			sscanf(value, "model\t\t: %u", +			       &cpu_info->model); +		} else if (!strncmp(value, "stepping\t: ", 10)) { +			sscanf(value, "stepping\t: %u", +			       &cpu_info->stepping); + +			/* Exit -> all values must have been set */ +			if (cpu_info->vendor == X86_VENDOR_UNKNOWN || +			    cpu_info->family == unknown || +			    cpu_info->model == unknown || +			    cpu_info->stepping == unknown) { +				ret = -EINVAL; +				goto out; +			} + +			ret = 0; +			goto out; +		} +	} +	ret = -ENODEV; +out: +	fclose(fp); +	/* Get some useful CPU capabilities from cpuid */ +	if (cpu_info->vendor != X86_VENDOR_AMD && +	    cpu_info->vendor != X86_VENDOR_INTEL) +		return ret; + +	cpuid_level	= cpuid_eax(0); +	ext_cpuid_level	= cpuid_eax(0x80000000); + +	/* Invariant TSC */ +	if (ext_cpuid_level >= 0x80000007 && +	    (cpuid_edx(0x80000007) & (1 << 8))) +		cpu_info->caps |= CPUPOWER_CAP_INV_TSC; + +	/* Aperf/Mperf registers support */ +	if (cpuid_level >= 6 && (cpuid_ecx(6) & 0x1)) +		cpu_info->caps |= CPUPOWER_CAP_APERF; + +	/* AMD Boost state enable/disable register */ +	if (cpu_info->vendor == X86_VENDOR_AMD) { +		if (ext_cpuid_level >= 0x80000007 && +		    (cpuid_edx(0x80000007) & (1 << 9))) +			cpu_info->caps |= CPUPOWER_CAP_AMD_CBP; +	} + +	if (cpu_info->vendor == X86_VENDOR_INTEL) { +		if (cpuid_level >= 6 && +		    (cpuid_eax(6) & (1 << 1))) +			cpu_info->caps |= CPUPOWER_CAP_INTEL_IDA; +	} + +	if (cpu_info->vendor == X86_VENDOR_INTEL) { +		/* Intel's perf-bias MSR support */ +		if (cpuid_level >= 6 && (cpuid_ecx(6) & (1 << 3))) +			cpu_info->caps |= CPUPOWER_CAP_PERF_BIAS; + +		/* Intel's Turbo Ratio Limit support */ +		if (cpu_info->family == 6) { +			switch (cpu_info->model) { +			case 0x1A:	/* Core i7, Xeon 5500 series +					 * Bloomfield, Gainstown NHM-EP +					 */ +			case 0x1E:	/* Core i7 and i5 Processor +					 * Clarksfield, Lynnfield, Jasper Forest +					 */ +			case 0x1F:	/* Core i7 and i5 Processor - Nehalem */ +			case 0x25:	/* Westmere Client +					 * Clarkdale, Arrandale +					 */ +			case 0x2C:	/* Westmere EP - Gulftown */ +				cpu_info->caps |= CPUPOWER_CAP_HAS_TURBO_RATIO; +			case 0x2A:	/* SNB */ +			case 0x2D:	/* SNB Xeon */ +			case 0x3A:	/* IVB */ +			case 0x3E:	/* IVB Xeon */ +				cpu_info->caps |= CPUPOWER_CAP_HAS_TURBO_RATIO; +				cpu_info->caps |= CPUPOWER_CAP_IS_SNB; +				break; +			case 0x2E:	/* Nehalem-EX Xeon - Beckton */ +			case 0x2F:	/* Westmere-EX Xeon - Eagleton */ +			default: +				break; +			} +		} +	} + +	/*	printf("ID: %u - Extid: 0x%x - Caps: 0x%llx\n", +		cpuid_level, ext_cpuid_level, cpu_info->caps); +	*/ +	return ret; +} diff --git a/tools/power/cpupower/utils/helpers/helpers.h b/tools/power/cpupower/utils/helpers/helpers.h new file mode 100644 index 00000000000..aa9e95486a2 --- /dev/null +++ b/tools/power/cpupower/utils/helpers/helpers.h @@ -0,0 +1,195 @@ +/* + *  (C) 2010,2011       Thomas Renninger <trenn@suse.de>, Novell Inc. + * + *  Licensed under the terms of the GNU GPL License version 2. + * + * Miscellaneous helpers which do not fit or are worth + * to put into separate headers + */ + +#ifndef __CPUPOWERUTILS_HELPERS__ +#define __CPUPOWERUTILS_HELPERS__ + +#include <libintl.h> +#include <locale.h> + +#include "helpers/bitmask.h" + +/* Internationalization ****************************/ +#ifdef NLS + +#define _(String) gettext(String) +#ifndef gettext_noop +#define gettext_noop(String) String +#endif +#define N_(String) gettext_noop(String) + +#else /* !NLS */ + +#define _(String) String +#define N_(String) String + +#endif +/* Internationalization ****************************/ + +extern int run_as_root; +extern struct bitmask *cpus_chosen; + +/* Global verbose (-d) stuff *********************************/ +/* + * define DEBUG via global Makefile variable + * Debug output is sent to stderr, do: + * cpupower monitor 2>/tmp/debug + * to split debug output away from normal output +*/ +#ifdef DEBUG +extern int be_verbose; + +#define dprint(fmt, ...) {					\ +		if (be_verbose) {				\ +			fprintf(stderr, "%s: " fmt,		\ +				__func__, ##__VA_ARGS__);	\ +		}						\ +	} +#else +static inline void dprint(const char *fmt, ...) { } +#endif +extern int be_verbose; +/* Global verbose (-v) stuff *********************************/ + +/* cpuid and cpuinfo helpers  **************************/ +enum cpupower_cpu_vendor {X86_VENDOR_UNKNOWN = 0, X86_VENDOR_INTEL, +			  X86_VENDOR_AMD, X86_VENDOR_MAX}; + +#define CPUPOWER_CAP_INV_TSC		0x00000001 +#define CPUPOWER_CAP_APERF		0x00000002 +#define CPUPOWER_CAP_AMD_CBP		0x00000004 +#define CPUPOWER_CAP_PERF_BIAS		0x00000008 +#define CPUPOWER_CAP_HAS_TURBO_RATIO	0x00000010 +#define CPUPOWER_CAP_IS_SNB		0x00000020 +#define CPUPOWER_CAP_INTEL_IDA		0x00000040 + +#define MAX_HW_PSTATES 10 + +struct cpupower_cpu_info { +	enum cpupower_cpu_vendor vendor; +	unsigned int family; +	unsigned int model; +	unsigned int stepping; +	/* CPU capabilities read out from cpuid */ +	unsigned long long caps; +}; + +/* get_cpu_info + * + * Extract CPU vendor, family, model, stepping info from /proc/cpuinfo + * + * Returns 0 on success or a negativ error code + * Only used on x86, below global's struct values are zero/unknown on + * other archs + */ +extern int get_cpu_info(unsigned int cpu, struct cpupower_cpu_info *cpu_info); +extern struct cpupower_cpu_info cpupower_cpu_info; +/* cpuid and cpuinfo helpers  **************************/ + +struct cpuid_core_info { +	int pkg; +	int core; +	int cpu; + +	/* flags */ +	unsigned int is_online:1; +}; + +/* CPU topology/hierarchy parsing ******************/ +struct cpupower_topology { +	/* Amount of CPU cores, packages and threads per core in the system */ +	unsigned int cores; +	unsigned int pkgs; +	unsigned int threads; /* per core */ + +	/* Array gets mallocated with cores entries, holding per core info */ +	struct cpuid_core_info *core_info; +}; + +extern int get_cpu_topology(struct cpupower_topology *cpu_top); +extern void cpu_topology_release(struct cpupower_topology cpu_top); + +/* CPU topology/hierarchy parsing ******************/ + +/* X86 ONLY ****************************************/ +#if defined(__i386__) || defined(__x86_64__) + +#include <pci/pci.h> + +/* Read/Write msr ****************************/ +extern int read_msr(int cpu, unsigned int idx, unsigned long long *val); +extern int write_msr(int cpu, unsigned int idx, unsigned long long val); + +extern int msr_intel_set_perf_bias(unsigned int cpu, unsigned int val); +extern int msr_intel_get_perf_bias(unsigned int cpu); +extern unsigned long long msr_intel_get_turbo_ratio(unsigned int cpu); + +/* Read/Write msr ****************************/ + +/* PCI stuff ****************************/ +extern int amd_pci_get_num_boost_states(int *active, int *states); +extern struct pci_dev *pci_acc_init(struct pci_access **pacc, int domain, +				    int bus, int slot, int func, int vendor, +				    int dev); +extern struct pci_dev *pci_slot_func_init(struct pci_access **pacc, +					      int slot, int func); + +/* PCI stuff ****************************/ + +/* AMD HW pstate decoding **************************/ + +extern int decode_pstates(unsigned int cpu, unsigned int cpu_family, +			  int boost_states, unsigned long *pstates, int *no); + +/* AMD HW pstate decoding **************************/ + +extern int cpufreq_has_boost_support(unsigned int cpu, int *support, +				     int *active, int * states); +/* + * CPUID functions returning a single datum + */ +unsigned int cpuid_eax(unsigned int op); +unsigned int cpuid_ebx(unsigned int op); +unsigned int cpuid_ecx(unsigned int op); +unsigned int cpuid_edx(unsigned int op); + +/* cpuid and cpuinfo helpers  **************************/ +/* X86 ONLY ********************************************/ +#else +static inline int decode_pstates(unsigned int cpu, unsigned int cpu_family, +				 int boost_states, unsigned long *pstates, +				 int *no) +{ return -1; }; + +static inline int read_msr(int cpu, unsigned int idx, unsigned long long *val) +{ return -1; }; +static inline int write_msr(int cpu, unsigned int idx, unsigned long long val) +{ return -1; }; +static inline int msr_intel_set_perf_bias(unsigned int cpu, unsigned int val) +{ return -1; }; +static inline int msr_intel_get_perf_bias(unsigned int cpu) +{ return -1; }; +static inline unsigned long long msr_intel_get_turbo_ratio(unsigned int cpu) +{ return 0; }; + +/* Read/Write msr ****************************/ + +static inline int cpufreq_has_boost_support(unsigned int cpu, int *support, +					    int *active, int * states) +{ return -1; } + +/* cpuid and cpuinfo helpers  **************************/ + +static inline unsigned int cpuid_eax(unsigned int op) { return 0; }; +static inline unsigned int cpuid_ebx(unsigned int op) { return 0; }; +static inline unsigned int cpuid_ecx(unsigned int op) { return 0; }; +static inline unsigned int cpuid_edx(unsigned int op) { return 0; }; +#endif /* defined(__i386__) || defined(__x86_64__) */ + +#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..1609243f5c6 --- /dev/null +++ b/tools/power/cpupower/utils/helpers/misc.c @@ -0,0 +1,27 @@ +#if defined(__i386__) || defined(__x86_64__) + +#include "helpers/helpers.h" + +int cpufreq_has_boost_support(unsigned int cpu, int *support, int *active, +			int *states) +{ +	struct cpupower_cpu_info cpu_info; +	int ret; + +	*support = *active = *states = 0; + +	ret = get_cpu_info(0, &cpu_info); +	if (ret) +		return ret; + +	if (cpupower_cpu_info.caps & CPUPOWER_CAP_AMD_CBP) { +		*support = 1; +		amd_pci_get_num_boost_states(active, states); +		if (ret <= 0) +			return ret; +		*support = 1; +	} else if (cpupower_cpu_info.caps & CPUPOWER_CAP_INTEL_IDA) +		*support = *active = 1; +	return 0; +} +#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..31a4b24a8bc --- /dev/null +++ b/tools/power/cpupower/utils/helpers/msr.c @@ -0,0 +1,115 @@ +#if defined(__i386__) || defined(__x86_64__) + +#include <fcntl.h> +#include <stdio.h> +#include <unistd.h> +#include <stdint.h> + +#include "helpers/helpers.h" + +/* Intel specific MSRs */ +#define MSR_IA32_PERF_STATUS		0x198 +#define MSR_IA32_MISC_ENABLES		0x1a0 +#define MSR_IA32_ENERGY_PERF_BIAS	0x1b0 +#define MSR_NEHALEM_TURBO_RATIO_LIMIT	0x1ad + +/* + * read_msr + * + * Will return 0 on success and -1 on failure. + * Possible errno values could be: + * EFAULT -If the read/write did not fully complete + * EIO    -If the CPU does not support MSRs + * ENXIO  -If the CPU does not exist + */ + +int read_msr(int cpu, unsigned int idx, unsigned long long *val) +{ +	int fd; +	char msr_file_name[64]; + +	sprintf(msr_file_name, "/dev/cpu/%d/msr", cpu); +	fd = open(msr_file_name, O_RDONLY); +	if (fd < 0) +		return -1; +	if (lseek(fd, idx, SEEK_CUR) == -1) +		goto err; +	if (read(fd, val, sizeof *val) != sizeof *val) +		goto err; +	close(fd); +	return 0; + err: +	close(fd); +	return -1; +} + +/* + * write_msr + * + * Will return 0 on success and -1 on failure. + * Possible errno values could be: + * EFAULT -If the read/write did not fully complete + * EIO    -If the CPU does not support MSRs + * ENXIO  -If the CPU does not exist + */ +int write_msr(int cpu, unsigned int idx, unsigned long long val) +{ +	int fd; +	char msr_file_name[64]; + +	sprintf(msr_file_name, "/dev/cpu/%d/msr", cpu); +	fd = open(msr_file_name, O_WRONLY); +	if (fd < 0) +		return -1; +	if (lseek(fd, idx, SEEK_CUR) == -1) +		goto err; +	if (write(fd, &val, sizeof val) != sizeof val) +		goto err; +	close(fd); +	return 0; + err: +	close(fd); +	return -1; +} + +int msr_intel_get_perf_bias(unsigned int cpu) +{ +	unsigned long long val; +	int ret; + +	if (!(cpupower_cpu_info.caps & CPUPOWER_CAP_PERF_BIAS)) +		return -1; + +	ret = read_msr(cpu, MSR_IA32_ENERGY_PERF_BIAS, &val); +	if (ret) +		return ret; +	return val; +} + +int msr_intel_set_perf_bias(unsigned int cpu, unsigned int val) +{ +	int ret; + +	if (!(cpupower_cpu_info.caps & CPUPOWER_CAP_PERF_BIAS)) +		return -1; + +	ret = write_msr(cpu, MSR_IA32_ENERGY_PERF_BIAS, val); +	if (ret) +		return ret; +	return 0; +} + +unsigned long long msr_intel_get_turbo_ratio(unsigned int cpu) +{ +	unsigned long long val; +	int ret; + +	if (!(cpupower_cpu_info.caps & CPUPOWER_CAP_HAS_TURBO_RATIO)) +		return -1; + +	ret = read_msr(cpu, MSR_NEHALEM_TURBO_RATIO_LIMIT, &val); +	if (ret) +		return ret; +	return val; +} +#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..9690798e644 --- /dev/null +++ b/tools/power/cpupower/utils/helpers/pci.c @@ -0,0 +1,55 @@ +#if defined(__i386__) || defined(__x86_64__) + +#include <helpers/helpers.h> + +/* + * pci_acc_init + * + * PCI access helper function depending on libpci + * + * **pacc : if a valid pci_dev is returned + *         *pacc must be passed to pci_acc_cleanup to free it + * + * domain: domain + * bus:    bus + * slot:   slot + * func:   func + * vendor: vendor + * device: device + * Pass -1 for one of the six above to match any + * + * Returns : + * struct pci_dev which can be used with pci_{read,write}_* functions + *                to access the PCI config space of matching pci devices + */ +struct pci_dev *pci_acc_init(struct pci_access **pacc, int domain, int bus, +			     int slot, int func, int vendor, int dev) +{ +	struct pci_filter filter_nb_link = { domain, bus, slot, func, +					     vendor, dev }; +	struct pci_dev *device; + +	*pacc = pci_alloc(); +	if (*pacc == NULL) +		return NULL; + +	pci_init(*pacc); +	pci_scan_bus(*pacc); + +	for (device = (*pacc)->devices; device; device = device->next) { +		if (pci_filter_match(&filter_nb_link, device)) +			return device; +	} +	pci_cleanup(*pacc); +	return NULL; +} + +/* Typically one wants to get a specific slot(device)/func of the root domain +   and bus */ +struct pci_dev *pci_slot_func_init(struct pci_access **pacc, int slot, +				       int func) +{ +	return pci_acc_init(pacc, 0, 0, slot, func, -1, -1); +} + +#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..851c7a16ca4 --- /dev/null +++ b/tools/power/cpupower/utils/helpers/sysfs.c @@ -0,0 +1,472 @@ +/* + *  (C) 2004-2009  Dominik Brodowski <linux@dominikbrodowski.de> + *  (C) 2011       Thomas Renninger <trenn@novell.com> Novell Inc. + * + *  Licensed under the terms of the GNU GPL License version 2. + */ + +#include <stdio.h> +#include <errno.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> + +#include "helpers/sysfs.h" + +unsigned int sysfs_read_file(const char *path, char *buf, size_t buflen) +{ +	int fd; +	ssize_t numread; + +	fd = open(path, O_RDONLY); +	if (fd == -1) +		return 0; + +	numread = read(fd, buf, buflen - 1); +	if (numread < 1) { +		close(fd); +		return 0; +	} + +	buf[numread] = '\0'; +	close(fd); + +	return (unsigned int) numread; +} + +/* + * Detect whether a CPU is online + * + * Returns: + *     1 -> if CPU is online + *     0 -> if CPU is offline + *     negative errno values in error case + */ +int sysfs_is_cpu_online(unsigned int cpu) +{ +	char path[SYSFS_PATH_MAX]; +	int fd; +	ssize_t numread; +	unsigned long long value; +	char linebuf[MAX_LINE_LEN]; +	char *endp; +	struct stat statbuf; + +	snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u", cpu); + +	if (stat(path, &statbuf) != 0) +		return 0; + +	/* +	 * kernel without CONFIG_HOTPLUG_CPU +	 * -> cpuX directory exists, but not cpuX/online file +	 */ +	snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/online", cpu); +	if (stat(path, &statbuf) != 0) +		return 1; + +	fd = open(path, O_RDONLY); +	if (fd == -1) +		return -errno; + +	numread = read(fd, linebuf, MAX_LINE_LEN - 1); +	if (numread < 1) { +		close(fd); +		return -EIO; +	} +	linebuf[numread] = '\0'; +	close(fd); + +	value = strtoull(linebuf, &endp, 0); +	if (value > 1 || value < 0) +		return -EINVAL; + +	return value; +} + +/* CPUidle idlestate specific /sys/devices/system/cpu/cpuX/cpuidle/ access */ + + +/* CPUidle idlestate specific /sys/devices/system/cpu/cpuX/cpuidle/ access */ + +/* + * helper function to check whether a file under "../cpuX/cpuidle/stateX/" dir + * exists. + * For example the functionality to disable c-states was introduced in later + * kernel versions, this function can be used to explicitly check for this + * feature. + * + * returns 1 if the file exists, 0 otherwise. + */ +unsigned int sysfs_idlestate_file_exists(unsigned int cpu, +					 unsigned int idlestate, +					 const char *fname) +{ +	char path[SYSFS_PATH_MAX]; +	struct stat statbuf; + + +	snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/cpuidle/state%u/%s", +		 cpu, idlestate, fname); +	if (stat(path, &statbuf) != 0) +		return 0; +	return 1; +} + +/* + * helper function to read file from /sys into given buffer + * fname is a relative path under "cpuX/cpuidle/stateX/" dir + * cstates starting with 0, C0 is not counted as cstate. + * This means if you want C1 info, pass 0 as idlestate param + */ +unsigned int sysfs_idlestate_read_file(unsigned int cpu, unsigned int idlestate, +			     const char *fname, char *buf, size_t buflen) +{ +	char path[SYSFS_PATH_MAX]; +	int fd; +	ssize_t numread; + +	snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/cpuidle/state%u/%s", +		 cpu, idlestate, fname); + +	fd = open(path, O_RDONLY); +	if (fd == -1) +		return 0; + +	numread = read(fd, buf, buflen - 1); +	if (numread < 1) { +		close(fd); +		return 0; +	} + +	buf[numread] = '\0'; +	close(fd); + +	return (unsigned int) numread; +} + +/*  + * helper function to write a new value to a /sys file + * fname is a relative path under "../cpuX/cpuidle/cstateY/" dir + * + * Returns the number of bytes written or 0 on error + */ +static +unsigned int sysfs_idlestate_write_file(unsigned int cpu, +					unsigned int idlestate, +					const char *fname, +					const char *value, size_t len) +{ +	char path[SYSFS_PATH_MAX]; +	int fd; +	ssize_t numwrite; + +	snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/cpuidle/state%u/%s", +		 cpu, idlestate, fname); + +	fd = open(path, O_WRONLY); +	if (fd == -1) +		return 0; + +	numwrite = write(fd, value, len); +	if (numwrite < 1) { +		close(fd); +		return 0; +	} + +	close(fd); + +	return (unsigned int) numwrite; +} + +/* read access to files which contain one numeric value */ + +enum idlestate_value { +	IDLESTATE_USAGE, +	IDLESTATE_POWER, +	IDLESTATE_LATENCY, +	IDLESTATE_TIME, +	IDLESTATE_DISABLE, +	MAX_IDLESTATE_VALUE_FILES +}; + +static const char *idlestate_value_files[MAX_IDLESTATE_VALUE_FILES] = { +	[IDLESTATE_USAGE] = "usage", +	[IDLESTATE_POWER] = "power", +	[IDLESTATE_LATENCY] = "latency", +	[IDLESTATE_TIME]  = "time", +	[IDLESTATE_DISABLE]  = "disable", +}; + +static unsigned long long sysfs_idlestate_get_one_value(unsigned int cpu, +						     unsigned int idlestate, +						     enum idlestate_value which) +{ +	unsigned long long value; +	unsigned int len; +	char linebuf[MAX_LINE_LEN]; +	char *endp; + +	if (which >= MAX_IDLESTATE_VALUE_FILES) +		return 0; + +	len = sysfs_idlestate_read_file(cpu, idlestate, +					idlestate_value_files[which], +					linebuf, sizeof(linebuf)); +	if (len == 0) +		return 0; + +	value = strtoull(linebuf, &endp, 0); + +	if (endp == linebuf || errno == ERANGE) +		return 0; + +	return value; +} + +/* read access to files which contain one string */ + +enum idlestate_string { +	IDLESTATE_DESC, +	IDLESTATE_NAME, +	MAX_IDLESTATE_STRING_FILES +}; + +static const char *idlestate_string_files[MAX_IDLESTATE_STRING_FILES] = { +	[IDLESTATE_DESC] = "desc", +	[IDLESTATE_NAME] = "name", +}; + + +static char *sysfs_idlestate_get_one_string(unsigned int cpu, +					unsigned int idlestate, +					enum idlestate_string which) +{ +	char linebuf[MAX_LINE_LEN]; +	char *result; +	unsigned int len; + +	if (which >= MAX_IDLESTATE_STRING_FILES) +		return NULL; + +	len = sysfs_idlestate_read_file(cpu, idlestate, +					idlestate_string_files[which], +					linebuf, sizeof(linebuf)); +	if (len == 0) +		return NULL; + +	result = strdup(linebuf); +	if (result == NULL) +		return NULL; + +	if (result[strlen(result) - 1] == '\n') +		result[strlen(result) - 1] = '\0'; + +	return result; +} + +/* + * Returns: + *    1  if disabled + *    0  if enabled + *    -1 if idlestate is not available + *    -2 if disabling is not supported by the kernel + */ +int sysfs_is_idlestate_disabled(unsigned int cpu, +				unsigned int idlestate) +{ +	if (sysfs_get_idlestate_count(cpu) <= idlestate) +		return -1; + +	if (!sysfs_idlestate_file_exists(cpu, idlestate, +				 idlestate_value_files[IDLESTATE_DISABLE])) +		return -2; +	return sysfs_idlestate_get_one_value(cpu, idlestate, IDLESTATE_DISABLE); +} + +/* + * Pass 1 as last argument to disable or 0 to enable the state + * Returns: + *    0  on success + *    negative values on error, for example: + *      -1 if idlestate is not available + *      -2 if disabling is not supported by the kernel + *      -3 No write access to disable/enable C-states + */ +int sysfs_idlestate_disable(unsigned int cpu, +			    unsigned int idlestate, +			    unsigned int disable) +{ +	char value[SYSFS_PATH_MAX]; +	int bytes_written; + +	if (sysfs_get_idlestate_count(cpu) <= idlestate) +		return -1; + +	if (!sysfs_idlestate_file_exists(cpu, idlestate, +				 idlestate_value_files[IDLESTATE_DISABLE])) +		return -2; + +	snprintf(value, SYSFS_PATH_MAX, "%u", disable); + +	bytes_written = sysfs_idlestate_write_file(cpu, idlestate, "disable", +						   value, sizeof(disable)); +	if (bytes_written) +		return 0; +	return -3; +} + +unsigned long sysfs_get_idlestate_latency(unsigned int cpu, +					  unsigned int idlestate) +{ +	return sysfs_idlestate_get_one_value(cpu, idlestate, IDLESTATE_LATENCY); +} + +unsigned long sysfs_get_idlestate_usage(unsigned int cpu, +					unsigned int idlestate) +{ +	return sysfs_idlestate_get_one_value(cpu, idlestate, IDLESTATE_USAGE); +} + +unsigned long long sysfs_get_idlestate_time(unsigned int cpu, +					unsigned int idlestate) +{ +	return sysfs_idlestate_get_one_value(cpu, idlestate, IDLESTATE_TIME); +} + +char *sysfs_get_idlestate_name(unsigned int cpu, unsigned int idlestate) +{ +	return sysfs_idlestate_get_one_string(cpu, idlestate, IDLESTATE_NAME); +} + +char *sysfs_get_idlestate_desc(unsigned int cpu, unsigned int idlestate) +{ +	return sysfs_idlestate_get_one_string(cpu, idlestate, IDLESTATE_DESC); +} + +/* + * Returns number of supported C-states of CPU core cpu + * Negativ in error case + * Zero if cpuidle does not export any C-states + */ +unsigned int sysfs_get_idlestate_count(unsigned int cpu) +{ +	char file[SYSFS_PATH_MAX]; +	struct stat statbuf; +	int idlestates = 1; + + +	snprintf(file, SYSFS_PATH_MAX, PATH_TO_CPU "cpuidle"); +	if (stat(file, &statbuf) != 0 || !S_ISDIR(statbuf.st_mode)) +		return -ENODEV; + +	snprintf(file, SYSFS_PATH_MAX, PATH_TO_CPU "cpu%u/cpuidle/state0", cpu); +	if (stat(file, &statbuf) != 0 || !S_ISDIR(statbuf.st_mode)) +		return 0; + +	while (stat(file, &statbuf) == 0 && S_ISDIR(statbuf.st_mode)) { +		snprintf(file, SYSFS_PATH_MAX, PATH_TO_CPU +			 "cpu%u/cpuidle/state%d", cpu, idlestates); +		idlestates++; +	} +	idlestates--; +	return idlestates; +} + +/* CPUidle general /sys/devices/system/cpu/cpuidle/ sysfs access ********/ + +/* + * helper function to read file from /sys into given buffer + * fname is a relative path under "cpu/cpuidle/" dir + */ +static unsigned int sysfs_cpuidle_read_file(const char *fname, char *buf, +					    size_t buflen) +{ +	char path[SYSFS_PATH_MAX]; + +	snprintf(path, sizeof(path), PATH_TO_CPU "cpuidle/%s", fname); + +	return sysfs_read_file(path, buf, buflen); +} + + + +/* read access to files which contain one string */ + +enum cpuidle_string { +	CPUIDLE_GOVERNOR, +	CPUIDLE_GOVERNOR_RO, +	CPUIDLE_DRIVER, +	MAX_CPUIDLE_STRING_FILES +}; + +static const char *cpuidle_string_files[MAX_CPUIDLE_STRING_FILES] = { +	[CPUIDLE_GOVERNOR]	= "current_governor", +	[CPUIDLE_GOVERNOR_RO]	= "current_governor_ro", +	[CPUIDLE_DRIVER]	= "current_driver", +}; + + +static char *sysfs_cpuidle_get_one_string(enum cpuidle_string which) +{ +	char linebuf[MAX_LINE_LEN]; +	char *result; +	unsigned int len; + +	if (which >= MAX_CPUIDLE_STRING_FILES) +		return NULL; + +	len = sysfs_cpuidle_read_file(cpuidle_string_files[which], +				linebuf, sizeof(linebuf)); +	if (len == 0) +		return NULL; + +	result = strdup(linebuf); +	if (result == NULL) +		return NULL; + +	if (result[strlen(result) - 1] == '\n') +		result[strlen(result) - 1] = '\0'; + +	return result; +} + +char *sysfs_get_cpuidle_governor(void) +{ +	char *tmp = sysfs_cpuidle_get_one_string(CPUIDLE_GOVERNOR_RO); +	if (!tmp) +		return sysfs_cpuidle_get_one_string(CPUIDLE_GOVERNOR); +	else +		return tmp; +} + +char *sysfs_get_cpuidle_driver(void) +{ +	return sysfs_cpuidle_get_one_string(CPUIDLE_DRIVER); +} +/* CPUidle idlestate specific /sys/devices/system/cpu/cpuX/cpuidle/ access */ + +/* + * Get sched_mc or sched_smt settings + * Pass "mc" or "smt" as argument + * + * Returns negative value on failure + */ +int sysfs_get_sched(const char *smt_mc) +{ +	return -ENODEV; +} + +/* + * Get sched_mc or sched_smt settings + * Pass "mc" or "smt" as argument + * + * Returns negative value on failure + */ +int sysfs_set_sched(const char *smt_mc, int val) +{ +	return -ENODEV; +} diff --git a/tools/power/cpupower/utils/helpers/sysfs.h b/tools/power/cpupower/utils/helpers/sysfs.h new file mode 100644 index 00000000000..d28f11fedbd --- /dev/null +++ b/tools/power/cpupower/utils/helpers/sysfs.h @@ -0,0 +1,38 @@ +#ifndef __CPUPOWER_HELPERS_SYSFS_H__ +#define __CPUPOWER_HELPERS_SYSFS_H__ + +#define PATH_TO_CPU "/sys/devices/system/cpu/" +#define MAX_LINE_LEN 255 +#define SYSFS_PATH_MAX 255 + +extern unsigned int sysfs_read_file(const char *path, char *buf, size_t buflen); + +extern unsigned int sysfs_idlestate_file_exists(unsigned int cpu, +						unsigned int idlestate, +						const char *fname); + +extern int sysfs_is_cpu_online(unsigned int cpu); + +extern int sysfs_is_idlestate_disabled(unsigned int cpu, +				       unsigned int idlestate); +extern int sysfs_idlestate_disable(unsigned int cpu, unsigned int idlestate, +				   unsigned int disable); +extern unsigned long sysfs_get_idlestate_latency(unsigned int cpu, +						unsigned int idlestate); +extern unsigned long sysfs_get_idlestate_usage(unsigned int cpu, +					unsigned int idlestate); +extern unsigned long long sysfs_get_idlestate_time(unsigned int cpu, +						unsigned int idlestate); +extern char *sysfs_get_idlestate_name(unsigned int cpu, +				unsigned int idlestate); +extern char *sysfs_get_idlestate_desc(unsigned int cpu, +				unsigned int idlestate); +extern unsigned int sysfs_get_idlestate_count(unsigned int cpu); + +extern char *sysfs_get_cpuidle_governor(void); +extern char *sysfs_get_cpuidle_driver(void); + +extern int sysfs_get_sched(const char *smt_mc); +extern int sysfs_set_sched(const char *smt_mc, int val); + +#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..c13120af519 --- /dev/null +++ b/tools/power/cpupower/utils/helpers/topology.c @@ -0,0 +1,116 @@ +/* + *  (C) 2010,2011       Thomas Renninger <trenn@suse.de>, Novell Inc. + * + *  Licensed under the terms of the GNU GPL License version 2. + * + * ToDo: Needs to be done more properly for AMD/Intel specifics + */ + +/* Helper struct for qsort, must be in sync with cpupower_topology.cpu_info */ +/* Be careful: Need to pass unsigned to the sort, so that offlined cores are +   in the end, but double check for -1 for offlined cpus at other places */ + +#include <stdlib.h> +#include <stdio.h> +#include <unistd.h> +#include <errno.h> +#include <fcntl.h> + +#include <helpers/helpers.h> +#include <helpers/sysfs.h> + +/* returns -1 on failure, 0 on success */ +static int sysfs_topology_read_file(unsigned int cpu, const char *fname, int *result) +{ +	char linebuf[MAX_LINE_LEN]; +	char *endp; +	char path[SYSFS_PATH_MAX]; + +	snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/topology/%s", +			 cpu, fname); +	if (sysfs_read_file(path, linebuf, MAX_LINE_LEN) == 0) +		return -1; +	*result = strtol(linebuf, &endp, 0); +	if (endp == linebuf || errno == ERANGE) +		return -1; +	return 0; +} + +static int __compare(const void *t1, const void *t2) +{ +	struct cpuid_core_info *top1 = (struct cpuid_core_info *)t1; +	struct cpuid_core_info *top2 = (struct cpuid_core_info *)t2; +	if (top1->pkg < top2->pkg) +		return -1; +	else if (top1->pkg > top2->pkg) +		return 1; +	else if (top1->core < top2->core) +		return -1; +	else if (top1->core > top2->core) +		return 1; +	else if (top1->cpu < top2->cpu) +		return -1; +	else if (top1->cpu > top2->cpu) +		return 1; +	else +		return 0; +} + +/* + * Returns amount of cpus, negative on error, cpu_top must be + * passed to cpu_topology_release to free resources + * + * Array is sorted after ->pkg, ->core, then ->cpu + */ +int get_cpu_topology(struct cpupower_topology *cpu_top) +{ +	int cpu, last_pkg, cpus = sysconf(_SC_NPROCESSORS_CONF); + +	cpu_top->core_info = malloc(sizeof(struct cpuid_core_info) * cpus); +	if (cpu_top->core_info == NULL) +		return -ENOMEM; +	cpu_top->pkgs = cpu_top->cores = 0; +	for (cpu = 0; cpu < cpus; cpu++) { +		cpu_top->core_info[cpu].cpu = cpu; +		cpu_top->core_info[cpu].is_online = sysfs_is_cpu_online(cpu); +		if(sysfs_topology_read_file( +			cpu, +			"physical_package_id", +			&(cpu_top->core_info[cpu].pkg)) < 0) +			return -1; +		if(sysfs_topology_read_file( +			cpu, +			"core_id", +			&(cpu_top->core_info[cpu].core)) < 0) +			return -1; +	} + +	qsort(cpu_top->core_info, cpus, sizeof(struct cpuid_core_info), +	      __compare); + +	/* Count the number of distinct pkgs values. This works +	   because the primary sort of the core_info struct was just +	   done by pkg value. */ +	last_pkg = cpu_top->core_info[0].pkg; +	for(cpu = 1; cpu < cpus; cpu++) { +		if(cpu_top->core_info[cpu].pkg != last_pkg) { +			last_pkg = cpu_top->core_info[cpu].pkg; +			cpu_top->pkgs++; +		} +	} +	cpu_top->pkgs++; + +	/* Intel's cores count is not consecutively numbered, there may +	 * be a core_id of 3, but none of 2. Assume there always is 0 +	 * Get amount of cores by counting duplicates in a package +	for (cpu = 0; cpu_top->core_info[cpu].pkg = 0 && cpu < cpus; cpu++) { +		if (cpu_top->core_info[cpu].core == 0) +	cpu_top->cores++; +	*/ +	return cpus; +} + +void cpu_topology_release(struct cpupower_topology cpu_top) +{ +	free(cpu_top.core_info); +} 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..2116df9ad83 --- /dev/null +++ b/tools/power/cpupower/utils/idle_monitor/amd_fam14h_idle.c @@ -0,0 +1,335 @@ +/* + *  (C) 2010,2011      Thomas Renninger <trenn@suse.de>, Novell Inc. + * + *  Licensed under the terms of the GNU GPL License version 2. + * + *  PCI initialization based on example code from: + *  Andreas Herrmann <andreas.herrmann3@amd.com> + */ + +#if defined(__i386__) || defined(__x86_64__) + +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <time.h> +#include <string.h> + +#include <pci/pci.h> + +#include "idle_monitor/cpupower-monitor.h" +#include "helpers/helpers.h" + +#define PCI_NON_PC0_OFFSET	0xb0 +#define PCI_PC1_OFFSET		0xb4 +#define PCI_PC6_OFFSET		0xb8 + +#define PCI_MONITOR_ENABLE_REG  0xe0 + +#define PCI_NON_PC0_ENABLE_BIT	0 +#define PCI_PC1_ENABLE_BIT	1 +#define PCI_PC6_ENABLE_BIT	2 + +#define PCI_NBP1_STAT_OFFSET	0x98 +#define PCI_NBP1_ACTIVE_BIT	2 +#define PCI_NBP1_ENTERED_BIT	1 + +#define PCI_NBP1_CAP_OFFSET	0x90 +#define PCI_NBP1_CAPABLE_BIT    31 + +#define OVERFLOW_MS		343597 /* 32 bit register filled at 12500 HZ +					  (1 tick per 80ns) */ + +enum amd_fam14h_states {NON_PC0 = 0, PC1, PC6, NBP1, +			AMD_FAM14H_STATE_NUM}; + +static int fam14h_get_count_percent(unsigned int self_id, double *percent, +				    unsigned int cpu); +static int fam14h_nbp1_count(unsigned int id, unsigned long long *count, +			     unsigned int cpu); + +static cstate_t amd_fam14h_cstates[AMD_FAM14H_STATE_NUM] = { +	{ +		.name			= "!PC0", +		.desc			= N_("Package in sleep state (PC1 or deeper)"), +		.id			= NON_PC0, +		.range			= RANGE_PACKAGE, +		.get_count_percent	= fam14h_get_count_percent, +	}, +	{ +		.name			= "PC1", +		.desc			= N_("Processor Package C1"), +		.id			= PC1, +		.range			= RANGE_PACKAGE, +		.get_count_percent	= fam14h_get_count_percent, +	}, +	{ +		.name			= "PC6", +		.desc			= N_("Processor Package C6"), +		.id			= PC6, +		.range			= RANGE_PACKAGE, +		.get_count_percent	= fam14h_get_count_percent, +	}, +	{ +		.name			= "NBP1", +		.desc			= N_("North Bridge P1 boolean counter (returns 0 or 1)"), +		.id			= NBP1, +		.range			= RANGE_PACKAGE, +		.get_count		= fam14h_nbp1_count, +	}, +}; + +static struct pci_access *pci_acc; +static struct pci_dev *amd_fam14h_pci_dev; +static int nbp1_entered; + +struct timespec start_time; +static unsigned long long timediff; + +#ifdef DEBUG +struct timespec dbg_time; +long dbg_timediff; +#endif + +static unsigned long long *previous_count[AMD_FAM14H_STATE_NUM]; +static unsigned long long *current_count[AMD_FAM14H_STATE_NUM]; + +static int amd_fam14h_get_pci_info(struct cstate *state, +				   unsigned int *pci_offset, +				   unsigned int *enable_bit, +				   unsigned int cpu) +{ +	switch (state->id) { +	case NON_PC0: +		*enable_bit = PCI_NON_PC0_ENABLE_BIT; +		*pci_offset = PCI_NON_PC0_OFFSET; +		break; +	case PC1: +		*enable_bit = PCI_PC1_ENABLE_BIT; +		*pci_offset = PCI_PC1_OFFSET; +		break; +	case PC6: +		*enable_bit = PCI_PC6_ENABLE_BIT; +		*pci_offset = PCI_PC6_OFFSET; +		break; +	case NBP1: +		*enable_bit = PCI_NBP1_ENTERED_BIT; +		*pci_offset = PCI_NBP1_STAT_OFFSET; +		break; +	default: +		return -1; +	}; +	return 0; +} + +static int amd_fam14h_init(cstate_t *state, unsigned int cpu) +{ +	int enable_bit, pci_offset, ret; +	uint32_t val; + +	ret = amd_fam14h_get_pci_info(state, &pci_offset, &enable_bit, cpu); +	if (ret) +		return ret; + +	/* NBP1 needs extra treating -> write 1 to D18F6x98 bit 1 for init */ +	if (state->id == NBP1) { +		val = pci_read_long(amd_fam14h_pci_dev, pci_offset); +		val |= 1 << enable_bit; +		val = pci_write_long(amd_fam14h_pci_dev, pci_offset, val); +		return ret; +	} + +	/* Enable monitor */ +	val = pci_read_long(amd_fam14h_pci_dev, PCI_MONITOR_ENABLE_REG); +	dprint("Init %s: read at offset: 0x%x val: %u\n", state->name, +	       PCI_MONITOR_ENABLE_REG, (unsigned int) val); +	val |= 1 << enable_bit; +	pci_write_long(amd_fam14h_pci_dev, PCI_MONITOR_ENABLE_REG, val); + +	dprint("Init %s: offset: 0x%x enable_bit: %d - val: %u (%u)\n", +	       state->name, PCI_MONITOR_ENABLE_REG, enable_bit, +	       (unsigned int) val, cpu); + +	/* Set counter to zero */ +	pci_write_long(amd_fam14h_pci_dev, pci_offset, 0); +	previous_count[state->id][cpu] = 0; + +	return 0; +} + +static int amd_fam14h_disable(cstate_t *state, unsigned int cpu) +{ +	int enable_bit, pci_offset, ret; +	uint32_t val; + +	ret = amd_fam14h_get_pci_info(state, &pci_offset, &enable_bit, cpu); +	if (ret) +		return ret; + +	val = pci_read_long(amd_fam14h_pci_dev, pci_offset); +	dprint("%s: offset: 0x%x %u\n", state->name, pci_offset, val); +	if (state->id == NBP1) { +		/* was the bit whether NBP1 got entered set? */ +		nbp1_entered = (val & (1 << PCI_NBP1_ACTIVE_BIT)) | +			(val & (1 << PCI_NBP1_ENTERED_BIT)); + +		dprint("NBP1 was %sentered - 0x%x - enable_bit: " +		       "%d - pci_offset: 0x%x\n", +		       nbp1_entered ? "" : "not ", +		       val, enable_bit, pci_offset); +		return ret; +	} +	current_count[state->id][cpu] = val; + +	dprint("%s: Current -  %llu (%u)\n", state->name, +	       current_count[state->id][cpu], cpu); +	dprint("%s: Previous - %llu (%u)\n", state->name, +	       previous_count[state->id][cpu], cpu); + +	val = pci_read_long(amd_fam14h_pci_dev, PCI_MONITOR_ENABLE_REG); +	val &= ~(1 << enable_bit); +	pci_write_long(amd_fam14h_pci_dev, PCI_MONITOR_ENABLE_REG, val); + +	return 0; +} + +static int fam14h_nbp1_count(unsigned int id, unsigned long long *count, +			     unsigned int cpu) +{ +	if (id == NBP1) { +		if (nbp1_entered) +			*count = 1; +		else +			*count = 0; +		return 0; +	} +	return -1; +} +static int fam14h_get_count_percent(unsigned int id, double *percent, +				    unsigned int cpu) +{ +	unsigned long diff; + +	if (id >= AMD_FAM14H_STATE_NUM) +		return -1; +	/* residency count in 80ns -> divide through 12.5 to get us residency */ +	diff = current_count[id][cpu] - previous_count[id][cpu]; + +	if (timediff == 0) +		*percent = 0.0; +	else +		*percent = 100.0 * diff / timediff / 12.5; + +	dprint("Timediff: %llu - res~: %lu us - percent: %.2f %%\n", +	       timediff, diff * 10 / 125, *percent); + +	return 0; +} + +static int amd_fam14h_start(void) +{ +	int num, cpu; +	clock_gettime(CLOCK_REALTIME, &start_time); +	for (num = 0; num < AMD_FAM14H_STATE_NUM; num++) { +		for (cpu = 0; cpu < cpu_count; cpu++) +			amd_fam14h_init(&amd_fam14h_cstates[num], cpu); +	} +#ifdef DEBUG +	clock_gettime(CLOCK_REALTIME, &dbg_time); +	dbg_timediff = timespec_diff_us(start_time, dbg_time); +	dprint("Enabling counters took: %lu us\n", +	       dbg_timediff); +#endif +	return 0; +} + +static int amd_fam14h_stop(void) +{ +	int num, cpu; +	struct timespec end_time; + +	clock_gettime(CLOCK_REALTIME, &end_time); + +	for (num = 0; num < AMD_FAM14H_STATE_NUM; num++) { +		for (cpu = 0; cpu < cpu_count; cpu++) +			amd_fam14h_disable(&amd_fam14h_cstates[num], cpu); +	} +#ifdef DEBUG +	clock_gettime(CLOCK_REALTIME, &dbg_time); +	dbg_timediff = timespec_diff_us(end_time, dbg_time); +	dprint("Disabling counters took: %lu ns\n", dbg_timediff); +#endif +	timediff = timespec_diff_us(start_time, end_time); +	if (timediff / 1000 > OVERFLOW_MS) +		print_overflow_err((unsigned int)timediff / 1000000, +				   OVERFLOW_MS / 1000); + +	return 0; +} + +static int is_nbp1_capable(void) +{ +	uint32_t val; +	val = pci_read_long(amd_fam14h_pci_dev, PCI_NBP1_CAP_OFFSET); +	return val & (1 << 31); +} + +struct cpuidle_monitor *amd_fam14h_register(void) +{ +	int num; + +	if (cpupower_cpu_info.vendor != X86_VENDOR_AMD) +		return NULL; + +	if (cpupower_cpu_info.family == 0x14) +		strncpy(amd_fam14h_monitor.name, "Fam_14h", +			MONITOR_NAME_LEN - 1); +	else if (cpupower_cpu_info.family == 0x12) +		strncpy(amd_fam14h_monitor.name, "Fam_12h", +			MONITOR_NAME_LEN - 1); +	else +		return NULL; + +	/* We do not alloc for nbp1 machine wide counter */ +	for (num = 0; num < AMD_FAM14H_STATE_NUM - 1; num++) { +		previous_count[num] = calloc(cpu_count, +					      sizeof(unsigned long long)); +		current_count[num]  = calloc(cpu_count, +					      sizeof(unsigned long long)); +	} + +	/* We need PCI device: Slot 18, Func 6, compare with BKDG +	   for fam 12h/14h */ +	amd_fam14h_pci_dev = pci_slot_func_init(&pci_acc, 0x18, 6); +	if (amd_fam14h_pci_dev == NULL || pci_acc == NULL) +		return NULL; + +	if (!is_nbp1_capable()) +		amd_fam14h_monitor.hw_states_num = AMD_FAM14H_STATE_NUM - 1; + +	amd_fam14h_monitor.name_len = strlen(amd_fam14h_monitor.name); +	return &amd_fam14h_monitor; +} + +static void amd_fam14h_unregister(void) +{ +	int num; +	for (num = 0; num < AMD_FAM14H_STATE_NUM - 1; num++) { +		free(previous_count[num]); +		free(current_count[num]); +	} +	pci_cleanup(pci_acc); +} + +struct cpuidle_monitor amd_fam14h_monitor = { +	.name			= "", +	.hw_states		= amd_fam14h_cstates, +	.hw_states_num		= AMD_FAM14H_STATE_NUM, +	.start			= amd_fam14h_start, +	.stop			= amd_fam14h_stop, +	.do_register		= amd_fam14h_register, +	.unregister		= amd_fam14h_unregister, +	.needs_root		= 1, +	.overflow_s		= OVERFLOW_MS / 1000, +}; +#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..bcd22a1a397 --- /dev/null +++ b/tools/power/cpupower/utils/idle_monitor/cpuidle_sysfs.c @@ -0,0 +1,196 @@ +/* + *  (C) 2010,2011       Thomas Renninger <trenn@suse.de>, Novell Inc + * + *  Licensed under the terms of the GNU GPL License version 2. + * + */ + +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <string.h> +#include <limits.h> + +#include "helpers/sysfs.h" +#include "helpers/helpers.h" +#include "idle_monitor/cpupower-monitor.h" + +#define CPUIDLE_STATES_MAX 10 +static cstate_t cpuidle_cstates[CPUIDLE_STATES_MAX]; +struct cpuidle_monitor cpuidle_sysfs_monitor; + +static unsigned long long **previous_count; +static unsigned long long **current_count; +struct timespec start_time; +static unsigned long long timediff; + +static int cpuidle_get_count_percent(unsigned int id, double *percent, +				     unsigned int cpu) +{ +	unsigned long long statediff = current_count[cpu][id] +		- previous_count[cpu][id]; +	dprint("%s: - diff: %llu - percent: %f (%u)\n", +	       cpuidle_cstates[id].name, timediff, *percent, cpu); + +	if (timediff == 0) +		*percent = 0.0; +	else +		*percent = ((100.0 * statediff) / timediff); + +	dprint("%s: - timediff: %llu - statediff: %llu - percent: %f (%u)\n", +	       cpuidle_cstates[id].name, timediff, statediff, *percent, cpu); + +	return 0; +} + +static int cpuidle_start(void) +{ +	int cpu, state; +	clock_gettime(CLOCK_REALTIME, &start_time); +	for (cpu = 0; cpu < cpu_count; cpu++) { +		for (state = 0; state < cpuidle_sysfs_monitor.hw_states_num; +		     state++) { +			previous_count[cpu][state] = +				sysfs_get_idlestate_time(cpu, state); +			dprint("CPU %d - State: %d - Val: %llu\n", +			       cpu, state, previous_count[cpu][state]); +		} +	}; +	return 0; +} + +static int cpuidle_stop(void) +{ +	int cpu, state; +	struct timespec end_time; +	clock_gettime(CLOCK_REALTIME, &end_time); +	timediff = timespec_diff_us(start_time, end_time); + +	for (cpu = 0; cpu < cpu_count; cpu++) { +		for (state = 0; state < cpuidle_sysfs_monitor.hw_states_num; +		     state++) { +			current_count[cpu][state] = +				sysfs_get_idlestate_time(cpu, state); +			dprint("CPU %d - State: %d - Val: %llu\n", +			       cpu, state, previous_count[cpu][state]); +		} +	}; +	return 0; +} + +void fix_up_intel_idle_driver_name(char *tmp, int num) +{ +	/* fix up cpuidle name for intel idle driver */ +	if (!strncmp(tmp, "NHM-", 4)) { +		switch (num) { +		case 1: +			strcpy(tmp, "C1"); +			break; +		case 2: +			strcpy(tmp, "C3"); +			break; +		case 3: +			strcpy(tmp, "C6"); +			break; +		} +	} else if (!strncmp(tmp, "SNB-", 4)) { +		switch (num) { +		case 1: +			strcpy(tmp, "C1"); +			break; +		case 2: +			strcpy(tmp, "C3"); +			break; +		case 3: +			strcpy(tmp, "C6"); +			break; +		case 4: +			strcpy(tmp, "C7"); +			break; +		} +	} else if (!strncmp(tmp, "ATM-", 4)) { +		switch (num) { +		case 1: +			strcpy(tmp, "C1"); +			break; +		case 2: +			strcpy(tmp, "C2"); +			break; +		case 3: +			strcpy(tmp, "C4"); +			break; +		case 4: +			strcpy(tmp, "C6"); +			break; +		} +	} +} + +static struct cpuidle_monitor *cpuidle_register(void) +{ +	int num; +	char *tmp; + +	/* Assume idle state count is the same for all CPUs */ +	cpuidle_sysfs_monitor.hw_states_num = sysfs_get_idlestate_count(0); + +	if (cpuidle_sysfs_monitor.hw_states_num <= 0) +		return NULL; + +	for (num = 0; num < cpuidle_sysfs_monitor.hw_states_num; num++) { +		tmp = sysfs_get_idlestate_name(0, num); +		if (tmp == NULL) +			continue; + +		fix_up_intel_idle_driver_name(tmp, num); +		strncpy(cpuidle_cstates[num].name, tmp, CSTATE_NAME_LEN - 1); +		free(tmp); + +		tmp = sysfs_get_idlestate_desc(0, num); +		if (tmp == NULL) +			continue; +		strncpy(cpuidle_cstates[num].desc, tmp,	CSTATE_DESC_LEN - 1); +		free(tmp); + +		cpuidle_cstates[num].range = RANGE_THREAD; +		cpuidle_cstates[num].id = num; +		cpuidle_cstates[num].get_count_percent = +			cpuidle_get_count_percent; +	}; + +	/* Free this at program termination */ +	previous_count = malloc(sizeof(long long *) * cpu_count); +	current_count = malloc(sizeof(long long *) * cpu_count); +	for (num = 0; num < cpu_count; num++) { +		previous_count[num] = malloc(sizeof(long long) * +					cpuidle_sysfs_monitor.hw_states_num); +		current_count[num] = malloc(sizeof(long long) * +					cpuidle_sysfs_monitor.hw_states_num); +	} + +	cpuidle_sysfs_monitor.name_len = strlen(cpuidle_sysfs_monitor.name); +	return &cpuidle_sysfs_monitor; +} + +void cpuidle_unregister(void) +{ +	int num; + +	for (num = 0; num < cpu_count; num++) { +		free(previous_count[num]); +		free(current_count[num]); +	} +	free(previous_count); +	free(current_count); +} + +struct cpuidle_monitor cpuidle_sysfs_monitor = { +	.name			= "Idle_Stats", +	.hw_states		= cpuidle_cstates, +	.start			= cpuidle_start, +	.stop			= cpuidle_stop, +	.do_register		= cpuidle_register, +	.unregister		= cpuidle_unregister, +	.needs_root		= 0, +	.overflow_s		= UINT_MAX, +}; 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..c4bae9203a6 --- /dev/null +++ b/tools/power/cpupower/utils/idle_monitor/cpupower-monitor.c @@ -0,0 +1,455 @@ +/* + *  (C) 2010,2011       Thomas Renninger <trenn@suse.de>, Novell Inc. + * + *  Licensed under the terms of the GNU GPL License version 2. + * + *  Output format inspired by Len Brown's <lenb@kernel.org> turbostat tool. + * + */ + + +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <signal.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <libgen.h> + +#include "idle_monitor/cpupower-monitor.h" +#include "idle_monitor/idle_monitors.h" +#include "helpers/helpers.h" + +/* Define pointers to all monitors.  */ +#define DEF(x) & x ## _monitor , +struct cpuidle_monitor *all_monitors[] = { +#include "idle_monitors.def" +0 +}; + +static struct cpuidle_monitor *monitors[MONITORS_MAX]; +static unsigned int avail_monitors; + +static char *progname; + +enum operation_mode_e { list = 1, show, show_all }; +static int mode; +static int interval = 1; +static char *show_monitors_param; +static struct cpupower_topology cpu_top; +static unsigned int wake_cpus; + +/* ToDo: Document this in the manpage */ +static char range_abbr[RANGE_MAX] = { 'T', 'C', 'P', 'M', }; + +static void print_wrong_arg_exit(void) +{ +	printf(_("invalid or unknown argument\n")); +	exit(EXIT_FAILURE); +} + +long long timespec_diff_us(struct timespec start, struct timespec end) +{ +	struct timespec temp; +	if ((end.tv_nsec - start.tv_nsec) < 0) { +		temp.tv_sec = end.tv_sec - start.tv_sec - 1; +		temp.tv_nsec = 1000000000 + end.tv_nsec - start.tv_nsec; +	} else { +		temp.tv_sec = end.tv_sec - start.tv_sec; +		temp.tv_nsec = end.tv_nsec - start.tv_nsec; +	} +	return (temp.tv_sec * 1000000) + (temp.tv_nsec / 1000); +} + +void print_n_spaces(int n) +{ +	int x; +	for (x = 0; x < n; x++) +		printf(" "); +} + +/* size of s must be at least n + 1 */ +int fill_string_with_spaces(char *s, int n) +{ +	int len = strlen(s); +	if (len > n) +		return -1; +	for (; len < n; len++) +		s[len] = ' '; +	s[len] = '\0'; +	return 0; +} + +void print_header(int topology_depth) +{ +	int unsigned mon; +	int state, need_len; +	cstate_t s; +	char buf[128] = ""; +	int percent_width = 4; + +	fill_string_with_spaces(buf, topology_depth * 5 - 1); +	printf("%s|", buf); + +	for (mon = 0; mon < avail_monitors; mon++) { +		need_len = monitors[mon]->hw_states_num * (percent_width + 3) +			- 1; +		if (mon != 0) { +			printf("|| "); +			need_len--; +		} +		sprintf(buf, "%s", monitors[mon]->name); +		fill_string_with_spaces(buf, need_len); +		printf("%s", buf); +	} +	printf("\n"); + +	if (topology_depth > 2) +		printf("PKG |"); +	if (topology_depth > 1) +		printf("CORE|"); +	if (topology_depth > 0) +		printf("CPU |"); + +	for (mon = 0; mon < avail_monitors; mon++) { +		if (mon != 0) +			printf("|| "); +		else +			printf(" "); +		for (state = 0; state < monitors[mon]->hw_states_num; state++) { +			if (state != 0) +				printf(" | "); +			s = monitors[mon]->hw_states[state]; +			sprintf(buf, "%s", s.name); +			fill_string_with_spaces(buf, percent_width); +			printf("%s", buf); +		} +		printf(" "); +	} +	printf("\n"); +} + + +void print_results(int topology_depth, int cpu) +{ +	unsigned int mon; +	int state, ret; +	double percent; +	unsigned long long result; +	cstate_t s; + +	/* Be careful CPUs may got resorted for pkg value do not just use cpu */ +	if (!bitmask_isbitset(cpus_chosen, cpu_top.core_info[cpu].cpu)) +		return; + +	if (topology_depth > 2) +		printf("%4d|", cpu_top.core_info[cpu].pkg); +	if (topology_depth > 1) +		printf("%4d|", cpu_top.core_info[cpu].core); +	if (topology_depth > 0) +		printf("%4d|", cpu_top.core_info[cpu].cpu); + +	for (mon = 0; mon < avail_monitors; mon++) { +		if (mon != 0) +			printf("||"); + +		for (state = 0; state < monitors[mon]->hw_states_num; state++) { +			if (state != 0) +				printf("|"); + +			s = monitors[mon]->hw_states[state]; + +			if (s.get_count_percent) { +				ret = s.get_count_percent(s.id, &percent, +						  cpu_top.core_info[cpu].cpu); +				if (ret) +					printf("******"); +				else if (percent >= 100.0) +					printf("%6.1f", percent); +				else +					printf("%6.2f", percent); +			} else if (s.get_count) { +				ret = s.get_count(s.id, &result, +						  cpu_top.core_info[cpu].cpu); +				if (ret) +					printf("******"); +				else +					printf("%6llu", result); +			} else { +				printf(_("Monitor %s, Counter %s has no count " +					 "function. Implementation error\n"), +				       monitors[mon]->name, s.name); +				exit(EXIT_FAILURE); +			} +		} +	} +	/* +	 * The monitor could still provide useful data, for example +	 * AMD HW counters partly sit in PCI config space. +	 * It's up to the monitor plug-in to check .is_online, this one +	 * is just for additional info. +	 */ +	if (!cpu_top.core_info[cpu].is_online) { +		printf(_(" *is offline\n")); +		return; +	} else +		printf("\n"); +} + + +/* param: string passed by -m param (The list of monitors to show) + * + * Monitors must have been registered already, matching monitors + * are picked out and available monitors array is overridden + * with matching ones + * + * Monitors get sorted in the same order the user passes them +*/ + +static void parse_monitor_param(char *param) +{ +	unsigned int num; +	int mon, hits = 0; +	char *tmp = param, *token; +	struct cpuidle_monitor *tmp_mons[MONITORS_MAX]; + + +	for (mon = 0; mon < MONITORS_MAX; mon++, tmp = NULL) { +		token = strtok(tmp, ","); +		if (token == NULL) +			break; +		if (strlen(token) >= MONITOR_NAME_LEN) { +			printf(_("%s: max monitor name length" +				 " (%d) exceeded\n"), token, MONITOR_NAME_LEN); +			continue; +		} + +		for (num = 0; num < avail_monitors; num++) { +			if (!strcmp(monitors[num]->name, token)) { +				dprint("Found requested monitor: %s\n", token); +				tmp_mons[hits] = monitors[num]; +				hits++; +			} +		} +	} +	if (hits == 0) { +		printf(_("No matching monitor found in %s, " +			 "try -l option\n"), param); +		exit(EXIT_FAILURE); +	} +	/* Override detected/registerd monitors array with requested one */ +	memcpy(monitors, tmp_mons, +		sizeof(struct cpuidle_monitor *) * MONITORS_MAX); +	avail_monitors = hits; +} + +void list_monitors(void) +{ +	unsigned int mon; +	int state; +	cstate_t s; + +	for (mon = 0; mon < avail_monitors; mon++) { +		printf(_("Monitor \"%s\" (%d states) - Might overflow after %u " +			 "s\n"), +			monitors[mon]->name, monitors[mon]->hw_states_num, +			monitors[mon]->overflow_s); + +		for (state = 0; state < monitors[mon]->hw_states_num; state++) { +			s = monitors[mon]->hw_states[state]; +			/* +			 * ToDo show more state capabilities: +			 * percent, time (granlarity) +			 */ +			printf("%s\t[%c] -> %s\n", s.name, range_abbr[s.range], +			       gettext(s.desc)); +		} +	} +} + +int fork_it(char **argv) +{ +	int status; +	unsigned int num; +	unsigned long long timediff; +	pid_t child_pid; +	struct timespec start, end; + +	child_pid = fork(); +	clock_gettime(CLOCK_REALTIME, &start); + +	for (num = 0; num < avail_monitors; num++) +		monitors[num]->start(); + +	if (!child_pid) { +		/* child */ +		execvp(argv[0], argv); +	} else { +		/* parent */ +		if (child_pid == -1) { +			perror("fork"); +			exit(1); +		} + +		signal(SIGINT, SIG_IGN); +		signal(SIGQUIT, SIG_IGN); +		if (waitpid(child_pid, &status, 0) == -1) { +			perror("wait"); +			exit(1); +		} +	} +	clock_gettime(CLOCK_REALTIME, &end); +	for (num = 0; num < avail_monitors; num++) +		monitors[num]->stop(); + +	timediff = timespec_diff_us(start, end); +	if (WIFEXITED(status)) +		printf(_("%s took %.5f seconds and exited with status %d\n"), +			argv[0], timediff / (1000.0 * 1000), +			WEXITSTATUS(status)); +	return 0; +} + +int do_interval_measure(int i) +{ +	unsigned int num; +	int cpu; + +	if (wake_cpus) +		for (cpu = 0; cpu < cpu_count; cpu++) +			bind_cpu(cpu); + +	for (num = 0; num < avail_monitors; num++) { +		dprint("HW C-state residency monitor: %s - States: %d\n", +		       monitors[num]->name, monitors[num]->hw_states_num); +		monitors[num]->start(); +	} + +	sleep(i); + +	if (wake_cpus) +		for (cpu = 0; cpu < cpu_count; cpu++) +			bind_cpu(cpu); + +	for (num = 0; num < avail_monitors; num++) +		monitors[num]->stop(); + + +	return 0; +} + +static void cmdline(int argc, char *argv[]) +{ +	int opt; +	progname = basename(argv[0]); + +	while ((opt = getopt(argc, argv, "+lci:m:")) != -1) { +		switch (opt) { +		case 'l': +			if (mode) +				print_wrong_arg_exit(); +			mode = list; +			break; +		case 'i': +			/* only allow -i with -m or no option */ +			if (mode && mode != show) +				print_wrong_arg_exit(); +			interval = atoi(optarg); +			break; +		case 'm': +			if (mode) +				print_wrong_arg_exit(); +			mode = show; +			show_monitors_param = optarg; +			break; +		case 'c': +			wake_cpus = 1; +			break; +		default: +			print_wrong_arg_exit(); +		} +	} +	if (!mode) +		mode = show_all; +} + +int cmd_monitor(int argc, char **argv) +{ +	unsigned int num; +	struct cpuidle_monitor *test_mon; +	int cpu; + +	cmdline(argc, argv); +	cpu_count = get_cpu_topology(&cpu_top); +	if (cpu_count < 0) { +		printf(_("Cannot read number of available processors\n")); +		return EXIT_FAILURE; +	} + +	/* Default is: monitor all CPUs */ +	if (bitmask_isallclear(cpus_chosen)) +		bitmask_setall(cpus_chosen); + +	dprint("System has up to %d CPU cores\n", cpu_count); + +	for (num = 0; all_monitors[num]; num++) { +		dprint("Try to register: %s\n", all_monitors[num]->name); +		test_mon = all_monitors[num]->do_register(); +		if (test_mon) { +			if (test_mon->needs_root && !run_as_root) { +				fprintf(stderr, _("Available monitor %s needs " +					  "root access\n"), test_mon->name); +				continue; +			} +			monitors[avail_monitors] = test_mon; +			dprint("%s registered\n", all_monitors[num]->name); +			avail_monitors++; +		} +	} + +	if (avail_monitors == 0) { +		printf(_("No HW Cstate monitors found\n")); +		return 1; +	} + +	if (mode == list) { +		list_monitors(); +		exit(EXIT_SUCCESS); +	} + +	if (mode == show) +		parse_monitor_param(show_monitors_param); + +	dprint("Packages: %d - Cores: %d - CPUs: %d\n", +	       cpu_top.pkgs, cpu_top.cores, cpu_count); + +	/* +	 * if any params left, it must be a command to fork +	 */ +	if (argc - optind) +		fork_it(argv + optind); +	else +		do_interval_measure(interval); + +	/* ToDo: Topology parsing needs fixing first to do +	   this more generically */ +	if (cpu_top.pkgs > 1) +		print_header(3); +	else +		print_header(1); + +	for (cpu = 0; cpu < cpu_count; cpu++) { +		if (cpu_top.pkgs > 1) +			print_results(3, cpu); +		else +			print_results(1, cpu); +	} + +	for (num = 0; num < avail_monitors; num++) +		monitors[num]->unregister(); + +	cpu_topology_release(cpu_top); +	return 0; +} 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..9e43f3371fb --- /dev/null +++ b/tools/power/cpupower/utils/idle_monitor/cpupower-monitor.h @@ -0,0 +1,85 @@ +/* + *  (C) 2010,2011       Thomas Renninger <trenn@suse.de>, Novell Inc. + * + *  Licensed under the terms of the GNU GPL License version 2. + * + */ + +#ifndef __CPUIDLE_INFO_HW__ +#define __CPUIDLE_INFO_HW__ + +#include <stdarg.h> +#include <time.h> + +#include "idle_monitor/idle_monitors.h" + +#define MONITORS_MAX 20 +#define MONITOR_NAME_LEN 20 +#define CSTATE_NAME_LEN 5 +#define CSTATE_DESC_LEN 60 + +int cpu_count; + +/* Hard to define the right names ...: */ +enum power_range_e { +	RANGE_THREAD,	/* Lowest in topology hierarcy, AMD: core, Intel: thread +			   kernel sysfs: cpu */ +	RANGE_CORE,	/* AMD: unit, Intel: core, kernel_sysfs: core_id */ +	RANGE_PACKAGE,	/* Package, processor socket */ +	RANGE_MACHINE,	/* Machine, platform wide */ +	RANGE_MAX }; + +typedef struct cstate { +	int  id; +	enum power_range_e range; +	char name[CSTATE_NAME_LEN]; +	char desc[CSTATE_DESC_LEN]; + +	/* either provide a percentage or a general count */ +	int (*get_count_percent)(unsigned int self_id, double *percent, +				 unsigned int cpu); +	int (*get_count)(unsigned int self_id, unsigned long long *count, +			 unsigned int cpu); +} cstate_t; + +struct cpuidle_monitor { +	/* Name must not contain whitespaces */ +	char name[MONITOR_NAME_LEN]; +	int name_len; +	int hw_states_num; +	cstate_t *hw_states; +	int (*start) (void); +	int (*stop) (void); +	struct cpuidle_monitor* (*do_register) (void); +	void (*unregister)(void); +	unsigned int overflow_s; +	int needs_root; +}; + +extern long long timespec_diff_us(struct timespec start, struct timespec end); + +#define print_overflow_err(mes, ov)						\ +{										\ +	fprintf(stderr, gettext("Measure took %u seconds, but registers could "	\ +				"overflow at %u seconds, results "		\ +				"could be inaccurate\n"), mes, ov);		\ +} + + +/* Taken over from x86info project sources  -> return 0 on success */ +#include <sched.h> +#include <sys/types.h> +#include <unistd.h> +static inline int bind_cpu(int cpu) +{ +	cpu_set_t set; + +	if (sched_getaffinity(getpid(), sizeof(set), &set) == 0) { +		CPU_ZERO(&set); +		CPU_SET(cpu, &set); +		return sched_setaffinity(getpid(), sizeof(set), &set); +	} +	return 1; +} + +#endif /* __CPUIDLE_INFO_HW__ */ diff --git a/tools/power/cpupower/utils/idle_monitor/hsw_ext_idle.c b/tools/power/cpupower/utils/idle_monitor/hsw_ext_idle.c new file mode 100644 index 00000000000..ebeaba6571a --- /dev/null +++ b/tools/power/cpupower/utils/idle_monitor/hsw_ext_idle.c @@ -0,0 +1,196 @@ +/* + *  (C) 2010,2011       Thomas Renninger <trenn@suse.de>, Novell Inc. + * + *  Licensed under the terms of the GNU GPL License version 2. + * + *  Based on SandyBridge monitor. Implements the new package C-states + *  (PC8, PC9, PC10) coming with a specific Haswell (family 0x45) CPU. + */ + +#if defined(__i386__) || defined(__x86_64__) + +#include <stdio.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> + +#include "helpers/helpers.h" +#include "idle_monitor/cpupower-monitor.h" + +#define MSR_PKG_C8_RESIDENCY           0x00000630 +#define MSR_PKG_C9_RESIDENCY           0x00000631 +#define MSR_PKG_C10_RESIDENCY          0x00000632 + +#define MSR_TSC	0x10 + +enum intel_hsw_ext_id { PC8 = 0, PC9, PC10, HSW_EXT_CSTATE_COUNT, +			TSC = 0xFFFF }; + +static int hsw_ext_get_count_percent(unsigned int self_id, double *percent, +				 unsigned int cpu); + +static cstate_t hsw_ext_cstates[HSW_EXT_CSTATE_COUNT] = { +	{ +		.name			= "PC8", +		.desc			= N_("Processor Package C8"), +		.id			= PC8, +		.range			= RANGE_PACKAGE, +		.get_count_percent	= hsw_ext_get_count_percent, +	}, +	{ +		.name			= "PC9", +		.desc			= N_("Processor Package C9"), +		.desc			= N_("Processor Package C2"), +		.id			= PC9, +		.range			= RANGE_PACKAGE, +		.get_count_percent	= hsw_ext_get_count_percent, +	}, +	{ +		.name			= "PC10", +		.desc			= N_("Processor Package C10"), +		.id			= PC10, +		.range			= RANGE_PACKAGE, +		.get_count_percent	= hsw_ext_get_count_percent, +	}, +}; + +static unsigned long long tsc_at_measure_start; +static unsigned long long tsc_at_measure_end; +static unsigned long long *previous_count[HSW_EXT_CSTATE_COUNT]; +static unsigned long long *current_count[HSW_EXT_CSTATE_COUNT]; +/* valid flag for all CPUs. If a MSR read failed it will be zero */ +static int *is_valid; + +static int hsw_ext_get_count(enum intel_hsw_ext_id id, unsigned long long *val, +			unsigned int cpu) +{ +	int msr; + +	switch (id) { +	case PC8: +		msr = MSR_PKG_C8_RESIDENCY; +		break; +	case PC9: +		msr = MSR_PKG_C9_RESIDENCY; +		break; +	case PC10: +		msr = MSR_PKG_C10_RESIDENCY; +		break; +	case TSC: +		msr = MSR_TSC; +		break; +	default: +		return -1; +	}; +	if (read_msr(cpu, msr, val)) +		return -1; +	return 0; +} + +static int hsw_ext_get_count_percent(unsigned int id, double *percent, +				 unsigned int cpu) +{ +	*percent = 0.0; + +	if (!is_valid[cpu]) +		return -1; + +	*percent = (100.0 * +		(current_count[id][cpu] - previous_count[id][cpu])) / +		(tsc_at_measure_end - tsc_at_measure_start); + +	dprint("%s: previous: %llu - current: %llu - (%u)\n", +		hsw_ext_cstates[id].name, previous_count[id][cpu], +		current_count[id][cpu], cpu); + +	dprint("%s: tsc_diff: %llu - count_diff: %llu - percent: %2.f (%u)\n", +	       hsw_ext_cstates[id].name, +	       (unsigned long long) tsc_at_measure_end - tsc_at_measure_start, +	       current_count[id][cpu] - previous_count[id][cpu], +	       *percent, cpu); + +	return 0; +} + +static int hsw_ext_start(void) +{ +	int num, cpu; +	unsigned long long val; + +	for (num = 0; num < HSW_EXT_CSTATE_COUNT; num++) { +		for (cpu = 0; cpu < cpu_count; cpu++) { +			hsw_ext_get_count(num, &val, cpu); +			previous_count[num][cpu] = val; +		} +	} +	hsw_ext_get_count(TSC, &tsc_at_measure_start, 0); +	return 0; +} + +static int hsw_ext_stop(void) +{ +	unsigned long long val; +	int num, cpu; + +	hsw_ext_get_count(TSC, &tsc_at_measure_end, 0); + +	for (num = 0; num < HSW_EXT_CSTATE_COUNT; num++) { +		for (cpu = 0; cpu < cpu_count; cpu++) { +			is_valid[cpu] = !hsw_ext_get_count(num, &val, cpu); +			current_count[num][cpu] = val; +		} +	} +	return 0; +} + +struct cpuidle_monitor intel_hsw_ext_monitor; + +static struct cpuidle_monitor *hsw_ext_register(void) +{ +	int num; + +	if (cpupower_cpu_info.vendor != X86_VENDOR_INTEL +	    || cpupower_cpu_info.family != 6) +		return NULL; + +	switch (cpupower_cpu_info.model) { +	case 0x45: /* HSW */ +		break; +	default: +		return NULL; +	} + +	is_valid = calloc(cpu_count, sizeof(int)); +	for (num = 0; num < HSW_EXT_CSTATE_COUNT; num++) { +		previous_count[num] = calloc(cpu_count, +					sizeof(unsigned long long)); +		current_count[num]  = calloc(cpu_count, +					sizeof(unsigned long long)); +	} +	intel_hsw_ext_monitor.name_len = strlen(intel_hsw_ext_monitor.name); +	return &intel_hsw_ext_monitor; +} + +void hsw_ext_unregister(void) +{ +	int num; +	free(is_valid); +	for (num = 0; num < HSW_EXT_CSTATE_COUNT; num++) { +		free(previous_count[num]); +		free(current_count[num]); +	} +} + +struct cpuidle_monitor intel_hsw_ext_monitor = { +	.name			= "HaswellExtended", +	.hw_states		= hsw_ext_cstates, +	.hw_states_num		= HSW_EXT_CSTATE_COUNT, +	.start			= hsw_ext_start, +	.stop			= hsw_ext_stop, +	.do_register		= hsw_ext_register, +	.unregister		= hsw_ext_unregister, +	.needs_root		= 1, +	.overflow_s		= 922000000 /* 922337203 seconds TSC overflow +					       at 20GHz */ +}; +#endif /* defined(__i386__) || defined(__x86_64__) */ 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..0d6ba4dbb9c --- /dev/null +++ b/tools/power/cpupower/utils/idle_monitor/idle_monitors.def @@ -0,0 +1,8 @@ +#if defined(__i386__) || defined(__x86_64__) +DEF(amd_fam14h) +DEF(intel_nhm) +DEF(intel_snb) +DEF(intel_hsw_ext) +DEF(mperf) +#endif +DEF(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 @@ +/* + *  (C) 2010,2011       Thomas Renninger <trenn@suse.de>, Novell Inc. + * + *  Licensed under the terms of the GNU GPL License version 2. + * + *  Based on the idea from Michael Matz <matz@suse.de> + * + */ + +#ifndef _CPUIDLE_IDLE_MONITORS_H_ +#define _CPUIDLE_IDLE_MONITORS_H_ + +#define DEF(x) extern struct cpuidle_monitor x ##_monitor; +#include "idle_monitors.def" +#undef DEF +extern struct cpuidle_monitor *all_monitors[]; + +#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..5650ab5a2c2 --- /dev/null +++ b/tools/power/cpupower/utils/idle_monitor/mperf_monitor.c @@ -0,0 +1,338 @@ +/* + *  (C) 2010,2011       Thomas Renninger <trenn@suse.de>, Novell Inc. + * + *  Licensed under the terms of the GNU GPL License version 2. + */ + +#if defined(__i386__) || defined(__x86_64__) + +#include <stdio.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> +#include <limits.h> + +#include <cpufreq.h> + +#include "helpers/helpers.h" +#include "idle_monitor/cpupower-monitor.h" + +#define MSR_APERF	0xE8 +#define MSR_MPERF	0xE7 + +#define MSR_TSC	0x10 + +#define MSR_AMD_HWCR 0xc0010015 + +enum mperf_id { C0 = 0, Cx, AVG_FREQ, MPERF_CSTATE_COUNT }; + +static int mperf_get_count_percent(unsigned int self_id, double *percent, +				   unsigned int cpu); +static int mperf_get_count_freq(unsigned int id, unsigned long long *count, +				unsigned int cpu); +static struct timespec time_start, time_end; + +static cstate_t mperf_cstates[MPERF_CSTATE_COUNT] = { +	{ +		.name			= "C0", +		.desc			= N_("Processor Core not idle"), +		.id			= C0, +		.range			= RANGE_THREAD, +		.get_count_percent	= mperf_get_count_percent, +	}, +	{ +		.name			= "Cx", +		.desc			= N_("Processor Core in an idle state"), +		.id			= Cx, +		.range			= RANGE_THREAD, +		.get_count_percent	= mperf_get_count_percent, +	}, + +	{ +		.name			= "Freq", +		.desc			= N_("Average Frequency (including boost) in MHz"), +		.id			= AVG_FREQ, +		.range			= RANGE_THREAD, +		.get_count		= mperf_get_count_freq, +	}, +}; + +enum MAX_FREQ_MODE { MAX_FREQ_SYSFS, MAX_FREQ_TSC_REF }; +static int max_freq_mode; +/* + * The max frequency mperf is ticking at (in C0), either retrieved via: + *   1) calculated after measurements if we know TSC ticks at mperf/P0 frequency + *   2) cpufreq /sys/devices/.../cpu0/cpufreq/cpuinfo_max_freq at init time + * 1. Is preferred as it also works without cpufreq subsystem (e.g. on Xen) + */ +static unsigned long max_frequency; + +static unsigned long long tsc_at_measure_start; +static unsigned long long tsc_at_measure_end; +static unsigned long long *mperf_previous_count; +static unsigned long long *aperf_previous_count; +static unsigned long long *mperf_current_count; +static unsigned long long *aperf_current_count; + +/* valid flag for all CPUs. If a MSR read failed it will be zero */ +static int *is_valid; + +static int mperf_get_tsc(unsigned long long *tsc) +{ +	int ret; +	ret = read_msr(0, MSR_TSC, tsc); +	if (ret) +		dprint("Reading TSC MSR failed, returning %llu\n", *tsc); +	return ret; +} + +static int mperf_init_stats(unsigned int cpu) +{ +	unsigned long long val; +	int ret; + +	ret = read_msr(cpu, MSR_APERF, &val); +	aperf_previous_count[cpu] = val; +	ret |= read_msr(cpu, MSR_MPERF, &val); +	mperf_previous_count[cpu] = val; +	is_valid[cpu] = !ret; + +	return 0; +} + +static int mperf_measure_stats(unsigned int cpu) +{ +	unsigned long long val; +	int ret; + +	ret = read_msr(cpu, MSR_APERF, &val); +	aperf_current_count[cpu] = val; +	ret |= read_msr(cpu, MSR_MPERF, &val); +	mperf_current_count[cpu] = val; +	is_valid[cpu] = !ret; + +	return 0; +} + +static int mperf_get_count_percent(unsigned int id, double *percent, +				   unsigned int cpu) +{ +	unsigned long long aperf_diff, mperf_diff, tsc_diff; +	unsigned long long timediff; + +	if (!is_valid[cpu]) +		return -1; + +	if (id != C0 && id != Cx) +		return -1; + +	mperf_diff = mperf_current_count[cpu] - mperf_previous_count[cpu]; +	aperf_diff = aperf_current_count[cpu] - aperf_previous_count[cpu]; + +	if (max_freq_mode == MAX_FREQ_TSC_REF) { +		tsc_diff = tsc_at_measure_end - tsc_at_measure_start; +		*percent = 100.0 * mperf_diff / tsc_diff; +		dprint("%s: TSC Ref - mperf_diff: %llu, tsc_diff: %llu\n", +		       mperf_cstates[id].name, mperf_diff, tsc_diff); +	} else if (max_freq_mode == MAX_FREQ_SYSFS) { +		timediff = timespec_diff_us(time_start, time_end); +		*percent = 100.0 * mperf_diff / timediff; +		dprint("%s: MAXFREQ - mperf_diff: %llu, time_diff: %llu\n", +		       mperf_cstates[id].name, mperf_diff, timediff); +	} else +		return -1; + +	if (id == Cx) +		*percent = 100.0 - *percent; + +	dprint("%s: previous: %llu - current: %llu - (%u)\n", +		mperf_cstates[id].name, mperf_diff, aperf_diff, cpu); +	dprint("%s: %f\n", mperf_cstates[id].name, *percent); +	return 0; +} + +static int mperf_get_count_freq(unsigned int id, unsigned long long *count, +				unsigned int cpu) +{ +	unsigned long long aperf_diff, mperf_diff, time_diff, tsc_diff; + +	if (id != AVG_FREQ) +		return 1; + +	if (!is_valid[cpu]) +		return -1; + +	mperf_diff = mperf_current_count[cpu] - mperf_previous_count[cpu]; +	aperf_diff = aperf_current_count[cpu] - aperf_previous_count[cpu]; + +	if (max_freq_mode == MAX_FREQ_TSC_REF) { +		/* Calculate max_freq from TSC count */ +		tsc_diff = tsc_at_measure_end - tsc_at_measure_start; +		time_diff = timespec_diff_us(time_start, time_end); +		max_frequency = tsc_diff / time_diff; +	} + +	*count = max_frequency * ((double)aperf_diff / mperf_diff); +	dprint("%s: Average freq based on %s maximum frequency:\n", +	       mperf_cstates[id].name, +	       (max_freq_mode == MAX_FREQ_TSC_REF) ? "TSC calculated" : "sysfs read"); +	dprint("%max_frequency: %lu", max_frequency); +	dprint("aperf_diff: %llu\n", aperf_diff); +	dprint("mperf_diff: %llu\n", mperf_diff); +	dprint("avg freq:   %llu\n", *count); +	return 0; +} + +static int mperf_start(void) +{ +	int cpu; +	unsigned long long dbg; + +	clock_gettime(CLOCK_REALTIME, &time_start); +	mperf_get_tsc(&tsc_at_measure_start); + +	for (cpu = 0; cpu < cpu_count; cpu++) +		mperf_init_stats(cpu); + +	mperf_get_tsc(&dbg); +	dprint("TSC diff: %llu\n", dbg - tsc_at_measure_start); +	return 0; +} + +static int mperf_stop(void) +{ +	unsigned long long dbg; +	int cpu; + +	for (cpu = 0; cpu < cpu_count; cpu++) +		mperf_measure_stats(cpu); + +	mperf_get_tsc(&tsc_at_measure_end); +	clock_gettime(CLOCK_REALTIME, &time_end); + +	mperf_get_tsc(&dbg); +	dprint("TSC diff: %llu\n", dbg - tsc_at_measure_end); + +	return 0; +} + +/* + * Mperf register is defined to tick at P0 (maximum) frequency + * + * Instead of reading out P0 which can be tricky to read out from HW, + * we use TSC counter if it reliably ticks at P0/mperf frequency. + * + * Still try to fall back to: + * /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq + * on older Intel HW without invariant TSC feature. + * Or on AMD machines where TSC does not tick at P0 (do not exist yet, but + * it's still double checked (MSR_AMD_HWCR)). + * + * On these machines the user would still get useful mperf + * stats when acpi-cpufreq driver is loaded. + */ +static int init_maxfreq_mode(void) +{ +	int ret; +	unsigned long long hwcr; +	unsigned long min; + +	if (!cpupower_cpu_info.caps & CPUPOWER_CAP_INV_TSC) +		goto use_sysfs; + +	if (cpupower_cpu_info.vendor == X86_VENDOR_AMD) { +		/* MSR_AMD_HWCR tells us whether TSC runs at P0/mperf +		 * freq. +		 * A test whether hwcr is accessable/available would be: +		 * (cpupower_cpu_info.family > 0x10 || +		 *   cpupower_cpu_info.family == 0x10 && +		 *   cpupower_cpu_info.model >= 0x2)) +		 * This should be the case for all aperf/mperf +		 * capable AMD machines and is therefore safe to test here. +		 * Compare with Linus kernel git commit: acf01734b1747b1ec4 +		 */ +		ret = read_msr(0, MSR_AMD_HWCR, &hwcr); +		/* +		 * If the MSR read failed, assume a Xen system that did +		 * not explicitly provide access to it and assume TSC works +		*/ +		if (ret != 0) { +			dprint("TSC read 0x%x failed - assume TSC working\n", +			       MSR_AMD_HWCR); +			return 0; +		} else if (1 & (hwcr >> 24)) { +			max_freq_mode = MAX_FREQ_TSC_REF; +			return 0; +		} else { /* Use sysfs max frequency if available */ } +	} else if (cpupower_cpu_info.vendor == X86_VENDOR_INTEL) { +		/* +		 * On Intel we assume mperf (in C0) is ticking at same +		 * rate than TSC +		 */ +		max_freq_mode = MAX_FREQ_TSC_REF; +		return 0; +	} +use_sysfs: +	if (cpufreq_get_hardware_limits(0, &min, &max_frequency)) { +		dprint("Cannot retrieve max freq from cpufreq kernel " +		       "subsystem\n"); +		return -1; +	} +	max_freq_mode = MAX_FREQ_SYSFS; +	return 0; +} + +/* + * This monitor provides: + * + * 1) Average frequency a CPU resided in + *    This always works if the CPU has aperf/mperf capabilities + * + * 2) C0 and Cx (any sleep state) time a CPU resided in + *    Works if mperf timer stops ticking in sleep states which + *    seem to be the case on all current HW. + * Both is directly retrieved from HW registers and is independent + * from kernel statistics. + */ +struct cpuidle_monitor mperf_monitor; +struct cpuidle_monitor *mperf_register(void) +{ +	if (!(cpupower_cpu_info.caps & CPUPOWER_CAP_APERF)) +		return NULL; + +	if (init_maxfreq_mode()) +		return NULL; + +	/* Free this at program termination */ +	is_valid = calloc(cpu_count, sizeof(int)); +	mperf_previous_count = calloc(cpu_count, sizeof(unsigned long long)); +	aperf_previous_count = calloc(cpu_count, sizeof(unsigned long long)); +	mperf_current_count = calloc(cpu_count, sizeof(unsigned long long)); +	aperf_current_count = calloc(cpu_count, sizeof(unsigned long long)); + +	mperf_monitor.name_len = strlen(mperf_monitor.name); +	return &mperf_monitor; +} + +void mperf_unregister(void) +{ +	free(mperf_previous_count); +	free(aperf_previous_count); +	free(mperf_current_count); +	free(aperf_current_count); +	free(is_valid); +} + +struct cpuidle_monitor mperf_monitor = { +	.name			= "Mperf", +	.hw_states_num		= MPERF_CSTATE_COUNT, +	.hw_states		= mperf_cstates, +	.start			= mperf_start, +	.stop			= mperf_stop, +	.do_register		= mperf_register, +	.unregister		= mperf_unregister, +	.needs_root		= 1, +	.overflow_s		= 922000000 /* 922337203 seconds TSC overflow +					       at 20GHz */ +}; +#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..d2a91dd0d56 --- /dev/null +++ b/tools/power/cpupower/utils/idle_monitor/nhm_idle.c @@ -0,0 +1,216 @@ +/* + *  (C) 2010,2011       Thomas Renninger <trenn@suse.de>, Novell Inc. + * + *  Licensed under the terms of the GNU GPL License version 2. + * + *  Based on Len Brown's <lenb@kernel.org> turbostat tool. + */ + +#if defined(__i386__) || defined(__x86_64__) + +#include <stdio.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> + +#include "helpers/helpers.h" +#include "idle_monitor/cpupower-monitor.h" + +#define MSR_PKG_C3_RESIDENCY	0x3F8 +#define MSR_PKG_C6_RESIDENCY	0x3F9 +#define MSR_CORE_C3_RESIDENCY	0x3FC +#define MSR_CORE_C6_RESIDENCY	0x3FD + +#define MSR_TSC	0x10 + +#define NHM_CSTATE_COUNT 4 + +enum intel_nhm_id { C3 = 0, C6, PC3, PC6, TSC = 0xFFFF }; + +static int nhm_get_count_percent(unsigned int self_id, double *percent, +				 unsigned int cpu); + +static cstate_t nhm_cstates[NHM_CSTATE_COUNT] = { +	{ +		.name			= "C3", +		.desc			= N_("Processor Core C3"), +		.id			= C3, +		.range			= RANGE_CORE, +		.get_count_percent	= nhm_get_count_percent, +	}, +	{ +		.name			= "C6", +		.desc			= N_("Processor Core C6"), +		.id			= C6, +		.range			= RANGE_CORE, +		.get_count_percent	= nhm_get_count_percent, +	}, + +	{ +		.name			= "PC3", +		.desc			= N_("Processor Package C3"), +		.id			= PC3, +		.range			= RANGE_PACKAGE, +		.get_count_percent	= nhm_get_count_percent, +	}, +	{ +		.name			= "PC6", +		.desc			= N_("Processor Package C6"), +		.id			= PC6, +		.range			= RANGE_PACKAGE, +		.get_count_percent	= nhm_get_count_percent, +	}, +}; + +static unsigned long long tsc_at_measure_start; +static unsigned long long tsc_at_measure_end; +static unsigned long long *previous_count[NHM_CSTATE_COUNT]; +static unsigned long long *current_count[NHM_CSTATE_COUNT]; +/* valid flag for all CPUs. If a MSR read failed it will be zero */ +static int *is_valid; + +static int nhm_get_count(enum intel_nhm_id id, unsigned long long *val, +			unsigned int cpu) +{ +	int msr; + +	switch (id) { +	case C3: +		msr = MSR_CORE_C3_RESIDENCY; +		break; +	case C6: +		msr = MSR_CORE_C6_RESIDENCY; +		break; +	case PC3: +		msr = MSR_PKG_C3_RESIDENCY; +		break; +	case PC6: +		msr = MSR_PKG_C6_RESIDENCY; +		break; +	case TSC: +		msr = MSR_TSC; +		break; +	default: +		return -1; +	}; +	if (read_msr(cpu, msr, val)) +		return -1; + +	return 0; +} + +static int nhm_get_count_percent(unsigned int id, double *percent, +				 unsigned int cpu) +{ +	*percent = 0.0; + +	if (!is_valid[cpu]) +		return -1; + +	*percent = (100.0 * +		(current_count[id][cpu] - previous_count[id][cpu])) / +		(tsc_at_measure_end - tsc_at_measure_start); + +	dprint("%s: previous: %llu - current: %llu - (%u)\n", +		nhm_cstates[id].name, previous_count[id][cpu], +		current_count[id][cpu], cpu); + +	dprint("%s: tsc_diff: %llu - count_diff: %llu - percent: %2.f (%u)\n", +	       nhm_cstates[id].name, +	       (unsigned long long) tsc_at_measure_end - tsc_at_measure_start, +	       current_count[id][cpu] - previous_count[id][cpu], +	       *percent, cpu); + +	return 0; +} + +static int nhm_start(void) +{ +	int num, cpu; +	unsigned long long dbg, val; + +	nhm_get_count(TSC, &tsc_at_measure_start, 0); + +	for (num = 0; num < NHM_CSTATE_COUNT; num++) { +		for (cpu = 0; cpu < cpu_count; cpu++) { +			is_valid[cpu] = !nhm_get_count(num, &val, cpu); +			previous_count[num][cpu] = val; +		} +	} +	nhm_get_count(TSC, &dbg, 0); +	dprint("TSC diff: %llu\n", dbg - tsc_at_measure_start); +	return 0; +} + +static int nhm_stop(void) +{ +	unsigned long long val; +	unsigned long long dbg; +	int num, cpu; + +	nhm_get_count(TSC, &tsc_at_measure_end, 0); + +	for (num = 0; num < NHM_CSTATE_COUNT; num++) { +		for (cpu = 0; cpu < cpu_count; cpu++) { +			is_valid[cpu] = !nhm_get_count(num, &val, cpu); +			current_count[num][cpu] = val; +		} +	} +	nhm_get_count(TSC, &dbg, 0); +	dprint("TSC diff: %llu\n", dbg - tsc_at_measure_end); + +	return 0; +} + +struct cpuidle_monitor intel_nhm_monitor; + +struct cpuidle_monitor *intel_nhm_register(void) +{ +	int num; + +	if (cpupower_cpu_info.vendor != X86_VENDOR_INTEL) +		return NULL; + +	if (!(cpupower_cpu_info.caps & CPUPOWER_CAP_INV_TSC)) +		return NULL; + +	if (!(cpupower_cpu_info.caps & CPUPOWER_CAP_APERF)) +		return NULL; + +	/* Free this at program termination */ +	is_valid = calloc(cpu_count, sizeof(int)); +	for (num = 0; num < NHM_CSTATE_COUNT; num++) { +		previous_count[num] = calloc(cpu_count, +					sizeof(unsigned long long)); +		current_count[num]  = calloc(cpu_count, +					sizeof(unsigned long long)); +	} + +	intel_nhm_monitor.name_len = strlen(intel_nhm_monitor.name); +	return &intel_nhm_monitor; +} + +void intel_nhm_unregister(void) +{ +	int num; + +	for (num = 0; num < NHM_CSTATE_COUNT; num++) { +		free(previous_count[num]); +		free(current_count[num]); +	} +	free(is_valid); +} + +struct cpuidle_monitor intel_nhm_monitor = { +	.name			= "Nehalem", +	.hw_states_num		= NHM_CSTATE_COUNT, +	.hw_states		= nhm_cstates, +	.start			= nhm_start, +	.stop			= nhm_stop, +	.do_register		= intel_nhm_register, +	.unregister		= intel_nhm_unregister, +	.needs_root		= 1, +	.overflow_s		= 922000000 /* 922337203 seconds TSC overflow +					       at 20GHz */ +}; +#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..efc8a69c9ab --- /dev/null +++ b/tools/power/cpupower/utils/idle_monitor/snb_idle.c @@ -0,0 +1,200 @@ +/* + *  (C) 2010,2011       Thomas Renninger <trenn@suse.de>, Novell Inc. + * + *  Licensed under the terms of the GNU GPL License version 2. + * + *  Based on Len Brown's <lenb@kernel.org> turbostat tool. + */ + +#if defined(__i386__) || defined(__x86_64__) + +#include <stdio.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> + +#include "helpers/helpers.h" +#include "idle_monitor/cpupower-monitor.h" + +#define MSR_PKG_C2_RESIDENCY	0x60D +#define MSR_PKG_C7_RESIDENCY	0x3FA +#define MSR_CORE_C7_RESIDENCY	0x3FE + +#define MSR_TSC	0x10 + +enum intel_snb_id { C7 = 0, PC2, PC7, SNB_CSTATE_COUNT, TSC = 0xFFFF }; + +static int snb_get_count_percent(unsigned int self_id, double *percent, +				 unsigned int cpu); + +static cstate_t snb_cstates[SNB_CSTATE_COUNT] = { +	{ +		.name			= "C7", +		.desc			= N_("Processor Core C7"), +		.id			= C7, +		.range			= RANGE_CORE, +		.get_count_percent	= snb_get_count_percent, +	}, +	{ +		.name			= "PC2", +		.desc			= N_("Processor Package C2"), +		.id			= PC2, +		.range			= RANGE_PACKAGE, +		.get_count_percent	= snb_get_count_percent, +	}, +	{ +		.name			= "PC7", +		.desc			= N_("Processor Package C7"), +		.id			= PC7, +		.range			= RANGE_PACKAGE, +		.get_count_percent	= snb_get_count_percent, +	}, +}; + +static unsigned long long tsc_at_measure_start; +static unsigned long long tsc_at_measure_end; +static unsigned long long *previous_count[SNB_CSTATE_COUNT]; +static unsigned long long *current_count[SNB_CSTATE_COUNT]; +/* valid flag for all CPUs. If a MSR read failed it will be zero */ +static int *is_valid; + +static int snb_get_count(enum intel_snb_id id, unsigned long long *val, +			unsigned int cpu) +{ +	int msr; + +	switch (id) { +	case C7: +		msr = MSR_CORE_C7_RESIDENCY; +		break; +	case PC2: +		msr = MSR_PKG_C2_RESIDENCY; +		break; +	case PC7: +		msr = MSR_PKG_C7_RESIDENCY; +		break; +	case TSC: +		msr = MSR_TSC; +		break; +	default: +		return -1; +	}; +	if (read_msr(cpu, msr, val)) +		return -1; +	return 0; +} + +static int snb_get_count_percent(unsigned int id, double *percent, +				 unsigned int cpu) +{ +	*percent = 0.0; + +	if (!is_valid[cpu]) +		return -1; + +	*percent = (100.0 * +		(current_count[id][cpu] - previous_count[id][cpu])) / +		(tsc_at_measure_end - tsc_at_measure_start); + +	dprint("%s: previous: %llu - current: %llu - (%u)\n", +		snb_cstates[id].name, previous_count[id][cpu], +		current_count[id][cpu], cpu); + +	dprint("%s: tsc_diff: %llu - count_diff: %llu - percent: %2.f (%u)\n", +	       snb_cstates[id].name, +	       (unsigned long long) tsc_at_measure_end - tsc_at_measure_start, +	       current_count[id][cpu] - previous_count[id][cpu], +	       *percent, cpu); + +	return 0; +} + +static int snb_start(void) +{ +	int num, cpu; +	unsigned long long val; + +	for (num = 0; num < SNB_CSTATE_COUNT; num++) { +		for (cpu = 0; cpu < cpu_count; cpu++) { +			snb_get_count(num, &val, cpu); +			previous_count[num][cpu] = val; +		} +	} +	snb_get_count(TSC, &tsc_at_measure_start, 0); +	return 0; +} + +static int snb_stop(void) +{ +	unsigned long long val; +	int num, cpu; + +	snb_get_count(TSC, &tsc_at_measure_end, 0); + +	for (num = 0; num < SNB_CSTATE_COUNT; num++) { +		for (cpu = 0; cpu < cpu_count; cpu++) { +			is_valid[cpu] = !snb_get_count(num, &val, cpu); +			current_count[num][cpu] = val; +		} +	} +	return 0; +} + +struct cpuidle_monitor intel_snb_monitor; + +static struct cpuidle_monitor *snb_register(void) +{ +	int num; + +	if (cpupower_cpu_info.vendor != X86_VENDOR_INTEL +	    || cpupower_cpu_info.family != 6) +		return NULL; + +	switch (cpupower_cpu_info.model) { +	case 0x2A: /* SNB */ +	case 0x2D: /* SNB Xeon */ +	case 0x3A: /* IVB */ +	case 0x3E: /* IVB Xeon */ +	case 0x3C: /* HSW */ +	case 0x3F: /* HSW */ +	case 0x45: /* HSW */ +	case 0x46: /* HSW */ +		break; +	default: +		return NULL; +	} + +	is_valid = calloc(cpu_count, sizeof(int)); +	for (num = 0; num < SNB_CSTATE_COUNT; num++) { +		previous_count[num] = calloc(cpu_count, +					sizeof(unsigned long long)); +		current_count[num]  = calloc(cpu_count, +					sizeof(unsigned long long)); +	} +	intel_snb_monitor.name_len = strlen(intel_snb_monitor.name); +	return &intel_snb_monitor; +} + +void snb_unregister(void) +{ +	int num; +	free(is_valid); +	for (num = 0; num < SNB_CSTATE_COUNT; num++) { +		free(previous_count[num]); +		free(current_count[num]); +	} +} + +struct cpuidle_monitor intel_snb_monitor = { +	.name			= "SandyBridge", +	.hw_states		= snb_cstates, +	.hw_states_num		= SNB_CSTATE_COUNT, +	.start			= snb_start, +	.stop			= snb_stop, +	.do_register		= snb_register, +	.unregister		= snb_unregister, +	.needs_root		= 1, +	.overflow_s		= 922000000 /* 922337203 seconds TSC overflow +					       at 20GHz */ +}; +#endif /* defined(__i386__) || defined(__x86_64__) */ diff --git a/tools/power/cpupower/utils/version-gen.sh b/tools/power/cpupower/utils/version-gen.sh new file mode 100755 index 00000000000..5ec41c55699 --- /dev/null +++ b/tools/power/cpupower/utils/version-gen.sh @@ -0,0 +1,35 @@ +#!/bin/sh +# +# Script which prints out the version to use for building cpupowerutils. +# Must be called from tools/power/cpupower/ +#  +# Heavily based on tools/perf/util/PERF-VERSION-GEN . + +LF=' +' + +# First check if there is a .git to get the version from git describe +# otherwise try to get the version from the kernel makefile +if test -d ../../../.git -o -f ../../../.git && +	VN=$(git describe --abbrev=4 HEAD 2>/dev/null) && +	case "$VN" in +	*$LF*) (exit 1) ;; +	v[0-9]*) +		git update-index -q --refresh +		test -z "$(git diff-index --name-only HEAD --)" || +		VN="$VN-dirty" ;; +	esac +then +	VN=$(echo "$VN" | sed -e 's/-/./g'); +else +	eval $(grep '^VERSION[[:space:]]*=' ../../../Makefile|tr -d ' ') +	eval $(grep '^PATCHLEVEL[[:space:]]*=' ../../../Makefile|tr -d ' ') +	eval $(grep '^SUBLEVEL[[:space:]]*=' ../../../Makefile|tr -d ' ') +	eval $(grep '^EXTRAVERSION[[:space:]]*=' ../../../Makefile|tr -d ' ') + +	VN="${VERSION}.${PATCHLEVEL}.${SUBLEVEL}${EXTRAVERSION}" +fi + +VN=$(expr "$VN" : v*'\(.*\)') + +echo $VN diff --git a/tools/power/x86/turbostat/.gitignore b/tools/power/x86/turbostat/.gitignore new file mode 100644 index 00000000000..7521370d356 --- /dev/null +++ b/tools/power/x86/turbostat/.gitignore @@ -0,0 +1 @@ +turbostat diff --git a/tools/power/x86/turbostat/Makefile b/tools/power/x86/turbostat/Makefile new file mode 100644 index 00000000000..d1b3a361e52 --- /dev/null +++ b/tools/power/x86/turbostat/Makefile @@ -0,0 +1,22 @@ +CC		= $(CROSS_COMPILE)gcc +BUILD_OUTPUT	:= $(PWD) +PREFIX		:= /usr +DESTDIR		:= + +turbostat : turbostat.c +CFLAGS +=	-Wall +CFLAGS +=	-DMSRHEADER='"../../../../arch/x86/include/uapi/asm/msr-index.h"' + +%: %.c +	@mkdir -p $(BUILD_OUTPUT) +	$(CC) $(CFLAGS) $< -o $(BUILD_OUTPUT)/$@ + +.PHONY : clean +clean : +	@rm -f $(BUILD_OUTPUT)/turbostat + +install : turbostat +	install -d  $(DESTDIR)$(PREFIX)/bin +	install $(BUILD_OUTPUT)/turbostat $(DESTDIR)$(PREFIX)/bin/turbostat +	install -d  $(DESTDIR)$(PREFIX)/share/man/man8 +	install turbostat.8 $(DESTDIR)$(PREFIX)/share/man/man8 diff --git a/tools/power/x86/turbostat/turbostat.8 b/tools/power/x86/turbostat/turbostat.8 new file mode 100644 index 00000000000..56bfb523c5b --- /dev/null +++ b/tools/power/x86/turbostat/turbostat.8 @@ -0,0 +1,221 @@ +.TH TURBOSTAT 8 +.SH NAME +turbostat \- Report processor frequency and idle statistics +.SH SYNOPSIS +.ft B +.B turbostat +.RB [ Options ] +.RB command +.br +.B turbostat +.RB [ Options ] +.RB [ "\-i interval_sec" ] +.SH DESCRIPTION +\fBturbostat \fP reports processor topology, frequency, +idle power-state statistics, temperature and power on modern X86 processors. +Either \fBcommand\fP is forked and statistics are printed +upon its completion, or statistics are printed periodically. + +\fBturbostat \fP +must be run on root, and +minimally requires that the processor +supports an "invariant" TSC, plus the APERF and MPERF MSRs. +Additional information is reported depending on hardware counter support. + +.SS Options +The \fB-p\fP option limits output to the 1st thread in 1st core of each package. +.PP +The \fB-P\fP option limits output to the 1st thread in each Package. +.PP +The \fB-S\fP option limits output to a 1-line System Summary for each interval. +.PP +The \fB-v\fP option increases verbosity. +.PP +The \fB-c MSR#\fP option includes the delta of the specified 32-bit MSR counter. +.PP +The \fB-C MSR#\fP option includes the delta of the specified 64-bit MSR counter. +.PP +The \fB-m MSR#\fP option includes the the specified 32-bit MSR value. +.PP +The \fB-M MSR#\fP option includes the the specified 64-bit MSR value. +.PP +The \fB-i interval_sec\fP option prints statistics every \fiinterval_sec\fP seconds. +The default is 5 seconds. +.PP +The \fBcommand\fP parameter forks \fBcommand\fP and upon its exit, +displays the statistics gathered since it was forked. +.PP +.SH FIELD DESCRIPTIONS +.nf +\fBPackage\fP processor package number. +\fBCore\fP processor core number. +\fBCPU\fP Linux CPU (logical processor) number. +Note that multiple CPUs per core indicate support for Intel(R) Hyper-Threading Technology. +\fBAVG_MHz\fP number of cycles executed divided by time elapsed. +\fB%Buzy\fP percent of the interval that the CPU retired instructions, aka. % of time in "C0" state. +\fBBzy_MHz\fP average clock rate while the CPU was busy (in "c0" state). +\fBTSC_MHz\fP average MHz that the TSC ran during the entire interval. +\fBCPU%c1, CPU%c3, CPU%c6, CPU%c7\fP show the percentage residency in hardware core idle states. +\fBCoreTmp\fP Degrees Celsius reported by the per-core Digital Thermal Sensor. +\fBPkgTtmp\fP Degrees Celsius reported by the per-package Package Thermal Monitor. +\fBPkg%pc2, Pkg%pc3, Pkg%pc6, Pkg%pc7\fP percentage residency in hardware package idle states. +\fBPkgWatt\fP Watts consumed by the whole package. +\fBCorWatt\fP Watts consumed by the core part of the package. +\fBGFXWatt\fP Watts consumed by the Graphics part of the package -- available only on client processors. +\fBRAMWatt\fP Watts consumed by the DRAM DIMMS -- available only on server processors. +\fBPKG_%\fP percent of the interval that RAPL throttling was active on the Package. +\fBRAM_%\fP percent of the interval that RAPL throttling was active on DRAM. +.fi +.PP +.SH EXAMPLE +Without any parameters, turbostat prints out counters ever 5 seconds. +(override interval with "-i sec" option, or specify a command +for turbostat to fork). + +The first row of statistics is a summary for the entire system. +For residency % columns, the summary is a weighted average. +For Temperature columns, the summary is the column maximum. +For Watts columns, the summary is a system total. +Subsequent rows show per-CPU statistics. + +.nf +[root@ivy]# ./turbostat +    Core     CPU Avg_MHz   %Busy Bzy_MHz TSC_MHz     SMI  CPU%c1  CPU%c3  CPU%c6  CPU%c7 CoreTmp  PkgTmp Pkg%pc2 Pkg%pc3 Pkg%pc6 Pkg%pc7 PkgWatt CorWatt GFXWatt  +       -       -       6    0.36    1596    3492       0    0.59    0.01   99.04    0.00      23      24   23.82    0.01   72.47    0.00    6.40    1.01    0.00 +       0       0       9    0.58    1596    3492       0    0.28    0.01   99.13    0.00      23      24   23.82    0.01   72.47    0.00    6.40    1.01    0.00 +       0       4       1    0.07    1596    3492       0    0.79 +       1       1      10    0.65    1596    3492       0    0.59    0.00   98.76    0.00      23 +       1       5       5    0.28    1596    3492       0    0.95 +       2       2      10    0.66    1596    3492       0    0.41    0.01   98.92    0.00      23 +       2       6       2    0.10    1597    3492       0    0.97 +       3       3       3    0.20    1596    3492       0    0.44    0.00   99.37    0.00      23 +       3       7       5    0.31    1596    3492       0    0.33 +.fi +.SH VERBOSE EXAMPLE +The "-v" option adds verbosity to the output: + +.nf +[root@ivy]# turbostat -v +turbostat v3.0 November 23, 2012 - Len Brown <lenb@kernel.org> +CPUID(0): GenuineIntel 13 CPUID levels; family:model:stepping 0x6:3a:9 (6:58:9) +CPUID(6): APERF, DTS, PTM, EPB +RAPL: 851 sec. Joule Counter Range +cpu0: MSR_NHM_PLATFORM_INFO: 0x81010f0012300 +16 * 100 = 1600 MHz max efficiency +35 * 100 = 3500 MHz TSC frequency +cpu0: MSR_NHM_SNB_PKG_CST_CFG_CTL: 0x1e008402 (UNdemote-C3, UNdemote-C1, demote-C3, demote-C1, locked: pkg-cstate-limit=2: pc6-noret) +cpu0: MSR_NHM_TURBO_RATIO_LIMIT: 0x25262727 +37 * 100 = 3700 MHz max turbo 4 active cores +38 * 100 = 3800 MHz max turbo 3 active cores +39 * 100 = 3900 MHz max turbo 2 active cores +39 * 100 = 3900 MHz max turbo 1 active cores +cpu0: MSR_IA32_ENERGY_PERF_BIAS: 0x00000006 (balanced) +cpu0: MSR_RAPL_POWER_UNIT: 0x000a1003 (0.125000 Watts, 0.000015 Joules, 0.000977 sec.) +cpu0: MSR_PKG_POWER_INFO: 0x01e00268 (77 W TDP, RAPL 60 - 0 W, 0.000000 sec.) +cpu0: MSR_PKG_POWER_LIMIT: 0x830000148268 (UNlocked) +cpu0: PKG Limit #1: ENabled (77.000000 Watts, 1.000000 sec, clamp DISabled) +cpu0: PKG Limit #2: ENabled (96.000000 Watts, 0.000977* sec, clamp DISabled) +cpu0: MSR_PP0_POLICY: 0 +cpu0: MSR_PP0_POWER_LIMIT: 0x00000000 (UNlocked) +cpu0: Cores Limit: DISabled (0.000000 Watts, 0.000977 sec, clamp DISabled) +cpu0: MSR_PP1_POLICY: 0 +cpu0: MSR_PP1_POWER_LIMIT: 0x00000000 (UNlocked) +cpu0: GFX Limit: DISabled (0.000000 Watts, 0.000977 sec, clamp DISabled) +cpu0: MSR_IA32_TEMPERATURE_TARGET: 0x00691400 (105 C) +cpu0: MSR_IA32_PACKAGE_THERM_STATUS: 0x884e0000 (27 C) +cpu0: MSR_IA32_THERM_STATUS: 0x88560000 (19 C +/- 1) +cpu1: MSR_IA32_THERM_STATUS: 0x88560000 (19 C +/- 1) +cpu2: MSR_IA32_THERM_STATUS: 0x88540000 (21 C +/- 1) +cpu3: MSR_IA32_THERM_STATUS: 0x884e0000 (27 C +/- 1) + ... +.fi +The \fBmax efficiency\fP frequency, a.k.a. Low Frequency Mode, is the frequency +available at the minimum package voltage.  The \fBTSC frequency\fP is the nominal +maximum frequency of the processor if turbo-mode were not available.  This frequency +should be sustainable on all CPUs indefinitely, given nominal power and cooling. +The remaining rows show what maximum turbo frequency is possible +depending on the number of idle cores.  Note that this information is +not available on all processors. +.SH FORK EXAMPLE +If turbostat is invoked with a command, it will fork that command +and output the statistics gathered when the command exits. +eg. Here a cycle soaker is run on 1 CPU (see %c0) for a few seconds +until ^C while the other CPUs are mostly idle: + +.nf +root@ivy: turbostat cat /dev/zero > /dev/null +^C +    Core     CPU Avg_MHz   %Busy Bzy_MHz TSC_MHz     SMI  CPU%c1  CPU%c3  CPU%c6  CPU%c7 CoreTmp  PkgTmp Pkg%pc2 Pkg%pc3 Pkg%pc6 Pkg%pc7 PkgWatt CorWatt GFXWatt  +       -       -     496   12.75    3886    3492       0   13.16    0.04   74.04    0.00      36      36    0.00    0.00    0.00    0.00   23.15   17.65    0.00 +       0       0      22    0.57    3830    3492       0    0.83    0.02   98.59    0.00      27      36    0.00    0.00    0.00    0.00   23.15   17.65    0.00 +       0       4       9    0.24    3829    3492       0    1.15 +       1       1       4    0.09    3783    3492       0   99.91    0.00    0.00    0.00      36 +       1       5    3880   99.82    3888    3492       0    0.18 +       2       2      17    0.44    3813    3492       0    0.77    0.04   98.75    0.00      28 +       2       6      12    0.32    3823    3492       0    0.89 +       3       3      16    0.43    3844    3492       0    0.63    0.11   98.84    0.00      30 +       3       7       4    0.11    3827    3492       0    0.94 +30.372243 sec + +.fi +Above the cycle soaker drives cpu5 up its 3.8 GHz turbo limit +while the other processors are generally in various states of idle. + +Note that cpu1 and cpu5 are HT siblings within core1. +As cpu5 is very busy, it prevents its sibling, cpu1, +from entering a c-state deeper than c1. + +Note that the Avg_MHz column reflects the total number of cycles executed +divided by the measurement interval.  If the %Busy column is 100%, +then the processor was running at that speed the entire interval. +The Avg_MHz multiplied by the %Busy results in the Bzy_MHz -- +which is the average frequency while the processor was executing -- +not including any non-busy idle time. + +.SH NOTES + +.B "turbostat " +must be run as root. + +.B "turbostat " +reads hardware counters, but doesn't write them. +So it will not interfere with the OS or other programs, including +multiple invocations of itself. + +\fBturbostat \fP +may work poorly on Linux-2.6.20 through 2.6.29, +as \fBacpi-cpufreq \fPperiodically cleared the APERF and MPERF +in those kernels. + +If the TSC column does not make sense, then +the other numbers will also make no sense. +Turbostat is lightweight, and its data collection is not atomic. +These issues are usually caused by an extremely short measurement +interval (much less than 1 second), or system activity that prevents +turbostat from being able to run on all CPUS to quickly collect data. + +The APERF, MPERF MSRs are defined to count non-halted cycles. +Although it is not guaranteed by the architecture, turbostat assumes +that they count at TSC rate, which is true on all processors tested to date. + +.SH REFERENCES +"Intel® Turbo Boost Technology +in Intel® Coreâ„¢ Microarchitecture (Nehalem) Based Processors" +http://download.intel.com/design/processor/applnots/320354.pdf + +"Intel® 64 and IA-32 Architectures Software Developer's Manual +Volume 3B: System Programming Guide" +http://www.intel.com/products/processor/manuals/ + +.SH FILES +.ta +.nf +/dev/cpu/*/msr +.fi + +.SH "SEE ALSO" +msr(4), vmstat(8) +.PP +.SH AUTHOR +.nf +Written by Len Brown <len.brown@intel.com> diff --git a/tools/power/x86/turbostat/turbostat.c b/tools/power/x86/turbostat/turbostat.c new file mode 100644 index 00000000000..d0396af99fa --- /dev/null +++ b/tools/power/x86/turbostat/turbostat.c @@ -0,0 +1,2462 @@ +/* + * turbostat -- show CPU frequency and C-state residency + * on modern Intel turbo-capable processors. + * + * Copyright (c) 2013 Intel Corporation. + * Len Brown <len.brown@intel.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#define _GNU_SOURCE +#include MSRHEADER +#include <stdarg.h> +#include <stdio.h> +#include <err.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <sys/stat.h> +#include <sys/resource.h> +#include <fcntl.h> +#include <signal.h> +#include <sys/time.h> +#include <stdlib.h> +#include <dirent.h> +#include <string.h> +#include <ctype.h> +#include <sched.h> +#include <cpuid.h> + +char *proc_stat = "/proc/stat"; +unsigned int interval_sec = 5;	/* set with -i interval_sec */ +unsigned int verbose;		/* set with -v */ +unsigned int rapl_verbose;	/* set with -R */ +unsigned int rapl_joules;	/* set with -J */ +unsigned int thermal_verbose;	/* set with -T */ +unsigned int summary_only;	/* set with -S */ +unsigned int dump_only;		/* set with -s */ +unsigned int skip_c0; +unsigned int skip_c1; +unsigned int do_nhm_cstates; +unsigned int do_snb_cstates; +unsigned int do_c8_c9_c10; +unsigned int do_slm_cstates; +unsigned int use_c1_residency_msr; +unsigned int has_aperf; +unsigned int has_epb; +unsigned int units = 1000000;	/* MHz etc */ +unsigned int genuine_intel; +unsigned int has_invariant_tsc; +unsigned int do_nehalem_platform_info; +unsigned int do_nehalem_turbo_ratio_limit; +unsigned int do_ivt_turbo_ratio_limit; +unsigned int extra_msr_offset32; +unsigned int extra_msr_offset64; +unsigned int extra_delta_offset32; +unsigned int extra_delta_offset64; +int do_smi; +double bclk; +unsigned int show_pkg; +unsigned int show_core; +unsigned int show_cpu; +unsigned int show_pkg_only; +unsigned int show_core_only; +char *output_buffer, *outp; +unsigned int do_rapl; +unsigned int do_dts; +unsigned int do_ptm; +unsigned int tcc_activation_temp; +unsigned int tcc_activation_temp_override; +double rapl_power_units, rapl_energy_units, rapl_time_units; +double rapl_joule_counter_range; + +#define RAPL_PKG		(1 << 0) +					/* 0x610 MSR_PKG_POWER_LIMIT */ +					/* 0x611 MSR_PKG_ENERGY_STATUS */ +#define RAPL_PKG_PERF_STATUS	(1 << 1) +					/* 0x613 MSR_PKG_PERF_STATUS */ +#define RAPL_PKG_POWER_INFO	(1 << 2) +					/* 0x614 MSR_PKG_POWER_INFO */ + +#define RAPL_DRAM		(1 << 3) +					/* 0x618 MSR_DRAM_POWER_LIMIT */ +					/* 0x619 MSR_DRAM_ENERGY_STATUS */ +					/* 0x61c MSR_DRAM_POWER_INFO */ +#define RAPL_DRAM_PERF_STATUS	(1 << 4) +					/* 0x61b MSR_DRAM_PERF_STATUS */ + +#define RAPL_CORES		(1 << 5) +					/* 0x638 MSR_PP0_POWER_LIMIT */ +					/* 0x639 MSR_PP0_ENERGY_STATUS */ +#define RAPL_CORE_POLICY	(1 << 6) +					/* 0x63a MSR_PP0_POLICY */ + + +#define RAPL_GFX		(1 << 7) +					/* 0x640 MSR_PP1_POWER_LIMIT */ +					/* 0x641 MSR_PP1_ENERGY_STATUS */ +					/* 0x642 MSR_PP1_POLICY */ +#define	TJMAX_DEFAULT	100 + +#define MAX(a, b) ((a) > (b) ? (a) : (b)) + +int aperf_mperf_unstable; +int backwards_count; +char *progname; + +cpu_set_t *cpu_present_set, *cpu_affinity_set; +size_t cpu_present_setsize, cpu_affinity_setsize; + +struct thread_data { +	unsigned long long tsc; +	unsigned long long aperf; +	unsigned long long mperf; +	unsigned long long c1; +	unsigned long long extra_msr64; +	unsigned long long extra_delta64; +	unsigned long long extra_msr32; +	unsigned long long extra_delta32; +	unsigned int smi_count; +	unsigned int cpu_id; +	unsigned int flags; +#define CPU_IS_FIRST_THREAD_IN_CORE	0x2 +#define CPU_IS_FIRST_CORE_IN_PACKAGE	0x4 +} *thread_even, *thread_odd; + +struct core_data { +	unsigned long long c3; +	unsigned long long c6; +	unsigned long long c7; +	unsigned int core_temp_c; +	unsigned int core_id; +} *core_even, *core_odd; + +struct pkg_data { +	unsigned long long pc2; +	unsigned long long pc3; +	unsigned long long pc6; +	unsigned long long pc7; +	unsigned long long pc8; +	unsigned long long pc9; +	unsigned long long pc10; +	unsigned int package_id; +	unsigned int energy_pkg;	/* MSR_PKG_ENERGY_STATUS */ +	unsigned int energy_dram;	/* MSR_DRAM_ENERGY_STATUS */ +	unsigned int energy_cores;	/* MSR_PP0_ENERGY_STATUS */ +	unsigned int energy_gfx;	/* MSR_PP1_ENERGY_STATUS */ +	unsigned int rapl_pkg_perf_status;	/* MSR_PKG_PERF_STATUS */ +	unsigned int rapl_dram_perf_status;	/* MSR_DRAM_PERF_STATUS */ +	unsigned int pkg_temp_c; + +} *package_even, *package_odd; + +#define ODD_COUNTERS thread_odd, core_odd, package_odd +#define EVEN_COUNTERS thread_even, core_even, package_even + +#define GET_THREAD(thread_base, thread_no, core_no, pkg_no) \ +	(thread_base + (pkg_no) * topo.num_cores_per_pkg * \ +		topo.num_threads_per_core + \ +		(core_no) * topo.num_threads_per_core + (thread_no)) +#define GET_CORE(core_base, core_no, pkg_no) \ +	(core_base + (pkg_no) * topo.num_cores_per_pkg + (core_no)) +#define GET_PKG(pkg_base, pkg_no) (pkg_base + pkg_no) + +struct system_summary { +	struct thread_data threads; +	struct core_data cores; +	struct pkg_data packages; +} sum, average; + + +struct topo_params { +	int num_packages; +	int num_cpus; +	int num_cores; +	int max_cpu_num; +	int num_cores_per_pkg; +	int num_threads_per_core; +} topo; + +struct timeval tv_even, tv_odd, tv_delta; + +void setup_all_buffers(void); + +int cpu_is_not_present(int cpu) +{ +	return !CPU_ISSET_S(cpu, cpu_present_setsize, cpu_present_set); +} +/* + * run func(thread, core, package) in topology order + * skip non-present cpus + */ + +int for_all_cpus(int (func)(struct thread_data *, struct core_data *, struct pkg_data *), +	struct thread_data *thread_base, struct core_data *core_base, struct pkg_data *pkg_base) +{ +	int retval, pkg_no, core_no, thread_no; + +	for (pkg_no = 0; pkg_no < topo.num_packages; ++pkg_no) { +		for (core_no = 0; core_no < topo.num_cores_per_pkg; ++core_no) { +			for (thread_no = 0; thread_no < +				topo.num_threads_per_core; ++thread_no) { +				struct thread_data *t; +				struct core_data *c; +				struct pkg_data *p; + +				t = GET_THREAD(thread_base, thread_no, core_no, pkg_no); + +				if (cpu_is_not_present(t->cpu_id)) +					continue; + +				c = GET_CORE(core_base, core_no, pkg_no); +				p = GET_PKG(pkg_base, pkg_no); + +				retval = func(t, c, p); +				if (retval) +					return retval; +			} +		} +	} +	return 0; +} + +int cpu_migrate(int cpu) +{ +	CPU_ZERO_S(cpu_affinity_setsize, cpu_affinity_set); +	CPU_SET_S(cpu, cpu_affinity_setsize, cpu_affinity_set); +	if (sched_setaffinity(0, cpu_affinity_setsize, cpu_affinity_set) == -1) +		return -1; +	else +		return 0; +} + +int get_msr(int cpu, off_t offset, unsigned long long *msr) +{ +	ssize_t retval; +	char pathname[32]; +	int fd; + +	sprintf(pathname, "/dev/cpu/%d/msr", cpu); +	fd = open(pathname, O_RDONLY); +	if (fd < 0) +		return -1; + +	retval = pread(fd, msr, sizeof *msr, offset); +	close(fd); + +	if (retval != sizeof *msr) { +		fprintf(stderr, "%s offset 0x%llx read failed\n", pathname, (unsigned long long)offset); +		return -1; +	} + +	return 0; +} + +/* + * Example Format w/ field column widths: + * + * Package    Core     CPU Avg_MHz Bzy_MHz TSC_MHz     SMI   %Busy CPU_%c1 CPU_%c3 CPU_%c6 CPU_%c7 CoreTmp  PkgTmp Pkg%pc2 Pkg%pc3 Pkg%pc6 Pkg%pc7 PkgWatt CorWatt GFXWatt + * 1234567 1234567 1234567 1234567 1234567 1234567 1234567 1234567 1234567 1234567 1234567 1234567 1234567 1234567 1234567 1234567 1234567 1234567 1234567 1234567 1234567 + */ + +void print_header(void) +{ +	if (show_pkg) +		outp += sprintf(outp, "Package "); +	if (show_core) +		outp += sprintf(outp, "    Core "); +	if (show_cpu) +		outp += sprintf(outp, "    CPU "); +	if (has_aperf) +		outp += sprintf(outp, "Avg_MHz "); +	if (do_nhm_cstates) +		outp += sprintf(outp, "  %%Busy "); +	if (has_aperf) +		outp += sprintf(outp, "Bzy_MHz "); +	outp += sprintf(outp, "TSC_MHz "); +	if (do_smi) +		outp += sprintf(outp, "    SMI "); +	if (extra_delta_offset32) +		outp += sprintf(outp, " count 0x%03X ", extra_delta_offset32); +	if (extra_delta_offset64) +		outp += sprintf(outp, " COUNT 0x%03X ", extra_delta_offset64); +	if (extra_msr_offset32) +		outp += sprintf(outp, "  MSR 0x%03X ", extra_msr_offset32); +	if (extra_msr_offset64) +		outp += sprintf(outp, "          MSR 0x%03X ", extra_msr_offset64); +	if (do_nhm_cstates) +		outp += sprintf(outp, " CPU%%c1 "); +	if (do_nhm_cstates && !do_slm_cstates) +		outp += sprintf(outp, " CPU%%c3 "); +	if (do_nhm_cstates) +		outp += sprintf(outp, " CPU%%c6 "); +	if (do_snb_cstates) +		outp += sprintf(outp, " CPU%%c7 "); + +	if (do_dts) +		outp += sprintf(outp, "CoreTmp "); +	if (do_ptm) +		outp += sprintf(outp, " PkgTmp "); + +	if (do_snb_cstates) +		outp += sprintf(outp, "Pkg%%pc2 "); +	if (do_nhm_cstates && !do_slm_cstates) +		outp += sprintf(outp, "Pkg%%pc3 "); +	if (do_nhm_cstates && !do_slm_cstates) +		outp += sprintf(outp, "Pkg%%pc6 "); +	if (do_snb_cstates) +		outp += sprintf(outp, "Pkg%%pc7 "); +	if (do_c8_c9_c10) { +		outp += sprintf(outp, "Pkg%%pc8 "); +		outp += sprintf(outp, "Pkg%%pc9 "); +		outp += sprintf(outp, "Pk%%pc10 "); +	} + +	if (do_rapl && !rapl_joules) { +		if (do_rapl & RAPL_PKG) +			outp += sprintf(outp, "PkgWatt "); +		if (do_rapl & RAPL_CORES) +			outp += sprintf(outp, "CorWatt "); +		if (do_rapl & RAPL_GFX) +			outp += sprintf(outp, "GFXWatt "); +		if (do_rapl & RAPL_DRAM) +			outp += sprintf(outp, "RAMWatt "); +		if (do_rapl & RAPL_PKG_PERF_STATUS) +			outp += sprintf(outp, "  PKG_%% "); +		if (do_rapl & RAPL_DRAM_PERF_STATUS) +			outp += sprintf(outp, "  RAM_%% "); +	} else { +		if (do_rapl & RAPL_PKG) +			outp += sprintf(outp, "  Pkg_J "); +		if (do_rapl & RAPL_CORES) +			outp += sprintf(outp, "  Cor_J "); +		if (do_rapl & RAPL_GFX) +			outp += sprintf(outp, "  GFX_J "); +		if (do_rapl & RAPL_DRAM) +			outp += sprintf(outp, "  RAM_W "); +		if (do_rapl & RAPL_PKG_PERF_STATUS) +			outp += sprintf(outp, "  PKG_%% "); +		if (do_rapl & RAPL_DRAM_PERF_STATUS) +			outp += sprintf(outp, "  RAM_%% "); +		outp += sprintf(outp, "  time "); + +	} +	outp += sprintf(outp, "\n"); +} + +int dump_counters(struct thread_data *t, struct core_data *c, +	struct pkg_data *p) +{ +	outp += sprintf(outp, "t %p, c %p, p %p\n", t, c, p); + +	if (t) { +		outp += sprintf(outp, "CPU: %d flags 0x%x\n", +			t->cpu_id, t->flags); +		outp += sprintf(outp, "TSC: %016llX\n", t->tsc); +		outp += sprintf(outp, "aperf: %016llX\n", t->aperf); +		outp += sprintf(outp, "mperf: %016llX\n", t->mperf); +		outp += sprintf(outp, "c1: %016llX\n", t->c1); +		outp += sprintf(outp, "msr0x%x: %08llX\n", +			extra_delta_offset32, t->extra_delta32); +		outp += sprintf(outp, "msr0x%x: %016llX\n", +			extra_delta_offset64, t->extra_delta64); +		outp += sprintf(outp, "msr0x%x: %08llX\n", +			extra_msr_offset32, t->extra_msr32); +		outp += sprintf(outp, "msr0x%x: %016llX\n", +			extra_msr_offset64, t->extra_msr64); +		if (do_smi) +			outp += sprintf(outp, "SMI: %08X\n", t->smi_count); +	} + +	if (c) { +		outp += sprintf(outp, "core: %d\n", c->core_id); +		outp += sprintf(outp, "c3: %016llX\n", c->c3); +		outp += sprintf(outp, "c6: %016llX\n", c->c6); +		outp += sprintf(outp, "c7: %016llX\n", c->c7); +		outp += sprintf(outp, "DTS: %dC\n", c->core_temp_c); +	} + +	if (p) { +		outp += sprintf(outp, "package: %d\n", p->package_id); +		outp += sprintf(outp, "pc2: %016llX\n", p->pc2); +		outp += sprintf(outp, "pc3: %016llX\n", p->pc3); +		outp += sprintf(outp, "pc6: %016llX\n", p->pc6); +		outp += sprintf(outp, "pc7: %016llX\n", p->pc7); +		outp += sprintf(outp, "pc8: %016llX\n", p->pc8); +		outp += sprintf(outp, "pc9: %016llX\n", p->pc9); +		outp += sprintf(outp, "pc10: %016llX\n", p->pc10); +		outp += sprintf(outp, "Joules PKG: %0X\n", p->energy_pkg); +		outp += sprintf(outp, "Joules COR: %0X\n", p->energy_cores); +		outp += sprintf(outp, "Joules GFX: %0X\n", p->energy_gfx); +		outp += sprintf(outp, "Joules RAM: %0X\n", p->energy_dram); +		outp += sprintf(outp, "Throttle PKG: %0X\n", +			p->rapl_pkg_perf_status); +		outp += sprintf(outp, "Throttle RAM: %0X\n", +			p->rapl_dram_perf_status); +		outp += sprintf(outp, "PTM: %dC\n", p->pkg_temp_c); +	} + +	outp += sprintf(outp, "\n"); + +	return 0; +} + +/* + * column formatting convention & formats + */ +int format_counters(struct thread_data *t, struct core_data *c, +	struct pkg_data *p) +{ +	double interval_float; +	char *fmt8; + +	 /* if showing only 1st thread in core and this isn't one, bail out */ +	if (show_core_only && !(t->flags & CPU_IS_FIRST_THREAD_IN_CORE)) +		return 0; + +	 /* if showing only 1st thread in pkg and this isn't one, bail out */ +	if (show_pkg_only && !(t->flags & CPU_IS_FIRST_CORE_IN_PACKAGE)) +		return 0; + +	interval_float = tv_delta.tv_sec + tv_delta.tv_usec/1000000.0; + +	/* topo columns, print blanks on 1st (average) line */ +	if (t == &average.threads) { +		if (show_pkg) +			outp += sprintf(outp, "       -"); +		if (show_core) +			outp += sprintf(outp, "       -"); +		if (show_cpu) +			outp += sprintf(outp, "       -"); +	} else { +		if (show_pkg) { +			if (p) +				outp += sprintf(outp, "%8d", p->package_id); +			else +				outp += sprintf(outp, "       -"); +		} +		if (show_core) { +			if (c) +				outp += sprintf(outp, "%8d", c->core_id); +			else +				outp += sprintf(outp, "       -"); +		} +		if (show_cpu) +			outp += sprintf(outp, "%8d", t->cpu_id); +	} + +	/* AvgMHz */ +	if (has_aperf) +		outp += sprintf(outp, "%8.0f", +			1.0 / units * t->aperf / interval_float); + +	/* %c0 */ +	if (do_nhm_cstates) { +		if (!skip_c0) +			outp += sprintf(outp, "%8.2f", 100.0 * t->mperf/t->tsc); +		else +			outp += sprintf(outp, "********"); +	} + +	/* BzyMHz */ +	if (has_aperf) +		outp += sprintf(outp, "%8.0f", +			1.0 * t->tsc / units * t->aperf / t->mperf / interval_float); + +	/* TSC */ +	outp += sprintf(outp, "%8.0f", 1.0 * t->tsc/units/interval_float); + +	/* SMI */ +	if (do_smi) +		outp += sprintf(outp, "%8d", t->smi_count); + +	/* delta */ +	if (extra_delta_offset32) +		outp += sprintf(outp, "  %11llu", t->extra_delta32); + +	/* DELTA */ +	if (extra_delta_offset64) +		outp += sprintf(outp, "  %11llu", t->extra_delta64); +	/* msr */ +	if (extra_msr_offset32) +		outp += sprintf(outp, "  0x%08llx", t->extra_msr32); + +	/* MSR */ +	if (extra_msr_offset64) +		outp += sprintf(outp, "  0x%016llx", t->extra_msr64); + +	if (do_nhm_cstates) { +		if (!skip_c1) +			outp += sprintf(outp, "%8.2f", 100.0 * t->c1/t->tsc); +		else +			outp += sprintf(outp, "********"); +	} + +	/* print per-core data only for 1st thread in core */ +	if (!(t->flags & CPU_IS_FIRST_THREAD_IN_CORE)) +		goto done; + +	if (do_nhm_cstates && !do_slm_cstates) +		outp += sprintf(outp, "%8.2f", 100.0 * c->c3/t->tsc); +	if (do_nhm_cstates) +		outp += sprintf(outp, "%8.2f", 100.0 * c->c6/t->tsc); +	if (do_snb_cstates) +		outp += sprintf(outp, "%8.2f", 100.0 * c->c7/t->tsc); + +	if (do_dts) +		outp += sprintf(outp, "%8d", c->core_temp_c); + +	/* print per-package data only for 1st core in package */ +	if (!(t->flags & CPU_IS_FIRST_CORE_IN_PACKAGE)) +		goto done; + +	if (do_ptm) +		outp += sprintf(outp, "%8d", p->pkg_temp_c); + +	if (do_snb_cstates) +		outp += sprintf(outp, "%8.2f", 100.0 * p->pc2/t->tsc); +	if (do_nhm_cstates && !do_slm_cstates) +		outp += sprintf(outp, "%8.2f", 100.0 * p->pc3/t->tsc); +	if (do_nhm_cstates && !do_slm_cstates) +		outp += sprintf(outp, "%8.2f", 100.0 * p->pc6/t->tsc); +	if (do_snb_cstates) +		outp += sprintf(outp, "%8.2f", 100.0 * p->pc7/t->tsc); +	if (do_c8_c9_c10) { +		outp += sprintf(outp, "%8.2f", 100.0 * p->pc8/t->tsc); +		outp += sprintf(outp, "%8.2f", 100.0 * p->pc9/t->tsc); +		outp += sprintf(outp, "%8.2f", 100.0 * p->pc10/t->tsc); +	} + +	/* + 	 * If measurement interval exceeds minimum RAPL Joule Counter range, + 	 * indicate that results are suspect by printing "**" in fraction place. + 	 */ +	if (interval_float < rapl_joule_counter_range) +		fmt8 = "%8.2f"; +	else +		fmt8 = " %6.0f**"; + +	if (do_rapl && !rapl_joules) { +		if (do_rapl & RAPL_PKG) +			outp += sprintf(outp, fmt8, p->energy_pkg * rapl_energy_units / interval_float); +		if (do_rapl & RAPL_CORES) +			outp += sprintf(outp, fmt8, p->energy_cores * rapl_energy_units / interval_float); +		if (do_rapl & RAPL_GFX) +			outp += sprintf(outp, fmt8, p->energy_gfx * rapl_energy_units / interval_float); +		if (do_rapl & RAPL_DRAM) +			outp += sprintf(outp, fmt8, p->energy_dram * rapl_energy_units / interval_float); +		if (do_rapl & RAPL_PKG_PERF_STATUS) +			outp += sprintf(outp, fmt8, 100.0 * p->rapl_pkg_perf_status * rapl_time_units / interval_float); +		if (do_rapl & RAPL_DRAM_PERF_STATUS) +			outp += sprintf(outp, fmt8, 100.0 * p->rapl_dram_perf_status * rapl_time_units / interval_float); +	} else { +		if (do_rapl & RAPL_PKG) +			outp += sprintf(outp, fmt8, +					p->energy_pkg * rapl_energy_units); +		if (do_rapl & RAPL_CORES) +			outp += sprintf(outp, fmt8, +					p->energy_cores * rapl_energy_units); +		if (do_rapl & RAPL_GFX) +			outp += sprintf(outp, fmt8, +					p->energy_gfx * rapl_energy_units); +		if (do_rapl & RAPL_DRAM) +			outp += sprintf(outp, fmt8, +					p->energy_dram * rapl_energy_units); +		if (do_rapl & RAPL_PKG_PERF_STATUS) +			outp += sprintf(outp, fmt8, 100.0 * p->rapl_pkg_perf_status * rapl_time_units / interval_float); +		if (do_rapl & RAPL_DRAM_PERF_STATUS) +			outp += sprintf(outp, fmt8, 100.0 * p->rapl_dram_perf_status * rapl_time_units / interval_float); +	outp += sprintf(outp, fmt8, interval_float); + +	} +done: +	outp += sprintf(outp, "\n"); + +	return 0; +} + +void flush_stdout() +{ +	fputs(output_buffer, stdout); +	fflush(stdout); +	outp = output_buffer; +} +void flush_stderr() +{ +	fputs(output_buffer, stderr); +	outp = output_buffer; +} +void format_all_counters(struct thread_data *t, struct core_data *c, struct pkg_data *p) +{ +	static int printed; + +	if (!printed || !summary_only) +		print_header(); + +	if (topo.num_cpus > 1) +		format_counters(&average.threads, &average.cores, +			&average.packages); + +	printed = 1; + +	if (summary_only) +		return; + +	for_all_cpus(format_counters, t, c, p); +} + +#define DELTA_WRAP32(new, old)			\ +	if (new > old) {			\ +		old = new - old;		\ +	} else {				\ +		old = 0x100000000 + new - old;	\ +	} + +void +delta_package(struct pkg_data *new, struct pkg_data *old) +{ +	old->pc2 = new->pc2 - old->pc2; +	old->pc3 = new->pc3 - old->pc3; +	old->pc6 = new->pc6 - old->pc6; +	old->pc7 = new->pc7 - old->pc7; +	old->pc8 = new->pc8 - old->pc8; +	old->pc9 = new->pc9 - old->pc9; +	old->pc10 = new->pc10 - old->pc10; +	old->pkg_temp_c = new->pkg_temp_c; + +	DELTA_WRAP32(new->energy_pkg, old->energy_pkg); +	DELTA_WRAP32(new->energy_cores, old->energy_cores); +	DELTA_WRAP32(new->energy_gfx, old->energy_gfx); +	DELTA_WRAP32(new->energy_dram, old->energy_dram); +	DELTA_WRAP32(new->rapl_pkg_perf_status, old->rapl_pkg_perf_status); +	DELTA_WRAP32(new->rapl_dram_perf_status, old->rapl_dram_perf_status); +} + +void +delta_core(struct core_data *new, struct core_data *old) +{ +	old->c3 = new->c3 - old->c3; +	old->c6 = new->c6 - old->c6; +	old->c7 = new->c7 - old->c7; +	old->core_temp_c = new->core_temp_c; +} + +/* + * old = new - old + */ +void +delta_thread(struct thread_data *new, struct thread_data *old, +	struct core_data *core_delta) +{ +	old->tsc = new->tsc - old->tsc; + +	/* check for TSC < 1 Mcycles over interval */ +	if (old->tsc < (1000 * 1000)) +		errx(-3, "Insanely slow TSC rate, TSC stops in idle?\n" +		     "You can disable all c-states by booting with \"idle=poll\"\n" +		     "or just the deep ones with \"processor.max_cstate=1\""); + +	old->c1 = new->c1 - old->c1; + +	if ((new->aperf > old->aperf) && (new->mperf > old->mperf)) { +		old->aperf = new->aperf - old->aperf; +		old->mperf = new->mperf - old->mperf; +	} else { + +		if (!aperf_mperf_unstable) { +			fprintf(stderr, "%s: APERF or MPERF went backwards *\n", progname); +			fprintf(stderr, "* Frequency results do not cover entire interval *\n"); +			fprintf(stderr, "* fix this by running Linux-2.6.30 or later *\n"); + +			aperf_mperf_unstable = 1; +		} +		/* +		 * mperf delta is likely a huge "positive" number +		 * can not use it for calculating c0 time +		 */ +		skip_c0 = 1; +		skip_c1 = 1; +	} + + +	if (use_c1_residency_msr) { +		/* +		 * Some models have a dedicated C1 residency MSR, +		 * which should be more accurate than the derivation below. +		 */ +	} else { +		/* +		 * As counter collection is not atomic, +		 * it is possible for mperf's non-halted cycles + idle states +		 * to exceed TSC's all cycles: show c1 = 0% in that case. +		 */ +		if ((old->mperf + core_delta->c3 + core_delta->c6 + core_delta->c7) > old->tsc) +			old->c1 = 0; +		else { +			/* normal case, derive c1 */ +			old->c1 = old->tsc - old->mperf - core_delta->c3 +				- core_delta->c6 - core_delta->c7; +		} +	} + +	if (old->mperf == 0) { +		if (verbose > 1) fprintf(stderr, "cpu%d MPERF 0!\n", old->cpu_id); +		old->mperf = 1;	/* divide by 0 protection */ +	} + +	old->extra_delta32 = new->extra_delta32 - old->extra_delta32; +	old->extra_delta32 &= 0xFFFFFFFF; + +	old->extra_delta64 = new->extra_delta64 - old->extra_delta64; + +	/* +	 * Extra MSR is just a snapshot, simply copy latest w/o subtracting +	 */ +	old->extra_msr32 = new->extra_msr32; +	old->extra_msr64 = new->extra_msr64; + +	if (do_smi) +		old->smi_count = new->smi_count - old->smi_count; +} + +int delta_cpu(struct thread_data *t, struct core_data *c, +	struct pkg_data *p, struct thread_data *t2, +	struct core_data *c2, struct pkg_data *p2) +{ +	/* calculate core delta only for 1st thread in core */ +	if (t->flags & CPU_IS_FIRST_THREAD_IN_CORE) +		delta_core(c, c2); + +	/* always calculate thread delta */ +	delta_thread(t, t2, c2);	/* c2 is core delta */ + +	/* calculate package delta only for 1st core in package */ +	if (t->flags & CPU_IS_FIRST_CORE_IN_PACKAGE) +		delta_package(p, p2); + +	return 0; +} + +void clear_counters(struct thread_data *t, struct core_data *c, struct pkg_data *p) +{ +	t->tsc = 0; +	t->aperf = 0; +	t->mperf = 0; +	t->c1 = 0; + +	t->smi_count = 0; +	t->extra_delta32 = 0; +	t->extra_delta64 = 0; + +	/* tells format_counters to dump all fields from this set */ +	t->flags = CPU_IS_FIRST_THREAD_IN_CORE | CPU_IS_FIRST_CORE_IN_PACKAGE; + +	c->c3 = 0; +	c->c6 = 0; +	c->c7 = 0; +	c->core_temp_c = 0; + +	p->pc2 = 0; +	p->pc3 = 0; +	p->pc6 = 0; +	p->pc7 = 0; +	p->pc8 = 0; +	p->pc9 = 0; +	p->pc10 = 0; + +	p->energy_pkg = 0; +	p->energy_dram = 0; +	p->energy_cores = 0; +	p->energy_gfx = 0; +	p->rapl_pkg_perf_status = 0; +	p->rapl_dram_perf_status = 0; +	p->pkg_temp_c = 0; +} +int sum_counters(struct thread_data *t, struct core_data *c, +	struct pkg_data *p) +{ +	average.threads.tsc += t->tsc; +	average.threads.aperf += t->aperf; +	average.threads.mperf += t->mperf; +	average.threads.c1 += t->c1; + +	average.threads.extra_delta32 += t->extra_delta32; +	average.threads.extra_delta64 += t->extra_delta64; + +	/* sum per-core values only for 1st thread in core */ +	if (!(t->flags & CPU_IS_FIRST_THREAD_IN_CORE)) +		return 0; + +	average.cores.c3 += c->c3; +	average.cores.c6 += c->c6; +	average.cores.c7 += c->c7; + +	average.cores.core_temp_c = MAX(average.cores.core_temp_c, c->core_temp_c); + +	/* sum per-pkg values only for 1st core in pkg */ +	if (!(t->flags & CPU_IS_FIRST_CORE_IN_PACKAGE)) +		return 0; + +	average.packages.pc2 += p->pc2; +	average.packages.pc3 += p->pc3; +	average.packages.pc6 += p->pc6; +	average.packages.pc7 += p->pc7; +	average.packages.pc8 += p->pc8; +	average.packages.pc9 += p->pc9; +	average.packages.pc10 += p->pc10; + +	average.packages.energy_pkg += p->energy_pkg; +	average.packages.energy_dram += p->energy_dram; +	average.packages.energy_cores += p->energy_cores; +	average.packages.energy_gfx += p->energy_gfx; + +	average.packages.pkg_temp_c = MAX(average.packages.pkg_temp_c, p->pkg_temp_c); + +	average.packages.rapl_pkg_perf_status += p->rapl_pkg_perf_status; +	average.packages.rapl_dram_perf_status += p->rapl_dram_perf_status; +	return 0; +} +/* + * sum the counters for all cpus in the system + * compute the weighted average + */ +void compute_average(struct thread_data *t, struct core_data *c, +	struct pkg_data *p) +{ +	clear_counters(&average.threads, &average.cores, &average.packages); + +	for_all_cpus(sum_counters, t, c, p); + +	average.threads.tsc /= topo.num_cpus; +	average.threads.aperf /= topo.num_cpus; +	average.threads.mperf /= topo.num_cpus; +	average.threads.c1 /= topo.num_cpus; + +	average.threads.extra_delta32 /= topo.num_cpus; +	average.threads.extra_delta32 &= 0xFFFFFFFF; + +	average.threads.extra_delta64 /= topo.num_cpus; + +	average.cores.c3 /= topo.num_cores; +	average.cores.c6 /= topo.num_cores; +	average.cores.c7 /= topo.num_cores; + +	average.packages.pc2 /= topo.num_packages; +	average.packages.pc3 /= topo.num_packages; +	average.packages.pc6 /= topo.num_packages; +	average.packages.pc7 /= topo.num_packages; + +	average.packages.pc8 /= topo.num_packages; +	average.packages.pc9 /= topo.num_packages; +	average.packages.pc10 /= topo.num_packages; +} + +static unsigned long long rdtsc(void) +{ +	unsigned int low, high; + +	asm volatile("rdtsc" : "=a" (low), "=d" (high)); + +	return low | ((unsigned long long)high) << 32; +} + + +/* + * get_counters(...) + * migrate to cpu + * acquire and record local counters for that cpu + */ +int get_counters(struct thread_data *t, struct core_data *c, struct pkg_data *p) +{ +	int cpu = t->cpu_id; +	unsigned long long msr; + +	if (cpu_migrate(cpu)) { +		fprintf(stderr, "Could not migrate to CPU %d\n", cpu); +		return -1; +	} + +	t->tsc = rdtsc();	/* we are running on local CPU of interest */ + +	if (has_aperf) { +		if (get_msr(cpu, MSR_IA32_APERF, &t->aperf)) +			return -3; +		if (get_msr(cpu, MSR_IA32_MPERF, &t->mperf)) +			return -4; +	} + +	if (do_smi) { +		if (get_msr(cpu, MSR_SMI_COUNT, &msr)) +			return -5; +		t->smi_count = msr & 0xFFFFFFFF; +	} +	if (extra_delta_offset32) { +		if (get_msr(cpu, extra_delta_offset32, &msr)) +			return -5; +		t->extra_delta32 = msr & 0xFFFFFFFF; +	} + +	if (extra_delta_offset64) +		if (get_msr(cpu, extra_delta_offset64, &t->extra_delta64)) +			return -5; + +	if (extra_msr_offset32) { +		if (get_msr(cpu, extra_msr_offset32, &msr)) +			return -5; +		t->extra_msr32 = msr & 0xFFFFFFFF; +	} + +	if (extra_msr_offset64) +		if (get_msr(cpu, extra_msr_offset64, &t->extra_msr64)) +			return -5; + +	if (use_c1_residency_msr) { +		if (get_msr(cpu, MSR_CORE_C1_RES, &t->c1)) +			return -6; +	} + +	/* collect core counters only for 1st thread in core */ +	if (!(t->flags & CPU_IS_FIRST_THREAD_IN_CORE)) +		return 0; + +	if (do_nhm_cstates && !do_slm_cstates) { +		if (get_msr(cpu, MSR_CORE_C3_RESIDENCY, &c->c3)) +			return -6; +	} + +	if (do_nhm_cstates) { +		if (get_msr(cpu, MSR_CORE_C6_RESIDENCY, &c->c6)) +			return -7; +	} + +	if (do_snb_cstates) +		if (get_msr(cpu, MSR_CORE_C7_RESIDENCY, &c->c7)) +			return -8; + +	if (do_dts) { +		if (get_msr(cpu, MSR_IA32_THERM_STATUS, &msr)) +			return -9; +		c->core_temp_c = tcc_activation_temp - ((msr >> 16) & 0x7F); +	} + + +	/* collect package counters only for 1st core in package */ +	if (!(t->flags & CPU_IS_FIRST_CORE_IN_PACKAGE)) +		return 0; + +	if (do_nhm_cstates && !do_slm_cstates) { +		if (get_msr(cpu, MSR_PKG_C3_RESIDENCY, &p->pc3)) +			return -9; +		if (get_msr(cpu, MSR_PKG_C6_RESIDENCY, &p->pc6)) +			return -10; +	} +	if (do_snb_cstates) { +		if (get_msr(cpu, MSR_PKG_C2_RESIDENCY, &p->pc2)) +			return -11; +		if (get_msr(cpu, MSR_PKG_C7_RESIDENCY, &p->pc7)) +			return -12; +	} +	if (do_c8_c9_c10) { +		if (get_msr(cpu, MSR_PKG_C8_RESIDENCY, &p->pc8)) +			return -13; +		if (get_msr(cpu, MSR_PKG_C9_RESIDENCY, &p->pc9)) +			return -13; +		if (get_msr(cpu, MSR_PKG_C10_RESIDENCY, &p->pc10)) +			return -13; +	} +	if (do_rapl & RAPL_PKG) { +		if (get_msr(cpu, MSR_PKG_ENERGY_STATUS, &msr)) +			return -13; +		p->energy_pkg = msr & 0xFFFFFFFF; +	} +	if (do_rapl & RAPL_CORES) { +		if (get_msr(cpu, MSR_PP0_ENERGY_STATUS, &msr)) +			return -14; +		p->energy_cores = msr & 0xFFFFFFFF; +	} +	if (do_rapl & RAPL_DRAM) { +		if (get_msr(cpu, MSR_DRAM_ENERGY_STATUS, &msr)) +			return -15; +		p->energy_dram = msr & 0xFFFFFFFF; +	} +	if (do_rapl & RAPL_GFX) { +		if (get_msr(cpu, MSR_PP1_ENERGY_STATUS, &msr)) +			return -16; +		p->energy_gfx = msr & 0xFFFFFFFF; +	} +	if (do_rapl & RAPL_PKG_PERF_STATUS) { +		if (get_msr(cpu, MSR_PKG_PERF_STATUS, &msr)) +			return -16; +		p->rapl_pkg_perf_status = msr & 0xFFFFFFFF; +	} +	if (do_rapl & RAPL_DRAM_PERF_STATUS) { +		if (get_msr(cpu, MSR_DRAM_PERF_STATUS, &msr)) +			return -16; +		p->rapl_dram_perf_status = msr & 0xFFFFFFFF; +	} +	if (do_ptm) { +		if (get_msr(cpu, MSR_IA32_PACKAGE_THERM_STATUS, &msr)) +			return -17; +		p->pkg_temp_c = tcc_activation_temp - ((msr >> 16) & 0x7F); +	} +	return 0; +} + +void print_verbose_header(void) +{ +	unsigned long long msr; +	unsigned int ratio; + +	if (!do_nehalem_platform_info) +		return; + +	get_msr(0, MSR_NHM_PLATFORM_INFO, &msr); + +	fprintf(stderr, "cpu0: MSR_NHM_PLATFORM_INFO: 0x%08llx\n", msr); + +	ratio = (msr >> 40) & 0xFF; +	fprintf(stderr, "%d * %.0f = %.0f MHz max efficiency\n", +		ratio, bclk, ratio * bclk); + +	ratio = (msr >> 8) & 0xFF; +	fprintf(stderr, "%d * %.0f = %.0f MHz TSC frequency\n", +		ratio, bclk, ratio * bclk); + +	get_msr(0, MSR_IA32_POWER_CTL, &msr); +	fprintf(stderr, "cpu0: MSR_IA32_POWER_CTL: 0x%08llx (C1E auto-promotion: %sabled)\n", +		msr, msr & 0x2 ? "EN" : "DIS"); + +	if (!do_ivt_turbo_ratio_limit) +		goto print_nhm_turbo_ratio_limits; + +	get_msr(0, MSR_IVT_TURBO_RATIO_LIMIT, &msr); + +	fprintf(stderr, "cpu0: MSR_IVT_TURBO_RATIO_LIMIT: 0x%08llx\n", msr); + +	ratio = (msr >> 56) & 0xFF; +	if (ratio) +		fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 16 active cores\n", +			ratio, bclk, ratio * bclk); + +	ratio = (msr >> 48) & 0xFF; +	if (ratio) +		fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 15 active cores\n", +			ratio, bclk, ratio * bclk); + +	ratio = (msr >> 40) & 0xFF; +	if (ratio) +		fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 14 active cores\n", +			ratio, bclk, ratio * bclk); + +	ratio = (msr >> 32) & 0xFF; +	if (ratio) +		fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 13 active cores\n", +			ratio, bclk, ratio * bclk); + +	ratio = (msr >> 24) & 0xFF; +	if (ratio) +		fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 12 active cores\n", +			ratio, bclk, ratio * bclk); + +	ratio = (msr >> 16) & 0xFF; +	if (ratio) +		fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 11 active cores\n", +			ratio, bclk, ratio * bclk); + +	ratio = (msr >> 8) & 0xFF; +	if (ratio) +		fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 10 active cores\n", +			ratio, bclk, ratio * bclk); + +	ratio = (msr >> 0) & 0xFF; +	if (ratio) +		fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 9 active cores\n", +			ratio, bclk, ratio * bclk); + +print_nhm_turbo_ratio_limits: +	get_msr(0, MSR_NHM_SNB_PKG_CST_CFG_CTL, &msr); + +#define SNB_C1_AUTO_UNDEMOTE              (1UL << 27) +#define SNB_C3_AUTO_UNDEMOTE              (1UL << 28) + +	fprintf(stderr, "cpu0: MSR_NHM_SNB_PKG_CST_CFG_CTL: 0x%08llx", msr); + +	fprintf(stderr, " (%s%s%s%s%slocked: pkg-cstate-limit=%d: ", +		(msr & SNB_C3_AUTO_UNDEMOTE) ? "UNdemote-C3, " : "", +		(msr & SNB_C1_AUTO_UNDEMOTE) ? "UNdemote-C1, " : "", +		(msr & NHM_C3_AUTO_DEMOTE) ? "demote-C3, " : "", +		(msr & NHM_C1_AUTO_DEMOTE) ? "demote-C1, " : "", +		(msr & (1 << 15)) ? "" : "UN", +		(unsigned int)msr & 7); + + +	switch(msr & 0x7) { +	case 0: +		fprintf(stderr, do_slm_cstates ? "no pkg states" : "pc0"); +		break; +	case 1: +		fprintf(stderr, do_slm_cstates ? "no pkg states" : do_snb_cstates ? "pc2" : "pc0"); +		break; +	case 2: +		fprintf(stderr, do_slm_cstates ? "invalid" : do_snb_cstates ? "pc6-noret" : "pc3"); +		break; +	case 3: +		fprintf(stderr, do_slm_cstates ? "invalid" : "pc6"); +		break; +	case 4: +		fprintf(stderr, do_slm_cstates ? "pc4" : "pc7"); +		break; +	case 5: +		fprintf(stderr, do_slm_cstates ? "invalid" : do_snb_cstates ? "pc7s" : "invalid"); +		break; +	case 6: +		fprintf(stderr, do_slm_cstates ? "pc6" : "invalid"); +		break; +	case 7: +		fprintf(stderr, do_slm_cstates ? "pc7" : "unlimited"); +		break; +	default: +		fprintf(stderr, "invalid"); +	} +	fprintf(stderr, ")\n"); + +	if (!do_nehalem_turbo_ratio_limit) +		return; + +	get_msr(0, MSR_NHM_TURBO_RATIO_LIMIT, &msr); + +	fprintf(stderr, "cpu0: MSR_NHM_TURBO_RATIO_LIMIT: 0x%08llx\n", msr); + +	ratio = (msr >> 56) & 0xFF; +	if (ratio) +		fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 8 active cores\n", +			ratio, bclk, ratio * bclk); + +	ratio = (msr >> 48) & 0xFF; +	if (ratio) +		fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 7 active cores\n", +			ratio, bclk, ratio * bclk); + +	ratio = (msr >> 40) & 0xFF; +	if (ratio) +		fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 6 active cores\n", +			ratio, bclk, ratio * bclk); + +	ratio = (msr >> 32) & 0xFF; +	if (ratio) +		fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 5 active cores\n", +			ratio, bclk, ratio * bclk); + +	ratio = (msr >> 24) & 0xFF; +	if (ratio) +		fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 4 active cores\n", +			ratio, bclk, ratio * bclk); + +	ratio = (msr >> 16) & 0xFF; +	if (ratio) +		fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 3 active cores\n", +			ratio, bclk, ratio * bclk); + +	ratio = (msr >> 8) & 0xFF; +	if (ratio) +		fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 2 active cores\n", +			ratio, bclk, ratio * bclk); + +	ratio = (msr >> 0) & 0xFF; +	if (ratio) +		fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 1 active cores\n", +			ratio, bclk, ratio * bclk); +} + +void free_all_buffers(void) +{ +	CPU_FREE(cpu_present_set); +	cpu_present_set = NULL; +	cpu_present_set = 0; + +	CPU_FREE(cpu_affinity_set); +	cpu_affinity_set = NULL; +	cpu_affinity_setsize = 0; + +	free(thread_even); +	free(core_even); +	free(package_even); + +	thread_even = NULL; +	core_even = NULL; +	package_even = NULL; + +	free(thread_odd); +	free(core_odd); +	free(package_odd); + +	thread_odd = NULL; +	core_odd = NULL; +	package_odd = NULL; + +	free(output_buffer); +	output_buffer = NULL; +	outp = NULL; +} + +/* + * Open a file, and exit on failure + */ +FILE *fopen_or_die(const char *path, const char *mode) +{ +	FILE *filep = fopen(path, "r"); +	if (!filep) +		err(1, "%s: open failed", path); +	return filep; +} + +/* + * Parse a file containing a single int. + */ +int parse_int_file(const char *fmt, ...) +{ +	va_list args; +	char path[PATH_MAX]; +	FILE *filep; +	int value; + +	va_start(args, fmt); +	vsnprintf(path, sizeof(path), fmt, args); +	va_end(args); +	filep = fopen_or_die(path, "r"); +	if (fscanf(filep, "%d", &value) != 1) +		err(1, "%s: failed to parse number from file", path); +	fclose(filep); +	return value; +} + +/* + * cpu_is_first_sibling_in_core(cpu) + * return 1 if given CPU is 1st HT sibling in the core + */ +int cpu_is_first_sibling_in_core(int cpu) +{ +	return cpu == parse_int_file("/sys/devices/system/cpu/cpu%d/topology/thread_siblings_list", cpu); +} + +/* + * cpu_is_first_core_in_package(cpu) + * return 1 if given CPU is 1st core in package + */ +int cpu_is_first_core_in_package(int cpu) +{ +	return cpu == parse_int_file("/sys/devices/system/cpu/cpu%d/topology/core_siblings_list", cpu); +} + +int get_physical_package_id(int cpu) +{ +	return parse_int_file("/sys/devices/system/cpu/cpu%d/topology/physical_package_id", cpu); +} + +int get_core_id(int cpu) +{ +	return parse_int_file("/sys/devices/system/cpu/cpu%d/topology/core_id", cpu); +} + +int get_num_ht_siblings(int cpu) +{ +	char path[80]; +	FILE *filep; +	int sib1, sib2; +	int matches; +	char character; + +	sprintf(path, "/sys/devices/system/cpu/cpu%d/topology/thread_siblings_list", cpu); +	filep = fopen_or_die(path, "r"); +	/* +	 * file format: +	 * if a pair of number with a character between: 2 siblings (eg. 1-2, or 1,4) +	 * otherwinse 1 sibling (self). +	 */ +	matches = fscanf(filep, "%d%c%d\n", &sib1, &character, &sib2); + +	fclose(filep); + +	if (matches == 3) +		return 2; +	else +		return 1; +} + +/* + * run func(thread, core, package) in topology order + * skip non-present cpus + */ + +int for_all_cpus_2(int (func)(struct thread_data *, struct core_data *, +	struct pkg_data *, struct thread_data *, struct core_data *, +	struct pkg_data *), struct thread_data *thread_base, +	struct core_data *core_base, struct pkg_data *pkg_base, +	struct thread_data *thread_base2, struct core_data *core_base2, +	struct pkg_data *pkg_base2) +{ +	int retval, pkg_no, core_no, thread_no; + +	for (pkg_no = 0; pkg_no < topo.num_packages; ++pkg_no) { +		for (core_no = 0; core_no < topo.num_cores_per_pkg; ++core_no) { +			for (thread_no = 0; thread_no < +				topo.num_threads_per_core; ++thread_no) { +				struct thread_data *t, *t2; +				struct core_data *c, *c2; +				struct pkg_data *p, *p2; + +				t = GET_THREAD(thread_base, thread_no, core_no, pkg_no); + +				if (cpu_is_not_present(t->cpu_id)) +					continue; + +				t2 = GET_THREAD(thread_base2, thread_no, core_no, pkg_no); + +				c = GET_CORE(core_base, core_no, pkg_no); +				c2 = GET_CORE(core_base2, core_no, pkg_no); + +				p = GET_PKG(pkg_base, pkg_no); +				p2 = GET_PKG(pkg_base2, pkg_no); + +				retval = func(t, c, p, t2, c2, p2); +				if (retval) +					return retval; +			} +		} +	} +	return 0; +} + +/* + * run func(cpu) on every cpu in /proc/stat + * return max_cpu number + */ +int for_all_proc_cpus(int (func)(int)) +{ +	FILE *fp; +	int cpu_num; +	int retval; + +	fp = fopen_or_die(proc_stat, "r"); + +	retval = fscanf(fp, "cpu %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d\n"); +	if (retval != 0) +		err(1, "%s: failed to parse format", proc_stat); + +	while (1) { +		retval = fscanf(fp, "cpu%u %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d\n", &cpu_num); +		if (retval != 1) +			break; + +		retval = func(cpu_num); +		if (retval) { +			fclose(fp); +			return(retval); +		} +	} +	fclose(fp); +	return 0; +} + +void re_initialize(void) +{ +	free_all_buffers(); +	setup_all_buffers(); +	printf("turbostat: re-initialized with num_cpus %d\n", topo.num_cpus); +} + + +/* + * count_cpus() + * remember the last one seen, it will be the max + */ +int count_cpus(int cpu) +{ +	if (topo.max_cpu_num < cpu) +		topo.max_cpu_num = cpu; + +	topo.num_cpus += 1; +	return 0; +} +int mark_cpu_present(int cpu) +{ +	CPU_SET_S(cpu, cpu_present_setsize, cpu_present_set); +	return 0; +} + +void turbostat_loop() +{ +	int retval; +	int restarted = 0; + +restart: +	restarted++; + +	retval = for_all_cpus(get_counters, EVEN_COUNTERS); +	if (retval < -1) { +		exit(retval); +	} else if (retval == -1) { +		if (restarted > 1) { +			exit(retval); +		} +		re_initialize(); +		goto restart; +	} +	restarted = 0; +	gettimeofday(&tv_even, (struct timezone *)NULL); + +	while (1) { +		if (for_all_proc_cpus(cpu_is_not_present)) { +			re_initialize(); +			goto restart; +		} +		sleep(interval_sec); +		retval = for_all_cpus(get_counters, ODD_COUNTERS); +		if (retval < -1) { +			exit(retval); +		} else if (retval == -1) { +			re_initialize(); +			goto restart; +		} +		gettimeofday(&tv_odd, (struct timezone *)NULL); +		timersub(&tv_odd, &tv_even, &tv_delta); +		for_all_cpus_2(delta_cpu, ODD_COUNTERS, EVEN_COUNTERS); +		compute_average(EVEN_COUNTERS); +		format_all_counters(EVEN_COUNTERS); +		flush_stdout(); +		sleep(interval_sec); +		retval = for_all_cpus(get_counters, EVEN_COUNTERS); +		if (retval < -1) { +			exit(retval); +		} else if (retval == -1) { +			re_initialize(); +			goto restart; +		} +		gettimeofday(&tv_even, (struct timezone *)NULL); +		timersub(&tv_even, &tv_odd, &tv_delta); +		for_all_cpus_2(delta_cpu, EVEN_COUNTERS, ODD_COUNTERS); +		compute_average(ODD_COUNTERS); +		format_all_counters(ODD_COUNTERS); +		flush_stdout(); +	} +} + +void check_dev_msr() +{ +	struct stat sb; + +	if (stat("/dev/cpu/0/msr", &sb)) +		err(-5, "no /dev/cpu/0/msr\n" +		    "Try \"# modprobe msr\""); +} + +void check_super_user() +{ +	if (getuid() != 0) +		errx(-6, "must be root"); +} + +int has_nehalem_turbo_ratio_limit(unsigned int family, unsigned int model) +{ +	if (!genuine_intel) +		return 0; + +	if (family != 6) +		return 0; + +	switch (model) { +	case 0x1A:	/* Core i7, Xeon 5500 series - Bloomfield, Gainstown NHM-EP */ +	case 0x1E:	/* Core i7 and i5 Processor - Clarksfield, Lynnfield, Jasper Forest */ +	case 0x1F:	/* Core i7 and i5 Processor - Nehalem */ +	case 0x25:	/* Westmere Client - Clarkdale, Arrandale */ +	case 0x2C:	/* Westmere EP - Gulftown */ +	case 0x2A:	/* SNB */ +	case 0x2D:	/* SNB Xeon */ +	case 0x3A:	/* IVB */ +	case 0x3E:	/* IVB Xeon */ +	case 0x3C:	/* HSW */ +	case 0x3F:	/* HSX */ +	case 0x45:	/* HSW */ +	case 0x46:	/* HSW */ +	case 0x37:	/* BYT */ +	case 0x4D:	/* AVN */ +	case 0x3D:	/* BDW */ +	case 0x4F:	/* BDX */ +	case 0x56:	/* BDX-DE */ +		return 1; +	case 0x2E:	/* Nehalem-EX Xeon - Beckton */ +	case 0x2F:	/* Westmere-EX Xeon - Eagleton */ +	default: +		return 0; +	} +} +int has_ivt_turbo_ratio_limit(unsigned int family, unsigned int model) +{ +	if (!genuine_intel) +		return 0; + +	if (family != 6) +		return 0; + +	switch (model) { +	case 0x3E:	/* IVB Xeon */ +		return 1; +	default: +		return 0; +	} +} + +/* + * print_epb() + * Decode the ENERGY_PERF_BIAS MSR + */ +int print_epb(struct thread_data *t, struct core_data *c, struct pkg_data *p) +{ +	unsigned long long msr; +	char *epb_string; +	int cpu; + +	if (!has_epb) +		return 0; + +	cpu = t->cpu_id; + +	/* EPB is per-package */ +	if (!(t->flags & CPU_IS_FIRST_THREAD_IN_CORE) || !(t->flags & CPU_IS_FIRST_CORE_IN_PACKAGE)) +		return 0; + +	if (cpu_migrate(cpu)) { +		fprintf(stderr, "Could not migrate to CPU %d\n", cpu); +		return -1; +	} + +	if (get_msr(cpu, MSR_IA32_ENERGY_PERF_BIAS, &msr)) +		return 0; + +	switch (msr & 0x7) { +	case ENERGY_PERF_BIAS_PERFORMANCE: +		epb_string = "performance"; +		break; +	case ENERGY_PERF_BIAS_NORMAL: +		epb_string = "balanced"; +		break; +	case ENERGY_PERF_BIAS_POWERSAVE: +		epb_string = "powersave"; +		break; +	default: +		epb_string = "custom"; +		break; +	} +	fprintf(stderr, "cpu%d: MSR_IA32_ENERGY_PERF_BIAS: 0x%08llx (%s)\n", cpu, msr, epb_string); + +	return 0; +} + +#define	RAPL_POWER_GRANULARITY	0x7FFF	/* 15 bit power granularity */ +#define	RAPL_TIME_GRANULARITY	0x3F /* 6 bit time granularity */ + +double get_tdp(model) +{ +	unsigned long long msr; + +	if (do_rapl & RAPL_PKG_POWER_INFO) +		if (!get_msr(0, MSR_PKG_POWER_INFO, &msr)) +			return ((msr >> 0) & RAPL_POWER_GRANULARITY) * rapl_power_units; + +	switch (model) { +	case 0x37: +	case 0x4D: +		return 30.0; +	default: +		return 135.0; +	} +} + + +/* + * rapl_probe() + * + * sets do_rapl, rapl_power_units, rapl_energy_units, rapl_time_units + */ +void rapl_probe(unsigned int family, unsigned int model) +{ +	unsigned long long msr; +	unsigned int time_unit; +	double tdp; + +	if (!genuine_intel) +		return; + +	if (family != 6) +		return; + +	switch (model) { +	case 0x2A: +	case 0x3A: +	case 0x3C:	/* HSW */ +	case 0x45:	/* HSW */ +	case 0x46:	/* HSW */ +	case 0x3D:	/* BDW */ +		do_rapl = RAPL_PKG | RAPL_CORES | RAPL_CORE_POLICY | RAPL_GFX | RAPL_PKG_POWER_INFO; +		break; +	case 0x3F:	/* HSX */ +	case 0x4F:	/* BDX */ +	case 0x56:	/* BDX-DE */ +		do_rapl = RAPL_PKG | RAPL_DRAM | RAPL_DRAM_PERF_STATUS | RAPL_PKG_PERF_STATUS | RAPL_PKG_POWER_INFO; +		break; +	case 0x2D: +	case 0x3E: +		do_rapl = RAPL_PKG | RAPL_CORES | RAPL_CORE_POLICY | RAPL_DRAM | RAPL_PKG_PERF_STATUS | RAPL_DRAM_PERF_STATUS | RAPL_PKG_POWER_INFO; +		break; +	case 0x37:	/* BYT */ +	case 0x4D:	/* AVN */ +		do_rapl = RAPL_PKG | RAPL_CORES ; +		break; +	default: +		return; +	} + +	/* units on package 0, verify later other packages match */ +	if (get_msr(0, MSR_RAPL_POWER_UNIT, &msr)) +		return; + +	rapl_power_units = 1.0 / (1 << (msr & 0xF)); +	if (model == 0x37) +		rapl_energy_units = 1.0 * (1 << (msr >> 8 & 0x1F)) / 1000000; +	else +		rapl_energy_units = 1.0 / (1 << (msr >> 8 & 0x1F)); + +	time_unit = msr >> 16 & 0xF; +	if (time_unit == 0) +		time_unit = 0xA; + +	rapl_time_units = 1.0 / (1 << (time_unit)); + +	tdp = get_tdp(model); + +	rapl_joule_counter_range = 0xFFFFFFFF * rapl_energy_units / tdp; +	if (verbose) +		fprintf(stderr, "RAPL: %.0f sec. Joule Counter Range, at %.0f Watts\n", rapl_joule_counter_range, tdp); + +	return; +} + +int print_thermal(struct thread_data *t, struct core_data *c, struct pkg_data *p) +{ +	unsigned long long msr; +	unsigned int dts; +	int cpu; + +	if (!(do_dts || do_ptm)) +		return 0; + +	cpu = t->cpu_id; + +	/* DTS is per-core, no need to print for each thread */ +	if (!(t->flags & CPU_IS_FIRST_THREAD_IN_CORE))  +		return 0; + +	if (cpu_migrate(cpu)) { +		fprintf(stderr, "Could not migrate to CPU %d\n", cpu); +		return -1; +	} + +	if (do_ptm && (t->flags & CPU_IS_FIRST_CORE_IN_PACKAGE)) { +		if (get_msr(cpu, MSR_IA32_PACKAGE_THERM_STATUS, &msr)) +			return 0; + +		dts = (msr >> 16) & 0x7F; +		fprintf(stderr, "cpu%d: MSR_IA32_PACKAGE_THERM_STATUS: 0x%08llx (%d C)\n", +			cpu, msr, tcc_activation_temp - dts); + +#ifdef	THERM_DEBUG +		if (get_msr(cpu, MSR_IA32_PACKAGE_THERM_INTERRUPT, &msr)) +			return 0; + +		dts = (msr >> 16) & 0x7F; +		dts2 = (msr >> 8) & 0x7F; +		fprintf(stderr, "cpu%d: MSR_IA32_PACKAGE_THERM_INTERRUPT: 0x%08llx (%d C, %d C)\n", +			cpu, msr, tcc_activation_temp - dts, tcc_activation_temp - dts2); +#endif +	} + + +	if (do_dts) { +		unsigned int resolution; + +		if (get_msr(cpu, MSR_IA32_THERM_STATUS, &msr)) +			return 0; + +		dts = (msr >> 16) & 0x7F; +		resolution = (msr >> 27) & 0xF; +		fprintf(stderr, "cpu%d: MSR_IA32_THERM_STATUS: 0x%08llx (%d C +/- %d)\n", +			cpu, msr, tcc_activation_temp - dts, resolution); + +#ifdef THERM_DEBUG +		if (get_msr(cpu, MSR_IA32_THERM_INTERRUPT, &msr)) +			return 0; + +		dts = (msr >> 16) & 0x7F; +		dts2 = (msr >> 8) & 0x7F; +		fprintf(stderr, "cpu%d: MSR_IA32_THERM_INTERRUPT: 0x%08llx (%d C, %d C)\n", +			cpu, msr, tcc_activation_temp - dts, tcc_activation_temp - dts2); +#endif +	} + +	return 0; +} +	 +void print_power_limit_msr(int cpu, unsigned long long msr, char *label) +{ +	fprintf(stderr, "cpu%d: %s: %sabled (%f Watts, %f sec, clamp %sabled)\n", +		cpu, label, +		((msr >> 15) & 1) ? "EN" : "DIS", +		((msr >> 0) & 0x7FFF) * rapl_power_units, +		(1.0 + (((msr >> 22) & 0x3)/4.0)) * (1 << ((msr >> 17) & 0x1F)) * rapl_time_units, +		(((msr >> 16) & 1) ? "EN" : "DIS")); + +	return; +} + +int print_rapl(struct thread_data *t, struct core_data *c, struct pkg_data *p) +{ +	unsigned long long msr; +	int cpu; + +	if (!do_rapl) +		return 0; + +	/* RAPL counters are per package, so print only for 1st thread/package */ +	if (!(t->flags & CPU_IS_FIRST_THREAD_IN_CORE) || !(t->flags & CPU_IS_FIRST_CORE_IN_PACKAGE)) +		return 0; + +	cpu = t->cpu_id; +	if (cpu_migrate(cpu)) { +		fprintf(stderr, "Could not migrate to CPU %d\n", cpu); +		return -1; +	} + +	if (get_msr(cpu, MSR_RAPL_POWER_UNIT, &msr)) +		return -1; + +	if (verbose) { +		fprintf(stderr, "cpu%d: MSR_RAPL_POWER_UNIT: 0x%08llx " +			"(%f Watts, %f Joules, %f sec.)\n", cpu, msr, +			rapl_power_units, rapl_energy_units, rapl_time_units); +	} +	if (do_rapl & RAPL_PKG_POWER_INFO) { + +		if (get_msr(cpu, MSR_PKG_POWER_INFO, &msr)) +                	return -5; + + +		fprintf(stderr, "cpu%d: MSR_PKG_POWER_INFO: 0x%08llx (%.0f W TDP, RAPL %.0f - %.0f W, %f sec.)\n", +			cpu, msr, +			((msr >>  0) & RAPL_POWER_GRANULARITY) * rapl_power_units, +			((msr >> 16) & RAPL_POWER_GRANULARITY) * rapl_power_units, +			((msr >> 32) & RAPL_POWER_GRANULARITY) * rapl_power_units, +			((msr >> 48) & RAPL_TIME_GRANULARITY) * rapl_time_units); + +	} +	if (do_rapl & RAPL_PKG) { + +		if (get_msr(cpu, MSR_PKG_POWER_LIMIT, &msr)) +			return -9; + +		fprintf(stderr, "cpu%d: MSR_PKG_POWER_LIMIT: 0x%08llx (%slocked)\n", +			cpu, msr, (msr >> 63) & 1 ? "": "UN"); + +		print_power_limit_msr(cpu, msr, "PKG Limit #1"); +		fprintf(stderr, "cpu%d: PKG Limit #2: %sabled (%f Watts, %f* sec, clamp %sabled)\n", +			cpu, +			((msr >> 47) & 1) ? "EN" : "DIS", +			((msr >> 32) & 0x7FFF) * rapl_power_units, +			(1.0 + (((msr >> 54) & 0x3)/4.0)) * (1 << ((msr >> 49) & 0x1F)) * rapl_time_units, +			((msr >> 48) & 1) ? "EN" : "DIS"); +	} + +	if (do_rapl & RAPL_DRAM) { +		if (get_msr(cpu, MSR_DRAM_POWER_INFO, &msr)) +                	return -6; + + +		fprintf(stderr, "cpu%d: MSR_DRAM_POWER_INFO,: 0x%08llx (%.0f W TDP, RAPL %.0f - %.0f W, %f sec.)\n", +			cpu, msr, +			((msr >>  0) & RAPL_POWER_GRANULARITY) * rapl_power_units, +			((msr >> 16) & RAPL_POWER_GRANULARITY) * rapl_power_units, +			((msr >> 32) & RAPL_POWER_GRANULARITY) * rapl_power_units, +			((msr >> 48) & RAPL_TIME_GRANULARITY) * rapl_time_units); + + +		if (get_msr(cpu, MSR_DRAM_POWER_LIMIT, &msr)) +			return -9; +		fprintf(stderr, "cpu%d: MSR_DRAM_POWER_LIMIT: 0x%08llx (%slocked)\n", +				cpu, msr, (msr >> 31) & 1 ? "": "UN"); + +		print_power_limit_msr(cpu, msr, "DRAM Limit"); +	} +	if (do_rapl & RAPL_CORE_POLICY) { +		if (verbose) { +			if (get_msr(cpu, MSR_PP0_POLICY, &msr)) +				return -7; + +			fprintf(stderr, "cpu%d: MSR_PP0_POLICY: %lld\n", cpu, msr & 0xF); +		} +	} +	if (do_rapl & RAPL_CORES) { +		if (verbose) { + +			if (get_msr(cpu, MSR_PP0_POWER_LIMIT, &msr)) +				return -9; +			fprintf(stderr, "cpu%d: MSR_PP0_POWER_LIMIT: 0x%08llx (%slocked)\n", +					cpu, msr, (msr >> 31) & 1 ? "": "UN"); +			print_power_limit_msr(cpu, msr, "Cores Limit"); +		} +	} +	if (do_rapl & RAPL_GFX) { +		if (verbose) { +			if (get_msr(cpu, MSR_PP1_POLICY, &msr)) +				return -8; + +			fprintf(stderr, "cpu%d: MSR_PP1_POLICY: %lld\n", cpu, msr & 0xF); + +			if (get_msr(cpu, MSR_PP1_POWER_LIMIT, &msr)) +				return -9; +			fprintf(stderr, "cpu%d: MSR_PP1_POWER_LIMIT: 0x%08llx (%slocked)\n", +					cpu, msr, (msr >> 31) & 1 ? "": "UN"); +			print_power_limit_msr(cpu, msr, "GFX Limit"); +		} +	} +	return 0; +} + + +int is_snb(unsigned int family, unsigned int model) +{ +	if (!genuine_intel) +		return 0; + +	switch (model) { +	case 0x2A: +	case 0x2D: +	case 0x3A:	/* IVB */ +	case 0x3E:	/* IVB Xeon */ +	case 0x3C:	/* HSW */ +	case 0x3F:	/* HSW */ +	case 0x45:	/* HSW */ +	case 0x46:	/* HSW */ +	case 0x3D:	/* BDW */ +	case 0x4F:	/* BDX */ +	case 0x56:	/* BDX-DE */ +		return 1; +	} +	return 0; +} + +int has_c8_c9_c10(unsigned int family, unsigned int model) +{ +	if (!genuine_intel) +		return 0; + +	switch (model) { +	case 0x45:	/* HSW */ +	case 0x3D:	/* BDW */ +		return 1; +	} +	return 0; +} + + +int is_slm(unsigned int family, unsigned int model) +{ +	if (!genuine_intel) +		return 0; +	switch (model) { +	case 0x37:	/* BYT */ +	case 0x4D:	/* AVN */ +		return 1; +	} +	return 0; +} + +#define SLM_BCLK_FREQS 5 +double slm_freq_table[SLM_BCLK_FREQS] = { 83.3, 100.0, 133.3, 116.7, 80.0}; + +double slm_bclk(void) +{ +	unsigned long long msr = 3; +	unsigned int i; +	double freq; + +	if (get_msr(0, MSR_FSB_FREQ, &msr)) +		fprintf(stderr, "SLM BCLK: unknown\n"); + +	i = msr & 0xf; +	if (i >= SLM_BCLK_FREQS) { +		fprintf(stderr, "SLM BCLK[%d] invalid\n", i); +		msr = 3; +	} +	freq = slm_freq_table[i]; + +	fprintf(stderr, "SLM BCLK: %.1f Mhz\n", freq); + +	return freq; +} + +double discover_bclk(unsigned int family, unsigned int model) +{ +	if (is_snb(family, model)) +		return 100.00; +	else if (is_slm(family, model)) +		return slm_bclk(); +	else +		return 133.33; +} + +/* + * MSR_IA32_TEMPERATURE_TARGET indicates the temperature where + * the Thermal Control Circuit (TCC) activates. + * This is usually equal to tjMax. + * + * Older processors do not have this MSR, so there we guess, + * but also allow cmdline over-ride with -T. + * + * Several MSR temperature values are in units of degrees-C + * below this value, including the Digital Thermal Sensor (DTS), + * Package Thermal Management Sensor (PTM), and thermal event thresholds. + */ +int set_temperature_target(struct thread_data *t, struct core_data *c, struct pkg_data *p) +{ +	unsigned long long msr; +	unsigned int target_c_local; +	int cpu; + +	/* tcc_activation_temp is used only for dts or ptm */ +	if (!(do_dts || do_ptm)) +		return 0; + +	/* this is a per-package concept */ +	if (!(t->flags & CPU_IS_FIRST_THREAD_IN_CORE) || !(t->flags & CPU_IS_FIRST_CORE_IN_PACKAGE)) +		return 0; + +	cpu = t->cpu_id; +	if (cpu_migrate(cpu)) { +		fprintf(stderr, "Could not migrate to CPU %d\n", cpu); +		return -1; +	} + +	if (tcc_activation_temp_override != 0) { +		tcc_activation_temp = tcc_activation_temp_override; +		fprintf(stderr, "cpu%d: Using cmdline TCC Target (%d C)\n", +			cpu, tcc_activation_temp); +		return 0; +	} + +	/* Temperature Target MSR is Nehalem and newer only */ +	if (!do_nehalem_platform_info) +		goto guess; + +	if (get_msr(0, MSR_IA32_TEMPERATURE_TARGET, &msr)) +		goto guess; + +	target_c_local = (msr >> 16) & 0xFF; + +	if (verbose) +		fprintf(stderr, "cpu%d: MSR_IA32_TEMPERATURE_TARGET: 0x%08llx (%d C)\n", +			cpu, msr, target_c_local); + +	if (!target_c_local) +		goto guess; + +	tcc_activation_temp = target_c_local; + +	return 0; + +guess: +	tcc_activation_temp = TJMAX_DEFAULT; +	fprintf(stderr, "cpu%d: Guessing tjMax %d C, Please use -T to specify\n", +		cpu, tcc_activation_temp); + +	return 0; +} +void check_cpuid() +{ +	unsigned int eax, ebx, ecx, edx, max_level; +	unsigned int fms, family, model, stepping; + +	eax = ebx = ecx = edx = 0; + +	__get_cpuid(0, &max_level, &ebx, &ecx, &edx); + +	if (ebx == 0x756e6547 && edx == 0x49656e69 && ecx == 0x6c65746e) +		genuine_intel = 1; + +	if (verbose) +		fprintf(stderr, "CPUID(0): %.4s%.4s%.4s ", +			(char *)&ebx, (char *)&edx, (char *)&ecx); + +	__get_cpuid(1, &fms, &ebx, &ecx, &edx); +	family = (fms >> 8) & 0xf; +	model = (fms >> 4) & 0xf; +	stepping = fms & 0xf; +	if (family == 6 || family == 0xf) +		model += ((fms >> 16) & 0xf) << 4; + +	if (verbose) +		fprintf(stderr, "%d CPUID levels; family:model:stepping 0x%x:%x:%x (%d:%d:%d)\n", +			max_level, family, model, stepping, family, model, stepping); + +	if (!(edx & (1 << 5))) +		errx(1, "CPUID: no MSR"); + +	/* +	 * check max extended function levels of CPUID. +	 * This is needed to check for invariant TSC. +	 * This check is valid for both Intel and AMD. +	 */ +	ebx = ecx = edx = 0; +	__get_cpuid(0x80000000, &max_level, &ebx, &ecx, &edx); + +	if (max_level < 0x80000007) +		errx(1, "CPUID: no invariant TSC (max_level 0x%x)", max_level); + +	/* +	 * Non-Stop TSC is advertised by CPUID.EAX=0x80000007: EDX.bit8 +	 * this check is valid for both Intel and AMD +	 */ +	__get_cpuid(0x80000007, &eax, &ebx, &ecx, &edx); +	has_invariant_tsc = edx & (1 << 8); + +	if (!has_invariant_tsc) +		errx(1, "No invariant TSC"); + +	/* +	 * APERF/MPERF is advertised by CPUID.EAX=0x6: ECX.bit0 +	 * this check is valid for both Intel and AMD +	 */ + +	__get_cpuid(0x6, &eax, &ebx, &ecx, &edx); +	has_aperf = ecx & (1 << 0); +	do_dts = eax & (1 << 0); +	do_ptm = eax & (1 << 6); +	has_epb = ecx & (1 << 3); + +	if (verbose) +		fprintf(stderr, "CPUID(6): %s%s%s%s\n", +			has_aperf ? "APERF" : "No APERF!", +			do_dts ? ", DTS" : "", +			do_ptm ? ", PTM": "", +			has_epb ? ", EPB": ""); + +	if (!has_aperf) +		errx(-1, "No APERF"); + +	do_nehalem_platform_info = genuine_intel && has_invariant_tsc; +	do_nhm_cstates = genuine_intel;	/* all Intel w/ non-stop TSC have NHM counters */ +	do_smi = do_nhm_cstates; +	do_snb_cstates = is_snb(family, model); +	do_c8_c9_c10 = has_c8_c9_c10(family, model); +	do_slm_cstates = is_slm(family, model); +	bclk = discover_bclk(family, model); + +	do_nehalem_turbo_ratio_limit = has_nehalem_turbo_ratio_limit(family, model); +	do_ivt_turbo_ratio_limit = has_ivt_turbo_ratio_limit(family, model); +	rapl_probe(family, model); + +	return; +} + + +void usage() +{ +	errx(1, "%s: [-v][-R][-T][-p|-P|-S][-c MSR#][-C MSR#][-m MSR#][-M MSR#][-i interval_sec | command ...]\n", +	     progname); +} + + +/* + * in /dev/cpu/ return success for names that are numbers + * ie. filter out ".", "..", "microcode". + */ +int dir_filter(const struct dirent *dirp) +{ +	if (isdigit(dirp->d_name[0])) +		return 1; +	else +		return 0; +} + +int open_dev_cpu_msr(int dummy1) +{ +	return 0; +} + +void topology_probe() +{ +	int i; +	int max_core_id = 0; +	int max_package_id = 0; +	int max_siblings = 0; +	struct cpu_topology { +		int core_id; +		int physical_package_id; +	} *cpus; + +	/* Initialize num_cpus, max_cpu_num */ +	topo.num_cpus = 0; +	topo.max_cpu_num = 0; +	for_all_proc_cpus(count_cpus); +	if (!summary_only && topo.num_cpus > 1) +		show_cpu = 1; + +	if (verbose > 1) +		fprintf(stderr, "num_cpus %d max_cpu_num %d\n", topo.num_cpus, topo.max_cpu_num); + +	cpus = calloc(1, (topo.max_cpu_num  + 1) * sizeof(struct cpu_topology)); +	if (cpus == NULL) +		err(1, "calloc cpus"); + +	/* +	 * Allocate and initialize cpu_present_set +	 */ +	cpu_present_set = CPU_ALLOC((topo.max_cpu_num + 1)); +	if (cpu_present_set == NULL) +		err(3, "CPU_ALLOC"); +	cpu_present_setsize = CPU_ALLOC_SIZE((topo.max_cpu_num + 1)); +	CPU_ZERO_S(cpu_present_setsize, cpu_present_set); +	for_all_proc_cpus(mark_cpu_present); + +	/* +	 * Allocate and initialize cpu_affinity_set +	 */ +	cpu_affinity_set = CPU_ALLOC((topo.max_cpu_num + 1)); +	if (cpu_affinity_set == NULL) +		err(3, "CPU_ALLOC"); +	cpu_affinity_setsize = CPU_ALLOC_SIZE((topo.max_cpu_num + 1)); +	CPU_ZERO_S(cpu_affinity_setsize, cpu_affinity_set); + + +	/* +	 * For online cpus +	 * find max_core_id, max_package_id +	 */ +	for (i = 0; i <= topo.max_cpu_num; ++i) { +		int siblings; + +		if (cpu_is_not_present(i)) { +			if (verbose > 1) +				fprintf(stderr, "cpu%d NOT PRESENT\n", i); +			continue; +		} +		cpus[i].core_id = get_core_id(i); +		if (cpus[i].core_id > max_core_id) +			max_core_id = cpus[i].core_id; + +		cpus[i].physical_package_id = get_physical_package_id(i); +		if (cpus[i].physical_package_id > max_package_id) +			max_package_id = cpus[i].physical_package_id; + +		siblings = get_num_ht_siblings(i); +		if (siblings > max_siblings) +			max_siblings = siblings; +		if (verbose > 1) +			fprintf(stderr, "cpu %d pkg %d core %d\n", +				i, cpus[i].physical_package_id, cpus[i].core_id); +	} +	topo.num_cores_per_pkg = max_core_id + 1; +	if (verbose > 1) +		fprintf(stderr, "max_core_id %d, sizing for %d cores per package\n", +			max_core_id, topo.num_cores_per_pkg); +	if (!summary_only && topo.num_cores_per_pkg > 1) +		show_core = 1; + +	topo.num_packages = max_package_id + 1; +	if (verbose > 1) +		fprintf(stderr, "max_package_id %d, sizing for %d packages\n", +			max_package_id, topo.num_packages); +	if (!summary_only && topo.num_packages > 1) +		show_pkg = 1; + +	topo.num_threads_per_core = max_siblings; +	if (verbose > 1) +		fprintf(stderr, "max_siblings %d\n", max_siblings); + +	free(cpus); +} + +void +allocate_counters(struct thread_data **t, struct core_data **c, struct pkg_data **p) +{ +	int i; + +	*t = calloc(topo.num_threads_per_core * topo.num_cores_per_pkg * +		topo.num_packages, sizeof(struct thread_data)); +	if (*t == NULL) +		goto error; + +	for (i = 0; i < topo.num_threads_per_core * +		topo.num_cores_per_pkg * topo.num_packages; i++) +		(*t)[i].cpu_id = -1; + +	*c = calloc(topo.num_cores_per_pkg * topo.num_packages, +		sizeof(struct core_data)); +	if (*c == NULL) +		goto error; + +	for (i = 0; i < topo.num_cores_per_pkg * topo.num_packages; i++) +		(*c)[i].core_id = -1; + +	*p = calloc(topo.num_packages, sizeof(struct pkg_data)); +	if (*p == NULL) +		goto error; + +	for (i = 0; i < topo.num_packages; i++) +		(*p)[i].package_id = i; + +	return; +error: +	err(1, "calloc counters"); +} +/* + * init_counter() + * + * set cpu_id, core_num, pkg_num + * set FIRST_THREAD_IN_CORE and FIRST_CORE_IN_PACKAGE + * + * increment topo.num_cores when 1st core in pkg seen + */ +void init_counter(struct thread_data *thread_base, struct core_data *core_base, +	struct pkg_data *pkg_base, int thread_num, int core_num, +	int pkg_num, int cpu_id) +{ +	struct thread_data *t; +	struct core_data *c; +	struct pkg_data *p; + +	t = GET_THREAD(thread_base, thread_num, core_num, pkg_num); +	c = GET_CORE(core_base, core_num, pkg_num); +	p = GET_PKG(pkg_base, pkg_num); + +	t->cpu_id = cpu_id; +	if (thread_num == 0) { +		t->flags |= CPU_IS_FIRST_THREAD_IN_CORE; +		if (cpu_is_first_core_in_package(cpu_id)) +			t->flags |= CPU_IS_FIRST_CORE_IN_PACKAGE; +	} + +	c->core_id = core_num; +	p->package_id = pkg_num; +} + + +int initialize_counters(int cpu_id) +{ +	int my_thread_id, my_core_id, my_package_id; + +	my_package_id = get_physical_package_id(cpu_id); +	my_core_id = get_core_id(cpu_id); + +	if (cpu_is_first_sibling_in_core(cpu_id)) { +		my_thread_id = 0; +		topo.num_cores++; +	} else { +		my_thread_id = 1; +	} + +	init_counter(EVEN_COUNTERS, my_thread_id, my_core_id, my_package_id, cpu_id); +	init_counter(ODD_COUNTERS, my_thread_id, my_core_id, my_package_id, cpu_id); +	return 0; +} + +void allocate_output_buffer() +{ +	output_buffer = calloc(1, (1 + topo.num_cpus) * 1024); +	outp = output_buffer; +	if (outp == NULL) +		err(-1, "calloc output buffer"); +} + +void setup_all_buffers(void) +{ +	topology_probe(); +	allocate_counters(&thread_even, &core_even, &package_even); +	allocate_counters(&thread_odd, &core_odd, &package_odd); +	allocate_output_buffer(); +	for_all_proc_cpus(initialize_counters); +} + +void turbostat_init() +{ +	check_cpuid(); + +	check_dev_msr(); +	check_super_user(); + +	setup_all_buffers(); + +	if (verbose) +		print_verbose_header(); + +	if (verbose) +		for_all_cpus(print_epb, ODD_COUNTERS); + +	if (verbose) +		for_all_cpus(print_rapl, ODD_COUNTERS); + +	for_all_cpus(set_temperature_target, ODD_COUNTERS); + +	if (verbose) +		for_all_cpus(print_thermal, ODD_COUNTERS); +} + +int fork_it(char **argv) +{ +	pid_t child_pid; +	int status; + +	status = for_all_cpus(get_counters, EVEN_COUNTERS); +	if (status) +		exit(status); +	/* clear affinity side-effect of get_counters() */ +	sched_setaffinity(0, cpu_present_setsize, cpu_present_set); +	gettimeofday(&tv_even, (struct timezone *)NULL); + +	child_pid = fork(); +	if (!child_pid) { +		/* child */ +		execvp(argv[0], argv); +	} else { + +		/* parent */ +		if (child_pid == -1) +			err(1, "fork"); + +		signal(SIGINT, SIG_IGN); +		signal(SIGQUIT, SIG_IGN); +		if (waitpid(child_pid, &status, 0) == -1) +			err(status, "waitpid"); +	} +	/* +	 * n.b. fork_it() does not check for errors from for_all_cpus() +	 * because re-starting is problematic when forking +	 */ +	for_all_cpus(get_counters, ODD_COUNTERS); +	gettimeofday(&tv_odd, (struct timezone *)NULL); +	timersub(&tv_odd, &tv_even, &tv_delta); +	for_all_cpus_2(delta_cpu, ODD_COUNTERS, EVEN_COUNTERS); +	compute_average(EVEN_COUNTERS); +	format_all_counters(EVEN_COUNTERS); +	flush_stderr(); + +	fprintf(stderr, "%.6f sec\n", tv_delta.tv_sec + tv_delta.tv_usec/1000000.0); + +	return status; +} + +int get_and_dump_counters(void) +{ +	int status; + +	status = for_all_cpus(get_counters, ODD_COUNTERS); +	if (status) +		return status; + +	status = for_all_cpus(dump_counters, ODD_COUNTERS); +	if (status) +		return status; + +	flush_stdout(); + +	return status; +} + +void cmdline(int argc, char **argv) +{ +	int opt; + +	progname = argv[0]; + +	while ((opt = getopt(argc, argv, "+pPsSvi:c:C:m:M:RJT:")) != -1) { +		switch (opt) { +		case 'p': +			show_core_only++; +			break; +		case 'P': +			show_pkg_only++; +			break; +		case 's': +			dump_only++; +			break; +		case 'S': +			summary_only++; +			break; +		case 'v': +			verbose++; +			break; +		case 'i': +			interval_sec = atoi(optarg); +			break; +		case 'c': +			sscanf(optarg, "%x", &extra_delta_offset32); +			break; +		case 'C': +			sscanf(optarg, "%x", &extra_delta_offset64); +			break; +		case 'm': +			sscanf(optarg, "%x", &extra_msr_offset32); +			break; +		case 'M': +			sscanf(optarg, "%x", &extra_msr_offset64); +			break; +		case 'R': +			rapl_verbose++; +			break; +		case 'T': +			tcc_activation_temp_override = atoi(optarg); +			break; +		case 'J': +			rapl_joules++; +			break; + +		default: +			usage(); +		} +	} +} + +int main(int argc, char **argv) +{ +	cmdline(argc, argv); + +	if (verbose) +		fprintf(stderr, "turbostat v3.7 Feb 6, 2014" +			" - Len Brown <lenb@kernel.org>\n"); + +	turbostat_init(); + +	/* dump counters and exit */ +	if (dump_only) +		return get_and_dump_counters(); + +	/* +	 * if any params left, it must be a command to fork +	 */ +	if (argc - optind) +		return fork_it(argv + optind); +	else +		turbostat_loop(); + +	return 0; +} diff --git a/tools/power/x86/x86_energy_perf_policy/Makefile b/tools/power/x86/x86_energy_perf_policy/Makefile new file mode 100644 index 00000000000..971c9ffdcb5 --- /dev/null +++ b/tools/power/x86/x86_energy_perf_policy/Makefile @@ -0,0 +1,10 @@ +DESTDIR ?= + +x86_energy_perf_policy : x86_energy_perf_policy.c + +clean : +	rm -f x86_energy_perf_policy + +install : +	install x86_energy_perf_policy ${DESTDIR}/usr/bin/ +	install x86_energy_perf_policy.8 ${DESTDIR}/usr/share/man/man8/ diff --git a/tools/power/x86/x86_energy_perf_policy/x86_energy_perf_policy.8 b/tools/power/x86/x86_energy_perf_policy/x86_energy_perf_policy.8 new file mode 100644 index 00000000000..8eaaad648cd --- /dev/null +++ b/tools/power/x86/x86_energy_perf_policy/x86_energy_perf_policy.8 @@ -0,0 +1,104 @@ +.\"  This page Copyright (C) 2010 Len Brown <len.brown@intel.com> +.\"  Distributed under the GPL, Copyleft 1994. +.TH X86_ENERGY_PERF_POLICY 8 +.SH NAME +x86_energy_perf_policy \- read or write MSR_IA32_ENERGY_PERF_BIAS +.SH SYNOPSIS +.ft B +.B x86_energy_perf_policy +.RB [ "\-c cpu" ] +.RB [ "\-v" ] +.RB "\-r" +.br +.B x86_energy_perf_policy +.RB [ "\-c cpu" ] +.RB [ "\-v" ] +.RB 'performance' +.br +.B x86_energy_perf_policy +.RB [ "\-c cpu" ] +.RB [ "\-v" ] +.RB 'normal' +.br +.B x86_energy_perf_policy +.RB [ "\-c cpu" ] +.RB [ "\-v" ] +.RB 'powersave' +.br +.B x86_energy_perf_policy +.RB [ "\-c cpu" ] +.RB [ "\-v" ] +.RB n +.br +.SH DESCRIPTION +\fBx86_energy_perf_policy\fP +allows software to convey +its policy for the relative importance of performance +versus energy savings to the processor. + +The processor uses this information in model-specific ways +when it must select trade-offs between performance and +energy efficiency. + +This policy hint does not supersede Processor Performance states +(P-states) or CPU Idle power states (C-states), but allows +software to have influence where it would otherwise be unable +to express a preference. + +For example, this setting may tell the hardware how +aggressively or conservatively to control frequency +in the "turbo range" above the explicitly OS-controlled +P-state frequency range.  It may also tell the hardware +how aggressively is should enter the OS requested C-states. + +Support for this feature is indicated by CPUID.06H.ECX.bit3 +per the Intel Architectures Software Developer's Manual. + +.SS Options +\fB-c\fP limits operation to a single CPU. +The default is to operate on all CPUs. +Note that MSR_IA32_ENERGY_PERF_BIAS is defined per +logical processor, but that the initial implementations +of the MSR were shared among all processors in each package. +.PP +\fB-v\fP increases verbosity.  By default +x86_energy_perf_policy is silent. +.PP +\fB-r\fP is for "read-only" mode - the unchanged state +is read and displayed. +.PP +.I performance +Set a policy where performance is paramount. +The processor will be unwilling to sacrifice any performance +for the sake of energy saving. This is the hardware default. +.PP +.I normal +Set a policy with a normal balance between performance and energy efficiency. +The processor will tolerate minor performance compromise +for potentially significant energy savings. +This reasonable default for most desktops and servers. +.PP +.I powersave +Set a policy where the processor can accept +a measurable performance hit to maximize energy efficiency. +.PP +.I n +Set MSR_IA32_ENERGY_PERF_BIAS to the specified number. +The range of valid numbers is 0-15, where 0 is maximum +performance and 15 is maximum energy efficiency. + +.SH NOTES +.B "x86_energy_perf_policy " +runs only as root. +.SH FILES +.ta +.nf +/dev/cpu/*/msr +.fi + +.SH "SEE ALSO" +msr(4) +.PP +.SH AUTHORS +.nf +Written by Len Brown <len.brown@intel.com> diff --git a/tools/power/x86/x86_energy_perf_policy/x86_energy_perf_policy.c b/tools/power/x86/x86_energy_perf_policy/x86_energy_perf_policy.c new file mode 100644 index 00000000000..40b3e5482f8 --- /dev/null +++ b/tools/power/x86/x86_energy_perf_policy/x86_energy_perf_policy.c @@ -0,0 +1,324 @@ +/* + * x86_energy_perf_policy -- set the energy versus performance + * policy preference bias on recent X86 processors. + */ +/* + * Copyright (c) 2010, Intel Corporation. + * Len Brown <len.brown@intel.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include <stdio.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/resource.h> +#include <fcntl.h> +#include <signal.h> +#include <sys/time.h> +#include <stdlib.h> +#include <string.h> + +unsigned int verbose;		/* set with -v */ +unsigned int read_only;		/* set with -r */ +char *progname; +unsigned long long new_bias; +int cpu = -1; + +/* + * Usage: + * + * -c cpu: limit action to a single CPU (default is all CPUs) + * -v: verbose output (can invoke more than once) + * -r: read-only, don't change any settings + * + *  performance + *	Performance is paramount. + *	Unwilling to sacrifice any performance + *	for the sake of energy saving. (hardware default) + * + *  normal + *	Can tolerate minor performance compromise + *	for potentially significant energy savings. + *	(reasonable default for most desktops and servers) + * + *  powersave + *	Can tolerate significant performance hit + *	to maximize energy savings. + * + * n + *	a numerical value to write to the underlying MSR. + */ +void usage(void) +{ +	printf("%s: [-c cpu] [-v] " +		"(-r | 'performance' | 'normal' | 'powersave' | n)\n", +		progname); +	exit(1); +} + +#define MSR_IA32_ENERGY_PERF_BIAS	0x000001b0 + +#define	BIAS_PERFORMANCE		0 +#define BIAS_BALANCE			6 +#define	BIAS_POWERSAVE			15 + +void cmdline(int argc, char **argv) +{ +	int opt; + +	progname = argv[0]; + +	while ((opt = getopt(argc, argv, "+rvc:")) != -1) { +		switch (opt) { +		case 'c': +			cpu = atoi(optarg); +			break; +		case 'r': +			read_only = 1; +			break; +		case 'v': +			verbose++; +			break; +		default: +			usage(); +		} +	} +	/* if -r, then should be no additional optind */ +	if (read_only && (argc > optind)) +		usage(); + +	/* +	 * if no -r , then must be one additional optind +	 */ +	if (!read_only) { + +		if (argc != optind + 1) { +			printf("must supply -r or policy param\n"); +			usage(); +			} + +		if (!strcmp("performance", argv[optind])) { +			new_bias = BIAS_PERFORMANCE; +		} else if (!strcmp("normal", argv[optind])) { +			new_bias = BIAS_BALANCE; +		} else if (!strcmp("powersave", argv[optind])) { +			new_bias = BIAS_POWERSAVE; +		} else { +			char *endptr; + +			new_bias = strtoull(argv[optind], &endptr, 0); +			if (endptr == argv[optind] || +				new_bias > BIAS_POWERSAVE) { +					fprintf(stderr, "invalid value: %s\n", +						argv[optind]); +				usage(); +			} +		} +	} +} + +/* + * validate_cpuid() + * returns on success, quietly exits on failure (make verbose with -v) + */ +void validate_cpuid(void) +{ +	unsigned int eax, ebx, ecx, edx, max_level; +	unsigned int fms, family, model, stepping; + +	eax = ebx = ecx = edx = 0; + +	asm("cpuid" : "=a" (max_level), "=b" (ebx), "=c" (ecx), +		"=d" (edx) : "a" (0)); + +	if (ebx != 0x756e6547 || edx != 0x49656e69 || ecx != 0x6c65746e) { +		if (verbose) +			fprintf(stderr, "%.4s%.4s%.4s != GenuineIntel", +				(char *)&ebx, (char *)&edx, (char *)&ecx); +		exit(1); +	} + +	asm("cpuid" : "=a" (fms), "=c" (ecx), "=d" (edx) : "a" (1) : "ebx"); +	family = (fms >> 8) & 0xf; +	model = (fms >> 4) & 0xf; +	stepping = fms & 0xf; +	if (family == 6 || family == 0xf) +		model += ((fms >> 16) & 0xf) << 4; + +	if (verbose > 1) +		printf("CPUID %d levels family:model:stepping " +			"0x%x:%x:%x (%d:%d:%d)\n", max_level, +			family, model, stepping, family, model, stepping); + +	if (!(edx & (1 << 5))) { +		if (verbose) +			printf("CPUID: no MSR\n"); +		exit(1); +	} + +	/* +	 * Support for MSR_IA32_ENERGY_PERF_BIAS +	 * is indicated by CPUID.06H.ECX.bit3 +	 */ +	asm("cpuid" : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx) : "a" (6)); +	if (verbose) +		printf("CPUID.06H.ECX: 0x%x\n", ecx); +	if (!(ecx & (1 << 3))) { +		if (verbose) +			printf("CPUID: No MSR_IA32_ENERGY_PERF_BIAS\n"); +		exit(1); +	} +	return;	/* success */ +} + +unsigned long long get_msr(int cpu, int offset) +{ +	unsigned long long msr; +	char msr_path[32]; +	int retval; +	int fd; + +	sprintf(msr_path, "/dev/cpu/%d/msr", cpu); +	fd = open(msr_path, O_RDONLY); +	if (fd < 0) { +		printf("Try \"# modprobe msr\"\n"); +		perror(msr_path); +		exit(1); +	} + +	retval = pread(fd, &msr, sizeof msr, offset); + +	if (retval != sizeof msr) { +		printf("pread cpu%d 0x%x = %d\n", cpu, offset, retval); +		exit(-2); +	} +	close(fd); +	return msr; +} + +unsigned long long  put_msr(int cpu, unsigned long long new_msr, int offset) +{ +	unsigned long long old_msr; +	char msr_path[32]; +	int retval; +	int fd; + +	sprintf(msr_path, "/dev/cpu/%d/msr", cpu); +	fd = open(msr_path, O_RDWR); +	if (fd < 0) { +		perror(msr_path); +		exit(1); +	} + +	retval = pread(fd, &old_msr, sizeof old_msr, offset); +	if (retval != sizeof old_msr) { +		perror("pwrite"); +		printf("pread cpu%d 0x%x = %d\n", cpu, offset, retval); +		exit(-2); +	} + +	retval = pwrite(fd, &new_msr, sizeof new_msr, offset); +	if (retval != sizeof new_msr) { +		perror("pwrite"); +		printf("pwrite cpu%d 0x%x = %d\n", cpu, offset, retval); +		exit(-2); +	} + +	close(fd); + +	return old_msr; +} + +void print_msr(int cpu) +{ +	printf("cpu%d: 0x%016llx\n", +		cpu, get_msr(cpu, MSR_IA32_ENERGY_PERF_BIAS)); +} + +void update_msr(int cpu) +{ +	unsigned long long previous_msr; + +	previous_msr = put_msr(cpu, new_bias, MSR_IA32_ENERGY_PERF_BIAS); + +	if (verbose) +		printf("cpu%d  msr0x%x 0x%016llx -> 0x%016llx\n", +			cpu, MSR_IA32_ENERGY_PERF_BIAS, previous_msr, new_bias); + +	return; +} + +char *proc_stat = "/proc/stat"; +/* + * run func() on every cpu in /dev/cpu + */ +void for_every_cpu(void (func)(int)) +{ +	FILE *fp; +	int retval; + +	fp = fopen(proc_stat, "r"); +	if (fp == NULL) { +		perror(proc_stat); +		exit(1); +	} + +	retval = fscanf(fp, "cpu %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d\n"); +	if (retval != 0) { +		perror("/proc/stat format"); +		exit(1); +	} + +	while (1) { +		int cpu; + +		retval = fscanf(fp, +			"cpu%u %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d\n", +			&cpu); +		if (retval != 1) +			break; + +		func(cpu); +	} +	fclose(fp); +} + +int main(int argc, char **argv) +{ +	cmdline(argc, argv); + +	if (verbose > 1) +		printf("x86_energy_perf_policy Nov 24, 2010" +				" - Len Brown <lenb@kernel.org>\n"); +	if (verbose > 1 && !read_only) +		printf("new_bias %lld\n", new_bias); + +	validate_cpuid(); + +	if (cpu != -1) { +		if (read_only) +			print_msr(cpu); +		else +			update_msr(cpu); +	} else { +		if (read_only) +			for_every_cpu(print_msr); +		else +			for_every_cpu(update_msr); +	} + +	return 0; +}  | 
