blob: 585cab9b0bdf3b3ed98cdb6ff403664f1efd07c6 [file] [log] [blame]
Chris Zankel9a8fd552005-06-23 22:01:26 -07001/*
2 * include/asm-xtensa/rwsem.h
3 *
4 * This file is subject to the terms and conditions of the GNU General Public
5 * License. See the file "COPYING" in the main directory of this archive
6 * for more details.
7 *
8 * Largely copied from include/asm-ppc/rwsem.h
9 *
10 * Copyright (C) 2001 - 2005 Tensilica Inc.
11 */
12
13#ifndef _XTENSA_RWSEM_H
14#define _XTENSA_RWSEM_H
15
Robert P. J. Day14ac12d2008-07-30 12:48:53 -070016#ifndef _LINUX_RWSEM_H
17#error "Please don't include <asm/rwsem.h> directly, use <linux/rwsem.h> instead."
18#endif
Thomas Gleixner1c8ed642011-01-26 20:05:56 +000019
Chris Zankel9a8fd552005-06-23 22:01:26 -070020#define RWSEM_UNLOCKED_VALUE 0x00000000
21#define RWSEM_ACTIVE_BIAS 0x00000001
22#define RWSEM_ACTIVE_MASK 0x0000ffff
23#define RWSEM_WAITING_BIAS (-0x00010000)
24#define RWSEM_ACTIVE_READ_BIAS RWSEM_ACTIVE_BIAS
25#define RWSEM_ACTIVE_WRITE_BIAS (RWSEM_WAITING_BIAS + RWSEM_ACTIVE_BIAS)
Chris Zankel9a8fd552005-06-23 22:01:26 -070026
Chris Zankel9a8fd552005-06-23 22:01:26 -070027#define __RWSEM_INITIALIZER(name) \
Thomas Gleixner235454c2011-01-23 15:23:14 +010028 { RWSEM_UNLOCKED_VALUE, __SPIN_LOCK_UNLOCKED((name).wait_lock), \
Ingo Molnar61f4c3d2006-07-03 00:24:29 -070029 LIST_HEAD_INIT((name).wait_list) }
Chris Zankel9a8fd552005-06-23 22:01:26 -070030
31#define DECLARE_RWSEM(name) \
32 struct rw_semaphore name = __RWSEM_INITIALIZER(name)
33
34extern struct rw_semaphore *rwsem_down_read_failed(struct rw_semaphore *sem);
35extern struct rw_semaphore *rwsem_down_write_failed(struct rw_semaphore *sem);
36extern struct rw_semaphore *rwsem_wake(struct rw_semaphore *sem);
37extern struct rw_semaphore *rwsem_downgrade_wake(struct rw_semaphore *sem);
38
39static inline void init_rwsem(struct rw_semaphore *sem)
40{
41 sem->count = RWSEM_UNLOCKED_VALUE;
42 spin_lock_init(&sem->wait_lock);
43 INIT_LIST_HEAD(&sem->wait_list);
Chris Zankel9a8fd552005-06-23 22:01:26 -070044}
45
46/*
47 * lock for reading
48 */
49static inline void __down_read(struct rw_semaphore *sem)
50{
51 if (atomic_add_return(1,(atomic_t *)(&sem->count)) > 0)
52 smp_wmb();
53 else
54 rwsem_down_read_failed(sem);
55}
56
57static inline int __down_read_trylock(struct rw_semaphore *sem)
58{
59 int tmp;
60
61 while ((tmp = sem->count) >= 0) {
62 if (tmp == cmpxchg(&sem->count, tmp,
63 tmp + RWSEM_ACTIVE_READ_BIAS)) {
64 smp_wmb();
65 return 1;
66 }
67 }
68 return 0;
69}
70
71/*
72 * lock for writing
73 */
74static inline void __down_write(struct rw_semaphore *sem)
75{
76 int tmp;
77
78 tmp = atomic_add_return(RWSEM_ACTIVE_WRITE_BIAS,
79 (atomic_t *)(&sem->count));
80 if (tmp == RWSEM_ACTIVE_WRITE_BIAS)
81 smp_wmb();
82 else
83 rwsem_down_write_failed(sem);
84}
85
86static inline int __down_write_trylock(struct rw_semaphore *sem)
87{
88 int tmp;
89
90 tmp = cmpxchg(&sem->count, RWSEM_UNLOCKED_VALUE,
91 RWSEM_ACTIVE_WRITE_BIAS);
92 smp_wmb();
93 return tmp == RWSEM_UNLOCKED_VALUE;
94}
95
96/*
97 * unlock after reading
98 */
99static inline void __up_read(struct rw_semaphore *sem)
100{
101 int tmp;
102
103 smp_wmb();
104 tmp = atomic_sub_return(1,(atomic_t *)(&sem->count));
105 if (tmp < -1 && (tmp & RWSEM_ACTIVE_MASK) == 0)
106 rwsem_wake(sem);
107}
108
109/*
110 * unlock after writing
111 */
112static inline void __up_write(struct rw_semaphore *sem)
113{
114 smp_wmb();
115 if (atomic_sub_return(RWSEM_ACTIVE_WRITE_BIAS,
116 (atomic_t *)(&sem->count)) < 0)
117 rwsem_wake(sem);
118}
119
120/*
121 * implement atomic add functionality
122 */
123static inline void rwsem_atomic_add(int delta, struct rw_semaphore *sem)
124{
125 atomic_add(delta, (atomic_t *)(&sem->count));
126}
127
128/*
129 * downgrade write lock to read lock
130 */
131static inline void __downgrade_write(struct rw_semaphore *sem)
132{
133 int tmp;
134
135 smp_wmb();
136 tmp = atomic_add_return(-RWSEM_WAITING_BIAS, (atomic_t *)(&sem->count));
137 if (tmp < 0)
138 rwsem_downgrade_wake(sem);
139}
140
141/*
142 * implement exchange and add functionality
143 */
144static inline int rwsem_atomic_update(int delta, struct rw_semaphore *sem)
145{
146 smp_mb();
147 return atomic_add_return(delta, (atomic_t *)(&sem->count));
148}
149
Jesper Juhlb9e122c2006-06-23 02:05:04 -0700150static inline int rwsem_is_locked(struct rw_semaphore *sem)
151{
152 return (sem->count != 0);
153}
154
155#endif /* _XTENSA_RWSEM_H */