]> www.infradead.org Git - users/dwmw2/linux.git/commitdiff
cpu/hotplug: Add dynamic states before CPUHP_BRINGUP_CPU for parallel bringup
authorDavid Woodhouse <dwmw@amazon.co.uk>
Thu, 28 Jan 2021 13:25:18 +0000 (13:25 +0000)
committerDavid Woodhouse <dwmw@amazon.co.uk>
Thu, 28 Jan 2021 20:11:58 +0000 (20:11 +0000)
If the platform registers these states, bring all CPUs to each registered
state in parallel, before the final bringup to CPUHP_BRINGUP_CPU.

Signed-off-by: David Woodhouse <dwmw@amazon.co.uk>
include/linux/cpuhotplug.h
kernel/cpu.c

index 0042ef362511d431ff74d322373db1abe0c6726a..ae07cd1dafe319f2ba15e69eed6352af7b5c0b3c 100644 (file)
@@ -92,6 +92,8 @@ enum cpuhp_state {
        CPUHP_MIPS_SOC_PREPARE,
        CPUHP_BP_PREPARE_DYN,
        CPUHP_BP_PREPARE_DYN_END                = CPUHP_BP_PREPARE_DYN + 20,
+       CPUHP_BP_PARALLEL_DYN,
+       CPUHP_BP_PARALLEL_DYN_END               = CPUHP_BP_PARALLEL_DYN + 4,
        CPUHP_BRINGUP_CPU,
        CPUHP_AP_IDLE_DEAD,
        CPUHP_AP_OFFLINE,
index 4e11e91010e11266b86302cad79532eb0e8d6dd3..11f9504b4845600cb78d47c51fc2acbe394989e4 100644 (file)
@@ -1335,6 +1335,24 @@ int bringup_hibernate_cpu(unsigned int sleep_cpu)
 void bringup_nonboot_cpus(unsigned int setup_max_cpus)
 {
        unsigned int cpu;
+       int n = setup_max_cpus - num_online_cpus();
+
+       /* ∀ parallel pre-bringup state, bring N CPUs to it */
+       if (n > 0) {
+               enum cpuhp_state st = CPUHP_BP_PARALLEL_DYN;
+
+               while (st <= CPUHP_BP_PARALLEL_DYN_END &&
+                      cpuhp_hp_states[st].name) {
+                       int i = n;
+
+                       for_each_present_cpu(cpu) {
+                               cpu_up(cpu, st);
+                               if (!--i)
+                                       break;
+                       }
+                       st++;
+               }
+       }
 
        for_each_present_cpu(cpu) {
                if (num_online_cpus() >= setup_max_cpus)
@@ -1702,6 +1720,10 @@ static int cpuhp_reserve_state(enum cpuhp_state state)
                step = cpuhp_hp_states + CPUHP_BP_PREPARE_DYN;
                end = CPUHP_BP_PREPARE_DYN_END;
                break;
+       case CPUHP_BP_PARALLEL_DYN:
+               step = cpuhp_hp_states + CPUHP_BP_PARALLEL_DYN;
+               end = CPUHP_BP_PARALLEL_DYN_END;
+               break;
        default:
                return -EINVAL;
        }
@@ -1726,14 +1748,15 @@ static int cpuhp_store_callbacks(enum cpuhp_state state, const char *name,
        /*
         * If name is NULL, then the state gets removed.
         *
-        * CPUHP_AP_ONLINE_DYN and CPUHP_BP_PREPARE_DYN are handed out on
+        * CPUHP_AP_ONLINE_DYN and CPUHP_BP_xxxxx_DYN are handed out on
         * the first allocation from these dynamic ranges, so the removal
         * would trigger a new allocation and clear the wrong (already
         * empty) state, leaving the callbacks of the to be cleared state
         * dangling, which causes wreckage on the next hotplug operation.
         */
        if (name && (state == CPUHP_AP_ONLINE_DYN ||
-                    state == CPUHP_BP_PREPARE_DYN)) {
+                    state == CPUHP_BP_PREPARE_DYN ||
+                    state == CPUHP_BP_PARALLEL_DYN)) {
                ret = cpuhp_reserve_state(state);
                if (ret < 0)
                        return ret;