atpic.c revision 151658
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 151658 2005-10-25 19:48: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
519121985Sjhb	/* Loop through all interrupt sources and add them. */
520128875Sjhb	for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) {
521121985Sjhb		if (i == ICU_SLAVEID)
522121985Sjhb			continue;
523128875Sjhb		intr_register_source(&ai->at_intsrc);
524121985Sjhb	}
525121985Sjhb}
526121985SjhbSYSINIT(atpic_init, SI_SUB_INTR, SI_ORDER_SECOND + 1, atpic_init, NULL)
527121985Sjhb
528121985Sjhbvoid
529122572Sjhbatpic_handle_intr(struct intrframe iframe)
530121985Sjhb{
531121985Sjhb	struct intsrc *isrc;
532121985Sjhb
533129131Sjhb	KASSERT((u_int)iframe.if_vec < NUM_ISA_IRQS,
534121985Sjhb	    ("unknown int %d\n", iframe.if_vec));
535121985Sjhb	isrc = &atintrs[iframe.if_vec].at_intsrc;
536122898Sjhb
537122898Sjhb	/*
538151658Sjhb	 * If we don't have an event, see if this is a spurious
539122898Sjhb	 * interrupt.
540122898Sjhb	 */
541151658Sjhb	if (isrc->is_event == NULL &&
542122898Sjhb	    (iframe.if_vec == 7 || iframe.if_vec == 15)) {
543122898Sjhb		int port, isr;
544122898Sjhb
545122898Sjhb		/*
546122898Sjhb		 * Read the ISR register to see if IRQ 7/15 is really
547122898Sjhb		 * pending.  Reset read register back to IRR when done.
548122898Sjhb		 */
549122898Sjhb		port = ((struct atpic *)isrc->is_pic)->at_ioaddr;
550122898Sjhb		mtx_lock_spin(&icu_lock);
551122898Sjhb		outb(port, OCW3_SEL | OCW3_RR | OCW3_RIS);
552122898Sjhb		isr = inb(port);
553122898Sjhb		outb(port, OCW3_SEL | OCW3_RR);
554122898Sjhb		mtx_unlock_spin(&icu_lock);
555129131Sjhb		if ((isr & IRQ_MASK(7)) == 0)
556122898Sjhb			return;
557122898Sjhb	}
558121985Sjhb	intr_execute_handlers(isrc, &iframe);
559121985Sjhb}
560121985Sjhb
561121985Sjhb#ifdef DEV_ISA
562121985Sjhb/*
563121985Sjhb * Bus attachment for the ISA PIC.
564121985Sjhb */
565121985Sjhbstatic struct isa_pnp_id atpic_ids[] = {
566121985Sjhb	{ 0x0000d041 /* PNP0000 */, "AT interrupt controller" },
567121985Sjhb	{ 0 }
568121985Sjhb};
569121985Sjhb
570121985Sjhbstatic int
571121985Sjhbatpic_probe(device_t dev)
572121985Sjhb{
573121985Sjhb	int result;
574121985Sjhb
575121985Sjhb	result = ISA_PNP_PROBE(device_get_parent(dev), dev, atpic_ids);
576121985Sjhb	if (result <= 0)
577121985Sjhb		device_quiet(dev);
578121985Sjhb	return (result);
579121985Sjhb}
580121985Sjhb
581121985Sjhb/*
582121985Sjhb * We might be granted IRQ 2, as this is typically consumed by chaining
583121985Sjhb * between the two PIC components.  If we're using the APIC, however,
584121985Sjhb * this may not be the case, and as such we should free the resource.
585121985Sjhb * (XXX untested)
586121985Sjhb *
587121985Sjhb * The generic ISA attachment code will handle allocating any other resources
588121985Sjhb * that we don't explicitly claim here.
589121985Sjhb */
590121985Sjhbstatic int
591121985Sjhbatpic_attach(device_t dev)
592121985Sjhb{
593121985Sjhb	struct resource *res;
594121985Sjhb	int rid;
595121985Sjhb
596121985Sjhb	/* Try to allocate our IRQ and then free it. */
597121985Sjhb	rid = 0;
598127135Snjl	res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 0);
599121985Sjhb	if (res != NULL)
600121985Sjhb		bus_release_resource(dev, SYS_RES_IRQ, rid, res);
601121985Sjhb	return (0);
602121985Sjhb}
603121985Sjhb
604121985Sjhbstatic device_method_t atpic_methods[] = {
605121985Sjhb	/* Device interface */
606121985Sjhb	DEVMETHOD(device_probe,		atpic_probe),
607121985Sjhb	DEVMETHOD(device_attach,	atpic_attach),
608121985Sjhb	DEVMETHOD(device_detach,	bus_generic_detach),
609121985Sjhb	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
610121985Sjhb	DEVMETHOD(device_suspend,	bus_generic_suspend),
611121985Sjhb	DEVMETHOD(device_resume,	bus_generic_resume),
612121985Sjhb	{ 0, 0 }
613121985Sjhb};
614121985Sjhb
615121985Sjhbstatic driver_t atpic_driver = {
616121985Sjhb	"atpic",
617121985Sjhb	atpic_methods,
618121985Sjhb	1,		/* no softc */
619121985Sjhb};
620121985Sjhb
621121985Sjhbstatic devclass_t atpic_devclass;
622121985Sjhb
623121985SjhbDRIVER_MODULE(atpic, isa, atpic_driver, atpic_devclass, 0, 0);
624122051Snyan#ifndef PC98
625121985SjhbDRIVER_MODULE(atpic, acpi, atpic_driver, atpic_devclass, 0, 0);
626122051Snyan#endif
627121985Sjhb
628121985Sjhb/*
629121985Sjhb * Return a bitmap of the current interrupt requests.  This is 8259-specific
630121985Sjhb * and is only suitable for use at probe time.
631121985Sjhb */
632121985Sjhbintrmask_t
633121985Sjhbisa_irq_pending(void)
634121985Sjhb{
635121985Sjhb	u_char irr1;
636121985Sjhb	u_char irr2;
637121985Sjhb
638121985Sjhb	irr1 = inb(IO_ICU1);
639121985Sjhb	irr2 = inb(IO_ICU2);
640121985Sjhb	return ((irr2 << 8) | irr1);
641121985Sjhb}
642121985Sjhb#endif /* DEV_ISA */
643