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