blob: dffc62589f7928019e864115f307dff1ee476fdb [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
Robert P. J. Day711be602007-06-08 11:56:31 +09002 * include/asm-sh/rwsem.h: R/W semaphores for SH using the stuff
Linus Torvalds1da177e2005-04-16 15:20:36 -07003 * in lib/rwsem.c.
4 */
5
6#ifndef _ASM_SH_RWSEM_H
7#define _ASM_SH_RWSEM_H
8
Robert P. J. Day711be602007-06-08 11:56:31 +09009#ifndef _LINUX_RWSEM_H
10#error "please don't include asm/rwsem.h directly, use linux/rwsem.h instead"
11#endif
12
Linus Torvalds1da177e2005-04-16 15:20:36 -070013#ifdef __KERNEL__
Thomas Gleixner1c8ed642011-01-26 20:05:56 +000014
Linus Torvalds1da177e2005-04-16 15:20:36 -070015#define RWSEM_UNLOCKED_VALUE 0x00000000
16#define RWSEM_ACTIVE_BIAS 0x00000001
17#define RWSEM_ACTIVE_MASK 0x0000ffff
18#define RWSEM_WAITING_BIAS (-0x00010000)
19#define RWSEM_ACTIVE_READ_BIAS RWSEM_ACTIVE_BIAS
20#define RWSEM_ACTIVE_WRITE_BIAS (RWSEM_WAITING_BIAS + RWSEM_ACTIVE_BIAS)
Linus Torvalds1da177e2005-04-16 15:20:36 -070021
Paul Mundtafbfb522006-12-04 18:17:28 +090022#ifdef CONFIG_DEBUG_LOCK_ALLOC
23# define __RWSEM_DEP_MAP_INIT(lockname) , .dep_map = { .name = #lockname }
24#else
25# define __RWSEM_DEP_MAP_INIT(lockname)
26#endif
27
Linus Torvalds1da177e2005-04-16 15:20:36 -070028#define __RWSEM_INITIALIZER(name) \
Thomas Gleixner969e46a2009-11-06 22:42:05 +000029 { RWSEM_UNLOCKED_VALUE, __SPIN_LOCK_UNLOCKED((name).wait_lock), \
Paul Mundtafbfb522006-12-04 18:17:28 +090030 LIST_HEAD_INIT((name).wait_list) \
31 __RWSEM_DEP_MAP_INIT(name) }
Linus Torvalds1da177e2005-04-16 15:20:36 -070032
33#define DECLARE_RWSEM(name) \
34 struct rw_semaphore name = __RWSEM_INITIALIZER(name)
35
36extern struct rw_semaphore *rwsem_down_read_failed(struct rw_semaphore *sem);
37extern struct rw_semaphore *rwsem_down_write_failed(struct rw_semaphore *sem);
38extern struct rw_semaphore *rwsem_wake(struct rw_semaphore *sem);
39extern struct rw_semaphore *rwsem_downgrade_wake(struct rw_semaphore *sem);
40
Paul Mundtafbfb522006-12-04 18:17:28 +090041extern void __init_rwsem(struct rw_semaphore *sem, const char *name,
42 struct lock_class_key *key);
43
44#define init_rwsem(sem) \
45do { \
46 static struct lock_class_key __key; \
47 \
48 __init_rwsem((sem), #sem, &__key); \
49} while (0)
50
Linus Torvalds1da177e2005-04-16 15:20:36 -070051static inline void init_rwsem(struct rw_semaphore *sem)
52{
53 sem->count = RWSEM_UNLOCKED_VALUE;
54 spin_lock_init(&sem->wait_lock);
55 INIT_LIST_HEAD(&sem->wait_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -070056}
57
58/*
59 * lock for reading
60 */
61static inline void __down_read(struct rw_semaphore *sem)
62{
63 if (atomic_inc_return((atomic_t *)(&sem->count)) > 0)
64 smp_wmb();
65 else
66 rwsem_down_read_failed(sem);
67}
68
69static inline int __down_read_trylock(struct rw_semaphore *sem)
70{
71 int tmp;
72
73 while ((tmp = sem->count) >= 0) {
74 if (tmp == cmpxchg(&sem->count, tmp,
75 tmp + RWSEM_ACTIVE_READ_BIAS)) {
76 smp_wmb();
77 return 1;
78 }
79 }
80 return 0;
81}
82
83/*
84 * lock for writing
85 */
86static inline void __down_write(struct rw_semaphore *sem)
87{
88 int tmp;
89
90 tmp = atomic_add_return(RWSEM_ACTIVE_WRITE_BIAS,
91 (atomic_t *)(&sem->count));
92 if (tmp == RWSEM_ACTIVE_WRITE_BIAS)
93 smp_wmb();
94 else
95 rwsem_down_write_failed(sem);
96}
97
98static inline int __down_write_trylock(struct rw_semaphore *sem)
99{
100 int tmp;
101
102 tmp = cmpxchg(&sem->count, RWSEM_UNLOCKED_VALUE,
103 RWSEM_ACTIVE_WRITE_BIAS);
104 smp_wmb();
105 return tmp == RWSEM_UNLOCKED_VALUE;
106}
107
108/*
109 * unlock after reading
110 */
111static inline void __up_read(struct rw_semaphore *sem)
112{
113 int tmp;
114
115 smp_wmb();
116 tmp = atomic_dec_return((atomic_t *)(&sem->count));
117 if (tmp < -1 && (tmp & RWSEM_ACTIVE_MASK) == 0)
118 rwsem_wake(sem);
119}
120
121/*
122 * unlock after writing
123 */
124static inline void __up_write(struct rw_semaphore *sem)
125{
126 smp_wmb();
127 if (atomic_sub_return(RWSEM_ACTIVE_WRITE_BIAS,
128 (atomic_t *)(&sem->count)) < 0)
129 rwsem_wake(sem);
130}
131
132/*
133 * implement atomic add functionality
134 */
135static inline void rwsem_atomic_add(int delta, struct rw_semaphore *sem)
136{
137 atomic_add(delta, (atomic_t *)(&sem->count));
138}
139
140/*
141 * downgrade write lock to read lock
142 */
143static inline void __downgrade_write(struct rw_semaphore *sem)
144{
145 int tmp;
146
147 smp_wmb();
148 tmp = atomic_add_return(-RWSEM_WAITING_BIAS, (atomic_t *)(&sem->count));
149 if (tmp < 0)
150 rwsem_downgrade_wake(sem);
151}
152
Paul Mundtafbfb522006-12-04 18:17:28 +0900153static inline void __down_write_nested(struct rw_semaphore *sem, int subclass)
154{
155 __down_write(sem);
156}
157
Linus Torvalds1da177e2005-04-16 15:20:36 -0700158/*
159 * implement exchange and add functionality
160 */
161static inline int rwsem_atomic_update(int delta, struct rw_semaphore *sem)
162{
163 smp_mb();
164 return atomic_add_return(delta, (atomic_t *)(&sem->count));
165}
166
Rik Van Rieleb92f4e2005-10-29 18:15:44 -0700167static inline int rwsem_is_locked(struct rw_semaphore *sem)
168{
169 return (sem->count != 0);
170}
171
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172#endif /* __KERNEL__ */
173#endif /* _ASM_SH_RWSEM_H */