/*
 *	from: vector.s, 386BSD 0.1 unknown origin
 * $FreeBSD: src/sys/i386/isa/apic_vector.s,v 1.47.2.5 2001/09/01 22:33:38 tegge Exp $
 */

#include <machine/asmacros.h>
#include <machine/lock.h>
#include <machine/psl.h>
#include <machine/trap.h>
#include <machine/segments.h>

#include "assym.s"

#ifdef foo
/* convert an absolute IRQ# into bitmask */
#define IRQ_LBIT(irq_num)	(1UL << (irq_num & 0x3f))
#endif

#define IRQ_SBITS(irq_num)	((irq_num) & 0x3f)

/* convert an absolute IRQ# into gd_ipending index */
#define IRQ_LIDX(irq_num)	((irq_num) >> 6)

#define MSI_PUSH_FRAME							\
	PUSH_FRAME_TFRIP ;	/* 15 regs + space for 5 extras */	\
	movq $0,TF_XFLAGS(%rsp) ;					\
	movq $0,TF_TRAPNO(%rsp) ;					\
	movq $0,TF_ADDR(%rsp) ;						\
	movq $0,TF_FLAGS(%rsp) ;					\
	movq $0,TF_ERR(%rsp) ;						\
	cld ;								\

/*
 * Interrupt call handlers run in the following sequence:
 *
 *	- Push the trap frame required by doreti
 *	- If we cannot take the interrupt set its ipending bit and
 *	  doreti.
 *	- If we can take the interrupt clear its ipending bit,
 *	  call the handler and doreti.
 *
 * YYY can cache gd base opitner instead of using hidden %fs prefixes.
 */

#define	MSI_HANDLER(irq_num)						\
	.text ;								\
	SUPERALIGN_TEXT ;						\
IDTVEC(msi_intr##irq_num) ;						\
	MSI_PUSH_FRAME ;						\
	FAKE_MCOUNT(TF_RIP(%rsp)) ;					\
	movq	lapic_eoi, %rax ;					\
	callq	*%rax ;							\
	movq	PCPU(curthread),%rbx ;					\
	testl	$-1,TD_NEST_COUNT(%rbx) ;				\
	jne	1f ;							\
	testl	$-1,TD_CRITCOUNT(%rbx) ;				\
	je	2f ;							\
1: ;									\
	/* in critical section, make interrupt pending */		\
	/* set the pending bit and return, leave interrupt masked */	\
	movq	$1,%rcx ;						\
	shlq	$IRQ_SBITS(irq_num),%rcx ;				\
	movq	$IRQ_LIDX(irq_num),%rdx ;				\
	orq	%rcx,PCPU_E8(ipending,%rdx) ;				\
	orl	$RQF_INTPEND,PCPU(reqflags) ;				\
	jmp	5f ;							\
2: ;									\
	/* clear pending bit, run handler */				\
	movq	$1,%rcx ;						\
	shlq	$IRQ_SBITS(irq_num),%rcx ;				\
	notq	%rcx ;							\
	movq	$IRQ_LIDX(irq_num),%rdx ;				\
	andq	%rcx,PCPU_E8(ipending,%rdx) ;				\
	pushq	$irq_num ;		/* trapframe -> intrframe */	\
	movq	%rsp, %rdi ;		/* pass frame by reference */	\
	incl	TD_CRITCOUNT(%rbx) ;					\
	sti ;								\
	call	ithread_fast_handler ;					\
	decl	TD_CRITCOUNT(%rbx) ;					\
	addq	$8, %rsp ;		/* intrframe -> trapframe */	\
5: ;									\
	MEXITCOUNT ;							\
	jmp	doreti ;						\


MCOUNT_LABEL(bintr)
	MSI_HANDLER(0)
	MSI_HANDLER(1)
	MSI_HANDLER(2)
	MSI_HANDLER(3)
	MSI_HANDLER(4)
	MSI_HANDLER(5)
	MSI_HANDLER(6)
	MSI_HANDLER(7)
	MSI_HANDLER(8)
	MSI_HANDLER(9)
	MSI_HANDLER(10)
	MSI_HANDLER(11)
	MSI_HANDLER(12)
	MSI_HANDLER(13)
	MSI_HANDLER(14)
	MSI_HANDLER(15)
	MSI_HANDLER(16)
	MSI_HANDLER(17)
	MSI_HANDLER(18)
	MSI_HANDLER(19)
	MSI_HANDLER(20)
	MSI_HANDLER(21)
	MSI_HANDLER(22)
	MSI_HANDLER(23)
	MSI_HANDLER(24)
	MSI_HANDLER(25)
	MSI_HANDLER(26)
	MSI_HANDLER(27)
	MSI_HANDLER(28)
	MSI_HANDLER(29)
	MSI_HANDLER(30)
	MSI_HANDLER(31)
	MSI_HANDLER(32)
	MSI_HANDLER(33)
	MSI_HANDLER(34)
	MSI_HANDLER(35)
	MSI_HANDLER(36)
	MSI_HANDLER(37)
	MSI_HANDLER(38)
	MSI_HANDLER(39)
	MSI_HANDLER(40)
	MSI_HANDLER(41)
	MSI_HANDLER(42)
	MSI_HANDLER(43)
	MSI_HANDLER(44)
	MSI_HANDLER(45)
	MSI_HANDLER(46)
	MSI_HANDLER(47)
	MSI_HANDLER(48)
	MSI_HANDLER(49)
	MSI_HANDLER(50)
	MSI_HANDLER(51)
	MSI_HANDLER(52)
	MSI_HANDLER(53)
	MSI_HANDLER(54)
	MSI_HANDLER(55)
	MSI_HANDLER(56)
	MSI_HANDLER(57)
	MSI_HANDLER(58)
	MSI_HANDLER(59)
	MSI_HANDLER(60)
	MSI_HANDLER(61)
	MSI_HANDLER(62)
	MSI_HANDLER(63)
	MSI_HANDLER(64)
	MSI_HANDLER(65)
	MSI_HANDLER(66)
	MSI_HANDLER(67)
	MSI_HANDLER(68)
	MSI_HANDLER(69)
	MSI_HANDLER(70)
	MSI_HANDLER(71)
	MSI_HANDLER(72)
	MSI_HANDLER(73)
	MSI_HANDLER(74)
	MSI_HANDLER(75)
	MSI_HANDLER(76)
	MSI_HANDLER(77)
	MSI_HANDLER(78)
	MSI_HANDLER(79)
	MSI_HANDLER(80)
	MSI_HANDLER(81)
	MSI_HANDLER(82)
	MSI_HANDLER(83)
	MSI_HANDLER(84)
	MSI_HANDLER(85)
	MSI_HANDLER(86)
	MSI_HANDLER(87)
	MSI_HANDLER(88)
	MSI_HANDLER(89)
	MSI_HANDLER(90)
	MSI_HANDLER(91)
	MSI_HANDLER(92)
	MSI_HANDLER(93)
	MSI_HANDLER(94)
	MSI_HANDLER(95)
	MSI_HANDLER(96)
	MSI_HANDLER(97)
	MSI_HANDLER(98)
	MSI_HANDLER(99)
	MSI_HANDLER(100)
	MSI_HANDLER(101)
	MSI_HANDLER(102)
	MSI_HANDLER(103)
	MSI_HANDLER(104)
	MSI_HANDLER(105)
	MSI_HANDLER(106)
	MSI_HANDLER(107)
	MSI_HANDLER(108)
	MSI_HANDLER(109)
	MSI_HANDLER(110)
	MSI_HANDLER(111)
	MSI_HANDLER(112)
	MSI_HANDLER(113)
	MSI_HANDLER(114)
	MSI_HANDLER(115)
	MSI_HANDLER(116)
	MSI_HANDLER(117)
	MSI_HANDLER(118)
	MSI_HANDLER(119)
	MSI_HANDLER(120)
	MSI_HANDLER(121)
	MSI_HANDLER(122)
	MSI_HANDLER(123)
	MSI_HANDLER(124)
	MSI_HANDLER(125)
	MSI_HANDLER(126)
	MSI_HANDLER(127)
	MSI_HANDLER(128)
	MSI_HANDLER(129)
	MSI_HANDLER(130)
	MSI_HANDLER(131)
	MSI_HANDLER(132)
	MSI_HANDLER(133)
	MSI_HANDLER(134)
	MSI_HANDLER(135)
	MSI_HANDLER(136)
	MSI_HANDLER(137)
	MSI_HANDLER(138)
	MSI_HANDLER(139)
	MSI_HANDLER(140)
	MSI_HANDLER(141)
	MSI_HANDLER(142)
	MSI_HANDLER(143)
	MSI_HANDLER(144)
	MSI_HANDLER(145)
	MSI_HANDLER(146)
	MSI_HANDLER(147)
	MSI_HANDLER(148)
	MSI_HANDLER(149)
	MSI_HANDLER(150)
	MSI_HANDLER(151)
	MSI_HANDLER(152)
	MSI_HANDLER(153)
	MSI_HANDLER(154)
	MSI_HANDLER(155)
	MSI_HANDLER(156)
	MSI_HANDLER(157)
	MSI_HANDLER(158)
	MSI_HANDLER(159)
	MSI_HANDLER(160)
	MSI_HANDLER(161)
	MSI_HANDLER(162)
	MSI_HANDLER(163)
	MSI_HANDLER(164)
	MSI_HANDLER(165)
	MSI_HANDLER(166)
	MSI_HANDLER(167)
	MSI_HANDLER(168)
	MSI_HANDLER(169)
	MSI_HANDLER(170)
	MSI_HANDLER(171)
	MSI_HANDLER(172)
	MSI_HANDLER(173)
	MSI_HANDLER(174)
	MSI_HANDLER(175)
	MSI_HANDLER(176)
	MSI_HANDLER(177)
	MSI_HANDLER(178)
	MSI_HANDLER(179)
	MSI_HANDLER(180)
	MSI_HANDLER(181)
	MSI_HANDLER(182)
	MSI_HANDLER(183)
	MSI_HANDLER(184)
	MSI_HANDLER(185)
	MSI_HANDLER(186)
	MSI_HANDLER(187)
	MSI_HANDLER(188)
	MSI_HANDLER(189)
	MSI_HANDLER(190)
	MSI_HANDLER(191)
MCOUNT_LABEL(eintr)

	.data

	.text
