diff options
author | Will Deacon <will.deacon@arm.com> | 2016-06-08 10:10:57 -0400 |
---|---|---|
committer | Will Deacon <will.deacon@arm.com> | 2016-06-15 04:51:36 -0400 |
commit | 3a5facd09da848193f5bcb0dea098a298bc1a29d (patch) | |
tree | 179c031fe6a5e8d9ce4b27ea966a2e09356bf847 | |
parent | 38b850a73034f075c4088e7511b36ebbef9dce00 (diff) |
arm64: spinlock: fix spin_unlock_wait for LSE atomics
Commit d86b8da04dfa ("arm64: spinlock: serialise spin_unlock_wait against
concurrent lockers") fixed spin_unlock_wait for LL/SC-based atomics under
the premise that the LSE atomics (in particular, the LDADDA instruction)
are indivisible.
Unfortunately, these instructions are only indivisible when used with the
-AL (full ordering) suffix and, consequently, the same issue can
theoretically be observed with LSE atomics, where a later (in program
order) load can be speculated before the write portion of the atomic
operation.
This patch fixes the issue by performing a CAS of the lock once we've
established that it's unlocked, in much the same way as the LL/SC code.
Fixes: d86b8da04dfa ("arm64: spinlock: serialise spin_unlock_wait against concurrent lockers")
Signed-off-by: Will Deacon <will.deacon@arm.com>
-rw-r--r-- | arch/arm64/include/asm/spinlock.h | 10 |
1 files changed, 7 insertions, 3 deletions
diff --git a/arch/arm64/include/asm/spinlock.h b/arch/arm64/include/asm/spinlock.h index aac64d55cb22..d5c894253e73 100644 --- a/arch/arm64/include/asm/spinlock.h +++ b/arch/arm64/include/asm/spinlock.h | |||
@@ -43,13 +43,17 @@ static inline void arch_spin_unlock_wait(arch_spinlock_t *lock) | |||
43 | "2: ldaxr %w0, %2\n" | 43 | "2: ldaxr %w0, %2\n" |
44 | " eor %w1, %w0, %w0, ror #16\n" | 44 | " eor %w1, %w0, %w0, ror #16\n" |
45 | " cbnz %w1, 1b\n" | 45 | " cbnz %w1, 1b\n" |
46 | /* Serialise against any concurrent lockers */ | ||
46 | ARM64_LSE_ATOMIC_INSN( | 47 | ARM64_LSE_ATOMIC_INSN( |
47 | /* LL/SC */ | 48 | /* LL/SC */ |
48 | " stxr %w1, %w0, %2\n" | 49 | " stxr %w1, %w0, %2\n" |
49 | " cbnz %w1, 2b\n", /* Serialise against any concurrent lockers */ | ||
50 | /* LSE atomics */ | ||
51 | " nop\n" | 50 | " nop\n" |
52 | " nop\n") | 51 | " nop\n", |
52 | /* LSE atomics */ | ||
53 | " mov %w1, %w0\n" | ||
54 | " cas %w0, %w0, %2\n" | ||
55 | " eor %w1, %w1, %w0\n") | ||
56 | " cbnz %w1, 2b\n" | ||
53 | : "=&r" (lockval), "=&r" (tmp), "+Q" (*lock) | 57 | : "=&r" (lockval), "=&r" (tmp), "+Q" (*lock) |
54 | : | 58 | : |
55 | : "memory"); | 59 | : "memory"); |