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 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
28 #include <fm/topo_mod.h>
29 #include <fm/topo_hc.h>
30 #include <libdevinfo.h>
32 #include <sys/fm/protocol.h>
33 #include <sys/param.h>
34 #include <sys/systeminfo.h>
37 #include <hostbridge.h>
40 #include <did_props.h>
45 * Generic code shared by all the hostbridge enumerators
47 static void hb_release(topo_mod_t
*, tnode_t
*);
48 static int hb_label(topo_mod_t
*, tnode_t
*, topo_version_t
, nvlist_t
*,
50 static int hb_enum(topo_mod_t
*, tnode_t
*, const char *, topo_instance_t
,
51 topo_instance_t
, void *, void *);
53 extern int platform_hb_label(topo_mod_t
*, tnode_t
*, nvlist_t
*, nvlist_t
**);
54 extern int platform_hb_enum(topo_mod_t
*, tnode_t
*,
55 const char *, topo_instance_t
, topo_instance_t
);
57 extern txprop_t ExHB_common_props
[];
58 extern txprop_t HB_common_props
[];
59 extern txprop_t RC_common_props
[];
60 extern int ExHB_propcnt
;
61 extern int HB_propcnt
;
62 extern int RC_propcnt
;
64 static int specific_hb_enum(topo_mod_t
*, tnode_t
*, const char *,
65 topo_instance_t
, topo_instance_t
, void *);
67 static const topo_modops_t Hb_ops
=
68 { hb_enum
, hb_release
};
69 static const topo_modinfo_t Hb_info
=
70 { HOSTBRIDGE
, FM_FMRI_SCHEME_HC
, HB_ENUMR_VERS
, &Hb_ops
};
72 static const topo_method_t Hb_methods
[] = {
73 { TOPO_METH_LABEL
, TOPO_METH_LABEL_DESC
,
74 TOPO_METH_LABEL_VERSION
, TOPO_STABILITY_INTERNAL
, hb_label
},
78 static const topo_pgroup_info_t hb_auth_pgroup
= {
80 TOPO_STABILITY_PRIVATE
,
81 TOPO_STABILITY_PRIVATE
,
86 _topo_init(topo_mod_t
*modhdl
, topo_version_t version
)
89 * Turn on module debugging output
91 if (getenv("TOPOHBDBG") != NULL
)
92 topo_mod_setdebug(modhdl
);
93 topo_mod_dprintf(modhdl
, "initializing hostbridge enumerator\n");
95 if (version
!= HB_ENUMR_VERS
)
96 return (topo_mod_seterrno(modhdl
, EMOD_VER_NEW
));
98 if (topo_mod_register(modhdl
, &Hb_info
, TOPO_VERSION
) < 0) {
99 topo_mod_dprintf(modhdl
, "hostbridge registration failed: %s\n",
100 topo_mod_errmsg(modhdl
));
101 return (-1); /* mod errno already set */
104 topo_mod_dprintf(modhdl
, "Hostbridge enumr initd\n");
110 _topo_fini(topo_mod_t
*modhdl
)
112 topo_mod_unregister(modhdl
);
116 hb_label(topo_mod_t
*mp
, tnode_t
*node
, topo_version_t version
,
117 nvlist_t
*in
, nvlist_t
**out
)
119 if (version
> TOPO_METH_LABEL_VERSION
)
120 return (topo_mod_seterrno(mp
, EMOD_VER_NEW
));
121 return (platform_hb_label(mp
, node
, in
, out
));
125 pci_enumr_load(topo_mod_t
*mp
)
127 topo_mod_t
*rp
= NULL
;
129 if ((rp
= topo_mod_load(mp
, PCI_ENUM
, PCI_ENUMR_VERS
)) == NULL
) {
131 "%s enumerator could not load %s.\n", HOSTBRIDGE
, PCI_ENUM
);
138 hb_enum(topo_mod_t
*mp
, tnode_t
*pn
, const char *name
, topo_instance_t imin
,
139 topo_instance_t imax
, void *notused
, void *data
)
144 if (strcmp(name
, HOSTBRIDGE
) != 0) {
146 "Currently only know how to enumerate %s components.\n",
151 * Load the pcibus enumerator
153 if ((pcimod
= pci_enumr_load(mp
)) == NULL
)
157 * If we're asked to enumerate a whole range of hostbridges, then
158 * we need to find them all. If we're just asked to enumerate a
159 * single hostbridge, we expect our caller to have passed us linked
160 * did_t structures we can use to enumerate the singled out hostbridge.
164 if (did_hash_init(mp
) < 0) {
166 "Hash initialization for hostbridge "
167 "enumerator failed.\n");
168 topo_mod_unload(pcimod
);
171 rv
= platform_hb_enum(mp
, pn
, name
, imin
, imax
);
174 rv
= specific_hb_enum(mp
, pn
, name
, imin
, imax
, data
);
182 hb_release(topo_mod_t
*mp
, tnode_t
*node
)
184 topo_method_unregister_all(mp
, node
);
188 hb_tnode_create(topo_mod_t
*mod
, tnode_t
*parent
,
189 const char *name
, topo_instance_t i
, void *priv
)
194 nvlist_t
*auth
= topo_mod_auth(mod
, parent
);
196 fmri
= topo_mod_hcfmri(mod
, parent
, FM_HC_SCHEME_VERSION
, name
, i
,
197 NULL
, auth
, NULL
, NULL
, NULL
);
200 topo_mod_dprintf(mod
,
201 "Unable to make nvlist for %s bind: %s.\n",
202 name
, topo_mod_errmsg(mod
));
206 ntn
= topo_node_bind(mod
, parent
, name
, i
, fmri
);
208 topo_mod_dprintf(mod
,
209 "topo_node_bind (%s%d/%s%d) failed: %s\n",
210 topo_node_name(parent
), topo_node_instance(parent
),
212 topo_strerror(topo_mod_errno(mod
)));
217 topo_node_setspecific(ntn
, priv
);
219 if (topo_pgroup_create(ntn
, &hb_auth_pgroup
, &err
) == 0) {
220 (void) topo_prop_inherit(ntn
, FM_FMRI_AUTHORITY
,
221 FM_FMRI_AUTH_PRODUCT
, &err
);
222 (void) topo_prop_inherit(ntn
, FM_FMRI_AUTHORITY
,
223 FM_FMRI_AUTH_PRODUCT_SN
, &err
);
224 (void) topo_prop_inherit(ntn
, FM_FMRI_AUTHORITY
,
225 FM_FMRI_AUTH_CHASSIS
, &err
);
226 (void) topo_prop_inherit(ntn
, FM_FMRI_AUTHORITY
,
227 FM_FMRI_AUTH_SERVER
, &err
);
230 if (topo_method_register(mod
, ntn
, Hb_methods
) < 0) {
231 topo_mod_dprintf(mod
, "topo_method_register failed: %s\n",
232 topo_strerror(topo_mod_errno(mod
)));
233 topo_node_unbind(ntn
);
240 pcihostbridge_declare(topo_mod_t
*mod
, tnode_t
*parent
, di_node_t din
,
246 if ((pd
= did_find(mod
, din
)) == NULL
)
248 if ((ntn
= hb_tnode_create(mod
, parent
, HOSTBRIDGE
, i
, din
)) == NULL
)
250 if (did_props_set(ntn
, pd
, HB_common_props
, HB_propcnt
) < 0) {
251 topo_node_unbind(ntn
);
255 * We expect to find pci buses beneath the hostbridge.
257 if (child_range_add(mod
, ntn
, PCI_BUS
, 0, MAX_HB_BUSES
) < 0) {
258 topo_node_unbind(ntn
);
265 pciexhostbridge_declare(topo_mod_t
*mod
, tnode_t
*parent
, di_node_t din
,
271 if ((pd
= did_find(mod
, din
)) == NULL
)
273 if ((ntn
= hb_tnode_create(mod
, parent
, HOSTBRIDGE
, hi
, din
)) == NULL
)
275 if (did_props_set(ntn
, pd
, ExHB_common_props
, ExHB_propcnt
) < 0) {
276 topo_node_unbind(ntn
);
280 * We expect to find root complexes beneath the hostbridge.
282 if (child_range_add(mod
, ntn
, PCIEX_ROOT
, 0, MAX_HB_BUSES
) < 0) {
283 topo_node_unbind(ntn
);
290 pciexrc_declare(topo_mod_t
*mod
, tnode_t
*parent
, di_node_t din
,
296 if ((pd
= did_find(mod
, din
)) == NULL
)
299 if ((ntn
= hb_tnode_create(mod
, parent
, PCIEX_ROOT
, ri
, din
)) == NULL
)
301 if (did_props_set(ntn
, pd
, RC_common_props
, RC_propcnt
) < 0) {
302 topo_node_unbind(ntn
);
306 * We expect to find pci-express buses beneath a root complex
308 if (child_range_add(mod
, ntn
, PCIEX_BUS
, 0, MAX_HB_BUSES
) < 0) {
309 topo_node_range_destroy(ntn
, PCIEX_BUS
);
317 specific_hb_enum(topo_mod_t
*mod
, tnode_t
*pn
, const char *name
,
318 topo_instance_t imin
, topo_instance_t imax
, void *priv
)
321 did_t
*iodid
= (did_t
*)priv
;
326 did_setspecific(mod
, priv
);
329 * Find the hostbridge of interest
332 for (brc
= 0; brc
< imin
; brc
++)
333 didp
= did_chain_get(didp
);
334 assert(didp
!= NULL
);
336 if ((hb
= pcihostbridge_declare(mod
, pn
, did_dinode(didp
), imin
))
340 while (didp
!= NULL
) {
341 did_BDF(didp
, &bus
, NULL
, NULL
);
342 if (topo_mod_enumerate(mod
,
343 hb
, PCI_BUS
, PCI_BUS
, bus
, bus
, didp
) != 0) {
344 return (topo_mod_seterrno(mod
, EMOD_PARTIAL_ENUM
));
346 didp
= did_link_get(didp
);