1 /*
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) 2000-2003 Silicon Graphics, Inc.  All Rights Reserved.
7  *
8  * This implemenation of synchronization variables is heavily based on
9  * one done by Steve Lord <lord@sgi.com>
10  *
11  * Paul Cassella <pwc@sgi.com>
12  */
13 
14 #ifndef _ASM_IA64_SN_SV_H
15 #define _ASM_IA64_SN_SV_H
16 
17 #include <linux/spinlock.h>
18 #include <asm/semaphore.h>
19 
20 #ifndef ASSERT
21 
22 #define ASSERT(x) do {							  \
23                     if(!(x)) {						  \
24 		      printk(KERN_ERR "%s\n", "Assertion failed: " # x);  \
25 		      BUG();						  \
26 		    }							  \
27                   } while(0)
28 #define _SV_ASSERT
29 #endif
30 
31 typedef void sv_mon_lock_t;
32 typedef void (*sv_mon_unlock_func_t)(sv_mon_lock_t *lock);
33 
34 /* sv_flags values: */
35 
36 #define SV_ORDER_FIFO        0x001
37 #define SV_ORDER_FILO        0x002
38 #define SV_ORDER_LIFO        SV_ORDER_FILO
39 
40 /* If at some point one order becomes preferable to others, we can
41    switch to it if the caller of sv_init doesn't specify. */
42 #define SV_ORDER_DEFAULT     SV_ORDER_FIFO
43 
44 #define SV_ORDER_MASK        0x00f
45 
46 
47 #define SV_MON_SEMA          0x010
48 #define SV_MON_SPIN          0x020
49 
50 #define SV_MON_MASK          0x0f0
51 
52 
53 /*
54    If the monitor lock can be aquired from interrupts.  Note that this
55    is a superset of the cases in which the sv can be touched from
56    interrupts.
57 
58    This is currently only valid when the monitor lock is a spinlock.
59 
60    If this is used, sv_wait, sv_signal, and sv_broadcast must all be
61    called with interrupts disabled, which has to happen anyway to have
62    acquired the monitor spinlock.
63  */
64 #define SV_INTS              0x100
65 
66 /* ditto for bottom halves */
67 #define SV_BHS               0x200
68 
69 
70 
71 /* sv_wait_flag values: */
72 #define SV_WAIT_SIG          0x001 /* Allow sv_wait to be interrupted by a signal */
73 
74 typedef struct sv_s {
75 	wait_queue_head_t sv_waiters;
76 	sv_mon_lock_t *sv_mon_lock;   /* Lock held for exclusive access to monitor. */
77 	sv_mon_unlock_func_t sv_mon_unlock_func;
78 	spinlock_t sv_lock;  /* Spinlock protecting the sv itself. */
79 	int sv_flags;
80 } sv_t;
81 
82 #define DECLARE_SYNC_VARIABLE(sv, l, f) sv_t sv = sv_init(&sv, l, f)
83 
84 /*
85  * @sv the sync variable to initialize
86  * @monitor_lock the lock enforcing exclusive running in the monitor
87  * @flags one of
88  *   SV_MON_SEMA monitor_lock is a semaphore
89  *   SV_MON_SPIN monitor_lock is a spinlock
90  * and a bitwise or of some subset of
91  *   SV_INTS - the monitor lock can be acquired from interrupts (and
92  *             hence, whenever we hold it, interrupts are disabled or
93  *             we're in an interrupt.)  This is only valid when
94  *             SV_MON_SPIN is set.
95  */
96 void sv_init(sv_t *sv, sv_mon_lock_t *monitor_lock, int flags);
97 
98 /*
99  * Set SV_WAIT_SIG in sv_wait_flags to let the sv_wait be interrupted by signals.
100  *
101  * timeout is how long to wait before giving up, or 0 to wait
102  * indefinitely.  It is given in jiffies, and is relative.
103  *
104  * The associated lock must be locked on entry.  It is unlocked on return.
105  *
106  * Return values:
107  *
108  * n < 0 : interrupted,  -n jiffies remaining on timeout, or -1 if timeout == 0
109  * n = 0 : timeout expired
110  * n > 0 : sv_signal()'d, n jiffies remaining on timeout, or 1 if timeout == 0
111  */
112 extern signed long sv_wait(sv_t *sv, int sv_wait_flags,
113 			   unsigned long timeout /* relative jiffies */);
114 
sv_wait_compat(sv_t * sv,sv_mon_lock_t * lock,int sv_wait_flags,unsigned long timeout,int sv_mon_type)115 static inline int sv_wait_compat(sv_t *sv, sv_mon_lock_t *lock, int sv_wait_flags,
116 				 unsigned long timeout, int sv_mon_type)
117 {
118 	ASSERT(sv_mon_type == (sv->sv_flags & SV_MON_MASK));
119 	if(sv->sv_mon_lock)
120 		ASSERT(lock == sv->sv_mon_lock);
121 	else
122 		sv->sv_mon_lock = lock;
123 
124 	return sv_wait(sv, sv_wait_flags, timeout);
125 }
126 
127 
128 /* These work like Irix's sv_wait() and sv_wait_sig(), except the
129    caller must call the one correpsonding to the type of the monitor
130    lock. */
131 #define sv_spin_wait(sv, lock)                              \
132         sv_wait_compat(sv, lock, 0, 0, SV_MON_SPIN)
133 #define sv_spin_wait_sig(sv, lock)                          \
134         sv_wait_compat(sv, lock, SV_WAIT_SIG, 0, SV_MON_SPIN)
135 
136 #define sv_sema_wait(sv, lock)                              \
137         sv_wait_compat(sv, lock, 0, 0, SV_MON_SEMA)
138 #define sv_sema_wait_sig(sv, lock)                          \
139         sv_wait_compat(sv, lock, SV_WAIT_SIG, 0, SV_MON_SEMA)
140 
141 /* These work as in Irix. */
142 void sv_signal(sv_t *sv);
143 void sv_broadcast(sv_t *sv);
144 
145 /* This works as in Irix. */
146 void sv_destroy(sv_t *sv);
147 
148 #ifdef _SV_ASSERT
149 #undef ASSERT
150 #undef _SV_ASSERT
151 #endif
152 
153 #endif /* _ASM_IA64_SN_SV_H */
154