summary refs log tree commit diff
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-rw-r--r--tools/power/acpi/Makefile18
-rw-r--r--tools/power/acpi/acpidump.859
-rw-r--r--tools/power/acpi/acpidump.c560
-rw-r--r--tools/power/x86/turbostat/turbostat.855
-rw-r--r--tools/power/x86/turbostat/turbostat.c214
5 files changed, 870 insertions, 36 deletions
diff --git a/tools/power/acpi/Makefile b/tools/power/acpi/Makefile
new file mode 100644
index 000000000000..6b9cf7a987c7
--- /dev/null
+++ b/tools/power/acpi/Makefile
@@ -0,0 +1,18 @@
+PROG= acpidump
+SRCS=	acpidump.c
+KERNEL_INCLUDE := ../../../include
+CFLAGS += -Wall -Wstrict-prototypes -Wdeclaration-after-statement -Os -s -D_LINUX -DDEFINE_ALTERNATE_TYPES -I$(KERNEL_INCLUDE) 
+
+all: acpidump
+$(PROG) : $(SRCS)
+	$(CC) $(CFLAGS) $(SRCS) -o $(PROG)
+
+CLEANFILES= $(PROG)
+
+clean : 
+	rm -f $(CLEANFILES) $(patsubst %.c,%.o, $(SRCS)) *~
+
+install :
+	install acpidump /usr/bin/acpidump
+	install acpidump.8 /usr/share/man/man8
+
diff --git a/tools/power/acpi/acpidump.8 b/tools/power/acpi/acpidump.8
new file mode 100644
index 000000000000..adfa99166e5e
--- /dev/null
+++ b/tools/power/acpi/acpidump.8
@@ -0,0 +1,59 @@
+.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
new file mode 100644
index 000000000000..07779871421c
--- /dev/null
+++ b/tools/power/acpi/acpidump.c
@@ -0,0 +1,560 @@
+/*
+ * (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 <sys/types.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/x86/turbostat/turbostat.8 b/tools/power/x86/turbostat/turbostat.8
index 74e44507dfe9..e4d0690cccf9 100644
--- a/tools/power/x86/turbostat/turbostat.8
+++ b/tools/power/x86/turbostat/turbostat.8
@@ -4,15 +4,11 @@ turbostat \- Report processor frequency and idle statistics
 .SH SYNOPSIS
 .ft B
 .B turbostat
-.RB [ "\-s" ]
-.RB [ "\-v" ]
-.RB [ "\-M MSR#" ]
+.RB [ Options ]
 .RB command
 .br
 .B turbostat
-.RB [ "\-s" ]
-.RB [ "\-v" ]
-.RB [ "\-M MSR#" ]
+.RB [ Options ]
 .RB [ "\-i interval_sec" ]
 .SH DESCRIPTION
 \fBturbostat \fP reports processor topology, frequency
@@ -27,16 +23,23 @@ supports an "invariant" TSC, plus the APERF and MPERF MSRs.
 on processors that additionally support C-state residency counters.
 
 .SS Options
-The \fB-s\fP option limits output to a 1-line system summary for each interval.
+The \fB-p\fP option limits output to the 1st thread in 1st core of each package.
 .PP
-The \fB-c\fP option limits output to the 1st thread in each core.
+The \fB-P\fP option limits output to the 1st thread in each Package.
 .PP
-The \fB-p\fP option limits output to the 1st thread in each package.
+The \fB-S\fP option limits output to a 1-line System Summary for each interval.
 .PP
 The \fB-v\fP option increases verbosity.
 .PP
-The \fB-M MSR#\fP option dumps the specified MSR,
-in addition to the usual frequency and idle statistics.
+The \fB-s\fP option prints the SMI counter, equivalent to "-c 0x34"
+.PP
+The \fB-c MSR#\fP option includes the delta of the specified 32-bit MSR counter.
+.PP
+The \fB-C MSR#\fP option includes the delta of the specified 64-bit MSR counter.
+.PP
+The \fB-m MSR#\fP option includes the the specified 32-bit MSR value.
+.PP
+The \fB-M MSR#\fP option includes the the specified 64-bit MSR value.
 .PP
 The \fB-i interval_sec\fP option prints statistics every \fiinterval_sec\fP seconds.
 The default is 5 seconds.
@@ -150,6 +153,29 @@ 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.
+Using the -m option, you can display how many SMIs have fired since reset, or if there
+are SMIs during the measurement interval, you can display the delta using the -d option.
+.nf
+[root@x980 ~]# turbostat -m 0x34
+cor CPU    %c0  GHz  TSC   MSR 0x034    %c1    %c3    %c6   %pc3   %pc6
+          1.41 1.82 3.38  0x00000000   8.92  37.82  51.85  17.37   0.55
+  0   0   3.73 2.03 3.38  0x00000055   1.72  48.25  46.31  17.38   0.55
+  0   6   0.14 1.63 3.38  0x00000056   5.30
+  1   2   2.51 1.80 3.38  0x00000056  15.65  29.33  52.52
+  1   8   0.10 1.65 3.38  0x00000056  18.05
+  2   4   1.16 1.68 3.38  0x00000056   5.87  24.47  68.50
+  2  10   0.10 1.63 3.38  0x00000056   6.93
+  8   1   3.84 1.91 3.38  0x00000056   1.36  50.65  44.16
+  8   7   0.08 1.64 3.38  0x00000056   5.12
+  9   3   1.82 1.73 3.38  0x00000056   7.59  24.21  66.38
+  9   9   0.09 1.68 3.38  0x00000056   9.32
+ 10   5   1.66 1.65 3.38  0x00000056  15.10  50.00  33.23
+ 10  11   1.72 1.65 3.38  0x00000056  15.05
+^C
+[root@x980 ~]# 
+.fi
 .SH NOTES
 
 .B "turbostat "
@@ -165,6 +191,13 @@ may work poorly on Linux-2.6.20 through 2.6.29,
 as \fBacpi-cpufreq \fPperiodically cleared the APERF and MPERF
 in those kernels.
 
+If the TSC column does not make sense, then
+the other numbers will also make no sense.
+Turbostat is lightweight, and its data collection is not atomic.
+These issues are usually caused by an extremely short measurement
+interval (much less than 1 second), or system activity that prevents
+turbostat from being able to run on all CPUS to quickly collect data.
+
 The APERF, MPERF MSRs are defined to count non-halted cycles.
 Although it is not guaranteed by the architecture, turbostat assumes
 that they count at TSC rate, which is true on all processors tested to date.
diff --git a/tools/power/x86/turbostat/turbostat.c b/tools/power/x86/turbostat/turbostat.c
index 861d77190206..2655ae9a3ad8 100644
--- a/tools/power/x86/turbostat/turbostat.c
+++ b/tools/power/x86/turbostat/turbostat.c
@@ -35,9 +35,9 @@
 #include <ctype.h>
 #include <sched.h>
 
-#define MSR_TSC	0x10
 #define MSR_NEHALEM_PLATFORM_INFO	0xCE
 #define MSR_NEHALEM_TURBO_RATIO_LIMIT	0x1AD
+#define MSR_IVT_TURBO_RATIO_LIMIT	0x1AE
 #define MSR_APERF	0xE8
 #define MSR_MPERF	0xE7
 #define MSR_PKG_C2_RESIDENCY	0x60D	/* SNB only */
@@ -62,7 +62,11 @@ unsigned int genuine_intel;
 unsigned int has_invariant_tsc;
 unsigned int do_nehalem_platform_info;
 unsigned int do_nehalem_turbo_ratio_limit;
-unsigned int extra_msr_offset;
+unsigned int do_ivt_turbo_ratio_limit;
+unsigned int extra_msr_offset32;
+unsigned int extra_msr_offset64;
+unsigned int extra_delta_offset32;
+unsigned int extra_delta_offset64;
 double bclk;
 unsigned int show_pkg;
 unsigned int show_core;
@@ -83,7 +87,10 @@ struct thread_data {
 	unsigned long long aperf;
 	unsigned long long mperf;
 	unsigned long long c1;	/* derived */
-	unsigned long long extra_msr;
+	unsigned long long extra_msr64;
+	unsigned long long extra_delta64;
+	unsigned long long extra_msr32;
+	unsigned long long extra_delta32;
 	unsigned int cpu_id;
 	unsigned int flags;
 #define CPU_IS_FIRST_THREAD_IN_CORE	0x2
@@ -222,6 +229,14 @@ void print_header(void)
 	if (has_aperf)
 		outp += sprintf(outp, "  GHz");
 	outp += sprintf(outp, "  TSC");
+	if (extra_delta_offset32)
+		outp += sprintf(outp, "  count 0x%03X", extra_delta_offset32);
+	if (extra_delta_offset64)
+		outp += sprintf(outp, "  COUNT 0x%03X", extra_delta_offset64);
+	if (extra_msr_offset32)
+		outp += sprintf(outp, "   MSR 0x%03X", extra_msr_offset32);
+	if (extra_msr_offset64)
+		outp += sprintf(outp, "           MSR 0x%03X", extra_msr_offset64);
 	if (do_nhm_cstates)
 		outp += sprintf(outp, "    %%c1");
 	if (do_nhm_cstates)
@@ -238,8 +253,6 @@ void print_header(void)
 		outp += sprintf(outp, "   %%pc6");
 	if (do_snb_cstates)
 		outp += sprintf(outp, "   %%pc7");
-	if (extra_msr_offset)
-		outp += sprintf(outp, "        MSR 0x%x ", extra_msr_offset);
 
 	outp += sprintf(outp, "\n");
 }
@@ -255,8 +268,14 @@ int dump_counters(struct thread_data *t, struct core_data *c,
 		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",
+			extra_delta_offset32, t->extra_delta32);
 		fprintf(stderr, "msr0x%x: %016llX\n",
-			extra_msr_offset, t->extra_msr);
+			extra_delta_offset64, t->extra_delta64);
+		fprintf(stderr, "msr0x%x: %08llX\n",
+			extra_msr_offset32, t->extra_msr32);
+		fprintf(stderr, "msr0x%x: %016llX\n",
+			extra_msr_offset64, t->extra_msr64);
 	}
 
 	if (c) {
@@ -360,6 +379,21 @@ int format_counters(struct thread_data *t, struct core_data *c,
 	/* TSC */
 	outp += sprintf(outp, "%5.2f", 1.0 * t->tsc/units/interval_float);
 
+	/* delta */
+	if (extra_delta_offset32)
+		outp += sprintf(outp, "  %11llu", t->extra_delta32);
+
+	/* DELTA */
+	if (extra_delta_offset64)
+		outp += sprintf(outp, "  %11llu", t->extra_delta64);
+	/* msr */
+	if (extra_msr_offset32)
+		outp += sprintf(outp, "  0x%08llx", t->extra_msr32);
+
+	/* MSR */
+	if (extra_msr_offset64)
+		outp += sprintf(outp, "  0x%016llx", t->extra_msr64);
+
 	if (do_nhm_cstates) {
 		if (!skip_c1)
 			outp += sprintf(outp, " %6.2f", 100.0 * t->c1/t->tsc);
@@ -391,8 +425,6 @@ int format_counters(struct thread_data *t, struct core_data *c,
 	if (do_snb_cstates)
 		outp += sprintf(outp, " %6.2f", 100.0 * p->pc7/t->tsc);
 done:
-	if (extra_msr_offset)
-		outp += sprintf(outp, "  0x%016llx", t->extra_msr);
 	outp += sprintf(outp, "\n");
 
 	return 0;
@@ -502,10 +534,16 @@ delta_thread(struct thread_data *new, struct thread_data *old,
 		old->mperf = 1;	/* divide by 0 protection */
 	}
 
+	old->extra_delta32 = new->extra_delta32 - old->extra_delta32;
+	old->extra_delta32 &= 0xFFFFFFFF;
+
+	old->extra_delta64 = new->extra_delta64 - old->extra_delta64;
+
 	/*
-	 * for "extra msr", just copy the latest w/o subtracting
+	 * Extra MSR is just a snapshot, simply copy latest w/o subtracting
 	 */
-	old->extra_msr = new->extra_msr;
+	old->extra_msr32 = new->extra_msr32;
+	old->extra_msr64 = new->extra_msr64;
 }
 
 int delta_cpu(struct thread_data *t, struct core_data *c,
@@ -533,6 +571,9 @@ void clear_counters(struct thread_data *t, struct core_data *c, struct pkg_data
 	t->mperf = 0;
 	t->c1 = 0;
 
+	t->extra_delta32 = 0;
+	t->extra_delta64 = 0;
+
 	/* tells format_counters to dump all fields from this set */
 	t->flags = CPU_IS_FIRST_THREAD_IN_CORE | CPU_IS_FIRST_CORE_IN_PACKAGE;
 
@@ -553,6 +594,9 @@ int sum_counters(struct thread_data *t, struct core_data *c,
 	average.threads.mperf += t->mperf;
 	average.threads.c1 += t->c1;
 
+	average.threads.extra_delta32 += t->extra_delta32;
+	average.threads.extra_delta64 += t->extra_delta64;
+
 	/* sum per-core values only for 1st thread in core */
 	if (!(t->flags & CPU_IS_FIRST_THREAD_IN_CORE))
 		return 0;
@@ -588,6 +632,11 @@ void compute_average(struct thread_data *t, struct core_data *c,
 	average.threads.mperf /= topo.num_cpus;
 	average.threads.c1 /= topo.num_cpus;
 
+	average.threads.extra_delta32 /= topo.num_cpus;
+	average.threads.extra_delta32 &= 0xFFFFFFFF;
+
+	average.threads.extra_delta64 /= topo.num_cpus;
+
 	average.cores.c3 /= topo.num_cores;
 	average.cores.c6 /= topo.num_cores;
 	average.cores.c7 /= topo.num_cores;
@@ -629,8 +678,24 @@ int get_counters(struct thread_data *t, struct core_data *c, struct pkg_data *p)
 			return -4;
 	}
 
-	if (extra_msr_offset)
-		if (get_msr(cpu, extra_msr_offset, &t->extra_msr))
+	if (extra_delta_offset32) {
+		if (get_msr(cpu, extra_delta_offset32, &t->extra_delta32))
+			return -5;
+		t->extra_delta32 &= 0xFFFFFFFF;
+	}
+
+	if (extra_delta_offset64)
+		if (get_msr(cpu, extra_delta_offset64, &t->extra_delta64))
+			return -5;
+
+	if (extra_msr_offset32) {
+		if (get_msr(cpu, extra_msr_offset32, &t->extra_msr32))
+			return -5;
+		t->extra_msr32 &= 0xFFFFFFFF;
+	}
+
+	if (extra_msr_offset64)
+		if (get_msr(cpu, extra_msr_offset64, &t->extra_msr64))
 			return -5;
 
 	/* collect core counters only for 1st thread in core */
@@ -677,6 +742,9 @@ void print_verbose_header(void)
 
 	get_msr(0, MSR_NEHALEM_PLATFORM_INFO, &msr);
 
+	if (verbose > 1)
+		fprintf(stderr, "MSR_NEHALEM_PLATFORM_INFO: 0x%llx\n", msr);
+
 	ratio = (msr >> 40) & 0xFF;
 	fprintf(stderr, "%d * %.0f = %.0f MHz max efficiency\n",
 		ratio, bclk, ratio * bclk);
@@ -685,14 +753,84 @@ void print_verbose_header(void)
 	fprintf(stderr, "%d * %.0f = %.0f MHz TSC frequency\n",
 		ratio, bclk, ratio * bclk);
 
+	if (!do_ivt_turbo_ratio_limit)
+		goto print_nhm_turbo_ratio_limits;
+
+	get_msr(0, MSR_IVT_TURBO_RATIO_LIMIT, &msr);
+
 	if (verbose > 1)
-		fprintf(stderr, "MSR_NEHALEM_PLATFORM_INFO: 0x%llx\n", msr);
+		fprintf(stderr, "MSR_IVT_TURBO_RATIO_LIMIT: 0x%llx\n", msr);
+
+	ratio = (msr >> 56) & 0xFF;
+	if (ratio)
+		fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 16 active cores\n",
+			ratio, bclk, ratio * bclk);
+
+	ratio = (msr >> 48) & 0xFF;
+	if (ratio)
+		fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 15 active cores\n",
+			ratio, bclk, ratio * bclk);
+
+	ratio = (msr >> 40) & 0xFF;
+	if (ratio)
+		fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 14 active cores\n",
+			ratio, bclk, ratio * bclk);
+
+	ratio = (msr >> 32) & 0xFF;
+	if (ratio)
+		fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 13 active cores\n",
+			ratio, bclk, ratio * bclk);
+
+	ratio = (msr >> 24) & 0xFF;
+	if (ratio)
+		fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 12 active cores\n",
+			ratio, bclk, ratio * bclk);
+
+	ratio = (msr >> 16) & 0xFF;
+	if (ratio)
+		fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 11 active cores\n",
+			ratio, bclk, ratio * bclk);
+
+	ratio = (msr >> 8) & 0xFF;
+	if (ratio)
+		fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 10 active cores\n",
+			ratio, bclk, ratio * bclk);
+
+	ratio = (msr >> 0) & 0xFF;
+	if (ratio)
+		fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 9 active cores\n",
+			ratio, bclk, ratio * bclk);
+
+print_nhm_turbo_ratio_limits:
 
 	if (!do_nehalem_turbo_ratio_limit)
 		return;
 
 	get_msr(0, MSR_NEHALEM_TURBO_RATIO_LIMIT, &msr);
 
+	if (verbose > 1)
+		fprintf(stderr, "MSR_NEHALEM_TURBO_RATIO_LIMIT: 0x%llx\n", msr);
+
+	ratio = (msr >> 56) & 0xFF;
+	if (ratio)
+		fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 8 active cores\n",
+			ratio, bclk, ratio * bclk);
+
+	ratio = (msr >> 48) & 0xFF;
+	if (ratio)
+		fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 7 active cores\n",
+			ratio, bclk, ratio * bclk);
+
+	ratio = (msr >> 40) & 0xFF;
+	if (ratio)
+		fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 6 active cores\n",
+			ratio, bclk, ratio * bclk);
+
+	ratio = (msr >> 32) & 0xFF;
+	if (ratio)
+		fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 5 active cores\n",
+			ratio, bclk, ratio * bclk);
+
 	ratio = (msr >> 24) & 0xFF;
 	if (ratio)
 		fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 4 active cores\n",
@@ -712,7 +850,6 @@ void print_verbose_header(void)
 	if (ratio)
 		fprintf(stderr, "%d * %.0f = %.0f MHz max turbo 1 active cores\n",
 			ratio, bclk, ratio * bclk);
-
 }
 
 void free_all_buffers(void)
@@ -1038,7 +1175,7 @@ int has_nehalem_turbo_ratio_limit(unsigned int family, unsigned int model)
 	case 0x2A:	/* SNB */
 	case 0x2D:	/* SNB Xeon */
 	case 0x3A:	/* IVB */
-	case 0x3D:	/* IVB Xeon */
+	case 0x3E:	/* IVB Xeon */
 		return 1;
 	case 0x2E:	/* Nehalem-EX Xeon - Beckton */
 	case 0x2F:	/* Westmere-EX Xeon - Eagleton */
@@ -1046,6 +1183,22 @@ int has_nehalem_turbo_ratio_limit(unsigned int family, unsigned int model)
 		return 0;
 	}
 }
+int has_ivt_turbo_ratio_limit(unsigned int family, unsigned int model)
+{
+	if (!genuine_intel)
+		return 0;
+
+	if (family != 6)
+		return 0;
+
+	switch (model) {
+	case 0x3E:	/* IVB Xeon */
+		return 1;
+	default:
+		return 0;
+	}
+}
+
 
 int is_snb(unsigned int family, unsigned int model)
 {
@@ -1056,7 +1209,7 @@ int is_snb(unsigned int family, unsigned int model)
 	case 0x2A:
 	case 0x2D:
 	case 0x3A:	/* IVB */
-	case 0x3D:	/* IVB Xeon */
+	case 0x3E:	/* IVB Xeon */
 		return 1;
 	}
 	return 0;
@@ -1145,12 +1298,13 @@ void check_cpuid()
 	bclk = discover_bclk(family, model);
 
 	do_nehalem_turbo_ratio_limit = has_nehalem_turbo_ratio_limit(family, model);
+	do_ivt_turbo_ratio_limit = has_ivt_turbo_ratio_limit(family, model);
 }
 
 
 void usage()
 {
-	fprintf(stderr, "%s: [-v] [-M MSR#] [-i interval_sec | command ...]\n",
+	fprintf(stderr, "%s: [-v][-p|-P|-S][-c MSR# | -s]][-C MSR#][-m MSR#][-M MSR#][-i interval_sec | command ...]\n",
 		progname);
 	exit(1);
 }
@@ -1440,15 +1594,15 @@ void cmdline(int argc, char **argv)
 
 	progname = argv[0];
 
-	while ((opt = getopt(argc, argv, "+cpsvi:M:")) != -1) {
+	while ((opt = getopt(argc, argv, "+pPSvisc:sC:m:M:")) != -1) {
 		switch (opt) {
-		case 'c':
+		case 'p':
 			show_core_only++;
 			break;
-		case 'p':
+		case 'P':
 			show_pkg_only++;
 			break;
-		case 's':
+		case 'S':
 			summary_only++;
 			break;
 		case 'v':
@@ -1457,10 +1611,20 @@ void cmdline(int argc, char **argv)
 		case 'i':
 			interval_sec = atoi(optarg);
 			break;
+		case 'c':
+			sscanf(optarg, "%x", &extra_delta_offset32);
+			break;
+		case 's':
+			extra_delta_offset32 = 0x34;	/* SMI counter */
+			break;
+		case 'C':
+			sscanf(optarg, "%x", &extra_delta_offset64);
+			break;
+		case 'm':
+			sscanf(optarg, "%x", &extra_msr_offset32);
+			break;
 		case 'M':
-			sscanf(optarg, "%x", &extra_msr_offset);
-			if (verbose > 1)
-				fprintf(stderr, "MSR 0x%X\n", extra_msr_offset);
+			sscanf(optarg, "%x", &extra_msr_offset64);
 			break;
 		default:
 			usage();
@@ -1473,7 +1637,7 @@ int main(int argc, char **argv)
 	cmdline(argc, argv);
 
 	if (verbose > 1)
-		fprintf(stderr, "turbostat v2.0 May 16, 2012"
+		fprintf(stderr, "turbostat v2.1 October 6, 2012"
 			" - Len Brown <lenb@kernel.org>\n");
 
 	turbostat_init();