atpic.c revision 169391
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 169391 2007-05-08 21:29:14Z 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),		\
128169391Sjhb	    atpic_enable_intr, atpic_disable_intr, atpic_vector,	\
129169391Sjhb	    atpic_source_pending, NULL,	atpic_resume, atpic_config_intr,\
130169391Sjhb	    atpic_assign_cpu }, (io), (base), IDT_IO_INTS + (base),	\
131169391Sjhb	    (imenptr) }
132121985Sjhb
133121985Sjhb#define	INTSRC(irq)							\
134128929Sjhb	{ { &atpics[(irq) / 8].at_pic }, IDTVEC(atpic_intr ## irq ),	\
135128929Sjhb	    (irq) % 8 }
136121985Sjhb
137121985Sjhbstruct atpic {
138121985Sjhb	struct pic at_pic;
139121985Sjhb	int	at_ioaddr;
140121985Sjhb	int	at_irqbase;
141121985Sjhb	uint8_t	at_intbase;
142121985Sjhb	uint8_t	*at_imen;
143121985Sjhb};
144121985Sjhb
145121985Sjhbstruct atpic_intsrc {
146121985Sjhb	struct intsrc at_intsrc;
147121985Sjhb	inthand_t *at_intr;
148128929Sjhb	int	at_irq;			/* Relative to PIC base. */
149128929Sjhb	enum intr_trigger at_trigger;
150122897Sjhb	u_long	at_count;
151122897Sjhb	u_long	at_straycount;
152121985Sjhb};
153121985Sjhb
154121985Sjhbstatic void atpic_enable_source(struct intsrc *isrc);
155133017Sscottlstatic void atpic_disable_source(struct intsrc *isrc, int eoi);
156121985Sjhbstatic void atpic_eoi_master(struct intsrc *isrc);
157121985Sjhbstatic void atpic_eoi_slave(struct intsrc *isrc);
158121985Sjhbstatic void atpic_enable_intr(struct intsrc *isrc);
159169391Sjhbstatic void atpic_disable_intr(struct intsrc *isrc);
160121985Sjhbstatic int atpic_vector(struct intsrc *isrc);
161163219Sjhbstatic void atpic_resume(struct pic *pic);
162121985Sjhbstatic int atpic_source_pending(struct intsrc *isrc);
163128931Sjhbstatic int atpic_config_intr(struct intsrc *isrc, enum intr_trigger trig,
164128931Sjhb    enum intr_polarity pol);
165156124Sjhbstatic void atpic_assign_cpu(struct intsrc *isrc, u_int apic_id);
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
289169391Sjhbstatic void
290169391Sjhbatpic_disable_intr(struct intsrc *isrc)
291169391Sjhb{
292169391Sjhb}
293169391Sjhb
294169391Sjhb
295121985Sjhbstatic int
296121985Sjhbatpic_vector(struct intsrc *isrc)
297121985Sjhb{
298121985Sjhb	struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc;
299121985Sjhb	struct atpic *ap = (struct atpic *)isrc->is_pic;
300121985Sjhb
301121985Sjhb	return (IRQ(ap, ai));
302121985Sjhb}
303121985Sjhb
304121985Sjhbstatic int
305121985Sjhbatpic_source_pending(struct intsrc *isrc)
306121985Sjhb{
307121985Sjhb	struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc;
308121985Sjhb	struct atpic *ap = (struct atpic *)isrc->is_pic;
309121985Sjhb
310128875Sjhb	return (inb(ap->at_ioaddr) & IMEN_MASK(ai));
311121985Sjhb}
312121985Sjhb
313121985Sjhbstatic void
314163219Sjhbatpic_resume(struct pic *pic)
315121985Sjhb{
316163219Sjhb	struct atpic *ap = (struct atpic *)pic;
317121985Sjhb
318163219Sjhb	i8259_init(ap, ap == &atpics[SLAVE]);
319129009Snyan#ifndef PC98
320163219Sjhb	if (ap == &atpics[SLAVE] && elcr_found)
321163219Sjhb		elcr_resume();
322129009Snyan#endif
323121985Sjhb}
324121985Sjhb
325128931Sjhbstatic int
326128931Sjhbatpic_config_intr(struct intsrc *isrc, enum intr_trigger trig,
327128931Sjhb    enum intr_polarity pol)
328128931Sjhb{
329128931Sjhb	struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc;
330128931Sjhb	u_int vector;
331128931Sjhb
332128931Sjhb	/* Map conforming values to edge/hi and sanity check the values. */
333128931Sjhb	if (trig == INTR_TRIGGER_CONFORM)
334128931Sjhb		trig = INTR_TRIGGER_EDGE;
335128931Sjhb	if (pol == INTR_POLARITY_CONFORM)
336128931Sjhb		pol = INTR_POLARITY_HIGH;
337128931Sjhb	vector = atpic_vector(isrc);
338128931Sjhb	if ((trig == INTR_TRIGGER_EDGE && pol == INTR_POLARITY_LOW) ||
339128931Sjhb	    (trig == INTR_TRIGGER_LEVEL && pol == INTR_POLARITY_HIGH)) {
340128931Sjhb		printf(
341128931Sjhb		"atpic: Mismatched config for IRQ%u: trigger %s, polarity %s\n",
342128931Sjhb		    vector, trig == INTR_TRIGGER_EDGE ? "edge" : "level",
343128931Sjhb		    pol == INTR_POLARITY_HIGH ? "high" : "low");
344128931Sjhb		return (EINVAL);
345128931Sjhb	}
346128931Sjhb
347128931Sjhb	/* If there is no change, just return. */
348128931Sjhb	if (ai->at_trigger == trig)
349128931Sjhb		return (0);
350128931Sjhb
351129009Snyan#ifdef PC98
352129009Snyan	if ((vector == 0 || vector == 1 || vector == 7 || vector == 8) &&
353129009Snyan	    trig == INTR_TRIGGER_LEVEL) {
354129009Snyan		if (bootverbose)
355129009Snyan			printf(
356129009Snyan		"atpic: Ignoring invalid level/low configuration for IRQ%u\n",
357129009Snyan			    vector);
358129009Snyan		return (EINVAL);
359129009Snyan	}
360129009Snyan	return (ENXIO);
361129009Snyan#else
362128931Sjhb	/*
363128931Sjhb	 * Certain IRQs can never be level/lo, so don't try to set them
364128931Sjhb	 * that way if asked.  At least some ELCR registers ignore setting
365128931Sjhb	 * these bits as well.
366128931Sjhb	 */
367128931Sjhb	if ((vector == 0 || vector == 1 || vector == 2 || vector == 13) &&
368128931Sjhb	    trig == INTR_TRIGGER_LEVEL) {
369128931Sjhb		if (bootverbose)
370128931Sjhb			printf(
371128931Sjhb		"atpic: Ignoring invalid level/low configuration for IRQ%u\n",
372128931Sjhb			    vector);
373128931Sjhb		return (EINVAL);
374128931Sjhb	}
375140451Sjhb	if (!elcr_found) {
376128931Sjhb		if (bootverbose)
377128931Sjhb			printf("atpic: No ELCR to configure IRQ%u as %s\n",
378128931Sjhb			    vector, trig == INTR_TRIGGER_EDGE ? "edge/high" :
379128931Sjhb			    "level/low");
380128931Sjhb		return (ENXIO);
381128931Sjhb	}
382128931Sjhb	if (bootverbose)
383128931Sjhb		printf("atpic: Programming IRQ%u as %s\n", vector,
384128931Sjhb		    trig == INTR_TRIGGER_EDGE ? "edge/high" : "level/low");
385128931Sjhb	mtx_lock_spin(&icu_lock);
386128931Sjhb	elcr_write_trigger(atpic_vector(isrc), trig);
387128931Sjhb	ai->at_trigger = trig;
388128931Sjhb	mtx_unlock_spin(&icu_lock);
389128931Sjhb	return (0);
390129009Snyan#endif /* PC98 */
391128931Sjhb}
392128931Sjhb
393121985Sjhbstatic void
394156124Sjhbatpic_assign_cpu(struct intsrc *isrc, u_int apic_id)
395156124Sjhb{
396156124Sjhb
397156124Sjhb	/*
398156124Sjhb	 * 8259A's are only used in UP in which case all interrupts always
399156124Sjhb	 * go to the sole CPU and this function shouldn't even be called.
400156124Sjhb	 */
401156124Sjhb	panic("%s: bad cookie", __func__);
402156124Sjhb}
403156124Sjhb
404156124Sjhbstatic void
405121985Sjhbi8259_init(struct atpic *pic, int slave)
406121985Sjhb{
407121985Sjhb	int imr_addr;
408121985Sjhb
409121985Sjhb	/* Reset the PIC and program with next four bytes. */
410121985Sjhb	mtx_lock_spin(&icu_lock);
411121985Sjhb#ifdef DEV_MCA
412122692Sjhb	/* MCA uses level triggered interrupts. */
413121985Sjhb	if (MCA_system)
414122692Sjhb		outb(pic->at_ioaddr, ICW1_RESET | ICW1_IC4 | ICW1_LTIM);
415121985Sjhb	else
416121985Sjhb#endif
417122692Sjhb		outb(pic->at_ioaddr, ICW1_RESET | ICW1_IC4);
418121985Sjhb	imr_addr = pic->at_ioaddr + ICU_IMR_OFFSET;
419121985Sjhb
420121985Sjhb	/* Start vector. */
421121985Sjhb	outb(imr_addr, pic->at_intbase);
422121985Sjhb
423121985Sjhb	/*
424121985Sjhb	 * Setup slave links.  For the master pic, indicate what line
425121985Sjhb	 * the slave is configured on.  For the slave indicate
426121985Sjhb	 * which line on the master we are connected to.
427121985Sjhb	 */
428121985Sjhb	if (slave)
429129131Sjhb		outb(imr_addr, ICU_SLAVEID);
430121985Sjhb	else
431129131Sjhb		outb(imr_addr, IRQ_MASK(ICU_SLAVEID));
432121985Sjhb
433121985Sjhb	/* Set mode. */
434121985Sjhb	if (slave)
435121985Sjhb		outb(imr_addr, SLAVE_MODE);
436121985Sjhb	else
437121985Sjhb		outb(imr_addr, MASTER_MODE);
438121985Sjhb
439121985Sjhb	/* Set interrupt enable mask. */
440121985Sjhb	outb(imr_addr, *pic->at_imen);
441121985Sjhb
442121985Sjhb	/* Reset is finished, default to IRR on read. */
443122692Sjhb	outb(pic->at_ioaddr, OCW3_SEL | OCW3_RR);
444121985Sjhb
445121985Sjhb#ifndef PC98
446122692Sjhb	/* OCW2_L1 sets priority order to 3-7, 0-2 (com2 first). */
447121985Sjhb	if (!slave)
448122692Sjhb		outb(pic->at_ioaddr, OCW2_R | OCW2_SL | OCW2_L1);
449121985Sjhb#endif
450121985Sjhb	mtx_unlock_spin(&icu_lock);
451121985Sjhb}
452121985Sjhb
453121985Sjhbvoid
454121985Sjhbatpic_startup(void)
455121985Sjhb{
456122897Sjhb	struct atpic_intsrc *ai;
457122897Sjhb	int i;
458121985Sjhb
459121985Sjhb	/* Start off with all interrupts disabled. */
460121985Sjhb	imen = 0xffff;
461121985Sjhb	i8259_init(&atpics[MASTER], 0);
462121985Sjhb	i8259_init(&atpics[SLAVE], 1);
463121985Sjhb	atpic_enable_source((struct intsrc *)&atintrs[ICU_SLAVEID]);
464122897Sjhb
465122897Sjhb	/* Install low-level interrupt handlers for all of our IRQs. */
466128875Sjhb	for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) {
467122897Sjhb		if (i == ICU_SLAVEID)
468122897Sjhb			continue;
469122897Sjhb		ai->at_intsrc.is_count = &ai->at_count;
470122897Sjhb		ai->at_intsrc.is_straycount = &ai->at_straycount;
471122897Sjhb		setidt(((struct atpic *)ai->at_intsrc.is_pic)->at_intbase +
472122897Sjhb		    ai->at_irq, ai->at_intr, SDT_SYS386IGT, SEL_KPL,
473122897Sjhb		    GSEL(GCODE_SEL, SEL_KPL));
474122897Sjhb	}
475128929Sjhb
476128929Sjhb#ifdef DEV_MCA
477128929Sjhb	/* For MCA systems, all interrupts are level triggered. */
478128929Sjhb	if (MCA_system)
479128929Sjhb		for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++)
480128929Sjhb			ai->at_trigger = INTR_TRIGGER_LEVEL;
481128929Sjhb	else
482128929Sjhb#endif
483128929Sjhb
484129009Snyan#ifdef PC98
485129009Snyan	for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++)
486129009Snyan		switch (i) {
487129009Snyan		case 0:
488129009Snyan		case 1:
489129009Snyan		case 7:
490129009Snyan		case 8:
491129009Snyan			ai->at_trigger = INTR_TRIGGER_EDGE;
492129009Snyan			break;
493129009Snyan		default:
494129009Snyan			ai->at_trigger = INTR_TRIGGER_LEVEL;
495129009Snyan			break;
496129009Snyan		}
497129009Snyan#else
498128929Sjhb	/*
499128929Sjhb	 * Look for an ELCR.  If we find one, update the trigger modes.
500128929Sjhb	 * If we don't find one, assume that IRQs 0, 1, 2, and 13 are
501128929Sjhb	 * edge triggered and that everything else is level triggered.
502128929Sjhb	 * We only use the trigger information to reprogram the ELCR if
503128929Sjhb	 * we have one and as an optimization to avoid masking edge
504128929Sjhb	 * triggered interrupts.  For the case that we don't have an ELCR,
505128929Sjhb	 * it doesn't hurt to mask an edge triggered interrupt, so we
506129095Sjhb	 * assume level trigger for any interrupt that we aren't sure is
507129095Sjhb	 * edge triggered.
508128929Sjhb	 */
509140451Sjhb	if (elcr_found) {
510128929Sjhb		for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++)
511128929Sjhb			ai->at_trigger = elcr_read_trigger(i);
512128929Sjhb	} else {
513128929Sjhb		for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++)
514128929Sjhb			switch (i) {
515128929Sjhb			case 0:
516128929Sjhb			case 1:
517128929Sjhb			case 2:
518128929Sjhb			case 8:
519128929Sjhb			case 13:
520128929Sjhb				ai->at_trigger = INTR_TRIGGER_EDGE;
521128929Sjhb				break;
522128929Sjhb			default:
523128929Sjhb				ai->at_trigger = INTR_TRIGGER_LEVEL;
524128929Sjhb				break;
525128929Sjhb			}
526128929Sjhb	}
527129009Snyan#endif /* PC98 */
528121985Sjhb}
529121985Sjhb
530121985Sjhbstatic void
531121985Sjhbatpic_init(void *dummy __unused)
532121985Sjhb{
533128875Sjhb	struct atpic_intsrc *ai;
534121985Sjhb	int i;
535121985Sjhb
536153136Sjhb	/*
537163219Sjhb	 * Register our PICs, even if we aren't going to use any of their
538163219Sjhb	 * pins so that they are suspended and resumed.
539163219Sjhb	 */
540163219Sjhb	if (intr_register_pic(&atpics[0].at_pic) != 0 ||
541163219Sjhb	    intr_register_pic(&atpics[1].at_pic) != 0)
542163219Sjhb		panic("Unable to register ATPICs");
543163219Sjhb
544163219Sjhb	/*
545153136Sjhb	 * If any of the ISA IRQs have an interrupt source already, then
546153136Sjhb	 * assume that the APICs are being used and don't register any
547153136Sjhb	 * of our interrupt sources.  This makes sure we don't accidentally
548153136Sjhb	 * use mixed mode.  The "accidental" use could otherwise occur on
549153136Sjhb	 * machines that route the ACPI SCI interrupt to a different ISA
550153136Sjhb	 * IRQ (at least one machines routes it to IRQ 13) thus disabling
551153136Sjhb	 * that APIC ISA routing and allowing the ATPIC source for that IRQ
552153136Sjhb	 * to leak through.  We used to depend on this feature for routing
553153136Sjhb	 * IRQ0 via mixed mode, but now we don't use mixed mode at all.
554153136Sjhb	 */
555153136Sjhb	for (i = 0; i < NUM_ISA_IRQS; i++)
556153136Sjhb		if (intr_lookup_source(i) != NULL)
557153136Sjhb			return;
558153136Sjhb
559121985Sjhb	/* Loop through all interrupt sources and add them. */
560128875Sjhb	for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) {
561121985Sjhb		if (i == ICU_SLAVEID)
562121985Sjhb			continue;
563128875Sjhb		intr_register_source(&ai->at_intsrc);
564121985Sjhb	}
565121985Sjhb}
566121985SjhbSYSINIT(atpic_init, SI_SUB_INTR, SI_ORDER_SECOND + 1, atpic_init, NULL)
567121985Sjhb
568121985Sjhbvoid
569165302Skmacyatpic_handle_intr(u_int vector, struct trapframe *frame)
570121985Sjhb{
571121985Sjhb	struct intsrc *isrc;
572121985Sjhb
573153242Sjhb	KASSERT(vector < NUM_ISA_IRQS, ("unknown int %u\n", vector));
574153146Sjhb	isrc = &atintrs[vector].at_intsrc;
575122898Sjhb
576122898Sjhb	/*
577151658Sjhb	 * If we don't have an event, see if this is a spurious
578122898Sjhb	 * interrupt.
579122898Sjhb	 */
580153146Sjhb	if (isrc->is_event == NULL && (vector == 7 || vector == 15)) {
581122898Sjhb		int port, isr;
582122898Sjhb
583122898Sjhb		/*
584122898Sjhb		 * Read the ISR register to see if IRQ 7/15 is really
585122898Sjhb		 * pending.  Reset read register back to IRR when done.
586122898Sjhb		 */
587122898Sjhb		port = ((struct atpic *)isrc->is_pic)->at_ioaddr;
588122898Sjhb		mtx_lock_spin(&icu_lock);
589122898Sjhb		outb(port, OCW3_SEL | OCW3_RR | OCW3_RIS);
590122898Sjhb		isr = inb(port);
591122898Sjhb		outb(port, OCW3_SEL | OCW3_RR);
592122898Sjhb		mtx_unlock_spin(&icu_lock);
593129131Sjhb		if ((isr & IRQ_MASK(7)) == 0)
594122898Sjhb			return;
595122898Sjhb	}
596165302Skmacy	intr_execute_handlers(isrc, frame);
597121985Sjhb}
598121985Sjhb
599121985Sjhb#ifdef DEV_ISA
600121985Sjhb/*
601121985Sjhb * Bus attachment for the ISA PIC.
602121985Sjhb */
603121985Sjhbstatic struct isa_pnp_id atpic_ids[] = {
604121985Sjhb	{ 0x0000d041 /* PNP0000 */, "AT interrupt controller" },
605121985Sjhb	{ 0 }
606121985Sjhb};
607121985Sjhb
608121985Sjhbstatic int
609121985Sjhbatpic_probe(device_t dev)
610121985Sjhb{
611121985Sjhb	int result;
612121985Sjhb
613121985Sjhb	result = ISA_PNP_PROBE(device_get_parent(dev), dev, atpic_ids);
614121985Sjhb	if (result <= 0)
615121985Sjhb		device_quiet(dev);
616121985Sjhb	return (result);
617121985Sjhb}
618121985Sjhb
619121985Sjhb/*
620121985Sjhb * We might be granted IRQ 2, as this is typically consumed by chaining
621121985Sjhb * between the two PIC components.  If we're using the APIC, however,
622121985Sjhb * this may not be the case, and as such we should free the resource.
623121985Sjhb * (XXX untested)
624121985Sjhb *
625121985Sjhb * The generic ISA attachment code will handle allocating any other resources
626121985Sjhb * that we don't explicitly claim here.
627121985Sjhb */
628121985Sjhbstatic int
629121985Sjhbatpic_attach(device_t dev)
630121985Sjhb{
631121985Sjhb	struct resource *res;
632121985Sjhb	int rid;
633121985Sjhb
634121985Sjhb	/* Try to allocate our IRQ and then free it. */
635121985Sjhb	rid = 0;
636127135Snjl	res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 0);
637121985Sjhb	if (res != NULL)
638121985Sjhb		bus_release_resource(dev, SYS_RES_IRQ, rid, res);
639121985Sjhb	return (0);
640121985Sjhb}
641121985Sjhb
642121985Sjhbstatic device_method_t atpic_methods[] = {
643121985Sjhb	/* Device interface */
644121985Sjhb	DEVMETHOD(device_probe,		atpic_probe),
645121985Sjhb	DEVMETHOD(device_attach,	atpic_attach),
646121985Sjhb	DEVMETHOD(device_detach,	bus_generic_detach),
647121985Sjhb	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
648121985Sjhb	DEVMETHOD(device_suspend,	bus_generic_suspend),
649121985Sjhb	DEVMETHOD(device_resume,	bus_generic_resume),
650121985Sjhb	{ 0, 0 }
651121985Sjhb};
652121985Sjhb
653121985Sjhbstatic driver_t atpic_driver = {
654121985Sjhb	"atpic",
655121985Sjhb	atpic_methods,
656121985Sjhb	1,		/* no softc */
657121985Sjhb};
658121985Sjhb
659121985Sjhbstatic devclass_t atpic_devclass;
660121985Sjhb
661121985SjhbDRIVER_MODULE(atpic, isa, atpic_driver, atpic_devclass, 0, 0);
662122051Snyan#ifndef PC98
663121985SjhbDRIVER_MODULE(atpic, acpi, atpic_driver, atpic_devclass, 0, 0);
664122051Snyan#endif
665121985Sjhb
666121985Sjhb/*
667121985Sjhb * Return a bitmap of the current interrupt requests.  This is 8259-specific
668121985Sjhb * and is only suitable for use at probe time.
669121985Sjhb */
670121985Sjhbintrmask_t
671121985Sjhbisa_irq_pending(void)
672121985Sjhb{
673121985Sjhb	u_char irr1;
674121985Sjhb	u_char irr2;
675121985Sjhb
676121985Sjhb	irr1 = inb(IO_ICU1);
677121985Sjhb	irr2 = inb(IO_ICU2);
678121985Sjhb	return ((irr2 << 8) | irr1);
679121985Sjhb}
680121985Sjhb#endif /* DEV_ISA */
681