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