atpic.c revision 133017
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 133017 2004-08-02 15:31:10Z scottl $");
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
59122051Snyan#include <pc98/pc98/pc98.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 */
115129009Snyan#ifndef PC98
116128929Sjhbstatic int using_elcr;
117129009Snyan#endif
118121985Sjhb
119121985Sjhbinthand_t
120121985Sjhb	IDTVEC(atpic_intr0), IDTVEC(atpic_intr1), IDTVEC(atpic_intr2),
121121985Sjhb	IDTVEC(atpic_intr3), IDTVEC(atpic_intr4), IDTVEC(atpic_intr5),
122121985Sjhb	IDTVEC(atpic_intr6), IDTVEC(atpic_intr7), IDTVEC(atpic_intr8),
123121985Sjhb	IDTVEC(atpic_intr9), IDTVEC(atpic_intr10), IDTVEC(atpic_intr11),
124121985Sjhb	IDTVEC(atpic_intr12), IDTVEC(atpic_intr13), IDTVEC(atpic_intr14),
125121985Sjhb	IDTVEC(atpic_intr15);
126121985Sjhb
127121985Sjhb#define	IRQ(ap, ai)	((ap)->at_irqbase + (ai)->at_irq)
128121985Sjhb
129128929Sjhb#define	ATPIC(io, base, eoi, imenptr)					\
130121985Sjhb     	{ { atpic_enable_source, atpic_disable_source, (eoi),		\
131121985Sjhb	    atpic_enable_intr, atpic_vector, atpic_source_pending, NULL, \
132128931Sjhb	    atpic_resume, atpic_config_intr }, (io), (base),		\
133128931Sjhb	    IDT_IO_INTS + (base), (imenptr) }
134121985Sjhb
135121985Sjhb#define	INTSRC(irq)							\
136128929Sjhb	{ { &atpics[(irq) / 8].at_pic }, IDTVEC(atpic_intr ## irq ),	\
137128929Sjhb	    (irq) % 8 }
138121985Sjhb
139121985Sjhbstruct atpic {
140121985Sjhb	struct pic at_pic;
141121985Sjhb	int	at_ioaddr;
142121985Sjhb	int	at_irqbase;
143121985Sjhb	uint8_t	at_intbase;
144121985Sjhb	uint8_t	*at_imen;
145121985Sjhb};
146121985Sjhb
147121985Sjhbstruct atpic_intsrc {
148121985Sjhb	struct intsrc at_intsrc;
149121985Sjhb	inthand_t *at_intr;
150128929Sjhb	int	at_irq;			/* Relative to PIC base. */
151128929Sjhb	enum intr_trigger at_trigger;
152122897Sjhb	u_long	at_count;
153122897Sjhb	u_long	at_straycount;
154121985Sjhb};
155121985Sjhb
156121985Sjhbstatic void atpic_enable_source(struct intsrc *isrc);
157133017Sscottlstatic void atpic_disable_source(struct intsrc *isrc, int eoi);
158121985Sjhbstatic void atpic_eoi_master(struct intsrc *isrc);
159121985Sjhbstatic void atpic_eoi_slave(struct intsrc *isrc);
160121985Sjhbstatic void atpic_enable_intr(struct intsrc *isrc);
161121985Sjhbstatic int atpic_vector(struct intsrc *isrc);
162121985Sjhbstatic void atpic_resume(struct intsrc *isrc);
163121985Sjhbstatic int atpic_source_pending(struct intsrc *isrc);
164128931Sjhbstatic int atpic_config_intr(struct intsrc *isrc, enum intr_trigger trig,
165128931Sjhb    enum intr_polarity pol);
166121985Sjhbstatic void i8259_init(struct atpic *pic, int slave);
167121985Sjhb
168121985Sjhbstatic struct atpic atpics[] = {
169121985Sjhb	ATPIC(IO_ICU1, 0, atpic_eoi_master, (uint8_t *)&imen),
170121985Sjhb	ATPIC(IO_ICU2, 8, atpic_eoi_slave, ((uint8_t *)&imen) + 1)
171121985Sjhb};
172121985Sjhb
173121985Sjhbstatic struct atpic_intsrc atintrs[] = {
174121985Sjhb	INTSRC(0),
175121985Sjhb	INTSRC(1),
176121985Sjhb	INTSRC(2),
177121985Sjhb	INTSRC(3),
178121985Sjhb	INTSRC(4),
179121985Sjhb	INTSRC(5),
180121985Sjhb	INTSRC(6),
181121985Sjhb	INTSRC(7),
182121985Sjhb	INTSRC(8),
183121985Sjhb	INTSRC(9),
184121985Sjhb	INTSRC(10),
185121985Sjhb	INTSRC(11),
186121985Sjhb	INTSRC(12),
187121985Sjhb	INTSRC(13),
188121985Sjhb	INTSRC(14),
189121985Sjhb	INTSRC(15),
190121985Sjhb};
191121985Sjhb
192129095SjhbCTASSERT(sizeof(atintrs) / sizeof(atintrs[0]) == NUM_ISA_IRQS);
193128875Sjhb
194133017Sscottlstatic __inline void
195133017Sscottl_atpic_eoi_master(struct intsrc *isrc)
196133017Sscottl{
197133017Sscottl
198133017Sscottl	KASSERT(isrc->is_pic == &atpics[MASTER].at_pic,
199133017Sscottl	    ("%s: mismatched pic", __func__));
200133017Sscottl#ifndef AUTO_EOI_1
201133017Sscottl	outb(atpics[MASTER].at_ioaddr, OCW2_EOI);
202133017Sscottl#endif
203133017Sscottl}
204133017Sscottl
205133017Sscottl/*
206133017Sscottl * The data sheet says no auto-EOI on slave, but it sometimes works.
207133017Sscottl * So, if AUTO_EOI_2 is enabled, we use it.
208133017Sscottl */
209133017Sscottlstatic __inline void
210133017Sscottl_atpic_eoi_slave(struct intsrc *isrc)
211133017Sscottl{
212133017Sscottl
213133017Sscottl	KASSERT(isrc->is_pic == &atpics[SLAVE].at_pic,
214133017Sscottl	    ("%s: mismatched pic", __func__));
215133017Sscottl#ifndef AUTO_EOI_2
216133017Sscottl	outb(atpics[SLAVE].at_ioaddr, OCW2_EOI);
217133017Sscottl#ifndef AUTO_EOI_1
218133017Sscottl	outb(atpics[MASTER].at_ioaddr, OCW2_EOI);
219133017Sscottl#endif
220133017Sscottl#endif
221133017Sscottl}
222133017Sscottl
223121985Sjhbstatic void
224121985Sjhbatpic_enable_source(struct intsrc *isrc)
225121985Sjhb{
226121985Sjhb	struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc;
227121985Sjhb	struct atpic *ap = (struct atpic *)isrc->is_pic;
228121985Sjhb
229121985Sjhb	mtx_lock_spin(&icu_lock);
230128875Sjhb	if (*ap->at_imen & IMEN_MASK(ai)) {
231128875Sjhb		*ap->at_imen &= ~IMEN_MASK(ai);
232128875Sjhb		outb(ap->at_ioaddr + ICU_IMR_OFFSET, *ap->at_imen);
233128875Sjhb	}
234121985Sjhb	mtx_unlock_spin(&icu_lock);
235121985Sjhb}
236121985Sjhb
237121985Sjhbstatic void
238133017Sscottlatpic_disable_source(struct intsrc *isrc, int eoi)
239121985Sjhb{
240121985Sjhb	struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc;
241121985Sjhb	struct atpic *ap = (struct atpic *)isrc->is_pic;
242121985Sjhb
243121985Sjhb	mtx_lock_spin(&icu_lock);
244133017Sscottl	if (ai->at_trigger != INTR_TRIGGER_EDGE) {
245133017Sscottl		*ap->at_imen |= IMEN_MASK(ai);
246133017Sscottl		outb(ap->at_ioaddr + ICU_IMR_OFFSET, *ap->at_imen);
247133017Sscottl	}
248133017Sscottl
249133017Sscottl	/*
250133017Sscottl	 * Take care to call these functions directly instead of through
251133017Sscottl	 * a function pointer.  All of the referenced variables should
252133017Sscottl	 * still be hot in the cache.
253133017Sscottl	 */
254133017Sscottl	if (eoi == PIC_EOI) {
255133017Sscottl		if (isrc->is_pic == &atpics[MASTER].at_pic)
256133017Sscottl			_atpic_eoi_master(isrc);
257133017Sscottl		else
258133017Sscottl			_atpic_eoi_slave(isrc);
259133017Sscottl	}
260133017Sscottl
261121985Sjhb	mtx_unlock_spin(&icu_lock);
262121985Sjhb}
263121985Sjhb
264121985Sjhbstatic void
265121985Sjhbatpic_eoi_master(struct intsrc *isrc)
266121985Sjhb{
267121985Sjhb#ifndef AUTO_EOI_1
268121985Sjhb	mtx_lock_spin(&icu_lock);
269133017Sscottl	_atpic_eoi_master(isrc);
270121985Sjhb	mtx_unlock_spin(&icu_lock);
271121985Sjhb#endif
272121985Sjhb}
273121985Sjhb
274121985Sjhbstatic void
275121985Sjhbatpic_eoi_slave(struct intsrc *isrc)
276121985Sjhb{
277121985Sjhb#ifndef AUTO_EOI_2
278121985Sjhb	mtx_lock_spin(&icu_lock);
279133017Sscottl	_atpic_eoi_slave(isrc);
280121985Sjhb	mtx_unlock_spin(&icu_lock);
281121985Sjhb#endif
282121985Sjhb}
283121985Sjhb
284121985Sjhbstatic void
285121985Sjhbatpic_enable_intr(struct intsrc *isrc)
286121985Sjhb{
287121985Sjhb}
288121985Sjhb
289121985Sjhbstatic int
290121985Sjhbatpic_vector(struct intsrc *isrc)
291121985Sjhb{
292121985Sjhb	struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc;
293121985Sjhb	struct atpic *ap = (struct atpic *)isrc->is_pic;
294121985Sjhb
295121985Sjhb	return (IRQ(ap, ai));
296121985Sjhb}
297121985Sjhb
298121985Sjhbstatic int
299121985Sjhbatpic_source_pending(struct intsrc *isrc)
300121985Sjhb{
301121985Sjhb	struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc;
302121985Sjhb	struct atpic *ap = (struct atpic *)isrc->is_pic;
303121985Sjhb
304128875Sjhb	return (inb(ap->at_ioaddr) & IMEN_MASK(ai));
305121985Sjhb}
306121985Sjhb
307121985Sjhbstatic void
308121985Sjhbatpic_resume(struct intsrc *isrc)
309121985Sjhb{
310121985Sjhb	struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc;
311121985Sjhb	struct atpic *ap = (struct atpic *)isrc->is_pic;
312121985Sjhb
313128929Sjhb	if (ai->at_irq == 0) {
314121985Sjhb		i8259_init(ap, ap == &atpics[SLAVE]);
315129009Snyan#ifndef PC98
316128929Sjhb		if (ap == &atpics[SLAVE] && using_elcr)
317128929Sjhb			elcr_resume();
318129009Snyan#endif
319128929Sjhb	}
320121985Sjhb}
321121985Sjhb
322128931Sjhbstatic int
323128931Sjhbatpic_config_intr(struct intsrc *isrc, enum intr_trigger trig,
324128931Sjhb    enum intr_polarity pol)
325128931Sjhb{
326128931Sjhb	struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc;
327128931Sjhb	u_int vector;
328128931Sjhb
329128931Sjhb	/* Map conforming values to edge/hi and sanity check the values. */
330128931Sjhb	if (trig == INTR_TRIGGER_CONFORM)
331128931Sjhb		trig = INTR_TRIGGER_EDGE;
332128931Sjhb	if (pol == INTR_POLARITY_CONFORM)
333128931Sjhb		pol = INTR_POLARITY_HIGH;
334128931Sjhb	vector = atpic_vector(isrc);
335128931Sjhb	if ((trig == INTR_TRIGGER_EDGE && pol == INTR_POLARITY_LOW) ||
336128931Sjhb	    (trig == INTR_TRIGGER_LEVEL && pol == INTR_POLARITY_HIGH)) {
337128931Sjhb		printf(
338128931Sjhb		"atpic: Mismatched config for IRQ%u: trigger %s, polarity %s\n",
339128931Sjhb		    vector, trig == INTR_TRIGGER_EDGE ? "edge" : "level",
340128931Sjhb		    pol == INTR_POLARITY_HIGH ? "high" : "low");
341128931Sjhb		return (EINVAL);
342128931Sjhb	}
343128931Sjhb
344128931Sjhb	/* If there is no change, just return. */
345128931Sjhb	if (ai->at_trigger == trig)
346128931Sjhb		return (0);
347128931Sjhb
348129009Snyan#ifdef PC98
349129009Snyan	if ((vector == 0 || vector == 1 || vector == 7 || vector == 8) &&
350129009Snyan	    trig == INTR_TRIGGER_LEVEL) {
351129009Snyan		if (bootverbose)
352129009Snyan			printf(
353129009Snyan		"atpic: Ignoring invalid level/low configuration for IRQ%u\n",
354129009Snyan			    vector);
355129009Snyan		return (EINVAL);
356129009Snyan	}
357129009Snyan	return (ENXIO);
358129009Snyan#else
359128931Sjhb	/*
360128931Sjhb	 * Certain IRQs can never be level/lo, so don't try to set them
361128931Sjhb	 * that way if asked.  At least some ELCR registers ignore setting
362128931Sjhb	 * these bits as well.
363128931Sjhb	 */
364128931Sjhb	if ((vector == 0 || vector == 1 || vector == 2 || vector == 13) &&
365128931Sjhb	    trig == INTR_TRIGGER_LEVEL) {
366128931Sjhb		if (bootverbose)
367128931Sjhb			printf(
368128931Sjhb		"atpic: Ignoring invalid level/low configuration for IRQ%u\n",
369128931Sjhb			    vector);
370128931Sjhb		return (EINVAL);
371128931Sjhb	}
372128931Sjhb	if (!using_elcr) {
373128931Sjhb		if (bootverbose)
374128931Sjhb			printf("atpic: No ELCR to configure IRQ%u as %s\n",
375128931Sjhb			    vector, trig == INTR_TRIGGER_EDGE ? "edge/high" :
376128931Sjhb			    "level/low");
377128931Sjhb		return (ENXIO);
378128931Sjhb	}
379128931Sjhb	if (bootverbose)
380128931Sjhb		printf("atpic: Programming IRQ%u as %s\n", vector,
381128931Sjhb		    trig == INTR_TRIGGER_EDGE ? "edge/high" : "level/low");
382128931Sjhb	mtx_lock_spin(&icu_lock);
383128931Sjhb	elcr_write_trigger(atpic_vector(isrc), trig);
384128931Sjhb	ai->at_trigger = trig;
385128931Sjhb	mtx_unlock_spin(&icu_lock);
386128931Sjhb	return (0);
387129009Snyan#endif /* PC98 */
388128931Sjhb}
389128931Sjhb
390121985Sjhbstatic void
391121985Sjhbi8259_init(struct atpic *pic, int slave)
392121985Sjhb{
393121985Sjhb	int imr_addr;
394121985Sjhb
395121985Sjhb	/* Reset the PIC and program with next four bytes. */
396121985Sjhb	mtx_lock_spin(&icu_lock);
397121985Sjhb#ifdef DEV_MCA
398122692Sjhb	/* MCA uses level triggered interrupts. */
399121985Sjhb	if (MCA_system)
400122692Sjhb		outb(pic->at_ioaddr, ICW1_RESET | ICW1_IC4 | ICW1_LTIM);
401121985Sjhb	else
402121985Sjhb#endif
403122692Sjhb		outb(pic->at_ioaddr, ICW1_RESET | ICW1_IC4);
404121985Sjhb	imr_addr = pic->at_ioaddr + ICU_IMR_OFFSET;
405121985Sjhb
406121985Sjhb	/* Start vector. */
407121985Sjhb	outb(imr_addr, pic->at_intbase);
408121985Sjhb
409121985Sjhb	/*
410121985Sjhb	 * Setup slave links.  For the master pic, indicate what line
411121985Sjhb	 * the slave is configured on.  For the slave indicate
412121985Sjhb	 * which line on the master we are connected to.
413121985Sjhb	 */
414121985Sjhb	if (slave)
415129131Sjhb		outb(imr_addr, ICU_SLAVEID);
416121985Sjhb	else
417129131Sjhb		outb(imr_addr, IRQ_MASK(ICU_SLAVEID));
418121985Sjhb
419121985Sjhb	/* Set mode. */
420121985Sjhb	if (slave)
421121985Sjhb		outb(imr_addr, SLAVE_MODE);
422121985Sjhb	else
423121985Sjhb		outb(imr_addr, MASTER_MODE);
424121985Sjhb
425121985Sjhb	/* Set interrupt enable mask. */
426121985Sjhb	outb(imr_addr, *pic->at_imen);
427121985Sjhb
428121985Sjhb	/* Reset is finished, default to IRR on read. */
429122692Sjhb	outb(pic->at_ioaddr, OCW3_SEL | OCW3_RR);
430121985Sjhb
431121985Sjhb#ifndef PC98
432122692Sjhb	/* OCW2_L1 sets priority order to 3-7, 0-2 (com2 first). */
433121985Sjhb	if (!slave)
434122692Sjhb		outb(pic->at_ioaddr, OCW2_R | OCW2_SL | OCW2_L1);
435121985Sjhb#endif
436121985Sjhb	mtx_unlock_spin(&icu_lock);
437121985Sjhb}
438121985Sjhb
439121985Sjhbvoid
440121985Sjhbatpic_startup(void)
441121985Sjhb{
442122897Sjhb	struct atpic_intsrc *ai;
443122897Sjhb	int i;
444121985Sjhb
445121985Sjhb	/* Start off with all interrupts disabled. */
446121985Sjhb	imen = 0xffff;
447121985Sjhb	i8259_init(&atpics[MASTER], 0);
448121985Sjhb	i8259_init(&atpics[SLAVE], 1);
449121985Sjhb	atpic_enable_source((struct intsrc *)&atintrs[ICU_SLAVEID]);
450122897Sjhb
451122897Sjhb	/* Install low-level interrupt handlers for all of our IRQs. */
452128875Sjhb	for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) {
453122897Sjhb		if (i == ICU_SLAVEID)
454122897Sjhb			continue;
455122897Sjhb		ai->at_intsrc.is_count = &ai->at_count;
456122897Sjhb		ai->at_intsrc.is_straycount = &ai->at_straycount;
457122897Sjhb		setidt(((struct atpic *)ai->at_intsrc.is_pic)->at_intbase +
458122897Sjhb		    ai->at_irq, ai->at_intr, SDT_SYS386IGT, SEL_KPL,
459122897Sjhb		    GSEL(GCODE_SEL, SEL_KPL));
460122897Sjhb	}
461128929Sjhb
462128929Sjhb#ifdef DEV_MCA
463128929Sjhb	/* For MCA systems, all interrupts are level triggered. */
464128929Sjhb	if (MCA_system)
465128929Sjhb		for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++)
466128929Sjhb			ai->at_trigger = INTR_TRIGGER_LEVEL;
467128929Sjhb	else
468128929Sjhb#endif
469128929Sjhb
470129009Snyan#ifdef PC98
471129009Snyan	for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++)
472129009Snyan		switch (i) {
473129009Snyan		case 0:
474129009Snyan		case 1:
475129009Snyan		case 7:
476129009Snyan		case 8:
477129009Snyan			ai->at_trigger = INTR_TRIGGER_EDGE;
478129009Snyan			break;
479129009Snyan		default:
480129009Snyan			ai->at_trigger = INTR_TRIGGER_LEVEL;
481129009Snyan			break;
482129009Snyan		}
483129009Snyan#else
484128929Sjhb	/*
485128929Sjhb	 * Look for an ELCR.  If we find one, update the trigger modes.
486128929Sjhb	 * If we don't find one, assume that IRQs 0, 1, 2, and 13 are
487128929Sjhb	 * edge triggered and that everything else is level triggered.
488128929Sjhb	 * We only use the trigger information to reprogram the ELCR if
489128929Sjhb	 * we have one and as an optimization to avoid masking edge
490128929Sjhb	 * triggered interrupts.  For the case that we don't have an ELCR,
491128929Sjhb	 * it doesn't hurt to mask an edge triggered interrupt, so we
492129095Sjhb	 * assume level trigger for any interrupt that we aren't sure is
493129095Sjhb	 * edge triggered.
494128929Sjhb	 */
495128929Sjhb	if (elcr_probe() == 0) {
496128929Sjhb		using_elcr = 1;
497128929Sjhb		for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++)
498128929Sjhb			ai->at_trigger = elcr_read_trigger(i);
499128929Sjhb	} else {
500128929Sjhb		for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++)
501128929Sjhb			switch (i) {
502128929Sjhb			case 0:
503128929Sjhb			case 1:
504128929Sjhb			case 2:
505128929Sjhb			case 8:
506128929Sjhb			case 13:
507128929Sjhb				ai->at_trigger = INTR_TRIGGER_EDGE;
508128929Sjhb				break;
509128929Sjhb			default:
510128929Sjhb				ai->at_trigger = INTR_TRIGGER_LEVEL;
511128929Sjhb				break;
512128929Sjhb			}
513128929Sjhb	}
514129009Snyan#endif /* PC98 */
515121985Sjhb}
516121985Sjhb
517121985Sjhbstatic void
518121985Sjhbatpic_init(void *dummy __unused)
519121985Sjhb{
520128875Sjhb	struct atpic_intsrc *ai;
521121985Sjhb	int i;
522121985Sjhb
523121985Sjhb	/* Loop through all interrupt sources and add them. */
524128875Sjhb	for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) {
525121985Sjhb		if (i == ICU_SLAVEID)
526121985Sjhb			continue;
527128875Sjhb		intr_register_source(&ai->at_intsrc);
528121985Sjhb	}
529121985Sjhb}
530121985SjhbSYSINIT(atpic_init, SI_SUB_INTR, SI_ORDER_SECOND + 1, atpic_init, NULL)
531121985Sjhb
532121985Sjhbvoid
533122572Sjhbatpic_handle_intr(struct intrframe iframe)
534121985Sjhb{
535121985Sjhb	struct intsrc *isrc;
536121985Sjhb
537129131Sjhb	KASSERT((u_int)iframe.if_vec < NUM_ISA_IRQS,
538121985Sjhb	    ("unknown int %d\n", iframe.if_vec));
539121985Sjhb	isrc = &atintrs[iframe.if_vec].at_intsrc;
540122898Sjhb
541122898Sjhb	/*
542122898Sjhb	 * If we don't have an ithread, see if this is a spurious
543122898Sjhb	 * interrupt.
544122898Sjhb	 */
545122898Sjhb	if (isrc->is_ithread == NULL &&
546122898Sjhb	    (iframe.if_vec == 7 || iframe.if_vec == 15)) {
547122898Sjhb		int port, isr;
548122898Sjhb
549122898Sjhb		/*
550122898Sjhb		 * Read the ISR register to see if IRQ 7/15 is really
551122898Sjhb		 * pending.  Reset read register back to IRR when done.
552122898Sjhb		 */
553122898Sjhb		port = ((struct atpic *)isrc->is_pic)->at_ioaddr;
554122898Sjhb		mtx_lock_spin(&icu_lock);
555122898Sjhb		outb(port, OCW3_SEL | OCW3_RR | OCW3_RIS);
556122898Sjhb		isr = inb(port);
557122898Sjhb		outb(port, OCW3_SEL | OCW3_RR);
558122898Sjhb		mtx_unlock_spin(&icu_lock);
559129131Sjhb		if ((isr & IRQ_MASK(7)) == 0)
560122898Sjhb			return;
561122898Sjhb	}
562121985Sjhb	intr_execute_handlers(isrc, &iframe);
563121985Sjhb}
564121985Sjhb
565121985Sjhb#ifdef DEV_ISA
566121985Sjhb/*
567121985Sjhb * Bus attachment for the ISA PIC.
568121985Sjhb */
569121985Sjhbstatic struct isa_pnp_id atpic_ids[] = {
570121985Sjhb	{ 0x0000d041 /* PNP0000 */, "AT interrupt controller" },
571121985Sjhb	{ 0 }
572121985Sjhb};
573121985Sjhb
574121985Sjhbstatic int
575121985Sjhbatpic_probe(device_t dev)
576121985Sjhb{
577121985Sjhb	int result;
578121985Sjhb
579121985Sjhb	result = ISA_PNP_PROBE(device_get_parent(dev), dev, atpic_ids);
580121985Sjhb	if (result <= 0)
581121985Sjhb		device_quiet(dev);
582121985Sjhb	return (result);
583121985Sjhb}
584121985Sjhb
585121985Sjhb/*
586121985Sjhb * We might be granted IRQ 2, as this is typically consumed by chaining
587121985Sjhb * between the two PIC components.  If we're using the APIC, however,
588121985Sjhb * this may not be the case, and as such we should free the resource.
589121985Sjhb * (XXX untested)
590121985Sjhb *
591121985Sjhb * The generic ISA attachment code will handle allocating any other resources
592121985Sjhb * that we don't explicitly claim here.
593121985Sjhb */
594121985Sjhbstatic int
595121985Sjhbatpic_attach(device_t dev)
596121985Sjhb{
597121985Sjhb	struct resource *res;
598121985Sjhb	int rid;
599121985Sjhb
600121985Sjhb	/* Try to allocate our IRQ and then free it. */
601121985Sjhb	rid = 0;
602127135Snjl	res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 0);
603121985Sjhb	if (res != NULL)
604121985Sjhb		bus_release_resource(dev, SYS_RES_IRQ, rid, res);
605121985Sjhb	return (0);
606121985Sjhb}
607121985Sjhb
608121985Sjhbstatic device_method_t atpic_methods[] = {
609121985Sjhb	/* Device interface */
610121985Sjhb	DEVMETHOD(device_probe,		atpic_probe),
611121985Sjhb	DEVMETHOD(device_attach,	atpic_attach),
612121985Sjhb	DEVMETHOD(device_detach,	bus_generic_detach),
613121985Sjhb	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
614121985Sjhb	DEVMETHOD(device_suspend,	bus_generic_suspend),
615121985Sjhb	DEVMETHOD(device_resume,	bus_generic_resume),
616121985Sjhb	{ 0, 0 }
617121985Sjhb};
618121985Sjhb
619121985Sjhbstatic driver_t atpic_driver = {
620121985Sjhb	"atpic",
621121985Sjhb	atpic_methods,
622121985Sjhb	1,		/* no softc */
623121985Sjhb};
624121985Sjhb
625121985Sjhbstatic devclass_t atpic_devclass;
626121985Sjhb
627121985SjhbDRIVER_MODULE(atpic, isa, atpic_driver, atpic_devclass, 0, 0);
628122051Snyan#ifndef PC98
629121985SjhbDRIVER_MODULE(atpic, acpi, atpic_driver, atpic_devclass, 0, 0);
630122051Snyan#endif
631121985Sjhb
632121985Sjhb/*
633121985Sjhb * Return a bitmap of the current interrupt requests.  This is 8259-specific
634121985Sjhb * and is only suitable for use at probe time.
635121985Sjhb */
636121985Sjhbintrmask_t
637121985Sjhbisa_irq_pending(void)
638121985Sjhb{
639121985Sjhb	u_char irr1;
640121985Sjhb	u_char irr2;
641121985Sjhb
642121985Sjhb	irr1 = inb(IO_ICU1);
643121985Sjhb	irr2 = inb(IO_ICU2);
644121985Sjhb	return ((irr2 << 8) | irr1);
645121985Sjhb}
646121985Sjhb#endif /* DEV_ISA */
647