summaryrefslogtreecommitdiff
path: root/tools/power
diff options
context:
space:
mode:
Diffstat (limited to 'tools/power')
-rw-r--r--tools/power/acpi/.gitignore8
-rw-r--r--tools/power/acpi/Makefile5
-rw-r--r--tools/power/acpi/Makefile.config5
-rw-r--r--tools/power/acpi/Makefile.rules5
-rw-r--r--tools/power/acpi/tools/acpidbg/Makefile5
-rw-r--r--tools/power/acpi/tools/acpidbg/acpidbg.c5
-rw-r--r--tools/power/acpi/tools/acpidump/Makefile5
-rw-r--r--tools/power/acpi/tools/ec/Makefile5
-rw-r--r--tools/power/acpi/tools/ec/ec_access.c3
-rw-r--r--tools/power/cpupower/Makefile14
-rw-r--r--tools/power/cpupower/bench/benchmark.c15
-rw-r--r--tools/power/cpupower/bench/benchmark.h15
-rw-r--r--tools/power/cpupower/bench/config.h15
-rw-r--r--tools/power/cpupower/bench/cpufreq-bench_plot.sh15
-rw-r--r--tools/power/cpupower/bench/cpufreq-bench_script.sh15
-rw-r--r--tools/power/cpupower/bench/main.c15
-rw-r--r--tools/power/cpupower/bench/parse.c15
-rw-r--r--tools/power/cpupower/bench/parse.h15
-rw-r--r--tools/power/cpupower/bench/system.c15
-rw-r--r--tools/power/cpupower/bench/system.h15
-rw-r--r--tools/power/cpupower/debug/i386/centrino-decode.c3
-rw-r--r--tools/power/cpupower/debug/i386/intel_gsic.c3
-rw-r--r--tools/power/cpupower/debug/i386/powernow-k8-decode.c3
-rw-r--r--tools/power/cpupower/debug/kernel/Makefile4
-rw-r--r--tools/power/cpupower/debug/kernel/cpufreq-test_tsc.c1
-rw-r--r--tools/power/cpupower/lib/cpufreq.c3
-rw-r--r--tools/power/cpupower/lib/cpufreq.h10
-rw-r--r--tools/power/cpupower/lib/cpuidle.c3
-rw-r--r--tools/power/cpupower/lib/cpupower.c3
-rw-r--r--tools/power/cpupower/man/cpupower-monitor.12
-rw-r--r--tools/power/cpupower/po/cs.po2
-rw-r--r--tools/power/cpupower/po/de.po2
-rw-r--r--tools/power/cpupower/po/fr.po2
-rw-r--r--tools/power/cpupower/po/it.po2
-rw-r--r--tools/power/cpupower/po/pt.po2
-rw-r--r--tools/power/cpupower/utils/cpufreq-info.c3
-rw-r--r--tools/power/cpupower/utils/cpufreq-set.c5
-rw-r--r--tools/power/cpupower/utils/cpuidle-info.c3
-rw-r--r--tools/power/cpupower/utils/cpupower-info.c3
-rw-r--r--tools/power/cpupower/utils/cpupower-set.c3
-rw-r--r--tools/power/cpupower/utils/cpupower.c3
-rw-r--r--tools/power/cpupower/utils/helpers/helpers.h3
-rw-r--r--tools/power/cpupower/utils/helpers/sysfs.c3
-rw-r--r--tools/power/cpupower/utils/helpers/topology.c3
-rw-r--r--tools/power/cpupower/utils/idle_monitor/amd_fam14h_idle.c3
-rw-r--r--tools/power/cpupower/utils/idle_monitor/cpuidle_sysfs.c4
-rw-r--r--tools/power/cpupower/utils/idle_monitor/cpupower-monitor.c4
-rw-r--r--tools/power/cpupower/utils/idle_monitor/cpupower-monitor.h4
-rw-r--r--tools/power/cpupower/utils/idle_monitor/hsw_ext_idle.c3
-rw-r--r--tools/power/cpupower/utils/idle_monitor/idle_monitors.h4
-rw-r--r--tools/power/cpupower/utils/idle_monitor/mperf_monitor.c3
-rw-r--r--tools/power/cpupower/utils/idle_monitor/nhm_idle.c3
-rw-r--r--tools/power/cpupower/utils/idle_monitor/snb_idle.c3
-rw-r--r--tools/power/pm-graph/README552
-rwxr-xr-xtools/power/pm-graph/bootgraph.py18
-rw-r--r--tools/power/pm-graph/config/example.cfg26
-rw-r--r--tools/power/pm-graph/sleepgraph.816
-rwxr-xr-xtools/power/pm-graph/sleepgraph.py867
-rw-r--r--tools/power/x86/intel-speed-select/.gitignore2
-rw-r--r--tools/power/x86/intel-speed-select/Build1
-rw-r--r--tools/power/x86/intel-speed-select/Makefile56
-rw-r--r--tools/power/x86/intel-speed-select/isst-config.c1607
-rw-r--r--tools/power/x86/intel-speed-select/isst-core.c721
-rw-r--r--tools/power/x86/intel-speed-select/isst-display.c479
-rw-r--r--tools/power/x86/intel-speed-select/isst.h231
-rwxr-xr-xtools/power/x86/intel_pstate_tracer/intel_pstate_tracer.py1
-rw-r--r--tools/power/x86/turbostat/turbostat.c14
-rw-r--r--tools/power/x86/x86_energy_perf_policy/x86_energy_perf_policy.c3
68 files changed, 4414 insertions, 495 deletions
diff --git a/tools/power/acpi/.gitignore b/tools/power/acpi/.gitignore
index cba3d994995c..f698a0e5bfa6 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 a8bf9081512b..ebd3e1a1c28e 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 f304be71c278..0111d246d1ca 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 373738338f51..2a6c170b57cd 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/tools/acpidbg/Makefile b/tools/power/acpi/tools/acpidbg/Makefile
index f2d06e773eb4..2ce0ee5d0deb 100644
--- a/tools/power/acpi/tools/acpidbg/Makefile
+++ b/tools/power/acpi/tools/acpidbg/Makefile
@@ -1,12 +1,9 @@
+# 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>
#
-# 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 ../../Makefile.config
diff --git a/tools/power/acpi/tools/acpidbg/acpidbg.c b/tools/power/acpi/tools/acpidbg/acpidbg.c
index 4308362d7068..3d2bfd716028 100644
--- a/tools/power/acpi/tools/acpidbg/acpidbg.c
+++ b/tools/power/acpi/tools/acpidbg/acpidbg.c
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* ACPI AML interfacing userspace utility
*
* Copyright (C) 2015, Intel Corporation
* Authors: 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 version 2 as
- * published by the Free Software Foundation.
*/
#include <acpi/acpi.h>
diff --git a/tools/power/acpi/tools/acpidump/Makefile b/tools/power/acpi/tools/acpidump/Makefile
index b436f8675f6a..1208a105a871 100644
--- a/tools/power/acpi/tools/acpidump/Makefile
+++ b/tools/power/acpi/tools/acpidump/Makefile
@@ -1,12 +1,9 @@
+# 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>
#
-# 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 ../../Makefile.config
diff --git a/tools/power/acpi/tools/ec/Makefile b/tools/power/acpi/tools/ec/Makefile
index 75d8a127b6ee..d0abac0ec23a 100644
--- a/tools/power/acpi/tools/ec/Makefile
+++ b/tools/power/acpi/tools/ec/Makefile
@@ -1,12 +1,9 @@
+# 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>
#
-# 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 ../../Makefile.config
diff --git a/tools/power/acpi/tools/ec/ec_access.c b/tools/power/acpi/tools/ec/ec_access.c
index 5f50642386db..8bb271b210d8 100644
--- a/tools/power/acpi/tools/ec/ec_access.c
+++ b/tools/power/acpi/tools/ec/ec_access.c
@@ -1,11 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* ec_access.c
*
* Copyright (C) 2010 SUSE Linux Products GmbH
* Author:
* Thomas Renninger <trenn@suse.de>
- *
- * This work is licensed under the terms of the GNU GPL, version 2.
*/
#include <fcntl.h>
diff --git a/tools/power/cpupower/Makefile b/tools/power/cpupower/Makefile
index fd8765af19bb..9063fca480b3 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)/
diff --git a/tools/power/cpupower/bench/benchmark.c b/tools/power/cpupower/bench/benchmark.c
index 429d51ab8031..c7234cf3f6ff 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 51d7f50ac2bb..bf612de897eb 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 ee6f258e5336..fec5b0b055f2 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 410021a12f40..9061b4f1244e 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.
diff --git a/tools/power/cpupower/bench/cpufreq-bench_script.sh b/tools/power/cpupower/bench/cpufreq-bench_script.sh
index de20d2a06879..4e9714b876d2 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.
diff --git a/tools/power/cpupower/bench/main.c b/tools/power/cpupower/bench/main.c
index 24910313a521..429d1b6b8bc8 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 84caee38418f..e63dc11fa3a5 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>
diff --git a/tools/power/cpupower/bench/parse.h b/tools/power/cpupower/bench/parse.h
index a8dc632d9eee..d5b3e34d7064 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 2bb3eef7d5c1..40f3679e70b5 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 3a8c858b78f0..530fa28230d1 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/debug/i386/centrino-decode.c b/tools/power/cpupower/debug/i386/centrino-decode.c
index 7ef24cce4926..700cd31a7d02 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 d032c826d42e..e5e926f46d6b 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 638a6b3bfd97..735dca1e25bc 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 c23e5a6ceb7e..7b5c43684be1 100644
--- a/tools/power/cpupower/debug/kernel/Makefile
+++ b/tools/power/cpupower/debug/kernel/Makefile
@@ -12,8 +12,8 @@ default:
$(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 6ff8383f2941..e364b170bf85 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/lib/cpufreq.c b/tools/power/cpupower/lib/cpufreq.c
index 80650497fb80..2f55d4d23446 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.
*/
diff --git a/tools/power/cpupower/lib/cpufreq.h b/tools/power/cpupower/lib/cpufreq.h
index 775738269cbf..a55f0d19215b 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__
diff --git a/tools/power/cpupower/lib/cpuidle.c b/tools/power/cpupower/lib/cpuidle.c
index 852d25462388..479c5971aa6d 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 9711d628b0f4..3656e697537e 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 914cbb9d9cd0..70a56476f4b0 100644
--- a/tools/power/cpupower/man/cpupower-monitor.1
+++ b/tools/power/cpupower/man/cpupower-monitor.1
@@ -61,7 +61,7 @@ Only display specific monitors. Use the monitor string(s) provided by \-l option
.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 cb22c45c5069..bfc7e1702ec9 100644
--- a/tools/power/cpupower/po/cs.po
+++ b/tools/power/cpupower/po/cs.po
@@ -98,7 +98,7 @@ msgstr ""
#: 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 840c17cc450a..70887bb8ba95 100644
--- a/tools/power/cpupower/po/de.po
+++ b/tools/power/cpupower/po/de.po
@@ -95,7 +95,7 @@ msgstr ""
#: 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/fr.po b/tools/power/cpupower/po/fr.po
index b46ca2548f86..b6e505b34e4a 100644
--- a/tools/power/cpupower/po/fr.po
+++ b/tools/power/cpupower/po/fr.po
@@ -95,7 +95,7 @@ msgstr ""
#: 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 f80c4ddb9bda..a1deeb52c9e0 100644
--- a/tools/power/cpupower/po/it.po
+++ b/tools/power/cpupower/po/it.po
@@ -95,7 +95,7 @@ msgstr ""
#: 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 990f5267ffe8..902186585bb9 100644
--- a/tools/power/cpupower/po/pt.po
+++ b/tools/power/cpupower/po/pt.po
@@ -93,7 +93,7 @@ msgstr ""
#: 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 10290b308797..e63cf55f81cf 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.
*/
diff --git a/tools/power/cpupower/utils/cpufreq-set.c b/tools/power/cpupower/utils/cpufreq-set.c
index 1eef0aed6423..6ed82fba5aaa 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 @@ int cmd_freq_set(int argc, char **argv)
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 b59c85defa05..f2b202c5552a 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 c7caa8eaa6d0..4c9d342b70ff 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 532f46b9a335..3cd95c6cb974 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 2dccf4998599..8e3d08042825 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/helpers.h b/tools/power/cpupower/utils/helpers/helpers.h
index 902139689315..357b19bb136e 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
*/
diff --git a/tools/power/cpupower/utils/helpers/sysfs.c b/tools/power/cpupower/utils/helpers/sysfs.c
index 4e8fe2c7b054..e13ff38329a0 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 a1a6c6041a1e..3dd0925d7594 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 2116df9ad832..3f893b99b337 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 5b8c4956ff9a..f634aeb65c5f 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 051da0a7c454..d3c3e6e7aa26 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 2ae50b499e0a..a2d901d3bfaf 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 f794d6bbb7e9..7c7451d3f494 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 4fcdeb1e07e8..e9e567ec879e 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 f2a7e9cfd577..44806a6dae11 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__)
diff --git a/tools/power/cpupower/utils/idle_monitor/nhm_idle.c b/tools/power/cpupower/utils/idle_monitor/nhm_idle.c
index abf8cb5f7349..be7256696a37 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 a2b45219648d..968333571cad 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/README b/tools/power/pm-graph/README
new file mode 100644
index 000000000000..58a5591e3951
--- /dev/null
+++ b/tools/power/pm-graph/README
@@ -0,0 +1,552 @@
+ p m - g r a p h
+
+ pm-graph: suspend/resume/boot timing analysis tools
+ Version: 5.4
+ 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/
+
+ 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 6dae57041537..666bcbda648d 100755
--- a/tools/power/pm-graph/bootgraph.py
+++ b/tools/power/pm-graph/bootgraph.py
@@ -1,17 +1,9 @@
#!/usr/bin/python2
+# SPDX-License-Identifier: GPL-2.0-only
#
# Tool for analyzing boot timing
# Copyright (c) 2013, Intel Corporation.
#
-# 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.
-#
# Authors:
# Todd Brandt <todd.e.brandt@linux.intel.com>
#
@@ -333,9 +325,9 @@ def parseKernelLog():
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')
@@ -356,7 +348,7 @@ def parseKernelLog():
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
@@ -1016,7 +1008,7 @@ if __name__ == '__main__':
updateKernelParams()
elif cmd == 'flistall':
for f in sysvals.getBootFtraceFilterFunctions():
- print f
+ print(f)
elif cmd == 'checkbl':
sysvals.getBootLoader()
pprint('Boot Loader: %s\n%s' % (sysvals.bootloader, sysvals.blexec))
diff --git a/tools/power/pm-graph/config/example.cfg b/tools/power/pm-graph/config/example.cfg
index 05b2efb9bb54..1ef3eb9383fa 100644
--- a/tools/power/pm-graph/config/example.cfg
+++ b/tools/power/pm-graph/config/example.cfg
@@ -98,12 +98,34 @@ postdelay: 0
# 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 @@ timeprec: 6
# 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 24a2e7d0ae63..9648be644d5f 100644
--- a/tools/power/pm-graph/sleepgraph.8
+++ b/tools/power/pm-graph/sleepgraph.8
@@ -53,6 +53,11 @@ disable rtcwake and require a user keypress to resume.
Add the dmesg and ftrace logs to the html output. They will be viewable by
clicking buttons in the timeline.
.TP
+\fB-turbostat\fR
+Use turbostat to execute the command in freeze mode (default: disabled). This
+will provide turbostat output in the log which will tell you which actual
+power modes were entered.
+.TP
\fB-result \fIfile\fR
Export a results table to a text file for parsing.
.TP
@@ -121,6 +126,10 @@ be created in a new subdirectory with a summary page: suspend-xN-{date}-{time}.
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 @@ which are barely visible in the timeline.
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,9 @@ Print out the contents of the ACPI Firmware Performance Data Table.
\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.
diff --git a/tools/power/pm-graph/sleepgraph.py b/tools/power/pm-graph/sleepgraph.py
index 52618f3444d4..4f46a7a1feb6 100755
--- a/tools/power/pm-graph/sleepgraph.py
+++ b/tools/power/pm-graph/sleepgraph.py
@@ -1,25 +1,17 @@
#!/usr/bin/python2
+# SPDX-License-Identifier: GPL-2.0-only
#
# Tool for analyzing suspend/resume timing
# Copyright (c) 2013, Intel Corporation.
#
-# 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.
-#
# Authors:
# Todd Brandt <todd.e.brandt@linux.intel.com>
#
# 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 +24,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
@@ -61,6 +54,7 @@ import ConfigParser
import gzip
from threading import Thread
from subprocess import call, Popen, PIPE
+import base64
def pprint(msg):
print(msg)
@@ -74,7 +68,7 @@ def pprint(msg):
# store system values and test parameters
class SystemValues:
title = 'SleepGraph'
- version = '5.2'
+ version = '5.4'
ansi = False
rs = 0
display = ''
@@ -82,8 +76,9 @@ class SystemValues:
sync = False
verbose = False
testlog = True
- dmesglog = False
+ dmesglog = True
ftracelog = False
+ tstat = False
mindevlen = 0.0
mincglen = 0.0
cgphase = ''
@@ -107,6 +102,8 @@ class SystemValues:
pmdpath = '/sys/power/pm_debug_messages'
traceevents = [
'suspend_resume',
+ 'wakeup_source_activate',
+ 'wakeup_source_deactivate',
'device_pm_callback_end',
'device_pm_callback_start'
]
@@ -138,6 +135,8 @@ class SystemValues:
x2delay = 0
skiphtml = False
usecallgraph = False
+ ftopfunc = 'suspend_devices_and_enter'
+ ftop = False
usetraceevents = False
usetracemarkers = True
usekprobes = True
@@ -166,6 +165,13 @@ class SystemValues:
'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': {},
@@ -199,9 +205,14 @@ class SystemValues:
'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
@@ -250,6 +261,7 @@ class SystemValues:
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()
@@ -328,6 +340,7 @@ class SystemValues:
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 != '':
@@ -339,21 +352,28 @@ class SystemValues:
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)
@@ -361,10 +381,10 @@ class SystemValues:
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')
@@ -384,7 +404,7 @@ class SystemValues:
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 = \
@@ -399,7 +419,7 @@ class SystemValues:
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(','):
@@ -410,6 +430,12 @@ class SystemValues:
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):
@@ -479,9 +505,9 @@ class SystemValues:
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 = ''
@@ -688,7 +714,8 @@ class SystemValues:
if self.bufsize > 0:
tgtsize = self.bufsize
elif self.usecallgraph or self.usedevsrc:
- bmax = (1*1024*1024) if self.suspendmode == 'disk' else (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
@@ -723,7 +750,10 @@ class SystemValues:
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:
@@ -776,9 +806,21 @@ class SystemValues:
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
@@ -829,6 +871,106 @@ class SystemValues:
if isgz:
return gzip.open(filename, mode+'b')
return open(filename, mode)
+ def mcelog(self, clear=False):
+ cmd = self.getExec('mcelog')
+ if not cmd:
+ return ''
+ if clear:
+ call(cmd+' > /dev/null 2>&1', shell=True)
+ return ''
+ fp = Popen([cmd], stdout=PIPE, stderr=PIPE).stdout
+ out = fp.read().strip()
+ fp.close()
+ if not out:
+ return ''
+ return base64.b64encode(out.encode('zlib'))
+ 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 = fp.read().strip()
+ fp.close()
+ return re.match('turbostat version [0-9\.]* .*', out)
+ def turbostat(self):
+ cmd = self.getExec('turbostat')
+ if not cmd:
+ return 'missing turbostat executable'
+ text = []
+ fullcmd = '%s -q -S echo freeze > %s' % (cmd, self.powerfile)
+ fp = Popen(['sh', '-c', fullcmd], stdout=PIPE, stderr=PIPE).stderr
+ for line in fp:
+ if re.match('[0-9.]* sec', line):
+ continue
+ text.append(line.split())
+ fp.close()
+ if len(text) < 2:
+ return 'turbostat output format error'
+ out = []
+ for key in text[0]:
+ values = []
+ idx = text[0].index(key)
+ for line in text[1:]:
+ if len(line) > idx:
+ values.append(line[idx])
+ out.append('%s=%s' % (key, ','.join(values)))
+ 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*)', 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\.]*)', 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']
@@ -923,7 +1065,14 @@ class Data:
'ERROR' : '.*ERROR.*',
'WARNING' : '.*WARNING.*',
'IRQ' : '.*genirq: .*',
- 'TASKFAIL': '.*Freezing of tasks failed.*',
+ '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'
@@ -941,6 +1090,9 @@ class Data:
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
@@ -975,8 +1127,24 @@ class Data:
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):
- 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:
@@ -991,16 +1159,19 @@ class Data:
msg = m.group('msg')
for err in self.errlist:
if re.match(self.errlist[err], msg):
- list.append((err, dir, t, i, i))
+ 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):
@@ -2053,7 +2224,7 @@ class FTraceCallGraph:
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
@@ -2358,6 +2529,9 @@ class TestProps:
'(?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>.*)'
@@ -2380,7 +2554,10 @@ class TestProps:
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
@@ -2394,6 +2571,44 @@ class TestProps:
self.ftrace_line_fmt = self.ftrace_line_fmt_nop
else:
doError('Invalid tracer format: [%s]' % tracer)
+ def decode(self, data):
+ try:
+ out = base64.b64decode(data).decode('zlib')
+ except:
+ out = data
+ return out
+ 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)
@@ -2436,14 +2651,31 @@ class TestProps:
sv.stamp = data.stamp
# firmware data
if sv.suspendmode == 'mem' and len(self.fwdata) > data.testnumber:
- data.fwSuspend, data.fwResume = self.fwdata[data.testnumber]
- if(data.fwSuspend > 0 or data.fwResume > 0):
- data.fwValid = True
+ 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 = self.decode(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])
@@ -2513,9 +2745,9 @@ class ProcessMonitor:
# 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()']
+ kpcheck = ['_cal: (', '_ret: (']
techeck = ['suspend_resume', 'device_pm_callback']
- tmcheck = ['tracing_mark_write']
+ tmcheck = ['SUSPEND START', 'RESUME COMPLETE']
sysvals.usekprobes = False
fp = sysvals.openlog(sysvals.ftracefile, 'r')
for line in fp:
@@ -2564,21 +2796,7 @@ def appendIncompleteTraceLog(testruns):
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
- continue
- elif re.match(tp.batteryfmt, line):
- tp.battery.append(line)
- continue
- elif re.match(tp.testerrfmt, line):
- tp.testerror.append(line)
+ if tp.stampInfo(line):
continue
# determine the trace data type (required for further parsing)
m = re.match(tp.tracertypefmt, line)
@@ -2701,26 +2919,7 @@ def parseTraceLog(live=False):
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
- elif re.match(tp.batteryfmt, line):
- tp.battery.append(line)
- continue
- elif re.match(tp.testerrfmt, line):
- tp.testerror.append(line)
- continue
- # firmware line: pull out any firmware data
- m = re.match(tp.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(tp.tracertypefmt, line)
@@ -2933,7 +3132,7 @@ def parseTraceLog(live=False):
tp.ktemp[key].append({
'pid': pid,
'begin': t.time,
- 'end': t.time,
+ 'end': -1,
'name': displayname,
'cdata': kprobedata,
'proc': m_proc,
@@ -2944,12 +3143,11 @@ def parseTraceLog(live=False):
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(phase != 'suspend_prepare' and kprobename in krescalls):
if phase in data.dmesg:
@@ -2971,8 +3169,10 @@ def parseTraceLog(live=False):
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: end marker is missing')
+ sysvals.vprint('WARNING: ftrace end marker is missing')
data.handleEndMarker(t.time)
if sysvals.suspendmode == 'command':
@@ -3021,9 +3221,11 @@ def parseTraceLog(live=False):
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)
@@ -3035,7 +3237,7 @@ def parseTraceLog(live=False):
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'])
@@ -3059,7 +3261,7 @@ def parseTraceLog(live=False):
if not devname:
sortkey = '%f%f%d' % (cg.start, cg.end, pid)
sortlist[sortkey] = cg
- elif len(cg.list) > 1000000:
+ 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
@@ -3141,25 +3343,7 @@ def loadKernelLog():
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
- elif re.match(tp.batteryfmt, line):
- tp.battery.append(line)
- continue
- elif re.match(tp.testerrfmt, line):
- tp.testerror.append(line)
- continue
- m = re.match(tp.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):
@@ -3184,7 +3368,7 @@ def loadKernelLog():
if data:
testruns.append(data)
if len(testruns) < 1:
- pprint('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
@@ -3523,6 +3707,8 @@ def addCallgraphs(sv, hf, data):
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):
@@ -3531,22 +3717,16 @@ def addCallgraphs(sv, hf, data):
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, title):
- # 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: 14px "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\
@@ -3555,12 +3735,23 @@ def createHTMLSummarySimple(testruns, htmlfile, title):
.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 = dict()
for data in sorted(testruns, key=lambda v:(v['mode'], v['host'], v['kernel'], v['time'])):
@@ -3571,27 +3762,35 @@ def createHTMLSummarySimple(testruns, htmlfile, title):
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])
+ 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['time'], tVal[0], tVal[1], data['url'], res,
data['issues'], data['sus_worst'], data['sus_worsttime'],
- data['res_worst'], data['res_worsttime']])
+ data['res_worst'], data['res_worsttime'], pkgpc10, syslpi])
idx = len(list[mode]['data']) - 1
- if data['result'] not in cnt:
- cnt[data['result']] = 1
+ if res.startswith('fail in'):
+ res = 'fail'
+ if res not in cnt:
+ cnt[res] = 1
else:
- cnt[data['result']] += 1
- if data['result'] == 'pass':
+ 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
@@ -3605,7 +3804,7 @@ def createHTMLSummarySimple(testruns, htmlfile, title):
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])
+ 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
@@ -3621,19 +3820,21 @@ def createHTMLSummarySimple(testruns, htmlfile, title):
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('Worst Suspend Device') + th.format('SD Time') +\
- th.format('Worst Resume Device') + th.format('RD Time') +\
- th.format('Detail') + '</tr>\n'
-
+ 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=12 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> '+\
@@ -3642,7 +3843,8 @@ def createHTMLSummarySimple(testruns, htmlfile, title):
'<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=12></td></tr>\n'
+ headnone = '<tr class="head"><td>{0}</td><td>{1}</td><td colspan='+\
+ colspan+'></td></tr>\n'
for mode in list:
# header line for each suspend mode
num = 0
@@ -3689,6 +3891,9 @@ def createHTMLSummarySimple(testruns, htmlfile, title):
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
@@ -3698,6 +3903,115 @@ def createHTMLSummarySimple(testruns, htmlfile, title):
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'], 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:
@@ -3999,7 +4313,7 @@ def createHTML(testruns, testfail):
for word in phase.split('_'):
id += word[0]
order = '%.2f' % ((p['order'] * pdelta) + pmargin)
- name = string.replace(phase, '_', ' &nbsp;')
+ name = phase.replace('_', ' &nbsp;')
devtl.html += devtl.html_legend.format(order, p['color'], name, id)
devtl.html += '</div>\n'
@@ -4588,6 +4902,7 @@ def setRuntimeSuspend(before=True):
def executeSuspend():
pm = ProcessMonitor()
tp = sysvals.tpath
+ wifi = sysvals.checkWifi()
testdata = []
battery = True if getBattery() else False
# run these commands to prepare the system for suspend
@@ -4621,6 +4936,7 @@ def executeSuspend():
pprint('SUSPEND START')
else:
pprint('SUSPEND START (press a key to resume)')
+ sysvals.mcelog(True)
bat1 = getBattery() if battery else False
# set rtcwake
if(sysvals.rtcwake):
@@ -4652,13 +4968,23 @@ def executeSuspend():
pf = open(sysvals.diskpowerfile, 'w')
pf.write(sysvals.diskmode)
pf.close()
- pf = open(sysvals.powerfile, 'w')
- pf.write(mode)
- # execution will pause here
- try:
- pf.close()
- except Exception as e:
- tdata['error'] = str(e)
+ if mode == 'freeze' and sysvals.haveTurbostat():
+ # execution will pause here
+ turbo = sysvals.turbostat()
+ if '|' in turbo:
+ tdata['turbo'] = turbo
+ else:
+ tdata['error'] = turbo
+ else:
+ if sysvals.haveTurbostat():
+ sysvals.vprint('WARNING: ignoring turbostat in mode "%s"' % mode)
+ 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
@@ -4672,9 +4998,14 @@ def executeSuspend():
sysvals.fsetVal('RESUME COMPLETE', 'trace_marker')
if(sysvals.suspendmode == 'mem' or sysvals.suspendmode == 'command'):
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):
@@ -4694,6 +5025,7 @@ def executeSuspend():
op.close()
sysvals.fsetVal('', 'trace')
devProps()
+ return testdata
def readFile(file):
if os.path.islink(file):
@@ -4780,7 +5112,7 @@ def deviceInfo(output=''):
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
@@ -4913,12 +5245,12 @@ def getModes():
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
@@ -4929,7 +5261,7 @@ def getModes():
modes.remove('mem')
if('disk' in modes and os.path.exists(sysvals.diskpowerfile)):
fp = open(sysvals.diskpowerfile, 'r')
- for m in string.split(fp.read()):
+ for m in fp.read().split():
modes.append('disk-%s' % m.strip('[]'))
fp.close()
return modes
@@ -4992,14 +5324,15 @@ def dmidecode(mempath, fatal=False):
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()
@@ -5022,14 +5355,15 @@ def dmidecode(mempath, fatal=False):
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()
@@ -5173,7 +5507,11 @@ def getFPDT(output):
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):
@@ -5290,13 +5628,14 @@ def statusCheck(probecheck=False):
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
- pprint(' 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'
@@ -5384,6 +5723,8 @@ def getArgFloat(name, args, min, max, main=True):
def processData(live=False):
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)
@@ -5396,13 +5737,36 @@ def processData(live=False):
parseKernelLog(data)
if(sysvals.ftracefile and (sysvals.usecallgraph or sysvals.usetraceevents)):
appendIncompleteTraceLog(testruns)
+ sysvals.vprint('System Info:')
+ for key in sorted(sysvals.stamp):
+ 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 sysvals.cgdump:
for data in testruns:
@@ -5426,12 +5790,15 @@ def processData(live=False):
# 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)
@@ -5450,14 +5817,18 @@ def runTest(n=0):
sysvals.initTestOutput('suspend')
# execute the test
- executeSuspend()
+ testdata = executeSuspend()
sysvals.cleanupFtrace()
if sysvals.skiphtml:
sysvals.sudoUserchown(sysvals.testdir)
return
- testruns, stamp = processData(True)
- for data in testruns:
- del data
+ 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:
@@ -5487,10 +5858,13 @@ def find_in_html(html, start, end, firstonly=True):
return ''
return out
-def data_from_html(file, outpath, devlist=False):
+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:
@@ -5499,6 +5873,7 @@ def data_from_html(file, outpath, devlist=False):
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:
@@ -5509,13 +5884,45 @@ def data_from_html(file, outpath, devlist=False):
result = 'fail'
else:
result = 'pass'
+ # extract error info
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)
+ 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:
- ilist.append('FREEZEx%d' % len(low.split('|')))
+ 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)
@@ -5527,82 +5934,98 @@ def data_from_html(file, outpath, devlist=False):
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])
- d = phase.split('_')[0]
+ 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)
- worst = {'suspend': {'name':'', 'time': 0.0},
- 'resume': {'name':'', 'time': 0.0}}
- for d in devices:
- if d not in worst:
- worst[d] = dict()
- dev = devices[d]
- if len(dev.keys()) > 0:
+ # 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=dev.get, 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': os.path.relpath(file, outpath),
+ 'url': sysvals.htmlfile,
}
- if devlist:
- data['devlist'] = devices
+ 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):
+ 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):
+ 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 = os.path.abspath('.') if local else inpath
- pprint('Generating a summary of folder "%s"' % 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):
- pprint('FTRACE: %s' % sysvals.ftracefile)
- if sysvals.dmesgfile:
- pprint('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
- data = data_from_html(os.path.join(dirname, filename), outpath)
+ data = data_from_html(os.path.join(dirname, filename), outpath, issues)
if(not data):
continue
testruns.append(data)
for key in desc:
if data[key] not in desc[key]:
desc[key].append(data[key])
- outfile = os.path.join(outpath, 'summary.html')
- pprint('Summary file: %s' % outfile)
+ 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, outfile, title)
+ 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:
@@ -5847,6 +6270,7 @@ def printHelp():
' 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'\
+ ' -turbostat Use turbostat to execute the command 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'\
@@ -5868,6 +6292,7 @@ def printHelp():
' 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'\
@@ -5887,6 +6312,7 @@ def printHelp():
' -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'\
@@ -5896,7 +6322,7 @@ def printHelp():
' [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.title, sysvals.version, sysvals.suspendmode, sysvals.ftopfunc))
return True
# ----------------- MAIN --------------------
@@ -5906,7 +6332,7 @@ if __name__ == '__main__':
cmd = ''
simplecmds = ['-sysinfo', '-modes', '-fpdt', '-flist', '-flistall',
'-devinfo', '-status', '-battery', '-xon', '-xoff', '-xstandby',
- '-xsuspend', '-xinit', '-xreset', '-xstat']
+ '-xsuspend', '-xinit', '-xreset', '-xstat', '-wifi']
if '-f' in sys.argv:
sysvals.cgskip = sysvals.configFile('cgskip.txt')
# loop through the command line arguments
@@ -5938,6 +6364,10 @@ if __name__ == '__main__':
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'):
@@ -5948,10 +6378,16 @@ if __name__ == '__main__':
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 == '-turbostat'):
+ sysvals.tstat = True
+ if not sysvals.haveTurbostat():
+ doError('Turbostat command not found')
elif(arg == '-verbose'):
sysvals.verbose = True
elif(arg == '-proc'):
@@ -6021,6 +6457,12 @@ if __name__ == '__main__':
except:
doError('No callgraph functions supplied', True)
sysvals.setCallgraphFilter(val)
+ elif(arg == '-skipkprobe'):
+ try:
+ val = args.next()
+ except:
+ doError('No kprobe functions supplied', True)
+ sysvals.skipKprobes(val)
elif(arg == '-cgskip'):
try:
val = args.next()
@@ -6159,7 +6601,7 @@ if __name__ == '__main__':
elif(cmd == 'devinfo'):
deviceInfo()
elif(cmd == 'modes'):
- print getModes()
+ pprint(getModes())
elif(cmd == 'flist'):
sysvals.getFtraceFilterFunctions(True)
elif(cmd == 'flistall'):
@@ -6171,11 +6613,18 @@ if __name__ == '__main__':
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(0)
@@ -6212,7 +6661,7 @@ if __name__ == '__main__':
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):
pprint('Waiting %d seconds...' % (sysvals.multitest['delay']))
diff --git a/tools/power/x86/intel-speed-select/.gitignore b/tools/power/x86/intel-speed-select/.gitignore
new file mode 100644
index 000000000000..f61145925ce9
--- /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 000000000000..b61456d75190
--- /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 000000000000..12c6939dca2a
--- /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 000000000000..91c5ad1685a1
--- /dev/null
+++ b/tools/power/x86/intel-speed-select/isst-config.c
@@ -0,0 +1,1607 @@
+// 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;
+
+/* 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(
+ 1, "/sys/devices/system/cpu/cpu%d/topology/physical_package_id",
+ cpu);
+}
+
+int get_physical_core_id(int cpu)
+{
+ return parse_int_file(
+ 1, "/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;
+}
+
+#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] + 1;
+
+ 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_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("CLOS %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);
+
+ 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_display_result(cpu, outf, "perf-profile", (char *)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);
+}
+
+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");
+ 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 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_display_result(cpu, outf, "core-power", "get-assoc", 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)
+ for_each_online_target_cpu_in_set(get_clos_assoc_for_cpu, NULL,
+ NULL, NULL, NULL);
+ else {
+ fprintf(stderr,
+ "Invalid target cpu. Specify with [-c|--cpu]\n");
+ }
+}
+
+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_config },
+ { "core-power", "enable", set_clos_enable },
+ { "core-power", "disable", set_clos_disable },
+ { "core-power", "config", set_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' },
+ { "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:h",
+ 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 '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);
+ printf("clos %d\n", current_clos);
+ 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("\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");
+ printf("\t\t\tFor Set commands, status is 0 for success and rest for failures\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;
+
+ 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();
+ isst_fill_platform_info();
+ if (isst_platform_info.api_version > supported_api_ver) {
+ printf("Incompatible API versions; Upgrade of tool is required\n");
+ exit(0);
+ }
+
+ process_command(argc, argv);
+}
+
+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 000000000000..8de4ac39a008
--- /dev/null
+++ b/tools/power/x86/intel-speed-select/isst-core.c
@@ -0,0 +1,721 @@
+// 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_set_tdp_level_msr(int cpu, int 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,
+ (unsigned long long *)&tdp_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_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_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 000000000000..f368b8323742
--- /dev/null
+++ b/tools/power/x86/intel-speed-select/isst-display.c
@@ -0,0 +1,479 @@
+// 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 100000
+
+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_packag_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(KHz)");
+ 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), "low-priority-base-frequency(KHz)");
+ 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(KHz)");
+ 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(KHz)");
+ 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(KHz)");
+ 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(KHz)");
+ 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(KHz)");
+ 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(KHz)");
+ 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_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_packag_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), "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(KHz)");
+ 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-support");
+ snprintf(value, sizeof(value), "%d", ctdp_level->fact_support);
+ format_and_print(outf, base_level + 4, header, value);
+
+ snprintf(header, sizeof(header),
+ "speed-select-base-freq-support");
+ snprintf(value, sizeof(value), "%d", ctdp_level->pbf_support);
+ format_and_print(outf, base_level + 4, header, value);
+
+ snprintf(header, sizeof(header),
+ "speed-select-base-freq-enabled");
+ snprintf(value, sizeof(value), "%d", ctdp_level->pbf_enabled);
+ format_and_print(outf, base_level + 4, header, value);
+
+ snprintf(header, sizeof(header),
+ "speed-select-turbo-freq-enabled");
+ snprintf(value, sizeof(value), "%d", ctdp_level->fact_enabled);
+ 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), "%d", j);
+ format_and_print(outf, base_level + 6, header, value);
+
+ snprintf(header, sizeof(header), "turbo-ratio");
+ snprintf(value, sizeof(value), "%d",
+ ctdp_level->trl_sse_active_cores[j]);
+ 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), "%d", j);
+ format_and_print(outf, base_level + 6, header, value);
+
+ snprintf(header, sizeof(header), "turbo-ratio");
+ snprintf(value, sizeof(value), "%d",
+ ctdp_level->trl_avx_active_cores[j]);
+ 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), "%d", j);
+ format_and_print(outf, base_level + 6, header, value);
+
+ snprintf(header, sizeof(header), "turbo-ratio");
+ snprintf(value, sizeof(value), "%d",
+ ctdp_level->trl_avx_512_active_cores[j]);
+ 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_packag_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_packag_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_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);
+ snprintf(value, sizeof(value), "%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 000000000000..221881761609
--- /dev/null
+++ b/tools/power/x86/intel-speed-select/isst.h
@@ -0,0 +1,231 @@
+/* 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;
+ 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_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_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 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);
+#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 2fa3c5757bcb..2d6d342b148f 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
diff --git a/tools/power/x86/turbostat/turbostat.c b/tools/power/x86/turbostat/turbostat.c
index c7727be9719f..75fc4fb9901c 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 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
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 65bbe627a425..34a796b303fe 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