1#ifndef _X86_64_SEMAPHORE_H
2#define _X86_64_SEMAPHORE_H
3
4#include <linux/linkage.h>
5
6#ifdef __KERNEL__
7
8/*
9 * SMP- and interrupt-safe semaphores..
10 *
11 * (C) Copyright 1996 Linus Torvalds
12 *
13 * Modified 1996-12-23 by Dave Grothe <dave@gcom.com> to fix bugs in
14 *                     the original code and to make semaphore waits
15 *                     interruptible so that processes waiting on
16 *                     semaphores can be killed.
17 * Modified 1999-02-14 by Andrea Arcangeli, split the sched.c helper
18 *		       functions in asm/sempahore-helper.h while fixing a
19 *		       potential and subtle race discovered by Ulrich Schmid
20 *		       in down_interruptible(). Since I started to play here I
21 *		       also implemented the `trylock' semaphore operation.
22 *          1999-07-02 Artur Skawina <skawina@geocities.com>
23 *                     Optimized "0(ecx)" -> "(ecx)" (the assembler does not
24 *                     do this). Changed calling sequences from push/jmp to
25 *                     traditional call/ret.
26 * Modified 2001-01-01 Andreas Franck <afranck@gmx.de>
27 *		       Some hacks to ensure compatibility with recent
28 *		       GCC snapshots, to avoid stack corruption when compiling
29 *		       with -fomit-frame-pointer. It's not sure if this will
30 *		       be fixed in GCC, as our previous implementation was a
31 *		       bit dubious.
32 *
33 * If you would like to see an analysis of this implementation, please
34 * ftp to gcom.com and download the file
35 * /pub/linux/src/semaphore/semaphore-2.0.24.tar.gz.
36 *
37 */
38
39#include <asm/system.h>
40#include <asm/atomic.h>
41#include <asm/rwlock.h>
42#include <linux/wait.h>
43#include <linux/rwsem.h>
44#include <linux/stringify.h>
45
46struct semaphore {
47	atomic_t count;
48	int sleepers;
49	wait_queue_head_t wait;
50#if WAITQUEUE_DEBUG
51	long __magic;
52#endif
53};
54
55#if WAITQUEUE_DEBUG
56# define __SEM_DEBUG_INIT(name) \
57		, (int)&(name).__magic
58#else
59# define __SEM_DEBUG_INIT(name)
60#endif
61
62#define __SEMAPHORE_INITIALIZER(name,count) \
63{ ATOMIC_INIT(count), 0, __WAIT_QUEUE_HEAD_INITIALIZER((name).wait) \
64	__SEM_DEBUG_INIT(name) }
65
66#define __MUTEX_INITIALIZER(name) \
67	__SEMAPHORE_INITIALIZER(name,1)
68
69#define __DECLARE_SEMAPHORE_GENERIC(name,count) \
70	struct semaphore name = __SEMAPHORE_INITIALIZER(name,count)
71
72#define DECLARE_MUTEX(name) __DECLARE_SEMAPHORE_GENERIC(name,1)
73#define DECLARE_MUTEX_LOCKED(name) __DECLARE_SEMAPHORE_GENERIC(name,0)
74
75static inline void sema_init (struct semaphore *sem, int val)
76{
77/*
78 *	*sem = (struct semaphore)__SEMAPHORE_INITIALIZER((*sem),val);
79 *
80 * i'd rather use the more flexible initialization above, but sadly
81 * GCC 2.7.2.3 emits a bogus warning. EGCS doesnt. Oh well.
82 */
83	atomic_set(&sem->count, val);
84	sem->sleepers = 0;
85	init_waitqueue_head(&sem->wait);
86#if WAITQUEUE_DEBUG
87	sem->__magic = (int)&sem->__magic;
88#endif
89}
90
91static inline void init_MUTEX (struct semaphore *sem)
92{
93	sema_init(sem, 1);
94}
95
96static inline void init_MUTEX_LOCKED (struct semaphore *sem)
97{
98	sema_init(sem, 0);
99}
100
101asmlinkage void __down_failed(void /* special register calling convention */);
102asmlinkage int  __down_failed_interruptible(void  /* params in registers */);
103asmlinkage int  __down_failed_trylock(void  /* params in registers */);
104asmlinkage void __up_wakeup(void /* special register calling convention */);
105
106asmlinkage void __down(struct semaphore * sem);
107asmlinkage int  __down_interruptible(struct semaphore * sem);
108asmlinkage int  __down_trylock(struct semaphore * sem);
109asmlinkage void __up(struct semaphore * sem);
110
111/*
112 * This is ugly, but we want the default case to fall through.
113 * "__down_failed" is a special asm handler that calls the C
114 * routine that actually waits. See arch/x86_64/kernel/semaphore.c
115 */
116static inline void down(struct semaphore * sem)
117{
118#if WAITQUEUE_DEBUG
119	CHECK_MAGIC(sem->__magic);
120#endif
121
122	__asm__ __volatile__(
123		"# atomic down operation\n\t"
124		LOCK "decl %0\n\t"     /* --sem->count */
125		"js 2f\n"
126		"1:\n"
127                ".subsection 1\n" \
128                ".ifndef _text_lock_" __stringify(KBUILD_BASENAME) "\n" \
129                "_text_lock_" __stringify(KBUILD_BASENAME) ":\n" \
130                ".endif\n" \
131		"2:\tcall __down_failed\n\t"
132		"jmp 1b\n"
133		".subsection 0"
134		:"=m" (sem->count)
135		:"D" (sem)
136		:"memory");
137}
138
139/*
140 * Interruptible try to acquire a semaphore.  If we obtained
141 * it, return zero.  If we were interrupted, returns -EINTR
142 */
143static inline int down_interruptible(struct semaphore * sem)
144{
145	int result;
146
147#if WAITQUEUE_DEBUG
148	CHECK_MAGIC(sem->__magic);
149#endif
150
151	__asm__ __volatile__(
152		"# atomic interruptible down operation\n\t"
153		LOCK "decl %1\n\t"     /* --sem->count */
154		"js 2f\n\t"
155		"xorl %0,%0\n"
156		"1:\n"
157                ".subsection 1\n" \
158               ".ifndef _text_lock_" __stringify(KBUILD_BASENAME) "\n" \
159                "_text_lock_" __stringify(KBUILD_BASENAME) ":\n" \
160                ".endif\n" \
161		"2:\tcall __down_failed_interruptible\n\t"
162		"jmp 1b\n"
163		".subsection 0"
164		:"=a" (result), "=m" (sem->count)
165		:"D" (sem)
166		:"memory");
167	return result;
168}
169
170/*
171 * Non-blockingly attempt to down() a semaphore.
172 * Returns zero if we acquired it
173 */
174static inline int down_trylock(struct semaphore * sem)
175{
176	int result;
177
178#if WAITQUEUE_DEBUG
179	CHECK_MAGIC(sem->__magic);
180#endif
181
182	__asm__ __volatile__(
183		"# atomic interruptible down operation\n\t"
184		LOCK "decl %1\n\t"     /* --sem->count */
185		"js 2f\n\t"
186		"xorl %0,%0\n"
187		"1:\n"
188                ".subsection 1\n" \
189                ".ifndef _text_lock_" __stringify(KBUILD_BASENAME) "\n" \
190                "_text_lock_" __stringify(KBUILD_BASENAME) ":\n" \
191                ".endif\n" \
192		"2:\tcall __down_failed_trylock\n\t"
193		"jmp 1b\n"
194		".subsection 0"
195		:"=a" (result), "=m" (sem->count)
196		:"D" (sem)
197		:"memory","cc");
198	return result;
199}
200
201/*
202 * Note! This is subtle. We jump to wake people up only if
203 * the semaphore was negative (== somebody was waiting on it).
204 * The default case (no contention) will result in NO
205 * jumps for both down() and up().
206 */
207static inline void up(struct semaphore * sem)
208{
209#if WAITQUEUE_DEBUG
210	CHECK_MAGIC(sem->__magic);
211#endif
212	__asm__ __volatile__(
213		"# atomic up operation\n\t"
214		LOCK "incl %0\n\t"     /* ++sem->count */
215		"jle 2f\n"
216		"1:\n"
217                ".subsection 1\n" \
218                ".ifndef _text_lock_" __stringify(KBUILD_BASENAME) "\n" \
219                "_text_lock_" __stringify(KBUILD_BASENAME) ":\n" \
220                ".endif\n" \
221		"2:\tcall __up_wakeup\n\t"
222		"jmp 1b\n"
223		".subsection 0"
224		:"=m" (sem->count)
225		:"D" (sem)
226		:"memory");
227}
228
229static inline int sem_getcount(struct semaphore *sem)
230{
231       return atomic_read(&sem->count);
232}
233
234#endif /* __KERNEL__ */
235#endif
236