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