aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGautham R. Shenoy <ego@linux.vnet.ibm.com>2017-02-27 00:40:07 -0500
committerMichael Ellerman <mpe@ellerman.id.au>2017-03-02 19:24:50 -0500
commit424f8acd328a111319ae30bf384e5dfb9bc8f8cb (patch)
tree348d5c63218de5501791d521fd5df93ce7a7cf59
parent7a70d7288c926ae88e0c773fbb506aa374e99c2d (diff)
powerpc/powernv: Fix bug due to labeling ambiguity in power_enter_stop
Commit 09206b600c76 ("powernv: Pass PSSCR value and mask to power9_idle_stop") added additional code in power_enter_stop() to distinguish between stop requests whose PSSCR had ESL=EC=1 from those which did not. When ESL=EC=1, we do a forward-jump to a location labelled by "1", which had the code to handle the ESL=EC=1 case. Unfortunately just a couple of instructions before this label, is the macro IDLE_STATE_ENTER_SEQ() which also has a label "1" in its expansion. As a result, the current code can result in directly executing stop instruction for deep stop requests with PSSCR ESL=EC=1, without saving the hypervisor state. Fix this BUG by labeling the location that handles ESL=EC=1 case with a more descriptive label ".Lhandle_esl_ec_set" (local label suggestion a la .Lxx from Anton Blanchard). While at it, rename the label "2" labelling the location of the code handling entry into deep stop states with ".Lhandle_deep_stop". For a good measure, change the label in IDLE_STATE_ENTER_SEQ() macro to an not-so commonly used value in order to avoid similar mishaps in the future. Fixes: 09206b600c76 ("powernv: Pass PSSCR value and mask to power9_idle_stop") Signed-off-by: Gautham R. Shenoy <ego@linux.vnet.ibm.com> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
-rw-r--r--arch/powerpc/include/asm/cpuidle.h4
-rw-r--r--arch/powerpc/kernel/idle_book3s.S10
2 files changed, 8 insertions, 6 deletions
diff --git a/arch/powerpc/include/asm/cpuidle.h b/arch/powerpc/include/asm/cpuidle.h
index fd321eb423cb..155731557c9b 100644
--- a/arch/powerpc/include/asm/cpuidle.h
+++ b/arch/powerpc/include/asm/cpuidle.h
@@ -70,8 +70,8 @@ static inline void report_invalid_psscr_val(u64 psscr_val, int err)
70 std r0,0(r1); \ 70 std r0,0(r1); \
71 ptesync; \ 71 ptesync; \
72 ld r0,0(r1); \ 72 ld r0,0(r1); \
731: cmpd cr0,r0,r0; \ 73236: cmpd cr0,r0,r0; \
74 bne 1b; \ 74 bne 236b; \
75 IDLE_INST; \ 75 IDLE_INST; \
76 76
77#define IDLE_STATE_ENTER_SEQ_NORET(IDLE_INST) \ 77#define IDLE_STATE_ENTER_SEQ_NORET(IDLE_INST) \
diff --git a/arch/powerpc/kernel/idle_book3s.S b/arch/powerpc/kernel/idle_book3s.S
index 5f61cc0349c0..995728736677 100644
--- a/arch/powerpc/kernel/idle_book3s.S
+++ b/arch/powerpc/kernel/idle_book3s.S
@@ -276,19 +276,21 @@ power_enter_stop:
276 */ 276 */
277 andis. r4,r3,PSSCR_EC_ESL_MASK_SHIFTED 277 andis. r4,r3,PSSCR_EC_ESL_MASK_SHIFTED
278 clrldi r3,r3,60 /* r3 = Bits[60:63] = Requested Level (RL) */ 278 clrldi r3,r3,60 /* r3 = Bits[60:63] = Requested Level (RL) */
279 bne 1f 279 bne .Lhandle_esl_ec_set
280 IDLE_STATE_ENTER_SEQ(PPC_STOP) 280 IDLE_STATE_ENTER_SEQ(PPC_STOP)
281 li r3,0 /* Since we didn't lose state, return 0 */ 281 li r3,0 /* Since we didn't lose state, return 0 */
282 b pnv_wakeup_noloss 282 b pnv_wakeup_noloss
283
284.Lhandle_esl_ec_set:
283/* 285/*
284 * Check if the requested state is a deep idle state. 286 * Check if the requested state is a deep idle state.
285 */ 287 */
2861: LOAD_REG_ADDRBASE(r5,pnv_first_deep_stop_state) 288 LOAD_REG_ADDRBASE(r5,pnv_first_deep_stop_state)
287 ld r4,ADDROFF(pnv_first_deep_stop_state)(r5) 289 ld r4,ADDROFF(pnv_first_deep_stop_state)(r5)
288 cmpd r3,r4 290 cmpd r3,r4
289 bge 2f 291 bge .Lhandle_deep_stop
290 IDLE_STATE_ENTER_SEQ_NORET(PPC_STOP) 292 IDLE_STATE_ENTER_SEQ_NORET(PPC_STOP)
2912: 293.Lhandle_deep_stop:
292/* 294/*
293 * Entering deep idle state. 295 * Entering deep idle state.
294 * Clear thread bit in PACA_CORE_IDLE_STATE, save SPRs to 296 * Clear thread bit in PACA_CORE_IDLE_STATE, save SPRs to