MP Implementation 2/4: Implement a poor-man's IPI messaging subsystem,
[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.5 2003/07/08 06:27:26 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.   A lock prefix is required for MP.
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         lock 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         lock cmpxchgl %ecx,mp_lock      /* ecx<->mem & JZ if eax matches */
80         jnz     2f
81         popfl                           /* success */
82         NON_GPROF_RET
83 2:
84 #ifdef INVARIANTS
85         movl    PCPU(cpuid),%eax        /* failure */
86         cmpl    %eax,mp_lock
87         je      3f
88 #endif
89         addl    $TDPRI_CRIT,TD_PRI(%edx)
90         popfl
91         call    lwkt_switch             /* will be correct on return */
92         movl    PCPU(curthread),%edx
93         subl    $TDPRI_CRIT,TD_PRI(%edx)
94         NON_GPROF_RET
95 3:
96         cmpl    $0,panicstr             /* don't double panic */
97         je      badmp_get
98         popfl
99         NON_GPROF_RET
100
101 NON_GPROF_ENTRY(try_mplock)
102         movl    PCPU(curthread),%edx
103         cmpl    $0,TD_MPCOUNT(%edx)
104         je      1f
105         incl    TD_MPCOUNT(%edx)        /* already have it, just ++mpcount */
106         movl    $1,%eax
107         NON_GPROF_RET
108 1:
109         pushfl
110         cli
111         movl    PCPU(cpuid),%ecx
112         movl    $-1,%eax
113         lock cmpxchgl %ecx,mp_lock      /* ecx<->mem & JZ if eax matches */
114         jnz     2f
115         movl    $1,TD_MPCOUNT(%edx)
116         popfl                           /* success */
117         movl    $1,%eax
118         NON_GPROF_RET
119 2:
120 #ifdef INVARIANTS
121         cmpl    $0,panicstr
122         jnz     3f
123         movl    PCPU(cpuid),%eax        /* failure */
124         cmpl    %eax,mp_lock
125         je      badmp_get
126 3:
127 #endif
128         popfl
129         movl    $0,%eax
130         NON_GPROF_RET
131
132 NON_GPROF_ENTRY(rel_mplock)
133         movl    PCPU(curthread),%edx
134         movl    TD_MPCOUNT(%edx),%eax
135         cmpl    $1,%eax
136         je      1f
137 #ifdef INVARIANTS
138         testl   %eax,%eax
139         jz      badmp_rel
140 #endif
141         subl    $1,%eax
142         movl    %eax,TD_MPCOUNT(%edx)
143         NON_GPROF_RET
144 1:
145         pushfl
146         cli
147 #ifdef INVARIANTS
148         movl    PCPU(cpuid),%ecx
149         cmpl    %ecx,mp_lock
150         jne     badmp_rel2
151 #endif
152         movl    $0,TD_MPCOUNT(%edx)
153         movl    $MP_FREE_LOCK,mp_lock
154         popfl
155         NON_GPROF_RET
156
157 #ifdef INVARIANTS
158
159 badmp_get:
160         pushl   $bmpsw1
161         call    panic
162 badmp_rel:
163         pushl   $bmpsw2
164         call    panic
165 badmp_rel2:
166         pushl   $bmpsw2a
167         call    panic
168
169         .data
170
171 bmpsw1:
172         .asciz  "try/get_mplock(): already have lock! %d %p"
173
174 bmpsw2:
175         .asciz  "rel_mplock(): mpcount already 0 @ %p %p %p %p %p %p %p %p!"
176
177 bmpsw2a:
178         .asciz  "rel_mplock(): Releasing another cpu's MP lock! %p %p"
179
180 #endif
181
182 #if 0
183 /* after 1st acquire of lock we grab all hardware INTs */
184 #ifdef GRAB_LOPRIO
185 #define GRAB_HWI        movl    $ALLHWI_LEVEL, lapic_tpr
186
187 /* after last release of lock give up LOW PRIO (ie, arbitrate INTerrupts) */
188 #define ARB_HWI         movl    $LOPRIO_LEVEL, lapic_tpr /* CHEAP_TPR */
189 #endif
190 #endif
191