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
_topo_init(topo_mod_t * modhdl,topo_version_t version)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
_topo_fini(topo_mod_t * modhdl)104 _topo_fini(topo_mod_t *modhdl)
105 {
106 topo_mod_unregister(modhdl);
107 }
108
109 static int
pci_label(topo_mod_t * mp,tnode_t * node,topo_version_t version,nvlist_t * in,nvlist_t ** out)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
pci_fru(topo_mod_t * mp,tnode_t * node,topo_version_t version,nvlist_t * in,nvlist_t ** out)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 *
pci_tnode_create(topo_mod_t * mod,tnode_t * parent,const char * name,topo_instance_t i,void * priv)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
hostbridge_asdevice(topo_mod_t * mod,tnode_t * bus)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 *
pciexfn_declare(topo_mod_t * mod,tnode_t * parent,di_node_t dn,topo_instance_t i)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 *
pciexdev_declare(topo_mod_t * mod,tnode_t * parent,di_node_t dn,topo_instance_t i)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 *
pciexbus_declare(topo_mod_t * mod,tnode_t * parent,di_node_t dn,topo_instance_t i)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 *
pcifn_declare(topo_mod_t * mod,tnode_t * parent,di_node_t dn,topo_instance_t i)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 *
pcidev_declare(topo_mod_t * mod,tnode_t * parent,di_node_t dn,topo_instance_t i)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 *
pcibus_declare(topo_mod_t * mod,tnode_t * parent,di_node_t dn,topo_instance_t i)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
pci_bridge_declare(topo_mod_t * mod,tnode_t * fn,di_node_t din,int board,int bridge,int rc,int depth)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
declare_dev_and_fn(topo_mod_t * mod,tnode_t * bus,tnode_t ** dev,di_node_t din,int board,int bridge,int rc,int devno,int fnno,int depth)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
pci_children_instantiate(topo_mod_t * mod,tnode_t * parent,di_node_t pn,int board,int bridge,int rc,int bover,int depth)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
pciexbus_enum(topo_mod_t * mp,tnode_t * ptn,char * pnm,topo_instance_t min,topo_instance_t max)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
pcibus_enum(topo_mod_t * mp,tnode_t * ptn,char * pnm,topo_instance_t min,topo_instance_t max,void * data)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
pci_enum(topo_mod_t * mod,tnode_t * ptn,const char * name,topo_instance_t min,topo_instance_t max,void * notused,void * data)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
pci_release(topo_mod_t * mp,tnode_t * node)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