1 /* $NetBSD: pcib.c,v 1.7 2001/06/21 19:00:18 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.7 2001/06/21 19:00:18 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(32)/*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(32 + 8)/*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)(XXX, 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 /* XXX */ 321 } 322 #endif 323 324 iba.iba_ic = &sc->sc_ic; 325 iba.iba_ic->ic_attach_hook = pcib_isa_attach_hook; 326 327 (void) config_found(&sc->sc_dev, &iba, pcib_print); 328 } 329 330 int 331 pcib_print(void *aux, const char *pnp) 332 { 333 struct isabus_attach_args *iba; 334 335 if (pnp) 336 printf("%s at %s", iba->iba_busname, pnp); 337 return (UNCONF); 338 } 339 340 void 341 pcib_isa_attach_hook(struct device *parent, struct device *self, 342 struct isabus_attach_args *iba) 343 { 344 345 /* Nothing to do. */ 346 } 347 348 void 349 pcib_set_icus(struct pcib_softc *sc) 350 { 351 352 /* Enable the cascade IRQ (2) if 8-15 is enabled. */ 353 if ((sc->sc_imask & 0xff00) != 0xff00) 354 sc->sc_imask &= ~(1U << 2); 355 else 356 sc->sc_imask |= (1U << 2); 357 358 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_OCW1, 359 sc->sc_imask & 0xff); 360 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2, PIC_OCW1, 361 (sc->sc_imask >> 8) & 0xff); 362 363 bus_space_write_1(sc->sc_iot, sc->sc_ioh_elcr, 0, 364 sc->sc_elcr & 0xff); 365 bus_space_write_1(sc->sc_iot, sc->sc_ioh_elcr, 1, 366 (sc->sc_elcr >> 8) & 0xff); 367 } 368 369 int 370 pcib_intr(void *v) 371 { 372 struct pcib_softc *sc = v; 373 struct algor_intrhand *ih; 374 int irq; 375 376 for (;;) { 377 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_OCW3, 378 OCW3_SELECT | OCW3_POLL); 379 irq = bus_space_read_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_OCW3); 380 if ((irq & OCW3_POLL_PENDING) == 0) 381 return (1); 382 383 irq = OCW3_POLL_IRQ(irq); 384 385 if (irq == 2) { 386 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2, 387 PIC_OCW3, OCW3_SELECT | OCW3_POLL); 388 irq = bus_space_read_1(sc->sc_iot, sc->sc_ioh_icu2, 389 PIC_OCW3); 390 if (irq & OCW3_POLL_PENDING) 391 irq = OCW3_POLL_IRQ(irq) + 8; 392 else 393 irq = 2; 394 } 395 396 sc->sc_intrtab[irq].intr_count.ev_count++; 397 for (ih = LIST_FIRST(&sc->sc_intrtab[irq].intr_q); 398 ih != NULL; ih = LIST_NEXT(ih, ih_q)) { 399 (*ih->ih_func)(ih->ih_arg); 400 } 401 402 /* Send a specific EOI to the 8259. */ 403 if (irq > 7) { 404 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2, 405 PIC_OCW2, OCW2_SELECT | OCW3_EOI | OCW3_SL | 406 OCW2_ILS(irq & 7)); 407 irq = 2; 408 } 409 410 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_OCW2, 411 OCW2_SELECT | OCW3_EOI | OCW3_SL | OCW2_ILS(irq)); 412 } 413 } 414 415 const struct evcnt * 416 pcib_isa_intr_evcnt(void *v, int irq) 417 { 418 struct pcib_softc *sc = v; 419 420 #if defined(ALGOR_P5064) 421 if (p5064_isa_to_irqmap[irq] != -1) 422 return (isa_intr_evcnt(sc->sc_parent_ic, irq)); 423 #endif 424 425 return (&sc->sc_intrtab[irq].intr_count); 426 } 427 428 void * 429 pcib_isa_intr_establish(void *v, int irq, int type, int level, 430 int (*func)(void *), void *arg) 431 { 432 struct pcib_softc *sc = v; 433 struct algor_intrhand *ih; 434 int s; 435 436 if (irq > 15 || irq == 2 || type == IST_NONE) 437 panic("pcib_isa_intr_establish: bad irq or type"); 438 439 #if defined(ALGOR_P5064) 440 if (p5064_isa_to_irqmap[irq] != -1) 441 return (isa_intr_establish(sc->sc_parent_ic, irq, type, 442 level, func, arg)); 443 #endif 444 445 switch (sc->sc_intrtab[irq].intr_type) { 446 case IST_NONE: 447 sc->sc_intrtab[irq].intr_type = type; 448 break; 449 450 case IST_EDGE: 451 case IST_LEVEL: 452 if (type == sc->sc_intrtab[irq].intr_type) 453 break; 454 /* FALLTHROUGH */ 455 case IST_PULSE: 456 /* 457 * We can't share interrupts in this case. 458 */ 459 return (NULL); 460 } 461 462 ih = malloc(sizeof(*ih), M_DEVBUF, M_NOWAIT); 463 if (ih == NULL) 464 return (NULL); 465 466 ih->ih_func = func; 467 ih->ih_arg = arg; 468 ih->ih_irq = irq; 469 ih->ih_irqmap = NULL; 470 471 s = splhigh(); 472 473 /* Insert the handler into the table. */ 474 LIST_INSERT_HEAD(&sc->sc_intrtab[irq].intr_q, ih, ih_q); 475 sc->sc_intrtab[irq].intr_type = type; 476 477 /* Enable it, set trigger mode. */ 478 sc->sc_imask &= ~(1 << irq); 479 if (sc->sc_intrtab[irq].intr_type == IST_LEVEL) 480 sc->sc_elcr |= (1 << irq); 481 else 482 sc->sc_elcr &= ~(1 << irq); 483 484 pcib_set_icus(sc); 485 486 splx(s); 487 488 return (ih); 489 } 490 491 void 492 pcib_isa_intr_disestablish(void *v, void *arg) 493 { 494 struct pcib_softc *sc = v; 495 struct algor_intrhand *ih = arg; 496 int s; 497 498 #if defined(ALGOR_P5064) 499 if (p5064_isa_to_irqmap[ih->ih_irq] != -1) { 500 isa_intr_disestablish(sc->sc_parent_ic, ih); 501 return; 502 } 503 #endif 504 505 s = splhigh(); 506 507 LIST_REMOVE(ih, ih_q); 508 509 /* If there are no more handlers on this IRQ, disable it. */ 510 if (LIST_FIRST(&sc->sc_intrtab[ih->ih_irq].intr_q) == NULL) { 511 sc->sc_imask |= (1 << ih->ih_irq); 512 pcib_set_icus(sc); 513 } 514 515 splx(s); 516 517 free(ih, M_DEVBUF); 518 } 519 520 int 521 pcib_isa_intr_alloc(void *v, int mask, int type, int *irq) 522 { 523 struct pcib_softc *sc = v; 524 int i, tmp, bestirq, count; 525 struct algor_intrhand *ih; 526 527 if (type == IST_NONE) 528 panic("pcib_intr_alloc: bogus type"); 529 530 bestirq = -1; 531 count = -1; 532 533 mask &= ~sc->sc_reserved; 534 535 #if 0 536 printf("pcib_intr_alloc: mask = 0x%04x\n", mask); 537 #endif 538 539 for (i = 0; i < 16; i++) { 540 if ((mask & (1 << i)) == 0) 541 continue; 542 543 switch (sc->sc_intrtab[i].intr_type) { 544 case IST_NONE: 545 /* 546 * If nothing's using the IRQ, just return it. 547 */ 548 *irq = i; 549 return (0); 550 551 case IST_EDGE: 552 case IST_LEVEL: 553 if (type != sc->sc_intrtab[i].intr_type) 554 continue; 555 /* 556 * If the IRQ is sharable, count the number of 557 * other handlers, and if it's smaller than the 558 * last IRQ like this, remember it. 559 */ 560 tmp = 0; 561 for (ih = LIST_FIRST(&sc->sc_intrtab[i].intr_q); 562 ih != NULL; ih = LIST_NEXT(ih, ih_q)) 563 tmp++; 564 if (bestirq == -1 || count > tmp) { 565 bestirq = i; 566 count = tmp; 567 } 568 break; 569 570 case IST_PULSE: 571 /* This just isn't sharable. */ 572 continue; 573 } 574 } 575 576 if (bestirq == -1) 577 return (1); 578 579 *irq = bestirq; 580 return (0); 581 } 582