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