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.
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.
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]
22 * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
29 #include <sys/cpupart.h>
31 #include <sys/promif.h>
32 #include <sys/types.h>
35 #define LGRP_TOPO_LEVELS 4 /* default height limit */
36 #define LGRP_TOPO_LEVELS_MAX 4 /* max height limit */
40 * Only collapse lgroups which have same latency (and resources)
42 int lgrp_collapse_equidist
= 1;
44 int lgrp_collapse_off
= 1; /* disable collapsing of duplicates */
47 * Height to limit lgroup topology
49 unsigned int lgrp_topo_levels
= LGRP_TOPO_LEVELS
;
51 int lgrp_split_off
= 1; /* disable splitting lgroups */
57 * - >0: on and bigger means more
59 int lgrp_topo_debug
= 0;
63 klgrpset_print(klgrpset_t lgrpset
)
68 prom_printf("0x%llx(", (u_longlong_t
)lgrpset
);
69 for (i
= 0; i
<= lgrp_alloc_max
; i
++)
70 if (klgrpset_ismember(lgrpset
, i
))
71 prom_printf("%d ", i
);
77 lgrp_rsets_print(char *string
, klgrpset_t
*rsets
)
81 prom_printf("%s\n", string
);
82 for (i
= 0; i
< LGRP_RSRC_COUNT
; i
++)
83 klgrpset_print(rsets
[i
]);
89 * Add "from" lgroup resources to "to" lgroup resources
92 lgrp_rsets_add(klgrpset_t
*from
, klgrpset_t
*to
)
96 for (i
= 0; i
< LGRP_RSRC_COUNT
; i
++)
97 klgrpset_or(to
[i
], from
[i
]);
102 * Copy "from" lgroup resources to "to" lgroup resources
105 lgrp_rsets_copy(klgrpset_t
*from
, klgrpset_t
*to
)
109 for (i
= 0; i
< LGRP_RSRC_COUNT
; i
++)
115 * Delete given lgroup ID from lgroup resource set of specified lgroup
116 * and its ancestors if "follow_parent" is set
119 lgrp_rsets_delete(lgrp_t
*lgrp
, lgrp_id_t lgrpid
, int follow_parent
)
123 while (lgrp
!= NULL
) {
124 for (i
= 0; i
< LGRP_RSRC_COUNT
; i
++)
125 klgrpset_del(lgrp
->lgrp_set
[i
], lgrpid
);
128 lgrp
= lgrp
->lgrp_parent
;
134 * Return whether given lgroup resource set empty
137 lgrp_rsets_empty(klgrpset_t
*rset
)
141 for (i
= 0; i
< LGRP_RSRC_COUNT
; i
++)
142 if (!klgrpset_isempty(rset
[i
]))
150 * Return whether given lgroup resource sets are same
153 lgrp_rsets_equal(klgrpset_t
*rset1
, klgrpset_t
*rset2
)
157 for (i
= 0; i
< LGRP_RSRC_COUNT
; i
++)
158 if (rset1
[i
] != rset2
[i
])
166 * Return whether specified lgroup ID is in given lgroup resource set
169 lgrp_rsets_member(klgrpset_t
*rset
, lgrp_id_t lgrpid
)
173 for (i
= 0; i
< LGRP_RSRC_COUNT
; i
++)
174 if (klgrpset_ismember(rset
[i
], lgrpid
))
182 * Return whether specified lgroup ID is in all lgroup resources
185 lgrp_rsets_member_all(klgrpset_t
*rset
, lgrp_id_t lgrpid
)
189 for (i
= 0; i
< LGRP_RSRC_COUNT
; i
++)
190 if (!klgrpset_ismember(rset
[i
], lgrpid
))
198 * Replace resources for given lgroup with specified resources at given
199 * latency and shift its old resources to its parent and its parent's resources
200 * to its parent, etc. until root lgroup reached
203 lgrp_rsets_replace(klgrpset_t
*rset
, int latency
, lgrp_t
*lgrp
, int shift
)
208 klgrpset_t rset_new
[LGRP_RSRC_COUNT
];
209 klgrpset_t rset_saved
[LGRP_RSRC_COUNT
];
213 lgrp_rsets_copy(rset
, rset_saved
);
214 while (cur
&& cur
!= lgrp_root
) {
216 * Save current resources and latency to insert in parent and
217 * then replace with new resources and latency
219 lgrp_rsets_copy(rset_saved
, rset_new
);
220 lgrp_rsets_copy(cur
->lgrp_set
, rset_saved
);
221 lgrp_rsets_copy(rset_new
, cur
->lgrp_set
);
224 lat_saved
= cur
->lgrp_latency
;
225 cur
->lgrp_latency
= lat_new
;
228 cur
= cur
->lgrp_parent
;
234 * Set "to" lgroup resource set with given lgroup ID
237 lgrp_rsets_set(klgrpset_t
*to
, lgrp_id_t lgrpid
)
242 klgrpset_clear(from
);
243 klgrpset_add(from
, lgrpid
);
244 for (i
= 0; i
< LGRP_RSRC_COUNT
; i
++) {
245 klgrpset_clear(to
[i
]);
246 klgrpset_or(to
[i
], from
);
252 * Delete any ancestors of given child lgroup which don't have any other
256 lgrp_ancestor_delete(lgrp_t
*child
, klgrpset_t
*changed
)
264 if (lgrp_topo_debug
> 1) {
265 prom_printf("lgrp_ancestor_delete(0x%p[%d],0x%p)\n",
266 (void *)child
, child
->lgrp_id
, (void *)changed
);
272 klgrpset_clear(*changed
);
275 * Visit ancestors, decrement child count for each, and remove any
276 * that don't have any children left until we reach an ancestor that
277 * has multiple children
280 parent
= child
->lgrp_parent
;
281 lgrpid
= current
->lgrp_id
;
282 while (parent
!= NULL
) {
284 if (lgrp_topo_debug
> 1)
285 prom_printf("lgrp_ancestor_delete: parent %d,"
287 parent
->lgrp_id
, lgrpid
);
290 klgrpset_del(parent
->lgrp_leaves
, lgrpid
);
291 klgrpset_del(parent
->lgrp_children
, lgrpid
);
292 parent
->lgrp_childcnt
--;
294 klgrpset_add(*changed
, parent
->lgrp_id
);
296 if (parent
->lgrp_childcnt
!= 0)
300 parent
= current
->lgrp_parent
;
301 lgrpid
= current
->lgrp_id
;
304 if (lgrp_topo_debug
> 0)
305 prom_printf("lgrp_ancestor_delete: destroy"
306 " lgrp %d at 0x%p\n",
307 current
->lgrp_id
, (void *)current
);
309 lgrp_destroy(current
);
313 if (lgrp_topo_debug
> 1 && changed
)
314 prom_printf("lgrp_ancestor_delete: changed %d lgrps: 0x%llx\n",
315 count
, (u_longlong_t
)*changed
);
323 * Consolidate lgrp1 into lgrp2
326 lgrp_consolidate(lgrp_t
*lgrp1
, lgrp_t
*lgrp2
, klgrpset_t
*changed
)
335 * Leaf lgroups should never need to be consolidated
337 if (lgrp1
== NULL
|| lgrp2
== NULL
|| lgrp1
->lgrp_childcnt
< 1 ||
338 lgrp2
->lgrp_childcnt
< 1)
342 if (lgrp_topo_debug
> 0)
343 prom_printf("lgrp_consolidate(0x%p[%d],0x%p[%d],0x%p)\n",
344 (void *)lgrp1
, lgrp1
->lgrp_id
, (void *)lgrp2
,
345 lgrp2
->lgrp_id
, (void *)changed
);
350 klgrpset_clear(*changed
);
353 * Lgroup represents resources within certain latency, so need to keep
354 * biggest latency value of lgroups being consolidated
356 if (lgrp1
->lgrp_latency
> lgrp2
->lgrp_latency
)
357 lgrp2
->lgrp_latency
= lgrp1
->lgrp_latency
;
360 * Delete ancestors of lgrp1 that don't have any other children
363 if (lgrp_topo_debug
> 1)
364 prom_printf("lgrp_consolidate: delete ancestors\n");
366 count
+= lgrp_ancestor_delete(lgrp1
, &changes
);
368 klgrpset_or(*changed
, changes
);
369 klgrpset_or(*changed
, lgrp1
->lgrp_id
);
374 * Reparent children lgroups of lgrp1 to lgrp2
376 for (i
= 0; i
<= lgrp_alloc_max
; i
++) {
377 if (i
== lgrp2
->lgrp_id
||
378 !klgrpset_ismember(lgrp1
->lgrp_children
, i
))
380 child
= lgrp_table
[i
];
381 if (!LGRP_EXISTS(child
))
384 if (lgrp_topo_debug
> 0)
385 prom_printf("lgrp_consolidate: reparent "
386 "lgrp %d to lgrp %d\n",
387 child
->lgrp_id
, lgrp2
->lgrp_id
);
389 klgrpset_or(lgrp2
->lgrp_leaves
, child
->lgrp_leaves
);
390 klgrpset_add(lgrp2
->lgrp_children
, child
->lgrp_id
);
391 lgrp2
->lgrp_childcnt
++;
392 child
->lgrp_parent
= lgrp2
;
394 klgrpset_add(*changed
, child
->lgrp_id
);
395 klgrpset_add(*changed
, lgrp2
->lgrp_id
);
401 * Proprogate leaves from lgrp2 to root
404 parent
= child
->lgrp_parent
;
405 while (parent
!= NULL
) {
406 klgrpset_or(parent
->lgrp_leaves
, child
->lgrp_leaves
);
408 klgrpset_add(*changed
, parent
->lgrp_id
);
411 parent
= parent
->lgrp_parent
;
415 if (lgrp_topo_debug
> 0)
416 prom_printf("lgrp_consolidate: destroy lgrp %d at 0x%p\n",
417 lgrp1
->lgrp_id
, (void *)lgrp1
);
418 if (lgrp_topo_debug
> 1 && changed
)
419 prom_printf("lgrp_consolidate: changed %d lgrps: 0x%llx\n",
420 count
, (u_longlong_t
)*changed
);
429 * Collapse duplicates of target lgroups given
432 lgrp_collapse_dups(klgrpset_t target_set
, int equidist_only
,
441 klgrpset_clear(*changed
);
443 if (lgrp_collapse_off
)
447 if (lgrp_topo_debug
> 0)
448 prom_printf("lgrp_collapse_dups(0x%llx)\n",
449 (u_longlong_t
)target_set
);
453 * Look for duplicates of each target lgroup
455 for (i
= 0; i
<= lgrp_alloc_max
; i
++) {
460 target
= lgrp_table
[i
];
463 * Skip to next lgroup if there isn't one here, this is root
464 * or leaf lgroup, or this isn't a target lgroup
466 if (!LGRP_EXISTS(target
) ||
467 target
== lgrp_root
|| target
->lgrp_childcnt
== 0 ||
468 !klgrpset_ismember(target_set
, target
->lgrp_id
))
472 * Find all lgroups with same resources and latency
475 if (lgrp_topo_debug
> 1)
476 prom_printf("lgrp_collapse_dups: find "
477 "dups of lgrp %d at 0x%p\n",
478 target
->lgrp_id
, (void *)target
);
481 for (j
= 0; j
<= lgrp_alloc_max
; j
++) {
484 lgrp
= lgrp_table
[j
];
487 * Skip lgroup if there isn't one here, this is root
488 * lgroup or leaf (which shouldn't have dups), or this
489 * lgroup doesn't have same resources
491 if (!LGRP_EXISTS(lgrp
) ||
492 lgrp
->lgrp_childcnt
== 0 ||
493 !lgrp_rsets_equal(lgrp
->lgrp_set
,
495 (lgrp
->lgrp_latency
!= target
->lgrp_latency
&&
500 * Keep first matching lgroup (but always keep root)
501 * and consolidate other duplicates into it
506 if (lgrp_topo_debug
> 1)
507 prom_printf("lgrp_collapse_dups: "
508 "keep lgrp %d at 0x%p\n",
509 keep
->lgrp_id
, (void *)keep
);
512 if (lgrp
== lgrp_root
) {
517 if (lgrp_topo_debug
> 0)
518 prom_printf("lgrp_collapse_dups:"
519 " consolidate lgrp %d at 0x%p"
520 " into lgrp %d at 0x%p\n",
521 lgrp
->lgrp_id
, (void *)lgrp
,
522 keep
->lgrp_id
, (void *)keep
);
524 count
+= lgrp_consolidate(lgrp
, keep
,
527 klgrpset_or(*changed
, changes
);
533 if (lgrp_topo_debug
> 1 && changed
)
534 prom_printf("lgrp_collapse_dups: changed %d lgrps: 0x%llx\n",
535 count
, (u_longlong_t
)*changed
);
543 * Create new parent lgroup with given latency and resources for
544 * specified child lgroup, and insert it into hierarchy
547 lgrp_new_parent(lgrp_t
*child
, int latency
, klgrpset_t
*rset
,
556 klgrpset_clear(*changed
);
559 * Create lgroup and set its latency and resources
562 new->lgrp_latency
= latency
;
563 lgrp_rsets_add(rset
, new->lgrp_set
);
566 * Insert new lgroup into hierarchy
568 old
= child
->lgrp_parent
;
569 new->lgrp_parent
= old
;
570 klgrpset_add(new->lgrp_children
, child
->lgrp_id
);
571 new->lgrp_childcnt
++;
572 klgrpset_add(new->lgrp_children
, child
->lgrp_id
);
573 klgrpset_copy(new->lgrp_leaves
, child
->lgrp_leaves
);
575 child
->lgrp_parent
= new;
577 klgrpset_del(old
->lgrp_children
, child
->lgrp_id
);
578 klgrpset_add(old
->lgrp_children
, new->lgrp_id
);
580 klgrpset_add(*changed
, old
->lgrp_id
);
585 klgrpset_add(*changed
, child
->lgrp_id
);
586 klgrpset_add(*changed
, new->lgrp_id
);
591 if (lgrp_topo_debug
> 1 && changed
)
592 prom_printf("lgrp_new_parent: changed %d lgrps: 0x%llx\n",
593 count
, (u_longlong_t
)*changed
);
601 * Proprogate resources of new leaf into parent lgroup of given child
604 lgrp_proprogate(lgrp_t
*newleaf
, lgrp_t
*child
, int latency
,
612 klgrpset_clear(*changed
);
614 if (child
== NULL
|| child
->lgrp_parent
== NULL
)
617 parent
= child
->lgrp_parent
;
618 klgrpset_or(parent
->lgrp_leaves
, child
->lgrp_leaves
);
620 klgrpset_add(*changed
, parent
->lgrp_id
);
624 * Don't proprogate new leaf resources to parent if it already
625 * contains these resources
627 if (lgrp_rsets_member_all(parent
->lgrp_set
, newleaf
->lgrp_id
)) {
629 if (lgrp_topo_debug
> 1 && changed
)
630 prom_printf("lgrp_proprogate: changed %d lgrps:"
632 count
, (u_longlong_t
)*changed
);
638 * Add leaf resources to parent lgroup
640 lgrp_rsets_add(newleaf
->lgrp_set
, parent
->lgrp_set
);
643 if (lgrp_topo_debug
> 1) {
644 prom_printf("lgrp_proprogate: newleaf %d(0x%p), "
645 "latency %d, child %d(0x%p), parent %d(0x%p)\n",
646 newleaf
->lgrp_id
, (void *)newleaf
, latency
, child
->lgrp_id
,
647 (void *)child
, parent
->lgrp_id
, (void *)parent
);
648 prom_printf("lgrp_proprogate: parent's leaves becomes 0x%llx\n",
649 (u_longlong_t
)parent
->lgrp_leaves
);
651 if (lgrp_topo_debug
> 0) {
652 prom_printf("lgrp_proprogate: adding to parent %d (0x%p)\n",
653 parent
->lgrp_id
, (void *)parent
);
654 lgrp_rsets_print("parent resources become:", parent
->lgrp_set
);
657 if (lgrp_topo_debug
> 2 && changed
)
658 prom_printf("lgrp_proprogate: changed %d lgrps: 0x%llx\n",
659 count
, (u_longlong_t
)*changed
);
668 * Split parent lgroup of given child if child's leaf decendant (oldleaf) has
669 * different latency to new leaf lgroup (newleaf) than leaf lgroups of given
673 lgrp_split(lgrp_t
*oldleaf
, lgrp_t
*newleaf
, lgrp_t
*child
,
684 klgrpset_clear(*changed
);
686 if (lgrp_split_off
|| newleaf
== NULL
|| child
== NULL
)
690 * Parent must have more than one child to have a child split from it
691 * and root lgroup contains all resources and never needs to be split
693 parent
= child
->lgrp_parent
;
694 if (parent
== NULL
|| parent
->lgrp_childcnt
< 2 || parent
== lgrp_root
)
698 if (lgrp_topo_debug
> 1)
699 prom_printf("lgrp_split(0x%p[%d],0x%p[%d],0x%p[%d],0x%p)\n",
700 (void *)oldleaf
, oldleaf
->lgrp_id
,
701 (void *)newleaf
, newleaf
->lgrp_id
,
702 (void *)child
, child
->lgrp_id
, (void *)changed
);
706 * Get latency between new leaf and old leaf whose lineage it is
709 latency
= lgrp_plat_latency(oldleaf
->lgrp_plathand
,
710 newleaf
->lgrp_plathand
);
713 * Check whether all sibling leaves of given child lgroup have same
714 * latency to new leaf
716 for (i
= 0; i
<= lgrp_alloc_max
; i
++) {
721 lgrp
= lgrp_table
[i
];
724 * Skip non-existent lgroups, old leaf, and any lgroups that
725 * don't have parent as common ancestor
727 if (!LGRP_EXISTS(lgrp
) || lgrp
== oldleaf
||
728 !klgrpset_ismember(parent
->lgrp_leaves
, lgrp
->lgrp_id
))
732 * Same latency, so skip
734 sibling_latency
= lgrp_plat_latency(lgrp
->lgrp_plathand
,
735 newleaf
->lgrp_plathand
);
737 if (lgrp_topo_debug
> 1)
738 prom_printf("lgrp_split: latency(%d,%d) %d,"
739 " latency(%d,%d) %d\n",
740 oldleaf
->lgrp_id
, newleaf
->lgrp_id
, latency
,
741 lgrp
->lgrp_id
, newleaf
->lgrp_id
, sibling_latency
);
743 if (sibling_latency
== latency
)
747 * Different latencies, so remove child from its parent and
748 * make new parent for old leaf with same latency and same
751 parent
->lgrp_childcnt
--;
752 klgrpset_del(parent
->lgrp_children
, child
->lgrp_id
);
753 klgrpset_del(parent
->lgrp_leaves
, oldleaf
->lgrp_id
);
754 grandparent
= parent
->lgrp_parent
;
756 grandparent
->lgrp_childcnt
++;
757 klgrpset_add(grandparent
->lgrp_children
,
761 klgrpset_add(*changed
, grandparent
->lgrp_id
);
763 child
->lgrp_parent
= grandparent
;
765 count
+= lgrp_new_parent(child
, parent
->lgrp_latency
,
766 parent
->lgrp_set
, &changes
);
768 klgrpset_or(*changed
, changes
);
770 klgrpset_add(*changed
, parent
->lgrp_id
);
771 klgrpset_add(*changed
, child
->lgrp_id
);
775 parent
= child
->lgrp_parent
;
777 if (lgrp_topo_debug
> 0) {
778 prom_printf("lgrp_split: new parent %d (0x%p) for"
780 parent
->lgrp_id
, (void *)parent
,
781 child
->lgrp_id
, (void *)child
);
782 lgrp_rsets_print("new parent resources:",
786 if (lgrp_topo_debug
> 1 && changed
)
787 prom_printf("lgrp_split: changed %d lgrps: 0x%llx\n",
788 count
, (u_longlong_t
)*changed
);
795 if (lgrp_topo_debug
> 1)
796 prom_printf("lgrp_split: no changes\n");
804 * Return height of lgroup topology from given lgroup to root
807 lgrp_topo_height(lgrp_t
*lgrp
)
811 if (!LGRP_EXISTS(lgrp
))
815 while (lgrp
!= NULL
) {
816 lgrp
= lgrp
->lgrp_parent
;
824 * Add resources of new leaf to old leaf's lineage
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
831 * - Latencies have been set for root and leaf lgroups
834 lgrp_lineage_add(lgrp_t
*newleaf
, lgrp_t
*oldleaf
, klgrpset_t
*changed
)
849 klgrpset_clear(*changed
);
851 if (newleaf
== NULL
|| oldleaf
== NULL
|| newleaf
== oldleaf
)
855 if (lgrp_topo_debug
> 0)
856 prom_printf("\nlgrp_lineage_add(0x%p[%d],0x%p[%d],0x%p)\n",
857 (void *)newleaf
, newleaf
->lgrp_id
,
858 (void *)oldleaf
, oldleaf
->lgrp_id
,
863 * Get latency between old and new leaves, so we can determine
864 * where the new leaf fits in the old leaf's lineage
866 latency
= lgrp_plat_latency(oldleaf
->lgrp_plathand
,
867 newleaf
->lgrp_plathand
);
870 * Determine height of lgroup topology from old leaf to root lgroup,
871 * so height of topology may be limited if necessary
873 nlevels
= lgrp_topo_height(oldleaf
);
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
);
882 * Can't add new leaf to old leaf's lineage if we haven't
883 * determined latency between them yet
889 parent
= child
->lgrp_parent
;
891 klgrpset_clear(collapse
);
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
901 klgrpset_t rset
[LGRP_RSRC_COUNT
];
904 if (lgrp_topo_debug
> 1)
905 prom_printf("lgrp_lineage_add: child %d (0x%p), parent"
907 child
->lgrp_id
, (void *)child
,
908 parent
->lgrp_id
, (void *)parent
);
912 * See whether parent lgroup needs to be split
914 * May need to split parent lgroup when it is ancestor to more
915 * than one leaf, but all its leaves don't have latency to new
916 * leaf within the parent lgroup's latency
917 * NOTE: Don't want to collapse this lgroup since we just split
920 count
= lgrp_split(oldleaf
, newleaf
, child
, &changes
);
923 if (lgrp_topo_debug
> 0)
924 prom_printf("lgrp_lineage_add: setting parent"
925 " for child %d from %d to %d\n",
926 child
->lgrp_id
, parent
->lgrp_id
,
927 child
->lgrp_parent
->lgrp_id
);
929 parent
= child
->lgrp_parent
;
932 klgrpset_or(*changed
, changes
);
936 * Already found where resources of new leaf belong in old
937 * leaf's lineage, so proprogate resources of new leaf up
938 * through rest of ancestors
941 total
+= lgrp_proprogate(newleaf
, child
, latency
,
944 klgrpset_or(*changed
, changes
);
946 parent
= child
->lgrp_parent
;
947 klgrpset_add(collapse
, parent
->lgrp_id
);
949 parent
= parent
->lgrp_parent
;
954 if (lgrp_topo_debug
> 1)
955 prom_printf("lgrp_lineage_add: latency 0x%x,"
956 " parent latency 0x%x\n",
957 latency
, parent
->lgrp_latency
);
960 * As we work our way from the old leaf to the root lgroup,
961 * new leaf resources should go in between two lgroups or into
962 * one of the parent lgroups somewhere along the line
964 if (latency
< parent
->lgrp_latency
) {
968 * New leaf resources should go in between current
972 if (lgrp_topo_debug
> 0)
973 prom_printf("lgrp_lineage_add: "
974 "latency < parent latency\n");
978 * Create lgroup with desired resources and insert it
979 * between child and parent
981 lgrp_rsets_copy(child
->lgrp_set
, rset
);
982 lgrp_rsets_add(newleaf
->lgrp_set
, rset
);
983 if (nlevels
>= lgrp_topo_levels
) {
986 if (lgrp_topo_debug
> 0) {
987 prom_printf("lgrp_lineage_add: nlevels "
988 "%d > lgrp_topo_levels %d\n",
989 nlevels
, lgrp_topo_levels
);
990 lgrp_rsets_print("rset ", rset
);
994 if (parent
== lgrp_root
) {
996 * Don't proprogate new leaf resources
997 * to parent, if it already contains
1000 if (lgrp_rsets_member_all(
1001 parent
->lgrp_set
, newleaf
->lgrp_id
))
1004 total
+= lgrp_proprogate(newleaf
, child
,
1010 if (lgrp_topo_debug
> 0) {
1011 prom_printf("lgrp_lineage_add: "
1012 "replaced parent lgrp %d at 0x%p"
1014 parent
->lgrp_id
, (void *)parent
,
1016 lgrp_rsets_print("old parent"
1017 " resources:", parent
->lgrp_set
);
1018 lgrp_rsets_print("new parent "
1019 "resources:", rset
);
1023 * Replace contents of parent with new
1024 * leaf + child resources since new leaf is
1025 * closer and shift its parent's resources to
1026 * its parent, etc. until root lgroup reached
1028 lgrp_rsets_replace(rset
, latency
, parent
, 1);
1030 klgrpset_or(*changed
, parent
->lgrp_id
);
1036 if (lgrp_topo_debug
> 0) {
1037 prom_printf("lgrp_lineage_add: "
1038 "lgrp_new_parent(0x%p,%d)\n",
1039 (void *)child
, latency
);
1040 lgrp_rsets_print("rset ", rset
);
1044 total
+= lgrp_new_parent(child
, latency
, rset
,
1046 intermed
= child
->lgrp_parent
;
1047 klgrpset_add(collapse
, intermed
->lgrp_id
);
1049 klgrpset_or(*changed
, changes
);
1053 if (lgrp_topo_debug
> 0) {
1054 prom_printf("lgrp_lineage_add: new "
1055 "parent lgrp %d at 0x%p for "
1056 "lgrp %d\n", intermed
->lgrp_id
,
1057 (void *)intermed
, child
->lgrp_id
);
1058 lgrp_rsets_print("new parent "
1059 "resources:", rset
);
1065 } else if (latency
== parent
->lgrp_latency
) {
1067 * New leaf resources should go into parent
1070 if (lgrp_topo_debug
> 0)
1071 prom_printf("lgrp_lineage_add: latency == "
1072 "parent latency\n");
1076 * It's already there, so don't need to do anything.
1078 if (lgrp_rsets_member_all(parent
->lgrp_set
,
1082 total
+= lgrp_proprogate(newleaf
, child
, latency
,
1084 parent
= child
->lgrp_parent
;
1085 klgrpset_add(collapse
, parent
->lgrp_id
);
1087 klgrpset_or(*changed
, changes
);
1093 parent
= parent
->lgrp_parent
;
1094 } while (parent
!= NULL
);
1097 * Consolidate any duplicate lgroups of ones just changed
1098 * Assume that there were no duplicates before last round of changes
1101 if (lgrp_topo_debug
> 1)
1102 prom_printf("lgrp_lineage_add: collapsing dups....\n");
1105 total
+= lgrp_collapse_dups(collapse
, lgrp_collapse_equidist
,
1108 klgrpset_or(*changed
, changes
);
1111 if (lgrp_topo_debug
> 1 && changed
)
1112 prom_printf("lgrp_lineage_add: changed %d lgrps: 0x%llx\n",
1113 total
, (u_longlong_t
)*changed
);
1121 * Add leaf lgroup to lgroup topology
1124 lgrp_leaf_add(lgrp_t
*leaf
, lgrp_t
**lgrps
, int lgrp_count
,
1125 klgrpset_t
*changed
)
1132 ASSERT(MUTEX_HELD(&cpu_lock
) || curthread
->t_preempt
> 0 ||
1136 if (lgrp_topo_debug
> 1)
1137 prom_printf("\nlgrp_leaf_add(0x%p[%d],0x%p,%d,0x%p)\n",
1138 (void *)leaf
, leaf
->lgrp_id
, (void *)lgrps
, lgrp_count
,
1144 klgrpset_clear(*changed
);
1147 * Initialize parent of leaf lgroup to root
1149 if (leaf
->lgrp_parent
== NULL
) {
1150 leaf
->lgrp_parent
= lgrp_root
;
1151 lgrp_root
->lgrp_childcnt
++;
1152 klgrpset_add(lgrp_root
->lgrp_children
, leaf
->lgrp_id
);
1154 klgrpset_or(lgrp_root
->lgrp_leaves
, leaf
->lgrp_leaves
);
1155 lgrp_rsets_add(leaf
->lgrp_set
, lgrp_root
->lgrp_set
);
1158 if (lgrp_topo_debug
> 1)
1159 lgrp_rsets_print("lgrp_leaf_add: root lgrp resources",
1160 lgrp_root
->lgrp_set
);
1164 klgrpset_add(*changed
, lgrp_root
->lgrp_id
);
1165 klgrpset_add(*changed
, leaf
->lgrp_id
);
1171 * Can't add leaf lgroup to rest of topology (and vice versa) unless
1172 * latency for it is available
1174 latency
= lgrp_plat_latency(leaf
->lgrp_plathand
, leaf
->lgrp_plathand
);
1177 if (lgrp_topo_debug
> 1 && changed
)
1178 prom_printf("lgrp_leaf_add: changed %d lgrps: 0x%llx\n",
1179 count
, (u_longlong_t
)*changed
);
1185 * Make sure that root and leaf lgroup latencies are set
1187 lgrp_root
->lgrp_latency
= lgrp_plat_latency(lgrp_root
->lgrp_plathand
,
1188 lgrp_root
->lgrp_plathand
);
1189 leaf
->lgrp_latency
= latency
;
1192 * Add leaf to lineage of other leaves and vice versa
1193 * since leaves come into existence at different times
1195 for (i
= 0; i
< lgrp_count
; i
++) {
1201 * Skip non-existent lgroups, new leaf lgroup, and
1204 if (!LGRP_EXISTS(lgrp
) || lgrp
== leaf
||
1205 lgrp
->lgrp_childcnt
!= 0) {
1207 if (lgrp_topo_debug
> 1)
1208 prom_printf("lgrp_leaf_add: skip "
1209 "lgrp %d at 0x%p\n",
1210 lgrp
->lgrp_id
, (void *)lgrp
);
1216 if (lgrp_topo_debug
> 0)
1217 prom_printf("lgrp_leaf_add: lgrp %d (0x%p) =>"
1218 " lgrp %d (0x%p)\n",
1219 leaf
->lgrp_id
, (void *)leaf
, lgrp
->lgrp_id
,
1223 count
+= lgrp_lineage_add(leaf
, lgrp
, &changes
);
1225 klgrpset_or(*changed
, changes
);
1227 count
+= lgrp_lineage_add(lgrp
, leaf
, &changes
);
1229 klgrpset_or(*changed
, changes
);
1233 if (lgrp_topo_debug
> 1 && changed
)
1234 prom_printf("lgrp_leaf_add: changed %d lgrps: 0x%llx\n",
1235 count
, (u_longlong_t
)*changed
);
1243 * Remove resources of leaf from lgroup hierarchy
1246 lgrp_leaf_delete(lgrp_t
*leaf
, lgrp_t
**lgrps
, int lgrp_count
,
1247 klgrpset_t
*changed
)
1250 klgrpset_t collapse
;
1255 ASSERT(MUTEX_HELD(&cpu_lock
) || curthread
->t_preempt
> 0 ||
1259 klgrpset_clear(collapse
);
1261 klgrpset_clear(*changed
);
1264 * Nothing to do if no leaf given
1270 if (lgrp_topo_debug
> 0)
1271 prom_printf("lgrp_leaf_delete(0x%p[%d],0x%p,%d,0x%p)\n",
1272 (void *)leaf
, leaf
->lgrp_id
, (void *)lgrps
, lgrp_count
,
1277 * Remove leaf from any lgroups containing its resources
1279 for (i
= 0; i
< lgrp_count
; i
++) {
1281 if (lgrp
== NULL
|| lgrp
->lgrp_id
== LGRP_NONE
||
1282 !lgrp_rsets_member(lgrp
->lgrp_set
, leaf
->lgrp_id
))
1286 if (lgrp_topo_debug
> 0)
1287 prom_printf("lgrp_leaf_delete: remove leaf from"
1288 " lgrp %d at %p\n", lgrp
->lgrp_id
, (void *)lgrp
);
1291 lgrp_rsets_delete(lgrp
, leaf
->lgrp_id
, 0);
1292 klgrpset_del(lgrp
->lgrp_leaves
, leaf
->lgrp_id
);
1294 klgrpset_add(collapse
, lgrp
->lgrp_id
);
1299 * Remove leaf and its ancestors that don't have any other children
1302 if (lgrp_topo_debug
> 1)
1303 prom_printf("lgrp_leaf_delete: remove leaf and ancestors\n");
1306 count
+= lgrp_ancestor_delete(leaf
, &changes
);
1307 klgrpset_or(collapse
, changes
);
1308 klgrpset_add(collapse
, leaf
->lgrp_id
);
1313 * Consolidate any duplicate lgroups of ones just changed
1314 * Assume that there were no duplicates before last round of changes
1317 if (lgrp_topo_debug
> 1)
1318 prom_printf("lgrp_leaf_delete: collapsing dups\n");
1320 count
+= lgrp_collapse_dups(collapse
, lgrp_collapse_equidist
,
1322 klgrpset_or(collapse
, changes
);
1324 klgrpset_copy(*changed
, collapse
);
1327 if (lgrp_topo_debug
> 1 && changed
)
1328 prom_printf("lgrp_leaf_delete: changed %d lgrps: 0x%llx\n",
1329 count
, (u_longlong_t
)*changed
);
1337 * Flatten lgroup topology down to height specified
1340 lgrp_topo_flatten(int levels
, lgrp_t
**lgrps
, int lgrp_count
,
1341 klgrpset_t
*changed
)
1349 * Only flatten down to 2 level for now
1355 * Look for non-leaf lgroups to remove and leaf lgroups to reparent
1358 for (i
= 0; i
<= lgrp_count
; i
++) {
1360 * Skip non-existent lgroups and root
1363 if (!LGRP_EXISTS(lgrp
))
1366 hdl
= lgrp
->lgrp_plathand
;
1368 if (lgrp
== lgrp_root
) {
1369 lgrp
->lgrp_latency
= lgrp_plat_latency(hdl
, hdl
);
1373 if (lgrp
->lgrp_childcnt
> 0) {
1377 * Remove non-leaf lgroup from lgroup topology
1379 parent
= lgrp
->lgrp_parent
;
1381 klgrpset_add(*changed
, lgrp
->lgrp_id
);
1382 klgrpset_add(*changed
, parent
->lgrp_id
);
1386 klgrpset_del(parent
->lgrp_children
,
1388 parent
->lgrp_childcnt
--;
1391 } else if (lgrp
->lgrp_parent
!= lgrp_root
) {
1393 * Reparent leaf lgroup to root
1396 klgrpset_add(*changed
, lgrp_root
->lgrp_id
);
1397 klgrpset_add(*changed
, lgrp
->lgrp_id
);
1400 lgrp
->lgrp_parent
= lgrp_root
;
1401 klgrpset_add(lgrp_root
->lgrp_children
, lgrp
->lgrp_id
);
1402 lgrp_root
->lgrp_childcnt
++;
1403 klgrpset_add(lgrp_root
->lgrp_leaves
, lgrp
->lgrp_id
);
1405 lgrp
->lgrp_latency
= lgrp_plat_latency(hdl
, hdl
);
1414 * Return current height limit for lgroup topology
1417 lgrp_topo_ht_limit(void)
1419 return (lgrp_topo_levels
);
1424 * Return default height limit for lgroup topology
1427 lgrp_topo_ht_limit_default(void)
1429 return (LGRP_TOPO_LEVELS
);
1434 * Set height limit for lgroup topology
1437 lgrp_topo_ht_limit_set(int ht
)
1439 if (ht
> LGRP_TOPO_LEVELS_MAX
)
1440 lgrp_topo_levels
= LGRP_TOPO_LEVELS_MAX
;
1442 lgrp_topo_levels
= ht
;
1449 * Update lgroup topology for any leaves that don't have their latency set
1451 * This may happen on some machines when the lgroup platform support doesn't
1452 * know the latencies between nodes soon enough to provide it when the
1453 * resources are being added. If the lgroup platform code needs to probe
1454 * memory to determine the latencies between nodes, it must wait until the
1455 * CPUs become active so at least one CPU in each node can probe memory in
1459 lgrp_topo_update(lgrp_t
**lgrps
, int lgrp_count
, klgrpset_t
*changed
)
1468 klgrpset_clear(*changed
);
1471 * For UMA machines, make sure that root lgroup contains all
1472 * resources. The root lgrp should also name itself as its own leaf
1475 for (i
= 0; i
< LGRP_RSRC_COUNT
; i
++)
1476 klgrpset_add(lgrp_root
->lgrp_set
[i
],
1477 lgrp_root
->lgrp_id
);
1478 klgrpset_add(lgrp_root
->lgrp_leaves
, lgrp_root
->lgrp_id
);
1482 mutex_enter(&cpu_lock
);
1483 pause_cpus(NULL
, NULL
);
1486 * Look for any leaf lgroup without its latency set, finish adding it
1487 * to the lgroup topology assuming that it exists and has the root
1488 * lgroup as its parent, and update the memory nodes of all lgroups
1489 * that have it as a memory resource.
1491 for (i
= 0; i
< lgrp_count
; i
++) {
1495 * Skip non-existent and non-leaf lgroups and any lgroup
1496 * with its latency set already
1498 if (lgrp
== NULL
|| lgrp
->lgrp_id
== LGRP_NONE
||
1499 lgrp
->lgrp_childcnt
!= 0 || lgrp
->lgrp_latency
!= 0)
1503 if (lgrp_topo_debug
> 1) {
1504 prom_printf("\nlgrp_topo_update: updating lineage "
1505 "of lgrp %d at 0x%p\n", lgrp
->lgrp_id
,
1510 count
+= lgrp_leaf_add(lgrp
, lgrps
, lgrp_count
, &changes
);
1512 klgrpset_or(*changed
, changes
);
1514 if (!klgrpset_isempty(changes
))
1515 (void) lgrp_mnode_update(changes
, NULL
);
1518 if (lgrp_topo_debug
> 1 && changed
)
1519 prom_printf("lgrp_topo_update: changed %d lgrps: "
1521 count
, (u_longlong_t
)*changed
);
1525 if (lgrp_topo_levels
< LGRP_TOPO_LEVELS
&& lgrp_topo_levels
== 2) {
1526 count
+= lgrp_topo_flatten(2, lgrps
, lgrp_count
, changed
);
1527 (void) lpl_topo_flatten(2);
1531 mutex_exit(&cpu_lock
);
1538 lgrp_print(lgrp_t
*lgrp
)
1542 prom_printf("LGRP %d", lgrp
->lgrp_id
);
1543 if (lgrp
->lgrp_childcnt
== 0)
1544 prom_printf(" (plathand %p)\n",
1545 (void *)lgrp
->lgrp_plathand
);
1549 prom_printf("\tlatency %d\n", lgrp
->lgrp_latency
);
1551 lgrp_rsets_print("\tresources", lgrp
->lgrp_set
);
1553 parent
= lgrp
->lgrp_parent
;
1554 prom_printf("\tparent 0x%p", (void *)parent
);
1556 prom_printf("[%d]\n", parent
->lgrp_id
);
1560 prom_printf("\tchild count %d, children ", lgrp
->lgrp_childcnt
);
1561 klgrpset_print(lgrp
->lgrp_children
);
1563 prom_printf("\tleaves ");
1564 klgrpset_print(lgrp
->lgrp_leaves
);
1569 lgrp_topo_print(lgrp_t
**lgrps
, int lgrp_max
)
1571 klgrpset_t siblings
;
1573 lgrp_print(lgrp_root
);
1574 siblings
= lgrp_root
->lgrp_children
;
1575 while (!klgrpset_isempty(siblings
)) {
1576 klgrpset_t children
;
1579 klgrpset_clear(children
);
1580 for (i
= 0; i
<= lgrp_max
; i
++) {
1584 if (lgrp
== NULL
|| !klgrpset_ismember(siblings
, i
))
1587 klgrpset_or(children
, lgrp
->lgrp_children
);
1589 klgrpset_copy(siblings
, children
);