1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <sys/fm/protocol.h> 30 #include <assert.h> 31 #include <stdio.h> 32 #include <stdlib.h> 33 #include <string.h> 34 #include <strings.h> 35 #include <alloca.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 44 #include <hostbridge.h> 45 #include <pcibus.h> 46 #include <did.h> 47 #include <did_props.h> 48 #include <util.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 topo_mod_register(modhdl, &Pci_info, TOPO_VERSION); 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; 165 166 if ((pd = did_find(mod, dn)) == NULL) 167 return (NULL); 168 if ((ntn = pci_tnode_create(mod, parent, PCIEX_FUNCTION, i, dn)) 169 == NULL) 170 return (NULL); 171 if (did_props_set(ntn, pd, Fn_common_props, Fn_propcnt) < 0) { 172 topo_node_unbind(ntn); 173 return (NULL); 174 } 175 /* 176 * We may find pci-express buses or plain-pci buses beneath a function 177 */ 178 if (child_range_add(mod, ntn, PCIEX_BUS, 0, MAX_HB_BUSES) < 0) { 179 topo_node_unbind(ntn); 180 return (NULL); 181 } 182 if (child_range_add(mod, ntn, PCI_BUS, 0, MAX_HB_BUSES) < 0) { 183 topo_node_range_destroy(ntn, PCIEX_BUS); 184 topo_node_unbind(ntn); 185 return (NULL); 186 } 187 return (ntn); 188 } 189 190 tnode_t * 191 pciexdev_declare(topo_mod_t *mod, tnode_t *parent, di_node_t dn, 192 topo_instance_t i) 193 { 194 did_t *pd; 195 tnode_t *ntn; 196 197 if ((pd = did_find(mod, dn)) == NULL) 198 return (NULL); 199 did_settnode(pd, parent); 200 201 if ((ntn = pci_tnode_create(mod, parent, PCIEX_DEVICE, i, dn)) == NULL) 202 return (NULL); 203 if (did_props_set(ntn, pd, Dev_common_props, Dev_propcnt) < 0) { 204 topo_node_unbind(ntn); 205 return (NULL); 206 } 207 208 /* 209 * We can expect to find pci-express functions beneath the device 210 */ 211 if (child_range_add(mod, 212 ntn, PCIEX_FUNCTION, 0, MAX_PCIDEV_FNS) < 0) { 213 topo_node_unbind(ntn); 214 return (NULL); 215 } 216 return (ntn); 217 } 218 219 tnode_t * 220 pciexbus_declare(topo_mod_t *mod, tnode_t *parent, di_node_t dn, 221 topo_instance_t i) 222 { 223 did_t *pd; 224 tnode_t *ntn; 225 226 if ((pd = did_find(mod, dn)) == NULL) 227 return (NULL); 228 did_settnode(pd, parent); 229 if ((ntn = pci_tnode_create(mod, parent, PCIEX_BUS, i, dn)) == NULL) 230 return (NULL); 231 if (did_props_set(ntn, pd, Bus_common_props, Bus_propcnt) < 0) { 232 topo_node_unbind(ntn); 233 return (NULL); 234 } 235 /* 236 * We can expect to find pci-express devices beneath the bus 237 */ 238 if (child_range_add(mod, 239 ntn, PCIEX_DEVICE, 0, MAX_PCIBUS_DEVS) < 0) { 240 topo_node_unbind(ntn); 241 return (NULL); 242 } 243 return (ntn); 244 } 245 246 tnode_t * 247 pcifn_declare(topo_mod_t *mod, tnode_t *parent, di_node_t dn, 248 topo_instance_t i) 249 { 250 did_t *pd; 251 tnode_t *ntn; 252 253 if ((pd = did_find(mod, dn)) == NULL) 254 return (NULL); 255 if ((ntn = pci_tnode_create(mod, parent, PCI_FUNCTION, i, dn)) == NULL) 256 return (NULL); 257 if (did_props_set(ntn, pd, Fn_common_props, Fn_propcnt) < 0) { 258 topo_node_unbind(ntn); 259 return (NULL); 260 } 261 /* 262 * We may find pci buses beneath a function 263 */ 264 if (child_range_add(mod, ntn, PCI_BUS, 0, MAX_HB_BUSES) < 0) { 265 topo_node_unbind(ntn); 266 return (NULL); 267 } 268 return (ntn); 269 } 270 271 tnode_t * 272 pcidev_declare(topo_mod_t *mod, tnode_t *parent, di_node_t dn, 273 topo_instance_t i) 274 { 275 did_t *pd; 276 tnode_t *ntn; 277 278 if ((pd = did_find(mod, dn)) == NULL) 279 return (NULL); 280 /* remember parent tnode */ 281 did_settnode(pd, parent); 282 283 if ((ntn = pci_tnode_create(mod, parent, PCI_DEVICE, i, dn)) == NULL) 284 return (NULL); 285 if (did_props_set(ntn, pd, Dev_common_props, Dev_propcnt) < 0) { 286 topo_node_unbind(ntn); 287 return (NULL); 288 } 289 290 /* 291 * We can expect to find pci functions beneath the device 292 */ 293 if (child_range_add(mod, ntn, PCI_FUNCTION, 0, MAX_PCIDEV_FNS) < 0) { 294 topo_node_unbind(ntn); 295 return (NULL); 296 } 297 return (ntn); 298 } 299 300 tnode_t * 301 pcibus_declare(topo_mod_t *mod, tnode_t *parent, di_node_t dn, 302 topo_instance_t i) 303 { 304 did_t *pd; 305 tnode_t *ntn; 306 int hbchild = 0; 307 308 if ((pd = did_find(mod, dn)) == NULL) 309 return (NULL); 310 did_settnode(pd, parent); 311 if ((ntn = pci_tnode_create(mod, parent, PCI_BUS, i, dn)) == NULL) 312 return (NULL); 313 /* 314 * If our devinfo node is lacking certain information of its 315 * own, and our parent topology node is a hostbridge, we may 316 * need/want to inherit information available in the 317 * hostbridge node's private data. 318 */ 319 if (strcmp(topo_node_name(parent), HOSTBRIDGE) == 0) 320 hbchild = 1; 321 if (did_props_set(ntn, pd, Bus_common_props, Bus_propcnt) < 0) { 322 topo_node_unbind(ntn); 323 return (NULL); 324 } 325 /* 326 * We can expect to find pci devices beneath the bus 327 */ 328 if (child_range_add(mod, ntn, PCI_DEVICE, 0, MAX_PCIBUS_DEVS) < 0) { 329 topo_node_unbind(ntn); 330 return (NULL); 331 } 332 /* 333 * On each bus child of the hostbridge, we represent the 334 * hostbridge as a device outside the range of legal device 335 * numbers. 336 */ 337 if (hbchild == 1) { 338 if (hostbridge_asdevice(mod, ntn) < 0) { 339 topo_node_range_destroy(ntn, PCI_DEVICE); 340 topo_node_unbind(ntn); 341 return (NULL); 342 } 343 } 344 return (ntn); 345 } 346 347 static int 348 pci_bridge_declare(topo_mod_t *mod, tnode_t *fn, di_node_t din, int board, 349 int bridge, int rc, int depth) 350 { 351 int err, excap, extyp; 352 353 excap = pciex_cap_get(mod, din); 354 extyp = excap & PCIE_PCIECAP_DEV_TYPE_MASK; 355 if (excap <= 0 || 356 extyp != PCIE_PCIECAP_DEV_TYPE_PCIE2PCI) 357 err = pci_children_instantiate(mod, fn, din, board, bridge, 358 rc, TRUST_BDF, depth + 1); 359 else 360 err = pci_children_instantiate(mod, fn, din, board, bridge, 361 rc - TO_PCI, TRUST_BDF, depth + 1); 362 return (err); 363 } 364 365 static void 366 declare_dev_and_fn(topo_mod_t *mod, tnode_t *bus, tnode_t **dev, di_node_t din, 367 int board, int bridge, int rc, int devno, int fnno, int depth) 368 { 369 int dcnt = 0; 370 tnode_t *fn; 371 uint_t class, subclass; 372 uint_t vid, did; 373 did_t *dp = NULL; 374 375 if (*dev == NULL) { 376 if (rc >= 0) 377 *dev = pciexdev_declare(mod, bus, din, devno); 378 else 379 *dev = pcidev_declare(mod, bus, din, devno); 380 if (*dev == NULL) 381 return; 382 ++dcnt; 383 } 384 if (rc >= 0) 385 fn = pciexfn_declare(mod, *dev, din, fnno); 386 else 387 fn = pcifn_declare(mod, *dev, din, fnno); 388 389 if (fn == NULL) { 390 if (dcnt) { 391 topo_node_unbind(*dev); 392 *dev = NULL; 393 } 394 return; 395 } 396 397 if (pci_classcode_get(mod, din, &class, &subclass) < 0) { 398 topo_node_unbind(fn); 399 if (dcnt) 400 topo_node_unbind(*dev); 401 return; 402 } 403 404 /* 405 * This function may be a bridge. If not, check for a possible 406 * topology map file and kick off its enumeration of lower-level 407 * devices. 408 */ 409 if (class == PCI_CLASS_BRIDGE && subclass == PCI_BRIDGE_PCI) { 410 (void) pci_bridge_declare(mod, fn, din, board, bridge, rc, 411 depth); 412 } 413 414 /* 415 * Check for a Neptune-based NIC. This could either be a Neptune 416 * adapter card or an Neptune ASIC on a board (e.g. motherboard) 417 * 418 * For Netpune adapter cards, use xfp-hc-topology.xml to expand 419 * topology to include the XFP optical module, which is a FRU on 420 * the Neptune based 10giga fiber NICs. 421 * 422 * For Neptune ASICs, use the XAUI enumerator to expand topology. 423 * The 10giga ports are externalized by a XAUI cards, which 424 * are FRUs. The XAUI enumerator in turn instantiates the XFP 425 * optical module FRUs. 426 */ 427 else if (class == PCI_CLASS_NET && 428 di_uintprop_get(mod, din, DI_VENDIDPROP, &vid) >= 0 && 429 di_uintprop_get(mod, din, DI_DEVIDPROP, &did) >= 0) { 430 if (vid == SUN_VENDOR_ID && did == NEPTUNE_DEVICE_ID) { 431 /* 432 * Is this an adapter card? Check the bus's physlot 433 */ 434 dp = did_find(mod, topo_node_getspecific(bus)); 435 if (did_physslot(dp) >= 0) { 436 topo_mod_dprintf(mod, "Found Neptune slot\n"); 437 (void) topo_mod_enummap(mod, fn, 438 "xfp", FM_FMRI_SCHEME_HC); 439 } else { 440 topo_mod_dprintf(mod, "Found Neptune ASIC\n"); 441 if (topo_mod_load(mod, XAUI, TOPO_VERSION) == 442 NULL) { 443 topo_mod_dprintf(mod, "pcibus enum " 444 "could not load xaui enum\n"); 445 topo_mod_seterrno(mod, 446 EMOD_PARTIAL_ENUM); 447 return; 448 } else { 449 if (topo_node_range_create(mod, fn, 450 XAUI, 0, 1) < 0) { 451 topo_mod_dprintf(mod, 452 "child_range_add for " 453 "XAUI failed: %s\n", 454 topo_strerror( 455 topo_mod_errno(mod))); 456 return; 457 } 458 (void) topo_mod_enumerate(mod, fn, 459 XAUI, XAUI, fnno, fnno, fn); 460 } 461 } 462 } 463 } 464 } 465 466 int 467 pci_children_instantiate(topo_mod_t *mod, tnode_t *parent, di_node_t pn, 468 int board, int bridge, int rc, int bover, int depth) 469 { 470 did_t *pps[MAX_PCIBUS_DEVS][MAX_PCIDEV_FNS]; 471 did_t *bp = NULL; 472 did_t *np; 473 di_node_t sib; 474 di_node_t din; 475 tnode_t *bn = NULL; 476 tnode_t *dn = NULL; 477 int pb = -1; 478 int b, d, f; 479 480 for (d = 0; d < MAX_PCIBUS_DEVS; d++) 481 for (f = 0; f < MAX_PCIDEV_FNS; f++) 482 pps[d][f] = NULL; 483 484 /* start at the parent's first sibling */ 485 sib = di_child_node(pn); 486 while (sib != DI_NODE_NIL) { 487 np = did_create(mod, sib, board, bridge, rc, bover); 488 if (np == NULL) 489 return (-1); 490 did_BDF(np, &b, &d, &f); 491 pps[d][f] = np; 492 if (bp == NULL) 493 bp = np; 494 if (pb < 0) 495 pb = ((bover == TRUST_BDF) ? b : bover); 496 sib = di_sibling_node(sib); 497 } 498 if (pb < 0 && bover < 0) 499 return (0); 500 if (rc >= 0) 501 bn = pciexbus_declare(mod, parent, pn, ((pb < 0) ? bover : pb)); 502 else 503 bn = pcibus_declare(mod, parent, pn, ((pb < 0) ? bover : pb)); 504 if (bn == NULL) 505 return (-1); 506 if (pb < 0) 507 return (0); 508 509 for (d = 0; d < MAX_PCIBUS_DEVS; d++) { 510 for (f = 0; f < MAX_PCIDEV_FNS; f++) { 511 if (pps[d][f] == NULL) 512 continue; 513 din = did_dinode(pps[d][f]); 514 515 /* 516 * Try to enumerate as many devices and functions as 517 * possible. If we fail to declare a device, break 518 * out of the function loop. 519 */ 520 declare_dev_and_fn(mod, bn, 521 &dn, din, board, bridge, rc, d, f, depth); 522 did_rele(pps[d][f]); 523 524 if (dn == NULL) 525 break; 526 } 527 dn = NULL; 528 } 529 return (0); 530 } 531 532 static int 533 pciexbus_enum(topo_mod_t *mp, tnode_t *ptn, char *pnm, topo_instance_t min, 534 topo_instance_t max) 535 { 536 di_node_t pdn; 537 int rc; 538 int retval; 539 540 /* 541 * PCI-Express; root complex shares the hostbridge's instance 542 * number. Parent node's private data is a simple di_node_t 543 * and we have to construct our own did hash and did_t. 544 */ 545 rc = topo_node_instance(ptn); 546 547 if ((pdn = topo_node_getspecific(ptn)) == DI_NODE_NIL) { 548 topo_mod_dprintf(mp, 549 "Parent %s node missing private data.\n" 550 "Unable to proceed with %s enumeration.\n", pnm, PCIEX_BUS); 551 return (0); 552 } 553 if (did_hash_init(mp) != 0) 554 return (-1); 555 if ((did_create(mp, pdn, 0, 0, rc, TRUST_BDF)) == NULL) 556 return (-1); /* errno already set */ 557 558 retval = pci_children_instantiate(mp, ptn, pdn, 0, 0, rc, 559 (min == max) ? min : TRUST_BDF, 0); 560 did_hash_fini(mp); 561 562 return (retval); 563 } 564 565 static int 566 pcibus_enum(topo_mod_t *mp, tnode_t *ptn, char *pnm, topo_instance_t min, 567 topo_instance_t max, void *data) 568 { 569 did_t *didp, *hbdid = (did_t *)data; 570 int retval; 571 572 /* 573 * XXTOPO: we should not be sharing private node data with another 574 * module. PCI Bus; Parent node's private data is a did_t. We'll 575 * use the did hash established by the parent. 576 */ 577 did_setspecific(mp, data); 578 579 /* 580 * If we're looking for a specific bus-instance, find the right 581 * did_t in the chain, otherwise, there should be only one did_t. 582 */ 583 if (min == max) { 584 int b; 585 didp = hbdid; 586 while (didp != NULL) { 587 did_BDF(didp, &b, NULL, NULL); 588 if (b == min) 589 break; 590 didp = did_link_get(didp); 591 } 592 if (didp == NULL) { 593 topo_mod_dprintf(mp, 594 "Parent %s node missing private data related\n" 595 "to %s instance %d.\n", pnm, PCI_BUS, min); 596 topo_mod_setspecific(mp, NULL); 597 return (0); 598 } 599 } else { 600 assert(did_link_get(hbdid) == NULL); 601 didp = hbdid; 602 } 603 retval = pci_children_instantiate(mp, ptn, did_dinode(didp), 604 did_board(didp), did_bridge(didp), did_rc(didp), 605 (min == max) ? min : TRUST_BDF, 0); 606 607 topo_mod_setspecific(mp, NULL); 608 609 return (retval); 610 } 611 612 /*ARGSUSED*/ 613 static int 614 pci_enum(topo_mod_t *mod, tnode_t *ptn, const char *name, 615 topo_instance_t min, topo_instance_t max, void *notused, void *data) 616 { 617 int retval; 618 char *pname; 619 620 topo_mod_dprintf(mod, "Enumerating pci!\n"); 621 622 if (strcmp(name, PCI_BUS) != 0 && strcmp(name, PCIEX_BUS) != 0) { 623 topo_mod_dprintf(mod, 624 "Currently only know how to enumerate %s or %s.\n", 625 PCI_BUS, PCIEX_BUS); 626 return (0); 627 } 628 pname = topo_node_name(ptn); 629 if (strcmp(pname, HOSTBRIDGE) != 0 && strcmp(pname, PCIEX_ROOT) != 0) { 630 topo_mod_dprintf(mod, 631 "Currently can only enumerate a %s or %s directly\n", 632 PCI_BUS, PCIEX_BUS); 633 topo_mod_dprintf(mod, 634 "descended from a %s or %s node.\n", 635 HOSTBRIDGE, PCIEX_ROOT); 636 return (0); 637 } 638 639 if (strcmp(name, PCI_BUS) == 0) { 640 retval = pcibus_enum(mod, ptn, pname, min, max, data); 641 } else if (strcmp(name, PCIEX_BUS) == 0) { 642 retval = pciexbus_enum(mod, ptn, pname, min, max); 643 } else { 644 topo_mod_dprintf(mod, 645 "Currently only know how to enumerate %s or %s not %s.\n", 646 PCI_BUS, PCIEX_BUS, name); 647 return (0); 648 } 649 650 return (retval); 651 } 652 653 /*ARGSUSED*/ 654 static void 655 pci_release(topo_mod_t *mp, tnode_t *node) 656 { 657 topo_method_unregister_all(mp, node); 658 659 /* 660 * node private data (did_t) for this node is destroyed in 661 * did_hash_destroy() 662 */ 663 664 topo_node_unbind(node); 665 } 666