1 /* 2 * Copyright (c) 2012 The DragonFly Project. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in 12 * the documentation and/or other materials provided with the 13 * distribution. 14 * 3. Neither the name of The DragonFly Project nor the names of its 15 * contributors may be used to endorse or promote products derived 16 * from this software without specific, prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 21 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 22 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 23 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 24 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 26 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 27 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 28 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 * 31 */ 32 33 #include <sys/param.h> 34 #include <sys/systm.h> 35 #include <sys/kernel.h> 36 #include <sys/sysctl.h> 37 #include <sys/sbuf.h> 38 #include <sys/cpu_topology.h> 39 40 #include <machine/smp.h> 41 42 #ifndef NAPICID 43 #define NAPICID 256 44 #endif 45 46 #define INDENT_BUF_SIZE LEVEL_NO*3 47 #define INVALID_ID -1 48 49 /* Per-cpu sysctl nodes and info */ 50 struct per_cpu_sysctl_info { 51 struct sysctl_ctx_list sysctl_ctx; 52 struct sysctl_oid *sysctl_tree; 53 char cpu_name[32]; 54 int physical_id; 55 int core_id; 56 char physical_siblings[8*MAXCPU]; 57 char core_siblings[8*MAXCPU]; 58 }; 59 typedef struct per_cpu_sysctl_info per_cpu_sysctl_info_t; 60 61 static cpu_node_t cpu_topology_nodes[MAXCPU]; /* Memory for topology */ 62 static cpu_node_t *cpu_root_node; /* Root node pointer */ 63 64 static struct sysctl_ctx_list cpu_topology_sysctl_ctx; 65 static struct sysctl_oid *cpu_topology_sysctl_tree; 66 static char cpu_topology_members[8*MAXCPU]; 67 static per_cpu_sysctl_info_t *pcpu_sysctl; 68 static void sbuf_print_cpuset(struct sbuf *sb, cpumask_t *mask); 69 70 int cpu_topology_levels_number = 1; 71 cpu_node_t *root_cpu_node; 72 73 MALLOC_DEFINE(M_PCPUSYS, "pcpusys", "pcpu sysctl topology"); 74 75 76 /* Get the next valid apicid starting 77 * from current apicid (curr_apicid 78 */ 79 static int 80 get_next_valid_apicid(int curr_apicid) 81 { 82 int next_apicid = curr_apicid; 83 do { 84 next_apicid++; 85 } 86 while(get_cpuid_from_apicid(next_apicid) == -1 && 87 next_apicid < NAPICID); 88 if (next_apicid == NAPICID) { 89 kprintf("Warning: No next valid APICID found. Returning -1\n"); 90 return -1; 91 } 92 return next_apicid; 93 } 94 95 /* Generic topology tree. The parameters have the following meaning: 96 * - children_no_per_level : the number of children on each level 97 * - level_types : the type of the level (THREAD, CORE, CHIP, etc) 98 * - cur_level : the current level of the tree 99 * - node : the current node 100 * - last_free_node : the last free node in the global array. 101 * - cpuid : basicly this are the ids of the leafs 102 */ 103 static void 104 build_topology_tree(int *children_no_per_level, 105 uint8_t *level_types, 106 int cur_level, 107 cpu_node_t *node, 108 cpu_node_t **last_free_node, 109 int *apicid) 110 { 111 int i; 112 113 node->child_no = children_no_per_level[cur_level]; 114 node->type = level_types[cur_level]; 115 CPUMASK_ASSZERO(node->members); 116 node->compute_unit_id = -1; 117 118 if (node->child_no == 0) { 119 *apicid = get_next_valid_apicid(*apicid); 120 CPUMASK_ASSBIT(node->members, get_cpuid_from_apicid(*apicid)); 121 return; 122 } 123 124 if (node->parent_node == NULL) 125 root_cpu_node = node; 126 127 for (i = 0; i < node->child_no; i++) { 128 node->child_node[i] = *last_free_node; 129 (*last_free_node)++; 130 131 node->child_node[i]->parent_node = node; 132 133 build_topology_tree(children_no_per_level, 134 level_types, 135 cur_level + 1, 136 node->child_node[i], 137 last_free_node, 138 apicid); 139 140 CPUMASK_ORMASK(node->members, node->child_node[i]->members); 141 } 142 } 143 144 #if defined(__x86_64__) && !defined(_KERNEL_VIRTUAL) 145 static void 146 migrate_elements(cpu_node_t **a, int n, int pos) 147 { 148 int i; 149 150 for (i = pos; i < n - 1 ; i++) { 151 a[i] = a[i+1]; 152 } 153 a[i] = NULL; 154 } 155 #endif 156 157 /* Build CPU topology. The detection is made by comparing the 158 * chip, core and logical IDs of each CPU with the IDs of the 159 * BSP. When we found a match, at that level the CPUs are siblings. 160 */ 161 static void 162 build_cpu_topology(void) 163 { 164 detect_cpu_topology(); 165 int i; 166 int BSPID = 0; 167 int threads_per_core = 0; 168 int cores_per_chip = 0; 169 int chips_per_package = 0; 170 int children_no_per_level[LEVEL_NO]; 171 uint8_t level_types[LEVEL_NO]; 172 int apicid = -1; 173 174 cpu_node_t *root = &cpu_topology_nodes[0]; 175 cpu_node_t *last_free_node = root + 1; 176 177 /* Assume that the topology is uniform. 178 * Find the number of siblings within chip 179 * and witin core to build up the topology 180 */ 181 for (i = 0; i < ncpus; i++) { 182 cpumask_t mask; 183 184 CPUMASK_ASSBIT(mask, i); 185 186 if (CPUMASK_TESTMASK(mask, smp_active_mask) == 0) 187 continue; 188 189 if (get_chip_ID(BSPID) == get_chip_ID(i)) 190 cores_per_chip++; 191 else 192 continue; 193 194 if (get_core_number_within_chip(BSPID) == 195 get_core_number_within_chip(i)) 196 threads_per_core++; 197 } 198 199 cores_per_chip /= threads_per_core; 200 chips_per_package = ncpus / (cores_per_chip * threads_per_core); 201 202 if (bootverbose) 203 kprintf("CPU Topology: cores_per_chip: %d; threads_per_core: %d; chips_per_package: %d;\n", 204 cores_per_chip, threads_per_core, chips_per_package); 205 206 if (threads_per_core > 1) { /* HT available - 4 levels */ 207 208 children_no_per_level[0] = chips_per_package; 209 children_no_per_level[1] = cores_per_chip; 210 children_no_per_level[2] = threads_per_core; 211 children_no_per_level[3] = 0; 212 213 level_types[0] = PACKAGE_LEVEL; 214 level_types[1] = CHIP_LEVEL; 215 level_types[2] = CORE_LEVEL; 216 level_types[3] = THREAD_LEVEL; 217 218 build_topology_tree(children_no_per_level, 219 level_types, 220 0, 221 root, 222 &last_free_node, 223 &apicid); 224 225 cpu_topology_levels_number = 4; 226 227 } else if (cores_per_chip > 1) { /* No HT available - 3 levels */ 228 229 children_no_per_level[0] = chips_per_package; 230 children_no_per_level[1] = cores_per_chip; 231 children_no_per_level[2] = 0; 232 233 level_types[0] = PACKAGE_LEVEL; 234 level_types[1] = CHIP_LEVEL; 235 level_types[2] = CORE_LEVEL; 236 237 build_topology_tree(children_no_per_level, 238 level_types, 239 0, 240 root, 241 &last_free_node, 242 &apicid); 243 244 cpu_topology_levels_number = 3; 245 246 } else { /* No HT and no Multi-Core - 2 levels */ 247 248 children_no_per_level[0] = chips_per_package; 249 children_no_per_level[1] = 0; 250 251 level_types[0] = PACKAGE_LEVEL; 252 level_types[1] = CHIP_LEVEL; 253 254 build_topology_tree(children_no_per_level, 255 level_types, 256 0, 257 root, 258 &last_free_node, 259 &apicid); 260 261 cpu_topology_levels_number = 2; 262 263 } 264 265 cpu_root_node = root; 266 267 268 #if defined(__x86_64__) && !defined(_KERNEL_VIRTUAL) 269 if (fix_amd_topology() == 0) { 270 int visited[MAXCPU], i, j, pos, cpuid; 271 cpu_node_t *leaf, *parent; 272 273 bzero(visited, MAXCPU * sizeof(int)); 274 275 for (i = 0; i < ncpus; i++) { 276 if (visited[i] == 0) { 277 pos = 0; 278 visited[i] = 1; 279 leaf = get_cpu_node_by_cpuid(i); 280 281 if (leaf->type == CORE_LEVEL) { 282 parent = leaf->parent_node; 283 284 last_free_node->child_node[0] = leaf; 285 last_free_node->child_no = 1; 286 last_free_node->members = leaf->members; 287 last_free_node->compute_unit_id = leaf->compute_unit_id; 288 last_free_node->parent_node = parent; 289 last_free_node->type = CORE_LEVEL; 290 291 292 for (j = 0; j < parent->child_no; j++) { 293 if (parent->child_node[j] != leaf) { 294 295 cpuid = BSFCPUMASK(parent->child_node[j]->members); 296 if (visited[cpuid] == 0 && 297 parent->child_node[j]->compute_unit_id == leaf->compute_unit_id) { 298 299 last_free_node->child_node[last_free_node->child_no] = parent->child_node[j]; 300 last_free_node->child_no++; 301 CPUMASK_ORMASK(last_free_node->members, parent->child_node[j]->members); 302 303 parent->child_node[j]->type = THREAD_LEVEL; 304 parent->child_node[j]->parent_node = last_free_node; 305 visited[cpuid] = 1; 306 307 migrate_elements(parent->child_node, parent->child_no, j); 308 parent->child_no--; 309 j--; 310 } 311 } else { 312 pos = j; 313 } 314 } 315 if (last_free_node->child_no > 1) { 316 parent->child_node[pos] = last_free_node; 317 leaf->type = THREAD_LEVEL; 318 leaf->parent_node = last_free_node; 319 last_free_node++; 320 } 321 } 322 } 323 } 324 } 325 #endif 326 } 327 328 /* Recursive function helper to print the CPU topology tree */ 329 static void 330 print_cpu_topology_tree_sysctl_helper(cpu_node_t *node, 331 struct sbuf *sb, 332 char * buf, 333 int buf_len, 334 int last) 335 { 336 int i; 337 int bsr_member; 338 339 sbuf_bcat(sb, buf, buf_len); 340 if (last) { 341 sbuf_printf(sb, "\\-"); 342 buf[buf_len] = ' ';buf_len++; 343 buf[buf_len] = ' ';buf_len++; 344 } else { 345 sbuf_printf(sb, "|-"); 346 buf[buf_len] = '|';buf_len++; 347 buf[buf_len] = ' ';buf_len++; 348 } 349 350 bsr_member = BSRCPUMASK(node->members); 351 352 if (node->type == PACKAGE_LEVEL) { 353 sbuf_printf(sb,"PACKAGE MEMBERS: "); 354 } else if (node->type == CHIP_LEVEL) { 355 sbuf_printf(sb,"CHIP ID %d: ", 356 get_chip_ID(bsr_member)); 357 } else if (node->type == CORE_LEVEL) { 358 if (node->compute_unit_id != (uint8_t)-1) { 359 sbuf_printf(sb,"Compute Unit ID %d: ", 360 node->compute_unit_id); 361 } else { 362 sbuf_printf(sb,"CORE ID %d: ", 363 get_core_number_within_chip(bsr_member)); 364 } 365 } else if (node->type == THREAD_LEVEL) { 366 if (node->compute_unit_id != (uint8_t)-1) { 367 sbuf_printf(sb,"CORE ID %d: ", 368 get_core_number_within_chip(bsr_member)); 369 } else { 370 sbuf_printf(sb,"THREAD ID %d: ", 371 get_logical_CPU_number_within_core(bsr_member)); 372 } 373 } else { 374 sbuf_printf(sb,"UNKNOWN: "); 375 } 376 sbuf_print_cpuset(sb, &node->members); 377 sbuf_printf(sb,"\n"); 378 379 for (i = 0; i < node->child_no; i++) { 380 print_cpu_topology_tree_sysctl_helper(node->child_node[i], 381 sb, buf, buf_len, i == (node->child_no -1)); 382 } 383 } 384 385 /* SYSCTL PROCEDURE for printing the CPU Topology tree */ 386 static int 387 print_cpu_topology_tree_sysctl(SYSCTL_HANDLER_ARGS) 388 { 389 struct sbuf *sb; 390 int ret; 391 char buf[INDENT_BUF_SIZE]; 392 393 KASSERT(cpu_root_node != NULL, ("cpu_root_node isn't initialized")); 394 395 sb = sbuf_new(NULL, NULL, 500, SBUF_AUTOEXTEND); 396 if (sb == NULL) { 397 return (ENOMEM); 398 } 399 sbuf_printf(sb,"\n"); 400 print_cpu_topology_tree_sysctl_helper(cpu_root_node, sb, buf, 0, 1); 401 402 sbuf_finish(sb); 403 404 ret = SYSCTL_OUT(req, sbuf_data(sb), sbuf_len(sb)); 405 406 sbuf_delete(sb); 407 408 return ret; 409 } 410 411 /* SYSCTL PROCEDURE for printing the CPU Topology level description */ 412 static int 413 print_cpu_topology_level_description_sysctl(SYSCTL_HANDLER_ARGS) 414 { 415 struct sbuf *sb; 416 int ret; 417 418 sb = sbuf_new(NULL, NULL, 500, SBUF_AUTOEXTEND); 419 if (sb == NULL) 420 return (ENOMEM); 421 422 if (cpu_topology_levels_number == 4) /* HT available */ 423 sbuf_printf(sb, "0 - thread; 1 - core; 2 - socket; 3 - anything"); 424 else if (cpu_topology_levels_number == 3) /* No HT available */ 425 sbuf_printf(sb, "0 - core; 1 - socket; 2 - anything"); 426 else if (cpu_topology_levels_number == 2) /* No HT and no Multi-Core */ 427 sbuf_printf(sb, "0 - socket; 1 - anything"); 428 else 429 sbuf_printf(sb, "Unknown"); 430 431 sbuf_finish(sb); 432 433 ret = SYSCTL_OUT(req, sbuf_data(sb), sbuf_len(sb)); 434 435 sbuf_delete(sb); 436 437 return ret; 438 } 439 440 /* Find a cpu_node_t by a mask */ 441 static cpu_node_t * 442 get_cpu_node_by_cpumask(cpu_node_t * node, 443 cpumask_t mask) { 444 445 cpu_node_t * found = NULL; 446 int i; 447 448 if (CPUMASK_CMPMASKEQ(node->members, mask)) 449 return node; 450 451 for (i = 0; i < node->child_no; i++) { 452 found = get_cpu_node_by_cpumask(node->child_node[i], mask); 453 if (found != NULL) { 454 return found; 455 } 456 } 457 return NULL; 458 } 459 460 cpu_node_t * 461 get_cpu_node_by_cpuid(int cpuid) { 462 cpumask_t mask; 463 464 CPUMASK_ASSBIT(mask, cpuid); 465 466 KASSERT(cpu_root_node != NULL, ("cpu_root_node isn't initialized")); 467 468 return get_cpu_node_by_cpumask(cpu_root_node, mask); 469 } 470 471 /* Get the mask of siblings for level_type of a cpuid */ 472 cpumask_t 473 get_cpumask_from_level(int cpuid, 474 uint8_t level_type) 475 { 476 cpu_node_t * node; 477 cpumask_t mask; 478 479 CPUMASK_ASSBIT(mask, cpuid); 480 481 KASSERT(cpu_root_node != NULL, ("cpu_root_node isn't initialized")); 482 483 node = get_cpu_node_by_cpumask(cpu_root_node, mask); 484 485 if (node == NULL) { 486 CPUMASK_ASSZERO(mask); 487 return mask; 488 } 489 490 while (node != NULL) { 491 if (node->type == level_type) { 492 return node->members; 493 } 494 node = node->parent_node; 495 } 496 CPUMASK_ASSZERO(mask); 497 498 return mask; 499 } 500 501 static const cpu_node_t * 502 get_cpu_node_by_chipid2(const cpu_node_t *node, int chip_id) 503 { 504 int cpuid; 505 506 if (node->type != CHIP_LEVEL) { 507 const cpu_node_t *ret = NULL; 508 int i; 509 510 for (i = 0; i < node->child_no; ++i) { 511 ret = get_cpu_node_by_chipid2(node->child_node[i], 512 chip_id); 513 if (ret != NULL) 514 break; 515 } 516 return ret; 517 } 518 519 cpuid = BSRCPUMASK(node->members); 520 if (get_chip_ID(cpuid) == chip_id) 521 return node; 522 return NULL; 523 } 524 525 const cpu_node_t * 526 get_cpu_node_by_chipid(int chip_id) 527 { 528 KASSERT(cpu_root_node != NULL, ("cpu_root_node isn't initialized")); 529 return get_cpu_node_by_chipid2(cpu_root_node, chip_id); 530 } 531 532 /* init pcpu_sysctl structure info */ 533 static void 534 init_pcpu_topology_sysctl(void) 535 { 536 int i; 537 cpumask_t mask; 538 struct sbuf sb; 539 540 pcpu_sysctl = kmalloc(sizeof(*pcpu_sysctl) * MAXCPU, M_PCPUSYS, 541 M_INTWAIT | M_ZERO); 542 543 for (i = 0; i < ncpus; i++) { 544 sbuf_new(&sb, pcpu_sysctl[i].cpu_name, 545 sizeof(pcpu_sysctl[i].cpu_name), SBUF_FIXEDLEN); 546 sbuf_printf(&sb,"cpu%d", i); 547 sbuf_finish(&sb); 548 549 550 /* Get physical siblings */ 551 mask = get_cpumask_from_level(i, CHIP_LEVEL); 552 if (CPUMASK_TESTZERO(mask)) { 553 pcpu_sysctl[i].physical_id = INVALID_ID; 554 continue; 555 } 556 557 sbuf_new(&sb, pcpu_sysctl[i].physical_siblings, 558 sizeof(pcpu_sysctl[i].physical_siblings), SBUF_FIXEDLEN); 559 sbuf_print_cpuset(&sb, &mask); 560 sbuf_trim(&sb); 561 sbuf_finish(&sb); 562 563 pcpu_sysctl[i].physical_id = get_chip_ID(i); 564 565 /* Get core siblings */ 566 mask = get_cpumask_from_level(i, CORE_LEVEL); 567 if (CPUMASK_TESTZERO(mask)) { 568 pcpu_sysctl[i].core_id = INVALID_ID; 569 continue; 570 } 571 572 sbuf_new(&sb, pcpu_sysctl[i].core_siblings, 573 sizeof(pcpu_sysctl[i].core_siblings), SBUF_FIXEDLEN); 574 sbuf_print_cpuset(&sb, &mask); 575 sbuf_trim(&sb); 576 sbuf_finish(&sb); 577 578 pcpu_sysctl[i].core_id = get_core_number_within_chip(i); 579 580 } 581 } 582 583 /* Build SYSCTL structure for revealing 584 * the CPU Topology to user-space. 585 */ 586 static void 587 build_sysctl_cpu_topology(void) 588 { 589 int i; 590 struct sbuf sb; 591 592 /* SYSCTL new leaf for "cpu_topology" */ 593 sysctl_ctx_init(&cpu_topology_sysctl_ctx); 594 cpu_topology_sysctl_tree = SYSCTL_ADD_NODE(&cpu_topology_sysctl_ctx, 595 SYSCTL_STATIC_CHILDREN(_hw), 596 OID_AUTO, 597 "cpu_topology", 598 CTLFLAG_RD, 0, ""); 599 600 /* SYSCTL cpu_topology "tree" entry */ 601 SYSCTL_ADD_PROC(&cpu_topology_sysctl_ctx, 602 SYSCTL_CHILDREN(cpu_topology_sysctl_tree), 603 OID_AUTO, "tree", CTLTYPE_STRING | CTLFLAG_RD, 604 NULL, 0, print_cpu_topology_tree_sysctl, "A", 605 "Tree print of CPU topology"); 606 607 /* SYSCTL cpu_topology "level_description" entry */ 608 SYSCTL_ADD_PROC(&cpu_topology_sysctl_ctx, 609 SYSCTL_CHILDREN(cpu_topology_sysctl_tree), 610 OID_AUTO, "level_description", CTLTYPE_STRING | CTLFLAG_RD, 611 NULL, 0, print_cpu_topology_level_description_sysctl, "A", 612 "Level description of CPU topology"); 613 614 /* SYSCTL cpu_topology "members" entry */ 615 sbuf_new(&sb, cpu_topology_members, 616 sizeof(cpu_topology_members), SBUF_FIXEDLEN); 617 sbuf_print_cpuset(&sb, &cpu_root_node->members); 618 sbuf_trim(&sb); 619 sbuf_finish(&sb); 620 SYSCTL_ADD_STRING(&cpu_topology_sysctl_ctx, 621 SYSCTL_CHILDREN(cpu_topology_sysctl_tree), 622 OID_AUTO, "members", CTLFLAG_RD, 623 cpu_topology_members, 0, 624 "Members of the CPU Topology"); 625 626 /* SYSCTL per_cpu info */ 627 for (i = 0; i < ncpus; i++) { 628 /* New leaf : hw.cpu_topology.cpux */ 629 sysctl_ctx_init(&pcpu_sysctl[i].sysctl_ctx); 630 pcpu_sysctl[i].sysctl_tree = SYSCTL_ADD_NODE(&pcpu_sysctl[i].sysctl_ctx, 631 SYSCTL_CHILDREN(cpu_topology_sysctl_tree), 632 OID_AUTO, 633 pcpu_sysctl[i].cpu_name, 634 CTLFLAG_RD, 0, ""); 635 636 /* Check if the physical_id found is valid */ 637 if (pcpu_sysctl[i].physical_id == INVALID_ID) { 638 continue; 639 } 640 641 /* Add physical id info */ 642 SYSCTL_ADD_INT(&pcpu_sysctl[i].sysctl_ctx, 643 SYSCTL_CHILDREN(pcpu_sysctl[i].sysctl_tree), 644 OID_AUTO, "physical_id", CTLFLAG_RD, 645 &pcpu_sysctl[i].physical_id, 0, 646 "Physical ID"); 647 648 /* Add physical siblings */ 649 SYSCTL_ADD_STRING(&pcpu_sysctl[i].sysctl_ctx, 650 SYSCTL_CHILDREN(pcpu_sysctl[i].sysctl_tree), 651 OID_AUTO, "physical_siblings", CTLFLAG_RD, 652 pcpu_sysctl[i].physical_siblings, 0, 653 "Physical siblings"); 654 655 /* Check if the core_id found is valid */ 656 if (pcpu_sysctl[i].core_id == INVALID_ID) { 657 continue; 658 } 659 660 /* Add core id info */ 661 SYSCTL_ADD_INT(&pcpu_sysctl[i].sysctl_ctx, 662 SYSCTL_CHILDREN(pcpu_sysctl[i].sysctl_tree), 663 OID_AUTO, "core_id", CTLFLAG_RD, 664 &pcpu_sysctl[i].core_id, 0, 665 "Core ID"); 666 667 /*Add core siblings */ 668 SYSCTL_ADD_STRING(&pcpu_sysctl[i].sysctl_ctx, 669 SYSCTL_CHILDREN(pcpu_sysctl[i].sysctl_tree), 670 OID_AUTO, "core_siblings", CTLFLAG_RD, 671 pcpu_sysctl[i].core_siblings, 0, 672 "Core siblings"); 673 } 674 } 675 676 static 677 void 678 sbuf_print_cpuset(struct sbuf *sb, cpumask_t *mask) 679 { 680 int i; 681 int b = -1; 682 int e = -1; 683 int more = 0; 684 685 sbuf_printf(sb, "cpus("); 686 CPUSET_FOREACH(i, *mask) { 687 if (b < 0) { 688 b = i; 689 e = b + 1; 690 continue; 691 } 692 if (e == i) { 693 ++e; 694 continue; 695 } 696 if (more) 697 sbuf_printf(sb, ", "); 698 if (b == e - 1) { 699 sbuf_printf(sb, "%d", b); 700 } else { 701 sbuf_printf(sb, "%d-%d", b, e - 1); 702 } 703 more = 1; 704 b = i; 705 e = b + 1; 706 } 707 if (more) 708 sbuf_printf(sb, ", "); 709 if (b >= 0) { 710 if (b == e - 1) { 711 sbuf_printf(sb, "%d", b); 712 } else { 713 sbuf_printf(sb, "%d-%d", b, e - 1); 714 } 715 } 716 sbuf_printf(sb, ") "); 717 } 718 719 /* Build the CPU Topology and SYSCTL Topology tree */ 720 static void 721 init_cpu_topology(void) 722 { 723 build_cpu_topology(); 724 725 init_pcpu_topology_sysctl(); 726 build_sysctl_cpu_topology(); 727 } 728 SYSINIT(cpu_topology, SI_BOOT2_CPU_TOPOLOGY, SI_ORDER_FIRST, 729 init_cpu_topology, NULL); 730