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