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