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