hc
2024-12-19 9370bb92b2d16684ee45cf24e879c93c509162da
kernel/arch/mips/kernel/smp-cps.c
....@@ -1,11 +1,7 @@
1
+// SPDX-License-Identifier: GPL-2.0-or-later
12 /*
23 * Copyright (C) 2013 Imagination Technologies
34 * Author: Paul Burton <paul.burton@mips.com>
4
- *
5
- * This program is free software; you can redistribute it and/or modify it
6
- * under the terms of the GNU General Public License as published by the
7
- * Free Software Foundation; either version 2 of the License, or (at your
8
- * option) any later version.
95 */
106
117 #include <linux/cpu.h>
....@@ -398,6 +394,57 @@
398394 local_irq_enable();
399395 }
400396
397
+#if defined(CONFIG_HOTPLUG_CPU) || defined(CONFIG_KEXEC)
398
+
399
+enum cpu_death {
400
+ CPU_DEATH_HALT,
401
+ CPU_DEATH_POWER,
402
+};
403
+
404
+static void cps_shutdown_this_cpu(enum cpu_death death)
405
+{
406
+ unsigned int cpu, core, vpe_id;
407
+
408
+ cpu = smp_processor_id();
409
+ core = cpu_core(&cpu_data[cpu]);
410
+
411
+ if (death == CPU_DEATH_HALT) {
412
+ vpe_id = cpu_vpe_id(&cpu_data[cpu]);
413
+
414
+ pr_debug("Halting core %d VP%d\n", core, vpe_id);
415
+ if (cpu_has_mipsmt) {
416
+ /* Halt this TC */
417
+ write_c0_tchalt(TCHALT_H);
418
+ instruction_hazard();
419
+ } else if (cpu_has_vp) {
420
+ write_cpc_cl_vp_stop(1 << vpe_id);
421
+
422
+ /* Ensure that the VP_STOP register is written */
423
+ wmb();
424
+ }
425
+ } else {
426
+ if (IS_ENABLED(CONFIG_HOTPLUG_CPU)) {
427
+ pr_debug("Gating power to core %d\n", core);
428
+ /* Power down the core */
429
+ cps_pm_enter_state(CPS_PM_POWER_GATED);
430
+ }
431
+ }
432
+}
433
+
434
+#ifdef CONFIG_KEXEC
435
+
436
+static void cps_kexec_nonboot_cpu(void)
437
+{
438
+ if (cpu_has_mipsmt || cpu_has_vp)
439
+ cps_shutdown_this_cpu(CPU_DEATH_HALT);
440
+ else
441
+ cps_shutdown_this_cpu(CPU_DEATH_POWER);
442
+}
443
+
444
+#endif /* CONFIG_KEXEC */
445
+
446
+#endif /* CONFIG_HOTPLUG_CPU || CONFIG_KEXEC */
447
+
401448 #ifdef CONFIG_HOTPLUG_CPU
402449
403450 static int cps_cpu_disable(void)
....@@ -421,19 +468,15 @@
421468 }
422469
423470 static unsigned cpu_death_sibling;
424
-static enum {
425
- CPU_DEATH_HALT,
426
- CPU_DEATH_POWER,
427
-} cpu_death;
471
+static enum cpu_death cpu_death;
428472
429473 void play_dead(void)
430474 {
431
- unsigned int cpu, core, vpe_id;
475
+ unsigned int cpu;
432476
433477 local_irq_disable();
434478 idle_task_exit();
435479 cpu = smp_processor_id();
436
- core = cpu_core(&cpu_data[cpu]);
437480 cpu_death = CPU_DEATH_POWER;
438481
439482 pr_debug("CPU%d going offline\n", cpu);
....@@ -456,25 +499,7 @@
456499 /* This CPU has chosen its way out */
457500 (void)cpu_report_death();
458501
459
- if (cpu_death == CPU_DEATH_HALT) {
460
- vpe_id = cpu_vpe_id(&cpu_data[cpu]);
461
-
462
- pr_debug("Halting core %d VP%d\n", core, vpe_id);
463
- if (cpu_has_mipsmt) {
464
- /* Halt this TC */
465
- write_c0_tchalt(TCHALT_H);
466
- instruction_hazard();
467
- } else if (cpu_has_vp) {
468
- write_cpc_cl_vp_stop(1 << vpe_id);
469
-
470
- /* Ensure that the VP_STOP register is written */
471
- wmb();
472
- }
473
- } else {
474
- pr_debug("Gating power to core %d\n", core);
475
- /* Power down the core */
476
- cps_pm_enter_state(CPS_PM_POWER_GATED);
477
- }
502
+ cps_shutdown_this_cpu(cpu_death);
478503
479504 /* This should never be reached */
480505 panic("Failed to offline CPU %u", cpu);
....@@ -593,6 +618,9 @@
593618 .cpu_disable = cps_cpu_disable,
594619 .cpu_die = cps_cpu_die,
595620 #endif
621
+#ifdef CONFIG_KEXEC
622
+ .kexec_nonboot_cpu = cps_kexec_nonboot_cpu,
623
+#endif
596624 };
597625
598626 bool mips_cps_smp_in_use(void)