Merge from vendor branch OPENPAM:
[dragonfly.git] / sys / platform / pc32 / isa / ipl.s
1 /*-
2  * Copyright (c) 1989, 1990 William F. Jolitz.
3  * Copyright (c) 1990 The Regents of the University of California.
4  * All rights reserved.
5  *
6  * This code is derived from software contributed to Berkeley by
7  * William Jolitz.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  * 3. All advertising materials mentioning features or use of this software
18  *    must display the following acknowledgement:
19  *      This product includes software developed by the University of
20  *      California, Berkeley and its contributors.
21  * 4. Neither the name of the University nor the names of its contributors
22  *    may be used to endorse or promote products derived from this software
23  *    without specific prior written permission.
24  *
25  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35  * SUCH DAMAGE.
36  *
37  *      @(#)ipl.s
38  *
39  * $FreeBSD: src/sys/i386/isa/ipl.s,v 1.32.2.3 2002/05/16 16:03:56 bde Exp $
40  * $DragonFly: src/sys/platform/pc32/isa/ipl.s,v 1.18 2005/06/16 21:12:47 dillon Exp $
41  */
42
43
44 /*
45  * AT/386
46  * Vector interrupt control section
47  *
48  *  ipending    - Pending interrupts (set when a masked interrupt occurs)
49  */
50
51         .text
52         /*
53          * GENERAL NOTES
54          *
55          *      - fast interrupts are always called with a critical section
56          *        held
57          *
58          *      - we release our critical section when scheduling interrupt
59          *        or softinterrupt threads in order so they can preempt
60          *        (unless we are called manually from a critical section, in
61          *        which case there will still be a critical section and
62          *        they won't preempt anyway).
63          *
64          *      - TD_NEST_COUNT prevents splz from nesting too deeply within
65          *        itself.  It is *not* actually an interrupt nesting count.
66          *        PCPU(intr_nesting_level) is an interrupt nesting count.
67          *
68          *      - We have to be careful in regards to local interrupts
69          *        occuring simultaniously with our doreti and splz 
70          *        processing.
71          */
72
73         /*
74          * DORETI
75          *
76          * Handle return from interrupts, traps and syscalls.  This function
77          * checks the cpl for unmasked pending interrupts (fast, normal, or
78          * soft) and schedules them if appropriate, then irets.
79          *
80          * If we are in a critical section we cannot run any pending ints
81          * nor can be play with mp_lock.
82          *
83          * NOTE: Since SPLs no longer exist, all callers of this function
84          * push $0 for the CPL.  HOWEVER, we *STILL* use the cpl mask within
85          * this function to mark fast interrupts which could not be dispatched
86          * do to the unavailability of the BGL.
87          */
88         SUPERALIGN_TEXT
89         .type   doreti,@function
90 doreti:
91         FAKE_MCOUNT(bintr)              /* init "from" bintr -> doreti */
92         popl    %eax                    /* cpl to restore XXX */
93         movl    $0,%eax                 /* irq mask unavailable due to BGL */
94         movl    PCPU(curthread),%ebx
95         cli                             /* interlock with TDPRI_CRIT */
96         cmpl    $0,PCPU(reqflags)       /* short cut if nothing to do */
97         je      5f
98         cmpl    $TDPRI_CRIT,TD_PRI(%ebx) /* can't unpend if in critical sec */
99         jge     5f
100         addl    $TDPRI_CRIT,TD_PRI(%ebx) /* force all ints to pending */
101 doreti_next:
102         sti                             /* allow new interrupts */
103         movl    %eax,%ecx               /* irq mask unavailable due to BGL */
104         notl    %ecx
105         cli                             /* disallow YYY remove */
106 #ifdef SMP
107         testl   $RQF_IPIQ,PCPU(reqflags)
108         jnz     doreti_ipiq
109 #endif
110         testl   PCPU(fpending),%ecx     /* check for an unmasked fast int */
111         jnz     doreti_fast
112
113         testl   PCPU(ipending),%ecx
114         jnz     doreti_intr
115
116         testl   $RQF_AST_MASK,PCPU(reqflags) /* any pending ASTs? */
117         jz      2f
118         testl   $PSL_VM,TF_EFLAGS(%esp)
119         jz      1f
120         cmpl    $1,in_vm86call          /* YYY make per 'cpu'? */
121         jnz     doreti_ast
122 1:
123         /* ASTs are only applicable when returning to userland */
124         testb   $SEL_RPL_MASK,TF_CS(%esp)
125         jnz     doreti_ast
126 2:
127         /*
128          * Nothing left to do, finish up.  Interrupts are still disabled.
129          * %eax contains the mask of IRQ's that are not available due to
130          * BGL requirements.  We can only clear RQF_INTPEND if *ALL* pending
131          * interrupts have been processed.
132          */
133         subl    $TDPRI_CRIT,TD_PRI(%ebx)        /* interlocked with cli */
134         testl   %eax,%eax
135         jnz     5f
136         andl    $~RQF_INTPEND,PCPU(reqflags)
137 5:
138         MEXITCOUNT
139         .globl  doreti_popl_fs
140         .globl  doreti_popl_es
141         .globl  doreti_popl_ds
142         .globl  doreti_iret
143         .globl  doreti_syscall_ret
144 doreti_syscall_ret:
145 doreti_popl_fs:
146         popl    %fs
147 doreti_popl_es:
148         popl    %es
149 doreti_popl_ds:
150         popl    %ds
151         popal
152         addl    $8,%esp
153 doreti_iret:
154         iret
155
156         ALIGN_TEXT
157         .globl  doreti_iret_fault
158 doreti_iret_fault:
159         subl    $8,%esp
160         pushal
161         pushl   %ds
162         .globl  doreti_popl_ds_fault
163 doreti_popl_ds_fault:
164         pushl   %es
165         .globl  doreti_popl_es_fault
166 doreti_popl_es_fault:
167         pushl   %fs
168         .globl  doreti_popl_fs_fault
169 doreti_popl_fs_fault:
170         movl    $0,TF_ERR(%esp) /* XXX should be the error code */
171         movl    $T_PROTFLT,TF_TRAPNO(%esp)
172         jmp     alltraps_with_regs_pushed
173
174         /*
175          * FAST interrupt pending.  NOTE: stack context holds frame structure
176          * for fast interrupt procedure, do not do random pushes or pops!
177          */
178         ALIGN_TEXT
179 doreti_fast:
180         andl    PCPU(fpending),%ecx     /* only check fast ints */
181         bsfl    %ecx, %ecx              /* locate the next dispatchable int */
182         btrl    %ecx, PCPU(fpending)    /* is it really still pending? */
183         jnc     doreti_next
184         pushl   %eax                    /* save IRQ mask unavailable for BGL */
185                                         /* NOTE: is also CPL in frame */
186 #ifdef SMP
187         pushl   %ecx                    /* save ecx */
188         call    try_mplock
189         popl    %ecx
190         testl   %eax,%eax
191         jz      1f
192         /* MP lock successful */
193 #endif
194         incl    PCPU(intr_nesting_level)
195         call    *fastunpend(,%ecx,4)
196         decl    PCPU(intr_nesting_level)
197 #ifdef SMP
198         call    rel_mplock
199 #endif
200         popl    %eax
201         jmp     doreti_next
202 1:
203         btsl    %ecx, PCPU(fpending)    /* oops, couldn't get the MP lock */
204         popl    %eax                    /* add to temp. cpl mask to ignore */
205         orl     PCPU(fpending),%eax
206         jmp     doreti_next
207
208         /*
209          *  INTR interrupt pending
210          *
211          *  Temporarily back-out our critical section to allow an interrupt
212          *  preempt us when we schedule it.  Bump intr_nesting_level to
213          *  prevent the switch code from recursing via splz too deeply.
214          */
215         ALIGN_TEXT
216 doreti_intr:
217         andl    PCPU(ipending),%ecx     /* only check normal ints */
218         bsfl    %ecx, %ecx              /* locate the next dispatchable int */
219         btrl    %ecx, PCPU(ipending)    /* is it really still pending? */
220         jnc     doreti_next
221         pushl   %eax
222         pushl   %ecx
223         incl    TD_NEST_COUNT(%ebx)     /* prevent doreti/splz nesting */
224         subl    $TDPRI_CRIT,TD_PRI(%ebx) /* so we can preempt */
225         call    sched_ithd              /* YYY must pull in imasks */
226         addl    $TDPRI_CRIT,TD_PRI(%ebx)
227         decl    TD_NEST_COUNT(%ebx)
228         addl    $4,%esp
229         popl    %eax
230         jmp     doreti_next
231
232         /*
233          * AST pending.  We clear RQF_AST_SIGNAL automatically, the others
234          * are cleared by the trap as they are processed.
235          *
236          * Temporarily back-out our critical section because trap() can be
237          * a long-winded call, and we want to be more syscall-like.  
238          *
239          * YYY theoretically we can call lwkt_switch directly if all we need
240          * to do is a reschedule.
241          */
242 doreti_ast:
243         andl    $~(RQF_AST_SIGNAL|RQF_AST_UPCALL),PCPU(reqflags)
244         sti
245         movl    %eax,%esi               /* save cpl (can't use stack) */
246         movl    $T_ASTFLT,TF_TRAPNO(%esp)
247         subl    $TDPRI_CRIT,TD_PRI(%ebx)
248 1:      call    trap
249         addl    $TDPRI_CRIT,TD_PRI(%ebx)
250         movl    %esi,%eax               /* restore cpl for loop */
251         jmp     doreti_next
252
253 #ifdef SMP
254         /*
255          * IPIQ message pending.  We clear RQF_IPIQ automatically.
256          */
257 doreti_ipiq:
258         movl    %eax,%esi               /* save cpl (can't use stack) */
259         incl    PCPU(intr_nesting_level)
260         andl    $~RQF_IPIQ,PCPU(reqflags)
261         subl    $8,%esp                 /* add dummy vec and ppl */
262         call    lwkt_process_ipiq_frame
263         addl    $8,%esp
264         decl    PCPU(intr_nesting_level)
265         movl    %esi,%eax               /* restore cpl for loop */
266         jmp     doreti_next
267
268 #endif
269
270         /*
271          * SPLZ() a C callable procedure to dispatch any unmasked pending
272          *        interrupts regardless of critical section nesting.  ASTs
273          *        are not dispatched.
274          *
275          *        Use %eax to track those IRQs that could not be processed
276          *        due to BGL requirements.
277          */
278         SUPERALIGN_TEXT
279
280 ENTRY(splz)
281         pushfl
282         pushl   %ebx
283         movl    PCPU(curthread),%ebx
284         addl    $TDPRI_CRIT,TD_PRI(%ebx)
285         movl    $0,%eax
286
287 splz_next:
288         cli
289         movl    %eax,%ecx               /* ecx = ~CPL */
290         notl    %ecx
291 #ifdef SMP
292         testl   $RQF_IPIQ,PCPU(reqflags)
293         jnz     splz_ipiq
294 #endif
295         testl   PCPU(fpending),%ecx     /* check for an unmasked fast int */
296         jnz     splz_fast
297
298         testl   PCPU(ipending),%ecx
299         jnz     splz_intr
300
301         subl    $TDPRI_CRIT,TD_PRI(%ebx)
302
303         /*
304          * Nothing left to do, finish up.  Interrupts are still disabled.
305          * If our mask of IRQs we couldn't process due to BGL requirements
306          * is 0 then there are no pending interrupt sources left and we
307          * can clear RQF_INTPEND.
308          */
309         testl   %eax,%eax
310         jnz     5f
311         andl    $~RQF_INTPEND,PCPU(reqflags)
312 5:
313         popl    %ebx
314         popfl
315         ret
316
317         /*
318          * FAST interrupt pending
319          */
320         ALIGN_TEXT
321 splz_fast:
322         andl    PCPU(fpending),%ecx     /* only check fast ints */
323         bsfl    %ecx, %ecx              /* locate the next dispatchable int */
324         btrl    %ecx, PCPU(fpending)    /* is it really still pending? */
325         jnc     splz_next
326         pushl   %eax
327 #ifdef SMP
328         pushl   %ecx
329         call    try_mplock
330         popl    %ecx
331         testl   %eax,%eax
332         jz      1f
333 #endif
334         incl    PCPU(intr_nesting_level)
335         call    *fastunpend(,%ecx,4)
336         decl    PCPU(intr_nesting_level)
337 #ifdef SMP
338         call    rel_mplock
339 #endif
340         popl    %eax
341         jmp     splz_next
342 1:
343         btsl    %ecx, PCPU(fpending)    /* oops, couldn't get the MP lock */
344         popl    %eax
345         orl     PCPU(fpending),%eax
346         jmp     splz_next
347
348         /*
349          *  INTR interrupt pending
350          *
351          *  Temporarily back-out our critical section to allow the interrupt
352          *  preempt us.
353          */
354         ALIGN_TEXT
355 splz_intr:
356         andl    PCPU(ipending),%ecx     /* only check normal ints */
357         bsfl    %ecx, %ecx              /* locate the next dispatchable int */
358         btrl    %ecx, PCPU(ipending)    /* is it really still pending? */
359         jnc     splz_next
360         sti
361         pushl   %eax
362         pushl   %ecx
363         subl    $TDPRI_CRIT,TD_PRI(%ebx)
364         incl    TD_NEST_COUNT(%ebx)     /* prevent doreti/splz nesting */
365         call    sched_ithd              /* YYY must pull in imasks */
366         addl    $TDPRI_CRIT,TD_PRI(%ebx)
367         decl    TD_NEST_COUNT(%ebx)     /* prevent doreti/splz nesting */
368         addl    $4,%esp
369         popl    %eax
370         jmp     splz_next
371
372 #ifdef SMP
373 splz_ipiq:
374         andl    $~RQF_IPIQ,PCPU(reqflags)
375         pushl   %eax
376         call    lwkt_process_ipiq
377         popl    %eax
378         jmp     splz_next
379 #endif
380
381         /*
382          * APIC/ICU specific ipl functions provide masking and unmasking
383          * calls for userland.
384          */
385
386 #ifdef APIC_IO
387 #include "i386/isa/apic_ipl.s"
388 #else
389 #include "i386/isa/icu_ipl.s"
390 #endif /* APIC_IO */