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