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 { 29951f22d5SMartin Schwidefsky int count = spin_retry; 306c8cd5bbSPhilipp Hachtmann unsigned int cpu = SPINLOCK_LOCKVAL; 3159b69787SGerald Schaefer unsigned int owner; 32951f22d5SMartin Schwidefsky 33951f22d5SMartin Schwidefsky while (1) { 345b3f683eSPhilipp Hachtmann owner = lp->lock; 3559b69787SGerald Schaefer if (!owner || smp_vcpu_scheduled(~owner)) { 3659b69787SGerald Schaefer for (count = spin_retry; count > 0; count--) { 370199c4e6SThomas Gleixner if (arch_spin_is_locked(lp)) 3896567161SChristian Ehrhardt continue; 395b3f683eSPhilipp Hachtmann if (_raw_compare_and_swap(&lp->lock, 0, cpu)) 4059b69787SGerald Schaefer return; 4159b69787SGerald Schaefer } 4259b69787SGerald Schaefer if (MACHINE_IS_LPAR) 4359b69787SGerald Schaefer continue; 4459b69787SGerald Schaefer } 455b3f683eSPhilipp Hachtmann owner = lp->lock; 4659b69787SGerald Schaefer if (owner) 478b646bd7SMartin Schwidefsky smp_yield_cpu(~owner); 485b3f683eSPhilipp Hachtmann if (_raw_compare_and_swap(&lp->lock, 0, cpu)) 49951f22d5SMartin Schwidefsky return; 50951f22d5SMartin Schwidefsky } 51951f22d5SMartin Schwidefsky } 520199c4e6SThomas Gleixner EXPORT_SYMBOL(arch_spin_lock_wait); 53951f22d5SMartin Schwidefsky 540199c4e6SThomas Gleixner void arch_spin_lock_wait_flags(arch_spinlock_t *lp, unsigned long flags) 55894cdde2SHisashi Hifumi { 56894cdde2SHisashi Hifumi int count = spin_retry; 576c8cd5bbSPhilipp Hachtmann unsigned int cpu = SPINLOCK_LOCKVAL; 5859b69787SGerald Schaefer unsigned int owner; 59894cdde2SHisashi Hifumi 60894cdde2SHisashi Hifumi local_irq_restore(flags); 61894cdde2SHisashi Hifumi while (1) { 625b3f683eSPhilipp Hachtmann owner = lp->lock; 6359b69787SGerald Schaefer if (!owner || smp_vcpu_scheduled(~owner)) { 6459b69787SGerald Schaefer for (count = spin_retry; count > 0; count--) { 650199c4e6SThomas Gleixner if (arch_spin_is_locked(lp)) 66894cdde2SHisashi Hifumi continue; 67894cdde2SHisashi Hifumi local_irq_disable(); 685b3f683eSPhilipp Hachtmann if (_raw_compare_and_swap(&lp->lock, 0, cpu)) 6959b69787SGerald Schaefer return; 7059b69787SGerald Schaefer local_irq_restore(flags); 7159b69787SGerald Schaefer } 7259b69787SGerald Schaefer if (MACHINE_IS_LPAR) 7359b69787SGerald Schaefer continue; 7459b69787SGerald Schaefer } 755b3f683eSPhilipp Hachtmann owner = lp->lock; 7659b69787SGerald Schaefer if (owner) 778b646bd7SMartin Schwidefsky smp_yield_cpu(~owner); 7859b69787SGerald Schaefer local_irq_disable(); 795b3f683eSPhilipp Hachtmann if (_raw_compare_and_swap(&lp->lock, 0, cpu)) 80894cdde2SHisashi Hifumi return; 81894cdde2SHisashi Hifumi local_irq_restore(flags); 82894cdde2SHisashi Hifumi } 83894cdde2SHisashi Hifumi } 840199c4e6SThomas Gleixner EXPORT_SYMBOL(arch_spin_lock_wait_flags); 85894cdde2SHisashi Hifumi 865b3f683eSPhilipp Hachtmann void arch_spin_relax(arch_spinlock_t *lp) 87951f22d5SMartin Schwidefsky { 885b3f683eSPhilipp Hachtmann unsigned int cpu = lp->lock; 8959b69787SGerald Schaefer if (cpu != 0) { 9059b69787SGerald Schaefer if (MACHINE_IS_VM || MACHINE_IS_KVM || 9159b69787SGerald Schaefer !smp_vcpu_scheduled(~cpu)) 928b646bd7SMartin Schwidefsky smp_yield_cpu(~cpu); 933c1fcfe2SMartin Schwidefsky } 9459b69787SGerald Schaefer } 950199c4e6SThomas Gleixner EXPORT_SYMBOL(arch_spin_relax); 963c1fcfe2SMartin Schwidefsky 975b3f683eSPhilipp Hachtmann int arch_spin_trylock_retry(arch_spinlock_t *lp) 985b3f683eSPhilipp Hachtmann { 995b3f683eSPhilipp Hachtmann int count; 1005b3f683eSPhilipp Hachtmann 1015b3f683eSPhilipp Hachtmann for (count = spin_retry; count > 0; count--) { 1025b3f683eSPhilipp Hachtmann if (arch_spin_is_locked(lp)) 1035b3f683eSPhilipp Hachtmann continue; 1045b3f683eSPhilipp Hachtmann if (arch_spin_trylock_once(lp)) 1055b3f683eSPhilipp Hachtmann return 1; 1065b3f683eSPhilipp Hachtmann } 1075b3f683eSPhilipp Hachtmann return 0; 1085b3f683eSPhilipp Hachtmann } 1095b3f683eSPhilipp Hachtmann EXPORT_SYMBOL(arch_spin_trylock_retry); 1105b3f683eSPhilipp Hachtmann 111fb3a6bbcSThomas Gleixner void _raw_read_lock_wait(arch_rwlock_t *rw) 112951f22d5SMartin Schwidefsky { 113951f22d5SMartin Schwidefsky unsigned int old; 114951f22d5SMartin Schwidefsky int count = spin_retry; 115951f22d5SMartin Schwidefsky 116951f22d5SMartin Schwidefsky while (1) { 117951f22d5SMartin Schwidefsky if (count-- <= 0) { 1188b646bd7SMartin Schwidefsky smp_yield(); 119951f22d5SMartin Schwidefsky count = spin_retry; 120951f22d5SMartin Schwidefsky } 121e5931943SThomas Gleixner if (!arch_read_can_lock(rw)) 12296567161SChristian Ehrhardt continue; 123951f22d5SMartin Schwidefsky old = rw->lock & 0x7fffffffU; 1245b3f683eSPhilipp Hachtmann if (_raw_compare_and_swap(&rw->lock, old, old + 1)) 125951f22d5SMartin Schwidefsky return; 126951f22d5SMartin Schwidefsky } 127951f22d5SMartin Schwidefsky } 128951f22d5SMartin Schwidefsky EXPORT_SYMBOL(_raw_read_lock_wait); 129951f22d5SMartin Schwidefsky 130fb3a6bbcSThomas Gleixner void _raw_read_lock_wait_flags(arch_rwlock_t *rw, unsigned long flags) 131ce58ae6fSHeiko Carstens { 132ce58ae6fSHeiko Carstens unsigned int old; 133ce58ae6fSHeiko Carstens int count = spin_retry; 134ce58ae6fSHeiko Carstens 135ce58ae6fSHeiko Carstens local_irq_restore(flags); 136ce58ae6fSHeiko Carstens while (1) { 137ce58ae6fSHeiko Carstens if (count-- <= 0) { 1388b646bd7SMartin Schwidefsky smp_yield(); 139ce58ae6fSHeiko Carstens count = spin_retry; 140ce58ae6fSHeiko Carstens } 141e5931943SThomas Gleixner if (!arch_read_can_lock(rw)) 142ce58ae6fSHeiko Carstens continue; 143ce58ae6fSHeiko Carstens old = rw->lock & 0x7fffffffU; 144ce58ae6fSHeiko Carstens local_irq_disable(); 1455b3f683eSPhilipp Hachtmann if (_raw_compare_and_swap(&rw->lock, old, old + 1)) 146ce58ae6fSHeiko Carstens return; 147ce58ae6fSHeiko Carstens } 148ce58ae6fSHeiko Carstens } 149ce58ae6fSHeiko Carstens EXPORT_SYMBOL(_raw_read_lock_wait_flags); 150ce58ae6fSHeiko Carstens 151fb3a6bbcSThomas Gleixner int _raw_read_trylock_retry(arch_rwlock_t *rw) 152951f22d5SMartin Schwidefsky { 153951f22d5SMartin Schwidefsky unsigned int old; 154951f22d5SMartin Schwidefsky int count = spin_retry; 155951f22d5SMartin Schwidefsky 156951f22d5SMartin Schwidefsky while (count-- > 0) { 157e5931943SThomas Gleixner if (!arch_read_can_lock(rw)) 15896567161SChristian Ehrhardt continue; 159951f22d5SMartin Schwidefsky old = rw->lock & 0x7fffffffU; 1605b3f683eSPhilipp Hachtmann if (_raw_compare_and_swap(&rw->lock, old, old + 1)) 161951f22d5SMartin Schwidefsky return 1; 162951f22d5SMartin Schwidefsky } 163951f22d5SMartin Schwidefsky return 0; 164951f22d5SMartin Schwidefsky } 165951f22d5SMartin Schwidefsky EXPORT_SYMBOL(_raw_read_trylock_retry); 166951f22d5SMartin Schwidefsky 167fb3a6bbcSThomas Gleixner void _raw_write_lock_wait(arch_rwlock_t *rw) 168951f22d5SMartin Schwidefsky { 169951f22d5SMartin Schwidefsky int count = spin_retry; 170951f22d5SMartin Schwidefsky 171951f22d5SMartin Schwidefsky while (1) { 172951f22d5SMartin Schwidefsky if (count-- <= 0) { 1738b646bd7SMartin Schwidefsky smp_yield(); 174951f22d5SMartin Schwidefsky count = spin_retry; 175951f22d5SMartin Schwidefsky } 176e5931943SThomas Gleixner if (!arch_write_can_lock(rw)) 17796567161SChristian Ehrhardt continue; 1785b3f683eSPhilipp Hachtmann if (_raw_compare_and_swap(&rw->lock, 0, 0x80000000)) 179951f22d5SMartin Schwidefsky return; 180951f22d5SMartin Schwidefsky } 181951f22d5SMartin Schwidefsky } 182951f22d5SMartin Schwidefsky EXPORT_SYMBOL(_raw_write_lock_wait); 183951f22d5SMartin Schwidefsky 184fb3a6bbcSThomas Gleixner void _raw_write_lock_wait_flags(arch_rwlock_t *rw, unsigned long flags) 185ce58ae6fSHeiko Carstens { 186ce58ae6fSHeiko Carstens int count = spin_retry; 187ce58ae6fSHeiko Carstens 188ce58ae6fSHeiko Carstens local_irq_restore(flags); 189ce58ae6fSHeiko Carstens while (1) { 190ce58ae6fSHeiko Carstens if (count-- <= 0) { 1918b646bd7SMartin Schwidefsky smp_yield(); 192ce58ae6fSHeiko Carstens count = spin_retry; 193ce58ae6fSHeiko Carstens } 194e5931943SThomas Gleixner if (!arch_write_can_lock(rw)) 195ce58ae6fSHeiko Carstens continue; 196ce58ae6fSHeiko Carstens local_irq_disable(); 1975b3f683eSPhilipp Hachtmann if (_raw_compare_and_swap(&rw->lock, 0, 0x80000000)) 198ce58ae6fSHeiko Carstens return; 199ce58ae6fSHeiko Carstens } 200ce58ae6fSHeiko Carstens } 201ce58ae6fSHeiko Carstens EXPORT_SYMBOL(_raw_write_lock_wait_flags); 202ce58ae6fSHeiko Carstens 203fb3a6bbcSThomas Gleixner int _raw_write_trylock_retry(arch_rwlock_t *rw) 204951f22d5SMartin Schwidefsky { 205951f22d5SMartin Schwidefsky int count = spin_retry; 206951f22d5SMartin Schwidefsky 207951f22d5SMartin Schwidefsky while (count-- > 0) { 208e5931943SThomas Gleixner if (!arch_write_can_lock(rw)) 20996567161SChristian Ehrhardt continue; 2105b3f683eSPhilipp Hachtmann if (_raw_compare_and_swap(&rw->lock, 0, 0x80000000)) 211951f22d5SMartin Schwidefsky return 1; 212951f22d5SMartin Schwidefsky } 213951f22d5SMartin Schwidefsky return 0; 214951f22d5SMartin Schwidefsky } 215951f22d5SMartin Schwidefsky EXPORT_SYMBOL(_raw_write_trylock_retry); 216