1 /* $NetBSD: pcib.c,v 1.11 2005/12/11 12:17:11 christos Exp $ */ 2 3 /* 4 * Copyright 2002 Wasabi Systems, Inc. 5 * All rights reserved. 6 * 7 * Written by Simon Burge for Wasabi Systems, Inc. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. All advertising materials mentioning features or use of this software 18 * must display the following acknowledgement: 19 * This product includes software developed for the NetBSD Project by 20 * Wasabi Systems, Inc. 21 * 4. The name of Wasabi Systems, Inc. may not be used to endorse 22 * or promote products derived from this software without specific prior 23 * written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND 26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 27 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 28 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC 29 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 35 * POSSIBILITY OF SUCH DAMAGE. 36 */ 37 38 #include <sys/cdefs.h> 39 __KERNEL_RCSID(0, "$NetBSD: pcib.c,v 1.11 2005/12/11 12:17:11 christos Exp $"); 40 41 #include <sys/param.h> 42 #include <sys/systm.h> 43 #include <sys/kernel.h> 44 #include <sys/device.h> 45 #include <sys/malloc.h> 46 47 #include <machine/bus.h> 48 #include <evbmips/malta/maltareg.h> 49 #include <evbmips/malta/maltavar.h> 50 #include <evbmips/malta/dev/gtreg.h> 51 #include <evbmips/malta/pci/pcibvar.h> 52 53 #include <dev/isa/isareg.h> 54 #include <dev/isa/isavar.h> 55 56 #include <dev/pci/pcireg.h> 57 #include <dev/pci/pcivar.h> 58 #include <dev/pci/pcidevs.h> 59 60 #include <dev/ic/i8259reg.h> 61 62 63 #define ICU_LEN 16 /* number of ISA IRQs */ 64 65 const char *isa_intrnames[ICU_LEN] = { 66 "timer", 67 "keyboard", 68 "reserved", /* by South Bridge (for cascading) */ 69 "com1", 70 "com0", 71 "not used", 72 "floppy", 73 "centronics", 74 "mcclock", 75 "i2c", 76 "pci A,B", /* PCI slots 1..4, ethernet */ 77 "pci C,D", /* PCI slots 1..4, audio, usb */ 78 "mouse", 79 "reserved", 80 "ide primary", 81 "ide secondary", /* and compact flash connector */ 82 }; 83 84 struct pcib_intrhead { 85 LIST_HEAD(, evbmips_intrhand) intr_q; 86 struct evcnt intr_count; 87 int intr_type; 88 }; 89 90 struct pcib_softc { 91 struct device sc_dev; 92 93 bus_space_tag_t sc_iot; 94 bus_space_handle_t sc_ioh_icu1; 95 bus_space_handle_t sc_ioh_icu2; 96 bus_space_handle_t sc_ioh_elcr; 97 98 struct mips_isa_chipset sc_ic; 99 100 struct pcib_intrhead sc_intrtab[ICU_LEN]; 101 102 u_int16_t sc_imask; 103 u_int16_t sc_elcr; 104 105 u_int16_t sc_reserved; 106 107 void *sc_ih; 108 }; 109 110 /* 111 * XXX 112 * There is only one pci-isa bridge, and all external interrupts 113 * are routed through it, so we need to remember the softc when 114 * called from other interrupt handling code. 115 */ 116 static struct pcib_softc *my_sc; 117 struct mips_isa_chipset *pcib_ic; 118 119 static int pcib_match(struct device *, struct cfdata *, void *); 120 static void pcib_attach(struct device *, struct device *, void *); 121 static int pcib_intr(void *v); 122 static void pcib_bridge_callback(struct device *); 123 static void pcib_set_icus(struct pcib_softc *sc); 124 static void pcib_cleanup(void *arg); 125 126 static const struct evcnt * 127 pcib_isa_intr_evcnt(void *, int); 128 static void *pcib_isa_intr_establish(void *, int, int, int, 129 int (*)(void *), void *); 130 static void pcib_isa_intr_disestablish(void *, void *); 131 static void pcib_isa_attach_hook(struct device *, struct device *, 132 struct isabus_attach_args *); 133 static int pcib_isa_intr_alloc(void *, int, int, int *); 134 static const char * 135 pcib_isa_intr_string(void *, int); 136 137 CFATTACH_DECL(pcib, sizeof(struct pcib_softc), 138 pcib_match, pcib_attach, NULL, NULL); 139 140 static int 141 pcib_match(struct device *parent, struct cfdata *match, void *aux) 142 { 143 struct pci_attach_args *pa = aux; 144 145 if (PCI_CLASS(pa->pa_class) == PCI_CLASS_BRIDGE && 146 PCI_SUBCLASS(pa->pa_class) == PCI_SUBCLASS_BRIDGE_ISA) 147 return (1); 148 149 return (0); 150 } 151 152 static void 153 pcib_attach(struct device *parent, struct device *self, void *aux) 154 { 155 struct pci_attach_args *pa = aux; 156 char devinfo[256]; 157 int i; 158 159 printf("\n"); 160 161 if (my_sc != NULL) 162 panic("pcib_attach: already attached!"); 163 my_sc = (void *)self; 164 165 /* 166 * Just print out a description and defer configuration 167 * until all PCI devices have been attached. 168 */ 169 pci_devinfo(pa->pa_id, pa->pa_class, 0, devinfo, sizeof(devinfo)); 170 printf("%s: %s, (rev . 0x%02x)\n", self->dv_xname, devinfo, 171 PCI_REVISION(pa->pa_class)); 172 173 my_sc->sc_iot = pa->pa_iot; 174 175 /* 176 * Map the PIC/ELCR registers. 177 */ 178 if (bus_space_map(my_sc->sc_iot, 0x4d0, 2, 0, &my_sc->sc_ioh_elcr) != 0) 179 printf("%s: unable to map ELCR registers\n", 180 my_sc->sc_dev.dv_xname); 181 if (bus_space_map(my_sc->sc_iot, IO_ICU1, 2, 0, &my_sc->sc_ioh_icu1) != 0) 182 printf("%s: unable to map ICU1 registers\n", 183 my_sc->sc_dev.dv_xname); 184 if (bus_space_map(my_sc->sc_iot, IO_ICU2, 2, 0, &my_sc->sc_ioh_icu2) != 0) 185 printf("%s: unable to map ICU2 registers\n", 186 my_sc->sc_dev.dv_xname); 187 188 /* All interrupts default to "masked off". */ 189 my_sc->sc_imask = 0xffff; 190 191 /* All interrupts default to edge-triggered. */ 192 my_sc->sc_elcr = 0; 193 194 /* 195 * Initialize the 8259s. 196 */ 197 /* reset, program device, 4 bytes */ 198 bus_space_write_1(my_sc->sc_iot, my_sc->sc_ioh_icu1, PIC_ICW1, 199 ICW1_SELECT | ICW1_IC4); 200 bus_space_write_1(my_sc->sc_iot, my_sc->sc_ioh_icu1, PIC_ICW2, 201 ICW2_VECTOR(0)/*XXX*/); 202 bus_space_write_1(my_sc->sc_iot, my_sc->sc_ioh_icu1, PIC_ICW3, 203 ICW3_CASCADE(2)); 204 bus_space_write_1(my_sc->sc_iot, my_sc->sc_ioh_icu1, PIC_ICW4, 205 ICW4_8086); 206 207 /* mask all interrupts */ 208 bus_space_write_1(my_sc->sc_iot, my_sc->sc_ioh_icu1, PIC_OCW1, 209 my_sc->sc_imask & 0xff); 210 211 /* enable special mask mode */ 212 bus_space_write_1(my_sc->sc_iot, my_sc->sc_ioh_icu1, PIC_OCW3, 213 OCW3_SELECT | OCW3_SSMM | OCW3_SMM); 214 215 /* read IRR by default */ 216 bus_space_write_1(my_sc->sc_iot, my_sc->sc_ioh_icu1, PIC_OCW3, 217 OCW3_SELECT | OCW3_RR); 218 219 /* reset, program device, 4 bytes */ 220 bus_space_write_1(my_sc->sc_iot, my_sc->sc_ioh_icu2, PIC_ICW1, 221 ICW1_SELECT | ICW1_IC4); 222 bus_space_write_1(my_sc->sc_iot, my_sc->sc_ioh_icu2, PIC_ICW2, 223 ICW2_VECTOR(0)/*XXX*/); 224 bus_space_write_1(my_sc->sc_iot, my_sc->sc_ioh_icu2, PIC_ICW3, 225 ICW3_CASCADE(2)); 226 bus_space_write_1(my_sc->sc_iot, my_sc->sc_ioh_icu2, PIC_ICW4, 227 ICW4_8086); 228 229 /* mask all interrupts */ 230 bus_space_write_1(my_sc->sc_iot, my_sc->sc_ioh_icu2, PIC_OCW1, 231 my_sc->sc_imask & 0xff); 232 233 /* enable special mask mode */ 234 bus_space_write_1(my_sc->sc_iot, my_sc->sc_ioh_icu2, PIC_OCW3, 235 OCW3_SELECT | OCW3_SSMM | OCW3_SMM); 236 237 /* read IRR by default */ 238 bus_space_write_1(my_sc->sc_iot, my_sc->sc_ioh_icu2, PIC_OCW3, 239 OCW3_SELECT | OCW3_RR); 240 241 /* 242 * Default all interrupts to edge-triggered. 243 */ 244 bus_space_write_1(my_sc->sc_iot, my_sc->sc_ioh_elcr, 0, 245 my_sc->sc_elcr & 0xff); 246 bus_space_write_1(my_sc->sc_iot, my_sc->sc_ioh_elcr, 1, 247 (my_sc->sc_elcr >> 8) & 0xff); 248 249 /* 250 * Some ISA interrupts are reserved for devices that 251 * we know are hard-wired to certain IRQs. 252 */ 253 my_sc->sc_reserved = 254 (1U << 0) | /* timer */ 255 (1U << 1) | /* keyboard controller (keyboard) */ 256 (1U << 2) | /* PIC cascade */ 257 (1U << 3) | /* COM 2 */ 258 (1U << 4) | /* COM 1 */ 259 (1U << 6) | /* floppy */ 260 (1U << 7) | /* centronics */ 261 (1U << 8) | /* RTC */ 262 (1U << 9) | /* I2C */ 263 (1U << 12) | /* keyboard controller (mouse) */ 264 (1U << 14) | /* IDE primary */ 265 (1U << 15); /* IDE secondary */ 266 267 /* Set up our ISA chipset. */ 268 my_sc->sc_ic.ic_v = my_sc; 269 my_sc->sc_ic.ic_intr_evcnt = pcib_isa_intr_evcnt; 270 my_sc->sc_ic.ic_intr_establish = pcib_isa_intr_establish; 271 my_sc->sc_ic.ic_intr_disestablish = pcib_isa_intr_disestablish; 272 my_sc->sc_ic.ic_intr_alloc = pcib_isa_intr_alloc; 273 my_sc->sc_ic.ic_intr_string = pcib_isa_intr_string; 274 275 pcib_ic = &my_sc->sc_ic; /* XXX for external use */ 276 277 /* Initialize our interrupt table. */ 278 for (i = 0; i < ICU_LEN; i++) { 279 #if 0 280 char irqstr[8]; /* 4 + 2 + NULL + sanity */ 281 282 sprintf(irqstr, "irq %d", i); 283 evcnt_attach_dynamic(&my_sc->sc_intrtab[i].intr_count, 284 EVCNT_TYPE_INTR, NULL, "pcib", irqstr); 285 #else 286 evcnt_attach_dynamic(&my_sc->sc_intrtab[i].intr_count, 287 EVCNT_TYPE_INTR, NULL, "pcib", isa_intrnames[i]); 288 #endif 289 LIST_INIT(&my_sc->sc_intrtab[i].intr_q); 290 my_sc->sc_intrtab[i].intr_type = IST_NONE; 291 } 292 293 /* Hook up our interrupt handler. */ 294 my_sc->sc_ih = evbmips_intr_establish(MALTA_SOUTHBRIDGE_INTR, pcib_intr, my_sc); 295 if (my_sc->sc_ih == NULL) 296 printf("%s: WARNING: unable to register interrupt handler\n", 297 my_sc->sc_dev.dv_xname); 298 299 300 /* 301 * Disable ISA interrupts before returning to YAMON. 302 */ 303 if (shutdownhook_establish(pcib_cleanup, my_sc) == NULL) 304 panic("pcib_attach: could not establish shutdown hook"); 305 306 config_defer(self, pcib_bridge_callback); 307 } 308 309 static void 310 pcib_bridge_callback(struct device *self) 311 { 312 struct pcib_softc *sc = (void *)self; 313 struct malta_config *mcp = &malta_configuration; 314 struct isabus_attach_args iba; 315 316 /* 317 * Attach the ISA bus behind this bridge. 318 */ 319 memset(&iba, 0, sizeof(iba)); 320 321 iba.iba_iot = &mcp->mc_iot; 322 iba.iba_memt = &mcp->mc_memt; 323 iba.iba_dmat = &mcp->mc_isa_dmat; 324 325 iba.iba_ic = &sc->sc_ic; 326 iba.iba_ic->ic_attach_hook = pcib_isa_attach_hook; 327 328 config_found_ia(&sc->sc_dev, "isabus", &iba, isabusprint); 329 } 330 331 static void 332 pcib_isa_attach_hook(struct device *parent, struct device *self, 333 struct isabus_attach_args *iba) 334 { 335 336 /* Nothing to do. */ 337 } 338 339 static void 340 pcib_set_icus(struct pcib_softc *sc) 341 { 342 343 /* Enable the cascade IRQ (2) if 8-15 is enabled. */ 344 if ((sc->sc_imask & 0xff00) != 0xff00) 345 sc->sc_imask &= ~(1U << 2); 346 else 347 sc->sc_imask |= (1U << 2); 348 349 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_OCW1, 350 sc->sc_imask & 0xff); 351 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2, PIC_OCW1, 352 (sc->sc_imask >> 8) & 0xff); 353 354 bus_space_write_1(sc->sc_iot, sc->sc_ioh_elcr, 0, 355 sc->sc_elcr & 0xff); 356 bus_space_write_1(sc->sc_iot, sc->sc_ioh_elcr, 1, 357 (sc->sc_elcr >> 8) & 0xff); 358 } 359 360 static int 361 pcib_intr(void *v) 362 { 363 struct pcib_softc *sc = v; 364 struct evbmips_intrhand *ih; 365 int irq; 366 367 for (;;) { 368 #if 1 369 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_OCW3, 370 OCW3_SELECT | OCW3_POLL); 371 irq = bus_space_read_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_OCW3); 372 if ((irq & OCW3_POLL_PENDING) == 0) 373 return (1); 374 375 irq = OCW3_POLL_IRQ(irq); 376 377 if (irq == 2) { 378 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2, 379 PIC_OCW3, OCW3_SELECT | OCW3_POLL); 380 irq = bus_space_read_1(sc->sc_iot, sc->sc_ioh_icu2, 381 PIC_OCW3); 382 if (irq & OCW3_POLL_PENDING) 383 irq = OCW3_POLL_IRQ(irq) + 8; 384 else 385 irq = 2; 386 } 387 #else 388 /* XXX - should be a function call to gt.c? */ 389 irq = GT_REGVAL(GT_PCI0_INTR_ACK) & 0xff; 390 391 /* 392 * From YAMON source code: 393 * 394 * IRQ7 is used to detect spurious interrupts. 395 * The interrupt acknowledge cycle returns IRQ7, if no 396 * interrupts is requested. 397 * We can differentiate between this situation and a 398 * "Normal" IRQ7 by reading the ISR. 399 */ 400 401 if (irq == 7) { 402 int reg; 403 404 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_OCW3, 405 OCW3_SELECT | OCW3_RR | OCW3_RIS); 406 reg = bus_space_read_1(sc->sc_iot, sc->sc_ioh_icu1, 407 PIC_OCW3); 408 if (!(reg & (1 << 7))) 409 break; /* spurious interrupt */ 410 } 411 #endif 412 413 sc->sc_intrtab[irq].intr_count.ev_count++; 414 LIST_FOREACH(ih, &sc->sc_intrtab[irq].intr_q, ih_q) 415 (*ih->ih_func)(ih->ih_arg); 416 417 /* Send a specific EOI to the 8259. */ 418 if (irq > 7) { 419 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2, 420 PIC_OCW2, OCW2_SELECT | OCW3_EOI | OCW3_SL | 421 OCW2_ILS(irq & 7)); 422 irq = 2; 423 } 424 425 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_OCW2, 426 OCW2_SELECT | OCW3_EOI | OCW3_SL | OCW2_ILS(irq)); 427 } 428 } 429 430 const char * 431 pcib_isa_intr_string(void *v, int irq) 432 { 433 static char irqstr[12]; /* 8 + 2 + NULL + sanity */ 434 435 if (irq == 0 || irq >= ICU_LEN || irq == 2) 436 panic("pcib_isa_intr_string: bogus isa irq 0x%x", irq); 437 438 sprintf(irqstr, "isa irq %d", irq); 439 return (irqstr); 440 } 441 442 const struct evcnt * 443 pcib_isa_intr_evcnt(void *v, int irq) 444 { 445 446 if (irq == 0 || irq >= ICU_LEN || irq == 2) 447 panic("pcib_isa_intr_evcnt: bogus isa irq 0x%x", irq); 448 449 return (&my_sc->sc_intrtab[irq].intr_count); 450 } 451 452 void * 453 pcib_isa_intr_establish(void *v, int irq, int type, int level, 454 int (*func)(void *), void *arg) 455 { 456 struct evbmips_intrhand *ih; 457 int s; 458 459 if (irq >= ICU_LEN || irq == 2 || type == IST_NONE) 460 panic("pcib_isa_intr_establish: bad irq or type"); 461 462 switch (my_sc->sc_intrtab[irq].intr_type) { 463 case IST_NONE: 464 my_sc->sc_intrtab[irq].intr_type = type; 465 break; 466 467 case IST_EDGE: 468 case IST_LEVEL: 469 if (type == my_sc->sc_intrtab[irq].intr_type) 470 break; 471 /* FALLTHROUGH */ 472 case IST_PULSE: 473 /* 474 * We can't share interrupts in this case. 475 */ 476 return (NULL); 477 } 478 479 ih = malloc(sizeof(*ih), M_DEVBUF, M_NOWAIT); 480 if (ih == NULL) 481 return (NULL); 482 483 ih->ih_func = func; 484 ih->ih_arg = arg; 485 ih->ih_irq = irq; 486 487 s = splhigh(); 488 489 /* Insert the handler into the table. */ 490 LIST_INSERT_HEAD(&my_sc->sc_intrtab[irq].intr_q, ih, ih_q); 491 my_sc->sc_intrtab[irq].intr_type = type; 492 493 /* Enable it, set trigger mode. */ 494 my_sc->sc_imask &= ~(1 << irq); 495 if (my_sc->sc_intrtab[irq].intr_type == IST_LEVEL) 496 my_sc->sc_elcr |= (1 << irq); 497 else 498 my_sc->sc_elcr &= ~(1 << irq); 499 500 pcib_set_icus(my_sc); 501 502 splx(s); 503 504 return (ih); 505 } 506 507 void 508 pcib_isa_intr_disestablish(void *v, void *arg) 509 { 510 struct evbmips_intrhand *ih = arg; 511 int s; 512 513 s = splhigh(); 514 515 LIST_REMOVE(ih, ih_q); 516 517 /* If there are no more handlers on this IRQ, disable it. */ 518 if (LIST_FIRST(&my_sc->sc_intrtab[ih->ih_irq].intr_q) == NULL) { 519 my_sc->sc_imask |= (1 << ih->ih_irq); 520 pcib_set_icus(my_sc); 521 } 522 523 splx(s); 524 525 free(ih, M_DEVBUF); 526 } 527 528 static int 529 pcib_isa_intr_alloc(void *v, int mask, int type, int *irq) 530 { 531 int i, tmp, bestirq, count; 532 struct evbmips_intrhand *ih; 533 534 if (type == IST_NONE) 535 panic("pcib_intr_alloc: bogus type"); 536 537 bestirq = -1; 538 count = -1; 539 540 mask &= ~my_sc->sc_reserved; 541 542 for (i = 0; i < ICU_LEN; i++) { 543 if ((mask & (1 << i)) == 0) 544 continue; 545 546 switch (my_sc->sc_intrtab[i].intr_type) { 547 case IST_NONE: 548 /* 549 * If nothing's using the IRQ, just return it. 550 */ 551 *irq = i; 552 return (0); 553 554 case IST_EDGE: 555 case IST_LEVEL: 556 if (type != my_sc->sc_intrtab[i].intr_type) 557 continue; 558 /* 559 * If the IRQ is sharable, count the number of 560 * other handlers, and if it's smaller than the 561 * last IRQ like this, remember it. 562 */ 563 tmp = 0; 564 for (ih = LIST_FIRST(&my_sc->sc_intrtab[i].intr_q); 565 ih != NULL; ih = LIST_NEXT(ih, ih_q)) 566 tmp++; 567 if (bestirq == -1 || count > tmp) { 568 bestirq = i; 569 count = tmp; 570 } 571 break; 572 573 case IST_PULSE: 574 /* This just isn't sharable. */ 575 continue; 576 } 577 } 578 579 if (bestirq == -1) 580 return (1); 581 582 *irq = bestirq; 583 return (0); 584 } 585 586 static void 587 pcib_cleanup(void *arg) 588 { 589 590 my_sc->sc_imask = 0xffff; 591 pcib_set_icus(my_sc); 592 } 593