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