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