Linux-libre 5.4.48-gnu
[librecmc/linux-libre.git] / arch / arm / common / vlock.S
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 /*
3  * vlock.S - simple voting lock implementation for ARM
4  *
5  * Created by:  Dave Martin, 2012-08-16
6  * Copyright:   (C) 2012-2013  Linaro Limited
7  *
8  * This algorithm is described in more detail in
9  * Documentation/arm/vlocks.rst.
10  */
11
12 #include <linux/linkage.h>
13 #include "vlock.h"
14
15 /* Select different code if voting flags  can fit in a single word. */
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  * The vlock structure must reside in Strongly-Ordered or Device memory.
42  * This implementation deliberately eliminates most of the barriers which
43  * would be required for other memory types, and assumes that independent
44  * writes to neighbouring locations within a cacheline do not interfere
45  * with one another.
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)