hwpmc_intel.c revision 184993
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 184993 2008-11-15 11:07:54Z jkoshy $"); 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> 40184802Sjkoshy#include <machine/md_var.h> 41184802Sjkoshy#include <machine/specialreg.h> 42184802Sjkoshy 43184802Sjkoshystatic int 44184802Sjkoshyintel_switch_in(struct pmc_cpu *pc, struct pmc_process *pp) 45184802Sjkoshy{ 46184802Sjkoshy (void) pc; 47184802Sjkoshy 48184802Sjkoshy PMCDBG(MDP,SWI,1, "pc=%p pp=%p enable-msr=%d", pc, pp, 49184802Sjkoshy pp->pp_flags & PMC_PP_ENABLE_MSR_ACCESS); 50184802Sjkoshy 51184802Sjkoshy /* allow the RDPMC instruction if needed */ 52184802Sjkoshy if (pp->pp_flags & PMC_PP_ENABLE_MSR_ACCESS) 53184802Sjkoshy load_cr4(rcr4() | CR4_PCE); 54184802Sjkoshy 55184802Sjkoshy PMCDBG(MDP,SWI,1, "cr4=0x%jx", (uintmax_t) rcr4()); 56184802Sjkoshy 57184802Sjkoshy return 0; 58184802Sjkoshy} 59184802Sjkoshy 60184802Sjkoshystatic int 61184802Sjkoshyintel_switch_out(struct pmc_cpu *pc, struct pmc_process *pp) 62184802Sjkoshy{ 63184802Sjkoshy (void) pc; 64184802Sjkoshy (void) pp; /* can be NULL */ 65184802Sjkoshy 66184802Sjkoshy PMCDBG(MDP,SWO,1, "pc=%p pp=%p cr4=0x%jx", pc, pp, 67184802Sjkoshy (uintmax_t) rcr4()); 68184802Sjkoshy 69184802Sjkoshy /* always turn off the RDPMC instruction */ 70184802Sjkoshy load_cr4(rcr4() & ~CR4_PCE); 71184802Sjkoshy 72184802Sjkoshy return 0; 73184802Sjkoshy} 74184802Sjkoshy 75184802Sjkoshystruct pmc_mdep * 76184802Sjkoshypmc_intel_initialize(void) 77184802Sjkoshy{ 78184802Sjkoshy struct pmc_mdep *pmc_mdep; 79184802Sjkoshy enum pmc_cputype cputype; 80184802Sjkoshy int error, model, nclasses, ncpus; 81184802Sjkoshy 82184802Sjkoshy KASSERT(strcmp(cpu_vendor, "GenuineIntel") == 0, 83184802Sjkoshy ("[intel,%d] Initializing non-intel processor", __LINE__)); 84184802Sjkoshy 85184802Sjkoshy PMCDBG(MDP,INI,0, "intel-initialize cpuid=0x%x", cpu_id); 86184802Sjkoshy 87184802Sjkoshy cputype = -1; 88184802Sjkoshy nclasses = 2; 89184802Sjkoshy 90184802Sjkoshy switch (cpu_id & 0xF00) { 91184802Sjkoshy#if defined(__i386__) 92184802Sjkoshy case 0x500: /* Pentium family processors */ 93184802Sjkoshy cputype = PMC_CPU_INTEL_P5; 94184802Sjkoshy break; 95184802Sjkoshy case 0x600: /* Pentium Pro, Celeron, Pentium II & III */ 96184802Sjkoshy switch ((cpu_id & 0xF0) >> 4) { /* model number field */ 97184802Sjkoshy case 0x1: 98184802Sjkoshy cputype = PMC_CPU_INTEL_P6; 99184802Sjkoshy break; 100184802Sjkoshy case 0x3: case 0x5: 101184802Sjkoshy cputype = PMC_CPU_INTEL_PII; 102184802Sjkoshy break; 103184802Sjkoshy case 0x6: 104184802Sjkoshy cputype = PMC_CPU_INTEL_CL; 105184802Sjkoshy break; 106184802Sjkoshy case 0x7: case 0x8: case 0xA: case 0xB: 107184802Sjkoshy cputype = PMC_CPU_INTEL_PIII; 108184802Sjkoshy break; 109184802Sjkoshy case 0x9: case 0xD: 110184802Sjkoshy cputype = PMC_CPU_INTEL_PM; 111184802Sjkoshy break; 112184802Sjkoshy } 113184802Sjkoshy break; 114184802Sjkoshy#endif 115184802Sjkoshy#if defined(__i386__) || defined(__amd64__) 116184802Sjkoshy case 0xF00: /* P4 */ 117184802Sjkoshy model = ((cpu_id & 0xF0000) >> 12) | ((cpu_id & 0xF0) >> 4); 118184802Sjkoshy if (model >= 0 && model <= 6) /* known models */ 119184802Sjkoshy cputype = PMC_CPU_INTEL_PIV; 120184802Sjkoshy break; 121184802Sjkoshy } 122184802Sjkoshy#endif 123184802Sjkoshy 124184802Sjkoshy if ((int) cputype == -1) { 125184802Sjkoshy printf("pmc: Unknown Intel CPU.\n"); 126184802Sjkoshy return (NULL); 127184802Sjkoshy } 128184802Sjkoshy 129184802Sjkoshy pmc_mdep = malloc(sizeof(struct pmc_mdep) + nclasses * 130184802Sjkoshy sizeof(struct pmc_classdep), M_PMC, M_WAITOK|M_ZERO); 131184802Sjkoshy 132184802Sjkoshy pmc_mdep->pmd_cputype = cputype; 133184802Sjkoshy pmc_mdep->pmd_nclass = nclasses; 134184802Sjkoshy 135184802Sjkoshy pmc_mdep->pmd_switch_in = intel_switch_in; 136184802Sjkoshy pmc_mdep->pmd_switch_out = intel_switch_out; 137184802Sjkoshy 138184802Sjkoshy ncpus = pmc_cpu_max(); 139184802Sjkoshy 140184802Sjkoshy error = pmc_tsc_initialize(pmc_mdep, ncpus); 141184802Sjkoshy if (error) 142184802Sjkoshy goto error; 143184802Sjkoshy 144184802Sjkoshy switch (cputype) { 145184802Sjkoshy#if defined(__i386__) || defined(__amd64__) 146184802Sjkoshy 147184802Sjkoshy /* 148184802Sjkoshy * Intel Pentium 4 Processors, and P4/EMT64 processors. 149184802Sjkoshy */ 150184802Sjkoshy 151184802Sjkoshy case PMC_CPU_INTEL_PIV: 152184802Sjkoshy error = pmc_p4_initialize(pmc_mdep, ncpus); 153184802Sjkoshy 154184993Sjkoshy KASSERT(pmc_mdep->pmd_npmc == TSC_NPMCS + P4_NPMCS, 155184993Sjkoshy ("[intel,%d] incorrect npmc count %d", __LINE__, 156184993Sjkoshy pmc_mdep->pmd_npmc)); 157184802Sjkoshy break; 158184802Sjkoshy#endif 159184802Sjkoshy 160184802Sjkoshy#if defined(__i386__) 161184802Sjkoshy /* 162184802Sjkoshy * P6 Family Processors 163184802Sjkoshy */ 164184802Sjkoshy 165184802Sjkoshy case PMC_CPU_INTEL_P6: 166184802Sjkoshy case PMC_CPU_INTEL_CL: 167184802Sjkoshy case PMC_CPU_INTEL_PII: 168184802Sjkoshy case PMC_CPU_INTEL_PIII: 169184802Sjkoshy case PMC_CPU_INTEL_PM: 170184802Sjkoshy error = pmc_p6_initialize(pmc_mdep, ncpus); 171184802Sjkoshy 172184993Sjkoshy KASSERT(pmc_mdep->pmd_npmc == TSC_NPMCS + P6_NPMCS, 173184993Sjkoshy ("[intel,%d] incorrect npmc count %d", __LINE__, 174184993Sjkoshy pmc_mdep->pmd_npmc)); 175184802Sjkoshy break; 176184802Sjkoshy 177184802Sjkoshy /* 178184802Sjkoshy * Intel Pentium PMCs. 179184802Sjkoshy */ 180184802Sjkoshy 181184802Sjkoshy case PMC_CPU_INTEL_P5: 182184802Sjkoshy error = pmc_p5_initialize(pmc_mdep, ncpus); 183184802Sjkoshy 184184993Sjkoshy KASSERT(pmc_mdep->pmd_npmc == TSC_NPMCS + PENTIUM_NPMCS, 185184993Sjkoshy ("[intel,%d] incorrect npmc count %d", __LINE__, 186184993Sjkoshy md->pmd_npmc)); 187184802Sjkoshy break; 188184802Sjkoshy#endif 189184802Sjkoshy 190184802Sjkoshy default: 191184802Sjkoshy KASSERT(0, ("[intel,%d] Unknown CPU type", __LINE__)); 192184802Sjkoshy } 193184802Sjkoshy 194184802Sjkoshy 195184802Sjkoshy error: 196184802Sjkoshy if (error) { 197184802Sjkoshy free(pmc_mdep, M_PMC); 198184802Sjkoshy pmc_mdep = NULL; 199184802Sjkoshy } 200184802Sjkoshy 201184802Sjkoshy return (pmc_mdep); 202184802Sjkoshy} 203184802Sjkoshy 204184802Sjkoshyvoid 205184802Sjkoshypmc_intel_finalize(struct pmc_mdep *md) 206184802Sjkoshy{ 207184802Sjkoshy pmc_tsc_finalize(md); 208184802Sjkoshy 209184802Sjkoshy switch (md->pmd_cputype) { 210184802Sjkoshy#if defined(__i386__) || defined(__amd64__) 211184802Sjkoshy case PMC_CPU_INTEL_PIV: 212184802Sjkoshy pmc_p4_finalize(md); 213184802Sjkoshy break; 214184802Sjkoshy#endif 215184802Sjkoshy#if defined(__i386__) 216184802Sjkoshy case PMC_CPU_INTEL_P6: 217184802Sjkoshy case PMC_CPU_INTEL_CL: 218184802Sjkoshy case PMC_CPU_INTEL_PII: 219184802Sjkoshy case PMC_CPU_INTEL_PIII: 220184802Sjkoshy case PMC_CPU_INTEL_PM: 221184802Sjkoshy pmc_p6_finalize(md); 222184802Sjkoshy break; 223184802Sjkoshy case PMC_CPU_INTEL_P5: 224184802Sjkoshy pmc_p5_finalize(md); 225184802Sjkoshy break; 226184802Sjkoshy#endif 227184802Sjkoshy default: 228184802Sjkoshy KASSERT(0, ("[intel,%d] unknown CPU type", __LINE__)); 229184802Sjkoshy } 230184802Sjkoshy} 231