1 /* $NetBSD: pcib.c,v 1.25 2024/02/08 20:11:56 andvar 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.25 2024/02/08 20:11:56 andvar 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/kmem.h> 46 47 #include <uvm/uvm_extern.h> 48 49 #include <sys/bus.h> 50 #include <evbmips/malta/maltareg.h> 51 #include <evbmips/malta/maltavar.h> 52 #include <evbmips/malta/dev/gtreg.h> 53 #include <evbmips/malta/pci/pcibvar.h> 54 55 #include <dev/isa/isareg.h> 56 #include <dev/isa/isavar.h> 57 58 #include <dev/pci/pcireg.h> 59 #include <dev/pci/pcivar.h> 60 #include <dev/pci/pcidevs.h> 61 62 #include <dev/ic/i8259reg.h> 63 64 65 #define ICU_LEN 16 /* number of ISA IRQs */ 66 67 const char * const isa_intrnames[ICU_LEN] = { 68 "timer", 69 "keyboard", 70 "reserved", /* by South Bridge (for cascading) */ 71 "com1", 72 "com0", 73 "not used", 74 "floppy", 75 "centronics", 76 "mcclock", 77 "i2c", 78 "pci A,B", /* PCI slots 1..4, ethernet */ 79 "pci C,D", /* PCI slots 1..4, audio, usb */ 80 "mouse", 81 "reserved", 82 "ide primary", 83 "ide secondary", /* and compact flash connector */ 84 }; 85 86 struct pcib_intrhead { 87 LIST_HEAD(, evbmips_intrhand) intr_q; 88 struct evcnt intr_count; 89 int intr_type; 90 }; 91 92 struct pcib_softc { 93 device_t sc_dev; 94 95 bus_space_tag_t sc_memt; 96 bus_space_tag_t sc_iot; 97 bus_space_handle_t sc_ioh_icu1; 98 bus_space_handle_t sc_ioh_icu2; 99 bus_space_handle_t sc_ioh_elcr; 100 101 bus_dma_tag_t sc_dmat; 102 103 struct mips_isa_chipset sc_ic; 104 105 struct pcib_intrhead sc_intrtab[ICU_LEN]; 106 107 u_int16_t sc_imask; 108 u_int16_t sc_elcr; 109 110 u_int16_t sc_reserved; 111 112 void *sc_ih; 113 }; 114 115 /* 116 * XXX 117 * There is only one pci-isa bridge, and all external interrupts 118 * are routed through it, so we need to remember the softc when 119 * called from other interrupt handling code. 120 */ 121 static struct pcib_softc *my_sc; 122 struct mips_isa_chipset *pcib_ic; 123 124 static int pcib_match(device_t, cfdata_t, void *); 125 static void pcib_attach(device_t, device_t, void *); 126 static int pcib_intr(void *v); 127 static void pcib_bridge_callback(device_t); 128 static void pcib_set_icus(struct pcib_softc *sc); 129 static void pcib_cleanup(void *arg); 130 131 static const struct evcnt * 132 pcib_isa_intr_evcnt(void *, int); 133 static void *pcib_isa_intr_establish(void *, int, int, int, 134 int (*)(void *), void *); 135 static void pcib_isa_intr_disestablish(void *, void *); 136 static void pcib_isa_attach_hook(device_t, device_t, 137 struct isabus_attach_args *); 138 static void pcib_isa_detach_hook(isa_chipset_tag_t, device_t); 139 static int pcib_isa_intr_alloc(void *, int, int, int *); 140 static const char * 141 pcib_isa_intr_string(void *, int, char *, size_t); 142 143 CFATTACH_DECL_NEW(pcib, sizeof(struct pcib_softc), 144 pcib_match, pcib_attach, NULL, NULL); 145 146 static int 147 malta_isa_dma_may_bounce(bus_dma_tag_t t, bus_dmamap_t map, int flags, 148 int *cookieflagsp) 149 { 150 if (((map->_dm_size / PAGE_SIZE) + 1) > map->_dm_segcnt) 151 *cookieflagsp |= _BUS_DMA_MIGHT_NEED_BOUNCE; 152 153 return 0; 154 } 155 156 static int 157 pcib_match(device_t parent, cfdata_t match, void *aux) 158 { 159 struct pci_attach_args *pa = aux; 160 161 if (PCI_CLASS(pa->pa_class) == PCI_CLASS_BRIDGE && 162 PCI_SUBCLASS(pa->pa_class) == PCI_SUBCLASS_BRIDGE_ISA) 163 return (1); 164 165 return (0); 166 } 167 168 static void 169 pcib_attach(device_t parent, device_t self, void *aux) 170 { 171 struct pci_attach_args * const pa = aux; 172 struct pcib_softc * const sc = device_private(self); 173 const char * const xname = device_xname(self); 174 char devinfo[256]; 175 int error; 176 177 printf("\n"); 178 179 if (my_sc != NULL) 180 panic("pcib_attach: already attached!"); 181 my_sc = sc; 182 sc->sc_dev = self; 183 184 /* 185 * Just print out a description and defer configuration 186 * until all PCI devices have been attached. 187 */ 188 pci_devinfo(pa->pa_id, pa->pa_class, 0, devinfo, sizeof(devinfo)); 189 printf("%s: %s, (rev . 0x%02x)\n", xname, devinfo, 190 PCI_REVISION(pa->pa_class)); 191 192 sc->sc_memt = pa->pa_memt; 193 sc->sc_iot = pa->pa_iot; 194 195 /* 196 * Initialize the DMA tag used for ISA DMA. 197 */ 198 error = bus_dmatag_subregion(pa->pa_dmat, MALTA_DMA_ISA_PHYSBASE, 199 MALTA_DMA_ISA_PHYSBASE + MALTA_DMA_ISA_SIZE - 1, &sc->sc_dmat, 0); 200 if (error) 201 panic("malta_dma_init: failed to create ISA dma tag: %d", 202 error); 203 sc->sc_dmat->_may_bounce = malta_isa_dma_may_bounce; 204 205 /* 206 * Map the PIC/ELCR registers. 207 */ 208 if (bus_space_map(sc->sc_iot, 0x4d0, 2, 0, &sc->sc_ioh_elcr) != 0) 209 printf("%s: unable to map ELCR registers\n", xname); 210 if (bus_space_map(sc->sc_iot, IO_ICU1, 2, 0, &sc->sc_ioh_icu1) != 0) 211 printf("%s: unable to map ICU1 registers\n", xname); 212 if (bus_space_map(sc->sc_iot, IO_ICU2, 2, 0, &sc->sc_ioh_icu2) != 0) 213 printf("%s: unable to map ICU2 registers\n", xname); 214 215 /* All interrupts default to "masked off". */ 216 sc->sc_imask = 0xffff; 217 218 /* All interrupts default to edge-triggered. */ 219 sc->sc_elcr = 0; 220 221 /* 222 * Initialize the 8259s. 223 */ 224 /* reset, program device, 4 bytes */ 225 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_ICW1, 226 ICW1_SELECT | ICW1_IC4); 227 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_ICW2, 228 ICW2_VECTOR(0)/*XXX*/); 229 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_ICW3, 230 ICW3_CASCADE(2)); 231 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_ICW4, 232 ICW4_8086); 233 234 /* mask all interrupts */ 235 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_OCW1, 236 sc->sc_imask & 0xff); 237 238 /* enable special mask mode */ 239 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_OCW3, 240 OCW3_SELECT | OCW3_SSMM | OCW3_SMM); 241 242 /* read IRR by default */ 243 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_OCW3, 244 OCW3_SELECT | OCW3_RR); 245 246 /* reset, program device, 4 bytes */ 247 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2, PIC_ICW1, 248 ICW1_SELECT | ICW1_IC4); 249 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2, PIC_ICW2, 250 ICW2_VECTOR(0)/*XXX*/); 251 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2, PIC_ICW3, 252 ICW3_CASCADE(2)); 253 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2, PIC_ICW4, 254 ICW4_8086); 255 256 /* mask all interrupts */ 257 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2, PIC_OCW1, 258 sc->sc_imask & 0xff); 259 260 /* enable special mask mode */ 261 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2, PIC_OCW3, 262 OCW3_SELECT | OCW3_SSMM | OCW3_SMM); 263 264 /* read IRR by default */ 265 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2, PIC_OCW3, 266 OCW3_SELECT | OCW3_RR); 267 268 /* 269 * Default all interrupts to edge-triggered. 270 */ 271 bus_space_write_1(sc->sc_iot, sc->sc_ioh_elcr, 0, 272 sc->sc_elcr & 0xff); 273 bus_space_write_1(sc->sc_iot, sc->sc_ioh_elcr, 1, 274 (sc->sc_elcr >> 8) & 0xff); 275 276 /* 277 * Some ISA interrupts are reserved for devices that 278 * we know are hard-wired to certain IRQs. 279 */ 280 sc->sc_reserved = 281 (1U << 0) | /* timer */ 282 (1U << 1) | /* keyboard controller (keyboard) */ 283 (1U << 2) | /* PIC cascade */ 284 (1U << 3) | /* COM 2 */ 285 (1U << 4) | /* COM 1 */ 286 (1U << 6) | /* floppy */ 287 (1U << 7) | /* centronics */ 288 (1U << 8) | /* RTC */ 289 (1U << 9) | /* I2C */ 290 (1U << 12) | /* keyboard controller (mouse) */ 291 (1U << 14) | /* IDE primary */ 292 (1U << 15); /* IDE secondary */ 293 294 /* Set up our ISA chipset. */ 295 sc->sc_ic.ic_v = sc; 296 sc->sc_ic.ic_intr_evcnt = pcib_isa_intr_evcnt; 297 sc->sc_ic.ic_intr_establish = pcib_isa_intr_establish; 298 sc->sc_ic.ic_intr_disestablish = pcib_isa_intr_disestablish; 299 sc->sc_ic.ic_intr_alloc = pcib_isa_intr_alloc; 300 sc->sc_ic.ic_intr_string = pcib_isa_intr_string; 301 302 pcib_ic = &sc->sc_ic; /* XXX for external use */ 303 304 /* Initialize our interrupt table. */ 305 for (size_t i = 0; i < ICU_LEN; i++) { 306 #if 0 307 char irqstr[8]; /* 4 + 2 + NULL + sanity */ 308 309 snprintf(irqstr, sizeof(irqstr), "irq %d", i); 310 evcnt_attach_dynamic(&sc->sc_intrtab[i].intr_count, 311 EVCNT_TYPE_INTR, NULL, "pcib", irqstr); 312 #else 313 evcnt_attach_dynamic(&sc->sc_intrtab[i].intr_count, 314 EVCNT_TYPE_INTR, NULL, "pcib", isa_intrnames[i]); 315 #endif 316 LIST_INIT(&sc->sc_intrtab[i].intr_q); 317 sc->sc_intrtab[i].intr_type = IST_NONE; 318 } 319 320 /* Hook up our interrupt handler. */ 321 sc->sc_ih = evbmips_intr_establish(MALTA_SOUTHBRIDGE_INTR, pcib_intr, sc); 322 if (sc->sc_ih == NULL) 323 printf("%s: WARNING: unable to register interrupt handler\n", 324 xname); 325 326 327 /* 328 * Disable ISA interrupts before returning to YAMON. 329 */ 330 if (shutdownhook_establish(pcib_cleanup, sc) == NULL) 331 panic("pcib_attach: could not establish shutdown hook"); 332 333 config_defer(self, pcib_bridge_callback); 334 } 335 336 static void 337 pcib_bridge_callback(device_t self) 338 { 339 struct pcib_softc *sc = device_private(self); 340 struct isabus_attach_args iba; 341 342 /* 343 * Attach the ISA bus behind this bridge. 344 */ 345 memset(&iba, 0, sizeof(iba)); 346 347 iba.iba_iot = sc->sc_iot; 348 iba.iba_memt = sc->sc_memt; 349 iba.iba_dmat = sc->sc_dmat; 350 351 iba.iba_ic = &sc->sc_ic; 352 iba.iba_ic->ic_attach_hook = pcib_isa_attach_hook; 353 iba.iba_ic->ic_detach_hook = pcib_isa_detach_hook; 354 355 config_found(self, &iba, isabusprint, CFARGS_NONE); 356 } 357 358 static void 359 pcib_isa_attach_hook(device_t parent, device_t self, 360 struct isabus_attach_args *iba) 361 { 362 363 /* Nothing to do. */ 364 } 365 366 static void 367 pcib_isa_detach_hook(isa_chipset_tag_t ic, device_t self) 368 { 369 370 /* Nothing to do. */ 371 } 372 373 static void 374 pcib_set_icus(struct pcib_softc *sc) 375 { 376 377 /* Enable the cascade IRQ (2) if 8-15 is enabled. */ 378 if ((sc->sc_imask & 0xff00) != 0xff00) 379 sc->sc_imask &= ~(1U << 2); 380 else 381 sc->sc_imask |= (1U << 2); 382 383 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_OCW1, 384 sc->sc_imask & 0xff); 385 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2, PIC_OCW1, 386 (sc->sc_imask >> 8) & 0xff); 387 388 bus_space_write_1(sc->sc_iot, sc->sc_ioh_elcr, 0, 389 sc->sc_elcr & 0xff); 390 bus_space_write_1(sc->sc_iot, sc->sc_ioh_elcr, 1, 391 (sc->sc_elcr >> 8) & 0xff); 392 } 393 394 static int 395 pcib_intr(void *v) 396 { 397 struct pcib_softc *sc = v; 398 struct evbmips_intrhand *ih; 399 int irq; 400 401 for (;;) { 402 #if 1 403 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_OCW3, 404 OCW3_SELECT | OCW3_POLL); 405 irq = bus_space_read_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_OCW3); 406 if ((irq & OCW3_POLL_PENDING) == 0) 407 return (1); 408 409 irq = OCW3_POLL_IRQ(irq); 410 411 if (irq == 2) { 412 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2, 413 PIC_OCW3, OCW3_SELECT | OCW3_POLL); 414 irq = bus_space_read_1(sc->sc_iot, sc->sc_ioh_icu2, 415 PIC_OCW3); 416 if (irq & OCW3_POLL_PENDING) 417 irq = OCW3_POLL_IRQ(irq) + 8; 418 else 419 irq = 2; 420 } 421 #else 422 /* XXX - should be a function call to gt.c? */ 423 irq = GT_REGVAL(GT_PCI0_INTR_ACK) & 0xff; 424 425 /* 426 * From YAMON source code: 427 * 428 * IRQ7 is used to detect spurious interrupts. 429 * The interrupt acknowledge cycle returns IRQ7, if no 430 * interrupts is requested. 431 * We can differentiate between this situation and a 432 * "Normal" IRQ7 by reading the ISR. 433 */ 434 435 if (irq == 7) { 436 int reg; 437 438 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_OCW3, 439 OCW3_SELECT | OCW3_RR | OCW3_RIS); 440 reg = bus_space_read_1(sc->sc_iot, sc->sc_ioh_icu1, 441 PIC_OCW3); 442 if (!(reg & (1 << 7))) 443 break; /* spurious interrupt */ 444 } 445 #endif 446 447 sc->sc_intrtab[irq].intr_count.ev_count++; 448 LIST_FOREACH(ih, &sc->sc_intrtab[irq].intr_q, ih_q) 449 (*ih->ih_func)(ih->ih_arg); 450 451 /* Send a specific EOI to the 8259. */ 452 if (irq > 7) { 453 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2, 454 PIC_OCW2, OCW2_SELECT | OCW2_EOI | OCW2_SL | 455 OCW2_ILS(irq & 7)); 456 irq = 2; 457 } 458 459 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_OCW2, 460 OCW2_SELECT | OCW2_EOI | OCW2_SL | OCW2_ILS(irq)); 461 } 462 } 463 464 const char * 465 pcib_isa_intr_string(void *v, int irq, char *buf, size_t len) 466 { 467 if (irq == 0 || irq >= ICU_LEN || irq == 2) 468 panic("%s: bogus isa irq 0x%x", __func__, irq); 469 470 snprintf(buf, len, "isa irq %d", irq); 471 return buf; 472 } 473 474 const struct evcnt * 475 pcib_isa_intr_evcnt(void *v, int irq) 476 { 477 478 if (irq == 0 || irq >= ICU_LEN || irq == 2) 479 panic("pcib_isa_intr_evcnt: bogus isa irq 0x%x", irq); 480 481 return (&my_sc->sc_intrtab[irq].intr_count); 482 } 483 484 void * 485 pcib_isa_intr_establish(void *v, int irq, int type, int level, 486 int (*func)(void *), void *arg) 487 { 488 struct evbmips_intrhand *ih; 489 int s; 490 491 if (irq >= ICU_LEN || irq == 2 || type == IST_NONE) 492 panic("pcib_isa_intr_establish: bad irq or type"); 493 494 switch (my_sc->sc_intrtab[irq].intr_type) { 495 case IST_NONE: 496 my_sc->sc_intrtab[irq].intr_type = type; 497 break; 498 499 case IST_EDGE: 500 case IST_LEVEL: 501 if (type == my_sc->sc_intrtab[irq].intr_type) 502 break; 503 /* FALLTHROUGH */ 504 case IST_PULSE: 505 /* 506 * We can't share interrupts in this case. 507 */ 508 return (NULL); 509 } 510 511 ih = kmem_alloc(sizeof(*ih), KM_SLEEP); 512 ih->ih_func = func; 513 ih->ih_arg = arg; 514 ih->ih_irq = irq; 515 516 s = splhigh(); 517 518 /* Insert the handler into the table. */ 519 LIST_INSERT_HEAD(&my_sc->sc_intrtab[irq].intr_q, ih, ih_q); 520 my_sc->sc_intrtab[irq].intr_type = type; 521 522 /* Enable it, set trigger mode. */ 523 my_sc->sc_imask &= ~(1 << irq); 524 if (my_sc->sc_intrtab[irq].intr_type == IST_LEVEL) 525 my_sc->sc_elcr |= (1 << irq); 526 else 527 my_sc->sc_elcr &= ~(1 << irq); 528 529 pcib_set_icus(my_sc); 530 531 splx(s); 532 533 return (ih); 534 } 535 536 void 537 pcib_isa_intr_disestablish(void *v, void *arg) 538 { 539 struct evbmips_intrhand *ih = arg; 540 int s; 541 542 s = splhigh(); 543 544 LIST_REMOVE(ih, ih_q); 545 546 /* If there are no more handlers on this IRQ, disable it. */ 547 if (LIST_FIRST(&my_sc->sc_intrtab[ih->ih_irq].intr_q) == NULL) { 548 my_sc->sc_imask |= (1 << ih->ih_irq); 549 pcib_set_icus(my_sc); 550 } 551 552 splx(s); 553 554 kmem_free(ih, sizeof(*ih)); 555 } 556 557 static int 558 pcib_isa_intr_alloc(void *v, int mask, int type, int *irq) 559 { 560 int i, tmp, bestirq, count; 561 struct evbmips_intrhand *ih; 562 563 if (type == IST_NONE) 564 panic("pcib_intr_alloc: bogus type"); 565 566 bestirq = -1; 567 count = -1; 568 569 mask &= ~my_sc->sc_reserved; 570 571 for (i = 0; i < ICU_LEN; i++) { 572 if ((mask & (1 << i)) == 0) 573 continue; 574 575 switch (my_sc->sc_intrtab[i].intr_type) { 576 case IST_NONE: 577 /* 578 * If nothing's using the IRQ, just return it. 579 */ 580 *irq = i; 581 return (0); 582 583 case IST_EDGE: 584 case IST_LEVEL: 585 if (type != my_sc->sc_intrtab[i].intr_type) 586 continue; 587 /* 588 * If the IRQ is shareable, count the number of 589 * other handlers, and if it's smaller than the 590 * last IRQ like this, remember it. 591 */ 592 tmp = 0; 593 for (ih = LIST_FIRST(&my_sc->sc_intrtab[i].intr_q); 594 ih != NULL; ih = LIST_NEXT(ih, ih_q)) 595 tmp++; 596 if (bestirq == -1 || count > tmp) { 597 bestirq = i; 598 count = tmp; 599 } 600 break; 601 602 case IST_PULSE: 603 /* This just isn't shareable. */ 604 continue; 605 } 606 } 607 608 if (bestirq == -1) 609 return (1); 610 611 *irq = bestirq; 612 return (0); 613 } 614 615 static void 616 pcib_cleanup(void *arg) 617 { 618 619 my_sc->sc_imask = 0xffff; 620 pcib_set_icus(my_sc); 621 } 622