1951f22d5SMartin Schwidefsky /* 2951f22d5SMartin Schwidefsky * Out of line spinlock code. 3951f22d5SMartin Schwidefsky * 4a53c8fabSHeiko Carstens * Copyright IBM Corp. 2004, 2006 5951f22d5SMartin Schwidefsky * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com) 6951f22d5SMartin Schwidefsky */ 7951f22d5SMartin Schwidefsky 8951f22d5SMartin Schwidefsky #include <linux/types.h> 9951f22d5SMartin Schwidefsky #include <linux/module.h> 10951f22d5SMartin Schwidefsky #include <linux/spinlock.h> 11951f22d5SMartin Schwidefsky #include <linux/init.h> 128b646bd7SMartin Schwidefsky #include <linux/smp.h> 13951f22d5SMartin Schwidefsky #include <asm/io.h> 14951f22d5SMartin Schwidefsky 15951f22d5SMartin Schwidefsky int spin_retry = 1000; 16951f22d5SMartin Schwidefsky 17951f22d5SMartin Schwidefsky /** 18951f22d5SMartin Schwidefsky * spin_retry= parameter 19951f22d5SMartin Schwidefsky */ 20951f22d5SMartin Schwidefsky static int __init spin_retry_setup(char *str) 21951f22d5SMartin Schwidefsky { 22951f22d5SMartin Schwidefsky spin_retry = simple_strtoul(str, &str, 0); 23951f22d5SMartin Schwidefsky return 1; 24951f22d5SMartin Schwidefsky } 25951f22d5SMartin Schwidefsky __setup("spin_retry=", spin_retry_setup); 26951f22d5SMartin Schwidefsky 270199c4e6SThomas Gleixner void arch_spin_lock_wait(arch_spinlock_t *lp) 28951f22d5SMartin Schwidefsky { 296c8cd5bbSPhilipp Hachtmann unsigned int cpu = SPINLOCK_LOCKVAL; 3059b69787SGerald Schaefer unsigned int owner; 312e4006b3SGerald Schaefer int count; 32951f22d5SMartin Schwidefsky 33951f22d5SMartin Schwidefsky while (1) { 345b3f683eSPhilipp Hachtmann owner = lp->lock; 3559b69787SGerald Schaefer if (!owner || smp_vcpu_scheduled(~owner)) { 362e4006b3SGerald Schaefer count = spin_retry; 372e4006b3SGerald Schaefer do { 380199c4e6SThomas Gleixner if (arch_spin_is_locked(lp)) 3996567161SChristian Ehrhardt continue; 405b3f683eSPhilipp Hachtmann if (_raw_compare_and_swap(&lp->lock, 0, cpu)) 4159b69787SGerald Schaefer return; 422e4006b3SGerald Schaefer } while (count-- > 0); 4359b69787SGerald Schaefer if (MACHINE_IS_LPAR) 4459b69787SGerald Schaefer continue; 4559b69787SGerald Schaefer } 465b3f683eSPhilipp Hachtmann owner = lp->lock; 4759b69787SGerald Schaefer if (owner) 488b646bd7SMartin Schwidefsky smp_yield_cpu(~owner); 495b3f683eSPhilipp Hachtmann if (_raw_compare_and_swap(&lp->lock, 0, cpu)) 50951f22d5SMartin Schwidefsky return; 51951f22d5SMartin Schwidefsky } 52951f22d5SMartin Schwidefsky } 530199c4e6SThomas Gleixner EXPORT_SYMBOL(arch_spin_lock_wait); 54951f22d5SMartin Schwidefsky 550199c4e6SThomas Gleixner void arch_spin_lock_wait_flags(arch_spinlock_t *lp, unsigned long flags) 56894cdde2SHisashi Hifumi { 576c8cd5bbSPhilipp Hachtmann unsigned int cpu = SPINLOCK_LOCKVAL; 5859b69787SGerald Schaefer unsigned int owner; 592e4006b3SGerald Schaefer int count; 60894cdde2SHisashi Hifumi 61894cdde2SHisashi Hifumi local_irq_restore(flags); 62894cdde2SHisashi Hifumi while (1) { 635b3f683eSPhilipp Hachtmann owner = lp->lock; 6459b69787SGerald Schaefer if (!owner || smp_vcpu_scheduled(~owner)) { 652e4006b3SGerald Schaefer count = spin_retry; 662e4006b3SGerald Schaefer do { 670199c4e6SThomas Gleixner if (arch_spin_is_locked(lp)) 68894cdde2SHisashi Hifumi continue; 69894cdde2SHisashi Hifumi local_irq_disable(); 705b3f683eSPhilipp Hachtmann if (_raw_compare_and_swap(&lp->lock, 0, cpu)) 7159b69787SGerald Schaefer return; 7259b69787SGerald Schaefer local_irq_restore(flags); 732e4006b3SGerald Schaefer } while (count-- > 0); 7459b69787SGerald Schaefer if (MACHINE_IS_LPAR) 7559b69787SGerald Schaefer continue; 7659b69787SGerald Schaefer } 775b3f683eSPhilipp Hachtmann owner = lp->lock; 7859b69787SGerald Schaefer if (owner) 798b646bd7SMartin Schwidefsky smp_yield_cpu(~owner); 8059b69787SGerald Schaefer local_irq_disable(); 815b3f683eSPhilipp Hachtmann if (_raw_compare_and_swap(&lp->lock, 0, cpu)) 82894cdde2SHisashi Hifumi return; 83894cdde2SHisashi Hifumi local_irq_restore(flags); 84894cdde2SHisashi Hifumi } 85894cdde2SHisashi Hifumi } 860199c4e6SThomas Gleixner EXPORT_SYMBOL(arch_spin_lock_wait_flags); 87894cdde2SHisashi Hifumi 885b3f683eSPhilipp Hachtmann void arch_spin_relax(arch_spinlock_t *lp) 89951f22d5SMartin Schwidefsky { 905b3f683eSPhilipp Hachtmann unsigned int cpu = lp->lock; 9159b69787SGerald Schaefer if (cpu != 0) { 9259b69787SGerald Schaefer if (MACHINE_IS_VM || MACHINE_IS_KVM || 9359b69787SGerald Schaefer !smp_vcpu_scheduled(~cpu)) 948b646bd7SMartin Schwidefsky smp_yield_cpu(~cpu); 953c1fcfe2SMartin Schwidefsky } 9659b69787SGerald Schaefer } 970199c4e6SThomas Gleixner EXPORT_SYMBOL(arch_spin_relax); 983c1fcfe2SMartin Schwidefsky 995b3f683eSPhilipp Hachtmann int arch_spin_trylock_retry(arch_spinlock_t *lp) 1005b3f683eSPhilipp Hachtmann { 1015b3f683eSPhilipp Hachtmann int count; 1025b3f683eSPhilipp Hachtmann 1035b3f683eSPhilipp Hachtmann for (count = spin_retry; count > 0; count--) { 1045b3f683eSPhilipp Hachtmann if (arch_spin_is_locked(lp)) 1055b3f683eSPhilipp Hachtmann continue; 1065b3f683eSPhilipp Hachtmann if (arch_spin_trylock_once(lp)) 1075b3f683eSPhilipp Hachtmann return 1; 1085b3f683eSPhilipp Hachtmann } 1095b3f683eSPhilipp Hachtmann return 0; 1105b3f683eSPhilipp Hachtmann } 1115b3f683eSPhilipp Hachtmann EXPORT_SYMBOL(arch_spin_trylock_retry); 1125b3f683eSPhilipp Hachtmann 113fb3a6bbcSThomas Gleixner void _raw_read_lock_wait(arch_rwlock_t *rw) 114951f22d5SMartin Schwidefsky { 115951f22d5SMartin Schwidefsky unsigned int old; 116951f22d5SMartin Schwidefsky int count = spin_retry; 117951f22d5SMartin Schwidefsky 118951f22d5SMartin Schwidefsky while (1) { 119951f22d5SMartin Schwidefsky if (count-- <= 0) { 1208b646bd7SMartin Schwidefsky smp_yield(); 121951f22d5SMartin Schwidefsky count = spin_retry; 122951f22d5SMartin Schwidefsky } 123e5931943SThomas Gleixner if (!arch_read_can_lock(rw)) 12496567161SChristian Ehrhardt continue; 125951f22d5SMartin Schwidefsky old = rw->lock & 0x7fffffffU; 1265b3f683eSPhilipp Hachtmann if (_raw_compare_and_swap(&rw->lock, old, old + 1)) 127951f22d5SMartin Schwidefsky return; 128951f22d5SMartin Schwidefsky } 129951f22d5SMartin Schwidefsky } 130951f22d5SMartin Schwidefsky EXPORT_SYMBOL(_raw_read_lock_wait); 131951f22d5SMartin Schwidefsky 132fb3a6bbcSThomas Gleixner void _raw_read_lock_wait_flags(arch_rwlock_t *rw, unsigned long flags) 133ce58ae6fSHeiko Carstens { 134ce58ae6fSHeiko Carstens unsigned int old; 135ce58ae6fSHeiko Carstens int count = spin_retry; 136ce58ae6fSHeiko Carstens 137ce58ae6fSHeiko Carstens local_irq_restore(flags); 138ce58ae6fSHeiko Carstens while (1) { 139ce58ae6fSHeiko Carstens if (count-- <= 0) { 1408b646bd7SMartin Schwidefsky smp_yield(); 141ce58ae6fSHeiko Carstens count = spin_retry; 142ce58ae6fSHeiko Carstens } 143e5931943SThomas Gleixner if (!arch_read_can_lock(rw)) 144ce58ae6fSHeiko Carstens continue; 145ce58ae6fSHeiko Carstens old = rw->lock & 0x7fffffffU; 146ce58ae6fSHeiko Carstens local_irq_disable(); 1475b3f683eSPhilipp Hachtmann if (_raw_compare_and_swap(&rw->lock, old, old + 1)) 148ce58ae6fSHeiko Carstens return; 149ce58ae6fSHeiko Carstens } 150ce58ae6fSHeiko Carstens } 151ce58ae6fSHeiko Carstens EXPORT_SYMBOL(_raw_read_lock_wait_flags); 152ce58ae6fSHeiko Carstens 153fb3a6bbcSThomas Gleixner int _raw_read_trylock_retry(arch_rwlock_t *rw) 154951f22d5SMartin Schwidefsky { 155951f22d5SMartin Schwidefsky unsigned int old; 156951f22d5SMartin Schwidefsky int count = spin_retry; 157951f22d5SMartin Schwidefsky 158951f22d5SMartin Schwidefsky while (count-- > 0) { 159e5931943SThomas Gleixner if (!arch_read_can_lock(rw)) 16096567161SChristian Ehrhardt continue; 161951f22d5SMartin Schwidefsky old = rw->lock & 0x7fffffffU; 1625b3f683eSPhilipp Hachtmann if (_raw_compare_and_swap(&rw->lock, old, old + 1)) 163951f22d5SMartin Schwidefsky return 1; 164951f22d5SMartin Schwidefsky } 165951f22d5SMartin Schwidefsky return 0; 166951f22d5SMartin Schwidefsky } 167951f22d5SMartin Schwidefsky EXPORT_SYMBOL(_raw_read_trylock_retry); 168951f22d5SMartin Schwidefsky 169fb3a6bbcSThomas Gleixner void _raw_write_lock_wait(arch_rwlock_t *rw) 170951f22d5SMartin Schwidefsky { 171951f22d5SMartin Schwidefsky int count = spin_retry; 172951f22d5SMartin Schwidefsky 173951f22d5SMartin Schwidefsky while (1) { 174951f22d5SMartin Schwidefsky if (count-- <= 0) { 1758b646bd7SMartin Schwidefsky smp_yield(); 176951f22d5SMartin Schwidefsky count = spin_retry; 177951f22d5SMartin Schwidefsky } 178e5931943SThomas Gleixner if (!arch_write_can_lock(rw)) 17996567161SChristian Ehrhardt continue; 1805b3f683eSPhilipp Hachtmann if (_raw_compare_and_swap(&rw->lock, 0, 0x80000000)) 181951f22d5SMartin Schwidefsky return; 182951f22d5SMartin Schwidefsky } 183951f22d5SMartin Schwidefsky } 184951f22d5SMartin Schwidefsky EXPORT_SYMBOL(_raw_write_lock_wait); 185951f22d5SMartin Schwidefsky 186fb3a6bbcSThomas Gleixner void _raw_write_lock_wait_flags(arch_rwlock_t *rw, unsigned long flags) 187ce58ae6fSHeiko Carstens { 188ce58ae6fSHeiko Carstens int count = spin_retry; 189ce58ae6fSHeiko Carstens 190ce58ae6fSHeiko Carstens local_irq_restore(flags); 191ce58ae6fSHeiko Carstens while (1) { 192ce58ae6fSHeiko Carstens if (count-- <= 0) { 1938b646bd7SMartin Schwidefsky smp_yield(); 194ce58ae6fSHeiko Carstens count = spin_retry; 195ce58ae6fSHeiko Carstens } 196e5931943SThomas Gleixner if (!arch_write_can_lock(rw)) 197ce58ae6fSHeiko Carstens continue; 198ce58ae6fSHeiko Carstens local_irq_disable(); 1995b3f683eSPhilipp Hachtmann if (_raw_compare_and_swap(&rw->lock, 0, 0x80000000)) 200ce58ae6fSHeiko Carstens return; 201ce58ae6fSHeiko Carstens } 202ce58ae6fSHeiko Carstens } 203ce58ae6fSHeiko Carstens EXPORT_SYMBOL(_raw_write_lock_wait_flags); 204ce58ae6fSHeiko Carstens 205fb3a6bbcSThomas Gleixner int _raw_write_trylock_retry(arch_rwlock_t *rw) 206951f22d5SMartin Schwidefsky { 207951f22d5SMartin Schwidefsky int count = spin_retry; 208951f22d5SMartin Schwidefsky 209951f22d5SMartin Schwidefsky while (count-- > 0) { 210e5931943SThomas Gleixner if (!arch_write_can_lock(rw)) 21196567161SChristian Ehrhardt continue; 2125b3f683eSPhilipp Hachtmann if (_raw_compare_and_swap(&rw->lock, 0, 0x80000000)) 213951f22d5SMartin Schwidefsky return 1; 214951f22d5SMartin Schwidefsky } 215951f22d5SMartin Schwidefsky return 0; 216951f22d5SMartin Schwidefsky } 217951f22d5SMartin Schwidefsky EXPORT_SYMBOL(_raw_write_trylock_retry); 218