diff options
author | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2015-01-14 11:52:33 -0500 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2015-01-23 09:17:04 -0500 |
commit | 2c72a44ecdf2a7ceac73844226e97ed2d5dd1e82 (patch) | |
tree | a8475e1252115402a27b4c9a822943782085b151 /arch/s390/lib | |
parent | 55b5eb75e7ccdfe94b6ea1be6bba0c21149abecf (diff) |
s390/spinlock: add compare-and-delay to lock wait loops
Add the compare-and-delay instruction to the spin-lock and rw-lock
retry loops. A CPU executing the compare-and-delay instruction stops
until the lock value has changed. This is done to make the locking
code for contended locks to behave better in regard to the multi-
hreading facility. A thread of a core executing a compare-and-delay
will allow the other threads of a core to get a larger share of the
core resources.
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'arch/s390/lib')
-rw-r--r-- | arch/s390/lib/spinlock.c | 52 |
1 files changed, 45 insertions, 7 deletions
diff --git a/arch/s390/lib/spinlock.c b/arch/s390/lib/spinlock.c index 034a35a3e9c1..d6c9991f7797 100644 --- a/arch/s390/lib/spinlock.c +++ b/arch/s390/lib/spinlock.c | |||
@@ -12,7 +12,15 @@ | |||
12 | #include <linux/smp.h> | 12 | #include <linux/smp.h> |
13 | #include <asm/io.h> | 13 | #include <asm/io.h> |
14 | 14 | ||
15 | int spin_retry = 1000; | 15 | int spin_retry = -1; |
16 | |||
17 | static int __init spin_retry_init(void) | ||
18 | { | ||
19 | if (spin_retry < 0) | ||
20 | spin_retry = MACHINE_HAS_CAD ? 10 : 1000; | ||
21 | return 0; | ||
22 | } | ||
23 | early_initcall(spin_retry_init); | ||
16 | 24 | ||
17 | /** | 25 | /** |
18 | * spin_retry= parameter | 26 | * spin_retry= parameter |
@@ -24,6 +32,11 @@ static int __init spin_retry_setup(char *str) | |||
24 | } | 32 | } |
25 | __setup("spin_retry=", spin_retry_setup); | 33 | __setup("spin_retry=", spin_retry_setup); |
26 | 34 | ||
35 | static inline void _raw_compare_and_delay(unsigned int *lock, unsigned int old) | ||
36 | { | ||
37 | asm(".insn rsy,0xeb0000000022,%0,0,%1" : : "d" (old), "Q" (*lock)); | ||
38 | } | ||
39 | |||
27 | void arch_spin_lock_wait(arch_spinlock_t *lp) | 40 | void arch_spin_lock_wait(arch_spinlock_t *lp) |
28 | { | 41 | { |
29 | unsigned int cpu = SPINLOCK_LOCKVAL; | 42 | unsigned int cpu = SPINLOCK_LOCKVAL; |
@@ -46,6 +59,8 @@ void arch_spin_lock_wait(arch_spinlock_t *lp) | |||
46 | /* Loop for a while on the lock value. */ | 59 | /* Loop for a while on the lock value. */ |
47 | count = spin_retry; | 60 | count = spin_retry; |
48 | do { | 61 | do { |
62 | if (MACHINE_HAS_CAD) | ||
63 | _raw_compare_and_delay(&lp->lock, owner); | ||
49 | owner = ACCESS_ONCE(lp->lock); | 64 | owner = ACCESS_ONCE(lp->lock); |
50 | } while (owner && count-- > 0); | 65 | } while (owner && count-- > 0); |
51 | if (!owner) | 66 | if (!owner) |
@@ -84,6 +99,8 @@ void arch_spin_lock_wait_flags(arch_spinlock_t *lp, unsigned long flags) | |||
84 | /* Loop for a while on the lock value. */ | 99 | /* Loop for a while on the lock value. */ |
85 | count = spin_retry; | 100 | count = spin_retry; |
86 | do { | 101 | do { |
102 | if (MACHINE_HAS_CAD) | ||
103 | _raw_compare_and_delay(&lp->lock, owner); | ||
87 | owner = ACCESS_ONCE(lp->lock); | 104 | owner = ACCESS_ONCE(lp->lock); |
88 | } while (owner && count-- > 0); | 105 | } while (owner && count-- > 0); |
89 | if (!owner) | 106 | if (!owner) |
@@ -100,11 +117,19 @@ EXPORT_SYMBOL(arch_spin_lock_wait_flags); | |||
100 | 117 | ||
101 | int arch_spin_trylock_retry(arch_spinlock_t *lp) | 118 | int arch_spin_trylock_retry(arch_spinlock_t *lp) |
102 | { | 119 | { |
120 | unsigned int cpu = SPINLOCK_LOCKVAL; | ||
121 | unsigned int owner; | ||
103 | int count; | 122 | int count; |
104 | 123 | ||
105 | for (count = spin_retry; count > 0; count--) | 124 | for (count = spin_retry; count > 0; count--) { |
106 | if (arch_spin_trylock_once(lp)) | 125 | owner = ACCESS_ONCE(lp->lock); |
107 | return 1; | 126 | /* Try to get the lock if it is free. */ |
127 | if (!owner) { | ||
128 | if (_raw_compare_and_swap(&lp->lock, 0, cpu)) | ||
129 | return 1; | ||
130 | } else if (MACHINE_HAS_CAD) | ||
131 | _raw_compare_and_delay(&lp->lock, owner); | ||
132 | } | ||
108 | return 0; | 133 | return 0; |
109 | } | 134 | } |
110 | EXPORT_SYMBOL(arch_spin_trylock_retry); | 135 | EXPORT_SYMBOL(arch_spin_trylock_retry); |
@@ -126,8 +151,11 @@ void _raw_read_lock_wait(arch_rwlock_t *rw) | |||
126 | } | 151 | } |
127 | old = ACCESS_ONCE(rw->lock); | 152 | old = ACCESS_ONCE(rw->lock); |
128 | owner = ACCESS_ONCE(rw->owner); | 153 | owner = ACCESS_ONCE(rw->owner); |
129 | if ((int) old < 0) | 154 | if ((int) old < 0) { |
155 | if (MACHINE_HAS_CAD) | ||
156 | _raw_compare_and_delay(&rw->lock, old); | ||
130 | continue; | 157 | continue; |
158 | } | ||
131 | if (_raw_compare_and_swap(&rw->lock, old, old + 1)) | 159 | if (_raw_compare_and_swap(&rw->lock, old, old + 1)) |
132 | return; | 160 | return; |
133 | } | 161 | } |
@@ -141,8 +169,11 @@ int _raw_read_trylock_retry(arch_rwlock_t *rw) | |||
141 | 169 | ||
142 | while (count-- > 0) { | 170 | while (count-- > 0) { |
143 | old = ACCESS_ONCE(rw->lock); | 171 | old = ACCESS_ONCE(rw->lock); |
144 | if ((int) old < 0) | 172 | if ((int) old < 0) { |
173 | if (MACHINE_HAS_CAD) | ||
174 | _raw_compare_and_delay(&rw->lock, old); | ||
145 | continue; | 175 | continue; |
176 | } | ||
146 | if (_raw_compare_and_swap(&rw->lock, old, old + 1)) | 177 | if (_raw_compare_and_swap(&rw->lock, old, old + 1)) |
147 | return 1; | 178 | return 1; |
148 | } | 179 | } |
@@ -173,6 +204,8 @@ void _raw_write_lock_wait(arch_rwlock_t *rw, unsigned int prev) | |||
173 | } | 204 | } |
174 | if ((old & 0x7fffffff) == 0 && (int) prev >= 0) | 205 | if ((old & 0x7fffffff) == 0 && (int) prev >= 0) |
175 | break; | 206 | break; |
207 | if (MACHINE_HAS_CAD) | ||
208 | _raw_compare_and_delay(&rw->lock, old); | ||
176 | } | 209 | } |
177 | } | 210 | } |
178 | EXPORT_SYMBOL(_raw_write_lock_wait); | 211 | EXPORT_SYMBOL(_raw_write_lock_wait); |
@@ -201,6 +234,8 @@ void _raw_write_lock_wait(arch_rwlock_t *rw) | |||
201 | smp_rmb(); | 234 | smp_rmb(); |
202 | if ((old & 0x7fffffff) == 0 && (int) prev >= 0) | 235 | if ((old & 0x7fffffff) == 0 && (int) prev >= 0) |
203 | break; | 236 | break; |
237 | if (MACHINE_HAS_CAD) | ||
238 | _raw_compare_and_delay(&rw->lock, old); | ||
204 | } | 239 | } |
205 | } | 240 | } |
206 | EXPORT_SYMBOL(_raw_write_lock_wait); | 241 | EXPORT_SYMBOL(_raw_write_lock_wait); |
@@ -214,8 +249,11 @@ int _raw_write_trylock_retry(arch_rwlock_t *rw) | |||
214 | 249 | ||
215 | while (count-- > 0) { | 250 | while (count-- > 0) { |
216 | old = ACCESS_ONCE(rw->lock); | 251 | old = ACCESS_ONCE(rw->lock); |
217 | if (old) | 252 | if (old) { |
253 | if (MACHINE_HAS_CAD) | ||
254 | _raw_compare_and_delay(&rw->lock, old); | ||
218 | continue; | 255 | continue; |
256 | } | ||
219 | if (_raw_compare_and_swap(&rw->lock, 0, 0x80000000)) | 257 | if (_raw_compare_and_swap(&rw->lock, 0, 0x80000000)) |
220 | return 1; | 258 | return 1; |
221 | } | 259 | } |