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