|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [PATCH v5 06/18] xen/x86: introduce "cpufreq=amd-cppc" xen cmdline
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 will be implemented in the ongoing commits.
New xen-pm internal flag XEN_PROCESSOR_PM_CPPC is introduced, to be
differentiated with legacy XEN_PROCESSOR_PM_PX. We define
XEN_PROCESSOR_PM_CPPC 0x100, as it is the next value to use after 8-bits wide
public xen-pm options. All xen-pm flag checking involving XEN_PROCESSOR_PM_PX
shall also be updated to consider XEN_PROCESSOR_PM_CPPC now.
Xen is not expected to support both or mixed mode (CPPC & legacy PSS, _PCT,
_PPC) operations, so only one cpufreq driver gets registerd, either amd-cppc
or legacy P-states driver, which is reflected and asserted by the incompatible
flags XEN_PROCESSOR_PM_PX and XEN_PROCESSOR_PM_CPPC.
Signed-off-by: Penny Zheng <Penny.Zheng@xxxxxxx>
---
v1 -> v2:
- Obey to alphabetic sorting and also strict it with CONFIG_AMD
- Remove unnecessary empty comment line
- Use __initconst_cf_clobber for pre-filled structure cpufreq_driver
- Make new switch-case code apply to Hygon CPUs too
- Change ENOSYS with EOPNOTSUPP
- Blanks around binary operator
- Change all amd_/-pstate defined values to amd_/-cppc
---
v2 -> v3
- refactor too long lines
- Make sure XEN_PROCESSOR_PM_PX and XEN_PROCESSOR_PM_CPPC incompatible flags
after cpufreq register registrantion
---
v3 -> v4:
- introduce XEN_PROCESSOR_PM_CPPC in xen internal header
- complement "Hygon" in log message
- remove unnecessary if()
- grow cpufreq_xen_opts[] array
---
v4 -> v5:
- remove XEN_PROCESSOR_PM_xxx flag sanitization from individual driver
- prefer ! over "== 0" in purely boolean contexts
- Blank line between non-fall-through case blocks
- add build-time checking between internal and public XEN_PROCESSOR_PM_*
values
- define XEN_PROCESSOR_PM_CPPC with 0x100, as it is the next value to use
after public interface, and public mask SIF_PM_MASK is 8 bits wide.
- as Dom0 will send the CPPC/Px data whenever it could, the return value shall
be 0 instead of -ENOSYS/EOPNOTSUP when platform doesn't require these data.
---
docs/misc/xen-command-line.pandoc | 7 ++-
xen/arch/x86/acpi/cpufreq/Makefile | 1 +
xen/arch/x86/acpi/cpufreq/amd-cppc.c | 68 +++++++++++++++++++++++
xen/arch/x86/acpi/cpufreq/cpufreq.c | 63 ++++++++++++++++++++-
xen/arch/x86/platform_hypercall.c | 13 ++++-
xen/drivers/acpi/pmstat.c | 3 +-
xen/drivers/cpufreq/cpufreq.c | 18 +++++-
xen/include/acpi/cpufreq/cpufreq.h | 6 +-
xen/include/acpi/cpufreq/processor_perf.h | 3 +
xen/include/public/sysctl.h | 1 +
10 files changed, 175 insertions(+), 8 deletions(-)
create mode 100644 xen/arch/x86/acpi/cpufreq/amd-cppc.c
diff --git a/docs/misc/xen-command-line.pandoc
b/docs/misc/xen-command-line.pandoc
index 89db6e83be..9ef847a336 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..9e64bf957a
--- /dev/null
+++ b/xen/arch/x86/acpi/cpufreq/amd-cppc.c
@@ -0,0 +1,68 @@
+/* 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;
+}
+
+static const struct cpufreq_driver __initconst_cf_clobber
+amd_cppc_cpufreq_driver =
+{
+ .name = XEN_AMD_CPPC_DRIVER_NAME,
+};
+
+int __init amd_cppc_register_driver(void)
+{
+ if ( !cpu_has_cppc )
+ {
+ xen_processor_pmbits &= ~XEN_PROCESSOR_PM_CPPC;
+ return -ENODEV;
+ }
+
+ return cpufreq_register_driver(&amd_cppc_cpufreq_driver);
+}
diff --git a/xen/arch/x86/acpi/cpufreq/cpufreq.c
b/xen/arch/x86/acpi/cpufreq/cpufreq.c
index 61e98b67bd..c40b610c86 100644
--- a/xen/arch/x86/acpi/cpufreq/cpufreq.c
+++ b/xen/arch/x86/acpi/cpufreq/cpufreq.c
@@ -148,6 +148,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 != -ENODEV )
@@ -157,7 +162,63 @@ 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;
+ unsigned int i;
+
+ if ( !IS_ENABLED(CONFIG_AMD) )
+ {
+ ret = -ENODEV;
+ break;
+ }
+ ret = -ENOENT;
+
+ 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 != -ENODEV )
+ break;
+ }
+
+ /*
+ * After cpufreq driver registeration, XEN_PROCESSOR_PM_CPPC
+ * and XEN_PROCESSOR_PM_PX shall become exclusive flags.
+ */
+ if ( !ret && i < cpufreq_xen_cnt )
+ {
+ switch ( cpufreq_xen_opts[i] )
+ {
+ case CPUFREQ_amd_cppc:
+ xen_processor_pmbits &= ~XEN_PROCESSOR_PM_PX;
+ break;
+
+ case CPUFREQ_xen:
+ xen_processor_pmbits &= ~XEN_PROCESSOR_PM_CPPC;
+ break;
+
+ case CPUFREQ_none:
+ default:
+ break;
+ }
+ }
+
break;
}
}
diff --git a/xen/arch/x86/platform_hypercall.c
b/xen/arch/x86/platform_hypercall.c
index 49717e9ca9..231912ed27 100644
--- a/xen/arch/x86/platform_hypercall.c
+++ b/xen/arch/x86/platform_hypercall.c
@@ -539,9 +539,12 @@ ret_t do_platform_op(
case XEN_PM_PX:
if ( !(xen_processor_pmbits & XEN_PROCESSOR_PM_PX) )
{
- ret = -ENOSYS;
+ 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;
@@ -573,6 +576,14 @@ ret_t do_platform_op(
}
case XEN_PM_CPPC:
+ if ( !(xen_processor_pmbits & XEN_PROCESSOR_PM_CPPC) )
+ {
+ 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/pmstat.c b/xen/drivers/acpi/pmstat.c
index f7351f219d..330bc3a1c2 100644
--- a/xen/drivers/acpi/pmstat.c
+++ b/xen/drivers/acpi/pmstat.c
@@ -464,7 +464,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 d1b51c8dd0..fe55720afd 100644
--- a/xen/drivers/cpufreq/cpufreq.c
+++ b/xen/drivers/cpufreq/cpufreq.c
@@ -65,14 +65,15 @@ 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] = { CPUFREQ_xen,
+enum cpufreq_xen_opt __initdata cpufreq_xen_opts[3] = { CPUFREQ_xen,
CPUFREQ_none };
unsigned int __initdata cpufreq_xen_cnt = 1;
-static const char __initconst cpufreq_opts_str[][5] = {
+static const char __initconst cpufreq_opts_str[][9] = {
[CPUFREQ_none] = "none",
[CPUFREQ_xen] = "xen",
[CPUFREQ_hwp] = "hwp",
+ [CPUFREQ_amd_cppc] = "amd-cppc",
};
static int __init cpufreq_cmdline_parse(const char *s, const char *e);
@@ -94,6 +95,8 @@ static int __init handle_cpufreq_cmdline(enum cpufreq_xen_opt
option)
{
int ret = 0;
+ /* Do not occupy bits reserved for public xen-pm */
+ BUILD_BUG_ON(MASK_INSR(XEN_PROCESSOR_PM_CPPC, SIF_PM_MASK));
if ( cpufreq_opts_contain(option) )
{
printk(XENLOG_WARNING "Duplicate cpufreq driver option: %s\n",
@@ -105,6 +108,10 @@ static int __init handle_cpufreq_cmdline(enum
cpufreq_xen_opt option)
cpufreq_xen_opts[cpufreq_xen_cnt++] = option;
switch ( option )
{
+ case CPUFREQ_amd_cppc:
+ xen_processor_pmbits |= XEN_PROCESSOR_PM_CPPC;
+ break;
+
case CPUFREQ_hwp:
case CPUFREQ_xen:
xen_processor_pmbits |= XEN_PROCESSOR_PM_PX;
@@ -172,6 +179,13 @@ static int __init cf_check setup_cpufreq_option(const char
*str)
if ( 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 ( 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 a3c84143af..83050c58b2 100644
--- a/xen/include/acpi/cpufreq/cpufreq.h
+++ b/xen/include/acpi/cpufreq/cpufreq.h
@@ -28,8 +28,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;
@@ -277,4 +278,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 f1f4f3138d..9b6466e705 100644
--- a/xen/include/acpi/cpufreq/processor_perf.h
+++ b/xen/include/acpi/cpufreq/processor_perf.h
@@ -5,6 +5,9 @@
#include <public/sysctl.h>
#include <xen/acpi.h>
+/* Internal ability bits */
+#define XEN_PROCESSOR_PM_CPPC 0x100
+
#define XEN_CPPC_INIT 0x40000000U
#define XEN_PX_INIT 0x80000000U
diff --git a/xen/include/public/sysctl.h b/xen/include/public/sysctl.h
index b0fec271d3..42997252ef 100644
--- a/xen/include/public/sysctl.h
+++ b/xen/include/public/sysctl.h
@@ -423,6 +423,7 @@ struct xen_set_cppc_para {
uint32_t activity_window;
};
+#define XEN_AMD_CPPC_DRIVER_NAME "amd-cppc"
#define XEN_HWP_DRIVER_NAME "hwp"
/*
--
2.34.1
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |