atpic.c revision 128931
1/*-
2 * Copyright (c) 2003 John Baldwin <jhb@FreeBSD.org>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the author nor the names of any co-contributors
14 *    may be used to endorse or promote products derived from this software
15 *    without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30/*
31 * PIC driver for the 8259A Master and Slave PICs in PC/AT machines.
32 */
33
34#include <sys/cdefs.h>
35__FBSDID("$FreeBSD: head/sys/i386/isa/atpic.c 128931 2004-05-04 21:02:56Z jhb $");
36
37#include "opt_auto_eoi.h"
38#include "opt_isa.h"
39
40#include <sys/param.h>
41#include <sys/systm.h>
42#include <sys/bus.h>
43#include <sys/interrupt.h>
44#include <sys/kernel.h>
45#include <sys/lock.h>
46#include <sys/mutex.h>
47
48#include <machine/cpufunc.h>
49#include <machine/frame.h>
50#include <machine/intr_machdep.h>
51#include <machine/md_var.h>
52#include <machine/resource.h>
53#include <machine/segments.h>
54
55#include <dev/ic/i8259.h>
56#include <i386/isa/icu.h>
57#ifdef PC98
58#include <pc98/pc98/pc98.h>
59#else
60#include <i386/isa/isa.h>
61#endif
62#include <isa/isavar.h>
63
64#define	MASTER	0
65#define	SLAVE	1
66
67/*
68 * Determine the base master and slave modes not including auto EOI support.
69 * All machines that FreeBSD supports use 8086 mode.
70 */
71#ifdef PC98
72/*
73 * PC-98 machines do not support auto EOI on the second PIC.  Also, it
74 * seems that PC-98 machine PICs use buffered mode, and the master PIC
75 * uses special fully nested mode.
76 */
77#define	BASE_MASTER_MODE	(ICW4_SFNM | ICW4_BUF | ICW4_MS | ICW4_8086)
78#define	BASE_SLAVE_MODE		(ICW4_BUF | ICW4_8086)
79#else
80#define	BASE_MASTER_MODE	ICW4_8086
81#define	BASE_SLAVE_MODE		ICW4_8086
82#endif
83
84/* Enable automatic EOI if requested. */
85#ifdef AUTO_EOI_1
86#define	MASTER_MODE		(BASE_MASTER_MODE | ICW4_AEOI)
87#else
88#define	MASTER_MODE		BASE_MASTER_MODE
89#endif
90#ifdef AUTO_EOI_2
91#define	SLAVE_MODE		(BASE_SLAVE_MODE | ICW4_AEOI)
92#else
93#define	SLAVE_MODE		BASE_SLAVE_MODE
94#endif
95
96#define	IMEN_MASK(ai)		(1 << (ai)->at_irq)
97
98#define	NUM_ISA_IRQS		16
99
100static void	atpic_init(void *dummy);
101
102unsigned int imen;	/* XXX */
103static int using_elcr;
104
105inthand_t
106	IDTVEC(atpic_intr0), IDTVEC(atpic_intr1), IDTVEC(atpic_intr2),
107	IDTVEC(atpic_intr3), IDTVEC(atpic_intr4), IDTVEC(atpic_intr5),
108	IDTVEC(atpic_intr6), IDTVEC(atpic_intr7), IDTVEC(atpic_intr8),
109	IDTVEC(atpic_intr9), IDTVEC(atpic_intr10), IDTVEC(atpic_intr11),
110	IDTVEC(atpic_intr12), IDTVEC(atpic_intr13), IDTVEC(atpic_intr14),
111	IDTVEC(atpic_intr15);
112
113#define	IRQ(ap, ai)	((ap)->at_irqbase + (ai)->at_irq)
114
115#define	ATPIC(io, base, eoi, imenptr)					\
116     	{ { atpic_enable_source, atpic_disable_source, (eoi),		\
117	    atpic_enable_intr, atpic_vector, atpic_source_pending, NULL, \
118	    atpic_resume, atpic_config_intr }, (io), (base),		\
119	    IDT_IO_INTS + (base), (imenptr) }
120
121#define	INTSRC(irq)							\
122	{ { &atpics[(irq) / 8].at_pic }, IDTVEC(atpic_intr ## irq ),	\
123	    (irq) % 8 }
124
125struct atpic {
126	struct pic at_pic;
127	int	at_ioaddr;
128	int	at_irqbase;
129	uint8_t	at_intbase;
130	uint8_t	*at_imen;
131};
132
133struct atpic_intsrc {
134	struct intsrc at_intsrc;
135	inthand_t *at_intr;
136	int	at_irq;			/* Relative to PIC base. */
137	enum intr_trigger at_trigger;
138	u_long	at_count;
139	u_long	at_straycount;
140};
141
142static void atpic_enable_source(struct intsrc *isrc);
143static void atpic_disable_source(struct intsrc *isrc);
144static void atpic_eoi_master(struct intsrc *isrc);
145static void atpic_eoi_slave(struct intsrc *isrc);
146static void atpic_enable_intr(struct intsrc *isrc);
147static int atpic_vector(struct intsrc *isrc);
148static void atpic_resume(struct intsrc *isrc);
149static int atpic_source_pending(struct intsrc *isrc);
150static int atpic_config_intr(struct intsrc *isrc, enum intr_trigger trig,
151    enum intr_polarity pol);
152static void i8259_init(struct atpic *pic, int slave);
153
154static struct atpic atpics[] = {
155	ATPIC(IO_ICU1, 0, atpic_eoi_master, (uint8_t *)&imen),
156	ATPIC(IO_ICU2, 8, atpic_eoi_slave, ((uint8_t *)&imen) + 1)
157};
158
159static struct atpic_intsrc atintrs[] = {
160	INTSRC(0),
161	INTSRC(1),
162	INTSRC(2),
163	INTSRC(3),
164	INTSRC(4),
165	INTSRC(5),
166	INTSRC(6),
167	INTSRC(7),
168	INTSRC(8),
169	INTSRC(9),
170	INTSRC(10),
171	INTSRC(11),
172	INTSRC(12),
173	INTSRC(13),
174	INTSRC(14),
175	INTSRC(15),
176};
177
178CTASSERT(sizeof(atintrs) / sizeof(struct atpic_intsrc) == NUM_ISA_IRQS);
179
180static void
181atpic_enable_source(struct intsrc *isrc)
182{
183	struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc;
184	struct atpic *ap = (struct atpic *)isrc->is_pic;
185
186	mtx_lock_spin(&icu_lock);
187	if (*ap->at_imen & IMEN_MASK(ai)) {
188		*ap->at_imen &= ~IMEN_MASK(ai);
189		outb(ap->at_ioaddr + ICU_IMR_OFFSET, *ap->at_imen);
190	}
191	mtx_unlock_spin(&icu_lock);
192}
193
194static void
195atpic_disable_source(struct intsrc *isrc)
196{
197	struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc;
198	struct atpic *ap = (struct atpic *)isrc->is_pic;
199
200	if (ai->at_trigger == INTR_TRIGGER_EDGE)
201		return;
202	mtx_lock_spin(&icu_lock);
203	*ap->at_imen |= IMEN_MASK(ai);
204	outb(ap->at_ioaddr + ICU_IMR_OFFSET, *ap->at_imen);
205	mtx_unlock_spin(&icu_lock);
206}
207
208static void
209atpic_eoi_master(struct intsrc *isrc)
210{
211
212	KASSERT(isrc->is_pic == &atpics[MASTER].at_pic,
213	    ("%s: mismatched pic", __func__));
214#ifndef AUTO_EOI_1
215	mtx_lock_spin(&icu_lock);
216	outb(atpics[MASTER].at_ioaddr, ICU_EOI);
217	mtx_unlock_spin(&icu_lock);
218#endif
219}
220
221/*
222 * The data sheet says no auto-EOI on slave, but it sometimes works.
223 * So, if AUTO_EOI_2 is enabled, we use it.
224 */
225static void
226atpic_eoi_slave(struct intsrc *isrc)
227{
228
229	KASSERT(isrc->is_pic == &atpics[SLAVE].at_pic,
230	    ("%s: mismatched pic", __func__));
231#ifndef AUTO_EOI_2
232	mtx_lock_spin(&icu_lock);
233	outb(atpics[SLAVE].at_ioaddr, ICU_EOI);
234#ifndef AUTO_EOI_1
235	outb(atpics[MASTER].at_ioaddr, ICU_EOI);
236#endif
237	mtx_unlock_spin(&icu_lock);
238#endif
239}
240
241static void
242atpic_enable_intr(struct intsrc *isrc)
243{
244}
245
246static int
247atpic_vector(struct intsrc *isrc)
248{
249	struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc;
250	struct atpic *ap = (struct atpic *)isrc->is_pic;
251
252	return (IRQ(ap, ai));
253}
254
255static int
256atpic_source_pending(struct intsrc *isrc)
257{
258	struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc;
259	struct atpic *ap = (struct atpic *)isrc->is_pic;
260
261	return (inb(ap->at_ioaddr) & IMEN_MASK(ai));
262}
263
264static void
265atpic_resume(struct intsrc *isrc)
266{
267	struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc;
268	struct atpic *ap = (struct atpic *)isrc->is_pic;
269
270	if (ai->at_irq == 0) {
271		i8259_init(ap, ap == &atpics[SLAVE]);
272		if (ap == &atpics[SLAVE] && using_elcr)
273			elcr_resume();
274	}
275}
276
277static int
278atpic_config_intr(struct intsrc *isrc, enum intr_trigger trig,
279    enum intr_polarity pol)
280{
281	struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc;
282	u_int vector;
283
284	/* Map conforming values to edge/hi and sanity check the values. */
285	if (trig == INTR_TRIGGER_CONFORM)
286		trig = INTR_TRIGGER_EDGE;
287	if (pol == INTR_POLARITY_CONFORM)
288		pol = INTR_POLARITY_HIGH;
289	vector = atpic_vector(isrc);
290	if ((trig == INTR_TRIGGER_EDGE && pol == INTR_POLARITY_LOW) ||
291	    (trig == INTR_TRIGGER_LEVEL && pol == INTR_POLARITY_HIGH)) {
292		printf(
293		"atpic: Mismatched config for IRQ%u: trigger %s, polarity %s\n",
294		    vector, trig == INTR_TRIGGER_EDGE ? "edge" : "level",
295		    pol == INTR_POLARITY_HIGH ? "high" : "low");
296		return (EINVAL);
297	}
298
299	/* If there is no change, just return. */
300	if (ai->at_trigger == trig)
301		return (0);
302
303	/*
304	 * Certain IRQs can never be level/lo, so don't try to set them
305	 * that way if asked.  At least some ELCR registers ignore setting
306	 * these bits as well.
307	 */
308	if ((vector == 0 || vector == 1 || vector == 2 || vector == 13) &&
309	    trig == INTR_TRIGGER_LEVEL) {
310		if (bootverbose)
311			printf(
312		"atpic: Ignoring invalid level/low configuration for IRQ%u\n",
313			    vector);
314		return (EINVAL);
315	}
316	if (!using_elcr) {
317		if (bootverbose)
318			printf("atpic: No ELCR to configure IRQ%u as %s\n",
319			    vector, trig == INTR_TRIGGER_EDGE ? "edge/high" :
320			    "level/low");
321		return (ENXIO);
322	}
323	if (bootverbose)
324		printf("atpic: Programming IRQ%u as %s\n", vector,
325		    trig == INTR_TRIGGER_EDGE ? "edge/high" : "level/low");
326	mtx_lock_spin(&icu_lock);
327	elcr_write_trigger(atpic_vector(isrc), trig);
328	ai->at_trigger = trig;
329	mtx_unlock_spin(&icu_lock);
330	return (0);
331}
332
333static void
334i8259_init(struct atpic *pic, int slave)
335{
336	int imr_addr;
337
338	/* Reset the PIC and program with next four bytes. */
339	mtx_lock_spin(&icu_lock);
340#ifdef DEV_MCA
341	/* MCA uses level triggered interrupts. */
342	if (MCA_system)
343		outb(pic->at_ioaddr, ICW1_RESET | ICW1_IC4 | ICW1_LTIM);
344	else
345#endif
346		outb(pic->at_ioaddr, ICW1_RESET | ICW1_IC4);
347	imr_addr = pic->at_ioaddr + ICU_IMR_OFFSET;
348
349	/* Start vector. */
350	outb(imr_addr, pic->at_intbase);
351
352	/*
353	 * Setup slave links.  For the master pic, indicate what line
354	 * the slave is configured on.  For the slave indicate
355	 * which line on the master we are connected to.
356	 */
357	if (slave)
358		outb(imr_addr, ICU_SLAVEID);	/* my slave id is 7 */
359	else
360		outb(imr_addr, IRQ_SLAVE);	/* slave on line 7 */
361
362	/* Set mode. */
363	if (slave)
364		outb(imr_addr, SLAVE_MODE);
365	else
366		outb(imr_addr, MASTER_MODE);
367
368	/* Set interrupt enable mask. */
369	outb(imr_addr, *pic->at_imen);
370
371	/* Reset is finished, default to IRR on read. */
372	outb(pic->at_ioaddr, OCW3_SEL | OCW3_RR);
373
374#ifndef PC98
375	/* OCW2_L1 sets priority order to 3-7, 0-2 (com2 first). */
376	if (!slave)
377		outb(pic->at_ioaddr, OCW2_R | OCW2_SL | OCW2_L1);
378#endif
379	mtx_unlock_spin(&icu_lock);
380}
381
382void
383atpic_startup(void)
384{
385	struct atpic_intsrc *ai;
386	int i;
387
388	/* Start off with all interrupts disabled. */
389	imen = 0xffff;
390	i8259_init(&atpics[MASTER], 0);
391	i8259_init(&atpics[SLAVE], 1);
392	atpic_enable_source((struct intsrc *)&atintrs[ICU_SLAVEID]);
393
394	/* Install low-level interrupt handlers for all of our IRQs. */
395	for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) {
396		if (i == ICU_SLAVEID)
397			continue;
398		ai->at_intsrc.is_count = &ai->at_count;
399		ai->at_intsrc.is_straycount = &ai->at_straycount;
400		setidt(((struct atpic *)ai->at_intsrc.is_pic)->at_intbase +
401		    ai->at_irq, ai->at_intr, SDT_SYS386IGT, SEL_KPL,
402		    GSEL(GCODE_SEL, SEL_KPL));
403	}
404
405#ifdef DEV_MCA
406	/* For MCA systems, all interrupts are level triggered. */
407	if (MCA_system)
408		for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++)
409			ai->at_trigger = INTR_TRIGGER_LEVEL;
410	else
411#endif
412
413	/*
414	 * Look for an ELCR.  If we find one, update the trigger modes.
415	 * If we don't find one, assume that IRQs 0, 1, 2, and 13 are
416	 * edge triggered and that everything else is level triggered.
417	 * We only use the trigger information to reprogram the ELCR if
418	 * we have one and as an optimization to avoid masking edge
419	 * triggered interrupts.  For the case that we don't have an ELCR,
420	 * it doesn't hurt to mask an edge triggered interrupt, so we
421	 * that is why we assume level trigger for any interrupt that we
422	 * aren't sure is edge triggered.
423	 */
424	if (elcr_probe() == 0) {
425		using_elcr = 1;
426		for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++)
427			ai->at_trigger = elcr_read_trigger(i);
428	} else {
429		for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++)
430			switch (i) {
431			case 0:
432			case 1:
433			case 2:
434			case 8:
435			case 13:
436				ai->at_trigger = INTR_TRIGGER_EDGE;
437				break;
438			default:
439				ai->at_trigger = INTR_TRIGGER_LEVEL;
440				break;
441			}
442	}
443}
444
445static void
446atpic_init(void *dummy __unused)
447{
448	struct atpic_intsrc *ai;
449	int i;
450
451	/* Loop through all interrupt sources and add them. */
452	for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) {
453		if (i == ICU_SLAVEID)
454			continue;
455		intr_register_source(&ai->at_intsrc);
456	}
457}
458SYSINIT(atpic_init, SI_SUB_INTR, SI_ORDER_SECOND + 1, atpic_init, NULL)
459
460void
461atpic_handle_intr(struct intrframe iframe)
462{
463	struct intsrc *isrc;
464
465	KASSERT((u_int)iframe.if_vec < ICU_LEN,
466	    ("unknown int %d\n", iframe.if_vec));
467	isrc = &atintrs[iframe.if_vec].at_intsrc;
468
469	/*
470	 * If we don't have an ithread, see if this is a spurious
471	 * interrupt.
472	 */
473	if (isrc->is_ithread == NULL &&
474	    (iframe.if_vec == 7 || iframe.if_vec == 15)) {
475		int port, isr;
476
477		/*
478		 * Read the ISR register to see if IRQ 7/15 is really
479		 * pending.  Reset read register back to IRR when done.
480		 */
481		port = ((struct atpic *)isrc->is_pic)->at_ioaddr;
482		mtx_lock_spin(&icu_lock);
483		outb(port, OCW3_SEL | OCW3_RR | OCW3_RIS);
484		isr = inb(port);
485		outb(port, OCW3_SEL | OCW3_RR);
486		mtx_unlock_spin(&icu_lock);
487		if ((isr & IRQ7) == 0)
488			return;
489	}
490	intr_execute_handlers(isrc, &iframe);
491}
492
493#ifdef DEV_ISA
494/*
495 * Bus attachment for the ISA PIC.
496 */
497static struct isa_pnp_id atpic_ids[] = {
498	{ 0x0000d041 /* PNP0000 */, "AT interrupt controller" },
499	{ 0 }
500};
501
502static int
503atpic_probe(device_t dev)
504{
505	int result;
506
507	result = ISA_PNP_PROBE(device_get_parent(dev), dev, atpic_ids);
508	if (result <= 0)
509		device_quiet(dev);
510	return (result);
511}
512
513/*
514 * We might be granted IRQ 2, as this is typically consumed by chaining
515 * between the two PIC components.  If we're using the APIC, however,
516 * this may not be the case, and as such we should free the resource.
517 * (XXX untested)
518 *
519 * The generic ISA attachment code will handle allocating any other resources
520 * that we don't explicitly claim here.
521 */
522static int
523atpic_attach(device_t dev)
524{
525	struct resource *res;
526	int rid;
527
528	/* Try to allocate our IRQ and then free it. */
529	rid = 0;
530	res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 0);
531	if (res != NULL)
532		bus_release_resource(dev, SYS_RES_IRQ, rid, res);
533	return (0);
534}
535
536static device_method_t atpic_methods[] = {
537	/* Device interface */
538	DEVMETHOD(device_probe,		atpic_probe),
539	DEVMETHOD(device_attach,	atpic_attach),
540	DEVMETHOD(device_detach,	bus_generic_detach),
541	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
542	DEVMETHOD(device_suspend,	bus_generic_suspend),
543	DEVMETHOD(device_resume,	bus_generic_resume),
544	{ 0, 0 }
545};
546
547static driver_t atpic_driver = {
548	"atpic",
549	atpic_methods,
550	1,		/* no softc */
551};
552
553static devclass_t atpic_devclass;
554
555DRIVER_MODULE(atpic, isa, atpic_driver, atpic_devclass, 0, 0);
556#ifndef PC98
557DRIVER_MODULE(atpic, acpi, atpic_driver, atpic_devclass, 0, 0);
558#endif
559
560/*
561 * Return a bitmap of the current interrupt requests.  This is 8259-specific
562 * and is only suitable for use at probe time.
563 */
564intrmask_t
565isa_irq_pending(void)
566{
567	u_char irr1;
568	u_char irr2;
569
570	irr1 = inb(IO_ICU1);
571	irr2 = inb(IO_ICU2);
572	return ((irr2 << 8) | irr1);
573}
574#endif /* DEV_ISA */
575