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