Commit | Line | Data |
---|---|---|
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 | 116 | 8: ; \ |
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 | 135 | IDTVEC(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 |
146 | 1: ; \ |
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 ; \ |
152 | 2: ; \ | |
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) ; \ |
164 | 5: ; \ | |
165 | MEXITCOUNT ; \ | |
166 | jmp doreti ; \ | |
167 | ||
20a6b6c7 SZ |
168 | INTR_HANDLER(0, IO_ICU1, ENABLE_ICU1) |
169 | INTR_HANDLER(1, IO_ICU1, ENABLE_ICU1) | |
170 | INTR_HANDLER(2, IO_ICU1, ENABLE_ICU1) | |
171 | INTR_HANDLER(3, IO_ICU1, ENABLE_ICU1) | |
172 | INTR_HANDLER(4, IO_ICU1, ENABLE_ICU1) | |
173 | INTR_HANDLER(5, IO_ICU1, ENABLE_ICU1) | |
174 | INTR_HANDLER(6, IO_ICU1, ENABLE_ICU1) | |
175 | INTR_HANDLER(7, IO_ICU1, ENABLE_ICU1) | |
176 | INTR_HANDLER(8, IO_ICU2, ENABLE_ICU1_AND_2) | |
177 | INTR_HANDLER(9, IO_ICU2, ENABLE_ICU1_AND_2) | |
178 | INTR_HANDLER(10, IO_ICU2, ENABLE_ICU1_AND_2) | |
179 | INTR_HANDLER(11, IO_ICU2, ENABLE_ICU1_AND_2) | |
180 | INTR_HANDLER(12, IO_ICU2, ENABLE_ICU1_AND_2) | |
181 | INTR_HANDLER(13, IO_ICU2, ENABLE_ICU1_AND_2) | |
182 | INTR_HANDLER(14, IO_ICU2, ENABLE_ICU1_AND_2) | |
183 | INTR_HANDLER(15, IO_ICU2, ENABLE_ICU1_AND_2) | |
984263bc MD |
184 | |
185 | .data | |
984263bc MD |
186 | |
187 | .text |