1 /* $Id: semaphore.c,v 1.9 2001/11/18 00:12:56 davem Exp $
2  * semaphore.c: Sparc64 semaphore implementation.
3  *
4  * This is basically the PPC semaphore scheme ported to use
5  * the sparc64 atomic instructions, so see the PPC code for
6  * credits.
7  */
8 
9 #include <linux/sched.h>
10 
11 /*
12  * Atomically update sem->count.
13  * This does the equivalent of the following:
14  *
15  *	old_count = sem->count;
16  *	tmp = MAX(old_count, 0) + incr;
17  *	sem->count = tmp;
18  *	return old_count;
19  */
__sem_update_count(struct semaphore * sem,int incr)20 static __inline__ int __sem_update_count(struct semaphore *sem, int incr)
21 {
22 	int old_count, tmp;
23 
24 	__asm__ __volatile__("\n"
25 "	! __sem_update_count old_count(%0) tmp(%1) incr(%4) &sem->count(%3)\n"
26 "1:	ldsw	[%3], %0\n"
27 "	mov	%0, %1\n"
28 "	cmp	%0, 0\n"
29 "	movl	%%icc, 0, %1\n"
30 "	add	%1, %4, %1\n"
31 "	cas	[%3], %0, %1\n"
32 "	cmp	%0, %1\n"
33 "	bne,pn	%%icc, 1b\n"
34 "	 membar #StoreLoad | #StoreStore\n"
35 	: "=&r" (old_count), "=&r" (tmp), "=m" (sem->count)
36 	: "r" (&sem->count), "r" (incr), "m" (sem->count)
37 	: "cc");
38 
39 	return old_count;
40 }
41 
__up(struct semaphore * sem)42 void __up(struct semaphore *sem)
43 {
44 	__sem_update_count(sem, 1);
45 	wake_up(&sem->wait);
46 }
47 
__down(struct semaphore * sem)48 void __down(struct semaphore * sem)
49 {
50 	struct task_struct *tsk = current;
51 	DECLARE_WAITQUEUE(wait, tsk);
52 
53 	tsk->state = TASK_UNINTERRUPTIBLE;
54 	add_wait_queue_exclusive(&sem->wait, &wait);
55 
56 	while (__sem_update_count(sem, -1) <= 0) {
57 		schedule();
58 		tsk->state = TASK_UNINTERRUPTIBLE;
59 	}
60 	remove_wait_queue(&sem->wait, &wait);
61 	tsk->state = TASK_RUNNING;
62 
63 	wake_up(&sem->wait);
64 }
65 
__down_interruptible(struct semaphore * sem)66 int __down_interruptible(struct semaphore * sem)
67 {
68 	int retval = 0;
69 	struct task_struct *tsk = current;
70 	DECLARE_WAITQUEUE(wait, tsk);
71 
72 	tsk->state = TASK_INTERRUPTIBLE;
73 	add_wait_queue_exclusive(&sem->wait, &wait);
74 
75 	while (__sem_update_count(sem, -1) <= 0) {
76 		if (signal_pending(current)) {
77 			__sem_update_count(sem, 0);
78 			retval = -EINTR;
79 			break;
80 		}
81 		schedule();
82 		tsk->state = TASK_INTERRUPTIBLE;
83 	}
84 	tsk->state = TASK_RUNNING;
85 	remove_wait_queue(&sem->wait, &wait);
86 	wake_up(&sem->wait);
87 	return retval;
88 }
89