aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/tile/include/asm/spinlock_32.h83
-rw-r--r--arch/tile/lib/spinlock_32.c161
2 files changed, 103 insertions, 141 deletions
diff --git a/arch/tile/include/asm/spinlock_32.h b/arch/tile/include/asm/spinlock_32.h
index 88efdde8dd2b..a8f2c6e31a87 100644
--- a/arch/tile/include/asm/spinlock_32.h
+++ b/arch/tile/include/asm/spinlock_32.h
@@ -78,13 +78,6 @@ void arch_spin_unlock_wait(arch_spinlock_t *lock);
78#define _RD_COUNT_SHIFT 24 78#define _RD_COUNT_SHIFT 24
79#define _RD_COUNT_WIDTH 8 79#define _RD_COUNT_WIDTH 8
80 80
81/* Internal functions; do not use. */
82void arch_read_lock_slow(arch_rwlock_t *, u32);
83int arch_read_trylock_slow(arch_rwlock_t *);
84void arch_read_unlock_slow(arch_rwlock_t *);
85void arch_write_lock_slow(arch_rwlock_t *, u32);
86void arch_write_unlock_slow(arch_rwlock_t *, u32);
87
88/** 81/**
89 * arch_read_can_lock() - would read_trylock() succeed? 82 * arch_read_can_lock() - would read_trylock() succeed?
90 */ 83 */
@@ -104,94 +97,32 @@ static inline int arch_write_can_lock(arch_rwlock_t *rwlock)
104/** 97/**
105 * arch_read_lock() - acquire a read lock. 98 * arch_read_lock() - acquire a read lock.
106 */ 99 */
107static inline void arch_read_lock(arch_rwlock_t *rwlock) 100void arch_read_lock(arch_rwlock_t *rwlock);
108{
109 u32 val = __insn_tns((int *)&rwlock->lock);
110 if (unlikely(val << _RD_COUNT_WIDTH)) {
111 arch_read_lock_slow(rwlock, val);
112 return;
113 }
114 rwlock->lock = val + (1 << _RD_COUNT_SHIFT);
115}
116 101
117/** 102/**
118 * arch_read_lock() - acquire a write lock. 103 * arch_write_lock() - acquire a write lock.
119 */ 104 */
120static inline void arch_write_lock(arch_rwlock_t *rwlock) 105void arch_write_lock(arch_rwlock_t *rwlock);
121{
122 u32 val = __insn_tns((int *)&rwlock->lock);
123 if (unlikely(val != 0)) {
124 arch_write_lock_slow(rwlock, val);
125 return;
126 }
127 rwlock->lock = 1 << _WR_NEXT_SHIFT;
128}
129 106
130/** 107/**
131 * arch_read_trylock() - try to acquire a read lock. 108 * arch_read_trylock() - try to acquire a read lock.
132 */ 109 */
133static inline int arch_read_trylock(arch_rwlock_t *rwlock) 110int arch_read_trylock(arch_rwlock_t *rwlock);
134{
135 int locked;
136 u32 val = __insn_tns((int *)&rwlock->lock);
137 if (unlikely(val & 1))
138 return arch_read_trylock_slow(rwlock);
139 locked = (val << _RD_COUNT_WIDTH) == 0;
140 rwlock->lock = val + (locked << _RD_COUNT_SHIFT);
141 return locked;
142}
143 111
144/** 112/**
145 * arch_write_trylock() - try to acquire a write lock. 113 * arch_write_trylock() - try to acquire a write lock.
146 */ 114 */
147static inline int arch_write_trylock(arch_rwlock_t *rwlock) 115int arch_write_trylock(arch_rwlock_t *rwlock);
148{
149 u32 val = __insn_tns((int *)&rwlock->lock);
150
151 /*
152 * If a tns is in progress, or there's a waiting or active locker,
153 * or active readers, we can't take the lock, so give up.
154 */
155 if (unlikely(val != 0)) {
156 if (!(val & 1))
157 rwlock->lock = val;
158 return 0;
159 }
160
161 /* Set the "next" field to mark it locked. */
162 rwlock->lock = 1 << _WR_NEXT_SHIFT;
163 return 1;
164}
165 116
166/** 117/**
167 * arch_read_unlock() - release a read lock. 118 * arch_read_unlock() - release a read lock.
168 */ 119 */
169static inline void arch_read_unlock(arch_rwlock_t *rwlock) 120void arch_read_unlock(arch_rwlock_t *rwlock);
170{
171 u32 val;
172 mb(); /* guarantee anything modified under the lock is visible */
173 val = __insn_tns((int *)&rwlock->lock);
174 if (unlikely(val & 1)) {
175 arch_read_unlock_slow(rwlock);
176 return;
177 }
178 rwlock->lock = val - (1 << _RD_COUNT_SHIFT);
179}
180 121
181/** 122/**
182 * arch_write_unlock() - release a write lock. 123 * arch_write_unlock() - release a write lock.
183 */ 124 */
184static inline void arch_write_unlock(arch_rwlock_t *rwlock) 125void arch_write_unlock(arch_rwlock_t *rwlock);
185{
186 u32 val;
187 mb(); /* guarantee anything modified under the lock is visible */
188 val = __insn_tns((int *)&rwlock->lock);
189 if (unlikely(val != (1 << _WR_NEXT_SHIFT))) {
190 arch_write_unlock_slow(rwlock, val);
191 return;
192 }
193 rwlock->lock = 0;
194}
195 126
196#define arch_read_lock_flags(lock, flags) arch_read_lock(lock) 127#define arch_read_lock_flags(lock, flags) arch_read_lock(lock)
197#define arch_write_lock_flags(lock, flags) arch_write_lock(lock) 128#define arch_write_lock_flags(lock, flags) arch_write_lock(lock)
diff --git a/arch/tile/lib/spinlock_32.c b/arch/tile/lib/spinlock_32.c
index 5cd1c4004eca..cb0999fb64b4 100644
--- a/arch/tile/lib/spinlock_32.c
+++ b/arch/tile/lib/spinlock_32.c
@@ -15,6 +15,7 @@
15#include <linux/spinlock.h> 15#include <linux/spinlock.h>
16#include <linux/module.h> 16#include <linux/module.h>
17#include <asm/processor.h> 17#include <asm/processor.h>
18#include <arch/spr_def.h>
18 19
19#include "spinlock_common.h" 20#include "spinlock_common.h"
20 21
@@ -91,75 +92,75 @@ EXPORT_SYMBOL(arch_spin_unlock_wait);
91#define RD_COUNT_MASK ((1 << RD_COUNT_WIDTH) - 1) 92#define RD_COUNT_MASK ((1 << RD_COUNT_WIDTH) - 1)
92 93
93 94
94/* Lock the word, spinning until there are no tns-ers. */ 95/*
95static inline u32 get_rwlock(arch_rwlock_t *rwlock) 96 * We can get the read lock if everything but the reader bits (which
96{ 97 * are in the high part of the word) is zero, i.e. no active or
97 u32 iterations = 0; 98 * waiting writers, no tns.
98 for (;;) { 99 *
99 u32 val = __insn_tns((int *)&rwlock->lock); 100 * We guard the tns/store-back with an interrupt critical section to
100 if (unlikely(val & 1)) { 101 * preserve the semantic that the same read lock can be acquired in an
101 delay_backoff(iterations++); 102 * interrupt context.
102 continue; 103 */
103 } 104inline int arch_read_trylock(arch_rwlock_t *rwlock)
104 return val;
105 }
106}
107
108int arch_read_trylock_slow(arch_rwlock_t *rwlock)
109{
110 u32 val = get_rwlock(rwlock);
111 int locked = (val << RD_COUNT_WIDTH) == 0;
112 rwlock->lock = val + (locked << RD_COUNT_SHIFT);
113 return locked;
114}
115EXPORT_SYMBOL(arch_read_trylock_slow);
116
117void arch_read_unlock_slow(arch_rwlock_t *rwlock)
118{
119 u32 val = get_rwlock(rwlock);
120 rwlock->lock = val - (1 << RD_COUNT_SHIFT);
121}
122EXPORT_SYMBOL(arch_read_unlock_slow);
123
124void arch_write_unlock_slow(arch_rwlock_t *rwlock, u32 val)
125{ 105{
126 u32 eq, mask = 1 << WR_CURR_SHIFT; 106 u32 val;
127 while (unlikely(val & 1)) { 107 __insn_mtspr(SPR_INTERRUPT_CRITICAL_SECTION, 1);
128 /* Limited backoff since we are the highest-priority task. */ 108 val = __insn_tns((int *)&rwlock->lock);
129 relax(4); 109 if (likely((val << _RD_COUNT_WIDTH) == 0)) {
130 val = __insn_tns((int *)&rwlock->lock); 110 val += 1 << RD_COUNT_SHIFT;
111 rwlock->lock = val;
112 __insn_mtspr(SPR_INTERRUPT_CRITICAL_SECTION, 0);