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@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