kernel: Make SMP support default (and non-optional).
[dragonfly.git] / sys / platform / pc64 / apic / apic_vector.s
1 /*
2  *      from: vector.s, 386BSD 0.1 unknown origin
3  * $FreeBSD: src/sys/i386/isa/apic_vector.s,v 1.47.2.5 2001/09/01 22:33:38 tegge Exp $
4  */
5
6 #if 0
7 #include "opt_auto_eoi.h"
8 #endif
9
10 #include <machine/asmacros.h>
11 #include <machine/lock.h>
12 #include <machine/psl.h>
13 #include <machine/trap.h>
14 #include <machine/segments.h>
15
16 #include <machine_base/icu/icu.h>
17 #include <bus/isa/isa.h>
18
19 #include "assym.s"
20
21 #include "apicreg.h"
22 #include <machine_base/apic/ioapic_ipl.h>
23 #include <machine/intr_machdep.h>
24
25 #ifdef foo
26 /* convert an absolute IRQ# into bitmask */
27 #define IRQ_LBIT(irq_num)       (1UL << (irq_num & 0x3f))
28 #endif
29
30 #define IRQ_SBITS(irq_num)      ((irq_num) & 0x3f)
31
32 /* convert an absolute IRQ# into gd_ipending index */
33 #define IRQ_LIDX(irq_num)       ((irq_num) >> 6)
34
35 #define MPLOCKED     lock ;
36
37 #define APIC_PUSH_FRAME                                                 \
38         PUSH_FRAME ;            /* 15 regs + space for 5 extras */      \
39         movq $0,TF_XFLAGS(%rsp) ;                                       \
40         movq $0,TF_TRAPNO(%rsp) ;                                       \
41         movq $0,TF_ADDR(%rsp) ;                                         \
42         movq $0,TF_FLAGS(%rsp) ;                                        \
43         movq $0,TF_ERR(%rsp) ;                                          \
44         cld ;                                                           \
45
46 /*
47  * JG stale? Warning: POP_FRAME can only be used if there is no chance of a
48  * segment register being changed (e.g. by procfs), which is why syscalls
49  * have to use doreti.
50  */
51 #define APIC_POP_FRAME                                                  \
52         POP_FRAME ;                                                     \
53
54 #define IOAPICADDR(irq_num) \
55         CNAME(ioapic_irqs) + IOAPIC_IRQI_SIZE * (irq_num) + IOAPIC_IRQI_ADDR
56 #define REDIRIDX(irq_num) \
57         CNAME(ioapic_irqs) + IOAPIC_IRQI_SIZE * (irq_num) + IOAPIC_IRQI_IDX
58 #define IOAPICFLAGS(irq_num) \
59         CNAME(ioapic_irqs) + IOAPIC_IRQI_SIZE * (irq_num) + IOAPIC_IRQI_FLAGS
60  
61 #define MASK_IRQ(irq_num)                                               \
62         IOAPIC_IMASK_LOCK ;                     /* into critical reg */ \
63         testl   $IOAPIC_IRQI_FLAG_MASKED, IOAPICFLAGS(irq_num) ;        \
64         jne     7f ;                    /* masked, don't mask */        \
65         orl     $IOAPIC_IRQI_FLAG_MASKED, IOAPICFLAGS(irq_num) ;        \
66                                                 /* set the mask bit */  \
67         movq    IOAPICADDR(irq_num), %rcx ;     /* ioapic addr */       \
68         movl    REDIRIDX(irq_num), %eax ;       /* get the index */     \
69         movl    %eax, (%rcx) ;                  /* write the index */   \
70         orl     $IOART_INTMASK,IOAPIC_WINDOW(%rcx) ;/* set the mask */  \
71 7: ;                                            /* already masked */    \
72         IOAPIC_IMASK_UNLOCK ;                                           \
73
74 /*
75  * Test to see whether we are handling an edge or level triggered INT.
76  *  Level-triggered INTs must still be masked as we don't clear the source,
77  *  and the EOI cycle would cause redundant INTs to occur.
78  */
79 #define MASK_LEVEL_IRQ(irq_num)                                         \
80         testl   $IOAPIC_IRQI_FLAG_LEVEL, IOAPICFLAGS(irq_num) ;         \
81         jz      9f ;                            /* edge, don't mask */  \
82         MASK_IRQ(irq_num) ;                                             \
83 9: ;                                                                    \
84
85 /*
86  * Test to see if the source is currntly masked, clear if so.
87  */
88 #define UNMASK_IRQ(irq_num)                                     \
89         cmpl    $0,%eax ;                                               \
90         jnz     8f ;                                                    \
91         IOAPIC_IMASK_LOCK ;                     /* into critical reg */ \
92         testl   $IOAPIC_IRQI_FLAG_MASKED, IOAPICFLAGS(irq_num) ;        \
93         je      7f ;                    /* bit clear, not masked */     \
94         andl    $~IOAPIC_IRQI_FLAG_MASKED, IOAPICFLAGS(irq_num) ;       \
95                                                 /* clear mask bit */    \
96         movq    IOAPICADDR(irq_num),%rcx ;      /* ioapic addr */       \
97         movl    REDIRIDX(irq_num), %eax ;       /* get the index */     \
98         movl    %eax,(%rcx) ;                   /* write the index */   \
99         andl    $~IOART_INTMASK,IOAPIC_WINDOW(%rcx) ;/* clear the mask */ \
100 7: ;                                                                    \
101         IOAPIC_IMASK_UNLOCK ;                                           \
102 8: ;                                                                    \
103
104 /*
105  * Interrupt call handlers run in the following sequence:
106  *
107  *      - Push the trap frame required by doreti
108  *      - Mask the interrupt and reenable its source
109  *      - If we cannot take the interrupt set its ipending bit and
110  *        doreti.
111  *      - If we can take the interrupt clear its ipending bit,
112  *        call the handler, then unmask and doreti.
113  *
114  * YYY can cache gd base opitner instead of using hidden %fs prefixes.
115  */
116
117 #define INTR_HANDLER(irq_num)                                           \
118         .text ;                                                         \
119         SUPERALIGN_TEXT ;                                               \
120 IDTVEC(ioapic_intr##irq_num) ;                                          \
121         APIC_PUSH_FRAME ;                                               \
122         FAKE_MCOUNT(TF_RIP(%rsp)) ;                                     \
123         MASK_LEVEL_IRQ(irq_num) ;                                       \
124         movq    lapic, %rax ;                                           \
125         movl    $0, LA_EOI(%rax) ;                                      \
126         movq    PCPU(curthread),%rbx ;                                  \
127         testl   $-1,TD_NEST_COUNT(%rbx) ;                               \
128         jne     1f ;                                                    \
129         testl   $-1,TD_CRITCOUNT(%rbx) ;                                \
130         je      2f ;                                                    \
131 1: ;                                                                    \
132         /* in critical section, make interrupt pending */               \
133         /* set the pending bit and return, leave interrupt masked */    \
134         movq    $1,%rcx ;                                               \
135         shlq    $IRQ_SBITS(irq_num),%rcx ;                              \
136         movq    $IRQ_LIDX(irq_num),%rdx ;                               \
137         orq     %rcx,PCPU_E8(ipending,%rdx) ;                           \
138         orl     $RQF_INTPEND,PCPU(reqflags) ;                           \
139         jmp     5f ;                                                    \
140 2: ;                                                                    \
141         /* clear pending bit, run handler */                            \
142         movq    $1,%rcx ;                                               \
143         shlq    $IRQ_SBITS(irq_num),%rcx ;                              \
144         notq    %rcx ;                                                  \
145         movq    $IRQ_LIDX(irq_num),%rdx ;                               \
146         andq    %rcx,PCPU_E8(ipending,%rdx) ;                           \
147         pushq   $irq_num ;              /* trapframe -> intrframe */    \
148         movq    %rsp, %rdi ;            /* pass frame by reference */   \
149         incl    TD_CRITCOUNT(%rbx) ;                                    \
150         sti ;                                                           \
151         call    ithread_fast_handler ;  /* returns 0 to unmask */       \
152         decl    TD_CRITCOUNT(%rbx) ;                                    \
153         addq    $8, %rsp ;              /* intrframe -> trapframe */    \
154         UNMASK_IRQ(irq_num) ;                                           \
155 5: ;                                                                    \
156         MEXITCOUNT ;                                                    \
157         jmp     doreti ;                                                \
158
159 /*
160  * Handle "spurious INTerrupts".
161  *
162  * NOTE: This is different than the "spurious INTerrupt" generated by an
163  *       8259 PIC for missing INTs.  See the APIC documentation for details.
164  *       This routine should NOT do an 'EOI' cycle.
165  *
166  * NOTE: Even though we don't do anything here we must still swapgs if
167  *       coming from a user frame in case the iretq faults... just use
168  *       the nominal APIC_PUSH_FRAME sequence to get it done.
169  */
170         .text
171         SUPERALIGN_TEXT
172         .globl Xspuriousint
173 Xspuriousint:
174         APIC_PUSH_FRAME
175         /* No EOI cycle used here */
176         FAKE_MCOUNT(TF_RIP(%rsp))
177         MEXITCOUNT
178         APIC_POP_FRAME
179         jmp     doreti_iret
180
181 /*
182  * Handle TLB shootdowns.
183  *
184  * NOTE: interrupts are left disabled.
185  */
186         .text
187         SUPERALIGN_TEXT
188         .globl  Xinvltlb
189 Xinvltlb:
190         APIC_PUSH_FRAME
191         movq    lapic, %rax
192         movl    $0, LA_EOI(%rax)        /* End Of Interrupt to APIC */
193         FAKE_MCOUNT(TF_RIP(%rsp))
194         subq    $8,%rsp                 /* make same as interrupt frame */
195         movq    %rsp,%rdi               /* pass frame by reference */
196         call    smp_invltlb_intr
197         addq    $8,%rsp                 /* turn into trapframe */
198         MEXITCOUNT
199         APIC_POP_FRAME
200         jmp     doreti_iret
201
202 /*
203  * Executed by a CPU when it receives an Xcpustop IPI from another CPU,
204  *
205  *  - We cannot call doreti
206  *  - Signals its receipt.
207  *  - Waits for permission to restart.
208  *  - Processing pending IPIQ events while waiting.
209  *  - Signals its restart.
210  */
211
212         .text
213         SUPERALIGN_TEXT
214         .globl Xcpustop
215 Xcpustop:
216         APIC_PUSH_FRAME
217         movq    lapic, %rax
218         movl    $0, LA_EOI(%rax)        /* End Of Interrupt to APIC */
219
220         movl    PCPU(cpuid), %eax
221         imull   $PCB_SIZE, %eax
222         leaq    CNAME(stoppcbs), %rdi
223         addq    %rax, %rdi
224         call    CNAME(savectx)          /* Save process context */
225
226         movslq  PCPU(cpuid), %rax
227
228         /*
229          * Indicate that we have stopped and loop waiting for permission
230          * to start again.  We must still process IPI events while in a
231          * stopped state.
232          *
233          * Interrupts must remain enabled for non-IPI'd per-cpu interrupts
234          * (e.g. Xtimer, Xinvltlb).
235          */
236         MPLOCKED
237         btsq    %rax, stopped_cpus      /* stopped_cpus |= (1<<id) */
238         sti
239 1:
240         andl    $~RQF_IPIQ,PCPU(reqflags)
241         pushq   %rax
242         call    lwkt_smp_stopped
243         popq    %rax
244         pause
245         btq     %rax, started_cpus      /* while (!(started_cpus & (1<<id))) */
246         jnc     1b
247
248         MPLOCKED
249         btrq    %rax, started_cpus      /* started_cpus &= ~(1<<id) */
250         MPLOCKED
251         btrq    %rax, stopped_cpus      /* stopped_cpus &= ~(1<<id) */
252
253         testq   %rax, %rax
254         jnz     2f
255
256         movq    CNAME(cpustop_restartfunc), %rax
257         testq   %rax, %rax
258         jz      2f
259         movq    $0, CNAME(cpustop_restartfunc)  /* One-shot */
260
261         call    *%rax
262 2:
263         MEXITCOUNT
264         APIC_POP_FRAME
265         jmp     doreti_iret
266
267         /*
268          * For now just have one ipiq IPI, but what we really want is
269          * to have one for each source cpu to the APICs don't get stalled
270          * backlogging the requests.
271          */
272         .text
273         SUPERALIGN_TEXT
274         .globl Xipiq
275 Xipiq:
276         APIC_PUSH_FRAME
277         movq    lapic, %rax
278         movl    $0, LA_EOI(%rax)        /* End Of Interrupt to APIC */
279         FAKE_MCOUNT(TF_RIP(%rsp))
280
281         incl    PCPU(cnt) + V_IPI
282         movq    PCPU(curthread),%rbx
283         testl   $-1,TD_CRITCOUNT(%rbx)
284         jne     1f
285         subq    $8,%rsp                 /* make same as interrupt frame */
286         movq    %rsp,%rdi               /* pass frame by reference */
287         incl    PCPU(intr_nesting_level)
288         incl    TD_CRITCOUNT(%rbx)
289         sti
290         call    lwkt_process_ipiq_frame
291         decl    TD_CRITCOUNT(%rbx)
292         decl    PCPU(intr_nesting_level)
293         addq    $8,%rsp                 /* turn into trapframe */
294         MEXITCOUNT
295         jmp     doreti
296 1:
297         orl     $RQF_IPIQ,PCPU(reqflags)
298         MEXITCOUNT
299         APIC_POP_FRAME
300         jmp     doreti_iret
301
302         .text
303         SUPERALIGN_TEXT
304         .globl Xtimer
305 Xtimer:
306         APIC_PUSH_FRAME
307         movq    lapic, %rax
308         movl    $0, LA_EOI(%rax)        /* End Of Interrupt to APIC */
309         FAKE_MCOUNT(TF_RIP(%rsp))
310
311         subq    $8,%rsp                 /* make same as interrupt frame */
312         movq    %rsp,%rdi               /* pass frame by reference */
313         call    lapic_timer_always
314         addq    $8,%rsp                 /* turn into trapframe */
315
316         incl    PCPU(cnt) + V_TIMER
317         movq    TF_RIP(%rsp),%rbx       /* sample addr before checking crit */
318         movq    %rbx,PCPU(sample_pc)
319         movq    PCPU(curthread),%rbx
320         testl   $-1,TD_CRITCOUNT(%rbx)
321         jne     1f
322         testl   $-1,TD_NEST_COUNT(%rbx)
323         jne     1f
324         subq    $8,%rsp                 /* make same as interrupt frame */
325         movq    %rsp,%rdi               /* pass frame by reference */
326         incl    PCPU(intr_nesting_level)
327         incl    TD_CRITCOUNT(%rbx)
328         sti
329         call    lapic_timer_process_frame
330         decl    TD_CRITCOUNT(%rbx)
331         decl    PCPU(intr_nesting_level)
332         addq    $8,%rsp                 /* turn into trapframe */
333         MEXITCOUNT
334         jmp     doreti
335 1:
336         orl     $RQF_TIMER,PCPU(reqflags)
337         MEXITCOUNT
338         APIC_POP_FRAME
339         jmp     doreti_iret
340
341 MCOUNT_LABEL(bintr)
342         INTR_HANDLER(0)
343         INTR_HANDLER(1)
344         INTR_HANDLER(2)
345         INTR_HANDLER(3)
346         INTR_HANDLER(4)
347         INTR_HANDLER(5)
348         INTR_HANDLER(6)
349         INTR_HANDLER(7)
350         INTR_HANDLER(8)
351         INTR_HANDLER(9)
352         INTR_HANDLER(10)
353         INTR_HANDLER(11)
354         INTR_HANDLER(12)
355         INTR_HANDLER(13)
356         INTR_HANDLER(14)
357         INTR_HANDLER(15)
358         INTR_HANDLER(16)
359         INTR_HANDLER(17)
360         INTR_HANDLER(18)
361         INTR_HANDLER(19)
362         INTR_HANDLER(20)
363         INTR_HANDLER(21)
364         INTR_HANDLER(22)
365         INTR_HANDLER(23)
366         INTR_HANDLER(24)
367         INTR_HANDLER(25)
368         INTR_HANDLER(26)
369         INTR_HANDLER(27)
370         INTR_HANDLER(28)
371         INTR_HANDLER(29)
372         INTR_HANDLER(30)
373         INTR_HANDLER(31)
374         INTR_HANDLER(32)
375         INTR_HANDLER(33)
376         INTR_HANDLER(34)
377         INTR_HANDLER(35)
378         INTR_HANDLER(36)
379         INTR_HANDLER(37)
380         INTR_HANDLER(38)
381         INTR_HANDLER(39)
382         INTR_HANDLER(40)
383         INTR_HANDLER(41)
384         INTR_HANDLER(42)
385         INTR_HANDLER(43)
386         INTR_HANDLER(44)
387         INTR_HANDLER(45)
388         INTR_HANDLER(46)
389         INTR_HANDLER(47)
390         INTR_HANDLER(48)
391         INTR_HANDLER(49)
392         INTR_HANDLER(50)
393         INTR_HANDLER(51)
394         INTR_HANDLER(52)
395         INTR_HANDLER(53)
396         INTR_HANDLER(54)
397         INTR_HANDLER(55)
398         INTR_HANDLER(56)
399         INTR_HANDLER(57)
400         INTR_HANDLER(58)
401         INTR_HANDLER(59)
402         INTR_HANDLER(60)
403         INTR_HANDLER(61)
404         INTR_HANDLER(62)
405         INTR_HANDLER(63)
406         INTR_HANDLER(64)
407         INTR_HANDLER(65)
408         INTR_HANDLER(66)
409         INTR_HANDLER(67)
410         INTR_HANDLER(68)
411         INTR_HANDLER(69)
412         INTR_HANDLER(70)
413         INTR_HANDLER(71)
414         INTR_HANDLER(72)
415         INTR_HANDLER(73)
416         INTR_HANDLER(74)
417         INTR_HANDLER(75)
418         INTR_HANDLER(76)
419         INTR_HANDLER(77)
420         INTR_HANDLER(78)
421         INTR_HANDLER(79)
422         INTR_HANDLER(80)
423         INTR_HANDLER(81)
424         INTR_HANDLER(82)
425         INTR_HANDLER(83)
426         INTR_HANDLER(84)
427         INTR_HANDLER(85)
428         INTR_HANDLER(86)
429         INTR_HANDLER(87)
430         INTR_HANDLER(88)
431         INTR_HANDLER(89)
432         INTR_HANDLER(90)
433         INTR_HANDLER(91)
434         INTR_HANDLER(92)
435         INTR_HANDLER(93)
436         INTR_HANDLER(94)
437         INTR_HANDLER(95)
438         INTR_HANDLER(96)
439         INTR_HANDLER(97)
440         INTR_HANDLER(98)
441         INTR_HANDLER(99)
442         INTR_HANDLER(100)
443         INTR_HANDLER(101)
444         INTR_HANDLER(102)
445         INTR_HANDLER(103)
446         INTR_HANDLER(104)
447         INTR_HANDLER(105)
448         INTR_HANDLER(106)
449         INTR_HANDLER(107)
450         INTR_HANDLER(108)
451         INTR_HANDLER(109)
452         INTR_HANDLER(110)
453         INTR_HANDLER(111)
454         INTR_HANDLER(112)
455         INTR_HANDLER(113)
456         INTR_HANDLER(114)
457         INTR_HANDLER(115)
458         INTR_HANDLER(116)
459         INTR_HANDLER(117)
460         INTR_HANDLER(118)
461         INTR_HANDLER(119)
462         INTR_HANDLER(120)
463         INTR_HANDLER(121)
464         INTR_HANDLER(122)
465         INTR_HANDLER(123)
466         INTR_HANDLER(124)
467         INTR_HANDLER(125)
468         INTR_HANDLER(126)
469         INTR_HANDLER(127)
470         INTR_HANDLER(128)
471         INTR_HANDLER(129)
472         INTR_HANDLER(130)
473         INTR_HANDLER(131)
474         INTR_HANDLER(132)
475         INTR_HANDLER(133)
476         INTR_HANDLER(134)
477         INTR_HANDLER(135)
478         INTR_HANDLER(136)
479         INTR_HANDLER(137)
480         INTR_HANDLER(138)
481         INTR_HANDLER(139)
482         INTR_HANDLER(140)
483         INTR_HANDLER(141)
484         INTR_HANDLER(142)
485         INTR_HANDLER(143)
486         INTR_HANDLER(144)
487         INTR_HANDLER(145)
488         INTR_HANDLER(146)
489         INTR_HANDLER(147)
490         INTR_HANDLER(148)
491         INTR_HANDLER(149)
492         INTR_HANDLER(150)
493         INTR_HANDLER(151)
494         INTR_HANDLER(152)
495         INTR_HANDLER(153)
496         INTR_HANDLER(154)
497         INTR_HANDLER(155)
498         INTR_HANDLER(156)
499         INTR_HANDLER(157)
500         INTR_HANDLER(158)
501         INTR_HANDLER(159)
502         INTR_HANDLER(160)
503         INTR_HANDLER(161)
504         INTR_HANDLER(162)
505         INTR_HANDLER(163)
506         INTR_HANDLER(164)
507         INTR_HANDLER(165)
508         INTR_HANDLER(166)
509         INTR_HANDLER(167)
510         INTR_HANDLER(168)
511         INTR_HANDLER(169)
512         INTR_HANDLER(170)
513         INTR_HANDLER(171)
514         INTR_HANDLER(172)
515         INTR_HANDLER(173)
516         INTR_HANDLER(174)
517         INTR_HANDLER(175)
518         INTR_HANDLER(176)
519         INTR_HANDLER(177)
520         INTR_HANDLER(178)
521         INTR_HANDLER(179)
522         INTR_HANDLER(180)
523         INTR_HANDLER(181)
524         INTR_HANDLER(182)
525         INTR_HANDLER(183)
526         INTR_HANDLER(184)
527         INTR_HANDLER(185)
528         INTR_HANDLER(186)
529         INTR_HANDLER(187)
530         INTR_HANDLER(188)
531         INTR_HANDLER(189)
532         INTR_HANDLER(190)
533         INTR_HANDLER(191)
534 MCOUNT_LABEL(eintr)
535
536         .data
537
538 /* variables used by stop_cpus()/restart_cpus()/Xcpustop */
539         .globl stopped_cpus, started_cpus
540 stopped_cpus:
541         .quad   0
542 started_cpus:
543         .quad   0
544
545         .globl CNAME(cpustop_restartfunc)
546 CNAME(cpustop_restartfunc):
547         .quad 0
548                 
549         .text
550