2 * SMP- and interrupt-safe semaphores helper functions.
4 * Copyright (C) 1996 Linus Torvalds
5 * Copyright (C) 1999 Andrea Arcangeli
6 * Copyright (C) 1999 Ralf Baechle
7 * Copyright (C) 1999 Silicon Graphics, Inc.
8 * Copyright (C) 2000 MIPS Technologies, Inc.
10 #ifndef _ASM_SEMAPHORE_HELPER_H
11 #define _ASM_SEMAPHORE_HELPER_H
13 #include <linux/config.h>
15 #define sem_read(a) ((a)->counter)
16 #define sem_inc(a) (((a)->counter)++)
17 #define sem_dec(a) (((a)->counter)--)
19 * These two _must_ execute atomically wrt each other.
21 static inline void wake_one_more(struct semaphore * sem)
23 atomic_inc(&sem->waking);
26 #ifdef CONFIG_CPU_HAS_LLSC
28 static inline int waking_non_zero(struct semaphore *sem)
33 "1:\tll\t%1, %2\t\t\t# waking_non_zero\n\t"
39 : "=r" (ret), "=r" (tmp), "+m" (sem->waking)
45 #else /* !CONFIG_CPU_HAS_LLSC */
48 * It doesn't make sense, IMHO, to endlessly turn interrupts off and on again.
49 * Do it once and that's it. ll/sc *has* it's advantages. HK
52 static inline int waking_non_zero(struct semaphore *sem)
58 if (sem_read(&sem->waking) > 0) {
59 sem_dec(&sem->waking);
65 #endif /* !CONFIG_CPU_HAS_LLSC */
67 #ifdef CONFIG_CPU_HAS_LLDSCD
70 * waking_non_zero_interruptible:
75 * We must undo the sem->count down_interruptible decrement
76 * simultaneously and atomically with the sem->waking adjustment,
77 * otherwise we can race with wake_one_more.
79 * This is accomplished by doing a 64-bit lld/scd on the 2 32-bit words.
81 * This is crazy. Normally it's strictly forbidden to use 64-bit operations
82 * in the 32-bit MIPS kernel. In this case it's however ok because if an
83 * interrupt has destroyed the upper half of registers sc will fail.
84 * Note also that this will not work for MIPS32 CPUs!
88 * If(sem->waking > 0) {
89 * Decrement(sem->waking)
91 * } else If(signal_pending(tsk)) {
92 * Increment(sem->count)
100 waking_non_zero_interruptible(struct semaphore *sem, struct task_struct *tsk)
104 __asm__ __volatile__(
108 "0:\tlld\t%1, %2\n\t"
112 "daddiu\t%1, %1, -1\n\t"
115 "1:\tbeqz\t%3, 2f\n\t"
117 "dli\t$1, 0x0000000100000000\n\t"
118 "daddu\t%1, %1, $1\n"
119 "2:\tscd\t%1, %2\n\t"
122 : "=&r" (ret), "=&r" (tmp), "=m" (*sem)
123 : "r" (signal_pending(tsk)), "i" (-EINTR));
129 * waking_non_zero_trylock is unused. we do everything in
130 * down_trylock and let non-ll/sc hosts bounce around.
133 static inline int waking_non_zero_trylock(struct semaphore *sem)
136 CHECK_MAGIC(sem->__magic);
142 #else /* !CONFIG_CPU_HAS_LLDSCD */
144 static inline int waking_non_zero_interruptible(struct semaphore *sem,
145 struct task_struct *tsk)
151 if (sem_read(&sem->waking) > 0) {
152 sem_dec(&sem->waking);
154 } else if (signal_pending(tsk)) {
155 sem_inc(&sem->count);
158 restore_flags(flags);
162 static inline int waking_non_zero_trylock(struct semaphore *sem)
168 if (sem_read(&sem->waking) <= 0)
169 sem_inc(&sem->count);
171 sem_dec(&sem->waking);
174 restore_flags(flags);
179 #endif /* !CONFIG_CPU_HAS_LLDSCD */
181 #endif /* _ASM_SEMAPHORE_HELPER_H */