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