1#!/bin/sh
2# SPDX-License-Identifier: GPL-2.0
3
4ATOMICDIR=$(dirname $0)
5
6. ${ATOMICDIR}/atomic-tbl.sh
7
8#gen_template_fallback(template, meta, pfx, name, sfx, order, atomic, int, args...)
9gen_template_fallback()
10{
11	local template="$1"; shift
12	local meta="$1"; shift
13	local pfx="$1"; shift
14	local name="$1"; shift
15	local sfx="$1"; shift
16	local order="$1"; shift
17	local atomic="$1"; shift
18	local int="$1"; shift
19
20	local ret="$(gen_ret_type "${meta}" "${int}")"
21	local retstmt="$(gen_ret_stmt "${meta}")"
22	local params="$(gen_params "${int}" "${atomic}" "$@")"
23	local args="$(gen_args "$@")"
24
25	. ${template}
26}
27
28#gen_order_fallback(meta, pfx, name, sfx, order, atomic, int, args...)
29gen_order_fallback()
30{
31	local meta="$1"; shift
32	local pfx="$1"; shift
33	local name="$1"; shift
34	local sfx="$1"; shift
35	local order="$1"; shift
36
37	local tmpl_order=${order#_}
38	local tmpl="${ATOMICDIR}/fallbacks/${tmpl_order:-fence}"
39	gen_template_fallback "${tmpl}" "${meta}" "${pfx}" "${name}" "${sfx}" "${order}" "$@"
40}
41
42#gen_proto_fallback(meta, pfx, name, sfx, order, atomic, int, args...)
43gen_proto_fallback()
44{
45	local meta="$1"; shift
46	local pfx="$1"; shift
47	local name="$1"; shift
48	local sfx="$1"; shift
49	local order="$1"; shift
50
51	local tmpl="$(find_fallback_template "${pfx}" "${name}" "${sfx}" "${order}")"
52	gen_template_fallback "${tmpl}" "${meta}" "${pfx}" "${name}" "${sfx}" "${order}" "$@"
53}
54
55#gen_proto_order_variant(meta, pfx, name, sfx, order, atomic, int, args...)
56gen_proto_order_variant()
57{
58	local meta="$1"; shift
59	local pfx="$1"; shift
60	local name="$1"; shift
61	local sfx="$1"; shift
62	local order="$1"; shift
63	local atomic="$1"
64
65	local atomicname="${atomic}_${pfx}${name}${sfx}${order}"
66	local basename="${atomic}_${pfx}${name}${sfx}"
67
68	local template="$(find_fallback_template "${pfx}" "${name}" "${sfx}" "${order}")"
69
70	# Where there is no possible fallback, this order variant is mandatory
71	# and must be provided by arch code. Add a comment to the header to
72	# make this obvious.
73	#
74	# Ideally we'd error on a missing definition, but arch code might
75	# define this order variant as a C function without a preprocessor
76	# symbol.
77	if [ -z ${template} ] && [ -z "${order}" ] && ! meta_has_relaxed "${meta}"; then
78		printf "#define raw_${atomicname} arch_${atomicname}\n\n"
79		return
80	fi
81
82	printf "#if defined(arch_${atomicname})\n"
83	printf "#define raw_${atomicname} arch_${atomicname}\n"
84
85	# Allow FULL/ACQUIRE/RELEASE ops to be defined in terms of RELAXED ops
86	if [ "${order}" != "_relaxed" ] && meta_has_relaxed "${meta}"; then
87		printf "#elif defined(arch_${basename}_relaxed)\n"
88		gen_order_fallback "${meta}" "${pfx}" "${name}" "${sfx}" "${order}" "$@"
89	fi
90
91	# Allow ACQUIRE/RELEASE/RELAXED ops to be defined in terms of FULL ops
92	if [ ! -z "${order}" ]; then
93		printf "#elif defined(arch_${basename})\n"
94		printf "#define raw_${atomicname} arch_${basename}\n"
95	fi
96
97	printf "#else\n"
98	if [ ! -z "${template}" ]; then
99		gen_proto_fallback "${meta}" "${pfx}" "${name}" "${sfx}" "${order}" "$@"
100	else
101		printf "#error \"Unable to define raw_${atomicname}\"\n"
102	fi
103
104	printf "#endif\n\n"
105}
106
107
108#gen_proto_order_variants(meta, pfx, name, sfx, atomic, int, args...)
109gen_proto_order_variants()
110{
111	local meta="$1"; shift
112	local pfx="$1"; shift
113	local name="$1"; shift
114	local sfx="$1"; shift
115	local atomic="$1"
116
117	gen_proto_order_variant "${meta}" "${pfx}" "${name}" "${sfx}" "" "$@"
118
119	if meta_has_acquire "${meta}"; then
120		gen_proto_order_variant "${meta}" "${pfx}" "${name}" "${sfx}" "_acquire" "$@"
121	fi
122
123	if meta_has_release "${meta}"; then
124		gen_proto_order_variant "${meta}" "${pfx}" "${name}" "${sfx}" "_release" "$@"
125	fi
126
127	if meta_has_relaxed "${meta}"; then
128		gen_proto_order_variant "${meta}" "${pfx}" "${name}" "${sfx}" "_relaxed" "$@"
129	fi
130}
131
132#gen_basic_fallbacks(basename)
133gen_basic_fallbacks()
134{
135	local basename="$1"; shift
136cat << EOF
137#define raw_${basename}_acquire arch_${basename}
138#define raw_${basename}_release arch_${basename}
139#define raw_${basename}_relaxed arch_${basename}
140EOF
141}
142
143gen_order_fallbacks()
144{
145	local xchg="$1"; shift
146
147cat <<EOF
148
149#define raw_${xchg}_relaxed arch_${xchg}_relaxed
150
151#ifdef arch_${xchg}_acquire
152#define raw_${xchg}_acquire arch_${xchg}_acquire
153#else
154#define raw_${xchg}_acquire(...) \\
155	__atomic_op_acquire(arch_${xchg}, __VA_ARGS__)
156#endif
157
158#ifdef arch_${xchg}_release
159#define raw_${xchg}_release arch_${xchg}_release
160#else
161#define raw_${xchg}_release(...) \\
162	__atomic_op_release(arch_${xchg}, __VA_ARGS__)
163#endif
164
165#ifdef arch_${xchg}
166#define raw_${xchg} arch_${xchg}
167#else
168#define raw_${xchg}(...) \\
169	__atomic_op_fence(arch_${xchg}, __VA_ARGS__)
170#endif
171
172EOF
173}
174
175gen_xchg_order_fallback()
176{
177	local xchg="$1"; shift
178	local order="$1"; shift
179	local forder="${order:-_fence}"
180
181	printf "#if defined(arch_${xchg}${order})\n"
182	printf "#define raw_${xchg}${order} arch_${xchg}${order}\n"
183
184	if [ "${order}" != "_relaxed" ]; then
185		printf "#elif defined(arch_${xchg}_relaxed)\n"
186		printf "#define raw_${xchg}${order}(...) \\\\\n"
187		printf "	__atomic_op${forder}(arch_${xchg}, __VA_ARGS__)\n"
188	fi
189
190	if [ ! -z "${order}" ]; then
191		printf "#elif defined(arch_${xchg})\n"
192		printf "#define raw_${xchg}${order} arch_${xchg}\n"
193	fi
194
195	printf "#else\n"
196	printf "extern void raw_${xchg}${order}_not_implemented(void);\n"
197	printf "#define raw_${xchg}${order}(...) raw_${xchg}${order}_not_implemented()\n"
198	printf "#endif\n\n"
199}
200
201gen_xchg_fallbacks()
202{
203	local xchg="$1"; shift
204
205	for order in "" "_acquire" "_release" "_relaxed"; do
206		gen_xchg_order_fallback "${xchg}" "${order}"
207	done
208}
209
210gen_try_cmpxchg_fallback()
211{
212	local cmpxchg="$1"; shift;
213	local order="$1"; shift;
214
215cat <<EOF
216#define raw_try_${cmpxchg}${order}(_ptr, _oldp, _new) \\
217({ \\
218	typeof(*(_ptr)) *___op = (_oldp), ___o = *___op, ___r; \\
219	___r = raw_${cmpxchg}${order}((_ptr), ___o, (_new)); \\
220	if (unlikely(___r != ___o)) \\
221		*___op = ___r; \\
222	likely(___r == ___o); \\
223})
224EOF
225}
226
227gen_try_cmpxchg_order_fallback()
228{
229	local cmpxchg="$1"; shift
230	local order="$1"; shift
231	local forder="${order:-_fence}"
232
233	printf "#if defined(arch_try_${cmpxchg}${order})\n"
234	printf "#define raw_try_${cmpxchg}${order} arch_try_${cmpxchg}${order}\n"
235
236	if [ "${order}" != "_relaxed" ]; then
237		printf "#elif defined(arch_try_${cmpxchg}_relaxed)\n"
238		printf "#define raw_try_${cmpxchg}${order}(...) \\\\\n"
239		printf "	__atomic_op${forder}(arch_try_${cmpxchg}, __VA_ARGS__)\n"
240	fi
241
242	if [ ! -z "${order}" ]; then
243		printf "#elif defined(arch_try_${cmpxchg})\n"
244		printf "#define raw_try_${cmpxchg}${order} arch_try_${cmpxchg}\n"
245	fi
246
247	printf "#else\n"
248	gen_try_cmpxchg_fallback "${cmpxchg}" "${order}"
249	printf "#endif\n\n"
250}
251
252gen_try_cmpxchg_fallbacks()
253{
254	local cmpxchg="$1"; shift;
255
256	for order in "" "_acquire" "_release" "_relaxed"; do
257		gen_try_cmpxchg_order_fallback "${cmpxchg}" "${order}"
258	done
259}
260
261gen_cmpxchg_local_fallbacks()
262{
263	local cmpxchg="$1"; shift
264
265	printf "#define raw_${cmpxchg} arch_${cmpxchg}\n\n"
266	printf "#ifdef arch_try_${cmpxchg}\n"
267	printf "#define raw_try_${cmpxchg} arch_try_${cmpxchg}\n"
268	printf "#else\n"
269	gen_try_cmpxchg_fallback "${cmpxchg}" ""
270	printf "#endif\n\n"
271}
272
273cat << EOF
274// SPDX-License-Identifier: GPL-2.0
275
276// Generated by $0
277// DO NOT MODIFY THIS FILE DIRECTLY
278
279#ifndef _LINUX_ATOMIC_FALLBACK_H
280#define _LINUX_ATOMIC_FALLBACK_H
281
282#include <linux/compiler.h>
283
284EOF
285
286for xchg in "xchg" "cmpxchg" "cmpxchg64" "cmpxchg128"; do
287	gen_xchg_fallbacks "${xchg}"
288done
289
290for cmpxchg in "cmpxchg" "cmpxchg64" "cmpxchg128"; do
291	gen_try_cmpxchg_fallbacks "${cmpxchg}"
292done
293
294for cmpxchg in "cmpxchg_local" "cmpxchg64_local" "cmpxchg128_local"; do
295	gen_cmpxchg_local_fallbacks "${cmpxchg}" ""
296done
297
298for cmpxchg in "sync_cmpxchg"; do
299	printf "#define raw_${cmpxchg} arch_${cmpxchg}\n\n"
300done
301
302grep '^[a-z]' "$1" | while read name meta args; do
303	gen_proto "${meta}" "${name}" "atomic" "int" ${args}
304done
305
306cat <<EOF
307#ifdef CONFIG_GENERIC_ATOMIC64
308#include <asm-generic/atomic64.h>
309#endif
310
311EOF
312
313grep '^[a-z]' "$1" | while read name meta args; do
314	gen_proto "${meta}" "${name}" "atomic64" "s64" ${args}
315done
316
317cat <<EOF
318#endif /* _LINUX_ATOMIC_FALLBACK_H */
319EOF
320