0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012 #include <linux/linkage.h>
0013 #include "vlock.h"
0014
0015
0016 #if VLOCK_VOTING_SIZE > 4
0017 #define FEW(x...)
0018 #define MANY(x...) x
0019 #else
0020 #define FEW(x...) x
0021 #define MANY(x...)
0022 #endif
0023
0024 @ voting lock for first-man coordination
0025
0026 .macro voting_begin rbase:req, rcpu:req, rscratch:req
0027 mov \rscratch, #1
0028 strb \rscratch, [\rbase, \rcpu]
0029 dmb
0030 .endm
0031
0032 .macro voting_end rbase:req, rcpu:req, rscratch:req
0033 dmb
0034 mov \rscratch, #0
0035 strb \rscratch, [\rbase, \rcpu]
0036 dsb st
0037 sev
0038 .endm
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048 @ r0: lock structure base
0049 @ r1: CPU ID (0-based index within cluster)
0050 ENTRY(vlock_trylock)
0051 add r1, r1, #VLOCK_VOTING_OFFSET
0052
0053 voting_begin r0, r1, r2
0054
0055 ldrb r2, [r0, #VLOCK_OWNER_OFFSET] @ check whether lock is held
0056 cmp r2, #VLOCK_OWNER_NONE
0057 bne trylock_fail @ fail if so
0058
0059 @ Control dependency implies strb not observable before previous ldrb.
0060
0061 strb r1, [r0, #VLOCK_OWNER_OFFSET] @ submit my vote
0062
0063 voting_end r0, r1, r2 @ implies DMB
0064
0065 @ Wait for the current round of voting to finish:
0066
0067 MANY( mov r3, #VLOCK_VOTING_OFFSET )
0068 0:
0069 MANY( ldr r2, [r0, r3] )
0070 FEW( ldr r2, [r0, #VLOCK_VOTING_OFFSET] )
0071 cmp r2, #0
0072 wfene
0073 bne 0b
0074 MANY( add r3, r3, #4 )
0075 MANY( cmp r3, #VLOCK_VOTING_OFFSET + VLOCK_VOTING_SIZE )
0076 MANY( bne 0b )
0077
0078 @ Check who won:
0079
0080 dmb
0081 ldrb r2, [r0, #VLOCK_OWNER_OFFSET]
0082 eor r0, r1, r2 @ zero if I won, else nonzero
0083 bx lr
0084
0085 trylock_fail:
0086 voting_end r0, r1, r2
0087 mov r0, #1 @ nonzero indicates that I lost
0088 bx lr
0089 ENDPROC(vlock_trylock)
0090
0091 @ r0: lock structure base
0092 ENTRY(vlock_unlock)
0093 dmb
0094 mov r1, #VLOCK_OWNER_NONE
0095 strb r1, [r0, #VLOCK_OWNER_OFFSET]
0096 dsb st
0097 sev
0098 bx lr
0099 ENDPROC(vlock_unlock)