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