Home | History | Annotate | Download | only in os
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 /*
     22  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
     23  * Use is subject to license terms.
     24  */
     25 
     26 /*
     27  * lgroup topology
     28  */
     29 
     30 #include <sys/cpupart.h>
     31 #include <sys/lgrp.h>
     32 #include <sys/promif.h>
     33 #include <sys/types.h>
     34 
     35 
     36 #define	LGRP_TOPO_LEVELS	4	/* default height limit */
     37 #define	LGRP_TOPO_LEVELS_MAX	4	/* max height limit */
     38 
     39 
     40 /*
     41  * Only collapse lgroups which have same latency (and resources)
     42  */
     43 int		lgrp_collapse_equidist = 1;
     44 
     45 int		lgrp_collapse_off = 1;	/* disable collapsing of duplicates */
     46 
     47 /*
     48  * Height to limit lgroup topology
     49  */
     50 unsigned int	lgrp_topo_levels = LGRP_TOPO_LEVELS;
     51 
     52 int		lgrp_split_off = 1;	/* disable splitting lgroups */
     53 
     54 #ifdef	DEBUG
     55 /*
     56  * Debugging output
     57  * - 0: off
     58  * - >0: on and bigger means more
     59  */
     60 int	lgrp_topo_debug = 0;
     61 
     62 
     63 void
     64 klgrpset_print(klgrpset_t lgrpset)
     65 {
     66 	int	i;
     67 
     68 
     69 	prom_printf("0x%llx(", (u_longlong_t)lgrpset);
     70 	for (i = 0; i <= lgrp_alloc_max; i++)
     71 		if (klgrpset_ismember(lgrpset, i))
     72 			prom_printf("%d ", i);
     73 	prom_printf(")\n");
     74 }
     75 
     76 
     77 void
     78 lgrp_rsets_print(char *string, klgrpset_t *rsets)
     79 {
     80 	int	i;
     81 
     82 	prom_printf("%s\n", string);
     83 	for (i = 0; i < LGRP_RSRC_COUNT; i++)
     84 		klgrpset_print(rsets[i]);
     85 }
     86 #endif	/* DEBUG */
     87 
     88 
     89 /*
     90  * Add "from" lgroup resources to "to" lgroup resources
     91  */
     92 void
     93 lgrp_rsets_add(klgrpset_t *from, klgrpset_t *to)
     94 {
     95 	int	i;
     96 
     97 	for (i = 0; i < LGRP_RSRC_COUNT; i++)
     98 		klgrpset_or(to[i], from[i]);
     99 }
    100 
    101 
    102 /*
    103  * Copy "from" lgroup resources to "to" lgroup resources
    104  */
    105 void
    106 lgrp_rsets_copy(klgrpset_t *from, klgrpset_t *to)
    107 {
    108 	int	i;
    109 
    110 	for (i = 0; i < LGRP_RSRC_COUNT; i++)
    111 		to[i] = from[i];
    112 }
    113 
    114 
    115 /*
    116  * Delete given lgroup ID from lgroup resource set of specified lgroup
    117  * and its ancestors if "follow_parent" is set
    118  */
    119 void
    120 lgrp_rsets_delete(lgrp_t *lgrp, lgrp_id_t lgrpid, int follow_parent)
    121 {
    122 	int	i;
    123 
    124 	while (lgrp != NULL) {
    125 		for (i = 0; i < LGRP_RSRC_COUNT; i++)
    126 			klgrpset_del(lgrp->lgrp_set[i], lgrpid);
    127 		if (!follow_parent)
    128 			break;
    129 		lgrp = lgrp->lgrp_parent;
    130 	}
    131 }
    132 
    133 
    134 /*
    135  * Return whether given lgroup resource set empty
    136  */
    137 int
    138 lgrp_rsets_empty(klgrpset_t *rset)
    139 {
    140 	int	i;
    141 
    142 	for (i = 0; i < LGRP_RSRC_COUNT; i++)
    143 		if (!klgrpset_isempty(rset[i]))
    144 			return (0);
    145 
    146 	return (1);
    147 }
    148 
    149 
    150 /*
    151  * Return whether given lgroup resource sets are same
    152  */
    153 int
    154 lgrp_rsets_equal(klgrpset_t *rset1, klgrpset_t *rset2)
    155 {
    156 	int	i;
    157 
    158 	for (i = 0; i < LGRP_RSRC_COUNT; i++)
    159 		if (rset1[i] != rset2[i])
    160 			return (0);
    161 
    162 	return (1);
    163 }
    164 
    165 
    166 /*
    167  * Return whether specified lgroup ID is in given lgroup resource set
    168  */
    169 int
    170 lgrp_rsets_member(klgrpset_t *rset, lgrp_id_t lgrpid)
    171 {
    172 	int	i;
    173 
    174 	for (i = 0; i < LGRP_RSRC_COUNT; i++)
    175 		if (klgrpset_ismember(rset[i], lgrpid))
    176 			return (1);
    177 
    178 	return (0);
    179 }
    180 
    181 
    182 /*
    183  * Return whether specified lgroup ID is in all lgroup resources
    184  */
    185 int
    186 lgrp_rsets_member_all(klgrpset_t *rset, lgrp_id_t lgrpid)
    187 {
    188 	int	i;
    189 
    190 	for (i = 0; i < LGRP_RSRC_COUNT; i++)
    191 		if (!klgrpset_ismember(rset[i], lgrpid))
    192 			return (0);
    193 
    194 	return (1);
    195 }
    196 
    197 
    198 /*
    199  * Replace resources for given lgroup with specified resources at given
    200  * latency and shift its old resources to its parent and its parent's resources
    201  * to its parent, etc. until root lgroup reached
    202  */
    203 void
    204 lgrp_rsets_replace(klgrpset_t *rset, int latency, lgrp_t *lgrp, int shift)
    205 {
    206 	lgrp_t		*cur;
    207 	int		lat_new;
    208 	int		lat_saved;
    209 	klgrpset_t	rset_new[LGRP_RSRC_COUNT];
    210 	klgrpset_t	rset_saved[LGRP_RSRC_COUNT];
    211 
    212 	cur = lgrp;
    213 	lat_saved = latency;
    214 	lgrp_rsets_copy(rset, rset_saved);
    215 	while (cur && cur != lgrp_root) {
    216 		/*
    217 		 * Save current resources and latency to insert in parent and
    218 		 * then replace with new resources and latency
    219 		 */
    220 		lgrp_rsets_copy(rset_saved, rset_new);
    221 		lgrp_rsets_copy(cur->lgrp_set, rset_saved);
    222 		lgrp_rsets_copy(rset_new, cur->lgrp_set);
    223 
    224 		lat_new = lat_saved;
    225 		lat_saved = cur->lgrp_latency;
    226 		cur->lgrp_latency = lat_new;
    227 		if (!shift)
    228 			break;
    229 		cur = cur->lgrp_parent;
    230 	}
    231 }
    232 
    233 
    234 /*
    235  * Set "to" lgroup resource set with given lgroup ID
    236  */
    237 void
    238 lgrp_rsets_set(klgrpset_t *to, lgrp_id_t lgrpid)
    239 {
    240 	klgrpset_t	from;
    241 	int		i;
    242 
    243 	klgrpset_clear(from);
    244 	klgrpset_add(from, lgrpid);
    245 	for (i = 0; i < LGRP_RSRC_COUNT; i++) {
    246 		klgrpset_clear(to[i]);
    247 		klgrpset_or(to[i], from);
    248 	}
    249 }
    250 
    251 
    252 /*
    253  * Delete any ancestors of given child lgroup which don't have any other
    254  * children
    255  */
    256 int
    257 lgrp_ancestor_delete(lgrp_t *child, klgrpset_t *changed)
    258 {
    259 	int		count;
    260 	lgrp_t		*current;
    261 	lgrp_id_t	lgrpid;
    262 	lgrp_t		*parent;
    263 
    264 #ifdef	DEBUG
    265 	if (lgrp_topo_debug > 1) {
    266 		prom_printf("lgrp_ancestor_delete(0x%p[%d],0x%p)\n",
    267 		    (void *)child, child->lgrp_id, (void *)changed);
    268 	}
    269 #endif	/* DEBUG */
    270 
    271 	count = 0;
    272 	if (changed)
    273 		klgrpset_clear(*changed);
    274 
    275 	/*
    276 	 * Visit ancestors, decrement child count for each, and remove any
    277 	 * that don't have any children left until we reach an ancestor that
    278 	 * has multiple children
    279 	 */
    280 	current = child;
    281 	parent = child->lgrp_parent;
    282 	lgrpid = current->lgrp_id;
    283 	while (parent != NULL) {
    284 #ifdef	DEBUG
    285 		if (lgrp_topo_debug > 1)
    286 			prom_printf("lgrp_ancestor_delete: parent %d,"
    287 			    " current %d\n",
    288 			    parent->lgrp_id, lgrpid);
    289 #endif	/* DEBUG */
    290 
    291 		klgrpset_del(parent->lgrp_leaves, lgrpid);
    292 		klgrpset_del(parent->lgrp_children, lgrpid);
    293 		parent->lgrp_childcnt--;
    294 		if (changed)
    295 			klgrpset_add(*changed, parent->lgrp_id);
    296 		count++;
    297 		if (parent->lgrp_childcnt != 0)
    298 			break;
    299 
    300 		current = parent;
    301 		parent = current->lgrp_parent;
    302 		lgrpid = current->lgrp_id;
    303 
    304 #ifdef	DEBUG
    305 		if (lgrp_topo_debug > 0)
    306 			prom_printf("lgrp_ancestor_delete: destroy"
    307 			    " lgrp %d at 0x%p\n",
    308 			    current->lgrp_id, (void *)current);
    309 #endif	/* DEBUG */
    310 		lgrp_destroy(current);
    311 	}
    312 
    313 #ifdef	DEBUG
    314 	if (lgrp_topo_debug > 1 && changed)
    315 		prom_printf("lgrp_ancestor_delete: changed %d lgrps: 0x%llx\n",
    316 		    count, (u_longlong_t)*changed);
    317 #endif	/* DEBUG */
    318 
    319 	return (count);
    320 }
    321 
    322 
    323 /*
    324  * Consolidate lgrp1 into lgrp2
    325  */
    326 int
    327 lgrp_consolidate(lgrp_t *lgrp1, lgrp_t *lgrp2, klgrpset_t *changed)
    328 {
    329 	klgrpset_t	changes;
    330 	lgrp_t		*child;
    331 	int		count;
    332 	int		i;
    333 	lgrp_t		*parent;
    334 
    335 	/*
    336 	 * Leaf lgroups should never need to be consolidated
    337 	 */
    338 	if (lgrp1 == NULL || lgrp2 == NULL || lgrp1->lgrp_childcnt < 1 ||
    339 	    lgrp2->lgrp_childcnt < 1)
    340 		return (0);
    341 
    342 #ifdef	DEBUG
    343 	if (lgrp_topo_debug > 0)
    344 		prom_printf("lgrp_consolidate(0x%p[%d],0x%p[%d],0x%p)\n",
    345 		    (void *)lgrp1, lgrp1->lgrp_id, (void *)lgrp2,
    346 		    lgrp2->lgrp_id, (void *)changed);
    347 #endif	/* DEBUG */
    348 
    349 	count = 0;
    350 	if (changed)
    351 		klgrpset_clear(*changed);
    352 
    353 	/*
    354 	 * Lgroup represents resources within certain latency, so need to keep
    355 	 * biggest latency value of lgroups being consolidated
    356 	 */
    357 	if (lgrp1->lgrp_latency > lgrp2->lgrp_latency)
    358 		lgrp2->lgrp_latency = lgrp1->lgrp_latency;
    359 
    360 	/*
    361 	 * Delete ancestors of lgrp1 that don't have any other children
    362 	 */
    363 #ifdef	DEBUG
    364 	if (lgrp_topo_debug > 1)
    365 		prom_printf("lgrp_consolidate: delete ancestors\n");
    366 #endif	/* DEBUG */
    367 	count += lgrp_ancestor_delete(lgrp1, &changes);
    368 	if (changed) {
    369 		klgrpset_or(*changed, changes);
    370 		klgrpset_or(*changed, lgrp1->lgrp_id);
    371 		count++;
    372 	}
    373 
    374 	/*
    375 	 * Reparent children lgroups of lgrp1 to lgrp2
    376 	 */
    377 	for (i = 0; i <= lgrp_alloc_max; i++) {
    378 		if (i == lgrp2->lgrp_id ||
    379 		    !klgrpset_ismember(lgrp1->lgrp_children, i))
    380 			continue;
    381 		child = lgrp_table[i];
    382 		if (!LGRP_EXISTS(child))
    383 			continue;
    384 #ifdef	DEBUG
    385 		if (lgrp_topo_debug > 0)
    386 			prom_printf("lgrp_consolidate: reparent "
    387 			    "lgrp %d to lgrp %d\n",
    388 			    child->lgrp_id, lgrp2->lgrp_id);
    389 #endif	/* DEBUG */
    390 		klgrpset_or(lgrp2->lgrp_leaves, child->lgrp_leaves);
    391 		klgrpset_add(lgrp2->lgrp_children, child->lgrp_id);
    392 		lgrp2->lgrp_childcnt++;
    393 		child->lgrp_parent = lgrp2;
    394 		if (changed) {
    395 			klgrpset_add(*changed, child->lgrp_id);
    396 			klgrpset_add(*changed, lgrp2->lgrp_id);
    397 		}
    398 		count += 2;
    399 	}
    400 
    401 	/*
    402 	 * Proprogate leaves from lgrp2 to root
    403 	 */
    404 	child = lgrp2;
    405 	parent = child->lgrp_parent;
    406 	while (parent != NULL) {
    407 		klgrpset_or(parent->lgrp_leaves, child->lgrp_leaves);
    408 		if (changed)
    409 			klgrpset_add(*changed, parent->lgrp_id);
    410 		count++;
    411 		child = parent;
    412 		parent = parent->lgrp_parent;
    413 	}
    414 
    415 #ifdef	DEBUG
    416 	if (lgrp_topo_debug > 0)
    417 		prom_printf("lgrp_consolidate: destroy lgrp %d at 0x%p\n",
    418 		    lgrp1->lgrp_id, (void *)lgrp1);
    419 	if (lgrp_topo_debug > 1 && changed)
    420 		prom_printf("lgrp_consolidate: changed %d lgrps: 0x%llx\n",
    421 		    count, (u_longlong_t)*changed);
    422 #endif	/* DEBUG */
    423 
    424 	lgrp_destroy(lgrp1);
    425 
    426 	return (count);
    427 }
    428 
    429 /*
    430  * Collapse duplicates of target lgroups given
    431  */
    432 int
    433 lgrp_collapse_dups(klgrpset_t target_set, int equidist_only,
    434     klgrpset_t *changed)
    435 {
    436 	klgrpset_t	changes;
    437 	int		count;
    438 	int		i;
    439 
    440 	count = 0;
    441 	if (changed)
    442 		klgrpset_clear(*changed);
    443 
    444 	if (lgrp_collapse_off)
    445 		return (0);
    446 
    447 #ifdef	DEBUG
    448 	if (lgrp_topo_debug > 0)
    449 		prom_printf("lgrp_collapse_dups(0x%llx)\n",
    450 		    (u_longlong_t)target_set);
    451 #endif	/* DEBUG */
    452 
    453 	/*
    454 	 * Look for duplicates of each target lgroup
    455 	 */
    456 	for (i = 0; i <= lgrp_alloc_max; i++) {
    457 		int	j;
    458 		lgrp_t	*keep;
    459 		lgrp_t	*target;
    460 
    461 		target = lgrp_table[i];
    462 
    463 		/*
    464 		 * Skip to next lgroup if there isn't one here, this is root
    465 		 * or leaf lgroup, or this isn't a target lgroup
    466 		 */
    467 		if (!LGRP_EXISTS(target) ||
    468 		    target == lgrp_root || target->lgrp_childcnt == 0 ||
    469 		    !klgrpset_ismember(target_set, target->lgrp_id))
    470 			continue;
    471 
    472 		/*
    473 		 * Find all lgroups with same resources and latency
    474 		 */
    475 #ifdef	DEBUG
    476 		if (lgrp_topo_debug > 1)
    477 			prom_printf("lgrp_collapse_dups: find "
    478 			    "dups of lgrp %d at 0x%p\n",
    479 			    target->lgrp_id, (void *)target);
    480 #endif	/* DEBUG */
    481 		keep = NULL;
    482 		for (j = 0; j <= lgrp_alloc_max; j++) {
    483 			lgrp_t	*lgrp;
    484 
    485 			lgrp = lgrp_table[j];
    486 
    487 			/*
    488 			 * Skip lgroup if there isn't one here, this is root
    489 			 * lgroup or leaf (which shouldn't have dups), or this
    490 			 * lgroup doesn't have same resources
    491 			 */
    492 			if (!LGRP_EXISTS(lgrp) ||
    493 			    lgrp->lgrp_childcnt == 0 ||
    494 			    !lgrp_rsets_equal(lgrp->lgrp_set,
    495 			    target->lgrp_set) ||
    496 			    (lgrp->lgrp_latency != target->lgrp_latency &&
    497 			    equidist_only))
    498 				continue;
    499 
    500 			/*
    501 			 * Keep first matching lgroup (but always keep root)
    502 			 * and consolidate other duplicates into it
    503 			 */
    504 			if (keep == NULL) {
    505 				keep = lgrp;
    506 #ifdef	DEBUG
    507 				if (lgrp_topo_debug > 1)
    508 					prom_printf("lgrp_collapse_dups: "
    509 					    "keep lgrp %d at 0x%p\n",
    510 					    keep->lgrp_id, (void *)keep);
    511 #endif	/* DEBUG */
    512 			} else {
    513 				if (lgrp == lgrp_root) {
    514 					lgrp = keep;
    515 					keep = lgrp_root;
    516 				}
    517 #ifdef	DEBUG
    518 				if (lgrp_topo_debug > 0)
    519 					prom_printf("lgrp_collapse_dups:"
    520 					    " consolidate lgrp %d at 0x%p"
    521 					    " into lgrp %d at 0x%p\n",
    522 					    lgrp->lgrp_id, (void *)lgrp,
    523 					    keep->lgrp_id, (void *)keep);
    524 #endif	/* DEBUG */
    525 				count += lgrp_consolidate(lgrp, keep,
    526 				    &changes);
    527 				if (changed)
    528 					klgrpset_or(*changed, changes);
    529 			}
    530 		}
    531 	}
    532 
    533 #ifdef	DEBUG
    534 	if (lgrp_topo_debug > 1 && changed)
    535 		prom_printf("lgrp_collapse_dups: changed %d lgrps: 0x%llx\n",
    536 		    count, (u_longlong_t)*changed);
    537 #endif	/* DEBUG */
    538 
    539 	return (count);
    540 }
    541 
    542 
    543 /*
    544  * Create new parent lgroup with given latency and resources for
    545  * specified child lgroup, and insert it into hierarchy
    546  */
    547 int
    548 lgrp_new_parent(lgrp_t *child, int latency, klgrpset_t *rset,
    549     klgrpset_t *changed)
    550 {
    551 	int	count;
    552 	lgrp_t	*new;
    553 	lgrp_t	*old;
    554 
    555 	count = 0;
    556 	if (changed)
    557 		klgrpset_clear(*changed);
    558 
    559 	/*
    560 	 * Create lgroup and set its latency and resources
    561 	 */
    562 	new = lgrp_create();
    563 	new->lgrp_latency = latency;
    564 	lgrp_rsets_add(rset, new->lgrp_set);
    565 
    566 	/*
    567 	 * Insert new lgroup into hierarchy
    568 	 */
    569 	old = child->lgrp_parent;
    570 	new->lgrp_parent = old;
    571 	klgrpset_add(new->lgrp_children, child->lgrp_id);
    572 	new->lgrp_childcnt++;
    573 	klgrpset_add(new->lgrp_children, child->lgrp_id);
    574 	klgrpset_copy(new->lgrp_leaves, child->lgrp_leaves);
    575 
    576 	child->lgrp_parent = new;
    577 	if (old) {
    578 		klgrpset_del(old->lgrp_children, child->lgrp_id);
    579 		klgrpset_add(old->lgrp_children, new->lgrp_id);
    580 		if (changed)
    581 			klgrpset_add(*changed, old->lgrp_id);
    582 		count++;
    583 	}
    584 
    585 	if (changed) {
    586 		klgrpset_add(*changed, child->lgrp_id);
    587 		klgrpset_add(*changed, new->lgrp_id);
    588 	}
    589 	count += 2;
    590 
    591 #ifdef	DEBUG
    592 	if (lgrp_topo_debug > 1 && changed)
    593 		prom_printf("lgrp_new_parent: changed %d lgrps: 0x%llx\n",
    594 		    count, (u_longlong_t)*changed);
    595 #endif	/* DEBUG */
    596 
    597 	return (count);
    598 }
    599 
    600 
    601 /*
    602  * Proprogate resources of new leaf into parent lgroup of given child
    603  */
    604 int
    605 lgrp_proprogate(lgrp_t *newleaf, lgrp_t *child, int latency,
    606     klgrpset_t *changed)
    607 {
    608 	int	count;
    609 	lgrp_t	*parent;
    610 
    611 	count = 0;
    612 	if (changed)
    613 		klgrpset_clear(*changed);
    614 
    615 	if (child == NULL || child->lgrp_parent == NULL)
    616 		return (0);
    617 
    618 	parent = child->lgrp_parent;
    619 	klgrpset_or(parent->lgrp_leaves, child->lgrp_leaves);
    620 	if (changed)
    621 		klgrpset_add(*changed, parent->lgrp_id);
    622 	count++;
    623 
    624 	/*
    625 	 * Don't proprogate new leaf resources to parent if it already
    626 	 * contains these resources
    627 	 */
    628 	if (lgrp_rsets_member_all(parent->lgrp_set, newleaf->lgrp_id)) {
    629 #ifdef	DEBUG
    630 		if (lgrp_topo_debug > 1 && changed)
    631 			prom_printf("lgrp_proprogate: changed %d lgrps:"
    632 			    " 0x%llx\n",
    633 			    count, (u_longlong_t)*changed);
    634 #endif	/* DEBUG */
    635 		return (count);
    636 	}
    637 
    638 	/*
    639 	 * Add leaf resources to parent lgroup
    640 	 */
    641 	lgrp_rsets_add(newleaf->lgrp_set, parent->lgrp_set);
    642 
    643 #ifdef	DEBUG
    644 	if (lgrp_topo_debug > 1) {
    645 		prom_printf("lgrp_proprogate: newleaf %d(0x%p), "
    646 		    "latency %d, child %d(0x%p), parent %d(0x%p)\n",
    647 		    newleaf->lgrp_id, (void *)newleaf, latency, child->lgrp_id,
    648 		    (void *)child, parent->lgrp_id, (void *)parent);
    649 		prom_printf("lgrp_proprogate: parent's leaves becomes 0x%llx\n",
    650 		    (u_longlong_t)parent->lgrp_leaves);
    651 	}
    652 	if (lgrp_topo_debug > 0) {
    653 		prom_printf("lgrp_proprogate: adding to parent %d (0x%p)\n",
    654 		    parent->lgrp_id, (void *)parent);
    655 		lgrp_rsets_print("parent resources become:", parent->lgrp_set);
    656 	}
    657 
    658 	if (lgrp_topo_debug > 2 && changed)
    659 		prom_printf("lgrp_proprogate: changed %d lgrps: 0x%llx\n",
    660 		    count, (u_longlong_t)*changed);
    661 
    662 #endif	/* DEBUG */
    663 
    664 	return (count);
    665 }
    666 
    667 
    668 /*
    669  * Split parent lgroup of given child if child's leaf decendant (oldleaf) has
    670  * different latency to new leaf lgroup (newleaf) than leaf lgroups of given
    671  * child's siblings
    672  */
    673 int
    674 lgrp_split(lgrp_t *oldleaf, lgrp_t *newleaf, lgrp_t *child,
    675     klgrpset_t *changed)
    676 {
    677 	klgrpset_t	changes;
    678 	int		count;
    679 	int		i;
    680 	int		latency;
    681 	lgrp_t		*parent;
    682 
    683 	count = 0;
    684 	if (changed)
    685 		klgrpset_clear(*changed);
    686 
    687 	if (lgrp_split_off || newleaf == NULL || child == NULL)
    688 		return (0);
    689 
    690 	/*
    691 	 * Parent must have more than one child to have a child split from it
    692 	 * and root lgroup contains all resources and never needs to be split
    693 	 */
    694 	parent = child->lgrp_parent;
    695 	if (parent == NULL || parent->lgrp_childcnt < 2 || parent == lgrp_root)
    696 		return (0);
    697 
    698 #ifdef	DEBUG
    699 	if (lgrp_topo_debug > 1)
    700 		prom_printf("lgrp_split(0x%p[%d],0x%p[%d],0x%p[%d],0x%p)\n",
    701 		    (void *)oldleaf, oldleaf->lgrp_id,
    702 		    (void *)newleaf, newleaf->lgrp_id,
    703 		    (void *)child, child->lgrp_id, (void *)changed);
    704 #endif	/* DEBUG */
    705 
    706 	/*
    707 	 * Get latency between new leaf and old leaf whose lineage it is
    708 	 * being added
    709 	 */
    710 	latency = lgrp_plat_latency(oldleaf->lgrp_plathand,
    711 	    newleaf->lgrp_plathand);
    712 
    713 	/*
    714 	 * Check whether all sibling leaves of given child lgroup have same
    715 	 * latency to new leaf
    716 	 */
    717 	for (i = 0; i <= lgrp_alloc_max; i++) {
    718 		lgrp_t		*grandparent;
    719 		lgrp_t		*lgrp;
    720 		int		sibling_latency;
    721 
    722 		lgrp = lgrp_table[i];
    723 
    724 		/*
    725 		 * Skip non-existent lgroups, old leaf, and any lgroups that
    726 		 * don't have parent as common ancestor
    727 		 */
    728 		if (!LGRP_EXISTS(lgrp) || lgrp == oldleaf ||
    729 		    !klgrpset_ismember(parent->lgrp_leaves, lgrp->lgrp_id))
    730 			continue;
    731 
    732 		/*
    733 		 * Same latency, so skip
    734 		 */
    735 		sibling_latency = lgrp_plat_latency(lgrp->lgrp_plathand,
    736 		    newleaf->lgrp_plathand);
    737 #ifdef	DEBUG
    738 		if (lgrp_topo_debug > 1)
    739 			prom_printf("lgrp_split: latency(%d,%d) %d,"
    740 			    " latency(%d,%d) %d\n",
    741 			    oldleaf->lgrp_id, newleaf->lgrp_id, latency,
    742 			    lgrp->lgrp_id, newleaf->lgrp_id, sibling_latency);
    743 #endif	/* DEBUG */
    744 		if (sibling_latency == latency)
    745 			continue;
    746 
    747 		/*
    748 		 * Different latencies, so  remove child from its parent and
    749 		 * make new parent for old leaf with same latency and same
    750 		 * resources
    751 		 */
    752 		parent->lgrp_childcnt--;
    753 		klgrpset_del(parent->lgrp_children, child->lgrp_id);
    754 		klgrpset_del(parent->lgrp_leaves, oldleaf->lgrp_id);
    755 		grandparent = parent->lgrp_parent;
    756 		if (grandparent) {
    757 			grandparent->lgrp_childcnt++;
    758 			klgrpset_add(grandparent->lgrp_children,
    759 			    child->lgrp_id);
    760 			count++;
    761 			if (changed)
    762 				klgrpset_add(*changed, grandparent->lgrp_id);
    763 		}
    764 		child->lgrp_parent = grandparent;
    765 
    766 		count += lgrp_new_parent(child, parent->lgrp_latency,
    767 		    parent->lgrp_set, &changes);
    768 		if (changed) {
    769 			klgrpset_or(*changed, changes);
    770 
    771 			klgrpset_add(*changed, parent->lgrp_id);
    772 			klgrpset_add(*changed, child->lgrp_id);
    773 			count += 2;
    774 		}
    775 
    776 		parent = child->lgrp_parent;
    777 #ifdef	DEBUG
    778 		if (lgrp_topo_debug > 0) {
    779 			prom_printf("lgrp_split: new parent %d (0x%p) for"
    780 			    " lgrp %d (0x%p)\n",
    781 			    parent->lgrp_id, (void *)parent,
    782 			    child->lgrp_id, (void *)child);
    783 			lgrp_rsets_print("new parent resources:",
    784 			    parent->lgrp_set);
    785 		}
    786 
    787 		if (lgrp_topo_debug > 1 && changed)
    788 			prom_printf("lgrp_split: changed %d lgrps: 0x%llx\n",
    789 			    count, (u_longlong_t)*changed);
    790 #endif	/* DEBUG */
    791 
    792 		return (count);
    793 	}
    794 
    795 #ifdef	DEBUG
    796 	if (lgrp_topo_debug > 1)
    797 		prom_printf("lgrp_split: no changes\n");
    798 #endif	/* DEBUG */
    799 
    800 	return (count);
    801 }
    802 
    803 
    804 /*
    805  * Return height of lgroup topology from given lgroup to root
    806  */
    807 int
    808 lgrp_topo_height(lgrp_t *lgrp)
    809 {
    810 	int	nlevels;
    811 
    812 	if (!LGRP_EXISTS(lgrp))
    813 		return (0);
    814 
    815 	nlevels = 0;
    816 	while (lgrp != NULL) {
    817 		lgrp = lgrp->lgrp_parent;
    818 		nlevels++;
    819 	}
    820 	return (nlevels);
    821 }
    822 
    823 
    824 /*
    825  * Add resources of new leaf to old leaf's lineage
    826  *
    827  * Assumes the following:
    828  * - Lgroup hierarchy consists of at least a root lgroup and its leaves
    829  *   including old and new ones given below
    830  * - New leaf lgroup has been created and does not need to have its resources
    831  *   added to it
    832  * - Latencies have been set for root and leaf lgroups
    833  */
    834 int
    835 lgrp_lineage_add(lgrp_t *newleaf, lgrp_t *oldleaf, klgrpset_t *changed)
    836 {
    837 	klgrpset_t	changes;
    838 	lgrp_t		*child;
    839 	klgrpset_t	collapse;
    840 	int		count;
    841 	int		latency;
    842 	int		nlevels;
    843 	lgrp_t		*parent;
    844 	int		proprogate;
    845 	int		total;
    846 
    847 
    848 	count = total = 0;
    849 	if (changed)
    850 		klgrpset_clear(*changed);
    851 
    852 	if (newleaf == NULL || oldleaf == NULL || newleaf == oldleaf)
    853 		return (0);
    854 
    855 #ifdef	DEBUG
    856 	if (lgrp_topo_debug > 0)
    857 		prom_printf("\nlgrp_lineage_add(0x%p[%d],0x%p[%d],0x%p)\n",
    858 		    (void *)newleaf, newleaf->lgrp_id,
    859 		    (void *)oldleaf, oldleaf->lgrp_id,
    860 		    (void *)changed);
    861 #endif	/* DEBUG */
    862 
    863 	/*
    864 	 * Get latency between old and new leaves, so we can determine
    865 	 * where the new leaf fits in the old leaf's lineage
    866 	 */
    867 	latency = lgrp_plat_latency(oldleaf->lgrp_plathand,
    868 	    newleaf->lgrp_plathand);
    869 
    870 	/*
    871 	 * Determine height of lgroup topology from old leaf to root lgroup,
    872 	 * so height of topology may be limited if necessary
    873 	 */
    874 	nlevels = lgrp_topo_height(oldleaf);
    875 
    876 #ifdef	DEBUG
    877 	if (lgrp_topo_debug > 1)
    878 		prom_printf("lgrp_lineage_add: latency(%d,%d) 0x%x, ht %d\n",
    879 		    oldleaf->lgrp_id, newleaf->lgrp_id, latency, nlevels);
    880 #endif	/* DEBUG */
    881 
    882 	/*
    883 	 * Can't add new leaf to old leaf's lineage if we haven't
    884 	 * determined latency between them yet
    885 	 */
    886 	if (latency == 0)
    887 		return (0);
    888 
    889 	child = oldleaf;
    890 	parent = child->lgrp_parent;
    891 	proprogate = 0;
    892 	klgrpset_clear(collapse);
    893 
    894 	/*
    895 	 * Lineage of old leaf is basically a sorted list of the other leaves
    896 	 * from closest to farthest, so find where to add new leaf to the
    897 	 * lineage and proprogate its resources from that point up to the root
    898 	 * lgroup since parent lgroups contain all the resources of their
    899 	 * children
    900 	 */
    901 	do {
    902 		klgrpset_t	rset[LGRP_RSRC_COUNT];
    903 
    904 #ifdef	DEBUG
    905 		if (lgrp_topo_debug > 1)
    906 			prom_printf("lgrp_lineage_add: child %d (0x%p), parent"
    907 			    " %d (0x%p)\n",
    908 			    child->lgrp_id, (void *)child,
    909 			    parent->lgrp_id, (void *)parent);
    910 #endif	/* DEBUG */
    911 
    912 		/*
    913 		 * See whether parent lgroup needs to be split
    914 		 *
    915 		 * May need to split parent lgroup when it is ancestor to more
    916 		 * than one leaf, but all its leaves don't have latency to new
    917 		 * leaf within the parent lgroup's latency
    918 		 * NOTE: Don't want to collapse this lgroup since we just split
    919 		 * it from parent
    920 		 */
    921 		count = lgrp_split(oldleaf, newleaf, child, &changes);
    922 		if (count) {
    923 #ifdef	DEBUG
    924 			if (lgrp_topo_debug > 0)
    925 				prom_printf("lgrp_lineage_add: setting parent"
    926 				    " for child %d from %d to %d\n",
    927 				    child->lgrp_id, parent->lgrp_id,
    928 				    child->lgrp_parent->lgrp_id);
    929 #endif	/* DEBUG */
    930 			parent = child->lgrp_parent;
    931 			total += count;
    932 			if (changed)
    933 				klgrpset_or(*changed, changes);
    934 		}
    935 
    936 		/*
    937 		 * Already found where resources of new leaf belong in old
    938 		 * leaf's lineage, so proprogate resources of new leaf up
    939 		 * through rest of ancestors
    940 		 */
    941 		if (proprogate) {
    942 			total += lgrp_proprogate(newleaf, child, latency,
    943 			    &changes);
    944 			if (changed)
    945 				klgrpset_or(*changed, changes);
    946 
    947 			parent = child->lgrp_parent;
    948 			klgrpset_add(collapse, parent->lgrp_id);
    949 			child = parent;
    950 			parent = parent->lgrp_parent;
    951 			continue;
    952 		}
    953 
    954 #ifdef	DEBUG
    955 		if (lgrp_topo_debug > 1)
    956 			prom_printf("lgrp_lineage_add: latency 0x%x,"
    957 			    " parent latency 0x%x\n",
    958 			    latency, parent->lgrp_latency);
    959 #endif	/* DEBUG */
    960 		/*
    961 		 * As we work our way from the old leaf to the root lgroup,
    962 		 * new leaf resources should go in between two lgroups or into
    963 		 * one of the parent lgroups somewhere along the line
    964 		 */
    965 		if (latency < parent->lgrp_latency) {
    966 			lgrp_t	*intermed;
    967 
    968 			/*
    969 			 * New leaf resources should go in between current
    970 			 * child and parent
    971 			 */
    972 #ifdef	DEBUG
    973 			if (lgrp_topo_debug > 0)
    974 				prom_printf("lgrp_lineage_add: "
    975 				    "latency < parent latency\n");
    976 #endif	/* DEBUG */
    977 
    978 			/*
    979 			 * Create lgroup with desired resources and insert it
    980 			 * between child and parent
    981 			 */
    982 			lgrp_rsets_copy(child->lgrp_set, rset);
    983 			lgrp_rsets_add(newleaf->lgrp_set, rset);
    984 			if (nlevels >= lgrp_topo_levels) {
    985 				if (parent == lgrp_root)
    986 					break;
    987 
    988 #ifdef	DEBUG
    989 				if (lgrp_topo_debug > 0) {
    990 					prom_printf("lgrp_lineage_add: "
    991 					    "replaced parent lgrp %d at 0x%p"
    992 					    " for lgrp %d\n",
    993 					    parent->lgrp_id, (void *)parent,
    994 					    child->lgrp_id);
    995 					lgrp_rsets_print("old parent"
    996 					    " resources:", parent->lgrp_set);
    997 					lgrp_rsets_print("new parent "
    998 					    "resources:", rset);
    999 				}
   1000 #endif	/* DEBUG */
   1001 				/*
   1002 				 * Replace contents of parent with new
   1003 				 * leaf + child resources since new leaf is
   1004 				 * closer and shift its parent's resources to
   1005 				 * its parent, etc. until root lgroup reached
   1006 				 */
   1007 				lgrp_rsets_replace(rset, latency, parent, 1);
   1008 				if (*changed)
   1009 					klgrpset_or(*changed, parent->lgrp_id);
   1010 				total++;
   1011 				proprogate++;
   1012 			} else {
   1013 				total += lgrp_new_parent(child, latency, rset,
   1014 				    &changes);
   1015 				intermed = child->lgrp_parent;
   1016 				klgrpset_add(collapse, intermed->lgrp_id);
   1017 				if (changed)
   1018 					klgrpset_or(*changed, changes);
   1019 				child = intermed;
   1020 				proprogate++;
   1021 #ifdef	DEBUG
   1022 				if (lgrp_topo_debug > 0) {
   1023 					prom_printf("lgrp_lineage_add: new "
   1024 					    "parent lgrp %d at 0x%p for "
   1025 					    "lgrp %d\n", intermed->lgrp_id,
   1026 					    (void *)intermed, child->lgrp_id);
   1027 					lgrp_rsets_print("new parent "
   1028 					    "resources:", rset);
   1029 				}
   1030 #endif	/* DEBUG */
   1031 				continue;
   1032 			}
   1033 
   1034 		} else if (latency == parent->lgrp_latency) {
   1035 			/*
   1036 			 * New leaf resources should go into parent
   1037 			 */
   1038 #ifdef	DEBUG
   1039 			if (lgrp_topo_debug > 0)
   1040 				prom_printf("lgrp_lineage_add: latency == "
   1041 				    "parent latency\n");
   1042 #endif	/* DEBUG */
   1043 
   1044 			/*
   1045 			 * It's already there, so don't need to do anything.
   1046 			 */
   1047 			if (lgrp_rsets_member_all(parent->lgrp_set,
   1048 			    newleaf->lgrp_id))
   1049 				break;
   1050 
   1051 			total += lgrp_proprogate(newleaf, child, latency,
   1052 			    &changes);
   1053 			parent = child->lgrp_parent;
   1054 			klgrpset_add(collapse, parent->lgrp_id);
   1055 			if (changed)
   1056 				klgrpset_or(*changed, changes);
   1057 
   1058 			proprogate++;
   1059 		}
   1060 
   1061 		child = parent;
   1062 		parent = parent->lgrp_parent;
   1063 	} while (parent != NULL);
   1064 
   1065 	/*
   1066 	 * Consolidate any duplicate lgroups of ones just changed
   1067 	 * Assume that there were no duplicates before last round of changes
   1068 	 */
   1069 #ifdef	DEBUG
   1070 	if (lgrp_topo_debug > 1)
   1071 		prom_printf("lgrp_lineage_add: collapsing dups....\n");
   1072 #endif	/* DEBUG */
   1073 
   1074 	total += lgrp_collapse_dups(collapse, lgrp_collapse_equidist,
   1075 	    &changes);
   1076 	if (changed)
   1077 		klgrpset_or(*changed, changes);
   1078 
   1079 #ifdef	DEBUG
   1080 	if (lgrp_topo_debug > 1 && changed)
   1081 		prom_printf("lgrp_lineage_add: changed %d lgrps: 0x%llx\n",
   1082 		    total, (u_longlong_t)*changed);
   1083 #endif	/* DEBUG */
   1084 
   1085 	return (total);
   1086 }
   1087 
   1088 
   1089 /*
   1090  * Add leaf lgroup to lgroup topology
   1091  */
   1092 int
   1093 lgrp_leaf_add(lgrp_t *leaf, lgrp_t **lgrps, int lgrp_count,
   1094     klgrpset_t *changed)
   1095 {
   1096 	klgrpset_t	changes;
   1097 	int		count;
   1098 	int		i;
   1099 	int		latency;
   1100 
   1101 	ASSERT(MUTEX_HELD(&cpu_lock) || curthread->t_preempt > 0 ||
   1102 	    !lgrp_initialized);
   1103 
   1104 #ifdef	DEBUG
   1105 	if (lgrp_topo_debug > 1)
   1106 		prom_printf("\nlgrp_leaf_add(0x%p[%d],0x%p,%d,0x%p)\n",
   1107 		    (void *)leaf, leaf->lgrp_id, (void *)lgrps, lgrp_count,
   1108 		    (void *)changed);
   1109 #endif	/* DEBUG */
   1110 
   1111 	count = 0;
   1112 	if (changed)
   1113 		klgrpset_clear(*changed);
   1114 
   1115 	/*
   1116 	 * Initialize parent of leaf lgroup to root
   1117 	 */
   1118 	if (leaf->lgrp_parent == NULL) {
   1119 		leaf->lgrp_parent = lgrp_root;
   1120 		lgrp_root->lgrp_childcnt++;
   1121 		klgrpset_add(lgrp_root->lgrp_children, leaf->lgrp_id);
   1122 
   1123 		klgrpset_or(lgrp_root->lgrp_leaves, leaf->lgrp_leaves);
   1124 		lgrp_rsets_add(leaf->lgrp_set, lgrp_root->lgrp_set);
   1125 
   1126 #ifdef	DEBUG
   1127 		if (lgrp_topo_debug > 1)
   1128 			lgrp_rsets_print("lgrp_leaf_add: root lgrp resources",
   1129 			    lgrp_root->lgrp_set);
   1130 #endif	/* DEBUG */
   1131 
   1132 		if (changed) {
   1133 			klgrpset_add(*changed, lgrp_root->lgrp_id);
   1134 			klgrpset_add(*changed, leaf->lgrp_id);
   1135 		}
   1136 		count += 2;
   1137 	}
   1138 
   1139 	/*
   1140 	 * Can't add leaf lgroup to rest of topology (and vice versa) unless
   1141 	 * latency for it is available
   1142 	 */
   1143 	latency = lgrp_plat_latency(leaf->lgrp_plathand, leaf->lgrp_plathand);
   1144 	if (latency == 0) {
   1145 #ifdef	DEBUG
   1146 		if (lgrp_topo_debug > 1 && changed)
   1147 			prom_printf("lgrp_leaf_add: changed %d lgrps: 0x%llx\n",
   1148 			    count, (u_longlong_t)*changed);
   1149 #endif	/* DEBUG */
   1150 		return (count);
   1151 	}
   1152 
   1153 	/*
   1154 	 * Make sure that root and leaf lgroup latencies are set
   1155 	 */
   1156 	lgrp_root->lgrp_latency = lgrp_plat_latency(lgrp_root->lgrp_plathand,
   1157 	    lgrp_root->lgrp_plathand);
   1158 	leaf->lgrp_latency = latency;
   1159 
   1160 	/*
   1161 	 * Add leaf to lineage of other leaves and vice versa
   1162 	 * since leaves come into existence at different times
   1163 	 */
   1164 	for (i = 0; i < lgrp_count; i++) {
   1165 		lgrp_t		*lgrp;
   1166 
   1167 		lgrp = lgrps[i];
   1168 
   1169 		/*
   1170 		 * Skip non-existent lgroups, new leaf lgroup, and
   1171 		 * non-leaf lgroups
   1172 		 */
   1173 		if (!LGRP_EXISTS(lgrp) || lgrp == leaf ||
   1174 		    lgrp->lgrp_childcnt != 0) {
   1175 #ifdef	DEBUG
   1176 			if (lgrp_topo_debug > 1)
   1177 				prom_printf("lgrp_leaf_add: skip "
   1178 				    "lgrp %d at 0x%p\n",
   1179 				    lgrp->lgrp_id, (void *)lgrp);
   1180 #endif	/* DEBUG */
   1181 			continue;
   1182 		}
   1183 
   1184 #ifdef	DEBUG
   1185 		if (lgrp_topo_debug > 0)
   1186 			prom_printf("lgrp_leaf_add: lgrp %d (0x%p) =>"
   1187 			    " lgrp %d (0x%p)\n",
   1188 			    leaf->lgrp_id, (void *)leaf, lgrp->lgrp_id,
   1189 			    (void *)lgrp);
   1190 #endif	/* DEBUG */
   1191 
   1192 		count += lgrp_lineage_add(leaf, lgrp, &changes);
   1193 		if (changed)
   1194 			klgrpset_or(*changed, changes);
   1195 
   1196 		count += lgrp_lineage_add(lgrp, leaf, &changes);
   1197 		if (changed)
   1198 			klgrpset_or(*changed, changes);
   1199 	}
   1200 
   1201 #ifdef	DEBUG
   1202 	if (lgrp_topo_debug > 1 && changed)
   1203 		prom_printf("lgrp_leaf_add: changed %d lgrps: 0x%llx\n",
   1204 		    count, (u_longlong_t)*changed);
   1205 #endif	/* DEBUG */
   1206 
   1207 	return (count);
   1208 }
   1209 
   1210 
   1211 /*
   1212  * Remove resources of leaf from lgroup hierarchy
   1213  */
   1214 int
   1215 lgrp_leaf_delete(lgrp_t *leaf, lgrp_t **lgrps, int lgrp_count,
   1216     klgrpset_t *changed)
   1217 {
   1218 	klgrpset_t	changes;
   1219 	klgrpset_t	collapse;
   1220 	int		count;
   1221 	int		i;
   1222 	lgrp_t		*lgrp;
   1223 
   1224 	ASSERT(MUTEX_HELD(&cpu_lock) || curthread->t_preempt > 0 ||
   1225 	    !lgrp_initialized);
   1226 
   1227 	count = 0;
   1228 	klgrpset_clear(collapse);
   1229 	if (changed)
   1230 		klgrpset_clear(*changed);
   1231 
   1232 	/*
   1233 	 * Nothing to do if no leaf given
   1234 	 */
   1235 	if (leaf == NULL)
   1236 		return (0);
   1237 
   1238 #ifdef	DEBUG
   1239 	if (lgrp_topo_debug > 0)
   1240 		prom_printf("lgrp_leaf_delete(0x%p[%d],0x%p,%d,0x%p)\n",
   1241 		    (void *)leaf, leaf->lgrp_id, (void *)lgrps, lgrp_count,
   1242 		    (void *)changed);
   1243 #endif	/* DEBUG */
   1244 
   1245 	/*
   1246 	 * Remove leaf from any lgroups containing its resources
   1247 	 */
   1248 	for (i = 0; i < lgrp_count; i++) {
   1249 		lgrp = lgrps[i];
   1250 		if (lgrp == NULL || lgrp->lgrp_id == LGRP_NONE ||
   1251 		    !lgrp_rsets_member(lgrp->lgrp_set, leaf->lgrp_id))
   1252 			continue;
   1253 
   1254 #ifdef	DEBUG
   1255 		if (lgrp_topo_debug > 0)
   1256 			prom_printf("lgrp_leaf_delete: remove leaf from"
   1257 			    " lgrp %d at %p\n", lgrp->lgrp_id, (void *)lgrp);
   1258 #endif	/* DEBUG */
   1259 
   1260 		lgrp_rsets_delete(lgrp, leaf->lgrp_id, 0);
   1261 		klgrpset_del(lgrp->lgrp_leaves, leaf->lgrp_id);
   1262 
   1263 		klgrpset_add(collapse, lgrp->lgrp_id);
   1264 		count++;
   1265 	}
   1266 
   1267 	/*
   1268 	 * Remove leaf and its ancestors that don't have any other children
   1269 	 */
   1270 #ifdef	DEBUG
   1271 	if (lgrp_topo_debug > 1)
   1272 		prom_printf("lgrp_leaf_delete: remove leaf and ancestors\n");
   1273 #endif	/* DEBUG */
   1274 
   1275 	count += lgrp_ancestor_delete(leaf, &changes);
   1276 	klgrpset_or(collapse, changes);
   1277 	klgrpset_add(collapse, leaf->lgrp_id);
   1278 	count++;
   1279 	lgrp_destroy(leaf);
   1280 
   1281 	/*
   1282 	 * Consolidate any duplicate lgroups of ones just changed
   1283 	 * Assume that there were no duplicates before last round of changes
   1284 	 */
   1285 #ifdef	DEBUG
   1286 	if (lgrp_topo_debug > 1)
   1287 		prom_printf("lgrp_leaf_delete: collapsing dups\n");
   1288 #endif	/* DEBUG */
   1289 	count += lgrp_collapse_dups(collapse, lgrp_collapse_equidist,
   1290 	    &changes);
   1291 	klgrpset_or(collapse, changes);
   1292 	if (changed)
   1293 		klgrpset_copy(*changed, collapse);
   1294 
   1295 #ifdef	DEBUG
   1296 	if (lgrp_topo_debug > 1 && changed)
   1297 		prom_printf("lgrp_leaf_delete: changed %d lgrps: 0x%llx\n",
   1298 		    count, (u_longlong_t)*changed);
   1299 #endif	/* DEBUG */
   1300 
   1301 	return (count);
   1302 }
   1303 
   1304 
   1305 /*
   1306  * Flatten lgroup topology down to height specified
   1307  */
   1308 int
   1309 lgrp_topo_flatten(int levels, lgrp_t **lgrps, int lgrp_count,
   1310     klgrpset_t *changed)
   1311 {
   1312 	int	count;
   1313 	int	i;
   1314 	lgrp_t	*lgrp;
   1315 	lgrp_handle_t hdl;
   1316 
   1317 	/*
   1318 	 * Only flatten down to 2 level for now
   1319 	 */
   1320 	if (levels != 2)
   1321 		return (0);
   1322 
   1323 	/*
   1324 	 * Look for non-leaf lgroups to remove and leaf lgroups to reparent
   1325 	 */
   1326 	count = 0;
   1327 	for (i = 0; i <= lgrp_count; i++) {
   1328 		/*
   1329 		 * Skip non-existent lgroups and root
   1330 		 */
   1331 		lgrp = lgrps[i];
   1332 		if (!LGRP_EXISTS(lgrp))
   1333 			continue;
   1334 
   1335 		hdl = lgrp->lgrp_plathand;
   1336 
   1337 		if (lgrp == lgrp_root) {
   1338 			lgrp->lgrp_latency = lgrp_plat_latency(hdl, hdl);
   1339 			continue;
   1340 		}
   1341 
   1342 		if (lgrp->lgrp_childcnt > 0) {
   1343 			lgrp_t	*parent;
   1344 
   1345 			/*
   1346 			 * Remove non-leaf lgroup from lgroup topology
   1347 			 */
   1348 			parent = lgrp->lgrp_parent;
   1349 			if (changed) {
   1350 				klgrpset_add(*changed, lgrp->lgrp_id);
   1351 				klgrpset_add(*changed, parent->lgrp_id);
   1352 				count += 2;
   1353 			}
   1354 			if (parent) {
   1355 				klgrpset_del(parent->lgrp_children,
   1356 				    lgrp->lgrp_id);
   1357 				parent->lgrp_childcnt--;
   1358 			}
   1359 			lgrp_destroy(lgrp);
   1360 		} else if (lgrp->lgrp_parent != lgrp_root) {
   1361 			/*
   1362 			 * Reparent leaf lgroup to root
   1363 			 */
   1364 			if (changed) {
   1365 				klgrpset_add(*changed, lgrp_root->lgrp_id);
   1366 				klgrpset_add(*changed, lgrp->lgrp_id);
   1367 				count += 2;
   1368 			}
   1369 			lgrp->lgrp_parent = lgrp_root;
   1370 			klgrpset_add(lgrp_root->lgrp_children, lgrp->lgrp_id);
   1371 			lgrp_root->lgrp_childcnt++;
   1372 			klgrpset_add(lgrp_root->lgrp_leaves, lgrp->lgrp_id);
   1373 
   1374 			lgrp->lgrp_latency = lgrp_plat_latency(hdl, hdl);
   1375 		}
   1376 	}
   1377 
   1378 	return (count);
   1379 }
   1380 
   1381 
   1382 /*
   1383  * Return current height limit for lgroup topology
   1384  */
   1385 int
   1386 lgrp_topo_ht_limit(void)
   1387 {
   1388 	return (lgrp_topo_levels);
   1389 }
   1390 
   1391 
   1392 /*
   1393  * Return default height limit for lgroup topology
   1394  */
   1395 int
   1396 lgrp_topo_ht_limit_default(void)
   1397 {
   1398 	return (LGRP_TOPO_LEVELS);
   1399 }
   1400 
   1401 
   1402 /*
   1403  * Set height limit for lgroup topology
   1404  */
   1405 int
   1406 lgrp_topo_ht_limit_set(int ht)
   1407 {
   1408 	if (ht > LGRP_TOPO_LEVELS_MAX)
   1409 		lgrp_topo_levels = LGRP_TOPO_LEVELS_MAX;
   1410 	else
   1411 		lgrp_topo_levels = ht;
   1412 
   1413 	return (ht);
   1414 }
   1415 
   1416 
   1417 /*
   1418  * Update lgroup topology for any leaves that don't have their latency set
   1419  *
   1420  * This may happen on some machines when the lgroup platform support doesn't
   1421  * know the latencies between nodes soon enough to provide it when the
   1422  * resources are being added.  If the lgroup platform code needs to probe
   1423  * memory to determine the latencies between nodes, it must wait until the
   1424  * CPUs become active so at least one CPU in each node can probe memory in
   1425  * each node.
   1426  */
   1427 int
   1428 lgrp_topo_update(lgrp_t **lgrps, int lgrp_count, klgrpset_t *changed)
   1429 {
   1430 	klgrpset_t	changes;
   1431 	int		count;
   1432 	int		i;
   1433 	lgrp_t		*lgrp;
   1434 
   1435 	count = 0;
   1436 	if (changed)
   1437 		klgrpset_clear(*changed);
   1438 
   1439 	/*
   1440 	 * For UMA machines, make sure that root lgroup contains all
   1441 	 * resources.  The root lgrp should also name itself as its own leaf
   1442 	 */
   1443 	if (nlgrps == 1) {
   1444 		for (i = 0; i < LGRP_RSRC_COUNT; i++)
   1445 			klgrpset_add(lgrp_root->lgrp_set[i],
   1446 			    lgrp_root->lgrp_id);
   1447 		klgrpset_add(lgrp_root->lgrp_leaves, lgrp_root->lgrp_id);
   1448 		return (0);
   1449 	}
   1450 
   1451 	mutex_enter(&cpu_lock);
   1452 	pause_cpus(NULL);
   1453 
   1454 	/*
   1455 	 * Look for any leaf lgroup without its latency set, finish adding it
   1456 	 * to the lgroup topology assuming that it exists and has the root
   1457 	 * lgroup as its parent, and update the memory nodes of all lgroups
   1458 	 * that have it as a memory resource.
   1459 	 */
   1460 	for (i = 0; i < lgrp_count; i++) {
   1461 		lgrp = lgrps[i];
   1462 
   1463 		/*
   1464 		 * Skip non-existent and non-leaf lgroups and any lgroup
   1465 		 * with its latency set already
   1466 		 */
   1467 		if (lgrp == NULL || lgrp->lgrp_id == LGRP_NONE ||
   1468 		    lgrp->lgrp_childcnt != 0 || lgrp->lgrp_latency != 0)
   1469 			continue;
   1470 
   1471 #ifdef	DEBUG
   1472 		if (lgrp_topo_debug > 1) {
   1473 			prom_printf("\nlgrp_topo_update: updating lineage "
   1474 			    "of lgrp %d at 0x%p\n", lgrp->lgrp_id,
   1475 			    (void *)lgrp);
   1476 		}
   1477 #endif	/* DEBUG */
   1478 
   1479 		count += lgrp_leaf_add(lgrp, lgrps, lgrp_count, &changes);
   1480 		if (changed)
   1481 			klgrpset_or(*changed, changes);
   1482 
   1483 		if (!klgrpset_isempty(changes))
   1484 			(void) lgrp_mnode_update(changes, NULL);
   1485 
   1486 #ifdef	DEBUG
   1487 		if (lgrp_topo_debug > 1 && changed)
   1488 			prom_printf("lgrp_topo_update: changed %d lgrps: "
   1489 			    "0x%llx\n",
   1490 			    count, (u_longlong_t)*changed);
   1491 #endif	/* DEBUG */
   1492 	}
   1493 
   1494 	if (lgrp_topo_levels < LGRP_TOPO_LEVELS && lgrp_topo_levels == 2) {
   1495 		count += lgrp_topo_flatten(2, lgrps, lgrp_count, changed);
   1496 		(void) lpl_topo_flatten(2);
   1497 	}
   1498 
   1499 	start_cpus();
   1500 	mutex_exit(&cpu_lock);
   1501 
   1502 	return (count);
   1503 }
   1504 
   1505 #ifdef	DEBUG
   1506 void
   1507 lgrp_print(lgrp_t *lgrp)
   1508 {
   1509 	lgrp_t	*parent;
   1510 
   1511 	prom_printf("LGRP %d", lgrp->lgrp_id);
   1512 	if (lgrp->lgrp_childcnt == 0)
   1513 		prom_printf(" (plathand %p)\n",
   1514 		    (void *)lgrp->lgrp_plathand);
   1515 	else
   1516 		prom_printf("\n");
   1517 
   1518 	prom_printf("\tlatency %d\n", lgrp->lgrp_latency);
   1519 
   1520 	lgrp_rsets_print("\tresources", lgrp->lgrp_set);
   1521 
   1522 	parent = lgrp->lgrp_parent;
   1523 	prom_printf("\tparent 0x%p", (void *)parent);
   1524 	if (parent)
   1525 		prom_printf("[%d]\n", parent->lgrp_id);
   1526 	else
   1527 		prom_printf("\n");
   1528 
   1529 	prom_printf("\tchild count %d, children ", lgrp->lgrp_childcnt);
   1530 	klgrpset_print(lgrp->lgrp_children);
   1531 
   1532 	prom_printf("\tleaves ");
   1533 	klgrpset_print(lgrp->lgrp_leaves);
   1534 }
   1535 
   1536 
   1537 void
   1538 lgrp_topo_print(lgrp_t **lgrps, int lgrp_max)
   1539 {
   1540 	klgrpset_t	siblings;
   1541 
   1542 	lgrp_print(lgrp_root);
   1543 	siblings = lgrp_root->lgrp_children;
   1544 	while (!klgrpset_isempty(siblings)) {
   1545 		klgrpset_t	children;
   1546 		int		i;
   1547 
   1548 		klgrpset_clear(children);
   1549 		for (i = 0; i <= lgrp_max; i++) {
   1550 			lgrp_t	*lgrp;
   1551 
   1552 			lgrp = lgrps[i];
   1553 			if (lgrp == NULL || !klgrpset_ismember(siblings, i))
   1554 				continue;
   1555 			lgrp_print(lgrp);
   1556 			klgrpset_or(children, lgrp->lgrp_children);
   1557 		}
   1558 		klgrpset_copy(siblings, children);
   1559 	}
   1560 }
   1561 #endif	/* DEBUG */
   1562