pc32: Split out isa_intr.h and move isa/intr_machdep.h to include/
[dragonfly.git] / sys / platform / pc32 / apic / apic_vector.s
CommitLineData
984263bc
MD
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
06f5be02
MD
6#include "opt_auto_eoi.h"
7
8#include <machine/asmacros.h>
06f5be02
MD
9#include <machine/lock.h>
10#include <machine/psl.h>
11#include <machine/trap.h>
06f5be02 12
a9295349 13#include <machine_base/icu/icu.h>
21ce0dfa 14#include <bus/isa/isa.h>
06f5be02
MD
15
16#include "assym.s"
984263bc 17
bdc560a1
MD
18#include "apicreg.h"
19#include "apic_ipl.h"
984263bc 20#include <machine/smp.h>
87cf6827 21#include <machine/intr_machdep.h>
984263bc 22
c263294b
SZ
23/* convert an absolute IRQ# into bitmask */
24#define IRQ_LBIT(irq_num) (1 << ((irq_num) & 0x1f))
984263bc 25
c263294b
SZ
26/* convert an absolute IRQ# into ipending index */
27#define IRQ_LIDX(irq_num) ((irq_num) >> 5)
984263bc 28
97359a5b
MD
29#ifdef SMP
30#define MPLOCKED lock ;
31#else
32#define MPLOCKED
33#endif
34
984263bc 35/*
8a8d5d85
MD
36 * Push an interrupt frame in a format acceptable to doreti, reload
37 * the segment registers for the kernel.
984263bc
MD
38 */
39#define PUSH_FRAME \
40 pushl $0 ; /* dummy error code */ \
41 pushl $0 ; /* dummy trap type */ \
4e7c41c5 42 pushl $0 ; /* dummy xflags type */ \
984263bc
MD
43 pushal ; \
44 pushl %ds ; /* save data and extra segments ... */ \
45 pushl %es ; \
8a8d5d85 46 pushl %fs ; \
4e7c41c5 47 pushl %gs ; \
c885c20e 48 cld ; \
8a8d5d85
MD
49 mov $KDSEL,%ax ; \
50 mov %ax,%ds ; \
51 mov %ax,%es ; \
4e7c41c5 52 mov %ax,%gs ; \
8a8d5d85
MD
53 mov $KPSEL,%ax ; \
54 mov %ax,%fs ; \
984263bc 55
8a8d5d85
MD
56/*
57 * Warning: POP_FRAME can only be used if there is no chance of a
58 * segment register being changed (e.g. by procfs), which is why syscalls
59 * have to use doreti.
60 */
984263bc 61#define POP_FRAME \
4e7c41c5 62 popl %gs ; \
984263bc
MD
63 popl %fs ; \
64 popl %es ; \
65 popl %ds ; \
66 popal ; \
4e7c41c5 67 addl $3*4,%esp ; /* dummy xflags, trap & error codes */ \
8a8d5d85 68
3d911e0a
SZ
69#define IOAPICADDR(irq_num) \
70 CNAME(int_to_apicintpin) + IOAPIC_IM_SIZE * (irq_num) + IOAPIC_IM_ADDR
71#define REDIRIDX(irq_num) \
72 CNAME(int_to_apicintpin) + IOAPIC_IM_SIZE * (irq_num) + IOAPIC_IM_ENTIDX
0f546930
SZ
73#define IOAPICFLAGS(irq_num) \
74 CNAME(int_to_apicintpin) + IOAPIC_IM_SIZE * (irq_num) + IOAPIC_IM_FLAGS
8a8d5d85 75
984263bc 76#define MASK_IRQ(irq_num) \
97359a5b 77 APIC_IMASK_LOCK ; /* into critical reg */ \
ea689d1c 78 testl $IOAPIC_IM_FLAG_MASKED, IOAPICFLAGS(irq_num) ; \
984263bc 79 jne 7f ; /* masked, don't mask */ \
ea689d1c
SZ
80 orl $IOAPIC_IM_FLAG_MASKED, IOAPICFLAGS(irq_num) ; \
81 /* set the mask bit */ \
984263bc
MD
82 movl IOAPICADDR(irq_num), %ecx ; /* ioapic addr */ \
83 movl REDIRIDX(irq_num), %eax ; /* get the index */ \
84 movl %eax, (%ecx) ; /* write the index */ \
bda48b43 85 orl $IOART_INTMASK,IOAPIC_WINDOW(%ecx) ;/* set the mask */ \
984263bc 867: ; /* already masked */ \
97359a5b 87 APIC_IMASK_UNLOCK ; \
8a8d5d85 88
984263bc
MD
89/*
90 * Test to see whether we are handling an edge or level triggered INT.
91 * Level-triggered INTs must still be masked as we don't clear the source,
92 * and the EOI cycle would cause redundant INTs to occur.
93 */
94#define MASK_LEVEL_IRQ(irq_num) \
0f546930 95 testl $IOAPIC_IM_FLAG_LEVEL, IOAPICFLAGS(irq_num) ; \
984263bc
MD
96 jz 9f ; /* edge, don't mask */ \
97 MASK_IRQ(irq_num) ; \
8a8d5d85 989: ; \
984263bc 99
984263bc
MD
100/*
101 * Test to see if the source is currntly masked, clear if so.
102 */
ea689d1c 103#define UNMASK_IRQ(irq_num) \
477d3c1c
MD
104 cmpl $0,%eax ; \
105 jnz 8f ; \
97359a5b 106 APIC_IMASK_LOCK ; /* into critical reg */ \
ea689d1c 107 testl $IOAPIC_IM_FLAG_MASKED, IOAPICFLAGS(irq_num) ; \
984263bc 108 je 7f ; /* bit clear, not masked */ \
ea689d1c
SZ
109 andl $~IOAPIC_IM_FLAG_MASKED, IOAPICFLAGS(irq_num) ; \
110 /* clear mask bit */ \
984263bc
MD
111 movl IOAPICADDR(irq_num),%ecx ; /* ioapic addr */ \
112 movl REDIRIDX(irq_num), %eax ; /* get the index */ \
113 movl %eax,(%ecx) ; /* write the index */ \
bda48b43 114 andl $~IOART_INTMASK,IOAPIC_WINDOW(%ecx) ;/* clear the mask */ \
984263bc 1157: ; \
97359a5b 116 APIC_IMASK_UNLOCK ; \
477d3c1c 1178: ; \
984263bc 118
30c5f287 119#ifdef SMP /* APIC-IO */
97359a5b 120
8a8d5d85 121/*
081be8a5 122 * Interrupt call handlers run in the following sequence:
8a8d5d85
MD
123 *
124 * - Push the trap frame required by doreti
125 * - Mask the interrupt and reenable its source
c263294b 126 * - If we cannot take the interrupt set its ipending bit and
b5d16701 127 * doreti.
c263294b 128 * - If we can take the interrupt clear its ipending bit,
8a8d5d85
MD
129 * call the handler, then unmask and doreti.
130 *
131 * YYY can cache gd base opitner instead of using hidden %fs prefixes.
132 */
133
20a6b6c7 134#define INTR_HANDLER(irq_num) \
8a8d5d85
MD
135 .text ; \
136 SUPERALIGN_TEXT ; \
20a6b6c7 137IDTVEC(apic_intr##irq_num) ; \
8a8d5d85 138 PUSH_FRAME ; \
4e7c41c5 139 FAKE_MCOUNT(15*4(%esp)) ; \
8a8d5d85 140 MASK_LEVEL_IRQ(irq_num) ; \
35408d22 141 movl $0, lapic_eoi ; \
8a8d5d85 142 movl PCPU(curthread),%ebx ; \
38787eef 143 movl $0,%eax ; /* CURRENT CPL IN FRAME (REMOVED) */ \
984263bc 144 pushl %eax ; \
1be5027b
MD
145 testl $-1,TD_NEST_COUNT(%ebx) ; \
146 jne 1f ; \
f9235b6d
MD
147 testl $-1,TD_CRITCOUNT(%ebx) ; \
148 je 2f ; \
8a8d5d85 1491: ; \
545a1cd3 150 /* in critical section, make interrupt pending */ \
8a8d5d85 151 /* set the pending bit and return, leave interrupt masked */ \
c263294b
SZ
152 movl $IRQ_LIDX(irq_num),%edx ; \
153 orl $IRQ_LBIT(irq_num),PCPU_E4(ipending,%edx) ; \
235957ed 154 orl $RQF_INTPEND,PCPU(reqflags) ; \
8a8d5d85
MD
155 jmp 5f ; \
1562: ; \
157 /* clear pending bit, run handler */ \
c263294b
SZ
158 movl $IRQ_LIDX(irq_num),%edx ; \
159 andl $~IRQ_LBIT(irq_num),PCPU_E4(ipending,%edx) ; \
477d3c1c 160 pushl $irq_num ; \
c7eb0589 161 pushl %esp ; /* pass frame by reference */ \
f9235b6d 162 incl TD_CRITCOUNT(%ebx) ; \
2d910aaf 163 sti ; \
477d3c1c 164 call ithread_fast_handler ; /* returns 0 to unmask */ \
f9235b6d 165 decl TD_CRITCOUNT(%ebx) ; \
c7eb0589 166 addl $8, %esp ; \
8a8d5d85
MD
167 UNMASK_IRQ(irq_num) ; \
1685: ; \
169 MEXITCOUNT ; \
170 jmp doreti ; \
984263bc 171
97359a5b
MD
172#endif
173
984263bc
MD
174/*
175 * Handle "spurious INTerrupts".
176 * Notes:
177 * This is different than the "spurious INTerrupt" generated by an
178 * 8259 PIC for missing INTs. See the APIC documentation for details.
179 * This routine should NOT do an 'EOI' cycle.
180 */
181 .text
182 SUPERALIGN_TEXT
2954c92f
MD
183 .globl Xspuriousint
184Xspuriousint:
984263bc
MD
185
186 /* No EOI cycle used here */
187
188 iret
189
190
191/*
192 * Handle TLB shootdowns.
2d910aaf
MD
193 *
194 * NOTE: Interrupts remain disabled.
984263bc
MD
195 */
196 .text
197 SUPERALIGN_TEXT
8a8d5d85
MD
198 .globl Xinvltlb
199Xinvltlb:
7d4d6fdb 200 PUSH_FRAME
984263bc 201 movl $0, lapic_eoi /* End Of Interrupt to APIC */
7d4d6fdb 202 FAKE_MCOUNT(15*4(%esp))
984263bc 203
7d4d6fdb
MD
204 subl $8,%esp /* make same as interrupt frame */
205 pushl %esp /* pass frame by reference */
206 call smp_invltlb_intr
207 addl $12,%esp
984263bc 208
7d4d6fdb
MD
209 MEXITCOUNT
210 jmp doreti_syscall_ret
984263bc 211
984263bc 212/*
984263bc
MD
213 * Executed by a CPU when it receives an Xcpustop IPI from another CPU,
214 *
215 * - Signals its receipt.
216 * - Waits for permission to restart.
bd8015ca 217 * - Processing pending IPIQ events while waiting.
984263bc
MD
218 * - Signals its restart.
219 */
220
221 .text
222 SUPERALIGN_TEXT
2954c92f
MD
223 .globl Xcpustop
224Xcpustop:
984263bc
MD
225 pushl %ebp
226 movl %esp, %ebp
227 pushl %eax
228 pushl %ecx
229 pushl %edx
230 pushl %ds /* save current data segment */
231 pushl %fs
232
233 movl $KDSEL, %eax
234 mov %ax, %ds /* use KERNEL data segment */
235 movl $KPSEL, %eax
236 mov %ax, %fs
237
238 movl $0, lapic_eoi /* End Of Interrupt to APIC */
239
2954c92f 240 movl PCPU(cpuid), %eax
984263bc
MD
241 imull $PCB_SIZE, %eax
242 leal CNAME(stoppcbs)(%eax), %eax
243 pushl %eax
244 call CNAME(savectx) /* Save process context */
245 addl $4, %esp
246
247
2954c92f 248 movl PCPU(cpuid), %eax
984263bc 249
bd8015ca
MD
250 /*
251 * Indicate that we have stopped and loop waiting for permission
252 * to start again. We must still process IPI events while in a
253 * stopped state.
2d910aaf
MD
254 *
255 * Interrupts must remain enabled for non-IPI'd per-cpu interrupts
256 * (e.g. Xtimer, Xinvltlb).
bd8015ca 257 */
97359a5b 258 MPLOCKED
2954c92f 259 btsl %eax, stopped_cpus /* stopped_cpus |= (1<<id) */
2d910aaf 260 sti
984263bc 2611:
bd8015ca
MD
262 andl $~RQF_IPIQ,PCPU(reqflags)
263 pushl %eax
264 call lwkt_smp_stopped
265 popl %eax
2954c92f 266 btl %eax, started_cpus /* while (!(started_cpus & (1<<id))) */
984263bc
MD
267 jnc 1b
268
97359a5b 269 MPLOCKED
2954c92f 270 btrl %eax, started_cpus /* started_cpus &= ~(1<<id) */
97359a5b 271 MPLOCKED
2954c92f 272 btrl %eax, stopped_cpus /* stopped_cpus &= ~(1<<id) */
984263bc
MD
273
274 test %eax, %eax
275 jnz 2f
276
277 movl CNAME(cpustop_restartfunc), %eax
278 test %eax, %eax
279 jz 2f
280 movl $0, CNAME(cpustop_restartfunc) /* One-shot */
281
282 call *%eax
2832:
284 popl %fs
285 popl %ds /* restore previous data segment */
286 popl %edx
287 popl %ecx
288 popl %eax
289 movl %ebp, %esp
290 popl %ebp
291 iret
292
96728c05
MD
293 /*
294 * For now just have one ipiq IPI, but what we really want is
295 * to have one for each source cpu to the APICs don't get stalled
296 * backlogging the requests.
297 */
298 .text
299 SUPERALIGN_TEXT
300 .globl Xipiq
301Xipiq:
302 PUSH_FRAME
303 movl $0, lapic_eoi /* End Of Interrupt to APIC */
4e7c41c5 304 FAKE_MCOUNT(15*4(%esp))
96728c05 305
b785701b 306 incl PCPU(cnt) + V_IPI
96728c05 307 movl PCPU(curthread),%ebx
f9235b6d
MD
308 testl $-1,TD_CRITCOUNT(%ebx)
309 jne 1f
88c4d2f6 310 subl $8,%esp /* make same as interrupt frame */
c7eb0589 311 pushl %esp /* pass frame by reference */
03aa8d99 312 incl PCPU(intr_nesting_level)
f9235b6d 313 incl TD_CRITCOUNT(%ebx)
2d910aaf 314 sti
88c4d2f6 315 call lwkt_process_ipiq_frame
f9235b6d 316 decl TD_CRITCOUNT(%ebx)
03aa8d99 317 decl PCPU(intr_nesting_level)
c7eb0589 318 addl $12,%esp
38787eef 319 pushl $0 /* CPL for frame (REMOVED) */
96728c05
MD
320 MEXITCOUNT
321 jmp doreti
3221:
235957ed 323 orl $RQF_IPIQ,PCPU(reqflags)
96728c05 324 MEXITCOUNT
7d4d6fdb 325 jmp doreti_syscall_ret
984263bc 326
78ea5a2a
SZ
327 .text
328 SUPERALIGN_TEXT
329 .globl Xtimer
330Xtimer:
331 PUSH_FRAME
332 movl $0, lapic_eoi /* End Of Interrupt to APIC */
333 FAKE_MCOUNT(15*4(%esp))
334
b785701b 335 incl PCPU(cnt) + V_TIMER
78ea5a2a 336 movl PCPU(curthread),%ebx
f9235b6d
MD
337 testl $-1,TD_CRITCOUNT(%ebx)
338 jne 1f
5119f32b
SZ
339 testl $-1,TD_NEST_COUNT(%ebx)
340 jne 1f
78ea5a2a
SZ
341 subl $8,%esp /* make same as interrupt frame */
342 pushl %esp /* pass frame by reference */
343 incl PCPU(intr_nesting_level)
f9235b6d 344 incl TD_CRITCOUNT(%ebx)
2d910aaf 345 sti
78ea5a2a 346 call lapic_timer_process_frame
f9235b6d 347 decl TD_CRITCOUNT(%ebx)
78ea5a2a
SZ
348 decl PCPU(intr_nesting_level)
349 addl $12,%esp
350 pushl $0 /* CPL for frame (REMOVED) */
351 MEXITCOUNT
352 jmp doreti
3531:
354 orl $RQF_TIMER,PCPU(reqflags)
355 MEXITCOUNT
7d4d6fdb 356 jmp doreti_syscall_ret
78ea5a2a 357
30c5f287 358#ifdef SMP /* APIC-IO */
97359a5b 359
984263bc 360MCOUNT_LABEL(bintr)
20a6b6c7
SZ
361 INTR_HANDLER(0)
362 INTR_HANDLER(1)
363 INTR_HANDLER(2)
364 INTR_HANDLER(3)
365 INTR_HANDLER(4)
366 INTR_HANDLER(5)
367 INTR_HANDLER(6)
368 INTR_HANDLER(7)
369 INTR_HANDLER(8)
370 INTR_HANDLER(9)
371 INTR_HANDLER(10)
372 INTR_HANDLER(11)
373 INTR_HANDLER(12)
374 INTR_HANDLER(13)
375 INTR_HANDLER(14)
376 INTR_HANDLER(15)
377 INTR_HANDLER(16)
378 INTR_HANDLER(17)
379 INTR_HANDLER(18)
380 INTR_HANDLER(19)
381 INTR_HANDLER(20)
382 INTR_HANDLER(21)
383 INTR_HANDLER(22)
384 INTR_HANDLER(23)
385 INTR_HANDLER(24)
386 INTR_HANDLER(25)
387 INTR_HANDLER(26)
388 INTR_HANDLER(27)
389 INTR_HANDLER(28)
390 INTR_HANDLER(29)
391 INTR_HANDLER(30)
392 INTR_HANDLER(31)
c571da4a
SZ
393 INTR_HANDLER(32)
394 INTR_HANDLER(33)
395 INTR_HANDLER(34)
396 INTR_HANDLER(35)
397 INTR_HANDLER(36)
398 INTR_HANDLER(37)
399 INTR_HANDLER(38)
400 INTR_HANDLER(39)
401 INTR_HANDLER(40)
402 INTR_HANDLER(41)
403 INTR_HANDLER(42)
404 INTR_HANDLER(43)
405 INTR_HANDLER(44)
406 INTR_HANDLER(45)
407 INTR_HANDLER(46)
408 INTR_HANDLER(47)
409 INTR_HANDLER(48)
410 INTR_HANDLER(49)
411 INTR_HANDLER(50)
412 INTR_HANDLER(51)
413 INTR_HANDLER(52)
414 INTR_HANDLER(53)
415 INTR_HANDLER(54)
416 INTR_HANDLER(55)
417 INTR_HANDLER(56)
418 INTR_HANDLER(57)
419 INTR_HANDLER(58)
420 INTR_HANDLER(59)
421 INTR_HANDLER(60)
422 INTR_HANDLER(61)
423 INTR_HANDLER(62)
424 INTR_HANDLER(63)
425 INTR_HANDLER(64)
426 INTR_HANDLER(65)
427 INTR_HANDLER(66)
428 INTR_HANDLER(67)
429 INTR_HANDLER(68)
430 INTR_HANDLER(69)
431 INTR_HANDLER(70)
432 INTR_HANDLER(71)
433 INTR_HANDLER(72)
434 INTR_HANDLER(73)
435 INTR_HANDLER(74)
436 INTR_HANDLER(75)
437 INTR_HANDLER(76)
438 INTR_HANDLER(77)
439 INTR_HANDLER(78)
440 INTR_HANDLER(79)
441 INTR_HANDLER(80)
442 INTR_HANDLER(81)
443 INTR_HANDLER(82)
444 INTR_HANDLER(83)
445 INTR_HANDLER(84)
446 INTR_HANDLER(85)
447 INTR_HANDLER(86)
448 INTR_HANDLER(87)
449 INTR_HANDLER(88)
450 INTR_HANDLER(89)
451 INTR_HANDLER(90)
452 INTR_HANDLER(91)
453 INTR_HANDLER(92)
454 INTR_HANDLER(93)
455 INTR_HANDLER(94)
456 INTR_HANDLER(95)
457 INTR_HANDLER(96)
458 INTR_HANDLER(97)
459 INTR_HANDLER(98)
460 INTR_HANDLER(99)
461 INTR_HANDLER(100)
462 INTR_HANDLER(101)
463 INTR_HANDLER(102)
464 INTR_HANDLER(103)
465 INTR_HANDLER(104)
466 INTR_HANDLER(105)
467 INTR_HANDLER(106)
468 INTR_HANDLER(107)
469 INTR_HANDLER(108)
470 INTR_HANDLER(109)
471 INTR_HANDLER(110)
472 INTR_HANDLER(111)
473 INTR_HANDLER(112)
474 INTR_HANDLER(113)
475 INTR_HANDLER(114)
476 INTR_HANDLER(115)
477 INTR_HANDLER(116)
478 INTR_HANDLER(117)
479 INTR_HANDLER(118)
480 INTR_HANDLER(119)
481 INTR_HANDLER(120)
482 INTR_HANDLER(121)
483 INTR_HANDLER(122)
484 INTR_HANDLER(123)
485 INTR_HANDLER(124)
486 INTR_HANDLER(125)
487 INTR_HANDLER(126)
488 INTR_HANDLER(127)
489 INTR_HANDLER(128)
490 INTR_HANDLER(129)
491 INTR_HANDLER(130)
492 INTR_HANDLER(131)
493 INTR_HANDLER(132)
494 INTR_HANDLER(133)
495 INTR_HANDLER(134)
496 INTR_HANDLER(135)
497 INTR_HANDLER(136)
498 INTR_HANDLER(137)
499 INTR_HANDLER(138)
500 INTR_HANDLER(139)
501 INTR_HANDLER(140)
502 INTR_HANDLER(141)
503 INTR_HANDLER(142)
504 INTR_HANDLER(143)
505 INTR_HANDLER(144)
506 INTR_HANDLER(145)
507 INTR_HANDLER(146)
508 INTR_HANDLER(147)
509 INTR_HANDLER(148)
510 INTR_HANDLER(149)
511 INTR_HANDLER(150)
512 INTR_HANDLER(151)
513 INTR_HANDLER(152)
514 INTR_HANDLER(153)
515 INTR_HANDLER(154)
516 INTR_HANDLER(155)
517 INTR_HANDLER(156)
518 INTR_HANDLER(157)
519 INTR_HANDLER(158)
520 INTR_HANDLER(159)
521 INTR_HANDLER(160)
522 INTR_HANDLER(161)
523 INTR_HANDLER(162)
524 INTR_HANDLER(163)
525 INTR_HANDLER(164)
526 INTR_HANDLER(165)
527 INTR_HANDLER(166)
528 INTR_HANDLER(167)
529 INTR_HANDLER(168)
530 INTR_HANDLER(169)
531 INTR_HANDLER(170)
532 INTR_HANDLER(171)
533 INTR_HANDLER(172)
534 INTR_HANDLER(173)
535 INTR_HANDLER(174)
536 INTR_HANDLER(175)
537 INTR_HANDLER(176)
538 INTR_HANDLER(177)
539 INTR_HANDLER(178)
540 INTR_HANDLER(179)
541 INTR_HANDLER(180)
542 INTR_HANDLER(181)
543 INTR_HANDLER(182)
544 INTR_HANDLER(183)
545 INTR_HANDLER(184)
546 INTR_HANDLER(185)
547 INTR_HANDLER(186)
548 INTR_HANDLER(187)
549 INTR_HANDLER(188)
550 INTR_HANDLER(189)
551 INTR_HANDLER(190)
552 INTR_HANDLER(191)
984263bc
MD
553MCOUNT_LABEL(eintr)
554
97359a5b
MD
555#endif
556
984263bc 557 .data
ef0fdad1 558
984263bc 559/* variables used by stop_cpus()/restart_cpus()/Xcpustop */
2954c92f
MD
560 .globl stopped_cpus, started_cpus
561stopped_cpus:
984263bc 562 .long 0
2954c92f 563started_cpus:
984263bc
MD
564 .long 0
565
984263bc 566 .globl CNAME(cpustop_restartfunc)
984263bc
MD
567CNAME(cpustop_restartfunc):
568 .long 0
569
984263bc 570 .text
06f5be02 571