1/*
2 * cmpxchg.h -- forked from asm/atomic.h with this copyright:
3 *
4 * Copyright 2010 Tilera Corporation. All Rights Reserved.
5 *
6 *   This program is free software; you can redistribute it and/or
7 *   modify it under the terms of the GNU General Public License
8 *   as published by the Free Software Foundation, version 2.
9 *
10 *   This program is distributed in the hope that it will be useful, but
11 *   WITHOUT ANY WARRANTY; without even the implied warranty of
12 *   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
13 *   NON INFRINGEMENT.  See the GNU General Public License for
14 *   more details.
15 *
16 */
17
18#ifndef _ASM_TILE_CMPXCHG_H
19#define _ASM_TILE_CMPXCHG_H
20
21#ifndef __ASSEMBLY__
22
23#include <asm/barrier.h>
24
25/* Nonexistent functions intended to cause compile errors. */
26extern void __xchg_called_with_bad_pointer(void)
27	__compiletime_error("Bad argument size for xchg");
28extern void __cmpxchg_called_with_bad_pointer(void)
29	__compiletime_error("Bad argument size for cmpxchg");
30
31#ifndef __tilegx__
32
33/* Note the _atomic_xxx() routines include a final mb(). */
34int _atomic_xchg(int *ptr, int n);
35int _atomic_xchg_add(int *v, int i);
36int _atomic_xchg_add_unless(int *v, int a, int u);
37int _atomic_cmpxchg(int *ptr, int o, int n);
38long long _atomic64_xchg(long long *v, long long n);
39long long _atomic64_xchg_add(long long *v, long long i);
40long long _atomic64_xchg_add_unless(long long *v, long long a, long long u);
41long long _atomic64_cmpxchg(long long *v, long long o, long long n);
42
43#define xchg(ptr, n)							\
44	({								\
45		if (sizeof(*(ptr)) != 4)				\
46			__xchg_called_with_bad_pointer();		\
47		smp_mb();						\
48		(typeof(*(ptr)))_atomic_xchg((int *)(ptr), (int)(n));	\
49	})
50
51#define cmpxchg(ptr, o, n)						\
52	({								\
53		if (sizeof(*(ptr)) != 4)				\
54			__cmpxchg_called_with_bad_pointer();		\
55		smp_mb();						\
56		(typeof(*(ptr)))_atomic_cmpxchg((int *)ptr, (int)o,	\
57						(int)n);		\
58	})
59
60#define xchg64(ptr, n)							\
61	({								\
62		if (sizeof(*(ptr)) != 8)				\
63			__xchg_called_with_bad_pointer();		\
64		smp_mb();						\
65		(typeof(*(ptr)))_atomic64_xchg((long long *)(ptr),	\
66						(long long)(n));	\
67	})
68
69#define cmpxchg64(ptr, o, n)						\
70	({								\
71		if (sizeof(*(ptr)) != 8)				\
72			__cmpxchg_called_with_bad_pointer();		\
73		smp_mb();						\
74		(typeof(*(ptr)))_atomic64_cmpxchg((long long *)ptr,	\
75					(long long)o, (long long)n);	\
76	})
77
78#else
79
80#define xchg(ptr, n)							\
81	({								\
82		typeof(*(ptr)) __x;					\
83		smp_mb();						\
84		switch (sizeof(*(ptr))) {				\
85		case 4:							\
86			__x = (typeof(__x))(unsigned long)		\
87				__insn_exch4((ptr),			\
88					(u32)(unsigned long)(n));	\
89			break;						\
90		case 8:							\
91			__x = (typeof(__x))				\
92				__insn_exch((ptr), (unsigned long)(n));	\
93			break;						\
94		default:						\
95			__xchg_called_with_bad_pointer();		\
96			break;						\
97		}							\
98		smp_mb();						\
99		__x;							\
100	})
101
102#define cmpxchg(ptr, o, n)						\
103	({								\
104		typeof(*(ptr)) __x;					\
105		__insn_mtspr(SPR_CMPEXCH_VALUE, (unsigned long)(o));	\
106		smp_mb();						\
107		switch (sizeof(*(ptr))) {				\
108		case 4:							\
109			__x = (typeof(__x))(unsigned long)		\
110				__insn_cmpexch4((ptr),			\
111					(u32)(unsigned long)(n));	\
112			break;						\
113		case 8:							\
114			__x = (typeof(__x))__insn_cmpexch((ptr),	\
115						(long long)(n));	\
116			break;						\
117		default:						\
118			__cmpxchg_called_with_bad_pointer();		\
119			break;						\
120		}							\
121		smp_mb();						\
122		__x;							\
123	})
124
125#define xchg64 xchg
126#define cmpxchg64 cmpxchg
127
128#endif
129
130#define tas(ptr) xchg((ptr), 1)
131
132#endif /* __ASSEMBLY__ */
133
134#endif /* _ASM_TILE_CMPXCHG_H */
135