Merge commit '7e934d3acc051b7ee3ef0d11571fd1225800a607'
[unleashed.git] / kernel / os / lgrp_topo.c
blob49c5298bb7ce6c48c707bdad70eb59153193875d
1 /*
2 * CDDL HEADER START
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]
19 * CDDL HEADER END
22 * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
26 * lgroup topology
29 #include <sys/cpupart.h>
30 #include <sys/lgrp.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 */
53 #ifdef DEBUG
55 * Debugging output
56 * - 0: off
57 * - >0: on and bigger means more
59 int lgrp_topo_debug = 0;
62 void
63 klgrpset_print(klgrpset_t lgrpset)
65 int i;
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);
72 prom_printf(")\n");
76 void
77 lgrp_rsets_print(char *string, klgrpset_t *rsets)
79 int i;
81 prom_printf("%s\n", string);
82 for (i = 0; i < LGRP_RSRC_COUNT; i++)
83 klgrpset_print(rsets[i]);
85 #endif /* DEBUG */
89 * Add "from" lgroup resources to "to" lgroup resources
91 void
92 lgrp_rsets_add(klgrpset_t *from, klgrpset_t *to)
94 int i;
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
104 void
105 lgrp_rsets_copy(klgrpset_t *from, klgrpset_t *to)
107 int i;
109 for (i = 0; i < LGRP_RSRC_COUNT; i++)
110 to[i] = from[i];
115 * Delete given lgroup ID from lgroup resource set of specified lgroup
116 * and its ancestors if "follow_parent" is set
118 void
119 lgrp_rsets_delete(lgrp_t *lgrp, lgrp_id_t lgrpid, int follow_parent)
121 int i;
123 while (lgrp != NULL) {
124 for (i = 0; i < LGRP_RSRC_COUNT; i++)
125 klgrpset_del(lgrp->lgrp_set[i], lgrpid);
126 if (!follow_parent)
127 break;
128 lgrp = lgrp->lgrp_parent;
134 * Return whether given lgroup resource set empty
137 lgrp_rsets_empty(klgrpset_t *rset)
139 int i;
141 for (i = 0; i < LGRP_RSRC_COUNT; i++)
142 if (!klgrpset_isempty(rset[i]))
143 return (0);
145 return (1);
150 * Return whether given lgroup resource sets are same
153 lgrp_rsets_equal(klgrpset_t *rset1, klgrpset_t *rset2)
155 int i;
157 for (i = 0; i < LGRP_RSRC_COUNT; i++)
158 if (rset1[i] != rset2[i])
159 return (0);
161 return (1);
166 * Return whether specified lgroup ID is in given lgroup resource set
169 lgrp_rsets_member(klgrpset_t *rset, lgrp_id_t lgrpid)
171 int i;
173 for (i = 0; i < LGRP_RSRC_COUNT; i++)
174 if (klgrpset_ismember(rset[i], lgrpid))
175 return (1);
177 return (0);
182 * Return whether specified lgroup ID is in all lgroup resources
185 lgrp_rsets_member_all(klgrpset_t *rset, lgrp_id_t lgrpid)
187 int i;
189 for (i = 0; i < LGRP_RSRC_COUNT; i++)
190 if (!klgrpset_ismember(rset[i], lgrpid))
191 return (0);
193 return (1);
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
202 void
203 lgrp_rsets_replace(klgrpset_t *rset, int latency, lgrp_t *lgrp, int shift)
205 lgrp_t *cur;
206 int lat_new;
207 int lat_saved;
208 klgrpset_t rset_new[LGRP_RSRC_COUNT];
209 klgrpset_t rset_saved[LGRP_RSRC_COUNT];
211 cur = lgrp;
212 lat_saved = latency;
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);
223 lat_new = lat_saved;
224 lat_saved = cur->lgrp_latency;
225 cur->lgrp_latency = lat_new;
226 if (!shift)
227 break;
228 cur = cur->lgrp_parent;
234 * Set "to" lgroup resource set with given lgroup ID
236 void
237 lgrp_rsets_set(klgrpset_t *to, lgrp_id_t lgrpid)
239 klgrpset_t from;
240 int i;
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
253 * children
256 lgrp_ancestor_delete(lgrp_t *child, klgrpset_t *changed)
258 int count;
259 lgrp_t *current;
260 lgrp_id_t lgrpid;
261 lgrp_t *parent;
263 #ifdef DEBUG
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);
268 #endif /* DEBUG */
270 count = 0;
271 if (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
279 current = child;
280 parent = child->lgrp_parent;
281 lgrpid = current->lgrp_id;
282 while (parent != NULL) {
283 #ifdef DEBUG
284 if (lgrp_topo_debug > 1)
285 prom_printf("lgrp_ancestor_delete: parent %d,"
286 " current %d\n",
287 parent->lgrp_id, lgrpid);
288 #endif /* DEBUG */
290 klgrpset_del(parent->lgrp_leaves, lgrpid);
291 klgrpset_del(parent->lgrp_children, lgrpid);
292 parent->lgrp_childcnt--;
293 if (changed)
294 klgrpset_add(*changed, parent->lgrp_id);
295 count++;
296 if (parent->lgrp_childcnt != 0)
297 break;
299 current = parent;
300 parent = current->lgrp_parent;
301 lgrpid = current->lgrp_id;
303 #ifdef DEBUG
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);
308 #endif /* DEBUG */
309 lgrp_destroy(current);
312 #ifdef DEBUG
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);
316 #endif /* DEBUG */
318 return (count);
323 * Consolidate lgrp1 into lgrp2
326 lgrp_consolidate(lgrp_t *lgrp1, lgrp_t *lgrp2, klgrpset_t *changed)
328 klgrpset_t changes;
329 lgrp_t *child;
330 int count;
331 int i;
332 lgrp_t *parent;
335 * Leaf lgroups should never need to be consolidated
337 if (lgrp1 == NULL || lgrp2 == NULL || lgrp1->lgrp_childcnt < 1 ||
338 lgrp2->lgrp_childcnt < 1)
339 return (0);
341 #ifdef DEBUG
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);
346 #endif /* DEBUG */
348 count = 0;
349 if (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
362 #ifdef DEBUG
363 if (lgrp_topo_debug > 1)
364 prom_printf("lgrp_consolidate: delete ancestors\n");
365 #endif /* DEBUG */
366 count += lgrp_ancestor_delete(lgrp1, &changes);
367 if (changed) {
368 klgrpset_or(*changed, changes);
369 klgrpset_or(*changed, lgrp1->lgrp_id);
370 count++;
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))
379 continue;
380 child = lgrp_table[i];
381 if (!LGRP_EXISTS(child))
382 continue;
383 #ifdef DEBUG
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);
388 #endif /* DEBUG */
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;
393 if (changed) {
394 klgrpset_add(*changed, child->lgrp_id);
395 klgrpset_add(*changed, lgrp2->lgrp_id);
397 count += 2;
401 * Proprogate leaves from lgrp2 to root
403 child = lgrp2;
404 parent = child->lgrp_parent;
405 while (parent != NULL) {
406 klgrpset_or(parent->lgrp_leaves, child->lgrp_leaves);
407 if (changed)
408 klgrpset_add(*changed, parent->lgrp_id);
409 count++;
410 child = parent;
411 parent = parent->lgrp_parent;
414 #ifdef DEBUG
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);
421 #endif /* DEBUG */
423 lgrp_destroy(lgrp1);
425 return (count);
429 * Collapse duplicates of target lgroups given
432 lgrp_collapse_dups(klgrpset_t target_set, int equidist_only,
433 klgrpset_t *changed)
435 klgrpset_t changes;
436 int count;
437 int i;
439 count = 0;
440 if (changed)
441 klgrpset_clear(*changed);
443 if (lgrp_collapse_off)
444 return (0);
446 #ifdef DEBUG
447 if (lgrp_topo_debug > 0)
448 prom_printf("lgrp_collapse_dups(0x%llx)\n",
449 (u_longlong_t)target_set);
450 #endif /* DEBUG */
453 * Look for duplicates of each target lgroup
455 for (i = 0; i <= lgrp_alloc_max; i++) {
456 int j;
457 lgrp_t *keep;
458 lgrp_t *target;
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))
469 continue;
472 * Find all lgroups with same resources and latency
474 #ifdef DEBUG
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);
479 #endif /* DEBUG */
480 keep = NULL;
481 for (j = 0; j <= lgrp_alloc_max; j++) {
482 lgrp_t *lgrp;
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,
494 target->lgrp_set) ||
495 (lgrp->lgrp_latency != target->lgrp_latency &&
496 equidist_only))
497 continue;
500 * Keep first matching lgroup (but always keep root)
501 * and consolidate other duplicates into it
503 if (keep == NULL) {
504 keep = lgrp;
505 #ifdef DEBUG
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);
510 #endif /* DEBUG */
511 } else {
512 if (lgrp == lgrp_root) {
513 lgrp = keep;
514 keep = lgrp_root;
516 #ifdef DEBUG
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);
523 #endif /* DEBUG */
524 count += lgrp_consolidate(lgrp, keep,
525 &changes);
526 if (changed)
527 klgrpset_or(*changed, changes);
532 #ifdef DEBUG
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);
536 #endif /* DEBUG */
538 return (count);
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,
548 klgrpset_t *changed)
550 int count;
551 lgrp_t *new;
552 lgrp_t *old;
554 count = 0;
555 if (changed)
556 klgrpset_clear(*changed);
559 * Create lgroup and set its latency and resources
561 new = lgrp_create();
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;
576 if (old) {
577 klgrpset_del(old->lgrp_children, child->lgrp_id);
578 klgrpset_add(old->lgrp_children, new->lgrp_id);
579 if (changed)
580 klgrpset_add(*changed, old->lgrp_id);
581 count++;
584 if (changed) {
585 klgrpset_add(*changed, child->lgrp_id);
586 klgrpset_add(*changed, new->lgrp_id);
588 count += 2;
590 #ifdef DEBUG
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);
594 #endif /* DEBUG */
596 return (count);
601 * Proprogate resources of new leaf into parent lgroup of given child
604 lgrp_proprogate(lgrp_t *newleaf, lgrp_t *child, int latency,
605 klgrpset_t *changed)
607 int count;
608 lgrp_t *parent;
610 count = 0;
611 if (changed)
612 klgrpset_clear(*changed);
614 if (child == NULL || child->lgrp_parent == NULL)
615 return (0);
617 parent = child->lgrp_parent;
618 klgrpset_or(parent->lgrp_leaves, child->lgrp_leaves);
619 if (changed)
620 klgrpset_add(*changed, parent->lgrp_id);
621 count++;
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)) {
628 #ifdef DEBUG
629 if (lgrp_topo_debug > 1 && changed)
630 prom_printf("lgrp_proprogate: changed %d lgrps:"
631 " 0x%llx\n",
632 count, (u_longlong_t)*changed);
633 #endif /* DEBUG */
634 return (count);
638 * Add leaf resources to parent lgroup
640 lgrp_rsets_add(newleaf->lgrp_set, parent->lgrp_set);
642 #ifdef DEBUG
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);
661 #endif /* DEBUG */
663 return (count);
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
670 * child's siblings
673 lgrp_split(lgrp_t *oldleaf, lgrp_t *newleaf, lgrp_t *child,
674 klgrpset_t *changed)
676 klgrpset_t changes;
677 int count;
678 int i;
679 int latency;
680 lgrp_t *parent;
682 count = 0;
683 if (changed)
684 klgrpset_clear(*changed);
686 if (lgrp_split_off || newleaf == NULL || child == NULL)
687 return (0);
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)
695 return (0);
697 #ifdef DEBUG
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);
703 #endif /* DEBUG */
706 * Get latency between new leaf and old leaf whose lineage it is
707 * being added
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++) {
717 lgrp_t *grandparent;
718 lgrp_t *lgrp;
719 int sibling_latency;
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))
729 continue;
732 * Same latency, so skip
734 sibling_latency = lgrp_plat_latency(lgrp->lgrp_plathand,
735 newleaf->lgrp_plathand);
736 #ifdef DEBUG
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);
742 #endif /* DEBUG */
743 if (sibling_latency == latency)
744 continue;
747 * Different latencies, so remove child from its parent and
748 * make new parent for old leaf with same latency and same
749 * resources
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;
755 if (grandparent) {
756 grandparent->lgrp_childcnt++;
757 klgrpset_add(grandparent->lgrp_children,
758 child->lgrp_id);
759 count++;
760 if (changed)
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);
767 if (changed) {
768 klgrpset_or(*changed, changes);
770 klgrpset_add(*changed, parent->lgrp_id);
771 klgrpset_add(*changed, child->lgrp_id);
772 count += 2;
775 parent = child->lgrp_parent;
776 #ifdef DEBUG
777 if (lgrp_topo_debug > 0) {
778 prom_printf("lgrp_split: new parent %d (0x%p) for"
779 " lgrp %d (0x%p)\n",
780 parent->lgrp_id, (void *)parent,
781 child->lgrp_id, (void *)child);
782 lgrp_rsets_print("new parent resources:",
783 parent->lgrp_set);
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 */
791 return (count);
794 #ifdef DEBUG
795 if (lgrp_topo_debug > 1)
796 prom_printf("lgrp_split: no changes\n");
797 #endif /* DEBUG */
799 return (count);
804 * Return height of lgroup topology from given lgroup to root
807 lgrp_topo_height(lgrp_t *lgrp)
809 int nlevels;
811 if (!LGRP_EXISTS(lgrp))
812 return (0);
814 nlevels = 0;
815 while (lgrp != NULL) {
816 lgrp = lgrp->lgrp_parent;
817 nlevels++;
819 return (nlevels);
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
830 * added to it
831 * - Latencies have been set for root and leaf lgroups
834 lgrp_lineage_add(lgrp_t *newleaf, lgrp_t *oldleaf, klgrpset_t *changed)
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;
847 count = total = 0;
848 if (changed)
849 klgrpset_clear(*changed);
851 if (newleaf == NULL || oldleaf == NULL || newleaf == oldleaf)
852 return (0);
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 (void *)newleaf, newleaf->lgrp_id,
858 (void *)oldleaf, oldleaf->lgrp_id,
859 (void *)changed);
860 #endif /* DEBUG */
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);
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 */
882 * Can't add new leaf to old leaf's lineage if we haven't
883 * determined latency between them yet
885 if (latency == 0)
886 return (0);
888 child = oldleaf;
889 parent = child->lgrp_parent;
890 proprogate = 0;
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
898 * children
900 do {
901 klgrpset_t rset[LGRP_RSRC_COUNT];
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, (void *)child,
908 parent->lgrp_id, (void *)parent);
909 #endif /* DEBUG */
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
918 * it from parent
920 count = lgrp_split(oldleaf, newleaf, child, &changes);
921 if (count) {
922 #ifdef DEBUG
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);
928 #endif /* DEBUG */
929 parent = child->lgrp_parent;
930 total += count;
931 if (changed)
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
940 if (proprogate) {
941 total += lgrp_proprogate(newleaf, child, latency,
942 &changes);
943 if (changed)
944 klgrpset_or(*changed, changes);
946 parent = child->lgrp_parent;
947 klgrpset_add(collapse, parent->lgrp_id);
948 child = parent;
949 parent = parent->lgrp_parent;
950 continue;
953 #ifdef DEBUG
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);
958 #endif /* DEBUG */
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) {
965 lgrp_t *intermed;
968 * New leaf resources should go in between current
969 * child and parent
971 #ifdef DEBUG
972 if (lgrp_topo_debug > 0)
973 prom_printf("lgrp_lineage_add: "
974 "latency < parent latency\n");
975 #endif /* DEBUG */
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) {
985 #ifdef DEBUG
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);
992 #endif /* DEBUG */
994 if (parent == lgrp_root) {
996 * Don't proprogate new leaf resources
997 * to parent, if it already contains
998 * these resources
1000 if (lgrp_rsets_member_all(
1001 parent->lgrp_set, newleaf->lgrp_id))
1002 break;
1004 total += lgrp_proprogate(newleaf, child,
1005 latency, &changes);
1006 break;
1009 #ifdef DEBUG
1010 if (lgrp_topo_debug > 0) {
1011 prom_printf("lgrp_lineage_add: "
1012 "replaced parent lgrp %d at 0x%p"
1013 " for lgrp %d\n",
1014 parent->lgrp_id, (void *)parent,
1015 child->lgrp_id);
1016 lgrp_rsets_print("old parent"
1017 " resources:", parent->lgrp_set);
1018 lgrp_rsets_print("new parent "
1019 "resources:", rset);
1021 #endif /* DEBUG */
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);
1029 if (*changed)
1030 klgrpset_or(*changed, parent->lgrp_id);
1031 total++;
1032 proprogate++;
1033 } else {
1035 #ifdef DEBUG
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);
1042 #endif /* DEBUG */
1044 total += lgrp_new_parent(child, latency, rset,
1045 &changes);
1046 intermed = child->lgrp_parent;
1047 klgrpset_add(collapse, intermed->lgrp_id);
1048 if (changed)
1049 klgrpset_or(*changed, changes);
1050 child = intermed;
1051 proprogate++;
1052 #ifdef DEBUG
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);
1061 #endif /* DEBUG */
1062 continue;
1065 } else if (latency == parent->lgrp_latency) {
1067 * New leaf resources should go into parent
1069 #ifdef DEBUG
1070 if (lgrp_topo_debug > 0)
1071 prom_printf("lgrp_lineage_add: latency == "
1072 "parent latency\n");
1073 #endif /* DEBUG */
1076 * It's already there, so don't need to do anything.
1078 if (lgrp_rsets_member_all(parent->lgrp_set,
1079 newleaf->lgrp_id))
1080 break;
1082 total += lgrp_proprogate(newleaf, child, latency,
1083 &changes);
1084 parent = child->lgrp_parent;
1085 klgrpset_add(collapse, parent->lgrp_id);
1086 if (changed)
1087 klgrpset_or(*changed, changes);
1089 proprogate++;
1092 child = parent;
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
1100 #ifdef DEBUG
1101 if (lgrp_topo_debug > 1)
1102 prom_printf("lgrp_lineage_add: collapsing dups....\n");
1103 #endif /* DEBUG */
1105 total += lgrp_collapse_dups(collapse, lgrp_collapse_equidist,
1106 &changes);
1107 if (changed)
1108 klgrpset_or(*changed, changes);
1110 #ifdef DEBUG
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);
1114 #endif /* DEBUG */
1116 return (total);
1121 * Add leaf lgroup to lgroup topology
1124 lgrp_leaf_add(lgrp_t *leaf, lgrp_t **lgrps, int lgrp_count,
1125 klgrpset_t *changed)
1127 klgrpset_t changes;
1128 int count;
1129 int i;
1130 int latency;
1132 ASSERT(MUTEX_HELD(&cpu_lock) || curthread->t_preempt > 0 ||
1133 !lgrp_initialized);
1135 #ifdef DEBUG
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,
1139 (void *)changed);
1140 #endif /* DEBUG */
1142 count = 0;
1143 if (changed)
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);
1157 #ifdef DEBUG
1158 if (lgrp_topo_debug > 1)
1159 lgrp_rsets_print("lgrp_leaf_add: root lgrp resources",
1160 lgrp_root->lgrp_set);
1161 #endif /* DEBUG */
1163 if (changed) {
1164 klgrpset_add(*changed, lgrp_root->lgrp_id);
1165 klgrpset_add(*changed, leaf->lgrp_id);
1167 count += 2;
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);
1175 if (latency == 0) {
1176 #ifdef DEBUG
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);
1180 #endif /* DEBUG */
1181 return (count);
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++) {
1196 lgrp_t *lgrp;
1198 lgrp = lgrps[i];
1201 * Skip non-existent lgroups, new leaf lgroup, and
1202 * non-leaf lgroups
1204 if (!LGRP_EXISTS(lgrp) || lgrp == leaf ||
1205 lgrp->lgrp_childcnt != 0) {
1206 #ifdef DEBUG
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);
1211 #endif /* DEBUG */
1212 continue;
1215 #ifdef DEBUG
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,
1220 (void *)lgrp);
1221 #endif /* DEBUG */
1223 count += lgrp_lineage_add(leaf, lgrp, &changes);
1224 if (changed)
1225 klgrpset_or(*changed, changes);
1227 count += lgrp_lineage_add(lgrp, leaf, &changes);
1228 if (changed)
1229 klgrpset_or(*changed, changes);
1232 #ifdef DEBUG
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);
1236 #endif /* DEBUG */
1238 return (count);
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)
1249 klgrpset_t changes;
1250 klgrpset_t collapse;
1251 int count;
1252 int i;
1253 lgrp_t *lgrp;
1255 ASSERT(MUTEX_HELD(&cpu_lock) || curthread->t_preempt > 0 ||
1256 !lgrp_initialized);
1258 count = 0;
1259 klgrpset_clear(collapse);
1260 if (changed)
1261 klgrpset_clear(*changed);
1264 * Nothing to do if no leaf given
1266 if (leaf == NULL)
1267 return (0);
1269 #ifdef DEBUG
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,
1273 (void *)changed);
1274 #endif /* DEBUG */
1277 * Remove leaf from any lgroups containing its resources
1279 for (i = 0; i < lgrp_count; i++) {
1280 lgrp = lgrps[i];
1281 if (lgrp == NULL || lgrp->lgrp_id == LGRP_NONE ||
1282 !lgrp_rsets_member(lgrp->lgrp_set, leaf->lgrp_id))
1283 continue;
1285 #ifdef DEBUG
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);
1289 #endif /* DEBUG */
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);
1295 count++;
1299 * Remove leaf and its ancestors that don't have any other children
1301 #ifdef DEBUG
1302 if (lgrp_topo_debug > 1)
1303 prom_printf("lgrp_leaf_delete: remove leaf and ancestors\n");
1304 #endif /* DEBUG */
1306 count += lgrp_ancestor_delete(leaf, &changes);
1307 klgrpset_or(collapse, changes);
1308 klgrpset_add(collapse, leaf->lgrp_id);
1309 count++;
1310 lgrp_destroy(leaf);
1313 * Consolidate any duplicate lgroups of ones just changed
1314 * Assume that there were no duplicates before last round of changes
1316 #ifdef DEBUG
1317 if (lgrp_topo_debug > 1)
1318 prom_printf("lgrp_leaf_delete: collapsing dups\n");
1319 #endif /* DEBUG */
1320 count += lgrp_collapse_dups(collapse, lgrp_collapse_equidist,
1321 &changes);
1322 klgrpset_or(collapse, changes);
1323 if (changed)
1324 klgrpset_copy(*changed, collapse);
1326 #ifdef DEBUG
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);
1330 #endif /* DEBUG */
1332 return (count);
1337 * Flatten lgroup topology down to height specified
1340 lgrp_topo_flatten(int levels, lgrp_t **lgrps, int lgrp_count,
1341 klgrpset_t *changed)
1343 int count;
1344 int i;
1345 lgrp_t *lgrp;
1346 lgrp_handle_t hdl;
1349 * Only flatten down to 2 level for now
1351 if (levels != 2)
1352 return (0);
1355 * Look for non-leaf lgroups to remove and leaf lgroups to reparent
1357 count = 0;
1358 for (i = 0; i <= lgrp_count; i++) {
1360 * Skip non-existent lgroups and root
1362 lgrp = lgrps[i];
1363 if (!LGRP_EXISTS(lgrp))
1364 continue;
1366 hdl = lgrp->lgrp_plathand;
1368 if (lgrp == lgrp_root) {
1369 lgrp->lgrp_latency = lgrp_plat_latency(hdl, hdl);
1370 continue;
1373 if (lgrp->lgrp_childcnt > 0) {
1374 lgrp_t *parent;
1377 * Remove non-leaf lgroup from lgroup topology
1379 parent = lgrp->lgrp_parent;
1380 if (changed) {
1381 klgrpset_add(*changed, lgrp->lgrp_id);
1382 klgrpset_add(*changed, parent->lgrp_id);
1383 count += 2;
1385 if (parent) {
1386 klgrpset_del(parent->lgrp_children,
1387 lgrp->lgrp_id);
1388 parent->lgrp_childcnt--;
1390 lgrp_destroy(lgrp);
1391 } else if (lgrp->lgrp_parent != lgrp_root) {
1393 * Reparent leaf lgroup to root
1395 if (changed) {
1396 klgrpset_add(*changed, lgrp_root->lgrp_id);
1397 klgrpset_add(*changed, lgrp->lgrp_id);
1398 count += 2;
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);
1409 return (count);
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;
1441 else
1442 lgrp_topo_levels = ht;
1444 return (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
1456 * each node.
1459 lgrp_topo_update(lgrp_t **lgrps, int lgrp_count, klgrpset_t *changed)
1461 klgrpset_t changes;
1462 int count;
1463 int i;
1464 lgrp_t *lgrp;
1466 count = 0;
1467 if (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
1474 if (nlgrps == 1) {
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);
1479 return (0);
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++) {
1492 lgrp = lgrps[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)
1500 continue;
1502 #ifdef DEBUG
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,
1506 (void *)lgrp);
1508 #endif /* DEBUG */
1510 count += lgrp_leaf_add(lgrp, lgrps, lgrp_count, &changes);
1511 if (changed)
1512 klgrpset_or(*changed, changes);
1514 if (!klgrpset_isempty(changes))
1515 (void) lgrp_mnode_update(changes, NULL);
1517 #ifdef DEBUG
1518 if (lgrp_topo_debug > 1 && changed)
1519 prom_printf("lgrp_topo_update: changed %d lgrps: "
1520 "0x%llx\n",
1521 count, (u_longlong_t)*changed);
1522 #endif /* DEBUG */
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);
1530 start_cpus();
1531 mutex_exit(&cpu_lock);
1533 return (count);
1536 #ifdef DEBUG
1537 void
1538 lgrp_print(lgrp_t *lgrp)
1540 lgrp_t *parent;
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);
1546 else
1547 prom_printf("\n");
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);
1555 if (parent)
1556 prom_printf("[%d]\n", parent->lgrp_id);
1557 else
1558 prom_printf("\n");
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);
1568 void
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;
1577 int i;
1579 klgrpset_clear(children);
1580 for (i = 0; i <= lgrp_max; i++) {
1581 lgrp_t *lgrp;
1583 lgrp = lgrps[i];
1584 if (lgrp == NULL || !klgrpset_ismember(siblings, i))
1585 continue;
1586 lgrp_print(lgrp);
1587 klgrpset_or(children, lgrp->lgrp_children);
1589 klgrpset_copy(siblings, children);
1592 #endif /* DEBUG */