Merge branch 'v3.10/topic/gator' into linux-linaro-lsk-v3.10
[firefly-linux-kernel-4.4.55.git] / arch / arm / common / vlock.S
1 /*
2  * vlock.S - simple voting lock implementation for ARM
3  *
4  * Created by:  Dave Martin, 2012-08-16
5  * Copyright:   (C) 2012-2013  Linaro Limited
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License version 2 as
9  * published by the Free Software Foundation.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  *
17  * This algorithm is described in more detail in
18  * Documentation/arm/vlocks.txt.
19  */
20
21 #include <linux/linkage.h>
22 #include "vlock.h"
23
24 /* Select different code if voting flags  can fit in a single word. */
25 #if VLOCK_VOTING_SIZE > 4
26 #define FEW(x...)
27 #define MANY(x...) x
28 #else
29 #define FEW(x...) x
30 #define MANY(x...)
31 #endif
32
33 @ voting lock for first-man coordination
34
35 .macro voting_begin rbase:req, rcpu:req, rscratch:req
36         mov     \rscratch, #1
37         strb    \rscratch, [\rbase, \rcpu]
38         dmb
39 .endm
40
41 .macro voting_end rbase:req, rcpu:req, rscratch:req
42         dmb
43         mov     \rscratch, #0
44         strb    \rscratch, [\rbase, \rcpu]
45         dsb
46         sev
47 .endm
48
49 /*
50  * The vlock structure must reside in Strongly-Ordered or Device memory.
51  * This implementation deliberately eliminates most of the barriers which
52  * would be required for other memory types, and assumes that independent
53  * writes to neighbouring locations within a cacheline do not interfere
54  * with one another.
55  */
56
57 @ r0: lock structure base
58 @ r1: CPU ID (0-based index within cluster)
59 ENTRY(vlock_trylock)
60         add     r1, r1, #VLOCK_VOTING_OFFSET
61
62         voting_begin    r0, r1, r2
63
64         ldrb    r2, [r0, #VLOCK_OWNER_OFFSET]   @ check whether lock is held
65         cmp     r2, #VLOCK_OWNER_NONE
66         bne     trylock_fail                    @ fail if so
67
68         @ Control dependency implies strb not observable before previous ldrb.
69
70         strb    r1, [r0, #VLOCK_OWNER_OFFSET]   @ submit my vote
71
72         voting_end      r0, r1, r2              @ implies DMB
73
74         @ Wait for the current round of voting to finish:
75
76  MANY(  mov     r3, #VLOCK_VOTING_OFFSET                        )
77 0:
78  MANY(  ldr     r2, [r0, r3]                                    )
79  FEW(   ldr     r2, [r0, #VLOCK_VOTING_OFFSET]                  )
80         cmp     r2, #0
81         wfene
82         bne     0b
83  MANY(  add     r3, r3, #4                                      )
84  MANY(  cmp     r3, #VLOCK_VOTING_OFFSET + VLOCK_VOTING_SIZE    )
85  MANY(  bne     0b                                              )
86
87         @ Check who won:
88
89         dmb
90         ldrb    r2, [r0, #VLOCK_OWNER_OFFSET]
91         eor     r0, r1, r2                      @ zero if I won, else nonzero
92         bx      lr
93
94 trylock_fail:
95         voting_end      r0, r1, r2
96         mov     r0, #1                          @ nonzero indicates that I lost
97         bx      lr
98 ENDPROC(vlock_trylock)
99
100 @ r0: lock structure base
101 ENTRY(vlock_unlock)
102         dmb
103         mov     r1, #VLOCK_OWNER_NONE
104         strb    r1, [r0, #VLOCK_OWNER_OFFSET]
105         dsb
106         sev
107         bx      lr
108 ENDPROC(vlock_unlock)