Home | History | Annotate | Line # | Download | only in isa
isabus.c revision 1.24
      1 /*	$NetBSD: isabus.c,v 1.24 2003/07/15 00:04:47 lukem Exp $	*/
      2 /*	$OpenBSD: isabus.c,v 1.15 1998/03/16 09:38:46 pefo Exp $	*/
      3 /*	NetBSD: isa.c,v 1.33 1995/06/28 04:30:51 cgd Exp 	*/
      4 
      5 /*-
      6  * Copyright (c) 1995 Per Fogelstrom
      7  * Copyright (c) 1993, 1994 Charles M. Hannum.
      8  * Copyright (c) 1990 The Regents of the University of California.
      9  * All rights reserved.
     10  *
     11  * This code is derived from software contributed to Berkeley by
     12  * William Jolitz and Don Ahn.
     13  *
     14  * Redistribution and use in source and binary forms, with or without
     15  * modification, are permitted provided that the following conditions
     16  * are met:
     17  * 1. Redistributions of source code must retain the above copyright
     18  *    notice, this list of conditions and the following disclaimer.
     19  * 2. Redistributions in binary form must reproduce the above copyright
     20  *    notice, this list of conditions and the following disclaimer in the
     21  *    documentation and/or other materials provided with the distribution.
     22  * 3. All advertising materials mentioning features or use of this software
     23  *    must display the following acknowledgement:
     24  *	This product includes software developed by the University of
     25  *	California, Berkeley and its contributors.
     26  * 4. Neither the name of the University nor the names of its contributors
     27  *    may be used to endorse or promote products derived from this software
     28  *    without specific prior written permission.
     29  *
     30  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     31  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     32  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     33  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     34  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     35  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     36  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     37  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     38  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     39  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     40  * SUCH DAMAGE.
     41  *
     42  *	@(#)isa.c	7.2 (Berkeley) 5/12/91
     43  */
     44 /*
     45  * Mach Operating System
     46  * Copyright (c) 1991,1990,1989 Carnegie Mellon University
     47  * All Rights Reserved.
     48  *
     49  * Permission to use, copy, modify and distribute this software and its
     50  * documentation is hereby granted, provided that both the copyright
     51  * notice and this permission notice appear in all copies of the
     52  * software, derivative works or modified versions, and any portions
     53  * thereof, and that both notices appear in supporting documentation.
     54  *
     55  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
     56  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
     57  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
     58  *
     59  * Carnegie Mellon requests users of this software to return to
     60  *
     61  *  Software Distribution Coordinator  or  Software.Distribution (at) CS.CMU.EDU
     62  *  School of Computer Science
     63  *  Carnegie Mellon University
     64  *  Pittsburgh PA 15213-3890
     65  *
     66  * any improvements or extensions that they make and grant Carnegie Mellon
     67  * the rights to redistribute these changes.
     68  */
     69 /*
     70   Copyright 1988, 1989 by Intel Corporation, Santa Clara, California.
     71 
     72 		All Rights Reserved
     73 
     74 Permission to use, copy, modify, and distribute this software and
     75 its documentation for any purpose and without fee is hereby
     76 granted, provided that the above copyright notice appears in all
     77 copies and that both the copyright notice and this permission notice
     78 appear in supporting documentation, and that the name of Intel
     79 not be used in advertising or publicity pertaining to distribution
     80 of the software without specific, written prior permission.
     81 
     82 INTEL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
     83 INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
     84 IN NO EVENT SHALL INTEL BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
     85 CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
     86 LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
     87 NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
     88 WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     89 */
     90 
     91 #include <sys/cdefs.h>
     92 __KERNEL_RCSID(0, "$NetBSD: isabus.c,v 1.24 2003/07/15 00:04:47 lukem Exp $");
     93 
     94 #include <sys/param.h>
     95 #include <sys/proc.h>
     96 #include <sys/user.h>
     97 #include <sys/systm.h>
     98 #include <sys/callout.h>
     99 #include <sys/time.h>
    100 #include <sys/kernel.h>
    101 #include <sys/device.h>
    102 #include <sys/malloc.h>
    103 #include <sys/extent.h>
    104 
    105 #include <uvm/uvm_extern.h>
    106 
    107 #include <machine/cpu.h>
    108 #include <machine/pio.h>
    109 #include <machine/autoconf.h>
    110 #include <machine/intr.h>
    111 
    112 #include <dev/ic/i8253reg.h>
    113 #include <dev/isa/isareg.h>
    114 #include <dev/isa/isavar.h>
    115 #include <arc/isa/isabrvar.h>
    116 #include <arc/isa/spkrreg.h>
    117 
    118 static int beeping;
    119 static struct callout sysbeep_ch = CALLOUT_INITIALIZER;
    120 
    121 static long isa_mem_ex_storage[EXTENT_FIXED_STORAGE_SIZE(16) / sizeof(long)];
    122 static long isa_io_ex_storage[EXTENT_FIXED_STORAGE_SIZE(16) / sizeof(long)];
    123 
    124 #define	IRQ_SLAVE	2
    125 
    126 /* Definition of the driver for autoconfig. */
    127 int	isabrprint(void *, const char *);
    128 
    129 extern struct arc_bus_space arc_bus_io, arc_bus_mem;
    130 
    131 void	isabr_attach_hook __P((struct device *, struct device *,
    132 			struct isabus_attach_args *));
    133 const struct evcnt *isabr_intr_evcnt __P((isa_chipset_tag_t, int));
    134 void	*isabr_intr_establish __P((isa_chipset_tag_t, int, int, int,
    135 			int (*)(void *), void *));
    136 void	isabr_intr_disestablish __P((isa_chipset_tag_t, void*));
    137 int	isabr_iointr __P((unsigned int, struct clockframe *));
    138 void	isabr_initicu __P((void));
    139 void	intr_calculatemasks __P((void));
    140 int	fakeintr __P((void *a));
    141 
    142 struct isabr_config *isabr_conf = NULL;
    143 u_int32_t imask[_IPL_N];	/* XXX */
    144 
    145 void
    146 isabrattach(sc)
    147 	struct isabr_softc *sc;
    148 {
    149 	struct isabus_attach_args iba;
    150 
    151 	if (isabr_conf == NULL)
    152 		panic("isabr_conf isn't initialized");
    153 
    154 	printf("\n");
    155 
    156 	/* Initialize interrupt controller */
    157 	isabr_initicu();
    158 
    159 /*XXX we may remove the abus part of the softc struct... */
    160 	sc->sc_bus.ab_dv = (struct device *)sc;
    161 	sc->sc_bus.ab_type = BUS_ISABR;
    162 
    163 	sc->arc_isa_cs.ic_attach_hook = isabr_attach_hook;
    164 	sc->arc_isa_cs.ic_intr_evcnt = isabr_intr_evcnt;
    165 	sc->arc_isa_cs.ic_intr_establish = isabr_intr_establish;
    166 	sc->arc_isa_cs.ic_intr_disestablish = isabr_intr_disestablish;
    167 
    168 	arc_bus_space_init_extent(&arc_bus_mem, (caddr_t)isa_mem_ex_storage,
    169 	    sizeof(isa_mem_ex_storage));
    170 	arc_bus_space_init_extent(&arc_bus_io, (caddr_t)isa_io_ex_storage,
    171 	    sizeof(isa_io_ex_storage));
    172 
    173 	iba.iba_busname = "isa";
    174 	iba.iba_iot = &arc_bus_io;
    175 	iba.iba_memt = &arc_bus_mem;
    176 	iba.iba_dmat = &sc->sc_dmat;
    177 	iba.iba_ic = &sc->arc_isa_cs;
    178 	config_found(&sc->sc_dev, &iba, isabrprint);
    179 }
    180 
    181 int
    182 isabrprint(aux, pnp)
    183 	void *aux;
    184 	const char *pnp;
    185 {
    186 	struct confargs *ca = aux;
    187 
    188         if (pnp)
    189                 aprint_normal("%s at %s", ca->ca_name, pnp);
    190         aprint_verbose(" isa_io_base 0x%lx isa_mem_base 0x%lx",
    191 		arc_bus_io.bs_vbase, arc_bus_mem.bs_vbase);
    192         return (UNCONF);
    193 }
    194 
    195 
    196 /*
    197  *	Interrupt system driver code
    198  *	============================
    199  */
    200 #define LEGAL_IRQ(x)    ((x) >= 0 && (x) < ICU_LEN && (x) != 2)
    201 
    202 int	imen;
    203 int	intrtype[ICU_LEN], intrmask[ICU_LEN], intrlevel[ICU_LEN];
    204 struct intrhand *intrhand[ICU_LEN];
    205 
    206 int fakeintr(a)
    207 	void *a;
    208 {
    209 	return 0;
    210 }
    211 
    212 /*
    213  * Recalculate the interrupt masks from scratch.
    214  * We could code special registry and deregistry versions of this function that
    215  * would be faster, but the code would be nastier, and we don't expect this to
    216  * happen very much anyway.
    217  */
    218 void
    219 intr_calculatemasks()
    220 {
    221 	int irq, level;
    222 	struct intrhand *q;
    223 
    224 	/* First, figure out which levels each IRQ uses. */
    225 	for (irq = 0; irq < ICU_LEN; irq++) {
    226 		int levels = 0;
    227 		for (q = intrhand[irq]; q; q = q->ih_next)
    228 			levels |= 1 << q->ih_level;
    229 		intrlevel[irq] = levels;
    230 	}
    231 
    232 	/* Then figure out which IRQs use each level. */
    233 	for (level = 0; level < _IPL_N; level++) {
    234 		int irqs = 0;
    235 		for (irq = 0; irq < ICU_LEN; irq++)
    236 			if (intrlevel[irq] & (1 << level))
    237 				irqs |= 1 << irq;
    238 		imask[level] = irqs;
    239 	}
    240 
    241 	imask[IPL_NONE] = 0;
    242 
    243 	imask[IPL_SOFT] |= imask[IPL_NONE];
    244 	imask[IPL_SOFTCLOCK] |= imask[IPL_SOFT];
    245 	imask[IPL_SOFTNET] |= imask[IPL_SOFTCLOCK];
    246 	imask[IPL_SOFTSERIAL] |= imask[IPL_SOFTNET];
    247 
    248 	/*
    249 	 * Enforce a hierarchy that gives slow devices a better chance at not
    250 	 * dropping data.
    251 	 */
    252 	imask[IPL_BIO] |= imask[IPL_SOFTSERIAL];
    253 	imask[IPL_NET] |= imask[IPL_BIO];
    254 	imask[IPL_TTY] |= imask[IPL_NET];
    255 
    256 	/*
    257 	 * Since run queues may be manipulated by both the statclock and tty,
    258 	 * network, and diskdrivers, clock > tty.
    259 	 */
    260 	imask[IPL_CLOCK] |= imask[IPL_TTY];
    261 	imask[IPL_STATCLOCK] |= imask[IPL_CLOCK];
    262 
    263 	/*
    264 	 * IPL_HIGH must block everything that can manipulate a run queue.
    265 	 */
    266 	imask[IPL_HIGH] |= imask[IPL_STATCLOCK];
    267 
    268 	/* And eventually calculate the complete masks. */
    269 	for (irq = 0; irq < ICU_LEN; irq++) {
    270 		int irqs = 1 << irq;
    271 		for (q = intrhand[irq]; q; q = q->ih_next)
    272 			irqs |= imask[q->ih_level];
    273 		intrmask[irq] = irqs;
    274 	}
    275 
    276 	/* Lastly, determine which IRQs are actually in use. */
    277 	{
    278 		int irqs = 0;
    279 		for (irq = 0; irq < ICU_LEN; irq++)
    280 			if (intrhand[irq])
    281 				irqs |= 1 << irq;
    282 		if (irqs >= 0x100) /* any IRQs >= 8 in use */
    283 			irqs |= 1 << IRQ_SLAVE;
    284 		imen = ~irqs;
    285 		isa_outb(IO_ICU1 + 1, imen);
    286 		isa_outb(IO_ICU2 + 1, imen >> 8);
    287 	}
    288 }
    289 
    290 void
    291 isabr_attach_hook(parent, self, iba)
    292 	struct device *parent, *self;
    293 	struct isabus_attach_args *iba;
    294 {
    295 
    296 	/* Nothing to do. */
    297 }
    298 
    299 const struct evcnt *
    300 isabr_intr_evcnt(ic, irq)
    301 	isa_chipset_tag_t ic;
    302 	int irq;
    303 {
    304 
    305 	/* XXX for now, no evcnt parent reported */
    306 	return NULL;
    307 }
    308 
    309 /*
    310  *	Establish a ISA bus interrupt.
    311  */
    312 void *
    313 isabr_intr_establish(ic, irq, type, level, ih_fun, ih_arg)
    314         isa_chipset_tag_t ic;
    315         int irq;
    316         int type;
    317         int level;
    318         int (*ih_fun) __P((void *));
    319         void *ih_arg;
    320 {
    321 	struct intrhand **p, *q, *ih;
    322 	static struct intrhand fakehand = {NULL, fakeintr};
    323 
    324 	/* no point in sleeping unless someone can free memory. */
    325 	ih = malloc(sizeof *ih, M_DEVBUF, cold ? M_NOWAIT : M_WAITOK);
    326 	if (ih == NULL)
    327 		panic("isa_intr_establish: can't malloc handler info");
    328 
    329 	if (!LEGAL_IRQ(irq) || type == IST_NONE)
    330 		panic("intr_establish: bogus irq or type");
    331 
    332 	switch (intrtype[irq]) {
    333 	case IST_NONE:
    334 		intrtype[irq] = type;
    335 		break;
    336 	case IST_EDGE:
    337 	case IST_LEVEL:
    338 		if (type == intrtype[irq])
    339 			break;
    340 	case IST_PULSE:
    341 		if (type != IST_NONE)
    342 			panic("intr_establish: can't share %s with %s",
    343 			    isa_intr_typename(intrtype[irq]),
    344 			    isa_intr_typename(type));
    345 		break;
    346 	}
    347 
    348 	/*
    349 	 * Figure out where to put the handler.
    350 	 * This is O(N^2), but we want to preserve the order, and N is
    351 	 * generally small.
    352 	 */
    353 	for (p = &intrhand[irq]; (q = *p) != NULL; p = &q->ih_next)
    354 		;
    355 
    356 	/*
    357 	 * Actually install a fake handler momentarily, since we might be doing
    358 	 * this with interrupts enabled and don't want the real routine called
    359 	 * until masking is set up.
    360 	 */
    361 	fakehand.ih_level = level;
    362 	*p = &fakehand;
    363 
    364 	intr_calculatemasks();
    365 
    366 	/*
    367 	 * Poke the real handler in now.
    368 	 */
    369 	ih->ih_fun = ih_fun;
    370 	ih->ih_arg = ih_arg;
    371 	ih->ih_count = 0;
    372 	ih->ih_next = NULL;
    373 	ih->ih_level = level;
    374 	ih->ih_irq = irq;
    375 	ih->ih_what = ""; /* XXX - should be eliminated */
    376 	*p = ih;
    377 
    378 	return (ih);
    379 }
    380 
    381 void
    382 isabr_intr_disestablish(ic, arg)
    383         isa_chipset_tag_t ic;
    384         void *arg;
    385 {
    386 
    387 }
    388 
    389 /*
    390  *	Process an interrupt from the ISA bus.
    391  */
    392 int
    393 isabr_iointr(mask, cf)
    394         unsigned mask;
    395         struct clockframe *cf;
    396 {
    397 	struct intrhand *ih;
    398 	int isa_vector;
    399 	int o_imen;
    400 
    401 	isa_vector = (*isabr_conf->ic_intr_status)();
    402 	if (isa_vector < 0)
    403 		return (~0);
    404 
    405 	o_imen = imen;
    406 	imen |= 1 << (isa_vector & (ICU_LEN - 1));
    407 	if(isa_vector & 0x08) {
    408 		isa_inb(IO_ICU2 + 1);
    409 		isa_outb(IO_ICU2 + 1, imen >> 8);
    410 		isa_outb(IO_ICU2, 0x60 + (isa_vector & 7));
    411 		isa_outb(IO_ICU1, 0x60 + IRQ_SLAVE);
    412 	}
    413 	else {
    414 		isa_inb(IO_ICU1 + 1);
    415 		isa_outb(IO_ICU1 + 1, imen);
    416 		isa_outb(IO_ICU1, 0x60 + isa_vector);
    417 	}
    418 	ih = intrhand[isa_vector];
    419 	if(isa_vector == 0) {	/* Clock */	/*XXX*/
    420 		(*ih->ih_fun)(cf);
    421 		ih = ih->ih_next;
    422 	}
    423 	while(ih) {
    424 		(*ih->ih_fun)(ih->ih_arg);
    425 		ih = ih->ih_next;
    426 	}
    427 	imen = o_imen;
    428 	isa_inb(IO_ICU1 + 1);
    429 	isa_inb(IO_ICU2 + 1);
    430 	isa_outb(IO_ICU1 + 1, imen);
    431 	isa_outb(IO_ICU2 + 1, imen >> 8);
    432 
    433 	return(~0);  /* Dont reenable */
    434 }
    435 
    436 
    437 /*
    438  * Initialize the Interrupt controller logic.
    439  */
    440 void
    441 isabr_initicu()
    442 {
    443 
    444 	int i;
    445 
    446 	for (i = 0; i < ICU_LEN; i++) {
    447 		switch (i) {
    448 		case 2:
    449 		case 8:
    450 			intrtype[i] = IST_EDGE;
    451 			break;
    452 		default:
    453 			intrtype[i] = IST_NONE;
    454 			break;
    455 		}
    456 	}
    457 
    458 	isa_outb(IO_ICU1, 0x11);		/* reset; program device, four bytes */
    459 	isa_outb(IO_ICU1+1, 0);			/* starting at this vector index */
    460 	isa_outb(IO_ICU1+1, 1 << IRQ_SLAVE);	/* slave on line 2 */
    461 	isa_outb(IO_ICU1+1, 1);			/* 8086 mode */
    462 	isa_outb(IO_ICU1+1, 0xff);		/* leave interrupts masked */
    463 	isa_outb(IO_ICU1, 0x68);		/* special mask mode (if available) */
    464 	isa_outb(IO_ICU1, 0x0a);		/* Read IRR by default. */
    465 #ifdef REORDER_IRQ
    466 	isa_outb(IO_ICU1, 0xc0 | (3 - 1));	/* pri order 3-7, 0-2 (com2 first) */
    467 #endif
    468 
    469 	isa_outb(IO_ICU2, 0x11);		/* reset; program device, four bytes */
    470 	isa_outb(IO_ICU2+1, 8);			/* staring at this vector index */
    471 	isa_outb(IO_ICU2+1, IRQ_SLAVE);
    472 	isa_outb(IO_ICU2+1, 1);			/* 8086 mode */
    473 	isa_outb(IO_ICU2+1, 0xff);		/* leave interrupts masked */
    474 	isa_outb(IO_ICU2, 0x68);		/* special mask mode (if available) */
    475 	isa_outb(IO_ICU2, 0x0a);		/* Read IRR by default. */
    476 }
    477 
    478 
    479 /*
    480  *	SPEAKER BEEPER...
    481  */
    482 void
    483 sysbeepstop(arg)
    484 	void *arg;
    485 {
    486 	int s;
    487 
    488 	/* disable counter 2 */
    489 	s = splhigh();
    490 	isa_outb(PITAUX_PORT, isa_inb(PITAUX_PORT) & ~PIT_SPKR);
    491 	splx(s);
    492 	beeping = 0;
    493 }
    494 
    495 void
    496 sysbeep(pitch, period)
    497 	int pitch, period;
    498 {
    499 	static int last_pitch, last_period;
    500 	int s;
    501 
    502 	if (cold)
    503 		return;		/* Can't beep yet. */
    504 
    505 	if (beeping)
    506 		callout_stop(&sysbeep_ch);
    507 	if (!beeping || last_pitch != pitch) {
    508 		s = splhigh();
    509 		isa_outb(IO_TIMER1 + TIMER_MODE,
    510 		    TIMER_SEL2 | TIMER_16BIT | TIMER_SQWAVE);
    511 		isa_outb(IO_TIMER1 + TIMER_CNTR2, TIMER_DIV(pitch) % 256);
    512 		isa_outb(IO_TIMER1 + TIMER_CNTR2, TIMER_DIV(pitch) / 256);
    513 		isa_outb(PITAUX_PORT, isa_inb(PITAUX_PORT) | PIT_SPKR);
    514 		splx(s);
    515 	}
    516 	last_pitch = pitch;
    517 	beeping = last_period = period;
    518 	callout_reset(&sysbeep_ch, period, sysbeepstop, NULL);
    519 }
    520 
    521 int
    522 isa_intr_alloc(isa_chipset_tag_t c, int mask, int type, int *irq_p)
    523 {
    524 	int irq;
    525 	int maybe_irq = -1;
    526 	int shared_depth = 0;
    527 	mask &= 0x8b28; /* choose from 3, 5, 8, 9, 11, 15 XXX */
    528 	for (irq = 0; mask != 0; mask >>= 1, irq++) {
    529 		if ((mask & 1) == 0)
    530 			continue;
    531 		if (intrtype[irq] == IST_NONE) {
    532 			*irq_p = irq;
    533 			return 0;
    534 		}
    535 		/* Level interrupts can be shared */
    536 		if (type == IST_LEVEL && intrtype[irq] == IST_LEVEL) {
    537 			struct intrhand *ih = intrhand[irq];
    538 			int depth;
    539 			if (maybe_irq == -1) {
    540  				maybe_irq = irq;
    541 				continue;
    542 			}
    543 			for (depth = 0; ih != NULL; ih = ih->ih_next)
    544 				depth++;
    545 			if (depth < shared_depth) {
    546 				maybe_irq = irq;
    547 				shared_depth = depth;
    548 			}
    549 		}
    550 	}
    551 	if (maybe_irq != -1) {
    552 		*irq_p = maybe_irq;
    553 		return 0;
    554 	}
    555 	return 1;
    556 }
    557