Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ARM: bitops: switch set/clear/change bitops to use ldrex/strex

Switch the set/clear/change bitops to use the word-based exclusive
operations, which are only present in a wider range of ARM architectures
than the byte-based exclusive operations.

Tested record:
- Nicolas Pitre: ext3,rw,le
- Sourav Poddar: nfs,le
- Will Deacon: ext3,rw,le
- Tony Lindgren: ext3+nfs,le

Reviewed-by: Nicolas Pitre <nicolas.pitre@linaro.org>
Tested-by: Sourav Poddar <sourav.poddar@ti.com>
Tested-by: Will Deacon <will.deacon@arm.com>
Tested-by: Tony Lindgren <tony@atomide.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

+63 -112
+22 -38
arch/arm/include/asm/bitops.h
··· 149 149 */ 150 150 151 151 /* 152 + * Native endian assembly bitops. nr = 0 -> word 0 bit 0. 153 + */ 154 + extern void _set_bit(int nr, volatile unsigned long * p); 155 + extern void _clear_bit(int nr, volatile unsigned long * p); 156 + extern void _change_bit(int nr, volatile unsigned long * p); 157 + extern int _test_and_set_bit(int nr, volatile unsigned long * p); 158 + extern int _test_and_clear_bit(int nr, volatile unsigned long * p); 159 + extern int _test_and_change_bit(int nr, volatile unsigned long * p); 160 + 161 + /* 152 162 * Little endian assembly bitops. nr = 0 -> byte 0 bit 0. 153 163 */ 154 - extern void _set_bit_le(int nr, volatile unsigned long * p); 155 - extern void _clear_bit_le(int nr, volatile unsigned long * p); 156 - extern void _change_bit_le(int nr, volatile unsigned long * p); 157 - extern int _test_and_set_bit_le(int nr, volatile unsigned long * p); 158 - extern int _test_and_clear_bit_le(int nr, volatile unsigned long * p); 159 - extern int _test_and_change_bit_le(int nr, volatile unsigned long * p); 160 164 extern int _find_first_zero_bit_le(const void * p, unsigned size); 161 165 extern int _find_next_zero_bit_le(const void * p, int size, int offset); 162 166 extern int _find_first_bit_le(const unsigned long *p, unsigned size); ··· 169 165 /* 170 166 * Big endian assembly bitops. nr = 0 -> byte 3 bit 0. 171 167 */ 172 - extern void _set_bit_be(int nr, volatile unsigned long * p); 173 - extern void _clear_bit_be(int nr, volatile unsigned long * p); 174 - extern void _change_bit_be(int nr, volatile unsigned long * p); 175 - extern int _test_and_set_bit_be(int nr, volatile unsigned long * p); 176 - extern int _test_and_clear_bit_be(int nr, volatile unsigned long * p); 177 - extern int _test_and_change_bit_be(int nr, volatile unsigned long * p); 178 168 extern int _find_first_zero_bit_be(const void * p, unsigned size); 179 169 extern int _find_next_zero_bit_be(const void * p, int size, int offset); 180 170 extern int _find_first_bit_be(const unsigned long *p, unsigned size); ··· 178 180 /* 179 181 * The __* form of bitops are non-atomic and may be reordered. 180 182 */ 181 - #define ATOMIC_BITOP_LE(name,nr,p) \ 182 - (__builtin_constant_p(nr) ? \ 183 - ____atomic_##name(nr, p) : \ 184 - _##name##_le(nr,p)) 185 - 186 - #define ATOMIC_BITOP_BE(name,nr,p) \ 187 - (__builtin_constant_p(nr) ? \ 188 - ____atomic_##name(nr, p) : \ 189 - _##name##_be(nr,p)) 183 + #define ATOMIC_BITOP(name,nr,p) \ 184 + (__builtin_constant_p(nr) ? ____atomic_##name(nr, p) : _##name(nr,p)) 190 185 #else 191 - #define ATOMIC_BITOP_LE(name,nr,p) _##name##_le(nr,p) 192 - #define ATOMIC_BITOP_BE(name,nr,p) _##name##_be(nr,p) 186 + #define ATOMIC_BITOP(name,nr,p) _##name(nr,p) 193 187 #endif 194 188 195 - #define NONATOMIC_BITOP(name,nr,p) \ 196 - (____nonatomic_##name(nr, p)) 189 + /* 190 + * Native endian atomic definitions. 191 + */ 192 + #define set_bit(nr,p) ATOMIC_BITOP(set_bit,nr,p) 193 + #define clear_bit(nr,p) ATOMIC_BITOP(clear_bit,nr,p) 194 + #define change_bit(nr,p) ATOMIC_BITOP(change_bit,nr,p) 195 + #define test_and_set_bit(nr,p) ATOMIC_BITOP(test_and_set_bit,nr,p) 196 + #define test_and_clear_bit(nr,p) ATOMIC_BITOP(test_and_clear_bit,nr,p) 197 + #define test_and_change_bit(nr,p) ATOMIC_BITOP(test_and_change_bit,nr,p) 197 198 198 199 #ifndef __ARMEB__ 199 200 /* 200 201 * These are the little endian, atomic definitions. 201 202 */ 202 - #define set_bit(nr,p) ATOMIC_BITOP_LE(set_bit,nr,p) 203 - #define clear_bit(nr,p) ATOMIC_BITOP_LE(clear_bit,nr,p) 204 - #define change_bit(nr,p) ATOMIC_BITOP_LE(change_bit,nr,p) 205 - #define test_and_set_bit(nr,p) ATOMIC_BITOP_LE(test_and_set_bit,nr,p) 206 - #define test_and_clear_bit(nr,p) ATOMIC_BITOP_LE(test_and_clear_bit,nr,p) 207 - #define test_and_change_bit(nr,p) ATOMIC_BITOP_LE(test_and_change_bit,nr,p) 208 203 #define find_first_zero_bit(p,sz) _find_first_zero_bit_le(p,sz) 209 204 #define find_next_zero_bit(p,sz,off) _find_next_zero_bit_le(p,sz,off) 210 205 #define find_first_bit(p,sz) _find_first_bit_le(p,sz) ··· 206 215 #define WORD_BITOFF_TO_LE(x) ((x)) 207 216 208 217 #else 209 - 210 218 /* 211 219 * These are the big endian, atomic definitions. 212 220 */ 213 - #define set_bit(nr,p) ATOMIC_BITOP_BE(set_bit,nr,p) 214 - #define clear_bit(nr,p) ATOMIC_BITOP_BE(clear_bit,nr,p) 215 - #define change_bit(nr,p) ATOMIC_BITOP_BE(change_bit,nr,p) 216 - #define test_and_set_bit(nr,p) ATOMIC_BITOP_BE(test_and_set_bit,nr,p) 217 - #define test_and_clear_bit(nr,p) ATOMIC_BITOP_BE(test_and_clear_bit,nr,p) 218 - #define test_and_change_bit(nr,p) ATOMIC_BITOP_BE(test_and_change_bit,nr,p) 219 221 #define find_first_zero_bit(p,sz) _find_first_zero_bit_be(p,sz) 220 222 #define find_next_zero_bit(p,sz,off) _find_next_zero_bit_be(p,sz,off) 221 223 #define find_first_bit(p,sz) _find_first_bit_be(p,sz)
+6 -12
arch/arm/kernel/armksyms.c
··· 140 140 #endif 141 141 142 142 /* bitops */ 143 - EXPORT_SYMBOL(_set_bit_le); 144 - EXPORT_SYMBOL(_test_and_set_bit_le); 145 - EXPORT_SYMBOL(_clear_bit_le); 146 - EXPORT_SYMBOL(_test_and_clear_bit_le); 147 - EXPORT_SYMBOL(_change_bit_le); 148 - EXPORT_SYMBOL(_test_and_change_bit_le); 143 + EXPORT_SYMBOL(_set_bit); 144 + EXPORT_SYMBOL(_test_and_set_bit); 145 + EXPORT_SYMBOL(_clear_bit); 146 + EXPORT_SYMBOL(_test_and_clear_bit); 147 + EXPORT_SYMBOL(_change_bit); 148 + EXPORT_SYMBOL(_test_and_change_bit); 149 149 EXPORT_SYMBOL(_find_first_zero_bit_le); 150 150 EXPORT_SYMBOL(_find_next_zero_bit_le); 151 151 EXPORT_SYMBOL(_find_first_bit_le); 152 152 EXPORT_SYMBOL(_find_next_bit_le); 153 153 154 154 #ifdef __ARMEB__ 155 - EXPORT_SYMBOL(_set_bit_be); 156 - EXPORT_SYMBOL(_test_and_set_bit_be); 157 - EXPORT_SYMBOL(_clear_bit_be); 158 - EXPORT_SYMBOL(_test_and_clear_bit_be); 159 - EXPORT_SYMBOL(_change_bit_be); 160 - EXPORT_SYMBOL(_test_and_change_bit_be); 161 155 EXPORT_SYMBOL(_find_first_zero_bit_be); 162 156 EXPORT_SYMBOL(_find_next_zero_bit_be); 163 157 EXPORT_SYMBOL(_find_first_bit_be);
+20 -18
arch/arm/lib/bitops.h
··· 1 - 2 - #if __LINUX_ARM_ARCH__ >= 6 && defined(CONFIG_CPU_32v6K) 1 + #if __LINUX_ARM_ARCH__ >= 6 3 2 .macro bitop, instr 4 3 ands ip, r1, #3 5 4 strneb r1, [ip] @ assert word-aligned 6 5 mov r2, #1 7 - and r3, r0, #7 @ Get bit offset 8 - add r1, r1, r0, lsr #3 @ Get byte offset 6 + and r3, r0, #31 @ Get bit offset 7 + mov r0, r0, lsr #5 8 + add r1, r1, r0, lsl #2 @ Get word offset 9 9 mov r3, r2, lsl r3 10 - 1: ldrexb r2, [r1] 10 + 1: ldrex r2, [r1] 11 11 \instr r2, r2, r3 12 - strexb r0, r2, [r1] 12 + strex r0, r2, [r1] 13 13 cmp r0, #0 14 14 bne 1b 15 15 mov pc, lr ··· 18 18 .macro testop, instr, store 19 19 ands ip, r1, #3 20 20 strneb r1, [ip] @ assert word-aligned 21 - and r3, r0, #7 @ Get bit offset 22 21 mov r2, #1 23 - add r1, r1, r0, lsr #3 @ Get byte offset 22 + and r3, r0, #31 @ Get bit offset 23 + mov r0, r0, lsr #5 24 + add r1, r1, r0, lsl #2 @ Get word offset 24 25 mov r3, r2, lsl r3 @ create mask 25 26 smp_dmb 26 - 1: ldrexb r2, [r1] 27 + 1: ldrex r2, [r1] 27 28 ands r0, r2, r3 @ save old value of bit 28 - \instr r2, r2, r3 @ toggle bit 29 - strexb ip, r2, [r1] 29 + \instr r2, r2, r3 @ toggle bit 30 + strex ip, r2, [r1] 30 31 cmp ip, #0 31 32 bne 1b 32 33 smp_dmb ··· 39 38 .macro bitop, instr 40 39 ands ip, r1, #3 41 40 strneb r1, [ip] @ assert word-aligned 42 - and r2, r0, #7 41 + and r2, r0, #31 42 + mov r0, r0, lsr #5 43 43 mov r3, #1 44 44 mov r3, r3, lsl r2 45 45 save_and_disable_irqs ip 46 - ldrb r2, [r1, r0, lsr #3] 46 + ldr r2, [r1, r0, lsl #2] 47 47 \instr r2, r2, r3 48 - strb r2, [r1, r0, lsr #3] 48 + str r2, [r1, r0, lsl #2] 49 49 restore_irqs ip 50 50 mov pc, lr 51 51 .endm ··· 62 60 .macro testop, instr, store 63 61 ands ip, r1, #3 64 62 strneb r1, [ip] @ assert word-aligned 65 - add r1, r1, r0, lsr #3 66 - and r3, r0, #7 67 - mov r0, #1 63 + and r3, r0, #31 64 + mov r0, r0, lsr #5 68 65 save_and_disable_irqs ip 69 - ldrb r2, [r1] 66 + ldr r2, [r1, r0, lsl #2]! 67 + mov r0, #1 70 68 tst r2, r0, lsl r3 71 69 \instr r2, r2, r0, lsl r3 72 70 \store r2, [r1]
+2 -8
arch/arm/lib/changebit.S
··· 12 12 #include "bitops.h" 13 13 .text 14 14 15 - /* Purpose : Function to change a bit 16 - * Prototype: int change_bit(int bit, void *addr) 17 - */ 18 - ENTRY(_change_bit_be) 19 - eor r0, r0, #0x18 @ big endian byte ordering 20 - ENTRY(_change_bit_le) 15 + ENTRY(_change_bit) 21 16 bitop eor 22 - ENDPROC(_change_bit_be) 23 - ENDPROC(_change_bit_le) 17 + ENDPROC(_change_bit)
+2 -9
arch/arm/lib/clearbit.S
··· 12 12 #include "bitops.h" 13 13 .text 14 14 15 - /* 16 - * Purpose : Function to clear a bit 17 - * Prototype: int clear_bit(int bit, void *addr) 18 - */ 19 - ENTRY(_clear_bit_be) 20 - eor r0, r0, #0x18 @ big endian byte ordering 21 - ENTRY(_clear_bit_le) 15 + ENTRY(_clear_bit) 22 16 bitop bic 23 - ENDPROC(_clear_bit_be) 24 - ENDPROC(_clear_bit_le) 17 + ENDPROC(_clear_bit)
+2 -9
arch/arm/lib/setbit.S
··· 12 12 #include "bitops.h" 13 13 .text 14 14 15 - /* 16 - * Purpose : Function to set a bit 17 - * Prototype: int set_bit(int bit, void *addr) 18 - */ 19 - ENTRY(_set_bit_be) 20 - eor r0, r0, #0x18 @ big endian byte ordering 21 - ENTRY(_set_bit_le) 15 + ENTRY(_set_bit) 22 16 bitop orr 23 - ENDPROC(_set_bit_be) 24 - ENDPROC(_set_bit_le) 17 + ENDPROC(_set_bit)
+3 -6
arch/arm/lib/testchangebit.S
··· 12 12 #include "bitops.h" 13 13 .text 14 14 15 - ENTRY(_test_and_change_bit_be) 16 - eor r0, r0, #0x18 @ big endian byte ordering 17 - ENTRY(_test_and_change_bit_le) 18 - testop eor, strb 19 - ENDPROC(_test_and_change_bit_be) 20 - ENDPROC(_test_and_change_bit_le) 15 + ENTRY(_test_and_change_bit) 16 + testop eor, str 17 + ENDPROC(_test_and_change_bit)
+3 -6
arch/arm/lib/testclearbit.S
··· 12 12 #include "bitops.h" 13 13 .text 14 14 15 - ENTRY(_test_and_clear_bit_be) 16 - eor r0, r0, #0x18 @ big endian byte ordering 17 - ENTRY(_test_and_clear_bit_le) 18 - testop bicne, strneb 19 - ENDPROC(_test_and_clear_bit_be) 20 - ENDPROC(_test_and_clear_bit_le) 15 + ENTRY(_test_and_clear_bit) 16 + testop bicne, strne 17 + ENDPROC(_test_and_clear_bit)
+3 -6
arch/arm/lib/testsetbit.S
··· 12 12 #include "bitops.h" 13 13 .text 14 14 15 - ENTRY(_test_and_set_bit_be) 16 - eor r0, r0, #0x18 @ big endian byte ordering 17 - ENTRY(_test_and_set_bit_le) 18 - testop orreq, streqb 19 - ENDPROC(_test_and_set_bit_be) 20 - ENDPROC(_test_and_set_bit_le) 15 + ENTRY(_test_and_set_bit) 16 + testop orreq, streq 17 + ENDPROC(_test_and_set_bit)