diff options
-rw-r--r-- | core/cpu.c | 91 | ||||
-rw-r--r-- | core/fast-reboot.c | 3 | ||||
-rw-r--r-- | core/init.c | 10 | ||||
-rw-r--r-- | include/cpu.h | 8 |
4 files changed, 74 insertions, 38 deletions
@@ -52,6 +52,8 @@ static bool hile_supported; static bool radix_supported; static unsigned long hid0_hile; static unsigned long hid0_attn; +static bool sreset_enabled; +static bool ipi_enabled; static bool pm_enabled; static bool current_hile_mode; static bool current_radix_mode; @@ -321,9 +323,7 @@ static void cpu_idle_p8(enum cpu_wake_cause wake_on) mtspr(SPR_LPCR, lpcr); } else { - /* Mark outselves sleeping so cpu_set_pm_enable knows to - * send an IPI - */ + /* Mark outselves sleeping so wakeup knows to send an IPI */ cpu->in_sleep = true; sync(); @@ -346,35 +346,6 @@ skip_sleep: reset_cpu_icp(); } -void cpu_set_pm_enable(bool enabled) -{ - struct cpu_thread *cpu; - - prlog(PR_INFO, "CPU: %sing power management\n", - enabled ? "enabl" : "disabl"); - - if (proc_gen != proc_gen_p8) - return; - - /* Public P8 Mambo has broken NAP */ - if (chip_quirk(QUIRK_MAMBO_CALLOUTS)) - return; - - pm_enabled = enabled; - - if (enabled) - return; - - /* If disabling, take everybody out of PM */ - sync(); - for_each_available_cpu(cpu) { - while (cpu->in_sleep || cpu->in_idle) { - icp_kick_cpu(cpu); - cpu_relax(); - } - } -} - static void cpu_idle_pm(enum cpu_wake_cause wake_on) { switch(proc_gen) { @@ -444,6 +415,62 @@ no_pm: } } +static void cpu_pm_disable(void) +{ + struct cpu_thread *cpu; + + pm_enabled = false; + sync(); + + if (proc_gen == proc_gen_p8) { + for_each_available_cpu(cpu) { + while (cpu->in_sleep || cpu->in_idle) { + icp_kick_cpu(cpu); + cpu_relax(); + } + } + } +} + +void cpu_set_sreset_enable(bool enabled) +{ + if (sreset_enabled == enabled) + return; + + if (proc_gen == proc_gen_p8) { + /* Public P8 Mambo has broken NAP */ + if (chip_quirk(QUIRK_MAMBO_CALLOUTS)) + return; + + sreset_enabled = enabled; + sync(); + + if (!enabled) { + cpu_pm_disable(); + } else { + if (ipi_enabled) + pm_enabled = true; + } + } +} + +void cpu_set_ipi_enable(bool enabled) +{ + if (ipi_enabled == enabled) + return; + + if (proc_gen == proc_gen_p8) { + ipi_enabled = enabled; + sync(); + if (!enabled) { + cpu_pm_disable(); + } else { + if (sreset_enabled) + pm_enabled = true; + } + } +} + void cpu_process_local_jobs(void) { struct cpu_thread *cpu = first_available_cpu(); diff --git a/core/fast-reboot.c b/core/fast-reboot.c index 7bfc06d..8af5c59 100644 --- a/core/fast-reboot.c +++ b/core/fast-reboot.c @@ -564,7 +564,8 @@ void __noreturn fast_reboot_entry(void) cpu_fast_reboot_complete(); /* We can now do NAP mode */ - cpu_set_pm_enable(true); + cpu_set_sreset_enable(true); + cpu_set_ipi_enable(true); /* Start preloading kernel and ramdisk */ start_preload_kernel(); diff --git a/core/init.c b/core/init.c index ab260d4..be49c3f 100644 --- a/core/init.c +++ b/core/init.c @@ -382,7 +382,7 @@ static bool load_kernel(void) * by our vectors. */ if (kernel_entry < 0x2000) { - cpu_set_pm_enable(false); + cpu_set_sreset_enable(false); memcpy(NULL, old_vectors, 0x2000); sync_icache(); } @@ -545,7 +545,8 @@ void __noreturn load_and_boot_kernel(bool is_reboot) mem_dump_free(); /* Take processours out of nap */ - cpu_set_pm_enable(false); + cpu_set_sreset_enable(false); + cpu_set_ipi_enable(false); /* Dump the selected console */ stdoutp = dt_prop_get_def(dt_chosen, "linux,stdout-path", NULL); @@ -725,6 +726,7 @@ void setup_reset_vector(void) while(src < &reset_patch_end) *(dst++) = *(src++); sync_icache(); + cpu_set_sreset_enable(true); } void copy_exception_vectors(void) @@ -932,6 +934,8 @@ void __noreturn __nomcount main_cpu_entry(const void *fdt) /* On P7/P8, get the ICPs and make sure they are in a sane state */ init_interrupts(); + if (proc_gen == proc_gen_p7 || proc_gen == proc_gen_p8) + cpu_set_ipi_enable(true); /* On P9, initialize XIVE */ init_xive(); @@ -957,7 +961,7 @@ void __noreturn __nomcount main_cpu_entry(const void *fdt) setup_reset_vector(); /* We can now do NAP mode */ - cpu_set_pm_enable(true); + cpu_set_sreset_enable(true); /* * Synchronize time bases. Thi resets all the TB values to a small diff --git a/include/cpu.h b/include/cpu.h index 77419ca..168fa99 100644 --- a/include/cpu.h +++ b/include/cpu.h @@ -263,8 +263,12 @@ extern void cpu_process_jobs(void); extern void cpu_process_local_jobs(void); /* Check if there's any job pending */ bool cpu_check_jobs(struct cpu_thread *cpu); -/* Enable/disable PM */ -void cpu_set_pm_enable(bool pm_enabled); + +/* OPAL sreset vector in place at 0x100 */ +void cpu_set_sreset_enable(bool sreset_enabled); + +/* IPI for PM modes is enabled */ +void cpu_set_ipi_enable(bool sreset_enabled); static inline void cpu_give_self_os(void) { |