aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin Schwidefsky <schwidefsky@de.ibm.com>2014-05-15 05:00:44 -0400
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2014-05-20 02:58:53 -0400
commitbae8f567344a7cb6a23ca6e13096ba785c69eb42 (patch)
treea0d91d9abf8405646ffbd5201d8c1b7f2627563c
parent2bf29df7460f4038f84ac5dea3cbe582d6d4af82 (diff)
s390/spinlock,rwlock: always to a load-and-test first
In case a lock is contended it is better to do a load-and-test first before trying to get the lock with compare-and-swap. This helps to avoid unnecessary cache invalidations of the cacheline for the lock if the CPU has to wait for the lock. For an uncontended lock doing the compare-and-swap directly is a bit better, if the CPU does not have the cacheline in its cache yet the compare-and-swap will get it read-write immediately while a load-and-test would get it read-only first. Always to the load-and-test first to avoid the cacheline invalidations for the contended case outweight the potential read-only to read-write cacheline upgrade for the uncontended case. Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
-rw-r--r--arch/s390/include/asm/spinlock.h50
-rw-r--r--arch/s390/lib/spinlock.c29
2 files changed, 46 insertions, 33 deletions
diff --git a/arch/s390/include/asm/spinlock.h b/arch/s390/include/asm/spinlock.h
index 5a0b2882ad48..96879f7ad6da 100644
--- a/arch/s390/include/asm/spinlock.h
+++ b/arch/s390/include/asm/spinlock.h
@@ -59,7 +59,9 @@ static inline int arch_spin_is_locked(arch_spinlock_t *lp)
59 59
60static inline int arch_spin_trylock_once(arch_spinlock_t *lp) 60static inline int arch_spin_trylock_once(arch_spinlock_t *lp)
61{ 61{
62 return _raw_compare_and_swap(&lp->lock, 0, SPINLOCK_LOCKVAL); 62 barrier();
63 return likely(arch_spin_value_unlocked(*lp) &&
64 _raw_compare_and_swap(&lp->lock, 0, SPINLOCK_LOCKVAL));
63} 65}
64 66
65static inline int arch_spin_tryrelease_once(arch_spinlock_t *lp) 67static inline int arch_spin_tryrelease_once(arch_spinlock_t *lp)
@@ -69,20 +71,20 @@ static inline int arch_spin_tryrelease_once(arch_spinlock_t *lp)
69 71
70static inline void arch_spin_lock(arch_spinlock_t *lp) 72static inline void arch_spin_lock(arch_spinlock_t *lp)
71{ 73{
72 if (unlikely(!arch_spin_trylock_once(lp))) 74 if (!arch_spin_trylock_once(lp))
73 arch_spin_lock_wait(lp); 75 arch_spin_lock_wait(lp);
74} 76}
75 77
76static inline void arch_spin_lock_flags(arch_spinlock_t *lp, 78static inline void arch_spin_lock_flags(arch_spinlock_t *lp,
77 unsigned long flags) 79 unsigned long flags)
78{ 80{
79 if (unlikely(!arch_spin_trylock_once(lp))) 81 if (!arch_spin_trylock_once(lp))
80 arch_spin_lock_wait_flags(lp, flags); 82 arch_spin_lock_wait_flags(lp, flags);
81} 83}
82 84
83static inline int arch_spin_trylock(arch_spinlock_t *lp) 85static inline int arch_spin_trylock(arch_spinlock_t *lp)
84{ 86{
85 if (unlikely(!arch_spin_trylock_once(lp))) 87 if (!arch_spin_trylock_once(lp))
86 return arch_spin_trylock_retry(lp); 88 return arch_spin_trylock_retry(lp);
87 return 1; 89 return 1;
88} 90}
@@ -128,19 +130,29 @@ extern void _raw_write_lock_wait(arch_rwlock_t *lp);
128extern void _raw_write_lock_wait_flags(arch_rwlock_t *lp, unsigned long flags); 130extern void _raw_write_lock_wait_flags(arch_rwlock_t *lp, unsigned long flags);
129extern int _raw_write_trylock_retry(arch_rwlock_t *lp); 131extern int _raw_write_trylock_retry(arch_rwlock_t *lp);
130 132
133static inline int arch_read_trylock_once(arch_rwlock_t *rw)
134{
135 unsigned int old = ACCESS_ONCE(rw->lock);
136 return likely((int) old >= 0 &&
137 _raw_compare_and_swap(&rw->lock, old, old + 1));
138}
139
140static inline int arch_write_trylock_once(arch_rwlock_t *rw)
141{
142 unsigned int old = ACCESS_ONCE(rw->lock);
143 return likely(old == 0 &&
144 _raw_compare_and_swap(&rw->lock, 0, 0x80000000));
145}
146
131static inline void arch_read_lock(arch_rwlock_t *rw) 147static inline void arch_read_lock(arch_rwlock_t *rw)
132{ 148{
133 unsigned int old; 149 if (!arch_read_trylock_once(rw))
134 old = rw->lock & 0x7fffffffU;
135 if (!_raw_compare_and_swap(&rw->lock, old, old + 1))
136 _raw_read_lock_wait(rw); 150 _raw_read_lock_wait(rw);
137} 151}
138 152
139static inline void arch_read_lock_flags(arch_rwlock_t *rw, unsigned long flags) 153static inline void arch_read_lock_flags(arch_rwlock_t *rw, unsigned long flags)
140{ 154{
141 unsigned int old; 155 if (!arch_read_trylock_once(rw))
142 old = rw->lock & 0x7fffffffU;
143 if (!_raw_compare_and_swap(&rw->lock, old, old + 1))
144 _raw_read_lock_wait_flags(rw, flags); 156 _raw_read_lock_wait_flags(rw, flags);
145} 157}
146 158
@@ -155,13 +167,13 @@ static inline void arch_read_unlock(arch_rwlock_t *rw)
155 167
156static inline void arch_write_lock(arch_rwlock_t *rw) 168static inline void arch_write_lock(arch_rwlock_t *rw)
157{ 169{
158 if (unlikely(!_raw_compare_and_swap(&rw->lock, 0, 0x80000000))) 170 if (!arch_write_trylock_once(rw))
159 _raw_write_lock_wait(rw); 171 _raw_write_lock_wait(rw);
160} 172}
161 173
162static inline void arch_write_lock_flags(arch_rwlock_t *rw, unsigned long flags) 174static inline void arch_write_lock_flags(arch_rwlock_t *rw, unsigned long flags)
163{ 175{
164 if (unlikely(!_raw_compare_and_swap(&rw->lock, 0, 0x80000000))) 176 if (!arch_write_trylock_once(rw))
165 _raw_write_lock_wait_flags(rw, flags); 177 _raw_write_lock_wait_flags(rw, flags);
166} 178}
167 179
@@ -172,18 +184,16 @@ static inline void arch_write_unlock(arch_rwlock_t *rw)
172 184
173static inline int arch_read_trylock(arch_rwlock_t *rw) 185static inline int arch_read_trylock(arch_rwlock_t *rw)
174{ 186{
175 unsigned int old; 187 if (!arch_read_trylock_once(rw))
176 old = rw->lock & 0x7fffffffU; 188 return _raw_read_trylock_retry(rw);
177 if (likely(_raw_compare_and_swap(&rw->lock, old, old + 1))) 189 return 1;
178 return 1;
179 return _raw_read_trylock_retry(rw);
180} 190}
181 191
182static inline int arch_write_trylock(arch_rwlock_t *rw) 192static inline int arch_write_trylock(arch_rwlock_t *rw)
183{ 193{
184 if (likely(_raw_compare_and_swap(&rw->lock, 0, 0x80000000))) 194 if (!arch_write_trylock_once(rw))
185 return 1; 195 return _raw_write_trylock_retry(rw);
186 return _raw_write_trylock_retry(rw); 196 return 1;
187} 197}
188 198
189#define arch_read_relax(lock) cpu_relax() 199#define arch_read_relax(lock) cpu_relax()
diff --git a/arch/s390/lib/spinlock.c b/arch/s390/lib/spinlock.c
index 3f0e682b7e62..284d879a9b8c 100644
--- a/arch/s390/lib/spinlock.c
+++ b/arch/s390/lib/spinlock.c
@@ -100,12 +100,9 @@ int arch_spin_trylock_retry(arch_spinlock_t *lp)
100{ 100{
101 int count; 101 int count;
102 102
103 for (count = spin_retry; count > 0; count--) { 103 for (count = spin_retry; count > 0; count--)
104 if (arch_spin_is_locked(lp))
105 continue;
106 if (arch_spin_trylock_once(lp)) 104 if (arch_spin_trylock_once(lp))
107 return 1; 105 return 1;
108 }
109 return 0; 106 return 0;
110} 107}
111EXPORT_SYMBOL(arch_spin_trylock_retry); 108EXPORT_SYMBOL(arch_spin_trylock_retry);
@@ -120,9 +117,9 @@ void _raw_read_lock_wait(arch_rwlock_t *rw)
120 smp_yield(); 117 smp_yield();
121 count = spin_retry; 118 count = spin_retry;
122 } 119 }
123 if (!arch_read_can_lock(rw)) 120 old = ACCESS_ONCE(rw->lock);
121 if ((int) old < 0)
124 continue; 122 continue;
125 old = rw->lock & 0x7fffffffU;
126 if (_raw_compare_and_swap(&rw->lock, old, old + 1)) 123 if (_raw_compare_and_swap(&rw->lock, old, old + 1))
127 return; 124 return;
128 } 125 }
@@ -140,9 +137,9 @@ void _raw_read_lock_wait_flags(arch_rwlock_t *rw, unsigned long flags)
140 smp_yield(); 137 smp_yield();
141 count = spin_retry; 138 count = spin_retry;
142 } 139 }
143 if (!arch_read_can_lock(rw)) 140 old = ACCESS_ONCE(rw->lock);
141 if ((int) old < 0)
144 continue; 142 continue;
145 old = rw->lock & 0x7fffffffU;
146 local_irq_disable(); 143 local_irq_disable();
147 if (_raw_compare_and_swap(&rw->lock, old, old + 1)) 144 if (_raw_compare_and_swap(&rw->lock, old, old + 1))
148 return; 145 return;
@@ -156,9 +153,9 @@ int _raw_read_trylock_retry(arch_rwlock_t *rw)
156 int count = spin_retry; 153 int count = spin_retry;
157 154
158 while (count-- > 0) { 155 while (count-- > 0) {
159 if (!arch_read_can_lock(rw)) 156 old = ACCESS_ONCE(rw->lock);
157 if ((int) old < 0)
160 continue; 158 continue;
161 old = rw->lock & 0x7fffffffU;
162 if (_raw_compare_and_swap(&rw->lock, old, old + 1)) 159 if (_raw_compare_and_swap(&rw->lock, old, old + 1))
163 return 1; 160 return 1;
164 } 161 }
@@ -168,6 +165,7 @@ EXPORT_SYMBOL(_raw_read_trylock_retry);
168 165
169void _raw_write_lock_wait(arch_rwlock_t *rw) 166void _raw_write_lock_wait(arch_rwlock_t *rw)
170{ 167{
168 unsigned int old;
171 int count = spin_retry; 169 int count = spin_retry;
172 170
173 while (1) { 171 while (1) {
@@ -175,7 +173,8 @@ void _raw_write_lock_wait(arch_rwlock_t *rw)
175 smp_yield(); 173 smp_yield();
176 count = spin_retry; 174 count = spin_retry;
177 } 175 }
178 if (!arch_write_can_lock(rw)) 176 old = ACCESS_ONCE(rw->lock);
177 if (old)
179 continue; 178 continue;
180 if (_raw_compare_and_swap(&rw->lock, 0, 0x80000000)) 179 if (_raw_compare_and_swap(&rw->lock, 0, 0x80000000))
181 return; 180 return;
@@ -185,6 +184,7 @@ EXPORT_SYMBOL(_raw_write_lock_wait);
185 184
186void _raw_write_lock_wait_flags(arch_rwlock_t *rw, unsigned long flags) 185void _raw_write_lock_wait_flags(arch_rwlock_t *rw, unsigned long flags)
187{ 186{
187 unsigned int old;
188 int count = spin_retry; 188 int count = spin_retry;
189 189
190 local_irq_restore(flags); 190 local_irq_restore(flags);
@@ -193,7 +193,8 @@ void _raw_write_lock_wait_flags(arch_rwlock_t *rw, unsigned long flags)
193 smp_yield(); 193 smp_yield();
194 count = spin_retry; 194 count = spin_retry;
195 } 195 }
196 if (!arch_write_can_lock(rw)) 196 old = ACCESS_ONCE(rw->lock);
197 if (old)
197 continue; 198 continue;
198 local_irq_disable(); 199 local_irq_disable();
199 if (_raw_compare_and_swap(&rw->lock, 0, 0x80000000)) 200 if (_raw_compare_and_swap(&rw->lock, 0, 0x80000000))
@@ -204,10 +205,12 @@ EXPORT_SYMBOL(_raw_write_lock_wait_flags);
204 205
205int _raw_write_trylock_retry(arch_rwlock_t *rw) 206int _raw_write_trylock_retry(arch_rwlock_t *rw)
206{ 207{
208 unsigned int old;
207 int count = spin_retry; 209 int count = spin_retry;
208 210
209 while (count-- > 0) { 211 while (count-- > 0) {
210 if (!arch_write_can_lock(rw)) 212 old = ACCESS_ONCE(rw->lock);
213 if (old)
211 continue; 214 continue;
212 if (_raw_compare_and_swap(&rw->lock, 0, 0x80000000)) 215 if (_raw_compare_and_swap(&rw->lock, 0, 0x80000000))
213 return 1; 216 return 1;