xref: /illumos-gate/usr/src/uts/common/os/lgrp_topo.c (revision 581cede61ac9c14d8d4ea452562a567189eead78)
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