/* $Id: dec_and_lock.S,v 1.2 2000/08/13 18:24:12 davem Exp $ * dec_and_lock.S: Sparc64 version of "atomic_dec_and_lock()" * using cas and ldstub instructions. * * Copyright (C) 2000 David S. Miller (davem@redhat.com) */ .text .align 64 /* CAS basically works like this: * * void CAS(MEM, REG1, REG2) * { * START_ATOMIC(); * if (*(MEM) == REG1) { * TMP = *(MEM); * *(MEM) = REG2; * REG2 = TMP; * } else * REG2 = *(MEM); * END_ATOMIC(); * } */ .globl atomic_dec_and_lock atomic_dec_and_lock: /* %o0 = counter, %o1 = lock */ loop1: lduw [%o0], %g5 subcc %g5, 1, %g7 be,pn %icc, to_zero nop nzero: cas [%o0], %g5, %g7 cmp %g5, %g7 bne,pn %icc, loop1 mov 0, %g1 out: retl mov %g1, %o0 to_zero:ldstub [%o1], %g3 brnz,pn %g3, spin_on_lock membar #StoreLoad | #StoreStore loop2: cas [%o0], %g5, %g7 /* ASSERT(g7 == 0) */ nop cmp %g5, %g7 be,pt %icc, out mov 1, %g1 lduw [%o0], %g5 subcc %g5, 1, %g7 be,pn %icc, loop2 nop membar #StoreStore | #LoadStore stb %g0, [%o1] b,pt %xcc, nzero nop spin_on_lock: ldub [%o1], %g3 brnz,pt %g3, spin_on_lock membar #LoadLoad ba,pt %xcc, to_zero nop nop