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

Subversion Repositories or1k

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

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
#ifndef _ALPHA_SEMAPHORE_H
2
#define _ALPHA_SEMAPHORE_H
3
 
4
/*
5
 * SMP- and interrupt-safe semaphores..
6
 *
7
 * (C) Copyright 1996 Linus Torvalds
8
 * (C) Copyright 1996, 2000 Richard Henderson
9
 */
10
 
11
#include <asm/current.h>
12
#include <asm/system.h>
13
#include <asm/atomic.h>
14
#include <linux/compiler.h>
15
#include <linux/wait.h>
16
#include <linux/rwsem.h>
17
 
18
struct semaphore {
19
        /* Careful, inline assembly knows about the position of these two.  */
20
        atomic_t count __attribute__((aligned(8)));
21
        atomic_t waking;                /* biased by -1 */
22
 
23
        wait_queue_head_t wait;
24
#if WAITQUEUE_DEBUG
25
        long __magic;
26
#endif
27
};
28
 
29
#if WAITQUEUE_DEBUG
30
# define __SEM_DEBUG_INIT(name)         , (long)&(name).__magic
31
#else
32
# define __SEM_DEBUG_INIT(name)
33
#endif
34
 
35
#define __SEMAPHORE_INITIALIZER(name,count)             \
36
        { ATOMIC_INIT(count), ATOMIC_INIT(-1),          \
37
          __WAIT_QUEUE_HEAD_INITIALIZER((name).wait)    \
38
          __SEM_DEBUG_INIT(name) }
39
 
40
#define __MUTEX_INITIALIZER(name) \
41
        __SEMAPHORE_INITIALIZER(name,1)
42
 
43
#define __DECLARE_SEMAPHORE_GENERIC(name,count) \
44
        struct semaphore name = __SEMAPHORE_INITIALIZER(name,count)
45
 
46
#define DECLARE_MUTEX(name) __DECLARE_SEMAPHORE_GENERIC(name,1)
47
#define DECLARE_MUTEX_LOCKED(name) __DECLARE_SEMAPHORE_GENERIC(name,0)
48
 
49
static inline void sema_init(struct semaphore *sem, int val)
50
{
51
        /*
52
         * Logically,
53
         *   *sem = (struct semaphore)__SEMAPHORE_INITIALIZER((*sem),val);
54
         * except that gcc produces better initializing by parts yet.
55
         */
56
 
57
        atomic_set(&sem->count, val);
58
        atomic_set(&sem->waking, -1);
59
        init_waitqueue_head(&sem->wait);
60
#if WAITQUEUE_DEBUG
61
        sem->__magic = (long)&sem->__magic;
62
#endif
63
}
64
 
65
static inline void init_MUTEX (struct semaphore *sem)
66
{
67
        sema_init(sem, 1);
68
}
69
 
70
static inline void init_MUTEX_LOCKED (struct semaphore *sem)
71
{
72
        sema_init(sem, 0);
73
}
74
 
75
extern void down(struct semaphore *);
76
extern void __down_failed(struct semaphore *);
77
extern int  down_interruptible(struct semaphore *);
78
extern int  __down_failed_interruptible(struct semaphore *);
79
extern int  down_trylock(struct semaphore *);
80
extern void up(struct semaphore *);
81
extern void __up_wakeup(struct semaphore *);
82
 
83
static inline int sem_getcount(struct semaphore *sem)
84
{
85
        return atomic_read(&sem->count);
86
}
87
 
88
/*
89
 * Hidden out of line code is fun, but extremely messy.  Rely on newer
90
 * compilers to do a respectable job with this.  The contention cases
91
 * are handled out of line in arch/alpha/kernel/semaphore.c.
92
 */
93
 
94
static inline void __down(struct semaphore *sem)
95
{
96
        long count = atomic_dec_return(&sem->count);
97
        if (unlikely(count < 0))
98
                __down_failed(sem);
99
}
100
 
101
static inline int __down_interruptible(struct semaphore *sem)
102
{
103
        long count = atomic_dec_return(&sem->count);
104
        if (unlikely(count < 0))
105
                return __down_failed_interruptible(sem);
106
        return 0;
107
}
108
 
109
/*
110
 * down_trylock returns 0 on success, 1 if we failed to get the lock.
111
 *
112
 * We must manipulate count and waking simultaneously and atomically.
113
 * Do this by using ll/sc on the pair of 32-bit words.
114
 */
115
 
116
static inline int __down_trylock(struct semaphore * sem)
117
{
118
        long ret, tmp, tmp2, sub;
119
 
120
        /* "Equivalent" C.  Note that we have to do this all without
121
           (taken) branches in order to be a valid ll/sc sequence.
122
 
123
           do {
124
                tmp = ldq_l;
125
                sub = 0x0000000100000000;
126
                ret = ((int)tmp <= 0);          // count <= 0 ?
127
                // Note that if count=0, the decrement overflows into
128
                // waking, so cancel the 1 loaded above.  Also cancel
129
                // it if the lock was already free.
130
                if ((int)tmp >= 0) sub = 0;     // count >= 0 ?
131
                ret &= ((long)tmp < 0);         // waking < 0 ?
132
                sub += 1;
133
                if (ret) break;
134
                tmp -= sub;
135
                tmp = stq_c = tmp;
136
           } while (tmp == 0);
137
        */
138
 
139
        __asm__ __volatile__(
140
                "1:     ldq_l   %1,%4\n"
141
                "       lda     %3,1\n"
142
                "       addl    %1,0,%2\n"
143
                "       sll     %3,32,%3\n"
144
                "       cmple   %2,0,%0\n"
145
                "       cmovge  %2,0,%3\n"
146
                "       cmplt   %1,0,%2\n"
147
                "       addq    %3,1,%3\n"
148
                "       and     %0,%2,%0\n"
149
                "       bne     %0,2f\n"
150
                "       subq    %1,%3,%1\n"
151
                "       stq_c   %1,%4\n"
152
                "       beq     %1,3f\n"
153
                "2:     mb\n"
154
                ".subsection 2\n"
155
                "3:     br      1b\n"
156
                ".previous"
157
                : "=&r"(ret), "=&r"(tmp), "=&r"(tmp2), "=&r"(sub)
158
                : "m"(*sem)
159
                : "memory");
160
 
161
        return ret;
162
}
163
 
164
static inline void __up(struct semaphore *sem)
165
{
166
        long ret, tmp, tmp2, tmp3;
167
 
168
        /* We must manipulate count and waking simultaneously and atomically.
169
           Otherwise we have races between up and __down_failed_interruptible
170
           waking up on a signal.
171
 
172
           "Equivalent" C.  Note that we have to do this all without
173
           (taken) branches in order to be a valid ll/sc sequence.
174
 
175
           do {
176
                tmp = ldq_l;
177
                ret = (int)tmp + 1;                     // count += 1;
178
                tmp2 = tmp & 0xffffffff00000000;        // extract waking
179
                if (ret <= 0)                           // still sleepers?
180
                        tmp2 += 0x0000000100000000;     // waking += 1;
181
                tmp = ret & 0x00000000ffffffff;         // insert count
182
                tmp |= tmp2;                            // insert waking;
183
               tmp = stq_c = tmp;
184
           } while (tmp == 0);
185
        */
186
 
187
        __asm__ __volatile__(
188
                "       mb\n"
189
                "1:     ldq_l   %1,%4\n"
190
                "       addl    %1,1,%0\n"
191
                "       zapnot  %1,0xf0,%2\n"
192
                "       addq    %2,%5,%3\n"
193
                "       cmovle  %0,%3,%2\n"
194
                "       zapnot  %0,0x0f,%1\n"
195
                "       bis     %1,%2,%1\n"
196
                "       stq_c   %1,%4\n"
197
                "       beq     %1,3f\n"
198
                "2:\n"
199
                ".subsection 2\n"
200
                "3:     br      1b\n"
201
                ".previous"
202
                : "=&r"(ret), "=&r"(tmp), "=&r"(tmp2), "=&r"(tmp3)
203
                : "m"(*sem), "r"(0x0000000100000000)
204
                : "memory");
205
 
206
        if (unlikely(ret <= 0))
207
                __up_wakeup(sem);
208
}
209
 
210
#if !WAITQUEUE_DEBUG && !defined(CONFIG_DEBUG_SEMAPHORE)
211
extern inline void down(struct semaphore *sem)
212
{
213
        __down(sem);
214
}
215
extern inline int down_interruptible(struct semaphore *sem)
216
{
217
        return __down_interruptible(sem);
218
}
219
extern inline int down_trylock(struct semaphore *sem)
220
{
221
        return __down_trylock(sem);
222
}
223
extern inline void up(struct semaphore *sem)
224
{
225
        __up(sem);
226
}
227
#endif
228
 
229
#endif

powered by: WebSVN 2.1.0

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