hwpmc_intel.c revision 206089
1184802Sjkoshy/*- 2184802Sjkoshy * Copyright (c) 2008 Joseph Koshy 3184802Sjkoshy * All rights reserved. 4184802Sjkoshy * 5184802Sjkoshy * Redistribution and use in source and binary forms, with or without 6184802Sjkoshy * modification, are permitted provided that the following conditions 7184802Sjkoshy * are met: 8184802Sjkoshy * 1. Redistributions of source code must retain the above copyright 9184802Sjkoshy * notice, this list of conditions and the following disclaimer. 10184802Sjkoshy * 2. Redistributions in binary form must reproduce the above copyright 11184802Sjkoshy * notice, this list of conditions and the following disclaimer in the 12184802Sjkoshy * documentation and/or other materials provided with the distribution. 13184802Sjkoshy * 14184802Sjkoshy * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15184802Sjkoshy * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16184802Sjkoshy * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17184802Sjkoshy * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18184802Sjkoshy * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19184802Sjkoshy * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20184802Sjkoshy * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21184802Sjkoshy * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22184802Sjkoshy * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23184802Sjkoshy * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24184802Sjkoshy * SUCH DAMAGE. 25184802Sjkoshy */ 26184802Sjkoshy 27184802Sjkoshy/* 28184802Sjkoshy * Common code for handling Intel CPUs. 29184802Sjkoshy */ 30184802Sjkoshy 31184802Sjkoshy#include <sys/cdefs.h> 32184802Sjkoshy__FBSDID("$FreeBSD: head/sys/dev/hwpmc/hwpmc_intel.c 206089 2010-04-02 13:23:49Z fabient $"); 33184802Sjkoshy 34184802Sjkoshy#include <sys/param.h> 35184802Sjkoshy#include <sys/pmc.h> 36184802Sjkoshy#include <sys/pmckern.h> 37184802Sjkoshy#include <sys/systm.h> 38184802Sjkoshy 39184802Sjkoshy#include <machine/cpu.h> 40185341Sjkim#include <machine/cputypes.h> 41184802Sjkoshy#include <machine/md_var.h> 42184802Sjkoshy#include <machine/specialreg.h> 43184802Sjkoshy 44184802Sjkoshystatic int 45184802Sjkoshyintel_switch_in(struct pmc_cpu *pc, struct pmc_process *pp) 46184802Sjkoshy{ 47184802Sjkoshy (void) pc; 48184802Sjkoshy 49184802Sjkoshy PMCDBG(MDP,SWI,1, "pc=%p pp=%p enable-msr=%d", pc, pp, 50184802Sjkoshy pp->pp_flags & PMC_PP_ENABLE_MSR_ACCESS); 51184802Sjkoshy 52184802Sjkoshy /* allow the RDPMC instruction if needed */ 53184802Sjkoshy if (pp->pp_flags & PMC_PP_ENABLE_MSR_ACCESS) 54184802Sjkoshy load_cr4(rcr4() | CR4_PCE); 55184802Sjkoshy 56184802Sjkoshy PMCDBG(MDP,SWI,1, "cr4=0x%jx", (uintmax_t) rcr4()); 57184802Sjkoshy 58184802Sjkoshy return 0; 59184802Sjkoshy} 60184802Sjkoshy 61184802Sjkoshystatic int 62184802Sjkoshyintel_switch_out(struct pmc_cpu *pc, struct pmc_process *pp) 63184802Sjkoshy{ 64184802Sjkoshy (void) pc; 65184802Sjkoshy (void) pp; /* can be NULL */ 66184802Sjkoshy 67184802Sjkoshy PMCDBG(MDP,SWO,1, "pc=%p pp=%p cr4=0x%jx", pc, pp, 68184802Sjkoshy (uintmax_t) rcr4()); 69184802Sjkoshy 70184802Sjkoshy /* always turn off the RDPMC instruction */ 71184802Sjkoshy load_cr4(rcr4() & ~CR4_PCE); 72184802Sjkoshy 73184802Sjkoshy return 0; 74184802Sjkoshy} 75184802Sjkoshy 76184802Sjkoshystruct pmc_mdep * 77184802Sjkoshypmc_intel_initialize(void) 78184802Sjkoshy{ 79184802Sjkoshy struct pmc_mdep *pmc_mdep; 80184802Sjkoshy enum pmc_cputype cputype; 81184802Sjkoshy int error, model, nclasses, ncpus; 82184802Sjkoshy 83185341Sjkim KASSERT(cpu_vendor_id == CPU_VENDOR_INTEL, 84184802Sjkoshy ("[intel,%d] Initializing non-intel processor", __LINE__)); 85184802Sjkoshy 86184802Sjkoshy PMCDBG(MDP,INI,0, "intel-initialize cpuid=0x%x", cpu_id); 87184802Sjkoshy 88184802Sjkoshy cputype = -1; 89184802Sjkoshy nclasses = 2; 90184802Sjkoshy 91185363Sjkoshy model = ((cpu_id & 0xF0000) >> 12) | ((cpu_id & 0xF0) >> 4); 92185363Sjkoshy 93184802Sjkoshy switch (cpu_id & 0xF00) { 94184802Sjkoshy#if defined(__i386__) 95184802Sjkoshy case 0x500: /* Pentium family processors */ 96184802Sjkoshy cputype = PMC_CPU_INTEL_P5; 97184802Sjkoshy break; 98185363Sjkoshy#endif 99184802Sjkoshy case 0x600: /* Pentium Pro, Celeron, Pentium II & III */ 100185363Sjkoshy switch (model) { 101185363Sjkoshy#if defined(__i386__) 102184802Sjkoshy case 0x1: 103184802Sjkoshy cputype = PMC_CPU_INTEL_P6; 104184802Sjkoshy break; 105184802Sjkoshy case 0x3: case 0x5: 106184802Sjkoshy cputype = PMC_CPU_INTEL_PII; 107184802Sjkoshy break; 108185363Sjkoshy case 0x6: case 0x16: 109184802Sjkoshy cputype = PMC_CPU_INTEL_CL; 110184802Sjkoshy break; 111184802Sjkoshy case 0x7: case 0x8: case 0xA: case 0xB: 112184802Sjkoshy cputype = PMC_CPU_INTEL_PIII; 113184802Sjkoshy break; 114184802Sjkoshy case 0x9: case 0xD: 115184802Sjkoshy cputype = PMC_CPU_INTEL_PM; 116184802Sjkoshy break; 117185363Sjkoshy#endif 118185363Sjkoshy case 0xE: 119185363Sjkoshy cputype = PMC_CPU_INTEL_CORE; 120185363Sjkoshy break; 121185363Sjkoshy case 0xF: 122185363Sjkoshy cputype = PMC_CPU_INTEL_CORE2; 123185363Sjkoshy nclasses = 3; 124185363Sjkoshy break; 125185363Sjkoshy case 0x17: 126185363Sjkoshy cputype = PMC_CPU_INTEL_CORE2EXTREME; 127185363Sjkoshy nclasses = 3; 128185363Sjkoshy break; 129185363Sjkoshy case 0x1C: /* Per Intel document 320047-002. */ 130185363Sjkoshy cputype = PMC_CPU_INTEL_ATOM; 131185363Sjkoshy nclasses = 3; 132185363Sjkoshy break; 133187761Sjeff case 0x1A: 134200669Sjkoshy case 0x1E: /* Per Intel document 253669-032 9/2009, pages A-2 and A-57 */ 135200669Sjkoshy case 0x1F: /* Per Intel document 253669-032 9/2009, pages A-2 and A-57 */ 136206089Sfabient case 0x2E: 137187761Sjeff cputype = PMC_CPU_INTEL_COREI7; 138206089Sfabient nclasses = 5; 139187761Sjeff break; 140206089Sfabient case 0x25: /* Per Intel document 253669-033US 12/2009. */ 141206089Sfabient case 0x2C: /* Per Intel document 253669-033US 12/2009. */ 142206089Sfabient cputype = PMC_CPU_INTEL_WESTMERE; 143206089Sfabient nclasses = 5; 144206089Sfabient break; 145184802Sjkoshy } 146184802Sjkoshy break; 147184802Sjkoshy#if defined(__i386__) || defined(__amd64__) 148184802Sjkoshy case 0xF00: /* P4 */ 149184802Sjkoshy if (model >= 0 && model <= 6) /* known models */ 150184802Sjkoshy cputype = PMC_CPU_INTEL_PIV; 151184802Sjkoshy break; 152184802Sjkoshy } 153184802Sjkoshy#endif 154184802Sjkoshy 155184802Sjkoshy if ((int) cputype == -1) { 156184802Sjkoshy printf("pmc: Unknown Intel CPU.\n"); 157184802Sjkoshy return (NULL); 158184802Sjkoshy } 159184802Sjkoshy 160184802Sjkoshy pmc_mdep = malloc(sizeof(struct pmc_mdep) + nclasses * 161184802Sjkoshy sizeof(struct pmc_classdep), M_PMC, M_WAITOK|M_ZERO); 162184802Sjkoshy 163184802Sjkoshy pmc_mdep->pmd_cputype = cputype; 164184802Sjkoshy pmc_mdep->pmd_nclass = nclasses; 165184802Sjkoshy 166184802Sjkoshy pmc_mdep->pmd_switch_in = intel_switch_in; 167184802Sjkoshy pmc_mdep->pmd_switch_out = intel_switch_out; 168184802Sjkoshy 169184802Sjkoshy ncpus = pmc_cpu_max(); 170184802Sjkoshy 171184802Sjkoshy error = pmc_tsc_initialize(pmc_mdep, ncpus); 172184802Sjkoshy if (error) 173184802Sjkoshy goto error; 174184802Sjkoshy 175184802Sjkoshy switch (cputype) { 176184802Sjkoshy#if defined(__i386__) || defined(__amd64__) 177185363Sjkoshy /* 178185363Sjkoshy * Intel Core, Core 2 and Atom processors. 179185363Sjkoshy */ 180185363Sjkoshy case PMC_CPU_INTEL_ATOM: 181185363Sjkoshy case PMC_CPU_INTEL_CORE: 182185363Sjkoshy case PMC_CPU_INTEL_CORE2: 183185585Sjkoshy case PMC_CPU_INTEL_CORE2EXTREME: 184187761Sjeff case PMC_CPU_INTEL_COREI7: 185206089Sfabient case PMC_CPU_INTEL_WESTMERE: 186185363Sjkoshy error = pmc_core_initialize(pmc_mdep, ncpus); 187185363Sjkoshy break; 188184802Sjkoshy 189184802Sjkoshy /* 190184802Sjkoshy * Intel Pentium 4 Processors, and P4/EMT64 processors. 191184802Sjkoshy */ 192184802Sjkoshy 193184802Sjkoshy case PMC_CPU_INTEL_PIV: 194184802Sjkoshy error = pmc_p4_initialize(pmc_mdep, ncpus); 195184802Sjkoshy 196184993Sjkoshy KASSERT(pmc_mdep->pmd_npmc == TSC_NPMCS + P4_NPMCS, 197184993Sjkoshy ("[intel,%d] incorrect npmc count %d", __LINE__, 198184993Sjkoshy pmc_mdep->pmd_npmc)); 199184802Sjkoshy break; 200184802Sjkoshy#endif 201184802Sjkoshy 202184802Sjkoshy#if defined(__i386__) 203184802Sjkoshy /* 204184802Sjkoshy * P6 Family Processors 205184802Sjkoshy */ 206184802Sjkoshy 207184802Sjkoshy case PMC_CPU_INTEL_P6: 208184802Sjkoshy case PMC_CPU_INTEL_CL: 209184802Sjkoshy case PMC_CPU_INTEL_PII: 210184802Sjkoshy case PMC_CPU_INTEL_PIII: 211184802Sjkoshy case PMC_CPU_INTEL_PM: 212184802Sjkoshy error = pmc_p6_initialize(pmc_mdep, ncpus); 213184802Sjkoshy 214184993Sjkoshy KASSERT(pmc_mdep->pmd_npmc == TSC_NPMCS + P6_NPMCS, 215184993Sjkoshy ("[intel,%d] incorrect npmc count %d", __LINE__, 216184993Sjkoshy pmc_mdep->pmd_npmc)); 217184802Sjkoshy break; 218184802Sjkoshy 219184802Sjkoshy /* 220184802Sjkoshy * Intel Pentium PMCs. 221184802Sjkoshy */ 222184802Sjkoshy 223184802Sjkoshy case PMC_CPU_INTEL_P5: 224184802Sjkoshy error = pmc_p5_initialize(pmc_mdep, ncpus); 225184802Sjkoshy 226184993Sjkoshy KASSERT(pmc_mdep->pmd_npmc == TSC_NPMCS + PENTIUM_NPMCS, 227184993Sjkoshy ("[intel,%d] incorrect npmc count %d", __LINE__, 228185363Sjkoshy pmc_mdep->pmd_npmc)); 229184802Sjkoshy break; 230184802Sjkoshy#endif 231184802Sjkoshy 232184802Sjkoshy default: 233184802Sjkoshy KASSERT(0, ("[intel,%d] Unknown CPU type", __LINE__)); 234184802Sjkoshy } 235184802Sjkoshy 236206089Sfabient /* 237206089Sfabient * Init the uncore class. 238206089Sfabient */ 239206089Sfabient#if defined(__i386__) || defined(__amd64__) 240206089Sfabient switch (cputype) { 241206089Sfabient /* 242206089Sfabient * Intel Corei7 and Westmere processors. 243206089Sfabient */ 244206089Sfabient case PMC_CPU_INTEL_COREI7: 245206089Sfabient case PMC_CPU_INTEL_WESTMERE: 246206089Sfabient error = pmc_uncore_initialize(pmc_mdep, ncpus); 247206089Sfabient break; 248206089Sfabient default: 249206089Sfabient break; 250206089Sfabient } 251206089Sfabient#endif 252184802Sjkoshy 253184802Sjkoshy error: 254184802Sjkoshy if (error) { 255184802Sjkoshy free(pmc_mdep, M_PMC); 256184802Sjkoshy pmc_mdep = NULL; 257184802Sjkoshy } 258184802Sjkoshy 259184802Sjkoshy return (pmc_mdep); 260184802Sjkoshy} 261184802Sjkoshy 262184802Sjkoshyvoid 263184802Sjkoshypmc_intel_finalize(struct pmc_mdep *md) 264184802Sjkoshy{ 265184802Sjkoshy pmc_tsc_finalize(md); 266184802Sjkoshy 267184802Sjkoshy switch (md->pmd_cputype) { 268184802Sjkoshy#if defined(__i386__) || defined(__amd64__) 269185363Sjkoshy case PMC_CPU_INTEL_ATOM: 270185363Sjkoshy case PMC_CPU_INTEL_CORE: 271185363Sjkoshy case PMC_CPU_INTEL_CORE2: 272185585Sjkoshy case PMC_CPU_INTEL_CORE2EXTREME: 273206089Sfabient case PMC_CPU_INTEL_COREI7: 274206089Sfabient case PMC_CPU_INTEL_WESTMERE: 275185363Sjkoshy pmc_core_finalize(md); 276185363Sjkoshy break; 277185363Sjkoshy 278184802Sjkoshy case PMC_CPU_INTEL_PIV: 279184802Sjkoshy pmc_p4_finalize(md); 280184802Sjkoshy break; 281184802Sjkoshy#endif 282184802Sjkoshy#if defined(__i386__) 283184802Sjkoshy case PMC_CPU_INTEL_P6: 284184802Sjkoshy case PMC_CPU_INTEL_CL: 285184802Sjkoshy case PMC_CPU_INTEL_PII: 286184802Sjkoshy case PMC_CPU_INTEL_PIII: 287184802Sjkoshy case PMC_CPU_INTEL_PM: 288184802Sjkoshy pmc_p6_finalize(md); 289184802Sjkoshy break; 290184802Sjkoshy case PMC_CPU_INTEL_P5: 291184802Sjkoshy pmc_p5_finalize(md); 292184802Sjkoshy break; 293184802Sjkoshy#endif 294184802Sjkoshy default: 295184802Sjkoshy KASSERT(0, ("[intel,%d] unknown CPU type", __LINE__)); 296184802Sjkoshy } 297206089Sfabient 298206089Sfabient /* 299206089Sfabient * Uncore. 300206089Sfabient */ 301206089Sfabient#if defined(__i386__) || defined(__amd64__) 302206089Sfabient switch (md->pmd_cputype) { 303206089Sfabient case PMC_CPU_INTEL_COREI7: 304206089Sfabient case PMC_CPU_INTEL_WESTMERE: 305206089Sfabient pmc_uncore_finalize(md); 306206089Sfabient break; 307206089Sfabient default: 308206089Sfabient break; 309206089Sfabient } 310206089Sfabient#endif 311184802Sjkoshy} 312