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