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