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