arm64: spinlock: Ensure forward-progress in spin_unlock_wait
authorWill Deacon <will.deacon@arm.com>
Thu, 2 Jun 2016 17:40:07 +0000 (18:40 +0100)
committerWill Deacon <will.deacon@arm.com>
Wed, 15 Jun 2016 10:23:14 +0000 (11:23 +0100)
commitc56bdcac153e60d96a619a59c7981f2a78cba598
tree059c7c94fd3b0b0e608a993724108583ee6219f3
parent3a5facd09da848193f5bcb0dea098a298bc1a29d
arm64: spinlock: Ensure forward-progress in spin_unlock_wait

Rather than wait until we observe the lock being free (which might never
happen), we can also return from spin_unlock_wait if we observe that the
lock is now held by somebody else, which implies that it was unlocked
but we just missed seeing it in that state.

Furthermore, in such a scenario there is no longer a need to write back
the value that we loaded, since we know that there has been a lock
hand-off, which is sufficient to publish any stores prior to the
unlock_wait because the ARm architecture ensures that a Store-Release
instruction is multi-copy atomic when observed by a Load-Acquire
instruction.

The litmus test is something like:

AArch64
{
0:X1=x; 0:X3=y;
1:X1=y;
2:X1=y; 2:X3=x;
}
 P0          | P1           | P2           ;
 MOV W0,#1   | MOV W0,#1    | LDAR W0,[X1] ;
 STR W0,[X1] | STLR W0,[X1] | LDR W2,[X3]  ;
 DMB SY      |              |              ;
 LDR W2,[X3] |              |              ;
exists
(0:X2=0 /\ 2:X0=1 /\ 2:X2=0)

where P0 is doing spin_unlock_wait, P1 is doing spin_unlock and P2 is
doing spin_lock.

Signed-off-by: Will Deacon <will.deacon@arm.com>
arch/arm64/include/asm/spinlock.h