Skip to content

Commit b0c5b4f

Browse files
rohanmclurempe
authored andcommitted
powerpc: powernv: Fix KCSAN datarace warnings on idle_state contention
The idle_state entry in the PACA on PowerNV features a bit which is atomically tested and set through ldarx/stdcx. to be used as a spinlock. This lock then guards access to other bit fields of idle_state. KCSAN cannot differentiate between any of these bitfield accesses as they all are implemented by 8-byte store/load instructions, thus cores contending on the bit-lock appear to data race with modifications to idle_state. Separate the bit-lock entry from the data guarded by the lock to avoid the possibility of data races being detected by KCSAN. Suggested-by: Nicholas Piggin <[email protected]> Signed-off-by: Rohan McLure <[email protected]> Reviewed-by: Nicholas Piggin <[email protected]> Signed-off-by: Michael Ellerman <[email protected]> Link: https://msgid.link/[email protected]
1 parent be286b8 commit b0c5b4f

File tree

2 files changed

+10
-7
lines changed

2 files changed

+10
-7
lines changed

arch/powerpc/include/asm/paca.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,7 @@ struct paca_struct {
191191
#ifdef CONFIG_PPC_POWERNV
192192
/* PowerNV idle fields */
193193
/* PNV_CORE_IDLE_* bits, all siblings work on thread 0 paca */
194+
unsigned long idle_lock; /* A value of 1 means acquired */
194195
unsigned long idle_state;
195196
union {
196197
/* P7/P8 specific fields */

arch/powerpc/platforms/powernv/idle.c

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -246,9 +246,9 @@ static inline void atomic_lock_thread_idle(void)
246246
{
247247
int cpu = raw_smp_processor_id();
248248
int first = cpu_first_thread_sibling(cpu);
249-
unsigned long *state = &paca_ptrs[first]->idle_state;
249+
unsigned long *lock = &paca_ptrs[first]->idle_lock;
250250

251-
while (unlikely(test_and_set_bit_lock(NR_PNV_CORE_IDLE_LOCK_BIT, state)))
251+
while (unlikely(test_and_set_bit_lock(NR_PNV_CORE_IDLE_LOCK_BIT, lock)))
252252
barrier();
253253
}
254254

@@ -258,29 +258,31 @@ static inline void atomic_unlock_and_stop_thread_idle(void)
258258
int first = cpu_first_thread_sibling(cpu);
259259
unsigned long thread = 1UL << cpu_thread_in_core(cpu);
260260
unsigned long *state = &paca_ptrs[first]->idle_state;
261+
unsigned long *lock = &paca_ptrs[first]->idle_lock;
261262
u64 s = READ_ONCE(*state);
262263
u64 new, tmp;
263264

264-
BUG_ON(!(s & PNV_CORE_IDLE_LOCK_BIT));
265+
BUG_ON(!(READ_ONCE(*lock) & PNV_CORE_IDLE_LOCK_BIT));
265266
BUG_ON(s & thread);
266267

267268
again:
268-
new = (s | thread) & ~PNV_CORE_IDLE_LOCK_BIT;
269+
new = s | thread;
269270
tmp = cmpxchg(state, s, new);
270271
if (unlikely(tmp != s)) {
271272
s = tmp;
272273
goto again;
273274
}
275+
clear_bit_unlock(NR_PNV_CORE_IDLE_LOCK_BIT, lock);
274276
}
275277

276278
static inline void atomic_unlock_thread_idle(void)
277279
{
278280
int cpu = raw_smp_processor_id();
279281
int first = cpu_first_thread_sibling(cpu);
280-
unsigned long *state = &paca_ptrs[first]->idle_state;
282+
unsigned long *lock = &paca_ptrs[first]->idle_lock;
281283

282-
BUG_ON(!test_bit(NR_PNV_CORE_IDLE_LOCK_BIT, state));
283-
clear_bit_unlock(NR_PNV_CORE_IDLE_LOCK_BIT, state);
284+
BUG_ON(!test_bit(NR_PNV_CORE_IDLE_LOCK_BIT, lock));
285+
clear_bit_unlock(NR_PNV_CORE_IDLE_LOCK_BIT, lock);
284286
}
285287

286288
/* P7 and P8 */

0 commit comments

Comments
 (0)