.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
---|
1 | 2 | /* |
---|
2 | 3 | * Copyright (C) 2013 Imagination Technologies |
---|
3 | 4 | * 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. |
---|
9 | 5 | */ |
---|
10 | 6 | |
---|
11 | 7 | #include <linux/cpu.h> |
---|
.. | .. |
---|
398 | 394 | local_irq_enable(); |
---|
399 | 395 | } |
---|
400 | 396 | |
---|
| 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 | + |
---|
401 | 448 | #ifdef CONFIG_HOTPLUG_CPU |
---|
402 | 449 | |
---|
403 | 450 | static int cps_cpu_disable(void) |
---|
.. | .. |
---|
421 | 468 | } |
---|
422 | 469 | |
---|
423 | 470 | 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; |
---|
428 | 472 | |
---|
429 | 473 | void play_dead(void) |
---|
430 | 474 | { |
---|
431 | | - unsigned int cpu, core, vpe_id; |
---|
| 475 | + unsigned int cpu; |
---|
432 | 476 | |
---|
433 | 477 | local_irq_disable(); |
---|
434 | 478 | idle_task_exit(); |
---|
435 | 479 | cpu = smp_processor_id(); |
---|
436 | | - core = cpu_core(&cpu_data[cpu]); |
---|
437 | 480 | cpu_death = CPU_DEATH_POWER; |
---|
438 | 481 | |
---|
439 | 482 | pr_debug("CPU%d going offline\n", cpu); |
---|
.. | .. |
---|
456 | 499 | /* This CPU has chosen its way out */ |
---|
457 | 500 | (void)cpu_report_death(); |
---|
458 | 501 | |
---|
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); |
---|
478 | 503 | |
---|
479 | 504 | /* This should never be reached */ |
---|
480 | 505 | panic("Failed to offline CPU %u", cpu); |
---|
.. | .. |
---|
593 | 618 | .cpu_disable = cps_cpu_disable, |
---|
594 | 619 | .cpu_die = cps_cpu_die, |
---|
595 | 620 | #endif |
---|
| 621 | +#ifdef CONFIG_KEXEC |
---|
| 622 | + .kexec_nonboot_cpu = cps_kexec_nonboot_cpu, |
---|
| 623 | +#endif |
---|
596 | 624 | }; |
---|
597 | 625 | |
---|
598 | 626 | bool mips_cps_smp_in_use(void) |
---|