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