Synchronized bit operations Currently the only way to specify how a bit operation is synchronized is via __. F.e. there is clear_bit and __clear_bit clear_bit() implies atomic behavior whereas __clear_bit is not atomic. However, neither one allows to specify an ordering mode that may be necessary for locking and unlocking etc. For that purpose we have additional macross smb_mb__before/after_xxx. However, processors have the ability to specify the synchronization mode in the atomic instruction itself and having cumbersome additional macros around makes it difficult to optimize bit operations behavior for various processors. This adds a variant with a _mode postfix that allows the specification of a synchronization mode: I.e. instead of set_bit(x,y) we can do set_bit(x,y, mode). The following modes are supported: BMODE_NONE No synchronization at all. Non atomic version of bitmap operation. F.e. set_bit(x,y, MODE_NONE) == __set_bit(x,y) BMODE_ATOMIC The operation is atomic but there is no guarantee how this operation is ordered respective to other memory operations. BMODE_LOCK An atomic operation that is guaranteed to become visible before all subsequent memory accesses suitable for lock acquisition. BMODE_UNLOCK An atomic operation that is guaranteed to become visible to other processors after all previos memory acceses and suitable for unlocking. MODE_BARRIER An atomic operation that is guaranteed to become visible between previous and later memory operations. For conveniences sake there are additional macros defined that do not require an extra parameter. One can do clear_bit_lock(x,y) clear_bit_unlock(x,y) and clear_bit_barrier(x,y) to get special synchronization behavior. In order to utilize these extended bit operations one has to add #include This patch only provides a generic implementation based on the bit operations that are already universally supported. The use of the generic definitions may not be optimal for many architectures. An architecture may provide its own definitions for bitops with synchronization modes by customizing include/asm-generic/bitmaps_mode.h and move it to include/asm-xxxx/bitmaps_mode.h Note that we are a long way from utilizing these synchronized bit modes since they constitute a completely different locking paradigm from the current barrier oriented scheme. In order for Signed-off-by: Christoph Lameter Index: linux-2.6.16-mm2/include/asm-generic/bitops_mode.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.16-mm2/include/asm-generic/bitops_mode.h 2006-03-31 11:10:41.000000000 -0800 @@ -0,0 +1,245 @@ +#ifndef _ASM_GENERIC_BITOPS_MODE_H +#define _ASM_GENERIC_BITOPS_MODE_H + +/* + * Copyright (C) 2006 Silicon Graphics, Incorporated + * Christoph Lameter + * + * Fallback logic for bit operations with synchronization mode + */ + +#include +#include +#include + +#define BMODE_NONE 0 +#define BMODE_ATOMIC 1 +#define BMODE_LOCK 2 +#define BMODE_UNLOCK 3 +#define BMODE_BARRIER 4 + +/** + * set_bit_mode - Set a bit in memory + * + * The address must be (at least) "long" aligned. + * Note that there are driver (e.g., eepro100) which use these operations to + * operate on hw-defined data-structures, so we can't easily change these + * operations to force a bigger alignment. + * + * bit 0 is the LSB of addr; bit 32 is the LSB of (addr+1). + */ +static __inline__ void +set_bit_mode (int nr, void *addr, int mode) +{ + switch (mode) { + case BMODE_NONE: + __set_bit(nr,addr); + return; + + case BMODE_ATOMIC: + set_bit(nr,addr); + return; + + case BMODE_LOCK: + set_bit(nr,addr); + smp_mb(); + return; + + case BMODE_UNLOCK: + smp_mb(); + set_bit(nr,addr); + return; + + case BMODE_BARRIER: + smp_mb(); + set_bit(nr,addr); + smp_mb(); + return; + } +} + +/** + * clear_bit_mode - Clears a bit in memory + */ +static __inline__ void +clear_bit_mode (int nr, void *addr, int mode) +{ + switch (mode) { + case BMODE_NONE: + __clear_bit(nr,addr); + return; + + case BMODE_ATOMIC: + clear_bit(nr,addr); + return; + + case BMODE_LOCK: + clear_bit(nr,addr); + smp_mb(); + return; + + case BMODE_UNLOCK: + smp_mb(); + clear_bit(nr,addr); + return; + + case BMODE_BARRIER: + smp_mb(); + clear_bit(nr,addr); + smp_mb(); + return; + } +} + +/** + * change_bit_mode - Toggle a bit in memory + */ +static __inline__ void +change_bit_mode (int nr, void *addr, int mode) +{ + switch (mode) { + case BMODE_NONE: + __change_bit(nr,addr); + return; + + case BMODE_ATOMIC: + change_bit(nr,addr); + return; + + case BMODE_LOCK: + change_bit(nr,addr); + smp_mb(); + return; + + case BMODE_UNLOCK: + smp_mb(); + change_bit(nr,addr); + return; + + case BMODE_BARRIER: + smp_mb(); + change_bit(nr,addr); + smp_mb(); + return; + } +} + +/** + * test_and_set_bit_mode - Set a bit and return its old value + */ +static __inline__ int +test_and_set_bit_mode (int nr, void *addr, int mode) +{ + int x; + switch (mode) { + case BMODE_NONE: + return __test_and_set_bit(nr,addr); + + case BMODE_ATOMIC: + return test_and_set_bit(nr,addr); + + case BMODE_LOCK: + x = test_and_set_bit(nr,addr); + smp_mb(); + return x; + + case BMODE_UNLOCK: + smp_mb(); + return test_and_set_bit(nr,addr); + + case BMODE_BARRIER: + smp_mb(); + x = test_and_set_bit(nr,addr); + smp_mb(); + return x; + } +} + +/** + * test_and_clear_bit - Clear a bit and return its old value + */ +static __inline__ int +test_and_clear_bit_mode (int nr, void *addr, int mode) +{ + int x; + switch (mode) { + case BMODE_NONE: + return __test_and_clear_bit(nr,addr); + + case BMODE_ATOMIC: + return test_and_clear_bit(nr,addr); + + case BMODE_LOCK: + x = test_and_clear_bit(nr,addr); + smp_mb(); + return x; + + case BMODE_UNLOCK: + smp_mb(); + return test_and_clear_bit(nr,addr); + + case BMODE_BARRIER: + smp_mb(); + x = test_and_set_bit(nr,addr); + smp_mb(); + return x; + } +} + +/** + * test_and_change_bit - Change a bit and return its old value + */ +static __inline__ int +test_and_change_bit_mode (int nr, void *addr, int mode) +{ + int x; + switch (mode) { + case BMODE_NONE: + return __test_and_change_bit(nr,addr); + + case BMODE_ATOMIC: + return test_and_change_bit(nr,addr); + + case BMODE_LOCK: + x = test_and_change_bit(nr,addr); + smp_mb(); + return x; + + case BMODE_UNLOCK: + smp_mb(); + return test_and_change_bit(nr,addr); + + case BMODE_BARRIER: + smp_mb(); + x = test_and_change_bit(nr,addr); + smp_mb(); + return x; + } +} + +/* A set of convenience definitions */ +#define set_bit_lock(a,b) set_bit_mode(a,b,BMODE_LOCK) +#define set_bit_unlock(a,b) set_bit_mode(a,b,BMODE_UNLOCK) +#define set_bit_barrier(a,b) set_bit_mode(a,b,BMODE_BARRIER) + +#define clear_bit_lock(a,b) clear_bit_mode(a,b,BMODE_LOCK) +#define clear_bit_unlock(a,b) clear_bit_mode(a,b,BMODE_UNLOCK) +#define clear_bit_barrier(a,b) clear_bit_mode(a,b,BMODE_BARRIER) + +#define change_bit_lock(a,b) change_bit_mode(a,b,BMODE_LOCK) +#define change_bit_unlock(a,b) change_bit_mode(a,b,BMODE_UNLOCK) +#define change_bit_barrier(a,b) change_bit_mode(a,b,BMODE_BARRIER) + +#define test_and_set_bit_lock(a,b) test_and_set_bit_mode(a,b,BMODE_LOCK) +#define test_and_set_bit_unlock(a,b) test_and_set_bit_mode(a,b,BMODE_UNLOCK) +#define test_and_set_bit_barrier(a,b) test_and_set_bit_mode(a,b,BMODE_BARRIER) + +#define test_and_clear_bit_lock(a,b) test_and_clear_bit_mode(a,b,BMODE_LOCK) +#define test_and_clear_bit_unlock(a,b) test_and_clear_bit_mode(a,b,BMODE_UNLOCK) +#define test_and_clear_bit_barrier(a,b) test_and_clear_bit_mode(a,b,BMODE_BARRIER) + +#define test_and_change_bit_lock(a,b) test_and_change_bit_mode(a,b,BMODE_LOCK) +#define test_and_change_bit_unlock(a,b) test_and_change_bit_mode(a,b,BMODE_UNLOCK) +#define test_and_change_bit_barrier(a,b) test_and_change_bit_mode(a,b,BMODE_BARRIER) + +#endif /* _ASM_GENERIC_BITOPS_MODE_H */