1 /* $NetBSD: pcib.c,v 1.16 2004/08/30 15:05:15 drochner 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.16 2004/08/30 15:05:15 drochner 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 CFATTACH_DECL(pcib, sizeof(struct pcib_softc), 125 pcib_match, pcib_attach, NULL, NULL); 126 127 void pcib_isa_attach_hook(struct device *, struct device *, 128 struct isabus_attach_args *); 129 130 int pcib_intr(void *); 131 132 void pcib_bridge_callback(struct device *); 133 134 const struct evcnt *pcib_isa_intr_evcnt(void *, int); 135 void *pcib_isa_intr_establish(void *, int, int, int, 136 int (*)(void *), void *); 137 void pcib_isa_intr_disestablish(void *, void *); 138 int pcib_isa_intr_alloc(void *, int, int, int *); 139 140 void pcib_set_icus(struct pcib_softc *); 141 142 int 143 pcib_match(struct device *parent, struct cfdata *match, void *aux) 144 { 145 struct pci_attach_args *pa = aux; 146 147 if (PCI_CLASS(pa->pa_class) == PCI_CLASS_BRIDGE && 148 PCI_SUBCLASS(pa->pa_class) == PCI_SUBCLASS_BRIDGE_ISA) 149 return (1); 150 151 return (0); 152 } 153 154 void 155 pcib_attach(struct device *parent, struct device *self, void *aux) 156 { 157 struct pcib_softc *sc = (void *) self; 158 struct pci_attach_args *pa = aux; 159 char devinfo[256]; 160 int i; 161 162 pci_devinfo(pa->pa_id, pa->pa_class, 0, devinfo, sizeof(devinfo)); 163 printf(": %s (rev. 0x%02x)\n", devinfo, 164 PCI_REVISION(pa->pa_class)); 165 166 sc->sc_iot = pa->pa_iot; 167 168 /* 169 * Map the PIC/ELCR registers. 170 */ 171 if (bus_space_map(sc->sc_iot, 0x4d0, 2, 0, &sc->sc_ioh_elcr) != 0) 172 printf("%s: unable to map ELCR registers\n", 173 sc->sc_dev.dv_xname); 174 if (bus_space_map(sc->sc_iot, IO_ICU1, 2, 0, &sc->sc_ioh_icu1) != 0) 175 printf("%s: unable to map ICU1 registers\n", 176 sc->sc_dev.dv_xname); 177 if (bus_space_map(sc->sc_iot, IO_ICU2, 2, 0, &sc->sc_ioh_icu2) != 0) 178 printf("%s: unable to map ICU2 registers\n", 179 sc->sc_dev.dv_xname); 180 181 /* All interrupts default to "masked off". */ 182 sc->sc_imask = 0xffff; 183 184 /* All interrupts default to edge-triggered. */ 185 sc->sc_elcr = 0; 186 187 /* 188 * Initialize the 8259s. 189 */ 190 191 /* reset, program device, 4 bytes */ 192 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_ICW1, 193 ICW1_SELECT | ICW1_IC4); 194 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_ICW2, 195 ICW2_VECTOR(0)/*XXX*/); 196 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_ICW3, 197 ICW3_CASCADE(2)); 198 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_ICW4, 199 ICW4_8086); 200 201 /* mask all interrupts */ 202 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_OCW1, 203 sc->sc_imask & 0xff); 204 205 /* enable special mask mode */ 206 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_OCW3, 207 OCW3_SELECT | OCW3_SSMM | OCW3_SMM); 208 209 /* read IRR by default */ 210 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_OCW3, 211 OCW3_SELECT | OCW3_RR); 212 213 /* reset; program device, 4 bytes */ 214 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2, PIC_ICW1, 215 ICW1_SELECT | ICW1_IC4); 216 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2, PIC_ICW2, 217 ICW2_VECTOR(0)/*XXX*/); 218 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2, PIC_ICW3, 219 ICW3_SIC(2)); 220 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2, PIC_ICW4, 221 ICW4_8086); 222 223 /* mask all interrupts */ 224 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2, PIC_OCW1, 225 (sc->sc_imask >> 8) & 0xff); 226 227 /* enable special mask mode */ 228 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2, PIC_OCW3, 229 OCW3_SELECT | OCW3_SSMM | OCW3_SMM); 230 231 /* read IRR by default */ 232 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2, PIC_OCW3, 233 OCW3_SELECT | OCW3_RR); 234 235 /* 236 * Default all interrupts to edge-triggered. 237 */ 238 bus_space_write_1(sc->sc_iot, sc->sc_ioh_elcr, 0, 239 sc->sc_elcr & 0xff); 240 bus_space_write_1(sc->sc_iot, sc->sc_ioh_elcr, 1, 241 (sc->sc_elcr >> 8) & 0xff); 242 243 /* 244 * Some ISA interrupts are reserved for devices that 245 * we know are hard-wired to certain IRQs. 246 */ 247 sc->sc_reserved = 248 (1U << 0) | /* timer */ 249 (1U << 1) | /* keyboard controller */ 250 (1U << 2) | /* PIC cascade */ 251 (1U << 3) | /* COM 2 */ 252 (1U << 4) | /* COM 1 */ 253 (1U << 6) | /* floppy */ 254 (1U << 7) | /* centronics */ 255 (1U << 8) | /* RTC */ 256 (1U << 12) | /* keyboard controller */ 257 (1U << 14) | /* IDE 0 */ 258 (1U << 15); /* IDE 1 */ 259 260 #if defined(ALGOR_P5064) 261 /* 262 * Some "ISA" interrupts are a little wacky, wired up directly 263 * to the P-5064 interrupt controller. 264 */ 265 sc->sc_parent_ic = &p5064_configuration.ac_ic; 266 #endif /* ALGOR_P5064 */ 267 268 /* Set up our ISA chipset. */ 269 sc->sc_ic.ic_v = sc; 270 sc->sc_ic.ic_intr_evcnt = pcib_isa_intr_evcnt; 271 sc->sc_ic.ic_intr_establish = pcib_isa_intr_establish; 272 sc->sc_ic.ic_intr_disestablish = pcib_isa_intr_disestablish; 273 sc->sc_ic.ic_intr_alloc = pcib_isa_intr_alloc; 274 275 /* Initialize our interrupt table. */ 276 for (i = 0; i < 16; i++) { 277 LIST_INIT(&sc->sc_intrtab[i].intr_q); 278 evcnt_attach_dynamic(&sc->sc_intrtab[i].intr_count, 279 EVCNT_TYPE_INTR, NULL, "pcib", pcib_intrnames[i]); 280 sc->sc_intrtab[i].intr_type = IST_NONE; 281 } 282 283 /* Hook up our interrupt handler. */ 284 #if defined(ALGOR_P5064) 285 sc->sc_ih = (*algor_intr_establish)(P5064_IRQ_ISABRIDGE, 286 pcib_intr, sc); 287 #elif defined(ALGOR_P6032) 288 sc->sc_ih = (*algor_intr_establish)(P6032_IRQ_ISABRIDGE, 289 pcib_intr, sc); 290 #endif 291 if (sc->sc_ih == NULL) 292 printf("%s: WARNING: unable to register interrupt handler\n", 293 sc->sc_dev.dv_xname); 294 295 config_defer(self, pcib_bridge_callback); 296 } 297 298 void 299 pcib_bridge_callback(self) 300 struct device *self; 301 { 302 struct pcib_softc *sc = (struct pcib_softc *)self; 303 struct isabus_attach_args iba; 304 305 memset(&iba, 0, sizeof(iba)); 306 307 #if defined(ALGOR_P5064) 308 { 309 struct p5064_config *acp = &p5064_configuration; 310 311 iba.iba_iot = &acp->ac_iot; 312 iba.iba_memt = &acp->ac_memt; 313 iba.iba_dmat = &acp->ac_isa_dmat; 314 } 315 #elif defined(ALGOR_P6032) 316 { 317 struct p6032_config *acp = &p6032_configuration; 318 319 iba.iba_iot = &acp->ac_iot; 320 iba.iba_memt = &acp->ac_memt; 321 iba.iba_dmat = &acp->ac_isa_dmat; 322 } 323 #endif 324 325 iba.iba_ic = &sc->sc_ic; 326 iba.iba_ic->ic_attach_hook = pcib_isa_attach_hook; 327 328 (void) config_found_ia(&sc->sc_dev, "isabus", &iba, isabusprint); 329 } 330 331 void 332 pcib_isa_attach_hook(struct device *parent, struct device *self, 333 struct isabus_attach_args *iba) 334 { 335 336 /* Nothing to do. */ 337 } 338 339 void 340 pcib_set_icus(struct pcib_softc *sc) 341 { 342 343 /* Enable the cascade IRQ (2) if 8-15 is enabled. */ 344 if ((sc->sc_imask & 0xff00) != 0xff00) 345 sc->sc_imask &= ~(1U << 2); 346 else 347 sc->sc_imask |= (1U << 2); 348 349 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_OCW1, 350 sc->sc_imask & 0xff); 351 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2, PIC_OCW1, 352 (sc->sc_imask >> 8) & 0xff); 353 354 bus_space_write_1(sc->sc_iot, sc->sc_ioh_elcr, 0, 355 sc->sc_elcr & 0xff); 356 bus_space_write_1(sc->sc_iot, sc->sc_ioh_elcr, 1, 357 (sc->sc_elcr >> 8) & 0xff); 358 } 359 360 int 361 pcib_intr(void *v) 362 { 363 struct pcib_softc *sc = v; 364 struct algor_intrhand *ih; 365 int irq; 366 367 for (;;) { 368 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_OCW3, 369 OCW3_SELECT | OCW3_POLL); 370 irq = bus_space_read_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_OCW3); 371 if ((irq & OCW3_POLL_PENDING) == 0) 372 return (1); 373 374 irq = OCW3_POLL_IRQ(irq); 375 376 if (irq == 2) { 377 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2, 378 PIC_OCW3, OCW3_SELECT | OCW3_POLL); 379 irq = bus_space_read_1(sc->sc_iot, sc->sc_ioh_icu2, 380 PIC_OCW3); 381 if (irq & OCW3_POLL_PENDING) 382 irq = OCW3_POLL_IRQ(irq) + 8; 383 else 384 irq = 2; 385 } 386 387 sc->sc_intrtab[irq].intr_count.ev_count++; 388 for (ih = LIST_FIRST(&sc->sc_intrtab[irq].intr_q); 389 ih != NULL; ih = LIST_NEXT(ih, ih_q)) { 390 (*ih->ih_func)(ih->ih_arg); 391 } 392 393 /* Send a specific EOI to the 8259. */ 394 if (irq > 7) { 395 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu2, 396 PIC_OCW2, OCW2_SELECT | OCW3_EOI | OCW3_SL | 397 OCW2_ILS(irq & 7)); 398 irq = 2; 399 } 400 401 bus_space_write_1(sc->sc_iot, sc->sc_ioh_icu1, PIC_OCW2, 402 OCW2_SELECT | OCW3_EOI | OCW3_SL | OCW2_ILS(irq)); 403 } 404 } 405 406 const struct evcnt * 407 pcib_isa_intr_evcnt(void *v, int irq) 408 { 409 struct pcib_softc *sc = v; 410 411 #if defined(ALGOR_P5064) 412 if (p5064_isa_to_irqmap[irq] != -1) 413 return (isa_intr_evcnt(sc->sc_parent_ic, irq)); 414 #endif 415 416 return (&sc->sc_intrtab[irq].intr_count); 417 } 418 419 void * 420 pcib_isa_intr_establish(void *v, int irq, int type, int level, 421 int (*func)(void *), void *arg) 422 { 423 struct pcib_softc *sc = v; 424 struct algor_intrhand *ih; 425 int s; 426 427 if (irq > 15 || irq == 2 || type == IST_NONE) 428 panic("pcib_isa_intr_establish: bad irq or type"); 429 430 #if defined(ALGOR_P5064) 431 if (p5064_isa_to_irqmap[irq] != -1) 432 return (isa_intr_establish(sc->sc_parent_ic, irq, type, 433 level, func, arg)); 434 #endif 435 436 switch (sc->sc_intrtab[irq].intr_type) { 437 case IST_NONE: 438 sc->sc_intrtab[irq].intr_type = type; 439 break; 440 441 case IST_EDGE: 442 case IST_LEVEL: 443 if (type == sc->sc_intrtab[irq].intr_type) 444 break; 445 /* FALLTHROUGH */ 446 case IST_PULSE: 447 /* 448 * We can't share interrupts in this case. 449 */ 450 return (NULL); 451 } 452 453 ih = malloc(sizeof(*ih), M_DEVBUF, M_NOWAIT); 454 if (ih == NULL) 455 return (NULL); 456 457 ih->ih_func = func; 458 ih->ih_arg = arg; 459 ih->ih_irq = irq; 460 ih->ih_irqmap = NULL; 461 462 s = splhigh(); 463 464 /* Insert the handler into the table. */ 465 LIST_INSERT_HEAD(&sc->sc_intrtab[irq].intr_q, ih, ih_q); 466 sc->sc_intrtab[irq].intr_type = type; 467 468 /* Enable it, set trigger mode. */ 469 sc->sc_imask &= ~(1 << irq); 470 if (sc->sc_intrtab[irq].intr_type == IST_LEVEL) 471 sc->sc_elcr |= (1 << irq); 472 else 473 sc->sc_elcr &= ~(1 << irq); 474 475 pcib_set_icus(sc); 476 477 splx(s); 478 479 return (ih); 480 } 481 482 void 483 pcib_isa_intr_disestablish(void *v, void *arg) 484 { 485 struct pcib_softc *sc = v; 486 struct algor_intrhand *ih = arg; 487 int s; 488 489 #if defined(ALGOR_P5064) 490 if (p5064_isa_to_irqmap[ih->ih_irq] != -1) { 491 isa_intr_disestablish(sc->sc_parent_ic, ih); 492 return; 493 } 494 #endif 495 496 s = splhigh(); 497 498 LIST_REMOVE(ih, ih_q); 499 500 /* If there are no more handlers on this IRQ, disable it. */ 501 if (LIST_FIRST(&sc->sc_intrtab[ih->ih_irq].intr_q) == NULL) { 502 sc->sc_imask |= (1 << ih->ih_irq); 503 pcib_set_icus(sc); 504 } 505 506 splx(s); 507 508 free(ih, M_DEVBUF); 509 } 510 511 int 512 pcib_isa_intr_alloc(void *v, int mask, int type, int *irq) 513 { 514 struct pcib_softc *sc = v; 515 int i, tmp, bestirq, count; 516 struct algor_intrhand *ih; 517 518 if (type == IST_NONE) 519 panic("pcib_intr_alloc: bogus type"); 520 521 bestirq = -1; 522 count = -1; 523 524 mask &= ~sc->sc_reserved; 525 526 #if 0 527 printf("pcib_intr_alloc: mask = 0x%04x\n", mask); 528 #endif 529 530 for (i = 0; i < 16; i++) { 531 if ((mask & (1 << i)) == 0) 532 continue; 533 534 switch (sc->sc_intrtab[i].intr_type) { 535 case IST_NONE: 536 /* 537 * If nothing's using the IRQ, just return it. 538 */ 539 *irq = i; 540 return (0); 541 542 case IST_EDGE: 543 case IST_LEVEL: 544 if (type != sc->sc_intrtab[i].intr_type) 545 continue; 546 /* 547 * If the IRQ is sharable, count the number of 548 * other handlers, and if it's smaller than the 549 * last IRQ like this, remember it. 550 */ 551 tmp = 0; 552 for (ih = LIST_FIRST(&sc->sc_intrtab[i].intr_q); 553 ih != NULL; ih = LIST_NEXT(ih, ih_q)) 554 tmp++; 555 if (bestirq == -1 || count > tmp) { 556 bestirq = i; 557 count = tmp; 558 } 559 break; 560 561 case IST_PULSE: 562 /* This just isn't sharable. */ 563 continue; 564 } 565 } 566 567 if (bestirq == -1) 568 return (1); 569 570 *irq = bestirq; 571 return (0); 572 } 573