*/
#define bitop(name, instr) \
-void name(int nr, volatile void *p) \
+static always_inline bool int_##name(int nr, volatile void *p, bool timeout,\
+ unsigned int max_try) \
{ \
volatile uint32_t *ptr = (uint32_t *)p + BIT_WORD((unsigned int)nr); \
const uint32_t mask = BIT_MASK((unsigned int)nr); \
" strex %0, %2, %1\n" \
: "=&r" (res), "+Qo" (*ptr), "=&r" (tmp) \
: "r" (mask)); \
- } while ( res ); \
+ \
+ if ( !res ) \
+ break; \
+ } while ( !timeout || ((--max_try) > 0) ); \
+ \
+ return !res; \
+} \
+ \
+void name(int nr, volatile void *p) \
+{ \
+ if ( !int_##name(nr, p, false, 0) ) \
+ ASSERT_UNREACHABLE(); \
+} \
+ \
+bool name##_timeout(int nr, volatile void *p, unsigned int max_try) \
+{ \
+ return int_##name(nr, p, true, max_try); \
}
#define testop(name, instr) \
-int name(int nr, volatile void *p) \
+static always_inline bool int_##name(int nr, volatile void *p, int *oldbit, \
+ bool timeout, unsigned int max_try) \
{ \
volatile uint32_t *ptr = (uint32_t *)p + BIT_WORD((unsigned int)nr); \
unsigned int bit = (unsigned int)nr % BITS_PER_WORD; \
const uint32_t mask = BIT_MASK(bit); \
unsigned long res, tmp; \
- int oldbit; \
\
ASSERT(((vaddr_t)p & 0x3) == 0); \
smp_mb(); \
" lsr %1, %3, %5 // Save old value of bit\n" \
" " __stringify(instr) " %3, %3, %4 // Toggle bit\n" \
" strex %0, %3, %2\n" \
- : "=&r" (res), "=&r" (oldbit), "+Qo" (*ptr), "=&r" (tmp) \
+ : "=&r" (res), "=&r" (*oldbit), "+Qo" (*ptr), "=&r" (tmp) \
: "r" (mask), "r" (bit)); \
- } while ( res ); \
+ \
+ if ( !res ) \
+ break; \
+ } while ( !timeout || ((--max_try) > 0) ); \
\
smp_mb(); \
\
- return oldbit & 1; \
+ *oldbit &= 1; \
+ \
+ return !res; \
+} \
+ \
+int name(int nr, volatile void *p) \
+{ \
+ int oldbit; \
+ \
+ if ( !int_##name(nr, p, &oldbit, false, 0) ) \
+ ASSERT_UNREACHABLE(); \
+ \
+ return oldbit; \
} \
+ \
+bool name##_timeout(int nr, volatile void *p, \
+ int *oldbit, unsigned int max_try) \
+{ \
+ return int_##name(nr, p, oldbit, true, max_try); \
+}
bitop(change_bit, eor)
bitop(clear_bit, bic)
*/
#define bitop(name, instr) \
-void name(int nr, volatile void *p) \
+static always_inline bool int_##name(int nr, volatile void *p, bool timeout,\
+ unsigned int max_try) \
{ \
volatile uint32_t *ptr = (uint32_t *)p + BIT_WORD((unsigned int)nr); \
const uint32_t mask = BIT_MASK((unsigned int)nr); \
" stxr %w0, %w2, %1\n" \
: "=&r" (res), "+Q" (*ptr), "=&r" (tmp) \
: "r" (mask)); \
- } while ( res ); \
+ \
+ if ( !res ) \
+ break; \
+ } while ( !timeout || ((--max_try) > 0) ); \
+ \
+ return !res; \
} \
+ \
+void name(int nr, volatile void *p) \
+{ \
+ if ( !int_##name(nr, p, false, 0) ) \
+ ASSERT_UNREACHABLE(); \
+} \
+ \
+bool name##_timeout(int nr, volatile void *p, unsigned int max_try) \
+{ \
+ return int_##name(nr, p, true, max_try); \
+}
#define testop(name, instr) \
-int name(int nr, volatile void *p) \
+static always_inline bool int_##name(int nr, volatile void *p, int *oldbit, \
+ bool timeout, unsigned int max_try) \
{ \
volatile uint32_t *ptr = (uint32_t *)p + BIT_WORD((unsigned int)nr); \
unsigned int bit = (unsigned int)nr % BITS_PER_WORD; \
const uint32_t mask = BIT_MASK(bit); \
unsigned long res, tmp; \
- unsigned long oldbit; \
\
do \
{ \
" lsr %w1, %w3, %w5 // Save old value of bit\n" \
" " __stringify(instr) " %w3, %w3, %w4 // Toggle bit\n" \
" stlxr %w0, %w3, %2\n" \
- : "=&r" (res), "=&r" (oldbit), "+Q" (*ptr), "=&r" (tmp) \
+ : "=&r" (res), "=&r" (*oldbit), "+Q" (*ptr), "=&r" (tmp) \
: "r" (mask), "r" (bit) \
: "memory"); \
- } while ( res ); \
+ \
+ if ( !res ) \
+ break; \
+ } while ( !timeout || ((--max_try) > 0) ); \
\
dmb(ish); \
\
- return oldbit & 1; \
+ *oldbit &= 1; \
+ \
+ return !res; \
+} \
+ \
+int name(int nr, volatile void *p) \
+{ \
+ int oldbit; \
+ \
+ if ( !int_##name(nr, p, &oldbit, false, 0) ) \
+ ASSERT_UNREACHABLE(); \
+ \
+ return oldbit; \
+} \
+ \
+bool name##_timeout(int nr, volatile void *p, \
+ int *oldbit, unsigned int max_try) \
+{ \
+ return int_##name(nr, p, oldbit, true, max_try); \
}
bitop(change_bit, eor)
# error "unknown ARM variant"
#endif
-/* Atomics bitops */
+/*
+ * Atomic bitops
+ *
+ * The helpers below *should* only be used on memory shared between
+ * trusted threads or we know the memory cannot be accessed by another
+ * thread.
+ */
+
void set_bit(int nr, volatile void *p);
void clear_bit(int nr, volatile void *p);
void change_bit(int nr, volatile void *p);
int test_and_clear_bit(int nr, volatile void *p);
int test_and_change_bit(int nr, volatile void *p);
+/*
+ * The helpers below may fail to update the memory if the action takes
+ * too long.
+ *
+ * @max_try: Maximum number of iterations
+ *
+ * The helpers will return true when the update has succeeded (i.e no
+ * timeout) and false if the update has failed.
+ */
+bool set_bit_timeout(int nr, volatile void *p, unsigned int max_try);
+bool clear_bit_timeout(int nr, volatile void *p, unsigned int max_try);
+bool change_bit_timeout(int nr, volatile void *p, unsigned int max_try);
+bool test_and_set_bit_timeout(int nr, volatile void *p,
+ int *oldbit, unsigned int max_try);
+bool test_and_clear_bit_timeout(int nr, volatile void *p,
+ int *oldbit, unsigned int max_try);
+bool test_and_change_bit_timeout(int nr, volatile void *p,
+ int *oldbit, unsigned int max_try);
+
/**
* __test_and_set_bit - Set a bit and return its old value
* @nr: Bit to set