atpic.c revision 153242
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 153242 2005-12-08 18:33:48Z 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, \
129128931Sjhb	    atpic_resume, atpic_config_intr }, (io), (base),		\
130128931Sjhb	    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);
163121985Sjhbstatic void i8259_init(struct atpic *pic, int slave);
164121985Sjhb
165121985Sjhbstatic struct atpic atpics[] = {
166121985Sjhb	ATPIC(IO_ICU1, 0, atpic_eoi_master, (uint8_t *)&imen),
167121985Sjhb	ATPIC(IO_ICU2, 8, atpic_eoi_slave, ((uint8_t *)&imen) + 1)
168121985Sjhb};
169121985Sjhb
170121985Sjhbstatic struct atpic_intsrc atintrs[] = {
171121985Sjhb	INTSRC(0),
172121985Sjhb	INTSRC(1),
173121985Sjhb	INTSRC(2),
174121985Sjhb	INTSRC(3),
175121985Sjhb	INTSRC(4),
176121985Sjhb	INTSRC(5),
177121985Sjhb	INTSRC(6),
178121985Sjhb	INTSRC(7),
179121985Sjhb	INTSRC(8),
180121985Sjhb	INTSRC(9),
181121985Sjhb	INTSRC(10),
182121985Sjhb	INTSRC(11),
183121985Sjhb	INTSRC(12),
184121985Sjhb	INTSRC(13),
185121985Sjhb	INTSRC(14),
186121985Sjhb	INTSRC(15),
187121985Sjhb};
188121985Sjhb
189129095SjhbCTASSERT(sizeof(atintrs) / sizeof(atintrs[0]) == NUM_ISA_IRQS);
190128875Sjhb
191133017Sscottlstatic __inline void
192133017Sscottl_atpic_eoi_master(struct intsrc *isrc)
193133017Sscottl{
194133017Sscottl
195133017Sscottl	KASSERT(isrc->is_pic == &atpics[MASTER].at_pic,
196133017Sscottl	    ("%s: mismatched pic", __func__));
197133017Sscottl#ifndef AUTO_EOI_1
198133017Sscottl	outb(atpics[MASTER].at_ioaddr, OCW2_EOI);
199133017Sscottl#endif
200133017Sscottl}
201133017Sscottl
202133017Sscottl/*
203133017Sscottl * The data sheet says no auto-EOI on slave, but it sometimes works.
204133017Sscottl * So, if AUTO_EOI_2 is enabled, we use it.
205133017Sscottl */
206133017Sscottlstatic __inline void
207133017Sscottl_atpic_eoi_slave(struct intsrc *isrc)
208133017Sscottl{
209133017Sscottl
210133017Sscottl	KASSERT(isrc->is_pic == &atpics[SLAVE].at_pic,
211133017Sscottl	    ("%s: mismatched pic", __func__));
212133017Sscottl#ifndef AUTO_EOI_2
213133017Sscottl	outb(atpics[SLAVE].at_ioaddr, OCW2_EOI);
214133017Sscottl#ifndef AUTO_EOI_1
215133017Sscottl	outb(atpics[MASTER].at_ioaddr, OCW2_EOI);
216133017Sscottl#endif
217133017Sscottl#endif
218133017Sscottl}
219133017Sscottl
220121985Sjhbstatic void
221121985Sjhbatpic_enable_source(struct intsrc *isrc)
222121985Sjhb{
223121985Sjhb	struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc;
224121985Sjhb	struct atpic *ap = (struct atpic *)isrc->is_pic;
225121985Sjhb
226121985Sjhb	mtx_lock_spin(&icu_lock);
227128875Sjhb	if (*ap->at_imen & IMEN_MASK(ai)) {
228128875Sjhb		*ap->at_imen &= ~IMEN_MASK(ai);
229128875Sjhb		outb(ap->at_ioaddr + ICU_IMR_OFFSET, *ap->at_imen);
230128875Sjhb	}
231121985Sjhb	mtx_unlock_spin(&icu_lock);
232121985Sjhb}
233121985Sjhb
234121985Sjhbstatic void
235133017Sscottlatpic_disable_source(struct intsrc *isrc, int eoi)
236121985Sjhb{
237121985Sjhb	struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc;
238121985Sjhb	struct atpic *ap = (struct atpic *)isrc->is_pic;
239121985Sjhb
240121985Sjhb	mtx_lock_spin(&icu_lock);
241133017Sscottl	if (ai->at_trigger != INTR_TRIGGER_EDGE) {
242133017Sscottl		*ap->at_imen |= IMEN_MASK(ai);
243133017Sscottl		outb(ap->at_ioaddr + ICU_IMR_OFFSET, *ap->at_imen);
244133017Sscottl	}
245133017Sscottl
246133017Sscottl	/*
247133017Sscottl	 * Take care to call these functions directly instead of through
248133017Sscottl	 * a function pointer.  All of the referenced variables should
249133017Sscottl	 * still be hot in the cache.
250133017Sscottl	 */
251133017Sscottl	if (eoi == PIC_EOI) {
252133017Sscottl		if (isrc->is_pic == &atpics[MASTER].at_pic)
253133017Sscottl			_atpic_eoi_master(isrc);
254133017Sscottl		else
255133017Sscottl			_atpic_eoi_slave(isrc);
256133017Sscottl	}
257133017Sscottl
258121985Sjhb	mtx_unlock_spin(&icu_lock);
259121985Sjhb}
260121985Sjhb
261121985Sjhbstatic void
262121985Sjhbatpic_eoi_master(struct intsrc *isrc)
263121985Sjhb{
264121985Sjhb#ifndef AUTO_EOI_1
265121985Sjhb	mtx_lock_spin(&icu_lock);
266133017Sscottl	_atpic_eoi_master(isrc);
267121985Sjhb	mtx_unlock_spin(&icu_lock);
268121985Sjhb#endif
269121985Sjhb}
270121985Sjhb
271121985Sjhbstatic void
272121985Sjhbatpic_eoi_slave(struct intsrc *isrc)
273121985Sjhb{
274121985Sjhb#ifndef AUTO_EOI_2
275121985Sjhb	mtx_lock_spin(&icu_lock);
276133017Sscottl	_atpic_eoi_slave(isrc);
277121985Sjhb	mtx_unlock_spin(&icu_lock);
278121985Sjhb#endif
279121985Sjhb}
280121985Sjhb
281121985Sjhbstatic void
282121985Sjhbatpic_enable_intr(struct intsrc *isrc)
283121985Sjhb{
284121985Sjhb}
285121985Sjhb
286121985Sjhbstatic int
287121985Sjhbatpic_vector(struct intsrc *isrc)
288121985Sjhb{
289121985Sjhb	struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc;
290121985Sjhb	struct atpic *ap = (struct atpic *)isrc->is_pic;
291121985Sjhb
292121985Sjhb	return (IRQ(ap, ai));
293121985Sjhb}
294121985Sjhb
295121985Sjhbstatic int
296121985Sjhbatpic_source_pending(struct intsrc *isrc)
297121985Sjhb{
298121985Sjhb	struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc;
299121985Sjhb	struct atpic *ap = (struct atpic *)isrc->is_pic;
300121985Sjhb
301128875Sjhb	return (inb(ap->at_ioaddr) & IMEN_MASK(ai));
302121985Sjhb}
303121985Sjhb
304121985Sjhbstatic void
305121985Sjhbatpic_resume(struct intsrc *isrc)
306121985Sjhb{
307121985Sjhb	struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc;
308121985Sjhb	struct atpic *ap = (struct atpic *)isrc->is_pic;
309121985Sjhb
310128929Sjhb	if (ai->at_irq == 0) {
311121985Sjhb		i8259_init(ap, ap == &atpics[SLAVE]);
312129009Snyan#ifndef PC98
313140451Sjhb		if (ap == &atpics[SLAVE] && elcr_found)
314128929Sjhb			elcr_resume();
315129009Snyan#endif
316128929Sjhb	}
317121985Sjhb}
318121985Sjhb
319128931Sjhbstatic int
320128931Sjhbatpic_config_intr(struct intsrc *isrc, enum intr_trigger trig,
321128931Sjhb    enum intr_polarity pol)
322128931Sjhb{
323128931Sjhb	struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc;
324128931Sjhb	u_int vector;
325128931Sjhb
326128931Sjhb	/* Map conforming values to edge/hi and sanity check the values. */
327128931Sjhb	if (trig == INTR_TRIGGER_CONFORM)
328128931Sjhb		trig = INTR_TRIGGER_EDGE;
329128931Sjhb	if (pol == INTR_POLARITY_CONFORM)
330128931Sjhb		pol = INTR_POLARITY_HIGH;
331128931Sjhb	vector = atpic_vector(isrc);
332128931Sjhb	if ((trig == INTR_TRIGGER_EDGE && pol == INTR_POLARITY_LOW) ||
333128931Sjhb	    (trig == INTR_TRIGGER_LEVEL && pol == INTR_POLARITY_HIGH)) {
334128931Sjhb		printf(
335128931Sjhb		"atpic: Mismatched config for IRQ%u: trigger %s, polarity %s\n",
336128931Sjhb		    vector, trig == INTR_TRIGGER_EDGE ? "edge" : "level",
337128931Sjhb		    pol == INTR_POLARITY_HIGH ? "high" : "low");
338128931Sjhb		return (EINVAL);
339128931Sjhb	}
340128931Sjhb
341128931Sjhb	/* If there is no change, just return. */
342128931Sjhb	if (ai->at_trigger == trig)
343128931Sjhb		return (0);
344128931Sjhb
345129009Snyan#ifdef PC98
346129009Snyan	if ((vector == 0 || vector == 1 || vector == 7 || vector == 8) &&
347129009Snyan	    trig == INTR_TRIGGER_LEVEL) {
348129009Snyan		if (bootverbose)
349129009Snyan			printf(
350129009Snyan		"atpic: Ignoring invalid level/low configuration for IRQ%u\n",
351129009Snyan			    vector);
352129009Snyan		return (EINVAL);
353129009Snyan	}
354129009Snyan	return (ENXIO);
355129009Snyan#else
356128931Sjhb	/*
357128931Sjhb	 * Certain IRQs can never be level/lo, so don't try to set them
358128931Sjhb	 * that way if asked.  At least some ELCR registers ignore setting
359128931Sjhb	 * these bits as well.
360128931Sjhb	 */
361128931Sjhb	if ((vector == 0 || vector == 1 || vector == 2 || vector == 13) &&
362128931Sjhb	    trig == INTR_TRIGGER_LEVEL) {
363128931Sjhb		if (bootverbose)
364128931Sjhb			printf(
365128931Sjhb		"atpic: Ignoring invalid level/low configuration for IRQ%u\n",
366128931Sjhb			    vector);
367128931Sjhb		return (EINVAL);
368128931Sjhb	}
369140451Sjhb	if (!elcr_found) {
370128931Sjhb		if (bootverbose)
371128931Sjhb			printf("atpic: No ELCR to configure IRQ%u as %s\n",
372128931Sjhb			    vector, trig == INTR_TRIGGER_EDGE ? "edge/high" :
373128931Sjhb			    "level/low");
374128931Sjhb		return (ENXIO);
375128931Sjhb	}
376128931Sjhb	if (bootverbose)
377128931Sjhb		printf("atpic: Programming IRQ%u as %s\n", vector,
378128931Sjhb		    trig == INTR_TRIGGER_EDGE ? "edge/high" : "level/low");
379128931Sjhb	mtx_lock_spin(&icu_lock);
380128931Sjhb	elcr_write_trigger(atpic_vector(isrc), trig);
381128931Sjhb	ai->at_trigger = trig;
382128931Sjhb	mtx_unlock_spin(&icu_lock);
383128931Sjhb	return (0);
384129009Snyan#endif /* PC98 */
385128931Sjhb}
386128931Sjhb
387121985Sjhbstatic void
388121985Sjhbi8259_init(struct atpic *pic, int slave)
389121985Sjhb{
390121985Sjhb	int imr_addr;
391121985Sjhb
392121985Sjhb	/* Reset the PIC and program with next four bytes. */
393121985Sjhb	mtx_lock_spin(&icu_lock);
394121985Sjhb#ifdef DEV_MCA
395122692Sjhb	/* MCA uses level triggered interrupts. */
396121985Sjhb	if (MCA_system)
397122692Sjhb		outb(pic->at_ioaddr, ICW1_RESET | ICW1_IC4 | ICW1_LTIM);
398121985Sjhb	else
399121985Sjhb#endif
400122692Sjhb		outb(pic->at_ioaddr, ICW1_RESET | ICW1_IC4);
401121985Sjhb	imr_addr = pic->at_ioaddr + ICU_IMR_OFFSET;
402121985Sjhb
403121985Sjhb	/* Start vector. */
404121985Sjhb	outb(imr_addr, pic->at_intbase);
405121985Sjhb
406121985Sjhb	/*
407121985Sjhb	 * Setup slave links.  For the master pic, indicate what line
408121985Sjhb	 * the slave is configured on.  For the slave indicate
409121985Sjhb	 * which line on the master we are connected to.
410121985Sjhb	 */
411121985Sjhb	if (slave)
412129131Sjhb		outb(imr_addr, ICU_SLAVEID);
413121985Sjhb	else
414129131Sjhb		outb(imr_addr, IRQ_MASK(ICU_SLAVEID));
415121985Sjhb
416121985Sjhb	/* Set mode. */
417121985Sjhb	if (slave)
418121985Sjhb		outb(imr_addr, SLAVE_MODE);
419121985Sjhb	else
420121985Sjhb		outb(imr_addr, MASTER_MODE);
421121985Sjhb
422121985Sjhb	/* Set interrupt enable mask. */
423121985Sjhb	outb(imr_addr, *pic->at_imen);
424121985Sjhb
425121985Sjhb	/* Reset is finished, default to IRR on read. */
426122692Sjhb	outb(pic->at_ioaddr, OCW3_SEL | OCW3_RR);
427121985Sjhb
428121985Sjhb#ifndef PC98
429122692Sjhb	/* OCW2_L1 sets priority order to 3-7, 0-2 (com2 first). */
430121985Sjhb	if (!slave)
431122692Sjhb		outb(pic->at_ioaddr, OCW2_R | OCW2_SL | OCW2_L1);
432121985Sjhb#endif
433121985Sjhb	mtx_unlock_spin(&icu_lock);
434121985Sjhb}
435121985Sjhb
436121985Sjhbvoid
437121985Sjhbatpic_startup(void)
438121985Sjhb{
439122897Sjhb	struct atpic_intsrc *ai;
440122897Sjhb	int i;
441121985Sjhb
442121985Sjhb	/* Start off with all interrupts disabled. */
443121985Sjhb	imen = 0xffff;
444121985Sjhb	i8259_init(&atpics[MASTER], 0);
445121985Sjhb	i8259_init(&atpics[SLAVE], 1);
446121985Sjhb	atpic_enable_source((struct intsrc *)&atintrs[ICU_SLAVEID]);
447122897Sjhb
448122897Sjhb	/* Install low-level interrupt handlers for all of our IRQs. */
449128875Sjhb	for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) {
450122897Sjhb		if (i == ICU_SLAVEID)
451122897Sjhb			continue;
452122897Sjhb		ai->at_intsrc.is_count = &ai->at_count;
453122897Sjhb		ai->at_intsrc.is_straycount = &ai->at_straycount;
454122897Sjhb		setidt(((struct atpic *)ai->at_intsrc.is_pic)->at_intbase +
455122897Sjhb		    ai->at_irq, ai->at_intr, SDT_SYS386IGT, SEL_KPL,
456122897Sjhb		    GSEL(GCODE_SEL, SEL_KPL));
457122897Sjhb	}
458128929Sjhb
459128929Sjhb#ifdef DEV_MCA
460128929Sjhb	/* For MCA systems, all interrupts are level triggered. */
461128929Sjhb	if (MCA_system)
462128929Sjhb		for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++)
463128929Sjhb			ai->at_trigger = INTR_TRIGGER_LEVEL;
464128929Sjhb	else
465128929Sjhb#endif
466128929Sjhb
467129009Snyan#ifdef PC98
468129009Snyan	for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++)
469129009Snyan		switch (i) {
470129009Snyan		case 0:
471129009Snyan		case 1:
472129009Snyan		case 7:
473129009Snyan		case 8:
474129009Snyan			ai->at_trigger = INTR_TRIGGER_EDGE;
475129009Snyan			break;
476129009Snyan		default:
477129009Snyan			ai->at_trigger = INTR_TRIGGER_LEVEL;
478129009Snyan			break;
479129009Snyan		}
480129009Snyan#else
481128929Sjhb	/*
482128929Sjhb	 * Look for an ELCR.  If we find one, update the trigger modes.
483128929Sjhb	 * If we don't find one, assume that IRQs 0, 1, 2, and 13 are
484128929Sjhb	 * edge triggered and that everything else is level triggered.
485128929Sjhb	 * We only use the trigger information to reprogram the ELCR if
486128929Sjhb	 * we have one and as an optimization to avoid masking edge
487128929Sjhb	 * triggered interrupts.  For the case that we don't have an ELCR,
488128929Sjhb	 * it doesn't hurt to mask an edge triggered interrupt, so we
489129095Sjhb	 * assume level trigger for any interrupt that we aren't sure is
490129095Sjhb	 * edge triggered.
491128929Sjhb	 */
492140451Sjhb	if (elcr_found) {
493128929Sjhb		for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++)
494128929Sjhb			ai->at_trigger = elcr_read_trigger(i);
495128929Sjhb	} else {
496128929Sjhb		for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++)
497128929Sjhb			switch (i) {
498128929Sjhb			case 0:
499128929Sjhb			case 1:
500128929Sjhb			case 2:
501128929Sjhb			case 8:
502128929Sjhb			case 13:
503128929Sjhb				ai->at_trigger = INTR_TRIGGER_EDGE;
504128929Sjhb				break;
505128929Sjhb			default:
506128929Sjhb				ai->at_trigger = INTR_TRIGGER_LEVEL;
507128929Sjhb				break;
508128929Sjhb			}
509128929Sjhb	}
510129009Snyan#endif /* PC98 */
511121985Sjhb}
512121985Sjhb
513121985Sjhbstatic void
514121985Sjhbatpic_init(void *dummy __unused)
515121985Sjhb{
516128875Sjhb	struct atpic_intsrc *ai;
517121985Sjhb	int i;
518121985Sjhb
519153136Sjhb	/*
520153136Sjhb	 * If any of the ISA IRQs have an interrupt source already, then
521153136Sjhb	 * assume that the APICs are being used and don't register any
522153136Sjhb	 * of our interrupt sources.  This makes sure we don't accidentally
523153136Sjhb	 * use mixed mode.  The "accidental" use could otherwise occur on
524153136Sjhb	 * machines that route the ACPI SCI interrupt to a different ISA
525153136Sjhb	 * IRQ (at least one machines routes it to IRQ 13) thus disabling
526153136Sjhb	 * that APIC ISA routing and allowing the ATPIC source for that IRQ
527153136Sjhb	 * to leak through.  We used to depend on this feature for routing
528153136Sjhb	 * IRQ0 via mixed mode, but now we don't use mixed mode at all.
529153136Sjhb	 */
530153136Sjhb	for (i = 0; i < NUM_ISA_IRQS; i++)
531153136Sjhb		if (intr_lookup_source(i) != NULL)
532153136Sjhb			return;
533153136Sjhb
534121985Sjhb	/* Loop through all interrupt sources and add them. */
535128875Sjhb	for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) {
536121985Sjhb		if (i == ICU_SLAVEID)
537121985Sjhb			continue;
538128875Sjhb		intr_register_source(&ai->at_intsrc);
539121985Sjhb	}
540121985Sjhb}
541121985SjhbSYSINIT(atpic_init, SI_SUB_INTR, SI_ORDER_SECOND + 1, atpic_init, NULL)
542121985Sjhb
543121985Sjhbvoid
544153146Sjhbatpic_handle_intr(u_int vector, struct trapframe frame)
545121985Sjhb{
546121985Sjhb	struct intsrc *isrc;
547121985Sjhb
548153242Sjhb	KASSERT(vector < NUM_ISA_IRQS, ("unknown int %u\n", vector));
549153146Sjhb	isrc = &atintrs[vector].at_intsrc;
550122898Sjhb
551122898Sjhb	/*
552151658Sjhb	 * If we don't have an event, see if this is a spurious
553122898Sjhb	 * interrupt.
554122898Sjhb	 */
555153146Sjhb	if (isrc->is_event == NULL && (vector == 7 || vector == 15)) {
556122898Sjhb		int port, isr;
557122898Sjhb
558122898Sjhb		/*
559122898Sjhb		 * Read the ISR register to see if IRQ 7/15 is really
560122898Sjhb		 * pending.  Reset read register back to IRR when done.
561122898Sjhb		 */
562122898Sjhb		port = ((struct atpic *)isrc->is_pic)->at_ioaddr;
563122898Sjhb		mtx_lock_spin(&icu_lock);
564122898Sjhb		outb(port, OCW3_SEL | OCW3_RR | OCW3_RIS);
565122898Sjhb		isr = inb(port);
566122898Sjhb		outb(port, OCW3_SEL | OCW3_RR);
567122898Sjhb		mtx_unlock_spin(&icu_lock);
568129131Sjhb		if ((isr & IRQ_MASK(7)) == 0)
569122898Sjhb			return;
570122898Sjhb	}
571153146Sjhb	intr_execute_handlers(isrc, &frame);
572121985Sjhb}
573121985Sjhb
574121985Sjhb#ifdef DEV_ISA
575121985Sjhb/*
576121985Sjhb * Bus attachment for the ISA PIC.
577121985Sjhb */
578121985Sjhbstatic struct isa_pnp_id atpic_ids[] = {
579121985Sjhb	{ 0x0000d041 /* PNP0000 */, "AT interrupt controller" },
580121985Sjhb	{ 0 }
581121985Sjhb};
582121985Sjhb
583121985Sjhbstatic int
584121985Sjhbatpic_probe(device_t dev)
585121985Sjhb{
586121985Sjhb	int result;
587121985Sjhb
588121985Sjhb	result = ISA_PNP_PROBE(device_get_parent(dev), dev, atpic_ids);
589121985Sjhb	if (result <= 0)
590121985Sjhb		device_quiet(dev);
591121985Sjhb	return (result);
592121985Sjhb}
593121985Sjhb
594121985Sjhb/*
595121985Sjhb * We might be granted IRQ 2, as this is typically consumed by chaining
596121985Sjhb * between the two PIC components.  If we're using the APIC, however,
597121985Sjhb * this may not be the case, and as such we should free the resource.
598121985Sjhb * (XXX untested)
599121985Sjhb *
600121985Sjhb * The generic ISA attachment code will handle allocating any other resources
601121985Sjhb * that we don't explicitly claim here.
602121985Sjhb */
603121985Sjhbstatic int
604121985Sjhbatpic_attach(device_t dev)
605121985Sjhb{
606121985Sjhb	struct resource *res;
607121985Sjhb	int rid;
608121985Sjhb
609121985Sjhb	/* Try to allocate our IRQ and then free it. */
610121985Sjhb	rid = 0;
611127135Snjl	res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 0);
612121985Sjhb	if (res != NULL)
613121985Sjhb		bus_release_resource(dev, SYS_RES_IRQ, rid, res);
614121985Sjhb	return (0);
615121985Sjhb}
616121985Sjhb
617121985Sjhbstatic device_method_t atpic_methods[] = {
618121985Sjhb	/* Device interface */
619121985Sjhb	DEVMETHOD(device_probe,		atpic_probe),
620121985Sjhb	DEVMETHOD(device_attach,	atpic_attach),
621121985Sjhb	DEVMETHOD(device_detach,	bus_generic_detach),
622121985Sjhb	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
623121985Sjhb	DEVMETHOD(device_suspend,	bus_generic_suspend),
624121985Sjhb	DEVMETHOD(device_resume,	bus_generic_resume),
625121985Sjhb	{ 0, 0 }
626121985Sjhb};
627121985Sjhb
628121985Sjhbstatic driver_t atpic_driver = {
629121985Sjhb	"atpic",
630121985Sjhb	atpic_methods,
631121985Sjhb	1,		/* no softc */
632121985Sjhb};
633121985Sjhb
634121985Sjhbstatic devclass_t atpic_devclass;
635121985Sjhb
636121985SjhbDRIVER_MODULE(atpic, isa, atpic_driver, atpic_devclass, 0, 0);
637122051Snyan#ifndef PC98
638121985SjhbDRIVER_MODULE(atpic, acpi, atpic_driver, atpic_devclass, 0, 0);
639122051Snyan#endif
640121985Sjhb
641121985Sjhb/*
642121985Sjhb * Return a bitmap of the current interrupt requests.  This is 8259-specific
643121985Sjhb * and is only suitable for use at probe time.
644121985Sjhb */
645121985Sjhbintrmask_t
646121985Sjhbisa_irq_pending(void)
647121985Sjhb{
648121985Sjhb	u_char irr1;
649121985Sjhb	u_char irr2;
650121985Sjhb
651121985Sjhb	irr1 = inb(IO_ICU1);
652121985Sjhb	irr2 = inb(IO_ICU2);
653121985Sjhb	return ((irr2 << 8) | irr1);
654121985Sjhb}
655121985Sjhb#endif /* DEV_ISA */
656