1#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 18struct 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 49static 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 65static inline void init_MUTEX (struct semaphore *sem) 66{ 67 sema_init(sem, 1); 68} 69 70static inline void init_MUTEX_LOCKED (struct semaphore *sem) 71{ 72 sema_init(sem, 0); 73} 74 75extern void down(struct semaphore *); 76extern void __down_failed(struct semaphore *); 77extern int down_interruptible(struct semaphore *); 78extern int __down_failed_interruptible(struct semaphore *); 79extern int down_trylock(struct semaphore *); 80extern void up(struct semaphore *); 81extern void __up_wakeup(struct semaphore *); 82 83static 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 94static 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 101static 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 116static 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 164static 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) 211extern inline void down(struct semaphore *sem) 212{ 213 __down(sem); 214} 215extern inline int down_interruptible(struct semaphore *sem) 216{ 217 return __down_interruptible(sem); 218} 219extern inline int down_trylock(struct semaphore *sem) 220{ 221 return __down_trylock(sem); 222} 223extern inline void up(struct semaphore *sem) 224{ 225 __up(sem); 226} 227#endif 228 229#endif 230