2 * Copyright (c) 2012 The DragonFly Project. All rights reserved.
4 * This code is derived from software contributed to The DragonFly Project
5 * by Matthew Dillon <dillon@backplane.com>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
17 * 3. Neither the name of The DragonFly Project nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific, prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38 #include <sys/param.h>
39 #include <sys/systm.h>
40 #include <sys/kernel.h>
41 #include <sys/sysctl.h>
42 #include <sys/malloc.h>
43 #include <sys/memrange.h>
44 #include <sys/cons.h> /* cngetc() */
45 #include <sys/machintr.h>
47 #include <sys/mplock2.h>
55 #include <machine/smp.h>
56 #include <machine_base/apic/apicreg.h>
57 #include <machine/atomic.h>
58 #include <machine/cpufunc.h>
59 #include <machine/cputypes.h>
60 #include <machine_base/apic/lapic.h>
61 #include <machine_base/apic/ioapic.h>
62 #include <machine/psl.h>
63 #include <machine/segments.h>
64 #include <machine/tss.h>
65 #include <machine/specialreg.h>
66 #include <machine/globaldata.h>
67 #include <machine/pmap_inval.h>
69 static cpu_node_t cpu_topology_nodes[MAXCPU];
70 static cpu_node_t *cpu_root_node;
72 static int print_cpu_topology_tree_sysctl(SYSCTL_HANDLER_ARGS);
74 /************************************/
75 /* CPU TOPOLOGY BUILDING FUNCTIONS */
76 /************************************/
79 /* Generic topology tree.
80 * @param children_no_per_level : the number of children on each level
81 * @param level_types : the type of the level (THREAD, CORE, CHIP, etc)
82 * @param cur_level : the current level of the tree
83 * @param node : the current node
84 * @param last_free_node : the last free node in the global array.
85 * @param cpuid : basicly this are the ids of the leafs
88 build_topology_tree(int *children_no_per_level,
92 cpu_node_t **last_free_node,
97 node->child_no = children_no_per_level[cur_level];
98 node->type = level_types[cur_level];
101 if (node->child_no == 0) {
102 node->child_node = NULL;
103 node->members = CPUMASK(*cpuid);
108 node->child_node = *last_free_node;
109 (*last_free_node) += node->child_no;
111 for (i = 0; i< node->child_no; i++) {
113 node->child_node[i].parent_node = node;
115 build_topology_tree(children_no_per_level,
118 &(node->child_node[i]),
122 node->members |= node->child_node[i].members;
126 /* Build CPU topology. The detection is made by comparing the
127 * chip,core and logical IDs of each CPU with the IDs of the
128 * BSP. When we found a match, at that level the CPUs are siblings.
131 build_cpu_topology(void)
133 detect_cpu_topology();
137 int threads_per_core = 0;
138 int cores_per_chip = 0;
139 int chips_per_package = 0;
140 int children_no_per_level[LEVEL_NO];
141 uint8_t level_types[LEVEL_NO];
144 cpu_node_t *root = &cpu_topology_nodes[0];
145 cpu_node_t *last_free_node = root + 1;
147 /* Assume that the topology is uniform.
148 * Find the number of siblings within chip
149 * and witin core to build up the topology
151 for (i = 0; i < ncpus; i++) {
153 if (get_chip_ID(BSPID) == get_chip_ID(i)) {
159 if (get_core_number_within_chip(BSPID)
160 == get_core_number_within_chip(i)) {
165 cores_per_chip /= threads_per_core;
166 chips_per_package = ncpus / (cores_per_chip * threads_per_core);
169 * For now we assume that we have a four level topology
171 children_no_per_level[0] = chips_per_package;
172 children_no_per_level[1] = cores_per_chip;
173 children_no_per_level[2] = threads_per_core;
174 children_no_per_level[3] = 0;
176 level_types[0] = PACKAGE_LEVEL;
177 level_types[1] = CHIP_LEVEL;
178 level_types[2] = CORE_LEVEL;
179 level_types[3] = THREAD_LEVEL;
181 build_topology_tree(children_no_per_level,
191 /* Find a cpu_node_t by a mask */
193 get_cpu_node_by_cpumask(cpu_node_t * node,
196 cpu_node_t * found = NULL;
199 if (node->members == mask) {
203 for (i = 0; i < node->child_no; i++) {
204 found = get_cpu_node_by_cpumask(&(node->child_node[i]), mask);
212 /* Get the mask of siblings for level_type of a cpuid */
214 get_cpumask_from_level(cpu_node_t * root,
219 cpumask_t mask = CPUMASK(cpuid);
220 node = get_cpu_node_by_cpumask(root, mask);
224 while (node != NULL) {
225 if (node->type == level_type) {
226 return node->members;
228 node = node->parent_node;
232 static struct sysctl_ctx_list cpu_topology_sysctl_ctx;
233 static struct sysctl_oid *cpu_topology_sysctl_tree;
236 init_cpu_topology(void)
238 cpu_root_node = build_cpu_topology();
240 sysctl_ctx_init(&topology_sysctl_ctx);
242 cpu_topology_sysctl_tree = SYSCTL_ADD_NODE(&sc->acpi_sysctl_ctx,
243 SYSCTL_STATIC_CHILDREN(_hw),
248 SYSCTL_ADD_PROC(&topology_sysctl_ctx, SYSCTL_CHILDREN(cpu_topology_sysctl_tree),
249 OID_AUTO, "tree", CTLTYPE_STRING | CTLFLAG_RD,
250 NULL, 0, print_cpu_topology_tree_sysctl, "A", "Tree print of CPU topology");
255 print_cpu_topology_tree_sysctl_helper(cpu_node_t *node, struct sbuf *sb, char * buf, int buf_len, int last)
257 sbuf_bcat(sb, buf, buf_len);
259 sbuf_printf(sb, "\\-");
260 buf[buf_len] = ' ';buf_len++;
261 buf[buf_len] = ' ';buf_len++;
263 sbuf_printf(sb, "\-");
264 buf[buf_len] = '|';buf_len++;
265 buf[buf_len] = ' ';buf_len++;
267 sbuf_printf(sb,"%d",node->members);
268 for (i = 0; i < node->child_no; i++) {
269 print_cpu_topology_tree_sysctl_helper(node->child_node[i], sb, buf, buf_len, i == (node->childno -1));
273 print_cpu_topology_tree_sysctl(SYSCTL_HANDLER_ARGS)
280 KASSERT(cpu_root_node != NULL, ("cpu_root_node isn't initialized"));
282 sb = sbuf_new(NULL, NULL, 500, SBUF_AUTOEXTEND);
286 print_cpu_topology_tree_sysctl_helper(cpu_root_node, sb, buf, 0, 0);
290 ret = SYSCTL_OUT(req, sbuf_data(sb), sbuf_len(sb));