atpic.c revision 156124
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 * 3. Neither the name of the author nor the names of any co-contributors
14121985Sjhb *    may be used to endorse or promote products derived from this software
15121985Sjhb *    without specific prior written permission.
16121985Sjhb *
17121985Sjhb * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18121985Sjhb * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19121985Sjhb * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20121985Sjhb * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21121985Sjhb * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22121985Sjhb * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23121985Sjhb * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24121985Sjhb * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25121985Sjhb * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26121985Sjhb * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27121985Sjhb * SUCH DAMAGE.
28121985Sjhb */
29121985Sjhb
30121985Sjhb/*
31121985Sjhb * PIC driver for the 8259A Master and Slave PICs in PC/AT machines.
32121985Sjhb */
33121985Sjhb
34121985Sjhb#include <sys/cdefs.h>
35121985Sjhb__FBSDID("$FreeBSD: head/sys/i386/isa/atpic.c 156124 2006-02-28 22:24:55Z jhb $");
36121985Sjhb
37121985Sjhb#include "opt_auto_eoi.h"
38121985Sjhb#include "opt_isa.h"
39121985Sjhb
40121985Sjhb#include <sys/param.h>
41121985Sjhb#include <sys/systm.h>
42121985Sjhb#include <sys/bus.h>
43121985Sjhb#include <sys/interrupt.h>
44121985Sjhb#include <sys/kernel.h>
45121985Sjhb#include <sys/lock.h>
46129876Sphk#include <sys/module.h>
47121985Sjhb#include <sys/mutex.h>
48121985Sjhb
49121985Sjhb#include <machine/cpufunc.h>
50121985Sjhb#include <machine/frame.h>
51121985Sjhb#include <machine/intr_machdep.h>
52121985Sjhb#include <machine/md_var.h>
53121985Sjhb#include <machine/resource.h>
54121985Sjhb#include <machine/segments.h>
55121985Sjhb
56124188Sjhb#include <dev/ic/i8259.h>
57121985Sjhb#include <i386/isa/icu.h>
58122051Snyan#ifdef PC98
59146049Snyan#include <pc98/cbus/cbus.h>
60122051Snyan#else
61121985Sjhb#include <i386/isa/isa.h>
62122051Snyan#endif
63121985Sjhb#include <isa/isavar.h>
64121985Sjhb
65121985Sjhb#define	MASTER	0
66121985Sjhb#define	SLAVE	1
67121985Sjhb
68124188Sjhb/*
69129131Sjhb * PC-98 machines wire the slave 8259A to pin 7 on the master PIC, and
70129131Sjhb * PC-AT machines wire the slave PIC to pin 2 on the master PIC.
71129131Sjhb */
72129131Sjhb#ifdef PC98
73129131Sjhb#define	ICU_SLAVEID	7
74129131Sjhb#else
75129131Sjhb#define	ICU_SLAVEID	2
76129131Sjhb#endif
77129131Sjhb
78129131Sjhb/*
79124188Sjhb * Determine the base master and slave modes not including auto EOI support.
80124188Sjhb * All machines that FreeBSD supports use 8086 mode.
81124188Sjhb */
82121985Sjhb#ifdef PC98
83124188Sjhb/*
84124188Sjhb * PC-98 machines do not support auto EOI on the second PIC.  Also, it
85124188Sjhb * seems that PC-98 machine PICs use buffered mode, and the master PIC
86124188Sjhb * uses special fully nested mode.
87124188Sjhb */
88124188Sjhb#define	BASE_MASTER_MODE	(ICW4_SFNM | ICW4_BUF | ICW4_MS | ICW4_8086)
89124188Sjhb#define	BASE_SLAVE_MODE		(ICW4_BUF | ICW4_8086)
90121985Sjhb#else
91124188Sjhb#define	BASE_MASTER_MODE	ICW4_8086
92124188Sjhb#define	BASE_SLAVE_MODE		ICW4_8086
93121985Sjhb#endif
94124188Sjhb
95124188Sjhb/* Enable automatic EOI if requested. */
96121985Sjhb#ifdef AUTO_EOI_1
97124188Sjhb#define	MASTER_MODE		(BASE_MASTER_MODE | ICW4_AEOI)
98121985Sjhb#else
99124188Sjhb#define	MASTER_MODE		BASE_MASTER_MODE
100121985Sjhb#endif
101121985Sjhb#ifdef AUTO_EOI_2
102124188Sjhb#define	SLAVE_MODE		(BASE_SLAVE_MODE | ICW4_AEOI)
103121985Sjhb#else
104124188Sjhb#define	SLAVE_MODE		BASE_SLAVE_MODE
105121985Sjhb#endif
106121985Sjhb
107129131Sjhb#define	IRQ_MASK(irq)		(1 << (irq))
108129131Sjhb#define	IMEN_MASK(ai)		(IRQ_MASK((ai)->at_irq))
109128875Sjhb
110128875Sjhb#define	NUM_ISA_IRQS		16
111128875Sjhb
112121985Sjhbstatic void	atpic_init(void *dummy);
113121985Sjhb
114121985Sjhbunsigned int imen;	/* XXX */
115121985Sjhb
116121985Sjhbinthand_t
117121985Sjhb	IDTVEC(atpic_intr0), IDTVEC(atpic_intr1), IDTVEC(atpic_intr2),
118121985Sjhb	IDTVEC(atpic_intr3), IDTVEC(atpic_intr4), IDTVEC(atpic_intr5),
119121985Sjhb	IDTVEC(atpic_intr6), IDTVEC(atpic_intr7), IDTVEC(atpic_intr8),
120121985Sjhb	IDTVEC(atpic_intr9), IDTVEC(atpic_intr10), IDTVEC(atpic_intr11),
121121985Sjhb	IDTVEC(atpic_intr12), IDTVEC(atpic_intr13), IDTVEC(atpic_intr14),
122121985Sjhb	IDTVEC(atpic_intr15);
123121985Sjhb
124121985Sjhb#define	IRQ(ap, ai)	((ap)->at_irqbase + (ai)->at_irq)
125121985Sjhb
126128929Sjhb#define	ATPIC(io, base, eoi, imenptr)					\
127121985Sjhb     	{ { atpic_enable_source, atpic_disable_source, (eoi),		\
128121985Sjhb	    atpic_enable_intr, atpic_vector, atpic_source_pending, NULL, \
129156124Sjhb	    atpic_resume, atpic_config_intr, atpic_assign_cpu }, (io),  \
130156124Sjhb	    (base), IDT_IO_INTS + (base), (imenptr) }
131121985Sjhb
132121985Sjhb#define	INTSRC(irq)							\
133128929Sjhb	{ { &atpics[(irq) / 8].at_pic }, IDTVEC(atpic_intr ## irq ),	\
134128929Sjhb	    (irq) % 8 }
135121985Sjhb
136121985Sjhbstruct atpic {
137121985Sjhb	struct pic at_pic;
138121985Sjhb	int	at_ioaddr;
139121985Sjhb	int	at_irqbase;
140121985Sjhb	uint8_t	at_intbase;
141121985Sjhb	uint8_t	*at_imen;
142121985Sjhb};
143121985Sjhb
144121985Sjhbstruct atpic_intsrc {
145121985Sjhb	struct intsrc at_intsrc;
146121985Sjhb	inthand_t *at_intr;
147128929Sjhb	int	at_irq;			/* Relative to PIC base. */
148128929Sjhb	enum intr_trigger at_trigger;
149122897Sjhb	u_long	at_count;
150122897Sjhb	u_long	at_straycount;
151121985Sjhb};
152121985Sjhb
153121985Sjhbstatic void atpic_enable_source(struct intsrc *isrc);
154133017Sscottlstatic void atpic_disable_source(struct intsrc *isrc, int eoi);
155121985Sjhbstatic void atpic_eoi_master(struct intsrc *isrc);
156121985Sjhbstatic void atpic_eoi_slave(struct intsrc *isrc);
157121985Sjhbstatic void atpic_enable_intr(struct intsrc *isrc);
158121985Sjhbstatic int atpic_vector(struct intsrc *isrc);
159121985Sjhbstatic void atpic_resume(struct intsrc *isrc);
160121985Sjhbstatic int atpic_source_pending(struct intsrc *isrc);
161128931Sjhbstatic int atpic_config_intr(struct intsrc *isrc, enum intr_trigger trig,
162128931Sjhb    enum intr_polarity pol);
163156124Sjhbstatic void atpic_assign_cpu(struct intsrc *isrc, u_int apic_id);
164121985Sjhbstatic void i8259_init(struct atpic *pic, int slave);
165121985Sjhb
166121985Sjhbstatic struct atpic atpics[] = {
167121985Sjhb	ATPIC(IO_ICU1, 0, atpic_eoi_master, (uint8_t *)&imen),
168121985Sjhb	ATPIC(IO_ICU2, 8, atpic_eoi_slave, ((uint8_t *)&imen) + 1)
169121985Sjhb};
170121985Sjhb
171121985Sjhbstatic struct atpic_intsrc atintrs[] = {
172121985Sjhb	INTSRC(0),
173121985Sjhb	INTSRC(1),
174121985Sjhb	INTSRC(2),
175121985Sjhb	INTSRC(3),
176121985Sjhb	INTSRC(4),
177121985Sjhb	INTSRC(5),
178121985Sjhb	INTSRC(6),
179121985Sjhb	INTSRC(7),
180121985Sjhb	INTSRC(8),
181121985Sjhb	INTSRC(9),
182121985Sjhb	INTSRC(10),
183121985Sjhb	INTSRC(11),
184121985Sjhb	INTSRC(12),
185121985Sjhb	INTSRC(13),
186121985Sjhb	INTSRC(14),
187121985Sjhb	INTSRC(15),
188121985Sjhb};
189121985Sjhb
190129095SjhbCTASSERT(sizeof(atintrs) / sizeof(atintrs[0]) == NUM_ISA_IRQS);
191128875Sjhb
192133017Sscottlstatic __inline void
193133017Sscottl_atpic_eoi_master(struct intsrc *isrc)
194133017Sscottl{
195133017Sscottl
196133017Sscottl	KASSERT(isrc->is_pic == &atpics[MASTER].at_pic,
197133017Sscottl	    ("%s: mismatched pic", __func__));
198133017Sscottl#ifndef AUTO_EOI_1
199133017Sscottl	outb(atpics[MASTER].at_ioaddr, OCW2_EOI);
200133017Sscottl#endif
201133017Sscottl}
202133017Sscottl
203133017Sscottl/*
204133017Sscottl * The data sheet says no auto-EOI on slave, but it sometimes works.
205133017Sscottl * So, if AUTO_EOI_2 is enabled, we use it.
206133017Sscottl */
207133017Sscottlstatic __inline void
208133017Sscottl_atpic_eoi_slave(struct intsrc *isrc)
209133017Sscottl{
210133017Sscottl
211133017Sscottl	KASSERT(isrc->is_pic == &atpics[SLAVE].at_pic,
212133017Sscottl	    ("%s: mismatched pic", __func__));
213133017Sscottl#ifndef AUTO_EOI_2
214133017Sscottl	outb(atpics[SLAVE].at_ioaddr, OCW2_EOI);
215133017Sscottl#ifndef AUTO_EOI_1
216133017Sscottl	outb(atpics[MASTER].at_ioaddr, OCW2_EOI);
217133017Sscottl#endif
218133017Sscottl#endif
219133017Sscottl}
220133017Sscottl
221121985Sjhbstatic void
222121985Sjhbatpic_enable_source(struct intsrc *isrc)
223121985Sjhb{
224121985Sjhb	struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc;
225121985Sjhb	struct atpic *ap = (struct atpic *)isrc->is_pic;
226121985Sjhb
227121985Sjhb	mtx_lock_spin(&icu_lock);
228128875Sjhb	if (*ap->at_imen & IMEN_MASK(ai)) {
229128875Sjhb		*ap->at_imen &= ~IMEN_MASK(ai);
230128875Sjhb		outb(ap->at_ioaddr + ICU_IMR_OFFSET, *ap->at_imen);
231128875Sjhb	}
232121985Sjhb	mtx_unlock_spin(&icu_lock);
233121985Sjhb}
234121985Sjhb
235121985Sjhbstatic void
236133017Sscottlatpic_disable_source(struct intsrc *isrc, int eoi)
237121985Sjhb{
238121985Sjhb	struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc;
239121985Sjhb	struct atpic *ap = (struct atpic *)isrc->is_pic;
240121985Sjhb
241121985Sjhb	mtx_lock_spin(&icu_lock);
242133017Sscottl	if (ai->at_trigger != INTR_TRIGGER_EDGE) {
243133017Sscottl		*ap->at_imen |= IMEN_MASK(ai);
244133017Sscottl		outb(ap->at_ioaddr + ICU_IMR_OFFSET, *ap->at_imen);
245133017Sscottl	}
246133017Sscottl
247133017Sscottl	/*
248133017Sscottl	 * Take care to call these functions directly instead of through
249133017Sscottl	 * a function pointer.  All of the referenced variables should
250133017Sscottl	 * still be hot in the cache.
251133017Sscottl	 */
252133017Sscottl	if (eoi == PIC_EOI) {
253133017Sscottl		if (isrc->is_pic == &atpics[MASTER].at_pic)
254133017Sscottl			_atpic_eoi_master(isrc);
255133017Sscottl		else
256133017Sscottl			_atpic_eoi_slave(isrc);
257133017Sscottl	}
258133017Sscottl
259121985Sjhb	mtx_unlock_spin(&icu_lock);
260121985Sjhb}
261121985Sjhb
262121985Sjhbstatic void
263121985Sjhbatpic_eoi_master(struct intsrc *isrc)
264121985Sjhb{
265121985Sjhb#ifndef AUTO_EOI_1
266121985Sjhb	mtx_lock_spin(&icu_lock);
267133017Sscottl	_atpic_eoi_master(isrc);
268121985Sjhb	mtx_unlock_spin(&icu_lock);
269121985Sjhb#endif
270121985Sjhb}
271121985Sjhb
272121985Sjhbstatic void
273121985Sjhbatpic_eoi_slave(struct intsrc *isrc)
274121985Sjhb{
275121985Sjhb#ifndef AUTO_EOI_2
276121985Sjhb	mtx_lock_spin(&icu_lock);
277133017Sscottl	_atpic_eoi_slave(isrc);
278121985Sjhb	mtx_unlock_spin(&icu_lock);
279121985Sjhb#endif
280121985Sjhb}
281121985Sjhb
282121985Sjhbstatic void
283121985Sjhbatpic_enable_intr(struct intsrc *isrc)
284121985Sjhb{
285121985Sjhb}
286121985Sjhb
287121985Sjhbstatic int
288121985Sjhbatpic_vector(struct intsrc *isrc)
289121985Sjhb{
290121985Sjhb	struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc;
291121985Sjhb	struct atpic *ap = (struct atpic *)isrc->is_pic;
292121985Sjhb
293121985Sjhb	return (IRQ(ap, ai));
294121985Sjhb}
295121985Sjhb
296121985Sjhbstatic int
297121985Sjhbatpic_source_pending(struct intsrc *isrc)
298121985Sjhb{
299121985Sjhb	struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc;
300121985Sjhb	struct atpic *ap = (struct atpic *)isrc->is_pic;
301121985Sjhb
302128875Sjhb	return (inb(ap->at_ioaddr) & IMEN_MASK(ai));
303121985Sjhb}
304121985Sjhb
305121985Sjhbstatic void
306121985Sjhbatpic_resume(struct intsrc *isrc)
307121985Sjhb{
308121985Sjhb	struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc;
309121985Sjhb	struct atpic *ap = (struct atpic *)isrc->is_pic;
310121985Sjhb
311128929Sjhb	if (ai->at_irq == 0) {
312121985Sjhb		i8259_init(ap, ap == &atpics[SLAVE]);
313129009Snyan#ifndef PC98
314140451Sjhb		if (ap == &atpics[SLAVE] && elcr_found)
315128929Sjhb			elcr_resume();
316129009Snyan#endif
317128929Sjhb	}
318121985Sjhb}
319121985Sjhb
320128931Sjhbstatic int
321128931Sjhbatpic_config_intr(struct intsrc *isrc, enum intr_trigger trig,
322128931Sjhb    enum intr_polarity pol)
323128931Sjhb{
324128931Sjhb	struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc;
325128931Sjhb	u_int vector;
326128931Sjhb
327128931Sjhb	/* Map conforming values to edge/hi and sanity check the values. */
328128931Sjhb	if (trig == INTR_TRIGGER_CONFORM)
329128931Sjhb		trig = INTR_TRIGGER_EDGE;
330128931Sjhb	if (pol == INTR_POLARITY_CONFORM)
331128931Sjhb		pol = INTR_POLARITY_HIGH;
332128931Sjhb	vector = atpic_vector(isrc);
333128931Sjhb	if ((trig == INTR_TRIGGER_EDGE && pol == INTR_POLARITY_LOW) ||
334128931Sjhb	    (trig == INTR_TRIGGER_LEVEL && pol == INTR_POLARITY_HIGH)) {
335128931Sjhb		printf(
336128931Sjhb		"atpic: Mismatched config for IRQ%u: trigger %s, polarity %s\n",
337128931Sjhb		    vector, trig == INTR_TRIGGER_EDGE ? "edge" : "level",
338128931Sjhb		    pol == INTR_POLARITY_HIGH ? "high" : "low");
339128931Sjhb		return (EINVAL);
340128931Sjhb	}
341128931Sjhb
342128931Sjhb	/* If there is no change, just return. */
343128931Sjhb	if (ai->at_trigger == trig)
344128931Sjhb		return (0);
345128931Sjhb
346129009Snyan#ifdef PC98
347129009Snyan	if ((vector == 0 || vector == 1 || vector == 7 || vector == 8) &&
348129009Snyan	    trig == INTR_TRIGGER_LEVEL) {
349129009Snyan		if (bootverbose)
350129009Snyan			printf(
351129009Snyan		"atpic: Ignoring invalid level/low configuration for IRQ%u\n",
352129009Snyan			    vector);
353129009Snyan		return (EINVAL);
354129009Snyan	}
355129009Snyan	return (ENXIO);
356129009Snyan#else
357128931Sjhb	/*
358128931Sjhb	 * Certain IRQs can never be level/lo, so don't try to set them
359128931Sjhb	 * that way if asked.  At least some ELCR registers ignore setting
360128931Sjhb	 * these bits as well.
361128931Sjhb	 */
362128931Sjhb	if ((vector == 0 || vector == 1 || vector == 2 || vector == 13) &&
363128931Sjhb	    trig == INTR_TRIGGER_LEVEL) {
364128931Sjhb		if (bootverbose)
365128931Sjhb			printf(
366128931Sjhb		"atpic: Ignoring invalid level/low configuration for IRQ%u\n",
367128931Sjhb			    vector);
368128931Sjhb		return (EINVAL);
369128931Sjhb	}
370140451Sjhb	if (!elcr_found) {
371128931Sjhb		if (bootverbose)
372128931Sjhb			printf("atpic: No ELCR to configure IRQ%u as %s\n",
373128931Sjhb			    vector, trig == INTR_TRIGGER_EDGE ? "edge/high" :
374128931Sjhb			    "level/low");
375128931Sjhb		return (ENXIO);
376128931Sjhb	}
377128931Sjhb	if (bootverbose)
378128931Sjhb		printf("atpic: Programming IRQ%u as %s\n", vector,
379128931Sjhb		    trig == INTR_TRIGGER_EDGE ? "edge/high" : "level/low");
380128931Sjhb	mtx_lock_spin(&icu_lock);
381128931Sjhb	elcr_write_trigger(atpic_vector(isrc), trig);
382128931Sjhb	ai->at_trigger = trig;
383128931Sjhb	mtx_unlock_spin(&icu_lock);
384128931Sjhb	return (0);
385129009Snyan#endif /* PC98 */
386128931Sjhb}
387128931Sjhb
388121985Sjhbstatic void
389156124Sjhbatpic_assign_cpu(struct intsrc *isrc, u_int apic_id)
390156124Sjhb{
391156124Sjhb
392156124Sjhb	/*
393156124Sjhb	 * 8259A's are only used in UP in which case all interrupts always
394156124Sjhb	 * go to the sole CPU and this function shouldn't even be called.
395156124Sjhb	 */
396156124Sjhb	panic("%s: bad cookie", __func__);
397156124Sjhb}
398156124Sjhb
399156124Sjhbstatic void
400121985Sjhbi8259_init(struct atpic *pic, int slave)
401121985Sjhb{
402121985Sjhb	int imr_addr;
403121985Sjhb
404121985Sjhb	/* Reset the PIC and program with next four bytes. */
405121985Sjhb	mtx_lock_spin(&icu_lock);
406121985Sjhb#ifdef DEV_MCA
407122692Sjhb	/* MCA uses level triggered interrupts. */
408121985Sjhb	if (MCA_system)
409122692Sjhb		outb(pic->at_ioaddr, ICW1_RESET | ICW1_IC4 | ICW1_LTIM);
410121985Sjhb	else
411121985Sjhb#endif
412122692Sjhb		outb(pic->at_ioaddr, ICW1_RESET | ICW1_IC4);
413121985Sjhb	imr_addr = pic->at_ioaddr + ICU_IMR_OFFSET;
414121985Sjhb
415121985Sjhb	/* Start vector. */
416121985Sjhb	outb(imr_addr, pic->at_intbase);
417121985Sjhb
418121985Sjhb	/*
419121985Sjhb	 * Setup slave links.  For the master pic, indicate what line
420121985Sjhb	 * the slave is configured on.  For the slave indicate
421121985Sjhb	 * which line on the master we are connected to.
422121985Sjhb	 */
423121985Sjhb	if (slave)
424129131Sjhb		outb(imr_addr, ICU_SLAVEID);
425121985Sjhb	else
426129131Sjhb		outb(imr_addr, IRQ_MASK(ICU_SLAVEID));
427121985Sjhb
428121985Sjhb	/* Set mode. */
429121985Sjhb	if (slave)
430121985Sjhb		outb(imr_addr, SLAVE_MODE);
431121985Sjhb	else
432121985Sjhb		outb(imr_addr, MASTER_MODE);
433121985Sjhb
434121985Sjhb	/* Set interrupt enable mask. */
435121985Sjhb	outb(imr_addr, *pic->at_imen);
436121985Sjhb
437121985Sjhb	/* Reset is finished, default to IRR on read. */
438122692Sjhb	outb(pic->at_ioaddr, OCW3_SEL | OCW3_RR);
439121985Sjhb
440121985Sjhb#ifndef PC98
441122692Sjhb	/* OCW2_L1 sets priority order to 3-7, 0-2 (com2 first). */
442121985Sjhb	if (!slave)
443122692Sjhb		outb(pic->at_ioaddr, OCW2_R | OCW2_SL | OCW2_L1);
444121985Sjhb#endif
445121985Sjhb	mtx_unlock_spin(&icu_lock);
446121985Sjhb}
447121985Sjhb
448121985Sjhbvoid
449121985Sjhbatpic_startup(void)
450121985Sjhb{
451122897Sjhb	struct atpic_intsrc *ai;
452122897Sjhb	int i;
453121985Sjhb
454121985Sjhb	/* Start off with all interrupts disabled. */
455121985Sjhb	imen = 0xffff;
456121985Sjhb	i8259_init(&atpics[MASTER], 0);
457121985Sjhb	i8259_init(&atpics[SLAVE], 1);
458121985Sjhb	atpic_enable_source((struct intsrc *)&atintrs[ICU_SLAVEID]);
459122897Sjhb
460122897Sjhb	/* Install low-level interrupt handlers for all of our IRQs. */
461128875Sjhb	for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) {
462122897Sjhb		if (i == ICU_SLAVEID)
463122897Sjhb			continue;
464122897Sjhb		ai->at_intsrc.is_count = &ai->at_count;
465122897Sjhb		ai->at_intsrc.is_straycount = &ai->at_straycount;
466122897Sjhb		setidt(((struct atpic *)ai->at_intsrc.is_pic)->at_intbase +
467122897Sjhb		    ai->at_irq, ai->at_intr, SDT_SYS386IGT, SEL_KPL,
468122897Sjhb		    GSEL(GCODE_SEL, SEL_KPL));
469122897Sjhb	}
470128929Sjhb
471128929Sjhb#ifdef DEV_MCA
472128929Sjhb	/* For MCA systems, all interrupts are level triggered. */
473128929Sjhb	if (MCA_system)
474128929Sjhb		for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++)
475128929Sjhb			ai->at_trigger = INTR_TRIGGER_LEVEL;
476128929Sjhb	else
477128929Sjhb#endif
478128929Sjhb
479129009Snyan#ifdef PC98
480129009Snyan	for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++)
481129009Snyan		switch (i) {
482129009Snyan		case 0:
483129009Snyan		case 1:
484129009Snyan		case 7:
485129009Snyan		case 8:
486129009Snyan			ai->at_trigger = INTR_TRIGGER_EDGE;
487129009Snyan			break;
488129009Snyan		default:
489129009Snyan			ai->at_trigger = INTR_TRIGGER_LEVEL;
490129009Snyan			break;
491129009Snyan		}
492129009Snyan#else
493128929Sjhb	/*
494128929Sjhb	 * Look for an ELCR.  If we find one, update the trigger modes.
495128929Sjhb	 * If we don't find one, assume that IRQs 0, 1, 2, and 13 are
496128929Sjhb	 * edge triggered and that everything else is level triggered.
497128929Sjhb	 * We only use the trigger information to reprogram the ELCR if
498128929Sjhb	 * we have one and as an optimization to avoid masking edge
499128929Sjhb	 * triggered interrupts.  For the case that we don't have an ELCR,
500128929Sjhb	 * it doesn't hurt to mask an edge triggered interrupt, so we
501129095Sjhb	 * assume level trigger for any interrupt that we aren't sure is
502129095Sjhb	 * edge triggered.
503128929Sjhb	 */
504140451Sjhb	if (elcr_found) {
505128929Sjhb		for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++)
506128929Sjhb			ai->at_trigger = elcr_read_trigger(i);
507128929Sjhb	} else {
508128929Sjhb		for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++)
509128929Sjhb			switch (i) {
510128929Sjhb			case 0:
511128929Sjhb			case 1:
512128929Sjhb			case 2:
513128929Sjhb			case 8:
514128929Sjhb			case 13:
515128929Sjhb				ai->at_trigger = INTR_TRIGGER_EDGE;
516128929Sjhb				break;
517128929Sjhb			default:
518128929Sjhb				ai->at_trigger = INTR_TRIGGER_LEVEL;
519128929Sjhb				break;
520128929Sjhb			}
521128929Sjhb	}
522129009Snyan#endif /* PC98 */
523121985Sjhb}
524121985Sjhb
525121985Sjhbstatic void
526121985Sjhbatpic_init(void *dummy __unused)
527121985Sjhb{
528128875Sjhb	struct atpic_intsrc *ai;
529121985Sjhb	int i;
530121985Sjhb
531153136Sjhb	/*
532153136Sjhb	 * If any of the ISA IRQs have an interrupt source already, then
533153136Sjhb	 * assume that the APICs are being used and don't register any
534153136Sjhb	 * of our interrupt sources.  This makes sure we don't accidentally
535153136Sjhb	 * use mixed mode.  The "accidental" use could otherwise occur on
536153136Sjhb	 * machines that route the ACPI SCI interrupt to a different ISA
537153136Sjhb	 * IRQ (at least one machines routes it to IRQ 13) thus disabling
538153136Sjhb	 * that APIC ISA routing and allowing the ATPIC source for that IRQ
539153136Sjhb	 * to leak through.  We used to depend on this feature for routing
540153136Sjhb	 * IRQ0 via mixed mode, but now we don't use mixed mode at all.
541153136Sjhb	 */
542153136Sjhb	for (i = 0; i < NUM_ISA_IRQS; i++)
543153136Sjhb		if (intr_lookup_source(i) != NULL)
544153136Sjhb			return;
545153136Sjhb
546121985Sjhb	/* Loop through all interrupt sources and add them. */
547128875Sjhb	for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) {
548121985Sjhb		if (i == ICU_SLAVEID)
549121985Sjhb			continue;
550128875Sjhb		intr_register_source(&ai->at_intsrc);
551121985Sjhb	}
552121985Sjhb}
553121985SjhbSYSINIT(atpic_init, SI_SUB_INTR, SI_ORDER_SECOND + 1, atpic_init, NULL)
554121985Sjhb
555121985Sjhbvoid
556153146Sjhbatpic_handle_intr(u_int vector, struct trapframe frame)
557121985Sjhb{
558121985Sjhb	struct intsrc *isrc;
559121985Sjhb
560153242Sjhb	KASSERT(vector < NUM_ISA_IRQS, ("unknown int %u\n", vector));
561153146Sjhb	isrc = &atintrs[vector].at_intsrc;
562122898Sjhb
563122898Sjhb	/*
564151658Sjhb	 * If we don't have an event, see if this is a spurious
565122898Sjhb	 * interrupt.
566122898Sjhb	 */
567153146Sjhb	if (isrc->is_event == NULL && (vector == 7 || vector == 15)) {
568122898Sjhb		int port, isr;
569122898Sjhb
570122898Sjhb		/*
571122898Sjhb		 * Read the ISR register to see if IRQ 7/15 is really
572122898Sjhb		 * pending.  Reset read register back to IRR when done.
573122898Sjhb		 */
574122898Sjhb		port = ((struct atpic *)isrc->is_pic)->at_ioaddr;
575122898Sjhb		mtx_lock_spin(&icu_lock);
576122898Sjhb		outb(port, OCW3_SEL | OCW3_RR | OCW3_RIS);
577122898Sjhb		isr = inb(port);
578122898Sjhb		outb(port, OCW3_SEL | OCW3_RR);
579122898Sjhb		mtx_unlock_spin(&icu_lock);
580129131Sjhb		if ((isr & IRQ_MASK(7)) == 0)
581122898Sjhb			return;
582122898Sjhb	}
583153146Sjhb	intr_execute_handlers(isrc, &frame);
584121985Sjhb}
585121985Sjhb
586121985Sjhb#ifdef DEV_ISA
587121985Sjhb/*
588121985Sjhb * Bus attachment for the ISA PIC.
589121985Sjhb */
590121985Sjhbstatic struct isa_pnp_id atpic_ids[] = {
591121985Sjhb	{ 0x0000d041 /* PNP0000 */, "AT interrupt controller" },
592121985Sjhb	{ 0 }
593121985Sjhb};
594121985Sjhb
595121985Sjhbstatic int
596121985Sjhbatpic_probe(device_t dev)
597121985Sjhb{
598121985Sjhb	int result;
599121985Sjhb
600121985Sjhb	result = ISA_PNP_PROBE(device_get_parent(dev), dev, atpic_ids);
601121985Sjhb	if (result <= 0)
602121985Sjhb		device_quiet(dev);
603121985Sjhb	return (result);
604121985Sjhb}
605121985Sjhb
606121985Sjhb/*
607121985Sjhb * We might be granted IRQ 2, as this is typically consumed by chaining
608121985Sjhb * between the two PIC components.  If we're using the APIC, however,
609121985Sjhb * this may not be the case, and as such we should free the resource.
610121985Sjhb * (XXX untested)
611121985Sjhb *
612121985Sjhb * The generic ISA attachment code will handle allocating any other resources
613121985Sjhb * that we don't explicitly claim here.
614121985Sjhb */
615121985Sjhbstatic int
616121985Sjhbatpic_attach(device_t dev)
617121985Sjhb{
618121985Sjhb	struct resource *res;
619121985Sjhb	int rid;
620121985Sjhb
621121985Sjhb	/* Try to allocate our IRQ and then free it. */
622121985Sjhb	rid = 0;
623127135Snjl	res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 0);
624121985Sjhb	if (res != NULL)
625121985Sjhb		bus_release_resource(dev, SYS_RES_IRQ, rid, res);
626121985Sjhb	return (0);
627121985Sjhb}
628121985Sjhb
629121985Sjhbstatic device_method_t atpic_methods[] = {
630121985Sjhb	/* Device interface */
631121985Sjhb	DEVMETHOD(device_probe,		atpic_probe),
632121985Sjhb	DEVMETHOD(device_attach,	atpic_attach),
633121985Sjhb	DEVMETHOD(device_detach,	bus_generic_detach),
634121985Sjhb	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
635121985Sjhb	DEVMETHOD(device_suspend,	bus_generic_suspend),
636121985Sjhb	DEVMETHOD(device_resume,	bus_generic_resume),
637121985Sjhb	{ 0, 0 }
638121985Sjhb};
639121985Sjhb
640121985Sjhbstatic driver_t atpic_driver = {
641121985Sjhb	"atpic",
642121985Sjhb	atpic_methods,
643121985Sjhb	1,		/* no softc */
644121985Sjhb};
645121985Sjhb
646121985Sjhbstatic devclass_t atpic_devclass;
647121985Sjhb
648121985SjhbDRIVER_MODULE(atpic, isa, atpic_driver, atpic_devclass, 0, 0);
649122051Snyan#ifndef PC98
650121985SjhbDRIVER_MODULE(atpic, acpi, atpic_driver, atpic_devclass, 0, 0);
651122051Snyan#endif
652121985Sjhb
653121985Sjhb/*
654121985Sjhb * Return a bitmap of the current interrupt requests.  This is 8259-specific
655121985Sjhb * and is only suitable for use at probe time.
656121985Sjhb */
657121985Sjhbintrmask_t
658121985Sjhbisa_irq_pending(void)
659121985Sjhb{
660121985Sjhb	u_char irr1;
661121985Sjhb	u_char irr2;
662121985Sjhb
663121985Sjhb	irr1 = inb(IO_ICU1);
664121985Sjhb	irr2 = inb(IO_ICU2);
665121985Sjhb	return ((irr2 << 8) | irr1);
666121985Sjhb}
667121985Sjhb#endif /* DEV_ISA */
668