tools/power/x86: A tool to validate Intel Speed Select commands
The Intel(R) Speed select technologies contains four features. Performance profile:An non architectural mechanism that allows multiple optimized performance profiles per system via static and/or dynamic adjustment of core count, workload, Tjmax, and TDP, etc. aka ISS in the documentation. Base Frequency: Enables users to increase guaranteed base frequency on certain cores (high priority cores) in exchange for lower base frequency on remaining cores (low priority cores). aka PBF in the documenation. Turbo frequency: Enables the ability to set different turbo ratio limits to cores based on priority. aka FACT in the documentation. Core power: An Interface that allows user to define per core/tile priority. There is a multi level help for commands and options. This can be used to check required arguments for each feature and commands for the feature. To start navigating the features start with $sudo intel-speed-select --help For help on a specific feature for example $sudo intel-speed-select perf-profile --help To get help for a command for a feature for example $sudo intel-speed-select perf-profile get-lock-status --help Signed-off-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com> Acked-by: Len Brown <len.brown@intel.com> Acked-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
This commit is contained in:
parent
f607874f35
commit
3fb4f7cd47
|
@ -19,6 +19,7 @@ help:
|
|||
@echo ' gpio - GPIO tools'
|
||||
@echo ' hv - tools used when in Hyper-V clients'
|
||||
@echo ' iio - IIO tools'
|
||||
@echo ' intel-speed-select - Intel Speed Select tool'
|
||||
@echo ' kvm_stat - top-like utility for displaying kvm statistics'
|
||||
@echo ' leds - LEDs tools'
|
||||
@echo ' liblockdep - user-space wrapper for kernel locking-validator'
|
||||
|
@ -82,7 +83,7 @@ perf: FORCE
|
|||
selftests: FORCE
|
||||
$(call descend,testing/$@)
|
||||
|
||||
turbostat x86_energy_perf_policy: FORCE
|
||||
turbostat x86_energy_perf_policy intel-speed-select: FORCE
|
||||
$(call descend,power/x86/$@)
|
||||
|
||||
tmon: FORCE
|
||||
|
@ -115,7 +116,7 @@ liblockdep_install:
|
|||
selftests_install:
|
||||
$(call descend,testing/$(@:_install=),install)
|
||||
|
||||
turbostat_install x86_energy_perf_policy_install:
|
||||
turbostat_install x86_energy_perf_policy_install intel-speed-select_install:
|
||||
$(call descend,power/x86/$(@:_install=),install)
|
||||
|
||||
tmon_install:
|
||||
|
@ -132,7 +133,7 @@ install: acpi_install cgroup_install cpupower_install gpio_install \
|
|||
perf_install selftests_install turbostat_install usb_install \
|
||||
virtio_install vm_install bpf_install x86_energy_perf_policy_install \
|
||||
tmon_install freefall_install objtool_install kvm_stat_install \
|
||||
wmi_install pci_install debugging_install
|
||||
wmi_install pci_install debugging_install intel-speed-select_install
|
||||
|
||||
acpi_clean:
|
||||
$(call descend,power/acpi,clean)
|
||||
|
@ -162,7 +163,7 @@ perf_clean:
|
|||
selftests_clean:
|
||||
$(call descend,testing/$(@:_clean=),clean)
|
||||
|
||||
turbostat_clean x86_energy_perf_policy_clean:
|
||||
turbostat_clean x86_energy_perf_policy_clean intel-speed-select_clean:
|
||||
$(call descend,power/x86/$(@:_clean=),clean)
|
||||
|
||||
tmon_clean:
|
||||
|
@ -178,6 +179,7 @@ clean: acpi_clean cgroup_clean cpupower_clean hv_clean firewire_clean \
|
|||
perf_clean selftests_clean turbostat_clean spi_clean usb_clean virtio_clean \
|
||||
vm_clean bpf_clean iio_clean x86_energy_perf_policy_clean tmon_clean \
|
||||
freefall_clean build_clean libbpf_clean libsubcmd_clean liblockdep_clean \
|
||||
gpio_clean objtool_clean leds_clean wmi_clean pci_clean firmware_clean debugging_clean
|
||||
gpio_clean objtool_clean leds_clean wmi_clean pci_clean firmware_clean debugging_clean \
|
||||
intel-speed-select_clean
|
||||
|
||||
.PHONY: FORCE
|
||||
|
|
1
tools/power/x86/intel-speed-select/Build
Normal file
1
tools/power/x86/intel-speed-select/Build
Normal file
|
@ -0,0 +1 @@
|
|||
intel-speed-select-y += isst-config.o isst-core.o isst-display.o
|
56
tools/power/x86/intel-speed-select/Makefile
Normal file
56
tools/power/x86/intel-speed-select/Makefile
Normal file
|
@ -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
|
1607
tools/power/x86/intel-speed-select/isst-config.c
Normal file
1607
tools/power/x86/intel-speed-select/isst-config.c
Normal file
File diff suppressed because it is too large
Load diff
721
tools/power/x86/intel-speed-select/isst-core.c
Normal file
721
tools/power/x86/intel-speed-select/isst-core.c
Normal file
|
@ -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;
|
||||
}
|
479
tools/power/x86/intel-speed-select/isst-display.c
Normal file
479
tools/power/x86/intel-speed-select/isst-display.c
Normal file
|
@ -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);
|
||||
}
|
231
tools/power/x86/intel-speed-select/isst.h
Normal file
231
tools/power/x86/intel-speed-select/isst.h
Normal file
|
@ -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
|
Loading…
Reference in a new issue