1 #ifndef _BITS_BITOPS_H
2 #define _BITS_BITOPS_H
3 
4 /** @file
5  *
6  * ARM bit operations
7  *
8  */
9 
10 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
11 
12 #include <stdint.h>
13 
14 /**
15  * Test and set bit atomically
16  *
17  * @v bit		Bit to set
18  * @v bits		Bit field
19  * @ret old		Old value of bit (zero or non-zero)
20  */
21 static inline __attribute__ (( always_inline )) int
test_and_set_bit(unsigned int bit,volatile void * bits)22 test_and_set_bit ( unsigned int bit, volatile void *bits ) {
23 	unsigned int index = ( bit / 64 );
24 	unsigned int offset = ( bit % 64 );
25 	volatile uint64_t *qword = ( ( ( volatile uint64_t * ) bits ) + index );
26 	uint64_t mask = ( 1UL << offset );
27 	uint64_t old;
28 	uint64_t new;
29 	uint32_t flag;
30 
31 	__asm__ __volatile__ ( "\n1:\n\t"
32 			       "ldxr %0, %3\n\t"
33 			       "orr %1, %0, %4\n\t"
34 			       "stxr %w2, %1, %3\n\t"
35 			       "tst %w2, %w2\n\t"
36 			       "bne 1b\n\t"
37 			       : "=&r" ( old ), "=&r" ( new ), "=&r" ( flag ),
38 				 "+Q" ( *qword )
39 			       : "r" ( mask )
40 			       : "cc" );
41 
42 	return ( !! ( old & mask ) );
43 }
44 
45 /**
46  * Test and clear bit atomically
47  *
48  * @v bit		Bit to set
49  * @v bits		Bit field
50  * @ret old		Old value of bit (zero or non-zero)
51  */
52 static inline __attribute__ (( always_inline )) int
test_and_clear_bit(unsigned int bit,volatile void * bits)53 test_and_clear_bit ( unsigned int bit, volatile void *bits ) {
54 	unsigned int index = ( bit / 64 );
55 	unsigned int offset = ( bit % 64 );
56 	volatile uint64_t *qword = ( ( ( volatile uint64_t * ) bits ) + index );
57 	uint64_t mask = ( 1UL << offset );
58 	uint64_t old;
59 	uint64_t new;
60 	uint32_t flag;
61 
62 	__asm__ __volatile__ ( "\n1:\n\t"
63 			       "ldxr %0, %3\n\t"
64 			       "bic %1, %0, %4\n\t"
65 			       "stxr %w2, %1, %3\n\t"
66 			       "tst %w2, %w2\n\t"
67 			       "bne 1b\n\t"
68 			       : "=&r" ( old ), "=&r" ( new ), "=&r" ( flag ),
69 				 "+Q" ( *qword )
70 			       : "r" ( mask )
71 			       : "cc" );
72 
73 	return ( !! ( old & mask ) );
74 }
75 
76 /**
77  * Set bit atomically
78  *
79  * @v bit		Bit to set
80  * @v bits		Bit field
81  */
82 static inline __attribute__ (( always_inline )) void
set_bit(unsigned int bit,volatile void * bits)83 set_bit ( unsigned int bit, volatile void *bits ) {
84 
85 	test_and_set_bit ( bit, bits );
86 }
87 
88 /**
89  * Clear bit atomically
90  *
91  * @v bit		Bit to set
92  * @v bits		Bit field
93  */
94 static inline __attribute__ (( always_inline )) void
clear_bit(unsigned int bit,volatile void * bits)95 clear_bit ( unsigned int bit, volatile void *bits ) {
96 
97 	test_and_clear_bit ( bit, bits );
98 }
99 
100 #endif /* _BITS_BITOPS_H */
101