1#ifndef __ARCH_S390_ATOMIC__
2#define __ARCH_S390_ATOMIC__
3
4/*
5 *  include/asm-s390x/atomic.h
6 *
7 *  S390 version
8 *    Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
9 *    Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
10 *               Denis Joseph Barrow
11 *
12 *  Derived from "include/asm-i386/bitops.h"
13 *    Copyright (C) 1992, Linus Torvalds
14 *
15 */
16
17/*
18 * Atomic operations that C can't guarantee us.  Useful for
19 * resource counting etc..
20 * S390 uses 'Compare And Swap' for atomicity in SMP enviroment
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  returns 0  if expected_oldval==value in *v ( swap was successful )
120  returns 1  if unsuccessful.
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  Spin till *v = expected_oldval then swap with newval.
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                                 /* __ARCH_S390_ATOMIC __            */
166