xref: /onnv-gate/usr/src/lib/fm/topo/modules/sun4v/sun4vpi/sun4vpi.c (revision 11583:24344dea001d)
17205Ssd77468 /*
27205Ssd77468  * CDDL HEADER START
37205Ssd77468  *
47205Ssd77468  * The contents of this file are subject to the terms of the
57205Ssd77468  * Common Development and Distribution License (the "License").
67205Ssd77468  * You may not use this file except in compliance with the License.
77205Ssd77468  *
87205Ssd77468  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97205Ssd77468  * or http://www.opensolaris.org/os/licensing.
107205Ssd77468  * See the License for the specific language governing permissions
117205Ssd77468  * and limitations under the License.
127205Ssd77468  *
137205Ssd77468  * When distributing Covered Code, include this CDDL HEADER in each
147205Ssd77468  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157205Ssd77468  * If applicable, add the following below this CDDL HEADER, with the
167205Ssd77468  * fields enclosed by brackets "[]" replaced with your own identifying
177205Ssd77468  * information: Portions Copyright [yyyy] [name of copyright owner]
187205Ssd77468  *
197205Ssd77468  * CDDL HEADER END
207205Ssd77468  */
217205Ssd77468 
227205Ssd77468 /*
23*11583SSurya.Prakki@Sun.COM  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
247205Ssd77468  * Use is subject to license terms.
257205Ssd77468  */
267205Ssd77468 
277205Ssd77468 /*
287205Ssd77468  * Main entry points for SUN4V Platform Independent topology enumerator
297205Ssd77468  */
307205Ssd77468 #include <sys/types.h>
317205Ssd77468 #include <strings.h>
327205Ssd77468 #include <fm/topo_mod.h>
337205Ssd77468 #include <fm/topo_hc.h>
347205Ssd77468 #include <sys/systeminfo.h>
357205Ssd77468 #include <pi_impl.h>
367205Ssd77468 
377205Ssd77468 /*
387205Ssd77468  * Entry point called by libtopo when enumeration is required
397205Ssd77468  */
407205Ssd77468 static topo_enum_f	pi_enum;	/* libtopo enumeration entry point */
417205Ssd77468 
427205Ssd77468 
437205Ssd77468 /*
447205Ssd77468  * Declare the operations vector and information structure used during
457205Ssd77468  * module registration
467205Ssd77468  */
477205Ssd77468 static topo_modops_t	pi_ops	= {pi_enum, NULL};
487205Ssd77468 static topo_modinfo_t	pi_modinfo	= {
497205Ssd77468     SUN4VPI_DESC, SUN4VPI_SCHEME, SUN4VPI_VERSION, &pi_ops
507205Ssd77468 };
517205Ssd77468 
527205Ssd77468 static int pi_enum_components(pi_enum_t *, tnode_t *, const char *,
537205Ssd77468     mde_cookie_t, mde_str_cookie_t, mde_str_cookie_t);
547205Ssd77468 
557205Ssd77468 
567205Ssd77468 /*
577205Ssd77468  * Called by libtopo when the topo module is loaded.
587205Ssd77468  */
597205Ssd77468 void
_topo_init(topo_mod_t * mod,topo_version_t version)607205Ssd77468 _topo_init(topo_mod_t *mod, topo_version_t version)
617205Ssd77468 {
627205Ssd77468 	int		result;
637205Ssd77468 	char		isa[MAXNAMELEN];
647205Ssd77468 
657205Ssd77468 	if (getenv("TOPOSUN4VPIDBG") != NULL) {
667205Ssd77468 		/* Debugging is requested for this module */
677205Ssd77468 		topo_mod_setdebug(mod);
687205Ssd77468 	}
697205Ssd77468 	topo_mod_dprintf(mod, "sun4vpi module initializing.\n");
707205Ssd77468 
717205Ssd77468 	if (version != TOPO_VERSION) {
72*11583SSurya.Prakki@Sun.COM 		(void) topo_mod_seterrno(mod, EMOD_VER_NEW);
737205Ssd77468 		topo_mod_dprintf(mod, "incompatible topo version %d\n",
747205Ssd77468 		    version);
757205Ssd77468 		return;
767205Ssd77468 	}
777205Ssd77468 
787205Ssd77468 	/* Verify that this is a SUN4V architecture machine */
797205Ssd77468 	(void) sysinfo(SI_MACHINE, isa, MAXNAMELEN);
807205Ssd77468 	if (strncmp(isa, "sun4v", MAXNAMELEN) != 0) {
817205Ssd77468 		topo_mod_dprintf(mod, "not sun4v architecture: %s\n", isa);
827205Ssd77468 		return;
837205Ssd77468 	}
847205Ssd77468 
857205Ssd77468 	result = topo_mod_register(mod, &pi_modinfo, TOPO_VERSION);
867205Ssd77468 	if (result < 0) {
877205Ssd77468 		topo_mod_dprintf(mod, "registration failed: %s\n",
887205Ssd77468 		    topo_mod_errmsg(mod));
897205Ssd77468 
907205Ssd77468 		/* module errno already set */
917205Ssd77468 		return;
927205Ssd77468 	}
937205Ssd77468 	topo_mod_dprintf(mod, "module ready.\n");
947205Ssd77468 }
957205Ssd77468 
967205Ssd77468 
977205Ssd77468 /*
987205Ssd77468  * Clean up any data used by the module before it is unloaded.
997205Ssd77468  */
1007205Ssd77468 void
_topo_fini(topo_mod_t * mod)1017205Ssd77468 _topo_fini(topo_mod_t *mod)
1027205Ssd77468 {
1037205Ssd77468 	topo_mod_dprintf(mod, "module finishing.\n");
1047205Ssd77468 
1057205Ssd77468 	/* Unregister from libtopo */
1067205Ssd77468 	topo_mod_unregister(mod);
1077205Ssd77468 }
1087205Ssd77468 
1097205Ssd77468 
1107205Ssd77468 /*
1117205Ssd77468  * Enumeration entry point for the SUN4V topology enumerator
1127205Ssd77468  */
1137205Ssd77468 /* ARGSUSED */
1147205Ssd77468 static int
pi_enum(topo_mod_t * mod,tnode_t * t_parent,const char * name,topo_instance_t min,topo_instance_t max,void * pi_private,void * data)1157205Ssd77468 pi_enum(topo_mod_t *mod, tnode_t *t_parent, const char *name,
1167205Ssd77468     topo_instance_t min, topo_instance_t max, void *pi_private, void *data)
1177205Ssd77468 {
1187205Ssd77468 	int		result;
1197205Ssd77468 	int		idx;
1207205Ssd77468 	int		num_components;
1217205Ssd77468 	size_t		csize;
1227205Ssd77468 	hrtime_t	starttime;
1237205Ssd77468 
1247205Ssd77468 	pi_enum_t	pi;
1257205Ssd77468 
1267205Ssd77468 	mde_cookie_t	*components;
1277205Ssd77468 	mde_str_cookie_t arc_cookie;
1287205Ssd77468 	mde_str_cookie_t component_cookie;
1297205Ssd77468 
1307205Ssd77468 	/* Begin enumeration */
1317205Ssd77468 	starttime = gethrtime();
1327205Ssd77468 	topo_mod_dprintf(mod, "enumeration starting.\n");
1337205Ssd77468 
1347205Ssd77468 	/* Initialize the walker */
1357205Ssd77468 	result = pi_walker_init(mod);
1367205Ssd77468 	if (result != 0) {
137*11583SSurya.Prakki@Sun.COM 		(void) topo_mod_seterrno(mod, EMOD_UKNOWN_ENUM);
1387205Ssd77468 		return (-1);
1397205Ssd77468 	}
1407205Ssd77468 
1417205Ssd77468 	/* Open a connection to the LDOM PRI */
1427205Ssd77468 	bzero(&pi, sizeof (pi_enum_t));
1437205Ssd77468 	result = pi_ldompri_open(mod, &pi);
1447205Ssd77468 	if (result != 0) {
1457205Ssd77468 		pi_walker_fini(mod);
1467205Ssd77468 		topo_mod_dprintf(mod, "could not open LDOM PRI\n");
147*11583SSurya.Prakki@Sun.COM 		(void) topo_mod_seterrno(mod, EMOD_UKNOWN_ENUM);
1487205Ssd77468 		return (-1);
1497205Ssd77468 	}
1507205Ssd77468 	pi.mod = mod;
1517205Ssd77468 
1527205Ssd77468 	/*
1537205Ssd77468 	 * Find the top of the components graph in the PRI using the machine
1547205Ssd77468 	 * description library.
1557205Ssd77468 	 */
1567205Ssd77468 	num_components = pi_find_mdenodes(mod, pi.mdp, MDE_INVAL_ELEM_COOKIE,
1577205Ssd77468 	    MD_STR_COMPONENTS, MD_STR_FWD, &components, &csize);
1587205Ssd77468 	if (num_components < 0 || components == NULL) {
1597205Ssd77468 		/* No nodes were found */
1607205Ssd77468 		pi_walker_fini(mod);
1617205Ssd77468 		topo_mod_dprintf(mod, "could not find components in PRI\n");
162*11583SSurya.Prakki@Sun.COM 		(void) topo_mod_seterrno(mod, EMOD_UKNOWN_ENUM);
1637205Ssd77468 		return (-1);
1647205Ssd77468 	}
1657205Ssd77468 
1667205Ssd77468 	/*
1677205Ssd77468 	 * There should be a single components node.  But scan all of the
1687205Ssd77468 	 * results just in case a future machine has multiple hierarchies
1697205Ssd77468 	 * for some unknown reason.
1707205Ssd77468 	 *
1717205Ssd77468 	 * We continue to walk components nodes until they are all exhausted
1727205Ssd77468 	 * and do not stop if a node cannot be enumerated.  Instead, we
1737205Ssd77468 	 * enumerate what we can and return a partial-enumeration error if
1747205Ssd77468 	 * there is a problem.
1757205Ssd77468 	 */
1767205Ssd77468 	topo_mod_dprintf(mod, "enumerating %d components hierarchies\n",
1777205Ssd77468 	    num_components);
1787205Ssd77468 
1797205Ssd77468 	component_cookie = md_find_name(pi.mdp, MD_STR_COMPONENT);
1807205Ssd77468 	arc_cookie	 = md_find_name(pi.mdp, MD_STR_FWD);
1817205Ssd77468 	result = 0;
1827205Ssd77468 	for (idx = 0; idx < num_components; idx++) {
1837205Ssd77468 		int	skip;
1847205Ssd77468 
1857205Ssd77468 		/*
1867205Ssd77468 		 * We have found a component hierarchy to process.  First,
1877205Ssd77468 		 * make sure we are not supposed to skip the graph.
1887205Ssd77468 		 */
1897205Ssd77468 		skip = pi_skip_node(mod, pi.mdp, components[idx]);
1907205Ssd77468 		if (skip == 0) {
1917205Ssd77468 			/*
1927205Ssd77468 			 * We have found a components node.  Find the top-
1937205Ssd77468 			 * level nodes and create a topology tree from them.
1947205Ssd77468 			 */
1957205Ssd77468 			result = pi_enum_components(&pi, t_parent, name,
1967205Ssd77468 			    components[idx], component_cookie, arc_cookie);
1977205Ssd77468 		}
1987205Ssd77468 	}
1997205Ssd77468 	topo_mod_free(mod, components, csize);
2007205Ssd77468 
2017205Ssd77468 	/* Close our connection to the PRI */
2027205Ssd77468 	pi_ldompri_close(mod, &pi);
2037205Ssd77468 
2047205Ssd77468 	/* Clean up after the walker */
2057205Ssd77468 	pi_walker_fini(mod);
2067205Ssd77468 
2077205Ssd77468 	/* Complete enumeration */
2087205Ssd77468 	topo_mod_dprintf(mod, "enumeration complete in %lld ms.\n",
2097205Ssd77468 	    ((gethrtime() - starttime)/MICROSEC));
2107205Ssd77468 
2117205Ssd77468 	/* All done */
2127205Ssd77468 	return (result);
2137205Ssd77468 }
2147205Ssd77468 
2157205Ssd77468 
2167205Ssd77468 /*
2177205Ssd77468  * This routined is called once for each mde node of type 'components'.  It
2187205Ssd77468  * initiates enumeration of the graph starting with with this node.
2197205Ssd77468  */
2207205Ssd77468 static int
pi_enum_components(pi_enum_t * pip,tnode_t * t_parent,const char * hc_name,mde_cookie_t mde_node,mde_str_cookie_t component_cookie,mde_str_cookie_t arc_cookie)2217205Ssd77468 pi_enum_components(pi_enum_t *pip, tnode_t *t_parent, const char *hc_name,
2227205Ssd77468     mde_cookie_t mde_node, mde_str_cookie_t component_cookie,
2237205Ssd77468     mde_str_cookie_t arc_cookie)
2247205Ssd77468 {
2257205Ssd77468 	int		result;
2267205Ssd77468 
2277205Ssd77468 	int		num_arcs;
2287205Ssd77468 	mde_cookie_t	*arcp;
2297205Ssd77468 	size_t		arcsize;
2307205Ssd77468 	int		arcidx;
2317205Ssd77468 
2327205Ssd77468 	topo_mod_t	*mod = pip->mod;
2337205Ssd77468 	md_t		*mdp = pip->mdp;
2347205Ssd77468 
2357205Ssd77468 	if (t_parent == NULL) {
2367205Ssd77468 		topo_mod_dprintf(mod,
2377205Ssd77468 		    "walker failed to create node range with a NULL parent\n");
238*11583SSurya.Prakki@Sun.COM 		(void) topo_mod_seterrno(mod, EMOD_METHOD_INVAL);
2397205Ssd77468 		return (-1);
2407205Ssd77468 	}
2417205Ssd77468 
2427205Ssd77468 	/* Determine how many children the given node has */
2437205Ssd77468 	num_arcs = md_get_prop_arcs(mdp, mde_node, MD_STR_FWD, NULL, 0);
2447205Ssd77468 	if (num_arcs == 0) {
2457205Ssd77468 		/*
2467205Ssd77468 		 * This components node has no children and is not a topo
2477205Ssd77468 		 * node itself, so set partial enumeration and return.
2487205Ssd77468 		 */
249*11583SSurya.Prakki@Sun.COM 		(void) topo_mod_seterrno(mod, EMOD_PARTIAL_ENUM);
2507205Ssd77468 		return (0);
2517205Ssd77468 	}
2527205Ssd77468 	topo_mod_dprintf(mod, "node_0x%llx has %d children\n",
2537205Ssd77468 	    (uint64_t)mde_node, num_arcs);
2547205Ssd77468 
2557205Ssd77468 	/* Get the indexes for all the child nodes and put them in an array */
2567205Ssd77468 	arcsize = sizeof (mde_cookie_t) * num_arcs;
2577205Ssd77468 	arcp = topo_mod_zalloc(mod, arcsize);
2587205Ssd77468 	if (arcp == NULL) {
2597205Ssd77468 		topo_mod_dprintf(mod, "out of memory\n");
260*11583SSurya.Prakki@Sun.COM 		(void) topo_mod_seterrno(mod, EMOD_NOMEM);
2617205Ssd77468 		return (-1);
2627205Ssd77468 	}
2637205Ssd77468 	num_arcs = md_get_prop_arcs(mdp, mde_node, MD_STR_FWD, arcp,
2647205Ssd77468 	    arcsize);
2657205Ssd77468 
2667205Ssd77468 	result = 0;
2677205Ssd77468 	for (arcidx = 0; arcidx < num_arcs; arcidx++) {
2687205Ssd77468 		/*
2697205Ssd77468 		 * Initiate walking the PRI graph starting with the current
2707205Ssd77468 		 * child of the components node.
2717205Ssd77468 		 */
2727205Ssd77468 		result = pi_walker(pip, t_parent, hc_name,
2737205Ssd77468 		    arcp[arcidx], component_cookie, arc_cookie);
2747205Ssd77468 		if (result != 0) {
275*11583SSurya.Prakki@Sun.COM 			(void) topo_mod_seterrno(mod, EMOD_PARTIAL_ENUM);
2767205Ssd77468 		}
2777205Ssd77468 	}
2787205Ssd77468 	topo_mod_free(mod, arcp, arcsize);
2797205Ssd77468 
2807205Ssd77468 	/*
2817205Ssd77468 	 * We have now walked the entire PRI graph.  Execute any deferred
2827205Ssd77468 	 * enumeration routines that need all the nodes to be available.
2837205Ssd77468 	 */
2847205Ssd77468 	result = pi_defer_exec(mod, mdp);
2857205Ssd77468 
2867205Ssd77468 	return (result);
2877205Ssd77468 }
288