aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/cpu.c91
-rw-r--r--core/fast-reboot.c3
-rw-r--r--core/init.c10
-rw-r--r--include/cpu.h8
4 files changed, 74 insertions, 38 deletions
diff --git a/core/cpu.c b/core/cpu.c
index cf86039..367856c 100644
--- a/core/cpu.c
+++ b/core/cpu.c
@@ -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)
{