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