Merge branch 'for-3.17' of git://linux-nfs.org/~bfields/linux
[firefly-linux-kernel-4.4.55.git] / arch / arm / lib / bitops.h
1 #include <asm/assembler.h>
2 #include <asm/unwind.h>
3
4 #if __LINUX_ARM_ARCH__ >= 6
5         .macro  bitop, name, instr
6 ENTRY(  \name           )
7 UNWIND( .fnstart        )
8         ands    ip, r1, #3
9         strneb  r1, [ip]                @ assert word-aligned
10         mov     r2, #1
11         and     r3, r0, #31             @ Get bit offset
12         mov     r0, r0, lsr #5
13         add     r1, r1, r0, lsl #2      @ Get word offset
14 #if __LINUX_ARM_ARCH__ >= 7 && defined(CONFIG_SMP)
15         .arch_extension mp
16         ALT_SMP(W(pldw) [r1])
17         ALT_UP(W(nop))
18 #endif
19         mov     r3, r2, lsl r3
20 1:      ldrex   r2, [r1]
21         \instr  r2, r2, r3
22         strex   r0, r2, [r1]
23         cmp     r0, #0
24         bne     1b
25         bx      lr
26 UNWIND( .fnend          )
27 ENDPROC(\name           )
28         .endm
29
30         .macro  testop, name, instr, store
31 ENTRY(  \name           )
32 UNWIND( .fnstart        )
33         ands    ip, r1, #3
34         strneb  r1, [ip]                @ assert word-aligned
35         mov     r2, #1
36         and     r3, r0, #31             @ Get bit offset
37         mov     r0, r0, lsr #5
38         add     r1, r1, r0, lsl #2      @ Get word offset
39         mov     r3, r2, lsl r3          @ create mask
40         smp_dmb
41 #if __LINUX_ARM_ARCH__ >= 7 && defined(CONFIG_SMP)
42         .arch_extension mp
43         ALT_SMP(W(pldw) [r1])
44         ALT_UP(W(nop))
45 #endif
46 1:      ldrex   r2, [r1]
47         ands    r0, r2, r3              @ save old value of bit
48         \instr  r2, r2, r3              @ toggle bit
49         strex   ip, r2, [r1]
50         cmp     ip, #0
51         bne     1b
52         smp_dmb
53         cmp     r0, #0
54         movne   r0, #1
55 2:      bx      lr
56 UNWIND( .fnend          )
57 ENDPROC(\name           )
58         .endm
59 #else
60         .macro  bitop, name, instr
61 ENTRY(  \name           )
62 UNWIND( .fnstart        )
63         ands    ip, r1, #3
64         strneb  r1, [ip]                @ assert word-aligned
65         and     r2, r0, #31
66         mov     r0, r0, lsr #5
67         mov     r3, #1
68         mov     r3, r3, lsl r2
69         save_and_disable_irqs ip
70         ldr     r2, [r1, r0, lsl #2]
71         \instr  r2, r2, r3
72         str     r2, [r1, r0, lsl #2]
73         restore_irqs ip
74         ret     lr
75 UNWIND( .fnend          )
76 ENDPROC(\name           )
77         .endm
78
79 /**
80  * testop - implement a test_and_xxx_bit operation.
81  * @instr: operational instruction
82  * @store: store instruction
83  *
84  * Note: we can trivially conditionalise the store instruction
85  * to avoid dirtying the data cache.
86  */
87         .macro  testop, name, instr, store
88 ENTRY(  \name           )
89 UNWIND( .fnstart        )
90         ands    ip, r1, #3
91         strneb  r1, [ip]                @ assert word-aligned
92         and     r3, r0, #31
93         mov     r0, r0, lsr #5
94         save_and_disable_irqs ip
95         ldr     r2, [r1, r0, lsl #2]!
96         mov     r0, #1
97         tst     r2, r0, lsl r3
98         \instr  r2, r2, r0, lsl r3
99         \store  r2, [r1]
100         moveq   r0, #0
101         restore_irqs ip
102         ret     lr
103 UNWIND( .fnend          )
104 ENDPROC(\name           )
105         .endm
106 #endif