123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127 |
- /*
- * arch/arm/include/asm/mutex.h
- *
- * ARM optimized mutex locking primitives
- *
- * Please look into asm-generic/mutex-xchg.h for a formal definition.
- */
- #ifndef _ASM_MUTEX_H
- #define _ASM_MUTEX_H
- #if __LINUX_ARM_ARCH__ < 6
- /* On pre-ARMv6 hardware the swp based implementation is the most efficient. */
- # include <asm-generic/mutex-xchg.h>
- #else
- /*
- * Attempting to lock a mutex on ARMv6+ can be done with a bastardized
- * atomic decrement (it is not a reliable atomic decrement but it satisfies
- * the defined semantics for our purpose, while being smaller and faster
- * than a real atomic decrement or atomic swap. The idea is to attempt
- * decrementing the lock value only once. If once decremented it isn't zero,
- * or if its store-back fails due to a dispute on the exclusive store, we
- * simply bail out immediately through the slow path where the lock will be
- * reattempted until it succeeds.
- */
- static inline void
- __mutex_fastpath_lock(atomic_t *count, void (*fail_fn)(atomic_t *))
- {
- int __ex_flag, __res;
- __asm__ (
- "ldrex %0, [%2] \n\t"
- "sub %0, %0, #1 \n\t"
- "strex %1, %0, [%2] "
- : "=&r" (__res), "=&r" (__ex_flag)
- : "r" (&(count)->counter)
- : "cc","memory" );
- __res |= __ex_flag;
- if (unlikely(__res != 0))
- fail_fn(count);
- }
- static inline int
- __mutex_fastpath_lock_retval(atomic_t *count, int (*fail_fn)(atomic_t *))
- {
- int __ex_flag, __res;
- __asm__ (
- "ldrex %0, [%2] \n\t"
- "sub %0, %0, #1 \n\t"
- "strex %1, %0, [%2] "
- : "=&r" (__res), "=&r" (__ex_flag)
- : "r" (&(count)->counter)
- : "cc","memory" );
- __res |= __ex_flag;
- if (unlikely(__res != 0))
- __res = fail_fn(count);
- return __res;
- }
- /*
- * Same trick is used for the unlock fast path. However the original value,
- * rather than the result, is used to test for success in order to have
- * better generated assembly.
- */
- static inline void
- __mutex_fastpath_unlock(atomic_t *count, void (*fail_fn)(atomic_t *))
- {
- int __ex_flag, __res, __orig;
- __asm__ (
- "ldrex %0, [%3] \n\t"
- "add %1, %0, #1 \n\t"
- "strex %2, %1, [%3] "
- : "=&r" (__orig), "=&r" (__res), "=&r" (__ex_flag)
- : "r" (&(count)->counter)
- : "cc","memory" );
- __orig |= __ex_flag;
- if (unlikely(__orig != 0))
- fail_fn(count);
- }
- /*
- * If the unlock was done on a contended lock, or if the unlock simply fails
- * then the mutex remains locked.
- */
- #define __mutex_slowpath_needs_to_unlock() 1
- /*
- * For __mutex_fastpath_trylock we use another construct which could be
- * described as a "single value cmpxchg".
- *
- * This provides the needed trylock semantics like cmpxchg would, but it is
- * lighter and less generic than a true cmpxchg implementation.
- */
- static inline int
- __mutex_fastpath_trylock(atomic_t *count, int (*fail_fn)(atomic_t *))
- {
- int __ex_flag, __res, __orig;
- __asm__ (
- "1: ldrex %0, [%3] \n\t"
- "subs %1, %0, #1 \n\t"
- "strexeq %2, %1, [%3] \n\t"
- "movlt %0, #0 \n\t"
- "cmpeq %2, #0 \n\t"
- "bgt 1b "
- : "=&r" (__orig), "=&r" (__res), "=&r" (__ex_flag)
- : "r" (&count->counter)
- : "cc", "memory" );
- return __orig;
- }
- #endif
- #endif
|