From 24726a1f5e41e416b1035f2486870def72a2ce8a Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Sat, 24 Jun 2017 14:17:27 -0500 Subject: [PATCH] cpu: Rework HILE change Create a more generic helper for changing HID0 bits on all processors. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Michael Neuling Signed-off-by: Stewart Smith --- core/cpu.c | 71 ++++++++++++++++++++++++++++------------------ core/fast-reboot.c | 5 ++-- include/cpu.h | 3 +- 3 files changed, 48 insertions(+), 31 deletions(-) diff --git a/core/cpu.c b/core/cpu.c index a083ed7e0df4..31f5c928bb67 100644 --- a/core/cpu.c +++ b/core/cpu.c @@ -52,6 +52,7 @@ static bool hile_supported; static unsigned long hid0_hile; static unsigned long hid0_attn; static bool pm_enabled; +static bool current_hile_mode; unsigned long cpu_secondary_start __force_data = 0; @@ -1024,44 +1025,51 @@ static int64_t opal_return_cpu(void) } opal_call(OPAL_RETURN_CPU, opal_return_cpu, 0); -static void cpu_change_hile(void *hilep) -{ - bool hile = *(bool *)hilep; - unsigned long hid0; - - hid0 = mfspr(SPR_HID0); - if (hile) - hid0 |= hid0_hile; - else - hid0 &= ~hid0_hile; - prlog(PR_DEBUG, "CPU: [%08x] HID0 set to 0x%016lx\n", - this_cpu()->pir, hid0); - set_hid0(hid0); +struct hid0_change_req { + uint64_t clr_bits; + uint64_t set_bits; +}; - this_cpu()->current_hile = hile; +static void cpu_change_hid0(void *__req) +{ + struct hid0_change_req *req = __req; + unsigned long hid0, new_hid0; + + hid0 = new_hid0 = mfspr(SPR_HID0); + new_hid0 &= ~req->clr_bits; + new_hid0 |= req->set_bits; + prlog(PR_DEBUG, "CPU: [%08x] HID0 change 0x%016lx -> 0x%016lx\n", + this_cpu()->pir, hid0, new_hid0); + set_hid0(new_hid0); } -static int64_t cpu_change_all_hile(bool hile) +static int64_t cpu_change_all_hid0(struct hid0_change_req *req) { struct cpu_thread *cpu; - prlog(PR_INFO, "CPU: Switching HILE on all CPUs to %d\n", hile); - for_each_available_cpu(cpu) { - if (cpu->current_hile == hile) + if (!cpu_is_thread0(cpu)) continue; if (cpu == this_cpu()) { - cpu_change_hile(&hile); + cpu_change_hid0(req); continue; } - cpu_wait_job(cpu_queue_job(cpu, "cpu_change_hile", - cpu_change_hile, &hile), true); + cpu_wait_job(cpu_queue_job(cpu, "cpu_change_hid0", + cpu_change_hid0, req), true); } return OPAL_SUCCESS; } +void cpu_fast_reboot_complete(void) +{ + /* Fast reboot will have cleared HID0:HILE */ + current_hile_mode = false; + +} + static int64_t opal_reinit_cpus(uint64_t flags) { + struct hid0_change_req req = { 0, 0 }; struct cpu_thread *cpu; int64_t rc = OPAL_SUCCESS; int i; @@ -1105,19 +1113,26 @@ static int64_t opal_reinit_cpus(uint64_t flags) this_cpu()->in_reinit = true; unlock(&reinit_lock); - /* - * If the flags affect endianness and we are on P8 DD2 or later, then - * use the HID bit. We use the PVR (we could use the EC level in - * the chip but the PVR is more readily available). - */ + /* If HILE change via HID0 is supported ... */ if (hile_supported && - (flags & (OPAL_REINIT_CPUS_HILE_BE | OPAL_REINIT_CPUS_HILE_LE))) { + (flags & (OPAL_REINIT_CPUS_HILE_BE | + OPAL_REINIT_CPUS_HILE_LE))) { bool hile = !!(flags & OPAL_REINIT_CPUS_HILE_LE); flags &= ~(OPAL_REINIT_CPUS_HILE_BE | OPAL_REINIT_CPUS_HILE_LE); - rc = cpu_change_all_hile(hile); + if (hile != current_hile_mode) { + if (hile) + req.set_bits |= hid0_hile; + else + req.clr_bits |= hid0_hile; + current_hile_mode = hile; + } } + /* Apply HID bits changes if any */ + if (req.set_bits || req.clr_bits) + cpu_change_all_hid0(&req); + /* If we have a P7, error out for LE switch, do nothing for BE */ if (proc_gen < proc_gen_p8) { if (flags & OPAL_REINIT_CPUS_HILE_LE) diff --git a/core/fast-reboot.c b/core/fast-reboot.c index 884441df7cc0..7bfc06dee0e2 100644 --- a/core/fast-reboot.c +++ b/core/fast-reboot.c @@ -370,8 +370,6 @@ static void cleanup_cpu_state(void) { struct cpu_thread *cpu = this_cpu(); - cpu->current_hile = false; - /* Per core cleanup */ if (cpu_is_thread0(cpu)) { /* Shared SPRs whacked back to normal */ @@ -562,6 +560,9 @@ void __noreturn fast_reboot_entry(void) /* Set our state to active */ this_cpu()->state = cpu_state_active; + /* Let the CPU layer do some last minute global cleanups */ + cpu_fast_reboot_complete(); + /* We can now do NAP mode */ cpu_set_pm_enable(true); diff --git a/include/cpu.h b/include/cpu.h index 0cb6389ac07e..1d19c200cd18 100644 --- a/include/cpu.h +++ b/include/cpu.h @@ -48,7 +48,6 @@ struct cpu_thread { uint32_t server_no; uint32_t chip_id; bool is_secondary; - bool current_hile; struct cpu_thread *primary; enum cpu_thread_state state; struct dt_node *node; @@ -271,4 +270,6 @@ extern unsigned long __attrconst cpu_stack_top(unsigned int pir); extern void cpu_idle_job(void); extern void cpu_idle_delay(unsigned long delay, unsigned long min_pm); +extern void cpu_fast_reboot_complete(void); + #endif /* __CPU_H */