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 2020 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 <fcntl.h> 35 #include <unistd.h> 36 #include <sys/param.h> 37 #include <sys/pci.h> 38 #include <sys/pcie.h> 39 #include <libdevinfo.h> 40 #include <libnvpair.h> 41 #include <fm/topo_mod.h> 42 #include <fm/topo_hc.h> 43 #include <sys/ddi_ufm.h> 44 #include <sys/stat.h> 45 #include <sys/types.h> 46 47 #include <hostbridge.h> 48 #include <pcibus.h> 49 #include <did.h> 50 #include <did_props.h> 51 #include <util.h> 52 #include <topo_nic.h> 53 #include <topo_usb.h> 54 55 extern txprop_t Bus_common_props[]; 56 extern txprop_t Dev_common_props[]; 57 extern txprop_t Fn_common_props[]; 58 extern int Bus_propcnt; 59 extern int Dev_propcnt; 60 extern int Fn_propcnt; 61 62 extern int platform_pci_label(topo_mod_t *mod, tnode_t *, nvlist_t *, 63 nvlist_t **); 64 extern int platform_pci_fru(topo_mod_t *mod, tnode_t *, nvlist_t *, 65 nvlist_t **); 66 static void pci_release(topo_mod_t *, tnode_t *); 67 static int pci_enum(topo_mod_t *, tnode_t *, const char *, topo_instance_t, 68 topo_instance_t, void *, void *); 69 static int pci_label(topo_mod_t *, tnode_t *, topo_version_t, nvlist_t *, 70 nvlist_t **); 71 static int pci_fru(topo_mod_t *, tnode_t *, topo_version_t, nvlist_t *, 72 nvlist_t **); 73 74 static const topo_modops_t Pci_ops = 75 { pci_enum, pci_release }; 76 static const topo_modinfo_t Pci_info = 77 { PCI_BUS, FM_FMRI_SCHEME_HC, PCI_ENUMR_VERS, &Pci_ops }; 78 79 static const topo_method_t Pci_methods[] = { 80 { TOPO_METH_LABEL, TOPO_METH_LABEL_DESC, 81 TOPO_METH_LABEL_VERSION, TOPO_STABILITY_INTERNAL, pci_label }, 82 { TOPO_METH_FRU_COMPUTE, TOPO_METH_FRU_COMPUTE_DESC, 83 TOPO_METH_FRU_COMPUTE_VERSION, TOPO_STABILITY_INTERNAL, pci_fru }, 84 { NULL } 85 }; 86 87 int 88 _topo_init(topo_mod_t *modhdl, topo_version_t version) 89 { 90 /* 91 * Turn on module debugging output 92 */ 93 if (getenv("TOPOPCIDBG") != NULL) 94 topo_mod_setdebug(modhdl); 95 topo_mod_dprintf(modhdl, "initializing pcibus builtin\n"); 96 97 if (version != PCI_ENUMR_VERS) 98 return (topo_mod_seterrno(modhdl, EMOD_VER_NEW)); 99 100 if (topo_mod_register(modhdl, &Pci_info, TOPO_VERSION) != 0) { 101 topo_mod_dprintf(modhdl, "failed to register module"); 102 return (-1); 103 } 104 topo_mod_dprintf(modhdl, "PCI Enumr initd\n"); 105 106 return (0); 107 } 108 109 void 110 _topo_fini(topo_mod_t *modhdl) 111 { 112 topo_mod_unregister(modhdl); 113 } 114 115 static int 116 pci_label(topo_mod_t *mp, tnode_t *node, topo_version_t version, 117 nvlist_t *in, nvlist_t **out) 118 { 119 if (version > TOPO_METH_LABEL_VERSION) 120 return (topo_mod_seterrno(mp, EMOD_VER_NEW)); 121 return (platform_pci_label(mp, node, in, out)); 122 } 123 static int 124 pci_fru(topo_mod_t *mp, tnode_t *node, topo_version_t version, 125 nvlist_t *in, nvlist_t **out) 126 { 127 if (version > TOPO_METH_FRU_COMPUTE_VERSION) 128 return (topo_mod_seterrno(mp, EMOD_VER_NEW)); 129 return (platform_pci_fru(mp, node, in, out)); 130 } 131 static tnode_t * 132 pci_tnode_create(topo_mod_t *mod, tnode_t *parent, 133 const char *name, topo_instance_t i, void *priv) 134 { 135 tnode_t *ntn; 136 137 if ((ntn = tnode_create(mod, parent, name, i, priv)) == NULL) 138 return (NULL); 139 if (topo_method_register(mod, ntn, Pci_methods) < 0) { 140 topo_mod_dprintf(mod, "topo_method_register failed: %s\n", 141 topo_strerror(topo_mod_errno(mod))); 142 topo_node_unbind(ntn); 143 return (NULL); 144 } 145 return (ntn); 146 } 147 148 /*ARGSUSED*/ 149 static int 150 hostbridge_asdevice(topo_mod_t *mod, tnode_t *bus) 151 { 152 di_node_t di; 153 tnode_t *dev32; 154 155 di = topo_node_getspecific(bus); 156 assert(di != DI_NODE_NIL); 157 158 if ((dev32 = pcidev_declare(mod, bus, di, 32)) == NULL) 159 return (-1); 160 if (pcifn_declare(mod, dev32, di, 0) == NULL) { 161 topo_node_unbind(dev32); 162 return (-1); 163 } 164 return (0); 165 } 166 167 static int 168 pciexfn_add_ufm(topo_mod_t *mod, tnode_t *node) 169 { 170 char *devpath = NULL; 171 ufm_ioc_getcaps_t ugc = { 0 }; 172 ufm_ioc_bufsz_t ufbz = { 0 }; 173 ufm_ioc_report_t ufmr = { 0 }; 174 nvlist_t *ufminfo = NULL, **images; 175 uint_t nimages; 176 int err, fd, ret = -1; 177 178 if (topo_prop_get_string(node, TOPO_PGROUP_IO, TOPO_IO_DEV, &devpath, 179 &err) != 0) { 180 return (topo_mod_seterrno(mod, EMOD_UNKNOWN)); 181 } 182 if (strlen(devpath) >= MAXPATHLEN) { 183 topo_mod_dprintf(mod, "devpath is too long: %s", devpath); 184 topo_mod_strfree(mod, devpath); 185 return (topo_mod_seterrno(mod, EMOD_UNKNOWN)); 186 } 187 188 if ((fd = open(DDI_UFM_DEV, O_RDONLY)) < 0) { 189 topo_mod_dprintf(mod, "%s: failed to open %s", __func__, 190 DDI_UFM_DEV); 191 topo_mod_strfree(mod, devpath); 192 return (0); 193 } 194 /* 195 * Make an ioctl to probe if the driver for this function is 196 * UFM-capable. If the ioctl fails or if it doesn't advertise the 197 * DDI_UFM_CAP_REPORT capability, we bail out. 198 */ 199 ugc.ufmg_version = DDI_UFM_CURRENT_VERSION; 200 (void) strlcpy(ugc.ufmg_devpath, devpath, MAXPATHLEN); 201 if (ioctl(fd, UFM_IOC_GETCAPS, &ugc) < 0) { 202 topo_mod_dprintf(mod, "UFM_IOC_GETCAPS failed: %s", 203 strerror(errno)); 204 (void) close(fd); 205 topo_mod_strfree(mod, devpath); 206 return (0); 207 } 208 if ((ugc.ufmg_caps & DDI_UFM_CAP_REPORT) == 0) { 209 topo_mod_dprintf(mod, "driver doesn't advertise " 210 "DDI_UFM_CAP_REPORT"); 211 (void) close(fd); 212 topo_mod_strfree(mod, devpath); 213 return (0); 214 } 215 216 /* 217 * If we made it this far, then the driver is indeed UFM-capable and 218 * is capable of reporting its firmware information. First step is to 219 * make an ioctl to query the size of the report data so that we can 220 * allocate a buffer large enough to hold it. 221 */ 222 ufbz.ufbz_version = DDI_UFM_CURRENT_VERSION; 223 (void) strlcpy(ufbz.ufbz_devpath, devpath, MAXPATHLEN); 224 if (ioctl(fd, UFM_IOC_REPORTSZ, &ufbz) < 0) { 225 topo_mod_dprintf(mod, "UFM_IOC_REPORTSZ failed: %s\n", 226 strerror(errno)); 227 (void) close(fd); 228 topo_mod_strfree(mod, devpath); 229 return (0); 230 } 231 232 ufmr.ufmr_version = DDI_UFM_CURRENT_VERSION; 233 if ((ufmr.ufmr_buf = topo_mod_alloc(mod, ufbz.ufbz_size)) == NULL) { 234 topo_mod_dprintf(mod, "failed to alloc %u bytes\n", 235 ufbz.ufbz_size); 236 (void) close(fd); 237 topo_mod_strfree(mod, devpath); 238 return (topo_mod_seterrno(mod, EMOD_NOMEM)); 239 } 240 ufmr.ufmr_bufsz = ufbz.ufbz_size; 241 (void) strlcpy(ufmr.ufmr_devpath, devpath, MAXPATHLEN); 242 topo_mod_strfree(mod, devpath); 243 244 /* 245 * Now, make the ioctl to retrieve the actual report data. The data 246 * is stored as a packed nvlist. 247 */ 248 if (ioctl(fd, UFM_IOC_REPORT, &ufmr) < 0) { 249 topo_mod_dprintf(mod, "UFM_IOC_REPORT failed: %s\n", 250 strerror(errno)); 251 topo_mod_free(mod, ufmr.ufmr_buf, ufmr.ufmr_bufsz); 252 (void) close(fd); 253 return (topo_mod_seterrno(mod, EMOD_UNKNOWN)); 254 } 255 (void) close(fd); 256 257 if (nvlist_unpack(ufmr.ufmr_buf, ufmr.ufmr_bufsz, &ufminfo, 258 NV_ENCODE_NATIVE) != 0) { 259 topo_mod_dprintf(mod, "failed to unpack nvlist\n"); 260 topo_mod_free(mod, ufmr.ufmr_buf, ufmr.ufmr_bufsz); 261 return (topo_mod_seterrno(mod, EMOD_UNKNOWN)); 262 } 263 topo_mod_free(mod, ufmr.ufmr_buf, ufmr.ufmr_bufsz); 264 265 if (nvlist_lookup_nvlist_array(ufminfo, DDI_UFM_NV_IMAGES, &images, 266 &nimages) != 0) { 267 topo_mod_dprintf(mod, "failed to lookup %s nvpair", 268 DDI_UFM_NV_IMAGES); 269 (void) topo_mod_seterrno(mod, EMOD_UNKNOWN); 270 goto err; 271 } 272 if (topo_node_range_create(mod, node, UFM, 0, (nimages - 1)) != 0) { 273 topo_mod_dprintf(mod, "failed to create %s range", UFM); 274 /* errno set */ 275 goto err; 276 } 277 for (uint_t i = 0; i < nimages; i++) { 278 tnode_t *ufmnode = NULL; 279 char *descr; 280 uint_t nslots; 281 nvlist_t **slots; 282 283 if (nvlist_lookup_string(images[i], DDI_UFM_NV_IMAGE_DESC, 284 &descr) != 0 || 285 nvlist_lookup_nvlist_array(images[i], 286 DDI_UFM_NV_IMAGE_SLOTS, &slots, &nslots) != 0) { 287 (void) topo_mod_seterrno(mod, EMOD_UNKNOWN); 288 goto err; 289 } 290 if ((ufmnode = topo_mod_create_ufm(mod, node, descr, NULL)) == 291 NULL) { 292 topo_mod_dprintf(mod, "failed to create ufm nodes for " 293 "%s", descr); 294 /* errno set */ 295 goto err; 296 } 297 for (uint_t s = 0; s < nslots; s++) { 298 topo_ufm_slot_info_t slotinfo = { 0 }; 299 uint32_t slotattrs; 300 301 if (nvlist_lookup_string(slots[s], 302 DDI_UFM_NV_SLOT_VERSION, 303 (char **)&slotinfo.usi_version) != 0 || 304 nvlist_lookup_uint32(slots[s], 305 DDI_UFM_NV_SLOT_ATTR, &slotattrs) != 0) { 306 topo_node_unbind(ufmnode); 307 topo_mod_dprintf(mod, "malformed slot nvlist"); 308 (void) topo_mod_seterrno(mod, EMOD_UNKNOWN); 309 goto err; 310 } 311 (void) nvlist_lookup_nvlist(slots[s], 312 DDI_UFM_NV_SLOT_MISC, &slotinfo.usi_extra); 313 314 if (slotattrs & DDI_UFM_ATTR_READABLE && 315 slotattrs & DDI_UFM_ATTR_WRITEABLE) 316 slotinfo.usi_mode = TOPO_UFM_SLOT_MODE_RW; 317 else if (slotattrs & DDI_UFM_ATTR_READABLE) 318 slotinfo.usi_mode = TOPO_UFM_SLOT_MODE_RO; 319 else if (slotattrs & DDI_UFM_ATTR_WRITEABLE) 320 slotinfo.usi_mode = TOPO_UFM_SLOT_MODE_WO; 321 else 322 slotinfo.usi_mode = TOPO_UFM_SLOT_MODE_NONE; 323 324 if (slotattrs & DDI_UFM_ATTR_ACTIVE) 325 slotinfo.usi_active = B_TRUE; 326 327 if (topo_node_range_create(mod, ufmnode, SLOT, 0, 328 (nslots - 1)) < 0) { 329 topo_mod_dprintf(mod, "failed to create %s " 330 "range", SLOT); 331 /* errno set */ 332 goto err; 333 } 334 if (topo_mod_create_ufm_slot(mod, ufmnode, 335 &slotinfo) == NULL) { 336 topo_node_unbind(ufmnode); 337 topo_mod_dprintf(mod, "failed to create ufm " 338 "slot %d for %s", s, descr); 339 /* errno set */ 340 goto err; 341 } 342 } 343 } 344 ret = 0; 345 err: 346 nvlist_free(ufminfo); 347 return (ret); 348 } 349 350 tnode_t * 351 pciexfn_declare(topo_mod_t *mod, tnode_t *parent, di_node_t dn, 352 topo_instance_t i) 353 { 354 did_t *pd; 355 tnode_t *ntn, *ptn; 356 di_node_t pdn; 357 uint_t class, subclass; 358 char *devtyp, *pdevtyp; 359 int pcie_devtyp, pexcap; 360 boolean_t dev_is_pcie, pdev_is_pcie; 361 362 /* We need the parent's dev info node for some of the info */ 363 ptn = find_predecessor(parent, PCIEX_FUNCTION); 364 /* If this is the first child under root, get root's ptn */ 365 if (ptn == NULL) 366 ptn = find_predecessor(parent, PCIEX_ROOT); 367 if (ptn == NULL) 368 return (NULL); 369 pdn = topo_node_getspecific(ptn); 370 371 /* Get the required info to populate the excap */ 372 (void) pci_classcode_get(mod, dn, &class, &subclass); 373 devtyp = pci_devtype_get(mod, dn); 374 pdevtyp = pci_devtype_get(mod, pdn); 375 pexcap = pciex_cap_get(mod, pdn); 376 377 dev_is_pcie = devtyp && (strcmp(devtyp, "pciex") == 0); 378 pdev_is_pcie = pdevtyp && (strcmp(pdevtyp, "pciex") == 0); 379 380 /* 381 * Populate the excap with correct PCIe device type. 382 * 383 * Device Parent Device Parent Device 384 * excap device-type device-type excap Class Code 385 * ------------------------------------------------------------------- 386 * PCI(default) pci N/A N/A != bridge 387 * PCIe pciex N/A N/A != bridge 388 * Root Port Defined in hostbridge 389 * Switch Up pciex pciex != up = bridge 390 * Switch Down pciex pciex = up = bridge 391 * PCIe-PCI pciex pci N/A = bridge 392 * PCI-PCIe pci pciex N/A = bridge 393 */ 394 pcie_devtyp = PCIE_PCIECAP_DEV_TYPE_PCI_DEV; 395 if (class == PCI_CLASS_BRIDGE && subclass == PCI_BRIDGE_PCI) { 396 if (pdev_is_pcie) { 397 if (dev_is_pcie) { 398 if (pexcap != PCIE_PCIECAP_DEV_TYPE_UP) 399 pcie_devtyp = PCIE_PCIECAP_DEV_TYPE_UP; 400 else 401 pcie_devtyp = 402 PCIE_PCIECAP_DEV_TYPE_DOWN; 403 } else { 404 pcie_devtyp = PCIE_PCIECAP_DEV_TYPE_PCIE2PCI; 405 } 406 } else { 407 if (dev_is_pcie) 408 pcie_devtyp = PCIE_PCIECAP_DEV_TYPE_PCI2PCIE; 409 } 410 } else { 411 if (pdev_is_pcie) 412 pcie_devtyp = PCIE_PCIECAP_DEV_TYPE_PCIE_DEV; 413 } 414 415 if ((pd = did_find(mod, dn)) == NULL) 416 return (NULL); 417 did_excap_set(pd, pcie_devtyp); 418 419 if ((ntn = pci_tnode_create(mod, parent, PCIEX_FUNCTION, i, dn)) 420 == NULL) 421 return (NULL); 422 if (did_props_set(ntn, pd, Fn_common_props, Fn_propcnt) < 0) { 423 topo_node_unbind(ntn); 424 return (NULL); 425 } 426 427 /* 428 * Check if the driver associated with this function exports firmware 429 * information via the DDI UFM subsystem and, if so, create the 430 * corresponding ufm topo nodes. 431 */ 432 if (pciexfn_add_ufm(mod, ntn) != 0) { 433 topo_node_unbind(ntn); 434 return (NULL); 435 } 436 437 /* 438 * We may find pci-express buses or plain-pci buses beneath a function 439 */ 440 if (child_range_add(mod, ntn, PCIEX_BUS, 0, MAX_HB_BUSES) < 0) { 441 topo_node_unbind(ntn); 442 return (NULL); 443 } 444 if (child_range_add(mod, ntn, PCI_BUS, 0, MAX_HB_BUSES) < 0) { 445 topo_node_range_destroy(ntn, PCIEX_BUS); 446 topo_node_unbind(ntn); 447 return (NULL); 448 } 449 return (ntn); 450 } 451 452 tnode_t * 453 pciexdev_declare(topo_mod_t *mod, tnode_t *parent, di_node_t dn, 454 topo_instance_t i) 455 { 456 did_t *pd; 457 tnode_t *ntn; 458 459 if ((pd = did_find(mod, dn)) == NULL) 460 return (NULL); 461 did_settnode(pd, parent); 462 463 if ((ntn = pci_tnode_create(mod, parent, PCIEX_DEVICE, i, dn)) == NULL) 464 return (NULL); 465 if (did_props_set(ntn, pd, Dev_common_props, Dev_propcnt) < 0) { 466 topo_node_unbind(ntn); 467 return (NULL); 468 } 469 470 /* 471 * We can expect to find pci-express functions beneath the device 472 */ 473 if (child_range_add(mod, 474 ntn, PCIEX_FUNCTION, 0, MAX_PCIDEV_FNS) < 0) { 475 topo_node_unbind(ntn); 476 return (NULL); 477 } 478 return (ntn); 479 } 480 481 tnode_t * 482 pciexbus_declare(topo_mod_t *mod, tnode_t *parent, di_node_t dn, 483 topo_instance_t i) 484 { 485 did_t *pd; 486 tnode_t *ntn; 487 488 if ((pd = did_find(mod, dn)) == NULL) 489 return (NULL); 490 did_settnode(pd, parent); 491 if ((ntn = pci_tnode_create(mod, parent, PCIEX_BUS, i, dn)) == NULL) 492 return (NULL); 493 if (did_props_set(ntn, pd, Bus_common_props, Bus_propcnt) < 0) { 494 topo_node_unbind(ntn); 495 return (NULL); 496 } 497 /* 498 * We can expect to find pci-express devices beneath the bus 499 */ 500 if (child_range_add(mod, 501 ntn, PCIEX_DEVICE, 0, MAX_PCIBUS_DEVS) < 0) { 502 topo_node_unbind(ntn); 503 return (NULL); 504 } 505 return (ntn); 506 } 507 508 tnode_t * 509 pcifn_declare(topo_mod_t *mod, tnode_t *parent, di_node_t dn, 510 topo_instance_t i) 511 { 512 did_t *pd; 513 tnode_t *ntn; 514 515 if ((pd = did_find(mod, dn)) == NULL) 516 return (NULL); 517 did_excap_set(pd, PCIE_PCIECAP_DEV_TYPE_PCI_DEV); 518 519 if ((ntn = pci_tnode_create(mod, parent, PCI_FUNCTION, i, dn)) == NULL) 520 return (NULL); 521 if (did_props_set(ntn, pd, Fn_common_props, Fn_propcnt) < 0) { 522 topo_node_unbind(ntn); 523 return (NULL); 524 } 525 /* 526 * We may find pci buses beneath a function 527 */ 528 if (child_range_add(mod, ntn, PCI_BUS, 0, MAX_HB_BUSES) < 0) { 529 topo_node_unbind(ntn); 530 return (NULL); 531 } 532 return (ntn); 533 } 534 535 tnode_t * 536 pcidev_declare(topo_mod_t *mod, tnode_t *parent, di_node_t dn, 537 topo_instance_t i) 538 { 539 did_t *pd; 540 tnode_t *ntn; 541 542 if ((pd = did_find(mod, dn)) == NULL) 543 return (NULL); 544 /* remember parent tnode */ 545 did_settnode(pd, parent); 546 547 if ((ntn = pci_tnode_create(mod, parent, PCI_DEVICE, i, dn)) == NULL) 548 return (NULL); 549 if (did_props_set(ntn, pd, Dev_common_props, Dev_propcnt) < 0) { 550 topo_node_unbind(ntn); 551 return (NULL); 552 } 553 554 /* 555 * We can expect to find pci functions beneath the device 556 */ 557 if (child_range_add(mod, ntn, PCI_FUNCTION, 0, MAX_PCIDEV_FNS) < 0) { 558 topo_node_unbind(ntn); 559 return (NULL); 560 } 561 return (ntn); 562 } 563 564 tnode_t * 565 pcibus_declare(topo_mod_t *mod, tnode_t *parent, di_node_t dn, 566 topo_instance_t i) 567 { 568 did_t *pd; 569 tnode_t *ntn; 570 int hbchild = 0; 571 572 if ((pd = did_find(mod, dn)) == NULL) 573 return (NULL); 574 did_settnode(pd, parent); 575 if ((ntn = pci_tnode_create(mod, parent, PCI_BUS, i, dn)) == NULL) 576 return (NULL); 577 /* 578 * If our devinfo node is lacking certain information of its 579 * own, and our parent topology node is a hostbridge, we may 580 * need/want to inherit information available in the 581 * hostbridge node's private data. 582 */ 583 if (strcmp(topo_node_name(parent), HOSTBRIDGE) == 0) 584 hbchild = 1; 585 if (did_props_set(ntn, pd, Bus_common_props, Bus_propcnt) < 0) { 586 topo_node_unbind(ntn); 587 return (NULL); 588 } 589 /* 590 * We can expect to find pci devices beneath the bus 591 */ 592 if (child_range_add(mod, ntn, PCI_DEVICE, 0, MAX_PCIBUS_DEVS) < 0) { 593 topo_node_unbind(ntn); 594 return (NULL); 595 } 596 /* 597 * On each bus child of the hostbridge, we represent the 598 * hostbridge as a device outside the range of legal device 599 * numbers. 600 */ 601 if (hbchild == 1) { 602 if (hostbridge_asdevice(mod, ntn) < 0) { 603 topo_node_range_destroy(ntn, PCI_DEVICE); 604 topo_node_unbind(ntn); 605 return (NULL); 606 } 607 } 608 return (ntn); 609 } 610 611 static int 612 pci_bridge_declare(topo_mod_t *mod, tnode_t *fn, di_node_t din, int board, 613 int bridge, int rc, int depth) 614 { 615 int err; 616 char *devtyp; 617 618 devtyp = pci_devtype_get(mod, din); 619 /* Check if the children are PCI or PCIe */ 620 if (devtyp && (strcmp(devtyp, "pciex") == 0)) 621 err = pci_children_instantiate(mod, fn, din, board, bridge, 622 rc, TRUST_BDF, depth + 1); 623 else 624 err = pci_children_instantiate(mod, fn, din, board, bridge, 625 rc - TO_PCI, TRUST_BDF, depth + 1); 626 return (err); 627 } 628 629 static void 630 declare_dev_and_fn(topo_mod_t *mod, tnode_t *bus, tnode_t **dev, di_node_t din, 631 int board, int bridge, int rc, int devno, int fnno, int depth) 632 { 633 int dcnt = 0, rcnt, err; 634 char *propstr, *label = NULL, *pdev = NULL; 635 tnode_t *fn; 636 uint_t class, subclass; 637 uint_t vid, did; 638 uint_t pdev_sz; 639 did_t *dp = NULL; 640 641 if (*dev == NULL) { 642 if (rc >= 0) 643 *dev = pciexdev_declare(mod, bus, din, devno); 644 else 645 *dev = pcidev_declare(mod, bus, din, devno); 646 if (*dev == NULL) 647 return; 648 ++dcnt; 649 } 650 if (rc >= 0) 651 fn = pciexfn_declare(mod, *dev, din, fnno); 652 else 653 fn = pcifn_declare(mod, *dev, din, fnno); 654 655 if (fn == NULL) { 656 if (dcnt) { 657 topo_node_unbind(*dev); 658 *dev = NULL; 659 } 660 return; 661 } 662 663 if (pci_classcode_get(mod, din, &class, &subclass) < 0) { 664 topo_node_unbind(fn); 665 if (dcnt) 666 topo_node_unbind(*dev); 667 return; 668 } 669 670 /* 671 * This function may be a bridge. If not, check for a possible 672 * topology map file and kick off its enumeration of lower-level 673 * devices. 674 */ 675 if (class == PCI_CLASS_BRIDGE && subclass == PCI_BRIDGE_PCI) { 676 (void) pci_bridge_declare(mod, fn, din, board, bridge, rc, 677 depth); 678 } 679 680 /* 681 * Check for a Neptune-based NIC. This could either be a Neptune 682 * adapter card or an Neptune ASIC on a board (e.g. motherboard) 683 * 684 * For Netpune adapter cards, use xfp-hc-topology.xml to expand 685 * topology to include the XFP optical module, which is a FRU on 686 * the Neptune based 10giga fiber NICs. 687 * 688 * For Neptune ASICs, use the XAUI enumerator to expand topology. 689 * The 10giga ports are externalized by a XAUI cards, which 690 * are FRUs. The XAUI enumerator in turn instantiates the XFP 691 * optical module FRUs. 692 */ 693 else if (class == PCI_CLASS_NET && 694 di_uintprop_get(mod, din, DI_VENDIDPROP, &vid) >= 0 && 695 di_uintprop_get(mod, din, DI_DEVIDPROP, &did) >= 0 && 696 vid == SUN_VENDOR_ID && did == NEPTUNE_DEVICE_ID) { 697 /* 698 * Is this an adapter card? Check the bus's physlot 699 */ 700 dp = did_find(mod, topo_node_getspecific(bus)); 701 if (did_physlot(dp) >= 0) { 702 topo_mod_dprintf(mod, "Found Neptune slot\n"); 703 (void) topo_mod_enummap(mod, fn, 704 "xfp", FM_FMRI_SCHEME_HC); 705 } else { 706 topo_mod_dprintf(mod, "Found Neptune ASIC\n"); 707 if (topo_mod_load(mod, XAUI, TOPO_VERSION) == NULL) { 708 topo_mod_dprintf(mod, "pcibus enum " 709 "could not load xaui enum\n"); 710 (void) topo_mod_seterrno(mod, 711 EMOD_PARTIAL_ENUM); 712 return; 713 } else { 714 if (topo_node_range_create(mod, fn, 715 XAUI, 0, 1) < 0) { 716 topo_mod_dprintf(mod, 717 "child_range_add for " 718 "XAUI failed: %s\n", 719 topo_strerror( 720 topo_mod_errno(mod))); 721 return; 722 } 723 (void) topo_mod_enumerate(mod, fn, 724 XAUI, XAUI, fnno, fnno, fn); 725 } 726 } 727 } else if (class == PCI_CLASS_NET) { 728 /* 729 * Ask the nic module if there are any nodes that need to be 730 * enumerated under this device. This might include things like 731 * transceivers or some day, LEDs. 732 */ 733 if (topo_mod_load(mod, NIC, NIC_VERSION) == NULL) { 734 topo_mod_dprintf(mod, "pcibus enum could not load " 735 "nic enum\n"); 736 (void) topo_mod_seterrno(mod, EMOD_PARTIAL_ENUM); 737 return; 738 } 739 740 (void) topo_mod_enumerate(mod, fn, NIC, NIC, 0, 0, din); 741 } else if (class == PCI_CLASS_SERIALBUS && subclass == PCI_SERIAL_USB) { 742 /* 743 * If we encounter a USB controller, make sure to enumerate all 744 * of its USB ports. 745 */ 746 if (topo_mod_load(mod, USB, USB_VERSION) == NULL) { 747 topo_mod_dprintf(mod, "pcibus enum could not load " 748 "usb enum\n"); 749 (void) topo_mod_seterrno(mod, EMOD_PARTIAL_ENUM); 750 return; 751 } 752 753 (void) topo_mod_enumerate(mod, fn, USB, USB_PCI, 0, 0, din); 754 } else if (class == PCI_CLASS_MASS) { 755 di_node_t cn; 756 int niports = 0; 757 extern void pci_iports_instantiate(topo_mod_t *, tnode_t *, 758 di_node_t, int); 759 extern void pci_receptacle_instantiate(topo_mod_t *, tnode_t *, 760 di_node_t); 761 762 for (cn = di_child_node(din); cn != DI_NODE_NIL; 763 cn = di_sibling_node(cn)) { 764 if (strcmp(di_node_name(cn), IPORT) == 0) 765 niports++; 766 } 767 if (niports > 0) 768 pci_iports_instantiate(mod, fn, din, niports); 769 770 if ((rcnt = di_prop_lookup_strings(DDI_DEV_T_ANY, din, 771 DI_RECEPTACLE_PHYMASK, &propstr)) > 0) { 772 if (topo_node_range_create(mod, fn, RECEPTACLE, 0, 773 rcnt) >= 0) 774 pci_receptacle_instantiate(mod, fn, din); 775 } 776 } 777 778 /* 779 * If this is an NVMe device and if the FRU label indicates it's not an 780 * onboard device then invoke the disk enumerator to enumerate the NVMe 781 * controller and associated namespaces. 782 * 783 * We skip NVMe devices that appear to be onboard as those are likely 784 * M.2 or U.2 devices and so should be enumerated via a 785 * platform-specific XML map so that they can be associated with the 786 * correct physical bay/slot. This code is intended to pick up NVMe 787 * devices that are part of PCIe add-in cards. 788 */ 789 if (topo_node_label(fn, &label, &err) != 0) { 790 topo_mod_dprintf(mod, "%s: failed to lookup FRU label on %s=%d", 791 __func__, topo_node_name(fn), topo_node_instance(fn)); 792 goto out; 793 } 794 795 if (class == PCI_CLASS_MASS && subclass == PCI_MASS_NVME && 796 strcmp(label, "MB") != 0) { 797 char *driver = di_driver_name(din); 798 char *slash; 799 topo_pgroup_info_t pgi; 800 801 if (topo_prop_get_string(fn, TOPO_PGROUP_IO, TOPO_IO_DEV, 802 &pdev, &err) != 0) { 803 topo_mod_dprintf(mod, "%s: failed to lookup %s on " 804 "%s=%d", __func__, TOPO_IO_DEV, topo_node_name(fn), 805 topo_node_instance(fn)); 806 goto out; 807 } 808 809 /* 810 * Add the binding properties that are required by the disk 811 * enumerator to discover the accociated NVMe controller. 812 */ 813 pdev_sz = strlen(pdev) + 1; 814 if ((slash = strrchr(pdev, '/')) == NULL) { 815 topo_mod_dprintf(mod, "%s: malformed dev path\n", 816 __func__); 817 (void) topo_mod_seterrno(mod, EMOD_PARTIAL_ENUM); 818 goto out; 819 } 820 *slash = '\0'; 821 822 pgi.tpi_name = TOPO_PGROUP_BINDING; 823 pgi.tpi_namestab = TOPO_STABILITY_PRIVATE; 824 pgi.tpi_datastab = TOPO_STABILITY_PRIVATE; 825 pgi.tpi_version = TOPO_VERSION; 826 if (topo_pgroup_create(fn, &pgi, &err) != 0 || 827 topo_prop_set_string(fn, TOPO_PGROUP_BINDING, 828 TOPO_BINDING_DRIVER, TOPO_PROP_IMMUTABLE, driver, 829 &err) != 0 || 830 topo_prop_set_string(fn, TOPO_PGROUP_BINDING, 831 TOPO_BINDING_PARENT_DEV, TOPO_PROP_IMMUTABLE, pdev, 832 &err) != 0) { 833 topo_mod_dprintf(mod, "%s: failed to set binding " 834 "props", __func__); 835 (void) topo_mod_seterrno(mod, EMOD_PARTIAL_ENUM); 836 goto out; 837 } 838 839 /* 840 * Load and invoke the disk enumerator module. 841 */ 842 if (topo_mod_load(mod, DISK, TOPO_VERSION) == NULL) { 843 topo_mod_dprintf(mod, "pcibus enum could not load " 844 "disk enum\n"); 845 (void) topo_mod_seterrno(mod, EMOD_PARTIAL_ENUM); 846 goto out; 847 } 848 (void) topo_mod_enumerate(mod, fn, DISK, NVME, 0, 0, NULL); 849 } 850 out: 851 if (pdev != NULL) { 852 topo_mod_free(mod, pdev, pdev_sz); 853 } 854 topo_mod_strfree(mod, label); 855 } 856 857 int 858 pci_children_instantiate(topo_mod_t *mod, tnode_t *parent, di_node_t pn, 859 int board, int bridge, int rc, int bover, int depth) 860 { 861 did_t *pps[MAX_PCIBUS_DEVS][MAX_PCIDEV_FNS]; 862 did_t *bp = NULL; 863 did_t *np; 864 di_node_t sib; 865 di_node_t din; 866 tnode_t *bn = NULL; 867 tnode_t *dn = NULL; 868 int pb = -1; 869 int b, d, f; 870 871 for (d = 0; d < MAX_PCIBUS_DEVS; d++) 872 for (f = 0; f < MAX_PCIDEV_FNS; f++) 873 pps[d][f] = NULL; 874 875 /* start at the parent's first sibling */ 876 sib = di_child_node(pn); 877 while (sib != DI_NODE_NIL) { 878 np = did_create(mod, sib, board, bridge, rc, bover); 879 if (np == NULL) 880 return (-1); 881 did_BDF(np, &b, &d, &f); 882 pps[d][f] = np; 883 if (bp == NULL) 884 bp = np; 885 if (pb < 0) 886 pb = ((bover == TRUST_BDF) ? b : bover); 887 sib = di_sibling_node(sib); 888 } 889 if (pb < 0 && bover < 0) 890 return (0); 891 if (rc >= 0) 892 bn = pciexbus_declare(mod, parent, pn, ((pb < 0) ? bover : pb)); 893 else 894 bn = pcibus_declare(mod, parent, pn, ((pb < 0) ? bover : pb)); 895 if (bn == NULL) 896 return (-1); 897 if (pb < 0) 898 return (0); 899 900 for (d = 0; d < MAX_PCIBUS_DEVS; d++) { 901 for (f = 0; f < MAX_PCIDEV_FNS; f++) { 902 if (pps[d][f] == NULL) 903 continue; 904 din = did_dinode(pps[d][f]); 905 906 /* 907 * Try to enumerate as many devices and functions as 908 * possible. If we fail to declare a device, break 909 * out of the function loop. 910 */ 911 declare_dev_and_fn(mod, bn, 912 &dn, din, board, bridge, rc, d, f, depth); 913 did_rele(pps[d][f]); 914 915 if (dn == NULL) 916 break; 917 } 918 dn = NULL; 919 } 920 return (0); 921 } 922 923 static int 924 pciexbus_enum(topo_mod_t *mp, tnode_t *ptn, char *pnm, topo_instance_t min, 925 topo_instance_t max) 926 { 927 di_node_t pdn; 928 int rc, hb; 929 tnode_t *hbtn; 930 int retval; 931 932 /* 933 * PCI-Express; parent node's private data is a simple di_node_t 934 * and we have to construct our own did hash and did_t. 935 */ 936 rc = topo_node_instance(ptn); 937 if ((hbtn = topo_node_parent(ptn)) != NULL) 938 hb = topo_node_instance(hbtn); 939 else 940 hb = rc; 941 942 if ((pdn = topo_node_getspecific(ptn)) == DI_NODE_NIL) { 943 topo_mod_dprintf(mp, 944 "Parent %s node missing private data.\n" 945 "Unable to proceed with %s enumeration.\n", pnm, PCIEX_BUS); 946 return (0); 947 } 948 if (did_hash_init(mp) != 0) 949 return (-1); 950 if ((did_create(mp, pdn, 0, hb, rc, TRUST_BDF)) == NULL) 951 return (-1); /* errno already set */ 952 953 retval = pci_children_instantiate(mp, ptn, pdn, 0, hb, rc, 954 (min == max) ? min : TRUST_BDF, 0); 955 did_hash_fini(mp); 956 957 return (retval); 958 } 959 960 static int 961 pcibus_enum(topo_mod_t *mp, tnode_t *ptn, char *pnm, topo_instance_t min, 962 topo_instance_t max, void *data) 963 { 964 did_t *didp, *hbdid = (did_t *)data; 965 int retval; 966 967 /* 968 * XXTOPO: we should not be sharing private node data with another 969 * module. PCI Bus; Parent node's private data is a did_t. We'll 970 * use the did hash established by the parent. 971 */ 972 did_setspecific(mp, data); 973 974 /* 975 * If we're looking for a specific bus-instance, find the right 976 * did_t in the chain, otherwise, there should be only one did_t. 977 */ 978 if (min == max) { 979 int b; 980 didp = hbdid; 981 while (didp != NULL) { 982 did_BDF(didp, &b, NULL, NULL); 983 if (b == min) 984 break; 985 didp = did_link_get(didp); 986 } 987 if (didp == NULL) { 988 topo_mod_dprintf(mp, 989 "Parent %s node missing private data related\n" 990 "to %s instance %d.\n", pnm, PCI_BUS, min); 991 topo_mod_setspecific(mp, NULL); 992 return (0); 993 } 994 } else { 995 assert(did_link_get(hbdid) == NULL); 996 didp = hbdid; 997 } 998 retval = pci_children_instantiate(mp, ptn, did_dinode(didp), 999 did_board(didp), did_bridge(didp), did_rc(didp), 1000 (min == max) ? min : TRUST_BDF, 0); 1001 1002 topo_mod_setspecific(mp, NULL); 1003 1004 return (retval); 1005 } 1006 1007 /*ARGSUSED*/ 1008 static int 1009 pci_enum(topo_mod_t *mod, tnode_t *ptn, const char *name, 1010 topo_instance_t min, topo_instance_t max, void *notused, void *data) 1011 { 1012 int retval; 1013 char *pname; 1014 1015 topo_mod_dprintf(mod, "Enumerating pci!\n"); 1016 1017 if (strcmp(name, PCI_BUS) != 0 && strcmp(name, PCIEX_BUS) != 0) { 1018 topo_mod_dprintf(mod, 1019 "Currently only know how to enumerate %s or %s.\n", 1020 PCI_BUS, PCIEX_BUS); 1021 return (0); 1022 } 1023 pname = topo_node_name(ptn); 1024 if (strcmp(pname, HOSTBRIDGE) != 0 && strcmp(pname, PCIEX_ROOT) != 0) { 1025 topo_mod_dprintf(mod, 1026 "Currently can only enumerate a %s or %s directly\n", 1027 PCI_BUS, PCIEX_BUS); 1028 topo_mod_dprintf(mod, 1029 "descended from a %s or %s node.\n", 1030 HOSTBRIDGE, PCIEX_ROOT); 1031 return (0); 1032 } 1033 1034 if (strcmp(name, PCI_BUS) == 0) { 1035 retval = pcibus_enum(mod, ptn, pname, min, max, data); 1036 } else if (strcmp(name, PCIEX_BUS) == 0) { 1037 retval = pciexbus_enum(mod, ptn, pname, min, max); 1038 } else { 1039 topo_mod_dprintf(mod, 1040 "Currently only know how to enumerate %s or %s not %s.\n", 1041 PCI_BUS, PCIEX_BUS, name); 1042 return (0); 1043 } 1044 1045 return (retval); 1046 } 1047 1048 /*ARGSUSED*/ 1049 static void 1050 pci_release(topo_mod_t *mp, tnode_t *node) 1051 { 1052 topo_method_unregister_all(mp, node); 1053 1054 /* 1055 * node private data (did_t) for this node is destroyed in 1056 * did_hash_destroy() 1057 */ 1058 1059 topo_node_unbind(node); 1060 } 1061