1 /* 2 * Copyright (c) 1997, Stefan Esser <se@freebsd.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice unmodified, this list of conditions, and the following 10 * disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 * 26 * $FreeBSD$ 27 * 28 */ 29 30 #include <sys/param.h> 31 #include <sys/systm.h> 32 #include <sys/bus.h> 33 #include <sys/kernel.h> 34 35 #include <pci/pcivar.h> 36 #include <pci/pcireg.h> 37 #include <i386/isa/pcibus.h> 38 39 #include <machine/segments.h> 40 #include <machine/pc/bios.h> 41 42 static int cfgmech; 43 static int devmax; 44 static int usebios; 45 46 static int pcibios_cfgread(pcicfgregs *cfg, int reg, int bytes); 47 static void pcibios_cfgwrite(pcicfgregs *cfg, int reg, int data, int bytes); 48 static int pcibios_cfgopen(void); 49 static int pcireg_cfgread(pcicfgregs *cfg, int reg, int bytes); 50 static void pcireg_cfgwrite(pcicfgregs *cfg, int reg, int data, int bytes); 51 static int pcireg_cfgopen(void); 52 53 /* read configuration space register */ 54 55 int 56 pci_cfgread(pcicfgregs *cfg, int reg, int bytes) 57 { 58 return(usebios ? 59 pcibios_cfgread(cfg, reg, bytes) : 60 pcireg_cfgread(cfg, reg, bytes)); 61 } 62 63 /* write configuration space register */ 64 65 void 66 pci_cfgwrite(pcicfgregs *cfg, int reg, int data, int bytes) 67 { 68 return(usebios ? 69 pcibios_cfgwrite(cfg, reg, data, bytes) : 70 pcireg_cfgwrite(cfg, reg, data, bytes)); 71 } 72 73 /* initialise access to PCI configuration space */ 74 static int 75 pci_cfgopen(void) 76 { 77 if (pcibios_cfgopen() != 0) { 78 usebios = 1; 79 } else if (pcireg_cfgopen() != 0) { 80 usebios = 0; 81 } else { 82 return(0); 83 } 84 return(1); 85 } 86 87 /* config space access using BIOS functions */ 88 89 static int 90 pcibios_cfgread(pcicfgregs *cfg, int reg, int bytes) 91 { 92 struct bios_regs args; 93 94 switch(bytes) { 95 case 1: 96 args.eax = PCIBIOS_READ_CONFIG_BYTE; 97 break; 98 case 2: 99 args.eax = PCIBIOS_READ_CONFIG_WORD; 100 break; 101 case 4: 102 args.eax = PCIBIOS_READ_CONFIG_DWORD; 103 break; 104 default: 105 return(-1); 106 } 107 args.ebx = (cfg->bus << 8) | (cfg->slot << 3) | (cfg->func); 108 args.edi = reg; 109 bios32(&args, PCIbios.ventry, GSEL(GCODE_SEL, SEL_KPL)); 110 /* check call results? */ 111 return(args.ecx); 112 } 113 114 static void 115 pcibios_cfgwrite(pcicfgregs *cfg, int reg, int data, int bytes) 116 { 117 struct bios_regs args; 118 119 switch(bytes) { 120 case 1: 121 args.eax = PCIBIOS_WRITE_CONFIG_BYTE; 122 break; 123 case 2: 124 args.eax = PCIBIOS_WRITE_CONFIG_WORD; 125 break; 126 case 4: 127 args.eax = PCIBIOS_WRITE_CONFIG_DWORD; 128 break; 129 default: 130 return; 131 } 132 args.ebx = (cfg->bus << 8) | (cfg->slot << 3) | (cfg->func); 133 args.ecx = data; 134 args.edi = reg; 135 bios32(&args, PCIbios.ventry, GSEL(GCODE_SEL, SEL_KPL)); 136 } 137 138 /* determine whether there is a PCI BIOS present */ 139 140 static int 141 pcibios_cfgopen(void) 142 { 143 /* check for a found entrypoint */ 144 return(PCIbios.entry != 0); 145 } 146 147 /* configuration space access using direct register operations */ 148 149 /* enable configuration space accesses and return data port address */ 150 151 static int 152 pci_cfgenable(unsigned bus, unsigned slot, unsigned func, int reg, int bytes) 153 { 154 int dataport = 0; 155 156 if (bus <= PCI_BUSMAX 157 && slot < devmax 158 && func <= PCI_FUNCMAX 159 && reg <= PCI_REGMAX 160 && bytes != 3 161 && (unsigned) bytes <= 4 162 && (reg & (bytes -1)) == 0) { 163 switch (cfgmech) { 164 case 1: 165 outl(CONF1_ADDR_PORT, (1 << 31) 166 | (bus << 16) | (slot << 11) 167 | (func << 8) | (reg & ~0x03)); 168 dataport = CONF1_DATA_PORT + (reg & 0x03); 169 break; 170 case 2: 171 outb(CONF2_ENABLE_PORT, 0xf0 | (func << 1)); 172 outb(CONF2_FORWARD_PORT, bus); 173 dataport = 0xc000 | (slot << 8) | reg; 174 break; 175 } 176 } 177 return (dataport); 178 } 179 180 /* disable configuration space accesses */ 181 182 static void 183 pci_cfgdisable(void) 184 { 185 switch (cfgmech) { 186 case 1: 187 outl(CONF1_ADDR_PORT, 0); 188 break; 189 case 2: 190 outb(CONF2_ENABLE_PORT, 0); 191 outb(CONF2_FORWARD_PORT, 0); 192 break; 193 } 194 } 195 196 static int 197 pcireg_cfgread(pcicfgregs *cfg, int reg, int bytes) 198 { 199 int data = -1; 200 int port; 201 202 port = pci_cfgenable(cfg->bus, cfg->slot, cfg->func, reg, bytes); 203 204 if (port != 0) { 205 switch (bytes) { 206 case 1: 207 data = inb(port); 208 break; 209 case 2: 210 data = inw(port); 211 break; 212 case 4: 213 data = inl(port); 214 break; 215 } 216 pci_cfgdisable(); 217 } 218 return (data); 219 } 220 221 static void 222 pcireg_cfgwrite(pcicfgregs *cfg, int reg, int data, int bytes) 223 { 224 int port; 225 226 port = pci_cfgenable(cfg->bus, cfg->slot, cfg->func, reg, bytes); 227 if (port != 0) { 228 switch (bytes) { 229 case 1: 230 outb(port, data); 231 break; 232 case 2: 233 outw(port, data); 234 break; 235 case 4: 236 outl(port, data); 237 break; 238 } 239 pci_cfgdisable(); 240 } 241 } 242 243 /* check whether the configuration mechanism has been correct identified */ 244 245 static int 246 pci_cfgcheck(int maxdev) 247 { 248 u_char device; 249 250 if (bootverbose) 251 printf("pci_cfgcheck:\tdevice "); 252 253 for (device = 0; device < maxdev; device++) { 254 unsigned id, class, header; 255 if (bootverbose) 256 printf("%d ", device); 257 258 id = inl(pci_cfgenable(0, device, 0, 0, 4)); 259 if (id == 0 || id == -1) 260 continue; 261 262 class = inl(pci_cfgenable(0, device, 0, 8, 4)) >> 8; 263 if (bootverbose) 264 printf("[class=%06x] ", class); 265 if (class == 0 || (class & 0xf870ff) != 0) 266 continue; 267 268 header = inb(pci_cfgenable(0, device, 0, 14, 1)); 269 if (bootverbose) 270 printf("[hdr=%02x] ", header); 271 if ((header & 0x7e) != 0) 272 continue; 273 274 if (bootverbose) 275 printf("is there (id=%08x)\n", id); 276 277 pci_cfgdisable(); 278 return (1); 279 } 280 if (bootverbose) 281 printf("-- nothing found\n"); 282 283 pci_cfgdisable(); 284 return (0); 285 } 286 287 static int 288 pcireg_cfgopen(void) 289 { 290 unsigned long mode1res,oldval1; 291 unsigned char mode2res,oldval2; 292 293 oldval1 = inl(CONF1_ADDR_PORT); 294 295 if (bootverbose) { 296 printf("pci_open(1):\tmode 1 addr port (0x0cf8) is 0x%08lx\n", 297 oldval1); 298 } 299 300 if ((oldval1 & CONF1_ENABLE_MSK) == 0) { 301 302 cfgmech = 1; 303 devmax = 32; 304 305 outl(CONF1_ADDR_PORT, CONF1_ENABLE_CHK); 306 outb(CONF1_ADDR_PORT +3, 0); 307 mode1res = inl(CONF1_ADDR_PORT); 308 outl(CONF1_ADDR_PORT, oldval1); 309 310 if (bootverbose) 311 printf("pci_open(1a):\tmode1res=0x%08lx (0x%08lx)\n", 312 mode1res, CONF1_ENABLE_CHK); 313 314 if (mode1res) { 315 if (pci_cfgcheck(32)) 316 return (cfgmech); 317 } 318 319 outl(CONF1_ADDR_PORT, CONF1_ENABLE_CHK1); 320 mode1res = inl(CONF1_ADDR_PORT); 321 outl(CONF1_ADDR_PORT, oldval1); 322 323 if (bootverbose) 324 printf("pci_open(1b):\tmode1res=0x%08lx (0x%08lx)\n", 325 mode1res, CONF1_ENABLE_CHK1); 326 327 if ((mode1res & CONF1_ENABLE_MSK1) == CONF1_ENABLE_RES1) { 328 if (pci_cfgcheck(32)) 329 return (cfgmech); 330 } 331 } 332 333 oldval2 = inb(CONF2_ENABLE_PORT); 334 335 if (bootverbose) { 336 printf("pci_open(2):\tmode 2 enable port (0x0cf8) is 0x%02x\n", 337 oldval2); 338 } 339 340 if ((oldval2 & 0xf0) == 0) { 341 342 cfgmech = 2; 343 devmax = 16; 344 345 outb(CONF2_ENABLE_PORT, CONF2_ENABLE_CHK); 346 mode2res = inb(CONF2_ENABLE_PORT); 347 outb(CONF2_ENABLE_PORT, oldval2); 348 349 if (bootverbose) 350 printf("pci_open(2a):\tmode2res=0x%02x (0x%02x)\n", 351 mode2res, CONF2_ENABLE_CHK); 352 353 if (mode2res == CONF2_ENABLE_RES) { 354 if (bootverbose) 355 printf("pci_open(2a):\tnow trying mechanism 2\n"); 356 357 if (pci_cfgcheck(16)) 358 return (cfgmech); 359 } 360 } 361 362 cfgmech = 0; 363 devmax = 0; 364 return (cfgmech); 365 } 366 367 static devclass_t pcib_devclass; 368 369 static const char * 370 nexus_pcib_is_host_bridge(pcicfgregs *cfg, 371 u_int32_t id, u_int8_t class, u_int8_t subclass, 372 u_int8_t *busnum) 373 { 374 const char *s = NULL; 375 static u_int8_t pxb[4]; /* hack for 450nx */ 376 377 *busnum = 0; 378 379 switch (id) { 380 case 0x12258086: 381 s = "Intel 824?? host to PCI bridge"; 382 /* XXX This is a guess */ 383 /* *busnum = pci_cfgread(cfg, 0x41, 1); */ 384 *busnum = cfg->bus; 385 break; 386 case 0x71208086: 387 s = "Intel 82810 (i810 GMCH) Host To Hub bridge"; 388 break; 389 case 0x71228086: 390 s = "Intel 82810-DC100 (i810-DC100 GMCH) Host To Hub bridge"; 391 break; 392 case 0x71248086: 393 s = "Intel 82810E (i810E GMCH) Host To Hub bridge"; 394 break; 395 case 0x71808086: 396 s = "Intel 82443LX (440 LX) host to PCI bridge"; 397 break; 398 case 0x71908086: 399 s = "Intel 82443BX (440 BX) host to PCI bridge"; 400 break; 401 case 0x71928086: 402 s = "Intel 82443BX host to PCI bridge (AGP disabled)"; 403 break; 404 case 0x71a08086: 405 s = "Intel 82443GX host to PCI bridge"; 406 break; 407 case 0x71a18086: 408 s = "Intel 82443GX host to AGP bridge"; 409 break; 410 case 0x71a28086: 411 s = "Intel 82443GX host to PCI bridge (AGP disabled)"; 412 break; 413 case 0x84c48086: 414 s = "Intel 82454KX/GX (Orion) host to PCI bridge"; 415 *busnum = pci_cfgread(cfg, 0x4a, 1); 416 break; 417 case 0x84ca8086: 418 /* 419 * For the 450nx chipset, there is a whole bundle of 420 * things pretending to be host bridges. The MIOC will 421 * be seen first and isn't really a pci bridge (the 422 * actual busses are attached to the PXB's). We need to 423 * read the registers of the MIOC to figure out the 424 * bus numbers for the PXB channels. 425 * 426 * Since the MIOC doesn't have a pci bus attached, we 427 * pretend it wasn't there. 428 */ 429 pxb[0] = pci_cfgread(cfg, 0xd0, 1); /* BUSNO[0] */ 430 pxb[1] = pci_cfgread(cfg, 0xd1, 1) + 1; /* SUBA[0]+1 */ 431 pxb[2] = pci_cfgread(cfg, 0xd3, 1); /* BUSNO[1] */ 432 pxb[3] = pci_cfgread(cfg, 0xd4, 1) + 1; /* SUBA[1]+1 */ 433 return NULL; 434 case 0x84cb8086: 435 switch (cfg->slot) { 436 case 0x12: 437 s = "Intel 82454NX PXB#0, Bus#A"; 438 *busnum = pxb[0]; 439 break; 440 case 0x13: 441 s = "Intel 82454NX PXB#0, Bus#B"; 442 *busnum = pxb[1]; 443 break; 444 case 0x14: 445 s = "Intel 82454NX PXB#1, Bus#A"; 446 *busnum = pxb[2]; 447 break; 448 case 0x15: 449 s = "Intel 82454NX PXB#1, Bus#B"; 450 *busnum = pxb[3]; 451 break; 452 } 453 break; 454 455 /* AMD -- vendor 0x1022 */ 456 case 0x70061022: 457 s = "AMD-751 host to PCI bridge"; 458 break; 459 460 /* SiS -- vendor 0x1039 */ 461 case 0x04961039: 462 s = "SiS 85c496"; 463 break; 464 case 0x04061039: 465 s = "SiS 85c501"; 466 break; 467 case 0x06011039: 468 s = "SiS 85c601"; 469 break; 470 case 0x55911039: 471 s = "SiS 5591 host to PCI bridge"; 472 break; 473 case 0x00011039: 474 s = "SiS 5591 host to AGP bridge"; 475 break; 476 477 /* VLSI -- vendor 0x1004 */ 478 case 0x00051004: 479 s = "VLSI 82C592 Host to PCI bridge"; 480 break; 481 482 /* XXX Here is MVP3, I got the datasheet but NO M/B to test it */ 483 /* totally. Please let me know if anything wrong. -F */ 484 /* XXX need info on the MVP3 -- any takers? */ 485 case 0x05981106: 486 s = "VIA 82C598MVP (Apollo MVP3) host bridge"; 487 break; 488 489 /* AcerLabs -- vendor 0x10b9 */ 490 /* Funny : The datasheet told me vendor id is "10b8",sub-vendor */ 491 /* id is '10b9" but the register always shows "10b9". -Foxfair */ 492 case 0x154110b9: 493 s = "AcerLabs M1541 (Aladdin-V) PCI host bridge"; 494 break; 495 496 /* OPTi -- vendor 0x1045 */ 497 case 0xc8221045: 498 s = "OPTi 82C822 host to PCI Bridge"; 499 break; 500 501 /* RCC -- vendor 0x1166 */ 502 case 0x00051166: 503 s = "RCC HE host to PCI bridge"; 504 *busnum = pci_cfgread(cfg, 0x44, 1); 505 break; 506 507 case 0x00061166: 508 /* FALLTHROUGH */ 509 case 0x00081166: 510 s = "RCC host to PCI bridge"; 511 *busnum = pci_cfgread(cfg, 0x44, 1); 512 break; 513 514 case 0x00091166: 515 s = "RCC LE host to PCI bridge"; 516 *busnum = pci_cfgread(cfg, 0x44, 1); 517 break; 518 519 /* Integrated Micro Solutions -- vendor 0x10e0 */ 520 case 0x884910e0: 521 s = "Integrated Micro Solutions VL Bridge"; 522 break; 523 524 default: 525 if (class == PCIC_BRIDGE && subclass == PCIS_BRIDGE_HOST) 526 s = "Host to PCI bridge"; 527 break; 528 } 529 530 return s; 531 } 532 533 /* 534 * Scan the first pci bus for host-pci bridges and add pcib instances 535 * to the nexus for each bridge. 536 */ 537 static void 538 nexus_pcib_identify(driver_t *driver, device_t parent) 539 { 540 pcicfgregs probe; 541 u_int8_t hdrtype; 542 int found = 0; 543 int pcifunchigh; 544 int found824xx = 0; 545 546 if (pci_cfgopen() == 0) 547 return; 548 probe.hose = 0; 549 probe.bus = 0; 550 retry: 551 for (probe.slot = 0; probe.slot <= PCI_SLOTMAX; probe.slot++) { 552 probe.func = 0; 553 hdrtype = pci_cfgread(&probe, PCIR_HEADERTYPE, 1); 554 if (hdrtype & PCIM_MFDEV) 555 pcifunchigh = 7; 556 else 557 pcifunchigh = 0; 558 for (probe.func = 0; 559 probe.func <= pcifunchigh; 560 probe.func++) { 561 /* 562 * Read the IDs and class from the device. 563 */ 564 u_int32_t id; 565 u_int8_t class, subclass, busnum; 566 device_t child; 567 const char *s; 568 569 id = pci_cfgread(&probe, PCIR_DEVVENDOR, 4); 570 if (id == -1) 571 continue; 572 class = pci_cfgread(&probe, PCIR_CLASS, 1); 573 subclass = pci_cfgread(&probe, PCIR_SUBCLASS, 1); 574 575 s = nexus_pcib_is_host_bridge(&probe, id, 576 class, subclass, 577 &busnum); 578 if (s) { 579 /* 580 * Add at priority 100 to make sure we 581 * go after any motherboard resources 582 */ 583 child = BUS_ADD_CHILD(parent, 100, 584 "pcib", busnum); 585 device_set_desc(child, s); 586 found = 1; 587 if (id == 0x12258086) 588 found824xx = 1; 589 } 590 } 591 } 592 if (found824xx && probe.bus == 0) { 593 probe.bus++; 594 goto retry; 595 } 596 597 /* 598 * Make sure we add at least one bridge since some old 599 * hardware doesn't actually have a host-pci bridge device. 600 * Note that pci_cfgopen() thinks we have PCI devices.. 601 */ 602 if (!found) { 603 if (bootverbose) 604 printf( 605 "nexus_pcib_identify: no bridge found, adding pcib0 anyway\n"); 606 BUS_ADD_CHILD(parent, 100, "pcib", 0); 607 } 608 } 609 610 static int 611 nexus_pcib_probe(device_t dev) 612 { 613 if (pci_cfgopen() != 0) { 614 device_add_child(dev, "pci", device_get_unit(dev)); 615 return 0; 616 } 617 return ENXIO; 618 } 619 620 static device_method_t nexus_pcib_methods[] = { 621 /* Device interface */ 622 DEVMETHOD(device_identify, nexus_pcib_identify), 623 DEVMETHOD(device_probe, nexus_pcib_probe), 624 DEVMETHOD(device_attach, bus_generic_attach), 625 DEVMETHOD(device_shutdown, bus_generic_shutdown), 626 DEVMETHOD(device_suspend, bus_generic_suspend), 627 DEVMETHOD(device_resume, bus_generic_resume), 628 629 /* Bus interface */ 630 DEVMETHOD(bus_print_child, bus_generic_print_child), 631 DEVMETHOD(bus_alloc_resource, bus_generic_alloc_resource), 632 DEVMETHOD(bus_release_resource, bus_generic_release_resource), 633 DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), 634 DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), 635 DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), 636 DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), 637 638 { 0, 0 } 639 }; 640 641 static driver_t nexus_pcib_driver = { 642 "pcib", 643 nexus_pcib_methods, 644 1, 645 }; 646 647 DRIVER_MODULE(pcib, nexus, nexus_pcib_driver, pcib_devclass, 0, 0); 648