From patchwork Wed Oct 5 19:32:06 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Shuah Khan X-Patchwork-Id: 613460 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 6A351C433F5 for ; Wed, 5 Oct 2022 19:32:19 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231346AbiJETcN (ORCPT ); Wed, 5 Oct 2022 15:32:13 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:56958 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231267AbiJETcL (ORCPT ); Wed, 5 Oct 2022 15:32:11 -0400 Received: from mail-io1-xd2b.google.com (mail-io1-xd2b.google.com [IPv6:2607:f8b0:4864:20::d2b]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 234067A747 for ; Wed, 5 Oct 2022 12:32:08 -0700 (PDT) Received: by mail-io1-xd2b.google.com with SMTP id o65so3524766iof.4 for ; Wed, 05 Oct 2022 12:32:08 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linuxfoundation.org; s=google; h=subject:from:cc:to:content-language:user-agent:mime-version:date :message-id:from:to:cc:subject:date; bh=LO+gWsiru6yKf06QGcQDqIJ2vDmcUSA8pUjzEEhhmuI=; b=KIR5eRkVtHniCNNY2UEH21/W62OoKQL4TWxtpLkx+Ndp68xmI7F/crqLwP25l8F6aN 0YDADvj5hEbdcOKOIGi7NCVeRp11dnZ3UTdA8mHE0SBQyPeouaryJ5LTPGAavlvbJGk5 Vi8zEg0uzNeJjcjmRqaN0pcGRyBTu/NJNCQXs= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=subject:from:cc:to:content-language:user-agent:mime-version:date :message-id:x-gm-message-state:from:to:cc:subject:date; bh=LO+gWsiru6yKf06QGcQDqIJ2vDmcUSA8pUjzEEhhmuI=; b=u5oSGmqKzWQbPoNXijOV3mNSl4qrUB1bM2eFLmnykOqMHfkLEs6Dk9PfD2NER4P3jN IVASXy/HQOb3G9opUzjH3ANkMIGc2mEZ3aGT1Oy4qEGAy1Tn1JWKqtMswtKj/ssFPx6h usFJFSjOTCd59J8rcOW3xue/VVBBJkHNByp+Elew4bgWq83ZaR6XQhiAIODUaXEqlfdr vq/9KcskTTxKThIAZhU7NiUKPijAdG6PLeoysZn87APXaUmET6yGSF8Xju6sUXlo/Psp tO7nRDQNv0Qgj7BdE+oNK44dGNYcKs2t/FcDGu+a+XOcCtCRm60WFp0yOjuoNyoc1D8X Plgg== X-Gm-Message-State: ACrzQf2G2LsDbepxMOfzrYIH/J8wSp10WLl0OHBNL6SZXTAwpEFnQ2qS BuonuTe0644auhCv2Bbq6aRiew== X-Google-Smtp-Source: AMsMyM52oUl3/Vl9PiehGv16P+1s+IwohB76k7E4woDi/vmd6IpTXC7O9FFUFIz0k8BjhHBTePKYPw== X-Received: by 2002:a5e:9911:0:b0:6b9:c02b:3746 with SMTP id t17-20020a5e9911000000b006b9c02b3746mr598936ioj.127.1664998327909; Wed, 05 Oct 2022 12:32:07 -0700 (PDT) Received: from [192.168.1.128] ([38.15.45.1]) by smtp.gmail.com with ESMTPSA id z26-20020a056602081a00b006b8321d618bsm962614iow.17.2022.10.05.12.32.07 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Wed, 05 Oct 2022 12:32:07 -0700 (PDT) Message-ID: Date: Wed, 5 Oct 2022 13:32:06 -0600 MIME-Version: 1.0 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:91.0) Gecko/20100101 Thunderbird/91.11.0 Content-Language: en-US To: Linus Torvalds Cc: Shuah Khan , "Rafael J. Wysocki" , Stephen Rothwell , Andrew Morton , linux-kselftest@vger.kernel.org, linux-kernel@vger.kernel.org, Viresh Kumar From: Shuah Khan Subject: [GIT PULL] Kselftest update for Linux 6.1-rc1 Precedence: bulk List-ID: X-Mailing-List: linux-kselftest@vger.kernel.org Hi Linus, Please pull the following Kselftest update for Linux 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 Please note that this update touches drivers/cpufreq to add a new test module, a new header file to include/linux. There are two conflicts with pm and mm trees: Stephen fixed these up in linux-next. 1. A conflict in: tools/testing/selftests/vm/hmm-tests.c between commit: ab7039dbcc61 ("selftests/vm: use top_srcdir instead of recomputing relative paths") from the kselftest tree and commit: 223e3150a0d8 ("hmm-tests: fix migrate_dirty_page test") from the mm tree. 2. A conflict in: drivers/cpufreq/amd-pstate.c between commit: d8bee41db83e ("cpufreq: amd-pstate: fix white-space") from the pm tree and commit: 8c766b24ee62 ("cpufreq: amd-pstate: Expose struct amd_cpudata") from the kselftest tree. diff for this pull request is attached thanks, -- Shuah ---------------------------------------------------------------- The following changes since commit 568035b01cfb107af8d2e4bd2fb9aea22cf5b868: Linux 6.0-rc1 (2022-08-14 15:50:18 -0700) are available in the Git repository at: git://git.kernel.org/pub/scm/linux/kernel/git/shuah/linux-kselftest tags/linux-kselftest-next-6.1-rc1 for you to fetch changes up to 83e14a57d59f22a89ad7d59752f5b69189299531: docs:kselftest: fix kselftest_module.h path of example module (2022-10-05 11:05:18 -0600) ---------------------------------------------------------------- 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 ---------------------------------------------------------------- Axel Rasmussen (1): selftests/vm: use top_srcdir instead of recomputing relative paths Hoi Pok Wu (1): docs:kselftest: fix kselftest_module.h path of example module Meng Li (6): cpufreq: amd-pstate: Expose struct amd_cpudata cpufreq: amd-pstate: Add test module for amd-pstate driver selftests: amd-pstate: Add test trigger for amd-pstate driver Documentation: amd-pstate: Add unit test introduction cpufreq: amd-pstate: modify type in argument 2 for filp_open cpufreq: amd-pstate: Add explanation for X86_AMD_PSTATE_UT Zhao Gongyi (5): selftests/cpu-hotplug: Correct log info selftests/cpu-hotplug: Use return instead of exit selftests/cpu-hotplug: Delete fault injection related code selftests/cpu-hotplug: Reserve one cpu online at least selftests/cpu-hotplug: Add log info when test success Documentation/admin-guide/pm/amd-pstate.rst | 76 ++++++ Documentation/dev-tools/kselftest.rst | 2 +- MAINTAINERS | 1 + drivers/cpufreq/Kconfig.x86 | 15 ++ drivers/cpufreq/Makefile | 1 + drivers/cpufreq/amd-pstate-ut.c | 293 +++++++++++++++++++++ drivers/cpufreq/amd-pstate.c | 60 +---- include/linux/amd-pstate.h | 77 ++++++ tools/testing/selftests/Makefile | 1 + tools/testing/selftests/amd-pstate/Makefile | 9 + .../testing/selftests/amd-pstate/amd-pstate-ut.sh | 56 ++++ tools/testing/selftests/amd-pstate/config | 1 + tools/testing/selftests/cpu-hotplug/Makefile | 2 +- tools/testing/selftests/cpu-hotplug/config | 1 - .../selftests/cpu-hotplug/cpu-on-off-test.sh | 140 +++------- tools/testing/selftests/vm/Makefile | 2 +- tools/testing/selftests/vm/gup_test.c | 2 +- tools/testing/selftests/vm/hmm-tests.c | 4 +- tools/testing/selftests/vm/ksm_tests.c | 2 +- 19 files changed, 574 insertions(+), 171 deletions(-) create mode 100644 drivers/cpufreq/amd-pstate-ut.c create mode 100644 include/linux/amd-pstate.h create mode 100644 tools/testing/selftests/amd-pstate/Makefile create mode 100755 tools/testing/selftests/amd-pstate/amd-pstate-ut.sh create mode 100644 tools/testing/selftests/amd-pstate/config delete mode 100644 tools/testing/selftests/cpu-hotplug/config ---------------------------------------------------------------- diff --git a/Documentation/admin-guide/pm/amd-pstate.rst b/Documentation/admin-guide/pm/amd-pstate.rst index 83b58eb4ab4d..8f3d30c5a0d8 100644 --- a/Documentation/admin-guide/pm/amd-pstate.rst +++ b/Documentation/admin-guide/pm/amd-pstate.rst @@ -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 `_. | + +---------+--------------------------------+------------------------------------------------------------------------------------+ + | 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 diff --git a/Documentation/dev-tools/kselftest.rst b/Documentation/dev-tools/kselftest.rst index e87973763b91..12b575b76b20 100644 --- a/Documentation/dev-tools/kselftest.rst +++ b/Documentation/dev-tools/kselftest.rst @@ -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(); diff --git a/MAINTAINERS b/MAINTAINERS index 8a5012ba6ff9..5c404d2686d1 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1045,6 +1045,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 diff --git a/drivers/cpufreq/Kconfig.x86 b/drivers/cpufreq/Kconfig.x86 index 55516043b656..310779b07daf 100644 --- a/drivers/cpufreq/Kconfig.x86 +++ b/drivers/cpufreq/Kconfig.x86 @@ -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 diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile index 285de70af877..49b98c62c5af 100644 --- a/drivers/cpufreq/Makefile +++ b/drivers/cpufreq/Makefile @@ -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 diff --git a/drivers/cpufreq/amd-pstate-ut.c b/drivers/cpufreq/amd-pstate-ut.c new file mode 100644 index 000000000000..e4a5b4d90f83 --- /dev/null +++ b/drivers/cpufreq/amd-pstate-ut.c @@ -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 + * + * 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 +#include +#include +#include +#include + +#include + +/* + * 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 "); +MODULE_DESCRIPTION("AMD P-state driver Test module"); +MODULE_LICENSE("GPL"); diff --git a/drivers/cpufreq/amd-pstate.c b/drivers/cpufreq/amd-pstate.c index 9ac75c1cde9c..218f777a5915 100644 --- a/drivers/cpufreq/amd-pstate.c +++ b/drivers/cpufreq/amd-pstate.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include @@ -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); diff --git a/include/linux/amd-pstate.h b/include/linux/amd-pstate.h new file mode 100644 index 000000000000..1c4b8659f171 --- /dev/null +++ b/include/linux/amd-pstate.h @@ -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 + */ + +#ifndef _LINUX_AMD_PSTATE_H +#define _LINUX_AMD_PSTATE_H + +#include + +/********************************************************************* + * 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 */ diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile index 10b34bb03bc1..02b4f3477eae 100644 --- a/tools/testing/selftests/Makefile +++ b/tools/testing/selftests/Makefile @@ -1,5 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 TARGETS += alsa +TARGETS += amd-pstate TARGETS += arm64 TARGETS += bpf TARGETS += breakpoints diff --git a/tools/testing/selftests/amd-pstate/Makefile b/tools/testing/selftests/amd-pstate/Makefile new file mode 100644 index 000000000000..199867f44b32 --- /dev/null +++ b/tools/testing/selftests/amd-pstate/Makefile @@ -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 diff --git a/tools/testing/selftests/amd-pstate/amd-pstate-ut.sh b/tools/testing/selftests/amd-pstate/amd-pstate-ut.sh new file mode 100755 index 000000000000..f8e82d91ffcf --- /dev/null +++ b/tools/testing/selftests/amd-pstate/amd-pstate-ut.sh @@ -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 diff --git a/tools/testing/selftests/amd-pstate/config b/tools/testing/selftests/amd-pstate/config new file mode 100644 index 000000000000..f43103c9adc4 --- /dev/null +++ b/tools/testing/selftests/amd-pstate/config @@ -0,0 +1 @@ +CONFIG_X86_AMD_PSTATE_UT=m diff --git a/tools/testing/selftests/cpu-hotplug/Makefile b/tools/testing/selftests/cpu-hotplug/Makefile index d8be047ee5b6..8b66c4738344 100644 --- a/tools/testing/selftests/cpu-hotplug/Makefile +++ b/tools/testing/selftests/cpu-hotplug/Makefile @@ -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: diff --git a/tools/testing/selftests/cpu-hotplug/config b/tools/testing/selftests/cpu-hotplug/config deleted file mode 100644 index d4aca2ad5069..000000000000 --- a/tools/testing/selftests/cpu-hotplug/config +++ /dev/null @@ -1 +0,0 @@ -CONFIG_NOTIFIER_ERROR_INJECTION=y diff --git a/tools/testing/selftests/cpu-hotplug/cpu-on-off-test.sh b/tools/testing/selftests/cpu-hotplug/cpu-on-off-test.sh index 0d26b5e3f966..d5dc7e0dc726 100755 --- a/tools/testing/selftests/cpu-hotplug/cpu-on-off-test.sh +++ b/tools/testing/selftests/cpu-hotplug/cpu-on-off-test.sh @@ -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 - -# -# Offline all hot-pluggable CPUs -# -for cpu in `hotpluggable_online_cpus`; do - offline_cpu_expect_success $cpu -done - -# -# Online all hot-pluggable CPUs again -# -for cpu in `hotplaggable_offline_cpus`; do - online_cpu_expect_success $cpu -done - -# -# Test with cpu notifier error injection -# +online_all_hot_pluggable_cpus -DEBUGFS=`mount -t debugfs | head -1 | awk '{ print $3 }'` -NOTIFIER_ERR_INJECT_DIR=$DEBUGFS/notifier-error-inject/cpu +offline_all_hot_pluggable_cpus -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 +online_all_hot_pluggable_cpus -echo 0 > $NOTIFIER_ERR_INJECT_DIR/actions/CPU_DOWN_PREPARE/error -/sbin/modprobe -q -r cpu-notifier-error-inject +exit $retval diff --git a/tools/testing/selftests/vm/Makefile b/tools/testing/selftests/vm/Makefile index d9fa6a9ea584..d516b8c38eed 100644 --- a/tools/testing/selftests/vm/Makefile +++ b/tools/testing/selftests/vm/Makefile @@ -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 diff --git a/tools/testing/selftests/vm/gup_test.c b/tools/testing/selftests/vm/gup_test.c index a309876d832f..e43879291dac 100644 --- a/tools/testing/selftests/vm/gup_test.c +++ b/tools/testing/selftests/vm/gup_test.c @@ -10,7 +10,7 @@ #include #include #include -#include "../../../../mm/gup_test.h" +#include #include "../kselftest.h" #include "util.h" diff --git a/tools/testing/selftests/vm/hmm-tests.c b/tools/testing/selftests/vm/hmm-tests.c index 529f53b40296..98b949c279be 100644 --- a/tools/testing/selftests/vm/hmm-tests.c +++ b/tools/testing/selftests/vm/hmm-tests.c @@ -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 +#include struct hmm_buffer { void *ptr; diff --git a/tools/testing/selftests/vm/ksm_tests.c b/tools/testing/selftests/vm/ksm_tests.c index f5e4e0bbd081..0d85be2350fa 100644 --- a/tools/testing/selftests/vm/ksm_tests.c +++ b/tools/testing/selftests/vm/ksm_tests.c @@ -11,7 +11,7 @@ #include #include "../kselftest.h" -#include "../../../../include/vdso/time64.h" +#include #include "util.h" #define KSM_SYSFS_PATH "/sys/kernel/mm/ksm/"