1
2
3
4
5
6
7
8
9
10
11
12 #include <linux/linkage.h>
13 #include "vlock.h"
14
15
16 #if VLOCK_VOTING_SIZE > 4
17 #define FEW(x...)
18 #define MANY(x...) x
19 #else
20 #define FEW(x...) x
21 #define MANY(x...)
22 #endif
23
24 @ voting lock for first-man coordination
25
26 .macro voting_begin rbase:req, rcpu:req, rscratch:req
27 mov \rscratch, #1
28 strb \rscratch, [\rbase, \rcpu]
29 dmb
30 .endm
31
32 .macro voting_end rbase:req, rcpu:req, rscratch:req
33 dmb
34 mov \rscratch, #0
35 strb \rscratch, [\rbase, \rcpu]
36 dsb st
37 sev
38 .endm
39
40
41
42
43
44
45
46
47
48 @ r0: lock structure base
49 @ r1: CPU ID (0-based index within cluster)
50 ENTRY(vlock_trylock)
51 add r1, r1, #VLOCK_VOTING_OFFSET
52
53 voting_begin r0, r1, r2
54
55 ldrb r2, [r0, #VLOCK_OWNER_OFFSET] @ check whether lock is held
56 cmp r2, #VLOCK_OWNER_NONE
57 bne trylock_fail @ fail if so
58
59 @ Control dependency implies strb not observable before previous ldrb.
60
61 strb r1, [r0, #VLOCK_OWNER_OFFSET] @ submit my vote
62
63 voting_end r0, r1, r2 @ implies DMB
64
65 @ Wait for the current round of voting to finish:
66
67 MANY( mov r3, #VLOCK_VOTING_OFFSET )
68 0:
69 MANY( ldr r2, [r0, r3] )
70 FEW( ldr r2, [r0, #VLOCK_VOTING_OFFSET] )
71 cmp r2, #0
72 wfene
73 bne 0b
74 MANY( add r3, r3, #4 )
75 MANY( cmp r3, #VLOCK_VOTING_OFFSET + VLOCK_VOTING_SIZE )
76 MANY( bne 0b )
77
78 @ Check who won:
79
80 dmb
81 ldrb r2, [r0, #VLOCK_OWNER_OFFSET]
82 eor r0, r1, r2 @ zero if I won, else nonzero
83 bx lr
84
85 trylock_fail:
86 voting_end r0, r1, r2
87 mov r0, #1 @ nonzero indicates that I lost
88 bx lr
89 ENDPROC(vlock_trylock)
90
91 @ r0: lock structure base
92 ENTRY(vlock_unlock)
93 dmb
94 mov r1, #VLOCK_OWNER_NONE
95 strb r1, [r0, #VLOCK_OWNER_OFFSET]
96 dsb st
97 sev
98 bx lr
99 ENDPROC(vlock_unlock)