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