atpic.c revision 129095
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 129095 2004-05-10 18:33:52Z 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 */
103#ifndef PC98
104static int using_elcr;
105#endif
106
107inthand_t
108	IDTVEC(atpic_intr0), IDTVEC(atpic_intr1), IDTVEC(atpic_intr2),
109	IDTVEC(atpic_intr3), IDTVEC(atpic_intr4), IDTVEC(atpic_intr5),
110	IDTVEC(atpic_intr6), IDTVEC(atpic_intr7), IDTVEC(atpic_intr8),
111	IDTVEC(atpic_intr9), IDTVEC(atpic_intr10), IDTVEC(atpic_intr11),
112	IDTVEC(atpic_intr12), IDTVEC(atpic_intr13), IDTVEC(atpic_intr14),
113	IDTVEC(atpic_intr15);
114
115#define	IRQ(ap, ai)	((ap)->at_irqbase + (ai)->at_irq)
116
117#define	ATPIC(io, base, eoi, imenptr)					\
118     	{ { atpic_enable_source, atpic_disable_source, (eoi),		\
119	    atpic_enable_intr, atpic_vector, atpic_source_pending, NULL, \
120	    atpic_resume, atpic_config_intr }, (io), (base),		\
121	    IDT_IO_INTS + (base), (imenptr) }
122
123#define	INTSRC(irq)							\
124	{ { &atpics[(irq) / 8].at_pic }, IDTVEC(atpic_intr ## irq ),	\
125	    (irq) % 8 }
126
127struct atpic {
128	struct pic at_pic;
129	int	at_ioaddr;
130	int	at_irqbase;
131	uint8_t	at_intbase;
132	uint8_t	*at_imen;
133};
134
135struct atpic_intsrc {
136	struct intsrc at_intsrc;
137	inthand_t *at_intr;
138	int	at_irq;			/* Relative to PIC base. */
139	enum intr_trigger at_trigger;
140	u_long	at_count;
141	u_long	at_straycount;
142};
143
144static void atpic_enable_source(struct intsrc *isrc);
145static void atpic_disable_source(struct intsrc *isrc);
146static void atpic_eoi_master(struct intsrc *isrc);
147static void atpic_eoi_slave(struct intsrc *isrc);
148static void atpic_enable_intr(struct intsrc *isrc);
149static int atpic_vector(struct intsrc *isrc);
150static void atpic_resume(struct intsrc *isrc);
151static int atpic_source_pending(struct intsrc *isrc);
152static int atpic_config_intr(struct intsrc *isrc, enum intr_trigger trig,
153    enum intr_polarity pol);
154static void i8259_init(struct atpic *pic, int slave);
155
156static struct atpic atpics[] = {
157	ATPIC(IO_ICU1, 0, atpic_eoi_master, (uint8_t *)&imen),
158	ATPIC(IO_ICU2, 8, atpic_eoi_slave, ((uint8_t *)&imen) + 1)
159};
160
161static struct atpic_intsrc atintrs[] = {
162	INTSRC(0),
163	INTSRC(1),
164	INTSRC(2),
165	INTSRC(3),
166	INTSRC(4),
167	INTSRC(5),
168	INTSRC(6),
169	INTSRC(7),
170	INTSRC(8),
171	INTSRC(9),
172	INTSRC(10),
173	INTSRC(11),
174	INTSRC(12),
175	INTSRC(13),
176	INTSRC(14),
177	INTSRC(15),
178};
179
180CTASSERT(sizeof(atintrs) / sizeof(atintrs[0]) == NUM_ISA_IRQS);
181
182static void
183atpic_enable_source(struct intsrc *isrc)
184{
185	struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc;
186	struct atpic *ap = (struct atpic *)isrc->is_pic;
187
188	mtx_lock_spin(&icu_lock);
189	if (*ap->at_imen & IMEN_MASK(ai)) {
190		*ap->at_imen &= ~IMEN_MASK(ai);
191		outb(ap->at_ioaddr + ICU_IMR_OFFSET, *ap->at_imen);
192	}
193	mtx_unlock_spin(&icu_lock);
194}
195
196static void
197atpic_disable_source(struct intsrc *isrc)
198{
199	struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc;
200	struct atpic *ap = (struct atpic *)isrc->is_pic;
201
202	if (ai->at_trigger == INTR_TRIGGER_EDGE)
203		return;
204	mtx_lock_spin(&icu_lock);
205	*ap->at_imen |= IMEN_MASK(ai);
206	outb(ap->at_ioaddr + ICU_IMR_OFFSET, *ap->at_imen);
207	mtx_unlock_spin(&icu_lock);
208}
209
210static void
211atpic_eoi_master(struct intsrc *isrc)
212{
213
214	KASSERT(isrc->is_pic == &atpics[MASTER].at_pic,
215	    ("%s: mismatched pic", __func__));
216#ifndef AUTO_EOI_1
217	mtx_lock_spin(&icu_lock);
218	outb(atpics[MASTER].at_ioaddr, ICU_EOI);
219	mtx_unlock_spin(&icu_lock);
220#endif
221}
222
223/*
224 * The data sheet says no auto-EOI on slave, but it sometimes works.
225 * So, if AUTO_EOI_2 is enabled, we use it.
226 */
227static void
228atpic_eoi_slave(struct intsrc *isrc)
229{
230
231	KASSERT(isrc->is_pic == &atpics[SLAVE].at_pic,
232	    ("%s: mismatched pic", __func__));
233#ifndef AUTO_EOI_2
234	mtx_lock_spin(&icu_lock);
235	outb(atpics[SLAVE].at_ioaddr, ICU_EOI);
236#ifndef AUTO_EOI_1
237	outb(atpics[MASTER].at_ioaddr, ICU_EOI);
238#endif
239	mtx_unlock_spin(&icu_lock);
240#endif
241}
242
243static void
244atpic_enable_intr(struct intsrc *isrc)
245{
246}
247
248static int
249atpic_vector(struct intsrc *isrc)
250{
251	struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc;
252	struct atpic *ap = (struct atpic *)isrc->is_pic;
253
254	return (IRQ(ap, ai));
255}
256
257static int
258atpic_source_pending(struct intsrc *isrc)
259{
260	struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc;
261	struct atpic *ap = (struct atpic *)isrc->is_pic;
262
263	return (inb(ap->at_ioaddr) & IMEN_MASK(ai));
264}
265
266static void
267atpic_resume(struct intsrc *isrc)
268{
269	struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc;
270	struct atpic *ap = (struct atpic *)isrc->is_pic;
271
272	if (ai->at_irq == 0) {
273		i8259_init(ap, ap == &atpics[SLAVE]);
274#ifndef PC98
275		if (ap == &atpics[SLAVE] && using_elcr)
276			elcr_resume();
277#endif
278	}
279}
280
281static int
282atpic_config_intr(struct intsrc *isrc, enum intr_trigger trig,
283    enum intr_polarity pol)
284{
285	struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc;
286	u_int vector;
287
288	/* Map conforming values to edge/hi and sanity check the values. */
289	if (trig == INTR_TRIGGER_CONFORM)
290		trig = INTR_TRIGGER_EDGE;
291	if (pol == INTR_POLARITY_CONFORM)
292		pol = INTR_POLARITY_HIGH;
293	vector = atpic_vector(isrc);
294	if ((trig == INTR_TRIGGER_EDGE && pol == INTR_POLARITY_LOW) ||
295	    (trig == INTR_TRIGGER_LEVEL && pol == INTR_POLARITY_HIGH)) {
296		printf(
297		"atpic: Mismatched config for IRQ%u: trigger %s, polarity %s\n",
298		    vector, trig == INTR_TRIGGER_EDGE ? "edge" : "level",
299		    pol == INTR_POLARITY_HIGH ? "high" : "low");
300		return (EINVAL);
301	}
302
303	/* If there is no change, just return. */
304	if (ai->at_trigger == trig)
305		return (0);
306
307#ifdef PC98
308	if ((vector == 0 || vector == 1 || vector == 7 || vector == 8) &&
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	return (ENXIO);
317#else
318	/*
319	 * Certain IRQs can never be level/lo, so don't try to set them
320	 * that way if asked.  At least some ELCR registers ignore setting
321	 * these bits as well.
322	 */
323	if ((vector == 0 || vector == 1 || vector == 2 || vector == 13) &&
324	    trig == INTR_TRIGGER_LEVEL) {
325		if (bootverbose)
326			printf(
327		"atpic: Ignoring invalid level/low configuration for IRQ%u\n",
328			    vector);
329		return (EINVAL);
330	}
331	if (!using_elcr) {
332		if (bootverbose)
333			printf("atpic: No ELCR to configure IRQ%u as %s\n",
334			    vector, trig == INTR_TRIGGER_EDGE ? "edge/high" :
335			    "level/low");
336		return (ENXIO);
337	}
338	if (bootverbose)
339		printf("atpic: Programming IRQ%u as %s\n", vector,
340		    trig == INTR_TRIGGER_EDGE ? "edge/high" : "level/low");
341	mtx_lock_spin(&icu_lock);
342	elcr_write_trigger(atpic_vector(isrc), trig);
343	ai->at_trigger = trig;
344	mtx_unlock_spin(&icu_lock);
345	return (0);
346#endif /* PC98 */
347}
348
349static void
350i8259_init(struct atpic *pic, int slave)
351{
352	int imr_addr;
353
354	/* Reset the PIC and program with next four bytes. */
355	mtx_lock_spin(&icu_lock);
356#ifdef DEV_MCA
357	/* MCA uses level triggered interrupts. */
358	if (MCA_system)
359		outb(pic->at_ioaddr, ICW1_RESET | ICW1_IC4 | ICW1_LTIM);
360	else
361#endif
362		outb(pic->at_ioaddr, ICW1_RESET | ICW1_IC4);
363	imr_addr = pic->at_ioaddr + ICU_IMR_OFFSET;
364
365	/* Start vector. */
366	outb(imr_addr, pic->at_intbase);
367
368	/*
369	 * Setup slave links.  For the master pic, indicate what line
370	 * the slave is configured on.  For the slave indicate
371	 * which line on the master we are connected to.
372	 */
373	if (slave)
374		outb(imr_addr, ICU_SLAVEID);	/* my slave id is 7 */
375	else
376		outb(imr_addr, IRQ_SLAVE);	/* slave on line 7 */
377
378	/* Set mode. */
379	if (slave)
380		outb(imr_addr, SLAVE_MODE);
381	else
382		outb(imr_addr, MASTER_MODE);
383
384	/* Set interrupt enable mask. */
385	outb(imr_addr, *pic->at_imen);
386
387	/* Reset is finished, default to IRR on read. */
388	outb(pic->at_ioaddr, OCW3_SEL | OCW3_RR);
389
390#ifndef PC98
391	/* OCW2_L1 sets priority order to 3-7, 0-2 (com2 first). */
392	if (!slave)
393		outb(pic->at_ioaddr, OCW2_R | OCW2_SL | OCW2_L1);
394#endif
395	mtx_unlock_spin(&icu_lock);
396}
397
398void
399atpic_startup(void)
400{
401	struct atpic_intsrc *ai;
402	int i;
403
404	/* Start off with all interrupts disabled. */
405	imen = 0xffff;
406	i8259_init(&atpics[MASTER], 0);
407	i8259_init(&atpics[SLAVE], 1);
408	atpic_enable_source((struct intsrc *)&atintrs[ICU_SLAVEID]);
409
410	/* Install low-level interrupt handlers for all of our IRQs. */
411	for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) {
412		if (i == ICU_SLAVEID)
413			continue;
414		ai->at_intsrc.is_count = &ai->at_count;
415		ai->at_intsrc.is_straycount = &ai->at_straycount;
416		setidt(((struct atpic *)ai->at_intsrc.is_pic)->at_intbase +
417		    ai->at_irq, ai->at_intr, SDT_SYS386IGT, SEL_KPL,
418		    GSEL(GCODE_SEL, SEL_KPL));
419	}
420
421#ifdef DEV_MCA
422	/* For MCA systems, all interrupts are level triggered. */
423	if (MCA_system)
424		for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++)
425			ai->at_trigger = INTR_TRIGGER_LEVEL;
426	else
427#endif
428
429#ifdef PC98
430	for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++)
431		switch (i) {
432		case 0:
433		case 1:
434		case 7:
435		case 8:
436			ai->at_trigger = INTR_TRIGGER_EDGE;
437			break;
438		default:
439			ai->at_trigger = INTR_TRIGGER_LEVEL;
440			break;
441		}
442#else
443	/*
444	 * Look for an ELCR.  If we find one, update the trigger modes.
445	 * If we don't find one, assume that IRQs 0, 1, 2, and 13 are
446	 * edge triggered and that everything else is level triggered.
447	 * We only use the trigger information to reprogram the ELCR if
448	 * we have one and as an optimization to avoid masking edge
449	 * triggered interrupts.  For the case that we don't have an ELCR,
450	 * it doesn't hurt to mask an edge triggered interrupt, so we
451	 * assume level trigger for any interrupt that we aren't sure is
452	 * edge triggered.
453	 */
454	if (elcr_probe() == 0) {
455		using_elcr = 1;
456		for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++)
457			ai->at_trigger = elcr_read_trigger(i);
458	} else {
459		for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++)
460			switch (i) {
461			case 0:
462			case 1:
463			case 2:
464			case 8:
465			case 13:
466				ai->at_trigger = INTR_TRIGGER_EDGE;
467				break;
468			default:
469				ai->at_trigger = INTR_TRIGGER_LEVEL;
470				break;
471			}
472	}
473#endif /* PC98 */
474}
475
476static void
477atpic_init(void *dummy __unused)
478{
479	struct atpic_intsrc *ai;
480	int i;
481
482	/* Loop through all interrupt sources and add them. */
483	for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) {
484		if (i == ICU_SLAVEID)
485			continue;
486		intr_register_source(&ai->at_intsrc);
487	}
488}
489SYSINIT(atpic_init, SI_SUB_INTR, SI_ORDER_SECOND + 1, atpic_init, NULL)
490
491void
492atpic_handle_intr(struct intrframe iframe)
493{
494	struct intsrc *isrc;
495
496	KASSERT((u_int)iframe.if_vec < ICU_LEN,
497	    ("unknown int %d\n", iframe.if_vec));
498	isrc = &atintrs[iframe.if_vec].at_intsrc;
499
500	/*
501	 * If we don't have an ithread, see if this is a spurious
502	 * interrupt.
503	 */
504	if (isrc->is_ithread == NULL &&
505	    (iframe.if_vec == 7 || iframe.if_vec == 15)) {
506		int port, isr;
507
508		/*
509		 * Read the ISR register to see if IRQ 7/15 is really
510		 * pending.  Reset read register back to IRR when done.
511		 */
512		port = ((struct atpic *)isrc->is_pic)->at_ioaddr;
513		mtx_lock_spin(&icu_lock);
514		outb(port, OCW3_SEL | OCW3_RR | OCW3_RIS);
515		isr = inb(port);
516		outb(port, OCW3_SEL | OCW3_RR);
517		mtx_unlock_spin(&icu_lock);
518		if ((isr & IRQ7) == 0)
519			return;
520	}
521	intr_execute_handlers(isrc, &iframe);
522}
523
524#ifdef DEV_ISA
525/*
526 * Bus attachment for the ISA PIC.
527 */
528static struct isa_pnp_id atpic_ids[] = {
529	{ 0x0000d041 /* PNP0000 */, "AT interrupt controller" },
530	{ 0 }
531};
532
533static int
534atpic_probe(device_t dev)
535{
536	int result;
537
538	result = ISA_PNP_PROBE(device_get_parent(dev), dev, atpic_ids);
539	if (result <= 0)
540		device_quiet(dev);
541	return (result);
542}
543
544/*
545 * We might be granted IRQ 2, as this is typically consumed by chaining
546 * between the two PIC components.  If we're using the APIC, however,
547 * this may not be the case, and as such we should free the resource.
548 * (XXX untested)
549 *
550 * The generic ISA attachment code will handle allocating any other resources
551 * that we don't explicitly claim here.
552 */
553static int
554atpic_attach(device_t dev)
555{
556	struct resource *res;
557	int rid;
558
559	/* Try to allocate our IRQ and then free it. */
560	rid = 0;
561	res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 0);
562	if (res != NULL)
563		bus_release_resource(dev, SYS_RES_IRQ, rid, res);
564	return (0);
565}
566
567static device_method_t atpic_methods[] = {
568	/* Device interface */
569	DEVMETHOD(device_probe,		atpic_probe),
570	DEVMETHOD(device_attach,	atpic_attach),
571	DEVMETHOD(device_detach,	bus_generic_detach),
572	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
573	DEVMETHOD(device_suspend,	bus_generic_suspend),
574	DEVMETHOD(device_resume,	bus_generic_resume),
575	{ 0, 0 }
576};
577
578static driver_t atpic_driver = {
579	"atpic",
580	atpic_methods,
581	1,		/* no softc */
582};
583
584static devclass_t atpic_devclass;
585
586DRIVER_MODULE(atpic, isa, atpic_driver, atpic_devclass, 0, 0);
587#ifndef PC98
588DRIVER_MODULE(atpic, acpi, atpic_driver, atpic_devclass, 0, 0);
589#endif
590
591/*
592 * Return a bitmap of the current interrupt requests.  This is 8259-specific
593 * and is only suitable for use at probe time.
594 */
595intrmask_t
596isa_irq_pending(void)
597{
598	u_char irr1;
599	u_char irr2;
600
601	irr1 = inb(IO_ICU1);
602	irr2 = inb(IO_ICU2);
603	return ((irr2 << 8) | irr1);
604}
605#endif /* DEV_ISA */
606