1 /* $OpenBSD: pcibios.c,v 1.24 2001/05/12 19:12:44 mickey Exp $ */ 2 /* $NetBSD: pcibios.c,v 1.5 2000/08/01 05:23:59 uch Exp $ */ 3 4 /* 5 * Copyright (c) 2000 Michael Shalayeff 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by Michael Shalayeff. 19 * 4. The name of the author may not be used to endorse or promote products 20 * derived from this software without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 25 * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT, 26 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 27 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 28 * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 30 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 31 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 32 * THE POSSIBILITY OF SUCH DAMAGE. 33 */ 34 /*- 35 * Copyright (c) 1999 The NetBSD Foundation, Inc. 36 * All rights reserved. 37 * 38 * This code is derived from software contributed to The NetBSD Foundation 39 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, 40 * NASA Ames Research Center. 41 * 42 * Redistribution and use in source and binary forms, with or without 43 * modification, are permitted provided that the following conditions 44 * are met: 45 * 1. Redistributions of source code must retain the above copyright 46 * notice, this list of conditions and the following disclaimer. 47 * 2. Redistributions in binary form must reproduce the above copyright 48 * notice, this list of conditions and the following disclaimer in the 49 * documentation and/or other materials provided with the distribution. 50 * 3. All advertising materials mentioning features or use of this software 51 * must display the following acknowledgement: 52 * This product includes software developed by the NetBSD 53 * Foundation, Inc. and its contributors. 54 * 4. Neither the name of The NetBSD Foundation nor the names of its 55 * contributors may be used to endorse or promote products derived 56 * from this software without specific prior written permission. 57 * 58 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 59 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 60 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 61 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 62 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 63 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 64 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 65 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 66 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 67 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 68 * POSSIBILITY OF SUCH DAMAGE. 69 */ 70 /* 71 * Copyright (c) 1999, by UCHIYAMA Yasushi 72 * All rights reserved. 73 * 74 * Redistribution and use in source and binary forms, with or without 75 * modification, are permitted provided that the following conditions 76 * are met: 77 * 1. Redistributions of source code must retain the above copyright 78 * notice, this list of conditions and the following disclaimer. 79 * 2. The name of the developer may NOT be used to endorse or promote products 80 * derived from this software without specific prior written permission. 81 * 82 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 83 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 84 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 85 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 86 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 87 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 88 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 89 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 90 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 91 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 92 * SUCH DAMAGE. 93 */ 94 95 /* 96 * Interface to the PCI BIOS and PCI Interrupt Routing table. 97 */ 98 99 #include <sys/param.h> 100 #include <sys/systm.h> 101 #include <sys/device.h> 102 #include <sys/malloc.h> 103 104 #include <dev/isa/isareg.h> 105 #include <i386/isa/isa_machdep.h> 106 107 #include <dev/pci/pcireg.h> 108 #include <dev/pci/pcivar.h> 109 #include <dev/pci/pcidevs.h> 110 111 #include <i386/pci/pcibiosvar.h> 112 113 #include <machine/biosvar.h> 114 115 int pcibios_present; 116 117 struct pcibios_pir_header pcibios_pir_header; 118 struct pcibios_intr_routing *pcibios_pir_table; 119 int pcibios_pir_table_nentries; 120 int pcibios_flags = 0; 121 122 struct bios32_entry pcibios_entry; 123 struct bios32_entry_info pcibios_entry_info; 124 125 struct pcibios_intr_routing *pcibios_pir_init __P((struct pcibios_softc *)); 126 127 int pcibios_get_status __P((struct pcibios_softc *, 128 u_int32_t *, u_int32_t *, u_int32_t *, 129 u_int32_t *, u_int32_t *, u_int32_t *, u_int32_t *)); 130 int pcibios_get_intr_routing __P((struct pcibios_softc *, 131 struct pcibios_intr_routing *, int *, u_int16_t *)); 132 133 int pcibios_return_code __P((struct pcibios_softc *, u_int16_t, const char *)); 134 135 void pcibios_print_exclirq __P((struct pcibios_softc *)); 136 void pcibios_print_pir_table __P((void)); 137 138 #define PCI_IRQ_TABLE_START 0xf0000 139 #define PCI_IRQ_TABLE_END 0xfffff 140 141 struct cfdriver pcibios_cd = { 142 NULL, "pcibios", DV_DULL 143 }; 144 145 int pcibiosprobe __P((struct device *, void *, void *)); 146 void pcibiosattach __P((struct device *, struct device *, void *)); 147 148 struct cfattach pcibios_ca = { 149 sizeof(struct pcibios_softc), pcibiosprobe, pcibiosattach 150 }; 151 152 int 153 pcibiosprobe(parent, match, aux) 154 struct device *parent; 155 void *match, *aux; 156 { 157 struct bios_attach_args *ba = aux; 158 u_int32_t rev_maj, rev_min, mech1, mech2, scmech1, scmech2, maxbus; 159 int rv; 160 161 if (strcmp(ba->bios_dev, "pcibios")) 162 return 0; 163 164 rv = bios32_service(PCIBIOS_SIGNATURE, &pcibios_entry, 165 &pcibios_entry_info); 166 167 PCIBIOS_PRINTV(("pcibiosprobe: 0x%lx:0x%lx at 0x%lx[0x%lx]\n", 168 pcibios_entry.segment, pcibios_entry.offset, 169 pcibios_entry_info.bei_base, pcibios_entry_info.bei_size)); 170 171 return rv && 172 pcibios_get_status(NULL, &rev_maj, &rev_min, &mech1, &mech2, 173 &scmech1, &scmech2, &maxbus) == PCIBIOS_SUCCESS; 174 } 175 176 void 177 pcibiosattach(parent, self, aux) 178 struct device *parent, *self; 179 void *aux; 180 { 181 struct pcibios_softc *sc = (struct pcibios_softc *)self; 182 u_int32_t rev_maj, rev_min, mech1, mech2, scmech1, scmech2; 183 184 pcibios_flags = sc->sc_dev.dv_cfdata->cf_flags; 185 186 pcibios_get_status((struct pcibios_softc *)self, &rev_maj, 187 &rev_min, &mech1, &mech2, 188 &scmech1, &scmech2, &sc->max_bus); 189 190 printf(": rev. %d.%d @ 0x%lx/0x%lx\n", 191 rev_maj, rev_min >> 4, pcibios_entry_info.bei_base, 192 pcibios_entry_info.bei_size); 193 194 PCIBIOS_PRINTV(("%s: config mechanism %s%s, special cycles %s%s, " 195 "last bus %d\n", sc->sc_dev.dv_xname, 196 mech1 ? "[1]" : "[x]", mech2 ? "[2]" : "[x]", 197 scmech1 ? "[1]" : "[x]", scmech2 ? "[2]" : "[x]", sc->max_bus)); 198 199 /* 200 * The PCI BIOS tells us the config mechanism; fill it in now 201 * so that pci_mode_detect() doesn't have to look for it. 202 */ 203 pci_mode = mech1 ? 1 : 2; 204 205 pcibios_present = 1; 206 207 /* 208 * Find the PCI IRQ Routing table. 209 */ 210 211 if (!(pcibios_flags & PCIBIOS_INTR_FIXUP) && 212 pcibios_pir_init((struct pcibios_softc *)self) != NULL) { 213 int rv; 214 215 /* 216 * Fixup interrupt routing. 217 */ 218 rv = pci_intr_fixup(sc, NULL, I386_BUS_SPACE_IO); 219 switch (rv) { 220 case -1: 221 /* Non-fatal error. */ 222 printf("%s: Warning, unable to fix up PCI interrupt " 223 "routing\n", sc->sc_dev.dv_xname); 224 break; 225 226 case 1: 227 /* Fatal error. */ 228 printf("%s: interrupt fixup failed\n", sc->sc_dev.dv_xname); 229 return; 230 } 231 232 /* 233 * XXX Clear `pciirq' from the ISA interrupt allocation 234 * XXX mask. 235 */ 236 } 237 238 if (!(pcibios_flags & PCIBIOS_BUS_FIXUP)) { 239 sc->max_bus = pci_bus_fixup(NULL, 0); 240 printf("%s: PCI bus #%d is the last bus\n", 241 sc->sc_dev.dv_xname, sc->max_bus); 242 } 243 244 if (!(pcibios_flags & PCIBIOS_ADDR_FIXUP)) 245 pci_addr_fixup(sc, NULL, sc->max_bus); 246 } 247 248 struct pcibios_intr_routing * 249 pcibios_pir_init(sc) 250 struct pcibios_softc *sc; 251 { 252 paddr_t pa; 253 254 pcibios_pir_table = NULL; 255 for (pa = PCI_IRQ_TABLE_START; pa < PCI_IRQ_TABLE_END; pa += 16) { 256 u_int8_t *p, cksum; 257 struct pcibios_pir_header *pirh; 258 int i; 259 260 pirh = (struct pcibios_pir_header *)p = ISA_HOLE_VADDR(pa); 261 if (pirh->signature != BIOS32_MAKESIG('$', 'P', 'I', 'R')) 262 continue; 263 264 cksum = 0; 265 for (i = 0; i < pirh->tablesize; i++) 266 cksum += p[i]; 267 268 printf("%s: PCI IRQ Routing Table rev. %d.%d @ 0x%lx/%d " 269 "(%d entries)\n", sc->sc_dev.dv_xname, 270 pirh->version >> 8, pirh->version & 0xff, pa, 271 pirh->tablesize, (pirh->tablesize - 32) / 16); 272 273 if (cksum != 0) { 274 printf("%s: bad IRQ table checksum\n", 275 sc->sc_dev.dv_xname); 276 continue; 277 } 278 279 if (pirh->tablesize < 32 || (pirh->tablesize % 16) != 0) { 280 printf("%s: bad IRQ table size\n", sc->sc_dev.dv_xname); 281 continue; 282 } 283 284 if (pirh->version != 0x0100) { 285 printf("%s: unsupported IRQ table version\n", 286 sc->sc_dev.dv_xname); 287 continue; 288 } 289 290 /* 291 * We can handle this table! Make a copy of it. 292 */ 293 pcibios_pir_header = *pirh; 294 pcibios_pir_table = 295 malloc(pirh->tablesize - 32, M_DEVBUF, M_NOWAIT); 296 if (pcibios_pir_table == NULL) { 297 printf("%s: no memory for $PIR\n", sc->sc_dev.dv_xname); 298 return NULL; 299 } 300 bcopy(p + 32, pcibios_pir_table, pirh->tablesize - 32); 301 pcibios_pir_table_nentries = (pirh->tablesize - 32) / 16; 302 303 } 304 305 /* 306 * If there was no PIR table found, try using the PCI BIOS 307 * Get Interrupt Routing call. 308 * 309 * XXX The interface to this call sucks; just allocate enough 310 * XXX room for 32 entries. 311 */ 312 if (pcibios_pir_table == NULL) { 313 314 pcibios_pir_table_nentries = 32; 315 pcibios_pir_table = malloc(pcibios_pir_table_nentries * 316 sizeof(*pcibios_pir_table), M_DEVBUF, M_NOWAIT); 317 if (pcibios_pir_table == NULL) { 318 printf("%s: no memory for $PIR\n", sc->sc_dev.dv_xname); 319 return NULL; 320 } 321 if (pcibios_get_intr_routing(sc, pcibios_pir_table, 322 &pcibios_pir_table_nentries, 323 &pcibios_pir_header.exclusive_irq) != PCIBIOS_SUCCESS) { 324 printf("%s: PCI IRQ Routing information unavailable.\n", 325 sc->sc_dev.dv_xname); 326 free(pcibios_pir_table, M_DEVBUF); 327 pcibios_pir_table = NULL; 328 pcibios_pir_table_nentries = 0; 329 return NULL; 330 } 331 printf("%s: PCI BIOS has %d Interrupt Routing table entries\n", 332 sc->sc_dev.dv_xname, pcibios_pir_table_nentries); 333 } 334 335 pcibios_print_exclirq(sc); 336 if (pcibios_flags & PCIBIOS_INTRDEBUG) 337 pcibios_print_pir_table(); 338 return pcibios_pir_table; 339 } 340 341 int 342 pcibios_get_status(sc, rev_maj, rev_min, mech1, mech2, scmech1, scmech2, maxbus) 343 struct pcibios_softc *sc; 344 u_int32_t *rev_maj, *rev_min, *mech1, *mech2, *scmech1, *scmech2, 345 *maxbus; 346 { 347 u_int32_t ax, bx, cx, edx; 348 int rv; 349 350 __asm __volatile("pushl %%es\n\t" 351 "pushl %%ds\n\t" 352 "movw 4(%%edi), %%ecx\n\t" 353 "movl %%ecx, %%ds\n\t" 354 "lcall %%cs:(%%edi)\n\t" 355 "pop %%ds\n\t" 356 "pop %%es\n\t" 357 "jc 1f\n\t" 358 "xor %%ah, %%ah\n" 359 "1:" 360 : "=a" (ax), "=b" (bx), "=c" (cx), "=d" (edx) 361 : "0" (0xb101), "D" (&pcibios_entry) 362 : "cc", "memory"); 363 364 rv = pcibios_return_code(sc, ax, "pcibios_get_status"); 365 if (rv != PCIBIOS_SUCCESS) 366 return (rv); 367 368 if (edx != BIOS32_MAKESIG('P', 'C', 'I', ' ')) 369 return (PCIBIOS_SERVICE_NOT_PRESENT); /* XXX */ 370 371 /* 372 * Fill in the various pieces if info we're looking for. 373 */ 374 *mech1 = ax & 1; 375 *mech2 = ax & (1 << 1); 376 *scmech1 = ax & (1 << 4); 377 *scmech2 = ax & (1 << 5); 378 *rev_maj = (bx >> 8) & 0xff; 379 *rev_min = bx & 0xff; 380 *maxbus = cx & 0xff; 381 382 return (PCIBIOS_SUCCESS); 383 } 384 385 int 386 pcibios_get_intr_routing(sc, table, nentries, exclirq) 387 struct pcibios_softc *sc; 388 struct pcibios_intr_routing *table; 389 int *nentries; 390 u_int16_t *exclirq; 391 { 392 u_int32_t ax, bx; 393 int rv; 394 struct { 395 u_int16_t size; 396 u_int32_t offset; 397 u_int16_t segment; 398 } __attribute__((__packed__)) args; 399 400 args.size = *nentries * sizeof(*table); 401 args.offset = (u_int32_t)table; 402 args.segment = GSEL(GDATA_SEL, SEL_KPL); 403 404 memset(table, 0, args.size); 405 406 __asm __volatile("pushl %%es\n\t" 407 "pushl %%ds\n\t" 408 "movw 4(%%esi), %%ecx\n\t" 409 "movl %%ecx, %%ds\n\t" 410 "lcall %%cs:(%%esi)\n\t" 411 "popl %%ds\n\t" 412 "popl %%es\n\t" 413 "jc 1f\n\t" 414 "xor %%ah, %%ah\n" 415 "1:\n" 416 : "=a" (ax), "=b" (bx) 417 : "0" (0xb10e), "1" (0), "D" (&args), "S" (&pcibios_entry) 418 : "%ecx", "%edx", "cc", "memory"); 419 420 rv = pcibios_return_code(sc, ax, "pcibios_get_intr_routing"); 421 if (rv != PCIBIOS_SUCCESS) 422 return (rv); 423 424 *nentries = args.size / sizeof(*table); 425 *exclirq |= bx; 426 427 return (PCIBIOS_SUCCESS); 428 } 429 430 int 431 pcibios_return_code(sc, ax, func) 432 struct pcibios_softc *sc; 433 u_int16_t ax; 434 const char *func; 435 { 436 const char *errstr; 437 int rv = ax >> 8; 438 char *nam; 439 440 if (sc) 441 nam = sc->sc_dev.dv_xname; 442 else 443 nam = "pcibios0"; 444 445 switch (rv) { 446 case PCIBIOS_SUCCESS: 447 return (PCIBIOS_SUCCESS); 448 449 case PCIBIOS_SERVICE_NOT_PRESENT: 450 errstr = "service not present"; 451 break; 452 453 case PCIBIOS_FUNCTION_NOT_SUPPORTED: 454 errstr = "function not supported"; 455 break; 456 457 case PCIBIOS_BAD_VENDOR_ID: 458 errstr = "bad vendor ID"; 459 break; 460 461 case PCIBIOS_DEVICE_NOT_FOUND: 462 errstr = "device not found"; 463 break; 464 465 case PCIBIOS_BAD_REGISTER_NUMBER: 466 errstr = "bad register number"; 467 break; 468 469 case PCIBIOS_SET_FAILED: 470 errstr = "set failed"; 471 break; 472 473 case PCIBIOS_BUFFER_TOO_SMALL: 474 errstr = "buffer too small"; 475 break; 476 477 default: 478 printf("%s: %s - unknown return code 0x%x\n", 479 nam, func, rv); 480 return (rv); 481 } 482 483 printf("%s: %s - %s\n", nam, func, errstr); 484 return (rv); 485 } 486 487 void 488 pcibios_print_exclirq(sc) 489 struct pcibios_softc *sc; 490 { 491 int i; 492 493 if (pcibios_pir_header.exclusive_irq) { 494 printf("%s: PCI Exclusive IRQs:", sc->sc_dev.dv_xname); 495 for (i = 0; i < 16; i++) { 496 if (pcibios_pir_header.exclusive_irq & (1 << i)) 497 printf(" %d", i); 498 } 499 printf("\n"); 500 } 501 } 502 503 void 504 pcibios_print_pir_table() 505 { 506 int i, j; 507 508 for (i = 0; i < pcibios_pir_table_nentries; i++) { 509 printf("PIR Entry %d:\n", i); 510 printf("\tBus: %d Device: %d\n", 511 pcibios_pir_table[i].bus, 512 PIR_DEVFUNC_DEVICE(pcibios_pir_table[i].device)); 513 for (j = 0; j < 4; j++) { 514 printf("\t\tINT%c: link 0x%02x bitmap 0x%04x\n", 515 'A' + j, 516 pcibios_pir_table[i].linkmap[j].link, 517 pcibios_pir_table[i].linkmap[j].bitmap); 518 } 519 } 520 } 521 522 void 523 pci_device_foreach(sc, pc, maxbus, func) 524 struct pcibios_softc *sc; 525 pci_chipset_tag_t pc; 526 int maxbus; 527 void (*func) __P((struct pcibios_softc *, pci_chipset_tag_t, pcitag_t)); 528 { 529 const struct pci_quirkdata *qd; 530 int bus, device, function, maxdevs, nfuncs; 531 pcireg_t id, bhlcr; 532 pcitag_t tag; 533 534 for (bus = 0; bus <= maxbus; bus++) { 535 maxdevs = pci_bus_maxdevs(pc, bus); 536 for (device = 0; device < maxdevs; device++) { 537 tag = pci_make_tag(pc, bus, device, 0); 538 id = pci_conf_read(pc, tag, PCI_ID_REG); 539 540 /* Invalid vendor ID value? */ 541 if (PCI_VENDOR(id) == PCI_VENDOR_INVALID) 542 continue; 543 /* XXX Not invalid, but we've done this ~forever. */ 544 if (PCI_VENDOR(id) == 0) 545 continue; 546 547 qd = pci_lookup_quirkdata(PCI_VENDOR(id), 548 PCI_PRODUCT(id)); 549 550 bhlcr = pci_conf_read(pc, tag, PCI_BHLC_REG); 551 if (PCI_HDRTYPE_MULTIFN(bhlcr) || 552 (qd != NULL && 553 (qd->quirks & PCI_QUIRK_MULTIFUNCTION) != 0)) 554 nfuncs = 8; 555 else 556 nfuncs = 1; 557 558 for (function = 0; function < nfuncs; function++) { 559 tag = pci_make_tag(pc, bus, device, function); 560 id = pci_conf_read(pc, tag, PCI_ID_REG); 561 562 /* Invalid vendor ID value? */ 563 if (PCI_VENDOR(id) == PCI_VENDOR_INVALID) 564 continue; 565 /* 566 * XXX Not invalid, but we've done this 567 * ~forever. 568 */ 569 if (PCI_VENDOR(id) == 0) 570 continue; 571 (*func)(sc, pc, tag); 572 } 573 } 574 } 575 } 576