1 /*
2 * This file and its contents are supplied under the terms of the
3 * Common Development and Distribution License ("CDDL"), version 1.0.
4 * You may only use this file in accordance with the terms of version
5 * 1.0 of the CDDL.
6 *
7 * A full copy of the text of the CDDL should have accompanied this
8 * source. A copy of the CDDL is also available via the Internet at
9 * http://www.illumos.org/license/CDDL.
10 */
11
12 /*
13 * Copyright 2023 Oxide Computer Company
14 */
15
16 #include <fcntl.h>
17 #include <libdevinfo.h>
18 #include <stdbool.h>
19 #include <string.h>
20 #include <strings.h>
21 #include <unistd.h>
22 #include <sys/debug.h>
23 #include <sys/pci.h>
24 #include <sys/pcie.h>
25 #include <sys/stat.h>
26 #include <sys/types.h>
27
28 #include <sys/fm/protocol.h>
29 #include <fm/topo_mod.h>
30 #include <fm/topo_list.h>
31 #include <fm/topo_method.h>
32 #include <fm/topo_hc.h>
33
34 #include "topo_pcie_impl.h"
35
36 static const topo_pgroup_info_t io_pgroup = {
37 .tpi_name = TOPO_PCIE_PGROUP_IO,
38 .tpi_namestab = TOPO_STABILITY_PRIVATE,
39 .tpi_datastab = TOPO_STABILITY_PRIVATE,
40 .tpi_version = 1
41 };
42
43 static const topo_pgroup_info_t pcicfg_pgroup = {
44 .tpi_name = TOPO_PCIE_PGROUP_PCI_CFG,
45 .tpi_namestab = TOPO_STABILITY_PRIVATE,
46 .tpi_datastab = TOPO_STABILITY_PRIVATE,
47 .tpi_version = 1
48 };
49
50 static const topo_pgroup_info_t pci_pgroup = {
51 .tpi_name = TOPO_PCIE_PGROUP_PCI,
52 .tpi_namestab = TOPO_STABILITY_PRIVATE,
53 .tpi_datastab = TOPO_STABILITY_PRIVATE,
54 .tpi_version = 1
55 };
56
57 static const topo_pgroup_info_t port_pgroup = {
58 .tpi_name = TOPO_PCIE_PGROUP_PORT,
59 .tpi_namestab = TOPO_STABILITY_PRIVATE,
60 .tpi_datastab = TOPO_STABILITY_PRIVATE,
61 .tpi_version = 1
62 };
63
64 const topo_pgroup_info_t pcielink_pgroup = {
65 .tpi_name = TOPO_PCIE_PGROUP_PCIE_LINK,
66 .tpi_namestab = TOPO_STABILITY_PRIVATE,
67 .tpi_datastab = TOPO_STABILITY_PRIVATE,
68 .tpi_version = 1
69 };
70
71 static const topo_pgroup_info_t pcilink_pgroup = {
72 .tpi_name = TOPO_PCIE_PGROUP_PCI_LINK,
73 .tpi_namestab = TOPO_STABILITY_PRIVATE,
74 .tpi_datastab = TOPO_STABILITY_PRIVATE,
75 .tpi_version = 1
76 };
77
78 typedef struct pcie_prop pcie_prop_t;
79 typedef bool (*f_prop)(topo_mod_t *, pcie_t *, pcie_node_t *, tnode_t *,
80 pcie_prop_t *);
81 typedef struct pcie_prop {
82 const topo_pgroup_info_t *pp_group;
83 const char *pp_di_prop;
84 const char *pp_topo_prop;
85 f_prop pp_func;
86 } pcie_prop_t;
87
88 static bool
devinfostr(topo_mod_t * mod,pcie_t * pcie,pcie_node_t * node,tnode_t * tn,pcie_prop_t * prop)89 devinfostr(topo_mod_t *mod, pcie_t *pcie, pcie_node_t *node, tnode_t *tn,
90 pcie_prop_t *prop)
91 {
92 return (pcie_topo_prop_copy(mod, node->pn_did, tn, prop->pp_group,
93 TOPO_TYPE_STRING, prop->pp_di_prop, prop->pp_topo_prop));
94 }
95
96 static bool
opt_devinfostr(topo_mod_t * mod,pcie_t * pcie,pcie_node_t * node,tnode_t * tn,pcie_prop_t * prop)97 opt_devinfostr(topo_mod_t *mod, pcie_t *pcie, pcie_node_t *node, tnode_t *tn,
98 pcie_prop_t *prop)
99 {
100 (void) devinfostr(mod, pcie, node, tn, prop);
101 return (true);
102 }
103
104 static bool
devinfo32(topo_mod_t * mod,pcie_t * pcie,pcie_node_t * node,tnode_t * tn,pcie_prop_t * prop)105 devinfo32(topo_mod_t *mod, pcie_t *pcie, pcie_node_t *node, tnode_t *tn,
106 pcie_prop_t *prop)
107 {
108 return (pcie_topo_prop_copy(mod, node->pn_did, tn, prop->pp_group,
109 TOPO_TYPE_UINT32, prop->pp_di_prop, prop->pp_topo_prop));
110 }
111
112 static bool
opt_devinfo32(topo_mod_t * mod,pcie_t * pcie,pcie_node_t * node,tnode_t * tn,pcie_prop_t * prop)113 opt_devinfo32(topo_mod_t *mod, pcie_t *pcie, pcie_node_t *node, tnode_t *tn,
114 pcie_prop_t *prop)
115 {
116 (void) devinfo32(mod, pcie, node, tn, prop);
117 return (true);
118 }
119
120 static bool
devinfo64(topo_mod_t * mod,pcie_t * pcie,pcie_node_t * node,tnode_t * tn,pcie_prop_t * prop)121 devinfo64(topo_mod_t *mod, pcie_t *pcie, pcie_node_t *node, tnode_t *tn,
122 pcie_prop_t *prop)
123 {
124 return (pcie_topo_prop_copy(mod, node->pn_did, tn, prop->pp_group,
125 TOPO_TYPE_UINT64, prop->pp_di_prop, prop->pp_topo_prop));
126 }
127
128 static bool
devinfo64_array(topo_mod_t * mod,pcie_t * pcie,pcie_node_t * node,tnode_t * tn,pcie_prop_t * prop)129 devinfo64_array(topo_mod_t *mod, pcie_t *pcie, pcie_node_t *node, tnode_t *tn,
130 pcie_prop_t *prop)
131 {
132 return (pcie_topo_prop_copy(mod, node->pn_did, tn, prop->pp_group,
133 TOPO_TYPE_UINT64_ARRAY, prop->pp_di_prop, prop->pp_topo_prop));
134 }
135
136 static bool
opt_devinfo32_array(topo_mod_t * mod,pcie_t * pcie,pcie_node_t * node,tnode_t * tn,pcie_prop_t * prop)137 opt_devinfo32_array(topo_mod_t *mod, pcie_t *pcie, pcie_node_t *node,
138 tnode_t *tn, pcie_prop_t *prop)
139 {
140 (void) pcie_topo_prop_copy(mod, node->pn_did, tn, prop->pp_group,
141 TOPO_TYPE_UINT32_ARRAY, prop->pp_di_prop, prop->pp_topo_prop);
142 return (true);
143 }
144
145 static bool
devinfobool(topo_mod_t * mod,pcie_t * pcie,pcie_node_t * node,tnode_t * tn,pcie_prop_t * prop)146 devinfobool(topo_mod_t *mod, pcie_t *pcie, pcie_node_t *node,
147 tnode_t *tn, pcie_prop_t *prop)
148 {
149 bool val = pcie_devinfo_getbool(mod, node->pn_did, prop->pp_di_prop);
150
151 return (pcie_topo_prop_set32(mod, tn, prop->pp_group,
152 prop->pp_topo_prop, val ? 1 : 0));
153 }
154
155 /* io properties */
156
157 static bool
set_devpath(topo_mod_t * mod,pcie_t * pcie,pcie_node_t * node,tnode_t * tn,pcie_prop_t * prop)158 set_devpath(topo_mod_t *mod, pcie_t *pcie, pcie_node_t *node, tnode_t *tn,
159 pcie_prop_t *prop)
160 {
161 return (pcie_topo_prop_setstr(mod, tn, prop->pp_group,
162 prop->pp_topo_prop, node->pn_path));
163 }
164
165 static bool
set_driver(topo_mod_t * mod,pcie_t * pcie,pcie_node_t * node,tnode_t * tn,pcie_prop_t * prop)166 set_driver(topo_mod_t *mod, pcie_t *pcie, pcie_node_t *node, tnode_t *tn,
167 pcie_prop_t *prop)
168 {
169 if (node->pn_drvname == NULL)
170 return (true);
171
172 return (pcie_topo_prop_setstr(mod, tn, prop->pp_group,
173 prop->pp_topo_prop, node->pn_drvname));
174 }
175
176 static bool
set_instance(topo_mod_t * mod,pcie_t * pcie,pcie_node_t * node,tnode_t * tn,pcie_prop_t * prop)177 set_instance(topo_mod_t *mod, pcie_t *pcie, pcie_node_t *node, tnode_t *tn,
178 pcie_prop_t *prop)
179 {
180 if (node->pn_drvname == NULL)
181 return (true);
182
183 return (pcie_topo_prop_set64(mod, tn, prop->pp_group,
184 prop->pp_topo_prop, node->pn_drvinst));
185 }
186
187 static pcie_prop_t io_props[] = {
188 { &io_pgroup, NULL, TOPO_PCIE_IO_DEV_PATH, set_devpath },
189 { &io_pgroup, NULL, TOPO_PCIE_IO_DRIVER, set_driver },
190 { &io_pgroup, NULL, TOPO_PCIE_IO_INSTANCE, set_instance },
191 };
192
193 /* link properties */
194
195 static bool
link_state(topo_mod_t * mod,pcie_t * pcie,pcie_node_t * node,tnode_t * tn,pcie_prop_t * prop)196 link_state(topo_mod_t *mod, pcie_t *pcie, pcie_node_t *node, tnode_t *tn,
197 pcie_prop_t *prop)
198 {
199 const char *val;
200
201 switch (topo_pcie_link_status(mod, node)) {
202 case PCI_LINK_UP:
203 val = TOPO_PCIE_LINK_UP_STR;
204 break;
205 case PCI_LINK_DOWN:
206 val = TOPO_PCIE_LINK_DOWN_STR;
207 break;
208 default:
209 /* Omit the property if link status is unknown */
210 return (true);
211 }
212
213 return (pcie_topo_prop_setstr(mod, tn, prop->pp_group,
214 prop->pp_topo_prop, val));
215 }
216
217 static bool
link_targspeed(topo_mod_t * mod,pcie_t * pcie,pcie_node_t * node,tnode_t * tn,pcie_prop_t * prop)218 link_targspeed(topo_mod_t *mod, pcie_t *pcie, pcie_node_t *node, tnode_t *tn,
219 pcie_prop_t *prop)
220 {
221 if (!pcie_devinfo_getbool(mod, node->pn_did, DI_PCIE_ADMIN_TAG))
222 return (true);
223
224 return (devinfo64(mod, pcie, node, tn, prop));
225 }
226
227 static pcie_prop_t pcie_link_props[] = {
228 { &pcielink_pgroup, NULL, TOPO_PCIE_LINK_STATE, link_state },
229 { &pcielink_pgroup, DI_PCIE_CUR_SPEED, TOPO_PCIE_LINK_CUR_SPEED,
230 devinfo64 },
231 { &pcielink_pgroup, DI_PCIE_CUR_WIDTH, TOPO_PCIE_LINK_CUR_WIDTH,
232 devinfo32 },
233 { &pcielink_pgroup, DI_PCIE_MAX_SPEED, TOPO_PCIE_LINK_MAX_SPEED,
234 devinfo64 },
235 { &pcielink_pgroup, DI_PCIE_MAX_WIDTH, TOPO_PCIE_LINK_MAX_WIDTH,
236 devinfo32 },
237 { &pcielink_pgroup, DI_PCIE_SUP_SPEEDS, TOPO_PCIE_LINK_SUP_SPEED,
238 devinfo64_array },
239 { &pcielink_pgroup, DI_PCIE_TARG_SPEED, TOPO_PCIE_LINK_ADMIN_SPEED,
240 link_targspeed },
241 };
242
243 static pcie_prop_t pci_link_props[] = {
244 { &pcilink_pgroup, NULL, TOPO_PCIE_LINK_STATE, link_state },
245 { &pcilink_pgroup, DI_PCI_66MHZ_CAPABLE, TOPO_PCIE_LINK_66MHZ_CAPABLE,
246 devinfobool },
247 };
248
249 /* link methods */
250
251 static int
topo_pcie_link_unusable(topo_mod_t * mod,tnode_t * tn,topo_version_t ver,nvlist_t * in,nvlist_t ** out)252 topo_pcie_link_unusable(topo_mod_t *mod, tnode_t *tn, topo_version_t ver,
253 nvlist_t *in, nvlist_t **out)
254 {
255 pcie_node_t *node = topo_node_getspecific(tn);
256 nvlist_t *nvl;
257 uint32_t unusable;
258
259 if (topo_mod_nvalloc(mod, &nvl, NV_UNIQUE_NAME) != 0)
260 return (topo_mod_seterrno(mod, EMOD_FMRI_NVL));
261
262 unusable = 1;
263 if (node != NULL && topo_pcie_link_status(mod, node) == PCI_LINK_UP)
264 unusable = 0;
265
266 if (nvlist_add_uint32(nvl, TOPO_METH_UNUSABLE_RET, unusable) != 0) {
267 nvlist_free(nvl);
268 return (topo_mod_seterrno(mod, EMOD_FMRI_NVL));
269 }
270
271 *out = nvl;
272
273 return (0);
274 }
275
276 static const topo_method_t link_methods[] = {
277 {
278 .tm_name = TOPO_METH_UNUSABLE,
279 .tm_desc = TOPO_METH_UNUSABLE_DESC,
280 .tm_version = TOPO_METH_UNUSABLE_VERSION,
281 .tm_stability = TOPO_STABILITY_INTERNAL,
282 .tm_func = topo_pcie_link_unusable
283 },
284 { .tm_name = NULL }
285 };
286
287 /* pci properties */
288
289 static bool
set_bdf(topo_mod_t * mod,pcie_t * pcie,pcie_node_t * node,tnode_t * tn,pcie_prop_t * prop)290 set_bdf(topo_mod_t *mod, pcie_t *pcie, pcie_node_t *node, tnode_t *tn,
291 pcie_prop_t *prop)
292 {
293 int32_t *val;
294 int nval;
295
296 if (node->pn_type == PCIE_NODE_ROOTNEXUS)
297 return (true);
298
299 nval = di_prop_lookup_ints(DDI_DEV_T_ANY, node->pn_did,
300 prop->pp_di_prop, &val);
301 if (nval < 1)
302 return (true);
303
304 return (
305 pcie_topo_prop_set32(mod, tn, prop->pp_group,
306 TOPO_PCIE_PCI_BUS, PCI_REG_BUS_G(val[0])) &&
307 pcie_topo_prop_set32(mod, tn, prop->pp_group,
308 TOPO_PCIE_PCI_DEVICE, PCI_REG_DEV_G(val[0])) &&
309 pcie_topo_prop_set32(mod, tn, prop->pp_group,
310 TOPO_PCIE_PCI_FUNCTION, PCI_REG_FUNC_G(val[0])) &&
311 pcie_topo_prop_set32(mod, tn, prop->pp_group,
312 TOPO_PCIE_PCI_SEGMENT, 0));
313 }
314
315 static bool
set_pci_type(topo_mod_t * mod,pcie_t * pcie,pcie_node_t * node,tnode_t * tn,pcie_prop_t * prop)316 set_pci_type(topo_mod_t *mod, pcie_t *pcie, pcie_node_t *node, tnode_t *tn,
317 pcie_prop_t *prop)
318 {
319 return (pcie_topo_prop_setstr(mod, tn, prop->pp_group,
320 prop->pp_topo_prop, pcie_type_name(node->pn_type)));
321 }
322
323 static bool
set_class(topo_mod_t * mod,pcie_t * pcie,pcie_node_t * node,tnode_t * tn,pcie_prop_t * prop)324 set_class(topo_mod_t *mod, pcie_t *pcie, pcie_node_t *node, tnode_t *tn,
325 pcie_prop_t *prop)
326 {
327 if (node->pn_class == 0)
328 return (true);
329
330 return (pcie_topo_prop_set32(mod, tn, prop->pp_group,
331 TOPO_PCIE_PCI_CLASS, node->pn_class) &&
332 pcie_topo_prop_set32(mod, tn, prop->pp_group,
333 TOPO_PCIE_PCI_SUBCLASS, node->pn_subclass) &&
334 pcie_topo_prop_set32(mod, tn, prop->pp_group,
335 TOPO_PCIE_PCI_INTERFACE, node->pn_intf));
336 }
337
338 static bool
set_pcidb(topo_mod_t * mod,pcie_t * pcie,pcie_node_t * node,tnode_t * tn,pcie_prop_t * prop)339 set_pcidb(topo_mod_t *mod, pcie_t *pcie, pcie_node_t *node, tnode_t *tn,
340 pcie_prop_t *prop)
341 {
342 int32_t vid, devid, ssvid, ssdevid;
343 pcidb_vendor_t *pciv;
344 pcidb_device_t *pcid;
345 pcidb_subvd_t *pcis;
346 di_node_t did = node->pn_did;
347
348 if (pcie->tp_pcidb_hdl == NULL)
349 goto out;
350
351 vid = pcie_devinfo_get32(mod, did, DI_VENDIDPROP);
352 devid = pcie_devinfo_get32(mod, did, DI_DEVIDPROP);
353 ssvid = pcie_devinfo_get32(mod, did, DI_SUBVENDIDPROP);
354 ssdevid = pcie_devinfo_get32(mod, did, DI_SUBSYSTEMID);
355
356 if (vid == -1)
357 goto out;
358
359 pciv = pcidb_lookup_vendor(pcie->tp_pcidb_hdl, (uint16_t)vid);
360 if (pciv == NULL)
361 goto out;
362 (void) pcie_topo_prop_setstr(mod, tn, prop->pp_group,
363 TOPO_PCIE_PCI_VENDOR_NAME, pcidb_vendor_name(pciv));
364
365 if (devid == -1)
366 goto out;
367
368 pcid = pcidb_lookup_device_by_vendor(pciv, (uint16_t)devid);
369 if (pcid == NULL)
370 goto out;
371 (void) pcie_topo_prop_setstr(mod, tn, prop->pp_group,
372 TOPO_PCIE_PCI_DEV_NAME, pcidb_device_name(pcid));
373
374 if (ssvid == -1 || ssdevid == -1 || ssvid == 0 || ssdevid == 0)
375 goto out;
376
377 pcis = pcidb_lookup_subvd_by_device(pcid, (uint16_t)ssvid,
378 (uint16_t)ssdevid);
379 if (pcis == NULL)
380 goto out;
381 (void) pcie_topo_prop_setstr(mod, tn, prop->pp_group,
382 TOPO_PCIE_PCI_SUBSYSTEM_NAME, pcidb_subvd_name(pcis));
383
384 out:
385 /*
386 * We always return success here, even if one or more of the lookups
387 * failed, or if the we don't have an open database handle.
388 */
389 return (true);
390 }
391
392 static bool
set_busrange(topo_mod_t * mod,pcie_t * pcie,pcie_node_t * node,tnode_t * tn,pcie_prop_t * prop)393 set_busrange(topo_mod_t *mod, pcie_t *pcie, pcie_node_t *node, tnode_t *tn,
394 pcie_prop_t *prop)
395 {
396 int32_t *val;
397 int nval;
398 uint32_t arr[3];
399
400 nval = di_prop_lookup_ints(DDI_DEV_T_ANY, node->pn_did,
401 prop->pp_di_prop, &val);
402 if (nval != 2)
403 return (true);
404
405 arr[0] = val[0];
406 arr[1] = val[1];
407
408 return (pcie_topo_prop_set32_array(mod, tn, prop->pp_group,
409 prop->pp_topo_prop, arr, 2));
410 }
411
412 static pcie_prop_t pci_props[] = {
413 /* io */
414 { &io_pgroup, NULL, TOPO_PCIE_IO_DEV_PATH, set_devpath },
415 { &io_pgroup, NULL, TOPO_PCIE_IO_DRIVER, set_driver },
416 { &io_pgroup, NULL, TOPO_PCIE_IO_INSTANCE, set_instance },
417 { &io_pgroup, DI_DEVTYPPROP, TOPO_PCIE_IO_DEVTYPE, opt_devinfostr },
418
419 /* pci-cfg */
420 { &pcicfg_pgroup, DI_REGPROP, NULL, set_bdf },
421 { &pcicfg_pgroup, DI_BUSRANGE, TOPO_PCIE_PCI_BUS_RANGE, set_busrange },
422 { &pcicfg_pgroup, DI_AADDRPROP, TOPO_PCIE_PCI_ASSIGNED_ADDR,
423 opt_devinfo32_array }, // XXX - decode further?
424
425 /* pci */
426 { &pci_pgroup, NULL, TOPO_PCIE_PCI_TYPE, set_pci_type },
427 { &pci_pgroup, NULL, NULL, set_class },
428 { &pci_pgroup, DI_MODELNAME, TOPO_PCIE_PCI_CLASS_STRING,
429 opt_devinfostr },
430 { &pci_pgroup, DI_VENDIDPROP, TOPO_PCIE_PCI_VENDOR_ID, opt_devinfo32 },
431 { &pci_pgroup, DI_DEVIDPROP, TOPO_PCIE_PCI_DEV_ID, opt_devinfo32 },
432 { &pci_pgroup, DI_SUBVENDIDPROP, TOPO_PCIE_PCI_SSVENDORID,
433 opt_devinfo32 },
434 { &pci_pgroup, DI_SUBSYSTEMID, TOPO_PCIE_PCI_SSID, opt_devinfo32 },
435 { &pci_pgroup, DI_REVIDPROP, TOPO_PCIE_PCI_REVID, opt_devinfo32 },
436 { &pci_pgroup, DI_PHYSPROP, TOPO_PCIE_PCI_SLOT, opt_devinfo32 },
437 { &pci_pgroup, NULL, NULL, set_pcidb },
438 };
439
440 static bool
pcie_apply_props(topo_mod_t * mod,pcie_t * pcie,pcie_node_t * node,tnode_t * tn,pcie_prop_t props[],size_t num)441 pcie_apply_props(topo_mod_t *mod, pcie_t *pcie, pcie_node_t *node,
442 tnode_t *tn, pcie_prop_t props[], size_t num)
443 {
444 bool ret = true;
445
446 for (size_t i = 0; i < num; i++) {
447 pcie_prop_t *p = &props[i];
448
449 if (p->pp_group != NULL &&
450 !pcie_topo_pgroup_create(mod, tn, p->pp_group)) {
451 return (false);
452 }
453
454 if (!p->pp_func(mod, pcie, node, tn, p))
455 ret = false;
456 }
457
458 return (ret);
459 }
460
461 bool
topo_pcie_set_io_props(topo_mod_t * mod,pcie_t * pcie,pcie_node_t * node,tnode_t * tn)462 topo_pcie_set_io_props(topo_mod_t *mod, pcie_t *pcie, pcie_node_t *node,
463 tnode_t *tn)
464 {
465 return (pcie_apply_props(mod, pcie, node, tn, io_props,
466 ARRAY_SIZE(io_props)));
467 }
468
469 bool
topo_pcie_set_pci_props(topo_mod_t * mod,pcie_t * pcie,pcie_node_t * node,tnode_t * tn)470 topo_pcie_set_pci_props(topo_mod_t *mod, pcie_t *pcie, pcie_node_t *node,
471 tnode_t *tn)
472 {
473 return (pcie_apply_props(mod, pcie, node, tn, pci_props,
474 ARRAY_SIZE(pci_props)));
475 }
476
477 bool
topo_pcie_set_port_props(topo_mod_t * mod,pcie_t * pcie,pcie_node_t * node,tnode_t * tn,topo_port_type_t type)478 topo_pcie_set_port_props(topo_mod_t *mod, pcie_t *pcie, pcie_node_t *node,
479 tnode_t *tn, topo_port_type_t type)
480 {
481 const topo_pgroup_info_t *pg = &port_pgroup;
482
483 if (!pcie_topo_pgroup_create(mod, tn, pg))
484 return (false);
485
486 return (pcie_topo_prop_setstr(mod, tn, pg, TOPO_PCIE_PORT_TYPE,
487 type == TOPO_PORT_DOWNSTREAM ? TOPO_PCIE_PORT_TYPE_DS :
488 TOPO_PCIE_PORT_TYPE_US));
489 }
490
491 bool
topo_pcie_set_link_props(topo_mod_t * mod,pcie_t * pcie,pcie_node_t * node,tnode_t * tn)492 topo_pcie_set_link_props(topo_mod_t *mod, pcie_t *pcie, pcie_node_t *node,
493 tnode_t *tn)
494 {
495 bool ret = false;
496
497 switch (node->pn_type) {
498 case PCIE_NODE_PCI_DEV:
499 case PCIE_NODE_PCIE_PCI:
500 ret = pcie_apply_props(mod, pcie, node, tn, pci_link_props,
501 ARRAY_SIZE(pci_link_props));
502 break;
503 default:
504 ret = pcie_apply_props(mod, pcie, node, tn, pcie_link_props,
505 ARRAY_SIZE(pcie_link_props));
506 break;
507 }
508
509 if (topo_method_register(mod, tn, link_methods) != 0) {
510 topo_mod_dprintf(mod, "failed to register link methods: %s",
511 topo_mod_errmsg(mod));
512 ret = false;
513 }
514
515 return (ret);
516 }
517