diff options
-rw-r--r-- | arch/s390/include/asm/setup.h | 3 | ||||
-rw-r--r-- | arch/s390/kernel/early.c | 18 | ||||
-rw-r--r-- | arch/s390/lib/spinlock.c | 52 |
3 files changed, 66 insertions, 7 deletions
diff --git a/arch/s390/include/asm/setup.h b/arch/s390/include/asm/setup.h index 7736fdd72595..b8d1e54b4733 100644 --- a/arch/s390/include/asm/setup.h +++ b/arch/s390/include/asm/setup.h | |||
@@ -57,6 +57,7 @@ extern void detect_memory_memblock(void); | |||
57 | #define MACHINE_FLAG_TE (1UL << 15) | 57 | #define MACHINE_FLAG_TE (1UL << 15) |
58 | #define MACHINE_FLAG_TLB_LC (1UL << 17) | 58 | #define MACHINE_FLAG_TLB_LC (1UL << 17) |
59 | #define MACHINE_FLAG_VX (1UL << 18) | 59 | #define MACHINE_FLAG_VX (1UL << 18) |
60 | #define MACHINE_FLAG_CAD (1UL << 19) | ||
60 | 61 | ||
61 | #define MACHINE_IS_VM (S390_lowcore.machine_flags & MACHINE_FLAG_VM) | 62 | #define MACHINE_IS_VM (S390_lowcore.machine_flags & MACHINE_FLAG_VM) |
62 | #define MACHINE_IS_KVM (S390_lowcore.machine_flags & MACHINE_FLAG_KVM) | 63 | #define MACHINE_IS_KVM (S390_lowcore.machine_flags & MACHINE_FLAG_KVM) |
@@ -80,6 +81,7 @@ extern void detect_memory_memblock(void); | |||
80 | #define MACHINE_HAS_TE (0) | 81 | #define MACHINE_HAS_TE (0) |
81 | #define MACHINE_HAS_TLB_LC (0) | 82 | #define MACHINE_HAS_TLB_LC (0) |
82 | #define MACHINE_HAS_VX (0) | 83 | #define MACHINE_HAS_VX (0) |
84 | #define MACHINE_HAS_CAD (0) | ||
83 | #else /* CONFIG_64BIT */ | 85 | #else /* CONFIG_64BIT */ |
84 | #define MACHINE_HAS_IEEE (1) | 86 | #define MACHINE_HAS_IEEE (1) |
85 | #define MACHINE_HAS_CSP (1) | 87 | #define MACHINE_HAS_CSP (1) |
@@ -93,6 +95,7 @@ extern void detect_memory_memblock(void); | |||
93 | #define MACHINE_HAS_TE (S390_lowcore.machine_flags & MACHINE_FLAG_TE) | 95 | #define MACHINE_HAS_TE (S390_lowcore.machine_flags & MACHINE_FLAG_TE) |
94 | #define MACHINE_HAS_TLB_LC (S390_lowcore.machine_flags & MACHINE_FLAG_TLB_LC) | 96 | #define MACHINE_HAS_TLB_LC (S390_lowcore.machine_flags & MACHINE_FLAG_TLB_LC) |
95 | #define MACHINE_HAS_VX (S390_lowcore.machine_flags & MACHINE_FLAG_VX) | 97 | #define MACHINE_HAS_VX (S390_lowcore.machine_flags & MACHINE_FLAG_VX) |
98 | #define MACHINE_HAS_CAD (S390_lowcore.machine_flags & MACHINE_FLAG_CAD) | ||
96 | #endif /* CONFIG_64BIT */ | 99 | #endif /* CONFIG_64BIT */ |
97 | 100 | ||
98 | /* | 101 | /* |
diff --git a/arch/s390/kernel/early.c b/arch/s390/kernel/early.c index 302ac1f7f8e7..70a329450901 100644 --- a/arch/s390/kernel/early.c +++ b/arch/s390/kernel/early.c | |||
@@ -393,9 +393,27 @@ static __init void detect_machine_facilities(void) | |||
393 | S390_lowcore.machine_flags |= MACHINE_FLAG_TLB_LC; | 393 | S390_lowcore.machine_flags |= MACHINE_FLAG_TLB_LC; |
394 | if (test_facility(129)) | 394 | if (test_facility(129)) |
395 | S390_lowcore.machine_flags |= MACHINE_FLAG_VX; | 395 | S390_lowcore.machine_flags |= MACHINE_FLAG_VX; |
396 | if (test_facility(128)) | ||
397 | S390_lowcore.machine_flags |= MACHINE_FLAG_CAD; | ||
396 | #endif | 398 | #endif |
397 | } | 399 | } |
398 | 400 | ||
401 | static int __init nocad_setup(char *str) | ||
402 | { | ||
403 | S390_lowcore.machine_flags &= ~MACHINE_FLAG_CAD; | ||
404 | return 0; | ||
405 | } | ||
406 | early_param("nocad", nocad_setup); | ||
407 | |||
408 | static int __init cad_init(void) | ||
409 | { | ||
410 | if (MACHINE_HAS_CAD) | ||
411 | /* Enable problem state CAD. */ | ||
412 | __ctl_set_bit(2, 3); | ||
413 | return 0; | ||
414 | } | ||
415 | early_initcall(cad_init); | ||
416 | |||
399 | static __init void rescue_initrd(void) | 417 | static __init void rescue_initrd(void) |
400 | { | 418 | { |
401 | #ifdef CONFIG_BLK_DEV_INITRD | 419 | #ifdef CONFIG_BLK_DEV_INITRD |
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 | } |