hwpmc_intel.c revision 184993
1/*- 2 * Copyright (c) 2008 Joseph Koshy 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27/* 28 * Common code for handling Intel CPUs. 29 */ 30 31#include <sys/cdefs.h> 32__FBSDID("$FreeBSD: head/sys/dev/hwpmc/hwpmc_intel.c 184993 2008-11-15 11:07:54Z jkoshy $"); 33 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/md_var.h> 41#include <machine/specialreg.h> 42 43static int 44intel_switch_in(struct pmc_cpu *pc, struct pmc_process *pp) 45{ 46 (void) pc; 47 48 PMCDBG(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 PMCDBG(MDP,SWI,1, "cr4=0x%jx", (uintmax_t) rcr4()); 56 57 return 0; 58} 59 60static int 61intel_switch_out(struct pmc_cpu *pc, struct pmc_process *pp) 62{ 63 (void) pc; 64 (void) pp; /* can be NULL */ 65 66 PMCDBG(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 75struct pmc_mdep * 76pmc_intel_initialize(void) 77{ 78 struct pmc_mdep *pmc_mdep; 79 enum pmc_cputype cputype; 80 int error, model, nclasses, ncpus; 81 82 KASSERT(strcmp(cpu_vendor, "GenuineIntel") == 0, 83 ("[intel,%d] Initializing non-intel processor", __LINE__)); 84 85 PMCDBG(MDP,INI,0, "intel-initialize cpuid=0x%x", cpu_id); 86 87 cputype = -1; 88 nclasses = 2; 89 90 switch (cpu_id & 0xF00) { 91#if defined(__i386__) 92 case 0x500: /* Pentium family processors */ 93 cputype = PMC_CPU_INTEL_P5; 94 break; 95 case 0x600: /* Pentium Pro, Celeron, Pentium II & III */ 96 switch ((cpu_id & 0xF0) >> 4) { /* model number field */ 97 case 0x1: 98 cputype = PMC_CPU_INTEL_P6; 99 break; 100 case 0x3: case 0x5: 101 cputype = PMC_CPU_INTEL_PII; 102 break; 103 case 0x6: 104 cputype = PMC_CPU_INTEL_CL; 105 break; 106 case 0x7: case 0x8: case 0xA: case 0xB: 107 cputype = PMC_CPU_INTEL_PIII; 108 break; 109 case 0x9: case 0xD: 110 cputype = PMC_CPU_INTEL_PM; 111 break; 112 } 113 break; 114#endif 115#if defined(__i386__) || defined(__amd64__) 116 case 0xF00: /* P4 */ 117 model = ((cpu_id & 0xF0000) >> 12) | ((cpu_id & 0xF0) >> 4); 118 if (model >= 0 && model <= 6) /* known models */ 119 cputype = PMC_CPU_INTEL_PIV; 120 break; 121 } 122#endif 123 124 if ((int) cputype == -1) { 125 printf("pmc: Unknown Intel CPU.\n"); 126 return (NULL); 127 } 128 129 pmc_mdep = malloc(sizeof(struct pmc_mdep) + nclasses * 130 sizeof(struct pmc_classdep), M_PMC, M_WAITOK|M_ZERO); 131 132 pmc_mdep->pmd_cputype = cputype; 133 pmc_mdep->pmd_nclass = nclasses; 134 135 pmc_mdep->pmd_switch_in = intel_switch_in; 136 pmc_mdep->pmd_switch_out = intel_switch_out; 137 138 ncpus = pmc_cpu_max(); 139 140 error = pmc_tsc_initialize(pmc_mdep, ncpus); 141 if (error) 142 goto error; 143 144 switch (cputype) { 145#if defined(__i386__) || defined(__amd64__) 146 147 /* 148 * Intel Pentium 4 Processors, and P4/EMT64 processors. 149 */ 150 151 case PMC_CPU_INTEL_PIV: 152 error = pmc_p4_initialize(pmc_mdep, ncpus); 153 154 KASSERT(pmc_mdep->pmd_npmc == TSC_NPMCS + P4_NPMCS, 155 ("[intel,%d] incorrect npmc count %d", __LINE__, 156 pmc_mdep->pmd_npmc)); 157 break; 158#endif 159 160#if defined(__i386__) 161 /* 162 * P6 Family Processors 163 */ 164 165 case PMC_CPU_INTEL_P6: 166 case PMC_CPU_INTEL_CL: 167 case PMC_CPU_INTEL_PII: 168 case PMC_CPU_INTEL_PIII: 169 case PMC_CPU_INTEL_PM: 170 error = pmc_p6_initialize(pmc_mdep, ncpus); 171 172 KASSERT(pmc_mdep->pmd_npmc == TSC_NPMCS + P6_NPMCS, 173 ("[intel,%d] incorrect npmc count %d", __LINE__, 174 pmc_mdep->pmd_npmc)); 175 break; 176 177 /* 178 * Intel Pentium PMCs. 179 */ 180 181 case PMC_CPU_INTEL_P5: 182 error = pmc_p5_initialize(pmc_mdep, ncpus); 183 184 KASSERT(pmc_mdep->pmd_npmc == TSC_NPMCS + PENTIUM_NPMCS, 185 ("[intel,%d] incorrect npmc count %d", __LINE__, 186 md->pmd_npmc)); 187 break; 188#endif 189 190 default: 191 KASSERT(0, ("[intel,%d] Unknown CPU type", __LINE__)); 192 } 193 194 195 error: 196 if (error) { 197 free(pmc_mdep, M_PMC); 198 pmc_mdep = NULL; 199 } 200 201 return (pmc_mdep); 202} 203 204void 205pmc_intel_finalize(struct pmc_mdep *md) 206{ 207 pmc_tsc_finalize(md); 208 209 switch (md->pmd_cputype) { 210#if defined(__i386__) || defined(__amd64__) 211 case PMC_CPU_INTEL_PIV: 212 pmc_p4_finalize(md); 213 break; 214#endif 215#if defined(__i386__) 216 case PMC_CPU_INTEL_P6: 217 case PMC_CPU_INTEL_CL: 218 case PMC_CPU_INTEL_PII: 219 case PMC_CPU_INTEL_PIII: 220 case PMC_CPU_INTEL_PM: 221 pmc_p6_finalize(md); 222 break; 223 case PMC_CPU_INTEL_P5: 224 pmc_p5_finalize(md); 225 break; 226#endif 227 default: 228 KASSERT(0, ("[intel,%d] unknown CPU type", __LINE__)); 229 } 230} 231