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 2007 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 return (-1); 154 return (0); 155 } 156 157 tnode_t * 158 pciexfn_declare(topo_mod_t *mod, tnode_t *parent, di_node_t dn, 159 topo_instance_t i) 160 { 161 did_t *pd; 162 tnode_t *ntn; 163 164 if ((pd = did_find(mod, dn)) == NULL) 165 return (NULL); 166 if ((ntn = pci_tnode_create(mod, parent, PCIEX_FUNCTION, i, dn)) 167 == NULL) 168 return (NULL); 169 if (did_props_set(ntn, pd, Fn_common_props, Fn_propcnt) < 0) { 170 topo_node_unbind(ntn); 171 return (NULL); 172 } 173 /* 174 * We may find pci-express buses or plain-pci buses beneath a function 175 */ 176 if (child_range_add(mod, ntn, PCIEX_BUS, 0, MAX_HB_BUSES) < 0) { 177 topo_node_range_destroy(ntn, PCIEX_BUS); 178 return (NULL); 179 } 180 if (child_range_add(mod, ntn, PCI_BUS, 0, MAX_HB_BUSES) < 0) { 181 topo_node_range_destroy(ntn, PCI_BUS); 182 return (NULL); 183 } 184 return (ntn); 185 } 186 187 tnode_t * 188 pciexdev_declare(topo_mod_t *mod, tnode_t *parent, di_node_t dn, 189 topo_instance_t i) 190 { 191 did_t *pd; 192 tnode_t *ntn; 193 194 if ((pd = did_find(mod, dn)) == NULL) 195 return (NULL); 196 did_settnode(pd, parent); 197 198 if ((ntn = pci_tnode_create(mod, parent, PCIEX_DEVICE, i, dn)) == NULL) 199 return (NULL); 200 if (did_props_set(ntn, pd, Dev_common_props, Dev_propcnt) < 0) { 201 topo_node_unbind(ntn); 202 return (NULL); 203 } 204 205 /* 206 * We can expect to find pci-express functions beneath the device 207 */ 208 if (child_range_add(mod, 209 ntn, PCIEX_FUNCTION, 0, MAX_PCIDEV_FNS) < 0) { 210 topo_node_range_destroy(ntn, PCIEX_FUNCTION); 211 return (NULL); 212 } 213 return (ntn); 214 } 215 216 tnode_t * 217 pciexbus_declare(topo_mod_t *mod, tnode_t *parent, di_node_t dn, 218 topo_instance_t i) 219 { 220 did_t *pd; 221 tnode_t *ntn; 222 223 if ((pd = did_find(mod, dn)) == NULL) 224 return (NULL); 225 if ((ntn = pci_tnode_create(mod, parent, PCIEX_BUS, i, dn)) == NULL) 226 return (NULL); 227 if (did_props_set(ntn, pd, Bus_common_props, Bus_propcnt) < 0) { 228 topo_node_range_destroy(ntn, PCI_DEVICE); 229 topo_node_unbind(ntn); 230 return (NULL); 231 } 232 /* 233 * We can expect to find pci-express devices beneath the bus 234 */ 235 if (child_range_add(mod, 236 ntn, PCIEX_DEVICE, 0, MAX_PCIBUS_DEVS) < 0) { 237 topo_node_range_destroy(ntn, PCIEX_DEVICE); 238 return (NULL); 239 } 240 return (ntn); 241 } 242 243 tnode_t * 244 pcifn_declare(topo_mod_t *mod, tnode_t *parent, di_node_t dn, 245 topo_instance_t i) 246 { 247 did_t *pd; 248 tnode_t *ntn; 249 250 if ((pd = did_find(mod, dn)) == NULL) 251 return (NULL); 252 if ((ntn = pci_tnode_create(mod, parent, PCI_FUNCTION, i, dn)) == NULL) 253 return (NULL); 254 if (did_props_set(ntn, pd, Fn_common_props, Fn_propcnt) < 0) { 255 topo_node_unbind(ntn); 256 return (NULL); 257 } 258 /* 259 * We may find pci buses beneath a function 260 */ 261 if (child_range_add(mod, ntn, PCI_BUS, 0, MAX_HB_BUSES) < 0) { 262 topo_node_unbind(ntn); 263 return (NULL); 264 } 265 return (ntn); 266 } 267 268 tnode_t * 269 pcidev_declare(topo_mod_t *mod, tnode_t *parent, di_node_t dn, 270 topo_instance_t i) 271 { 272 did_t *pd; 273 did_t *ppd; 274 di_node_t pdn; 275 tnode_t *ntn; 276 277 if ((pdn = topo_node_getspecific(parent)) == DI_NODE_NIL) 278 return (NULL); 279 if ((ppd = did_find(mod, pdn)) == NULL) 280 return (NULL); 281 if ((pd = did_find(mod, dn)) == NULL) 282 return (NULL); 283 /* remember parent tnode */ 284 did_settnode(pd, parent); 285 286 if ((ntn = pci_tnode_create(mod, parent, PCI_DEVICE, i, dn)) == NULL) 287 return (NULL); 288 /* 289 * If our devinfo node is lacking certain information of its 290 * own, we may need/want to inherit the information available 291 * from our parent node's private data. 292 */ 293 294 did_inherit(ppd, pd); 295 if (did_props_set(ntn, pd, Dev_common_props, Dev_propcnt) < 0) { 296 topo_node_unbind(ntn); 297 return (NULL); 298 } 299 300 /* 301 * We can expect to find pci functions beneath the device 302 */ 303 if (child_range_add(mod, ntn, PCI_FUNCTION, 0, MAX_PCIDEV_FNS) < 0) { 304 topo_node_range_destroy(ntn, PCI_FUNCTION); 305 topo_node_unbind(ntn); 306 return (NULL); 307 } 308 return (ntn); 309 } 310 311 tnode_t * 312 pcibus_declare(topo_mod_t *mod, tnode_t *parent, di_node_t dn, 313 topo_instance_t i) 314 { 315 did_t *pd; 316 tnode_t *ntn; 317 int hbchild = 0; 318 319 if ((pd = did_find(mod, dn)) == NULL) 320 return (NULL); 321 if ((ntn = pci_tnode_create(mod, parent, PCI_BUS, i, dn)) == NULL) 322 return (NULL); 323 /* 324 * If our devinfo node is lacking certain information of its 325 * own, and our parent topology node is a hostbridge, we may 326 * need/want to inherit information available in the 327 * hostbridge node's private data. 328 */ 329 if (strcmp(topo_node_name(parent), HOSTBRIDGE) == 0) 330 hbchild = 1; 331 if (did_props_set(ntn, pd, Bus_common_props, Bus_propcnt) < 0) { 332 topo_node_unbind(ntn); 333 return (NULL); 334 } 335 /* 336 * We can expect to find pci devices beneath the bus 337 */ 338 if (child_range_add(mod, ntn, PCI_DEVICE, 0, MAX_PCIBUS_DEVS) < 0) { 339 topo_node_unbind(ntn); 340 return (NULL); 341 } 342 /* 343 * On each bus child of the hostbridge, we represent the 344 * hostbridge as a device outside the range of legal device 345 * numbers. 346 */ 347 if (hbchild == 1) { 348 if (hostbridge_asdevice(mod, ntn) < 0) { 349 topo_node_range_destroy(ntn, PCI_DEVICE); 350 topo_node_unbind(ntn); 351 return (NULL); 352 } 353 } 354 return (ntn); 355 } 356 357 static int 358 pci_bridge_declare(topo_mod_t *mod, tnode_t *fn, di_node_t din, int board, 359 int bridge, int rc, int depth) 360 { 361 int err, excap, extyp; 362 363 excap = pciex_cap_get(mod, din); 364 extyp = excap & PCIE_PCIECAP_DEV_TYPE_MASK; 365 if (excap <= 0 || 366 extyp != PCIE_PCIECAP_DEV_TYPE_PCIE2PCI) 367 err = pci_children_instantiate(mod, fn, din, board, bridge, 368 rc, TRUST_BDF, depth + 1); 369 else 370 err = pci_children_instantiate(mod, fn, din, board, bridge, 371 rc - TO_PCI, TRUST_BDF, depth + 1); 372 return (err); 373 } 374 375 static int 376 declare_dev_and_fn(topo_mod_t *mod, tnode_t *bus, tnode_t **dev, di_node_t din, 377 int board, int bridge, int rc, int devno, int fnno, int depth) 378 { 379 int err = 0; 380 tnode_t *fn; 381 uint_t class, subclass; 382 383 if (*dev == NULL) { 384 if (rc >= 0) 385 *dev = pciexdev_declare(mod, bus, din, devno); 386 else 387 *dev = pcidev_declare(mod, bus, din, devno); 388 if (*dev == NULL) 389 return (-1); 390 } 391 if (rc >= 0) 392 fn = pciexfn_declare(mod, *dev, din, fnno); 393 else 394 fn = pcifn_declare(mod, *dev, din, fnno); 395 if (fn == NULL) 396 return (-1); 397 if (pci_classcode_get(mod, din, &class, &subclass) < 0) 398 return (-1); 399 400 /* 401 * This function may be a bridge. If not, check for a possible 402 * topology map file and kick off its enumeration of lower-level 403 * devices. 404 */ 405 if (class == PCI_CLASS_BRIDGE && subclass == PCI_BRIDGE_PCI) 406 err = pci_bridge_declare(mod, fn, din, board, bridge, rc, 407 depth); 408 else if (class == PCI_CLASS_MASS) 409 (void) topo_mod_enummap(mod, fn, "storage", FM_FMRI_SCHEME_HC); 410 411 return (err); 412 } 413 414 int 415 pci_children_instantiate(topo_mod_t *mod, tnode_t *parent, di_node_t pn, 416 int board, int bridge, int rc, int bover, int depth) 417 { 418 did_t *pps[MAX_PCIBUS_DEVS][MAX_PCIDEV_FNS]; 419 did_t *bp = NULL; 420 did_t *np; 421 di_node_t sib; 422 di_node_t din; 423 tnode_t *bn = NULL; 424 tnode_t *dn = NULL; 425 int pb = -1; 426 int b, d, f; 427 428 for (d = 0; d < MAX_PCIBUS_DEVS; d++) 429 for (f = 0; f < MAX_PCIDEV_FNS; f++) 430 pps[d][f] = NULL; 431 432 /* start at the parent's first sibling */ 433 sib = di_child_node(pn); 434 while (sib != DI_NODE_NIL) { 435 np = did_create(mod, sib, board, bridge, rc, bover); 436 if (np == NULL) 437 return (-1); 438 did_BDF(np, &b, &d, &f); 439 pps[d][f] = np; 440 if (bp == NULL) 441 bp = np; 442 if (pb < 0) 443 pb = ((bover == TRUST_BDF) ? b : bover); 444 sib = di_sibling_node(sib); 445 } 446 if (pb < 0 && bover < 0) 447 return (0); 448 if (rc >= 0) 449 bn = pciexbus_declare(mod, parent, pn, ((pb < 0) ? bover : pb)); 450 else 451 bn = pcibus_declare(mod, parent, pn, ((pb < 0) ? bover : pb)); 452 if (bn == NULL) 453 return (-1); 454 if (pb < 0) 455 return (0); 456 457 for (d = 0; d < MAX_PCIBUS_DEVS; d++) { 458 for (f = 0; f < MAX_PCIDEV_FNS; f++) { 459 if (pps[d][f] == NULL) 460 continue; 461 din = did_dinode(pps[d][f]); 462 /* 463 * Ignore error and try to enumerate as much as 464 * possible. If we ever need to check for an 465 * error all declared buses, devices and functions 466 * need to be cleaned up 467 */ 468 (void) declare_dev_and_fn(mod, bn, 469 &dn, din, board, bridge, rc, d, f, depth); 470 did_rele(pps[d][f]); 471 } 472 dn = NULL; 473 } 474 return (0); 475 } 476 477 static int 478 pciexbus_enum(topo_mod_t *mp, tnode_t *ptn, char *pnm, topo_instance_t min, 479 topo_instance_t max) 480 { 481 di_node_t pdn; 482 int rc; 483 int retval; 484 485 /* 486 * PCI-Express; root complex shares the hostbridge's instance 487 * number. Parent node's private data is a simple di_node_t 488 * and we have to construct our own did hash and did_t. 489 */ 490 rc = topo_node_instance(ptn); 491 492 if ((pdn = topo_node_getspecific(ptn)) == DI_NODE_NIL) { 493 topo_mod_dprintf(mp, 494 "Parent %s node missing private data.\n" 495 "Unable to proceed with %s enumeration.\n", pnm, PCIEX_BUS); 496 return (0); 497 } 498 did_hash_init(mp); 499 if ((did_create(mp, pdn, 0, 0, rc, TRUST_BDF)) == NULL) 500 return (-1); /* errno already set */ 501 502 retval = pci_children_instantiate(mp, ptn, pdn, 0, 0, rc, 503 (min == max) ? min : TRUST_BDF, 0); 504 did_hash_fini(mp); 505 506 return (retval); 507 } 508 509 static int 510 pcibus_enum(topo_mod_t *mp, tnode_t *ptn, char *pnm, topo_instance_t min, 511 topo_instance_t max, void *data) 512 { 513 did_t *didp, *hbdid = (did_t *)data; 514 int retval; 515 516 /* 517 * XXTOPO: we should not be sharing private node data with another 518 * module. PCI Bus; Parent node's private data is a did_t. We'll 519 * use the did hash established by the parent. 520 */ 521 did_setspecific(mp, data); 522 523 /* 524 * If we're looking for a specific bus-instance, find the right 525 * did_t in the chain, otherwise, there should be only one did_t. 526 */ 527 if (min == max) { 528 int b; 529 didp = hbdid; 530 while (didp != NULL) { 531 did_BDF(didp, &b, NULL, NULL); 532 if (b == min) 533 break; 534 didp = did_link_get(didp); 535 } 536 if (didp == NULL) { 537 topo_mod_dprintf(mp, 538 "Parent %s node missing private data related\n" 539 "to %s instance %d.\n", pnm, PCI_BUS, min); 540 topo_mod_setspecific(mp, NULL); 541 return (0); 542 } 543 } else { 544 assert(did_link_get(hbdid) == NULL); 545 didp = hbdid; 546 } 547 retval = pci_children_instantiate(mp, ptn, did_dinode(didp), 548 did_board(didp), did_bridge(didp), did_rc(didp), 549 (min == max) ? min : TRUST_BDF, 0); 550 551 topo_mod_setspecific(mp, NULL); 552 553 return (retval); 554 } 555 556 /*ARGSUSED*/ 557 static int 558 pci_enum(topo_mod_t *mod, tnode_t *ptn, const char *name, 559 topo_instance_t min, topo_instance_t max, void *notused, void *data) 560 { 561 int retval; 562 char *pname; 563 564 topo_mod_dprintf(mod, "Enumerating pci!\n"); 565 566 if (strcmp(name, PCI_BUS) != 0 && strcmp(name, PCIEX_BUS) != 0) { 567 topo_mod_dprintf(mod, 568 "Currently only know how to enumerate %s or %s.\n", 569 PCI_BUS, PCIEX_BUS); 570 return (0); 571 } 572 pname = topo_node_name(ptn); 573 if (strcmp(pname, HOSTBRIDGE) != 0 && strcmp(pname, PCIEX_ROOT) != 0) { 574 topo_mod_dprintf(mod, 575 "Currently can only enumerate a %s or %s directly\n", 576 PCI_BUS, PCIEX_BUS); 577 topo_mod_dprintf(mod, 578 "descended from a %s or %s node.\n", 579 HOSTBRIDGE, PCIEX_ROOT); 580 return (0); 581 } 582 583 if (strcmp(name, PCI_BUS) == 0) { 584 retval = pcibus_enum(mod, ptn, pname, min, max, data); 585 } else if (strcmp(name, PCIEX_BUS) == 0) { 586 retval = pciexbus_enum(mod, ptn, pname, min, max); 587 } else { 588 topo_mod_dprintf(mod, 589 "Currently only know how to enumerate %s or %s not %s.\n", 590 PCI_BUS, PCIEX_BUS, name); 591 return (0); 592 } 593 594 return (retval); 595 } 596 597 /*ARGSUSED*/ 598 static void 599 pci_release(topo_mod_t *mp, tnode_t *node) 600 { 601 topo_method_unregister_all(mp, node); 602 603 /* 604 * node private data (did_t) for this node is destroyed in 605 * did_hash_destroy() 606 */ 607 608 topo_node_unbind(node); 609 } 610