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