1/*
2 *  arch/s390/lib/spinlock.c
3 *    Out of line spinlock code.
4 *
5 *    Copyright (C) IBM Corp. 2004, 2006
6 *    Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com)
7 */
8
9#include <linux/types.h>
10#include <linux/module.h>
11#include <linux/spinlock.h>
12#include <linux/init.h>
13#include <asm/io.h>
14
15int spin_retry = 1000;
16
17/**
18 * spin_retry= parameter
19 */
20static int __init spin_retry_setup(char *str)
21{
22	spin_retry = simple_strtoul(str, &str, 0);
23	return 1;
24}
25__setup("spin_retry=", spin_retry_setup);
26
27static inline void _raw_yield(void)
28{
29	if (MACHINE_HAS_DIAG44)
30		asm volatile("diag 0,0,0x44");
31}
32
33static inline void _raw_yield_cpu(int cpu)
34{
35	if (MACHINE_HAS_DIAG9C)
36		asm volatile("diag %0,0,0x9c"
37			     : : "d" (__cpu_logical_map[cpu]));
38	else
39		_raw_yield();
40}
41
42void _raw_spin_lock_wait(raw_spinlock_t *lp, unsigned int pc)
43{
44	int count = spin_retry;
45	unsigned int cpu = ~smp_processor_id();
46
47	while (1) {
48		if (count-- <= 0) {
49			unsigned int owner = lp->owner_cpu;
50			if (owner != 0)
51				_raw_yield_cpu(~owner);
52			count = spin_retry;
53		}
54		if (__raw_spin_is_locked(lp))
55			continue;
56		if (_raw_compare_and_swap(&lp->owner_cpu, 0, cpu) == 0) {
57			lp->owner_pc = pc;
58			return;
59		}
60	}
61}
62EXPORT_SYMBOL(_raw_spin_lock_wait);
63
64int _raw_spin_trylock_retry(raw_spinlock_t *lp, unsigned int pc)
65{
66	unsigned int cpu = ~smp_processor_id();
67	int count;
68
69	for (count = spin_retry; count > 0; count--) {
70		if (__raw_spin_is_locked(lp))
71			continue;
72		if (_raw_compare_and_swap(&lp->owner_cpu, 0, cpu) == 0) {
73			lp->owner_pc = pc;
74			return 1;
75		}
76	}
77	return 0;
78}
79EXPORT_SYMBOL(_raw_spin_trylock_retry);
80
81void _raw_spin_relax(raw_spinlock_t *lock)
82{
83	unsigned int cpu = lock->owner_cpu;
84	if (cpu != 0)
85		_raw_yield_cpu(~cpu);
86}
87EXPORT_SYMBOL(_raw_spin_relax);
88
89void _raw_read_lock_wait(raw_rwlock_t *rw)
90{
91	unsigned int old;
92	int count = spin_retry;
93
94	while (1) {
95		if (count-- <= 0) {
96			_raw_yield();
97			count = spin_retry;
98		}
99		if (!__raw_read_can_lock(rw))
100			continue;
101		old = rw->lock & 0x7fffffffU;
102		if (_raw_compare_and_swap(&rw->lock, old, old + 1) == old)
103			return;
104	}
105}
106EXPORT_SYMBOL(_raw_read_lock_wait);
107
108int _raw_read_trylock_retry(raw_rwlock_t *rw)
109{
110	unsigned int old;
111	int count = spin_retry;
112
113	while (count-- > 0) {
114		if (!__raw_read_can_lock(rw))
115			continue;
116		old = rw->lock & 0x7fffffffU;
117		if (_raw_compare_and_swap(&rw->lock, old, old + 1) == old)
118			return 1;
119	}
120	return 0;
121}
122EXPORT_SYMBOL(_raw_read_trylock_retry);
123
124void _raw_write_lock_wait(raw_rwlock_t *rw)
125{
126	int count = spin_retry;
127
128	while (1) {
129		if (count-- <= 0) {
130			_raw_yield();
131			count = spin_retry;
132		}
133		if (!__raw_write_can_lock(rw))
134			continue;
135		if (_raw_compare_and_swap(&rw->lock, 0, 0x80000000) == 0)
136			return;
137	}
138}
139EXPORT_SYMBOL(_raw_write_lock_wait);
140
141int _raw_write_trylock_retry(raw_rwlock_t *rw)
142{
143	int count = spin_retry;
144
145	while (count-- > 0) {
146		if (!__raw_write_can_lock(rw))
147			continue;
148		if (_raw_compare_and_swap(&rw->lock, 0, 0x80000000) == 0)
149			return 1;
150	}
151	return 0;
152}
153EXPORT_SYMBOL(_raw_write_trylock_retry);
154