1 #ifndef _BITS_BITOPS_H
2 #define _BITS_BITOPS_H
3
4 /** @file
5 *
6 * x86 bit operations
7 *
8 * We perform atomic bit set and bit clear operations using "lock bts"
9 * and "lock btr". We use the output constraint to inform the
10 * compiler that any memory from the start of the bit field up to and
11 * including the byte containing the bit may be modified. (This is
12 * overkill but shouldn't matter in practice since we're unlikely to
13 * subsequently read other bits from the same bit field.)
14 */
15
16 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
17
18 #include <stdint.h>
19
20 /**
21 * Set bit atomically
22 *
23 * @v bit Bit to set
24 * @v bits Bit field
25 */
26 static inline __attribute__ (( always_inline )) void
set_bit(unsigned int bit,volatile void * bits)27 set_bit ( unsigned int bit, volatile void *bits ) {
28 volatile struct {
29 uint8_t byte[ ( bit / 8 ) + 1 ];
30 } *bytes = bits;
31
32 __asm__ __volatile__ ( "lock bts %1, %0"
33 : "+m" ( *bytes ) : "Ir" ( bit ) );
34 }
35
36 /**
37 * Clear bit atomically
38 *
39 * @v bit Bit to set
40 * @v bits Bit field
41 */
42 static inline __attribute__ (( always_inline )) void
clear_bit(unsigned int bit,volatile void * bits)43 clear_bit ( unsigned int bit, volatile void *bits ) {
44 volatile struct {
45 uint8_t byte[ ( bit / 8 ) + 1 ];
46 } *bytes = bits;
47
48 __asm__ __volatile__ ( "lock btr %1, %0"
49 : "+m" ( *bytes ) : "Ir" ( bit ) );
50 }
51
52 /**
53 * Test and set bit atomically
54 *
55 * @v bit Bit to set
56 * @v bits Bit field
57 * @ret old Old value of bit (zero or non-zero)
58 */
59 static inline __attribute__ (( always_inline )) int
test_and_set_bit(unsigned int bit,volatile void * bits)60 test_and_set_bit ( unsigned int bit, volatile void *bits ) {
61 volatile struct {
62 uint8_t byte[ ( bit / 8 ) + 1 ];
63 } *bytes = bits;
64 int old;
65
66 __asm__ __volatile__ ( "lock bts %2, %0\n\t"
67 "sbb %1, %1\n\t"
68 : "+m" ( *bytes ), "=r" ( old )
69 : "Ir" ( bit ) );
70 return old;
71 }
72
73 /**
74 * Test and clear bit atomically
75 *
76 * @v bit Bit to set
77 * @v bits Bit field
78 * @ret old Old value of bit (zero or non-zero)
79 */
80 static inline __attribute__ (( always_inline )) int
test_and_clear_bit(unsigned int bit,volatile void * bits)81 test_and_clear_bit ( unsigned int bit, volatile void *bits ) {
82 volatile struct {
83 uint8_t byte[ ( bit / 8 ) + 1 ];
84 } *bytes = bits;
85 int old;
86
87 __asm__ __volatile__ ( "lock btr %2, %0\n\t"
88 "sbb %1, %1\n\t"
89 : "+m" ( *bytes ), "=r" ( old )
90 : "Ir" ( bit ) );
91 return old;
92 }
93
94 #endif /* _BITS_BITOPS_H */
95