import of upstream 2.4.34.4 from kernel.org
[linux-2.4.git] / arch / sparc64 / lib / dec_and_lock.S
1 /* $Id: dec_and_lock.S,v 1.5 2001/11/18 00:12:56 davem Exp $
2  * dec_and_lock.S: Sparc64 version of "atomic_dec_and_lock()"
3  *                 using cas and ldstub instructions.
4  *
5  * Copyright (C) 2000 David S. Miller (davem@redhat.com)
6  */
7 #include <linux/config.h>
8
9 #ifndef CONFIG_DEBUG_SPINLOCK
10         .text
11         .align  64
12
13         /* CAS basically works like this:
14          *
15          * void CAS(MEM, REG1, REG2)
16          * {
17          *   START_ATOMIC();
18          *   if (*(MEM) == REG1) {
19          *     TMP = *(MEM);
20          *     *(MEM) = REG2;
21          *     REG2 = TMP;
22          *   } else
23          *     REG2 = *(MEM);
24          *   END_ATOMIC();
25          * }
26          */
27
28         .globl  atomic_dec_and_lock
29 atomic_dec_and_lock:    /* %o0 = counter, %o1 = lock */
30 loop1:  lduw    [%o0], %g5
31         subcc   %g5, 1, %g7
32         be,pn   %icc, to_zero
33          nop
34 nzero:  cas     [%o0], %g5, %g7
35         cmp     %g5, %g7
36         bne,pn  %icc, loop1
37          mov    0, %g1
38
39 out:
40         membar  #StoreLoad | #StoreStore
41         retl
42          mov    %g1, %o0
43 to_zero:
44         ldstub  [%o1], %g3
45         brnz,pn %g3, spin_on_lock
46          membar #StoreLoad | #StoreStore
47 loop2:  cas     [%o0], %g5, %g7         /* ASSERT(g7 == 0) */
48         cmp     %g5, %g7
49
50         be,pt   %icc, out
51          mov    1, %g1
52         lduw    [%o0], %g5
53         subcc   %g5, 1, %g7
54         be,pn   %icc, loop2
55          nop
56         membar  #StoreStore | #LoadStore
57         stb     %g0, [%o1]
58
59         b,pt    %xcc, nzero
60          nop
61 spin_on_lock:
62         ldub    [%o1], %g3
63         brnz,pt %g3, spin_on_lock
64          membar #LoadLoad
65         ba,pt   %xcc, to_zero
66          nop
67         nop
68
69 #endif /* !(CONFIG_DEBUG_SPINLOCK) */