public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH] cpu/hotplug: Fix NULL kobject warning in cpuhp_smt_enable()
@ 2026-04-17  7:55 Jinjie Ruan
  2026-04-18 11:55 ` Catalin Marinas
  0 siblings, 1 reply; 8+ messages in thread
From: Jinjie Ruan @ 2026-04-17  7:55 UTC (permalink / raw)
  To: tglx, peterz, sudeep.holla, yangyicong, dietmar.eggemann,
	Jonathan.Cameron, catalin.marinas, linux-kernel
  Cc: ruanjinjie

When booting with `maxcpus` greater than the number of present CPUs (e.g.,
QEMU -smp cpus=4,maxcpus=8), some CPUs are marked as 'present' but have not
yet been registered via register_cpu(). Consequently, the per-cpu device
objects for these CPUs are not yet initialized.

In cpuhp_smt_enable(), the code iterates over all present CPUs. Calling
_cpu_up() for these unregistered CPUs eventually leads to
sysfs_create_group() being called with a NULL kobject (or a kobject
without a directory), triggering the following warning in
fs/sysfs/group.c:

	if (WARN_ON(!kobj || (!update && !kobj->sd)))
		return -EINVAL;

Fix this by adding a check for get_cpu_device(cpu). This ensures that
SMT is only enabled for CPUs that have successfully completed their
base device registration in sysfs.

How to reproduce:

	1. echo off > /sys/devices/system/cpu/smt/control
		psci: CPU1 killed (polled 0 ms)
		psci: CPU3 killed (polled 0 ms)

	2. echo 2 > /sys/devices/system/cpu/smt/control

	Detected PIPT I-cache on CPU1
	GICv3: CPU1: found redistributor 1 region 0:0x00000000080c0000
	CPU1: Booted secondary processor 0x0000000001 [0x410fd082]
	Detected PIPT I-cache on CPU3
	GICv3: CPU3: found redistributor 3 region 0:0x0000000008100000
	CPU3: Booted secondary processor 0x0000000003 [0x410fd082]
	------------[ cut here ]------------
	WARNING: fs/sysfs/group.c:137 at internal_create_group+0x41c/0x4bc, CPU#2: sh/181
	Modules linked in:
	CPU: 2 UID: 0 PID: 181 Comm: sh Not tainted 7.0.0-rc1-00010-g8d13386c7624 #142 PREEMPT
	Hardware name: QEMU KVM Virtual Machine, BIOS 0.0.0 02/06/2015
	pstate: 20000005 (nzCv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--)
	pc : internal_create_group+0x41c/0x4bc
	lr : sysfs_create_group+0x18/0x24
	sp : ffff80008078ba40
	x29: ffff80008078ba40 x28: ffff296c980ad000 x27: ffff00007fb94128
	x26: 0000000000000054 x25: ffffd693e845f3f0 x24: 0000000000000001
	x23: 0000000000000001 x22: 0000000000000004 x21: 0000000000000000
	x20: ffffd693e845fc10 x19: 0000000000000004 x18: 00000000ffffffff
	x17: 0000000000000000 x16: 0000000000000000 x15: 0000000000000000
	x14: 0000000000000358 x13: 0000000000000007 x12: 0000000000000350
	x11: 0000000000000008 x10: 0000000000000407 x9 : 0000000000000400
	x8 : ffff00007fbf3b60 x7 : 0000000000000000 x6 : ffffd693e845f3f0
	x5 : ffff00007fb94128 x4 : 0000000000000000 x3 : ffff000000f4eac0
	x2 : ffffd693e7095a08 x1 : 0000000000000000 x0 : 0000000000000000
	Call trace:
	 internal_create_group+0x41c/0x4bc (P)
	 sysfs_create_group+0x18/0x24
	 topology_add_dev+0x1c/0x28
	 cpuhp_invoke_callback+0x104/0x20c
	 __cpuhp_invoke_callback_range+0x94/0x11c
	 _cpu_up+0x200/0x37c
	 cpuhp_smt_enable+0xbc/0x114
	 control_store+0xe8/0x1d4
	 dev_attr_store+0x18/0x2c
	 sysfs_kf_write+0x7c/0x94
	 kernfs_fop_write_iter+0x128/0x1b8
	 vfs_write+0x2b0/0x354
	 ksys_write+0x68/0xfc
	 __arm64_sys_write+0x1c/0x28
	 invoke_syscall+0x48/0x10c
	 el0_svc_common.constprop.0+0x40/0xe8
	 do_el0_svc+0x20/0x2c
	 el0_svc+0x34/0x124
	 el0t_64_sync_handler+0xa0/0xe4
	 el0t_64_sync+0x198/0x19c
	---[ end trace 0000000000000000 ]---

Cc: stable@vger.kernel.org
Fixes: eed4583bcf9a6 ("arm64: Kconfig: Enable HOTPLUG_SMT")
Signed-off-by: Jinjie Ruan <ruanjinjie@huawei.com>
---
 kernel/cpu.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/kernel/cpu.c b/kernel/cpu.c
index bc4f7a9ba64e..df725d92ad4f 100644
--- a/kernel/cpu.c
+++ b/kernel/cpu.c
@@ -2706,6 +2706,13 @@ int cpuhp_smt_enable(void)
 	cpu_maps_update_begin();
 	cpu_smt_control = CPU_SMT_ENABLED;
 	for_each_present_cpu(cpu) {
+		/*
+		 * Skip CPUs that have not been registered in sysfs yet.
+		 * This avoids triggering NULL kobject warnings for maxcpus.
+		 */
+		if (!get_cpu_device(cpu))
+			continue;
+
 		/* Skip online CPUs and CPUs on offline nodes */
 		if (cpu_online(cpu) || !node_online(cpu_to_node(cpu)))
 			continue;
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [PATCH] cpu/hotplug: Fix NULL kobject warning in cpuhp_smt_enable()
  2026-04-17  7:55 [PATCH] cpu/hotplug: Fix NULL kobject warning in cpuhp_smt_enable() Jinjie Ruan
@ 2026-04-18 11:55 ` Catalin Marinas
  2026-04-18 15:05   ` Catalin Marinas
  2026-04-23 10:08   ` Thomas Gleixner
  0 siblings, 2 replies; 8+ messages in thread
From: Catalin Marinas @ 2026-04-18 11:55 UTC (permalink / raw)
  To: Jinjie Ruan
  Cc: tglx, peterz, sudeep.holla, yangyicong, dietmar.eggemann,
	Jonathan.Cameron, linux-kernel, James Morse, linux-arm-kernel

+ James Morse, linux-arm-kernel

On Fri, Apr 17, 2026 at 03:55:34PM +0800, Jinjie Ruan wrote:
> When booting with `maxcpus` greater than the number of present CPUs (e.g.,
> QEMU -smp cpus=4,maxcpus=8), some CPUs are marked as 'present' but have not
> yet been registered via register_cpu(). Consequently, the per-cpu device
> objects for these CPUs are not yet initialized.
> 
> In cpuhp_smt_enable(), the code iterates over all present CPUs. Calling
> _cpu_up() for these unregistered CPUs eventually leads to
> sysfs_create_group() being called with a NULL kobject (or a kobject
> without a directory), triggering the following warning in
> fs/sysfs/group.c:
> 
> 	if (WARN_ON(!kobj || (!update && !kobj->sd)))
> 		return -EINVAL;
> 
> Fix this by adding a check for get_cpu_device(cpu). This ensures that
> SMT is only enabled for CPUs that have successfully completed their
> base device registration in sysfs.
> 
> How to reproduce:
> 
> 	1. echo off > /sys/devices/system/cpu/smt/control
> 		psci: CPU1 killed (polled 0 ms)
> 		psci: CPU3 killed (polled 0 ms)
> 
> 	2. echo 2 > /sys/devices/system/cpu/smt/control
> 
> 	Detected PIPT I-cache on CPU1
> 	GICv3: CPU1: found redistributor 1 region 0:0x00000000080c0000
> 	CPU1: Booted secondary processor 0x0000000001 [0x410fd082]
> 	Detected PIPT I-cache on CPU3
> 	GICv3: CPU3: found redistributor 3 region 0:0x0000000008100000
> 	CPU3: Booted secondary processor 0x0000000003 [0x410fd082]
> 	------------[ cut here ]------------
> 	WARNING: fs/sysfs/group.c:137 at internal_create_group+0x41c/0x4bc, CPU#2: sh/181
> 	Modules linked in:
> 	CPU: 2 UID: 0 PID: 181 Comm: sh Not tainted 7.0.0-rc1-00010-g8d13386c7624 #142 PREEMPT
> 	Hardware name: QEMU KVM Virtual Machine, BIOS 0.0.0 02/06/2015
> 	pstate: 20000005 (nzCv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--)
> 	pc : internal_create_group+0x41c/0x4bc
> 	lr : sysfs_create_group+0x18/0x24
> 	sp : ffff80008078ba40
> 	x29: ffff80008078ba40 x28: ffff296c980ad000 x27: ffff00007fb94128
> 	x26: 0000000000000054 x25: ffffd693e845f3f0 x24: 0000000000000001
> 	x23: 0000000000000001 x22: 0000000000000004 x21: 0000000000000000
> 	x20: ffffd693e845fc10 x19: 0000000000000004 x18: 00000000ffffffff
> 	x17: 0000000000000000 x16: 0000000000000000 x15: 0000000000000000
> 	x14: 0000000000000358 x13: 0000000000000007 x12: 0000000000000350
> 	x11: 0000000000000008 x10: 0000000000000407 x9 : 0000000000000400
> 	x8 : ffff00007fbf3b60 x7 : 0000000000000000 x6 : ffffd693e845f3f0
> 	x5 : ffff00007fb94128 x4 : 0000000000000000 x3 : ffff000000f4eac0
> 	x2 : ffffd693e7095a08 x1 : 0000000000000000 x0 : 0000000000000000
> 	Call trace:
> 	 internal_create_group+0x41c/0x4bc (P)
> 	 sysfs_create_group+0x18/0x24
> 	 topology_add_dev+0x1c/0x28
> 	 cpuhp_invoke_callback+0x104/0x20c
> 	 __cpuhp_invoke_callback_range+0x94/0x11c
> 	 _cpu_up+0x200/0x37c
> 	 cpuhp_smt_enable+0xbc/0x114
> 	 control_store+0xe8/0x1d4
> 	 dev_attr_store+0x18/0x2c
> 	 sysfs_kf_write+0x7c/0x94
> 	 kernfs_fop_write_iter+0x128/0x1b8
> 	 vfs_write+0x2b0/0x354
> 	 ksys_write+0x68/0xfc
> 	 __arm64_sys_write+0x1c/0x28
> 	 invoke_syscall+0x48/0x10c
> 	 el0_svc_common.constprop.0+0x40/0xe8
> 	 do_el0_svc+0x20/0x2c
> 	 el0_svc+0x34/0x124
> 	 el0t_64_sync_handler+0xa0/0xe4
> 	 el0t_64_sync+0x198/0x19c
> 	---[ end trace 0000000000000000 ]---
> 
> Cc: stable@vger.kernel.org
> Fixes: eed4583bcf9a6 ("arm64: Kconfig: Enable HOTPLUG_SMT")
> Signed-off-by: Jinjie Ruan <ruanjinjie@huawei.com>
> ---
>  kernel/cpu.c | 7 +++++++
>  1 file changed, 7 insertions(+)
> 
> diff --git a/kernel/cpu.c b/kernel/cpu.c
> index bc4f7a9ba64e..df725d92ad4f 100644
> --- a/kernel/cpu.c
> +++ b/kernel/cpu.c
> @@ -2706,6 +2706,13 @@ int cpuhp_smt_enable(void)
>  	cpu_maps_update_begin();
>  	cpu_smt_control = CPU_SMT_ENABLED;
>  	for_each_present_cpu(cpu) {
> +		/*
> +		 * Skip CPUs that have not been registered in sysfs yet.
> +		 * This avoids triggering NULL kobject warnings for maxcpus.
> +		 */
> +		if (!get_cpu_device(cpu))
> +			continue;
> +
>  		/* Skip online CPUs and CPUs on offline nodes */
>  		if (cpu_online(cpu) || !node_online(cpu_to_node(cpu)))
>  			continue;

I spent some time trying to understand how we can get into this
situation. It seems to be an ACPI only thing.

Since commit eba4675008a6 ("arm64: arch_register_cpu() variant to check
if an ACPI handle is now available.") as part of the virtual CPU hotplug
series, arch_register_cpu() can defer registering the CPU devices. IIUC
this is done later via acpi_processor_hotadd_init(). smp_prepare_cpus(),
however, still marks them as present.

cpuhp_smt_enable(), if triggered later, walks the present cpus and
attempts _cpu_up(). cpuhp_up_callbacks() will call topology_add_dev()
(registered as a CPUHP_TOPOLOGY_PREPARE callback) and warn since
get_cpu_device() returns NULL. I think this can't happen during early
_cpu_up() calls since smp_init() is called before the topology callback
has been registered (slightly later during do_basic_setup()).

I'm not sure what the best fix should be. If we go with something along
the lines of the above, I wonder whether we should instead return an
error in the topology_add_dev() callback if get_cpu_device() returns
NULL. It feels a bit wrong to add a check for sysfs in
cpuhp_smt_enable() just because of some callbacks attempted by
_cpu_up(). There's precedent in cpu_capacity_sysctl_add() returning
-ENOENT. However, this messes up the smt control enabling since
cpuhp_smt_enable() will bail out early and return an error.

Another option would have been to avoid marking such CPUs present but I
think this will break other things. Yet another option is to register
all CPU devices even if they never come up (like maxcpus greater than
actual CPUs).

Opinions? It might be an arm64+ACPI-only thing.

-- 
Catalin

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH] cpu/hotplug: Fix NULL kobject warning in cpuhp_smt_enable()
  2026-04-18 11:55 ` Catalin Marinas
@ 2026-04-18 15:05   ` Catalin Marinas
  2026-04-20  1:29     ` Jinjie Ruan
  2026-04-23 12:46     ` Jinjie Ruan
  2026-04-23 10:08   ` Thomas Gleixner
  1 sibling, 2 replies; 8+ messages in thread
From: Catalin Marinas @ 2026-04-18 15:05 UTC (permalink / raw)
  To: Jinjie Ruan
  Cc: tglx, peterz, sudeep.holla, yangyicong, dietmar.eggemann,
	Jonathan.Cameron, linux-kernel, James Morse, linux-arm-kernel

On Sat, Apr 18, 2026 at 12:55:22PM +0100, Catalin Marinas wrote:
> On Fri, Apr 17, 2026 at 03:55:34PM +0800, Jinjie Ruan wrote:
> > When booting with `maxcpus` greater than the number of present CPUs (e.g.,
> > QEMU -smp cpus=4,maxcpus=8), some CPUs are marked as 'present' but have not
> > yet been registered via register_cpu(). Consequently, the per-cpu device
> > objects for these CPUs are not yet initialized.
[...]
> Another option would have been to avoid marking such CPUs present but I
> think this will break other things. Yet another option is to register
> all CPU devices even if they never come up (like maxcpus greater than
> actual CPUs).

Something like below, untested (and I don't claim I properly understand
this code; just lots of tokens used trying to make sense of it ;))

------------------------8<-------------------------
diff --git a/arch/arm64/kernel/acpi.c b/arch/arm64/kernel/acpi.c
index a9d884fd1d00..4c0a5ed906ea 100644
--- a/arch/arm64/kernel/acpi.c
+++ b/arch/arm64/kernel/acpi.c
@@ -448,12 +448,14 @@ int acpi_map_cpu(acpi_handle handle, phys_cpuid_t physid, u32 apci_id,
 		return *pcpu;
 	}
 
+	set_cpu_present(*pcpu, true);
 	return 0;
 }
 EXPORT_SYMBOL(acpi_map_cpu);
 
 int acpi_unmap_cpu(int cpu)
 {
+	set_cpu_present(cpu, false);
 	return 0;
 }
 EXPORT_SYMBOL(acpi_unmap_cpu);
diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c
index 1aa324104afb..751a74d997e1 100644
--- a/arch/arm64/kernel/smp.c
+++ b/arch/arm64/kernel/smp.c
@@ -510,8 +510,10 @@ int arch_register_cpu(int cpu)
 	struct cpu *c = &per_cpu(cpu_devices, cpu);
 
 	if (!acpi_disabled && !acpi_handle &&
-	    IS_ENABLED(CONFIG_ACPI_HOTPLUG_CPU))
+	    IS_ENABLED(CONFIG_ACPI_HOTPLUG_CPU)) {
+		set_cpu_present(cpu, false);
 		return -EPROBE_DEFER;
+	}
 
 #ifdef CONFIG_ACPI_HOTPLUG_CPU
 	/* For now block anything that looks like physical CPU Hotplug */

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [PATCH] cpu/hotplug: Fix NULL kobject warning in cpuhp_smt_enable()
  2026-04-18 15:05   ` Catalin Marinas
@ 2026-04-20  1:29     ` Jinjie Ruan
  2026-04-23 12:46     ` Jinjie Ruan
  1 sibling, 0 replies; 8+ messages in thread
From: Jinjie Ruan @ 2026-04-20  1:29 UTC (permalink / raw)
  To: Catalin Marinas
  Cc: tglx, peterz, sudeep.holla, yangyicong, dietmar.eggemann,
	Jonathan.Cameron, linux-kernel, James Morse, linux-arm-kernel



On 4/18/2026 11:05 PM, Catalin Marinas wrote:
> On Sat, Apr 18, 2026 at 12:55:22PM +0100, Catalin Marinas wrote:
>> On Fri, Apr 17, 2026 at 03:55:34PM +0800, Jinjie Ruan wrote:
>>> When booting with `maxcpus` greater than the number of present CPUs (e.g.,
>>> QEMU -smp cpus=4,maxcpus=8), some CPUs are marked as 'present' but have not
>>> yet been registered via register_cpu(). Consequently, the per-cpu device
>>> objects for these CPUs are not yet initialized.
> [...]
>> Another option would have been to avoid marking such CPUs present but I
>> think this will break other things. Yet another option is to register
>> all CPU devices even if they never come up (like maxcpus greater than
>> actual CPUs).
> 
> Something like below, untested (and I don't claim I properly understand
> this code; just lots of tokens used trying to make sense of it ;))
> 
> ------------------------8<-------------------------
> diff --git a/arch/arm64/kernel/acpi.c b/arch/arm64/kernel/acpi.c
> index a9d884fd1d00..4c0a5ed906ea 100644
> --- a/arch/arm64/kernel/acpi.c
> +++ b/arch/arm64/kernel/acpi.c
> @@ -448,12 +448,14 @@ int acpi_map_cpu(acpi_handle handle, phys_cpuid_t physid, u32 apci_id,
>  		return *pcpu;
>  	}
>  
> +	set_cpu_present(*pcpu, true);
>  	return 0;
>  }
>  EXPORT_SYMBOL(acpi_map_cpu);
>  
>  int acpi_unmap_cpu(int cpu)
>  {
> +	set_cpu_present(cpu, false);
>  	return 0;
>  }
>  EXPORT_SYMBOL(acpi_unmap_cpu);
> diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c
> index 1aa324104afb..751a74d997e1 100644
> --- a/arch/arm64/kernel/smp.c
> +++ b/arch/arm64/kernel/smp.c
> @@ -510,8 +510,10 @@ int arch_register_cpu(int cpu)
>  	struct cpu *c = &per_cpu(cpu_devices, cpu);
>  
>  	if (!acpi_disabled && !acpi_handle &&
> -	    IS_ENABLED(CONFIG_ACPI_HOTPLUG_CPU))
> +	    IS_ENABLED(CONFIG_ACPI_HOTPLUG_CPU)) {
> +		set_cpu_present(cpu, false);
>  		return -EPROBE_DEFER;
> +	}

I have verified this patch in my local environment, and it passes the test.

>  
>  #ifdef CONFIG_ACPI_HOTPLUG_CPU
>  	/* For now block anything that looks like physical CPU Hotplug */
> 


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH] cpu/hotplug: Fix NULL kobject warning in cpuhp_smt_enable()
  2026-04-18 11:55 ` Catalin Marinas
  2026-04-18 15:05   ` Catalin Marinas
@ 2026-04-23 10:08   ` Thomas Gleixner
  2026-04-23 12:32     ` Jinjie Ruan
  1 sibling, 1 reply; 8+ messages in thread
From: Thomas Gleixner @ 2026-04-23 10:08 UTC (permalink / raw)
  To: Catalin Marinas, Jinjie Ruan
  Cc: peterz, sudeep.holla, yangyicong, dietmar.eggemann,
	Jonathan.Cameron, linux-kernel, James Morse, linux-arm-kernel

On Sat, Apr 18 2026 at 12:55, Catalin Marinas wrote:
> Another option would have been to avoid marking such CPUs present but I
> think this will break other things. Yet another option is to register
> all CPU devices even if they never come up (like maxcpus greater than
> actual CPUs).
>
> Opinions? It might be an arm64+ACPI-only thing.

I think so. The proper thing to do is to apply sane limits:

 1) The possible CPUs enumerated by firmware N_POSSIBLE_FW

 2) The maxcpus limit on the command line N_MAXCPUS_CL

So the actual possible CPUs evaluates to:

   num_possible = min(N_POSSIBLE_FW, N_MAXCPUS_CL, CONFIG_NR_CPUS);

The evaluation of the firmware should not mark CPUs present which are
actually not. ACPI gives you that information. See:

         5.2.12.14 GIC CPU Interface (GICC) Structure

in the ACPI spec. That has two related bits:

Enabled:

   If this bit is set, the processor is ready for use. If this bit is
   clear and the Online Capable bit is set, the system supports enabling
   this processor during OS runtime. If this bit is clear and the Online
   Capable bit is also clear, this processor is un- usable, and the
   operating system support will not attempt to use it.

Online Capable:

   The information conveyed by this bit depends on the value of the
   Enabled bit. If the Enabled bit is set, this bit is reserved and must
   be zero. Otherwise, if this bit is set, the system supports enabling
   this processor later during OS runtime

So the combination of those gives you the right answer:

   Enabled	Online
   	        Capable
   0            0        Not present, not possible
   0            1        Not present, but possible to "hotplug" layter
   1            0        Present
   1            1        Invalid

The kernel sizes everything on the number of possible CPUs and the
present CPU mask is only there to figure out which CPUs are actually
usable and can be brought up.

The runtime physical hotplug mechanics use acpi_[un]map_cpu() to toggle
the present bit.

Thanks,

        tglx




^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH] cpu/hotplug: Fix NULL kobject warning in cpuhp_smt_enable()
  2026-04-23 10:08   ` Thomas Gleixner
@ 2026-04-23 12:32     ` Jinjie Ruan
  2026-04-23 20:11       ` Catalin Marinas
  0 siblings, 1 reply; 8+ messages in thread
From: Jinjie Ruan @ 2026-04-23 12:32 UTC (permalink / raw)
  To: Thomas Gleixner, Catalin Marinas
  Cc: peterz, sudeep.holla, yangyicong, dietmar.eggemann,
	Jonathan.Cameron, linux-kernel, James Morse, linux-arm-kernel



On 4/23/2026 6:08 PM, Thomas Gleixner wrote:
> On Sat, Apr 18 2026 at 12:55, Catalin Marinas wrote:
>> Another option would have been to avoid marking such CPUs present but I
>> think this will break other things. Yet another option is to register
>> all CPU devices even if they never come up (like maxcpus greater than
>> actual CPUs).
>>
>> Opinions? It might be an arm64+ACPI-only thing.
> 
> I think so. The proper thing to do is to apply sane limits:
> 
>  1) The possible CPUs enumerated by firmware N_POSSIBLE_FW
> 
>  2) The maxcpus limit on the command line N_MAXCPUS_CL
> 
> So the actual possible CPUs evaluates to:
> 
>    num_possible = min(N_POSSIBLE_FW, N_MAXCPUS_CL, CONFIG_NR_CPUS);
> 
> The evaluation of the firmware should not mark CPUs present which are
> actually not. ACPI gives you that information. See:
> 
>          5.2.12.14 GIC CPU Interface (GICC) Structure
> 
> in the ACPI spec. That has two related bits:
> 
> Enabled:
> 
>    If this bit is set, the processor is ready for use. If this bit is
>    clear and the Online Capable bit is set, the system supports enabling
>    this processor during OS runtime. If this bit is clear and the Online
>    Capable bit is also clear, this processor is un- usable, and the
>    operating system support will not attempt to use it.
> 
> Online Capable:
> 
>    The information conveyed by this bit depends on the value of the
>    Enabled bit. If the Enabled bit is set, this bit is reserved and must
>    be zero. Otherwise, if this bit is set, the system supports enabling
>    this processor later during OS runtime
> 
> So the combination of those gives you the right answer:
> 
>    Enabled	Online
>    	        Capable
>    0            0        Not present, not possible
>    0            1        Not present, but possible to "hotplug" layter
>    1            0        Present
>    1            1        Invalid

On x86, it seems that all CPUs with the ACPI_MADT_ENABLED bit set will
be marked as present.

acpi_parse_x2apic()
  -> enabled = processor->lapic_flags & ACPI_MADT_ENABLED
  -> topology_register_apic(enabled)
     -> topo_register_apic(enabled)
        -> set_cpu_present(cpu, true)

> 
> The kernel sizes everything on the number of possible CPUs and the
> present CPU mask is only there to figure out which CPUs are actually
> usable and can be brought up.

> 
> The runtime physical hotplug mechanics use acpi_[un]map_cpu() to toggle
> the present bit.
> 
> Thanks,
> 
>         tglx
> 
> 
> 


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH] cpu/hotplug: Fix NULL kobject warning in cpuhp_smt_enable()
  2026-04-18 15:05   ` Catalin Marinas
  2026-04-20  1:29     ` Jinjie Ruan
@ 2026-04-23 12:46     ` Jinjie Ruan
  1 sibling, 0 replies; 8+ messages in thread
From: Jinjie Ruan @ 2026-04-23 12:46 UTC (permalink / raw)
  To: Catalin Marinas
  Cc: tglx, peterz, sudeep.holla, yangyicong, dietmar.eggemann,
	Jonathan.Cameron, linux-kernel, James Morse, linux-arm-kernel



On 4/18/2026 11:05 PM, Catalin Marinas wrote:
> On Sat, Apr 18, 2026 at 12:55:22PM +0100, Catalin Marinas wrote:
>> On Fri, Apr 17, 2026 at 03:55:34PM +0800, Jinjie Ruan wrote:
>>> When booting with `maxcpus` greater than the number of present CPUs (e.g.,
>>> QEMU -smp cpus=4,maxcpus=8), some CPUs are marked as 'present' but have not
>>> yet been registered via register_cpu(). Consequently, the per-cpu device
>>> objects for these CPUs are not yet initialized.
> [...]
>> Another option would have been to avoid marking such CPUs present but I
>> think this will break other things. Yet another option is to register
>> all CPU devices even if they never come up (like maxcpus greater than
>> actual CPUs).
> 
> Something like below, untested (and I don't claim I properly understand
> this code; just lots of tokens used trying to make sense of it ;))
> 
> ------------------------8<-------------------------
> diff --git a/arch/arm64/kernel/acpi.c b/arch/arm64/kernel/acpi.c
> index a9d884fd1d00..4c0a5ed906ea 100644
> --- a/arch/arm64/kernel/acpi.c
> +++ b/arch/arm64/kernel/acpi.c
> @@ -448,12 +448,14 @@ int acpi_map_cpu(acpi_handle handle, phys_cpuid_t physid, u32 apci_id,
>  		return *pcpu;
>  	}
>  
> +	set_cpu_present(*pcpu, true);
>  	return 0;
>  }
>  EXPORT_SYMBOL(acpi_map_cpu);
>  
>  int acpi_unmap_cpu(int cpu)
>  {
> +	set_cpu_present(cpu, false);

This logic, where we set 'present' in acpi_map_cpu() and clear it in
acpi_unmap_cpu(), seems to align with how x86 does it.

acpi_map_cpu()
  -> topology_hotplug_apic()
     -> topo_set_cpuids()
        -> set_cpu_present(cpu, true)

acpi_unmap_cpu()
  -> topology_hotunplug_apic(cpu)
     -> set_cpu_present(cpu, false)

Should we consider moving the setting/clearing of the 'present' bit into
the generic ACPI code (e.g., within the success path of acpi_map_cpu)?
This would ensure consistency across architectures and prevent new
implementations from missing these critical state updates.

>  	return 0;
>  }
>  EXPORT_SYMBOL(acpi_unmap_cpu);
> diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c
> index 1aa324104afb..751a74d997e1 100644
> --- a/arch/arm64/kernel/smp.c
> +++ b/arch/arm64/kernel/smp.c
> @@ -510,8 +510,10 @@ int arch_register_cpu(int cpu)
>  	struct cpu *c = &per_cpu(cpu_devices, cpu);
>  
>  	if (!acpi_disabled && !acpi_handle &&
> -	    IS_ENABLED(CONFIG_ACPI_HOTPLUG_CPU))
> +	    IS_ENABLED(CONFIG_ACPI_HOTPLUG_CPU)) {
> +		set_cpu_present(cpu, false);
>  		return -EPROBE_DEFER;
> +	}
>  
>  #ifdef CONFIG_ACPI_HOTPLUG_CPU
>  	/* For now block anything that looks like physical CPU Hotplug */
> 


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH] cpu/hotplug: Fix NULL kobject warning in cpuhp_smt_enable()
  2026-04-23 12:32     ` Jinjie Ruan
@ 2026-04-23 20:11       ` Catalin Marinas
  0 siblings, 0 replies; 8+ messages in thread
From: Catalin Marinas @ 2026-04-23 20:11 UTC (permalink / raw)
  To: Jinjie Ruan
  Cc: Thomas Gleixner, peterz, sudeep.holla, yangyicong,
	dietmar.eggemann, Jonathan.Cameron, linux-kernel, James Morse,
	linux-arm-kernel

On Thu, Apr 23, 2026 at 08:32:34PM +0800, Jinjie Ruan wrote:
> On 4/23/2026 6:08 PM, Thomas Gleixner wrote:
> > On Sat, Apr 18 2026 at 12:55, Catalin Marinas wrote:
> >> Another option would have been to avoid marking such CPUs present but I
> >> think this will break other things. Yet another option is to register
> >> all CPU devices even if they never come up (like maxcpus greater than
> >> actual CPUs).
> >>
> >> Opinions? It might be an arm64+ACPI-only thing.
> > 
> > I think so. The proper thing to do is to apply sane limits:
> > 
> >  1) The possible CPUs enumerated by firmware N_POSSIBLE_FW
> > 
> >  2) The maxcpus limit on the command line N_MAXCPUS_CL
> > 
> > So the actual possible CPUs evaluates to:
> > 
> >    num_possible = min(N_POSSIBLE_FW, N_MAXCPUS_CL, CONFIG_NR_CPUS);
> > 
> > The evaluation of the firmware should not mark CPUs present which are
> > actually not. ACPI gives you that information. See:
> > 
> >          5.2.12.14 GIC CPU Interface (GICC) Structure
> > 
> > in the ACPI spec. That has two related bits:
> > 
> > Enabled:
> > 
> >    If this bit is set, the processor is ready for use. If this bit is
> >    clear and the Online Capable bit is set, the system supports enabling
> >    this processor during OS runtime. If this bit is clear and the Online
> >    Capable bit is also clear, this processor is un- usable, and the
> >    operating system support will not attempt to use it.
> > 
> > Online Capable:
> > 
> >    The information conveyed by this bit depends on the value of the
> >    Enabled bit. If the Enabled bit is set, this bit is reserved and must
> >    be zero. Otherwise, if this bit is set, the system supports enabling
> >    this processor later during OS runtime
> > 
> > So the combination of those gives you the right answer:
> > 
> >    Enabled	Online
> >    	        Capable
> >    0            0        Not present, not possible
> >    0            1        Not present, but possible to "hotplug" layter
> >    1            0        Present
> >    1            1        Invalid
> 
> On x86, it seems that all CPUs with the ACPI_MADT_ENABLED bit set will
> be marked as present.
> 
> acpi_parse_x2apic()
>   -> enabled = processor->lapic_flags & ACPI_MADT_ENABLED
>   -> topology_register_apic(enabled)
>      -> topo_register_apic(enabled)
>         -> set_cpu_present(cpu, true)

Yes but arm64 marks all CPUs present even if !ACPI_MADT_ENABLED as we
don't have the notion of hardware CPU hotplug.

I need to dig some more into the original vCPU hotplug support and why
we ended up with all CPUs marked as present even if not calling
register_cpu():

https://lore.kernel.org/linux-arm-kernel/20240529133446.28446-1-Jonathan.Cameron@huawei.com/

What's the MADT GICC provided by qemu with "-smp cpus=4,maxcpus=8"? If
it says Enabled for the first 4 and Online Capable for the rest, maybe
we can try something like below:

----------------------8<-----------------
diff --git a/arch/arm64/kernel/acpi.c b/arch/arm64/kernel/acpi.c
index 5891f92c2035..681aa2bbc399 100644
--- a/arch/arm64/kernel/acpi.c
+++ b/arch/arm64/kernel/acpi.c
@@ -448,12 +448,14 @@ int acpi_map_cpu(acpi_handle handle, phys_cpuid_t physid, u32 apci_id,
 		return *pcpu;
 	}
 
+	set_cpu_present(*pcpu, true);
 	return 0;
 }
 EXPORT_SYMBOL(acpi_map_cpu);
 
 int acpi_unmap_cpu(int cpu)
 {
+	set_cpu_present(cpu, false);
 	return 0;
 }
 EXPORT_SYMBOL(acpi_unmap_cpu);
diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c
index 1aa324104afb..6421027669fc 100644
--- a/arch/arm64/kernel/smp.c
+++ b/arch/arm64/kernel/smp.c
@@ -566,6 +566,11 @@ struct acpi_madt_generic_interrupt *acpi_cpu_get_madt_gicc(int cpu)
 }
 EXPORT_SYMBOL_GPL(acpi_cpu_get_madt_gicc);
 
+static bool acpi_cpu_is_present(int cpu)
+{
+	return acpi_cpu_get_madt_gicc(cpu)->flags & ACPI_MADT_ENABLED;
+}
+
 /*
  * acpi_map_gic_cpu_interface - parse processor MADT entry
  *
@@ -670,6 +675,11 @@ static void __init acpi_parse_and_init_cpus(void)
 		early_map_cpu_to_node(i, acpi_numa_get_nid(i));
 }
 #else
+static bool acpi_cpu_is_present(int cpu)
+{
+	return false;
+}
+
 #define acpi_parse_and_init_cpus(...)	do { } while (0)
 #endif
 
@@ -808,7 +818,8 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
 		if (err)
 			continue;
 
-		set_cpu_present(cpu, true);
+		if (acpi_disabled || acpi_cpu_is_present(cpu))
+			set_cpu_present(cpu, true);
 		numa_store_cpu_info(cpu);
 	}
 }

^ permalink raw reply related	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2026-04-23 20:11 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-04-17  7:55 [PATCH] cpu/hotplug: Fix NULL kobject warning in cpuhp_smt_enable() Jinjie Ruan
2026-04-18 11:55 ` Catalin Marinas
2026-04-18 15:05   ` Catalin Marinas
2026-04-20  1:29     ` Jinjie Ruan
2026-04-23 12:46     ` Jinjie Ruan
2026-04-23 10:08   ` Thomas Gleixner
2026-04-23 12:32     ` Jinjie Ruan
2026-04-23 20:11       ` Catalin Marinas

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox