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>
This commit is contained in:
Russell King 2011-01-16 18:02:17 +00:00
parent a16ede35a2
commit 6323f0cced
9 changed files with 63 additions and 112 deletions

View File

@ -148,15 +148,19 @@ ____atomic_test_and_change_bit(unsigned int bit, volatile unsigned long *p)
* Note that bit 0 is defined to be 32-bit word bit 0, not byte 0 bit 0. * Note that bit 0 is defined to be 32-bit word bit 0, not byte 0 bit 0.
*/ */
/*
* Native endian assembly bitops. nr = 0 -> word 0 bit 0.
*/
extern void _set_bit(int nr, volatile unsigned long * p);
extern void _clear_bit(int nr, volatile unsigned long * p);
extern void _change_bit(int nr, volatile unsigned long * p);
extern int _test_and_set_bit(int nr, volatile unsigned long * p);
extern int _test_and_clear_bit(int nr, volatile unsigned long * p);
extern int _test_and_change_bit(int nr, volatile unsigned long * p);
/* /*
* Little endian assembly bitops. nr = 0 -> byte 0 bit 0. * Little endian assembly bitops. nr = 0 -> byte 0 bit 0.
*/ */
extern void _set_bit_le(int nr, volatile unsigned long * p);
extern void _clear_bit_le(int nr, volatile unsigned long * p);
extern void _change_bit_le(int nr, volatile unsigned long * p);
extern int _test_and_set_bit_le(int nr, volatile unsigned long * p);
extern int _test_and_clear_bit_le(int nr, volatile unsigned long * p);
extern int _test_and_change_bit_le(int nr, volatile unsigned long * p);
extern int _find_first_zero_bit_le(const void * p, unsigned size); extern int _find_first_zero_bit_le(const void * p, unsigned size);
extern int _find_next_zero_bit_le(const void * p, int size, int offset); extern int _find_next_zero_bit_le(const void * p, int size, int offset);
extern int _find_first_bit_le(const unsigned long *p, unsigned size); extern int _find_first_bit_le(const unsigned long *p, unsigned size);
@ -165,12 +169,6 @@ extern int _find_next_bit_le(const unsigned long *p, int size, int offset);
/* /*
* Big endian assembly bitops. nr = 0 -> byte 3 bit 0. * Big endian assembly bitops. nr = 0 -> byte 3 bit 0.
*/ */
extern void _set_bit_be(int nr, volatile unsigned long * p);
extern void _clear_bit_be(int nr, volatile unsigned long * p);
extern void _change_bit_be(int nr, volatile unsigned long * p);
extern int _test_and_set_bit_be(int nr, volatile unsigned long * p);
extern int _test_and_clear_bit_be(int nr, volatile unsigned long * p);
extern int _test_and_change_bit_be(int nr, volatile unsigned long * p);
extern int _find_first_zero_bit_be(const void * p, unsigned size); extern int _find_first_zero_bit_be(const void * p, unsigned size);
extern int _find_next_zero_bit_be(const void * p, int size, int offset); extern int _find_next_zero_bit_be(const void * p, int size, int offset);
extern int _find_first_bit_be(const unsigned long *p, unsigned size); extern int _find_first_bit_be(const unsigned long *p, unsigned size);
@ -180,33 +178,26 @@ extern int _find_next_bit_be(const unsigned long *p, int size, int offset);
/* /*
* The __* form of bitops are non-atomic and may be reordered. * The __* form of bitops are non-atomic and may be reordered.
*/ */
#define ATOMIC_BITOP_LE(name,nr,p) \ #define ATOMIC_BITOP(name,nr,p) \
(__builtin_constant_p(nr) ? \ (__builtin_constant_p(nr) ? ____atomic_##name(nr, p) : _##name(nr,p))
____atomic_##name(nr, p) : \
_##name##_le(nr,p))
#define ATOMIC_BITOP_BE(name,nr,p) \
(__builtin_constant_p(nr) ? \
____atomic_##name(nr, p) : \
_##name##_be(nr,p))
#else #else
#define ATOMIC_BITOP_LE(name,nr,p) _##name##_le(nr,p) #define ATOMIC_BITOP(name,nr,p) _##name(nr,p)
#define ATOMIC_BITOP_BE(name,nr,p) _##name##_be(nr,p)
#endif #endif
#define NONATOMIC_BITOP(name,nr,p) \ /*
(____nonatomic_##name(nr, p)) * Native endian atomic definitions.
*/
#define set_bit(nr,p) ATOMIC_BITOP(set_bit,nr,p)
#define clear_bit(nr,p) ATOMIC_BITOP(clear_bit,nr,p)
#define change_bit(nr,p) ATOMIC_BITOP(change_bit,nr,p)
#define test_and_set_bit(nr,p) ATOMIC_BITOP(test_and_set_bit,nr,p)
#define test_and_clear_bit(nr,p) ATOMIC_BITOP(test_and_clear_bit,nr,p)
#define test_and_change_bit(nr,p) ATOMIC_BITOP(test_and_change_bit,nr,p)
#ifndef __ARMEB__ #ifndef __ARMEB__
/* /*
* These are the little endian, atomic definitions. * These are the little endian, atomic definitions.
*/ */
#define set_bit(nr,p) ATOMIC_BITOP_LE(set_bit,nr,p)
#define clear_bit(nr,p) ATOMIC_BITOP_LE(clear_bit,nr,p)
#define change_bit(nr,p) ATOMIC_BITOP_LE(change_bit,nr,p)
#define test_and_set_bit(nr,p) ATOMIC_BITOP_LE(test_and_set_bit,nr,p)
#define test_and_clear_bit(nr,p) ATOMIC_BITOP_LE(test_and_clear_bit,nr,p)
#define test_and_change_bit(nr,p) ATOMIC_BITOP_LE(test_and_change_bit,nr,p)
#define find_first_zero_bit(p,sz) _find_first_zero_bit_le(p,sz) #define find_first_zero_bit(p,sz) _find_first_zero_bit_le(p,sz)
#define find_next_zero_bit(p,sz,off) _find_next_zero_bit_le(p,sz,off) #define find_next_zero_bit(p,sz,off) _find_next_zero_bit_le(p,sz,off)
#define find_first_bit(p,sz) _find_first_bit_le(p,sz) #define find_first_bit(p,sz) _find_first_bit_le(p,sz)
@ -215,16 +206,9 @@ extern int _find_next_bit_be(const unsigned long *p, int size, int offset);
#define WORD_BITOFF_TO_LE(x) ((x)) #define WORD_BITOFF_TO_LE(x) ((x))
#else #else
/* /*
* These are the big endian, atomic definitions. * These are the big endian, atomic definitions.
*/ */
#define set_bit(nr,p) ATOMIC_BITOP_BE(set_bit,nr,p)
#define clear_bit(nr,p) ATOMIC_BITOP_BE(clear_bit,nr,p)
#define change_bit(nr,p) ATOMIC_BITOP_BE(change_bit,nr,p)
#define test_and_set_bit(nr,p) ATOMIC_BITOP_BE(test_and_set_bit,nr,p)
#define test_and_clear_bit(nr,p) ATOMIC_BITOP_BE(test_and_clear_bit,nr,p)
#define test_and_change_bit(nr,p) ATOMIC_BITOP_BE(test_and_change_bit,nr,p)
#define find_first_zero_bit(p,sz) _find_first_zero_bit_be(p,sz) #define find_first_zero_bit(p,sz) _find_first_zero_bit_be(p,sz)
#define find_next_zero_bit(p,sz,off) _find_next_zero_bit_be(p,sz,off) #define find_next_zero_bit(p,sz,off) _find_next_zero_bit_be(p,sz,off)
#define find_first_bit(p,sz) _find_first_bit_be(p,sz) #define find_first_bit(p,sz) _find_first_bit_be(p,sz)

View File

@ -140,24 +140,18 @@ EXPORT_SYMBOL(__aeabi_ulcmp);
#endif #endif
/* bitops */ /* bitops */
EXPORT_SYMBOL(_set_bit_le); EXPORT_SYMBOL(_set_bit);
EXPORT_SYMBOL(_test_and_set_bit_le); EXPORT_SYMBOL(_test_and_set_bit);
EXPORT_SYMBOL(_clear_bit_le); EXPORT_SYMBOL(_clear_bit);
EXPORT_SYMBOL(_test_and_clear_bit_le); EXPORT_SYMBOL(_test_and_clear_bit);
EXPORT_SYMBOL(_change_bit_le); EXPORT_SYMBOL(_change_bit);
EXPORT_SYMBOL(_test_and_change_bit_le); EXPORT_SYMBOL(_test_and_change_bit);
EXPORT_SYMBOL(_find_first_zero_bit_le); EXPORT_SYMBOL(_find_first_zero_bit_le);
EXPORT_SYMBOL(_find_next_zero_bit_le); EXPORT_SYMBOL(_find_next_zero_bit_le);
EXPORT_SYMBOL(_find_first_bit_le); EXPORT_SYMBOL(_find_first_bit_le);
EXPORT_SYMBOL(_find_next_bit_le); EXPORT_SYMBOL(_find_next_bit_le);
#ifdef __ARMEB__ #ifdef __ARMEB__
EXPORT_SYMBOL(_set_bit_be);
EXPORT_SYMBOL(_test_and_set_bit_be);
EXPORT_SYMBOL(_clear_bit_be);
EXPORT_SYMBOL(_test_and_clear_bit_be);
EXPORT_SYMBOL(_change_bit_be);
EXPORT_SYMBOL(_test_and_change_bit_be);
EXPORT_SYMBOL(_find_first_zero_bit_be); EXPORT_SYMBOL(_find_first_zero_bit_be);
EXPORT_SYMBOL(_find_next_zero_bit_be); EXPORT_SYMBOL(_find_next_zero_bit_be);
EXPORT_SYMBOL(_find_first_bit_be); EXPORT_SYMBOL(_find_first_bit_be);

View File

@ -1,15 +1,15 @@
#if __LINUX_ARM_ARCH__ >= 6
#if __LINUX_ARM_ARCH__ >= 6 && defined(CONFIG_CPU_32v6K)
.macro bitop, instr .macro bitop, instr
ands ip, r1, #3 ands ip, r1, #3
strneb r1, [ip] @ assert word-aligned strneb r1, [ip] @ assert word-aligned
mov r2, #1 mov r2, #1
and r3, r0, #7 @ Get bit offset and r3, r0, #31 @ Get bit offset
add r1, r1, r0, lsr #3 @ Get byte offset mov r0, r0, lsr #5
add r1, r1, r0, lsl #2 @ Get word offset
mov r3, r2, lsl r3 mov r3, r2, lsl r3
1: ldrexb r2, [r1] 1: ldrex r2, [r1]
\instr r2, r2, r3 \instr r2, r2, r3
strexb r0, r2, [r1] strex r0, r2, [r1]
cmp r0, #0 cmp r0, #0
bne 1b bne 1b
mov pc, lr mov pc, lr
@ -18,15 +18,16 @@
.macro testop, instr, store .macro testop, instr, store
ands ip, r1, #3 ands ip, r1, #3
strneb r1, [ip] @ assert word-aligned strneb r1, [ip] @ assert word-aligned
and r3, r0, #7 @ Get bit offset
mov r2, #1 mov r2, #1
add r1, r1, r0, lsr #3 @ Get byte offset and r3, r0, #31 @ Get bit offset
mov r0, r0, lsr #5
add r1, r1, r0, lsl #2 @ Get word offset
mov r3, r2, lsl r3 @ create mask mov r3, r2, lsl r3 @ create mask
smp_dmb smp_dmb
1: ldrexb r2, [r1] 1: ldrex r2, [r1]
ands r0, r2, r3 @ save old value of bit ands r0, r2, r3 @ save old value of bit
\instr r2, r2, r3 @ toggle bit \instr r2, r2, r3 @ toggle bit
strexb ip, r2, [r1] strex ip, r2, [r1]
cmp ip, #0 cmp ip, #0
bne 1b bne 1b
smp_dmb smp_dmb
@ -38,13 +39,14 @@
.macro bitop, instr .macro bitop, instr
ands ip, r1, #3 ands ip, r1, #3
strneb r1, [ip] @ assert word-aligned strneb r1, [ip] @ assert word-aligned
and r2, r0, #7 and r2, r0, #31
mov r0, r0, lsr #5
mov r3, #1 mov r3, #1
mov r3, r3, lsl r2 mov r3, r3, lsl r2
save_and_disable_irqs ip save_and_disable_irqs ip
ldrb r2, [r1, r0, lsr #3] ldr r2, [r1, r0, lsl #2]
\instr r2, r2, r3 \instr r2, r2, r3
strb r2, [r1, r0, lsr #3] str r2, [r1, r0, lsl #2]
restore_irqs ip restore_irqs ip
mov pc, lr mov pc, lr
.endm .endm
@ -60,11 +62,11 @@
.macro testop, instr, store .macro testop, instr, store
ands ip, r1, #3 ands ip, r1, #3
strneb r1, [ip] @ assert word-aligned strneb r1, [ip] @ assert word-aligned
add r1, r1, r0, lsr #3 and r3, r0, #31
and r3, r0, #7 mov r0, r0, lsr #5
mov r0, #1
save_and_disable_irqs ip save_and_disable_irqs ip
ldrb r2, [r1] ldr r2, [r1, r0, lsl #2]!
mov r0, #1
tst r2, r0, lsl r3 tst r2, r0, lsl r3
\instr r2, r2, r0, lsl r3 \instr r2, r2, r0, lsl r3
\store r2, [r1] \store r2, [r1]

View File

@ -12,12 +12,6 @@
#include "bitops.h" #include "bitops.h"
.text .text
/* Purpose : Function to change a bit ENTRY(_change_bit)
* Prototype: int change_bit(int bit, void *addr)
*/
ENTRY(_change_bit_be)
eor r0, r0, #0x18 @ big endian byte ordering
ENTRY(_change_bit_le)
bitop eor bitop eor
ENDPROC(_change_bit_be) ENDPROC(_change_bit)
ENDPROC(_change_bit_le)

View File

@ -12,13 +12,6 @@
#include "bitops.h" #include "bitops.h"
.text .text
/* ENTRY(_clear_bit)
* Purpose : Function to clear a bit
* Prototype: int clear_bit(int bit, void *addr)
*/
ENTRY(_clear_bit_be)
eor r0, r0, #0x18 @ big endian byte ordering
ENTRY(_clear_bit_le)
bitop bic bitop bic
ENDPROC(_clear_bit_be) ENDPROC(_clear_bit)
ENDPROC(_clear_bit_le)

View File

@ -12,13 +12,6 @@
#include "bitops.h" #include "bitops.h"
.text .text
/* ENTRY(_set_bit)
* Purpose : Function to set a bit
* Prototype: int set_bit(int bit, void *addr)
*/
ENTRY(_set_bit_be)
eor r0, r0, #0x18 @ big endian byte ordering
ENTRY(_set_bit_le)
bitop orr bitop orr
ENDPROC(_set_bit_be) ENDPROC(_set_bit)
ENDPROC(_set_bit_le)

View File

@ -12,9 +12,6 @@
#include "bitops.h" #include "bitops.h"
.text .text
ENTRY(_test_and_change_bit_be) ENTRY(_test_and_change_bit)
eor r0, r0, #0x18 @ big endian byte ordering testop eor, str
ENTRY(_test_and_change_bit_le) ENDPROC(_test_and_change_bit)
testop eor, strb
ENDPROC(_test_and_change_bit_be)
ENDPROC(_test_and_change_bit_le)

View File

@ -12,9 +12,6 @@
#include "bitops.h" #include "bitops.h"
.text .text
ENTRY(_test_and_clear_bit_be) ENTRY(_test_and_clear_bit)
eor r0, r0, #0x18 @ big endian byte ordering testop bicne, strne
ENTRY(_test_and_clear_bit_le) ENDPROC(_test_and_clear_bit)
testop bicne, strneb
ENDPROC(_test_and_clear_bit_be)
ENDPROC(_test_and_clear_bit_le)

View File

@ -12,9 +12,6 @@
#include "bitops.h" #include "bitops.h"
.text .text
ENTRY(_test_and_set_bit_be) ENTRY(_test_and_set_bit)
eor r0, r0, #0x18 @ big endian byte ordering testop orreq, streq
ENTRY(_test_and_set_bit_le) ENDPROC(_test_and_set_bit)
testop orreq, streqb
ENDPROC(_test_and_set_bit_be)
ENDPROC(_test_and_set_bit_le)