xen/arch/x86/acpi/Makefile | 2 +- xen/arch/x86/platform_hypercall.c | 6 ++++-- xen/drivers/Makefile | 2 +- xen/drivers/acpi/pm-op.c | 3 ++- xen/drivers/acpi/pmstat.c | 8 ++++++-- xen/drivers/cpufreq/Kconfig | 14 +++++++++++++- xen/include/acpi/cpufreq/cpufreq.h | 13 ++++++++++++- xen/include/acpi/cpufreq/processor_perf.h | 3 --- xen/include/xen/acpi.h | 8 ++++++++ xen/include/xen/pmstat.h | 15 ++++++++++++++- xen/include/xen/sched.h | 7 +++++++ 11 files changed, 68 insertions(+), 13 deletions(-)
Add CONFIG_CPUFREQ to allow CPU frequency scaling support to be
disabled at build time. When disabled, this removes cpufreq code
from the build.
Introduce IS_ENABLED(CONFIG_CPUFREQ) checks for relevant do_pm_op and
do_platform_op subops and other functions that require CONFIG_CPUFREQ to
work.
Add stubs where necessary.
Signed-off-by: Stefano Stabellini <stefano.stabellini@amd.com>
---
Changes in v4:
- fix IS_ENABLED(CPUFREQ)
- remove #ifdef in platform_hypercall.c and use DCE
- move cpufreq_controller enum out of #ifdef
---
xen/arch/x86/acpi/Makefile | 2 +-
xen/arch/x86/platform_hypercall.c | 6 ++++--
xen/drivers/Makefile | 2 +-
xen/drivers/acpi/pm-op.c | 3 ++-
xen/drivers/acpi/pmstat.c | 8 ++++++--
xen/drivers/cpufreq/Kconfig | 14 +++++++++++++-
xen/include/acpi/cpufreq/cpufreq.h | 13 ++++++++++++-
xen/include/acpi/cpufreq/processor_perf.h | 3 ---
xen/include/xen/acpi.h | 8 ++++++++
xen/include/xen/pmstat.h | 15 ++++++++++++++-
xen/include/xen/sched.h | 7 +++++++
11 files changed, 68 insertions(+), 13 deletions(-)
diff --git a/xen/arch/x86/acpi/Makefile b/xen/arch/x86/acpi/Makefile
index 041377e2bb..aa476f65d5 100644
--- a/xen/arch/x86/acpi/Makefile
+++ b/xen/arch/x86/acpi/Makefile
@@ -1,4 +1,4 @@
-obj-y += cpufreq/
+obj-$(CONFIG_CPUFREQ) += cpufreq/
obj-y += lib.o power.o cpu_idle.o cpuidle_menu.o
obj-bin-y += boot.init.o wakeup_prot.o
diff --git a/xen/arch/x86/platform_hypercall.c b/xen/arch/x86/platform_hypercall.c
index c6c5135806..1dc7dae919 100644
--- a/xen/arch/x86/platform_hypercall.c
+++ b/xen/arch/x86/platform_hypercall.c
@@ -487,7 +487,8 @@ ret_t do_platform_op(
case XENPF_change_freq:
ret = -ENOSYS;
- if ( cpufreq_controller != FREQCTL_dom0_kernel )
+ if ( !IS_ENABLED(CONFIG_CPUFREQ) ||
+ cpufreq_controller != FREQCTL_dom0_kernel )
break;
ret = -EINVAL;
if ( op->u.change_freq.flags || !cpu_online(op->u.change_freq.cpu) )
@@ -507,7 +508,8 @@ ret_t do_platform_op(
XEN_GUEST_HANDLE(uint64) idletimes;
ret = -ENOSYS;
- if ( cpufreq_controller != FREQCTL_dom0_kernel )
+ if ( !IS_ENABLED(CONFIG_CPUFREQ) ||
+ cpufreq_controller != FREQCTL_dom0_kernel )
break;
ctlmap.nr_bits = op->u.getidletime.cpumap_nr_cpus;
diff --git a/xen/drivers/Makefile b/xen/drivers/Makefile
index 2a1ae8ad13..3d81b8dde4 100644
--- a/xen/drivers/Makefile
+++ b/xen/drivers/Makefile
@@ -1,5 +1,5 @@
obj-y += char/
-obj-$(CONFIG_HAS_CPUFREQ) += cpufreq/
+obj-$(CONFIG_CPUFREQ) += cpufreq/
obj-$(CONFIG_HAS_PCI) += pci/
obj-$(CONFIG_HAS_VPCI) += vpci/
obj-$(CONFIG_HAS_PASSTHROUGH) += passthrough/
diff --git a/xen/drivers/acpi/pm-op.c b/xen/drivers/acpi/pm-op.c
index 07bddc58d9..72f1eea62f 100644
--- a/xen/drivers/acpi/pm-op.c
+++ b/xen/drivers/acpi/pm-op.c
@@ -367,7 +367,8 @@ int do_pm_op(struct xen_sysctl_pm_op *op)
return ret;
}
- if ( op->cpuid >= nr_cpu_ids || !cpu_online(op->cpuid) )
+ if ( op->cpuid >= nr_cpu_ids || !cpu_online(op->cpuid) ||
+ !IS_ENABLED(CONFIG_CPUFREQ) )
return -EINVAL;
pmpt = processor_pminfo[op->cpuid];
diff --git a/xen/drivers/acpi/pmstat.c b/xen/drivers/acpi/pmstat.c
index 0f31736df2..d640d3a92c 100644
--- a/xen/drivers/acpi/pmstat.c
+++ b/xen/drivers/acpi/pmstat.c
@@ -76,6 +76,9 @@ void cpufreq_statistic_update(unsigned int cpu, uint8_t from, uint8_t to)
spinlock_t *cpufreq_statistic_lock =
&per_cpu(cpufreq_statistic_lock, cpu);
+ if ( !IS_ENABLED(CONFIG_CPUFREQ) )
+ return;
+
spin_lock(cpufreq_statistic_lock);
pxpt = per_cpu(cpufreq_statistic_data, cpu);
@@ -105,7 +108,7 @@ int cpufreq_statistic_init(unsigned int cpu)
spin_lock_init(cpufreq_statistic_lock);
- if ( !pmpt )
+ if ( !pmpt || !IS_ENABLED(CONFIG_CPUFREQ) )
return -EINVAL;
/* Only need to initialize in Px mode */
@@ -225,7 +228,8 @@ int do_get_pm_info(struct xen_sysctl_get_pmstat *op)
int ret = 0;
const struct processor_pminfo *pmpt;
- if ( !op || (op->cpuid >= nr_cpu_ids) || !cpu_online(op->cpuid) )
+ if ( !IS_ENABLED(CONFIG_CPUFREQ) || !op || (op->cpuid >= nr_cpu_ids) ||
+ !cpu_online(op->cpuid) )
return -EINVAL;
pmpt = processor_pminfo[op->cpuid];
diff --git a/xen/drivers/cpufreq/Kconfig b/xen/drivers/cpufreq/Kconfig
index cce80f4aec..b9b93c1a26 100644
--- a/xen/drivers/cpufreq/Kconfig
+++ b/xen/drivers/cpufreq/Kconfig
@@ -1,3 +1,15 @@
-
config HAS_CPUFREQ
bool
+
+config CPUFREQ
+ bool "CPU Frequency scaling"
+ default y
+ depends on HAS_CPUFREQ
+ help
+ Enable CPU frequency scaling and power management governors.
+ This allows Xen to dynamically adjust CPU P-states (performance
+ states) based on system load.
+
+ Disabling this option removes all cpufreq governors and power
+ management interfaces. This is useful for real-time systems or
+ minimal hypervisor builds.
diff --git a/xen/include/acpi/cpufreq/cpufreq.h b/xen/include/acpi/cpufreq/cpufreq.h
index 0171ccf0ba..828d23961c 100644
--- a/xen/include/acpi/cpufreq/cpufreq.h
+++ b/xen/include/acpi/cpufreq/cpufreq.h
@@ -381,8 +381,19 @@ int write_ondemand_up_threshold(unsigned int up_threshold);
int write_userspace_scaling_setspeed(unsigned int cpu, unsigned int freq);
+#ifdef CONFIG_CPUFREQ
+int cpufreq_add_cpu(unsigned int cpu);
+int cpufreq_del_cpu(unsigned int cpu);
+
void cpufreq_dbs_timer_suspend(void);
void cpufreq_dbs_timer_resume(void);
+#else
+static inline int cpufreq_add_cpu(unsigned int cpu) { return -EOPNOTSUPP; }
+static inline int cpufreq_del_cpu(unsigned int cpu) { return -EOPNOTSUPP; }
+
+static inline void cpufreq_dbs_timer_suspend(void) {}
+static inline void cpufreq_dbs_timer_resume(void) {}
+#endif
void intel_feature_detect(struct cpufreq_policy *policy);
@@ -398,7 +409,7 @@ void intel_feature_detect(struct cpufreq_policy *policy);
int hwp_cmdline_parse(const char *s, const char *e);
int hwp_register_driver(void);
-#ifdef CONFIG_INTEL
+#if defined(CONFIG_INTEL) && defined(CONFIG_CPUFREQ)
bool hwp_active(void);
#else
static inline bool hwp_active(void) { return false; }
diff --git a/xen/include/acpi/cpufreq/processor_perf.h b/xen/include/acpi/cpufreq/processor_perf.h
index 0a87bc0384..bad9d94865 100644
--- a/xen/include/acpi/cpufreq/processor_perf.h
+++ b/xen/include/acpi/cpufreq/processor_perf.h
@@ -36,9 +36,6 @@ static inline void cpufreq_statistic_exit(unsigned int cpu) {}
int cpufreq_limit_change(unsigned int cpu);
-int cpufreq_add_cpu(unsigned int cpu);
-int cpufreq_del_cpu(unsigned int cpu);
-
struct processor_performance {
uint32_t state;
uint32_t platform_limit;
diff --git a/xen/include/xen/acpi.h b/xen/include/xen/acpi.h
index 90635ba0f3..ae6dba481c 100644
--- a/xen/include/xen/acpi.h
+++ b/xen/include/xen/acpi.h
@@ -186,7 +186,15 @@ static inline void acpi_set_csubstate_limit(unsigned int new_limit) { return; }
#endif
#ifdef XEN_GUEST_HANDLE
+#ifdef CONFIG_CPUFREQ
int acpi_set_pdc_bits(unsigned int acpi_id, XEN_GUEST_HANDLE(uint32));
+#else
+static inline int acpi_set_pdc_bits(unsigned int acpi_id,
+ XEN_GUEST_HANDLE(uint32) pdc)
+{
+ return -EOPNOTSUPP;
+}
+#endif
#endif
int arch_acpi_set_pdc_bits(u32 acpi_id, u32 *, u32 mask);
diff --git a/xen/include/xen/pmstat.h b/xen/include/xen/pmstat.h
index 6096560d3c..51d3ee404f 100644
--- a/xen/include/xen/pmstat.h
+++ b/xen/include/xen/pmstat.h
@@ -5,10 +5,23 @@
#include <public/platform.h> /* for struct xen_processor_power */
#include <public/sysctl.h> /* for struct pm_cx_stat */
+#ifdef CONFIG_CPUFREQ
int set_px_pminfo(uint32_t acpi_id, struct xen_processor_performance *perf);
-long set_cx_pminfo(uint32_t acpi_id, struct xen_processor_power *power);
int set_cppc_pminfo(unsigned int acpi_id,
const struct xen_processor_cppc *cppc_data);
+#else
+static inline int set_px_pminfo(uint32_t acpi_id,
+ struct xen_processor_performance *perf)
+{
+ return -EOPNOTSUPP;
+}
+static inline int set_cppc_pminfo(unsigned int acpi_id,
+ const struct xen_processor_cppc *cppc_data)
+{
+ return -EOPNOTSUPP;
+}
+#endif
+long set_cx_pminfo(uint32_t acpi_id, struct xen_processor_power *power);
#ifdef CONFIG_COMPAT
struct compat_processor_performance;
diff --git a/xen/include/xen/sched.h b/xen/include/xen/sched.h
index 1268632344..084f3835dc 100644
--- a/xen/include/xen/sched.h
+++ b/xen/include/xen/sched.h
@@ -1259,6 +1259,7 @@ extern enum cpufreq_controller {
FREQCTL_none, FREQCTL_dom0_kernel, FREQCTL_xen
} cpufreq_controller;
+#ifdef CONFIG_CPUFREQ
static always_inline bool is_cpufreq_controller(const struct domain *d)
{
/*
@@ -1274,6 +1275,12 @@ static always_inline bool is_cpufreq_controller(const struct domain *d)
return (is_pv_domain(d) && is_hardware_domain(d) &&
cpufreq_controller == FREQCTL_dom0_kernel);
}
+#else
+static always_inline bool is_cpufreq_controller(const struct domain *d)
+{
+ return false;
+}
+#endif
int cpupool_move_domain(struct domain *d, struct cpupool *c);
int cpupool_do_sysctl(struct xen_sysctl_cpupool_op *op);
--
2.25.1
On 14.02.2026 00:51, Stefano Stabellini wrote:
> Add CONFIG_CPUFREQ to allow CPU frequency scaling support to be
> disabled at build time. When disabled, this removes cpufreq code
> from the build.
>
> Introduce IS_ENABLED(CONFIG_CPUFREQ) checks for relevant do_pm_op and
> do_platform_op subops and other functions that require CONFIG_CPUFREQ to
> work.
>
> Add stubs where necessary.
>
> Signed-off-by: Stefano Stabellini <stefano.stabellini@amd.com>
> ---
> Changes in v4:
> - fix IS_ENABLED(CPUFREQ)
> - remove #ifdef in platform_hypercall.c and use DCE
> - move cpufreq_controller enum out of #ifdef
Where did the v3 revlog go? Especially when submit patches faster than people
can look at them, they might skip a version (or more), while still having
looked at a yet earlier one.
> --- a/xen/drivers/acpi/pm-op.c
> +++ b/xen/drivers/acpi/pm-op.c
> @@ -367,7 +367,8 @@ int do_pm_op(struct xen_sysctl_pm_op *op)
> return ret;
> }
>
> - if ( op->cpuid >= nr_cpu_ids || !cpu_online(op->cpuid) )
> + if ( op->cpuid >= nr_cpu_ids || !cpu_online(op->cpuid) ||
> + !IS_ENABLED(CONFIG_CPUFREQ) )
Have the compile time constant part first? Else any possible side effects
of the other expressions may prevent the compiler from fully dropping all
code here.
> --- a/xen/include/acpi/cpufreq/cpufreq.h
> +++ b/xen/include/acpi/cpufreq/cpufreq.h
> @@ -381,8 +381,19 @@ int write_ondemand_up_threshold(unsigned int up_threshold);
>
> int write_userspace_scaling_setspeed(unsigned int cpu, unsigned int freq);
>
> +#ifdef CONFIG_CPUFREQ
> +int cpufreq_add_cpu(unsigned int cpu);
> +int cpufreq_del_cpu(unsigned int cpu);
> +
> void cpufreq_dbs_timer_suspend(void);
> void cpufreq_dbs_timer_resume(void);
> +#else
> +static inline int cpufreq_add_cpu(unsigned int cpu) { return -EOPNOTSUPP; }
> +static inline int cpufreq_del_cpu(unsigned int cpu) { return -EOPNOTSUPP; }
Returning an error here looks wrong, even if technically it is benign right now
(as the one [each] remaining call doesn't check the error code).
> --- a/xen/include/xen/acpi.h
> +++ b/xen/include/xen/acpi.h
> @@ -186,7 +186,15 @@ static inline void acpi_set_csubstate_limit(unsigned int new_limit) { return; }
> #endif
>
> #ifdef XEN_GUEST_HANDLE
> +#ifdef CONFIG_CPUFREQ
> int acpi_set_pdc_bits(unsigned int acpi_id, XEN_GUEST_HANDLE(uint32));
> +#else
> +static inline int acpi_set_pdc_bits(unsigned int acpi_id,
> + XEN_GUEST_HANDLE(uint32) pdc)
> +{
> + return -EOPNOTSUPP;
Here use of an error indicator would result in the XENPF_set_processor_pminfo
sub-op failing. That's not correct, as this is a notification from Dom0 to us.
If we can't make use of the provided data, we should silently ignore it.
> --- a/xen/include/xen/pmstat.h
> +++ b/xen/include/xen/pmstat.h
> @@ -5,10 +5,23 @@
> #include <public/platform.h> /* for struct xen_processor_power */
> #include <public/sysctl.h> /* for struct pm_cx_stat */
>
> +#ifdef CONFIG_CPUFREQ
> int set_px_pminfo(uint32_t acpi_id, struct xen_processor_performance *perf);
> -long set_cx_pminfo(uint32_t acpi_id, struct xen_processor_power *power);
> int set_cppc_pminfo(unsigned int acpi_id,
> const struct xen_processor_cppc *cppc_data);
> +#else
> +static inline int set_px_pminfo(uint32_t acpi_id,
> + struct xen_processor_performance *perf)
> +{
> + return -EOPNOTSUPP;
> +}
> +static inline int set_cppc_pminfo(unsigned int acpi_id,
> + const struct xen_processor_cppc *cppc_data)
> +{
> + return -EOPNOTSUPP;
> +}
Same here, I suppose.
> --- a/xen/include/xen/sched.h
> +++ b/xen/include/xen/sched.h
> @@ -1259,6 +1259,7 @@ extern enum cpufreq_controller {
> FREQCTL_none, FREQCTL_dom0_kernel, FREQCTL_xen
> } cpufreq_controller;
As previously indicated, these might better be invisible when CPUFREQ=n. But
see also below.
How about (name subject to improvement)
static inline is_hwdom_cpufreq_controller(void)
{
#ifdef CONFIG_CPUFREQ
return cpufreq_controller == FREQCTL_dom0_kernel;
#else
return false;
#endif
}
for use both ...
> +#ifdef CONFIG_CPUFREQ
> static always_inline bool is_cpufreq_controller(const struct domain *d)
> {
> /*
> @@ -1274,6 +1275,12 @@ static always_inline bool is_cpufreq_controller(const struct domain *d)
> return (is_pv_domain(d) && is_hardware_domain(d) &&
> cpufreq_controller == FREQCTL_dom0_kernel);
... here and in do_platform_op()? Or, keeping the enum visible,
static inline is_hwdom_cpufreq_controller(void)
{
return IS_ENABLED(CONFIG_CPUFREQ) &&
cpufreq_controller == FREQCTL_dom0_kernel;
}
Of course the possibly-compile-time-constant part of the expression would
then want to move first, to allow the fencing in is_pv_domain() to also be
dropped.
> }
> +#else
> +static always_inline bool is_cpufreq_controller(const struct domain *d)
> +{
> + return false;
> +}
> +#endif
Too much redundancy: The #ifdef would better be in the function body. But
with the other adjustment the need for an #ifdef would disappear here
anyway.
Jan
On Sat Feb 14, 2026 at 12:51 AM CET, Stefano Stabellini wrote: > - if ( op->cpuid >= nr_cpu_ids || !cpu_online(op->cpuid) ) > + if ( op->cpuid >= nr_cpu_ids || !cpu_online(op->cpuid) || > + !IS_ENABLED(CONFIG_CPUFREQ) ) Largely inconsequential here (and other places in the patch), but I think IS_ENABLED(foo) should go first in all conditional chains so that any invoked function in the OR list is skipped. It's likely in this case it doesn't matter, because cpu_onlin() is a macro that calls a static inline so the whole AST is known to the compiler, but it's trickier when there's non-obvious extern functions at play. In those cases the compiler will still make the calls because it can't know the call won't have side effects. Thus, as a matter of principle, I think IS_ENABLED() checks should always come first. Cheers, Alejandro
© 2016 - 2026 Red Hat, Inc.