1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright (c) 2008 Joseph Koshy
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29 /*
30 * Common code for handling Intel CPUs.
31 */
32
33 #include <sys/cdefs.h>
34 #include <sys/param.h>
35 #include <sys/pmc.h>
36 #include <sys/pmckern.h>
37 #include <sys/systm.h>
38
39 #include <machine/cpu.h>
40 #include <machine/cputypes.h>
41 #include <machine/md_var.h>
42 #include <machine/specialreg.h>
43
44 static int
intel_switch_in(struct pmc_cpu * pc,struct pmc_process * pp)45 intel_switch_in(struct pmc_cpu *pc, struct pmc_process *pp)
46 {
47 (void) pc;
48
49 PMCDBG3(MDP,SWI,1, "pc=%p pp=%p enable-msr=%d", pc, pp,
50 pp->pp_flags & PMC_PP_ENABLE_MSR_ACCESS);
51
52 /* allow the RDPMC instruction if needed */
53 if (pp->pp_flags & PMC_PP_ENABLE_MSR_ACCESS)
54 load_cr4(rcr4() | CR4_PCE);
55
56 PMCDBG1(MDP,SWI,1, "cr4=0x%jx", (uintmax_t) rcr4());
57
58 return 0;
59 }
60
61 static int
intel_switch_out(struct pmc_cpu * pc,struct pmc_process * pp)62 intel_switch_out(struct pmc_cpu *pc, struct pmc_process *pp)
63 {
64 (void) pc;
65 (void) pp; /* can be NULL */
66
67 PMCDBG3(MDP,SWO,1, "pc=%p pp=%p cr4=0x%jx", pc, pp,
68 (uintmax_t) rcr4());
69
70 /* always turn off the RDPMC instruction */
71 load_cr4(rcr4() & ~CR4_PCE);
72
73 return 0;
74 }
75
76 struct pmc_mdep *
pmc_intel_initialize(void)77 pmc_intel_initialize(void)
78 {
79 struct pmc_mdep *pmc_mdep;
80 enum pmc_cputype cputype;
81 int error, family, model, nclasses, ncpus, stepping, verov;
82
83 KASSERT(cpu_vendor_id == CPU_VENDOR_INTEL,
84 ("[intel,%d] Initializing non-intel processor", __LINE__));
85
86 PMCDBG1(MDP,INI,0, "intel-initialize cpuid=0x%x", cpu_id);
87
88 cputype = -1;
89 nclasses = 2;
90 error = 0;
91 verov = 0;
92 family = CPUID_TO_FAMILY(cpu_id);
93 model = CPUID_TO_MODEL(cpu_id);
94 stepping = CPUID_TO_STEPPING(cpu_id);
95
96 snprintf(pmc_cpuid, sizeof(pmc_cpuid), "GenuineIntel-%d-%02X-%X",
97 family, model, stepping);
98
99 switch (cpu_id & 0xF00) {
100 case 0x600:
101 switch (model) {
102 case 0xE:
103 cputype = PMC_CPU_INTEL_CORE;
104 break;
105 case 0xF:
106 /* Per Intel document 315338-020. */
107 if (stepping == 0x7) {
108 cputype = PMC_CPU_INTEL_CORE;
109 verov = 1;
110 } else {
111 cputype = PMC_CPU_INTEL_CORE2;
112 nclasses = 3;
113 }
114 break;
115 case 0x17:
116 cputype = PMC_CPU_INTEL_CORE2EXTREME;
117 nclasses = 3;
118 break;
119 case 0x1A:
120 case 0x1E: /*
121 * Per Intel document 253669-032 9/2009,
122 * pages A-2 and A-57
123 */
124 case 0x1F: /*
125 * Per Intel document 253669-032 9/2009,
126 * pages A-2 and A-57
127 */
128 cputype = PMC_CPU_INTEL_COREI7;
129 nclasses = 5;
130 break;
131 case 0x2E:
132 cputype = PMC_CPU_INTEL_NEHALEM_EX;
133 nclasses = 3;
134 break;
135 case 0x25: /* Per Intel document 253669-033US 12/2009. */
136 case 0x2C: /* Per Intel document 253669-033US 12/2009. */
137 cputype = PMC_CPU_INTEL_WESTMERE;
138 nclasses = 5;
139 break;
140 case 0x2F: /* Westmere-EX, seen in wild */
141 cputype = PMC_CPU_INTEL_WESTMERE_EX;
142 nclasses = 3;
143 break;
144 case 0x2A: /* Per Intel document 253669-039US 05/2011. */
145 cputype = PMC_CPU_INTEL_SANDYBRIDGE;
146 nclasses = 3;
147 break;
148 case 0x2D: /* Per Intel document 253669-044US 08/2012. */
149 cputype = PMC_CPU_INTEL_SANDYBRIDGE_XEON;
150 nclasses = 3;
151 break;
152 case 0x3A: /* Per Intel document 253669-043US 05/2012. */
153 cputype = PMC_CPU_INTEL_IVYBRIDGE;
154 nclasses = 3;
155 break;
156 case 0x3E: /* Per Intel document 325462-045US 01/2013. */
157 cputype = PMC_CPU_INTEL_IVYBRIDGE_XEON;
158 nclasses = 3;
159 break;
160 case 0x3D:
161 case 0x47:
162 cputype = PMC_CPU_INTEL_BROADWELL;
163 nclasses = 3;
164 break;
165 case 0x4f:
166 case 0x56:
167 cputype = PMC_CPU_INTEL_BROADWELL_XEON;
168 nclasses = 3;
169 break;
170 case 0x3C: /* Per Intel document 325462-045US 01/2013. */
171 case 0x45: /* Per Intel document 325462-045US 09/2014. */
172 cputype = PMC_CPU_INTEL_HASWELL;
173 nclasses = 3;
174 break;
175 case 0x3F: /* Per Intel document 325462-045US 09/2014. */
176 case 0x46: /* Per Intel document 325462-045US 09/2014. */
177 /* Should 46 be XEON. probably its own? */
178 cputype = PMC_CPU_INTEL_HASWELL_XEON;
179 nclasses = 3;
180 break;
181 /* Skylake */
182 case 0x4e:
183 case 0x5e:
184 /* Kabylake */
185 case 0x8E: /* Per Intel document 325462-063US July 2017. */
186 case 0x9E: /* Per Intel document 325462-063US July 2017. */
187 /* Cometlake */
188 case 0xA5:
189 case 0xA6:
190 cputype = PMC_CPU_INTEL_SKYLAKE;
191 nclasses = 3;
192 break;
193 case 0x55: /* SDM rev 63 */
194 cputype = PMC_CPU_INTEL_SKYLAKE_XEON;
195 nclasses = 3;
196 break;
197 /* Icelake */
198 case 0x7D:
199 case 0x7E:
200 /* Tigerlake */
201 case 0x8C:
202 case 0x8D:
203 /* Rocketlake */
204 case 0xA7:
205 cputype = PMC_CPU_INTEL_ICELAKE;
206 nclasses = 3;
207 break;
208 case 0x6A:
209 case 0x6C:
210 cputype = PMC_CPU_INTEL_ICELAKE_XEON;
211 nclasses = 3;
212 break;
213 case 0x97:
214 case 0x9A:
215 cputype = PMC_CPU_INTEL_ALDERLAKE;
216 nclasses = 3;
217 break;
218 case 0x1C: /* Per Intel document 320047-002. */
219 case 0x26:
220 case 0x27:
221 case 0x35:
222 case 0x36:
223 cputype = PMC_CPU_INTEL_ATOM;
224 nclasses = 3;
225 break;
226 case 0x37:
227 case 0x4A:
228 case 0x4D: /* Per Intel document 330061-001 01/2014. */
229 case 0x5A:
230 case 0x5D:
231 cputype = PMC_CPU_INTEL_ATOM_SILVERMONT;
232 nclasses = 3;
233 break;
234 case 0x5C: /* Per Intel document 325462-071US 10/2019. */
235 case 0x5F:
236 cputype = PMC_CPU_INTEL_ATOM_GOLDMONT;
237 nclasses = 3;
238 break;
239 case 0x7A:
240 cputype = PMC_CPU_INTEL_ATOM_GOLDMONT_P;
241 nclasses = 3;
242 break;
243 case 0x86:
244 case 0x96:
245 cputype = PMC_CPU_INTEL_ATOM_TREMONT;
246 nclasses = 3;
247 break;
248 }
249 break;
250 }
251
252
253 if ((int) cputype == -1) {
254 printf("pmc: Unknown Intel CPU.\n");
255 return (NULL);
256 }
257
258 /* Allocate base class and initialize machine dependent struct */
259 pmc_mdep = pmc_mdep_alloc(nclasses);
260
261 pmc_mdep->pmd_cputype = cputype;
262 pmc_mdep->pmd_switch_in = intel_switch_in;
263 pmc_mdep->pmd_switch_out = intel_switch_out;
264
265 ncpus = pmc_cpu_max();
266 error = pmc_tsc_initialize(pmc_mdep, ncpus);
267 if (error)
268 goto error;
269
270 MPASS(nclasses >= PMC_MDEP_CLASS_INDEX_IAF);
271 error = pmc_core_initialize(pmc_mdep, ncpus, verov);
272 if (error) {
273 pmc_tsc_finalize(pmc_mdep);
274 goto error;
275 }
276
277 /*
278 * Init the uncore class.
279 */
280 switch (cputype) {
281 /*
282 * Intel Corei7 and Westmere processors.
283 */
284 case PMC_CPU_INTEL_COREI7:
285 case PMC_CPU_INTEL_WESTMERE:
286 #ifdef notyet
287 /*
288 * TODO: re-enable uncore class on these processors.
289 *
290 * The uncore unit was reworked beginning with Sandy Bridge, including
291 * the MSRs required to program it. In particular, we need to:
292 * - Parse the MSR_UNC_CBO_CONFIG MSR for number of C-box units in the
293 * system
294 * - Support reading and writing to ARB and C-box units, depending on
295 * the requested event
296 * - Create some kind of mapping between C-box <--> CPU
297 *
298 * Also TODO: support other later changes to these interfaces, to
299 * enable the uncore class on generations newer than Broadwell.
300 * Skylake+ appears to use newer addresses for the uncore MSRs.
301 */
302 case PMC_CPU_INTEL_HASWELL:
303 case PMC_CPU_INTEL_BROADWELL:
304 case PMC_CPU_INTEL_SANDYBRIDGE:
305 #endif
306 MPASS(nclasses >= PMC_MDEP_CLASS_INDEX_UCF);
307 error = pmc_uncore_initialize(pmc_mdep, ncpus);
308 break;
309 default:
310 break;
311 }
312 error:
313 if (error) {
314 pmc_mdep_free(pmc_mdep);
315 pmc_mdep = NULL;
316 }
317
318 return (pmc_mdep);
319 }
320
321 void
pmc_intel_finalize(struct pmc_mdep * md)322 pmc_intel_finalize(struct pmc_mdep *md)
323 {
324 pmc_tsc_finalize(md);
325
326 pmc_core_finalize(md);
327
328 /*
329 * Uncore.
330 */
331 switch (md->pmd_cputype) {
332 case PMC_CPU_INTEL_COREI7:
333 case PMC_CPU_INTEL_WESTMERE:
334 #ifdef notyet
335 case PMC_CPU_INTEL_HASWELL:
336 case PMC_CPU_INTEL_BROADWELL:
337 case PMC_CPU_INTEL_SANDYBRIDGE:
338 #endif
339 pmc_uncore_finalize(md);
340 break;
341 default:
342 break;
343 }
344 }
345