1121985Sjhb/*-
2121985Sjhb * Copyright (c) 2003 John Baldwin <jhb@FreeBSD.org>
3121985Sjhb *
4121985Sjhb * Redistribution and use in source and binary forms, with or without
5121985Sjhb * modification, are permitted provided that the following conditions
6121985Sjhb * are met:
7121985Sjhb * 1. Redistributions of source code must retain the above copyright
8121985Sjhb *    notice, this list of conditions and the following disclaimer.
9121985Sjhb * 2. Redistributions in binary form must reproduce the above copyright
10121985Sjhb *    notice, this list of conditions and the following disclaimer in the
11121985Sjhb *    documentation and/or other materials provided with the distribution.
12121985Sjhb *
13121985Sjhb * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14121985Sjhb * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15121985Sjhb * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16121985Sjhb * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17121985Sjhb * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18121985Sjhb * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19121985Sjhb * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20121985Sjhb * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21121985Sjhb * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22121985Sjhb * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23121985Sjhb * SUCH DAMAGE.
24121985Sjhb */
25121985Sjhb
26121985Sjhb/*
27121985Sjhb * PIC driver for the 8259A Master and Slave PICs in PC/AT machines.
28121985Sjhb */
29121985Sjhb
30121985Sjhb#include <sys/cdefs.h>
31121985Sjhb__FBSDID("$FreeBSD: stable/11/sys/x86/isa/atpic.c 367457 2020-11-07 18:10:59Z dim $");
32121985Sjhb
33121985Sjhb#include "opt_auto_eoi.h"
34121985Sjhb#include "opt_isa.h"
35277285Simp#include "opt_mca.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
57263379Simp#include <isa/isareg.h>
58122051Snyan#endif
59121985Sjhb#include <isa/isavar.h>
60277311Simp#ifdef DEV_MCA
61277311Simp#include <i386/bios/mca_machdep.h>
62277311Simp#endif
63121985Sjhb
64204309Sattilio#ifdef __amd64__
65204309Sattilio#define	SDT_ATPIC	SDT_SYSIGT
66204309Sattilio#define	GSEL_ATPIC	0
67204309Sattilio#else
68204309Sattilio#define	SDT_ATPIC	SDT_SYS386IGT
69204309Sattilio#define	GSEL_ATPIC	GSEL(GCODE_SEL, SEL_KPL)
70204309Sattilio#endif
71204309Sattilio
72121985Sjhb#define	MASTER	0
73121985Sjhb#define	SLAVE	1
74121985Sjhb
75339928Sjhb#define	IMEN_MASK(ai)		(IRQ_MASK((ai)->at_irq))
76339928Sjhb
77128875Sjhb#define	NUM_ISA_IRQS		16
78128875Sjhb
79121985Sjhbstatic void	atpic_init(void *dummy);
80121985Sjhb
81121985Sjhbinthand_t
82121985Sjhb	IDTVEC(atpic_intr0), IDTVEC(atpic_intr1), IDTVEC(atpic_intr2),
83121985Sjhb	IDTVEC(atpic_intr3), IDTVEC(atpic_intr4), IDTVEC(atpic_intr5),
84121985Sjhb	IDTVEC(atpic_intr6), IDTVEC(atpic_intr7), IDTVEC(atpic_intr8),
85121985Sjhb	IDTVEC(atpic_intr9), IDTVEC(atpic_intr10), IDTVEC(atpic_intr11),
86121985Sjhb	IDTVEC(atpic_intr12), IDTVEC(atpic_intr13), IDTVEC(atpic_intr14),
87121985Sjhb	IDTVEC(atpic_intr15);
88329462Skib/* XXXKIB i386 uses stubs until pti comes */
89329462Skibinthand_t
90329462Skib	IDTVEC(atpic_intr0_pti), IDTVEC(atpic_intr1_pti),
91329462Skib	IDTVEC(atpic_intr2_pti), IDTVEC(atpic_intr3_pti),
92329462Skib	IDTVEC(atpic_intr4_pti), IDTVEC(atpic_intr5_pti),
93329462Skib	IDTVEC(atpic_intr6_pti), IDTVEC(atpic_intr7_pti),
94329462Skib	IDTVEC(atpic_intr8_pti), IDTVEC(atpic_intr9_pti),
95329462Skib	IDTVEC(atpic_intr10_pti), IDTVEC(atpic_intr11_pti),
96329462Skib	IDTVEC(atpic_intr12_pti), IDTVEC(atpic_intr13_pti),
97329462Skib	IDTVEC(atpic_intr14_pti), IDTVEC(atpic_intr15_pti);
98121985Sjhb
99121985Sjhb#define	IRQ(ap, ai)	((ap)->at_irqbase + (ai)->at_irq)
100121985Sjhb
101339928Sjhb#define	ATPIC(io, base, eoi) {						\
102339928Sjhb		.at_pic = {						\
103340016Sjhb			.pic_register_sources = atpic_register_sources,	\
104339928Sjhb			.pic_enable_source = atpic_enable_source,	\
105339928Sjhb			.pic_disable_source = atpic_disable_source,	\
106339928Sjhb			.pic_eoi_source = (eoi),			\
107339928Sjhb			.pic_enable_intr = atpic_enable_intr,		\
108339928Sjhb			.pic_disable_intr = atpic_disable_intr,		\
109339928Sjhb			.pic_vector = atpic_vector,			\
110339928Sjhb			.pic_source_pending = atpic_source_pending,	\
111339928Sjhb			.pic_resume = atpic_resume,			\
112339928Sjhb			.pic_config_intr = atpic_config_intr,		\
113339928Sjhb			.pic_assign_cpu = atpic_assign_cpu		\
114339928Sjhb		},							\
115339928Sjhb		.at_ioaddr = (io),					\
116339928Sjhb		.at_irqbase = (base),					\
117339928Sjhb		.at_intbase = IDT_IO_INTS + (base),			\
118339928Sjhb		.at_imen = 0xff,					\
119339928Sjhb	}
120121985Sjhb
121121985Sjhb#define	INTSRC(irq)							\
122128929Sjhb	{ { &atpics[(irq) / 8].at_pic }, IDTVEC(atpic_intr ## irq ),	\
123329462Skib	    IDTVEC(atpic_intr ## irq ## _pti), (irq) % 8 }
124121985Sjhb
125121985Sjhbstruct atpic {
126121985Sjhb	struct pic at_pic;
127121985Sjhb	int	at_ioaddr;
128121985Sjhb	int	at_irqbase;
129121985Sjhb	uint8_t	at_intbase;
130339928Sjhb	uint8_t	at_imen;
131121985Sjhb};
132121985Sjhb
133121985Sjhbstruct atpic_intsrc {
134121985Sjhb	struct intsrc at_intsrc;
135329462Skib	inthand_t *at_intr, *at_intr_pti;
136128929Sjhb	int	at_irq;			/* Relative to PIC base. */
137128929Sjhb	enum intr_trigger at_trigger;
138122897Sjhb	u_long	at_count;
139122897Sjhb	u_long	at_straycount;
140121985Sjhb};
141121985Sjhb
142340016Sjhbstatic void atpic_register_sources(struct pic *pic);
143121985Sjhbstatic void atpic_enable_source(struct intsrc *isrc);
144133017Sscottlstatic void atpic_disable_source(struct intsrc *isrc, int eoi);
145121985Sjhbstatic void atpic_eoi_master(struct intsrc *isrc);
146121985Sjhbstatic void atpic_eoi_slave(struct intsrc *isrc);
147121985Sjhbstatic void atpic_enable_intr(struct intsrc *isrc);
148169391Sjhbstatic void atpic_disable_intr(struct intsrc *isrc);
149121985Sjhbstatic int atpic_vector(struct intsrc *isrc);
150255726Sgibbsstatic void atpic_resume(struct pic *pic, bool suspend_cancelled);
151121985Sjhbstatic int atpic_source_pending(struct intsrc *isrc);
152128931Sjhbstatic int atpic_config_intr(struct intsrc *isrc, enum intr_trigger trig,
153128931Sjhb    enum intr_polarity pol);
154195249Sjhbstatic int atpic_assign_cpu(struct intsrc *isrc, u_int apic_id);
155121985Sjhbstatic void i8259_init(struct atpic *pic, int slave);
156121985Sjhb
157121985Sjhbstatic struct atpic atpics[] = {
158339928Sjhb	ATPIC(IO_ICU1, 0, atpic_eoi_master),
159339928Sjhb	ATPIC(IO_ICU2, 8, atpic_eoi_slave)
160121985Sjhb};
161121985Sjhb
162121985Sjhbstatic struct atpic_intsrc atintrs[] = {
163121985Sjhb	INTSRC(0),
164121985Sjhb	INTSRC(1),
165121985Sjhb	INTSRC(2),
166121985Sjhb	INTSRC(3),
167121985Sjhb	INTSRC(4),
168121985Sjhb	INTSRC(5),
169121985Sjhb	INTSRC(6),
170121985Sjhb	INTSRC(7),
171121985Sjhb	INTSRC(8),
172121985Sjhb	INTSRC(9),
173121985Sjhb	INTSRC(10),
174121985Sjhb	INTSRC(11),
175121985Sjhb	INTSRC(12),
176121985Sjhb	INTSRC(13),
177121985Sjhb	INTSRC(14),
178121985Sjhb	INTSRC(15),
179121985Sjhb};
180121985Sjhb
181298308SpfgCTASSERT(nitems(atintrs) == NUM_ISA_IRQS);
182128875Sjhb
183133017Sscottlstatic __inline void
184133017Sscottl_atpic_eoi_master(struct intsrc *isrc)
185133017Sscottl{
186133017Sscottl
187133017Sscottl	KASSERT(isrc->is_pic == &atpics[MASTER].at_pic,
188133017Sscottl	    ("%s: mismatched pic", __func__));
189133017Sscottl#ifndef AUTO_EOI_1
190133017Sscottl	outb(atpics[MASTER].at_ioaddr, OCW2_EOI);
191133017Sscottl#endif
192133017Sscottl}
193133017Sscottl
194133017Sscottl/*
195133017Sscottl * The data sheet says no auto-EOI on slave, but it sometimes works.
196133017Sscottl * So, if AUTO_EOI_2 is enabled, we use it.
197133017Sscottl */
198133017Sscottlstatic __inline void
199133017Sscottl_atpic_eoi_slave(struct intsrc *isrc)
200133017Sscottl{
201133017Sscottl
202133017Sscottl	KASSERT(isrc->is_pic == &atpics[SLAVE].at_pic,
203133017Sscottl	    ("%s: mismatched pic", __func__));
204133017Sscottl#ifndef AUTO_EOI_2
205133017Sscottl	outb(atpics[SLAVE].at_ioaddr, OCW2_EOI);
206133017Sscottl#ifndef AUTO_EOI_1
207133017Sscottl	outb(atpics[MASTER].at_ioaddr, OCW2_EOI);
208133017Sscottl#endif
209133017Sscottl#endif
210133017Sscottl}
211133017Sscottl
212121985Sjhbstatic void
213340016Sjhbatpic_register_sources(struct pic *pic)
214340016Sjhb{
215340016Sjhb	struct atpic *ap = (struct atpic *)pic;
216340016Sjhb	struct atpic_intsrc *ai;
217340016Sjhb	int i;
218340016Sjhb
219340016Sjhb	/*
220340016Sjhb	 * If any of the ISA IRQs have an interrupt source already, then
221340016Sjhb	 * assume that the I/O APICs are being used and don't register any
222340016Sjhb	 * of our interrupt sources.  This makes sure we don't accidentally
223340016Sjhb	 * use mixed mode.  The "accidental" use could otherwise occur on
224340016Sjhb	 * machines that route the ACPI SCI interrupt to a different ISA
225340016Sjhb	 * IRQ (at least one machine routes it to IRQ 13) thus disabling
226340016Sjhb	 * that APIC ISA routing and allowing the ATPIC source for that IRQ
227340016Sjhb	 * to leak through.  We used to depend on this feature for routing
228340016Sjhb	 * IRQ0 via mixed mode, but now we don't use mixed mode at all.
229340016Sjhb	 *
230340016Sjhb	 * To avoid the slave not register sources after the master
231340016Sjhb	 * registers its sources, register all IRQs when this function is
232340016Sjhb	 * called on the master.
233340016Sjhb	 */
234340016Sjhb	if (ap != &atpics[MASTER])
235340016Sjhb		return;
236340016Sjhb	for (i = 0; i < NUM_ISA_IRQS; i++)
237340016Sjhb		if (intr_lookup_source(i) != NULL)
238340016Sjhb			return;
239340016Sjhb
240340016Sjhb	/* Loop through all interrupt sources and add them. */
241340016Sjhb	for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) {
242340016Sjhb		if (i == ICU_SLAVEID)
243340016Sjhb			continue;
244340016Sjhb		intr_register_source(&ai->at_intsrc);
245340016Sjhb	}
246340016Sjhb}
247340016Sjhb
248340016Sjhbstatic void
249121985Sjhbatpic_enable_source(struct intsrc *isrc)
250121985Sjhb{
251121985Sjhb	struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc;
252121985Sjhb	struct atpic *ap = (struct atpic *)isrc->is_pic;
253121985Sjhb
254177468Sjhb	spinlock_enter();
255339928Sjhb	if (ap->at_imen & IMEN_MASK(ai)) {
256339928Sjhb		ap->at_imen &= ~IMEN_MASK(ai);
257339928Sjhb		outb(ap->at_ioaddr + ICU_IMR_OFFSET, ap->at_imen);
258128875Sjhb	}
259177468Sjhb	spinlock_exit();
260121985Sjhb}
261121985Sjhb
262121985Sjhbstatic void
263133017Sscottlatpic_disable_source(struct intsrc *isrc, int eoi)
264121985Sjhb{
265121985Sjhb	struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc;
266121985Sjhb	struct atpic *ap = (struct atpic *)isrc->is_pic;
267121985Sjhb
268177468Sjhb	spinlock_enter();
269133017Sscottl	if (ai->at_trigger != INTR_TRIGGER_EDGE) {
270339928Sjhb		ap->at_imen |= IMEN_MASK(ai);
271339928Sjhb		outb(ap->at_ioaddr + ICU_IMR_OFFSET, ap->at_imen);
272133017Sscottl	}
273133017Sscottl
274133017Sscottl	/*
275133017Sscottl	 * Take care to call these functions directly instead of through
276133017Sscottl	 * a function pointer.  All of the referenced variables should
277133017Sscottl	 * still be hot in the cache.
278133017Sscottl	 */
279133017Sscottl	if (eoi == PIC_EOI) {
280133017Sscottl		if (isrc->is_pic == &atpics[MASTER].at_pic)
281133017Sscottl			_atpic_eoi_master(isrc);
282133017Sscottl		else
283133017Sscottl			_atpic_eoi_slave(isrc);
284133017Sscottl	}
285133017Sscottl
286177468Sjhb	spinlock_exit();
287121985Sjhb}
288121985Sjhb
289121985Sjhbstatic void
290121985Sjhbatpic_eoi_master(struct intsrc *isrc)
291121985Sjhb{
292121985Sjhb#ifndef AUTO_EOI_1
293177468Sjhb	spinlock_enter();
294133017Sscottl	_atpic_eoi_master(isrc);
295177468Sjhb	spinlock_exit();
296121985Sjhb#endif
297121985Sjhb}
298121985Sjhb
299121985Sjhbstatic void
300121985Sjhbatpic_eoi_slave(struct intsrc *isrc)
301121985Sjhb{
302121985Sjhb#ifndef AUTO_EOI_2
303177468Sjhb	spinlock_enter();
304133017Sscottl	_atpic_eoi_slave(isrc);
305177468Sjhb	spinlock_exit();
306121985Sjhb#endif
307121985Sjhb}
308121985Sjhb
309121985Sjhbstatic void
310121985Sjhbatpic_enable_intr(struct intsrc *isrc)
311121985Sjhb{
312121985Sjhb}
313121985Sjhb
314169391Sjhbstatic void
315169391Sjhbatpic_disable_intr(struct intsrc *isrc)
316169391Sjhb{
317169391Sjhb}
318169391Sjhb
319169391Sjhb
320121985Sjhbstatic int
321121985Sjhbatpic_vector(struct intsrc *isrc)
322121985Sjhb{
323121985Sjhb	struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc;
324121985Sjhb	struct atpic *ap = (struct atpic *)isrc->is_pic;
325121985Sjhb
326121985Sjhb	return (IRQ(ap, ai));
327121985Sjhb}
328121985Sjhb
329121985Sjhbstatic int
330121985Sjhbatpic_source_pending(struct intsrc *isrc)
331121985Sjhb{
332121985Sjhb	struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc;
333121985Sjhb	struct atpic *ap = (struct atpic *)isrc->is_pic;
334121985Sjhb
335128875Sjhb	return (inb(ap->at_ioaddr) & IMEN_MASK(ai));
336121985Sjhb}
337121985Sjhb
338121985Sjhbstatic void
339255726Sgibbsatpic_resume(struct pic *pic, bool suspend_cancelled)
340121985Sjhb{
341163219Sjhb	struct atpic *ap = (struct atpic *)pic;
342121985Sjhb
343163219Sjhb	i8259_init(ap, ap == &atpics[SLAVE]);
344129009Snyan#ifndef PC98
345163219Sjhb	if (ap == &atpics[SLAVE] && elcr_found)
346163219Sjhb		elcr_resume();
347129009Snyan#endif
348121985Sjhb}
349121985Sjhb
350128931Sjhbstatic int
351128931Sjhbatpic_config_intr(struct intsrc *isrc, enum intr_trigger trig,
352128931Sjhb    enum intr_polarity pol)
353128931Sjhb{
354128931Sjhb	struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc;
355128931Sjhb	u_int vector;
356128931Sjhb
357128931Sjhb	/* Map conforming values to edge/hi and sanity check the values. */
358128931Sjhb	if (trig == INTR_TRIGGER_CONFORM)
359128931Sjhb		trig = INTR_TRIGGER_EDGE;
360128931Sjhb	if (pol == INTR_POLARITY_CONFORM)
361128931Sjhb		pol = INTR_POLARITY_HIGH;
362128931Sjhb	vector = atpic_vector(isrc);
363128931Sjhb	if ((trig == INTR_TRIGGER_EDGE && pol == INTR_POLARITY_LOW) ||
364128931Sjhb	    (trig == INTR_TRIGGER_LEVEL && pol == INTR_POLARITY_HIGH)) {
365128931Sjhb		printf(
366128931Sjhb		"atpic: Mismatched config for IRQ%u: trigger %s, polarity %s\n",
367128931Sjhb		    vector, trig == INTR_TRIGGER_EDGE ? "edge" : "level",
368128931Sjhb		    pol == INTR_POLARITY_HIGH ? "high" : "low");
369128931Sjhb		return (EINVAL);
370128931Sjhb	}
371128931Sjhb
372128931Sjhb	/* If there is no change, just return. */
373128931Sjhb	if (ai->at_trigger == trig)
374128931Sjhb		return (0);
375128931Sjhb
376129009Snyan#ifdef PC98
377129009Snyan	if ((vector == 0 || vector == 1 || vector == 7 || vector == 8) &&
378129009Snyan	    trig == INTR_TRIGGER_LEVEL) {
379129009Snyan		if (bootverbose)
380129009Snyan			printf(
381129009Snyan		"atpic: Ignoring invalid level/low configuration for IRQ%u\n",
382129009Snyan			    vector);
383129009Snyan		return (EINVAL);
384129009Snyan	}
385129009Snyan	return (ENXIO);
386129009Snyan#else
387128931Sjhb	/*
388128931Sjhb	 * Certain IRQs can never be level/lo, so don't try to set them
389128931Sjhb	 * that way if asked.  At least some ELCR registers ignore setting
390128931Sjhb	 * these bits as well.
391128931Sjhb	 */
392128931Sjhb	if ((vector == 0 || vector == 1 || vector == 2 || vector == 13) &&
393128931Sjhb	    trig == INTR_TRIGGER_LEVEL) {
394128931Sjhb		if (bootverbose)
395128931Sjhb			printf(
396128931Sjhb		"atpic: Ignoring invalid level/low configuration for IRQ%u\n",
397128931Sjhb			    vector);
398128931Sjhb		return (EINVAL);
399128931Sjhb	}
400140451Sjhb	if (!elcr_found) {
401128931Sjhb		if (bootverbose)
402128931Sjhb			printf("atpic: No ELCR to configure IRQ%u as %s\n",
403128931Sjhb			    vector, trig == INTR_TRIGGER_EDGE ? "edge/high" :
404128931Sjhb			    "level/low");
405128931Sjhb		return (ENXIO);
406128931Sjhb	}
407128931Sjhb	if (bootverbose)
408128931Sjhb		printf("atpic: Programming IRQ%u as %s\n", vector,
409128931Sjhb		    trig == INTR_TRIGGER_EDGE ? "edge/high" : "level/low");
410177468Sjhb	spinlock_enter();
411128931Sjhb	elcr_write_trigger(atpic_vector(isrc), trig);
412128931Sjhb	ai->at_trigger = trig;
413177468Sjhb	spinlock_exit();
414128931Sjhb	return (0);
415129009Snyan#endif /* PC98 */
416128931Sjhb}
417128931Sjhb
418195249Sjhbstatic int
419156124Sjhbatpic_assign_cpu(struct intsrc *isrc, u_int apic_id)
420156124Sjhb{
421156124Sjhb
422156124Sjhb	/*
423156124Sjhb	 * 8259A's are only used in UP in which case all interrupts always
424156124Sjhb	 * go to the sole CPU and this function shouldn't even be called.
425156124Sjhb	 */
426156124Sjhb	panic("%s: bad cookie", __func__);
427156124Sjhb}
428156124Sjhb
429156124Sjhbstatic void
430121985Sjhbi8259_init(struct atpic *pic, int slave)
431121985Sjhb{
432121985Sjhb	int imr_addr;
433121985Sjhb
434121985Sjhb	/* Reset the PIC and program with next four bytes. */
435177468Sjhb	spinlock_enter();
436121985Sjhb#ifdef DEV_MCA
437122692Sjhb	/* MCA uses level triggered interrupts. */
438121985Sjhb	if (MCA_system)
439122692Sjhb		outb(pic->at_ioaddr, ICW1_RESET | ICW1_IC4 | ICW1_LTIM);
440121985Sjhb	else
441121985Sjhb#endif
442122692Sjhb		outb(pic->at_ioaddr, ICW1_RESET | ICW1_IC4);
443121985Sjhb	imr_addr = pic->at_ioaddr + ICU_IMR_OFFSET;
444121985Sjhb
445121985Sjhb	/* Start vector. */
446121985Sjhb	outb(imr_addr, pic->at_intbase);
447121985Sjhb
448121985Sjhb	/*
449121985Sjhb	 * Setup slave links.  For the master pic, indicate what line
450121985Sjhb	 * the slave is configured on.  For the slave indicate
451121985Sjhb	 * which line on the master we are connected to.
452121985Sjhb	 */
453121985Sjhb	if (slave)
454129131Sjhb		outb(imr_addr, ICU_SLAVEID);
455121985Sjhb	else
456129131Sjhb		outb(imr_addr, IRQ_MASK(ICU_SLAVEID));
457121985Sjhb
458121985Sjhb	/* Set mode. */
459121985Sjhb	if (slave)
460121985Sjhb		outb(imr_addr, SLAVE_MODE);
461121985Sjhb	else
462121985Sjhb		outb(imr_addr, MASTER_MODE);
463121985Sjhb
464121985Sjhb	/* Set interrupt enable mask. */
465339928Sjhb	outb(imr_addr, pic->at_imen);
466121985Sjhb
467121985Sjhb	/* Reset is finished, default to IRR on read. */
468122692Sjhb	outb(pic->at_ioaddr, OCW3_SEL | OCW3_RR);
469121985Sjhb
470121985Sjhb#ifndef PC98
471122692Sjhb	/* OCW2_L1 sets priority order to 3-7, 0-2 (com2 first). */
472121985Sjhb	if (!slave)
473122692Sjhb		outb(pic->at_ioaddr, OCW2_R | OCW2_SL | OCW2_L1);
474121985Sjhb#endif
475177468Sjhb	spinlock_exit();
476121985Sjhb}
477121985Sjhb
478121985Sjhbvoid
479121985Sjhbatpic_startup(void)
480121985Sjhb{
481122897Sjhb	struct atpic_intsrc *ai;
482122897Sjhb	int i;
483121985Sjhb
484121985Sjhb	/* Start off with all interrupts disabled. */
485121985Sjhb	i8259_init(&atpics[MASTER], 0);
486121985Sjhb	i8259_init(&atpics[SLAVE], 1);
487121985Sjhb	atpic_enable_source((struct intsrc *)&atintrs[ICU_SLAVEID]);
488122897Sjhb
489122897Sjhb	/* Install low-level interrupt handlers for all of our IRQs. */
490128875Sjhb	for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) {
491122897Sjhb		if (i == ICU_SLAVEID)
492122897Sjhb			continue;
493122897Sjhb		ai->at_intsrc.is_count = &ai->at_count;
494122897Sjhb		ai->at_intsrc.is_straycount = &ai->at_straycount;
495122897Sjhb		setidt(((struct atpic *)ai->at_intsrc.is_pic)->at_intbase +
496329462Skib		    ai->at_irq, pti ? ai->at_intr_pti : ai->at_intr, SDT_ATPIC,
497329462Skib		    SEL_KPL, GSEL_ATPIC);
498122897Sjhb	}
499128929Sjhb
500128929Sjhb#ifdef DEV_MCA
501128929Sjhb	/* For MCA systems, all interrupts are level triggered. */
502128929Sjhb	if (MCA_system)
503128929Sjhb		for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++)
504128929Sjhb			ai->at_trigger = INTR_TRIGGER_LEVEL;
505128929Sjhb	else
506128929Sjhb#endif
507128929Sjhb
508129009Snyan#ifdef PC98
509129009Snyan	for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++)
510129009Snyan		switch (i) {
511129009Snyan		case 0:
512129009Snyan		case 1:
513129009Snyan		case 7:
514129009Snyan		case 8:
515129009Snyan			ai->at_trigger = INTR_TRIGGER_EDGE;
516129009Snyan			break;
517129009Snyan		default:
518129009Snyan			ai->at_trigger = INTR_TRIGGER_LEVEL;
519129009Snyan			break;
520129009Snyan		}
521129009Snyan#else
522128929Sjhb	/*
523128929Sjhb	 * Look for an ELCR.  If we find one, update the trigger modes.
524128929Sjhb	 * If we don't find one, assume that IRQs 0, 1, 2, and 13 are
525128929Sjhb	 * edge triggered and that everything else is level triggered.
526128929Sjhb	 * We only use the trigger information to reprogram the ELCR if
527128929Sjhb	 * we have one and as an optimization to avoid masking edge
528128929Sjhb	 * triggered interrupts.  For the case that we don't have an ELCR,
529128929Sjhb	 * it doesn't hurt to mask an edge triggered interrupt, so we
530129095Sjhb	 * assume level trigger for any interrupt that we aren't sure is
531129095Sjhb	 * edge triggered.
532128929Sjhb	 */
533140451Sjhb	if (elcr_found) {
534128929Sjhb		for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++)
535128929Sjhb			ai->at_trigger = elcr_read_trigger(i);
536128929Sjhb	} else {
537128929Sjhb		for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++)
538128929Sjhb			switch (i) {
539128929Sjhb			case 0:
540128929Sjhb			case 1:
541128929Sjhb			case 2:
542128929Sjhb			case 8:
543128929Sjhb			case 13:
544128929Sjhb				ai->at_trigger = INTR_TRIGGER_EDGE;
545128929Sjhb				break;
546128929Sjhb			default:
547128929Sjhb				ai->at_trigger = INTR_TRIGGER_LEVEL;
548128929Sjhb				break;
549128929Sjhb			}
550128929Sjhb	}
551129009Snyan#endif /* PC98 */
552121985Sjhb}
553121985Sjhb
554121985Sjhbstatic void
555121985Sjhbatpic_init(void *dummy __unused)
556121985Sjhb{
557121985Sjhb
558153136Sjhb	/*
559163219Sjhb	 * Register our PICs, even if we aren't going to use any of their
560163219Sjhb	 * pins so that they are suspended and resumed.
561163219Sjhb	 */
562163219Sjhb	if (intr_register_pic(&atpics[0].at_pic) != 0 ||
563163219Sjhb	    intr_register_pic(&atpics[1].at_pic) != 0)
564163219Sjhb		panic("Unable to register ATPICs");
565163219Sjhb
566340016Sjhb	if (num_io_irqs == 0)
567340016Sjhb		num_io_irqs = NUM_ISA_IRQS;
568121985Sjhb}
569269675SroygerSYSINIT(atpic_init, SI_SUB_INTR, SI_ORDER_FOURTH, atpic_init, NULL);
570121985Sjhb
571121985Sjhbvoid
572165302Skmacyatpic_handle_intr(u_int vector, struct trapframe *frame)
573121985Sjhb{
574121985Sjhb	struct intsrc *isrc;
575121985Sjhb
576153242Sjhb	KASSERT(vector < NUM_ISA_IRQS, ("unknown int %u\n", vector));
577153146Sjhb	isrc = &atintrs[vector].at_intsrc;
578122898Sjhb
579122898Sjhb	/*
580151658Sjhb	 * If we don't have an event, see if this is a spurious
581122898Sjhb	 * interrupt.
582122898Sjhb	 */
583153146Sjhb	if (isrc->is_event == NULL && (vector == 7 || vector == 15)) {
584122898Sjhb		int port, isr;
585122898Sjhb
586122898Sjhb		/*
587122898Sjhb		 * Read the ISR register to see if IRQ 7/15 is really
588122898Sjhb		 * pending.  Reset read register back to IRR when done.
589122898Sjhb		 */
590122898Sjhb		port = ((struct atpic *)isrc->is_pic)->at_ioaddr;
591177468Sjhb		spinlock_enter();
592122898Sjhb		outb(port, OCW3_SEL | OCW3_RR | OCW3_RIS);
593122898Sjhb		isr = inb(port);
594122898Sjhb		outb(port, OCW3_SEL | OCW3_RR);
595177468Sjhb		spinlock_exit();
596129131Sjhb		if ((isr & IRQ_MASK(7)) == 0)
597122898Sjhb			return;
598122898Sjhb	}
599165302Skmacy	intr_execute_handlers(isrc, frame);
600121985Sjhb}
601121985Sjhb
602121985Sjhb#ifdef DEV_ISA
603121985Sjhb/*
604121985Sjhb * Bus attachment for the ISA PIC.
605121985Sjhb */
606121985Sjhbstatic struct isa_pnp_id atpic_ids[] = {
607121985Sjhb	{ 0x0000d041 /* PNP0000 */, "AT interrupt controller" },
608121985Sjhb	{ 0 }
609121985Sjhb};
610121985Sjhb
611121985Sjhbstatic int
612121985Sjhbatpic_probe(device_t dev)
613121985Sjhb{
614121985Sjhb	int result;
615121985Sjhb
616121985Sjhb	result = ISA_PNP_PROBE(device_get_parent(dev), dev, atpic_ids);
617121985Sjhb	if (result <= 0)
618121985Sjhb		device_quiet(dev);
619121985Sjhb	return (result);
620121985Sjhb}
621121985Sjhb
622121985Sjhb/*
623121985Sjhb * We might be granted IRQ 2, as this is typically consumed by chaining
624121985Sjhb * between the two PIC components.  If we're using the APIC, however,
625121985Sjhb * this may not be the case, and as such we should free the resource.
626121985Sjhb * (XXX untested)
627121985Sjhb *
628121985Sjhb * The generic ISA attachment code will handle allocating any other resources
629121985Sjhb * that we don't explicitly claim here.
630121985Sjhb */
631121985Sjhbstatic int
632121985Sjhbatpic_attach(device_t dev)
633121985Sjhb{
634121985Sjhb	struct resource *res;
635121985Sjhb	int rid;
636121985Sjhb
637121985Sjhb	/* Try to allocate our IRQ and then free it. */
638121985Sjhb	rid = 0;
639127135Snjl	res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 0);
640121985Sjhb	if (res != NULL)
641121985Sjhb		bus_release_resource(dev, SYS_RES_IRQ, rid, res);
642121985Sjhb	return (0);
643121985Sjhb}
644121985Sjhb
645121985Sjhbstatic device_method_t atpic_methods[] = {
646121985Sjhb	/* Device interface */
647121985Sjhb	DEVMETHOD(device_probe,		atpic_probe),
648121985Sjhb	DEVMETHOD(device_attach,	atpic_attach),
649121985Sjhb	DEVMETHOD(device_detach,	bus_generic_detach),
650121985Sjhb	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
651121985Sjhb	DEVMETHOD(device_suspend,	bus_generic_suspend),
652121985Sjhb	DEVMETHOD(device_resume,	bus_generic_resume),
653121985Sjhb	{ 0, 0 }
654121985Sjhb};
655121985Sjhb
656121985Sjhbstatic driver_t atpic_driver = {
657121985Sjhb	"atpic",
658121985Sjhb	atpic_methods,
659121985Sjhb	1,		/* no softc */
660121985Sjhb};
661121985Sjhb
662121985Sjhbstatic devclass_t atpic_devclass;
663121985Sjhb
664121985SjhbDRIVER_MODULE(atpic, isa, atpic_driver, atpic_devclass, 0, 0);
665122051Snyan#ifndef PC98
666121985SjhbDRIVER_MODULE(atpic, acpi, atpic_driver, atpic_devclass, 0, 0);
667122051Snyan#endif
668121985Sjhb
669121985Sjhb/*
670121985Sjhb * Return a bitmap of the current interrupt requests.  This is 8259-specific
671121985Sjhb * and is only suitable for use at probe time.
672121985Sjhb */
673121985Sjhbintrmask_t
674121985Sjhbisa_irq_pending(void)
675121985Sjhb{
676121985Sjhb	u_char irr1;
677121985Sjhb	u_char irr2;
678121985Sjhb
679121985Sjhb	irr1 = inb(IO_ICU1);
680121985Sjhb	irr2 = inb(IO_ICU2);
681121985Sjhb	return ((irr2 << 8) | irr1);
682121985Sjhb}
683121985Sjhb#endif /* DEV_ISA */
684