forked from Minki/linux
linux-kselftest-next-6.1-rc1
This Kselftest update for Linux 6.1-rc1 consists of fixes and new tests. - Adds a amd-pstate-ut test module, this module is used by kselftest to unit test amd-pstate functionality - Fixes and cleanups to to cpu-hotplug to delete the fault injection test code - Improvements to vm test to use top_srcdir for builds -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEPZKym/RZuOCGeA/kCwJExA0NQxwFAmM912gACgkQCwJExA0N QxzfAhAAspak4B2FVZdXrb7ulGxCV2CSd49qXbv++7rBy3Ey17XlIO8pUj2FMPpx nBrD2UD+ET/6wHjSzkcSzU47N2BnhetuUWqN2vPmuYo4c8xDME9VSWeoKQ9Yw5rc 6r6TxNG/Jbxab4y9r8jibwkidVzcgfYO/Ecnj9HAZ6wDERkVG+LBxpX4HpxEnCsY c3frYFl0cdtLOSGbEA18qctG7ro2otgh4+cWVfSo9NDypL9UfF8bZ8DzqeMOwRLr z2S8L+kBPyQx+ZNdqUgNOfegVx2gKu/P43Xpg8WqRJG/42xxmRmftEOLoVKZ1cCe Rpjv+ZV+/u3QnbEejqJ7MU/QX9JzMG35O4mo7ojxpOJ+cZNXc1ycOm+IOvTCSUJE fiqM2idLvQNjKMVI+FHvkE+9us6K8fzquCYqgRLBKCnfnJJfgT6tWwZpw/G8OSZ6 Px37bfQhALzDj79OkxxoV96GdkR9a2L8GRvZG+7W4l6Oa00OM+rK1oQnjKVgmjT5 wtMwJAXGpwFYqnJagtXcg8dsxS/ZA+k4Eq/skd/yUlCmugmgeVltjk3UmEAYs6Nx ame3798/haptgR1u7ncqltqjx11YR2k9i0Sjf7iqQl8zJhjtDdePAlo2gB4mFUio mZ9BBxCD+oUnAZprA5AwN0ZxPKLWgvPS5rLqTtFt3Pf0agjHSpY= =O0Lh -----END PGP SIGNATURE----- Merge tag 'linux-kselftest-next-6.1-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/shuah/linux-kselftest Pull Kselftest updates from Shuah Khan: "Fixes and new tests: - Add an amd-pstate-ut test module, used by kselftest to unit test amd-pstate functionality - Fixes and cleanups to to cpu-hotplug to delete the fault injection test code - Improvements to vm test to use top_srcdir for builds" * tag 'linux-kselftest-next-6.1-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/shuah/linux-kselftest: docs:kselftest: fix kselftest_module.h path of example module cpufreq: amd-pstate: Add explanation for X86_AMD_PSTATE_UT selftests/cpu-hotplug: Add log info when test success selftests/cpu-hotplug: Reserve one cpu online at least selftests/cpu-hotplug: Delete fault injection related code selftests/cpu-hotplug: Use return instead of exit selftests/cpu-hotplug: Correct log info cpufreq: amd-pstate: modify type in argument 2 for filp_open Documentation: amd-pstate: Add unit test introduction selftests: amd-pstate: Add test trigger for amd-pstate driver cpufreq: amd-pstate: Add test module for amd-pstate driver cpufreq: amd-pstate: Expose struct amd_cpudata selftests/vm: use top_srcdir instead of recomputing relative paths
This commit is contained in:
commit
dd42d9c3f4
@ -182,6 +182,7 @@ to the ``struct sugov_cpu`` that the utilization update belongs to.
|
||||
Then, ``amd-pstate`` updates the desired performance according to the CPU
|
||||
scheduler assigned.
|
||||
|
||||
.. _processor_support:
|
||||
|
||||
Processor Support
|
||||
=======================
|
||||
@ -282,6 +283,8 @@ efficiency frequency management method on AMD processors.
|
||||
Kernel Module Options for ``amd-pstate``
|
||||
=========================================
|
||||
|
||||
.. _shared_mem:
|
||||
|
||||
``shared_mem``
|
||||
Use a module param (shared_mem) to enable related processors manually with
|
||||
**amd_pstate.shared_mem=1**.
|
||||
@ -393,6 +396,76 @@ about part of the output. ::
|
||||
CPU_005 712 116384 39 49 166 0.7565 9645075 2214891 38431470 25.1 11.646 469 2.496 kworker/5:0-40
|
||||
CPU_006 712 116408 39 49 166 0.6769 8950227 1839034 37192089 24.06 11.272 470 2.496 kworker/6:0-1264
|
||||
|
||||
Unit Tests for amd-pstate
|
||||
-------------------------
|
||||
|
||||
``amd-pstate-ut`` is a test module for testing the ``amd-pstate`` driver.
|
||||
|
||||
* It can help all users to verify their processor support (SBIOS/Firmware or Hardware).
|
||||
|
||||
* Kernel can have a basic function test to avoid the kernel regression during the update.
|
||||
|
||||
* We can introduce more functional or performance tests to align the result together, it will benefit power and performance scale optimization.
|
||||
|
||||
1. Test case decriptions
|
||||
|
||||
+---------+--------------------------------+------------------------------------------------------------------------------------+
|
||||
| Index | Functions | Description |
|
||||
+=========+================================+====================================================================================+
|
||||
| 0 | amd_pstate_ut_acpi_cpc_valid || Check whether the _CPC object is present in SBIOS. |
|
||||
| | || |
|
||||
| | || The detail refer to `Processor Support <processor_support_>`_. |
|
||||
+---------+--------------------------------+------------------------------------------------------------------------------------+
|
||||
| 1 | amd_pstate_ut_check_enabled || Check whether AMD P-State is enabled. |
|
||||
| | || |
|
||||
| | || AMD P-States and ACPI hardware P-States always can be supported in one processor. |
|
||||
| | | But AMD P-States has the higher priority and if it is enabled with |
|
||||
| | | :c:macro:`MSR_AMD_CPPC_ENABLE` or ``cppc_set_enable``, it will respond to the |
|
||||
| | | request from AMD P-States. |
|
||||
+---------+--------------------------------+------------------------------------------------------------------------------------+
|
||||
| 2 | amd_pstate_ut_check_perf || Check if the each performance values are reasonable. |
|
||||
| | || highest_perf >= nominal_perf > lowest_nonlinear_perf > lowest_perf > 0. |
|
||||
+---------+--------------------------------+------------------------------------------------------------------------------------+
|
||||
| 3 | amd_pstate_ut_check_freq || Check if the each frequency values and max freq when set support boost mode |
|
||||
| | | are reasonable. |
|
||||
| | || max_freq >= nominal_freq > lowest_nonlinear_freq > min_freq > 0 |
|
||||
| | || If boost is not active but supported, this maximum frequency will be larger than |
|
||||
| | | the one in ``cpuinfo``. |
|
||||
+---------+--------------------------------+------------------------------------------------------------------------------------+
|
||||
|
||||
#. How to execute the tests
|
||||
|
||||
We use test module in the kselftest frameworks to implement it.
|
||||
We create amd-pstate-ut module and tie it into kselftest.(for
|
||||
details refer to Linux Kernel Selftests [4]_).
|
||||
|
||||
1. Build
|
||||
|
||||
+ open the :c:macro:`CONFIG_X86_AMD_PSTATE` configuration option.
|
||||
+ set the :c:macro:`CONFIG_X86_AMD_PSTATE_UT` configuration option to M.
|
||||
+ make project
|
||||
+ make selftest ::
|
||||
|
||||
$ cd linux
|
||||
$ make -C tools/testing/selftests
|
||||
|
||||
#. Installation & Steps ::
|
||||
|
||||
$ make -C tools/testing/selftests install INSTALL_PATH=~/kselftest
|
||||
$ sudo ./kselftest/run_kselftest.sh -c amd-pstate
|
||||
TAP version 13
|
||||
1..1
|
||||
# selftests: amd-pstate: amd-pstate-ut.sh
|
||||
# amd-pstate-ut: ok
|
||||
ok 1 selftests: amd-pstate: amd-pstate-ut.sh
|
||||
|
||||
#. Results ::
|
||||
|
||||
$ dmesg | grep "amd_pstate_ut" | tee log.txt
|
||||
[12977.570663] amd_pstate_ut: 1 amd_pstate_ut_acpi_cpc_valid success!
|
||||
[12977.570673] amd_pstate_ut: 2 amd_pstate_ut_check_enabled success!
|
||||
[12977.571207] amd_pstate_ut: 3 amd_pstate_ut_check_perf success!
|
||||
[12977.571212] amd_pstate_ut: 4 amd_pstate_ut_check_freq success!
|
||||
|
||||
Reference
|
||||
===========
|
||||
@ -405,3 +478,6 @@ Reference
|
||||
|
||||
.. [3] Processor Programming Reference (PPR) for AMD Family 19h Model 51h, Revision A1 Processors
|
||||
https://www.amd.com/system/files/TechDocs/56569-A1-PUB.zip
|
||||
|
||||
.. [4] Linux Kernel Selftests,
|
||||
https://www.kernel.org/doc/html/latest/dev-tools/kselftest.html
|
||||
|
@ -320,7 +320,7 @@ A bare bones test module might look like this:
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#include "../tools/testing/selftests/kselftest/module.h"
|
||||
#include "../tools/testing/selftests/kselftest_module.h"
|
||||
|
||||
KSTM_MODULE_GLOBALS();
|
||||
|
||||
|
@ -1070,6 +1070,7 @@ L: linux-pm@vger.kernel.org
|
||||
S: Supported
|
||||
F: Documentation/admin-guide/pm/amd-pstate.rst
|
||||
F: drivers/cpufreq/amd-pstate*
|
||||
F: include/linux/amd-pstate.h
|
||||
F: tools/power/x86/amd_pstate_tracer/amd_pstate_trace.py
|
||||
|
||||
AMD PTDMA DRIVER
|
||||
|
@ -51,6 +51,21 @@ config X86_AMD_PSTATE
|
||||
|
||||
If in doubt, say N.
|
||||
|
||||
config X86_AMD_PSTATE_UT
|
||||
tristate "selftest for AMD Processor P-State driver"
|
||||
depends on X86 && ACPI_PROCESSOR
|
||||
default n
|
||||
help
|
||||
This kernel module is used for testing. It's safe to say M here.
|
||||
|
||||
It can also be built-in without X86_AMD_PSTATE enabled.
|
||||
Currently, only tests for amd-pstate are supported. If X86_AMD_PSTATE
|
||||
is set disabled, it can tell the users test can only run on amd-pstate
|
||||
driver, please set X86_AMD_PSTATE enabled.
|
||||
In the future, comparison tests will be added. It can set amd-pstate
|
||||
disabled and set acpi-cpufreq enabled to run test cases, then compare
|
||||
the test results.
|
||||
|
||||
config X86_ACPI_CPUFREQ
|
||||
tristate "ACPI Processor P-States driver"
|
||||
depends on ACPI_PROCESSOR
|
||||
|
@ -30,6 +30,7 @@ amd_pstate-y := amd-pstate.o amd-pstate-trace.o
|
||||
|
||||
obj-$(CONFIG_X86_ACPI_CPUFREQ) += acpi-cpufreq.o
|
||||
obj-$(CONFIG_X86_AMD_PSTATE) += amd_pstate.o
|
||||
obj-$(CONFIG_X86_AMD_PSTATE_UT) += amd-pstate-ut.o
|
||||
obj-$(CONFIG_X86_POWERNOW_K8) += powernow-k8.o
|
||||
obj-$(CONFIG_X86_PCC_CPUFREQ) += pcc-cpufreq.o
|
||||
obj-$(CONFIG_X86_POWERNOW_K6) += powernow-k6.o
|
||||
|
293
drivers/cpufreq/amd-pstate-ut.c
Normal file
293
drivers/cpufreq/amd-pstate-ut.c
Normal file
@ -0,0 +1,293 @@
|
||||
// SPDX-License-Identifier: GPL-1.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/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/amd-pstate.h>
|
||||
|
||||
#include <acpi/cppc_acpi.h>
|
||||
|
||||
/*
|
||||
* Abbreviations:
|
||||
* amd_pstate_ut: used as a shortform for AMD P-State unit test.
|
||||
* It helps to keep variable names smaller, simpler
|
||||
*/
|
||||
enum amd_pstate_ut_result {
|
||||
AMD_PSTATE_UT_RESULT_PASS,
|
||||
AMD_PSTATE_UT_RESULT_FAIL,
|
||||
};
|
||||
|
||||
struct amd_pstate_ut_struct {
|
||||
const char *name;
|
||||
void (*func)(u32 index);
|
||||
enum amd_pstate_ut_result result;
|
||||
};
|
||||
|
||||
/*
|
||||
* Kernel module for testing the AMD P-State unit test
|
||||
*/
|
||||
static void amd_pstate_ut_acpi_cpc_valid(u32 index);
|
||||
static void amd_pstate_ut_check_enabled(u32 index);
|
||||
static void amd_pstate_ut_check_perf(u32 index);
|
||||
static void amd_pstate_ut_check_freq(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 }
|
||||
};
|
||||
|
||||
static bool get_shared_mem(void)
|
||||
{
|
||||
bool result = false;
|
||||
char path[] = "/sys/module/amd_pstate/parameters/shared_mem";
|
||||
char buf[5] = {0};
|
||||
struct file *filp = NULL;
|
||||
loff_t pos = 0;
|
||||
ssize_t ret;
|
||||
|
||||
if (!boot_cpu_has(X86_FEATURE_CPPC)) {
|
||||
filp = filp_open(path, O_RDONLY, 0);
|
||||
if (IS_ERR(filp))
|
||||
pr_err("%s unable to open %s file!\n", __func__, path);
|
||||
else {
|
||||
ret = kernel_read(filp, &buf, sizeof(buf), &pos);
|
||||
if (ret < 0)
|
||||
pr_err("%s read %s file fail ret=%ld!\n",
|
||||
__func__, path, (long)ret);
|
||||
filp_close(filp, NULL);
|
||||
}
|
||||
|
||||
if ('Y' == *buf)
|
||||
result = true;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* check the _CPC object is present in SBIOS.
|
||||
*/
|
||||
static void amd_pstate_ut_acpi_cpc_valid(u32 index)
|
||||
{
|
||||
if (acpi_cpc_valid())
|
||||
amd_pstate_ut_cases[index].result = AMD_PSTATE_UT_RESULT_PASS;
|
||||
else {
|
||||
amd_pstate_ut_cases[index].result = AMD_PSTATE_UT_RESULT_FAIL;
|
||||
pr_err("%s the _CPC object is not present in SBIOS!\n", __func__);
|
||||
}
|
||||
}
|
||||
|
||||
static void amd_pstate_ut_pstate_enable(u32 index)
|
||||
{
|
||||
int ret = 0;
|
||||
u64 cppc_enable = 0;
|
||||
|
||||
ret = rdmsrl_safe(MSR_AMD_CPPC_ENABLE, &cppc_enable);
|
||||
if (ret) {
|
||||
amd_pstate_ut_cases[index].result = AMD_PSTATE_UT_RESULT_FAIL;
|
||||
pr_err("%s rdmsrl_safe MSR_AMD_CPPC_ENABLE ret=%d error!\n", __func__, ret);
|
||||
return;
|
||||
}
|
||||
if (cppc_enable)
|
||||
amd_pstate_ut_cases[index].result = AMD_PSTATE_UT_RESULT_PASS;
|
||||
else {
|
||||
amd_pstate_ut_cases[index].result = AMD_PSTATE_UT_RESULT_FAIL;
|
||||
pr_err("%s amd pstate must be enabled!\n", __func__);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* check if amd pstate is enabled
|
||||
*/
|
||||
static void amd_pstate_ut_check_enabled(u32 index)
|
||||
{
|
||||
if (get_shared_mem())
|
||||
amd_pstate_ut_cases[index].result = AMD_PSTATE_UT_RESULT_PASS;
|
||||
else
|
||||
amd_pstate_ut_pstate_enable(index);
|
||||
}
|
||||
|
||||
/*
|
||||
* check if performance values are reasonable.
|
||||
* highest_perf >= nominal_perf > lowest_nonlinear_perf > lowest_perf > 0
|
||||
*/
|
||||
static void 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;
|
||||
struct cpufreq_policy *policy = NULL;
|
||||
struct amd_cpudata *cpudata = NULL;
|
||||
|
||||
highest_perf = amd_get_highest_perf();
|
||||
|
||||
for_each_possible_cpu(cpu) {
|
||||
policy = cpufreq_cpu_get(cpu);
|
||||
if (!policy)
|
||||
break;
|
||||
cpudata = policy->driver_data;
|
||||
|
||||
if (get_shared_mem()) {
|
||||
ret = cppc_get_perf_caps(cpu, &cppc_perf);
|
||||
if (ret) {
|
||||
amd_pstate_ut_cases[index].result = AMD_PSTATE_UT_RESULT_FAIL;
|
||||
pr_err("%s cppc_get_perf_caps ret=%d error!\n", __func__, ret);
|
||||
return;
|
||||
}
|
||||
|
||||
nominal_perf = cppc_perf.nominal_perf;
|
||||
lowest_nonlinear_perf = cppc_perf.lowest_nonlinear_perf;
|
||||
lowest_perf = cppc_perf.lowest_perf;
|
||||
} else {
|
||||
ret = rdmsrl_safe_on_cpu(cpu, MSR_AMD_CPPC_CAP1, &cap1);
|
||||
if (ret) {
|
||||
amd_pstate_ut_cases[index].result = AMD_PSTATE_UT_RESULT_FAIL;
|
||||
pr_err("%s read CPPC_CAP1 ret=%d error!\n", __func__, ret);
|
||||
return;
|
||||
}
|
||||
|
||||
nominal_perf = AMD_CPPC_NOMINAL_PERF(cap1);
|
||||
lowest_nonlinear_perf = AMD_CPPC_LOWNONLIN_PERF(cap1);
|
||||
lowest_perf = AMD_CPPC_LOWEST_PERF(cap1);
|
||||
}
|
||||
|
||||
if ((highest_perf != READ_ONCE(cpudata->highest_perf)) ||
|
||||
(nominal_perf != READ_ONCE(cpudata->nominal_perf)) ||
|
||||
(lowest_nonlinear_perf != READ_ONCE(cpudata->lowest_nonlinear_perf)) ||
|
||||
(lowest_perf != READ_ONCE(cpudata->lowest_perf))) {
|
||||
amd_pstate_ut_cases[index].result = AMD_PSTATE_UT_RESULT_FAIL;
|
||||
pr_err("%s cpu%d highest=%d %d nominal=%d %d lowest_nonlinear=%d %d lowest=%d %d, they should be equal!\n",
|
||||
__func__, cpu, highest_perf, cpudata->highest_perf,
|
||||
nominal_perf, cpudata->nominal_perf,
|
||||
lowest_nonlinear_perf, cpudata->lowest_nonlinear_perf,
|
||||
lowest_perf, cpudata->lowest_perf);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!((highest_perf >= nominal_perf) &&
|
||||
(nominal_perf > lowest_nonlinear_perf) &&
|
||||
(lowest_nonlinear_perf > lowest_perf) &&
|
||||
(lowest_perf > 0))) {
|
||||
amd_pstate_ut_cases[index].result = AMD_PSTATE_UT_RESULT_FAIL;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
amd_pstate_ut_cases[index].result = AMD_PSTATE_UT_RESULT_PASS;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 void amd_pstate_ut_check_freq(u32 index)
|
||||
{
|
||||
int cpu = 0;
|
||||
struct cpufreq_policy *policy = NULL;
|
||||
struct amd_cpudata *cpudata = NULL;
|
||||
|
||||
for_each_possible_cpu(cpu) {
|
||||
policy = cpufreq_cpu_get(cpu);
|
||||
if (!policy)
|
||||
break;
|
||||
cpudata = policy->driver_data;
|
||||
|
||||
if (!((cpudata->max_freq >= cpudata->nominal_freq) &&
|
||||
(cpudata->nominal_freq > cpudata->lowest_nonlinear_freq) &&
|
||||
(cpudata->lowest_nonlinear_freq > cpudata->min_freq) &&
|
||||
(cpudata->min_freq > 0))) {
|
||||
amd_pstate_ut_cases[index].result = AMD_PSTATE_UT_RESULT_FAIL;
|
||||
pr_err("%s cpu%d max=%d >= nominal=%d > lowest_nonlinear=%d > min=%d > 0, the formula is incorrect!\n",
|
||||
__func__, cpu, cpudata->max_freq, cpudata->nominal_freq,
|
||||
cpudata->lowest_nonlinear_freq, cpudata->min_freq);
|
||||
return;
|
||||
}
|
||||
|
||||
if (cpudata->min_freq != policy->min) {
|
||||
amd_pstate_ut_cases[index].result = AMD_PSTATE_UT_RESULT_FAIL;
|
||||
pr_err("%s cpu%d cpudata_min_freq=%d policy_min=%d, they should be equal!\n",
|
||||
__func__, cpu, cpudata->min_freq, policy->min);
|
||||
return;
|
||||
}
|
||||
|
||||
if (cpudata->boost_supported) {
|
||||
if ((policy->max == cpudata->max_freq) ||
|
||||
(policy->max == cpudata->nominal_freq))
|
||||
amd_pstate_ut_cases[index].result = AMD_PSTATE_UT_RESULT_PASS;
|
||||
else {
|
||||
amd_pstate_ut_cases[index].result = AMD_PSTATE_UT_RESULT_FAIL;
|
||||
pr_err("%s cpu%d policy_max=%d should be equal cpu_max=%d or cpu_nominal=%d !\n",
|
||||
__func__, cpu, policy->max, cpudata->max_freq,
|
||||
cpudata->nominal_freq);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
amd_pstate_ut_cases[index].result = AMD_PSTATE_UT_RESULT_FAIL;
|
||||
pr_err("%s cpu%d must support boost!\n", __func__, cpu);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
amd_pstate_ut_cases[index].result = AMD_PSTATE_UT_RESULT_PASS;
|
||||
}
|
||||
|
||||
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++) {
|
||||
amd_pstate_ut_cases[i].func(i);
|
||||
switch (amd_pstate_ut_cases[i].result) {
|
||||
case AMD_PSTATE_UT_RESULT_PASS:
|
||||
pr_info("%-4d %-20s\t success!\n", i+1, amd_pstate_ut_cases[i].name);
|
||||
break;
|
||||
case AMD_PSTATE_UT_RESULT_FAIL:
|
||||
default:
|
||||
pr_info("%-4d %-20s\t fail!\n", i+1, amd_pstate_ut_cases[i].name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
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");
|
@ -36,6 +36,7 @@
|
||||
#include <linux/delay.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/static_call.h>
|
||||
#include <linux/amd-pstate.h>
|
||||
|
||||
#include <acpi/processor.h>
|
||||
#include <acpi/cppc_acpi.h>
|
||||
@ -65,65 +66,6 @@ MODULE_PARM_DESC(shared_mem,
|
||||
|
||||
static struct cpufreq_driver amd_pstate_driver;
|
||||
|
||||
/**
|
||||
* struct amd_aperf_mperf
|
||||
* @aperf: actual performance frequency clock count
|
||||
* @mperf: maximum performance frequency clock count
|
||||
* @tsc: time stamp counter
|
||||
*/
|
||||
struct amd_aperf_mperf {
|
||||
u64 aperf;
|
||||
u64 mperf;
|
||||
u64 tsc;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct amd_cpudata - private CPU data for AMD P-State
|
||||
* @cpu: CPU number
|
||||
* @req: constraint request to apply
|
||||
* @cppc_req_cached: cached performance request hints
|
||||
* @highest_perf: the maximum performance an individual processor may reach,
|
||||
* assuming ideal conditions
|
||||
* @nominal_perf: the maximum sustained performance level of the processor,
|
||||
* assuming ideal operating conditions
|
||||
* @lowest_nonlinear_perf: the lowest performance level at which nonlinear power
|
||||
* savings are achieved
|
||||
* @lowest_perf: the absolute lowest performance level of the processor
|
||||
* @max_freq: the frequency that mapped to highest_perf
|
||||
* @min_freq: the frequency that mapped to lowest_perf
|
||||
* @nominal_freq: the frequency that mapped to nominal_perf
|
||||
* @lowest_nonlinear_freq: the frequency that mapped to lowest_nonlinear_perf
|
||||
* @cur: Difference of Aperf/Mperf/tsc count between last and current sample
|
||||
* @prev: Last Aperf/Mperf/tsc count value read from register
|
||||
* @freq: current cpu frequency value
|
||||
* @boost_supported: check whether the Processor or SBIOS supports boost mode
|
||||
*
|
||||
* The amd_cpudata is key private data for each CPU thread in AMD P-State, and
|
||||
* represents all the attributes and goals that AMD P-State requests at runtime.
|
||||
*/
|
||||
struct amd_cpudata {
|
||||
int cpu;
|
||||
|
||||
struct freq_qos_request req[2];
|
||||
u64 cppc_req_cached;
|
||||
|
||||
u32 highest_perf;
|
||||
u32 nominal_perf;
|
||||
u32 lowest_nonlinear_perf;
|
||||
u32 lowest_perf;
|
||||
|
||||
u32 max_freq;
|
||||
u32 min_freq;
|
||||
u32 nominal_freq;
|
||||
u32 lowest_nonlinear_freq;
|
||||
|
||||
struct amd_aperf_mperf cur;
|
||||
struct amd_aperf_mperf prev;
|
||||
|
||||
u64 freq;
|
||||
bool boost_supported;
|
||||
};
|
||||
|
||||
static inline int pstate_enable(bool enable)
|
||||
{
|
||||
return wrmsrl_safe(MSR_AMD_CPPC_ENABLE, enable);
|
||||
|
77
include/linux/amd-pstate.h
Normal file
77
include/linux/amd-pstate.h
Normal file
@ -0,0 +1,77 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* linux/include/linux/amd-pstate.h
|
||||
*
|
||||
* Copyright (C) 2022 Advanced Micro Devices, Inc.
|
||||
*
|
||||
* Author: Meng Li <li.meng@amd.com>
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_AMD_PSTATE_H
|
||||
#define _LINUX_AMD_PSTATE_H
|
||||
|
||||
#include <linux/pm_qos.h>
|
||||
|
||||
/*********************************************************************
|
||||
* AMD P-state INTERFACE *
|
||||
*********************************************************************/
|
||||
/**
|
||||
* struct amd_aperf_mperf
|
||||
* @aperf: actual performance frequency clock count
|
||||
* @mperf: maximum performance frequency clock count
|
||||
* @tsc: time stamp counter
|
||||
*/
|
||||
struct amd_aperf_mperf {
|
||||
u64 aperf;
|
||||
u64 mperf;
|
||||
u64 tsc;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct amd_cpudata - private CPU data for AMD P-State
|
||||
* @cpu: CPU number
|
||||
* @req: constraint request to apply
|
||||
* @cppc_req_cached: cached performance request hints
|
||||
* @highest_perf: the maximum performance an individual processor may reach,
|
||||
* assuming ideal conditions
|
||||
* @nominal_perf: the maximum sustained performance level of the processor,
|
||||
* assuming ideal operating conditions
|
||||
* @lowest_nonlinear_perf: the lowest performance level at which nonlinear power
|
||||
* savings are achieved
|
||||
* @lowest_perf: the absolute lowest performance level of the processor
|
||||
* @max_freq: the frequency that mapped to highest_perf
|
||||
* @min_freq: the frequency that mapped to lowest_perf
|
||||
* @nominal_freq: the frequency that mapped to nominal_perf
|
||||
* @lowest_nonlinear_freq: the frequency that mapped to lowest_nonlinear_perf
|
||||
* @cur: Difference of Aperf/Mperf/tsc count between last and current sample
|
||||
* @prev: Last Aperf/Mperf/tsc count value read from register
|
||||
* @freq: current cpu frequency value
|
||||
* @boost_supported: check whether the Processor or SBIOS supports boost mode
|
||||
*
|
||||
* The amd_cpudata is key private data for each CPU thread in AMD P-State, and
|
||||
* represents all the attributes and goals that AMD P-State requests at runtime.
|
||||
*/
|
||||
struct amd_cpudata {
|
||||
int cpu;
|
||||
|
||||
struct freq_qos_request req[2];
|
||||
u64 cppc_req_cached;
|
||||
|
||||
u32 highest_perf;
|
||||
u32 nominal_perf;
|
||||
u32 lowest_nonlinear_perf;
|
||||
u32 lowest_perf;
|
||||
|
||||
u32 max_freq;
|
||||
u32 min_freq;
|
||||
u32 nominal_freq;
|
||||
u32 lowest_nonlinear_freq;
|
||||
|
||||
struct amd_aperf_mperf cur;
|
||||
struct amd_aperf_mperf prev;
|
||||
|
||||
u64 freq;
|
||||
bool boost_supported;
|
||||
};
|
||||
|
||||
#endif /* _LINUX_AMD_PSTATE_H */
|
@ -1,5 +1,6 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
TARGETS += alsa
|
||||
TARGETS += amd-pstate
|
||||
TARGETS += arm64
|
||||
TARGETS += bpf
|
||||
TARGETS += breakpoints
|
||||
|
9
tools/testing/selftests/amd-pstate/Makefile
Normal file
9
tools/testing/selftests/amd-pstate/Makefile
Normal file
@ -0,0 +1,9 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
# Makefile for amd-pstate/ function selftests
|
||||
|
||||
# No binaries, but make sure arg-less "make" doesn't trigger "run_tests"
|
||||
all:
|
||||
|
||||
TEST_PROGS := amd-pstate-ut.sh
|
||||
|
||||
include ../lib.mk
|
56
tools/testing/selftests/amd-pstate/amd-pstate-ut.sh
Executable file
56
tools/testing/selftests/amd-pstate/amd-pstate-ut.sh
Executable file
@ -0,0 +1,56 @@
|
||||
#!/bin/sh
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
# amd-pstate-ut is a test module for testing the amd-pstate driver.
|
||||
# It can only run on x86 architectures and current cpufreq driver
|
||||
# must be amd-pstate.
|
||||
# (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.
|
||||
|
||||
# Kselftest framework requirement - SKIP code is 4.
|
||||
ksft_skip=4
|
||||
|
||||
# amd-pstate-ut only run on x86/x86_64 AMD systems.
|
||||
ARCH=$(uname -m 2>/dev/null | sed -e 's/i.86/x86/' -e 's/x86_64/x86/')
|
||||
VENDOR=$(cat /proc/cpuinfo | grep -m 1 'vendor_id' | awk '{print $NF}')
|
||||
|
||||
if ! echo "$ARCH" | grep -q x86; then
|
||||
echo "$0 # Skipped: Test can only run on x86 architectures."
|
||||
exit $ksft_skip
|
||||
fi
|
||||
|
||||
if ! echo "$VENDOR" | grep -iq amd; then
|
||||
echo "$0 # Skipped: Test can only run on AMD CPU."
|
||||
echo "$0 # Current cpu vendor is $VENDOR."
|
||||
exit $ksft_skip
|
||||
fi
|
||||
|
||||
scaling_driver=$(cat /sys/devices/system/cpu/cpufreq/policy0/scaling_driver)
|
||||
if [ "$scaling_driver" != "amd-pstate" ]; then
|
||||
echo "$0 # Skipped: Test can only run on amd-pstate driver."
|
||||
echo "$0 # Please set X86_AMD_PSTATE enabled."
|
||||
echo "$0 # Current cpufreq scaling drvier is $scaling_driver."
|
||||
exit $ksft_skip
|
||||
fi
|
||||
|
||||
msg="Skip all tests:"
|
||||
if [ ! -w /dev ]; then
|
||||
echo $msg please run this as root >&2
|
||||
exit $ksft_skip
|
||||
fi
|
||||
|
||||
if ! /sbin/modprobe -q -n amd-pstate-ut; then
|
||||
echo "amd-pstate-ut: module amd-pstate-ut is not found [SKIP]"
|
||||
exit $ksft_skip
|
||||
fi
|
||||
if /sbin/modprobe -q amd-pstate-ut; then
|
||||
/sbin/modprobe -q -r amd-pstate-ut
|
||||
echo "amd-pstate-ut: ok"
|
||||
else
|
||||
echo "amd-pstate-ut: [FAIL]"
|
||||
exit 1
|
||||
fi
|
1
tools/testing/selftests/amd-pstate/config
Normal file
1
tools/testing/selftests/amd-pstate/config
Normal file
@ -0,0 +1 @@
|
||||
CONFIG_X86_AMD_PSTATE_UT=m
|
@ -6,6 +6,6 @@ TEST_PROGS := cpu-on-off-test.sh
|
||||
include ../lib.mk
|
||||
|
||||
run_full_test:
|
||||
@/bin/bash ./cpu-on-off-test.sh -a || echo "cpu-hotplug selftests: [FAIL]"
|
||||
@/bin/bash ./cpu-on-off-test.sh -a && echo "cpu-hotplug selftests: [PASS]" || echo "cpu-hotplug selftests: [FAIL]"
|
||||
|
||||
clean:
|
||||
|
@ -1 +0,0 @@
|
||||
CONFIG_NOTIFIER_ERROR_INJECTION=y
|
@ -4,6 +4,7 @@
|
||||
SYSFS=
|
||||
# Kselftest framework requirement - SKIP code is 4.
|
||||
ksft_skip=4
|
||||
retval=0
|
||||
|
||||
prerequisite()
|
||||
{
|
||||
@ -102,10 +103,10 @@ online_cpu_expect_success()
|
||||
|
||||
if ! online_cpu $cpu; then
|
||||
echo $FUNCNAME $cpu: unexpected fail >&2
|
||||
exit 1
|
||||
retval=1
|
||||
elif ! cpu_is_online $cpu; then
|
||||
echo $FUNCNAME $cpu: unexpected offline >&2
|
||||
exit 1
|
||||
retval=1
|
||||
fi
|
||||
}
|
||||
|
||||
@ -115,10 +116,10 @@ online_cpu_expect_fail()
|
||||
|
||||
if online_cpu $cpu 2> /dev/null; then
|
||||
echo $FUNCNAME $cpu: unexpected success >&2
|
||||
exit 1
|
||||
retval=1
|
||||
elif ! cpu_is_offline $cpu; then
|
||||
echo $FUNCNAME $cpu: unexpected online >&2
|
||||
exit 1
|
||||
retval=1
|
||||
fi
|
||||
}
|
||||
|
||||
@ -128,10 +129,10 @@ offline_cpu_expect_success()
|
||||
|
||||
if ! offline_cpu $cpu; then
|
||||
echo $FUNCNAME $cpu: unexpected fail >&2
|
||||
exit 1
|
||||
retval=1
|
||||
elif ! cpu_is_offline $cpu; then
|
||||
echo $FUNCNAME $cpu: unexpected offline >&2
|
||||
exit 1
|
||||
retval=1
|
||||
fi
|
||||
}
|
||||
|
||||
@ -141,16 +142,33 @@ offline_cpu_expect_fail()
|
||||
|
||||
if offline_cpu $cpu 2> /dev/null; then
|
||||
echo $FUNCNAME $cpu: unexpected success >&2
|
||||
exit 1
|
||||
retval=1
|
||||
elif ! cpu_is_online $cpu; then
|
||||
echo $FUNCNAME $cpu: unexpected offline >&2
|
||||
exit 1
|
||||
retval=1
|
||||
fi
|
||||
}
|
||||
|
||||
error=-12
|
||||
online_all_hot_pluggable_cpus()
|
||||
{
|
||||
for cpu in `hotplaggable_offline_cpus`; do
|
||||
online_cpu_expect_success $cpu
|
||||
done
|
||||
}
|
||||
|
||||
offline_all_hot_pluggable_cpus()
|
||||
{
|
||||
local reserve_cpu=$online_max
|
||||
for cpu in `hotpluggable_online_cpus`; do
|
||||
# Reserve one cpu oneline at least.
|
||||
if [ $cpu -eq $reserve_cpu ];then
|
||||
continue
|
||||
fi
|
||||
offline_cpu_expect_success $cpu
|
||||
done
|
||||
}
|
||||
|
||||
allcpus=0
|
||||
priority=0
|
||||
online_cpus=0
|
||||
online_max=0
|
||||
offline_cpus=0
|
||||
@ -158,31 +176,20 @@ offline_max=0
|
||||
present_cpus=0
|
||||
present_max=0
|
||||
|
||||
while getopts e:ahp: opt; do
|
||||
while getopts ah opt; do
|
||||
case $opt in
|
||||
e)
|
||||
error=$OPTARG
|
||||
;;
|
||||
a)
|
||||
allcpus=1
|
||||
;;
|
||||
h)
|
||||
echo "Usage $0 [ -a ] [ -e errno ] [ -p notifier-priority ]"
|
||||
echo "Usage $0 [ -a ]"
|
||||
echo -e "\t default offline one cpu"
|
||||
echo -e "\t run with -a option to offline all cpus"
|
||||
exit
|
||||
;;
|
||||
p)
|
||||
priority=$OPTARG
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
if ! [ "$error" -ge -4095 -a "$error" -lt 0 ]; then
|
||||
echo "error code must be -4095 <= errno < 0" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
prerequisite
|
||||
|
||||
#
|
||||
@ -196,12 +203,12 @@ if [ $allcpus -eq 0 ]; then
|
||||
online_cpu_expect_success $online_max
|
||||
|
||||
if [[ $offline_cpus -gt 0 ]]; then
|
||||
echo -e "\t offline to online to offline: cpu $present_max"
|
||||
echo -e "\t online to offline to online: cpu $present_max"
|
||||
online_cpu_expect_success $present_max
|
||||
offline_cpu_expect_success $present_max
|
||||
online_cpu $present_max
|
||||
fi
|
||||
exit 0
|
||||
exit $retval
|
||||
else
|
||||
echo "Full scope test: all hotplug cpus"
|
||||
echo -e "\t online all offline cpus"
|
||||
@ -209,85 +216,10 @@ else
|
||||
echo -e "\t online all offline cpus"
|
||||
fi
|
||||
|
||||
#
|
||||
# Online all hot-pluggable CPUs
|
||||
#
|
||||
for cpu in `hotplaggable_offline_cpus`; do
|
||||
online_cpu_expect_success $cpu
|
||||
done
|
||||
online_all_hot_pluggable_cpus
|
||||
|
||||
#
|
||||
# Offline all hot-pluggable CPUs
|
||||
#
|
||||
for cpu in `hotpluggable_online_cpus`; do
|
||||
offline_cpu_expect_success $cpu
|
||||
done
|
||||
offline_all_hot_pluggable_cpus
|
||||
|
||||
#
|
||||
# Online all hot-pluggable CPUs again
|
||||
#
|
||||
for cpu in `hotplaggable_offline_cpus`; do
|
||||
online_cpu_expect_success $cpu
|
||||
done
|
||||
online_all_hot_pluggable_cpus
|
||||
|
||||
#
|
||||
# Test with cpu notifier error injection
|
||||
#
|
||||
|
||||
DEBUGFS=`mount -t debugfs | head -1 | awk '{ print $3 }'`
|
||||
NOTIFIER_ERR_INJECT_DIR=$DEBUGFS/notifier-error-inject/cpu
|
||||
|
||||
prerequisite_extra()
|
||||
{
|
||||
msg="skip extra tests:"
|
||||
|
||||
/sbin/modprobe -q -r cpu-notifier-error-inject
|
||||
/sbin/modprobe -q cpu-notifier-error-inject priority=$priority
|
||||
|
||||
if [ ! -d "$DEBUGFS" ]; then
|
||||
echo $msg debugfs is not mounted >&2
|
||||
exit $ksft_skip
|
||||
fi
|
||||
|
||||
if [ ! -d $NOTIFIER_ERR_INJECT_DIR ]; then
|
||||
echo $msg cpu-notifier-error-inject module is not available >&2
|
||||
exit $ksft_skip
|
||||
fi
|
||||
}
|
||||
|
||||
prerequisite_extra
|
||||
|
||||
#
|
||||
# Offline all hot-pluggable CPUs
|
||||
#
|
||||
echo 0 > $NOTIFIER_ERR_INJECT_DIR/actions/CPU_DOWN_PREPARE/error
|
||||
for cpu in `hotpluggable_online_cpus`; do
|
||||
offline_cpu_expect_success $cpu
|
||||
done
|
||||
|
||||
#
|
||||
# Test CPU hot-add error handling (offline => online)
|
||||
#
|
||||
echo $error > $NOTIFIER_ERR_INJECT_DIR/actions/CPU_UP_PREPARE/error
|
||||
for cpu in `hotplaggable_offline_cpus`; do
|
||||
online_cpu_expect_fail $cpu
|
||||
done
|
||||
|
||||
#
|
||||
# Online all hot-pluggable CPUs
|
||||
#
|
||||
echo 0 > $NOTIFIER_ERR_INJECT_DIR/actions/CPU_UP_PREPARE/error
|
||||
for cpu in `hotplaggable_offline_cpus`; do
|
||||
online_cpu_expect_success $cpu
|
||||
done
|
||||
|
||||
#
|
||||
# Test CPU hot-remove error handling (online => offline)
|
||||
#
|
||||
echo $error > $NOTIFIER_ERR_INJECT_DIR/actions/CPU_DOWN_PREPARE/error
|
||||
for cpu in `hotpluggable_online_cpus`; do
|
||||
offline_cpu_expect_fail $cpu
|
||||
done
|
||||
|
||||
echo 0 > $NOTIFIER_ERR_INJECT_DIR/actions/CPU_DOWN_PREPARE/error
|
||||
/sbin/modprobe -q -r cpu-notifier-error-inject
|
||||
exit $retval
|
||||
|
@ -25,7 +25,7 @@ MACHINE ?= $(shell echo $(uname_M) | sed -e 's/aarch64.*/arm64/' -e 's/ppc64.*/p
|
||||
# LDLIBS.
|
||||
MAKEFLAGS += --no-builtin-rules
|
||||
|
||||
CFLAGS = -Wall -I ../../../../usr/include $(EXTRA_CFLAGS) $(KHDR_INCLUDES)
|
||||
CFLAGS = -Wall -I $(top_srcdir) -I $(top_srcdir)/usr/include $(EXTRA_CFLAGS) $(KHDR_INCLUDES)
|
||||
LDLIBS = -lrt -lpthread
|
||||
TEST_GEN_FILES = compaction_test
|
||||
TEST_GEN_FILES += gup_test
|
||||
|
@ -10,7 +10,7 @@
|
||||
#include <sys/types.h>
|
||||
#include <pthread.h>
|
||||
#include <assert.h>
|
||||
#include "../../../../mm/gup_test.h"
|
||||
#include <mm/gup_test.h>
|
||||
#include "../kselftest.h"
|
||||
|
||||
#include "util.h"
|
||||
|
@ -35,8 +35,8 @@
|
||||
* This is a private UAPI to the kernel test module so it isn't exported
|
||||
* in the usual include/uapi/... directory.
|
||||
*/
|
||||
#include "../../../../lib/test_hmm_uapi.h"
|
||||
#include "../../../../mm/gup_test.h"
|
||||
#include <lib/test_hmm_uapi.h>
|
||||
#include <mm/gup_test.h>
|
||||
|
||||
struct hmm_buffer {
|
||||
void *ptr;
|
||||
|
@ -11,7 +11,7 @@
|
||||
#include <err.h>
|
||||
|
||||
#include "../kselftest.h"
|
||||
#include "../../../../include/vdso/time64.h"
|
||||
#include <include/vdso/time64.h>
|
||||
#include "util.h"
|
||||
|
||||
#define KSM_SYSFS_PATH "/sys/kernel/mm/ksm/"
|
||||
|
Loading…
Reference in New Issue
Block a user