diff options
Diffstat (limited to 'tools/power')
35 files changed, 4503 insertions, 1247 deletions
diff --git a/tools/power/acpi/Makefile b/tools/power/acpi/Makefile index bafeb8d662a..e5a3c4be2a1 100644 --- a/tools/power/acpi/Makefile +++ b/tools/power/acpi/Makefile @@ -1,18 +1,156 @@ -PROG= acpidump -SRCS=	acpidump.c +# 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 -CFLAGS += -Wall -Wstrict-prototypes -Wdeclaration-after-statement -Os -s -D_LINUX -DDEFINE_ALTERNATE_TYPES -I$(KERNEL_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 -all: acpidump -$(PROG) : $(SRCS) -	$(CC) $(CFLAGS) $(SRCS) -o $(PROG) +install-tools: +	$(INSTALL) -d $(DESTDIR)${sbindir} +	$(INSTALL_PROGRAM) $(OUTPUT)acpidump $(DESTDIR)${sbindir} -CLEANFILES= $(PROG) +install-man: +	$(INSTALL_DATA) -D man/acpidump.8 $(DESTDIR)${mandir}/man8/acpidump.8 -clean :  -	rm -f $(CLEANFILES) $(patsubst %.c,%.o, $(SRCS)) *~ +install: all install-tools install-man -install : -	install acpidump /usr/sbin/acpidump -	install acpidump.8 /usr/share/man/man8 +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/acpidump.8 b/tools/power/acpi/acpidump.8 deleted file mode 100644 index adfa99166e5..00000000000 --- a/tools/power/acpi/acpidump.8 +++ /dev/null @@ -1,59 +0,0 @@ -.TH ACPIDUMP 8 -.SH NAME -acpidump \- Dump system's ACPI tables to an ASCII file. -.SH SYNOPSIS -.ft B -.B acpidump > acpidump.out -.SH DESCRIPTION -\fBacpidump \fP 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. -.SS Options -no options worth worrying about. -.PP -.SH EXAMPLE - -.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/dynamic/* -.fi - -.PP -.SH AUTHOR -.nf -Written by Len Brown <len.brown@intel.com> diff --git a/tools/power/acpi/acpidump.c b/tools/power/acpi/acpidump.c deleted file mode 100644 index a84553a0e0d..00000000000 --- a/tools/power/acpi/acpidump.c +++ /dev/null @@ -1,559 +0,0 @@ -/* - * (c) Alexey Starikovskiy, Intel, 2005-2006. - * 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. - */ - -#ifdef DEFINE_ALTERNATE_TYPES -/* hack to enable building old application with new headers -lenb */ -#define acpi_fadt_descriptor acpi_table_fadt -#define acpi_rsdp_descriptor acpi_table_rsdp -#define DSDT_SIG ACPI_SIG_DSDT -#define FACS_SIG ACPI_SIG_FACS -#define FADT_SIG ACPI_SIG_FADT -#define xfirmware_ctrl Xfacs -#define firmware_ctrl facs - -typedef int				s32; -typedef unsigned char			u8; -typedef unsigned short			u16; -typedef unsigned int			u32; -typedef unsigned long long		u64; -typedef long long			s64; -#endif - -#include <sys/mman.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <stdio.h> -#include <string.h> -#include <unistd.h> -#include <getopt.h> - -#include <dirent.h> - -#include <acpi/acconfig.h> -#include <acpi/platform/acenv.h> -#include <acpi/actypes.h> -#include <acpi/actbl.h> - -static inline u8 checksum(u8 * buffer, u32 length) -{ -	u8 sum = 0, *i = buffer; -	buffer += length; -	for (; i < buffer; sum += *(i++)); -	return sum; -} - -static unsigned long psz, addr, length; -static int print, connect, skip; -static u8 select_sig[4]; - -static unsigned long read_efi_systab( void ) -{ -	char buffer[80]; -	unsigned long addr; -	FILE *f = fopen("/sys/firmware/efi/systab", "r"); -	if (f) { -		while (fgets(buffer, 80, f)) { -			if (sscanf(buffer, "ACPI20=0x%lx", &addr) == 1) -				return addr; -		} -		fclose(f); -	} -	return 0; -} - -static u8 *acpi_map_memory(unsigned long where, unsigned length) -{ -	unsigned long offset; -	u8 *there; -	int fd = open("/dev/mem", O_RDONLY); -	if (fd < 0) { -		fprintf(stderr, "acpi_os_map_memory: cannot open /dev/mem\n"); -		exit(1); -	} -	offset = where % psz; -	there = mmap(NULL, length + offset, PROT_READ, MAP_PRIVATE, -			 fd, where - offset); -	close(fd); -	if (there == MAP_FAILED) return 0; -	return (there + offset); -} - -static void acpi_unmap_memory(u8 * there, unsigned length) -{ -	unsigned long offset = (unsigned long)there % psz; -	munmap(there - offset, length + offset); -} - -static struct acpi_table_header *acpi_map_table(unsigned long where, char *sig) -{ -	unsigned size; -	struct acpi_table_header *tbl = (struct acpi_table_header *) -	    acpi_map_memory(where, sizeof(struct acpi_table_header)); -	if (!tbl || (sig && memcmp(sig, tbl->signature, 4))) return 0; -	size = tbl->length; -	acpi_unmap_memory((u8 *) tbl, sizeof(struct acpi_table_header)); -	return (struct acpi_table_header *)acpi_map_memory(where, size); -} - -static void acpi_unmap_table(struct acpi_table_header *tbl) -{ -	acpi_unmap_memory((u8 *)tbl, tbl->length); -} - -static struct acpi_rsdp_descriptor *acpi_scan_for_rsdp(u8 *begin, u32 length) -{ -	struct acpi_rsdp_descriptor *rsdp; -	u8 *i, *end = begin + length; -	/* Search from given start address for the requested length */ -	for (i = begin; i < end; i += ACPI_RSDP_SCAN_STEP) { -		/* The signature and checksum must both be correct */ -		if (memcmp((char *)i, "RSD PTR ", 8)) continue; -		rsdp = (struct acpi_rsdp_descriptor *)i; -		/* Signature matches, check the appropriate checksum */ -		if (!checksum((u8 *) rsdp, (rsdp->revision < 2) ? -			      ACPI_RSDP_CHECKSUM_LENGTH : -			      ACPI_RSDP_XCHECKSUM_LENGTH)) -			/* Checksum valid, we have found a valid RSDP */ -			return rsdp; -	} -	/* Searched entire block, no RSDP was found */ -	return 0; -} - -/* - * Output data - */ -static void acpi_show_data(int fd, u8 * data, int size) -{ -	char buffer[256]; -	int len; -	int i, remain = size; -	while (remain > 0) { -		len = snprintf(buffer, 256, "  %04x:", size - remain); -		for (i = 0; i < 16 && i < remain; i++) { -			len += -			    snprintf(&buffer[len], 256 - len, " %02x", data[i]); -		} -		for (; i < 16; i++) { -			len += snprintf(&buffer[len], 256 - len, "   "); -		} -		len += snprintf(&buffer[len], 256 - len, "  "); -		for (i = 0; i < 16 && i < remain; i++) { -			buffer[len++] = (isprint(data[i])) ? data[i] : '.'; -		} -		buffer[len++] = '\n'; -		write(fd, buffer, len); -		data += 16; -		remain -= 16; -	} -} - -/* - * Output ACPI table - */ -static void acpi_show_table(int fd, struct acpi_table_header *table, unsigned long addr) -{ -	char buff[80]; -	int len = snprintf(buff, 80, "%.4s @ %p\n", table->signature, (void *)addr); -	write(fd, buff, len); -	acpi_show_data(fd, (u8 *) table, table->length); -	buff[0] = '\n'; -	write(fd, buff, 1); -} - -static void write_table(int fd, struct acpi_table_header *tbl, unsigned long addr) -{ -	static int select_done = 0; -	if (!select_sig[0]) { -		if (print) { -			acpi_show_table(fd, tbl, addr); -		} else { -			write(fd, tbl, tbl->length); -		} -	} else if (!select_done && !memcmp(select_sig, tbl->signature, 4)) { -		if (skip > 0) { -			--skip; -			return; -		} -		if (print) { -			acpi_show_table(fd, tbl, addr); -		} else { -			write(fd, tbl, tbl->length); -		} -		select_done = 1; -	} -} - -static void acpi_dump_FADT(int fd, struct acpi_table_header *tbl, unsigned long xaddr) { -	struct acpi_fadt_descriptor x; -	unsigned long addr; -	size_t len = sizeof(struct acpi_fadt_descriptor); -	if (len > tbl->length) len = tbl->length; -	memcpy(&x, tbl, len); -	x.header.length = len; -	if (checksum((u8 *)tbl, len)) { -		fprintf(stderr, "Wrong checksum for FADT!\n"); -	} -	if (x.header.length >= 148 && x.Xdsdt) { -		addr = (unsigned long)x.Xdsdt; -		if (connect) { -			x.Xdsdt = lseek(fd, 0, SEEK_CUR); -		} -	} else if (x.header.length >= 44 && x.dsdt) { -		addr = (unsigned long)x.dsdt; -		if (connect) { -			x.dsdt = lseek(fd, 0, SEEK_CUR); -		} -	} else { -		fprintf(stderr, "No DSDT in FADT!\n"); -		goto no_dsdt; -	} -	tbl = acpi_map_table(addr, DSDT_SIG); -	if (!tbl) goto no_dsdt; -	if (checksum((u8 *)tbl, tbl->length)) -		fprintf(stderr, "Wrong checksum for DSDT!\n"); -	write_table(fd, tbl, addr); -	acpi_unmap_table(tbl); -no_dsdt: -	if (x.header.length >= 140 && x.xfirmware_ctrl) { -		addr = (unsigned long)x.xfirmware_ctrl; -		if (connect) { -			x.xfirmware_ctrl = lseek(fd, 0, SEEK_CUR); -		} -	} else if (x.header.length >= 40 && x.firmware_ctrl) { -		addr = (unsigned long)x.firmware_ctrl; -		if (connect) { -			x.firmware_ctrl = lseek(fd, 0, SEEK_CUR); -		} -	} else { -		fprintf(stderr, "No FACS in FADT!\n"); -		goto no_facs; -	} -	tbl = acpi_map_table(addr, FACS_SIG); -	if (!tbl) goto no_facs; -	/* do not checksum FACS */ -	write_table(fd, tbl, addr); -	acpi_unmap_table(tbl); -no_facs: -	write_table(fd, (struct acpi_table_header *)&x, xaddr); -} - -static int acpi_dump_SDT(int fd, struct acpi_rsdp_descriptor *rsdp) -{ -	struct acpi_table_header *sdt, *tbl = 0; -	int xsdt = 1, i, num; -	char *offset; -	unsigned long addr; -	if (rsdp->revision > 1 && rsdp->xsdt_physical_address) { -		tbl = acpi_map_table(rsdp->xsdt_physical_address, "XSDT"); -	} -	if (!tbl && rsdp->rsdt_physical_address) { -		xsdt = 0; -		tbl = acpi_map_table(rsdp->rsdt_physical_address, "RSDT"); -	} -	if (!tbl) return 0; -	sdt = malloc(tbl->length); -	memcpy(sdt, tbl, tbl->length); -	acpi_unmap_table(tbl); -	if (checksum((u8 *)sdt, sdt->length)) -		fprintf(stderr, "Wrong checksum for %s!\n", (xsdt)?"XSDT":"RSDT"); -	num = (sdt->length - sizeof(struct acpi_table_header))/((xsdt)?sizeof(u64):sizeof(u32)); -	offset = (char *)sdt + sizeof(struct acpi_table_header); -	for (i = 0; i < num; ++i, offset += ((xsdt) ? sizeof(u64) : sizeof(u32))) { -		addr = (xsdt) ? (unsigned long)(*(u64 *)offset): -				(unsigned long)(*(u32 *)offset); -		if (!addr) continue; -		tbl = acpi_map_table(addr, 0); -		if (!tbl) continue; -		if (!memcmp(tbl->signature, FADT_SIG, 4)) { -			acpi_dump_FADT(fd, tbl, addr); -		} else { -			if (checksum((u8 *)tbl, tbl->length)) -				fprintf(stderr, "Wrong checksum for generic table!\n"); -			write_table(fd, tbl, addr); -		} -		acpi_unmap_table(tbl); -		if (connect) { -			if (xsdt) -				(*(u64*)offset) = lseek(fd, 0, SEEK_CUR); -			else -				(*(u32*)offset) = lseek(fd, 0, SEEK_CUR); -		} -	} -	if (xsdt) { -		addr = (unsigned long)rsdp->xsdt_physical_address; -		if (connect) { -			rsdp->xsdt_physical_address = lseek(fd, 0, SEEK_CUR); -		} -	} else { -		addr = (unsigned long)rsdp->rsdt_physical_address; -		if (connect) { -			rsdp->rsdt_physical_address = lseek(fd, 0, SEEK_CUR); -		} -	} -	write_table(fd, sdt, addr); -	free (sdt); -	return 1; -} - -#define DYNAMIC_SSDT	"/sys/firmware/acpi/tables/dynamic" - -static void acpi_dump_dynamic_SSDT(int fd) -{ -	struct stat file_stat; -	char filename[256], *ptr; -	DIR *tabledir; -	struct dirent *entry; -	FILE *fp; -	int count, readcount, length; -	struct acpi_table_header table_header, *ptable; - -	if (stat(DYNAMIC_SSDT, &file_stat) == -1) { -		/* The directory doesn't exist */ -		return; -	} -	tabledir = opendir(DYNAMIC_SSDT); -	if(!tabledir){ -		/*can't open the directory */ -		return; -         } - -	while ((entry = readdir(tabledir)) != 0){ -		/* skip the file of . /.. */ -		if (entry->d_name[0] == '.') -			continue; - -		sprintf(filename, "%s/%s", DYNAMIC_SSDT, entry->d_name); -		fp = fopen(filename, "r"); -		if (fp == NULL) { -			fprintf(stderr, "Can't open the file of %s\n", -						filename); -			continue; -		} -		/* Read the Table header to parse the table length */ -		count = fread(&table_header, 1, sizeof(struct acpi_table_header), fp); -		if (count < sizeof(table_header)) { -			/* the length is lessn than ACPI table header. skip it */ -			fclose(fp); -			continue; -		} -		length = table_header.length; -		ptr = malloc(table_header.length); -		fseek(fp, 0, SEEK_SET); -		readcount = 0; -		while(!feof(fp) && readcount < length) { -			count = fread(ptr + readcount, 1, 256, fp); -			readcount += count; -		} -		fclose(fp); -		ptable = (struct acpi_table_header *) ptr; -		if (checksum((u8 *) ptable, ptable->length)) -			fprintf(stderr, "Wrong checksum " -					"for dynamic SSDT table!\n"); -		write_table(fd, ptable, 0); -		free(ptr); -	} -	closedir(tabledir); -	return; -} - -static void usage(const char *progname) -{ -	puts("Usage:"); -	printf("%s [--addr 0x1234][--table DSDT][--output filename]" -		"[--binary][--length 0x456][--help]\n", progname); -	puts("\t--addr 0x1234 or -a 0x1234 -- look for tables at this physical address"); -	puts("\t--table DSDT or -t DSDT -- only dump table with DSDT signature"); -	puts("\t--output filename or -o filename -- redirect output from stdin to filename"); -	puts("\t--binary or -b -- dump data in binary form rather than in hex-dump format"); -	puts("\t--length 0x456 or -l 0x456 -- works only with --addr, dump physical memory" -		"\n\t\tregion without trying to understand it's contents"); -	puts("\t--skip 2 or -s 2 -- skip 2 tables of the given name and output only 3rd one"); -	puts("\t--help or -h -- this help message"); -	exit(0); -} - -static struct option long_options[] = { -	{"addr", 1, 0, 0}, -	{"table", 1, 0, 0}, -	{"output", 1, 0, 0}, -	{"binary", 0, 0, 0}, -	{"length", 1, 0, 0}, -	{"skip", 1, 0, 0}, -	{"help", 0, 0, 0}, -	{0, 0, 0, 0} -}; -int main(int argc, char **argv) -{ -	int option_index, c, fd; -	u8 *raw; -	struct acpi_rsdp_descriptor rsdpx, *x = 0; -	char *filename = 0; -	char buff[80]; -	memset(select_sig, 0, 4); -	print = 1; -	connect = 0; -	addr = length = 0; -	skip = 0; -	while (1) { -		option_index = 0; -		c = getopt_long(argc, argv, "a:t:o:bl:s:h", -				    long_options, &option_index); -		if (c == -1) -			break; - -		switch (c) { -		case 0: -			switch (option_index) { -			case 0: -				addr = strtoul(optarg, (char **)NULL, 16); -				break; -			case 1: -				memcpy(select_sig, optarg, 4); -				break; -			case 2: -				filename = optarg; -				break; -			case 3: -				print = 0; -				break; -			case 4: -				length = strtoul(optarg, (char **)NULL, 16); -				break; -			case 5: -				skip = strtoul(optarg, (char **)NULL, 10); -				break; -			case 6: -				usage(argv[0]); -				exit(0); -			} -			break; -		case 'a': -			addr = strtoul(optarg, (char **)NULL, 16); -			break; -		case 't': -			memcpy(select_sig, optarg, 4); -			break; -		case 'o': -			filename = optarg; -			break; -		case 'b': -			print = 0; -			break; -		case 'l': -			length = strtoul(optarg, (char **)NULL, 16); -			break; -		case 's': -			skip = strtoul(optarg, (char **)NULL, 10); -			break; -		case 'h': -			usage(argv[0]); -			exit(0); -		default: -			printf("Unknown option!\n"); -			usage(argv[0]); -			exit(0); -		} -	} - -	fd = STDOUT_FILENO; -	if (filename) { -		fd = creat(filename, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH); -		if (fd < 0) -			return fd; -	} - -	if (!select_sig[0] && !print) { -		connect = 1; -	} - -	psz = sysconf(_SC_PAGESIZE); -	if (length && addr) { -		/* We know length and address, it means we just want a memory dump */ -		if (!(raw = acpi_map_memory(addr, length))) -			goto not_found; -		write(fd, raw, length); -		acpi_unmap_memory(raw, length); -		close(fd); -		return 0; -	} - -	length = sizeof(struct acpi_rsdp_descriptor); -	if (!addr) { -		addr = read_efi_systab(); -		if (!addr) { -			addr = ACPI_HI_RSDP_WINDOW_BASE; -			length = ACPI_HI_RSDP_WINDOW_SIZE; -		} -	} - -	if (!(raw = acpi_map_memory(addr, length)) || -	    !(x = acpi_scan_for_rsdp(raw, length))) -		goto not_found; - -	/* Find RSDP and print all found tables */ -	memcpy(&rsdpx, x, sizeof(struct acpi_rsdp_descriptor)); -	acpi_unmap_memory(raw, length); -	if (connect) { -		lseek(fd, sizeof(struct acpi_rsdp_descriptor), SEEK_SET); -	} -	if (!acpi_dump_SDT(fd, &rsdpx)) -		goto not_found; -	if (connect) { -		lseek(fd, 0, SEEK_SET); -		write(fd, x, (rsdpx.revision < 2) ? -			ACPI_RSDP_CHECKSUM_LENGTH : ACPI_RSDP_XCHECKSUM_LENGTH); -	} else if (!select_sig[0] || !memcmp("RSD PTR ", select_sig, 4)) { -		addr += (long)x - (long)raw; -		length = snprintf(buff, 80, "RSD PTR @ %p\n", (void *)addr); -		write(fd, buff, length); -		acpi_show_data(fd, (u8 *) & rsdpx, (rsdpx.revision < 2) ? -				ACPI_RSDP_CHECKSUM_LENGTH : ACPI_RSDP_XCHECKSUM_LENGTH); -		buff[0] = '\n'; -		write(fd, buff, 1); -	} -	acpi_dump_dynamic_SSDT(fd); -	close(fd); -	return 0; -not_found: -	close(fd); -	fprintf(stderr, "ACPI tables were not found. If you know location " -		"of RSD PTR table (from dmesg, etc), " -		"supply it with either --addr or -a option\n"); -	return 1; -} 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/Makefile b/tools/power/cpupower/Makefile index cbfec92af32..2e2ba2efa0d 100644 --- a/tools/power/cpupower/Makefile +++ b/tools/power/cpupower/Makefile @@ -62,7 +62,7 @@ LIB_MAJ=			0.0.0  LIB_MIN=			0  PACKAGE =			cpupower -PACKAGE_BUGREPORT =		cpufreq@vger.kernel.org +PACKAGE_BUGREPORT =		linux-pm@vger.kernel.org  LANGUAGES = 			de fr it cs pt @@ -274,6 +274,8 @@ 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 @@ -295,8 +297,12 @@ uninstall:  	- rm -f $(DESTDIR)${libdir}/libcpupower.*  	- rm -f $(DESTDIR)${includedir}/cpufreq.h  	- rm -f $(DESTDIR)${bindir}/utils/cpupower -	- rm -f $(DESTDIR)${mandir}/man1/cpufreq-set.1 -	- rm -f $(DESTDIR)${mandir}/man1/cpufreq-info.1 +	- 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; diff --git a/tools/power/cpupower/README b/tools/power/cpupower/README index fd9d4c0d668..1c68f47663b 100644 --- a/tools/power/cpupower/README +++ b/tools/power/cpupower/README @@ -1,6 +1,4 @@ -The cpufrequtils package (homepage:  -http://www.kernel.org/pub/linux/utils/kernel/cpufreq/cpufrequtils.html )  -consists of the following elements: +The cpupower package consists of the following elements:  requirements  ------------ @@ -11,10 +9,10 @@ providing cpuid.h is needed.  For both it's not explicitly checked for (yet). -libcpufreq +libcpupower  ---------- -"libcpufreq" is a library which offers a unified access method for userspace +"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 @@ -28,22 +26,22 @@ make  su  make install -should suffice on most systems. It builds default libcpufreq, -cpufreq-set and cpufreq-info files and installs them in /usr/lib and -/usr/bin, respectively. 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. +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 cpufrequtils; +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  -cpufrequtils. +cpupower.          Dominik Brodowski diff --git a/tools/power/cpupower/ToDo b/tools/power/cpupower/ToDo index 874b78b586e..6e8b89f282e 100644 --- a/tools/power/cpupower/ToDo +++ b/tools/power/cpupower/ToDo @@ -3,7 +3,6 @@ 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 -- Adjust README  - Somewhere saw the ability to read power consumption of    RAM from HW on Intel SandyBridge -> another monitor?  - Add another c1e debug idle monitor diff --git a/tools/power/cpupower/debug/kernel/cpufreq-test_tsc.c b/tools/power/cpupower/debug/kernel/cpufreq-test_tsc.c index 66cace601e5..5224ee5b392 100644 --- a/tools/power/cpupower/debug/kernel/cpufreq-test_tsc.c +++ b/tools/power/cpupower/debug/kernel/cpufreq-test_tsc.c @@ -18,19 +18,16 @@   * 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 - *     cpufreq@vger.kernel.org + *     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> -#include <acpi/acpi_bus.h> -#include <acpi/acpi_drivers.h> -  static int pm_tmr_ioport = 0;  /*helper function to safely read acpi pm timesource*/ diff --git a/tools/power/cpupower/man/cpupower-frequency-info.1 b/tools/power/cpupower/man/cpupower-frequency-info.1 index 4a1918ea8f9..9c85a382e35 100644 --- a/tools/power/cpupower/man/cpupower-frequency-info.1 +++ b/tools/power/cpupower/man/cpupower-frequency-info.1 @@ -50,6 +50,9 @@ Prints out information like provided by the /proc/cpufreq interface in 2.4. and  \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 diff --git a/tools/power/cpupower/man/cpupower-idle-info.1 b/tools/power/cpupower/man/cpupower-idle-info.1 index 4178effd9e9..7b3646adb92 100644 --- a/tools/power/cpupower/man/cpupower-idle-info.1 +++ b/tools/power/cpupower/man/cpupower-idle-info.1 @@ -87,4 +87,5 @@ Thomas Renninger <trenn@suse.de>  .fi  .SH "SEE ALSO"  .LP -cpupower(1), cpupower\-monitor(1), cpupower\-info(1), cpupower\-set(1) +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 index 58e21196f17..340bcd0be7d 100644 --- a/tools/power/cpupower/man/cpupower-info.1 +++ b/tools/power/cpupower/man/cpupower-info.1 @@ -3,7 +3,7 @@  cpupower\-info \- Shows processor power related kernel or hardware configurations  .SH SYNOPSIS  .ft B -.B cpupower info [ \-b ] [ \-s ] [ \-m ] +.B cpupower info [ \-b ]  .SH DESCRIPTION  \fBcpupower info \fP shows kernel configurations or processor hardware diff --git a/tools/power/cpupower/man/cpupower-set.1 b/tools/power/cpupower/man/cpupower-set.1 index 9dbd536518a..2bcc696f449 100644 --- a/tools/power/cpupower/man/cpupower-set.1 +++ b/tools/power/cpupower/man/cpupower-set.1 @@ -3,7 +3,7 @@  cpupower\-set \- Set processor power related kernel or hardware configurations  .SH SYNOPSIS  .ft B -.B cpupower set [ \-b VAL ] [ \-s VAL ] [ \-m VAL ] +.B cpupower set [ \-b VAL ]  .SH DESCRIPTION @@ -55,35 +55,6 @@ Use \fBcpupower -c all info -b\fP to verify.  This options needs the msr kernel driver (CONFIG_X86_MSR) loaded.  .RE -.PP -\-\-sched\-mc,  \-m [ VAL ] -.RE -\-\-sched\-smt, \-s [ VAL ] -.RS 4 -\-\-sched\-mc utilizes cores in one processor package/socket first before -processes are scheduled to other processor packages/sockets. - -\-\-sched\-smt utilizes thread siblings of one processor core first before -processes are scheduled to other cores. - -The impact on power consumption and performance (positiv or negativ) heavily -depends on processor support for deep sleep states, frequency scaling and -frequency boost modes and their dependencies between other thread siblings -and processor cores. - -Taken over from kernel documentation: - -Adjust the kernel's multi-core scheduler support. - -Possible values are: -.RS 2 -0 - No power saving load balance (default value) - -1 - Fill one thread/core/package first for long running threads - -2 - Also bias task wakeups to semi-idle cpu package for power -savings -.RE  .SH "SEE ALSO"  cpupower-info(1), cpupower-monitor(1), powertop(1) diff --git a/tools/power/cpupower/utils/cpufreq-info.c b/tools/power/cpupower/utils/cpufreq-info.c index 28953c9a7bd..b4b90a97662 100644 --- a/tools/power/cpupower/utils/cpufreq-info.c +++ b/tools/power/cpupower/utils/cpufreq-info.c @@ -82,29 +82,42 @@ static void proc_cpufreq_output(void)  	}  } +static int no_rounding;  static void print_speed(unsigned long speed)  {  	unsigned long tmp; -	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)); -	} else -		printf("%lu kHz", speed); +	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;  } @@ -113,26 +126,38 @@ static void print_duration(unsigned long duration)  {  	unsigned long tmp; -	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); - +	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;  } @@ -525,6 +550,7 @@ static struct option info_opts[] = {  	{ .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'},  	{ },  }; @@ -538,7 +564,8 @@ int cmd_freq_info(int argc, char **argv)  	int output_param = 0;  	do { -		ret = getopt_long(argc, argv, "oefwldpgrasmyb", info_opts, NULL); +		ret = getopt_long(argc, argv, "oefwldpgrasmybn", info_opts, +				  NULL);  		switch (ret) {  		case '?':  			output_param = '?'; @@ -575,6 +602,9 @@ int cmd_freq_info(int argc, char **argv)  			}  			human = 1;  			break; +		case 'n': +			no_rounding = 1; +			break;  		default:  			fprintf(stderr, "invalid or unknown argument\n");  			return EXIT_FAILURE; diff --git a/tools/power/cpupower/utils/cpufreq-set.c b/tools/power/cpupower/utils/cpufreq-set.c index dd1539eb8c6..a416de80c55 100644 --- a/tools/power/cpupower/utils/cpufreq-set.c +++ b/tools/power/cpupower/utils/cpufreq-set.c @@ -257,7 +257,7 @@ int cmd_freq_set(int argc, char **argv)  				print_unknown_arg();  				return -EINVAL;  			} -			if ((sscanf(optarg, "%s", gov)) != 1) { +			if ((sscanf(optarg, "%19s", gov)) != 1) {  				print_unknown_arg();  				return -EINVAL;  			} diff --git a/tools/power/cpupower/utils/cpuidle-set.c b/tools/power/cpupower/utils/cpuidle-set.c index c78141c5dfa..d45d8d775c0 100644 --- a/tools/power/cpupower/utils/cpuidle-set.c +++ b/tools/power/cpupower/utils/cpuidle-set.c @@ -13,8 +13,14 @@  #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", +	  .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'},  	{ },  }; @@ -23,11 +29,13 @@ int cmd_idle_set(int argc, char **argv)  {  	extern char *optarg;  	extern int optind, opterr, optopt; -	int ret = 0, cont = 1, param = 0, idlestate = 0; -	unsigned int cpu = 0; +	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:", info_opts, NULL); +		ret = getopt_long(argc, argv, "d:e:ED:", info_opts, NULL);  		if (ret == -1)  			break;  		switch (ret) { @@ -53,6 +61,27 @@ int cmd_idle_set(int argc, char **argv)  			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; @@ -79,8 +108,14 @@ int cmd_idle_set(int argc, char **argv)  		if (!bitmask_isbitset(cpus_chosen, cpu))  			continue; -		switch (param) { +		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) @@ -107,6 +142,34 @@ int cmd_idle_set(int argc, char **argv)  		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")); diff --git a/tools/power/cpupower/utils/cpupower-info.c b/tools/power/cpupower/utils/cpupower-info.c index 3f68632c28c..136d979e958 100644 --- a/tools/power/cpupower/utils/cpupower-info.c +++ b/tools/power/cpupower/utils/cpupower-info.c @@ -18,8 +18,6 @@  static struct option set_opts[] = {  	{ .name = "perf-bias",	.has_arg = optional_argument,	.flag = NULL,	.val = 'b'}, -	{ .name = "sched-mc",	.has_arg = optional_argument,	.flag = NULL,	.val = 'm'}, -	{ .name = "sched-smt",	.has_arg = optional_argument,	.flag = NULL,	.val = 's'},  	{ },  }; @@ -37,8 +35,6 @@ int cmd_info(int argc, char **argv)  	union {  		struct { -			int sched_mc:1; -			int sched_smt:1;  			int perf_bias:1;  		};  		int params; @@ -49,23 +45,13 @@ int cmd_info(int argc, char **argv)  	textdomain(PACKAGE);  	/* parameter parsing */ -	while ((ret = getopt_long(argc, argv, "msb", set_opts, NULL)) != -1) { +	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; -		case 'm': -			if (params.sched_mc) -				print_wrong_arg_exit(); -			params.sched_mc = 1; -			break; -		case 's': -			if (params.sched_smt) -				print_wrong_arg_exit(); -			params.sched_smt = 1; -			break;  		default:  			print_wrong_arg_exit();  		} @@ -78,25 +64,6 @@ int cmd_info(int argc, char **argv)  	if (bitmask_isallclear(cpus_chosen))  		bitmask_setbit(cpus_chosen, 0); -	if (params.sched_mc) { -		ret = sysfs_get_sched("mc"); -		printf(_("System's multi core scheduler setting: ")); -		if (ret < 0) -			/* if sysfs file is missing it's: errno == ENOENT */ -			printf(_("not supported\n")); -		else -			printf("%d\n", ret); -	} -	if (params.sched_smt) { -		ret = sysfs_get_sched("smt"); -		printf(_("System's thread sibling scheduler setting: ")); -		if (ret < 0) -			/* if sysfs file is missing it's: errno == ENOENT */ -			printf(_("not supported\n")); -		else -			printf("%d\n", ret); -	} -  	/* Add more per cpu options here */  	if (!params.perf_bias)  		return ret; @@ -125,11 +92,12 @@ int cmd_info(int argc, char **argv)  		if (params.perf_bias) {  			ret = msr_intel_get_perf_bias(cpu);  			if (ret < 0) { -				printf(_("Could not read perf-bias value\n")); -				break; +				fprintf(stderr, +			_("Could not read perf-bias value[%d]\n"), ret); +				exit(EXIT_FAILURE);  			} else  				printf(_("perf-bias: %d\n"), ret);  		}  	} -	return ret; +	return 0;  } diff --git a/tools/power/cpupower/utils/cpupower-set.c b/tools/power/cpupower/utils/cpupower-set.c index dc4de376211..573c75f8e3f 100644 --- a/tools/power/cpupower/utils/cpupower-set.c +++ b/tools/power/cpupower/utils/cpupower-set.c @@ -18,9 +18,7 @@  #include "helpers/bitmask.h"  static struct option set_opts[] = { -	{ .name = "perf-bias",	.has_arg = optional_argument,	.flag = NULL,	.val = 'b'}, -	{ .name = "sched-mc",	.has_arg = optional_argument,	.flag = NULL,	.val = 'm'}, -	{ .name = "sched-smt",	.has_arg = optional_argument,	.flag = NULL,	.val = 's'}, +	{ .name = "perf-bias",	.has_arg = required_argument,	.flag = NULL,	.val = 'b'},  	{ },  }; @@ -38,13 +36,11 @@ int cmd_set(int argc, char **argv)  	union {  		struct { -			int sched_mc:1; -			int sched_smt:1;  			int perf_bias:1;  		};  		int params;  	} params; -	int sched_mc = 0, sched_smt = 0, perf_bias = 0; +	int perf_bias = 0;  	int ret = 0;  	setlocale(LC_ALL, ""); @@ -52,7 +48,7 @@ int cmd_set(int argc, char **argv)  	params.params = 0;  	/* parameter parsing */ -	while ((ret = getopt_long(argc, argv, "m:s:b:", +	while ((ret = getopt_long(argc, argv, "b:",  						set_opts, NULL)) != -1) {  		switch (ret) {  		case 'b': @@ -66,28 +62,6 @@ int cmd_set(int argc, char **argv)  			}  			params.perf_bias = 1;  			break; -		case 'm': -			if (params.sched_mc) -				print_wrong_arg_exit(); -			sched_mc = atoi(optarg); -			if (sched_mc < 0 || sched_mc > 2) { -				printf(_("--sched-mc param out " -					 "of range [0-%d]\n"), 2); -				print_wrong_arg_exit(); -			} -			params.sched_mc = 1; -			break; -		case 's': -			if (params.sched_smt) -				print_wrong_arg_exit(); -			sched_smt = atoi(optarg); -			if (sched_smt < 0 || sched_smt > 2) { -				printf(_("--sched-smt param out " -					 "of range [0-%d]\n"), 2); -				print_wrong_arg_exit(); -			} -			params.sched_smt = 1; -			break;  		default:  			print_wrong_arg_exit();  		} @@ -96,19 +70,6 @@ int cmd_set(int argc, char **argv)  	if (!params.params)  		print_wrong_arg_exit(); -	if (params.sched_mc) { -		ret = sysfs_set_sched("mc", sched_mc); -		if (ret) -			fprintf(stderr, _("Error setting sched-mc %s\n"), -				(ret == -ENODEV) ? "not supported" : ""); -	} -	if (params.sched_smt) { -		ret = sysfs_set_sched("smt", sched_smt); -		if (ret) -			fprintf(stderr, _("Error setting sched-smt %s\n"), -				(ret == -ENODEV) ? "not supported" : ""); -	} -  	/* Default is: set all CPUs */  	if (bitmask_isallclear(cpus_chosen))  		bitmask_setall(cpus_chosen); diff --git a/tools/power/cpupower/utils/cpupower.c b/tools/power/cpupower/utils/cpupower.c index 7efc570ffba..7cdcf88659c 100644 --- a/tools/power/cpupower/utils/cpupower.c +++ b/tools/power/cpupower/utils/cpupower.c @@ -12,6 +12,9 @@  #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" @@ -169,6 +172,8 @@ 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)); @@ -195,6 +200,15 @@ int main(int argc, const char *argv[])  	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; diff --git a/tools/power/cpupower/utils/helpers/sysfs.c b/tools/power/cpupower/utils/helpers/sysfs.c index 5cdc600e815..851c7a16ca4 100644 --- a/tools/power/cpupower/utils/helpers/sysfs.c +++ b/tools/power/cpupower/utils/helpers/sysfs.c @@ -278,7 +278,7 @@ static char *sysfs_idlestate_get_one_string(unsigned int cpu,  int sysfs_is_idlestate_disabled(unsigned int cpu,  				unsigned int idlestate)  { -	if (sysfs_get_idlestate_count(cpu) < idlestate) +	if (sysfs_get_idlestate_count(cpu) <= idlestate)  		return -1;  	if (!sysfs_idlestate_file_exists(cpu, idlestate, @@ -303,7 +303,7 @@ int sysfs_idlestate_disable(unsigned int cpu,  	char value[SYSFS_PATH_MAX];  	int bytes_written; -	if (sysfs_get_idlestate_count(cpu) < idlestate) +	if (sysfs_get_idlestate_count(cpu) <= idlestate)  		return -1;  	if (!sysfs_idlestate_file_exists(cpu, idlestate, 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 index f09641da40d..d1b3a361e52 100644 --- a/tools/power/x86/turbostat/Makefile +++ b/tools/power/x86/turbostat/Makefile @@ -5,7 +5,7 @@ DESTDIR		:=  turbostat : turbostat.c  CFLAGS +=	-Wall -CFLAGS +=	-I../../../../arch/x86/include/uapi/ +CFLAGS +=	-DMSRHEADER='"../../../../arch/x86/include/uapi/asm/msr-index.h"'  %: %.c  	@mkdir -p $(BUILD_OUTPUT) diff --git a/tools/power/x86/turbostat/turbostat.8 b/tools/power/x86/turbostat/turbostat.8 index b4ddb748356..56bfb523c5b 100644 --- a/tools/power/x86/turbostat/turbostat.8 +++ b/tools/power/x86/turbostat/turbostat.8 @@ -47,21 +47,22 @@ displays the statistics gathered since it was forked.  .PP  .SH FIELD DESCRIPTIONS  .nf -\fBpk\fP processor package number. -\fBcor\fP processor core number. +\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. -\fB%c0\fP percent of the interval that the CPU retired instructions. -\fBGHz\fP average clock rate while the CPU was in c0 state. -\fBTSC\fP average GHz that the TSC ran during the entire interval. -\fB%c1, %c3, %c6, %c7\fP show the percentage residency in hardware core idle states. -\fBCTMP\fP Degrees Celsius reported by the per-core Digital Thermal Sensor. -\fBPTMP\fP Degrees Celsius reported by the per-package Package Thermal Monitor. -\fB%pc2, %pc3, %pc6, %pc7\fP percentage residency in hardware package idle states. -\fBPkg_W\fP Watts consumed by the whole package. -\fBCor_W\fP Watts consumed by the core part of the package. -\fBGFX_W\fP Watts consumed by the Graphics part of the package -- available only on client processors. -\fBRAM_W\fP Watts consumed by the DRAM DIMMS -- available only on server processors. +\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 @@ -78,29 +79,17 @@ For Watts columns, the summary is a system total.  Subsequent rows show per-CPU statistics.  .nf -[root@sandy]# ./turbostat -cor CPU    %c0  GHz  TSC    %c1    %c3    %c6    %c7 CTMP PTMP   %pc2   %pc3   %pc6   %pc7  Pkg_W  Cor_W GFX_W -          0.06 0.80 2.29   0.11   0.00   0.00  99.83   47   40   0.26   0.01   0.44  98.78   3.49   0.12  0.14 -  0   0   0.07 0.80 2.29   0.07   0.00   0.00  99.86   40   40   0.26   0.01   0.44  98.78   3.49   0.12  0.14 -  0   4   0.03 0.80 2.29   0.12 -  1   1   0.04 0.80 2.29   0.25   0.01   0.00  99.71   40 -  1   5   0.16 0.80 2.29   0.13 -  2   2   0.05 0.80 2.29   0.06   0.01   0.00  99.88   40 -  2   6   0.03 0.80 2.29   0.08 -  3   3   0.05 0.80 2.29   0.08   0.00   0.00  99.87   47 -  3   7   0.04 0.84 2.29   0.09 -.fi -.SH SUMMARY EXAMPLE -The "-s" option prints the column headers just once, -and then the one line system summary for each sample interval. - -.nf -[root@wsm]# turbostat -S -   %c0  GHz  TSC    %c1    %c3    %c6 CTMP   %pc3   %pc6 -  1.40 2.81 3.38  10.78  43.47  44.35   42  13.67   2.09 -  1.34 2.90 3.38  11.48  58.96  28.23   41  19.89   0.15 -  1.55 2.72 3.38  26.73  37.66  34.07   42   2.53   2.80 -  1.37 2.83 3.38  16.95  60.05  21.63   42   5.76   0.20 +[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: @@ -154,55 +143,35 @@ 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@x980 lenb]# ./turbostat cat /dev/zero > /dev/null +root@ivy: turbostat cat /dev/zero > /dev/null  ^C -cor CPU    %c0  GHz  TSC    %c1    %c3    %c6   %pc3   %pc6 -          8.86 3.61 3.38  15.06  31.19  44.89   0.00   0.00 -  0   0   1.46 3.22 3.38  16.84  29.48  52.22   0.00   0.00 -  0   6   0.21 3.06 3.38  18.09 -  1   2   0.53 3.33 3.38   2.80  46.40  50.27 -  1   8   0.89 3.47 3.38   2.44 -  2   4   1.36 3.43 3.38   9.04  23.71  65.89 -  2  10   0.18 2.86 3.38  10.22 -  8   1   0.04 2.87 3.38  99.96   0.01   0.00 -  8   7  99.72 3.63 3.38   0.27 -  9   3   0.31 3.21 3.38   7.64  56.55  35.50 -  9   9   0.08 2.95 3.38   7.88 - 10   5   1.42 3.43 3.38   2.14  30.99  65.44 - 10  11   0.16 2.88 3.38   3.40 +    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 cpu7 up its 3.6 GHz turbo limit +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 cpu7 are HT siblings within core8. -As cpu7 is very busy, it prevents its sibling, cpu1, +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 turbostat reports average GHz of 3.63, while -the arithmetic average of the GHz column above is lower. -This is a weighted average, where the weight is %c0.  ie. it is the total number of -un-halted cycles elapsed per time divided by the number of CPUs. -.SH SMI COUNTING EXAMPLE -On Intel Nehalem and newer processors, MSR 0x34 is a System Management Mode Interrupt (SMI) counter. -This counter is shown by default under the "SMI" column. -.nf -[root@x980 ~]# turbostat -cor CPU    %c0  GHz  TSC SMI    %c1    %c3    %c6 CTMP   %pc3   %pc6 -          0.11 1.91 3.38   0   1.84   0.26  97.79   29   0.82  83.87 -  0   0   0.40 1.63 3.38   0  10.27   0.12  89.20   20   0.82  83.88 -  0   6   0.06 1.63 3.38   0  10.61 -  1   2   0.37 2.63 3.38   0   0.02   0.10  99.51   22 -  1   8   0.01 1.62 3.38   0   0.39 -  2   4   0.07 1.62 3.38   0   0.04   0.07  99.82   23 -  2  10   0.02 1.62 3.38   0   0.09 -  8   1   0.23 1.64 3.38   0   0.10   1.07  98.60   24 -  8   7   0.02 1.64 3.38   0   0.31 -  9   3   0.03 1.62 3.38   0   0.03   0.05  99.89   29 -  9   9   0.02 1.62 3.38   0   0.05 - 10   5   0.07 1.62 3.38   0   0.08   0.12  99.73   27 - 10  11   0.03 1.62 3.38   0   0.13 -^C -.fi +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 " diff --git a/tools/power/x86/turbostat/turbostat.c b/tools/power/x86/turbostat/turbostat.c index fe702076ca4..d0396af99fa 100644 --- a/tools/power/x86/turbostat/turbostat.c +++ b/tools/power/x86/turbostat/turbostat.c @@ -2,7 +2,7 @@   * turbostat -- show CPU frequency and C-state residency   * on modern Intel turbo-capable processors.   * - * Copyright (c) 2012 Intel Corporation. + * Copyright (c) 2013 Intel Corporation.   * Len Brown <len.brown@intel.com>   *   * This program is free software; you can redistribute it and/or modify it @@ -20,8 +20,10 @@   */  #define _GNU_SOURCE -#include <asm/msr.h> +#include MSRHEADER +#include <stdarg.h>  #include <stdio.h> +#include <err.h>  #include <unistd.h>  #include <sys/types.h>  #include <sys/wait.h> @@ -35,21 +37,26 @@  #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 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 = 1000000000;	/* Ghz etc */ +unsigned int units = 1000000;	/* MHz etc */  unsigned int genuine_intel;  unsigned int has_invariant_tsc;  unsigned int do_nehalem_platform_info; @@ -75,12 +82,32 @@ 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) -#define RAPL_CORES	(1 << 1) -#define RAPL_GFX	(1 << 2) -#define RAPL_DRAM	(1 << 3) -#define RAPL_PKG_PERF_STATUS	(1 << 4) -#define RAPL_DRAM_PERF_STATUS	(1 << 5) +#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)) @@ -96,7 +123,7 @@ struct thread_data {  	unsigned long long tsc;  	unsigned long long aperf;  	unsigned long long mperf; -	unsigned long long c1;	/* derived */ +	unsigned long long c1;  	unsigned long long extra_msr64;  	unsigned long long extra_delta64;  	unsigned long long extra_msr32; @@ -230,156 +257,170 @@ int get_msr(int cpu, off_t offset, unsigned long long *msr)  	close(fd);  	if (retval != sizeof *msr) { -		fprintf(stderr, "%s offset 0x%zx read failed\n", pathname, offset); +		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, "pk"); -	if (show_pkg) -		outp += sprintf(outp, " "); +		outp += sprintf(outp, "Package ");  	if (show_core) -		outp += sprintf(outp, "cor"); +		outp += sprintf(outp, "    Core ");  	if (show_cpu) -		outp += sprintf(outp, " CPU"); -	if (show_pkg || show_core || show_cpu) -		outp += sprintf(outp, " "); +		outp += sprintf(outp, "    CPU "); +	if (has_aperf) +		outp += sprintf(outp, "Avg_MHz ");  	if (do_nhm_cstates) -		outp += sprintf(outp, "   %%c0"); +		outp += sprintf(outp, "  %%Busy ");  	if (has_aperf) -		outp += sprintf(outp, "  GHz"); -	outp += sprintf(outp, "  TSC"); +		outp += sprintf(outp, "Bzy_MHz "); +	outp += sprintf(outp, "TSC_MHz ");  	if (do_smi) -		outp += sprintf(outp, " SMI"); +		outp += sprintf(outp, "    SMI ");  	if (extra_delta_offset32) -		outp += sprintf(outp, "  count 0x%03X", 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); +		outp += sprintf(outp, " COUNT 0x%03X ", extra_delta_offset64);  	if (extra_msr_offset32) -		outp += sprintf(outp, "   MSR 0x%03X", 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, "    %%c1"); +		outp += sprintf(outp, "          MSR 0x%03X ", extra_msr_offset64);  	if (do_nhm_cstates) -		outp += sprintf(outp, "    %%c3"); +		outp += sprintf(outp, " CPU%%c1 "); +	if (do_nhm_cstates && !do_slm_cstates) +		outp += sprintf(outp, " CPU%%c3 ");  	if (do_nhm_cstates) -		outp += sprintf(outp, "    %%c6"); +		outp += sprintf(outp, " CPU%%c6 ");  	if (do_snb_cstates) -		outp += sprintf(outp, "    %%c7"); +		outp += sprintf(outp, " CPU%%c7 ");  	if (do_dts) -		outp += sprintf(outp, " CTMP"); +		outp += sprintf(outp, "CoreTmp ");  	if (do_ptm) -		outp += sprintf(outp, " PTMP"); +		outp += sprintf(outp, " PkgTmp ");  	if (do_snb_cstates) -		outp += sprintf(outp, "   %%pc2"); -	if (do_nhm_cstates) -		outp += sprintf(outp, "   %%pc3"); -	if (do_nhm_cstates) -		outp += sprintf(outp, "   %%pc6"); +		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, "   %%pc7"); +		outp += sprintf(outp, "Pkg%%pc7 ");  	if (do_c8_c9_c10) { -		outp += sprintf(outp, "   %%pc8"); -		outp += sprintf(outp, "   %%pc9"); -		outp += sprintf(outp, "  %%pc10"); -	} - -	if (do_rapl & RAPL_PKG) -		outp += sprintf(outp, "  Pkg_W"); -	if (do_rapl & RAPL_CORES) -		outp += sprintf(outp, "  Cor_W"); -	if (do_rapl & RAPL_GFX) -		outp += sprintf(outp, " GFX_W"); -	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, "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)  { -	fprintf(stderr, "t %p, c %p, p %p\n", t, c, p); +	outp += sprintf(outp, "t %p, c %p, p %p\n", t, c, p);  	if (t) { -		fprintf(stderr, "CPU: %d flags 0x%x\n", t->cpu_id, t->flags); -		fprintf(stderr, "TSC: %016llX\n", t->tsc); -		fprintf(stderr, "aperf: %016llX\n", t->aperf); -		fprintf(stderr, "mperf: %016llX\n", t->mperf); -		fprintf(stderr, "c1: %016llX\n", t->c1); -		fprintf(stderr, "msr0x%x: %08llX\n", +		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); -		fprintf(stderr, "msr0x%x: %016llX\n", +		outp += sprintf(outp, "msr0x%x: %016llX\n",  			extra_delta_offset64, t->extra_delta64); -		fprintf(stderr, "msr0x%x: %08llX\n", +		outp += sprintf(outp, "msr0x%x: %08llX\n",  			extra_msr_offset32, t->extra_msr32); -		fprintf(stderr, "msr0x%x: %016llX\n", +		outp += sprintf(outp, "msr0x%x: %016llX\n",  			extra_msr_offset64, t->extra_msr64);  		if (do_smi) -			fprintf(stderr, "SMI: %08X\n", t->smi_count); +			outp += sprintf(outp, "SMI: %08X\n", t->smi_count);  	}  	if (c) { -		fprintf(stderr, "core: %d\n", c->core_id); -		fprintf(stderr, "c3: %016llX\n", c->c3); -		fprintf(stderr, "c6: %016llX\n", c->c6); -		fprintf(stderr, "c7: %016llX\n", c->c7); -		fprintf(stderr, "DTS: %dC\n", c->core_temp_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) { -		fprintf(stderr, "package: %d\n", p->package_id); -		fprintf(stderr, "pc2: %016llX\n", p->pc2); -		fprintf(stderr, "pc3: %016llX\n", p->pc3); -		fprintf(stderr, "pc6: %016llX\n", p->pc6); -		fprintf(stderr, "pc7: %016llX\n", p->pc7); -		fprintf(stderr, "pc8: %016llX\n", p->pc8); -		fprintf(stderr, "pc9: %016llX\n", p->pc9); -		fprintf(stderr, "pc10: %016llX\n", p->pc10); -		fprintf(stderr, "Joules PKG: %0X\n", p->energy_pkg); -		fprintf(stderr, "Joules COR: %0X\n", p->energy_cores); -		fprintf(stderr, "Joules GFX: %0X\n", p->energy_gfx); -		fprintf(stderr, "Joules RAM: %0X\n", p->energy_dram); -		fprintf(stderr, "Throttle PKG: %0X\n", p->rapl_pkg_perf_status); -		fprintf(stderr, "Throttle RAM: %0X\n", p->rapl_dram_perf_status); -		fprintf(stderr, "PTM: %dC\n", p->pkg_temp_c); +		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 - * package: "pk" 2 columns %2d - * core: "cor" 3 columns %3d - * CPU: "CPU" 3 columns %3d - * Pkg_W: %6.2 - * Cor_W: %6.2 - * GFX_W: %5.2 - * RAM_W: %5.2 - * GHz: "GHz" 3 columns %3.2 - * TSC: "TSC" 3 columns %3.2 - * SMI: "SMI" 4 columns %4d - * percentage " %pc3" %6.2 - * Perf Status percentage: %5.2 - * "CTMP" 4 columns %4d   */  int format_counters(struct thread_data *t, struct core_data *c,  	struct pkg_data *p)  {  	double interval_float; -	char *fmt5, *fmt6; +	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)) @@ -394,65 +435,52 @@ int format_counters(struct thread_data *t, struct core_data *c,  	/* topo columns, print blanks on 1st (average) line */  	if (t == &average.threads) {  		if (show_pkg) -			outp += sprintf(outp, "  "); -		if (show_pkg && show_core) -			outp += sprintf(outp, " "); +			outp += sprintf(outp, "       -");  		if (show_core) -			outp += sprintf(outp, "   "); +			outp += sprintf(outp, "       -");  		if (show_cpu) -			outp += sprintf(outp, " " "   "); +			outp += sprintf(outp, "       -");  	} else {  		if (show_pkg) {  			if (p) -				outp += sprintf(outp, "%2d", p->package_id); +				outp += sprintf(outp, "%8d", p->package_id);  			else -				outp += sprintf(outp, "  "); +				outp += sprintf(outp, "       -");  		} -		if (show_pkg && show_core) -			outp += sprintf(outp, " ");  		if (show_core) {  			if (c) -				outp += sprintf(outp, "%3d", c->core_id); +				outp += sprintf(outp, "%8d", c->core_id);  			else -				outp += sprintf(outp, "   "); +				outp += sprintf(outp, "       -");  		}  		if (show_cpu) -			outp += sprintf(outp, " %3d", t->cpu_id); +			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 (show_pkg || show_core || show_cpu) -			outp += sprintf(outp, " ");  		if (!skip_c0) -			outp += sprintf(outp, "%6.2f", 100.0 * t->mperf/t->tsc); +			outp += sprintf(outp, "%8.2f", 100.0 * t->mperf/t->tsc);  		else -			outp += sprintf(outp, "  ****"); +			outp += sprintf(outp, "********");  	} -	/* GHz */ -	if (has_aperf) { -		if (!aperf_mperf_unstable) { -			outp += sprintf(outp, " %3.2f", -				1.0 * t->tsc / units * t->aperf / -				t->mperf / interval_float); -		} else { -			if (t->aperf > t->tsc || t->mperf > t->tsc) { -				outp += sprintf(outp, " ***"); -			} else { -				outp += sprintf(outp, "%3.1f*", -					1.0 * t->tsc / -					units * t->aperf / -					t->mperf / interval_float); -			} -		} -	} +	/* BzyMHz */ +	if (has_aperf) +		outp += sprintf(outp, "%8.0f", +			1.0 * t->tsc / units * t->aperf / t->mperf / interval_float);  	/* TSC */ -	outp += sprintf(outp, "%5.2f", 1.0 * t->tsc/units/interval_float); +	outp += sprintf(outp, "%8.0f", 1.0 * t->tsc/units/interval_float);  	/* SMI */  	if (do_smi) -		outp += sprintf(outp, "%4d", t->smi_count); +		outp += sprintf(outp, "%8d", t->smi_count);  	/* delta */  	if (extra_delta_offset32) @@ -471,71 +499,88 @@ int format_counters(struct thread_data *t, struct core_data *c,  	if (do_nhm_cstates) {  		if (!skip_c1) -			outp += sprintf(outp, " %6.2f", 100.0 * t->c1/t->tsc); +			outp += sprintf(outp, "%8.2f", 100.0 * t->c1/t->tsc);  		else -			outp += sprintf(outp, "  ****"); +			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, " %6.2f", 100.0 * c->c3/t->tsc); -	if (do_nhm_cstates) -		outp += sprintf(outp, " %6.2f", 100.0 * c->c6/t->tsc); +		outp += sprintf(outp, "%8.2f", 100.0 * c->c6/t->tsc);  	if (do_snb_cstates) -		outp += sprintf(outp, " %6.2f", 100.0 * c->c7/t->tsc); +		outp += sprintf(outp, "%8.2f", 100.0 * c->c7/t->tsc);  	if (do_dts) -		outp += sprintf(outp, " %4d", c->core_temp_c); +		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, " %4d", p->pkg_temp_c); +		outp += sprintf(outp, "%8d", p->pkg_temp_c);  	if (do_snb_cstates) -		outp += sprintf(outp, " %6.2f", 100.0 * p->pc2/t->tsc); -	if (do_nhm_cstates) -		outp += sprintf(outp, " %6.2f", 100.0 * p->pc3/t->tsc); -	if (do_nhm_cstates) -		outp += sprintf(outp, " %6.2f", 100.0 * p->pc6/t->tsc); +		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, " %6.2f", 100.0 * p->pc7/t->tsc); +		outp += sprintf(outp, "%8.2f", 100.0 * p->pc7/t->tsc);  	if (do_c8_c9_c10) { -		outp += sprintf(outp, " %6.2f", 100.0 * p->pc8/t->tsc); -		outp += sprintf(outp, " %6.2f", 100.0 * p->pc9/t->tsc); -		outp += sprintf(outp, " %6.2f", 100.0 * p->pc10/t->tsc); +		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) { -		fmt5 = " %5.2f"; -		fmt6 = " %6.2f"; +	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 { -		fmt5 = " %3.0f**"; -		fmt6 = " %4.0f**"; -	} - -	if (do_rapl & RAPL_PKG) -		outp += sprintf(outp, fmt6, p->energy_pkg * rapl_energy_units / interval_float); -	if (do_rapl & RAPL_CORES) -		outp += sprintf(outp, fmt6, p->energy_cores * rapl_energy_units / interval_float); -	if (do_rapl & RAPL_GFX) -		outp += sprintf(outp, fmt5, p->energy_gfx * rapl_energy_units / interval_float);  -	if (do_rapl & RAPL_DRAM) -		outp += sprintf(outp, fmt5, p->energy_dram * rapl_energy_units / interval_float); -	if (do_rapl & RAPL_PKG_PERF_STATUS ) -		outp += sprintf(outp, fmt5, 100.0 * p->rapl_pkg_perf_status * rapl_time_units / interval_float); -	if (do_rapl & RAPL_DRAM_PERF_STATUS ) -		outp += sprintf(outp, fmt5, 100.0 * p->rapl_dram_perf_status * rapl_time_units / interval_float); +		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"); @@ -618,12 +663,10 @@ delta_thread(struct thread_data *new, struct thread_data *old,  	old->tsc = new->tsc - old->tsc;  	/* check for TSC < 1 Mcycles over interval */ -	if (old->tsc < (1000 * 1000)) { -		fprintf(stderr, "Insanely slow TSC rate, TSC stops in idle?\n"); -		fprintf(stderr, "You can disable all c-states by booting with \"idle=poll\"\n"); -		fprintf(stderr, "or just the deep ones with \"processor.max_cstate=1\"\n"); -		exit(-3); -	} +	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; @@ -648,17 +691,24 @@ delta_thread(struct thread_data *new, struct thread_data *old,  	} -	/* -	 * 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 +	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) { @@ -872,13 +922,21 @@ int get_counters(struct thread_data *t, struct core_data *c, struct pkg_data *p)  		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) { +	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;  	} @@ -898,7 +956,7 @@ int get_counters(struct thread_data *t, struct core_data *c, struct pkg_data *p)  	if (!(t->flags & CPU_IS_FIRST_CORE_IN_PACKAGE))  		return 0; -	if (do_nhm_cstates) { +	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)) @@ -977,7 +1035,7 @@ void print_verbose_header(void)  		ratio, bclk, ratio * bclk);  	get_msr(0, MSR_IA32_POWER_CTL, &msr); -	fprintf(stderr, "cpu0: MSR_IA32_POWER_CTL: 0x%08llx (C1E: %sabled)\n", +	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) @@ -1046,25 +1104,28 @@ print_nhm_turbo_ratio_limits:  	switch(msr & 0x7) {  	case 0: -		fprintf(stderr, "pc0"); +		fprintf(stderr, do_slm_cstates ? "no pkg states" : "pc0");  		break;  	case 1: -		fprintf(stderr, do_snb_cstates ? "pc2" : "pc0"); +		fprintf(stderr, do_slm_cstates ? "no pkg states" : do_snb_cstates ? "pc2" : "pc0");  		break;  	case 2: -		fprintf(stderr, do_snb_cstates ? "pc6-noret" : "pc3"); +		fprintf(stderr, do_slm_cstates ? "invalid" : do_snb_cstates ? "pc6-noret" : "pc3");  		break;  	case 3: -		fprintf(stderr, "pc6"); +		fprintf(stderr, do_slm_cstates ? "invalid" : "pc6");  		break;  	case 4: -		fprintf(stderr, "pc7"); +		fprintf(stderr, do_slm_cstates ? "pc4" : "pc7");  		break;  	case 5: -		fprintf(stderr, do_snb_cstates ? "pc7s" : "invalid"); +		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, "unlimited"); +		fprintf(stderr, do_slm_cstates ? "pc7" : "unlimited");  		break;  	default:  		fprintf(stderr, "invalid"); @@ -1151,24 +1212,43 @@ void free_all_buffers(void)  }  /* + * 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)  { -	char path[64]; -	FILE *filep; -	int first_cpu; - -	sprintf(path, "/sys/devices/system/cpu/cpu%d/topology/thread_siblings_list", cpu); -	filep = fopen(path, "r"); -	if (filep == NULL) { -		perror(path); -		exit(1); -	} -	fscanf(filep, "%d", &first_cpu); -	fclose(filep); -	return (cpu == first_cpu); +	return cpu == parse_int_file("/sys/devices/system/cpu/cpu%d/topology/thread_siblings_list", cpu);  }  /* @@ -1177,53 +1257,17 @@ int cpu_is_first_sibling_in_core(int cpu)   */  int cpu_is_first_core_in_package(int cpu)  { -	char path[64]; -	FILE *filep; -	int first_cpu; - -	sprintf(path, "/sys/devices/system/cpu/cpu%d/topology/core_siblings_list", cpu); -	filep = fopen(path, "r"); -	if (filep == NULL) { -		perror(path); -		exit(1); -	} -	fscanf(filep, "%d", &first_cpu); -	fclose(filep); -	return (cpu == first_cpu); +	return cpu == parse_int_file("/sys/devices/system/cpu/cpu%d/topology/core_siblings_list", cpu);  }  int get_physical_package_id(int cpu)  { -	char path[80]; -	FILE *filep; -	int pkg; - -	sprintf(path, "/sys/devices/system/cpu/cpu%d/topology/physical_package_id", cpu); -	filep = fopen(path, "r"); -	if (filep == NULL) { -		perror(path); -		exit(1); -	} -	fscanf(filep, "%d", &pkg); -	fclose(filep); -	return pkg; +	return parse_int_file("/sys/devices/system/cpu/cpu%d/topology/physical_package_id", cpu);  }  int get_core_id(int cpu)  { -	char path[80]; -	FILE *filep; -	int core; - -	sprintf(path, "/sys/devices/system/cpu/cpu%d/topology/core_id", cpu); -	filep = fopen(path, "r"); -	if (filep == NULL) { -		perror(path); -		exit(1); -	} -	fscanf(filep, "%d", &core); -	fclose(filep); -	return core; +	return parse_int_file("/sys/devices/system/cpu/cpu%d/topology/core_id", cpu);  }  int get_num_ht_siblings(int cpu) @@ -1235,11 +1279,7 @@ int get_num_ht_siblings(int cpu)  	char character;  	sprintf(path, "/sys/devices/system/cpu/cpu%d/topology/thread_siblings_list", cpu); -	filep = fopen(path, "r"); -	if (filep == NULL) { -		perror(path); -		exit(1); -	} +	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) @@ -1309,17 +1349,11 @@ int for_all_proc_cpus(int (func)(int))  	int cpu_num;  	int retval; -	fp = fopen(proc_stat, "r"); -	if (fp == NULL) { -		perror(proc_stat); -		exit(1); -	} +	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) { -		perror("/proc/stat format"); -		exit(1); -	} +	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); @@ -1423,19 +1457,15 @@ void check_dev_msr()  {  	struct stat sb; -	if (stat("/dev/cpu/0/msr", &sb)) { -		fprintf(stderr, "no /dev/cpu/0/msr\n"); -		fprintf(stderr, "Try \"# modprobe msr\"\n"); -		exit(-5); -	} +	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) { -		fprintf(stderr, "must be root\n"); -		exit(-6); -	} +	if (getuid() != 0) +		errx(-6, "must be root");  }  int has_nehalem_turbo_ratio_limit(unsigned int family, unsigned int model) @@ -1457,9 +1487,14 @@ int has_nehalem_turbo_ratio_limit(unsigned int family, unsigned int model)  	case 0x3A:	/* IVB */  	case 0x3E:	/* IVB Xeon */  	case 0x3C:	/* HSW */ -	case 0x3F:	/* 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 */ @@ -1532,14 +1567,33 @@ int print_epb(struct thread_data *t, struct core_data *c, struct pkg_data *p)  #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 + * 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) @@ -1552,14 +1606,23 @@ void rapl_probe(unsigned int family, unsigned int model)  	case 0x2A:  	case 0x3A:  	case 0x3C:	/* HSW */ -	case 0x3F:	/* HSW */  	case 0x45:	/* HSW */  	case 0x46:	/* HSW */ -		do_rapl = RAPL_PKG | RAPL_CORES | RAPL_GFX; +	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_DRAM | RAPL_PKG_PERF_STATUS | RAPL_DRAM_PERF_STATUS; +		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; @@ -1570,19 +1633,22 @@ void rapl_probe(unsigned int family, unsigned int model)  		return;  	rapl_power_units = 1.0 / (1 << (msr & 0xF)); -	rapl_energy_units = 1.0 / (1 << (msr >> 8 & 0x1F)); -	rapl_time_units = 1.0 / (1 << (msr >> 16 & 0xF)); +	if (model == 0x37) +		rapl_energy_units = 1.0 * (1 << (msr >> 8 & 0x1F)) / 1000000; +	else +		rapl_energy_units = 1.0 / (1 << (msr >> 8 & 0x1F)); -	/* get TDP to determine energy counter range */ -	if (get_msr(0, MSR_PKG_POWER_INFO, &msr)) -		return; +	time_unit = msr >> 16 & 0xF; +	if (time_unit == 0) +		time_unit = 0xA; -	tdp = ((msr >> 0) & RAPL_POWER_GRANULARITY) * rapl_power_units; +	rapl_time_units = 1.0 / (1 << (time_unit)); -	rapl_joule_counter_range = 0xFFFFFFFF * rapl_energy_units / tdp; +	tdp = get_tdp(model); +	rapl_joule_counter_range = 0xFFFFFFFF * rapl_energy_units / tdp;  	if (verbose) -		fprintf(stderr, "RAPL: %.0f sec. Joule Counter Range\n", rapl_joule_counter_range); +		fprintf(stderr, "RAPL: %.0f sec. Joule Counter Range, at %.0f Watts\n", rapl_joule_counter_range, tdp);  	return;  } @@ -1668,7 +1734,6 @@ int print_rapl(struct thread_data *t, struct core_data *c, struct pkg_data *p)  {  	unsigned long long msr;  	int cpu; -	double local_rapl_power_units, local_rapl_energy_units, local_rapl_time_units;  	if (!do_rapl)  		return 0; @@ -1686,23 +1751,13 @@ int print_rapl(struct thread_data *t, struct core_data *c, struct pkg_data *p)  	if (get_msr(cpu, MSR_RAPL_POWER_UNIT, &msr))  		return -1; -	local_rapl_power_units = 1.0 / (1 << (msr & 0xF)); -	local_rapl_energy_units = 1.0 / (1 << (msr >> 8 & 0x1F)); -	local_rapl_time_units = 1.0 / (1 << (msr >> 16 & 0xF)); - -	if (local_rapl_power_units != rapl_power_units) -		fprintf(stderr, "cpu%d, ERROR: Power units mis-match\n", cpu); -	if (local_rapl_energy_units != rapl_energy_units) -		fprintf(stderr, "cpu%d, ERROR: Energy units mis-match\n", cpu); -	if (local_rapl_time_units != rapl_time_units) -		fprintf(stderr, "cpu%d, ERROR: Time units mis-match\n", cpu); -  	if (verbose) {  		fprintf(stderr, "cpu%d: MSR_RAPL_POWER_UNIT: 0x%08llx "  			"(%f Watts, %f Joules, %f sec.)\n", cpu, msr, -			local_rapl_power_units, local_rapl_energy_units, local_rapl_time_units); +			rapl_power_units, rapl_energy_units, rapl_time_units);  	} -	if (do_rapl & RAPL_PKG) { +	if (do_rapl & RAPL_PKG_POWER_INFO) { +  		if (get_msr(cpu, MSR_PKG_POWER_INFO, &msr))                  	return -5; @@ -1714,6 +1769,9 @@ int print_rapl(struct thread_data *t, struct core_data *c, struct pkg_data *p)  			((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; @@ -1749,12 +1807,16 @@ int print_rapl(struct thread_data *t, struct core_data *c, struct pkg_data *p)  		print_power_limit_msr(cpu, msr, "DRAM Limit");  	} -	if (do_rapl & RAPL_CORES) { +	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; @@ -1795,6 +1857,9 @@ int is_snb(unsigned int family, unsigned int model)  	case 0x3F:	/* HSW */  	case 0x45:	/* HSW */  	case 0x46:	/* HSW */ +	case 0x3D:	/* BDW */ +	case 0x4F:	/* BDX */ +	case 0x56:	/* BDX-DE */  		return 1;  	}  	return 0; @@ -1806,17 +1871,56 @@ int has_c8_c9_c10(unsigned int family, unsigned int model)  		return 0;  	switch (model) { -	case 0x45: +	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;  } @@ -1867,13 +1971,13 @@ int set_temperature_target(struct thread_data *t, struct core_data *c, struct pk  	if (get_msr(0, MSR_IA32_TEMPERATURE_TARGET, &msr))  		goto guess; -	target_c_local = (msr >> 16) & 0x7F; +	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 < 85 || target_c_local > 120) +	if (!target_c_local)  		goto guess;  	tcc_activation_temp = target_c_local; @@ -1894,7 +1998,7 @@ void check_cpuid()  	eax = ebx = ecx = edx = 0; -	asm("cpuid" : "=a" (max_level), "=b" (ebx), "=c" (ecx), "=d" (edx) : "a" (0)); +	__get_cpuid(0, &max_level, &ebx, &ecx, &edx);  	if (ebx == 0x756e6547 && edx == 0x49656e69 && ecx == 0x6c65746e)  		genuine_intel = 1; @@ -1903,7 +2007,7 @@ void check_cpuid()  		fprintf(stderr, "CPUID(0): %.4s%.4s%.4s ",  			(char *)&ebx, (char *)&edx, (char *)&ecx); -	asm("cpuid" : "=a" (fms), "=c" (ecx), "=d" (edx) : "a" (1) : "ebx"); +	__get_cpuid(1, &fms, &ebx, &ecx, &edx);  	family = (fms >> 8) & 0xf;  	model = (fms >> 4) & 0xf;  	stepping = fms & 0xf; @@ -1914,10 +2018,8 @@ void check_cpuid()  		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))) { -		fprintf(stderr, "CPUID: no MSR\n"); -		exit(1); -	} +	if (!(edx & (1 << 5))) +		errx(1, "CPUID: no MSR");  	/*  	 * check max extended function levels of CPUID. @@ -1925,31 +2027,27 @@ void check_cpuid()  	 * This check is valid for both Intel and AMD.  	 */  	ebx = ecx = edx = 0; -	asm("cpuid" : "=a" (max_level), "=b" (ebx), "=c" (ecx), "=d" (edx) : "a" (0x80000000)); +	__get_cpuid(0x80000000, &max_level, &ebx, &ecx, &edx); -	if (max_level < 0x80000007) { -		fprintf(stderr, "CPUID: no invariant TSC (max_level 0x%x)\n", max_level); -		exit(1); -	} +	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  	 */ -	asm("cpuid" : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx) : "a" (0x80000007)); +	__get_cpuid(0x80000007, &eax, &ebx, &ecx, &edx);  	has_invariant_tsc = edx & (1 << 8); -	if (!has_invariant_tsc) { -		fprintf(stderr, "No invariant TSC\n"); -		exit(1); -	} +	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  	 */ -	asm("cpuid" : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx) : "a" (0x6)); +	__get_cpuid(0x6, &eax, &ebx, &ecx, &edx);  	has_aperf = ecx & (1 << 0);  	do_dts = eax & (1 << 0);  	do_ptm = eax & (1 << 6); @@ -1963,13 +2061,14 @@ void check_cpuid()  			has_epb ? ", EPB": "");  	if (!has_aperf) -		exit(-1); +		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); @@ -1982,9 +2081,8 @@ void check_cpuid()  void usage()  { -	fprintf(stderr, "%s: [-v][-R][-T][-p|-P|-S][-c MSR# | -s]][-C MSR#][-m MSR#][-M MSR#][-i interval_sec | command ...]\n", -		progname); -	exit(1); +	errx(1, "%s: [-v][-R][-T][-p|-P|-S][-c MSR#][-C MSR#][-m MSR#][-M MSR#][-i interval_sec | command ...]\n", +	     progname);  } @@ -2027,19 +2125,15 @@ void topology_probe()  		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) { -		perror("calloc cpus"); -		exit(1); -	} +	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) { -		perror("CPU_ALLOC"); -		exit(3); -	} +	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); @@ -2048,10 +2142,8 @@ void topology_probe()  	 * Allocate and initialize cpu_affinity_set  	 */  	cpu_affinity_set = CPU_ALLOC((topo.max_cpu_num + 1)); -	if (cpu_affinity_set == NULL) { -		perror("CPU_ALLOC"); -		exit(3); -	} +	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); @@ -2135,8 +2227,7 @@ allocate_counters(struct thread_data **t, struct core_data **c, struct pkg_data  	return;  error: -	perror("calloc counters"); -	exit(1); +	err(1, "calloc counters");  }  /*   * init_counter() @@ -2191,12 +2282,10 @@ int initialize_counters(int cpu_id)  void allocate_output_buffer()  { -	output_buffer = calloc(1, (1 + topo.num_cpus) * 256); +	output_buffer = calloc(1, (1 + topo.num_cpus) * 1024);  	outp = output_buffer; -	if (outp == NULL) { -		perror("calloc"); -		exit(-1); -	} +	if (outp == NULL) +		err(-1, "calloc output buffer");  }  void setup_all_buffers(void) @@ -2207,6 +2296,7 @@ void setup_all_buffers(void)  	allocate_output_buffer();  	for_all_proc_cpus(initialize_counters);  } +  void turbostat_init()  {  	check_cpuid(); @@ -2250,17 +2340,13 @@ int fork_it(char **argv)  	} else {  		/* parent */ -		if (child_pid == -1) { -			perror("fork"); -			exit(1); -		} +		if (child_pid == -1) +			err(1, "fork");  		signal(SIGINT, SIG_IGN);  		signal(SIGQUIT, SIG_IGN); -		if (waitpid(child_pid, &status, 0) == -1) { -			perror("wait"); -			exit(status); -		} +		if (waitpid(child_pid, &status, 0) == -1) +			err(status, "waitpid");  	}  	/*  	 * n.b. fork_it() does not check for errors from for_all_cpus() @@ -2279,13 +2365,30 @@ int fork_it(char **argv)  	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, "+pPSvi:sc:sC:m:M:RT:")) != -1) { +	while ((opt = getopt(argc, argv, "+pPsSvi:c:C:m:M:RJT:")) != -1) {  		switch (opt) {  		case 'p':  			show_core_only++; @@ -2293,6 +2396,9 @@ void cmdline(int argc, char **argv)  		case 'P':  			show_pkg_only++;  			break; +		case 's': +			dump_only++; +			break;  		case 'S':  			summary_only++;  			break; @@ -2320,6 +2426,10 @@ void cmdline(int argc, char **argv)  		case 'T':  			tcc_activation_temp_override = atoi(optarg);  			break; +		case 'J': +			rapl_joules++; +			break; +  		default:  			usage();  		} @@ -2331,11 +2441,15 @@ int main(int argc, char **argv)  	cmdline(argc, argv);  	if (verbose) -		fprintf(stderr, "turbostat v3.4 April 17, 2013" +		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  	 */  | 
