1#ifndef __ARCH_S390_ATOMIC__
2#define __ARCH_S390_ATOMIC__
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23typedef struct { volatile int counter; } __attribute__ ((aligned (4))) atomic_t;
24#define ATOMIC_INIT(i) { (i) }
25
26#define atomic_eieio() __asm__ __volatile__ ("BCR 15,0")
27
28#define __CS_LOOP(old_val, new_val, ptr, op_val, op_string) \
29 __asm__ __volatile__(" l %0,0(%2)\n" \
30 "0: lr %1,%0\n" \
31 op_string " %1,%3\n" \
32 " cs %0,%1,0(%2)\n" \
33 " jl 0b" \
34 : "=&d" (old_val), "=&d" (new_val) \
35 : "a" (ptr), "d" (op_val) : "cc" );
36
37#define atomic_read(v) ((v)->counter)
38#define atomic_set(v,i) (((v)->counter) = (i))
39
40static __inline__ void atomic_add(int i, atomic_t *v)
41{
42 int old_val, new_val;
43 __CS_LOOP(old_val, new_val, v, i, "ar");
44}
45
46static __inline__ int atomic_add_return (int i, atomic_t *v)
47{
48 int old_val, new_val;
49 __CS_LOOP(old_val, new_val, v, i, "ar");
50 return new_val;
51}
52
53static __inline__ int atomic_add_negative(int i, atomic_t *v)
54{
55 int old_val, new_val;
56 __CS_LOOP(old_val, new_val, v, i, "ar");
57 return new_val < 0;
58}
59
60static __inline__ void atomic_sub(int i, atomic_t *v)
61{
62 int old_val, new_val;
63 __CS_LOOP(old_val, new_val, v, i, "sr");
64}
65
66static __inline__ void atomic_inc(volatile atomic_t *v)
67{
68 int old_val, new_val;
69 __CS_LOOP(old_val, new_val, v, 1, "ar");
70}
71
72static __inline__ int atomic_inc_return(volatile atomic_t *v)
73{
74 int old_val, new_val;
75 __CS_LOOP(old_val, new_val, v, 1, "ar");
76 return new_val;
77}
78
79static __inline__ int atomic_inc_and_test(volatile atomic_t *v)
80{
81 int old_val, new_val;
82 __CS_LOOP(old_val, new_val, v, 1, "ar");
83 return new_val != 0;
84}
85
86static __inline__ void atomic_dec(volatile atomic_t *v)
87{
88 int old_val, new_val;
89 __CS_LOOP(old_val, new_val, v, 1, "sr");
90}
91
92static __inline__ int atomic_dec_return(volatile atomic_t *v)
93{
94 int old_val, new_val;
95 __CS_LOOP(old_val, new_val, v, 1, "sr");
96 return new_val;
97}
98
99static __inline__ int atomic_dec_and_test(volatile atomic_t *v)
100{
101 int old_val, new_val;
102 __CS_LOOP(old_val, new_val, v, 1, "sr");
103 return new_val == 0;
104}
105
106static __inline__ void atomic_clear_mask(unsigned long mask, atomic_t *v)
107{
108 int old_val, new_val;
109 __CS_LOOP(old_val, new_val, v, ~mask, "nr");
110}
111
112static __inline__ void atomic_set_mask(unsigned long mask, atomic_t *v)
113{
114 int old_val, new_val;
115 __CS_LOOP(old_val, new_val, v, mask, "or");
116}
117
118
119
120
121
122static __inline__ int
123atomic_compare_and_swap(int expected_oldval,int new_val,atomic_t *v)
124{
125 int retval;
126
127 __asm__ __volatile__(
128 " lr 0,%2\n"
129 " cs 0,%3,0(%1)\n"
130 " ipm %0\n"
131 " srl %0,28\n"
132 "0:"
133 : "=&d" (retval)
134 : "a" (v), "d" (expected_oldval) , "d" (new_val)
135 : "0", "cc");
136 return retval;
137}
138
139
140
141
142static __inline__ void
143atomic_compare_and_swap_spin(int expected_oldval,int new_val,atomic_t *v)
144{
145 __asm__ __volatile__(
146 "0: lr 0,%1\n"
147 " cs 0,%2,0(%0)\n"
148 " jl 0b\n"
149 : : "a" (v), "d" (expected_oldval) , "d" (new_val)
150 : "cc", "0" );
151}
152
153#define atomic_compare_and_swap_debug(where,from,to) \
154if (atomic_compare_and_swap ((from), (to), (where))) {\
155 printk (KERN_WARNING"%s/%d atomic counter:%s couldn't be changed from %d(%s) to %d(%s), was %d\n",\
156 __FILE__,__LINE__,#where,(from),#from,(to),#to,atomic_read (where));\
157 atomic_set(where,(to));\
158}
159
160#define smp_mb__before_atomic_dec() smp_mb()
161#define smp_mb__after_atomic_dec() smp_mb()
162#define smp_mb__before_atomic_inc() smp_mb()
163#define smp_mb__after_atomic_inc() smp_mb()
164
165#endif
166
167