LoongArch: Always enumerate MADT and setup logical-physical CPU mapping
authorHuacai Chen <chenhuacai@loongson.cn>
Sat, 20 Jul 2024 14:40:58 +0000 (22:40 +0800)
committerHuacai Chen <chenhuacai@loongson.cn>
Sat, 20 Jul 2024 14:40:58 +0000 (22:40 +0800)
Some drivers want to use cpu_logical_map(), early_cpu_to_node() and some
other CPU mapping APIs, even if we use "nr_cpus=1" to hard limit the CPU
number. This is strongly required for the multi-bridges machines.

Currently, we stop parsing the MADT if the nr_cpus limit is reached, but
to achieve the above goal we should always enumerate the MADT table and
setup logical-physical CPU mapping whether there is a nr_cpus limit.

Rework the MADT enumeration:

1. Define a flag "cpu_enumerated" to distinguish the first enumeration
   (cpu_enumerated=0) and the physical hotplug case (cpu_enumerated=1)
   for set_processor_mask().

2. If cpu_enumerated=0, stop parsing only when NR_CPUS limit is reached,
   so we can setup logical-physical CPU mapping; if cpu_enumerated=1,
   stop parsing when nr_cpu_ids limit is reached, so we can avoid some
   runtime bugs. Once logical-physical CPU mapping is setup, we will let
   cpu_enumerated=1.

3. Use find_first_zero_bit() instead of cpumask_next_zero() to find the
   next zero bit (free logical CPU id) in the cpu_present_mask, because
   cpumask_next_zero() will stop at nr_cpu_ids.

4. Only touch cpu_possible_mask if cpu_enumerated=0, this is in order to
   avoid some potential crashes, because cpu_possible_mask is marked as
   __ro_after_init.

5. In prefill_possible_map(), clear cpu_present_mask bits greater than
   nr_cpu_ids, in order to avoid a CPU be "present" but not "possible".

Signed-off-by: Huacai Chen <chenhuacai@loongson.cn>
arch/loongarch/kernel/acpi.c
arch/loongarch/kernel/setup.c
arch/loongarch/kernel/smp.c

index 5cf59c617126b7d00f65b3310ef39ea7bfb98e96..929a497c987e84308d2e301bfd8df95534641345 100644 (file)
@@ -57,15 +57,22 @@ void __iomem *acpi_os_ioremap(acpi_physical_address phys, acpi_size size)
                return ioremap_cache(phys, size);
 }
 
+static int cpu_enumerated = 0;
+
 #ifdef CONFIG_SMP
 static int set_processor_mask(u32 id, u32 flags)
 {
-
+       int nr_cpus;
        int cpu, cpuid = id;
 
-       if (num_processors >= nr_cpu_ids) {
-               pr_warn(PREFIX "nr_cpus/possible_cpus limit of %i reached."
-                       " processor 0x%x ignored.\n", nr_cpu_ids, cpuid);
+       if (!cpu_enumerated)
+               nr_cpus = NR_CPUS;
+       else
+               nr_cpus = nr_cpu_ids;
+
+       if (num_processors >= nr_cpus) {
+               pr_warn(PREFIX "nr_cpus limit of %i reached."
+                       " processor 0x%x ignored.\n", nr_cpus, cpuid);
 
                return -ENODEV;
 
@@ -73,11 +80,13 @@ static int set_processor_mask(u32 id, u32 flags)
        if (cpuid == loongson_sysconf.boot_cpu_id)
                cpu = 0;
        else
-               cpu = cpumask_next_zero(-1, cpu_present_mask);
+               cpu = find_first_zero_bit(cpumask_bits(cpu_present_mask), NR_CPUS);
+
+       if (!cpu_enumerated)
+               set_cpu_possible(cpu, true);
 
        if (flags & ACPI_MADT_ENABLED) {
                num_processors++;
-               set_cpu_possible(cpu, true);
                set_cpu_present(cpu, true);
                __cpu_number_map[cpuid] = cpu;
                __cpu_logical_map[cpu] = cpuid;
@@ -138,6 +147,7 @@ static void __init acpi_process_madt(void)
        acpi_table_parse_madt(ACPI_MADT_TYPE_EIO_PIC,
                        acpi_parse_eio_master, MAX_IO_PICS);
 
+       cpu_enumerated = 1;
        loongson_sysconf.nr_cpus = num_processors;
 }
 
index 3d048f1be1438863831e19817711292558d75149..0f0740f0be274ac3ba944776e0f2889540e99308 100644 (file)
@@ -576,8 +576,10 @@ static void __init prefill_possible_map(void)
 
        for (i = 0; i < possible; i++)
                set_cpu_possible(i, true);
-       for (; i < NR_CPUS; i++)
+       for (; i < NR_CPUS; i++) {
+               set_cpu_present(i, false);
                set_cpu_possible(i, false);
+       }
 
        set_nr_cpu_ids(possible);
 }
index 1436d2465939b2d79744833c8c5a4abe3ead8916..03b2b7669cf5ddd24779ba292d536ebe747fab03 100644 (file)
@@ -271,11 +271,10 @@ static void __init fdt_smp_setup(void)
                if (cpuid >= nr_cpu_ids)
                        continue;
 
-               if (cpuid == loongson_sysconf.boot_cpu_id) {
+               if (cpuid == loongson_sysconf.boot_cpu_id)
                        cpu = 0;
-               } else {
-                       cpu = cpumask_next_zero(-1, cpu_present_mask);
-               }
+               else
+                       cpu = find_first_zero_bit(cpumask_bits(cpu_present_mask), NR_CPUS);
 
                num_processors++;
                set_cpu_possible(cpu, true);