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 2009 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 /* 27 * Copyright 2019 Joyent, Inc. 28 */ 29 30 #include <assert.h> 31 #include <alloca.h> 32 #include <string.h> 33 #include <strings.h> 34 #include <limits.h> 35 #include <sys/types.h> 36 #include <sys/pci.h> 37 #include <sys/pcie.h> 38 #include <sys/fm/protocol.h> 39 #include <fm/topo_mod.h> 40 #include <fm/topo_hc.h> 41 #include <libdevinfo.h> 42 #include <hostbridge.h> 43 #include <pcibus.h> 44 #include <did.h> 45 #include <did_props.h> 46 #include <fm/libtopo.h> 47 #include <pcidb.h> 48 49 static int ASRU_set(tnode_t *, did_t *, 50 const char *, const char *, const char *); 51 static int FRU_set(tnode_t *, did_t *, 52 const char *, const char *, const char *); 53 static int DEVprop_set(tnode_t *, did_t *, 54 const char *, const char *, const char *); 55 static int DRIVERprop_set(tnode_t *, did_t *, 56 const char *, const char *, const char *); 57 static int INSTprop_set(tnode_t *, did_t *, 58 const char *, const char *, const char *); 59 static int MODULEprop_set(tnode_t *, did_t *, 60 const char *, const char *, const char *); 61 static int EXCAP_set(tnode_t *, did_t *, 62 const char *, const char *, const char *); 63 static int BDF_set(tnode_t *, did_t *, 64 const char *, const char *, const char *); 65 static int label_set(tnode_t *, did_t *, 66 const char *, const char *, const char *); 67 static int maybe_di_chars_copy(tnode_t *, did_t *, 68 const char *, const char *, const char *); 69 static int maybe_di_uint_to_str(tnode_t *, did_t *, 70 const char *, const char *, const char *); 71 static int maybe_di_uint_to_dec_str(tnode_t *, did_t *, 72 const char *, const char *, const char *); 73 static int AADDR_set(tnode_t *, did_t *, 74 const char *, const char *, const char *); 75 static int maybe_pcidb_set(tnode_t *, did_t *, 76 const char *, const char *, const char *); 77 static int maybe_di_int_to_uint32(tnode_t *, did_t *, 78 const char *, const char *, const char *); 79 static int maybe_pcie_speed(tnode_t *, did_t *, 80 const char *, const char *, const char *); 81 static int maybe_pcie_supported_speed(tnode_t *, did_t *, 82 const char *, const char *, const char *); 83 static int maybe_pcie_target_speed(tnode_t *, did_t *, 84 const char *, const char *, const char *); 85 86 /* 87 * Arrays of "property translation routines" to set the properties a 88 * given type of topology node should have. 89 * 90 * Note that the label_set translation *MUST COME BEFORE* the FRU 91 * translation. For the near term we're setting the FRU fmri to 92 * be a legacy-hc style FMRI based on the label, so the label needs 93 * to have been set before we do the FRU translation. 94 * 95 */ 96 97 static const topo_pgroup_info_t io_pgroup = 98 { TOPO_PGROUP_IO, TOPO_STABILITY_PRIVATE, TOPO_STABILITY_PRIVATE, 1 }; 99 static const topo_pgroup_info_t pci_pgroup = 100 { TOPO_PGROUP_PCI, TOPO_STABILITY_PRIVATE, TOPO_STABILITY_PRIVATE, 1 }; 101 102 static const topo_pgroup_info_t protocol_pgroup = { 103 TOPO_PGROUP_PROTOCOL, 104 TOPO_STABILITY_PRIVATE, 105 TOPO_STABILITY_PRIVATE, 106 1 107 }; /* Request to create protocol will be ignored by libtopo */ 108 109 txprop_t Fn_common_props[] = { 110 { NULL, &io_pgroup, TOPO_IO_DEV, DEVprop_set }, 111 { DI_DEVTYPPROP, &io_pgroup, TOPO_IO_DEVTYPE, maybe_di_chars_copy }, 112 { DI_DEVIDPROP, &pci_pgroup, TOPO_PCI_DEVID, maybe_di_uint_to_str }, 113 { NULL, &io_pgroup, TOPO_IO_DRIVER, DRIVERprop_set }, 114 { NULL, &io_pgroup, TOPO_IO_INSTANCE, INSTprop_set }, 115 { NULL, &io_pgroup, TOPO_IO_MODULE, MODULEprop_set }, 116 { "serd_io_device_nonfatal_n", &io_pgroup, "serd_io_device_nonfatal_n", 117 maybe_di_uint_to_dec_str }, 118 { "serd_io_device_nonfatal_t", &io_pgroup, "serd_io_device_nonfatal_t", 119 maybe_di_chars_copy }, 120 { "serd_io_device_nonfatal_btlp_n", &io_pgroup, 121 "serd_io_device_nonfatal_btlp_n", maybe_di_uint_to_dec_str }, 122 { "serd_io_device_nonfatal_btlp_t", &io_pgroup, 123 "serd_io_device_nonfatal_btlp_t", maybe_di_chars_copy }, 124 { "serd_io_device_nonfatal_bdllp_n", &io_pgroup, 125 "serd_io_device_nonfatal_bdllp_n", maybe_di_uint_to_dec_str }, 126 { "serd_io_device_nonfatal_bdllp_t", &io_pgroup, 127 "serd_io_device_nonfatal_bdllp_t", maybe_di_chars_copy }, 128 { "serd_io_device_nonfatal_re_n", &io_pgroup, 129 "serd_io_device_nonfatal_re_n", maybe_di_uint_to_dec_str }, 130 { "serd_io_device_nonfatal_re_t", &io_pgroup, 131 "serd_io_device_nonfatal_re_t", maybe_di_chars_copy }, 132 { "serd_io_device_nonfatal_rto_n", &io_pgroup, 133 "serd_io_device_nonfatal_rto_n", maybe_di_uint_to_dec_str }, 134 { "serd_io_device_nonfatal_rto_t", &io_pgroup, 135 "serd_io_device_nonfatal_rto_t", maybe_di_chars_copy }, 136 { "serd_io_device_nonfatal_rnr_n", &io_pgroup, 137 "serd_io_device_nonfatal_rnr_n", maybe_di_uint_to_dec_str }, 138 { "serd_io_device_nonfatal_rnr_t", &io_pgroup, 139 "serd_io_pciex_corrlink-bus_rnr_t", maybe_di_chars_copy }, 140 { "serd_io_pciex_corrlink-bus_btlp_n", &io_pgroup, 141 "serd_io_pciex_corrlink-bus_btlp_n", maybe_di_uint_to_dec_str }, 142 { "serd_io_pciex_corrlink-bus_btlp_t", &io_pgroup, 143 "serd_io_pciex_corrlink-bus_btlp_t", maybe_di_chars_copy }, 144 { "serd_io_pciex_corrlink-bus_bdllp_n", &io_pgroup, 145 "serd_io_pciex_corrlink-bus_bdllp_n", maybe_di_uint_to_dec_str }, 146 { "serd_io_pciex_corrlink-bus_bdllp_t", &io_pgroup, 147 "serd_io_pciex_corrlink-bus_bdllp_t", maybe_di_chars_copy }, 148 { "serd_io_pciex_corrlink-bus_re_n", &io_pgroup, 149 "serd_io_pciex_corrlink-bus_re_n", maybe_di_uint_to_dec_str }, 150 { "serd_io_pciex_corrlink-bus_re_t", &io_pgroup, 151 "serd_io_pciex_corrlink-bus_re_t", maybe_di_chars_copy }, 152 { "serd_io_pciex_corrlink-bus_rto_n", &io_pgroup, 153 "serd_io_pciex_corrlink-bus_rto_n", maybe_di_uint_to_dec_str }, 154 { "serd_io_pciex_corrlink-bus_rto_t", &io_pgroup, 155 "serd_io_pciex_corrlink-bus_rto_t", maybe_di_chars_copy }, 156 { "serd_io_pciex_corrlink-bus_rnr_n", &io_pgroup, 157 "serd_io_pciex_corrlink-bus_rnr_n", maybe_di_uint_to_dec_str }, 158 { "serd_io_pciex_corrlink-bus_rnr_t", &io_pgroup, 159 "serd_io_pciex_corrlink-bus_rnr_t", maybe_di_chars_copy }, 160 { NULL, &pci_pgroup, TOPO_PCI_EXCAP, EXCAP_set }, 161 { DI_CLASSPROP, &pci_pgroup, TOPO_PCI_CLASS, maybe_di_uint_to_str }, 162 { DI_VENDIDPROP, &pci_pgroup, TOPO_PCI_VENDID, maybe_di_uint_to_str }, 163 { DI_AADDRPROP, &pci_pgroup, TOPO_PCI_AADDR, AADDR_set }, 164 { NULL, &protocol_pgroup, TOPO_PROP_LABEL, label_set }, 165 { NULL, &protocol_pgroup, TOPO_PROP_FRU, FRU_set }, 166 { NULL, &protocol_pgroup, TOPO_PROP_ASRU, ASRU_set }, 167 /* 168 * This entry will attempt to set the following three properties via 169 * lookups in the PCI database: 170 * - vendor-name 171 * - device-name 172 * - subsystem-name 173 */ 174 { NULL, &pci_pgroup, NULL, maybe_pcidb_set } 175 }; 176 177 txprop_t Dev_common_props[] = { 178 { NULL, &protocol_pgroup, TOPO_PROP_LABEL, label_set }, 179 { NULL, &protocol_pgroup, TOPO_PROP_FRU, FRU_set }, 180 { NULL, &protocol_pgroup, TOPO_PROP_ASRU, ASRU_set }, 181 { DI_PCIE_MAX_WIDTH, &pci_pgroup, TOPO_PCI_MAX_WIDTH, 182 maybe_di_int_to_uint32 }, 183 { DI_PCIE_CUR_WIDTH, &pci_pgroup, TOPO_PCI_CUR_WIDTH, 184 maybe_di_int_to_uint32 }, 185 { DI_PCIE_MAX_SPEED, &pci_pgroup, TOPO_PCI_MAX_SPEED, 186 maybe_pcie_speed }, 187 { DI_PCIE_CUR_SPEED, &pci_pgroup, TOPO_PCI_CUR_SPEED, 188 maybe_pcie_speed }, 189 { DI_PCIE_SUP_SPEEDS, &pci_pgroup, TOPO_PCI_SUP_SPEED, 190 maybe_pcie_supported_speed }, 191 { NULL, &pci_pgroup, TOPO_PCI_ADMIN_SPEED, maybe_pcie_target_speed } 192 }; 193 194 txprop_t Bus_common_props[] = { 195 { DI_DEVTYPPROP, &io_pgroup, TOPO_IO_DEVTYPE, maybe_di_chars_copy }, 196 { NULL, &io_pgroup, TOPO_IO_DRIVER, DRIVERprop_set }, 197 { NULL, &io_pgroup, TOPO_IO_INSTANCE, INSTprop_set }, 198 { NULL, &io_pgroup, TOPO_IO_MODULE, MODULEprop_set }, 199 { NULL, &protocol_pgroup, TOPO_PROP_LABEL, label_set }, 200 { NULL, &protocol_pgroup, TOPO_PROP_FRU, FRU_set }, 201 { NULL, &protocol_pgroup, TOPO_PROP_ASRU, ASRU_set } 202 }; 203 204 txprop_t RC_common_props[] = { 205 { NULL, &io_pgroup, TOPO_IO_DEV, DEVprop_set }, 206 { DI_DEVTYPPROP, &io_pgroup, TOPO_IO_DEVTYPE, maybe_di_chars_copy }, 207 { NULL, &io_pgroup, TOPO_IO_DRIVER, DRIVERprop_set }, 208 { NULL, &io_pgroup, TOPO_IO_INSTANCE, INSTprop_set }, 209 { NULL, &io_pgroup, TOPO_IO_MODULE, MODULEprop_set }, 210 { NULL, &pci_pgroup, TOPO_PCI_EXCAP, EXCAP_set }, 211 { NULL, &pci_pgroup, TOPO_PCI_BDF, BDF_set }, 212 { NULL, &protocol_pgroup, TOPO_PROP_ASRU, ASRU_set }, 213 /* 214 * These props need to be put at the end of table. x86pi has its 215 * own way to set them. 216 */ 217 { NULL, &protocol_pgroup, TOPO_PROP_LABEL, label_set }, 218 { NULL, &protocol_pgroup, TOPO_PROP_FRU, FRU_set } 219 }; 220 221 txprop_t ExHB_common_props[] = { 222 { NULL, &protocol_pgroup, TOPO_PROP_ASRU, ASRU_set }, 223 /* 224 * These props need to be put at the end of table. x86pi has its 225 * own way to set them. 226 */ 227 { NULL, &protocol_pgroup, TOPO_PROP_LABEL, label_set }, 228 { NULL, &protocol_pgroup, TOPO_PROP_FRU, FRU_set } 229 }; 230 231 txprop_t IOB_common_props[] = { 232 { NULL, &protocol_pgroup, TOPO_PROP_LABEL, label_set }, 233 { NULL, &protocol_pgroup, TOPO_PROP_FRU, FRU_set }, 234 { NULL, &protocol_pgroup, TOPO_PROP_ASRU, ASRU_set } 235 }; 236 237 txprop_t HB_common_props[] = { 238 { NULL, &io_pgroup, TOPO_IO_DEV, DEVprop_set }, 239 { NULL, &io_pgroup, TOPO_IO_DRIVER, DRIVERprop_set }, 240 { NULL, &io_pgroup, TOPO_IO_INSTANCE, INSTprop_set }, 241 { NULL, &io_pgroup, TOPO_IO_MODULE, MODULEprop_set }, 242 { NULL, &protocol_pgroup, TOPO_PROP_ASRU, ASRU_set }, 243 /* 244 * These props need to be put at the end of table. x86pi has its 245 * own way to set them. 246 */ 247 { NULL, &protocol_pgroup, TOPO_PROP_LABEL, label_set }, 248 { NULL, &protocol_pgroup, TOPO_PROP_FRU, FRU_set } 249 }; 250 251 int Bus_propcnt = sizeof (Bus_common_props) / sizeof (txprop_t); 252 int Dev_propcnt = sizeof (Dev_common_props) / sizeof (txprop_t); 253 int ExHB_propcnt = sizeof (ExHB_common_props) / sizeof (txprop_t); 254 int HB_propcnt = sizeof (HB_common_props) / sizeof (txprop_t); 255 int IOB_propcnt = sizeof (IOB_common_props) / sizeof (txprop_t); 256 int RC_propcnt = sizeof (RC_common_props) / sizeof (txprop_t); 257 int Fn_propcnt = sizeof (Fn_common_props) / sizeof (txprop_t); 258 259 /* 260 * If this devinfo node came originally from OBP data, we'll have prom 261 * properties associated with the node where we can find properties of 262 * interest. We ignore anything after the the first four bytes of the 263 * property, and interpet those first four bytes as our unsigned 264 * integer. If we don't find the property or it's not large enough, 265 * 'val' will remained unchanged and we'll return -1. Otherwise 'val' 266 * gets updated with the property value and we return 0. 267 */ 268 static int 269 promprop2uint(topo_mod_t *mod, di_node_t n, const char *propnm, uint_t *val) 270 { 271 di_prom_handle_t ptp = DI_PROM_HANDLE_NIL; 272 di_prom_prop_t pp = DI_PROM_PROP_NIL; 273 uchar_t *buf; 274 275 if ((ptp = topo_mod_prominfo(mod)) == DI_PROM_HANDLE_NIL) 276 return (-1); 277 278 while ((pp = di_prom_prop_next(ptp, n, pp)) != DI_PROM_PROP_NIL) { 279 if (strcmp(di_prom_prop_name(pp), propnm) == 0) { 280 if (di_prom_prop_data(pp, &buf) < sizeof (uint_t)) 281 continue; 282 bcopy(buf, val, sizeof (uint_t)); 283 return (0); 284 } 285 } 286 return (-1); 287 } 288 289 /* 290 * If this devinfo node was added by the PCI hotplug framework it 291 * doesn't have the PROM properties, but hopefully has the properties 292 * we're looking for attached directly to the devinfo node. We only 293 * care about the first four bytes of the property, which we read as 294 * our unsigned integer. The remaining bytes are ignored. If we 295 * don't find the property we're looking for, or can't get its value, 296 * 'val' remains unchanged and we return -1. Otherwise 'val' gets the 297 * property value and we return 0. 298 */ 299 static int 300 hwprop2uint(di_node_t n, const char *propnm, uint_t *val) 301 { 302 di_prop_t hp = DI_PROP_NIL; 303 uchar_t *buf; 304 305 while ((hp = di_prop_next(n, hp)) != DI_PROP_NIL) { 306 if (strcmp(di_prop_name(hp), propnm) == 0) { 307 if (di_prop_bytes(hp, &buf) < sizeof (uint_t)) 308 continue; 309 bcopy(buf, val, sizeof (uint_t)); 310 return (0); 311 } 312 } 313 return (-1); 314 } 315 316 int 317 di_uintprop_get(topo_mod_t *mod, di_node_t n, const char *pnm, uint_t *pv) 318 { 319 if (hwprop2uint(n, pnm, pv) < 0) 320 if (promprop2uint(mod, n, pnm, pv) < 0) 321 return (-1); 322 return (0); 323 } 324 325 int 326 di_bytes_get(topo_mod_t *mod, di_node_t n, const char *pnm, int *sz, 327 uchar_t **db) 328 { 329 di_prom_handle_t ptp = DI_PROM_HANDLE_NIL; 330 di_prom_prop_t pp = DI_PROM_PROP_NIL; 331 di_prop_t hp = DI_PROP_NIL; 332 333 if ((ptp = topo_mod_prominfo(mod)) == DI_PROM_HANDLE_NIL) 334 return (-1); 335 336 *sz = -1; 337 while ((hp = di_prop_next(n, hp)) != DI_PROP_NIL) { 338 if (strcmp(di_prop_name(hp), pnm) == 0) { 339 if ((*sz = di_prop_bytes(hp, db)) < 0) 340 continue; 341 break; 342 } 343 } 344 if (*sz < 0) { 345 while ((pp = di_prom_prop_next(ptp, n, pp)) != 346 DI_PROM_PROP_NIL) { 347 if (strcmp(di_prom_prop_name(pp), pnm) == 0) { 348 *sz = di_prom_prop_data(pp, db); 349 if (*sz < 0) 350 continue; 351 break; 352 } 353 } 354 } 355 356 if (*sz < 0) 357 return (-1); 358 return (0); 359 } 360 361 /* 362 * fix_dev_prop -- sometimes di_devfs_path() doesn't tell the whole 363 * story, leaving off the device and function number. Chances are if 364 * devfs doesn't put these on then we'll never see this device as an 365 * error detector called out in an ereport. Unfortunately, there are 366 * races and we sometimes do get ereports from devices that devfs 367 * decides aren't there. For example, the error injector card seems 368 * to bounce in and out of existence according to devfs. We tack on 369 * the missing dev and fn here so that the DEV property used to look 370 * up the topology node is correct. 371 */ 372 static char * 373 dev_path_fix(topo_mod_t *mp, char *path, int devno, int fnno) 374 { 375 char *lastslash; 376 char *newpath; 377 int need; 378 379 /* 380 * We only care about the last component of the dev path. If 381 * we don't find a slash, something is weird. 382 */ 383 lastslash = strrchr(path, '/'); 384 assert(lastslash != NULL); 385 386 /* 387 * If an @ sign is present in the last component, the 388 * di_devfs_path() result had the device,fn unit-address. 389 * In that case there's nothing we need do. 390 */ 391 if (strchr(lastslash, '@') != NULL) 392 return (path); 393 394 if (fnno == 0) 395 need = snprintf(NULL, 0, "%s@%x", path, devno); 396 else 397 need = snprintf(NULL, 0, "%s@%x,%x", path, devno, fnno); 398 need++; 399 400 if ((newpath = topo_mod_alloc(mp, need)) == NULL) { 401 topo_mod_strfree(mp, path); 402 return (NULL); 403 } 404 405 if (fnno == 0) 406 (void) snprintf(newpath, need, "%s@%x", path, devno); 407 else 408 (void) snprintf(newpath, need, "%s@%x,%x", path, devno, fnno); 409 410 topo_mod_strfree(mp, path); 411 return (newpath); 412 } 413 414 /* 415 * dev_for_hostbridge() -- For hostbridges we truncate the devfs path 416 * after the first element in the bus address. 417 */ 418 static char * 419 dev_for_hostbridge(topo_mod_t *mp, char *path) 420 { 421 char *lastslash; 422 char *newpath; 423 char *comma; 424 int plen; 425 426 plen = strlen(path) + 1; 427 428 /* 429 * We only care about the last component of the dev path. If 430 * we don't find a slash, something is weird. 431 */ 432 lastslash = strrchr(path, '/'); 433 assert(lastslash != NULL); 434 435 /* 436 * Find the comma in the last component component@x,y, and 437 * truncate the comma and any following number. 438 */ 439 comma = strchr(lastslash, ','); 440 assert(comma != NULL); 441 442 *comma = '\0'; 443 if ((newpath = topo_mod_strdup(mp, path)) == NULL) { 444 topo_mod_free(mp, path, plen); 445 return (NULL); 446 } 447 448 *comma = ','; 449 topo_mod_free(mp, path, plen); 450 return (newpath); 451 } 452 453 /*ARGSUSED*/ 454 static int 455 ASRU_set(tnode_t *tn, did_t *pd, 456 const char *dpnm, const char *tpgrp, const char *tpnm) 457 { 458 topo_mod_t *mp; 459 nvlist_t *fmri; 460 char *dnpath, *path, *fpath, *nm; 461 int d, e, f; 462 463 /* 464 * If this topology node represents a function of device, 465 * set the ASRU to a dev scheme FMRI based on the value of 466 * di_devfs_path(). If that path is NULL, set the ASRU to 467 * be the resource describing this topology node. If this 468 * isn't a function, inherit any ASRU from the parent. 469 */ 470 mp = did_mod(pd); 471 nm = topo_node_name(tn); 472 if ((strcmp(nm, PCI_BUS) == 0 && did_gettnode(pd) && 473 strcmp(topo_node_name(did_gettnode(pd)), HOSTBRIDGE) == 0) || 474 strcmp(nm, PCI_FUNCTION) == 0 || strcmp(nm, PCIEX_FUNCTION) == 0 || 475 strcmp(nm, PCIEX_ROOT) == 0) { 476 if ((dnpath = di_devfs_path(did_dinode(pd))) != NULL) { 477 /* 478 * Dup the path, dev_path_fix() may replace it and 479 * dev_path_fix() wouldn't know to use 480 * di_devfs_path_free() 481 */ 482 if ((path = topo_mod_strdup(mp, dnpath)) == NULL) { 483 di_devfs_path_free(dnpath); 484 return (topo_mod_seterrno(mp, EMOD_NOMEM)); 485 } 486 di_devfs_path_free(dnpath); 487 did_BDF(pd, NULL, &d, &f); 488 if ((fpath = dev_path_fix(mp, path, d, f)) == NULL) 489 return (topo_mod_seterrno(mp, EMOD_NOMEM)); 490 491 fmri = topo_mod_devfmri(mp, FM_DEV_SCHEME_VERSION, 492 fpath, NULL); 493 if (fmri == NULL) { 494 topo_mod_dprintf(mp, 495 "dev:///%s fmri creation failed.\n", fpath); 496 topo_mod_strfree(mp, fpath); 497 return (-1); 498 } 499 topo_mod_strfree(mp, fpath); 500 } else { 501 topo_mod_dprintf(mp, "NULL di_devfs_path.\n"); 502 if (topo_prop_get_fmri(tn, TOPO_PGROUP_PROTOCOL, 503 TOPO_PROP_RESOURCE, &fmri, &e) < 0) 504 return (topo_mod_seterrno(mp, e)); 505 } 506 if (topo_node_asru_set(tn, fmri, 0, &e) < 0) { 507 nvlist_free(fmri); 508 return (topo_mod_seterrno(mp, e)); 509 } 510 nvlist_free(fmri); 511 return (0); 512 } 513 (void) topo_node_asru_set(tn, NULL, 0, &e); 514 515 return (0); 516 } 517 518 /* 519 * Set the FRU property to the hc fmri of this tnode 520 */ 521 int 522 FRU_fmri_set(topo_mod_t *mp, tnode_t *tn) 523 { 524 nvlist_t *fmri; 525 int err, e; 526 527 if (topo_node_resource(tn, &fmri, &err) < 0 || 528 fmri == NULL) { 529 topo_mod_dprintf(mp, "FRU_fmri_set error: %s\n", 530 topo_strerror(topo_mod_errno(mp))); 531 return (topo_mod_seterrno(mp, err)); 532 } 533 e = topo_node_fru_set(tn, fmri, 0, &err); 534 nvlist_free(fmri); 535 if (e < 0) 536 return (topo_mod_seterrno(mp, err)); 537 return (0); 538 } 539 540 tnode_t * 541 find_predecessor(tnode_t *tn, char *mod_name) 542 { 543 tnode_t *pnode = topo_node_parent(tn); 544 545 while (pnode && (strcmp(topo_node_name(pnode), mod_name) != 0)) { 546 pnode = topo_node_parent(pnode); 547 } 548 return (pnode); 549 } 550 551 static int 552 use_predecessor_fru(tnode_t *tn, char *mod_name) 553 { 554 tnode_t *pnode = NULL; 555 nvlist_t *fru = NULL; 556 int err = 0; 557 558 if ((pnode = find_predecessor(tn, mod_name)) == NULL) 559 return (-1); 560 if ((pnode = topo_node_parent(pnode)) == NULL) 561 return (-1); 562 if (topo_node_fru(pnode, &fru, NULL, &err) != 0) 563 return (-1); 564 565 (void) topo_node_fru_set(tn, fru, 0, &err); 566 nvlist_free(fru); 567 568 return (0); 569 } 570 571 static int 572 use_predecessor_label(topo_mod_t *mod, tnode_t *tn, char *mod_name) 573 { 574 tnode_t *pnode = NULL; 575 int err = 0; 576 char *plabel = NULL; 577 578 if ((pnode = find_predecessor(tn, mod_name)) == NULL) 579 return (-1); 580 if ((pnode = topo_node_parent(pnode)) == NULL) 581 return (-1); 582 if (topo_node_label(pnode, &plabel, &err) != 0 || plabel == NULL) 583 return (-1); 584 585 (void) topo_node_label_set(tn, plabel, &err); 586 587 topo_mod_strfree(mod, plabel); 588 589 return (0); 590 } 591 592 593 /*ARGSUSED*/ 594 static int 595 FRU_set(tnode_t *tn, did_t *pd, 596 const char *dpnm, const char *tpgrp, const char *tpnm) 597 { 598 topo_mod_t *mp; 599 char *nm; 600 int e = 0, err = 0; 601 602 nm = topo_node_name(tn); 603 mp = did_mod(pd); 604 605 /* 606 * If this is a PCIEX_BUS and its parent is a PCIEX_ROOT, 607 * check for a CPUBOARD predecessor. If found, inherit its 608 * parent's FRU. Otherwise, continue with FRU set. 609 */ 610 if ((strcmp(nm, PCIEX_BUS) == 0) && 611 (strcmp(topo_node_name(topo_node_parent(tn)), PCIEX_ROOT) == 0)) { 612 613 if (use_predecessor_fru(tn, CPUBOARD) == 0) 614 return (0); 615 } 616 /* 617 * If this topology node represents something other than an 618 * ioboard or a device that implements a slot, inherit the 619 * parent's FRU value. If there is no label, inherit our 620 * parent's FRU value. Otherwise, munge up an fmri based on 621 * the label. 622 */ 623 if (strcmp(nm, IOBOARD) != 0 && strcmp(nm, PCI_DEVICE) != 0 && 624 strcmp(nm, PCIEX_DEVICE) != 0 && strcmp(nm, PCIEX_BUS) != 0) { 625 (void) topo_node_fru_set(tn, NULL, 0, &e); 626 return (0); 627 } 628 629 /* 630 * If ioboard, set fru fmri to hc fmri 631 */ 632 if (strcmp(nm, IOBOARD) == 0) { 633 e = FRU_fmri_set(mp, tn); 634 return (e); 635 } else if (strcmp(nm, PCI_DEVICE) == 0 || 636 strcmp(nm, PCIEX_DEVICE) == 0 || strcmp(nm, PCIEX_BUS) == 0) { 637 nvlist_t *in, *out; 638 639 mp = did_mod(pd); 640 if (topo_mod_nvalloc(mp, &in, NV_UNIQUE_NAME) != 0) 641 return (topo_mod_seterrno(mp, EMOD_FMRI_NVL)); 642 if (nvlist_add_uint64(in, "nv1", (uintptr_t)pd) != 0) { 643 nvlist_free(in); 644 return (topo_mod_seterrno(mp, EMOD_NOMEM)); 645 } 646 if (topo_method_invoke(tn, 647 TOPO_METH_FRU_COMPUTE, TOPO_METH_FRU_COMPUTE_VERSION, 648 in, &out, &err) != 0) { 649 nvlist_free(in); 650 return (topo_mod_seterrno(mp, err)); 651 } 652 nvlist_free(in); 653 (void) topo_node_fru_set(tn, out, 0, &err); 654 nvlist_free(out); 655 } else 656 (void) topo_node_fru_set(tn, NULL, 0, &err); 657 658 return (0); 659 } 660 661 /*ARGSUSED*/ 662 static int 663 label_set(tnode_t *tn, did_t *pd, 664 const char *dpnm, const char *tpgrp, const char *tpnm) 665 { 666 topo_mod_t *mp; 667 nvlist_t *in, *out; 668 char *label; 669 int err; 670 671 mp = did_mod(pd); 672 /* 673 * If this is a PCIEX_BUS and its parent is a PCIEX_ROOT, 674 * check for a CPUBOARD predecessor. If found, inherit its 675 * parent's Label. Otherwise, continue with label set. 676 */ 677 if ((strcmp(topo_node_name(tn), PCIEX_BUS) == 0) && 678 (strcmp(topo_node_name(topo_node_parent(tn)), PCIEX_ROOT) == 0)) { 679 680 if (use_predecessor_label(mp, tn, CPUBOARD) == 0) 681 return (0); 682 } 683 if (topo_mod_nvalloc(mp, &in, NV_UNIQUE_NAME) != 0) 684 return (topo_mod_seterrno(mp, EMOD_FMRI_NVL)); 685 if (nvlist_add_uint64(in, TOPO_METH_LABEL_ARG_NVL, (uintptr_t)pd) != 686 0) { 687 nvlist_free(in); 688 return (topo_mod_seterrno(mp, EMOD_NOMEM)); 689 } 690 if (topo_method_invoke(tn, 691 TOPO_METH_LABEL, TOPO_METH_LABEL_VERSION, in, &out, &err) != 0) { 692 nvlist_free(in); 693 return (topo_mod_seterrno(mp, err)); 694 } 695 nvlist_free(in); 696 if (out != NULL && 697 nvlist_lookup_string(out, TOPO_METH_LABEL_RET_STR, &label) == 0) { 698 if (topo_prop_set_string(tn, TOPO_PGROUP_PROTOCOL, 699 TOPO_PROP_LABEL, TOPO_PROP_IMMUTABLE, label, &err) != 0) { 700 nvlist_free(out); 701 return (topo_mod_seterrno(mp, err)); 702 } 703 nvlist_free(out); 704 } 705 return (0); 706 } 707 708 /*ARGSUSED*/ 709 static int 710 EXCAP_set(tnode_t *tn, did_t *pd, 711 const char *dpnm, const char *tpgrp, const char *tpnm) 712 { 713 int excap = did_excap(pd); 714 int err; 715 int e = 0; 716 717 switch (excap & PCIE_PCIECAP_DEV_TYPE_MASK) { 718 case PCIE_PCIECAP_DEV_TYPE_ROOT: 719 e = topo_prop_set_string(tn, TOPO_PGROUP_PCI, 720 TOPO_PCI_EXCAP, TOPO_PROP_IMMUTABLE, PCIEX_ROOT, &err); 721 break; 722 case PCIE_PCIECAP_DEV_TYPE_UP: 723 e = topo_prop_set_string(tn, TOPO_PGROUP_PCI, 724 TOPO_PCI_EXCAP, TOPO_PROP_IMMUTABLE, PCIEX_SWUP, &err); 725 break; 726 case PCIE_PCIECAP_DEV_TYPE_DOWN: 727 e = topo_prop_set_string(tn, TOPO_PGROUP_PCI, 728 TOPO_PCI_EXCAP, TOPO_PROP_IMMUTABLE, PCIEX_SWDWN, &err); 729 break; 730 case PCIE_PCIECAP_DEV_TYPE_PCI2PCIE: 731 e = topo_prop_set_string(tn, TOPO_PGROUP_PCI, 732 TOPO_PCI_EXCAP, TOPO_PROP_IMMUTABLE, PCIEX_BUS, &err); 733 break; 734 case PCIE_PCIECAP_DEV_TYPE_PCIE2PCI: 735 e = topo_prop_set_string(tn, TOPO_PGROUP_PCI, 736 TOPO_PCI_EXCAP, TOPO_PROP_IMMUTABLE, PCI_BUS, &err); 737 break; 738 case PCIE_PCIECAP_DEV_TYPE_PCIE_DEV: 739 e = topo_prop_set_string(tn, TOPO_PGROUP_PCI, 740 TOPO_PCI_EXCAP, TOPO_PROP_IMMUTABLE, PCIEX_DEVICE, &err); 741 break; 742 } 743 if (e != 0) 744 return (topo_mod_seterrno(did_mod(pd), err)); 745 return (0); 746 } 747 748 /*ARGSUSED*/ 749 static int 750 DEVprop_set(tnode_t *tn, did_t *pd, 751 const char *dpnm, const char *tpgrp, const char *tpnm) 752 { 753 topo_mod_t *mp; 754 char *dnpath; 755 char *path, *fpath; 756 int d, f; 757 int err, e; 758 759 mp = did_mod(pd); 760 if ((dnpath = di_devfs_path(did_dinode(pd))) == NULL) { 761 topo_mod_dprintf(mp, "NULL di_devfs_path.\n"); 762 return (topo_mod_seterrno(mp, ETOPO_PROP_NOENT)); 763 } 764 if ((path = topo_mod_strdup(mp, dnpath)) == NULL) { 765 di_devfs_path_free(dnpath); 766 return (-1); 767 } 768 di_devfs_path_free(dnpath); 769 770 /* The DEV path is modified for hostbridges */ 771 if (strcmp(topo_node_name(tn), HOSTBRIDGE) == 0) { 772 fpath = dev_for_hostbridge(did_mod(pd), path); 773 } else { 774 did_BDF(pd, NULL, &d, &f); 775 fpath = dev_path_fix(mp, path, d, f); 776 } 777 if (fpath == NULL) 778 return (-1); 779 e = topo_prop_set_string(tn, 780 tpgrp, tpnm, TOPO_PROP_IMMUTABLE, fpath, &err); 781 topo_mod_strfree(mp, fpath); 782 if (e != 0) 783 return (topo_mod_seterrno(mp, err)); 784 return (0); 785 } 786 787 /*ARGSUSED*/ 788 static int 789 DRIVERprop_set(tnode_t *tn, did_t *pd, 790 const char *dpnm, const char *tpgrp, const char *tpnm) 791 { 792 char *dnm; 793 int err; 794 795 if ((dnm = di_driver_name(did_dinode(pd))) == NULL) 796 return (0); 797 if (topo_prop_set_string(tn, 798 tpgrp, tpnm, TOPO_PROP_IMMUTABLE, dnm, &err) < 0) 799 return (topo_mod_seterrno(did_mod(pd), err)); 800 801 return (0); 802 } 803 804 /*ARGSUSED*/ 805 static int 806 INSTprop_set(tnode_t *tn, did_t *pd, 807 const char *dpnm, const char *tpgrp, const char *tpnm) 808 { 809 int inst, err; 810 811 if ((inst = di_instance(did_dinode(pd))) == -1) 812 return (0); 813 if (topo_prop_set_uint32(tn, 814 tpgrp, tpnm, TOPO_PROP_IMMUTABLE, inst, &err) < 0) 815 return (topo_mod_seterrno(did_mod(pd), err)); 816 817 return (0); 818 } 819 820 /*ARGSUSED*/ 821 static int 822 MODULEprop_set(tnode_t *tn, did_t *pd, 823 const char *dpnm, const char *tpgrp, const char *tpnm) 824 { 825 nvlist_t *mod; 826 topo_mod_t *mp; 827 char *dnm; 828 int err; 829 830 if ((dnm = di_driver_name(did_dinode(pd))) == NULL) 831 return (0); 832 833 mp = did_mod(pd); 834 if ((mod = topo_mod_modfmri(mp, FM_MOD_SCHEME_VERSION, dnm)) == NULL) 835 return (0); /* driver maybe detached, return success */ 836 837 if (topo_prop_set_fmri(tn, tpgrp, tpnm, TOPO_PROP_IMMUTABLE, mod, 838 &err) < 0) { 839 nvlist_free(mod); 840 return (topo_mod_seterrno(mp, err)); 841 } 842 nvlist_free(mod); 843 844 return (0); 845 } 846 847 /*ARGSUSED*/ 848 static int 849 maybe_di_chars_copy(tnode_t *tn, did_t *pd, 850 const char *dpnm, const char *tpgrp, const char *tpnm) 851 { 852 topo_mod_t *mp; 853 uchar_t *typbuf; 854 char *tmpbuf; 855 int sz = -1; 856 int err, e; 857 858 if (di_bytes_get(did_mod(pd), did_dinode(pd), dpnm, &sz, &typbuf) < 0) 859 return (0); 860 mp = did_mod(pd); 861 862 if ((tmpbuf = topo_mod_alloc(mp, sz + 1)) == NULL) 863 return (topo_mod_seterrno(mp, EMOD_NOMEM)); 864 865 bcopy(typbuf, tmpbuf, sz); 866 tmpbuf[sz] = 0; 867 e = topo_prop_set_string(tn, 868 tpgrp, tpnm, TOPO_PROP_IMMUTABLE, tmpbuf, &err); 869 topo_mod_free(mp, tmpbuf, sz + 1); 870 if (e != 0) 871 return (topo_mod_seterrno(mp, err)); 872 return (0); 873 } 874 875 static int 876 uint_to_strprop(topo_mod_t *mp, uint_t v, tnode_t *tn, 877 const char *tpgrp, const char *tpnm) 878 { 879 char str[21]; /* sizeof (UINT64_MAX) + '\0' */ 880 int e; 881 882 (void) snprintf(str, 21, "%x", v); 883 if (topo_prop_set_string(tn, 884 tpgrp, tpnm, TOPO_PROP_IMMUTABLE, str, &e) < 0) 885 return (topo_mod_seterrno(mp, e)); 886 return (0); 887 } 888 889 static int 890 maybe_di_uint_to_str(tnode_t *tn, did_t *pd, 891 const char *dpnm, const char *tpgrp, const char *tpnm) 892 { 893 uint_t v; 894 895 if (di_uintprop_get(did_mod(pd), did_dinode(pd), dpnm, &v) < 0) 896 return (0); 897 898 return (uint_to_strprop(did_mod(pd), v, tn, tpgrp, tpnm)); 899 } 900 901 static int 902 uint_to_dec_strprop(topo_mod_t *mp, uint_t v, tnode_t *tn, 903 const char *tpgrp, const char *tpnm) 904 { 905 char str[21]; /* sizeof (UINT64_MAX) + '\0' */ 906 int e; 907 908 (void) snprintf(str, 21, "%d", v); 909 if (topo_prop_set_string(tn, 910 tpgrp, tpnm, TOPO_PROP_IMMUTABLE, str, &e) < 0) 911 return (topo_mod_seterrno(mp, e)); 912 return (0); 913 } 914 915 static int 916 maybe_di_uint_to_dec_str(tnode_t *tn, did_t *pd, 917 const char *dpnm, const char *tpgrp, const char *tpnm) 918 { 919 uint_t v; 920 921 if (di_uintprop_get(did_mod(pd), did_dinode(pd), dpnm, &v) < 0) 922 return (0); 923 924 return (uint_to_dec_strprop(did_mod(pd), v, tn, tpgrp, tpnm)); 925 } 926 927 static int 928 AADDR_set(tnode_t *tn, did_t *pd, const char *dpnm, const char *tpgrp, 929 const char *tpnm) 930 { 931 topo_mod_t *mp; 932 uchar_t *typbuf; 933 int sz = -1; 934 int err, e; 935 936 if (di_bytes_get(did_mod(pd), did_dinode(pd), dpnm, &sz, &typbuf) < 0) 937 return (0); 938 939 mp = did_mod(pd); 940 941 e = topo_prop_set_uint32_array(tn, tpgrp, tpnm, TOPO_PROP_IMMUTABLE, 942 /*LINTED*/ 943 (uint32_t *)typbuf, sz/4, &err); 944 945 if (e != 0) 946 return (topo_mod_seterrno(mp, err)); 947 return (0); 948 } 949 950 /*ARGSUSED*/ 951 static int 952 BDF_set(tnode_t *tn, did_t *pd, const char *dpnm, const char *tpgrp, 953 const char *tpnm) 954 { 955 int bdf; 956 char str[23]; /* '0x' + sizeof (UINT64_MAX) + '\0' */ 957 int e; 958 959 if ((bdf = did_bdf(pd)) <= 0) 960 return (0); 961 962 (void) snprintf(str, 23, "0x%x", bdf); 963 if (topo_prop_set_string(tn, 964 tpgrp, tpnm, TOPO_PROP_IMMUTABLE, str, &e) < 0) 965 return (topo_mod_seterrno(did_mod(pd), e)); 966 return (0); 967 } 968 969 /*ARGSUSED*/ 970 static int 971 maybe_pcidb_set(tnode_t *tn, did_t *pd, const char *dpnm, const char *tpgrp, 972 const char *tpnm) 973 { 974 const char *vname, *dname = NULL, *ssname = NULL; 975 uint_t vid, pid, svid, ssid; 976 pcidb_vendor_t *pciv; 977 pcidb_device_t *pcid; 978 pcidb_subvd_t *pcis = NULL; 979 pcidb_hdl_t *pcih; 980 topo_mod_t *mod = did_mod(pd); 981 int err; 982 983 /* 984 * At a minimum, we need the vid/devid of the device to be able to 985 * lookup anything in the PCI database. So if we fail to look either 986 * of those up, bail out. 987 */ 988 if (di_uintprop_get(did_mod(pd), did_dinode(pd), DI_VENDIDPROP, &vid) < 989 0 || di_uintprop_get(did_mod(pd), did_dinode(pd), DI_DEVIDPROP, 990 &pid) < 0) { 991 return (0); 992 } 993 /* 994 * If we fail to lookup the vendor, by the vid that's also a 995 * deal-breaker. 996 */ 997 if ((pcih = topo_mod_pcidb(mod)) == NULL || 998 (pciv = pcidb_lookup_vendor(pcih, vid)) == NULL) { 999 return (0); 1000 } 1001 1002 /* lookup vendor-name and set the topo property, if found */ 1003 vname = pcidb_vendor_name(pciv); 1004 if (vname != NULL && 1005 topo_prop_set_string(tn, tpgrp, TOPO_PCI_VENDNM, 1006 TOPO_PROP_IMMUTABLE, vname, &err) != 0) { 1007 return (topo_mod_seterrno(mod, err)); 1008 } 1009 1010 /* lookup device-name and set the topo property, if found */ 1011 if ((pcid = pcidb_lookup_device_by_vendor(pciv, pid)) != NULL) { 1012 dname = pcidb_device_name(pcid); 1013 } 1014 if (dname != NULL && 1015 topo_prop_set_string(tn, tpgrp, TOPO_PCI_DEVNM, 1016 TOPO_PROP_IMMUTABLE, dname, &err) != 0) { 1017 return (topo_mod_seterrno(mod, err)); 1018 } 1019 1020 /* 1021 * Not all devices will have a subsystem-name that we can lookup, 1022 * but if both subsystem-vendorid and subsystem-id exist in devinfo and 1023 * if we were previously able to find the device by devid then we can 1024 * at least attempt a lookup. If found, set the topo property. 1025 */ 1026 if (pcid != NULL && 1027 di_uintprop_get(did_mod(pd), did_dinode(pd), DI_SUBVENDIDPROP, 1028 &svid) == 0 && 1029 di_uintprop_get(did_mod(pd), did_dinode(pd), DI_SUBSYSTEMID, 1030 &ssid) == 0) { 1031 pcis = pcidb_lookup_subvd_by_device(pcid, svid, ssid); 1032 } 1033 if (pcis != NULL) { 1034 ssname = pcidb_subvd_name(pcis); 1035 } 1036 if (ssname != NULL && strlen(ssname) > 0 && 1037 topo_prop_set_string(tn, tpgrp, TOPO_PCI_SUBSYSNM, 1038 TOPO_PROP_IMMUTABLE, ssname, &err) != 0) { 1039 return (topo_mod_seterrno(mod, err)); 1040 } 1041 return (0); 1042 } 1043 1044 int 1045 did_props_set(tnode_t *tn, did_t *pd, txprop_t txarray[], int txnum) 1046 { 1047 topo_mod_t *mp; 1048 int i, r, e; 1049 1050 mp = did_mod(pd); 1051 for (i = 0; i < txnum; i++) { 1052 /* 1053 * Ensure the property group has been created. 1054 */ 1055 if (txarray[i].tx_tpgroup != NULL) { 1056 if (topo_pgroup_create(tn, txarray[i].tx_tpgroup, &e) 1057 < 0) { 1058 if (e != ETOPO_PROP_DEFD) 1059 return (topo_mod_seterrno(mp, e)); 1060 } 1061 } 1062 1063 topo_mod_dprintf(mp, 1064 "Setting property %s in group %s.\n", 1065 txarray[i].tx_tprop, txarray[i].tx_tpgroup->tpi_name); 1066 r = txarray[i].tx_xlate(tn, pd, 1067 txarray[i].tx_diprop, txarray[i].tx_tpgroup->tpi_name, 1068 txarray[i].tx_tprop); 1069 if (r != 0) { 1070 topo_mod_dprintf(mp, "failed.\n"); 1071 topo_mod_dprintf(mp, "Error was %s.\n", 1072 topo_strerror(topo_mod_errno(mp))); 1073 return (-1); 1074 } 1075 topo_mod_dprintf(mp, "succeeded.\n"); 1076 } 1077 return (0); 1078 } 1079 1080 static int 1081 maybe_di_int_to_uint32(tnode_t *tn, did_t *pd, const char *dpnm, 1082 const char *tpgrp, const char *tpnm) 1083 { 1084 int ret, *vals; 1085 1086 ret = di_prop_lookup_ints(DDI_DEV_T_ANY, did_dinode(pd), dpnm, &vals); 1087 if (ret != 1) { 1088 return (0); 1089 } 1090 1091 if (topo_prop_set_uint32(tn, tpgrp, tpnm, 0, (uint32_t)*vals, &ret) != 1092 0) { 1093 return (topo_mod_seterrno(did_mod(pd), ret)); 1094 } 1095 1096 return (0); 1097 } 1098 1099 static int 1100 maybe_pcie_speed(tnode_t *tn, did_t *pd, const char *dpnm, const char *tpgrp, 1101 const char *tpnm) 1102 { 1103 int ret; 1104 int64_t *vals; 1105 1106 ret = di_prop_lookup_int64(DDI_DEV_T_ANY, did_dinode(pd), dpnm, &vals); 1107 if (ret != 1) { 1108 return (0); 1109 } 1110 1111 if (topo_prop_set_uint64(tn, tpgrp, tpnm, 0, (uint64_t)*vals, &ret) != 1112 0) { 1113 return (topo_mod_seterrno(did_mod(pd), ret)); 1114 } 1115 return (0); 1116 } 1117 1118 static int 1119 maybe_pcie_supported_speed(tnode_t *tn, did_t *pd, const char *dpnm, 1120 const char *tpgrp, const char *tpnm) 1121 { 1122 int ret; 1123 uint_t count; 1124 int64_t *vals; 1125 1126 ret = di_prop_lookup_int64(DDI_DEV_T_ANY, did_dinode(pd), dpnm, &vals); 1127 if (ret < 1) { 1128 return (0); 1129 } 1130 1131 count = (uint_t)ret; 1132 if (topo_prop_set_uint64_array(tn, tpgrp, tpnm, 0, (uint64_t *)vals, 1133 count, &ret) != 0) { 1134 return (topo_mod_seterrno(did_mod(pd), ret)); 1135 } 1136 return (0); 1137 } 1138 1139 static int 1140 maybe_pcie_target_speed(tnode_t *tn, did_t *pd, const char *dpnm, 1141 const char *tpgrp, const char *tpnm) 1142 { 1143 di_prop_t prop = DI_PROP_NIL; 1144 boolean_t admin = B_FALSE; 1145 int64_t *val = NULL; 1146 int ret; 1147 1148 while ((prop = di_prop_next(did_dinode(pd), prop)) != DI_PROP_NIL) { 1149 const char *n = di_prop_name(prop); 1150 1151 if (strcmp(DI_PCIE_ADMIN_TAG, n) == 0) { 1152 admin = B_TRUE; 1153 } else if (strcmp(DI_PCIE_TARG_SPEED, n) == 0) { 1154 if (di_prop_int64(prop, &val) != 1) { 1155 val = NULL; 1156 } 1157 } 1158 } 1159 1160 if (!admin || val == NULL) { 1161 return (0); 1162 } 1163 1164 if (topo_prop_set_uint64(tn, tpgrp, tpnm, 0, (uint64_t)*val, &ret) != 1165 0) { 1166 return (topo_mod_seterrno(did_mod(pd), ret)); 1167 } 1168 return (0); 1169 } 1170