1 /* $NetBSD: isa_machdep.c,v 1.2 2002/11/03 21:43:31 chris Exp $ */ 2 3 /*- 4 * Copyright (c) 1996-1998 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Mark Brinicombe, Charles M. Hannum and by Jason R. Thorpe of the 9 * Numerical Aerospace Simulation Facility, NASA Ames Research Center. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. All advertising materials mentioning features or use of this software 20 * must display the following acknowledgement: 21 * This product includes software developed by the NetBSD 22 * Foundation, Inc. and its contributors. 23 * 4. Neither the name of The NetBSD Foundation nor the names of its 24 * contributors may be used to endorse or promote products derived 25 * from this software without specific prior written permission. 26 * 27 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 28 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 29 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 30 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 31 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 33 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 34 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 35 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 37 * POSSIBILITY OF SUCH DAMAGE. 38 */ 39 40 /*- 41 * Copyright (c) 1991 The Regents of the University of California. 42 * All rights reserved. 43 * 44 * This code is derived from software contributed to Berkeley by 45 * William Jolitz. 46 * 47 * Redistribution and use in source and binary forms, with or without 48 * modification, are permitted provided that the following conditions 49 * are met: 50 * 1. Redistributions of source code must retain the above copyright 51 * notice, this list of conditions and the following disclaimer. 52 * 2. Redistributions in binary form must reproduce the above copyright 53 * notice, this list of conditions and the following disclaimer in the 54 * documentation and/or other materials provided with the distribution. 55 * 3. All advertising materials mentioning features or use of this software 56 * must display the following acknowledgement: 57 * This product includes software developed by the University of 58 * California, Berkeley and its contributors. 59 * 4. Neither the name of the University nor the names of its contributors 60 * may be used to endorse or promote products derived from this software 61 * without specific prior written permission. 62 * 63 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 64 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 65 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 66 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 67 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 68 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 69 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 70 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 71 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 72 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 73 * SUCH DAMAGE. 74 * 75 * @(#)isa.c 7.2 (Berkeley) 5/13/91 76 */ 77 78 #include "opt_irqstats.h" 79 80 #include <sys/param.h> 81 #include <sys/systm.h> 82 #include <sys/kernel.h> 83 #include <sys/syslog.h> 84 #include <sys/device.h> 85 #include <sys/malloc.h> 86 #include <sys/proc.h> 87 88 #define _ARM32_BUS_DMA_PRIVATE 89 #include <machine/bus.h> 90 91 #include <machine/intr.h> 92 #include <machine/pio.h> 93 #include <machine/bootconfig.h> 94 #include <machine/isa_machdep.h> 95 96 #include <dev/isa/isareg.h> 97 #include <dev/isa/isavar.h> 98 #include <dev/isa/isadmareg.h> 99 #include <dev/isa/isadmavar.h> 100 #include <arm/footbridge/isa/icu.h> 101 #include <arm/footbridge/dc21285reg.h> 102 #include <arm/footbridge/dc21285mem.h> 103 104 #include <uvm/uvm_extern.h> 105 106 #include "isadma.h" 107 108 /* prototypes */ 109 static void isa_icu_init __P((void)); 110 111 struct arm32_isa_chipset isa_chipset_tag; 112 113 void isa_strayintr __P((int)); 114 void intr_calculatemasks __P((void)); 115 int fakeintr __P((void *)); 116 117 int isa_irqdispatch __P((void *arg)); 118 119 u_int imask[NIPL]; 120 unsigned imen; 121 122 #define AUTO_EOI_1 123 #define AUTO_EOI_2 124 125 /* 126 * Fill in default interrupt table (in case of spuruious interrupt 127 * during configuration of kernel, setup interrupt control unit 128 */ 129 static void 130 isa_icu_init(void) 131 { 132 /* initialize 8259's */ 133 outb(IO_ICU1, 0x11); /* reset; program device, four bytes */ 134 outb(IO_ICU1+1, ICU_OFFSET); /* starting at this vector index */ 135 outb(IO_ICU1+1, 1 << IRQ_SLAVE); /* slave on line 2 */ 136 #ifdef AUTO_EOI_1 137 outb(IO_ICU1+1, 2 | 1); /* auto EOI, 8086 mode */ 138 #else 139 outb(IO_ICU1+1, 1); /* 8086 mode */ 140 #endif 141 outb(IO_ICU1+1, 0xff); /* leave interrupts masked */ 142 outb(IO_ICU1, 0x68); /* special mask mode (if available) */ 143 outb(IO_ICU1, 0x0a); /* Read IRR by default. */ 144 #ifdef REORDER_IRQ 145 outb(IO_ICU1, 0xc0 | (3 - 1)); /* pri order 3-7, 0-2 (com2 first) */ 146 #endif 147 148 outb(IO_ICU2, 0x11); /* reset; program device, four bytes */ 149 outb(IO_ICU2+1, ICU_OFFSET+8); /* staring at this vector index */ 150 outb(IO_ICU2+1, IRQ_SLAVE); 151 #ifdef AUTO_EOI_2 152 outb(IO_ICU2+1, 2 | 1); /* auto EOI, 8086 mode */ 153 #else 154 outb(IO_ICU2+1, 1); /* 8086 mode */ 155 #endif 156 outb(IO_ICU2+1, 0xff); /* leave interrupts masked */ 157 outb(IO_ICU2, 0x68); /* special mask mode (if available) */ 158 outb(IO_ICU2, 0x0a); /* Read IRR by default. */ 159 } 160 161 /* 162 * Caught a stray interrupt, notify 163 */ 164 void 165 isa_strayintr(irq) 166 int irq; 167 { 168 static u_long strays; 169 170 /* 171 * Stray interrupts on irq 7 occur when an interrupt line is raised 172 * and then lowered before the CPU acknowledges it. This generally 173 * means either the device is screwed or something is cli'ing too 174 * long and it's timing out. 175 */ 176 if (++strays <= 5) 177 log(LOG_ERR, "stray interrupt %d%s\n", irq, 178 strays >= 5 ? "; stopped logging" : ""); 179 } 180 181 static struct intrq isa_intrq[ICU_LEN]; 182 183 /* 184 * Recalculate the interrupt masks from scratch. 185 * We could code special registry and deregistry versions of this function that 186 * would be faster, but the code would be nastier, and we don't expect this to 187 * happen very much anyway. 188 */ 189 void 190 intr_calculatemasks() 191 { 192 int irq, level; 193 struct intrq *iq; 194 struct intrhand *ih; 195 196 /* First, figure out which levels each IRQ uses. */ 197 for (irq = 0; irq < ICU_LEN; irq++) { 198 int levels = 0; 199 iq = &isa_intrq[irq]; 200 for (ih = TAILQ_FIRST(&iq->iq_list); ih != NULL; 201 ih = TAILQ_NEXT(ih, ih_list)) 202 levels |= (1U << ih->ih_ipl); 203 iq->iq_levels = levels; 204 } 205 206 /* Then figure out which IRQs use each level. */ 207 for (level = 0; level < NIPL; level++) { 208 int irqs = 0; 209 for (irq = 0; irq < ICU_LEN; irq++) 210 if (isa_intrq[irq].iq_levels & (1U << level)) 211 irqs |= (1U << irq); 212 imask[level] = irqs; 213 } 214 215 /* 216 * IPL_NONE is used for hardware interrupts that are never blocked, 217 * and do not block anything else. 218 */ 219 imask[IPL_NONE] = 0; 220 221 imask[IPL_SOFT] |= imask[IPL_NONE]; 222 imask[IPL_SOFTCLOCK] |= imask[IPL_SOFT]; 223 imask[IPL_SOFTNET] |= imask[IPL_SOFTCLOCK]; 224 225 /* 226 * Enforce a hierarchy that gives slow devices a better chance at not 227 * dropping data. 228 */ 229 imask[IPL_BIO] |= imask[IPL_SOFTCLOCK]; 230 imask[IPL_NET] |= imask[IPL_BIO]; 231 imask[IPL_SOFTSERIAL] |= imask[IPL_NET]; 232 imask[IPL_TTY] |= imask[IPL_NET]; 233 /* 234 * There are tty, network and disk drivers that use free() at interrupt 235 * time, so imp > (tty | net | bio). 236 */ 237 imask[IPL_IMP] |= imask[IPL_TTY]; 238 imask[IPL_AUDIO] |= imask[IPL_IMP]; 239 240 /* 241 * Since run queues may be manipulated by both the statclock and tty, 242 * network, and disk drivers, clock > imp. 243 */ 244 imask[IPL_CLOCK] |= imask[IPL_IMP]; 245 imask[IPL_STATCLOCK] |= imask[IPL_CLOCK]; 246 247 /* 248 * IPL_HIGH must block everything that can manipulate a run queue. 249 */ 250 imask[IPL_HIGH] |= imask[IPL_STATCLOCK]; 251 252 /* 253 * We need serial drivers to run at the absolute highest priority to 254 * avoid overruns, so serial > high. 255 */ 256 imask[IPL_SERIAL] |= imask[IPL_HIGH]; 257 258 /* And eventually calculate the complete masks. */ 259 for (irq = 0; irq < ICU_LEN; irq++) { 260 int irqs = 1 << irq; 261 iq = &isa_intrq[irq]; 262 for (ih = TAILQ_FIRST(&iq->iq_list); ih != NULL; 263 ih = TAILQ_NEXT(ih, ih_list)) 264 irqs |= imask[ih->ih_ipl]; 265 iq->iq_mask = irqs; 266 } 267 268 /* Lastly, determine which IRQs are actually in use. */ 269 { 270 int irqs = 0; 271 for (irq = 0; irq < ICU_LEN; irq++) 272 if (!TAILQ_EMPTY(&isa_intrq[irq].iq_list)) 273 irqs |= (1U << irq); 274 if (irqs >= 0x100) /* any IRQs >= 8 in use */ 275 irqs |= 1 << IRQ_SLAVE; 276 imen = ~irqs; 277 SET_ICUS(); 278 } 279 #if 0 280 printf("type\tmask\tlevel\thand\n"); 281 for (irq = 0; irq < ICU_LEN; irq++) { 282 printf("%x\t%04x\t%x\t%p\n", intrtype[irq], intrmask[irq], 283 intrlevel[irq], intrhand[irq]); 284 } 285 for (level = 0; level < IPL_LEVELS; ++level) 286 printf("%d: %08x\n", level, imask[level]); 287 #endif 288 } 289 290 int 291 fakeintr(arg) 292 void *arg; 293 { 294 295 return 0; 296 } 297 298 #define LEGAL_IRQ(x) ((x) >= 0 && (x) < ICU_LEN && (x) != 2) 299 300 int 301 isa_intr_alloc(ic, mask, type, irq) 302 isa_chipset_tag_t ic; 303 int mask; 304 int type; 305 int *irq; 306 { 307 int i, tmp, bestirq, count; 308 struct intrq *iq; 309 struct intrhand *ih; 310 311 if (type == IST_NONE) 312 panic("intr_alloc: bogus type"); 313 314 bestirq = -1; 315 count = -1; 316 317 /* some interrupts should never be dynamically allocated */ 318 mask &= 0xdef8; 319 320 /* 321 * XXX some interrupts will be used later (6 for fdc, 12 for pms). 322 * the right answer is to do "breadth-first" searching of devices. 323 */ 324 mask &= 0xefbf; 325 326 for (i = 0; i < ICU_LEN; i++) { 327 if (LEGAL_IRQ(i) == 0 || (mask & (1<<i)) == 0) 328 continue; 329 330 iq = &isa_intrq[i]; 331 switch(iq->iq_ist) { 332 case IST_NONE: 333 /* 334 * if nothing's using the irq, just return it 335 */ 336 *irq = i; 337 return (0); 338 339 case IST_EDGE: 340 case IST_LEVEL: 341 if (type != iq->iq_ist) 342 continue; 343 /* 344 * if the irq is shareable, count the number of other 345 * handlers, and if it's smaller than the last irq like 346 * this, remember it 347 * 348 * XXX We should probably also consider the 349 * interrupt level and stick IPL_TTY with other 350 * IPL_TTY, etc. 351 */ 352 tmp = 0; 353 TAILQ_FOREACH(ih, &(iq->iq_list), ih_list) 354 tmp++; 355 if ((bestirq == -1) || (count > tmp)) { 356 bestirq = i; 357 count = tmp; 358 } 359 break; 360 361 case IST_PULSE: 362 /* this just isn't shareable */ 363 continue; 364 } 365 } 366 367 if (bestirq == -1) 368 return (1); 369 370 *irq = bestirq; 371 372 return (0); 373 } 374 375 const struct evcnt * 376 isa_intr_evcnt(isa_chipset_tag_t ic, int irq) 377 { 378 return &isa_intrq[irq].iq_ev; 379 } 380 381 /* 382 * Set up an interrupt handler to start being called. 383 * XXX PRONE TO RACE CONDITIONS, UGLY, 'INTERESTING' INSERTION ALGORITHM. 384 */ 385 void * 386 isa_intr_establish(ic, irq, type, level, ih_fun, ih_arg) 387 isa_chipset_tag_t ic; 388 int irq; 389 int type; 390 int level; 391 int (*ih_fun) __P((void *)); 392 void *ih_arg; 393 { 394 struct intrq *iq; 395 struct intrhand *ih; 396 u_int oldirqstate; 397 398 #if 0 399 printf("isa_intr_establish(%d, %d, %d)\n", irq, type, level); 400 #endif 401 /* no point in sleeping unless someone can free memory. */ 402 ih = malloc(sizeof *ih, M_DEVBUF, cold ? M_NOWAIT : M_WAITOK); 403 if (ih == NULL) 404 return (NULL); 405 406 if (!LEGAL_IRQ(irq) || type == IST_NONE) 407 panic("intr_establish: bogus irq or type"); 408 409 iq = &isa_intrq[irq]; 410 411 switch (iq->iq_ist) { 412 case IST_NONE: 413 iq->iq_ist = type; 414 #if 0 415 printf("Setting irq %d to type %d - ", irq, type); 416 #endif 417 if (irq < 8) { 418 outb(0x4d0, (inb(0x4d0) & ~(1 << irq)) 419 | ((type == IST_LEVEL) ? (1 << irq) : 0)); 420 /* printf("%02x\n", inb(0x4d0));*/ 421 } else { 422 outb(0x4d1, (inb(0x4d1) & ~(1 << irq)) 423 | ((type == IST_LEVEL) ? (1 << irq) : 0)); 424 /* printf("%02x\n", inb(0x4d1));*/ 425 } 426 break; 427 case IST_EDGE: 428 case IST_LEVEL: 429 if (iq->iq_ist == type) 430 break; 431 case IST_PULSE: 432 if (type != IST_NONE) 433 panic("intr_establish: can't share %s with %s", 434 isa_intr_typename(iq->iq_ist), 435 isa_intr_typename(type)); 436 break; 437 } 438 439 ih->ih_func = ih_fun; 440 ih->ih_arg = ih_arg; 441 ih->ih_ipl = level; 442 ih->ih_irq = irq; 443 444 /* do not stop us */ 445 oldirqstate = disable_interrupts(I32_bit); 446 447 TAILQ_INSERT_TAIL(&iq->iq_list, ih, ih_list); 448 449 intr_calculatemasks(); 450 restore_interrupts(oldirqstate); 451 452 return (ih); 453 } 454 455 /* 456 * Deregister an interrupt handler. 457 */ 458 void 459 isa_intr_disestablish(ic, arg) 460 isa_chipset_tag_t ic; 461 void *arg; 462 { 463 struct intrhand *ih = arg; 464 struct intrq *iq = &isa_intrq[ih->ih_irq]; 465 int irq = ih->ih_irq; 466 u_int oldirqstate; 467 468 if (!LEGAL_IRQ(irq)) 469 panic("intr_disestablish: bogus irq"); 470 471 oldirqstate = disable_interrupts(I32_bit); 472 473 TAILQ_REMOVE(&iq->iq_list, ih, ih_list); 474 475 intr_calculatemasks(); 476 477 restore_interrupts(oldirqstate); 478 479 free(ih, M_DEVBUF); 480 481 if (TAILQ_EMPTY(&(iq->iq_list))) 482 iq->iq_ist = IST_NONE; 483 } 484 485 /* 486 * isa_intr_init() 487 * 488 * Initialise the ISA ICU and attach an ISA interrupt handler to the 489 * ISA interrupt line on the footbridge. 490 */ 491 void 492 isa_intr_init(void) 493 { 494 static void *isa_ih; 495 struct intrq *iq; 496 int i; 497 498 /* 499 * should get the parent here, but initialisation order being so 500 * strange I need to check if it's available 501 */ 502 for (i = 0; i < ICU_LEN; i++) { 503 iq = &isa_intrq[i]; 504 TAILQ_INIT(&iq->iq_list); 505 506 sprintf(iq->iq_name, "irq %d", i); 507 evcnt_attach_dynamic(&iq->iq_ev, EVCNT_TYPE_INTR, 508 NULL, "isa", iq->iq_name); 509 } 510 511 isa_icu_init(); 512 intr_calculatemasks(); 513 /* something to break the build in an informative way */ 514 #ifndef ISA_FOOTBRIDGE_IRQ 515 #warning Before using isa with footbridge you must define ISA_FOOTBRIDGE_IRQ 516 #endif 517 isa_ih = footbridge_intr_claim(ISA_FOOTBRIDGE_IRQ, IPL_BIO, "isabus", 518 isa_irqdispatch, NULL); 519 520 } 521 522 /* Static array of ISA DMA segments. We only have one on CATS */ 523 #if NISADMA > 0 524 struct arm32_dma_range machdep_isa_dma_ranges[1]; 525 #endif 526 527 void 528 isa_footbridge_init(iobase, membase) 529 u_int iobase, membase; 530 { 531 #if NISADMA > 0 532 extern struct arm32_dma_range *footbridge_isa_dma_ranges; 533 extern int footbridge_isa_dma_nranges; 534 535 machdep_isa_dma_ranges[0].dr_sysbase = bootconfig.dram[0].address; 536 machdep_isa_dma_ranges[0].dr_busbase = bootconfig.dram[0].address; 537 machdep_isa_dma_ranges[0].dr_len = (16 * 1024 * 1024); 538 539 footbridge_isa_dma_ranges = machdep_isa_dma_ranges; 540 footbridge_isa_dma_nranges = 1; 541 #endif 542 543 isa_io_init(iobase, membase); 544 } 545 546 void 547 isa_attach_hook(parent, self, iba) 548 struct device *parent, *self; 549 struct isabus_attach_args *iba; 550 { 551 /* 552 * Since we can only have one ISA bus, we just use a single 553 * statically allocated ISA chipset structure. Pass it up 554 * now. 555 */ 556 iba->iba_ic = &isa_chipset_tag; 557 #if NISADMA > 0 558 isa_dma_init(); 559 #endif 560 } 561 562 int 563 isa_irqdispatch(arg) 564 void *arg; 565 { 566 struct clockframe *frame = arg; 567 int irq; 568 struct intrq *iq; 569 struct intrhand *ih; 570 u_int iack; 571 int res = 0; 572 573 iack = *((u_int *)(DC21285_PCI_IACK_VBASE)); 574 iack &= 0xff; 575 if (iack < 0x20 || iack > 0x2f) { 576 printf("isa_irqdispatch: %x\n", iack); 577 return(0); 578 } 579 580 irq = iack & 0x0f; 581 iq = &isa_intrq[irq]; 582 iq->iq_ev.ev_count++; 583 for (ih = TAILQ_FIRST(&iq->iq_list); res != 1 && ih != NULL; 584 ih = TAILQ_NEXT(ih, ih_list)) { 585 res = (*ih->ih_func)(ih->ih_arg ? ih->ih_arg : frame); 586 } 587 return res; 588 } 589 590 591 void 592 isa_fillw(val, addr, len) 593 u_int val; 594 void *addr; 595 size_t len; 596 { 597 if ((u_int)addr >= isa_mem_data_vaddr() 598 && (u_int)addr < isa_mem_data_vaddr() + 0x100000) { 599 bus_size_t offset = ((u_int)addr) & 0xfffff; 600 bus_space_set_region_2(&isa_mem_bs_tag, 601 (bus_space_handle_t)isa_mem_bs_tag.bs_cookie, offset, 602 val, len); 603 } else { 604 u_short *ptr = addr; 605 606 while (len > 0) { 607 *ptr++ = val; 608 --len; 609 } 610 } 611 } 612