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 * $Id: pcibus.c,v 1.46 1999/08/10 09:22:21 peter Exp $ 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 #ifdef PCI_COMPAT 40 /* XXX this is a terrible hack, which keeps the Tekram AMD SCSI driver happy */ 41 #define cfgmech pci_mechanism 42 int cfgmech; 43 #else 44 static int cfgmech; 45 #endif /* PCI_COMPAT */ 46 static int devmax; 47 48 /* enable configuration space accesses and return data port address */ 49 50 static int 51 pci_cfgenable(unsigned bus, unsigned slot, unsigned func, int reg, int bytes) 52 { 53 int dataport = 0; 54 55 if (bus <= PCI_BUSMAX 56 && slot < devmax 57 && func <= PCI_FUNCMAX 58 && reg <= PCI_REGMAX 59 && bytes != 3 60 && (unsigned) bytes <= 4 61 && (reg & (bytes -1)) == 0) { 62 switch (cfgmech) { 63 case 1: 64 outl(CONF1_ADDR_PORT, (1 << 31) 65 | (bus << 16) | (slot << 11) 66 | (func << 8) | (reg & ~0x03)); 67 dataport = CONF1_DATA_PORT + (reg & 0x03); 68 break; 69 case 2: 70 outb(CONF2_ENABLE_PORT, 0xf0 | (func << 1)); 71 outb(CONF2_FORWARD_PORT, bus); 72 dataport = 0xc000 | (slot << 8) | reg; 73 break; 74 } 75 } 76 return (dataport); 77 } 78 79 /* disable configuration space accesses */ 80 81 static void 82 pci_cfgdisable(void) 83 { 84 switch (cfgmech) { 85 case 1: 86 outl(CONF1_ADDR_PORT, 0); 87 break; 88 case 2: 89 outb(CONF2_ENABLE_PORT, 0); 90 outb(CONF2_FORWARD_PORT, 0); 91 break; 92 } 93 } 94 95 /* read configuration space register */ 96 97 int 98 pci_cfgread(pcicfgregs *cfg, int reg, int bytes) 99 { 100 int data = -1; 101 int port; 102 103 port = pci_cfgenable(cfg->bus, cfg->slot, cfg->func, reg, bytes); 104 105 if (port != 0) { 106 switch (bytes) { 107 case 1: 108 data = inb(port); 109 break; 110 case 2: 111 data = inw(port); 112 break; 113 case 4: 114 data = inl(port); 115 break; 116 } 117 pci_cfgdisable(); 118 } 119 return (data); 120 } 121 122 /* write configuration space register */ 123 124 void 125 pci_cfgwrite(pcicfgregs *cfg, int reg, int data, int bytes) 126 { 127 int port; 128 129 port = pci_cfgenable(cfg->bus, cfg->slot, cfg->func, reg, bytes); 130 if (port != 0) { 131 switch (bytes) { 132 case 1: 133 outb(port, data); 134 break; 135 case 2: 136 outw(port, data); 137 break; 138 case 4: 139 outl(port, data); 140 break; 141 } 142 pci_cfgdisable(); 143 } 144 } 145 146 /* check whether the configuration mechanism has been correct identified */ 147 148 static int 149 pci_cfgcheck(int maxdev) 150 { 151 u_char device; 152 153 if (bootverbose) 154 printf("pci_cfgcheck:\tdevice "); 155 156 for (device = 0; device < maxdev; device++) { 157 unsigned id, class, header; 158 if (bootverbose) 159 printf("%d ", device); 160 161 id = inl(pci_cfgenable(0, device, 0, 0, 4)); 162 if (id == 0 || id == -1) 163 continue; 164 165 class = inl(pci_cfgenable(0, device, 0, 8, 4)) >> 8; 166 if (bootverbose) 167 printf("[class=%06x] ", class); 168 if (class == 0 || (class & 0xf870ff) != 0) 169 continue; 170 171 header = inb(pci_cfgenable(0, device, 0, 14, 1)); 172 if (bootverbose) 173 printf("[hdr=%02x] ", header); 174 if ((header & 0x7e) != 0) 175 continue; 176 177 if (bootverbose) 178 printf("is there (id=%08x)\n", id); 179 180 pci_cfgdisable(); 181 return (1); 182 } 183 if (bootverbose) 184 printf("-- nothing found\n"); 185 186 pci_cfgdisable(); 187 return (0); 188 } 189 190 static int 191 pci_cfgopen(void) 192 { 193 unsigned long mode1res,oldval1; 194 unsigned char mode2res,oldval2; 195 196 oldval1 = inl(CONF1_ADDR_PORT); 197 198 if (bootverbose) { 199 printf("pci_open(1):\tmode 1 addr port (0x0cf8) is 0x%08lx\n", 200 oldval1); 201 } 202 203 if ((oldval1 & CONF1_ENABLE_MSK) == 0) { 204 205 cfgmech = 1; 206 devmax = 32; 207 208 outl(CONF1_ADDR_PORT, CONF1_ENABLE_CHK); 209 outb(CONF1_ADDR_PORT +3, 0); 210 mode1res = inl(CONF1_ADDR_PORT); 211 outl(CONF1_ADDR_PORT, oldval1); 212 213 if (bootverbose) 214 printf("pci_open(1a):\tmode1res=0x%08lx (0x%08lx)\n", 215 mode1res, CONF1_ENABLE_CHK); 216 217 if (mode1res) { 218 if (pci_cfgcheck(32)) 219 return (cfgmech); 220 } 221 222 outl(CONF1_ADDR_PORT, CONF1_ENABLE_CHK1); 223 mode1res = inl(CONF1_ADDR_PORT); 224 outl(CONF1_ADDR_PORT, oldval1); 225 226 if (bootverbose) 227 printf("pci_open(1b):\tmode1res=0x%08lx (0x%08lx)\n", 228 mode1res, CONF1_ENABLE_CHK1); 229 230 if ((mode1res & CONF1_ENABLE_MSK1) == CONF1_ENABLE_RES1) { 231 if (pci_cfgcheck(32)) 232 return (cfgmech); 233 } 234 } 235 236 oldval2 = inb(CONF2_ENABLE_PORT); 237 238 if (bootverbose) { 239 printf("pci_open(2):\tmode 2 enable port (0x0cf8) is 0x%02x\n", 240 oldval2); 241 } 242 243 if ((oldval2 & 0xf0) == 0) { 244 245 cfgmech = 2; 246 devmax = 16; 247 248 outb(CONF2_ENABLE_PORT, CONF2_ENABLE_CHK); 249 mode2res = inb(CONF2_ENABLE_PORT); 250 outb(CONF2_ENABLE_PORT, oldval2); 251 252 if (bootverbose) 253 printf("pci_open(2a):\tmode2res=0x%02x (0x%02x)\n", 254 mode2res, CONF2_ENABLE_CHK); 255 256 if (mode2res == CONF2_ENABLE_RES) { 257 if (bootverbose) 258 printf("pci_open(2a):\tnow trying mechanism 2\n"); 259 260 if (pci_cfgcheck(16)) 261 return (cfgmech); 262 } 263 } 264 265 cfgmech = 0; 266 devmax = 0; 267 return (cfgmech); 268 } 269 270 static devclass_t pcib_devclass; 271 272 static const char * 273 nexus_pcib_is_host_bridge(pcicfgregs *cfg, 274 u_int32_t id, u_int8_t class, u_int8_t subclass, 275 u_int8_t *busnum) 276 { 277 const char *s = NULL; 278 static u_int8_t pxb[4]; /* hack for 450nx */ 279 280 *busnum = 0; 281 282 switch (id) { 283 case 0x12258086: 284 s = "Intel 824?? host to PCI bridge"; 285 /* XXX This is a guess */ 286 *busnum = pci_cfgread(cfg, 0x41, 1); 287 break; 288 case 0x71808086: 289 s = "Intel 82443LX (440 LX) host to PCI bridge"; 290 break; 291 case 0x71908086: 292 s = "Intel 82443BX (440 BX) host to PCI bridge"; 293 break; 294 case 0x71928086: 295 s = "Intel 82443BX host to PCI bridge (AGP disabled)"; 296 break; 297 case 0x71a08086: 298 s = "Intel 82443GX host to PCI bridge"; 299 break; 300 case 0x71a18086: 301 s = "Intel 82443GX host to AGP bridge"; 302 break; 303 case 0x71a28086: 304 s = "Intel 82443GX host to PCI bridge (AGP disabled)"; 305 break; 306 case 0x84c48086: 307 s = "Intel 82454KX/GX (Orion) host to PCI bridge"; 308 *busnum = pci_cfgread(cfg, 0x4a, 1); 309 break; 310 case 0x84ca8086: 311 /* 312 * For the 450nx chipset, there is a whole bundle of 313 * things pretending to be host bridges. The MIOC will 314 * be seen first and isn't really a pci bridge (the 315 * actual busses are attached to the PXB's). We need to 316 * read the registers of the MIOC to figure out the 317 * bus numbers for the PXB channels. 318 * 319 * Since the MIOC doesn't have a pci bus attached, we 320 * pretend it wasn't there. 321 */ 322 pxb[0] = pci_cfgread(cfg, 0xd0, 1); /* BUSNO[0] */ 323 pxb[1] = pci_cfgread(cfg, 0xd1, 1) + 1; /* SUBA[0]+1 */ 324 pxb[2] = pci_cfgread(cfg, 0xd3, 1); /* BUSNO[1] */ 325 pxb[3] = pci_cfgread(cfg, 0xd4, 1) + 1; /* SUBA[1]+1 */ 326 return NULL; 327 case 0x84cb8086: 328 switch (cfg->slot) { 329 case 0x12: 330 s = "Intel 82454NX PXB#0, Bus#A"; 331 *busnum = pxb[0]; 332 break; 333 case 0x13: 334 s = "Intel 82454NX PXB#0, Bus#B"; 335 *busnum = pxb[1]; 336 break; 337 case 0x14: 338 s = "Intel 82454NX PXB#1, Bus#A"; 339 *busnum = pxb[2]; 340 break; 341 case 0x15: 342 s = "Intel 82454NX PXB#1, Bus#B"; 343 *busnum = pxb[3]; 344 break; 345 } 346 break; 347 348 /* SiS -- vendor 0x1039 */ 349 case 0x04961039: 350 s = "SiS 85c496"; 351 break; 352 case 0x04061039: 353 s = "SiS 85c501"; 354 break; 355 case 0x06011039: 356 s = "SiS 85c601"; 357 break; 358 case 0x55911039: 359 s = "SiS 5591 host to PCI bridge"; 360 break; 361 case 0x00011039: 362 s = "SiS 5591 host to AGP bridge"; 363 break; 364 365 /* VLSI -- vendor 0x1004 */ 366 case 0x00051004: 367 s = "VLSI 82C592 Host to PCI bridge"; 368 break; 369 370 /* XXX Here is MVP3, I got the datasheet but NO M/B to test it */ 371 /* totally. Please let me know if anything wrong. -F */ 372 /* XXX need info on the MVP3 -- any takers? */ 373 case 0x05981106: 374 s = "VIA 82C598MVP (Apollo MVP3) host bridge"; 375 break; 376 377 /* AcerLabs -- vendor 0x10b9 */ 378 /* Funny : The datasheet told me vendor id is "10b8",sub-vendor */ 379 /* id is '10b9" but the register always shows "10b9". -Foxfair */ 380 case 0x154110b9: 381 s = "AcerLabs M1541 (Aladdin-V) PCI host bridge"; 382 break; 383 384 /* OPTi -- vendor 0x1045 */ 385 case 0xc8221045: 386 s = "OPTi 82C822 host to PCI Bridge"; 387 break; 388 389 /* Ross (?) -- vendor 0x1166 */ 390 case 0x00051166: 391 s = "Ross (?) host to PCI bridge"; 392 /* just guessing the secondary bus register number ... */ 393 *busnum = pci_cfgread(cfg, 0x45, 1); 394 break; 395 396 /* Integrated Micro Solutions -- vendor 0x10e0 */ 397 case 0x884910e0: 398 s = "Integrated Micro Solutions VL Bridge"; 399 break; 400 401 default: 402 if (class == PCIC_BRIDGE && subclass == PCIS_BRIDGE_HOST) 403 s = "Host to PCI bridge"; 404 break; 405 } 406 407 return s; 408 } 409 410 /* 411 * Scan the first pci bus for host-pci bridges and add pcib instances 412 * to the nexus for each bridge. 413 */ 414 static void 415 nexus_pcib_identify(driver_t *driver, device_t parent) 416 { 417 pcicfgregs probe; 418 419 if (pci_cfgopen() == 0) 420 return; 421 probe.hose = 0; 422 probe.bus = 0; 423 for (probe.slot = 0; probe.slot <= PCI_SLOTMAX; probe.slot++) { 424 int pcifunchigh = 0; 425 for (probe.func = 0; 426 probe.func <= pcifunchigh; 427 probe.func++) { 428 /* 429 * Read the IDs and class from the device. 430 */ 431 u_int32_t id; 432 u_int8_t class, subclass, busnum; 433 device_t child; 434 const char *s; 435 436 id = pci_cfgread(&probe, PCIR_DEVVENDOR, 4); 437 if (id == -1) 438 continue; 439 class = pci_cfgread(&probe, PCIR_CLASS, 1); 440 subclass = pci_cfgread(&probe, PCIR_SUBCLASS, 1); 441 442 s = nexus_pcib_is_host_bridge(&probe, id, 443 class, subclass, 444 &busnum); 445 if (s) { 446 /* 447 * Add at priority 100 to make sure we 448 * go after any motherboard resources 449 */ 450 child = BUS_ADD_CHILD(parent, 100, 451 "pcib", busnum); 452 device_set_desc(child, s); 453 } 454 } 455 } 456 } 457 458 static int 459 nexus_pcib_probe(device_t dev) 460 { 461 if (pci_cfgopen() != 0) { 462 device_add_child(dev, "pci", device_get_unit(dev), 0); 463 return 0; 464 } 465 return ENXIO; 466 } 467 468 static device_method_t nexus_pcib_methods[] = { 469 /* Device interface */ 470 DEVMETHOD(device_identify, nexus_pcib_identify), 471 DEVMETHOD(device_probe, nexus_pcib_probe), 472 DEVMETHOD(device_attach, bus_generic_attach), 473 DEVMETHOD(device_shutdown, bus_generic_shutdown), 474 DEVMETHOD(device_suspend, bus_generic_suspend), 475 DEVMETHOD(device_resume, bus_generic_resume), 476 477 /* Bus interface */ 478 DEVMETHOD(bus_print_child, bus_generic_print_child), 479 DEVMETHOD(bus_alloc_resource, bus_generic_alloc_resource), 480 DEVMETHOD(bus_release_resource, bus_generic_release_resource), 481 DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), 482 DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), 483 DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), 484 DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), 485 486 { 0, 0 } 487 }; 488 489 static driver_t nexus_pcib_driver = { 490 "pcib", 491 nexus_pcib_methods, 492 1, 493 }; 494 495 DRIVER_MODULE(pcib, nexus, nexus_pcib_driver, pcib_devclass, 0, 0); 496