|
@@ -68,7 +68,7 @@ static int pnv_save_sprs_for_deep_states(void)
|
|
* all cpus at boot. Get these reg values of current cpu and use the
|
|
* all cpus at boot. Get these reg values of current cpu and use the
|
|
* same across all cpus.
|
|
* same across all cpus.
|
|
*/
|
|
*/
|
|
- uint64_t lpcr_val = mfspr(SPRN_LPCR) & ~(u64)LPCR_PECE1;
|
|
|
|
|
|
+ uint64_t lpcr_val = mfspr(SPRN_LPCR);
|
|
uint64_t hid0_val = mfspr(SPRN_HID0);
|
|
uint64_t hid0_val = mfspr(SPRN_HID0);
|
|
uint64_t hid1_val = mfspr(SPRN_HID1);
|
|
uint64_t hid1_val = mfspr(SPRN_HID1);
|
|
uint64_t hid4_val = mfspr(SPRN_HID4);
|
|
uint64_t hid4_val = mfspr(SPRN_HID4);
|
|
@@ -355,6 +355,14 @@ void power9_idle(void)
|
|
}
|
|
}
|
|
|
|
|
|
#ifdef CONFIG_HOTPLUG_CPU
|
|
#ifdef CONFIG_HOTPLUG_CPU
|
|
|
|
+static void pnv_program_cpu_hotplug_lpcr(unsigned int cpu, u64 lpcr_val)
|
|
|
|
+{
|
|
|
|
+ u64 pir = get_hard_smp_processor_id(cpu);
|
|
|
|
+
|
|
|
|
+ mtspr(SPRN_LPCR, lpcr_val);
|
|
|
|
+ opal_slw_set_reg(pir, SPRN_LPCR, lpcr_val);
|
|
|
|
+}
|
|
|
|
+
|
|
/*
|
|
/*
|
|
* pnv_cpu_offline: A function that puts the CPU into the deepest
|
|
* pnv_cpu_offline: A function that puts the CPU into the deepest
|
|
* available platform idle state on a CPU-Offline.
|
|
* available platform idle state on a CPU-Offline.
|
|
@@ -364,6 +372,20 @@ unsigned long pnv_cpu_offline(unsigned int cpu)
|
|
{
|
|
{
|
|
unsigned long srr1;
|
|
unsigned long srr1;
|
|
u32 idle_states = pnv_get_supported_cpuidle_states();
|
|
u32 idle_states = pnv_get_supported_cpuidle_states();
|
|
|
|
+ u64 lpcr_val;
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * We don't want to take decrementer interrupts while we are
|
|
|
|
+ * offline, so clear LPCR:PECE1. We keep PECE2 (and
|
|
|
|
+ * LPCR_PECE_HVEE on P9) enabled as to let IPIs in.
|
|
|
|
+ *
|
|
|
|
+ * If the CPU gets woken up by a special wakeup, ensure that
|
|
|
|
+ * the SLW engine sets LPCR with decrementer bit cleared, else
|
|
|
|
+ * the CPU will come back to the kernel due to a spurious
|
|
|
|
+ * wakeup.
|
|
|
|
+ */
|
|
|
|
+ lpcr_val = mfspr(SPRN_LPCR) & ~(u64)LPCR_PECE1;
|
|
|
|
+ pnv_program_cpu_hotplug_lpcr(cpu, lpcr_val);
|
|
|
|
|
|
__ppc64_runlatch_off();
|
|
__ppc64_runlatch_off();
|
|
|
|
|
|
@@ -394,6 +416,16 @@ unsigned long pnv_cpu_offline(unsigned int cpu)
|
|
|
|
|
|
__ppc64_runlatch_on();
|
|
__ppc64_runlatch_on();
|
|
|
|
|
|
|
|
+ /*
|
|
|
|
+ * Re-enable decrementer interrupts in LPCR.
|
|
|
|
+ *
|
|
|
|
+ * Further, we want stop states to be woken up by decrementer
|
|
|
|
+ * for non-hotplug cases. So program the LPCR via stop api as
|
|
|
|
+ * well.
|
|
|
|
+ */
|
|
|
|
+ lpcr_val = mfspr(SPRN_LPCR) | (u64)LPCR_PECE1;
|
|
|
|
+ pnv_program_cpu_hotplug_lpcr(cpu, lpcr_val);
|
|
|
|
+
|
|
return srr1;
|
|
return srr1;
|
|
}
|
|
}
|
|
#endif
|
|
#endif
|