aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNicholas Piggin <npiggin@gmail.com>2018-04-05 01:50:49 -0400
committerMichael Ellerman <mpe@ellerman.id.au>2018-04-05 02:10:36 -0400
commita57ac411832384eb93df4bfed2bf644c4089720e (patch)
treefbfa8e9eeb925305975b80dc68abd18fc16c8fea
parenta67cc594dffd29cfe33fbee40932c9d04197ab2f (diff)
powerpc/64s: Fix dt_cpu_ftrs to have restore_cpu clear unwanted LPCR bits
Presently the dt_cpu_ftrs restore_cpu will only add bits to the LPCR for secondaries, but some bits must be removed (e.g., UPRT for HPT). Not clearing these bits on secondaries causes checkstops when booting with disable_radix. restore_cpu can not just set LPCR, because it is also called by the idle wakeup code which relies on opal_slw_set_reg to restore the value of LPCR, at least on P8 which does not save LPCR to stack in the idle code. Fix this by including a mask of bits to clear from LPCR as well, which is used by restore_cpu. This is a little messy now, but it's a minimal fix that can be backported. Longer term, the idle SPR save/restore code can be reworked to completely avoid calls to restore_cpu, then restore_cpu would be able to unconditionally set LPCR to match boot processor environment. Fixes: 5a61ef74f269f ("powerpc/64s: Support new device tree binding for discovering CPU features") Cc: stable@vger.kernel.org # v4.12+ Signed-off-by: Nicholas Piggin <npiggin@gmail.com> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
-rw-r--r--arch/powerpc/kernel/dt_cpu_ftrs.c12
1 files changed, 9 insertions, 3 deletions
diff --git a/arch/powerpc/kernel/dt_cpu_ftrs.c b/arch/powerpc/kernel/dt_cpu_ftrs.c
index 11a3a4fed3fb..ed7605d8fd2d 100644
--- a/arch/powerpc/kernel/dt_cpu_ftrs.c
+++ b/arch/powerpc/kernel/dt_cpu_ftrs.c
@@ -83,6 +83,7 @@ static int hv_mode;
83 83
84static struct { 84static struct {
85 u64 lpcr; 85 u64 lpcr;
86 u64 lpcr_clear;
86 u64 hfscr; 87 u64 hfscr;
87 u64 fscr; 88 u64 fscr;
88} system_registers; 89} system_registers;
@@ -91,6 +92,8 @@ static void (*init_pmu_registers)(void);
91 92
92static void __restore_cpu_cpufeatures(void) 93static void __restore_cpu_cpufeatures(void)
93{ 94{
95 u64 lpcr;
96
94 /* 97 /*
95 * LPCR is restored by the power on engine already. It can be changed 98 * LPCR is restored by the power on engine already. It can be changed
96 * after early init e.g., by radix enable, and we have no unified API 99 * after early init e.g., by radix enable, and we have no unified API
@@ -103,8 +106,10 @@ static void __restore_cpu_cpufeatures(void)
103 * The best we can do to accommodate secondary boot and idle restore 106 * The best we can do to accommodate secondary boot and idle restore
104 * for now is "or" LPCR with existing. 107 * for now is "or" LPCR with existing.
105 */ 108 */
106 109 lpcr = mfspr(SPRN_LPCR);
107 mtspr(SPRN_LPCR, system_registers.lpcr | mfspr(SPRN_LPCR)); 110 lpcr |= system_registers.lpcr;
111 lpcr &= ~system_registers.lpcr_clear;
112 mtspr(SPRN_LPCR, lpcr);
108 if (hv_mode) { 113 if (hv_mode) {
109 mtspr(SPRN_LPID, 0); 114 mtspr(SPRN_LPID, 0);
110 mtspr(SPRN_HFSCR, system_registers.hfscr); 115 mtspr(SPRN_HFSCR, system_registers.hfscr);
@@ -324,8 +329,9 @@ static int __init feat_enable_mmu_hash_v3(struct dt_cpu_feature *f)
324{ 329{
325 u64 lpcr; 330 u64 lpcr;
326 331
332 system_registers.lpcr_clear |= (LPCR_ISL | LPCR_UPRT | LPCR_HR);
327 lpcr = mfspr(SPRN_LPCR); 333 lpcr = mfspr(SPRN_LPCR);
328 lpcr &= ~LPCR_ISL; 334 lpcr &= ~(LPCR_ISL | LPCR_UPRT | LPCR_HR);
329 mtspr(SPRN_LPCR, lpcr); 335 mtspr(SPRN_LPCR, lpcr);
330 336
331 cur_cpu_spec->mmu_features |= MMU_FTRS_HASH_BASE; 337 cur_cpu_spec->mmu_features |= MMU_FTRS_HASH_BASE;