^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) /* SPDX-License-Identifier: GPL-2.0 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /* atomic.S: These things are too big to do inline.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * Copyright (C) 1999, 2007 2012 David S. Miller (davem@davemloft.net)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) #include <linux/linkage.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <asm/asi.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <asm/backoff.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <asm/export.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) .text
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) /* Three versions of the atomic routines, one that
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) * does not return a value and does not perform
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) * memory barriers, and a two which return
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) * a value, the new and old value resp. and does the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) * barriers.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #define ATOMIC_OP(op) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) ENTRY(atomic_##op) /* %o0 = increment, %o1 = atomic_ptr */ \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) BACKOFF_SETUP(%o2); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) 1: lduw [%o1], %g1; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) op %g1, %o0, %g7; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) cas [%o1], %g1, %g7; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) cmp %g1, %g7; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) bne,pn %icc, BACKOFF_LABEL(2f, 1b); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) nop; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) retl; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) nop; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) 2: BACKOFF_SPIN(%o2, %o3, 1b); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) ENDPROC(atomic_##op); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) EXPORT_SYMBOL(atomic_##op);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) #define ATOMIC_OP_RETURN(op) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) ENTRY(atomic_##op##_return) /* %o0 = increment, %o1 = atomic_ptr */ \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) BACKOFF_SETUP(%o2); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) 1: lduw [%o1], %g1; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) op %g1, %o0, %g7; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) cas [%o1], %g1, %g7; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) cmp %g1, %g7; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) bne,pn %icc, BACKOFF_LABEL(2f, 1b); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) op %g1, %o0, %g1; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) retl; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) sra %g1, 0, %o0; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) 2: BACKOFF_SPIN(%o2, %o3, 1b); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) ENDPROC(atomic_##op##_return); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) EXPORT_SYMBOL(atomic_##op##_return);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) #define ATOMIC_FETCH_OP(op) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) ENTRY(atomic_fetch_##op) /* %o0 = increment, %o1 = atomic_ptr */ \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) BACKOFF_SETUP(%o2); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) 1: lduw [%o1], %g1; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) op %g1, %o0, %g7; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) cas [%o1], %g1, %g7; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) cmp %g1, %g7; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) bne,pn %icc, BACKOFF_LABEL(2f, 1b); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) nop; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) retl; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) sra %g1, 0, %o0; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) 2: BACKOFF_SPIN(%o2, %o3, 1b); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) ENDPROC(atomic_fetch_##op); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) EXPORT_SYMBOL(atomic_fetch_##op);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) ATOMIC_OP(add)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) ATOMIC_OP_RETURN(add)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) ATOMIC_FETCH_OP(add)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) ATOMIC_OP(sub)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) ATOMIC_OP_RETURN(sub)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) ATOMIC_FETCH_OP(sub)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) ATOMIC_OP(and)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) ATOMIC_FETCH_OP(and)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) ATOMIC_OP(or)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) ATOMIC_FETCH_OP(or)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) ATOMIC_OP(xor)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) ATOMIC_FETCH_OP(xor)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) #undef ATOMIC_FETCH_OP
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) #undef ATOMIC_OP_RETURN
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) #undef ATOMIC_OP
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) #define ATOMIC64_OP(op) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) ENTRY(atomic64_##op) /* %o0 = increment, %o1 = atomic_ptr */ \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) BACKOFF_SETUP(%o2); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) 1: ldx [%o1], %g1; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) op %g1, %o0, %g7; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) casx [%o1], %g1, %g7; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) cmp %g1, %g7; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) bne,pn %xcc, BACKOFF_LABEL(2f, 1b); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) nop; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) retl; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) nop; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) 2: BACKOFF_SPIN(%o2, %o3, 1b); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) ENDPROC(atomic64_##op); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) EXPORT_SYMBOL(atomic64_##op);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) #define ATOMIC64_OP_RETURN(op) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) ENTRY(atomic64_##op##_return) /* %o0 = increment, %o1 = atomic_ptr */ \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) BACKOFF_SETUP(%o2); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) 1: ldx [%o1], %g1; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) op %g1, %o0, %g7; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) casx [%o1], %g1, %g7; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) cmp %g1, %g7; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) bne,pn %xcc, BACKOFF_LABEL(2f, 1b); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) nop; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) retl; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) op %g1, %o0, %o0; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) 2: BACKOFF_SPIN(%o2, %o3, 1b); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) ENDPROC(atomic64_##op##_return); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) EXPORT_SYMBOL(atomic64_##op##_return);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) #define ATOMIC64_FETCH_OP(op) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) ENTRY(atomic64_fetch_##op) /* %o0 = increment, %o1 = atomic_ptr */ \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) BACKOFF_SETUP(%o2); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) 1: ldx [%o1], %g1; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) op %g1, %o0, %g7; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) casx [%o1], %g1, %g7; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) cmp %g1, %g7; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) bne,pn %xcc, BACKOFF_LABEL(2f, 1b); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) nop; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) retl; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) mov %g1, %o0; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) 2: BACKOFF_SPIN(%o2, %o3, 1b); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) ENDPROC(atomic64_fetch_##op); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) EXPORT_SYMBOL(atomic64_fetch_##op);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) ATOMIC64_OP(add)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) ATOMIC64_OP_RETURN(add)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) ATOMIC64_FETCH_OP(add)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) ATOMIC64_OP(sub)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) ATOMIC64_OP_RETURN(sub)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) ATOMIC64_FETCH_OP(sub)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) ATOMIC64_OP(and)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) ATOMIC64_FETCH_OP(and)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) ATOMIC64_OP(or)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) ATOMIC64_FETCH_OP(or)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) ATOMIC64_OP(xor)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) ATOMIC64_FETCH_OP(xor)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) #undef ATOMIC64_FETCH_OP
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) #undef ATOMIC64_OP_RETURN
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) #undef ATOMIC64_OP
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) ENTRY(atomic64_dec_if_positive) /* %o0 = atomic_ptr */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) BACKOFF_SETUP(%o2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) 1: ldx [%o0], %g1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) brlez,pn %g1, 3f
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) sub %g1, 1, %g7
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) casx [%o0], %g1, %g7
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) cmp %g1, %g7
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) bne,pn %xcc, BACKOFF_LABEL(2f, 1b)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) nop
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) 3: retl
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) sub %g1, 1, %o0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) 2: BACKOFF_SPIN(%o2, %o3, 1b)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) ENDPROC(atomic64_dec_if_positive)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) EXPORT_SYMBOL(atomic64_dec_if_positive)