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