blob: f6c951c7a875bf3ac27b7146786cc81034181c05 [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
Linus Torvalds1da177e2005-04-16 15:20:36 -070022/*
23 * lock for reading
24 */
25static inline void __down_read(struct rw_semaphore *sem)
26{
Michal Hocko2e927c62016-04-07 17:12:22 +020027 if (atomic_inc_return((atomic_t *)(&sem->count)) <= 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -070028 rwsem_down_read_failed(sem);
29}
30
31static inline int __down_read_trylock(struct rw_semaphore *sem)
32{
33 int tmp;
34
35 while ((tmp = sem->count) >= 0) {
36 if (tmp == cmpxchg(&sem->count, tmp,
37 tmp + RWSEM_ACTIVE_READ_BIAS)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -070038 return 1;
39 }
40 }
41 return 0;
42}
43
44/*
45 * lock for writing
46 */
47static inline void __down_write(struct rw_semaphore *sem)
48{
49 int tmp;
50
51 tmp = atomic_add_return(RWSEM_ACTIVE_WRITE_BIAS,
52 (atomic_t *)(&sem->count));
Michal Hocko2e927c62016-04-07 17:12:22 +020053 if (tmp != RWSEM_ACTIVE_WRITE_BIAS)
Linus Torvalds1da177e2005-04-16 15:20:36 -070054 rwsem_down_write_failed(sem);
55}
56
57static inline int __down_write_trylock(struct rw_semaphore *sem)
58{
59 int tmp;
60
61 tmp = cmpxchg(&sem->count, RWSEM_UNLOCKED_VALUE,
62 RWSEM_ACTIVE_WRITE_BIAS);
Linus Torvalds1da177e2005-04-16 15:20:36 -070063 return tmp == RWSEM_UNLOCKED_VALUE;
64}
65
66/*
67 * unlock after reading
68 */
69static inline void __up_read(struct rw_semaphore *sem)
70{
71 int tmp;
72
Linus Torvalds1da177e2005-04-16 15:20:36 -070073 tmp = atomic_dec_return((atomic_t *)(&sem->count));
74 if (tmp < -1 && (tmp & RWSEM_ACTIVE_MASK) == 0)
75 rwsem_wake(sem);
76}
77
78/*
79 * unlock after writing
80 */
81static inline void __up_write(struct rw_semaphore *sem)
82{
Linus Torvalds1da177e2005-04-16 15:20:36 -070083 if (atomic_sub_return(RWSEM_ACTIVE_WRITE_BIAS,
84 (atomic_t *)(&sem->count)) < 0)
85 rwsem_wake(sem);
86}
87
88/*
89 * implement atomic add functionality
90 */
91static inline void rwsem_atomic_add(int delta, struct rw_semaphore *sem)
92{
93 atomic_add(delta, (atomic_t *)(&sem->count));
94}
95
96/*
97 * downgrade write lock to read lock
98 */
99static inline void __downgrade_write(struct rw_semaphore *sem)
100{
101 int tmp;
102
Linus Torvalds1da177e2005-04-16 15:20:36 -0700103 tmp = atomic_add_return(-RWSEM_WAITING_BIAS, (atomic_t *)(&sem->count));
104 if (tmp < 0)
105 rwsem_downgrade_wake(sem);
106}
107
108/*
109 * implement exchange and add functionality
110 */
111static inline int rwsem_atomic_update(int delta, struct rw_semaphore *sem)
112{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700113 return atomic_add_return(delta, (atomic_t *)(&sem->count));
114}
115
Linus Torvalds1da177e2005-04-16 15:20:36 -0700116#endif /* __KERNEL__ */
117#endif /* _ASM_SH_RWSEM_H */