OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [include/] [asm-mips64/] [semaphore.h] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*
2
 * This file is subject to the terms and conditions of the GNU General Public
3
 * License.  See the file "COPYING" in the main directory of this archive
4
 * for more details.
5
 *
6
 * Copyright (C) 1996  Linus Torvalds
7
 * Copyright (C) 1998, 99, 2000, 01  Ralf Baechle
8
 * Copyright (C) 1999, 2000, 01  Silicon Graphics, Inc.
9
 * Copyright (C) 2000, 01 MIPS Technologies, Inc.
10
 */
11
#ifndef _ASM_SEMAPHORE_H
12
#define _ASM_SEMAPHORE_H
13
 
14
#include <linux/compiler.h>
15
#include <linux/config.h>
16
#include <linux/spinlock.h>
17
#include <linux/wait.h>
18
#include <linux/rwsem.h>
19
#include <asm/atomic.h>
20
 
21
struct semaphore {
22
#ifdef __MIPSEB__
23
        atomic_t count;
24
        atomic_t waking;
25
#else
26
        atomic_t waking;
27
        atomic_t count;
28
#endif
29
        wait_queue_head_t wait;
30
#if WAITQUEUE_DEBUG
31
        long __magic;
32
#endif
33
} __attribute__((aligned(8)));
34
 
35
#if WAITQUEUE_DEBUG
36
# define __SEM_DEBUG_INIT(name) , .__magic = (long)&(name).__magic
37
#else
38
# define __SEM_DEBUG_INIT(name)
39
#endif
40
 
41
#define __SEMAPHORE_INITIALIZER(name,_count) {                          \
42
        .count  = ATOMIC_INIT(_count),                                  \
43
        .waking = ATOMIC_INIT(0),                                        \
44
        .wait   = __WAIT_QUEUE_HEAD_INITIALIZER((name).wait)            \
45
        __SEM_DEBUG_INIT(name)                                          \
46
}
47
 
48
#define __MUTEX_INITIALIZER(name) __SEMAPHORE_INITIALIZER(name, 1)
49
 
50
#define __DECLARE_SEMAPHORE_GENERIC(name,count) \
51
        struct semaphore name = __SEMAPHORE_INITIALIZER(name, count)
52
 
53
#define DECLARE_MUTEX(name) __DECLARE_SEMAPHORE_GENERIC(name, 1)
54
#define DECLARE_MUTEX_LOCKED(name) __DECLARE_SEMAPHORE_GENERIC(name,0)
55
 
56
static inline void sema_init (struct semaphore *sem, int val)
57
{
58
        atomic_set(&sem->count, val);
59
        atomic_set(&sem->waking, 0);
60
        init_waitqueue_head(&sem->wait);
61
#if WAITQUEUE_DEBUG
62
        sem->__magic = (long)&sem->__magic;
63
#endif
64
}
65
 
66
static inline void init_MUTEX (struct semaphore *sem)
67
{
68
        sema_init(sem, 1);
69
}
70
 
71
static inline void init_MUTEX_LOCKED (struct semaphore *sem)
72
{
73
        sema_init(sem, 0);
74
}
75
 
76
#ifndef CONFIG_CPU_HAS_LLDSCD
77
/*
78
 * On machines without lld/scd we need a spinlock to make the manipulation of
79
 * sem->count and sem->waking atomic.
80
 */
81
extern spinlock_t semaphore_lock;
82
#endif
83
 
84
extern void __down_failed(struct semaphore * sem);
85
extern int  __down_failed_interruptible(struct semaphore * sem);
86
extern void __up_wakeup(struct semaphore * sem);
87
 
88
static inline void down(struct semaphore * sem)
89
{
90
        int count;
91
 
92
#if WAITQUEUE_DEBUG
93
        CHECK_MAGIC(sem->__magic);
94
#endif
95
        count = atomic_dec_return(&sem->count);
96
        if (unlikely(count < 0))
97
                __down_failed(sem);
98
}
99
 
100
/*
101
 * Interruptible try to acquire a semaphore.  If we obtained
102
 * it, return zero.  If we were interrupted, returns -EINTR
103
 */
104
static inline int down_interruptible(struct semaphore * sem)
105
{
106
        int count;
107
 
108
#if WAITQUEUE_DEBUG
109
        CHECK_MAGIC(sem->__magic);
110
#endif
111
        count = atomic_dec_return(&sem->count);
112
        if (unlikely(count < 0))
113
                return __down_failed_interruptible(sem);
114
 
115
        return 0;
116
}
117
 
118
#ifdef CONFIG_CPU_HAS_LLDSCD
119
 
120
/*
121
 * down_trylock returns 0 on success, 1 if we failed to get the lock.
122
 *
123
 * We must manipulate count and waking simultaneously and atomically.
124
 * Here, we do this by using lld/scd on the pair of 32-bit words.
125
 *
126
 * Pseudocode:
127
 *
128
 *   Decrement(sem->count)
129
 *   If(sem->count >=0) {
130
 *      Return(SUCCESS)                 // resource is free
131
 *   } else {
132
 *      If(sem->waking <= 0) {          // if no wakeup pending
133
 *         Increment(sem->count)        // undo decrement
134
 *         Return(FAILURE)
135
 *      } else {
136
 *         Decrement(sem->waking)       // otherwise "steal" wakeup
137
 *         Return(SUCCESS)
138
 *      }
139
 *   }
140
 */
141
static inline int down_trylock(struct semaphore * sem)
142
{
143
        long ret, tmp, tmp2, sub;
144
 
145
#if WAITQUEUE_DEBUG
146
        CHECK_MAGIC(sem->__magic);
147
#endif
148
 
149
        __asm__ __volatile__(
150
        "       .set    mips3                   # down_trylock          \n"
151
        "0:     lld     %1, %4                                          \n"
152
        "       dli     %3, 0x0000000100000000  # count -= 1            \n"
153
        "       dsubu   %1, %3                                          \n"
154
        "       li      %0, 0                   # ret = 0               \n"
155
        "       bgez    %1, 2f                  # if count >= 0         \n"
156
        "       sll     %2, %1, 0               # extract waking        \n"
157
        "       blez    %2, 1f                  # if waking < 0 -> 1f   \n"
158
        "       daddiu  %1, %1, -1              # waking -= 1           \n"
159
        "       b       2f                                              \n"
160
        "1:     daddu   %1, %1, %3              # count += 1            \n"
161
        "       li      %0, 1                   # ret = 1               \n"
162
        "2:     scd     %1, %4                                          \n"
163
        "       beqz    %1, 0b                                          \n"
164
        "       sync                                                    \n"
165
        "       .set    mips0                                           \n"
166
        : "=&r"(ret), "=&r"(tmp), "=&r"(tmp2), "=&r"(sub)
167
        : "m"(*sem)
168
        : "memory");
169
 
170
        return ret;
171
}
172
 
173
/*
174
 * Note! This is subtle. We jump to wake people up only if
175
 * the semaphore was negative (== somebody was waiting on it).
176
 */
177
static inline void up(struct semaphore * sem)
178
{
179
        unsigned long tmp, tmp2;
180
        int count;
181
 
182
#if WAITQUEUE_DEBUG
183
        CHECK_MAGIC(sem->__magic);
184
#endif
185
        /*
186
         * We must manipulate count and waking simultaneously and atomically.
187
         * Otherwise we have races between up and __down_failed_interruptible
188
         * waking up on a signal.
189
         */
190
 
191
        __asm__ __volatile__(
192
        "       .set    mips3                                   \n"
193
        "       sync                    # up                    \n"
194
        "1:     lld     %1, %3                                  \n"
195
        "       dsra32  %0, %1, 0       # extract count to %0   \n"
196
        "       daddiu  %0, 1           # count += 1            \n"
197
        "       slti    %2, %0, 1       # %3 = (%0 <= 0)        \n"
198
        "       daddu   %1, %2          # waking += %3          \n"
199
        "       dsll32 %1, %1, 0        # zero-extend %1        \n"
200
        "       dsrl32 %1, %1, 0                                \n"
201
        "       dsll32  %2, %0, 0       # Reassemble union      \n"
202
        "       or      %1, %2          # from count and waking \n"
203
        "       scd     %1, %3                                  \n"
204
        "       beqz    %1, 1b                                  \n"
205
        "       .set    mips0                                   \n"
206
        : "=&r"(count), "=&r"(tmp), "=&r"(tmp2), "+m"(*sem)
207
        :
208
        : "memory");
209
 
210
        if (unlikely(count <= 0))
211
                __up_wakeup(sem);
212
}
213
 
214
#else
215
 
216
/*
217
 * Non-blockingly attempt to down() a semaphore.
218
 * Returns zero if we acquired it
219
 */
220
static inline int down_trylock(struct semaphore * sem)
221
{
222
        unsigned long flags;
223
        int count, waking;
224
        int ret = 0;
225
 
226
#if WAITQUEUE_DEBUG
227
        CHECK_MAGIC(sem->__magic);
228
#endif
229
 
230
        spin_lock_irqsave(&semaphore_lock, flags);
231
        count = atomic_read(&sem->count) - 1;
232
        atomic_set(&sem->count, count);
233
        if (unlikely(count < 0)) {
234
                waking = atomic_read(&sem->waking);
235
                if (waking <= 0) {
236
                        atomic_set(&sem->count, count + 1);
237
                        ret = 1;
238
                } else {
239
                        atomic_set(&sem->waking, waking - 1);
240
                        ret = 0;
241
                }
242
        }
243
        spin_unlock_irqrestore(&semaphore_lock, flags);
244
 
245
        return ret;
246
}
247
 
248
/*
249
 * Note! This is subtle. We jump to wake people up only if
250
 * the semaphore was negative (== somebody was waiting on it).
251
 */
252
static inline void up(struct semaphore * sem)
253
{
254
        unsigned long flags;
255
        int count, waking;
256
 
257
#if WAITQUEUE_DEBUG
258
        CHECK_MAGIC(sem->__magic);
259
#endif
260
        /*
261
         * We must manipulate count and waking simultaneously and atomically.
262
         * Otherwise we have races between up and __down_failed_interruptible
263
         * waking up on a signal.
264
         */
265
 
266
        spin_lock_irqsave(&semaphore_lock, flags);
267
        count = atomic_read(&sem->count) + 1;
268
        waking = atomic_read(&sem->waking);
269
        if (count <= 0)
270
                waking++;
271
        atomic_set(&sem->count, count);
272
        atomic_set(&sem->waking, waking);
273
        spin_unlock_irqrestore(&semaphore_lock, flags);
274
 
275
        if (unlikely(count <= 0))
276
                __up_wakeup(sem);
277
}
278
 
279
#endif /* CONFIG_CPU_HAS_LLDSCD */
280
 
281
static inline int sem_getcount(struct semaphore *sem)
282
{
283
        return atomic_read(&sem->count);
284
}
285
 
286
#endif /* _ASM_SEMAPHORE_H */

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.