| .. | .. |
|---|
| 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 | + pr_debug("Gating power to core %d\n", core); |
|---|
| 427 | + /* Power down the core */ |
|---|
| 428 | + cps_pm_enter_state(CPS_PM_POWER_GATED); |
|---|
| 429 | + } |
|---|
| 430 | +} |
|---|
| 431 | + |
|---|
| 432 | +#ifdef CONFIG_KEXEC |
|---|
| 433 | + |
|---|
| 434 | +static void cps_kexec_nonboot_cpu(void) |
|---|
| 435 | +{ |
|---|
| 436 | + if (cpu_has_mipsmt || cpu_has_vp) |
|---|
| 437 | + cps_shutdown_this_cpu(CPU_DEATH_HALT); |
|---|
| 438 | + else |
|---|
| 439 | + cps_shutdown_this_cpu(CPU_DEATH_POWER); |
|---|
| 440 | +} |
|---|
| 441 | + |
|---|
| 442 | +#endif /* CONFIG_KEXEC */ |
|---|
| 443 | + |
|---|
| 444 | +#endif /* CONFIG_HOTPLUG_CPU || CONFIG_KEXEC */ |
|---|
| 445 | + |
|---|
| 401 | 446 | #ifdef CONFIG_HOTPLUG_CPU |
|---|
| 402 | 447 | |
|---|
| 403 | 448 | static int cps_cpu_disable(void) |
|---|
| .. | .. |
|---|
| 421 | 466 | } |
|---|
| 422 | 467 | |
|---|
| 423 | 468 | static unsigned cpu_death_sibling; |
|---|
| 424 | | -static enum { |
|---|
| 425 | | - CPU_DEATH_HALT, |
|---|
| 426 | | - CPU_DEATH_POWER, |
|---|
| 427 | | -} cpu_death; |
|---|
| 469 | +static enum cpu_death cpu_death; |
|---|
| 428 | 470 | |
|---|
| 429 | 471 | void play_dead(void) |
|---|
| 430 | 472 | { |
|---|
| 431 | | - unsigned int cpu, core, vpe_id; |
|---|
| 473 | + unsigned int cpu; |
|---|
| 432 | 474 | |
|---|
| 433 | 475 | local_irq_disable(); |
|---|
| 434 | 476 | idle_task_exit(); |
|---|
| 435 | 477 | cpu = smp_processor_id(); |
|---|
| 436 | | - core = cpu_core(&cpu_data[cpu]); |
|---|
| 437 | 478 | cpu_death = CPU_DEATH_POWER; |
|---|
| 438 | 479 | |
|---|
| 439 | 480 | pr_debug("CPU%d going offline\n", cpu); |
|---|
| .. | .. |
|---|
| 456 | 497 | /* This CPU has chosen its way out */ |
|---|
| 457 | 498 | (void)cpu_report_death(); |
|---|
| 458 | 499 | |
|---|
| 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 | | - } |
|---|
| 500 | + cps_shutdown_this_cpu(cpu_death); |
|---|
| 478 | 501 | |
|---|
| 479 | 502 | /* This should never be reached */ |
|---|
| 480 | 503 | panic("Failed to offline CPU %u", cpu); |
|---|
| .. | .. |
|---|
| 593 | 616 | .cpu_disable = cps_cpu_disable, |
|---|
| 594 | 617 | .cpu_die = cps_cpu_die, |
|---|
| 595 | 618 | #endif |
|---|
| 619 | +#ifdef CONFIG_KEXEC |
|---|
| 620 | + .kexec_nonboot_cpu = cps_kexec_nonboot_cpu, |
|---|
| 621 | +#endif |
|---|
| 596 | 622 | }; |
|---|
| 597 | 623 | |
|---|
| 598 | 624 | bool mips_cps_smp_in_use(void) |
|---|