aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sparc/include
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2010-08-18 01:49:26 -0400
committerDavid S. Miller <davem@davemloft.net>2010-08-18 01:49:26 -0400
commit9b3bb86acabe0c05923cea1ed3b0bee9439fef4b (patch)
tree44095535e5f2634c319122b718c8998ee3b52511 /arch/sparc/include
parentb10f997bb0f4e5b34d447f498fb85834a40d3acb (diff)
sparc64: Make rwsems 64-bit.
Basically tip-off the powerpc code, use a 64-bit type and atomic64_t interfaces for the implementation. This gets us off of the by-hand asm code I wrote, which frankly I think probably ruins I-cache hit rates. The idea was the keep the call chains less deep, but anything taking the rw-semaphores probably is also calling other stuff and therefore already has allocated a stack-frame. So no real stack frame savings ever. Ben H. has posted patches to make powerpc use 64-bit too and with some abstractions we can probably use a shared header file somewhere. With suggestions from Sam Ravnborg. Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'arch/sparc/include')
-rw-r--r--arch/sparc/include/asm/rwsem-const.h12
-rw-r--r--arch/sparc/include/asm/rwsem.h120
2 files changed, 103 insertions, 29 deletions
diff --git a/arch/sparc/include/asm/rwsem-const.h b/arch/sparc/include/asm/rwsem-const.h
deleted file mode 100644
index e4c61a18bb28..000000000000
--- a/arch/sparc/include/asm/rwsem-const.h
+++ /dev/null
@@ -1,12 +0,0 @@
1/* rwsem-const.h: RW semaphore counter constants. */
2#ifndef _SPARC64_RWSEM_CONST_H
3#define _SPARC64_RWSEM_CONST_H
4
5#define RWSEM_UNLOCKED_VALUE 0x00000000
6#define RWSEM_ACTIVE_BIAS 0x00000001
7#define RWSEM_ACTIVE_MASK 0x0000ffff
8#define RWSEM_WAITING_BIAS (-0x00010000)
9#define RWSEM_ACTIVE_READ_BIAS RWSEM_ACTIVE_BIAS
10#define RWSEM_ACTIVE_WRITE_BIAS (RWSEM_WAITING_BIAS + RWSEM_ACTIVE_BIAS)
11
12#endif /* _SPARC64_RWSEM_CONST_H */
diff --git a/arch/sparc/include/asm/rwsem.h b/arch/sparc/include/asm/rwsem.h
index 6e5621006f85..a2b4302869bc 100644
--- a/arch/sparc/include/asm/rwsem.h
+++ b/arch/sparc/include/asm/rwsem.h
@@ -15,16 +15,21 @@
15 15
16#include <linux/list.h> 16#include <linux/list.h>
17#include <linux/spinlock.h> 17#include <linux/spinlock.h>
18#include <asm/rwsem-const.h>
19 18
20struct rwsem_waiter; 19struct rwsem_waiter;
21 20
22struct rw_semaphore { 21struct rw_semaphore {
23 signed int count; 22 signed long count;
24 spinlock_t wait_lock; 23#define RWSEM_UNLOCKED_VALUE 0x00000000L
25 struct list_head wait_list; 24#define RWSEM_ACTIVE_BIAS 0x00000001L
25#define RWSEM_ACTIVE_MASK 0xffffffffL
26#define RWSEM_WAITING_BIAS (-RWSEM_ACTIVE_MASK-1)
27#define RWSEM_ACTIVE_READ_BIAS RWSEM_ACTIVE_BIAS
28#define RWSEM_ACTIVE_WRITE_BIAS (RWSEM_WAITING_BIAS + RWSEM_ACTIVE_BIAS)
29 spinlock_t wait_lock;
30 struct list_head wait_list;
26#ifdef CONFIG_DEBUG_LOCK_ALLOC 31#ifdef CONFIG_DEBUG_LOCK_ALLOC
27 struct lockdep_map dep_map; 32 struct lockdep_map dep_map;
28#endif 33#endif
29}; 34};
30 35
@@ -41,6 +46,11 @@ struct rw_semaphore {
41#define DECLARE_RWSEM(name) \ 46#define DECLARE_RWSEM(name) \
42 struct rw_semaphore name = __RWSEM_INITIALIZER(name) 47 struct rw_semaphore name = __RWSEM_INITIALIZER(name)
43 48
49extern struct rw_semaphore *rwsem_down_read_failed(struct rw_semaphore *sem);
50extern struct rw_semaphore *rwsem_down_write_failed(struct rw_semaphore *sem);
51extern struct rw_semaphore *rwsem_wake(struct rw_semaphore *sem);
52extern struct rw_semaphore *rwsem_downgrade_wake(struct rw_semaphore *sem);
53
44extern void __init_rwsem(struct rw_semaphore *sem, const char *name, 54extern void __init_rwsem(struct rw_semaphore *sem, const char *name,
45 struct lock_class_key *key); 55 struct lock_class_key *key);
46 56
@@ -51,27 +61,103 @@ do { \
51 __init_rwsem((sem), #sem, &__key); \ 61 __init_rwsem((sem), #sem, &__key); \
52} while (0) 62} while (0)
53 63
54extern void __down_read(struct rw_semaphore *sem); 64/*
55extern int __down_read_trylock(struct rw_semaphore *sem); 65 * lock for reading
56extern void __down_write(struct rw_semaphore *sem); 66 */
57extern int __down_write_trylock(struct rw_semaphore *sem); 67static inline void __down_read(struct rw_semaphore *sem)
58extern void __up_read(struct rw_semaphore *sem); 68{
59extern void __up_write(struct rw_semaphore *sem); 69 if (unlikely(atomic64_inc_return((atomic64_t *)(&sem->count)) <= 0L))
60extern void __downgrade_write(struct rw_semaphore *sem); 70 rwsem_down_read_failed(sem);
71}
72
73static inline int __down_read_trylock(struct rw_semaphore *sem)
74{
75 long tmp;
76
77 while ((tmp = sem->count) >= 0L) {
78 if (tmp == cmpxchg(&sem->count, tmp,
79 tmp + RWSEM_ACTIVE_READ_BIAS)) {
80 return 1;
81 }
82 }
83 return 0;
84}
61 85
86/*
87 * lock for writing
88 */
62static inline void __down_write_nested(struct rw_semaphore *sem, int subclass) 89static inline void __down_write_nested(struct rw_semaphore *sem, int subclass)
63{ 90{
64 __down_write(sem); 91 long tmp;
92
93 tmp = atomic64_add_return(RWSEM_ACTIVE_WRITE_BIAS,
94 (atomic64_t *)(&sem->count));
95 if (unlikely(tmp != RWSEM_ACTIVE_WRITE_BIAS))
96 rwsem_down_write_failed(sem);
65} 97}
66 98
67static inline int rwsem_atomic_update(int delta, struct rw_semaphore *sem) 99static inline void __down_write(struct rw_semaphore *sem)
68{ 100{
69 return atomic_add_return(delta, (atomic_t *)(&sem->count)); 101 __down_write_nested(sem, 0);
102}
103
104static inline int __down_write_trylock(struct rw_semaphore *sem)
105{
106 long tmp;
107
108 tmp = cmpxchg(&sem->count, RWSEM_UNLOCKED_VALUE,
109 RWSEM_ACTIVE_WRITE_BIAS);
110 return tmp == RWSEM_UNLOCKED_VALUE;
70} 111}
71 112
72static inline void rwsem_atomic_add(int delta, struct rw_semaphore *sem) 113/*
114 * unlock after reading
115 */
116static inline void __up_read(struct rw_semaphore *sem)
117{
118 long tmp;
119
120 tmp = atomic64_dec_return((atomic64_t *)(&sem->count));
121 if (unlikely(tmp < -1L && (tmp & RWSEM_ACTIVE_MASK) == 0L))
122 rwsem_wake(sem);
123}
124
125/*
126 * unlock after writing
127 */
128static inline void __up_write(struct rw_semaphore *sem)
129{
130 if (unlikely(atomic64_sub_return(RWSEM_ACTIVE_WRITE_BIAS,
131 (atomic64_t *)(&sem->count)) < 0L))
132 rwsem_wake(sem);
133}
134
135/*
136 * implement atomic add functionality
137 */
138static inline void rwsem_atomic_add(long delta, struct rw_semaphore *sem)
139{
140 atomic64_add(delta, (atomic64_t *)(&sem->count));
141}
142
143/*
144 * downgrade write lock to read lock
145 */
146static inline void __downgrade_write(struct rw_semaphore *sem)
147{
148 long tmp;
149
150 tmp = atomic64_add_return(-RWSEM_WAITING_BIAS, (atomic64_t *)(&sem->count));
151 if (tmp < 0L)
152 rwsem_downgrade_wake(sem);
153}
154
155/*
156 * implement exchange and add functionality
157 */
158static inline long rwsem_atomic_update(long delta, struct rw_semaphore *sem)
73{ 159{
74 atomic_add(delta, (atomic_t *)(&sem->count)); 160 return atomic64_add_return(delta, (atomic64_t *)(&sem->count));
75} 161}
76 162
77static inline int rwsem_is_locked(struct rw_semaphore *sem) 163static inline int rwsem_is_locked(struct rw_semaphore *sem)