#include "opt_auto_eoi.h"
#include <machine/asmacros.h>
#include <machine/lock.h>
#include <machine/psl.h>
#include <machine/trap.h>
#include <machine/segments.h>
#include <machine_base/icu/icu.h>
#include <machine_base/icu/icu_ipl.h>
#include <bus/isa/isa.h>
#include "assym.s"
#define ICU_EOI 0x20
#define IRQ_LBIT(irq_num) (1 << (irq_num))
#define IRQ_BIT(irq_num) (1 << ((irq_num) % 8))
#define IRQ_BYTE(irq_num) ((irq_num) >> 3)
#ifdef AUTO_EOI_1
#define ENABLE_ICU1
#define OUTB_ICU1
#else
#define ENABLE_ICU1 \
movb $ICU_EOI,%al ; \
OUTB_ICU1 ; \
#define OUTB_ICU1 \
outb %al,$IO_ICU1 ; \
#endif
#ifdef AUTO_EOI_2
#define ENABLE_ICU1_AND_2 ENABLE_ICU1
#else
#define ENABLE_ICU1_AND_2 \
movb $ICU_EOI,%al ; \
outb %al,$IO_ICU2 ; \
OUTB_ICU1 ; \
#endif
#define ICU_PUSH_FRAME \
PUSH_FRAME_TFRIP ; \
movl $0,TF_XFLAGS(%rsp) ; \
movl $0,TF_TRAPNO(%rsp) ; \
movl $0,TF_ADDR(%rsp) ; \
movl $0,TF_FLAGS(%rsp) ; \
movl $0,TF_ERR(%rsp) ; \
cld ; \
#define MASK_IRQ(icu, irq_num) \
movb icu_imen + IRQ_BYTE(irq_num),%al ; \
orb $IRQ_BIT(irq_num),%al ; \
movb %al,icu_imen + IRQ_BYTE(irq_num) ; \
outb %al,$icu+ICU_IMR_OFFSET ; \
#define UNMASK_IRQ(icu, irq_num) \
cmpl $0,%eax ; \
jnz 8f ; \
ICU_IMASK_LOCK ; \
movb icu_imen + IRQ_BYTE(irq_num),%al ; \
andb $~IRQ_BIT(irq_num),%al ; \
movb %al,icu_imen + IRQ_BYTE(irq_num) ; \
outb %al,$icu+ICU_IMR_OFFSET ; \
ICU_IMASK_UNLOCK ; \
8: ; \
#define INTR_HANDLER(irq_num, icu, enable_icus) \
.text ; \
SUPERALIGN_TEXT ; \
IDTVEC(icu_intr##irq_num) ; \
ICU_PUSH_FRAME ; \
FAKE_MCOUNT(TF_RIP(%rsp)) ; \
ICU_IMASK_LOCK ; \
MASK_IRQ(icu, irq_num) ; \
enable_icus ; \
ICU_IMASK_UNLOCK ; \
movq PCPU(curthread),%rbx ; \
testl $-1,TD_NEST_COUNT(%rbx) ; \
jne 1f ; \
testl $-1,TD_CRITCOUNT(%rbx) ; \
je 2f ; \
1: ; \
\
movq $0,%rdx ; \
orq $IRQ_LBIT(irq_num),PCPU_E8(ipending,%rdx) ; \
orl $RQF_INTPEND, PCPU(reqflags) ; \
jmp 5f ; \
2: ; \
\
movq $0,%rdx ; \
andq $~IRQ_LBIT(irq_num),PCPU_E8(ipending,%rdx) ; \
pushq $irq_num ; \
movq %rsp,%rdi ; \
incl TD_CRITCOUNT(%rbx) ; \
sti ; \
call ithread_fast_handler ; \
decl TD_CRITCOUNT(%rbx) ; \
addq $8,%rsp ; \
UNMASK_IRQ(icu, irq_num) ; \
5: ; \
MEXITCOUNT ; \
jmp doreti ; \
MCOUNT_LABEL(bintr)
INTR_HANDLER(0, IO_ICU1, ENABLE_ICU1)
INTR_HANDLER(1, IO_ICU1, ENABLE_ICU1)
INTR_HANDLER(2, IO_ICU1, ENABLE_ICU1)
INTR_HANDLER(3, IO_ICU1, ENABLE_ICU1)
INTR_HANDLER(4, IO_ICU1, ENABLE_ICU1)
INTR_HANDLER(5, IO_ICU1, ENABLE_ICU1)
INTR_HANDLER(6, IO_ICU1, ENABLE_ICU1)
INTR_HANDLER(7, IO_ICU1, ENABLE_ICU1)
INTR_HANDLER(8, IO_ICU2, ENABLE_ICU1_AND_2)
INTR_HANDLER(9, IO_ICU2, ENABLE_ICU1_AND_2)
INTR_HANDLER(10, IO_ICU2, ENABLE_ICU1_AND_2)
INTR_HANDLER(11, IO_ICU2, ENABLE_ICU1_AND_2)
INTR_HANDLER(12, IO_ICU2, ENABLE_ICU1_AND_2)
INTR_HANDLER(13, IO_ICU2, ENABLE_ICU1_AND_2)
INTR_HANDLER(14, IO_ICU2, ENABLE_ICU1_AND_2)
INTR_HANDLER(15, IO_ICU2, ENABLE_ICU1_AND_2)
MCOUNT_LABEL(eintr)
.data
.text