File: /usr/src/linux/include/asm-s390x/atomic.h

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     
23     typedef struct { volatile int counter; } atomic_t __attribute__ ((aligned (4)));
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     static __inline__ int atomic_read(atomic_t *v)
38     {
39             int retval;
40             __asm__ __volatile__("bcr      15,0\n\t"
41                                  "l        %0,%1"
42                                  : "=d" (retval) : "m" (*v) );
43             return retval;
44     }
45     
46     static __inline__ void atomic_set(atomic_t *v, int i)
47     {
48             __asm__ __volatile__("st  %1,%0\n\t"
49                                  "bcr 15,0"
50                                  : "=m" (*v) : "d" (i) );
51     }
52     
53     static __inline__ void atomic_add(int i, atomic_t *v)
54     {
55     	int old_val, new_val;
56     	__CS_LOOP(old_val, new_val, v, i, "ar");
57     }
58     
59     static __inline__ int atomic_add_return (int i, atomic_t *v)
60     {
61     	int old_val, new_val;
62     	__CS_LOOP(old_val, new_val, v, i, "ar");
63     	return new_val;
64     }
65     
66     static __inline__ int atomic_add_negative(int i, atomic_t *v)
67     {
68     	int old_val, new_val;
69             __CS_LOOP(old_val, new_val, v, i, "ar");
70             return new_val < 0;
71     }
72     
73     static __inline__ void atomic_sub(int i, atomic_t *v)
74     {
75     	int old_val, new_val;
76     	__CS_LOOP(old_val, new_val, v, i, "sr");
77     }
78     
79     static __inline__ void atomic_inc(volatile atomic_t *v)
80     {
81     	int old_val, new_val;
82     	__CS_LOOP(old_val, new_val, v, 1, "ar");
83     }
84     
85     static __inline__ int atomic_inc_return(volatile atomic_t *v)
86     {
87     	int old_val, new_val;
88     	__CS_LOOP(old_val, new_val, v, 1, "ar");
89             return new_val;
90     }
91     
92     static __inline__ int atomic_inc_and_test(volatile atomic_t *v)
93     {
94     	int old_val, new_val;
95     	__CS_LOOP(old_val, new_val, v, 1, "ar");
96     	return new_val != 0;
97     }
98     
99     static __inline__ void atomic_dec(volatile atomic_t *v)
100     {
101     	int old_val, new_val;
102     	__CS_LOOP(old_val, new_val, v, 1, "sr");
103     }
104     
105     static __inline__ int atomic_dec_return(volatile atomic_t *v)
106     {
107     	int old_val, new_val;
108     	__CS_LOOP(old_val, new_val, v, 1, "sr");
109     	return new_val;
110     }
111     
112     static __inline__ int atomic_dec_and_test(volatile atomic_t *v)
113     {
114     	int old_val, new_val;
115     	__CS_LOOP(old_val, new_val, v, 1, "sr");
116             return new_val == 0;
117     }
118     
119     static __inline__ void atomic_clear_mask(unsigned long mask, atomic_t *v)
120     {
121     	int old_val, new_val;
122     	__CS_LOOP(old_val, new_val, v, ~mask, "nr");
123     }
124     
125     static __inline__ void atomic_set_mask(unsigned long mask, atomic_t *v)
126     {
127     	int old_val, new_val;
128     	__CS_LOOP(old_val, new_val, v, mask, "or");
129     }
130     
131     /*
132       returns 0  if expected_oldval==value in *v ( swap was successful )
133       returns 1  if unsuccessful.
134     */
135     static __inline__ int
136     atomic_compare_and_swap(int expected_oldval,int new_val,atomic_t *v)
137     {
138             int retval;
139     
140             __asm__ __volatile__(
141                     "  lr   0,%2\n"
142                     "  cs   0,%3,0(%1)\n"
143                     "  ipm  %0\n"
144                     "  srl  %0,28\n"
145                     "0:"
146                     : "=&d" (retval)
147                     : "a" (v), "d" (expected_oldval) , "d" (new_val)
148                     : "0", "cc");
149             return retval;
150     }
151     
152     /*
153       Spin till *v = expected_oldval then swap with newval.
154      */
155     static __inline__ void
156     atomic_compare_and_swap_spin(int expected_oldval,int new_val,atomic_t *v)
157     {
158             __asm__ __volatile__(
159                     "0: lr  0,%1\n"
160                     "   cs  0,%2,0(%0)\n"
161                     "   jl  0b\n"
162                     : : "a" (v), "d" (expected_oldval) , "d" (new_val)
163                     : "cc", "0" );
164     }
165     
166     #define atomic_compare_and_swap_debug(where,from,to) \
167     if (atomic_compare_and_swap ((from), (to), (where))) {\
168     	printk (KERN_WARNING"%s/%d atomic counter:%s couldn't be changed from %d(%s) to %d(%s), was %d\n",\
169     		__FILE__,__LINE__,#where,(from),#from,(to),#to,atomic_read (where));\
170             atomic_set(where,(to));\
171     }
172     
173     #define smp_mb__before_atomic_dec()	smp_mb()
174     #define smp_mb__after_atomic_dec()	smp_mb()
175     #define smp_mb__before_atomic_inc()	smp_mb()
176     #define smp_mb__after_atomic_inc()	smp_mb()
177     
178     #endif                                 /* __ARCH_S390_ATOMIC __            */
179