text: /* Modified by Broadcom Corp. Portions Copyright (c) Broadcom Corp, 2012. */
  /*
   * 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
  