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 cputype = PMC_CPU_INTEL_ALDERLAKE; 215 nclasses = 3; 216 break; 217 case 0x1C: /* Per Intel document 320047-002. */ 218 case 0x26: 219 case 0x27: 220 case 0x35: 221 case 0x36: 222 cputype = PMC_CPU_INTEL_ATOM; 223 nclasses = 3; 224 break; 225 case 0x37: 226 case 0x4A: 227 case 0x4D: /* Per Intel document 330061-001 01/2014. */ 228 case 0x5A: 229 case 0x5D: 230 cputype = PMC_CPU_INTEL_ATOM_SILVERMONT; 231 nclasses = 3; 232 break; 233 case 0x5C: /* Per Intel document 325462-071US 10/2019. */ 234 case 0x5F: 235 cputype = PMC_CPU_INTEL_ATOM_GOLDMONT; 236 nclasses = 3; 237 break; 238 case 0x7A: 239 cputype = PMC_CPU_INTEL_ATOM_GOLDMONT_P; 240 nclasses = 3; 241 break; 242 case 0x86: 243 case 0x96: 244 cputype = PMC_CPU_INTEL_ATOM_TREMONT; 245 nclasses = 3; 246 break; 247 } 248 break; 249 } 250 251 252 if ((int) cputype == -1) { 253 printf("pmc: Unknown Intel CPU.\n"); 254 return (NULL); 255 } 256 257 /* Allocate base class and initialize machine dependent struct */ 258 pmc_mdep = pmc_mdep_alloc(nclasses); 259 260 pmc_mdep->pmd_cputype = cputype; 261 pmc_mdep->pmd_switch_in = intel_switch_in; 262 pmc_mdep->pmd_switch_out = intel_switch_out; 263 264 ncpus = pmc_cpu_max(); 265 error = pmc_tsc_initialize(pmc_mdep, ncpus); 266 if (error) 267 goto error; 268 269 MPASS(nclasses >= PMC_MDEP_CLASS_INDEX_IAF); 270 error = pmc_core_initialize(pmc_mdep, ncpus, verov); 271 if (error) { 272 pmc_tsc_finalize(pmc_mdep); 273 goto error; 274 } 275 276 /* 277 * Init the uncore class. 278 */ 279 switch (cputype) { 280 /* 281 * Intel Corei7 and Westmere processors. 282 */ 283 case PMC_CPU_INTEL_COREI7: 284 case PMC_CPU_INTEL_WESTMERE: 285 #ifdef notyet 286 /* 287 * TODO: re-enable uncore class on these processors. 288 * 289 * The uncore unit was reworked beginning with Sandy Bridge, including 290 * the MSRs required to program it. In particular, we need to: 291 * - Parse the MSR_UNC_CBO_CONFIG MSR for number of C-box units in the 292 * system 293 * - Support reading and writing to ARB and C-box units, depending on 294 * the requested event 295 * - Create some kind of mapping between C-box <--> CPU 296 * 297 * Also TODO: support other later changes to these interfaces, to 298 * enable the uncore class on generations newer than Broadwell. 299 * Skylake+ appears to use newer addresses for the uncore MSRs. 300 */ 301 case PMC_CPU_INTEL_HASWELL: 302 case PMC_CPU_INTEL_BROADWELL: 303 case PMC_CPU_INTEL_SANDYBRIDGE: 304 #endif 305 MPASS(nclasses >= PMC_MDEP_CLASS_INDEX_UCF); 306 error = pmc_uncore_initialize(pmc_mdep, ncpus); 307 break; 308 default: 309 break; 310 } 311 error: 312 if (error) { 313 pmc_mdep_free(pmc_mdep); 314 pmc_mdep = NULL; 315 } 316 317 return (pmc_mdep); 318 } 319 320 void 321 pmc_intel_finalize(struct pmc_mdep *md) 322 { 323 pmc_tsc_finalize(md); 324 325 pmc_core_finalize(md); 326 327 /* 328 * Uncore. 329 */ 330 switch (md->pmd_cputype) { 331 case PMC_CPU_INTEL_COREI7: 332 case PMC_CPU_INTEL_WESTMERE: 333 #ifdef notyet 334 case PMC_CPU_INTEL_HASWELL: 335 case PMC_CPU_INTEL_BROADWELL: 336 case PMC_CPU_INTEL_SANDYBRIDGE: 337 #endif 338 pmc_uncore_finalize(md); 339 break; 340 default: 341 break; 342 } 343 } 344