xref: /illumos-gate/usr/src/lib/fm/topo/modules/common/pcibus/pcibus.c (revision 508a0e8cf1600b06c1f7361ad76e736710d3fdf8)
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 2019 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/ddi_ufm.h>
44 #include <sys/stat.h>
45 #include <sys/types.h>
46 
47 #include <hostbridge.h>
48 #include <pcibus.h>
49 #include <did.h>
50 #include <did_props.h>
51 #include <util.h>
52 #include <topo_nic.h>
53 #include <topo_usb.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 *node)
169 {
170 	char *devpath = NULL;
171 	ufm_ioc_getcaps_t ugc = { 0 };
172 	ufm_ioc_bufsz_t ufbz = { 0 };
173 	ufm_ioc_report_t ufmr = { 0 };
174 	nvlist_t *ufminfo = NULL, **images;
175 	uint_t nimages;
176 	int err, fd, ret = -1;
177 
178 	if (topo_prop_get_string(node, TOPO_PGROUP_IO, TOPO_IO_DEV, &devpath,
179 	    &err) != 0) {
180 		return (topo_mod_seterrno(mod, EMOD_UNKNOWN));
181 	}
182 	if (strlen(devpath) >= MAXPATHLEN) {
183 		topo_mod_dprintf(mod, "devpath is too long: %s", devpath);
184 		topo_mod_strfree(mod, devpath);
185 		return (topo_mod_seterrno(mod, EMOD_UNKNOWN));
186 	}
187 
188 	if ((fd = open(DDI_UFM_DEV, O_RDONLY)) < 0) {
189 		topo_mod_dprintf(mod, "%s: failed to open %s", __func__,
190 		    DDI_UFM_DEV);
191 		topo_mod_strfree(mod, devpath);
192 		return (0);
193 	}
194 	/*
195 	 * Make an ioctl to probe if the driver for this function is
196 	 * UFM-capable.  If the ioctl fails or if it doesn't advertise the
197 	 * DDI_UFM_CAP_REPORT capability, we bail out.
198 	 */
199 	ugc.ufmg_version = DDI_UFM_CURRENT_VERSION;
200 	(void) strlcpy(ugc.ufmg_devpath, devpath, MAXPATHLEN);
201 	if (ioctl(fd, UFM_IOC_GETCAPS, &ugc) < 0) {
202 		topo_mod_dprintf(mod, "UFM_IOC_GETCAPS failed: %s",
203 		    strerror(errno));
204 		(void) close(fd);
205 		topo_mod_strfree(mod, devpath);
206 		return (0);
207 	}
208 	if ((ugc.ufmg_caps & DDI_UFM_CAP_REPORT) == 0) {
209 		topo_mod_dprintf(mod, "driver doesn't advertise "
210 		    "DDI_UFM_CAP_REPORT");
211 		(void) close(fd);
212 		topo_mod_strfree(mod, devpath);
213 		return (0);
214 	}
215 
216 	/*
217 	 * If we made it this far, then the driver is indeed UFM-capable and
218 	 * is capable of reporting its firmware information.  First step is to
219 	 * make an ioctl to query the size of the report data so that we can
220 	 * allocate a buffer large enough to hold it.
221 	 */
222 	ufbz.ufbz_version = DDI_UFM_CURRENT_VERSION;
223 	(void) strlcpy(ufbz.ufbz_devpath, devpath, MAXPATHLEN);
224 	if (ioctl(fd, UFM_IOC_REPORTSZ, &ufbz) < 0) {
225 		topo_mod_dprintf(mod, "UFM_IOC_REPORTSZ failed: %s\n",
226 		    strerror(errno));
227 		(void) close(fd);
228 		topo_mod_strfree(mod, devpath);
229 		return (0);
230 	}
231 
232 	ufmr.ufmr_version = DDI_UFM_CURRENT_VERSION;
233 	if ((ufmr.ufmr_buf = topo_mod_alloc(mod, ufbz.ufbz_size)) == NULL) {
234 		topo_mod_dprintf(mod, "failed to alloc %u bytes\n",
235 		    ufbz.ufbz_size);
236 		(void) close(fd);
237 		topo_mod_strfree(mod, devpath);
238 		return (topo_mod_seterrno(mod, EMOD_NOMEM));
239 	}
240 	ufmr.ufmr_bufsz = ufbz.ufbz_size;
241 	(void) strlcpy(ufmr.ufmr_devpath, devpath, MAXPATHLEN);
242 	topo_mod_strfree(mod, devpath);
243 
244 	/*
245 	 * Now, make the ioctl to retrieve the actual report data.  The data
246 	 * is stored as a packed nvlist.
247 	 */
248 	if (ioctl(fd, UFM_IOC_REPORT, &ufmr) < 0) {
249 		topo_mod_dprintf(mod, "UFM_IOC_REPORT failed: %s\n",
250 		    strerror(errno));
251 		topo_mod_free(mod, ufmr.ufmr_buf, ufmr.ufmr_bufsz);
252 		(void) close(fd);
253 		return (topo_mod_seterrno(mod, EMOD_UNKNOWN));
254 	}
255 	(void) close(fd);
256 
257 	if (nvlist_unpack(ufmr.ufmr_buf, ufmr.ufmr_bufsz, &ufminfo,
258 	    NV_ENCODE_NATIVE) != 0) {
259 		topo_mod_dprintf(mod, "failed to unpack nvlist\n");
260 		topo_mod_free(mod, ufmr.ufmr_buf, ufmr.ufmr_bufsz);
261 		return (topo_mod_seterrno(mod, EMOD_UNKNOWN));
262 	}
263 	topo_mod_free(mod, ufmr.ufmr_buf, ufmr.ufmr_bufsz);
264 
265 	if (nvlist_lookup_nvlist_array(ufminfo, DDI_UFM_NV_IMAGES, &images,
266 	    &nimages) != 0) {
267 		topo_mod_dprintf(mod, "failed to lookup %s nvpair",
268 		    DDI_UFM_NV_IMAGES);
269 		(void) topo_mod_seterrno(mod, EMOD_UNKNOWN);
270 		goto err;
271 	}
272 	if (topo_node_range_create(mod, node, UFM, 0, (nimages - 1)) != 0) {
273 		topo_mod_dprintf(mod, "failed to create %s range", UFM);
274 		/* errno set */
275 		goto err;
276 	}
277 	for (uint_t i = 0; i < nimages; i++) {
278 		tnode_t *ufmnode = NULL;
279 		char *descr;
280 		uint_t nslots;
281 		nvlist_t **slots;
282 
283 		if (nvlist_lookup_string(images[i], DDI_UFM_NV_IMAGE_DESC,
284 		    &descr) != 0 ||
285 		    nvlist_lookup_nvlist_array(images[i],
286 		    DDI_UFM_NV_IMAGE_SLOTS, &slots, &nslots) != 0) {
287 			(void) topo_mod_seterrno(mod, EMOD_UNKNOWN);
288 			goto err;
289 		}
290 		if ((ufmnode = topo_mod_create_ufm(mod, node, descr, NULL)) ==
291 		    NULL) {
292 			topo_mod_dprintf(mod, "failed to create ufm nodes for "
293 			    "%s", descr);
294 			/* errno set */
295 			goto err;
296 		}
297 		for (uint_t s = 0; s < nslots; s++) {
298 			topo_ufm_slot_info_t slotinfo = { 0 };
299 			uint32_t slotattrs;
300 
301 			if (nvlist_lookup_string(slots[s],
302 			    DDI_UFM_NV_SLOT_VERSION,
303 			    (char **)&slotinfo.usi_version) != 0 ||
304 			    nvlist_lookup_uint32(slots[s],
305 			    DDI_UFM_NV_SLOT_ATTR, &slotattrs) != 0) {
306 				topo_node_unbind(ufmnode);
307 				topo_mod_dprintf(mod, "malformed slot nvlist");
308 				(void) topo_mod_seterrno(mod, EMOD_UNKNOWN);
309 				goto err;
310 			}
311 			(void) nvlist_lookup_nvlist(slots[s],
312 			    DDI_UFM_NV_SLOT_MISC, &slotinfo.usi_extra);
313 
314 			if (slotattrs & DDI_UFM_ATTR_READABLE &&
315 			    slotattrs & DDI_UFM_ATTR_WRITEABLE)
316 				slotinfo.usi_mode = TOPO_UFM_SLOT_MODE_RW;
317 			else if (slotattrs & DDI_UFM_ATTR_READABLE)
318 				slotinfo.usi_mode = TOPO_UFM_SLOT_MODE_RO;
319 			else if (slotattrs & DDI_UFM_ATTR_WRITEABLE)
320 				slotinfo.usi_mode = TOPO_UFM_SLOT_MODE_WO;
321 			else
322 				slotinfo.usi_mode = TOPO_UFM_SLOT_MODE_NONE;
323 
324 			if (slotattrs & DDI_UFM_ATTR_ACTIVE)
325 				slotinfo.usi_active = B_TRUE;
326 
327 			if (topo_node_range_create(mod, ufmnode, SLOT, 0,
328 			    (nslots - 1)) < 0) {
329 				topo_mod_dprintf(mod, "failed to create %s "
330 				    "range", SLOT);
331 				/* errno set */
332 				goto err;
333 			}
334 			if (topo_mod_create_ufm_slot(mod, ufmnode,
335 			    &slotinfo) == NULL) {
336 				topo_node_unbind(ufmnode);
337 				topo_mod_dprintf(mod, "failed to create ufm "
338 				    "slot %d for %s", s, descr);
339 				/* errno set */
340 				goto err;
341 			}
342 		}
343 	}
344 	ret = 0;
345 err:
346 	nvlist_free(ufminfo);
347 	return (ret);
348 }
349 
350 tnode_t *
351 pciexfn_declare(topo_mod_t *mod, tnode_t *parent, di_node_t dn,
352     topo_instance_t i)
353 {
354 	did_t *pd;
355 	tnode_t *ntn, *ptn;
356 	di_node_t pdn;
357 	uint_t class, subclass;
358 	char *devtyp, *pdevtyp;
359 	int pcie_devtyp, pexcap;
360 	boolean_t dev_is_pcie, pdev_is_pcie;
361 
362 	/* We need the parent's dev info node for some of the info */
363 	ptn = find_predecessor(parent, PCIEX_FUNCTION);
364 	/* If this is the first child under root, get root's ptn */
365 	if (ptn == NULL)
366 		ptn = find_predecessor(parent, PCIEX_ROOT);
367 	if (ptn == NULL)
368 		return (NULL);
369 	pdn = topo_node_getspecific(ptn);
370 
371 	/* Get the required info to populate the excap */
372 	(void) pci_classcode_get(mod, dn, &class, &subclass);
373 	devtyp = pci_devtype_get(mod, dn);
374 	pdevtyp = pci_devtype_get(mod, pdn);
375 	pexcap = pciex_cap_get(mod, pdn);
376 
377 	dev_is_pcie = devtyp && (strcmp(devtyp, "pciex") == 0);
378 	pdev_is_pcie = pdevtyp && (strcmp(pdevtyp, "pciex") == 0);
379 
380 	/*
381 	 * Populate the excap with correct PCIe device type.
382 	 *
383 	 * Device	Parent		Device		Parent	Device
384 	 * excap	device-type	device-type	excap	Class Code
385 	 * -------------------------------------------------------------------
386 	 * PCI(default)	pci		N/A		N/A	!= bridge
387 	 * PCIe		pciex		N/A		N/A	!= bridge
388 	 * Root Port	Defined in hostbridge
389 	 * Switch Up	pciex		pciex		!= up	= bridge
390 	 * Switch Down	pciex		pciex		= up	= bridge
391 	 * PCIe-PCI	pciex		pci		N/A	= bridge
392 	 * PCI-PCIe	pci		pciex		N/A	= bridge
393 	 */
394 	pcie_devtyp = PCIE_PCIECAP_DEV_TYPE_PCI_DEV;
395 	if (class == PCI_CLASS_BRIDGE && subclass == PCI_BRIDGE_PCI) {
396 		if (pdev_is_pcie) {
397 			if (dev_is_pcie) {
398 				if (pexcap != PCIE_PCIECAP_DEV_TYPE_UP)
399 					pcie_devtyp = PCIE_PCIECAP_DEV_TYPE_UP;
400 				else
401 					pcie_devtyp =
402 					    PCIE_PCIECAP_DEV_TYPE_DOWN;
403 			} else {
404 				pcie_devtyp = PCIE_PCIECAP_DEV_TYPE_PCIE2PCI;
405 			}
406 		} else {
407 			if (dev_is_pcie)
408 				pcie_devtyp = PCIE_PCIECAP_DEV_TYPE_PCI2PCIE;
409 		}
410 	} else {
411 		if (pdev_is_pcie)
412 			pcie_devtyp = PCIE_PCIECAP_DEV_TYPE_PCIE_DEV;
413 	}
414 
415 	if ((pd = did_find(mod, dn)) == NULL)
416 		return (NULL);
417 	did_excap_set(pd, pcie_devtyp);
418 
419 	if ((ntn = pci_tnode_create(mod, parent, PCIEX_FUNCTION, i, dn))
420 	    == NULL)
421 		return (NULL);
422 	if (did_props_set(ntn, pd, Fn_common_props, Fn_propcnt) < 0) {
423 		topo_node_unbind(ntn);
424 		return (NULL);
425 	}
426 
427 	/*
428 	 * Check if the driver associated with this function exports firmware
429 	 * information via the DDI UFM subsystem and, if so, create the
430 	 * corresponding ufm topo nodes.
431 	 */
432 	if (pciexfn_add_ufm(mod, ntn) != 0) {
433 		topo_node_unbind(ntn);
434 		return (NULL);
435 	}
436 
437 	/*
438 	 * We may find pci-express buses or plain-pci buses beneath a function
439 	 */
440 	if (child_range_add(mod, ntn, PCIEX_BUS, 0, MAX_HB_BUSES) < 0) {
441 		topo_node_unbind(ntn);
442 		return (NULL);
443 	}
444 	if (child_range_add(mod, ntn, PCI_BUS, 0, MAX_HB_BUSES) < 0) {
445 		topo_node_range_destroy(ntn, PCIEX_BUS);
446 		topo_node_unbind(ntn);
447 		return (NULL);
448 	}
449 	return (ntn);
450 }
451 
452 tnode_t *
453 pciexdev_declare(topo_mod_t *mod, tnode_t *parent, di_node_t dn,
454     topo_instance_t i)
455 {
456 	did_t *pd;
457 	tnode_t *ntn;
458 
459 	if ((pd = did_find(mod, dn)) == NULL)
460 		return (NULL);
461 	did_settnode(pd, parent);
462 
463 	if ((ntn = pci_tnode_create(mod, parent, PCIEX_DEVICE, i, dn)) == NULL)
464 		return (NULL);
465 	if (did_props_set(ntn, pd, Dev_common_props, Dev_propcnt) < 0) {
466 		topo_node_unbind(ntn);
467 		return (NULL);
468 	}
469 
470 	/*
471 	 * We can expect to find pci-express functions beneath the device
472 	 */
473 	if (child_range_add(mod,
474 	    ntn, PCIEX_FUNCTION, 0, MAX_PCIDEV_FNS) < 0) {
475 		topo_node_unbind(ntn);
476 		return (NULL);
477 	}
478 	return (ntn);
479 }
480 
481 tnode_t *
482 pciexbus_declare(topo_mod_t *mod, tnode_t *parent, di_node_t dn,
483     topo_instance_t i)
484 {
485 	did_t *pd;
486 	tnode_t *ntn;
487 
488 	if ((pd = did_find(mod, dn)) == NULL)
489 		return (NULL);
490 	did_settnode(pd, parent);
491 	if ((ntn = pci_tnode_create(mod, parent, PCIEX_BUS, i, dn)) == NULL)
492 		return (NULL);
493 	if (did_props_set(ntn, pd, Bus_common_props, Bus_propcnt) < 0) {
494 		topo_node_unbind(ntn);
495 		return (NULL);
496 	}
497 	/*
498 	 * We can expect to find pci-express devices beneath the bus
499 	 */
500 	if (child_range_add(mod,
501 	    ntn, PCIEX_DEVICE, 0, MAX_PCIBUS_DEVS) < 0) {
502 		topo_node_unbind(ntn);
503 		return (NULL);
504 	}
505 	return (ntn);
506 }
507 
508 tnode_t *
509 pcifn_declare(topo_mod_t *mod, tnode_t *parent, di_node_t dn,
510     topo_instance_t i)
511 {
512 	did_t *pd;
513 	tnode_t *ntn;
514 
515 	if ((pd = did_find(mod, dn)) == NULL)
516 		return (NULL);
517 	did_excap_set(pd, PCIE_PCIECAP_DEV_TYPE_PCI_DEV);
518 
519 	if ((ntn = pci_tnode_create(mod, parent, PCI_FUNCTION, i, dn)) == NULL)
520 		return (NULL);
521 	if (did_props_set(ntn, pd, Fn_common_props, Fn_propcnt) < 0) {
522 		topo_node_unbind(ntn);
523 		return (NULL);
524 	}
525 	/*
526 	 * We may find pci buses beneath a function
527 	 */
528 	if (child_range_add(mod, ntn, PCI_BUS, 0, MAX_HB_BUSES) < 0) {
529 		topo_node_unbind(ntn);
530 		return (NULL);
531 	}
532 	return (ntn);
533 }
534 
535 tnode_t *
536 pcidev_declare(topo_mod_t *mod, tnode_t *parent, di_node_t dn,
537     topo_instance_t i)
538 {
539 	did_t *pd;
540 	tnode_t *ntn;
541 
542 	if ((pd = did_find(mod, dn)) == NULL)
543 		return (NULL);
544 	/* remember parent tnode */
545 	did_settnode(pd, parent);
546 
547 	if ((ntn = pci_tnode_create(mod, parent, PCI_DEVICE, i, dn)) == NULL)
548 		return (NULL);
549 	if (did_props_set(ntn, pd, Dev_common_props, Dev_propcnt) < 0) {
550 		topo_node_unbind(ntn);
551 		return (NULL);
552 	}
553 
554 	/*
555 	 * We can expect to find pci functions beneath the device
556 	 */
557 	if (child_range_add(mod, ntn, PCI_FUNCTION, 0, MAX_PCIDEV_FNS) < 0) {
558 		topo_node_unbind(ntn);
559 		return (NULL);
560 	}
561 	return (ntn);
562 }
563 
564 tnode_t *
565 pcibus_declare(topo_mod_t *mod, tnode_t *parent, di_node_t dn,
566     topo_instance_t i)
567 {
568 	did_t *pd;
569 	tnode_t *ntn;
570 	int hbchild = 0;
571 
572 	if ((pd = did_find(mod, dn)) == NULL)
573 		return (NULL);
574 	did_settnode(pd, parent);
575 	if ((ntn = pci_tnode_create(mod, parent, PCI_BUS, i, dn)) == NULL)
576 		return (NULL);
577 	/*
578 	 * If our devinfo node is lacking certain information of its
579 	 * own, and our parent topology node is a hostbridge, we may
580 	 * need/want to inherit information available in the
581 	 * hostbridge node's private data.
582 	 */
583 	if (strcmp(topo_node_name(parent), HOSTBRIDGE) == 0)
584 		hbchild = 1;
585 	if (did_props_set(ntn, pd, Bus_common_props, Bus_propcnt) < 0) {
586 		topo_node_unbind(ntn);
587 		return (NULL);
588 	}
589 	/*
590 	 * We can expect to find pci devices beneath the bus
591 	 */
592 	if (child_range_add(mod, ntn, PCI_DEVICE, 0, MAX_PCIBUS_DEVS) < 0) {
593 		topo_node_unbind(ntn);
594 		return (NULL);
595 	}
596 	/*
597 	 * On each bus child of the hostbridge, we represent the
598 	 * hostbridge as a device outside the range of legal device
599 	 * numbers.
600 	 */
601 	if (hbchild == 1) {
602 		if (hostbridge_asdevice(mod, ntn) < 0) {
603 			topo_node_range_destroy(ntn, PCI_DEVICE);
604 			topo_node_unbind(ntn);
605 			return (NULL);
606 		}
607 	}
608 	return (ntn);
609 }
610 
611 static int
612 pci_bridge_declare(topo_mod_t *mod, tnode_t *fn, di_node_t din, int board,
613     int bridge, int rc, int depth)
614 {
615 	int err;
616 	char *devtyp;
617 
618 	devtyp = pci_devtype_get(mod, din);
619 	/* Check if the children are PCI or PCIe */
620 	if (devtyp && (strcmp(devtyp, "pciex") == 0))
621 		err = pci_children_instantiate(mod, fn, din, board, bridge,
622 		    rc, TRUST_BDF, depth + 1);
623 	else
624 		err = pci_children_instantiate(mod, fn, din, board, bridge,
625 		    rc - TO_PCI, TRUST_BDF, depth + 1);
626 	return (err);
627 }
628 
629 static void
630 declare_dev_and_fn(topo_mod_t *mod, tnode_t *bus, tnode_t **dev, di_node_t din,
631     int board, int bridge, int rc, int devno, int fnno, int depth)
632 {
633 	int dcnt = 0, rcnt;
634 	char *propstr;
635 	tnode_t *fn;
636 	uint_t class, subclass;
637 	uint_t vid, did;
638 	did_t *dp = NULL;
639 
640 	if (*dev == NULL) {
641 		if (rc >= 0)
642 			*dev = pciexdev_declare(mod, bus, din, devno);
643 		else
644 			*dev = pcidev_declare(mod, bus, din, devno);
645 		if (*dev == NULL)
646 			return;
647 		++dcnt;
648 	}
649 	if (rc >= 0)
650 		fn = pciexfn_declare(mod, *dev, din, fnno);
651 	else
652 		fn = pcifn_declare(mod, *dev, din, fnno);
653 
654 	if (fn == NULL) {
655 		if (dcnt) {
656 			topo_node_unbind(*dev);
657 			*dev = NULL;
658 		}
659 		return;
660 	}
661 
662 	if (pci_classcode_get(mod, din, &class, &subclass) < 0) {
663 		topo_node_unbind(fn);
664 		if (dcnt)
665 			topo_node_unbind(*dev);
666 		return;
667 	}
668 
669 	/*
670 	 * This function may be a bridge.  If not, check for a possible
671 	 * topology map file and kick off its enumeration of lower-level
672 	 * devices.
673 	 */
674 	if (class == PCI_CLASS_BRIDGE && subclass == PCI_BRIDGE_PCI) {
675 		(void) pci_bridge_declare(mod, fn, din, board, bridge, rc,
676 		    depth);
677 	}
678 
679 	/*
680 	 * Check for a Neptune-based NIC. This could either be a Neptune
681 	 * adapter card or an Neptune ASIC on a board (e.g. motherboard)
682 	 *
683 	 * For Netpune adapter cards, use xfp-hc-topology.xml to expand
684 	 * topology to include the XFP optical module, which is a FRU on
685 	 * the Neptune based 10giga fiber NICs.
686 	 *
687 	 * For Neptune ASICs, use the XAUI enumerator to expand topology.
688 	 * The 10giga ports are externalized by a XAUI cards, which
689 	 * are FRUs. The XAUI enumerator in turn instantiates the XFP
690 	 * optical module FRUs.
691 	 */
692 	else if (class == PCI_CLASS_NET &&
693 	    di_uintprop_get(mod, din, DI_VENDIDPROP, &vid) >= 0 &&
694 	    di_uintprop_get(mod, din, DI_DEVIDPROP, &did) >= 0 &&
695 	    vid == SUN_VENDOR_ID && did == NEPTUNE_DEVICE_ID) {
696 		/*
697 		 * Is this an adapter card? Check the bus's physlot
698 		 */
699 		dp = did_find(mod, topo_node_getspecific(bus));
700 		if (did_physlot(dp) >= 0) {
701 			topo_mod_dprintf(mod, "Found Neptune slot\n");
702 			(void) topo_mod_enummap(mod, fn,
703 			    "xfp", FM_FMRI_SCHEME_HC);
704 		} else {
705 			topo_mod_dprintf(mod, "Found Neptune ASIC\n");
706 			if (topo_mod_load(mod, XAUI, TOPO_VERSION) == NULL) {
707 				topo_mod_dprintf(mod, "pcibus enum "
708 				    "could not load xaui enum\n");
709 				(void) topo_mod_seterrno(mod,
710 				    EMOD_PARTIAL_ENUM);
711 				return;
712 			} else {
713 				if (topo_node_range_create(mod, fn,
714 				    XAUI, 0, 1) < 0) {
715 					topo_mod_dprintf(mod,
716 					    "child_range_add for "
717 					    "XAUI failed: %s\n",
718 					    topo_strerror(
719 					    topo_mod_errno(mod)));
720 					return;
721 				}
722 				(void) topo_mod_enumerate(mod, fn,
723 				    XAUI, XAUI, fnno, fnno, fn);
724 			}
725 		}
726 	} else if (class == PCI_CLASS_NET) {
727 		/*
728 		 * Ask the nic module if there are any nodes that need to be
729 		 * enumerated under this device. This might include things like
730 		 * transceivers or some day, LEDs.
731 		 */
732 		if (topo_mod_load(mod, NIC, NIC_VERSION) == NULL) {
733 			topo_mod_dprintf(mod, "pcibus enum could not load "
734 			    "nic enum\n");
735 			(void) topo_mod_seterrno(mod, EMOD_PARTIAL_ENUM);
736 			return;
737 		}
738 
739 		(void) topo_mod_enumerate(mod, fn, NIC, NIC, 0, 0, din);
740 	} else if (class == PCI_CLASS_SERIALBUS && subclass == PCI_SERIAL_USB) {
741 		/*
742 		 * If we encounter a USB controller, make sure to enumerate all
743 		 * of its USB ports.
744 		 */
745 		if (topo_mod_load(mod, USB, USB_VERSION) == NULL) {
746 			topo_mod_dprintf(mod, "pcibus enum could not load "
747 			    "usb enum\n");
748 			(void) topo_mod_seterrno(mod, EMOD_PARTIAL_ENUM);
749 			return;
750 		}
751 
752 		(void) topo_mod_enumerate(mod, fn, USB, USB_PCI, 0, 0, din);
753 	} else if (class == PCI_CLASS_MASS) {
754 		di_node_t cn;
755 		int niports = 0;
756 		extern void pci_iports_instantiate(topo_mod_t *, tnode_t *,
757 		    di_node_t, int);
758 		extern void pci_receptacle_instantiate(topo_mod_t *, tnode_t *,
759 		    di_node_t);
760 
761 		for (cn = di_child_node(din); cn != DI_NODE_NIL;
762 		    cn = di_sibling_node(cn)) {
763 			if (strcmp(di_node_name(cn), IPORT) == 0)
764 				niports++;
765 		}
766 		if (niports > 0)
767 			pci_iports_instantiate(mod, fn, din, niports);
768 
769 		if ((rcnt = di_prop_lookup_strings(DDI_DEV_T_ANY, din,
770 		    DI_RECEPTACLE_PHYMASK, &propstr)) > 0) {
771 			if (topo_node_range_create(mod, fn, RECEPTACLE, 0,
772 			    rcnt) >= 0)
773 				pci_receptacle_instantiate(mod, fn, din);
774 		}
775 	}
776 }
777 
778 int
779 pci_children_instantiate(topo_mod_t *mod, tnode_t *parent, di_node_t pn,
780     int board, int bridge, int rc, int bover, int depth)
781 {
782 	did_t *pps[MAX_PCIBUS_DEVS][MAX_PCIDEV_FNS];
783 	did_t *bp = NULL;
784 	did_t *np;
785 	di_node_t sib;
786 	di_node_t din;
787 	tnode_t *bn = NULL;
788 	tnode_t *dn = NULL;
789 	int pb = -1;
790 	int b, d, f;
791 
792 	for (d = 0; d < MAX_PCIBUS_DEVS; d++)
793 		for (f = 0; f < MAX_PCIDEV_FNS; f++)
794 			pps[d][f] = NULL;
795 
796 	/* start at the parent's first sibling */
797 	sib = di_child_node(pn);
798 	while (sib != DI_NODE_NIL) {
799 		np = did_create(mod, sib, board, bridge, rc, bover);
800 		if (np == NULL)
801 			return (-1);
802 		did_BDF(np, &b, &d, &f);
803 		pps[d][f] = np;
804 		if (bp == NULL)
805 			bp = np;
806 		if (pb < 0)
807 			pb = ((bover == TRUST_BDF) ? b : bover);
808 		sib = di_sibling_node(sib);
809 	}
810 	if (pb < 0 && bover < 0)
811 		return (0);
812 	if (rc >= 0)
813 		bn = pciexbus_declare(mod, parent, pn, ((pb < 0) ? bover : pb));
814 	else
815 		bn = pcibus_declare(mod, parent, pn, ((pb < 0) ? bover : pb));
816 	if (bn == NULL)
817 		return (-1);
818 	if (pb < 0)
819 		return (0);
820 
821 	for (d = 0; d < MAX_PCIBUS_DEVS; d++) {
822 		for (f = 0; f < MAX_PCIDEV_FNS; f++) {
823 			if (pps[d][f] == NULL)
824 				continue;
825 			din = did_dinode(pps[d][f]);
826 
827 			/*
828 			 * Try to enumerate as many devices and functions as
829 			 * possible.  If we fail to declare a device, break
830 			 * out of the function loop.
831 			 */
832 			declare_dev_and_fn(mod, bn,
833 			    &dn, din, board, bridge, rc, d, f, depth);
834 			did_rele(pps[d][f]);
835 
836 			if (dn == NULL)
837 				break;
838 		}
839 		dn = NULL;
840 	}
841 	return (0);
842 }
843 
844 static int
845 pciexbus_enum(topo_mod_t *mp, tnode_t *ptn, char *pnm, topo_instance_t min,
846     topo_instance_t max)
847 {
848 	di_node_t pdn;
849 	int rc, hb;
850 	tnode_t *hbtn;
851 	int retval;
852 
853 	/*
854 	 * PCI-Express; parent node's private data is a simple di_node_t
855 	 * and we have to construct our own did hash and did_t.
856 	 */
857 	rc = topo_node_instance(ptn);
858 	if ((hbtn = topo_node_parent(ptn)) != NULL)
859 		hb = topo_node_instance(hbtn);
860 	else
861 		hb = rc;
862 
863 	if ((pdn = topo_node_getspecific(ptn)) == DI_NODE_NIL) {
864 		topo_mod_dprintf(mp,
865 		    "Parent %s node missing private data.\n"
866 		    "Unable to proceed with %s enumeration.\n", pnm, PCIEX_BUS);
867 		return (0);
868 	}
869 	if (did_hash_init(mp) != 0)
870 		return (-1);
871 	if ((did_create(mp, pdn, 0, hb, rc, TRUST_BDF)) == NULL)
872 		return (-1);	/* errno already set */
873 
874 	retval = pci_children_instantiate(mp, ptn, pdn, 0, hb, rc,
875 	    (min == max) ? min : TRUST_BDF, 0);
876 	did_hash_fini(mp);
877 
878 	return (retval);
879 }
880 
881 static int
882 pcibus_enum(topo_mod_t *mp, tnode_t *ptn, char *pnm, topo_instance_t min,
883     topo_instance_t max, void *data)
884 {
885 	did_t *didp, *hbdid = (did_t *)data;
886 	int retval;
887 
888 	/*
889 	 * XXTOPO: we should not be sharing private node data with another
890 	 * module. PCI Bus; Parent node's private data is a did_t.  We'll
891 	 * use the did hash established by the parent.
892 	 */
893 	did_setspecific(mp, data);
894 
895 	/*
896 	 * If we're looking for a specific bus-instance, find the right
897 	 * did_t in the chain, otherwise, there should be only one did_t.
898 	 */
899 	if (min == max) {
900 		int b;
901 		didp = hbdid;
902 		while (didp != NULL) {
903 			did_BDF(didp, &b, NULL, NULL);
904 			if (b == min)
905 				break;
906 			didp = did_link_get(didp);
907 		}
908 		if (didp == NULL) {
909 			topo_mod_dprintf(mp,
910 			    "Parent %s node missing private data related\n"
911 			    "to %s instance %d.\n", pnm, PCI_BUS, min);
912 			topo_mod_setspecific(mp, NULL);
913 			return (0);
914 		}
915 	} else {
916 		assert(did_link_get(hbdid) == NULL);
917 		didp = hbdid;
918 	}
919 	retval = pci_children_instantiate(mp, ptn, did_dinode(didp),
920 	    did_board(didp), did_bridge(didp), did_rc(didp),
921 	    (min == max) ? min : TRUST_BDF, 0);
922 
923 	topo_mod_setspecific(mp, NULL);
924 
925 	return (retval);
926 }
927 
928 /*ARGSUSED*/
929 static int
930 pci_enum(topo_mod_t *mod, tnode_t *ptn, const char *name,
931     topo_instance_t min, topo_instance_t max, void *notused, void *data)
932 {
933 	int retval;
934 	char *pname;
935 
936 	topo_mod_dprintf(mod, "Enumerating pci!\n");
937 
938 	if (strcmp(name, PCI_BUS) != 0 && strcmp(name, PCIEX_BUS) != 0) {
939 		topo_mod_dprintf(mod,
940 		    "Currently only know how to enumerate %s or %s.\n",
941 		    PCI_BUS, PCIEX_BUS);
942 		return (0);
943 	}
944 	pname = topo_node_name(ptn);
945 	if (strcmp(pname, HOSTBRIDGE) != 0 && strcmp(pname, PCIEX_ROOT) != 0) {
946 		topo_mod_dprintf(mod,
947 		    "Currently can only enumerate a %s or %s directly\n",
948 		    PCI_BUS, PCIEX_BUS);
949 		topo_mod_dprintf(mod,
950 		    "descended from a %s or %s node.\n",
951 		    HOSTBRIDGE, PCIEX_ROOT);
952 		return (0);
953 	}
954 
955 	if (strcmp(name, PCI_BUS) == 0) {
956 		retval = pcibus_enum(mod, ptn, pname, min, max, data);
957 	} else if (strcmp(name, PCIEX_BUS) == 0) {
958 		retval = pciexbus_enum(mod, ptn, pname, min, max);
959 	} else {
960 		topo_mod_dprintf(mod,
961 		    "Currently only know how to enumerate %s or %s not %s.\n",
962 		    PCI_BUS, PCIEX_BUS, name);
963 		return (0);
964 	}
965 
966 	return (retval);
967 }
968 
969 /*ARGSUSED*/
970 static void
971 pci_release(topo_mod_t *mp, tnode_t *node)
972 {
973 	topo_method_unregister_all(mp, node);
974 
975 	/*
976 	 * node private data (did_t) for this node is destroyed in
977 	 * did_hash_destroy()
978 	 */
979 
980 	topo_node_unbind(node);
981 }
982