Home | History | Annotate | Line # | Download | only in isa
isabus.c revision 1.21
      1 /*	$NetBSD: isabus.c,v 1.21 2003/06/14 19:11:41 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_EDGE:
    322 	case IST_LEVEL:
    323 		if (type == intrtype[irq])
    324 			break;
    325 	case IST_PULSE:
    326 		if (type != IST_NONE)
    327 			panic("intr_establish: can't share %s with %s",
    328 			    isa_intr_typename(intrtype[irq]),
    329 			    isa_intr_typename(type));
    330 		break;
    331 	}
    332 
    333 	/*
    334 	 * Figure out where to put the handler.
    335 	 * This is O(N^2), but we want to preserve the order, and N is
    336 	 * generally small.
    337 	 */
    338 	for (p = &intrhand[irq]; (q = *p) != NULL; p = &q->ih_next)
    339 		;
    340 
    341 	/*
    342 	 * Actually install a fake handler momentarily, since we might be doing
    343 	 * this with interrupts enabled and don't want the real routine called
    344 	 * until masking is set up.
    345 	 */
    346 	fakehand.ih_level = level;
    347 	*p = &fakehand;
    348 
    349 	intr_calculatemasks();
    350 
    351 	/*
    352 	 * Poke the real handler in now.
    353 	 */
    354 	ih->ih_fun = ih_fun;
    355 	ih->ih_arg = ih_arg;
    356 	ih->ih_count = 0;
    357 	ih->ih_next = NULL;
    358 	ih->ih_level = level;
    359 	ih->ih_irq = irq;
    360 	ih->ih_what = ""; /* XXX - should be eliminated */
    361 	*p = ih;
    362 
    363 	return (ih);
    364 }
    365 
    366 void
    367 isabr_intr_disestablish(ic, arg)
    368         isa_chipset_tag_t ic;
    369         void *arg;
    370 {
    371 
    372 }
    373 
    374 /*
    375  *	Process an interrupt from the ISA bus.
    376  */
    377 int
    378 isabr_iointr(mask, cf)
    379         unsigned mask;
    380         struct clockframe *cf;
    381 {
    382 	struct intrhand *ih;
    383 	int isa_vector;
    384 	int o_imen;
    385 
    386 	isa_vector = (*isabr_conf->ic_intr_status)();
    387 	if (isa_vector < 0)
    388 		return (~0);
    389 
    390 	o_imen = imen;
    391 	imen |= 1 << (isa_vector & (ICU_LEN - 1));
    392 	if(isa_vector & 0x08) {
    393 		isa_inb(IO_ICU2 + 1);
    394 		isa_outb(IO_ICU2 + 1, imen >> 8);
    395 		isa_outb(IO_ICU2, 0x60 + (isa_vector & 7));
    396 		isa_outb(IO_ICU1, 0x60 + IRQ_SLAVE);
    397 	}
    398 	else {
    399 		isa_inb(IO_ICU1 + 1);
    400 		isa_outb(IO_ICU1 + 1, imen);
    401 		isa_outb(IO_ICU1, 0x60 + isa_vector);
    402 	}
    403 	ih = intrhand[isa_vector];
    404 	if(isa_vector == 0) {	/* Clock */	/*XXX*/
    405 		(*ih->ih_fun)(cf);
    406 		ih = ih->ih_next;
    407 	}
    408 	while(ih) {
    409 		(*ih->ih_fun)(ih->ih_arg);
    410 		ih = ih->ih_next;
    411 	}
    412 	imen = o_imen;
    413 	isa_inb(IO_ICU1 + 1);
    414 	isa_inb(IO_ICU2 + 1);
    415 	isa_outb(IO_ICU1 + 1, imen);
    416 	isa_outb(IO_ICU2 + 1, imen >> 8);
    417 
    418 	return(~0);  /* Dont reenable */
    419 }
    420 
    421 
    422 /*
    423  * Initialize the Interrupt controller logic.
    424  */
    425 void
    426 isabr_initicu()
    427 {
    428 
    429 	isa_outb(IO_ICU1, 0x11);		/* reset; program device, four bytes */
    430 	isa_outb(IO_ICU1+1, 0);			/* starting at this vector index */
    431 	isa_outb(IO_ICU1+1, 1 << IRQ_SLAVE);	/* slave on line 2 */
    432 	isa_outb(IO_ICU1+1, 1);			/* 8086 mode */
    433 	isa_outb(IO_ICU1+1, 0xff);		/* leave interrupts masked */
    434 	isa_outb(IO_ICU1, 0x68);		/* special mask mode (if available) */
    435 	isa_outb(IO_ICU1, 0x0a);		/* Read IRR by default. */
    436 #ifdef REORDER_IRQ
    437 	isa_outb(IO_ICU1, 0xc0 | (3 - 1));	/* pri order 3-7, 0-2 (com2 first) */
    438 #endif
    439 
    440 	isa_outb(IO_ICU2, 0x11);		/* reset; program device, four bytes */
    441 	isa_outb(IO_ICU2+1, 8);			/* staring at this vector index */
    442 	isa_outb(IO_ICU2+1, IRQ_SLAVE);
    443 	isa_outb(IO_ICU2+1, 1);			/* 8086 mode */
    444 	isa_outb(IO_ICU2+1, 0xff);		/* leave interrupts masked */
    445 	isa_outb(IO_ICU2, 0x68);		/* special mask mode (if available) */
    446 	isa_outb(IO_ICU2, 0x0a);		/* Read IRR by default. */
    447 }
    448 
    449 
    450 /*
    451  *	SPEAKER BEEPER...
    452  */
    453 void
    454 sysbeepstop(arg)
    455 	void *arg;
    456 {
    457 	int s;
    458 
    459 	/* disable counter 2 */
    460 	s = splhigh();
    461 	isa_outb(PITAUX_PORT, isa_inb(PITAUX_PORT) & ~PIT_SPKR);
    462 	splx(s);
    463 	beeping = 0;
    464 }
    465 
    466 void
    467 sysbeep(pitch, period)
    468 	int pitch, period;
    469 {
    470 	static int last_pitch, last_period;
    471 	int s;
    472 
    473 	if (cold)
    474 		return;		/* Can't beep yet. */
    475 
    476 	if (beeping)
    477 		callout_stop(&sysbeep_ch);
    478 	if (!beeping || last_pitch != pitch) {
    479 		s = splhigh();
    480 		isa_outb(IO_TIMER1 + TIMER_MODE,
    481 		    TIMER_SEL2 | TIMER_16BIT | TIMER_SQWAVE);
    482 		isa_outb(IO_TIMER1 + TIMER_CNTR2, TIMER_DIV(pitch) % 256);
    483 		isa_outb(IO_TIMER1 + TIMER_CNTR2, TIMER_DIV(pitch) / 256);
    484 		isa_outb(PITAUX_PORT, isa_inb(PITAUX_PORT) | PIT_SPKR);
    485 		splx(s);
    486 	}
    487 	last_pitch = pitch;
    488 	beeping = last_period = period;
    489 	callout_reset(&sysbeep_ch, period, sysbeepstop, NULL);
    490 }
    491 
    492 int
    493 isa_intr_alloc(isa_chipset_tag_t c, int mask, int type, int *irq_p)
    494 {
    495 	int irq;
    496 	int maybe_irq = -1;
    497 	int shared_depth = 0;
    498 	mask &= 0x8b28; /* choose from 3, 5, 8, 9, 11, 15 XXX */
    499 	for (irq = 0; mask != 0; mask >>= 1, irq++) {
    500 		if ((mask & 1) == 0)
    501 			continue;
    502 		if (intrtype[irq] == IST_NONE) {
    503 			*irq_p = irq;
    504 			return 0;
    505 		}
    506 		/* Level interrupts can be shared */
    507 		if (type == IST_LEVEL && intrtype[irq] == IST_LEVEL) {
    508 			struct intrhand *ih = intrhand[irq];
    509 			int depth;
    510 			if (maybe_irq == -1) {
    511  				maybe_irq = irq;
    512 				continue;
    513 			}
    514 			for (depth = 0; ih != NULL; ih = ih->ih_next)
    515 				depth++;
    516 			if (depth < shared_depth) {
    517 				maybe_irq = irq;
    518 				shared_depth = depth;
    519 			}
    520 		}
    521 	}
    522 	if (maybe_irq != -1) {
    523 		*irq_p = maybe_irq;
    524 		return 0;
    525 	}
    526 	return 1;
    527 }
    528