1f77c018aSMihai Carabas /*
2f77c018aSMihai Carabas * Copyright (c) 2012 The DragonFly Project. All rights reserved.
3f77c018aSMihai Carabas *
4f77c018aSMihai Carabas * Redistribution and use in source and binary forms, with or without
5f77c018aSMihai Carabas * modification, are permitted provided that the following conditions
6f77c018aSMihai Carabas * are met:
7f77c018aSMihai Carabas *
8f77c018aSMihai Carabas * 1. Redistributions of source code must retain the above copyright
9f77c018aSMihai Carabas * notice, this list of conditions and the following disclaimer.
10f77c018aSMihai Carabas * 2. Redistributions in binary form must reproduce the above copyright
11f77c018aSMihai Carabas * notice, this list of conditions and the following disclaimer in
12f77c018aSMihai Carabas * the documentation and/or other materials provided with the
13f77c018aSMihai Carabas * distribution.
14f77c018aSMihai Carabas * 3. Neither the name of The DragonFly Project nor the names of its
15f77c018aSMihai Carabas * contributors may be used to endorse or promote products derived
16f77c018aSMihai Carabas * from this software without specific, prior written permission.
17f77c018aSMihai Carabas *
18f77c018aSMihai Carabas * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19f77c018aSMihai Carabas * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20f77c018aSMihai Carabas * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
21f77c018aSMihai Carabas * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
22f77c018aSMihai Carabas * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
23f77c018aSMihai Carabas * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
24f77c018aSMihai Carabas * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25f77c018aSMihai Carabas * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
26f77c018aSMihai Carabas * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27f77c018aSMihai Carabas * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
28f77c018aSMihai Carabas * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29f77c018aSMihai Carabas * SUCH DAMAGE.
30f77c018aSMihai Carabas */
31f77c018aSMihai Carabas
32f77c018aSMihai Carabas #include <sys/param.h>
33f77c018aSMihai Carabas #include <sys/systm.h>
34f77c018aSMihai Carabas #include <sys/kernel.h>
35e2164e29Szrj #include <sys/malloc.h>
36f77c018aSMihai Carabas #include <sys/sysctl.h>
37f77c018aSMihai Carabas #include <sys/sbuf.h>
38f77c018aSMihai Carabas #include <sys/cpu_topology.h>
39f77c018aSMihai Carabas
40f77c018aSMihai Carabas #include <machine/smp.h>
41f77c018aSMihai Carabas
42f77c018aSMihai Carabas #ifndef NAPICID
43f77c018aSMihai Carabas #define NAPICID 256
44f77c018aSMihai Carabas #endif
45f77c018aSMihai Carabas
46f77c018aSMihai Carabas #define INDENT_BUF_SIZE LEVEL_NO*3
47f77c018aSMihai Carabas #define INVALID_ID -1
48f77c018aSMihai Carabas
49f77c018aSMihai Carabas /* Per-cpu sysctl nodes and info */
50f77c018aSMihai Carabas struct per_cpu_sysctl_info {
51f77c018aSMihai Carabas struct sysctl_ctx_list sysctl_ctx;
52f77c018aSMihai Carabas struct sysctl_oid *sysctl_tree;
53f77c018aSMihai Carabas char cpu_name[32];
54f77c018aSMihai Carabas int physical_id;
55f77c018aSMihai Carabas int core_id;
568e5d7c42SMatthew Dillon int ht_id; /* thread id within core */
57f77c018aSMihai Carabas char physical_siblings[8*MAXCPU];
58f77c018aSMihai Carabas char core_siblings[8*MAXCPU];
59f77c018aSMihai Carabas };
60f77c018aSMihai Carabas typedef struct per_cpu_sysctl_info per_cpu_sysctl_info_t;
61f77c018aSMihai Carabas
62*53a91b8eSMatthew Dillon /* Memory for topology */
63*53a91b8eSMatthew Dillon __read_frequently static cpu_node_t cpu_topology_nodes[MAXCPU];
64*53a91b8eSMatthew Dillon /* Root node pointer */
65*53a91b8eSMatthew Dillon __read_frequently static cpu_node_t *cpu_root_node;
66f77c018aSMihai Carabas
67f77c018aSMihai Carabas static struct sysctl_ctx_list cpu_topology_sysctl_ctx;
68f77c018aSMihai Carabas static struct sysctl_oid *cpu_topology_sysctl_tree;
69f77c018aSMihai Carabas static char cpu_topology_members[8*MAXCPU];
70d8f4ebf4SCharlie Root static per_cpu_sysctl_info_t *pcpu_sysctl;
71399efd7fSMatthew Dillon static void sbuf_print_cpuset(struct sbuf *sb, cpumask_t *mask);
72f77c018aSMihai Carabas
73*53a91b8eSMatthew Dillon __read_frequently int cpu_topology_levels_number = 1;
74*53a91b8eSMatthew Dillon __read_frequently int cpu_topology_ht_ids;
75*53a91b8eSMatthew Dillon __read_frequently int cpu_topology_core_ids;
76*53a91b8eSMatthew Dillon __read_frequently int cpu_topology_phys_ids;
77*53a91b8eSMatthew Dillon __read_frequently cpu_node_t *root_cpu_node;
78f77c018aSMihai Carabas
79d8f4ebf4SCharlie Root MALLOC_DEFINE(M_PCPUSYS, "pcpusys", "pcpu sysctl topology");
80d8f4ebf4SCharlie Root
818e5d7c42SMatthew Dillon SYSCTL_INT(_hw, OID_AUTO, cpu_topology_ht_ids, CTLFLAG_RW,
828e5d7c42SMatthew Dillon &cpu_topology_ht_ids, 0, "# of logical cores per real core");
8333ee48c4SMatthew Dillon SYSCTL_INT(_hw, OID_AUTO, cpu_topology_core_ids, CTLFLAG_RW,
8433ee48c4SMatthew Dillon &cpu_topology_core_ids, 0, "# of real cores per package");
8533ee48c4SMatthew Dillon SYSCTL_INT(_hw, OID_AUTO, cpu_topology_phys_ids, CTLFLAG_RW,
8633ee48c4SMatthew Dillon &cpu_topology_phys_ids, 0, "# of physical packages");
87d8f4ebf4SCharlie Root
88f77c018aSMihai Carabas /* Get the next valid apicid starting
89f77c018aSMihai Carabas * from current apicid (curr_apicid
90f77c018aSMihai Carabas */
91f77c018aSMihai Carabas static int
get_next_valid_apicid(int curr_apicid)92f77c018aSMihai Carabas get_next_valid_apicid(int curr_apicid)
93f77c018aSMihai Carabas {
94f77c018aSMihai Carabas int next_apicid = curr_apicid;
95f77c018aSMihai Carabas do {
96f77c018aSMihai Carabas next_apicid++;
97f77c018aSMihai Carabas }
98f77c018aSMihai Carabas while(get_cpuid_from_apicid(next_apicid) == -1 &&
99f77c018aSMihai Carabas next_apicid < NAPICID);
100f77c018aSMihai Carabas if (next_apicid == NAPICID) {
101f77c018aSMihai Carabas kprintf("Warning: No next valid APICID found. Returning -1\n");
102f77c018aSMihai Carabas return -1;
103f77c018aSMihai Carabas }
104f77c018aSMihai Carabas return next_apicid;
105f77c018aSMihai Carabas }
106f77c018aSMihai Carabas
107f77c018aSMihai Carabas /* Generic topology tree. The parameters have the following meaning:
108f77c018aSMihai Carabas * - children_no_per_level : the number of children on each level
109f77c018aSMihai Carabas * - level_types : the type of the level (THREAD, CORE, CHIP, etc)
110f77c018aSMihai Carabas * - cur_level : the current level of the tree
111f77c018aSMihai Carabas * - node : the current node
112f77c018aSMihai Carabas * - last_free_node : the last free node in the global array.
113f77c018aSMihai Carabas * - cpuid : basicly this are the ids of the leafs
114f77c018aSMihai Carabas */
115f77c018aSMihai Carabas static void
build_topology_tree(int * children_no_per_level,uint8_t * level_types,int cur_level,cpu_node_t * node,cpu_node_t ** last_free_node,int * apicid)116f77c018aSMihai Carabas build_topology_tree(int *children_no_per_level,
117f77c018aSMihai Carabas uint8_t *level_types,
118f77c018aSMihai Carabas int cur_level,
119f77c018aSMihai Carabas cpu_node_t *node,
120f77c018aSMihai Carabas cpu_node_t **last_free_node,
121f77c018aSMihai Carabas int *apicid)
122f77c018aSMihai Carabas {
123f77c018aSMihai Carabas int i;
124f77c018aSMihai Carabas
125f77c018aSMihai Carabas node->child_no = children_no_per_level[cur_level];
126f77c018aSMihai Carabas node->type = level_types[cur_level];
127c07315c4SMatthew Dillon CPUMASK_ASSZERO(node->members);
1280e9325d3SMihai Carabas node->compute_unit_id = -1;
129f77c018aSMihai Carabas
130f77c018aSMihai Carabas if (node->child_no == 0) {
131f77c018aSMihai Carabas *apicid = get_next_valid_apicid(*apicid);
132c07315c4SMatthew Dillon CPUMASK_ASSBIT(node->members, get_cpuid_from_apicid(*apicid));
133f77c018aSMihai Carabas return;
134f77c018aSMihai Carabas }
135f77c018aSMihai Carabas
136e28d8b15SMatthew Dillon if (node->parent_node == NULL)
137e28d8b15SMatthew Dillon root_cpu_node = node;
138f77c018aSMihai Carabas
139f77c018aSMihai Carabas for (i = 0; i < node->child_no; i++) {
1400e9325d3SMihai Carabas node->child_node[i] = *last_free_node;
1410e9325d3SMihai Carabas (*last_free_node)++;
1420e9325d3SMihai Carabas
1430e9325d3SMihai Carabas node->child_node[i]->parent_node = node;
144f77c018aSMihai Carabas
145f77c018aSMihai Carabas build_topology_tree(children_no_per_level,
146f77c018aSMihai Carabas level_types,
147f77c018aSMihai Carabas cur_level + 1,
1480e9325d3SMihai Carabas node->child_node[i],
149f77c018aSMihai Carabas last_free_node,
150f77c018aSMihai Carabas apicid);
151f77c018aSMihai Carabas
152c07315c4SMatthew Dillon CPUMASK_ORMASK(node->members, node->child_node[i]->members);
153f77c018aSMihai Carabas }
154f77c018aSMihai Carabas }
155f77c018aSMihai Carabas
156493a3e86SSascha Wildner #if defined(__x86_64__) && !defined(_KERNEL_VIRTUAL)
157493a3e86SSascha Wildner static void
migrate_elements(cpu_node_t ** a,int n,int pos)158493a3e86SSascha Wildner migrate_elements(cpu_node_t **a, int n, int pos)
159493a3e86SSascha Wildner {
1600e9325d3SMihai Carabas int i;
1610e9325d3SMihai Carabas
1620e9325d3SMihai Carabas for (i = pos; i < n - 1 ; i++) {
1630e9325d3SMihai Carabas a[i] = a[i+1];
1640e9325d3SMihai Carabas }
1650e9325d3SMihai Carabas a[i] = NULL;
1660e9325d3SMihai Carabas }
167493a3e86SSascha Wildner #endif
1680e9325d3SMihai Carabas
169f77c018aSMihai Carabas /* Build CPU topology. The detection is made by comparing the
170f77c018aSMihai Carabas * chip, core and logical IDs of each CPU with the IDs of the
171f77c018aSMihai Carabas * BSP. When we found a match, at that level the CPUs are siblings.
172f77c018aSMihai Carabas */
1730e9325d3SMihai Carabas static void
build_cpu_topology(int assumed_ncpus)174c7f9edd8SMatthew Dillon build_cpu_topology(int assumed_ncpus)
175f77c018aSMihai Carabas {
176f77c018aSMihai Carabas int i;
177f77c018aSMihai Carabas int BSPID = 0;
178f77c018aSMihai Carabas int threads_per_core = 0;
179f77c018aSMihai Carabas int cores_per_chip = 0;
180f77c018aSMihai Carabas int chips_per_package = 0;
181f77c018aSMihai Carabas int children_no_per_level[LEVEL_NO];
182f77c018aSMihai Carabas uint8_t level_types[LEVEL_NO];
183f77c018aSMihai Carabas int apicid = -1;
184f77c018aSMihai Carabas cpu_node_t *root = &cpu_topology_nodes[0];
185f77c018aSMihai Carabas cpu_node_t *last_free_node = root + 1;
186f77c018aSMihai Carabas
1873a3b0c3aSMatthew Dillon detect_cpu_topology();
1883a3b0c3aSMatthew Dillon
1896f2099feSMatthew Dillon /*
1906f2099feSMatthew Dillon * Assume that the topology is uniform.
1919cd8f4f8SMatthew Dillon * Find the number of siblings within the chip
1929cd8f4f8SMatthew Dillon * and within the core to build up the topology.
193f77c018aSMihai Carabas */
194c7f9edd8SMatthew Dillon for (i = 0; i < assumed_ncpus; i++) {
195c07315c4SMatthew Dillon cpumask_t mask;
196f77c018aSMihai Carabas
197c07315c4SMatthew Dillon CPUMASK_ASSBIT(mask, i);
198f77c018aSMihai Carabas
1996f2099feSMatthew Dillon #if 0
2006f2099feSMatthew Dillon /* smp_active_mask has not been initialized yet, ignore */
201c07315c4SMatthew Dillon if (CPUMASK_TESTMASK(mask, smp_active_mask) == 0)
202f77c018aSMihai Carabas continue;
2036f2099feSMatthew Dillon #endif
204f77c018aSMihai Carabas
205c70d4562SMatthew Dillon if (get_chip_ID(BSPID) != get_chip_ID(i))
206f77c018aSMihai Carabas continue;
207c70d4562SMatthew Dillon ++cores_per_chip;
208f77c018aSMihai Carabas
209f77c018aSMihai Carabas if (get_core_number_within_chip(BSPID) ==
210c70d4562SMatthew Dillon get_core_number_within_chip(i)) {
211c70d4562SMatthew Dillon ++threads_per_core;
212c70d4562SMatthew Dillon }
213f77c018aSMihai Carabas }
214f77c018aSMihai Carabas
215f77c018aSMihai Carabas cores_per_chip /= threads_per_core;
216c7f9edd8SMatthew Dillon chips_per_package = assumed_ncpus / (cores_per_chip * threads_per_core);
217f77c018aSMihai Carabas
218c70d4562SMatthew Dillon kprintf("CPU Topology: cores_per_chip: %d; threads_per_core: %d; "
219c70d4562SMatthew Dillon "chips_per_package: %d;\n",
220f77c018aSMihai Carabas cores_per_chip, threads_per_core, chips_per_package);
221f77c018aSMihai Carabas
222f77c018aSMihai Carabas if (threads_per_core > 1) { /* HT available - 4 levels */
223f77c018aSMihai Carabas
224f77c018aSMihai Carabas children_no_per_level[0] = chips_per_package;
225f77c018aSMihai Carabas children_no_per_level[1] = cores_per_chip;
226f77c018aSMihai Carabas children_no_per_level[2] = threads_per_core;
227f77c018aSMihai Carabas children_no_per_level[3] = 0;
228f77c018aSMihai Carabas
229f77c018aSMihai Carabas level_types[0] = PACKAGE_LEVEL;
230f77c018aSMihai Carabas level_types[1] = CHIP_LEVEL;
231f77c018aSMihai Carabas level_types[2] = CORE_LEVEL;
232f77c018aSMihai Carabas level_types[3] = THREAD_LEVEL;
233f77c018aSMihai Carabas
234f77c018aSMihai Carabas build_topology_tree(children_no_per_level,
235f77c018aSMihai Carabas level_types,
236f77c018aSMihai Carabas 0,
237f77c018aSMihai Carabas root,
238f77c018aSMihai Carabas &last_free_node,
239f77c018aSMihai Carabas &apicid);
240f77c018aSMihai Carabas
241f77c018aSMihai Carabas cpu_topology_levels_number = 4;
242f77c018aSMihai Carabas
243f77c018aSMihai Carabas } else if (cores_per_chip > 1) { /* No HT available - 3 levels */
244f77c018aSMihai Carabas
245f77c018aSMihai Carabas children_no_per_level[0] = chips_per_package;
246f77c018aSMihai Carabas children_no_per_level[1] = cores_per_chip;
247f77c018aSMihai Carabas children_no_per_level[2] = 0;
248f77c018aSMihai Carabas
249f77c018aSMihai Carabas level_types[0] = PACKAGE_LEVEL;
250f77c018aSMihai Carabas level_types[1] = CHIP_LEVEL;
251f77c018aSMihai Carabas level_types[2] = CORE_LEVEL;
252f77c018aSMihai Carabas
253f77c018aSMihai Carabas build_topology_tree(children_no_per_level,
254f77c018aSMihai Carabas level_types,
255f77c018aSMihai Carabas 0,
256f77c018aSMihai Carabas root,
257f77c018aSMihai Carabas &last_free_node,
258f77c018aSMihai Carabas &apicid);
259f77c018aSMihai Carabas
260f77c018aSMihai Carabas cpu_topology_levels_number = 3;
261f77c018aSMihai Carabas
262f77c018aSMihai Carabas } else { /* No HT and no Multi-Core - 2 levels */
263f77c018aSMihai Carabas
264f77c018aSMihai Carabas children_no_per_level[0] = chips_per_package;
265f77c018aSMihai Carabas children_no_per_level[1] = 0;
266f77c018aSMihai Carabas
267f77c018aSMihai Carabas level_types[0] = PACKAGE_LEVEL;
268f77c018aSMihai Carabas level_types[1] = CHIP_LEVEL;
269f77c018aSMihai Carabas
270f77c018aSMihai Carabas build_topology_tree(children_no_per_level,
271f77c018aSMihai Carabas level_types,
272f77c018aSMihai Carabas 0,
273f77c018aSMihai Carabas root,
274f77c018aSMihai Carabas &last_free_node,
275f77c018aSMihai Carabas &apicid);
276f77c018aSMihai Carabas
277f77c018aSMihai Carabas cpu_topology_levels_number = 2;
278f77c018aSMihai Carabas
279f77c018aSMihai Carabas }
280f77c018aSMihai Carabas
2810e9325d3SMihai Carabas cpu_root_node = root;
2820e9325d3SMihai Carabas
2830e9325d3SMihai Carabas
284493a3e86SSascha Wildner #if defined(__x86_64__) && !defined(_KERNEL_VIRTUAL)
2850e9325d3SMihai Carabas if (fix_amd_topology() == 0) {
2860e9325d3SMihai Carabas int visited[MAXCPU], i, j, pos, cpuid;
2870e9325d3SMihai Carabas cpu_node_t *leaf, *parent;
2880e9325d3SMihai Carabas
2890e9325d3SMihai Carabas bzero(visited, MAXCPU * sizeof(int));
2900e9325d3SMihai Carabas
291c7f9edd8SMatthew Dillon for (i = 0; i < assumed_ncpus; i++) {
2920e9325d3SMihai Carabas if (visited[i] == 0) {
2930e9325d3SMihai Carabas pos = 0;
2940e9325d3SMihai Carabas visited[i] = 1;
2950e9325d3SMihai Carabas leaf = get_cpu_node_by_cpuid(i);
2960e9325d3SMihai Carabas
2979cd8f4f8SMatthew Dillon KASSERT(leaf != NULL, ("cpu %d NULL node", i));
2980e9325d3SMihai Carabas if (leaf->type == CORE_LEVEL) {
2990e9325d3SMihai Carabas parent = leaf->parent_node;
3000e9325d3SMihai Carabas
3010e9325d3SMihai Carabas last_free_node->child_node[0] = leaf;
3020e9325d3SMihai Carabas last_free_node->child_no = 1;
3030e9325d3SMihai Carabas last_free_node->members = leaf->members;
3040e9325d3SMihai Carabas last_free_node->compute_unit_id = leaf->compute_unit_id;
3050e9325d3SMihai Carabas last_free_node->parent_node = parent;
3060e9325d3SMihai Carabas last_free_node->type = CORE_LEVEL;
3070e9325d3SMihai Carabas
3080e9325d3SMihai Carabas
3090e9325d3SMihai Carabas for (j = 0; j < parent->child_no; j++) {
3100e9325d3SMihai Carabas if (parent->child_node[j] != leaf) {
3110e9325d3SMihai Carabas
3120e9325d3SMihai Carabas cpuid = BSFCPUMASK(parent->child_node[j]->members);
3130e9325d3SMihai Carabas if (visited[cpuid] == 0 &&
3140e9325d3SMihai Carabas parent->child_node[j]->compute_unit_id == leaf->compute_unit_id) {
3150e9325d3SMihai Carabas
3160e9325d3SMihai Carabas last_free_node->child_node[last_free_node->child_no] = parent->child_node[j];
3170e9325d3SMihai Carabas last_free_node->child_no++;
318c07315c4SMatthew Dillon CPUMASK_ORMASK(last_free_node->members, parent->child_node[j]->members);
3190e9325d3SMihai Carabas
3200e9325d3SMihai Carabas parent->child_node[j]->type = THREAD_LEVEL;
3210e9325d3SMihai Carabas parent->child_node[j]->parent_node = last_free_node;
3220e9325d3SMihai Carabas visited[cpuid] = 1;
3230e9325d3SMihai Carabas
3240e9325d3SMihai Carabas migrate_elements(parent->child_node, parent->child_no, j);
3250e9325d3SMihai Carabas parent->child_no--;
3260e9325d3SMihai Carabas j--;
3270e9325d3SMihai Carabas }
3280e9325d3SMihai Carabas } else {
3290e9325d3SMihai Carabas pos = j;
3300e9325d3SMihai Carabas }
3310e9325d3SMihai Carabas }
3320e9325d3SMihai Carabas if (last_free_node->child_no > 1) {
3330e9325d3SMihai Carabas parent->child_node[pos] = last_free_node;
3340e9325d3SMihai Carabas leaf->type = THREAD_LEVEL;
3350e9325d3SMihai Carabas leaf->parent_node = last_free_node;
3360e9325d3SMihai Carabas last_free_node++;
3370e9325d3SMihai Carabas }
3380e9325d3SMihai Carabas }
3390e9325d3SMihai Carabas }
3400e9325d3SMihai Carabas }
3410e9325d3SMihai Carabas }
3420e9325d3SMihai Carabas #endif
343f77c018aSMihai Carabas }
344f77c018aSMihai Carabas
345f77c018aSMihai Carabas /* Recursive function helper to print the CPU topology tree */
346f77c018aSMihai Carabas static void
print_cpu_topology_tree_sysctl_helper(cpu_node_t * node,struct sbuf * sb,char * buf,int buf_len,int last)347f77c018aSMihai Carabas print_cpu_topology_tree_sysctl_helper(cpu_node_t *node,
348f77c018aSMihai Carabas struct sbuf *sb,
349f77c018aSMihai Carabas char * buf,
350f77c018aSMihai Carabas int buf_len,
351f77c018aSMihai Carabas int last)
352f77c018aSMihai Carabas {
353f77c018aSMihai Carabas int i;
354f77c018aSMihai Carabas int bsr_member;
355f77c018aSMihai Carabas
356f77c018aSMihai Carabas sbuf_bcat(sb, buf, buf_len);
357f77c018aSMihai Carabas if (last) {
358f77c018aSMihai Carabas sbuf_printf(sb, "\\-");
359f77c018aSMihai Carabas buf[buf_len] = ' ';buf_len++;
360f77c018aSMihai Carabas buf[buf_len] = ' ';buf_len++;
361f77c018aSMihai Carabas } else {
362f77c018aSMihai Carabas sbuf_printf(sb, "|-");
363f77c018aSMihai Carabas buf[buf_len] = '|';buf_len++;
364f77c018aSMihai Carabas buf[buf_len] = ' ';buf_len++;
365f77c018aSMihai Carabas }
366f77c018aSMihai Carabas
367f77c018aSMihai Carabas bsr_member = BSRCPUMASK(node->members);
368f77c018aSMihai Carabas
369f77c018aSMihai Carabas if (node->type == PACKAGE_LEVEL) {
370f77c018aSMihai Carabas sbuf_printf(sb,"PACKAGE MEMBERS: ");
371f77c018aSMihai Carabas } else if (node->type == CHIP_LEVEL) {
372f77c018aSMihai Carabas sbuf_printf(sb,"CHIP ID %d: ",
373f77c018aSMihai Carabas get_chip_ID(bsr_member));
374f77c018aSMihai Carabas } else if (node->type == CORE_LEVEL) {
3759fc6d334SSascha Wildner if (node->compute_unit_id != (uint8_t)-1) {
3760e9325d3SMihai Carabas sbuf_printf(sb,"Compute Unit ID %d: ",
3770e9325d3SMihai Carabas node->compute_unit_id);
3780e9325d3SMihai Carabas } else {
379f77c018aSMihai Carabas sbuf_printf(sb,"CORE ID %d: ",
380f77c018aSMihai Carabas get_core_number_within_chip(bsr_member));
3810e9325d3SMihai Carabas }
382f77c018aSMihai Carabas } else if (node->type == THREAD_LEVEL) {
3839fc6d334SSascha Wildner if (node->compute_unit_id != (uint8_t)-1) {
384c70d4562SMatthew Dillon sbuf_printf(sb,"THREAD ID %d: ",
3850e9325d3SMihai Carabas get_core_number_within_chip(bsr_member));
3860e9325d3SMihai Carabas } else {
387f77c018aSMihai Carabas sbuf_printf(sb,"THREAD ID %d: ",
388f77c018aSMihai Carabas get_logical_CPU_number_within_core(bsr_member));
3890e9325d3SMihai Carabas }
390f77c018aSMihai Carabas } else {
391f77c018aSMihai Carabas sbuf_printf(sb,"UNKNOWN: ");
392f77c018aSMihai Carabas }
393399efd7fSMatthew Dillon sbuf_print_cpuset(sb, &node->members);
394f77c018aSMihai Carabas sbuf_printf(sb,"\n");
395f77c018aSMihai Carabas
396f77c018aSMihai Carabas for (i = 0; i < node->child_no; i++) {
3970e9325d3SMihai Carabas print_cpu_topology_tree_sysctl_helper(node->child_node[i],
398f77c018aSMihai Carabas sb, buf, buf_len, i == (node->child_no -1));
399f77c018aSMihai Carabas }
400f77c018aSMihai Carabas }
401f77c018aSMihai Carabas
402f77c018aSMihai Carabas /* SYSCTL PROCEDURE for printing the CPU Topology tree */
403f77c018aSMihai Carabas static int
print_cpu_topology_tree_sysctl(SYSCTL_HANDLER_ARGS)404f77c018aSMihai Carabas print_cpu_topology_tree_sysctl(SYSCTL_HANDLER_ARGS)
405f77c018aSMihai Carabas {
406f77c018aSMihai Carabas struct sbuf *sb;
407f77c018aSMihai Carabas int ret;
408f77c018aSMihai Carabas char buf[INDENT_BUF_SIZE];
409f77c018aSMihai Carabas
410f77c018aSMihai Carabas KASSERT(cpu_root_node != NULL, ("cpu_root_node isn't initialized"));
411f77c018aSMihai Carabas
412f77c018aSMihai Carabas sb = sbuf_new(NULL, NULL, 500, SBUF_AUTOEXTEND);
413f77c018aSMihai Carabas if (sb == NULL) {
414f77c018aSMihai Carabas return (ENOMEM);
415f77c018aSMihai Carabas }
416f77c018aSMihai Carabas sbuf_printf(sb,"\n");
417f77c018aSMihai Carabas print_cpu_topology_tree_sysctl_helper(cpu_root_node, sb, buf, 0, 1);
418f77c018aSMihai Carabas
419f77c018aSMihai Carabas sbuf_finish(sb);
420f77c018aSMihai Carabas
421f77c018aSMihai Carabas ret = SYSCTL_OUT(req, sbuf_data(sb), sbuf_len(sb));
422f77c018aSMihai Carabas
423f77c018aSMihai Carabas sbuf_delete(sb);
424f77c018aSMihai Carabas
425f77c018aSMihai Carabas return ret;
426f77c018aSMihai Carabas }
427f77c018aSMihai Carabas
428f77c018aSMihai Carabas /* SYSCTL PROCEDURE for printing the CPU Topology level description */
429f77c018aSMihai Carabas static int
print_cpu_topology_level_description_sysctl(SYSCTL_HANDLER_ARGS)430f77c018aSMihai Carabas print_cpu_topology_level_description_sysctl(SYSCTL_HANDLER_ARGS)
431f77c018aSMihai Carabas {
432f77c018aSMihai Carabas struct sbuf *sb;
433f77c018aSMihai Carabas int ret;
434f77c018aSMihai Carabas
435f77c018aSMihai Carabas sb = sbuf_new(NULL, NULL, 500, SBUF_AUTOEXTEND);
436f77c018aSMihai Carabas if (sb == NULL)
437f77c018aSMihai Carabas return (ENOMEM);
438f77c018aSMihai Carabas
439f77c018aSMihai Carabas if (cpu_topology_levels_number == 4) /* HT available */
440f77c018aSMihai Carabas sbuf_printf(sb, "0 - thread; 1 - core; 2 - socket; 3 - anything");
441f77c018aSMihai Carabas else if (cpu_topology_levels_number == 3) /* No HT available */
442f77c018aSMihai Carabas sbuf_printf(sb, "0 - core; 1 - socket; 2 - anything");
443f77c018aSMihai Carabas else if (cpu_topology_levels_number == 2) /* No HT and no Multi-Core */
444f77c018aSMihai Carabas sbuf_printf(sb, "0 - socket; 1 - anything");
445f77c018aSMihai Carabas else
446f77c018aSMihai Carabas sbuf_printf(sb, "Unknown");
447f77c018aSMihai Carabas
448f77c018aSMihai Carabas sbuf_finish(sb);
449f77c018aSMihai Carabas
450f77c018aSMihai Carabas ret = SYSCTL_OUT(req, sbuf_data(sb), sbuf_len(sb));
451f77c018aSMihai Carabas
452f77c018aSMihai Carabas sbuf_delete(sb);
453f77c018aSMihai Carabas
454f77c018aSMihai Carabas return ret;
455f77c018aSMihai Carabas }
456f77c018aSMihai Carabas
457f77c018aSMihai Carabas /* Find a cpu_node_t by a mask */
458f77c018aSMihai Carabas static cpu_node_t *
get_cpu_node_by_cpumask(cpu_node_t * node,cpumask_t mask)459f77c018aSMihai Carabas get_cpu_node_by_cpumask(cpu_node_t * node,
460f77c018aSMihai Carabas cpumask_t mask) {
461f77c018aSMihai Carabas
462f77c018aSMihai Carabas cpu_node_t * found = NULL;
463f77c018aSMihai Carabas int i;
464f77c018aSMihai Carabas
465c07315c4SMatthew Dillon if (CPUMASK_CMPMASKEQ(node->members, mask))
466f77c018aSMihai Carabas return node;
467f77c018aSMihai Carabas
468f77c018aSMihai Carabas for (i = 0; i < node->child_no; i++) {
4690e9325d3SMihai Carabas found = get_cpu_node_by_cpumask(node->child_node[i], mask);
470f77c018aSMihai Carabas if (found != NULL) {
471f77c018aSMihai Carabas return found;
472f77c018aSMihai Carabas }
473f77c018aSMihai Carabas }
474f77c018aSMihai Carabas return NULL;
475f77c018aSMihai Carabas }
476f77c018aSMihai Carabas
477f77c018aSMihai Carabas cpu_node_t *
get_cpu_node_by_cpuid(int cpuid)478f77c018aSMihai Carabas get_cpu_node_by_cpuid(int cpuid) {
479c07315c4SMatthew Dillon cpumask_t mask;
480c07315c4SMatthew Dillon
481c07315c4SMatthew Dillon CPUMASK_ASSBIT(mask, cpuid);
482f77c018aSMihai Carabas
483f77c018aSMihai Carabas KASSERT(cpu_root_node != NULL, ("cpu_root_node isn't initialized"));
484f77c018aSMihai Carabas
485f77c018aSMihai Carabas return get_cpu_node_by_cpumask(cpu_root_node, mask);
486f77c018aSMihai Carabas }
487f77c018aSMihai Carabas
488f77c018aSMihai Carabas /* Get the mask of siblings for level_type of a cpuid */
489f77c018aSMihai Carabas cpumask_t
get_cpumask_from_level(int cpuid,uint8_t level_type)490f77c018aSMihai Carabas get_cpumask_from_level(int cpuid,
491f77c018aSMihai Carabas uint8_t level_type)
492f77c018aSMihai Carabas {
493f77c018aSMihai Carabas cpu_node_t * node;
494c07315c4SMatthew Dillon cpumask_t mask;
495c07315c4SMatthew Dillon
496c07315c4SMatthew Dillon CPUMASK_ASSBIT(mask, cpuid);
497f77c018aSMihai Carabas
498f77c018aSMihai Carabas KASSERT(cpu_root_node != NULL, ("cpu_root_node isn't initialized"));
499f77c018aSMihai Carabas
500f77c018aSMihai Carabas node = get_cpu_node_by_cpumask(cpu_root_node, mask);
501f77c018aSMihai Carabas
502f77c018aSMihai Carabas if (node == NULL) {
503c07315c4SMatthew Dillon CPUMASK_ASSZERO(mask);
504c07315c4SMatthew Dillon return mask;
505f77c018aSMihai Carabas }
506f77c018aSMihai Carabas
507f77c018aSMihai Carabas while (node != NULL) {
508f77c018aSMihai Carabas if (node->type == level_type) {
509f77c018aSMihai Carabas return node->members;
510f77c018aSMihai Carabas }
511f77c018aSMihai Carabas node = node->parent_node;
512f77c018aSMihai Carabas }
513c07315c4SMatthew Dillon CPUMASK_ASSZERO(mask);
514f77c018aSMihai Carabas
515c07315c4SMatthew Dillon return mask;
516f77c018aSMihai Carabas }
517f77c018aSMihai Carabas
518d452e98bSSepherosa Ziehau static const cpu_node_t *
get_cpu_node_by_chipid2(const cpu_node_t * node,int chip_id)519d452e98bSSepherosa Ziehau get_cpu_node_by_chipid2(const cpu_node_t *node, int chip_id)
520d452e98bSSepherosa Ziehau {
521d452e98bSSepherosa Ziehau int cpuid;
522d452e98bSSepherosa Ziehau
523d452e98bSSepherosa Ziehau if (node->type != CHIP_LEVEL) {
524d452e98bSSepherosa Ziehau const cpu_node_t *ret = NULL;
525d452e98bSSepherosa Ziehau int i;
526d452e98bSSepherosa Ziehau
527d452e98bSSepherosa Ziehau for (i = 0; i < node->child_no; ++i) {
528d452e98bSSepherosa Ziehau ret = get_cpu_node_by_chipid2(node->child_node[i],
529d452e98bSSepherosa Ziehau chip_id);
530d452e98bSSepherosa Ziehau if (ret != NULL)
531d452e98bSSepherosa Ziehau break;
532d452e98bSSepherosa Ziehau }
533d452e98bSSepherosa Ziehau return ret;
534d452e98bSSepherosa Ziehau }
535d452e98bSSepherosa Ziehau
536d452e98bSSepherosa Ziehau cpuid = BSRCPUMASK(node->members);
537d452e98bSSepherosa Ziehau if (get_chip_ID(cpuid) == chip_id)
538d452e98bSSepherosa Ziehau return node;
539d452e98bSSepherosa Ziehau return NULL;
540d452e98bSSepherosa Ziehau }
541d452e98bSSepherosa Ziehau
542d452e98bSSepherosa Ziehau const cpu_node_t *
get_cpu_node_by_chipid(int chip_id)543d452e98bSSepherosa Ziehau get_cpu_node_by_chipid(int chip_id)
544d452e98bSSepherosa Ziehau {
545d452e98bSSepherosa Ziehau KASSERT(cpu_root_node != NULL, ("cpu_root_node isn't initialized"));
546d452e98bSSepherosa Ziehau return get_cpu_node_by_chipid2(cpu_root_node, chip_id);
547d452e98bSSepherosa Ziehau }
548d452e98bSSepherosa Ziehau
549f77c018aSMihai Carabas /* init pcpu_sysctl structure info */
550f77c018aSMihai Carabas static void
init_pcpu_topology_sysctl(int assumed_ncpus)551c7f9edd8SMatthew Dillon init_pcpu_topology_sysctl(int assumed_ncpus)
552f77c018aSMihai Carabas {
553f77c018aSMihai Carabas struct sbuf sb;
5549002b0d5SMatthew Dillon cpumask_t mask;
5559002b0d5SMatthew Dillon int min_id = -1;
5569002b0d5SMatthew Dillon int max_id = -1;
5579002b0d5SMatthew Dillon int i;
5589002b0d5SMatthew Dillon int phys_id;
559f77c018aSMihai Carabas
560d8f4ebf4SCharlie Root pcpu_sysctl = kmalloc(sizeof(*pcpu_sysctl) * MAXCPU, M_PCPUSYS,
561d8f4ebf4SCharlie Root M_INTWAIT | M_ZERO);
562f77c018aSMihai Carabas
563c7f9edd8SMatthew Dillon for (i = 0; i < assumed_ncpus; i++) {
564f77c018aSMihai Carabas sbuf_new(&sb, pcpu_sysctl[i].cpu_name,
565f77c018aSMihai Carabas sizeof(pcpu_sysctl[i].cpu_name), SBUF_FIXEDLEN);
566f77c018aSMihai Carabas sbuf_printf(&sb,"cpu%d", i);
567f77c018aSMihai Carabas sbuf_finish(&sb);
568f77c018aSMihai Carabas
569f77c018aSMihai Carabas
570f77c018aSMihai Carabas /* Get physical siblings */
571f77c018aSMihai Carabas mask = get_cpumask_from_level(i, CHIP_LEVEL);
572c07315c4SMatthew Dillon if (CPUMASK_TESTZERO(mask)) {
573f77c018aSMihai Carabas pcpu_sysctl[i].physical_id = INVALID_ID;
574f77c018aSMihai Carabas continue;
575f77c018aSMihai Carabas }
576f77c018aSMihai Carabas
577f77c018aSMihai Carabas sbuf_new(&sb, pcpu_sysctl[i].physical_siblings,
578f77c018aSMihai Carabas sizeof(pcpu_sysctl[i].physical_siblings), SBUF_FIXEDLEN);
579399efd7fSMatthew Dillon sbuf_print_cpuset(&sb, &mask);
580f77c018aSMihai Carabas sbuf_trim(&sb);
581f77c018aSMihai Carabas sbuf_finish(&sb);
582f77c018aSMihai Carabas
5839002b0d5SMatthew Dillon phys_id = get_chip_ID(i);
5849002b0d5SMatthew Dillon pcpu_sysctl[i].physical_id = phys_id;
5859002b0d5SMatthew Dillon if (min_id < 0 || min_id > phys_id)
5869002b0d5SMatthew Dillon min_id = phys_id;
5879002b0d5SMatthew Dillon if (max_id < 0 || max_id < phys_id)
5889002b0d5SMatthew Dillon max_id = phys_id;
589f77c018aSMihai Carabas
590f77c018aSMihai Carabas /* Get core siblings */
591f77c018aSMihai Carabas mask = get_cpumask_from_level(i, CORE_LEVEL);
592c07315c4SMatthew Dillon if (CPUMASK_TESTZERO(mask)) {
593f77c018aSMihai Carabas pcpu_sysctl[i].core_id = INVALID_ID;
594f77c018aSMihai Carabas continue;
595f77c018aSMihai Carabas }
596f77c018aSMihai Carabas
597f77c018aSMihai Carabas sbuf_new(&sb, pcpu_sysctl[i].core_siblings,
598f77c018aSMihai Carabas sizeof(pcpu_sysctl[i].core_siblings), SBUF_FIXEDLEN);
599399efd7fSMatthew Dillon sbuf_print_cpuset(&sb, &mask);
600f77c018aSMihai Carabas sbuf_trim(&sb);
601f77c018aSMihai Carabas sbuf_finish(&sb);
602f77c018aSMihai Carabas
603f77c018aSMihai Carabas pcpu_sysctl[i].core_id = get_core_number_within_chip(i);
6048e5d7c42SMatthew Dillon if (cpu_topology_core_ids < pcpu_sysctl[i].core_id + 1)
60533ee48c4SMatthew Dillon cpu_topology_core_ids = pcpu_sysctl[i].core_id + 1;
606f77c018aSMihai Carabas
6078e5d7c42SMatthew Dillon pcpu_sysctl[i].ht_id = get_logical_CPU_number_within_core(i);
6088e5d7c42SMatthew Dillon if (cpu_topology_ht_ids < pcpu_sysctl[i].ht_id + 1)
6098e5d7c42SMatthew Dillon cpu_topology_ht_ids = pcpu_sysctl[i].ht_id + 1;
610f77c018aSMihai Carabas }
6119002b0d5SMatthew Dillon
6129002b0d5SMatthew Dillon /*
6139002b0d5SMatthew Dillon * Normalize physical ids so they can be used by the VM system.
6149002b0d5SMatthew Dillon * Some systems number starting at 0 others number starting at 1.
6159002b0d5SMatthew Dillon */
6169002b0d5SMatthew Dillon cpu_topology_phys_ids = max_id - min_id + 1;
6179002b0d5SMatthew Dillon if (cpu_topology_phys_ids <= 0) /* don't crash */
6189002b0d5SMatthew Dillon cpu_topology_phys_ids = 1;
619c7f9edd8SMatthew Dillon for (i = 0; i < assumed_ncpus; i++) {
6209002b0d5SMatthew Dillon pcpu_sysctl[i].physical_id %= cpu_topology_phys_ids;
6219002b0d5SMatthew Dillon }
622f77c018aSMihai Carabas }
623f77c018aSMihai Carabas
624f77c018aSMihai Carabas /* Build SYSCTL structure for revealing
625f77c018aSMihai Carabas * the CPU Topology to user-space.
626f77c018aSMihai Carabas */
627f77c018aSMihai Carabas static void
build_sysctl_cpu_topology(int assumed_ncpus)628c7f9edd8SMatthew Dillon build_sysctl_cpu_topology(int assumed_ncpus)
629f77c018aSMihai Carabas {
630f77c018aSMihai Carabas int i;
631f77c018aSMihai Carabas struct sbuf sb;
632f77c018aSMihai Carabas
633f77c018aSMihai Carabas /* SYSCTL new leaf for "cpu_topology" */
634f77c018aSMihai Carabas sysctl_ctx_init(&cpu_topology_sysctl_ctx);
635f77c018aSMihai Carabas cpu_topology_sysctl_tree = SYSCTL_ADD_NODE(&cpu_topology_sysctl_ctx,
636f77c018aSMihai Carabas SYSCTL_STATIC_CHILDREN(_hw),
637f77c018aSMihai Carabas OID_AUTO,
638f77c018aSMihai Carabas "cpu_topology",
639f77c018aSMihai Carabas CTLFLAG_RD, 0, "");
640f77c018aSMihai Carabas
641f77c018aSMihai Carabas /* SYSCTL cpu_topology "tree" entry */
642f77c018aSMihai Carabas SYSCTL_ADD_PROC(&cpu_topology_sysctl_ctx,
643f77c018aSMihai Carabas SYSCTL_CHILDREN(cpu_topology_sysctl_tree),
644f77c018aSMihai Carabas OID_AUTO, "tree", CTLTYPE_STRING | CTLFLAG_RD,
645f77c018aSMihai Carabas NULL, 0, print_cpu_topology_tree_sysctl, "A",
646f77c018aSMihai Carabas "Tree print of CPU topology");
647f77c018aSMihai Carabas
648f77c018aSMihai Carabas /* SYSCTL cpu_topology "level_description" entry */
649f77c018aSMihai Carabas SYSCTL_ADD_PROC(&cpu_topology_sysctl_ctx,
650f77c018aSMihai Carabas SYSCTL_CHILDREN(cpu_topology_sysctl_tree),
651f77c018aSMihai Carabas OID_AUTO, "level_description", CTLTYPE_STRING | CTLFLAG_RD,
652f77c018aSMihai Carabas NULL, 0, print_cpu_topology_level_description_sysctl, "A",
653f77c018aSMihai Carabas "Level description of CPU topology");
654f77c018aSMihai Carabas
655f77c018aSMihai Carabas /* SYSCTL cpu_topology "members" entry */
656f77c018aSMihai Carabas sbuf_new(&sb, cpu_topology_members,
657f77c018aSMihai Carabas sizeof(cpu_topology_members), SBUF_FIXEDLEN);
658399efd7fSMatthew Dillon sbuf_print_cpuset(&sb, &cpu_root_node->members);
659f77c018aSMihai Carabas sbuf_trim(&sb);
660f77c018aSMihai Carabas sbuf_finish(&sb);
661f77c018aSMihai Carabas SYSCTL_ADD_STRING(&cpu_topology_sysctl_ctx,
662f77c018aSMihai Carabas SYSCTL_CHILDREN(cpu_topology_sysctl_tree),
663f77c018aSMihai Carabas OID_AUTO, "members", CTLFLAG_RD,
664f77c018aSMihai Carabas cpu_topology_members, 0,
665f77c018aSMihai Carabas "Members of the CPU Topology");
666f77c018aSMihai Carabas
667f77c018aSMihai Carabas /* SYSCTL per_cpu info */
668c7f9edd8SMatthew Dillon for (i = 0; i < assumed_ncpus; i++) {
669f77c018aSMihai Carabas /* New leaf : hw.cpu_topology.cpux */
670f77c018aSMihai Carabas sysctl_ctx_init(&pcpu_sysctl[i].sysctl_ctx);
671f77c018aSMihai Carabas pcpu_sysctl[i].sysctl_tree = SYSCTL_ADD_NODE(&pcpu_sysctl[i].sysctl_ctx,
672f77c018aSMihai Carabas SYSCTL_CHILDREN(cpu_topology_sysctl_tree),
673f77c018aSMihai Carabas OID_AUTO,
674f77c018aSMihai Carabas pcpu_sysctl[i].cpu_name,
675f77c018aSMihai Carabas CTLFLAG_RD, 0, "");
676f77c018aSMihai Carabas
677f77c018aSMihai Carabas /* Check if the physical_id found is valid */
678f77c018aSMihai Carabas if (pcpu_sysctl[i].physical_id == INVALID_ID) {
679f77c018aSMihai Carabas continue;
680f77c018aSMihai Carabas }
681f77c018aSMihai Carabas
682f77c018aSMihai Carabas /* Add physical id info */
683f77c018aSMihai Carabas SYSCTL_ADD_INT(&pcpu_sysctl[i].sysctl_ctx,
684f77c018aSMihai Carabas SYSCTL_CHILDREN(pcpu_sysctl[i].sysctl_tree),
685f77c018aSMihai Carabas OID_AUTO, "physical_id", CTLFLAG_RD,
686f77c018aSMihai Carabas &pcpu_sysctl[i].physical_id, 0,
687f77c018aSMihai Carabas "Physical ID");
688f77c018aSMihai Carabas
689f77c018aSMihai Carabas /* Add physical siblings */
690f77c018aSMihai Carabas SYSCTL_ADD_STRING(&pcpu_sysctl[i].sysctl_ctx,
691f77c018aSMihai Carabas SYSCTL_CHILDREN(pcpu_sysctl[i].sysctl_tree),
692f77c018aSMihai Carabas OID_AUTO, "physical_siblings", CTLFLAG_RD,
693f77c018aSMihai Carabas pcpu_sysctl[i].physical_siblings, 0,
694f77c018aSMihai Carabas "Physical siblings");
695f77c018aSMihai Carabas
696f77c018aSMihai Carabas /* Check if the core_id found is valid */
697f77c018aSMihai Carabas if (pcpu_sysctl[i].core_id == INVALID_ID) {
698f77c018aSMihai Carabas continue;
699f77c018aSMihai Carabas }
700f77c018aSMihai Carabas
701f77c018aSMihai Carabas /* Add core id info */
702f77c018aSMihai Carabas SYSCTL_ADD_INT(&pcpu_sysctl[i].sysctl_ctx,
703f77c018aSMihai Carabas SYSCTL_CHILDREN(pcpu_sysctl[i].sysctl_tree),
704f77c018aSMihai Carabas OID_AUTO, "core_id", CTLFLAG_RD,
705f77c018aSMihai Carabas &pcpu_sysctl[i].core_id, 0,
706f77c018aSMihai Carabas "Core ID");
707f77c018aSMihai Carabas
708f77c018aSMihai Carabas /*Add core siblings */
709f77c018aSMihai Carabas SYSCTL_ADD_STRING(&pcpu_sysctl[i].sysctl_ctx,
710f77c018aSMihai Carabas SYSCTL_CHILDREN(pcpu_sysctl[i].sysctl_tree),
711f77c018aSMihai Carabas OID_AUTO, "core_siblings", CTLFLAG_RD,
712f77c018aSMihai Carabas pcpu_sysctl[i].core_siblings, 0,
713f77c018aSMihai Carabas "Core siblings");
714f77c018aSMihai Carabas }
715f77c018aSMihai Carabas }
716f77c018aSMihai Carabas
717399efd7fSMatthew Dillon static
718399efd7fSMatthew Dillon void
sbuf_print_cpuset(struct sbuf * sb,cpumask_t * mask)719399efd7fSMatthew Dillon sbuf_print_cpuset(struct sbuf *sb, cpumask_t *mask)
720399efd7fSMatthew Dillon {
721399efd7fSMatthew Dillon int i;
722399efd7fSMatthew Dillon int b = -1;
723399efd7fSMatthew Dillon int e = -1;
724399efd7fSMatthew Dillon int more = 0;
725399efd7fSMatthew Dillon
726399efd7fSMatthew Dillon sbuf_printf(sb, "cpus(");
727399efd7fSMatthew Dillon CPUSET_FOREACH(i, *mask) {
728399efd7fSMatthew Dillon if (b < 0) {
729399efd7fSMatthew Dillon b = i;
730399efd7fSMatthew Dillon e = b + 1;
731399efd7fSMatthew Dillon continue;
732399efd7fSMatthew Dillon }
733399efd7fSMatthew Dillon if (e == i) {
734399efd7fSMatthew Dillon ++e;
735399efd7fSMatthew Dillon continue;
736399efd7fSMatthew Dillon }
737399efd7fSMatthew Dillon if (more)
738399efd7fSMatthew Dillon sbuf_printf(sb, ", ");
739399efd7fSMatthew Dillon if (b == e - 1) {
740399efd7fSMatthew Dillon sbuf_printf(sb, "%d", b);
741399efd7fSMatthew Dillon } else {
742399efd7fSMatthew Dillon sbuf_printf(sb, "%d-%d", b, e - 1);
743399efd7fSMatthew Dillon }
744399efd7fSMatthew Dillon more = 1;
745399efd7fSMatthew Dillon b = i;
746399efd7fSMatthew Dillon e = b + 1;
747399efd7fSMatthew Dillon }
748399efd7fSMatthew Dillon if (more)
749399efd7fSMatthew Dillon sbuf_printf(sb, ", ");
750399efd7fSMatthew Dillon if (b >= 0) {
75152a4925cSMatthew Dillon if (b == e - 1) {
752399efd7fSMatthew Dillon sbuf_printf(sb, "%d", b);
753399efd7fSMatthew Dillon } else {
754399efd7fSMatthew Dillon sbuf_printf(sb, "%d-%d", b, e - 1);
755399efd7fSMatthew Dillon }
756399efd7fSMatthew Dillon }
757399efd7fSMatthew Dillon sbuf_printf(sb, ") ");
758399efd7fSMatthew Dillon }
759399efd7fSMatthew Dillon
76033ee48c4SMatthew Dillon int
get_cpu_ht_id(int cpuid)7618e5d7c42SMatthew Dillon get_cpu_ht_id(int cpuid)
7628e5d7c42SMatthew Dillon {
7638e5d7c42SMatthew Dillon if (pcpu_sysctl)
7648e5d7c42SMatthew Dillon return(pcpu_sysctl[cpuid].ht_id);
7658e5d7c42SMatthew Dillon return(0);
7668e5d7c42SMatthew Dillon }
7678e5d7c42SMatthew Dillon
7688e5d7c42SMatthew Dillon int
get_cpu_core_id(int cpuid)76933ee48c4SMatthew Dillon get_cpu_core_id(int cpuid)
77033ee48c4SMatthew Dillon {
77133ee48c4SMatthew Dillon if (pcpu_sysctl)
77233ee48c4SMatthew Dillon return(pcpu_sysctl[cpuid].core_id);
77333ee48c4SMatthew Dillon return(0);
77433ee48c4SMatthew Dillon }
77533ee48c4SMatthew Dillon
77633ee48c4SMatthew Dillon int
get_cpu_phys_id(int cpuid)77733ee48c4SMatthew Dillon get_cpu_phys_id(int cpuid)
77833ee48c4SMatthew Dillon {
77933ee48c4SMatthew Dillon if (pcpu_sysctl)
78033ee48c4SMatthew Dillon return(pcpu_sysctl[cpuid].physical_id);
78133ee48c4SMatthew Dillon return(0);
78233ee48c4SMatthew Dillon }
78333ee48c4SMatthew Dillon
784c70d4562SMatthew Dillon /*
785c70d4562SMatthew Dillon * Returns the highest amount of memory attached to any single node.
786c70d4562SMatthew Dillon * Returns 0 if the system is not NUMA or only has one node.
787c70d4562SMatthew Dillon *
788c70d4562SMatthew Dillon * This function is used by the scheduler.
789c70d4562SMatthew Dillon */
790c70d4562SMatthew Dillon long
get_highest_node_memory(void)791c70d4562SMatthew Dillon get_highest_node_memory(void)
792c70d4562SMatthew Dillon {
793c70d4562SMatthew Dillon long highest = 0;
794c70d4562SMatthew Dillon
795c70d4562SMatthew Dillon if (cpu_root_node && cpu_root_node->type == PACKAGE_LEVEL &&
796c70d4562SMatthew Dillon cpu_root_node->child_node[1]) {
797c70d4562SMatthew Dillon cpu_node_t *cpup;
798c70d4562SMatthew Dillon int i;
799c70d4562SMatthew Dillon
800c70d4562SMatthew Dillon for (i = 0 ; i < MAXCPU && cpu_root_node->child_node[i]; ++i) {
801c70d4562SMatthew Dillon cpup = cpu_root_node->child_node[i];
802c70d4562SMatthew Dillon if (highest < cpup->phys_mem)
803c70d4562SMatthew Dillon highest = cpup->phys_mem;
804c70d4562SMatthew Dillon }
805c70d4562SMatthew Dillon }
806c70d4562SMatthew Dillon return highest;
807c70d4562SMatthew Dillon }
808c70d4562SMatthew Dillon
809c7f9edd8SMatthew Dillon extern int naps;
810c7f9edd8SMatthew Dillon
811f77c018aSMihai Carabas /* Build the CPU Topology and SYSCTL Topology tree */
812f77c018aSMihai Carabas static void
init_cpu_topology(void)813f77c018aSMihai Carabas init_cpu_topology(void)
814f77c018aSMihai Carabas {
815c7f9edd8SMatthew Dillon int assumed_ncpus;
816f77c018aSMihai Carabas
817c7f9edd8SMatthew Dillon assumed_ncpus = naps + 1;
818c7f9edd8SMatthew Dillon
819c7f9edd8SMatthew Dillon build_cpu_topology(assumed_ncpus);
820c7f9edd8SMatthew Dillon init_pcpu_topology_sysctl(assumed_ncpus);
821c7f9edd8SMatthew Dillon build_sysctl_cpu_topology(assumed_ncpus);
822f77c018aSMihai Carabas }
823f77c018aSMihai Carabas SYSINIT(cpu_topology, SI_BOOT2_CPU_TOPOLOGY, SI_ORDER_FIRST,
824f3f3eadbSSascha Wildner init_cpu_topology, NULL);
825