diff options
author | Jan200101 <sentrycraft123@gmail.com> | 2021-11-28 15:40:28 +0100 |
---|---|---|
committer | Jan200101 <sentrycraft123@gmail.com> | 2021-11-28 15:42:17 +0100 |
commit | d39788f1fe96e14f04e5e7f9a223427a32cddf1a (patch) | |
tree | d548fce3cd24e6a68a25d6f41b6b2c6d2e23eb50 /SOURCES/AMD_CPPC.patch | |
parent | 603d921759e256c1fd9824078eab66907e7b2ad5 (diff) | |
download | kernel-fsync-d39788f1fe96e14f04e5e7f9a223427a32cddf1a.tar.gz kernel-fsync-d39788f1fe96e14f04e5e7f9a223427a32cddf1a.zip |
kernel 5.15.4
Diffstat (limited to 'SOURCES/AMD_CPPC.patch')
-rw-r--r-- | SOURCES/AMD_CPPC.patch | 2088 |
1 files changed, 1142 insertions, 946 deletions
diff --git a/SOURCES/AMD_CPPC.patch b/SOURCES/AMD_CPPC.patch index 97cfa77..fe4c48f 100644 --- a/SOURCES/AMD_CPPC.patch +++ b/SOURCES/AMD_CPPC.patch @@ -1,35 +1,32 @@ -From 674082f34ac8bfab164a630a275eac291e1bd7be Mon Sep 17 00:00:00 2001 -From: Huang Rui <ray.huang@amd.com> -Date: Thu, 28 Jan 2021 10:50:26 +0800 -Subject: x86/cpufreatures: add AMD CPPC extension feature flag +Add Collaborative Processor Performance Control feature flag for AMD +processors. -Add Collaborative Processor Performance Control Extension feature flag -for AMD processors. +This feature flag will be used on the following amd-pstate driver. The +amd-pstate driver has two approaches to implement the frequency control +behavior. That depends on the CPU hardware implementation. One is "Full +MSR Support" and another is "Shared Memory Support". The feature flag +indicates the current processors with "Full MSR Support". +Acked-by: Borislav Petkov <bp@suse.de> Signed-off-by: Huang Rui <ray.huang@amd.com> --- arch/x86/include/asm/cpufeatures.h | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/x86/include/asm/cpufeatures.h b/arch/x86/include/asm/cpufeatures.h -index d0ce5cfd3ac14..f7aea50e33711 100644 +index d5b5f2ab87a0..18de5f76f198 100644 --- a/arch/x86/include/asm/cpufeatures.h +++ b/arch/x86/include/asm/cpufeatures.h -@@ -313,6 +313,7 @@ +@@ -315,6 +315,7 @@ #define X86_FEATURE_AMD_SSBD (13*32+24) /* "" Speculative Store Bypass Disable */ #define X86_FEATURE_VIRT_SSBD (13*32+25) /* Virtualized Speculative Store Bypass Disable */ #define X86_FEATURE_AMD_SSB_NO (13*32+26) /* "" Speculative Store Bypass is fixed in hardware. */ -+#define X86_FEATURE_AMD_CPPC_EXT (13*32+27) /* Collaborative Processor Performance Control Extension */ - ++#define X86_FEATURE_CPPC (13*32+27) /* Collaborative Processor Performance Control */ + /* Thermal and Power Management Leaf, CPUID level 0x00000006 (EAX), word 14 */ #define X86_FEATURE_DTHERM (14*32+ 0) /* Digital Thermal Sensor */ --- -cgit 1.2.3-1.el7 -From 8180f01cf18d8ba79dac94a817294e85a8d84dc4 Mon Sep 17 00:00:00 2001 -From: Huang Rui <ray.huang@amd.com> -Date: Mon, 25 Jan 2021 15:50:24 +0800 -Subject: x86/msr: add AMD CPPC MSR definitions + AMD CPPC (Collaborative Processor Performance Control) function uses MSR registers to manage the performance hints. So add the MSR register macro @@ -41,13 +38,13 @@ Signed-off-by: Huang Rui <ray.huang@amd.com> 1 file changed, 17 insertions(+) diff --git a/arch/x86/include/asm/msr-index.h b/arch/x86/include/asm/msr-index.h -index a7c413432b33d..ce42e15cf3034 100644 +index 01e2650b9585..e7945ef6a8df 100644 --- a/arch/x86/include/asm/msr-index.h +++ b/arch/x86/include/asm/msr-index.h @@ -486,6 +486,23 @@ - + #define MSR_AMD64_VIRT_SPEC_CTRL 0xc001011f - + +/* AMD Collaborative Processor Performance Control MSRs */ +#define MSR_AMD_CPPC_CAP1 0xc00102b0 +#define MSR_AMD_CPPC_ENABLE 0xc00102b1 @@ -67,50 +64,186 @@ index a7c413432b33d..ce42e15cf3034 100644 + /* Fam 17h MSRs */ #define MSR_F17H_IRPERF 0xc00000e9 + + + + +From: Steven Noonan <steven@valvesoftware.com> + +According to the ACPI v6.2 (and later) specification, SystemIO can be +used for _CPC registers. This teaches cppc_acpi how to handle such +registers. + +This patch was tested using the amd_pstate driver on my Zephyrus G15 +(model GA503QS) using the current version 410 BIOS, which uses +a SystemIO register for the HighestPerformance element in _CPC. + +Signed-off-by: Steven Noonan <steven@valvesoftware.com> +Signed-off-by: Huang Rui <ray.huang@amd.com> +--- + drivers/acpi/cppc_acpi.c | 46 +++++++++++++++++++++++++++++++++++++--- + 1 file changed, 43 insertions(+), 3 deletions(-) + +diff --git a/drivers/acpi/cppc_acpi.c b/drivers/acpi/cppc_acpi.c +index a85c351589be..ca62c3dc9899 100644 +--- a/drivers/acpi/cppc_acpi.c ++++ b/drivers/acpi/cppc_acpi.c +@@ -746,9 +746,24 @@ int acpi_cppc_processor_probe(struct acpi_processor *pr) + goto out_free; + cpc_ptr->cpc_regs[i-2].sys_mem_vaddr = addr; + } ++ } else if (gas_t->space_id == ACPI_ADR_SPACE_SYSTEM_IO) { ++ if (gas_t->access_width < 1 || gas_t->access_width > 3) { ++ /* 1 = 8-bit, 2 = 16-bit, and 3 = 32-bit. SystemIO doesn't ++ * implement 64-bit registers. ++ */ ++ pr_debug("Invalid access width %d for SystemIO register\n", ++ gas_t->access_width); ++ goto out_free; ++ } ++ if (gas_t->address & ~0xFFFFULL) { ++ /* SystemIO registers use 16-bit integer addresses */ ++ pr_debug("Invalid IO port %llu for SystemIO register\n", ++ gas_t->address); ++ goto out_free; ++ } + } else { + if (gas_t->space_id != ACPI_ADR_SPACE_FIXED_HARDWARE || !cpc_ffh_supported()) { +- /* Support only PCC ,SYS MEM and FFH type regs */ ++ /* Support only PCC, SystemMemory, SystemIO, and FFH type regs. */ + pr_debug("Unsupported register type: %d\n", gas_t->space_id); + goto out_free; + } +@@ -923,7 +938,20 @@ static int cpc_read(int cpu, struct cpc_register_resource *reg_res, u64 *val) + } + + *val = 0; +- if (reg->space_id == ACPI_ADR_SPACE_PLATFORM_COMM && pcc_ss_id >= 0) ++ ++ if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_IO) { ++ u32 width = 8 << (reg->access_width - 1); ++ acpi_status status; ++ ++ status = acpi_os_read_port((acpi_io_address)reg->address, (u32 *)val, width); ++ ++ if (status != AE_OK) { ++ pr_debug("Error: Failed to read SystemIO port %llx\n", reg->address); ++ return -EFAULT; ++ } ++ ++ return 0; ++ } else if (reg->space_id == ACPI_ADR_SPACE_PLATFORM_COMM && pcc_ss_id >= 0) + vaddr = GET_PCC_VADDR(reg->address, pcc_ss_id); + else if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) + vaddr = reg_res->sys_mem_vaddr; +@@ -962,7 +990,19 @@ static int cpc_write(int cpu, struct cpc_register_resource *reg_res, u64 val) + int pcc_ss_id = per_cpu(cpu_pcc_subspace_idx, cpu); + struct cpc_reg *reg = ®_res->cpc_entry.reg; + +- if (reg->space_id == ACPI_ADR_SPACE_PLATFORM_COMM && pcc_ss_id >= 0) ++ if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_IO) { ++ u32 width = 8 << (reg->access_width - 1); ++ acpi_status status; ++ ++ status = acpi_os_write_port((acpi_io_address)reg->address, (u32)val, width); ++ ++ if (status != AE_OK) { ++ pr_debug("Error: Failed to write SystemIO port %llx\n", reg->address); ++ return -EFAULT; ++ } ++ ++ return 0; ++ } else if (reg->space_id == ACPI_ADR_SPACE_PLATFORM_COMM && pcc_ss_id >= 0) + vaddr = GET_PCC_VADDR(reg->address, pcc_ss_id); + else if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) + vaddr = reg_res->sys_mem_vaddr; + + + +From: Mario Limonciello <mario.limonciello@amd.com> + +As this is a static check, it should be based upon what is currently +present on the system. This makes probeing more deterministic. + +While local APIC flags field (lapic_flags) of cpu core in MADT table is +0, then the cpu core won't be enabled. In this case, _CPC won't be found +in this core, and return back to _CPC invalid with walking through +possible cpus (include disable cpus). This is not expected, so switch to +check present CPUs instead. + +Reported-by: Jinzhou Su <Jinzhou.Su@amd.com> +Signed-off-by: Mario Limonciello <mario.limonciello@amd.com> +Signed-off-by: Huang Rui <ray.huang@amd.com> +--- + drivers/acpi/cppc_acpi.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/acpi/cppc_acpi.c b/drivers/acpi/cppc_acpi.c +index ca62c3dc9899..a46f227dc254 100644 +--- a/drivers/acpi/cppc_acpi.c ++++ b/drivers/acpi/cppc_acpi.c +@@ -411,7 +411,7 @@ bool acpi_cpc_valid(void) + struct cpc_desc *cpc_ptr; + int cpu; + +- for_each_possible_cpu(cpu) { ++ for_each_present_cpu(cpu) { + cpc_ptr = per_cpu(cpc_desc_ptr, cpu); + if (!cpc_ptr) + return false; + --- -cgit 1.2.3-1.el7 -From 8dc33d1590f80a60f12325e7c646a8551a41adf1 Mon Sep 17 00:00:00 2001 From: Jinzhou Su <Jinzhou.Su@amd.com> -Date: Mon, 9 Aug 2021 19:04:17 +0800 -Subject: ACPI: CPPC: add cppc enable register function -Export the cppc enable register function for future use. +Add a new function to enable CPPC feature. This function +will write Continuous Performance Control package +EnableRegister field on the processor. + +CPPC EnableRegister register described in section 8.4.7.1 of ACPI 6.4: +This element is optional. If supported, contains a resource descriptor +with a single Register() descriptor that describes a register to which +OSPM writes a One to enable CPPC on this processor. Before this register +is set, the processor will be controlled by legacy mechanisms (ACPI +Pstates, firmware, etc.). + +This register will be used for AMD processors to enable amd-pstate +function instead of legacy ACPI P-States. Signed-off-by: Jinzhou Su <Jinzhou.Su@amd.com> Signed-off-by: Huang Rui <ray.huang@amd.com> --- - drivers/acpi/cppc_acpi.c | 42 ++++++++++++++++++++++++++++++++++++++++++ + drivers/acpi/cppc_acpi.c | 45 ++++++++++++++++++++++++++++++++++++++++ include/acpi/cppc_acpi.h | 5 +++++ - 2 files changed, 47 insertions(+) + 2 files changed, 50 insertions(+) diff --git a/drivers/acpi/cppc_acpi.c b/drivers/acpi/cppc_acpi.c -index a4d4eebba1da4..de4b30545215f 100644 +index a46f227dc254..003df9fba122 100644 --- a/drivers/acpi/cppc_acpi.c +++ b/drivers/acpi/cppc_acpi.c -@@ -1220,6 +1220,48 @@ out_err: +@@ -1262,6 +1262,51 @@ int cppc_get_perf_ctrs(int cpunum, struct cppc_perf_fb_ctrs *perf_fb_ctrs) } EXPORT_SYMBOL_GPL(cppc_get_perf_ctrs); - + +/** -+ * cppc_set_enable - Set to enable CPPC register. ++ * cppc_set_enable - Set to enable CPPC on the processor by writing the ++ * Continuous Performance Control package EnableRegister field. + * @cpu: CPU for which to enable CPPC register. -+ * @enable: enable field to write into share memory. ++ * @enable: 0 - disable, 1 - enable CPPC feature on the processor. + * -+ * Return: 0 for success, -ERRNO otherwise. ++ * Return: 0 for success, -ERRNO or -EIO otherwise. + */ -+int cppc_set_enable(int cpu, u32 enable) ++int cppc_set_enable(int cpu, bool enable) +{ + int pcc_ss_id = per_cpu(cpu_pcc_subspace_idx, cpu); + struct cpc_register_resource *enable_reg; + struct cpc_desc *cpc_desc = per_cpu(cpc_desc_ptr, cpu); + struct cppc_pcc_data *pcc_ss_data = NULL; -+ int ret = -1; ++ int ret = -EINVAL; + + if (!cpc_desc) { + pr_debug("No CPC descriptor for CPU:%d\n", cpu); -+ return -ENODEV; ++ return -EINVAL; + } + + enable_reg = &cpc_desc->cpc_regs[ENABLE]; @@ -127,11 +260,13 @@ index a4d4eebba1da4..de4b30545215f 100644 + pcc_ss_data = pcc_data[pcc_ss_id]; + + down_write(&pcc_ss_data->pcc_lock); -+ send_pcc_cmd(pcc_ss_id, CMD_WRITE); ++ /* after writing CPC, transfer the ownership of PCC to platfrom */ ++ ret = send_pcc_cmd(pcc_ss_id, CMD_WRITE); + up_write(&pcc_ss_data->pcc_lock); ++ return ret; + } + -+ return ret; ++ return cpc_write(cpu, enable_reg, enable); +} +EXPORT_SYMBOL_GPL(cppc_set_enable); + @@ -139,36 +274,30 @@ index a4d4eebba1da4..de4b30545215f 100644 * cppc_set_perf - Set a CPU's performance controls. * @cpu: CPU for which to set performance controls. diff --git a/include/acpi/cppc_acpi.h b/include/acpi/cppc_acpi.h -index 9f4985b4d64de..3fdae40a75fcd 100644 +index bc159a9b4a73..92b7ea8d8f5e 100644 --- a/include/acpi/cppc_acpi.h +++ b/include/acpi/cppc_acpi.h -@@ -137,6 +137,7 @@ struct cppc_cpudata { - extern int cppc_get_desired_perf(int cpunum, u64 *desired_perf); +@@ -138,6 +138,7 @@ extern int cppc_get_desired_perf(int cpunum, u64 *desired_perf); + extern int cppc_get_nominal_perf(int cpunum, u64 *nominal_perf); extern int cppc_get_perf_ctrs(int cpu, struct cppc_perf_fb_ctrs *perf_fb_ctrs); extern int cppc_set_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls); -+extern int cppc_set_enable(int cpu, u32 enable); ++extern int cppc_set_enable(int cpu, bool enable); extern int cppc_get_perf_caps(int cpu, struct cppc_perf_caps *caps); extern bool acpi_cpc_valid(void); extern int acpi_get_psd_map(unsigned int cpu, struct cppc_cpudata *cpu_data); -@@ -157,6 +158,10 @@ static inline int cppc_set_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls) +@@ -162,6 +163,10 @@ static inline int cppc_set_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls) { return -ENOTSUPP; } -+static inline int cppc_set_enable(int cpu, u32 enable) ++static inline int cppc_set_enable(int cpu, bool enable) +{ + return -ENOTSUPP; +} static inline int cppc_get_perf_caps(int cpu, struct cppc_perf_caps *caps) { return -ENOTSUPP; --- -cgit 1.2.3-1.el7 -From df9ad0b99a9f0e3371aa94e49fe92a2c2a9fa95d Mon Sep 17 00:00:00 2001 -From: Huang Rui <ray.huang@amd.com> -Date: Thu, 10 Jun 2021 18:04:45 +0800 -Subject: cpufreq: amd: introduce a new amd pstate driver to support future - processors + amd-pstate is the AMD CPU performance scaling driver that introduces a new CPU frequency control mechanism on AMD Zen based CPU series in Linux @@ -188,17 +317,17 @@ the hardware and SBIOS functionalities. There are two types of hardware implementations for amd-pstate: one is full MSR support and another is shared memory support. It can use -X86_FEATURE_AMD_CPPC_EXT feature flag to distinguish the different types. +X86_FEATURE_CPPC feature flag to distinguish the different types. Using the new AMD P-States method + kernel governors (*schedutil*, *ondemand*, ...) to manage the frequency update is the most appropriate bridge between AMD Zen based hardware processor and Linux kernel, the -processor is able to ajust to the most efficiency frequency according to +processor is able to adjust to the most efficiency frequency according to the kernel scheduler loading. -Performance Per Watt (PPW) Caculation: +Performance Per Watt (PPW) Calculation: -The PPW caculation is referred by below paper: +The PPW calculation is referred by below paper: https://software.intel.com/content/dam/develop/external/us/en/documents/performance-per-what-paper.pdf Below formula is referred from below spec to measure the PPW: @@ -206,13 +335,13 @@ Below formula is referred from below spec to measure the PPW: (F / t) / P = F * t / (t * E) = F / E, "F" is the number of frames per second. -"P" is power measurd in watts. +"P" is power measured in watts. "E" is energy measured in joules. We use the RAPL interface with "perf" tool to get the energy data of the package power. -The data comparsions between amd-pstate and acpi-freq module are tested on +The data comparisons between amd-pstate and acpi-freq module are tested on AMD Cezanne processor: 1) TBench CPU benchmark: @@ -280,30 +409,34 @@ performance per watt scaling on mobile CPU benchmarks in most of cases. Signed-off-by: Huang Rui <ray.huang@amd.com> --- - drivers/cpufreq/Kconfig.x86 | 13 ++ + drivers/cpufreq/Kconfig.x86 | 17 ++ drivers/cpufreq/Makefile | 1 + - drivers/cpufreq/amd-pstate.c | 478 +++++++++++++++++++++++++++++++++++++++++++ - 3 files changed, 492 insertions(+) + drivers/cpufreq/amd-pstate.c | 398 +++++++++++++++++++++++++++++++++++ + 3 files changed, 416 insertions(+) create mode 100644 drivers/cpufreq/amd-pstate.c diff --git a/drivers/cpufreq/Kconfig.x86 b/drivers/cpufreq/Kconfig.x86 -index 92701a18bdd91..9cd7e338bdcdf 100644 +index 92701a18bdd9..21837eb1698b 100644 --- a/drivers/cpufreq/Kconfig.x86 +++ b/drivers/cpufreq/Kconfig.x86 -@@ -34,6 +34,19 @@ config X86_PCC_CPUFREQ - +@@ -34,6 +34,23 @@ config X86_PCC_CPUFREQ + If in doubt, say N. - + +config X86_AMD_PSTATE + tristate "AMD Processor P-State driver" + depends on X86 + select ACPI_PROCESSOR if ACPI -+ select ACPI_CPPC_LIB if X86_64 && ACPI && SCHED_MC_PRIO ++ select ACPI_CPPC_LIB if X86_64 && ACPI + select CPU_FREQ_GOV_SCHEDUTIL if SMP + help + This driver adds a CPUFreq driver which utilizes a fine grain -+ processor performance freqency control range instead of legacy -+ performance levels. This driver also supports newer AMD CPUs. ++ processor performance frequency control range instead of legacy ++ performance levels. This driver supports the AMD processors with ++ _CPC object in the SBIOS. ++ ++ For details, take a look at: ++ <file:Documentation/admin-guide/pm/amd-pstate.rst>. + + If in doubt, say N. + @@ -311,43 +444,29 @@ index 92701a18bdd91..9cd7e338bdcdf 100644 tristate "ACPI Processor P-States driver" depends on ACPI_PROCESSOR diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile -index 27d3bd7ea9d4e..3d4bd7141cf85 100644 +index 48ee5859030c..c8d307010922 100644 --- a/drivers/cpufreq/Makefile +++ b/drivers/cpufreq/Makefile -@@ -24,6 +24,7 @@ obj-$(CONFIG_CPUFREQ_DT_PLATDEV) += cpufreq-dt-platdev.o - # powernow-k8 can load then. ACPI is preferred to all other hardware-specific drivers. +@@ -25,6 +25,7 @@ obj-$(CONFIG_CPUFREQ_DT_PLATDEV) += cpufreq-dt-platdev.o # speedstep-* is preferred over p4-clockmod. - -+obj-$(CONFIG_X86_AMD_PSTATE) += amd-pstate.o + obj-$(CONFIG_X86_ACPI_CPUFREQ) += acpi-cpufreq.o ++obj-$(CONFIG_X86_AMD_PSTATE) += amd-pstate.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.c b/drivers/cpufreq/amd-pstate.c new file mode 100644 -index 0000000000000..4c9c9bf1d72bb +index 000000000000..8b501a72c3dd --- /dev/null +++ b/drivers/cpufreq/amd-pstate.c -@@ -0,0 +1,478 @@ +@@ -0,0 +1,398 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * amd-pstate.c - AMD Processor P-state Frequency Driver + * + * Copyright (C) 2021 Advanced Micro Devices, Inc. All Rights Reserved. + * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation; either version 2 -+ * of the License, or (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License along with -+ * this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -+ * + * Author: Huang Rui <ray.huang@amd.com> + */ + @@ -366,6 +485,7 @@ index 0000000000000..4c9c9bf1d72bb +#include <linux/io.h> +#include <linux/delay.h> +#include <linux/uaccess.h> ++#include <linux/static_call.h> + +#include <acpi/processor.h> +#include <acpi/cppc_acpi.h> @@ -384,7 +504,6 @@ index 0000000000000..4c9c9bf1d72bb + int cpu; + + struct freq_qos_request req[2]; -+ struct cpufreq_policy *policy; + + u64 cppc_req_cached; + @@ -399,26 +518,16 @@ index 0000000000000..4c9c9bf1d72bb + u32 lowest_nonlinear_freq; +}; + -+struct amd_pstate_perf_funcs { -+ int (*enable)(bool enable); -+ int (*init_perf)(struct amd_cpudata *cpudata); -+ void (*update_perf)(struct amd_cpudata *cpudata, -+ u32 min_perf, u32 des_perf, -+ u32 max_perf, bool fast_switch); -+}; -+ +static inline int pstate_enable(bool enable) +{ + return wrmsrl_safe(MSR_AMD_CPPC_ENABLE, enable ? 1 : 0); +} + -+static int -+amd_pstate_enable(struct amd_pstate_perf_funcs *funcs, bool enable) -+{ -+ if (!funcs) -+ return -EINVAL; ++DEFINE_STATIC_CALL(amd_pstate_enable, pstate_enable); + -+ return funcs->enable(enable); ++static inline int amd_pstate_enable(bool enable) ++{ ++ return static_call(amd_pstate_enable)(enable); +} + +static int pstate_init_perf(struct amd_cpudata *cpudata) @@ -430,9 +539,10 @@ index 0000000000000..4c9c9bf1d72bb + if (ret) + return ret; + -+ /* Some AMD processors has specific power features that the cppc entry -+ * doesn't indicate the highest performance. It will introduce the -+ * feature in following days. ++ /* ++ * TODO: Introduce AMD specific power feature. ++ * ++ * CPPC entry doesn't indicate the highest performance in some ASICs. + */ + WRITE_ONCE(cpudata->highest_perf, amd_get_highest_perf()); + @@ -443,19 +553,15 @@ index 0000000000000..4c9c9bf1d72bb + return 0; +} + -+static int amd_pstate_init_perf(struct amd_cpudata *cpudata) -+{ -+ struct amd_pstate_perf_funcs *funcs = cpufreq_get_driver_data(); -+ -+ if (!funcs) -+ return -EINVAL; ++DEFINE_STATIC_CALL(amd_pstate_init_perf, pstate_init_perf); + -+ return funcs->init_perf(cpudata); ++static inline int amd_pstate_init_perf(struct amd_cpudata *cpudata) ++{ ++ return static_call(amd_pstate_init_perf)(cpudata); +} + -+static void pstate_update_perf(struct amd_cpudata *cpudata, -+ u32 min_perf, u32 des_perf, u32 max_perf, -+ bool fast_switch) ++static void pstate_update_perf(struct amd_cpudata *cpudata, u32 min_perf, ++ u32 des_perf, u32 max_perf, bool fast_switch) +{ + if (fast_switch) + wrmsrl(MSR_AMD_CPPC_REQ, READ_ONCE(cpudata->cppc_req_cached)); @@ -464,24 +570,18 @@ index 0000000000000..4c9c9bf1d72bb + READ_ONCE(cpudata->cppc_req_cached)); +} + -+static int -+amd_pstate_update_perf(struct amd_cpudata *cpudata, u32 min_perf, -+ u32 des_perf, u32 max_perf, bool fast_switch) -+{ -+ struct amd_pstate_perf_funcs *funcs = cpufreq_get_driver_data(); -+ -+ if (!funcs) -+ return -EINVAL; ++DEFINE_STATIC_CALL(amd_pstate_update_perf, pstate_update_perf); + -+ funcs->update_perf(cpudata, min_perf, des_perf, -+ max_perf, fast_switch); -+ -+ return 0; ++static inline void amd_pstate_update_perf(struct amd_cpudata *cpudata, ++ u32 min_perf, u32 des_perf, ++ u32 max_perf, bool fast_switch) ++{ ++ static_call(amd_pstate_update_perf)(cpudata, min_perf, des_perf, ++ max_perf, fast_switch); +} + -+static int -+amd_pstate_update(struct amd_cpudata *cpudata, u32 min_perf, -+ u32 des_perf, u32 max_perf, bool fast_switch) ++static void amd_pstate_update(struct amd_cpudata *cpudata, u32 min_perf, ++ u32 des_perf, u32 max_perf, bool fast_switch) +{ + u64 prev = READ_ONCE(cpudata->cppc_req_cached); + u64 value = prev; @@ -496,12 +596,12 @@ index 0000000000000..4c9c9bf1d72bb + value |= REQ_MAX_PERF(max_perf); + + if (value == prev) -+ return 0; ++ return; + + WRITE_ONCE(cpudata->cppc_req_cached, value); + -+ return amd_pstate_update_perf(cpudata, min_perf, des_perf, -+ max_perf, fast_switch); ++ amd_pstate_update_perf(cpudata, min_perf, des_perf, ++ max_perf, fast_switch); +} + +static int amd_pstate_verify(struct cpufreq_policy_data *policy) @@ -515,31 +615,29 @@ index 0000000000000..4c9c9bf1d72bb + unsigned int target_freq, + unsigned int relation) +{ -+ int ret; + struct cpufreq_freqs freqs; + struct amd_cpudata *cpudata = policy->driver_data; -+ unsigned long amd_max_perf, amd_min_perf, amd_des_perf, -+ amd_cap_perf; ++ unsigned long max_perf, min_perf, des_perf, cap_perf; + + if (!cpudata->max_freq) + return -ENODEV; + -+ amd_cap_perf = READ_ONCE(cpudata->highest_perf); -+ amd_min_perf = READ_ONCE(cpudata->lowest_nonlinear_perf); -+ amd_max_perf = amd_cap_perf; ++ cap_perf = READ_ONCE(cpudata->highest_perf); ++ min_perf = READ_ONCE(cpudata->lowest_nonlinear_perf); ++ max_perf = cap_perf; + + freqs.old = policy->cur; + freqs.new = target_freq; + -+ amd_des_perf = DIV_ROUND_CLOSEST(target_freq * amd_cap_perf, -+ cpudata->max_freq); ++ des_perf = DIV_ROUND_CLOSEST(target_freq * cap_perf, ++ cpudata->max_freq); + + cpufreq_freq_transition_begin(policy, &freqs); -+ ret = amd_pstate_update(cpudata, amd_min_perf, amd_des_perf, -+ amd_max_perf, false); ++ amd_pstate_update(cpudata, min_perf, des_perf, ++ max_perf, false); + cpufreq_freq_transition_end(policy, &freqs, false); + -+ return ret; ++ return 0; +} + +static int amd_get_min_freq(struct amd_cpudata *cpudata) @@ -580,16 +678,13 @@ index 0000000000000..4c9c9bf1d72bb +static int amd_get_nominal_freq(struct amd_cpudata *cpudata) +{ + struct cppc_perf_caps cppc_perf; -+ u32 nominal_freq; + + int ret = cppc_get_perf_caps(cpudata->cpu, &cppc_perf); + if (ret) + return ret; + -+ nominal_freq = cppc_perf.nominal_freq; -+ + /* Switch to khz */ -+ return nominal_freq * 1000; ++ return cppc_perf.nominal_freq * 1000; +} + +static int amd_get_lowest_nonlinear_freq(struct amd_cpudata *cpudata) @@ -608,8 +703,8 @@ index 0000000000000..4c9c9bf1d72bb + + lowest_nonlinear_perf = cppc_perf.lowest_nonlinear_perf; + -+ lowest_nonlinear_ratio = div_u64(lowest_nonlinear_perf << -+ SCHED_CAPACITY_SHIFT, nominal_perf); ++ lowest_nonlinear_ratio = div_u64(lowest_nonlinear_perf << SCHED_CAPACITY_SHIFT, ++ nominal_perf); + + lowest_nonlinear_freq = nominal_freq * lowest_nonlinear_ratio >> SCHED_CAPACITY_SHIFT; + @@ -617,33 +712,9 @@ index 0000000000000..4c9c9bf1d72bb + return lowest_nonlinear_freq * 1000; +} + -+static int amd_pstate_init_freqs_in_cpudata(struct amd_cpudata *cpudata, -+ u32 max_freq, u32 min_freq, -+ u32 nominal_freq, -+ u32 lowest_nonlinear_freq) -+{ -+ if (!cpudata) -+ return -EINVAL; -+ -+ /* Initial processor data capability frequencies */ -+ cpudata->max_freq = max_freq; -+ cpudata->min_freq = min_freq; -+ cpudata->nominal_freq = nominal_freq; -+ cpudata->lowest_nonlinear_freq = lowest_nonlinear_freq; -+ -+ return 0; -+} -+ -+static struct amd_pstate_perf_funcs pstate_funcs = { -+ .enable = pstate_enable, -+ .init_perf = pstate_init_perf, -+ .update_perf = pstate_update_perf, -+}; -+ +static int amd_pstate_cpu_init(struct cpufreq_policy *policy) +{ + int min_freq, max_freq, nominal_freq, lowest_nonlinear_freq, ret; -+ unsigned int cpu = policy->cpu; + struct device *dev; + struct amd_cpudata *cpudata; + @@ -655,8 +726,7 @@ index 0000000000000..4c9c9bf1d72bb + if (!cpudata) + return -ENOMEM; + -+ cpudata->cpu = cpu; -+ cpudata->policy = policy; ++ cpudata->cpu = policy->cpu; + + ret = amd_pstate_init_perf(cpudata); + if (ret) @@ -700,20 +770,16 @@ index 0000000000000..4c9c9bf1d72bb + goto free_cpudata2; + } + -+ ret = amd_pstate_init_freqs_in_cpudata(cpudata, max_freq, min_freq, -+ nominal_freq, -+ lowest_nonlinear_freq); -+ if (ret) { -+ dev_err(dev, "Failed to init cpudata (%d)\n", ret); -+ goto free_cpudata3; -+ } ++ /* Initial processor data capability frequencies */ ++ cpudata->max_freq = max_freq; ++ cpudata->min_freq = min_freq; ++ cpudata->nominal_freq = nominal_freq; ++ cpudata->lowest_nonlinear_freq = lowest_nonlinear_freq; + + policy->driver_data = cpudata; + + return 0; + -+free_cpudata3: -+ freq_qos_remove_request(&cpudata->req[1]); +free_cpudata2: + freq_qos_remove_request(&cpudata->req[0]); +free_cpudata1: @@ -746,14 +812,12 @@ index 0000000000000..4c9c9bf1d72bb +static int __init amd_pstate_init(void) +{ + int ret; -+ struct amd_pstate_perf_funcs *funcs; + + if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD) + return -ENODEV; + + if (!acpi_cpc_valid()) { -+ pr_debug("%s, the _CPC object is not present in SBIOS\n", -+ __func__); ++ pr_debug("the _CPC object is not present in SBIOS\n"); + return -ENODEV; + } + @@ -762,42 +826,31 @@ index 0000000000000..4c9c9bf1d72bb + return -EEXIST; + + /* capability check */ -+ if (!boot_cpu_has(X86_FEATURE_AMD_CPPC_EXT)) { -+ pr_debug("%s, AMD CPPC extension functionality is supported\n", -+ __func__); ++ if (!boot_cpu_has(X86_FEATURE_CPPC)) { ++ pr_debug("AMD CPPC MSR based functionality is not supported\n"); + return -ENODEV; + } + -+ funcs = &pstate_funcs; -+ + /* enable amd pstate feature */ -+ ret = amd_pstate_enable(funcs, true); ++ ret = amd_pstate_enable(true); + if (ret) { -+ pr_err("%s, failed to enable amd-pstate with return %d\n", -+ __func__, ret); ++ pr_err("failed to enable amd-pstate with return %d\n", ret); + return ret; + } + -+ amd_pstate_driver.driver_data = funcs; -+ + ret = cpufreq_register_driver(&amd_pstate_driver); -+ if (ret) { -+ pr_err("%s, return %d\n", __func__, ret); -+ return ret; -+ } ++ if (ret) ++ pr_err("failed to register amd_pstate_driver with return %d\n", ++ ret); + -+ return 0; ++ return ret; +} + +static void __exit amd_pstate_exit(void) +{ -+ struct amd_pstate_perf_funcs *funcs; -+ -+ funcs = cpufreq_get_driver_data(); -+ + cpufreq_unregister_driver(&amd_pstate_driver); + -+ amd_pstate_enable(funcs, false); ++ amd_pstate_enable(false); +} + +module_init(amd_pstate_init); @@ -806,138 +859,124 @@ index 0000000000000..4c9c9bf1d72bb +MODULE_AUTHOR("Huang Rui <ray.huang@amd.com>"); +MODULE_DESCRIPTION("AMD Processor P-state Frequency Driver"); +MODULE_LICENSE("GPL"); --- -cgit 1.2.3-1.el7 -From 54beca4738acc38c08710cfcb1c3312755000cf6 Mon Sep 17 00:00:00 2001 -From: Huang Rui <ray.huang@amd.com> -Date: Fri, 13 Aug 2021 18:43:47 +0800 -Subject: cpufreq: amd: add fast switch function for amd-pstate module -Introduce the fast switch function for amd-pstate module on the AMD -processors which support the full MSR register control. It's able to -decrease the lattency on interrupt context. + +Introduce the fast switch function for amd-pstate on the AMD processors +which support the full MSR register control. It's able to decrease the +latency on interrupt context. Signed-off-by: Huang Rui <ray.huang@amd.com> --- - drivers/cpufreq/amd-pstate.c | 64 ++++++++++++++++++++++++++++++++++++++++++++ - 1 file changed, 64 insertions(+) + drivers/cpufreq/amd-pstate.c | 35 +++++++++++++++++++++++++++++++++++ + 1 file changed, 35 insertions(+) diff --git a/drivers/cpufreq/amd-pstate.c b/drivers/cpufreq/amd-pstate.c -index 4c9c9bf1d72bb..32b4f6d797830 100644 +index 8b501a72c3dd..4a02a42f4113 100644 --- a/drivers/cpufreq/amd-pstate.c +++ b/drivers/cpufreq/amd-pstate.c -@@ -212,6 +212,66 @@ static int amd_pstate_target(struct cpufreq_policy *policy, - return ret; +@@ -177,6 +177,38 @@ static int amd_pstate_target(struct cpufreq_policy *policy, + return 0; } - + +static void amd_pstate_adjust_perf(unsigned int cpu, -+ unsigned long min_perf, ++ unsigned long _min_perf, + unsigned long target_perf, + unsigned long capacity) +{ -+ unsigned long amd_max_perf, amd_min_perf, amd_des_perf, -+ amd_cap_perf, lowest_nonlinear_perf; ++ unsigned long max_perf, min_perf, des_perf, ++ cap_perf, lowest_nonlinear_perf; + struct cpufreq_policy *policy = cpufreq_cpu_get(cpu); + struct amd_cpudata *cpudata = policy->driver_data; + -+ amd_cap_perf = READ_ONCE(cpudata->highest_perf); ++ cap_perf = READ_ONCE(cpudata->highest_perf); + lowest_nonlinear_perf = READ_ONCE(cpudata->lowest_nonlinear_perf); + + if (target_perf < capacity) -+ amd_des_perf = DIV_ROUND_UP(amd_cap_perf * target_perf, -+ capacity); -+ -+ amd_min_perf = READ_ONCE(cpudata->highest_perf); -+ if (min_perf < capacity) -+ amd_min_perf = DIV_ROUND_UP(amd_cap_perf * min_perf, capacity); ++ des_perf = DIV_ROUND_UP(cap_perf * target_perf, capacity); + -+ if (amd_min_perf < lowest_nonlinear_perf) -+ amd_min_perf = lowest_nonlinear_perf; ++ min_perf = READ_ONCE(cpudata->highest_perf); ++ if (_min_perf < capacity) ++ min_perf = DIV_ROUND_UP(cap_perf * _min_perf, capacity); + -+ amd_max_perf = amd_cap_perf; -+ if (amd_max_perf < amd_min_perf) -+ amd_max_perf = amd_min_perf; ++ if (min_perf < lowest_nonlinear_perf) ++ min_perf = lowest_nonlinear_perf; + -+ amd_des_perf = clamp_t(unsigned long, amd_des_perf, -+ amd_min_perf, amd_max_perf); ++ max_perf = cap_perf; ++ if (max_perf < min_perf) ++ max_perf = min_perf; + -+ amd_pstate_update(cpudata, amd_min_perf, amd_des_perf, -+ amd_max_perf, true); -+} -+ -+static unsigned int amd_pstate_fast_switch(struct cpufreq_policy *policy, -+ unsigned int target_freq) -+{ -+ u64 ratio; -+ struct amd_cpudata *cpudata = policy->driver_data; -+ unsigned long amd_max_perf, amd_min_perf, amd_des_perf, nominal_perf; -+ -+ if (!cpudata->max_freq) -+ return -ENODEV; -+ -+ amd_max_perf = READ_ONCE(cpudata->highest_perf); -+ amd_min_perf = READ_ONCE(cpudata->lowest_nonlinear_perf); ++ des_perf = clamp_t(unsigned long, des_perf, min_perf, max_perf); + -+ amd_des_perf = DIV_ROUND_UP(target_freq * amd_max_perf, -+ cpudata->max_freq); -+ -+ amd_pstate_update(cpudata, amd_min_perf, amd_des_perf, -+ amd_max_perf, true); -+ -+ nominal_perf = READ_ONCE(cpudata->nominal_perf); -+ ratio = div_u64(amd_des_perf << SCHED_CAPACITY_SHIFT, nominal_perf); -+ -+ return cpudata->nominal_freq * ratio >> SCHED_CAPACITY_SHIFT; ++ amd_pstate_update(cpudata, min_perf, des_perf, max_perf, true); +} + static int amd_get_min_freq(struct amd_cpudata *cpudata) { struct cppc_perf_caps cppc_perf; -@@ -356,6 +416,8 @@ static int amd_pstate_cpu_init(struct cpufreq_policy *policy) +@@ -293,6 +325,8 @@ static int amd_pstate_cpu_init(struct cpufreq_policy *policy) /* It will be updated by governor */ policy->cur = policy->cpuinfo.min_freq; - + + policy->fast_switch_possible = true; + ret = freq_qos_add_request(&policy->constraints, &cpudata->req[0], FREQ_QOS_MIN, policy->cpuinfo.min_freq); if (ret < 0) { -@@ -408,6 +470,8 @@ static struct cpufreq_driver amd_pstate_driver = { +@@ -341,6 +375,7 @@ static struct cpufreq_driver amd_pstate_driver = { .flags = CPUFREQ_CONST_LOOPS | CPUFREQ_NEED_UPDATE_LIMITS, .verify = amd_pstate_verify, .target = amd_pstate_target, -+ .fast_switch = amd_pstate_fast_switch, + .adjust_perf = amd_pstate_adjust_perf, .init = amd_pstate_cpu_init, .exit = amd_pstate_cpu_exit, .name = "amd-pstate", --- -cgit 1.2.3-1.el7 -From ad7cc7a238ee889b9001d95fef83172763b95939 Mon Sep 17 00:00:00 2001 -From: Huang Rui <ray.huang@amd.com> -Date: Mon, 9 Aug 2021 19:06:51 +0800 -Subject: cpufreq: amd: add acpi cppc function as the backend for legacy - processors -In some old Zen based processors, they are using the shared memory that -exposed from ACPI SBIOS. + +In some of Zen2 and Zen3 based processors, they are using the shared +memory that exposed from ACPI SBIOS. In this kind of the processors, +there is no MSR support, so we add acpi cppc function as the backend for +them. + +It is using a module param (shared_mem) to enable related processors +manually. We will enable this by default once we address performance +issue on this solution. Signed-off-by: Jinzhou Su <Jinzhou.Su@amd.com> Signed-off-by: Huang Rui <ray.huang@amd.com> --- - drivers/cpufreq/amd-pstate.c | 63 +++++++++++++++++++++++++++++++++++++++----- - 1 file changed, 57 insertions(+), 6 deletions(-) + drivers/cpufreq/amd-pstate.c | 71 ++++++++++++++++++++++++++++++++++-- + 1 file changed, 67 insertions(+), 4 deletions(-) diff --git a/drivers/cpufreq/amd-pstate.c b/drivers/cpufreq/amd-pstate.c -index 32b4f6d797830..a46cd5dd9f7cc 100644 +index 4a02a42f4113..14a29326ceae 100644 --- a/drivers/cpufreq/amd-pstate.c +++ b/drivers/cpufreq/amd-pstate.c -@@ -82,6 +82,19 @@ static inline int pstate_enable(bool enable) +@@ -35,6 +35,19 @@ + #define AMD_PSTATE_TRANSITION_LATENCY 0x20000 + #define AMD_PSTATE_TRANSITION_DELAY 500 + ++/* TODO: We need more time to fine tune processors with shared memory solution ++ * with community together. ++ * ++ * There are some performance drops on the CPU benchmarks which reports from ++ * Suse. We are co-working with them to fine tune the shared memory solution. So ++ * we disable it by default to go acpi-cpufreq on these processors and add a ++ * module parameter to be able to enable it manually for debugging. ++ */ ++static bool shared_mem = false; ++module_param(shared_mem, bool, 0444); ++MODULE_PARM_DESC(shared_mem, ++ "enable amd-pstate on processors with shared memory solution (false = disabled (default), true = enabled)"); ++ + static struct cpufreq_driver amd_pstate_driver; + + struct amd_cpudata { +@@ -60,6 +73,19 @@ static inline int pstate_enable(bool enable) return wrmsrl_safe(MSR_AMD_CPPC_ENABLE, enable ? 1 : 0); } - + +static int cppc_enable(bool enable) +{ + int cpu, ret = 0; @@ -951,13 +990,13 @@ index 32b4f6d797830..a46cd5dd9f7cc 100644 + return ret; +} + - static int - amd_pstate_enable(struct amd_pstate_perf_funcs *funcs, bool enable) - { -@@ -113,6 +126,24 @@ static int pstate_init_perf(struct amd_cpudata *cpudata) + DEFINE_STATIC_CALL(amd_pstate_enable, pstate_enable); + + static inline int amd_pstate_enable(bool enable) +@@ -90,6 +116,24 @@ static int pstate_init_perf(struct amd_cpudata *cpudata) return 0; } - + +static int cppc_init_perf(struct amd_cpudata *cpudata) +{ + struct cppc_perf_caps cppc_perf; @@ -976,13 +1015,13 @@ index 32b4f6d797830..a46cd5dd9f7cc 100644 + return 0; +} + - static int amd_pstate_init_perf(struct amd_cpudata *cpudata) - { - struct amd_pstate_perf_funcs *funcs = cpufreq_get_driver_data(); -@@ -134,6 +165,19 @@ static void pstate_update_perf(struct amd_cpudata *cpudata, + DEFINE_STATIC_CALL(amd_pstate_init_perf, pstate_init_perf); + + static inline int amd_pstate_init_perf(struct amd_cpudata *cpudata) +@@ -107,6 +151,19 @@ static void pstate_update_perf(struct amd_cpudata *cpudata, u32 min_perf, READ_ONCE(cpudata->cppc_req_cached)); } - + +static void cppc_update_perf(struct amd_cpudata *cpudata, + u32 min_perf, u32 des_perf, + u32 max_perf, bool fast_switch) @@ -996,67 +1035,46 @@ index 32b4f6d797830..a46cd5dd9f7cc 100644 + cppc_set_perf(cpudata->cpu, &perf_ctrls); +} + - static int - amd_pstate_update_perf(struct amd_cpudata *cpudata, u32 min_perf, - u32 des_perf, u32 max_perf, bool fast_switch) -@@ -370,6 +414,12 @@ static struct amd_pstate_perf_funcs pstate_funcs = { - .update_perf = pstate_update_perf, - }; - -+static struct amd_pstate_perf_funcs cppc_funcs = { -+ .enable = cppc_enable, -+ .init_perf = cppc_init_perf, -+ .update_perf = cppc_update_perf, -+}; -+ - static int amd_pstate_cpu_init(struct cpufreq_policy *policy) - { - int min_freq, max_freq, nominal_freq, lowest_nonlinear_freq, ret; -@@ -416,7 +466,8 @@ static int amd_pstate_cpu_init(struct cpufreq_policy *policy) + DEFINE_STATIC_CALL(amd_pstate_update_perf, pstate_update_perf); + + static inline void amd_pstate_update_perf(struct amd_cpudata *cpudata, +@@ -325,7 +382,8 @@ static int amd_pstate_cpu_init(struct cpufreq_policy *policy) /* It will be updated by governor */ policy->cur = policy->cpuinfo.min_freq; - + - policy->fast_switch_possible = true; -+ if (boot_cpu_has(X86_FEATURE_AMD_CPPC_EXT)) ++ if (boot_cpu_has(X86_FEATURE_CPPC)) + policy->fast_switch_possible = true; - + ret = freq_qos_add_request(&policy->constraints, &cpudata->req[0], FREQ_QOS_MIN, policy->cpuinfo.min_freq); -@@ -471,7 +522,6 @@ static struct cpufreq_driver amd_pstate_driver = { +@@ -375,7 +433,6 @@ static struct cpufreq_driver amd_pstate_driver = { + .flags = CPUFREQ_CONST_LOOPS | CPUFREQ_NEED_UPDATE_LIMITS, .verify = amd_pstate_verify, .target = amd_pstate_target, - .fast_switch = amd_pstate_fast_switch, - .adjust_perf = amd_pstate_adjust_perf, .init = amd_pstate_cpu_init, .exit = amd_pstate_cpu_exit, .name = "amd-pstate", -@@ -496,14 +546,15 @@ static int __init amd_pstate_init(void) +@@ -398,8 +455,14 @@ static int __init amd_pstate_init(void) return -EEXIST; - + /* capability check */ -- if (!boot_cpu_has(X86_FEATURE_AMD_CPPC_EXT)) { -+ if (boot_cpu_has(X86_FEATURE_AMD_CPPC_EXT)) { - pr_debug("%s, AMD CPPC extension functionality is supported\n", - __func__); -- return -ENODEV; -+ funcs = &pstate_funcs; +- if (!boot_cpu_has(X86_FEATURE_CPPC)) { +- pr_debug("AMD CPPC MSR based functionality is not supported\n"); ++ if (boot_cpu_has(X86_FEATURE_CPPC)) { ++ pr_debug("AMD CPPC MSR based functionality is supported\n"); + amd_pstate_driver.adjust_perf = amd_pstate_adjust_perf; ++ } else if (shared_mem) { ++ static_call_update(amd_pstate_enable, cppc_enable); ++ static_call_update(amd_pstate_init_perf, cppc_init_perf); ++ static_call_update(amd_pstate_update_perf, cppc_update_perf); + } else { -+ funcs = &cppc_funcs; + return -ENODEV; } + -- funcs = &pstate_funcs; -- - /* enable amd pstate feature */ - ret = amd_pstate_enable(funcs, true); - if (ret) { --- -cgit 1.2.3-1.el7 -From e007c18166d11d78757454ebfac967ae460ebf08 Mon Sep 17 00:00:00 2001 -From: Huang Rui <ray.huang@amd.com> -Date: Thu, 10 Jun 2021 20:24:00 +0800 -Subject: cpufreq: amd: add trace for amd-pstate module Add trace event to monitor the performance value changes which is controlled by cpu governors. @@ -1065,20 +1083,20 @@ Signed-off-by: Huang Rui <ray.huang@amd.com> --- drivers/cpufreq/Makefile | 6 ++- drivers/cpufreq/amd-pstate-trace.c | 2 + - drivers/cpufreq/amd-pstate-trace.h | 96 ++++++++++++++++++++++++++++++++++++++ - drivers/cpufreq/amd-pstate.c | 19 ++++++-- - 4 files changed, 118 insertions(+), 5 deletions(-) + drivers/cpufreq/amd-pstate-trace.h | 77 ++++++++++++++++++++++++++++++ + drivers/cpufreq/amd-pstate.c | 4 ++ + 4 files changed, 88 insertions(+), 1 deletion(-) create mode 100644 drivers/cpufreq/amd-pstate-trace.c create mode 100644 drivers/cpufreq/amd-pstate-trace.h diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile -index 3d4bd7141cf85..c1909475eaf9e 100644 +index c8d307010922..285de70af877 100644 --- a/drivers/cpufreq/Makefile +++ b/drivers/cpufreq/Makefile @@ -17,6 +17,10 @@ obj-$(CONFIG_CPU_FREQ_GOV_ATTR_SET) += cpufreq_governor_attr_set.o obj-$(CONFIG_CPUFREQ_DT) += cpufreq-dt.o obj-$(CONFIG_CPUFREQ_DT_PLATDEV) += cpufreq-dt-platdev.o - + +# Traces +CFLAGS_amd-pstate-trace.o := -I$(src) +amd_pstate-y := amd-pstate.o amd-pstate-trace.o @@ -1086,18 +1104,18 @@ index 3d4bd7141cf85..c1909475eaf9e 100644 ################################################################################## # x86 drivers. # Link order matters. K8 is preferred to ACPI because of firmware bugs in early -@@ -24,7 +28,7 @@ obj-$(CONFIG_CPUFREQ_DT_PLATDEV) += cpufreq-dt-platdev.o - # powernow-k8 can load then. ACPI is preferred to all other hardware-specific drivers. +@@ -25,7 +29,7 @@ obj-$(CONFIG_CPUFREQ_DT_PLATDEV) += cpufreq-dt-platdev.o # speedstep-* is preferred over p4-clockmod. - + + obj-$(CONFIG_X86_ACPI_CPUFREQ) += acpi-cpufreq.o -obj-$(CONFIG_X86_AMD_PSTATE) += amd-pstate.o +obj-$(CONFIG_X86_AMD_PSTATE) += amd_pstate.o - obj-$(CONFIG_X86_ACPI_CPUFREQ) += acpi-cpufreq.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-trace.c b/drivers/cpufreq/amd-pstate-trace.c new file mode 100644 -index 0000000000000..891b696dcd694 +index 000000000000..891b696dcd69 --- /dev/null +++ b/drivers/cpufreq/amd-pstate-trace.c @@ -0,0 +1,2 @@ @@ -1105,30 +1123,16 @@ index 0000000000000..891b696dcd694 +#include "amd-pstate-trace.h" diff --git a/drivers/cpufreq/amd-pstate-trace.h b/drivers/cpufreq/amd-pstate-trace.h new file mode 100644 -index 0000000000000..50c85e150f303 +index 000000000000..647505957d4f --- /dev/null +++ b/drivers/cpufreq/amd-pstate-trace.h -@@ -0,0 +1,96 @@ +@@ -0,0 +1,77 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * amd-pstate-trace.h - AMD Processor P-state Frequency Driver Tracer + * + * Copyright (C) 2021 Advanced Micro Devices, Inc. All Rights Reserved. + * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation; either version 2 -+ * of the License, or (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License along with -+ * this program; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -+ * + * Author: Huang Rui <ray.huang@amd.com> + */ + @@ -1153,18 +1157,16 @@ index 0000000000000..50c85e150f303 + unsigned long target_perf, + unsigned long capacity, + unsigned int cpu_id, -+ u64 prev, -+ u64 value, -+ int type ++ bool changed, ++ bool fast_switch + ), + + TP_ARGS(min_perf, + target_perf, + capacity, + cpu_id, -+ prev, -+ value, -+ type ++ changed, ++ fast_switch + ), + + TP_STRUCT__entry( @@ -1172,9 +1174,8 @@ index 0000000000000..50c85e150f303 + __field(unsigned long, target_perf) + __field(unsigned long, capacity) + __field(unsigned int, cpu_id) -+ __field(u64, prev) -+ __field(u64, value) -+ __field(int, type) ++ __field(bool, changed) ++ __field(bool, fast_switch) + ), + + TP_fast_assign( @@ -1182,19 +1183,17 @@ index 0000000000000..50c85e150f303 + __entry->target_perf = target_perf; + __entry->capacity = capacity; + __entry->cpu_id = cpu_id; -+ __entry->prev = prev; -+ __entry->value = value; -+ __entry->type = type; ++ __entry->changed = changed; ++ __entry->fast_switch = fast_switch; + ), + -+ TP_printk("amd_min_perf=%lu amd_des_perf=%lu amd_max_perf=%lu cpu_id=%u prev=0x%llx value=0x%llx type=0x%d", ++ TP_printk("amd_min_perf=%lu amd_des_perf=%lu amd_max_perf=%lu cpu_id=%u changed=%s fast_switch=%s", + (unsigned long)__entry->min_perf, + (unsigned long)__entry->target_perf, + (unsigned long)__entry->capacity, + (unsigned int)__entry->cpu_id, -+ (u64)__entry->prev, -+ (u64)__entry->value, -+ (int)__entry->type ++ (__entry->changed) ? "true" : "false", ++ (__entry->fast_switch) ? "true" : "false" + ) +); + @@ -1206,127 +1205,55 @@ index 0000000000000..50c85e150f303 + +#include <trace/define_trace.h> diff --git a/drivers/cpufreq/amd-pstate.c b/drivers/cpufreq/amd-pstate.c -index a46cd5dd9f7cc..ea965a122431d 100644 +index 14a29326ceae..5e080d0dc45f 100644 --- a/drivers/cpufreq/amd-pstate.c +++ b/drivers/cpufreq/amd-pstate.c -@@ -44,10 +44,18 @@ +@@ -31,6 +31,7 @@ #include <asm/processor.h> #include <asm/cpufeature.h> #include <asm/cpu_device_id.h> +#include "amd-pstate-trace.h" - + #define AMD_PSTATE_TRANSITION_LATENCY 0x20000 #define AMD_PSTATE_TRANSITION_DELAY 500 - -+enum switch_type -+{ -+ AMD_TARGET = 0, -+ AMD_ADJUST_PERF, -+ AMD_FAST_SWITCH, -+}; -+ - static struct cpufreq_driver amd_pstate_driver; - - struct amd_cpudata { -@@ -195,7 +203,8 @@ amd_pstate_update_perf(struct amd_cpudata *cpudata, u32 min_perf, - - static int - amd_pstate_update(struct amd_cpudata *cpudata, u32 min_perf, -- u32 des_perf, u32 max_perf, bool fast_switch) -+ u32 des_perf, u32 max_perf, bool fast_switch, -+ enum switch_type type) - { - u64 prev = READ_ONCE(cpudata->cppc_req_cached); - u64 value = prev; -@@ -209,6 +218,8 @@ amd_pstate_update(struct amd_cpudata *cpudata, u32 min_perf, +@@ -189,6 +190,9 @@ static void amd_pstate_update(struct amd_cpudata *cpudata, u32 min_perf, value &= ~REQ_MAX_PERF(~0L); value |= REQ_MAX_PERF(max_perf); - + + trace_amd_pstate_perf(min_perf, des_perf, max_perf, -+ cpudata->cpu, prev, value, type); ++ cpudata->cpu, (value != prev), fast_switch); ++ if (value == prev) - return 0; - -@@ -250,7 +261,7 @@ static int amd_pstate_target(struct cpufreq_policy *policy, - - cpufreq_freq_transition_begin(policy, &freqs); - ret = amd_pstate_update(cpudata, amd_min_perf, amd_des_perf, -- amd_max_perf, false); -+ amd_max_perf, false, AMD_TARGET); - cpufreq_freq_transition_end(policy, &freqs, false); - - return ret; -@@ -288,7 +299,7 @@ static void amd_pstate_adjust_perf(unsigned int cpu, - amd_min_perf, amd_max_perf); - - amd_pstate_update(cpudata, amd_min_perf, amd_des_perf, -- amd_max_perf, true); -+ amd_max_perf, true, AMD_ADJUST_PERF); - } - - static unsigned int amd_pstate_fast_switch(struct cpufreq_policy *policy, -@@ -308,7 +319,7 @@ static unsigned int amd_pstate_fast_switch(struct cpufreq_policy *policy, - cpudata->max_freq); + return; + - amd_pstate_update(cpudata, amd_min_perf, amd_des_perf, -- amd_max_perf, true); -+ amd_max_perf, true, AMD_FAST_SWITCH); - nominal_perf = READ_ONCE(cpudata->nominal_perf); - ratio = div_u64(amd_des_perf << SCHED_CAPACITY_SHIFT, nominal_perf); --- -cgit 1.2.3-1.el7 - -From 24ab2966561da669b9879a6167e2cc7e5929735c Mon Sep 17 00:00:00 2001 -From: Huang Rui <ray.huang@amd.com> -Date: Thu, 10 Jun 2021 23:13:00 +0800 -Subject: cpufreq: amd: add boost mode support for amd-pstate If the sbios supports the boost mode of amd-pstate, let's switch to boost enabled by default. Signed-off-by: Huang Rui <ray.huang@amd.com> --- - drivers/cpufreq/amd-pstate.c | 50 ++++++++++++++++++++++++++++++++++++++++++++ - 1 file changed, 50 insertions(+) + drivers/cpufreq/amd-pstate.c | 44 ++++++++++++++++++++++++++++++++++++ + 1 file changed, 44 insertions(+) diff --git a/drivers/cpufreq/amd-pstate.c b/drivers/cpufreq/amd-pstate.c -index ea965a122431d..67a9a117f5243 100644 +index 5e080d0dc45f..0c335a917307 100644 --- a/drivers/cpufreq/amd-pstate.c +++ b/drivers/cpufreq/amd-pstate.c -@@ -75,6 +75,8 @@ struct amd_cpudata { +@@ -67,6 +67,8 @@ struct amd_cpudata { u32 min_freq; u32 nominal_freq; u32 lowest_nonlinear_freq; + + bool boost_supported; }; - - struct amd_pstate_perf_funcs { -@@ -229,6 +231,19 @@ amd_pstate_update(struct amd_cpudata *cpudata, u32 min_perf, - max_perf, fast_switch); - } - -+static bool amd_pstate_boost_supported(struct amd_cpudata *cpudata) -+{ -+ u32 highest_perf, nominal_perf; -+ -+ highest_perf = READ_ONCE(cpudata->highest_perf); -+ nominal_perf = READ_ONCE(cpudata->nominal_perf); -+ -+ if (highest_perf > nominal_perf) -+ return true; -+ -+ return false; -+} -+ - static int amd_pstate_verify(struct cpufreq_policy_data *policy) - { - cpufreq_verify_within_cpu_limits(policy); -@@ -402,6 +417,37 @@ static int amd_get_lowest_nonlinear_freq(struct amd_cpudata *cpudata) + + static inline int pstate_enable(bool enable) +@@ -342,6 +344,45 @@ static int amd_get_lowest_nonlinear_freq(struct amd_cpudata *cpudata) return lowest_nonlinear_freq * 1000; } - + +static int amd_pstate_set_boost(struct cpufreq_policy *policy, int state) +{ + struct amd_cpudata *cpudata = policy->driver_data; @@ -1354,110 +1281,67 @@ index ea965a122431d..67a9a117f5243 100644 + +static void amd_pstate_boost_init(struct amd_cpudata *cpudata) +{ ++ u32 highest_perf, nominal_perf; ++ ++ highest_perf = READ_ONCE(cpudata->highest_perf); ++ nominal_perf = READ_ONCE(cpudata->nominal_perf); ++ ++ if (highest_perf <= nominal_perf) ++ return; ++ + cpudata->boost_supported = true; + amd_pstate_driver.boost_enabled = true; +} + - static int amd_pstate_init_freqs_in_cpudata(struct amd_cpudata *cpudata, - u32 max_freq, u32 min_freq, - u32 nominal_freq, -@@ -504,6 +550,9 @@ static int amd_pstate_cpu_init(struct cpufreq_policy *policy) - + static int amd_pstate_cpu_init(struct cpufreq_policy *policy) + { + int min_freq, max_freq, nominal_freq, lowest_nonlinear_freq, ret; +@@ -411,6 +452,8 @@ static int amd_pstate_cpu_init(struct cpufreq_policy *policy) + policy->driver_data = cpudata; - -+ if (amd_pstate_boost_supported(cpudata)) -+ amd_pstate_boost_init(cpudata); + ++ amd_pstate_boost_init(cpudata); + return 0; - - free_cpudata3: -@@ -535,6 +584,7 @@ static struct cpufreq_driver amd_pstate_driver = { - .fast_switch = amd_pstate_fast_switch, + + free_cpudata2: +@@ -439,6 +482,7 @@ static struct cpufreq_driver amd_pstate_driver = { + .target = amd_pstate_target, .init = amd_pstate_cpu_init, .exit = amd_pstate_cpu_exit, + .set_boost = amd_pstate_set_boost, .name = "amd-pstate", }; + --- -cgit 1.2.3-1.el7 - -From fdbec5a44fab1213e459312b542e27dc0181d7e4 Mon Sep 17 00:00:00 2001 -From: Huang Rui <ray.huang@amd.com> -Date: Sat, 19 Jun 2021 23:41:30 +0800 -Subject: cpufreq: amd: add amd-pstate checking support check attribute -The amd-pstate hardware support check will be needed by cpupower to know -whether amd-pstate is enabled and supported. - -Signed-off-by: Huang Rui <ray.huang@amd.com> ---- - drivers/cpufreq/amd-pstate.c | 14 ++++++++++++++ - 1 file changed, 14 insertions(+) - -diff --git a/drivers/cpufreq/amd-pstate.c b/drivers/cpufreq/amd-pstate.c -index 67a9a117f5243..48dedd5af1016 100644 ---- a/drivers/cpufreq/amd-pstate.c -+++ b/drivers/cpufreq/amd-pstate.c -@@ -577,6 +577,19 @@ static int amd_pstate_cpu_exit(struct cpufreq_policy *policy) - return 0; - } - -+static ssize_t show_is_amd_pstate_enabled(struct cpufreq_policy *policy, -+ char *buf) -+{ -+ return sprintf(&buf[0], "%d\n", acpi_cpc_valid() ? 1 : 0); -+} -+ -+cpufreq_freq_attr_ro(is_amd_pstate_enabled); -+ -+static struct freq_attr *amd_pstate_attr[] = { -+ &is_amd_pstate_enabled, -+ NULL, -+}; -+ - static struct cpufreq_driver amd_pstate_driver = { - .flags = CPUFREQ_CONST_LOOPS | CPUFREQ_NEED_UPDATE_LIMITS, - .verify = amd_pstate_verify, -@@ -586,6 +599,7 @@ static struct cpufreq_driver amd_pstate_driver = { - .exit = amd_pstate_cpu_exit, - .set_boost = amd_pstate_set_boost, - .name = "amd-pstate", -+ .attr = amd_pstate_attr, - }; - - static int __init amd_pstate_init(void) --- -cgit 1.2.3-1.el7 - -From 4043d05067a68c58255a6759c528bb78db656327 Mon Sep 17 00:00:00 2001 -From: Huang Rui <ray.huang@amd.com> -Date: Sun, 20 Jun 2021 13:26:01 +0800 -Subject: cpufreq: amd: add amd-pstate frequencies attributes Introduce sysfs attributes to get the different level processor frequencies. Signed-off-by: Huang Rui <ray.huang@amd.com> --- - drivers/cpufreq/amd-pstate.c | 80 +++++++++++++++++++++++++++++++++++++++++++- - 1 file changed, 79 insertions(+), 1 deletion(-) + drivers/cpufreq/amd-pstate.c | 46 ++++++++++++++++++++++++++++++++++++ + 1 file changed, 46 insertions(+) diff --git a/drivers/cpufreq/amd-pstate.c b/drivers/cpufreq/amd-pstate.c -index 48dedd5af1016..3c727a22cb69d 100644 +index 0c335a917307..09c5fd8bd9da 100644 --- a/drivers/cpufreq/amd-pstate.c +++ b/drivers/cpufreq/amd-pstate.c -@@ -577,16 +577,94 @@ static int amd_pstate_cpu_exit(struct cpufreq_policy *policy) +@@ -476,6 +476,51 @@ static int amd_pstate_cpu_exit(struct cpufreq_policy *policy) return 0; } - --static ssize_t show_is_amd_pstate_enabled(struct cpufreq_policy *policy, + +/* Sysfs attributes */ + ++/* This frequency is to indicate the maximum hardware frequency. ++ * If boost is not active but supported, the frequency will be larger than the ++ * one in cpuinfo. ++ */ +static ssize_t show_amd_pstate_max_freq(struct cpufreq_policy *policy, - char *buf) ++ char *buf) +{ -+ int ret = 0, max_freq; ++ int max_freq; + struct amd_cpudata *cpudata; + + cpudata = policy->driver_data; @@ -1466,201 +1350,91 @@ index 48dedd5af1016..3c727a22cb69d 100644 + if (max_freq < 0) + return max_freq; + -+ ret += sprintf(&buf[ret], "%u\n", max_freq); -+ -+ return ret; -+} -+ -+static ssize_t show_amd_pstate_nominal_freq(struct cpufreq_policy *policy, -+ char *buf) -+{ -+ int ret = 0, nominal_freq; -+ struct amd_cpudata *cpudata; -+ -+ cpudata = policy->driver_data; -+ -+ nominal_freq = amd_get_nominal_freq(cpudata); -+ if (nominal_freq < 0) -+ return nominal_freq; -+ -+ ret += sprintf(&buf[ret], "%u\n", nominal_freq); -+ -+ return ret; -+} -+ -+static ssize_t -+show_amd_pstate_lowest_nonlinear_freq(struct cpufreq_policy *policy, char *buf) -+{ -+ int ret = 0, freq; -+ struct amd_cpudata *cpudata; -+ -+ cpudata = policy->driver_data; -+ -+ freq = amd_get_lowest_nonlinear_freq(cpudata); -+ if (freq < 0) -+ return freq; -+ -+ ret += sprintf(&buf[ret], "%u\n", freq); -+ -+ return ret; ++ return sprintf(&buf[0], "%u\n", max_freq); +} + -+static ssize_t show_amd_pstate_min_freq(struct cpufreq_policy *policy, char *buf) ++static ssize_t show_amd_pstate_lowest_nonlinear_freq(struct cpufreq_policy *policy, ++ char *buf) +{ -+ int ret = 0; + int freq; + struct amd_cpudata *cpudata; + + cpudata = policy->driver_data; + -+ freq = amd_get_min_freq(cpudata); ++ freq = amd_get_lowest_nonlinear_freq(cpudata); + if (freq < 0) + return freq; + -+ ret += sprintf(&buf[ret], "%u\n", freq); -+ -+ return ret; ++ return sprintf(&buf[0], "%u\n", freq); +} + -+static ssize_t show_is_amd_pstate_enabled(struct cpufreq_policy *policy, -+ char *buf) - { - return sprintf(&buf[0], "%d\n", acpi_cpc_valid() ? 1 : 0); - } - - cpufreq_freq_attr_ro(is_amd_pstate_enabled); +cpufreq_freq_attr_ro(amd_pstate_max_freq); -+cpufreq_freq_attr_ro(amd_pstate_nominal_freq); +cpufreq_freq_attr_ro(amd_pstate_lowest_nonlinear_freq); -+cpufreq_freq_attr_ro(amd_pstate_min_freq); - - static struct freq_attr *amd_pstate_attr[] = { - &is_amd_pstate_enabled, ++ ++static struct freq_attr *amd_pstate_attr[] = { + &amd_pstate_max_freq, -+ &amd_pstate_nominal_freq, + &amd_pstate_lowest_nonlinear_freq, -+ &amd_pstate_min_freq, - NULL, ++ NULL, ++}; ++ + static struct cpufreq_driver amd_pstate_driver = { + .flags = CPUFREQ_CONST_LOOPS | CPUFREQ_NEED_UPDATE_LIMITS, + .verify = amd_pstate_verify, +@@ -484,6 +529,7 @@ static struct cpufreq_driver amd_pstate_driver = { + .exit = amd_pstate_cpu_exit, + .set_boost = amd_pstate_set_boost, + .name = "amd-pstate", ++ .attr = amd_pstate_attr, }; + + static int __init amd_pstate_init(void) --- -cgit 1.2.3-1.el7 -From 4b56a82d37ecb8e9f9df2d0b055939577ff147cf Mon Sep 17 00:00:00 2001 -From: Huang Rui <ray.huang@amd.com> -Date: Sun, 20 Jun 2021 15:01:08 +0800 -Subject: cpufreq: amd: add amd-pstate performance attributes Introduce sysfs attributes to get the different level amd-pstate performances. Signed-off-by: Huang Rui <ray.huang@amd.com> --- - drivers/cpufreq/amd-pstate.c | 66 ++++++++++++++++++++++++++++++++++++++++++++ - 1 file changed, 66 insertions(+) + drivers/cpufreq/amd-pstate.c | 17 +++++++++++++++++ + 1 file changed, 17 insertions(+) diff --git a/drivers/cpufreq/amd-pstate.c b/drivers/cpufreq/amd-pstate.c -index 3c727a22cb69d..9c60388d45edc 100644 +index 09c5fd8bd9da..458313cdba93 100644 --- a/drivers/cpufreq/amd-pstate.c +++ b/drivers/cpufreq/amd-pstate.c -@@ -647,6 +647,62 @@ static ssize_t show_amd_pstate_min_freq(struct cpufreq_policy *policy, char *buf - return ret; +@@ -512,12 +512,29 @@ static ssize_t show_amd_pstate_lowest_nonlinear_freq(struct cpufreq_policy *poli + return sprintf(&buf[0], "%u\n", freq); } - -+static ssize_t -+show_amd_pstate_highest_perf(struct cpufreq_policy *policy, char *buf) + ++/* In some of ASICs, the highest_perf is not the one in the _CPC table, so we ++ * need to expose it to sysfs. ++ */ ++static ssize_t show_amd_pstate_highest_perf(struct cpufreq_policy *policy, ++ char *buf) +{ -+ int ret = 0; + u32 perf; + struct amd_cpudata *cpudata = policy->driver_data; + + perf = READ_ONCE(cpudata->highest_perf); + -+ ret += sprintf(&buf[ret], "%u\n", perf); -+ -+ return ret; -+} -+ -+static ssize_t -+show_amd_pstate_nominal_perf(struct cpufreq_policy *policy, char *buf) -+{ -+ int ret = 0; -+ u32 perf; -+ struct amd_cpudata *cpudata = policy->driver_data; -+ -+ perf = READ_ONCE(cpudata->nominal_perf); -+ -+ ret += sprintf(&buf[ret], "%u\n", perf); -+ -+ return ret; -+} -+ -+static ssize_t -+show_amd_pstate_lowest_nonlinear_perf(struct cpufreq_policy *policy, char *buf) -+{ -+ int ret = 0; -+ u32 perf; -+ struct amd_cpudata *cpudata = policy->driver_data; -+ -+ perf = READ_ONCE(cpudata->lowest_nonlinear_perf); -+ -+ ret += sprintf(&buf[ret], "%u\n", perf); -+ -+ return ret; -+} -+ -+static ssize_t -+show_amd_pstate_lowest_perf(struct cpufreq_policy *policy, char *buf) -+{ -+ int ret = 0; -+ u32 perf; -+ struct amd_cpudata *cpudata = policy->driver_data; -+ -+ perf = READ_ONCE(cpudata->lowest_perf); -+ -+ ret += sprintf(&buf[ret], "%u\n", perf); -+ -+ return ret; ++ return sprintf(&buf[0], "%u\n", perf); +} + - static ssize_t show_is_amd_pstate_enabled(struct cpufreq_policy *policy, - char *buf) - { -@@ -654,17 +710,27 @@ static ssize_t show_is_amd_pstate_enabled(struct cpufreq_policy *policy, - } - - cpufreq_freq_attr_ro(is_amd_pstate_enabled); -+ cpufreq_freq_attr_ro(amd_pstate_max_freq); - cpufreq_freq_attr_ro(amd_pstate_nominal_freq); cpufreq_freq_attr_ro(amd_pstate_lowest_nonlinear_freq); - cpufreq_freq_attr_ro(amd_pstate_min_freq); - + +cpufreq_freq_attr_ro(amd_pstate_highest_perf); -+cpufreq_freq_attr_ro(amd_pstate_nominal_perf); -+cpufreq_freq_attr_ro(amd_pstate_lowest_nonlinear_perf); -+cpufreq_freq_attr_ro(amd_pstate_lowest_perf); + static struct freq_attr *amd_pstate_attr[] = { - &is_amd_pstate_enabled, &amd_pstate_max_freq, - &amd_pstate_nominal_freq, &amd_pstate_lowest_nonlinear_freq, - &amd_pstate_min_freq, + &amd_pstate_highest_perf, -+ &amd_pstate_nominal_perf, -+ &amd_pstate_lowest_nonlinear_perf, -+ &amd_pstate_lowest_perf, NULL, }; + --- -cgit 1.2.3-1.el7 -From 5b16452c4363a46a28bd65a00a4a3282bdb7ec69 Mon Sep 17 00:00:00 2001 -From: Huang Rui <ray.huang@amd.com> -Date: Mon, 14 Jun 2021 22:52:01 +0800 -Subject: cpupower: add AMD P-state capability flag Add AMD P-state capability flag in cpupower to indicate AMD new P-state kernel module support on Ryzen processors. @@ -1671,7 +1445,7 @@ Signed-off-by: Huang Rui <ray.huang@amd.com> 1 file changed, 1 insertion(+) diff --git a/tools/power/cpupower/utils/helpers/helpers.h b/tools/power/cpupower/utils/helpers/helpers.h -index 33ffacee7fcb9..b4813efdfb009 100644 +index 33ffacee7fcb..b4813efdfb00 100644 --- a/tools/power/cpupower/utils/helpers/helpers.h +++ b/tools/power/cpupower/utils/helpers/helpers.h @@ -73,6 +73,7 @@ enum cpupower_cpu_vendor {X86_VENDOR_UNKNOWN = 0, X86_VENDOR_INTEL, @@ -1679,83 +1453,106 @@ index 33ffacee7fcb9..b4813efdfb009 100644 #define CPUPOWER_CAP_AMD_PSTATEDEF 0x00000200 #define CPUPOWER_CAP_AMD_CPB_MSR 0x00000400 +#define CPUPOWER_CAP_AMD_PSTATE 0x00000800 - + #define CPUPOWER_AMD_CPBDIS 0x02000000 + --- -cgit 1.2.3-1.el7 -From 456b88736d16414c3cce9dd5101b05dfe38baa18 Mon Sep 17 00:00:00 2001 -From: Huang Rui <ray.huang@amd.com> -Date: Sun, 27 Jun 2021 22:25:39 +0800 -Subject: cpupower: add the function to check amd-pstate enabled -Introduce the cpupower_amd_pstate_enabled() to check whether the kernel -mode enables amd-pstate. +The processor with amd-pstate function also supports legacy ACPI +hardware P-States feature as well. Once driver sets amd-pstate eanbled, +the processor will respond the finer grain amd-pstate feature instead of +legacy ACPI P-States. So it introduces the cpupower_amd_pstate_enabled() +to check whether the current kernel enables amd-pstate or acpi-cpufreq +module. Signed-off-by: Huang Rui <ray.huang@amd.com> --- - tools/power/cpupower/utils/helpers/helpers.h | 5 +++++ - tools/power/cpupower/utils/helpers/misc.c | 20 ++++++++++++++++++++ - 2 files changed, 25 insertions(+) + tools/power/cpupower/utils/helpers/helpers.h | 10 ++++++++++ + tools/power/cpupower/utils/helpers/misc.c | 18 ++++++++++++++++++ + 2 files changed, 28 insertions(+) diff --git a/tools/power/cpupower/utils/helpers/helpers.h b/tools/power/cpupower/utils/helpers/helpers.h -index b4813efdfb009..eb43c14d1728e 100644 +index b4813efdfb00..e03cc97297aa 100644 --- a/tools/power/cpupower/utils/helpers/helpers.h +++ b/tools/power/cpupower/utils/helpers/helpers.h -@@ -136,6 +136,11 @@ extern int decode_pstates(unsigned int cpu, int boost_states, - +@@ -11,6 +11,7 @@ + + #include <libintl.h> + #include <locale.h> ++#include <stdbool.h> + + #include "helpers/bitmask.h" + #include <cpupower.h> +@@ -136,6 +137,12 @@ extern int decode_pstates(unsigned int cpu, int boost_states, + extern int cpufreq_has_boost_support(unsigned int cpu, int *support, int *active, int * states); + -+/* AMD PSTATE enabling **************************/ ++/* AMD P-States stuff **************************/ ++extern bool cpupower_amd_pstate_enabled(void); + -+extern unsigned long cpupower_amd_pstate_enabled(unsigned int cpu); ++/* AMD P-States stuff **************************/ + /* * CPUID functions returning a single datum */ +@@ -168,6 +175,9 @@ static inline int cpufreq_has_boost_support(unsigned int cpu, int *support, + int *active, int * states) + { return -1; } + ++static inline bool cpupower_amd_pstate_enabled(void) ++{ return false; } ++ + /* cpuid and cpuinfo helpers **************************/ + + static inline unsigned int cpuid_eax(unsigned int op) { return 0; }; diff --git a/tools/power/cpupower/utils/helpers/misc.c b/tools/power/cpupower/utils/helpers/misc.c -index fc6e345117216..07d80775fb680 100644 +index fc6e34511721..0c483cdefcc2 100644 --- a/tools/power/cpupower/utils/helpers/misc.c +++ b/tools/power/cpupower/utils/helpers/misc.c -@@ -83,6 +83,26 @@ int cpupower_intel_set_perf_bias(unsigned int cpu, unsigned int val) +@@ -3,9 +3,11 @@ + #include <stdio.h> + #include <errno.h> + #include <stdlib.h> ++#include <string.h> + + #include "helpers/helpers.h" + #include "helpers/sysfs.h" ++#include "cpufreq.h" + + #if defined(__i386__) || defined(__x86_64__) + +@@ -83,6 +85,22 @@ int cpupower_intel_set_perf_bias(unsigned int cpu, unsigned int val) return 0; } - -+unsigned long cpupower_amd_pstate_enabled(unsigned int cpu) + ++bool cpupower_amd_pstate_enabled(void) +{ -+ char linebuf[MAX_LINE_LEN]; -+ char path[SYSFS_PATH_MAX]; -+ unsigned long val; -+ char *endp; ++ char *driver = cpufreq_get_driver(0); ++ bool ret = false; + -+ snprintf(path, sizeof(path), -+ PATH_TO_CPU "cpu%u/cpufreq/is_amd_pstate_enabled", cpu); ++ if (!driver) ++ return ret; + -+ if (cpupower_read_sysfs(path, linebuf, MAX_LINE_LEN) == 0) -+ return 0; ++ if (!strcmp(driver, "amd-pstate")) ++ ret = true; + -+ val = strtoul(linebuf, &endp, 0); -+ if (endp == linebuf || errno == ERANGE) -+ return 0; ++ cpufreq_put_driver(driver); + -+ return val; ++ return ret; +} + #endif /* #if defined(__i386__) || defined(__x86_64__) */ - + /* get_cpustate --- -cgit 1.2.3-1.el7 -From 9537cd2a2aa718faba5d61c1196d7b05c52a89f4 Mon Sep 17 00:00:00 2001 -From: Huang Rui <ray.huang@amd.com> -Date: Sun, 27 Jun 2021 22:40:14 +0800 -Subject: cpupower: initial AMD P-state capability -If kernel enables AMD P-state, cpupower won't need to respond ACPI -hardware P-states function anymore. + +If kernel starts the amd-pstate module, the cpupower will initial the +capability flag as CPUPOWER_CAP_AMD_PSTATE. And once amd-pstate +capability is set, it won't need to set legacy ACPI relative +capabilities anymore. Signed-off-by: Huang Rui <ray.huang@amd.com> --- @@ -1763,15 +1560,15 @@ Signed-off-by: Huang Rui <ray.huang@amd.com> 1 file changed, 13 insertions(+) diff --git a/tools/power/cpupower/utils/helpers/cpuid.c b/tools/power/cpupower/utils/helpers/cpuid.c -index 72eb435931803..78218c54acca9 100644 +index 72eb43593180..2a6dc104e76b 100644 --- a/tools/power/cpupower/utils/helpers/cpuid.c +++ b/tools/power/cpupower/utils/helpers/cpuid.c -@@ -149,6 +149,19 @@ out: +@@ -149,6 +149,19 @@ int get_cpu_info(struct cpupower_cpu_info *cpu_info) if (ext_cpuid_level >= 0x80000008 && cpuid_ebx(0x80000008) & (1 << 4)) cpu_info->caps |= CPUPOWER_CAP_AMD_RDPRU; + -+ if (cpupower_amd_pstate_enabled(0)) { ++ if (cpupower_amd_pstate_enabled()) { + cpu_info->caps |= CPUPOWER_CAP_AMD_PSTATE; + + /* @@ -1784,206 +1581,573 @@ index 72eb435931803..78218c54acca9 100644 + cpu_info->caps &= ~CPUPOWER_CAP_AMD_PSTATEDEF; + } } - + if (cpu_info->vendor == X86_VENDOR_INTEL) { --- -cgit 1.2.3-1.el7 -From d3f392c951479c73e5a4b0c8d94901aafd5b9da7 Mon Sep 17 00:00:00 2001 -From: Huang Rui <ray.huang@amd.com> -Date: Sun, 20 Jun 2021 17:07:25 +0800 -Subject: cpupower: add amd-pstate sysfs entries into libcpufreq -These amd-pstate sysfs entries will be used on cpupower for amd-pstate -kernel module. + +Expose the helper into cpufreq header, then cpufreq driver can use this +function to get the sysfs value if it has any specific sysfs interfaces. Signed-off-by: Huang Rui <ray.huang@amd.com> --- - tools/power/cpupower/lib/cpufreq.c | 18 +++++++++++++++++- - 1 file changed, 17 insertions(+), 1 deletion(-) + tools/power/cpupower/lib/cpufreq.c | 21 +++++++++++++++------ + tools/power/cpupower/lib/cpufreq.h | 12 ++++++++++++ + 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/tools/power/cpupower/lib/cpufreq.c b/tools/power/cpupower/lib/cpufreq.c -index c3b56db8b9214..3f92ddadaad26 100644 +index c3b56db8b921..02719cc400a1 100644 --- a/tools/power/cpupower/lib/cpufreq.c +++ b/tools/power/cpupower/lib/cpufreq.c -@@ -69,6 +69,14 @@ enum cpufreq_value { - SCALING_MIN_FREQ, - SCALING_MAX_FREQ, - STATS_NUM_TRANSITIONS, -+ AMD_PSTATE_HIGHEST_PERF, -+ AMD_PSTATE_NOMINAL_PERF, -+ AMD_PSTATE_LOWEST_NONLINEAR_PERF, -+ AMD_PSTATE_LOWEST_PERF, -+ AMD_PSTATE_MAX_FREQ, -+ AMD_PSTATE_NOMINAL_FREQ, -+ AMD_PSTATE_LOWEST_NONLINEAR_FREQ, -+ AMD_PSTATE_MIN_FREQ, - MAX_CPUFREQ_VALUE_READ_FILES +@@ -83,20 +83,21 @@ static const char *cpufreq_value_files[MAX_CPUFREQ_VALUE_READ_FILES] = { + [STATS_NUM_TRANSITIONS] = "stats/total_trans" }; + +- +-static unsigned long sysfs_cpufreq_get_one_value(unsigned int cpu, +- enum cpufreq_value which) ++unsigned long cpufreq_get_sysfs_value_from_table(unsigned int cpu, ++ const char **table, ++ unsigned index, ++ unsigned size) + { + unsigned long value; + unsigned int len; + char linebuf[MAX_LINE_LEN]; + char *endp; + +- if (which >= MAX_CPUFREQ_VALUE_READ_FILES) ++ if (!table && !table[index] && index >= size) + return 0; + +- len = sysfs_cpufreq_read_file(cpu, cpufreq_value_files[which], +- linebuf, sizeof(linebuf)); ++ len = sysfs_cpufreq_read_file(cpu, table[index], linebuf, ++ sizeof(linebuf)); + + if (len == 0) + return 0; +@@ -109,6 +110,14 @@ static unsigned long sysfs_cpufreq_get_one_value(unsigned int cpu, + return value; + } + ++static unsigned long sysfs_cpufreq_get_one_value(unsigned int cpu, ++ enum cpufreq_value which) ++{ ++ return cpufreq_get_sysfs_value_from_table(cpu, cpufreq_value_files, ++ which, ++ MAX_CPUFREQ_VALUE_READ_FILES); ++} ++ + /* read access to files which contain one string */ + + enum cpufreq_string { +diff --git a/tools/power/cpupower/lib/cpufreq.h b/tools/power/cpupower/lib/cpufreq.h +index 95f4fd9e2656..107668c0c454 100644 +--- a/tools/power/cpupower/lib/cpufreq.h ++++ b/tools/power/cpupower/lib/cpufreq.h +@@ -203,6 +203,18 @@ int cpufreq_modify_policy_governor(unsigned int cpu, char *governor); + int cpufreq_set_frequency(unsigned int cpu, + unsigned long target_frequency); + ++/* ++ * get the sysfs value from specific table ++ * ++ * Read the value with the sysfs file name from specific table. Does ++ * only work if the cpufreq driver has the specific sysfs interfaces. ++ */ ++ ++unsigned long cpufreq_get_sysfs_value_from_table(unsigned int cpu, ++ const char **table, ++ unsigned index, ++ unsigned size); ++ + #ifdef __cplusplus + } + #endif -@@ -80,7 +88,15 @@ static const char *cpufreq_value_files[MAX_CPUFREQ_VALUE_READ_FILES] = { - [SCALING_CUR_FREQ] = "scaling_cur_freq", - [SCALING_MIN_FREQ] = "scaling_min_freq", - [SCALING_MAX_FREQ] = "scaling_max_freq", -- [STATS_NUM_TRANSITIONS] = "stats/total_trans" -+ [STATS_NUM_TRANSITIONS] = "stats/total_trans", -+ [AMD_PSTATE_HIGHEST_PERF] = "amd_pstate_highest_perf", -+ [AMD_PSTATE_NOMINAL_PERF] = "amd_pstate_nominal_perf", -+ [AMD_PSTATE_LOWEST_NONLINEAR_PERF] = "amd_pstate_lowest_nonlinear_perf", -+ [AMD_PSTATE_LOWEST_PERF] = "amd_pstate_lowest_perf", -+ [AMD_PSTATE_MAX_FREQ] = "amd_pstate_max_freq", -+ [AMD_PSTATE_NOMINAL_FREQ] = "amd_pstate_nominal_freq", -+ [AMD_PSTATE_LOWEST_NONLINEAR_FREQ] = "amd_pstate_lowest_nonlinear_freq", -+ [AMD_PSTATE_MIN_FREQ] = "amd_pstate_min_freq" - }; --- -cgit 1.2.3-1.el7 +Kernel ACPI subsytem introduced the sysfs attributes for acpi cppc +library in below path: -From c7249e524ce793bfe0575f45a0f8245f51b02af7 Mon Sep 17 00:00:00 2001 -From: Huang Rui <ray.huang@amd.com> -Date: Sun, 20 Jun 2021 17:35:45 +0800 -Subject: cpupower: enable boost state support for amd-pstate module +/sys/devices/system/cpu/cpuX/acpi_cppc/ -The AMD P-state boost API is different from ACPI hardware P-states, so -implement the support for amd-pstate kernel module. +And these attributes will be used for amd-pstate driver to provide some +performance and frequency values. Signed-off-by: Huang Rui <ray.huang@amd.com> --- - tools/power/cpupower/lib/cpufreq.c | 20 ++++++++++++++++++++ - tools/power/cpupower/lib/cpufreq.h | 3 +++ - tools/power/cpupower/utils/helpers/misc.c | 7 +++++++ - 3 files changed, 30 insertions(+) + tools/power/cpupower/Makefile | 6 +-- + tools/power/cpupower/lib/acpi_cppc.c | 59 ++++++++++++++++++++++++++++ + tools/power/cpupower/lib/acpi_cppc.h | 21 ++++++++++ + 3 files changed, 83 insertions(+), 3 deletions(-) + create mode 100644 tools/power/cpupower/lib/acpi_cppc.c + create mode 100644 tools/power/cpupower/lib/acpi_cppc.h + +diff --git a/tools/power/cpupower/Makefile b/tools/power/cpupower/Makefile +index 3b1594447f29..e9b6de314654 100644 +--- a/tools/power/cpupower/Makefile ++++ b/tools/power/cpupower/Makefile +@@ -143,9 +143,9 @@ UTIL_HEADERS = utils/helpers/helpers.h utils/idle_monitor/cpupower-monitor.h \ + utils/helpers/bitmask.h \ + utils/idle_monitor/idle_monitors.h utils/idle_monitor/idle_monitors.def + +-LIB_HEADERS = lib/cpufreq.h lib/cpupower.h lib/cpuidle.h +-LIB_SRC = lib/cpufreq.c lib/cpupower.c lib/cpuidle.c +-LIB_OBJS = lib/cpufreq.o lib/cpupower.o lib/cpuidle.o ++LIB_HEADERS = lib/cpufreq.h lib/cpupower.h lib/cpuidle.h lib/acpi_cppc.h ++LIB_SRC = lib/cpufreq.c lib/cpupower.c lib/cpuidle.c lib/acpi_cppc.c ++LIB_OBJS = lib/cpufreq.o lib/cpupower.o lib/cpuidle.o lib/acpi_cppc.o + LIB_OBJS := $(addprefix $(OUTPUT),$(LIB_OBJS)) + + override CFLAGS += -pipe +diff --git a/tools/power/cpupower/lib/acpi_cppc.c b/tools/power/cpupower/lib/acpi_cppc.c +new file mode 100644 +index 000000000000..a07a8922eca2 +--- /dev/null ++++ b/tools/power/cpupower/lib/acpi_cppc.c +@@ -0,0 +1,59 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++ ++#include <stdio.h> ++#include <errno.h> ++#include <stdlib.h> ++#include <string.h> ++#include <sys/types.h> ++#include <sys/stat.h> ++#include <fcntl.h> ++#include <unistd.h> ++ ++#include "cpupower_intern.h" ++#include "acpi_cppc.h" ++ ++/* ACPI CPPC sysfs access ***********************************************/ ++ ++static int acpi_cppc_read_file(unsigned int cpu, const char *fname, ++ char *buf, size_t buflen) ++{ ++ char path[SYSFS_PATH_MAX]; ++ ++ snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/acpi_cppc/%s", ++ cpu, fname); ++ return cpupower_read_sysfs(path, buf, buflen); ++} ++ ++static const char *acpi_cppc_value_files[] = { ++ [HIGHEST_PERF] = "highest_perf", ++ [LOWEST_PERF] = "lowest_perf", ++ [NOMINAL_PERF] = "nominal_perf", ++ [LOWEST_NONLINEAR_PERF] = "lowest_nonlinear_perf", ++ [LOWEST_FREQ] = "lowest_freq", ++ [NOMINAL_FREQ] = "nominal_freq", ++ [REFERENCE_PERF] = "reference_perf", ++ [WRAPAROUND_TIME] = "wraparound_time" ++}; ++ ++unsigned long acpi_cppc_get_data(unsigned cpu, enum acpi_cppc_value which) ++{ ++ unsigned long long value; ++ unsigned int len; ++ char linebuf[MAX_LINE_LEN]; ++ char *endp; ++ ++ if (which >= MAX_CPPC_VALUE_FILES) ++ return 0; ++ ++ len = acpi_cppc_read_file(cpu, acpi_cppc_value_files[which], ++ linebuf, sizeof(linebuf)); ++ if (len == 0) ++ return 0; ++ ++ value = strtoull(linebuf, &endp, 0); ++ ++ if (endp == linebuf || errno == ERANGE) ++ return 0; ++ ++ return value; ++} +diff --git a/tools/power/cpupower/lib/acpi_cppc.h b/tools/power/cpupower/lib/acpi_cppc.h +new file mode 100644 +index 000000000000..576291155224 +--- /dev/null ++++ b/tools/power/cpupower/lib/acpi_cppc.h +@@ -0,0 +1,21 @@ ++/* SPDX-License-Identifier: GPL-2.0-only */ ++ ++#ifndef __ACPI_CPPC_H__ ++#define __ACPI_CPPC_H__ ++ ++enum acpi_cppc_value { ++ HIGHEST_PERF, ++ LOWEST_PERF, ++ NOMINAL_PERF, ++ LOWEST_NONLINEAR_PERF, ++ LOWEST_FREQ, ++ NOMINAL_FREQ, ++ REFERENCE_PERF, ++ WRAPAROUND_TIME, ++ MAX_CPPC_VALUE_FILES ++}; ++ ++extern unsigned long acpi_cppc_get_data(unsigned cpu, ++ enum acpi_cppc_value which); ++ ++#endif /* _ACPI_CPPC_H */ -diff --git a/tools/power/cpupower/lib/cpufreq.c b/tools/power/cpupower/lib/cpufreq.c -index 3f92ddadaad26..37da87bdcfb1c 100644 ---- a/tools/power/cpupower/lib/cpufreq.c -+++ b/tools/power/cpupower/lib/cpufreq.c -@@ -790,3 +790,23 @@ unsigned long cpufreq_get_transitions(unsigned int cpu) - { - return sysfs_cpufreq_get_one_value(cpu, STATS_NUM_TRANSITIONS); + + +Introduce the marco definitions and access helper function for +amd-pstate sysfs interfaces such as each performance goals and frequency +levels in amd helper file. They will be used to read the sysfs attribute +from amd-pstate cpufreq driver for cpupower utilities. + +Signed-off-by: Huang Rui <ray.huang@amd.com> +--- + tools/power/cpupower/utils/helpers/amd.c | 30 ++++++++++++++++++++++++ + 1 file changed, 30 insertions(+) + +diff --git a/tools/power/cpupower/utils/helpers/amd.c b/tools/power/cpupower/utils/helpers/amd.c +index 97f2c857048e..14c658daba4b 100644 +--- a/tools/power/cpupower/utils/helpers/amd.c ++++ b/tools/power/cpupower/utils/helpers/amd.c +@@ -8,7 +8,10 @@ + #include <pci/pci.h> + + #include "helpers/helpers.h" ++#include "cpufreq.h" ++#include "acpi_cppc.h" + ++/* ACPI P-States Helper Functions for AMD Processors ***************/ + #define MSR_AMD_PSTATE_STATUS 0xc0010063 + #define MSR_AMD_PSTATE 0xc0010064 + #define MSR_AMD_PSTATE_LIMIT 0xc0010061 +@@ -146,4 +149,31 @@ int amd_pci_get_num_boost_states(int *active, int *states) + pci_cleanup(pci_acc); + return 0; } + -+int amd_pstate_boost_support(unsigned int cpu) -+{ -+ unsigned int highest_perf, nominal_perf; ++/* ACPI P-States Helper Functions for AMD Processors ***************/ + -+ highest_perf = sysfs_cpufreq_get_one_value(cpu, AMD_PSTATE_HIGHEST_PERF); -+ nominal_perf = sysfs_cpufreq_get_one_value(cpu, AMD_PSTATE_NOMINAL_PERF); ++/* AMD P-States Helper Functions ***************/ ++enum amd_pstate_value { ++ AMD_PSTATE_HIGHEST_PERF, ++ AMD_PSTATE_MAX_FREQ, ++ AMD_PSTATE_LOWEST_NONLINEAR_FREQ, ++ MAX_AMD_PSTATE_VALUE_READ_FILES, ++}; + -+ return highest_perf > nominal_perf ? 1 : 0; ++static const char *amd_pstate_value_files[MAX_AMD_PSTATE_VALUE_READ_FILES] = { ++ [AMD_PSTATE_HIGHEST_PERF] = "amd_pstate_highest_perf", ++ [AMD_PSTATE_MAX_FREQ] = "amd_pstate_max_freq", ++ [AMD_PSTATE_LOWEST_NONLINEAR_FREQ] = "amd_pstate_lowest_nonlinear_freq", ++}; ++ ++static unsigned long amd_pstate_get_data(unsigned int cpu, ++ enum amd_pstate_value value) ++{ ++ return cpufreq_get_sysfs_value_from_table(cpu, ++ amd_pstate_value_files, ++ value, ++ MAX_AMD_PSTATE_VALUE_READ_FILES); +} + -+int amd_pstate_boost_enabled(unsigned int cpu) ++/* AMD P-States Helper Functions ***************/ + #endif /* defined(__i386__) || defined(__x86_64__) */ + + + +The legacy ACPI hardware P-States function has 3 P-States on ACPI table, +the CPU frequency only can be switched between the 3 P-States. While the +processor supports the boost state, it will have another boost state +that the frequency can be higher than P0 state, and the state can be +decoded by the function of decode_pstates() and read by +amd_pci_get_num_boost_states(). + +However, the new AMD P-States function is different than legacy ACPI +hardware P-State on AMD processors. That has a finer grain frequency +range between the highest and lowest frequency. And boost frequency is +actually the frequency which is mapped on highest performance ratio. The +similiar previous P0 frequency is mapped on nominal performance ratio. +If the highest performance on the processor is higher than nominal +performance, then we think the current processor supports the boost +state. And it uses amd_pstate_boost_init() to initialize boost for AMD +P-States function. + +Signed-off-by: Huang Rui <ray.huang@amd.com> +--- + tools/power/cpupower/utils/helpers/amd.c | 18 ++++++++++++++++++ + tools/power/cpupower/utils/helpers/helpers.h | 5 +++++ + tools/power/cpupower/utils/helpers/misc.c | 2 ++ + 3 files changed, 25 insertions(+) + +diff --git a/tools/power/cpupower/utils/helpers/amd.c b/tools/power/cpupower/utils/helpers/amd.c +index 14c658daba4b..bde6065cabf4 100644 +--- a/tools/power/cpupower/utils/helpers/amd.c ++++ b/tools/power/cpupower/utils/helpers/amd.c +@@ -175,5 +175,23 @@ static unsigned long amd_pstate_get_data(unsigned int cpu, + MAX_AMD_PSTATE_VALUE_READ_FILES); + } + ++void amd_pstate_boost_init(unsigned int cpu, int *support, int *active) +{ -+ unsigned int cpuinfo_max, amd_pstate_max; ++ unsigned long highest_perf, nominal_perf, cpuinfo_min, ++ cpuinfo_max, amd_pstate_max; ++ ++ highest_perf = amd_pstate_get_data(cpu, AMD_PSTATE_HIGHEST_PERF); ++ nominal_perf = acpi_cppc_get_data(cpu, NOMINAL_PERF); ++ ++ *support = highest_perf > nominal_perf ? 1 : 0; ++ if (!(*support)) ++ return; + -+ cpuinfo_max = sysfs_cpufreq_get_one_value(cpu, CPUINFO_MAX_FREQ); -+ amd_pstate_max = sysfs_cpufreq_get_one_value(cpu, AMD_PSTATE_MAX_FREQ); ++ cpufreq_get_hardware_limits(cpu, &cpuinfo_min, &cpuinfo_max); ++ amd_pstate_max = amd_pstate_get_data(cpu, AMD_PSTATE_MAX_FREQ); + -+ return cpuinfo_max == amd_pstate_max ? 1 : 0; ++ *active = cpuinfo_max == amd_pstate_max ? 1 : 0; +} -diff --git a/tools/power/cpupower/lib/cpufreq.h b/tools/power/cpupower/lib/cpufreq.h -index 95f4fd9e2656c..d54d02a7a4f44 100644 ---- a/tools/power/cpupower/lib/cpufreq.h -+++ b/tools/power/cpupower/lib/cpufreq.h -@@ -203,6 +203,9 @@ int cpufreq_modify_policy_governor(unsigned int cpu, char *governor); - int cpufreq_set_frequency(unsigned int cpu, - unsigned long target_frequency); - -+int amd_pstate_boost_support(unsigned int cpu); -+int amd_pstate_boost_enabled(unsigned int cpu); + - #ifdef __cplusplus - } - #endif + /* AMD P-States Helper Functions ***************/ + #endif /* defined(__i386__) || defined(__x86_64__) */ +diff --git a/tools/power/cpupower/utils/helpers/helpers.h b/tools/power/cpupower/utils/helpers/helpers.h +index e03cc97297aa..c03925bea655 100644 +--- a/tools/power/cpupower/utils/helpers/helpers.h ++++ b/tools/power/cpupower/utils/helpers/helpers.h +@@ -140,6 +140,8 @@ extern int cpufreq_has_boost_support(unsigned int cpu, int *support, + + /* AMD P-States stuff **************************/ + extern bool cpupower_amd_pstate_enabled(void); ++extern void amd_pstate_boost_init(unsigned int cpu, ++ int *support, int *active); + + /* AMD P-States stuff **************************/ + +@@ -177,6 +179,9 @@ static inline int cpufreq_has_boost_support(unsigned int cpu, int *support, + + static inline bool cpupower_amd_pstate_enabled(void) + { return false; } ++static void amd_pstate_boost_init(unsigned int cpu, ++ int *support, int *active) ++{ return; } + + /* cpuid and cpuinfo helpers **************************/ + diff --git a/tools/power/cpupower/utils/helpers/misc.c b/tools/power/cpupower/utils/helpers/misc.c -index 07d80775fb680..aba9793207600 100644 +index 0c483cdefcc2..e0d3145434d3 100644 --- a/tools/power/cpupower/utils/helpers/misc.c +++ b/tools/power/cpupower/utils/helpers/misc.c -@@ -10,6 +10,7 @@ - #if defined(__i386__) || defined(__x86_64__) - - #include "cpupower_intern.h" -+#include "cpufreq.h" - - #define MSR_AMD_HWCR 0xc0010015 - -@@ -39,6 +40,12 @@ int cpufreq_has_boost_support(unsigned int cpu, int *support, int *active, +@@ -41,6 +41,8 @@ int cpufreq_has_boost_support(unsigned int cpu, int *support, int *active, if (ret) return ret; } -+ } if ((cpupower_cpu_info.caps & CPUPOWER_CAP_AMD_PSTATE) && -+ amd_pstate_boost_support(cpu)) { -+ *support = 1; -+ -+ if (amd_pstate_boost_enabled(cpu)) -+ *active = 1; ++ } else if (cpupower_cpu_info.caps & CPUPOWER_CAP_AMD_PSTATE) { ++ amd_pstate_boost_init(cpu, support, active); } else if (cpupower_cpu_info.caps & CPUPOWER_CAP_INTEL_IDA) *support = *active = 1; return 0; --- -cgit 1.2.3-1.el7 -From cf79733de00a260c6d3e5038f00cdb91a71df9af Mon Sep 17 00:00:00 2001 -From: Huang Rui <ray.huang@amd.com> -Date: Sun, 20 Jun 2021 18:25:55 +0800 -Subject: cpupower: add amd-pstate get data function to query the info -Frequency-info needs an interface to query the current amd-pstate data. + +The print_speed can be as a common function, and expose it into misc +helper header. Then it can be used on other helper files as well. Signed-off-by: Huang Rui <ray.huang@amd.com> --- - tools/power/cpupower/lib/cpufreq.c | 6 ++++++ - tools/power/cpupower/lib/cpufreq.h | 13 +++++++++++++ - 2 files changed, 19 insertions(+) + tools/power/cpupower/utils/cpufreq-info.c | 59 ++++---------------- + tools/power/cpupower/utils/helpers/helpers.h | 1 + + tools/power/cpupower/utils/helpers/misc.c | 42 ++++++++++++++ + 3 files changed, 54 insertions(+), 48 deletions(-) -diff --git a/tools/power/cpupower/lib/cpufreq.c b/tools/power/cpupower/lib/cpufreq.c -index 37da87bdcfb1c..1443080868da3 100644 ---- a/tools/power/cpupower/lib/cpufreq.c -+++ b/tools/power/cpupower/lib/cpufreq.c -@@ -810,3 +810,9 @@ int amd_pstate_boost_enabled(unsigned int cpu) - - return cpuinfo_max == amd_pstate_max ? 1 : 0; +diff --git a/tools/power/cpupower/utils/cpufreq-info.c b/tools/power/cpupower/utils/cpufreq-info.c +index f9895e31ff5a..b429454bf3ae 100644 +--- a/tools/power/cpupower/utils/cpufreq-info.c ++++ b/tools/power/cpupower/utils/cpufreq-info.c +@@ -84,43 +84,6 @@ static void proc_cpufreq_output(void) + } + + static int no_rounding; +-static void print_speed(unsigned long speed) +-{ +- unsigned long tmp; +- +- if (no_rounding) { +- if (speed > 1000000) +- printf("%u.%06u GHz", ((unsigned int) speed/1000000), +- ((unsigned int) speed%1000000)); +- else if (speed > 1000) +- printf("%u.%03u MHz", ((unsigned int) speed/1000), +- (unsigned int) (speed%1000)); +- else +- printf("%lu kHz", speed); +- } else { +- if (speed > 1000000) { +- tmp = speed%10000; +- if (tmp >= 5000) +- speed += 10000; +- printf("%u.%02u GHz", ((unsigned int) speed/1000000), +- ((unsigned int) (speed%1000000)/10000)); +- } else if (speed > 100000) { +- tmp = speed%1000; +- if (tmp >= 500) +- speed += 1000; +- printf("%u MHz", ((unsigned int) speed/1000)); +- } else if (speed > 1000) { +- tmp = speed%100; +- if (tmp >= 50) +- speed += 100; +- printf("%u.%01u MHz", ((unsigned int) speed/1000), +- ((unsigned int) (speed%1000)/100)); +- } +- } +- +- return; +-} +- + static void print_duration(unsigned long duration) + { + unsigned long tmp; +@@ -254,11 +217,11 @@ static int get_boost_mode(unsigned int cpu) + if (freqs) { + printf(_(" boost frequency steps: ")); + while (freqs->next) { +- print_speed(freqs->frequency); ++ print_speed(freqs->frequency, no_rounding); + printf(", "); + freqs = freqs->next; + } +- print_speed(freqs->frequency); ++ print_speed(freqs->frequency, no_rounding); + printf("\n"); + cpufreq_put_available_frequencies(freqs); + } +@@ -277,7 +240,7 @@ static int get_freq_kernel(unsigned int cpu, unsigned int human) + return -EINVAL; + } + if (human) { +- print_speed(freq); ++ print_speed(freq, no_rounding); + } else + printf("%lu", freq); + printf(_(" (asserted by call to kernel)\n")); +@@ -296,7 +259,7 @@ static int get_freq_hardware(unsigned int cpu, unsigned int human) + return -EINVAL; + } + if (human) { +- print_speed(freq); ++ print_speed(freq, no_rounding); + } else + printf("%lu", freq); + printf(_(" (asserted by call to hardware)\n")); +@@ -316,9 +279,9 @@ static int get_hardware_limits(unsigned int cpu, unsigned int human) + + if (human) { + printf(_(" hardware limits: ")); +- print_speed(min); ++ print_speed(min, no_rounding); + printf(" - "); +- print_speed(max); ++ print_speed(max, no_rounding); + printf("\n"); + } else { + printf("%lu %lu\n", min, max); +@@ -350,9 +313,9 @@ static int get_policy(unsigned int cpu) + return -EINVAL; + } + printf(_(" current policy: frequency should be within ")); +- print_speed(policy->min); ++ print_speed(policy->min, no_rounding); + printf(_(" and ")); +- print_speed(policy->max); ++ print_speed(policy->max, no_rounding); + + printf(".\n "); + printf(_("The governor \"%s\" may decide which speed to use\n" +@@ -436,7 +399,7 @@ static int get_freq_stats(unsigned int cpu, unsigned int human) + struct cpufreq_stats *stats = cpufreq_get_stats(cpu, &total_time); + while (stats) { + if (human) { +- print_speed(stats->frequency); ++ print_speed(stats->frequency, no_rounding); + printf(":%.2f%%", + (100.0 * stats->time_in_state) / total_time); + } else +@@ -486,11 +449,11 @@ static void debug_output_one(unsigned int cpu) + if (freqs) { + printf(_(" available frequency steps: ")); + while (freqs->next) { +- print_speed(freqs->frequency); ++ print_speed(freqs->frequency, no_rounding); + printf(", "); + freqs = freqs->next; + } +- print_speed(freqs->frequency); ++ print_speed(freqs->frequency, no_rounding); + printf("\n"); + cpufreq_put_available_frequencies(freqs); + } +diff --git a/tools/power/cpupower/utils/helpers/helpers.h b/tools/power/cpupower/utils/helpers/helpers.h +index c03925bea655..fbbfa6047c83 100644 +--- a/tools/power/cpupower/utils/helpers/helpers.h ++++ b/tools/power/cpupower/utils/helpers/helpers.h +@@ -200,5 +200,6 @@ extern struct bitmask *offline_cpus; + void get_cpustate(void); + void print_online_cpus(void); + void print_offline_cpus(void); ++void print_speed(unsigned long speed, int no_rounding); + + #endif /* __CPUPOWERUTILS_HELPERS__ */ +diff --git a/tools/power/cpupower/utils/helpers/misc.c b/tools/power/cpupower/utils/helpers/misc.c +index e0d3145434d3..d693c96cd09c 100644 +--- a/tools/power/cpupower/utils/helpers/misc.c ++++ b/tools/power/cpupower/utils/helpers/misc.c +@@ -164,3 +164,45 @@ void print_offline_cpus(void) + printf(_("cpupower set operation was not performed on them\n")); + } } + -+unsigned amd_pstate_get_data(unsigned int cpu, enum amd_pstate_param param) ++/* ++ * print_speed ++ * ++ * Print the exact CPU frequency with appropriate unit ++ */ ++void print_speed(unsigned long speed, int no_rounding) +{ -+ return sysfs_cpufreq_get_one_value(cpu, -+ param + AMD_PSTATE_HIGHEST_PERF); ++ unsigned long tmp; ++ ++ if (no_rounding) { ++ if (speed > 1000000) ++ printf("%u.%06u GHz", ((unsigned int) speed/1000000), ++ ((unsigned int) speed%1000000)); ++ else if (speed > 1000) ++ printf("%u.%03u MHz", ((unsigned int) speed/1000), ++ (unsigned int) (speed%1000)); ++ else ++ printf("%lu kHz", speed); ++ } else { ++ if (speed > 1000000) { ++ tmp = speed%10000; ++ if (tmp >= 5000) ++ speed += 10000; ++ printf("%u.%02u GHz", ((unsigned int) speed/1000000), ++ ((unsigned int) (speed%1000000)/10000)); ++ } else if (speed > 100000) { ++ tmp = speed%1000; ++ if (tmp >= 500) ++ speed += 1000; ++ printf("%u MHz", ((unsigned int) speed/1000)); ++ } else if (speed > 1000) { ++ tmp = speed%100; ++ if (tmp >= 50) ++ speed += 100; ++ printf("%u.%01u MHz", ((unsigned int) speed/1000), ++ ((unsigned int) (speed%1000)/100)); ++ } ++ } ++ ++ return; +} -diff --git a/tools/power/cpupower/lib/cpufreq.h b/tools/power/cpupower/lib/cpufreq.h -index d54d02a7a4f44..954e72704fc07 100644 ---- a/tools/power/cpupower/lib/cpufreq.h -+++ b/tools/power/cpupower/lib/cpufreq.h -@@ -206,6 +206,19 @@ int cpufreq_set_frequency(unsigned int cpu, - int amd_pstate_boost_support(unsigned int cpu); - int amd_pstate_boost_enabled(unsigned int cpu); -+enum amd_pstate_param { -+ HIGHEST_PERF, -+ NOMINAL_PERF, -+ LOWEST_NONLINEAR_PERF, -+ LOWEST_PERF, -+ MAX_FREQ, -+ NOMINAL_FREQ, -+ LOWEST_NONLINEAR_FREQ, -+ MIN_FREQ, -+}; -+ -+unsigned amd_pstate_get_data(unsigned int cpu, enum amd_pstate_param param); -+ - #ifdef __cplusplus - } - #endif --- -cgit 1.2.3-1.el7 -From 573a0ff1add6bb6df585d6535abaaa0e1afc61c9 Mon Sep 17 00:00:00 2001 -From: Huang Rui <ray.huang@amd.com> -Date: Thu, 10 Jun 2021 23:48:03 +0800 -Subject: cpupower: print amd-pstate information on cpupower amd-pstate kernel module is using the fine grain frequency instead of acpi hardware pstate. So the performance and frequency values should be @@ -1991,70 +2155,110 @@ printed in frequency-info. Signed-off-by: Huang Rui <ray.huang@amd.com> --- - tools/power/cpupower/utils/cpufreq-info.c | 27 ++++++++++++++++++++++++--- - 1 file changed, 24 insertions(+), 3 deletions(-) + tools/power/cpupower/utils/cpufreq-info.c | 9 ++++--- + tools/power/cpupower/utils/helpers/amd.c | 28 ++++++++++++++++++++ + tools/power/cpupower/utils/helpers/helpers.h | 5 ++++ + 3 files changed, 39 insertions(+), 3 deletions(-) diff --git a/tools/power/cpupower/utils/cpufreq-info.c b/tools/power/cpupower/utils/cpufreq-info.c -index f9895e31ff5ae..9eabed209adcb 100644 +index b429454bf3ae..f828f3c35a6f 100644 --- a/tools/power/cpupower/utils/cpufreq-info.c +++ b/tools/power/cpupower/utils/cpufreq-info.c -@@ -183,9 +183,30 @@ static int get_boost_mode_x86(unsigned int cpu) +@@ -146,9 +146,12 @@ static int get_boost_mode_x86(unsigned int cpu) printf(_(" Supported: %s\n"), support ? _("yes") : _("no")); printf(_(" Active: %s\n"), active ? _("yes") : _("no")); - + - if ((cpupower_cpu_info.vendor == X86_VENDOR_AMD && - cpupower_cpu_info.family >= 0x10) || - cpupower_cpu_info.vendor == X86_VENDOR_HYGON) { + if (cpupower_cpu_info.vendor == X86_VENDOR_AMD && + cpupower_cpu_info.caps & CPUPOWER_CAP_AMD_PSTATE) { -+ printf(_(" AMD PSTATE Highest Performance: %u. Maximum Frequency: "), -+ amd_pstate_get_data(cpu, HIGHEST_PERF)); -+ print_speed(amd_pstate_get_data(cpu, MAX_FREQ)); -+ printf(".\n"); -+ -+ printf(_(" AMD PSTATE Nominal Performance: %u. Nominal Frequency: "), -+ amd_pstate_get_data(cpu, NOMINAL_PERF)); -+ print_speed(amd_pstate_get_data(cpu, NOMINAL_FREQ)); -+ printf(".\n"); -+ -+ printf(_(" AMD PSTATE Lowest Non-linear Performance: %u. Lowest Non-linear Frequency: "), -+ amd_pstate_get_data(cpu, LOWEST_NONLINEAR_PERF)); -+ print_speed(amd_pstate_get_data(cpu, LOWEST_NONLINEAR_FREQ)); -+ printf(".\n"); -+ -+ printf(_(" AMD PSTATE Lowest Performance: %u. Lowest Frequency: "), -+ amd_pstate_get_data(cpu, LOWEST_PERF)); -+ print_speed(amd_pstate_get_data(cpu, MIN_FREQ)); -+ printf(".\n"); ++ amd_pstate_show_perf_and_freq(cpu, no_rounding); + } else if ((cpupower_cpu_info.vendor == X86_VENDOR_AMD && + cpupower_cpu_info.family >= 0x10) || + cpupower_cpu_info.vendor == X86_VENDOR_HYGON) { ret = decode_pstates(cpu, b_states, pstates, &pstate_no); if (ret) return ret; --- -cgit 1.2.3-1.el7 +diff --git a/tools/power/cpupower/utils/helpers/amd.c b/tools/power/cpupower/utils/helpers/amd.c +index bde6065cabf4..a1115891d76d 100644 +--- a/tools/power/cpupower/utils/helpers/amd.c ++++ b/tools/power/cpupower/utils/helpers/amd.c +@@ -193,5 +193,33 @@ void amd_pstate_boost_init(unsigned int cpu, int *support, int *active) + *active = cpuinfo_max == amd_pstate_max ? 1 : 0; + } + ++void amd_pstate_show_perf_and_freq(unsigned int cpu, int no_rounding) ++{ ++ printf(_(" AMD PSTATE Highest Performance: %lu. Maximum Frequency: "), ++ amd_pstate_get_data(cpu, AMD_PSTATE_HIGHEST_PERF)); ++ /* If boost isn't active, the cpuinfo_max doesn't indicate real max ++ * frequency. So we read it back from amd-pstate sysfs entry. ++ */ ++ print_speed(amd_pstate_get_data(cpu, AMD_PSTATE_MAX_FREQ), no_rounding); ++ printf(".\n"); ++ ++ printf(_(" AMD PSTATE Nominal Performance: %lu. Nominal Frequency: "), ++ acpi_cppc_get_data(cpu, NOMINAL_PERF)); ++ print_speed(acpi_cppc_get_data(cpu, NOMINAL_FREQ) * 1000, ++ no_rounding); ++ printf(".\n"); ++ ++ printf(_(" AMD PSTATE Lowest Non-linear Performance: %lu. Lowest Non-linear Frequency: "), ++ acpi_cppc_get_data(cpu, LOWEST_NONLINEAR_PERF)); ++ print_speed(amd_pstate_get_data(cpu, AMD_PSTATE_LOWEST_NONLINEAR_FREQ), ++ no_rounding); ++ printf(".\n"); ++ ++ printf(_(" AMD PSTATE Lowest Performance: %lu. Lowest Frequency: "), ++ acpi_cppc_get_data(cpu, LOWEST_PERF)); ++ print_speed(acpi_cppc_get_data(cpu, LOWEST_FREQ) * 1000, no_rounding); ++ printf(".\n"); ++} ++ + /* AMD P-States Helper Functions ***************/ + #endif /* defined(__i386__) || defined(__x86_64__) */ +diff --git a/tools/power/cpupower/utils/helpers/helpers.h b/tools/power/cpupower/utils/helpers/helpers.h +index fbbfa6047c83..5f6862502dbf 100644 +--- a/tools/power/cpupower/utils/helpers/helpers.h ++++ b/tools/power/cpupower/utils/helpers/helpers.h +@@ -142,6 +142,8 @@ extern int cpufreq_has_boost_support(unsigned int cpu, int *support, + extern bool cpupower_amd_pstate_enabled(void); + extern void amd_pstate_boost_init(unsigned int cpu, + int *support, int *active); ++extern void amd_pstate_show_perf_and_freq(unsigned int cpu, ++ int no_rounding); + + /* AMD P-States stuff **************************/ + +@@ -182,6 +184,9 @@ static inline bool cpupower_amd_pstate_enabled(void) + static void amd_pstate_boost_init(unsigned int cpu, + int *support, int *active) + { return; } ++static inline void amd_pstate_show_perf_and_freq(unsigned int cpu, ++ int no_rounding) ++{ return; } + + /* cpuid and cpuinfo helpers **************************/ + + -From abfcbc164c1aa0c63d5e256854bad977a9645586 Mon Sep 17 00:00:00 2001 -From: Huang Rui <ray.huang@amd.com> -Date: Thu, 10 Jun 2021 23:40:18 +0800 -Subject: Documentation: amd-pstate: add amd-pstate driver introduction Introduce the amd-pstate driver design and implementation. Signed-off-by: Huang Rui <ray.huang@amd.com> --- - Documentation/admin-guide/pm/amd_pstate.rst | 377 +++++++++++++++++++++++++ - Documentation/admin-guide/pm/working-state.rst | 1 + - 2 files changed, 378 insertions(+) - create mode 100644 Documentation/admin-guide/pm/amd_pstate.rst + Documentation/admin-guide/pm/amd-pstate.rst | 373 ++++++++++++++++++ + .../admin-guide/pm/working-state.rst | 1 + + 2 files changed, 374 insertions(+) + create mode 100644 Documentation/admin-guide/pm/amd-pstate.rst -diff --git a/Documentation/admin-guide/pm/amd_pstate.rst b/Documentation/admin-guide/pm/amd_pstate.rst +diff --git a/Documentation/admin-guide/pm/amd-pstate.rst b/Documentation/admin-guide/pm/amd-pstate.rst new file mode 100644 -index 0000000000000..c3659dde0cee8 +index 000000000000..24a88476fc69 --- /dev/null -+++ b/Documentation/admin-guide/pm/amd_pstate.rst -@@ -0,0 +1,377 @@ ++++ b/Documentation/admin-guide/pm/amd-pstate.rst +@@ -0,0 +1,373 @@ +.. SPDX-License-Identifier: GPL-2.0 +.. include:: <isonum.txt> + @@ -2252,8 +2456,8 @@ index 0000000000000..c3659dde0cee8 + +There are two types of hardware implementations for ``amd-pstate``: one is +`Full MSR Support <perf_cap_>`_ and another is `Shared Memory Support -+<perf_cap_>`_. It can use :c:macro:`X86_FEATURE_AMD_CPPC_EXT` feature flag -+(for details refer to Processor Programming Reference (PPR) for AMD Family ++<perf_cap_>`_. It can use :c:macro:`X86_FEATURE_CPPC` feature flag (for ++details refer to Processor Programming Reference (PPR) for AMD Family +19h Model 21h, Revision B0 Processors [3]_) to indicate the different +types. ``amd-pstate`` is to register different ``amd_pstate_perf_funcs`` +instances for different hardware implementations. @@ -2265,7 +2469,7 @@ index 0000000000000..c3659dde0cee8 +----------------- + +Some new Zen3 processors such as Cezanne provide the MSR registers directly -+while the :c:macro:`X86_FEATURE_AMD_CPPC_EXT` CPU feature flag is set. ++while the :c:macro:`X86_FEATURE_CPPC` CPU feature flag is set. +``amd-pstate`` can handle the MSR register to implement the fast switch +function in ``CPUFreq`` that can shrink latency of frequency control on the +interrupt context. @@ -2273,10 +2477,10 @@ index 0000000000000..c3659dde0cee8 +Shared Memory Support +---------------------- + -+If :c:macro:`X86_FEATURE_AMD_CPPC_EXT` CPU feature flag is not set, that -+means the processor supports shared memory solution. In this case, -+``amd-pstate`` uses the ``cppc_acpi`` helper methods to implement the -+callback functions of ``amd_pstate_perf_funcs``. ++If :c:macro:`X86_FEATURE_CPPC` CPU feature flag is not set, that means the ++processor supports shared memory solution. In this case, ``amd-pstate`` ++uses the ``cppc_acpi`` helper methods to implement the callback functions ++of ``amd_pstate_perf_funcs``. + + +AMD P-States and ACPI hardware P-States always can be supported in one @@ -2301,14 +2505,7 @@ index 0000000000000..c3659dde0cee8 + /sys/devices/system/cpu/cpufreq/policy0/amd_pstate_min_freq + /sys/devices/system/cpu/cpufreq/policy0/amd_pstate_nominal_freq + /sys/devices/system/cpu/cpufreq/policy0/amd_pstate_nominal_perf -+ /sys/devices/system/cpu/cpufreq/policy0/is_amd_pstate_enabled -+ + -+``is_amd_pstate_enabled`` -+ -+Query whether current kernel loads ``amd-pstate`` to enable the AMD -+P-States functionality. -+This attribute is read-only. + +``amd_pstate_highest_perf / amd_pstate_max_freq`` + @@ -2332,9 +2529,11 @@ index 0000000000000..c3659dde0cee8 +Capability <perf_cap_>`_). +This attribute is read-only. + -+``amd_pstate_lowest_perf / amd_pstate_min_freq`` ++``amd_pstate_lowest_perf`` + -+The lowest physical CPPC performance and CPU frequency. ++The lowest physical CPPC performance. The minimum CPU frequency can be read ++back from ``cpuinfo`` member of ``cpufreq_policy``, so we won't expose it ++here. +This attribute is read-only. + + @@ -2408,12 +2607,13 @@ index 0000000000000..c3659dde0cee8 + # ||| / delay + # TASK-PID CPU# |||| TIMESTAMP FUNCTION + # | | | |||| | | -+ <idle>-0 [000] d.s. 244057.464842: amd_pstate_perf: amd_min_perf=39 amd_des_perf=39 amd_max_perf=166 cpu_id=0 prev=0x2727a6 value=0x2727a6 -+ <idle>-0 [000] d.h. 244057.475436: amd_pstate_perf: amd_min_perf=39 amd_des_perf=39 amd_max_perf=166 cpu_id=0 prev=0x2727a6 value=0x2727a6 -+ <idle>-0 [000] d.h. 244057.476629: amd_pstate_perf: amd_min_perf=39 amd_des_perf=39 amd_max_perf=166 cpu_id=0 prev=0x2727a6 value=0x2727a6 -+ <idle>-0 [000] d.s. 244057.484847: amd_pstate_perf: amd_min_perf=39 amd_des_perf=39 amd_max_perf=166 cpu_id=0 prev=0x2727a6 value=0x2727a6 -+ <idle>-0 [000] d.h. 244057.499821: amd_pstate_perf: amd_min_perf=39 amd_des_perf=39 amd_max_perf=166 cpu_id=0 prev=0x2727a6 value=0x2727a6 -+ avahi-daemon-528 [000] d... 244057.513568: amd_pstate_perf: amd_min_perf=39 amd_des_perf=39 amd_max_perf=166 cpu_id=0 prev=0x2727a6 value=0x2727a6 ++ <idle>-0 [015] dN... 4995.979886: amd_pstate_perf: amd_min_perf=85 amd_des_perf=85 amd_max_perf=166 cpu_id=15 changed=false fast_switch=true ++ <idle>-0 [007] d.h.. 4995.979893: amd_pstate_perf: amd_min_perf=85 amd_des_perf=85 amd_max_perf=166 cpu_id=7 changed=false fast_switch=true ++ cat-2161 [000] d.... 4995.980841: amd_pstate_perf: amd_min_perf=85 amd_des_perf=85 amd_max_perf=166 cpu_id=0 changed=false fast_switch=true ++ sshd-2125 [004] d.s.. 4995.980968: amd_pstate_perf: amd_min_perf=85 amd_des_perf=85 amd_max_perf=166 cpu_id=4 changed=false fast_switch=true ++ <idle>-0 [007] d.s.. 4995.980968: amd_pstate_perf: amd_min_perf=85 amd_des_perf=85 amd_max_perf=166 cpu_id=7 changed=false fast_switch=true ++ <idle>-0 [003] d.s.. 4995.980971: amd_pstate_perf: amd_min_perf=85 amd_des_perf=85 amd_max_perf=166 cpu_id=3 changed=false fast_switch=true ++ <idle>-0 [011] d.s.. 4995.980996: amd_pstate_perf: amd_min_perf=85 amd_des_perf=85 amd_max_perf=166 cpu_id=11 changed=false fast_switch=true + +The cpu_frequency trace event will be triggered either by the ``schedutil`` scaling +governor (for the policies it is attached to), or by the ``CPUFreq`` core (for the @@ -2433,18 +2633,14 @@ index 0000000000000..c3659dde0cee8 + https://www.amd.com/system/files/TechDocs/55898_B1_pub_0.50.zip + diff --git a/Documentation/admin-guide/pm/working-state.rst b/Documentation/admin-guide/pm/working-state.rst -index f40994c422dc0..28db6156b55d5 100644 +index f40994c422dc..5d2757e2de65 100644 --- a/Documentation/admin-guide/pm/working-state.rst +++ b/Documentation/admin-guide/pm/working-state.rst @@ -11,6 +11,7 @@ Working-State Power Management intel_idle cpufreq intel_pstate -+ amd_pstate ++ amd-pstate cpufreq_drivers intel_epb intel-speed-select --- -cgit 1.2.3-1.el7 - - |