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 *
14121985Sjhb * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15121985Sjhb * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16121985Sjhb * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17121985Sjhb * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18121985Sjhb * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19121985Sjhb * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20121985Sjhb * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21121985Sjhb * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22121985Sjhb * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23121985Sjhb * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24121985Sjhb * SUCH DAMAGE.
25121985Sjhb */
26121985Sjhb
27121985Sjhb/*
28121985Sjhb * PIC driver for the 8259A Master and Slave PICs in PC/AT machines.
29121985Sjhb */
30121985Sjhb
31121985Sjhb#include <sys/cdefs.h>
32121985Sjhb__FBSDID("$FreeBSD: releng/10.3/sys/x86/isa/atpic.c 262192 2014-02-18 20:27:17Z jhb $");
33121985Sjhb
34121985Sjhb#include "opt_auto_eoi.h"
35121985Sjhb#include "opt_isa.h"
36121985Sjhb
37121985Sjhb#include <sys/param.h>
38121985Sjhb#include <sys/systm.h>
39121985Sjhb#include <sys/bus.h>
40121985Sjhb#include <sys/interrupt.h>
41121985Sjhb#include <sys/kernel.h>
42121985Sjhb#include <sys/lock.h>
43129876Sphk#include <sys/module.h>
44121985Sjhb
45121985Sjhb#include <machine/cpufunc.h>
46121985Sjhb#include <machine/frame.h>
47121985Sjhb#include <machine/intr_machdep.h>
48121985Sjhb#include <machine/md_var.h>
49121985Sjhb#include <machine/resource.h>
50121985Sjhb#include <machine/segments.h>
51121985Sjhb
52124188Sjhb#include <dev/ic/i8259.h>
53204309Sattilio#include <x86/isa/icu.h>
54122051Snyan#ifdef PC98
55146049Snyan#include <pc98/cbus/cbus.h>
56122051Snyan#else
57204309Sattilio#include <x86/isa/isa.h>
58122051Snyan#endif
59121985Sjhb#include <isa/isavar.h>
60121985Sjhb
61204309Sattilio#ifdef __amd64__
62204309Sattilio#define	SDT_ATPIC	SDT_SYSIGT
63204309Sattilio#define	GSEL_ATPIC	0
64204309Sattilio#else
65204309Sattilio#define	SDT_ATPIC	SDT_SYS386IGT
66204309Sattilio#define	GSEL_ATPIC	GSEL(GCODE_SEL, SEL_KPL)
67204309Sattilio#endif
68204309Sattilio
69121985Sjhb#define	MASTER	0
70121985Sjhb#define	SLAVE	1
71121985Sjhb
72128875Sjhb#define	NUM_ISA_IRQS		16
73128875Sjhb
74121985Sjhbstatic void	atpic_init(void *dummy);
75121985Sjhb
76121985Sjhbunsigned int imen;	/* XXX */
77121985Sjhb
78121985Sjhbinthand_t
79121985Sjhb	IDTVEC(atpic_intr0), IDTVEC(atpic_intr1), IDTVEC(atpic_intr2),
80121985Sjhb	IDTVEC(atpic_intr3), IDTVEC(atpic_intr4), IDTVEC(atpic_intr5),
81121985Sjhb	IDTVEC(atpic_intr6), IDTVEC(atpic_intr7), IDTVEC(atpic_intr8),
82121985Sjhb	IDTVEC(atpic_intr9), IDTVEC(atpic_intr10), IDTVEC(atpic_intr11),
83121985Sjhb	IDTVEC(atpic_intr12), IDTVEC(atpic_intr13), IDTVEC(atpic_intr14),
84121985Sjhb	IDTVEC(atpic_intr15);
85121985Sjhb
86121985Sjhb#define	IRQ(ap, ai)	((ap)->at_irqbase + (ai)->at_irq)
87121985Sjhb
88128929Sjhb#define	ATPIC(io, base, eoi, imenptr)					\
89121985Sjhb     	{ { atpic_enable_source, atpic_disable_source, (eoi),		\
90169391Sjhb	    atpic_enable_intr, atpic_disable_intr, atpic_vector,	\
91169391Sjhb	    atpic_source_pending, NULL,	atpic_resume, atpic_config_intr,\
92169391Sjhb	    atpic_assign_cpu }, (io), (base), IDT_IO_INTS + (base),	\
93169391Sjhb	    (imenptr) }
94121985Sjhb
95121985Sjhb#define	INTSRC(irq)							\
96128929Sjhb	{ { &atpics[(irq) / 8].at_pic }, IDTVEC(atpic_intr ## irq ),	\
97128929Sjhb	    (irq) % 8 }
98121985Sjhb
99121985Sjhbstruct atpic {
100121985Sjhb	struct pic at_pic;
101121985Sjhb	int	at_ioaddr;
102121985Sjhb	int	at_irqbase;
103121985Sjhb	uint8_t	at_intbase;
104121985Sjhb	uint8_t	*at_imen;
105121985Sjhb};
106121985Sjhb
107121985Sjhbstruct atpic_intsrc {
108121985Sjhb	struct intsrc at_intsrc;
109121985Sjhb	inthand_t *at_intr;
110128929Sjhb	int	at_irq;			/* Relative to PIC base. */
111128929Sjhb	enum intr_trigger at_trigger;
112122897Sjhb	u_long	at_count;
113122897Sjhb	u_long	at_straycount;
114121985Sjhb};
115121985Sjhb
116121985Sjhbstatic void atpic_enable_source(struct intsrc *isrc);
117133017Sscottlstatic void atpic_disable_source(struct intsrc *isrc, int eoi);
118121985Sjhbstatic void atpic_eoi_master(struct intsrc *isrc);
119121985Sjhbstatic void atpic_eoi_slave(struct intsrc *isrc);
120121985Sjhbstatic void atpic_enable_intr(struct intsrc *isrc);
121169391Sjhbstatic void atpic_disable_intr(struct intsrc *isrc);
122121985Sjhbstatic int atpic_vector(struct intsrc *isrc);
123255726Sgibbsstatic void atpic_resume(struct pic *pic, bool suspend_cancelled);
124121985Sjhbstatic int atpic_source_pending(struct intsrc *isrc);
125128931Sjhbstatic int atpic_config_intr(struct intsrc *isrc, enum intr_trigger trig,
126128931Sjhb    enum intr_polarity pol);
127195249Sjhbstatic int atpic_assign_cpu(struct intsrc *isrc, u_int apic_id);
128121985Sjhbstatic void i8259_init(struct atpic *pic, int slave);
129121985Sjhb
130121985Sjhbstatic struct atpic atpics[] = {
131121985Sjhb	ATPIC(IO_ICU1, 0, atpic_eoi_master, (uint8_t *)&imen),
132121985Sjhb	ATPIC(IO_ICU2, 8, atpic_eoi_slave, ((uint8_t *)&imen) + 1)
133121985Sjhb};
134121985Sjhb
135121985Sjhbstatic struct atpic_intsrc atintrs[] = {
136121985Sjhb	INTSRC(0),
137121985Sjhb	INTSRC(1),
138121985Sjhb	INTSRC(2),
139121985Sjhb	INTSRC(3),
140121985Sjhb	INTSRC(4),
141121985Sjhb	INTSRC(5),
142121985Sjhb	INTSRC(6),
143121985Sjhb	INTSRC(7),
144121985Sjhb	INTSRC(8),
145121985Sjhb	INTSRC(9),
146121985Sjhb	INTSRC(10),
147121985Sjhb	INTSRC(11),
148121985Sjhb	INTSRC(12),
149121985Sjhb	INTSRC(13),
150121985Sjhb	INTSRC(14),
151121985Sjhb	INTSRC(15),
152121985Sjhb};
153121985Sjhb
154129095SjhbCTASSERT(sizeof(atintrs) / sizeof(atintrs[0]) == NUM_ISA_IRQS);
155128875Sjhb
156133017Sscottlstatic __inline void
157133017Sscottl_atpic_eoi_master(struct intsrc *isrc)
158133017Sscottl{
159133017Sscottl
160133017Sscottl	KASSERT(isrc->is_pic == &atpics[MASTER].at_pic,
161133017Sscottl	    ("%s: mismatched pic", __func__));
162133017Sscottl#ifndef AUTO_EOI_1
163133017Sscottl	outb(atpics[MASTER].at_ioaddr, OCW2_EOI);
164133017Sscottl#endif
165133017Sscottl}
166133017Sscottl
167133017Sscottl/*
168133017Sscottl * The data sheet says no auto-EOI on slave, but it sometimes works.
169133017Sscottl * So, if AUTO_EOI_2 is enabled, we use it.
170133017Sscottl */
171133017Sscottlstatic __inline void
172133017Sscottl_atpic_eoi_slave(struct intsrc *isrc)
173133017Sscottl{
174133017Sscottl
175133017Sscottl	KASSERT(isrc->is_pic == &atpics[SLAVE].at_pic,
176133017Sscottl	    ("%s: mismatched pic", __func__));
177133017Sscottl#ifndef AUTO_EOI_2
178133017Sscottl	outb(atpics[SLAVE].at_ioaddr, OCW2_EOI);
179133017Sscottl#ifndef AUTO_EOI_1
180133017Sscottl	outb(atpics[MASTER].at_ioaddr, OCW2_EOI);
181133017Sscottl#endif
182133017Sscottl#endif
183133017Sscottl}
184133017Sscottl
185121985Sjhbstatic void
186121985Sjhbatpic_enable_source(struct intsrc *isrc)
187121985Sjhb{
188121985Sjhb	struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc;
189121985Sjhb	struct atpic *ap = (struct atpic *)isrc->is_pic;
190121985Sjhb
191177468Sjhb	spinlock_enter();
192128875Sjhb	if (*ap->at_imen & IMEN_MASK(ai)) {
193128875Sjhb		*ap->at_imen &= ~IMEN_MASK(ai);
194128875Sjhb		outb(ap->at_ioaddr + ICU_IMR_OFFSET, *ap->at_imen);
195128875Sjhb	}
196177468Sjhb	spinlock_exit();
197121985Sjhb}
198121985Sjhb
199121985Sjhbstatic void
200133017Sscottlatpic_disable_source(struct intsrc *isrc, int eoi)
201121985Sjhb{
202121985Sjhb	struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc;
203121985Sjhb	struct atpic *ap = (struct atpic *)isrc->is_pic;
204121985Sjhb
205177468Sjhb	spinlock_enter();
206133017Sscottl	if (ai->at_trigger != INTR_TRIGGER_EDGE) {
207133017Sscottl		*ap->at_imen |= IMEN_MASK(ai);
208133017Sscottl		outb(ap->at_ioaddr + ICU_IMR_OFFSET, *ap->at_imen);
209133017Sscottl	}
210133017Sscottl
211133017Sscottl	/*
212133017Sscottl	 * Take care to call these functions directly instead of through
213133017Sscottl	 * a function pointer.  All of the referenced variables should
214133017Sscottl	 * still be hot in the cache.
215133017Sscottl	 */
216133017Sscottl	if (eoi == PIC_EOI) {
217133017Sscottl		if (isrc->is_pic == &atpics[MASTER].at_pic)
218133017Sscottl			_atpic_eoi_master(isrc);
219133017Sscottl		else
220133017Sscottl			_atpic_eoi_slave(isrc);
221133017Sscottl	}
222133017Sscottl
223177468Sjhb	spinlock_exit();
224121985Sjhb}
225121985Sjhb
226121985Sjhbstatic void
227121985Sjhbatpic_eoi_master(struct intsrc *isrc)
228121985Sjhb{
229121985Sjhb#ifndef AUTO_EOI_1
230177468Sjhb	spinlock_enter();
231133017Sscottl	_atpic_eoi_master(isrc);
232177468Sjhb	spinlock_exit();
233121985Sjhb#endif
234121985Sjhb}
235121985Sjhb
236121985Sjhbstatic void
237121985Sjhbatpic_eoi_slave(struct intsrc *isrc)
238121985Sjhb{
239121985Sjhb#ifndef AUTO_EOI_2
240177468Sjhb	spinlock_enter();
241133017Sscottl	_atpic_eoi_slave(isrc);
242177468Sjhb	spinlock_exit();
243121985Sjhb#endif
244121985Sjhb}
245121985Sjhb
246121985Sjhbstatic void
247121985Sjhbatpic_enable_intr(struct intsrc *isrc)
248121985Sjhb{
249121985Sjhb}
250121985Sjhb
251169391Sjhbstatic void
252169391Sjhbatpic_disable_intr(struct intsrc *isrc)
253169391Sjhb{
254169391Sjhb}
255169391Sjhb
256169391Sjhb
257121985Sjhbstatic int
258121985Sjhbatpic_vector(struct intsrc *isrc)
259121985Sjhb{
260121985Sjhb	struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc;
261121985Sjhb	struct atpic *ap = (struct atpic *)isrc->is_pic;
262121985Sjhb
263121985Sjhb	return (IRQ(ap, ai));
264121985Sjhb}
265121985Sjhb
266121985Sjhbstatic int
267121985Sjhbatpic_source_pending(struct intsrc *isrc)
268121985Sjhb{
269121985Sjhb	struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc;
270121985Sjhb	struct atpic *ap = (struct atpic *)isrc->is_pic;
271121985Sjhb
272128875Sjhb	return (inb(ap->at_ioaddr) & IMEN_MASK(ai));
273121985Sjhb}
274121985Sjhb
275121985Sjhbstatic void
276255726Sgibbsatpic_resume(struct pic *pic, bool suspend_cancelled)
277121985Sjhb{
278163219Sjhb	struct atpic *ap = (struct atpic *)pic;
279121985Sjhb
280163219Sjhb	i8259_init(ap, ap == &atpics[SLAVE]);
281129009Snyan#ifndef PC98
282163219Sjhb	if (ap == &atpics[SLAVE] && elcr_found)
283163219Sjhb		elcr_resume();
284129009Snyan#endif
285121985Sjhb}
286121985Sjhb
287128931Sjhbstatic int
288128931Sjhbatpic_config_intr(struct intsrc *isrc, enum intr_trigger trig,
289128931Sjhb    enum intr_polarity pol)
290128931Sjhb{
291128931Sjhb	struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc;
292128931Sjhb	u_int vector;
293128931Sjhb
294128931Sjhb	/* Map conforming values to edge/hi and sanity check the values. */
295128931Sjhb	if (trig == INTR_TRIGGER_CONFORM)
296128931Sjhb		trig = INTR_TRIGGER_EDGE;
297128931Sjhb	if (pol == INTR_POLARITY_CONFORM)
298128931Sjhb		pol = INTR_POLARITY_HIGH;
299128931Sjhb	vector = atpic_vector(isrc);
300128931Sjhb	if ((trig == INTR_TRIGGER_EDGE && pol == INTR_POLARITY_LOW) ||
301128931Sjhb	    (trig == INTR_TRIGGER_LEVEL && pol == INTR_POLARITY_HIGH)) {
302128931Sjhb		printf(
303128931Sjhb		"atpic: Mismatched config for IRQ%u: trigger %s, polarity %s\n",
304128931Sjhb		    vector, trig == INTR_TRIGGER_EDGE ? "edge" : "level",
305128931Sjhb		    pol == INTR_POLARITY_HIGH ? "high" : "low");
306128931Sjhb		return (EINVAL);
307128931Sjhb	}
308128931Sjhb
309128931Sjhb	/* If there is no change, just return. */
310128931Sjhb	if (ai->at_trigger == trig)
311128931Sjhb		return (0);
312128931Sjhb
313129009Snyan#ifdef PC98
314129009Snyan	if ((vector == 0 || vector == 1 || vector == 7 || vector == 8) &&
315129009Snyan	    trig == INTR_TRIGGER_LEVEL) {
316129009Snyan		if (bootverbose)
317129009Snyan			printf(
318129009Snyan		"atpic: Ignoring invalid level/low configuration for IRQ%u\n",
319129009Snyan			    vector);
320129009Snyan		return (EINVAL);
321129009Snyan	}
322129009Snyan	return (ENXIO);
323129009Snyan#else
324128931Sjhb	/*
325128931Sjhb	 * Certain IRQs can never be level/lo, so don't try to set them
326128931Sjhb	 * that way if asked.  At least some ELCR registers ignore setting
327128931Sjhb	 * these bits as well.
328128931Sjhb	 */
329128931Sjhb	if ((vector == 0 || vector == 1 || vector == 2 || vector == 13) &&
330128931Sjhb	    trig == INTR_TRIGGER_LEVEL) {
331128931Sjhb		if (bootverbose)
332128931Sjhb			printf(
333128931Sjhb		"atpic: Ignoring invalid level/low configuration for IRQ%u\n",
334128931Sjhb			    vector);
335128931Sjhb		return (EINVAL);
336128931Sjhb	}
337140451Sjhb	if (!elcr_found) {
338128931Sjhb		if (bootverbose)
339128931Sjhb			printf("atpic: No ELCR to configure IRQ%u as %s\n",
340128931Sjhb			    vector, trig == INTR_TRIGGER_EDGE ? "edge/high" :
341128931Sjhb			    "level/low");
342128931Sjhb		return (ENXIO);
343128931Sjhb	}
344128931Sjhb	if (bootverbose)
345128931Sjhb		printf("atpic: Programming IRQ%u as %s\n", vector,
346128931Sjhb		    trig == INTR_TRIGGER_EDGE ? "edge/high" : "level/low");
347177468Sjhb	spinlock_enter();
348128931Sjhb	elcr_write_trigger(atpic_vector(isrc), trig);
349128931Sjhb	ai->at_trigger = trig;
350177468Sjhb	spinlock_exit();
351128931Sjhb	return (0);
352129009Snyan#endif /* PC98 */
353128931Sjhb}
354128931Sjhb
355195249Sjhbstatic int
356156124Sjhbatpic_assign_cpu(struct intsrc *isrc, u_int apic_id)
357156124Sjhb{
358156124Sjhb
359156124Sjhb	/*
360156124Sjhb	 * 8259A's are only used in UP in which case all interrupts always
361156124Sjhb	 * go to the sole CPU and this function shouldn't even be called.
362156124Sjhb	 */
363156124Sjhb	panic("%s: bad cookie", __func__);
364156124Sjhb}
365156124Sjhb
366156124Sjhbstatic void
367121985Sjhbi8259_init(struct atpic *pic, int slave)
368121985Sjhb{
369121985Sjhb	int imr_addr;
370121985Sjhb
371121985Sjhb	/* Reset the PIC and program with next four bytes. */
372177468Sjhb	spinlock_enter();
373121985Sjhb#ifdef DEV_MCA
374122692Sjhb	/* MCA uses level triggered interrupts. */
375121985Sjhb	if (MCA_system)
376122692Sjhb		outb(pic->at_ioaddr, ICW1_RESET | ICW1_IC4 | ICW1_LTIM);
377121985Sjhb	else
378121985Sjhb#endif
379122692Sjhb		outb(pic->at_ioaddr, ICW1_RESET | ICW1_IC4);
380121985Sjhb	imr_addr = pic->at_ioaddr + ICU_IMR_OFFSET;
381121985Sjhb
382121985Sjhb	/* Start vector. */
383121985Sjhb	outb(imr_addr, pic->at_intbase);
384121985Sjhb
385121985Sjhb	/*
386121985Sjhb	 * Setup slave links.  For the master pic, indicate what line
387121985Sjhb	 * the slave is configured on.  For the slave indicate
388121985Sjhb	 * which line on the master we are connected to.
389121985Sjhb	 */
390121985Sjhb	if (slave)
391129131Sjhb		outb(imr_addr, ICU_SLAVEID);
392121985Sjhb	else
393129131Sjhb		outb(imr_addr, IRQ_MASK(ICU_SLAVEID));
394121985Sjhb
395121985Sjhb	/* Set mode. */
396121985Sjhb	if (slave)
397121985Sjhb		outb(imr_addr, SLAVE_MODE);
398121985Sjhb	else
399121985Sjhb		outb(imr_addr, MASTER_MODE);
400121985Sjhb
401121985Sjhb	/* Set interrupt enable mask. */
402121985Sjhb	outb(imr_addr, *pic->at_imen);
403121985Sjhb
404121985Sjhb	/* Reset is finished, default to IRR on read. */
405122692Sjhb	outb(pic->at_ioaddr, OCW3_SEL | OCW3_RR);
406121985Sjhb
407121985Sjhb#ifndef PC98
408122692Sjhb	/* OCW2_L1 sets priority order to 3-7, 0-2 (com2 first). */
409121985Sjhb	if (!slave)
410122692Sjhb		outb(pic->at_ioaddr, OCW2_R | OCW2_SL | OCW2_L1);
411121985Sjhb#endif
412177468Sjhb	spinlock_exit();
413121985Sjhb}
414121985Sjhb
415121985Sjhbvoid
416121985Sjhbatpic_startup(void)
417121985Sjhb{
418122897Sjhb	struct atpic_intsrc *ai;
419122897Sjhb	int i;
420121985Sjhb
421121985Sjhb	/* Start off with all interrupts disabled. */
422121985Sjhb	imen = 0xffff;
423121985Sjhb	i8259_init(&atpics[MASTER], 0);
424121985Sjhb	i8259_init(&atpics[SLAVE], 1);
425121985Sjhb	atpic_enable_source((struct intsrc *)&atintrs[ICU_SLAVEID]);
426122897Sjhb
427122897Sjhb	/* Install low-level interrupt handlers for all of our IRQs. */
428128875Sjhb	for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) {
429122897Sjhb		if (i == ICU_SLAVEID)
430122897Sjhb			continue;
431122897Sjhb		ai->at_intsrc.is_count = &ai->at_count;
432122897Sjhb		ai->at_intsrc.is_straycount = &ai->at_straycount;
433122897Sjhb		setidt(((struct atpic *)ai->at_intsrc.is_pic)->at_intbase +
434204309Sattilio		    ai->at_irq, ai->at_intr, SDT_ATPIC, SEL_KPL, GSEL_ATPIC);
435122897Sjhb	}
436128929Sjhb
437128929Sjhb#ifdef DEV_MCA
438128929Sjhb	/* For MCA systems, all interrupts are level triggered. */
439128929Sjhb	if (MCA_system)
440128929Sjhb		for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++)
441128929Sjhb			ai->at_trigger = INTR_TRIGGER_LEVEL;
442128929Sjhb	else
443128929Sjhb#endif
444128929Sjhb
445129009Snyan#ifdef PC98
446129009Snyan	for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++)
447129009Snyan		switch (i) {
448129009Snyan		case 0:
449129009Snyan		case 1:
450129009Snyan		case 7:
451129009Snyan		case 8:
452129009Snyan			ai->at_trigger = INTR_TRIGGER_EDGE;
453129009Snyan			break;
454129009Snyan		default:
455129009Snyan			ai->at_trigger = INTR_TRIGGER_LEVEL;
456129009Snyan			break;
457129009Snyan		}
458129009Snyan#else
459128929Sjhb	/*
460128929Sjhb	 * Look for an ELCR.  If we find one, update the trigger modes.
461128929Sjhb	 * If we don't find one, assume that IRQs 0, 1, 2, and 13 are
462128929Sjhb	 * edge triggered and that everything else is level triggered.
463128929Sjhb	 * We only use the trigger information to reprogram the ELCR if
464128929Sjhb	 * we have one and as an optimization to avoid masking edge
465128929Sjhb	 * triggered interrupts.  For the case that we don't have an ELCR,
466128929Sjhb	 * it doesn't hurt to mask an edge triggered interrupt, so we
467129095Sjhb	 * assume level trigger for any interrupt that we aren't sure is
468129095Sjhb	 * edge triggered.
469128929Sjhb	 */
470140451Sjhb	if (elcr_found) {
471128929Sjhb		for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++)
472128929Sjhb			ai->at_trigger = elcr_read_trigger(i);
473128929Sjhb	} else {
474128929Sjhb		for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++)
475128929Sjhb			switch (i) {
476128929Sjhb			case 0:
477128929Sjhb			case 1:
478128929Sjhb			case 2:
479128929Sjhb			case 8:
480128929Sjhb			case 13:
481128929Sjhb				ai->at_trigger = INTR_TRIGGER_EDGE;
482128929Sjhb				break;
483128929Sjhb			default:
484128929Sjhb				ai->at_trigger = INTR_TRIGGER_LEVEL;
485128929Sjhb				break;
486128929Sjhb			}
487128929Sjhb	}
488129009Snyan#endif /* PC98 */
489121985Sjhb}
490121985Sjhb
491121985Sjhbstatic void
492121985Sjhbatpic_init(void *dummy __unused)
493121985Sjhb{
494128875Sjhb	struct atpic_intsrc *ai;
495121985Sjhb	int i;
496121985Sjhb
497153136Sjhb	/*
498163219Sjhb	 * Register our PICs, even if we aren't going to use any of their
499163219Sjhb	 * pins so that they are suspended and resumed.
500163219Sjhb	 */
501163219Sjhb	if (intr_register_pic(&atpics[0].at_pic) != 0 ||
502163219Sjhb	    intr_register_pic(&atpics[1].at_pic) != 0)
503163219Sjhb		panic("Unable to register ATPICs");
504163219Sjhb
505163219Sjhb	/*
506153136Sjhb	 * If any of the ISA IRQs have an interrupt source already, then
507153136Sjhb	 * assume that the APICs are being used and don't register any
508153136Sjhb	 * of our interrupt sources.  This makes sure we don't accidentally
509153136Sjhb	 * use mixed mode.  The "accidental" use could otherwise occur on
510153136Sjhb	 * machines that route the ACPI SCI interrupt to a different ISA
511153136Sjhb	 * IRQ (at least one machines routes it to IRQ 13) thus disabling
512153136Sjhb	 * that APIC ISA routing and allowing the ATPIC source for that IRQ
513153136Sjhb	 * to leak through.  We used to depend on this feature for routing
514153136Sjhb	 * IRQ0 via mixed mode, but now we don't use mixed mode at all.
515153136Sjhb	 */
516153136Sjhb	for (i = 0; i < NUM_ISA_IRQS; i++)
517153136Sjhb		if (intr_lookup_source(i) != NULL)
518153136Sjhb			return;
519153136Sjhb
520121985Sjhb	/* Loop through all interrupt sources and add them. */
521128875Sjhb	for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) {
522121985Sjhb		if (i == ICU_SLAVEID)
523121985Sjhb			continue;
524128875Sjhb		intr_register_source(&ai->at_intsrc);
525121985Sjhb	}
526121985Sjhb}
527177253SrwatsonSYSINIT(atpic_init, SI_SUB_INTR, SI_ORDER_SECOND + 1, atpic_init, NULL);
528121985Sjhb
529121985Sjhbvoid
530165302Skmacyatpic_handle_intr(u_int vector, struct trapframe *frame)
531121985Sjhb{
532121985Sjhb	struct intsrc *isrc;
533121985Sjhb
534153242Sjhb	KASSERT(vector < NUM_ISA_IRQS, ("unknown int %u\n", vector));
535153146Sjhb	isrc = &atintrs[vector].at_intsrc;
536122898Sjhb
537122898Sjhb	/*
538151658Sjhb	 * If we don't have an event, see if this is a spurious
539122898Sjhb	 * interrupt.
540122898Sjhb	 */
541153146Sjhb	if (isrc->is_event == NULL && (vector == 7 || vector == 15)) {
542122898Sjhb		int port, isr;
543122898Sjhb
544122898Sjhb		/*
545122898Sjhb		 * Read the ISR register to see if IRQ 7/15 is really
546122898Sjhb		 * pending.  Reset read register back to IRR when done.
547122898Sjhb		 */
548122898Sjhb		port = ((struct atpic *)isrc->is_pic)->at_ioaddr;
549177468Sjhb		spinlock_enter();
550122898Sjhb		outb(port, OCW3_SEL | OCW3_RR | OCW3_RIS);
551122898Sjhb		isr = inb(port);
552122898Sjhb		outb(port, OCW3_SEL | OCW3_RR);
553177468Sjhb		spinlock_exit();
554129131Sjhb		if ((isr & IRQ_MASK(7)) == 0)
555122898Sjhb			return;
556122898Sjhb	}
557165302Skmacy	intr_execute_handlers(isrc, frame);
558121985Sjhb}
559121985Sjhb
560121985Sjhb#ifdef DEV_ISA
561121985Sjhb/*
562121985Sjhb * Bus attachment for the ISA PIC.
563121985Sjhb */
564121985Sjhbstatic struct isa_pnp_id atpic_ids[] = {
565121985Sjhb	{ 0x0000d041 /* PNP0000 */, "AT interrupt controller" },
566121985Sjhb	{ 0 }
567121985Sjhb};
568121985Sjhb
569121985Sjhbstatic int
570121985Sjhbatpic_probe(device_t dev)
571121985Sjhb{
572121985Sjhb	int result;
573121985Sjhb
574121985Sjhb	result = ISA_PNP_PROBE(device_get_parent(dev), dev, atpic_ids);
575121985Sjhb	if (result <= 0)
576121985Sjhb		device_quiet(dev);
577121985Sjhb	return (result);
578121985Sjhb}
579121985Sjhb
580121985Sjhb/*
581121985Sjhb * We might be granted IRQ 2, as this is typically consumed by chaining
582121985Sjhb * between the two PIC components.  If we're using the APIC, however,
583121985Sjhb * this may not be the case, and as such we should free the resource.
584121985Sjhb * (XXX untested)
585121985Sjhb *
586121985Sjhb * The generic ISA attachment code will handle allocating any other resources
587121985Sjhb * that we don't explicitly claim here.
588121985Sjhb */
589121985Sjhbstatic int
590121985Sjhbatpic_attach(device_t dev)
591121985Sjhb{
592121985Sjhb	struct resource *res;
593121985Sjhb	int rid;
594121985Sjhb
595121985Sjhb	/* Try to allocate our IRQ and then free it. */
596121985Sjhb	rid = 0;
597127135Snjl	res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 0);
598121985Sjhb	if (res != NULL)
599121985Sjhb		bus_release_resource(dev, SYS_RES_IRQ, rid, res);
600121985Sjhb	return (0);
601121985Sjhb}
602121985Sjhb
603121985Sjhbstatic device_method_t atpic_methods[] = {
604121985Sjhb	/* Device interface */
605121985Sjhb	DEVMETHOD(device_probe,		atpic_probe),
606121985Sjhb	DEVMETHOD(device_attach,	atpic_attach),
607121985Sjhb	DEVMETHOD(device_detach,	bus_generic_detach),
608121985Sjhb	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
609121985Sjhb	DEVMETHOD(device_suspend,	bus_generic_suspend),
610121985Sjhb	DEVMETHOD(device_resume,	bus_generic_resume),
611121985Sjhb	{ 0, 0 }
612121985Sjhb};
613121985Sjhb
614121985Sjhbstatic driver_t atpic_driver = {
615121985Sjhb	"atpic",
616121985Sjhb	atpic_methods,
617121985Sjhb	1,		/* no softc */
618121985Sjhb};
619121985Sjhb
620121985Sjhbstatic devclass_t atpic_devclass;
621121985Sjhb
622121985SjhbDRIVER_MODULE(atpic, isa, atpic_driver, atpic_devclass, 0, 0);
623122051Snyan#ifndef PC98
624121985SjhbDRIVER_MODULE(atpic, acpi, atpic_driver, atpic_devclass, 0, 0);
625122051Snyan#endif
626121985Sjhb
627121985Sjhb/*
628121985Sjhb * Return a bitmap of the current interrupt requests.  This is 8259-specific
629121985Sjhb * and is only suitable for use at probe time.
630121985Sjhb */
631121985Sjhbintrmask_t
632121985Sjhbisa_irq_pending(void)
633121985Sjhb{
634121985Sjhb	u_char irr1;
635121985Sjhb	u_char irr2;
636121985Sjhb
637121985Sjhb	irr1 = inb(IO_ICU1);
638121985Sjhb	irr2 = inb(IO_ICU2);
639121985Sjhb	return ((irr2 << 8) | irr1);
640121985Sjhb}
641121985Sjhb#endif /* DEV_ISA */
642