18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */ 28c2ecf20Sopenharmony_ci/* atomic.S: These things are too big to do inline. 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright (C) 1999, 2007 2012 David S. Miller (davem@davemloft.net) 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include <linux/linkage.h> 88c2ecf20Sopenharmony_ci#include <asm/asi.h> 98c2ecf20Sopenharmony_ci#include <asm/backoff.h> 108c2ecf20Sopenharmony_ci#include <asm/export.h> 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci .text 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci /* Three versions of the atomic routines, one that 158c2ecf20Sopenharmony_ci * does not return a value and does not perform 168c2ecf20Sopenharmony_ci * memory barriers, and a two which return 178c2ecf20Sopenharmony_ci * a value, the new and old value resp. and does the 188c2ecf20Sopenharmony_ci * barriers. 198c2ecf20Sopenharmony_ci */ 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#define ATOMIC_OP(op) \ 228c2ecf20Sopenharmony_ciENTRY(atomic_##op) /* %o0 = increment, %o1 = atomic_ptr */ \ 238c2ecf20Sopenharmony_ci BACKOFF_SETUP(%o2); \ 248c2ecf20Sopenharmony_ci1: lduw [%o1], %g1; \ 258c2ecf20Sopenharmony_ci op %g1, %o0, %g7; \ 268c2ecf20Sopenharmony_ci cas [%o1], %g1, %g7; \ 278c2ecf20Sopenharmony_ci cmp %g1, %g7; \ 288c2ecf20Sopenharmony_ci bne,pn %icc, BACKOFF_LABEL(2f, 1b); \ 298c2ecf20Sopenharmony_ci nop; \ 308c2ecf20Sopenharmony_ci retl; \ 318c2ecf20Sopenharmony_ci nop; \ 328c2ecf20Sopenharmony_ci2: BACKOFF_SPIN(%o2, %o3, 1b); \ 338c2ecf20Sopenharmony_ciENDPROC(atomic_##op); \ 348c2ecf20Sopenharmony_ciEXPORT_SYMBOL(atomic_##op); 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci#define ATOMIC_OP_RETURN(op) \ 378c2ecf20Sopenharmony_ciENTRY(atomic_##op##_return) /* %o0 = increment, %o1 = atomic_ptr */ \ 388c2ecf20Sopenharmony_ci BACKOFF_SETUP(%o2); \ 398c2ecf20Sopenharmony_ci1: lduw [%o1], %g1; \ 408c2ecf20Sopenharmony_ci op %g1, %o0, %g7; \ 418c2ecf20Sopenharmony_ci cas [%o1], %g1, %g7; \ 428c2ecf20Sopenharmony_ci cmp %g1, %g7; \ 438c2ecf20Sopenharmony_ci bne,pn %icc, BACKOFF_LABEL(2f, 1b); \ 448c2ecf20Sopenharmony_ci op %g1, %o0, %g1; \ 458c2ecf20Sopenharmony_ci retl; \ 468c2ecf20Sopenharmony_ci sra %g1, 0, %o0; \ 478c2ecf20Sopenharmony_ci2: BACKOFF_SPIN(%o2, %o3, 1b); \ 488c2ecf20Sopenharmony_ciENDPROC(atomic_##op##_return); \ 498c2ecf20Sopenharmony_ciEXPORT_SYMBOL(atomic_##op##_return); 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci#define ATOMIC_FETCH_OP(op) \ 528c2ecf20Sopenharmony_ciENTRY(atomic_fetch_##op) /* %o0 = increment, %o1 = atomic_ptr */ \ 538c2ecf20Sopenharmony_ci BACKOFF_SETUP(%o2); \ 548c2ecf20Sopenharmony_ci1: lduw [%o1], %g1; \ 558c2ecf20Sopenharmony_ci op %g1, %o0, %g7; \ 568c2ecf20Sopenharmony_ci cas [%o1], %g1, %g7; \ 578c2ecf20Sopenharmony_ci cmp %g1, %g7; \ 588c2ecf20Sopenharmony_ci bne,pn %icc, BACKOFF_LABEL(2f, 1b); \ 598c2ecf20Sopenharmony_ci nop; \ 608c2ecf20Sopenharmony_ci retl; \ 618c2ecf20Sopenharmony_ci sra %g1, 0, %o0; \ 628c2ecf20Sopenharmony_ci2: BACKOFF_SPIN(%o2, %o3, 1b); \ 638c2ecf20Sopenharmony_ciENDPROC(atomic_fetch_##op); \ 648c2ecf20Sopenharmony_ciEXPORT_SYMBOL(atomic_fetch_##op); 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ciATOMIC_OP(add) 678c2ecf20Sopenharmony_ciATOMIC_OP_RETURN(add) 688c2ecf20Sopenharmony_ciATOMIC_FETCH_OP(add) 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ciATOMIC_OP(sub) 718c2ecf20Sopenharmony_ciATOMIC_OP_RETURN(sub) 728c2ecf20Sopenharmony_ciATOMIC_FETCH_OP(sub) 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ciATOMIC_OP(and) 758c2ecf20Sopenharmony_ciATOMIC_FETCH_OP(and) 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ciATOMIC_OP(or) 788c2ecf20Sopenharmony_ciATOMIC_FETCH_OP(or) 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ciATOMIC_OP(xor) 818c2ecf20Sopenharmony_ciATOMIC_FETCH_OP(xor) 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci#undef ATOMIC_FETCH_OP 848c2ecf20Sopenharmony_ci#undef ATOMIC_OP_RETURN 858c2ecf20Sopenharmony_ci#undef ATOMIC_OP 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci#define ATOMIC64_OP(op) \ 888c2ecf20Sopenharmony_ciENTRY(atomic64_##op) /* %o0 = increment, %o1 = atomic_ptr */ \ 898c2ecf20Sopenharmony_ci BACKOFF_SETUP(%o2); \ 908c2ecf20Sopenharmony_ci1: ldx [%o1], %g1; \ 918c2ecf20Sopenharmony_ci op %g1, %o0, %g7; \ 928c2ecf20Sopenharmony_ci casx [%o1], %g1, %g7; \ 938c2ecf20Sopenharmony_ci cmp %g1, %g7; \ 948c2ecf20Sopenharmony_ci bne,pn %xcc, BACKOFF_LABEL(2f, 1b); \ 958c2ecf20Sopenharmony_ci nop; \ 968c2ecf20Sopenharmony_ci retl; \ 978c2ecf20Sopenharmony_ci nop; \ 988c2ecf20Sopenharmony_ci2: BACKOFF_SPIN(%o2, %o3, 1b); \ 998c2ecf20Sopenharmony_ciENDPROC(atomic64_##op); \ 1008c2ecf20Sopenharmony_ciEXPORT_SYMBOL(atomic64_##op); 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci#define ATOMIC64_OP_RETURN(op) \ 1038c2ecf20Sopenharmony_ciENTRY(atomic64_##op##_return) /* %o0 = increment, %o1 = atomic_ptr */ \ 1048c2ecf20Sopenharmony_ci BACKOFF_SETUP(%o2); \ 1058c2ecf20Sopenharmony_ci1: ldx [%o1], %g1; \ 1068c2ecf20Sopenharmony_ci op %g1, %o0, %g7; \ 1078c2ecf20Sopenharmony_ci casx [%o1], %g1, %g7; \ 1088c2ecf20Sopenharmony_ci cmp %g1, %g7; \ 1098c2ecf20Sopenharmony_ci bne,pn %xcc, BACKOFF_LABEL(2f, 1b); \ 1108c2ecf20Sopenharmony_ci nop; \ 1118c2ecf20Sopenharmony_ci retl; \ 1128c2ecf20Sopenharmony_ci op %g1, %o0, %o0; \ 1138c2ecf20Sopenharmony_ci2: BACKOFF_SPIN(%o2, %o3, 1b); \ 1148c2ecf20Sopenharmony_ciENDPROC(atomic64_##op##_return); \ 1158c2ecf20Sopenharmony_ciEXPORT_SYMBOL(atomic64_##op##_return); 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci#define ATOMIC64_FETCH_OP(op) \ 1188c2ecf20Sopenharmony_ciENTRY(atomic64_fetch_##op) /* %o0 = increment, %o1 = atomic_ptr */ \ 1198c2ecf20Sopenharmony_ci BACKOFF_SETUP(%o2); \ 1208c2ecf20Sopenharmony_ci1: ldx [%o1], %g1; \ 1218c2ecf20Sopenharmony_ci op %g1, %o0, %g7; \ 1228c2ecf20Sopenharmony_ci casx [%o1], %g1, %g7; \ 1238c2ecf20Sopenharmony_ci cmp %g1, %g7; \ 1248c2ecf20Sopenharmony_ci bne,pn %xcc, BACKOFF_LABEL(2f, 1b); \ 1258c2ecf20Sopenharmony_ci nop; \ 1268c2ecf20Sopenharmony_ci retl; \ 1278c2ecf20Sopenharmony_ci mov %g1, %o0; \ 1288c2ecf20Sopenharmony_ci2: BACKOFF_SPIN(%o2, %o3, 1b); \ 1298c2ecf20Sopenharmony_ciENDPROC(atomic64_fetch_##op); \ 1308c2ecf20Sopenharmony_ciEXPORT_SYMBOL(atomic64_fetch_##op); 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ciATOMIC64_OP(add) 1338c2ecf20Sopenharmony_ciATOMIC64_OP_RETURN(add) 1348c2ecf20Sopenharmony_ciATOMIC64_FETCH_OP(add) 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ciATOMIC64_OP(sub) 1378c2ecf20Sopenharmony_ciATOMIC64_OP_RETURN(sub) 1388c2ecf20Sopenharmony_ciATOMIC64_FETCH_OP(sub) 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ciATOMIC64_OP(and) 1418c2ecf20Sopenharmony_ciATOMIC64_FETCH_OP(and) 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ciATOMIC64_OP(or) 1448c2ecf20Sopenharmony_ciATOMIC64_FETCH_OP(or) 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ciATOMIC64_OP(xor) 1478c2ecf20Sopenharmony_ciATOMIC64_FETCH_OP(xor) 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci#undef ATOMIC64_FETCH_OP 1508c2ecf20Sopenharmony_ci#undef ATOMIC64_OP_RETURN 1518c2ecf20Sopenharmony_ci#undef ATOMIC64_OP 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ciENTRY(atomic64_dec_if_positive) /* %o0 = atomic_ptr */ 1548c2ecf20Sopenharmony_ci BACKOFF_SETUP(%o2) 1558c2ecf20Sopenharmony_ci1: ldx [%o0], %g1 1568c2ecf20Sopenharmony_ci brlez,pn %g1, 3f 1578c2ecf20Sopenharmony_ci sub %g1, 1, %g7 1588c2ecf20Sopenharmony_ci casx [%o0], %g1, %g7 1598c2ecf20Sopenharmony_ci cmp %g1, %g7 1608c2ecf20Sopenharmony_ci bne,pn %xcc, BACKOFF_LABEL(2f, 1b) 1618c2ecf20Sopenharmony_ci nop 1628c2ecf20Sopenharmony_ci3: retl 1638c2ecf20Sopenharmony_ci sub %g1, 1, %o0 1648c2ecf20Sopenharmony_ci2: BACKOFF_SPIN(%o2, %o3, 1b) 1658c2ecf20Sopenharmony_ciENDPROC(atomic64_dec_if_positive) 1668c2ecf20Sopenharmony_ciEXPORT_SYMBOL(atomic64_dec_if_positive) 167