blob: 2fa4202123538a7a1a050a8b3900db1548d3f25b [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 -070027extern struct rw_semaphore *rwsem_down_read_failed(struct rw_semaphore *sem);
28extern struct rw_semaphore *rwsem_down_write_failed(struct rw_semaphore *sem);
29extern struct rw_semaphore *rwsem_wake(struct rw_semaphore *sem);
30extern struct rw_semaphore *rwsem_downgrade_wake(struct rw_semaphore *sem);
31
Chris Zankel9a8fd552005-06-23 22:01:26 -070032/*
33 * lock for reading
34 */
35static inline void __down_read(struct rw_semaphore *sem)
36{
37 if (atomic_add_return(1,(atomic_t *)(&sem->count)) > 0)
38 smp_wmb();
39 else
40 rwsem_down_read_failed(sem);
41}
42
43static inline int __down_read_trylock(struct rw_semaphore *sem)
44{
45 int tmp;
46
47 while ((tmp = sem->count) >= 0) {
48 if (tmp == cmpxchg(&sem->count, tmp,
49 tmp + RWSEM_ACTIVE_READ_BIAS)) {
50 smp_wmb();
51 return 1;
52 }
53 }
54 return 0;
55}
56
57/*
58 * lock for writing
59 */
60static inline void __down_write(struct rw_semaphore *sem)
61{
62 int tmp;
63
64 tmp = atomic_add_return(RWSEM_ACTIVE_WRITE_BIAS,
65 (atomic_t *)(&sem->count));
66 if (tmp == RWSEM_ACTIVE_WRITE_BIAS)
67 smp_wmb();
68 else
69 rwsem_down_write_failed(sem);
70}
71
72static inline int __down_write_trylock(struct rw_semaphore *sem)
73{
74 int tmp;
75
76 tmp = cmpxchg(&sem->count, RWSEM_UNLOCKED_VALUE,
77 RWSEM_ACTIVE_WRITE_BIAS);
78 smp_wmb();
79 return tmp == RWSEM_UNLOCKED_VALUE;
80}
81
82/*
83 * unlock after reading
84 */
85static inline void __up_read(struct rw_semaphore *sem)
86{
87 int tmp;
88
89 smp_wmb();
90 tmp = atomic_sub_return(1,(atomic_t *)(&sem->count));
91 if (tmp < -1 && (tmp & RWSEM_ACTIVE_MASK) == 0)
92 rwsem_wake(sem);
93}
94
95/*
96 * unlock after writing
97 */
98static inline void __up_write(struct rw_semaphore *sem)
99{
100 smp_wmb();
101 if (atomic_sub_return(RWSEM_ACTIVE_WRITE_BIAS,
102 (atomic_t *)(&sem->count)) < 0)
103 rwsem_wake(sem);
104}
105
106/*
107 * implement atomic add functionality
108 */
109static inline void rwsem_atomic_add(int delta, struct rw_semaphore *sem)
110{
111 atomic_add(delta, (atomic_t *)(&sem->count));
112}
113
114/*
115 * downgrade write lock to read lock
116 */
117static inline void __downgrade_write(struct rw_semaphore *sem)
118{
119 int tmp;
120
121 smp_wmb();
122 tmp = atomic_add_return(-RWSEM_WAITING_BIAS, (atomic_t *)(&sem->count));
123 if (tmp < 0)
124 rwsem_downgrade_wake(sem);
125}
126
127/*
128 * implement exchange and add functionality
129 */
130static inline int rwsem_atomic_update(int delta, struct rw_semaphore *sem)
131{
132 smp_mb();
133 return atomic_add_return(delta, (atomic_t *)(&sem->count));
134}
135
Jesper Juhlb9e122c2006-06-23 02:05:04 -0700136static inline int rwsem_is_locked(struct rw_semaphore *sem)
137{
138 return (sem->count != 0);
139}
140
141#endif /* _XTENSA_RWSEM_H */