xref: /openbmc/linux/arch/s390/lib/spinlock.c (revision 5b3f683e)
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;
303c1fcfe2SMartin Schwidefsky 	unsigned int cpu = ~smp_processor_id();
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;
57894cdde2SHisashi Hifumi 	unsigned int cpu = ~smp_processor_id();
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