atpic.c revision 122051
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 * 3. Neither the name of the author nor the names of any co-contributors
14121985Sjhb *    may be used to endorse or promote products derived from this software
15121985Sjhb *    without specific prior written permission.
16121985Sjhb *
17121985Sjhb * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18121985Sjhb * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19121985Sjhb * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20121985Sjhb * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21121985Sjhb * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22121985Sjhb * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23121985Sjhb * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24121985Sjhb * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25121985Sjhb * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26121985Sjhb * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27121985Sjhb * SUCH DAMAGE.
28121985Sjhb */
29121985Sjhb
30121985Sjhb/*
31121985Sjhb * PIC driver for the 8259A Master and Slave PICs in PC/AT machines.
32121985Sjhb */
33121985Sjhb
34121985Sjhb#include <sys/cdefs.h>
35121985Sjhb__FBSDID("$FreeBSD: head/sys/i386/isa/atpic.c 122051 2003-11-04 13:13:04Z nyan $");
36121985Sjhb
37121985Sjhb#include "opt_auto_eoi.h"
38121985Sjhb#include "opt_isa.h"
39121985Sjhb
40121985Sjhb#include <sys/param.h>
41121985Sjhb#include <sys/systm.h>
42121985Sjhb#include <sys/bus.h>
43121985Sjhb#include <sys/interrupt.h>
44121985Sjhb#include <sys/kernel.h>
45121985Sjhb#include <sys/lock.h>
46121985Sjhb#include <sys/mutex.h>
47121985Sjhb
48121985Sjhb#include <machine/cpufunc.h>
49121985Sjhb#include <machine/frame.h>
50121985Sjhb#include <machine/intr_machdep.h>
51121985Sjhb#include <machine/md_var.h>
52121985Sjhb#include <machine/resource.h>
53121985Sjhb#include <machine/segments.h>
54121985Sjhb
55121985Sjhb#include <i386/isa/icu.h>
56122051Snyan#ifdef PC98
57122051Snyan#include <pc98/pc98/pc98.h>
58122051Snyan#else
59121985Sjhb#include <i386/isa/isa.h>
60122051Snyan#endif
61121985Sjhb#include <isa/isavar.h>
62121985Sjhb
63121985Sjhb#define	MASTER	0
64121985Sjhb#define	SLAVE	1
65121985Sjhb
66121985Sjhb/* XXX: Magic numbers */
67121985Sjhb#ifdef PC98
68121985Sjhb#ifdef AUTO_EOI_1
69121985Sjhb#define	MASTER_MODE	0x1f	/* Master auto EOI, 8086 mode */
70121985Sjhb#else
71121985Sjhb#define	MASTER_MODE	0x1d	/* Master 8086 mode */
72121985Sjhb#endif
73121985Sjhb#define	SLAVE_MODE	9	/* 8086 mode */
74121985Sjhb#else /* IBM-PC */
75121985Sjhb#ifdef AUTO_EOI_1
76121985Sjhb#define	MASTER_MODE	(2 | 1)	/* Auto EOI, 8086 mode */
77121985Sjhb#else
78121985Sjhb#define	MASTER_MODE	1	/* 8086 mode */
79121985Sjhb#endif
80121985Sjhb#ifdef AUTO_EOI_2
81121985Sjhb#define	SLAVE_MODE	(2 | 1)	/* Auto EOI, 8086 mode */
82121985Sjhb#else
83121985Sjhb#define	SLAVE_MODE	1	/* 8086 mode */
84121985Sjhb#endif
85121985Sjhb#endif /* PC98 */
86121985Sjhb
87121985Sjhbstatic void	atpic_init(void *dummy);
88121985Sjhb
89121985Sjhbunsigned int imen;	/* XXX */
90121985Sjhb
91121985Sjhbinthand_t
92121985Sjhb	IDTVEC(atpic_intr0), IDTVEC(atpic_intr1), IDTVEC(atpic_intr2),
93121985Sjhb	IDTVEC(atpic_intr3), IDTVEC(atpic_intr4), IDTVEC(atpic_intr5),
94121985Sjhb	IDTVEC(atpic_intr6), IDTVEC(atpic_intr7), IDTVEC(atpic_intr8),
95121985Sjhb	IDTVEC(atpic_intr9), IDTVEC(atpic_intr10), IDTVEC(atpic_intr11),
96121985Sjhb	IDTVEC(atpic_intr12), IDTVEC(atpic_intr13), IDTVEC(atpic_intr14),
97121985Sjhb	IDTVEC(atpic_intr15);
98121985Sjhb
99121985Sjhb#define	IRQ(ap, ai)	((ap)->at_irqbase + (ai)->at_irq)
100121985Sjhb
101121985Sjhb#define	ATPIC(io, base, eoi, imenptr)				\
102121985Sjhb     	{ { atpic_enable_source, atpic_disable_source, (eoi),		\
103121985Sjhb	    atpic_enable_intr, atpic_vector, atpic_source_pending, NULL, \
104121985Sjhb	    atpic_resume }, (io), (base), IDT_IO_INTS + (base), (imenptr) }
105121985Sjhb
106121985Sjhb#define	INTSRC(irq)							\
107121985Sjhb	{ { &atpics[(irq) / 8].at_pic }, (irq) % 8,			\
108121985Sjhb	    IDTVEC(atpic_intr ## irq ) }
109121985Sjhb
110121985Sjhbstruct atpic {
111121985Sjhb	struct pic at_pic;
112121985Sjhb	int	at_ioaddr;
113121985Sjhb	int	at_irqbase;
114121985Sjhb	uint8_t	at_intbase;
115121985Sjhb	uint8_t	*at_imen;
116121985Sjhb};
117121985Sjhb
118121985Sjhbstruct atpic_intsrc {
119121985Sjhb	struct intsrc at_intsrc;
120121985Sjhb	int	at_irq;		/* Relative to PIC base. */
121121985Sjhb	inthand_t *at_intr;
122121985Sjhb};
123121985Sjhb
124121985Sjhbstatic void atpic_enable_source(struct intsrc *isrc);
125121985Sjhbstatic void atpic_disable_source(struct intsrc *isrc);
126121985Sjhbstatic void atpic_eoi_master(struct intsrc *isrc);
127121985Sjhbstatic void atpic_eoi_slave(struct intsrc *isrc);
128121985Sjhbstatic void atpic_enable_intr(struct intsrc *isrc);
129121985Sjhbstatic int atpic_vector(struct intsrc *isrc);
130121985Sjhbstatic void atpic_resume(struct intsrc *isrc);
131121985Sjhbstatic int atpic_source_pending(struct intsrc *isrc);
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
158121985Sjhbstatic void
159121985Sjhbatpic_enable_source(struct intsrc *isrc)
160121985Sjhb{
161121985Sjhb	struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc;
162121985Sjhb	struct atpic *ap = (struct atpic *)isrc->is_pic;
163121985Sjhb
164121985Sjhb	mtx_lock_spin(&icu_lock);
165121985Sjhb	*ap->at_imen &= ~(1 << ai->at_irq);
166121985Sjhb	outb(ap->at_ioaddr + ICU_IMR_OFFSET, *ap->at_imen);
167121985Sjhb	mtx_unlock_spin(&icu_lock);
168121985Sjhb}
169121985Sjhb
170121985Sjhbstatic void
171121985Sjhbatpic_disable_source(struct intsrc *isrc)
172121985Sjhb{
173121985Sjhb	struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc;
174121985Sjhb	struct atpic *ap = (struct atpic *)isrc->is_pic;
175121985Sjhb
176121985Sjhb	mtx_lock_spin(&icu_lock);
177121985Sjhb	*ap->at_imen |= (1 << ai->at_irq);
178121985Sjhb	outb(ap->at_ioaddr + ICU_IMR_OFFSET, *ap->at_imen);
179121985Sjhb	mtx_unlock_spin(&icu_lock);
180121985Sjhb}
181121985Sjhb
182121985Sjhbstatic void
183121985Sjhbatpic_eoi_master(struct intsrc *isrc)
184121985Sjhb{
185121985Sjhb
186121985Sjhb	KASSERT(isrc->is_pic == &atpics[MASTER].at_pic,
187121985Sjhb	    ("%s: mismatched pic", __func__));
188121985Sjhb#ifndef AUTO_EOI_1
189121985Sjhb	mtx_lock_spin(&icu_lock);
190121985Sjhb	outb(atpics[MASTER].at_ioaddr, ICU_EOI);
191121985Sjhb	mtx_unlock_spin(&icu_lock);
192121985Sjhb#endif
193121985Sjhb}
194121985Sjhb
195121985Sjhbstatic void
196121985Sjhbatpic_eoi_slave(struct intsrc *isrc)
197121985Sjhb{
198121985Sjhb
199121985Sjhb	KASSERT(isrc->is_pic == &atpics[SLAVE].at_pic,
200121985Sjhb	    ("%s: mismatched pic", __func__));
201121985Sjhb#ifndef AUTO_EOI_2
202121985Sjhb	mtx_lock_spin(&icu_lock);
203121985Sjhb	outb(atpics[SLAVE].at_ioaddr, ICU_EOI);
204121985Sjhb#ifndef AUTO_EOI_1
205121985Sjhb	outb(atpics[MASTER].at_ioaddr, ICU_EOI);
206121985Sjhb#endif
207121985Sjhb	mtx_unlock_spin(&icu_lock);
208121985Sjhb#endif
209121985Sjhb}
210121985Sjhb
211121985Sjhbstatic void
212121985Sjhbatpic_enable_intr(struct intsrc *isrc)
213121985Sjhb{
214121985Sjhb	struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc;
215121985Sjhb	struct atpic *ap = (struct atpic *)isrc->is_pic;
216121985Sjhb	register_t eflags;
217121985Sjhb
218121985Sjhb	mtx_lock_spin(&icu_lock);
219121985Sjhb	eflags = intr_disable();
220121985Sjhb	setidt(ap->at_intbase + ai->at_irq, ai->at_intr, SDT_SYS386IGT,
221121985Sjhb	    SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
222121985Sjhb	intr_restore(eflags);
223121985Sjhb	mtx_unlock_spin(&icu_lock);
224121985Sjhb}
225121985Sjhb
226121985Sjhbstatic int
227121985Sjhbatpic_vector(struct intsrc *isrc)
228121985Sjhb{
229121985Sjhb	struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc;
230121985Sjhb	struct atpic *ap = (struct atpic *)isrc->is_pic;
231121985Sjhb
232121985Sjhb	return (IRQ(ap, ai));
233121985Sjhb}
234121985Sjhb
235121985Sjhbstatic int
236121985Sjhbatpic_source_pending(struct intsrc *isrc)
237121985Sjhb{
238121985Sjhb	struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc;
239121985Sjhb	struct atpic *ap = (struct atpic *)isrc->is_pic;
240121985Sjhb
241121985Sjhb	return (inb(ap->at_ioaddr) & (1 << ai->at_irq));
242121985Sjhb}
243121985Sjhb
244121985Sjhbstatic void
245121985Sjhbatpic_resume(struct intsrc *isrc)
246121985Sjhb{
247121985Sjhb	struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc;
248121985Sjhb	struct atpic *ap = (struct atpic *)isrc->is_pic;
249121985Sjhb
250121985Sjhb	if (ai->at_irq == 0)
251121985Sjhb		i8259_init(ap, ap == &atpics[SLAVE]);
252121985Sjhb}
253121985Sjhb
254121985Sjhbstatic void
255121985Sjhbi8259_init(struct atpic *pic, int slave)
256121985Sjhb{
257121985Sjhb	int imr_addr;
258121985Sjhb
259121985Sjhb	/* Reset the PIC and program with next four bytes. */
260121985Sjhb	mtx_lock_spin(&icu_lock);
261121985Sjhb#ifdef DEV_MCA
262121985Sjhb	if (MCA_system)
263121985Sjhb		outb(pic->at_ioaddr, 0x19);
264121985Sjhb	else
265121985Sjhb#endif
266121985Sjhb		outb(pic->at_ioaddr, 0x11);
267121985Sjhb	imr_addr = pic->at_ioaddr + ICU_IMR_OFFSET;
268121985Sjhb
269121985Sjhb	/* Start vector. */
270121985Sjhb	outb(imr_addr, pic->at_intbase);
271121985Sjhb
272121985Sjhb	/*
273121985Sjhb	 * Setup slave links.  For the master pic, indicate what line
274121985Sjhb	 * the slave is configured on.  For the slave indicate
275121985Sjhb	 * which line on the master we are connected to.
276121985Sjhb	 */
277121985Sjhb	if (slave)
278121985Sjhb		outb(imr_addr, ICU_SLAVEID);	/* my slave id is 7 */
279121985Sjhb	else
280121985Sjhb		outb(imr_addr, IRQ_SLAVE);	/* slave on line 7 */
281121985Sjhb
282121985Sjhb	/* Set mode. */
283121985Sjhb	if (slave)
284121985Sjhb		outb(imr_addr, SLAVE_MODE);
285121985Sjhb	else
286121985Sjhb		outb(imr_addr, MASTER_MODE);
287121985Sjhb
288121985Sjhb	/* Set interrupt enable mask. */
289121985Sjhb	outb(imr_addr, *pic->at_imen);
290121985Sjhb
291121985Sjhb	/* Reset is finished, default to IRR on read. */
292121985Sjhb	outb(pic->at_ioaddr, 0x0a);
293121985Sjhb
294121985Sjhb#ifndef PC98
295121985Sjhb	/* Set priority order to 3-7, 0-2 (com2 first). */
296121985Sjhb	if (!slave)
297121985Sjhb		outb(pic->at_ioaddr, 0xc0 | (3 - 1));
298121985Sjhb#endif
299121985Sjhb	mtx_unlock_spin(&icu_lock);
300121985Sjhb}
301121985Sjhb
302121985Sjhbvoid
303121985Sjhbatpic_startup(void)
304121985Sjhb{
305121985Sjhb
306121985Sjhb	/* Start off with all interrupts disabled. */
307121985Sjhb	imen = 0xffff;
308121985Sjhb	i8259_init(&atpics[MASTER], 0);
309121985Sjhb	i8259_init(&atpics[SLAVE], 1);
310121985Sjhb	atpic_enable_source((struct intsrc *)&atintrs[ICU_SLAVEID]);
311121985Sjhb}
312121985Sjhb
313121985Sjhbstatic void
314121985Sjhbatpic_init(void *dummy __unused)
315121985Sjhb{
316121985Sjhb	struct atpic_intsrc *ai;
317121985Sjhb	int i;
318121985Sjhb
319121985Sjhb	/* Loop through all interrupt sources and add them. */
320121985Sjhb	for (i = 0; i < sizeof(atintrs) / sizeof(struct atpic_intsrc); i++) {
321121985Sjhb		if (i == ICU_SLAVEID)
322121985Sjhb			continue;
323121985Sjhb		ai = &atintrs[i];
324121985Sjhb		intr_register_source(&ai->at_intsrc);
325121985Sjhb	}
326121985Sjhb}
327121985SjhbSYSINIT(atpic_init, SI_SUB_INTR, SI_ORDER_SECOND + 1, atpic_init, NULL)
328121985Sjhb
329121985Sjhbvoid
330121985Sjhbatpic_sched_ithd(struct intrframe iframe)
331121985Sjhb{
332121985Sjhb	struct intsrc *isrc;
333121985Sjhb
334121985Sjhb	KASSERT((uint)iframe.if_vec < ICU_LEN,
335121985Sjhb	    ("unknown int %d\n", iframe.if_vec));
336121985Sjhb	isrc = &atintrs[iframe.if_vec].at_intsrc;
337121985Sjhb	intr_execute_handlers(isrc, &iframe);
338121985Sjhb}
339121985Sjhb
340121985Sjhb#ifdef DEV_ISA
341121985Sjhb/*
342121985Sjhb * Bus attachment for the ISA PIC.
343121985Sjhb */
344121985Sjhbstatic struct isa_pnp_id atpic_ids[] = {
345121985Sjhb	{ 0x0000d041 /* PNP0000 */, "AT interrupt controller" },
346121985Sjhb	{ 0 }
347121985Sjhb};
348121985Sjhb
349121985Sjhbstatic int
350121985Sjhbatpic_probe(device_t dev)
351121985Sjhb{
352121985Sjhb	int result;
353121985Sjhb
354121985Sjhb	result = ISA_PNP_PROBE(device_get_parent(dev), dev, atpic_ids);
355121985Sjhb	if (result <= 0)
356121985Sjhb		device_quiet(dev);
357121985Sjhb	return (result);
358121985Sjhb}
359121985Sjhb
360121985Sjhb/*
361121985Sjhb * We might be granted IRQ 2, as this is typically consumed by chaining
362121985Sjhb * between the two PIC components.  If we're using the APIC, however,
363121985Sjhb * this may not be the case, and as such we should free the resource.
364121985Sjhb * (XXX untested)
365121985Sjhb *
366121985Sjhb * The generic ISA attachment code will handle allocating any other resources
367121985Sjhb * that we don't explicitly claim here.
368121985Sjhb */
369121985Sjhbstatic int
370121985Sjhbatpic_attach(device_t dev)
371121985Sjhb{
372121985Sjhb	struct resource *res;
373121985Sjhb	int rid;
374121985Sjhb
375121985Sjhb	/* Try to allocate our IRQ and then free it. */
376121985Sjhb	rid = 0;
377121985Sjhb	res = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1, 0);
378121985Sjhb	if (res != NULL)
379121985Sjhb		bus_release_resource(dev, SYS_RES_IRQ, rid, res);
380121985Sjhb	return (0);
381121985Sjhb}
382121985Sjhb
383121985Sjhbstatic device_method_t atpic_methods[] = {
384121985Sjhb	/* Device interface */
385121985Sjhb	DEVMETHOD(device_probe,		atpic_probe),
386121985Sjhb	DEVMETHOD(device_attach,	atpic_attach),
387121985Sjhb	DEVMETHOD(device_detach,	bus_generic_detach),
388121985Sjhb	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
389121985Sjhb	DEVMETHOD(device_suspend,	bus_generic_suspend),
390121985Sjhb	DEVMETHOD(device_resume,	bus_generic_resume),
391121985Sjhb	{ 0, 0 }
392121985Sjhb};
393121985Sjhb
394121985Sjhbstatic driver_t atpic_driver = {
395121985Sjhb	"atpic",
396121985Sjhb	atpic_methods,
397121985Sjhb	1,		/* no softc */
398121985Sjhb};
399121985Sjhb
400121985Sjhbstatic devclass_t atpic_devclass;
401121985Sjhb
402121985SjhbDRIVER_MODULE(atpic, isa, atpic_driver, atpic_devclass, 0, 0);
403122051Snyan#ifndef PC98
404121985SjhbDRIVER_MODULE(atpic, acpi, atpic_driver, atpic_devclass, 0, 0);
405122051Snyan#endif
406121985Sjhb
407121985Sjhb/*
408121985Sjhb * Return a bitmap of the current interrupt requests.  This is 8259-specific
409121985Sjhb * and is only suitable for use at probe time.
410121985Sjhb */
411121985Sjhbintrmask_t
412121985Sjhbisa_irq_pending(void)
413121985Sjhb{
414121985Sjhb	u_char irr1;
415121985Sjhb	u_char irr2;
416121985Sjhb
417121985Sjhb	irr1 = inb(IO_ICU1);
418121985Sjhb	irr2 = inb(IO_ICU2);
419121985Sjhb	return ((irr2 << 8) | irr1);
420121985Sjhb}
421121985Sjhb#endif /* DEV_ISA */
422