Home | History | Annotate | Line # | Download | only in isa
isabus.c revision 1.23
      1 /*	$NetBSD: isabus.c,v 1.23 2003/06/15 05:58:45 tsutsui 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/param.h>
     92 #include <sys/proc.h>
     93 #include <sys/user.h>
     94 #include <sys/systm.h>
     95 #include <sys/callout.h>
     96 #include <sys/time.h>
     97 #include <sys/kernel.h>
     98 #include <sys/device.h>
     99 #include <sys/malloc.h>
    100 #include <sys/extent.h>
    101 
    102 #include <uvm/uvm_extern.h>
    103 
    104 #include <machine/cpu.h>
    105 #include <machine/pio.h>
    106 #include <machine/autoconf.h>
    107 #include <machine/intr.h>
    108 
    109 #include <dev/ic/i8253reg.h>
    110 #include <dev/isa/isareg.h>
    111 #include <dev/isa/isavar.h>
    112 #include <arc/isa/isabrvar.h>
    113 #include <arc/isa/spkrreg.h>
    114 
    115 static int beeping;
    116 static struct callout sysbeep_ch = CALLOUT_INITIALIZER;
    117 
    118 static long isa_mem_ex_storage[EXTENT_FIXED_STORAGE_SIZE(16) / sizeof(long)];
    119 static long isa_io_ex_storage[EXTENT_FIXED_STORAGE_SIZE(16) / sizeof(long)];
    120 
    121 #define	IRQ_SLAVE	2
    122 
    123 /* Definition of the driver for autoconfig. */
    124 int	isabrprint(void *, const char *);
    125 
    126 extern struct arc_bus_space arc_bus_io, arc_bus_mem;
    127 
    128 void	isabr_attach_hook __P((struct device *, struct device *,
    129 			struct isabus_attach_args *));
    130 const struct evcnt *isabr_intr_evcnt __P((isa_chipset_tag_t, int));
    131 void	*isabr_intr_establish __P((isa_chipset_tag_t, int, int, int,
    132 			int (*)(void *), void *));
    133 void	isabr_intr_disestablish __P((isa_chipset_tag_t, void*));
    134 int	isabr_iointr __P((unsigned int, struct clockframe *));
    135 void	isabr_initicu __P((void));
    136 void	intr_calculatemasks __P((void));
    137 int	fakeintr __P((void *a));
    138 
    139 struct isabr_config *isabr_conf = NULL;
    140 u_int32_t imask[_IPL_N];	/* XXX */
    141 
    142 void
    143 isabrattach(sc)
    144 	struct isabr_softc *sc;
    145 {
    146 	struct isabus_attach_args iba;
    147 
    148 	if (isabr_conf == NULL)
    149 		panic("isabr_conf isn't initialized");
    150 
    151 	printf("\n");
    152 
    153 	/* Initialize interrupt controller */
    154 	isabr_initicu();
    155 
    156 /*XXX we may remove the abus part of the softc struct... */
    157 	sc->sc_bus.ab_dv = (struct device *)sc;
    158 	sc->sc_bus.ab_type = BUS_ISABR;
    159 
    160 	sc->arc_isa_cs.ic_attach_hook = isabr_attach_hook;
    161 	sc->arc_isa_cs.ic_intr_evcnt = isabr_intr_evcnt;
    162 	sc->arc_isa_cs.ic_intr_establish = isabr_intr_establish;
    163 	sc->arc_isa_cs.ic_intr_disestablish = isabr_intr_disestablish;
    164 
    165 	arc_bus_space_init_extent(&arc_bus_mem, (caddr_t)isa_mem_ex_storage,
    166 	    sizeof(isa_mem_ex_storage));
    167 	arc_bus_space_init_extent(&arc_bus_io, (caddr_t)isa_io_ex_storage,
    168 	    sizeof(isa_io_ex_storage));
    169 
    170 	iba.iba_busname = "isa";
    171 	iba.iba_iot = &arc_bus_io;
    172 	iba.iba_memt = &arc_bus_mem;
    173 	iba.iba_dmat = &sc->sc_dmat;
    174 	iba.iba_ic = &sc->arc_isa_cs;
    175 	config_found(&sc->sc_dev, &iba, isabrprint);
    176 }
    177 
    178 int
    179 isabrprint(aux, pnp)
    180 	void *aux;
    181 	const char *pnp;
    182 {
    183 	struct confargs *ca = aux;
    184 
    185         if (pnp)
    186                 aprint_normal("%s at %s", ca->ca_name, pnp);
    187         aprint_verbose(" isa_io_base 0x%lx isa_mem_base 0x%lx",
    188 		arc_bus_io.bs_vbase, arc_bus_mem.bs_vbase);
    189         return (UNCONF);
    190 }
    191 
    192 
    193 /*
    194  *	Interrupt system driver code
    195  *	============================
    196  */
    197 #define LEGAL_IRQ(x)    ((x) >= 0 && (x) < ICU_LEN && (x) != 2)
    198 
    199 int	imen;
    200 int	intrtype[ICU_LEN], intrmask[ICU_LEN], intrlevel[ICU_LEN];
    201 struct intrhand *intrhand[ICU_LEN];
    202 
    203 int fakeintr(a)
    204 	void *a;
    205 {
    206 	return 0;
    207 }
    208 
    209 /*
    210  * Recalculate the interrupt masks from scratch.
    211  * We could code special registry and deregistry versions of this function that
    212  * would be faster, but the code would be nastier, and we don't expect this to
    213  * happen very much anyway.
    214  */
    215 void
    216 intr_calculatemasks()
    217 {
    218 	int irq, level;
    219 	struct intrhand *q;
    220 
    221 	/* First, figure out which levels each IRQ uses. */
    222 	for (irq = 0; irq < ICU_LEN; irq++) {
    223 		int levels = 0;
    224 		for (q = intrhand[irq]; q; q = q->ih_next)
    225 			levels |= 1 << q->ih_level;
    226 		intrlevel[irq] = levels;
    227 	}
    228 
    229 	/* Then figure out which IRQs use each level. */
    230 	for (level = 0; level < _IPL_N; level++) {
    231 		int irqs = 0;
    232 		for (irq = 0; irq < ICU_LEN; irq++)
    233 			if (intrlevel[irq] & (1 << level))
    234 				irqs |= 1 << irq;
    235 		imask[level] = irqs;
    236 	}
    237 
    238 	imask[IPL_NONE] = 0;
    239 
    240 	imask[IPL_SOFT] |= imask[IPL_NONE];
    241 	imask[IPL_SOFTCLOCK] |= imask[IPL_SOFT];
    242 	imask[IPL_SOFTNET] |= imask[IPL_SOFTCLOCK];
    243 	imask[IPL_SOFTSERIAL] |= imask[IPL_SOFTNET];
    244 
    245 	/*
    246 	 * Enforce a hierarchy that gives slow devices a better chance at not
    247 	 * dropping data.
    248 	 */
    249 	imask[IPL_BIO] |= imask[IPL_SOFTSERIAL];
    250 	imask[IPL_NET] |= imask[IPL_BIO];
    251 	imask[IPL_TTY] |= imask[IPL_NET];
    252 
    253 	/*
    254 	 * Since run queues may be manipulated by both the statclock and tty,
    255 	 * network, and diskdrivers, clock > tty.
    256 	 */
    257 	imask[IPL_CLOCK] |= imask[IPL_TTY];
    258 	imask[IPL_STATCLOCK] |= imask[IPL_CLOCK];
    259 
    260 	/*
    261 	 * IPL_HIGH must block everything that can manipulate a run queue.
    262 	 */
    263 	imask[IPL_HIGH] |= imask[IPL_STATCLOCK];
    264 
    265 	/* And eventually calculate the complete masks. */
    266 	for (irq = 0; irq < ICU_LEN; irq++) {
    267 		int irqs = 1 << irq;
    268 		for (q = intrhand[irq]; q; q = q->ih_next)
    269 			irqs |= imask[q->ih_level];
    270 		intrmask[irq] = irqs;
    271 	}
    272 
    273 	/* Lastly, determine which IRQs are actually in use. */
    274 	{
    275 		int irqs = 0;
    276 		for (irq = 0; irq < ICU_LEN; irq++)
    277 			if (intrhand[irq])
    278 				irqs |= 1 << irq;
    279 		if (irqs >= 0x100) /* any IRQs >= 8 in use */
    280 			irqs |= 1 << IRQ_SLAVE;
    281 		imen = ~irqs;
    282 		isa_outb(IO_ICU1 + 1, imen);
    283 		isa_outb(IO_ICU2 + 1, imen >> 8);
    284 	}
    285 }
    286 
    287 void
    288 isabr_attach_hook(parent, self, iba)
    289 	struct device *parent, *self;
    290 	struct isabus_attach_args *iba;
    291 {
    292 
    293 	/* Nothing to do. */
    294 }
    295 
    296 const struct evcnt *
    297 isabr_intr_evcnt(ic, irq)
    298 	isa_chipset_tag_t ic;
    299 	int irq;
    300 {
    301 
    302 	/* XXX for now, no evcnt parent reported */
    303 	return NULL;
    304 }
    305 
    306 /*
    307  *	Establish a ISA bus interrupt.
    308  */
    309 void *
    310 isabr_intr_establish(ic, irq, type, level, ih_fun, ih_arg)
    311         isa_chipset_tag_t ic;
    312         int irq;
    313         int type;
    314         int level;
    315         int (*ih_fun) __P((void *));
    316         void *ih_arg;
    317 {
    318 	struct intrhand **p, *q, *ih;
    319 	static struct intrhand fakehand = {NULL, fakeintr};
    320 
    321 	/* no point in sleeping unless someone can free memory. */
    322 	ih = malloc(sizeof *ih, M_DEVBUF, cold ? M_NOWAIT : M_WAITOK);
    323 	if (ih == NULL)
    324 		panic("isa_intr_establish: can't malloc handler info");
    325 
    326 	if (!LEGAL_IRQ(irq) || type == IST_NONE)
    327 		panic("intr_establish: bogus irq or type");
    328 
    329 	switch (intrtype[irq]) {
    330 	case IST_NONE:
    331 		intrtype[irq] = type;
    332 		break;
    333 	case IST_EDGE:
    334 	case IST_LEVEL:
    335 		if (type == intrtype[irq])
    336 			break;
    337 	case IST_PULSE:
    338 		if (type != IST_NONE)
    339 			panic("intr_establish: can't share %s with %s",
    340 			    isa_intr_typename(intrtype[irq]),
    341 			    isa_intr_typename(type));
    342 		break;
    343 	}
    344 
    345 	/*
    346 	 * Figure out where to put the handler.
    347 	 * This is O(N^2), but we want to preserve the order, and N is
    348 	 * generally small.
    349 	 */
    350 	for (p = &intrhand[irq]; (q = *p) != NULL; p = &q->ih_next)
    351 		;
    352 
    353 	/*
    354 	 * Actually install a fake handler momentarily, since we might be doing
    355 	 * this with interrupts enabled and don't want the real routine called
    356 	 * until masking is set up.
    357 	 */
    358 	fakehand.ih_level = level;
    359 	*p = &fakehand;
    360 
    361 	intr_calculatemasks();
    362 
    363 	/*
    364 	 * Poke the real handler in now.
    365 	 */
    366 	ih->ih_fun = ih_fun;
    367 	ih->ih_arg = ih_arg;
    368 	ih->ih_count = 0;
    369 	ih->ih_next = NULL;
    370 	ih->ih_level = level;
    371 	ih->ih_irq = irq;
    372 	ih->ih_what = ""; /* XXX - should be eliminated */
    373 	*p = ih;
    374 
    375 	return (ih);
    376 }
    377 
    378 void
    379 isabr_intr_disestablish(ic, arg)
    380         isa_chipset_tag_t ic;
    381         void *arg;
    382 {
    383 
    384 }
    385 
    386 /*
    387  *	Process an interrupt from the ISA bus.
    388  */
    389 int
    390 isabr_iointr(mask, cf)
    391         unsigned mask;
    392         struct clockframe *cf;
    393 {
    394 	struct intrhand *ih;
    395 	int isa_vector;
    396 	int o_imen;
    397 
    398 	isa_vector = (*isabr_conf->ic_intr_status)();
    399 	if (isa_vector < 0)
    400 		return (~0);
    401 
    402 	o_imen = imen;
    403 	imen |= 1 << (isa_vector & (ICU_LEN - 1));
    404 	if(isa_vector & 0x08) {
    405 		isa_inb(IO_ICU2 + 1);
    406 		isa_outb(IO_ICU2 + 1, imen >> 8);
    407 		isa_outb(IO_ICU2, 0x60 + (isa_vector & 7));
    408 		isa_outb(IO_ICU1, 0x60 + IRQ_SLAVE);
    409 	}
    410 	else {
    411 		isa_inb(IO_ICU1 + 1);
    412 		isa_outb(IO_ICU1 + 1, imen);
    413 		isa_outb(IO_ICU1, 0x60 + isa_vector);
    414 	}
    415 	ih = intrhand[isa_vector];
    416 	if(isa_vector == 0) {	/* Clock */	/*XXX*/
    417 		(*ih->ih_fun)(cf);
    418 		ih = ih->ih_next;
    419 	}
    420 	while(ih) {
    421 		(*ih->ih_fun)(ih->ih_arg);
    422 		ih = ih->ih_next;
    423 	}
    424 	imen = o_imen;
    425 	isa_inb(IO_ICU1 + 1);
    426 	isa_inb(IO_ICU2 + 1);
    427 	isa_outb(IO_ICU1 + 1, imen);
    428 	isa_outb(IO_ICU2 + 1, imen >> 8);
    429 
    430 	return(~0);  /* Dont reenable */
    431 }
    432 
    433 
    434 /*
    435  * Initialize the Interrupt controller logic.
    436  */
    437 void
    438 isabr_initicu()
    439 {
    440 
    441 	int i;
    442 
    443 	for (i = 0; i < ICU_LEN; i++) {
    444 		switch (i) {
    445 		case 2:
    446 		case 8:
    447 			intrtype[i] = IST_EDGE;
    448 			break;
    449 		default:
    450 			intrtype[i] = IST_NONE;
    451 			break;
    452 		}
    453 	}
    454 
    455 	isa_outb(IO_ICU1, 0x11);		/* reset; program device, four bytes */
    456 	isa_outb(IO_ICU1+1, 0);			/* starting at this vector index */
    457 	isa_outb(IO_ICU1+1, 1 << IRQ_SLAVE);	/* slave on line 2 */
    458 	isa_outb(IO_ICU1+1, 1);			/* 8086 mode */
    459 	isa_outb(IO_ICU1+1, 0xff);		/* leave interrupts masked */
    460 	isa_outb(IO_ICU1, 0x68);		/* special mask mode (if available) */
    461 	isa_outb(IO_ICU1, 0x0a);		/* Read IRR by default. */
    462 #ifdef REORDER_IRQ
    463 	isa_outb(IO_ICU1, 0xc0 | (3 - 1));	/* pri order 3-7, 0-2 (com2 first) */
    464 #endif
    465 
    466 	isa_outb(IO_ICU2, 0x11);		/* reset; program device, four bytes */
    467 	isa_outb(IO_ICU2+1, 8);			/* staring at this vector index */
    468 	isa_outb(IO_ICU2+1, IRQ_SLAVE);
    469 	isa_outb(IO_ICU2+1, 1);			/* 8086 mode */
    470 	isa_outb(IO_ICU2+1, 0xff);		/* leave interrupts masked */
    471 	isa_outb(IO_ICU2, 0x68);		/* special mask mode (if available) */
    472 	isa_outb(IO_ICU2, 0x0a);		/* Read IRR by default. */
    473 }
    474 
    475 
    476 /*
    477  *	SPEAKER BEEPER...
    478  */
    479 void
    480 sysbeepstop(arg)
    481 	void *arg;
    482 {
    483 	int s;
    484 
    485 	/* disable counter 2 */
    486 	s = splhigh();
    487 	isa_outb(PITAUX_PORT, isa_inb(PITAUX_PORT) & ~PIT_SPKR);
    488 	splx(s);
    489 	beeping = 0;
    490 }
    491 
    492 void
    493 sysbeep(pitch, period)
    494 	int pitch, period;
    495 {
    496 	static int last_pitch, last_period;
    497 	int s;
    498 
    499 	if (cold)
    500 		return;		/* Can't beep yet. */
    501 
    502 	if (beeping)
    503 		callout_stop(&sysbeep_ch);
    504 	if (!beeping || last_pitch != pitch) {
    505 		s = splhigh();
    506 		isa_outb(IO_TIMER1 + TIMER_MODE,
    507 		    TIMER_SEL2 | TIMER_16BIT | TIMER_SQWAVE);
    508 		isa_outb(IO_TIMER1 + TIMER_CNTR2, TIMER_DIV(pitch) % 256);
    509 		isa_outb(IO_TIMER1 + TIMER_CNTR2, TIMER_DIV(pitch) / 256);
    510 		isa_outb(PITAUX_PORT, isa_inb(PITAUX_PORT) | PIT_SPKR);
    511 		splx(s);
    512 	}
    513 	last_pitch = pitch;
    514 	beeping = last_period = period;
    515 	callout_reset(&sysbeep_ch, period, sysbeepstop, NULL);
    516 }
    517 
    518 int
    519 isa_intr_alloc(isa_chipset_tag_t c, int mask, int type, int *irq_p)
    520 {
    521 	int irq;
    522 	int maybe_irq = -1;
    523 	int shared_depth = 0;
    524 	mask &= 0x8b28; /* choose from 3, 5, 8, 9, 11, 15 XXX */
    525 	for (irq = 0; mask != 0; mask >>= 1, irq++) {
    526 		if ((mask & 1) == 0)
    527 			continue;
    528 		if (intrtype[irq] == IST_NONE) {
    529 			*irq_p = irq;
    530 			return 0;
    531 		}
    532 		/* Level interrupts can be shared */
    533 		if (type == IST_LEVEL && intrtype[irq] == IST_LEVEL) {
    534 			struct intrhand *ih = intrhand[irq];
    535 			int depth;
    536 			if (maybe_irq == -1) {
    537  				maybe_irq = irq;
    538 				continue;
    539 			}
    540 			for (depth = 0; ih != NULL; ih = ih->ih_next)
    541 				depth++;
    542 			if (depth < shared_depth) {
    543 				maybe_irq = irq;
    544 				shared_depth = depth;
    545 			}
    546 		}
    547 	}
    548 	if (maybe_irq != -1) {
    549 		*irq_p = maybe_irq;
    550 		return 0;
    551 	}
    552 	return 1;
    553 }
    554