ICU/APIC cleanup part 7/many.
[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.22 2005/11/02 22:59:47 dillon Exp $
41  */
42
43 #include "use_npx.h"
44
45 #include <machine/asmacros.h>
46 #include <machine/segments.h>
47 #include <machine/ipl.h>
48 #include <machine/lock.h>
49 #include <machine/psl.h>
50 #include <machine/trap.h>
51 #include <machine/smptests.h>           /** various SMP options */
52  
53 #include "assym.s"
54
55 /*
56  * AT/386
57  * Vector interrupt control section
58  *
59  *  ipending    - Pending interrupts (set when a masked interrupt occurs)
60  *  spending    - Pending software interrupts
61  */
62         .data
63         ALIGN_DATA
64
65         .text
66         SUPERALIGN_TEXT
67
68         /*
69          * GENERAL NOTES
70          *
71          *      - fast interrupts are always called with a critical section
72          *        held
73          *
74          *      - we release our critical section when scheduling interrupt
75          *        or softinterrupt threads in order so they can preempt
76          *        (unless we are called manually from a critical section, in
77          *        which case there will still be a critical section and
78          *        they won't preempt anyway).
79          *
80          *      - TD_NEST_COUNT prevents splz from nesting too deeply within
81          *        itself.  It is *not* actually an interrupt nesting count.
82          *        PCPU(intr_nesting_level) is an interrupt nesting count.
83          *
84          *      - We have to be careful in regards to local interrupts
85          *        occuring simultaniously with our doreti and splz 
86          *        processing.
87          */
88
89         /*
90          * DORETI
91          *
92          * Handle return from interrupts, traps and syscalls.  This function
93          * checks the cpl for unmasked pending interrupts (fast, normal, or
94          * soft) and schedules them if appropriate, then irets.
95          *
96          * If we are in a critical section we cannot run any pending ints
97          * nor can be play with mp_lock.
98          *
99          * NOTE: Since SPLs no longer exist, all callers of this function
100          * push $0 for the CPL.  HOWEVER, we *STILL* use the cpl mask within
101          * this function to mark fast interrupts which could not be dispatched
102          * do to the unavailability of the BGL.
103          */
104         SUPERALIGN_TEXT
105         .globl  doreti
106         .type   doreti,@function
107 doreti:
108         FAKE_MCOUNT(bintr)              /* init "from" bintr -> doreti */
109         popl    %eax                    /* cpl to restore XXX */
110         movl    $0,%eax                 /* irq mask unavailable due to BGL */
111         movl    PCPU(curthread),%ebx
112         cli                             /* interlock with TDPRI_CRIT */
113         cmpl    $0,PCPU(reqflags)       /* short cut if nothing to do */
114         je      5f
115         cmpl    $TDPRI_CRIT,TD_PRI(%ebx) /* can't unpend if in critical sec */
116         jge     5f
117         addl    $TDPRI_CRIT,TD_PRI(%ebx) /* force all ints to pending */
118 doreti_next:
119         sti                             /* allow new interrupts */
120         movl    %eax,%ecx               /* irq mask unavailable due to BGL */
121         notl    %ecx
122         cli                             /* disallow YYY remove */
123 #ifdef SMP
124         testl   $RQF_IPIQ,PCPU(reqflags)
125         jnz     doreti_ipiq
126 #endif
127         testl   PCPU(fpending),%ecx     /* check for an unmasked fast int */
128         jnz     doreti_fast
129
130         testl   PCPU(ipending),%ecx     /* check for an unmasked slow int */
131         jnz     doreti_intr
132
133         movl    PCPU(spending),%ecx     /* check for a pending software int */
134         cmpl    $0,%ecx
135         jnz     doreti_soft
136
137         testl   $RQF_AST_MASK,PCPU(reqflags) /* any pending ASTs? */
138         jz      2f
139         testl   $PSL_VM,TF_EFLAGS(%esp)
140         jz      1f
141         cmpl    $1,in_vm86call          /* YYY make per 'cpu'? */
142         jnz     doreti_ast
143 1:
144         /* ASTs are only applicable when returning to userland */
145         testb   $SEL_RPL_MASK,TF_CS(%esp)
146         jnz     doreti_ast
147 2:
148         /*
149          * Nothing left to do, finish up.  Interrupts are still disabled.
150          * %eax contains the mask of IRQ's that are not available due to
151          * BGL requirements.  We can only clear RQF_INTPEND if *ALL* pending
152          * interrupts have been processed.
153          */
154         subl    $TDPRI_CRIT,TD_PRI(%ebx)        /* interlocked with cli */
155         testl   %eax,%eax
156         jnz     5f
157         andl    $~RQF_INTPEND,PCPU(reqflags)
158 5:
159         MEXITCOUNT
160         .globl  doreti_popl_fs
161         .globl  doreti_popl_es
162         .globl  doreti_popl_ds
163         .globl  doreti_iret
164         .globl  doreti_syscall_ret
165 doreti_syscall_ret:
166 doreti_popl_fs:
167         popl    %fs
168 doreti_popl_es:
169         popl    %es
170 doreti_popl_ds:
171         popl    %ds
172         popal
173         addl    $8,%esp
174 doreti_iret:
175         iret
176
177         ALIGN_TEXT
178         .globl  doreti_iret_fault
179 doreti_iret_fault:
180         subl    $8,%esp
181         pushal
182         pushl   %ds
183         .globl  doreti_popl_ds_fault
184 doreti_popl_ds_fault:
185         pushl   %es
186         .globl  doreti_popl_es_fault
187 doreti_popl_es_fault:
188         pushl   %fs
189         .globl  doreti_popl_fs_fault
190 doreti_popl_fs_fault:
191         movl    $0,TF_ERR(%esp) /* XXX should be the error code */
192         movl    $T_PROTFLT,TF_TRAPNO(%esp)
193         jmp     alltraps_with_regs_pushed
194
195         /*
196          * FAST interrupt pending.  NOTE: stack context holds frame structure
197          * for fast interrupt procedure, do not do random pushes or pops!
198          */
199         ALIGN_TEXT
200 doreti_fast:
201         andl    PCPU(fpending),%ecx     /* only check fast ints */
202         bsfl    %ecx, %ecx              /* locate the next dispatchable int */
203         btrl    %ecx, PCPU(fpending)    /* is it really still pending? */
204         jnc     doreti_next
205         pushl   %eax                    /* save IRQ mask unavailable for BGL */
206                                         /* NOTE: is also CPL in frame */
207 #ifdef SMP
208         pushl   %ecx                    /* save ecx */
209         call    try_mplock
210         popl    %ecx
211         testl   %eax,%eax
212         jz      1f
213         /* MP lock successful */
214 #endif
215         incl    PCPU(intr_nesting_level)
216         call    *fastunpend(,%ecx,4)
217         decl    PCPU(intr_nesting_level)
218 #ifdef SMP
219         call    rel_mplock
220 #endif
221         popl    %eax
222         jmp     doreti_next
223 1:
224         btsl    %ecx, PCPU(fpending)    /* oops, couldn't get the MP lock */
225         popl    %eax                    /* add to temp. cpl mask to ignore */
226         orl     PCPU(fpending),%eax
227         jmp     doreti_next
228
229         /*
230          *  INTR interrupt pending
231          *
232          *  Temporarily back-out our critical section to allow an interrupt
233          *  preempt us when we schedule it.  Bump intr_nesting_level to
234          *  prevent the switch code from recursing via splz too deeply.
235          */
236         ALIGN_TEXT
237 doreti_intr:
238         andl    PCPU(ipending),%ecx     /* only check normal ints */
239         bsfl    %ecx, %ecx              /* locate the next dispatchable int */
240         btrl    %ecx, PCPU(ipending)    /* is it really still pending? */
241         jnc     doreti_next
242         pushl   %eax
243         pushl   %ecx
244         incl    TD_NEST_COUNT(%ebx)     /* prevent doreti/splz nesting */
245         subl    $TDPRI_CRIT,TD_PRI(%ebx) /* so we can preempt */
246         call    sched_ithd              /* YYY must pull in imasks */
247         addl    $TDPRI_CRIT,TD_PRI(%ebx)
248         decl    TD_NEST_COUNT(%ebx)
249         addl    $4,%esp
250         popl    %eax
251         jmp     doreti_next
252
253         /*
254          *  SOFT interrupt pending
255          *
256          *  Temporarily back-out our critical section to allow an interrupt
257          *  preempt us when we schedule it.  Bump intr_nesting_level to
258          *  prevent the switch code from recursing via splz too deeply.
259          */
260         ALIGN_TEXT
261 doreti_soft:
262         bsfl    %ecx,%ecx               /* locate the next pending softint */
263         btrl    %ecx,PCPU(spending)     /* make sure its still pending */
264         jnc     doreti_next
265         addl    $FIRST_SOFTINT,%ecx     /* actual intr number */
266         pushl   %eax
267         pushl   %ecx
268         incl    TD_NEST_COUNT(%ebx)     /* prevent doreti/splz nesting */
269         subl    $TDPRI_CRIT,TD_PRI(%ebx) /* so we can preempt */
270         call    sched_ithd              /* YYY must pull in imasks */
271         addl    $TDPRI_CRIT,TD_PRI(%ebx)
272         decl    TD_NEST_COUNT(%ebx)
273         addl    $4,%esp
274         popl    %eax
275         jmp     doreti_next
276
277         /*
278          * AST pending.  We clear RQF_AST_SIGNAL automatically, the others
279          * are cleared by the trap as they are processed.
280          *
281          * Temporarily back-out our critical section because trap() can be
282          * a long-winded call, and we want to be more syscall-like.  
283          *
284          * YYY theoretically we can call lwkt_switch directly if all we need
285          * to do is a reschedule.
286          */
287 doreti_ast:
288         andl    $~(RQF_AST_SIGNAL|RQF_AST_UPCALL),PCPU(reqflags)
289         sti
290         movl    %eax,%esi               /* save cpl (can't use stack) */
291         movl    $T_ASTFLT,TF_TRAPNO(%esp)
292         subl    $TDPRI_CRIT,TD_PRI(%ebx)
293 1:      call    trap
294         addl    $TDPRI_CRIT,TD_PRI(%ebx)
295         movl    %esi,%eax               /* restore cpl for loop */
296         jmp     doreti_next
297
298 #ifdef SMP
299         /*
300          * IPIQ message pending.  We clear RQF_IPIQ automatically.
301          */
302 doreti_ipiq:
303         movl    %eax,%esi               /* save cpl (can't use stack) */
304         incl    PCPU(intr_nesting_level)
305         andl    $~RQF_IPIQ,PCPU(reqflags)
306         subl    $8,%esp                 /* add dummy vec and ppl */
307         call    lwkt_process_ipiq_frame
308         addl    $8,%esp
309         decl    PCPU(intr_nesting_level)
310         movl    %esi,%eax               /* restore cpl for loop */
311         jmp     doreti_next
312
313 #endif
314
315         /*
316          * SPLZ() a C callable procedure to dispatch any unmasked pending
317          *        interrupts regardless of critical section nesting.  ASTs
318          *        are not dispatched.
319          *
320          *        Use %eax to track those IRQs that could not be processed
321          *        due to BGL requirements.
322          */
323         SUPERALIGN_TEXT
324
325 ENTRY(splz)
326         pushfl
327         pushl   %ebx
328         movl    PCPU(curthread),%ebx
329         addl    $TDPRI_CRIT,TD_PRI(%ebx)
330         movl    $0,%eax
331
332 splz_next:
333         cli
334         movl    %eax,%ecx               /* ecx = ~CPL */
335         notl    %ecx
336 #ifdef SMP
337         testl   $RQF_IPIQ,PCPU(reqflags)
338         jnz     splz_ipiq
339 #endif
340         testl   PCPU(fpending),%ecx     /* check for an unmasked fast int */
341         jnz     splz_fast
342
343         testl   PCPU(ipending),%ecx
344         jnz     splz_intr
345
346         movl    PCPU(spending),%ecx
347         cmpl    $0,%ecx
348         jnz     splz_soft
349
350         subl    $TDPRI_CRIT,TD_PRI(%ebx)
351
352         /*
353          * Nothing left to do, finish up.  Interrupts are still disabled.
354          * If our mask of IRQs we couldn't process due to BGL requirements
355          * is 0 then there are no pending interrupt sources left and we
356          * can clear RQF_INTPEND.
357          */
358         testl   %eax,%eax
359         jnz     5f
360         andl    $~RQF_INTPEND,PCPU(reqflags)
361 5:
362         popl    %ebx
363         popfl
364         ret
365
366         /*
367          * FAST interrupt pending
368          */
369         ALIGN_TEXT
370 splz_fast:
371         andl    PCPU(fpending),%ecx     /* only check fast ints */
372         bsfl    %ecx, %ecx              /* locate the next dispatchable int */
373         btrl    %ecx, PCPU(fpending)    /* is it really still pending? */
374         jnc     splz_next
375         pushl   %eax
376 #ifdef SMP
377         pushl   %ecx
378         call    try_mplock
379         popl    %ecx
380         testl   %eax,%eax
381         jz      1f
382 #endif
383         incl    PCPU(intr_nesting_level)
384         call    *fastunpend(,%ecx,4)
385         decl    PCPU(intr_nesting_level)
386 #ifdef SMP
387         call    rel_mplock
388 #endif
389         popl    %eax
390         jmp     splz_next
391 1:
392         btsl    %ecx, PCPU(fpending)    /* oops, couldn't get the MP lock */
393         popl    %eax
394         orl     PCPU(fpending),%eax
395         jmp     splz_next
396
397         /*
398          *  INTR interrupt pending
399          *
400          *  Temporarily back-out our critical section to allow the interrupt
401          *  preempt us.
402          */
403         ALIGN_TEXT
404 splz_intr:
405         andl    PCPU(ipending),%ecx     /* only check normal ints */
406         bsfl    %ecx, %ecx              /* locate the next dispatchable int */
407         btrl    %ecx, PCPU(ipending)    /* is it really still pending? */
408         jnc     splz_next
409         sti
410         pushl   %eax
411         pushl   %ecx
412         subl    $TDPRI_CRIT,TD_PRI(%ebx)
413         incl    TD_NEST_COUNT(%ebx)     /* prevent doreti/splz nesting */
414         call    sched_ithd              /* YYY must pull in imasks */
415         addl    $TDPRI_CRIT,TD_PRI(%ebx)
416         decl    TD_NEST_COUNT(%ebx)     /* prevent doreti/splz nesting */
417         addl    $4,%esp
418         popl    %eax
419         jmp     splz_next
420
421         /*
422          *  SOFT interrupt pending
423          *
424          *  Temporarily back-out our critical section to allow the interrupt
425          *  preempt us.
426          */
427         ALIGN_TEXT
428 splz_soft:
429         bsfl    %ecx,%ecx               /* locate the next pending softint */
430         btrl    %ecx,PCPU(spending)     /* make sure its still pending */
431         jnc     splz_next
432         addl    $FIRST_SOFTINT,%ecx     /* actual intr number */
433         sti
434         pushl   %eax
435         pushl   %ecx
436         subl    $TDPRI_CRIT,TD_PRI(%ebx)
437         incl    TD_NEST_COUNT(%ebx)     /* prevent doreti/splz nesting */
438         call    sched_ithd              /* YYY must pull in imasks */
439         addl    $TDPRI_CRIT,TD_PRI(%ebx)
440         decl    TD_NEST_COUNT(%ebx)     /* prevent doreti/splz nesting */
441         addl    $4,%esp
442         popl    %eax
443         jmp     splz_next
444
445 #ifdef SMP
446 splz_ipiq:
447         andl    $~RQF_IPIQ,PCPU(reqflags)
448         pushl   %eax
449         call    lwkt_process_ipiq
450         popl    %eax
451         jmp     splz_next
452 #endif
453