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