1 /* 2 * arch/s390/lib/spinlock.c 3 * Out of line spinlock code. 4 * 5 * Copyright (C) IBM Corp. 2004, 2006 6 * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com) 7 */ 8 9 #include <linux/types.h> 10 #include <linux/module.h> 11 #include <linux/spinlock.h> 12 #include <linux/init.h> 13 #include <asm/io.h> 14 15 int spin_retry = 1000; 16 17 /** 18 * spin_retry= parameter 19 */ 20 static int __init spin_retry_setup(char *str) 21 { 22 spin_retry = simple_strtoul(str, &str, 0); 23 return 1; 24 } 25 __setup("spin_retry=", spin_retry_setup); 26 27 static inline void _raw_yield(void) 28 { 29 if (MACHINE_HAS_DIAG44) 30 asm volatile("diag 0,0,0x44"); 31 } 32 33 static inline void _raw_yield_cpu(int cpu) 34 { 35 if (MACHINE_HAS_DIAG9C) 36 asm volatile("diag %0,0,0x9c" 37 : : "d" (cpu_logical_map(cpu))); 38 else 39 _raw_yield(); 40 } 41 42 void arch_spin_lock_wait(arch_spinlock_t *lp) 43 { 44 int count = spin_retry; 45 unsigned int cpu = ~smp_processor_id(); 46 unsigned int owner; 47 48 while (1) { 49 owner = lp->owner_cpu; 50 if (!owner || smp_vcpu_scheduled(~owner)) { 51 for (count = spin_retry; count > 0; count--) { 52 if (arch_spin_is_locked(lp)) 53 continue; 54 if (_raw_compare_and_swap(&lp->owner_cpu, 0, 55 cpu) == 0) 56 return; 57 } 58 if (MACHINE_IS_LPAR) 59 continue; 60 } 61 owner = lp->owner_cpu; 62 if (owner) 63 _raw_yield_cpu(~owner); 64 if (_raw_compare_and_swap(&lp->owner_cpu, 0, cpu) == 0) 65 return; 66 } 67 } 68 EXPORT_SYMBOL(arch_spin_lock_wait); 69 70 void arch_spin_lock_wait_flags(arch_spinlock_t *lp, unsigned long flags) 71 { 72 int count = spin_retry; 73 unsigned int cpu = ~smp_processor_id(); 74 unsigned int owner; 75 76 local_irq_restore(flags); 77 while (1) { 78 owner = lp->owner_cpu; 79 if (!owner || smp_vcpu_scheduled(~owner)) { 80 for (count = spin_retry; count > 0; count--) { 81 if (arch_spin_is_locked(lp)) 82 continue; 83 local_irq_disable(); 84 if (_raw_compare_and_swap(&lp->owner_cpu, 0, 85 cpu) == 0) 86 return; 87 local_irq_restore(flags); 88 } 89 if (MACHINE_IS_LPAR) 90 continue; 91 } 92 owner = lp->owner_cpu; 93 if (owner) 94 _raw_yield_cpu(~owner); 95 local_irq_disable(); 96 if (_raw_compare_and_swap(&lp->owner_cpu, 0, cpu) == 0) 97 return; 98 local_irq_restore(flags); 99 } 100 } 101 EXPORT_SYMBOL(arch_spin_lock_wait_flags); 102 103 int arch_spin_trylock_retry(arch_spinlock_t *lp) 104 { 105 unsigned int cpu = ~smp_processor_id(); 106 int count; 107 108 for (count = spin_retry; count > 0; count--) { 109 if (arch_spin_is_locked(lp)) 110 continue; 111 if (_raw_compare_and_swap(&lp->owner_cpu, 0, cpu) == 0) 112 return 1; 113 } 114 return 0; 115 } 116 EXPORT_SYMBOL(arch_spin_trylock_retry); 117 118 void arch_spin_relax(arch_spinlock_t *lock) 119 { 120 unsigned int cpu = lock->owner_cpu; 121 if (cpu != 0) { 122 if (MACHINE_IS_VM || MACHINE_IS_KVM || 123 !smp_vcpu_scheduled(~cpu)) 124 _raw_yield_cpu(~cpu); 125 } 126 } 127 EXPORT_SYMBOL(arch_spin_relax); 128 129 void _raw_read_lock_wait(arch_rwlock_t *rw) 130 { 131 unsigned int old; 132 int count = spin_retry; 133 134 while (1) { 135 if (count-- <= 0) { 136 _raw_yield(); 137 count = spin_retry; 138 } 139 if (!arch_read_can_lock(rw)) 140 continue; 141 old = rw->lock & 0x7fffffffU; 142 if (_raw_compare_and_swap(&rw->lock, old, old + 1) == old) 143 return; 144 } 145 } 146 EXPORT_SYMBOL(_raw_read_lock_wait); 147 148 void _raw_read_lock_wait_flags(arch_rwlock_t *rw, unsigned long flags) 149 { 150 unsigned int old; 151 int count = spin_retry; 152 153 local_irq_restore(flags); 154 while (1) { 155 if (count-- <= 0) { 156 _raw_yield(); 157 count = spin_retry; 158 } 159 if (!arch_read_can_lock(rw)) 160 continue; 161 old = rw->lock & 0x7fffffffU; 162 local_irq_disable(); 163 if (_raw_compare_and_swap(&rw->lock, old, old + 1) == old) 164 return; 165 } 166 } 167 EXPORT_SYMBOL(_raw_read_lock_wait_flags); 168 169 int _raw_read_trylock_retry(arch_rwlock_t *rw) 170 { 171 unsigned int old; 172 int count = spin_retry; 173 174 while (count-- > 0) { 175 if (!arch_read_can_lock(rw)) 176 continue; 177 old = rw->lock & 0x7fffffffU; 178 if (_raw_compare_and_swap(&rw->lock, old, old + 1) == old) 179 return 1; 180 } 181 return 0; 182 } 183 EXPORT_SYMBOL(_raw_read_trylock_retry); 184 185 void _raw_write_lock_wait(arch_rwlock_t *rw) 186 { 187 int count = spin_retry; 188 189 while (1) { 190 if (count-- <= 0) { 191 _raw_yield(); 192 count = spin_retry; 193 } 194 if (!arch_write_can_lock(rw)) 195 continue; 196 if (_raw_compare_and_swap(&rw->lock, 0, 0x80000000) == 0) 197 return; 198 } 199 } 200 EXPORT_SYMBOL(_raw_write_lock_wait); 201 202 void _raw_write_lock_wait_flags(arch_rwlock_t *rw, unsigned long flags) 203 { 204 int count = spin_retry; 205 206 local_irq_restore(flags); 207 while (1) { 208 if (count-- <= 0) { 209 _raw_yield(); 210 count = spin_retry; 211 } 212 if (!arch_write_can_lock(rw)) 213 continue; 214 local_irq_disable(); 215 if (_raw_compare_and_swap(&rw->lock, 0, 0x80000000) == 0) 216 return; 217 } 218 } 219 EXPORT_SYMBOL(_raw_write_lock_wait_flags); 220 221 int _raw_write_trylock_retry(arch_rwlock_t *rw) 222 { 223 int count = spin_retry; 224 225 while (count-- > 0) { 226 if (!arch_write_can_lock(rw)) 227 continue; 228 if (_raw_compare_and_swap(&rw->lock, 0, 0x80000000) == 0) 229 return 1; 230 } 231 return 0; 232 } 233 EXPORT_SYMBOL(_raw_write_trylock_retry); 234