mali_osk_bitops.h 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. /*
  2. * This confidential and proprietary software may be used only as
  3. * authorised by a licensing agreement from ARM Limited
  4. * (C) COPYRIGHT 2008-2010, 2013 ARM Limited
  5. * ALL RIGHTS RESERVED
  6. * The entire notice above must be reproduced on all authorised
  7. * copies and copies may only be made to the extent permitted
  8. * by a licensing agreement from ARM Limited.
  9. */
  10. /**
  11. * @file mali_osk_bitops.h
  12. * Implementation of the OS abstraction layer for the kernel device driver
  13. */
  14. #ifndef __MALI_OSK_BITOPS_H__
  15. #define __MALI_OSK_BITOPS_H__
  16. #ifdef __cplusplus
  17. extern "C" {
  18. #endif
  19. MALI_STATIC_INLINE void _mali_internal_clear_bit( u32 bit, u32 *addr )
  20. {
  21. MALI_DEBUG_ASSERT( bit < 32 );
  22. MALI_DEBUG_ASSERT( NULL != addr );
  23. (*addr) &= ~(1 << bit);
  24. }
  25. MALI_STATIC_INLINE void _mali_internal_set_bit( u32 bit, u32 *addr )
  26. {
  27. MALI_DEBUG_ASSERT( bit < 32 );
  28. MALI_DEBUG_ASSERT( NULL != addr );
  29. (*addr) |= (1 << bit);
  30. }
  31. MALI_STATIC_INLINE u32 _mali_internal_test_bit( u32 bit, u32 value )
  32. {
  33. MALI_DEBUG_ASSERT( bit < 32 );
  34. return value & (1 << bit);
  35. }
  36. MALI_STATIC_INLINE int _mali_internal_find_first_zero_bit( u32 value )
  37. {
  38. u32 inverted;
  39. u32 negated;
  40. u32 isolated;
  41. u32 leading_zeros;
  42. /* Begin with xxx...x0yyy...y, where ys are 1, number of ys is in range 0..31 */
  43. inverted = ~value; /* zzz...z1000...0 */
  44. /* Using count_trailing_zeros on inverted value -
  45. * See ARM System Developers Guide for details of count_trailing_zeros */
  46. /* Isolate the zero: it is preceeded by a run of 1s, so add 1 to it */
  47. negated = (u32)-inverted ; /* -a == ~a + 1 (mod 2^n) for n-bit numbers */
  48. /* negated = xxx...x1000...0 */
  49. isolated = negated & inverted ; /* xxx...x1000...0 & zzz...z1000...0, zs are ~xs */
  50. /* And so the first zero bit is in the same position as the 1 == number of 1s that preceeded it
  51. * Note that the output is zero if value was all 1s */
  52. leading_zeros = _mali_osk_clz( isolated );
  53. return 31 - leading_zeros;
  54. }
  55. /** @defgroup _mali_osk_bitops OSK Non-atomic Bit-operations
  56. * @{ */
  57. /**
  58. * These bit-operations do not work atomically, and so locks must be used if
  59. * atomicity is required.
  60. *
  61. * Reference implementations for Little Endian are provided, and so it should
  62. * not normally be necessary to re-implement these. Efficient bit-twiddling
  63. * techniques are used where possible, implemented in portable C.
  64. *
  65. * Note that these reference implementations rely on _mali_osk_clz() being
  66. * implemented.
  67. */
  68. /** @brief Clear a bit in a sequence of 32-bit words
  69. * @param nr bit number to clear, starting from the (Little-endian) least
  70. * significant bit
  71. * @param addr starting point for counting.
  72. */
  73. MALI_STATIC_INLINE void _mali_osk_clear_nonatomic_bit( u32 nr, u32 *addr )
  74. {
  75. addr += nr >> 5; /* find the correct word */
  76. nr = nr & ((1 << 5)-1); /* The bit number within the word */
  77. _mali_internal_clear_bit( nr, addr );
  78. }
  79. /** @brief Set a bit in a sequence of 32-bit words
  80. * @param nr bit number to set, starting from the (Little-endian) least
  81. * significant bit
  82. * @param addr starting point for counting.
  83. */
  84. MALI_STATIC_INLINE void _mali_osk_set_nonatomic_bit( u32 nr, u32 *addr )
  85. {
  86. addr += nr >> 5; /* find the correct word */
  87. nr = nr & ((1 << 5)-1); /* The bit number within the word */
  88. _mali_internal_set_bit( nr, addr );
  89. }
  90. /** @brief Test a bit in a sequence of 32-bit words
  91. * @param nr bit number to test, starting from the (Little-endian) least
  92. * significant bit
  93. * @param addr starting point for counting.
  94. * @return zero if bit was clear, non-zero if set. Do not rely on the return
  95. * value being related to the actual word under test.
  96. */
  97. MALI_STATIC_INLINE u32 _mali_osk_test_bit( u32 nr, u32 *addr )
  98. {
  99. addr += nr >> 5; /* find the correct word */
  100. nr = nr & ((1 << 5)-1); /* The bit number within the word */
  101. return _mali_internal_test_bit( nr, *addr );
  102. }
  103. /* Return maxbit if not found */
  104. /** @brief Find the first zero bit in a sequence of 32-bit words
  105. * @param addr starting point for search.
  106. * @param maxbit the maximum number of bits to search
  107. * @return the number of the first zero bit found, or maxbit if none were found
  108. * in the specified range.
  109. */
  110. MALI_STATIC_INLINE u32 _mali_osk_find_first_zero_bit( const u32 *addr, u32 maxbit )
  111. {
  112. u32 total;
  113. for ( total = 0; total < maxbit; total += 32, ++addr ) {
  114. int result;
  115. result = _mali_internal_find_first_zero_bit( *addr );
  116. /* non-negative signifies the bit was found */
  117. if ( result >= 0 ) {
  118. total += (u32)result;
  119. break;
  120. }
  121. }
  122. /* Now check if we reached maxbit or above */
  123. if ( total >= maxbit ) {
  124. total = maxbit;
  125. }
  126. return total; /* either the found bit nr, or maxbit if not found */
  127. }
  128. /** @} */ /* end group _mali_osk_bitops */
  129. #ifdef __cplusplus
  130. }
  131. #endif
  132. #endif /* __MALI_OSK_BITOPS_H__ */