pci_pir.c revision 57092
136108Sjb/* 248558Sdes * Copyright (c) 1997, Stefan Esser <se@freebsd.org> 336108Sjb * All rights reserved. 436108Sjb * 543818Swes * Redistribution and use in source and binary forms, with or without 643818Swes * modification, are permitted provided that the following conditions 743818Swes * are met: 843818Swes * 1. Redistributions of source code must retain the above copyright 943818Swes * notice unmodified, this list of conditions, and the following 1043818Swes * disclaimer. 1143818Swes * 2. Redistributions in binary form must reproduce the above copyright 1243818Swes * notice, this list of conditions and the following disclaimer in the 1343818Swes * documentation and/or other materials provided with the distribution. 1443818Swes * 1543818Swes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1643818Swes * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1743818Swes * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 1843818Swes * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 1943818Swes * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2043818Swes * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2143818Swes * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2243818Swes * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2343818Swes * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2443818Swes * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2543818Swes * 2643818Swes * $FreeBSD: head/sys/i386/pci/pci_pir.c 57092 2000-02-09 20:05:30Z gallatin $ 2736108Sjb * 2836108Sjb */ 2936108Sjb 3036108Sjb#include <sys/param.h> 3136108Sjb#include <sys/systm.h> 3236108Sjb#include <sys/bus.h> 3336108Sjb#include <sys/kernel.h> 3436108Sjb 3536108Sjb#include <pci/pcivar.h> 3636108Sjb#include <pci/pcireg.h> 3748558Sdes#include <i386/isa/pcibus.h> 3848558Sdes 3948558Sdesstatic int cfgmech; 4048558Sdesstatic int devmax; 4148558Sdes 4248558Sdes/* enable configuration space accesses and return data port address */ 4336108Sjb 4436108Sjbstatic int 4536108Sjbpci_cfgenable(unsigned bus, unsigned slot, unsigned func, int reg, int bytes) 4636108Sjb{ 4736108Sjb int dataport = 0; 4836108Sjb 4936108Sjb if (bus <= PCI_BUSMAX 5036108Sjb && slot < devmax 5136108Sjb && func <= PCI_FUNCMAX 5236108Sjb && reg <= PCI_REGMAX 5336108Sjb && bytes != 3 5436108Sjb && (unsigned) bytes <= 4 5536108Sjb && (reg & (bytes -1)) == 0) { 5636108Sjb switch (cfgmech) { 5736108Sjb case 1: 5836108Sjb outl(CONF1_ADDR_PORT, (1 << 31) 5936108Sjb | (bus << 16) | (slot << 11) 6036108Sjb | (func << 8) | (reg & ~0x03)); 6136108Sjb dataport = CONF1_DATA_PORT + (reg & 0x03); 6236108Sjb break; 6336108Sjb case 2: 6436108Sjb outb(CONF2_ENABLE_PORT, 0xf0 | (func << 1)); 6536108Sjb outb(CONF2_FORWARD_PORT, bus); 6636108Sjb dataport = 0xc000 | (slot << 8) | reg; 6736108Sjb break; 6836108Sjb } 6936108Sjb } 7036108Sjb return (dataport); 7136108Sjb} 7236108Sjb 7336108Sjb/* disable configuration space accesses */ 7436108Sjb 7536108Sjbstatic void 7636108Sjbpci_cfgdisable(void) 7736108Sjb{ 7836108Sjb switch (cfgmech) { 7936108Sjb case 1: 8036108Sjb outl(CONF1_ADDR_PORT, 0); 8136108Sjb break; 8236108Sjb case 2: 8336108Sjb outb(CONF2_ENABLE_PORT, 0); 8436108Sjb outb(CONF2_FORWARD_PORT, 0); 8536108Sjb break; 8636108Sjb } 8736108Sjb} 8836108Sjb 8936108Sjb/* read configuration space register */ 9036108Sjb 9136108Sjbint 9236108Sjbpci_cfgread(pcicfgregs *cfg, int reg, int bytes) 9336108Sjb{ 9436108Sjb int data = -1; 9536108Sjb int port; 9636108Sjb 9736108Sjb port = pci_cfgenable(cfg->bus, cfg->slot, cfg->func, reg, bytes); 9836108Sjb 9936108Sjb if (port != 0) { 10036108Sjb switch (bytes) { 10136108Sjb case 1: 10236108Sjb data = inb(port); 10336108Sjb break; 10436108Sjb case 2: 10536108Sjb data = inw(port); 10636108Sjb break; 10736108Sjb case 4: 10836108Sjb data = inl(port); 10936108Sjb break; 11036108Sjb } 11136108Sjb pci_cfgdisable(); 11236108Sjb } 11336108Sjb return (data); 11436108Sjb} 11536108Sjb 11636108Sjb/* write configuration space register */ 11736108Sjb 11836108Sjbvoid 11936108Sjbpci_cfgwrite(pcicfgregs *cfg, int reg, int data, int bytes) 12036108Sjb{ 12136108Sjb int port; 12236108Sjb 12336108Sjb port = pci_cfgenable(cfg->bus, cfg->slot, cfg->func, reg, bytes); 12436108Sjb if (port != 0) { 12536108Sjb switch (bytes) { 12636108Sjb case 1: 12736108Sjb outb(port, data); 12836108Sjb break; 12936108Sjb case 2: 13036108Sjb outw(port, data); 13136108Sjb break; 13236108Sjb case 4: 13336108Sjb outl(port, data); 13436108Sjb break; 13536108Sjb } 13636108Sjb pci_cfgdisable(); 13736108Sjb } 13836108Sjb} 13936108Sjb 14036108Sjb/* check whether the configuration mechanism has been correct identified */ 14136108Sjb 14236108Sjbstatic int 14336108Sjbpci_cfgcheck(int maxdev) 14436108Sjb{ 14536108Sjb u_char device; 14636108Sjb 14736108Sjb if (bootverbose) 14836108Sjb printf("pci_cfgcheck:\tdevice "); 14936108Sjb 15036108Sjb for (device = 0; device < maxdev; device++) { 15136108Sjb unsigned id, class, header; 15236108Sjb if (bootverbose) 15336108Sjb printf("%d ", device); 15436108Sjb 15536108Sjb id = inl(pci_cfgenable(0, device, 0, 0, 4)); 15636108Sjb if (id == 0 || id == -1) 15736108Sjb continue; 15836108Sjb 15936108Sjb class = inl(pci_cfgenable(0, device, 0, 8, 4)) >> 8; 16036108Sjb if (bootverbose) 16136108Sjb printf("[class=%06x] ", class); 16236108Sjb if (class == 0 || (class & 0xf870ff) != 0) 16336108Sjb continue; 16436108Sjb 16536108Sjb header = inb(pci_cfgenable(0, device, 0, 14, 1)); 16636108Sjb if (bootverbose) 16736108Sjb printf("[hdr=%02x] ", header); 16836108Sjb if ((header & 0x7e) != 0) 16936108Sjb continue; 17036108Sjb 17136108Sjb if (bootverbose) 17236108Sjb printf("is there (id=%08x)\n", id); 17336108Sjb 17436108Sjb pci_cfgdisable(); 17536108Sjb return (1); 17636108Sjb } 17736108Sjb if (bootverbose) 17836108Sjb printf("-- nothing found\n"); 17936108Sjb 18036108Sjb pci_cfgdisable(); 18136108Sjb return (0); 18236108Sjb} 18336108Sjb 18436108Sjbstatic int 18536108Sjbpci_cfgopen(void) 18636108Sjb{ 18736108Sjb unsigned long mode1res,oldval1; 18836108Sjb unsigned char mode2res,oldval2; 18936108Sjb 19036108Sjb oldval1 = inl(CONF1_ADDR_PORT); 19136108Sjb 19236108Sjb if (bootverbose) { 19336108Sjb printf("pci_open(1):\tmode 1 addr port (0x0cf8) is 0x%08lx\n", 19436108Sjb oldval1); 19536108Sjb } 19636108Sjb 19736108Sjb if ((oldval1 & CONF1_ENABLE_MSK) == 0) { 19836108Sjb 19936108Sjb cfgmech = 1; 20036108Sjb devmax = 32; 20136108Sjb 20236108Sjb outl(CONF1_ADDR_PORT, CONF1_ENABLE_CHK); 20336108Sjb outb(CONF1_ADDR_PORT +3, 0); 20436108Sjb mode1res = inl(CONF1_ADDR_PORT); 20536108Sjb outl(CONF1_ADDR_PORT, oldval1); 20636108Sjb 20736108Sjb if (bootverbose) 20836108Sjb printf("pci_open(1a):\tmode1res=0x%08lx (0x%08lx)\n", 20936108Sjb mode1res, CONF1_ENABLE_CHK); 21036108Sjb 21136108Sjb if (mode1res) { 21236108Sjb if (pci_cfgcheck(32)) 21336108Sjb return (cfgmech); 21436108Sjb } 21536108Sjb 21636108Sjb outl(CONF1_ADDR_PORT, CONF1_ENABLE_CHK1); 21736108Sjb mode1res = inl(CONF1_ADDR_PORT); 21836108Sjb outl(CONF1_ADDR_PORT, oldval1); 21936108Sjb 22036108Sjb if (bootverbose) 22136108Sjb printf("pci_open(1b):\tmode1res=0x%08lx (0x%08lx)\n", 22236108Sjb mode1res, CONF1_ENABLE_CHK1); 22336108Sjb 22436108Sjb if ((mode1res & CONF1_ENABLE_MSK1) == CONF1_ENABLE_RES1) { 22536108Sjb if (pci_cfgcheck(32)) 22636108Sjb return (cfgmech); 22736108Sjb } 22836108Sjb } 22936108Sjb 23036108Sjb oldval2 = inb(CONF2_ENABLE_PORT); 23136108Sjb 23236108Sjb if (bootverbose) { 23336108Sjb printf("pci_open(2):\tmode 2 enable port (0x0cf8) is 0x%02x\n", 23436108Sjb oldval2); 23536108Sjb } 23636108Sjb 23736108Sjb if ((oldval2 & 0xf0) == 0) { 23836108Sjb 23936108Sjb cfgmech = 2; 24036108Sjb devmax = 16; 24136108Sjb 24236108Sjb outb(CONF2_ENABLE_PORT, CONF2_ENABLE_CHK); 24336108Sjb mode2res = inb(CONF2_ENABLE_PORT); 24436108Sjb outb(CONF2_ENABLE_PORT, oldval2); 24536108Sjb 24636108Sjb if (bootverbose) 24736108Sjb printf("pci_open(2a):\tmode2res=0x%02x (0x%02x)\n", 24836108Sjb mode2res, CONF2_ENABLE_CHK); 24936108Sjb 25036108Sjb if (mode2res == CONF2_ENABLE_RES) { 25136108Sjb if (bootverbose) 25236108Sjb printf("pci_open(2a):\tnow trying mechanism 2\n"); 25336108Sjb 25436108Sjb if (pci_cfgcheck(16)) 25536108Sjb return (cfgmech); 25636108Sjb } 25736108Sjb } 25836108Sjb 25936108Sjb cfgmech = 0; 26036108Sjb devmax = 0; 26136108Sjb return (cfgmech); 26236108Sjb} 26336108Sjb 26436108Sjbstatic devclass_t pcib_devclass; 26536108Sjb 26636108Sjbstatic const char * 26736108Sjbnexus_pcib_is_host_bridge(pcicfgregs *cfg, 26836108Sjb u_int32_t id, u_int8_t class, u_int8_t subclass, 26936108Sjb u_int8_t *busnum) 27036108Sjb{ 27136108Sjb const char *s = NULL; 27236108Sjb static u_int8_t pxb[4]; /* hack for 450nx */ 27336108Sjb 27436108Sjb *busnum = 0; 27536108Sjb 27636108Sjb switch (id) { 27736108Sjb case 0x12258086: 27836108Sjb s = "Intel 824?? host to PCI bridge"; 27936108Sjb /* XXX This is a guess */ 28036108Sjb *busnum = pci_cfgread(cfg, 0x41, 1); 28136108Sjb break; 28236108Sjb case 0x71208086: 28336108Sjb s = "Intel 82810 (i810 GMCH) Host To Hub bridge"; 28436108Sjb break; 28536108Sjb case 0x71228086: 28636108Sjb s = "Intel 82810-DC100 (i810-DC100 GMCH) Host To Hub bridge"; 28736108Sjb break; 28836108Sjb case 0x71248086: 28936108Sjb s = "Intel 82810E (i810E GMCH) Host To Hub bridge"; 29036108Sjb break; 29136108Sjb case 0x71808086: 29236108Sjb s = "Intel 82443LX (440 LX) host to PCI bridge"; 29336108Sjb break; 29436108Sjb case 0x71908086: 29536108Sjb s = "Intel 82443BX (440 BX) host to PCI bridge"; 29636108Sjb break; 29736108Sjb case 0x71928086: 29836108Sjb s = "Intel 82443BX host to PCI bridge (AGP disabled)"; 29936108Sjb break; 30036108Sjb case 0x71a08086: 30136108Sjb s = "Intel 82443GX host to PCI bridge"; 30236108Sjb break; 30336108Sjb case 0x71a18086: 30436108Sjb s = "Intel 82443GX host to AGP bridge"; 30536108Sjb break; 306 case 0x71a28086: 307 s = "Intel 82443GX host to PCI bridge (AGP disabled)"; 308 break; 309 case 0x84c48086: 310 s = "Intel 82454KX/GX (Orion) host to PCI bridge"; 311 *busnum = pci_cfgread(cfg, 0x4a, 1); 312 break; 313 case 0x84ca8086: 314 /* 315 * For the 450nx chipset, there is a whole bundle of 316 * things pretending to be host bridges. The MIOC will 317 * be seen first and isn't really a pci bridge (the 318 * actual busses are attached to the PXB's). We need to 319 * read the registers of the MIOC to figure out the 320 * bus numbers for the PXB channels. 321 * 322 * Since the MIOC doesn't have a pci bus attached, we 323 * pretend it wasn't there. 324 */ 325 pxb[0] = pci_cfgread(cfg, 0xd0, 1); /* BUSNO[0] */ 326 pxb[1] = pci_cfgread(cfg, 0xd1, 1) + 1; /* SUBA[0]+1 */ 327 pxb[2] = pci_cfgread(cfg, 0xd3, 1); /* BUSNO[1] */ 328 pxb[3] = pci_cfgread(cfg, 0xd4, 1) + 1; /* SUBA[1]+1 */ 329 return NULL; 330 case 0x84cb8086: 331 switch (cfg->slot) { 332 case 0x12: 333 s = "Intel 82454NX PXB#0, Bus#A"; 334 *busnum = pxb[0]; 335 break; 336 case 0x13: 337 s = "Intel 82454NX PXB#0, Bus#B"; 338 *busnum = pxb[1]; 339 break; 340 case 0x14: 341 s = "Intel 82454NX PXB#1, Bus#A"; 342 *busnum = pxb[2]; 343 break; 344 case 0x15: 345 s = "Intel 82454NX PXB#1, Bus#B"; 346 *busnum = pxb[3]; 347 break; 348 } 349 break; 350 351 /* AMD -- vendor 0x1022 */ 352 case 0x70061022: 353 s = "AMD-751 host to PCI bridge"; 354 break; 355 356 /* SiS -- vendor 0x1039 */ 357 case 0x04961039: 358 s = "SiS 85c496"; 359 break; 360 case 0x04061039: 361 s = "SiS 85c501"; 362 break; 363 case 0x06011039: 364 s = "SiS 85c601"; 365 break; 366 case 0x55911039: 367 s = "SiS 5591 host to PCI bridge"; 368 break; 369 case 0x00011039: 370 s = "SiS 5591 host to AGP bridge"; 371 break; 372 373 /* VLSI -- vendor 0x1004 */ 374 case 0x00051004: 375 s = "VLSI 82C592 Host to PCI bridge"; 376 break; 377 378 /* XXX Here is MVP3, I got the datasheet but NO M/B to test it */ 379 /* totally. Please let me know if anything wrong. -F */ 380 /* XXX need info on the MVP3 -- any takers? */ 381 case 0x05981106: 382 s = "VIA 82C598MVP (Apollo MVP3) host bridge"; 383 break; 384 385 /* AcerLabs -- vendor 0x10b9 */ 386 /* Funny : The datasheet told me vendor id is "10b8",sub-vendor */ 387 /* id is '10b9" but the register always shows "10b9". -Foxfair */ 388 case 0x154110b9: 389 s = "AcerLabs M1541 (Aladdin-V) PCI host bridge"; 390 break; 391 392 /* OPTi -- vendor 0x1045 */ 393 case 0xc8221045: 394 s = "OPTi 82C822 host to PCI Bridge"; 395 break; 396 397 /* RCC -- vendor 0x1166 */ 398 case 0x00051166: 399 s = "RCC HE host to PCI bridge"; 400 *busnum = pci_cfgread(cfg, 0x44, 1); 401 break; 402 403 case 0x00061166: 404 /* FALLTHROUGH */ 405 case 0x00081166: 406 s = "RCC host to PCI bridge"; 407 *busnum = pci_cfgread(cfg, 0x44, 1); 408 break; 409 410 case 0x00091166: 411 s = "RCC LE host to PCI bridge"; 412 *busnum = pci_cfgread(cfg, 0x44, 1); 413 break; 414 415 /* Integrated Micro Solutions -- vendor 0x10e0 */ 416 case 0x884910e0: 417 s = "Integrated Micro Solutions VL Bridge"; 418 break; 419 420 default: 421 if (class == PCIC_BRIDGE && subclass == PCIS_BRIDGE_HOST) 422 s = "Host to PCI bridge"; 423 break; 424 } 425 426 return s; 427} 428 429/* 430 * Scan the first pci bus for host-pci bridges and add pcib instances 431 * to the nexus for each bridge. 432 */ 433static void 434nexus_pcib_identify(driver_t *driver, device_t parent) 435{ 436 pcicfgregs probe; 437 u_int8_t hdrtype; 438 int found = 0; 439 int pcifunchigh; 440 441 if (pci_cfgopen() == 0) 442 return; 443 probe.hose = 0; 444 probe.bus = 0; 445 for (probe.slot = 0; probe.slot <= PCI_SLOTMAX; probe.slot++) { 446 hdrtype = pci_cfgread(&probe, PCIR_HEADERTYPE, 1); 447 if (hdrtype & PCIM_MFDEV) 448 pcifunchigh = 7; 449 else 450 pcifunchigh = 0; 451 for (probe.func = 0; 452 probe.func <= pcifunchigh; 453 probe.func++) { 454 /* 455 * Read the IDs and class from the device. 456 */ 457 u_int32_t id; 458 u_int8_t class, subclass, busnum; 459 device_t child; 460 const char *s; 461 462 id = pci_cfgread(&probe, PCIR_DEVVENDOR, 4); 463 if (id == -1) 464 continue; 465 class = pci_cfgread(&probe, PCIR_CLASS, 1); 466 subclass = pci_cfgread(&probe, PCIR_SUBCLASS, 1); 467 468 s = nexus_pcib_is_host_bridge(&probe, id, 469 class, subclass, 470 &busnum); 471 if (s) { 472 /* 473 * Add at priority 100 to make sure we 474 * go after any motherboard resources 475 */ 476 child = BUS_ADD_CHILD(parent, 100, 477 "pcib", busnum); 478 device_set_desc(child, s); 479 found = 1; 480 } 481 } 482 } 483 484 /* 485 * Make sure we add at least one bridge since some old 486 * hardware doesn't actually have a host-pci bridge device. 487 * Note that pci_cfgopen() thinks we have PCI devices.. 488 */ 489 if (!found) { 490 if (bootverbose) 491 printf( 492 "nexus_pcib_identify: no bridge found, adding pcib0 anyway\n"); 493 BUS_ADD_CHILD(parent, 100, "pcib", 0); 494 } 495} 496 497static int 498nexus_pcib_probe(device_t dev) 499{ 500 if (pci_cfgopen() != 0) { 501 device_add_child(dev, "pci", device_get_unit(dev)); 502 return 0; 503 } 504 return ENXIO; 505} 506 507static device_method_t nexus_pcib_methods[] = { 508 /* Device interface */ 509 DEVMETHOD(device_identify, nexus_pcib_identify), 510 DEVMETHOD(device_probe, nexus_pcib_probe), 511 DEVMETHOD(device_attach, bus_generic_attach), 512 DEVMETHOD(device_shutdown, bus_generic_shutdown), 513 DEVMETHOD(device_suspend, bus_generic_suspend), 514 DEVMETHOD(device_resume, bus_generic_resume), 515 516 /* Bus interface */ 517 DEVMETHOD(bus_print_child, bus_generic_print_child), 518 DEVMETHOD(bus_alloc_resource, bus_generic_alloc_resource), 519 DEVMETHOD(bus_release_resource, bus_generic_release_resource), 520 DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), 521 DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), 522 DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), 523 DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), 524 525 { 0, 0 } 526}; 527 528static driver_t nexus_pcib_driver = { 529 "pcib", 530 nexus_pcib_methods, 531 1, 532}; 533 534DRIVER_MODULE(pcib, nexus, nexus_pcib_driver, pcib_devclass, 0, 0); 535