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