[PATCH] arm64: of: handle multiple threads in ARM cpu node

Alireza Sanaee
2025-01-10T16:11:00Z

Update `of_parse_and_init_cpus` to parse reg property of CPU node as
an array based as per spec for SMT threads.

Spec v0.4 Section 3.8.1:
The value of reg is a <prop-encoded-**array**> that defines a unique
CPU/thread id for the CPU/threads represented by the CPU node. **If a CPU
supports more than one thread (i.e. multiple streams of execution) the
reg property is an array with 1 element per thread**. The address-cells
on the /cpus node specifies how many cells each element of the array
takes. Software can determine the number of threads by dividing the size
of reg by the parent node's address-cells.

An accurate example of 1 core with 2 SMTs:

cpus {
#size-cells = <0x00>;
#address-cells = <0x01>;

cpu@0 {
phandle = <0x8000>;
**reg = <0x00 0x01>;**
enable-method = "psci";
compatible = "arm,cortex-a57";
device_type = "cpu";
};
};

Instead of:

cpus {
#size-cells = <0x00>;
#address-cells = <0x01>;

cpu@0 {
phandle = <0x8000>;
reg = <0x00>;
enable-method = "psci";
compatible = "arm,cortex-a57";
device_type = "cpu";
};

cpu@1 {
phandle = <0x8001>;
reg = <0x01>;
enable-method = "psci";
compatible = "arm,cortex-a57";
device_type = "cpu";
};
};

which is **NOT** accurate.

Signed-off-by: Alireza Sanaee <alireza.sanaee@huawei.com>
---
arch/arm64/kernel/smp.c | 74 +++++++++++++++++++++++------------------
1 file changed, 41 insertions(+), 33 deletions(-)

diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c
index 3b3f6b56e733..8dd3b3c82967 100644
--- a/arch/arm64/kernel/smp.c
+++ b/arch/arm64/kernel/smp.c
@@ -689,53 +689,61 @@ static void __init acpi_parse_and_init_cpus(void)
static void __init of_parse_and_init_cpus(void)
{
struct device_node *dn;
+ u64 hwid;
+ u32 tid;

for_each_of_cpu_node(dn) {
- u64 hwid = of_get_cpu_hwid(dn, 0);
+ tid = 0;

- if (hwid & ~MPIDR_HWID_BITMASK)
- goto next;
+ while (1) {
+ hwid = of_get_cpu_hwid(dn, tid++);
+ if (hwid == ~0ULL)
+ break;

- if (is_mpidr_duplicate(cpu_count, hwid)) {
- pr_err("%pOF: duplicate cpu reg properties in the DT\n",
- dn);
- goto next;
- }
+ if (hwid & ~MPIDR_HWID_BITMASK)
+ goto next;

- /*
- * The numbering scheme requires that the boot CPU
- * must be assigned logical id 0. Record it so that
- * the logical map built from DT is validated and can
- * be used.
- */
- if (hwid == cpu_logical_map(0)) {
- if (bootcpu_valid) {
- pr_err("%pOF: duplicate boot cpu reg property in DT\n",
- dn);
+ if (is_mpidr_duplicate(cpu_count, hwid)) {
+ pr_err("%pOF: duplicate cpu reg properties in the DT\n",
+ dn);
goto next;
}

- bootcpu_valid = true;
- early_map_cpu_to_node(0, of_node_to_nid(dn));
-
/*
- * cpu_logical_map has already been
- * initialized and the boot cpu doesn't need
- * the enable-method so continue without
- * incrementing cpu.
+ * The numbering scheme requires that the boot CPU
+ * must be assigned logical id 0. Record it so that
+ * the logical map built from DT is validated and can
+ * be used.
*/
- continue;
- }
+ if (hwid == cpu_logical_map(0)) {
+ if (bootcpu_valid) {
+ pr_err("%pOF: duplicate boot cpu reg property in DT\n",
+ dn);
+ goto next;
+ }
+
+ bootcpu_valid = true;
+ early_map_cpu_to_node(0, of_node_to_nid(dn));
+
+ /*
+ * cpu_logical_map has already been
+ * initialized and the boot cpu doesn't need
+ * the enable-method so continue without
+ * incrementing cpu.
+ */
+ continue;
+ }

- if (cpu_count >= NR_CPUS)
- goto next;
+ if (cpu_count >= NR_CPUS)
+ goto next;

- pr_debug("cpu logical map 0x%llx\n", hwid);
- set_cpu_logical_map(cpu_count, hwid);
+ pr_debug("cpu logical map 0x%llx\n", hwid);
+ set_cpu_logical_map(cpu_count, hwid);

- early_map_cpu_to_node(cpu_count, of_node_to_nid(dn));
+ early_map_cpu_to_node(cpu_count, of_node_to_nid(dn));
next:
- cpu_count++;
+ cpu_count++;
+ }
}
}

--
2.43.0