hwpmc_intel.c revision 184802
1207753Smm/*- 2207753Smm * Copyright (c) 2008 Joseph Koshy 3207753Smm * All rights reserved. 4207753Smm * 5207753Smm * Redistribution and use in source and binary forms, with or without 6207753Smm * modification, are permitted provided that the following conditions 7207753Smm * are met: 8207753Smm * 1. Redistributions of source code must retain the above copyright 9207753Smm * notice, this list of conditions and the following disclaimer. 10207753Smm * 2. Redistributions in binary form must reproduce the above copyright 11207753Smm * notice, this list of conditions and the following disclaimer in the 12207753Smm * documentation and/or other materials provided with the distribution. 13207753Smm * 14207753Smm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15207753Smm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16207753Smm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17207753Smm * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18207753Smm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19207753Smm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20207753Smm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21207753Smm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22207753Smm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23207753Smm * 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 184802 2008-11-09 17:37: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(md->pmd_npmc == TSC_NPMCS + P4_NPMCS, ("[intel,%d] " 155 "incorrect npmc count %d", __LINE__, md->pmd_npmc)); 156 break; 157#endif 158 159#if defined(__i386__) 160 /* 161 * P6 Family Processors 162 */ 163 164 case PMC_CPU_INTEL_P6: 165 case PMC_CPU_INTEL_CL: 166 case PMC_CPU_INTEL_PII: 167 case PMC_CPU_INTEL_PIII: 168 case PMC_CPU_INTEL_PM: 169 error = pmc_p6_initialize(pmc_mdep, ncpus); 170 171 KASSERT(md->pmd_npmc == TSC_NPMCS + P6_NPMCS, ("[intel,%d] " 172 "incorrect npmc count %d", __LINE__, md->pmd_npmc)); 173 break; 174 175 /* 176 * Intel Pentium PMCs. 177 */ 178 179 case PMC_CPU_INTEL_P5: 180 error = pmc_p5_initialize(pmc_mdep, ncpus); 181 182 KASSERT(md->pmd_npmc == TSC_NPMCS + PENTIUM_NPMCS, ("[intel,%d] " 183 "incorrect npmc count %d", __LINE__, md->pmd_npmc)); 184 break; 185#endif 186 187 default: 188 KASSERT(0, ("[intel,%d] Unknown CPU type", __LINE__)); 189 } 190 191 192 error: 193 if (error) { 194 free(pmc_mdep, M_PMC); 195 pmc_mdep = NULL; 196 } 197 198 return (pmc_mdep); 199} 200 201void 202pmc_intel_finalize(struct pmc_mdep *md) 203{ 204 pmc_tsc_finalize(md); 205 206 switch (md->pmd_cputype) { 207#if defined(__i386__) || defined(__amd64__) 208 case PMC_CPU_INTEL_PIV: 209 pmc_p4_finalize(md); 210 break; 211#endif 212#if defined(__i386__) 213 case PMC_CPU_INTEL_P6: 214 case PMC_CPU_INTEL_CL: 215 case PMC_CPU_INTEL_PII: 216 case PMC_CPU_INTEL_PIII: 217 case PMC_CPU_INTEL_PM: 218 pmc_p6_finalize(md); 219 break; 220 case PMC_CPU_INTEL_P5: 221 pmc_p5_finalize(md); 222 break; 223#endif 224 default: 225 KASSERT(0, ("[intel,%d] unknown CPU type", __LINE__)); 226 } 227} 228