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