aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorShreyas B. Prabhu <shreyas@linux.vnet.ibm.com>2015-07-06 16:09:23 -0400
committerMichael Ellerman <mpe@ellerman.id.au>2015-07-06 20:16:52 -0400
commitb32aadc1a8ed84afbe924cd2ced31cd6a2e67074 (patch)
treedf7b688ff244a67421b3c6ba93c901f1f7f138e9
parenta8956a7b7232da5f4ce4a305c72a54cc5e4a8307 (diff)
powerpc/powernv: Fix race in updating core_idle_state
core_idle_state is maintained for each core. It uses 0-7 bits to track whether a thread in the core has entered fastsleep or winkle. 8th bit is used as a lock bit. The lock bit is set in these 2 scenarios- - The thread is first in subcore to wakeup from sleep/winkle. - If its the last thread in the core about to enter sleep/winkle While the lock bit is set, if any other thread in the core wakes up, it loops until the lock bit is cleared before proceeding in the wakeup path. This helps prevent race conditions w.r.t fastsleep workaround and prevents threads from switching to process context before core/subcore resources are restored. But, in the path to sleep/winkle entry, we currently don't check for lock-bit. This exposes us to following race when running with subcore on- First thread in the subcorea Another thread in the same waking up core entering sleep/winkle lwarx r15,0,r14 ori r15,r15,PNV_CORE_IDLE_LOCK_BIT stwcx. r15,0,r14 [Code to restore subcore state] lwarx r15,0,r14 [clear thread bit] stwcx. r15,0,r14 andi. r15,r15,PNV_CORE_IDLE_THREAD_BITS stw r15,0(r14) Here, after the thread entering sleep clears its thread bit in core_idle_state, the value is overwritten by the thread waking up. In such cases when the core enters fastsleep, code mistakes an idle thread as running. Because of this, the first thread waking up from fastsleep which is supposed to resync timebase skips it. So we can end up having a core with stale timebase value. This patch fixes the above race by looping on the lock bit even while entering the idle states. Signed-off-by: Shreyas B. Prabhu <shreyas@linux.vnet.ibm.com> Fixes: 7b54e9f213f76 'powernv/powerpc: Add winkle support for offline cpus' Cc: stable@vger.kernel.org # 3.19+ Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
-rw-r--r--arch/powerpc/kernel/idle_power7.S31
1 files changed, 21 insertions, 10 deletions
diff --git a/arch/powerpc/kernel/idle_power7.S b/arch/powerpc/kernel/idle_power7.S
index ccde8f084ce4..112ccf497562 100644
--- a/arch/powerpc/kernel/idle_power7.S
+++ b/arch/powerpc/kernel/idle_power7.S
@@ -52,6 +52,22 @@
52 .text 52 .text
53 53
54/* 54/*
55 * Used by threads when the lock bit of core_idle_state is set.
56 * Threads will spin in HMT_LOW until the lock bit is cleared.
57 * r14 - pointer to core_idle_state
58 * r15 - used to load contents of core_idle_state
59 */
60
61core_idle_lock_held:
62 HMT_LOW
633: lwz r15,0(r14)
64 andi. r15,r15,PNV_CORE_IDLE_LOCK_BIT
65 bne 3b
66 HMT_MEDIUM
67 lwarx r15,0,r14
68 blr
69
70/*
55 * Pass requested state in r3: 71 * Pass requested state in r3:
56 * r3 - PNV_THREAD_NAP/SLEEP/WINKLE 72 * r3 - PNV_THREAD_NAP/SLEEP/WINKLE
57 * 73 *
@@ -150,6 +166,10 @@ power7_enter_nap_mode:
150 ld r14,PACA_CORE_IDLE_STATE_PTR(r13) 166 ld r14,PACA_CORE_IDLE_STATE_PTR(r13)
151lwarx_loop1: 167lwarx_loop1:
152 lwarx r15,0,r14 168 lwarx r15,0,r14
169
170 andi. r9,r15,PNV_CORE_IDLE_LOCK_BIT
171 bnel core_idle_lock_held
172
153 andc r15,r15,r7 /* Clear thread bit */ 173 andc r15,r15,r7 /* Clear thread bit */
154 174
155 andi. r15,r15,PNV_CORE_IDLE_THREAD_BITS 175 andi. r15,r15,PNV_CORE_IDLE_THREAD_BITS
@@ -294,7 +314,7 @@ lwarx_loop2:
294 * workaround undo code or resyncing timebase or restoring context 314 * workaround undo code or resyncing timebase or restoring context
295 * In either case loop until the lock bit is cleared. 315 * In either case loop until the lock bit is cleared.
296 */ 316 */
297 bne core_idle_lock_held 317 bnel core_idle_lock_held
298 318
299 cmpwi cr2,r15,0 319 cmpwi cr2,r15,0
300 lbz r4,PACA_SUBCORE_SIBLING_MASK(r13) 320 lbz r4,PACA_SUBCORE_SIBLING_MASK(r13)
@@ -319,15 +339,6 @@ lwarx_loop2:
319 isync 339 isync
320 b common_exit 340 b common_exit
321 341
322core_idle_lock_held:
323 HMT_LOW
324core_idle_lock_loop:
325 lwz r15,0(14)
326 andi. r9,r15,PNV_CORE_IDLE_LOCK_BIT
327 bne core_idle_lock_loop
328 HMT_MEDIUM
329 b lwarx_loop2
330
331first_thread_in_subcore: 342first_thread_in_subcore:
332 /* First thread in subcore to wakeup */ 343 /* First thread in subcore to wakeup */
333 ori r15,r15,PNV_CORE_IDLE_LOCK_BIT 344 ori r15,r15,PNV_CORE_IDLE_LOCK_BIT