kernel - Add callout debugging
[dragonfly.git] / sys / kern / subr_cpu_topology.c
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         int ht_id;                              /* thread id within core */
57         char physical_siblings[8*MAXCPU];
58         char core_siblings[8*MAXCPU];
59 };
60 typedef struct per_cpu_sysctl_info per_cpu_sysctl_info_t;
61
62 static cpu_node_t cpu_topology_nodes[MAXCPU];   /* Memory for topology */
63 static cpu_node_t *cpu_root_node;               /* Root node pointer */
64
65 static struct sysctl_ctx_list cpu_topology_sysctl_ctx;
66 static struct sysctl_oid *cpu_topology_sysctl_tree;
67 static char cpu_topology_members[8*MAXCPU];
68 static per_cpu_sysctl_info_t *pcpu_sysctl;
69 static void sbuf_print_cpuset(struct sbuf *sb, cpumask_t *mask);
70
71 int cpu_topology_levels_number = 1;
72 int cpu_topology_ht_ids;
73 int cpu_topology_core_ids;
74 int cpu_topology_phys_ids;
75 cpu_node_t *root_cpu_node;
76
77 MALLOC_DEFINE(M_PCPUSYS, "pcpusys", "pcpu sysctl topology");
78
79 SYSCTL_INT(_hw, OID_AUTO, cpu_topology_ht_ids, CTLFLAG_RW,
80            &cpu_topology_ht_ids, 0, "# of logical cores per real core");
81 SYSCTL_INT(_hw, OID_AUTO, cpu_topology_core_ids, CTLFLAG_RW,
82            &cpu_topology_core_ids, 0, "# of real cores per package");
83 SYSCTL_INT(_hw, OID_AUTO, cpu_topology_phys_ids, CTLFLAG_RW,
84            &cpu_topology_phys_ids, 0, "# of physical packages");
85
86 /* Get the next valid apicid starting
87  * from current apicid (curr_apicid
88  */
89 static int
90 get_next_valid_apicid(int curr_apicid)
91 {
92         int next_apicid = curr_apicid;
93         do {
94                 next_apicid++;
95         }
96         while(get_cpuid_from_apicid(next_apicid) == -1 &&
97            next_apicid < NAPICID);
98         if (next_apicid == NAPICID) {
99                 kprintf("Warning: No next valid APICID found. Returning -1\n");
100                 return -1;
101         }
102         return next_apicid;
103 }
104
105 /* Generic topology tree. The parameters have the following meaning:
106  * - children_no_per_level : the number of children on each level
107  * - level_types : the type of the level (THREAD, CORE, CHIP, etc)
108  * - cur_level : the current level of the tree
109  * - node : the current node
110  * - last_free_node : the last free node in the global array.
111  * - cpuid : basicly this are the ids of the leafs
112  */ 
113 static void
114 build_topology_tree(int *children_no_per_level,
115    uint8_t *level_types,
116    int cur_level, 
117    cpu_node_t *node,
118    cpu_node_t **last_free_node,
119    int *apicid)
120 {
121         int i;
122
123         node->child_no = children_no_per_level[cur_level];
124         node->type = level_types[cur_level];
125         CPUMASK_ASSZERO(node->members);
126         node->compute_unit_id = -1;
127
128         if (node->child_no == 0) {
129                 *apicid = get_next_valid_apicid(*apicid);
130                 CPUMASK_ASSBIT(node->members, get_cpuid_from_apicid(*apicid));
131                 return;
132         }
133
134         if (node->parent_node == NULL)
135                 root_cpu_node = node;
136         
137         for (i = 0; i < node->child_no; i++) {
138                 node->child_node[i] = *last_free_node;
139                 (*last_free_node)++;
140
141                 node->child_node[i]->parent_node = node;
142
143                 build_topology_tree(children_no_per_level,
144                     level_types,
145                     cur_level + 1,
146                     node->child_node[i],
147                     last_free_node,
148                     apicid);
149
150                 CPUMASK_ORMASK(node->members, node->child_node[i]->members);
151         }
152 }
153
154 #if defined(__x86_64__) && !defined(_KERNEL_VIRTUAL)
155 static void
156 migrate_elements(cpu_node_t **a, int n, int pos)
157 {
158         int i;
159
160         for (i = pos; i < n - 1 ; i++) {
161                 a[i] = a[i+1];
162         }
163         a[i] = NULL;
164 }
165 #endif
166
167 /* Build CPU topology. The detection is made by comparing the
168  * chip, core and logical IDs of each CPU with the IDs of the 
169  * BSP. When we found a match, at that level the CPUs are siblings.
170  */
171 static void
172 build_cpu_topology(int assumed_ncpus)
173 {
174         int i;
175         int BSPID = 0;
176         int threads_per_core = 0;
177         int cores_per_chip = 0;
178         int chips_per_package = 0;
179         int children_no_per_level[LEVEL_NO];
180         uint8_t level_types[LEVEL_NO];
181         int apicid = -1;
182         cpu_node_t *root = &cpu_topology_nodes[0];
183         cpu_node_t *last_free_node = root + 1;
184
185         detect_cpu_topology();
186
187         /*
188          * Assume that the topology is uniform.
189          * Find the number of siblings within chip
190          * and witin core to build up the topology.
191          */
192         for (i = 0; i < assumed_ncpus; i++) {
193                 cpumask_t mask;
194
195                 CPUMASK_ASSBIT(mask, i);
196
197 #if 0
198                 /* smp_active_mask has not been initialized yet, ignore */
199                 if (CPUMASK_TESTMASK(mask, smp_active_mask) == 0)
200                         continue;
201 #endif
202
203                 if (get_chip_ID(BSPID) != get_chip_ID(i))
204                         continue;
205                 ++cores_per_chip;
206
207                 if (get_core_number_within_chip(BSPID) ==
208                     get_core_number_within_chip(i)) {
209                         ++threads_per_core;
210                 }
211         }
212
213         cores_per_chip /= threads_per_core;
214         chips_per_package = assumed_ncpus / (cores_per_chip * threads_per_core);
215         
216         kprintf("CPU Topology: cores_per_chip: %d; threads_per_core: %d; "
217                 "chips_per_package: %d;\n",
218                 cores_per_chip, threads_per_core, chips_per_package);
219
220         if (threads_per_core > 1) { /* HT available - 4 levels */
221
222                 children_no_per_level[0] = chips_per_package;
223                 children_no_per_level[1] = cores_per_chip;
224                 children_no_per_level[2] = threads_per_core;
225                 children_no_per_level[3] = 0;
226
227                 level_types[0] = PACKAGE_LEVEL;
228                 level_types[1] = CHIP_LEVEL;
229                 level_types[2] = CORE_LEVEL;
230                 level_types[3] = THREAD_LEVEL;
231         
232                 build_topology_tree(children_no_per_level,
233                     level_types,
234                     0,
235                     root,
236                     &last_free_node,
237                     &apicid);
238
239                 cpu_topology_levels_number = 4;
240
241         } else if (cores_per_chip > 1) { /* No HT available - 3 levels */
242
243                 children_no_per_level[0] = chips_per_package;
244                 children_no_per_level[1] = cores_per_chip;
245                 children_no_per_level[2] = 0;
246
247                 level_types[0] = PACKAGE_LEVEL;
248                 level_types[1] = CHIP_LEVEL;
249                 level_types[2] = CORE_LEVEL;
250         
251                 build_topology_tree(children_no_per_level,
252                     level_types,
253                     0,
254                     root,
255                     &last_free_node,
256                     &apicid);
257
258                 cpu_topology_levels_number = 3;
259
260         } else { /* No HT and no Multi-Core - 2 levels */
261
262                 children_no_per_level[0] = chips_per_package;
263                 children_no_per_level[1] = 0;
264
265                 level_types[0] = PACKAGE_LEVEL;
266                 level_types[1] = CHIP_LEVEL;
267         
268                 build_topology_tree(children_no_per_level,
269                     level_types,
270                     0,
271                     root,
272                     &last_free_node,
273                     &apicid);
274
275                 cpu_topology_levels_number = 2;
276
277         }
278
279         cpu_root_node = root;
280
281
282 #if defined(__x86_64__) && !defined(_KERNEL_VIRTUAL)
283         if (fix_amd_topology() == 0) {
284                 int visited[MAXCPU], i, j, pos, cpuid;
285                 cpu_node_t *leaf, *parent;
286
287                 bzero(visited, MAXCPU * sizeof(int));
288
289                 for (i = 0; i < assumed_ncpus; i++) {
290                         if (visited[i] == 0) {
291                                 pos = 0;
292                                 visited[i] = 1;
293                                 leaf = get_cpu_node_by_cpuid(i);
294
295                                 if (leaf->type == CORE_LEVEL) {
296                                         parent = leaf->parent_node;
297
298                                         last_free_node->child_node[0] = leaf;
299                                         last_free_node->child_no = 1;
300                                         last_free_node->members = leaf->members;
301                                         last_free_node->compute_unit_id = leaf->compute_unit_id;
302                                         last_free_node->parent_node = parent;
303                                         last_free_node->type = CORE_LEVEL;
304
305
306                                         for (j = 0; j < parent->child_no; j++) {
307                                                 if (parent->child_node[j] != leaf) {
308
309                                                         cpuid = BSFCPUMASK(parent->child_node[j]->members);
310                                                         if (visited[cpuid] == 0 &&
311                                                             parent->child_node[j]->compute_unit_id == leaf->compute_unit_id) {
312
313                                                                 last_free_node->child_node[last_free_node->child_no] = parent->child_node[j];
314                                                                 last_free_node->child_no++;
315                                                                 CPUMASK_ORMASK(last_free_node->members, parent->child_node[j]->members);
316
317                                                                 parent->child_node[j]->type = THREAD_LEVEL;
318                                                                 parent->child_node[j]->parent_node = last_free_node;
319                                                                 visited[cpuid] = 1;
320
321                                                                 migrate_elements(parent->child_node, parent->child_no, j);
322                                                                 parent->child_no--;
323                                                                 j--;
324                                                         }
325                                                 } else {
326                                                         pos = j;
327                                                 }
328                                         }
329                                         if (last_free_node->child_no > 1) {
330                                                 parent->child_node[pos] = last_free_node;
331                                                 leaf->type = THREAD_LEVEL;
332                                                 leaf->parent_node = last_free_node;
333                                                 last_free_node++;
334                                         }
335                                 }
336                         }
337                 }
338         }
339 #endif
340 }
341
342 /* Recursive function helper to print the CPU topology tree */
343 static void
344 print_cpu_topology_tree_sysctl_helper(cpu_node_t *node,
345     struct sbuf *sb,
346     char * buf,
347     int buf_len,
348     int last)
349 {
350         int i;
351         int bsr_member;
352
353         sbuf_bcat(sb, buf, buf_len);
354         if (last) {
355                 sbuf_printf(sb, "\\-");
356                 buf[buf_len] = ' ';buf_len++;
357                 buf[buf_len] = ' ';buf_len++;
358         } else {
359                 sbuf_printf(sb, "|-");
360                 buf[buf_len] = '|';buf_len++;
361                 buf[buf_len] = ' ';buf_len++;
362         }
363         
364         bsr_member = BSRCPUMASK(node->members);
365
366         if (node->type == PACKAGE_LEVEL) {
367                 sbuf_printf(sb,"PACKAGE MEMBERS: ");
368         } else if (node->type == CHIP_LEVEL) {
369                 sbuf_printf(sb,"CHIP ID %d: ",
370                         get_chip_ID(bsr_member));
371         } else if (node->type == CORE_LEVEL) {
372                 if (node->compute_unit_id != (uint8_t)-1) {
373                         sbuf_printf(sb,"Compute Unit ID %d: ",
374                                 node->compute_unit_id);
375                 } else {
376                         sbuf_printf(sb,"CORE ID %d: ",
377                                 get_core_number_within_chip(bsr_member));
378                 }
379         } else if (node->type == THREAD_LEVEL) {
380                 if (node->compute_unit_id != (uint8_t)-1) {
381                         sbuf_printf(sb,"THREAD ID %d: ",
382                                 get_core_number_within_chip(bsr_member));
383                 } else {
384                         sbuf_printf(sb,"THREAD ID %d: ",
385                                 get_logical_CPU_number_within_core(bsr_member));
386                 }
387         } else {
388                 sbuf_printf(sb,"UNKNOWN: ");
389         }
390         sbuf_print_cpuset(sb, &node->members);
391         sbuf_printf(sb,"\n");
392
393         for (i = 0; i < node->child_no; i++) {
394                 print_cpu_topology_tree_sysctl_helper(node->child_node[i],
395                     sb, buf, buf_len, i == (node->child_no -1));
396         }
397 }
398
399 /* SYSCTL PROCEDURE for printing the CPU Topology tree */
400 static int
401 print_cpu_topology_tree_sysctl(SYSCTL_HANDLER_ARGS)
402 {
403         struct sbuf *sb;
404         int ret;
405         char buf[INDENT_BUF_SIZE];
406
407         KASSERT(cpu_root_node != NULL, ("cpu_root_node isn't initialized"));
408
409         sb = sbuf_new(NULL, NULL, 500, SBUF_AUTOEXTEND);
410         if (sb == NULL) {
411                 return (ENOMEM);
412         }
413         sbuf_printf(sb,"\n");
414         print_cpu_topology_tree_sysctl_helper(cpu_root_node, sb, buf, 0, 1);
415
416         sbuf_finish(sb);
417
418         ret = SYSCTL_OUT(req, sbuf_data(sb), sbuf_len(sb));
419
420         sbuf_delete(sb);
421
422         return ret;
423 }
424
425 /* SYSCTL PROCEDURE for printing the CPU Topology level description */
426 static int
427 print_cpu_topology_level_description_sysctl(SYSCTL_HANDLER_ARGS)
428 {
429         struct sbuf *sb;
430         int ret;
431
432         sb = sbuf_new(NULL, NULL, 500, SBUF_AUTOEXTEND);
433         if (sb == NULL)
434                 return (ENOMEM);
435
436         if (cpu_topology_levels_number == 4) /* HT available */
437                 sbuf_printf(sb, "0 - thread; 1 - core; 2 - socket; 3 - anything");
438         else if (cpu_topology_levels_number == 3) /* No HT available */
439                 sbuf_printf(sb, "0 - core; 1 - socket; 2 - anything");
440         else if (cpu_topology_levels_number == 2) /* No HT and no Multi-Core */
441                 sbuf_printf(sb, "0 - socket; 1 - anything");
442         else
443                 sbuf_printf(sb, "Unknown");
444
445         sbuf_finish(sb);
446
447         ret = SYSCTL_OUT(req, sbuf_data(sb), sbuf_len(sb));
448
449         sbuf_delete(sb);
450
451         return ret;     
452 }
453
454 /* Find a cpu_node_t by a mask */
455 static cpu_node_t *
456 get_cpu_node_by_cpumask(cpu_node_t * node,
457                         cpumask_t mask) {
458
459         cpu_node_t * found = NULL;
460         int i;
461
462         if (CPUMASK_CMPMASKEQ(node->members, mask))
463                 return node;
464
465         for (i = 0; i < node->child_no; i++) {
466                 found = get_cpu_node_by_cpumask(node->child_node[i], mask);
467                 if (found != NULL) {
468                         return found;
469                 }
470         }
471         return NULL;
472 }
473
474 cpu_node_t *
475 get_cpu_node_by_cpuid(int cpuid) {
476         cpumask_t mask;
477
478         CPUMASK_ASSBIT(mask, cpuid);
479
480         KASSERT(cpu_root_node != NULL, ("cpu_root_node isn't initialized"));
481
482         return get_cpu_node_by_cpumask(cpu_root_node, mask);
483 }
484
485 /* Get the mask of siblings for level_type of a cpuid */
486 cpumask_t
487 get_cpumask_from_level(int cpuid,
488                         uint8_t level_type)
489 {
490         cpu_node_t * node;
491         cpumask_t mask;
492
493         CPUMASK_ASSBIT(mask, cpuid);
494
495         KASSERT(cpu_root_node != NULL, ("cpu_root_node isn't initialized"));
496
497         node = get_cpu_node_by_cpumask(cpu_root_node, mask);
498
499         if (node == NULL) {
500                 CPUMASK_ASSZERO(mask);
501                 return mask;
502         }
503
504         while (node != NULL) {
505                 if (node->type == level_type) {
506                         return node->members;
507                 }
508                 node = node->parent_node;
509         }
510         CPUMASK_ASSZERO(mask);
511
512         return mask;
513 }
514
515 static const cpu_node_t *
516 get_cpu_node_by_chipid2(const cpu_node_t *node, int chip_id)
517 {
518         int cpuid;
519
520         if (node->type != CHIP_LEVEL) {
521                 const cpu_node_t *ret = NULL;
522                 int i;
523
524                 for (i = 0; i < node->child_no; ++i) {
525                         ret = get_cpu_node_by_chipid2(node->child_node[i],
526                             chip_id);
527                         if (ret != NULL)
528                                 break;
529                 }
530                 return ret;
531         }
532
533         cpuid = BSRCPUMASK(node->members);
534         if (get_chip_ID(cpuid) == chip_id)
535                 return node;
536         return NULL;
537 }
538
539 const cpu_node_t *
540 get_cpu_node_by_chipid(int chip_id)
541 {
542         KASSERT(cpu_root_node != NULL, ("cpu_root_node isn't initialized"));
543         return get_cpu_node_by_chipid2(cpu_root_node, chip_id);
544 }
545
546 /* init pcpu_sysctl structure info */
547 static void
548 init_pcpu_topology_sysctl(int assumed_ncpus)
549 {
550         struct sbuf sb;
551         cpumask_t mask;
552         int min_id = -1;
553         int max_id = -1;
554         int i;
555         int phys_id;
556
557         pcpu_sysctl = kmalloc(sizeof(*pcpu_sysctl) * MAXCPU, M_PCPUSYS,
558                               M_INTWAIT | M_ZERO);
559
560         for (i = 0; i < assumed_ncpus; i++) {
561                 sbuf_new(&sb, pcpu_sysctl[i].cpu_name,
562                     sizeof(pcpu_sysctl[i].cpu_name), SBUF_FIXEDLEN);
563                 sbuf_printf(&sb,"cpu%d", i);
564                 sbuf_finish(&sb);
565
566
567                 /* Get physical siblings */
568                 mask = get_cpumask_from_level(i, CHIP_LEVEL);
569                 if (CPUMASK_TESTZERO(mask)) {
570                         pcpu_sysctl[i].physical_id = INVALID_ID;
571                         continue;
572                 }
573
574                 sbuf_new(&sb, pcpu_sysctl[i].physical_siblings,
575                     sizeof(pcpu_sysctl[i].physical_siblings), SBUF_FIXEDLEN);
576                 sbuf_print_cpuset(&sb, &mask);
577                 sbuf_trim(&sb);
578                 sbuf_finish(&sb);
579
580                 phys_id = get_chip_ID(i);
581                 pcpu_sysctl[i].physical_id = phys_id;
582                 if (min_id < 0 || min_id > phys_id)
583                         min_id = phys_id;
584                 if (max_id < 0 || max_id < phys_id)
585                         max_id = phys_id;
586
587                 /* Get core siblings */
588                 mask = get_cpumask_from_level(i, CORE_LEVEL);
589                 if (CPUMASK_TESTZERO(mask)) {
590                         pcpu_sysctl[i].core_id = INVALID_ID;
591                         continue;
592                 }
593
594                 sbuf_new(&sb, pcpu_sysctl[i].core_siblings,
595                     sizeof(pcpu_sysctl[i].core_siblings), SBUF_FIXEDLEN);
596                 sbuf_print_cpuset(&sb, &mask);
597                 sbuf_trim(&sb);
598                 sbuf_finish(&sb);
599
600                 pcpu_sysctl[i].core_id = get_core_number_within_chip(i);
601                 if (cpu_topology_core_ids < pcpu_sysctl[i].core_id + 1)
602                         cpu_topology_core_ids = pcpu_sysctl[i].core_id + 1;
603
604                 pcpu_sysctl[i].ht_id = get_logical_CPU_number_within_core(i);
605                 if (cpu_topology_ht_ids < pcpu_sysctl[i].ht_id + 1)
606                         cpu_topology_ht_ids = pcpu_sysctl[i].ht_id + 1;
607         }
608
609         /*
610          * Normalize physical ids so they can be used by the VM system.
611          * Some systems number starting at 0 others number starting at 1.
612          */
613         cpu_topology_phys_ids = max_id - min_id + 1;
614         if (cpu_topology_phys_ids <= 0)         /* don't crash */
615                 cpu_topology_phys_ids = 1;
616         for (i = 0; i < assumed_ncpus; i++) {
617                 pcpu_sysctl[i].physical_id %= cpu_topology_phys_ids;
618         }
619 }
620
621 /* Build SYSCTL structure for revealing
622  * the CPU Topology to user-space.
623  */
624 static void
625 build_sysctl_cpu_topology(int assumed_ncpus)
626 {
627         int i;
628         struct sbuf sb;
629         
630         /* SYSCTL new leaf for "cpu_topology" */
631         sysctl_ctx_init(&cpu_topology_sysctl_ctx);
632         cpu_topology_sysctl_tree = SYSCTL_ADD_NODE(&cpu_topology_sysctl_ctx,
633             SYSCTL_STATIC_CHILDREN(_hw),
634             OID_AUTO,
635             "cpu_topology",
636             CTLFLAG_RD, 0, "");
637
638         /* SYSCTL cpu_topology "tree" entry */
639         SYSCTL_ADD_PROC(&cpu_topology_sysctl_ctx,
640             SYSCTL_CHILDREN(cpu_topology_sysctl_tree),
641             OID_AUTO, "tree", CTLTYPE_STRING | CTLFLAG_RD,
642             NULL, 0, print_cpu_topology_tree_sysctl, "A",
643             "Tree print of CPU topology");
644
645         /* SYSCTL cpu_topology "level_description" entry */
646         SYSCTL_ADD_PROC(&cpu_topology_sysctl_ctx,
647             SYSCTL_CHILDREN(cpu_topology_sysctl_tree),
648             OID_AUTO, "level_description", CTLTYPE_STRING | CTLFLAG_RD,
649             NULL, 0, print_cpu_topology_level_description_sysctl, "A",
650             "Level description of CPU topology");
651
652         /* SYSCTL cpu_topology "members" entry */
653         sbuf_new(&sb, cpu_topology_members,
654             sizeof(cpu_topology_members), SBUF_FIXEDLEN);
655         sbuf_print_cpuset(&sb, &cpu_root_node->members);
656         sbuf_trim(&sb);
657         sbuf_finish(&sb);
658         SYSCTL_ADD_STRING(&cpu_topology_sysctl_ctx,
659             SYSCTL_CHILDREN(cpu_topology_sysctl_tree),
660             OID_AUTO, "members", CTLFLAG_RD,
661             cpu_topology_members, 0,
662             "Members of the CPU Topology");
663
664         /* SYSCTL per_cpu info */
665         for (i = 0; i < assumed_ncpus; i++) {
666                 /* New leaf : hw.cpu_topology.cpux */
667                 sysctl_ctx_init(&pcpu_sysctl[i].sysctl_ctx); 
668                 pcpu_sysctl[i].sysctl_tree = SYSCTL_ADD_NODE(&pcpu_sysctl[i].sysctl_ctx,
669                     SYSCTL_CHILDREN(cpu_topology_sysctl_tree),
670                     OID_AUTO,
671                     pcpu_sysctl[i].cpu_name,
672                     CTLFLAG_RD, 0, "");
673
674                 /* Check if the physical_id found is valid */
675                 if (pcpu_sysctl[i].physical_id == INVALID_ID) {
676                         continue;
677                 }
678
679                 /* Add physical id info */
680                 SYSCTL_ADD_INT(&pcpu_sysctl[i].sysctl_ctx,
681                     SYSCTL_CHILDREN(pcpu_sysctl[i].sysctl_tree),
682                     OID_AUTO, "physical_id", CTLFLAG_RD,
683                     &pcpu_sysctl[i].physical_id, 0,
684                     "Physical ID");
685
686                 /* Add physical siblings */
687                 SYSCTL_ADD_STRING(&pcpu_sysctl[i].sysctl_ctx,
688                     SYSCTL_CHILDREN(pcpu_sysctl[i].sysctl_tree),
689                     OID_AUTO, "physical_siblings", CTLFLAG_RD,
690                     pcpu_sysctl[i].physical_siblings, 0,
691                     "Physical siblings");
692
693                 /* Check if the core_id found is valid */
694                 if (pcpu_sysctl[i].core_id == INVALID_ID) {
695                         continue;
696                 }
697
698                 /* Add core id info */
699                 SYSCTL_ADD_INT(&pcpu_sysctl[i].sysctl_ctx,
700                     SYSCTL_CHILDREN(pcpu_sysctl[i].sysctl_tree),
701                     OID_AUTO, "core_id", CTLFLAG_RD,
702                     &pcpu_sysctl[i].core_id, 0,
703                     "Core ID");
704                 
705                 /*Add core siblings */
706                 SYSCTL_ADD_STRING(&pcpu_sysctl[i].sysctl_ctx,
707                     SYSCTL_CHILDREN(pcpu_sysctl[i].sysctl_tree),
708                     OID_AUTO, "core_siblings", CTLFLAG_RD,
709                     pcpu_sysctl[i].core_siblings, 0,
710                     "Core siblings");
711         }
712 }
713
714 static
715 void
716 sbuf_print_cpuset(struct sbuf *sb, cpumask_t *mask)
717 {
718         int i;
719         int b = -1;
720         int e = -1;
721         int more = 0;
722
723         sbuf_printf(sb, "cpus(");
724         CPUSET_FOREACH(i, *mask) {
725                 if (b < 0) {
726                         b = i;
727                         e = b + 1;
728                         continue;
729                 }
730                 if (e == i) {
731                         ++e;
732                         continue;
733                 }
734                 if (more)
735                         sbuf_printf(sb, ", ");
736                 if (b == e - 1) {
737                         sbuf_printf(sb, "%d", b);
738                 } else {
739                         sbuf_printf(sb, "%d-%d", b, e - 1);
740                 }
741                 more = 1;
742                 b = i;
743                 e = b + 1;
744         }
745         if (more)
746                 sbuf_printf(sb, ", ");
747         if (b >= 0) {
748                 if (b == e - 1) {
749                         sbuf_printf(sb, "%d", b);
750                 } else {
751                         sbuf_printf(sb, "%d-%d", b, e - 1);
752                 }
753         }
754         sbuf_printf(sb, ") ");
755 }
756
757 int
758 get_cpu_ht_id(int cpuid)
759 {
760         if (pcpu_sysctl)
761                 return(pcpu_sysctl[cpuid].ht_id);
762         return(0);
763 }
764
765 int
766 get_cpu_core_id(int cpuid)
767 {
768         if (pcpu_sysctl)
769                 return(pcpu_sysctl[cpuid].core_id);
770         return(0);
771 }
772
773 int
774 get_cpu_phys_id(int cpuid)
775 {
776         if (pcpu_sysctl)
777                 return(pcpu_sysctl[cpuid].physical_id);
778         return(0);
779 }
780
781 /*
782  * Returns the highest amount of memory attached to any single node.
783  * Returns 0 if the system is not NUMA or only has one node.
784  *
785  * This function is used by the scheduler.
786  */
787 long
788 get_highest_node_memory(void)
789 {
790         long highest = 0;
791
792         if (cpu_root_node && cpu_root_node->type == PACKAGE_LEVEL &&
793             cpu_root_node->child_node[1]) {
794                 cpu_node_t *cpup;
795                 int i;
796
797                 for (i = 0 ; i < MAXCPU && cpu_root_node->child_node[i]; ++i) {
798                         cpup = cpu_root_node->child_node[i];
799                         if (highest < cpup->phys_mem)
800                                 highest = cpup->phys_mem;
801                 }
802         }
803         return highest;
804 }
805
806 extern int naps;
807
808 /* Build the CPU Topology and SYSCTL Topology tree */
809 static void
810 init_cpu_topology(void)
811 {
812         int assumed_ncpus;
813
814         assumed_ncpus = naps + 1;
815
816         build_cpu_topology(assumed_ncpus);
817         init_pcpu_topology_sysctl(assumed_ncpus);
818         build_sysctl_cpu_topology(assumed_ncpus);
819 }
820 SYSINIT(cpu_topology, SI_BOOT2_CPU_TOPOLOGY, SI_ORDER_FIRST,
821     init_cpu_topology, NULL);