1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #include <sys/fm/protocol.h> 28 #include <assert.h> 29 #include <stdio.h> 30 #include <stdlib.h> 31 #include <string.h> 32 #include <strings.h> 33 #include <alloca.h> 34 #include <sys/param.h> 35 #include <sys/pci.h> 36 #include <sys/pcie.h> 37 #include <libdevinfo.h> 38 #include <libnvpair.h> 39 #include <fm/topo_mod.h> 40 #include <fm/topo_hc.h> 41 42 #include <hostbridge.h> 43 #include <pcibus.h> 44 #include <did.h> 45 #include <did_props.h> 46 #include <util.h> 47 48 extern txprop_t Bus_common_props[]; 49 extern txprop_t Dev_common_props[]; 50 extern txprop_t Fn_common_props[]; 51 extern int Bus_propcnt; 52 extern int Dev_propcnt; 53 extern int Fn_propcnt; 54 55 extern int platform_pci_label(topo_mod_t *mod, tnode_t *, nvlist_t *, 56 nvlist_t **); 57 extern int platform_pci_fru(topo_mod_t *mod, tnode_t *, nvlist_t *, 58 nvlist_t **); 59 static void pci_release(topo_mod_t *, tnode_t *); 60 static int pci_enum(topo_mod_t *, tnode_t *, const char *, topo_instance_t, 61 topo_instance_t, void *, void *); 62 static int pci_label(topo_mod_t *, tnode_t *, topo_version_t, nvlist_t *, 63 nvlist_t **); 64 static int pci_fru(topo_mod_t *, tnode_t *, topo_version_t, nvlist_t *, 65 nvlist_t **); 66 67 static const topo_modops_t Pci_ops = 68 { pci_enum, pci_release }; 69 static const topo_modinfo_t Pci_info = 70 { PCI_BUS, FM_FMRI_SCHEME_HC, PCI_ENUMR_VERS, &Pci_ops }; 71 72 static const topo_method_t Pci_methods[] = { 73 { TOPO_METH_LABEL, TOPO_METH_LABEL_DESC, 74 TOPO_METH_LABEL_VERSION, TOPO_STABILITY_INTERNAL, pci_label }, 75 { TOPO_METH_FRU_COMPUTE, TOPO_METH_FRU_COMPUTE_DESC, 76 TOPO_METH_FRU_COMPUTE_VERSION, TOPO_STABILITY_INTERNAL, pci_fru }, 77 { NULL } 78 }; 79 80 int 81 _topo_init(topo_mod_t *modhdl, topo_version_t version) 82 { 83 /* 84 * Turn on module debugging output 85 */ 86 if (getenv("TOPOPCIDBG") != NULL) 87 topo_mod_setdebug(modhdl); 88 topo_mod_dprintf(modhdl, "initializing pcibus builtin\n"); 89 90 if (version != PCI_ENUMR_VERS) 91 return (topo_mod_seterrno(modhdl, EMOD_VER_NEW)); 92 93 topo_mod_register(modhdl, &Pci_info, TOPO_VERSION); 94 topo_mod_dprintf(modhdl, "PCI Enumr initd\n"); 95 96 return (0); 97 } 98 99 void 100 _topo_fini(topo_mod_t *modhdl) 101 { 102 topo_mod_unregister(modhdl); 103 } 104 105 static int 106 pci_label(topo_mod_t *mp, tnode_t *node, topo_version_t version, 107 nvlist_t *in, nvlist_t **out) 108 { 109 if (version > TOPO_METH_LABEL_VERSION) 110 return (topo_mod_seterrno(mp, EMOD_VER_NEW)); 111 return (platform_pci_label(mp, node, in, out)); 112 } 113 static int 114 pci_fru(topo_mod_t *mp, tnode_t *node, topo_version_t version, 115 nvlist_t *in, nvlist_t **out) 116 { 117 if (version > TOPO_METH_FRU_COMPUTE_VERSION) 118 return (topo_mod_seterrno(mp, EMOD_VER_NEW)); 119 return (platform_pci_fru(mp, node, in, out)); 120 } 121 static tnode_t * 122 pci_tnode_create(topo_mod_t *mod, tnode_t *parent, 123 const char *name, topo_instance_t i, void *priv) 124 { 125 tnode_t *ntn; 126 127 if ((ntn = tnode_create(mod, parent, name, i, priv)) == NULL) 128 return (NULL); 129 if (topo_method_register(mod, ntn, Pci_methods) < 0) { 130 topo_mod_dprintf(mod, "topo_method_register failed: %s\n", 131 topo_strerror(topo_mod_errno(mod))); 132 topo_node_unbind(ntn); 133 return (NULL); 134 } 135 return (ntn); 136 } 137 138 /*ARGSUSED*/ 139 static int 140 hostbridge_asdevice(topo_mod_t *mod, tnode_t *bus) 141 { 142 di_node_t di; 143 tnode_t *dev32; 144 145 di = topo_node_getspecific(bus); 146 assert(di != DI_NODE_NIL); 147 148 if ((dev32 = pcidev_declare(mod, bus, di, 32)) == NULL) 149 return (-1); 150 if (pcifn_declare(mod, dev32, di, 0) == NULL) { 151 topo_node_unbind(dev32); 152 return (-1); 153 } 154 return (0); 155 } 156 157 tnode_t * 158 pciexfn_declare(topo_mod_t *mod, tnode_t *parent, di_node_t dn, 159 topo_instance_t i) 160 { 161 did_t *pd; 162 tnode_t *ntn, *ptn; 163 di_node_t pdn; 164 uint_t class, subclass; 165 char *devtyp, *pdevtyp; 166 int pcie_devtyp, pexcap; 167 boolean_t dev_is_pcie, pdev_is_pcie; 168 169 /* We need the parent's dev info node for some of the info */ 170 ptn = find_predecessor(parent, PCIEX_FUNCTION); 171 /* If this is the first child under root, get root's ptn */ 172 if (ptn == NULL) 173 ptn = find_predecessor(parent, PCIEX_ROOT); 174 if (ptn == NULL) 175 return (NULL); 176 pdn = topo_node_getspecific(ptn); 177 178 /* Get the required info to populate the excap */ 179 (void) pci_classcode_get(mod, dn, &class, &subclass); 180 devtyp = pci_devtype_get(mod, dn); 181 pdevtyp = pci_devtype_get(mod, pdn); 182 pexcap = pciex_cap_get(mod, pdn); 183 184 dev_is_pcie = devtyp && (strcmp(devtyp, "pciex") == 0); 185 pdev_is_pcie = pdevtyp && (strcmp(pdevtyp, "pciex") == 0); 186 187 /* 188 * Populate the excap with correct PCIe device type. 189 * 190 * Device Parent Device Parent Device 191 * excap device-type device-type excap Class Code 192 * ------------------------------------------------------------------- 193 * PCI(default) pci N/A N/A != bridge 194 * PCIe pciex N/A N/A != bridge 195 * Root Port Defined in hostbridge 196 * Switch Up pciex pciex != up = bridge 197 * Switch Down pciex pciex = up = bridge 198 * PCIe-PCI pciex pci N/A = bridge 199 * PCI-PCIe pci pciex N/A = bridge 200 */ 201 pcie_devtyp = PCIE_PCIECAP_DEV_TYPE_PCI_DEV; 202 if (class == PCI_CLASS_BRIDGE && subclass == PCI_BRIDGE_PCI) { 203 if (pdev_is_pcie) { 204 if (dev_is_pcie) { 205 if (pexcap != PCIE_PCIECAP_DEV_TYPE_UP) 206 pcie_devtyp = PCIE_PCIECAP_DEV_TYPE_UP; 207 else 208 pcie_devtyp = 209 PCIE_PCIECAP_DEV_TYPE_DOWN; 210 } else { 211 pcie_devtyp = PCIE_PCIECAP_DEV_TYPE_PCIE2PCI; 212 } 213 } else { 214 if (dev_is_pcie) 215 pcie_devtyp = PCIE_PCIECAP_DEV_TYPE_PCI2PCIE; 216 } 217 } else { 218 if (pdev_is_pcie) 219 pcie_devtyp = PCIE_PCIECAP_DEV_TYPE_PCIE_DEV; 220 } 221 222 if ((pd = did_find(mod, dn)) == NULL) 223 return (NULL); 224 did_excap_set(pd, pcie_devtyp); 225 226 if ((ntn = pci_tnode_create(mod, parent, PCIEX_FUNCTION, i, dn)) 227 == NULL) 228 return (NULL); 229 if (did_props_set(ntn, pd, Fn_common_props, Fn_propcnt) < 0) { 230 topo_node_unbind(ntn); 231 return (NULL); 232 } 233 /* 234 * We may find pci-express buses or plain-pci buses beneath a function 235 */ 236 if (child_range_add(mod, ntn, PCIEX_BUS, 0, MAX_HB_BUSES) < 0) { 237 topo_node_unbind(ntn); 238 return (NULL); 239 } 240 if (child_range_add(mod, ntn, PCI_BUS, 0, MAX_HB_BUSES) < 0) { 241 topo_node_range_destroy(ntn, PCIEX_BUS); 242 topo_node_unbind(ntn); 243 return (NULL); 244 } 245 return (ntn); 246 } 247 248 tnode_t * 249 pciexdev_declare(topo_mod_t *mod, tnode_t *parent, di_node_t dn, 250 topo_instance_t i) 251 { 252 did_t *pd; 253 tnode_t *ntn; 254 255 if ((pd = did_find(mod, dn)) == NULL) 256 return (NULL); 257 did_settnode(pd, parent); 258 259 if ((ntn = pci_tnode_create(mod, parent, PCIEX_DEVICE, i, dn)) == NULL) 260 return (NULL); 261 if (did_props_set(ntn, pd, Dev_common_props, Dev_propcnt) < 0) { 262 topo_node_unbind(ntn); 263 return (NULL); 264 } 265 266 /* 267 * We can expect to find pci-express functions beneath the device 268 */ 269 if (child_range_add(mod, 270 ntn, PCIEX_FUNCTION, 0, MAX_PCIDEV_FNS) < 0) { 271 topo_node_unbind(ntn); 272 return (NULL); 273 } 274 return (ntn); 275 } 276 277 tnode_t * 278 pciexbus_declare(topo_mod_t *mod, tnode_t *parent, di_node_t dn, 279 topo_instance_t i) 280 { 281 did_t *pd; 282 tnode_t *ntn; 283 284 if ((pd = did_find(mod, dn)) == NULL) 285 return (NULL); 286 did_settnode(pd, parent); 287 if ((ntn = pci_tnode_create(mod, parent, PCIEX_BUS, i, dn)) == NULL) 288 return (NULL); 289 if (did_props_set(ntn, pd, Bus_common_props, Bus_propcnt) < 0) { 290 topo_node_unbind(ntn); 291 return (NULL); 292 } 293 /* 294 * We can expect to find pci-express devices beneath the bus 295 */ 296 if (child_range_add(mod, 297 ntn, PCIEX_DEVICE, 0, MAX_PCIBUS_DEVS) < 0) { 298 topo_node_unbind(ntn); 299 return (NULL); 300 } 301 return (ntn); 302 } 303 304 tnode_t * 305 pcifn_declare(topo_mod_t *mod, tnode_t *parent, di_node_t dn, 306 topo_instance_t i) 307 { 308 did_t *pd; 309 tnode_t *ntn; 310 311 if ((pd = did_find(mod, dn)) == NULL) 312 return (NULL); 313 did_excap_set(pd, PCIE_PCIECAP_DEV_TYPE_PCI_DEV); 314 315 if ((ntn = pci_tnode_create(mod, parent, PCI_FUNCTION, i, dn)) == NULL) 316 return (NULL); 317 if (did_props_set(ntn, pd, Fn_common_props, Fn_propcnt) < 0) { 318 topo_node_unbind(ntn); 319 return (NULL); 320 } 321 /* 322 * We may find pci buses beneath a function 323 */ 324 if (child_range_add(mod, ntn, PCI_BUS, 0, MAX_HB_BUSES) < 0) { 325 topo_node_unbind(ntn); 326 return (NULL); 327 } 328 return (ntn); 329 } 330 331 tnode_t * 332 pcidev_declare(topo_mod_t *mod, tnode_t *parent, di_node_t dn, 333 topo_instance_t i) 334 { 335 did_t *pd; 336 tnode_t *ntn; 337 338 if ((pd = did_find(mod, dn)) == NULL) 339 return (NULL); 340 /* remember parent tnode */ 341 did_settnode(pd, parent); 342 343 if ((ntn = pci_tnode_create(mod, parent, PCI_DEVICE, i, dn)) == NULL) 344 return (NULL); 345 if (did_props_set(ntn, pd, Dev_common_props, Dev_propcnt) < 0) { 346 topo_node_unbind(ntn); 347 return (NULL); 348 } 349 350 /* 351 * We can expect to find pci functions beneath the device 352 */ 353 if (child_range_add(mod, ntn, PCI_FUNCTION, 0, MAX_PCIDEV_FNS) < 0) { 354 topo_node_unbind(ntn); 355 return (NULL); 356 } 357 return (ntn); 358 } 359 360 tnode_t * 361 pcibus_declare(topo_mod_t *mod, tnode_t *parent, di_node_t dn, 362 topo_instance_t i) 363 { 364 did_t *pd; 365 tnode_t *ntn; 366 int hbchild = 0; 367 368 if ((pd = did_find(mod, dn)) == NULL) 369 return (NULL); 370 did_settnode(pd, parent); 371 if ((ntn = pci_tnode_create(mod, parent, PCI_BUS, i, dn)) == NULL) 372 return (NULL); 373 /* 374 * If our devinfo node is lacking certain information of its 375 * own, and our parent topology node is a hostbridge, we may 376 * need/want to inherit information available in the 377 * hostbridge node's private data. 378 */ 379 if (strcmp(topo_node_name(parent), HOSTBRIDGE) == 0) 380 hbchild = 1; 381 if (did_props_set(ntn, pd, Bus_common_props, Bus_propcnt) < 0) { 382 topo_node_unbind(ntn); 383 return (NULL); 384 } 385 /* 386 * We can expect to find pci devices beneath the bus 387 */ 388 if (child_range_add(mod, ntn, PCI_DEVICE, 0, MAX_PCIBUS_DEVS) < 0) { 389 topo_node_unbind(ntn); 390 return (NULL); 391 } 392 /* 393 * On each bus child of the hostbridge, we represent the 394 * hostbridge as a device outside the range of legal device 395 * numbers. 396 */ 397 if (hbchild == 1) { 398 if (hostbridge_asdevice(mod, ntn) < 0) { 399 topo_node_range_destroy(ntn, PCI_DEVICE); 400 topo_node_unbind(ntn); 401 return (NULL); 402 } 403 } 404 return (ntn); 405 } 406 407 static int 408 pci_bridge_declare(topo_mod_t *mod, tnode_t *fn, di_node_t din, int board, 409 int bridge, int rc, int depth) 410 { 411 int err; 412 char *devtyp; 413 414 devtyp = pci_devtype_get(mod, din); 415 /* Check if the children are PCI or PCIe */ 416 if (strcmp(devtyp, "pciex") == 0) 417 err = pci_children_instantiate(mod, fn, din, board, bridge, 418 rc, TRUST_BDF, depth + 1); 419 else 420 err = pci_children_instantiate(mod, fn, din, board, bridge, 421 rc - TO_PCI, TRUST_BDF, depth + 1); 422 return (err); 423 } 424 425 static void 426 declare_dev_and_fn(topo_mod_t *mod, tnode_t *bus, tnode_t **dev, di_node_t din, 427 int board, int bridge, int rc, int devno, int fnno, int depth) 428 { 429 int dcnt = 0; 430 tnode_t *fn; 431 uint_t class, subclass; 432 uint_t vid, did; 433 did_t *dp = NULL; 434 435 if (*dev == NULL) { 436 if (rc >= 0) 437 *dev = pciexdev_declare(mod, bus, din, devno); 438 else 439 *dev = pcidev_declare(mod, bus, din, devno); 440 if (*dev == NULL) 441 return; 442 ++dcnt; 443 } 444 if (rc >= 0) 445 fn = pciexfn_declare(mod, *dev, din, fnno); 446 else 447 fn = pcifn_declare(mod, *dev, din, fnno); 448 449 if (fn == NULL) { 450 if (dcnt) { 451 topo_node_unbind(*dev); 452 *dev = NULL; 453 } 454 return; 455 } 456 457 if (pci_classcode_get(mod, din, &class, &subclass) < 0) { 458 topo_node_unbind(fn); 459 if (dcnt) 460 topo_node_unbind(*dev); 461 return; 462 } 463 464 /* 465 * This function may be a bridge. If not, check for a possible 466 * topology map file and kick off its enumeration of lower-level 467 * devices. 468 */ 469 if (class == PCI_CLASS_BRIDGE && subclass == PCI_BRIDGE_PCI) { 470 (void) pci_bridge_declare(mod, fn, din, board, bridge, rc, 471 depth); 472 } 473 474 /* 475 * Check for a Neptune-based NIC. This could either be a Neptune 476 * adapter card or an Neptune ASIC on a board (e.g. motherboard) 477 * 478 * For Netpune adapter cards, use xfp-hc-topology.xml to expand 479 * topology to include the XFP optical module, which is a FRU on 480 * the Neptune based 10giga fiber NICs. 481 * 482 * For Neptune ASICs, use the XAUI enumerator to expand topology. 483 * The 10giga ports are externalized by a XAUI cards, which 484 * are FRUs. The XAUI enumerator in turn instantiates the XFP 485 * optical module FRUs. 486 */ 487 else if (class == PCI_CLASS_NET && 488 di_uintprop_get(mod, din, DI_VENDIDPROP, &vid) >= 0 && 489 di_uintprop_get(mod, din, DI_DEVIDPROP, &did) >= 0) { 490 if (vid == SUN_VENDOR_ID && did == NEPTUNE_DEVICE_ID) { 491 /* 492 * Is this an adapter card? Check the bus's physlot 493 */ 494 dp = did_find(mod, topo_node_getspecific(bus)); 495 if (did_physlot(dp) >= 0) { 496 topo_mod_dprintf(mod, "Found Neptune slot\n"); 497 (void) topo_mod_enummap(mod, fn, 498 "xfp", FM_FMRI_SCHEME_HC); 499 } else { 500 topo_mod_dprintf(mod, "Found Neptune ASIC\n"); 501 if (topo_mod_load(mod, XAUI, TOPO_VERSION) == 502 NULL) { 503 topo_mod_dprintf(mod, "pcibus enum " 504 "could not load xaui enum\n"); 505 topo_mod_seterrno(mod, 506 EMOD_PARTIAL_ENUM); 507 return; 508 } else { 509 if (topo_node_range_create(mod, fn, 510 XAUI, 0, 1) < 0) { 511 topo_mod_dprintf(mod, 512 "child_range_add for " 513 "XAUI failed: %s\n", 514 topo_strerror( 515 topo_mod_errno(mod))); 516 return; 517 } 518 (void) topo_mod_enumerate(mod, fn, 519 XAUI, XAUI, fnno, fnno, fn); 520 } 521 } 522 } 523 } 524 } 525 526 int 527 pci_children_instantiate(topo_mod_t *mod, tnode_t *parent, di_node_t pn, 528 int board, int bridge, int rc, int bover, int depth) 529 { 530 did_t *pps[MAX_PCIBUS_DEVS][MAX_PCIDEV_FNS]; 531 did_t *bp = NULL; 532 did_t *np; 533 di_node_t sib; 534 di_node_t din; 535 tnode_t *bn = NULL; 536 tnode_t *dn = NULL; 537 int pb = -1; 538 int b, d, f; 539 540 for (d = 0; d < MAX_PCIBUS_DEVS; d++) 541 for (f = 0; f < MAX_PCIDEV_FNS; f++) 542 pps[d][f] = NULL; 543 544 /* start at the parent's first sibling */ 545 sib = di_child_node(pn); 546 while (sib != DI_NODE_NIL) { 547 np = did_create(mod, sib, board, bridge, rc, bover); 548 if (np == NULL) 549 return (-1); 550 did_BDF(np, &b, &d, &f); 551 pps[d][f] = np; 552 if (bp == NULL) 553 bp = np; 554 if (pb < 0) 555 pb = ((bover == TRUST_BDF) ? b : bover); 556 sib = di_sibling_node(sib); 557 } 558 if (pb < 0 && bover < 0) 559 return (0); 560 if (rc >= 0) 561 bn = pciexbus_declare(mod, parent, pn, ((pb < 0) ? bover : pb)); 562 else 563 bn = pcibus_declare(mod, parent, pn, ((pb < 0) ? bover : pb)); 564 if (bn == NULL) 565 return (-1); 566 if (pb < 0) 567 return (0); 568 569 for (d = 0; d < MAX_PCIBUS_DEVS; d++) { 570 for (f = 0; f < MAX_PCIDEV_FNS; f++) { 571 if (pps[d][f] == NULL) 572 continue; 573 din = did_dinode(pps[d][f]); 574 575 /* 576 * Try to enumerate as many devices and functions as 577 * possible. If we fail to declare a device, break 578 * out of the function loop. 579 */ 580 declare_dev_and_fn(mod, bn, 581 &dn, din, board, bridge, rc, d, f, depth); 582 did_rele(pps[d][f]); 583 584 if (dn == NULL) 585 break; 586 } 587 dn = NULL; 588 } 589 return (0); 590 } 591 592 static int 593 pciexbus_enum(topo_mod_t *mp, tnode_t *ptn, char *pnm, topo_instance_t min, 594 topo_instance_t max) 595 { 596 di_node_t pdn; 597 int rc; 598 int retval; 599 600 /* 601 * PCI-Express; root complex shares the hostbridge's instance 602 * number. Parent node's private data is a simple di_node_t 603 * and we have to construct our own did hash and did_t. 604 */ 605 rc = topo_node_instance(ptn); 606 607 if ((pdn = topo_node_getspecific(ptn)) == DI_NODE_NIL) { 608 topo_mod_dprintf(mp, 609 "Parent %s node missing private data.\n" 610 "Unable to proceed with %s enumeration.\n", pnm, PCIEX_BUS); 611 return (0); 612 } 613 if (did_hash_init(mp) != 0) 614 return (-1); 615 if ((did_create(mp, pdn, 0, 0, rc, TRUST_BDF)) == NULL) 616 return (-1); /* errno already set */ 617 618 retval = pci_children_instantiate(mp, ptn, pdn, 0, 0, rc, 619 (min == max) ? min : TRUST_BDF, 0); 620 did_hash_fini(mp); 621 622 return (retval); 623 } 624 625 static int 626 pcibus_enum(topo_mod_t *mp, tnode_t *ptn, char *pnm, topo_instance_t min, 627 topo_instance_t max, void *data) 628 { 629 did_t *didp, *hbdid = (did_t *)data; 630 int retval; 631 632 /* 633 * XXTOPO: we should not be sharing private node data with another 634 * module. PCI Bus; Parent node's private data is a did_t. We'll 635 * use the did hash established by the parent. 636 */ 637 did_setspecific(mp, data); 638 639 /* 640 * If we're looking for a specific bus-instance, find the right 641 * did_t in the chain, otherwise, there should be only one did_t. 642 */ 643 if (min == max) { 644 int b; 645 didp = hbdid; 646 while (didp != NULL) { 647 did_BDF(didp, &b, NULL, NULL); 648 if (b == min) 649 break; 650 didp = did_link_get(didp); 651 } 652 if (didp == NULL) { 653 topo_mod_dprintf(mp, 654 "Parent %s node missing private data related\n" 655 "to %s instance %d.\n", pnm, PCI_BUS, min); 656 topo_mod_setspecific(mp, NULL); 657 return (0); 658 } 659 } else { 660 assert(did_link_get(hbdid) == NULL); 661 didp = hbdid; 662 } 663 retval = pci_children_instantiate(mp, ptn, did_dinode(didp), 664 did_board(didp), did_bridge(didp), did_rc(didp), 665 (min == max) ? min : TRUST_BDF, 0); 666 667 topo_mod_setspecific(mp, NULL); 668 669 return (retval); 670 } 671 672 /*ARGSUSED*/ 673 static int 674 pci_enum(topo_mod_t *mod, tnode_t *ptn, const char *name, 675 topo_instance_t min, topo_instance_t max, void *notused, void *data) 676 { 677 int retval; 678 char *pname; 679 680 topo_mod_dprintf(mod, "Enumerating pci!\n"); 681 682 if (strcmp(name, PCI_BUS) != 0 && strcmp(name, PCIEX_BUS) != 0) { 683 topo_mod_dprintf(mod, 684 "Currently only know how to enumerate %s or %s.\n", 685 PCI_BUS, PCIEX_BUS); 686 return (0); 687 } 688 pname = topo_node_name(ptn); 689 if (strcmp(pname, HOSTBRIDGE) != 0 && strcmp(pname, PCIEX_ROOT) != 0) { 690 topo_mod_dprintf(mod, 691 "Currently can only enumerate a %s or %s directly\n", 692 PCI_BUS, PCIEX_BUS); 693 topo_mod_dprintf(mod, 694 "descended from a %s or %s node.\n", 695 HOSTBRIDGE, PCIEX_ROOT); 696 return (0); 697 } 698 699 if (strcmp(name, PCI_BUS) == 0) { 700 retval = pcibus_enum(mod, ptn, pname, min, max, data); 701 } else if (strcmp(name, PCIEX_BUS) == 0) { 702 retval = pciexbus_enum(mod, ptn, pname, min, max); 703 } else { 704 topo_mod_dprintf(mod, 705 "Currently only know how to enumerate %s or %s not %s.\n", 706 PCI_BUS, PCIEX_BUS, name); 707 return (0); 708 } 709 710 return (retval); 711 } 712 713 /*ARGSUSED*/ 714 static void 715 pci_release(topo_mod_t *mp, tnode_t *node) 716 { 717 topo_method_unregister_all(mp, node); 718 719 /* 720 * node private data (did_t) for this node is destroyed in 721 * did_hash_destroy() 722 */ 723 724 topo_node_unbind(node); 725 } 726