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