summaryrefslogtreecommitdiffstats
path: root/arch/s390/lib
diff options
context:
space:
mode:
Diffstat (limited to 'arch/s390/lib')
-rw-r--r--arch/s390/lib/spinlock.c81
1 files changed, 47 insertions, 34 deletions
diff --git a/arch/s390/lib/spinlock.c b/arch/s390/lib/spinlock.c
index 1dd282c742b5..5b0e445bc3f3 100644
--- a/arch/s390/lib/spinlock.c
+++ b/arch/s390/lib/spinlock.c
@@ -31,23 +31,31 @@ void arch_spin_lock_wait(arch_spinlock_t *lp)
int count;
while (1) {
- owner = lp->lock;
- if (!owner || smp_vcpu_scheduled(~owner)) {
- count = spin_retry;
- do {
- if (arch_spin_is_locked(lp))
- continue;
- if (_raw_compare_and_swap(&lp->lock, 0, cpu))
- return;
- } while (count-- > 0);
- if (MACHINE_IS_LPAR)
- continue;
+ owner = ACCESS_ONCE(lp->lock);
+ /* Try to get the lock if it is free. */
+ if (!owner) {
+ if (_raw_compare_and_swap(&lp->lock, 0, cpu))
+ return;
+ continue;
}
- owner = lp->lock;
- if (owner)
+ /* Check if the lock owner is running. */
+ if (!smp_vcpu_scheduled(~owner)) {
+ smp_yield_cpu(~owner);
+ continue;
+ }
+ /* Loop for a while on the lock value. */
+ count = spin_retry;
+ do {
+ owner = ACCESS_ONCE(lp->lock);
+ } while (owner && count-- > 0);
+ if (!owner)
+ continue;
+ /*
+ * For multiple layers of hypervisors, e.g. z/VM + LPAR
+ * yield the CPU if the lock is still unavailable.
+ */
+ if (!MACHINE_IS_LPAR)
smp_yield_cpu(~owner);
- if (_raw_compare_and_swap(&lp->lock, 0, cpu))
- return;
}
}
EXPORT_SYMBOL(arch_spin_lock_wait);
@@ -60,27 +68,32 @@ void arch_spin_lock_wait_flags(arch_spinlock_t *lp, unsigned long flags)
local_irq_restore(flags);
while (1) {
- owner = lp->lock;
- if (!owner || smp_vcpu_scheduled(~owner)) {
- count = spin_retry;
- do {
- if (arch_spin_is_locked(lp))
- continue;
- local_irq_disable();
- if (_raw_compare_and_swap(&lp->lock, 0, cpu))
- return;
- local_irq_restore(flags);
- } while (count-- > 0);
- if (MACHINE_IS_LPAR)
- continue;
+ owner = ACCESS_ONCE(lp->lock);
+ /* Try to get the lock if it is free. */
+ if (!owner) {
+ local_irq_disable();
+ if (_raw_compare_and_swap(&lp->lock, 0, cpu))
+ return;
+ local_irq_restore(flags);
}
- owner = lp->lock;
- if (owner)
+ /* Check if the lock owner is running. */
+ if (!smp_vcpu_scheduled(~owner)) {
+ smp_yield_cpu(~owner);
+ continue;
+ }
+ /* Loop for a while on the lock value. */
+ count = spin_retry;
+ do {
+ owner = ACCESS_ONCE(lp->lock);
+ } while (owner && count-- > 0);
+ if (!owner)
+ continue;
+ /*
+ * For multiple layers of hypervisors, e.g. z/VM + LPAR
+ * yield the CPU if the lock is still unavailable.
+ */
+ if (!MACHINE_IS_LPAR)
smp_yield_cpu(~owner);
- local_irq_disable();
- if (_raw_compare_and_swap(&lp->lock, 0, cpu))
- return;
- local_irq_restore(flags);
}
}
EXPORT_SYMBOL(arch_spin_lock_wait_flags);