Deleted Added
full compact
nmi.c (45676) nmi.c (45720)
1/*-
2 * Copyright (c) 1991 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * William Jolitz.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by the University of
19 * California, Berkeley and its contributors.
20 * 4. Neither the name of the University nor the names of its contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 *
36 * from: @(#)isa.c 7.2 (Berkeley) 5/13/91
1/*-
2 * Copyright (c) 1991 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * William Jolitz.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by the University of
19 * California, Berkeley and its contributors.
20 * 4. Neither the name of the University nor the names of its contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 *
36 * from: @(#)isa.c 7.2 (Berkeley) 5/13/91
37 * $Id: intr_machdep.c,v 1.16 1999/01/08 19:17:48 bde Exp $
37 * $Id: intr_machdep.c,v 1.17 1999/04/14 14:26:36 bde Exp $
38 */
39
40#include "opt_auto_eoi.h"
41
42#include <sys/param.h>
43#ifndef SMP
44#include <machine/lock.h>
45#endif
46#include <sys/systm.h>
47#include <sys/syslog.h>
48#include <machine/ipl.h>
49#include <machine/md_var.h>
50#include <machine/segments.h>
51#if defined(APIC_IO)
52#include <machine/smp.h>
53#include <machine/smptests.h> /** FAST_HI */
54#endif /* APIC_IO */
55#include <i386/isa/isa_device.h>
56#ifdef PC98
57#include <pc98/pc98/pc98.h>
58#include <pc98/pc98/pc98_machdep.h>
59#include <pc98/pc98/epsonio.h>
60#else
61#include <i386/isa/isa.h>
62#endif
63#include <i386/isa/icu.h>
64
65#include <i386/isa/intr_machdep.h>
66#include <sys/interrupt.h>
67#ifdef APIC_IO
68#include <machine/clock.h>
69#endif
70
71/* XXX should be in suitable include files */
72#ifdef PC98
73#define ICU_IMR_OFFSET 2 /* IO_ICU{1,2} + 2 */
74#define ICU_SLAVEID 7
75#else
76#define ICU_IMR_OFFSET 1 /* IO_ICU{1,2} + 1 */
77#define ICU_SLAVEID 2
78#endif
79
80#ifdef APIC_IO
81/*
82 * This is to accommodate "mixed-mode" programming for
83 * motherboards that don't connect the 8254 to the IO APIC.
84 */
85#define AUTO_EOI_1 1
86#endif
87
88#define NR_INTRNAMES (1 + ICU_LEN + 2 * ICU_LEN)
89
90u_long *intr_countp[ICU_LEN];
91inthand2_t *intr_handler[ICU_LEN];
92u_int intr_mask[ICU_LEN];
93static u_int* intr_mptr[ICU_LEN];
94void *intr_unit[ICU_LEN];
95
96static inthand_t *fastintr[ICU_LEN] = {
97 &IDTVEC(fastintr0), &IDTVEC(fastintr1),
98 &IDTVEC(fastintr2), &IDTVEC(fastintr3),
99 &IDTVEC(fastintr4), &IDTVEC(fastintr5),
100 &IDTVEC(fastintr6), &IDTVEC(fastintr7),
101 &IDTVEC(fastintr8), &IDTVEC(fastintr9),
102 &IDTVEC(fastintr10), &IDTVEC(fastintr11),
103 &IDTVEC(fastintr12), &IDTVEC(fastintr13),
104 &IDTVEC(fastintr14), &IDTVEC(fastintr15)
105#if defined(APIC_IO)
106 , &IDTVEC(fastintr16), &IDTVEC(fastintr17),
107 &IDTVEC(fastintr18), &IDTVEC(fastintr19),
108 &IDTVEC(fastintr20), &IDTVEC(fastintr21),
109 &IDTVEC(fastintr22), &IDTVEC(fastintr23)
110#endif /* APIC_IO */
111};
112
113static inthand_t *slowintr[ICU_LEN] = {
114 &IDTVEC(intr0), &IDTVEC(intr1), &IDTVEC(intr2), &IDTVEC(intr3),
115 &IDTVEC(intr4), &IDTVEC(intr5), &IDTVEC(intr6), &IDTVEC(intr7),
116 &IDTVEC(intr8), &IDTVEC(intr9), &IDTVEC(intr10), &IDTVEC(intr11),
117 &IDTVEC(intr12), &IDTVEC(intr13), &IDTVEC(intr14), &IDTVEC(intr15)
118#if defined(APIC_IO)
119 , &IDTVEC(intr16), &IDTVEC(intr17), &IDTVEC(intr18), &IDTVEC(intr19),
120 &IDTVEC(intr20), &IDTVEC(intr21), &IDTVEC(intr22), &IDTVEC(intr23)
121#endif /* APIC_IO */
122};
123
124static inthand2_t isa_strayintr;
125
126#ifdef PC98
127#define NMI_PARITY 0x04
128#define NMI_EPARITY 0x02
129#else
130#define NMI_PARITY (1 << 7)
131#define NMI_IOCHAN (1 << 6)
132#define ENMI_WATCHDOG (1 << 7)
133#define ENMI_BUSTIMER (1 << 6)
134#define ENMI_IOSTATUS (1 << 5)
135#endif
136
137/*
138 * Handle a NMI, possibly a machine check.
139 * return true to panic system, false to ignore.
140 */
141int
142isa_nmi(cd)
143 int cd;
144{
145#ifdef PC98
146 int port = inb(0x33);
147 if (epson_machine_id == 0x20)
148 epson_outb(0xc16, epson_inb(0xc16) | 0x1);
149 if (port & NMI_PARITY) {
150 panic("BASE RAM parity error, likely hardware failure.");
151 } else if (port & NMI_EPARITY) {
152 panic("EXTENDED RAM parity error, likely hardware failure.");
153 } else {
154 printf("\nNMI Resume ??\n");
155 return(0);
156 }
157#else /* IBM-PC */
158 int isa_port = inb(0x61);
159 int eisa_port = inb(0x461);
160
161 if (isa_port & NMI_PARITY)
162 panic("RAM parity error, likely hardware failure.");
163
164 if (isa_port & NMI_IOCHAN)
165 panic("I/O channel check, likely hardware failure.");
166
167 /*
168 * On a real EISA machine, this will never happen. However it can
169 * happen on ISA machines which implement XT style floating point
170 * error handling (very rare). Save them from a meaningless panic.
171 */
172 if (eisa_port == 0xff)
173 return(0);
174
175 if (eisa_port & ENMI_WATCHDOG)
176 panic("EISA watchdog timer expired, likely hardware failure.");
177
178 if (eisa_port & ENMI_BUSTIMER)
179 panic("EISA bus timeout, likely hardware failure.");
180
181 if (eisa_port & ENMI_IOSTATUS)
182 panic("EISA I/O port status error.");
183
184 printf("\nNMI ISA %x, EISA %x\n", isa_port, eisa_port);
185 return(0);
186#endif
187}
188
189/*
190 * Fill in default interrupt table (in case of spuruious interrupt
191 * during configuration of kernel, setup interrupt control unit
192 */
193void
194isa_defaultirq()
195{
196 int i;
197
198 /* icu vectors */
199 for (i = 0; i < ICU_LEN; i++)
200 icu_unset(i, (inthand2_t *)NULL);
201
202 /* initialize 8259's */
203 outb(IO_ICU1, 0x11); /* reset; program device, four bytes */
204
205 outb(IO_ICU1+ICU_IMR_OFFSET, NRSVIDT); /* starting at this vector index */
206 outb(IO_ICU1+ICU_IMR_OFFSET, IRQ_SLAVE); /* slave on line 7 */
207#ifdef PC98
208#ifdef AUTO_EOI_1
209 outb(IO_ICU1+ICU_IMR_OFFSET, 0x1f); /* (master) auto EOI, 8086 mode */
210#else
211 outb(IO_ICU1+ICU_IMR_OFFSET, 0x1d); /* (master) 8086 mode */
212#endif
213#else /* IBM-PC */
214#ifdef AUTO_EOI_1
215 outb(IO_ICU1+ICU_IMR_OFFSET, 2 | 1); /* auto EOI, 8086 mode */
216#else
217 outb(IO_ICU1+ICU_IMR_OFFSET, 1); /* 8086 mode */
218#endif
219#endif /* PC98 */
220 outb(IO_ICU1+ICU_IMR_OFFSET, 0xff); /* leave interrupts masked */
221 outb(IO_ICU1, 0x0a); /* default to IRR on read */
222#ifndef PC98
223 outb(IO_ICU1, 0xc0 | (3 - 1)); /* pri order 3-7, 0-2 (com2 first) */
224#endif /* !PC98 */
225
226 outb(IO_ICU2, 0x11); /* reset; program device, four bytes */
227 outb(IO_ICU2+ICU_IMR_OFFSET, NRSVIDT+8); /* staring at this vector index */
228 outb(IO_ICU2+ICU_IMR_OFFSET, ICU_SLAVEID); /* my slave id is 7 */
229#ifdef PC98
230 outb(IO_ICU2+ICU_IMR_OFFSET,9); /* 8086 mode */
231#else /* IBM-PC */
232#ifdef AUTO_EOI_2
233 outb(IO_ICU2+ICU_IMR_OFFSET, 2 | 1); /* auto EOI, 8086 mode */
234#else
235 outb(IO_ICU2+ICU_IMR_OFFSET,1); /* 8086 mode */
236#endif
237#endif /* PC98 */
238 outb(IO_ICU2+ICU_IMR_OFFSET, 0xff); /* leave interrupts masked */
239 outb(IO_ICU2, 0x0a); /* default to IRR on read */
240}
241
242/*
243 * Caught a stray interrupt, notify
244 */
245static void
246isa_strayintr(vcookiep)
247 void *vcookiep;
248{
249 int intr = (void **)vcookiep - &intr_unit[0];
250
251 /* DON'T BOTHER FOR NOW! */
252 /* for some reason, we get bursts of intr #7, even if not enabled! */
253 /*
254 * Well the reason you got bursts of intr #7 is because someone
255 * raised an interrupt line and dropped it before the 8259 could
256 * prioritize it. This is documented in the intel data book. This
257 * means you have BAD hardware! I have changed this so that only
258 * the first 5 get logged, then it quits logging them, and puts
259 * out a special message. rgrimes 3/25/1993
260 */
261 /*
262 * XXX TODO print a different message for #7 if it is for a
263 * glitch. Glitches can be distinguished from real #7's by
264 * testing that the in-service bit is _not_ set. The test
265 * must be done before sending an EOI so it can't be done if
266 * we are using AUTO_EOI_1.
267 */
268 if (intrcnt[1 + intr] <= 5)
269 log(LOG_ERR, "stray irq %d\n", intr);
270 if (intrcnt[1 + intr] == 5)
271 log(LOG_CRIT,
272 "too many stray irq %d's; not logging any more\n", intr);
273}
274
275/*
276 * Return a bitmap of the current interrupt requests. This is 8259-specific
277 * and is only suitable for use at probe time.
278 */
279intrmask_t
280isa_irq_pending()
281{
282 u_char irr1;
283 u_char irr2;
284
285 irr1 = inb(IO_ICU1);
286 irr2 = inb(IO_ICU2);
287 return ((irr2 << 8) | irr1);
288}
289
290int
291update_intr_masks(void)
292{
293 int intr, n=0;
294 u_int mask,*maskptr;
295
296 for (intr=0; intr < ICU_LEN; intr ++) {
297#if defined(APIC_IO)
298 /* no 8259 SLAVE to ignore */
299#else
300 if (intr==ICU_SLAVEID) continue; /* ignore 8259 SLAVE output */
301#endif /* APIC_IO */
302 maskptr = intr_mptr[intr];
303 if (!maskptr) continue;
304 *maskptr |= 1 << intr;
305 mask = *maskptr;
306 if (mask != intr_mask[intr]) {
307#if 0
308 printf ("intr_mask[%2d] old=%08x new=%08x ptr=%p.\n",
309 intr, intr_mask[intr], mask, maskptr);
310#endif
311 intr_mask[intr]=mask;
312 n++;
313 }
314
315 }
316 return (n);
317}
318
319static const char *
320isa_get_nameunit(int id)
321{
322 static char buf[32];
323 struct isa_device *dp;
324
325 if (id == -1)
326 return ("pci"); /* XXX may also be eisa */
327 if (id == 0)
328 return ("clk0"); /* XXX may also be sloppy driver */
329 if (id == 1)
330 return ("rtc0");
38 */
39
40#include "opt_auto_eoi.h"
41
42#include <sys/param.h>
43#ifndef SMP
44#include <machine/lock.h>
45#endif
46#include <sys/systm.h>
47#include <sys/syslog.h>
48#include <machine/ipl.h>
49#include <machine/md_var.h>
50#include <machine/segments.h>
51#if defined(APIC_IO)
52#include <machine/smp.h>
53#include <machine/smptests.h> /** FAST_HI */
54#endif /* APIC_IO */
55#include <i386/isa/isa_device.h>
56#ifdef PC98
57#include <pc98/pc98/pc98.h>
58#include <pc98/pc98/pc98_machdep.h>
59#include <pc98/pc98/epsonio.h>
60#else
61#include <i386/isa/isa.h>
62#endif
63#include <i386/isa/icu.h>
64
65#include <i386/isa/intr_machdep.h>
66#include <sys/interrupt.h>
67#ifdef APIC_IO
68#include <machine/clock.h>
69#endif
70
71/* XXX should be in suitable include files */
72#ifdef PC98
73#define ICU_IMR_OFFSET 2 /* IO_ICU{1,2} + 2 */
74#define ICU_SLAVEID 7
75#else
76#define ICU_IMR_OFFSET 1 /* IO_ICU{1,2} + 1 */
77#define ICU_SLAVEID 2
78#endif
79
80#ifdef APIC_IO
81/*
82 * This is to accommodate "mixed-mode" programming for
83 * motherboards that don't connect the 8254 to the IO APIC.
84 */
85#define AUTO_EOI_1 1
86#endif
87
88#define NR_INTRNAMES (1 + ICU_LEN + 2 * ICU_LEN)
89
90u_long *intr_countp[ICU_LEN];
91inthand2_t *intr_handler[ICU_LEN];
92u_int intr_mask[ICU_LEN];
93static u_int* intr_mptr[ICU_LEN];
94void *intr_unit[ICU_LEN];
95
96static inthand_t *fastintr[ICU_LEN] = {
97 &IDTVEC(fastintr0), &IDTVEC(fastintr1),
98 &IDTVEC(fastintr2), &IDTVEC(fastintr3),
99 &IDTVEC(fastintr4), &IDTVEC(fastintr5),
100 &IDTVEC(fastintr6), &IDTVEC(fastintr7),
101 &IDTVEC(fastintr8), &IDTVEC(fastintr9),
102 &IDTVEC(fastintr10), &IDTVEC(fastintr11),
103 &IDTVEC(fastintr12), &IDTVEC(fastintr13),
104 &IDTVEC(fastintr14), &IDTVEC(fastintr15)
105#if defined(APIC_IO)
106 , &IDTVEC(fastintr16), &IDTVEC(fastintr17),
107 &IDTVEC(fastintr18), &IDTVEC(fastintr19),
108 &IDTVEC(fastintr20), &IDTVEC(fastintr21),
109 &IDTVEC(fastintr22), &IDTVEC(fastintr23)
110#endif /* APIC_IO */
111};
112
113static inthand_t *slowintr[ICU_LEN] = {
114 &IDTVEC(intr0), &IDTVEC(intr1), &IDTVEC(intr2), &IDTVEC(intr3),
115 &IDTVEC(intr4), &IDTVEC(intr5), &IDTVEC(intr6), &IDTVEC(intr7),
116 &IDTVEC(intr8), &IDTVEC(intr9), &IDTVEC(intr10), &IDTVEC(intr11),
117 &IDTVEC(intr12), &IDTVEC(intr13), &IDTVEC(intr14), &IDTVEC(intr15)
118#if defined(APIC_IO)
119 , &IDTVEC(intr16), &IDTVEC(intr17), &IDTVEC(intr18), &IDTVEC(intr19),
120 &IDTVEC(intr20), &IDTVEC(intr21), &IDTVEC(intr22), &IDTVEC(intr23)
121#endif /* APIC_IO */
122};
123
124static inthand2_t isa_strayintr;
125
126#ifdef PC98
127#define NMI_PARITY 0x04
128#define NMI_EPARITY 0x02
129#else
130#define NMI_PARITY (1 << 7)
131#define NMI_IOCHAN (1 << 6)
132#define ENMI_WATCHDOG (1 << 7)
133#define ENMI_BUSTIMER (1 << 6)
134#define ENMI_IOSTATUS (1 << 5)
135#endif
136
137/*
138 * Handle a NMI, possibly a machine check.
139 * return true to panic system, false to ignore.
140 */
141int
142isa_nmi(cd)
143 int cd;
144{
145#ifdef PC98
146 int port = inb(0x33);
147 if (epson_machine_id == 0x20)
148 epson_outb(0xc16, epson_inb(0xc16) | 0x1);
149 if (port & NMI_PARITY) {
150 panic("BASE RAM parity error, likely hardware failure.");
151 } else if (port & NMI_EPARITY) {
152 panic("EXTENDED RAM parity error, likely hardware failure.");
153 } else {
154 printf("\nNMI Resume ??\n");
155 return(0);
156 }
157#else /* IBM-PC */
158 int isa_port = inb(0x61);
159 int eisa_port = inb(0x461);
160
161 if (isa_port & NMI_PARITY)
162 panic("RAM parity error, likely hardware failure.");
163
164 if (isa_port & NMI_IOCHAN)
165 panic("I/O channel check, likely hardware failure.");
166
167 /*
168 * On a real EISA machine, this will never happen. However it can
169 * happen on ISA machines which implement XT style floating point
170 * error handling (very rare). Save them from a meaningless panic.
171 */
172 if (eisa_port == 0xff)
173 return(0);
174
175 if (eisa_port & ENMI_WATCHDOG)
176 panic("EISA watchdog timer expired, likely hardware failure.");
177
178 if (eisa_port & ENMI_BUSTIMER)
179 panic("EISA bus timeout, likely hardware failure.");
180
181 if (eisa_port & ENMI_IOSTATUS)
182 panic("EISA I/O port status error.");
183
184 printf("\nNMI ISA %x, EISA %x\n", isa_port, eisa_port);
185 return(0);
186#endif
187}
188
189/*
190 * Fill in default interrupt table (in case of spuruious interrupt
191 * during configuration of kernel, setup interrupt control unit
192 */
193void
194isa_defaultirq()
195{
196 int i;
197
198 /* icu vectors */
199 for (i = 0; i < ICU_LEN; i++)
200 icu_unset(i, (inthand2_t *)NULL);
201
202 /* initialize 8259's */
203 outb(IO_ICU1, 0x11); /* reset; program device, four bytes */
204
205 outb(IO_ICU1+ICU_IMR_OFFSET, NRSVIDT); /* starting at this vector index */
206 outb(IO_ICU1+ICU_IMR_OFFSET, IRQ_SLAVE); /* slave on line 7 */
207#ifdef PC98
208#ifdef AUTO_EOI_1
209 outb(IO_ICU1+ICU_IMR_OFFSET, 0x1f); /* (master) auto EOI, 8086 mode */
210#else
211 outb(IO_ICU1+ICU_IMR_OFFSET, 0x1d); /* (master) 8086 mode */
212#endif
213#else /* IBM-PC */
214#ifdef AUTO_EOI_1
215 outb(IO_ICU1+ICU_IMR_OFFSET, 2 | 1); /* auto EOI, 8086 mode */
216#else
217 outb(IO_ICU1+ICU_IMR_OFFSET, 1); /* 8086 mode */
218#endif
219#endif /* PC98 */
220 outb(IO_ICU1+ICU_IMR_OFFSET, 0xff); /* leave interrupts masked */
221 outb(IO_ICU1, 0x0a); /* default to IRR on read */
222#ifndef PC98
223 outb(IO_ICU1, 0xc0 | (3 - 1)); /* pri order 3-7, 0-2 (com2 first) */
224#endif /* !PC98 */
225
226 outb(IO_ICU2, 0x11); /* reset; program device, four bytes */
227 outb(IO_ICU2+ICU_IMR_OFFSET, NRSVIDT+8); /* staring at this vector index */
228 outb(IO_ICU2+ICU_IMR_OFFSET, ICU_SLAVEID); /* my slave id is 7 */
229#ifdef PC98
230 outb(IO_ICU2+ICU_IMR_OFFSET,9); /* 8086 mode */
231#else /* IBM-PC */
232#ifdef AUTO_EOI_2
233 outb(IO_ICU2+ICU_IMR_OFFSET, 2 | 1); /* auto EOI, 8086 mode */
234#else
235 outb(IO_ICU2+ICU_IMR_OFFSET,1); /* 8086 mode */
236#endif
237#endif /* PC98 */
238 outb(IO_ICU2+ICU_IMR_OFFSET, 0xff); /* leave interrupts masked */
239 outb(IO_ICU2, 0x0a); /* default to IRR on read */
240}
241
242/*
243 * Caught a stray interrupt, notify
244 */
245static void
246isa_strayintr(vcookiep)
247 void *vcookiep;
248{
249 int intr = (void **)vcookiep - &intr_unit[0];
250
251 /* DON'T BOTHER FOR NOW! */
252 /* for some reason, we get bursts of intr #7, even if not enabled! */
253 /*
254 * Well the reason you got bursts of intr #7 is because someone
255 * raised an interrupt line and dropped it before the 8259 could
256 * prioritize it. This is documented in the intel data book. This
257 * means you have BAD hardware! I have changed this so that only
258 * the first 5 get logged, then it quits logging them, and puts
259 * out a special message. rgrimes 3/25/1993
260 */
261 /*
262 * XXX TODO print a different message for #7 if it is for a
263 * glitch. Glitches can be distinguished from real #7's by
264 * testing that the in-service bit is _not_ set. The test
265 * must be done before sending an EOI so it can't be done if
266 * we are using AUTO_EOI_1.
267 */
268 if (intrcnt[1 + intr] <= 5)
269 log(LOG_ERR, "stray irq %d\n", intr);
270 if (intrcnt[1 + intr] == 5)
271 log(LOG_CRIT,
272 "too many stray irq %d's; not logging any more\n", intr);
273}
274
275/*
276 * Return a bitmap of the current interrupt requests. This is 8259-specific
277 * and is only suitable for use at probe time.
278 */
279intrmask_t
280isa_irq_pending()
281{
282 u_char irr1;
283 u_char irr2;
284
285 irr1 = inb(IO_ICU1);
286 irr2 = inb(IO_ICU2);
287 return ((irr2 << 8) | irr1);
288}
289
290int
291update_intr_masks(void)
292{
293 int intr, n=0;
294 u_int mask,*maskptr;
295
296 for (intr=0; intr < ICU_LEN; intr ++) {
297#if defined(APIC_IO)
298 /* no 8259 SLAVE to ignore */
299#else
300 if (intr==ICU_SLAVEID) continue; /* ignore 8259 SLAVE output */
301#endif /* APIC_IO */
302 maskptr = intr_mptr[intr];
303 if (!maskptr) continue;
304 *maskptr |= 1 << intr;
305 mask = *maskptr;
306 if (mask != intr_mask[intr]) {
307#if 0
308 printf ("intr_mask[%2d] old=%08x new=%08x ptr=%p.\n",
309 intr, intr_mask[intr], mask, maskptr);
310#endif
311 intr_mask[intr]=mask;
312 n++;
313 }
314
315 }
316 return (n);
317}
318
319static const char *
320isa_get_nameunit(int id)
321{
322 static char buf[32];
323 struct isa_device *dp;
324
325 if (id == -1)
326 return ("pci"); /* XXX may also be eisa */
327 if (id == 0)
328 return ("clk0"); /* XXX may also be sloppy driver */
329 if (id == 1)
330 return ("rtc0");
331#if 0
331 for (dp = isa_devtab_bio; dp->id_driver != NULL; dp++)
332 if (dp->id_id == id)
333 goto found_device;
334 for (dp = isa_devtab_cam; dp->id_driver != NULL; dp++)
335 if (dp->id_id == id)
336 goto found_device;
337 for (dp = isa_devtab_net; dp->id_driver != NULL; dp++)
338 if (dp->id_id == id)
339 goto found_device;
340 for (dp = isa_devtab_null; dp->id_driver != NULL; dp++)
341 if (dp->id_id == id)
342 goto found_device;
343 for (dp = isa_devtab_tty; dp->id_driver != NULL; dp++)
344 if (dp->id_id == id)
345 goto found_device;
332 for (dp = isa_devtab_bio; dp->id_driver != NULL; dp++)
333 if (dp->id_id == id)
334 goto found_device;
335 for (dp = isa_devtab_cam; dp->id_driver != NULL; dp++)
336 if (dp->id_id == id)
337 goto found_device;
338 for (dp = isa_devtab_net; dp->id_driver != NULL; dp++)
339 if (dp->id_id == id)
340 goto found_device;
341 for (dp = isa_devtab_null; dp->id_driver != NULL; dp++)
342 if (dp->id_id == id)
343 goto found_device;
344 for (dp = isa_devtab_tty; dp->id_driver != NULL; dp++)
345 if (dp->id_id == id)
346 goto found_device;
347#endif
346 return "???";
347
348found_device:
349 snprintf(buf, sizeof(buf), "%s%d", dp->id_driver->name, dp->id_unit);
350 return (buf);
351}
352
353void
354update_intrname(int intr, int device_id)
355{
356 char buf[32];
357 char *cp;
358 const char *name;
359 int name_index, off, strayintr;
360
361 /*
362 * Initialise strings for bitbucket and stray interrupt counters.
363 * These have statically allocated indices 0 and 1 through ICU_LEN.
364 */
365 if (intrnames[0] == '\0') {
366 off = sprintf(intrnames, "???") + 1;
367 for (strayintr = 0; strayintr < ICU_LEN; strayintr++)
368 off += sprintf(intrnames + off, "stray irq%d",
369 strayintr) + 1;
370 }
371
372 name = isa_get_nameunit(device_id);
373 if (snprintf(buf, sizeof(buf), "%s irq%d", name, intr) >= sizeof(buf))
374 goto use_bitbucket;
375
376 /*
377 * Search for `buf' in `intrnames'. In the usual case when it is
378 * not found, append it to the end if there is enough space (the \0
379 * terminator for the previous string, if any, becomes a separator).
380 */
381 for (cp = intrnames, name_index = 0;
382 cp != eintrnames && name_index < NR_INTRNAMES;
383 cp += strlen(cp) + 1, name_index++) {
384 if (*cp == '\0') {
385 if (strlen(buf) >= eintrnames - cp)
386 break;
387 strcpy(cp, buf);
388 goto found;
389 }
390 if (strcmp(cp, buf) == 0)
391 goto found;
392 }
393
394use_bitbucket:
395 printf("update_intrname: counting %s irq%d as %s\n", name, intr,
396 intrnames);
397 name_index = 0;
398found:
399 intr_countp[intr] = &intrcnt[name_index];
400}
401
402int
403icu_setup(int intr, inthand2_t *handler, void *arg, u_int *maskptr, int flags)
404{
405#ifdef FAST_HI
406 int select; /* the select register is 8 bits */
407 int vector;
408 u_int32_t value; /* the window register is 32 bits */
409#endif /* FAST_HI */
410 u_long ef;
411 u_int mask = (maskptr ? *maskptr : 0);
412
413#if defined(APIC_IO)
414 if ((u_int)intr >= ICU_LEN) /* no 8259 SLAVE to ignore */
415#else
416 if ((u_int)intr >= ICU_LEN || intr == ICU_SLAVEID)
417#endif /* APIC_IO */
418 if (intr_handler[intr] != isa_strayintr)
419 return (EBUSY);
420
421 ef = read_eflags();
422 disable_intr();
423 intr_handler[intr] = handler;
424 intr_mptr[intr] = maskptr;
425 intr_mask[intr] = mask | (1 << intr);
426 intr_unit[intr] = arg;
427#ifdef FAST_HI
428 if (flags & INTR_FAST) {
429 vector = TPR_FAST_INTS + intr;
430 setidt(vector, fastintr[intr],
431 SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
432 }
433 else {
434 vector = TPR_SLOW_INTS + intr;
435#ifdef APIC_INTR_REORDER
436#ifdef APIC_INTR_HIGHPRI_CLOCK
437 /* XXX: Hack (kludge?) for more accurate clock. */
438 if (intr == apic_8254_intr || intr == 8) {
439 vector = TPR_FAST_INTS + intr;
440 }
441#endif
442#endif
443 setidt(vector, slowintr[intr],
444 SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
445 }
446#ifdef APIC_INTR_REORDER
447 set_lapic_isrloc(intr, vector);
448#endif
449 /*
450 * Reprogram the vector in the IO APIC.
451 */
452 if (int_to_apicintpin[intr].ioapic >= 0) {
453 select = int_to_apicintpin[intr].redirindex;
454 value = io_apic_read(int_to_apicintpin[intr].ioapic,
455 select) & ~IOART_INTVEC;
456 io_apic_write(int_to_apicintpin[intr].ioapic,
457 select, value | vector);
458 }
459#else
460 setidt(ICU_OFFSET + intr,
461 flags & INTR_FAST ? fastintr[intr] : slowintr[intr],
462 SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
463#endif /* FAST_HI */
464 INTREN(1 << intr);
465 MPINTR_UNLOCK();
466 write_eflags(ef);
467 return (0);
468}
469
470void
471register_imask(dvp, mask)
472 struct isa_device *dvp;
473 u_int mask;
474{
475 if (dvp->id_alive && dvp->id_irq) {
476 int intr;
477
478 intr = ffs(dvp->id_irq) - 1;
479 intr_mask[intr] = mask | (1 <<intr);
480 }
481 (void) update_intr_masks();
482}
483
484int
485icu_unset(intr, handler)
486 int intr;
487 inthand2_t *handler;
488{
489 u_long ef;
490
491 if ((u_int)intr >= ICU_LEN || handler != intr_handler[intr])
492 return (EINVAL);
493
494 INTRDIS(1 << intr);
495 ef = read_eflags();
496 disable_intr();
497 intr_countp[intr] = &intrcnt[1 + intr];
498 intr_handler[intr] = isa_strayintr;
499 intr_mptr[intr] = NULL;
500 intr_mask[intr] = HWI_MASK | SWI_MASK;
501 intr_unit[intr] = &intr_unit[intr];
502#ifdef FAST_HI_XXX
503 /* XXX how do I re-create dvp here? */
504 setidt(flags & INTR_FAST ? TPR_FAST_INTS + intr : TPR_SLOW_INTS + intr,
505 slowintr[intr], SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
506#else /* FAST_HI */
507#ifdef APIC_INTR_REORDER
508 set_lapic_isrloc(intr, ICU_OFFSET + intr);
509#endif
510 setidt(ICU_OFFSET + intr, slowintr[intr], SDT_SYS386IGT, SEL_KPL,
511 GSEL(GCODE_SEL, SEL_KPL));
512#endif /* FAST_HI */
513 MPINTR_UNLOCK();
514 write_eflags(ef);
515 return (0);
516}
348 return "???";
349
350found_device:
351 snprintf(buf, sizeof(buf), "%s%d", dp->id_driver->name, dp->id_unit);
352 return (buf);
353}
354
355void
356update_intrname(int intr, int device_id)
357{
358 char buf[32];
359 char *cp;
360 const char *name;
361 int name_index, off, strayintr;
362
363 /*
364 * Initialise strings for bitbucket and stray interrupt counters.
365 * These have statically allocated indices 0 and 1 through ICU_LEN.
366 */
367 if (intrnames[0] == '\0') {
368 off = sprintf(intrnames, "???") + 1;
369 for (strayintr = 0; strayintr < ICU_LEN; strayintr++)
370 off += sprintf(intrnames + off, "stray irq%d",
371 strayintr) + 1;
372 }
373
374 name = isa_get_nameunit(device_id);
375 if (snprintf(buf, sizeof(buf), "%s irq%d", name, intr) >= sizeof(buf))
376 goto use_bitbucket;
377
378 /*
379 * Search for `buf' in `intrnames'. In the usual case when it is
380 * not found, append it to the end if there is enough space (the \0
381 * terminator for the previous string, if any, becomes a separator).
382 */
383 for (cp = intrnames, name_index = 0;
384 cp != eintrnames && name_index < NR_INTRNAMES;
385 cp += strlen(cp) + 1, name_index++) {
386 if (*cp == '\0') {
387 if (strlen(buf) >= eintrnames - cp)
388 break;
389 strcpy(cp, buf);
390 goto found;
391 }
392 if (strcmp(cp, buf) == 0)
393 goto found;
394 }
395
396use_bitbucket:
397 printf("update_intrname: counting %s irq%d as %s\n", name, intr,
398 intrnames);
399 name_index = 0;
400found:
401 intr_countp[intr] = &intrcnt[name_index];
402}
403
404int
405icu_setup(int intr, inthand2_t *handler, void *arg, u_int *maskptr, int flags)
406{
407#ifdef FAST_HI
408 int select; /* the select register is 8 bits */
409 int vector;
410 u_int32_t value; /* the window register is 32 bits */
411#endif /* FAST_HI */
412 u_long ef;
413 u_int mask = (maskptr ? *maskptr : 0);
414
415#if defined(APIC_IO)
416 if ((u_int)intr >= ICU_LEN) /* no 8259 SLAVE to ignore */
417#else
418 if ((u_int)intr >= ICU_LEN || intr == ICU_SLAVEID)
419#endif /* APIC_IO */
420 if (intr_handler[intr] != isa_strayintr)
421 return (EBUSY);
422
423 ef = read_eflags();
424 disable_intr();
425 intr_handler[intr] = handler;
426 intr_mptr[intr] = maskptr;
427 intr_mask[intr] = mask | (1 << intr);
428 intr_unit[intr] = arg;
429#ifdef FAST_HI
430 if (flags & INTR_FAST) {
431 vector = TPR_FAST_INTS + intr;
432 setidt(vector, fastintr[intr],
433 SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
434 }
435 else {
436 vector = TPR_SLOW_INTS + intr;
437#ifdef APIC_INTR_REORDER
438#ifdef APIC_INTR_HIGHPRI_CLOCK
439 /* XXX: Hack (kludge?) for more accurate clock. */
440 if (intr == apic_8254_intr || intr == 8) {
441 vector = TPR_FAST_INTS + intr;
442 }
443#endif
444#endif
445 setidt(vector, slowintr[intr],
446 SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
447 }
448#ifdef APIC_INTR_REORDER
449 set_lapic_isrloc(intr, vector);
450#endif
451 /*
452 * Reprogram the vector in the IO APIC.
453 */
454 if (int_to_apicintpin[intr].ioapic >= 0) {
455 select = int_to_apicintpin[intr].redirindex;
456 value = io_apic_read(int_to_apicintpin[intr].ioapic,
457 select) & ~IOART_INTVEC;
458 io_apic_write(int_to_apicintpin[intr].ioapic,
459 select, value | vector);
460 }
461#else
462 setidt(ICU_OFFSET + intr,
463 flags & INTR_FAST ? fastintr[intr] : slowintr[intr],
464 SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
465#endif /* FAST_HI */
466 INTREN(1 << intr);
467 MPINTR_UNLOCK();
468 write_eflags(ef);
469 return (0);
470}
471
472void
473register_imask(dvp, mask)
474 struct isa_device *dvp;
475 u_int mask;
476{
477 if (dvp->id_alive && dvp->id_irq) {
478 int intr;
479
480 intr = ffs(dvp->id_irq) - 1;
481 intr_mask[intr] = mask | (1 <<intr);
482 }
483 (void) update_intr_masks();
484}
485
486int
487icu_unset(intr, handler)
488 int intr;
489 inthand2_t *handler;
490{
491 u_long ef;
492
493 if ((u_int)intr >= ICU_LEN || handler != intr_handler[intr])
494 return (EINVAL);
495
496 INTRDIS(1 << intr);
497 ef = read_eflags();
498 disable_intr();
499 intr_countp[intr] = &intrcnt[1 + intr];
500 intr_handler[intr] = isa_strayintr;
501 intr_mptr[intr] = NULL;
502 intr_mask[intr] = HWI_MASK | SWI_MASK;
503 intr_unit[intr] = &intr_unit[intr];
504#ifdef FAST_HI_XXX
505 /* XXX how do I re-create dvp here? */
506 setidt(flags & INTR_FAST ? TPR_FAST_INTS + intr : TPR_SLOW_INTS + intr,
507 slowintr[intr], SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
508#else /* FAST_HI */
509#ifdef APIC_INTR_REORDER
510 set_lapic_isrloc(intr, ICU_OFFSET + intr);
511#endif
512 setidt(ICU_OFFSET + intr, slowintr[intr], SDT_SYS386IGT, SEL_KPL,
513 GSEL(GCODE_SEL, SEL_KPL));
514#endif /* FAST_HI */
515 MPINTR_UNLOCK();
516 write_eflags(ef);
517 return (0);
518}