mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-08-05 16:54:27 +00:00

- Fix potential division-by-zero error in em_compute_costs() (Yaxiong Tian). - Fix typos in energy model documentation and example driver code (Moon Hee Lee, Atul Kumar Pant). - Rearrange the energy model management code and add a new function for adjusting a CPU energy model after adjusting the capacity of the given CPU to it (Rafael Wysocki). - Refactor cpufreq_online(), add and use cpufreq policy locking guards, use __free() in policy reference counting, and clean up core cpufreq code on top of that (Rafael Wysocki). - Fix boost handling on CPU suspend/resume and sysfs updates (Viresh Kumar). - Fix des_perf clamping with max_perf in amd_pstate_update() (Dhananjay Ugwekar). - Add offline, online and suspend callbacks to the amd-pstate driver, rename and use the existing amd_pstate_epp callbacks in it (Dhananjay Ugwekar). - Add support for the "Requested CPU Min frequency" BIOS option to the amd-pstate driver (Dhananjay Ugwekar). - Reset amd-pstate driver mode after running selftests (Swapnil Sapkal). - Avoid shadowing ret in amd_pstate_ut_check_driver() (Nathan Chancellor). - Add helper for governor checks to the schedutil cpufreq governor and move cpufreq-specific EAS checks to cpufreq (Rafael Wysocki). - Populate the cpu_capacity sysfs entries from the intel_pstate driver after registering asym capacity support (Ricardo Neri). - Add support for enabling Energy-aware scheduling (EAS) to the intel_pstate driver when operating in the passive mode on a hybrid platform (Rafael Wysocki). - Drop redundant cpus_read_lock() from store_local_boost() in the cpufreq core (Seyediman Seyedarab). - Replace sscanf() with kstrtouint() in the cpufreq code and use a symbol instead of a raw number in it (Bowen Yu). - Add support for autonomous CPU performance state selection to the CPPC cpufreq driver (Lifeng Zheng). - OPP: Add dev_pm_opp_set_level() (Praveen Talari). - Introduce scope-based cleanup headers and mutex locking guards in OPP core (Viresh Kumar). - Switch OPP to use kmemdup_array() (Zhang Enpei). - Optimize bucket assignment when next_timer_ns equals KTIME_MAX in the menu cpuidle governor (Zhongqiu Han). - Convert the cpuidle PSCI driver to a faux device one (Sudeep Holla). - Add C1 demotion on/off sysfs knob to the intel_idle driver (Artem Bityutskiy). - Fix typos in two comments in the teo cpuidle governor (Atul Kumar Pant). - Fix denying of auto suspend in pm_suspend_timer_fn() (Charan Teja Kalla). - Move debug runtime PM attributes to runtime_attrs[] (Rafael Wysocki). - Add new devm_ functions for enabling runtime PM and runtime PM reference counting (Bence Csókás). - Remove size arguments from strscpy() calls in the hibernation core code (Thorsten Blum). - Adjust the handling of devices with asynchronous suspend enabled during system suspend and resume to start resuming them immediately after resuming their parents and to start suspending such a device immediately after suspending its first child (Rafael Wysocki). - Adjust messages printed during tasks freezing to avoid using pr_cont() (Andrew Sayers, Paul Menzel). - Clean up unnecessary usage of !! in pm_print_times_init() (Zihuan Zhang). - Add missing wakeup source attribute relax_count to sysfs and remove the space character at the end ofi the string produced by pm_show_wakelocks() (Zijun Hu). - Add configurable pm_test delay for hibernation (Zihuan Zhang). - Disable asynchronous suspend in ucsi_ccg_probe() to prevent the cypd4226 device on Tegra boards from suspending prematurely (Jon Hunter). - Unbreak printing PM debug messages during hibernation and clean up some related code (Rafael Wysocki). - Add a systemd service to run cpupower and change cpupower binding's Makefile to use -lcpupower (John B. Wyatt IV, Francesco Poli). -----BEGIN PGP SIGNATURE----- iQFGBAABCAAwFiEEcM8Aw/RY0dgsiRUR7l+9nS/U47UFAmg0xS0SHHJqd0Byand5 c29ja2kubmV0AAoJEO5fvZ0v1OO1AwwH/Rvgza5YBPb9JZqWJT/ZiBw7HcEWHhP1 fNfcVU1gXPZiF0yoPfjfJua6BcLj6lyQ3d/+zWqqAcWfmRSD6HPe8yYz8qALUAqj RWhDa04aGj6B9bQuOjejatznYlQlkwCRT7zec+75D+dAHVMqR/Vt2LFAetCadgHe MQibAQmVFXu3RFkBjReTAdGzVoTXkwoZDrzdfA2aFAfMJNtJpOW4atUZvnucuctv VK3ZratrctCIw7yXEoB1nWSmlY7R5JlslplBfndjmmOnky3YxNr7C6paqwtbTWoF MiX48qkmLOGeO6gS8s/lVCDQ4oZ+UNFQvXRsM5NGjycBikhHX/dp/w4= =dIqJ -----END PGP SIGNATURE----- Merge tag 'pm-6.16-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm Pull power management updates from Rafael Wysocki: "Once again, the changes are dominated by cpufreq updates, but this time the majority of them are cpufreq core changes, mostly related to the introduction of policy locking guards and __free() usage, and fixes related to boost handling. Still, there is also a significant update of the intel_pstate driver making it register an energy model when running on a hybrid platform which is used for enabling energy-aware scheduling (EAS) if the driver operates in the passive mode (and schedutil is used as the cpufreq governor for all CPUs which is the passive mode default). There are some amd-pstate driver updates too, for a good measure, including the "Requested CPU Min frequency" BIOS option support and new online/offline callbacks. In the cpuidle space, the most significant change is the addition of a C1 demotion on/off sysfs knob to intel_idle which should help some users to configure their systems more precisely. There is also the conversion of the PSCI cpuidle driver to a faux device one and there are two small updates of cpuidle governors. Device power management is also modified quite a bit, especially the handling of devices with asynchronous suspend and resume enabled during system transitions. They are now going to be handled more asynchronously during suspend transitions and somewhat less aggressively during resume transitions. Apart from the above, the operating performance points (OPP) library is now going to use mutex locking guards and scope-based cleanup helpers and there is the usual bunch of assorted fixes and code cleanups. Specifics: - Fix potential division-by-zero error in em_compute_costs() (Yaxiong Tian) - Fix typos in energy model documentation and example driver code (Moon Hee Lee, Atul Kumar Pant) - Rearrange the energy model management code and add a new function for adjusting a CPU energy model after adjusting the capacity of the given CPU to it (Rafael Wysocki) - Refactor cpufreq_online(), add and use cpufreq policy locking guards, use __free() in policy reference counting, and clean up core cpufreq code on top of that (Rafael Wysocki) - Fix boost handling on CPU suspend/resume and sysfs updates (Viresh Kumar) - Fix des_perf clamping with max_perf in amd_pstate_update() (Dhananjay Ugwekar) - Add offline, online and suspend callbacks to the amd-pstate driver, rename and use the existing amd_pstate_epp callbacks in it (Dhananjay Ugwekar) - Add support for the "Requested CPU Min frequency" BIOS option to the amd-pstate driver (Dhananjay Ugwekar) - Reset amd-pstate driver mode after running selftests (Swapnil Sapkal) - Avoid shadowing ret in amd_pstate_ut_check_driver() (Nathan Chancellor) - Add helper for governor checks to the schedutil cpufreq governor and move cpufreq-specific EAS checks to cpufreq (Rafael Wysocki) - Populate the cpu_capacity sysfs entries from the intel_pstate driver after registering asym capacity support (Ricardo Neri) - Add support for enabling Energy-aware scheduling (EAS) to the intel_pstate driver when operating in the passive mode on a hybrid platform (Rafael Wysocki) - Drop redundant cpus_read_lock() from store_local_boost() in the cpufreq core (Seyediman Seyedarab) - Replace sscanf() with kstrtouint() in the cpufreq code and use a symbol instead of a raw number in it (Bowen Yu) - Add support for autonomous CPU performance state selection to the CPPC cpufreq driver (Lifeng Zheng) - OPP: Add dev_pm_opp_set_level() (Praveen Talari) - Introduce scope-based cleanup headers and mutex locking guards in OPP core (Viresh Kumar) - Switch OPP to use kmemdup_array() (Zhang Enpei) - Optimize bucket assignment when next_timer_ns equals KTIME_MAX in the menu cpuidle governor (Zhongqiu Han) - Convert the cpuidle PSCI driver to a faux device one (Sudeep Holla) - Add C1 demotion on/off sysfs knob to the intel_idle driver (Artem Bityutskiy) - Fix typos in two comments in the teo cpuidle governor (Atul Kumar Pant) - Fix denying of auto suspend in pm_suspend_timer_fn() (Charan Teja Kalla) - Move debug runtime PM attributes to runtime_attrs[] (Rafael Wysocki) - Add new devm_ functions for enabling runtime PM and runtime PM reference counting (Bence Csókás) - Remove size arguments from strscpy() calls in the hibernation core code (Thorsten Blum) - Adjust the handling of devices with asynchronous suspend enabled during system suspend and resume to start resuming them immediately after resuming their parents and to start suspending such a device immediately after suspending its first child (Rafael Wysocki) - Adjust messages printed during tasks freezing to avoid using pr_cont() (Andrew Sayers, Paul Menzel) - Clean up unnecessary usage of !! in pm_print_times_init() (Zihuan Zhang) - Add missing wakeup source attribute relax_count to sysfs and remove the space character at the end ofi the string produced by pm_show_wakelocks() (Zijun Hu) - Add configurable pm_test delay for hibernation (Zihuan Zhang) - Disable asynchronous suspend in ucsi_ccg_probe() to prevent the cypd4226 device on Tegra boards from suspending prematurely (Jon Hunter) - Unbreak printing PM debug messages during hibernation and clean up some related code (Rafael Wysocki) - Add a systemd service to run cpupower and change cpupower binding's Makefile to use -lcpupower (John B. Wyatt IV, Francesco Poli)" * tag 'pm-6.16-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm: (72 commits) cpufreq: CPPC: Add support for autonomous selection cpufreq: Update sscanf() to kstrtouint() cpufreq: Replace magic number OPP: switch to use kmemdup_array() PM: freezer: Rewrite restarting tasks log to remove stray *done.* PM: runtime: fix denying of auto suspend in pm_suspend_timer_fn() cpufreq: drop redundant cpus_read_lock() from store_local_boost() cpupower: do not install files to /etc/default/ cpupower: do not call systemctl at install time cpupower: do not write DESTDIR to cpupower.service PM: sleep: Introduce pm_sleep_transition_in_progress() cpufreq/amd-pstate: Avoid shadowing ret in amd_pstate_ut_check_driver() cpufreq: intel_pstate: Document hybrid processor support cpufreq: intel_pstate: EAS: Increase cost for CPUs using L3 cache cpufreq: intel_pstate: EAS support for hybrid platforms PM: EM: Introduce em_adjust_cpu_capacity() PM: EM: Move CPU capacity check to em_adjust_new_capacity() PM: EM: Documentation: Fix typos in example driver code cpufreq: Drop policy locking from cpufreq_policy_is_good_for_eas() PM: sleep: Introduce pm_suspend_in_progress() ...
298 lines
8.2 KiB
C
298 lines
8.2 KiB
C
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
/*
|
|
* AMD Processor P-state Frequency Driver Unit Test
|
|
*
|
|
* Copyright (C) 2022 Advanced Micro Devices, Inc. All Rights Reserved.
|
|
*
|
|
* Author: Meng Li <li.meng@amd.com>
|
|
*
|
|
* The AMD P-State Unit Test is a test module for testing the amd-pstate
|
|
* driver. 1) It can help all users to verify their processor support
|
|
* (SBIOS/Firmware or Hardware). 2) Kernel can have a basic function
|
|
* test to avoid the kernel regression during the update. 3) We can
|
|
* introduce more functional or performance tests to align the result
|
|
* together, it will benefit power and performance scale optimization.
|
|
*
|
|
* This driver implements basic framework with plans to enhance it with
|
|
* additional test cases to improve the depth and coverage of the test.
|
|
*
|
|
* See Documentation/admin-guide/pm/amd-pstate.rst Unit Tests for
|
|
* amd-pstate to get more detail.
|
|
*/
|
|
|
|
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
|
|
|
#include <linux/bitfield.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/module.h>
|
|
#include <linux/moduleparam.h>
|
|
#include <linux/fs.h>
|
|
#include <linux/cleanup.h>
|
|
|
|
#include <acpi/cppc_acpi.h>
|
|
|
|
#include <asm/msr.h>
|
|
|
|
#include "amd-pstate.h"
|
|
|
|
|
|
struct amd_pstate_ut_struct {
|
|
const char *name;
|
|
int (*func)(u32 index);
|
|
};
|
|
|
|
/*
|
|
* Kernel module for testing the AMD P-State unit test
|
|
*/
|
|
static int amd_pstate_ut_acpi_cpc_valid(u32 index);
|
|
static int amd_pstate_ut_check_enabled(u32 index);
|
|
static int amd_pstate_ut_check_perf(u32 index);
|
|
static int amd_pstate_ut_check_freq(u32 index);
|
|
static int amd_pstate_ut_check_driver(u32 index);
|
|
|
|
static struct amd_pstate_ut_struct amd_pstate_ut_cases[] = {
|
|
{"amd_pstate_ut_acpi_cpc_valid", amd_pstate_ut_acpi_cpc_valid },
|
|
{"amd_pstate_ut_check_enabled", amd_pstate_ut_check_enabled },
|
|
{"amd_pstate_ut_check_perf", amd_pstate_ut_check_perf },
|
|
{"amd_pstate_ut_check_freq", amd_pstate_ut_check_freq },
|
|
{"amd_pstate_ut_check_driver", amd_pstate_ut_check_driver }
|
|
};
|
|
|
|
static bool get_shared_mem(void)
|
|
{
|
|
bool result = false;
|
|
|
|
if (!boot_cpu_has(X86_FEATURE_CPPC))
|
|
result = true;
|
|
|
|
return result;
|
|
}
|
|
|
|
/*
|
|
* check the _CPC object is present in SBIOS.
|
|
*/
|
|
static int amd_pstate_ut_acpi_cpc_valid(u32 index)
|
|
{
|
|
if (!acpi_cpc_valid()) {
|
|
pr_err("%s the _CPC object is not present in SBIOS!\n", __func__);
|
|
return -EINVAL;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* check if amd pstate is enabled
|
|
*/
|
|
static int amd_pstate_ut_check_enabled(u32 index)
|
|
{
|
|
u64 cppc_enable = 0;
|
|
int ret;
|
|
|
|
if (get_shared_mem())
|
|
return 0;
|
|
|
|
ret = rdmsrq_safe(MSR_AMD_CPPC_ENABLE, &cppc_enable);
|
|
if (ret) {
|
|
pr_err("%s rdmsrq_safe MSR_AMD_CPPC_ENABLE ret=%d error!\n", __func__, ret);
|
|
return ret;
|
|
}
|
|
|
|
if (!cppc_enable) {
|
|
pr_err("%s amd pstate must be enabled!\n", __func__);
|
|
return -EINVAL;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* check if performance values are reasonable.
|
|
* highest_perf >= nominal_perf > lowest_nonlinear_perf > lowest_perf > 0
|
|
*/
|
|
static int amd_pstate_ut_check_perf(u32 index)
|
|
{
|
|
int cpu = 0, ret = 0;
|
|
u32 highest_perf = 0, nominal_perf = 0, lowest_nonlinear_perf = 0, lowest_perf = 0;
|
|
u64 cap1 = 0;
|
|
struct cppc_perf_caps cppc_perf;
|
|
union perf_cached cur_perf;
|
|
|
|
for_each_online_cpu(cpu) {
|
|
struct cpufreq_policy *policy __free(put_cpufreq_policy) = NULL;
|
|
struct amd_cpudata *cpudata;
|
|
|
|
policy = cpufreq_cpu_get(cpu);
|
|
if (!policy)
|
|
continue;
|
|
cpudata = policy->driver_data;
|
|
|
|
if (get_shared_mem()) {
|
|
ret = cppc_get_perf_caps(cpu, &cppc_perf);
|
|
if (ret) {
|
|
pr_err("%s cppc_get_perf_caps ret=%d error!\n", __func__, ret);
|
|
return ret;
|
|
}
|
|
|
|
highest_perf = cppc_perf.highest_perf;
|
|
nominal_perf = cppc_perf.nominal_perf;
|
|
lowest_nonlinear_perf = cppc_perf.lowest_nonlinear_perf;
|
|
lowest_perf = cppc_perf.lowest_perf;
|
|
} else {
|
|
ret = rdmsrq_safe_on_cpu(cpu, MSR_AMD_CPPC_CAP1, &cap1);
|
|
if (ret) {
|
|
pr_err("%s read CPPC_CAP1 ret=%d error!\n", __func__, ret);
|
|
return ret;
|
|
}
|
|
|
|
highest_perf = FIELD_GET(AMD_CPPC_HIGHEST_PERF_MASK, cap1);
|
|
nominal_perf = FIELD_GET(AMD_CPPC_NOMINAL_PERF_MASK, cap1);
|
|
lowest_nonlinear_perf = FIELD_GET(AMD_CPPC_LOWNONLIN_PERF_MASK, cap1);
|
|
lowest_perf = FIELD_GET(AMD_CPPC_LOWEST_PERF_MASK, cap1);
|
|
}
|
|
|
|
cur_perf = READ_ONCE(cpudata->perf);
|
|
if (highest_perf != cur_perf.highest_perf && !cpudata->hw_prefcore) {
|
|
pr_err("%s cpu%d highest=%d %d highest perf doesn't match\n",
|
|
__func__, cpu, highest_perf, cur_perf.highest_perf);
|
|
return -EINVAL;
|
|
}
|
|
if (nominal_perf != cur_perf.nominal_perf ||
|
|
(lowest_nonlinear_perf != cur_perf.lowest_nonlinear_perf) ||
|
|
(lowest_perf != cur_perf.lowest_perf)) {
|
|
pr_err("%s cpu%d nominal=%d %d lowest_nonlinear=%d %d lowest=%d %d, they should be equal!\n",
|
|
__func__, cpu, nominal_perf, cur_perf.nominal_perf,
|
|
lowest_nonlinear_perf, cur_perf.lowest_nonlinear_perf,
|
|
lowest_perf, cur_perf.lowest_perf);
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (!((highest_perf >= nominal_perf) &&
|
|
(nominal_perf > lowest_nonlinear_perf) &&
|
|
(lowest_nonlinear_perf >= lowest_perf) &&
|
|
(lowest_perf > 0))) {
|
|
pr_err("%s cpu%d highest=%d >= nominal=%d > lowest_nonlinear=%d > lowest=%d > 0, the formula is incorrect!\n",
|
|
__func__, cpu, highest_perf, nominal_perf,
|
|
lowest_nonlinear_perf, lowest_perf);
|
|
return -EINVAL;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Check if frequency values are reasonable.
|
|
* max_freq >= nominal_freq > lowest_nonlinear_freq > min_freq > 0
|
|
* check max freq when set support boost mode.
|
|
*/
|
|
static int amd_pstate_ut_check_freq(u32 index)
|
|
{
|
|
int cpu = 0;
|
|
|
|
for_each_online_cpu(cpu) {
|
|
struct cpufreq_policy *policy __free(put_cpufreq_policy) = NULL;
|
|
struct amd_cpudata *cpudata;
|
|
|
|
policy = cpufreq_cpu_get(cpu);
|
|
if (!policy)
|
|
continue;
|
|
cpudata = policy->driver_data;
|
|
|
|
if (!((policy->cpuinfo.max_freq >= cpudata->nominal_freq) &&
|
|
(cpudata->nominal_freq > cpudata->lowest_nonlinear_freq) &&
|
|
(cpudata->lowest_nonlinear_freq >= policy->cpuinfo.min_freq) &&
|
|
(policy->cpuinfo.min_freq > 0))) {
|
|
pr_err("%s cpu%d max=%d >= nominal=%d > lowest_nonlinear=%d > min=%d > 0, the formula is incorrect!\n",
|
|
__func__, cpu, policy->cpuinfo.max_freq, cpudata->nominal_freq,
|
|
cpudata->lowest_nonlinear_freq, policy->cpuinfo.min_freq);
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (cpudata->lowest_nonlinear_freq != policy->min) {
|
|
pr_err("%s cpu%d cpudata_lowest_nonlinear_freq=%d policy_min=%d, they should be equal!\n",
|
|
__func__, cpu, cpudata->lowest_nonlinear_freq, policy->min);
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (cpudata->boost_supported) {
|
|
if ((policy->max != policy->cpuinfo.max_freq) &&
|
|
(policy->max != cpudata->nominal_freq)) {
|
|
pr_err("%s cpu%d policy_max=%d should be equal cpu_max=%d or cpu_nominal=%d !\n",
|
|
__func__, cpu, policy->max, policy->cpuinfo.max_freq,
|
|
cpudata->nominal_freq);
|
|
return -EINVAL;
|
|
}
|
|
} else {
|
|
pr_err("%s cpu%d must support boost!\n", __func__, cpu);
|
|
return -EINVAL;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int amd_pstate_set_mode(enum amd_pstate_mode mode)
|
|
{
|
|
const char *mode_str = amd_pstate_get_mode_string(mode);
|
|
|
|
pr_debug("->setting mode to %s\n", mode_str);
|
|
|
|
return amd_pstate_update_status(mode_str, strlen(mode_str));
|
|
}
|
|
|
|
static int amd_pstate_ut_check_driver(u32 index)
|
|
{
|
|
enum amd_pstate_mode mode1, mode2 = AMD_PSTATE_DISABLE;
|
|
enum amd_pstate_mode orig_mode = amd_pstate_get_status();
|
|
int ret;
|
|
|
|
for (mode1 = AMD_PSTATE_DISABLE; mode1 < AMD_PSTATE_MAX; mode1++) {
|
|
ret = amd_pstate_set_mode(mode1);
|
|
if (ret)
|
|
return ret;
|
|
for (mode2 = AMD_PSTATE_DISABLE; mode2 < AMD_PSTATE_MAX; mode2++) {
|
|
if (mode1 == mode2)
|
|
continue;
|
|
ret = amd_pstate_set_mode(mode2);
|
|
if (ret)
|
|
goto out;
|
|
}
|
|
}
|
|
|
|
out:
|
|
if (ret)
|
|
pr_warn("%s: failed to update status for %s->%s: %d\n", __func__,
|
|
amd_pstate_get_mode_string(mode1),
|
|
amd_pstate_get_mode_string(mode2), ret);
|
|
|
|
amd_pstate_set_mode(orig_mode);
|
|
return ret;
|
|
}
|
|
|
|
static int __init amd_pstate_ut_init(void)
|
|
{
|
|
u32 i = 0, arr_size = ARRAY_SIZE(amd_pstate_ut_cases);
|
|
|
|
for (i = 0; i < arr_size; i++) {
|
|
int ret = amd_pstate_ut_cases[i].func(i);
|
|
|
|
if (ret)
|
|
pr_err("%-4d %-20s\t fail: %d!\n", i+1, amd_pstate_ut_cases[i].name, ret);
|
|
else
|
|
pr_info("%-4d %-20s\t success!\n", i+1, amd_pstate_ut_cases[i].name);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void __exit amd_pstate_ut_exit(void)
|
|
{
|
|
}
|
|
|
|
module_init(amd_pstate_ut_init);
|
|
module_exit(amd_pstate_ut_exit);
|
|
|
|
MODULE_AUTHOR("Meng Li <li.meng@amd.com>");
|
|
MODULE_DESCRIPTION("AMD P-state driver Test module");
|
|
MODULE_LICENSE("GPL");
|