1/* 2 * from: vector.s, 386BSD 0.1 unknown origin
| 1/* 2 * from: vector.s, 386BSD 0.1 unknown origin
|
3 * $FreeBSD: head/sys/amd64/isa/atpic_vector.S 91328 2002-02-26 20:33:41Z dillon $
| 3 * $FreeBSD: head/sys/amd64/isa/atpic_vector.S 93264 2002-03-27 05:39:23Z dillon $
|
4 */ 5 6/* 7 * modified for PC98 by Kakefuda 8 */ 9 10#ifdef PC98 11#define ICU_IMR_OFFSET 2 /* IO_ICU{1,2} + 2 */ 12#else 13#define ICU_IMR_OFFSET 1 /* IO_ICU{1,2} + 1 */ 14#endif 15 16#define ICU_EOI 0x20 /* XXX - define elsewhere */ 17 18#define IRQ_BIT(irq_num) (1 << ((irq_num) % 8))
| 4 */ 5 6/* 7 * modified for PC98 by Kakefuda 8 */ 9 10#ifdef PC98 11#define ICU_IMR_OFFSET 2 /* IO_ICU{1,2} + 2 */ 12#else 13#define ICU_IMR_OFFSET 1 /* IO_ICU{1,2} + 1 */ 14#endif 15 16#define ICU_EOI 0x20 /* XXX - define elsewhere */ 17 18#define IRQ_BIT(irq_num) (1 << ((irq_num) % 8))
|
| 19#define IRQ_LBIT(irq_num) (1 << (irq_num))
|
19#define IRQ_BYTE(irq_num) ((irq_num) >> 3) 20 21#ifdef AUTO_EOI_1
| 20#define IRQ_BYTE(irq_num) ((irq_num) >> 3) 21 22#ifdef AUTO_EOI_1
|
| 23
|
22#define ENABLE_ICU1 /* use auto-EOI to reduce i/o */ 23#define OUTB_ICU1
| 24#define ENABLE_ICU1 /* use auto-EOI to reduce i/o */ 25#define OUTB_ICU1
|
| 26
|
24#else
| 27#else
|
| 28
|
25#define ENABLE_ICU1 \ 26 movb $ICU_EOI,%al ; /* as soon as possible send EOI ... */ \ 27 OUTB_ICU1 /* ... to clear in service bit */
| 29#define ENABLE_ICU1 \ 30 movb $ICU_EOI,%al ; /* as soon as possible send EOI ... */ \ 31 OUTB_ICU1 /* ... to clear in service bit */
|
| 32
|
28#define OUTB_ICU1 \ 29 outb %al,$IO_ICU1
| 33#define OUTB_ICU1 \ 34 outb %al,$IO_ICU1
|
| 35
|
30#endif 31 32#ifdef AUTO_EOI_2 33/* 34 * The data sheet says no auto-EOI on slave, but it sometimes works. 35 */ 36#define ENABLE_ICU1_AND_2 ENABLE_ICU1
| 36#endif 37 38#ifdef AUTO_EOI_2 39/* 40 * The data sheet says no auto-EOI on slave, but it sometimes works. 41 */ 42#define ENABLE_ICU1_AND_2 ENABLE_ICU1
|
| 43
|
37#else
| 44#else
|
| 45
|
38#define ENABLE_ICU1_AND_2 \ 39 movb $ICU_EOI,%al ; /* as above */ \ 40 outb %al,$IO_ICU2 ; /* but do second icu first ... */ \ 41 OUTB_ICU1 /* ... then first icu (if !AUTO_EOI_1) */
| 46#define ENABLE_ICU1_AND_2 \ 47 movb $ICU_EOI,%al ; /* as above */ \ 48 outb %al,$IO_ICU2 ; /* but do second icu first ... */ \ 49 OUTB_ICU1 /* ... then first icu (if !AUTO_EOI_1) */
|
| 50
|
42#endif 43
| 51#endif 52
|
| 53#define PUSH_FRAME \ 54 pushl $0 ; /* dummy error code */ \ 55 pushl $0 ; /* dummy trap type */ \ 56 pushal ; /* 8 ints */ \ 57 pushl %ds ; /* save data and extra segments ... */ \ 58 pushl %es ; \ 59 pushl %fs 60 61#define PUSH_DUMMY \ 62 pushfl ; /* eflags */ \ 63 pushl %cs ; /* cs */ \ 64 pushl 12(%esp) ; /* original caller eip */ \ 65 pushl $0 ; /* dummy error code */ \ 66 pushl $0 ; /* dummy trap type */ \ 67 subl $11*4,%esp 68 69#define POP_FRAME \ 70 popl %fs ; \ 71 popl %es ; \ 72 popl %ds ; \ 73 popal ; \ 74 addl $4+4,%esp 75 76#define POP_DUMMY \ 77 addl $16*4,%esp 78 79#define MASK_IRQ(icu, irq_num) \ 80 movb imen + IRQ_BYTE(irq_num),%al ; \ 81 orb $IRQ_BIT(irq_num),%al ; \ 82 movb %al,imen + IRQ_BYTE(irq_num) ; \ 83 outb %al,$icu+ICU_IMR_OFFSET 84 85#define UNMASK_IRQ(icu, irq_num) \ 86 movb imen + IRQ_BYTE(irq_num),%al ; \ 87 andb $~IRQ_BIT(irq_num),%al ; \ 88 movb %al,imen + IRQ_BYTE(irq_num) ; \ 89 outb %al,$icu+ICU_IMR_OFFSET
|
44/* 45 * Macros for interrupt interrupt entry, call to handler, and exit. 46 */ 47
| 90/* 91 * Macros for interrupt interrupt entry, call to handler, and exit. 92 */ 93
|
48#define FAST_INTR(irq_num, vec_name, enable_icus) \
| 94#define FAST_INTR(irq_num, vec_name, icu, enable_icus) \
|
49 .text ; \ 50 SUPERALIGN_TEXT ; \ 51IDTVEC(vec_name) ; \
| 95 .text ; \ 96 SUPERALIGN_TEXT ; \ 97IDTVEC(vec_name) ; \
|
52 pushl $0 ; /* dummy error code */ \ 53 pushl $0 ; /* dummy trap type */ \ 54 pushal ; \ 55 pushl %ds ; \ 56 pushl %es ; \ 57 pushl %fs ; \
| 98 PUSH_FRAME ; \
|
58 mov $KDSEL,%ax ; \ 59 mov %ax,%ds ; \ 60 mov %ax,%es ; \ 61 mov $KPSEL,%ax ; \ 62 mov %ax,%fs ; \ 63 FAKE_MCOUNT((12+ACTUALLY_PUSHED)*4(%esp)) ; \
| 99 mov $KDSEL,%ax ; \ 100 mov %ax,%ds ; \ 101 mov %ax,%es ; \ 102 mov $KPSEL,%ax ; \ 103 mov %ax,%fs ; \ 104 FAKE_MCOUNT((12+ACTUALLY_PUSHED)*4(%esp)) ; \
|
64 call critical_enter ; \
| |
65 movl PCPU(CURTHREAD),%ebx ; \
| 105 movl PCPU(CURTHREAD),%ebx ; \
|
| 106 cmpl $0,TD_CRITNEST(%ebx) ; \ 107 je 1f ; \ 108; \ 109 movl $1,PCPU(INT_PENDING) ; \ 110 orl $IRQ_LBIT(irq_num),PCPU(FPENDING) ; \ 111 MASK_IRQ(icu, irq_num) ; \ 112 enable_icus ; \ 113 jmp 10f ; \ 1141: ; \ 115 incl TD_CRITNEST(%ebx) ; \
|
66 incl TD_INTR_NESTING_LEVEL(%ebx) ; \ 67 pushl intr_unit + (irq_num) * 4 ; \
| 116 incl TD_INTR_NESTING_LEVEL(%ebx) ; \ 117 pushl intr_unit + (irq_num) * 4 ; \
|
68 call *intr_handler + (irq_num) * 4 ; /* do the work ASAP */ \ 69 enable_icus ; /* (re)enable ASAP (helps edge trigger?) */ \
| 118 call *intr_handler + (irq_num) * 4 ; \
|
70 addl $4,%esp ; \
| 119 addl $4,%esp ; \
|
| 120 enable_icus ; \
|
71 incl cnt+V_INTR ; /* book-keeping can wait */ \ 72 movl intr_countp + (irq_num) * 4,%eax ; \ 73 incl (%eax) ; \
| 121 incl cnt+V_INTR ; /* book-keeping can wait */ \ 122 movl intr_countp + (irq_num) * 4,%eax ; \ 123 incl (%eax) ; \
|
| 124 decl TD_CRITNEST(%ebx) ; \ 125 cmpl $0,PCPU(INT_PENDING) ; \ 126 je 2f ; \ 127; \ 128 call unpend ; \ 1292: ; \
|
74 decl TD_INTR_NESTING_LEVEL(%ebx) ; \
| 130 decl TD_INTR_NESTING_LEVEL(%ebx) ; \
|
75 call critical_exit ; \
| 13110: ; \
|
76 MEXITCOUNT ; \ 77 jmp doreti 78
| 132 MEXITCOUNT ; \ 133 jmp doreti 134
|
| 135/* 136 * Restart a fast interrupt that was held up by a critical section. 137 * This routine is called from unpend(). unpend() ensures we are 138 * in a critical section and deals with the interrupt nesting level 139 * for us. If we previously masked the irq, we have to unmask it. 140 * 141 * We have a choice. We can regenerate the irq using the 'int' 142 * instruction or we can create a dummy frame and call the interrupt 143 * handler directly. I've chosen to use the dummy-frame method. 144 */ 145#define FAST_UNPEND(irq_num, vec_name, icu) \ 146 .text ; \ 147 SUPERALIGN_TEXT ; \ 148IDTVEC(vec_name) ; \ 149; \ 150 pushl %ebp ; \ 151 movl %esp, %ebp ; \ 152 PUSH_DUMMY ; \ 153 pushl intr_unit + (irq_num) * 4 ; \ 154 call *intr_handler + (irq_num) * 4 ; /* do the work ASAP */ \ 155 addl $4, %esp ; \ 156 incl cnt+V_INTR ; /* book-keeping can wait */ \ 157 movl intr_countp + (irq_num) * 4,%eax ; \ 158 incl (%eax) ; \ 159 UNMASK_IRQ(icu, irq_num) ; \ 160 POP_DUMMY ; \ 161 popl %ebp ; \ 162 ret 163
|
79/* 80 * Slow, threaded interrupts. 81 * 82 * XXX Most of the parameters here are obsolete. Fix this when we're 83 * done. 84 * XXX we really shouldn't return via doreti if we just schedule the 85 * interrupt handler and don't run anything. We could just do an 86 * iret. FIXME. 87 */
| 164/* 165 * Slow, threaded interrupts. 166 * 167 * XXX Most of the parameters here are obsolete. Fix this when we're 168 * done. 169 * XXX we really shouldn't return via doreti if we just schedule the 170 * interrupt handler and don't run anything. We could just do an 171 * iret. FIXME. 172 */
|
88#define INTR(irq_num, vec_name, icu, enable_icus, reg, maybe_extra_ipending) \
| 173#define INTR(irq_num, vec_name, icu, enable_icus, maybe_extra_ipending) \
|
89 .text ; \ 90 SUPERALIGN_TEXT ; \ 91IDTVEC(vec_name) ; \
| 174 .text ; \ 175 SUPERALIGN_TEXT ; \ 176IDTVEC(vec_name) ; \
|
92 pushl $0 ; /* dummy error code */ \ 93 pushl $0 ; /* dummy trap type */ \ 94 pushal ; \ 95 pushl %ds ; /* save our data and extra segments ... */ \ 96 pushl %es ; \ 97 pushl %fs ; \
| 177 PUSH_FRAME ; \
|
98 mov $KDSEL,%ax ; /* load kernel ds, es and fs */ \ 99 mov %ax,%ds ; \ 100 mov %ax,%es ; \ 101 mov $KPSEL,%ax ; \ 102 mov %ax,%fs ; \
| 178 mov $KDSEL,%ax ; /* load kernel ds, es and fs */ \ 179 mov %ax,%ds ; \ 180 mov %ax,%es ; \ 181 mov $KPSEL,%ax ; \ 182 mov %ax,%fs ; \
|
| 183; \
|
103 maybe_extra_ipending ; \
| 184 maybe_extra_ipending ; \
|
104 movb imen + IRQ_BYTE(irq_num),%al ; \ 105 orb $IRQ_BIT(irq_num),%al ; \ 106 movb %al,imen + IRQ_BYTE(irq_num) ; \ 107 outb %al,$icu+ICU_IMR_OFFSET ; \
| 185 MASK_IRQ(icu, irq_num) ; \
|
108 enable_icus ; \
| 186 enable_icus ; \
|
| 187; \
|
109 movl PCPU(CURTHREAD),%ebx ; \
| 188 movl PCPU(CURTHREAD),%ebx ; \
|
| 189 cmpl $0,TD_CRITNEST(%ebx) ; \ 190 je 1f ; \ 191 movl $1,PCPU(INT_PENDING); \ 192 orl $IRQ_LBIT(irq_num),PCPU(IPENDING) ; \ 193 jmp 10f ; \ 1941: ; \
|
110 incl TD_INTR_NESTING_LEVEL(%ebx) ; \
| 195 incl TD_INTR_NESTING_LEVEL(%ebx) ; \
|
| 196; \
|
111 FAKE_MCOUNT(13*4(%esp)) ; /* XXX late to avoid double count */ \
| 197 FAKE_MCOUNT(13*4(%esp)) ; /* XXX late to avoid double count */ \
|
| 198 cmpl $0,PCPU(INT_PENDING) ; \ 199 je 9f ; \ 200 call unpend ; \ 2019: ; \
|
112 pushl $irq_num; /* pass the IRQ */ \ 113 call sched_ithd ; \ 114 addl $4, %esp ; /* discard the parameter */ \
| 202 pushl $irq_num; /* pass the IRQ */ \ 203 call sched_ithd ; \ 204 addl $4, %esp ; /* discard the parameter */ \
|
| 205; \
|
115 decl TD_INTR_NESTING_LEVEL(%ebx) ; \
| 206 decl TD_INTR_NESTING_LEVEL(%ebx) ; \
|
| 20710: ; \
|
116 MEXITCOUNT ; \
| 208 MEXITCOUNT ; \
|
117 /* We could usually avoid the following jmp by inlining some of */ \ 118 /* doreti, but it's probably better to use less cache. */ \ 119 jmp doreti /* and catch up inside doreti */
| 209 jmp doreti
|
120 121MCOUNT_LABEL(bintr)
| 210 211MCOUNT_LABEL(bintr)
|
122 FAST_INTR(0,fastintr0, ENABLE_ICU1) 123 FAST_INTR(1,fastintr1, ENABLE_ICU1) 124 FAST_INTR(2,fastintr2, ENABLE_ICU1) 125 FAST_INTR(3,fastintr3, ENABLE_ICU1) 126 FAST_INTR(4,fastintr4, ENABLE_ICU1) 127 FAST_INTR(5,fastintr5, ENABLE_ICU1) 128 FAST_INTR(6,fastintr6, ENABLE_ICU1) 129 FAST_INTR(7,fastintr7, ENABLE_ICU1) 130 FAST_INTR(8,fastintr8, ENABLE_ICU1_AND_2) 131 FAST_INTR(9,fastintr9, ENABLE_ICU1_AND_2) 132 FAST_INTR(10,fastintr10, ENABLE_ICU1_AND_2) 133 FAST_INTR(11,fastintr11, ENABLE_ICU1_AND_2) 134 FAST_INTR(12,fastintr12, ENABLE_ICU1_AND_2) 135 FAST_INTR(13,fastintr13, ENABLE_ICU1_AND_2) 136 FAST_INTR(14,fastintr14, ENABLE_ICU1_AND_2) 137 FAST_INTR(15,fastintr15, ENABLE_ICU1_AND_2)
| 212 FAST_INTR(0,fastintr0, IO_ICU1, ENABLE_ICU1) 213 FAST_INTR(1,fastintr1, IO_ICU1, ENABLE_ICU1) 214 FAST_INTR(2,fastintr2, IO_ICU1, ENABLE_ICU1) 215 FAST_INTR(3,fastintr3, IO_ICU1, ENABLE_ICU1) 216 FAST_INTR(4,fastintr4, IO_ICU1, ENABLE_ICU1) 217 FAST_INTR(5,fastintr5, IO_ICU1, ENABLE_ICU1) 218 FAST_INTR(6,fastintr6, IO_ICU1, ENABLE_ICU1) 219 FAST_INTR(7,fastintr7, IO_ICU1, ENABLE_ICU1) 220 FAST_INTR(8,fastintr8, IO_ICU2, ENABLE_ICU1_AND_2) 221 FAST_INTR(9,fastintr9, IO_ICU2, ENABLE_ICU1_AND_2) 222 FAST_INTR(10,fastintr10, IO_ICU2, ENABLE_ICU1_AND_2) 223 FAST_INTR(11,fastintr11, IO_ICU2, ENABLE_ICU1_AND_2) 224 FAST_INTR(12,fastintr12, IO_ICU2, ENABLE_ICU1_AND_2) 225 FAST_INTR(13,fastintr13, IO_ICU2, ENABLE_ICU1_AND_2) 226 FAST_INTR(14,fastintr14, IO_ICU2, ENABLE_ICU1_AND_2) 227 FAST_INTR(15,fastintr15, IO_ICU2, ENABLE_ICU1_AND_2)
|
138 139#define CLKINTR_PENDING movl $1,CNAME(clkintr_pending) 140/* Threaded interrupts */
| 228 229#define CLKINTR_PENDING movl $1,CNAME(clkintr_pending) 230/* Threaded interrupts */
|
141 INTR(0,intr0, IO_ICU1, ENABLE_ICU1, al, CLKINTR_PENDING) 142 INTR(1,intr1, IO_ICU1, ENABLE_ICU1, al,) 143 INTR(2,intr2, IO_ICU1, ENABLE_ICU1, al,) 144 INTR(3,intr3, IO_ICU1, ENABLE_ICU1, al,) 145 INTR(4,intr4, IO_ICU1, ENABLE_ICU1, al,) 146 INTR(5,intr5, IO_ICU1, ENABLE_ICU1, al,) 147 INTR(6,intr6, IO_ICU1, ENABLE_ICU1, al,) 148 INTR(7,intr7, IO_ICU1, ENABLE_ICU1, al,) 149 INTR(8,intr8, IO_ICU2, ENABLE_ICU1_AND_2, ah,) 150 INTR(9,intr9, IO_ICU2, ENABLE_ICU1_AND_2, ah,) 151 INTR(10,intr10, IO_ICU2, ENABLE_ICU1_AND_2, ah,) 152 INTR(11,intr11, IO_ICU2, ENABLE_ICU1_AND_2, ah,) 153 INTR(12,intr12, IO_ICU2, ENABLE_ICU1_AND_2, ah,) 154 INTR(13,intr13, IO_ICU2, ENABLE_ICU1_AND_2, ah,) 155 INTR(14,intr14, IO_ICU2, ENABLE_ICU1_AND_2, ah,) 156 INTR(15,intr15, IO_ICU2, ENABLE_ICU1_AND_2, ah,)
| 231 INTR(0,intr0, IO_ICU1, ENABLE_ICU1, CLKINTR_PENDING) 232 INTR(1,intr1, IO_ICU1, ENABLE_ICU1,) 233 INTR(2,intr2, IO_ICU1, ENABLE_ICU1,) 234 INTR(3,intr3, IO_ICU1, ENABLE_ICU1,) 235 INTR(4,intr4, IO_ICU1, ENABLE_ICU1,) 236 INTR(5,intr5, IO_ICU1, ENABLE_ICU1,) 237 INTR(6,intr6, IO_ICU1, ENABLE_ICU1,) 238 INTR(7,intr7, IO_ICU1, ENABLE_ICU1,) 239 INTR(8,intr8, IO_ICU2, ENABLE_ICU1_AND_2,) 240 INTR(9,intr9, IO_ICU2, ENABLE_ICU1_AND_2,) 241 INTR(10,intr10, IO_ICU2, ENABLE_ICU1_AND_2,) 242 INTR(11,intr11, IO_ICU2, ENABLE_ICU1_AND_2,) 243 INTR(12,intr12, IO_ICU2, ENABLE_ICU1_AND_2,) 244 INTR(13,intr13, IO_ICU2, ENABLE_ICU1_AND_2,) 245 INTR(14,intr14, IO_ICU2, ENABLE_ICU1_AND_2,) 246 INTR(15,intr15, IO_ICU2, ENABLE_ICU1_AND_2,)
|
157
| 247
|
| 248 FAST_UNPEND(0,fastunpend0, IO_ICU1) 249 FAST_UNPEND(1,fastunpend1, IO_ICU1) 250 FAST_UNPEND(2,fastunpend2, IO_ICU1) 251 FAST_UNPEND(3,fastunpend3, IO_ICU1) 252 FAST_UNPEND(4,fastunpend4, IO_ICU1) 253 FAST_UNPEND(5,fastunpend5, IO_ICU1) 254 FAST_UNPEND(6,fastunpend6, IO_ICU1) 255 FAST_UNPEND(7,fastunpend7, IO_ICU1) 256 FAST_UNPEND(8,fastunpend8, IO_ICU2) 257 FAST_UNPEND(9,fastunpend9, IO_ICU2) 258 FAST_UNPEND(10,fastunpend10, IO_ICU2) 259 FAST_UNPEND(11,fastunpend11, IO_ICU2) 260 FAST_UNPEND(12,fastunpend12, IO_ICU2) 261 FAST_UNPEND(13,fastunpend13, IO_ICU2) 262 FAST_UNPEND(14,fastunpend14, IO_ICU2) 263 FAST_UNPEND(15,fastunpend15, IO_ICU2)
|
158MCOUNT_LABEL(eintr)
| 264MCOUNT_LABEL(eintr)
|
| 265
|
| |