xref: /netbsd/sys/arch/x86/x86/cpu_topology.c (revision 6550d01e)
1 /*	$NetBSD: cpu_topology.c,v 1.6 2010/05/29 05:53:57 rmind Exp $	*/
2 
3 /*-
4  * Copyright (c) 2009 Mindaugas Rasiukevicius <rmind at NetBSD org>,
5  * Copyright (c) 2008 YAMAMOTO Takashi,
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
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 the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29 
30 /*
31  * x86 CPU topology detection.
32  *
33  * References:
34  * - 53668.pdf (7.10.2), 276613.pdf
35  * - 31116.pdf, 41256.pdf, 25481.pdf
36  */
37 
38 #include <sys/cdefs.h>
39 __KERNEL_RCSID(0, "$NetBSD: cpu_topology.c,v 1.6 2010/05/29 05:53:57 rmind Exp $");
40 
41 #include <sys/param.h>
42 #include <sys/bitops.h>
43 
44 #include <machine/specialreg.h>
45 #include <machine/cpu.h>
46 
47 #include <x86/cpufunc.h>
48 #include <x86/cputypes.h>
49 #include <x86/cpuvar.h>
50 
51 void
52 x86_cpu_topology(struct cpu_info *ci)
53 {
54 	u_int lp_max;		/* Logical processors per package (node) */
55 	u_int core_max;		/* Core per package */
56 	int n, cpu_family, apic_id, smt_bits, core_bits = 0;
57 	uint32_t descs[4], lextmode;
58 
59 	apic_id = ci->ci_initapicid;
60 	cpu_family = CPUID2FAMILY(ci->ci_signature);
61 
62 	/* Initial values. */
63 	ci->ci_package_id = apic_id;
64 	ci->ci_core_id = 0;
65 	ci->ci_smt_id = 0;
66 
67 	switch (cpu_vendor) {
68 	case CPUVENDOR_INTEL:
69 		if (cpu_family < 6)
70 			return;
71 		break;
72 	case CPUVENDOR_AMD:
73 		if (cpu_family < 0xf)
74 			return;
75 		break;
76 	default:
77 		return;
78 	}
79 
80 	/* Determine the extended feature flags. */
81 	x86_cpuid(0x80000000, descs);
82 	lextmode = descs[0];
83 	if (lextmode >= 0x80000001) {
84 		x86_cpuid(0x80000001, descs);
85 		ci->ci_feat_val[2] = descs[3]; /* edx */
86 		ci->ci_feat_val[3] = descs[2]; /* ecx */
87 	}
88 
89 	/* Check for HTT support.  See notes below regarding AMD. */
90 	if ((ci->ci_feat_val[0] & CPUID_HTT) != 0) {
91 		/* Maximum number of LPs sharing a cache (ebx[23:16]). */
92 		x86_cpuid(1, descs);
93 		lp_max = (descs[1] >> 16) & 0xff;
94 	} else {
95 		lp_max = 1;
96 	}
97 
98 	switch (cpu_vendor) {
99 	case CPUVENDOR_INTEL:
100 		/* Check for leaf 4 support. */
101 		x86_cpuid(0, descs);
102 		if (descs[0] >= 4) {
103 			/* Maximum number of Cores per package (eax[31:26]). */
104 			x86_cpuid2(4, 0, descs);
105 			core_max = (descs[0] >> 26) + 1;
106 		} else {
107 			core_max = 1;
108 		}
109 		break;
110 	case CPUVENDOR_AMD:
111 		/* In a case of AMD, HTT flag means CMP support. */
112 		if ((ci->ci_feat_val[0] & CPUID_HTT) == 0) {
113 			core_max = 1;
114 			break;
115 		}
116 		/* Legacy Method, LPs represent Cores. */
117 		if (cpu_family < 0x10 || lextmode < 0x80000008) {
118 			core_max = lp_max;
119 			break;
120 		}
121 		/* Number of Cores (NC) per package (ecx[7:0]). */
122 		x86_cpuid(0x80000008, descs);
123 		core_max = (descs[2] & 0xff) + 1;
124 		/* Amount of bits representing Core ID (ecx[15:12]). */
125 		n = (descs[2] >> 12) & 0x0f;
126 		if (n != 0) {
127 			/*
128 			 * Extended Method.
129 			 * core_bits = 2 ^ n (power of two)
130 			 */
131 			core_bits = 1 << n;
132 		}
133 		break;
134 	default:
135 		core_max = 1;
136 	}
137 
138 	KASSERT(lp_max >= core_max);
139 	smt_bits = ilog2((lp_max / core_max) - 1) + 1;
140 	if (core_bits == 0) {
141 		core_bits = ilog2(core_max - 1) + 1;
142 	}
143 
144 	/*
145 	 * Family 0xf and 0x10 processors may have different structure of
146 	 * APIC ID.  Detect that via special MSR register and move the bits,
147 	 * if necessary (ref: InitApicIdCpuIdLo).
148 	 */
149 	if (cpu_vendor == CPUVENDOR_AMD && cpu_family < 0x11) {	/* XXX */
150 		const uint64_t reg = rdmsr(MSR_NB_CFG);
151 		if ((reg & NB_CFG_INITAPICCPUIDLO) == 0) {
152 			/*
153 			 * 0xf:  { CoreId, NodeId[2:0] }
154 			 * 0x10: { CoreId[1:0], 000b, NodeId[2:0] }
155 			 */
156 			const u_int node_id = apic_id & __BITS(0, 2);
157 			apic_id = (cpu_family == 0xf) ?
158 			    (apic_id >> core_bits) | (node_id << core_bits) :
159 			    (apic_id >> 5) | (node_id << 2);
160 		}
161 	}
162 
163 	if (smt_bits + core_bits) {
164 		ci->ci_package_id = apic_id >> (smt_bits + core_bits);
165 	}
166 	if (core_bits) {
167 		u_int core_mask = __BITS(smt_bits, smt_bits + core_bits - 1);
168 		ci->ci_core_id = __SHIFTOUT(apic_id, core_mask);
169 	}
170 	if (smt_bits) {
171 		u_int smt_mask = __BITS(0, smt_bits - 1);
172 		ci->ci_smt_id = __SHIFTOUT(apic_id, smt_mask);
173 	}
174 }
175