xref: /illumos-gate/usr/src/lib/fm/topo/modules/common/pcibus/pcibus.c (revision 46b592853d0f4f11781b6b0a7533f267c6aee132)
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 #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 <sys/param.h>
35 #include <sys/pci.h>
36 #include <sys/pcie.h>
37 #include <libdevinfo.h>
38 #include <libnvpair.h>
39 #include <fm/topo_mod.h>
40 #include <fm/topo_hc.h>
41 
42 #include <hostbridge.h>
43 #include <pcibus.h>
44 #include <did.h>
45 #include <did_props.h>
46 #include <util.h>
47 
48 extern txprop_t Bus_common_props[];
49 extern txprop_t Dev_common_props[];
50 extern txprop_t Fn_common_props[];
51 extern int Bus_propcnt;
52 extern int Dev_propcnt;
53 extern int Fn_propcnt;
54 
55 extern int platform_pci_label(topo_mod_t *mod, tnode_t *, nvlist_t *,
56     nvlist_t **);
57 extern int platform_pci_fru(topo_mod_t *mod, tnode_t *, nvlist_t *,
58     nvlist_t **);
59 static void pci_release(topo_mod_t *, tnode_t *);
60 static int pci_enum(topo_mod_t *, tnode_t *, const char *, topo_instance_t,
61     topo_instance_t, void *, void *);
62 static int pci_label(topo_mod_t *, tnode_t *, topo_version_t, nvlist_t *,
63     nvlist_t **);
64 static int pci_fru(topo_mod_t *, tnode_t *, topo_version_t, nvlist_t *,
65     nvlist_t **);
66 
67 static const topo_modops_t Pci_ops =
68 	{ pci_enum, pci_release };
69 static const topo_modinfo_t Pci_info =
70 	{ PCI_BUS, FM_FMRI_SCHEME_HC, PCI_ENUMR_VERS, &Pci_ops };
71 
72 static const topo_method_t Pci_methods[] = {
73 	{ TOPO_METH_LABEL, TOPO_METH_LABEL_DESC,
74 	    TOPO_METH_LABEL_VERSION, TOPO_STABILITY_INTERNAL, pci_label },
75 	{ TOPO_METH_FRU_COMPUTE, TOPO_METH_FRU_COMPUTE_DESC,
76 	    TOPO_METH_FRU_COMPUTE_VERSION, TOPO_STABILITY_INTERNAL, pci_fru },
77 	{ NULL }
78 };
79 
80 int
81 _topo_init(topo_mod_t *modhdl, topo_version_t version)
82 {
83 	/*
84 	 * Turn on module debugging output
85 	 */
86 	if (getenv("TOPOPCIDBG") != NULL)
87 		topo_mod_setdebug(modhdl);
88 	topo_mod_dprintf(modhdl, "initializing pcibus builtin\n");
89 
90 	if (version != PCI_ENUMR_VERS)
91 		return (topo_mod_seterrno(modhdl, EMOD_VER_NEW));
92 
93 	topo_mod_register(modhdl, &Pci_info, TOPO_VERSION);
94 	topo_mod_dprintf(modhdl, "PCI Enumr initd\n");
95 
96 	return (0);
97 }
98 
99 void
100 _topo_fini(topo_mod_t *modhdl)
101 {
102 	topo_mod_unregister(modhdl);
103 }
104 
105 static int
106 pci_label(topo_mod_t *mp, tnode_t *node, topo_version_t version,
107     nvlist_t *in, nvlist_t **out)
108 {
109 	if (version > TOPO_METH_LABEL_VERSION)
110 		return (topo_mod_seterrno(mp, EMOD_VER_NEW));
111 	return (platform_pci_label(mp, node, in, out));
112 }
113 static int
114 pci_fru(topo_mod_t *mp, tnode_t *node, topo_version_t version,
115     nvlist_t *in, nvlist_t **out)
116 {
117 	if (version > TOPO_METH_FRU_COMPUTE_VERSION)
118 		return (topo_mod_seterrno(mp, EMOD_VER_NEW));
119 	return (platform_pci_fru(mp, node, in, out));
120 }
121 static tnode_t *
122 pci_tnode_create(topo_mod_t *mod, tnode_t *parent,
123     const char *name, topo_instance_t i, void *priv)
124 {
125 	tnode_t *ntn;
126 
127 	if ((ntn = tnode_create(mod, parent, name, i, priv)) == NULL)
128 		return (NULL);
129 	if (topo_method_register(mod, ntn, Pci_methods) < 0) {
130 		topo_mod_dprintf(mod, "topo_method_register failed: %s\n",
131 		    topo_strerror(topo_mod_errno(mod)));
132 		topo_node_unbind(ntn);
133 		return (NULL);
134 	}
135 	return (ntn);
136 }
137 
138 /*ARGSUSED*/
139 static int
140 hostbridge_asdevice(topo_mod_t *mod, tnode_t *bus)
141 {
142 	di_node_t di;
143 	tnode_t *dev32;
144 
145 	di = topo_node_getspecific(bus);
146 	assert(di != DI_NODE_NIL);
147 
148 	if ((dev32 = pcidev_declare(mod, bus, di, 32)) == NULL)
149 		return (-1);
150 	if (pcifn_declare(mod, dev32, di, 0) == NULL) {
151 		topo_node_unbind(dev32);
152 		return (-1);
153 	}
154 	return (0);
155 }
156 
157 tnode_t *
158 pciexfn_declare(topo_mod_t *mod, tnode_t *parent, di_node_t dn,
159     topo_instance_t i)
160 {
161 	did_t *pd;
162 	tnode_t *ntn, *ptn;
163 	di_node_t pdn;
164 	uint_t class, subclass;
165 	char *devtyp, *pdevtyp;
166 	int pcie_devtyp, pexcap;
167 	boolean_t dev_is_pcie, pdev_is_pcie;
168 
169 	/* We need the parent's dev info node for some of the info */
170 	ptn = find_predecessor(parent, PCIEX_FUNCTION);
171 	/* If this is the first child under root, get root's ptn */
172 	if (ptn == NULL)
173 		ptn = find_predecessor(parent, PCIEX_ROOT);
174 	if (ptn == NULL)
175 		return (NULL);
176 	pdn = topo_node_getspecific(ptn);
177 
178 	/* Get the required info to populate the excap */
179 	(void) pci_classcode_get(mod, dn, &class, &subclass);
180 	devtyp = pci_devtype_get(mod, dn);
181 	pdevtyp = pci_devtype_get(mod, pdn);
182 	pexcap = pciex_cap_get(mod, pdn);
183 
184 	dev_is_pcie = devtyp && (strcmp(devtyp, "pciex") == 0);
185 	pdev_is_pcie = pdevtyp && (strcmp(pdevtyp, "pciex") == 0);
186 
187 	/*
188 	 * Populate the excap with correct PCIe device type.
189 	 *
190 	 * Device	Parent		Device		Parent	Device
191 	 * excap	device-type	device-type	excap	Class Code
192 	 * -------------------------------------------------------------------
193 	 * PCI(default)	pci		N/A		N/A	!= bridge
194 	 * PCIe		pciex		N/A		N/A	!= bridge
195 	 * Root Port	Defined in hostbridge
196 	 * Switch Up	pciex		pciex		!= up	= bridge
197 	 * Switch Down	pciex		pciex		= up	= bridge
198 	 * PCIe-PCI	pciex		pci		N/A	= bridge
199 	 * PCI-PCIe	pci		pciex		N/A	= bridge
200 	 */
201 	pcie_devtyp = PCIE_PCIECAP_DEV_TYPE_PCI_DEV;
202 	if (class == PCI_CLASS_BRIDGE && subclass == PCI_BRIDGE_PCI) {
203 		if (pdev_is_pcie) {
204 			if (dev_is_pcie) {
205 				if (pexcap != PCIE_PCIECAP_DEV_TYPE_UP)
206 					pcie_devtyp = PCIE_PCIECAP_DEV_TYPE_UP;
207 				else
208 					pcie_devtyp =
209 					    PCIE_PCIECAP_DEV_TYPE_DOWN;
210 			} else {
211 				pcie_devtyp = PCIE_PCIECAP_DEV_TYPE_PCIE2PCI;
212 			}
213 		} else {
214 			if (dev_is_pcie)
215 				pcie_devtyp = PCIE_PCIECAP_DEV_TYPE_PCI2PCIE;
216 		}
217 	} else {
218 		if (pdev_is_pcie)
219 			pcie_devtyp = PCIE_PCIECAP_DEV_TYPE_PCIE_DEV;
220 	}
221 
222 	if ((pd = did_find(mod, dn)) == NULL)
223 		return (NULL);
224 	did_excap_set(pd, pcie_devtyp);
225 
226 	if ((ntn = pci_tnode_create(mod, parent, PCIEX_FUNCTION, i, dn))
227 	    == NULL)
228 		return (NULL);
229 	if (did_props_set(ntn, pd, Fn_common_props, Fn_propcnt) < 0) {
230 		topo_node_unbind(ntn);
231 		return (NULL);
232 	}
233 	/*
234 	 * We may find pci-express buses or plain-pci buses beneath a function
235 	 */
236 	if (child_range_add(mod, ntn, PCIEX_BUS, 0, MAX_HB_BUSES) < 0) {
237 		topo_node_unbind(ntn);
238 		return (NULL);
239 	}
240 	if (child_range_add(mod, ntn, PCI_BUS, 0, MAX_HB_BUSES) < 0) {
241 		topo_node_range_destroy(ntn, PCIEX_BUS);
242 		topo_node_unbind(ntn);
243 		return (NULL);
244 	}
245 	return (ntn);
246 }
247 
248 tnode_t *
249 pciexdev_declare(topo_mod_t *mod, tnode_t *parent, di_node_t dn,
250     topo_instance_t i)
251 {
252 	did_t *pd;
253 	tnode_t *ntn;
254 
255 	if ((pd = did_find(mod, dn)) == NULL)
256 		return (NULL);
257 	did_settnode(pd, parent);
258 
259 	if ((ntn = pci_tnode_create(mod, parent, PCIEX_DEVICE, i, dn)) == NULL)
260 		return (NULL);
261 	if (did_props_set(ntn, pd, Dev_common_props, Dev_propcnt) < 0) {
262 		topo_node_unbind(ntn);
263 		return (NULL);
264 	}
265 
266 	/*
267 	 * We can expect to find pci-express functions beneath the device
268 	 */
269 	if (child_range_add(mod,
270 	    ntn, PCIEX_FUNCTION, 0, MAX_PCIDEV_FNS) < 0) {
271 		topo_node_unbind(ntn);
272 		return (NULL);
273 	}
274 	return (ntn);
275 }
276 
277 tnode_t *
278 pciexbus_declare(topo_mod_t *mod, tnode_t *parent, di_node_t dn,
279     topo_instance_t i)
280 {
281 	did_t *pd;
282 	tnode_t *ntn;
283 
284 	if ((pd = did_find(mod, dn)) == NULL)
285 		return (NULL);
286 	did_settnode(pd, parent);
287 	if ((ntn = pci_tnode_create(mod, parent, PCIEX_BUS, i, dn)) == NULL)
288 		return (NULL);
289 	if (did_props_set(ntn, pd, Bus_common_props, Bus_propcnt) < 0) {
290 		topo_node_unbind(ntn);
291 		return (NULL);
292 	}
293 	/*
294 	 * We can expect to find pci-express devices beneath the bus
295 	 */
296 	if (child_range_add(mod,
297 	    ntn, PCIEX_DEVICE, 0, MAX_PCIBUS_DEVS) < 0) {
298 		topo_node_unbind(ntn);
299 		return (NULL);
300 	}
301 	return (ntn);
302 }
303 
304 tnode_t *
305 pcifn_declare(topo_mod_t *mod, tnode_t *parent, di_node_t dn,
306     topo_instance_t i)
307 {
308 	did_t *pd;
309 	tnode_t *ntn;
310 
311 	if ((pd = did_find(mod, dn)) == NULL)
312 		return (NULL);
313 	did_excap_set(pd, PCIE_PCIECAP_DEV_TYPE_PCI_DEV);
314 
315 	if ((ntn = pci_tnode_create(mod, parent, PCI_FUNCTION, i, dn)) == NULL)
316 		return (NULL);
317 	if (did_props_set(ntn, pd, Fn_common_props, Fn_propcnt) < 0) {
318 		topo_node_unbind(ntn);
319 		return (NULL);
320 	}
321 	/*
322 	 * We may find pci buses beneath a function
323 	 */
324 	if (child_range_add(mod, ntn, PCI_BUS, 0, MAX_HB_BUSES) < 0) {
325 		topo_node_unbind(ntn);
326 		return (NULL);
327 	}
328 	return (ntn);
329 }
330 
331 tnode_t *
332 pcidev_declare(topo_mod_t *mod, tnode_t *parent, di_node_t dn,
333     topo_instance_t i)
334 {
335 	did_t *pd;
336 	tnode_t *ntn;
337 
338 	if ((pd = did_find(mod, dn)) == NULL)
339 		return (NULL);
340 	/* remember parent tnode */
341 	did_settnode(pd, parent);
342 
343 	if ((ntn = pci_tnode_create(mod, parent, PCI_DEVICE, i, dn)) == NULL)
344 		return (NULL);
345 	if (did_props_set(ntn, pd, Dev_common_props, Dev_propcnt) < 0) {
346 		topo_node_unbind(ntn);
347 		return (NULL);
348 	}
349 
350 	/*
351 	 * We can expect to find pci functions beneath the device
352 	 */
353 	if (child_range_add(mod, ntn, PCI_FUNCTION, 0, MAX_PCIDEV_FNS) < 0) {
354 		topo_node_unbind(ntn);
355 		return (NULL);
356 	}
357 	return (ntn);
358 }
359 
360 tnode_t *
361 pcibus_declare(topo_mod_t *mod, tnode_t *parent, di_node_t dn,
362     topo_instance_t i)
363 {
364 	did_t *pd;
365 	tnode_t *ntn;
366 	int hbchild = 0;
367 
368 	if ((pd = did_find(mod, dn)) == NULL)
369 		return (NULL);
370 	did_settnode(pd, parent);
371 	if ((ntn = pci_tnode_create(mod, parent, PCI_BUS, i, dn)) == NULL)
372 		return (NULL);
373 	/*
374 	 * If our devinfo node is lacking certain information of its
375 	 * own, and our parent topology node is a hostbridge, we may
376 	 * need/want to inherit information available in the
377 	 * hostbridge node's private data.
378 	 */
379 	if (strcmp(topo_node_name(parent), HOSTBRIDGE) == 0)
380 		hbchild = 1;
381 	if (did_props_set(ntn, pd, Bus_common_props, Bus_propcnt) < 0) {
382 		topo_node_unbind(ntn);
383 		return (NULL);
384 	}
385 	/*
386 	 * We can expect to find pci devices beneath the bus
387 	 */
388 	if (child_range_add(mod, ntn, PCI_DEVICE, 0, MAX_PCIBUS_DEVS) < 0) {
389 		topo_node_unbind(ntn);
390 		return (NULL);
391 	}
392 	/*
393 	 * On each bus child of the hostbridge, we represent the
394 	 * hostbridge as a device outside the range of legal device
395 	 * numbers.
396 	 */
397 	if (hbchild == 1) {
398 		if (hostbridge_asdevice(mod, ntn) < 0) {
399 			topo_node_range_destroy(ntn, PCI_DEVICE);
400 			topo_node_unbind(ntn);
401 			return (NULL);
402 		}
403 	}
404 	return (ntn);
405 }
406 
407 static int
408 pci_bridge_declare(topo_mod_t *mod, tnode_t *fn, di_node_t din, int board,
409     int bridge, int rc, int depth)
410 {
411 	int err;
412 	char *devtyp;
413 
414 	devtyp = pci_devtype_get(mod, din);
415 	/* Check if the children are PCI or PCIe */
416 	if (devtyp && (strcmp(devtyp, "pciex") == 0))
417 		err = pci_children_instantiate(mod, fn, din, board, bridge,
418 		    rc, TRUST_BDF, depth + 1);
419 	else
420 		err = pci_children_instantiate(mod, fn, din, board, bridge,
421 		    rc - TO_PCI, TRUST_BDF, depth + 1);
422 	return (err);
423 }
424 
425 static void
426 declare_dev_and_fn(topo_mod_t *mod, tnode_t *bus, tnode_t **dev, di_node_t din,
427     int board, int bridge, int rc, int devno, int fnno, int depth)
428 {
429 	int dcnt = 0;
430 	tnode_t *fn;
431 	uint_t class, subclass;
432 	uint_t vid, did;
433 	did_t *dp = NULL;
434 
435 	if (*dev == NULL) {
436 		if (rc >= 0)
437 			*dev = pciexdev_declare(mod, bus, din, devno);
438 		else
439 			*dev = pcidev_declare(mod, bus, din, devno);
440 		if (*dev == NULL)
441 			return;
442 		++dcnt;
443 	}
444 	if (rc >= 0)
445 		fn = pciexfn_declare(mod, *dev, din, fnno);
446 	else
447 		fn = pcifn_declare(mod, *dev, din, fnno);
448 
449 	if (fn == NULL) {
450 		if (dcnt) {
451 			topo_node_unbind(*dev);
452 			*dev = NULL;
453 		}
454 		return;
455 	}
456 
457 	if (pci_classcode_get(mod, din, &class, &subclass) < 0) {
458 		topo_node_unbind(fn);
459 		if (dcnt)
460 			topo_node_unbind(*dev);
461 		return;
462 	}
463 
464 	/*
465 	 * This function may be a bridge.  If not, check for a possible
466 	 * topology map file and kick off its enumeration of lower-level
467 	 * devices.
468 	 */
469 	if (class == PCI_CLASS_BRIDGE && subclass == PCI_BRIDGE_PCI) {
470 		(void) pci_bridge_declare(mod, fn, din, board, bridge, rc,
471 		    depth);
472 	}
473 
474 	/*
475 	 * Check for a Neptune-based NIC. This could either be a Neptune
476 	 * adapter card or an Neptune ASIC on a board (e.g. motherboard)
477 	 *
478 	 * For Netpune adapter cards, use xfp-hc-topology.xml to expand
479 	 * topology to include the XFP optical module, which is a FRU on
480 	 * the Neptune based 10giga fiber NICs.
481 	 *
482 	 * For Neptune ASICs, use the XAUI enumerator to expand topology.
483 	 * The 10giga ports are externalized by a XAUI cards, which
484 	 * are FRUs. The XAUI enumerator in turn instantiates the XFP
485 	 * optical module FRUs.
486 	 */
487 	else if (class == PCI_CLASS_NET &&
488 	    di_uintprop_get(mod, din, DI_VENDIDPROP, &vid) >= 0 &&
489 	    di_uintprop_get(mod, din, DI_DEVIDPROP, &did) >= 0) {
490 		if (vid == SUN_VENDOR_ID && did == NEPTUNE_DEVICE_ID) {
491 			/*
492 			 * Is this an adapter card? Check the bus's physlot
493 			 */
494 			dp = did_find(mod, topo_node_getspecific(bus));
495 			if (did_physlot(dp) >= 0) {
496 				topo_mod_dprintf(mod, "Found Neptune slot\n");
497 				(void) topo_mod_enummap(mod, fn,
498 				    "xfp", FM_FMRI_SCHEME_HC);
499 			} else {
500 				topo_mod_dprintf(mod, "Found Neptune ASIC\n");
501 				if (topo_mod_load(mod, XAUI, TOPO_VERSION) ==
502 				    NULL) {
503 					topo_mod_dprintf(mod, "pcibus enum "
504 					    "could not load xaui enum\n");
505 					topo_mod_seterrno(mod,
506 					    EMOD_PARTIAL_ENUM);
507 					return;
508 				} else {
509 					if (topo_node_range_create(mod, fn,
510 					    XAUI, 0, 1) < 0) {
511 						topo_mod_dprintf(mod,
512 						    "child_range_add for "
513 						    "XAUI failed: %s\n",
514 						    topo_strerror(
515 						    topo_mod_errno(mod)));
516 						return;
517 					}
518 					(void) topo_mod_enumerate(mod, fn,
519 					    XAUI, XAUI, fnno, fnno, fn);
520 				}
521 			}
522 		}
523 	}
524 }
525 
526 int
527 pci_children_instantiate(topo_mod_t *mod, tnode_t *parent, di_node_t pn,
528     int board, int bridge, int rc, int bover, int depth)
529 {
530 	did_t *pps[MAX_PCIBUS_DEVS][MAX_PCIDEV_FNS];
531 	did_t *bp = NULL;
532 	did_t *np;
533 	di_node_t sib;
534 	di_node_t din;
535 	tnode_t *bn = NULL;
536 	tnode_t *dn = NULL;
537 	int pb = -1;
538 	int b, d, f;
539 
540 	for (d = 0; d < MAX_PCIBUS_DEVS; d++)
541 		for (f = 0; f < MAX_PCIDEV_FNS; f++)
542 			pps[d][f] = NULL;
543 
544 	/* start at the parent's first sibling */
545 	sib = di_child_node(pn);
546 	while (sib != DI_NODE_NIL) {
547 		np = did_create(mod, sib, board, bridge, rc, bover);
548 		if (np == NULL)
549 			return (-1);
550 		did_BDF(np, &b, &d, &f);
551 		pps[d][f] = np;
552 		if (bp == NULL)
553 			bp = np;
554 		if (pb < 0)
555 			pb = ((bover == TRUST_BDF) ? b : bover);
556 		sib = di_sibling_node(sib);
557 	}
558 	if (pb < 0 && bover < 0)
559 		return (0);
560 	if (rc >= 0)
561 		bn = pciexbus_declare(mod, parent, pn, ((pb < 0) ? bover : pb));
562 	else
563 		bn = pcibus_declare(mod, parent, pn, ((pb < 0) ? bover : pb));
564 	if (bn == NULL)
565 		return (-1);
566 	if (pb < 0)
567 		return (0);
568 
569 	for (d = 0; d < MAX_PCIBUS_DEVS; d++) {
570 		for (f = 0; f < MAX_PCIDEV_FNS; f++) {
571 			if (pps[d][f] == NULL)
572 				continue;
573 			din = did_dinode(pps[d][f]);
574 
575 			/*
576 			 * Try to enumerate as many devices and functions as
577 			 * possible.  If we fail to declare a device, break
578 			 * out of the function loop.
579 			 */
580 			declare_dev_and_fn(mod, bn,
581 			    &dn, din, board, bridge, rc, d, f, depth);
582 			did_rele(pps[d][f]);
583 
584 			if (dn == NULL)
585 				break;
586 		}
587 		dn = NULL;
588 	}
589 	return (0);
590 }
591 
592 static int
593 pciexbus_enum(topo_mod_t *mp, tnode_t *ptn, char *pnm, topo_instance_t min,
594     topo_instance_t max)
595 {
596 	di_node_t pdn;
597 	int rc;
598 	int retval;
599 
600 	/*
601 	 * PCI-Express; root complex shares the hostbridge's instance
602 	 * number.  Parent node's private data is a simple di_node_t
603 	 * and we have to construct our own did hash and did_t.
604 	 */
605 	rc = topo_node_instance(ptn);
606 
607 	if ((pdn = topo_node_getspecific(ptn)) == DI_NODE_NIL) {
608 		topo_mod_dprintf(mp,
609 		    "Parent %s node missing private data.\n"
610 		    "Unable to proceed with %s enumeration.\n", pnm, PCIEX_BUS);
611 		return (0);
612 	}
613 	if (did_hash_init(mp) != 0)
614 		return (-1);
615 	if ((did_create(mp, pdn, 0, 0, rc, TRUST_BDF)) == NULL)
616 		return (-1);	/* errno already set */
617 
618 	retval = pci_children_instantiate(mp, ptn, pdn, 0, 0, rc,
619 	    (min == max) ? min : TRUST_BDF, 0);
620 	did_hash_fini(mp);
621 
622 	return (retval);
623 }
624 
625 static int
626 pcibus_enum(topo_mod_t *mp, tnode_t *ptn, char *pnm, topo_instance_t min,
627     topo_instance_t max, void *data)
628 {
629 	did_t *didp, *hbdid = (did_t *)data;
630 	int retval;
631 
632 	/*
633 	 * XXTOPO: we should not be sharing private node data with another
634 	 * module. PCI Bus; Parent node's private data is a did_t.  We'll
635 	 * use the did hash established by the parent.
636 	 */
637 	did_setspecific(mp, data);
638 
639 	/*
640 	 * If we're looking for a specific bus-instance, find the right
641 	 * did_t in the chain, otherwise, there should be only one did_t.
642 	 */
643 	if (min == max) {
644 		int b;
645 		didp = hbdid;
646 		while (didp != NULL) {
647 			did_BDF(didp, &b, NULL, NULL);
648 			if (b == min)
649 				break;
650 			didp = did_link_get(didp);
651 		}
652 		if (didp == NULL) {
653 			topo_mod_dprintf(mp,
654 			    "Parent %s node missing private data related\n"
655 			    "to %s instance %d.\n", pnm, PCI_BUS, min);
656 			topo_mod_setspecific(mp, NULL);
657 			return (0);
658 		}
659 	} else {
660 		assert(did_link_get(hbdid) == NULL);
661 		didp = hbdid;
662 	}
663 	retval = pci_children_instantiate(mp, ptn, did_dinode(didp),
664 	    did_board(didp), did_bridge(didp), did_rc(didp),
665 	    (min == max) ? min : TRUST_BDF, 0);
666 
667 	topo_mod_setspecific(mp, NULL);
668 
669 	return (retval);
670 }
671 
672 /*ARGSUSED*/
673 static int
674 pci_enum(topo_mod_t *mod, tnode_t *ptn, const char *name,
675     topo_instance_t min, topo_instance_t max, void *notused, void *data)
676 {
677 	int retval;
678 	char *pname;
679 
680 	topo_mod_dprintf(mod, "Enumerating pci!\n");
681 
682 	if (strcmp(name, PCI_BUS) != 0 && strcmp(name, PCIEX_BUS) != 0) {
683 		topo_mod_dprintf(mod,
684 		    "Currently only know how to enumerate %s or %s.\n",
685 		    PCI_BUS, PCIEX_BUS);
686 		return (0);
687 	}
688 	pname = topo_node_name(ptn);
689 	if (strcmp(pname, HOSTBRIDGE) != 0 && strcmp(pname, PCIEX_ROOT) != 0) {
690 		topo_mod_dprintf(mod,
691 		    "Currently can only enumerate a %s or %s directly\n",
692 		    PCI_BUS, PCIEX_BUS);
693 		topo_mod_dprintf(mod,
694 		    "descended from a %s or %s node.\n",
695 		    HOSTBRIDGE, PCIEX_ROOT);
696 		return (0);
697 	}
698 
699 	if (strcmp(name, PCI_BUS) == 0) {
700 		retval = pcibus_enum(mod, ptn, pname, min, max, data);
701 	} else if (strcmp(name, PCIEX_BUS) == 0) {
702 		retval = pciexbus_enum(mod, ptn, pname, min, max);
703 	} else {
704 		topo_mod_dprintf(mod,
705 		    "Currently only know how to enumerate %s or %s not %s.\n",
706 		    PCI_BUS, PCIEX_BUS, name);
707 		return (0);
708 	}
709 
710 	return (retval);
711 }
712 
713 /*ARGSUSED*/
714 static void
715 pci_release(topo_mod_t *mp, tnode_t *node)
716 {
717 	topo_method_unregister_all(mp, node);
718 
719 	/*
720 	 * node private data (did_t) for this node is destroyed in
721 	 * did_hash_destroy()
722 	 */
723 
724 	topo_node_unbind(node);
725 }
726