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