diff options
author | Gautham R. Shenoy <ego@linux.vnet.ibm.com> | 2017-02-27 00:40:07 -0500 |
---|---|---|
committer | Michael Ellerman <mpe@ellerman.id.au> | 2017-03-02 19:24:50 -0500 |
commit | 424f8acd328a111319ae30bf384e5dfb9bc8f8cb (patch) | |
tree | 348d5c63218de5501791d521fd5df93ce7a7cf59 | |
parent | 7a70d7288c926ae88e0c773fbb506aa374e99c2d (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.h | 4 | ||||
-rw-r--r-- | arch/powerpc/kernel/idle_book3s.S | 10 |
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); \ |
73 | 1: cmpd cr0,r0,r0; \ | 73 | 236: 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 | */ |
286 | 1: 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) |
291 | 2: | 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 |