xref: /openbmc/linux/arch/s390/lib/spinlock.c (revision 2e4006b3)
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