make oldconfig will rebuild these...
[linux-2.4.21-pre4.git] / include / asm-mips64 / semaphore-helper.h
1 /*
2  * SMP- and interrupt-safe semaphores helper functions.
3  *
4  * (C) Copyright 1996 Linus Torvalds
5  * (C) Copyright 1999 Andrea Arcangeli
6  * (C) Copyright 1999, 2001 Ralf Baechle
7  * (C) Copyright 1999, 2001 Silicon Graphics, Inc.
8  */
9 #ifndef _ASM_SEMAPHORE_HELPER_H
10 #define _ASM_SEMAPHORE_HELPER_H
11
12 /*
13  * These two _must_ execute atomically wrt each other.
14  */
15 static inline void wake_one_more(struct semaphore * sem)
16 {
17         atomic_inc(&sem->waking);
18 }
19
20 static inline int waking_non_zero(struct semaphore *sem)
21 {
22         int ret, tmp;
23
24         __asm__ __volatile__(
25         "1:\tll\t%1, %2\t\t\t# waking_non_zero\n\t"
26         "blez\t%1, 2f\n\t"
27         "subu\t%0, %1, 1\n\t"
28         "sc\t%0, %2\n\t"
29         "beqz\t%0, 1b\n"
30         "2:"
31         : "=r" (ret), "=r" (tmp), "+m" (sem->waking)
32         : "0" (0));
33
34         return ret;
35 }
36
37 /*
38  * waking_non_zero_interruptible:
39  *      1       got the lock
40  *      0       go to sleep
41  *      -EINTR  interrupted
42  *
43  * We must undo the sem->count down_interruptible decrement
44  * simultaneously and atomically with the sem->waking adjustment,
45  * otherwise we can race with wake_one_more.
46  *
47  * This is accomplished by doing a 64-bit lld/scd on the 2 32-bit words.
48  *
49  * Pseudocode:
50  *
51  * If(sem->waking > 0) {
52  *      Decrement(sem->waking)
53  *      Return(SUCCESS)
54  * } else If(signal_pending(tsk)) {
55  *      Increment(sem->count)
56  *      Return(-EINTR)
57  * } else {
58  *      Return(SLEEP)
59  * }
60  */
61
62 static inline int
63 waking_non_zero_interruptible(struct semaphore *sem, struct task_struct *tsk)
64 {
65         long ret, tmp;
66
67 #ifdef __MIPSEB__
68
69         __asm__ __volatile__(
70         ".set\tpush\t\t\t# waking_non_zero_interruptible\n\t"
71         ".set\tnoat\n\t"
72         "0:\tlld\t%1, %2\n\t"
73         "li\t%0, 0\n\t"
74         "sll\t$1, %1, 0\n\t"
75         "blez\t$1, 1f\n\t"
76         "daddiu\t%1, %1, -1\n\t"
77         "li\t%0, 1\n\t"
78         "b\t2f\n\t"
79         "1:\tbeqz\t%3, 2f\n\t"
80         "li\t%0, %4\n\t"
81         "dli\t$1, 0x0000000100000000\n\t"
82         "daddu\t%1, %1, $1\n\t"
83         "2:\tscd\t%1, %2\n\t"
84         "beqz\t%1, 0b\n\t"
85         ".set\tpop"
86         : "=&r" (ret), "=&r" (tmp), "=m" (*sem)
87         : "r" (signal_pending(tsk)), "i" (-EINTR));
88
89 #elif defined(__MIPSEL__)
90
91         __asm__ __volatile__(
92         ".set\tpush\t\t\t# waking_non_zero_interruptible\n\t"
93         ".set\t noat\n"
94         "0:\tlld\t%1, %2\n\t"
95         "li\t%0, 0\n\t"
96         "blez\t%1, 1f\n\t"
97         "dli\t$1, 0x0000000100000000\n\t"
98         "dsubu\t%1, %1, $1\n\t"
99         "li\t%0, 1\n\t"
100         "b\t2f\n"
101         "1:\tbeqz\t%3, 2f\n\t"
102         "li\t%0, %4\n\t"
103         /*
104          * It would be nice to assume that sem->count
105          * is != -1, but we will guard against that case
106          */
107         "daddiu\t$1, %1, 1\n\t"
108         "dsll32\t$1, $1, 0\n\t"
109         "dsrl32\t$1, $1, 0\n\t"
110         "dsrl32\t%1, %1, 0\n\t"
111         "dsll32\t%1, %1, 0\n\t"
112         "or\t%1, %1, $1\n"
113         "2:\tscd\t%1, %2\n\t"
114         "beqz\t %1, 0b\n\t"
115         ".set\tpop"
116         : "=&r" (ret), "=&r" (tmp), "=m" (*sem)
117         : "r" (signal_pending(tsk)), "i" (-EINTR));
118
119 #endif
120
121         return ret;
122 }
123
124 /*
125  * waking_non_zero_trylock is unused.  we do everything in
126  * down_trylock and let non-ll/sc hosts bounce around.
127  */
128
129 static inline int waking_non_zero_trylock(struct semaphore *sem)
130 {
131 #if WAITQUEUE_DEBUG
132         CHECK_MAGIC(sem->__magic);
133 #endif
134
135         return 0;
136 }
137
138 #endif /* _ASM_SEMAPHORE_HELPER_H */