atpic.c revision 277311
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: head/sys/x86/isa/atpic.c 277311 2015-01-18 03:43:47Z imp $");
33121985Sjhb
34121985Sjhb#include "opt_auto_eoi.h"
35121985Sjhb#include "opt_isa.h"
36277285Simp#include "opt_mca.h"
37121985Sjhb
38121985Sjhb#include <sys/param.h>
39121985Sjhb#include <sys/systm.h>
40121985Sjhb#include <sys/bus.h>
41121985Sjhb#include <sys/interrupt.h>
42121985Sjhb#include <sys/kernel.h>
43121985Sjhb#include <sys/lock.h>
44129876Sphk#include <sys/module.h>
45121985Sjhb
46121985Sjhb#include <machine/cpufunc.h>
47121985Sjhb#include <machine/frame.h>
48121985Sjhb#include <machine/intr_machdep.h>
49121985Sjhb#include <machine/md_var.h>
50121985Sjhb#include <machine/resource.h>
51121985Sjhb#include <machine/segments.h>
52121985Sjhb
53124188Sjhb#include <dev/ic/i8259.h>
54204309Sattilio#include <x86/isa/icu.h>
55122051Snyan#ifdef PC98
56146049Snyan#include <pc98/cbus/cbus.h>
57122051Snyan#else
58263379Simp#include <isa/isareg.h>
59122051Snyan#endif
60121985Sjhb#include <isa/isavar.h>
61277311Simp#ifdef DEV_MCA
62277311Simp#include <i386/bios/mca_machdep.h>
63277311Simp#endif
64121985Sjhb
65204309Sattilio#ifdef __amd64__
66204309Sattilio#define	SDT_ATPIC	SDT_SYSIGT
67204309Sattilio#define	GSEL_ATPIC	0
68204309Sattilio#else
69204309Sattilio#define	SDT_ATPIC	SDT_SYS386IGT
70204309Sattilio#define	GSEL_ATPIC	GSEL(GCODE_SEL, SEL_KPL)
71204309Sattilio#endif
72204309Sattilio
73121985Sjhb#define	MASTER	0
74121985Sjhb#define	SLAVE	1
75121985Sjhb
76128875Sjhb#define	NUM_ISA_IRQS		16
77128875Sjhb
78121985Sjhbstatic void	atpic_init(void *dummy);
79121985Sjhb
80121985Sjhbunsigned int imen;	/* XXX */
81121985Sjhb
82121985Sjhbinthand_t
83121985Sjhb	IDTVEC(atpic_intr0), IDTVEC(atpic_intr1), IDTVEC(atpic_intr2),
84121985Sjhb	IDTVEC(atpic_intr3), IDTVEC(atpic_intr4), IDTVEC(atpic_intr5),
85121985Sjhb	IDTVEC(atpic_intr6), IDTVEC(atpic_intr7), IDTVEC(atpic_intr8),
86121985Sjhb	IDTVEC(atpic_intr9), IDTVEC(atpic_intr10), IDTVEC(atpic_intr11),
87121985Sjhb	IDTVEC(atpic_intr12), IDTVEC(atpic_intr13), IDTVEC(atpic_intr14),
88121985Sjhb	IDTVEC(atpic_intr15);
89121985Sjhb
90121985Sjhb#define	IRQ(ap, ai)	((ap)->at_irqbase + (ai)->at_irq)
91121985Sjhb
92128929Sjhb#define	ATPIC(io, base, eoi, imenptr)					\
93121985Sjhb     	{ { atpic_enable_source, atpic_disable_source, (eoi),		\
94169391Sjhb	    atpic_enable_intr, atpic_disable_intr, atpic_vector,	\
95169391Sjhb	    atpic_source_pending, NULL,	atpic_resume, atpic_config_intr,\
96169391Sjhb	    atpic_assign_cpu }, (io), (base), IDT_IO_INTS + (base),	\
97169391Sjhb	    (imenptr) }
98121985Sjhb
99121985Sjhb#define	INTSRC(irq)							\
100128929Sjhb	{ { &atpics[(irq) / 8].at_pic }, IDTVEC(atpic_intr ## irq ),	\
101128929Sjhb	    (irq) % 8 }
102121985Sjhb
103121985Sjhbstruct atpic {
104121985Sjhb	struct pic at_pic;
105121985Sjhb	int	at_ioaddr;
106121985Sjhb	int	at_irqbase;
107121985Sjhb	uint8_t	at_intbase;
108121985Sjhb	uint8_t	*at_imen;
109121985Sjhb};
110121985Sjhb
111121985Sjhbstruct atpic_intsrc {
112121985Sjhb	struct intsrc at_intsrc;
113121985Sjhb	inthand_t *at_intr;
114128929Sjhb	int	at_irq;			/* Relative to PIC base. */
115128929Sjhb	enum intr_trigger at_trigger;
116122897Sjhb	u_long	at_count;
117122897Sjhb	u_long	at_straycount;
118121985Sjhb};
119121985Sjhb
120121985Sjhbstatic void atpic_enable_source(struct intsrc *isrc);
121133017Sscottlstatic void atpic_disable_source(struct intsrc *isrc, int eoi);
122121985Sjhbstatic void atpic_eoi_master(struct intsrc *isrc);
123121985Sjhbstatic void atpic_eoi_slave(struct intsrc *isrc);
124121985Sjhbstatic void atpic_enable_intr(struct intsrc *isrc);
125169391Sjhbstatic void atpic_disable_intr(struct intsrc *isrc);
126121985Sjhbstatic int atpic_vector(struct intsrc *isrc);
127255726Sgibbsstatic void atpic_resume(struct pic *pic, bool suspend_cancelled);
128121985Sjhbstatic int atpic_source_pending(struct intsrc *isrc);
129128931Sjhbstatic int atpic_config_intr(struct intsrc *isrc, enum intr_trigger trig,
130128931Sjhb    enum intr_polarity pol);
131195249Sjhbstatic int atpic_assign_cpu(struct intsrc *isrc, u_int apic_id);
132121985Sjhbstatic void i8259_init(struct atpic *pic, int slave);
133121985Sjhb
134121985Sjhbstatic struct atpic atpics[] = {
135121985Sjhb	ATPIC(IO_ICU1, 0, atpic_eoi_master, (uint8_t *)&imen),
136121985Sjhb	ATPIC(IO_ICU2, 8, atpic_eoi_slave, ((uint8_t *)&imen) + 1)
137121985Sjhb};
138121985Sjhb
139121985Sjhbstatic struct atpic_intsrc atintrs[] = {
140121985Sjhb	INTSRC(0),
141121985Sjhb	INTSRC(1),
142121985Sjhb	INTSRC(2),
143121985Sjhb	INTSRC(3),
144121985Sjhb	INTSRC(4),
145121985Sjhb	INTSRC(5),
146121985Sjhb	INTSRC(6),
147121985Sjhb	INTSRC(7),
148121985Sjhb	INTSRC(8),
149121985Sjhb	INTSRC(9),
150121985Sjhb	INTSRC(10),
151121985Sjhb	INTSRC(11),
152121985Sjhb	INTSRC(12),
153121985Sjhb	INTSRC(13),
154121985Sjhb	INTSRC(14),
155121985Sjhb	INTSRC(15),
156121985Sjhb};
157121985Sjhb
158129095SjhbCTASSERT(sizeof(atintrs) / sizeof(atintrs[0]) == NUM_ISA_IRQS);
159128875Sjhb
160133017Sscottlstatic __inline void
161133017Sscottl_atpic_eoi_master(struct intsrc *isrc)
162133017Sscottl{
163133017Sscottl
164133017Sscottl	KASSERT(isrc->is_pic == &atpics[MASTER].at_pic,
165133017Sscottl	    ("%s: mismatched pic", __func__));
166133017Sscottl#ifndef AUTO_EOI_1
167133017Sscottl	outb(atpics[MASTER].at_ioaddr, OCW2_EOI);
168133017Sscottl#endif
169133017Sscottl}
170133017Sscottl
171133017Sscottl/*
172133017Sscottl * The data sheet says no auto-EOI on slave, but it sometimes works.
173133017Sscottl * So, if AUTO_EOI_2 is enabled, we use it.
174133017Sscottl */
175133017Sscottlstatic __inline void
176133017Sscottl_atpic_eoi_slave(struct intsrc *isrc)
177133017Sscottl{
178133017Sscottl
179133017Sscottl	KASSERT(isrc->is_pic == &atpics[SLAVE].at_pic,
180133017Sscottl	    ("%s: mismatched pic", __func__));
181133017Sscottl#ifndef AUTO_EOI_2
182133017Sscottl	outb(atpics[SLAVE].at_ioaddr, OCW2_EOI);
183133017Sscottl#ifndef AUTO_EOI_1
184133017Sscottl	outb(atpics[MASTER].at_ioaddr, OCW2_EOI);
185133017Sscottl#endif
186133017Sscottl#endif
187133017Sscottl}
188133017Sscottl
189121985Sjhbstatic void
190121985Sjhbatpic_enable_source(struct intsrc *isrc)
191121985Sjhb{
192121985Sjhb	struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc;
193121985Sjhb	struct atpic *ap = (struct atpic *)isrc->is_pic;
194121985Sjhb
195177468Sjhb	spinlock_enter();
196128875Sjhb	if (*ap->at_imen & IMEN_MASK(ai)) {
197128875Sjhb		*ap->at_imen &= ~IMEN_MASK(ai);
198128875Sjhb		outb(ap->at_ioaddr + ICU_IMR_OFFSET, *ap->at_imen);
199128875Sjhb	}
200177468Sjhb	spinlock_exit();
201121985Sjhb}
202121985Sjhb
203121985Sjhbstatic void
204133017Sscottlatpic_disable_source(struct intsrc *isrc, int eoi)
205121985Sjhb{
206121985Sjhb	struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc;
207121985Sjhb	struct atpic *ap = (struct atpic *)isrc->is_pic;
208121985Sjhb
209177468Sjhb	spinlock_enter();
210133017Sscottl	if (ai->at_trigger != INTR_TRIGGER_EDGE) {
211133017Sscottl		*ap->at_imen |= IMEN_MASK(ai);
212133017Sscottl		outb(ap->at_ioaddr + ICU_IMR_OFFSET, *ap->at_imen);
213133017Sscottl	}
214133017Sscottl
215133017Sscottl	/*
216133017Sscottl	 * Take care to call these functions directly instead of through
217133017Sscottl	 * a function pointer.  All of the referenced variables should
218133017Sscottl	 * still be hot in the cache.
219133017Sscottl	 */
220133017Sscottl	if (eoi == PIC_EOI) {
221133017Sscottl		if (isrc->is_pic == &atpics[MASTER].at_pic)
222133017Sscottl			_atpic_eoi_master(isrc);
223133017Sscottl		else
224133017Sscottl			_atpic_eoi_slave(isrc);
225133017Sscottl	}
226133017Sscottl
227177468Sjhb	spinlock_exit();
228121985Sjhb}
229121985Sjhb
230121985Sjhbstatic void
231121985Sjhbatpic_eoi_master(struct intsrc *isrc)
232121985Sjhb{
233121985Sjhb#ifndef AUTO_EOI_1
234177468Sjhb	spinlock_enter();
235133017Sscottl	_atpic_eoi_master(isrc);
236177468Sjhb	spinlock_exit();
237121985Sjhb#endif
238121985Sjhb}
239121985Sjhb
240121985Sjhbstatic void
241121985Sjhbatpic_eoi_slave(struct intsrc *isrc)
242121985Sjhb{
243121985Sjhb#ifndef AUTO_EOI_2
244177468Sjhb	spinlock_enter();
245133017Sscottl	_atpic_eoi_slave(isrc);
246177468Sjhb	spinlock_exit();
247121985Sjhb#endif
248121985Sjhb}
249121985Sjhb
250121985Sjhbstatic void
251121985Sjhbatpic_enable_intr(struct intsrc *isrc)
252121985Sjhb{
253121985Sjhb}
254121985Sjhb
255169391Sjhbstatic void
256169391Sjhbatpic_disable_intr(struct intsrc *isrc)
257169391Sjhb{
258169391Sjhb}
259169391Sjhb
260169391Sjhb
261121985Sjhbstatic int
262121985Sjhbatpic_vector(struct intsrc *isrc)
263121985Sjhb{
264121985Sjhb	struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc;
265121985Sjhb	struct atpic *ap = (struct atpic *)isrc->is_pic;
266121985Sjhb
267121985Sjhb	return (IRQ(ap, ai));
268121985Sjhb}
269121985Sjhb
270121985Sjhbstatic int
271121985Sjhbatpic_source_pending(struct intsrc *isrc)
272121985Sjhb{
273121985Sjhb	struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc;
274121985Sjhb	struct atpic *ap = (struct atpic *)isrc->is_pic;
275121985Sjhb
276128875Sjhb	return (inb(ap->at_ioaddr) & IMEN_MASK(ai));
277121985Sjhb}
278121985Sjhb
279121985Sjhbstatic void
280255726Sgibbsatpic_resume(struct pic *pic, bool suspend_cancelled)
281121985Sjhb{
282163219Sjhb	struct atpic *ap = (struct atpic *)pic;
283121985Sjhb
284163219Sjhb	i8259_init(ap, ap == &atpics[SLAVE]);
285129009Snyan#ifndef PC98
286163219Sjhb	if (ap == &atpics[SLAVE] && elcr_found)
287163219Sjhb		elcr_resume();
288129009Snyan#endif
289121985Sjhb}
290121985Sjhb
291128931Sjhbstatic int
292128931Sjhbatpic_config_intr(struct intsrc *isrc, enum intr_trigger trig,
293128931Sjhb    enum intr_polarity pol)
294128931Sjhb{
295128931Sjhb	struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc;
296128931Sjhb	u_int vector;
297128931Sjhb
298128931Sjhb	/* Map conforming values to edge/hi and sanity check the values. */
299128931Sjhb	if (trig == INTR_TRIGGER_CONFORM)
300128931Sjhb		trig = INTR_TRIGGER_EDGE;
301128931Sjhb	if (pol == INTR_POLARITY_CONFORM)
302128931Sjhb		pol = INTR_POLARITY_HIGH;
303128931Sjhb	vector = atpic_vector(isrc);
304128931Sjhb	if ((trig == INTR_TRIGGER_EDGE && pol == INTR_POLARITY_LOW) ||
305128931Sjhb	    (trig == INTR_TRIGGER_LEVEL && pol == INTR_POLARITY_HIGH)) {
306128931Sjhb		printf(
307128931Sjhb		"atpic: Mismatched config for IRQ%u: trigger %s, polarity %s\n",
308128931Sjhb		    vector, trig == INTR_TRIGGER_EDGE ? "edge" : "level",
309128931Sjhb		    pol == INTR_POLARITY_HIGH ? "high" : "low");
310128931Sjhb		return (EINVAL);
311128931Sjhb	}
312128931Sjhb
313128931Sjhb	/* If there is no change, just return. */
314128931Sjhb	if (ai->at_trigger == trig)
315128931Sjhb		return (0);
316128931Sjhb
317129009Snyan#ifdef PC98
318129009Snyan	if ((vector == 0 || vector == 1 || vector == 7 || vector == 8) &&
319129009Snyan	    trig == INTR_TRIGGER_LEVEL) {
320129009Snyan		if (bootverbose)
321129009Snyan			printf(
322129009Snyan		"atpic: Ignoring invalid level/low configuration for IRQ%u\n",
323129009Snyan			    vector);
324129009Snyan		return (EINVAL);
325129009Snyan	}
326129009Snyan	return (ENXIO);
327129009Snyan#else
328128931Sjhb	/*
329128931Sjhb	 * Certain IRQs can never be level/lo, so don't try to set them
330128931Sjhb	 * that way if asked.  At least some ELCR registers ignore setting
331128931Sjhb	 * these bits as well.
332128931Sjhb	 */
333128931Sjhb	if ((vector == 0 || vector == 1 || vector == 2 || vector == 13) &&
334128931Sjhb	    trig == INTR_TRIGGER_LEVEL) {
335128931Sjhb		if (bootverbose)
336128931Sjhb			printf(
337128931Sjhb		"atpic: Ignoring invalid level/low configuration for IRQ%u\n",
338128931Sjhb			    vector);
339128931Sjhb		return (EINVAL);
340128931Sjhb	}
341140451Sjhb	if (!elcr_found) {
342128931Sjhb		if (bootverbose)
343128931Sjhb			printf("atpic: No ELCR to configure IRQ%u as %s\n",
344128931Sjhb			    vector, trig == INTR_TRIGGER_EDGE ? "edge/high" :
345128931Sjhb			    "level/low");
346128931Sjhb		return (ENXIO);
347128931Sjhb	}
348128931Sjhb	if (bootverbose)
349128931Sjhb		printf("atpic: Programming IRQ%u as %s\n", vector,
350128931Sjhb		    trig == INTR_TRIGGER_EDGE ? "edge/high" : "level/low");
351177468Sjhb	spinlock_enter();
352128931Sjhb	elcr_write_trigger(atpic_vector(isrc), trig);
353128931Sjhb	ai->at_trigger = trig;
354177468Sjhb	spinlock_exit();
355128931Sjhb	return (0);
356129009Snyan#endif /* PC98 */
357128931Sjhb}
358128931Sjhb
359195249Sjhbstatic int
360156124Sjhbatpic_assign_cpu(struct intsrc *isrc, u_int apic_id)
361156124Sjhb{
362156124Sjhb
363156124Sjhb	/*
364156124Sjhb	 * 8259A's are only used in UP in which case all interrupts always
365156124Sjhb	 * go to the sole CPU and this function shouldn't even be called.
366156124Sjhb	 */
367156124Sjhb	panic("%s: bad cookie", __func__);
368156124Sjhb}
369156124Sjhb
370156124Sjhbstatic void
371121985Sjhbi8259_init(struct atpic *pic, int slave)
372121985Sjhb{
373121985Sjhb	int imr_addr;
374121985Sjhb
375121985Sjhb	/* Reset the PIC and program with next four bytes. */
376177468Sjhb	spinlock_enter();
377121985Sjhb#ifdef DEV_MCA
378122692Sjhb	/* MCA uses level triggered interrupts. */
379121985Sjhb	if (MCA_system)
380122692Sjhb		outb(pic->at_ioaddr, ICW1_RESET | ICW1_IC4 | ICW1_LTIM);
381121985Sjhb	else
382121985Sjhb#endif
383122692Sjhb		outb(pic->at_ioaddr, ICW1_RESET | ICW1_IC4);
384121985Sjhb	imr_addr = pic->at_ioaddr + ICU_IMR_OFFSET;
385121985Sjhb
386121985Sjhb	/* Start vector. */
387121985Sjhb	outb(imr_addr, pic->at_intbase);
388121985Sjhb
389121985Sjhb	/*
390121985Sjhb	 * Setup slave links.  For the master pic, indicate what line
391121985Sjhb	 * the slave is configured on.  For the slave indicate
392121985Sjhb	 * which line on the master we are connected to.
393121985Sjhb	 */
394121985Sjhb	if (slave)
395129131Sjhb		outb(imr_addr, ICU_SLAVEID);
396121985Sjhb	else
397129131Sjhb		outb(imr_addr, IRQ_MASK(ICU_SLAVEID));
398121985Sjhb
399121985Sjhb	/* Set mode. */
400121985Sjhb	if (slave)
401121985Sjhb		outb(imr_addr, SLAVE_MODE);
402121985Sjhb	else
403121985Sjhb		outb(imr_addr, MASTER_MODE);
404121985Sjhb
405121985Sjhb	/* Set interrupt enable mask. */
406121985Sjhb	outb(imr_addr, *pic->at_imen);
407121985Sjhb
408121985Sjhb	/* Reset is finished, default to IRR on read. */
409122692Sjhb	outb(pic->at_ioaddr, OCW3_SEL | OCW3_RR);
410121985Sjhb
411121985Sjhb#ifndef PC98
412122692Sjhb	/* OCW2_L1 sets priority order to 3-7, 0-2 (com2 first). */
413121985Sjhb	if (!slave)
414122692Sjhb		outb(pic->at_ioaddr, OCW2_R | OCW2_SL | OCW2_L1);
415121985Sjhb#endif
416177468Sjhb	spinlock_exit();
417121985Sjhb}
418121985Sjhb
419121985Sjhbvoid
420121985Sjhbatpic_startup(void)
421121985Sjhb{
422122897Sjhb	struct atpic_intsrc *ai;
423122897Sjhb	int i;
424121985Sjhb
425121985Sjhb	/* Start off with all interrupts disabled. */
426121985Sjhb	imen = 0xffff;
427121985Sjhb	i8259_init(&atpics[MASTER], 0);
428121985Sjhb	i8259_init(&atpics[SLAVE], 1);
429121985Sjhb	atpic_enable_source((struct intsrc *)&atintrs[ICU_SLAVEID]);
430122897Sjhb
431122897Sjhb	/* Install low-level interrupt handlers for all of our IRQs. */
432128875Sjhb	for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) {
433122897Sjhb		if (i == ICU_SLAVEID)
434122897Sjhb			continue;
435122897Sjhb		ai->at_intsrc.is_count = &ai->at_count;
436122897Sjhb		ai->at_intsrc.is_straycount = &ai->at_straycount;
437122897Sjhb		setidt(((struct atpic *)ai->at_intsrc.is_pic)->at_intbase +
438204309Sattilio		    ai->at_irq, ai->at_intr, SDT_ATPIC, SEL_KPL, GSEL_ATPIC);
439122897Sjhb	}
440128929Sjhb
441128929Sjhb#ifdef DEV_MCA
442128929Sjhb	/* For MCA systems, all interrupts are level triggered. */
443128929Sjhb	if (MCA_system)
444128929Sjhb		for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++)
445128929Sjhb			ai->at_trigger = INTR_TRIGGER_LEVEL;
446128929Sjhb	else
447128929Sjhb#endif
448128929Sjhb
449129009Snyan#ifdef PC98
450129009Snyan	for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++)
451129009Snyan		switch (i) {
452129009Snyan		case 0:
453129009Snyan		case 1:
454129009Snyan		case 7:
455129009Snyan		case 8:
456129009Snyan			ai->at_trigger = INTR_TRIGGER_EDGE;
457129009Snyan			break;
458129009Snyan		default:
459129009Snyan			ai->at_trigger = INTR_TRIGGER_LEVEL;
460129009Snyan			break;
461129009Snyan		}
462129009Snyan#else
463128929Sjhb	/*
464128929Sjhb	 * Look for an ELCR.  If we find one, update the trigger modes.
465128929Sjhb	 * If we don't find one, assume that IRQs 0, 1, 2, and 13 are
466128929Sjhb	 * edge triggered and that everything else is level triggered.
467128929Sjhb	 * We only use the trigger information to reprogram the ELCR if
468128929Sjhb	 * we have one and as an optimization to avoid masking edge
469128929Sjhb	 * triggered interrupts.  For the case that we don't have an ELCR,
470128929Sjhb	 * it doesn't hurt to mask an edge triggered interrupt, so we
471129095Sjhb	 * assume level trigger for any interrupt that we aren't sure is
472129095Sjhb	 * edge triggered.
473128929Sjhb	 */
474140451Sjhb	if (elcr_found) {
475128929Sjhb		for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++)
476128929Sjhb			ai->at_trigger = elcr_read_trigger(i);
477128929Sjhb	} else {
478128929Sjhb		for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++)
479128929Sjhb			switch (i) {
480128929Sjhb			case 0:
481128929Sjhb			case 1:
482128929Sjhb			case 2:
483128929Sjhb			case 8:
484128929Sjhb			case 13:
485128929Sjhb				ai->at_trigger = INTR_TRIGGER_EDGE;
486128929Sjhb				break;
487128929Sjhb			default:
488128929Sjhb				ai->at_trigger = INTR_TRIGGER_LEVEL;
489128929Sjhb				break;
490128929Sjhb			}
491128929Sjhb	}
492129009Snyan#endif /* PC98 */
493121985Sjhb}
494121985Sjhb
495121985Sjhbstatic void
496121985Sjhbatpic_init(void *dummy __unused)
497121985Sjhb{
498128875Sjhb	struct atpic_intsrc *ai;
499121985Sjhb	int i;
500121985Sjhb
501153136Sjhb	/*
502163219Sjhb	 * Register our PICs, even if we aren't going to use any of their
503163219Sjhb	 * pins so that they are suspended and resumed.
504163219Sjhb	 */
505163219Sjhb	if (intr_register_pic(&atpics[0].at_pic) != 0 ||
506163219Sjhb	    intr_register_pic(&atpics[1].at_pic) != 0)
507163219Sjhb		panic("Unable to register ATPICs");
508163219Sjhb
509163219Sjhb	/*
510153136Sjhb	 * If any of the ISA IRQs have an interrupt source already, then
511153136Sjhb	 * assume that the APICs are being used and don't register any
512153136Sjhb	 * of our interrupt sources.  This makes sure we don't accidentally
513153136Sjhb	 * use mixed mode.  The "accidental" use could otherwise occur on
514153136Sjhb	 * machines that route the ACPI SCI interrupt to a different ISA
515153136Sjhb	 * IRQ (at least one machines routes it to IRQ 13) thus disabling
516153136Sjhb	 * that APIC ISA routing and allowing the ATPIC source for that IRQ
517153136Sjhb	 * to leak through.  We used to depend on this feature for routing
518153136Sjhb	 * IRQ0 via mixed mode, but now we don't use mixed mode at all.
519153136Sjhb	 */
520153136Sjhb	for (i = 0; i < NUM_ISA_IRQS; i++)
521153136Sjhb		if (intr_lookup_source(i) != NULL)
522153136Sjhb			return;
523153136Sjhb
524121985Sjhb	/* Loop through all interrupt sources and add them. */
525128875Sjhb	for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) {
526121985Sjhb		if (i == ICU_SLAVEID)
527121985Sjhb			continue;
528128875Sjhb		intr_register_source(&ai->at_intsrc);
529121985Sjhb	}
530121985Sjhb}
531269675SroygerSYSINIT(atpic_init, SI_SUB_INTR, SI_ORDER_FOURTH, atpic_init, NULL);
532121985Sjhb
533121985Sjhbvoid
534165302Skmacyatpic_handle_intr(u_int vector, struct trapframe *frame)
535121985Sjhb{
536121985Sjhb	struct intsrc *isrc;
537121985Sjhb
538153242Sjhb	KASSERT(vector < NUM_ISA_IRQS, ("unknown int %u\n", vector));
539153146Sjhb	isrc = &atintrs[vector].at_intsrc;
540122898Sjhb
541122898Sjhb	/*
542151658Sjhb	 * If we don't have an event, see if this is a spurious
543122898Sjhb	 * interrupt.
544122898Sjhb	 */
545153146Sjhb	if (isrc->is_event == NULL && (vector == 7 || vector == 15)) {
546122898Sjhb		int port, isr;
547122898Sjhb
548122898Sjhb		/*
549122898Sjhb		 * Read the ISR register to see if IRQ 7/15 is really
550122898Sjhb		 * pending.  Reset read register back to IRR when done.
551122898Sjhb		 */
552122898Sjhb		port = ((struct atpic *)isrc->is_pic)->at_ioaddr;
553177468Sjhb		spinlock_enter();
554122898Sjhb		outb(port, OCW3_SEL | OCW3_RR | OCW3_RIS);
555122898Sjhb		isr = inb(port);
556122898Sjhb		outb(port, OCW3_SEL | OCW3_RR);
557177468Sjhb		spinlock_exit();
558129131Sjhb		if ((isr & IRQ_MASK(7)) == 0)
559122898Sjhb			return;
560122898Sjhb	}
561165302Skmacy	intr_execute_handlers(isrc, frame);
562121985Sjhb}
563121985Sjhb
564121985Sjhb#ifdef DEV_ISA
565121985Sjhb/*
566121985Sjhb * Bus attachment for the ISA PIC.
567121985Sjhb */
568121985Sjhbstatic struct isa_pnp_id atpic_ids[] = {
569121985Sjhb	{ 0x0000d041 /* PNP0000 */, "AT interrupt controller" },
570121985Sjhb	{ 0 }
571121985Sjhb};
572121985Sjhb
573121985Sjhbstatic int
574121985Sjhbatpic_probe(device_t dev)
575121985Sjhb{
576121985Sjhb	int result;
577121985Sjhb
578121985Sjhb	result = ISA_PNP_PROBE(device_get_parent(dev), dev, atpic_ids);
579121985Sjhb	if (result <= 0)
580121985Sjhb		device_quiet(dev);
581121985Sjhb	return (result);
582121985Sjhb}
583121985Sjhb
584121985Sjhb/*
585121985Sjhb * We might be granted IRQ 2, as this is typically consumed by chaining
586121985Sjhb * between the two PIC components.  If we're using the APIC, however,
587121985Sjhb * this may not be the case, and as such we should free the resource.
588121985Sjhb * (XXX untested)
589121985Sjhb *
590121985Sjhb * The generic ISA attachment code will handle allocating any other resources
591121985Sjhb * that we don't explicitly claim here.
592121985Sjhb */
593121985Sjhbstatic int
594121985Sjhbatpic_attach(device_t dev)
595121985Sjhb{
596121985Sjhb	struct resource *res;
597121985Sjhb	int rid;
598121985Sjhb
599121985Sjhb	/* Try to allocate our IRQ and then free it. */
600121985Sjhb	rid = 0;
601127135Snjl	res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 0);
602121985Sjhb	if (res != NULL)
603121985Sjhb		bus_release_resource(dev, SYS_RES_IRQ, rid, res);
604121985Sjhb	return (0);
605121985Sjhb}
606121985Sjhb
607121985Sjhbstatic device_method_t atpic_methods[] = {
608121985Sjhb	/* Device interface */
609121985Sjhb	DEVMETHOD(device_probe,		atpic_probe),
610121985Sjhb	DEVMETHOD(device_attach,	atpic_attach),
611121985Sjhb	DEVMETHOD(device_detach,	bus_generic_detach),
612121985Sjhb	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
613121985Sjhb	DEVMETHOD(device_suspend,	bus_generic_suspend),
614121985Sjhb	DEVMETHOD(device_resume,	bus_generic_resume),
615121985Sjhb	{ 0, 0 }
616121985Sjhb};
617121985Sjhb
618121985Sjhbstatic driver_t atpic_driver = {
619121985Sjhb	"atpic",
620121985Sjhb	atpic_methods,
621121985Sjhb	1,		/* no softc */
622121985Sjhb};
623121985Sjhb
624121985Sjhbstatic devclass_t atpic_devclass;
625121985Sjhb
626121985SjhbDRIVER_MODULE(atpic, isa, atpic_driver, atpic_devclass, 0, 0);
627122051Snyan#ifndef PC98
628121985SjhbDRIVER_MODULE(atpic, acpi, atpic_driver, atpic_devclass, 0, 0);
629122051Snyan#endif
630121985Sjhb
631121985Sjhb/*
632121985Sjhb * Return a bitmap of the current interrupt requests.  This is 8259-specific
633121985Sjhb * and is only suitable for use at probe time.
634121985Sjhb */
635121985Sjhbintrmask_t
636121985Sjhbisa_irq_pending(void)
637121985Sjhb{
638121985Sjhb	u_char irr1;
639121985Sjhb	u_char irr2;
640121985Sjhb
641121985Sjhb	irr1 = inb(IO_ICU1);
642121985Sjhb	irr2 = inb(IO_ICU2);
643121985Sjhb	return ((irr2 << 8) | irr1);
644121985Sjhb}
645121985Sjhb#endif /* DEV_ISA */
646