@@ -429,7 +429,7 @@ static int cpuhp_should_run(unsigned int cpu)
429
429
/* Execute the teardown callbacks. Used to be CPU_DOWN_PREPARE */
430
430
static int cpuhp_ap_offline (unsigned int cpu , struct cpuhp_cpu_state * st )
431
431
{
432
- enum cpuhp_state target = max ((int )st -> target , CPUHP_AP_ONLINE );
432
+ enum cpuhp_state target = max ((int )st -> target , CPUHP_TEARDOWN_CPU );
433
433
434
434
return cpuhp_down_callbacks (cpu , st , cpuhp_ap_states , target );
435
435
}
@@ -469,6 +469,9 @@ static void cpuhp_thread_fun(unsigned int cpu)
469
469
ret = cpuhp_invoke_callback (cpu , st -> cb_state , st -> cb );
470
470
}
471
471
} else {
472
+ /* Cannot happen .... */
473
+ BUG_ON (st -> state < CPUHP_KICK_AP_THREAD );
474
+
472
475
/* Regular hotplug work */
473
476
if (st -> state < st -> target )
474
477
ret = cpuhp_ap_online (cpu , st );
@@ -502,12 +505,8 @@ static int cpuhp_invoke_ap_callback(int cpu, enum cpuhp_state state,
502
505
}
503
506
504
507
/* Regular hotplug invocation of the AP hotplug thread */
505
- static int cpuhp_kick_ap_work ( unsigned int cpu )
508
+ static void __cpuhp_kick_ap_work ( struct cpuhp_cpu_state * st )
506
509
{
507
- struct cpuhp_cpu_state * st = per_cpu_ptr (& cpuhp_state , cpu );
508
- enum cpuhp_state state = st -> state ;
509
-
510
- trace_cpuhp_enter (cpu , st -> target , state , cpuhp_kick_ap_work );
511
510
st -> result = 0 ;
512
511
st -> cb = NULL ;
513
512
/*
@@ -517,6 +516,15 @@ static int cpuhp_kick_ap_work(unsigned int cpu)
517
516
smp_mb ();
518
517
st -> should_run = true;
519
518
wake_up_process (st -> thread );
519
+ }
520
+
521
+ static int cpuhp_kick_ap_work (unsigned int cpu )
522
+ {
523
+ struct cpuhp_cpu_state * st = per_cpu_ptr (& cpuhp_state , cpu );
524
+ enum cpuhp_state state = st -> state ;
525
+
526
+ trace_cpuhp_enter (cpu , st -> target , state , cpuhp_kick_ap_work );
527
+ __cpuhp_kick_ap_work (st );
520
528
wait_for_completion (& st -> done );
521
529
trace_cpuhp_exit (cpu , st -> state , state , st -> result );
522
530
return st -> result ;
@@ -688,6 +696,9 @@ static int takedown_cpu(unsigned int cpu)
688
696
else
689
697
synchronize_rcu ();
690
698
699
+ /* Park the hotplug thread */
700
+ kthread_park (per_cpu_ptr (& cpuhp_state , cpu )-> thread );
701
+
691
702
/*
692
703
* Prevent irq alloc/free while the dying cpu reorganizes the
693
704
* interrupt affinities.
@@ -765,10 +776,34 @@ static int __ref _cpu_down(unsigned int cpu, int tasks_frozen,
765
776
766
777
prev_state = st -> state ;
767
778
st -> target = target ;
779
+ /*
780
+ * If the current CPU state is in the range of the AP hotplug thread,
781
+ * then we need to kick the thread.
782
+ */
783
+ if (st -> state >= CPUHP_KICK_AP_THREAD ) {
784
+ ret = cpuhp_kick_ap_work (cpu );
785
+ /*
786
+ * The AP side has done the error rollback already. Just
787
+ * return the error code..
788
+ */
789
+ if (ret )
790
+ goto out ;
791
+
792
+ /*
793
+ * We might have stopped still in the range of the AP hotplug
794
+ * thread. Nothing to do anymore.
795
+ */
796
+ if (st -> state >= CPUHP_KICK_AP_THREAD )
797
+ goto out ;
798
+ }
799
+ /*
800
+ * The AP brought itself down below CPUHP_KICK_AP_THREAD. So we need
801
+ * to do the further cleanups.
802
+ */
768
803
ret = cpuhp_down_callbacks (cpu , st , cpuhp_bp_states , target );
769
804
770
805
hasdied = prev_state != st -> state && st -> state == CPUHP_OFFLINE ;
771
-
806
+ out :
772
807
cpu_hotplug_done ();
773
808
/* This post dead nonsense must die */
774
809
if (!ret && hasdied )
@@ -828,10 +863,13 @@ void notify_cpu_starting(unsigned int cpu)
828
863
*/
829
864
static int cpuhp_set_cpu_active (unsigned int cpu )
830
865
{
866
+ struct cpuhp_cpu_state * st = per_cpu_ptr (& cpuhp_state , cpu );
867
+
831
868
/* The cpu is marked online, set it active now */
832
869
set_cpu_active (cpu , true);
833
- /* Unpark the stopper thread */
870
+ /* Unpark the stopper thread and the hotplug thread */
834
871
stop_machine_unpark (cpu );
872
+ kthread_unpark (st -> thread );
835
873
return 0 ;
836
874
}
837
875
@@ -868,6 +906,26 @@ static int _cpu_up(unsigned int cpu, int tasks_frozen, enum cpuhp_state target)
868
906
cpuhp_tasks_frozen = tasks_frozen ;
869
907
870
908
st -> target = target ;
909
+ /*
910
+ * If the current CPU state is in the range of the AP hotplug thread,
911
+ * then we need to kick the thread once more.
912
+ */
913
+ if (st -> state >= CPUHP_KICK_AP_THREAD ) {
914
+ ret = cpuhp_kick_ap_work (cpu );
915
+ /*
916
+ * The AP side has done the error rollback already. Just
917
+ * return the error code..
918
+ */
919
+ if (ret )
920
+ goto out ;
921
+ }
922
+
923
+ /*
924
+ * Try to reach the target state. We max out on the BP at
925
+ * CPUHP_KICK_AP_THREAD. After that the AP hotplug thread is
926
+ * responsible for bringing it up to the target state.
927
+ */
928
+ target = min ((int )target , CPUHP_KICK_AP_THREAD );
871
929
ret = cpuhp_up_callbacks (cpu , st , cpuhp_bp_states , target );
872
930
out :
873
931
cpu_hotplug_done ();
@@ -1093,19 +1151,13 @@ static struct cpuhp_step cpuhp_bp_states[] = {
1093
1151
.startup = cpuhp_set_cpu_active ,
1094
1152
.teardown = NULL ,
1095
1153
},
1096
- [CPUHP_SMPBOOT_THREADS ] = {
1097
- .name = "smpboot:threads" ,
1098
- .startup = smpboot_unpark_threads ,
1099
- .teardown = smpboot_park_threads ,
1100
- },
1101
- [CPUHP_NOTIFY_ONLINE ] = {
1102
- .name = "notify:online" ,
1103
- .startup = notify_online ,
1104
- .teardown = notify_down_prepare ,
1105
- .cant_stop = true,
1154
+ [CPUHP_KICK_AP_THREAD ] = {
1155
+ .name = "cpuhp:kickthread" ,
1156
+ .startup = cpuhp_kick_ap_work ,
1157
+ .teardown = cpuhp_kick_ap_work ,
1106
1158
},
1107
1159
#endif
1108
- [CPUHP_ONLINE ] = {
1160
+ [CPUHP_BP_ONLINE ] = {
1109
1161
.name = "online" ,
1110
1162
.startup = NULL ,
1111
1163
.teardown = NULL ,
@@ -1122,6 +1174,16 @@ static struct cpuhp_step cpuhp_ap_states[] = {
1122
1174
.skip_onerr = true,
1123
1175
.cant_stop = true,
1124
1176
},
1177
+ [CPUHP_AP_SMPBOOT_THREADS ] = {
1178
+ .name = "smpboot:threads" ,
1179
+ .startup = smpboot_unpark_threads ,
1180
+ .teardown = smpboot_park_threads ,
1181
+ },
1182
+ [CPUHP_AP_NOTIFY_ONLINE ] = {
1183
+ .name = "notify:online" ,
1184
+ .startup = notify_online ,
1185
+ .teardown = notify_down_prepare ,
1186
+ },
1125
1187
#endif
1126
1188
[CPUHP_ONLINE ] = {
1127
1189
.name = "online" ,
@@ -1140,7 +1202,9 @@ static int cpuhp_cb_check(enum cpuhp_state state)
1140
1202
1141
1203
static bool cpuhp_is_ap_state (enum cpuhp_state state )
1142
1204
{
1143
- return (state >= CPUHP_AP_OFFLINE && state <= CPUHP_AP_ONLINE );
1205
+ if (state >= CPUHP_AP_OFFLINE && state <= CPUHP_AP_ONLINE )
1206
+ return true;
1207
+ return state > CPUHP_BP_ONLINE ;
1144
1208
}
1145
1209
1146
1210
static struct cpuhp_step * cpuhp_get_step (enum cpuhp_state state )
@@ -1172,14 +1236,6 @@ static void *cpuhp_get_teardown_cb(enum cpuhp_state state)
1172
1236
return cpuhp_get_step (state )-> teardown ;
1173
1237
}
1174
1238
1175
- /* Helper function to run callback on the target cpu */
1176
- static void cpuhp_on_cpu_cb (void * __cb )
1177
- {
1178
- int (* cb )(unsigned int cpu ) = __cb ;
1179
-
1180
- BUG_ON (cb (smp_processor_id ()));
1181
- }
1182
-
1183
1239
/*
1184
1240
* Call the startup/teardown function for a step either on the AP or
1185
1241
* on the current CPU.
@@ -1191,26 +1247,18 @@ static int cpuhp_issue_call(int cpu, enum cpuhp_state state,
1191
1247
1192
1248
if (!cb )
1193
1249
return 0 ;
1194
-
1195
- /*
1196
- * This invokes the callback directly for now. In a later step we
1197
- * convert that to use cpuhp_invoke_callback().
1198
- */
1199
- if (cpuhp_is_ap_state (state )) {
1200
- /*
1201
- * Note, that a function called on the AP is not
1202
- * allowed to fail.
1203
- */
1204
- if (cpu_online (cpu ))
1205
- smp_call_function_single (cpu , cpuhp_on_cpu_cb , cb , 1 );
1206
- return 0 ;
1207
- }
1208
-
1209
1250
/*
1210
1251
* The non AP bound callbacks can fail on bringup. On teardown
1211
1252
* e.g. module removal we crash for now.
1212
1253
*/
1213
- ret = cb (cpu );
1254
+ #ifdef CONFIG_SMP
1255
+ if (cpuhp_is_ap_state (state ))
1256
+ ret = cpuhp_invoke_ap_callback (cpu , state , cb );
1257
+ else
1258
+ ret = cpuhp_invoke_callback (cpu , state , cb );
1259
+ #else
1260
+ ret = cpuhp_invoke_callback (cpu , state , cb );
1261
+ #endif
1214
1262
BUG_ON (ret && !bringup );
1215
1263
return ret ;
1216
1264
}
@@ -1252,11 +1300,11 @@ static int cpuhp_reserve_state(enum cpuhp_state state)
1252
1300
enum cpuhp_state i ;
1253
1301
1254
1302
mutex_lock (& cpuhp_state_mutex );
1255
- for (i = CPUHP_ONLINE_DYN ; i <= CPUHP_ONLINE_DYN_END ; i ++ ) {
1256
- if (cpuhp_bp_states [i ].name )
1303
+ for (i = CPUHP_AP_ONLINE_DYN ; i <= CPUHP_AP_ONLINE_DYN_END ; i ++ ) {
1304
+ if (cpuhp_ap_states [i ].name )
1257
1305
continue ;
1258
1306
1259
- cpuhp_bp_states [i ].name = "Reserved" ;
1307
+ cpuhp_ap_states [i ].name = "Reserved" ;
1260
1308
mutex_unlock (& cpuhp_state_mutex );
1261
1309
return i ;
1262
1310
}
@@ -1289,7 +1337,7 @@ int __cpuhp_setup_state(enum cpuhp_state state,
1289
1337
get_online_cpus ();
1290
1338
1291
1339
/* currently assignments for the ONLINE state are possible */
1292
- if (state == CPUHP_ONLINE_DYN ) {
1340
+ if (state == CPUHP_AP_ONLINE_DYN ) {
1293
1341
dyn_state = 1 ;
1294
1342
ret = cpuhp_reserve_state (state );
1295
1343
if (ret < 0 )
0 commit comments