Commit | Line | Data |
---|---|---|
0c912232 MT |
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 | |
22 | __mutex_fastpath_lock(atomic_t *count, void (*fail_fn)(atomic_t *)) | |
23 | { | |
c20f326a | 24 | int __done, __res; |
0c912232 MT |
25 | |
26 | __asm__ __volatile__ ( | |
77ba93a7 PM |
27 | "movli.l @%2, %0 \n" |
28 | "add #-1, %0 \n" | |
29 | "movco.l %0, @%2 \n" | |
30 | "movt %1 \n" | |
c20f326a | 31 | : "=&z" (__res), "=&r" (__done) |
0c912232 MT |
32 | : "r" (&(count)->counter) |
33 | : "t"); | |
34 | ||
c20f326a | 35 | if (unlikely(!__done || __res != 0)) |
0c912232 MT |
36 | fail_fn(count); |
37 | } | |
38 | ||
39 | static inline int | |
40 | __mutex_fastpath_lock_retval(atomic_t *count, int (*fail_fn)(atomic_t *)) | |
41 | { | |
c20f326a | 42 | int __done, __res; |
0c912232 MT |
43 | |
44 | __asm__ __volatile__ ( | |
77ba93a7 PM |
45 | "movli.l @%2, %0 \n" |
46 | "add #-1, %0 \n" | |
47 | "movco.l %0, @%2 \n" | |
48 | "movt %1 \n" | |
c20f326a | 49 | : "=&z" (__res), "=&r" (__done) |
0c912232 MT |
50 | : "r" (&(count)->counter) |
51 | : "t"); | |
52 | ||
c20f326a | 53 | if (unlikely(!__done || __res != 0)) |
0c912232 MT |
54 | __res = fail_fn(count); |
55 | ||
56 | return __res; | |
57 | } | |
58 | ||
59 | static inline void | |
60 | __mutex_fastpath_unlock(atomic_t *count, void (*fail_fn)(atomic_t *)) | |
61 | { | |
c20f326a | 62 | int __done, __res; |
0c912232 MT |
63 | |
64 | __asm__ __volatile__ ( | |
77ba93a7 | 65 | "movli.l @%2, %0 \n\t" |
0c912232 | 66 | "add #1, %0 \n\t" |
77ba93a7 PM |
67 | "movco.l %0, @%2 \n\t" |
68 | "movt %1 \n\t" | |
c20f326a | 69 | : "=&z" (__res), "=&r" (__done) |
0c912232 MT |
70 | : "r" (&(count)->counter) |
71 | : "t"); | |
72 | ||
c20f326a | 73 | if (unlikely(!__done || __res <= 0)) |
0c912232 MT |
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 | |
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 */ |