| #ifndef _BITS_BITOPS_H |
| #define _BITS_BITOPS_H |
| |
| /** @file |
| * |
| * x86 bit operations |
| * |
| * We perform atomic bit set and bit clear operations using "lock bts" |
| * and "lock btr". We use the output constraint to inform the |
| * compiler that any memory from the start of the bit field up to and |
| * including the byte containing the bit may be modified. (This is |
| * overkill but shouldn't matter in practice since we're unlikely to |
| * subsequently read other bits from the same bit field.) |
| */ |
| |
| FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); |
| |
| #include <stdint.h> |
| |
| /** |
| * Set bit atomically |
| * |
| * @v bit Bit to set |
| * @v bits Bit field |
| */ |
| static inline __attribute__ (( always_inline )) void |
| set_bit ( unsigned int bit, volatile void *bits ) { |
| volatile struct { |
| uint8_t byte[ ( bit / 8 ) + 1 ]; |
| } *bytes = bits; |
| |
| __asm__ __volatile__ ( "lock btsl %k1, %0" |
| : "+m" ( *bytes ) : "Ir" ( bit ) ); |
| } |
| |
| /** |
| * Clear bit atomically |
| * |
| * @v bit Bit to set |
| * @v bits Bit field |
| */ |
| static inline __attribute__ (( always_inline )) void |
| clear_bit ( unsigned int bit, volatile void *bits ) { |
| volatile struct { |
| uint8_t byte[ ( bit / 8 ) + 1 ]; |
| } *bytes = bits; |
| |
| __asm__ __volatile__ ( "lock btrl %k1, %0" |
| : "+m" ( *bytes ) : "Ir" ( bit ) ); |
| } |
| |
| /** |
| * Test and set bit atomically |
| * |
| * @v bit Bit to set |
| * @v bits Bit field |
| * @ret old Old value of bit (zero or non-zero) |
| */ |
| static inline __attribute__ (( always_inline )) int |
| test_and_set_bit ( unsigned int bit, volatile void *bits ) { |
| volatile struct { |
| uint8_t byte[ ( bit / 8 ) + 1 ]; |
| } *bytes = bits; |
| int old; |
| |
| __asm__ __volatile__ ( "lock btsl %k2, %0\n\t" |
| "sbb %1, %1\n\t" |
| : "+m" ( *bytes ), "=r" ( old ) |
| : "Ir" ( bit ) ); |
| return old; |
| } |
| |
| /** |
| * Test and clear bit atomically |
| * |
| * @v bit Bit to set |
| * @v bits Bit field |
| * @ret old Old value of bit (zero or non-zero) |
| */ |
| static inline __attribute__ (( always_inline )) int |
| test_and_clear_bit ( unsigned int bit, volatile void *bits ) { |
| volatile struct { |
| uint8_t byte[ ( bit / 8 ) + 1 ]; |
| } *bytes = bits; |
| int old; |
| |
| __asm__ __volatile__ ( "lock btrl %k2, %0\n\t" |
| "sbb %1, %1\n\t" |
| : "+m" ( *bytes ), "=r" ( old ) |
| : "Ir" ( bit ) ); |
| return old; |
| } |
| |
| #endif /* _BITS_BITOPS_H */ |