xref: /OK3568_Linux_fs/kernel/drivers/gpu/arm/mali400/mali/common/mali_osk_bitops.h (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1 /*
2  * Copyright (C) 2010, 2013-2014, 2016-2017 ARM Limited. All rights reserved.
3  *
4  * This program is free software and is provided to you under the terms of the GNU General Public License version 2
5  * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
6  *
7  * A copy of the licence is included with the program, and can also be obtained from Free Software
8  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
9  */
10 
11 /**
12  * @file mali_osk_bitops.h
13  * Implementation of the OS abstraction layer for the kernel device driver
14  */
15 
16 #ifndef __MALI_OSK_BITOPS_H__
17 #define __MALI_OSK_BITOPS_H__
18 
19 #ifdef __cplusplus
20 extern "C" {
21 #endif
22 
_mali_internal_clear_bit(u32 bit,u32 * addr)23 MALI_STATIC_INLINE void _mali_internal_clear_bit(u32 bit, u32 *addr)
24 {
25 	MALI_DEBUG_ASSERT(bit < 32);
26 	MALI_DEBUG_ASSERT(NULL != addr);
27 
28 	(*addr) &= ~(1 << bit);
29 }
30 
_mali_internal_set_bit(u32 bit,u32 * addr)31 MALI_STATIC_INLINE void _mali_internal_set_bit(u32 bit, u32 *addr)
32 {
33 	MALI_DEBUG_ASSERT(bit < 32);
34 	MALI_DEBUG_ASSERT(NULL != addr);
35 
36 	(*addr) |= (1 << bit);
37 }
38 
_mali_internal_test_bit(u32 bit,u32 value)39 MALI_STATIC_INLINE u32 _mali_internal_test_bit(u32 bit, u32 value)
40 {
41 	MALI_DEBUG_ASSERT(bit < 32);
42 	return value & (1 << bit);
43 }
44 
_mali_internal_find_first_zero_bit(u32 value)45 MALI_STATIC_INLINE int _mali_internal_find_first_zero_bit(u32 value)
46 {
47 	u32 inverted;
48 	u32 negated;
49 	u32 isolated;
50 	u32 leading_zeros;
51 
52 	/* Begin with xxx...x0yyy...y, where ys are 1, number of ys is in range  0..31 */
53 	inverted = ~value; /* zzz...z1000...0 */
54 	/* Using count_trailing_zeros on inverted value -
55 	 * See ARM System Developers Guide for details of count_trailing_zeros */
56 
57 	/* Isolate the zero: it is preceeded by a run of 1s, so add 1 to it */
58 	negated = (u32) - inverted ; /* -a == ~a + 1 (mod 2^n) for n-bit numbers */
59 	/* negated = xxx...x1000...0 */
60 
61 	isolated = negated & inverted ; /* xxx...x1000...0 & zzz...z1000...0, zs are ~xs */
62 	/* And so the first zero bit is in the same position as the 1 == number of 1s that preceeded it
63 	 * Note that the output is zero if value was all 1s */
64 
65 	leading_zeros = _mali_osk_clz(isolated);
66 
67 	return 31 - leading_zeros;
68 }
69 
70 
71 /** @defgroup _mali_osk_bitops OSK Non-atomic Bit-operations
72  * @{ */
73 
74 /**
75  * These bit-operations do not work atomically, and so locks must be used if
76  * atomicity is required.
77  *
78  * Reference implementations for Little Endian are provided, and so it should
79  * not normally be necessary to re-implement these. Efficient bit-twiddling
80  * techniques are used where possible, implemented in portable C.
81  *
82  * Note that these reference implementations rely on _mali_osk_clz() being
83  * implemented.
84  */
85 
86 /** @brief Clear a bit in a sequence of 32-bit words
87  * @param nr bit number to clear, starting from the (Little-endian) least
88  * significant bit
89  * @param addr starting point for counting.
90  */
_mali_osk_clear_nonatomic_bit(u32 nr,u32 * addr)91 MALI_STATIC_INLINE void _mali_osk_clear_nonatomic_bit(u32 nr, u32 *addr)
92 {
93 	addr += nr >> 5; /* find the correct word */
94 	nr = nr & ((1 << 5) - 1); /* The bit number within the word */
95 
96 	_mali_internal_clear_bit(nr, addr);
97 }
98 
99 /** @brief Set a bit in a sequence of 32-bit words
100  * @param nr bit number to set, starting from the (Little-endian) least
101  * significant bit
102  * @param addr starting point for counting.
103  */
_mali_osk_set_nonatomic_bit(u32 nr,u32 * addr)104 MALI_STATIC_INLINE void _mali_osk_set_nonatomic_bit(u32 nr, u32 *addr)
105 {
106 	addr += nr >> 5; /* find the correct word */
107 	nr = nr & ((1 << 5) - 1); /* The bit number within the word */
108 
109 	_mali_internal_set_bit(nr, addr);
110 }
111 
112 /** @brief Test a bit in a sequence of 32-bit words
113  * @param nr bit number to test, starting from the (Little-endian) least
114  * significant bit
115  * @param addr starting point for counting.
116  * @return zero if bit was clear, non-zero if set. Do not rely on the return
117  * value being related to the actual word under test.
118  */
_mali_osk_test_bit(u32 nr,u32 * addr)119 MALI_STATIC_INLINE u32 _mali_osk_test_bit(u32 nr, u32 *addr)
120 {
121 	addr += nr >> 5; /* find the correct word */
122 	nr = nr & ((1 << 5) - 1); /* The bit number within the word */
123 
124 	return _mali_internal_test_bit(nr, *addr);
125 }
126 
127 /* Return maxbit if not found */
128 /** @brief Find the first zero bit in a sequence of 32-bit words
129  * @param addr starting point for search.
130  * @param maxbit the maximum number of bits to search
131  * @return the number of the first zero bit found, or maxbit if none were found
132  * in the specified range.
133  */
_mali_osk_find_first_zero_bit(const u32 * addr,u32 maxbit)134 MALI_STATIC_INLINE u32 _mali_osk_find_first_zero_bit(const u32 *addr, u32 maxbit)
135 {
136 	u32 total;
137 
138 	for (total = 0; total < maxbit; total += 32, ++addr) {
139 		int result;
140 		result = _mali_internal_find_first_zero_bit(*addr);
141 
142 		/* non-negative signifies the bit was found */
143 		if (result >= 0) {
144 			total += (u32)result;
145 			break;
146 		}
147 	}
148 
149 	/* Now check if we reached maxbit or above */
150 	if (total >= maxbit) {
151 		total = maxbit;
152 	}
153 
154 	return total; /* either the found bit nr, or maxbit if not found */
155 }
156 /** @} */ /* end group _mali_osk_bitops */
157 
158 #ifdef __cplusplus
159 }
160 #endif
161 
162 #endif /* __MALI_OSK_BITOPS_H__ */
163