Update Linux to v5.4.2

Change-Id: Idf6911045d9d382da2cfe01b1edff026404ac8fd
diff --git a/tools/power/acpi/.gitignore b/tools/power/acpi/.gitignore
index cba3d99..f698a0e 100644
--- a/tools/power/acpi/.gitignore
+++ b/tools/power/acpi/.gitignore
@@ -1,4 +1,4 @@
-acpidbg
-acpidump
-ec
-include
+/acpidbg
+/acpidump
+/ec
+/include/
diff --git a/tools/power/acpi/Makefile b/tools/power/acpi/Makefile
index a8bf908..ebd3e1a 100644
--- a/tools/power/acpi/Makefile
+++ b/tools/power/acpi/Makefile
@@ -1,12 +1,9 @@
+# SPDX-License-Identifier: GPL-2.0-only
 # 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.
 
 include ../../scripts/Makefile.include
 
diff --git a/tools/power/acpi/Makefile.config b/tools/power/acpi/Makefile.config
index f304be7..0111d24 100644
--- a/tools/power/acpi/Makefile.config
+++ b/tools/power/acpi/Makefile.config
@@ -1,12 +1,9 @@
+# SPDX-License-Identifier: GPL-2.0-only
 # tools/power/acpi/Makefile.config - ACPI tool Makefile
 #
 # Copyright (c) 2015, 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.
 
 ifeq ($(srctree),)
 srctree := $(patsubst %/,%,$(dir $(shell pwd)))
diff --git a/tools/power/acpi/Makefile.rules b/tools/power/acpi/Makefile.rules
index 3737383..2a6c170 100644
--- a/tools/power/acpi/Makefile.rules
+++ b/tools/power/acpi/Makefile.rules
@@ -1,12 +1,9 @@
+# SPDX-License-Identifier: GPL-2.0-only
 # tools/power/acpi/Makefile.rules - ACPI tool Makefile
 #
 # Copyright (c) 2015, 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.
 
 objdir := $(OUTPUT)tools/$(TOOL)/
 toolobjs := $(addprefix $(objdir),$(TOOL_OBJS))
diff --git a/tools/power/acpi/common/cmfsize.c b/tools/power/acpi/common/cmfsize.c
index ff8025d..28c11c6 100644
--- a/tools/power/acpi/common/cmfsize.c
+++ b/tools/power/acpi/common/cmfsize.c
@@ -3,7 +3,7 @@
  *
  * Module Name: cfsize - Common get file size function
  *
- * Copyright (C) 2000 - 2018, Intel Corp.
+ * Copyright (C) 2000 - 2019, Intel Corp.
  *
  *****************************************************************************/
 
diff --git a/tools/power/acpi/common/getopt.c b/tools/power/acpi/common/getopt.c
index 7be89b8..6b41d8b 100644
--- a/tools/power/acpi/common/getopt.c
+++ b/tools/power/acpi/common/getopt.c
@@ -3,7 +3,7 @@
  *
  * Module Name: getopt
  *
- * Copyright (C) 2000 - 2018, Intel Corp.
+ * Copyright (C) 2000 - 2019, Intel Corp.
  *
  *****************************************************************************/
 
diff --git a/tools/power/acpi/os_specific/service_layers/oslinuxtbl.c b/tools/power/acpi/os_specific/service_layers/oslinuxtbl.c
index a20c703..d1f3d44 100644
--- a/tools/power/acpi/os_specific/service_layers/oslinuxtbl.c
+++ b/tools/power/acpi/os_specific/service_layers/oslinuxtbl.c
@@ -3,7 +3,7 @@
  *
  * Module Name: oslinuxtbl - Linux OSL for obtaining ACPI tables
  *
- * Copyright (C) 2000 - 2018, Intel Corp.
+ * Copyright (C) 2000 - 2019, Intel Corp.
  *
  *****************************************************************************/
 
@@ -19,7 +19,7 @@
 typedef struct osl_table_info {
 	struct osl_table_info *next;
 	u32 instance;
-	char signature[ACPI_NAME_SIZE];
+	char signature[ACPI_NAMESEG_SIZE];
 
 } osl_table_info;
 
@@ -286,14 +286,14 @@
 		return (AE_NO_MEMORY);
 	}
 
-	ACPI_MOVE_NAME(new_info->signature, signature);
+	ACPI_COPY_NAMESEG(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 (ACPI_COMPARE_NAMESEG(next->signature, signature)) {
 				if (next->instance == instance) {
 					found = TRUE;
 				}
@@ -782,11 +782,11 @@
 
 	/* 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 (ACPI_COMPARE_NAMESEG(signature, ACPI_RSDP_NAME) ||
+	    ACPI_COMPARE_NAMESEG(signature, ACPI_SIG_RSDT) ||
+	    ACPI_COMPARE_NAMESEG(signature, ACPI_SIG_XSDT) ||
+	    ACPI_COMPARE_NAMESEG(signature, ACPI_SIG_DSDT) ||
+	    ACPI_COMPARE_NAMESEG(signature, ACPI_SIG_FACS)) {
 
 find_next_instance:
 
@@ -797,7 +797,7 @@
 		 * 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 (ACPI_COMPARE_NAMESEG(signature, ACPI_SIG_DSDT)) {
 			if (current_instance < 2) {
 				if ((gbl_fadt->header.length >=
 				     MIN_FADT_FOR_XDSDT) && gbl_fadt->Xdsdt
@@ -815,7 +815,7 @@
 					    dsdt;
 				}
 			}
-		} else if (ACPI_COMPARE_NAME(signature, ACPI_SIG_FACS)) {
+		} else if (ACPI_COMPARE_NAMESEG(signature, ACPI_SIG_FACS)) {
 			if (current_instance < 2) {
 				if ((gbl_fadt->header.length >=
 				     MIN_FADT_FOR_XFACS) && gbl_fadt->Xfacs
@@ -833,7 +833,7 @@
 					    facs;
 				}
 			}
-		} else if (ACPI_COMPARE_NAME(signature, ACPI_SIG_XSDT)) {
+		} else if (ACPI_COMPARE_NAMESEG(signature, ACPI_SIG_XSDT)) {
 			if (!gbl_revision) {
 				return (AE_BAD_SIGNATURE);
 			}
@@ -842,7 +842,7 @@
 				    (acpi_physical_address)gbl_rsdp.
 				    xsdt_physical_address;
 			}
-		} else if (ACPI_COMPARE_NAME(signature, ACPI_SIG_RSDT)) {
+		} else if (ACPI_COMPARE_NAMESEG(signature, ACPI_SIG_RSDT)) {
 			if (current_instance == 0) {
 				table_address =
 				    (acpi_physical_address)gbl_rsdp.
@@ -931,7 +931,7 @@
 
 			/* Does this table match the requested signature? */
 
-			if (!ACPI_COMPARE_NAME
+			if (!ACPI_COMPARE_NAMESEG
 			    (mapped_table->signature, signature)) {
 				osl_unmap_table(mapped_table);
 				mapped_table = NULL;
@@ -995,7 +995,7 @@
 {
 	void *table_dir;
 	u32 instance;
-	char temp_name[ACPI_NAME_SIZE];
+	char temp_name[ACPI_NAMESEG_SIZE];
 	char *filename;
 	acpi_status status = AE_OK;
 
@@ -1086,8 +1086,8 @@
 				return (AE_BAD_SIGNATURE);
 			}
 		} else
-		    if (!ACPI_COMPARE_NAME(signature, mapped_table->signature))
-		{
+		    if (!ACPI_COMPARE_NAMESEG
+			(signature, mapped_table->signature)) {
 			acpi_os_unmap_memory(mapped_table,
 					     sizeof(struct acpi_table_header));
 			return (AE_BAD_SIGNATURE);
@@ -1158,15 +1158,15 @@
 
 	/* Ignore meaningless files */
 
-	if (strlen(filename) < ACPI_NAME_SIZE) {
+	if (strlen(filename) < ACPI_NAMESEG_SIZE) {
 		return (AE_BAD_SIGNATURE);
 	}
 
 	/* Extract instance number */
 
-	if (isdigit((int)filename[ACPI_NAME_SIZE])) {
-		sscanf(&filename[ACPI_NAME_SIZE], "%u", instance);
-	} else if (strlen(filename) != ACPI_NAME_SIZE) {
+	if (isdigit((int)filename[ACPI_NAMESEG_SIZE])) {
+		sscanf(&filename[ACPI_NAMESEG_SIZE], "%u", instance);
+	} else if (strlen(filename) != ACPI_NAMESEG_SIZE) {
 		return (AE_BAD_SIGNATURE);
 	} else {
 		*instance = 0;
@@ -1174,7 +1174,7 @@
 
 	/* Extract signature */
 
-	ACPI_MOVE_NAME(signature, filename);
+	ACPI_COPY_NAMESEG(signature, filename);
 	return (AE_OK);
 }
 
@@ -1236,7 +1236,7 @@
 				status = AE_BAD_SIGNATURE;
 				goto exit;
 			}
-		} else if (!ACPI_COMPARE_NAME(signature, header.signature)) {
+		} else if (!ACPI_COMPARE_NAMESEG(signature, header.signature)) {
 			fprintf(stderr,
 				"Incorrect signature: Expecting %4.4s, found %4.4s\n",
 				signature, header.signature);
@@ -1311,7 +1311,7 @@
 {
 	void *table_dir;
 	u32 current_instance = 0;
-	char temp_name[ACPI_NAME_SIZE];
+	char temp_name[ACPI_NAMESEG_SIZE];
 	char table_filename[PATH_MAX];
 	char *filename;
 	acpi_status status;
@@ -1329,7 +1329,7 @@
 
 		/* Ignore meaningless files */
 
-		if (!ACPI_COMPARE_NAME(filename, signature)) {
+		if (!ACPI_COMPARE_NAMESEG(filename, signature)) {
 			continue;
 		}
 
diff --git a/tools/power/acpi/os_specific/service_layers/osunixdir.c b/tools/power/acpi/os_specific/service_layers/osunixdir.c
index 4fd44e2..30913f1 100644
--- a/tools/power/acpi/os_specific/service_layers/osunixdir.c
+++ b/tools/power/acpi/os_specific/service_layers/osunixdir.c
@@ -3,7 +3,7 @@
  *
  * Module Name: osunixdir - Unix directory access interfaces
  *
- * Copyright (C) 2000 - 2018, Intel Corp.
+ * Copyright (C) 2000 - 2019, Intel Corp.
  *
  *****************************************************************************/
 
diff --git a/tools/power/acpi/os_specific/service_layers/osunixmap.c b/tools/power/acpi/os_specific/service_layers/osunixmap.c
index 93d8359..29dfb47 100644
--- a/tools/power/acpi/os_specific/service_layers/osunixmap.c
+++ b/tools/power/acpi/os_specific/service_layers/osunixmap.c
@@ -3,7 +3,7 @@
  *
  * Module Name: osunixmap - Unix OSL for file mappings
  *
- * Copyright (C) 2000 - 2018, Intel Corp.
+ * Copyright (C) 2000 - 2019, Intel Corp.
  *
  *****************************************************************************/
 
diff --git a/tools/power/acpi/os_specific/service_layers/osunixxf.c b/tools/power/acpi/os_specific/service_layers/osunixxf.c
index 8a88e87..83d3b3b 100644
--- a/tools/power/acpi/os_specific/service_layers/osunixxf.c
+++ b/tools/power/acpi/os_specific/service_layers/osunixxf.c
@@ -3,7 +3,7 @@
  *
  * Module Name: osunixxf - UNIX OSL interfaces
  *
- * Copyright (C) 2000 - 2018, Intel Corp.
+ * Copyright (C) 2000 - 2019, Intel Corp.
  *
  *****************************************************************************/
 
diff --git a/tools/power/acpi/tools/acpidbg/Makefile b/tools/power/acpi/tools/acpidbg/Makefile
new file mode 100644
index 0000000..2ce0ee5
--- /dev/null
+++ b/tools/power/acpi/tools/acpidbg/Makefile
@@ -0,0 +1,22 @@
+# SPDX-License-Identifier: GPL-2.0-only
+# tools/power/acpi/tools/acpidbg/Makefile - ACPI tool Makefile
+#
+# Copyright (c) 2015, Intel Corporation
+#   Author: Lv Zheng <lv.zheng@intel.com>
+#
+
+include ../../Makefile.config
+
+TOOL = acpidbg
+vpath %.c \
+	../../../../../drivers/acpi/acpica\
+	../../common\
+	../../os_specific/service_layers\
+	.
+CFLAGS += -DACPI_APPLICATION -DACPI_SINGLE_THREAD -DACPI_DEBUGGER\
+	-I.
+LDFLAGS += -lpthread
+TOOL_OBJS = \
+	acpidbg.o
+
+include ../../Makefile.rules
diff --git a/tools/power/acpi/tools/acpidbg/acpidbg.c b/tools/power/acpi/tools/acpidbg/acpidbg.c
new file mode 100644
index 0000000..3d2bfd7
--- /dev/null
+++ b/tools/power/acpi/tools/acpidbg/acpidbg.c
@@ -0,0 +1,441 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * ACPI AML interfacing userspace utility
+ *
+ * Copyright (C) 2015, Intel Corporation
+ * Authors: Lv Zheng <lv.zheng@intel.com>
+ */
+
+#include <acpi/acpi.h>
+
+/* Headers not included by include/acpi/platform/aclinux.h */
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <error.h>
+#include <stdbool.h>
+#include <fcntl.h>
+#include <assert.h>
+#include <sys/select.h>
+#include "../../../../../include/linux/circ_buf.h"
+
+#define ACPI_AML_FILE		"/sys/kernel/debug/acpi/acpidbg"
+#define ACPI_AML_SEC_TICK	1
+#define ACPI_AML_USEC_PEEK	200
+#define ACPI_AML_BUF_SIZE	4096
+
+#define ACPI_AML_BATCH_WRITE_CMD	0x00 /* Write command to kernel */
+#define ACPI_AML_BATCH_READ_LOG		0x01 /* Read log from kernel */
+#define ACPI_AML_BATCH_WRITE_LOG	0x02 /* Write log to console */
+
+#define ACPI_AML_LOG_START		0x00
+#define ACPI_AML_PROMPT_START		0x01
+#define ACPI_AML_PROMPT_STOP		0x02
+#define ACPI_AML_LOG_STOP		0x03
+#define ACPI_AML_PROMPT_ROLL		0x04
+
+#define ACPI_AML_INTERACTIVE	0x00
+#define ACPI_AML_BATCH		0x01
+
+#define circ_count(circ) \
+	(CIRC_CNT((circ)->head, (circ)->tail, ACPI_AML_BUF_SIZE))
+#define circ_count_to_end(circ) \
+	(CIRC_CNT_TO_END((circ)->head, (circ)->tail, ACPI_AML_BUF_SIZE))
+#define circ_space(circ) \
+	(CIRC_SPACE((circ)->head, (circ)->tail, ACPI_AML_BUF_SIZE))
+#define circ_space_to_end(circ) \
+	(CIRC_SPACE_TO_END((circ)->head, (circ)->tail, ACPI_AML_BUF_SIZE))
+
+#define acpi_aml_cmd_count()	circ_count(&acpi_aml_cmd_crc)
+#define acpi_aml_log_count()	circ_count(&acpi_aml_log_crc)
+#define acpi_aml_cmd_space()	circ_space(&acpi_aml_cmd_crc)
+#define acpi_aml_log_space()	circ_space(&acpi_aml_log_crc)
+
+#define ACPI_AML_DO(_fd, _op, _buf, _ret)				\
+	do {								\
+		_ret = acpi_aml_##_op(_fd, &acpi_aml_##_buf##_crc);	\
+		if (_ret == 0) {					\
+			fprintf(stderr,					\
+				"%s %s pipe closed.\n", #_buf, #_op);	\
+			return;						\
+		}							\
+	} while (0)
+#define ACPI_AML_BATCH_DO(_fd, _op, _buf, _ret)				\
+	do {								\
+		_ret = acpi_aml_##_op##_batch_##_buf(_fd,		\
+			 &acpi_aml_##_buf##_crc);			\
+		if (_ret == 0)						\
+			return;						\
+	} while (0)
+
+
+static char acpi_aml_cmd_buf[ACPI_AML_BUF_SIZE];
+static char acpi_aml_log_buf[ACPI_AML_BUF_SIZE];
+static struct circ_buf acpi_aml_cmd_crc = {
+	.buf = acpi_aml_cmd_buf,
+	.head = 0,
+	.tail = 0,
+};
+static struct circ_buf acpi_aml_log_crc = {
+	.buf = acpi_aml_log_buf,
+	.head = 0,
+	.tail = 0,
+};
+static const char *acpi_aml_file_path = ACPI_AML_FILE;
+static unsigned long acpi_aml_mode = ACPI_AML_INTERACTIVE;
+static bool acpi_aml_exit;
+
+static bool acpi_aml_batch_drain;
+static unsigned long acpi_aml_batch_state;
+static char acpi_aml_batch_prompt;
+static char acpi_aml_batch_roll;
+static unsigned long acpi_aml_log_state;
+static char *acpi_aml_batch_cmd = NULL;
+static char *acpi_aml_batch_pos = NULL;
+
+static int acpi_aml_set_fl(int fd, int flags)
+{
+	int ret;
+
+	ret = fcntl(fd, F_GETFL, 0);
+	if (ret < 0) {
+		perror("fcntl(F_GETFL)");
+		return ret;
+	}
+	flags |= ret;
+	ret = fcntl(fd, F_SETFL, flags);
+	if (ret < 0) {
+		perror("fcntl(F_SETFL)");
+		return ret;
+	}
+	return ret;
+}
+
+static int acpi_aml_set_fd(int fd, int maxfd, fd_set *set)
+{
+	if (fd > maxfd)
+		maxfd = fd;
+	FD_SET(fd, set);
+	return maxfd;
+}
+
+static int acpi_aml_read(int fd, struct circ_buf *crc)
+{
+	char *p;
+	int len;
+
+	p = &crc->buf[crc->head];
+	len = circ_space_to_end(crc);
+	len = read(fd, p, len);
+	if (len < 0)
+		perror("read");
+	else if (len > 0)
+		crc->head = (crc->head + len) & (ACPI_AML_BUF_SIZE - 1);
+	return len;
+}
+
+static int acpi_aml_read_batch_cmd(int unused, struct circ_buf *crc)
+{
+	char *p;
+	int len;
+	int remained = strlen(acpi_aml_batch_pos);
+
+	p = &crc->buf[crc->head];
+	len = circ_space_to_end(crc);
+	if (len > remained) {
+		memcpy(p, acpi_aml_batch_pos, remained);
+		acpi_aml_batch_pos += remained;
+		len = remained;
+	} else {
+		memcpy(p, acpi_aml_batch_pos, len);
+		acpi_aml_batch_pos += len;
+	}
+	if (len > 0)
+		crc->head = (crc->head + len) & (ACPI_AML_BUF_SIZE - 1);
+	return len;
+}
+
+static int acpi_aml_read_batch_log(int fd, struct circ_buf *crc)
+{
+	char *p;
+	int len;
+	int ret = 0;
+
+	p = &crc->buf[crc->head];
+	len = circ_space_to_end(crc);
+	while (ret < len && acpi_aml_log_state != ACPI_AML_LOG_STOP) {
+		if (acpi_aml_log_state == ACPI_AML_PROMPT_ROLL) {
+			*p = acpi_aml_batch_roll;
+			len = 1;
+			crc->head = (crc->head + 1) & (ACPI_AML_BUF_SIZE - 1);
+			ret += 1;
+			acpi_aml_log_state = ACPI_AML_LOG_START;
+		} else {
+			len = read(fd, p, 1);
+			if (len <= 0) {
+				if (len < 0)
+					perror("read");
+				ret = len;
+				break;
+			}
+		}
+		switch (acpi_aml_log_state) {
+		case ACPI_AML_LOG_START:
+			if (*p == '\n')
+				acpi_aml_log_state = ACPI_AML_PROMPT_START;
+			crc->head = (crc->head + 1) & (ACPI_AML_BUF_SIZE - 1);
+			ret += 1;
+			break;
+		case ACPI_AML_PROMPT_START:
+			if (*p == ACPI_DEBUGGER_COMMAND_PROMPT ||
+			    *p == ACPI_DEBUGGER_EXECUTE_PROMPT) {
+				acpi_aml_batch_prompt = *p;
+				acpi_aml_log_state = ACPI_AML_PROMPT_STOP;
+			} else {
+				if (*p != '\n')
+					acpi_aml_log_state = ACPI_AML_LOG_START;
+				crc->head = (crc->head + 1) & (ACPI_AML_BUF_SIZE - 1);
+				ret += 1;
+			}
+			break;
+		case ACPI_AML_PROMPT_STOP:
+			if (*p == ' ') {
+				acpi_aml_log_state = ACPI_AML_LOG_STOP;
+				acpi_aml_exit = true;
+			} else {
+				/* Roll back */
+				acpi_aml_log_state = ACPI_AML_PROMPT_ROLL;
+				acpi_aml_batch_roll = *p;
+				*p = acpi_aml_batch_prompt;
+				crc->head = (crc->head + 1) & (ACPI_AML_BUF_SIZE - 1);
+				ret += 1;
+			}
+			break;
+		default:
+			assert(0);
+			break;
+		}
+	}
+	return ret;
+}
+
+static int acpi_aml_write(int fd, struct circ_buf *crc)
+{
+	char *p;
+	int len;
+
+	p = &crc->buf[crc->tail];
+	len = circ_count_to_end(crc);
+	len = write(fd, p, len);
+	if (len < 0)
+		perror("write");
+	else if (len > 0)
+		crc->tail = (crc->tail + len) & (ACPI_AML_BUF_SIZE - 1);
+	return len;
+}
+
+static int acpi_aml_write_batch_log(int fd, struct circ_buf *crc)
+{
+	char *p;
+	int len;
+
+	p = &crc->buf[crc->tail];
+	len = circ_count_to_end(crc);
+	if (!acpi_aml_batch_drain) {
+		len = write(fd, p, len);
+		if (len < 0)
+			perror("write");
+	}
+	if (len > 0)
+		crc->tail = (crc->tail + len) & (ACPI_AML_BUF_SIZE - 1);
+	return len;
+}
+
+static int acpi_aml_write_batch_cmd(int fd, struct circ_buf *crc)
+{
+	int len;
+
+	len = acpi_aml_write(fd, crc);
+	if (circ_count_to_end(crc) == 0)
+		acpi_aml_batch_state = ACPI_AML_BATCH_READ_LOG;
+	return len;
+}
+
+static void acpi_aml_loop(int fd)
+{
+	fd_set rfds;
+	fd_set wfds;
+	struct timeval tv;
+	int ret;
+	int maxfd = 0;
+
+	if (acpi_aml_mode == ACPI_AML_BATCH) {
+		acpi_aml_log_state = ACPI_AML_LOG_START;
+		acpi_aml_batch_pos = acpi_aml_batch_cmd;
+		if (acpi_aml_batch_drain)
+			acpi_aml_batch_state = ACPI_AML_BATCH_READ_LOG;
+		else
+			acpi_aml_batch_state = ACPI_AML_BATCH_WRITE_CMD;
+	}
+	acpi_aml_exit = false;
+	while (!acpi_aml_exit) {
+		tv.tv_sec = ACPI_AML_SEC_TICK;
+		tv.tv_usec = 0;
+		FD_ZERO(&rfds);
+		FD_ZERO(&wfds);
+
+		if (acpi_aml_cmd_space()) {
+			if (acpi_aml_mode == ACPI_AML_INTERACTIVE)
+				maxfd = acpi_aml_set_fd(STDIN_FILENO, maxfd, &rfds);
+			else if (strlen(acpi_aml_batch_pos) &&
+				 acpi_aml_batch_state == ACPI_AML_BATCH_WRITE_CMD)
+				ACPI_AML_BATCH_DO(STDIN_FILENO, read, cmd, ret);
+		}
+		if (acpi_aml_cmd_count() &&
+		    (acpi_aml_mode == ACPI_AML_INTERACTIVE ||
+		     acpi_aml_batch_state == ACPI_AML_BATCH_WRITE_CMD))
+			maxfd = acpi_aml_set_fd(fd, maxfd, &wfds);
+		if (acpi_aml_log_space() &&
+		    (acpi_aml_mode == ACPI_AML_INTERACTIVE ||
+		     acpi_aml_batch_state == ACPI_AML_BATCH_READ_LOG))
+			maxfd = acpi_aml_set_fd(fd, maxfd, &rfds);
+		if (acpi_aml_log_count())
+			maxfd = acpi_aml_set_fd(STDOUT_FILENO, maxfd, &wfds);
+
+		ret = select(maxfd+1, &rfds, &wfds, NULL, &tv);
+		if (ret < 0) {
+			perror("select");
+			break;
+		}
+		if (ret > 0) {
+			if (FD_ISSET(STDIN_FILENO, &rfds))
+				ACPI_AML_DO(STDIN_FILENO, read, cmd, ret);
+			if (FD_ISSET(fd, &wfds)) {
+				if (acpi_aml_mode == ACPI_AML_BATCH)
+					ACPI_AML_BATCH_DO(fd, write, cmd, ret);
+				else
+					ACPI_AML_DO(fd, write, cmd, ret);
+			}
+			if (FD_ISSET(fd, &rfds)) {
+				if (acpi_aml_mode == ACPI_AML_BATCH)
+					ACPI_AML_BATCH_DO(fd, read, log, ret);
+				else
+					ACPI_AML_DO(fd, read, log, ret);
+			}
+			if (FD_ISSET(STDOUT_FILENO, &wfds)) {
+				if (acpi_aml_mode == ACPI_AML_BATCH)
+					ACPI_AML_BATCH_DO(STDOUT_FILENO, write, log, ret);
+				else
+					ACPI_AML_DO(STDOUT_FILENO, write, log, ret);
+			}
+		}
+	}
+}
+
+static bool acpi_aml_readable(int fd)
+{
+	fd_set rfds;
+	struct timeval tv;
+	int ret;
+	int maxfd = 0;
+
+	tv.tv_sec = 0;
+	tv.tv_usec = ACPI_AML_USEC_PEEK;
+	FD_ZERO(&rfds);
+	maxfd = acpi_aml_set_fd(fd, maxfd, &rfds);
+	ret = select(maxfd+1, &rfds, NULL, NULL, &tv);
+	if (ret < 0)
+		perror("select");
+	if (ret > 0 && FD_ISSET(fd, &rfds))
+		return true;
+	return false;
+}
+
+/*
+ * This is a userspace IO flush implementation, replying on the prompt
+ * characters and can be turned into a flush() call after kernel implements
+ * .flush() filesystem operation.
+ */
+static void acpi_aml_flush(int fd)
+{
+	while (acpi_aml_readable(fd)) {
+		acpi_aml_batch_drain = true;
+		acpi_aml_loop(fd);
+		acpi_aml_batch_drain = false;
+	}
+}
+
+void usage(FILE *file, char *progname)
+{
+	fprintf(file, "usage: %s [-b cmd] [-f file] [-h]\n", progname);
+	fprintf(file, "\nOptions:\n");
+	fprintf(file, "  -b     Specify command to be executed in batch mode\n");
+	fprintf(file, "  -f     Specify interface file other than");
+	fprintf(file, "         /sys/kernel/debug/acpi/acpidbg\n");
+	fprintf(file, "  -h     Print this help message\n");
+}
+
+int main(int argc, char **argv)
+{
+	int fd = -1;
+	int ch;
+	int len;
+	int ret = EXIT_SUCCESS;
+
+	while ((ch = getopt(argc, argv, "b:f:h")) != -1) {
+		switch (ch) {
+		case 'b':
+			if (acpi_aml_batch_cmd) {
+				fprintf(stderr, "Already specify %s\n",
+					acpi_aml_batch_cmd);
+				ret = EXIT_FAILURE;
+				goto exit;
+			}
+			len = strlen(optarg);
+			acpi_aml_batch_cmd = calloc(len + 2, 1);
+			if (!acpi_aml_batch_cmd) {
+				perror("calloc");
+				ret = EXIT_FAILURE;
+				goto exit;
+			}
+			memcpy(acpi_aml_batch_cmd, optarg, len);
+			acpi_aml_batch_cmd[len] = '\n';
+			acpi_aml_mode = ACPI_AML_BATCH;
+			break;
+		case 'f':
+			acpi_aml_file_path = optarg;
+			break;
+		case 'h':
+			usage(stdout, argv[0]);
+			goto exit;
+			break;
+		case '?':
+		default:
+			usage(stderr, argv[0]);
+			ret = EXIT_FAILURE;
+			goto exit;
+			break;
+		}
+	}
+
+	fd = open(acpi_aml_file_path, O_RDWR | O_NONBLOCK);
+	if (fd < 0) {
+		perror("open");
+		ret = EXIT_FAILURE;
+		goto exit;
+	}
+	acpi_aml_set_fl(STDIN_FILENO, O_NONBLOCK);
+	acpi_aml_set_fl(STDOUT_FILENO, O_NONBLOCK);
+
+	if (acpi_aml_mode == ACPI_AML_BATCH)
+		acpi_aml_flush(fd);
+	acpi_aml_loop(fd);
+
+exit:
+	if (fd >= 0)
+		close(fd);
+	if (acpi_aml_batch_cmd)
+		free(acpi_aml_batch_cmd);
+	return ret;
+}
diff --git a/tools/power/acpi/tools/acpidump/Makefile b/tools/power/acpi/tools/acpidump/Makefile
new file mode 100644
index 0000000..1208a10
--- /dev/null
+++ b/tools/power/acpi/tools/acpidump/Makefile
@@ -0,0 +1,53 @@
+# SPDX-License-Identifier: GPL-2.0-only
+# tools/power/acpi/tools/acpidump/Makefile - ACPI tool Makefile
+#
+# Copyright (c) 2015, Intel Corporation
+#   Author: Lv Zheng <lv.zheng@intel.com>
+#
+
+include ../../Makefile.config
+
+TOOL = acpidump
+EXTRA_INSTALL = install-man
+EXTRA_UNINSTALL = uninstall-man
+
+vpath %.c \
+	../../../../../drivers/acpi/acpica\
+	./\
+	../../common\
+	../../os_specific/service_layers
+CFLAGS += -DACPI_DUMP_APP -I.
+TOOL_OBJS = \
+	apdump.o\
+	apfiles.o\
+	apmain.o\
+	osunixdir.o\
+	osunixmap.o\
+	osunixxf.o\
+	tbprint.o\
+	tbxfroot.o\
+	utascii.o\
+	utbuffer.o\
+	utdebug.o\
+	utexcep.o\
+	utglobal.o\
+	uthex.o\
+	utmath.o\
+	utnonansi.o\
+	utprint.o\
+	utstring.o\
+	utstrsuppt.o\
+	utstrtoul64.o\
+	utxferror.o\
+	oslinuxtbl.o\
+	cmfsize.o\
+	getopt.o
+
+include ../../Makefile.rules
+
+install-man: $(srctree)/man/acpidump.8
+	$(ECHO) "  INST    " acpidump.8
+	$(QUIET) $(INSTALL_DATA) -D $< $(DESTDIR)$(mandir)/man8/acpidump.8
+uninstall-man:
+	$(ECHO) "  UNINST  " acpidump.8
+	$(QUIET) rm -f $(DESTDIR)$(mandir)/man8/acpidump.8
diff --git a/tools/power/acpi/tools/acpidump/acpidump.h b/tools/power/acpi/tools/acpidump/acpidump.h
new file mode 100644
index 0000000..2eb0aaa
--- /dev/null
+++ b/tools/power/acpi/tools/acpidump/acpidump.h
@@ -0,0 +1,85 @@
+/* SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 */
+/******************************************************************************
+ *
+ * Module Name: acpidump.h - Include file for acpi_dump utility
+ *
+ * Copyright (C) 2000 - 2019, Intel Corp.
+ *
+ *****************************************************************************/
+
+/*
+ * Global variables. Defined in main.c only, externed in all other files
+ */
+#ifdef _DECLARE_GLOBALS
+#define EXTERN
+#define INIT_GLOBAL(a,b)        a=b
+#else
+#define EXTERN                  extern
+#define INIT_GLOBAL(a,b)        a
+#endif
+
+#include <acpi/acpi.h>
+#include "accommon.h"
+#include "actables.h"
+#include "acapps.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, TRUE);
+EXTERN u8 INIT_GLOBAL(gbl_do_not_dump_xsdt, FALSE);
+EXTERN ACPI_FILE INIT_GLOBAL(gbl_output_file, NULL);
+EXTERN char INIT_GLOBAL(*gbl_output_filename, NULL);
+EXTERN u64 INIT_GLOBAL(gbl_rsdp_base, 0);
+
+/* 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 0000000..820baeb
--- /dev/null
+++ b/tools/power/acpi/tools/acpidump/apdump.c
@@ -0,0 +1,402 @@
+// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
+/******************************************************************************
+ *
+ * Module Name: apdump - Dump routines for ACPI tables (acpidump)
+ *
+ * Copyright (C) 2000 - 2019, Intel Corp.
+ *
+ *****************************************************************************/
+
+#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_nameseg(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 (acpi_tb_get_rsdp_length(rsdp));
+	}
+
+	/* 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.
+	 */
+	fprintf(gbl_output_file, "%4.4s @ 0x%8.8X%8.8X\n",
+		table->signature, ACPI_FORMAT_UINT64(address));
+
+	acpi_ut_dump_buffer_to_file(gbl_output_file,
+				    ACPI_CAST_PTR(u8, table), table_length,
+				    DB_BYTE_DISPLAY, 0);
+	fprintf(gbl_output_file, "\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);
+		ACPI_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, &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);
+	ACPI_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_NAMESEG_SIZE + 1];
+	u32 instance;
+	struct acpi_table_header *table;
+	acpi_physical_address address;
+	acpi_status status;
+	int table_status;
+
+	if (strlen(signature) != ACPI_NAMESEG_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_NAMESEG(local_signature, "FADT")) {
+		strcpy(local_signature, ACPI_SIG_FADT);
+	} else if (ACPI_COMPARE_NAMESEG(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);
+		ACPI_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);
+	}
+
+	if (!acpi_ut_valid_nameseg(table->signature)) {
+		fprintf(stderr,
+			"No valid ACPI signature was found in input file %s\n",
+			pathname);
+	}
+
+	/* 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:
+	ACPI_FREE(table);
+	return (table_status);
+}
diff --git a/tools/power/acpi/tools/acpidump/apfiles.c b/tools/power/acpi/tools/acpidump/apfiles.c
new file mode 100644
index 0000000..16d919b
--- /dev/null
+++ b/tools/power/acpi/tools/acpidump/apfiles.c
@@ -0,0 +1,229 @@
+// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
+/******************************************************************************
+ *
+ * Module Name: apfiles - File-related functions for acpidump utility
+ *
+ * Copyright (C) 2000 - 2019, Intel Corp.
+ *
+ *****************************************************************************/
+
+#include "acpidump.h"
+
+/* Local prototypes */
+
+static int ap_is_existing_file(char *pathname);
+
+/******************************************************************************
+ *
+ * FUNCTION:    ap_is_existing_file
+ *
+ * PARAMETERS:  pathname            - Output filename
+ *
+ * RETURN:      0 on success
+ *
+ * DESCRIPTION: Query for file overwrite if it already exists.
+ *
+ ******************************************************************************/
+
+static int ap_is_existing_file(char *pathname)
+{
+#if !defined(_GNU_EFI) && !defined(_EDK2_EFI)
+	struct stat stat_info;
+	int in_char;
+
+	if (!stat(pathname, &stat_info)) {
+		fprintf(stderr,
+			"Target path already exists, overwrite? [y|n] ");
+
+		in_char = fgetc(stdin);
+		if (in_char == '\n') {
+			in_char = fgetc(stdin);
+		}
+
+		if (in_char != 'y' && in_char != 'Y') {
+			return (-1);
+		}
+	}
+#endif
+
+	return (0);
+}
+
+/******************************************************************************
+ *
+ * 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)
+{
+	ACPI_FILE file;
+
+	/* If file exists, prompt for overwrite */
+
+	if (ap_is_existing_file(pathname) != 0) {
+		return (-1);
+	}
+
+	/* Point stdout to the file */
+
+	file = fopen(pathname, "w");
+	if (!file) {
+		fprintf(stderr, "Could not open output file: %s\n", pathname);
+		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_NAMESEG_SIZE + 16];
+	char instance_str[16];
+	ACPI_FILE file;
+	acpi_size 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_COPY_NAMESEG(filename, ACPI_RSDP_NAME);
+	} else {
+		ACPI_COPY_NAMESEG(filename, table->signature);
+	}
+
+	filename[0] = (char)tolower((int)filename[0]);
+	filename[1] = (char)tolower((int)filename[1]);
+	filename[2] = (char)tolower((int)filename[2]);
+	filename[3] = (char)tolower((int)filename[3]);
+	filename[ACPI_NAMESEG_SIZE] = 0;
+
+	/* Handle multiple SSDts - create different filenames for each */
+
+	if (instance > 0) {
+		snprintf(instance_str, sizeof(instance_str), "%u", instance);
+		strcat(filename, instance_str);
+	}
+
+	strcat(filename, FILE_SUFFIX_BINARY_TABLE);
+
+	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) {
+		fprintf(stderr, "Could not open output file: %s\n", filename);
+		return (-1);
+	}
+
+	actual = fwrite(table, 1, table_length, file);
+	if (actual != table_length) {
+		fprintf(stderr, "Error writing binary output file: %s\n",
+			filename);
+		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;
+	ACPI_FILE file;
+	u32 file_size;
+	acpi_size actual;
+
+	/* Must use binary mode */
+
+	file = fopen(pathname, "rb");
+	if (!file) {
+		fprintf(stderr, "Could not open input file: %s\n", pathname);
+		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 = ACPI_ALLOCATE_ZEROED(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);
+		ACPI_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 0000000..d8f1b57
--- /dev/null
+++ b/tools/power/acpi/tools/acpidump/apmain.c
@@ -0,0 +1,366 @@
+// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
+/******************************************************************************
+ *
+ * Module Name: apmain - Main module for the acpidump utility
+ *
+ * Copyright (C) 2000 - 2019, Intel Corp.
+ *
+ *****************************************************************************/
+
+#define _DECLARE_GLOBALS
+#include "acpidump.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 int 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:bc:f:hn:o:r:sv^xz"
+
+/******************************************************************************
+ *
+ * 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("-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("-vd", "Display build date and time");
+	ACPI_OPTION("-z", "Verbose mode");
+
+	ACPI_USAGE_TEXT("\nTable Options:\n");
+
+	ACPI_OPTION("-a <Address>", "Get table via a physical address");
+	ACPI_OPTION("-c <on|off>", "Turning on/off customized table dumping");
+	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");
+
+	ACPI_USAGE_TEXT("\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:      Status
+ *
+ * DESCRIPTION: Add an action item to the action table
+ *
+ ******************************************************************************/
+
+static int 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 %d)\n",
+			AP_MAX_ACTIONS);
+		return (-1);
+	}
+
+	return (0);
+}
+
+/******************************************************************************
+ *
+ * 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)) != ACPI_OPT_END)
+		switch (j) {
+			/*
+			 * Global options
+			 */
+		case 'b':	/* Dump all input tables to binary files */
+
+			gbl_binary_mode = TRUE;
+			continue;
+
+		case 'c':	/* Dump customized tables */
+
+			if (!strcmp(acpi_gbl_optarg, "on")) {
+				gbl_dump_customized_tables = TRUE;
+			} else if (!strcmp(acpi_gbl_optarg, "off")) {
+				gbl_dump_customized_tables = FALSE;
+			} else {
+				fprintf(stderr,
+					"%s: Cannot handle this switch, please use on|off\n",
+					acpi_gbl_optarg);
+				return (-1);
+			}
+			continue;
+
+		case 'h':
+		case '?':
+
+			ap_display_usage();
+			return (1);
+
+		case 'o':	/* Redirect output to a single file */
+
+			if (ap_open_output_file(acpi_gbl_optarg)) {
+				return (-1);
+			}
+			continue;
+
+		case 'r':	/* Dump tables from specified RSDP */
+
+			status =
+			    acpi_ut_strtoul64(acpi_gbl_optarg, &gbl_rsdp_base);
+			if (ACPI_FAILURE(status)) {
+				fprintf(stderr,
+					"%s: Could not convert to a physical address\n",
+					acpi_gbl_optarg);
+				return (-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':	/* -v: (Version): signon already emitted, just exit */
+
+			switch (acpi_gbl_optarg[0]) {
+			case '^':	/* -v: (Version) */
+
+				fprintf(stderr,
+					ACPI_COMMON_SIGNON(AP_UTILITY_NAME));
+				return (1);
+
+			case 'd':
+
+				fprintf(stderr,
+					ACPI_COMMON_SIGNON(AP_UTILITY_NAME));
+				printf(ACPI_COMMON_BUILD_TIME);
+				return (1);
+
+			default:
+
+				printf("Unknown option: -v%s\n",
+				       acpi_gbl_optarg);
+				return (-1);
+			}
+			break;
+
+		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 */
+
+			if (ap_insert_action
+			    (acpi_gbl_optarg, AP_DUMP_TABLE_BY_ADDRESS)) {
+				return (-1);
+			}
+			break;
+
+		case 'f':	/* Get table from a file */
+
+			if (ap_insert_action
+			    (acpi_gbl_optarg, AP_DUMP_TABLE_BY_FILE)) {
+				return (-1);
+			}
+			break;
+
+		case 'n':	/* Get table by input name (signature) */
+
+			if (ap_insert_action
+			    (acpi_gbl_optarg, AP_DUMP_TABLE_BY_NAME)) {
+				return (-1);
+			}
+			break;
+
+		default:
+
+			ap_display_usage();
+			return (-1);
+		}
+
+	/* If there are no actions, this means "get/dump all tables" */
+
+	if (current_action == 0) {
+		if (ap_insert_action(NULL, AP_DUMP_ALL_TABLES)) {
+			return (-1);
+		}
+	}
+
+	return (0);
+}
+
+/******************************************************************************
+ *
+ * FUNCTION:    main
+ *
+ * PARAMETERS:  argc/argv           - Standard argc/argv
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: C main function for acpidump utility
+ *
+ ******************************************************************************/
+
+#if !defined(_GNU_EFI) && !defined(_EDK2_EFI)
+int ACPI_SYSTEM_XFACE main(int argc, char *argv[])
+#else
+int ACPI_SYSTEM_XFACE acpi_main(int argc, char *argv[])
+#endif
+{
+	int status = 0;
+	struct ap_dump_action *action;
+	u32 file_size;
+	u32 i;
+
+	ACPI_DEBUG_INITIALIZE();	/* For debug version only */
+	acpi_os_initialize();
+	gbl_output_file = ACPI_FILE_OUT;
+	acpi_gbl_integer_byte_width = 8;
+
+	/* Process command line options */
+
+	status = ap_do_options(argc, argv);
+	if (status > 0) {
+		return (0);
+	}
+	if (status < 0) {
+		return (status);
+	}
+
+	/* 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_filename) {
+		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 0000000..d0abac0
--- /dev/null
+++ b/tools/power/acpi/tools/ec/Makefile
@@ -0,0 +1,14 @@
+# SPDX-License-Identifier: GPL-2.0-only
+# tools/power/acpi/tools/acpidump/Makefile - ACPI tool Makefile
+#
+# Copyright (c) 2015, Intel Corporation
+#   Author: Lv Zheng <lv.zheng@intel.com>
+#
+
+include ../../Makefile.config
+
+TOOL = ec
+TOOL_OBJS = \
+	ec_access.o
+
+include ../../Makefile.rules
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 0000000..8bb271b
--- /dev/null
+++ b/tools/power/acpi/tools/ec/ec_access.c
@@ -0,0 +1,237 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * ec_access.c
+ *
+ * Copyright (C) 2010 SUSE Linux Products GmbH
+ * Author:
+ *      Thomas Renninger <trenn@suse.de>
+ */
+
+#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 system.");
+	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 1dd5f4f..c862249 100644
--- a/tools/power/cpupower/Makefile
+++ b/tools/power/cpupower/Makefile
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
 # Makefile for cpupower
 #
 # Copyright (C) 2005,2006 Dominik Brodowski <linux@dominikbrodowski.net>
@@ -6,19 +7,6 @@
 #
 # Copyright (C) 2003,2004 Greg Kroah-Hartman <greg@kroah.com>
 #
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; version 2 of the License.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-# General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-#
 OUTPUT=./
 ifeq ("$(origin O)", "command line")
 	OUTPUT := $(O)/
@@ -30,7 +18,6 @@
 $(if $(OUTDIR),, $(error output directory "$(OUTPUT)" does not exist))
 endif
 
-include ../../scripts/Makefile.arch
 
 # --- CONFIGURATION BEGIN ---
 
@@ -81,14 +68,10 @@
 sbindir ?=	/usr/sbin
 mandir ?=	/usr/man
 includedir ?=	/usr/include
-ifeq ($(IS_64_BIT), 1)
-libdir ?=	/usr/lib64
-else
-libdir ?=	/usr/lib
-endif
 localedir ?=	/usr/share/locale
 docdir ?=       /usr/share/doc/packages/cpupower
 confdir ?=      /etc/
+bash_completion_dir ?= /usr/share/bash-completion/completions
 
 # Toolchain: what tools do we use, and what options do they need:
 
@@ -96,7 +79,8 @@
 INSTALL = /usr/bin/install -c
 INSTALL_PROGRAM = ${INSTALL}
 INSTALL_DATA  = ${INSTALL} -m 644
-INSTALL_SCRIPT = ${INSTALL_PROGRAM}
+#bash completion scripts get sourced and so they should be rw only.
+INSTALL_SCRIPT = ${INSTALL} -m 644
 
 # If you are running a cross compiler, you may want to set this
 # to something more interesting, like "arm-linux-".  If you want
@@ -110,6 +94,14 @@
 HOSTCC = gcc
 MKDIR = mkdir
 
+# 64bit library detection
+include ../../scripts/Makefile.arch
+
+ifeq ($(IS_64_BIT), 1)
+libdir ?=	/usr/lib64
+else
+libdir ?=	/usr/lib
+endif
 
 # Now we set up the build system
 #
@@ -129,7 +121,7 @@
 WARNINGS += $(call cc-supports,-Wdeclaration-after-statement)
 WARNINGS += -Wshadow
 
-CFLAGS += -DVERSION=\"$(VERSION)\" -DPACKAGE=\"$(PACKAGE)\" \
+override CFLAGS += -DVERSION=\"$(VERSION)\" -DPACKAGE=\"$(PACKAGE)\" \
 		-DPACKAGE_BUGREPORT=\"$(PACKAGE_BUGREPORT)\" -D_GNU_SOURCE
 
 UTIL_OBJS =  utils/helpers/amd.o utils/helpers/msr.o \
@@ -156,12 +148,12 @@
 LIB_OBJS = 	lib/cpufreq.o lib/cpupower.o lib/cpuidle.o
 LIB_OBJS :=	$(addprefix $(OUTPUT),$(LIB_OBJS))
 
-CFLAGS +=	-pipe
+override CFLAGS +=	-pipe
 
 ifeq ($(strip $(NLS)),true)
 	INSTALL_NLS += install-gmo
 	COMPILE_NLS += create-gmo
-	CFLAGS += -DNLS
+	override CFLAGS += -DNLS
 endif
 
 ifeq ($(strip $(CPUFREQ_BENCH)),true)
@@ -175,7 +167,7 @@
         UTIL_SRC += $(LIB_SRC)
 endif
 
-CFLAGS += $(WARNINGS)
+override CFLAGS += $(WARNINGS)
 
 ifeq ($(strip $(V)),false)
 	QUIET=@
@@ -188,10 +180,10 @@
 
 # if DEBUG is enabled, then we do not strip or optimize
 ifeq ($(strip $(DEBUG)),true)
-	CFLAGS += -O1 -g -DDEBUG
+	override CFLAGS += -O1 -g -DDEBUG
 	STRIPCMD = /bin/true -Since_we_are_debugging
 else
-	CFLAGS += $(OPTIMIZATION) -fomit-frame-pointer
+	override CFLAGS += $(OPTIMIZATION) -fomit-frame-pointer
 	STRIPCMD = $(STRIP) -s --remove-section=.note --remove-section=.comment
 endif
 
@@ -288,6 +280,8 @@
 install-tools:
 	$(INSTALL) -d $(DESTDIR)${bindir}
 	$(INSTALL_PROGRAM) $(OUTPUT)cpupower $(DESTDIR)${bindir}
+	$(INSTALL) -d $(DESTDIR)${bash_completion_dir}
+	$(INSTALL_SCRIPT) cpupower-completion.sh '$(DESTDIR)${bash_completion_dir}/cpupower'
 
 install-man:
 	$(INSTALL_DATA) -D man/cpupower.1 $(DESTDIR)${mandir}/man1/cpupower.1
diff --git a/tools/power/cpupower/bench/benchmark.c b/tools/power/cpupower/bench/benchmark.c
index 429d51a..c7234cf 100644
--- a/tools/power/cpupower/bench/benchmark.c
+++ b/tools/power/cpupower/bench/benchmark.c
@@ -1,20 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
 /*  cpufreq-bench CPUFreq microbenchmark
  *
  *  Copyright (C) 2008 Christian Kornacker <ckornacker@suse.de>
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  */
 
 #include <stdio.h>
diff --git a/tools/power/cpupower/bench/benchmark.h b/tools/power/cpupower/bench/benchmark.h
index 51d7f50..bf612de 100644
--- a/tools/power/cpupower/bench/benchmark.h
+++ b/tools/power/cpupower/bench/benchmark.h
@@ -1,20 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
 /*  cpufreq-bench CPUFreq microbenchmark
  *
  *  Copyright (C) 2008 Christian Kornacker <ckornacker@suse.de>
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  */
 
 /* load loop, this schould take about 1 to 2ms to complete */
diff --git a/tools/power/cpupower/bench/config.h b/tools/power/cpupower/bench/config.h
index ee6f258..fec5b0b 100644
--- a/tools/power/cpupower/bench/config.h
+++ b/tools/power/cpupower/bench/config.h
@@ -1,20 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
 /*  cpufreq-bench CPUFreq microbenchmark
  *
  *  Copyright (C) 2008 Christian Kornacker <ckornacker@suse.de>
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  */
 
 /* initial loop count for the load calibration */
diff --git a/tools/power/cpupower/bench/cpufreq-bench_plot.sh b/tools/power/cpupower/bench/cpufreq-bench_plot.sh
index 410021a..f5f8b3c 100644
--- a/tools/power/cpupower/bench/cpufreq-bench_plot.sh
+++ b/tools/power/cpupower/bench/cpufreq-bench_plot.sh
@@ -1,19 +1,6 @@
 #!/bin/bash
+# SPDX-License-Identifier: GPL-2.0-or-later
 
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2, or (at your option)
-# any later version.
-
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
-# 02110-1301, USA.
 
 # Author/Copyright(c): 2009, Thomas Renninger <trenn@suse.de>, Novell Inc.
 
@@ -101,4 +88,4 @@
 echo >> $dir/plot_script.gpl
 
 gnuplot $dir/plot_script.gpl
-rm -r $dir
\ No newline at end of file
+rm -r $dir
diff --git a/tools/power/cpupower/bench/cpufreq-bench_script.sh b/tools/power/cpupower/bench/cpufreq-bench_script.sh
index de20d2a..785a367 100644
--- a/tools/power/cpupower/bench/cpufreq-bench_script.sh
+++ b/tools/power/cpupower/bench/cpufreq-bench_script.sh
@@ -1,19 +1,6 @@
 #!/bin/bash
+# SPDX-License-Identifier: GPL-2.0-or-later
 
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2, or (at your option)
-# any later version.
-
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
-# 02110-1301, USA.
 
 # Author/Copyright(c): 2009, Thomas Renninger <trenn@suse.de>, Novell Inc.
 
@@ -98,4 +85,4 @@
 }
 
 measure
-create_plots
\ No newline at end of file
+create_plots
diff --git a/tools/power/cpupower/bench/main.c b/tools/power/cpupower/bench/main.c
index 2491031..429d1b6 100644
--- a/tools/power/cpupower/bench/main.c
+++ b/tools/power/cpupower/bench/main.c
@@ -1,20 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
 /*  cpufreq-bench CPUFreq microbenchmark
  *
  *  Copyright (C) 2008 Christian Kornacker <ckornacker@suse.de>
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  */
 
 #include <stdio.h>
diff --git a/tools/power/cpupower/bench/parse.c b/tools/power/cpupower/bench/parse.c
index 9ba8a44..e63dc11 100644
--- a/tools/power/cpupower/bench/parse.c
+++ b/tools/power/cpupower/bench/parse.c
@@ -1,20 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
 /*  cpufreq-bench CPUFreq microbenchmark
  *
  *  Copyright (C) 2008 Christian Kornacker <ckornacker@suse.de>
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  */
 
 #include <stdio.h>
@@ -145,7 +132,7 @@
 	config->cpu = 0;
 	config->prio = SCHED_HIGH;
 	config->verbose = 0;
-	strncpy(config->governor, "ondemand", 8);
+	strncpy(config->governor, "ondemand", sizeof(config->governor));
 
 	config->output = stdout;
 
diff --git a/tools/power/cpupower/bench/parse.h b/tools/power/cpupower/bench/parse.h
index a8dc632..d5b3e34 100644
--- a/tools/power/cpupower/bench/parse.h
+++ b/tools/power/cpupower/bench/parse.h
@@ -1,20 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
 /*  cpufreq-bench CPUFreq microbenchmark
  *
  *  Copyright (C) 2008 Christian Kornacker <ckornacker@suse.de>
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  */
 
 /* struct that holds the required config parameters */
diff --git a/tools/power/cpupower/bench/system.c b/tools/power/cpupower/bench/system.c
index 2bb3eef..40f3679 100644
--- a/tools/power/cpupower/bench/system.c
+++ b/tools/power/cpupower/bench/system.c
@@ -1,20 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
 /*  cpufreq-bench CPUFreq microbenchmark
  *
  *  Copyright (C) 2008 Christian Kornacker <ckornacker@suse.de>
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  */
 
 #include <stdio.h>
diff --git a/tools/power/cpupower/bench/system.h b/tools/power/cpupower/bench/system.h
index 3a8c858..530fa28 100644
--- a/tools/power/cpupower/bench/system.h
+++ b/tools/power/cpupower/bench/system.h
@@ -1,20 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
 /*  cpufreq-bench CPUFreq microbenchmark
  *
  *  Copyright (C) 2008 Christian Kornacker <ckornacker@suse.de>
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  */
 
 #include "parse.h"
diff --git a/tools/power/cpupower/cpupower-completion.sh b/tools/power/cpupower/cpupower-completion.sh
new file mode 100644
index 0000000..e10839c
--- /dev/null
+++ b/tools/power/cpupower/cpupower-completion.sh
@@ -0,0 +1,128 @@
+# -*- shell-script -*-
+# bash completion script for cpupower
+# Taken from git.git's completion script.
+
+_cpupower_commands="frequency-info frequency-set idle-info idle-set set info monitor"
+
+_frequency_info ()
+{
+	local flags="-f -w -l -d -p -g -a -s -y -o -m -n --freq --hwfreq --hwlimits --driver --policy --governors --related-cpus --affected-cpus --stats --latency --proc --human --no-rounding"
+	local prev="${COMP_WORDS[COMP_CWORD-1]}"
+	local cur="${COMP_WORDS[COMP_CWORD]}"
+	case "$prev" in
+		frequency-info) COMPREPLY=($(compgen -W "$flags" -- "$cur")) ;;
+	esac
+}
+
+_frequency_set ()
+{
+	local flags="-f -g --freq --governor -d --min -u --max -r --related"
+	local prev="${COMP_WORDS[COMP_CWORD-1]}"
+	local cur="${COMP_WORDS[COMP_CWORD]}"
+	case "$prev" in
+		-f| --freq | -d | --min | -u | --max)
+		if [ -d /sys/devices/system/cpu/cpufreq/ ] ; then
+			COMPREPLY=($(compgen -W '$(cat $(ls -d /sys/devices/system/cpu/cpufreq/policy* | head -1)/scaling_available_frequencies)' -- "$cur"))
+		fi ;;
+		-g| --governor)
+		if [ -d /sys/devices/system/cpu/cpufreq/ ] ; then
+			COMPREPLY=($(compgen -W '$(cat $(ls -d /sys/devices/system/cpu/cpufreq/policy* | head -1)/scaling_available_governors)' -- "$cur"))
+		fi;;
+		frequency-set) COMPREPLY=($(compgen -W "$flags" -- "$cur")) ;;
+	esac
+}
+
+_idle_info()
+{
+	local flags="-f --silent"
+	local prev="${COMP_WORDS[COMP_CWORD-1]}"
+	local cur="${COMP_WORDS[COMP_CWORD]}"
+	case "$prev" in
+		idle-info) COMPREPLY=($(compgen -W "$flags" -- "$cur")) ;;
+	esac
+}
+
+_idle_set()
+{
+	local flags="-d --disable -e --enable -D --disable-by-latency -E --enable-all"
+	local prev="${COMP_WORDS[COMP_CWORD-1]}"
+	local cur="${COMP_WORDS[COMP_CWORD]}"
+	case "$prev" in
+		idle-set) COMPREPLY=($(compgen -W "$flags" -- "$cur")) ;;
+	esac
+}
+
+_set()
+{
+	local flags="--perf-bias, -b"
+	local prev="${COMP_WORDS[COMP_CWORD-1]}"
+	local cur="${COMP_WORDS[COMP_CWORD]}"
+	case "$prev" in
+		set) COMPREPLY=($(compgen -W "$flags" -- "$cur")) ;;
+	esac
+}
+
+_monitor()
+{
+	local flags="-l -m -i -c -v"
+	local prev="${COMP_WORDS[COMP_CWORD-1]}"
+	local cur="${COMP_WORDS[COMP_CWORD]}"
+	case "$prev" in
+		monitor) COMPREPLY=($(compgen -W "$flags" -- "$cur")) ;;
+	esac
+}
+
+_taskset()
+{
+	local prev_to_prev="${COMP_WORDS[COMP_CWORD-2]}"
+	local prev="${COMP_WORDS[COMP_CWORD-1]}"
+	local cur="${COMP_WORDS[COMP_CWORD]}"
+	case "$prev_to_prev" in
+		-c|--cpu) COMPREPLY=($(compgen -W "$_cpupower_commands" -- "$cur")) ;;
+	esac
+	case "$prev" in
+		frequency-info) _frequency_info ;;
+		frequency-set) _frequency_set ;;
+		idle-info) _idle_info ;;
+		idle-set) _idle_set ;;
+		set) _set ;;
+		monitor) _monitor ;;
+	esac
+
+}
+
+_cpupower ()
+{
+	local i
+	local c=1
+	local command
+
+	while test $c -lt $COMP_CWORD; do
+		if test $c == 1; then
+			command="${COMP_WORDS[c]}"
+		fi
+		c=$((++c))
+	done
+
+	# Complete name of subcommand if the user has not finished typing it yet.
+	if test $c -eq $COMP_CWORD -a -z "$command"; then
+		COMPREPLY=($(compgen -W "help -v --version -c --cpu $_cpupower_commands" -- "${COMP_WORDS[COMP_CWORD]}"))
+		return
+	fi
+
+	# Complete arguments to subcommands.
+	case "$command" in
+		-v|--version) return ;;
+		-c|--cpu) _taskset ;;
+		help) COMPREPLY=($(compgen -W "$_cpupower_commands" -- "${COMP_WORDS[COMP_CWORD]}")) ;;
+		frequency-info) _frequency_info ;;
+		frequency-set) _frequency_set ;;
+		idle-info) _idle_info ;;
+		idle-set) _idle_set ;;
+		set) _set ;;
+		monitor) _monitor ;;
+	esac
+}
+
+complete -o bashdefault -o default -F _cpupower cpupower 2>/dev/null \
+    || complete -o default -F _cpupower cpupower
diff --git a/tools/power/cpupower/debug/i386/centrino-decode.c b/tools/power/cpupower/debug/i386/centrino-decode.c
index 7ef24cc..700cd31 100644
--- a/tools/power/cpupower/debug/i386/centrino-decode.c
+++ b/tools/power/cpupower/debug/i386/centrino-decode.c
@@ -1,8 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  *  (C) 2003 - 2004  Dominik Brodowski <linux@dominikbrodowski.de>
  *
- *  Licensed under the terms of the GNU GPL License version 2.
- *
  * Based on code found in
  * linux/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c
  * and originally developed by Jeremy Fitzhardinge.
diff --git a/tools/power/cpupower/debug/i386/intel_gsic.c b/tools/power/cpupower/debug/i386/intel_gsic.c
index d032c82..e5e926f 100644
--- a/tools/power/cpupower/debug/i386/intel_gsic.c
+++ b/tools/power/cpupower/debug/i386/intel_gsic.c
@@ -1,9 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  *  (C) 2003  Bruno Ducrot
  *  (C) 2004  Dominik Brodowski <linux@dominikbrodowski.de>
  *
- *  Licensed under the terms of the GNU GPL License version 2.
- *
  * Based on code found in
  * linux/include/asm-i386/ist.h and linux/arch/i386/kernel/setup.c
  * and originally developed by Andy Grover <andrew.grover@intel.com>
diff --git a/tools/power/cpupower/debug/i386/powernow-k8-decode.c b/tools/power/cpupower/debug/i386/powernow-k8-decode.c
index 638a6b3..735dca1 100644
--- a/tools/power/cpupower/debug/i386/powernow-k8-decode.c
+++ b/tools/power/cpupower/debug/i386/powernow-k8-decode.c
@@ -1,8 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  *  (C) 2004 Bruno Ducrot <ducrot@poupinou.org>
  *
- *  Licensed under the terms of the GNU GPL License version 2.
- *
  * Based on code found in
  * linux/arch/i386/kernel/cpu/cpufreq/powernow-k8.c
  * and originally developed by Paul Devriendt
diff --git a/tools/power/cpupower/debug/kernel/Makefile b/tools/power/cpupower/debug/kernel/Makefile
index c23e5a6..7b5c436 100644
--- a/tools/power/cpupower/debug/kernel/Makefile
+++ b/tools/power/cpupower/debug/kernel/Makefile
@@ -12,8 +12,8 @@
 	$(MAKE) -C $(KDIR) M=$(CURDIR)
 
 clean:
-	- rm -rf *.o *.ko .tmp-versions .*.cmd .*.mod.* *.mod.c
-	- rm -rf .tmp_versions* Module.symvers modules.order
+	- rm -rf *.o *.ko .*.cmd .*.mod.* *.mod.c
+	- rm -rf Module.symvers modules.order
 
 install: default
 	install -d $(KMISC)
diff --git a/tools/power/cpupower/debug/kernel/cpufreq-test_tsc.c b/tools/power/cpupower/debug/kernel/cpufreq-test_tsc.c
index 6ff8383..e364b17 100644
--- a/tools/power/cpupower/debug/kernel/cpufreq-test_tsc.c
+++ b/tools/power/cpupower/debug/kernel/cpufreq-test_tsc.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  * test module to check whether the TSC-based delay routine continues
  * to work properly after cpufreq transitions. Needs ACPI to work
diff --git a/tools/power/cpupower/debug/x86_64/Makefile b/tools/power/cpupower/debug/x86_64/Makefile
index 59af84b..b1b6c43 100644
--- a/tools/power/cpupower/debug/x86_64/Makefile
+++ b/tools/power/cpupower/debug/x86_64/Makefile
@@ -13,10 +13,10 @@
 default: all
 
 $(OUTPUT)centrino-decode: ../i386/centrino-decode.c
-	$(CC) $(CFLAGS) -o $@ $<
+	$(CC) $(CFLAGS) -o $@ $(LDFLAGS) $<
 
 $(OUTPUT)powernow-k8-decode: ../i386/powernow-k8-decode.c
-	$(CC) $(CFLAGS) -o $@ $<
+	$(CC) $(CFLAGS) -o $@ $(LDFLAGS) $<
 
 all: $(OUTPUT)centrino-decode $(OUTPUT)powernow-k8-decode
 
diff --git a/tools/power/cpupower/lib/cpufreq.c b/tools/power/cpupower/lib/cpufreq.c
index 0c0f3e3..2f55d4d 100644
--- a/tools/power/cpupower/lib/cpufreq.c
+++ b/tools/power/cpupower/lib/cpufreq.c
@@ -1,7 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  *  (C) 2004-2009  Dominik Brodowski <linux@dominikbrodowski.de>
- *
- *  Licensed under the terms of the GNU GPL License version 2.
  */
 
 
@@ -333,17 +332,20 @@
 }
 
 
-struct cpufreq_available_frequencies
-*cpufreq_get_available_frequencies(unsigned int cpu)
+struct cpufreq_frequencies
+*cpufreq_get_frequencies(const char *type, unsigned int cpu)
 {
-	struct cpufreq_available_frequencies *first = NULL;
-	struct cpufreq_available_frequencies *current = NULL;
+	struct cpufreq_frequencies *first = NULL;
+	struct cpufreq_frequencies *current = NULL;
 	char one_value[SYSFS_PATH_MAX];
 	char linebuf[MAX_LINE_LEN];
+	char fname[MAX_LINE_LEN];
 	unsigned int pos, i;
 	unsigned int len;
 
-	len = sysfs_cpufreq_read_file(cpu, "scaling_available_frequencies",
+	snprintf(fname, MAX_LINE_LEN, "scaling_%s_frequencies", type);
+
+	len = sysfs_cpufreq_read_file(cpu, fname,
 				linebuf, sizeof(linebuf));
 	if (len == 0)
 		return NULL;
@@ -389,9 +391,9 @@
 	return NULL;
 }
 
-void cpufreq_put_available_frequencies(struct cpufreq_available_frequencies
-				*any) {
-	struct cpufreq_available_frequencies *tmp, *next;
+void cpufreq_put_frequencies(struct cpufreq_frequencies *any)
+{
+	struct cpufreq_frequencies *tmp, *next;
 
 	if (!any)
 		return;
diff --git a/tools/power/cpupower/lib/cpufreq.h b/tools/power/cpupower/lib/cpufreq.h
index 60beaf5..a55f0d1 100644
--- a/tools/power/cpupower/lib/cpufreq.h
+++ b/tools/power/cpupower/lib/cpufreq.h
@@ -1,16 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
 /*
  *  cpufreq.h - definitions for libcpufreq
  *
  *  Copyright (C) 2004-2009  Dominik Brodowski <linux@dominikbrodowski.de>
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation, version 2 of the License.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
  */
 
 #ifndef __CPUPOWER_CPUFREQ_H__
@@ -28,10 +20,10 @@
 	struct cpufreq_available_governors *first;
 };
 
-struct cpufreq_available_frequencies {
+struct cpufreq_frequencies {
 	unsigned long frequency;
-	struct cpufreq_available_frequencies *next;
-	struct cpufreq_available_frequencies *first;
+	struct cpufreq_frequencies *next;
+	struct cpufreq_frequencies *first;
 };
 
 
@@ -129,14 +121,14 @@
  *
  * Only present on _some_ ->target() cpufreq drivers. For information purposes
  * only. Please free allocated memory by calling
- * cpufreq_put_available_frequencies after use.
+ * cpufreq_put_frequencies after use.
  */
 
-struct cpufreq_available_frequencies
-*cpufreq_get_available_frequencies(unsigned int cpu);
+struct cpufreq_frequencies
+*cpufreq_get_frequencies(const char *type, unsigned int cpu);
 
-void cpufreq_put_available_frequencies(
-		struct cpufreq_available_frequencies *first);
+void cpufreq_put_frequencies(
+		struct cpufreq_frequencies *first);
 
 
 /* determine affected CPUs
diff --git a/tools/power/cpupower/lib/cpuidle.c b/tools/power/cpupower/lib/cpuidle.c
index 852d254..479c597 100644
--- a/tools/power/cpupower/lib/cpuidle.c
+++ b/tools/power/cpupower/lib/cpuidle.c
@@ -1,8 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  *  (C) 2004-2009  Dominik Brodowski <linux@dominikbrodowski.de>
  *  (C) 2011       Thomas Renninger <trenn@novell.com> Novell Inc.
- *
- *  Licensed under the terms of the GNU GPL License version 2.
  */
 
 #include <stdio.h>
diff --git a/tools/power/cpupower/lib/cpupower.c b/tools/power/cpupower/lib/cpupower.c
index 9711d62..3656e69 100644
--- a/tools/power/cpupower/lib/cpupower.c
+++ b/tools/power/cpupower/lib/cpupower.c
@@ -1,7 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  *  (C) 2004-2009  Dominik Brodowski <linux@dominikbrodowski.de>
- *
- *  Licensed under the terms of the GNU GPL License version 2.
  */
 
 #include <sys/types.h>
diff --git a/tools/power/cpupower/man/cpupower-monitor.1 b/tools/power/cpupower/man/cpupower-monitor.1
index 914cbb9..70a5647 100644
--- a/tools/power/cpupower/man/cpupower-monitor.1
+++ b/tools/power/cpupower/man/cpupower-monitor.1
@@ -61,7 +61,7 @@
 .PP
 \-i seconds
 .RS 4
-Measure intervall.
+Measure interval.
 .RE
 .PP
 \-c
diff --git a/tools/power/cpupower/po/cs.po b/tools/power/cpupower/po/cs.po
index cb22c45..bfc7e17 100644
--- a/tools/power/cpupower/po/cs.po
+++ b/tools/power/cpupower/po/cs.po
@@ -98,7 +98,7 @@
 
 #: utils/idle_monitor/cpupower-monitor.c:74
 #, c-format
-msgid "\t -i: time intervall to measure for in seconds (default 1)\n"
+msgid "\t -i: time interval to measure for in seconds (default 1)\n"
 msgstr ""
 
 #: utils/idle_monitor/cpupower-monitor.c:75
diff --git a/tools/power/cpupower/po/de.po b/tools/power/cpupower/po/de.po
index 840c17c..9780a44 100644
--- a/tools/power/cpupower/po/de.po
+++ b/tools/power/cpupower/po/de.po
@@ -8,66 +8,66 @@
 "Project-Id-Version: cpufrequtils 006\n"
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2011-03-08 17:03+0100\n"
-"PO-Revision-Date: 2009-08-08 17:18+0100\n"
-"Last-Translator:  <linux@dominikbrodowski.net>\n"
+"PO-Revision-Date: 2019-06-02 15:23+0200\n"
+"Last-Translator: Benjamin Weis <benjamin.weis@gmx.com>\n"
 "Language-Team: NONE\n"
 "Language: \n"
 "MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=ISO-8859-1\n"
+"Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
 "Plural-Forms: nplurals=2; plural=(n != 1);\n"
 
 #: utils/idle_monitor/nhm_idle.c:36
 msgid "Processor Core C3"
-msgstr ""
+msgstr "Prozessorkern C3"
 
 #: utils/idle_monitor/nhm_idle.c:43
 msgid "Processor Core C6"
-msgstr ""
+msgstr "Prozessorkern C6"
 
 #: utils/idle_monitor/nhm_idle.c:51
 msgid "Processor Package C3"
-msgstr ""
+msgstr "Prozessorpaket C3"
 
 #: utils/idle_monitor/nhm_idle.c:58 utils/idle_monitor/amd_fam14h_idle.c:70
 msgid "Processor Package C6"
-msgstr ""
+msgstr "Prozessorpaket C6"
 
 #: utils/idle_monitor/snb_idle.c:33
 msgid "Processor Core C7"
-msgstr ""
+msgstr "Prozessorkern C7"
 
 #: utils/idle_monitor/snb_idle.c:40
 msgid "Processor Package C2"
-msgstr ""
+msgstr "Prozessorpaket C2"
 
 #: utils/idle_monitor/snb_idle.c:47
 msgid "Processor Package C7"
-msgstr ""
+msgstr "Prozessorpaket C7"
 
 #: utils/idle_monitor/amd_fam14h_idle.c:56
 msgid "Package in sleep state (PC1 or deeper)"
-msgstr ""
+msgstr "Paket in Schlafzustand (PC1 oder tiefer)"
 
 #: utils/idle_monitor/amd_fam14h_idle.c:63
 msgid "Processor Package C1"
-msgstr ""
+msgstr "Prozessorpaket C1"
 
 #: utils/idle_monitor/amd_fam14h_idle.c:77
 msgid "North Bridge P1 boolean counter (returns 0 or 1)"
-msgstr ""
+msgstr "North Bridge P1 boolescher Zähler (gibt 0 oder 1 zurück)"
 
 #: utils/idle_monitor/mperf_monitor.c:35
 msgid "Processor Core not idle"
-msgstr ""
+msgstr "Prozessorkern ist nicht im Leerlauf"
 
 #: utils/idle_monitor/mperf_monitor.c:42
 msgid "Processor Core in an idle state"
-msgstr ""
+msgstr "Prozessorkern ist in einem Ruhezustand"
 
 #: utils/idle_monitor/mperf_monitor.c:50
 msgid "Average Frequency (including boost) in MHz"
-msgstr ""
+msgstr "Durchschnittliche Frequenz (einschließlich Boost) in MHz"
 
 #: utils/idle_monitor/cpupower-monitor.c:66
 #, c-format
@@ -75,6 +75,8 @@
 "cpupower monitor: [-h] [ [-t] | [-l] | [-m <mon1>,[<mon2>] ] ] [-i "
 "interval_sec | -c command ...]\n"
 msgstr ""
+"cpupower monitor: [-h] [ [-t] | [-l] | [-m <mon1>,[<mon2>] ] ] [-i "
+"interval_sec | -c Befehl ...]\n"
 
 #: utils/idle_monitor/cpupower-monitor.c:69
 #, c-format
@@ -82,36 +84,40 @@
 "cpupower monitor: [-v] [-h] [ [-t] | [-l] | [-m <mon1>,[<mon2>] ] ] [-i "
 "interval_sec | -c command ...]\n"
 msgstr ""
+"cpupower monitor: [-v] [-h] [ [-t] | [-l] | [-m <mon1>,[<mon2>] ] ] [-i "
+"interval_sec | -c Befehl ...]\n"
 
 #: utils/idle_monitor/cpupower-monitor.c:71
 #, c-format
 msgid "\t -v: be more verbose\n"
-msgstr ""
+msgstr "\t -v: ausführlicher\n"
 
 #: utils/idle_monitor/cpupower-monitor.c:73
 #, c-format
 msgid "\t -h: print this help\n"
-msgstr ""
+msgstr "\t -h: diese Hilfe ausgeben\n"
 
 #: utils/idle_monitor/cpupower-monitor.c:74
 #, c-format
-msgid "\t -i: time intervall to measure for in seconds (default 1)\n"
-msgstr ""
+msgid "\t -i: time interval to measure for in seconds (default 1)\n"
+msgstr "\t -i: Zeitintervall für die Messung in Sekunden (Standard 1)\n"
 
 #: utils/idle_monitor/cpupower-monitor.c:75
 #, c-format
 msgid "\t -t: show CPU topology/hierarchy\n"
-msgstr ""
+msgstr "\t -t: CPU-Topologie/Hierarchie anzeigen\n"
 
 #: utils/idle_monitor/cpupower-monitor.c:76
 #, c-format
 msgid "\t -l: list available CPU sleep monitors (for use with -m)\n"
 msgstr ""
+"\t -l: verfügbare CPU-Schlafwächter auflisten (für Verwendung mit -m)\n"
 
 #: utils/idle_monitor/cpupower-monitor.c:77
 #, c-format
 msgid "\t -m: show specific CPU sleep monitors only (in same order)\n"
 msgstr ""
+"\t -m: spezifische CPU-Schlafwächter anzeigen (in gleicher Reihenfolge)\n"
 
 #: utils/idle_monitor/cpupower-monitor.c:79
 #, c-format
@@ -119,71 +125,73 @@
 "only one of: -t, -l, -m are allowed\n"
 "If none of them is passed,"
 msgstr ""
+"nur einer von: -t, -l, -m ist erlaubt\n"
+"Wenn keiner von ihnen übergeben wird,"
 
 #: utils/idle_monitor/cpupower-monitor.c:80
 #, c-format
 msgid " all supported monitors are shown\n"
-msgstr ""
+msgstr " werden alle unterstützten Wächter angezeigt\n"
 
 #: utils/idle_monitor/cpupower-monitor.c:197
 #, c-format
 msgid "Monitor %s, Counter %s has no count function. Implementation error\n"
-msgstr ""
+msgstr "Wächter %s, Zähler %s hat keine Zählfunktion. Implementierungsfehler\n"
 
 #: utils/idle_monitor/cpupower-monitor.c:207
 #, c-format
 msgid " *is offline\n"
-msgstr ""
+msgstr " *ist offline\n"
 
 #: utils/idle_monitor/cpupower-monitor.c:236
 #, c-format
 msgid "%s: max monitor name length (%d) exceeded\n"
-msgstr ""
+msgstr "%s: max. Wächternamenslänge (%d) überschritten\n"
 
 #: utils/idle_monitor/cpupower-monitor.c:250
 #, c-format
 msgid "No matching monitor found in %s, try -l option\n"
-msgstr ""
+msgstr "Kein passender Wächter in %s gefunden, versuchen Sie die Option -l\n"
 
 #: utils/idle_monitor/cpupower-monitor.c:266
 #, c-format
 msgid "Monitor \"%s\" (%d states) - Might overflow after %u s\n"
-msgstr ""
+msgstr "Wächter \"%s\" (%d Zustände) - Könnte nach %u s überlaufen\n"
 
 #: utils/idle_monitor/cpupower-monitor.c:319
 #, c-format
 msgid "%s took %.5f seconds and exited with status %d\n"
-msgstr ""
+msgstr "%s hat %.5f Sekunden gedauert und hat sich mit Status %d beendet\n"
 
 #: utils/idle_monitor/cpupower-monitor.c:406
 #, c-format
 msgid "Cannot read number of available processors\n"
-msgstr ""
+msgstr "Anzahl der verfügbaren Prozessoren kann nicht gelesen werden\n"
 
 #: utils/idle_monitor/cpupower-monitor.c:417
 #, c-format
 msgid "Available monitor %s needs root access\n"
-msgstr ""
+msgstr "Verfügbarer Wächter %s benötigt root-Zugriff\n"
 
 #: utils/idle_monitor/cpupower-monitor.c:428
 #, c-format
 msgid "No HW Cstate monitors found\n"
-msgstr ""
+msgstr "Keine HW C-Zustandswächter gefunden\n"
 
 #: utils/cpupower.c:78
 #, c-format
 msgid "cpupower [ -c cpulist ] subcommand [ARGS]\n"
-msgstr ""
+msgstr "cpupower [ -c cpulist ] Unterbefehl [ARGS]\n"
 
 #: utils/cpupower.c:79
 #, c-format
 msgid "cpupower --version\n"
-msgstr ""
+msgstr "cpupower --version\n"
 
 #: utils/cpupower.c:80
 #, c-format
 msgid "Supported subcommands are:\n"
-msgstr ""
+msgstr "Unterstützte Unterbefehle sind:\n"
 
 #: utils/cpupower.c:83
 #, c-format
@@ -191,11 +199,15 @@
 "\n"
 "Some subcommands can make use of the -c cpulist option.\n"
 msgstr ""
+"\n"
+"Einige Unterbefehle können die Option -c cpulist verwenden.\n"
 
 #: utils/cpupower.c:84
 #, c-format
 msgid "Look at the general cpupower manpage how to use it\n"
 msgstr ""
+"Schauen Sie sich die allgemeine cpupower manpage an, um zu erfahren, wie man "
+"es benutzt\n"
 
 #: utils/cpupower.c:85
 #, c-format
@@ -217,30 +229,31 @@
 #: utils/cpupower.c:114
 #, c-format
 msgid "Error parsing cpu list\n"
-msgstr ""
+msgstr "Fehler beim Parsen der CPU-Liste\n"
 
 #: utils/cpupower.c:172
 #, c-format
 msgid "Subcommand %s needs root privileges\n"
-msgstr ""
+msgstr "Unterbefehl %s benötigt root-Rechte\n"
 
 #: utils/cpufreq-info.c:31
 #, c-format
 msgid "Couldn't count the number of CPUs (%s: %s), assuming 1\n"
 msgstr ""
-"Konnte nicht die Anzahl der CPUs herausfinden (%s : %s), nehme daher 1 an.\n"
+"Anzahl der CPUs konnte nicht herausgefinden werden (%s: %s), es wird daher 1 "
+"angenommen\n"
 
 #: utils/cpufreq-info.c:63
 #, c-format
 msgid ""
 "          minimum CPU frequency  -  maximum CPU frequency  -  governor\n"
-msgstr ""
-"          minimale CPU-Taktfreq. -  maximale CPU-Taktfreq. -  Regler  \n"
+msgstr "          minimale CPU-Frequenz  -  maximale CPU-Frequenz  -  Regler\n"
 
 #: utils/cpufreq-info.c:151
 #, c-format
 msgid "Error while evaluating Boost Capabilities on CPU %d -- are you root?\n"
 msgstr ""
+"Fehler beim Evaluieren der Boost-Fähigkeiten bei CPU %d -- sind Sie root?\n"
 
 #. P state changes via MSR are identified via cpuid 80000007
 #. on Intel and AMD, but we assume boost capable machines can do that
@@ -250,50 +263,50 @@
 #: utils/cpufreq-info.c:161
 #, c-format
 msgid "  boost state support: \n"
-msgstr ""
+msgstr "  Boost-Zustand-Unterstützung: \n"
 
 #: utils/cpufreq-info.c:163
 #, c-format
 msgid "    Supported: %s\n"
-msgstr ""
+msgstr "    Unterstützt: %s\n"
 
 #: utils/cpufreq-info.c:163 utils/cpufreq-info.c:164
 msgid "yes"
-msgstr ""
+msgstr "ja"
 
 #: utils/cpufreq-info.c:163 utils/cpufreq-info.c:164
 msgid "no"
-msgstr ""
+msgstr "nein"
 
 #: utils/cpufreq-info.c:164
-#, fuzzy, c-format
+#, c-format
 msgid "    Active: %s\n"
-msgstr "  Treiber: %s\n"
+msgstr "    Aktiv: %s\n"
 
 #: utils/cpufreq-info.c:177
 #, c-format
 msgid "    Boost States: %d\n"
-msgstr ""
+msgstr "    Boost-Zustände: %d\n"
 
 #: utils/cpufreq-info.c:178
 #, c-format
 msgid "    Total States: %d\n"
-msgstr ""
+msgstr "    Gesamtzustände: %d\n"
 
 #: utils/cpufreq-info.c:181
 #, c-format
 msgid "    Pstate-Pb%d: %luMHz (boost state)\n"
-msgstr ""
+msgstr "    Pstate-Pb%d: %luMHz (Boost-Zustand)\n"
 
 #: utils/cpufreq-info.c:184
 #, c-format
 msgid "    Pstate-P%d:  %luMHz\n"
-msgstr ""
+msgstr "    Pstate-P%d:  %luMHz\n"
 
 #: utils/cpufreq-info.c:211
 #, c-format
 msgid "  no or unknown cpufreq driver is active on this CPU\n"
-msgstr "  kein oder nicht bestimmbarer cpufreq-Treiber aktiv\n"
+msgstr "  kein oder ein unbekannter cpufreq-Treiber ist auf dieser CPU aktiv\n"
 
 #: utils/cpufreq-info.c:213
 #, c-format
@@ -303,12 +316,12 @@
 #: utils/cpufreq-info.c:219
 #, c-format
 msgid "  CPUs which run at the same hardware frequency: "
-msgstr "  Folgende CPUs laufen mit der gleichen Hardware-Taktfrequenz: "
+msgstr "  CPUs, die mit der gleichen Hardwarefrequenz laufen: "
 
 #: utils/cpufreq-info.c:230
 #, c-format
 msgid "  CPUs which need to have their frequency coordinated by software: "
-msgstr "  Die Taktfrequenz folgender CPUs werden per Software koordiniert: "
+msgstr "  CPUs, die ihre Frequenz mit Software koordinieren müssen: "
 
 #: utils/cpufreq-info.c:241
 #, c-format
@@ -318,22 +331,22 @@
 #: utils/cpufreq-info.c:247
 #, c-format
 msgid "  hardware limits: "
-msgstr "  Hardwarebedingte Grenzen der Taktfrequenz: "
+msgstr "  Hardwarebegrenzungen: "
 
 #: utils/cpufreq-info.c:256
 #, c-format
 msgid "  available frequency steps: "
-msgstr "  mögliche Taktfrequenzen: "
+msgstr "  verfügbare Frequenzschritte: "
 
 #: utils/cpufreq-info.c:269
 #, c-format
 msgid "  available cpufreq governors: "
-msgstr "  mögliche Regler: "
+msgstr "  verfügbare cpufreq-Regler: "
 
 #: utils/cpufreq-info.c:280
 #, c-format
 msgid "  current policy: frequency should be within "
-msgstr "  momentane Taktik: die Frequenz soll innerhalb "
+msgstr "  momentane Richtlinie: Frequenz sollte innerhalb "
 
 #: utils/cpufreq-info.c:282
 #, c-format
@@ -346,29 +359,28 @@
 "The governor \"%s\" may decide which speed to use\n"
 "                  within this range.\n"
 msgstr ""
-"  liegen. Der Regler \"%s\" kann frei entscheiden,\n"
-"                    welche Taktfrequenz innerhalb dieser Grenze verwendet "
-"wird.\n"
+"  sein. Der Regler \"%s\" kann frei entscheiden,\n"
+"                    welche Geschwindigkeit er in diesem Bereich verwendet.\n"
 
 #: utils/cpufreq-info.c:293
 #, c-format
 msgid "  current CPU frequency is "
-msgstr "  momentane Taktfrequenz ist "
+msgstr "  momentane CPU-Frequenz ist "
 
 #: utils/cpufreq-info.c:296
 #, c-format
 msgid " (asserted by call to hardware)"
-msgstr "  (verifiziert durch Nachfrage bei der Hardware)"
+msgstr " (durch Aufruf der Hardware sichergestellt)"
 
 #: utils/cpufreq-info.c:304
 #, c-format
 msgid "  cpufreq stats: "
-msgstr "  Statistik:"
+msgstr "  cpufreq-Statistiken: "
 
 #: utils/cpufreq-info.c:472
-#, fuzzy, c-format
+#, c-format
 msgid "Usage: cpupower freqinfo [options]\n"
-msgstr "Aufruf: cpufreq-info [Optionen]\n"
+msgstr "Aufruf: cpupower freqinfo [Optionen]\n"
 
 #: utils/cpufreq-info.c:473 utils/cpufreq-set.c:26 utils/cpupower-set.c:23
 #: utils/cpupower-info.c:22 utils/cpuidle-info.c:148
@@ -377,11 +389,9 @@
 msgstr "Optionen:\n"
 
 #: utils/cpufreq-info.c:474
-#, fuzzy, c-format
+#, c-format
 msgid "  -e, --debug          Prints out debug information [default]\n"
-msgstr ""
-"  -e, --debug          Erzeugt detaillierte Informationen, hilfreich\n"
-"                       zum Aufspüren von Fehlern\n"
+msgstr "  -e, --debug          Gibt Debug-Informationen aus [Standard]\n"
 
 #: utils/cpufreq-info.c:475
 #, c-format
@@ -424,7 +434,7 @@
 #: utils/cpufreq-info.c:482
 #, c-format
 msgid "  -g, --governors      Determines available cpufreq governors *\n"
-msgstr "  -g, --governors      Erzeugt eine Liste mit verfügbaren Reglern *\n"
+msgstr "  -g, --governors      Ermittelt verfügbare cpufreq-Regler *\n"
 
 #: utils/cpufreq-info.c:483
 #, c-format
@@ -449,8 +459,7 @@
 #: utils/cpufreq-info.c:486
 #, c-format
 msgid "  -s, --stats          Shows cpufreq statistics if available\n"
-msgstr ""
-"  -s, --stats          Zeigt, sofern möglich, Statistiken über cpufreq an.\n"
+msgstr "  -s, --stats          Zeigt cpufreq-Statistiken an, falls vorhanden\n"
 
 #: utils/cpufreq-info.c:487
 #, c-format
@@ -464,13 +473,13 @@
 #: utils/cpufreq-info.c:488
 #, c-format
 msgid "  -b, --boost          Checks for turbo or boost modes  *\n"
-msgstr ""
+msgstr "  -b, --boost          Prüft auf Turbo- oder Boost-Modi  *\n"
 
 #: utils/cpufreq-info.c:489
 #, c-format
 msgid ""
-"  -o, --proc           Prints out information like provided by the /proc/"
-"cpufreq\n"
+"  -o, --proc           Prints out information like provided by the "
+"/proc/cpufreq\n"
 "                       interface in 2.4. and early 2.6. kernels\n"
 msgstr ""
 "  -o, --proc           Erzeugt Informationen in einem ähnlichem Format zu "
@@ -509,8 +518,8 @@
 "For the arguments marked with *, omitting the -c or --cpu argument is\n"
 "equivalent to setting it to zero\n"
 msgstr ""
-"Bei den mit * markierten Parametern wird '--cpu 0' angenommen, soweit nicht\n"
-"mittels -c oder --cpu etwas anderes angegeben wird\n"
+"Für die mit * markierten Argumente ist das Weglassen des Arguments\n"
+"-c oder --cpu gleichbedeutend mit der Einstellung auf Null\n"
 
 #: utils/cpufreq-info.c:580
 #, c-format
@@ -525,8 +534,8 @@
 "You can't specify more than one --cpu parameter and/or\n"
 "more than one output-specific argument\n"
 msgstr ""
-"Man kann nicht mehr als einen --cpu-Parameter und/oder mehr als einen\n"
-"informationsspezifischen Parameter gleichzeitig angeben\n"
+"Sie können nicht mehr als einen Parameter --cpu und/oder\n"
+"mehr als ein ausgabespezifisches Argument angeben\n"
 
 #: utils/cpufreq-info.c:600 utils/cpufreq-set.c:82 utils/cpupower-set.c:42
 #: utils/cpupower-info.c:42 utils/cpuidle-info.c:213
@@ -538,17 +547,17 @@
 #, c-format
 msgid "couldn't analyze CPU %d as it doesn't seem to be present\n"
 msgstr ""
-"Konnte nicht die CPU %d analysieren, da sie (scheinbar?) nicht existiert.\n"
+"CPU %d konnte nicht analysiert werden, da sie scheinbar nicht existiert\n"
 
 #: utils/cpufreq-info.c:620 utils/cpupower-info.c:142
 #, c-format
 msgid "analyzing CPU %d:\n"
-msgstr "analysiere CPU %d:\n"
+msgstr "CPU %d wird analysiert:\n"
 
 #: utils/cpufreq-set.c:25
-#, fuzzy, c-format
+#, c-format
 msgid "Usage: cpupower frequency-set [options]\n"
-msgstr "Aufruf: cpufreq-set [Optionen]\n"
+msgstr "Aufruf: cpupower frequency-set [Optionen]\n"
 
 #: utils/cpufreq-set.c:27
 #, c-format
@@ -556,7 +565,7 @@
 "  -d FREQ, --min FREQ      new minimum CPU frequency the governor may "
 "select\n"
 msgstr ""
-"  -d FREQ, --min FREQ      neue minimale Taktfrequenz, die der Regler\n"
+"  -d FREQ, --min FREQ      neue minimale CPU-Frequenz, die der Regler\n"
 "                           auswählen darf\n"
 
 #: utils/cpufreq-set.c:28
@@ -571,7 +580,7 @@
 #: utils/cpufreq-set.c:29
 #, c-format
 msgid "  -g GOV, --governor GOV   new cpufreq governor\n"
-msgstr "  -g GOV, --governors GOV  wechsle zu Regler GOV\n"
+msgstr "  -g GOV, --governors GOV   neuer cpufreq-Regler\n"
 
 #: utils/cpufreq-set.c:30
 #, c-format
@@ -579,29 +588,29 @@
 "  -f FREQ, --freq FREQ     specific frequency to be set. Requires userspace\n"
 "                           governor to be available and loaded\n"
 msgstr ""
-"  -f FREQ, --freq FREQ     setze exakte Taktfrequenz. Benötigt den Regler\n"
-"                           'userspace'.\n"
+"  -f FREQ, --freq FREQ     bestimmte Frequenz, die eingestellt werden soll.\n"
+"                           Erfordert einen verfügbaren und geladenen "
+"userspace-Regler\n"
 
 #: utils/cpufreq-set.c:32
 #, c-format
 msgid "  -r, --related            Switches all hardware-related CPUs\n"
-msgstr ""
-"  -r, --related            Setze Werte für alle CPUs, deren Taktfrequenz\n"
-"                           hardwarebedingt identisch ist.\n"
+msgstr "  -r, --related            Schaltet alle hardwarebezogenen CPUs um\n"
 
 #: utils/cpufreq-set.c:33 utils/cpupower-set.c:28 utils/cpupower-info.c:27
 #, c-format
 msgid "  -h, --help               Prints out this screen\n"
-msgstr "  -h, --help               Gibt diese Kurzübersicht aus\n"
+msgstr "  -h, --help               Gibt diesen Bildschirm aus\n"
 
 #: utils/cpufreq-set.c:35
-#, fuzzy, c-format
+#, c-format
 msgid ""
 "Notes:\n"
 "1. Omitting the -c or --cpu argument is equivalent to setting it to \"all\"\n"
 msgstr ""
-"Bei den mit * markierten Parametern wird '--cpu 0' angenommen, soweit nicht\n"
-"mittels -c oder --cpu etwas anderes angegeben wird\n"
+"Hinweis:\n"
+"1. Das Weglassen des Arguments -c oder --cpu ist gleichbedeutend mit der "
+"Einstellung auf \"all\"\n"
 
 #: utils/cpufreq-set.c:37
 #, fuzzy, c-format
@@ -636,17 +645,21 @@
 "frequency\n"
 "   or because the userspace governor isn't loaded?\n"
 msgstr ""
-"Beim Einstellen ist ein Fehler aufgetreten. Typische Fehlerquellen sind:\n"
-"- nicht ausreichende Rechte (Administrator)\n"
-"- der Regler ist nicht verfügbar bzw. nicht geladen\n"
-"- die angegebene Taktik ist inkorrekt\n"
-"- eine spezifische Frequenz wurde angegeben, aber der Regler 'userspace'\n"
-"  kann entweder hardwarebedingt nicht genutzt werden oder ist nicht geladen\n"
+"Fehler beim Festlegen neuer Werte. Häufige Fehler:\n"
+"- Verfügen Sie über die erforderlichen Administrationsrechte? (Superuser?)\n"
+"- Ist der von Ihnen gewünschte Regler verfügbar und mittels modprobe "
+"geladen?\n"
+"- Versuchen Sie eine ungültige Richtlinie festzulegen?\n"
+"- Versuchen Sie eine bestimmte Frequenz festzulegen, aber der "
+"userspace-Regler ist nicht verfügbar,\n"
+"   z.B. wegen Hardware, die nicht auf eine bestimmte Frequenz eingestellt "
+"werden kann\n"
+"   oder weil der userspace-Regler nicht geladen ist?\n"
 
 #: utils/cpufreq-set.c:170
 #, c-format
 msgid "wrong, unknown or unhandled CPU?\n"
-msgstr "unbekannte oder nicht regelbare CPU\n"
+msgstr "falsche, unbekannte oder nicht regelbare CPU?\n"
 
 #: utils/cpufreq-set.c:302
 #, c-format
@@ -654,8 +667,8 @@
 "the -f/--freq parameter cannot be combined with -d/--min, -u/--max or\n"
 "-g/--governor parameters\n"
 msgstr ""
-"Der -f bzw. --freq-Parameter kann nicht mit den Parametern -d/--min, -u/--"
-"max\n"
+"Der -f bzw. --freq-Parameter kann nicht mit den Parametern -d/--min, "
+"-u/--max\n"
 "oder -g/--governor kombiniert werden\n"
 
 #: utils/cpufreq-set.c:308
@@ -664,18 +677,18 @@
 "At least one parameter out of -f/--freq, -d/--min, -u/--max, and\n"
 "-g/--governor must be passed\n"
 msgstr ""
-"Es muss mindestens ein Parameter aus -f/--freq, -d/--min, -u/--max oder\n"
-"-g/--governor angegeben werden.\n"
+"Mindestens ein Parameter aus -f/--freq, -d/--min, -u/--max und\n"
+"-g/--governor muss übergeben werden\n"
 
 #: utils/cpufreq-set.c:347
 #, c-format
 msgid "Setting cpu: %d\n"
-msgstr ""
+msgstr "CPU einstellen: %d\n"
 
 #: utils/cpupower-set.c:22
 #, c-format
 msgid "Usage: cpupower set [ -b val ] [ -m val ] [ -s val ]\n"
-msgstr ""
+msgstr "Aufruf: cpupower set [ -b val ] [ -m val ] [ -s val ]\n"
 
 #: utils/cpupower-set.c:24
 #, c-format
@@ -689,6 +702,8 @@
 msgid ""
 "  -m, --sched-mc  [VAL]    Sets the kernel's multi core scheduler policy.\n"
 msgstr ""
+"  -m, --sched-mc  [VAL]    Legt die Mehrkern-Scheduler-Richtlinie des "
+"Kernels fest.\n"
 
 #: utils/cpupower-set.c:27
 #, c-format
@@ -700,37 +715,37 @@
 #: utils/cpupower-set.c:80
 #, c-format
 msgid "--perf-bias param out of range [0-%d]\n"
-msgstr ""
+msgstr "--perf-bias-Parameter außerhalb des Bereichs [0-%d]\n"
 
 #: utils/cpupower-set.c:91
 #, c-format
 msgid "--sched-mc param out of range [0-%d]\n"
-msgstr ""
+msgstr "Parameter --sched-mc außerhalb des Bereichs [0-%d]\n"
 
 #: utils/cpupower-set.c:102
 #, c-format
 msgid "--sched-smt param out of range [0-%d]\n"
-msgstr ""
+msgstr "Parameter --sched-smt außerhalb des Bereichs [0-%d]\n"
 
 #: utils/cpupower-set.c:121
 #, c-format
 msgid "Error setting sched-mc %s\n"
-msgstr ""
+msgstr "Fehler beim Einstellen von sched-mc %s\n"
 
 #: utils/cpupower-set.c:127
 #, c-format
 msgid "Error setting sched-smt %s\n"
-msgstr ""
+msgstr "Fehler beim Einstellen von sched-smt %s\n"
 
 #: utils/cpupower-set.c:146
 #, c-format
 msgid "Error setting perf-bias value on CPU %d\n"
-msgstr ""
+msgstr "Fehler beim Einstellen des perf-bias-Wertes auf der CPU %d\n"
 
 #: utils/cpupower-info.c:21
 #, c-format
 msgid "Usage: cpupower info [ -b ] [ -m ] [ -s ]\n"
-msgstr ""
+msgstr "Aufruf: cpupower info [ -b ] [ -m ] [ -s ]\n"
 
 #: utils/cpupower-info.c:23
 #, c-format
@@ -740,9 +755,10 @@
 msgstr ""
 
 #: utils/cpupower-info.c:25
-#, fuzzy, c-format
+#, c-format
 msgid "  -m, --sched-mc     Gets the kernel's multi core scheduler policy.\n"
-msgstr "  -p, --policy         Findet die momentane Taktik heraus *\n"
+msgstr ""
+"  -m, --sched-mc     Ruft die Mehrkern-Scheduler-Richtlinie des Kernels ab.\n"
 
 #: utils/cpupower-info.c:26
 #, c-format
@@ -756,17 +772,20 @@
 "\n"
 "Passing no option will show all info, by default only on core 0\n"
 msgstr ""
+"\n"
+"Wenn Sie keine Option übergeben, werden alle Informationen angezeigt, "
+"standardmäßig nur auf Kern 0\n"
 
 #: utils/cpupower-info.c:102
 #, c-format
 msgid "System's multi core scheduler setting: "
-msgstr ""
+msgstr "Mehrkern-Scheduler-Einstellung des Systems: "
 
 #. if sysfs file is missing it's: errno == ENOENT
 #: utils/cpupower-info.c:105 utils/cpupower-info.c:114
 #, c-format
 msgid "not supported\n"
-msgstr ""
+msgstr "nicht unterstützt\n"
 
 #: utils/cpupower-info.c:111
 #, c-format
@@ -786,164 +805,161 @@
 #: utils/cpupower-info.c:147
 #, c-format
 msgid "Could not read perf-bias value\n"
-msgstr ""
+msgstr "perf-bias-Wert konnte nicht gelesen werden\n"
 
 #: utils/cpupower-info.c:150
 #, c-format
 msgid "perf-bias: %d\n"
-msgstr ""
+msgstr "perf-bias: %d\n"
 
 #: utils/cpuidle-info.c:28
-#, fuzzy, c-format
+#, c-format
 msgid "Analyzing CPU %d:\n"
-msgstr "analysiere CPU %d:\n"
+msgstr "CPU %d wird analysiert:\n"
 
 #: utils/cpuidle-info.c:32
 #, c-format
 msgid "CPU %u: No idle states\n"
-msgstr ""
+msgstr "CPU %u: Keine Ruhezustände\n"
 
 #: utils/cpuidle-info.c:36
 #, c-format
 msgid "CPU %u: Can't read idle state info\n"
-msgstr ""
+msgstr "CPU %u: Ruhezustands-Informationen können nicht gelesen werden\n"
 
 #: utils/cpuidle-info.c:41
 #, c-format
 msgid "Could not determine max idle state %u\n"
-msgstr ""
+msgstr "Max. Ruhezustand %u konnte nicht bestimmt werden\n"
 
 #: utils/cpuidle-info.c:46
 #, c-format
 msgid "Number of idle states: %d\n"
-msgstr ""
+msgstr "Anzahl der Ruhezustände: %d\n"
 
 #: utils/cpuidle-info.c:48
-#, fuzzy, c-format
+#, c-format
 msgid "Available idle states:"
-msgstr "  mögliche Taktfrequenzen: "
+msgstr "Verfügbare Ruhezustände:"
 
 #: utils/cpuidle-info.c:71
 #, c-format
 msgid "Flags/Description: %s\n"
-msgstr ""
+msgstr "Merker/Beschreibung: %s\n"
 
 #: utils/cpuidle-info.c:74
 #, c-format
 msgid "Latency: %lu\n"
-msgstr ""
+msgstr "Latenz: %lu\n"
 
 #: utils/cpuidle-info.c:76
 #, c-format
 msgid "Usage: %lu\n"
-msgstr ""
+msgstr "Aufruf: %lu\n"
 
 #: utils/cpuidle-info.c:78
 #, c-format
 msgid "Duration: %llu\n"
-msgstr ""
+msgstr "Dauer: %llu\n"
 
 #: utils/cpuidle-info.c:90
 #, c-format
 msgid "Could not determine cpuidle driver\n"
-msgstr ""
+msgstr "cpuidle-Treiber konnte nicht bestimmt werden\n"
 
 #: utils/cpuidle-info.c:94
-#, fuzzy, c-format
+#, c-format
 msgid "CPUidle driver: %s\n"
-msgstr "  Treiber: %s\n"
+msgstr "CPUidle-Treiber: %s\n"
 
 #: utils/cpuidle-info.c:99
 #, c-format
 msgid "Could not determine cpuidle governor\n"
-msgstr ""
+msgstr "cpuidle-Regler konnte nicht bestimmt werden\n"
 
 #: utils/cpuidle-info.c:103
 #, c-format
 msgid "CPUidle governor: %s\n"
-msgstr ""
+msgstr "CPUidle-Regler: %s\n"
 
 #: utils/cpuidle-info.c:122
 #, c-format
 msgid "CPU %u: Can't read C-state info\n"
-msgstr ""
+msgstr "CPU %u: C-Zustands-Informationen können nicht gelesen werden\n"
 
 #. printf("Cstates: %d\n", cstates);
 #: utils/cpuidle-info.c:127
 #, c-format
 msgid "active state:            C0\n"
-msgstr ""
+msgstr "aktiver Zustand:            C0\n"
 
 #: utils/cpuidle-info.c:128
 #, c-format
 msgid "max_cstate:              C%u\n"
-msgstr ""
+msgstr "max_cstate:              C%u\n"
 
 #: utils/cpuidle-info.c:129
-#, fuzzy, c-format
+#, c-format
 msgid "maximum allowed latency: %lu usec\n"
-msgstr "  Maximale Dauer eines Taktfrequenzwechsels: "
+msgstr "maximal erlaubte Latenz: %lu usec\n"
 
 #: utils/cpuidle-info.c:130
 #, c-format
 msgid "states:\t\n"
-msgstr ""
+msgstr "Zustände:\t\n"
 
 #: utils/cpuidle-info.c:132
 #, c-format
 msgid "    C%d:                  type[C%d] "
-msgstr ""
+msgstr "    C%d:                  Typ[C%d] "
 
 #: utils/cpuidle-info.c:134
 #, c-format
 msgid "promotion[--] demotion[--] "
-msgstr ""
+msgstr "promotion[--] demotion[--] "
 
 #: utils/cpuidle-info.c:135
 #, c-format
 msgid "latency[%03lu] "
-msgstr ""
+msgstr "Latenz[%03lu] "
 
 #: utils/cpuidle-info.c:137
 #, c-format
 msgid "usage[%08lu] "
-msgstr ""
+msgstr "Aufruf[%08lu] "
 
 #: utils/cpuidle-info.c:139
 #, c-format
 msgid "duration[%020Lu] \n"
-msgstr ""
+msgstr "Dauer[%020Lu] \n"
 
 #: utils/cpuidle-info.c:147
-#, fuzzy, c-format
+#, c-format
 msgid "Usage: cpupower idleinfo [options]\n"
-msgstr "Aufruf: cpufreq-info [Optionen]\n"
+msgstr "Aufruf: cpupower idleinfo [Optionen]\n"
 
 #: utils/cpuidle-info.c:149
-#, fuzzy, c-format
+#, c-format
 msgid "  -s, --silent         Only show general C-state information\n"
 msgstr ""
-"  -e, --debug          Erzeugt detaillierte Informationen, hilfreich\n"
-"                       zum Aufspüren von Fehlern\n"
+"  -s, --silent         Nur allgemeine C-Zustands-Informationen anzeigen\n"
 
 #: utils/cpuidle-info.c:150
-#, fuzzy, c-format
+#, c-format
 msgid ""
-"  -o, --proc           Prints out information like provided by the /proc/"
-"acpi/processor/*/power\n"
+"  -o, --proc           Prints out information like provided by the "
+"/proc/acpi/processor/*/power\n"
 "                       interface in older kernels\n"
 msgstr ""
-"  -o, --proc           Erzeugt Informationen in einem ähnlichem Format zu "
-"dem\n"
-"                       der /proc/cpufreq-Datei in 2.4. und frühen 2.6.\n"
-"                       Kernel-Versionen\n"
+"  -o, --proc           Gibt Informationen so aus, wie sie von der "
+"Schnittstelle\n"
+"                       /proc/acpi/processor/*/power in älteren Kerneln "
+"bereitgestellt werden\n"
 
 #: utils/cpuidle-info.c:209
-#, fuzzy, c-format
+#, c-format
 msgid "You can't specify more than one output-specific argument\n"
-msgstr ""
-"Man kann nicht mehr als einen --cpu-Parameter und/oder mehr als einen\n"
-"informationsspezifischen Parameter gleichzeitig angeben\n"
+msgstr "Sie können nicht mehr als ein ausgabenspezifisches Argument angeben\n"
 
 #~ msgid ""
 #~ "  -c CPU, --cpu CPU    CPU number which information shall be determined "
@@ -956,6 +972,6 @@
 #~ "  -c CPU, --cpu CPU        number of CPU where cpufreq settings shall be "
 #~ "modified\n"
 #~ msgstr ""
-#~ "  -c CPU, --cpu CPU        Nummer der CPU, deren Taktfrequenz-"
-#~ "Einstellung\n"
+#~ "  -c CPU, --cpu CPU        Nummer der CPU, deren "
+#~ "Taktfrequenz-Einstellung\n"
 #~ "                           werden soll\n"
diff --git a/tools/power/cpupower/po/fr.po b/tools/power/cpupower/po/fr.po
index b46ca25..b6e505b 100644
--- a/tools/power/cpupower/po/fr.po
+++ b/tools/power/cpupower/po/fr.po
@@ -95,7 +95,7 @@
 
 #: utils/idle_monitor/cpupower-monitor.c:74
 #, c-format
-msgid "\t -i: time intervall to measure for in seconds (default 1)\n"
+msgid "\t -i: time interval to measure for in seconds (default 1)\n"
 msgstr ""
 
 #: utils/idle_monitor/cpupower-monitor.c:75
diff --git a/tools/power/cpupower/po/it.po b/tools/power/cpupower/po/it.po
index f80c4dd..a1deeb5 100644
--- a/tools/power/cpupower/po/it.po
+++ b/tools/power/cpupower/po/it.po
@@ -95,7 +95,7 @@
 
 #: utils/idle_monitor/cpupower-monitor.c:74
 #, c-format
-msgid "\t -i: time intervall to measure for in seconds (default 1)\n"
+msgid "\t -i: time interval to measure for in seconds (default 1)\n"
 msgstr ""
 
 #: utils/idle_monitor/cpupower-monitor.c:75
diff --git a/tools/power/cpupower/po/pt.po b/tools/power/cpupower/po/pt.po
index 990f526..9021865 100644
--- a/tools/power/cpupower/po/pt.po
+++ b/tools/power/cpupower/po/pt.po
@@ -93,7 +93,7 @@
 
 #: utils/idle_monitor/cpupower-monitor.c:74
 #, c-format
-msgid "\t -i: time intervall to measure for in seconds (default 1)\n"
+msgid "\t -i: time interval to measure for in seconds (default 1)\n"
 msgstr ""
 
 #: utils/idle_monitor/cpupower-monitor.c:75
diff --git a/tools/power/cpupower/utils/cpufreq-info.c b/tools/power/cpupower/utils/cpufreq-info.c
index ccd08dd..e63cf55 100644
--- a/tools/power/cpupower/utils/cpufreq-info.c
+++ b/tools/power/cpupower/utils/cpufreq-info.c
@@ -1,7 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  *  (C) 2004-2009  Dominik Brodowski <linux@dominikbrodowski.de>
- *
- *  Licensed under the terms of the GNU GPL License version 2.
  */
 
 
@@ -161,18 +160,12 @@
 	return;
 }
 
-/* --boost / -b */
-
-static int get_boost_mode(unsigned int cpu)
+static int get_boost_mode_x86(unsigned int cpu)
 {
 	int support, active, b_states = 0, ret, pstate_no, i;
 	/* ToDo: Make this more global */
 	unsigned long pstates[MAX_HW_PSTATES] = {0,};
 
-	if (cpupower_cpu_info.vendor != X86_VENDOR_AMD &&
-	    cpupower_cpu_info.vendor != X86_VENDOR_INTEL)
-		return 0;
-
 	ret = cpufreq_has_boost_support(cpu, &support, &active, &b_states);
 	if (ret) {
 		printf(_("Error while evaluating Boost Capabilities"
@@ -190,8 +183,9 @@
 	printf(_("    Supported: %s\n"), support ? _("yes") : _("no"));
 	printf(_("    Active: %s\n"), active ? _("yes") : _("no"));
 
-	if (cpupower_cpu_info.vendor == X86_VENDOR_AMD &&
-	    cpupower_cpu_info.family >= 0x10) {
+	if ((cpupower_cpu_info.vendor == X86_VENDOR_AMD &&
+	     cpupower_cpu_info.family >= 0x10) ||
+	     cpupower_cpu_info.vendor == X86_VENDOR_HYGON) {
 		ret = decode_pstates(cpu, cpupower_cpu_info.family, b_states,
 				     pstates, &pstate_no);
 		if (ret)
@@ -246,6 +240,33 @@
 	return 0;
 }
 
+/* --boost / -b */
+
+static int get_boost_mode(unsigned int cpu)
+{
+	struct cpufreq_frequencies *freqs;
+
+	if (cpupower_cpu_info.vendor == X86_VENDOR_AMD ||
+	    cpupower_cpu_info.vendor == X86_VENDOR_HYGON ||
+	    cpupower_cpu_info.vendor == X86_VENDOR_INTEL)
+		return get_boost_mode_x86(cpu);
+
+	freqs = cpufreq_get_frequencies("boost", cpu);
+	if (freqs) {
+		printf(_("  boost frequency steps: "));
+		while (freqs->next) {
+			print_speed(freqs->frequency);
+			printf(", ");
+			freqs = freqs->next;
+		}
+		print_speed(freqs->frequency);
+		printf("\n");
+		cpufreq_put_frequencies(freqs);
+	}
+
+	return 0;
+}
+
 /* --freq / -f */
 
 static int get_freq_kernel(unsigned int cpu, unsigned int human)
@@ -454,7 +475,7 @@
 
 static void debug_output_one(unsigned int cpu)
 {
-	struct cpufreq_available_frequencies *freqs;
+	struct cpufreq_frequencies *freqs;
 
 	get_driver(cpu);
 	get_related_cpus(cpu);
@@ -462,7 +483,7 @@
 	get_latency(cpu, 1);
 	get_hardware_limits(cpu, 1);
 
-	freqs = cpufreq_get_available_frequencies(cpu);
+	freqs = cpufreq_get_frequencies("available", cpu);
 	if (freqs) {
 		printf(_("  available frequency steps:  "));
 		while (freqs->next) {
@@ -472,7 +493,7 @@
 		}
 		print_speed(freqs->frequency);
 		printf("\n");
-		cpufreq_put_available_frequencies(freqs);
+		cpufreq_put_frequencies(freqs);
 	}
 
 	get_available_governors(cpu);
diff --git a/tools/power/cpupower/utils/cpufreq-set.c b/tools/power/cpupower/utils/cpufreq-set.c
index 1eef0ae..6ed82fb 100644
--- a/tools/power/cpupower/utils/cpufreq-set.c
+++ b/tools/power/cpupower/utils/cpufreq-set.c
@@ -1,7 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  *  (C) 2004-2009  Dominik Brodowski <linux@dominikbrodowski.de>
- *
- *  Licensed under the terms of the GNU GPL License version 2.
  */
 
 
@@ -306,6 +305,8 @@
 				bitmask_setbit(cpus_chosen, cpus->cpu);
 				cpus = cpus->next;
 			}
+			/* Set the last cpu in related cpus list */
+			bitmask_setbit(cpus_chosen, cpus->cpu);
 			cpufreq_put_related_cpus(cpus);
 		}
 	}
diff --git a/tools/power/cpupower/utils/cpuidle-info.c b/tools/power/cpupower/utils/cpuidle-info.c
index b59c85d..f2b202c 100644
--- a/tools/power/cpupower/utils/cpuidle-info.c
+++ b/tools/power/cpupower/utils/cpuidle-info.c
@@ -1,8 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  *  (C) 2004-2009  Dominik Brodowski <linux@dominikbrodowski.de>
  *  (C) 2010       Thomas Renninger <trenn@suse.de>
- *
- *  Licensed under the terms of the GNU GPL License version 2.
  */
 
 
diff --git a/tools/power/cpupower/utils/cpupower-info.c b/tools/power/cpupower/utils/cpupower-info.c
index c7caa8e..4c9d342 100644
--- a/tools/power/cpupower/utils/cpupower-info.c
+++ b/tools/power/cpupower/utils/cpupower-info.c
@@ -1,7 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  *  (C) 2011 Thomas Renninger <trenn@suse.de>, Novell Inc.
- *
- *  Licensed under the terms of the GNU GPL License version 2.
  */
 
 
diff --git a/tools/power/cpupower/utils/cpupower-set.c b/tools/power/cpupower/utils/cpupower-set.c
index 532f46b..3cd95c6 100644
--- a/tools/power/cpupower/utils/cpupower-set.c
+++ b/tools/power/cpupower/utils/cpupower-set.c
@@ -1,7 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  *  (C) 2011 Thomas Renninger <trenn@suse.de>, Novell Inc.
- *
- *  Licensed under the terms of the GNU GPL License version 2.
  */
 
 
diff --git a/tools/power/cpupower/utils/cpupower.c b/tools/power/cpupower/utils/cpupower.c
index 2dccf49..8e3d080 100644
--- a/tools/power/cpupower/utils/cpupower.c
+++ b/tools/power/cpupower/utils/cpupower.c
@@ -1,8 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  *  (C) 2010,2011       Thomas Renninger <trenn@suse.de>, Novell Inc.
  *
- *  Licensed under the terms of the GNU GPL License version 2.
- *
  *  Ideas taken over from the perf userspace tool (included in the Linus
  *  kernel git repo): subcommand builtins and param parsing.
  */
diff --git a/tools/power/cpupower/utils/helpers/amd.c b/tools/power/cpupower/utils/helpers/amd.c
index 9607ada..7c4f83a 100644
--- a/tools/power/cpupower/utils/helpers/amd.c
+++ b/tools/power/cpupower/utils/helpers/amd.c
@@ -45,7 +45,7 @@
 
 	if (family == 0x12)
 		t = pstate.val & 0xf;
-	else if (family == 0x17)
+	else if (family == 0x17 || family == 0x18)
 		t = pstate.fam17h_bits.did;
 	else
 		t = pstate.bits.did;
@@ -59,7 +59,7 @@
 	int fid, did, cof;
 
 	did = get_did(family, pstate);
-	if (family == 0x17) {
+	if (family == 0x17 || family == 0x18) {
 		fid = pstate.fam17h_bits.fid;
 		cof = 200 * fid / did;
 	} else {
diff --git a/tools/power/cpupower/utils/helpers/cpuid.c b/tools/power/cpupower/utils/helpers/cpuid.c
index 732b0b4..5cc39d4 100644
--- a/tools/power/cpupower/utils/helpers/cpuid.c
+++ b/tools/power/cpupower/utils/helpers/cpuid.c
@@ -8,7 +8,7 @@
 #include "helpers/helpers.h"
 
 static const char *cpu_vendor_table[X86_VENDOR_MAX] = {
-	"Unknown", "GenuineIntel", "AuthenticAMD",
+	"Unknown", "GenuineIntel", "AuthenticAMD", "HygonGenuine",
 };
 
 #if defined(__i386__) || defined(__x86_64__)
@@ -109,6 +109,7 @@
 	fclose(fp);
 	/* Get some useful CPU capabilities from cpuid */
 	if (cpu_info->vendor != X86_VENDOR_AMD &&
+	    cpu_info->vendor != X86_VENDOR_HYGON &&
 	    cpu_info->vendor != X86_VENDOR_INTEL)
 		return ret;
 
@@ -124,8 +125,9 @@
 	if (cpuid_level >= 6 && (cpuid_ecx(6) & 0x1))
 		cpu_info->caps |= CPUPOWER_CAP_APERF;
 
-	/* AMD Boost state enable/disable register */
-	if (cpu_info->vendor == X86_VENDOR_AMD) {
+	/* AMD or Hygon Boost state enable/disable register */
+	if (cpu_info->vendor == X86_VENDOR_AMD ||
+	    cpu_info->vendor == X86_VENDOR_HYGON) {
 		if (ext_cpuid_level >= 0x80000007 &&
 		    (cpuid_edx(0x80000007) & (1 << 9)))
 			cpu_info->caps |= CPUPOWER_CAP_AMD_CBP;
diff --git a/tools/power/cpupower/utils/helpers/helpers.h b/tools/power/cpupower/utils/helpers/helpers.h
index 41da392..357b19b 100644
--- a/tools/power/cpupower/utils/helpers/helpers.h
+++ b/tools/power/cpupower/utils/helpers/helpers.h
@@ -1,8 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
 /*
  *  (C) 2010,2011       Thomas Renninger <trenn@suse.de>, Novell Inc.
  *
- *  Licensed under the terms of the GNU GPL License version 2.
- *
  * Miscellaneous helpers which do not fit or are worth
  * to put into separate headers
  */
@@ -61,7 +60,7 @@
 
 /* cpuid and cpuinfo helpers  **************************/
 enum cpupower_cpu_vendor {X86_VENDOR_UNKNOWN = 0, X86_VENDOR_INTEL,
-			  X86_VENDOR_AMD, X86_VENDOR_MAX};
+			  X86_VENDOR_AMD, X86_VENDOR_HYGON, X86_VENDOR_MAX};
 
 #define CPUPOWER_CAP_INV_TSC		0x00000001
 #define CPUPOWER_CAP_APERF		0x00000002
diff --git a/tools/power/cpupower/utils/helpers/misc.c b/tools/power/cpupower/utils/helpers/misc.c
index 80fdf55..f406adc 100644
--- a/tools/power/cpupower/utils/helpers/misc.c
+++ b/tools/power/cpupower/utils/helpers/misc.c
@@ -26,7 +26,7 @@
 		 * has Hardware determined variable increments instead.
 		 */
 
-		if (cpu_info.family == 0x17) {
+		if (cpu_info.family == 0x17 || cpu_info.family == 0x18) {
 			if (!read_msr(cpu, MSR_AMD_HWCR, &val)) {
 				if (!(val & CPUPOWER_AMD_CPBDIS))
 					*active = 1;
diff --git a/tools/power/cpupower/utils/helpers/sysfs.c b/tools/power/cpupower/utils/helpers/sysfs.c
index 4e8fe2c..e13ff38 100644
--- a/tools/power/cpupower/utils/helpers/sysfs.c
+++ b/tools/power/cpupower/utils/helpers/sysfs.c
@@ -1,8 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  *  (C) 2004-2009  Dominik Brodowski <linux@dominikbrodowski.de>
  *  (C) 2011       Thomas Renninger <trenn@novell.com> Novell Inc.
- *
- *  Licensed under the terms of the GNU GPL License version 2.
  */
 
 #include <stdio.h>
diff --git a/tools/power/cpupower/utils/helpers/topology.c b/tools/power/cpupower/utils/helpers/topology.c
index a1a6c60..3dd0925 100644
--- a/tools/power/cpupower/utils/helpers/topology.c
+++ b/tools/power/cpupower/utils/helpers/topology.c
@@ -1,8 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  *  (C) 2010,2011       Thomas Renninger <trenn@suse.de>, Novell Inc.
  *
- *  Licensed under the terms of the GNU GPL License version 2.
- *
  * ToDo: Needs to be done more properly for AMD/Intel specifics
  */
 
diff --git a/tools/power/cpupower/utils/idle_monitor/amd_fam14h_idle.c b/tools/power/cpupower/utils/idle_monitor/amd_fam14h_idle.c
index 2116df9..3f893b9 100644
--- a/tools/power/cpupower/utils/idle_monitor/amd_fam14h_idle.c
+++ b/tools/power/cpupower/utils/idle_monitor/amd_fam14h_idle.c
@@ -1,8 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  *  (C) 2010,2011      Thomas Renninger <trenn@suse.de>, Novell Inc.
  *
- *  Licensed under the terms of the GNU GPL License version 2.
- *
  *  PCI initialization based on example code from:
  *  Andreas Herrmann <andreas.herrmann3@amd.com>
  */
diff --git a/tools/power/cpupower/utils/idle_monitor/cpuidle_sysfs.c b/tools/power/cpupower/utils/idle_monitor/cpuidle_sysfs.c
index 5b8c495..f634aeb 100644
--- a/tools/power/cpupower/utils/idle_monitor/cpuidle_sysfs.c
+++ b/tools/power/cpupower/utils/idle_monitor/cpuidle_sysfs.c
@@ -1,8 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  *  (C) 2010,2011       Thomas Renninger <trenn@suse.de>, Novell Inc
- *
- *  Licensed under the terms of the GNU GPL License version 2.
- *
  */
 
 #include <stdio.h>
diff --git a/tools/power/cpupower/utils/idle_monitor/cpupower-monitor.c b/tools/power/cpupower/utils/idle_monitor/cpupower-monitor.c
index 051da0a..d3c3e6e 100644
--- a/tools/power/cpupower/utils/idle_monitor/cpupower-monitor.c
+++ b/tools/power/cpupower/utils/idle_monitor/cpupower-monitor.c
@@ -1,10 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  *  (C) 2010,2011       Thomas Renninger <trenn@suse.de>, Novell Inc.
  *
- *  Licensed under the terms of the GNU GPL License version 2.
- *
  *  Output format inspired by Len Brown's <lenb@kernel.org> turbostat tool.
- *
  */
 
 
diff --git a/tools/power/cpupower/utils/idle_monitor/cpupower-monitor.h b/tools/power/cpupower/utils/idle_monitor/cpupower-monitor.h
index 2ae50b4..a2d901d 100644
--- a/tools/power/cpupower/utils/idle_monitor/cpupower-monitor.h
+++ b/tools/power/cpupower/utils/idle_monitor/cpupower-monitor.h
@@ -1,8 +1,6 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
 /*
  *  (C) 2010,2011       Thomas Renninger <trenn@suse.de>, Novell Inc.
- *
- *  Licensed under the terms of the GNU GPL License version 2.
- *
  */
 
 #ifndef __CPUIDLE_INFO_HW__
diff --git a/tools/power/cpupower/utils/idle_monitor/hsw_ext_idle.c b/tools/power/cpupower/utils/idle_monitor/hsw_ext_idle.c
index f794d6b..7c7451d 100644
--- a/tools/power/cpupower/utils/idle_monitor/hsw_ext_idle.c
+++ b/tools/power/cpupower/utils/idle_monitor/hsw_ext_idle.c
@@ -1,8 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  *  (C) 2010,2011       Thomas Renninger <trenn@suse.de>, Novell Inc.
  *
- *  Licensed under the terms of the GNU GPL License version 2.
- *
  *  Based on SandyBridge monitor. Implements the new package C-states
  *  (PC8, PC9, PC10) coming with a specific Haswell (family 0x45) CPU.
  */
diff --git a/tools/power/cpupower/utils/idle_monitor/idle_monitors.h b/tools/power/cpupower/utils/idle_monitor/idle_monitors.h
index 4fcdeb1..e9e567e 100644
--- a/tools/power/cpupower/utils/idle_monitor/idle_monitors.h
+++ b/tools/power/cpupower/utils/idle_monitor/idle_monitors.h
@@ -1,10 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
 /*
  *  (C) 2010,2011       Thomas Renninger <trenn@suse.de>, Novell Inc.
  *
- *  Licensed under the terms of the GNU GPL License version 2.
- *
  *  Based on the idea from Michael Matz <matz@suse.de>
- *
  */
 
 #ifndef _CPUIDLE_IDLE_MONITORS_H_
diff --git a/tools/power/cpupower/utils/idle_monitor/mperf_monitor.c b/tools/power/cpupower/utils/idle_monitor/mperf_monitor.c
index d7c2a6d..44806a6 100644
--- a/tools/power/cpupower/utils/idle_monitor/mperf_monitor.c
+++ b/tools/power/cpupower/utils/idle_monitor/mperf_monitor.c
@@ -1,7 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  *  (C) 2010,2011       Thomas Renninger <trenn@suse.de>, Novell Inc.
- *
- *  Licensed under the terms of the GNU GPL License version 2.
  */
 
 #if defined(__i386__) || defined(__x86_64__)
@@ -241,7 +240,8 @@
 	if (!(cpupower_cpu_info.caps & CPUPOWER_CAP_INV_TSC))
 		goto use_sysfs;
 
-	if (cpupower_cpu_info.vendor == X86_VENDOR_AMD) {
+	if (cpupower_cpu_info.vendor == X86_VENDOR_AMD ||
+	    cpupower_cpu_info.vendor == X86_VENDOR_HYGON) {
 		/* MSR_AMD_HWCR tells us whether TSC runs at P0/mperf
 		 * freq.
 		 * A test whether hwcr is accessable/available would be:
diff --git a/tools/power/cpupower/utils/idle_monitor/nhm_idle.c b/tools/power/cpupower/utils/idle_monitor/nhm_idle.c
index abf8cb5..be72566 100644
--- a/tools/power/cpupower/utils/idle_monitor/nhm_idle.c
+++ b/tools/power/cpupower/utils/idle_monitor/nhm_idle.c
@@ -1,8 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  *  (C) 2010,2011       Thomas Renninger <trenn@suse.de>, Novell Inc.
  *
- *  Licensed under the terms of the GNU GPL License version 2.
- *
  *  Based on Len Brown's <lenb@kernel.org> turbostat tool.
  */
 
diff --git a/tools/power/cpupower/utils/idle_monitor/snb_idle.c b/tools/power/cpupower/utils/idle_monitor/snb_idle.c
index a2b4521..9683335 100644
--- a/tools/power/cpupower/utils/idle_monitor/snb_idle.c
+++ b/tools/power/cpupower/utils/idle_monitor/snb_idle.c
@@ -1,8 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  *  (C) 2010,2011       Thomas Renninger <trenn@suse.de>, Novell Inc.
  *
- *  Licensed under the terms of the GNU GPL License version 2.
- *
  *  Based on Len Brown's <lenb@kernel.org> turbostat tool.
  */
 
diff --git a/tools/power/pm-graph/Makefile b/tools/power/pm-graph/Makefile
index c1899cd..8455415 100644
--- a/tools/power/pm-graph/Makefile
+++ b/tools/power/pm-graph/Makefile
@@ -23,8 +23,8 @@
 	install -m 644 config/suspend-x2-proc.cfg $(DESTDIR)$(PREFIX)/lib/pm-graph/config
 
 	install -d  $(DESTDIR)$(PREFIX)/bin
-	ln -s $(DESTDIR)$(PREFIX)/lib/pm-graph/bootgraph.py $(DESTDIR)$(PREFIX)/bin/bootgraph
-	ln -s $(DESTDIR)$(PREFIX)/lib/pm-graph/sleepgraph.py $(DESTDIR)$(PREFIX)/bin/sleepgraph
+	ln -s ../lib/pm-graph/bootgraph.py $(DESTDIR)$(PREFIX)/bin/bootgraph
+	ln -s ../lib/pm-graph/sleepgraph.py $(DESTDIR)$(PREFIX)/bin/sleepgraph
 
 	install -d  $(DESTDIR)$(PREFIX)/share/man/man8
 	install bootgraph.8 $(DESTDIR)$(PREFIX)/share/man/man8
diff --git a/tools/power/pm-graph/README b/tools/power/pm-graph/README
new file mode 100644
index 0000000..96259f6
--- /dev/null
+++ b/tools/power/pm-graph/README
@@ -0,0 +1,556 @@
+                     p m - g r a p h
+
+   pm-graph: suspend/resume/boot timing analysis tools
+    Version: 5.5
+     Author: Todd Brandt <todd.e.brandt@intel.com>
+  Home Page: https://01.org/pm-graph
+
+ Report bugs/issues at bugzilla.kernel.org Tools/pm-graph
+	- https://bugzilla.kernel.org/buglist.cgi?component=pm-graph&product=Tools
+
+ Full documentation available online & in man pages
+	- Getting Started:
+	  https://01.org/pm-graph/documentation/getting-started
+
+	- Config File Format:
+	  https://01.org/pm-graph/documentation/3-config-file-format
+
+	- upstream version in git:
+	  https://github.com/intel/pm-graph/
+
+ Requirements:
+	- runs with python2 or python3, choice is made by /usr/bin/python link
+	- python2 now requires python-configparser be installed
+
+ Table of Contents
+	- Overview
+	- Setup
+	- Usage
+		- Basic Usage
+		- Dev Mode Usage
+		- Proc Mode Usage
+	- Configuration Files
+		- Usage Examples
+		- Config File Options
+	- Custom Timeline Entries
+		- Adding/Editing Timeline Functions
+		- Adding/Editing Dev Timeline Source Functions
+		- Verifying your Custom Functions
+	- Testing on consumer linux Operating Systems
+		- Android
+
+------------------------------------------------------------------
+|                          OVERVIEW                              |
+------------------------------------------------------------------
+
+ This tool suite is designed to assist kernel and OS developers in optimizing
+ their linux stack's suspend/resume & boot time. Using a kernel image built
+ with a few extra options enabled, the tools will execute a suspend or boot,
+ and will capture dmesg and ftrace data. This data is transformed into a set of
+ timelines and a callgraph to give a quick and detailed view of which devices
+ and kernel processes are taking the most time in suspend/resume & boot.
+
+------------------------------------------------------------------
+|                            SETUP                               |
+------------------------------------------------------------------
+
+    These packages are required to execute the scripts
+       - python
+       - python-requests
+
+       Ubuntu:
+          sudo apt-get install python python-requests
+
+       Fedora:
+          sudo dnf install python python-requests
+
+    The tools can most easily be installed via git clone and make install
+
+    $> git clone http://github.com/intel/pm-graph.git
+    $> cd pm-graph
+    $> sudo make install
+    $> man sleepgraph ; man bootgraph
+
+    Setup involves some minor kernel configuration
+
+    The following kernel build options are required for all kernels:
+        CONFIG_DEVMEM=y
+        CONFIG_PM_DEBUG=y
+        CONFIG_PM_SLEEP_DEBUG=y
+        CONFIG_FTRACE=y
+        CONFIG_FUNCTION_TRACER=y
+        CONFIG_FUNCTION_GRAPH_TRACER=y
+        CONFIG_KPROBES=y
+        CONFIG_KPROBES_ON_FTRACE=y
+
+	In kernel 3.15.0, two patches were upstreamed which enable the
+        v3.0 behavior. These patches allow the tool to read all the
+        data from trace events instead of from dmesg. You can enable
+        this behavior on earlier kernels with these patches:
+
+        (kernel/pre-3.15/enable_trace_events_suspend_resume.patch)
+        (kernel/pre-3.15/enable_trace_events_device_pm_callback.patch)
+
+	If you're using a kernel older than 3.15.0, the following
+        additional kernel parameters are required:
+        (e.g. in file /etc/default/grub)
+        GRUB_CMDLINE_LINUX_DEFAULT="... initcall_debug log_buf_len=32M ..."
+
+	If you're using a kernel older than 3.11-rc2, the following simple
+		patch must be applied to enable ftrace data:
+        in file: kernel/power/suspend.c
+        in function: int suspend_devices_and_enter(suspend_state_t state)
+        remove call to "ftrace_stop();"
+        remove call to "ftrace_start();"
+
+        There is a patch which does this for kernel v3.8.0:
+        (kernel/pre-3.11-rc2/enable_ftrace_in_suspendresume.patch)
+
+
+
+------------------------------------------------------------------
+|                            USAGE                               |
+------------------------------------------------------------------
+
+Basic Usage
+___________
+
+ 1) First configure a kernel using the instructions from the previous sections.
+    Then build, install, and boot with it.
+ 2) Open up a terminal window and execute the mode list command:
+
+	%> sudo ./sleepgraph.py -modes
+		['freeze', 'mem', 'disk']
+
+ Execute a test using one of the available power modes, e.g. mem (S3):
+
+	%> sudo ./sleepgraph.py -m mem -rtcwake 15
+
+		or with a config file
+
+	%> sudo ./sleepgraph.py -config config/suspend.cfg
+
+ When the system comes back you'll see the script finishing up and
+ creating the output files in the test subdir. It generates output
+ files in subdirectory: suspend-mmddyy-HHMMSS. The ftrace file can
+ be used to regenerate the html timeline with different options
+
+     HTML output:                    <hostname>_<mode>.html
+     raw dmesg output:               <hostname>_<mode>_dmesg.txt
+     raw ftrace output:              <hostname>_<mode>_ftrace.txt
+
+ View the html in firefox or chrome.
+
+
+Dev Mode Usage
+______________
+
+ Developer mode adds information on low level source calls to the timeline.
+ The tool sets kprobes on all delay and mutex calls to see which devices
+ are waiting for something and when. It also sets a suite of kprobes on
+ subsystem dependent calls to better fill out the timeline.
+
+ The tool will also expose kernel threads that don't normally show up in the
+ timeline. This is useful in discovering dependent threads to get a better
+ idea of what each device is waiting for. For instance, the scsi_eh thread,
+ a.k.a. scsi resume error handler, is what each SATA disk device waits for
+ before it can continue resume.
+
+ The timeline will be much larger if run with dev mode, so it can be useful
+ to set the -mindev option to clip out any device blocks that are too small
+ to see easily. The following command will give a nice dev mode run:
+
+ %> sudo ./sleepgraph.py -m mem -rtcwake 15 -mindev 1 -dev
+
+	or with a config file
+
+ %> sudo ./sleepgraph.py -config config/suspend-dev.cfg
+
+
+Proc Mode Usage
+_______________
+
+ Proc mode adds user process info to the timeline. This is done in a manner
+ similar to the bootchart utility, which graphs init processes and their
+ execution as the system boots. This tool option does the same thing but for
+ the period before and after suspend/resume.
+
+ In order to see any process info, there needs to be some delay before or
+ after resume since processes are frozen in suspend_prepare and thawed in
+ resume_complete. The predelay and postdelay args allow you to do this. It
+ can also be useful to run in x2 mode with an x2 delay, this way you can
+ see process activity before and after resume, and in between two
+ successive suspend/resumes.
+
+ The command can be run like this:
+
+ %> sudo ./sleepgraph.py -m mem -rtcwake 15 -x2 -x2delay 1000 -predelay 1000 -postdelay 1000 -proc
+
+	or with a config file
+
+ %> sudo ./sleepgraph.py -config config/suspend-proc.cfg
+
+
+------------------------------------------------------------------
+|                    CONFIGURATION FILES                         |
+------------------------------------------------------------------
+
+ Since 4.0 we've moved to using config files in lieu of command line options.
+ The config folder contains a collection of typical use cases.
+ There are corresponding configs for other power modes:
+
+	Simple suspend/resume with basic timeline (mem/freeze/standby)
+		config/suspend.cfg
+		config/freeze.cfg
+		config/standby.cfg
+
+	Dev mode suspend/resume with dev timeline (mem/freeze/standby)
+		config/suspend-dev.cfg
+		config/freeze-dev.cfg
+		config/standby-dev.cfg
+
+	Simple suspend/resume with timeline and callgraph (mem/freeze/standby)
+		config/suspend-callgraph.cfg
+		config/freeze-callgraph.cfg
+		config/standby-callgraph.cfg
+
+	Sample proc mode x2 run using mem suspend
+		config/suspend-x2-proc.cfg
+
+	Sample for editing timeline funcs (moves internal functions into config)
+		config/custom-timeline-functions.cfg
+
+	Sample debug config for serio subsystem
+		config/debug-serio-suspend.cfg
+
+
+Usage Examples
+______________
+
+ Run a simple mem suspend:
+ %> sudo ./sleepgraph.py -config config/suspend.cfg
+
+ Run a mem suspend with callgraph data:
+ %> sudo ./sleepgraph.py -config config/suspend-callgraph.cfg
+
+ Run a mem suspend with dev mode detail:
+ %> sudo ./sleepgraph.py -config config/suspend-dev.cfg
+
+
+Config File Options
+___________________
+
+ [Settings]
+
+ # Verbosity: print verbose messages (def: false)
+ verbose: false
+
+ # Suspend Mode: e.g. standby, mem, freeze, disk (def: mem)
+ mode: mem
+
+ # Output Directory Format: {hostname}, {date}, {time} give current values
+ output-dir: suspend-{hostname}-{date}-{time}
+
+ # Automatic Wakeup: use rtcwake to wakeup after X seconds (def: infinity)
+ rtcwake: 15
+
+ # Add Logs: add the dmesg and ftrace log to the html output (def: false)
+ addlogs: false
+
+ # Sus/Res Gap: insert a gap between sus & res in the timeline (def: false)
+ srgap: false
+
+ # Custom Command: Command to execute in lieu of suspend (def: "")
+ command: echo mem > /sys/power/state
+
+ # Proc mode: graph user processes and cpu usage in the timeline (def: false)
+ proc: false
+
+ # Dev mode: graph source functions in the timeline (def: false)
+ dev: false
+
+ # Suspend/Resume x2: run 2 suspend/resumes back to back (def: false)
+ x2: false
+
+ # x2 Suspend Delay: time delay between the two test runs in ms (def: 0 ms)
+ x2delay: 0
+
+ # Pre Suspend Delay: nclude an N ms delay before (1st) suspend (def: 0 ms)
+ predelay: 0
+
+ # Post Resume Delay: include an N ms delay after (last) resume (def: 0 ms)
+ postdelay: 0
+
+ # Min Device Length: graph only dev callbacks longer than min (def: 0.001 ms)
+ mindev: 0.001
+
+ # Callgraph: gather ftrace callgraph data on all timeline events (def: false)
+ callgraph: false
+
+ # Expand Callgraph: pre-expand the callgraph treeviews in html (def: false)
+ expandcg: false
+
+ # Min Callgraph Length: show callgraphs only if longer than min (def: 1 ms)
+ mincg: 1
+
+ # Timestamp Precision: number of sig digits in timestamps (0:S, [3:ms], 6:us)
+ timeprec: 3
+
+ # Device Filter: show only devs whose name/driver includes one of these strings
+ devicefilter: _cpu_up,_cpu_down,i915,usb
+
+ # Override default timeline entries:
+ # Do not use the internal default functions for timeline entries (def: false)
+ # Set this to true if you intend to only use the ones defined in the config
+ override-timeline-functions: true
+
+ # Override default dev timeline entries:
+ # Do not use the internal default functions for dev timeline entries (def: false)
+ # Set this to true if you intend to only use the ones defined in the config
+ override-dev-timeline-functions: true
+
+ # Call Loop Max Gap (dev mode only)
+ # merge loops of the same call if each is less than maxgap apart (def: 100us)
+ callloop-maxgap: 0.0001
+
+ # Call Loop Max Length (dev mode only)
+ # merge loops of the same call if each is less than maxlen in length (def: 5ms)
+ callloop-maxlen: 0.005
+
+------------------------------------------------------------------
+|                   CUSTOM TIMELINE ENTRIES                      |
+------------------------------------------------------------------
+
+Adding or Editing Timeline Functions
+____________________________________
+
+ The tool uses an array of function names to fill out empty spaces in the
+ timeline where device callbacks don't appear. For instance, in suspend_prepare
+ the tool adds the sys_sync and freeze_processes calls as virtual device blocks
+ in the timeline to show you where the time is going. These calls should fill
+ the timeline with contiguous data so that most kernel execution is covered.
+
+ It is possible to add new function calls to the timeline by adding them to
+ the config. It's also possible to copy the internal timeline functions into
+ the config so that you can override and edit them. Place them in the
+ timeline_functions_ARCH section with the name of your architecture appended.
+ i.e. for x86_64: [timeline_functions_x86_64]
+
+ Use the override-timeline-functions option if you only want to use your
+ custom calls, or leave it false to append them to the internal ones.
+
+ This section includes a list of functions (set using kprobes) which use both
+ symbol data and function arg data. The args are pulled directly from the
+ stack using this architecture's registers and stack formatting. Each entry
+ can include up to four pieces of info: The function name, a format string,
+ an argument list, and a color. But only a function name is required.
+
+ For a full example config, see config/custom-timeline-functions.cfg. It pulls
+ all the internal timeline functions into the config and allows you to edit
+ them.
+
+  Entry format:
+
+    function: format{fn_arg1}_{fn_arg2} fn_arg1 fn_arg2 ... [color=purple]
+
+  Required Arguments:
+
+    function: The symbol name for the function you want probed, this is the
+              minimum required for an entry, it will show up as the function
+              name with no arguments.
+
+        example: _cpu_up:
+
+  Optional Arguments:
+
+    format: The format to display the data on the timeline in. Use braces to
+            enclose the arg names.
+
+        example: CPU_ON[{cpu}]
+
+    color: The color of the entry block in the timeline. The default color is
+           transparent, so the entry shares the phase color. The color is an
+           html color string, either a word, or an RGB.
+
+        example: [color=#CC00CC]
+
+    arglist: A list of arguments from registers/stack addresses. See URL:
+             https://www.kernel.org/doc/Documentation/trace/kprobetrace.txt
+
+        example: cpu=%di:s32
+
+ Here is a full example entry. It displays cpu resume calls in the timeline
+ in orange. They will appear as CPU_ON[0], CPU_ON[1], etc.
+
+  [timeline_functions_x86_64]
+  _cpu_up: CPU_ON[{cpu}] cpu=%di:s32 [color=orange]
+
+
+Adding or Editing Dev Mode Timeline Source Functions
+____________________________________________________
+
+ In dev mode, the tool uses an array of function names to monitor source
+ execution within the timeline entries.
+
+ The function calls are displayed inside the main device/call blocks in the
+ timeline. However, if a function call is not within a main timeline event,
+ it will spawn an entirely new event named after the caller's kernel thread.
+ These asynchronous kernel threads will populate in a separate section
+ beneath the main device/call section.
+
+ The tool has a set of hard coded calls which focus on the most common use
+ cases: msleep, udelay, schedule_timeout, mutex_lock_slowpath, etc. These are
+ the functions that add a hardcoded time delay to the suspend/resume path.
+ The tool also includes some common functions native to important
+ subsystems: ata, i915, and ACPI, etc.
+
+ It is possible to add new function calls to the dev timeline by adding them
+ to the config. It's also possible to copy the internal dev timeline
+ functions into the config so that you can override and edit them. Place them
+ in the dev_timeline_functions_ARCH section with the name of your architecture
+ appended. i.e. for x86_64: [dev_timeline_functions_x86_64]
+
+ Use the override-dev-timeline-functions option if you only want to use your
+ custom calls, or leave it false to append them to the internal ones.
+
+ The format is the same as the timeline_functions_x86_64 section. It's a
+ list of functions (set using kprobes) which use both symbol data and function
+ arg data. The args are pulled directly from the stack using this
+ architecture's registers and stack formatting. Each entry can include up
+ to four pieces of info: The function name, a format string, an argument list,
+ and a color. But only the function name is required.
+
+ For a full example config, see config/custom-timeline-functions.cfg. It pulls
+ all the internal dev timeline functions into the config and allows you to edit
+ them.
+
+ Here is a full example entry. It displays the ATA port reset calls as
+ ataN_port_reset in the timeline. This is where most of the SATA disk resume
+ time goes, so it can be helpful to see the low level call.
+
+  [dev_timeline_functions_x86_64]
+  ata_eh_recover: ata{port}_port_reset port=+36(%di):s32 [color=#CC00CC]
+
+
+Verifying your custom functions
+_______________________________
+
+ Once you have a set of functions (kprobes) defined, it can be useful to
+ perform a quick check to see if you formatted them correctly and if the system
+ actually supports them. To do this, run the tool with your config file
+ and the -status option. The tool will go through all the kprobes (both
+ custom and internal if you haven't overridden them) and actually attempts
+ to set them in ftrace. It will then print out success or fail for you.
+
+ Note that kprobes which don't actually exist in the kernel won't stop the
+ tool, they just wont show up.
+
+ For example:
+
+ sudo ./sleepgraph.py -config config/custom-timeline-functions.cfg -status
+ Checking this system (myhostname)...
+    have root access: YES
+    is sysfs mounted: YES
+    is "mem" a valid power mode: YES
+    is ftrace supported: YES
+    are kprobes supported: YES
+    timeline data source: FTRACE (all trace events found)
+    is rtcwake supported: YES
+    verifying timeline kprobes work:
+         _cpu_down: YES
+         _cpu_up: YES
+         acpi_pm_finish: YES
+         acpi_pm_prepare: YES
+         freeze_kernel_threads: YES
+         freeze_processes: YES
+         sys_sync: YES
+         thaw_processes: YES
+    verifying dev kprobes work:
+         __const_udelay: YES
+         __mutex_lock_slowpath: YES
+         acpi_os_stall: YES
+         acpi_ps_parse_aml: YES
+         intel_opregion_init: NO
+         intel_opregion_register: NO
+         intel_opregion_setup: NO
+         msleep: YES
+         schedule_timeout: YES
+         schedule_timeout_uninterruptible: YES
+         usleep_range: YES
+
+
+------------------------------------------------------------------
+|           TESTING ON CONSUMER LINUX OPERATING SYSTEMS          |
+------------------------------------------------------------------
+
+Android
+_______
+
+ The easiest way to execute on an android device is to run the android.sh
+ script on the device, then pull the ftrace log back to the host and run
+ sleepgraph.py on it.
+
+ Here are the steps:
+
+ [download and install the tool on the device]
+
+	host%> wget https://raw.githubusercontent.com/intel/pm-graph/master/tools/android.sh
+	host%> adb connect 192.168.1.6
+	host%> adb root
+	# push the script to a writeable location
+	host%> adb push android.sh /sdcard/
+
+ [check whether the tool will run on your device]
+
+	host%> adb shell
+	dev%> cd /sdcard
+	dev%> sh android.sh status
+		host    : asus_t100
+		kernel  : 3.14.0-i386-dirty
+		modes   : freeze mem
+		rtcwake : supported
+		ftrace  : supported
+		trace events {
+		    suspend_resume: found
+		    device_pm_callback_end: found
+		    device_pm_callback_start: found
+		}
+	# the above is what you see on a system that's properly patched
+
+ [execute the suspend]
+
+	# NOTE: The suspend will only work if the screen isn't timed out,
+	# so you have to press some keys first to wake it up b4 suspend)
+	dev%> sh android.sh suspend mem
+	------------------------------------
+	Suspend/Resume timing test initiated
+	------------------------------------
+	hostname   : asus_t100
+	kernel     : 3.14.0-i386-dirty
+	mode       : mem
+	ftrace out : /mnt/shell/emulated/0/ftrace.txt
+	dmesg out  : /mnt/shell/emulated/0/dmesg.txt
+	log file   : /mnt/shell/emulated/0/log.txt
+	------------------------------------
+	INITIALIZING FTRACE........DONE
+	STARTING FTRACE
+	SUSPEND START @ 21:24:02 (rtcwake in 10 seconds)
+	<adb connection will now terminate>
+
+ [retrieve the data from the device]
+
+	# I find that you have to actually kill the adb process and
+	# reconnect sometimes in order for the connection to work post-suspend
+	host%> adb connect 192.168.1.6
+	# (required) get the ftrace data, this is the most important piece
+	host%> adb pull /sdcard/ftrace.txt
+	# (optional) get the dmesg data, this is for debugging
+	host%> adb pull /sdcard/dmesg.txt
+	# (optional) get the log, which just lists some test times for comparison
+	host%> adb pull /sdcard/log.txt
+
+ [create an output html file using sleepgraph.py]
+
+	host%> sleepgraph.py -ftrace ftrace.txt
+
+ You should now have an output.html with the android data, enjoy!
diff --git a/tools/power/pm-graph/bootgraph.py b/tools/power/pm-graph/bootgraph.py
index 8ee626c..d3b99a1 100755
--- a/tools/power/pm-graph/bootgraph.py
+++ b/tools/power/pm-graph/bootgraph.py
@@ -1,4 +1,5 @@
-#!/usr/bin/python2
+#!/usr/bin/python
+# SPDX-License-Identifier: GPL-2.0-only
 #
 # Tool for analyzing boot timing
 # Copyright (c) 2013, Intel Corporation.
@@ -34,6 +35,10 @@
 from subprocess import call, Popen, PIPE
 import sleepgraph as aslib
 
+def pprint(msg):
+	print(msg)
+	sys.stdout.flush()
+
 # ----------------- CLASSES --------------------
 
 # Class: SystemValues
@@ -85,7 +90,7 @@
 		cmdline = 'initcall_debug log_buf_len=32M'
 		if self.useftrace:
 			if self.cpucount > 0:
-				bs = min(self.memtotal / 2, 2*1024*1024) / self.cpucount
+				bs = min(self.memtotal // 2, 2*1024*1024) // self.cpucount
 			else:
 				bs = 131072
 			cmdline += ' trace_buf_size=%dK trace_clock=global '\
@@ -141,13 +146,13 @@
 			if arg in ['-h', '-v', '-cronjob', '-reboot', '-verbose']:
 				continue
 			elif arg in ['-o', '-dmesg', '-ftrace', '-func']:
-				args.next()
+				next(args)
 				continue
 			elif arg == '-result':
-				cmdline += ' %s "%s"' % (arg, os.path.abspath(args.next()))
+				cmdline += ' %s "%s"' % (arg, os.path.abspath(next(args)))
 				continue
 			elif arg == '-cgskip':
-				file = self.configFile(args.next())
+				file = self.configFile(next(args))
 				cmdline += ' %s "%s"' % (arg, os.path.abspath(file))
 				continue
 			cmdline += ' '+arg
@@ -157,11 +162,11 @@
 		return cmdline
 	def manualRebootRequired(self):
 		cmdline = self.kernelParams()
-		print 'To generate a new timeline manually, follow these steps:\n'
-		print '1. Add the CMDLINE string to your kernel command line.'
-		print '2. Reboot the system.'
-		print '3. After reboot, re-run this tool with the same arguments but no command (w/o -reboot or -manual).\n'
-		print 'CMDLINE="%s"' % cmdline
+		pprint('To generate a new timeline manually, follow these steps:\n\n'\
+		'1. Add the CMDLINE string to your kernel command line.\n'\
+		'2. Reboot the system.\n'\
+		'3. After reboot, re-run this tool with the same arguments but no command (w/o -reboot or -manual).\n\n'\
+		'CMDLINE="%s"' % cmdline)
 		sys.exit()
 	def blGrub(self):
 		blcmd = ''
@@ -296,11 +301,11 @@
 	tp = aslib.TestProps()
 	devtemp = dict()
 	if(sysvals.dmesgfile):
-		lf = open(sysvals.dmesgfile, 'r')
+		lf = open(sysvals.dmesgfile, 'rb')
 	else:
 		lf = Popen('dmesg', stdout=PIPE).stdout
 	for line in lf:
-		line = line.replace('\r\n', '')
+		line = aslib.ascii(line).replace('\r\n', '')
 		# grab the stamp and sysinfo
 		if re.match(tp.stampfmt, line):
 			tp.stamp = line
@@ -329,9 +334,9 @@
 			if(not sysvals.stamp['kernel']):
 				sysvals.stamp['kernel'] = sysvals.kernelVersion(msg)
 			continue
-		m = re.match('.* setting system clock to (?P<t>.*) UTC.*', msg)
+		m = re.match('.* setting system clock to (?P<d>[0-9\-]*)[ A-Z](?P<t>[0-9:]*) UTC.*', msg)
 		if(m):
-			bt = datetime.strptime(m.group('t'), '%Y-%m-%d %H:%M:%S')
+			bt = datetime.strptime(m.group('d')+' '+m.group('t'), '%Y-%m-%d %H:%M:%S')
 			bt = bt - timedelta(seconds=int(ktime))
 			data.boottime = bt.strftime('%Y-%m-%d_%H:%M:%S')
 			sysvals.stamp['time'] = bt.strftime('%B %d %Y, %I:%M:%S %p')
@@ -352,7 +357,7 @@
 				data.newAction(phase, f, pid, start, ktime, int(r), int(t))
 				del devtemp[f]
 			continue
-		if(re.match('^Freeing unused kernel memory.*', msg)):
+		if(re.match('^Freeing unused kernel .*', msg)):
 			data.tUserMode = ktime
 			data.dmesg['kernel']['end'] = ktime
 			data.dmesg['user']['start'] = ktime
@@ -431,7 +436,7 @@
 			if len(cg.list) < 1 or cg.invalid or (cg.end - cg.start == 0):
 				continue
 			if(not cg.postProcess()):
-				print('Sanity check failed for %s-%d' % (proc, pid))
+				pprint('Sanity check failed for %s-%d' % (proc, pid))
 				continue
 			# match cg data to devices
 			devname = data.deviceMatch(pid, cg)
@@ -442,8 +447,8 @@
 				sysvals.vprint('%s callgraph found for %s %s-%d [%f - %f]' %\
 					(kind, cg.name, proc, pid, cg.start, cg.end))
 			elif len(cg.list) > 1000000:
-				print 'WARNING: the callgraph found for %s is massive! (%d lines)' %\
-					(devname, len(cg.list))
+				pprint('WARNING: the callgraph found for %s is massive! (%d lines)' %\
+					(devname, len(cg.list)))
 
 # Function: retrieveLogs
 # Description:
@@ -528,7 +533,7 @@
 	tMax = data.end
 	tTotal = tMax - t0
 	if(tTotal == 0):
-		print('ERROR: No timeline data')
+		pprint('ERROR: No timeline data')
 		return False
 	user_mode = '%.0f'%(data.tUserMode*1000)
 	last_init = '%.0f'%(tTotal*1000)
@@ -653,7 +658,7 @@
 		statinfo += '\t"%s": [\n\t\t"%s",\n' % (n, devstats[n]['info'])
 		if 'fstat' in devstats[n]:
 			funcs = devstats[n]['fstat']
-			for f in sorted(funcs, key=funcs.get, reverse=True):
+			for f in sorted(funcs, key=lambda k:(funcs[k], k), reverse=True):
 				if funcs[f][0] < 0.01 and len(funcs) > 10:
 					break
 				statinfo += '\t\t"%f|%s|%d",\n' % (funcs[f][0], f, funcs[f][1])
@@ -733,8 +738,8 @@
 		op.write('@reboot python %s\n' % sysvals.cronjobCmdString())
 		op.close()
 		res = call([cmd, cronfile])
-	except Exception, e:
-		print 'Exception: %s' % str(e)
+	except Exception as e:
+		pprint('Exception: %s' % str(e))
 		shutil.move(backfile, cronfile)
 		res = -1
 	if res != 0:
@@ -749,8 +754,8 @@
 		try:
 			call(sysvals.blexec, stderr=PIPE, stdout=PIPE,
 				env={'PATH': '.:/sbin:/usr/sbin:/usr/bin:/sbin:/bin'})
-		except Exception, e:
-			print 'Exception: %s\n' % str(e)
+		except Exception as e:
+			pprint('Exception: %s\n' % str(e))
 		return
 	# extract the option and create a grub config without it
 	sysvals.rootUser(True)
@@ -796,8 +801,8 @@
 		op.close()
 		res = call(sysvals.blexec)
 		os.remove(grubfile)
-	except Exception, e:
-		print 'Exception: %s' % str(e)
+	except Exception as e:
+		pprint('Exception: %s' % str(e))
 		res = -1
 	# cleanup
 	shutil.move(tempfile, grubfile)
@@ -821,7 +826,7 @@
 def doError(msg, help=False):
 	if help == True:
 		printHelp()
-	print 'ERROR: %s\n' % msg
+	pprint('ERROR: %s\n' % msg)
 	sysvals.outputResult({'error':msg})
 	sys.exit()
 
@@ -829,52 +834,52 @@
 # Description:
 #	 print out the help text
 def printHelp():
-	print('')
-	print('%s v%s' % (sysvals.title, sysvals.version))
-	print('Usage: bootgraph <options> <command>')
-	print('')
-	print('Description:')
-	print('  This tool reads in a dmesg log of linux kernel boot and')
-	print('  creates an html representation of the boot timeline up to')
-	print('  the start of the init process.')
-	print('')
-	print('  If no specific command is given the tool reads the current dmesg')
-	print('  and/or ftrace log and creates a timeline')
-	print('')
-	print('  Generates output files in subdirectory: boot-yymmdd-HHMMSS')
-	print('   HTML output:                    <hostname>_boot.html')
-	print('   raw dmesg output:               <hostname>_boot_dmesg.txt')
-	print('   raw ftrace output:              <hostname>_boot_ftrace.txt')
-	print('')
-	print('Options:')
-	print('  -h            Print this help text')
-	print('  -v            Print the current tool version')
-	print('  -verbose      Print extra information during execution and analysis')
-	print('  -addlogs      Add the dmesg log to the html output')
-	print('  -result fn    Export a results table to a text file for parsing.')
-	print('  -o name       Overrides the output subdirectory name when running a new test')
-	print('                default: boot-{date}-{time}')
-	print(' [advanced]')
-	print('  -fstat        Use ftrace to add function detail and statistics (default: disabled)')
-	print('  -f/-callgraph Add callgraph detail, can be very large (default: disabled)')
-	print('  -maxdepth N   limit the callgraph data to N call levels (default: 2)')
-	print('  -mincg ms     Discard all callgraphs shorter than ms milliseconds (e.g. 0.001 for us)')
-	print('  -timeprec N   Number of significant digits in timestamps (0:S, 3:ms, [6:us])')
-	print('  -expandcg     pre-expand the callgraph data in the html output (default: disabled)')
-	print('  -func list    Limit ftrace to comma-delimited list of functions (default: do_one_initcall)')
-	print('  -cgfilter S   Filter the callgraph output in the timeline')
-	print('  -cgskip file  Callgraph functions to skip, off to disable (default: cgskip.txt)')
-	print('  -bl name      Use the following boot loader for kernel params (default: grub)')
-	print('  -reboot       Reboot the machine automatically and generate a new timeline')
-	print('  -manual       Show the steps to generate a new timeline manually (used with -reboot)')
-	print('')
-	print('Other commands:')
-	print('  -flistall     Print all functions capable of being captured in ftrace')
-	print('  -sysinfo      Print out system info extracted from BIOS')
-	print(' [redo]')
-	print('  -dmesg file   Create HTML output using dmesg input (used with -ftrace)')
-	print('  -ftrace file  Create HTML output using ftrace input (used with -dmesg)')
-	print('')
+	pprint('\n%s v%s\n'\
+	'Usage: bootgraph <options> <command>\n'\
+	'\n'\
+	'Description:\n'\
+	'  This tool reads in a dmesg log of linux kernel boot and\n'\
+	'  creates an html representation of the boot timeline up to\n'\
+	'  the start of the init process.\n'\
+	'\n'\
+	'  If no specific command is given the tool reads the current dmesg\n'\
+	'  and/or ftrace log and creates a timeline\n'\
+	'\n'\
+	'  Generates output files in subdirectory: boot-yymmdd-HHMMSS\n'\
+	'   HTML output:                    <hostname>_boot.html\n'\
+	'   raw dmesg output:               <hostname>_boot_dmesg.txt\n'\
+	'   raw ftrace output:              <hostname>_boot_ftrace.txt\n'\
+	'\n'\
+	'Options:\n'\
+	'  -h            Print this help text\n'\
+	'  -v            Print the current tool version\n'\
+	'  -verbose      Print extra information during execution and analysis\n'\
+	'  -addlogs      Add the dmesg log to the html output\n'\
+	'  -result fn    Export a results table to a text file for parsing.\n'\
+	'  -o name       Overrides the output subdirectory name when running a new test\n'\
+	'                default: boot-{date}-{time}\n'\
+	' [advanced]\n'\
+	'  -fstat        Use ftrace to add function detail and statistics (default: disabled)\n'\
+	'  -f/-callgraph Add callgraph detail, can be very large (default: disabled)\n'\
+	'  -maxdepth N   limit the callgraph data to N call levels (default: 2)\n'\
+	'  -mincg ms     Discard all callgraphs shorter than ms milliseconds (e.g. 0.001 for us)\n'\
+	'  -timeprec N   Number of significant digits in timestamps (0:S, 3:ms, [6:us])\n'\
+	'  -expandcg     pre-expand the callgraph data in the html output (default: disabled)\n'\
+	'  -func list    Limit ftrace to comma-delimited list of functions (default: do_one_initcall)\n'\
+	'  -cgfilter S   Filter the callgraph output in the timeline\n'\
+	'  -cgskip file  Callgraph functions to skip, off to disable (default: cgskip.txt)\n'\
+	'  -bl name      Use the following boot loader for kernel params (default: grub)\n'\
+	'  -reboot       Reboot the machine automatically and generate a new timeline\n'\
+	'  -manual       Show the steps to generate a new timeline manually (used with -reboot)\n'\
+	'\n'\
+	'Other commands:\n'\
+	'  -flistall     Print all functions capable of being captured in ftrace\n'\
+	'  -sysinfo      Print out system info extracted from BIOS\n'\
+	'  -which exec   Print an executable path, should function even without PATH\n'\
+	' [redo]\n'\
+	'  -dmesg file   Create HTML output using dmesg input (used with -ftrace)\n'\
+	'  -ftrace file  Create HTML output using ftrace input (used with -dmesg)\n'\
+	'' % (sysvals.title, sysvals.version))
 	return True
 
 # ----------------- MAIN --------------------
@@ -895,7 +900,7 @@
 			printHelp()
 			sys.exit()
 		elif(arg == '-v'):
-			print("Version %s" % sysvals.version)
+			pprint("Version %s" % sysvals.version)
 			sys.exit()
 		elif(arg == '-verbose'):
 			sysvals.verbose = True
@@ -912,13 +917,13 @@
 			sysvals.mincglen = aslib.getArgFloat('-mincg', args, 0.0, 10000.0)
 		elif(arg == '-cgfilter'):
 			try:
-				val = args.next()
+				val = next(args)
 			except:
 				doError('No callgraph functions supplied', True)
 			sysvals.setCallgraphFilter(val)
 		elif(arg == '-cgskip'):
 			try:
-				val = args.next()
+				val = next(args)
 			except:
 				doError('No file supplied', True)
 			if val.lower() in switchoff:
@@ -929,7 +934,7 @@
 					doError('%s does not exist' % cgskip)
 		elif(arg == '-bl'):
 			try:
-				val = args.next()
+				val = next(args)
 			except:
 				doError('No boot loader name supplied', True)
 			if val.lower() not in ['grub']:
@@ -942,7 +947,7 @@
 			sysvals.max_graph_depth = aslib.getArgInt('-maxdepth', args, 0, 1000)
 		elif(arg == '-func'):
 			try:
-				val = args.next()
+				val = next(args)
 			except:
 				doError('No filter functions supplied', True)
 			sysvals.useftrace = True
@@ -951,7 +956,7 @@
 			sysvals.setGraphFilter(val)
 		elif(arg == '-ftrace'):
 			try:
-				val = args.next()
+				val = next(args)
 			except:
 				doError('No ftrace file supplied', True)
 			if(os.path.exists(val) == False):
@@ -964,7 +969,7 @@
 			sysvals.cgexp = True
 		elif(arg == '-dmesg'):
 			try:
-				val = args.next()
+				val = next(args)
 			except:
 				doError('No dmesg file supplied', True)
 			if(os.path.exists(val) == False):
@@ -973,13 +978,13 @@
 			sysvals.dmesgfile = val
 		elif(arg == '-o'):
 			try:
-				val = args.next()
+				val = next(args)
 			except:
 				doError('No subdirectory name supplied', True)
 			sysvals.testdir = sysvals.setOutputFolder(val)
 		elif(arg == '-result'):
 			try:
-				val = args.next()
+				val = next(args)
 			except:
 				doError('No result file supplied', True)
 			sysvals.result = val
@@ -991,6 +996,17 @@
 		# remaining options are only for cron job use
 		elif(arg == '-cronjob'):
 			sysvals.iscronjob = True
+		elif(arg == '-which'):
+			try:
+				val = next(args)
+			except:
+				doError('No executable supplied', True)
+			out = sysvals.getExec(val)
+			if not out:
+				print('%s not found' % val)
+				sys.exit(1)
+			print(out)
+			sys.exit(0)
 		else:
 			doError('Invalid argument: '+arg, True)
 
@@ -1013,10 +1029,10 @@
 			updateKernelParams()
 		elif cmd == 'flistall':
 			for f in sysvals.getBootFtraceFilterFunctions():
-				print f
+				print(f)
 		elif cmd == 'checkbl':
 			sysvals.getBootLoader()
-			print 'Boot Loader: %s\n%s' % (sysvals.bootloader, sysvals.blexec)
+			pprint('Boot Loader: %s\n%s' % (sysvals.bootloader, sysvals.blexec))
 		elif(cmd == 'sysinfo'):
 			sysvals.printSystemInfo(True)
 		sys.exit()
diff --git a/tools/power/pm-graph/config/cgskip.txt b/tools/power/pm-graph/config/cgskip.txt
index e48d588..9ff88e7 100644
--- a/tools/power/pm-graph/config/cgskip.txt
+++ b/tools/power/pm-graph/config/cgskip.txt
@@ -27,6 +27,7 @@
 # console calls
 printk
 dev_printk
+__dev_printk
 console_unlock
 
 # memory handling
diff --git a/tools/power/pm-graph/config/custom-timeline-functions.cfg b/tools/power/pm-graph/config/custom-timeline-functions.cfg
index f8fcb06..4f80ad7 100644
--- a/tools/power/pm-graph/config/custom-timeline-functions.cfg
+++ b/tools/power/pm-graph/config/custom-timeline-functions.cfg
@@ -105,7 +105,7 @@
 #       example: [color=#CC00CC]
 #
 #   arglist: A list of arguments from registers/stack addresses. See URL:
-#            https://www.kernel.org/doc/Documentation/trace/kprobetrace.rst
+#            https://www.kernel.org/doc/Documentation/trace/kprobetrace.txt
 #
 #       example: cpu=%di:s32
 #
@@ -170,7 +170,7 @@
 #       example: [color=#CC00CC]
 #
 #   arglist: A list of arguments from registers/stack addresses. See URL:
-#            https://www.kernel.org/doc/Documentation/trace/kprobetrace.rst
+#            https://www.kernel.org/doc/Documentation/trace/kprobetrace.txt
 #
 #       example: port=+36(%di):s32
 #
diff --git a/tools/power/pm-graph/config/example.cfg b/tools/power/pm-graph/config/example.cfg
index 05b2efb..1ef3eb9 100644
--- a/tools/power/pm-graph/config/example.cfg
+++ b/tools/power/pm-graph/config/example.cfg
@@ -98,12 +98,34 @@
 # graph only devices longer than min in the timeline (default: 0.001 ms)
 mindev: 0.001
 
+# Call Loop Max Gap (dev mode only)
+# merge loops of the same call if each is less than maxgap apart (def: 100us)
+callloop-maxgap: 0.0001
+
+# Call Loop Max Length (dev mode only)
+# merge loops of the same call if each is less than maxlen in length (def: 5ms)
+callloop-maxlen: 0.005
+
+# Override default timeline entries:
+# Do not use the internal default functions for timeline entries (def: false)
+# Set this to true if you intend to only use the ones defined in the config
+override-timeline-functions: true
+
+# Override default dev timeline entries:
+# Do not use the internal default functions for dev timeline entries (def: false)
+# Set this to true if you intend to only use the ones defined in the config
+override-dev-timeline-functions: true
+
 # ---- Debug Options ----
 
 # Callgraph
 # gather detailed ftrace callgraph data on all timeline events (default: false)
 callgraph: false
 
+# Max graph depth
+# limit the callgraph trace to this depth (default: 0 = all)
+maxdepth: 2
+
 # Callgraph phase filter
 # Only enable callgraphs for one phase, i.e. resume_noirq (default: all)
 cgphase: suspend
@@ -131,3 +153,7 @@
 # Add kprobe functions to the timeline
 # Add functions to the timeline from a text file (default: no-action)
 # fadd: file.txt
+
+# Ftrace buffer size
+# Set trace buffer size to N kilo-bytes (default: all of free memory up to 3GB)
+# bufsize: 1000
diff --git a/tools/power/pm-graph/sleepgraph.8 b/tools/power/pm-graph/sleepgraph.8
index 070be2c..43aee64 100644
--- a/tools/power/pm-graph/sleepgraph.8
+++ b/tools/power/pm-graph/sleepgraph.8
@@ -53,6 +53,11 @@
 Add the dmesg and ftrace logs to the html output. They will be viewable by
 clicking buttons in the timeline.
 .TP
+\fB-noturbostat\fR
+By default, if turbostat is found and the requested mode is freeze, sleepgraph
+will execute the suspend via turbostat and collect data in the timeline log.
+This option disables the use of turbostat.
+.TP
 \fB-result \fIfile\fR
 Export a results table to a text file for parsing.
 .TP
@@ -65,9 +70,9 @@
 by 5 seconds to allow runtime suspend changes to occur. The settings are restored
 after the test is complete.
 .TP
-\fB-display \fIon/off\fR
-Turn the display on or off for the test using the xset command. This helps
-maintain the consistecy of test data for better comparison.
+\fB-display \fIon/off/standby/suspend\fR
+Switch the display to the requested mode for the test using the xset command.
+This helps maintain the consistency of test data for better comparison.
 .TP
 \fB-skiphtml\fR
 Run the test and capture the trace logs, but skip the timeline generation.
@@ -121,6 +126,10 @@
 Use ftrace to create device callgraphs (default: disabled). This can produce
 very large outputs, i.e. 10MB - 100MB.
 .TP
+\fB-ftop\fR
+Use ftrace on the top level call: "suspend_devices_and_enter" only (default: disabled).
+This option implies -f and creates a single callgraph covering all of suspend/resume.
+.TP
 \fB-maxdepth \fIlevel\fR
 limit the callgraph trace depth to \fIlevel\fR (default: 0=all). This is
 the best way to limit the output size when using callgraphs via -f.
@@ -138,8 +147,8 @@
 The value is a float: e.g. 0.001 represents 1 us.
 .TP
 \fB-cgfilter \fI"func1,func2,..."\fR
-Reduce callgraph output in the timeline by limiting it to a list of calls. The
-argument can be a single function name or a comma delimited list.
+Reduce callgraph output in the timeline by limiting it certain devices. The
+argument can be a single device name or a comma delimited list.
 (default: none)
 .TP
 \fB-cgskip \fIfile\fR
@@ -183,6 +192,16 @@
 \fB-battery\fR
 Print out battery status and current charge.
 .TP
+\fB-wifi\fR
+Print out wifi status and connection details.
+.TP
+\fB-xon/-xoff/-xstandby/-xsuspend\fR
+Test xset by attempting to switch the display to the given mode. This
+is the same command which will be issued by \fB-display \fImode\fR.
+.TP
+\fB-xstat\fR
+Get the current DPMS display mode.
+.TP
 \fB-sysinfo\fR
 Print out system info extracted from BIOS. Reads /dev/mem directly instead of going through dmidecode.
 .TP
diff --git a/tools/power/pm-graph/sleepgraph.py b/tools/power/pm-graph/sleepgraph.py
index 0c76047..f7d1c1f 100755
--- a/tools/power/pm-graph/sleepgraph.py
+++ b/tools/power/pm-graph/sleepgraph.py
@@ -1,4 +1,5 @@
-#!/usr/bin/python2
+#!/usr/bin/python
+# SPDX-License-Identifier: GPL-2.0-only
 #
 # Tool for analyzing suspend/resume timing
 # Copyright (c) 2013, Intel Corporation.
@@ -17,9 +18,9 @@
 #
 # Links:
 #	 Home Page
-#	   https://01.org/suspendresume
+#	   https://01.org/pm-graph
 #	 Source repo
-#	   git@github.com:01org/pm-graph
+#	   git@github.com:intel/pm-graph
 #
 # Description:
 #	 This tool is designed to assist kernel and OS developers in optimizing
@@ -32,6 +33,7 @@
 #	 viewed in firefox or chrome.
 #
 #	 The following kernel build options are required:
+#		 CONFIG_DEVMEM=y
 #		 CONFIG_PM_DEBUG=y
 #		 CONFIG_PM_SLEEP_DEBUG=y
 #		 CONFIG_FTRACE=y
@@ -54,12 +56,22 @@
 import string
 import re
 import platform
+import signal
+import codecs
 from datetime import datetime
 import struct
-import ConfigParser
+import configparser
 import gzip
 from threading import Thread
 from subprocess import call, Popen, PIPE
+import base64
+
+def pprint(msg):
+	print(msg)
+	sys.stdout.flush()
+
+def ascii(text):
+	return text.decode('ascii', 'ignore')
 
 # ----------------- CLASSES --------------------
 
@@ -69,16 +81,17 @@
 #	 store system values and test parameters
 class SystemValues:
 	title = 'SleepGraph'
-	version = '5.1'
+	version = '5.5'
 	ansi = False
 	rs = 0
-	display = 0
+	display = ''
 	gzip = False
 	sync = False
 	verbose = False
 	testlog = True
-	dmesglog = False
+	dmesglog = True
 	ftracelog = False
+	tstat = True
 	mindevlen = 0.0
 	mincglen = 0.0
 	cgphase = ''
@@ -99,8 +112,11 @@
 	tpath = '/sys/kernel/debug/tracing/'
 	fpdtpath = '/sys/firmware/acpi/tables/FPDT'
 	epath = '/sys/kernel/debug/tracing/events/power/'
+	pmdpath = '/sys/power/pm_debug_messages'
 	traceevents = [
 		'suspend_resume',
+		'wakeup_source_activate',
+		'wakeup_source_deactivate',
 		'device_pm_callback_end',
 		'device_pm_callback_start'
 	]
@@ -109,8 +125,10 @@
 	mempath = '/dev/mem'
 	powerfile = '/sys/power/state'
 	mempowerfile = '/sys/power/mem_sleep'
+	diskpowerfile = '/sys/power/disk'
 	suspendmode = 'mem'
 	memmode = ''
+	diskmode = ''
 	hostname = 'localhost'
 	prefix = 'test'
 	teststamp = ''
@@ -130,6 +148,8 @@
 	x2delay = 0
 	skiphtml = False
 	usecallgraph = False
+	ftopfunc = 'suspend_devices_and_enter'
+	ftop = False
 	usetraceevents = False
 	usetracemarkers = True
 	usekprobes = True
@@ -137,16 +157,16 @@
 	useprocmon = False
 	notestrun = False
 	cgdump = False
+	devdump = False
 	mixedphaseheight = True
 	devprops = dict()
+	platinfo = []
 	predelay = 0
 	postdelay = 0
-	procexecfmt = 'ps - (?P<ps>.*)$'
-	devpropfmt = '# Device Properties: .*'
-	tracertypefmt = '# tracer: (?P<t>.*)'
-	firmwarefmt = '# fwsuspend (?P<s>[0-9]*) fwresume (?P<r>[0-9]*)$'
+	pmdebug = ''
 	tracefuncs = {
 		'sys_sync': {},
+		'ksys_sync': {},
 		'__pm_notifier_call_chain': {},
 		'pm_prepare_console': {},
 		'pm_notifier_call_chain': {},
@@ -159,6 +179,13 @@
 		'acpi_hibernation_leave': {},
 		'acpi_pm_freeze': {},
 		'acpi_pm_thaw': {},
+		'acpi_s2idle_end': {},
+		'acpi_s2idle_sync': {},
+		'acpi_s2idle_begin': {},
+		'acpi_s2idle_prepare': {},
+		'acpi_s2idle_wake': {},
+		'acpi_s2idle_wakeup': {},
+		'acpi_s2idle_restore': {},
 		'hibernate_preallocate_memory': {},
 		'create_basic_memory_bitmaps': {},
 		'swsusp_write': {},
@@ -187,18 +214,25 @@
 	dev_tracefuncs = {
 		# general wait/delay/sleep
 		'msleep': { 'args_x86_64': {'time':'%di:s32'}, 'ub': 1 },
-		'schedule_timeout_uninterruptible': { 'args_x86_64': {'timeout':'%di:s32'}, 'ub': 1 },
 		'schedule_timeout': { 'args_x86_64': {'timeout':'%di:s32'}, 'ub': 1 },
 		'udelay': { 'func':'__const_udelay', 'args_x86_64': {'loops':'%di:s32'}, 'ub': 1 },
 		'usleep_range': { 'args_x86_64': {'min':'%di:s32', 'max':'%si:s32'}, 'ub': 1 },
 		'mutex_lock_slowpath': { 'func':'__mutex_lock_slowpath', 'ub': 1 },
 		'acpi_os_stall': {'ub': 1},
+		'rt_mutex_slowlock': {'ub': 1},
 		# ACPI
 		'acpi_resume_power_resources': {},
-		'acpi_ps_parse_aml': {},
+		'acpi_ps_execute_method': { 'args_x86_64': {
+			'fullpath':'+0(+40(%di)):string',
+		}},
+		# mei_me
+		'mei_reset': {},
 		# filesystem
 		'ext4_sync_fs': {},
 		# 80211
+		'ath10k_bmi_read_memory': { 'args_x86_64': {'length':'%cx:s32'} },
+		'ath10k_bmi_write_memory': { 'args_x86_64': {'length':'%cx:s32'} },
+		'ath10k_bmi_fast_download': { 'args_x86_64': {'length':'%cx:s32'} },
 		'iwlagn_mac_start': {},
 		'iwlagn_alloc_bcast_station': {},
 		'iwl_trans_pcie_start_hw': {},
@@ -241,6 +275,8 @@
 	timeformat = '%.3f'
 	cmdline = '%s %s' % \
 			(os.path.basename(sys.argv[0]), ' '.join(sys.argv[1:]))
+	kparams = ''
+	sudouser = ''
 	def __init__(self):
 		self.archargs = 'args_'+platform.machine()
 		self.hostname = platform.node()
@@ -256,36 +292,65 @@
 		if (hasattr(sys.stdout, 'isatty') and sys.stdout.isatty()):
 			self.ansi = True
 		self.testdir = datetime.now().strftime('suspend-%y%m%d-%H%M%S')
+		if os.getuid() == 0 and 'SUDO_USER' in os.environ and \
+			os.environ['SUDO_USER']:
+			self.sudouser = os.environ['SUDO_USER']
 	def vprint(self, msg):
 		self.logmsg += msg+'\n'
-		if(self.verbose):
-			print(msg)
+		if self.verbose or msg.startswith('WARNING:'):
+			pprint(msg)
+	def signalHandler(self, signum, frame):
+		if not self.result:
+			return
+		signame = self.signames[signum] if signum in self.signames else 'UNKNOWN'
+		msg = 'Signal %s caused a tool exit, line %d' % (signame, frame.f_lineno)
+		sysvals.outputResult({'error':msg})
+		sys.exit(3)
+	def signalHandlerInit(self):
+		capture = ['BUS', 'SYS', 'XCPU', 'XFSZ', 'PWR', 'HUP', 'INT', 'QUIT',
+			'ILL', 'ABRT', 'FPE', 'SEGV', 'TERM', 'TSTP']
+		self.signames = dict()
+		for i in capture:
+			s = 'SIG'+i
+			try:
+				signum = getattr(signal, s)
+				signal.signal(signum, self.signalHandler)
+			except:
+				continue
+			self.signames[signum] = s
 	def rootCheck(self, fatal=True):
 		if(os.access(self.powerfile, os.W_OK)):
 			return True
 		if fatal:
 			msg = 'This command requires sysfs mount and root access'
-			print('ERROR: %s\n') % msg
+			pprint('ERROR: %s\n' % msg)
 			self.outputResult({'error':msg})
-			sys.exit()
+			sys.exit(1)
 		return False
 	def rootUser(self, fatal=False):
 		if 'USER' in os.environ and os.environ['USER'] == 'root':
 			return True
 		if fatal:
 			msg = 'This command must be run as root'
-			print('ERROR: %s\n') % msg
+			pprint('ERROR: %s\n' % msg)
 			self.outputResult({'error':msg})
-			sys.exit()
+			sys.exit(1)
 		return False
 	def getExec(self, cmd):
-		dirlist = ['/sbin', '/bin', '/usr/sbin', '/usr/bin',
-			'/usr/local/sbin', '/usr/local/bin']
-		for path in dirlist:
+		try:
+			fp = Popen(['which', cmd], stdout=PIPE, stderr=PIPE).stdout
+			out = ascii(fp.read()).strip()
+			fp.close()
+		except:
+			out = ''
+		if out:
+			return out
+		for path in ['/sbin', '/bin', '/usr/sbin', '/usr/bin',
+			'/usr/local/sbin', '/usr/local/bin']:
 			cmdfull = os.path.join(path, cmd)
 			if os.path.exists(cmdfull):
 				return cmdfull
-		return ''
+		return out
 	def setPrecision(self, num):
 		if num < 0 or num > 6:
 			return
@@ -296,6 +361,7 @@
 		args['date'] = n.strftime('%y%m%d')
 		args['time'] = n.strftime('%H%M%S')
 		args['hostname'] = args['host'] = self.hostname
+		args['mode'] = self.suspendmode
 		return value.format(**args)
 	def setOutputFile(self):
 		if self.dmesgfile != '':
@@ -307,21 +373,28 @@
 			if(m):
 				self.htmlfile = m.group('name')+'.html'
 	def systemInfo(self, info):
-		p = c = m = b = ''
+		p = m = ''
 		if 'baseboard-manufacturer' in info:
 			m = info['baseboard-manufacturer']
 		elif 'system-manufacturer' in info:
 			m = info['system-manufacturer']
-		if 'baseboard-product-name' in info:
-			p = info['baseboard-product-name']
-		elif 'system-product-name' in info:
+		if 'system-product-name' in info:
 			p = info['system-product-name']
-		if 'processor-version' in info:
-			c = info['processor-version']
-		if 'bios-version' in info:
-			b = info['bios-version']
-		self.sysstamp = '# sysinfo | man:%s | plat:%s | cpu:%s | bios:%s | numcpu:%d | memsz:%d | memfr:%d' % \
-			(m, p, c, b, self.cpucount, self.memtotal, self.memfree)
+		elif 'baseboard-product-name' in info:
+			p = info['baseboard-product-name']
+		if m[:5].lower() == 'intel' and 'baseboard-product-name' in info:
+			p = info['baseboard-product-name']
+		c = info['processor-version'] if 'processor-version' in info else ''
+		b = info['bios-version'] if 'bios-version' in info else ''
+		r = info['bios-release-date'] if 'bios-release-date' in info else ''
+		self.sysstamp = '# sysinfo | man:%s | plat:%s | cpu:%s | bios:%s | biosdate:%s | numcpu:%d | memsz:%d | memfr:%d' % \
+			(m, p, c, b, r, self.cpucount, self.memtotal, self.memfree)
+		try:
+			kcmd = open('/proc/cmdline', 'r').read().strip()
+		except:
+			kcmd = ''
+		if kcmd:
+			self.sysstamp += '\n# kparams | %s' % kcmd
 	def printSystemInfo(self, fatal=False):
 		self.rootCheck(True)
 		out = dmidecode(self.mempath, fatal)
@@ -329,10 +402,10 @@
 			return
 		fmt = '%-24s: %s'
 		for name in sorted(out):
-			print fmt % (name, out[name])
-		print fmt % ('cpucount', ('%d' % self.cpucount))
-		print fmt % ('memtotal', ('%d kB' % self.memtotal))
-		print fmt % ('memfree', ('%d kB' % self.memfree))
+			print(fmt % (name, out[name]))
+		print(fmt % ('cpucount', ('%d' % self.cpucount)))
+		print(fmt % ('memtotal', ('%d kB' % self.memtotal)))
+		print(fmt % ('memfree', ('%d kB' % self.memfree)))
 	def cpuInfo(self):
 		self.cpucount = 0
 		fp = open('/proc/cpuinfo', 'r')
@@ -352,7 +425,7 @@
 	def initTestOutput(self, name):
 		self.prefix = self.hostname
 		v = open('/proc/version', 'r').read().strip()
-		kver = string.split(v)[2]
+		kver = v.split()[2]
 		fmt = name+'-%m%d%y-%H%M%S'
 		testtime = datetime.now().strftime(fmt)
 		self.teststamp = \
@@ -367,7 +440,7 @@
 		self.htmlfile = \
 			self.testdir+'/'+self.prefix+'_'+self.suspendmode+'.html'
 		if not os.path.isdir(self.testdir):
-			os.mkdir(self.testdir)
+			os.makedirs(self.testdir)
 	def getValueList(self, value):
 		out = []
 		for i in value.split(','):
@@ -378,6 +451,12 @@
 		self.devicefilter = self.getValueList(value)
 	def setCallgraphFilter(self, value):
 		self.cgfilter = self.getValueList(value)
+	def skipKprobes(self, value):
+		for k in self.getValueList(value):
+			if k in self.tracefuncs:
+				del self.tracefuncs[k]
+			if k in self.dev_tracefuncs:
+				del self.dev_tracefuncs[k]
 	def setCallgraphBlacklist(self, file):
 		self.cgblacklist = self.listFromFile(file)
 	def rtcWakeAlarmOn(self):
@@ -397,7 +476,7 @@
 		fp = Popen('dmesg', stdout=PIPE).stdout
 		ktime = '0'
 		for line in fp:
-			line = line.replace('\r\n', '')
+			line = ascii(line).replace('\r\n', '')
 			idx = line.find('[')
 			if idx > 1:
 				line = line[idx:]
@@ -406,12 +485,12 @@
 				ktime = m.group('ktime')
 		fp.close()
 		self.dmesgstart = float(ktime)
-	def getdmesg(self, fwdata=[]):
-		op = self.writeDatafileHeader(sysvals.dmesgfile, fwdata)
+	def getdmesg(self, testdata):
+		op = self.writeDatafileHeader(sysvals.dmesgfile, testdata)
 		# store all new dmesg lines since initdmesg was called
 		fp = Popen('dmesg', stdout=PIPE).stdout
 		for line in fp:
-			line = line.replace('\r\n', '')
+			line = ascii(line).replace('\r\n', '')
 			idx = line.find('[')
 			if idx > 1:
 				line = line[idx:]
@@ -443,13 +522,13 @@
 			call('cat '+self.tpath+'available_filter_functions', shell=True)
 			return
 		master = self.listFromFile(self.tpath+'available_filter_functions')
-		for i in self.tracefuncs:
+		for i in sorted(self.tracefuncs):
 			if 'func' in self.tracefuncs[i]:
 				i = self.tracefuncs[i]['func']
 			if i in master:
-				print i
+				print(i)
 			else:
-				print self.colorText(i)
+				print(self.colorText(i))
 	def setFtraceFilterFunctions(self, list):
 		master = self.listFromFile(self.tpath+'available_filter_functions')
 		flist = ''
@@ -535,7 +614,7 @@
 		if len(self.kprobes) < 1:
 			return
 		if output:
-			print('    kprobe functions in this kernel:')
+			pprint('    kprobe functions in this kernel:')
 		# first test each kprobe
 		rejects = []
 		# sort kprobes: trace, ub-dev, custom, dev
@@ -557,7 +636,7 @@
 				else:
 					kpl[2].append(name)
 			if output:
-				print('         %s: %s' % (name, res))
+				pprint('         %s: %s' % (name, res))
 		kplist = kpl[0] + kpl[1] + kpl[2] + kpl[3]
 		# remove all failed ones from the list
 		for name in rejects:
@@ -570,8 +649,8 @@
 		self.fsetVal(kprobeevents, 'kprobe_events')
 		if output:
 			check = self.fgetVal('kprobe_events')
-			linesack = (len(check.split('\n')) - 1) / 2
-			print('    kprobe functions enabled: %d/%d' % (linesack, linesout))
+			linesack = (len(check.split('\n')) - 1) // 2
+			pprint('    kprobe functions enabled: %d/%d' % (linesack, linesout))
 		self.fsetVal('1', 'events/kprobes/enable')
 	def testKprobe(self, kname, kprobe):
 		self.fsetVal('0', 'events/kprobes/enable')
@@ -588,19 +667,19 @@
 		if linesack < linesout:
 			return False
 		return True
-	def setVal(self, val, file, mode='w'):
+	def setVal(self, val, file):
 		if not os.path.exists(file):
 			return False
 		try:
-			fp = open(file, mode, 0)
-			fp.write(val)
+			fp = open(file, 'wb', 0)
+			fp.write(val.encode())
 			fp.flush()
 			fp.close()
 		except:
 			return False
 		return True
-	def fsetVal(self, val, path, mode='w'):
-		return self.setVal(val, self.tpath+path, mode)
+	def fsetVal(self, val, path):
+		return self.setVal(val, self.tpath+path)
 	def getVal(self, file):
 		res = ''
 		if not os.path.exists(file):
@@ -619,6 +698,8 @@
 			self.fsetVal('0', 'events/kprobes/enable')
 			self.fsetVal('', 'kprobe_events')
 			self.fsetVal('1024', 'buffer_size_kb')
+		if self.pmdebug:
+			self.setVal(self.pmdebug, self.pmdpath)
 	def setupAllKprobes(self):
 		for name in self.tracefuncs:
 			self.defaultKprobe(name, self.tracefuncs[name])
@@ -637,10 +718,15 @@
 		return False
 	def initFtrace(self):
 		self.printSystemInfo(False)
-		print('INITIALIZING FTRACE...')
+		pprint('INITIALIZING FTRACE...')
 		# turn trace off
 		self.fsetVal('0', 'tracing_on')
 		self.cleanupFtrace()
+		# pm debug messages
+		pv = self.getVal(self.pmdpath)
+		if pv != '1':
+			self.setVal('1', self.pmdpath)
+			self.pmdebug = pv
 		# set the trace clock to global
 		self.fsetVal('global', 'trace_clock')
 		self.fsetVal('nop', 'current_tracer')
@@ -649,16 +735,18 @@
 		if self.bufsize > 0:
 			tgtsize = self.bufsize
 		elif self.usecallgraph or self.usedevsrc:
-			tgtsize = min(self.memfree, 3*1024*1024)
+			bmax = (1*1024*1024) if self.suspendmode in ['disk', 'command'] \
+				else (3*1024*1024)
+			tgtsize = min(self.memfree, bmax)
 		else:
 			tgtsize = 65536
-		while not self.fsetVal('%d' % (tgtsize / cpus), 'buffer_size_kb'):
+		while not self.fsetVal('%d' % (tgtsize // cpus), 'buffer_size_kb'):
 			# if the size failed to set, lower it and keep trying
 			tgtsize -= 65536
 			if tgtsize < 65536:
 				tgtsize = int(self.fgetVal('buffer_size_kb')) * cpus
 				break
-		print 'Setting trace buffers to %d kB (%d kB per cpu)' % (tgtsize, tgtsize/cpus)
+		pprint('Setting trace buffers to %d kB (%d kB per cpu)' % (tgtsize, tgtsize/cpus))
 		# initialize the callgraph trace
 		if(self.usecallgraph):
 			# set trace type
@@ -683,7 +771,10 @@
 					cf.append(self.tracefuncs[fn]['func'])
 				else:
 					cf.append(fn)
-			self.setFtraceFilterFunctions(cf)
+			if self.ftop:
+				self.setFtraceFilterFunctions([self.ftopfunc])
+			else:
+				self.setFtraceFilterFunctions(cf)
 		# initialize the kprobe trace
 		elif self.usekprobes:
 			for name in self.tracefuncs:
@@ -691,7 +782,7 @@
 			if self.usedevsrc:
 				for name in self.dev_tracefuncs:
 					self.defaultKprobe(name, self.dev_tracefuncs[name])
-			print('INITIALIZING KPROBES...')
+			pprint('INITIALIZING KPROBES...')
 			self.addKprobes(self.verbose)
 		if(self.usetraceevents):
 			# turn trace events on
@@ -728,19 +819,36 @@
 		if not self.ansi:
 			return str
 		return '\x1B[%d;40m%s\x1B[m' % (color, str)
-	def writeDatafileHeader(self, filename, fwdata=[]):
+	def writeDatafileHeader(self, filename, testdata):
 		fp = self.openlog(filename, 'w')
 		fp.write('%s\n%s\n# command | %s\n' % (self.teststamp, self.sysstamp, self.cmdline))
-		if(self.suspendmode == 'mem' or self.suspendmode == 'command'):
-			for fw in fwdata:
+		for test in testdata:
+			if 'fw' in test:
+				fw = test['fw']
 				if(fw):
 					fp.write('# fwsuspend %u fwresume %u\n' % (fw[0], fw[1]))
+			if 'mcelog' in test:
+				fp.write('# mcelog %s\n' % test['mcelog'])
+			if 'turbo' in test:
+				fp.write('# turbostat %s\n' % test['turbo'])
+			if 'bat' in test:
+				(a1, c1), (a2, c2) = test['bat']
+				fp.write('# battery %s %d %s %d\n' % (a1, c1, a2, c2))
+			if 'wifi' in test:
+				wstr = []
+				for wifi in test['wifi']:
+					tmp = []
+					for key in sorted(wifi):
+						tmp.append('%s:%s' % (key, wifi[key]))
+					wstr.append('|'.join(tmp))
+				fp.write('# wifi %s\n' % (','.join(wstr)))
+			if test['error'] or len(testdata) > 1:
+				fp.write('# enter_sleep_error %s\n' % test['error'])
 		return fp
-	def sudouser(self, dir):
-		if os.path.exists(dir) and os.getuid() == 0 and \
-			'SUDO_USER' in os.environ:
+	def sudoUserchown(self, dir):
+		if os.path.exists(dir) and self.sudouser:
 			cmd = 'chown -R {0}:{0} {1} > /dev/null 2>&1'
-			call(cmd.format(os.environ['SUDO_USER'], dir), shell=True)
+			call(cmd.format(self.sudouser, dir), shell=True)
 	def outputResult(self, testdata, num=0):
 		if not self.result:
 			return
@@ -762,7 +870,7 @@
 		if 'bugurl' in testdata:
 			fp.write('url%s: %s\n' % (n, testdata['bugurl']))
 		fp.close()
-		self.sudouser(self.result)
+		self.sudoUserchown(self.result)
 	def configFile(self, file):
 		dir = os.path.dirname(os.path.realpath(__file__))
 		if os.path.exists(file):
@@ -776,14 +884,244 @@
 		isgz = self.gzip
 		if mode == 'r':
 			try:
-				with gzip.open(filename, mode+'b') as fp:
+				with gzip.open(filename, mode+'t') as fp:
 					test = fp.read(64)
 				isgz = True
 			except:
 				isgz = False
 		if isgz:
-			return gzip.open(filename, mode+'b')
+			return gzip.open(filename, mode+'t')
 		return open(filename, mode)
+	def b64unzip(self, data):
+		try:
+			out = codecs.decode(base64.b64decode(data), 'zlib').decode()
+		except:
+			out = data
+		return out
+	def b64zip(self, data):
+		out = base64.b64encode(codecs.encode(data.encode(), 'zlib')).decode()
+		return out
+	def mcelog(self, clear=False):
+		cmd = self.getExec('mcelog')
+		if not cmd:
+			return ''
+		if clear:
+			call(cmd+' > /dev/null 2>&1', shell=True)
+			return ''
+		try:
+			fp = Popen([cmd], stdout=PIPE, stderr=PIPE).stdout
+			out = ascii(fp.read()).strip()
+			fp.close()
+		except:
+			return ''
+		if not out:
+			return ''
+		return self.b64zip(out)
+	def platforminfo(self):
+		# add platform info on to a completed ftrace file
+		if not os.path.exists(self.ftracefile):
+			return False
+		footer = '#\n'
+
+		# add test command string line if need be
+		if self.suspendmode == 'command' and self.testcommand:
+			footer += '# platform-testcmd: %s\n' % (self.testcommand)
+
+		# get a list of target devices from the ftrace file
+		props = dict()
+		tp = TestProps()
+		tf = self.openlog(self.ftracefile, 'r')
+		for line in tf:
+			# determine the trace data type (required for further parsing)
+			m = re.match(tp.tracertypefmt, line)
+			if(m):
+				tp.setTracerType(m.group('t'))
+				continue
+			# parse only valid lines, if this is not one move on
+			m = re.match(tp.ftrace_line_fmt, line)
+			if(not m or 'device_pm_callback_start' not in line):
+				continue
+			m = re.match('.*: (?P<drv>.*) (?P<d>.*), parent: *(?P<p>.*), .*', m.group('msg'));
+			if(not m):
+				continue
+			dev = m.group('d')
+			if dev not in props:
+				props[dev] = DevProps()
+		tf.close()
+
+		# now get the syspath for each target device
+		for dirname, dirnames, filenames in os.walk('/sys/devices'):
+			if(re.match('.*/power', dirname) and 'async' in filenames):
+				dev = dirname.split('/')[-2]
+				if dev in props and (not props[dev].syspath or len(dirname) < len(props[dev].syspath)):
+					props[dev].syspath = dirname[:-6]
+
+		# now fill in the properties for our target devices
+		for dev in sorted(props):
+			dirname = props[dev].syspath
+			if not dirname or not os.path.exists(dirname):
+				continue
+			with open(dirname+'/power/async') as fp:
+				text = fp.read()
+				props[dev].isasync = False
+				if 'enabled' in text:
+					props[dev].isasync = True
+			fields = os.listdir(dirname)
+			if 'product' in fields:
+				with open(dirname+'/product', 'rb') as fp:
+					props[dev].altname = ascii(fp.read())
+			elif 'name' in fields:
+				with open(dirname+'/name', 'rb') as fp:
+					props[dev].altname = ascii(fp.read())
+			elif 'model' in fields:
+				with open(dirname+'/model', 'rb') as fp:
+					props[dev].altname = ascii(fp.read())
+			elif 'description' in fields:
+				with open(dirname+'/description', 'rb') as fp:
+					props[dev].altname = ascii(fp.read())
+			elif 'id' in fields:
+				with open(dirname+'/id', 'rb') as fp:
+					props[dev].altname = ascii(fp.read())
+			elif 'idVendor' in fields and 'idProduct' in fields:
+				idv, idp = '', ''
+				with open(dirname+'/idVendor', 'rb') as fp:
+					idv = ascii(fp.read()).strip()
+				with open(dirname+'/idProduct', 'rb') as fp:
+					idp = ascii(fp.read()).strip()
+				props[dev].altname = '%s:%s' % (idv, idp)
+			if props[dev].altname:
+				out = props[dev].altname.strip().replace('\n', ' ')\
+					.replace(',', ' ').replace(';', ' ')
+				props[dev].altname = out
+
+		# add a devinfo line to the bottom of ftrace
+		out = ''
+		for dev in sorted(props):
+			out += props[dev].out(dev)
+		footer += '# platform-devinfo: %s\n' % self.b64zip(out)
+
+		# add a line for each of these commands with their outputs
+		cmds = [
+			['pcidevices', 'lspci', '-tv'],
+			['interrupts', 'cat', '/proc/interrupts'],
+			['gpecounts', 'sh', '-c', 'grep -v invalid /sys/firmware/acpi/interrupts/gpe*'],
+		]
+		for cargs in cmds:
+			name = cargs[0]
+			cmdline = ' '.join(cargs[1:])
+			cmdpath = self.getExec(cargs[1])
+			if not cmdpath:
+				continue
+			cmd = [cmdpath] + cargs[2:]
+			try:
+				fp = Popen(cmd, stdout=PIPE, stderr=PIPE).stdout
+				info = ascii(fp.read()).strip()
+				fp.close()
+			except:
+				continue
+			if not info:
+				continue
+			footer += '# platform-%s: %s | %s\n' % (name, cmdline, self.b64zip(info))
+
+		with self.openlog(self.ftracefile, 'a') as fp:
+			fp.write(footer)
+		return True
+	def haveTurbostat(self):
+		if not self.tstat:
+			return False
+		cmd = self.getExec('turbostat')
+		if not cmd:
+			return False
+		fp = Popen([cmd, '-v'], stdout=PIPE, stderr=PIPE).stderr
+		out = ascii(fp.read()).strip()
+		fp.close()
+		if re.match('turbostat version [0-9\.]* .*', out):
+			sysvals.vprint(out)
+			return True
+		return False
+	def turbostat(self):
+		cmd = self.getExec('turbostat')
+		rawout = keyline = valline = ''
+		fullcmd = '%s -q -S echo freeze > %s' % (cmd, self.powerfile)
+		fp = Popen(['sh', '-c', fullcmd], stdout=PIPE, stderr=PIPE).stderr
+		for line in fp:
+			line = ascii(line)
+			rawout += line
+			if keyline and valline:
+				continue
+			if re.match('(?i)Avg_MHz.*', line):
+				keyline = line.strip().split()
+			elif keyline:
+				valline = line.strip().split()
+		fp.close()
+		if not keyline or not valline or len(keyline) != len(valline):
+			errmsg = 'unrecognized turbostat output:\n'+rawout.strip()
+			sysvals.vprint(errmsg)
+			if not sysvals.verbose:
+				pprint(errmsg)
+			return ''
+		if sysvals.verbose:
+			pprint(rawout.strip())
+		out = []
+		for key in keyline:
+			idx = keyline.index(key)
+			val = valline[idx]
+			out.append('%s=%s' % (key, val))
+		return '|'.join(out)
+	def checkWifi(self):
+		out = dict()
+		iwcmd, ifcmd = self.getExec('iwconfig'), self.getExec('ifconfig')
+		if not iwcmd or not ifcmd:
+			return out
+		fp = Popen(iwcmd, stdout=PIPE, stderr=PIPE).stdout
+		for line in fp:
+			m = re.match('(?P<dev>\S*) .* ESSID:(?P<ess>\S*)', ascii(line))
+			if not m:
+				continue
+			out['device'] = m.group('dev')
+			if '"' in m.group('ess'):
+				out['essid'] = m.group('ess').strip('"')
+				break
+		fp.close()
+		if 'device' in out:
+			fp = Popen([ifcmd, out['device']], stdout=PIPE, stderr=PIPE).stdout
+			for line in fp:
+				m = re.match('.* inet (?P<ip>[0-9\.]*)', ascii(line))
+				if m:
+					out['ip'] = m.group('ip')
+					break
+			fp.close()
+		return out
+	def errorSummary(self, errinfo, msg):
+		found = False
+		for entry in errinfo:
+			if re.match(entry['match'], msg):
+				entry['count'] += 1
+				if self.hostname not in entry['urls']:
+					entry['urls'][self.hostname] = [self.htmlfile]
+				elif self.htmlfile not in entry['urls'][self.hostname]:
+					entry['urls'][self.hostname].append(self.htmlfile)
+				found = True
+				break
+		if found:
+			return
+		arr = msg.split()
+		for j in range(len(arr)):
+			if re.match('^[0-9,\-\.]*$', arr[j]):
+				arr[j] = '[0-9,\-\.]*'
+			else:
+				arr[j] = arr[j]\
+					.replace('\\', '\\\\').replace(']', '\]').replace('[', '\[')\
+					.replace('.', '\.').replace('+', '\+').replace('*', '\*')\
+					.replace('(', '\(').replace(')', '\)')
+		mstr = ' '.join(arr)
+		entry = {
+			'line': msg,
+			'match': mstr,
+			'count': 1,
+			'urls': {self.hostname: [self.htmlfile]}
+		}
+		errinfo.append(entry)
 
 sysvals = SystemValues()
 switchvalues = ['enable', 'disable', 'on', 'off', 'true', 'false', '1', '0']
@@ -800,15 +1138,16 @@
 #	 Simple class which holds property values collected
 #	 for all the devices used in the timeline.
 class DevProps:
-	syspath = ''
-	altname = ''
-	async = True
-	xtraclass = ''
-	xtrainfo = ''
+	def __init__(self):
+		self.syspath = ''
+		self.altname = ''
+		self.isasync = True
+		self.xtraclass = ''
+		self.xtrainfo = ''
 	def out(self, dev):
-		return '%s,%s,%d;' % (dev, self.altname, self.async)
+		return '%s,%s,%d;' % (dev, self.altname, self.isasync)
 	def debug(self, dev):
-		print '%s:\n\taltname = %s\n\t  async = %s' % (dev, self.altname, self.async)
+		pprint('%s:\n\taltname = %s\n\t  async = %s' % (dev, self.altname, self.isasync))
 	def altName(self, dev):
 		if not self.altname or self.altname == dev:
 			return dev
@@ -816,13 +1155,13 @@
 	def xtraClass(self):
 		if self.xtraclass:
 			return ' '+self.xtraclass
-		if not self.async:
+		if not self.isasync:
 			return ' sync'
 		return ''
 	def xtraInfo(self):
 		if self.xtraclass:
 			return ' '+self.xtraclass
-		if self.async:
+		if self.isasync:
 			return ' async_device'
 		return ' sync_device'
 
@@ -831,9 +1170,6 @@
 #	 A container used to create a device hierachy, with a single root node
 #	 and a tree of child nodes. Used by Data.deviceTopology()
 class DeviceNode:
-	name = ''
-	children = 0
-	depth = 0
 	def __init__(self, nodename, nodedepth):
 		self.name = nodename
 		self.children = []
@@ -861,72 +1197,105 @@
 #	}
 #
 class Data:
-	dmesg = {}  # root data structure
-	phases = [] # ordered list of phases
-	start = 0.0 # test start
-	end = 0.0   # test end
-	tSuspended = 0.0 # low-level suspend start
-	tResumed = 0.0   # low-level resume start
-	tKernSus = 0.0   # kernel level suspend start
-	tKernRes = 0.0   # kernel level resume end
-	tLow = 0.0       # time spent in low-level suspend (standby/freeze)
-	fwValid = False  # is firmware data available
-	fwSuspend = 0    # time spent in firmware suspend
-	fwResume = 0     # time spent in firmware resume
-	dmesgtext = []   # dmesg text file in memory
-	pstl = 0         # process timeline
-	testnumber = 0
-	idstr = ''
-	html_device_id = 0
-	stamp = 0
-	outfile = ''
-	devpids = []
-	kerror = False
+	phasedef = {
+		'suspend_prepare': {'order': 0, 'color': '#CCFFCC'},
+		        'suspend': {'order': 1, 'color': '#88FF88'},
+		   'suspend_late': {'order': 2, 'color': '#00AA00'},
+		  'suspend_noirq': {'order': 3, 'color': '#008888'},
+		'suspend_machine': {'order': 4, 'color': '#0000FF'},
+		 'resume_machine': {'order': 5, 'color': '#FF0000'},
+		   'resume_noirq': {'order': 6, 'color': '#FF9900'},
+		   'resume_early': {'order': 7, 'color': '#FFCC00'},
+		         'resume': {'order': 8, 'color': '#FFFF88'},
+		'resume_complete': {'order': 9, 'color': '#FFFFCC'},
+	}
+	errlist = {
+		'HWERROR' : '.*\[ *Hardware Error *\].*',
+		'FWBUG'   : '.*\[ *Firmware Bug *\].*',
+		'BUG'     : '.*BUG.*',
+		'ERROR'   : '.*ERROR.*',
+		'WARNING' : '.*WARNING.*',
+		'IRQ'     : '.*genirq: .*',
+		'TASKFAIL': '.*Freezing of tasks *.*',
+		'ACPI'    : '.*ACPI *(?P<b>[A-Za-z]*) *Error[: ].*',
+		'DEVFAIL' : '.* failed to (?P<b>[a-z]*) async: .*',
+		'DISKFULL': '.*No space left on device.*',
+		'USBERR'  : '.*usb .*device .*, error [0-9-]*',
+		'ATAERR'  : ' *ata[0-9\.]*: .*failed.*',
+		'MEIERR'  : ' *mei.*: .*failed.*',
+		'TPMERR'  : '(?i) *tpm *tpm[0-9]*: .*error.*',
+	}
 	def __init__(self, num):
 		idchar = 'abcdefghij'
-		self.pstl = dict()
+		self.start = 0.0 # test start
+		self.end = 0.0   # test end
+		self.tSuspended = 0.0 # low-level suspend start
+		self.tResumed = 0.0   # low-level resume start
+		self.tKernSus = 0.0   # kernel level suspend start
+		self.tKernRes = 0.0   # kernel level resume end
+		self.fwValid = False  # is firmware data available
+		self.fwSuspend = 0    # time spent in firmware suspend
+		self.fwResume = 0     # time spent in firmware resume
+		self.html_device_id = 0
+		self.stamp = 0
+		self.outfile = ''
+		self.kerror = False
+		self.battery = 0
+		self.wifi = 0
+		self.turbostat = 0
+		self.mcelog = 0
+		self.enterfail = ''
+		self.currphase = ''
+		self.pstl = dict()    # process timeline
 		self.testnumber = num
 		self.idstr = idchar[num]
-		self.dmesgtext = []
-		self.phases = []
-		self.dmesg = { # fixed list of 10 phases
-			'suspend_prepare': {'list': dict(), 'start': -1.0, 'end': -1.0,
-								'row': 0, 'color': '#CCFFCC', 'order': 0},
-			        'suspend': {'list': dict(), 'start': -1.0, 'end': -1.0,
-								'row': 0, 'color': '#88FF88', 'order': 1},
-			   'suspend_late': {'list': dict(), 'start': -1.0, 'end': -1.0,
-								'row': 0, 'color': '#00AA00', 'order': 2},
-			  'suspend_noirq': {'list': dict(), 'start': -1.0, 'end': -1.0,
-								'row': 0, 'color': '#008888', 'order': 3},
-		    'suspend_machine': {'list': dict(), 'start': -1.0, 'end': -1.0,
-								'row': 0, 'color': '#0000FF', 'order': 4},
-			 'resume_machine': {'list': dict(), 'start': -1.0, 'end': -1.0,
-								'row': 0, 'color': '#FF0000', 'order': 5},
-			   'resume_noirq': {'list': dict(), 'start': -1.0, 'end': -1.0,
-								'row': 0, 'color': '#FF9900', 'order': 6},
-			   'resume_early': {'list': dict(), 'start': -1.0, 'end': -1.0,
-								'row': 0, 'color': '#FFCC00', 'order': 7},
-			         'resume': {'list': dict(), 'start': -1.0, 'end': -1.0,
-								'row': 0, 'color': '#FFFF88', 'order': 8},
-			'resume_complete': {'list': dict(), 'start': -1.0, 'end': -1.0,
-								'row': 0, 'color': '#FFFFCC', 'order': 9}
-		}
-		self.phases = self.sortedPhases()
-		self.devicegroups = []
-		for phase in self.phases:
-			self.devicegroups.append([phase])
+		self.dmesgtext = []   # dmesg text file in memory
+		self.dmesg = dict()   # root data structure
 		self.errorinfo = {'suspend':[],'resume':[]}
+		self.tLow = []        # time spent in low-level suspends (standby/freeze)
+		self.devpids = []
+		self.devicegroups = 0
+	def sortedPhases(self):
+		return sorted(self.dmesg, key=lambda k:self.dmesg[k]['order'])
+	def initDevicegroups(self):
+		# called when phases are all finished being added
+		for phase in sorted(self.dmesg.keys()):
+			if '*' in phase:
+				p = phase.split('*')
+				pnew = '%s%d' % (p[0], len(p))
+				self.dmesg[pnew] = self.dmesg.pop(phase)
+		self.devicegroups = []
+		for phase in self.sortedPhases():
+			self.devicegroups.append([phase])
+	def nextPhase(self, phase, offset):
+		order = self.dmesg[phase]['order'] + offset
+		for p in self.dmesg:
+			if self.dmesg[p]['order'] == order:
+				return p
+		return ''
+	def lastPhase(self):
+		plist = self.sortedPhases()
+		if len(plist) < 1:
+			return ''
+		return plist[-1]
+	def turbostatInfo(self):
+		tp = TestProps()
+		out = {'syslpi':'N/A','pkgpc10':'N/A'}
+		for line in self.dmesgtext:
+			m = re.match(tp.tstatfmt, line)
+			if not m:
+				continue
+			for i in m.group('t').split('|'):
+				if 'SYS%LPI' in i:
+					out['syslpi'] = i.split('=')[-1]+'%'
+				elif 'pc10' in i:
+					out['pkgpc10'] = i.split('=')[-1]+'%'
+			break
+		return out
 	def extractErrorInfo(self):
-		elist = {
-			'HWERROR' : '.*\[ *Hardware Error *\].*',
-			'FWBUG'   : '.*\[ *Firmware Bug *\].*',
-			'BUG'     : '.*BUG.*',
-			'ERROR'   : '.*ERROR.*',
-			'WARNING' : '.*WARNING.*',
-			'IRQ'     : '.*genirq: .*',
-			'TASKFAIL': '.*Freezing of tasks failed.*',
-		}
-		lf = sysvals.openlog(sysvals.dmesgfile, 'r')
+		lf = self.dmesgtext
+		if len(self.dmesgtext) < 1 and sysvals.dmesgfile:
+			lf = sysvals.openlog(sysvals.dmesgfile, 'r')
 		i = 0
 		list = []
 		for line in lf:
@@ -939,24 +1308,27 @@
 				continue
 			dir = 'suspend' if t < self.tSuspended else 'resume'
 			msg = m.group('msg')
-			for err in elist:
-				if re.match(elist[err], msg):
-					list.append((err, dir, t, i, i))
+			for err in self.errlist:
+				if re.match(self.errlist[err], msg):
+					list.append((msg, err, dir, t, i, i))
 					self.kerror = True
 					break
-		for e in list:
-			type, dir, t, idx1, idx2 = e
+		msglist = []
+		for msg, type, dir, t, idx1, idx2 in list:
+			msglist.append(msg)
 			sysvals.vprint('kernel %s found in %s at %f' % (type, dir, t))
 			self.errorinfo[dir].append((type, t, idx1, idx2))
 		if self.kerror:
 			sysvals.dmesglog = True
-		lf.close()
+		if len(self.dmesgtext) < 1 and sysvals.dmesgfile:
+			lf.close()
+		return msglist
 	def setStart(self, time):
 		self.start = time
 	def setEnd(self, time):
 		self.end = time
 	def isTraceEventOutsideDeviceCalls(self, pid, time):
-		for phase in self.phases:
+		for phase in self.sortedPhases():
 			list = self.dmesg[phase]['list']
 			for dev in list:
 				d = list[dev]
@@ -964,16 +1336,10 @@
 					time < d['end']):
 					return False
 		return True
-	def phaseCollision(self, phase, isbegin, line):
-		key = 'end'
-		if isbegin:
-			key = 'start'
-		if self.dmesg[phase][key] >= 0:
-			sysvals.vprint('IGNORE: %s' % line.strip())
-			return True
-		return False
 	def sourcePhase(self, start):
-		for phase in self.phases:
+		for phase in self.sortedPhases():
+			if 'machine' in phase:
+				continue
 			pend = self.dmesg[phase]['end']
 			if start <= pend:
 				return phase
@@ -1004,14 +1370,15 @@
 		return tgtdev
 	def addDeviceFunctionCall(self, displayname, kprobename, proc, pid, start, end, cdata, rdata):
 		# try to place the call in a device
-		tgtdev = self.sourceDevice(self.phases, start, end, pid, 'device')
+		phases = self.sortedPhases()
+		tgtdev = self.sourceDevice(phases, start, end, pid, 'device')
 		# calls with device pids that occur outside device bounds are dropped
 		# TODO: include these somehow
 		if not tgtdev and pid in self.devpids:
 			return False
 		# try to place the call in a thread
 		if not tgtdev:
-			tgtdev = self.sourceDevice(self.phases, start, end, pid, 'thread')
+			tgtdev = self.sourceDevice(phases, start, end, pid, 'thread')
 		# create new thread blocks, expand as new calls are found
 		if not tgtdev:
 			if proc == '<...>':
@@ -1053,7 +1420,7 @@
 	def overflowDevices(self):
 		# get a list of devices that extend beyond the end of this test run
 		devlist = []
-		for phase in self.phases:
+		for phase in self.sortedPhases():
 			list = self.dmesg[phase]['list']
 			for devname in list:
 				dev = list[devname]
@@ -1064,7 +1431,7 @@
 		# merge any devices that overlap devlist
 		for dev in devlist:
 			devname = dev['name']
-			for phase in self.phases:
+			for phase in self.sortedPhases():
 				list = self.dmesg[phase]['list']
 				if devname not in list:
 					continue
@@ -1079,7 +1446,7 @@
 				del list[devname]
 	def usurpTouchingThread(self, name, dev):
 		# the caller test has priority of this thread, give it to him
-		for phase in self.phases:
+		for phase in self.sortedPhases():
 			list = self.dmesg[phase]['list']
 			if name in list:
 				tdev = list[name]
@@ -1093,7 +1460,7 @@
 				break
 	def stitchTouchingThreads(self, testlist):
 		# merge any threads between tests that touch
-		for phase in self.phases:
+		for phase in self.sortedPhases():
 			list = self.dmesg[phase]['list']
 			for devname in list:
 				dev = list[devname]
@@ -1103,7 +1470,7 @@
 					data.usurpTouchingThread(devname, dev)
 	def optimizeDevSrc(self):
 		# merge any src call loops to reduce timeline size
-		for phase in self.phases:
+		for phase in self.sortedPhases():
 			list = self.dmesg[phase]['list']
 			for dev in list:
 				if 'src' not in list[dev]:
@@ -1141,7 +1508,7 @@
 		self.tKernSus = self.trimTimeVal(self.tKernSus, t0, dT, left)
 		self.tKernRes = self.trimTimeVal(self.tKernRes, t0, dT, left)
 		self.end = self.trimTimeVal(self.end, t0, dT, left)
-		for phase in self.phases:
+		for phase in self.sortedPhases():
 			p = self.dmesg[phase]
 			p['start'] = self.trimTimeVal(p['start'], t0, dT, left)
 			p['end'] = self.trimTimeVal(p['end'], t0, dT, left)
@@ -1150,6 +1517,7 @@
 				d = list[name]
 				d['start'] = self.trimTimeVal(d['start'], t0, dT, left)
 				d['end'] = self.trimTimeVal(d['end'], t0, dT, left)
+				d['length'] = d['end'] - d['start']
 				if('ftrace' in d):
 					cg = d['ftrace']
 					cg.start = self.trimTimeVal(cg.start, t0, dT, left)
@@ -1166,55 +1534,67 @@
 				tm = self.trimTimeVal(tm, t0, dT, left)
 				list.append((type, tm, idx1, idx2))
 			self.errorinfo[dir] = list
-	def normalizeTime(self, tZero):
+	def trimFreezeTime(self, tZero):
 		# trim out any standby or freeze clock time
-		if(self.tSuspended != self.tResumed):
-			if(self.tResumed > tZero):
-				self.trimTime(self.tSuspended, \
-					self.tResumed-self.tSuspended, True)
-			else:
-				self.trimTime(self.tSuspended, \
-					self.tResumed-self.tSuspended, False)
+		lp = ''
+		for phase in self.sortedPhases():
+			if 'resume_machine' in phase and 'suspend_machine' in lp:
+				tS, tR = self.dmesg[lp]['end'], self.dmesg[phase]['start']
+				tL = tR - tS
+				if tL > 0:
+					left = True if tR > tZero else False
+					self.trimTime(tS, tL, left)
+					self.tLow.append('%.0f'%(tL*1000))
+			lp = phase
 	def getTimeValues(self):
-		sktime = (self.dmesg['suspend_machine']['end'] - \
-			self.tKernSus) * 1000
-		rktime = (self.dmesg['resume_complete']['end'] - \
-			self.dmesg['resume_machine']['start']) * 1000
+		sktime = (self.tSuspended - self.tKernSus) * 1000
+		rktime = (self.tKernRes - self.tResumed) * 1000
 		return (sktime, rktime)
-	def setPhase(self, phase, ktime, isbegin):
+	def setPhase(self, phase, ktime, isbegin, order=-1):
 		if(isbegin):
+			# phase start over current phase
+			if self.currphase:
+				if 'resume_machine' not in self.currphase:
+					sysvals.vprint('WARNING: phase %s failed to end' % self.currphase)
+				self.dmesg[self.currphase]['end'] = ktime
+			phases = self.dmesg.keys()
+			color = self.phasedef[phase]['color']
+			count = len(phases) if order < 0 else order
+			# create unique name for every new phase
+			while phase in phases:
+				phase += '*'
+			self.dmesg[phase] = {'list': dict(), 'start': -1.0, 'end': -1.0,
+				'row': 0, 'color': color, 'order': count}
 			self.dmesg[phase]['start'] = ktime
+			self.currphase = phase
 		else:
+			# phase end without a start
+			if phase not in self.currphase:
+				if self.currphase:
+					sysvals.vprint('WARNING: %s ended instead of %s, ftrace corruption?' % (phase, self.currphase))
+				else:
+					sysvals.vprint('WARNING: %s ended without a start, ftrace corruption?' % phase)
+					return phase
+			phase = self.currphase
 			self.dmesg[phase]['end'] = ktime
-	def dmesgSortVal(self, phase):
-		return self.dmesg[phase]['order']
-	def sortedPhases(self):
-		return sorted(self.dmesg, key=self.dmesgSortVal)
+			self.currphase = ''
+		return phase
 	def sortedDevices(self, phase):
 		list = self.dmesg[phase]['list']
-		slist = []
-		tmp = dict()
-		for devname in list:
-			dev = list[devname]
-			if dev['length'] == 0:
-				continue
-			tmp[dev['start']] = devname
-		for t in sorted(tmp):
-			slist.append(tmp[t])
-		return slist
+		return sorted(list, key=lambda k:list[k]['start'])
 	def fixupInitcalls(self, phase):
 		# if any calls never returned, clip them at system resume end
 		phaselist = self.dmesg[phase]['list']
 		for devname in phaselist:
 			dev = phaselist[devname]
 			if(dev['end'] < 0):
-				for p in self.phases:
+				for p in self.sortedPhases():
 					if self.dmesg[p]['end'] > dev['start']:
 						dev['end'] = self.dmesg[p]['end']
 						break
 				sysvals.vprint('%s (%s): callback didnt return' % (devname, phase))
 	def deviceFilter(self, devicefilter):
-		for phase in self.phases:
+		for phase in self.sortedPhases():
 			list = self.dmesg[phase]['list']
 			rmlist = []
 			for name in list:
@@ -1229,7 +1609,7 @@
 				del list[name]
 	def fixupInitcallsThatDidntReturn(self):
 		# if any calls never returned, clip them at system resume end
-		for phase in self.phases:
+		for phase in self.sortedPhases():
 			self.fixupInitcalls(phase)
 	def phaseOverlap(self, phases):
 		rmgroups = []
@@ -1248,17 +1628,18 @@
 		self.devicegroups.append(newgroup)
 	def newActionGlobal(self, name, start, end, pid=-1, color=''):
 		# which phase is this device callback or action in
+		phases = self.sortedPhases()
 		targetphase = 'none'
 		htmlclass = ''
 		overlap = 0.0
-		phases = []
-		for phase in self.phases:
+		myphases = []
+		for phase in phases:
 			pstart = self.dmesg[phase]['start']
 			pend = self.dmesg[phase]['end']
 			# see if the action overlaps this phase
 			o = max(0, min(end, pend) - max(start, pstart))
 			if o > 0:
-				phases.append(phase)
+				myphases.append(phase)
 			# set the target phase to the one that overlaps most
 			if o > overlap:
 				if overlap > 0 and phase == 'post_resume':
@@ -1267,19 +1648,19 @@
 				overlap = o
 		# if no target phase was found, pin it to the edge
 		if targetphase == 'none':
-			p0start = self.dmesg[self.phases[0]]['start']
+			p0start = self.dmesg[phases[0]]['start']
 			if start <= p0start:
-				targetphase = self.phases[0]
+				targetphase = phases[0]
 			else:
-				targetphase = self.phases[-1]
+				targetphase = phases[-1]
 		if pid == -2:
 			htmlclass = ' bg'
 		elif pid == -3:
 			htmlclass = ' ps'
-		if len(phases) > 1:
+		if len(myphases) > 1:
 			htmlclass = ' bg'
-			self.phaseOverlap(phases)
-		if targetphase in self.phases:
+			self.phaseOverlap(myphases)
+		if targetphase in phases:
 			newname = self.newAction(targetphase, name, pid, '', start, end, '', htmlclass, color)
 			return (targetphase, newname)
 		return False
@@ -1311,21 +1692,45 @@
 			if(list[child]['par'] == devname):
 				devlist.append(child)
 		return devlist
+	def maxDeviceNameSize(self, phase):
+		size = 0
+		for name in self.dmesg[phase]['list']:
+			if len(name) > size:
+				size = len(name)
+		return size
 	def printDetails(self):
 		sysvals.vprint('Timeline Details:')
 		sysvals.vprint('          test start: %f' % self.start)
 		sysvals.vprint('kernel suspend start: %f' % self.tKernSus)
-		for phase in self.phases:
-			dc = len(self.dmesg[phase]['list'])
-			sysvals.vprint('    %16s: %f - %f (%d devices)' % (phase, \
-				self.dmesg[phase]['start'], self.dmesg[phase]['end'], dc))
+		tS = tR = False
+		for phase in self.sortedPhases():
+			devlist = self.dmesg[phase]['list']
+			dc, ps, pe = len(devlist), self.dmesg[phase]['start'], self.dmesg[phase]['end']
+			if not tS and ps >= self.tSuspended:
+				sysvals.vprint('   machine suspended: %f' % self.tSuspended)
+				tS = True
+			if not tR and ps >= self.tResumed:
+				sysvals.vprint('     machine resumed: %f' % self.tResumed)
+				tR = True
+			sysvals.vprint('%20s: %f - %f (%d devices)' % (phase, ps, pe, dc))
+			if sysvals.devdump:
+				sysvals.vprint(''.join('-' for i in range(80)))
+				maxname = '%d' % self.maxDeviceNameSize(phase)
+				fmt = '%3d) %'+maxname+'s - %f - %f'
+				c = 1
+				for name in sorted(devlist):
+					s = devlist[name]['start']
+					e = devlist[name]['end']
+					sysvals.vprint(fmt % (c, name, s, e))
+					c += 1
+				sysvals.vprint(''.join('-' for i in range(80)))
 		sysvals.vprint('   kernel resume end: %f' % self.tKernRes)
 		sysvals.vprint('            test end: %f' % self.end)
 	def deviceChildrenAllPhases(self, devname):
 		devlist = []
-		for phase in self.phases:
+		for phase in self.sortedPhases():
 			list = self.deviceChildren(devname, phase)
-			for dev in list:
+			for dev in sorted(list):
 				if dev not in devlist:
 					devlist.append(dev)
 		return devlist
@@ -1344,7 +1749,7 @@
 		if node.name:
 			info = ''
 			drv = ''
-			for phase in self.phases:
+			for phase in self.sortedPhases():
 				list = self.dmesg[phase]['list']
 				if node.name in list:
 					s = list[node.name]['start']
@@ -1365,16 +1770,16 @@
 	def rootDeviceList(self):
 		# list of devices graphed
 		real = []
-		for phase in self.dmesg:
+		for phase in self.sortedPhases():
 			list = self.dmesg[phase]['list']
-			for dev in list:
+			for dev in sorted(list):
 				if list[dev]['pid'] >= 0 and dev not in real:
 					real.append(dev)
 		# list of top-most root devices
 		rootlist = []
-		for phase in self.dmesg:
+		for phase in self.sortedPhases():
 			list = self.dmesg[phase]['list']
-			for dev in list:
+			for dev in sorted(list):
 				pdev = list[dev]['par']
 				pid = list[dev]['pid']
 				if(pid < 0 or re.match('[0-9]*-[0-9]*\.[0-9]*[\.0-9]*\:[\.0-9]*$', pdev)):
@@ -1455,9 +1860,9 @@
 	def createProcessUsageEvents(self):
 		# get an array of process names
 		proclist = []
-		for t in self.pstl:
+		for t in sorted(self.pstl):
 			pslist = self.pstl[t]
-			for ps in pslist:
+			for ps in sorted(pslist):
 				if ps not in proclist:
 					proclist.append(ps)
 		# get a list of data points for suspend and resume
@@ -1478,10 +1883,31 @@
 			c = self.addProcessUsageEvent(ps, tres)
 			if c > 0:
 				sysvals.vprint('%25s (res): %d' % (ps, c))
+	def handleEndMarker(self, time):
+		dm = self.dmesg
+		self.setEnd(time)
+		self.initDevicegroups()
+		# give suspend_prepare an end if needed
+		if 'suspend_prepare' in dm and dm['suspend_prepare']['end'] < 0:
+			dm['suspend_prepare']['end'] = time
+		# assume resume machine ends at next phase start
+		if 'resume_machine' in dm and dm['resume_machine']['end'] < 0:
+			np = self.nextPhase('resume_machine', 1)
+			if np:
+				dm['resume_machine']['end'] = dm[np]['start']
+		# if kernel resume end not found, assume its the end marker
+		if self.tKernRes == 0.0:
+			self.tKernRes = time
+		# if kernel suspend start not found, assume its the end marker
+		if self.tKernSus == 0.0:
+			self.tKernSus = time
+		# set resume complete to end at end marker
+		if 'resume_complete' in dm:
+			dm['resume_complete']['end'] = time
 	def debugPrint(self):
-		for p in self.phases:
+		for p in self.sortedPhases():
 			list = self.dmesg[p]['list']
-			for devname in list:
+			for devname in sorted(list):
 				dev = list[devname]
 				if 'ftrace' in dev:
 					dev['ftrace'].debugPrint(' [%s]' % devname)
@@ -1490,9 +1916,9 @@
 # Description:
 #	 A container for kprobe function data we want in the dev timeline
 class DevFunction:
-	row = 0
-	count = 1
 	def __init__(self, name, args, caller, ret, start, end, u, proc, pid, color):
+		self.row = 0
+		self.count = 1
 		self.name = name
 		self.args = args
 		self.caller = caller
@@ -1546,16 +1972,15 @@
 #			 suspend_resume: phase or custom exec block data
 #			 device_pm_callback: device callback info
 class FTraceLine:
-	time = 0.0
-	length = 0.0
-	fcall = False
-	freturn = False
-	fevent = False
-	fkprobe = False
-	depth = 0
-	name = ''
-	type = ''
 	def __init__(self, t, m='', d=''):
+		self.length = 0.0
+		self.fcall = False
+		self.freturn = False
+		self.fevent = False
+		self.fkprobe = False
+		self.depth = 0
+		self.name = ''
+		self.type = ''
 		self.time = float(t)
 		if not m and not d:
 			return
@@ -1633,13 +2058,13 @@
 		return len(str)/2
 	def debugPrint(self, info=''):
 		if self.isLeaf():
-			print(' -- %12.6f (depth=%02d): %s(); (%.3f us) %s' % (self.time, \
+			pprint(' -- %12.6f (depth=%02d): %s(); (%.3f us) %s' % (self.time, \
 				self.depth, self.name, self.length*1000000, info))
 		elif self.freturn:
-			print(' -- %12.6f (depth=%02d): %s} (%.3f us) %s' % (self.time, \
+			pprint(' -- %12.6f (depth=%02d): %s} (%.3f us) %s' % (self.time, \
 				self.depth, self.name, self.length*1000000, info))
 		else:
-			print(' -- %12.6f (depth=%02d): %s() { (%.3f us) %s' % (self.time, \
+			pprint(' -- %12.6f (depth=%02d): %s() { (%.3f us) %s' % (self.time, \
 				self.depth, self.name, self.length*1000000, info))
 	def startMarker(self):
 		# Is this the starting line of a suspend?
@@ -1675,19 +2100,13 @@
 #	 Each instance is tied to a single device in a single phase, and is
 #	 comprised of an ordered list of FTraceLine objects
 class FTraceCallGraph:
-	id = ''
-	start = -1.0
-	end = -1.0
-	list = []
-	invalid = False
-	depth = 0
-	pid = 0
-	name = ''
-	partial = False
 	vfname = 'missing_function_name'
-	ignore = False
-	sv = 0
 	def __init__(self, pid, sv):
+		self.id = ''
+		self.invalid = False
+		self.name = ''
+		self.partial = False
+		self.ignore = False
 		self.start = -1.0
 		self.end = -1.0
 		self.list = []
@@ -1786,7 +2205,7 @@
 			if warning and ('[make leaf]', line) not in info:
 				info.append(('', line))
 		if warning:
-			print 'WARNING: ftrace data missing, corrections made:'
+			pprint('WARNING: ftrace data missing, corrections made:')
 			for i in info:
 				t, obj = i
 				if obj:
@@ -1846,10 +2265,10 @@
 		id = 'task %s' % (self.pid)
 		window = '(%f - %f)' % (self.start, line.time)
 		if(self.depth < 0):
-			print('Data misalignment for '+id+\
+			pprint('Data misalignment for '+id+\
 				' (buffer overflow), ignoring this callback')
 		else:
-			print('Too much data for '+id+\
+			pprint('Too much data for '+id+\
 				' '+window+', ignoring this callback')
 	def slice(self, dev):
 		minicg = FTraceCallGraph(dev['pid'], self.sv)
@@ -1902,7 +2321,7 @@
 			elif l.isReturn():
 				if(l.depth not in stack):
 					if self.sv.verbose:
-						print 'Post Process Error: Depth missing'
+						pprint('Post Process Error: Depth missing')
 						l.debugPrint()
 					return False
 				# calculate call length from call/return lines
@@ -1919,7 +2338,7 @@
 			return True
 		elif(cnt < 0):
 			if self.sv.verbose:
-				print 'Post Process Error: Depth is less than 0'
+				pprint('Post Process Error: Depth is less than 0')
 			return False
 		# trace ended before call tree finished
 		return self.repair(cnt)
@@ -1943,11 +2362,11 @@
 						dev['ftrace'] = cg
 					found = devname
 			return found
-		for p in data.phases:
+		for p in data.sortedPhases():
 			if(data.dmesg[p]['start'] <= self.start and
 				self.start <= data.dmesg[p]['end']):
 				list = data.dmesg[p]['list']
-				for devname in list:
+				for devname in sorted(list, key=lambda k:list[k]['start']):
 					dev = list[devname]
 					if(pid == dev['pid'] and
 						self.start <= dev['start'] and
@@ -1966,7 +2385,7 @@
 		if fs < data.start or fe > data.end:
 			return
 		phase = ''
-		for p in data.phases:
+		for p in data.sortedPhases():
 			if(data.dmesg[p]['start'] <= self.start and
 				self.start < data.dmesg[p]['end']):
 				phase = p
@@ -1978,20 +2397,20 @@
 			phase, myname = out
 			data.dmesg[phase]['list'][myname]['ftrace'] = self
 	def debugPrint(self, info=''):
-		print('%s pid=%d [%f - %f] %.3f us') % \
+		pprint('%s pid=%d [%f - %f] %.3f us' % \
 			(self.name, self.pid, self.start, self.end,
-			(self.end - self.start)*1000000)
+			(self.end - self.start)*1000000))
 		for l in self.list:
 			if l.isLeaf():
-				print('%f (%02d): %s(); (%.3f us)%s' % (l.time, \
+				pprint('%f (%02d): %s(); (%.3f us)%s' % (l.time, \
 					l.depth, l.name, l.length*1000000, info))
 			elif l.freturn:
-				print('%f (%02d): %s} (%.3f us)%s' % (l.time, \
+				pprint('%f (%02d): %s} (%.3f us)%s' % (l.time, \
 					l.depth, l.name, l.length*1000000, info))
 			else:
-				print('%f (%02d): %s() { (%.3f us)%s' % (l.time, \
+				pprint('%f (%02d): %s() { (%.3f us)%s' % (l.time, \
 					l.depth, l.name, l.length*1000000, info))
-		print(' ')
+		pprint(' ')
 
 class DevItem:
 	def __init__(self, test, phase, dev):
@@ -2008,23 +2427,20 @@
 #	 A container for a device timeline which calculates
 #	 all the html properties to display it correctly
 class Timeline:
-	html = ''
-	height = 0	# total timeline height
-	scaleH = 20	# timescale (top) row height
-	rowH = 30	# device row height
-	bodyH = 0	# body height
-	rows = 0	# total timeline rows
-	rowlines = dict()
-	rowheight = dict()
 	html_tblock = '<div id="block{0}" class="tblock" style="left:{1}%;width:{2}%;"><div class="tback" style="height:{3}px"></div>\n'
 	html_device = '<div id="{0}" title="{1}" class="thread{7}" style="left:{2}%;top:{3}px;height:{4}px;width:{5}%;{8}">{6}</div>\n'
 	html_phase = '<div class="phase" style="left:{0}%;width:{1}%;top:{2}px;height:{3}px;background:{4}">{5}</div>\n'
 	html_phaselet = '<div id="{0}" class="phaselet" style="left:{1}%;width:{2}%;background:{3}"></div>\n'
 	html_legend = '<div id="p{3}" class="square" style="left:{0}%;background:{1}">&nbsp;{2}</div>\n'
 	def __init__(self, rowheight, scaleheight):
-		self.rowH = rowheight
-		self.scaleH = scaleheight
 		self.html = ''
+		self.height = 0  # total timeline height
+		self.scaleH = scaleheight # timescale (top) row height
+		self.rowH = rowheight     # device row height
+		self.bodyH = 0   # body height
+		self.rows = 0    # total timeline rows
+		self.rowlines = dict()
+		self.rowheight = dict()
 	def createHeader(self, sv, stamp):
 		if(not stamp['time']):
 			return
@@ -2192,7 +2608,7 @@
 		# if there is 1 line per row, draw them the standard way
 		for t, p in standardphases:
 			for i in sorted(self.rowheight[t][p]):
-				self.rowheight[t][p][i] = self.bodyH/len(self.rowlines[t][p])
+				self.rowheight[t][p][i] = float(self.bodyH)/len(self.rowlines[t][p])
 	def createZoomBox(self, mode='command', testcount=1):
 		# Create bounding box, add buttons
 		html_zoombox = '<center><button id="zoomin">ZOOM IN +</button><button id="zoomout">ZOOM OUT -</button><button id="zoomdef">ZOOM 1:1</button></center>\n'
@@ -2251,18 +2667,22 @@
 # Description:
 #	 A list of values describing the properties of these test runs
 class TestProps:
-	stamp = ''
-	sysinfo = ''
-	cmdline = ''
-	kparams = ''
-	S0i3 = False
-	fwdata = []
 	stampfmt = '# [a-z]*-(?P<m>[0-9]{2})(?P<d>[0-9]{2})(?P<y>[0-9]{2})-'+\
 				'(?P<H>[0-9]{2})(?P<M>[0-9]{2})(?P<S>[0-9]{2})'+\
 				' (?P<host>.*) (?P<mode>.*) (?P<kernel>.*)$'
+	batteryfmt = '^# battery (?P<a1>\w*) (?P<c1>\d*) (?P<a2>\w*) (?P<c2>\d*)'
+	wififmt    = '^# wifi (?P<w>.*)'
+	tstatfmt   = '^# turbostat (?P<t>\S*)'
+	mcelogfmt  = '^# mcelog (?P<m>\S*)'
+	testerrfmt = '^# enter_sleep_error (?P<e>.*)'
 	sysinfofmt = '^# sysinfo .*'
 	cmdlinefmt = '^# command \| (?P<cmd>.*)'
 	kparamsfmt = '^# kparams \| (?P<kp>.*)'
+	devpropfmt = '# Device Properties: .*'
+	pinfofmt   = '# platform-(?P<val>[a-z,A-Z,0-9]*): (?P<info>.*)'
+	tracertypefmt = '# tracer: (?P<t>.*)'
+	firmwarefmt = '# fwsuspend (?P<s>[0-9]*) fwresume (?P<r>[0-9]*)$'
+	procexecfmt = 'ps - (?P<ps>.*)$'
 	ftrace_line_fmt_fg = \
 		'^ *(?P<time>[0-9\.]*) *\| *(?P<cpu>[0-9]*)\)'+\
 		' *(?P<proc>.*)-(?P<pid>[0-9]*) *\|'+\
@@ -2271,11 +2691,20 @@
 		' *(?P<proc>.*)-(?P<pid>[0-9]*) *\[(?P<cpu>[0-9]*)\] *'+\
 		'(?P<flags>.{4}) *(?P<time>[0-9\.]*): *'+\
 		'(?P<msg>.*)'
-	ftrace_line_fmt = ftrace_line_fmt_nop
-	cgformat = False
-	data = 0
-	ktemp = dict()
 	def __init__(self):
+		self.stamp = ''
+		self.sysinfo = ''
+		self.cmdline = ''
+		self.kparams = ''
+		self.testerror = []
+		self.mcelog = []
+		self.turbostat = []
+		self.battery = []
+		self.wifi = []
+		self.fwdata = []
+		self.ftrace_line_fmt = self.ftrace_line_fmt_nop
+		self.cgformat = False
+		self.data = 0
 		self.ktemp = dict()
 	def setTracerType(self, tracer):
 		if(tracer == 'function_graph'):
@@ -2285,7 +2714,40 @@
 			self.ftrace_line_fmt = self.ftrace_line_fmt_nop
 		else:
 			doError('Invalid tracer format: [%s]' % tracer)
+	def stampInfo(self, line):
+		if re.match(self.stampfmt, line):
+			self.stamp = line
+			return True
+		elif re.match(self.sysinfofmt, line):
+			self.sysinfo = line
+			return True
+		elif re.match(self.kparamsfmt, line):
+			self.kparams = line
+			return True
+		elif re.match(self.cmdlinefmt, line):
+			self.cmdline = line
+			return True
+		elif re.match(self.mcelogfmt, line):
+			self.mcelog.append(line)
+			return True
+		elif re.match(self.tstatfmt, line):
+			self.turbostat.append(line)
+			return True
+		elif re.match(self.batteryfmt, line):
+			self.battery.append(line)
+			return True
+		elif re.match(self.wififmt, line):
+			self.wifi.append(line)
+			return True
+		elif re.match(self.testerrfmt, line):
+			self.testerror.append(line)
+			return True
+		elif re.match(self.firmwarefmt, line):
+			self.fwdata.append(line)
+			return True
+		return False
 	def parseStamp(self, data, sv):
+		# global test data
 		m = re.match(self.stampfmt, self.stamp)
 		data.stamp = {'time': '', 'host': '', 'mode': ''}
 		dt = datetime(int(m.group('y'))+2000, int(m.group('m')),
@@ -2324,29 +2786,99 @@
 				sv.kparams = m.group('kp')
 		if not sv.stamp:
 			sv.stamp = data.stamp
+		# firmware data
+		if sv.suspendmode == 'mem' and len(self.fwdata) > data.testnumber:
+			m = re.match(self.firmwarefmt, self.fwdata[data.testnumber])
+			if m:
+				data.fwSuspend, data.fwResume = int(m.group('s')), int(m.group('r'))
+				if(data.fwSuspend > 0 or data.fwResume > 0):
+					data.fwValid = True
+		# mcelog data
+		if len(self.mcelog) > data.testnumber:
+			m = re.match(self.mcelogfmt, self.mcelog[data.testnumber])
+			if m:
+				data.mcelog = sv.b64unzip(m.group('m'))
+		# turbostat data
+		if len(self.turbostat) > data.testnumber:
+			m = re.match(self.tstatfmt, self.turbostat[data.testnumber])
+			if m:
+				data.turbostat = m.group('t')
+		# battery data
+		if len(self.battery) > data.testnumber:
+			m = re.match(self.batteryfmt, self.battery[data.testnumber])
+			if m:
+				data.battery = m.groups()
+		# wifi data
+		if len(self.wifi) > data.testnumber:
+			m = re.match(self.wififmt, self.wifi[data.testnumber])
+			if m:
+				data.wifi = m.group('w')
+		# sleep mode enter errors
+		if len(self.testerror) > data.testnumber:
+			m = re.match(self.testerrfmt, self.testerror[data.testnumber])
+			if m:
+				data.enterfail = m.group('e')
+	def devprops(self, data):
+		props = dict()
+		devlist = data.split(';')
+		for dev in devlist:
+			f = dev.split(',')
+			if len(f) < 3:
+				continue
+			dev = f[0]
+			props[dev] = DevProps()
+			props[dev].altname = f[1]
+			if int(f[2]):
+				props[dev].isasync = True
+			else:
+				props[dev].isasync = False
+		return props
+	def parseDevprops(self, line, sv):
+		idx = line.index(': ') + 2
+		if idx >= len(line):
+			return
+		props = self.devprops(line[idx:])
+		if sv.suspendmode == 'command' and 'testcommandstring' in props:
+			sv.testcommand = props['testcommandstring'].altname
+		sv.devprops = props
+	def parsePlatformInfo(self, line, sv):
+		m = re.match(self.pinfofmt, line)
+		if not m:
+			return
+		name, info = m.group('val'), m.group('info')
+		if name == 'devinfo':
+			sv.devprops = self.devprops(sv.b64unzip(info))
+			return
+		elif name == 'testcmd':
+			sv.testcommand = info
+			return
+		field = info.split('|')
+		if len(field) < 2:
+			return
+		cmdline = field[0].strip()
+		output = sv.b64unzip(field[1].strip())
+		sv.platinfo.append([name, cmdline, output])
 
 # Class: TestRun
 # Description:
 #	 A container for a suspend/resume test run. This is necessary as
 #	 there could be more than one, and they need to be separate.
 class TestRun:
-	ftemp = dict()
-	ttemp = dict()
-	data = 0
 	def __init__(self, dataobj):
 		self.data = dataobj
 		self.ftemp = dict()
 		self.ttemp = dict()
 
 class ProcessMonitor:
-	proclist = dict()
-	running = False
+	def __init__(self):
+		self.proclist = dict()
+		self.running = False
 	def procstat(self):
 		c = ['cat /proc/[1-9]*/stat 2>/dev/null']
 		process = Popen(c, shell=True, stdout=PIPE)
 		running = dict()
 		for line in process.stdout:
-			data = line.split()
+			data = ascii(line).split()
 			pid = data[0]
 			name = re.sub('[()]', '', data[1])
 			user = int(data[13])
@@ -2390,8 +2922,8 @@
 #	 Quickly determine if the ftrace log has all of the trace events,
 #	 markers, and/or kprobes required for primary parsing.
 def doesTraceLogHaveTraceEvents():
-	kpcheck = ['_cal: (', '_cpu_down()']
-	techeck = ['suspend_resume']
+	kpcheck = ['_cal: (', '_ret: (']
+	techeck = ['suspend_resume', 'device_pm_callback']
 	tmcheck = ['SUSPEND START', 'RESUME COMPLETE']
 	sysvals.usekprobes = False
 	fp = sysvals.openlog(sysvals.ftracefile, 'r')
@@ -2414,23 +2946,14 @@
 				check.remove(i)
 		tmcheck = check
 	fp.close()
-	if len(techeck) == 0:
-		sysvals.usetraceevents = True
-	else:
-		sysvals.usetraceevents = False
-	if len(tmcheck) == 0:
-		sysvals.usetracemarkers = True
-	else:
-		sysvals.usetracemarkers = False
+	sysvals.usetraceevents = True if len(techeck) < 2 else False
+	sysvals.usetracemarkers = True if len(tmcheck) == 0 else False
 
 # Function: appendIncompleteTraceLog
 # Description:
 #	 [deprecated for kernel 3.15 or newer]
-#	 Legacy support of ftrace outputs that lack the device_pm_callback
-#	 and/or suspend_resume trace events. The primary data should be
-#	 taken from dmesg, and this ftrace is used only for callgraph data
-#	 or custom actions in the timeline. The data is appended to the Data
-#	 objects provided.
+#	 Adds callgraph data which lacks trace event data. This is only
+#	 for timelines generated from 3.15 or older
 # Arguments:
 #	 testruns: the array of Data objects obtained from parseKernelLog
 def appendIncompleteTraceLog(testruns):
@@ -2450,24 +2973,20 @@
 	for line in tf:
 		# remove any latent carriage returns
 		line = line.replace('\r\n', '')
-		# grab the stamp and sysinfo
-		if re.match(tp.stampfmt, line):
-			tp.stamp = line
-			continue
-		elif re.match(tp.sysinfofmt, line):
-			tp.sysinfo = line
-			continue
-		elif re.match(tp.cmdlinefmt, line):
-			tp.cmdline = line
+		if tp.stampInfo(line):
 			continue
 		# determine the trace data type (required for further parsing)
-		m = re.match(sysvals.tracertypefmt, line)
+		m = re.match(tp.tracertypefmt, line)
 		if(m):
 			tp.setTracerType(m.group('t'))
 			continue
 		# device properties line
-		if(re.match(sysvals.devpropfmt, line)):
-			devProps(line)
+		if(re.match(tp.devpropfmt, line)):
+			tp.parseDevprops(line, sysvals)
+			continue
+		# platform info line
+		if(re.match(tp.pinfofmt, line)):
+			tp.parsePlatformInfo(line, sysvals)
 			continue
 		# parse only valid lines, if this is not one move on
 		m = re.match(tp.ftrace_line_fmt, line)
@@ -2506,87 +3025,7 @@
 			continue
 		# trace event processing
 		if(t.fevent):
-			# general trace events have two types, begin and end
-			if(re.match('(?P<name>.*) begin$', t.name)):
-				isbegin = True
-			elif(re.match('(?P<name>.*) end$', t.name)):
-				isbegin = False
-			else:
-				continue
-			m = re.match('(?P<name>.*)\[(?P<val>[0-9]*)\] .*', t.name)
-			if(m):
-				val = m.group('val')
-				if val == '0':
-					name = m.group('name')
-				else:
-					name = m.group('name')+'['+val+']'
-			else:
-				m = re.match('(?P<name>.*) .*', t.name)
-				name = m.group('name')
-			# special processing for trace events
-			if re.match('dpm_prepare\[.*', name):
-				continue
-			elif re.match('machine_suspend.*', name):
-				continue
-			elif re.match('suspend_enter\[.*', name):
-				if(not isbegin):
-					data.dmesg['suspend_prepare']['end'] = t.time
-				continue
-			elif re.match('dpm_suspend\[.*', name):
-				if(not isbegin):
-					data.dmesg['suspend']['end'] = t.time
-				continue
-			elif re.match('dpm_suspend_late\[.*', name):
-				if(isbegin):
-					data.dmesg['suspend_late']['start'] = t.time
-				else:
-					data.dmesg['suspend_late']['end'] = t.time
-				continue
-			elif re.match('dpm_suspend_noirq\[.*', name):
-				if(isbegin):
-					data.dmesg['suspend_noirq']['start'] = t.time
-				else:
-					data.dmesg['suspend_noirq']['end'] = t.time
-				continue
-			elif re.match('dpm_resume_noirq\[.*', name):
-				if(isbegin):
-					data.dmesg['resume_machine']['end'] = t.time
-					data.dmesg['resume_noirq']['start'] = t.time
-				else:
-					data.dmesg['resume_noirq']['end'] = t.time
-				continue
-			elif re.match('dpm_resume_early\[.*', name):
-				if(isbegin):
-					data.dmesg['resume_early']['start'] = t.time
-				else:
-					data.dmesg['resume_early']['end'] = t.time
-				continue
-			elif re.match('dpm_resume\[.*', name):
-				if(isbegin):
-					data.dmesg['resume']['start'] = t.time
-				else:
-					data.dmesg['resume']['end'] = t.time
-				continue
-			elif re.match('dpm_complete\[.*', name):
-				if(isbegin):
-					data.dmesg['resume_complete']['start'] = t.time
-				else:
-					data.dmesg['resume_complete']['end'] = t.time
-				continue
-			# skip trace events inside devices calls
-			if(not data.isTraceEventOutsideDeviceCalls(pid, t.time)):
-				continue
-			# global events (outside device calls) are simply graphed
-			if(isbegin):
-				# store each trace event in ttemp
-				if(name not in testrun[testidx].ttemp):
-					testrun[testidx].ttemp[name] = []
-				testrun[testidx].ttemp[name].append(\
-					{'begin': t.time, 'end': t.time})
-			else:
-				# finish off matching trace event in ttemp
-				if(name in testrun[testidx].ttemp):
-					testrun[testidx].ttemp[name][-1]['end'] = t.time
+			continue
 		# call/return processing
 		elif sysvals.usecallgraph:
 			# create a callgraph object for the data
@@ -2603,12 +3042,6 @@
 	tf.close()
 
 	for test in testrun:
-		# add the traceevent data to the device hierarchy
-		if(sysvals.usetraceevents):
-			for name in test.ttemp:
-				for event in test.ttemp[name]:
-					test.data.newActionGlobal(name, event['begin'], event['end'])
-
 		# add the callgraph data to the device hierarchy
 		for pid in test.ftemp:
 			for cg in test.ftemp[pid]:
@@ -2621,7 +3054,7 @@
 					continue
 				callstart = cg.start
 				callend = cg.end
-				for p in test.data.phases:
+				for p in test.data.sortedPhases():
 					if(test.data.dmesg[p]['start'] <= callstart and
 						callstart <= test.data.dmesg[p]['end']):
 						list = test.data.dmesg[p]['list']
@@ -2648,10 +3081,13 @@
 		doError('%s does not exist' % sysvals.ftracefile)
 	if not live:
 		sysvals.setupAllKprobes()
-	tracewatch = []
+	ksuscalls = ['pm_prepare_console']
+	krescalls = ['pm_restore_console']
+	tracewatch = ['irq_wakeup']
 	if sysvals.usekprobes:
 		tracewatch += ['sync_filesystems', 'freeze_processes', 'syscore_suspend',
-			'syscore_resume', 'resume_console', 'thaw_processes', 'CPU_ON', 'CPU_OFF']
+			'syscore_resume', 'resume_console', 'thaw_processes', 'CPU_ON',
+			'CPU_OFF', 'timekeeping_freeze', 'acpi_suspend']
 
 	# extract the callgraph and traceevent data
 	tp = TestProps()
@@ -2664,29 +3100,20 @@
 	for line in tf:
 		# remove any latent carriage returns
 		line = line.replace('\r\n', '')
-		# stamp and sysinfo lines
-		if re.match(tp.stampfmt, line):
-			tp.stamp = line
-			continue
-		elif re.match(tp.sysinfofmt, line):
-			tp.sysinfo = line
-			continue
-		elif re.match(tp.cmdlinefmt, line):
-			tp.cmdline = line
-			continue
-		# firmware line: pull out any firmware data
-		m = re.match(sysvals.firmwarefmt, line)
-		if(m):
-			tp.fwdata.append((int(m.group('s')), int(m.group('r'))))
+		if tp.stampInfo(line):
 			continue
 		# tracer type line: determine the trace data type
-		m = re.match(sysvals.tracertypefmt, line)
+		m = re.match(tp.tracertypefmt, line)
 		if(m):
 			tp.setTracerType(m.group('t'))
 			continue
 		# device properties line
-		if(re.match(sysvals.devpropfmt, line)):
-			devProps(line)
+		if(re.match(tp.devpropfmt, line)):
+			tp.parseDevprops(line, sysvals)
+			continue
+		# platform info line
+		if(re.match(tp.pinfofmt, line)):
+			tp.parsePlatformInfo(line, sysvals)
 			continue
 		# ignore all other commented lines
 		if line[0] == '#':
@@ -2714,20 +3141,20 @@
 			continue
 		# find the start of suspend
 		if(t.startMarker()):
-			phase = 'suspend_prepare'
 			data = Data(len(testdata))
 			testdata.append(data)
 			testrun = TestRun(data)
 			testruns.append(testrun)
 			tp.parseStamp(data, sysvals)
 			data.setStart(t.time)
-			data.tKernSus = t.time
+			data.first_suspend_prepare = True
+			phase = data.setPhase('suspend_prepare', t.time, True)
 			continue
 		if(not data):
 			continue
 		# process cpu exec line
 		if t.type == 'tracing_mark_write':
-			m = re.match(sysvals.procexecfmt, t.name)
+			m = re.match(tp.procexecfmt, t.name)
 			if(m):
 				proclist = dict()
 				for ps in m.group('ps').split(','):
@@ -2740,28 +3167,17 @@
 				continue
 		# find the end of resume
 		if(t.endMarker()):
-			data.setEnd(t.time)
-			if data.tKernRes == 0.0:
-				data.tKernRes = t.time
-			if data.dmesg['resume_complete']['end'] < 0:
-				data.dmesg['resume_complete']['end'] = t.time
-			if sysvals.suspendmode == 'mem' and len(tp.fwdata) > data.testnumber:
-				data.fwSuspend, data.fwResume = tp.fwdata[data.testnumber]
-				if(data.tSuspended != 0 and data.tResumed != 0 and \
-					(data.fwSuspend > 0 or data.fwResume > 0)):
-					data.fwValid = True
+			data.handleEndMarker(t.time)
 			if(not sysvals.usetracemarkers):
 				# no trace markers? then quit and be sure to finish recording
 				# the event we used to trigger resume end
-				if(len(testrun.ttemp['thaw_processes']) > 0):
+				if('thaw_processes' in testrun.ttemp and len(testrun.ttemp['thaw_processes']) > 0):
 					# if an entry exists, assume this is its end
 					testrun.ttemp['thaw_processes'][-1]['end'] = t.time
 				break
 			continue
 		# trace event processing
 		if(t.fevent):
-			if(phase == 'post_resume'):
-				data.setEnd(t.time)
 			if(t.type == 'suspend_resume'):
 				# suspend_resume trace events have two types, begin and end
 				if(re.match('(?P<name>.*) begin$', t.name)):
@@ -2770,102 +3186,75 @@
 					isbegin = False
 				else:
 					continue
-				m = re.match('(?P<name>.*)\[(?P<val>[0-9]*)\] .*', t.name)
-				if(m):
-					val = m.group('val')
-					if val == '0':
-						name = m.group('name')
-					else:
-						name = m.group('name')+'['+val+']'
+				if '[' in t.name:
+					m = re.match('(?P<name>.*)\[.*', t.name)
 				else:
 					m = re.match('(?P<name>.*) .*', t.name)
-					name = m.group('name')
+				name = m.group('name')
 				# ignore these events
 				if(name.split('[')[0] in tracewatch):
 					continue
 				# -- phase changes --
 				# start of kernel suspend
 				if(re.match('suspend_enter\[.*', t.name)):
-					if(isbegin and data.start == data.tKernSus):
-						data.dmesg[phase]['start'] = t.time
+					if(isbegin):
 						data.tKernSus = t.time
 					continue
 				# suspend_prepare start
 				elif(re.match('dpm_prepare\[.*', t.name)):
-					phase = 'suspend_prepare'
-					if(not isbegin):
-						data.dmesg[phase]['end'] = t.time
-						if data.dmesg[phase]['start'] < 0:
-							data.dmesg[phase]['start'] = data.start
+					if isbegin and data.first_suspend_prepare:
+						data.first_suspend_prepare = False
+						if data.tKernSus == 0:
+							data.tKernSus = t.time
+						continue
+					phase = data.setPhase('suspend_prepare', t.time, isbegin)
 					continue
 				# suspend start
 				elif(re.match('dpm_suspend\[.*', t.name)):
-					phase = 'suspend'
-					data.setPhase(phase, t.time, isbegin)
+					phase = data.setPhase('suspend', t.time, isbegin)
 					continue
 				# suspend_late start
 				elif(re.match('dpm_suspend_late\[.*', t.name)):
-					phase = 'suspend_late'
-					data.setPhase(phase, t.time, isbegin)
+					phase = data.setPhase('suspend_late', t.time, isbegin)
 					continue
 				# suspend_noirq start
 				elif(re.match('dpm_suspend_noirq\[.*', t.name)):
-					if data.phaseCollision('suspend_noirq', isbegin, line):
-						continue
-					phase = 'suspend_noirq'
-					data.setPhase(phase, t.time, isbegin)
-					if(not isbegin):
-						phase = 'suspend_machine'
-						data.dmesg[phase]['start'] = t.time
+					phase = data.setPhase('suspend_noirq', t.time, isbegin)
 					continue
 				# suspend_machine/resume_machine
 				elif(re.match('machine_suspend\[.*', t.name)):
 					if(isbegin):
-						phase = 'suspend_machine'
-						data.dmesg[phase]['end'] = t.time
-						data.tSuspended = t.time
+						lp = data.lastPhase()
+						if lp == 'resume_machine':
+							data.dmesg[lp]['end'] = t.time
+						phase = data.setPhase('suspend_machine', data.dmesg[lp]['end'], True)
+						data.setPhase(phase, t.time, False)
+						if data.tSuspended == 0:
+							data.tSuspended = t.time
 					else:
-						if(sysvals.suspendmode in ['mem', 'disk'] and not tp.S0i3):
-							data.dmesg['suspend_machine']['end'] = t.time
+						phase = data.setPhase('resume_machine', t.time, True)
+						if(sysvals.suspendmode in ['mem', 'disk']):
+							susp = phase.replace('resume', 'suspend')
+							if susp in data.dmesg:
+								data.dmesg[susp]['end'] = t.time
 							data.tSuspended = t.time
-						phase = 'resume_machine'
-						data.dmesg[phase]['start'] = t.time
 						data.tResumed = t.time
-						data.tLow = data.tResumed - data.tSuspended
-					continue
-				# acpi_suspend
-				elif(re.match('acpi_suspend\[.*', t.name)):
-					# acpi_suspend[0] S0i3
-					if(re.match('acpi_suspend\[0\] begin', t.name)):
-						if(sysvals.suspendmode == 'mem'):
-							tp.S0i3 = True
-							data.dmesg['suspend_machine']['end'] = t.time
-							data.tSuspended = t.time
 					continue
 				# resume_noirq start
 				elif(re.match('dpm_resume_noirq\[.*', t.name)):
-					if data.phaseCollision('resume_noirq', isbegin, line):
-						continue
-					phase = 'resume_noirq'
-					data.setPhase(phase, t.time, isbegin)
-					if(isbegin):
-						data.dmesg['resume_machine']['end'] = t.time
+					phase = data.setPhase('resume_noirq', t.time, isbegin)
 					continue
 				# resume_early start
 				elif(re.match('dpm_resume_early\[.*', t.name)):
-					phase = 'resume_early'
-					data.setPhase(phase, t.time, isbegin)
+					phase = data.setPhase('resume_early', t.time, isbegin)
 					continue
 				# resume start
 				elif(re.match('dpm_resume\[.*', t.name)):
-					phase = 'resume'
-					data.setPhase(phase, t.time, isbegin)
+					phase = data.setPhase('resume', t.time, isbegin)
 					continue
 				# resume complete start
 				elif(re.match('dpm_complete\[.*', t.name)):
-					phase = 'resume_complete'
-					if(isbegin):
-						data.dmesg[phase]['start'] = t.time
+					phase = data.setPhase('resume_complete', t.time, isbegin)
 					continue
 				# skip trace events inside devices calls
 				if(not data.isTraceEventOutsideDeviceCalls(pid, t.time)):
@@ -2881,13 +3270,10 @@
 					if(len(testrun.ttemp[name]) > 0):
 						# if an entry exists, assume this is its end
 						testrun.ttemp[name][-1]['end'] = t.time
-					elif(phase == 'post_resume'):
-						# post resume events can just have ends
-						testrun.ttemp[name].append({
-							'begin': data.dmesg[phase]['start'],
-							'end': t.time})
 			# device callback start
 			elif(t.type == 'device_pm_callback_start'):
+				if phase not in data.dmesg:
+					continue
 				m = re.match('(?P<drv>.*) (?P<d>.*), parent: *(?P<p>.*), .*',\
 					t.name);
 				if(not m):
@@ -2901,6 +3287,8 @@
 						data.devpids.append(pid)
 			# device callback finish
 			elif(t.type == 'device_pm_callback_end'):
+				if phase not in data.dmesg:
+					continue
 				m = re.match('(?P<drv>.*) (?P<d>.*), err.*', t.name);
 				if(not m):
 					continue
@@ -2926,24 +3314,26 @@
 				tp.ktemp[key].append({
 					'pid': pid,
 					'begin': t.time,
-					'end': t.time,
+					'end': -1,
 					'name': displayname,
 					'cdata': kprobedata,
 					'proc': m_proc,
 				})
+				# start of kernel resume
+				if(phase == 'suspend_prepare' and kprobename in ksuscalls):
+					data.tKernSus = t.time
 			elif(t.freturn):
 				if(key not in tp.ktemp) or len(tp.ktemp[key]) < 1:
 					continue
-				e = tp.ktemp[key][-1]
-				if e['begin'] < 0.0 or t.time - e['begin'] < 0.000001:
-					tp.ktemp[key].pop()
-				else:
-					e['end'] = t.time
-					e['rdata'] = kprobedata
+				e = next((x for x in reversed(tp.ktemp[key]) if x['end'] < 0), 0)
+				if not e:
+					continue
+				e['end'] = t.time
+				e['rdata'] = kprobedata
 				# end of kernel resume
-				if(kprobename == 'pm_notifier_call_chain' or \
-					kprobename == 'pm_restore_console'):
-					data.dmesg[phase]['end'] = t.time
+				if(phase != 'suspend_prepare' and kprobename in krescalls):
+					if phase in data.dmesg:
+						data.dmesg[phase]['end'] = t.time
 					data.tKernRes = t.time
 
 		# callgraph processing
@@ -2961,10 +3351,15 @@
 			if(res == -1):
 				testrun.ftemp[key][-1].addLine(t)
 	tf.close()
+	if len(testdata) < 1:
+		sysvals.vprint('WARNING: ftrace start marker is missing')
+	if data and not data.devicegroups:
+		sysvals.vprint('WARNING: ftrace end marker is missing')
+		data.handleEndMarker(t.time)
 
 	if sysvals.suspendmode == 'command':
 		for test in testruns:
-			for p in test.data.phases:
+			for p in test.data.sortedPhases():
 				if p == 'suspend_prepare':
 					test.data.dmesg[p]['start'] = test.data.start
 					test.data.dmesg[p]['end'] = test.data.end
@@ -2973,13 +3368,20 @@
 					test.data.dmesg[p]['end'] = test.data.end
 			test.data.tSuspended = test.data.end
 			test.data.tResumed = test.data.end
-			test.data.tLow = 0
 			test.data.fwValid = False
 
 	# dev source and procmon events can be unreadable with mixed phase height
 	if sysvals.usedevsrc or sysvals.useprocmon:
 		sysvals.mixedphaseheight = False
 
+	# expand phase boundaries so there are no gaps
+	for data in testdata:
+		lp = data.sortedPhases()[0]
+		for p in data.sortedPhases():
+			if(p != lp and not ('machine' in p and 'machine' in lp)):
+				data.dmesg[lp]['end'] = data.dmesg[p]['start']
+			lp = p
+
 	for i in range(len(testruns)):
 		test = testruns[i]
 		data = test.data
@@ -2993,36 +3395,38 @@
 		# add the traceevent data to the device hierarchy
 		if(sysvals.usetraceevents):
 			# add actual trace funcs
-			for name in test.ttemp:
+			for name in sorted(test.ttemp):
 				for event in test.ttemp[name]:
 					data.newActionGlobal(name, event['begin'], event['end'], event['pid'])
 			# add the kprobe based virtual tracefuncs as actual devices
-			for key in tp.ktemp:
+			for key in sorted(tp.ktemp):
 				name, pid = key
 				if name not in sysvals.tracefuncs:
 					continue
+				if pid not in data.devpids:
+					data.devpids.append(pid)
 				for e in tp.ktemp[key]:
 					kb, ke = e['begin'], e['end']
-					if kb == ke or tlb > kb or tle <= kb:
+					if ke - kb < 0.000001 or tlb > kb or tle <= kb:
 						continue
 					color = sysvals.kprobeColor(name)
 					data.newActionGlobal(e['name'], kb, ke, pid, color)
 			# add config base kprobes and dev kprobes
 			if sysvals.usedevsrc:
-				for key in tp.ktemp:
+				for key in sorted(tp.ktemp):
 					name, pid = key
 					if name in sysvals.tracefuncs or name not in sysvals.dev_tracefuncs:
 						continue
 					for e in tp.ktemp[key]:
 						kb, ke = e['begin'], e['end']
-						if kb == ke or tlb > kb or tle <= kb:
+						if ke - kb < 0.000001 or tlb > kb or tle <= kb:
 							continue
 						data.addDeviceFunctionCall(e['name'], name, e['proc'], pid, kb,
 							ke, e['cdata'], e['rdata'])
 		if sysvals.usecallgraph:
 			# add the callgraph data to the device hierarchy
 			sortlist = dict()
-			for key in test.ftemp:
+			for key in sorted(test.ftemp):
 				proc, pid = key
 				for cg in test.ftemp[key]:
 					if len(cg.list) < 1 or cg.invalid or (cg.end - cg.start == 0):
@@ -3039,9 +3443,9 @@
 					if not devname:
 						sortkey = '%f%f%d' % (cg.start, cg.end, pid)
 						sortlist[sortkey] = cg
-					elif len(cg.list) > 1000000:
-						print 'WARNING: the callgraph for %s is massive (%d lines)' %\
-							(devname, len(cg.list))
+					elif len(cg.list) > 1000000 and cg.name != sysvals.ftopfunc:
+						sysvals.vprint('WARNING: the callgraph for %s is massive (%d lines)' %\
+							(devname, len(cg.list)))
 			# create blocks for orphan cg data
 			for sortkey in sorted(sortlist):
 				cg = sortlist[sortkey]
@@ -3057,25 +3461,29 @@
 	for data in testdata:
 		tn = '' if len(testdata) == 1 else ('%d' % (data.testnumber + 1))
 		terr = ''
-		lp = data.phases[0]
-		for p in data.phases:
-			if(data.dmesg[p]['start'] < 0 and data.dmesg[p]['end'] < 0):
+		phasedef = data.phasedef
+		lp = 'suspend_prepare'
+		for p in sorted(phasedef, key=lambda k:phasedef[k]['order']):
+			if p not in data.dmesg:
 				if not terr:
-					print 'TEST%s FAILED: %s failed in %s phase' % (tn, sysvals.suspendmode, lp)
+					pprint('TEST%s FAILED: %s failed in %s phase' % (tn, sysvals.suspendmode, lp))
 					terr = '%s%s failed in %s phase' % (sysvals.suspendmode, tn, lp)
 					error.append(terr)
+					if data.tSuspended == 0:
+						data.tSuspended = data.dmesg[lp]['end']
+					if data.tResumed == 0:
+						data.tResumed = data.dmesg[lp]['end']
+					data.fwValid = False
 				sysvals.vprint('WARNING: phase "%s" is missing!' % p)
-			if(data.dmesg[p]['start'] < 0):
-				data.dmesg[p]['start'] = data.dmesg[lp]['end']
-				if(p == 'resume_machine'):
-					data.tSuspended = data.dmesg[lp]['end']
-					data.tResumed = data.dmesg[lp]['end']
-					data.tLow = 0
-			if(data.dmesg[p]['end'] < 0):
-				data.dmesg[p]['end'] = data.dmesg[p]['start']
-			if(p != lp and not ('machine' in p and 'machine' in lp)):
-				data.dmesg[lp]['end'] = data.dmesg[p]['start']
 			lp = p
+		if not terr and data.enterfail:
+			pprint('test%s FAILED: enter %s failed with %s' % (tn, sysvals.suspendmode, data.enterfail))
+			terr = 'test%s failed to enter %s mode' % (tn, sysvals.suspendmode)
+			error.append(terr)
+		if data.tSuspended == 0:
+			data.tSuspended = data.tKernRes
+		if data.tResumed == 0:
+			data.tResumed = data.tSuspended
 
 		if(len(sysvals.devicefilter) > 0):
 			data.deviceFilter(sysvals.devicefilter)
@@ -3117,19 +3525,7 @@
 		idx = line.find('[')
 		if idx > 1:
 			line = line[idx:]
-		# grab the stamp and sysinfo
-		if re.match(tp.stampfmt, line):
-			tp.stamp = line
-			continue
-		elif re.match(tp.sysinfofmt, line):
-			tp.sysinfo = line
-			continue
-		elif re.match(tp.cmdlinefmt, line):
-			tp.cmdline = line
-			continue
-		m = re.match(sysvals.firmwarefmt, line)
-		if(m):
-			tp.fwdata.append((int(m.group('s')), int(m.group('r'))))
+		if tp.stampInfo(line):
 			continue
 		m = re.match('[ \t]*(\[ *)(?P<ktime>[0-9\.]*)(\]) (?P<msg>.*)', line)
 		if(not m):
@@ -3140,10 +3536,6 @@
 				testruns.append(data)
 			data = Data(len(testruns))
 			tp.parseStamp(data, sysvals)
-			if len(tp.fwdata) > data.testnumber:
-				data.fwSuspend, data.fwResume = tp.fwdata[data.testnumber]
-				if(data.fwSuspend > 0 or data.fwResume > 0):
-					data.fwValid = True
 		if(not data):
 			continue
 		m = re.match('.* *(?P<k>[0-9]\.[0-9]{2}\.[0-9]-.*) .*', msg)
@@ -3158,7 +3550,7 @@
 	if data:
 		testruns.append(data)
 	if len(testruns) < 1:
-		print('ERROR: dmesg log has no suspend/resume data: %s' \
+		doError('dmesg log has no suspend/resume data: %s' \
 			% sysvals.dmesgfile)
 
 	# fix lines with same timestamp/function with the call and return swapped
@@ -3199,30 +3591,30 @@
 
 	# dmesg phase match table
 	dm = {
-		'suspend_prepare': 'PM: Syncing filesystems.*',
-		        'suspend': 'PM: Entering [a-z]* sleep.*',
-		   'suspend_late': 'PM: suspend of devices complete after.*',
-		  'suspend_noirq': 'PM: late suspend of devices complete after.*',
-		'suspend_machine': 'PM: noirq suspend of devices complete after.*',
-		 'resume_machine': 'ACPI: Low-level resume complete.*',
-		   'resume_noirq': 'ACPI: Waking up from system sleep state.*',
-		   'resume_early': 'PM: noirq resume of devices complete after.*',
-		         'resume': 'PM: early resume of devices complete after.*',
-		'resume_complete': 'PM: resume of devices complete after.*',
-		    'post_resume': '.*Restarting tasks \.\.\..*',
+		'suspend_prepare': ['PM: Syncing filesystems.*'],
+		        'suspend': ['PM: Entering [a-z]* sleep.*', 'Suspending console.*'],
+		   'suspend_late': ['PM: suspend of devices complete after.*'],
+		  'suspend_noirq': ['PM: late suspend of devices complete after.*'],
+		'suspend_machine': ['PM: noirq suspend of devices complete after.*'],
+		 'resume_machine': ['ACPI: Low-level resume complete.*'],
+		   'resume_noirq': ['ACPI: Waking up from system sleep state.*'],
+		   'resume_early': ['PM: noirq resume of devices complete after.*'],
+		         'resume': ['PM: early resume of devices complete after.*'],
+		'resume_complete': ['PM: resume of devices complete after.*'],
+		    'post_resume': ['.*Restarting tasks \.\.\..*'],
 	}
 	if(sysvals.suspendmode == 'standby'):
-		dm['resume_machine'] = 'PM: Restoring platform NVS memory'
+		dm['resume_machine'] = ['PM: Restoring platform NVS memory']
 	elif(sysvals.suspendmode == 'disk'):
-		dm['suspend_late'] = 'PM: freeze of devices complete after.*'
-		dm['suspend_noirq'] = 'PM: late freeze of devices complete after.*'
-		dm['suspend_machine'] = 'PM: noirq freeze of devices complete after.*'
-		dm['resume_machine'] = 'PM: Restoring platform NVS memory'
-		dm['resume_early'] = 'PM: noirq restore of devices complete after.*'
-		dm['resume'] = 'PM: early restore of devices complete after.*'
-		dm['resume_complete'] = 'PM: restore of devices complete after.*'
+		dm['suspend_late'] = ['PM: freeze of devices complete after.*']
+		dm['suspend_noirq'] = ['PM: late freeze of devices complete after.*']
+		dm['suspend_machine'] = ['PM: noirq freeze of devices complete after.*']
+		dm['resume_machine'] = ['PM: Restoring platform NVS memory']
+		dm['resume_early'] = ['PM: noirq restore of devices complete after.*']
+		dm['resume'] = ['PM: early restore of devices complete after.*']
+		dm['resume_complete'] = ['PM: restore of devices complete after.*']
 	elif(sysvals.suspendmode == 'freeze'):
-		dm['resume_machine'] = 'ACPI: resume from mwait'
+		dm['resume_machine'] = ['ACPI: resume from mwait']
 
 	# action table (expected events that occur and show up in dmesg)
 	at = {
@@ -3264,81 +3656,89 @@
 		else:
 			continue
 
+		# check for a phase change line
+		phasechange = False
+		for p in dm:
+			for s in dm[p]:
+				if(re.match(s, msg)):
+					phasechange, phase = True, p
+					break
+
 		# hack for determining resume_machine end for freeze
 		if(not sysvals.usetraceevents and sysvals.suspendmode == 'freeze' \
 			and phase == 'resume_machine' and \
 			re.match('calling  (?P<f>.*)\+ @ .*, parent: .*', msg)):
-			data.dmesg['resume_machine']['end'] = ktime
+			data.setPhase(phase, ktime, False)
 			phase = 'resume_noirq'
-			data.dmesg[phase]['start'] = ktime
+			data.setPhase(phase, ktime, True)
 
-		# suspend start
-		if(re.match(dm['suspend_prepare'], msg)):
-			phase = 'suspend_prepare'
-			data.dmesg[phase]['start'] = ktime
-			data.setStart(ktime)
-			data.tKernSus = ktime
-		# suspend start
-		elif(re.match(dm['suspend'], msg)):
-			data.dmesg['suspend_prepare']['end'] = ktime
-			phase = 'suspend'
-			data.dmesg[phase]['start'] = ktime
-		# suspend_late start
-		elif(re.match(dm['suspend_late'], msg)):
-			data.dmesg['suspend']['end'] = ktime
-			phase = 'suspend_late'
-			data.dmesg[phase]['start'] = ktime
-		# suspend_noirq start
-		elif(re.match(dm['suspend_noirq'], msg)):
-			data.dmesg['suspend_late']['end'] = ktime
-			phase = 'suspend_noirq'
-			data.dmesg[phase]['start'] = ktime
-		# suspend_machine start
-		elif(re.match(dm['suspend_machine'], msg)):
-			data.dmesg['suspend_noirq']['end'] = ktime
-			phase = 'suspend_machine'
-			data.dmesg[phase]['start'] = ktime
-		# resume_machine start
-		elif(re.match(dm['resume_machine'], msg)):
-			if(sysvals.suspendmode in ['freeze', 'standby']):
-				data.tSuspended = prevktime
-				data.dmesg['suspend_machine']['end'] = prevktime
-			else:
-				data.tSuspended = ktime
-				data.dmesg['suspend_machine']['end'] = ktime
-			phase = 'resume_machine'
-			data.tResumed = ktime
-			data.tLow = data.tResumed - data.tSuspended
-			data.dmesg[phase]['start'] = ktime
-		# resume_noirq start
-		elif(re.match(dm['resume_noirq'], msg)):
-			data.dmesg['resume_machine']['end'] = ktime
-			phase = 'resume_noirq'
-			data.dmesg[phase]['start'] = ktime
-		# resume_early start
-		elif(re.match(dm['resume_early'], msg)):
-			data.dmesg['resume_noirq']['end'] = ktime
-			phase = 'resume_early'
-			data.dmesg[phase]['start'] = ktime
-		# resume start
-		elif(re.match(dm['resume'], msg)):
-			data.dmesg['resume_early']['end'] = ktime
-			phase = 'resume'
-			data.dmesg[phase]['start'] = ktime
-		# resume complete start
-		elif(re.match(dm['resume_complete'], msg)):
-			data.dmesg['resume']['end'] = ktime
-			phase = 'resume_complete'
-			data.dmesg[phase]['start'] = ktime
-		# post resume start
-		elif(re.match(dm['post_resume'], msg)):
-			data.dmesg['resume_complete']['end'] = ktime
-			data.setEnd(ktime)
-			data.tKernRes = ktime
-			break
+		if phasechange:
+			if phase == 'suspend_prepare':
+				data.setPhase(phase, ktime, True)
+				data.setStart(ktime)
+				data.tKernSus = ktime
+			elif phase == 'suspend':
+				lp = data.lastPhase()
+				if lp:
+					data.setPhase(lp, ktime, False)
+				data.setPhase(phase, ktime, True)
+			elif phase == 'suspend_late':
+				lp = data.lastPhase()
+				if lp:
+					data.setPhase(lp, ktime, False)
+				data.setPhase(phase, ktime, True)
+			elif phase == 'suspend_noirq':
+				lp = data.lastPhase()
+				if lp:
+					data.setPhase(lp, ktime, False)
+				data.setPhase(phase, ktime, True)
+			elif phase == 'suspend_machine':
+				lp = data.lastPhase()
+				if lp:
+					data.setPhase(lp, ktime, False)
+				data.setPhase(phase, ktime, True)
+			elif phase == 'resume_machine':
+				lp = data.lastPhase()
+				if(sysvals.suspendmode in ['freeze', 'standby']):
+					data.tSuspended = prevktime
+					if lp:
+						data.setPhase(lp, prevktime, False)
+				else:
+					data.tSuspended = ktime
+					if lp:
+						data.setPhase(lp, prevktime, False)
+				data.tResumed = ktime
+				data.setPhase(phase, ktime, True)
+			elif phase == 'resume_noirq':
+				lp = data.lastPhase()
+				if lp:
+					data.setPhase(lp, ktime, False)
+				data.setPhase(phase, ktime, True)
+			elif phase == 'resume_early':
+				lp = data.lastPhase()
+				if lp:
+					data.setPhase(lp, ktime, False)
+				data.setPhase(phase, ktime, True)
+			elif phase == 'resume':
+				lp = data.lastPhase()
+				if lp:
+					data.setPhase(lp, ktime, False)
+				data.setPhase(phase, ktime, True)
+			elif phase == 'resume_complete':
+				lp = data.lastPhase()
+				if lp:
+					data.setPhase(lp, ktime, False)
+				data.setPhase(phase, ktime, True)
+			elif phase == 'post_resume':
+				lp = data.lastPhase()
+				if lp:
+					data.setPhase(lp, ktime, False)
+				data.setEnd(ktime)
+				data.tKernRes = ktime
+				break
 
 		# -- device callbacks --
-		if(phase in data.phases):
+		if(phase in data.sortedPhases()):
 			# device init call
 			if(re.match('calling  (?P<f>.*)\+ @ .*, parent: .*', msg)):
 				sm = re.match('calling  (?P<f>.*)\+ @ '+\
@@ -3364,7 +3764,7 @@
 		# if trace events are not available, these are better than nothing
 		if(not sysvals.usetraceevents):
 			# look for known actions
-			for a in at:
+			for a in sorted(at):
 				if(re.match(at[a]['smsg'], msg)):
 					if(a not in actions):
 						actions[a] = []
@@ -3396,27 +3796,34 @@
 				actions[cpu].append({'begin': cpu_start, 'end': ktime})
 				cpu_start = ktime
 		prevktime = ktime
+	data.initDevicegroups()
 
 	# fill in any missing phases
-	lp = data.phases[0]
-	for p in data.phases:
-		if(data.dmesg[p]['start'] < 0 and data.dmesg[p]['end'] < 0):
-			print('WARNING: phase "%s" is missing, something went wrong!' % p)
-			print('    In %s, this dmesg line denotes the start of %s:' % \
-				(sysvals.suspendmode, p))
-			print('        "%s"' % dm[p])
-		if(data.dmesg[p]['start'] < 0):
-			data.dmesg[p]['start'] = data.dmesg[lp]['end']
-			if(p == 'resume_machine'):
-				data.tSuspended = data.dmesg[lp]['end']
-				data.tResumed = data.dmesg[lp]['end']
-				data.tLow = 0
-		if(data.dmesg[p]['end'] < 0):
-			data.dmesg[p]['end'] = data.dmesg[p]['start']
+	phasedef = data.phasedef
+	terr, lp = '', 'suspend_prepare'
+	for p in sorted(phasedef, key=lambda k:phasedef[k]['order']):
+		if p not in data.dmesg:
+			if not terr:
+				pprint('TEST FAILED: %s failed in %s phase' % (sysvals.suspendmode, lp))
+				terr = '%s failed in %s phase' % (sysvals.suspendmode, lp)
+				if data.tSuspended == 0:
+					data.tSuspended = data.dmesg[lp]['end']
+				if data.tResumed == 0:
+					data.tResumed = data.dmesg[lp]['end']
+			sysvals.vprint('WARNING: phase "%s" is missing!' % p)
 		lp = p
+	lp = data.sortedPhases()[0]
+	for p in data.sortedPhases():
+		if(p != lp and not ('machine' in p and 'machine' in lp)):
+			data.dmesg[lp]['end'] = data.dmesg[p]['start']
+		lp = p
+	if data.tSuspended == 0:
+		data.tSuspended = data.tKernRes
+	if data.tResumed == 0:
+		data.tResumed = data.tSuspended
 
 	# fill in any actions we've found
-	for name in actions:
+	for name in sorted(actions):
 		for event in actions[name]:
 			data.newActionGlobal(name, event['begin'], event['end'])
 
@@ -3462,7 +3869,7 @@
 	hf.write('<section id="callgraphs" class="callgraph">\n')
 	# write out the ftrace data converted to html
 	num = 0
-	for p in data.phases:
+	for p in data.sortedPhases():
 		if sv.cgphase and p != sv.cgphase:
 			continue
 		list = data.dmesg[p]['list']
@@ -3482,6 +3889,8 @@
 				name += ' '+p
 			if('ftrace' in dev):
 				cg = dev['ftrace']
+				if cg.name == sv.ftopfunc:
+					name = 'top level suspend/resume call'
 				num = callgraphHTML(sv, hf, num, cg,
 					name, color, dev['id'])
 			if('ftraces' in dev):
@@ -3490,22 +3899,16 @@
 						name+' &rarr; '+cg.name, color, dev['id'])
 	hf.write('\n\n    </section>\n')
 
-# Function: createHTMLSummarySimple
-# Description:
-#	 Create summary html file for a series of tests
-# Arguments:
-#	 testruns: array of Data objects from parseTraceLog
-def createHTMLSummarySimple(testruns, htmlfile, folder):
-	# write the html header first (html head, css code, up to body start)
-	html = '<!DOCTYPE html>\n<html>\n<head>\n\
+def summaryCSS(title, center=True):
+	tdcenter = 'text-align:center;' if center else ''
+	out = '<!DOCTYPE html>\n<html>\n<head>\n\
 	<meta http-equiv="content-type" content="text/html; charset=UTF-8">\n\
-	<title>SleepGraph Summary</title>\n\
+	<title>'+title+'</title>\n\
 	<style type=\'text/css\'>\n\
 		.stamp {width: 100%;text-align:center;background:#888;line-height:30px;color:white;font: 25px Arial;}\n\
-		table {width:100%;border-collapse: collapse;}\n\
-		.summary {border:1px solid;}\n\
+		table {width:100%;border-collapse: collapse;border:1px solid;}\n\
 		th {border: 1px solid black;background:#222;color:white;}\n\
-		td {font: 16px "Times New Roman";text-align: center;}\n\
+		td {font: 14px "Times New Roman";'+tdcenter+'}\n\
 		tr.head td {border: 1px solid black;background:#aaa;}\n\
 		tr.alt {background-color:#ddd;}\n\
 		tr.notice {color:red;}\n\
@@ -3514,14 +3917,25 @@
 		.maxval {background-color:#FFBBBB;}\n\
 		.head a {color:#000;text-decoration: none;}\n\
 	</style>\n</head>\n<body>\n'
+	return out
+
+# Function: createHTMLSummarySimple
+# Description:
+#	 Create summary html file for a series of tests
+# Arguments:
+#	 testruns: array of Data objects from parseTraceLog
+def createHTMLSummarySimple(testruns, htmlfile, title):
+	# write the html header first (html head, css code, up to body start)
+	html = summaryCSS('Summary - SleepGraph')
 
 	# extract the test data into list
 	list = dict()
-	tAvg, tMin, tMax, tMed = [0.0, 0.0], [0.0, 0.0], [0.0, 0.0], [[], []]
+	tAvg, tMin, tMax, tMed = [0.0, 0.0], [0.0, 0.0], [0.0, 0.0], [dict(), dict()]
 	iMin, iMed, iMax = [0, 0], [0, 0], [0, 0]
 	num = 0
+	useturbo = False
 	lastmode = ''
-	cnt = {'pass':0, 'fail':0, 'hang':0}
+	cnt = dict()
 	for data in sorted(testruns, key=lambda v:(v['mode'], v['host'], v['kernel'], v['time'])):
 		mode = data['mode']
 		if mode not in list:
@@ -3529,24 +3943,36 @@
 		if lastmode and lastmode != mode and num > 0:
 			for i in range(2):
 				s = sorted(tMed[i])
-				list[lastmode]['med'][i] = s[int(len(s)/2)]
-				iMed[i] = tMed[i].index(list[lastmode]['med'][i])
+				list[lastmode]['med'][i] = s[int(len(s)//2)]
+				iMed[i] = tMed[i][list[lastmode]['med'][i]]
 			list[lastmode]['avg'] = [tAvg[0] / num, tAvg[1] / num]
 			list[lastmode]['min'] = tMin
 			list[lastmode]['max'] = tMax
 			list[lastmode]['idx'] = (iMin, iMed, iMax)
-			tAvg, tMin, tMax, tMed = [0.0, 0.0], [0.0, 0.0], [0.0, 0.0], [[], []]
+			tAvg, tMin, tMax, tMed = [0.0, 0.0], [0.0, 0.0], [0.0, 0.0], [dict(), dict()]
 			iMin, iMed, iMax = [0, 0], [0, 0], [0, 0]
 			num = 0
+		pkgpc10 = syslpi = ''
+		if 'pkgpc10' in data and 'syslpi' in data:
+			pkgpc10 = data['pkgpc10']
+			syslpi = data['syslpi']
+			useturbo = True
+		res = data['result']
 		tVal = [float(data['suspend']), float(data['resume'])]
 		list[mode]['data'].append([data['host'], data['kernel'],
-			data['time'], tVal[0], tVal[1], data['url'], data['result'],
-			data['issues']])
+			data['time'], tVal[0], tVal[1], data['url'], res,
+			data['issues'], data['sus_worst'], data['sus_worsttime'],
+			data['res_worst'], data['res_worsttime'], pkgpc10, syslpi])
 		idx = len(list[mode]['data']) - 1
-		if data['result'] == 'pass':
-			cnt['pass'] += 1
+		if res.startswith('fail in'):
+			res = 'fail'
+		if res not in cnt:
+			cnt[res] = 1
+		else:
+			cnt[res] += 1
+		if res == 'pass':
 			for i in range(2):
-				tMed[i].append(tVal[i])
+				tMed[i][tVal[i]] = idx
 				tAvg[i] += tVal[i]
 				if tMin[i] == 0 or tVal[i] < tMin[i]:
 					iMin[i] = idx
@@ -3555,16 +3981,12 @@
 					iMax[i] = idx
 					tMax[i] = tVal[i]
 			num += 1
-		elif data['result'] == 'hang':
-			cnt['hang'] += 1
-		elif data['result'] == 'fail':
-			cnt['fail'] += 1
 		lastmode = mode
 	if lastmode and num > 0:
 		for i in range(2):
 			s = sorted(tMed[i])
-			list[lastmode]['med'][i] = s[int(len(s)/2)]
-			iMed[i] = tMed[i].index(list[lastmode]['med'][i])
+			list[lastmode]['med'][i] = s[int(len(s)//2)]
+			iMed[i] = tMed[i][list[lastmode]['med'][i]]
 		list[lastmode]['avg'] = [tAvg[0] / num, tAvg[1] / num]
 		list[lastmode]['min'] = tMin
 		list[lastmode]['max'] = tMax
@@ -3575,21 +3997,26 @@
 	for ilk in sorted(cnt, reverse=True):
 		if cnt[ilk] > 0:
 			desc.append('%d %s' % (cnt[ilk], ilk))
-	html += '<div class="stamp">%s (%d tests: %s)</div>\n' % (folder, len(testruns), ', '.join(desc))
+	html += '<div class="stamp">%s (%d tests: %s)</div>\n' % (title, len(testruns), ', '.join(desc))
 	th = '\t<th>{0}</th>\n'
 	td = '\t<td>{0}</td>\n'
 	tdh = '\t<td{1}>{0}</td>\n'
 	tdlink = '\t<td><a href="{0}">html</a></td>\n'
+	colspan = '14' if useturbo else '12'
 
 	# table header
-	html += '<table class="summary">\n<tr>\n' + th.format('#') +\
+	html += '<table>\n<tr>\n' + th.format('#') +\
 		th.format('Mode') + th.format('Host') + th.format('Kernel') +\
 		th.format('Test Time') + th.format('Result') + th.format('Issues') +\
-		th.format('Suspend') + th.format('Resume') + th.format('Detail') + '</tr>\n'
-
+		th.format('Suspend') + th.format('Resume') +\
+		th.format('Worst Suspend Device') + th.format('SD Time') +\
+		th.format('Worst Resume Device') + th.format('RD Time')
+	if useturbo:
+		html += th.format('PkgPC10') + th.format('SysLPI')
+	html += th.format('Detail')+'</tr>\n'
 	# export list into html
 	head = '<tr class="head"><td>{0}</td><td>{1}</td>'+\
-		'<td colspan=8 class="sus">Suspend Avg={2} '+\
+		'<td colspan='+colspan+' class="sus">Suspend Avg={2} '+\
 		'<span class=minval><a href="#s{10}min">Min={3}</a></span> '+\
 		'<span class=medval><a href="#s{10}med">Med={4}</a></span> '+\
 		'<span class=maxval><a href="#s{10}max">Max={5}</a></span> '+\
@@ -3598,8 +4025,9 @@
 		'<span class=medval><a href="#r{10}med">Med={8}</a></span> '+\
 		'<span class=maxval><a href="#r{10}max">Max={9}</a></span></td>'+\
 		'</tr>\n'
-	headnone = '<tr class="head"><td>{0}</td><td>{1}</td><td colspan=8></td></tr>\n'
-	for mode in list:
+	headnone = '<tr class="head"><td>{0}</td><td>{1}</td><td colspan='+\
+		colspan+'></td></tr>\n'
+	for mode in sorted(list):
 		# header line for each suspend mode
 		num = 0
 		tAvg, tMin, tMax, tMed = list[mode]['avg'], list[mode]['min'],\
@@ -3641,6 +4069,13 @@
 			html += td.format(d[7])										# issues
 			html += tdh.format('%.3f ms' % d[3], tHigh[0]) if d[3] else td.format('')	# suspend
 			html += tdh.format('%.3f ms' % d[4], tHigh[1]) if d[4] else td.format('')	# resume
+			html += td.format(d[8])										# sus_worst
+			html += td.format('%.3f ms' % d[9])	if d[9] else td.format('')		# sus_worst time
+			html += td.format(d[10])									# res_worst
+			html += td.format('%.3f ms' % d[11]) if d[11] else td.format('')	# res_worst time
+			if useturbo:
+				html += td.format(d[12])								# pkg_pc10
+				html += td.format(d[13])								# syslpi
 			html += tdlink.format(d[5]) if d[5] else td.format('')		# url
 			html += '</tr>\n'
 			num += 1
@@ -3650,6 +4085,116 @@
 	hf.write(html+'</table>\n</body>\n</html>\n')
 	hf.close()
 
+def createHTMLDeviceSummary(testruns, htmlfile, title):
+	html = summaryCSS('Device Summary - SleepGraph', False)
+
+	# create global device list from all tests
+	devall = dict()
+	for data in testruns:
+		host, url, devlist = data['host'], data['url'], data['devlist']
+		for type in devlist:
+			if type not in devall:
+				devall[type] = dict()
+			mdevlist, devlist = devall[type], data['devlist'][type]
+			for name in devlist:
+				length = devlist[name]
+				if name not in mdevlist:
+					mdevlist[name] = {'name': name, 'host': host,
+						'worst': length, 'total': length, 'count': 1,
+						'url': url}
+				else:
+					if length > mdevlist[name]['worst']:
+						mdevlist[name]['worst'] = length
+						mdevlist[name]['url'] = url
+						mdevlist[name]['host'] = host
+					mdevlist[name]['total'] += length
+					mdevlist[name]['count'] += 1
+
+	# generate the html
+	th = '\t<th>{0}</th>\n'
+	td = '\t<td align=center>{0}</td>\n'
+	tdr = '\t<td align=right>{0}</td>\n'
+	tdlink = '\t<td align=center><a href="{0}">html</a></td>\n'
+	limit = 1
+	for type in sorted(devall, reverse=True):
+		num = 0
+		devlist = devall[type]
+		# table header
+		html += '<div class="stamp">%s (%s devices > %d ms)</div><table>\n' % \
+			(title, type.upper(), limit)
+		html += '<tr>\n' + '<th align=right>Device Name</th>' +\
+			th.format('Average Time') + th.format('Count') +\
+			th.format('Worst Time') + th.format('Host (worst time)') +\
+			th.format('Link (worst time)') + '</tr>\n'
+		for name in sorted(devlist, key=lambda k:(devlist[k]['worst'], \
+			devlist[k]['total'], devlist[k]['name']), reverse=True):
+			data = devall[type][name]
+			data['average'] = data['total'] / data['count']
+			if data['average'] < limit:
+				continue
+			# row classes - alternate row color
+			rcls = ['alt'] if num % 2 == 1 else []
+			html += '<tr class="'+(' '.join(rcls))+'">\n' if len(rcls) > 0 else '<tr>\n'
+			html += tdr.format(data['name'])				# name
+			html += td.format('%.3f ms' % data['average'])	# average
+			html += td.format(data['count'])				# count
+			html += td.format('%.3f ms' % data['worst'])	# worst
+			html += td.format(data['host'])					# host
+			html += tdlink.format(data['url'])				# url
+			html += '</tr>\n'
+			num += 1
+		html += '</table>\n'
+
+	# flush the data to file
+	hf = open(htmlfile, 'w')
+	hf.write(html+'</body>\n</html>\n')
+	hf.close()
+	return devall
+
+def createHTMLIssuesSummary(testruns, issues, htmlfile, title, extra=''):
+	multihost = len([e for e in issues if len(e['urls']) > 1]) > 0
+	html = summaryCSS('Issues Summary - SleepGraph', False)
+	total = len(testruns)
+
+	# generate the html
+	th = '\t<th>{0}</th>\n'
+	td = '\t<td align={0}>{1}</td>\n'
+	tdlink = '<a href="{1}">{0}</a>'
+	subtitle = '%d issues' % len(issues) if len(issues) > 0 else 'no issues'
+	html += '<div class="stamp">%s (%s)</div><table>\n' % (title, subtitle)
+	html += '<tr>\n' + th.format('Issue') + th.format('Count')
+	if multihost:
+		html += th.format('Hosts')
+	html += th.format('Tests') + th.format('Fail Rate') +\
+		th.format('First Instance') + '</tr>\n'
+
+	num = 0
+	for e in sorted(issues, key=lambda v:v['count'], reverse=True):
+		testtotal = 0
+		links = []
+		for host in sorted(e['urls']):
+			links.append(tdlink.format(host, e['urls'][host][0]))
+			testtotal += len(e['urls'][host])
+		rate = '%d/%d (%.2f%%)' % (testtotal, total, 100*float(testtotal)/float(total))
+		# row classes - alternate row color
+		rcls = ['alt'] if num % 2 == 1 else []
+		html += '<tr class="'+(' '.join(rcls))+'">\n' if len(rcls) > 0 else '<tr>\n'
+		html += td.format('left', e['line'])		# issue
+		html += td.format('center', e['count'])		# count
+		if multihost:
+			html += td.format('center', len(e['urls']))	# hosts
+		html += td.format('center', testtotal)		# test count
+		html += td.format('center', rate)			# test rate
+		html += td.format('center nowrap', '<br>'.join(links))	# links
+		html += '</tr>\n'
+		num += 1
+
+	# flush the data to file
+	hf = open(htmlfile, 'w')
+	hf.write(html+'</table>\n'+extra+'</body>\n</html>\n')
+	hf.close()
+	return issues
+
 def ordinal(value):
 	suffix = 'th'
 	if value < 10 or value > 19:
@@ -3670,14 +4215,15 @@
 #	 True if the html file was created, false if it failed
 def createHTML(testruns, testfail):
 	if len(testruns) < 1:
-		print('ERROR: Not enough test data to build a timeline')
+		pprint('ERROR: Not enough test data to build a timeline')
 		return
 
 	kerror = False
 	for data in testruns:
 		if data.kerror:
 			kerror = True
-		data.normalizeTime(testruns[-1].tSuspended)
+		if(sysvals.suspendmode in ['freeze', 'standby']):
+			data.trimFreezeTime(testruns[-1].tSuspended)
 
 	# html function templates
 	html_error = '<div id="{1}" title="kernel error/warning" class="err" style="right:{0}%">{2}&rarr;</div>\n'
@@ -3721,8 +4267,8 @@
 		sktime, rktime = data.getTimeValues()
 		if(tTotal == 0):
 			doError('No timeline data')
-		if(data.tLow > 0):
-			low_time = '%.0f'%(data.tLow*1000)
+		if(len(data.tLow) > 0):
+			low_time = '+'.join(data.tLow)
 		if sysvals.suspendmode == 'command':
 			run_time = '%.0f'%((data.end-data.start)*1000)
 			if sysvals.testcommand:
@@ -3743,7 +4289,7 @@
 			if(len(testruns) > 1):
 				testdesc1 = testdesc2 = ordinal(data.testnumber+1)
 				testdesc2 += ' '
-			if(data.tLow == 0):
+			if(len(data.tLow) == 0):
 				thtml = html_timetotal.format(suspend_time, \
 					resume_time, testdesc1, stitle, rtitle)
 			else:
@@ -3762,7 +4308,7 @@
 			rtitle = 'time from firmware mode to return from kernel enter_state(%s) [kernel time only]' % sysvals.suspendmode
 			if(len(testruns) > 1):
 				testdesc = ordinal(data.testnumber+1)+' '+testdesc
-			if(data.tLow == 0):
+			if(len(data.tLow) == 0):
 				thtml = html_timetotal.format(suspend_time, \
 					resume_time, testdesc, stitle, rtitle)
 			else:
@@ -3788,7 +4334,7 @@
 		for group in data.devicegroups:
 			devlist = []
 			for phase in group:
-				for devname in data.tdevlist[phase]:
+				for devname in sorted(data.tdevlist[phase]):
 					d = DevItem(data.testnumber, phase, data.dmesg[phase]['list'][devname])
 					devlist.append(d)
 					if d.isa('kth'):
@@ -3820,15 +4366,14 @@
 
 	# draw the full timeline
 	devtl.createZoomBox(sysvals.suspendmode, len(testruns))
-	phases = {'suspend':[],'resume':[]}
-	for phase in data.dmesg:
-		if 'resume' in phase:
-			phases['resume'].append(phase)
-		else:
-			phases['suspend'].append(phase)
-
-	# draw each test run chronologically
 	for data in testruns:
+		# draw each test run and block chronologically
+		phases = {'suspend':[],'resume':[]}
+		for phase in data.sortedPhases():
+			if data.dmesg[phase]['start'] >= data.tSuspended:
+				phases['resume'].append(phase)
+			else:
+				phases['suspend'].append(phase)
 		# now draw the actual timeline blocks
 		for dir in phases:
 			# draw suspend and resume blocks separately
@@ -3850,7 +4395,7 @@
 				continue
 			width = '%f' % (((mTotal*100.0)-sysvals.srgap/2)/tTotal)
 			devtl.html += devtl.html_tblock.format(bname, left, width, devtl.scaleH)
-			for b in sorted(phases[dir]):
+			for b in phases[dir]:
 				# draw the phase color background
 				phase = data.dmesg[b]
 				length = phase['end']-phase['start']
@@ -3865,10 +4410,10 @@
 				id = '%d_%d' % (idx1, idx2)
 				right = '%f' % (((mMax-t)*100.0)/mTotal)
 				devtl.html += html_error.format(right, id, type)
-			for b in sorted(phases[dir]):
+			for b in phases[dir]:
 				# draw the devices for this phase
 				phaselist = data.dmesg[b]['list']
-				for d in data.tdevlist[b]:
+				for d in sorted(data.tdevlist[b]):
 					name = d
 					drv = ''
 					dev = phaselist[d]
@@ -3942,19 +4487,17 @@
 
 	# draw a legend which describes the phases by color
 	if sysvals.suspendmode != 'command':
-		data = testruns[-1]
+		phasedef = testruns[-1].phasedef
 		devtl.html += '<div class="legend">\n'
-		pdelta = 100.0/len(data.phases)
+		pdelta = 100.0/len(phasedef.keys())
 		pmargin = pdelta / 4.0
-		for phase in data.phases:
-			tmp = phase.split('_')
-			id = tmp[0][0]
-			if(len(tmp) > 1):
-				id += tmp[1][0]
-			order = '%.2f' % ((data.dmesg[phase]['order'] * pdelta) + pmargin)
-			name = string.replace(phase, '_', ' &nbsp;')
-			devtl.html += devtl.html_legend.format(order, \
-				data.dmesg[phase]['color'], name, id)
+		for phase in sorted(phasedef, key=lambda k:phasedef[k]['order']):
+			id, p = '', phasedef[phase]
+			for word in phase.split('_'):
+				id += word[0]
+			order = '%.2f' % ((p['order'] * pdelta) + pmargin)
+			name = phase.replace('_', ' &nbsp;')
+			devtl.html += devtl.html_legend.format(order, p['color'], name, id)
 		devtl.html += '</div>\n'
 
 	hf = open(sysvals.htmlfile, 'w')
@@ -3970,7 +4513,7 @@
 		pscolor = 'linear-gradient(to top left, #ccc, #eee)'
 		hf.write(devtl.html_phaselet.format('pre_suspend_process', \
 			'0', '0', pscolor))
-		for b in data.phases:
+		for b in data.sortedPhases():
 			phase = data.dmesg[b]
 			length = phase['end']-phase['start']
 			left = '%.3f' % (((phase['start']-t0)*100.0)/tTotal)
@@ -4522,18 +5065,18 @@
 			sv.rstgt, sv.rsval, sv.rsdir = 'on', 'auto', 'enabled'
 		else:
 			sv.rstgt, sv.rsval, sv.rsdir = 'auto', 'on', 'disabled'
-		print('CONFIGURING RUNTIME SUSPEND...')
+		pprint('CONFIGURING RUNTIME SUSPEND...')
 		sv.rslist = deviceInfo(sv.rstgt)
 		for i in sv.rslist:
 			sv.setVal(sv.rsval, i)
-		print('runtime suspend %s on all devices (%d changed)' % (sv.rsdir, len(sv.rslist)))
-		print('waiting 5 seconds...')
+		pprint('runtime suspend %s on all devices (%d changed)' % (sv.rsdir, len(sv.rslist)))
+		pprint('waiting 5 seconds...')
 		time.sleep(5)
 	else:
 		# runtime suspend re-enable or re-disable
 		for i in sv.rslist:
 			sv.setVal(sv.rstgt, i)
-		print('runtime suspend settings restored on %d devices' % len(sv.rslist))
+		pprint('runtime suspend settings restored on %d devices' % len(sv.rslist))
 
 # Function: executeSuspend
 # Description:
@@ -4542,25 +5085,22 @@
 def executeSuspend():
 	pm = ProcessMonitor()
 	tp = sysvals.tpath
-	fwdata = []
+	wifi = sysvals.checkWifi()
+	testdata = []
+	battery = True if getBattery() else False
 	# run these commands to prepare the system for suspend
 	if sysvals.display:
-		if sysvals.display > 0:
-			print('TURN DISPLAY ON')
-			call('xset -d :0.0 dpms force suspend', shell=True)
-			call('xset -d :0.0 dpms force on', shell=True)
-		else:
-			print('TURN DISPLAY OFF')
-			call('xset -d :0.0 dpms force suspend', shell=True)
+		pprint('SET DISPLAY TO %s' % sysvals.display.upper())
+		displayControl(sysvals.display)
 		time.sleep(1)
 	if sysvals.sync:
-		print('SYNCING FILESYSTEMS')
+		pprint('SYNCING FILESYSTEMS')
 		call('sync', shell=True)
 	# mark the start point in the kernel ring buffer just as we start
 	sysvals.initdmesg()
 	# start ftrace
 	if(sysvals.usecallgraph or sysvals.usetraceevents):
-		print('START TRACING')
+		pprint('START TRACING')
 		sysvals.fsetVal('1', 'tracing_on')
 		if sysvals.useprocmon:
 			pm.start()
@@ -4573,15 +5113,17 @@
 			sysvals.fsetVal('WAIT END', 'trace_marker')
 		# start message
 		if sysvals.testcommand != '':
-			print('COMMAND START')
+			pprint('COMMAND START')
 		else:
 			if(sysvals.rtcwake):
-				print('SUSPEND START')
+				pprint('SUSPEND START')
 			else:
-				print('SUSPEND START (press a key to resume)')
+				pprint('SUSPEND START (press a key to resume)')
+		sysvals.mcelog(True)
+		bat1 = getBattery() if battery else False
 		# set rtcwake
 		if(sysvals.rtcwake):
-			print('will issue an rtcwake in %d seconds' % sysvals.rtcwaketime)
+			pprint('will issue an rtcwake in %d seconds' % sysvals.rtcwaketime)
 			sysvals.rtcWakeAlarmOn()
 		# start of suspend trace marker
 		if(sysvals.usecallgraph or sysvals.usetraceevents):
@@ -4592,8 +5134,11 @@
 			time.sleep(sysvals.predelay/1000.0)
 			sysvals.fsetVal('WAIT END', 'trace_marker')
 		# initiate suspend or command
+		tdata = {'error': ''}
 		if sysvals.testcommand != '':
-			call(sysvals.testcommand+' 2>&1', shell=True);
+			res = call(sysvals.testcommand+' 2>&1', shell=True);
+			if res != 0:
+				tdata['error'] = 'cmd returned %d' % res
 		else:
 			mode = sysvals.suspendmode
 			if sysvals.memmode and os.path.exists(sysvals.mempowerfile):
@@ -4601,13 +5146,24 @@
 				pf = open(sysvals.mempowerfile, 'w')
 				pf.write(sysvals.memmode)
 				pf.close()
-			pf = open(sysvals.powerfile, 'w')
-			pf.write(mode)
-			# execution will pause here
-			try:
+			if sysvals.diskmode and os.path.exists(sysvals.diskpowerfile):
+				mode = 'disk'
+				pf = open(sysvals.diskpowerfile, 'w')
+				pf.write(sysvals.diskmode)
 				pf.close()
-			except:
-				pass
+			if mode == 'freeze' and sysvals.haveTurbostat():
+				# execution will pause here
+				turbo = sysvals.turbostat()
+				if turbo:
+					tdata['turbo'] = turbo
+			else:
+				pf = open(sysvals.powerfile, 'w')
+				pf.write(mode)
+				# execution will pause here
+				try:
+					pf.close()
+				except Exception as e:
+					tdata['error'] = str(e)
 		if(sysvals.rtcwake):
 			sysvals.rtcWakeAlarmOff()
 		# postdelay delay
@@ -4616,27 +5172,39 @@
 			time.sleep(sysvals.postdelay/1000.0)
 			sysvals.fsetVal('WAIT END', 'trace_marker')
 		# return from suspend
-		print('RESUME COMPLETE')
+		pprint('RESUME COMPLETE')
 		if(sysvals.usecallgraph or sysvals.usetraceevents):
 			sysvals.fsetVal('RESUME COMPLETE', 'trace_marker')
 		if(sysvals.suspendmode == 'mem' or sysvals.suspendmode == 'command'):
-			fwdata.append(getFPDT(False))
+			tdata['fw'] = getFPDT(False)
+		mcelog = sysvals.mcelog()
+		if mcelog:
+			tdata['mcelog'] = mcelog
+		bat2 = getBattery() if battery else False
+		if battery and bat1 and bat2:
+			tdata['bat'] = (bat1, bat2)
+		if 'device' in wifi and 'ip' in wifi:
+			tdata['wifi'] = (wifi, sysvals.checkWifi())
+		testdata.append(tdata)
 	# stop ftrace
 	if(sysvals.usecallgraph or sysvals.usetraceevents):
 		if sysvals.useprocmon:
 			pm.stop()
 		sysvals.fsetVal('0', 'tracing_on')
-		print('CAPTURING TRACE')
-		op = sysvals.writeDatafileHeader(sysvals.ftracefile, fwdata)
+	# grab a copy of the dmesg output
+	pprint('CAPTURING DMESG')
+	sysvals.getdmesg(testdata)
+	# grab a copy of the ftrace output
+	if(sysvals.usecallgraph or sysvals.usetraceevents):
+		pprint('CAPTURING TRACE')
+		op = sysvals.writeDatafileHeader(sysvals.ftracefile, testdata)
 		fp = open(tp+'trace', 'r')
 		for line in fp:
 			op.write(line)
 		op.close()
 		sysvals.fsetVal('', 'trace')
-		devProps()
-	# grab a copy of the dmesg output
-	print('CAPTURING DMESG')
-	sysvals.getdmesg(fwdata)
+		sysvals.platforminfo()
+	return testdata
 
 def readFile(file):
 	if os.path.islink(file):
@@ -4651,9 +5219,9 @@
 #	 The time string, e.g. "1901m16s"
 def ms2nice(val):
 	val = int(val)
-	h = val / 3600000
-	m = (val / 60000) % 60
-	s = (val / 1000) % 60
+	h = val // 3600000
+	m = (val // 60000) % 60
+	s = (val // 1000) % 60
 	if h > 0:
 		return '%d:%02d:%02d' % (h, m, s)
 	if m > 0:
@@ -4673,15 +5241,15 @@
 #	 a list of USB device names to sysvals for better timeline readability
 def deviceInfo(output=''):
 	if not output:
-		print('LEGEND')
-		print('---------------------------------------------------------------------------------------------')
-		print('  A = async/sync PM queue (A/S)               C = runtime active children')
-		print('  R = runtime suspend enabled/disabled (E/D)  rACTIVE = runtime active (min/sec)')
-		print('  S = runtime status active/suspended (A/S)   rSUSPEND = runtime suspend (min/sec)')
-		print('  U = runtime usage count')
-		print('---------------------------------------------------------------------------------------------')
-		print('DEVICE                     NAME                       A R S U C    rACTIVE   rSUSPEND')
-		print('---------------------------------------------------------------------------------------------')
+		pprint('LEGEND\n'\
+		'---------------------------------------------------------------------------------------------\n'\
+		'  A = async/sync PM queue (A/S)               C = runtime active children\n'\
+		'  R = runtime suspend enabled/disabled (E/D)  rACTIVE = runtime active (min/sec)\n'\
+		'  S = runtime status active/suspended (A/S)   rSUSPEND = runtime suspend (min/sec)\n'\
+		'  U = runtime usage count\n'\
+		'---------------------------------------------------------------------------------------------\n'\
+		'DEVICE                     NAME                       A R S U C    rACTIVE   rSUSPEND\n'\
+		'---------------------------------------------------------------------------------------------')
 
 	res = []
 	tgtval = 'runtime_status'
@@ -4723,130 +5291,9 @@
 			ms2nice(power['runtime_active_time']), \
 			ms2nice(power['runtime_suspended_time']))
 	for i in sorted(lines):
-		print lines[i]
+		print(lines[i])
 	return res
 
-# Function: devProps
-# Description:
-#	 Retrieve a list of properties for all devices in the trace log
-def devProps(data=0):
-	props = dict()
-
-	if data:
-		idx = data.index(': ') + 2
-		if idx >= len(data):
-			return
-		devlist = data[idx:].split(';')
-		for dev in devlist:
-			f = dev.split(',')
-			if len(f) < 3:
-				continue
-			dev = f[0]
-			props[dev] = DevProps()
-			props[dev].altname = f[1]
-			if int(f[2]):
-				props[dev].async = True
-			else:
-				props[dev].async = False
-			sysvals.devprops = props
-		if sysvals.suspendmode == 'command' and 'testcommandstring' in props:
-			sysvals.testcommand = props['testcommandstring'].altname
-		return
-
-	if(os.path.exists(sysvals.ftracefile) == False):
-		doError('%s does not exist' % sysvals.ftracefile)
-
-	# first get the list of devices we need properties for
-	msghead = 'Additional data added by AnalyzeSuspend'
-	alreadystamped = False
-	tp = TestProps()
-	tf = sysvals.openlog(sysvals.ftracefile, 'r')
-	for line in tf:
-		if msghead in line:
-			alreadystamped = True
-			continue
-		# determine the trace data type (required for further parsing)
-		m = re.match(sysvals.tracertypefmt, line)
-		if(m):
-			tp.setTracerType(m.group('t'))
-			continue
-		# parse only valid lines, if this is not one move on
-		m = re.match(tp.ftrace_line_fmt, line)
-		if(not m or 'device_pm_callback_start' not in line):
-			continue
-		m = re.match('.*: (?P<drv>.*) (?P<d>.*), parent: *(?P<p>.*), .*', m.group('msg'));
-		if(not m):
-			continue
-		dev = m.group('d')
-		if dev not in props:
-			props[dev] = DevProps()
-	tf.close()
-
-	if not alreadystamped and sysvals.suspendmode == 'command':
-		out = '#\n# '+msghead+'\n# Device Properties: '
-		out += 'testcommandstring,%s,0;' % (sysvals.testcommand)
-		with sysvals.openlog(sysvals.ftracefile, 'a') as fp:
-			fp.write(out+'\n')
-		sysvals.devprops = props
-		return
-
-	# now get the syspath for each of our target devices
-	for dirname, dirnames, filenames in os.walk('/sys/devices'):
-		if(re.match('.*/power', dirname) and 'async' in filenames):
-			dev = dirname.split('/')[-2]
-			if dev in props and (not props[dev].syspath or len(dirname) < len(props[dev].syspath)):
-				props[dev].syspath = dirname[:-6]
-
-	# now fill in the properties for our target devices
-	for dev in props:
-		dirname = props[dev].syspath
-		if not dirname or not os.path.exists(dirname):
-			continue
-		with open(dirname+'/power/async') as fp:
-			text = fp.read()
-			props[dev].async = False
-			if 'enabled' in text:
-				props[dev].async = True
-		fields = os.listdir(dirname)
-		if 'product' in fields:
-			with open(dirname+'/product') as fp:
-				props[dev].altname = fp.read()
-		elif 'name' in fields:
-			with open(dirname+'/name') as fp:
-				props[dev].altname = fp.read()
-		elif 'model' in fields:
-			with open(dirname+'/model') as fp:
-				props[dev].altname = fp.read()
-		elif 'description' in fields:
-			with open(dirname+'/description') as fp:
-				props[dev].altname = fp.read()
-		elif 'id' in fields:
-			with open(dirname+'/id') as fp:
-				props[dev].altname = fp.read()
-		elif 'idVendor' in fields and 'idProduct' in fields:
-			idv, idp = '', ''
-			with open(dirname+'/idVendor') as fp:
-				idv = fp.read().strip()
-			with open(dirname+'/idProduct') as fp:
-				idp = fp.read().strip()
-			props[dev].altname = '%s:%s' % (idv, idp)
-
-		if props[dev].altname:
-			out = props[dev].altname.strip().replace('\n', ' ')
-			out = out.replace(',', ' ')
-			out = out.replace(';', ' ')
-			props[dev].altname = out
-
-	# and now write the data to the ftrace file
-	if not alreadystamped:
-		out = '#\n# '+msghead+'\n# Device Properties: '
-		for dev in sorted(props):
-			out += props[dev].out(dev)
-		with sysvals.openlog(sysvals.ftracefile, 'a') as fp:
-			fp.write(out+'\n')
-
-	sysvals.devprops = props
-
 # Function: getModes
 # Description:
 #	 Determine the supported power modes on this system
@@ -4856,12 +5303,12 @@
 	modes = []
 	if(os.path.exists(sysvals.powerfile)):
 		fp = open(sysvals.powerfile, 'r')
-		modes = string.split(fp.read())
+		modes = fp.read().split()
 		fp.close()
 	if(os.path.exists(sysvals.mempowerfile)):
 		deep = False
 		fp = open(sysvals.mempowerfile, 'r')
-		for m in string.split(fp.read()):
+		for m in fp.read().split():
 			memmode = m.strip('[]')
 			if memmode == 'deep':
 				deep = True
@@ -4870,6 +5317,11 @@
 		fp.close()
 		if 'mem' in modes and not deep:
 			modes.remove('mem')
+	if('disk' in modes and os.path.exists(sysvals.diskpowerfile)):
+		fp = open(sysvals.diskpowerfile, 'r')
+		for m in fp.read().split():
+			modes.append('disk-%s' % m.strip('[]'))
+		fp.close()
 	return modes
 
 # Function: dmidecode
@@ -4930,25 +5382,26 @@
 				continue
 
 	# read in the memory for scanning
-	fp = open(mempath, 'rb')
 	try:
+		fp = open(mempath, 'rb')
 		fp.seek(memaddr)
 		buf = fp.read(memsize)
 	except:
 		if(fatal):
 			doError('DMI table is unreachable, sorry')
 		else:
+			pprint('WARNING: /dev/mem is not readable, ignoring DMI data')
 			return out
 	fp.close()
 
 	# search for either an SM table or DMI table
 	i = base = length = num = 0
 	while(i < memsize):
-		if buf[i:i+4] == '_SM_' and i < memsize - 16:
+		if buf[i:i+4] == b'_SM_' and i < memsize - 16:
 			length = struct.unpack('H', buf[i+22:i+24])[0]
 			base, num = struct.unpack('IH', buf[i+24:i+30])
 			break
-		elif buf[i:i+5] == '_DMI_':
+		elif buf[i:i+5] == b'_DMI_':
 			length = struct.unpack('H', buf[i+6:i+8])[0]
 			base, num = struct.unpack('IH', buf[i+8:i+14])
 			break
@@ -4960,14 +5413,15 @@
 			return out
 
 	# read in the SM or DMI table
-	fp = open(mempath, 'rb')
 	try:
+		fp = open(mempath, 'rb')
 		fp.seek(base)
 		buf = fp.read(length)
 	except:
 		if(fatal):
 			doError('DMI table is unreachable, sorry')
 		else:
+			pprint('WARNING: /dev/mem is not readable, ignoring DMI data')
 			return out
 	fp.close()
 
@@ -4980,22 +5434,23 @@
 			if 0 == struct.unpack('H', buf[n:n+2])[0]:
 				break
 			n += 1
-		data = buf[i+size:n+2].split('\0')
+		data = buf[i+size:n+2].split(b'\0')
 		for name in info:
 			itype, idxadr = info[name]
 			if itype == type:
-				idx = struct.unpack('B', buf[i+idxadr])[0]
+				idx = struct.unpack('B', buf[i+idxadr:i+idxadr+1])[0]
 				if idx > 0 and idx < len(data) - 1:
-					s = data[idx-1].strip()
-					if s and s.lower() != 'to be filled by o.e.m.':
-						out[name] = data[idx-1]
+					s = data[idx-1].decode('utf-8')
+					if s.strip() and s.strip().lower() != 'to be filled by o.e.m.':
+						out[name] = s
 		i = n + 2
 		count += 1
 	return out
 
 def getBattery():
-	p = '/sys/class/power_supply'
-	bat = dict()
+	p, charge, bat = '/sys/class/power_supply', 0, {}
+	if not os.path.exists(p):
+		return False
 	for d in os.listdir(p):
 		type = sysvals.getVal(os.path.join(p, d, 'type')).strip().lower()
 		if type != 'battery':
@@ -5003,15 +5458,47 @@
 		for v in ['status', 'energy_now', 'capacity_now']:
 			bat[v] = sysvals.getVal(os.path.join(p, d, v)).strip().lower()
 		break
-	ac = True
-	if 'status' in bat and 'discharging' in bat['status']:
-		ac = False
-	charge = 0
+	if 'status' not in bat:
+		return False
+	ac = False if 'discharging' in bat['status'] else True
 	for v in ['energy_now', 'capacity_now']:
 		if v in bat and bat[v]:
 			charge = int(bat[v])
 	return (ac, charge)
 
+def displayControl(cmd):
+	xset, ret = 'timeout 10 xset -d :0.0 {0}', 0
+	if sysvals.sudouser:
+		xset = 'sudo -u %s %s' % (sysvals.sudouser, xset)
+	if cmd == 'init':
+		ret = call(xset.format('dpms 0 0 0'), shell=True)
+		if not ret:
+			ret = call(xset.format('s off'), shell=True)
+	elif cmd == 'reset':
+		ret = call(xset.format('s reset'), shell=True)
+	elif cmd in ['on', 'off', 'standby', 'suspend']:
+		b4 = displayControl('stat')
+		ret = call(xset.format('dpms force %s' % cmd), shell=True)
+		if not ret:
+			curr = displayControl('stat')
+			sysvals.vprint('Display Switched: %s -> %s' % (b4, curr))
+			if curr != cmd:
+				sysvals.vprint('WARNING: Display failed to change to %s' % cmd)
+		if ret:
+			sysvals.vprint('WARNING: Display failed to change to %s with xset' % cmd)
+			return ret
+	elif cmd == 'stat':
+		fp = Popen(xset.format('q').split(' '), stdout=PIPE).stdout
+		ret = 'unknown'
+		for line in fp:
+			m = re.match('[\s]*Monitor is (?P<m>.*)', ascii(line))
+			if(m and len(m.group('m')) >= 2):
+				out = m.group('m').lower()
+				ret = out[3:] if out[0:2] == 'in' else out
+				break
+		fp.close()
+	return ret
+
 # Function: getFPDT
 # Description:
 #	 Read the acpi bios tables and pull out FPDT, the firmware data
@@ -5055,20 +5542,22 @@
 
 	table = struct.unpack('4sIBB6s8sI4sI', buf[0:36])
 	if(output):
-		print('')
-		print('Firmware Performance Data Table (%s)' % table[0])
-		print('                  Signature : %s' % table[0])
-		print('               Table Length : %u' % table[1])
-		print('                   Revision : %u' % table[2])
-		print('                   Checksum : 0x%x' % table[3])
-		print('                     OEM ID : %s' % table[4])
-		print('               OEM Table ID : %s' % table[5])
-		print('               OEM Revision : %u' % table[6])
-		print('                 Creator ID : %s' % table[7])
-		print('           Creator Revision : 0x%x' % table[8])
-		print('')
+		pprint('\n'\
+		'Firmware Performance Data Table (%s)\n'\
+		'                  Signature : %s\n'\
+		'               Table Length : %u\n'\
+		'                   Revision : %u\n'\
+		'                   Checksum : 0x%x\n'\
+		'                     OEM ID : %s\n'\
+		'               OEM Table ID : %s\n'\
+		'               OEM Revision : %u\n'\
+		'                 Creator ID : %s\n'\
+		'           Creator Revision : 0x%x\n'\
+		'' % (ascii(table[0]), ascii(table[0]), table[1], table[2],
+			table[3], ascii(table[4]), ascii(table[5]), table[6],
+			ascii(table[7]), table[8]))
 
-	if(table[0] != 'FPDT'):
+	if(table[0] != b'FPDT'):
 		if(output):
 			doError('Invalid FPDT table')
 		return False
@@ -5077,7 +5566,11 @@
 	i = 0
 	fwData = [0, 0]
 	records = buf[36:]
-	fp = open(sysvals.mempath, 'rb')
+	try:
+		fp = open(sysvals.mempath, 'rb')
+	except:
+		pprint('WARNING: /dev/mem is not readable, ignoring the FPDT data')
+		return False
 	while(i < len(records)):
 		header = struct.unpack('HBB', records[i:i+4])
 		if(header[0] not in rectype):
@@ -5092,22 +5585,24 @@
 			first = fp.read(8)
 		except:
 			if(output):
-				print('Bad address 0x%x in %s' % (addr, sysvals.mempath))
+				pprint('Bad address 0x%x in %s' % (addr, sysvals.mempath))
 			return [0, 0]
 		rechead = struct.unpack('4sI', first)
 		recdata = fp.read(rechead[1]-8)
-		if(rechead[0] == 'FBPT'):
-			record = struct.unpack('HBBIQQQQQ', recdata)
+		if(rechead[0] == b'FBPT'):
+			record = struct.unpack('HBBIQQQQQ', recdata[:48])
 			if(output):
-				print('%s (%s)' % (rectype[header[0]], rechead[0]))
-				print('                  Reset END : %u ns' % record[4])
-				print('  OS Loader LoadImage Start : %u ns' % record[5])
-				print(' OS Loader StartImage Start : %u ns' % record[6])
-				print('     ExitBootServices Entry : %u ns' % record[7])
-				print('      ExitBootServices Exit : %u ns' % record[8])
-		elif(rechead[0] == 'S3PT'):
+				pprint('%s (%s)\n'\
+				'                  Reset END : %u ns\n'\
+				'  OS Loader LoadImage Start : %u ns\n'\
+				' OS Loader StartImage Start : %u ns\n'\
+				'     ExitBootServices Entry : %u ns\n'\
+				'      ExitBootServices Exit : %u ns'\
+				'' % (rectype[header[0]], ascii(rechead[0]), record[4], record[5],
+					record[6], record[7], record[8]))
+		elif(rechead[0] == b'S3PT'):
 			if(output):
-				print('%s (%s)' % (rectype[header[0]], rechead[0]))
+				pprint('%s (%s)' % (rectype[header[0]], ascii(rechead[0])))
 			j = 0
 			while(j < len(recdata)):
 				prechead = struct.unpack('HBB', recdata[j:j+4])
@@ -5117,27 +5612,26 @@
 					record = struct.unpack('IIQQ', recdata[j:j+prechead[1]])
 					fwData[1] = record[2]
 					if(output):
-						print('    %s' % prectype[prechead[0]])
-						print('               Resume Count : %u' % \
-							record[1])
-						print('                 FullResume : %u ns' % \
-							record[2])
-						print('              AverageResume : %u ns' % \
-							record[3])
+						pprint('    %s\n'\
+						'               Resume Count : %u\n'\
+						'                 FullResume : %u ns\n'\
+						'              AverageResume : %u ns'\
+						'' % (prectype[prechead[0]], record[1],
+								record[2], record[3]))
 				elif(prechead[0] == 1):
 					record = struct.unpack('QQ', recdata[j+4:j+prechead[1]])
 					fwData[0] = record[1] - record[0]
 					if(output):
-						print('    %s' % prectype[prechead[0]])
-						print('               SuspendStart : %u ns' % \
-							record[0])
-						print('                 SuspendEnd : %u ns' % \
-							record[1])
-						print('                SuspendTime : %u ns' % \
-							fwData[0])
+						pprint('    %s\n'\
+						'               SuspendStart : %u ns\n'\
+						'                 SuspendEnd : %u ns\n'\
+						'                SuspendTime : %u ns'\
+						'' % (prectype[prechead[0]], record[0],
+								record[1], fwData[0]))
+
 				j += prechead[1]
 		if(output):
-			print('')
+			pprint('')
 		i += header[1]
 	fp.close()
 	return fwData
@@ -5149,26 +5643,26 @@
 # Output:
 #	 True if the test will work, False if not
 def statusCheck(probecheck=False):
-	status = True
+	status = ''
 
-	print('Checking this system (%s)...' % platform.node())
+	pprint('Checking this system (%s)...' % platform.node())
 
 	# check we have root access
 	res = sysvals.colorText('NO (No features of this tool will work!)')
 	if(sysvals.rootCheck(False)):
 		res = 'YES'
-	print('    have root access: %s' % res)
+	pprint('    have root access: %s' % res)
 	if(res != 'YES'):
-		print('    Try running this script with sudo')
-		return False
+		pprint('    Try running this script with sudo')
+		return 'missing root access'
 
 	# check sysfs is mounted
 	res = sysvals.colorText('NO (No features of this tool will work!)')
 	if(os.path.exists(sysvals.powerfile)):
 		res = 'YES'
-	print('    is sysfs mounted: %s' % res)
+	pprint('    is sysfs mounted: %s' % res)
 	if(res != 'YES'):
-		return False
+		return 'sysfs is missing'
 
 	# check target mode is a valid mode
 	if sysvals.suspendmode != 'command':
@@ -5177,11 +5671,11 @@
 		if(sysvals.suspendmode in modes):
 			res = 'YES'
 		else:
-			status = False
-		print('    is "%s" a valid power mode: %s' % (sysvals.suspendmode, res))
+			status = '%s mode is not supported' % sysvals.suspendmode
+		pprint('    is "%s" a valid power mode: %s' % (sysvals.suspendmode, res))
 		if(res == 'NO'):
-			print('      valid power modes are: %s' % modes)
-			print('      please choose one with -m')
+			pprint('      valid power modes are: %s' % modes)
+			pprint('      please choose one with -m')
 
 	# check if ftrace is available
 	res = sysvals.colorText('NO')
@@ -5189,17 +5683,18 @@
 	if(ftgood):
 		res = 'YES'
 	elif(sysvals.usecallgraph):
-		status = False
-	print('    is ftrace supported: %s' % res)
+		status = 'ftrace is not properly supported'
+	pprint('    is ftrace supported: %s' % res)
 
 	# check if kprobes are available
-	res = sysvals.colorText('NO')
-	sysvals.usekprobes = sysvals.verifyKprobes()
-	if(sysvals.usekprobes):
-		res = 'YES'
-	else:
-		sysvals.usedevsrc = False
-	print('    are kprobes supported: %s' % res)
+	if sysvals.usekprobes:
+		res = sysvals.colorText('NO')
+		sysvals.usekprobes = sysvals.verifyKprobes()
+		if(sysvals.usekprobes):
+			res = 'YES'
+		else:
+			sysvals.usedevsrc = False
+		pprint('    are kprobes supported: %s' % res)
 
 	# what data source are we using
 	res = 'DMESG'
@@ -5210,15 +5705,15 @@
 				sysvals.usetraceevents = False
 		if(sysvals.usetraceevents):
 			res = 'FTRACE (all trace events found)'
-	print('    timeline data source: %s' % res)
+	pprint('    timeline data source: %s' % res)
 
 	# check if rtcwake
 	res = sysvals.colorText('NO')
 	if(sysvals.rtcpath != ''):
 		res = 'YES'
 	elif(sysvals.rtcwake):
-		status = False
-	print('    is rtcwake supported: %s' % res)
+		status = 'rtcwake is not properly supported'
+	pprint('    is rtcwake supported: %s' % res)
 
 	if not probecheck:
 		return status
@@ -5243,9 +5738,9 @@
 def doError(msg, help=False):
 	if(help == True):
 		printHelp()
-	print('ERROR: %s\n') % msg
+	pprint('ERROR: %s\n' % msg)
 	sysvals.outputResult({'error':msg})
-	sys.exit()
+	sys.exit(1)
 
 # Function: getArgInt
 # Description:
@@ -5253,7 +5748,7 @@
 def getArgInt(name, args, min, max, main=True):
 	if main:
 		try:
-			arg = args.next()
+			arg = next(args)
 		except:
 			doError(name+': no argument supplied', True)
 	else:
@@ -5272,7 +5767,7 @@
 def getArgFloat(name, args, min, max, main=True):
 	if main:
 		try:
-			arg = args.next()
+			arg = next(args)
 		except:
 			doError(name+': no argument supplied', True)
 	else:
@@ -5286,7 +5781,9 @@
 	return val
 
 def processData(live=False):
-	print('PROCESSING DATA')
+	pprint('PROCESSING DATA')
+	sysvals.vprint('usetraceevents=%s, usetracemarkers=%s, usekprobes=%s' % \
+		(sysvals.usetraceevents, sysvals.usetracemarkers, sysvals.usekprobes))
 	error = ''
 	if(sysvals.usetraceevents):
 		testruns, error = parseTraceLog(live)
@@ -5299,18 +5796,56 @@
 			parseKernelLog(data)
 		if(sysvals.ftracefile and (sysvals.usecallgraph or sysvals.usetraceevents)):
 			appendIncompleteTraceLog(testruns)
+	shown = ['bios', 'biosdate', 'cpu', 'host', 'kernel', 'man', 'memfr',
+			'memsz', 'mode', 'numcpu', 'plat', 'time']
+	sysvals.vprint('System Info:')
+	for key in sorted(sysvals.stamp):
+		if key in shown:
+			sysvals.vprint('    %-8s : %s' % (key.upper(), sysvals.stamp[key]))
+	if sysvals.kparams:
+		sysvals.vprint('Kparams:\n    %s' % sysvals.kparams)
 	sysvals.vprint('Command:\n    %s' % sysvals.cmdline)
 	for data in testruns:
+		if data.mcelog:
+			sysvals.vprint('MCELOG Data:')
+			for line in data.mcelog.split('\n'):
+				sysvals.vprint('    %s' % line)
+		if data.turbostat:
+			idx, s = 0, 'Turbostat:\n    '
+			for val in data.turbostat.split('|'):
+				idx += len(val) + 1
+				if idx >= 80:
+					idx = 0
+					s += '\n    '
+				s += val + ' '
+			sysvals.vprint(s)
+		if data.battery:
+			a1, c1, a2, c2 = data.battery
+			s = 'Battery:\n    Before - AC: %s, Charge: %d\n     After - AC: %s, Charge: %d' % \
+				(a1, int(c1), a2, int(c2))
+			sysvals.vprint(s)
+		if data.wifi:
+			w = data.wifi.replace('|', ' ').split(',')
+			s = 'Wifi:\n    Before %s\n     After %s' % \
+				(w[0], w[1])
+			sysvals.vprint(s)
 		data.printDetails()
+		if len(sysvals.platinfo) > 0:
+			sysvals.vprint('\nPlatform Info:')
+			for info in sysvals.platinfo:
+				sysvals.vprint(info[0]+' - '+info[1])
+				sysvals.vprint(info[2])
+			sysvals.vprint('')
 	if sysvals.cgdump:
 		for data in testruns:
 			data.debugPrint()
-		sys.exit()
+		sys.exit(0)
 	if len(testruns) < 1:
+		pprint('ERROR: Not enough test data to build a timeline')
 		return (testruns, {'error': 'timeline generation failed'})
 	sysvals.vprint('Creating the html timeline (%s)...' % sysvals.htmlfile)
 	createHTML(testruns, error)
-	print('DONE')
+	pprint('DONE')
 	data = testruns[0]
 	stamp = data.stamp
 	stamp['suspend'], stamp['resume'] = data.getTimeValues()
@@ -5323,18 +5858,22 @@
 # Function: rerunTest
 # Description:
 #	 generate an output from an existing set of ftrace/dmesg logs
-def rerunTest():
+def rerunTest(htmlfile=''):
 	if sysvals.ftracefile:
 		doesTraceLogHaveTraceEvents()
 	if not sysvals.dmesgfile and not sysvals.usetraceevents:
 		doError('recreating this html output requires a dmesg file')
-	sysvals.setOutputFile()
+	if htmlfile:
+		sysvals.htmlfile = htmlfile
+	else:
+		sysvals.setOutputFile()
 	if os.path.exists(sysvals.htmlfile):
 		if not os.path.isfile(sysvals.htmlfile):
 			doError('a directory already exists with this name: %s' % sysvals.htmlfile)
 		elif not os.access(sysvals.htmlfile, os.W_OK):
 			doError('missing permission to write to %s' % sysvals.htmlfile)
 	testruns, stamp = processData(False)
+	sysvals.logmsg = ''
 	return stamp
 
 # Function: runTest
@@ -5346,16 +5885,23 @@
 	sysvals.initTestOutput('suspend')
 
 	# execute the test
-	executeSuspend()
+	testdata = executeSuspend()
 	sysvals.cleanupFtrace()
 	if sysvals.skiphtml:
-		sysvals.sudouser(sysvals.testdir)
+		sysvals.sudoUserchown(sysvals.testdir)
 		return
-	testruns, stamp = processData(True)
-	for data in testruns:
-		del data
-	sysvals.sudouser(sysvals.testdir)
+	if not testdata[0]['error']:
+		testruns, stamp = processData(True)
+		for data in testruns:
+			del data
+	else:
+		stamp = testdata[0]
+
+	sysvals.sudoUserchown(sysvals.testdir)
 	sysvals.outputResult(stamp, n)
+	if 'error' in stamp:
+		return 2
+	return 0
 
 def find_in_html(html, start, end, firstonly=True):
 	n, out = 0, []
@@ -5380,69 +5926,174 @@
 		return ''
 	return out
 
+def data_from_html(file, outpath, issues, fulldetail=False):
+	html = open(file, 'r').read()
+	sysvals.htmlfile = os.path.relpath(file, outpath)
+	# extract general info
+	suspend = find_in_html(html, 'Kernel Suspend', 'ms')
+	resume = find_in_html(html, 'Kernel Resume', 'ms')
+	sysinfo = find_in_html(html, '<div class="stamp sysinfo">', '</div>')
+	line = find_in_html(html, '<div class="stamp">', '</div>')
+	stmp = line.split()
+	if not suspend or not resume or len(stmp) != 8:
+		return False
+	try:
+		dt = datetime.strptime(' '.join(stmp[3:]), '%B %d %Y, %I:%M:%S %p')
+	except:
+		return False
+	sysvals.hostname = stmp[0]
+	tstr = dt.strftime('%Y/%m/%d %H:%M:%S')
+	error = find_in_html(html, '<table class="testfail"><tr><td>', '</td>')
+	if error:
+		m = re.match('[a-z]* failed in (?P<p>[a-z0-9_]*) phase', error)
+		if m:
+			result = 'fail in %s' % m.group('p')
+		else:
+			result = 'fail'
+	else:
+		result = 'pass'
+	# extract error info
+	ilist = []
+	extra = dict()
+	log = find_in_html(html, '<div id="dmesglog" style="display:none;">',
+		'</div>').strip()
+	if log:
+		d = Data(0)
+		d.end = 999999999
+		d.dmesgtext = log.split('\n')
+		msglist = d.extractErrorInfo()
+		for msg in msglist:
+			sysvals.errorSummary(issues, msg)
+		if stmp[2] == 'freeze':
+			extra = d.turbostatInfo()
+		elist = dict()
+		for dir in d.errorinfo:
+			for err in d.errorinfo[dir]:
+				if err[0] not in elist:
+					elist[err[0]] = 0
+				elist[err[0]] += 1
+		for i in elist:
+			ilist.append('%sx%d' % (i, elist[i]) if elist[i] > 1 else i)
+	low = find_in_html(html, 'freeze time: <b>', ' ms</b>')
+	if low and '|' in low:
+		issue = 'FREEZEx%d' % len(low.split('|'))
+		match = [i for i in issues if i['match'] == issue]
+		if len(match) > 0:
+			match[0]['count'] += 1
+			if sysvals.hostname not in match[0]['urls']:
+				match[0]['urls'][sysvals.hostname] = [sysvals.htmlfile]
+			elif sysvals.htmlfile not in match[0]['urls'][sysvals.hostname]:
+				match[0]['urls'][sysvals.hostname].append(sysvals.htmlfile)
+		else:
+			issues.append({
+				'match': issue, 'count': 1, 'line': issue,
+				'urls': {sysvals.hostname: [sysvals.htmlfile]},
+			})
+		ilist.append(issue)
+	# extract device info
+	devices = dict()
+	for line in html.split('\n'):
+		m = re.match(' *<div id=\"[a,0-9]*\" *title=\"(?P<title>.*)\" class=\"thread.*', line)
+		if not m or 'thread kth' in line or 'thread sec' in line:
+			continue
+		m = re.match('(?P<n>.*) \((?P<t>[0-9,\.]*) ms\) (?P<p>.*)', m.group('title'))
+		if not m:
+			continue
+		name, time, phase = m.group('n'), m.group('t'), m.group('p')
+		if ' async' in name or ' sync' in name:
+			name = ' '.join(name.split(' ')[:-1])
+		if phase.startswith('suspend'):
+			d = 'suspend'
+		elif phase.startswith('resume'):
+			d = 'resume'
+		else:
+			continue
+		if d not in devices:
+			devices[d] = dict()
+		if name not in devices[d]:
+			devices[d][name] = 0.0
+		devices[d][name] += float(time)
+	# create worst device info
+	worst = dict()
+	for d in ['suspend', 'resume']:
+		worst[d] = {'name':'', 'time': 0.0}
+		dev = devices[d] if d in devices else 0
+		if dev and len(dev.keys()) > 0:
+			n = sorted(dev, key=lambda k:(dev[k], k), reverse=True)[0]
+			worst[d]['name'], worst[d]['time'] = n, dev[n]
+	data = {
+		'mode': stmp[2],
+		'host': stmp[0],
+		'kernel': stmp[1],
+		'sysinfo': sysinfo,
+		'time': tstr,
+		'result': result,
+		'issues': ' '.join(ilist),
+		'suspend': suspend,
+		'resume': resume,
+		'devlist': devices,
+		'sus_worst': worst['suspend']['name'],
+		'sus_worsttime': worst['suspend']['time'],
+		'res_worst': worst['resume']['name'],
+		'res_worsttime': worst['resume']['time'],
+		'url': sysvals.htmlfile,
+	}
+	for key in extra:
+		data[key] = extra[key]
+	if fulldetail:
+		data['funclist'] = find_in_html(html, '<div title="', '" class="traceevent"', False)
+	return data
+
+def genHtml(subdir, force=False):
+	for dirname, dirnames, filenames in os.walk(subdir):
+		sysvals.dmesgfile = sysvals.ftracefile = sysvals.htmlfile = ''
+		for filename in filenames:
+			if(re.match('.*_dmesg.txt', filename)):
+				sysvals.dmesgfile = os.path.join(dirname, filename)
+			elif(re.match('.*_ftrace.txt', filename)):
+				sysvals.ftracefile = os.path.join(dirname, filename)
+		sysvals.setOutputFile()
+		if sysvals.ftracefile and sysvals.htmlfile and \
+			(force or not os.path.exists(sysvals.htmlfile)):
+			pprint('FTRACE: %s' % sysvals.ftracefile)
+			if sysvals.dmesgfile:
+				pprint('DMESG : %s' % sysvals.dmesgfile)
+			rerunTest()
+
 # Function: runSummary
 # Description:
 #	 create a summary of tests in a sub-directory
 def runSummary(subdir, local=True, genhtml=False):
 	inpath = os.path.abspath(subdir)
-	outpath = inpath
-	if local:
-		outpath = os.path.abspath('.')
-	print('Generating a summary of folder "%s"' % inpath)
+	outpath = os.path.abspath('.') if local else inpath
+	pprint('Generating a summary of folder:\n   %s' % inpath)
 	if genhtml:
-		for dirname, dirnames, filenames in os.walk(subdir):
-			sysvals.dmesgfile = sysvals.ftracefile = sysvals.htmlfile = ''
-			for filename in filenames:
-				if(re.match('.*_dmesg.txt', filename)):
-					sysvals.dmesgfile = os.path.join(dirname, filename)
-				elif(re.match('.*_ftrace.txt', filename)):
-					sysvals.ftracefile = os.path.join(dirname, filename)
-			sysvals.setOutputFile()
-			if sysvals.ftracefile and sysvals.htmlfile and \
-				not os.path.exists(sysvals.htmlfile):
-				print('FTRACE: %s' % sysvals.ftracefile)
-				if sysvals.dmesgfile:
-					print('DMESG : %s' % sysvals.dmesgfile)
-				rerunTest()
+		genHtml(subdir)
+	issues = []
 	testruns = []
+	desc = {'host':[],'mode':[],'kernel':[]}
 	for dirname, dirnames, filenames in os.walk(subdir):
 		for filename in filenames:
 			if(not re.match('.*.html', filename)):
 				continue
-			file = os.path.join(dirname, filename)
-			html = open(file, 'r').read()
-			suspend = find_in_html(html, 'Kernel Suspend', 'ms')
-			resume = find_in_html(html, 'Kernel Resume', 'ms')
-			line = find_in_html(html, '<div class="stamp">', '</div>')
-			stmp = line.split()
-			if not suspend or not resume or len(stmp) != 8:
+			data = data_from_html(os.path.join(dirname, filename), outpath, issues)
+			if(not data):
 				continue
-			try:
-				dt = datetime.strptime(' '.join(stmp[3:]), '%B %d %Y, %I:%M:%S %p')
-			except:
-				continue
-			tstr = dt.strftime('%Y/%m/%d %H:%M:%S')
-			error = find_in_html(html, '<table class="testfail"><tr><td>', '</td>')
-			result = 'fail' if error else 'pass'
-			ilist = []
-			e = find_in_html(html, 'class="err"[\w=":;\.%\- ]*>', '&rarr;</div>', False)
-			for i in list(set(e)):
-				ilist.append('%sx%d' % (i, e.count(i)) if e.count(i) > 1 else i)
-			data = {
-				'mode': stmp[2],
-				'host': stmp[0],
-				'kernel': stmp[1],
-				'time': tstr,
-				'result': result,
-				'issues': ','.join(ilist),
-				'suspend': suspend,
-				'resume': resume,
-				'url': os.path.relpath(file, outpath),
-			}
 			testruns.append(data)
-	outfile = os.path.join(outpath, 'summary.html')
-	print('Summary file: %s' % outfile)
-	createHTMLSummarySimple(testruns, outfile, inpath)
+			for key in desc:
+				if data[key] not in desc[key]:
+					desc[key].append(data[key])
+	pprint('Summary files:')
+	if len(desc['host']) == len(desc['mode']) == len(desc['kernel']) == 1:
+		title = '%s %s %s' % (desc['host'][0], desc['kernel'][0], desc['mode'][0])
+	else:
+		title = inpath
+	createHTMLSummarySimple(testruns, os.path.join(outpath, 'summary.html'), title)
+	pprint('   summary.html         - tabular list of test data found')
+	createHTMLDeviceSummary(testruns, os.path.join(outpath, 'summary-devices.html'), title)
+	pprint('   summary-devices.html - kernel device list sorted by total execution time')
+	createHTMLIssuesSummary(testruns, issues, os.path.join(outpath, 'summary-issues.html'), title)
+	pprint('   summary-issues.html  - kernel issues found sorted by frequency')
 
 # Function: checkArgBool
 # Description:
@@ -5459,7 +6110,7 @@
 # Description:
 #	 Configure the script via the info in a config file
 def configFromFile(file):
-	Config = ConfigParser.ConfigParser()
+	Config = configparser.ConfigParser()
 
 	Config.read(file)
 	sections = Config.sections()
@@ -5499,13 +6150,10 @@
 				else:
 					doError('invalid value --> (%s: %s), use "enable/disable"' % (option, value), True)
 			elif(option == 'display'):
-				if value in switchvalues:
-					if value in switchoff:
-						sysvals.display = -1
-					else:
-						sysvals.display = 1
-				else:
-					doError('invalid value --> (%s: %s), use "on/off"' % (option, value), True)
+				disopt = ['on', 'off', 'standby', 'suspend']
+				if value not in disopt:
+					doError('invalid value --> (%s: %s), use %s' % (option, value, disopt), True)
+				sysvals.display = value
 			elif(option == 'gzip'):
 				sysvals.gzip = checkArgBool(option, value)
 			elif(option == 'cgfilter'):
@@ -5521,9 +6169,9 @@
 				sysvals.cgtest = getArgInt('cgtest', value, 0, 1, False)
 			elif(option == 'cgphase'):
 				d = Data(0)
-				if value not in d.phases:
+				if value not in d.sortedPhases():
 					doError('invalid phase --> (%s: %s), valid phases are %s'\
-						% (option, value, d.phases), True)
+						% (option, value, d.sortedPhases()), True)
 				sysvals.cgphase = value
 			elif(option == 'fadd'):
 				file = sysvals.configFile(value)
@@ -5660,84 +6308,89 @@
 # Description:
 #	 print out the help text
 def printHelp():
-	print('')
-	print('%s v%s' % (sysvals.title, sysvals.version))
-	print('Usage: sudo sleepgraph <options> <commands>')
-	print('')
-	print('Description:')
-	print('  This tool is designed to assist kernel and OS developers in optimizing')
-	print('  their linux stack\'s suspend/resume time. Using a kernel image built')
-	print('  with a few extra options enabled, the tool will execute a suspend and')
-	print('  capture dmesg and ftrace data until resume is complete. This data is')
-	print('  transformed into a device timeline and an optional callgraph to give')
-	print('  a detailed view of which devices/subsystems are taking the most')
-	print('  time in suspend/resume.')
-	print('')
-	print('  If no specific command is given, the default behavior is to initiate')
-	print('  a suspend/resume and capture the dmesg/ftrace output as an html timeline.')
-	print('')
-	print('  Generates output files in subdirectory: suspend-yymmdd-HHMMSS')
-	print('   HTML output:                    <hostname>_<mode>.html')
-	print('   raw dmesg output:               <hostname>_<mode>_dmesg.txt')
-	print('   raw ftrace output:              <hostname>_<mode>_ftrace.txt')
-	print('')
-	print('Options:')
-	print('   -h           Print this help text')
-	print('   -v           Print the current tool version')
-	print('   -config fn   Pull arguments and config options from file fn')
-	print('   -verbose     Print extra information during execution and analysis')
-	print('   -m mode      Mode to initiate for suspend (default: %s)') % (sysvals.suspendmode)
-	print('   -o name      Overrides the output subdirectory name when running a new test')
-	print('                default: suspend-{date}-{time}')
-	print('   -rtcwake t   Wakeup t seconds after suspend, set t to "off" to disable (default: 15)')
-	print('   -addlogs     Add the dmesg and ftrace logs to the html output')
-	print('   -srgap       Add a visible gap in the timeline between sus/res (default: disabled)')
-	print('   -skiphtml    Run the test and capture the trace logs, but skip the timeline (default: disabled)')
-	print('   -result fn   Export a results table to a text file for parsing.')
-	print('  [testprep]')
-	print('   -sync        Sync the filesystems before starting the test')
-	print('   -rs on/off   Enable/disable runtime suspend for all devices, restore all after test')
-	print('   -display on/off  Turn the display on or off for the test')
-	print('  [advanced]')
-	print('   -gzip        Gzip the trace and dmesg logs to save space')
-	print('   -cmd {s}     Run the timeline over a custom command, e.g. "sync -d"')
-	print('   -proc        Add usermode process info into the timeline (default: disabled)')
-	print('   -dev         Add kernel function calls and threads to the timeline (default: disabled)')
-	print('   -x2          Run two suspend/resumes back to back (default: disabled)')
-	print('   -x2delay t   Include t ms delay between multiple test runs (default: 0 ms)')
-	print('   -predelay t  Include t ms delay before 1st suspend (default: 0 ms)')
-	print('   -postdelay t Include t ms delay after last resume (default: 0 ms)')
-	print('   -mindev ms   Discard all device blocks shorter than ms milliseconds (e.g. 0.001 for us)')
-	print('   -multi n d   Execute <n> consecutive tests at <d> seconds intervals. The outputs will')
-	print('                be created in a new subdirectory with a summary page.')
-	print('  [debug]')
-	print('   -f           Use ftrace to create device callgraphs (default: disabled)')
-	print('   -maxdepth N  limit the callgraph data to N call levels (default: 0=all)')
-	print('   -expandcg    pre-expand the callgraph data in the html output (default: disabled)')
-	print('   -fadd file   Add functions to be graphed in the timeline from a list in a text file')
-	print('   -filter "d1,d2,..." Filter out all but this comma-delimited list of device names')
-	print('   -mincg  ms   Discard all callgraphs shorter than ms milliseconds (e.g. 0.001 for us)')
-	print('   -cgphase P   Only show callgraph data for phase P (e.g. suspend_late)')
-	print('   -cgtest N    Only show callgraph data for test N (e.g. 0 or 1 in an x2 run)')
-	print('   -timeprec N  Number of significant digits in timestamps (0:S, [3:ms], 6:us)')
-	print('   -cgfilter S  Filter the callgraph output in the timeline')
-	print('   -cgskip file Callgraph functions to skip, off to disable (default: cgskip.txt)')
-	print('   -bufsize N   Set trace buffer size to N kilo-bytes (default: all of free memory)')
-	print('')
-	print('Other commands:')
-	print('   -modes       List available suspend modes')
-	print('   -status      Test to see if the system is enabled to run this tool')
-	print('   -fpdt        Print out the contents of the ACPI Firmware Performance Data Table')
-	print('   -battery     Print out battery info (if available)')
-	print('   -sysinfo     Print out system info extracted from BIOS')
-	print('   -devinfo     Print out the pm settings of all devices which support runtime suspend')
-	print('   -flist       Print the list of functions currently being captured in ftrace')
-	print('   -flistall    Print all functions capable of being captured in ftrace')
-	print('   -summary dir Create a summary of tests in this dir [-genhtml builds missing html]')
-	print('  [redo]')
-	print('   -ftrace ftracefile  Create HTML output using ftrace input (used with -dmesg)')
-	print('   -dmesg dmesgfile    Create HTML output using dmesg (used with -ftrace)')
-	print('')
+	pprint('\n%s v%s\n'\
+	'Usage: sudo sleepgraph <options> <commands>\n'\
+	'\n'\
+	'Description:\n'\
+	'  This tool is designed to assist kernel and OS developers in optimizing\n'\
+	'  their linux stack\'s suspend/resume time. Using a kernel image built\n'\
+	'  with a few extra options enabled, the tool will execute a suspend and\n'\
+	'  capture dmesg and ftrace data until resume is complete. This data is\n'\
+	'  transformed into a device timeline and an optional callgraph to give\n'\
+	'  a detailed view of which devices/subsystems are taking the most\n'\
+	'  time in suspend/resume.\n'\
+	'\n'\
+	'  If no specific command is given, the default behavior is to initiate\n'\
+	'  a suspend/resume and capture the dmesg/ftrace output as an html timeline.\n'\
+	'\n'\
+	'  Generates output files in subdirectory: suspend-yymmdd-HHMMSS\n'\
+	'   HTML output:                    <hostname>_<mode>.html\n'\
+	'   raw dmesg output:               <hostname>_<mode>_dmesg.txt\n'\
+	'   raw ftrace output:              <hostname>_<mode>_ftrace.txt\n'\
+	'\n'\
+	'Options:\n'\
+	'   -h           Print this help text\n'\
+	'   -v           Print the current tool version\n'\
+	'   -config fn   Pull arguments and config options from file fn\n'\
+	'   -verbose     Print extra information during execution and analysis\n'\
+	'   -m mode      Mode to initiate for suspend (default: %s)\n'\
+	'   -o name      Overrides the output subdirectory name when running a new test\n'\
+	'                default: suspend-{date}-{time}\n'\
+	'   -rtcwake t   Wakeup t seconds after suspend, set t to "off" to disable (default: 15)\n'\
+	'   -addlogs     Add the dmesg and ftrace logs to the html output\n'\
+	'   -noturbostat Dont use turbostat in freeze mode (default: disabled)\n'\
+	'   -srgap       Add a visible gap in the timeline between sus/res (default: disabled)\n'\
+	'   -skiphtml    Run the test and capture the trace logs, but skip the timeline (default: disabled)\n'\
+	'   -result fn   Export a results table to a text file for parsing.\n'\
+	'  [testprep]\n'\
+	'   -sync        Sync the filesystems before starting the test\n'\
+	'   -rs on/off   Enable/disable runtime suspend for all devices, restore all after test\n'\
+	'   -display m   Change the display mode to m for the test (on/off/standby/suspend)\n'\
+	'  [advanced]\n'\
+	'   -gzip        Gzip the trace and dmesg logs to save space\n'\
+	'   -cmd {s}     Run the timeline over a custom command, e.g. "sync -d"\n'\
+	'   -proc        Add usermode process info into the timeline (default: disabled)\n'\
+	'   -dev         Add kernel function calls and threads to the timeline (default: disabled)\n'\
+	'   -x2          Run two suspend/resumes back to back (default: disabled)\n'\
+	'   -x2delay t   Include t ms delay between multiple test runs (default: 0 ms)\n'\
+	'   -predelay t  Include t ms delay before 1st suspend (default: 0 ms)\n'\
+	'   -postdelay t Include t ms delay after last resume (default: 0 ms)\n'\
+	'   -mindev ms   Discard all device blocks shorter than ms milliseconds (e.g. 0.001 for us)\n'\
+	'   -multi n d   Execute <n> consecutive tests at <d> seconds intervals. The outputs will\n'\
+	'                be created in a new subdirectory with a summary page.\n'\
+	'  [debug]\n'\
+	'   -f           Use ftrace to create device callgraphs (default: disabled)\n'\
+	'   -ftop        Use ftrace on the top level call: "%s" (default: disabled)\n'\
+	'   -maxdepth N  limit the callgraph data to N call levels (default: 0=all)\n'\
+	'   -expandcg    pre-expand the callgraph data in the html output (default: disabled)\n'\
+	'   -fadd file   Add functions to be graphed in the timeline from a list in a text file\n'\
+	'   -filter "d1,d2,..." Filter out all but this comma-delimited list of device names\n'\
+	'   -mincg  ms   Discard all callgraphs shorter than ms milliseconds (e.g. 0.001 for us)\n'\
+	'   -cgphase P   Only show callgraph data for phase P (e.g. suspend_late)\n'\
+	'   -cgtest N    Only show callgraph data for test N (e.g. 0 or 1 in an x2 run)\n'\
+	'   -timeprec N  Number of significant digits in timestamps (0:S, [3:ms], 6:us)\n'\
+	'   -cgfilter S  Filter the callgraph output in the timeline\n'\
+	'   -cgskip file Callgraph functions to skip, off to disable (default: cgskip.txt)\n'\
+	'   -bufsize N   Set trace buffer size to N kilo-bytes (default: all of free memory)\n'\
+	'   -devdump     Print out all the raw device data for each phase\n'\
+	'   -cgdump      Print out all the raw callgraph data\n'\
+	'\n'\
+	'Other commands:\n'\
+	'   -modes       List available suspend modes\n'\
+	'   -status      Test to see if the system is enabled to run this tool\n'\
+	'   -fpdt        Print out the contents of the ACPI Firmware Performance Data Table\n'\
+	'   -battery     Print out battery info (if available)\n'\
+	'   -wifi        Print out wifi connection info (if wireless-tools and device exists)\n'\
+	'   -x<mode>     Test xset by toggling the given mode (on/off/standby/suspend)\n'\
+	'   -sysinfo     Print out system info extracted from BIOS\n'\
+	'   -devinfo     Print out the pm settings of all devices which support runtime suspend\n'\
+	'   -flist       Print the list of functions currently being captured in ftrace\n'\
+	'   -flistall    Print all functions capable of being captured in ftrace\n'\
+	'   -summary dir Create a summary of tests in this dir [-genhtml builds missing html]\n'\
+	'  [redo]\n'\
+	'   -ftrace ftracefile  Create HTML output using ftrace input (used with -dmesg)\n'\
+	'   -dmesg dmesgfile    Create HTML output using dmesg (used with -ftrace)\n'\
+	'' % (sysvals.title, sysvals.version, sysvals.suspendmode, sysvals.ftopfunc))
 	return True
 
 # ----------------- MAIN --------------------
@@ -5745,7 +6398,9 @@
 if __name__ == '__main__':
 	genhtml = False
 	cmd = ''
-	simplecmds = ['-sysinfo', '-modes', '-fpdt', '-flist', '-flistall', '-devinfo', '-status', '-battery']
+	simplecmds = ['-sysinfo', '-modes', '-fpdt', '-flist', '-flistall',
+		'-devinfo', '-status', '-battery', '-xon', '-xoff', '-xstandby',
+		'-xsuspend', '-xinit', '-xreset', '-xstat', '-wifi']
 	if '-f' in sys.argv:
 		sysvals.cgskip = sysvals.configFile('cgskip.txt')
 	# loop through the command line arguments
@@ -5753,7 +6408,7 @@
 	for arg in args:
 		if(arg == '-m'):
 			try:
-				val = args.next()
+				val = next(args)
 			except:
 				doError('No mode supplied', True)
 			if val == 'command' and not sysvals.testcommand:
@@ -5763,10 +6418,10 @@
 			cmd = arg[1:]
 		elif(arg == '-h'):
 			printHelp()
-			sys.exit()
+			sys.exit(0)
 		elif(arg == '-v'):
-			print("Version %s" % sysvals.version)
-			sys.exit()
+			pprint("Version %s" % sysvals.version)
+			sys.exit(0)
 		elif(arg == '-x2'):
 			sysvals.execcount = 2
 		elif(arg == '-x2delay'):
@@ -5777,14 +6432,28 @@
 			sysvals.postdelay = getArgInt('-postdelay', args, 0, 60000)
 		elif(arg == '-f'):
 			sysvals.usecallgraph = True
+		elif(arg == '-ftop'):
+			sysvals.usecallgraph = True
+			sysvals.ftop = True
+			sysvals.usekprobes = False
 		elif(arg == '-skiphtml'):
 			sysvals.skiphtml = True
 		elif(arg == '-cgdump'):
 			sysvals.cgdump = True
+		elif(arg == '-devdump'):
+			sysvals.devdump = True
 		elif(arg == '-genhtml'):
 			genhtml = True
 		elif(arg == '-addlogs'):
 			sysvals.dmesglog = sysvals.ftracelog = True
+		elif(arg == '-nologs'):
+			sysvals.dmesglog = sysvals.ftracelog = False
+		elif(arg == '-addlogdmesg'):
+			sysvals.dmesglog = True
+		elif(arg == '-addlogftrace'):
+			sysvals.ftracelog = True
+		elif(arg == '-noturbostat'):
+			sysvals.tstat = False
 		elif(arg == '-verbose'):
 			sysvals.verbose = True
 		elif(arg == '-proc'):
@@ -5797,7 +6466,7 @@
 			sysvals.gzip = True
 		elif(arg == '-rs'):
 			try:
-				val = args.next()
+				val = next(args)
 			except:
 				doError('-rs requires "enable" or "disable"', True)
 			if val.lower() in switchvalues:
@@ -5809,21 +6478,18 @@
 				doError('invalid option: %s, use "enable/disable" or "on/off"' % val, True)
 		elif(arg == '-display'):
 			try:
-				val = args.next()
+				val = next(args)
 			except:
-				doError('-display requires "on" or "off"', True)
-			if val.lower() in switchvalues:
-				if val.lower() in switchoff:
-					sysvals.display = -1
-				else:
-					sysvals.display = 1
-			else:
-				doError('invalid option: %s, use "on/off"' % val, True)
+				doError('-display requires an mode value', True)
+			disopt = ['on', 'off', 'standby', 'suspend']
+			if val.lower() not in disopt:
+				doError('valid display mode values are %s' % disopt, True)
+			sysvals.display = val.lower()
 		elif(arg == '-maxdepth'):
 			sysvals.max_graph_depth = getArgInt('-maxdepth', args, 0, 1000)
 		elif(arg == '-rtcwake'):
 			try:
-				val = args.next()
+				val = next(args)
 			except:
 				doError('No rtcwake time supplied', True)
 			if val.lower() in switchoff:
@@ -5843,23 +6509,29 @@
 			sysvals.cgtest = getArgInt('-cgtest', args, 0, 1)
 		elif(arg == '-cgphase'):
 			try:
-				val = args.next()
+				val = next(args)
 			except:
 				doError('No phase name supplied', True)
 			d = Data(0)
-			if val not in d.phases:
+			if val not in d.phasedef:
 				doError('invalid phase --> (%s: %s), valid phases are %s'\
-					% (arg, val, d.phases), True)
+					% (arg, val, d.phasedef.keys()), True)
 			sysvals.cgphase = val
 		elif(arg == '-cgfilter'):
 			try:
-				val = args.next()
+				val = next(args)
 			except:
 				doError('No callgraph functions supplied', True)
 			sysvals.setCallgraphFilter(val)
+		elif(arg == '-skipkprobe'):
+			try:
+				val = next(args)
+			except:
+				doError('No kprobe functions supplied', True)
+			sysvals.skipKprobes(val)
 		elif(arg == '-cgskip'):
 			try:
-				val = args.next()
+				val = next(args)
 			except:
 				doError('No file supplied', True)
 			if val.lower() in switchoff:
@@ -5874,7 +6546,7 @@
 			sysvals.callloopmaxlen = getArgFloat('-callloop-maxlen', args, 0.0, 1.0)
 		elif(arg == '-cmd'):
 			try:
-				val = args.next()
+				val = next(args)
 			except:
 				doError('No command string supplied', True)
 			sysvals.testcommand = val
@@ -5889,13 +6561,13 @@
 			sysvals.multitest['delay'] = getArgInt('-multi n d (delay between tests)', args, 0, 3600)
 		elif(arg == '-o'):
 			try:
-				val = args.next()
+				val = next(args)
 			except:
 				doError('No subdirectory name supplied', True)
 			sysvals.outdir = sysvals.setOutputFolder(val)
 		elif(arg == '-config'):
 			try:
-				val = args.next()
+				val = next(args)
 			except:
 				doError('No text file supplied', True)
 			file = sysvals.configFile(val)
@@ -5904,7 +6576,7 @@
 			configFromFile(file)
 		elif(arg == '-fadd'):
 			try:
-				val = args.next()
+				val = next(args)
 			except:
 				doError('No text file supplied', True)
 			file = sysvals.configFile(val)
@@ -5913,7 +6585,7 @@
 			sysvals.addFtraceFilterFunctions(file)
 		elif(arg == '-dmesg'):
 			try:
-				val = args.next()
+				val = next(args)
 			except:
 				doError('No dmesg file supplied', True)
 			sysvals.notestrun = True
@@ -5922,7 +6594,7 @@
 				doError('%s does not exist' % sysvals.dmesgfile)
 		elif(arg == '-ftrace'):
 			try:
-				val = args.next()
+				val = next(args)
 			except:
 				doError('No ftrace file supplied', True)
 			sysvals.notestrun = True
@@ -5931,7 +6603,7 @@
 				doError('%s does not exist' % sysvals.ftracefile)
 		elif(arg == '-summary'):
 			try:
-				val = args.next()
+				val = next(args)
 			except:
 				doError('No directory supplied', True)
 			cmd = 'summary'
@@ -5941,16 +6613,17 @@
 				doError('%s is not accesible' % val)
 		elif(arg == '-filter'):
 			try:
-				val = args.next()
+				val = next(args)
 			except:
 				doError('No devnames supplied', True)
 			sysvals.setDeviceFilter(val)
 		elif(arg == '-result'):
 			try:
-				val = args.next()
+				val = next(args)
 			except:
 				doError('No result file supplied', True)
 			sysvals.result = val
+			sysvals.signalHandlerInit()
 		else:
 			doError('Invalid argument: '+arg, True)
 
@@ -5975,43 +6648,61 @@
 
 	# just run a utility command and exit
 	if(cmd != ''):
+		ret = 0
 		if(cmd == 'status'):
-			statusCheck(True)
+			if not statusCheck(True):
+				ret = 1
 		elif(cmd == 'fpdt'):
-			getFPDT(True)
+			if not getFPDT(True):
+				ret = 1
 		elif(cmd == 'battery'):
-			print 'AC Connect: %s\nCharge: %d' % getBattery()
+			out = getBattery()
+			if out:
+				pprint('AC Connect    : %s\nBattery Charge: %d' % out)
+			else:
+				pprint('no battery found')
+				ret = 1
 		elif(cmd == 'sysinfo'):
 			sysvals.printSystemInfo(True)
 		elif(cmd == 'devinfo'):
 			deviceInfo()
 		elif(cmd == 'modes'):
-			print getModes()
+			pprint(getModes())
 		elif(cmd == 'flist'):
 			sysvals.getFtraceFilterFunctions(True)
 		elif(cmd == 'flistall'):
 			sysvals.getFtraceFilterFunctions(False)
 		elif(cmd == 'summary'):
 			runSummary(sysvals.outdir, True, genhtml)
-		sys.exit()
+		elif(cmd in ['xon', 'xoff', 'xstandby', 'xsuspend', 'xinit', 'xreset']):
+			sysvals.verbose = True
+			ret = displayControl(cmd[1:])
+		elif(cmd == 'xstat'):
+			pprint('Display Status: %s' % displayControl('stat').upper())
+		elif(cmd == 'wifi'):
+			out = sysvals.checkWifi()
+			if 'device' not in out:
+				pprint('WIFI interface not found')
+			else:
+				for key in sorted(out):
+					pprint('%6s: %s' % (key.upper(), out[key]))
+		sys.exit(ret)
 
 	# if instructed, re-analyze existing data files
 	if(sysvals.notestrun):
-		stamp = rerunTest()
+		stamp = rerunTest(sysvals.outdir)
 		sysvals.outputResult(stamp)
-		sys.exit()
+		sys.exit(0)
 
 	# verify that we can run a test
-	if(not statusCheck()):
-		doError('Check FAILED, aborting the test run!')
+	error = statusCheck()
+	if(error):
+		doError(error)
 
-	# extract mem modes and convert
+	# extract mem/disk extra modes and convert
 	mode = sysvals.suspendmode
-	if 'mem' == mode[:3]:
-		if '-' in mode:
-			memmode = mode.split('-')[-1]
-		else:
-			memmode = 'deep'
+	if mode.startswith('mem'):
+		memmode = mode.split('-', 1)[-1] if '-' in mode else 'deep'
 		if memmode == 'shallow':
 			mode = 'standby'
 		elif memmode ==  's2idle':
@@ -6020,38 +6711,42 @@
 			mode = 'mem'
 		sysvals.memmode = memmode
 		sysvals.suspendmode = mode
+	if mode.startswith('disk-'):
+		sysvals.diskmode = mode.split('-', 1)[-1]
+		sysvals.suspendmode = 'disk'
 
 	sysvals.systemInfo(dmidecode(sysvals.mempath))
 
 	setRuntimeSuspend(True)
 	if sysvals.display:
-		call('xset -d :0.0 dpms 0 0 0', shell=True)
-		call('xset -d :0.0 s off', shell=True)
+		displayControl('init')
+	ret = 0
 	if sysvals.multitest['run']:
 		# run multiple tests in a separate subdirectory
 		if not sysvals.outdir:
 			s = 'suspend-x%d' % sysvals.multitest['count']
 			sysvals.outdir = datetime.now().strftime(s+'-%y%m%d-%H%M%S')
 		if not os.path.isdir(sysvals.outdir):
-			os.mkdir(sysvals.outdir)
+			os.makedirs(sysvals.outdir)
 		for i in range(sysvals.multitest['count']):
 			if(i != 0):
-				print('Waiting %d seconds...' % (sysvals.multitest['delay']))
+				pprint('Waiting %d seconds...' % (sysvals.multitest['delay']))
 				time.sleep(sysvals.multitest['delay'])
-			print('TEST (%d/%d) START' % (i+1, sysvals.multitest['count']))
+			pprint('TEST (%d/%d) START' % (i+1, sysvals.multitest['count']))
 			fmt = 'suspend-%y%m%d-%H%M%S'
 			sysvals.testdir = os.path.join(sysvals.outdir, datetime.now().strftime(fmt))
-			runTest(i+1)
-			print('TEST (%d/%d) COMPLETE' % (i+1, sysvals.multitest['count']))
+			ret = runTest(i+1)
+			pprint('TEST (%d/%d) COMPLETE' % (i+1, sysvals.multitest['count']))
 			sysvals.logmsg = ''
 		if not sysvals.skiphtml:
 			runSummary(sysvals.outdir, False, False)
-		sysvals.sudouser(sysvals.outdir)
+		sysvals.sudoUserchown(sysvals.outdir)
 	else:
 		if sysvals.outdir:
 			sysvals.testdir = sysvals.outdir
 		# run the test in the current directory
-		runTest()
+		ret = runTest()
 	if sysvals.display:
-		call('xset -d :0.0 s reset', shell=True)
+		displayControl('reset')
 	setRuntimeSuspend(False)
+	sys.exit(ret)
diff --git a/tools/power/x86/intel-speed-select/.gitignore b/tools/power/x86/intel-speed-select/.gitignore
new file mode 100644
index 0000000..f611459
--- /dev/null
+++ b/tools/power/x86/intel-speed-select/.gitignore
@@ -0,0 +1,2 @@
+include/
+intel-speed-select
diff --git a/tools/power/x86/intel-speed-select/Build b/tools/power/x86/intel-speed-select/Build
new file mode 100644
index 0000000..b61456d
--- /dev/null
+++ b/tools/power/x86/intel-speed-select/Build
@@ -0,0 +1 @@
+intel-speed-select-y +=  isst-config.o isst-core.o isst-display.o
diff --git a/tools/power/x86/intel-speed-select/Makefile b/tools/power/x86/intel-speed-select/Makefile
new file mode 100644
index 0000000..12c6939
--- /dev/null
+++ b/tools/power/x86/intel-speed-select/Makefile
@@ -0,0 +1,56 @@
+# SPDX-License-Identifier: GPL-2.0
+include ../../../scripts/Makefile.include
+
+bindir ?= /usr/bin
+
+ifeq ($(srctree),)
+srctree := $(patsubst %/,%,$(dir $(CURDIR)))
+srctree := $(patsubst %/,%,$(dir $(srctree)))
+srctree := $(patsubst %/,%,$(dir $(srctree)))
+srctree := $(patsubst %/,%,$(dir $(srctree)))
+endif
+
+# Do not use make's built-in rules
+# (this improves performance and avoids hard-to-debug behaviour);
+MAKEFLAGS += -r
+
+override CFLAGS += -O2 -Wall -g -D_GNU_SOURCE -I$(OUTPUT)include
+
+ALL_TARGETS := intel-speed-select
+ALL_PROGRAMS := $(patsubst %,$(OUTPUT)%,$(ALL_TARGETS))
+
+all: $(ALL_PROGRAMS)
+
+export srctree OUTPUT CC LD CFLAGS
+include $(srctree)/tools/build/Makefile.include
+
+#
+# We need the following to be outside of kernel tree
+#
+$(OUTPUT)include/linux/isst_if.h: ../../../../include/uapi/linux/isst_if.h
+	mkdir -p $(OUTPUT)include/linux 2>&1 || true
+	ln -sf $(CURDIR)/../../../../include/uapi/linux/isst_if.h $@
+
+prepare: $(OUTPUT)include/linux/isst_if.h
+
+ISST_IN := $(OUTPUT)intel-speed-select-in.o
+
+$(ISST_IN): prepare FORCE
+	$(Q)$(MAKE) $(build)=intel-speed-select
+$(OUTPUT)intel-speed-select: $(ISST_IN)
+	$(QUIET_LINK)$(CC) $(CFLAGS) $(LDFLAGS) $< -o $@
+
+clean:
+	rm -f $(ALL_PROGRAMS)
+	rm -rf $(OUTPUT)include/linux/isst_if.h
+	find $(if $(OUTPUT),$(OUTPUT),.) -name '*.o' -delete -o -name '\.*.d' -delete
+
+install: $(ALL_PROGRAMS)
+	install -d -m 755 $(DESTDIR)$(bindir);		\
+	for program in $(ALL_PROGRAMS); do		\
+		install $$program $(DESTDIR)$(bindir);	\
+	done
+
+FORCE:
+
+.PHONY: all install clean FORCE prepare
diff --git a/tools/power/x86/intel-speed-select/isst-config.c b/tools/power/x86/intel-speed-select/isst-config.c
new file mode 100644
index 0000000..2a9890c
--- /dev/null
+++ b/tools/power/x86/intel-speed-select/isst-config.c
@@ -0,0 +1,1706 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Intel Speed Select -- Enumerate and control features
+ * Copyright (c) 2019 Intel Corporation.
+ */
+
+#include <linux/isst_if.h>
+
+#include "isst.h"
+
+struct process_cmd_struct {
+	char *feature;
+	char *command;
+	void (*process_fn)(void);
+};
+
+static const char *version_str = "v1.0";
+static const int supported_api_ver = 1;
+static struct isst_if_platform_info isst_platform_info;
+static char *progname;
+static int debug_flag;
+static FILE *outf;
+
+static int cpu_model;
+
+#define MAX_CPUS_IN_ONE_REQ 64
+static short max_target_cpus;
+static unsigned short target_cpus[MAX_CPUS_IN_ONE_REQ];
+
+static int topo_max_cpus;
+static size_t present_cpumask_size;
+static cpu_set_t *present_cpumask;
+static size_t target_cpumask_size;
+static cpu_set_t *target_cpumask;
+static int tdp_level = 0xFF;
+static int fact_bucket = 0xFF;
+static int fact_avx = 0xFF;
+static unsigned long long fact_trl;
+static int out_format_json;
+static int cmd_help;
+static int force_online_offline;
+
+/* clos related */
+static int current_clos = -1;
+static int clos_epp = -1;
+static int clos_prop_prio = -1;
+static int clos_min = -1;
+static int clos_max = -1;
+static int clos_desired = -1;
+static int clos_priority_type;
+
+struct _cpu_map {
+	unsigned short core_id;
+	unsigned short pkg_id;
+	unsigned short die_id;
+	unsigned short punit_cpu;
+	unsigned short punit_cpu_core;
+};
+struct _cpu_map *cpu_map;
+
+void debug_printf(const char *format, ...)
+{
+	va_list args;
+
+	va_start(args, format);
+
+	if (debug_flag)
+		vprintf(format, args);
+
+	va_end(args);
+}
+
+static void update_cpu_model(void)
+{
+	unsigned int ebx, ecx, edx;
+	unsigned int fms, family;
+
+	__cpuid(1, fms, ebx, ecx, edx);
+	family = (fms >> 8) & 0xf;
+	cpu_model = (fms >> 4) & 0xf;
+	if (family == 6 || family == 0xf)
+		cpu_model += ((fms >> 16) & 0xf) << 4;
+}
+
+/* Open a file, and exit on failure */
+static FILE *fopen_or_exit(const char *path, const char *mode)
+{
+	FILE *filep = fopen(path, mode);
+
+	if (!filep)
+		err(1, "%s: open failed", path);
+
+	return filep;
+}
+
+/* Parse a file containing a single int */
+static int parse_int_file(int fatal, 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);
+	if (fatal) {
+		filep = fopen_or_exit(path, "r");
+	} else {
+		filep = fopen(path, "r");
+		if (!filep)
+			return -1;
+	}
+	if (fscanf(filep, "%d", &value) != 1)
+		err(1, "%s: failed to parse number from file", path);
+	fclose(filep);
+
+	return value;
+}
+
+int cpufreq_sysfs_present(void)
+{
+	DIR *dir;
+
+	dir = opendir("/sys/devices/system/cpu/cpu0/cpufreq");
+	if (dir) {
+		closedir(dir);
+		return 1;
+	}
+
+	return 0;
+}
+
+int out_format_is_json(void)
+{
+	return out_format_json;
+}
+
+int get_physical_package_id(int cpu)
+{
+	return parse_int_file(
+		0, "/sys/devices/system/cpu/cpu%d/topology/physical_package_id",
+		cpu);
+}
+
+int get_physical_core_id(int cpu)
+{
+	return parse_int_file(
+		0, "/sys/devices/system/cpu/cpu%d/topology/core_id", cpu);
+}
+
+int get_physical_die_id(int cpu)
+{
+	int ret;
+
+	ret = parse_int_file(0, "/sys/devices/system/cpu/cpu%d/topology/die_id",
+			     cpu);
+	if (ret < 0)
+		ret = 0;
+
+	return ret;
+}
+
+int get_topo_max_cpus(void)
+{
+	return topo_max_cpus;
+}
+
+static void set_cpu_online_offline(int cpu, int state)
+{
+	char buffer[128];
+	int fd;
+
+	snprintf(buffer, sizeof(buffer),
+		 "/sys/devices/system/cpu/cpu%d/online", cpu);
+
+	fd = open(buffer, O_WRONLY);
+	if (fd < 0)
+		err(-1, "%s open failed", buffer);
+
+	if (state)
+		write(fd, "1\n", 2);
+	else
+		write(fd, "0\n", 2);
+
+	close(fd);
+}
+
+#define MAX_PACKAGE_COUNT 8
+#define MAX_DIE_PER_PACKAGE 2
+static void for_each_online_package_in_set(void (*callback)(int, void *, void *,
+							    void *, void *),
+					   void *arg1, void *arg2, void *arg3,
+					   void *arg4)
+{
+	int max_packages[MAX_PACKAGE_COUNT * MAX_PACKAGE_COUNT];
+	int pkg_index = 0, i;
+
+	memset(max_packages, 0xff, sizeof(max_packages));
+	for (i = 0; i < topo_max_cpus; ++i) {
+		int j, online, pkg_id, die_id = 0, skip = 0;
+
+		if (!CPU_ISSET_S(i, present_cpumask_size, present_cpumask))
+			continue;
+		if (i)
+			online = parse_int_file(
+				1, "/sys/devices/system/cpu/cpu%d/online", i);
+		else
+			online =
+				1; /* online entry for CPU 0 needs some special configs */
+
+		die_id = get_physical_die_id(i);
+		if (die_id < 0)
+			die_id = 0;
+		pkg_id = get_physical_package_id(i);
+		/* Create an unique id for package, die combination to store */
+		pkg_id = (MAX_PACKAGE_COUNT * pkg_id + die_id);
+
+		for (j = 0; j < pkg_index; ++j) {
+			if (max_packages[j] == pkg_id) {
+				skip = 1;
+				break;
+			}
+		}
+
+		if (!skip && online && callback) {
+			callback(i, arg1, arg2, arg3, arg4);
+			max_packages[pkg_index++] = pkg_id;
+		}
+	}
+}
+
+static void for_each_online_target_cpu_in_set(
+	void (*callback)(int, void *, void *, void *, void *), void *arg1,
+	void *arg2, void *arg3, void *arg4)
+{
+	int i;
+
+	for (i = 0; i < topo_max_cpus; ++i) {
+		int online;
+
+		if (!CPU_ISSET_S(i, target_cpumask_size, target_cpumask))
+			continue;
+		if (i)
+			online = parse_int_file(
+				1, "/sys/devices/system/cpu/cpu%d/online", i);
+		else
+			online =
+				1; /* online entry for CPU 0 needs some special configs */
+
+		if (online && callback)
+			callback(i, arg1, arg2, arg3, arg4);
+	}
+}
+
+#define BITMASK_SIZE 32
+static void set_max_cpu_num(void)
+{
+	FILE *filep;
+	unsigned long dummy;
+
+	topo_max_cpus = 0;
+	filep = fopen_or_exit(
+		"/sys/devices/system/cpu/cpu0/topology/thread_siblings", "r");
+	while (fscanf(filep, "%lx,", &dummy) == 1)
+		topo_max_cpus += BITMASK_SIZE;
+	fclose(filep);
+	topo_max_cpus--; /* 0 based */
+
+	debug_printf("max cpus %d\n", topo_max_cpus);
+}
+
+size_t alloc_cpu_set(cpu_set_t **cpu_set)
+{
+	cpu_set_t *_cpu_set;
+	size_t size;
+
+	_cpu_set = CPU_ALLOC((topo_max_cpus + 1));
+	if (_cpu_set == NULL)
+		err(3, "CPU_ALLOC");
+	size = CPU_ALLOC_SIZE((topo_max_cpus + 1));
+	CPU_ZERO_S(size, _cpu_set);
+
+	*cpu_set = _cpu_set;
+	return size;
+}
+
+void free_cpu_set(cpu_set_t *cpu_set)
+{
+	CPU_FREE(cpu_set);
+}
+
+static int cpu_cnt[MAX_PACKAGE_COUNT][MAX_DIE_PER_PACKAGE];
+static void set_cpu_present_cpu_mask(void)
+{
+	size_t size;
+	DIR *dir;
+	int i;
+
+	size = alloc_cpu_set(&present_cpumask);
+	present_cpumask_size = size;
+	for (i = 0; i < topo_max_cpus; ++i) {
+		char buffer[256];
+
+		snprintf(buffer, sizeof(buffer),
+			 "/sys/devices/system/cpu/cpu%d", i);
+		dir = opendir(buffer);
+		if (dir) {
+			int pkg_id, die_id;
+
+			CPU_SET_S(i, size, present_cpumask);
+			die_id = get_physical_die_id(i);
+			if (die_id < 0)
+				die_id = 0;
+
+			pkg_id = get_physical_package_id(i);
+			if (pkg_id < MAX_PACKAGE_COUNT &&
+			    die_id < MAX_DIE_PER_PACKAGE)
+				cpu_cnt[pkg_id][die_id]++;
+		}
+		closedir(dir);
+	}
+}
+
+int get_cpu_count(int pkg_id, int die_id)
+{
+	if (pkg_id < MAX_PACKAGE_COUNT && die_id < MAX_DIE_PER_PACKAGE)
+		return cpu_cnt[pkg_id][die_id];
+
+	return 0;
+}
+
+static void set_cpu_target_cpu_mask(void)
+{
+	size_t size;
+	int i;
+
+	size = alloc_cpu_set(&target_cpumask);
+	target_cpumask_size = size;
+	for (i = 0; i < max_target_cpus; ++i) {
+		if (!CPU_ISSET_S(target_cpus[i], present_cpumask_size,
+				 present_cpumask))
+			continue;
+
+		CPU_SET_S(target_cpus[i], size, target_cpumask);
+	}
+}
+
+static void create_cpu_map(void)
+{
+	const char *pathname = "/dev/isst_interface";
+	int i, fd = 0;
+	struct isst_if_cpu_maps map;
+
+	cpu_map = malloc(sizeof(*cpu_map) * topo_max_cpus);
+	if (!cpu_map)
+		err(3, "cpumap");
+
+	fd = open(pathname, O_RDWR);
+	if (fd < 0)
+		err(-1, "%s open failed", pathname);
+
+	for (i = 0; i < topo_max_cpus; ++i) {
+		if (!CPU_ISSET_S(i, present_cpumask_size, present_cpumask))
+			continue;
+
+		map.cmd_count = 1;
+		map.cpu_map[0].logical_cpu = i;
+
+		debug_printf(" map logical_cpu:%d\n",
+			     map.cpu_map[0].logical_cpu);
+		if (ioctl(fd, ISST_IF_GET_PHY_ID, &map) == -1) {
+			perror("ISST_IF_GET_PHY_ID");
+			fprintf(outf, "Error: map logical_cpu:%d\n",
+				map.cpu_map[0].logical_cpu);
+			continue;
+		}
+		cpu_map[i].core_id = get_physical_core_id(i);
+		cpu_map[i].pkg_id = get_physical_package_id(i);
+		cpu_map[i].die_id = get_physical_die_id(i);
+		cpu_map[i].punit_cpu = map.cpu_map[0].physical_cpu;
+		cpu_map[i].punit_cpu_core = (map.cpu_map[0].physical_cpu >>
+					     1); // shift to get core id
+
+		debug_printf(
+			"map logical_cpu:%d core: %d die:%d pkg:%d punit_cpu:%d punit_core:%d\n",
+			i, cpu_map[i].core_id, cpu_map[i].die_id,
+			cpu_map[i].pkg_id, cpu_map[i].punit_cpu,
+			cpu_map[i].punit_cpu_core);
+	}
+
+	if (fd)
+		close(fd);
+}
+
+int find_logical_cpu(int pkg_id, int die_id, int punit_core_id)
+{
+	int i;
+
+	for (i = 0; i < topo_max_cpus; ++i) {
+		if (cpu_map[i].pkg_id == pkg_id &&
+		    cpu_map[i].die_id == die_id &&
+		    cpu_map[i].punit_cpu_core == punit_core_id)
+			return i;
+	}
+
+	return -EINVAL;
+}
+
+void set_cpu_mask_from_punit_coremask(int cpu, unsigned long long core_mask,
+				      size_t core_cpumask_size,
+				      cpu_set_t *core_cpumask, int *cpu_cnt)
+{
+	int i, cnt = 0;
+	int die_id, pkg_id;
+
+	*cpu_cnt = 0;
+	die_id = get_physical_die_id(cpu);
+	pkg_id = get_physical_package_id(cpu);
+
+	for (i = 0; i < 64; ++i) {
+		if (core_mask & BIT(i)) {
+			int j;
+
+			for (j = 0; j < topo_max_cpus; ++j) {
+				if (!CPU_ISSET_S(j, present_cpumask_size, present_cpumask))
+					continue;
+
+				if (cpu_map[j].pkg_id == pkg_id &&
+				    cpu_map[j].die_id == die_id &&
+				    cpu_map[j].punit_cpu_core == i) {
+					CPU_SET_S(j, core_cpumask_size,
+						  core_cpumask);
+					++cnt;
+				}
+			}
+		}
+	}
+
+	*cpu_cnt = cnt;
+}
+
+int find_phy_core_num(int logical_cpu)
+{
+	if (logical_cpu < topo_max_cpus)
+		return cpu_map[logical_cpu].punit_cpu_core;
+
+	return -EINVAL;
+}
+
+static int isst_send_mmio_command(unsigned int cpu, unsigned int reg, int write,
+				  unsigned int *value)
+{
+	struct isst_if_io_regs io_regs;
+	const char *pathname = "/dev/isst_interface";
+	int cmd;
+	int fd;
+
+	debug_printf("mmio_cmd cpu:%d reg:%d write:%d\n", cpu, reg, write);
+
+	fd = open(pathname, O_RDWR);
+	if (fd < 0)
+		err(-1, "%s open failed", pathname);
+
+	io_regs.req_count = 1;
+	io_regs.io_reg[0].logical_cpu = cpu;
+	io_regs.io_reg[0].reg = reg;
+	cmd = ISST_IF_IO_CMD;
+	if (write) {
+		io_regs.io_reg[0].read_write = 1;
+		io_regs.io_reg[0].value = *value;
+	} else {
+		io_regs.io_reg[0].read_write = 0;
+	}
+
+	if (ioctl(fd, cmd, &io_regs) == -1) {
+		perror("ISST_IF_IO_CMD");
+		fprintf(outf, "Error: mmio_cmd cpu:%d reg:%x read_write:%x\n",
+			cpu, reg, write);
+	} else {
+		if (!write)
+			*value = io_regs.io_reg[0].value;
+
+		debug_printf(
+			"mmio_cmd response: cpu:%d reg:%x rd_write:%x resp:%x\n",
+			cpu, reg, write, *value);
+	}
+
+	close(fd);
+
+	return 0;
+}
+
+int isst_send_mbox_command(unsigned int cpu, unsigned char command,
+			   unsigned char sub_command, unsigned int parameter,
+			   unsigned int req_data, unsigned int *resp)
+{
+	const char *pathname = "/dev/isst_interface";
+	int fd;
+	struct isst_if_mbox_cmds mbox_cmds = { 0 };
+
+	debug_printf(
+		"mbox_send: cpu:%d command:%x sub_command:%x parameter:%x req_data:%x\n",
+		cpu, command, sub_command, parameter, req_data);
+
+	if (isst_platform_info.mmio_supported && command == CONFIG_CLOS) {
+		unsigned int value;
+		int write = 0;
+		int clos_id, core_id, ret = 0;
+
+		debug_printf("CPU %d\n", cpu);
+
+		if (parameter & BIT(MBOX_CMD_WRITE_BIT)) {
+			value = req_data;
+			write = 1;
+		}
+
+		switch (sub_command) {
+		case CLOS_PQR_ASSOC:
+			core_id = parameter & 0xff;
+			ret = isst_send_mmio_command(
+				cpu, PQR_ASSOC_OFFSET + core_id * 4, write,
+				&value);
+			if (!ret && !write)
+				*resp = value;
+			break;
+		case CLOS_PM_CLOS:
+			clos_id = parameter & 0x03;
+			ret = isst_send_mmio_command(
+				cpu, PM_CLOS_OFFSET + clos_id * 4, write,
+				&value);
+			if (!ret && !write)
+				*resp = value;
+			break;
+		case CLOS_PM_QOS_CONFIG:
+			ret = isst_send_mmio_command(cpu, PM_QOS_CONFIG_OFFSET,
+						     write, &value);
+			if (!ret && !write)
+				*resp = value;
+			break;
+		case CLOS_STATUS:
+			break;
+		default:
+			break;
+		}
+		return ret;
+	}
+
+	mbox_cmds.cmd_count = 1;
+	mbox_cmds.mbox_cmd[0].logical_cpu = cpu;
+	mbox_cmds.mbox_cmd[0].command = command;
+	mbox_cmds.mbox_cmd[0].sub_command = sub_command;
+	mbox_cmds.mbox_cmd[0].parameter = parameter;
+	mbox_cmds.mbox_cmd[0].req_data = req_data;
+
+	fd = open(pathname, O_RDWR);
+	if (fd < 0)
+		err(-1, "%s open failed", pathname);
+
+	if (ioctl(fd, ISST_IF_MBOX_COMMAND, &mbox_cmds) == -1) {
+		perror("ISST_IF_MBOX_COMMAND");
+		fprintf(outf,
+			"Error: mbox_cmd cpu:%d command:%x sub_command:%x parameter:%x req_data:%x\n",
+			cpu, command, sub_command, parameter, req_data);
+	} else {
+		*resp = mbox_cmds.mbox_cmd[0].resp_data;
+		debug_printf(
+			"mbox_cmd response: cpu:%d command:%x sub_command:%x parameter:%x req_data:%x resp:%x\n",
+			cpu, command, sub_command, parameter, req_data, *resp);
+	}
+
+	close(fd);
+
+	return 0;
+}
+
+int isst_send_msr_command(unsigned int cpu, unsigned int msr, int write,
+			  unsigned long long *req_resp)
+{
+	struct isst_if_msr_cmds msr_cmds;
+	const char *pathname = "/dev/isst_interface";
+	int fd;
+
+	fd = open(pathname, O_RDWR);
+	if (fd < 0)
+		err(-1, "%s open failed", pathname);
+
+	msr_cmds.cmd_count = 1;
+	msr_cmds.msr_cmd[0].logical_cpu = cpu;
+	msr_cmds.msr_cmd[0].msr = msr;
+	msr_cmds.msr_cmd[0].read_write = write;
+	if (write)
+		msr_cmds.msr_cmd[0].data = *req_resp;
+
+	if (ioctl(fd, ISST_IF_MSR_COMMAND, &msr_cmds) == -1) {
+		perror("ISST_IF_MSR_COMMAD");
+		fprintf(outf, "Error: msr_cmd cpu:%d msr:%x read_write:%d\n",
+			cpu, msr, write);
+	} else {
+		if (!write)
+			*req_resp = msr_cmds.msr_cmd[0].data;
+
+		debug_printf(
+			"msr_cmd response: cpu:%d msr:%x rd_write:%x resp:%llx %llx\n",
+			cpu, msr, write, *req_resp, msr_cmds.msr_cmd[0].data);
+	}
+
+	close(fd);
+
+	return 0;
+}
+
+static int isst_fill_platform_info(void)
+{
+	const char *pathname = "/dev/isst_interface";
+	int fd;
+
+	fd = open(pathname, O_RDWR);
+	if (fd < 0)
+		err(-1, "%s open failed", pathname);
+
+	if (ioctl(fd, ISST_IF_GET_PLATFORM_INFO, &isst_platform_info) == -1) {
+		perror("ISST_IF_GET_PLATFORM_INFO");
+		close(fd);
+		return -1;
+	}
+
+	close(fd);
+
+	if (isst_platform_info.api_version > supported_api_ver) {
+		printf("Incompatible API versions; Upgrade of tool is required\n");
+		return -1;
+	}
+	return 0;
+}
+
+static void isst_print_platform_information(void)
+{
+	struct isst_if_platform_info platform_info;
+	const char *pathname = "/dev/isst_interface";
+	int fd;
+
+	fd = open(pathname, O_RDWR);
+	if (fd < 0)
+		err(-1, "%s open failed", pathname);
+
+	if (ioctl(fd, ISST_IF_GET_PLATFORM_INFO, &platform_info) == -1) {
+		perror("ISST_IF_GET_PLATFORM_INFO");
+	} else {
+		fprintf(outf, "Platform: API version : %d\n",
+			platform_info.api_version);
+		fprintf(outf, "Platform: Driver version : %d\n",
+			platform_info.driver_version);
+		fprintf(outf, "Platform: mbox supported : %d\n",
+			platform_info.mbox_supported);
+		fprintf(outf, "Platform: mmio supported : %d\n",
+			platform_info.mmio_supported);
+	}
+
+	close(fd);
+
+	exit(0);
+}
+
+static void exec_on_get_ctdp_cpu(int cpu, void *arg1, void *arg2, void *arg3,
+				 void *arg4)
+{
+	int (*fn_ptr)(int cpu, void *arg);
+	int ret;
+
+	fn_ptr = arg1;
+	ret = fn_ptr(cpu, arg2);
+	if (ret)
+		perror("get_tdp_*");
+	else
+		isst_ctdp_display_core_info(cpu, outf, arg3,
+					    *(unsigned int *)arg4);
+}
+
+#define _get_tdp_level(desc, suffix, object, help)                                \
+	static void get_tdp_##object(void)                                        \
+	{                                                                         \
+		struct isst_pkg_ctdp ctdp;                                        \
+\
+		if (cmd_help) {                                                   \
+			fprintf(stderr,                                           \
+				"Print %s [No command arguments are required]\n", \
+				help);                                            \
+			exit(0);                                                  \
+		}                                                                 \
+		isst_ctdp_display_information_start(outf);                        \
+		if (max_target_cpus)                                              \
+			for_each_online_target_cpu_in_set(                        \
+				exec_on_get_ctdp_cpu, isst_get_ctdp_##suffix,     \
+				&ctdp, desc, &ctdp.object);                       \
+		else                                                              \
+			for_each_online_package_in_set(exec_on_get_ctdp_cpu,      \
+						       isst_get_ctdp_##suffix,    \
+						       &ctdp, desc,               \
+						       &ctdp.object);             \
+		isst_ctdp_display_information_end(outf);                          \
+	}
+
+_get_tdp_level("get-config-levels", levels, levels, "TDP levels");
+_get_tdp_level("get-config-version", levels, version, "TDP version");
+_get_tdp_level("get-config-enabled", levels, enabled, "TDP enable status");
+_get_tdp_level("get-config-current_level", levels, current_level,
+	       "Current TDP Level");
+_get_tdp_level("get-lock-status", levels, locked, "TDP lock status");
+
+static void dump_isst_config_for_cpu(int cpu, void *arg1, void *arg2,
+				     void *arg3, void *arg4)
+{
+	struct isst_pkg_ctdp pkg_dev;
+	int ret;
+
+	memset(&pkg_dev, 0, sizeof(pkg_dev));
+	ret = isst_get_process_ctdp(cpu, tdp_level, &pkg_dev);
+	if (ret) {
+		perror("isst_get_process_ctdp");
+	} else {
+		isst_ctdp_display_information(cpu, outf, tdp_level, &pkg_dev);
+		isst_get_process_ctdp_complete(cpu, &pkg_dev);
+	}
+}
+
+static void dump_isst_config(void)
+{
+	if (cmd_help) {
+		fprintf(stderr,
+			"Print Intel(R) Speed Select Technology Performance profile configuration\n");
+		fprintf(stderr,
+			"including base frequency and turbo frequency configurations\n");
+		fprintf(stderr, "Optional: -l|--level : Specify tdp level\n");
+		fprintf(stderr,
+			"\tIf no arguments, dump information for all TDP levels\n");
+		exit(0);
+	}
+
+	isst_ctdp_display_information_start(outf);
+
+	if (max_target_cpus)
+		for_each_online_target_cpu_in_set(dump_isst_config_for_cpu,
+						  NULL, NULL, NULL, NULL);
+	else
+		for_each_online_package_in_set(dump_isst_config_for_cpu, NULL,
+					       NULL, NULL, NULL);
+
+	isst_ctdp_display_information_end(outf);
+}
+
+static void set_tdp_level_for_cpu(int cpu, void *arg1, void *arg2, void *arg3,
+				  void *arg4)
+{
+	int ret;
+
+	ret = isst_set_tdp_level(cpu, tdp_level);
+	if (ret)
+		perror("set_tdp_level_for_cpu");
+	else {
+		isst_display_result(cpu, outf, "perf-profile", "set_tdp_level",
+				    ret);
+		if (force_online_offline) {
+			struct isst_pkg_ctdp_level_info ctdp_level;
+			int pkg_id = get_physical_package_id(cpu);
+			int die_id = get_physical_die_id(cpu);
+
+			fprintf(stderr, "Option is set to online/offline\n");
+			ctdp_level.core_cpumask_size =
+				alloc_cpu_set(&ctdp_level.core_cpumask);
+			isst_get_coremask_info(cpu, tdp_level, &ctdp_level);
+			if (ctdp_level.cpu_count) {
+				int i, max_cpus = get_topo_max_cpus();
+				for (i = 0; i < max_cpus; ++i) {
+					if (pkg_id != get_physical_package_id(i) || die_id != get_physical_die_id(i))
+						continue;
+					if (CPU_ISSET_S(i, ctdp_level.core_cpumask_size, ctdp_level.core_cpumask)) {
+						fprintf(stderr, "online cpu %d\n", i);
+						set_cpu_online_offline(i, 1);
+					} else {
+						fprintf(stderr, "offline cpu %d\n", i);
+						set_cpu_online_offline(i, 0);
+					}
+				}
+			}
+		}
+	}
+}
+
+static void set_tdp_level(void)
+{
+	if (cmd_help) {
+		fprintf(stderr, "Set Config TDP level\n");
+		fprintf(stderr,
+			"\t Arguments: -l|--level : Specify tdp level\n");
+		fprintf(stderr,
+			"\t Optional Arguments: -o | online : online/offline for the tdp level\n");
+		exit(0);
+	}
+
+	if (tdp_level == 0xff) {
+		fprintf(outf, "Invalid command: specify tdp_level\n");
+		exit(1);
+	}
+	isst_ctdp_display_information_start(outf);
+	if (max_target_cpus)
+		for_each_online_target_cpu_in_set(set_tdp_level_for_cpu, NULL,
+						  NULL, NULL, NULL);
+	else
+		for_each_online_package_in_set(set_tdp_level_for_cpu, NULL,
+					       NULL, NULL, NULL);
+	isst_ctdp_display_information_end(outf);
+}
+
+static void dump_pbf_config_for_cpu(int cpu, void *arg1, void *arg2, void *arg3,
+				    void *arg4)
+{
+	struct isst_pbf_info pbf_info;
+	int ret;
+
+	ret = isst_get_pbf_info(cpu, tdp_level, &pbf_info);
+	if (ret) {
+		perror("isst_get_pbf_info");
+	} else {
+		isst_pbf_display_information(cpu, outf, tdp_level, &pbf_info);
+		isst_get_pbf_info_complete(&pbf_info);
+	}
+}
+
+static void dump_pbf_config(void)
+{
+	if (cmd_help) {
+		fprintf(stderr,
+			"Print Intel(R) Speed Select Technology base frequency configuration for a TDP level\n");
+		fprintf(stderr,
+			"\tArguments: -l|--level : Specify tdp level\n");
+		exit(0);
+	}
+
+	if (tdp_level == 0xff) {
+		fprintf(outf, "Invalid command: specify tdp_level\n");
+		exit(1);
+	}
+
+	isst_ctdp_display_information_start(outf);
+	if (max_target_cpus)
+		for_each_online_target_cpu_in_set(dump_pbf_config_for_cpu, NULL,
+						  NULL, NULL, NULL);
+	else
+		for_each_online_package_in_set(dump_pbf_config_for_cpu, NULL,
+					       NULL, NULL, NULL);
+	isst_ctdp_display_information_end(outf);
+}
+
+static void set_pbf_for_cpu(int cpu, void *arg1, void *arg2, void *arg3,
+			    void *arg4)
+{
+	int ret;
+	int status = *(int *)arg4;
+
+	ret = isst_set_pbf_fact_status(cpu, 1, status);
+	if (ret) {
+		perror("isst_set_pbf");
+	} else {
+		if (status)
+			isst_display_result(cpu, outf, "base-freq", "enable",
+					    ret);
+		else
+			isst_display_result(cpu, outf, "base-freq", "disable",
+					    ret);
+	}
+}
+
+static void set_pbf_enable(void)
+{
+	int status = 1;
+
+	if (cmd_help) {
+		fprintf(stderr,
+			"Enable Intel Speed Select Technology base frequency feature [No command arguments are required]\n");
+		exit(0);
+	}
+
+	isst_ctdp_display_information_start(outf);
+	if (max_target_cpus)
+		for_each_online_target_cpu_in_set(set_pbf_for_cpu, NULL, NULL,
+						  NULL, &status);
+	else
+		for_each_online_package_in_set(set_pbf_for_cpu, NULL, NULL,
+					       NULL, &status);
+	isst_ctdp_display_information_end(outf);
+}
+
+static void set_pbf_disable(void)
+{
+	int status = 0;
+
+	if (cmd_help) {
+		fprintf(stderr,
+			"Disable Intel Speed Select Technology base frequency feature [No command arguments are required]\n");
+		exit(0);
+	}
+
+	isst_ctdp_display_information_start(outf);
+	if (max_target_cpus)
+		for_each_online_target_cpu_in_set(set_pbf_for_cpu, NULL, NULL,
+						  NULL, &status);
+	else
+		for_each_online_package_in_set(set_pbf_for_cpu, NULL, NULL,
+					       NULL, &status);
+	isst_ctdp_display_information_end(outf);
+}
+
+static void dump_fact_config_for_cpu(int cpu, void *arg1, void *arg2,
+				     void *arg3, void *arg4)
+{
+	struct isst_fact_info fact_info;
+	int ret;
+
+	ret = isst_get_fact_info(cpu, tdp_level, &fact_info);
+	if (ret)
+		perror("isst_get_fact_bucket_info");
+	else
+		isst_fact_display_information(cpu, outf, tdp_level, fact_bucket,
+					      fact_avx, &fact_info);
+}
+
+static void dump_fact_config(void)
+{
+	if (cmd_help) {
+		fprintf(stderr,
+			"Print complete Intel Speed Select Technology turbo frequency configuration for a TDP level. Other arguments are optional.\n");
+		fprintf(stderr,
+			"\tArguments: -l|--level : Specify tdp level\n");
+		fprintf(stderr,
+			"\tArguments: -b|--bucket : Bucket index to dump\n");
+		fprintf(stderr,
+			"\tArguments: -r|--trl-type : Specify trl type: sse|avx2|avx512\n");
+		exit(0);
+	}
+
+	if (tdp_level == 0xff) {
+		fprintf(outf, "Invalid command: specify tdp_level\n");
+		exit(1);
+	}
+
+	isst_ctdp_display_information_start(outf);
+	if (max_target_cpus)
+		for_each_online_target_cpu_in_set(dump_fact_config_for_cpu,
+						  NULL, NULL, NULL, NULL);
+	else
+		for_each_online_package_in_set(dump_fact_config_for_cpu, NULL,
+					       NULL, NULL, NULL);
+	isst_ctdp_display_information_end(outf);
+}
+
+static void set_fact_for_cpu(int cpu, void *arg1, void *arg2, void *arg3,
+			     void *arg4)
+{
+	int ret;
+	int status = *(int *)arg4;
+
+	ret = isst_set_pbf_fact_status(cpu, 0, status);
+	if (ret)
+		perror("isst_set_fact");
+	else {
+		if (status) {
+			struct isst_pkg_ctdp pkg_dev;
+
+			ret = isst_get_ctdp_levels(cpu, &pkg_dev);
+			if (ret) {
+				isst_display_result(cpu, outf, "turbo-freq",
+						    "enable", ret);
+				return;
+			}
+			ret = isst_set_trl(cpu, fact_trl);
+			isst_display_result(cpu, outf, "turbo-freq", "enable",
+					    ret);
+		} else {
+			/* Since we modified TRL during Fact enable, restore it */
+			isst_set_trl_from_current_tdp(cpu, fact_trl);
+			isst_display_result(cpu, outf, "turbo-freq", "disable",
+					    ret);
+		}
+	}
+}
+
+static void set_fact_enable(void)
+{
+	int status = 1;
+
+	if (cmd_help) {
+		fprintf(stderr,
+			"Enable Intel Speed Select Technology Turbo frequency feature\n");
+		fprintf(stderr,
+			"Optional: -t|--trl : Specify turbo ratio limit\n");
+		exit(0);
+	}
+
+	isst_ctdp_display_information_start(outf);
+	if (max_target_cpus)
+		for_each_online_target_cpu_in_set(set_fact_for_cpu, NULL, NULL,
+						  NULL, &status);
+	else
+		for_each_online_package_in_set(set_fact_for_cpu, NULL, NULL,
+					       NULL, &status);
+	isst_ctdp_display_information_end(outf);
+}
+
+static void set_fact_disable(void)
+{
+	int status = 0;
+
+	if (cmd_help) {
+		fprintf(stderr,
+			"Disable Intel Speed Select Technology turbo frequency feature\n");
+		fprintf(stderr,
+			"Optional: -t|--trl : Specify turbo ratio limit\n");
+		exit(0);
+	}
+
+	isst_ctdp_display_information_start(outf);
+	if (max_target_cpus)
+		for_each_online_target_cpu_in_set(set_fact_for_cpu, NULL, NULL,
+						  NULL, &status);
+	else
+		for_each_online_package_in_set(set_fact_for_cpu, NULL, NULL,
+					       NULL, &status);
+	isst_ctdp_display_information_end(outf);
+}
+
+static void enable_clos_qos_config(int cpu, void *arg1, void *arg2, void *arg3,
+				   void *arg4)
+{
+	int ret;
+	int status = *(int *)arg4;
+
+	ret = isst_pm_qos_config(cpu, status, clos_priority_type);
+	if (ret) {
+		perror("isst_pm_qos_config");
+	} else {
+		if (status)
+			isst_display_result(cpu, outf, "core-power", "enable",
+					    ret);
+		else
+			isst_display_result(cpu, outf, "core-power", "disable",
+					    ret);
+	}
+}
+
+static void set_clos_enable(void)
+{
+	int status = 1;
+
+	if (cmd_help) {
+		fprintf(stderr, "Enable core-power for a package/die\n");
+		fprintf(stderr,
+			"\tClos Enable: Specify priority type with [--priority|-p]\n");
+		fprintf(stderr, "\t\t 0: Proportional, 1: Ordered\n");
+		exit(0);
+	}
+
+	if (cpufreq_sysfs_present()) {
+		fprintf(stderr,
+			"cpufreq subsystem and core-power enable will interfere with each other!\n");
+	}
+
+	isst_ctdp_display_information_start(outf);
+	if (max_target_cpus)
+		for_each_online_target_cpu_in_set(enable_clos_qos_config, NULL,
+						  NULL, NULL, &status);
+	else
+		for_each_online_package_in_set(enable_clos_qos_config, NULL,
+					       NULL, NULL, &status);
+	isst_ctdp_display_information_end(outf);
+}
+
+static void set_clos_disable(void)
+{
+	int status = 0;
+
+	if (cmd_help) {
+		fprintf(stderr,
+			"Disable core-power: [No command arguments are required]\n");
+		exit(0);
+	}
+
+	isst_ctdp_display_information_start(outf);
+	if (max_target_cpus)
+		for_each_online_target_cpu_in_set(enable_clos_qos_config, NULL,
+						  NULL, NULL, &status);
+	else
+		for_each_online_package_in_set(enable_clos_qos_config, NULL,
+					       NULL, NULL, &status);
+	isst_ctdp_display_information_end(outf);
+}
+
+static void dump_clos_config_for_cpu(int cpu, void *arg1, void *arg2,
+				     void *arg3, void *arg4)
+{
+	struct isst_clos_config clos_config;
+	int ret;
+
+	ret = isst_pm_get_clos(cpu, current_clos, &clos_config);
+	if (ret)
+		perror("isst_pm_get_clos");
+	else
+		isst_clos_display_information(cpu, outf, current_clos,
+					      &clos_config);
+}
+
+static void dump_clos_config(void)
+{
+	if (cmd_help) {
+		fprintf(stderr,
+			"Print Intel Speed Select Technology core power configuration\n");
+		fprintf(stderr,
+			"\tArguments: [-c | --clos]: Specify clos id\n");
+		exit(0);
+	}
+	if (current_clos < 0 || current_clos > 3) {
+		fprintf(stderr, "Invalid clos id\n");
+		exit(0);
+	}
+
+	isst_ctdp_display_information_start(outf);
+	if (max_target_cpus)
+		for_each_online_target_cpu_in_set(dump_clos_config_for_cpu,
+						  NULL, NULL, NULL, NULL);
+	else
+		for_each_online_package_in_set(dump_clos_config_for_cpu, NULL,
+					       NULL, NULL, NULL);
+	isst_ctdp_display_information_end(outf);
+}
+
+static void get_clos_info_for_cpu(int cpu, void *arg1, void *arg2, void *arg3,
+				  void *arg4)
+{
+	int enable, ret, prio_type;
+
+	ret = isst_clos_get_clos_information(cpu, &enable, &prio_type);
+	if (ret)
+		perror("isst_clos_get_info");
+	else
+		isst_clos_display_clos_information(cpu, outf, enable, prio_type);
+}
+
+static void dump_clos_info(void)
+{
+	if (cmd_help) {
+		fprintf(stderr,
+			"Print Intel Speed Select Technology core power information\n");
+		fprintf(stderr, "\tSpecify targeted cpu id with [--cpu|-c]\n");
+		exit(0);
+	}
+
+	if (!max_target_cpus) {
+		fprintf(stderr,
+			"Invalid target cpu. Specify with [-c|--cpu]\n");
+		exit(0);
+	}
+
+	isst_ctdp_display_information_start(outf);
+	for_each_online_target_cpu_in_set(get_clos_info_for_cpu, NULL,
+					  NULL, NULL, NULL);
+	isst_ctdp_display_information_end(outf);
+
+}
+
+static void set_clos_config_for_cpu(int cpu, void *arg1, void *arg2, void *arg3,
+				    void *arg4)
+{
+	struct isst_clos_config clos_config;
+	int ret;
+
+	clos_config.pkg_id = get_physical_package_id(cpu);
+	clos_config.die_id = get_physical_die_id(cpu);
+
+	clos_config.epp = clos_epp;
+	clos_config.clos_prop_prio = clos_prop_prio;
+	clos_config.clos_min = clos_min;
+	clos_config.clos_max = clos_max;
+	clos_config.clos_desired = clos_desired;
+	ret = isst_set_clos(cpu, current_clos, &clos_config);
+	if (ret)
+		perror("isst_set_clos");
+	else
+		isst_display_result(cpu, outf, "core-power", "config", ret);
+}
+
+static void set_clos_config(void)
+{
+	if (cmd_help) {
+		fprintf(stderr,
+			"Set core-power configuration for one of the four clos ids\n");
+		fprintf(stderr,
+			"\tSpecify targeted clos id with [--clos|-c]\n");
+		fprintf(stderr, "\tSpecify clos EPP with [--epp|-e]\n");
+		fprintf(stderr,
+			"\tSpecify clos Proportional Priority [--weight|-w]\n");
+		fprintf(stderr, "\tSpecify clos min with [--min|-n]\n");
+		fprintf(stderr, "\tSpecify clos max with [--max|-m]\n");
+		fprintf(stderr, "\tSpecify clos desired with [--desired|-d]\n");
+		exit(0);
+	}
+
+	if (current_clos < 0 || current_clos > 3) {
+		fprintf(stderr, "Invalid clos id\n");
+		exit(0);
+	}
+	if (clos_epp < 0 || clos_epp > 0x0F) {
+		fprintf(stderr, "clos epp is not specified, default: 0\n");
+		clos_epp = 0;
+	}
+	if (clos_prop_prio < 0 || clos_prop_prio > 0x0F) {
+		fprintf(stderr,
+			"clos frequency weight is not specified, default: 0\n");
+		clos_prop_prio = 0;
+	}
+	if (clos_min < 0) {
+		fprintf(stderr, "clos min is not specified, default: 0\n");
+		clos_min = 0;
+	}
+	if (clos_max < 0) {
+		fprintf(stderr, "clos max is not specified, default: 0xff\n");
+		clos_max = 0xff;
+	}
+	if (clos_desired < 0) {
+		fprintf(stderr, "clos desired is not specified, default: 0\n");
+		clos_desired = 0x00;
+	}
+
+	isst_ctdp_display_information_start(outf);
+	if (max_target_cpus)
+		for_each_online_target_cpu_in_set(set_clos_config_for_cpu, NULL,
+						  NULL, NULL, NULL);
+	else
+		for_each_online_package_in_set(set_clos_config_for_cpu, NULL,
+					       NULL, NULL, NULL);
+	isst_ctdp_display_information_end(outf);
+}
+
+static void set_clos_assoc_for_cpu(int cpu, void *arg1, void *arg2, void *arg3,
+				   void *arg4)
+{
+	int ret;
+
+	ret = isst_clos_associate(cpu, current_clos);
+	if (ret)
+		perror("isst_clos_associate");
+	else
+		isst_display_result(cpu, outf, "core-power", "assoc", ret);
+}
+
+static void set_clos_assoc(void)
+{
+	if (cmd_help) {
+		fprintf(stderr, "Associate a clos id to a CPU\n");
+		fprintf(stderr,
+			"\tSpecify targeted clos id with [--clos|-c]\n");
+		exit(0);
+	}
+
+	if (current_clos < 0 || current_clos > 3) {
+		fprintf(stderr, "Invalid clos id\n");
+		exit(0);
+	}
+	if (max_target_cpus)
+		for_each_online_target_cpu_in_set(set_clos_assoc_for_cpu, NULL,
+						  NULL, NULL, NULL);
+	else {
+		fprintf(stderr,
+			"Invalid target cpu. Specify with [-c|--cpu]\n");
+	}
+}
+
+static void get_clos_assoc_for_cpu(int cpu, void *arg1, void *arg2, void *arg3,
+				   void *arg4)
+{
+	int clos, ret;
+
+	ret = isst_clos_get_assoc_status(cpu, &clos);
+	if (ret)
+		perror("isst_clos_get_assoc_status");
+	else
+		isst_clos_display_assoc_information(cpu, outf, clos);
+}
+
+static void get_clos_assoc(void)
+{
+	if (cmd_help) {
+		fprintf(stderr, "Get associate clos id to a CPU\n");
+		fprintf(stderr, "\tSpecify targeted cpu id with [--cpu|-c]\n");
+		exit(0);
+	}
+
+	if (!max_target_cpus) {
+		fprintf(stderr,
+			"Invalid target cpu. Specify with [-c|--cpu]\n");
+		exit(0);
+	}
+
+	isst_ctdp_display_information_start(outf);
+	for_each_online_target_cpu_in_set(get_clos_assoc_for_cpu, NULL,
+					  NULL, NULL, NULL);
+	isst_ctdp_display_information_end(outf);
+}
+
+static struct process_cmd_struct isst_cmds[] = {
+	{ "perf-profile", "get-lock-status", get_tdp_locked },
+	{ "perf-profile", "get-config-levels", get_tdp_levels },
+	{ "perf-profile", "get-config-version", get_tdp_version },
+	{ "perf-profile", "get-config-enabled", get_tdp_enabled },
+	{ "perf-profile", "get-config-current-level", get_tdp_current_level },
+	{ "perf-profile", "set-config-level", set_tdp_level },
+	{ "perf-profile", "info", dump_isst_config },
+	{ "base-freq", "info", dump_pbf_config },
+	{ "base-freq", "enable", set_pbf_enable },
+	{ "base-freq", "disable", set_pbf_disable },
+	{ "turbo-freq", "info", dump_fact_config },
+	{ "turbo-freq", "enable", set_fact_enable },
+	{ "turbo-freq", "disable", set_fact_disable },
+	{ "core-power", "info", dump_clos_info },
+	{ "core-power", "enable", set_clos_enable },
+	{ "core-power", "disable", set_clos_disable },
+	{ "core-power", "config", set_clos_config },
+	{ "core-power", "get-config", dump_clos_config },
+	{ "core-power", "assoc", set_clos_assoc },
+	{ "core-power", "get-assoc", get_clos_assoc },
+	{ NULL, NULL, NULL }
+};
+
+/*
+ * parse cpuset with following syntax
+ * 1,2,4..6,8-10 and set bits in cpu_subset
+ */
+void parse_cpu_command(char *optarg)
+{
+	unsigned int start, end;
+	char *next;
+
+	next = optarg;
+
+	while (next && *next) {
+		if (*next == '-') /* no negative cpu numbers */
+			goto error;
+
+		start = strtoul(next, &next, 10);
+
+		if (max_target_cpus < MAX_CPUS_IN_ONE_REQ)
+			target_cpus[max_target_cpus++] = start;
+
+		if (*next == '\0')
+			break;
+
+		if (*next == ',') {
+			next += 1;
+			continue;
+		}
+
+		if (*next == '-') {
+			next += 1; /* start range */
+		} else if (*next == '.') {
+			next += 1;
+			if (*next == '.')
+				next += 1; /* start range */
+			else
+				goto error;
+		}
+
+		end = strtoul(next, &next, 10);
+		if (end <= start)
+			goto error;
+
+		while (++start <= end) {
+			if (max_target_cpus < MAX_CPUS_IN_ONE_REQ)
+				target_cpus[max_target_cpus++] = start;
+		}
+
+		if (*next == ',')
+			next += 1;
+		else if (*next != '\0')
+			goto error;
+	}
+
+#ifdef DEBUG
+	{
+		int i;
+
+		for (i = 0; i < max_target_cpus; ++i)
+			printf("cpu [%d] in arg\n", target_cpus[i]);
+	}
+#endif
+	return;
+
+error:
+	fprintf(stderr, "\"--cpu %s\" malformed\n", optarg);
+	exit(-1);
+}
+
+static void parse_cmd_args(int argc, int start, char **argv)
+{
+	int opt;
+	int option_index;
+
+	static struct option long_options[] = {
+		{ "bucket", required_argument, 0, 'b' },
+		{ "level", required_argument, 0, 'l' },
+		{ "online", required_argument, 0, 'o' },
+		{ "trl-type", required_argument, 0, 'r' },
+		{ "trl", required_argument, 0, 't' },
+		{ "help", no_argument, 0, 'h' },
+		{ "clos", required_argument, 0, 'c' },
+		{ "desired", required_argument, 0, 'd' },
+		{ "epp", required_argument, 0, 'e' },
+		{ "min", required_argument, 0, 'n' },
+		{ "max", required_argument, 0, 'm' },
+		{ "priority", required_argument, 0, 'p' },
+		{ "weight", required_argument, 0, 'w' },
+		{ 0, 0, 0, 0 }
+	};
+
+	option_index = start;
+
+	optind = start + 1;
+	while ((opt = getopt_long(argc, argv, "b:l:t:c:d:e:n:m:p:w:ho",
+				  long_options, &option_index)) != -1) {
+		switch (opt) {
+		case 'b':
+			fact_bucket = atoi(optarg);
+			break;
+		case 'h':
+			cmd_help = 1;
+			break;
+		case 'l':
+			tdp_level = atoi(optarg);
+			break;
+		case 'o':
+			force_online_offline = 1;
+			break;
+		case 't':
+			sscanf(optarg, "0x%llx", &fact_trl);
+			break;
+		case 'r':
+			if (!strncmp(optarg, "sse", 3)) {
+				fact_avx = 0x01;
+			} else if (!strncmp(optarg, "avx2", 4)) {
+				fact_avx = 0x02;
+			} else if (!strncmp(optarg, "avx512", 4)) {
+				fact_avx = 0x04;
+			} else {
+				fprintf(outf, "Invalid sse,avx options\n");
+				exit(1);
+			}
+			break;
+		/* CLOS related */
+		case 'c':
+			current_clos = atoi(optarg);
+			break;
+		case 'd':
+			clos_desired = atoi(optarg);
+			break;
+		case 'e':
+			clos_epp = atoi(optarg);
+			break;
+		case 'n':
+			clos_min = atoi(optarg);
+			break;
+		case 'm':
+			clos_max = atoi(optarg);
+			break;
+		case 'p':
+			clos_priority_type = atoi(optarg);
+			break;
+		case 'w':
+			clos_prop_prio = atoi(optarg);
+			break;
+		default:
+			printf("no match\n");
+		}
+	}
+}
+
+static void isst_help(void)
+{
+	printf("perf-profile:\tAn architectural mechanism that allows multiple optimized \n\
+		performance profiles per system via static and/or dynamic\n\
+		adjustment of core count, workload, Tjmax, and\n\
+		TDP, etc.\n");
+	printf("\nCommands : For feature=perf-profile\n");
+	printf("\tinfo\n");
+	printf("\tget-lock-status\n");
+	printf("\tget-config-levels\n");
+	printf("\tget-config-version\n");
+	printf("\tget-config-enabled\n");
+	printf("\tget-config-current-level\n");
+	printf("\tset-config-level\n");
+}
+
+static void pbf_help(void)
+{
+	printf("base-freq:\tEnables users to increase guaranteed base frequency\n\
+		on certain cores (high priority cores) in exchange for lower\n\
+		base frequency on remaining cores (low priority cores).\n");
+	printf("\tcommand : info\n");
+	printf("\tcommand : enable\n");
+	printf("\tcommand : disable\n");
+}
+
+static void fact_help(void)
+{
+	printf("turbo-freq:\tEnables the ability to set different turbo ratio\n\
+		limits to cores based on priority.\n");
+	printf("\nCommand: For feature=turbo-freq\n");
+	printf("\tcommand : info\n");
+	printf("\tcommand : enable\n");
+	printf("\tcommand : disable\n");
+}
+
+static void core_power_help(void)
+{
+	printf("core-power:\tInterface that allows user to define per core/tile\n\
+		priority.\n");
+	printf("\nCommands : For feature=core-power\n");
+	printf("\tinfo\n");
+	printf("\tenable\n");
+	printf("\tdisable\n");
+	printf("\tconfig\n");
+	printf("\tget-config\n");
+	printf("\tassoc\n");
+	printf("\tget-assoc\n");
+}
+
+struct process_cmd_help_struct {
+	char *feature;
+	void (*process_fn)(void);
+};
+
+static struct process_cmd_help_struct isst_help_cmds[] = {
+	{ "perf-profile", isst_help },
+	{ "base-freq", pbf_help },
+	{ "turbo-freq", fact_help },
+	{ "core-power", core_power_help },
+	{ NULL, NULL }
+};
+
+void process_command(int argc, char **argv)
+{
+	int i = 0, matched = 0;
+	char *feature = argv[optind];
+	char *cmd = argv[optind + 1];
+
+	if (!feature || !cmd)
+		return;
+
+	debug_printf("feature name [%s] command [%s]\n", feature, cmd);
+	if (!strcmp(cmd, "-h") || !strcmp(cmd, "--help")) {
+		while (isst_help_cmds[i].feature) {
+			if (!strcmp(isst_help_cmds[i].feature, feature)) {
+				isst_help_cmds[i].process_fn();
+				exit(0);
+			}
+			++i;
+		}
+	}
+
+	create_cpu_map();
+
+	i = 0;
+	while (isst_cmds[i].feature) {
+		if (!strcmp(isst_cmds[i].feature, feature) &&
+		    !strcmp(isst_cmds[i].command, cmd)) {
+			parse_cmd_args(argc, optind + 1, argv);
+			isst_cmds[i].process_fn();
+			matched = 1;
+			break;
+		}
+		++i;
+	}
+
+	if (!matched)
+		fprintf(stderr, "Invalid command\n");
+}
+
+static void usage(void)
+{
+	printf("Intel(R) Speed Select Technology\n");
+	printf("\nUsage:\n");
+	printf("intel-speed-select [OPTIONS] FEATURE COMMAND COMMAND_ARGUMENTS\n");
+	printf("\nUse this tool to enumerate and control the Intel Speed Select Technology features,\n");
+	printf("\nFEATURE : [perf-profile|base-freq|turbo-freq|core-power]\n");
+	printf("\nFor help on each feature, use -h|--help\n");
+	printf("\tFor example:  intel-speed-select perf-profile -h\n");
+
+	printf("\nFor additional help on each command for a feature, use --h|--help\n");
+	printf("\tFor example:  intel-speed-select perf-profile get-lock-status -h\n");
+	printf("\t\t This will print help for the command \"get-lock-status\" for the feature \"perf-profile\"\n");
+
+	printf("\nOPTIONS\n");
+	printf("\t[-c|--cpu] : logical cpu number\n");
+	printf("\t\tDefault: Die scoped for all dies in the system with multiple dies/package\n");
+	printf("\t\t\t Or Package scoped for all Packages when each package contains one die\n");
+	printf("\t[-d|--debug] : Debug mode\n");
+	printf("\t[-h|--help] : Print help\n");
+	printf("\t[-i|--info] : Print platform information\n");
+	printf("\t[-o|--out] : Output file\n");
+	printf("\t\t\tDefault : stderr\n");
+	printf("\t[-f|--format] : output format [json|text]. Default: text\n");
+	printf("\t[-v|--version] : Print version\n");
+
+	printf("\nResult format\n");
+	printf("\tResult display uses a common format for each command:\n");
+	printf("\tResults are formatted in text/JSON with\n");
+	printf("\t\tPackage, Die, CPU, and command specific results.\n");
+	exit(1);
+}
+
+static void print_version(void)
+{
+	fprintf(outf, "Version %s\n", version_str);
+	fprintf(outf, "Build date %s time %s\n", __DATE__, __TIME__);
+	exit(0);
+}
+
+static void cmdline(int argc, char **argv)
+{
+	int opt;
+	int option_index = 0;
+	int ret;
+
+	static struct option long_options[] = {
+		{ "cpu", required_argument, 0, 'c' },
+		{ "debug", no_argument, 0, 'd' },
+		{ "format", required_argument, 0, 'f' },
+		{ "help", no_argument, 0, 'h' },
+		{ "info", no_argument, 0, 'i' },
+		{ "out", required_argument, 0, 'o' },
+		{ "version", no_argument, 0, 'v' },
+		{ 0, 0, 0, 0 }
+	};
+
+	progname = argv[0];
+	while ((opt = getopt_long_only(argc, argv, "+c:df:hio:v", long_options,
+				       &option_index)) != -1) {
+		switch (opt) {
+		case 'c':
+			parse_cpu_command(optarg);
+			break;
+		case 'd':
+			debug_flag = 1;
+			printf("Debug Mode ON\n");
+			break;
+		case 'f':
+			if (!strncmp(optarg, "json", 4))
+				out_format_json = 1;
+			break;
+		case 'h':
+			usage();
+			break;
+		case 'i':
+			isst_print_platform_information();
+			break;
+		case 'o':
+			if (outf)
+				fclose(outf);
+			outf = fopen_or_exit(optarg, "w");
+			break;
+		case 'v':
+			print_version();
+			break;
+		default:
+			usage();
+		}
+	}
+
+	if (geteuid() != 0) {
+		fprintf(stderr, "Must run as root\n");
+		exit(0);
+	}
+
+	if (optind > (argc - 2)) {
+		fprintf(stderr, "Feature name and|or command not specified\n");
+		exit(0);
+	}
+	update_cpu_model();
+	printf("Intel(R) Speed Select Technology\n");
+	printf("Executing on CPU model:%d[0x%x]\n", cpu_model, cpu_model);
+	set_max_cpu_num();
+	set_cpu_present_cpu_mask();
+	set_cpu_target_cpu_mask();
+	ret = isst_fill_platform_info();
+	if (ret)
+		goto out;
+
+	process_command(argc, argv);
+out:
+	free_cpu_set(present_cpumask);
+	free_cpu_set(target_cpumask);
+}
+
+int main(int argc, char **argv)
+{
+	outf = stderr;
+	cmdline(argc, argv);
+	return 0;
+}
diff --git a/tools/power/x86/intel-speed-select/isst-core.c b/tools/power/x86/intel-speed-select/isst-core.c
new file mode 100644
index 0000000..6dee533
--- /dev/null
+++ b/tools/power/x86/intel-speed-select/isst-core.c
@@ -0,0 +1,768 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Intel Speed Select -- Enumerate and control features
+ * Copyright (c) 2019 Intel Corporation.
+ */
+
+#include "isst.h"
+
+int isst_get_ctdp_levels(int cpu, struct isst_pkg_ctdp *pkg_dev)
+{
+	unsigned int resp;
+	int ret;
+
+	ret = isst_send_mbox_command(cpu, CONFIG_TDP,
+				     CONFIG_TDP_GET_LEVELS_INFO, 0, 0, &resp);
+	if (ret)
+		return ret;
+
+	debug_printf("cpu:%d CONFIG_TDP_GET_LEVELS_INFO resp:%x\n", cpu, resp);
+
+	pkg_dev->version = resp & 0xff;
+	pkg_dev->levels = (resp >> 8) & 0xff;
+	pkg_dev->current_level = (resp >> 16) & 0xff;
+	pkg_dev->locked = !!(resp & BIT(24));
+	pkg_dev->enabled = !!(resp & BIT(31));
+
+	return 0;
+}
+
+int isst_get_ctdp_control(int cpu, int config_index,
+			  struct isst_pkg_ctdp_level_info *ctdp_level)
+{
+	unsigned int resp;
+	int ret;
+
+	ret = isst_send_mbox_command(cpu, CONFIG_TDP,
+				     CONFIG_TDP_GET_TDP_CONTROL, 0,
+				     config_index, &resp);
+	if (ret)
+		return ret;
+
+	ctdp_level->fact_support = resp & BIT(0);
+	ctdp_level->pbf_support = !!(resp & BIT(1));
+	ctdp_level->fact_enabled = !!(resp & BIT(16));
+	ctdp_level->pbf_enabled = !!(resp & BIT(17));
+
+	debug_printf(
+		"cpu:%d CONFIG_TDP_GET_TDP_CONTROL resp:%x fact_support:%d pbf_support: %d fact_enabled:%d pbf_enabled:%d\n",
+		cpu, resp, ctdp_level->fact_support, ctdp_level->pbf_support,
+		ctdp_level->fact_enabled, ctdp_level->pbf_enabled);
+
+	return 0;
+}
+
+int isst_get_tdp_info(int cpu, int config_index,
+		      struct isst_pkg_ctdp_level_info *ctdp_level)
+{
+	unsigned int resp;
+	int ret;
+
+	ret = isst_send_mbox_command(cpu, CONFIG_TDP, CONFIG_TDP_GET_TDP_INFO,
+				     0, config_index, &resp);
+	if (ret)
+		return ret;
+
+	ctdp_level->pkg_tdp = resp & GENMASK(14, 0);
+	ctdp_level->tdp_ratio = (resp & GENMASK(23, 16)) >> 16;
+
+	debug_printf(
+		"cpu:%d ctdp:%d CONFIG_TDP_GET_TDP_INFO resp:%x tdp_ratio:%d pkg_tdp:%d\n",
+		cpu, config_index, resp, ctdp_level->tdp_ratio,
+		ctdp_level->pkg_tdp);
+	return 0;
+}
+
+int isst_get_pwr_info(int cpu, int config_index,
+		      struct isst_pkg_ctdp_level_info *ctdp_level)
+{
+	unsigned int resp;
+	int ret;
+
+	ret = isst_send_mbox_command(cpu, CONFIG_TDP, CONFIG_TDP_GET_PWR_INFO,
+				     0, config_index, &resp);
+	if (ret)
+		return ret;
+
+	ctdp_level->pkg_max_power = resp & GENMASK(14, 0);
+	ctdp_level->pkg_min_power = (resp & GENMASK(30, 16)) >> 16;
+
+	debug_printf(
+		"cpu:%d ctdp:%d CONFIG_TDP_GET_PWR_INFO resp:%x pkg_max_power:%d pkg_min_power:%d\n",
+		cpu, config_index, resp, ctdp_level->pkg_max_power,
+		ctdp_level->pkg_min_power);
+
+	return 0;
+}
+
+int isst_get_tjmax_info(int cpu, int config_index,
+			struct isst_pkg_ctdp_level_info *ctdp_level)
+{
+	unsigned int resp;
+	int ret;
+
+	ret = isst_send_mbox_command(cpu, CONFIG_TDP, CONFIG_TDP_GET_TJMAX_INFO,
+				     0, config_index, &resp);
+	if (ret)
+		return ret;
+
+	ctdp_level->t_proc_hot = resp & GENMASK(7, 0);
+
+	debug_printf(
+		"cpu:%d ctdp:%d CONFIG_TDP_GET_TJMAX_INFO resp:%x t_proc_hot:%d\n",
+		cpu, config_index, resp, ctdp_level->t_proc_hot);
+
+	return 0;
+}
+
+int isst_get_coremask_info(int cpu, int config_index,
+			   struct isst_pkg_ctdp_level_info *ctdp_level)
+{
+	unsigned int resp;
+	int i, ret;
+
+	ctdp_level->cpu_count = 0;
+	for (i = 0; i < 2; ++i) {
+		unsigned long long mask;
+		int cpu_count = 0;
+
+		ret = isst_send_mbox_command(cpu, CONFIG_TDP,
+					     CONFIG_TDP_GET_CORE_MASK, 0,
+					     (i << 8) | config_index, &resp);
+		if (ret)
+			return ret;
+
+		debug_printf(
+			"cpu:%d ctdp:%d mask:%d CONFIG_TDP_GET_CORE_MASK resp:%x\n",
+			cpu, config_index, i, resp);
+
+		mask = (unsigned long long)resp << (32 * i);
+		set_cpu_mask_from_punit_coremask(cpu, mask,
+						 ctdp_level->core_cpumask_size,
+						 ctdp_level->core_cpumask,
+						 &cpu_count);
+		ctdp_level->cpu_count += cpu_count;
+		debug_printf("cpu:%d ctdp:%d mask:%d cpu count:%d\n", cpu,
+			     config_index, i, ctdp_level->cpu_count);
+	}
+
+	return 0;
+}
+
+int isst_get_get_trl(int cpu, int level, int avx_level, int *trl)
+{
+	unsigned int req, resp;
+	int ret;
+
+	req = level | (avx_level << 16);
+	ret = isst_send_mbox_command(cpu, CONFIG_TDP,
+				     CONFIG_TDP_GET_TURBO_LIMIT_RATIOS, 0, req,
+				     &resp);
+	if (ret)
+		return ret;
+
+	debug_printf(
+		"cpu:%d CONFIG_TDP_GET_TURBO_LIMIT_RATIOS req:%x resp:%x\n",
+		cpu, req, resp);
+
+	trl[0] = resp & GENMASK(7, 0);
+	trl[1] = (resp & GENMASK(15, 8)) >> 8;
+	trl[2] = (resp & GENMASK(23, 16)) >> 16;
+	trl[3] = (resp & GENMASK(31, 24)) >> 24;
+
+	req = level | BIT(8) | (avx_level << 16);
+	ret = isst_send_mbox_command(cpu, CONFIG_TDP,
+				     CONFIG_TDP_GET_TURBO_LIMIT_RATIOS, 0, req,
+				     &resp);
+	if (ret)
+		return ret;
+
+	debug_printf("cpu:%d CONFIG_TDP_GET_TURBO_LIMIT req:%x resp:%x\n", cpu,
+		     req, resp);
+
+	trl[4] = resp & GENMASK(7, 0);
+	trl[5] = (resp & GENMASK(15, 8)) >> 8;
+	trl[6] = (resp & GENMASK(23, 16)) >> 16;
+	trl[7] = (resp & GENMASK(31, 24)) >> 24;
+
+	return 0;
+}
+
+int isst_get_trl_bucket_info(int cpu, unsigned long long *buckets_info)
+{
+	int ret;
+
+	debug_printf("cpu:%d bucket info via MSR\n", cpu);
+
+	*buckets_info = 0;
+
+	ret = isst_send_msr_command(cpu, 0x1ae, 0, buckets_info);
+	if (ret)
+		return ret;
+
+	debug_printf("cpu:%d bucket info via MSR successful 0x%llx\n", cpu,
+		     *buckets_info);
+
+	return 0;
+}
+
+int isst_set_tdp_level_msr(int cpu, int tdp_level)
+{
+	unsigned long long level = tdp_level;
+	int ret;
+
+	debug_printf("cpu: tdp_level via MSR %d\n", cpu, tdp_level);
+
+	if (isst_get_config_tdp_lock_status(cpu)) {
+		debug_printf("cpu: tdp_locked %d\n", cpu);
+		return -1;
+	}
+
+	if (tdp_level > 2)
+		return -1; /* invalid value */
+
+	ret = isst_send_msr_command(cpu, 0x64b, 1, &level);
+	if (ret)
+		return ret;
+
+	debug_printf("cpu: tdp_level via MSR successful %d\n", cpu, tdp_level);
+
+	return 0;
+}
+
+int isst_set_tdp_level(int cpu, int tdp_level)
+{
+	unsigned int resp;
+	int ret;
+
+	ret = isst_send_mbox_command(cpu, CONFIG_TDP, CONFIG_TDP_SET_LEVEL, 0,
+				     tdp_level, &resp);
+	if (ret)
+		return isst_set_tdp_level_msr(cpu, tdp_level);
+
+	return 0;
+}
+
+int isst_get_pbf_info(int cpu, int level, struct isst_pbf_info *pbf_info)
+{
+	unsigned int req, resp;
+	int i, ret;
+
+	pbf_info->core_cpumask_size = alloc_cpu_set(&pbf_info->core_cpumask);
+
+	for (i = 0; i < 2; ++i) {
+		unsigned long long mask;
+		int count;
+
+		ret = isst_send_mbox_command(cpu, CONFIG_TDP,
+					     CONFIG_TDP_PBF_GET_CORE_MASK_INFO,
+					     0, (i << 8) | level, &resp);
+		if (ret)
+			return ret;
+
+		debug_printf(
+			"cpu:%d CONFIG_TDP_PBF_GET_CORE_MASK_INFO resp:%x\n",
+			cpu, resp);
+
+		mask = (unsigned long long)resp << (32 * i);
+		set_cpu_mask_from_punit_coremask(cpu, mask,
+						 pbf_info->core_cpumask_size,
+						 pbf_info->core_cpumask,
+						 &count);
+	}
+
+	req = level;
+	ret = isst_send_mbox_command(cpu, CONFIG_TDP,
+				     CONFIG_TDP_PBF_GET_P1HI_P1LO_INFO, 0, req,
+				     &resp);
+	if (ret)
+		return ret;
+
+	debug_printf("cpu:%d CONFIG_TDP_PBF_GET_P1HI_P1LO_INFO resp:%x\n", cpu,
+		     resp);
+
+	pbf_info->p1_low = resp & 0xff;
+	pbf_info->p1_high = (resp & GENMASK(15, 8)) >> 8;
+
+	req = level;
+	ret = isst_send_mbox_command(
+		cpu, CONFIG_TDP, CONFIG_TDP_PBF_GET_TDP_INFO, 0, req, &resp);
+	if (ret)
+		return ret;
+
+	debug_printf("cpu:%d CONFIG_TDP_PBF_GET_TDP_INFO resp:%x\n", cpu, resp);
+
+	pbf_info->tdp = resp & 0xffff;
+
+	req = level;
+	ret = isst_send_mbox_command(
+		cpu, CONFIG_TDP, CONFIG_TDP_PBF_GET_TJ_MAX_INFO, 0, req, &resp);
+	if (ret)
+		return ret;
+
+	debug_printf("cpu:%d CONFIG_TDP_PBF_GET_TJ_MAX_INFO resp:%x\n", cpu,
+		     resp);
+	pbf_info->t_control = (resp >> 8) & 0xff;
+	pbf_info->t_prochot = resp & 0xff;
+
+	return 0;
+}
+
+void isst_get_pbf_info_complete(struct isst_pbf_info *pbf_info)
+{
+	free_cpu_set(pbf_info->core_cpumask);
+}
+
+int isst_set_pbf_fact_status(int cpu, int pbf, int enable)
+{
+	struct isst_pkg_ctdp pkg_dev;
+	struct isst_pkg_ctdp_level_info ctdp_level;
+	int current_level;
+	unsigned int req = 0, resp;
+	int ret;
+
+	ret = isst_get_ctdp_levels(cpu, &pkg_dev);
+	if (ret)
+		return ret;
+
+	current_level = pkg_dev.current_level;
+
+	ret = isst_get_ctdp_control(cpu, current_level, &ctdp_level);
+	if (ret)
+		return ret;
+
+	if (pbf) {
+		if (ctdp_level.fact_enabled)
+			req = BIT(16);
+
+		if (enable)
+			req |= BIT(17);
+		else
+			req &= ~BIT(17);
+	} else {
+		if (ctdp_level.pbf_enabled)
+			req = BIT(17);
+
+		if (enable)
+			req |= BIT(16);
+		else
+			req &= ~BIT(16);
+	}
+
+	ret = isst_send_mbox_command(cpu, CONFIG_TDP,
+				     CONFIG_TDP_SET_TDP_CONTROL, 0, req, &resp);
+	if (ret)
+		return ret;
+
+	debug_printf("cpu:%d CONFIG_TDP_SET_TDP_CONTROL pbf/fact:%d req:%x\n",
+		     cpu, pbf, req);
+
+	return 0;
+}
+
+int isst_get_fact_bucket_info(int cpu, int level,
+			      struct isst_fact_bucket_info *bucket_info)
+{
+	unsigned int resp;
+	int i, k, ret;
+
+	for (i = 0; i < 2; ++i) {
+		int j;
+
+		ret = isst_send_mbox_command(
+			cpu, CONFIG_TDP,
+			CONFIG_TDP_GET_FACT_HP_TURBO_LIMIT_NUMCORES, 0,
+			(i << 8) | level, &resp);
+		if (ret)
+			return ret;
+
+		debug_printf(
+			"cpu:%d CONFIG_TDP_GET_FACT_HP_TURBO_LIMIT_NUMCORES index:%d level:%d resp:%x\n",
+			cpu, i, level, resp);
+
+		for (j = 0; j < 4; ++j) {
+			bucket_info[j + (i * 4)].high_priority_cores_count =
+				(resp >> (j * 8)) & 0xff;
+		}
+	}
+
+	for (k = 0; k < 3; ++k) {
+		for (i = 0; i < 2; ++i) {
+			int j;
+
+			ret = isst_send_mbox_command(
+				cpu, CONFIG_TDP,
+				CONFIG_TDP_GET_FACT_HP_TURBO_LIMIT_RATIOS, 0,
+				(k << 16) | (i << 8) | level, &resp);
+			if (ret)
+				return ret;
+
+			debug_printf(
+				"cpu:%d CONFIG_TDP_GET_FACT_HP_TURBO_LIMIT_RATIOS index:%d level:%d avx:%d resp:%x\n",
+				cpu, i, level, k, resp);
+
+			for (j = 0; j < 4; ++j) {
+				switch (k) {
+				case 0:
+					bucket_info[j + (i * 4)].sse_trl =
+						(resp >> (j * 8)) & 0xff;
+					break;
+				case 1:
+					bucket_info[j + (i * 4)].avx_trl =
+						(resp >> (j * 8)) & 0xff;
+					break;
+				case 2:
+					bucket_info[j + (i * 4)].avx512_trl =
+						(resp >> (j * 8)) & 0xff;
+					break;
+				default:
+					break;
+				}
+			}
+		}
+	}
+
+	return 0;
+}
+
+int isst_get_fact_info(int cpu, int level, struct isst_fact_info *fact_info)
+{
+	unsigned int resp;
+	int ret;
+
+	ret = isst_send_mbox_command(cpu, CONFIG_TDP,
+				     CONFIG_TDP_GET_FACT_LP_CLIPPING_RATIO, 0,
+				     level, &resp);
+	if (ret)
+		return ret;
+
+	debug_printf("cpu:%d CONFIG_TDP_GET_FACT_LP_CLIPPING_RATIO resp:%x\n",
+		     cpu, resp);
+
+	fact_info->lp_clipping_ratio_license_sse = resp & 0xff;
+	fact_info->lp_clipping_ratio_license_avx2 = (resp >> 8) & 0xff;
+	fact_info->lp_clipping_ratio_license_avx512 = (resp >> 16) & 0xff;
+
+	ret = isst_get_fact_bucket_info(cpu, level, fact_info->bucket_info);
+
+	return ret;
+}
+
+int isst_set_trl(int cpu, unsigned long long trl)
+{
+	int ret;
+
+	if (!trl)
+		trl = 0xFFFFFFFFFFFFFFFFULL;
+
+	ret = isst_send_msr_command(cpu, 0x1AD, 1, &trl);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+int isst_set_trl_from_current_tdp(int cpu, unsigned long long trl)
+{
+	unsigned long long msr_trl;
+	int ret;
+
+	if (trl) {
+		msr_trl = trl;
+	} else {
+		struct isst_pkg_ctdp pkg_dev;
+		int trl[8];
+		int i;
+
+		ret = isst_get_ctdp_levels(cpu, &pkg_dev);
+		if (ret)
+			return ret;
+
+		ret = isst_get_get_trl(cpu, pkg_dev.current_level, 0, trl);
+		if (ret)
+			return ret;
+
+		msr_trl = 0;
+		for (i = 0; i < 8; ++i) {
+			unsigned long long _trl = trl[i];
+
+			msr_trl |= (_trl << (i * 8));
+		}
+	}
+	ret = isst_send_msr_command(cpu, 0x1AD, 1, &msr_trl);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+/* Return 1 if locked */
+int isst_get_config_tdp_lock_status(int cpu)
+{
+	unsigned long long tdp_control = 0;
+	int ret;
+
+	ret = isst_send_msr_command(cpu, 0x64b, 0, &tdp_control);
+	if (ret)
+		return ret;
+
+	ret = !!(tdp_control & BIT(31));
+
+	return ret;
+}
+
+void isst_get_process_ctdp_complete(int cpu, struct isst_pkg_ctdp *pkg_dev)
+{
+	int i;
+
+	if (!pkg_dev->processed)
+		return;
+
+	for (i = 0; i < pkg_dev->levels; ++i) {
+		struct isst_pkg_ctdp_level_info *ctdp_level;
+
+		ctdp_level = &pkg_dev->ctdp_level[i];
+		if (ctdp_level->pbf_support)
+			free_cpu_set(ctdp_level->pbf_info.core_cpumask);
+		free_cpu_set(ctdp_level->core_cpumask);
+	}
+}
+
+int isst_get_process_ctdp(int cpu, int tdp_level, struct isst_pkg_ctdp *pkg_dev)
+{
+	int i, ret;
+
+	if (pkg_dev->processed)
+		return 0;
+
+	ret = isst_get_ctdp_levels(cpu, pkg_dev);
+	if (ret)
+		return ret;
+
+	debug_printf("cpu: %d ctdp enable:%d current level: %d levels:%d\n",
+		     cpu, pkg_dev->enabled, pkg_dev->current_level,
+		     pkg_dev->levels);
+
+	for (i = 0; i <= pkg_dev->levels; ++i) {
+		struct isst_pkg_ctdp_level_info *ctdp_level;
+
+		if (tdp_level != 0xff && i != tdp_level)
+			continue;
+
+		debug_printf("cpu:%d Get Information for TDP level:%d\n", cpu,
+			     i);
+		ctdp_level = &pkg_dev->ctdp_level[i];
+
+		ctdp_level->processed = 1;
+		ctdp_level->level = i;
+		ctdp_level->control_cpu = cpu;
+		ctdp_level->pkg_id = get_physical_package_id(cpu);
+		ctdp_level->die_id = get_physical_die_id(cpu);
+
+		ret = isst_get_ctdp_control(cpu, i, ctdp_level);
+		if (ret)
+			return ret;
+
+		ret = isst_get_tdp_info(cpu, i, ctdp_level);
+		if (ret)
+			return ret;
+
+		ret = isst_get_pwr_info(cpu, i, ctdp_level);
+		if (ret)
+			return ret;
+
+		ret = isst_get_tjmax_info(cpu, i, ctdp_level);
+		if (ret)
+			return ret;
+
+		ctdp_level->core_cpumask_size =
+			alloc_cpu_set(&ctdp_level->core_cpumask);
+		ret = isst_get_coremask_info(cpu, i, ctdp_level);
+		if (ret)
+			return ret;
+
+		ret = isst_get_trl_bucket_info(cpu, &ctdp_level->buckets_info);
+		if (ret)
+			return ret;
+
+		ret = isst_get_get_trl(cpu, i, 0,
+				       ctdp_level->trl_sse_active_cores);
+		if (ret)
+			return ret;
+
+		ret = isst_get_get_trl(cpu, i, 1,
+				       ctdp_level->trl_avx_active_cores);
+		if (ret)
+			return ret;
+
+		ret = isst_get_get_trl(cpu, i, 2,
+				       ctdp_level->trl_avx_512_active_cores);
+		if (ret)
+			return ret;
+
+		if (ctdp_level->pbf_support) {
+			ret = isst_get_pbf_info(cpu, i, &ctdp_level->pbf_info);
+			if (!ret)
+				ctdp_level->pbf_found = 1;
+		}
+
+		if (ctdp_level->fact_support) {
+			ret = isst_get_fact_info(cpu, i,
+						 &ctdp_level->fact_info);
+			if (ret)
+				return ret;
+		}
+	}
+
+	pkg_dev->processed = 1;
+
+	return 0;
+}
+
+int isst_clos_get_clos_information(int cpu, int *enable, int *type)
+{
+	unsigned int resp;
+	int ret;
+
+	ret = isst_send_mbox_command(cpu, CONFIG_CLOS, CLOS_PM_QOS_CONFIG, 0, 0,
+				     &resp);
+	if (ret)
+		return ret;
+
+	debug_printf("cpu:%d CLOS_PM_QOS_CONFIG resp:%x\n", cpu, resp);
+
+	if (resp & BIT(1))
+		*enable = 1;
+	else
+		*enable = 0;
+
+	if (resp & BIT(2))
+		*type = 1;
+	else
+		*type = 0;
+
+	return 0;
+}
+
+int isst_pm_qos_config(int cpu, int enable_clos, int priority_type)
+{
+	unsigned int req, resp;
+	int ret;
+
+	ret = isst_send_mbox_command(cpu, CONFIG_CLOS, CLOS_PM_QOS_CONFIG, 0, 0,
+				     &resp);
+	if (ret)
+		return ret;
+
+	debug_printf("cpu:%d CLOS_PM_QOS_CONFIG resp:%x\n", cpu, resp);
+
+	req = resp;
+
+	if (enable_clos)
+		req = req | BIT(1);
+	else
+		req = req & ~BIT(1);
+
+	if (priority_type)
+		req = req | BIT(2);
+	else
+		req = req & ~BIT(2);
+
+	ret = isst_send_mbox_command(cpu, CONFIG_CLOS, CLOS_PM_QOS_CONFIG,
+				     BIT(MBOX_CMD_WRITE_BIT), req, &resp);
+	if (ret)
+		return ret;
+
+	debug_printf("cpu:%d CLOS_PM_QOS_CONFIG priority type:%d req:%x\n", cpu,
+		     priority_type, req);
+
+	return 0;
+}
+
+int isst_pm_get_clos(int cpu, int clos, struct isst_clos_config *clos_config)
+{
+	unsigned int resp;
+	int ret;
+
+	ret = isst_send_mbox_command(cpu, CONFIG_CLOS, CLOS_PM_CLOS, clos, 0,
+				     &resp);
+	if (ret)
+		return ret;
+
+	clos_config->pkg_id = get_physical_package_id(cpu);
+	clos_config->die_id = get_physical_die_id(cpu);
+
+	clos_config->epp = resp & 0x0f;
+	clos_config->clos_prop_prio = (resp >> 4) & 0x0f;
+	clos_config->clos_min = (resp >> 8) & 0xff;
+	clos_config->clos_max = (resp >> 16) & 0xff;
+	clos_config->clos_desired = (resp >> 24) & 0xff;
+
+	return 0;
+}
+
+int isst_set_clos(int cpu, int clos, struct isst_clos_config *clos_config)
+{
+	unsigned int req, resp;
+	unsigned int param;
+	int ret;
+
+	req = clos_config->epp & 0x0f;
+	req |= (clos_config->clos_prop_prio & 0x0f) << 4;
+	req |= (clos_config->clos_min & 0xff) << 8;
+	req |= (clos_config->clos_max & 0xff) << 16;
+	req |= (clos_config->clos_desired & 0xff) << 24;
+
+	param = BIT(MBOX_CMD_WRITE_BIT) | clos;
+
+	ret = isst_send_mbox_command(cpu, CONFIG_CLOS, CLOS_PM_CLOS, param, req,
+				     &resp);
+	if (ret)
+		return ret;
+
+	debug_printf("cpu:%d CLOS_PM_CLOS param:%x req:%x\n", cpu, param, req);
+
+	return 0;
+}
+
+int isst_clos_get_assoc_status(int cpu, int *clos_id)
+{
+	unsigned int resp;
+	unsigned int param;
+	int core_id, ret;
+
+	core_id = find_phy_core_num(cpu);
+	param = core_id;
+
+	ret = isst_send_mbox_command(cpu, CONFIG_CLOS, CLOS_PQR_ASSOC, param, 0,
+				     &resp);
+	if (ret)
+		return ret;
+
+	debug_printf("cpu:%d CLOS_PQR_ASSOC param:%x resp:%x\n", cpu, param,
+		     resp);
+	*clos_id = (resp >> 16) & 0x03;
+
+	return 0;
+}
+
+int isst_clos_associate(int cpu, int clos_id)
+{
+	unsigned int req, resp;
+	unsigned int param;
+	int core_id, ret;
+
+	req = (clos_id & 0x03) << 16;
+	core_id = find_phy_core_num(cpu);
+	param = BIT(MBOX_CMD_WRITE_BIT) | core_id;
+
+	ret = isst_send_mbox_command(cpu, CONFIG_CLOS, CLOS_PQR_ASSOC, param,
+				     req, &resp);
+	if (ret)
+		return ret;
+
+	debug_printf("cpu:%d CLOS_PQR_ASSOC param:%x req:%x\n", cpu, param,
+		     req);
+
+	return 0;
+}
diff --git a/tools/power/x86/intel-speed-select/isst-display.c b/tools/power/x86/intel-speed-select/isst-display.c
new file mode 100644
index 0000000..40346d5
--- /dev/null
+++ b/tools/power/x86/intel-speed-select/isst-display.c
@@ -0,0 +1,600 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Intel dynamic_speed_select -- Enumerate and control features
+ * Copyright (c) 2019 Intel Corporation.
+ */
+
+#include "isst.h"
+
+#define DISP_FREQ_MULTIPLIER 100
+
+static void printcpulist(int str_len, char *str, int mask_size,
+			 cpu_set_t *cpu_mask)
+{
+	int i, first, curr_index, index;
+
+	if (!CPU_COUNT_S(mask_size, cpu_mask)) {
+		snprintf(str, str_len, "none");
+		return;
+	}
+
+	curr_index = 0;
+	first = 1;
+	for (i = 0; i < get_topo_max_cpus(); ++i) {
+		if (!CPU_ISSET_S(i, mask_size, cpu_mask))
+			continue;
+		if (!first) {
+			index = snprintf(&str[curr_index],
+					 str_len - curr_index, ",");
+			curr_index += index;
+		}
+		index = snprintf(&str[curr_index], str_len - curr_index, "%d",
+				 i);
+		curr_index += index;
+		first = 0;
+	}
+}
+
+static void printcpumask(int str_len, char *str, int mask_size,
+			 cpu_set_t *cpu_mask)
+{
+	int i, max_cpus = get_topo_max_cpus();
+	unsigned int *mask;
+	int size, index, curr_index;
+
+	size = max_cpus / (sizeof(unsigned int) * 8);
+	if (max_cpus % (sizeof(unsigned int) * 8))
+		size++;
+
+	mask = calloc(size, sizeof(unsigned int));
+	if (!mask)
+		return;
+
+	for (i = 0; i < max_cpus; ++i) {
+		int mask_index, bit_index;
+
+		if (!CPU_ISSET_S(i, mask_size, cpu_mask))
+			continue;
+
+		mask_index = i / (sizeof(unsigned int) * 8);
+		bit_index = i % (sizeof(unsigned int) * 8);
+		mask[mask_index] |= BIT(bit_index);
+	}
+
+	curr_index = 0;
+	for (i = size - 1; i >= 0; --i) {
+		index = snprintf(&str[curr_index], str_len - curr_index, "%08x",
+				 mask[i]);
+		curr_index += index;
+		if (i) {
+			strncat(&str[curr_index], ",", str_len - curr_index);
+			curr_index++;
+		}
+	}
+
+	free(mask);
+}
+
+static void format_and_print_txt(FILE *outf, int level, char *header,
+				 char *value)
+{
+	char *spaces = "  ";
+	static char delimiters[256];
+	int i, j = 0;
+
+	if (!level)
+		return;
+
+	if (level == 1) {
+		strcpy(delimiters, " ");
+	} else {
+		for (i = 0; i < level - 1; ++i)
+			j += snprintf(&delimiters[j], sizeof(delimiters) - j,
+				      "%s", spaces);
+	}
+
+	if (header && value) {
+		fprintf(outf, "%s", delimiters);
+		fprintf(outf, "%s:%s\n", header, value);
+	} else if (header) {
+		fprintf(outf, "%s", delimiters);
+		fprintf(outf, "%s\n", header);
+	}
+}
+
+static int last_level;
+static void format_and_print(FILE *outf, int level, char *header, char *value)
+{
+	char *spaces = "  ";
+	static char delimiters[256];
+	int i;
+
+	if (!out_format_is_json()) {
+		format_and_print_txt(outf, level, header, value);
+		return;
+	}
+
+	if (level == 0) {
+		if (header)
+			fprintf(outf, "{");
+		else
+			fprintf(outf, "\n}\n");
+
+	} else {
+		int j = 0;
+
+		for (i = 0; i < level; ++i)
+			j += snprintf(&delimiters[j], sizeof(delimiters) - j,
+				      "%s", spaces);
+
+		if (last_level == level)
+			fprintf(outf, ",\n");
+
+		if (value) {
+			if (last_level != level)
+				fprintf(outf, "\n");
+
+			fprintf(outf, "%s\"%s\": ", delimiters, header);
+			fprintf(outf, "\"%s\"", value);
+		} else {
+			for (i = last_level - 1; i >= level; --i) {
+				int k = 0;
+
+				for (j = i; j > 0; --j)
+					k += snprintf(&delimiters[k],
+						      sizeof(delimiters) - k,
+						      "%s", spaces);
+				if (i == level && header)
+					fprintf(outf, "\n%s},", delimiters);
+				else
+					fprintf(outf, "\n%s}", delimiters);
+			}
+			if (abs(last_level - level) < 3)
+				fprintf(outf, "\n");
+			if (header)
+				fprintf(outf, "%s\"%s\": {", delimiters,
+					header);
+		}
+	}
+
+	last_level = level;
+}
+
+static void print_package_info(int cpu, FILE *outf)
+{
+	char header[256];
+
+	snprintf(header, sizeof(header), "package-%d",
+		 get_physical_package_id(cpu));
+	format_and_print(outf, 1, header, NULL);
+	snprintf(header, sizeof(header), "die-%d", get_physical_die_id(cpu));
+	format_and_print(outf, 2, header, NULL);
+	snprintf(header, sizeof(header), "cpu-%d", cpu);
+	format_and_print(outf, 3, header, NULL);
+}
+
+static void _isst_pbf_display_information(int cpu, FILE *outf, int level,
+					  struct isst_pbf_info *pbf_info,
+					  int disp_level)
+{
+	char header[256];
+	char value[256];
+
+	snprintf(header, sizeof(header), "speed-select-base-freq");
+	format_and_print(outf, disp_level, header, NULL);
+
+	snprintf(header, sizeof(header), "high-priority-base-frequency(MHz)");
+	snprintf(value, sizeof(value), "%d",
+		 pbf_info->p1_high * DISP_FREQ_MULTIPLIER);
+	format_and_print(outf, disp_level + 1, header, value);
+
+	snprintf(header, sizeof(header), "high-priority-cpu-mask");
+	printcpumask(sizeof(value), value, pbf_info->core_cpumask_size,
+		     pbf_info->core_cpumask);
+	format_and_print(outf, disp_level + 1, header, value);
+
+	snprintf(header, sizeof(header), "high-priority-cpu-list");
+	printcpulist(sizeof(value), value,
+		     pbf_info->core_cpumask_size,
+		     pbf_info->core_cpumask);
+	format_and_print(outf, disp_level + 1, header, value);
+
+	snprintf(header, sizeof(header), "low-priority-base-frequency(MHz)");
+	snprintf(value, sizeof(value), "%d",
+		 pbf_info->p1_low * DISP_FREQ_MULTIPLIER);
+	format_and_print(outf, disp_level + 1, header, value);
+
+	snprintf(header, sizeof(header), "tjunction-temperature(C)");
+	snprintf(value, sizeof(value), "%d", pbf_info->t_prochot);
+	format_and_print(outf, disp_level + 1, header, value);
+
+	snprintf(header, sizeof(header), "thermal-design-power(W)");
+	snprintf(value, sizeof(value), "%d", pbf_info->tdp);
+	format_and_print(outf, disp_level + 1, header, value);
+}
+
+static void _isst_fact_display_information(int cpu, FILE *outf, int level,
+					   int fact_bucket, int fact_avx,
+					   struct isst_fact_info *fact_info,
+					   int base_level)
+{
+	struct isst_fact_bucket_info *bucket_info = fact_info->bucket_info;
+	char header[256];
+	char value[256];
+	int j;
+
+	snprintf(header, sizeof(header), "speed-select-turbo-freq");
+	format_and_print(outf, base_level, header, NULL);
+	for (j = 0; j < ISST_FACT_MAX_BUCKETS; ++j) {
+		if (fact_bucket != 0xff && fact_bucket != j)
+			continue;
+
+		if (!bucket_info[j].high_priority_cores_count)
+			break;
+
+		snprintf(header, sizeof(header), "bucket-%d", j);
+		format_and_print(outf, base_level + 1, header, NULL);
+
+		snprintf(header, sizeof(header), "high-priority-cores-count");
+		snprintf(value, sizeof(value), "%d",
+			 bucket_info[j].high_priority_cores_count);
+		format_and_print(outf, base_level + 2, header, value);
+
+		if (fact_avx & 0x01) {
+			snprintf(header, sizeof(header),
+				 "high-priority-max-frequency(MHz)");
+			snprintf(value, sizeof(value), "%d",
+				 bucket_info[j].sse_trl * DISP_FREQ_MULTIPLIER);
+			format_and_print(outf, base_level + 2, header, value);
+		}
+
+		if (fact_avx & 0x02) {
+			snprintf(header, sizeof(header),
+				 "high-priority-max-avx2-frequency(MHz)");
+			snprintf(value, sizeof(value), "%d",
+				 bucket_info[j].avx_trl * DISP_FREQ_MULTIPLIER);
+			format_and_print(outf, base_level + 2, header, value);
+		}
+
+		if (fact_avx & 0x04) {
+			snprintf(header, sizeof(header),
+				 "high-priority-max-avx512-frequency(MHz)");
+			snprintf(value, sizeof(value), "%d",
+				 bucket_info[j].avx512_trl *
+					 DISP_FREQ_MULTIPLIER);
+			format_and_print(outf, base_level + 2, header, value);
+		}
+	}
+	snprintf(header, sizeof(header),
+		 "speed-select-turbo-freq-clip-frequencies");
+	format_and_print(outf, base_level + 1, header, NULL);
+	snprintf(header, sizeof(header), "low-priority-max-frequency(MHz)");
+	snprintf(value, sizeof(value), "%d",
+		 fact_info->lp_clipping_ratio_license_sse *
+			 DISP_FREQ_MULTIPLIER);
+	format_and_print(outf, base_level + 2, header, value);
+	snprintf(header, sizeof(header),
+		 "low-priority-max-avx2-frequency(MHz)");
+	snprintf(value, sizeof(value), "%d",
+		 fact_info->lp_clipping_ratio_license_avx2 *
+			 DISP_FREQ_MULTIPLIER);
+	format_and_print(outf, base_level + 2, header, value);
+	snprintf(header, sizeof(header),
+		 "low-priority-max-avx512-frequency(MHz)");
+	snprintf(value, sizeof(value), "%d",
+		 fact_info->lp_clipping_ratio_license_avx512 *
+			 DISP_FREQ_MULTIPLIER);
+	format_and_print(outf, base_level + 2, header, value);
+}
+
+void isst_ctdp_display_core_info(int cpu, FILE *outf, char *prefix,
+				 unsigned int val)
+{
+	char header[256];
+	char value[256];
+
+	snprintf(header, sizeof(header), "package-%d",
+		 get_physical_package_id(cpu));
+	format_and_print(outf, 1, header, NULL);
+	snprintf(header, sizeof(header), "die-%d", get_physical_die_id(cpu));
+	format_and_print(outf, 2, header, NULL);
+	snprintf(header, sizeof(header), "cpu-%d", cpu);
+	format_and_print(outf, 3, header, NULL);
+
+	snprintf(value, sizeof(value), "%u", val);
+	format_and_print(outf, 4, prefix, value);
+
+	format_and_print(outf, 1, NULL, NULL);
+}
+
+void isst_ctdp_display_information(int cpu, FILE *outf, int tdp_level,
+				   struct isst_pkg_ctdp *pkg_dev)
+{
+	char header[256];
+	char value[256];
+	int i, base_level = 1;
+
+	print_package_info(cpu, outf);
+
+	for (i = 0; i <= pkg_dev->levels; ++i) {
+		struct isst_pkg_ctdp_level_info *ctdp_level;
+		int j;
+
+		ctdp_level = &pkg_dev->ctdp_level[i];
+		if (!ctdp_level->processed)
+			continue;
+
+		snprintf(header, sizeof(header), "perf-profile-level-%d",
+			 ctdp_level->level);
+		format_and_print(outf, base_level + 3, header, NULL);
+
+		snprintf(header, sizeof(header), "cpu-count");
+		j = get_cpu_count(get_physical_die_id(cpu),
+				  get_physical_die_id(cpu));
+		snprintf(value, sizeof(value), "%d", j);
+		format_and_print(outf, base_level + 4, header, value);
+
+		snprintf(header, sizeof(header), "enable-cpu-mask");
+		printcpumask(sizeof(value), value,
+			     ctdp_level->core_cpumask_size,
+			     ctdp_level->core_cpumask);
+		format_and_print(outf, base_level + 4, header, value);
+
+		snprintf(header, sizeof(header), "enable-cpu-list");
+		printcpulist(sizeof(value), value,
+			     ctdp_level->core_cpumask_size,
+			     ctdp_level->core_cpumask);
+		format_and_print(outf, base_level + 4, header, value);
+
+		snprintf(header, sizeof(header), "thermal-design-power-ratio");
+		snprintf(value, sizeof(value), "%d", ctdp_level->tdp_ratio);
+		format_and_print(outf, base_level + 4, header, value);
+
+		snprintf(header, sizeof(header), "base-frequency(MHz)");
+		snprintf(value, sizeof(value), "%d",
+			 ctdp_level->tdp_ratio * DISP_FREQ_MULTIPLIER);
+		format_and_print(outf, base_level + 4, header, value);
+
+		snprintf(header, sizeof(header),
+			 "speed-select-turbo-freq");
+		if (ctdp_level->fact_support) {
+			if (ctdp_level->fact_enabled)
+				snprintf(value, sizeof(value), "enabled");
+			else
+				snprintf(value, sizeof(value), "disabled");
+		} else
+			snprintf(value, sizeof(value), "unsupported");
+		format_and_print(outf, base_level + 4, header, value);
+
+		snprintf(header, sizeof(header),
+			 "speed-select-base-freq");
+		if (ctdp_level->pbf_support) {
+			if (ctdp_level->pbf_enabled)
+				snprintf(value, sizeof(value), "enabled");
+			else
+				snprintf(value, sizeof(value), "disabled");
+		} else
+			snprintf(value, sizeof(value), "unsupported");
+		format_and_print(outf, base_level + 4, header, value);
+
+		snprintf(header, sizeof(header), "thermal-design-power(W)");
+		snprintf(value, sizeof(value), "%d", ctdp_level->pkg_tdp);
+		format_and_print(outf, base_level + 4, header, value);
+
+		snprintf(header, sizeof(header), "tjunction-max(C)");
+		snprintf(value, sizeof(value), "%d", ctdp_level->t_proc_hot);
+		format_and_print(outf, base_level + 4, header, value);
+
+		snprintf(header, sizeof(header), "turbo-ratio-limits-sse");
+		format_and_print(outf, base_level + 4, header, NULL);
+		for (j = 0; j < 8; ++j) {
+			snprintf(header, sizeof(header), "bucket-%d", j);
+			format_and_print(outf, base_level + 5, header, NULL);
+
+			snprintf(header, sizeof(header), "core-count");
+			snprintf(value, sizeof(value), "%llu", (ctdp_level->buckets_info >> (j * 8)) & 0xff);
+			format_and_print(outf, base_level + 6, header, value);
+
+			snprintf(header, sizeof(header),
+				"max-turbo-frequency(MHz)");
+			snprintf(value, sizeof(value), "%d",
+				 ctdp_level->trl_sse_active_cores[j] *
+				  DISP_FREQ_MULTIPLIER);
+			format_and_print(outf, base_level + 6, header, value);
+		}
+		snprintf(header, sizeof(header), "turbo-ratio-limits-avx");
+		format_and_print(outf, base_level + 4, header, NULL);
+		for (j = 0; j < 8; ++j) {
+			snprintf(header, sizeof(header), "bucket-%d", j);
+			format_and_print(outf, base_level + 5, header, NULL);
+
+			snprintf(header, sizeof(header), "core-count");
+			snprintf(value, sizeof(value), "%llu", (ctdp_level->buckets_info >> (j * 8)) & 0xff);
+			format_and_print(outf, base_level + 6, header, value);
+
+			snprintf(header, sizeof(header),
+				"max-turbo-frequency(MHz)");
+			snprintf(value, sizeof(value), "%d",
+				 ctdp_level->trl_avx_active_cores[j] *
+				  DISP_FREQ_MULTIPLIER);
+			format_and_print(outf, base_level + 6, header, value);
+		}
+
+		snprintf(header, sizeof(header), "turbo-ratio-limits-avx512");
+		format_and_print(outf, base_level + 4, header, NULL);
+		for (j = 0; j < 8; ++j) {
+			snprintf(header, sizeof(header), "bucket-%d", j);
+			format_and_print(outf, base_level + 5, header, NULL);
+
+			snprintf(header, sizeof(header), "core-count");
+			snprintf(value, sizeof(value), "%llu", (ctdp_level->buckets_info >> (j * 8)) & 0xff);
+			format_and_print(outf, base_level + 6, header, value);
+
+			snprintf(header, sizeof(header),
+				"max-turbo-frequency(MHz)");
+			snprintf(value, sizeof(value), "%d",
+				 ctdp_level->trl_avx_512_active_cores[j] *
+				  DISP_FREQ_MULTIPLIER);
+			format_and_print(outf, base_level + 6, header, value);
+		}
+		if (ctdp_level->pbf_support)
+			_isst_pbf_display_information(cpu, outf, i,
+						      &ctdp_level->pbf_info,
+						      base_level + 4);
+		if (ctdp_level->fact_support)
+			_isst_fact_display_information(cpu, outf, i, 0xff, 0xff,
+						       &ctdp_level->fact_info,
+						       base_level + 4);
+	}
+
+	format_and_print(outf, 1, NULL, NULL);
+}
+
+void isst_ctdp_display_information_start(FILE *outf)
+{
+	last_level = 0;
+	format_and_print(outf, 0, "start", NULL);
+}
+
+void isst_ctdp_display_information_end(FILE *outf)
+{
+	format_and_print(outf, 0, NULL, NULL);
+}
+
+void isst_pbf_display_information(int cpu, FILE *outf, int level,
+				  struct isst_pbf_info *pbf_info)
+{
+	print_package_info(cpu, outf);
+	_isst_pbf_display_information(cpu, outf, level, pbf_info, 4);
+	format_and_print(outf, 1, NULL, NULL);
+}
+
+void isst_fact_display_information(int cpu, FILE *outf, int level,
+				   int fact_bucket, int fact_avx,
+				   struct isst_fact_info *fact_info)
+{
+	print_package_info(cpu, outf);
+	_isst_fact_display_information(cpu, outf, level, fact_bucket, fact_avx,
+				       fact_info, 4);
+	format_and_print(outf, 1, NULL, NULL);
+}
+
+void isst_clos_display_information(int cpu, FILE *outf, int clos,
+				   struct isst_clos_config *clos_config)
+{
+	char header[256];
+	char value[256];
+
+	snprintf(header, sizeof(header), "package-%d",
+		 get_physical_package_id(cpu));
+	format_and_print(outf, 1, header, NULL);
+	snprintf(header, sizeof(header), "die-%d", get_physical_die_id(cpu));
+	format_and_print(outf, 2, header, NULL);
+	snprintf(header, sizeof(header), "cpu-%d", cpu);
+	format_and_print(outf, 3, header, NULL);
+
+	snprintf(header, sizeof(header), "core-power");
+	format_and_print(outf, 4, header, NULL);
+
+	snprintf(header, sizeof(header), "clos");
+	snprintf(value, sizeof(value), "%d", clos);
+	format_and_print(outf, 5, header, value);
+
+	snprintf(header, sizeof(header), "epp");
+	snprintf(value, sizeof(value), "%d", clos_config->epp);
+	format_and_print(outf, 5, header, value);
+
+	snprintf(header, sizeof(header), "clos-proportional-priority");
+	snprintf(value, sizeof(value), "%d", clos_config->clos_prop_prio);
+	format_and_print(outf, 5, header, value);
+
+	snprintf(header, sizeof(header), "clos-min");
+	snprintf(value, sizeof(value), "%d", clos_config->clos_min);
+	format_and_print(outf, 5, header, value);
+
+	snprintf(header, sizeof(header), "clos-max");
+	snprintf(value, sizeof(value), "%d", clos_config->clos_max);
+	format_and_print(outf, 5, header, value);
+
+	snprintf(header, sizeof(header), "clos-desired");
+	snprintf(value, sizeof(value), "%d", clos_config->clos_desired);
+	format_and_print(outf, 5, header, value);
+
+	format_and_print(outf, 1, NULL, NULL);
+}
+
+void isst_clos_display_clos_information(int cpu, FILE *outf,
+					int clos_enable, int type)
+{
+	char header[256];
+	char value[256];
+
+	snprintf(header, sizeof(header), "package-%d",
+		 get_physical_package_id(cpu));
+	format_and_print(outf, 1, header, NULL);
+	snprintf(header, sizeof(header), "die-%d", get_physical_die_id(cpu));
+	format_and_print(outf, 2, header, NULL);
+	snprintf(header, sizeof(header), "cpu-%d", cpu);
+	format_and_print(outf, 3, header, NULL);
+
+	snprintf(header, sizeof(header), "core-power");
+	format_and_print(outf, 4, header, NULL);
+
+	snprintf(header, sizeof(header), "enable-status");
+	snprintf(value, sizeof(value), "%d", clos_enable);
+	format_and_print(outf, 5, header, value);
+
+	snprintf(header, sizeof(header), "priority-type");
+	snprintf(value, sizeof(value), "%d", type);
+	format_and_print(outf, 5, header, value);
+
+	format_and_print(outf, 1, NULL, NULL);
+}
+
+void isst_clos_display_assoc_information(int cpu, FILE *outf, int clos)
+{
+	char header[256];
+	char value[256];
+
+	snprintf(header, sizeof(header), "package-%d",
+		 get_physical_package_id(cpu));
+	format_and_print(outf, 1, header, NULL);
+	snprintf(header, sizeof(header), "die-%d", get_physical_die_id(cpu));
+	format_and_print(outf, 2, header, NULL);
+	snprintf(header, sizeof(header), "cpu-%d", cpu);
+	format_and_print(outf, 3, header, NULL);
+
+	snprintf(header, sizeof(header), "get-assoc");
+	format_and_print(outf, 4, header, NULL);
+
+	snprintf(header, sizeof(header), "clos");
+	snprintf(value, sizeof(value), "%d", clos);
+	format_and_print(outf, 5, header, value);
+
+	format_and_print(outf, 1, NULL, NULL);
+}
+
+void isst_display_result(int cpu, FILE *outf, char *feature, char *cmd,
+			 int result)
+{
+	char header[256];
+	char value[256];
+
+	snprintf(header, sizeof(header), "package-%d",
+		 get_physical_package_id(cpu));
+	format_and_print(outf, 1, header, NULL);
+	snprintf(header, sizeof(header), "die-%d", get_physical_die_id(cpu));
+	format_and_print(outf, 2, header, NULL);
+	snprintf(header, sizeof(header), "cpu-%d", cpu);
+	format_and_print(outf, 3, header, NULL);
+	snprintf(header, sizeof(header), "%s", feature);
+	format_and_print(outf, 4, header, NULL);
+	snprintf(header, sizeof(header), "%s", cmd);
+	if (!result)
+		snprintf(value, sizeof(value), "success");
+	else
+		snprintf(value, sizeof(value), "failed(error %d)", result);
+	format_and_print(outf, 5, header, value);
+
+	format_and_print(outf, 1, NULL, NULL);
+}
diff --git a/tools/power/x86/intel-speed-select/isst.h b/tools/power/x86/intel-speed-select/isst.h
new file mode 100644
index 0000000..d280b27
--- /dev/null
+++ b/tools/power/x86/intel-speed-select/isst.h
@@ -0,0 +1,240 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Intel Speed Select -- Enumerate and control features
+ * Copyright (c) 2019 Intel Corporation.
+ */
+
+#ifndef _ISST_H_
+#define _ISST_H_
+
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sched.h>
+#include <sys/stat.h>
+#include <sys/resource.h>
+#include <getopt.h>
+#include <err.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <sys/time.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
+#include <cpuid.h>
+#include <dirent.h>
+#include <errno.h>
+
+#include <stdarg.h>
+#include <sys/ioctl.h>
+
+#define BIT(x) (1 << (x))
+#define GENMASK(h, l) (((~0UL) << (l)) & (~0UL >> (sizeof(long) * 8 - 1 - (h))))
+#define GENMASK_ULL(h, l)                                                      \
+	(((~0ULL) << (l)) & (~0ULL >> (sizeof(long long) * 8 - 1 - (h))))
+
+#define CONFIG_TDP				0x7f
+#define CONFIG_TDP_GET_LEVELS_INFO		0x00
+#define CONFIG_TDP_GET_TDP_CONTROL		0x01
+#define CONFIG_TDP_SET_TDP_CONTROL		0x02
+#define CONFIG_TDP_GET_TDP_INFO			0x03
+#define CONFIG_TDP_GET_PWR_INFO			0x04
+#define CONFIG_TDP_GET_TJMAX_INFO		0x05
+#define CONFIG_TDP_GET_CORE_MASK		0x06
+#define CONFIG_TDP_GET_TURBO_LIMIT_RATIOS	0x07
+#define CONFIG_TDP_SET_LEVEL			0x08
+#define CONFIG_TDP_GET_UNCORE_P0_P1_INFO	0X09
+#define CONFIG_TDP_GET_P1_INFO			0x0a
+#define CONFIG_TDP_GET_MEM_FREQ			0x0b
+
+#define CONFIG_TDP_GET_FACT_HP_TURBO_LIMIT_NUMCORES	0x10
+#define CONFIG_TDP_GET_FACT_HP_TURBO_LIMIT_RATIOS	0x11
+#define CONFIG_TDP_GET_FACT_LP_CLIPPING_RATIO		0x12
+
+#define CONFIG_TDP_PBF_GET_CORE_MASK_INFO	0x20
+#define CONFIG_TDP_PBF_GET_P1HI_P1LO_INFO	0x21
+#define CONFIG_TDP_PBF_GET_TJ_MAX_INFO		0x22
+#define CONFIG_TDP_PBF_GET_TDP_INFO		0X23
+
+#define CONFIG_CLOS				0xd0
+#define CLOS_PQR_ASSOC				0x00
+#define CLOS_PM_CLOS				0x01
+#define CLOS_PM_QOS_CONFIG			0x02
+#define CLOS_STATUS				0x03
+
+#define MBOX_CMD_WRITE_BIT			0x08
+
+#define PM_QOS_INFO_OFFSET			0x00
+#define PM_QOS_CONFIG_OFFSET			0x04
+#define PM_CLOS_OFFSET				0x08
+#define PQR_ASSOC_OFFSET			0x20
+
+struct isst_clos_config {
+	int pkg_id;
+	int die_id;
+	unsigned char epp;
+	unsigned char clos_prop_prio;
+	unsigned char clos_min;
+	unsigned char clos_max;
+	unsigned char clos_desired;
+};
+
+struct isst_fact_bucket_info {
+	int high_priority_cores_count;
+	int sse_trl;
+	int avx_trl;
+	int avx512_trl;
+};
+
+struct isst_pbf_info {
+	int pbf_acticated;
+	int pbf_available;
+	size_t core_cpumask_size;
+	cpu_set_t *core_cpumask;
+	int p1_high;
+	int p1_low;
+	int t_control;
+	int t_prochot;
+	int tdp;
+};
+
+#define ISST_TRL_MAX_ACTIVE_CORES	8
+#define ISST_FACT_MAX_BUCKETS		8
+struct isst_fact_info {
+	int lp_clipping_ratio_license_sse;
+	int lp_clipping_ratio_license_avx2;
+	int lp_clipping_ratio_license_avx512;
+	struct isst_fact_bucket_info bucket_info[ISST_FACT_MAX_BUCKETS];
+};
+
+struct isst_pkg_ctdp_level_info {
+	int processed;
+	int control_cpu;
+	int pkg_id;
+	int die_id;
+	int level;
+	int fact_support;
+	int pbf_support;
+	int fact_enabled;
+	int pbf_enabled;
+	int tdp_ratio;
+	int active;
+	int tdp_control;
+	int pkg_tdp;
+	int pkg_min_power;
+	int pkg_max_power;
+	int fact;
+	int t_proc_hot;
+	int uncore_p0;
+	int uncore_p1;
+	int sse_p1;
+	int avx2_p1;
+	int avx512_p1;
+	int mem_freq;
+	size_t core_cpumask_size;
+	cpu_set_t *core_cpumask;
+	int cpu_count;
+	unsigned long long buckets_info;
+	int trl_sse_active_cores[ISST_TRL_MAX_ACTIVE_CORES];
+	int trl_avx_active_cores[ISST_TRL_MAX_ACTIVE_CORES];
+	int trl_avx_512_active_cores[ISST_TRL_MAX_ACTIVE_CORES];
+	int kobj_bucket_index;
+	int active_bucket;
+	int fact_max_index;
+	int fact_max_config;
+	int pbf_found;
+	int pbf_active;
+	struct isst_pbf_info pbf_info;
+	struct isst_fact_info fact_info;
+};
+
+#define ISST_MAX_TDP_LEVELS	(4 + 1) /* +1 for base config */
+struct isst_pkg_ctdp {
+	int locked;
+	int version;
+	int processed;
+	int levels;
+	int current_level;
+	int enabled;
+	struct isst_pkg_ctdp_level_info ctdp_level[ISST_MAX_TDP_LEVELS];
+};
+
+extern int get_topo_max_cpus(void);
+extern int get_cpu_count(int pkg_id, int die_id);
+
+/* Common interfaces */
+extern void debug_printf(const char *format, ...);
+extern int out_format_is_json(void);
+extern int get_physical_package_id(int cpu);
+extern int get_physical_die_id(int cpu);
+extern size_t alloc_cpu_set(cpu_set_t **cpu_set);
+extern void free_cpu_set(cpu_set_t *cpu_set);
+extern int find_logical_cpu(int pkg_id, int die_id, int phy_cpu);
+extern int find_phy_cpu_num(int logical_cpu);
+extern int find_phy_core_num(int logical_cpu);
+extern void set_cpu_mask_from_punit_coremask(int cpu,
+					     unsigned long long core_mask,
+					     size_t core_cpumask_size,
+					     cpu_set_t *core_cpumask,
+					     int *cpu_cnt);
+
+extern int isst_send_mbox_command(unsigned int cpu, unsigned char command,
+				  unsigned char sub_command,
+				  unsigned int write,
+				  unsigned int req_data, unsigned int *resp);
+
+extern int isst_send_msr_command(unsigned int cpu, unsigned int command,
+				 int write, unsigned long long *req_resp);
+
+extern int isst_get_ctdp_levels(int cpu, struct isst_pkg_ctdp *pkg_dev);
+extern int isst_get_coremask_info(int cpu, int config_index,
+			   struct isst_pkg_ctdp_level_info *ctdp_level);
+extern int isst_get_process_ctdp(int cpu, int tdp_level,
+				 struct isst_pkg_ctdp *pkg_dev);
+extern void isst_get_process_ctdp_complete(int cpu,
+					   struct isst_pkg_ctdp *pkg_dev);
+extern void isst_ctdp_display_information(int cpu, FILE *outf, int tdp_level,
+					  struct isst_pkg_ctdp *pkg_dev);
+extern void isst_ctdp_display_core_info(int cpu, FILE *outf, char *prefix,
+					unsigned int val);
+extern void isst_ctdp_display_information_start(FILE *outf);
+extern void isst_ctdp_display_information_end(FILE *outf);
+extern void isst_pbf_display_information(int cpu, FILE *outf, int level,
+					 struct isst_pbf_info *info);
+extern int isst_set_tdp_level(int cpu, int tdp_level);
+extern int isst_set_tdp_level_msr(int cpu, int tdp_level);
+extern int isst_set_pbf_fact_status(int cpu, int pbf, int enable);
+extern int isst_get_pbf_info(int cpu, int level,
+			     struct isst_pbf_info *pbf_info);
+extern void isst_get_pbf_info_complete(struct isst_pbf_info *pbf_info);
+extern int isst_get_fact_info(int cpu, int level,
+			      struct isst_fact_info *fact_info);
+extern int isst_get_fact_bucket_info(int cpu, int level,
+				     struct isst_fact_bucket_info *bucket_info);
+extern void isst_fact_display_information(int cpu, FILE *outf, int level,
+					  int fact_bucket, int fact_avx,
+					  struct isst_fact_info *fact_info);
+extern int isst_set_trl(int cpu, unsigned long long trl);
+extern int isst_set_trl_from_current_tdp(int cpu, unsigned long long trl);
+extern int isst_get_config_tdp_lock_status(int cpu);
+
+extern int isst_pm_qos_config(int cpu, int enable_clos, int priority_type);
+extern int isst_pm_get_clos(int cpu, int clos,
+			    struct isst_clos_config *clos_config);
+extern int isst_set_clos(int cpu, int clos,
+			 struct isst_clos_config *clos_config);
+extern int isst_clos_associate(int cpu, int clos);
+extern int isst_clos_get_assoc_status(int cpu, int *clos_id);
+extern void isst_clos_display_information(int cpu, FILE *outf, int clos,
+					  struct isst_clos_config *clos_config);
+extern void isst_clos_display_assoc_information(int cpu, FILE *outf, int clos);
+extern int isst_read_reg(unsigned short reg, unsigned int *val);
+extern int isst_write_reg(int reg, unsigned int val);
+
+extern void isst_display_result(int cpu, FILE *outf, char *feature, char *cmd,
+				int result);
+
+extern int isst_clos_get_clos_information(int cpu, int *enable, int *type);
+extern void isst_clos_display_clos_information(int cpu, FILE *outf,
+					       int clos_enable, int type);
+#endif
diff --git a/tools/power/x86/intel_pstate_tracer/intel_pstate_tracer.py b/tools/power/x86/intel_pstate_tracer/intel_pstate_tracer.py
index 84e2b64..2d6d342 100755
--- a/tools/power/x86/intel_pstate_tracer/intel_pstate_tracer.py
+++ b/tools/power/x86/intel_pstate_tracer/intel_pstate_tracer.py
@@ -1,4 +1,5 @@
 #!/usr/bin/python
+# SPDX-License-Identifier: GPL-2.0-only
 # -*- coding: utf-8 -*-
 #
 """ This utility can be used to debug and tune the performance of the
@@ -585,9 +586,9 @@
 
 read_trace_data(filename)
 
-clear_trace_file()
-# Free the memory
 if interval:
+    clear_trace_file()
+    # Free the memory
     free_trace_buffer()
 
 if graph_data_present == False:
diff --git a/tools/power/x86/turbostat/Makefile b/tools/power/x86/turbostat/Makefile
index 2ab25aa..13f1e8b 100644
--- a/tools/power/x86/turbostat/Makefile
+++ b/tools/power/x86/turbostat/Makefile
@@ -9,13 +9,14 @@
 endif
 
 turbostat : turbostat.c
-CFLAGS +=	-Wall
-CFLAGS +=	-DMSRHEADER='"../../../../arch/x86/include/asm/msr-index.h"'
-CFLAGS +=	-DINTEL_FAMILY_HEADER='"../../../../arch/x86/include/asm/intel-family.h"'
+override CFLAGS +=	-O2 -Wall -I../../../include
+override CFLAGS +=	-DMSRHEADER='"../../../../arch/x86/include/asm/msr-index.h"'
+override CFLAGS +=	-DINTEL_FAMILY_HEADER='"../../../../arch/x86/include/asm/intel-family.h"'
+override CFLAGS +=	-D_FORTIFY_SOURCE=2
 
 %: %.c
 	@mkdir -p $(BUILD_OUTPUT)
-	$(CC) $(CFLAGS) $< -o $(BUILD_OUTPUT)/$@
+	$(CC) $(CFLAGS) $< -o $(BUILD_OUTPUT)/$@ $(LDFLAGS)
 
 .PHONY : clean
 clean :
diff --git a/tools/power/x86/turbostat/turbostat.c b/tools/power/x86/turbostat/turbostat.c
index 980bd9d..5d0fddd 100644
--- a/tools/power/x86/turbostat/turbostat.c
+++ b/tools/power/x86/turbostat/turbostat.c
@@ -1,22 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  * turbostat -- show CPU frequency and C-state residency
- * on modern Intel turbo-capable processors.
+ * on modern Intel and AMD processors.
  *
  * Copyright (c) 2013 Intel Corporation.
  * Len Brown <len.brown@intel.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
  */
 
 #define _GNU_SOURCE
@@ -44,13 +32,13 @@
 #include <cpuid.h>
 #include <linux/capability.h>
 #include <errno.h>
+#include <math.h>
 
 char *proc_stat = "/proc/stat";
 FILE *outf;
 int *fd_percpu;
 struct timeval interval_tv = {5, 0};
 struct timespec interval_ts = {5, 0};
-struct timespec one_msec = {0, 1000000};
 unsigned int num_iterations;
 unsigned int debug;
 unsigned int quiet;
@@ -63,7 +51,6 @@
 unsigned int do_snb_cstates;
 unsigned int do_knl_cstates;
 unsigned int do_slm_cstates;
-unsigned int do_cnl_cstates;
 unsigned int use_c1_residency_msr;
 unsigned int has_aperf;
 unsigned int has_epb;
@@ -71,6 +58,9 @@
 unsigned int do_irtl_hsw;
 unsigned int units = 1000000;	/* MHz etc */
 unsigned int genuine_intel;
+unsigned int authentic_amd;
+unsigned int hygon_genuine;
+unsigned int max_level, max_extended_level;
 unsigned int has_invariant_tsc;
 unsigned int do_nhm_platform_info;
 unsigned int no_MSR_MISC_PWR_MGMT;
@@ -110,6 +100,7 @@
 unsigned int has_hwp_pkg;		/* IA32_HWP_REQUEST_PKG */
 unsigned int has_misc_feature_control;
 unsigned int first_counter_read = 1;
+int ignore_stdin;
 
 #define RAPL_PKG		(1 << 0)
 					/* 0x610 MSR_PKG_POWER_LIMIT */
@@ -139,9 +130,21 @@
 
 #define RAPL_CORES_ENERGY_STATUS	(1 << 9)
 					/* 0x639 MSR_PP0_ENERGY_STATUS */
+#define RAPL_PER_CORE_ENERGY	(1 << 10)
+					/* Indicates cores energy collection is per-core,
+					 * not per-package. */
+#define RAPL_AMD_F17H		(1 << 11)
+					/* 0xc0010299 MSR_RAPL_PWR_UNIT */
+					/* 0xc001029a MSR_CORE_ENERGY_STAT */
+					/* 0xc001029b MSR_PKG_ENERGY_STAT */
 #define RAPL_CORES (RAPL_CORES_ENERGY_STATUS | RAPL_CORES_POWER_LIMIT)
 #define	TJMAX_DEFAULT	100
 
+/* MSRs that are not yet in the kernel-provided header. */
+#define MSR_RAPL_PWR_UNIT	0xc0010299
+#define MSR_CORE_ENERGY_STAT	0xc001029a
+#define MSR_PKG_ENERGY_STAT	0xc001029b
+
 #define MAX(a, b) ((a) > (b) ? (a) : (b))
 
 /*
@@ -164,6 +167,7 @@
 struct thread_data {
 	struct timeval tv_begin;
 	struct timeval tv_end;
+	struct timeval tv_delta;
 	unsigned long long tsc;
 	unsigned long long aperf;
 	unsigned long long mperf;
@@ -185,6 +189,7 @@
 	unsigned long long c7;
 	unsigned long long mc6_us;	/* duplicate as per-core for now, even though per module */
 	unsigned int core_temp_c;
+	unsigned int core_energy;	/* MSR_CORE_ENERGY_STAT */
 	unsigned int core_id;
 	unsigned long long counter[MAX_ADDED_COUNTERS];
 } *core_even, *core_odd;
@@ -271,6 +276,7 @@
 
 struct cpu_topology {
 	int physical_package_id;
+	int die_id;
 	int logical_cpu_id;
 	int physical_node_id;
 	int logical_node_id;	/* 0-based count within the package */
@@ -281,6 +287,7 @@
 
 struct topo_params {
 	int num_packages;
+	int num_die;
 	int num_cpus;
 	int num_cores;
 	int max_cpu_num;
@@ -312,9 +319,8 @@
 	int retval, pkg_no, core_no, thread_no, node_no;
 
 	for (pkg_no = 0; pkg_no < topo.num_packages; ++pkg_no) {
-		for (core_no = 0; core_no < topo.cores_per_node; ++core_no) {
-			for (node_no = 0; node_no < topo.nodes_per_pkg;
-			     node_no++) {
+		for (node_no = 0; node_no < topo.nodes_per_pkg; node_no++) {
+			for (core_no = 0; core_no < topo.cores_per_node; ++core_no) {
 				for (thread_no = 0; thread_no <
 					topo.threads_per_core; ++thread_no) {
 					struct thread_data *t;
@@ -440,6 +446,7 @@
 	{ 0x0, "CPU" },
 	{ 0x0, "APIC" },
 	{ 0x0, "X2APIC" },
+	{ 0x0, "Die" },
 };
 
 #define MAX_BIC (sizeof(bic) / sizeof(struct msr_counter))
@@ -493,6 +500,7 @@
 #define	BIC_CPU		(1ULL << 47)
 #define	BIC_APIC	(1ULL << 48)
 #define	BIC_X2APIC	(1ULL << 49)
+#define	BIC_Die		(1ULL << 50)
 
 #define BIC_DISABLED_BY_DEFAULT	(BIC_USEC | BIC_TOD | BIC_APIC | BIC_X2APIC)
 
@@ -500,6 +508,7 @@
 unsigned long long bic_present = BIC_USEC | BIC_TOD | BIC_sysfs | BIC_APIC | BIC_X2APIC;
 
 #define DO_BIC(COUNTER_NAME) (bic_enabled & bic_present & COUNTER_NAME)
+#define DO_BIC_READ(COUNTER_NAME) (bic_present & COUNTER_NAME)
 #define ENABLE_BIC(COUNTER_NAME) (bic_enabled |= COUNTER_NAME)
 #define BIC_PRESENT(COUNTER_BIT) (bic_present |= COUNTER_BIT)
 #define BIC_NOT_PRESENT(COUNTER_BIT) (bic_present &= ~COUNTER_BIT)
@@ -619,6 +628,8 @@
 		outp += sprintf(outp, "%sTime_Of_Day_Seconds", (printed++ ? delim : ""));
 	if (DO_BIC(BIC_Package))
 		outp += sprintf(outp, "%sPackage", (printed++ ? delim : ""));
+	if (DO_BIC(BIC_Die))
+		outp += sprintf(outp, "%sDie", (printed++ ? delim : ""));
 	if (DO_BIC(BIC_Node))
 		outp += sprintf(outp, "%sNode", (printed++ ? delim : ""));
 	if (DO_BIC(BIC_Core))
@@ -665,7 +676,7 @@
 
 	if (DO_BIC(BIC_CPU_c1))
 		outp += sprintf(outp, "%sCPU%%c1", (printed++ ? delim : ""));
-	if (DO_BIC(BIC_CPU_c3) && !do_slm_cstates && !do_knl_cstates && !do_cnl_cstates)
+	if (DO_BIC(BIC_CPU_c3))
 		outp += sprintf(outp, "%sCPU%%c3", (printed++ ? delim : ""));
 	if (DO_BIC(BIC_CPU_c6))
 		outp += sprintf(outp, "%sCPU%%c6", (printed++ ? delim : ""));
@@ -678,6 +689,14 @@
 	if (DO_BIC(BIC_CoreTmp))
 		outp += sprintf(outp, "%sCoreTmp", (printed++ ? delim : ""));
 
+	if (do_rapl && !rapl_joules) {
+		if (DO_BIC(BIC_CorWatt) && (do_rapl & RAPL_PER_CORE_ENERGY))
+			outp += sprintf(outp, "%sCorWatt", (printed++ ? delim : ""));
+	} else if (do_rapl && rapl_joules) {
+		if (DO_BIC(BIC_Cor_J) && (do_rapl & RAPL_PER_CORE_ENERGY))
+			outp += sprintf(outp, "%sCor_J", (printed++ ? delim : ""));
+	}
+
 	for (mp = sys.cp; mp; mp = mp->next) {
 		if (mp->format == FORMAT_RAW) {
 			if (mp->width == 64)
@@ -732,7 +751,7 @@
 	if (do_rapl && !rapl_joules) {
 		if (DO_BIC(BIC_PkgWatt))
 			outp += sprintf(outp, "%sPkgWatt", (printed++ ? delim : ""));
-		if (DO_BIC(BIC_CorWatt))
+		if (DO_BIC(BIC_CorWatt) && !(do_rapl & RAPL_PER_CORE_ENERGY))
 			outp += sprintf(outp, "%sCorWatt", (printed++ ? delim : ""));
 		if (DO_BIC(BIC_GFXWatt))
 			outp += sprintf(outp, "%sGFXWatt", (printed++ ? delim : ""));
@@ -745,7 +764,7 @@
 	} else if (do_rapl && rapl_joules) {
 		if (DO_BIC(BIC_Pkg_J))
 			outp += sprintf(outp, "%sPkg_J", (printed++ ? delim : ""));
-		if (DO_BIC(BIC_Cor_J))
+		if (DO_BIC(BIC_Cor_J) && !(do_rapl & RAPL_PER_CORE_ENERGY))
 			outp += sprintf(outp, "%sCor_J", (printed++ ? delim : ""));
 		if (DO_BIC(BIC_GFX_J))
 			outp += sprintf(outp, "%sGFX_J", (printed++ ? delim : ""));
@@ -806,6 +825,7 @@
 		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);
+		outp += sprintf(outp, "Joules: %0X\n", c->core_energy);
 
 		for (i = 0, mp = sys.cp; mp; i++, mp = mp->next) {
 			outp += sprintf(outp, "cADDED [%d] msr0x%x: %08llX\n",
@@ -832,7 +852,6 @@
 		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, "pc10: %016llX\n", p->pc10);
 		outp += sprintf(outp, "cpu_lpi: %016llX\n", p->cpu_lpi);
 		outp += sprintf(outp, "sys_lpi: %016llX\n", p->sys_lpi);
 		outp += sprintf(outp, "Joules PKG: %0X\n", p->energy_pkg);
@@ -894,7 +913,7 @@
 	if (DO_BIC(BIC_TOD))
 		outp += sprintf(outp, "%10ld.%06ld\t", t->tv_end.tv_sec, t->tv_end.tv_usec);
 
-	interval_float = tv_delta.tv_sec + tv_delta.tv_usec/1000000.0;
+	interval_float = t->tv_delta.tv_sec + t->tv_delta.tv_usec/1000000.0;
 
 	tsc = t->tsc * tsc_tweak;
 
@@ -902,6 +921,8 @@
 	if (t == &average.threads) {
 		if (DO_BIC(BIC_Package))
 			outp += sprintf(outp, "%s-", (printed++ ? delim : ""));
+		if (DO_BIC(BIC_Die))
+			outp += sprintf(outp, "%s-", (printed++ ? delim : ""));
 		if (DO_BIC(BIC_Node))
 			outp += sprintf(outp, "%s-", (printed++ ? delim : ""));
 		if (DO_BIC(BIC_Core))
@@ -919,6 +940,12 @@
 			else
 				outp += sprintf(outp, "%s-", (printed++ ? delim : ""));
 		}
+		if (DO_BIC(BIC_Die)) {
+			if (c)
+				outp += sprintf(outp, "%s%d", (printed++ ? delim : ""), cpus[t->cpu_id].die_id);
+			else
+				outp += sprintf(outp, "%s-", (printed++ ? delim : ""));
+		}
 		if (DO_BIC(BIC_Node)) {
 			if (t)
 				outp += sprintf(outp, "%s%d",
@@ -1001,7 +1028,7 @@
 	if (!(t->flags & CPU_IS_FIRST_THREAD_IN_CORE))
 		goto done;
 
-	if (DO_BIC(BIC_CPU_c3) && !do_slm_cstates && !do_knl_cstates && !do_cnl_cstates)
+	if (DO_BIC(BIC_CPU_c3))
 		outp += sprintf(outp, "%s%.2f", (printed++ ? delim : ""), 100.0 * c->c3/tsc);
 	if (DO_BIC(BIC_CPU_c6))
 		outp += sprintf(outp, "%s%.2f", (printed++ ? delim : ""), 100.0 * c->c6/tsc);
@@ -1031,6 +1058,20 @@
 		}
 	}
 
+	/*
+	 * If measurement interval exceeds minimum RAPL Joule Counter range,
+	 * indicate that results are suspect by printing "**" in fraction place.
+	 */
+	if (interval_float < rapl_joule_counter_range)
+		fmt8 = "%s%.2f";
+	else
+		fmt8 = "%6.0f**";
+
+	if (DO_BIC(BIC_CorWatt) && (do_rapl & RAPL_PER_CORE_ENERGY))
+		outp += sprintf(outp, fmt8, (printed++ ? delim : ""), c->core_energy * rapl_energy_units / interval_float);
+	if (DO_BIC(BIC_Cor_J) && (do_rapl & RAPL_PER_CORE_ENERGY))
+		outp += sprintf(outp, fmt8, (printed++ ? delim : ""), c->core_energy * rapl_energy_units);
+
 	/* print per-package data only for 1st core in package */
 	if (!(t->flags & CPU_IS_FIRST_CORE_IN_PACKAGE))
 		goto done;
@@ -1083,18 +1124,9 @@
 	if (DO_BIC(BIC_SYS_LPI))
 		outp += sprintf(outp, "%s%.2f", (printed++ ? delim : ""), 100.0 * p->sys_lpi / 1000000.0 / interval_float);
 
-	/*
- 	 * If measurement interval exceeds minimum RAPL Joule Counter range,
- 	 * indicate that results are suspect by printing "**" in fraction place.
- 	 */
-	if (interval_float < rapl_joule_counter_range)
-		fmt8 = "%s%.2f";
-	else
-		fmt8 = "%6.0f**";
-
 	if (DO_BIC(BIC_PkgWatt))
 		outp += sprintf(outp, fmt8, (printed++ ? delim : ""), p->energy_pkg * rapl_energy_units / interval_float);
-	if (DO_BIC(BIC_CorWatt))
+	if (DO_BIC(BIC_CorWatt) && !(do_rapl & RAPL_PER_CORE_ENERGY))
 		outp += sprintf(outp, fmt8, (printed++ ? delim : ""), p->energy_cores * rapl_energy_units / interval_float);
 	if (DO_BIC(BIC_GFXWatt))
 		outp += sprintf(outp, fmt8, (printed++ ? delim : ""), p->energy_gfx * rapl_energy_units / interval_float);
@@ -1102,7 +1134,7 @@
 		outp += sprintf(outp, fmt8, (printed++ ? delim : ""), p->energy_dram * rapl_dram_energy_units / interval_float);
 	if (DO_BIC(BIC_Pkg_J))
 		outp += sprintf(outp, fmt8, (printed++ ? delim : ""), p->energy_pkg * rapl_energy_units);
-	if (DO_BIC(BIC_Cor_J))
+	if (DO_BIC(BIC_Cor_J) && !(do_rapl & RAPL_PER_CORE_ENERGY))
 		outp += sprintf(outp, fmt8, (printed++ ? delim : ""), p->energy_cores * rapl_energy_units);
 	if (DO_BIC(BIC_GFX_J))
 		outp += sprintf(outp, fmt8, (printed++ ? delim : ""), p->energy_gfx * rapl_energy_units);
@@ -1247,6 +1279,8 @@
 	old->core_temp_c = new->core_temp_c;
 	old->mc6_us = new->mc6_us - old->mc6_us;
 
+	DELTA_WRAP32(new->core_energy, old->core_energy);
+
 	for (i = 0, mp = sys.cp; mp; i++, mp = mp->next) {
 		if (mp->format == FORMAT_RAW)
 			old->counter[i] = new->counter[i];
@@ -1255,6 +1289,14 @@
 	}
 }
 
+int soft_c1_residency_display(int bic)
+{
+	if (!DO_BIC(BIC_CPU_c1) || use_c1_residency_msr)
+		return 0;
+
+	return DO_BIC_READ(bic);
+}
+
 /*
  * old = new - old
  */
@@ -1277,6 +1319,7 @@
 	 * over-write old w/ new so we can print end of interval values
 	 */
 
+	timersub(&new->tv_begin, &old->tv_begin, &old->tv_delta);
 	old->tv_begin = new->tv_begin;
 	old->tv_end = new->tv_end;
 
@@ -1290,7 +1333,8 @@
 
 	old->c1 = new->c1 - old->c1;
 
-	if (DO_BIC(BIC_Avg_MHz) || DO_BIC(BIC_Busy) || DO_BIC(BIC_Bzy_MHz)) {
+	if (DO_BIC(BIC_Avg_MHz) || DO_BIC(BIC_Busy) || DO_BIC(BIC_Bzy_MHz) ||
+	    soft_c1_residency_display(BIC_Avg_MHz)) {
 		if ((new->aperf > old->aperf) && (new->mperf > old->mperf)) {
 			old->aperf = new->aperf - old->aperf;
 			old->mperf = new->mperf - old->mperf;
@@ -1372,6 +1416,8 @@
 	t->tv_begin.tv_usec = 0;
 	t->tv_end.tv_sec = 0;
 	t->tv_end.tv_usec = 0;
+	t->tv_delta.tv_sec = 0;
+	t->tv_delta.tv_usec = 0;
 
 	t->tsc = 0;
 	t->aperf = 0;
@@ -1389,6 +1435,7 @@
 	c->c7 = 0;
 	c->mc6_us = 0;
 	c->core_temp_c = 0;
+	c->core_energy = 0;
 
 	p->pkg_wtd_core_c0 = 0;
 	p->pkg_any_core_c0 = 0;
@@ -1471,6 +1518,8 @@
 
 	average.cores.core_temp_c = MAX(average.cores.core_temp_c, c->core_temp_c);
 
+	average.cores.core_energy += c->core_energy;
+
 	for (i = 0, mp = sys.cp; mp; i++, mp = mp->next) {
 		if (mp->format == FORMAT_RAW)
 			continue;
@@ -1538,6 +1587,9 @@
 
 	for_all_cpus(sum_counters, t, c, p);
 
+	/* Use the global time delta for the average. */
+	average.threads.tv_delta = tv_delta;
+
 	average.threads.tsc /= topo.num_cpus;
 	average.threads.aperf /= topo.num_cpus;
 	average.threads.mperf /= topo.num_cpus;
@@ -1667,30 +1719,51 @@
 
 void get_apic_id(struct thread_data *t)
 {
-	unsigned int eax, ebx, ecx, edx, max_level;
+	unsigned int eax, ebx, ecx, edx;
 
-	eax = ebx = ecx = edx = 0;
+	if (DO_BIC(BIC_APIC)) {
+		eax = ebx = ecx = edx = 0;
+		__cpuid(1, eax, ebx, ecx, edx);
+
+		t->apic_id = (ebx >> 24) & 0xff;
+	}
+
+	if (!DO_BIC(BIC_X2APIC))
+		return;
+
+	if (authentic_amd || hygon_genuine) {
+		unsigned int topology_extensions;
+
+		if (max_extended_level < 0x8000001e)
+			return;
+
+		eax = ebx = ecx = edx = 0;
+		__cpuid(0x80000001, eax, ebx, ecx, edx);
+			topology_extensions = ecx & (1 << 22);
+
+		if (topology_extensions == 0)
+			return;
+
+		eax = ebx = ecx = edx = 0;
+		__cpuid(0x8000001e, eax, ebx, ecx, edx);
+
+		t->x2apic_id = eax;
+		return;
+	}
 
 	if (!genuine_intel)
 		return;
 
-	__cpuid(0, max_level, ebx, ecx, edx);
-
-	__cpuid(1, eax, ebx, ecx, edx);
-	t->apic_id = (ebx >> 24) & 0xf;
-
 	if (max_level < 0xb)
 		return;
 
-	if (!DO_BIC(BIC_X2APIC))
-		return;
-
 	ecx = 0;
 	__cpuid(0xb, eax, ebx, ecx, edx);
 	t->x2apic_id = edx;
 
-	if (debug && (t->apic_id != t->x2apic_id))
-		fprintf(outf, "cpu%d: apic 0x%x x2apic 0x%x\n", t->cpu_id, t->apic_id, t->x2apic_id);
+	if (debug && (t->apic_id != (t->x2apic_id & 0xff)))
+		fprintf(outf, "cpu%d: BIOS BUG: apic 0x%x x2apic 0x%x\n",
+				t->cpu_id, t->apic_id, t->x2apic_id);
 }
 
 /*
@@ -1706,19 +1779,20 @@
 	struct msr_counter *mp;
 	int i;
 
-	gettimeofday(&t->tv_begin, (struct timezone *)NULL);
-
 	if (cpu_migrate(cpu)) {
 		fprintf(outf, "Could not migrate to CPU %d\n", cpu);
 		return -1;
 	}
 
+	gettimeofday(&t->tv_begin, (struct timezone *)NULL);
+
 	if (first_counter_read)
 		get_apic_id(t);
 retry:
 	t->tsc = rdtsc();	/* we are running on local CPU of interest */
 
-	if (DO_BIC(BIC_Avg_MHz) || DO_BIC(BIC_Busy) || DO_BIC(BIC_Bzy_MHz)) {
+	if (DO_BIC(BIC_Avg_MHz) || DO_BIC(BIC_Busy) || DO_BIC(BIC_Bzy_MHz) ||
+	    soft_c1_residency_display(BIC_Avg_MHz)) {
 		unsigned long long tsc_before, tsc_between, tsc_after, aperf_time, mperf_time;
 
 		/*
@@ -1795,20 +1869,20 @@
 	if (!(t->flags & CPU_IS_FIRST_THREAD_IN_CORE))
 		goto done;
 
-	if (DO_BIC(BIC_CPU_c3) && !do_slm_cstates && !do_knl_cstates && !do_cnl_cstates) {
+	if (DO_BIC(BIC_CPU_c3) || soft_c1_residency_display(BIC_CPU_c3)) {
 		if (get_msr(cpu, MSR_CORE_C3_RESIDENCY, &c->c3))
 			return -6;
 	}
 
-	if (DO_BIC(BIC_CPU_c6) && !do_knl_cstates) {
+	if ((DO_BIC(BIC_CPU_c6) || soft_c1_residency_display(BIC_CPU_c6)) && !do_knl_cstates) {
 		if (get_msr(cpu, MSR_CORE_C6_RESIDENCY, &c->c6))
 			return -7;
-	} else if (do_knl_cstates) {
+	} else if (do_knl_cstates || soft_c1_residency_display(BIC_CPU_c6)) {
 		if (get_msr(cpu, MSR_KNL_CORE_C6_RESIDENCY, &c->c6))
 			return -7;
 	}
 
-	if (DO_BIC(BIC_CPU_c7))
+	if (DO_BIC(BIC_CPU_c7) || soft_c1_residency_display(BIC_CPU_c7))
 		if (get_msr(cpu, MSR_CORE_C7_RESIDENCY, &c->c7))
 			return -8;
 
@@ -1822,6 +1896,12 @@
 		c->core_temp_c = tcc_activation_temp - ((msr >> 16) & 0x7F);
 	}
 
+	if (do_rapl & RAPL_AMD_F17H) {
+		if (get_msr(cpu, MSR_CORE_ENERGY_STAT, &msr))
+			return -14;
+		c->core_energy = msr & 0xFFFFFFFF;
+	}
+
 	for (i = 0, mp = sys.cp; mp; i++, mp = mp->next) {
 		if (get_mp(cpu, mp, &c->counter[i]))
 			return -10;
@@ -1911,6 +1991,11 @@
 			return -16;
 		p->rapl_dram_perf_status = msr & 0xFFFFFFFF;
 	}
+	if (do_rapl & RAPL_AMD_F17H) {
+		if (get_msr(cpu, MSR_PKG_ENERGY_STAT, &msr))
+			return -13;
+		p->energy_pkg = msr & 0xFFFFFFFF;
+	}
 	if (DO_BIC(BIC_PkgTmp)) {
 		if (get_msr(cpu, MSR_IA32_PACKAGE_THERM_STATUS, &msr))
 			return -17;
@@ -1953,11 +2038,12 @@
 #define PCL_7S 11 /* PC7 Shrink */
 #define PCL__8 12 /* PC8 */
 #define PCL__9 13 /* PC9 */
-#define PCLUNL 14 /* Unlimited */
+#define PCL_10 14 /* PC10 */
+#define PCLUNL 15 /* Unlimited */
 
 int pkg_cstate_limit = PCLUKN;
 char *pkg_cstate_limit_strings[] = { "reserved", "unknown", "pc0", "pc1", "pc2",
-	"pc3", "pc4", "pc6", "pc6n", "pc6r", "pc7", "pc7s", "pc8", "pc9", "unlimited"};
+	"pc3", "pc4", "pc6", "pc6n", "pc6r", "pc7", "pc7s", "pc8", "pc9", "pc10", "unlimited"};
 
 int nhm_pkg_cstate_limits[16] = {PCL__0, PCL__1, PCL__3, PCL__6, PCL__7, PCLRSV, PCLRSV, PCLUNL, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV};
 int snb_pkg_cstate_limits[16] = {PCL__0, PCL__2, PCL_6N, PCL_6R, PCL__7, PCL_7S, PCLRSV, PCLUNL, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV};
@@ -1965,7 +2051,7 @@
 int slv_pkg_cstate_limits[16] = {PCL__0, PCL__1, PCLRSV, PCLRSV, PCL__4, PCLRSV, PCL__6, PCL__7, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCL__6, PCL__7};
 int amt_pkg_cstate_limits[16] = {PCLUNL, PCL__1, PCL__2, PCLRSV, PCLRSV, PCLRSV, PCL__6, PCL__7, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV};
 int phi_pkg_cstate_limits[16] = {PCL__0, PCL__2, PCL_6N, PCL_6R, PCLRSV, PCLRSV, PCLRSV, PCLUNL, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV};
-int bxt_pkg_cstate_limits[16] = {PCL__0, PCL__2, PCLUNL, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV};
+int glm_pkg_cstate_limits[16] = {PCLUNL, PCL__1, PCL__3, PCL__6, PCL__7, PCL_7S, PCL__8, PCL__9, PCL_10, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV};
 int skx_pkg_cstate_limits[16] = {PCL__0, PCL__2, PCL_6N, PCL_6R, PCLRSV, PCLRSV, PCLRSV, PCLUNL, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV, PCLRSV};
 
 
@@ -2082,7 +2168,7 @@
 	switch (model) {
 	case INTEL_FAM6_ATOM_GOLDMONT:
 	case INTEL_FAM6_SKYLAKE_X:
-	case INTEL_FAM6_ATOM_DENVERTON:
+	case INTEL_FAM6_ATOM_GOLDMONT_D:
 		return 1;
 	}
 	return 0;
@@ -2432,6 +2518,8 @@
 
 /*
  * Parse a file containing a single int.
+ * Return 0 if file can not be opened
+ * Exit if file can be opened, but can not be parsed
  */
 int parse_int_file(const char *fmt, ...)
 {
@@ -2443,7 +2531,9 @@
 	va_start(args, fmt);
 	vsnprintf(path, sizeof(path), fmt, args);
 	va_end(args);
-	filep = fopen_or_die(path, "r");
+	filep = fopen(path, "r");
+	if (!filep)
+		return 0;
 	if (fscanf(filep, "%d", &value) != 1)
 		err(1, "%s: failed to parse number from file", path);
 	fclose(filep);
@@ -2464,6 +2554,11 @@
 	return parse_int_file("/sys/devices/system/cpu/cpu%d/topology/physical_package_id", cpu);
 }
 
+int get_die_id(int cpu)
+{
+	return parse_int_file("/sys/devices/system/cpu/cpu%d/topology/die_id", cpu);
+}
+
 int get_core_id(int cpu)
 {
 	return parse_int_file("/sys/devices/system/cpu/cpu%d/topology/core_id", cpu);
@@ -2554,7 +2649,8 @@
 	filep = fopen_or_die(path, "r");
 	do {
 		offset -= BITMASK_SIZE;
-		fscanf(filep, "%lx%c", &map, &character);
+		if (fscanf(filep, "%lx%c", &map, &character) != 2)
+			err(1, "%s: failed to parse file", path);
 		for (shift = 0; shift < BITMASK_SIZE; shift++) {
 			if ((map >> shift) & 0x1) {
 				so = shift + offset;
@@ -2831,8 +2927,12 @@
 	fp = fopen_or_die("/sys/devices/system/cpu/cpuidle/low_power_idle_cpu_residency_us", "r");
 
 	retval = fscanf(fp, "%lld", &cpuidle_cur_cpu_lpi_us);
-	if (retval != 1)
-		err(1, "CPU LPI");
+	if (retval != 1) {
+		fprintf(stderr, "Disabling Low Power Idle CPU output\n");
+		BIC_NOT_PRESENT(BIC_CPU_LPI);
+		fclose(fp);
+		return -1;
+	}
 
 	fclose(fp);
 
@@ -2854,9 +2954,12 @@
 	fp = fopen_or_die("/sys/devices/system/cpu/cpuidle/low_power_idle_system_residency_us", "r");
 
 	retval = fscanf(fp, "%lld", &cpuidle_cur_sys_lpi_us);
-	if (retval != 1)
-		err(1, "SYS LPI");
-
+	if (retval != 1) {
+		fprintf(stderr, "Disabling Low Power Idle System output\n");
+		BIC_NOT_PRESENT(BIC_SYS_LPI);
+		fclose(fp);
+		return -1;
+	}
 	fclose(fp);
 
 	return 0;
@@ -2902,8 +3005,6 @@
 			fprintf(stderr, "SIGUSR1\n");
 		break;
 	}
-	/* make sure this manually-invoked interval is at least 1ms long */
-	nanosleep(&one_msec, NULL);
 }
 
 void setup_signal_handler(void)
@@ -2922,29 +3023,38 @@
 
 void do_sleep(void)
 {
-	struct timeval select_timeout;
+	struct timeval tout;
+	struct timespec rest;
 	fd_set readfds;
 	int retval;
 
 	FD_ZERO(&readfds);
 	FD_SET(0, &readfds);
 
-	if (!isatty(fileno(stdin))) {
+	if (ignore_stdin) {
 		nanosleep(&interval_ts, NULL);
 		return;
 	}
 
-	select_timeout = interval_tv;
-	retval = select(1, &readfds, NULL, NULL, &select_timeout);
+	tout = interval_tv;
+	retval = select(1, &readfds, NULL, NULL, &tout);
 
 	if (retval == 1) {
 		switch (getc(stdin)) {
 		case 'q':
 			exit_requested = 1;
 			break;
+		case EOF:
+			/*
+			 * 'stdin' is a pipe closed on the other end. There
+			 * won't be any further input.
+			 */
+			ignore_stdin = 1;
+			/* Sleep the rest of the time */
+			rest.tv_sec = (tout.tv_sec + tout.tv_usec / 1000000);
+			rest.tv_nsec = (tout.tv_usec % 1000000) * 1000;
+			nanosleep(&rest, NULL);
 		}
-		/* make sure this manually-invoked interval is at least 1ms long */
-		nanosleep(&one_msec, NULL);
 	}
 }
 
@@ -3113,13 +3223,8 @@
 	bclk = discover_bclk(family, model);
 
 	switch (model) {
-	case INTEL_FAM6_NEHALEM_EP:	/* Core i7, Xeon 5500 series - Bloomfield, Gainstown NHM-EP */
 	case INTEL_FAM6_NEHALEM:	/* Core i7 and i5 Processor - Clarksfield, Lynnfield, Jasper Forest */
-	case 0x1F:	/* Core i7 and i5 Processor - Nehalem */
-	case INTEL_FAM6_WESTMERE:	/* Westmere Client - Clarkdale, Arrandale */
-	case INTEL_FAM6_WESTMERE_EP:	/* Westmere EP - Gulftown */
 	case INTEL_FAM6_NEHALEM_EX:	/* Nehalem-EX Xeon - Beckton */
-	case INTEL_FAM6_WESTMERE_EX:	/* Westmere-EX Xeon - Eagleton */
 		pkg_cstate_limits = nhm_pkg_cstate_limits;
 		break;
 	case INTEL_FAM6_SANDYBRIDGE:	/* SNB */
@@ -3129,19 +3234,15 @@
 		pkg_cstate_limits = snb_pkg_cstate_limits;
 		has_misc_feature_control = 1;
 		break;
-	case INTEL_FAM6_HASWELL_CORE:	/* HSW */
+	case INTEL_FAM6_HASWELL:	/* HSW */
+	case INTEL_FAM6_HASWELL_G:	/* HSW */
 	case INTEL_FAM6_HASWELL_X:	/* HSX */
-	case INTEL_FAM6_HASWELL_ULT:	/* HSW */
-	case INTEL_FAM6_HASWELL_GT3E:	/* HSW */
-	case INTEL_FAM6_BROADWELL_CORE:	/* BDW */
-	case INTEL_FAM6_BROADWELL_GT3E:	/* BDW */
+	case INTEL_FAM6_HASWELL_L:	/* HSW */
+	case INTEL_FAM6_BROADWELL:	/* BDW */
+	case INTEL_FAM6_BROADWELL_G:	/* BDW */
 	case INTEL_FAM6_BROADWELL_X:	/* BDX */
-	case INTEL_FAM6_BROADWELL_XEON_D:	/* BDX-DE */
-	case INTEL_FAM6_SKYLAKE_MOBILE:	/* SKL */
-	case INTEL_FAM6_SKYLAKE_DESKTOP:	/* SKL */
-	case INTEL_FAM6_KABYLAKE_MOBILE:	/* KBL */
-	case INTEL_FAM6_KABYLAKE_DESKTOP:	/* KBL */
-	case INTEL_FAM6_CANNONLAKE_MOBILE:	/* CNL */
+	case INTEL_FAM6_SKYLAKE_L:	/* SKL */
+	case INTEL_FAM6_CANNONLAKE_L:	/* CNL */
 		pkg_cstate_limits = hsw_pkg_cstate_limits;
 		has_misc_feature_control = 1;
 		break;
@@ -3149,9 +3250,9 @@
 		pkg_cstate_limits = skx_pkg_cstate_limits;
 		has_misc_feature_control = 1;
 		break;
-	case INTEL_FAM6_ATOM_SILVERMONT1:	/* BYT */
+	case INTEL_FAM6_ATOM_SILVERMONT:	/* BYT */
 		no_MSR_MISC_PWR_MGMT = 1;
-	case INTEL_FAM6_ATOM_SILVERMONT2:	/* AVN */
+	case INTEL_FAM6_ATOM_SILVERMONT_D:	/* AVN */
 		pkg_cstate_limits = slv_pkg_cstate_limits;
 		break;
 	case INTEL_FAM6_ATOM_AIRMONT:	/* AMT */
@@ -3159,13 +3260,12 @@
 		no_MSR_MISC_PWR_MGMT = 1;
 		break;
 	case INTEL_FAM6_XEON_PHI_KNL:	/* PHI */
-	case INTEL_FAM6_XEON_PHI_KNM:
 		pkg_cstate_limits = phi_pkg_cstate_limits;
 		break;
 	case INTEL_FAM6_ATOM_GOLDMONT:	/* BXT */
-	case INTEL_FAM6_ATOM_GEMINI_LAKE:
-	case INTEL_FAM6_ATOM_DENVERTON:	/* DNV */
-		pkg_cstate_limits = bxt_pkg_cstate_limits;
+	case INTEL_FAM6_ATOM_GOLDMONT_PLUS:
+	case INTEL_FAM6_ATOM_GOLDMONT_D:	/* DNV */
+		pkg_cstate_limits = glm_pkg_cstate_limits;
 		break;
 	default:
 		return 0;
@@ -3193,9 +3293,9 @@
 		return 0;
 
 	switch (model) {
-	case INTEL_FAM6_ATOM_SILVERMONT1:
-	case INTEL_FAM6_ATOM_MERRIFIELD:
-	case INTEL_FAM6_ATOM_MOOREFIELD:
+	case INTEL_FAM6_ATOM_SILVERMONT:
+	case INTEL_FAM6_ATOM_SILVERMONT_MID:
+	case INTEL_FAM6_ATOM_AIRMONT_MID:
 		return 1;
 	}
 	return 0;
@@ -3207,7 +3307,7 @@
 		return 0;
 
 	switch (model) {
-	case INTEL_FAM6_ATOM_DENVERTON:
+	case INTEL_FAM6_ATOM_GOLDMONT_D:
 		return 1;
 	}
 	return 0;
@@ -3220,7 +3320,6 @@
 
 	switch (model) {
 	case INTEL_FAM6_BROADWELL_X:
-	case INTEL_FAM6_BROADWELL_XEON_D:
 		return 1;
 	}
 	return 0;
@@ -3246,9 +3345,7 @@
 	switch (model) {
 	/* Nehalem compatible, but do not include turbo-ratio limit support */
 	case INTEL_FAM6_NEHALEM_EX:	/* Nehalem-EX Xeon - Beckton */
-	case INTEL_FAM6_WESTMERE_EX:	/* Westmere-EX Xeon - Eagleton */
 	case INTEL_FAM6_XEON_PHI_KNL:	/* PHI - Knights Landing (different MSR definition) */
-	case INTEL_FAM6_XEON_PHI_KNM:
 		return 0;
 	default:
 		return 1;
@@ -3303,7 +3400,6 @@
 
 	switch (model) {
 	case INTEL_FAM6_XEON_PHI_KNL:	/* Knights Landing */
-	case INTEL_FAM6_XEON_PHI_KNM:
 		return 1;
 	default:
 		return 0;
@@ -3335,23 +3431,18 @@
 
 	switch (model) {
 	case INTEL_FAM6_IVYBRIDGE:	/* IVB */
-	case INTEL_FAM6_HASWELL_CORE:	/* HSW */
+	case INTEL_FAM6_HASWELL:	/* HSW */
 	case INTEL_FAM6_HASWELL_X:	/* HSX */
-	case INTEL_FAM6_HASWELL_ULT:	/* HSW */
-	case INTEL_FAM6_HASWELL_GT3E:	/* HSW */
-	case INTEL_FAM6_BROADWELL_CORE:	/* BDW */
-	case INTEL_FAM6_BROADWELL_GT3E:	/* BDW */
+	case INTEL_FAM6_HASWELL_L:	/* HSW */
+	case INTEL_FAM6_HASWELL_G:	/* HSW */
+	case INTEL_FAM6_BROADWELL:	/* BDW */
+	case INTEL_FAM6_BROADWELL_G:	/* BDW */
 	case INTEL_FAM6_BROADWELL_X:	/* BDX */
-	case INTEL_FAM6_BROADWELL_XEON_D:	/* BDX-DE */
-	case INTEL_FAM6_SKYLAKE_MOBILE:	/* SKL */
-	case INTEL_FAM6_SKYLAKE_DESKTOP:	/* SKL */
-	case INTEL_FAM6_KABYLAKE_MOBILE:	/* KBL */
-	case INTEL_FAM6_KABYLAKE_DESKTOP:	/* KBL */
-	case INTEL_FAM6_CANNONLAKE_MOBILE:	/* CNL */
+	case INTEL_FAM6_SKYLAKE_L:	/* SKL */
+	case INTEL_FAM6_CANNONLAKE_L:	/* CNL */
 	case INTEL_FAM6_SKYLAKE_X:	/* SKX */
 
 	case INTEL_FAM6_XEON_PHI_KNL:	/* Knights Landing */
-	case INTEL_FAM6_XEON_PHI_KNM:
 		return 1;
 	default:
 		return 0;
@@ -3407,14 +3498,14 @@
 		input = fopen(path, "r");
 		if (input == NULL)
 			continue;
-		fgets(name_buf, sizeof(name_buf), input);
+		if (!fgets(name_buf, sizeof(name_buf), input))
+			err(1, "%s: failed to read file", path);
 
 		 /* truncate "C1-HSW\n" to "C1", or truncate "C1\n" to "C1" */
 		sp = strchr(name_buf, '-');
 		if (!sp)
 			sp = strchrnul(name_buf, '\n');
 		*sp = '\0';
-
 		fclose(input);
 
 		sprintf(path, "/sys/devices/system/cpu/cpu%d/cpuidle/state%d/desc",
@@ -3422,7 +3513,8 @@
 		input = fopen(path, "r");
 		if (input == NULL)
 			continue;
-		fgets(desc, sizeof(desc), input);
+		if (!fgets(desc, sizeof(desc), input))
+			err(1, "%s: failed to read file", path);
 
 		fprintf(outf, "cpu%d: %s: %s", base_cpu, name_buf, desc);
 		fclose(input);
@@ -3441,20 +3533,22 @@
 			base_cpu);
 	input = fopen(path, "r");
 	if (input == NULL) {
-		fprintf(stderr, "NSFOD %s\n", path);
+		fprintf(outf, "NSFOD %s\n", path);
 		return;
 	}
-	fgets(driver_buf, sizeof(driver_buf), input);
+	if (!fgets(driver_buf, sizeof(driver_buf), input))
+		err(1, "%s: failed to read file", path);
 	fclose(input);
 
 	sprintf(path, "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_governor",
 			base_cpu);
 	input = fopen(path, "r");
 	if (input == NULL) {
-		fprintf(stderr, "NSFOD %s\n", path);
+		fprintf(outf, "NSFOD %s\n", path);
 		return;
 	}
-	fgets(governor_buf, sizeof(governor_buf), input);
+	if (!fgets(governor_buf, sizeof(governor_buf), input))
+		err(1, "%s: failed to read file", path);
 	fclose(input);
 
 	fprintf(outf, "cpu%d: cpufreq driver: %s", base_cpu, driver_buf);
@@ -3463,7 +3557,8 @@
 	sprintf(path, "/sys/devices/system/cpu/cpufreq/boost");
 	input = fopen(path, "r");
 	if (input != NULL) {
-		fscanf(input, "%d", &turbo);
+		if (fscanf(input, "%d", &turbo) != 1)
+			err(1, "%s: failed to parse number from file", path);
 		fprintf(outf, "cpufreq boost: %d\n", turbo);
 		fclose(input);
 	}
@@ -3471,7 +3566,8 @@
 	sprintf(path, "/sys/devices/system/cpu/intel_pstate/no_turbo");
 	input = fopen(path, "r");
 	if (input != NULL) {
-		fscanf(input, "%d", &turbo);
+		if (fscanf(input, "%d", &turbo) != 1)
+			err(1, "%s: failed to parse number from file", path);
 		fprintf(outf, "cpufreq intel_pstate no_turbo: %d\n", turbo);
 		fclose(input);
 	}
@@ -3715,7 +3811,7 @@
 #define	RAPL_POWER_GRANULARITY	0x7FFF	/* 15 bit power granularity */
 #define	RAPL_TIME_GRANULARITY	0x3F /* 6 bit time granularity */
 
-double get_tdp(unsigned int model)
+double get_tdp_intel(unsigned int model)
 {
 	unsigned long long msr;
 
@@ -3724,14 +3820,25 @@
 			return ((msr >> 0) & RAPL_POWER_GRANULARITY) * rapl_power_units;
 
 	switch (model) {
-	case INTEL_FAM6_ATOM_SILVERMONT1:
-	case INTEL_FAM6_ATOM_SILVERMONT2:
+	case INTEL_FAM6_ATOM_SILVERMONT:
+	case INTEL_FAM6_ATOM_SILVERMONT_D:
 		return 30.0;
 	default:
 		return 135.0;
 	}
 }
 
+double get_tdp_amd(unsigned int family)
+{
+	switch (family) {
+	case 0x17:
+	case 0x18:
+	default:
+		/* This is the max stock TDP of HEDT/Server Fam17h chips */
+		return 250.0;
+	}
+}
+
 /*
  * rapl_dram_energy_units_probe()
  * Energy units are either hard-coded, or come from RAPL Energy Unit MSR.
@@ -3744,41 +3851,30 @@
 	switch (model) {
 	case INTEL_FAM6_HASWELL_X:	/* HSX */
 	case INTEL_FAM6_BROADWELL_X:	/* BDX */
-	case INTEL_FAM6_BROADWELL_XEON_D:	/* BDX-DE */
 	case INTEL_FAM6_XEON_PHI_KNL:	/* KNL */
-	case INTEL_FAM6_XEON_PHI_KNM:
 		return (rapl_dram_energy_units = 15.3 / 1000000);
 	default:
 		return (rapl_energy_units);
 	}
 }
 
-
-/*
- * rapl_probe()
- *
- * sets do_rapl, rapl_power_units, rapl_energy_units, rapl_time_units
- */
-void rapl_probe(unsigned int family, unsigned int model)
+void rapl_probe_intel(unsigned int family, unsigned int model)
 {
 	unsigned long long msr;
 	unsigned int time_unit;
 	double tdp;
 
-	if (!genuine_intel)
-		return;
-
 	if (family != 6)
 		return;
 
 	switch (model) {
 	case INTEL_FAM6_SANDYBRIDGE:
 	case INTEL_FAM6_IVYBRIDGE:
-	case INTEL_FAM6_HASWELL_CORE:	/* HSW */
-	case INTEL_FAM6_HASWELL_ULT:	/* HSW */
-	case INTEL_FAM6_HASWELL_GT3E:	/* HSW */
-	case INTEL_FAM6_BROADWELL_CORE:	/* BDW */
-	case INTEL_FAM6_BROADWELL_GT3E:	/* BDW */
+	case INTEL_FAM6_HASWELL:	/* HSW */
+	case INTEL_FAM6_HASWELL_L:	/* HSW */
+	case INTEL_FAM6_HASWELL_G:	/* HSW */
+	case INTEL_FAM6_BROADWELL:	/* BDW */
+	case INTEL_FAM6_BROADWELL_G:	/* BDW */
 		do_rapl = RAPL_PKG | RAPL_CORES | RAPL_CORE_POLICY | RAPL_GFX | RAPL_PKG_POWER_INFO;
 		if (rapl_joules) {
 			BIC_PRESENT(BIC_Pkg_J);
@@ -3791,18 +3887,15 @@
 		}
 		break;
 	case INTEL_FAM6_ATOM_GOLDMONT:	/* BXT */
-	case INTEL_FAM6_ATOM_GEMINI_LAKE:
+	case INTEL_FAM6_ATOM_GOLDMONT_PLUS:
 		do_rapl = RAPL_PKG | RAPL_PKG_POWER_INFO;
 		if (rapl_joules)
 			BIC_PRESENT(BIC_Pkg_J);
 		else
 			BIC_PRESENT(BIC_PkgWatt);
 		break;
-	case INTEL_FAM6_SKYLAKE_MOBILE:	/* SKL */
-	case INTEL_FAM6_SKYLAKE_DESKTOP:	/* SKL */
-	case INTEL_FAM6_KABYLAKE_MOBILE:	/* KBL */
-	case INTEL_FAM6_KABYLAKE_DESKTOP:	/* KBL */
-	case INTEL_FAM6_CANNONLAKE_MOBILE:	/* CNL */
+	case INTEL_FAM6_SKYLAKE_L:	/* SKL */
+	case INTEL_FAM6_CANNONLAKE_L:	/* CNL */
 		do_rapl = RAPL_PKG | RAPL_CORES | RAPL_CORE_POLICY | RAPL_DRAM | RAPL_DRAM_PERF_STATUS | RAPL_PKG_PERF_STATUS | RAPL_GFX | RAPL_PKG_POWER_INFO;
 		BIC_PRESENT(BIC_PKG__);
 		BIC_PRESENT(BIC_RAM__);
@@ -3820,10 +3913,8 @@
 		break;
 	case INTEL_FAM6_HASWELL_X:	/* HSX */
 	case INTEL_FAM6_BROADWELL_X:	/* BDX */
-	case INTEL_FAM6_BROADWELL_XEON_D:	/* BDX-DE */
 	case INTEL_FAM6_SKYLAKE_X:	/* SKX */
 	case INTEL_FAM6_XEON_PHI_KNL:	/* KNL */
-	case INTEL_FAM6_XEON_PHI_KNM:
 		do_rapl = RAPL_PKG | RAPL_DRAM | RAPL_DRAM_POWER_INFO | RAPL_DRAM_PERF_STATUS | RAPL_PKG_PERF_STATUS | RAPL_PKG_POWER_INFO;
 		BIC_PRESENT(BIC_PKG__);
 		BIC_PRESENT(BIC_RAM__);
@@ -3850,8 +3941,8 @@
 			BIC_PRESENT(BIC_RAMWatt);
 		}
 		break;
-	case INTEL_FAM6_ATOM_SILVERMONT1:	/* BYT */
-	case INTEL_FAM6_ATOM_SILVERMONT2:	/* AVN */
+	case INTEL_FAM6_ATOM_SILVERMONT:	/* BYT */
+	case INTEL_FAM6_ATOM_SILVERMONT_D:	/* AVN */
 		do_rapl = RAPL_PKG | RAPL_CORES;
 		if (rapl_joules) {
 			BIC_PRESENT(BIC_Pkg_J);
@@ -3861,7 +3952,7 @@
 			BIC_PRESENT(BIC_CorWatt);
 		}
 		break;
-	case INTEL_FAM6_ATOM_DENVERTON:	/* DNV */
+	case INTEL_FAM6_ATOM_GOLDMONT_D:	/* DNV */
 		do_rapl = RAPL_PKG | RAPL_DRAM | RAPL_DRAM_POWER_INFO | RAPL_DRAM_PERF_STATUS | RAPL_PKG_PERF_STATUS | RAPL_PKG_POWER_INFO | RAPL_CORES_ENERGY_STATUS;
 		BIC_PRESENT(BIC_PKG__);
 		BIC_PRESENT(BIC_RAM__);
@@ -3884,7 +3975,7 @@
 		return;
 
 	rapl_power_units = 1.0 / (1 << (msr & 0xF));
-	if (model == INTEL_FAM6_ATOM_SILVERMONT1)
+	if (model == INTEL_FAM6_ATOM_SILVERMONT)
 		rapl_energy_units = 1.0 * (1 << (msr >> 8 & 0x1F)) / 1000000;
 	else
 		rapl_energy_units = 1.0 / (1 << (msr >> 8 & 0x1F));
@@ -3897,13 +3988,70 @@
 
 	rapl_time_units = 1.0 / (1 << (time_unit));
 
-	tdp = get_tdp(model);
+	tdp = get_tdp_intel(model);
 
 	rapl_joule_counter_range = 0xFFFFFFFF * rapl_energy_units / tdp;
 	if (!quiet)
 		fprintf(outf, "RAPL: %.0f sec. Joule Counter Range, at %.0f Watts\n", rapl_joule_counter_range, tdp);
+}
 
-	return;
+void rapl_probe_amd(unsigned int family, unsigned int model)
+{
+	unsigned long long msr;
+	unsigned int eax, ebx, ecx, edx;
+	unsigned int has_rapl = 0;
+	double tdp;
+
+	if (max_extended_level >= 0x80000007) {
+		__cpuid(0x80000007, eax, ebx, ecx, edx);
+		/* RAPL (Fam 17h) */
+		has_rapl = edx & (1 << 14);
+	}
+
+	if (!has_rapl)
+		return;
+
+	switch (family) {
+	case 0x17: /* Zen, Zen+ */
+	case 0x18: /* Hygon Dhyana */
+		do_rapl = RAPL_AMD_F17H | RAPL_PER_CORE_ENERGY;
+		if (rapl_joules) {
+			BIC_PRESENT(BIC_Pkg_J);
+			BIC_PRESENT(BIC_Cor_J);
+		} else {
+			BIC_PRESENT(BIC_PkgWatt);
+			BIC_PRESENT(BIC_CorWatt);
+		}
+		break;
+	default:
+		return;
+	}
+
+	if (get_msr(base_cpu, MSR_RAPL_PWR_UNIT, &msr))
+		return;
+
+	rapl_time_units = ldexp(1.0, -(msr >> 16 & 0xf));
+	rapl_energy_units = ldexp(1.0, -(msr >> 8 & 0x1f));
+	rapl_power_units = ldexp(1.0, -(msr & 0xf));
+
+	tdp = get_tdp_amd(family);
+
+	rapl_joule_counter_range = 0xFFFFFFFF * rapl_energy_units / tdp;
+	if (!quiet)
+		fprintf(outf, "RAPL: %.0f sec. Joule Counter Range, at %.0f Watts\n", rapl_joule_counter_range, tdp);
+}
+
+/*
+ * rapl_probe()
+ *
+ * sets do_rapl, rapl_power_units, rapl_energy_units, rapl_time_units
+ */
+void rapl_probe(unsigned int family, unsigned int model)
+{
+	if (genuine_intel)
+		rapl_probe_intel(family, model);
+	if (authentic_amd || hygon_genuine)
+		rapl_probe_amd(family, model);
 }
 
 void perf_limit_reasons_probe(unsigned int family, unsigned int model)
@@ -3915,9 +4063,9 @@
 		return;
 
 	switch (model) {
-	case INTEL_FAM6_HASWELL_CORE:	/* HSW */
-	case INTEL_FAM6_HASWELL_ULT:	/* HSW */
-	case INTEL_FAM6_HASWELL_GT3E:	/* HSW */
+	case INTEL_FAM6_HASWELL:	/* HSW */
+	case INTEL_FAM6_HASWELL_L:	/* HSW */
+	case INTEL_FAM6_HASWELL_G:	/* HSW */
 		do_gfx_perf_limit_reasons = 1;
 	case INTEL_FAM6_HASWELL_X:	/* HSX */
 		do_core_perf_limit_reasons = 1;
@@ -4009,6 +4157,7 @@
 int print_rapl(struct thread_data *t, struct core_data *c, struct pkg_data *p)
 {
 	unsigned long long msr;
+	const char *msr_name;
 	int cpu;
 
 	if (!do_rapl)
@@ -4024,10 +4173,17 @@
 		return -1;
 	}
 
-	if (get_msr(cpu, MSR_RAPL_POWER_UNIT, &msr))
-		return -1;
+	if (do_rapl & RAPL_AMD_F17H) {
+		msr_name = "MSR_RAPL_PWR_UNIT";
+		if (get_msr(cpu, MSR_RAPL_PWR_UNIT, &msr))
+			return -1;
+	} else {
+		msr_name = "MSR_RAPL_POWER_UNIT";
+		if (get_msr(cpu, MSR_RAPL_POWER_UNIT, &msr))
+			return -1;
+	}
 
-	fprintf(outf, "cpu%d: MSR_RAPL_POWER_UNIT: 0x%08llx (%f Watts, %f Joules, %f sec.)\n", cpu, msr,
+	fprintf(outf, "cpu%d: %s: 0x%08llx (%f Watts, %f Joules, %f sec.)\n", cpu, msr_name, msr,
 		rapl_power_units, rapl_energy_units, rapl_time_units);
 
 	if (do_rapl & RAPL_PKG_POWER_INFO) {
@@ -4124,32 +4280,28 @@
 	switch (model) {
 	case INTEL_FAM6_SANDYBRIDGE:
 	case INTEL_FAM6_SANDYBRIDGE_X:
-	case INTEL_FAM6_IVYBRIDGE:	/* IVB */
-	case INTEL_FAM6_IVYBRIDGE_X:	/* IVB Xeon */
-	case INTEL_FAM6_HASWELL_CORE:	/* HSW */
-	case INTEL_FAM6_HASWELL_X:	/* HSW */
-	case INTEL_FAM6_HASWELL_ULT:	/* HSW */
-	case INTEL_FAM6_HASWELL_GT3E:	/* HSW */
-	case INTEL_FAM6_BROADWELL_CORE:	/* BDW */
-	case INTEL_FAM6_BROADWELL_GT3E:	/* BDW */
-	case INTEL_FAM6_BROADWELL_X:	/* BDX */
-	case INTEL_FAM6_BROADWELL_XEON_D:	/* BDX-DE */
-	case INTEL_FAM6_SKYLAKE_MOBILE:	/* SKL */
-	case INTEL_FAM6_SKYLAKE_DESKTOP:	/* SKL */
-	case INTEL_FAM6_KABYLAKE_MOBILE:	/* KBL */
-	case INTEL_FAM6_KABYLAKE_DESKTOP:	/* KBL */
-	case INTEL_FAM6_CANNONLAKE_MOBILE:	/* CNL */
-	case INTEL_FAM6_SKYLAKE_X:	/* SKX */
-	case INTEL_FAM6_ATOM_GOLDMONT:	/* BXT */
-	case INTEL_FAM6_ATOM_GEMINI_LAKE:
-	case INTEL_FAM6_ATOM_DENVERTON:	/* DNV */
+	case INTEL_FAM6_IVYBRIDGE:		/* IVB */
+	case INTEL_FAM6_IVYBRIDGE_X:		/* IVB Xeon */
+	case INTEL_FAM6_HASWELL:		/* HSW */
+	case INTEL_FAM6_HASWELL_X:		/* HSW */
+	case INTEL_FAM6_HASWELL_L:		/* HSW */
+	case INTEL_FAM6_HASWELL_G:		/* HSW */
+	case INTEL_FAM6_BROADWELL:		/* BDW */
+	case INTEL_FAM6_BROADWELL_G:		/* BDW */
+	case INTEL_FAM6_BROADWELL_X:		/* BDX */
+	case INTEL_FAM6_SKYLAKE_L:		/* SKL */
+	case INTEL_FAM6_CANNONLAKE_L:		/* CNL */
+	case INTEL_FAM6_SKYLAKE_X:		/* SKX */
+	case INTEL_FAM6_ATOM_GOLDMONT:		/* BXT */
+	case INTEL_FAM6_ATOM_GOLDMONT_PLUS:
+	case INTEL_FAM6_ATOM_GOLDMONT_D:	/* DNV */
 		return 1;
 	}
 	return 0;
 }
 
 /*
- * HSW adds support for additional MSRs:
+ * HSW ULT added support for C8/C9/C10 MSRs:
  *
  * MSR_PKG_C8_RESIDENCY		0x00000630
  * MSR_PKG_C9_RESIDENCY		0x00000631
@@ -4160,21 +4312,18 @@
  * MSR_PKGC10_IRTL		0x00000635
  *
  */
-int has_hsw_msrs(unsigned int family, unsigned int model)
+int has_c8910_msrs(unsigned int family, unsigned int model)
 {
 	if (!genuine_intel)
 		return 0;
 
 	switch (model) {
-	case INTEL_FAM6_HASWELL_ULT:	/* HSW */
-	case INTEL_FAM6_BROADWELL_CORE:	/* BDW */
-	case INTEL_FAM6_SKYLAKE_MOBILE:	/* SKL */
-	case INTEL_FAM6_SKYLAKE_DESKTOP:	/* SKL */
-	case INTEL_FAM6_KABYLAKE_MOBILE:	/* KBL */
-	case INTEL_FAM6_KABYLAKE_DESKTOP:	/* KBL */
-	case INTEL_FAM6_CANNONLAKE_MOBILE:	/* CNL */
+	case INTEL_FAM6_HASWELL_L:	/* HSW */
+	case INTEL_FAM6_BROADWELL:	/* BDW */
+	case INTEL_FAM6_SKYLAKE_L:	/* SKL */
+	case INTEL_FAM6_CANNONLAKE_L:	/* CNL */
 	case INTEL_FAM6_ATOM_GOLDMONT:	/* BXT */
-	case INTEL_FAM6_ATOM_GEMINI_LAKE:
+	case INTEL_FAM6_ATOM_GOLDMONT_PLUS:
 		return 1;
 	}
 	return 0;
@@ -4194,11 +4343,8 @@
 		return 0;
 
 	switch (model) {
-	case INTEL_FAM6_SKYLAKE_MOBILE:	/* SKL */
-	case INTEL_FAM6_SKYLAKE_DESKTOP:	/* SKL */
-	case INTEL_FAM6_KABYLAKE_MOBILE:	/* KBL */
-	case INTEL_FAM6_KABYLAKE_DESKTOP:	/* KBL */
-	case INTEL_FAM6_CANNONLAKE_MOBILE:	/* CNL */
+	case INTEL_FAM6_SKYLAKE_L:	/* SKL */
+	case INTEL_FAM6_CANNONLAKE_L:	/* CNL */
 		return 1;
 	}
 	return 0;
@@ -4209,8 +4355,8 @@
 	if (!genuine_intel)
 		return 0;
 	switch (model) {
-	case INTEL_FAM6_ATOM_SILVERMONT1:	/* BYT */
-	case INTEL_FAM6_ATOM_SILVERMONT2:	/* AVN */
+	case INTEL_FAM6_ATOM_SILVERMONT:	/* BYT */
+	case INTEL_FAM6_ATOM_SILVERMONT_D:	/* AVN */
 		return 1;
 	}
 	return 0;
@@ -4222,7 +4368,6 @@
 		return 0;
 	switch (model) {
 	case INTEL_FAM6_XEON_PHI_KNL:	/* KNL */
-	case INTEL_FAM6_XEON_PHI_KNM:
 		return 1;
 	}
 	return 0;
@@ -4234,7 +4379,7 @@
 		return 0;
 
 	switch (model) {
-	case INTEL_FAM6_CANNONLAKE_MOBILE: /* CNL */
+	case INTEL_FAM6_CANNONLAKE_L: /* CNL */
 		return 1;
 	}
 
@@ -4436,18 +4581,62 @@
 			base_cpu, msr, msr & (1 << 0) ? "EN" : "DIS");
 }
 
+/*
+ * When models are the same, for the purpose of turbostat, reuse
+ */
+unsigned int intel_model_duplicates(unsigned int model)
+{
+
+	switch(model) {
+	case INTEL_FAM6_NEHALEM_EP:	/* Core i7, Xeon 5500 series - Bloomfield, Gainstown NHM-EP */
+	case INTEL_FAM6_NEHALEM:	/* Core i7 and i5 Processor - Clarksfield, Lynnfield, Jasper Forest */
+	case 0x1F:	/* Core i7 and i5 Processor - Nehalem */
+	case INTEL_FAM6_WESTMERE:	/* Westmere Client - Clarkdale, Arrandale */
+	case INTEL_FAM6_WESTMERE_EP:	/* Westmere EP - Gulftown */
+		return INTEL_FAM6_NEHALEM;
+
+	case INTEL_FAM6_NEHALEM_EX:	/* Nehalem-EX Xeon - Beckton */
+	case INTEL_FAM6_WESTMERE_EX:	/* Westmere-EX Xeon - Eagleton */
+		return INTEL_FAM6_NEHALEM_EX;
+
+	case INTEL_FAM6_XEON_PHI_KNM:
+		return INTEL_FAM6_XEON_PHI_KNL;
+
+	case INTEL_FAM6_BROADWELL_X:
+	case INTEL_FAM6_BROADWELL_D:	/* BDX-DE */
+		return INTEL_FAM6_BROADWELL_X;
+
+	case INTEL_FAM6_SKYLAKE_L:
+	case INTEL_FAM6_SKYLAKE:
+	case INTEL_FAM6_KABYLAKE_L:
+	case INTEL_FAM6_KABYLAKE:
+		return INTEL_FAM6_SKYLAKE_L;
+
+	case INTEL_FAM6_ICELAKE_L:
+	case INTEL_FAM6_ICELAKE_NNPI:
+		return INTEL_FAM6_CANNONLAKE_L;
+
+	case INTEL_FAM6_ATOM_TREMONT_D:
+		return INTEL_FAM6_ATOM_GOLDMONT_D;
+	}
+	return model;
+}
 void process_cpuid()
 {
-	unsigned int eax, ebx, ecx, edx, max_level, max_extended_level;
-	unsigned int fms, family, model, stepping;
+	unsigned int eax, ebx, ecx, edx;
+	unsigned int fms, family, model, stepping, ecx_flags, edx_flags;
 	unsigned int has_turbo;
 
 	eax = ebx = ecx = edx = 0;
 
 	__cpuid(0, max_level, ebx, ecx, edx);
 
-	if (ebx == 0x756e6547 && edx == 0x49656e69 && ecx == 0x6c65746e)
+	if (ebx == 0x756e6547 && ecx == 0x6c65746e && edx == 0x49656e69)
 		genuine_intel = 1;
+	else if (ebx == 0x68747541 && ecx == 0x444d4163 && edx == 0x69746e65)
+		authentic_amd = 1;
+	else if (ebx == 0x6f677948 && ecx == 0x656e6975 && edx == 0x6e65476e)
+		hygon_genuine = 1;
 
 	if (!quiet)
 		fprintf(outf, "CPUID(0): %.4s%.4s%.4s ",
@@ -4461,25 +4650,8 @@
 		family += (fms >> 20) & 0xff;
 	if (family >= 6)
 		model += ((fms >> 16) & 0xf) << 4;
-
-	if (!quiet) {
-		fprintf(outf, "%d CPUID levels; family:model:stepping 0x%x:%x:%x (%d:%d:%d)\n",
-			max_level, family, model, stepping, family, model, stepping);
-		fprintf(outf, "CPUID(1): %s %s %s %s %s %s %s %s %s %s\n",
-			ecx & (1 << 0) ? "SSE3" : "-",
-			ecx & (1 << 3) ? "MONITOR" : "-",
-			ecx & (1 << 6) ? "SMX" : "-",
-			ecx & (1 << 7) ? "EIST" : "-",
-			ecx & (1 << 8) ? "TM2" : "-",
-			edx & (1 << 4) ? "TSC" : "-",
-			edx & (1 << 5) ? "MSR" : "-",
-			edx & (1 << 22) ? "ACPI-TM" : "-",
-			edx & (1 << 28) ? "HT" : "-",
-			edx & (1 << 29) ? "TM" : "-");
-	}
-
-	if (!(edx & (1 << 5)))
-		errx(1, "CPUID: no MSR");
+	ecx_flags = ecx;
+	edx_flags = edx;
 
 	/*
 	 * check max extended function levels of CPUID.
@@ -4489,6 +4661,27 @@
 	ebx = ecx = edx = 0;
 	__cpuid(0x80000000, max_extended_level, ebx, ecx, edx);
 
+	if (!quiet) {
+		fprintf(outf, "0x%x CPUID levels; 0x%x xlevels; family:model:stepping 0x%x:%x:%x (%d:%d:%d)\n",
+			max_level, max_extended_level, family, model, stepping, family, model, stepping);
+		fprintf(outf, "CPUID(1): %s %s %s %s %s %s %s %s %s %s\n",
+			ecx_flags & (1 << 0) ? "SSE3" : "-",
+			ecx_flags & (1 << 3) ? "MONITOR" : "-",
+			ecx_flags & (1 << 6) ? "SMX" : "-",
+			ecx_flags & (1 << 7) ? "EIST" : "-",
+			ecx_flags & (1 << 8) ? "TM2" : "-",
+			edx_flags & (1 << 4) ? "TSC" : "-",
+			edx_flags & (1 << 5) ? "MSR" : "-",
+			edx_flags & (1 << 22) ? "ACPI-TM" : "-",
+			edx_flags & (1 << 28) ? "HT" : "-",
+			edx_flags & (1 << 29) ? "TM" : "-");
+	}
+	if (genuine_intel)
+		model = intel_model_duplicates(model);
+
+	if (!(edx_flags & (1 << 5)))
+		errx(1, "CPUID: no MSR");
+
 	if (max_extended_level >= 0x80000007) {
 
 		/*
@@ -4575,17 +4768,14 @@
 
 			if (crystal_hz == 0)
 				switch(model) {
-				case INTEL_FAM6_SKYLAKE_MOBILE:	/* SKL */
-				case INTEL_FAM6_SKYLAKE_DESKTOP:	/* SKL */
-				case INTEL_FAM6_KABYLAKE_MOBILE:	/* KBL */
-				case INTEL_FAM6_KABYLAKE_DESKTOP:	/* KBL */
+				case INTEL_FAM6_SKYLAKE_L:	/* SKL */
 					crystal_hz = 24000000;	/* 24.0 MHz */
 					break;
-				case INTEL_FAM6_ATOM_DENVERTON:	/* DNV */
+				case INTEL_FAM6_ATOM_GOLDMONT_D:	/* DNV */
 					crystal_hz = 25000000;	/* 25.0 MHz */
 					break;
 				case INTEL_FAM6_ATOM_GOLDMONT:	/* BXT */
-				case INTEL_FAM6_ATOM_GEMINI_LAKE:
+				case INTEL_FAM6_ATOM_GOLDMONT_PLUS:
 					crystal_hz = 19200000;	/* 19.2 MHz */
 					break;
 				default:
@@ -4667,12 +4857,12 @@
 		BIC_NOT_PRESENT(BIC_CPU_c7);
 		BIC_NOT_PRESENT(BIC_Pkgpc7);
 	}
-	if (has_hsw_msrs(family, model)) {
+	if (has_c8910_msrs(family, model)) {
 		BIC_PRESENT(BIC_Pkgpc8);
 		BIC_PRESENT(BIC_Pkgpc9);
 		BIC_PRESENT(BIC_Pkgpc10);
 	}
-	do_irtl_hsw = has_hsw_msrs(family, model);
+	do_irtl_hsw = has_c8910_msrs(family, model);
 	if (has_skl_msrs(family, model)) {
 		BIC_PRESENT(BIC_Totl_c0);
 		BIC_PRESENT(BIC_Any_c0);
@@ -4681,7 +4871,9 @@
 	}
 	do_slm_cstates = is_slm(family, model);
 	do_knl_cstates  = is_knl(family, model);
-	do_cnl_cstates = is_cnl(family, model);
+
+	if (do_slm_cstates || do_knl_cstates || is_cnl(family, model))
+		BIC_NOT_PRESENT(BIC_CPU_c3);
 
 	if (!quiet)
 		decode_misc_pwr_mgmt_msr();
@@ -4748,6 +4940,7 @@
 	int i;
 	int max_core_id = 0;
 	int max_package_id = 0;
+	int max_die_id = 0;
 	int max_siblings = 0;
 
 	/* Initialize num_cpus, max_cpu_num */
@@ -4814,6 +5007,11 @@
 		if (cpus[i].physical_package_id > max_package_id)
 			max_package_id = cpus[i].physical_package_id;
 
+		/* get die information */
+		cpus[i].die_id = get_die_id(i);
+		if (cpus[i].die_id > max_die_id)
+			max_die_id = cpus[i].die_id;
+
 		/* get numa node information */
 		cpus[i].physical_node_id = get_physical_node_id(&cpus[i]);
 		if (cpus[i].physical_node_id > topo.max_node_num)
@@ -4839,6 +5037,13 @@
 	if (!summary_only && topo.cores_per_node > 1)
 		BIC_PRESENT(BIC_Core);
 
+	topo.num_die = max_die_id + 1;
+	if (debug > 1)
+		fprintf(outf, "max_die_id %d, sizing for %d die\n",
+				max_die_id, topo.num_die);
+	if (!summary_only && topo.num_die > 1)
+		BIC_PRESENT(BIC_Die);
+
 	topo.num_packages = max_package_id + 1;
 	if (debug > 1)
 		fprintf(outf, "max_package_id %d, sizing for %d packages\n",
@@ -4860,9 +5065,11 @@
 		return;
 
 	for (i = 0; i <= topo.max_cpu_num; ++i) {
+		if (cpu_is_not_present(i))
+			continue;
 		fprintf(outf,
-			"cpu %d pkg %d node %d lnode %d core %d thread %d\n",
-			i, cpus[i].physical_package_id,
+			"cpu %d pkg %d die %d node %d lnode %d core %d thread %d\n",
+			i, cpus[i].physical_package_id, cpus[i].die_id,
 			cpus[i].physical_node_id,
 			cpus[i].logical_node_id,
 			cpus[i].physical_core_id,
@@ -4953,7 +5160,7 @@
 
 void allocate_output_buffer()
 {
-	output_buffer = calloc(1, (1 + topo.num_cpus) * 1024);
+	output_buffer = calloc(1, (1 + topo.num_cpus) * 2048);
 	outp = output_buffer;
 	if (outp == NULL)
 		err(-1, "calloc output buffer");
@@ -5054,6 +5261,9 @@
 		signal(SIGQUIT, SIG_IGN);
 		if (waitpid(child_pid, &status, 0) == -1)
 			err(status, "waitpid");
+
+		if (WIFEXITED(status))
+			status = WEXITSTATUS(status);
 	}
 	/*
 	 * n.b. fork_it() does not check for errors from for_all_cpus()
@@ -5096,7 +5306,7 @@
 }
 
 void print_version() {
-	fprintf(outf, "turbostat version 18.07.27"
+	fprintf(outf, "turbostat version 19.08.31"
 		" - Len Brown <lenb@kernel.org>\n");
 }
 
@@ -5293,7 +5503,8 @@
 		input = fopen(path, "r");
 		if (input == NULL)
 			continue;
-		fgets(name_buf, sizeof(name_buf), input);
+		if (!fgets(name_buf, sizeof(name_buf), input))
+			err(1, "%s: failed to read file", path);
 
 		 /* truncate "C1-HSW\n" to "C1", or truncate "C1\n" to "C1" */
 		sp = strchr(name_buf, '-');
@@ -5320,7 +5531,8 @@
 		input = fopen(path, "r");
 		if (input == NULL)
 			continue;
-		fgets(name_buf, sizeof(name_buf), input);
+		if (!fgets(name_buf, sizeof(name_buf), input))
+			err(1, "%s: failed to read file", path);
 		 /* truncate "C1-HSW\n" to "C1", or truncate "C1\n" to "C1" */
 		sp = strchr(name_buf, '-');
 		if (!sp)
diff --git a/tools/power/x86/x86_energy_perf_policy/Makefile b/tools/power/x86/x86_energy_perf_policy/Makefile
index f4534fb..666b325 100644
--- a/tools/power/x86/x86_energy_perf_policy/Makefile
+++ b/tools/power/x86/x86_energy_perf_policy/Makefile
@@ -9,12 +9,13 @@
 endif
 
 x86_energy_perf_policy : x86_energy_perf_policy.c
-CFLAGS +=	-Wall
-CFLAGS +=	-DMSRHEADER='"../../../../arch/x86/include/asm/msr-index.h"'
+override CFLAGS +=	-O2 -Wall -I../../../include
+override CFLAGS +=	-DMSRHEADER='"../../../../arch/x86/include/asm/msr-index.h"'
+override CFLAGS +=	-D_FORTIFY_SOURCE=2
 
 %: %.c
 	@mkdir -p $(BUILD_OUTPUT)
-	$(CC) $(CFLAGS) $< -o $(BUILD_OUTPUT)/$@
+	$(CC) $(CFLAGS) $< -o $(BUILD_OUTPUT)/$@ $(LDFLAGS)
 
 .PHONY : clean
 clean :
diff --git a/tools/power/x86/x86_energy_perf_policy/x86_energy_perf_policy.8 b/tools/power/x86/x86_energy_perf_policy/x86_energy_perf_policy.8
index 17db1c3..78c6361 100644
--- a/tools/power/x86/x86_energy_perf_policy/x86_energy_perf_policy.8
+++ b/tools/power/x86/x86_energy_perf_policy/x86_energy_perf_policy.8
@@ -40,7 +40,7 @@
 Hardware P-States (HWP) are effectively an expansion of hardware
 P-state control from the opportunistic turbo-mode P-state range
 to include the entire range of available P-states.
-On Broadwell Xeon, the initial HWP implementation, EBP influenced HWP.
+On Broadwell Xeon, the initial HWP implementation, EPB influenced HWP.
 That influence was removed in subsequent generations,
 where it was moved to the
 Energy_Performance_Preference (EPP) field in
diff --git a/tools/power/x86/x86_energy_perf_policy/x86_energy_perf_policy.c b/tools/power/x86/x86_energy_perf_policy/x86_energy_perf_policy.c
index 65bbe62..3fe1eed 100644
--- a/tools/power/x86/x86_energy_perf_policy/x86_energy_perf_policy.c
+++ b/tools/power/x86/x86_energy_perf_policy/x86_energy_perf_policy.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  * x86_energy_perf_policy -- set the energy versus performance
  * policy preference bias on recent X86 processors.
@@ -5,8 +6,6 @@
 /*
  * Copyright (c) 2010 - 2017 Intel Corporation.
  * Len Brown <len.brown@intel.com>
- *
- * This program is released under GPL v2
  */
 
 #define _GNU_SOURCE
@@ -546,7 +545,7 @@
 
 	progname = argv[0];
 
-	while ((opt = getopt_long_only(argc, argv, "+a:c:dD:E:e:f:m:M:rt:u:vw",
+	while ((opt = getopt_long_only(argc, argv, "+a:c:dD:E:e:f:m:M:rt:u:vw:",
 				long_options, &option_index)) != -1) {
 		switch (opt) {
 		case 'a':
@@ -1260,6 +1259,15 @@
 		if (system("/sbin/modprobe msr > /dev/null 2>&1"))
 			err(-5, "no /dev/cpu/0/msr, Try \"# modprobe msr\" ");
 }
+
+static void get_cpuid_or_exit(unsigned int leaf,
+			     unsigned int *eax, unsigned int *ebx,
+			     unsigned int *ecx, unsigned int *edx)
+{
+	if (!__get_cpuid(leaf, eax, ebx, ecx, edx))
+		errx(1, "Processor not supported\n");
+}
+
 /*
  * early_cpuid()
  * initialize turbo_is_enabled, has_hwp, has_epb
@@ -1267,15 +1275,10 @@
  */
 void early_cpuid(void)
 {
-	unsigned int eax, ebx, ecx, edx, max_level;
+	unsigned int eax, ebx, ecx, edx;
 	unsigned int fms, family, model;
 
-	__get_cpuid(0, &max_level, &ebx, &ecx, &edx);
-
-	if (max_level < 6)
-		errx(1, "Processor not supported\n");
-
-	__get_cpuid(1, &fms, &ebx, &ecx, &edx);
+	get_cpuid_or_exit(1, &fms, &ebx, &ecx, &edx);
 	family = (fms >> 8) & 0xf;
 	model = (fms >> 4) & 0xf;
 	if (family == 6 || family == 0xf)
@@ -1289,7 +1292,7 @@
 		bdx_highest_ratio = msr & 0xFF;
 	}
 
-	__get_cpuid(0x6, &eax, &ebx, &ecx, &edx);
+	get_cpuid_or_exit(0x6, &eax, &ebx, &ecx, &edx);
 	turbo_is_enabled = (eax >> 1) & 1;
 	has_hwp = (eax >> 7) & 1;
 	has_epb = (ecx >> 3) & 1;
@@ -1307,7 +1310,7 @@
 
 	eax = ebx = ecx = edx = 0;
 
-	__get_cpuid(0, &max_level, &ebx, &ecx, &edx);
+	get_cpuid_or_exit(0, &max_level, &ebx, &ecx, &edx);
 
 	if (ebx == 0x756e6547 && edx == 0x49656e69 && ecx == 0x6c65746e)
 		genuine_intel = 1;
@@ -1316,7 +1319,7 @@
 		fprintf(stderr, "CPUID(0): %.4s%.4s%.4s ",
 			(char *)&ebx, (char *)&edx, (char *)&ecx);
 
-	__get_cpuid(1, &fms, &ebx, &ecx, &edx);
+	get_cpuid_or_exit(1, &fms, &ebx, &ecx, &edx);
 	family = (fms >> 8) & 0xf;
 	model = (fms >> 4) & 0xf;
 	stepping = fms & 0xf;
@@ -1341,7 +1344,7 @@
 		errx(1, "CPUID: no MSR");
 
 
-	__get_cpuid(0x6, &eax, &ebx, &ecx, &edx);
+	get_cpuid_or_exit(0x6, &eax, &ebx, &ecx, &edx);
 	/* turbo_is_enabled already set */
 	/* has_hwp already set */
 	has_hwp_notify = eax & (1 << 8);