Subversion Repositories Kolibri OS

Rev

Rev 6082 | Rev 6659 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
5270 serge 1
#ifndef _ASM_X86_ATOMIC64_32_H
2
#define _ASM_X86_ATOMIC64_32_H
3
 
4
#include 
5
#include 
6
#include 
6082 serge 7
#include 
5270 serge 8
 
9
/* An 64bit atomic type */
10
 
11
typedef struct {
12
	u64 __aligned(8) counter;
13
} atomic64_t;
14
 
15
#define ATOMIC64_INIT(val)	{ (val) }
16
 
17
#define __ATOMIC64_DECL(sym) void atomic64_##sym(atomic64_t *, ...)
18
#ifndef ATOMIC64_EXPORT
19
#define ATOMIC64_DECL_ONE __ATOMIC64_DECL
20
#else
21
#define ATOMIC64_DECL_ONE(sym) __ATOMIC64_DECL(sym); \
22
	ATOMIC64_EXPORT(atomic64_##sym)
23
#endif
24
 
25
#ifdef CONFIG_X86_CMPXCHG64
26
#define __alternative_atomic64(f, g, out, in...) \
27
	asm volatile("call %P[func]" \
28
		     : out : [func] "i" (atomic64_##g##_cx8), ## in)
29
 
30
#define ATOMIC64_DECL(sym) ATOMIC64_DECL_ONE(sym##_cx8)
31
#else
32
#define __alternative_atomic64(f, g, out, in...) \
33
	alternative_call(atomic64_##f##_386, atomic64_##g##_cx8, \
34
			 X86_FEATURE_CX8, ASM_OUTPUT2(out), ## in)
35
 
36
#define ATOMIC64_DECL(sym) ATOMIC64_DECL_ONE(sym##_cx8); \
37
	ATOMIC64_DECL_ONE(sym##_386)
38
 
39
ATOMIC64_DECL_ONE(add_386);
40
ATOMIC64_DECL_ONE(sub_386);
41
ATOMIC64_DECL_ONE(inc_386);
42
ATOMIC64_DECL_ONE(dec_386);
43
#endif
44
 
45
#define alternative_atomic64(f, out, in...) \
46
	__alternative_atomic64(f, f, ASM_OUTPUT2(out), ## in)
47
 
48
ATOMIC64_DECL(read);
49
ATOMIC64_DECL(set);
50
ATOMIC64_DECL(xchg);
51
ATOMIC64_DECL(add_return);
52
ATOMIC64_DECL(sub_return);
53
ATOMIC64_DECL(inc_return);
54
ATOMIC64_DECL(dec_return);
55
ATOMIC64_DECL(dec_if_positive);
56
ATOMIC64_DECL(inc_not_zero);
57
ATOMIC64_DECL(add_unless);
58
 
59
#undef ATOMIC64_DECL
60
#undef ATOMIC64_DECL_ONE
61
#undef __ATOMIC64_DECL
62
#undef ATOMIC64_EXPORT
63
 
64
/**
65
 * atomic64_cmpxchg - cmpxchg atomic64 variable
66
 * @v: pointer to type atomic64_t
67
 * @o: expected value
68
 * @n: new value
69
 *
70
 * Atomically sets @v to @n if it was equal to @o and returns
71
 * the old value.
72
 */
73
 
74
static inline long long atomic64_cmpxchg(atomic64_t *v, long long o, long long n)
75
{
76
	return cmpxchg64(&v->counter, o, n);
77
}
78
 
79
/**
80
 * atomic64_xchg - xchg atomic64 variable
81
 * @v: pointer to type atomic64_t
82
 * @n: value to assign
83
 *
84
 * Atomically xchgs the value of @v to @n and returns
85
 * the old value.
86
 */
87
static inline long long atomic64_xchg(atomic64_t *v, long long n)
88
{
89
    long long o;
90
    unsigned high = (unsigned)(n >> 32);
91
    unsigned low = (unsigned)n;
92
 
93
    asm volatile(
94
    "1:                 \n\t"
95
    "cmpxchg8b (%%esi)  \n\t"
96
    "jnz 1b             \n\t"
97
    :"=&A" (o)
98
    :"S" (v), "b" (low), "c" (high)
99
    : "memory", "cc");
100
    return o;
101
}
102
 
103
/**
104
 * atomic64_set - set atomic64 variable
105
 * @v: pointer to type atomic64_t
106
 * @i: value to assign
107
 *
108
 * Atomically sets the value of @v to @n.
109
 */
110
static inline void atomic64_set(atomic64_t *v, long long i)
111
{
112
    __sync_lock_test_and_set((long long *)&v->counter, i);
113
}
114
 
115
/**
116
 * atomic64_read - read atomic64 variable
117
 * @v: pointer to type atomic64_t
118
 *
119
 * Atomically reads the value of @v and returns it.
120
 */
121
static inline long long atomic64_read(const atomic64_t *v)
122
{
123
    return __sync_fetch_and_add( (long long *)&v->counter, 0);
124
}
125
 
126
/**
127
 * atomic64_add_return - add and return
128
 * @i: integer value to add
129
 * @v: pointer to type atomic64_t
130
 *
131
 * Atomically adds @i to @v and returns @i + *@v
132
 */
133
static inline long long atomic64_add_return(long long i, atomic64_t *v)
134
{
135
	alternative_atomic64(add_return,
136
			     ASM_OUTPUT2("+A" (i), "+c" (v)),
137
			     ASM_NO_INPUT_CLOBBER("memory"));
138
	return i;
139
}
140
 
141
/*
142
 * Other variants with different arithmetic operators:
143
 */
144
static inline long long atomic64_sub_return(long long i, atomic64_t *v)
145
{
146
	alternative_atomic64(sub_return,
147
			     ASM_OUTPUT2("+A" (i), "+c" (v)),
148
			     ASM_NO_INPUT_CLOBBER("memory"));
149
	return i;
150
}
151
 
152
static inline long long atomic64_inc_return(atomic64_t *v)
153
{
154
	long long a;
155
	alternative_atomic64(inc_return, "=&A" (a),
156
			     "S" (v) : "memory", "ecx");
157
	return a;
158
}
159
 
160
static inline long long atomic64_dec_return(atomic64_t *v)
161
{
162
	long long a;
163
	alternative_atomic64(dec_return, "=&A" (a),
164
			     "S" (v) : "memory", "ecx");
165
	return a;
166
}
167
 
168
/**
169
 * atomic64_add - add integer to atomic64 variable
170
 * @i: integer value to add
171
 * @v: pointer to type atomic64_t
172
 *
173
 * Atomically adds @i to @v.
174
 */
175
static inline long long atomic64_add(long long i, atomic64_t *v)
176
{
177
	__alternative_atomic64(add, add_return,
178
			       ASM_OUTPUT2("+A" (i), "+c" (v)),
179
			       ASM_NO_INPUT_CLOBBER("memory"));
180
	return i;
181
}
182
 
183
/**
184
 * atomic64_sub - subtract the atomic64 variable
185
 * @i: integer value to subtract
186
 * @v: pointer to type atomic64_t
187
 *
188
 * Atomically subtracts @i from @v.
189
 */
190
static inline long long atomic64_sub(long long i, atomic64_t *v)
191
{
192
	__alternative_atomic64(sub, sub_return,
193
			       ASM_OUTPUT2("+A" (i), "+c" (v)),
194
			       ASM_NO_INPUT_CLOBBER("memory"));
195
	return i;
196
}
197
 
198
/**
199
 * atomic64_sub_and_test - subtract value from variable and test result
200
 * @i: integer value to subtract
201
 * @v: pointer to type atomic64_t
202
 *
203
 * Atomically subtracts @i from @v and returns
204
 * true if the result is zero, or false for all
205
 * other cases.
206
 */
207
static inline int atomic64_sub_and_test(long long i, atomic64_t *v)
208
{
209
	return atomic64_sub_return(i, v) == 0;
210
}
211
 
212
/**
213
 * atomic64_inc - increment atomic64 variable
214
 * @v: pointer to type atomic64_t
215
 *
216
 * Atomically increments @v by 1.
217
 */
218
static inline void atomic64_inc(atomic64_t *v)
219
{
220
	__alternative_atomic64(inc, inc_return, /* no output */,
221
			       "S" (v) : "memory", "eax", "ecx", "edx");
222
}
223
 
224
/**
225
 * atomic64_dec - decrement atomic64 variable
226
 * @v: pointer to type atomic64_t
227
 *
228
 * Atomically decrements @v by 1.
229
 */
230
static inline void atomic64_dec(atomic64_t *v)
231
{
232
	__alternative_atomic64(dec, dec_return, /* no output */,
233
			       "S" (v) : "memory", "eax", "ecx", "edx");
234
}
235
 
236
/**
237
 * atomic64_dec_and_test - decrement and test
238
 * @v: pointer to type atomic64_t
239
 *
240
 * Atomically decrements @v by 1 and
241
 * returns true if the result is 0, or false for all other
242
 * cases.
243
 */
244
static inline int atomic64_dec_and_test(atomic64_t *v)
245
{
246
	return atomic64_dec_return(v) == 0;
247
}
248
 
249
/**
250
 * atomic64_inc_and_test - increment and test
251
 * @v: pointer to type atomic64_t
252
 *
253
 * Atomically increments @v by 1
254
 * and returns true if the result is zero, or false for all
255
 * other cases.
256
 */
257
static inline int atomic64_inc_and_test(atomic64_t *v)
258
{
259
	return atomic64_inc_return(v) == 0;
260
}
261
 
262
/**
263
 * atomic64_add_negative - add and test if negative
264
 * @i: integer value to add
265
 * @v: pointer to type atomic64_t
266
 *
267
 * Atomically adds @i to @v and returns true
268
 * if the result is negative, or false when
269
 * result is greater than or equal to zero.
270
 */
271
static inline int atomic64_add_negative(long long i, atomic64_t *v)
272
{
273
	return atomic64_add_return(i, v) < 0;
274
}
275
 
276
/**
277
 * atomic64_add_unless - add unless the number is a given value
278
 * @v: pointer of type atomic64_t
279
 * @a: the amount to add to v...
280
 * @u: ...unless v is equal to u.
281
 *
282
 * Atomically adds @a to @v, so long as it was not @u.
283
 * Returns non-zero if the add was done, zero otherwise.
284
 */
285
static inline int atomic64_add_unless(atomic64_t *v, long long a, long long u)
286
{
287
	unsigned low = (unsigned)u;
288
	unsigned high = (unsigned)(u >> 32);
289
	alternative_atomic64(add_unless,
290
			     ASM_OUTPUT2("+A" (a), "+c" (low), "+D" (high)),
291
			     "S" (v) : "memory");
292
	return (int)a;
293
}
294
 
295
 
296
static inline int atomic64_inc_not_zero(atomic64_t *v)
297
{
298
	int r;
299
	alternative_atomic64(inc_not_zero, "=&a" (r),
300
			     "S" (v) : "ecx", "edx", "memory");
301
	return r;
302
}
303
 
304
static inline long long atomic64_dec_if_positive(atomic64_t *v)
305
{
306
	long long r;
307
	alternative_atomic64(dec_if_positive, "=&A" (r),
308
			     "S" (v) : "ecx", "memory");
309
	return r;
310
}
311
 
312
#undef alternative_atomic64
313
#undef __alternative_atomic64
314
 
6588 serge 315
#define ATOMIC64_OP(op, c_op)						\
316
static inline void atomic64_##op(long long i, atomic64_t *v)		\
317
{									\
318
	long long old, c = 0;						\
319
	while ((old = atomic64_cmpxchg(v, c, c c_op i)) != c)		\
320
		c = old;						\
321
}
322
 
323
ATOMIC64_OP(and, &)
324
ATOMIC64_OP(or, |)
325
ATOMIC64_OP(xor, ^)
326
 
327
#undef ATOMIC64_OP
328
 
5270 serge 329
#endif /* _ASM_X86_ATOMIC64_32_H */