aa0dbea2edcaffd4d5d7888be50f130901778a2a
[dragonfly.git] / sys / platform / pc32 / i386 / mplock.s
1 /*
2  * ----------------------------------------------------------------------------
3  * "THE BEER-WARE LICENSE" (Revision 42):
4  * <phk@FreeBSD.org> wrote this file.  As long as you retain this notice you
5  * can do whatever you want with this stuff. If we meet some day, and you think
6  * this stuff is worth it, you can buy me a beer in return.   Poul-Henning Kamp
7  * ----------------------------------------------------------------------------
8  *
9  * $FreeBSD: src/sys/i386/i386/mplock.s,v 1.29.2.2 2000/05/16 06:58:06 dillon Exp $
10  * $DragonFly: src/sys/platform/pc32/i386/mplock.s,v 1.4 2003/07/06 21:23:48 dillon Exp $
11  *
12  * Functions for locking between CPUs in a SMP system.
13  *
14  * This is an "exclusive counting semaphore".  This means that it can be
15  * free (0xffffffff) or be owned by a CPU (0xXXYYYYYY where XX is CPU-id
16  * and YYYYYY is the count).
17  *
18  * Contrary to most implementations around, this one is entirely atomic:
19  * The attempt to seize/release the semaphore and the increment/decrement
20  * is done in one atomic operation.  This way we are safe from all kinds
21  * of weird reentrancy situations.
22  */
23
24 #include <machine/asmacros.h>
25 #include <machine/smptests.h>           /** GRAB_LOPRIO */
26 #include <machine/apic.h>
27
28 #include "assym.s"
29
30         .data
31         ALIGN_DATA
32 #ifdef SMP
33         .globl  mp_lock
34 mp_lock:
35         .long   -1                      /* initialized to not held */
36 #endif
37
38         .text
39         SUPERALIGN_TEXT
40
41         /*
42          * Note on cmpxchgl... exchanges ecx with mem if mem matches eax.
43          * Z=1 (jz) on success. 
44          */
45 NON_GPROF_ENTRY(cpu_get_initial_mplock)
46         movl    PCPU(curthread),%ecx
47         movl    $1,TD_MPCOUNT(%ecx)     /* curthread has mpcount of 1 */
48         movl    $0,mp_lock              /* owned by cpu 0 */
49         NON_GPROF_RET
50
51         /*
52          * cpu_try_mplock() returns non-zero on success, 0 on failure.  It
53          * only adjusts mp_lock.  It does not touch td_mpcount, and it
54          * must be called from inside a critical section.
55          */
56 NON_GPROF_ENTRY(cpu_try_mplock)
57         movl    PCPU(cpuid),%ecx
58         movl    $-1,%eax
59         cmpxchgl %ecx,mp_lock           /* ecx<->mem if eax matches */
60         jnz     1f
61         movl    $1,%eax
62         NON_GPROF_RET
63 1:
64         movl    $0,%eax
65         NON_GPROF_RET
66
67 NON_GPROF_ENTRY(get_mplock)
68         movl    PCPU(curthread),%edx
69         cmpl    $0,TD_MPCOUNT(%edx)
70         je      1f
71         incl    TD_MPCOUNT(%edx)        /* already have it, just ++mpcount */
72         NON_GPROF_RET
73 1:
74         pushfl
75         cli
76         movl    $1,TD_MPCOUNT(%edx)
77         movl    PCPU(cpuid),%ecx
78         movl    $-1,%eax
79         cmpxchgl %ecx,mp_lock           /* ecx<->mem & JZ if eax matches */
80         jnz     2f
81         popfl                           /* success */
82         NON_GPROF_RET
83 2:
84         movl    PCPU(cpuid),%eax        /* failure */
85         cmpl    %eax,mp_lock
86         je      badmp_get
87         popfl
88         jmp     lwkt_switch             /* will be correct on return */
89
90 NON_GPROF_ENTRY(try_mplock)
91         movl    PCPU(curthread),%edx
92         cmpl    $0,TD_MPCOUNT(%edx)
93         je      1f
94         incl    TD_MPCOUNT(%edx)        /* already have it, just ++mpcount */
95         movl    $1,%eax
96         NON_GPROF_RET
97 1:
98         pushfl
99         cli
100         movl    PCPU(cpuid),%ecx
101         movl    $-1,%eax
102         cmpxchgl %ecx,mp_lock           /* ecx<->mem & JZ if eax matches */
103         jnz     2f
104         movl    $1,TD_MPCOUNT(%edx)
105         popfl                           /* success */
106         movl    $1,%eax
107         NON_GPROF_RET
108 2:
109         movl    PCPU(cpuid),%eax        /* failure */
110         cmpl    %eax,mp_lock
111         je      badmp_get
112         popfl
113         movl    $0,%eax
114         NON_GPROF_RET
115
116 NON_GPROF_ENTRY(rel_mplock)
117         movl    PCPU(curthread),%edx
118         cmpl    $1,TD_MPCOUNT(%edx)
119         je      1f
120         subl    $1,TD_MPCOUNT(%edx)
121         NON_GPROF_RET
122 1:
123         pushfl
124         cli
125         movl    $0,TD_MPCOUNT(%edx)
126         movl    $MP_FREE_LOCK,mp_lock
127         popfl
128         NON_GPROF_RET
129
130 badmp_get:
131         pushl   $bmpsw1
132         call    panic
133 badmp_rel:
134         pushl   $bmpsw2
135         call    panic
136
137         .data
138
139 bmpsw1:
140         .asciz  "try/get_mplock(): already have lock!"
141
142 bmpsw2:
143         .asciz  "rel_mplock(): not holding lock!"
144
145 #if 0
146 /* after 1st acquire of lock we grab all hardware INTs */
147 #ifdef GRAB_LOPRIO
148 #define GRAB_HWI        movl    $ALLHWI_LEVEL, lapic_tpr
149
150 /* after last release of lock give up LOW PRIO (ie, arbitrate INTerrupts) */
151 #define ARB_HWI         movl    $LOPRIO_LEVEL, lapic_tpr /* CHEAP_TPR */
152 #endif
153 #endif
154