xref: /onnv-gate/usr/src/lib/fm/topo/modules/common/hostbridge/hostbridge.c (revision 10462:ec0e4f3134ef)
13062Scindi /*
23062Scindi  * CDDL HEADER START
33062Scindi  *
43062Scindi  * The contents of this file are subject to the terms of the
53062Scindi  * Common Development and Distribution License (the "License").
63062Scindi  * You may not use this file except in compliance with the License.
73062Scindi  *
83062Scindi  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
93062Scindi  * or http://www.opensolaris.org/os/licensing.
103062Scindi  * See the License for the specific language governing permissions
113062Scindi  * and limitations under the License.
123062Scindi  *
133062Scindi  * When distributing Covered Code, include this CDDL HEADER in each
143062Scindi  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
153062Scindi  * If applicable, add the following below this CDDL HEADER, with the
163062Scindi  * fields enclosed by brackets "[]" replaced with your own identifying
173062Scindi  * information: Portions Copyright [yyyy] [name of copyright owner]
183062Scindi  *
193062Scindi  * CDDL HEADER END
203062Scindi  */
213062Scindi 
223062Scindi /*
23*10462SSean.Ye@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
243062Scindi  * Use is subject to license terms.
253062Scindi  */
263062Scindi 
273062Scindi #include <string.h>
283062Scindi #include <fm/topo_mod.h>
293062Scindi #include <fm/topo_hc.h>
303062Scindi #include <libdevinfo.h>
313062Scindi #include <limits.h>
323062Scindi #include <sys/fm/protocol.h>
333062Scindi #include <sys/param.h>
343062Scindi #include <sys/systeminfo.h>
353062Scindi #include <assert.h>
363062Scindi 
373062Scindi #include <hostbridge.h>
383062Scindi #include <pcibus.h>
393062Scindi #include <did.h>
403062Scindi #include <did_props.h>
413062Scindi #include <util.h>
423062Scindi 
433062Scindi /*
443062Scindi  * hostbridge.c
453062Scindi  *	Generic code shared by all the hostbridge enumerators
463062Scindi  */
473062Scindi static void hb_release(topo_mod_t *, tnode_t *);
483062Scindi static int hb_label(topo_mod_t *, tnode_t *, topo_version_t, nvlist_t *,
493062Scindi     nvlist_t **);
503062Scindi static int hb_enum(topo_mod_t *, tnode_t *, const char *, topo_instance_t,
513062Scindi     topo_instance_t, void *, void *);
523062Scindi 
533062Scindi extern int platform_hb_label(topo_mod_t *, tnode_t *, nvlist_t *, nvlist_t **);
543062Scindi extern int platform_hb_enum(topo_mod_t *, tnode_t *,
553062Scindi     const char *, topo_instance_t, topo_instance_t);
563062Scindi 
573062Scindi extern txprop_t ExHB_common_props[];
583062Scindi extern txprop_t HB_common_props[];
593062Scindi extern txprop_t RC_common_props[];
603062Scindi extern int ExHB_propcnt;
613062Scindi extern int HB_propcnt;
623062Scindi extern int RC_propcnt;
633062Scindi 
643062Scindi static int specific_hb_enum(topo_mod_t *, tnode_t *, const char *,
653062Scindi     topo_instance_t, topo_instance_t, void *);
663062Scindi 
673062Scindi static const topo_modops_t Hb_ops =
683062Scindi 	{ hb_enum, hb_release };
693062Scindi static const topo_modinfo_t Hb_info =
703062Scindi 	{ HOSTBRIDGE, FM_FMRI_SCHEME_HC, HB_ENUMR_VERS, &Hb_ops };
713062Scindi 
723062Scindi static const topo_method_t Hb_methods[] = {
733062Scindi 	{ TOPO_METH_LABEL, TOPO_METH_LABEL_DESC,
743062Scindi 	    TOPO_METH_LABEL_VERSION, TOPO_STABILITY_INTERNAL, hb_label },
753062Scindi 	{ NULL }
763062Scindi };
773062Scindi 
783062Scindi static const topo_pgroup_info_t hb_auth_pgroup = {
793062Scindi 	FM_FMRI_AUTHORITY,
803062Scindi 	TOPO_STABILITY_PRIVATE,
813062Scindi 	TOPO_STABILITY_PRIVATE,
823062Scindi 	1
833062Scindi };
843062Scindi 
853062Scindi int
_topo_init(topo_mod_t * modhdl,topo_version_t version)863062Scindi _topo_init(topo_mod_t *modhdl, topo_version_t version)
873062Scindi {
883062Scindi 	/*
893062Scindi 	 * Turn on module debugging output
903062Scindi 	 */
913062Scindi 	if (getenv("TOPOHBDBG") != NULL)
923062Scindi 		topo_mod_setdebug(modhdl);
933062Scindi 	topo_mod_dprintf(modhdl, "initializing hostbridge enumerator\n");
943062Scindi 
953062Scindi 	if (version != HB_ENUMR_VERS)
963062Scindi 		return (topo_mod_seterrno(modhdl, EMOD_VER_NEW));
973062Scindi 
983062Scindi 	if (topo_mod_register(modhdl, &Hb_info, TOPO_VERSION) < 0) {
993062Scindi 		topo_mod_dprintf(modhdl, "hostbridge registration failed: %s\n",
1003062Scindi 		    topo_mod_errmsg(modhdl));
1013062Scindi 		return (-1); /* mod errno already set */
1023062Scindi 	}
1033062Scindi 
1043062Scindi 	topo_mod_dprintf(modhdl, "Hostbridge enumr initd\n");
1053062Scindi 
1063062Scindi 	return (0);
1073062Scindi }
1083062Scindi 
1093062Scindi void
_topo_fini(topo_mod_t * modhdl)1103062Scindi _topo_fini(topo_mod_t *modhdl)
1113062Scindi {
1123062Scindi 	topo_mod_unregister(modhdl);
1133062Scindi }
1143062Scindi 
1153062Scindi static int
hb_label(topo_mod_t * mp,tnode_t * node,topo_version_t version,nvlist_t * in,nvlist_t ** out)1163062Scindi hb_label(topo_mod_t *mp, tnode_t *node, topo_version_t version,
1173062Scindi     nvlist_t *in, nvlist_t **out)
1183062Scindi {
1193062Scindi 	if (version > TOPO_METH_LABEL_VERSION)
1203062Scindi 		return (topo_mod_seterrno(mp, EMOD_VER_NEW));
1213062Scindi 	return (platform_hb_label(mp, node, in, out));
1223062Scindi }
1233062Scindi 
1243062Scindi static topo_mod_t *
pci_enumr_load(topo_mod_t * mp)1253062Scindi pci_enumr_load(topo_mod_t *mp)
1263062Scindi {
1273062Scindi 	topo_mod_t *rp = NULL;
1283062Scindi 
1293062Scindi 	if ((rp = topo_mod_load(mp, PCI_ENUM, PCI_ENUMR_VERS)) == NULL) {
1303062Scindi 		topo_mod_dprintf(mp,
1313062Scindi 		    "%s enumerator could not load %s.\n", HOSTBRIDGE, PCI_ENUM);
1323062Scindi 	}
1333062Scindi 	return (rp);
1343062Scindi }
1353062Scindi 
1363062Scindi /*ARGSUSED*/
1373062Scindi static int
hb_enum(topo_mod_t * mp,tnode_t * pn,const char * name,topo_instance_t imin,topo_instance_t imax,void * notused,void * data)1383062Scindi hb_enum(topo_mod_t *mp, tnode_t *pn, const char *name, topo_instance_t imin,
1393062Scindi     topo_instance_t imax, void *notused, void *data)
1403062Scindi {
1414328Scindi 	int rv;
1423062Scindi 	topo_mod_t *pcimod;
1433062Scindi 
1443062Scindi 	if (strcmp(name, HOSTBRIDGE) != 0) {
1453062Scindi 		topo_mod_dprintf(mp,
1463062Scindi 		    "Currently only know how to enumerate %s components.\n",
1473062Scindi 		    HOSTBRIDGE);
1483062Scindi 		return (0);
1493062Scindi 	}
1503062Scindi 	/*
1513062Scindi 	 * Load the pcibus enumerator
1523062Scindi 	 */
1533062Scindi 	if ((pcimod = pci_enumr_load(mp)) == NULL)
1543062Scindi 		return (-1);
1553062Scindi 
1563062Scindi 	/*
1573062Scindi 	 * If we're asked to enumerate a whole range of hostbridges, then
1583062Scindi 	 * we need to find them all.  If we're just asked to enumerate a
1593062Scindi 	 * single hostbridge, we expect our caller to have passed us linked
1603062Scindi 	 * did_t structures we can use to enumerate the singled out hostbridge.
1613062Scindi 	 */
1623062Scindi 	if (imin != imax) {
1633062Scindi 
1643062Scindi 		if (did_hash_init(mp) < 0) {
1653062Scindi 			topo_mod_dprintf(mp,
1663062Scindi 			    "Hash initialization for hostbridge "
1673062Scindi 			    "enumerator failed.\n");
1683062Scindi 			topo_mod_unload(pcimod);
1693062Scindi 			return (-1);
1703062Scindi 		}
1714328Scindi 		rv = platform_hb_enum(mp, pn, name, imin, imax);
1723062Scindi 		did_hash_fini(mp);
1733062Scindi 	} else {
1744328Scindi 		rv = specific_hb_enum(mp, pn, name, imin, imax, data);
1753062Scindi 	}
1764328Scindi 
1774328Scindi 	return (rv);
1783062Scindi }
1793062Scindi 
1803062Scindi /*ARGSUSED*/
1813062Scindi static void
hb_release(topo_mod_t * mp,tnode_t * node)1823062Scindi hb_release(topo_mod_t *mp, tnode_t *node)
1833062Scindi {
1843062Scindi 	topo_method_unregister_all(mp, node);
1853062Scindi }
1863062Scindi 
1873062Scindi static tnode_t *
hb_tnode_create(topo_mod_t * mod,tnode_t * parent,const char * name,topo_instance_t i,void * priv)1883062Scindi hb_tnode_create(topo_mod_t *mod, tnode_t *parent,
1893062Scindi     const char *name, topo_instance_t i, void *priv)
1903062Scindi {
1913062Scindi 	int err;
1923062Scindi 	nvlist_t *fmri;
1933062Scindi 	tnode_t *ntn;
1943062Scindi 	nvlist_t *auth = topo_mod_auth(mod, parent);
1953062Scindi 
1963062Scindi 	fmri = topo_mod_hcfmri(mod, parent, FM_HC_SCHEME_VERSION, name, i,
1973062Scindi 	    NULL, auth, NULL, NULL, NULL);
1983062Scindi 	nvlist_free(auth);
1993062Scindi 	if (fmri == NULL) {
2003062Scindi 		topo_mod_dprintf(mod,
2013062Scindi 		    "Unable to make nvlist for %s bind: %s.\n",
2023062Scindi 		    name, topo_mod_errmsg(mod));
2033062Scindi 		return (NULL);
2043062Scindi 	}
2053062Scindi 
2063062Scindi 	ntn = topo_node_bind(mod, parent, name, i, fmri);
2073062Scindi 	if (ntn == NULL) {
2083062Scindi 		topo_mod_dprintf(mod,
2093062Scindi 		    "topo_node_bind (%s%d/%s%d) failed: %s\n",
2103062Scindi 		    topo_node_name(parent), topo_node_instance(parent),
2113062Scindi 		    name, i,
2123062Scindi 		    topo_strerror(topo_mod_errno(mod)));
2133062Scindi 		nvlist_free(fmri);
2143062Scindi 		return (NULL);
2153062Scindi 	}
2163062Scindi 	nvlist_free(fmri);
2173062Scindi 	topo_node_setspecific(ntn, priv);
2183062Scindi 
2193062Scindi 	if (topo_pgroup_create(ntn, &hb_auth_pgroup, &err) == 0) {
2203062Scindi 		(void) topo_prop_inherit(ntn, FM_FMRI_AUTHORITY,
2213062Scindi 		    FM_FMRI_AUTH_PRODUCT, &err);
2223062Scindi 		(void) topo_prop_inherit(ntn, FM_FMRI_AUTHORITY,
223*10462SSean.Ye@Sun.COM 		    FM_FMRI_AUTH_PRODUCT_SN, &err);
224*10462SSean.Ye@Sun.COM 		(void) topo_prop_inherit(ntn, FM_FMRI_AUTHORITY,
2253062Scindi 		    FM_FMRI_AUTH_CHASSIS, &err);
2263062Scindi 		(void) topo_prop_inherit(ntn, FM_FMRI_AUTHORITY,
2273062Scindi 		    FM_FMRI_AUTH_SERVER, &err);
2283062Scindi 	}
2293062Scindi 
2303062Scindi 	if (topo_method_register(mod, ntn, Hb_methods) < 0) {
2313062Scindi 		topo_mod_dprintf(mod, "topo_method_register failed: %s\n",
2323062Scindi 		    topo_strerror(topo_mod_errno(mod)));
2333062Scindi 		topo_node_unbind(ntn);
2343062Scindi 		return (NULL);
2353062Scindi 	}
2363062Scindi 	return (ntn);
2373062Scindi }
2383062Scindi 
2393062Scindi tnode_t *
pcihostbridge_declare(topo_mod_t * mod,tnode_t * parent,di_node_t din,topo_instance_t i)2403062Scindi pcihostbridge_declare(topo_mod_t *mod, tnode_t *parent, di_node_t din,
2413062Scindi     topo_instance_t i)
2423062Scindi {
2433062Scindi 	did_t *pd;
2443062Scindi 	tnode_t *ntn;
2453062Scindi 
2463062Scindi 	if ((pd = did_find(mod, din)) == NULL)
2473062Scindi 		return (NULL);
2483062Scindi 	if ((ntn = hb_tnode_create(mod, parent, HOSTBRIDGE, i, din)) == NULL)
2493062Scindi 		return (NULL);
2503062Scindi 	if (did_props_set(ntn, pd, HB_common_props, HB_propcnt) < 0) {
2513062Scindi 		topo_node_unbind(ntn);
2523062Scindi 		return (NULL);
2533062Scindi 	}
2543062Scindi 	/*
2553062Scindi 	 * We expect to find pci buses beneath the hostbridge.
2563062Scindi 	 */
2573062Scindi 	if (child_range_add(mod, ntn, PCI_BUS, 0, MAX_HB_BUSES) < 0) {
2583062Scindi 		topo_node_unbind(ntn);
2593062Scindi 		return (NULL);
2603062Scindi 	}
2613062Scindi 	return (ntn);
2623062Scindi }
2633062Scindi 
2643062Scindi tnode_t *
pciexhostbridge_declare(topo_mod_t * mod,tnode_t * parent,di_node_t din,topo_instance_t hi)2653062Scindi pciexhostbridge_declare(topo_mod_t *mod, tnode_t *parent, di_node_t din,
2663062Scindi     topo_instance_t hi)
2673062Scindi {
2683062Scindi 	did_t *pd;
2693062Scindi 	tnode_t *ntn;
2703062Scindi 
2713062Scindi 	if ((pd = did_find(mod, din)) == NULL)
2723062Scindi 		return (NULL);
2733062Scindi 	if ((ntn = hb_tnode_create(mod, parent, HOSTBRIDGE, hi, din)) == NULL)
2743062Scindi 		return (NULL);
2753062Scindi 	if (did_props_set(ntn, pd, ExHB_common_props, ExHB_propcnt) < 0) {
2763062Scindi 		topo_node_unbind(ntn);
2773062Scindi 		return (NULL);
2783062Scindi 	}
2793062Scindi 	/*
2803062Scindi 	 * We expect to find root complexes beneath the hostbridge.
2813062Scindi 	 */
2823062Scindi 	if (child_range_add(mod, ntn, PCIEX_ROOT, 0, MAX_HB_BUSES) < 0) {
2833062Scindi 		topo_node_unbind(ntn);
2843062Scindi 		return (NULL);
2853062Scindi 	}
2863062Scindi 	return (ntn);
2873062Scindi }
2883062Scindi 
2893062Scindi tnode_t *
pciexrc_declare(topo_mod_t * mod,tnode_t * parent,di_node_t din,topo_instance_t ri)2903062Scindi pciexrc_declare(topo_mod_t *mod, tnode_t *parent, di_node_t din,
2913062Scindi     topo_instance_t ri)
2923062Scindi {
2933062Scindi 	did_t *pd;
2943062Scindi 	tnode_t *ntn;
2953062Scindi 
2963062Scindi 	if ((pd = did_find(mod, din)) == NULL)
2973062Scindi 		return (NULL);
2983062Scindi 	did_markrc(pd);
2993062Scindi 	if ((ntn = hb_tnode_create(mod, parent, PCIEX_ROOT, ri, din)) == NULL)
3003062Scindi 		return (NULL);
3013062Scindi 	if (did_props_set(ntn, pd, RC_common_props, RC_propcnt) < 0) {
3023062Scindi 		topo_node_unbind(ntn);
3033062Scindi 		return (NULL);
3043062Scindi 	}
3053062Scindi 	/*
3063062Scindi 	 * We expect to find pci-express buses beneath a root complex
3073062Scindi 	 */
3083062Scindi 	if (child_range_add(mod, ntn, PCIEX_BUS, 0, MAX_HB_BUSES) < 0) {
3093062Scindi 		topo_node_range_destroy(ntn, PCIEX_BUS);
3103062Scindi 		return (NULL);
3113062Scindi 	}
3123062Scindi 	return (ntn);
3133062Scindi }
3143062Scindi 
3153062Scindi /*ARGSUSED*/
3163062Scindi static int
specific_hb_enum(topo_mod_t * mod,tnode_t * pn,const char * name,topo_instance_t imin,topo_instance_t imax,void * priv)3173062Scindi specific_hb_enum(topo_mod_t *mod, tnode_t *pn, const char *name,
3183062Scindi     topo_instance_t imin, topo_instance_t imax, void *priv)
3193062Scindi {
3203062Scindi 	tnode_t *hb;
3213062Scindi 	did_t *iodid = (did_t *)priv;
3223062Scindi 	did_t *didp;
3233062Scindi 	int brc = 0;
3243062Scindi 	int bus;
3253062Scindi 
3263062Scindi 	did_setspecific(mod, priv);
3273062Scindi 
3283062Scindi 	/*
3293062Scindi 	 * Find the hostbridge of interest
3303062Scindi 	 */
3313062Scindi 	didp = iodid;
3323062Scindi 	for (brc = 0; brc < imin; brc++)
3333062Scindi 		didp = did_chain_get(didp);
3343062Scindi 	assert(didp != NULL);
3353062Scindi 
3363062Scindi 	if ((hb = pcihostbridge_declare(mod, pn, did_dinode(didp), imin))
3373062Scindi 	    == NULL) {
3383062Scindi 		return (-1);
3393062Scindi 	}
3403062Scindi 	while (didp != NULL) {
3413062Scindi 		did_BDF(didp, &bus, NULL, NULL);
3423062Scindi 		if (topo_mod_enumerate(mod,
3433062Scindi 		    hb, PCI_BUS, PCI_BUS, bus, bus, didp) != 0) {
3443062Scindi 			return (topo_mod_seterrno(mod, EMOD_PARTIAL_ENUM));
3453062Scindi 		}
3463062Scindi 		didp = did_link_get(didp);
3473062Scindi 	}
3483062Scindi 
3493062Scindi 	return (0);
3503062Scindi }
351