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