xref: /illumos-gate/usr/src/lib/fm/topo/modules/common/pcibus/pcibus.c (revision b210e77709da8e42dfe621e10ccf4be504206058)
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 (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
24  * Copyright 2020 Joyent, Inc.
25  */
26 
27 #include <sys/fm/protocol.h>
28 #include <assert.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <strings.h>
33 #include <alloca.h>
34 #include <fcntl.h>
35 #include <unistd.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 #include <sys/stat.h>
44 #include <sys/types.h>
45 
46 #include <hostbridge.h>
47 #include <pcibus.h>
48 #include <did.h>
49 #include <did_props.h>
50 #include <util.h>
51 #include <topo_nic.h>
52 #include <topo_usb.h>
53 #include <topo_ufm.h>
54 
55 extern txprop_t Bus_common_props[];
56 extern txprop_t Dev_common_props[];
57 extern txprop_t Fn_common_props[];
58 extern int Bus_propcnt;
59 extern int Dev_propcnt;
60 extern int Fn_propcnt;
61 
62 extern int platform_pci_label(topo_mod_t *mod, tnode_t *, nvlist_t *,
63     nvlist_t **);
64 extern int platform_pci_fru(topo_mod_t *mod, tnode_t *, nvlist_t *,
65     nvlist_t **);
66 static void pci_release(topo_mod_t *, tnode_t *);
67 static int pci_enum(topo_mod_t *, tnode_t *, const char *, topo_instance_t,
68     topo_instance_t, void *, void *);
69 static int pci_label(topo_mod_t *, tnode_t *, topo_version_t, nvlist_t *,
70     nvlist_t **);
71 static int pci_fru(topo_mod_t *, tnode_t *, topo_version_t, nvlist_t *,
72     nvlist_t **);
73 
74 static const topo_modops_t Pci_ops =
75 	{ pci_enum, pci_release };
76 static const topo_modinfo_t Pci_info =
77 	{ PCI_BUS, FM_FMRI_SCHEME_HC, PCI_ENUMR_VERS, &Pci_ops };
78 
79 static const topo_method_t Pci_methods[] = {
80 	{ TOPO_METH_LABEL, TOPO_METH_LABEL_DESC,
81 	    TOPO_METH_LABEL_VERSION, TOPO_STABILITY_INTERNAL, pci_label },
82 	{ TOPO_METH_FRU_COMPUTE, TOPO_METH_FRU_COMPUTE_DESC,
83 	    TOPO_METH_FRU_COMPUTE_VERSION, TOPO_STABILITY_INTERNAL, pci_fru },
84 	{ NULL }
85 };
86 
87 int
88 _topo_init(topo_mod_t *modhdl, topo_version_t version)
89 {
90 	/*
91 	 * Turn on module debugging output
92 	 */
93 	if (getenv("TOPOPCIDBG") != NULL)
94 		topo_mod_setdebug(modhdl);
95 	topo_mod_dprintf(modhdl, "initializing pcibus builtin\n");
96 
97 	if (version != PCI_ENUMR_VERS)
98 		return (topo_mod_seterrno(modhdl, EMOD_VER_NEW));
99 
100 	if (topo_mod_register(modhdl, &Pci_info, TOPO_VERSION) != 0) {
101 		topo_mod_dprintf(modhdl, "failed to register module");
102 		return (-1);
103 	}
104 	topo_mod_dprintf(modhdl, "PCI Enumr initd\n");
105 
106 	return (0);
107 }
108 
109 void
110 _topo_fini(topo_mod_t *modhdl)
111 {
112 	topo_mod_unregister(modhdl);
113 }
114 
115 static int
116 pci_label(topo_mod_t *mp, tnode_t *node, topo_version_t version,
117     nvlist_t *in, nvlist_t **out)
118 {
119 	if (version > TOPO_METH_LABEL_VERSION)
120 		return (topo_mod_seterrno(mp, EMOD_VER_NEW));
121 	return (platform_pci_label(mp, node, in, out));
122 }
123 static int
124 pci_fru(topo_mod_t *mp, tnode_t *node, topo_version_t version,
125     nvlist_t *in, nvlist_t **out)
126 {
127 	if (version > TOPO_METH_FRU_COMPUTE_VERSION)
128 		return (topo_mod_seterrno(mp, EMOD_VER_NEW));
129 	return (platform_pci_fru(mp, node, in, out));
130 }
131 static tnode_t *
132 pci_tnode_create(topo_mod_t *mod, tnode_t *parent,
133     const char *name, topo_instance_t i, void *priv)
134 {
135 	tnode_t *ntn;
136 
137 	if ((ntn = tnode_create(mod, parent, name, i, priv)) == NULL)
138 		return (NULL);
139 	if (topo_method_register(mod, ntn, Pci_methods) < 0) {
140 		topo_mod_dprintf(mod, "topo_method_register failed: %s\n",
141 		    topo_strerror(topo_mod_errno(mod)));
142 		topo_node_unbind(ntn);
143 		return (NULL);
144 	}
145 	return (ntn);
146 }
147 
148 /*ARGSUSED*/
149 static int
150 hostbridge_asdevice(topo_mod_t *mod, tnode_t *bus)
151 {
152 	di_node_t di;
153 	tnode_t *dev32;
154 
155 	di = topo_node_getspecific(bus);
156 	assert(di != DI_NODE_NIL);
157 
158 	if ((dev32 = pcidev_declare(mod, bus, di, 32)) == NULL)
159 		return (-1);
160 	if (pcifn_declare(mod, dev32, di, 0) == NULL) {
161 		topo_node_unbind(dev32);
162 		return (-1);
163 	}
164 	return (0);
165 }
166 
167 static int
168 pciexfn_add_ufm(topo_mod_t *mod, tnode_t *parent, tnode_t *node)
169 {
170 	int err;
171 	char *devpath = NULL;
172 	tnode_t *create;
173 	topo_ufm_devinfo_t tud;
174 
175 	if (topo_prop_get_string(node, TOPO_PGROUP_IO, TOPO_IO_DEV, &devpath,
176 	    &err) != 0) {
177 		return (topo_mod_seterrno(mod, EMOD_UNKNOWN));
178 	}
179 
180 	/*
181 	 * In general, almost all UFMs are device-wide. That is, in a
182 	 * multi-function device, there is still a single global firmware image.
183 	 * At this time, we default to putting the UFM data always on the device
184 	 * node. However, if someone creates a UFM on something that's not the
185 	 * first function, we'll create a UFM under that function for now. If we
186 	 * add support for hardware that has per-function UFMs, then we should
187 	 * update the UFM API to convey that scope.
188 	 */
189 	if (topo_node_instance(node) != 0) {
190 		create = node;
191 	} else {
192 		create = parent;
193 	}
194 
195 	if (topo_mod_load(mod, TOPO_MOD_UFM, TOPO_VERSION) == NULL) {
196 		topo_mod_dprintf(mod, "pcibus enum could not load ufm module");
197 		topo_mod_strfree(mod, devpath);
198 		return (topo_mod_seterrno(mod, EMOD_PARTIAL_ENUM));
199 	}
200 
201 	tud.tud_method = TOPO_UFM_M_DEVINFO;
202 	tud.tud_path = devpath;
203 	err = topo_mod_enumerate(mod, create, TOPO_MOD_UFM, UFM, 0, UINT32_MAX,
204 	    &tud);
205 	topo_mod_strfree(mod, devpath);
206 
207 	return (err);
208 }
209 
210 tnode_t *
211 pciexfn_declare(topo_mod_t *mod, tnode_t *parent, di_node_t dn,
212     topo_instance_t i)
213 {
214 	did_t *pd;
215 	tnode_t *ntn, *ptn;
216 	di_node_t pdn;
217 	uint_t class, subclass;
218 	char *devtyp, *pdevtyp;
219 	int pcie_devtyp, pexcap;
220 	boolean_t dev_is_pcie, pdev_is_pcie;
221 
222 	/* We need the parent's dev info node for some of the info */
223 	ptn = find_predecessor(parent, PCIEX_FUNCTION);
224 	/* If this is the first child under root, get root's ptn */
225 	if (ptn == NULL)
226 		ptn = find_predecessor(parent, PCIEX_ROOT);
227 	if (ptn == NULL)
228 		return (NULL);
229 	pdn = topo_node_getspecific(ptn);
230 
231 	/* Get the required info to populate the excap */
232 	(void) pci_classcode_get(mod, dn, &class, &subclass);
233 	devtyp = pci_devtype_get(mod, dn);
234 	pdevtyp = pci_devtype_get(mod, pdn);
235 	pexcap = pciex_cap_get(mod, pdn);
236 
237 	dev_is_pcie = devtyp && (strcmp(devtyp, "pciex") == 0);
238 	pdev_is_pcie = pdevtyp && (strcmp(pdevtyp, "pciex") == 0);
239 
240 	/*
241 	 * Populate the excap with correct PCIe device type.
242 	 *
243 	 * Device	Parent		Device		Parent	Device
244 	 * excap	device-type	device-type	excap	Class Code
245 	 * -------------------------------------------------------------------
246 	 * PCI(default)	pci		N/A		N/A	!= bridge
247 	 * PCIe		pciex		N/A		N/A	!= bridge
248 	 * Root Port	Defined in hostbridge
249 	 * Switch Up	pciex		pciex		!= up	= bridge
250 	 * Switch Down	pciex		pciex		= up	= bridge
251 	 * PCIe-PCI	pciex		pci		N/A	= bridge
252 	 * PCI-PCIe	pci		pciex		N/A	= bridge
253 	 */
254 	pcie_devtyp = PCIE_PCIECAP_DEV_TYPE_PCI_DEV;
255 	if (class == PCI_CLASS_BRIDGE && subclass == PCI_BRIDGE_PCI) {
256 		if (pdev_is_pcie) {
257 			if (dev_is_pcie) {
258 				if (pexcap != PCIE_PCIECAP_DEV_TYPE_UP)
259 					pcie_devtyp = PCIE_PCIECAP_DEV_TYPE_UP;
260 				else
261 					pcie_devtyp =
262 					    PCIE_PCIECAP_DEV_TYPE_DOWN;
263 			} else {
264 				pcie_devtyp = PCIE_PCIECAP_DEV_TYPE_PCIE2PCI;
265 			}
266 		} else {
267 			if (dev_is_pcie)
268 				pcie_devtyp = PCIE_PCIECAP_DEV_TYPE_PCI2PCIE;
269 		}
270 	} else {
271 		if (pdev_is_pcie)
272 			pcie_devtyp = PCIE_PCIECAP_DEV_TYPE_PCIE_DEV;
273 	}
274 
275 	if ((pd = did_find(mod, dn)) == NULL)
276 		return (NULL);
277 	did_excap_set(pd, pcie_devtyp);
278 
279 	if ((ntn = pci_tnode_create(mod, parent, PCIEX_FUNCTION, i, dn))
280 	    == NULL)
281 		return (NULL);
282 	if (did_props_set(ntn, pd, Fn_common_props, Fn_propcnt) < 0) {
283 		topo_node_unbind(ntn);
284 		return (NULL);
285 	}
286 
287 	/*
288 	 * Check if the driver associated with this function exports firmware
289 	 * information via the DDI UFM subsystem and, if so, create the
290 	 * corresponding ufm topo nodes.
291 	 */
292 	if (pciexfn_add_ufm(mod, parent, ntn) != 0) {
293 		topo_node_unbind(ntn);
294 		return (NULL);
295 	}
296 
297 	/*
298 	 * We may find pci-express buses or plain-pci buses beneath a function
299 	 */
300 	if (child_range_add(mod, ntn, PCIEX_BUS, 0, MAX_HB_BUSES) < 0) {
301 		topo_node_unbind(ntn);
302 		return (NULL);
303 	}
304 	if (child_range_add(mod, ntn, PCI_BUS, 0, MAX_HB_BUSES) < 0) {
305 		topo_node_range_destroy(ntn, PCIEX_BUS);
306 		topo_node_unbind(ntn);
307 		return (NULL);
308 	}
309 	return (ntn);
310 }
311 
312 tnode_t *
313 pciexdev_declare(topo_mod_t *mod, tnode_t *parent, di_node_t dn,
314     topo_instance_t i)
315 {
316 	did_t *pd;
317 	tnode_t *ntn;
318 
319 	if ((pd = did_find(mod, dn)) == NULL)
320 		return (NULL);
321 	did_settnode(pd, parent);
322 
323 	if ((ntn = pci_tnode_create(mod, parent, PCIEX_DEVICE, i, dn)) == NULL)
324 		return (NULL);
325 	if (did_props_set(ntn, pd, Dev_common_props, Dev_propcnt) < 0) {
326 		topo_node_unbind(ntn);
327 		return (NULL);
328 	}
329 
330 	if (pci_create_dev_sensors(mod, ntn) < 0) {
331 		topo_node_unbind(ntn);
332 		return (NULL);
333 	}
334 
335 	/*
336 	 * We can expect to find pci-express functions beneath the device
337 	 */
338 	if (child_range_add(mod,
339 	    ntn, PCIEX_FUNCTION, 0, MAX_PCIDEV_FNS) < 0) {
340 		topo_node_unbind(ntn);
341 		return (NULL);
342 	}
343 	return (ntn);
344 }
345 
346 tnode_t *
347 pciexbus_declare(topo_mod_t *mod, tnode_t *parent, di_node_t dn,
348     topo_instance_t i)
349 {
350 	did_t *pd;
351 	tnode_t *ntn;
352 
353 	if ((pd = did_find(mod, dn)) == NULL)
354 		return (NULL);
355 	did_settnode(pd, parent);
356 	if ((ntn = pci_tnode_create(mod, parent, PCIEX_BUS, i, dn)) == NULL)
357 		return (NULL);
358 	if (did_props_set(ntn, pd, Bus_common_props, Bus_propcnt) < 0) {
359 		topo_node_unbind(ntn);
360 		return (NULL);
361 	}
362 	/*
363 	 * We can expect to find pci-express devices beneath the bus
364 	 */
365 	if (child_range_add(mod,
366 	    ntn, PCIEX_DEVICE, 0, MAX_PCIBUS_DEVS) < 0) {
367 		topo_node_unbind(ntn);
368 		return (NULL);
369 	}
370 	return (ntn);
371 }
372 
373 tnode_t *
374 pcifn_declare(topo_mod_t *mod, tnode_t *parent, di_node_t dn,
375     topo_instance_t i)
376 {
377 	did_t *pd;
378 	tnode_t *ntn;
379 
380 	if ((pd = did_find(mod, dn)) == NULL)
381 		return (NULL);
382 	did_excap_set(pd, PCIE_PCIECAP_DEV_TYPE_PCI_DEV);
383 
384 	if ((ntn = pci_tnode_create(mod, parent, PCI_FUNCTION, i, dn)) == NULL)
385 		return (NULL);
386 	if (did_props_set(ntn, pd, Fn_common_props, Fn_propcnt) < 0) {
387 		topo_node_unbind(ntn);
388 		return (NULL);
389 	}
390 	/*
391 	 * We may find pci buses beneath a function
392 	 */
393 	if (child_range_add(mod, ntn, PCI_BUS, 0, MAX_HB_BUSES) < 0) {
394 		topo_node_unbind(ntn);
395 		return (NULL);
396 	}
397 	return (ntn);
398 }
399 
400 tnode_t *
401 pcidev_declare(topo_mod_t *mod, tnode_t *parent, di_node_t dn,
402     topo_instance_t i)
403 {
404 	did_t *pd;
405 	tnode_t *ntn;
406 
407 	if ((pd = did_find(mod, dn)) == NULL)
408 		return (NULL);
409 	/* remember parent tnode */
410 	did_settnode(pd, parent);
411 
412 	if ((ntn = pci_tnode_create(mod, parent, PCI_DEVICE, i, dn)) == NULL)
413 		return (NULL);
414 	if (did_props_set(ntn, pd, Dev_common_props, Dev_propcnt) < 0) {
415 		topo_node_unbind(ntn);
416 		return (NULL);
417 	}
418 
419 	if (pci_create_dev_sensors(mod, ntn) < 0) {
420 		topo_node_unbind(ntn);
421 		return (NULL);
422 	}
423 
424 	/*
425 	 * We can expect to find pci functions beneath the device
426 	 */
427 	if (child_range_add(mod, ntn, PCI_FUNCTION, 0, MAX_PCIDEV_FNS) < 0) {
428 		topo_node_unbind(ntn);
429 		return (NULL);
430 	}
431 	return (ntn);
432 }
433 
434 tnode_t *
435 pcibus_declare(topo_mod_t *mod, tnode_t *parent, di_node_t dn,
436     topo_instance_t i)
437 {
438 	did_t *pd;
439 	tnode_t *ntn;
440 	int hbchild = 0;
441 
442 	if ((pd = did_find(mod, dn)) == NULL)
443 		return (NULL);
444 	did_settnode(pd, parent);
445 	if ((ntn = pci_tnode_create(mod, parent, PCI_BUS, i, dn)) == NULL)
446 		return (NULL);
447 	/*
448 	 * If our devinfo node is lacking certain information of its
449 	 * own, and our parent topology node is a hostbridge, we may
450 	 * need/want to inherit information available in the
451 	 * hostbridge node's private data.
452 	 */
453 	if (strcmp(topo_node_name(parent), HOSTBRIDGE) == 0)
454 		hbchild = 1;
455 	if (did_props_set(ntn, pd, Bus_common_props, Bus_propcnt) < 0) {
456 		topo_node_unbind(ntn);
457 		return (NULL);
458 	}
459 	/*
460 	 * We can expect to find pci devices beneath the bus
461 	 */
462 	if (child_range_add(mod, ntn, PCI_DEVICE, 0, MAX_PCIBUS_DEVS) < 0) {
463 		topo_node_unbind(ntn);
464 		return (NULL);
465 	}
466 	/*
467 	 * On each bus child of the hostbridge, we represent the
468 	 * hostbridge as a device outside the range of legal device
469 	 * numbers.
470 	 */
471 	if (hbchild == 1) {
472 		if (hostbridge_asdevice(mod, ntn) < 0) {
473 			topo_node_range_destroy(ntn, PCI_DEVICE);
474 			topo_node_unbind(ntn);
475 			return (NULL);
476 		}
477 	}
478 	return (ntn);
479 }
480 
481 static int
482 pci_bridge_declare(topo_mod_t *mod, tnode_t *fn, di_node_t din, int board,
483     int bridge, int rc, int depth)
484 {
485 	int err;
486 	char *devtyp;
487 
488 	devtyp = pci_devtype_get(mod, din);
489 	/* Check if the children are PCI or PCIe */
490 	if (devtyp && (strcmp(devtyp, "pciex") == 0))
491 		err = pci_children_instantiate(mod, fn, din, board, bridge,
492 		    rc, TRUST_BDF, depth + 1);
493 	else
494 		err = pci_children_instantiate(mod, fn, din, board, bridge,
495 		    rc - TO_PCI, TRUST_BDF, depth + 1);
496 	return (err);
497 }
498 
499 static void
500 declare_dev_and_fn(topo_mod_t *mod, tnode_t *bus, tnode_t **dev, di_node_t din,
501     int board, int bridge, int rc, int devno, int fnno, int depth)
502 {
503 	int dcnt = 0, rcnt, err;
504 	char *propstr, *label = NULL, *pdev = NULL;
505 	tnode_t *fn;
506 	uint_t class, subclass;
507 	uint_t vid, did;
508 	uint_t pdev_sz = 0;
509 	did_t *dp = NULL;
510 
511 	if (*dev == NULL) {
512 		if (rc >= 0)
513 			*dev = pciexdev_declare(mod, bus, din, devno);
514 		else
515 			*dev = pcidev_declare(mod, bus, din, devno);
516 		if (*dev == NULL)
517 			return;
518 		++dcnt;
519 	}
520 	if (rc >= 0)
521 		fn = pciexfn_declare(mod, *dev, din, fnno);
522 	else
523 		fn = pcifn_declare(mod, *dev, din, fnno);
524 
525 	if (fn == NULL) {
526 		if (dcnt) {
527 			topo_node_unbind(*dev);
528 			*dev = NULL;
529 		}
530 		return;
531 	}
532 
533 	if (pci_classcode_get(mod, din, &class, &subclass) < 0) {
534 		topo_node_unbind(fn);
535 		if (dcnt)
536 			topo_node_unbind(*dev);
537 		return;
538 	}
539 
540 	/*
541 	 * This function may be a bridge.  If not, check for a possible
542 	 * topology map file and kick off its enumeration of lower-level
543 	 * devices.
544 	 */
545 	if (class == PCI_CLASS_BRIDGE && subclass == PCI_BRIDGE_PCI) {
546 		(void) pci_bridge_declare(mod, fn, din, board, bridge, rc,
547 		    depth);
548 	}
549 
550 	/*
551 	 * Check for a Neptune-based NIC. This could either be a Neptune
552 	 * adapter card or an Neptune ASIC on a board (e.g. motherboard)
553 	 *
554 	 * For Netpune adapter cards, use xfp-hc-topology.xml to expand
555 	 * topology to include the XFP optical module, which is a FRU on
556 	 * the Neptune based 10giga fiber NICs.
557 	 *
558 	 * For Neptune ASICs, use the XAUI enumerator to expand topology.
559 	 * The 10giga ports are externalized by a XAUI cards, which
560 	 * are FRUs. The XAUI enumerator in turn instantiates the XFP
561 	 * optical module FRUs.
562 	 */
563 	else if (class == PCI_CLASS_NET &&
564 	    di_uintprop_get(mod, din, DI_VENDIDPROP, &vid) >= 0 &&
565 	    di_uintprop_get(mod, din, DI_DEVIDPROP, &did) >= 0 &&
566 	    vid == SUN_VENDOR_ID && did == NEPTUNE_DEVICE_ID) {
567 		/*
568 		 * Is this an adapter card? Check the bus's physlot
569 		 */
570 		dp = did_find(mod, topo_node_getspecific(bus));
571 		if (did_physlot(dp) >= 0) {
572 			topo_mod_dprintf(mod, "Found Neptune slot\n");
573 			(void) topo_mod_enummap(mod, fn,
574 			    "xfp", FM_FMRI_SCHEME_HC);
575 		} else {
576 			topo_mod_dprintf(mod, "Found Neptune ASIC\n");
577 			if (topo_mod_load(mod, XAUI, TOPO_VERSION) == NULL) {
578 				topo_mod_dprintf(mod, "pcibus enum "
579 				    "could not load xaui enum\n");
580 				(void) topo_mod_seterrno(mod,
581 				    EMOD_PARTIAL_ENUM);
582 				return;
583 			} else {
584 				if (topo_node_range_create(mod, fn,
585 				    XAUI, 0, 1) < 0) {
586 					topo_mod_dprintf(mod,
587 					    "child_range_add for "
588 					    "XAUI failed: %s\n",
589 					    topo_strerror(
590 					    topo_mod_errno(mod)));
591 					return;
592 				}
593 				(void) topo_mod_enumerate(mod, fn,
594 				    XAUI, XAUI, fnno, fnno, fn);
595 			}
596 		}
597 	} else if (class == PCI_CLASS_NET) {
598 		/*
599 		 * Ask the nic module if there are any nodes that need to be
600 		 * enumerated under this device. This might include things like
601 		 * transceivers or some day, LEDs.
602 		 */
603 		if (topo_mod_load(mod, NIC, NIC_VERSION) == NULL) {
604 			topo_mod_dprintf(mod, "pcibus enum could not load "
605 			    "nic enum\n");
606 			(void) topo_mod_seterrno(mod, EMOD_PARTIAL_ENUM);
607 			return;
608 		}
609 
610 		(void) topo_mod_enumerate(mod, fn, NIC, NIC, 0, 0, din);
611 	} else if (class == PCI_CLASS_SERIALBUS && subclass == PCI_SERIAL_USB) {
612 		/*
613 		 * If we encounter a USB controller, make sure to enumerate all
614 		 * of its USB ports.
615 		 */
616 		if (topo_mod_load(mod, USB, USB_VERSION) == NULL) {
617 			topo_mod_dprintf(mod, "pcibus enum could not load "
618 			    "usb enum\n");
619 			(void) topo_mod_seterrno(mod, EMOD_PARTIAL_ENUM);
620 			return;
621 		}
622 
623 		(void) topo_mod_enumerate(mod, fn, USB, USB_PCI, 0, 0, din);
624 	} else if (class == PCI_CLASS_MASS) {
625 		di_node_t cn;
626 		int niports = 0;
627 		extern void pci_iports_instantiate(topo_mod_t *, tnode_t *,
628 		    di_node_t, int);
629 		extern void pci_receptacle_instantiate(topo_mod_t *, tnode_t *,
630 		    di_node_t);
631 
632 		for (cn = di_child_node(din); cn != DI_NODE_NIL;
633 		    cn = di_sibling_node(cn)) {
634 			if (strcmp(di_node_name(cn), IPORT) == 0)
635 				niports++;
636 		}
637 		if (niports > 0)
638 			pci_iports_instantiate(mod, fn, din, niports);
639 
640 		if ((rcnt = di_prop_lookup_strings(DDI_DEV_T_ANY, din,
641 		    DI_RECEPTACLE_PHYMASK, &propstr)) > 0) {
642 			if (topo_node_range_create(mod, fn, RECEPTACLE, 0,
643 			    rcnt) >= 0)
644 				pci_receptacle_instantiate(mod, fn, din);
645 		}
646 	}
647 
648 	/*
649 	 * If this is an NVMe device and if the FRU label indicates it's not an
650 	 * onboard device then invoke the disk enumerator to enumerate the NVMe
651 	 * controller and associated namespaces.
652 	 *
653 	 * We skip NVMe devices that appear to be onboard as those are likely
654 	 * M.2 or U.2 devices and so should be enumerated via a
655 	 * platform-specific XML map so that they can be associated with the
656 	 * correct physical bay/slot.  This code is intended to pick up NVMe
657 	 * devices that are part of PCIe add-in cards.
658 	 */
659 	if (topo_node_label(fn, &label, &err) != 0) {
660 		topo_mod_dprintf(mod, "%s: failed to lookup FRU label on "
661 		    "%s=%" PRIu64, __func__, topo_node_name(fn),
662 		    topo_node_instance(fn));
663 		goto out;
664 	}
665 
666 	if (class == PCI_CLASS_MASS && subclass == PCI_MASS_NVME &&
667 	    strcmp(label, "MB") != 0) {
668 		char *driver = di_driver_name(din);
669 		char *slash;
670 		topo_pgroup_info_t pgi;
671 
672 		if (topo_prop_get_string(fn, TOPO_PGROUP_IO, TOPO_IO_DEV,
673 		    &pdev, &err) != 0) {
674 			topo_mod_dprintf(mod, "%s: failed to lookup %s on "
675 			    "%s=%" PRIu64, __func__, TOPO_IO_DEV,
676 			    topo_node_name(fn), topo_node_instance(fn));
677 			goto out;
678 		}
679 
680 		/*
681 		 * Add the binding properties that are required by the disk
682 		 * enumerator to discover the accociated NVMe controller.
683 		 */
684 		pdev_sz = strlen(pdev) + 1;
685 		if ((slash = strrchr(pdev, '/')) == NULL) {
686 			topo_mod_dprintf(mod, "%s: malformed dev path\n",
687 			    __func__);
688 			(void) topo_mod_seterrno(mod, EMOD_PARTIAL_ENUM);
689 			goto out;
690 		}
691 		*slash = '\0';
692 
693 		pgi.tpi_name = TOPO_PGROUP_BINDING;
694 		pgi.tpi_namestab = TOPO_STABILITY_PRIVATE;
695 		pgi.tpi_datastab = TOPO_STABILITY_PRIVATE;
696 		pgi.tpi_version = TOPO_VERSION;
697 		if (topo_pgroup_create(fn, &pgi, &err) != 0 ||
698 		    topo_prop_set_string(fn, TOPO_PGROUP_BINDING,
699 		    TOPO_BINDING_DRIVER, TOPO_PROP_IMMUTABLE, driver,
700 		    &err) != 0 ||
701 		    topo_prop_set_string(fn, TOPO_PGROUP_BINDING,
702 		    TOPO_BINDING_PARENT_DEV, TOPO_PROP_IMMUTABLE, pdev,
703 		    &err) != 0) {
704 			topo_mod_dprintf(mod, "%s: failed to set binding "
705 			    "props", __func__);
706 			(void) topo_mod_seterrno(mod, EMOD_PARTIAL_ENUM);
707 			goto out;
708 		}
709 
710 		/*
711 		 * Load and invoke the disk enumerator module.
712 		 */
713 		if (topo_mod_load(mod, DISK, TOPO_VERSION) == NULL) {
714 			topo_mod_dprintf(mod, "pcibus enum could not load "
715 			    "disk enum\n");
716 			(void) topo_mod_seterrno(mod, EMOD_PARTIAL_ENUM);
717 			goto out;
718 		}
719 		(void) topo_mod_enumerate(mod, fn, DISK, NVME, 0, 0, NULL);
720 	}
721 out:
722 	if (pdev != NULL) {
723 		topo_mod_free(mod, pdev, pdev_sz);
724 	}
725 	topo_mod_strfree(mod, label);
726 }
727 
728 int
729 pci_children_instantiate(topo_mod_t *mod, tnode_t *parent, di_node_t pn,
730     int board, int bridge, int rc, int bover, int depth)
731 {
732 	did_t *pps[MAX_PCIBUS_DEVS][MAX_PCIDEV_FNS];
733 	did_t *bp = NULL;
734 	did_t *np;
735 	di_node_t sib;
736 	di_node_t din;
737 	tnode_t *bn = NULL;
738 	tnode_t *dn = NULL;
739 	int pb = -1;
740 	int b, d, f;
741 
742 	for (d = 0; d < MAX_PCIBUS_DEVS; d++)
743 		for (f = 0; f < MAX_PCIDEV_FNS; f++)
744 			pps[d][f] = NULL;
745 
746 	/* start at the parent's first sibling */
747 	sib = di_child_node(pn);
748 	while (sib != DI_NODE_NIL) {
749 		np = did_create(mod, sib, board, bridge, rc, bover);
750 		if (np == NULL)
751 			return (-1);
752 		did_BDF(np, &b, &d, &f);
753 		pps[d][f] = np;
754 		if (bp == NULL)
755 			bp = np;
756 		if (pb < 0)
757 			pb = ((bover == TRUST_BDF) ? b : bover);
758 		sib = di_sibling_node(sib);
759 	}
760 	if (pb < 0 && bover < 0)
761 		return (0);
762 	if (rc >= 0)
763 		bn = pciexbus_declare(mod, parent, pn, ((pb < 0) ? bover : pb));
764 	else
765 		bn = pcibus_declare(mod, parent, pn, ((pb < 0) ? bover : pb));
766 	if (bn == NULL)
767 		return (-1);
768 	if (pb < 0)
769 		return (0);
770 
771 	for (d = 0; d < MAX_PCIBUS_DEVS; d++) {
772 		for (f = 0; f < MAX_PCIDEV_FNS; f++) {
773 			if (pps[d][f] == NULL)
774 				continue;
775 			din = did_dinode(pps[d][f]);
776 
777 			/*
778 			 * Try to enumerate as many devices and functions as
779 			 * possible.  If we fail to declare a device, break
780 			 * out of the function loop.
781 			 */
782 			declare_dev_and_fn(mod, bn,
783 			    &dn, din, board, bridge, rc, d, f, depth);
784 			did_rele(pps[d][f]);
785 
786 			if (dn == NULL)
787 				break;
788 		}
789 		dn = NULL;
790 	}
791 	return (0);
792 }
793 
794 static int
795 pciexbus_enum(topo_mod_t *mp, tnode_t *ptn, char *pnm, topo_instance_t min,
796     topo_instance_t max)
797 {
798 	di_node_t pdn;
799 	int rc, hb;
800 	tnode_t *hbtn;
801 	int retval;
802 
803 	/*
804 	 * PCI-Express; parent node's private data is a simple di_node_t
805 	 * and we have to construct our own did hash and did_t.
806 	 */
807 	rc = topo_node_instance(ptn);
808 	if ((hbtn = topo_node_parent(ptn)) != NULL)
809 		hb = topo_node_instance(hbtn);
810 	else
811 		hb = rc;
812 
813 	if ((pdn = topo_node_getspecific(ptn)) == DI_NODE_NIL) {
814 		topo_mod_dprintf(mp,
815 		    "Parent %s node missing private data.\n"
816 		    "Unable to proceed with %s enumeration.\n", pnm, PCIEX_BUS);
817 		return (0);
818 	}
819 	if (did_hash_init(mp) != 0)
820 		return (-1);
821 	if ((did_create(mp, pdn, 0, hb, rc, TRUST_BDF)) == NULL)
822 		return (-1);	/* errno already set */
823 
824 	retval = pci_children_instantiate(mp, ptn, pdn, 0, hb, rc,
825 	    (min == max) ? min : TRUST_BDF, 0);
826 	did_hash_fini(mp);
827 
828 	return (retval);
829 }
830 
831 static int
832 pcibus_enum(topo_mod_t *mp, tnode_t *ptn, char *pnm, topo_instance_t min,
833     topo_instance_t max, void *data)
834 {
835 	did_t *didp, *hbdid = (did_t *)data;
836 	int retval;
837 
838 	/*
839 	 * XXTOPO: we should not be sharing private node data with another
840 	 * module. PCI Bus; Parent node's private data is a did_t.  We'll
841 	 * use the did hash established by the parent.
842 	 */
843 	did_setspecific(mp, data);
844 
845 	/*
846 	 * If we're looking for a specific bus-instance, find the right
847 	 * did_t in the chain, otherwise, there should be only one did_t.
848 	 */
849 	if (min == max) {
850 		int b;
851 		didp = hbdid;
852 		while (didp != NULL) {
853 			did_BDF(didp, &b, NULL, NULL);
854 			if (b == min)
855 				break;
856 			didp = did_link_get(didp);
857 		}
858 		if (didp == NULL) {
859 			topo_mod_dprintf(mp,
860 			    "Parent %s node missing private data related\n"
861 			    "to %s instance %" PRIu64 ".\n", pnm, PCI_BUS, min);
862 			topo_mod_setspecific(mp, NULL);
863 			return (0);
864 		}
865 	} else {
866 		assert(did_link_get(hbdid) == NULL);
867 		didp = hbdid;
868 	}
869 	retval = pci_children_instantiate(mp, ptn, did_dinode(didp),
870 	    did_board(didp), did_bridge(didp), did_rc(didp),
871 	    (min == max) ? min : TRUST_BDF, 0);
872 
873 	topo_mod_setspecific(mp, NULL);
874 
875 	return (retval);
876 }
877 
878 /*ARGSUSED*/
879 static int
880 pci_enum(topo_mod_t *mod, tnode_t *ptn, const char *name,
881     topo_instance_t min, topo_instance_t max, void *notused, void *data)
882 {
883 	int retval;
884 	char *pname;
885 
886 	topo_mod_dprintf(mod, "Enumerating pci!\n");
887 
888 	if (strcmp(name, PCI_BUS) != 0 && strcmp(name, PCIEX_BUS) != 0) {
889 		topo_mod_dprintf(mod,
890 		    "Currently only know how to enumerate %s or %s.\n",
891 		    PCI_BUS, PCIEX_BUS);
892 		return (0);
893 	}
894 	pname = topo_node_name(ptn);
895 	if (strcmp(pname, HOSTBRIDGE) != 0 && strcmp(pname, PCIEX_ROOT) != 0) {
896 		topo_mod_dprintf(mod,
897 		    "Currently can only enumerate a %s or %s directly\n",
898 		    PCI_BUS, PCIEX_BUS);
899 		topo_mod_dprintf(mod,
900 		    "descended from a %s or %s node.\n",
901 		    HOSTBRIDGE, PCIEX_ROOT);
902 		return (0);
903 	}
904 
905 	if (strcmp(name, PCI_BUS) == 0) {
906 		retval = pcibus_enum(mod, ptn, pname, min, max, data);
907 	} else if (strcmp(name, PCIEX_BUS) == 0) {
908 		retval = pciexbus_enum(mod, ptn, pname, min, max);
909 	} else {
910 		topo_mod_dprintf(mod,
911 		    "Currently only know how to enumerate %s or %s not %s.\n",
912 		    PCI_BUS, PCIEX_BUS, name);
913 		return (0);
914 	}
915 
916 	return (retval);
917 }
918 
919 /*ARGSUSED*/
920 static void
921 pci_release(topo_mod_t *mp, tnode_t *node)
922 {
923 	topo_method_unregister_all(mp, node);
924 
925 	/*
926 	 * node private data (did_t) for this node is destroyed in
927 	 * did_hash_destroy()
928 	 */
929 
930 	topo_node_unbind(node);
931 }
932