xref: /onnv-gate/usr/src/uts/common/os/lgrp_topo.c (revision 7632:91aa3d8541b5)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
55608Srv207048  * Common Development and Distribution License (the "License").
65608Srv207048  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
22*7632SNick.Todd@Sun.COM  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate /*
270Sstevel@tonic-gate  * lgroup topology
280Sstevel@tonic-gate  */
290Sstevel@tonic-gate 
300Sstevel@tonic-gate #include <sys/cpupart.h>
310Sstevel@tonic-gate #include <sys/lgrp.h>
320Sstevel@tonic-gate #include <sys/promif.h>
330Sstevel@tonic-gate #include <sys/types.h>
340Sstevel@tonic-gate 
350Sstevel@tonic-gate 
360Sstevel@tonic-gate #define	LGRP_TOPO_LEVELS	4	/* default height limit */
370Sstevel@tonic-gate #define	LGRP_TOPO_LEVELS_MAX	4	/* max height limit */
380Sstevel@tonic-gate 
390Sstevel@tonic-gate 
400Sstevel@tonic-gate /*
410Sstevel@tonic-gate  * Only collapse lgroups which have same latency (and resources)
420Sstevel@tonic-gate  */
430Sstevel@tonic-gate int		lgrp_collapse_equidist = 1;
440Sstevel@tonic-gate 
450Sstevel@tonic-gate int		lgrp_collapse_off = 1;	/* disable collapsing of duplicates */
460Sstevel@tonic-gate 
470Sstevel@tonic-gate /*
480Sstevel@tonic-gate  * Height to limit lgroup topology
490Sstevel@tonic-gate  */
500Sstevel@tonic-gate unsigned int	lgrp_topo_levels = LGRP_TOPO_LEVELS;
510Sstevel@tonic-gate 
520Sstevel@tonic-gate int		lgrp_split_off = 1;	/* disable splitting lgroups */
530Sstevel@tonic-gate 
540Sstevel@tonic-gate #ifdef	DEBUG
550Sstevel@tonic-gate /*
560Sstevel@tonic-gate  * Debugging output
570Sstevel@tonic-gate  * - 0: off
580Sstevel@tonic-gate  * - >0: on and bigger means more
590Sstevel@tonic-gate  */
600Sstevel@tonic-gate int	lgrp_topo_debug = 0;
610Sstevel@tonic-gate 
620Sstevel@tonic-gate 
630Sstevel@tonic-gate void
640Sstevel@tonic-gate klgrpset_print(klgrpset_t lgrpset)
650Sstevel@tonic-gate {
660Sstevel@tonic-gate 	int	i;
670Sstevel@tonic-gate 
680Sstevel@tonic-gate 
690Sstevel@tonic-gate 	prom_printf("0x%llx(", (u_longlong_t)lgrpset);
700Sstevel@tonic-gate 	for (i = 0; i <= lgrp_alloc_max; i++)
710Sstevel@tonic-gate 		if (klgrpset_ismember(lgrpset, i))
720Sstevel@tonic-gate 			prom_printf("%d ", i);
730Sstevel@tonic-gate 	prom_printf(")\n");
740Sstevel@tonic-gate }
750Sstevel@tonic-gate 
760Sstevel@tonic-gate 
770Sstevel@tonic-gate void
780Sstevel@tonic-gate lgrp_rsets_print(char *string, klgrpset_t *rsets)
790Sstevel@tonic-gate {
800Sstevel@tonic-gate 	int	i;
810Sstevel@tonic-gate 
820Sstevel@tonic-gate 	prom_printf("%s\n", string);
830Sstevel@tonic-gate 	for (i = 0; i < LGRP_RSRC_COUNT; i++)
840Sstevel@tonic-gate 		klgrpset_print(rsets[i]);
850Sstevel@tonic-gate }
860Sstevel@tonic-gate #endif	/* DEBUG */
870Sstevel@tonic-gate 
880Sstevel@tonic-gate 
890Sstevel@tonic-gate /*
900Sstevel@tonic-gate  * Add "from" lgroup resources to "to" lgroup resources
910Sstevel@tonic-gate  */
920Sstevel@tonic-gate void
930Sstevel@tonic-gate lgrp_rsets_add(klgrpset_t *from, klgrpset_t *to)
940Sstevel@tonic-gate {
950Sstevel@tonic-gate 	int	i;
960Sstevel@tonic-gate 
970Sstevel@tonic-gate 	for (i = 0; i < LGRP_RSRC_COUNT; i++)
980Sstevel@tonic-gate 		klgrpset_or(to[i], from[i]);
990Sstevel@tonic-gate }
1000Sstevel@tonic-gate 
1010Sstevel@tonic-gate 
1020Sstevel@tonic-gate /*
1030Sstevel@tonic-gate  * Copy "from" lgroup resources to "to" lgroup resources
1040Sstevel@tonic-gate  */
1050Sstevel@tonic-gate void
1060Sstevel@tonic-gate lgrp_rsets_copy(klgrpset_t *from, klgrpset_t *to)
1070Sstevel@tonic-gate {
1080Sstevel@tonic-gate 	int	i;
1090Sstevel@tonic-gate 
1100Sstevel@tonic-gate 	for (i = 0; i < LGRP_RSRC_COUNT; i++)
1110Sstevel@tonic-gate 		to[i] = from[i];
1120Sstevel@tonic-gate }
1130Sstevel@tonic-gate 
1140Sstevel@tonic-gate 
1150Sstevel@tonic-gate /*
1160Sstevel@tonic-gate  * Delete given lgroup ID from lgroup resource set of specified lgroup
1170Sstevel@tonic-gate  * and its ancestors if "follow_parent" is set
1180Sstevel@tonic-gate  */
1190Sstevel@tonic-gate void
1200Sstevel@tonic-gate lgrp_rsets_delete(lgrp_t *lgrp, lgrp_id_t lgrpid, int follow_parent)
1210Sstevel@tonic-gate {
1220Sstevel@tonic-gate 	int	i;
1230Sstevel@tonic-gate 
1240Sstevel@tonic-gate 	while (lgrp != NULL) {
1250Sstevel@tonic-gate 		for (i = 0; i < LGRP_RSRC_COUNT; i++)
1260Sstevel@tonic-gate 			klgrpset_del(lgrp->lgrp_set[i], lgrpid);
1270Sstevel@tonic-gate 		if (!follow_parent)
1280Sstevel@tonic-gate 			break;
1290Sstevel@tonic-gate 		lgrp = lgrp->lgrp_parent;
1300Sstevel@tonic-gate 	}
1310Sstevel@tonic-gate }
1320Sstevel@tonic-gate 
1330Sstevel@tonic-gate 
1340Sstevel@tonic-gate /*
1350Sstevel@tonic-gate  * Return whether given lgroup resource set empty
1360Sstevel@tonic-gate  */
1370Sstevel@tonic-gate int
1380Sstevel@tonic-gate lgrp_rsets_empty(klgrpset_t *rset)
1390Sstevel@tonic-gate {
1400Sstevel@tonic-gate 	int	i;
1410Sstevel@tonic-gate 
1420Sstevel@tonic-gate 	for (i = 0; i < LGRP_RSRC_COUNT; i++)
1430Sstevel@tonic-gate 		if (!klgrpset_isempty(rset[i]))
1440Sstevel@tonic-gate 			return (0);
1450Sstevel@tonic-gate 
1460Sstevel@tonic-gate 	return (1);
1470Sstevel@tonic-gate }
1480Sstevel@tonic-gate 
1490Sstevel@tonic-gate 
1500Sstevel@tonic-gate /*
1510Sstevel@tonic-gate  * Return whether given lgroup resource sets are same
1520Sstevel@tonic-gate  */
1530Sstevel@tonic-gate int
1540Sstevel@tonic-gate lgrp_rsets_equal(klgrpset_t *rset1, klgrpset_t *rset2)
1550Sstevel@tonic-gate {
1560Sstevel@tonic-gate 	int	i;
1570Sstevel@tonic-gate 
1580Sstevel@tonic-gate 	for (i = 0; i < LGRP_RSRC_COUNT; i++)
1590Sstevel@tonic-gate 		if (rset1[i] != rset2[i])
1600Sstevel@tonic-gate 			return (0);
1610Sstevel@tonic-gate 
1620Sstevel@tonic-gate 	return (1);
1630Sstevel@tonic-gate }
1640Sstevel@tonic-gate 
1650Sstevel@tonic-gate 
1660Sstevel@tonic-gate /*
1670Sstevel@tonic-gate  * Return whether specified lgroup ID is in given lgroup resource set
1680Sstevel@tonic-gate  */
1690Sstevel@tonic-gate int
1700Sstevel@tonic-gate lgrp_rsets_member(klgrpset_t *rset, lgrp_id_t lgrpid)
1710Sstevel@tonic-gate {
1720Sstevel@tonic-gate 	int	i;
1730Sstevel@tonic-gate 
1740Sstevel@tonic-gate 	for (i = 0; i < LGRP_RSRC_COUNT; i++)
1750Sstevel@tonic-gate 		if (klgrpset_ismember(rset[i], lgrpid))
1760Sstevel@tonic-gate 			return (1);
1770Sstevel@tonic-gate 
1780Sstevel@tonic-gate 	return (0);
1790Sstevel@tonic-gate }
1800Sstevel@tonic-gate 
1810Sstevel@tonic-gate 
1820Sstevel@tonic-gate /*
1830Sstevel@tonic-gate  * Return whether specified lgroup ID is in all lgroup resources
1840Sstevel@tonic-gate  */
1850Sstevel@tonic-gate int
1860Sstevel@tonic-gate lgrp_rsets_member_all(klgrpset_t *rset, lgrp_id_t lgrpid)
1870Sstevel@tonic-gate {
1880Sstevel@tonic-gate 	int	i;
1890Sstevel@tonic-gate 
1900Sstevel@tonic-gate 	for (i = 0; i < LGRP_RSRC_COUNT; i++)
1910Sstevel@tonic-gate 		if (!klgrpset_ismember(rset[i], lgrpid))
1920Sstevel@tonic-gate 			return (0);
1930Sstevel@tonic-gate 
1940Sstevel@tonic-gate 	return (1);
1950Sstevel@tonic-gate }
1960Sstevel@tonic-gate 
1970Sstevel@tonic-gate 
1980Sstevel@tonic-gate /*
1990Sstevel@tonic-gate  * Replace resources for given lgroup with specified resources at given
2000Sstevel@tonic-gate  * latency and shift its old resources to its parent and its parent's resources
2010Sstevel@tonic-gate  * to its parent, etc. until root lgroup reached
2020Sstevel@tonic-gate  */
2030Sstevel@tonic-gate void
2040Sstevel@tonic-gate lgrp_rsets_replace(klgrpset_t *rset, int latency, lgrp_t *lgrp, int shift)
2050Sstevel@tonic-gate {
2060Sstevel@tonic-gate 	lgrp_t		*cur;
2070Sstevel@tonic-gate 	int		lat_new;
2080Sstevel@tonic-gate 	int		lat_saved;
2090Sstevel@tonic-gate 	klgrpset_t	rset_new[LGRP_RSRC_COUNT];
2100Sstevel@tonic-gate 	klgrpset_t	rset_saved[LGRP_RSRC_COUNT];
2110Sstevel@tonic-gate 
2120Sstevel@tonic-gate 	cur = lgrp;
2130Sstevel@tonic-gate 	lat_saved = latency;
2140Sstevel@tonic-gate 	lgrp_rsets_copy(rset, rset_saved);
2150Sstevel@tonic-gate 	while (cur && cur != lgrp_root) {
2160Sstevel@tonic-gate 		/*
2170Sstevel@tonic-gate 		 * Save current resources and latency to insert in parent and
2180Sstevel@tonic-gate 		 * then replace with new resources and latency
2190Sstevel@tonic-gate 		 */
2200Sstevel@tonic-gate 		lgrp_rsets_copy(rset_saved, rset_new);
2210Sstevel@tonic-gate 		lgrp_rsets_copy(cur->lgrp_set, rset_saved);
2220Sstevel@tonic-gate 		lgrp_rsets_copy(rset_new, cur->lgrp_set);
2230Sstevel@tonic-gate 
2240Sstevel@tonic-gate 		lat_new = lat_saved;
2250Sstevel@tonic-gate 		lat_saved = cur->lgrp_latency;
2260Sstevel@tonic-gate 		cur->lgrp_latency = lat_new;
2270Sstevel@tonic-gate 		if (!shift)
2280Sstevel@tonic-gate 			break;
2290Sstevel@tonic-gate 		cur = cur->lgrp_parent;
2300Sstevel@tonic-gate 	}
2310Sstevel@tonic-gate }
2320Sstevel@tonic-gate 
2330Sstevel@tonic-gate 
2340Sstevel@tonic-gate /*
2350Sstevel@tonic-gate  * Set "to" lgroup resource set with given lgroup ID
2360Sstevel@tonic-gate  */
2370Sstevel@tonic-gate void
2380Sstevel@tonic-gate lgrp_rsets_set(klgrpset_t *to, lgrp_id_t lgrpid)
2390Sstevel@tonic-gate {
2400Sstevel@tonic-gate 	klgrpset_t	from;
2410Sstevel@tonic-gate 	int		i;
2420Sstevel@tonic-gate 
2430Sstevel@tonic-gate 	klgrpset_clear(from);
2440Sstevel@tonic-gate 	klgrpset_add(from, lgrpid);
2450Sstevel@tonic-gate 	for (i = 0; i < LGRP_RSRC_COUNT; i++) {
2460Sstevel@tonic-gate 		klgrpset_clear(to[i]);
2470Sstevel@tonic-gate 		klgrpset_or(to[i], from);
2480Sstevel@tonic-gate 	}
2490Sstevel@tonic-gate }
2500Sstevel@tonic-gate 
2510Sstevel@tonic-gate 
2520Sstevel@tonic-gate /*
2530Sstevel@tonic-gate  * Delete any ancestors of given child lgroup which don't have any other
2540Sstevel@tonic-gate  * children
2550Sstevel@tonic-gate  */
2560Sstevel@tonic-gate int
2570Sstevel@tonic-gate lgrp_ancestor_delete(lgrp_t *child, klgrpset_t *changed)
2580Sstevel@tonic-gate {
2590Sstevel@tonic-gate 	int		count;
2600Sstevel@tonic-gate 	lgrp_t		*current;
2610Sstevel@tonic-gate 	lgrp_id_t	lgrpid;
2620Sstevel@tonic-gate 	lgrp_t		*parent;
2630Sstevel@tonic-gate 
2640Sstevel@tonic-gate #ifdef	DEBUG
2650Sstevel@tonic-gate 	if (lgrp_topo_debug > 1) {
2660Sstevel@tonic-gate 		prom_printf("lgrp_ancestor_delete(0x%p[%d],0x%p)\n",
267*7632SNick.Todd@Sun.COM 		    (void *)child, child->lgrp_id, (void *)changed);
2680Sstevel@tonic-gate 	}
2690Sstevel@tonic-gate #endif	/* DEBUG */
2700Sstevel@tonic-gate 
2710Sstevel@tonic-gate 	count = 0;
2720Sstevel@tonic-gate 	if (changed)
2730Sstevel@tonic-gate 		klgrpset_clear(*changed);
2740Sstevel@tonic-gate 
2750Sstevel@tonic-gate 	/*
2760Sstevel@tonic-gate 	 * Visit ancestors, decrement child count for each, and remove any
2770Sstevel@tonic-gate 	 * that don't have any children left until we reach an ancestor that
2780Sstevel@tonic-gate 	 * has multiple children
2790Sstevel@tonic-gate 	 */
2800Sstevel@tonic-gate 	current = child;
2810Sstevel@tonic-gate 	parent = child->lgrp_parent;
2820Sstevel@tonic-gate 	lgrpid = current->lgrp_id;
2830Sstevel@tonic-gate 	while (parent != NULL) {
2840Sstevel@tonic-gate #ifdef	DEBUG
2850Sstevel@tonic-gate 		if (lgrp_topo_debug > 1)
2860Sstevel@tonic-gate 			prom_printf("lgrp_ancestor_delete: parent %d,"
2870Sstevel@tonic-gate 			    " current %d\n",
2880Sstevel@tonic-gate 			    parent->lgrp_id, lgrpid);
2890Sstevel@tonic-gate #endif	/* DEBUG */
2900Sstevel@tonic-gate 
2910Sstevel@tonic-gate 		klgrpset_del(parent->lgrp_leaves, lgrpid);
2920Sstevel@tonic-gate 		klgrpset_del(parent->lgrp_children, lgrpid);
2930Sstevel@tonic-gate 		parent->lgrp_childcnt--;
2940Sstevel@tonic-gate 		if (changed)
2950Sstevel@tonic-gate 			klgrpset_add(*changed, parent->lgrp_id);
2960Sstevel@tonic-gate 		count++;
2970Sstevel@tonic-gate 		if (parent->lgrp_childcnt != 0)
2980Sstevel@tonic-gate 			break;
2990Sstevel@tonic-gate 
3000Sstevel@tonic-gate 		current = parent;
3010Sstevel@tonic-gate 		parent = current->lgrp_parent;
3020Sstevel@tonic-gate 		lgrpid = current->lgrp_id;
3030Sstevel@tonic-gate 
3040Sstevel@tonic-gate #ifdef	DEBUG
3050Sstevel@tonic-gate 		if (lgrp_topo_debug > 0)
3060Sstevel@tonic-gate 			prom_printf("lgrp_ancestor_delete: destroy"
3070Sstevel@tonic-gate 			    " lgrp %d at 0x%p\n",
308*7632SNick.Todd@Sun.COM 			    current->lgrp_id, (void *)current);
3090Sstevel@tonic-gate #endif	/* DEBUG */
3100Sstevel@tonic-gate 		lgrp_destroy(current);
3110Sstevel@tonic-gate 	}
3120Sstevel@tonic-gate 
3130Sstevel@tonic-gate #ifdef	DEBUG
3140Sstevel@tonic-gate 	if (lgrp_topo_debug > 1 && changed)
3150Sstevel@tonic-gate 		prom_printf("lgrp_ancestor_delete: changed %d lgrps: 0x%llx\n",
3160Sstevel@tonic-gate 		    count, (u_longlong_t)*changed);
3170Sstevel@tonic-gate #endif	/* DEBUG */
3180Sstevel@tonic-gate 
3190Sstevel@tonic-gate 	return (count);
3200Sstevel@tonic-gate }
3210Sstevel@tonic-gate 
3220Sstevel@tonic-gate 
3230Sstevel@tonic-gate /*
3240Sstevel@tonic-gate  * Consolidate lgrp1 into lgrp2
3250Sstevel@tonic-gate  */
3260Sstevel@tonic-gate int
3270Sstevel@tonic-gate lgrp_consolidate(lgrp_t *lgrp1, lgrp_t *lgrp2, klgrpset_t *changed)
3280Sstevel@tonic-gate {
3290Sstevel@tonic-gate 	klgrpset_t	changes;
3300Sstevel@tonic-gate 	lgrp_t		*child;
3310Sstevel@tonic-gate 	int		count;
3320Sstevel@tonic-gate 	int		i;
3330Sstevel@tonic-gate 	lgrp_t		*parent;
3340Sstevel@tonic-gate 
3350Sstevel@tonic-gate 	/*
3360Sstevel@tonic-gate 	 * Leaf lgroups should never need to be consolidated
3370Sstevel@tonic-gate 	 */
3380Sstevel@tonic-gate 	if (lgrp1 == NULL || lgrp2 == NULL || lgrp1->lgrp_childcnt < 1 ||
3390Sstevel@tonic-gate 	    lgrp2->lgrp_childcnt < 1)
3400Sstevel@tonic-gate 		return (0);
3410Sstevel@tonic-gate 
3420Sstevel@tonic-gate #ifdef	DEBUG
3430Sstevel@tonic-gate 	if (lgrp_topo_debug > 0)
3440Sstevel@tonic-gate 		prom_printf("lgrp_consolidate(0x%p[%d],0x%p[%d],0x%p)\n",
345*7632SNick.Todd@Sun.COM 		    (void *)lgrp1, lgrp1->lgrp_id, (void *)lgrp2,
346*7632SNick.Todd@Sun.COM 		    lgrp2->lgrp_id, (void *)changed);
3470Sstevel@tonic-gate #endif	/* DEBUG */
3480Sstevel@tonic-gate 
3490Sstevel@tonic-gate 	count = 0;
3500Sstevel@tonic-gate 	if (changed)
3510Sstevel@tonic-gate 		klgrpset_clear(*changed);
3520Sstevel@tonic-gate 
3530Sstevel@tonic-gate 	/*
3540Sstevel@tonic-gate 	 * Lgroup represents resources within certain latency, so need to keep
3550Sstevel@tonic-gate 	 * biggest latency value of lgroups being consolidated
3560Sstevel@tonic-gate 	 */
3570Sstevel@tonic-gate 	if (lgrp1->lgrp_latency > lgrp2->lgrp_latency)
3580Sstevel@tonic-gate 		lgrp2->lgrp_latency = lgrp1->lgrp_latency;
3590Sstevel@tonic-gate 
3600Sstevel@tonic-gate 	/*
3610Sstevel@tonic-gate 	 * Delete ancestors of lgrp1 that don't have any other children
3620Sstevel@tonic-gate 	 */
3630Sstevel@tonic-gate #ifdef	DEBUG
3640Sstevel@tonic-gate 	if (lgrp_topo_debug > 1)
3650Sstevel@tonic-gate 		prom_printf("lgrp_consolidate: delete ancestors\n");
3660Sstevel@tonic-gate #endif	/* DEBUG */
3670Sstevel@tonic-gate 	count += lgrp_ancestor_delete(lgrp1, &changes);
3680Sstevel@tonic-gate 	if (changed) {
3690Sstevel@tonic-gate 		klgrpset_or(*changed, changes);
3700Sstevel@tonic-gate 		klgrpset_or(*changed, lgrp1->lgrp_id);
3710Sstevel@tonic-gate 		count++;
3720Sstevel@tonic-gate 	}
3730Sstevel@tonic-gate 
3740Sstevel@tonic-gate 	/*
3750Sstevel@tonic-gate 	 * Reparent children lgroups of lgrp1 to lgrp2
3760Sstevel@tonic-gate 	 */
3770Sstevel@tonic-gate 	for (i = 0; i <= lgrp_alloc_max; i++) {
3780Sstevel@tonic-gate 		if (i == lgrp2->lgrp_id ||
3790Sstevel@tonic-gate 		    !klgrpset_ismember(lgrp1->lgrp_children, i))
3800Sstevel@tonic-gate 			continue;
3810Sstevel@tonic-gate 		child = lgrp_table[i];
3820Sstevel@tonic-gate 		if (!LGRP_EXISTS(child))
3830Sstevel@tonic-gate 			continue;
3840Sstevel@tonic-gate #ifdef	DEBUG
3850Sstevel@tonic-gate 		if (lgrp_topo_debug > 0)
3860Sstevel@tonic-gate 			prom_printf("lgrp_consolidate: reparent "
3870Sstevel@tonic-gate 			    "lgrp %d to lgrp %d\n",
3880Sstevel@tonic-gate 			    child->lgrp_id, lgrp2->lgrp_id);
3890Sstevel@tonic-gate #endif	/* DEBUG */
3900Sstevel@tonic-gate 		klgrpset_or(lgrp2->lgrp_leaves, child->lgrp_leaves);
3910Sstevel@tonic-gate 		klgrpset_add(lgrp2->lgrp_children, child->lgrp_id);
3920Sstevel@tonic-gate 		lgrp2->lgrp_childcnt++;
3930Sstevel@tonic-gate 		child->lgrp_parent = lgrp2;
3940Sstevel@tonic-gate 		if (changed) {
3950Sstevel@tonic-gate 			klgrpset_add(*changed, child->lgrp_id);
3960Sstevel@tonic-gate 			klgrpset_add(*changed, lgrp2->lgrp_id);
3970Sstevel@tonic-gate 		}
3980Sstevel@tonic-gate 		count += 2;
3990Sstevel@tonic-gate 	}
4000Sstevel@tonic-gate 
4010Sstevel@tonic-gate 	/*
4020Sstevel@tonic-gate 	 * Proprogate leaves from lgrp2 to root
4030Sstevel@tonic-gate 	 */
4040Sstevel@tonic-gate 	child = lgrp2;
4050Sstevel@tonic-gate 	parent = child->lgrp_parent;
4060Sstevel@tonic-gate 	while (parent != NULL) {
4070Sstevel@tonic-gate 		klgrpset_or(parent->lgrp_leaves, child->lgrp_leaves);
4080Sstevel@tonic-gate 		if (changed)
4090Sstevel@tonic-gate 			klgrpset_add(*changed, parent->lgrp_id);
4100Sstevel@tonic-gate 		count++;
4110Sstevel@tonic-gate 		child = parent;
4120Sstevel@tonic-gate 		parent = parent->lgrp_parent;
4130Sstevel@tonic-gate 	}
4140Sstevel@tonic-gate 
4150Sstevel@tonic-gate #ifdef	DEBUG
4160Sstevel@tonic-gate 	if (lgrp_topo_debug > 0)
4170Sstevel@tonic-gate 		prom_printf("lgrp_consolidate: destroy lgrp %d at 0x%p\n",
418*7632SNick.Todd@Sun.COM 		    lgrp1->lgrp_id, (void *)lgrp1);
4190Sstevel@tonic-gate 	if (lgrp_topo_debug > 1 && changed)
4200Sstevel@tonic-gate 		prom_printf("lgrp_consolidate: changed %d lgrps: 0x%llx\n",
4210Sstevel@tonic-gate 		    count, (u_longlong_t)*changed);
4220Sstevel@tonic-gate #endif	/* DEBUG */
4230Sstevel@tonic-gate 
4240Sstevel@tonic-gate 	lgrp_destroy(lgrp1);
4250Sstevel@tonic-gate 
4260Sstevel@tonic-gate 	return (count);
4270Sstevel@tonic-gate }
4280Sstevel@tonic-gate 
4290Sstevel@tonic-gate /*
4300Sstevel@tonic-gate  * Collapse duplicates of target lgroups given
4310Sstevel@tonic-gate  */
4320Sstevel@tonic-gate int
4330Sstevel@tonic-gate lgrp_collapse_dups(klgrpset_t target_set, int equidist_only,
4340Sstevel@tonic-gate     klgrpset_t *changed)
4350Sstevel@tonic-gate {
4360Sstevel@tonic-gate 	klgrpset_t	changes;
4370Sstevel@tonic-gate 	int		count;
4380Sstevel@tonic-gate 	int		i;
4390Sstevel@tonic-gate 
4400Sstevel@tonic-gate 	count = 0;
4410Sstevel@tonic-gate 	if (changed)
4420Sstevel@tonic-gate 		klgrpset_clear(*changed);
4430Sstevel@tonic-gate 
4440Sstevel@tonic-gate 	if (lgrp_collapse_off)
4450Sstevel@tonic-gate 		return (0);
4460Sstevel@tonic-gate 
4470Sstevel@tonic-gate #ifdef	DEBUG
4480Sstevel@tonic-gate 	if (lgrp_topo_debug > 0)
4490Sstevel@tonic-gate 		prom_printf("lgrp_collapse_dups(0x%llx)\n",
4500Sstevel@tonic-gate 		    (u_longlong_t)target_set);
4510Sstevel@tonic-gate #endif	/* DEBUG */
4520Sstevel@tonic-gate 
4530Sstevel@tonic-gate 	/*
4540Sstevel@tonic-gate 	 * Look for duplicates of each target lgroup
4550Sstevel@tonic-gate 	 */
4560Sstevel@tonic-gate 	for (i = 0; i <= lgrp_alloc_max; i++) {
4570Sstevel@tonic-gate 		int	j;
4580Sstevel@tonic-gate 		lgrp_t	*keep;
4590Sstevel@tonic-gate 		lgrp_t	*target;
4600Sstevel@tonic-gate 
4610Sstevel@tonic-gate 		target = lgrp_table[i];
4620Sstevel@tonic-gate 
4630Sstevel@tonic-gate 		/*
4640Sstevel@tonic-gate 		 * Skip to next lgroup if there isn't one here, this is root
4650Sstevel@tonic-gate 		 * or leaf lgroup, or this isn't a target lgroup
4660Sstevel@tonic-gate 		 */
4670Sstevel@tonic-gate 		if (!LGRP_EXISTS(target) ||
4680Sstevel@tonic-gate 		    target == lgrp_root || target->lgrp_childcnt == 0 ||
4690Sstevel@tonic-gate 		    !klgrpset_ismember(target_set, target->lgrp_id))
4700Sstevel@tonic-gate 			continue;
4710Sstevel@tonic-gate 
4720Sstevel@tonic-gate 		/*
4730Sstevel@tonic-gate 		 * Find all lgroups with same resources and latency
4740Sstevel@tonic-gate 		 */
4750Sstevel@tonic-gate #ifdef	DEBUG
4760Sstevel@tonic-gate 		if (lgrp_topo_debug > 1)
4770Sstevel@tonic-gate 			prom_printf("lgrp_collapse_dups: find "
4780Sstevel@tonic-gate 			    "dups of lgrp %d at 0x%p\n",
479*7632SNick.Todd@Sun.COM 			    target->lgrp_id, (void *)target);
4800Sstevel@tonic-gate #endif	/* DEBUG */
4810Sstevel@tonic-gate 		keep = NULL;
4820Sstevel@tonic-gate 		for (j = 0; j <= lgrp_alloc_max; j++) {
4830Sstevel@tonic-gate 			lgrp_t	*lgrp;
4840Sstevel@tonic-gate 
4850Sstevel@tonic-gate 			lgrp = lgrp_table[j];
4860Sstevel@tonic-gate 
4870Sstevel@tonic-gate 			/*
4880Sstevel@tonic-gate 			 * Skip lgroup if there isn't one here, this is root
4890Sstevel@tonic-gate 			 * lgroup or leaf (which shouldn't have dups), or this
4900Sstevel@tonic-gate 			 * lgroup doesn't have same resources
4910Sstevel@tonic-gate 			 */
4920Sstevel@tonic-gate 			if (!LGRP_EXISTS(lgrp) ||
4930Sstevel@tonic-gate 			    lgrp->lgrp_childcnt == 0 ||
4940Sstevel@tonic-gate 			    !lgrp_rsets_equal(lgrp->lgrp_set,
4950Sstevel@tonic-gate 			    target->lgrp_set) ||
4960Sstevel@tonic-gate 			    (lgrp->lgrp_latency != target->lgrp_latency &&
4970Sstevel@tonic-gate 			    equidist_only))
4980Sstevel@tonic-gate 				continue;
4990Sstevel@tonic-gate 
5000Sstevel@tonic-gate 			/*
5010Sstevel@tonic-gate 			 * Keep first matching lgroup (but always keep root)
5020Sstevel@tonic-gate 			 * and consolidate other duplicates into it
5030Sstevel@tonic-gate 			 */
5040Sstevel@tonic-gate 			if (keep == NULL) {
5050Sstevel@tonic-gate 				keep = lgrp;
5060Sstevel@tonic-gate #ifdef	DEBUG
5070Sstevel@tonic-gate 				if (lgrp_topo_debug > 1)
5080Sstevel@tonic-gate 					prom_printf("lgrp_collapse_dups: "
5090Sstevel@tonic-gate 					    "keep lgrp %d at 0x%p\n",
510*7632SNick.Todd@Sun.COM 					    keep->lgrp_id, (void *)keep);
5110Sstevel@tonic-gate #endif	/* DEBUG */
5120Sstevel@tonic-gate 			} else {
5130Sstevel@tonic-gate 				if (lgrp == lgrp_root) {
5140Sstevel@tonic-gate 					lgrp = keep;
5150Sstevel@tonic-gate 					keep = lgrp_root;
5160Sstevel@tonic-gate 				}
5170Sstevel@tonic-gate #ifdef	DEBUG
5180Sstevel@tonic-gate 				if (lgrp_topo_debug > 0)
5190Sstevel@tonic-gate 					prom_printf("lgrp_collapse_dups:"
5200Sstevel@tonic-gate 					    " consolidate lgrp %d at 0x%p"
5210Sstevel@tonic-gate 					    " into lgrp %d at 0x%p\n",
522*7632SNick.Todd@Sun.COM 					    lgrp->lgrp_id, (void *)lgrp,
523*7632SNick.Todd@Sun.COM 					    keep->lgrp_id, (void *)keep);
5240Sstevel@tonic-gate #endif	/* DEBUG */
5250Sstevel@tonic-gate 				count += lgrp_consolidate(lgrp, keep,
5260Sstevel@tonic-gate 				    &changes);
5270Sstevel@tonic-gate 				if (changed)
5280Sstevel@tonic-gate 					klgrpset_or(*changed, changes);
5290Sstevel@tonic-gate 			}
5300Sstevel@tonic-gate 		}
5310Sstevel@tonic-gate 	}
5320Sstevel@tonic-gate 
5330Sstevel@tonic-gate #ifdef	DEBUG
5340Sstevel@tonic-gate 	if (lgrp_topo_debug > 1 && changed)
5350Sstevel@tonic-gate 		prom_printf("lgrp_collapse_dups: changed %d lgrps: 0x%llx\n",
5360Sstevel@tonic-gate 		    count, (u_longlong_t)*changed);
5370Sstevel@tonic-gate #endif	/* DEBUG */
5380Sstevel@tonic-gate 
5390Sstevel@tonic-gate 	return (count);
5400Sstevel@tonic-gate }
5410Sstevel@tonic-gate 
5420Sstevel@tonic-gate 
5430Sstevel@tonic-gate /*
5440Sstevel@tonic-gate  * Create new parent lgroup with given latency and resources for
5450Sstevel@tonic-gate  * specified child lgroup, and insert it into hierarchy
5460Sstevel@tonic-gate  */
5470Sstevel@tonic-gate int
5480Sstevel@tonic-gate lgrp_new_parent(lgrp_t *child, int latency, klgrpset_t *rset,
5490Sstevel@tonic-gate     klgrpset_t *changed)
5500Sstevel@tonic-gate {
5510Sstevel@tonic-gate 	int	count;
5520Sstevel@tonic-gate 	lgrp_t	*new;
5530Sstevel@tonic-gate 	lgrp_t	*old;
5540Sstevel@tonic-gate 
5550Sstevel@tonic-gate 	count = 0;
5560Sstevel@tonic-gate 	if (changed)
5570Sstevel@tonic-gate 		klgrpset_clear(*changed);
5580Sstevel@tonic-gate 
5590Sstevel@tonic-gate 	/*
5600Sstevel@tonic-gate 	 * Create lgroup and set its latency and resources
5610Sstevel@tonic-gate 	 */
5620Sstevel@tonic-gate 	new = lgrp_create();
5630Sstevel@tonic-gate 	new->lgrp_latency = latency;
5640Sstevel@tonic-gate 	lgrp_rsets_add(rset, new->lgrp_set);
5650Sstevel@tonic-gate 
5660Sstevel@tonic-gate 	/*
5670Sstevel@tonic-gate 	 * Insert new lgroup into hierarchy
5680Sstevel@tonic-gate 	 */
5690Sstevel@tonic-gate 	old = child->lgrp_parent;
5700Sstevel@tonic-gate 	new->lgrp_parent = old;
5710Sstevel@tonic-gate 	klgrpset_add(new->lgrp_children, child->lgrp_id);
5720Sstevel@tonic-gate 	new->lgrp_childcnt++;
5730Sstevel@tonic-gate 	klgrpset_add(new->lgrp_children, child->lgrp_id);
5740Sstevel@tonic-gate 	klgrpset_copy(new->lgrp_leaves, child->lgrp_leaves);
5750Sstevel@tonic-gate 
5760Sstevel@tonic-gate 	child->lgrp_parent = new;
5770Sstevel@tonic-gate 	if (old) {
5780Sstevel@tonic-gate 		klgrpset_del(old->lgrp_children, child->lgrp_id);
5790Sstevel@tonic-gate 		klgrpset_add(old->lgrp_children, new->lgrp_id);
5800Sstevel@tonic-gate 		if (changed)
5810Sstevel@tonic-gate 			klgrpset_add(*changed, old->lgrp_id);
5820Sstevel@tonic-gate 		count++;
5830Sstevel@tonic-gate 	}
5840Sstevel@tonic-gate 
5850Sstevel@tonic-gate 	if (changed) {
5860Sstevel@tonic-gate 		klgrpset_add(*changed, child->lgrp_id);
5870Sstevel@tonic-gate 		klgrpset_add(*changed, new->lgrp_id);
5880Sstevel@tonic-gate 	}
5890Sstevel@tonic-gate 	count += 2;
5900Sstevel@tonic-gate 
5910Sstevel@tonic-gate #ifdef	DEBUG
5920Sstevel@tonic-gate 	if (lgrp_topo_debug > 1 && changed)
5930Sstevel@tonic-gate 		prom_printf("lgrp_new_parent: changed %d lgrps: 0x%llx\n",
5940Sstevel@tonic-gate 		    count, (u_longlong_t)*changed);
5950Sstevel@tonic-gate #endif	/* DEBUG */
5960Sstevel@tonic-gate 
5970Sstevel@tonic-gate 	return (count);
5980Sstevel@tonic-gate }
5990Sstevel@tonic-gate 
6000Sstevel@tonic-gate 
6010Sstevel@tonic-gate /*
6020Sstevel@tonic-gate  * Proprogate resources of new leaf into parent lgroup of given child
6030Sstevel@tonic-gate  */
6040Sstevel@tonic-gate int
6050Sstevel@tonic-gate lgrp_proprogate(lgrp_t *newleaf, lgrp_t *child, int latency,
6060Sstevel@tonic-gate     klgrpset_t *changed)
6070Sstevel@tonic-gate {
6080Sstevel@tonic-gate 	int	count;
6090Sstevel@tonic-gate 	lgrp_t	*parent;
6100Sstevel@tonic-gate 
6110Sstevel@tonic-gate 	count = 0;
6120Sstevel@tonic-gate 	if (changed)
6130Sstevel@tonic-gate 		klgrpset_clear(*changed);
6140Sstevel@tonic-gate 
6150Sstevel@tonic-gate 	if (child == NULL || child->lgrp_parent == NULL)
6160Sstevel@tonic-gate 		return (0);
6170Sstevel@tonic-gate 
6180Sstevel@tonic-gate 	parent = child->lgrp_parent;
6190Sstevel@tonic-gate 	klgrpset_or(parent->lgrp_leaves, child->lgrp_leaves);
6200Sstevel@tonic-gate 	if (changed)
6210Sstevel@tonic-gate 		klgrpset_add(*changed, parent->lgrp_id);
6220Sstevel@tonic-gate 	count++;
6230Sstevel@tonic-gate 
6240Sstevel@tonic-gate 	/*
6250Sstevel@tonic-gate 	 * Don't proprogate new leaf resources to parent if it already
6260Sstevel@tonic-gate 	 * contains these resources
6270Sstevel@tonic-gate 	 */
6280Sstevel@tonic-gate 	if (lgrp_rsets_member_all(parent->lgrp_set, newleaf->lgrp_id)) {
6290Sstevel@tonic-gate #ifdef	DEBUG
6300Sstevel@tonic-gate 		if (lgrp_topo_debug > 1 && changed)
6310Sstevel@tonic-gate 			prom_printf("lgrp_proprogate: changed %d lgrps:"
6320Sstevel@tonic-gate 			    " 0x%llx\n",
6330Sstevel@tonic-gate 			    count, (u_longlong_t)*changed);
6340Sstevel@tonic-gate #endif	/* DEBUG */
6350Sstevel@tonic-gate 		return (count);
6360Sstevel@tonic-gate 	}
6370Sstevel@tonic-gate 
6380Sstevel@tonic-gate 	/*
6390Sstevel@tonic-gate 	 * Add leaf resources to parent lgroup
6400Sstevel@tonic-gate 	 */
6410Sstevel@tonic-gate 	lgrp_rsets_add(newleaf->lgrp_set, parent->lgrp_set);
6420Sstevel@tonic-gate 
6430Sstevel@tonic-gate #ifdef	DEBUG
6440Sstevel@tonic-gate 	if (lgrp_topo_debug > 1) {
6450Sstevel@tonic-gate 		prom_printf("lgrp_proprogate: newleaf %d(0x%p), "
6460Sstevel@tonic-gate 		    "latency %d, child %d(0x%p), parent %d(0x%p)\n",
647*7632SNick.Todd@Sun.COM 		    newleaf->lgrp_id, (void *)newleaf, latency, child->lgrp_id,
648*7632SNick.Todd@Sun.COM 		    (void *)child, parent->lgrp_id, (void *)parent);
6490Sstevel@tonic-gate 		prom_printf("lgrp_proprogate: parent's leaves becomes 0x%llx\n",
6500Sstevel@tonic-gate 		    (u_longlong_t)parent->lgrp_leaves);
6510Sstevel@tonic-gate 	}
6520Sstevel@tonic-gate 	if (lgrp_topo_debug > 0) {
6530Sstevel@tonic-gate 		prom_printf("lgrp_proprogate: adding to parent %d (0x%p)\n",
654*7632SNick.Todd@Sun.COM 		    parent->lgrp_id, (void *)parent);
6550Sstevel@tonic-gate 		lgrp_rsets_print("parent resources become:", parent->lgrp_set);
6560Sstevel@tonic-gate 	}
6570Sstevel@tonic-gate 
6580Sstevel@tonic-gate 	if (lgrp_topo_debug > 2 && changed)
6590Sstevel@tonic-gate 		prom_printf("lgrp_proprogate: changed %d lgrps: 0x%llx\n",
6600Sstevel@tonic-gate 		    count, (u_longlong_t)*changed);
6610Sstevel@tonic-gate 
6620Sstevel@tonic-gate #endif	/* DEBUG */
6630Sstevel@tonic-gate 
6640Sstevel@tonic-gate 	return (count);
6650Sstevel@tonic-gate }
6660Sstevel@tonic-gate 
6670Sstevel@tonic-gate 
6680Sstevel@tonic-gate /*
6690Sstevel@tonic-gate  * Split parent lgroup of given child if child's leaf decendant (oldleaf) has
6700Sstevel@tonic-gate  * different latency to new leaf lgroup (newleaf) than leaf lgroups of given
6710Sstevel@tonic-gate  * child's siblings
6720Sstevel@tonic-gate  */
6730Sstevel@tonic-gate int
6740Sstevel@tonic-gate lgrp_split(lgrp_t *oldleaf, lgrp_t *newleaf, lgrp_t *child,
6750Sstevel@tonic-gate     klgrpset_t *changed)
6760Sstevel@tonic-gate {
6770Sstevel@tonic-gate 	klgrpset_t	changes;
6780Sstevel@tonic-gate 	int		count;
6790Sstevel@tonic-gate 	int		i;
6800Sstevel@tonic-gate 	int		latency;
6810Sstevel@tonic-gate 	lgrp_t		*parent;
6820Sstevel@tonic-gate 
6830Sstevel@tonic-gate 	count = 0;
6840Sstevel@tonic-gate 	if (changed)
6850Sstevel@tonic-gate 		klgrpset_clear(*changed);
6860Sstevel@tonic-gate 
6870Sstevel@tonic-gate 	if (lgrp_split_off || newleaf == NULL || child == NULL)
6880Sstevel@tonic-gate 		return (0);
6890Sstevel@tonic-gate 
6900Sstevel@tonic-gate 	/*
6910Sstevel@tonic-gate 	 * Parent must have more than one child to have a child split from it
6920Sstevel@tonic-gate 	 * and root lgroup contains all resources and never needs to be split
6930Sstevel@tonic-gate 	 */
6940Sstevel@tonic-gate 	parent = child->lgrp_parent;
6950Sstevel@tonic-gate 	if (parent == NULL || parent->lgrp_childcnt < 2 || parent == lgrp_root)
6960Sstevel@tonic-gate 		return (0);
6970Sstevel@tonic-gate 
6980Sstevel@tonic-gate #ifdef	DEBUG
6990Sstevel@tonic-gate 	if (lgrp_topo_debug > 1)
7000Sstevel@tonic-gate 		prom_printf("lgrp_split(0x%p[%d],0x%p[%d],0x%p[%d],0x%p)\n",
701*7632SNick.Todd@Sun.COM 		    (void *)oldleaf, oldleaf->lgrp_id,
702*7632SNick.Todd@Sun.COM 		    (void *)newleaf, newleaf->lgrp_id,
703*7632SNick.Todd@Sun.COM 		    (void *)child, child->lgrp_id, (void *)changed);
7040Sstevel@tonic-gate #endif	/* DEBUG */
7050Sstevel@tonic-gate 
7060Sstevel@tonic-gate 	/*
7070Sstevel@tonic-gate 	 * Get latency between new leaf and old leaf whose lineage it is
7080Sstevel@tonic-gate 	 * being added
7090Sstevel@tonic-gate 	 */
7100Sstevel@tonic-gate 	latency = lgrp_plat_latency(oldleaf->lgrp_plathand,
7110Sstevel@tonic-gate 	    newleaf->lgrp_plathand);
7120Sstevel@tonic-gate 
7130Sstevel@tonic-gate 	/*
7140Sstevel@tonic-gate 	 * Check whether all sibling leaves of given child lgroup have same
7150Sstevel@tonic-gate 	 * latency to new leaf
7160Sstevel@tonic-gate 	 */
7170Sstevel@tonic-gate 	for (i = 0; i <= lgrp_alloc_max; i++) {
7180Sstevel@tonic-gate 		lgrp_t		*grandparent;
7190Sstevel@tonic-gate 		lgrp_t		*lgrp;
7200Sstevel@tonic-gate 		int		sibling_latency;
7210Sstevel@tonic-gate 
7220Sstevel@tonic-gate 		lgrp = lgrp_table[i];
7230Sstevel@tonic-gate 
7240Sstevel@tonic-gate 		/*
7250Sstevel@tonic-gate 		 * Skip non-existent lgroups, old leaf, and any lgroups that
7260Sstevel@tonic-gate 		 * don't have parent as common ancestor
7270Sstevel@tonic-gate 		 */
7280Sstevel@tonic-gate 		if (!LGRP_EXISTS(lgrp) || lgrp == oldleaf ||
7290Sstevel@tonic-gate 		    !klgrpset_ismember(parent->lgrp_leaves, lgrp->lgrp_id))
7300Sstevel@tonic-gate 			continue;
7310Sstevel@tonic-gate 
7320Sstevel@tonic-gate 		/*
7330Sstevel@tonic-gate 		 * Same latency, so skip
7340Sstevel@tonic-gate 		 */
7350Sstevel@tonic-gate 		sibling_latency = lgrp_plat_latency(lgrp->lgrp_plathand,
7360Sstevel@tonic-gate 		    newleaf->lgrp_plathand);
7370Sstevel@tonic-gate #ifdef	DEBUG
7380Sstevel@tonic-gate 		if (lgrp_topo_debug > 1)
7390Sstevel@tonic-gate 			prom_printf("lgrp_split: latency(%d,%d) %d,"
7400Sstevel@tonic-gate 			    " latency(%d,%d) %d\n",
7410Sstevel@tonic-gate 			    oldleaf->lgrp_id, newleaf->lgrp_id, latency,
7420Sstevel@tonic-gate 			    lgrp->lgrp_id, newleaf->lgrp_id, sibling_latency);
7430Sstevel@tonic-gate #endif	/* DEBUG */
7440Sstevel@tonic-gate 		if (sibling_latency == latency)
7450Sstevel@tonic-gate 			continue;
7460Sstevel@tonic-gate 
7470Sstevel@tonic-gate 		/*
7480Sstevel@tonic-gate 		 * Different latencies, so  remove child from its parent and
7490Sstevel@tonic-gate 		 * make new parent for old leaf with same latency and same
7500Sstevel@tonic-gate 		 * resources
7510Sstevel@tonic-gate 		 */
7520Sstevel@tonic-gate 		parent->lgrp_childcnt--;
7530Sstevel@tonic-gate 		klgrpset_del(parent->lgrp_children, child->lgrp_id);
7540Sstevel@tonic-gate 		klgrpset_del(parent->lgrp_leaves, oldleaf->lgrp_id);
7550Sstevel@tonic-gate 		grandparent = parent->lgrp_parent;
7560Sstevel@tonic-gate 		if (grandparent) {
7570Sstevel@tonic-gate 			grandparent->lgrp_childcnt++;
7580Sstevel@tonic-gate 			klgrpset_add(grandparent->lgrp_children,
7590Sstevel@tonic-gate 			    child->lgrp_id);
7600Sstevel@tonic-gate 			count++;
7610Sstevel@tonic-gate 			if (changed)
7620Sstevel@tonic-gate 				klgrpset_add(*changed, grandparent->lgrp_id);
7630Sstevel@tonic-gate 		}
7640Sstevel@tonic-gate 		child->lgrp_parent = grandparent;
7650Sstevel@tonic-gate 
7660Sstevel@tonic-gate 		count += lgrp_new_parent(child, parent->lgrp_latency,
7670Sstevel@tonic-gate 		    parent->lgrp_set, &changes);
7680Sstevel@tonic-gate 		if (changed) {
7690Sstevel@tonic-gate 			klgrpset_or(*changed, changes);
7700Sstevel@tonic-gate 
7710Sstevel@tonic-gate 			klgrpset_add(*changed, parent->lgrp_id);
7720Sstevel@tonic-gate 			klgrpset_add(*changed, child->lgrp_id);
7730Sstevel@tonic-gate 			count += 2;
7740Sstevel@tonic-gate 		}
7750Sstevel@tonic-gate 
7760Sstevel@tonic-gate 		parent = child->lgrp_parent;
7770Sstevel@tonic-gate #ifdef	DEBUG
7780Sstevel@tonic-gate 		if (lgrp_topo_debug > 0) {
7790Sstevel@tonic-gate 			prom_printf("lgrp_split: new parent %d (0x%p) for"
7800Sstevel@tonic-gate 			    " lgrp %d (0x%p)\n",
781*7632SNick.Todd@Sun.COM 			    parent->lgrp_id, (void *)parent,
782*7632SNick.Todd@Sun.COM 			    child->lgrp_id, (void *)child);
7830Sstevel@tonic-gate 			lgrp_rsets_print("new parent resources:",
7840Sstevel@tonic-gate 			    parent->lgrp_set);
7850Sstevel@tonic-gate 		}
7860Sstevel@tonic-gate 
7870Sstevel@tonic-gate 		if (lgrp_topo_debug > 1 && changed)
7880Sstevel@tonic-gate 			prom_printf("lgrp_split: changed %d lgrps: 0x%llx\n",
7890Sstevel@tonic-gate 			    count, (u_longlong_t)*changed);
7900Sstevel@tonic-gate #endif	/* DEBUG */
7910Sstevel@tonic-gate 
7920Sstevel@tonic-gate 		return (count);
7930Sstevel@tonic-gate 	}
7940Sstevel@tonic-gate 
7950Sstevel@tonic-gate #ifdef	DEBUG
7960Sstevel@tonic-gate 	if (lgrp_topo_debug > 1)
7970Sstevel@tonic-gate 		prom_printf("lgrp_split: no changes\n");
7980Sstevel@tonic-gate #endif	/* DEBUG */
7990Sstevel@tonic-gate 
8000Sstevel@tonic-gate 	return (count);
8010Sstevel@tonic-gate }
8020Sstevel@tonic-gate 
8030Sstevel@tonic-gate 
8040Sstevel@tonic-gate /*
8050Sstevel@tonic-gate  * Return height of lgroup topology from given lgroup to root
8060Sstevel@tonic-gate  */
8070Sstevel@tonic-gate int
8080Sstevel@tonic-gate lgrp_topo_height(lgrp_t *lgrp)
8090Sstevel@tonic-gate {
8100Sstevel@tonic-gate 	int	nlevels;
8110Sstevel@tonic-gate 
8120Sstevel@tonic-gate 	if (!LGRP_EXISTS(lgrp))
8130Sstevel@tonic-gate 		return (0);
8140Sstevel@tonic-gate 
8150Sstevel@tonic-gate 	nlevels = 0;
8160Sstevel@tonic-gate 	while (lgrp != NULL) {
8170Sstevel@tonic-gate 		lgrp = lgrp->lgrp_parent;
8180Sstevel@tonic-gate 		nlevels++;
8190Sstevel@tonic-gate 	}
8200Sstevel@tonic-gate 	return (nlevels);
8210Sstevel@tonic-gate }
8220Sstevel@tonic-gate 
8230Sstevel@tonic-gate 
8240Sstevel@tonic-gate /*
8250Sstevel@tonic-gate  * Add resources of new leaf to old leaf's lineage
8260Sstevel@tonic-gate  *
8270Sstevel@tonic-gate  * Assumes the following:
8280Sstevel@tonic-gate  * - Lgroup hierarchy consists of at least a root lgroup and its leaves
8290Sstevel@tonic-gate  *   including old and new ones given below
8300Sstevel@tonic-gate  * - New leaf lgroup has been created and does not need to have its resources
8310Sstevel@tonic-gate  *   added to it
8320Sstevel@tonic-gate  * - Latencies have been set for root and leaf lgroups
8330Sstevel@tonic-gate  */
8340Sstevel@tonic-gate int
8350Sstevel@tonic-gate lgrp_lineage_add(lgrp_t *newleaf, lgrp_t *oldleaf, klgrpset_t *changed)
8360Sstevel@tonic-gate {
8370Sstevel@tonic-gate 	klgrpset_t	changes;
8380Sstevel@tonic-gate 	lgrp_t		*child;
8390Sstevel@tonic-gate 	klgrpset_t	collapse;
8400Sstevel@tonic-gate 	int		count;
8410Sstevel@tonic-gate 	int		latency;
8420Sstevel@tonic-gate 	int		nlevels;
8430Sstevel@tonic-gate 	lgrp_t		*parent;
8440Sstevel@tonic-gate 	int		proprogate;
8450Sstevel@tonic-gate 	int		total;
8460Sstevel@tonic-gate 
8470Sstevel@tonic-gate 
8480Sstevel@tonic-gate 	count = total = 0;
8490Sstevel@tonic-gate 	if (changed)
8500Sstevel@tonic-gate 		klgrpset_clear(*changed);
8510Sstevel@tonic-gate 
8520Sstevel@tonic-gate 	if (newleaf == NULL || oldleaf == NULL || newleaf == oldleaf)
8530Sstevel@tonic-gate 		return (0);
8540Sstevel@tonic-gate 
8550Sstevel@tonic-gate #ifdef	DEBUG
8560Sstevel@tonic-gate 	if (lgrp_topo_debug > 0)
8570Sstevel@tonic-gate 		prom_printf("\nlgrp_lineage_add(0x%p[%d],0x%p[%d],0x%p)\n",
858*7632SNick.Todd@Sun.COM 		    (void *)newleaf, newleaf->lgrp_id,
859*7632SNick.Todd@Sun.COM 		    (void *)oldleaf, oldleaf->lgrp_id,
860*7632SNick.Todd@Sun.COM 		    (void *)changed);
8610Sstevel@tonic-gate #endif	/* DEBUG */
8620Sstevel@tonic-gate 
8630Sstevel@tonic-gate 	/*
8640Sstevel@tonic-gate 	 * Get latency between old and new leaves, so we can determine
8650Sstevel@tonic-gate 	 * where the new leaf fits in the old leaf's lineage
8660Sstevel@tonic-gate 	 */
8670Sstevel@tonic-gate 	latency = lgrp_plat_latency(oldleaf->lgrp_plathand,
8680Sstevel@tonic-gate 	    newleaf->lgrp_plathand);
8690Sstevel@tonic-gate 
8700Sstevel@tonic-gate 	/*
8710Sstevel@tonic-gate 	 * Determine height of lgroup topology from old leaf to root lgroup,
8720Sstevel@tonic-gate 	 * so height of topology may be limited if necessary
8730Sstevel@tonic-gate 	 */
8740Sstevel@tonic-gate 	nlevels = lgrp_topo_height(oldleaf);
8750Sstevel@tonic-gate 
8760Sstevel@tonic-gate #ifdef	DEBUG
8770Sstevel@tonic-gate 	if (lgrp_topo_debug > 1)
8780Sstevel@tonic-gate 		prom_printf("lgrp_lineage_add: latency(%d,%d) 0x%x, ht %d\n",
8790Sstevel@tonic-gate 		    oldleaf->lgrp_id, newleaf->lgrp_id, latency, nlevels);
8800Sstevel@tonic-gate #endif	/* DEBUG */
8810Sstevel@tonic-gate 
8820Sstevel@tonic-gate 	/*
8830Sstevel@tonic-gate 	 * Can't add new leaf to old leaf's lineage if we haven't
8840Sstevel@tonic-gate 	 * determined latency between them yet
8850Sstevel@tonic-gate 	 */
8860Sstevel@tonic-gate 	if (latency == 0)
8870Sstevel@tonic-gate 		return (0);
8880Sstevel@tonic-gate 
8890Sstevel@tonic-gate 	child = oldleaf;
8900Sstevel@tonic-gate 	parent = child->lgrp_parent;
8910Sstevel@tonic-gate 	proprogate = 0;
8920Sstevel@tonic-gate 	klgrpset_clear(collapse);
8930Sstevel@tonic-gate 
8940Sstevel@tonic-gate 	/*
8950Sstevel@tonic-gate 	 * Lineage of old leaf is basically a sorted list of the other leaves
8960Sstevel@tonic-gate 	 * from closest to farthest, so find where to add new leaf to the
8970Sstevel@tonic-gate 	 * lineage and proprogate its resources from that point up to the root
8980Sstevel@tonic-gate 	 * lgroup since parent lgroups contain all the resources of their
8990Sstevel@tonic-gate 	 * children
9000Sstevel@tonic-gate 	 */
9010Sstevel@tonic-gate 	do {
9020Sstevel@tonic-gate 		klgrpset_t	rset[LGRP_RSRC_COUNT];
9030Sstevel@tonic-gate 
9040Sstevel@tonic-gate #ifdef	DEBUG
9050Sstevel@tonic-gate 		if (lgrp_topo_debug > 1)
9060Sstevel@tonic-gate 			prom_printf("lgrp_lineage_add: child %d (0x%p), parent"
9070Sstevel@tonic-gate 			    " %d (0x%p)\n",
908*7632SNick.Todd@Sun.COM 			    child->lgrp_id, (void *)child,
909*7632SNick.Todd@Sun.COM 			    parent->lgrp_id, (void *)parent);
9100Sstevel@tonic-gate #endif	/* DEBUG */
9110Sstevel@tonic-gate 
9120Sstevel@tonic-gate 		/*
9130Sstevel@tonic-gate 		 * See whether parent lgroup needs to be split
9140Sstevel@tonic-gate 		 *
9150Sstevel@tonic-gate 		 * May need to split parent lgroup when it is ancestor to more
9160Sstevel@tonic-gate 		 * than one leaf, but all its leaves don't have latency to new
9170Sstevel@tonic-gate 		 * leaf within the parent lgroup's latency
9180Sstevel@tonic-gate 		 * NOTE: Don't want to collapse this lgroup since we just split
9190Sstevel@tonic-gate 		 * it from parent
9200Sstevel@tonic-gate 		 */
9210Sstevel@tonic-gate 		count = lgrp_split(oldleaf, newleaf, child, &changes);
9220Sstevel@tonic-gate 		if (count) {
9230Sstevel@tonic-gate #ifdef	DEBUG
9240Sstevel@tonic-gate 			if (lgrp_topo_debug > 0)
9250Sstevel@tonic-gate 				prom_printf("lgrp_lineage_add: setting parent"
9260Sstevel@tonic-gate 				    " for child %d from %d to %d\n",
9270Sstevel@tonic-gate 				    child->lgrp_id, parent->lgrp_id,
9280Sstevel@tonic-gate 				    child->lgrp_parent->lgrp_id);
9290Sstevel@tonic-gate #endif	/* DEBUG */
9300Sstevel@tonic-gate 			parent = child->lgrp_parent;
9310Sstevel@tonic-gate 			total += count;
9320Sstevel@tonic-gate 			if (changed)
9330Sstevel@tonic-gate 				klgrpset_or(*changed, changes);
9340Sstevel@tonic-gate 		}
9350Sstevel@tonic-gate 
9360Sstevel@tonic-gate 		/*
9370Sstevel@tonic-gate 		 * Already found where resources of new leaf belong in old
9380Sstevel@tonic-gate 		 * leaf's lineage, so proprogate resources of new leaf up
9390Sstevel@tonic-gate 		 * through rest of ancestors
9400Sstevel@tonic-gate 		 */
9410Sstevel@tonic-gate 		if (proprogate) {
9420Sstevel@tonic-gate 			total += lgrp_proprogate(newleaf, child, latency,
9430Sstevel@tonic-gate 			    &changes);
9440Sstevel@tonic-gate 			if (changed)
9450Sstevel@tonic-gate 				klgrpset_or(*changed, changes);
9460Sstevel@tonic-gate 
9470Sstevel@tonic-gate 			parent = child->lgrp_parent;
9480Sstevel@tonic-gate 			klgrpset_add(collapse, parent->lgrp_id);
9490Sstevel@tonic-gate 			child = parent;
9500Sstevel@tonic-gate 			parent = parent->lgrp_parent;
9510Sstevel@tonic-gate 			continue;
9520Sstevel@tonic-gate 		}
9530Sstevel@tonic-gate 
9540Sstevel@tonic-gate #ifdef	DEBUG
9550Sstevel@tonic-gate 		if (lgrp_topo_debug > 1)
9560Sstevel@tonic-gate 			prom_printf("lgrp_lineage_add: latency 0x%x,"
9570Sstevel@tonic-gate 			    " parent latency 0x%x\n",
9580Sstevel@tonic-gate 			    latency, parent->lgrp_latency);
9590Sstevel@tonic-gate #endif	/* DEBUG */
9600Sstevel@tonic-gate 		/*
9610Sstevel@tonic-gate 		 * As we work our way from the old leaf to the root lgroup,
9620Sstevel@tonic-gate 		 * new leaf resources should go in between two lgroups or into
9630Sstevel@tonic-gate 		 * one of the parent lgroups somewhere along the line
9640Sstevel@tonic-gate 		 */
9650Sstevel@tonic-gate 		if (latency < parent->lgrp_latency) {
9660Sstevel@tonic-gate 			lgrp_t	*intermed;
9670Sstevel@tonic-gate 
9680Sstevel@tonic-gate 			/*
9690Sstevel@tonic-gate 			 * New leaf resources should go in between current
9700Sstevel@tonic-gate 			 * child and parent
9710Sstevel@tonic-gate 			 */
9720Sstevel@tonic-gate #ifdef	DEBUG
9730Sstevel@tonic-gate 			if (lgrp_topo_debug > 0)
9740Sstevel@tonic-gate 				prom_printf("lgrp_lineage_add: "
9750Sstevel@tonic-gate 				    "latency < parent latency\n");
9760Sstevel@tonic-gate #endif	/* DEBUG */
9770Sstevel@tonic-gate 
9780Sstevel@tonic-gate 			/*
9790Sstevel@tonic-gate 			 * Create lgroup with desired resources and insert it
9800Sstevel@tonic-gate 			 * between child and parent
9810Sstevel@tonic-gate 			 */
9820Sstevel@tonic-gate 			lgrp_rsets_copy(child->lgrp_set, rset);
9830Sstevel@tonic-gate 			lgrp_rsets_add(newleaf->lgrp_set, rset);
9840Sstevel@tonic-gate 			if (nlevels >= lgrp_topo_levels) {
9850Sstevel@tonic-gate 				if (parent == lgrp_root)
9860Sstevel@tonic-gate 					break;
9870Sstevel@tonic-gate 
9880Sstevel@tonic-gate #ifdef	DEBUG
9890Sstevel@tonic-gate 				if (lgrp_topo_debug > 0) {
9900Sstevel@tonic-gate 					prom_printf("lgrp_lineage_add: "
9910Sstevel@tonic-gate 					    "replaced parent lgrp %d at 0x%p"
9920Sstevel@tonic-gate 					    " for lgrp %d\n",
993*7632SNick.Todd@Sun.COM 					    parent->lgrp_id, (void *)parent,
9940Sstevel@tonic-gate 					    child->lgrp_id);
9950Sstevel@tonic-gate 					lgrp_rsets_print("old parent"
9960Sstevel@tonic-gate 					    " resources:", parent->lgrp_set);
9970Sstevel@tonic-gate 					lgrp_rsets_print("new parent "
9980Sstevel@tonic-gate 					    "resources:", rset);
9990Sstevel@tonic-gate 				}
10000Sstevel@tonic-gate #endif	/* DEBUG */
10010Sstevel@tonic-gate 				/*
10020Sstevel@tonic-gate 				 * Replace contents of parent with new
10030Sstevel@tonic-gate 				 * leaf + child resources since new leaf is
10040Sstevel@tonic-gate 				 * closer and shift its parent's resources to
10050Sstevel@tonic-gate 				 * its parent, etc. until root lgroup reached
10060Sstevel@tonic-gate 				 */
10070Sstevel@tonic-gate 				lgrp_rsets_replace(rset, latency, parent, 1);
10080Sstevel@tonic-gate 				if (*changed)
10090Sstevel@tonic-gate 					klgrpset_or(*changed, parent->lgrp_id);
10100Sstevel@tonic-gate 				total++;
10110Sstevel@tonic-gate 				proprogate++;
10120Sstevel@tonic-gate 			} else {
10130Sstevel@tonic-gate 				total += lgrp_new_parent(child, latency, rset,
10140Sstevel@tonic-gate 				    &changes);
10150Sstevel@tonic-gate 				intermed = child->lgrp_parent;
10160Sstevel@tonic-gate 				klgrpset_add(collapse, intermed->lgrp_id);
10170Sstevel@tonic-gate 				if (changed)
10180Sstevel@tonic-gate 					klgrpset_or(*changed, changes);
10190Sstevel@tonic-gate 				child = intermed;
10200Sstevel@tonic-gate 				proprogate++;
10210Sstevel@tonic-gate #ifdef	DEBUG
10220Sstevel@tonic-gate 				if (lgrp_topo_debug > 0) {
10230Sstevel@tonic-gate 					prom_printf("lgrp_lineage_add: new "
10240Sstevel@tonic-gate 					    "parent lgrp %d at 0x%p for "
10250Sstevel@tonic-gate 					    "lgrp %d\n", intermed->lgrp_id,
1026*7632SNick.Todd@Sun.COM 					    (void *)intermed, child->lgrp_id);
10270Sstevel@tonic-gate 					lgrp_rsets_print("new parent "
10280Sstevel@tonic-gate 					    "resources:", rset);
10290Sstevel@tonic-gate 				}
10300Sstevel@tonic-gate #endif	/* DEBUG */
10310Sstevel@tonic-gate 				continue;
10320Sstevel@tonic-gate 			}
10330Sstevel@tonic-gate 
10340Sstevel@tonic-gate 		} else if (latency == parent->lgrp_latency) {
10350Sstevel@tonic-gate 			/*
10360Sstevel@tonic-gate 			 * New leaf resources should go into parent
10370Sstevel@tonic-gate 			 */
10380Sstevel@tonic-gate #ifdef	DEBUG
10390Sstevel@tonic-gate 			if (lgrp_topo_debug > 0)
10400Sstevel@tonic-gate 				prom_printf("lgrp_lineage_add: latency == "
10410Sstevel@tonic-gate 				    "parent latency\n");
10420Sstevel@tonic-gate #endif	/* DEBUG */
10430Sstevel@tonic-gate 
10440Sstevel@tonic-gate 			/*
10450Sstevel@tonic-gate 			 * It's already there, so don't need to do anything.
10460Sstevel@tonic-gate 			 */
10470Sstevel@tonic-gate 			if (lgrp_rsets_member_all(parent->lgrp_set,
10480Sstevel@tonic-gate 			    newleaf->lgrp_id))
10490Sstevel@tonic-gate 				break;
10500Sstevel@tonic-gate 
10510Sstevel@tonic-gate 			total += lgrp_proprogate(newleaf, child, latency,
10520Sstevel@tonic-gate 			    &changes);
10530Sstevel@tonic-gate 			parent = child->lgrp_parent;
10540Sstevel@tonic-gate 			klgrpset_add(collapse, parent->lgrp_id);
10550Sstevel@tonic-gate 			if (changed)
10560Sstevel@tonic-gate 				klgrpset_or(*changed, changes);
10570Sstevel@tonic-gate 
10580Sstevel@tonic-gate 			proprogate++;
10590Sstevel@tonic-gate 		}
10600Sstevel@tonic-gate 
10610Sstevel@tonic-gate 		child = parent;
10620Sstevel@tonic-gate 		parent = parent->lgrp_parent;
10630Sstevel@tonic-gate 	} while (parent != NULL);
10640Sstevel@tonic-gate 
10650Sstevel@tonic-gate 	/*
10660Sstevel@tonic-gate 	 * Consolidate any duplicate lgroups of ones just changed
10670Sstevel@tonic-gate 	 * Assume that there were no duplicates before last round of changes
10680Sstevel@tonic-gate 	 */
10690Sstevel@tonic-gate #ifdef	DEBUG
10700Sstevel@tonic-gate 	if (lgrp_topo_debug > 1)
10710Sstevel@tonic-gate 		prom_printf("lgrp_lineage_add: collapsing dups....\n");
10720Sstevel@tonic-gate #endif	/* DEBUG */
10730Sstevel@tonic-gate 
10740Sstevel@tonic-gate 	total += lgrp_collapse_dups(collapse, lgrp_collapse_equidist,
10750Sstevel@tonic-gate 	    &changes);
10760Sstevel@tonic-gate 	if (changed)
10770Sstevel@tonic-gate 		klgrpset_or(*changed, changes);
10780Sstevel@tonic-gate 
10790Sstevel@tonic-gate #ifdef	DEBUG
10800Sstevel@tonic-gate 	if (lgrp_topo_debug > 1 && changed)
10810Sstevel@tonic-gate 		prom_printf("lgrp_lineage_add: changed %d lgrps: 0x%llx\n",
10820Sstevel@tonic-gate 		    total, (u_longlong_t)*changed);
10830Sstevel@tonic-gate #endif	/* DEBUG */
10840Sstevel@tonic-gate 
10850Sstevel@tonic-gate 	return (total);
10860Sstevel@tonic-gate }
10870Sstevel@tonic-gate 
10880Sstevel@tonic-gate 
10890Sstevel@tonic-gate /*
10900Sstevel@tonic-gate  * Add leaf lgroup to lgroup topology
10910Sstevel@tonic-gate  */
10920Sstevel@tonic-gate int
10930Sstevel@tonic-gate lgrp_leaf_add(lgrp_t *leaf, lgrp_t **lgrps, int lgrp_count,
10940Sstevel@tonic-gate     klgrpset_t *changed)
10950Sstevel@tonic-gate {
10960Sstevel@tonic-gate 	klgrpset_t	changes;
10970Sstevel@tonic-gate 	int		count;
10980Sstevel@tonic-gate 	int		i;
10990Sstevel@tonic-gate 	int		latency;
11000Sstevel@tonic-gate 
11010Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&cpu_lock) || curthread->t_preempt > 0 ||
11020Sstevel@tonic-gate 	    !lgrp_initialized);
11030Sstevel@tonic-gate 
11040Sstevel@tonic-gate #ifdef	DEBUG
11050Sstevel@tonic-gate 	if (lgrp_topo_debug > 1)
11060Sstevel@tonic-gate 		prom_printf("\nlgrp_leaf_add(0x%p[%d],0x%p,%d,0x%p)\n",
1107*7632SNick.Todd@Sun.COM 		    (void *)leaf, leaf->lgrp_id, (void *)lgrps, lgrp_count,
1108*7632SNick.Todd@Sun.COM 		    (void *)changed);
11090Sstevel@tonic-gate #endif	/* DEBUG */
11100Sstevel@tonic-gate 
11110Sstevel@tonic-gate 	count = 0;
11120Sstevel@tonic-gate 	if (changed)
11130Sstevel@tonic-gate 		klgrpset_clear(*changed);
11140Sstevel@tonic-gate 
11150Sstevel@tonic-gate 	/*
11160Sstevel@tonic-gate 	 * Initialize parent of leaf lgroup to root
11170Sstevel@tonic-gate 	 */
11180Sstevel@tonic-gate 	if (leaf->lgrp_parent == NULL) {
11190Sstevel@tonic-gate 		leaf->lgrp_parent = lgrp_root;
11200Sstevel@tonic-gate 		lgrp_root->lgrp_childcnt++;
11210Sstevel@tonic-gate 		klgrpset_add(lgrp_root->lgrp_children, leaf->lgrp_id);
11220Sstevel@tonic-gate 
11230Sstevel@tonic-gate 		klgrpset_or(lgrp_root->lgrp_leaves, leaf->lgrp_leaves);
11240Sstevel@tonic-gate 		lgrp_rsets_add(leaf->lgrp_set, lgrp_root->lgrp_set);
11250Sstevel@tonic-gate 
11260Sstevel@tonic-gate #ifdef	DEBUG
11270Sstevel@tonic-gate 		if (lgrp_topo_debug > 1)
11280Sstevel@tonic-gate 			lgrp_rsets_print("lgrp_leaf_add: root lgrp resources",
11290Sstevel@tonic-gate 			    lgrp_root->lgrp_set);
11300Sstevel@tonic-gate #endif	/* DEBUG */
11310Sstevel@tonic-gate 
11320Sstevel@tonic-gate 		if (changed) {
11330Sstevel@tonic-gate 			klgrpset_add(*changed, lgrp_root->lgrp_id);
11340Sstevel@tonic-gate 			klgrpset_add(*changed, leaf->lgrp_id);
11350Sstevel@tonic-gate 		}
11360Sstevel@tonic-gate 		count += 2;
11370Sstevel@tonic-gate 	}
11380Sstevel@tonic-gate 
11390Sstevel@tonic-gate 	/*
11400Sstevel@tonic-gate 	 * Can't add leaf lgroup to rest of topology (and vice versa) unless
11410Sstevel@tonic-gate 	 * latency for it is available
11420Sstevel@tonic-gate 	 */
11430Sstevel@tonic-gate 	latency = lgrp_plat_latency(leaf->lgrp_plathand, leaf->lgrp_plathand);
11440Sstevel@tonic-gate 	if (latency == 0) {
11450Sstevel@tonic-gate #ifdef	DEBUG
11460Sstevel@tonic-gate 		if (lgrp_topo_debug > 1 && changed)
11470Sstevel@tonic-gate 			prom_printf("lgrp_leaf_add: changed %d lgrps: 0x%llx\n",
11480Sstevel@tonic-gate 			    count, (u_longlong_t)*changed);
11490Sstevel@tonic-gate #endif	/* DEBUG */
11500Sstevel@tonic-gate 		return (count);
11510Sstevel@tonic-gate 	}
11520Sstevel@tonic-gate 
11530Sstevel@tonic-gate 	/*
11540Sstevel@tonic-gate 	 * Make sure that root and leaf lgroup latencies are set
11550Sstevel@tonic-gate 	 */
11560Sstevel@tonic-gate 	lgrp_root->lgrp_latency = lgrp_plat_latency(lgrp_root->lgrp_plathand,
11570Sstevel@tonic-gate 	    lgrp_root->lgrp_plathand);
11580Sstevel@tonic-gate 	leaf->lgrp_latency = latency;
11590Sstevel@tonic-gate 
11600Sstevel@tonic-gate 	/*
11610Sstevel@tonic-gate 	 * Add leaf to lineage of other leaves and vice versa
11620Sstevel@tonic-gate 	 * since leaves come into existence at different times
11630Sstevel@tonic-gate 	 */
11640Sstevel@tonic-gate 	for (i = 0; i < lgrp_count; i++) {
11650Sstevel@tonic-gate 		lgrp_t		*lgrp;
11660Sstevel@tonic-gate 
11670Sstevel@tonic-gate 		lgrp = lgrps[i];
11680Sstevel@tonic-gate 
11690Sstevel@tonic-gate 		/*
11700Sstevel@tonic-gate 		 * Skip non-existent lgroups, new leaf lgroup, and
11710Sstevel@tonic-gate 		 * non-leaf lgroups
11720Sstevel@tonic-gate 		 */
11730Sstevel@tonic-gate 		if (!LGRP_EXISTS(lgrp) || lgrp == leaf ||
11740Sstevel@tonic-gate 		    lgrp->lgrp_childcnt != 0) {
11750Sstevel@tonic-gate #ifdef	DEBUG
11760Sstevel@tonic-gate 			if (lgrp_topo_debug > 1)
11770Sstevel@tonic-gate 				prom_printf("lgrp_leaf_add: skip "
11780Sstevel@tonic-gate 				    "lgrp %d at 0x%p\n",
1179*7632SNick.Todd@Sun.COM 				    lgrp->lgrp_id, (void *)lgrp);
11800Sstevel@tonic-gate #endif	/* DEBUG */
11810Sstevel@tonic-gate 			continue;
11820Sstevel@tonic-gate 		}
11830Sstevel@tonic-gate 
11840Sstevel@tonic-gate #ifdef	DEBUG
11850Sstevel@tonic-gate 		if (lgrp_topo_debug > 0)
11860Sstevel@tonic-gate 			prom_printf("lgrp_leaf_add: lgrp %d (0x%p) =>"
11870Sstevel@tonic-gate 			    " lgrp %d (0x%p)\n",
1188*7632SNick.Todd@Sun.COM 			    leaf->lgrp_id, (void *)leaf, lgrp->lgrp_id,
1189*7632SNick.Todd@Sun.COM 			    (void *)lgrp);
11900Sstevel@tonic-gate #endif	/* DEBUG */
11910Sstevel@tonic-gate 
11920Sstevel@tonic-gate 		count += lgrp_lineage_add(leaf, lgrp, &changes);
11930Sstevel@tonic-gate 		if (changed)
11940Sstevel@tonic-gate 			klgrpset_or(*changed, changes);
11950Sstevel@tonic-gate 
11960Sstevel@tonic-gate 		count += lgrp_lineage_add(lgrp, leaf, &changes);
11970Sstevel@tonic-gate 		if (changed)
11980Sstevel@tonic-gate 			klgrpset_or(*changed, changes);
11990Sstevel@tonic-gate 	}
12000Sstevel@tonic-gate 
12010Sstevel@tonic-gate #ifdef	DEBUG
12020Sstevel@tonic-gate 	if (lgrp_topo_debug > 1 && changed)
12030Sstevel@tonic-gate 		prom_printf("lgrp_leaf_add: changed %d lgrps: 0x%llx\n",
12040Sstevel@tonic-gate 		    count, (u_longlong_t)*changed);
12050Sstevel@tonic-gate #endif	/* DEBUG */
12060Sstevel@tonic-gate 
12070Sstevel@tonic-gate 	return (count);
12080Sstevel@tonic-gate }
12090Sstevel@tonic-gate 
12100Sstevel@tonic-gate 
12110Sstevel@tonic-gate /*
12120Sstevel@tonic-gate  * Remove resources of leaf from lgroup hierarchy
12130Sstevel@tonic-gate  */
12140Sstevel@tonic-gate int
12150Sstevel@tonic-gate lgrp_leaf_delete(lgrp_t *leaf, lgrp_t **lgrps, int lgrp_count,
12160Sstevel@tonic-gate     klgrpset_t *changed)
12170Sstevel@tonic-gate {
12180Sstevel@tonic-gate 	klgrpset_t	changes;
12190Sstevel@tonic-gate 	klgrpset_t	collapse;
12200Sstevel@tonic-gate 	int		count;
12210Sstevel@tonic-gate 	int		i;
12220Sstevel@tonic-gate 	lgrp_t		*lgrp;
12230Sstevel@tonic-gate 
12240Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&cpu_lock) || curthread->t_preempt > 0 ||
12250Sstevel@tonic-gate 	    !lgrp_initialized);
12260Sstevel@tonic-gate 
12270Sstevel@tonic-gate 	count = 0;
12280Sstevel@tonic-gate 	klgrpset_clear(collapse);
12290Sstevel@tonic-gate 	if (changed)
12300Sstevel@tonic-gate 		klgrpset_clear(*changed);
12310Sstevel@tonic-gate 
12320Sstevel@tonic-gate 	/*
12330Sstevel@tonic-gate 	 * Nothing to do if no leaf given
12340Sstevel@tonic-gate 	 */
12350Sstevel@tonic-gate 	if (leaf == NULL)
12360Sstevel@tonic-gate 		return (0);
12370Sstevel@tonic-gate 
12380Sstevel@tonic-gate #ifdef	DEBUG
12390Sstevel@tonic-gate 	if (lgrp_topo_debug > 0)
12400Sstevel@tonic-gate 		prom_printf("lgrp_leaf_delete(0x%p[%d],0x%p,%d,0x%p)\n",
1241*7632SNick.Todd@Sun.COM 		    (void *)leaf, leaf->lgrp_id, (void *)lgrps, lgrp_count,
1242*7632SNick.Todd@Sun.COM 		    (void *)changed);
12430Sstevel@tonic-gate #endif	/* DEBUG */
12440Sstevel@tonic-gate 
12450Sstevel@tonic-gate 	/*
12460Sstevel@tonic-gate 	 * Remove leaf from any lgroups containing its resources
12470Sstevel@tonic-gate 	 */
12480Sstevel@tonic-gate 	for (i = 0; i < lgrp_count; i++) {
12490Sstevel@tonic-gate 		lgrp = lgrps[i];
12500Sstevel@tonic-gate 		if (lgrp == NULL || lgrp->lgrp_id == LGRP_NONE ||
12510Sstevel@tonic-gate 		    !lgrp_rsets_member(lgrp->lgrp_set, leaf->lgrp_id))
12520Sstevel@tonic-gate 			continue;
12530Sstevel@tonic-gate 
12540Sstevel@tonic-gate #ifdef	DEBUG
12550Sstevel@tonic-gate 		if (lgrp_topo_debug > 0)
12560Sstevel@tonic-gate 			prom_printf("lgrp_leaf_delete: remove leaf from"
1257*7632SNick.Todd@Sun.COM 			    " lgrp %d at %p\n", lgrp->lgrp_id, (void *)lgrp);
12580Sstevel@tonic-gate #endif	/* DEBUG */
12590Sstevel@tonic-gate 
12600Sstevel@tonic-gate 		lgrp_rsets_delete(lgrp, leaf->lgrp_id, 0);
12610Sstevel@tonic-gate 		klgrpset_del(lgrp->lgrp_leaves, leaf->lgrp_id);
12620Sstevel@tonic-gate 
12630Sstevel@tonic-gate 		klgrpset_add(collapse, lgrp->lgrp_id);
12640Sstevel@tonic-gate 		count++;
12650Sstevel@tonic-gate 	}
12660Sstevel@tonic-gate 
12670Sstevel@tonic-gate 	/*
12680Sstevel@tonic-gate 	 * Remove leaf and its ancestors that don't have any other children
12690Sstevel@tonic-gate 	 */
12700Sstevel@tonic-gate #ifdef	DEBUG
12710Sstevel@tonic-gate 	if (lgrp_topo_debug > 1)
12720Sstevel@tonic-gate 		prom_printf("lgrp_leaf_delete: remove leaf and ancestors\n");
12730Sstevel@tonic-gate #endif	/* DEBUG */
12740Sstevel@tonic-gate 
12750Sstevel@tonic-gate 	count += lgrp_ancestor_delete(leaf, &changes);
12760Sstevel@tonic-gate 	klgrpset_or(collapse, changes);
12770Sstevel@tonic-gate 	klgrpset_add(collapse, leaf->lgrp_id);
12780Sstevel@tonic-gate 	count++;
12790Sstevel@tonic-gate 	lgrp_destroy(leaf);
12800Sstevel@tonic-gate 
12810Sstevel@tonic-gate 	/*
12820Sstevel@tonic-gate 	 * Consolidate any duplicate lgroups of ones just changed
12830Sstevel@tonic-gate 	 * Assume that there were no duplicates before last round of changes
12840Sstevel@tonic-gate 	 */
12850Sstevel@tonic-gate #ifdef	DEBUG
12860Sstevel@tonic-gate 	if (lgrp_topo_debug > 1)
12870Sstevel@tonic-gate 		prom_printf("lgrp_leaf_delete: collapsing dups\n");
12880Sstevel@tonic-gate #endif	/* DEBUG */
12890Sstevel@tonic-gate 	count += lgrp_collapse_dups(collapse, lgrp_collapse_equidist,
12900Sstevel@tonic-gate 	    &changes);
12910Sstevel@tonic-gate 	klgrpset_or(collapse, changes);
12920Sstevel@tonic-gate 	if (changed)
12930Sstevel@tonic-gate 		klgrpset_copy(*changed, collapse);
12940Sstevel@tonic-gate 
12950Sstevel@tonic-gate #ifdef	DEBUG
12960Sstevel@tonic-gate 	if (lgrp_topo_debug > 1 && changed)
12970Sstevel@tonic-gate 		prom_printf("lgrp_leaf_delete: changed %d lgrps: 0x%llx\n",
12980Sstevel@tonic-gate 		    count, (u_longlong_t)*changed);
12990Sstevel@tonic-gate #endif	/* DEBUG */
13000Sstevel@tonic-gate 
13010Sstevel@tonic-gate 	return (count);
13020Sstevel@tonic-gate }
13030Sstevel@tonic-gate 
13040Sstevel@tonic-gate 
13050Sstevel@tonic-gate /*
13060Sstevel@tonic-gate  * Flatten lgroup topology down to height specified
13070Sstevel@tonic-gate  */
13080Sstevel@tonic-gate int
13090Sstevel@tonic-gate lgrp_topo_flatten(int levels, lgrp_t **lgrps, int lgrp_count,
13100Sstevel@tonic-gate     klgrpset_t *changed)
13110Sstevel@tonic-gate {
13120Sstevel@tonic-gate 	int	count;
13130Sstevel@tonic-gate 	int	i;
13140Sstevel@tonic-gate 	lgrp_t	*lgrp;
13155608Srv207048 	lgrp_handle_t hdl;
13160Sstevel@tonic-gate 
13170Sstevel@tonic-gate 	/*
13180Sstevel@tonic-gate 	 * Only flatten down to 2 level for now
13190Sstevel@tonic-gate 	 */
13200Sstevel@tonic-gate 	if (levels != 2)
13210Sstevel@tonic-gate 		return (0);
13220Sstevel@tonic-gate 
13230Sstevel@tonic-gate 	/*
13240Sstevel@tonic-gate 	 * Look for non-leaf lgroups to remove and leaf lgroups to reparent
13250Sstevel@tonic-gate 	 */
13260Sstevel@tonic-gate 	count = 0;
13270Sstevel@tonic-gate 	for (i = 0; i <= lgrp_count; i++) {
13280Sstevel@tonic-gate 		/*
13290Sstevel@tonic-gate 		 * Skip non-existent lgroups and root
13300Sstevel@tonic-gate 		 */
13310Sstevel@tonic-gate 		lgrp = lgrps[i];
13325602Srv207048 		if (!LGRP_EXISTS(lgrp))
13330Sstevel@tonic-gate 			continue;
13340Sstevel@tonic-gate 
13355608Srv207048 		hdl = lgrp->lgrp_plathand;
13365608Srv207048 
13375608Srv207048 		if (lgrp == lgrp_root) {
13385608Srv207048 			lgrp->lgrp_latency = lgrp_plat_latency(hdl, hdl);
13395602Srv207048 			continue;
13405602Srv207048 		}
13415602Srv207048 
13420Sstevel@tonic-gate 		if (lgrp->lgrp_childcnt > 0) {
13430Sstevel@tonic-gate 			lgrp_t	*parent;
13440Sstevel@tonic-gate 
13450Sstevel@tonic-gate 			/*
13460Sstevel@tonic-gate 			 * Remove non-leaf lgroup from lgroup topology
13470Sstevel@tonic-gate 			 */
13480Sstevel@tonic-gate 			parent = lgrp->lgrp_parent;
13490Sstevel@tonic-gate 			if (changed) {
13500Sstevel@tonic-gate 				klgrpset_add(*changed, lgrp->lgrp_id);
13510Sstevel@tonic-gate 				klgrpset_add(*changed, parent->lgrp_id);
13520Sstevel@tonic-gate 				count += 2;
13530Sstevel@tonic-gate 			}
13540Sstevel@tonic-gate 			if (parent) {
13550Sstevel@tonic-gate 				klgrpset_del(parent->lgrp_children,
13560Sstevel@tonic-gate 				    lgrp->lgrp_id);
13570Sstevel@tonic-gate 				parent->lgrp_childcnt--;
13580Sstevel@tonic-gate 			}
13590Sstevel@tonic-gate 			lgrp_destroy(lgrp);
13600Sstevel@tonic-gate 		} else if (lgrp->lgrp_parent != lgrp_root) {
13610Sstevel@tonic-gate 			/*
13620Sstevel@tonic-gate 			 * Reparent leaf lgroup to root
13630Sstevel@tonic-gate 			 */
13640Sstevel@tonic-gate 			if (changed) {
13650Sstevel@tonic-gate 				klgrpset_add(*changed, lgrp_root->lgrp_id);
13660Sstevel@tonic-gate 				klgrpset_add(*changed, lgrp->lgrp_id);
13670Sstevel@tonic-gate 				count += 2;
13680Sstevel@tonic-gate 			}
13690Sstevel@tonic-gate 			lgrp->lgrp_parent = lgrp_root;
13700Sstevel@tonic-gate 			klgrpset_add(lgrp_root->lgrp_children, lgrp->lgrp_id);
13710Sstevel@tonic-gate 			lgrp_root->lgrp_childcnt++;
13720Sstevel@tonic-gate 			klgrpset_add(lgrp_root->lgrp_leaves, lgrp->lgrp_id);
13735602Srv207048 
13745608Srv207048 			lgrp->lgrp_latency = lgrp_plat_latency(hdl, hdl);
13750Sstevel@tonic-gate 		}
13760Sstevel@tonic-gate 	}
13770Sstevel@tonic-gate 
13780Sstevel@tonic-gate 	return (count);
13790Sstevel@tonic-gate }
13800Sstevel@tonic-gate 
13810Sstevel@tonic-gate 
13820Sstevel@tonic-gate /*
13830Sstevel@tonic-gate  * Return current height limit for lgroup topology
13840Sstevel@tonic-gate  */
13850Sstevel@tonic-gate int
13860Sstevel@tonic-gate lgrp_topo_ht_limit(void)
13870Sstevel@tonic-gate {
13880Sstevel@tonic-gate 	return (lgrp_topo_levels);
13890Sstevel@tonic-gate }
13900Sstevel@tonic-gate 
13910Sstevel@tonic-gate 
13920Sstevel@tonic-gate /*
13930Sstevel@tonic-gate  * Return default height limit for lgroup topology
13940Sstevel@tonic-gate  */
13950Sstevel@tonic-gate int
13960Sstevel@tonic-gate lgrp_topo_ht_limit_default(void)
13970Sstevel@tonic-gate {
13980Sstevel@tonic-gate 	return (LGRP_TOPO_LEVELS);
13990Sstevel@tonic-gate }
14000Sstevel@tonic-gate 
14010Sstevel@tonic-gate 
14020Sstevel@tonic-gate /*
14030Sstevel@tonic-gate  * Set height limit for lgroup topology
14040Sstevel@tonic-gate  */
14050Sstevel@tonic-gate int
14060Sstevel@tonic-gate lgrp_topo_ht_limit_set(int ht)
14070Sstevel@tonic-gate {
14080Sstevel@tonic-gate 	if (ht > LGRP_TOPO_LEVELS_MAX)
14090Sstevel@tonic-gate 		lgrp_topo_levels = LGRP_TOPO_LEVELS_MAX;
14100Sstevel@tonic-gate 	else
14110Sstevel@tonic-gate 		lgrp_topo_levels = ht;
14120Sstevel@tonic-gate 
14130Sstevel@tonic-gate 	return (ht);
14140Sstevel@tonic-gate }
14150Sstevel@tonic-gate 
14160Sstevel@tonic-gate 
14170Sstevel@tonic-gate /*
14180Sstevel@tonic-gate  * Update lgroup topology for any leaves that don't have their latency set
14190Sstevel@tonic-gate  *
14200Sstevel@tonic-gate  * This may happen on some machines when the lgroup platform support doesn't
14210Sstevel@tonic-gate  * know the latencies between nodes soon enough to provide it when the
14220Sstevel@tonic-gate  * resources are being added.  If the lgroup platform code needs to probe
14230Sstevel@tonic-gate  * memory to determine the latencies between nodes, it must wait until the
14240Sstevel@tonic-gate  * CPUs become active so at least one CPU in each node can probe memory in
14250Sstevel@tonic-gate  * each node.
14260Sstevel@tonic-gate  */
14270Sstevel@tonic-gate int
14280Sstevel@tonic-gate lgrp_topo_update(lgrp_t **lgrps, int lgrp_count, klgrpset_t *changed)
14290Sstevel@tonic-gate {
14300Sstevel@tonic-gate 	klgrpset_t	changes;
14310Sstevel@tonic-gate 	int		count;
14320Sstevel@tonic-gate 	int		i;
14330Sstevel@tonic-gate 	lgrp_t		*lgrp;
14340Sstevel@tonic-gate 
14350Sstevel@tonic-gate 	count = 0;
14360Sstevel@tonic-gate 	if (changed)
14370Sstevel@tonic-gate 		klgrpset_clear(*changed);
14380Sstevel@tonic-gate 
14390Sstevel@tonic-gate 	/*
14400Sstevel@tonic-gate 	 * For UMA machines, make sure that root lgroup contains all
14410Sstevel@tonic-gate 	 * resources.  The root lgrp should also name itself as its own leaf
14420Sstevel@tonic-gate 	 */
14430Sstevel@tonic-gate 	if (nlgrps == 1) {
14440Sstevel@tonic-gate 		for (i = 0; i < LGRP_RSRC_COUNT; i++)
14450Sstevel@tonic-gate 			klgrpset_add(lgrp_root->lgrp_set[i],
14460Sstevel@tonic-gate 			    lgrp_root->lgrp_id);
14470Sstevel@tonic-gate 		klgrpset_add(lgrp_root->lgrp_leaves, lgrp_root->lgrp_id);
14480Sstevel@tonic-gate 		return (0);
14490Sstevel@tonic-gate 	}
14500Sstevel@tonic-gate 
14510Sstevel@tonic-gate 	mutex_enter(&cpu_lock);
14520Sstevel@tonic-gate 	pause_cpus(NULL);
14530Sstevel@tonic-gate 
14540Sstevel@tonic-gate 	/*
14550Sstevel@tonic-gate 	 * Look for any leaf lgroup without its latency set, finish adding it
14560Sstevel@tonic-gate 	 * to the lgroup topology assuming that it exists and has the root
14570Sstevel@tonic-gate 	 * lgroup as its parent, and update the memory nodes of all lgroups
14580Sstevel@tonic-gate 	 * that have it as a memory resource.
14590Sstevel@tonic-gate 	 */
14600Sstevel@tonic-gate 	for (i = 0; i < lgrp_count; i++) {
14610Sstevel@tonic-gate 		lgrp = lgrps[i];
14620Sstevel@tonic-gate 
14630Sstevel@tonic-gate 		/*
14640Sstevel@tonic-gate 		 * Skip non-existent and non-leaf lgroups and any lgroup
14650Sstevel@tonic-gate 		 * with its latency set already
14660Sstevel@tonic-gate 		 */
14670Sstevel@tonic-gate 		if (lgrp == NULL || lgrp->lgrp_id == LGRP_NONE ||
14680Sstevel@tonic-gate 		    lgrp->lgrp_childcnt != 0 || lgrp->lgrp_latency != 0)
14690Sstevel@tonic-gate 			continue;
14700Sstevel@tonic-gate 
14710Sstevel@tonic-gate #ifdef	DEBUG
14720Sstevel@tonic-gate 		if (lgrp_topo_debug > 1) {
14730Sstevel@tonic-gate 			prom_printf("\nlgrp_topo_update: updating lineage "
1474*7632SNick.Todd@Sun.COM 			    "of lgrp %d at 0x%p\n", lgrp->lgrp_id,
1475*7632SNick.Todd@Sun.COM 			    (void *)lgrp);
14760Sstevel@tonic-gate 		}
14770Sstevel@tonic-gate #endif	/* DEBUG */
14780Sstevel@tonic-gate 
14790Sstevel@tonic-gate 		count += lgrp_leaf_add(lgrp, lgrps, lgrp_count, &changes);
14800Sstevel@tonic-gate 		if (changed)
14810Sstevel@tonic-gate 			klgrpset_or(*changed, changes);
14820Sstevel@tonic-gate 
14830Sstevel@tonic-gate 		if (!klgrpset_isempty(changes))
14840Sstevel@tonic-gate 			(void) lgrp_mnode_update(changes, NULL);
14850Sstevel@tonic-gate 
14860Sstevel@tonic-gate #ifdef	DEBUG
14870Sstevel@tonic-gate 		if (lgrp_topo_debug > 1 && changed)
14880Sstevel@tonic-gate 			prom_printf("lgrp_topo_update: changed %d lgrps: "
14890Sstevel@tonic-gate 			    "0x%llx\n",
14900Sstevel@tonic-gate 			    count, (u_longlong_t)*changed);
14910Sstevel@tonic-gate #endif	/* DEBUG */
14920Sstevel@tonic-gate 	}
14930Sstevel@tonic-gate 
14940Sstevel@tonic-gate 	if (lgrp_topo_levels < LGRP_TOPO_LEVELS && lgrp_topo_levels == 2) {
14950Sstevel@tonic-gate 		count += lgrp_topo_flatten(2, lgrps, lgrp_count, changed);
14960Sstevel@tonic-gate 		(void) lpl_topo_flatten(2);
14970Sstevel@tonic-gate 	}
14980Sstevel@tonic-gate 
14990Sstevel@tonic-gate 	start_cpus();
15000Sstevel@tonic-gate 	mutex_exit(&cpu_lock);
15010Sstevel@tonic-gate 
15020Sstevel@tonic-gate 	return (count);
15030Sstevel@tonic-gate }
15040Sstevel@tonic-gate 
15050Sstevel@tonic-gate #ifdef	DEBUG
15060Sstevel@tonic-gate void
15070Sstevel@tonic-gate lgrp_print(lgrp_t *lgrp)
15080Sstevel@tonic-gate {
15090Sstevel@tonic-gate 	lgrp_t	*parent;
15100Sstevel@tonic-gate 
15110Sstevel@tonic-gate 	prom_printf("LGRP %d", lgrp->lgrp_id);
15120Sstevel@tonic-gate 	if (lgrp->lgrp_childcnt == 0)
15130Sstevel@tonic-gate 		prom_printf(" (plathand %p)\n",
15140Sstevel@tonic-gate 		    (void *)lgrp->lgrp_plathand);
15150Sstevel@tonic-gate 	else
15160Sstevel@tonic-gate 		prom_printf("\n");
15170Sstevel@tonic-gate 
15180Sstevel@tonic-gate 	prom_printf("\tlatency %d\n", lgrp->lgrp_latency);
15190Sstevel@tonic-gate 
15200Sstevel@tonic-gate 	lgrp_rsets_print("\tresources", lgrp->lgrp_set);
15210Sstevel@tonic-gate 
15220Sstevel@tonic-gate 	parent = lgrp->lgrp_parent;
1523*7632SNick.Todd@Sun.COM 	prom_printf("\tparent 0x%p", (void *)parent);
15240Sstevel@tonic-gate 	if (parent)
15250Sstevel@tonic-gate 		prom_printf("[%d]\n", parent->lgrp_id);
15260Sstevel@tonic-gate 	else
15270Sstevel@tonic-gate 		prom_printf("\n");
15280Sstevel@tonic-gate 
15290Sstevel@tonic-gate 	prom_printf("\tchild count %d, children ", lgrp->lgrp_childcnt);
15300Sstevel@tonic-gate 	klgrpset_print(lgrp->lgrp_children);
15310Sstevel@tonic-gate 
15320Sstevel@tonic-gate 	prom_printf("\tleaves ");
15330Sstevel@tonic-gate 	klgrpset_print(lgrp->lgrp_leaves);
15340Sstevel@tonic-gate }
15350Sstevel@tonic-gate 
15360Sstevel@tonic-gate 
15370Sstevel@tonic-gate void
15380Sstevel@tonic-gate lgrp_topo_print(lgrp_t **lgrps, int lgrp_max)
15390Sstevel@tonic-gate {
15400Sstevel@tonic-gate 	klgrpset_t	siblings;
15410Sstevel@tonic-gate 
15420Sstevel@tonic-gate 	lgrp_print(lgrp_root);
15430Sstevel@tonic-gate 	siblings = lgrp_root->lgrp_children;
15440Sstevel@tonic-gate 	while (!klgrpset_isempty(siblings)) {
15450Sstevel@tonic-gate 		klgrpset_t	children;
15460Sstevel@tonic-gate 		int		i;
15470Sstevel@tonic-gate 
15480Sstevel@tonic-gate 		klgrpset_clear(children);
15490Sstevel@tonic-gate 		for (i = 0; i <= lgrp_max; i++) {
15500Sstevel@tonic-gate 			lgrp_t	*lgrp;
15510Sstevel@tonic-gate 
15520Sstevel@tonic-gate 			lgrp = lgrps[i];
15530Sstevel@tonic-gate 			if (lgrp == NULL || !klgrpset_ismember(siblings, i))
15540Sstevel@tonic-gate 				continue;
15550Sstevel@tonic-gate 			lgrp_print(lgrp);
15560Sstevel@tonic-gate 			klgrpset_or(children, lgrp->lgrp_children);
15570Sstevel@tonic-gate 		}
15580Sstevel@tonic-gate 		klgrpset_copy(siblings, children);
15590Sstevel@tonic-gate 	}
15600Sstevel@tonic-gate }
15610Sstevel@tonic-gate #endif	/* DEBUG */
1562