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