18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
28c2ecf20Sopenharmony_ci#ifndef _ALPHA_CMPXCHG_H
38c2ecf20Sopenharmony_ci#error Do not include xchg.h directly!
48c2ecf20Sopenharmony_ci#else
58c2ecf20Sopenharmony_ci/*
68c2ecf20Sopenharmony_ci * xchg/xchg_local and cmpxchg/cmpxchg_local share the same code
78c2ecf20Sopenharmony_ci * except that local version do not have the expensive memory barrier.
88c2ecf20Sopenharmony_ci * So this file is included twice from asm/cmpxchg.h.
98c2ecf20Sopenharmony_ci */
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci/*
128c2ecf20Sopenharmony_ci * Atomic exchange.
138c2ecf20Sopenharmony_ci * Since it can be used to implement critical sections
148c2ecf20Sopenharmony_ci * it must clobber "memory" (also for interrupts in UP).
158c2ecf20Sopenharmony_ci */
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_cistatic inline unsigned long
188c2ecf20Sopenharmony_ci____xchg(_u8, volatile char *m, unsigned long val)
198c2ecf20Sopenharmony_ci{
208c2ecf20Sopenharmony_ci	unsigned long ret, tmp, addr64;
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ci	__asm__ __volatile__(
238c2ecf20Sopenharmony_ci	"	andnot	%4,7,%3\n"
248c2ecf20Sopenharmony_ci	"	insbl	%1,%4,%1\n"
258c2ecf20Sopenharmony_ci	"1:	ldq_l	%2,0(%3)\n"
268c2ecf20Sopenharmony_ci	"	extbl	%2,%4,%0\n"
278c2ecf20Sopenharmony_ci	"	mskbl	%2,%4,%2\n"
288c2ecf20Sopenharmony_ci	"	or	%1,%2,%2\n"
298c2ecf20Sopenharmony_ci	"	stq_c	%2,0(%3)\n"
308c2ecf20Sopenharmony_ci	"	beq	%2,2f\n"
318c2ecf20Sopenharmony_ci	".subsection 2\n"
328c2ecf20Sopenharmony_ci	"2:	br	1b\n"
338c2ecf20Sopenharmony_ci	".previous"
348c2ecf20Sopenharmony_ci	: "=&r" (ret), "=&r" (val), "=&r" (tmp), "=&r" (addr64)
358c2ecf20Sopenharmony_ci	: "r" ((long)m), "1" (val) : "memory");
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_ci	return ret;
388c2ecf20Sopenharmony_ci}
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_cistatic inline unsigned long
418c2ecf20Sopenharmony_ci____xchg(_u16, volatile short *m, unsigned long val)
428c2ecf20Sopenharmony_ci{
438c2ecf20Sopenharmony_ci	unsigned long ret, tmp, addr64;
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ci	__asm__ __volatile__(
468c2ecf20Sopenharmony_ci	"	andnot	%4,7,%3\n"
478c2ecf20Sopenharmony_ci	"	inswl	%1,%4,%1\n"
488c2ecf20Sopenharmony_ci	"1:	ldq_l	%2,0(%3)\n"
498c2ecf20Sopenharmony_ci	"	extwl	%2,%4,%0\n"
508c2ecf20Sopenharmony_ci	"	mskwl	%2,%4,%2\n"
518c2ecf20Sopenharmony_ci	"	or	%1,%2,%2\n"
528c2ecf20Sopenharmony_ci	"	stq_c	%2,0(%3)\n"
538c2ecf20Sopenharmony_ci	"	beq	%2,2f\n"
548c2ecf20Sopenharmony_ci	".subsection 2\n"
558c2ecf20Sopenharmony_ci	"2:	br	1b\n"
568c2ecf20Sopenharmony_ci	".previous"
578c2ecf20Sopenharmony_ci	: "=&r" (ret), "=&r" (val), "=&r" (tmp), "=&r" (addr64)
588c2ecf20Sopenharmony_ci	: "r" ((long)m), "1" (val) : "memory");
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci	return ret;
618c2ecf20Sopenharmony_ci}
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_cistatic inline unsigned long
648c2ecf20Sopenharmony_ci____xchg(_u32, volatile int *m, unsigned long val)
658c2ecf20Sopenharmony_ci{
668c2ecf20Sopenharmony_ci	unsigned long dummy;
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci	__asm__ __volatile__(
698c2ecf20Sopenharmony_ci	"1:	ldl_l %0,%4\n"
708c2ecf20Sopenharmony_ci	"	bis $31,%3,%1\n"
718c2ecf20Sopenharmony_ci	"	stl_c %1,%2\n"
728c2ecf20Sopenharmony_ci	"	beq %1,2f\n"
738c2ecf20Sopenharmony_ci	".subsection 2\n"
748c2ecf20Sopenharmony_ci	"2:	br 1b\n"
758c2ecf20Sopenharmony_ci	".previous"
768c2ecf20Sopenharmony_ci	: "=&r" (val), "=&r" (dummy), "=m" (*m)
778c2ecf20Sopenharmony_ci	: "rI" (val), "m" (*m) : "memory");
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci	return val;
808c2ecf20Sopenharmony_ci}
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_cistatic inline unsigned long
838c2ecf20Sopenharmony_ci____xchg(_u64, volatile long *m, unsigned long val)
848c2ecf20Sopenharmony_ci{
858c2ecf20Sopenharmony_ci	unsigned long dummy;
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_ci	__asm__ __volatile__(
888c2ecf20Sopenharmony_ci	"1:	ldq_l %0,%4\n"
898c2ecf20Sopenharmony_ci	"	bis $31,%3,%1\n"
908c2ecf20Sopenharmony_ci	"	stq_c %1,%2\n"
918c2ecf20Sopenharmony_ci	"	beq %1,2f\n"
928c2ecf20Sopenharmony_ci	".subsection 2\n"
938c2ecf20Sopenharmony_ci	"2:	br 1b\n"
948c2ecf20Sopenharmony_ci	".previous"
958c2ecf20Sopenharmony_ci	: "=&r" (val), "=&r" (dummy), "=m" (*m)
968c2ecf20Sopenharmony_ci	: "rI" (val), "m" (*m) : "memory");
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci	return val;
998c2ecf20Sopenharmony_ci}
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci/* This function doesn't exist, so you'll get a linker error
1028c2ecf20Sopenharmony_ci   if something tries to do an invalid xchg().  */
1038c2ecf20Sopenharmony_ciextern void __xchg_called_with_bad_pointer(void);
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_cistatic __always_inline unsigned long
1068c2ecf20Sopenharmony_ci____xchg(, volatile void *ptr, unsigned long x, int size)
1078c2ecf20Sopenharmony_ci{
1088c2ecf20Sopenharmony_ci	switch (size) {
1098c2ecf20Sopenharmony_ci		case 1:
1108c2ecf20Sopenharmony_ci			return ____xchg(_u8, ptr, x);
1118c2ecf20Sopenharmony_ci		case 2:
1128c2ecf20Sopenharmony_ci			return ____xchg(_u16, ptr, x);
1138c2ecf20Sopenharmony_ci		case 4:
1148c2ecf20Sopenharmony_ci			return ____xchg(_u32, ptr, x);
1158c2ecf20Sopenharmony_ci		case 8:
1168c2ecf20Sopenharmony_ci			return ____xchg(_u64, ptr, x);
1178c2ecf20Sopenharmony_ci	}
1188c2ecf20Sopenharmony_ci	__xchg_called_with_bad_pointer();
1198c2ecf20Sopenharmony_ci	return x;
1208c2ecf20Sopenharmony_ci}
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_ci/*
1238c2ecf20Sopenharmony_ci * Atomic compare and exchange.  Compare OLD with MEM, if identical,
1248c2ecf20Sopenharmony_ci * store NEW in MEM.  Return the initial value in MEM.  Success is
1258c2ecf20Sopenharmony_ci * indicated by comparing RETURN with OLD.
1268c2ecf20Sopenharmony_ci */
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_cistatic inline unsigned long
1298c2ecf20Sopenharmony_ci____cmpxchg(_u8, volatile char *m, unsigned char old, unsigned char new)
1308c2ecf20Sopenharmony_ci{
1318c2ecf20Sopenharmony_ci	unsigned long prev, tmp, cmp, addr64;
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ci	__asm__ __volatile__(
1348c2ecf20Sopenharmony_ci	"	andnot	%5,7,%4\n"
1358c2ecf20Sopenharmony_ci	"	insbl	%1,%5,%1\n"
1368c2ecf20Sopenharmony_ci	"1:	ldq_l	%2,0(%4)\n"
1378c2ecf20Sopenharmony_ci	"	extbl	%2,%5,%0\n"
1388c2ecf20Sopenharmony_ci	"	cmpeq	%0,%6,%3\n"
1398c2ecf20Sopenharmony_ci	"	beq	%3,2f\n"
1408c2ecf20Sopenharmony_ci	"	mskbl	%2,%5,%2\n"
1418c2ecf20Sopenharmony_ci	"	or	%1,%2,%2\n"
1428c2ecf20Sopenharmony_ci	"	stq_c	%2,0(%4)\n"
1438c2ecf20Sopenharmony_ci	"	beq	%2,3f\n"
1448c2ecf20Sopenharmony_ci	"2:\n"
1458c2ecf20Sopenharmony_ci	".subsection 2\n"
1468c2ecf20Sopenharmony_ci	"3:	br	1b\n"
1478c2ecf20Sopenharmony_ci	".previous"
1488c2ecf20Sopenharmony_ci	: "=&r" (prev), "=&r" (new), "=&r" (tmp), "=&r" (cmp), "=&r" (addr64)
1498c2ecf20Sopenharmony_ci	: "r" ((long)m), "Ir" (old), "1" (new) : "memory");
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci	return prev;
1528c2ecf20Sopenharmony_ci}
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_cistatic inline unsigned long
1558c2ecf20Sopenharmony_ci____cmpxchg(_u16, volatile short *m, unsigned short old, unsigned short new)
1568c2ecf20Sopenharmony_ci{
1578c2ecf20Sopenharmony_ci	unsigned long prev, tmp, cmp, addr64;
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_ci	__asm__ __volatile__(
1608c2ecf20Sopenharmony_ci	"	andnot	%5,7,%4\n"
1618c2ecf20Sopenharmony_ci	"	inswl	%1,%5,%1\n"
1628c2ecf20Sopenharmony_ci	"1:	ldq_l	%2,0(%4)\n"
1638c2ecf20Sopenharmony_ci	"	extwl	%2,%5,%0\n"
1648c2ecf20Sopenharmony_ci	"	cmpeq	%0,%6,%3\n"
1658c2ecf20Sopenharmony_ci	"	beq	%3,2f\n"
1668c2ecf20Sopenharmony_ci	"	mskwl	%2,%5,%2\n"
1678c2ecf20Sopenharmony_ci	"	or	%1,%2,%2\n"
1688c2ecf20Sopenharmony_ci	"	stq_c	%2,0(%4)\n"
1698c2ecf20Sopenharmony_ci	"	beq	%2,3f\n"
1708c2ecf20Sopenharmony_ci	"2:\n"
1718c2ecf20Sopenharmony_ci	".subsection 2\n"
1728c2ecf20Sopenharmony_ci	"3:	br	1b\n"
1738c2ecf20Sopenharmony_ci	".previous"
1748c2ecf20Sopenharmony_ci	: "=&r" (prev), "=&r" (new), "=&r" (tmp), "=&r" (cmp), "=&r" (addr64)
1758c2ecf20Sopenharmony_ci	: "r" ((long)m), "Ir" (old), "1" (new) : "memory");
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_ci	return prev;
1788c2ecf20Sopenharmony_ci}
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_cistatic inline unsigned long
1818c2ecf20Sopenharmony_ci____cmpxchg(_u32, volatile int *m, int old, int new)
1828c2ecf20Sopenharmony_ci{
1838c2ecf20Sopenharmony_ci	unsigned long prev, cmp;
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_ci	__asm__ __volatile__(
1868c2ecf20Sopenharmony_ci	"1:	ldl_l %0,%5\n"
1878c2ecf20Sopenharmony_ci	"	cmpeq %0,%3,%1\n"
1888c2ecf20Sopenharmony_ci	"	beq %1,2f\n"
1898c2ecf20Sopenharmony_ci	"	mov %4,%1\n"
1908c2ecf20Sopenharmony_ci	"	stl_c %1,%2\n"
1918c2ecf20Sopenharmony_ci	"	beq %1,3f\n"
1928c2ecf20Sopenharmony_ci	"2:\n"
1938c2ecf20Sopenharmony_ci	".subsection 2\n"
1948c2ecf20Sopenharmony_ci	"3:	br 1b\n"
1958c2ecf20Sopenharmony_ci	".previous"
1968c2ecf20Sopenharmony_ci	: "=&r"(prev), "=&r"(cmp), "=m"(*m)
1978c2ecf20Sopenharmony_ci	: "r"((long) old), "r"(new), "m"(*m) : "memory");
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_ci	return prev;
2008c2ecf20Sopenharmony_ci}
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_cistatic inline unsigned long
2038c2ecf20Sopenharmony_ci____cmpxchg(_u64, volatile long *m, unsigned long old, unsigned long new)
2048c2ecf20Sopenharmony_ci{
2058c2ecf20Sopenharmony_ci	unsigned long prev, cmp;
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_ci	__asm__ __volatile__(
2088c2ecf20Sopenharmony_ci	"1:	ldq_l %0,%5\n"
2098c2ecf20Sopenharmony_ci	"	cmpeq %0,%3,%1\n"
2108c2ecf20Sopenharmony_ci	"	beq %1,2f\n"
2118c2ecf20Sopenharmony_ci	"	mov %4,%1\n"
2128c2ecf20Sopenharmony_ci	"	stq_c %1,%2\n"
2138c2ecf20Sopenharmony_ci	"	beq %1,3f\n"
2148c2ecf20Sopenharmony_ci	"2:\n"
2158c2ecf20Sopenharmony_ci	".subsection 2\n"
2168c2ecf20Sopenharmony_ci	"3:	br 1b\n"
2178c2ecf20Sopenharmony_ci	".previous"
2188c2ecf20Sopenharmony_ci	: "=&r"(prev), "=&r"(cmp), "=m"(*m)
2198c2ecf20Sopenharmony_ci	: "r"((long) old), "r"(new), "m"(*m) : "memory");
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_ci	return prev;
2228c2ecf20Sopenharmony_ci}
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_ci/* This function doesn't exist, so you'll get a linker error
2258c2ecf20Sopenharmony_ci   if something tries to do an invalid cmpxchg().  */
2268c2ecf20Sopenharmony_ciextern void __cmpxchg_called_with_bad_pointer(void);
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_cistatic __always_inline unsigned long
2298c2ecf20Sopenharmony_ci____cmpxchg(, volatile void *ptr, unsigned long old, unsigned long new,
2308c2ecf20Sopenharmony_ci	      int size)
2318c2ecf20Sopenharmony_ci{
2328c2ecf20Sopenharmony_ci	switch (size) {
2338c2ecf20Sopenharmony_ci		case 1:
2348c2ecf20Sopenharmony_ci			return ____cmpxchg(_u8, ptr, old, new);
2358c2ecf20Sopenharmony_ci		case 2:
2368c2ecf20Sopenharmony_ci			return ____cmpxchg(_u16, ptr, old, new);
2378c2ecf20Sopenharmony_ci		case 4:
2388c2ecf20Sopenharmony_ci			return ____cmpxchg(_u32, ptr, old, new);
2398c2ecf20Sopenharmony_ci		case 8:
2408c2ecf20Sopenharmony_ci			return ____cmpxchg(_u64, ptr, old, new);
2418c2ecf20Sopenharmony_ci	}
2428c2ecf20Sopenharmony_ci	__cmpxchg_called_with_bad_pointer();
2438c2ecf20Sopenharmony_ci	return old;
2448c2ecf20Sopenharmony_ci}
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_ci#endif
247