1 /*
2  * arch/sh/include/asm/mutex-llsc.h
3  *
4  * SH-4A optimized mutex locking primitives
5  *
6  * Please look into asm-generic/mutex-xchg.h for a formal definition.
7  */
8 #ifndef __ASM_SH_MUTEX_LLSC_H
9 #define __ASM_SH_MUTEX_LLSC_H
10 
11 /*
12  * Attempting to lock a mutex on SH4A is done like in ARMv6+ architecure.
13  * with a bastardized atomic decrement (it is not a reliable atomic decrement
14  * but it satisfies the defined semantics for our purpose, while being
15  * smaller and faster than a real atomic decrement or atomic swap.
16  * The idea is to attempt  decrementing the lock value only once. If once
17  * decremented it isn't zero, or if its store-back fails due to a dispute
18  * on the exclusive store, we simply bail out immediately through the slow
19  * path where the lock will be reattempted until it succeeds.
20  */
21 static inline void
__mutex_fastpath_lock(atomic_t * count,void (* fail_fn)(atomic_t *))22 __mutex_fastpath_lock(atomic_t *count, void (*fail_fn)(atomic_t *))
23 {
24 	int __done, __res;
25 
26 	__asm__ __volatile__ (
27 		"movli.l	@%2, %0	\n"
28 		"add		#-1, %0	\n"
29 		"movco.l	%0, @%2	\n"
30 		"movt		%1	\n"
31 		: "=&z" (__res), "=&r" (__done)
32 		: "r" (&(count)->counter)
33 		: "t");
34 
35 	if (unlikely(!__done || __res != 0))
36 		fail_fn(count);
37 }
38 
39 static inline int
__mutex_fastpath_lock_retval(atomic_t * count,int (* fail_fn)(atomic_t *))40 __mutex_fastpath_lock_retval(atomic_t *count, int (*fail_fn)(atomic_t *))
41 {
42 	int __done, __res;
43 
44 	__asm__ __volatile__ (
45 		"movli.l	@%2, %0	\n"
46 		"add		#-1, %0	\n"
47 		"movco.l	%0, @%2	\n"
48 		"movt		%1	\n"
49 		: "=&z" (__res), "=&r" (__done)
50 		: "r" (&(count)->counter)
51 		: "t");
52 
53 	if (unlikely(!__done || __res != 0))
54 		__res = fail_fn(count);
55 
56 	return __res;
57 }
58 
59 static inline void
__mutex_fastpath_unlock(atomic_t * count,void (* fail_fn)(atomic_t *))60 __mutex_fastpath_unlock(atomic_t *count, void (*fail_fn)(atomic_t *))
61 {
62 	int __done, __res;
63 
64 	__asm__ __volatile__ (
65 		"movli.l	@%2, %0	\n\t"
66 		"add		#1, %0	\n\t"
67 		"movco.l	%0, @%2 \n\t"
68 		"movt		%1	\n\t"
69 		: "=&z" (__res), "=&r" (__done)
70 		: "r" (&(count)->counter)
71 		: "t");
72 
73 	if (unlikely(!__done || __res <= 0))
74 		fail_fn(count);
75 }
76 
77 /*
78  * If the unlock was done on a contended lock, or if the unlock simply fails
79  * then the mutex remains locked.
80  */
81 #define __mutex_slowpath_needs_to_unlock()	1
82 
83 /*
84  * For __mutex_fastpath_trylock we do an atomic decrement and check the
85  * result and put it in the __res variable.
86  */
87 static inline int
__mutex_fastpath_trylock(atomic_t * count,int (* fail_fn)(atomic_t *))88 __mutex_fastpath_trylock(atomic_t *count, int (*fail_fn)(atomic_t *))
89 {
90 	int __res, __orig;
91 
92 	__asm__ __volatile__ (
93 		"1: movli.l	@%2, %0		\n\t"
94 		"dt		%0		\n\t"
95 		"movco.l	%0,@%2		\n\t"
96 		"bf		1b		\n\t"
97 		"cmp/eq		#0,%0		\n\t"
98 		"bt		2f		\n\t"
99 		"mov		#0, %1		\n\t"
100 		"bf		3f		\n\t"
101 		"2: mov		#1, %1		\n\t"
102 		"3:				"
103 		: "=&z" (__orig), "=&r" (__res)
104 		: "r" (&count->counter)
105 		: "t");
106 
107 	return __res;
108 }
109 #endif /* __ASM_SH_MUTEX_LLSC_H */
110