]>
Commit | Line | Data |
---|---|---|
342e73b3 JL |
1 | #ifndef _ASM_POWERPC_RWSEM_H |
2 | #define _ASM_POWERPC_RWSEM_H | |
3 | ||
20b31b53 RD |
4 | #ifndef _LINUX_RWSEM_H |
5 | #error "Please don't include <asm/rwsem.h> directly, use <linux/rwsem.h> instead." | |
6 | #endif | |
7 | ||
342e73b3 JL |
8 | #ifdef __KERNEL__ |
9 | ||
1da177e4 | 10 | /* |
b8b572e1 SR |
11 | * R/W semaphores for PPC using the stuff in lib/rwsem.c. |
12 | * Adapted largely from include/asm-i386/rwsem.h | |
1da177e4 | 13 | * by Paul Mackerras <paulus@samba.org>. |
1da177e4 LT |
14 | */ |
15 | ||
1da177e4 LT |
16 | #include <linux/list.h> |
17 | #include <linux/spinlock.h> | |
18 | #include <asm/atomic.h> | |
19 | #include <asm/system.h> | |
20 | ||
21 | /* | |
22 | * the semaphore definition | |
23 | */ | |
529b7307 BH |
24 | #ifdef CONFIG_PPC64 |
25 | # define RWSEM_ACTIVE_MASK 0xffffffffL | |
26 | #else | |
27 | # define RWSEM_ACTIVE_MASK 0x0000ffffL | |
28 | #endif | |
29 | ||
30 | #define RWSEM_UNLOCKED_VALUE 0x00000000L | |
31 | #define RWSEM_ACTIVE_BIAS 0x00000001L | |
32 | #define RWSEM_WAITING_BIAS (-RWSEM_ACTIVE_MASK-1) | |
1da177e4 LT |
33 | #define RWSEM_ACTIVE_READ_BIAS RWSEM_ACTIVE_BIAS |
34 | #define RWSEM_ACTIVE_WRITE_BIAS (RWSEM_WAITING_BIAS + RWSEM_ACTIVE_BIAS) | |
529b7307 BH |
35 | |
36 | struct rw_semaphore { | |
37 | long count; | |
1da177e4 LT |
38 | spinlock_t wait_lock; |
39 | struct list_head wait_list; | |
945feb17 BH |
40 | #ifdef CONFIG_DEBUG_LOCK_ALLOC |
41 | struct lockdep_map dep_map; | |
42 | #endif | |
1da177e4 LT |
43 | }; |
44 | ||
945feb17 BH |
45 | #ifdef CONFIG_DEBUG_LOCK_ALLOC |
46 | # define __RWSEM_DEP_MAP_INIT(lockname) , .dep_map = { .name = #lockname } | |
47 | #else | |
48 | # define __RWSEM_DEP_MAP_INIT(lockname) | |
49 | #endif | |
50 | ||
529b7307 BH |
51 | #define __RWSEM_INITIALIZER(name) \ |
52 | { \ | |
53 | RWSEM_UNLOCKED_VALUE, \ | |
54 | __SPIN_LOCK_UNLOCKED((name).wait_lock), \ | |
55 | LIST_HEAD_INIT((name).wait_list) \ | |
56 | __RWSEM_DEP_MAP_INIT(name) \ | |
57 | } | |
1da177e4 LT |
58 | |
59 | #define DECLARE_RWSEM(name) \ | |
60 | struct rw_semaphore name = __RWSEM_INITIALIZER(name) | |
61 | ||
62 | extern struct rw_semaphore *rwsem_down_read_failed(struct rw_semaphore *sem); | |
63 | extern struct rw_semaphore *rwsem_down_write_failed(struct rw_semaphore *sem); | |
64 | extern struct rw_semaphore *rwsem_wake(struct rw_semaphore *sem); | |
65 | extern struct rw_semaphore *rwsem_downgrade_wake(struct rw_semaphore *sem); | |
66 | ||
945feb17 BH |
67 | extern void __init_rwsem(struct rw_semaphore *sem, const char *name, |
68 | struct lock_class_key *key); | |
69 | ||
70 | #define init_rwsem(sem) \ | |
71 | do { \ | |
72 | static struct lock_class_key __key; \ | |
73 | \ | |
74 | __init_rwsem((sem), #sem, &__key); \ | |
75 | } while (0) | |
1da177e4 LT |
76 | |
77 | /* | |
78 | * lock for reading | |
79 | */ | |
80 | static inline void __down_read(struct rw_semaphore *sem) | |
81 | { | |
529b7307 | 82 | if (unlikely(atomic_long_inc_return((atomic_long_t *)&sem->count) <= 0)) |
1da177e4 LT |
83 | rwsem_down_read_failed(sem); |
84 | } | |
85 | ||
86 | static inline int __down_read_trylock(struct rw_semaphore *sem) | |
87 | { | |
529b7307 | 88 | long tmp; |
1da177e4 LT |
89 | |
90 | while ((tmp = sem->count) >= 0) { | |
91 | if (tmp == cmpxchg(&sem->count, tmp, | |
92 | tmp + RWSEM_ACTIVE_READ_BIAS)) { | |
93 | return 1; | |
94 | } | |
95 | } | |
96 | return 0; | |
97 | } | |
98 | ||
99 | /* | |
100 | * lock for writing | |
101 | */ | |
945feb17 | 102 | static inline void __down_write_nested(struct rw_semaphore *sem, int subclass) |
1da177e4 | 103 | { |
529b7307 | 104 | long tmp; |
1da177e4 | 105 | |
529b7307 BH |
106 | tmp = atomic_long_add_return(RWSEM_ACTIVE_WRITE_BIAS, |
107 | (atomic_long_t *)&sem->count); | |
1da177e4 LT |
108 | if (unlikely(tmp != RWSEM_ACTIVE_WRITE_BIAS)) |
109 | rwsem_down_write_failed(sem); | |
110 | } | |
111 | ||
945feb17 BH |
112 | static inline void __down_write(struct rw_semaphore *sem) |
113 | { | |
114 | __down_write_nested(sem, 0); | |
115 | } | |
116 | ||
1da177e4 LT |
117 | static inline int __down_write_trylock(struct rw_semaphore *sem) |
118 | { | |
529b7307 | 119 | long tmp; |
1da177e4 LT |
120 | |
121 | tmp = cmpxchg(&sem->count, RWSEM_UNLOCKED_VALUE, | |
122 | RWSEM_ACTIVE_WRITE_BIAS); | |
123 | return tmp == RWSEM_UNLOCKED_VALUE; | |
124 | } | |
125 | ||
126 | /* | |
127 | * unlock after reading | |
128 | */ | |
129 | static inline void __up_read(struct rw_semaphore *sem) | |
130 | { | |
529b7307 | 131 | long tmp; |
1da177e4 | 132 | |
529b7307 | 133 | tmp = atomic_long_dec_return((atomic_long_t *)&sem->count); |
1da177e4 LT |
134 | if (unlikely(tmp < -1 && (tmp & RWSEM_ACTIVE_MASK) == 0)) |
135 | rwsem_wake(sem); | |
136 | } | |
137 | ||
138 | /* | |
139 | * unlock after writing | |
140 | */ | |
141 | static inline void __up_write(struct rw_semaphore *sem) | |
142 | { | |
529b7307 BH |
143 | if (unlikely(atomic_long_sub_return(RWSEM_ACTIVE_WRITE_BIAS, |
144 | (atomic_long_t *)&sem->count) < 0)) | |
1da177e4 LT |
145 | rwsem_wake(sem); |
146 | } | |
147 | ||
148 | /* | |
149 | * implement atomic add functionality | |
150 | */ | |
529b7307 | 151 | static inline void rwsem_atomic_add(long delta, struct rw_semaphore *sem) |
1da177e4 | 152 | { |
529b7307 | 153 | atomic_long_add(delta, (atomic_long_t *)&sem->count); |
1da177e4 LT |
154 | } |
155 | ||
156 | /* | |
157 | * downgrade write lock to read lock | |
158 | */ | |
159 | static inline void __downgrade_write(struct rw_semaphore *sem) | |
160 | { | |
529b7307 | 161 | long tmp; |
1da177e4 | 162 | |
529b7307 BH |
163 | tmp = atomic_long_add_return(-RWSEM_WAITING_BIAS, |
164 | (atomic_long_t *)&sem->count); | |
1da177e4 LT |
165 | if (tmp < 0) |
166 | rwsem_downgrade_wake(sem); | |
167 | } | |
168 | ||
169 | /* | |
170 | * implement exchange and add functionality | |
171 | */ | |
529b7307 | 172 | static inline long rwsem_atomic_update(long delta, struct rw_semaphore *sem) |
1da177e4 | 173 | { |
529b7307 | 174 | return atomic_long_add_return(delta, (atomic_long_t *)&sem->count); |
1da177e4 LT |
175 | } |
176 | ||
eb92f4ef RVR |
177 | static inline int rwsem_is_locked(struct rw_semaphore *sem) |
178 | { | |
529b7307 | 179 | return sem->count != 0; |
eb92f4ef RVR |
180 | } |
181 | ||
342e73b3 JL |
182 | #endif /* __KERNEL__ */ |
183 | #endif /* _ASM_POWERPC_RWSEM_H */ |