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.
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.
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]
23 * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright (c) 2017, Joyent, Inc.
27 #include <sys/fm/protocol.h>
34 #include <sys/param.h>
37 #include <libdevinfo.h>
38 #include <libnvpair.h>
39 #include <fm/topo_mod.h>
40 #include <fm/topo_hc.h>
42 #include <hostbridge.h>
45 #include <did_props.h>
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
;
56 extern int platform_pci_label(topo_mod_t
*mod
, tnode_t
*, nvlist_t
*,
58 extern int platform_pci_fru(topo_mod_t
*mod
, tnode_t
*, 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
*,
65 static int pci_fru(topo_mod_t
*, tnode_t
*, topo_version_t
, nvlist_t
*,
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
};
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
},
82 _topo_init(topo_mod_t
*modhdl
, topo_version_t version
)
85 * Turn on module debugging output
87 if (getenv("TOPOPCIDBG") != NULL
)
88 topo_mod_setdebug(modhdl
);
89 topo_mod_dprintf(modhdl
, "initializing pcibus builtin\n");
91 if (version
!= PCI_ENUMR_VERS
)
92 return (topo_mod_seterrno(modhdl
, EMOD_VER_NEW
));
94 if (topo_mod_register(modhdl
, &Pci_info
, TOPO_VERSION
) != 0) {
95 topo_mod_dprintf(modhdl
, "failed to register module");
98 topo_mod_dprintf(modhdl
, "PCI Enumr initd\n");
104 _topo_fini(topo_mod_t
*modhdl
)
106 topo_mod_unregister(modhdl
);
110 pci_label(topo_mod_t
*mp
, tnode_t
*node
, topo_version_t version
,
111 nvlist_t
*in
, nvlist_t
**out
)
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
));
118 pci_fru(topo_mod_t
*mp
, tnode_t
*node
, topo_version_t version
,
119 nvlist_t
*in
, nvlist_t
**out
)
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
));
126 pci_tnode_create(topo_mod_t
*mod
, tnode_t
*parent
,
127 const char *name
, topo_instance_t i
, void *priv
)
131 if ((ntn
= tnode_create(mod
, parent
, name
, i
, priv
)) == 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
);
144 hostbridge_asdevice(topo_mod_t
*mod
, tnode_t
*bus
)
149 di
= topo_node_getspecific(bus
);
150 assert(di
!= DI_NODE_NIL
);
152 if ((dev32
= pcidev_declare(mod
, bus
, di
, 32)) == NULL
)
154 if (pcifn_declare(mod
, dev32
, di
, 0) == NULL
) {
155 topo_node_unbind(dev32
);
162 pciexfn_declare(topo_mod_t
*mod
, tnode_t
*parent
, di_node_t dn
,
168 uint_t
class, subclass
;
169 char *devtyp
, *pdevtyp
;
170 int pcie_devtyp
, pexcap
;
171 boolean_t dev_is_pcie
, pdev_is_pcie
;
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 */
177 ptn
= find_predecessor(parent
, PCIEX_ROOT
);
180 pdn
= topo_node_getspecific(ptn
);
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
);
188 dev_is_pcie
= devtyp
&& (strcmp(devtyp
, "pciex") == 0);
189 pdev_is_pcie
= pdevtyp
&& (strcmp(pdevtyp
, "pciex") == 0);
192 * Populate the excap with correct PCIe device type.
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
205 pcie_devtyp
= PCIE_PCIECAP_DEV_TYPE_PCI_DEV
;
206 if (class == PCI_CLASS_BRIDGE
&& subclass
== PCI_BRIDGE_PCI
) {
209 if (pexcap
!= PCIE_PCIECAP_DEV_TYPE_UP
)
210 pcie_devtyp
= PCIE_PCIECAP_DEV_TYPE_UP
;
213 PCIE_PCIECAP_DEV_TYPE_DOWN
;
215 pcie_devtyp
= PCIE_PCIECAP_DEV_TYPE_PCIE2PCI
;
219 pcie_devtyp
= PCIE_PCIECAP_DEV_TYPE_PCI2PCIE
;
223 pcie_devtyp
= PCIE_PCIECAP_DEV_TYPE_PCIE_DEV
;
226 if ((pd
= did_find(mod
, dn
)) == NULL
)
228 did_excap_set(pd
, pcie_devtyp
);
230 if ((ntn
= pci_tnode_create(mod
, parent
, PCIEX_FUNCTION
, i
, dn
))
233 if (did_props_set(ntn
, pd
, Fn_common_props
, Fn_propcnt
) < 0) {
234 topo_node_unbind(ntn
);
238 * We may find pci-express buses or plain-pci buses beneath a function
240 if (child_range_add(mod
, ntn
, PCIEX_BUS
, 0, MAX_HB_BUSES
) < 0) {
241 topo_node_unbind(ntn
);
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
);
253 pciexdev_declare(topo_mod_t
*mod
, tnode_t
*parent
, di_node_t dn
,
259 if ((pd
= did_find(mod
, dn
)) == NULL
)
261 did_settnode(pd
, parent
);
263 if ((ntn
= pci_tnode_create(mod
, parent
, PCIEX_DEVICE
, i
, dn
)) == NULL
)
265 if (did_props_set(ntn
, pd
, Dev_common_props
, Dev_propcnt
) < 0) {
266 topo_node_unbind(ntn
);
271 * We can expect to find pci-express functions beneath the device
273 if (child_range_add(mod
,
274 ntn
, PCIEX_FUNCTION
, 0, MAX_PCIDEV_FNS
) < 0) {
275 topo_node_unbind(ntn
);
282 pciexbus_declare(topo_mod_t
*mod
, tnode_t
*parent
, di_node_t dn
,
288 if ((pd
= did_find(mod
, dn
)) == NULL
)
290 did_settnode(pd
, parent
);
291 if ((ntn
= pci_tnode_create(mod
, parent
, PCIEX_BUS
, i
, dn
)) == NULL
)
293 if (did_props_set(ntn
, pd
, Bus_common_props
, Bus_propcnt
) < 0) {
294 topo_node_unbind(ntn
);
298 * We can expect to find pci-express devices beneath the bus
300 if (child_range_add(mod
,
301 ntn
, PCIEX_DEVICE
, 0, MAX_PCIBUS_DEVS
) < 0) {
302 topo_node_unbind(ntn
);
309 pcifn_declare(topo_mod_t
*mod
, tnode_t
*parent
, di_node_t dn
,
315 if ((pd
= did_find(mod
, dn
)) == NULL
)
317 did_excap_set(pd
, PCIE_PCIECAP_DEV_TYPE_PCI_DEV
);
319 if ((ntn
= pci_tnode_create(mod
, parent
, PCI_FUNCTION
, i
, dn
)) == NULL
)
321 if (did_props_set(ntn
, pd
, Fn_common_props
, Fn_propcnt
) < 0) {
322 topo_node_unbind(ntn
);
326 * We may find pci buses beneath a function
328 if (child_range_add(mod
, ntn
, PCI_BUS
, 0, MAX_HB_BUSES
) < 0) {
329 topo_node_unbind(ntn
);
336 pcidev_declare(topo_mod_t
*mod
, tnode_t
*parent
, di_node_t dn
,
342 if ((pd
= did_find(mod
, dn
)) == NULL
)
344 /* remember parent tnode */
345 did_settnode(pd
, parent
);
347 if ((ntn
= pci_tnode_create(mod
, parent
, PCI_DEVICE
, i
, dn
)) == NULL
)
349 if (did_props_set(ntn
, pd
, Dev_common_props
, Dev_propcnt
) < 0) {
350 topo_node_unbind(ntn
);
355 * We can expect to find pci functions beneath the device
357 if (child_range_add(mod
, ntn
, PCI_FUNCTION
, 0, MAX_PCIDEV_FNS
) < 0) {
358 topo_node_unbind(ntn
);
365 pcibus_declare(topo_mod_t
*mod
, tnode_t
*parent
, di_node_t dn
,
372 if ((pd
= did_find(mod
, dn
)) == NULL
)
374 did_settnode(pd
, parent
);
375 if ((ntn
= pci_tnode_create(mod
, parent
, PCI_BUS
, i
, dn
)) == NULL
)
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.
383 if (strcmp(topo_node_name(parent
), HOSTBRIDGE
) == 0)
385 if (did_props_set(ntn
, pd
, Bus_common_props
, Bus_propcnt
) < 0) {
386 topo_node_unbind(ntn
);
390 * We can expect to find pci devices beneath the bus
392 if (child_range_add(mod
, ntn
, PCI_DEVICE
, 0, MAX_PCIBUS_DEVS
) < 0) {
393 topo_node_unbind(ntn
);
397 * On each bus child of the hostbridge, we represent the
398 * hostbridge as a device outside the range of legal device
402 if (hostbridge_asdevice(mod
, ntn
) < 0) {
403 topo_node_range_destroy(ntn
, PCI_DEVICE
);
404 topo_node_unbind(ntn
);
412 pci_bridge_declare(topo_mod_t
*mod
, tnode_t
*fn
, di_node_t din
, int board
,
413 int bridge
, int rc
, int depth
)
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);
424 err
= pci_children_instantiate(mod
, fn
, din
, board
, bridge
,
425 rc
- TO_PCI
, TRUST_BDF
, depth
+ 1);
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
)
436 uint_t
class, subclass
;
442 *dev
= pciexdev_declare(mod
, bus
, din
, devno
);
444 *dev
= pcidev_declare(mod
, bus
, din
, devno
);
450 fn
= pciexfn_declare(mod
, *dev
, din
, fnno
);
452 fn
= pcifn_declare(mod
, *dev
, din
, fnno
);
456 topo_node_unbind(*dev
);
462 if (pci_classcode_get(mod
, din
, &class, &subclass
) < 0) {
463 topo_node_unbind(fn
);
465 topo_node_unbind(*dev
);
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
474 if (class == PCI_CLASS_BRIDGE
&& subclass
== PCI_BRIDGE_PCI
) {
475 (void) pci_bridge_declare(mod
, fn
, din
, board
, bridge
, rc
,
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)
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.
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.
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
) {
497 * Is this an adapter card? Check the bus's physlot
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
);
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
,
513 if (topo_node_range_create(mod
, fn
,
515 topo_mod_dprintf(mod
,
516 "child_range_add for "
519 topo_mod_errno(mod
)));
522 (void) topo_mod_enumerate(mod
, fn
,
523 XAUI
, XAUI
, fnno
, fnno
, fn
);
526 } else if (class == PCI_CLASS_NET
) {
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.
532 if (topo_mod_load(mod
, NIC
, NIC_VERSION
) == NULL
) {
533 topo_mod_dprintf(mod
, "pcibus enum could not load "
535 (void) topo_mod_seterrno(mod
, EMOD_PARTIAL_ENUM
);
539 (void) topo_mod_enumerate(mod
, fn
, NIC
, NIC
, 0, 0, din
);
540 } else if (class == PCI_CLASS_MASS
) {
543 extern void pci_iports_instantiate(topo_mod_t
*, tnode_t
*,
545 extern void pci_receptacle_instantiate(topo_mod_t
*, tnode_t
*,
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)
554 pci_iports_instantiate(mod
, fn
, din
, niports
);
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,
560 pci_receptacle_instantiate(mod
, fn
, din
);
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
)
569 did_t
*pps
[MAX_PCIBUS_DEVS
][MAX_PCIDEV_FNS
];
579 for (d
= 0; d
< MAX_PCIBUS_DEVS
; d
++)
580 for (f
= 0; f
< MAX_PCIDEV_FNS
; f
++)
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
);
589 did_BDF(np
, &b
, &d
, &f
);
594 pb
= ((bover
== TRUST_BDF
) ? b
: bover
);
595 sib
= di_sibling_node(sib
);
597 if (pb
< 0 && bover
< 0)
600 bn
= pciexbus_declare(mod
, parent
, pn
, ((pb
< 0) ? bover
: pb
));
602 bn
= pcibus_declare(mod
, parent
, pn
, ((pb
< 0) ? bover
: pb
));
608 for (d
= 0; d
< MAX_PCIBUS_DEVS
; d
++) {
609 for (f
= 0; f
< MAX_PCIDEV_FNS
; f
++) {
610 if (pps
[d
][f
] == NULL
)
612 din
= did_dinode(pps
[d
][f
]);
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.
619 declare_dev_and_fn(mod
, bn
,
620 &dn
, din
, board
, bridge
, rc
, d
, f
, depth
);
632 pciexbus_enum(topo_mod_t
*mp
, tnode_t
*ptn
, char *pnm
, topo_instance_t min
,
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.
644 rc
= topo_node_instance(ptn
);
645 if ((hbtn
= topo_node_parent(ptn
)) != NULL
)
646 hb
= topo_node_instance(hbtn
);
650 if ((pdn
= topo_node_getspecific(ptn
)) == DI_NODE_NIL
) {
652 "Parent %s node missing private data.\n"
653 "Unable to proceed with %s enumeration.\n", pnm
, PCIEX_BUS
);
656 if (did_hash_init(mp
) != 0)
658 if ((did_create(mp
, pdn
, 0, hb
, rc
, TRUST_BDF
)) == NULL
)
659 return (-1); /* errno already set */
661 retval
= pci_children_instantiate(mp
, ptn
, pdn
, 0, hb
, rc
,
662 (min
== max
) ? min
: TRUST_BDF
, 0);
669 pcibus_enum(topo_mod_t
*mp
, tnode_t
*ptn
, char *pnm
, topo_instance_t min
,
670 topo_instance_t max
, void *data
)
672 did_t
*didp
, *hbdid
= (did_t
*)data
;
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.
680 did_setspecific(mp
, data
);
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.
689 while (didp
!= NULL
) {
690 did_BDF(didp
, &b
, NULL
, NULL
);
693 didp
= did_link_get(didp
);
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
);
703 assert(did_link_get(hbdid
) == NULL
);
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);
710 topo_mod_setspecific(mp
, NULL
);
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
)
723 topo_mod_dprintf(mod
, "Enumerating pci!\n");
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",
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",
736 topo_mod_dprintf(mod
,
737 "descended from a %s or %s node.\n",
738 HOSTBRIDGE
, PCIEX_ROOT
);
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
);
747 topo_mod_dprintf(mod
,
748 "Currently only know how to enumerate %s or %s not %s.\n",
749 PCI_BUS
, PCIEX_BUS
, name
);
758 pci_release(topo_mod_t
*mp
, tnode_t
*node
)
760 topo_method_unregister_all(mp
, node
);
763 * node private data (did_t) for this node is destroyed in
767 topo_node_unbind(node
);