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