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