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 /* 30 * did.c 31 * The acronym did means "Dev-Info-Data". Many properties and 32 * characteristics of topology nodes are, with a bit of coaxing 33 * derived from devinfo nodes. These routines do some of the 34 * derivation and also encapsulate the discoveries in did_t 35 * structures that get associated with topology nodes as their 36 * "private" data. 37 */ 38 #include <alloca.h> 39 #include <assert.h> 40 #include <string.h> 41 #include <strings.h> 42 #include <sys/types.h> 43 #include <libtopo.h> 44 #include <libnvpair.h> 45 #include <libdevinfo.h> 46 #include <sys/pcie.h> 47 48 #include "topo_mod.h" 49 #include "hostbridge.h" 50 #include "pcibus.h" 51 #include "did_impl.h" 52 #include "did_props.h" 53 54 static void slotnm_destroy(slotnm_t *); 55 56 static slotnm_t * 57 slotnm_create(topo_mod_t *mp, int dev, char *str) 58 { 59 slotnm_t *p; 60 61 if ((p = topo_mod_alloc(mp, sizeof (slotnm_t))) == NULL) 62 return (NULL); 63 p->snm_mod = mp; 64 p->snm_next = NULL; 65 p->snm_dev = dev; 66 p->snm_label = topo_mod_strdup(mp, str); 67 if (p->snm_label == NULL) { 68 slotnm_destroy(p); 69 return (NULL); 70 } 71 return (p); 72 } 73 74 static void 75 slotnm_destroy(slotnm_t *p) 76 { 77 if (p == NULL) 78 return; 79 slotnm_destroy(p->snm_next); 80 if (p->snm_label != NULL) 81 topo_mod_strfree(p->snm_mod, p->snm_label); 82 topo_mod_free(p->snm_mod, p, sizeof (slotnm_t)); 83 } 84 85 static int 86 slotnm_cp(did_t *from, did_t *to, int *nslots) 87 { 88 slotnm_t *nxt, *new; 89 slotnm_t *last = NULL; 90 91 *nslots = 0; 92 for (nxt = from->dp_slotnames; nxt != NULL; nxt = nxt->snm_next) { 93 new = slotnm_create(to->dp_mod, nxt->snm_dev, nxt->snm_label); 94 if (new == NULL) { 95 if (to->dp_slotnames != NULL) 96 slotnm_destroy(to->dp_slotnames); 97 to->dp_slotnames = NULL; 98 *nslots = 0; 99 return (-1); 100 } 101 if (last == NULL) { 102 to->dp_slotnames = last = new; 103 } else { 104 last->snm_next = new; 105 last = new; 106 } 107 (*nslots)++; 108 } 109 if (*nslots > 0) 110 topo_mod_dprintf(to->dp_mod, 111 "%p inherits %d slot label(s) from %p.\n", 112 to, *nslots, from); 113 return (0); 114 } 115 116 static int 117 di_physlotinfo_get(topo_mod_t *mp, di_node_t src, uint_t excap, 118 int *slotnum, char **slotnm, di_prom_handle_t promtree) 119 { 120 char *slotbuf; 121 int sz; 122 uchar_t *buf; 123 124 *slotnum = -1; 125 (void) di_uintprop_get(src, DI_PHYSPROP, (uint_t *)slotnum, 126 promtree); 127 /* 128 * If no physical slot number property was found, then the 129 * capabilities register may indicate the pci-express device 130 * implements a slot, and we should record which slot. 131 */ 132 if (*slotnum == -1 && (excap & PCIE_PCIECAP_SLOT_IMPL) != 0) { 133 uint_t slotcap; 134 int e; 135 e = di_uintprop_get(src, "pcie-slotcap-reg", &slotcap, 136 promtree); 137 if (e == 0) 138 *slotnum = slotcap >> PCIE_SLOTCAP_PHY_SLOT_NUM_SHIFT; 139 } 140 if (*slotnum == -1) 141 return (0); 142 143 /* 144 * For PCI-Express, there is only one downstream device, so check for 145 * a slot-names property, and if it exists, ignore the slotmask value 146 * and use the string as the label. 147 */ 148 if (di_bytes_get(src, DI_SLOTPROP, &sz, &buf, promtree) == 0 && 149 sz > 4) { 150 slotbuf = (char *)&buf[4]; 151 } else { 152 /* 153 * Make generic description string "SLOT <num>", allow up to 154 * 10 digits for number 155 */ 156 slotbuf = alloca(16); 157 (void) snprintf(slotbuf, 16, "SLOT %d", *slotnum); 158 } 159 if ((*slotnm = topo_mod_strdup(mp, slotbuf)) == NULL) 160 return (-1); 161 162 return (0); 163 } 164 165 static int 166 di_slotinfo_get(topo_mod_t *mp, di_node_t src, int *nslots, slotnm_t **slots, 167 di_prom_handle_t promtree) 168 { 169 slotnm_t *lastslot = NULL; 170 slotnm_t *newslot; 171 uchar_t *slotbuf; 172 uint_t slotmap = 0; 173 char *slotname; 174 int andbit; 175 int sz = -1; 176 177 *slots = NULL; 178 *nslots = 0; 179 if (di_bytes_get(src, DI_SLOTPROP, &sz, &slotbuf, promtree) < 0) 180 return (0); 181 if (sz < sizeof (uint_t)) 182 return (0); 183 bcopy(slotbuf, &slotmap, sizeof (uint_t)); 184 if (slotmap == 0) 185 return (0); 186 187 slotname = (char *)&slotbuf[4]; 188 for (andbit = 0; andbit < 32; andbit++) { 189 if (slotmap & (1 << andbit)) { 190 char *s = slotname; 191 slotname += strlen(s) + 1; 192 if ((newslot = slotnm_create(mp, andbit, s)) == NULL) { 193 slotnm_destroy(*slots); 194 *slots = NULL; 195 *nslots = 0; 196 return (-1); 197 } 198 if (lastslot == NULL) 199 *slots = lastslot = newslot; 200 else { 201 lastslot->snm_next = newslot; 202 lastslot = newslot; 203 } 204 (*nslots)++; 205 } 206 } 207 return (0); 208 } 209 210 int 211 did_physslot(did_t *did) 212 { 213 assert(did != NULL); 214 return (did->dp_physlot); 215 } 216 217 218 did_hash_t * 219 did_hash(did_t *did) 220 { 221 assert(did != NULL); 222 return (did->dp_hash); 223 } 224 225 did_t * 226 did_create(did_hash_t *dhash, di_node_t src, 227 int ibrd, int ibrdge, int irc, int ibus, di_prom_handle_t promtree) 228 { 229 topo_mod_t *mp; 230 did_t *np; 231 did_t *pd; 232 uint_t code; 233 uint_t reg; 234 235 mp = dhash->dph_mod; 236 if ((pd = did_hash_lookup(dhash, src)) != NULL) { 237 topo_mod_dprintf(mp, "Attempt to create existing did_t.\n"); 238 assert(ibus == TRUST_BDF || (pd->dp_bus == ibus)); 239 return (pd); 240 } 241 242 if ((np = topo_mod_zalloc(mp, sizeof (did_t))) == NULL) 243 return (NULL); 244 np->dp_mod = mp; 245 np->dp_src = src; 246 np->dp_hash = dhash; 247 248 /* 249 * We must have a reg prop and from it we extract the bus #, 250 * device #, and function #. 251 */ 252 if (di_uintprop_get(src, DI_REGPROP, ®, promtree) < 0) { 253 topo_mod_free(mp, np, sizeof (did_t)); 254 return (NULL); 255 } 256 np->dp_board = ibrd; 257 np->dp_bridge = ibrdge; 258 np->dp_rc = irc; 259 if (ibus == TRUST_BDF) 260 np->dp_bus = PCI_REG_BUS_G(reg); 261 else 262 np->dp_bus = ibus; 263 np->dp_dev = PCI_REG_DEV_G(reg); 264 np->dp_fn = PCI_REG_FUNC_G(reg); 265 np->dp_bdf = (PCI_REG_BUS_G(reg) << 8) | (PCI_REG_DEV_G(reg) << 3) | 266 PCI_REG_FUNC_G(reg); 267 /* 268 * There *may* be a class code we can capture. If there wasn't 269 * one, capture that fact by setting the class value to -1. 270 */ 271 if (di_uintprop_get(src, DI_CCPROP, &code, promtree) == 0) { 272 np->dp_class = GETCLASS(code); 273 np->dp_subclass = GETSUBCLASS(code); 274 } else { 275 np->dp_class = -1; 276 } 277 /* 278 * There *may* be a PCI-express capabilities register we can capture. 279 * If there wasn't one, the capabilities will be the out-of-bounds 280 * value of zero. 281 */ 282 (void) di_uintprop_get(src, "pcie-capid-reg", &np->dp_excap, 283 promtree); 284 /* 285 * There *may* be a physical slot number property we can capture. 286 */ 287 if (di_physlotinfo_get(mp, 288 src, np->dp_excap, &np->dp_physlot, &np->dp_physlot_label, 289 promtree) < 0) { 290 topo_mod_free(mp, np, sizeof (did_t)); 291 return (NULL); 292 } 293 /* 294 * There *may* be PCI slot info we can capture 295 */ 296 if (di_slotinfo_get(mp, src, &np->dp_nslots, &np->dp_slotnames, 297 promtree) < 0) { 298 if (np->dp_physlot_label != NULL) 299 topo_mod_strfree(mp, np->dp_physlot_label); 300 topo_mod_free(mp, np, sizeof (did_t)); 301 return (NULL); 302 } 303 did_hash_insert(dhash, src, np); 304 did_hold(np); 305 return (np); 306 } 307 308 did_t * 309 did_link_get(did_t *dp) 310 { 311 assert(dp != NULL); 312 return (dp->dp_link); 313 } 314 315 did_t * 316 did_chain_get(did_t *dp) 317 { 318 assert(dp != NULL); 319 return (dp->dp_chain); 320 } 321 322 void 323 did_link_set(tnode_t *head, did_t *tail) 324 { 325 did_t *hd, *pd; 326 327 assert(head != NULL); 328 pd = hd = topo_node_private(head); 329 assert(hd != NULL); 330 while ((hd = did_link_get(hd)) != NULL) 331 pd = hd; 332 pd->dp_link = tail; 333 tail->dp_link = NULL; 334 } 335 336 void 337 did_did_link_set(did_t *from, did_t *to) 338 { 339 assert(from != NULL && to != NULL); 340 from->dp_link = to; 341 } 342 343 void 344 did_did_chain_set(did_t *from, did_t *to) 345 { 346 assert(from != NULL && to != NULL); 347 from->dp_chain = to; 348 } 349 350 void 351 did_destroy(did_t *dp) 352 { 353 assert(dp != NULL); 354 355 /* 356 * did_destroy() is called only from did_hash_destroy() when 357 * all references to the did_t have been released. We can 358 * safely destroy the did_t. If at some later time, more 359 * fine-grained reference count control is desired, this 360 * code will need to change 361 */ 362 363 if (dp->dp_physlot_label != NULL) 364 topo_mod_strfree(dp->dp_mod, dp->dp_physlot_label); 365 slotnm_destroy(dp->dp_slotnames); 366 topo_mod_free(dp->dp_mod, dp, sizeof (did_t)); 367 } 368 369 void 370 did_hold(did_t *dp) 371 { 372 assert(dp != NULL); 373 dp->dp_refcnt++; 374 } 375 376 void 377 did_rele(did_t *dp) 378 { 379 assert(dp != NULL); 380 assert(dp->dp_refcnt > 0); 381 dp->dp_refcnt--; 382 } 383 384 di_node_t 385 did_dinode(did_t *dp) 386 { 387 assert(dp != NULL); 388 assert(dp->dp_src != NULL); 389 return (dp->dp_src); 390 } 391 392 topo_mod_t * 393 did_mod(did_t *dp) 394 { 395 assert(dp != NULL); 396 return (dp->dp_mod); 397 } 398 399 void 400 did_markrc(did_t *dp) 401 { 402 assert(dp != NULL); 403 dp->dp_excap |= PCIE_PCIECAP_DEV_TYPE_ROOT; 404 } 405 406 void 407 did_BDF(did_t *dp, int *bus, int *dev, int *fn) 408 { 409 assert(dp != NULL); 410 if (bus != NULL) 411 *bus = dp->dp_bus; 412 if (dev != NULL) 413 *dev = dp->dp_dev; 414 if (fn != NULL) 415 *fn = dp->dp_fn; 416 } 417 418 int 419 did_board(did_t *did) 420 { 421 assert(did != NULL); 422 return (did->dp_board); 423 } 424 425 int 426 did_bridge(did_t *did) 427 { 428 assert(did != NULL); 429 return (did->dp_bridge); 430 } 431 432 int 433 did_rc(did_t *did) 434 { 435 assert(did != NULL); 436 return (did->dp_rc); 437 } 438 439 static int 440 did_numlabels(did_t *dp) 441 { 442 assert(dp != NULL); 443 return (dp->dp_nslots); 444 } 445 446 int 447 did_excap(did_t *dp) 448 { 449 assert(dp != NULL); 450 return ((int)dp->dp_excap); 451 } 452 453 int 454 did_bdf(did_t *dp) 455 { 456 assert(dp != NULL); 457 return ((int)dp->dp_bdf); 458 } 459 460 const char * 461 did_label(did_t *dp, int dev) 462 { 463 slotnm_t *slot; 464 465 assert(dp != NULL); 466 if (dp->dp_physlot_label != NULL) 467 return (dp->dp_physlot_label); 468 for (slot = dp->dp_slotnames; slot != NULL; slot = slot->snm_next) 469 if (slot->snm_dev == dev) 470 break; 471 if (slot != NULL) 472 return (slot->snm_label); 473 return (NULL); 474 } 475 476 did_t * 477 did_find(did_hash_t *dhash, di_node_t dn) 478 { 479 return (did_hash_lookup(dhash, dn)); 480 } 481 482 int 483 pci_BDF_get(did_hash_t *dhash, di_node_t dn, int *bus, int *dev, int *fn) 484 { 485 did_t *dp; 486 487 if ((dp = did_find(dhash, dn)) == NULL) 488 return (-1); 489 *bus = dp->dp_bus; 490 *dev = dp->dp_dev; 491 *fn = dp->dp_fn; 492 did_rele(dp); 493 return (0); 494 } 495 496 int 497 pci_classcode_get(did_hash_t *dhash, 498 di_node_t dn, uint_t *class, uint_t *sub) 499 { 500 did_t *dp; 501 502 if ((dp = did_find(dhash, dn)) == NULL) 503 return (-1); 504 if (dp->dp_class < 0) { 505 did_rele(dp); 506 return (-1); 507 } 508 *class = dp->dp_class; 509 *sub = dp->dp_subclass; 510 did_rele(dp); 511 return (0); 512 } 513 514 int 515 pciex_cap_get(did_hash_t *dhash, di_node_t dn) 516 { 517 did_t *dp; 518 519 if ((dp = did_find(dhash, dn)) == NULL) 520 return (-1); 521 did_rele(dp); 522 return (dp->dp_excap); 523 } 524 525 int 526 did_inherit(did_t *pdp, did_t *dp) 527 { 528 /* 529 * If the child already has a label, we're done. 530 */ 531 assert(dp != NULL); 532 if (did_numlabels(dp) > 0) 533 return (0); 534 535 assert(pdp != NULL); 536 537 /* 538 * If the child and parent are the same, we're done. 539 */ 540 if (dp == pdp) 541 return (0); 542 543 if (pdp->dp_physlot_label != NULL) { 544 topo_mod_dprintf(dp->dp_mod, 545 "%p inherits physlot label from %p.\n", dp, pdp); 546 dp->dp_physlot_label = 547 topo_mod_strdup(dp->dp_mod, pdp->dp_physlot_label); 548 if (dp->dp_physlot_label == NULL) 549 return (-1); 550 } 551 if (slotnm_cp(pdp, dp, &dp->dp_nslots) < 0) 552 return (-1); 553 return (0); 554 } 555