icu: Split out icu/icu.c
[dragonfly.git] / sys / platform / pc32 / icu / icu_vector.s
CommitLineData
984263bc
MD
1/*
2 * from: vector.s, 386BSD 0.1 unknown origin
3 * $FreeBSD: src/sys/i386/isa/icu_vector.s,v 1.14.2.2 2000/07/18 21:12:42 dfr Exp $
97359a5b
MD
4 */
5/*
6 * WARNING! SMP builds can use the ICU now so this code must be MP safe.
984263bc
MD
7 */
8
06f5be02
MD
9#include "opt_auto_eoi.h"
10
11#include <machine/asmacros.h>
06f5be02
MD
12#include <machine/lock.h>
13#include <machine/psl.h>
14#include <machine/trap.h>
a9295349 15#include <machine_base/icu/icu.h>
1c2bce94
SZ
16#include <machine_base/icu/icu_ipl.h>
17
21ce0dfa 18#include <bus/isa/isa.h>
06f5be02
MD
19
20#include "assym.s"
984263bc
MD
21
22#define ICU_EOI 0x20 /* XXX - define elsewhere */
23
ef0fdad1 24#define IRQ_LBIT(irq_num) (1 << (irq_num))
984263bc
MD
25#define IRQ_BIT(irq_num) (1 << ((irq_num) % 8))
26#define IRQ_BYTE(irq_num) ((irq_num) >> 3)
27
28#ifdef AUTO_EOI_1
29#define ENABLE_ICU1 /* use auto-EOI to reduce i/o */
30#define OUTB_ICU1
31#else
ef0fdad1
MD
32#define ENABLE_ICU1 \
33 movb $ICU_EOI,%al ; /* as soon as possible send EOI ... */ \
34 OUTB_ICU1 ; /* ... to clear in service bit */ \
35
36#define OUTB_ICU1 \
37 outb %al,$IO_ICU1 ; \
38
984263bc
MD
39#endif
40
41#ifdef AUTO_EOI_2
42/*
43 * The data sheet says no auto-EOI on slave, but it sometimes works.
44 */
45#define ENABLE_ICU1_AND_2 ENABLE_ICU1
46#else
ef0fdad1
MD
47#define ENABLE_ICU1_AND_2 \
48 movb $ICU_EOI,%al ; /* as above */ \
49 outb %al,$IO_ICU2 ; /* but do second icu first ... */ \
50 OUTB_ICU1 ; /* ... then first icu (if !AUTO_EOI_1) */ \
51
984263bc
MD
52#endif
53
54/*
ef0fdad1 55 * Macro helpers
984263bc 56 */
ef0fdad1
MD
57#define PUSH_FRAME \
58 pushl $0 ; /* dummy error code */ \
59 pushl $0 ; /* dummy trap type */ \
4e7c41c5 60 pushl $0 ; /* dummy xflags */ \
ef0fdad1
MD
61 pushal ; /* 8 registers */ \
62 pushl %ds ; \
63 pushl %es ; \
64 pushl %fs ; \
4e7c41c5 65 pushl %gs ; \
c885c20e 66 cld ; \
ef0fdad1
MD
67 mov $KDSEL,%ax ; \
68 mov %ax,%ds ; \
69 mov %ax,%es ; \
4e7c41c5 70 mov %ax,%gs ; \
ef0fdad1
MD
71 mov $KPSEL,%ax ; \
72 mov %ax,%fs ; \
73
74#define PUSH_DUMMY \
75 pushfl ; /* phys int frame / flags */ \
76 pushl %cs ; /* phys int frame / cs */ \
77 pushl 12(%esp) ; /* original caller eip */ \
78 pushl $0 ; /* dummy error code */ \
79 pushl $0 ; /* dummy trap type */ \
4e7c41c5
MD
80 pushl $0 ; /* dummy xflags */ \
81 subl $13*4,%esp ; /* pushal + 4 seg regs (dummy) + CPL */ \
984263bc 82
ef0fdad1
MD
83/*
84 * Warning: POP_FRAME can only be used if there is no chance of a
85 * segment register being changed (e.g. by procfs), which is why syscalls
86 * have to use doreti.
87 */
88#define POP_FRAME \
4e7c41c5 89 popl %gs ; \
ef0fdad1
MD
90 popl %fs ; \
91 popl %es ; \
92 popl %ds ; \
93 popal ; \
94 addl $2*4,%esp ; /* dummy trap & error codes */ \
95
96#define POP_DUMMY \
4e7c41c5 97 addl $19*4,%esp ; \
ef0fdad1
MD
98
99#define MASK_IRQ(icu, irq_num) \
97359a5b 100 ICU_IMASK_LOCK ; \
06f5be02 101 movb icu_imen + IRQ_BYTE(irq_num),%al ; \
ef0fdad1 102 orb $IRQ_BIT(irq_num),%al ; \
06f5be02 103 movb %al,icu_imen + IRQ_BYTE(irq_num) ; \
ef0fdad1 104 outb %al,$icu+ICU_IMR_OFFSET ; \
97359a5b 105 ICU_IMASK_UNLOCK ; \
ef0fdad1
MD
106
107#define UNMASK_IRQ(icu, irq_num) \
477d3c1c
MD
108 cmpl $0,%eax ; \
109 jnz 8f ; \
97359a5b 110 ICU_IMASK_LOCK ; \
06f5be02 111 movb icu_imen + IRQ_BYTE(irq_num),%al ; \
ef0fdad1 112 andb $~IRQ_BIT(irq_num),%al ; \
06f5be02 113 movb %al,icu_imen + IRQ_BYTE(irq_num) ; \
ef0fdad1 114 outb %al,$icu+ICU_IMR_OFFSET ; \
97359a5b 115 ICU_IMASK_UNLOCK ; \
477d3c1c 1168: ; \
ef0fdad1
MD
117
118/*
081be8a5 119 * Interrupt call handlers run in the following sequence:
ef0fdad1
MD
120 *
121 * - Push the trap frame required by doreti.
122 * - Mask the interrupt and reenable its source.
c263294b 123 * - If we cannot take the interrupt set its ipending bit and
ef0fdad1 124 * doreti.
c263294b 125 * - If we can take the interrupt clear its ipending bit,
ef0fdad1
MD
126 * call the handler, then unmask the interrupt and doreti.
127 *
128 * YYY can cache gd base pointer instead of using hidden %fs
129 * prefixes.
130 */
131
20a6b6c7 132#define INTR_HANDLER(irq_num, icu, enable_icus) \
ee776109
MD
133 .text ; \
134 SUPERALIGN_TEXT ; \
20a6b6c7 135IDTVEC(icu_intr##irq_num) ; \
ef0fdad1 136 PUSH_FRAME ; \
4e7c41c5 137 FAKE_MCOUNT(15*4(%esp)) ; \
ef0fdad1
MD
138 MASK_IRQ(icu, irq_num) ; \
139 enable_icus ; \
2954c92f 140 movl PCPU(curthread),%ebx ; \
38787eef 141 pushl $0 ; /* DUMMY CPL FOR DORETI */ \
1be5027b
MD
142 testl $-1,TD_NEST_COUNT(%ebx) ; \
143 jne 1f ; \
f9235b6d
MD
144 testl $-1,TD_CRITCOUNT(%ebx) ; \
145 je 2f ; \
ef0fdad1
MD
1461: ; \
147 /* set pending bit and return, leave interrupt masked */ \
c263294b
SZ
148 movl $0,%edx ; \
149 orl $IRQ_LBIT(irq_num),PCPU_E4(ipending,%edx) ; \
235957ed 150 orl $RQF_INTPEND, PCPU(reqflags) ; \
ef0fdad1
MD
151 jmp 5f ; \
1522: ; \
153 /* clear pending bit, run handler */ \
c263294b
SZ
154 movl $0,%edx ; \
155 andl $~IRQ_LBIT(irq_num),PCPU_E4(ipending,%edx) ; \
477d3c1c 156 pushl $irq_num ; \
c7eb0589 157 pushl %esp ; /* pass frame by reference */ \
f9235b6d 158 incl TD_CRITCOUNT(%ebx) ; \
2d910aaf 159 sti ; \
477d3c1c 160 call ithread_fast_handler ; /* returns 0 to unmask int */ \
f9235b6d 161 decl TD_CRITCOUNT(%ebx) ; \
c7eb0589 162 addl $8,%esp ; \
ef0fdad1
MD
163 UNMASK_IRQ(icu, irq_num) ; \
1645: ; \
165 MEXITCOUNT ; \
166 jmp doreti ; \
167
984263bc 168MCOUNT_LABEL(bintr)
20a6b6c7
SZ
169 INTR_HANDLER(0, IO_ICU1, ENABLE_ICU1)
170 INTR_HANDLER(1, IO_ICU1, ENABLE_ICU1)
171 INTR_HANDLER(2, IO_ICU1, ENABLE_ICU1)
172 INTR_HANDLER(3, IO_ICU1, ENABLE_ICU1)
173 INTR_HANDLER(4, IO_ICU1, ENABLE_ICU1)
174 INTR_HANDLER(5, IO_ICU1, ENABLE_ICU1)
175 INTR_HANDLER(6, IO_ICU1, ENABLE_ICU1)
176 INTR_HANDLER(7, IO_ICU1, ENABLE_ICU1)
177 INTR_HANDLER(8, IO_ICU2, ENABLE_ICU1_AND_2)
178 INTR_HANDLER(9, IO_ICU2, ENABLE_ICU1_AND_2)
179 INTR_HANDLER(10, IO_ICU2, ENABLE_ICU1_AND_2)
180 INTR_HANDLER(11, IO_ICU2, ENABLE_ICU1_AND_2)
181 INTR_HANDLER(12, IO_ICU2, ENABLE_ICU1_AND_2)
182 INTR_HANDLER(13, IO_ICU2, ENABLE_ICU1_AND_2)
183 INTR_HANDLER(14, IO_ICU2, ENABLE_ICU1_AND_2)
184 INTR_HANDLER(15, IO_ICU2, ENABLE_ICU1_AND_2)
984263bc
MD
185MCOUNT_LABEL(eintr)
186
187 .data
984263bc
MD
188
189 .text