18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * include/asm-xtensa/atomic.h 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Atomic operations that C can't guarantee us. Useful for resource counting.. 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General Public 78c2ecf20Sopenharmony_ci * License. See the file "COPYING" in the main directory of this archive 88c2ecf20Sopenharmony_ci * for more details. 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci * Copyright (C) 2001 - 2008 Tensilica Inc. 118c2ecf20Sopenharmony_ci */ 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#ifndef _XTENSA_ATOMIC_H 148c2ecf20Sopenharmony_ci#define _XTENSA_ATOMIC_H 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#include <linux/stringify.h> 178c2ecf20Sopenharmony_ci#include <linux/types.h> 188c2ecf20Sopenharmony_ci#include <asm/processor.h> 198c2ecf20Sopenharmony_ci#include <asm/cmpxchg.h> 208c2ecf20Sopenharmony_ci#include <asm/barrier.h> 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci/* 238c2ecf20Sopenharmony_ci * This Xtensa implementation assumes that the right mechanism 248c2ecf20Sopenharmony_ci * for exclusion is for locking interrupts to level EXCM_LEVEL. 258c2ecf20Sopenharmony_ci * 268c2ecf20Sopenharmony_ci * Locking interrupts looks like this: 278c2ecf20Sopenharmony_ci * 288c2ecf20Sopenharmony_ci * rsil a15, TOPLEVEL 298c2ecf20Sopenharmony_ci * <code> 308c2ecf20Sopenharmony_ci * wsr a15, PS 318c2ecf20Sopenharmony_ci * rsync 328c2ecf20Sopenharmony_ci * 338c2ecf20Sopenharmony_ci * Note that a15 is used here because the register allocation 348c2ecf20Sopenharmony_ci * done by the compiler is not guaranteed and a window overflow 358c2ecf20Sopenharmony_ci * may not occur between the rsil and wsr instructions. By using 368c2ecf20Sopenharmony_ci * a15 in the rsil, the machine is guaranteed to be in a state 378c2ecf20Sopenharmony_ci * where no register reference will cause an overflow. 388c2ecf20Sopenharmony_ci */ 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci/** 418c2ecf20Sopenharmony_ci * atomic_read - read atomic variable 428c2ecf20Sopenharmony_ci * @v: pointer of type atomic_t 438c2ecf20Sopenharmony_ci * 448c2ecf20Sopenharmony_ci * Atomically reads the value of @v. 458c2ecf20Sopenharmony_ci */ 468c2ecf20Sopenharmony_ci#define atomic_read(v) READ_ONCE((v)->counter) 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci/** 498c2ecf20Sopenharmony_ci * atomic_set - set atomic variable 508c2ecf20Sopenharmony_ci * @v: pointer of type atomic_t 518c2ecf20Sopenharmony_ci * @i: required value 528c2ecf20Sopenharmony_ci * 538c2ecf20Sopenharmony_ci * Atomically sets the value of @v to @i. 548c2ecf20Sopenharmony_ci */ 558c2ecf20Sopenharmony_ci#define atomic_set(v,i) WRITE_ONCE((v)->counter, (i)) 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci#if XCHAL_HAVE_EXCLUSIVE 588c2ecf20Sopenharmony_ci#define ATOMIC_OP(op) \ 598c2ecf20Sopenharmony_cistatic inline void atomic_##op(int i, atomic_t *v) \ 608c2ecf20Sopenharmony_ci{ \ 618c2ecf20Sopenharmony_ci unsigned long tmp; \ 628c2ecf20Sopenharmony_ci int result; \ 638c2ecf20Sopenharmony_ci \ 648c2ecf20Sopenharmony_ci __asm__ __volatile__( \ 658c2ecf20Sopenharmony_ci "1: l32ex %[tmp], %[addr]\n" \ 668c2ecf20Sopenharmony_ci " " #op " %[result], %[tmp], %[i]\n" \ 678c2ecf20Sopenharmony_ci " s32ex %[result], %[addr]\n" \ 688c2ecf20Sopenharmony_ci " getex %[result]\n" \ 698c2ecf20Sopenharmony_ci " beqz %[result], 1b\n" \ 708c2ecf20Sopenharmony_ci : [result] "=&a" (result), [tmp] "=&a" (tmp) \ 718c2ecf20Sopenharmony_ci : [i] "a" (i), [addr] "a" (v) \ 728c2ecf20Sopenharmony_ci : "memory" \ 738c2ecf20Sopenharmony_ci ); \ 748c2ecf20Sopenharmony_ci} \ 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci#define ATOMIC_OP_RETURN(op) \ 778c2ecf20Sopenharmony_cistatic inline int atomic_##op##_return(int i, atomic_t *v) \ 788c2ecf20Sopenharmony_ci{ \ 798c2ecf20Sopenharmony_ci unsigned long tmp; \ 808c2ecf20Sopenharmony_ci int result; \ 818c2ecf20Sopenharmony_ci \ 828c2ecf20Sopenharmony_ci __asm__ __volatile__( \ 838c2ecf20Sopenharmony_ci "1: l32ex %[tmp], %[addr]\n" \ 848c2ecf20Sopenharmony_ci " " #op " %[result], %[tmp], %[i]\n" \ 858c2ecf20Sopenharmony_ci " s32ex %[result], %[addr]\n" \ 868c2ecf20Sopenharmony_ci " getex %[result]\n" \ 878c2ecf20Sopenharmony_ci " beqz %[result], 1b\n" \ 888c2ecf20Sopenharmony_ci " " #op " %[result], %[tmp], %[i]\n" \ 898c2ecf20Sopenharmony_ci : [result] "=&a" (result), [tmp] "=&a" (tmp) \ 908c2ecf20Sopenharmony_ci : [i] "a" (i), [addr] "a" (v) \ 918c2ecf20Sopenharmony_ci : "memory" \ 928c2ecf20Sopenharmony_ci ); \ 938c2ecf20Sopenharmony_ci \ 948c2ecf20Sopenharmony_ci return result; \ 958c2ecf20Sopenharmony_ci} 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci#define ATOMIC_FETCH_OP(op) \ 988c2ecf20Sopenharmony_cistatic inline int atomic_fetch_##op(int i, atomic_t *v) \ 998c2ecf20Sopenharmony_ci{ \ 1008c2ecf20Sopenharmony_ci unsigned long tmp; \ 1018c2ecf20Sopenharmony_ci int result; \ 1028c2ecf20Sopenharmony_ci \ 1038c2ecf20Sopenharmony_ci __asm__ __volatile__( \ 1048c2ecf20Sopenharmony_ci "1: l32ex %[tmp], %[addr]\n" \ 1058c2ecf20Sopenharmony_ci " " #op " %[result], %[tmp], %[i]\n" \ 1068c2ecf20Sopenharmony_ci " s32ex %[result], %[addr]\n" \ 1078c2ecf20Sopenharmony_ci " getex %[result]\n" \ 1088c2ecf20Sopenharmony_ci " beqz %[result], 1b\n" \ 1098c2ecf20Sopenharmony_ci : [result] "=&a" (result), [tmp] "=&a" (tmp) \ 1108c2ecf20Sopenharmony_ci : [i] "a" (i), [addr] "a" (v) \ 1118c2ecf20Sopenharmony_ci : "memory" \ 1128c2ecf20Sopenharmony_ci ); \ 1138c2ecf20Sopenharmony_ci \ 1148c2ecf20Sopenharmony_ci return tmp; \ 1158c2ecf20Sopenharmony_ci} 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci#elif XCHAL_HAVE_S32C1I 1188c2ecf20Sopenharmony_ci#define ATOMIC_OP(op) \ 1198c2ecf20Sopenharmony_cistatic inline void atomic_##op(int i, atomic_t * v) \ 1208c2ecf20Sopenharmony_ci{ \ 1218c2ecf20Sopenharmony_ci unsigned long tmp; \ 1228c2ecf20Sopenharmony_ci int result; \ 1238c2ecf20Sopenharmony_ci \ 1248c2ecf20Sopenharmony_ci __asm__ __volatile__( \ 1258c2ecf20Sopenharmony_ci "1: l32i %[tmp], %[mem]\n" \ 1268c2ecf20Sopenharmony_ci " wsr %[tmp], scompare1\n" \ 1278c2ecf20Sopenharmony_ci " " #op " %[result], %[tmp], %[i]\n" \ 1288c2ecf20Sopenharmony_ci " s32c1i %[result], %[mem]\n" \ 1298c2ecf20Sopenharmony_ci " bne %[result], %[tmp], 1b\n" \ 1308c2ecf20Sopenharmony_ci : [result] "=&a" (result), [tmp] "=&a" (tmp), \ 1318c2ecf20Sopenharmony_ci [mem] "+m" (*v) \ 1328c2ecf20Sopenharmony_ci : [i] "a" (i) \ 1338c2ecf20Sopenharmony_ci : "memory" \ 1348c2ecf20Sopenharmony_ci ); \ 1358c2ecf20Sopenharmony_ci} \ 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci#define ATOMIC_OP_RETURN(op) \ 1388c2ecf20Sopenharmony_cistatic inline int atomic_##op##_return(int i, atomic_t * v) \ 1398c2ecf20Sopenharmony_ci{ \ 1408c2ecf20Sopenharmony_ci unsigned long tmp; \ 1418c2ecf20Sopenharmony_ci int result; \ 1428c2ecf20Sopenharmony_ci \ 1438c2ecf20Sopenharmony_ci __asm__ __volatile__( \ 1448c2ecf20Sopenharmony_ci "1: l32i %[tmp], %[mem]\n" \ 1458c2ecf20Sopenharmony_ci " wsr %[tmp], scompare1\n" \ 1468c2ecf20Sopenharmony_ci " " #op " %[result], %[tmp], %[i]\n" \ 1478c2ecf20Sopenharmony_ci " s32c1i %[result], %[mem]\n" \ 1488c2ecf20Sopenharmony_ci " bne %[result], %[tmp], 1b\n" \ 1498c2ecf20Sopenharmony_ci " " #op " %[result], %[result], %[i]\n" \ 1508c2ecf20Sopenharmony_ci : [result] "=&a" (result), [tmp] "=&a" (tmp), \ 1518c2ecf20Sopenharmony_ci [mem] "+m" (*v) \ 1528c2ecf20Sopenharmony_ci : [i] "a" (i) \ 1538c2ecf20Sopenharmony_ci : "memory" \ 1548c2ecf20Sopenharmony_ci ); \ 1558c2ecf20Sopenharmony_ci \ 1568c2ecf20Sopenharmony_ci return result; \ 1578c2ecf20Sopenharmony_ci} 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci#define ATOMIC_FETCH_OP(op) \ 1608c2ecf20Sopenharmony_cistatic inline int atomic_fetch_##op(int i, atomic_t * v) \ 1618c2ecf20Sopenharmony_ci{ \ 1628c2ecf20Sopenharmony_ci unsigned long tmp; \ 1638c2ecf20Sopenharmony_ci int result; \ 1648c2ecf20Sopenharmony_ci \ 1658c2ecf20Sopenharmony_ci __asm__ __volatile__( \ 1668c2ecf20Sopenharmony_ci "1: l32i %[tmp], %[mem]\n" \ 1678c2ecf20Sopenharmony_ci " wsr %[tmp], scompare1\n" \ 1688c2ecf20Sopenharmony_ci " " #op " %[result], %[tmp], %[i]\n" \ 1698c2ecf20Sopenharmony_ci " s32c1i %[result], %[mem]\n" \ 1708c2ecf20Sopenharmony_ci " bne %[result], %[tmp], 1b\n" \ 1718c2ecf20Sopenharmony_ci : [result] "=&a" (result), [tmp] "=&a" (tmp), \ 1728c2ecf20Sopenharmony_ci [mem] "+m" (*v) \ 1738c2ecf20Sopenharmony_ci : [i] "a" (i) \ 1748c2ecf20Sopenharmony_ci : "memory" \ 1758c2ecf20Sopenharmony_ci ); \ 1768c2ecf20Sopenharmony_ci \ 1778c2ecf20Sopenharmony_ci return result; \ 1788c2ecf20Sopenharmony_ci} 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci#else /* XCHAL_HAVE_S32C1I */ 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci#define ATOMIC_OP(op) \ 1838c2ecf20Sopenharmony_cistatic inline void atomic_##op(int i, atomic_t * v) \ 1848c2ecf20Sopenharmony_ci{ \ 1858c2ecf20Sopenharmony_ci unsigned int vval; \ 1868c2ecf20Sopenharmony_ci \ 1878c2ecf20Sopenharmony_ci __asm__ __volatile__( \ 1888c2ecf20Sopenharmony_ci " rsil a15, "__stringify(TOPLEVEL)"\n" \ 1898c2ecf20Sopenharmony_ci " l32i %[result], %[mem]\n" \ 1908c2ecf20Sopenharmony_ci " " #op " %[result], %[result], %[i]\n" \ 1918c2ecf20Sopenharmony_ci " s32i %[result], %[mem]\n" \ 1928c2ecf20Sopenharmony_ci " wsr a15, ps\n" \ 1938c2ecf20Sopenharmony_ci " rsync\n" \ 1948c2ecf20Sopenharmony_ci : [result] "=&a" (vval), [mem] "+m" (*v) \ 1958c2ecf20Sopenharmony_ci : [i] "a" (i) \ 1968c2ecf20Sopenharmony_ci : "a15", "memory" \ 1978c2ecf20Sopenharmony_ci ); \ 1988c2ecf20Sopenharmony_ci} \ 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci#define ATOMIC_OP_RETURN(op) \ 2018c2ecf20Sopenharmony_cistatic inline int atomic_##op##_return(int i, atomic_t * v) \ 2028c2ecf20Sopenharmony_ci{ \ 2038c2ecf20Sopenharmony_ci unsigned int vval; \ 2048c2ecf20Sopenharmony_ci \ 2058c2ecf20Sopenharmony_ci __asm__ __volatile__( \ 2068c2ecf20Sopenharmony_ci " rsil a15,"__stringify(TOPLEVEL)"\n" \ 2078c2ecf20Sopenharmony_ci " l32i %[result], %[mem]\n" \ 2088c2ecf20Sopenharmony_ci " " #op " %[result], %[result], %[i]\n" \ 2098c2ecf20Sopenharmony_ci " s32i %[result], %[mem]\n" \ 2108c2ecf20Sopenharmony_ci " wsr a15, ps\n" \ 2118c2ecf20Sopenharmony_ci " rsync\n" \ 2128c2ecf20Sopenharmony_ci : [result] "=&a" (vval), [mem] "+m" (*v) \ 2138c2ecf20Sopenharmony_ci : [i] "a" (i) \ 2148c2ecf20Sopenharmony_ci : "a15", "memory" \ 2158c2ecf20Sopenharmony_ci ); \ 2168c2ecf20Sopenharmony_ci \ 2178c2ecf20Sopenharmony_ci return vval; \ 2188c2ecf20Sopenharmony_ci} 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci#define ATOMIC_FETCH_OP(op) \ 2218c2ecf20Sopenharmony_cistatic inline int atomic_fetch_##op(int i, atomic_t * v) \ 2228c2ecf20Sopenharmony_ci{ \ 2238c2ecf20Sopenharmony_ci unsigned int tmp, vval; \ 2248c2ecf20Sopenharmony_ci \ 2258c2ecf20Sopenharmony_ci __asm__ __volatile__( \ 2268c2ecf20Sopenharmony_ci " rsil a15,"__stringify(TOPLEVEL)"\n" \ 2278c2ecf20Sopenharmony_ci " l32i %[result], %[mem]\n" \ 2288c2ecf20Sopenharmony_ci " " #op " %[tmp], %[result], %[i]\n" \ 2298c2ecf20Sopenharmony_ci " s32i %[tmp], %[mem]\n" \ 2308c2ecf20Sopenharmony_ci " wsr a15, ps\n" \ 2318c2ecf20Sopenharmony_ci " rsync\n" \ 2328c2ecf20Sopenharmony_ci : [result] "=&a" (vval), [tmp] "=&a" (tmp), \ 2338c2ecf20Sopenharmony_ci [mem] "+m" (*v) \ 2348c2ecf20Sopenharmony_ci : [i] "a" (i) \ 2358c2ecf20Sopenharmony_ci : "a15", "memory" \ 2368c2ecf20Sopenharmony_ci ); \ 2378c2ecf20Sopenharmony_ci \ 2388c2ecf20Sopenharmony_ci return vval; \ 2398c2ecf20Sopenharmony_ci} 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci#endif /* XCHAL_HAVE_S32C1I */ 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci#define ATOMIC_OPS(op) ATOMIC_OP(op) ATOMIC_FETCH_OP(op) ATOMIC_OP_RETURN(op) 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ciATOMIC_OPS(add) 2468c2ecf20Sopenharmony_ciATOMIC_OPS(sub) 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci#undef ATOMIC_OPS 2498c2ecf20Sopenharmony_ci#define ATOMIC_OPS(op) ATOMIC_OP(op) ATOMIC_FETCH_OP(op) 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ciATOMIC_OPS(and) 2528c2ecf20Sopenharmony_ciATOMIC_OPS(or) 2538c2ecf20Sopenharmony_ciATOMIC_OPS(xor) 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci#undef ATOMIC_OPS 2568c2ecf20Sopenharmony_ci#undef ATOMIC_FETCH_OP 2578c2ecf20Sopenharmony_ci#undef ATOMIC_OP_RETURN 2588c2ecf20Sopenharmony_ci#undef ATOMIC_OP 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci#define atomic_cmpxchg(v, o, n) ((int)cmpxchg(&((v)->counter), (o), (n))) 2618c2ecf20Sopenharmony_ci#define atomic_xchg(v, new) (xchg(&((v)->counter), new)) 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci#endif /* _XTENSA_ATOMIC_H */ 264