summaryrefslogtreecommitdiffstats
path: root/arch/tile/lib
diff options
context:
space:
mode:
authorChris Metcalf2015-04-28 19:02:26 +0200
committerChris Metcalf2015-04-29 04:43:13 +0200
commit14c3dec2a875d898262be79c0f85e5f2b70a71b0 (patch)
tree19bd68642900f5e232d0eaaa7283690b68af8135 /arch/tile/lib
parentLinux 4.1-rc1 (diff)
downloadkernel-qcow2-linux-14c3dec2a875d898262be79c0f85e5f2b70a71b0.tar.gz
kernel-qcow2-linux-14c3dec2a875d898262be79c0f85e5f2b70a71b0.tar.xz
kernel-qcow2-linux-14c3dec2a875d898262be79c0f85e5f2b70a71b0.zip
tile: modify arch_spin_unlock_wait() semantics
Rather than trying to wait until all possible lockers have unlocked the lock, we now only wait until the current locker (if any) has released the lock. The old code was correct, but the new code works more like the x86 code and thus hopefully is more appropriate under contention. See commit 78bff1c8684f ("x86/ticketlock: Fix spin_unlock_wait() livelock") for x86. Signed-off-by: Chris Metcalf <cmetcalf@ezchip.com>
Diffstat (limited to 'arch/tile/lib')
-rw-r--r--arch/tile/lib/spinlock_32.c11
-rw-r--r--arch/tile/lib/spinlock_64.c11
2 files changed, 20 insertions, 2 deletions
diff --git a/arch/tile/lib/spinlock_32.c b/arch/tile/lib/spinlock_32.c
index b34f79aada48..88c2a53362e7 100644
--- a/arch/tile/lib/spinlock_32.c
+++ b/arch/tile/lib/spinlock_32.c
@@ -65,8 +65,17 @@ EXPORT_SYMBOL(arch_spin_trylock);
void arch_spin_unlock_wait(arch_spinlock_t *lock)
{
u32 iterations = 0;
- while (arch_spin_is_locked(lock))
+ int curr = READ_ONCE(lock->current_ticket);
+ int next = READ_ONCE(lock->next_ticket);
+
+ /* Return immediately if unlocked. */
+ if (next == curr)
+ return;
+
+ /* Wait until the current locker has released the lock. */
+ do {
delay_backoff(iterations++);
+ } while (READ_ONCE(lock->current_ticket) == curr);
}
EXPORT_SYMBOL(arch_spin_unlock_wait);
diff --git a/arch/tile/lib/spinlock_64.c b/arch/tile/lib/spinlock_64.c
index d6fb9581e980..c8d1f94ff1fe 100644
--- a/arch/tile/lib/spinlock_64.c
+++ b/arch/tile/lib/spinlock_64.c
@@ -65,8 +65,17 @@ EXPORT_SYMBOL(arch_spin_trylock);
void arch_spin_unlock_wait(arch_spinlock_t *lock)
{
u32 iterations = 0;
- while (arch_spin_is_locked(lock))
+ u32 val = READ_ONCE(lock->lock);
+ u32 curr = arch_spin_current(val);
+
+ /* Return immediately if unlocked. */
+ if (arch_spin_next(val) == curr)
+ return;
+
+ /* Wait until the current locker has released the lock. */
+ do {
delay_backoff(iterations++);
+ } while (arch_spin_current(READ_ONCE(lock->lock)) == curr);
}
EXPORT_SYMBOL(arch_spin_unlock_wait);