[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [xen master] xen/cpufreq: introduce "cpufreq=amd-cppc" xen cmdline and amd-cppc driver
commit cf55bb78722df362501fe8221aa8ca5993bd222c Author: Penny Zheng <Penny.Zheng@xxxxxxx> AuthorDate: Thu Aug 28 14:46:16 2025 +0200 Commit: Jan Beulich <jbeulich@xxxxxxxx> CommitDate: Thu Aug 28 14:46:16 2025 +0200 xen/cpufreq: introduce "cpufreq=amd-cppc" xen cmdline and amd-cppc driver Users need to set "cpufreq=amd-cppc" in xen cmdline to enable amd-cppc driver, which selects ACPI Collaborative Performance and Power Control (CPPC) on supported AMD hardware to provide a finer grained frequency control mechanism. `verbose` option can also be included to support verbose print. When users setting "cpufreq=amd-cppc", a new amd-cppc driver shall be registered and used. All hooks for amd-cppc driver are transiently missing, and we temporarily make registration fail with -EOPNOTSUPP here. It will be fixed along with the implementation. New xen-pm internal flag XEN_PROCESSOR_PM_CPPC is introduced, to stand for cpufreq driver in CPPC mode. We define XEN_PROCESSOR_PM_CPPC 0x100, as it is the next value to use after 8-bits wide public xen-pm options. We also add sanity check on compile time. All XEN_PROCESSOR_PM_xxx checking shall be updated to consider "XEN_PROCESSOR_PM_CPPC" too. XEN_PROCESSOR_PM_CPPC and XEN_PROCESSOR_PM_PX are firstly set when Xen parsed relative driver signature from xen cmdline, and will become exclusive after cpufreq driver registration. It is because that platform could not support both or mixed mode (CPPC & legacy Px) operations, and only one cpufreq driver could be registerd in Xen at one time, such as on AMD, it is either amd-cppc or legacy P-states driver. Xen rely on XEN_PROCESSOR_PM_CPPC flag to tell current cpufreq driver is in CPPC mode, and accepts relative hypercall. It will neglect Px request and yields success. Signed-off-by: Penny Zheng <Penny.Zheng@xxxxxxx> Acked-by: Jan Beulich <jbeulich@xxxxxxxx> --- docs/misc/xen-command-line.pandoc | 7 +++- xen/arch/x86/acpi/cpufreq/Makefile | 1 + xen/arch/x86/acpi/cpufreq/amd-cppc.c | 59 ++++++++++++++++++++++++++ xen/arch/x86/acpi/cpufreq/cpufreq.c | 69 ++++++++++++++++++++++++++++++- xen/arch/x86/platform_hypercall.c | 14 +++++++ xen/drivers/acpi/pm-op.c | 3 +- xen/drivers/cpufreq/cpufreq.c | 13 +++++- xen/include/acpi/cpufreq/cpufreq.h | 6 ++- xen/include/acpi/cpufreq/processor_perf.h | 10 +++++ 9 files changed, 175 insertions(+), 7 deletions(-) diff --git a/docs/misc/xen-command-line.pandoc b/docs/misc/xen-command-line.pandoc index a75b6c9301..3916cc81f6 100644 --- a/docs/misc/xen-command-line.pandoc +++ b/docs/misc/xen-command-line.pandoc @@ -515,7 +515,7 @@ If set, force use of the performance counters for oprofile, rather than detectin available support. ### cpufreq -> `= none | {{ <boolean> | xen } { [:[powersave|performance|ondemand|userspace][,[<maxfreq>]][,[<minfreq>]]] } [,verbose]} | dom0-kernel | hwp[:[<hdc>][,verbose]]` +> `= none | {{ <boolean> | xen } { [:[powersave|performance|ondemand|userspace][,[<maxfreq>]][,[<minfreq>]]] } [,verbose]} | dom0-kernel | hwp[:[<hdc>][,verbose]] | amd-cppc[:[verbose]]` > Default: `xen` @@ -526,7 +526,7 @@ choice of `dom0-kernel` is deprecated and not supported by all Dom0 kernels. * `<maxfreq>` and `<minfreq>` are integers which represent max and min processor frequencies respectively. * `verbose` option can be included as a string or also as `verbose=<integer>` - for `xen`. It is a boolean for `hwp`. + for `xen`. It is a boolean for `hwp` and `amd-cppc`. * `hwp` selects Hardware-Controlled Performance States (HWP) on supported Intel hardware. HWP is a Skylake+ feature which provides better CPU power management. The default is disabled. If `hwp` is selected, but hardware @@ -534,6 +534,9 @@ choice of `dom0-kernel` is deprecated and not supported by all Dom0 kernels. * `<hdc>` is a boolean to enable Hardware Duty Cycling (HDC). HDC enables the processor to autonomously force physical package components into idle state. The default is enabled, but the option only applies when `hwp` is enabled. +* `amd-cppc` selects ACPI Collaborative Performance and Power Control (CPPC) + on supported AMD hardware to provide finer grained frequency control + mechanism. The default is disabled. There is also support for `;`-separated fallback options: `cpufreq=hwp;xen,verbose`. This first tries `hwp` and falls back to `xen` if diff --git a/xen/arch/x86/acpi/cpufreq/Makefile b/xen/arch/x86/acpi/cpufreq/Makefile index e7dbe434a8..a2ba34bda0 100644 --- a/xen/arch/x86/acpi/cpufreq/Makefile +++ b/xen/arch/x86/acpi/cpufreq/Makefile @@ -1,4 +1,5 @@ obj-$(CONFIG_INTEL) += acpi.o +obj-$(CONFIG_AMD) += amd-cppc.o obj-y += cpufreq.o obj-$(CONFIG_INTEL) += hwp.o obj-$(CONFIG_AMD) += powernow.o diff --git a/xen/arch/x86/acpi/cpufreq/amd-cppc.c b/xen/arch/x86/acpi/cpufreq/amd-cppc.c new file mode 100644 index 0000000000..3377783f7e --- /dev/null +++ b/xen/arch/x86/acpi/cpufreq/amd-cppc.c @@ -0,0 +1,59 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * amd-cppc.c - AMD Processor CPPC Frequency Driver + * + * Copyright (C) 2025 Advanced Micro Devices, Inc. All Rights Reserved. + * + * Author: Penny Zheng <penny.zheng@xxxxxxx> + * + * AMD CPPC cpufreq driver introduces a new CPU performance scaling design + * for AMD processors using the ACPI Collaborative Performance and Power + * Control (CPPC) feature which provides finer grained frequency control range. + */ + +#include <xen/domain.h> +#include <xen/init.h> +#include <xen/param.h> +#include <acpi/cpufreq/cpufreq.h> + +static bool __init amd_cppc_handle_option(const char *s, const char *end) +{ + int ret; + + ret = parse_boolean("verbose", s, end); + if ( ret >= 0 ) + { + cpufreq_verbose = ret; + return true; + } + + return false; +} + +int __init amd_cppc_cmdline_parse(const char *s, const char *e) +{ + do { + const char *end = strpbrk(s, ",;"); + + if ( !amd_cppc_handle_option(s, end) ) + { + printk(XENLOG_WARNING + "cpufreq/amd-cppc: option '%.*s' not recognized\n", + (int)((end ?: e) - s), s); + + return -EINVAL; + } + + s = end ? end + 1 : NULL; + } while ( s && s < e ); + + return 0; +} + +int __init amd_cppc_register_driver(void) +{ + if ( !cpu_has_cppc ) + return -ENODEV; + + return -EOPNOTSUPP; +} diff --git a/xen/arch/x86/acpi/cpufreq/cpufreq.c b/xen/arch/x86/acpi/cpufreq/cpufreq.c index e227376bab..94e8e11c15 100644 --- a/xen/arch/x86/acpi/cpufreq/cpufreq.c +++ b/xen/arch/x86/acpi/cpufreq/cpufreq.c @@ -131,12 +131,14 @@ static int __init cf_check cpufreq_driver_init(void) if ( cpufreq_controller == FREQCTL_xen ) { + unsigned int i; + ret = -ENOENT; switch ( boot_cpu_data.x86_vendor ) { case X86_VENDOR_INTEL: - for ( unsigned int i = 0; i < cpufreq_xen_cnt; i++ ) + for ( i = 0; i < cpufreq_xen_cnt; i++ ) { switch ( cpufreq_xen_opts[i] ) { @@ -151,6 +153,11 @@ static int __init cf_check cpufreq_driver_init(void) case CPUFREQ_none: ret = 0; break; + + default: + printk(XENLOG_WARNING + "Unsupported cpufreq driver for vendor Intel\n"); + break; } if ( !ret || ret == -EBUSY ) @@ -160,13 +167,71 @@ static int __init cf_check cpufreq_driver_init(void) case X86_VENDOR_AMD: case X86_VENDOR_HYGON: - ret = IS_ENABLED(CONFIG_AMD) ? powernow_register_driver() : -ENODEV; +#ifdef CONFIG_AMD + for ( i = 0; i < cpufreq_xen_cnt; i++ ) + { + switch ( cpufreq_xen_opts[i] ) + { + case CPUFREQ_xen: + ret = powernow_register_driver(); + break; + + case CPUFREQ_amd_cppc: + ret = amd_cppc_register_driver(); + break; + + case CPUFREQ_none: + ret = 0; + break; + + default: + printk(XENLOG_WARNING + "Unsupported cpufreq driver for vendor AMD or Hygon\n"); + break; + } + + if ( !ret || ret == -EBUSY ) + break; + } +#else + ret = -ENODEV; +#endif /* CONFIG_AMD */ break; default: printk(XENLOG_ERR "Cpufreq: unsupported x86 vendor\n"); break; } + + /* + * After successful cpufreq driver registeration, XEN_PROCESSOR_PM_CPPC + * and XEN_PROCESSOR_PM_PX shall become exclusive flags. + */ + if ( !ret ) + { + ASSERT(i < cpufreq_xen_cnt); + switch ( cpufreq_xen_opts[i] ) + { + case CPUFREQ_amd_cppc: + xen_processor_pmbits &= ~XEN_PROCESSOR_PM_PX; + break; + + case CPUFREQ_hwp: + case CPUFREQ_xen: + xen_processor_pmbits &= ~XEN_PROCESSOR_PM_CPPC; + break; + + default: + break; + } + } + else if ( ret != -EBUSY ) + /* + * No cpufreq driver gets registered, clear both + * XEN_PROCESSOR_PM_CPPC and XEN_PROCESSOR_PM_PX + */ + xen_processor_pmbits &= ~(XEN_PROCESSOR_PM_CPPC | + XEN_PROCESSOR_PM_PX); } return ret; diff --git a/xen/arch/x86/platform_hypercall.c b/xen/arch/x86/platform_hypercall.c index fafc176475..79bb99e0b6 100644 --- a/xen/arch/x86/platform_hypercall.c +++ b/xen/arch/x86/platform_hypercall.c @@ -546,6 +546,8 @@ ret_t do_platform_op( ret = 0; break; } + /* Xen doesn't support mixed mode */ + ASSERT(!(xen_processor_pmbits & XEN_PROCESSOR_PM_CPPC)); ret = set_px_pminfo(op->u.set_pminfo.id, &op->u.set_pminfo.u.perf); break; @@ -578,6 +580,18 @@ ret_t do_platform_op( } case XEN_PM_CPPC: + if ( !(xen_processor_pmbits & XEN_PROCESSOR_PM_CPPC) ) + { + /* + * Neglect CPPC-info when registered cpufreq driver + * isn't in CPPC mode + */ + ret = 0; + break; + } + /* Xen doesn't support mixed mode */ + ASSERT(!(xen_processor_pmbits & XEN_PROCESSOR_PM_PX)); + ret = set_cppc_pminfo(op->u.set_pminfo.id, &op->u.set_pminfo.u.cppc_data); break; diff --git a/xen/drivers/acpi/pm-op.c b/xen/drivers/acpi/pm-op.c index e3b5c8bcaa..2f516e62b1 100644 --- a/xen/drivers/acpi/pm-op.c +++ b/xen/drivers/acpi/pm-op.c @@ -352,7 +352,8 @@ int do_pm_op(struct xen_sysctl_pm_op *op) switch ( op->cmd & PM_PARA_CATEGORY_MASK ) { case CPUFREQ_PARA: - if ( !(xen_processor_pmbits & XEN_PROCESSOR_PM_PX) ) + if ( !(xen_processor_pmbits & (XEN_PROCESSOR_PM_PX | + XEN_PROCESSOR_PM_CPPC)) ) return -ENODEV; if ( !pmpt || !(pmpt->init & (XEN_PX_INIT | XEN_CPPC_INIT)) ) return -EINVAL; diff --git a/xen/drivers/cpufreq/cpufreq.c b/xen/drivers/cpufreq/cpufreq.c index f553fbcb1c..fe6bd7ff25 100644 --- a/xen/drivers/cpufreq/cpufreq.c +++ b/xen/drivers/cpufreq/cpufreq.c @@ -65,7 +65,7 @@ LIST_HEAD_READ_MOSTLY(cpufreq_governor_list); /* set xen as default cpufreq */ enum cpufreq_controller cpufreq_controller = FREQCTL_xen; -enum cpufreq_xen_opt __initdata cpufreq_xen_opts[2] = { [0] = CPUFREQ_xen }; +enum cpufreq_xen_opt __initdata cpufreq_xen_opts[3] = { [0] = CPUFREQ_xen }; unsigned int __initdata cpufreq_xen_cnt = 1; static int __init cpufreq_cmdline_parse(const char *s, const char *e); @@ -99,6 +99,10 @@ static int __init handle_cpufreq_cmdline(enum cpufreq_xen_opt option) xen_processor_pmbits |= XEN_PROCESSOR_PM_PX; break; + case CPUFREQ_amd_cppc: + xen_processor_pmbits |= XEN_PROCESSOR_PM_CPPC; + break; + default: ASSERT_UNREACHABLE(); ret = -EINVAL; @@ -162,6 +166,13 @@ static int __init cf_check setup_cpufreq_option(const char *str) if ( !ret && arg[0] && arg[1] ) ret = hwp_cmdline_parse(arg + 1, end); } + else if ( IS_ENABLED(CONFIG_AMD) && choice < 0 && + !cmdline_strcmp(str, "amd-cppc") ) + { + ret = handle_cpufreq_cmdline(CPUFREQ_amd_cppc); + if ( !ret && arg[0] && arg[1] ) + ret = amd_cppc_cmdline_parse(arg + 1, end); + } else ret = -EINVAL; diff --git a/xen/include/acpi/cpufreq/cpufreq.h b/xen/include/acpi/cpufreq/cpufreq.h index fd530632b4..5d4881eea8 100644 --- a/xen/include/acpi/cpufreq/cpufreq.h +++ b/xen/include/acpi/cpufreq/cpufreq.h @@ -26,8 +26,9 @@ enum cpufreq_xen_opt { CPUFREQ_none, CPUFREQ_xen, CPUFREQ_hwp, + CPUFREQ_amd_cppc, }; -extern enum cpufreq_xen_opt cpufreq_xen_opts[2]; +extern enum cpufreq_xen_opt cpufreq_xen_opts[3]; extern unsigned int cpufreq_xen_cnt; struct cpufreq_governor; @@ -272,4 +273,7 @@ int set_hwp_para(struct cpufreq_policy *policy, int acpi_cpufreq_register(void); +int amd_cppc_cmdline_parse(const char *s, const char *e); +int amd_cppc_register_driver(void); + #endif /* __XEN_CPUFREQ_PM_H__ */ diff --git a/xen/include/acpi/cpufreq/processor_perf.h b/xen/include/acpi/cpufreq/processor_perf.h index e6576314f0..0a87bc0384 100644 --- a/xen/include/acpi/cpufreq/processor_perf.h +++ b/xen/include/acpi/cpufreq/processor_perf.h @@ -5,6 +5,16 @@ #include <public/sysctl.h> #include <xen/acpi.h> +/* + * Internal xen-pm options + * They are extension to public xen-pm options (XEN_PROCESSOR_PM_xxx) defined + * in public/platform.h, guarded by SIF_PM_MASK + */ +#define XEN_PROCESSOR_PM_CPPC 0x100 +#if XEN_PROCESSOR_PM_CPPC & MASK_EXTR(~0, SIF_PM_MASK) +# error "XEN_PROCESSOR_PM_CPPC shall not occupy bits reserved for public xen-pm options" +#endif + #define XEN_CPPC_INIT 0x40000000U #define XEN_PX_INIT 0x80000000U -- generated by git-patchbot for /home/xen/git/xen.git#master
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |