atpic.c revision 329462
1121985Sjhb/*-
2121985Sjhb * Copyright (c) 2003 John Baldwin <jhb@FreeBSD.org>
3121985Sjhb * All rights reserved.
4121985Sjhb *
5121985Sjhb * Redistribution and use in source and binary forms, with or without
6121985Sjhb * modification, are permitted provided that the following conditions
7121985Sjhb * are met:
8121985Sjhb * 1. Redistributions of source code must retain the above copyright
9121985Sjhb *    notice, this list of conditions and the following disclaimer.
10121985Sjhb * 2. Redistributions in binary form must reproduce the above copyright
11121985Sjhb *    notice, this list of conditions and the following disclaimer in the
12121985Sjhb *    documentation and/or other materials provided with the distribution.
13121985Sjhb *
14121985Sjhb * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15121985Sjhb * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16121985Sjhb * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17121985Sjhb * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18121985Sjhb * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19121985Sjhb * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20121985Sjhb * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21121985Sjhb * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22121985Sjhb * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23121985Sjhb * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24121985Sjhb * SUCH DAMAGE.
25121985Sjhb */
26121985Sjhb
27121985Sjhb/*
28121985Sjhb * PIC driver for the 8259A Master and Slave PICs in PC/AT machines.
29121985Sjhb */
30121985Sjhb
31121985Sjhb#include <sys/cdefs.h>
32121985Sjhb__FBSDID("$FreeBSD: stable/11/sys/x86/isa/atpic.c 329462 2018-02-17 18:00:01Z kib $");
33121985Sjhb
34121985Sjhb#include "opt_auto_eoi.h"
35121985Sjhb#include "opt_isa.h"
36277285Simp#include "opt_mca.h"
37121985Sjhb
38121985Sjhb#include <sys/param.h>
39121985Sjhb#include <sys/systm.h>
40121985Sjhb#include <sys/bus.h>
41121985Sjhb#include <sys/interrupt.h>
42121985Sjhb#include <sys/kernel.h>
43121985Sjhb#include <sys/lock.h>
44129876Sphk#include <sys/module.h>
45121985Sjhb
46121985Sjhb#include <machine/cpufunc.h>
47121985Sjhb#include <machine/frame.h>
48121985Sjhb#include <machine/intr_machdep.h>
49121985Sjhb#include <machine/md_var.h>
50121985Sjhb#include <machine/resource.h>
51121985Sjhb#include <machine/segments.h>
52121985Sjhb
53124188Sjhb#include <dev/ic/i8259.h>
54204309Sattilio#include <x86/isa/icu.h>
55122051Snyan#ifdef PC98
56146049Snyan#include <pc98/cbus/cbus.h>
57122051Snyan#else
58263379Simp#include <isa/isareg.h>
59122051Snyan#endif
60121985Sjhb#include <isa/isavar.h>
61277311Simp#ifdef DEV_MCA
62277311Simp#include <i386/bios/mca_machdep.h>
63277311Simp#endif
64121985Sjhb
65204309Sattilio#ifdef __amd64__
66204309Sattilio#define	SDT_ATPIC	SDT_SYSIGT
67204309Sattilio#define	GSEL_ATPIC	0
68204309Sattilio#else
69204309Sattilio#define	SDT_ATPIC	SDT_SYS386IGT
70204309Sattilio#define	GSEL_ATPIC	GSEL(GCODE_SEL, SEL_KPL)
71204309Sattilio#endif
72204309Sattilio
73121985Sjhb#define	MASTER	0
74121985Sjhb#define	SLAVE	1
75121985Sjhb
76128875Sjhb#define	NUM_ISA_IRQS		16
77128875Sjhb
78121985Sjhbstatic void	atpic_init(void *dummy);
79121985Sjhb
80121985Sjhbunsigned int imen;	/* XXX */
81121985Sjhb
82121985Sjhbinthand_t
83121985Sjhb	IDTVEC(atpic_intr0), IDTVEC(atpic_intr1), IDTVEC(atpic_intr2),
84121985Sjhb	IDTVEC(atpic_intr3), IDTVEC(atpic_intr4), IDTVEC(atpic_intr5),
85121985Sjhb	IDTVEC(atpic_intr6), IDTVEC(atpic_intr7), IDTVEC(atpic_intr8),
86121985Sjhb	IDTVEC(atpic_intr9), IDTVEC(atpic_intr10), IDTVEC(atpic_intr11),
87121985Sjhb	IDTVEC(atpic_intr12), IDTVEC(atpic_intr13), IDTVEC(atpic_intr14),
88121985Sjhb	IDTVEC(atpic_intr15);
89329462Skib/* XXXKIB i386 uses stubs until pti comes */
90329462Skibinthand_t
91329462Skib	IDTVEC(atpic_intr0_pti), IDTVEC(atpic_intr1_pti),
92329462Skib	IDTVEC(atpic_intr2_pti), IDTVEC(atpic_intr3_pti),
93329462Skib	IDTVEC(atpic_intr4_pti), IDTVEC(atpic_intr5_pti),
94329462Skib	IDTVEC(atpic_intr6_pti), IDTVEC(atpic_intr7_pti),
95329462Skib	IDTVEC(atpic_intr8_pti), IDTVEC(atpic_intr9_pti),
96329462Skib	IDTVEC(atpic_intr10_pti), IDTVEC(atpic_intr11_pti),
97329462Skib	IDTVEC(atpic_intr12_pti), IDTVEC(atpic_intr13_pti),
98329462Skib	IDTVEC(atpic_intr14_pti), IDTVEC(atpic_intr15_pti);
99121985Sjhb
100121985Sjhb#define	IRQ(ap, ai)	((ap)->at_irqbase + (ai)->at_irq)
101121985Sjhb
102128929Sjhb#define	ATPIC(io, base, eoi, imenptr)					\
103121985Sjhb     	{ { atpic_enable_source, atpic_disable_source, (eoi),		\
104169391Sjhb	    atpic_enable_intr, atpic_disable_intr, atpic_vector,	\
105169391Sjhb	    atpic_source_pending, NULL,	atpic_resume, atpic_config_intr,\
106169391Sjhb	    atpic_assign_cpu }, (io), (base), IDT_IO_INTS + (base),	\
107169391Sjhb	    (imenptr) }
108121985Sjhb
109121985Sjhb#define	INTSRC(irq)							\
110128929Sjhb	{ { &atpics[(irq) / 8].at_pic }, IDTVEC(atpic_intr ## irq ),	\
111329462Skib	    IDTVEC(atpic_intr ## irq ## _pti), (irq) % 8 }
112121985Sjhb
113121985Sjhbstruct atpic {
114121985Sjhb	struct pic at_pic;
115121985Sjhb	int	at_ioaddr;
116121985Sjhb	int	at_irqbase;
117121985Sjhb	uint8_t	at_intbase;
118121985Sjhb	uint8_t	*at_imen;
119121985Sjhb};
120121985Sjhb
121121985Sjhbstruct atpic_intsrc {
122121985Sjhb	struct intsrc at_intsrc;
123329462Skib	inthand_t *at_intr, *at_intr_pti;
124128929Sjhb	int	at_irq;			/* Relative to PIC base. */
125128929Sjhb	enum intr_trigger at_trigger;
126122897Sjhb	u_long	at_count;
127122897Sjhb	u_long	at_straycount;
128121985Sjhb};
129121985Sjhb
130121985Sjhbstatic void atpic_enable_source(struct intsrc *isrc);
131133017Sscottlstatic void atpic_disable_source(struct intsrc *isrc, int eoi);
132121985Sjhbstatic void atpic_eoi_master(struct intsrc *isrc);
133121985Sjhbstatic void atpic_eoi_slave(struct intsrc *isrc);
134121985Sjhbstatic void atpic_enable_intr(struct intsrc *isrc);
135169391Sjhbstatic void atpic_disable_intr(struct intsrc *isrc);
136121985Sjhbstatic int atpic_vector(struct intsrc *isrc);
137255726Sgibbsstatic void atpic_resume(struct pic *pic, bool suspend_cancelled);
138121985Sjhbstatic int atpic_source_pending(struct intsrc *isrc);
139128931Sjhbstatic int atpic_config_intr(struct intsrc *isrc, enum intr_trigger trig,
140128931Sjhb    enum intr_polarity pol);
141195249Sjhbstatic int atpic_assign_cpu(struct intsrc *isrc, u_int apic_id);
142121985Sjhbstatic void i8259_init(struct atpic *pic, int slave);
143121985Sjhb
144121985Sjhbstatic struct atpic atpics[] = {
145121985Sjhb	ATPIC(IO_ICU1, 0, atpic_eoi_master, (uint8_t *)&imen),
146121985Sjhb	ATPIC(IO_ICU2, 8, atpic_eoi_slave, ((uint8_t *)&imen) + 1)
147121985Sjhb};
148121985Sjhb
149121985Sjhbstatic struct atpic_intsrc atintrs[] = {
150121985Sjhb	INTSRC(0),
151121985Sjhb	INTSRC(1),
152121985Sjhb	INTSRC(2),
153121985Sjhb	INTSRC(3),
154121985Sjhb	INTSRC(4),
155121985Sjhb	INTSRC(5),
156121985Sjhb	INTSRC(6),
157121985Sjhb	INTSRC(7),
158121985Sjhb	INTSRC(8),
159121985Sjhb	INTSRC(9),
160121985Sjhb	INTSRC(10),
161121985Sjhb	INTSRC(11),
162121985Sjhb	INTSRC(12),
163121985Sjhb	INTSRC(13),
164121985Sjhb	INTSRC(14),
165121985Sjhb	INTSRC(15),
166121985Sjhb};
167121985Sjhb
168298308SpfgCTASSERT(nitems(atintrs) == NUM_ISA_IRQS);
169128875Sjhb
170133017Sscottlstatic __inline void
171133017Sscottl_atpic_eoi_master(struct intsrc *isrc)
172133017Sscottl{
173133017Sscottl
174133017Sscottl	KASSERT(isrc->is_pic == &atpics[MASTER].at_pic,
175133017Sscottl	    ("%s: mismatched pic", __func__));
176133017Sscottl#ifndef AUTO_EOI_1
177133017Sscottl	outb(atpics[MASTER].at_ioaddr, OCW2_EOI);
178133017Sscottl#endif
179133017Sscottl}
180133017Sscottl
181133017Sscottl/*
182133017Sscottl * The data sheet says no auto-EOI on slave, but it sometimes works.
183133017Sscottl * So, if AUTO_EOI_2 is enabled, we use it.
184133017Sscottl */
185133017Sscottlstatic __inline void
186133017Sscottl_atpic_eoi_slave(struct intsrc *isrc)
187133017Sscottl{
188133017Sscottl
189133017Sscottl	KASSERT(isrc->is_pic == &atpics[SLAVE].at_pic,
190133017Sscottl	    ("%s: mismatched pic", __func__));
191133017Sscottl#ifndef AUTO_EOI_2
192133017Sscottl	outb(atpics[SLAVE].at_ioaddr, OCW2_EOI);
193133017Sscottl#ifndef AUTO_EOI_1
194133017Sscottl	outb(atpics[MASTER].at_ioaddr, OCW2_EOI);
195133017Sscottl#endif
196133017Sscottl#endif
197133017Sscottl}
198133017Sscottl
199121985Sjhbstatic void
200121985Sjhbatpic_enable_source(struct intsrc *isrc)
201121985Sjhb{
202121985Sjhb	struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc;
203121985Sjhb	struct atpic *ap = (struct atpic *)isrc->is_pic;
204121985Sjhb
205177468Sjhb	spinlock_enter();
206128875Sjhb	if (*ap->at_imen & IMEN_MASK(ai)) {
207128875Sjhb		*ap->at_imen &= ~IMEN_MASK(ai);
208128875Sjhb		outb(ap->at_ioaddr + ICU_IMR_OFFSET, *ap->at_imen);
209128875Sjhb	}
210177468Sjhb	spinlock_exit();
211121985Sjhb}
212121985Sjhb
213121985Sjhbstatic void
214133017Sscottlatpic_disable_source(struct intsrc *isrc, int eoi)
215121985Sjhb{
216121985Sjhb	struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc;
217121985Sjhb	struct atpic *ap = (struct atpic *)isrc->is_pic;
218121985Sjhb
219177468Sjhb	spinlock_enter();
220133017Sscottl	if (ai->at_trigger != INTR_TRIGGER_EDGE) {
221133017Sscottl		*ap->at_imen |= IMEN_MASK(ai);
222133017Sscottl		outb(ap->at_ioaddr + ICU_IMR_OFFSET, *ap->at_imen);
223133017Sscottl	}
224133017Sscottl
225133017Sscottl	/*
226133017Sscottl	 * Take care to call these functions directly instead of through
227133017Sscottl	 * a function pointer.  All of the referenced variables should
228133017Sscottl	 * still be hot in the cache.
229133017Sscottl	 */
230133017Sscottl	if (eoi == PIC_EOI) {
231133017Sscottl		if (isrc->is_pic == &atpics[MASTER].at_pic)
232133017Sscottl			_atpic_eoi_master(isrc);
233133017Sscottl		else
234133017Sscottl			_atpic_eoi_slave(isrc);
235133017Sscottl	}
236133017Sscottl
237177468Sjhb	spinlock_exit();
238121985Sjhb}
239121985Sjhb
240121985Sjhbstatic void
241121985Sjhbatpic_eoi_master(struct intsrc *isrc)
242121985Sjhb{
243121985Sjhb#ifndef AUTO_EOI_1
244177468Sjhb	spinlock_enter();
245133017Sscottl	_atpic_eoi_master(isrc);
246177468Sjhb	spinlock_exit();
247121985Sjhb#endif
248121985Sjhb}
249121985Sjhb
250121985Sjhbstatic void
251121985Sjhbatpic_eoi_slave(struct intsrc *isrc)
252121985Sjhb{
253121985Sjhb#ifndef AUTO_EOI_2
254177468Sjhb	spinlock_enter();
255133017Sscottl	_atpic_eoi_slave(isrc);
256177468Sjhb	spinlock_exit();
257121985Sjhb#endif
258121985Sjhb}
259121985Sjhb
260121985Sjhbstatic void
261121985Sjhbatpic_enable_intr(struct intsrc *isrc)
262121985Sjhb{
263121985Sjhb}
264121985Sjhb
265169391Sjhbstatic void
266169391Sjhbatpic_disable_intr(struct intsrc *isrc)
267169391Sjhb{
268169391Sjhb}
269169391Sjhb
270169391Sjhb
271121985Sjhbstatic int
272121985Sjhbatpic_vector(struct intsrc *isrc)
273121985Sjhb{
274121985Sjhb	struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc;
275121985Sjhb	struct atpic *ap = (struct atpic *)isrc->is_pic;
276121985Sjhb
277121985Sjhb	return (IRQ(ap, ai));
278121985Sjhb}
279121985Sjhb
280121985Sjhbstatic int
281121985Sjhbatpic_source_pending(struct intsrc *isrc)
282121985Sjhb{
283121985Sjhb	struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc;
284121985Sjhb	struct atpic *ap = (struct atpic *)isrc->is_pic;
285121985Sjhb
286128875Sjhb	return (inb(ap->at_ioaddr) & IMEN_MASK(ai));
287121985Sjhb}
288121985Sjhb
289121985Sjhbstatic void
290255726Sgibbsatpic_resume(struct pic *pic, bool suspend_cancelled)
291121985Sjhb{
292163219Sjhb	struct atpic *ap = (struct atpic *)pic;
293121985Sjhb
294163219Sjhb	i8259_init(ap, ap == &atpics[SLAVE]);
295129009Snyan#ifndef PC98
296163219Sjhb	if (ap == &atpics[SLAVE] && elcr_found)
297163219Sjhb		elcr_resume();
298129009Snyan#endif
299121985Sjhb}
300121985Sjhb
301128931Sjhbstatic int
302128931Sjhbatpic_config_intr(struct intsrc *isrc, enum intr_trigger trig,
303128931Sjhb    enum intr_polarity pol)
304128931Sjhb{
305128931Sjhb	struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc;
306128931Sjhb	u_int vector;
307128931Sjhb
308128931Sjhb	/* Map conforming values to edge/hi and sanity check the values. */
309128931Sjhb	if (trig == INTR_TRIGGER_CONFORM)
310128931Sjhb		trig = INTR_TRIGGER_EDGE;
311128931Sjhb	if (pol == INTR_POLARITY_CONFORM)
312128931Sjhb		pol = INTR_POLARITY_HIGH;
313128931Sjhb	vector = atpic_vector(isrc);
314128931Sjhb	if ((trig == INTR_TRIGGER_EDGE && pol == INTR_POLARITY_LOW) ||
315128931Sjhb	    (trig == INTR_TRIGGER_LEVEL && pol == INTR_POLARITY_HIGH)) {
316128931Sjhb		printf(
317128931Sjhb		"atpic: Mismatched config for IRQ%u: trigger %s, polarity %s\n",
318128931Sjhb		    vector, trig == INTR_TRIGGER_EDGE ? "edge" : "level",
319128931Sjhb		    pol == INTR_POLARITY_HIGH ? "high" : "low");
320128931Sjhb		return (EINVAL);
321128931Sjhb	}
322128931Sjhb
323128931Sjhb	/* If there is no change, just return. */
324128931Sjhb	if (ai->at_trigger == trig)
325128931Sjhb		return (0);
326128931Sjhb
327129009Snyan#ifdef PC98
328129009Snyan	if ((vector == 0 || vector == 1 || vector == 7 || vector == 8) &&
329129009Snyan	    trig == INTR_TRIGGER_LEVEL) {
330129009Snyan		if (bootverbose)
331129009Snyan			printf(
332129009Snyan		"atpic: Ignoring invalid level/low configuration for IRQ%u\n",
333129009Snyan			    vector);
334129009Snyan		return (EINVAL);
335129009Snyan	}
336129009Snyan	return (ENXIO);
337129009Snyan#else
338128931Sjhb	/*
339128931Sjhb	 * Certain IRQs can never be level/lo, so don't try to set them
340128931Sjhb	 * that way if asked.  At least some ELCR registers ignore setting
341128931Sjhb	 * these bits as well.
342128931Sjhb	 */
343128931Sjhb	if ((vector == 0 || vector == 1 || vector == 2 || vector == 13) &&
344128931Sjhb	    trig == INTR_TRIGGER_LEVEL) {
345128931Sjhb		if (bootverbose)
346128931Sjhb			printf(
347128931Sjhb		"atpic: Ignoring invalid level/low configuration for IRQ%u\n",
348128931Sjhb			    vector);
349128931Sjhb		return (EINVAL);
350128931Sjhb	}
351140451Sjhb	if (!elcr_found) {
352128931Sjhb		if (bootverbose)
353128931Sjhb			printf("atpic: No ELCR to configure IRQ%u as %s\n",
354128931Sjhb			    vector, trig == INTR_TRIGGER_EDGE ? "edge/high" :
355128931Sjhb			    "level/low");
356128931Sjhb		return (ENXIO);
357128931Sjhb	}
358128931Sjhb	if (bootverbose)
359128931Sjhb		printf("atpic: Programming IRQ%u as %s\n", vector,
360128931Sjhb		    trig == INTR_TRIGGER_EDGE ? "edge/high" : "level/low");
361177468Sjhb	spinlock_enter();
362128931Sjhb	elcr_write_trigger(atpic_vector(isrc), trig);
363128931Sjhb	ai->at_trigger = trig;
364177468Sjhb	spinlock_exit();
365128931Sjhb	return (0);
366129009Snyan#endif /* PC98 */
367128931Sjhb}
368128931Sjhb
369195249Sjhbstatic int
370156124Sjhbatpic_assign_cpu(struct intsrc *isrc, u_int apic_id)
371156124Sjhb{
372156124Sjhb
373156124Sjhb	/*
374156124Sjhb	 * 8259A's are only used in UP in which case all interrupts always
375156124Sjhb	 * go to the sole CPU and this function shouldn't even be called.
376156124Sjhb	 */
377156124Sjhb	panic("%s: bad cookie", __func__);
378156124Sjhb}
379156124Sjhb
380156124Sjhbstatic void
381121985Sjhbi8259_init(struct atpic *pic, int slave)
382121985Sjhb{
383121985Sjhb	int imr_addr;
384121985Sjhb
385121985Sjhb	/* Reset the PIC and program with next four bytes. */
386177468Sjhb	spinlock_enter();
387121985Sjhb#ifdef DEV_MCA
388122692Sjhb	/* MCA uses level triggered interrupts. */
389121985Sjhb	if (MCA_system)
390122692Sjhb		outb(pic->at_ioaddr, ICW1_RESET | ICW1_IC4 | ICW1_LTIM);
391121985Sjhb	else
392121985Sjhb#endif
393122692Sjhb		outb(pic->at_ioaddr, ICW1_RESET | ICW1_IC4);
394121985Sjhb	imr_addr = pic->at_ioaddr + ICU_IMR_OFFSET;
395121985Sjhb
396121985Sjhb	/* Start vector. */
397121985Sjhb	outb(imr_addr, pic->at_intbase);
398121985Sjhb
399121985Sjhb	/*
400121985Sjhb	 * Setup slave links.  For the master pic, indicate what line
401121985Sjhb	 * the slave is configured on.  For the slave indicate
402121985Sjhb	 * which line on the master we are connected to.
403121985Sjhb	 */
404121985Sjhb	if (slave)
405129131Sjhb		outb(imr_addr, ICU_SLAVEID);
406121985Sjhb	else
407129131Sjhb		outb(imr_addr, IRQ_MASK(ICU_SLAVEID));
408121985Sjhb
409121985Sjhb	/* Set mode. */
410121985Sjhb	if (slave)
411121985Sjhb		outb(imr_addr, SLAVE_MODE);
412121985Sjhb	else
413121985Sjhb		outb(imr_addr, MASTER_MODE);
414121985Sjhb
415121985Sjhb	/* Set interrupt enable mask. */
416121985Sjhb	outb(imr_addr, *pic->at_imen);
417121985Sjhb
418121985Sjhb	/* Reset is finished, default to IRR on read. */
419122692Sjhb	outb(pic->at_ioaddr, OCW3_SEL | OCW3_RR);
420121985Sjhb
421121985Sjhb#ifndef PC98
422122692Sjhb	/* OCW2_L1 sets priority order to 3-7, 0-2 (com2 first). */
423121985Sjhb	if (!slave)
424122692Sjhb		outb(pic->at_ioaddr, OCW2_R | OCW2_SL | OCW2_L1);
425121985Sjhb#endif
426177468Sjhb	spinlock_exit();
427121985Sjhb}
428121985Sjhb
429121985Sjhbvoid
430121985Sjhbatpic_startup(void)
431121985Sjhb{
432122897Sjhb	struct atpic_intsrc *ai;
433122897Sjhb	int i;
434121985Sjhb
435121985Sjhb	/* Start off with all interrupts disabled. */
436121985Sjhb	imen = 0xffff;
437121985Sjhb	i8259_init(&atpics[MASTER], 0);
438121985Sjhb	i8259_init(&atpics[SLAVE], 1);
439121985Sjhb	atpic_enable_source((struct intsrc *)&atintrs[ICU_SLAVEID]);
440122897Sjhb
441122897Sjhb	/* Install low-level interrupt handlers for all of our IRQs. */
442128875Sjhb	for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) {
443122897Sjhb		if (i == ICU_SLAVEID)
444122897Sjhb			continue;
445122897Sjhb		ai->at_intsrc.is_count = &ai->at_count;
446122897Sjhb		ai->at_intsrc.is_straycount = &ai->at_straycount;
447122897Sjhb		setidt(((struct atpic *)ai->at_intsrc.is_pic)->at_intbase +
448329462Skib		    ai->at_irq, pti ? ai->at_intr_pti : ai->at_intr, SDT_ATPIC,
449329462Skib		    SEL_KPL, GSEL_ATPIC);
450122897Sjhb	}
451128929Sjhb
452128929Sjhb#ifdef DEV_MCA
453128929Sjhb	/* For MCA systems, all interrupts are level triggered. */
454128929Sjhb	if (MCA_system)
455128929Sjhb		for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++)
456128929Sjhb			ai->at_trigger = INTR_TRIGGER_LEVEL;
457128929Sjhb	else
458128929Sjhb#endif
459128929Sjhb
460129009Snyan#ifdef PC98
461129009Snyan	for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++)
462129009Snyan		switch (i) {
463129009Snyan		case 0:
464129009Snyan		case 1:
465129009Snyan		case 7:
466129009Snyan		case 8:
467129009Snyan			ai->at_trigger = INTR_TRIGGER_EDGE;
468129009Snyan			break;
469129009Snyan		default:
470129009Snyan			ai->at_trigger = INTR_TRIGGER_LEVEL;
471129009Snyan			break;
472129009Snyan		}
473129009Snyan#else
474128929Sjhb	/*
475128929Sjhb	 * Look for an ELCR.  If we find one, update the trigger modes.
476128929Sjhb	 * If we don't find one, assume that IRQs 0, 1, 2, and 13 are
477128929Sjhb	 * edge triggered and that everything else is level triggered.
478128929Sjhb	 * We only use the trigger information to reprogram the ELCR if
479128929Sjhb	 * we have one and as an optimization to avoid masking edge
480128929Sjhb	 * triggered interrupts.  For the case that we don't have an ELCR,
481128929Sjhb	 * it doesn't hurt to mask an edge triggered interrupt, so we
482129095Sjhb	 * assume level trigger for any interrupt that we aren't sure is
483129095Sjhb	 * edge triggered.
484128929Sjhb	 */
485140451Sjhb	if (elcr_found) {
486128929Sjhb		for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++)
487128929Sjhb			ai->at_trigger = elcr_read_trigger(i);
488128929Sjhb	} else {
489128929Sjhb		for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++)
490128929Sjhb			switch (i) {
491128929Sjhb			case 0:
492128929Sjhb			case 1:
493128929Sjhb			case 2:
494128929Sjhb			case 8:
495128929Sjhb			case 13:
496128929Sjhb				ai->at_trigger = INTR_TRIGGER_EDGE;
497128929Sjhb				break;
498128929Sjhb			default:
499128929Sjhb				ai->at_trigger = INTR_TRIGGER_LEVEL;
500128929Sjhb				break;
501128929Sjhb			}
502128929Sjhb	}
503129009Snyan#endif /* PC98 */
504121985Sjhb}
505121985Sjhb
506121985Sjhbstatic void
507121985Sjhbatpic_init(void *dummy __unused)
508121985Sjhb{
509128875Sjhb	struct atpic_intsrc *ai;
510121985Sjhb	int i;
511121985Sjhb
512153136Sjhb	/*
513163219Sjhb	 * Register our PICs, even if we aren't going to use any of their
514163219Sjhb	 * pins so that they are suspended and resumed.
515163219Sjhb	 */
516163219Sjhb	if (intr_register_pic(&atpics[0].at_pic) != 0 ||
517163219Sjhb	    intr_register_pic(&atpics[1].at_pic) != 0)
518163219Sjhb		panic("Unable to register ATPICs");
519163219Sjhb
520163219Sjhb	/*
521153136Sjhb	 * If any of the ISA IRQs have an interrupt source already, then
522153136Sjhb	 * assume that the APICs are being used and don't register any
523153136Sjhb	 * of our interrupt sources.  This makes sure we don't accidentally
524153136Sjhb	 * use mixed mode.  The "accidental" use could otherwise occur on
525153136Sjhb	 * machines that route the ACPI SCI interrupt to a different ISA
526153136Sjhb	 * IRQ (at least one machines routes it to IRQ 13) thus disabling
527153136Sjhb	 * that APIC ISA routing and allowing the ATPIC source for that IRQ
528153136Sjhb	 * to leak through.  We used to depend on this feature for routing
529153136Sjhb	 * IRQ0 via mixed mode, but now we don't use mixed mode at all.
530153136Sjhb	 */
531153136Sjhb	for (i = 0; i < NUM_ISA_IRQS; i++)
532153136Sjhb		if (intr_lookup_source(i) != NULL)
533153136Sjhb			return;
534153136Sjhb
535121985Sjhb	/* Loop through all interrupt sources and add them. */
536128875Sjhb	for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) {
537121985Sjhb		if (i == ICU_SLAVEID)
538121985Sjhb			continue;
539128875Sjhb		intr_register_source(&ai->at_intsrc);
540121985Sjhb	}
541121985Sjhb}
542269675SroygerSYSINIT(atpic_init, SI_SUB_INTR, SI_ORDER_FOURTH, atpic_init, NULL);
543121985Sjhb
544121985Sjhbvoid
545165302Skmacyatpic_handle_intr(u_int vector, struct trapframe *frame)
546121985Sjhb{
547121985Sjhb	struct intsrc *isrc;
548121985Sjhb
549153242Sjhb	KASSERT(vector < NUM_ISA_IRQS, ("unknown int %u\n", vector));
550153146Sjhb	isrc = &atintrs[vector].at_intsrc;
551122898Sjhb
552122898Sjhb	/*
553151658Sjhb	 * If we don't have an event, see if this is a spurious
554122898Sjhb	 * interrupt.
555122898Sjhb	 */
556153146Sjhb	if (isrc->is_event == NULL && (vector == 7 || vector == 15)) {
557122898Sjhb		int port, isr;
558122898Sjhb
559122898Sjhb		/*
560122898Sjhb		 * Read the ISR register to see if IRQ 7/15 is really
561122898Sjhb		 * pending.  Reset read register back to IRR when done.
562122898Sjhb		 */
563122898Sjhb		port = ((struct atpic *)isrc->is_pic)->at_ioaddr;
564177468Sjhb		spinlock_enter();
565122898Sjhb		outb(port, OCW3_SEL | OCW3_RR | OCW3_RIS);
566122898Sjhb		isr = inb(port);
567122898Sjhb		outb(port, OCW3_SEL | OCW3_RR);
568177468Sjhb		spinlock_exit();
569129131Sjhb		if ((isr & IRQ_MASK(7)) == 0)
570122898Sjhb			return;
571122898Sjhb	}
572165302Skmacy	intr_execute_handlers(isrc, frame);
573121985Sjhb}
574121985Sjhb
575121985Sjhb#ifdef DEV_ISA
576121985Sjhb/*
577121985Sjhb * Bus attachment for the ISA PIC.
578121985Sjhb */
579121985Sjhbstatic struct isa_pnp_id atpic_ids[] = {
580121985Sjhb	{ 0x0000d041 /* PNP0000 */, "AT interrupt controller" },
581121985Sjhb	{ 0 }
582121985Sjhb};
583121985Sjhb
584121985Sjhbstatic int
585121985Sjhbatpic_probe(device_t dev)
586121985Sjhb{
587121985Sjhb	int result;
588121985Sjhb
589121985Sjhb	result = ISA_PNP_PROBE(device_get_parent(dev), dev, atpic_ids);
590121985Sjhb	if (result <= 0)
591121985Sjhb		device_quiet(dev);
592121985Sjhb	return (result);
593121985Sjhb}
594121985Sjhb
595121985Sjhb/*
596121985Sjhb * We might be granted IRQ 2, as this is typically consumed by chaining
597121985Sjhb * between the two PIC components.  If we're using the APIC, however,
598121985Sjhb * this may not be the case, and as such we should free the resource.
599121985Sjhb * (XXX untested)
600121985Sjhb *
601121985Sjhb * The generic ISA attachment code will handle allocating any other resources
602121985Sjhb * that we don't explicitly claim here.
603121985Sjhb */
604121985Sjhbstatic int
605121985Sjhbatpic_attach(device_t dev)
606121985Sjhb{
607121985Sjhb	struct resource *res;
608121985Sjhb	int rid;
609121985Sjhb
610121985Sjhb	/* Try to allocate our IRQ and then free it. */
611121985Sjhb	rid = 0;
612127135Snjl	res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 0);
613121985Sjhb	if (res != NULL)
614121985Sjhb		bus_release_resource(dev, SYS_RES_IRQ, rid, res);
615121985Sjhb	return (0);
616121985Sjhb}
617121985Sjhb
618121985Sjhbstatic device_method_t atpic_methods[] = {
619121985Sjhb	/* Device interface */
620121985Sjhb	DEVMETHOD(device_probe,		atpic_probe),
621121985Sjhb	DEVMETHOD(device_attach,	atpic_attach),
622121985Sjhb	DEVMETHOD(device_detach,	bus_generic_detach),
623121985Sjhb	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
624121985Sjhb	DEVMETHOD(device_suspend,	bus_generic_suspend),
625121985Sjhb	DEVMETHOD(device_resume,	bus_generic_resume),
626121985Sjhb	{ 0, 0 }
627121985Sjhb};
628121985Sjhb
629121985Sjhbstatic driver_t atpic_driver = {
630121985Sjhb	"atpic",
631121985Sjhb	atpic_methods,
632121985Sjhb	1,		/* no softc */
633121985Sjhb};
634121985Sjhb
635121985Sjhbstatic devclass_t atpic_devclass;
636121985Sjhb
637121985SjhbDRIVER_MODULE(atpic, isa, atpic_driver, atpic_devclass, 0, 0);
638122051Snyan#ifndef PC98
639121985SjhbDRIVER_MODULE(atpic, acpi, atpic_driver, atpic_devclass, 0, 0);
640122051Snyan#endif
641121985Sjhb
642121985Sjhb/*
643121985Sjhb * Return a bitmap of the current interrupt requests.  This is 8259-specific
644121985Sjhb * and is only suitable for use at probe time.
645121985Sjhb */
646121985Sjhbintrmask_t
647121985Sjhbisa_irq_pending(void)
648121985Sjhb{
649121985Sjhb	u_char irr1;
650121985Sjhb	u_char irr2;
651121985Sjhb
652121985Sjhb	irr1 = inb(IO_ICU1);
653121985Sjhb	irr2 = inb(IO_ICU2);
654121985Sjhb	return ((irr2 << 8) | irr1);
655121985Sjhb}
656121985Sjhb#endif /* DEV_ISA */
657