SMT-disable enforcement check is moved into a separate
architecture-specific function.
For now this operations only support Arm64. For proper Arm32 support,
there needs to be a mechanism to free per-cpu page tables, allocated in
init_domheap_mappings. Also, hotplug is not supported if ITS enabled,
and partially supported FFA, or TEE is enabled, as they use non-static
IRQ actions.
Remove ifdef guards for x86 in flask, as cpu hotplug is now
supported on more architectures.
Signed-off-by: Mykyta Poturai <mykyta_poturai@epam.com>
---
v6->v7:
* use IS_ENABLED istead of ifdef in more places
* remove unneded variables
* more explicit fallthrough in do_sysctl
v5->v6:
* fix style issues
* rename arch_smt_cpu_disable -> arch_cpu_can_stay_online and invert the
logic
* use IS_ENABLED istead of ifdef
* remove explicit list af arch-specific SYSCTL_CPU_HOTPLUG_* options
from the common handler
* fix flask issue
v4->v5:
* move handling to common code
* rename config to CPU_HOTPUG
* merge with "smp: Move cpu_up/down helpers to common code"
v3->v4:
* don't reimplement cpu_up/down helpers
* add Kconfig option
* fixup formatting
v2->v3:
* no changes
v1->v2:
* remove SMT ops
* remove cpu == 0 checks
* add XSM hooks
* only implement for 64bit Arm
Signed-off-by: Mykyta Poturai <mykyta_poturai@epam.com>
---
xen/arch/arm/smp.c | 9 ++++++++
xen/arch/ppc/stubs.c | 4 ++++
xen/arch/riscv/stubs.c | 5 ++++
xen/arch/x86/include/asm/smp.h | 3 ---
xen/arch/x86/smp.c | 36 +++--------------------------
xen/arch/x86/sysctl.c | 13 ++++-------
xen/common/Kconfig | 6 ++---
xen/common/smp.c | 35 ++++++++++++++++++++++++++++
xen/common/sysctl.c | 42 ++++++++++++++++++++++++++++++++++
xen/include/xen/smp.h | 4 ++++
xen/xsm/flask/hooks.c | 2 --
11 files changed, 109 insertions(+), 50 deletions(-)
diff --git a/xen/arch/arm/smp.c b/xen/arch/arm/smp.c
index b372472188..0ea64d2ee1 100644
--- a/xen/arch/arm/smp.c
+++ b/xen/arch/arm/smp.c
@@ -44,6 +44,15 @@ void smp_send_call_function_mask(const cpumask_t *mask)
}
}
+/*
+ * We currently don't support SMT on ARM so we don't need any special logic for
+ * CPU disabling
+ */
+inline bool arch_cpu_can_stay_online(unsigned int cpu)
+{
+ return true;
+}
+
/*
* Local variables:
* mode: C
diff --git a/xen/arch/ppc/stubs.c b/xen/arch/ppc/stubs.c
index a333f06119..8f280ba080 100644
--- a/xen/arch/ppc/stubs.c
+++ b/xen/arch/ppc/stubs.c
@@ -101,6 +101,10 @@ void smp_send_call_function_mask(const cpumask_t *mask)
BUG_ON("unimplemented");
}
+bool arch_cpu_can_stay_online(unsigned int cpu)
+{
+ BUG_ON("unimplemented");
+}
/* irq.c */
void irq_ack_none(struct irq_desc *desc)
diff --git a/xen/arch/riscv/stubs.c b/xen/arch/riscv/stubs.c
index daadff0138..7c3cda7bc5 100644
--- a/xen/arch/riscv/stubs.c
+++ b/xen/arch/riscv/stubs.c
@@ -70,6 +70,11 @@ void smp_send_call_function_mask(const cpumask_t *mask)
BUG_ON("unimplemented");
}
+bool arch_cpu_can_stay_online(unsigned int cpu)
+{
+ BUG_ON("unimplemented");
+}
+
/* irq.c */
void irq_ack_none(struct irq_desc *desc)
diff --git a/xen/arch/x86/include/asm/smp.h b/xen/arch/x86/include/asm/smp.h
index 3f16e62696..cb3e0fed19 100644
--- a/xen/arch/x86/include/asm/smp.h
+++ b/xen/arch/x86/include/asm/smp.h
@@ -50,9 +50,6 @@ int cpu_add(uint32_t apic_id, uint32_t acpi_id, uint32_t pxm);
void __stop_this_cpu(void);
-long cf_check cpu_up_helper(void *data);
-long cf_check cpu_down_helper(void *data);
-
long cf_check core_parking_helper(void *data);
bool core_parking_remove(unsigned int cpu);
uint32_t get_cur_idle_nums(void);
diff --git a/xen/arch/x86/smp.c b/xen/arch/x86/smp.c
index a49505fb57..b781e933f2 100644
--- a/xen/arch/x86/smp.c
+++ b/xen/arch/x86/smp.c
@@ -418,38 +418,8 @@ void cf_check call_function_interrupt(void)
smp_call_function_interrupt();
}
-#ifdef CONFIG_CPU_HOTPLUG
-long cf_check cpu_up_helper(void *data)
+bool arch_cpu_can_stay_online(unsigned int cpu)
{
- unsigned int cpu = (unsigned long)data;
- int ret = cpu_up(cpu);
-
- /* Have one more go on EBUSY. */
- if ( ret == -EBUSY )
- ret = cpu_up(cpu);
-
- if ( !ret && !opt_smt &&
- cpu_data[cpu].compute_unit_id == INVALID_CUID &&
- cpumask_weight(per_cpu(cpu_sibling_mask, cpu)) > 1 )
- {
- ret = cpu_down_helper(data);
- if ( ret )
- printk("Could not re-offline CPU%u (%d)\n", cpu, ret);
- else
- ret = -EPERM;
- }
-
- return ret;
-}
-
-long cf_check cpu_down_helper(void *data)
-{
- int cpu = (unsigned long)data;
- int ret = cpu_down(cpu);
-
- /* Have one more go on EBUSY. */
- if ( ret == -EBUSY )
- ret = cpu_down(cpu);
- return ret;
+ return opt_smt || cpu_data[cpu].compute_unit_id != INVALID_CUID ||
+ cpumask_weight(per_cpu(cpu_sibling_mask, cpu)) <= 1;
}
-#endif
diff --git a/xen/arch/x86/sysctl.c b/xen/arch/x86/sysctl.c
index bdad44fef1..072726debc 100644
--- a/xen/arch/x86/sysctl.c
+++ b/xen/arch/x86/sysctl.c
@@ -120,7 +120,6 @@ long arch_do_sysctl(
case XEN_SYSCTL_cpu_hotplug:
{
- unsigned int cpu = sysctl->u.cpu_hotplug.cpu;
unsigned int op = sysctl->u.cpu_hotplug.op;
bool plug;
long (*fn)(void *data);
@@ -128,6 +127,7 @@ long arch_do_sysctl(
if ( !IS_ENABLED(CONFIG_CPU_HOTPLUG) )
{
+ ASSERT_UNREACHABLE();
ret = -EOPNOTSUPP;
break;
}
@@ -135,15 +135,10 @@ long arch_do_sysctl(
switch ( op )
{
case XEN_SYSCTL_CPU_HOTPLUG_ONLINE:
- plug = true;
- fn = cpu_up_helper;
- hcpu = _p(cpu);
- break;
-
case XEN_SYSCTL_CPU_HOTPLUG_OFFLINE:
- plug = false;
- fn = cpu_down_helper;
- hcpu = _p(cpu);
+ /* Handled by common code */
+ ASSERT_UNREACHABLE();
+ ret = -EOPNOTSUPP;
break;
case XEN_SYSCTL_CPU_HOTPLUG_SMT_ENABLE:
diff --git a/xen/common/Kconfig b/xen/common/Kconfig
index 0e5b4738a8..9e26217404 100644
--- a/xen/common/Kconfig
+++ b/xen/common/Kconfig
@@ -638,9 +638,9 @@ config SYSTEM_SUSPEND
If unsure, say N.
config CPU_HOTPLUG
- bool "CPU online/offline support"
- depends on X86
- default y
+ bool "CPU online/offline support" if EXPERT || X86
+ depends on X86 || (ARM_64 && !HAS_ITS)
+ default y if X86
help
Enable support for bringing CPUs online and offline at runtime. On
X86 this is required for disabling SMT.
diff --git a/xen/common/smp.c b/xen/common/smp.c
index a011f541f1..e2bf82856e 100644
--- a/xen/common/smp.c
+++ b/xen/common/smp.c
@@ -16,6 +16,7 @@
* GNU General Public License for more details.
*/
+#include <xen/cpu.h>
#include <asm/hardirq.h>
#include <asm/processor.h>
#include <xen/spinlock.h>
@@ -104,6 +105,40 @@ void smp_call_function_interrupt(void)
irq_exit();
}
+#ifdef CONFIG_CPU_HOTPLUG
+long cf_check cpu_up_helper(void *data)
+{
+ unsigned int cpu = (unsigned long)data;
+ int ret = cpu_up(cpu);
+
+ /* Have one more go on EBUSY. */
+ if ( ret == -EBUSY )
+ ret = cpu_up(cpu);
+
+ if ( !ret && !arch_cpu_can_stay_online(cpu) )
+ {
+ ret = cpu_down_helper(data);
+ if ( ret )
+ printk("Could not re-offline CPU%u (%d)\n", cpu, ret);
+ else
+ ret = -EPERM;
+ }
+
+ return ret;
+}
+
+long cf_check cpu_down_helper(void *data)
+{
+ unsigned int cpu = (unsigned long)data;
+ int ret = cpu_down(cpu);
+
+ /* Have one more go on EBUSY. */
+ if ( ret == -EBUSY )
+ ret = cpu_down(cpu);
+ return ret;
+}
+#endif /* CONFIG_CPU_HOTPLUG */
+
/*
* Local variables:
* mode: C
diff --git a/xen/common/sysctl.c b/xen/common/sysctl.c
index 5207664252..da95446039 100644
--- a/xen/common/sysctl.c
+++ b/xen/common/sysctl.c
@@ -483,6 +483,48 @@ long do_sysctl(XEN_GUEST_HANDLE_PARAM(xen_sysctl_t) u_sysctl)
copyback = 1;
break;
+ case XEN_SYSCTL_cpu_hotplug:
+ {
+ unsigned int hp_op = op->u.cpu_hotplug.op;
+ bool plug;
+ long (*fn)(void *data);
+ void *hcpu = _p(op->u.cpu_hotplug.cpu);
+
+ ret = -EOPNOTSUPP;
+ if ( !IS_ENABLED(CONFIG_CPU_HOTPLUG) )
+ break;
+
+ switch ( hp_op )
+ {
+ case XEN_SYSCTL_CPU_HOTPLUG_ONLINE:
+ plug = true;
+ fn = cpu_up_helper;
+ break;
+
+ case XEN_SYSCTL_CPU_HOTPLUG_OFFLINE:
+ plug = false;
+ fn = cpu_down_helper;
+ break;
+
+ default:
+ fn = NULL;
+ break;
+ }
+
+ if ( fn )
+ {
+ ret = plug ? xsm_resource_plug_core(XSM_HOOK)
+ : xsm_resource_unplug_core(XSM_HOOK);
+
+ if ( !ret )
+ ret = continue_hypercall_on_cpu(0, fn, hcpu);
+
+ break;
+ }
+ }
+
+ /* Use the arch handler for cases not handled here */
+ fallthrough;
default:
ret = arch_do_sysctl(op, u_sysctl);
copyback = 0;
diff --git a/xen/include/xen/smp.h b/xen/include/xen/smp.h
index 2ca9ff1bfc..04530738c9 100644
--- a/xen/include/xen/smp.h
+++ b/xen/include/xen/smp.h
@@ -76,4 +76,8 @@ extern void *stack_base[NR_CPUS];
void initialize_cpu_data(unsigned int cpu);
int setup_cpu_root_pgt(unsigned int cpu);
+bool arch_cpu_can_stay_online(unsigned int cpu);
+long cf_check cpu_up_helper(void *data);
+long cf_check cpu_down_helper(void *data);
+
#endif /* __XEN_SMP_H__ */
diff --git a/xen/xsm/flask/hooks.c b/xen/xsm/flask/hooks.c
index b250b27065..01f9d50605 100644
--- a/xen/xsm/flask/hooks.c
+++ b/xen/xsm/flask/hooks.c
@@ -835,9 +835,7 @@ static int cf_check flask_sysctl(int cmd)
case XEN_SYSCTL_getdomaininfolist:
case XEN_SYSCTL_page_offline_op:
case XEN_SYSCTL_scheduler_op:
-#ifdef CONFIG_X86
case XEN_SYSCTL_cpu_hotplug:
-#endif
return 0;
case XEN_SYSCTL_tbuf_op:
--
2.51.2
On 30.03.2026 13:59, Mykyta Poturai wrote: > --- a/xen/common/Kconfig > +++ b/xen/common/Kconfig > @@ -638,9 +638,9 @@ config SYSTEM_SUSPEND > If unsure, say N. > > config CPU_HOTPLUG > - bool "CPU online/offline support" > - depends on X86 > - default y > + bool "CPU online/offline support" if EXPERT || X86 Why not just EXPERT? > + depends on X86 || (ARM_64 && !HAS_ITS) The !HAS_ITS is puzzling, and it doesn't help that that option looks misnamed (HAS_* shouldn't have prompts imo). The description says something there, yes, but then also mentions FFA and TEE. Yet for those the option remains available. > + default y if X86 Shorter as "default X86". Jan
© 2016 - 2026 Red Hat, Inc.