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