hwpmc_intel.c revision 250097
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 250097 2013-04-30 08:33:38Z davide $");
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 */
71249069Ssbruno	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;
90250097Sdavide	error = 0;
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:
134249069Ssbruno		case 0x1E:	/*
135249069Ssbruno				 * Per Intel document 253669-032 9/2009,
136249069Ssbruno				 * pages A-2 and A-57
137249069Ssbruno				 */
138249069Ssbruno		case 0x1F:	/*
139249069Ssbruno				 * Per Intel document 253669-032 9/2009,
140249069Ssbruno				 * pages A-2 and A-57
141249069Ssbruno				 */
142206089Sfabient		case 0x2E:
143187761Sjeff			cputype = PMC_CPU_INTEL_COREI7;
144206089Sfabient			nclasses = 5;
145187761Sjeff			break;
146206089Sfabient		case 0x25:	/* Per Intel document 253669-033US 12/2009. */
147206089Sfabient		case 0x2C:	/* Per Intel document 253669-033US 12/2009. */
148206089Sfabient			cputype = PMC_CPU_INTEL_WESTMERE;
149206089Sfabient			nclasses = 5;
150206089Sfabient			break;
151232366Sdavide		case 0x2A:	/* Per Intel document 253669-039US 05/2011. */
152232366Sdavide			cputype = PMC_CPU_INTEL_SANDYBRIDGE;
153232366Sdavide			nclasses = 5;
154232366Sdavide			break;
155241738Ssbruno		case 0x2D:	/* Per Intel document 253669-044US 08/2012. */
156241738Ssbruno			cputype = PMC_CPU_INTEL_SANDYBRIDGE_XEON;
157241738Ssbruno			nclasses = 3;
158241738Ssbruno			break;
159240164Sfabient		case 0x3A:	/* Per Intel document 253669-043US 05/2012. */
160240164Sfabient			cputype = PMC_CPU_INTEL_IVYBRIDGE;
161240164Sfabient			nclasses = 3;
162240164Sfabient			break;
163246166Ssbruno		case 0x3E:	/* Per Intel document 325462-045US 01/2013. */
164246166Ssbruno			cputype = PMC_CPU_INTEL_IVYBRIDGE_XEON;
165246166Ssbruno			nclasses = 3;
166246166Ssbruno			break;
167248842Ssbruno		case 0x3C:	/* Per Intel document 325462-045US 01/2013. */
168248842Ssbruno			cputype = PMC_CPU_INTEL_HASWELL;
169248842Ssbruno			nclasses = 5;
170248842Ssbruno			break;
171184802Sjkoshy		}
172184802Sjkoshy		break;
173184802Sjkoshy#if	defined(__i386__) || defined(__amd64__)
174184802Sjkoshy	case 0xF00:		/* P4 */
175184802Sjkoshy		if (model >= 0 && model <= 6) /* known models */
176184802Sjkoshy			cputype = PMC_CPU_INTEL_PIV;
177184802Sjkoshy		break;
178184802Sjkoshy	}
179184802Sjkoshy#endif
180184802Sjkoshy
181184802Sjkoshy	if ((int) cputype == -1) {
182184802Sjkoshy		printf("pmc: Unknown Intel CPU.\n");
183184802Sjkoshy		return (NULL);
184184802Sjkoshy	}
185184802Sjkoshy
186233628Sfabient	/* Allocate base class and initialize machine dependent struct */
187233628Sfabient	pmc_mdep = pmc_mdep_alloc(nclasses);
188184802Sjkoshy
189249069Ssbruno	pmc_mdep->pmd_cputype	 = cputype;
190184802Sjkoshy	pmc_mdep->pmd_switch_in	 = intel_switch_in;
191184802Sjkoshy	pmc_mdep->pmd_switch_out = intel_switch_out;
192184802Sjkoshy
193184802Sjkoshy	ncpus = pmc_cpu_max();
194184802Sjkoshy
195184802Sjkoshy	switch (cputype) {
196184802Sjkoshy#if	defined(__i386__) || defined(__amd64__)
197185363Sjkoshy		/*
198185363Sjkoshy		 * Intel Core, Core 2 and Atom processors.
199185363Sjkoshy		 */
200185363Sjkoshy	case PMC_CPU_INTEL_ATOM:
201185363Sjkoshy	case PMC_CPU_INTEL_CORE:
202185363Sjkoshy	case PMC_CPU_INTEL_CORE2:
203185585Sjkoshy	case PMC_CPU_INTEL_CORE2EXTREME:
204187761Sjeff	case PMC_CPU_INTEL_COREI7:
205240164Sfabient	case PMC_CPU_INTEL_IVYBRIDGE:
206232366Sdavide	case PMC_CPU_INTEL_SANDYBRIDGE:
207206089Sfabient	case PMC_CPU_INTEL_WESTMERE:
208241738Ssbruno	case PMC_CPU_INTEL_SANDYBRIDGE_XEON:
209246166Ssbruno	case PMC_CPU_INTEL_IVYBRIDGE_XEON:
210248842Ssbruno	case PMC_CPU_INTEL_HASWELL:
211185363Sjkoshy		error = pmc_core_initialize(pmc_mdep, ncpus);
212185363Sjkoshy		break;
213184802Sjkoshy
214184802Sjkoshy		/*
215184802Sjkoshy		 * Intel Pentium 4 Processors, and P4/EMT64 processors.
216184802Sjkoshy		 */
217184802Sjkoshy
218184802Sjkoshy	case PMC_CPU_INTEL_PIV:
219184802Sjkoshy		error = pmc_p4_initialize(pmc_mdep, ncpus);
220184802Sjkoshy		break;
221184802Sjkoshy#endif
222184802Sjkoshy
223184802Sjkoshy#if	defined(__i386__)
224184802Sjkoshy		/*
225184802Sjkoshy		 * P6 Family Processors
226184802Sjkoshy		 */
227184802Sjkoshy
228184802Sjkoshy	case PMC_CPU_INTEL_P6:
229184802Sjkoshy	case PMC_CPU_INTEL_CL:
230184802Sjkoshy	case PMC_CPU_INTEL_PII:
231184802Sjkoshy	case PMC_CPU_INTEL_PIII:
232184802Sjkoshy	case PMC_CPU_INTEL_PM:
233184802Sjkoshy		error = pmc_p6_initialize(pmc_mdep, ncpus);
234184802Sjkoshy		break;
235184802Sjkoshy
236184802Sjkoshy		/*
237184802Sjkoshy		 * Intel Pentium PMCs.
238184802Sjkoshy		 */
239184802Sjkoshy
240184802Sjkoshy	case PMC_CPU_INTEL_P5:
241184802Sjkoshy		error = pmc_p5_initialize(pmc_mdep, ncpus);
242184802Sjkoshy		break;
243184802Sjkoshy#endif
244184802Sjkoshy
245184802Sjkoshy	default:
246184802Sjkoshy		KASSERT(0, ("[intel,%d] Unknown CPU type", __LINE__));
247184802Sjkoshy	}
248184802Sjkoshy
249233569Sgonzo	if (error)
250233569Sgonzo		goto error;
251233569Sgonzo
252206089Sfabient	/*
253206089Sfabient	 * Init the uncore class.
254206089Sfabient	 */
255206089Sfabient#if	defined(__i386__) || defined(__amd64__)
256206089Sfabient	switch (cputype) {
257206089Sfabient		/*
258206089Sfabient		 * Intel Corei7 and Westmere processors.
259206089Sfabient		 */
260206089Sfabient	case PMC_CPU_INTEL_COREI7:
261248842Ssbruno	case PMC_CPU_INTEL_HASWELL:
262232366Sdavide	case PMC_CPU_INTEL_SANDYBRIDGE:
263206089Sfabient	case PMC_CPU_INTEL_WESTMERE:
264206089Sfabient		error = pmc_uncore_initialize(pmc_mdep, ncpus);
265206089Sfabient		break;
266206089Sfabient	default:
267206089Sfabient		break;
268206089Sfabient	}
269206089Sfabient#endif
270250097Sdavide	error = pmc_tsc_initialize(pmc_mdep, ncpus);
271184802Sjkoshy  error:
272184802Sjkoshy	if (error) {
273250097Sdavide		pmc_mdep_free(pmc_mdep);
274184802Sjkoshy		pmc_mdep = NULL;
275184802Sjkoshy	}
276184802Sjkoshy
277184802Sjkoshy	return (pmc_mdep);
278184802Sjkoshy}
279184802Sjkoshy
280184802Sjkoshyvoid
281184802Sjkoshypmc_intel_finalize(struct pmc_mdep *md)
282184802Sjkoshy{
283184802Sjkoshy	pmc_tsc_finalize(md);
284184802Sjkoshy
285184802Sjkoshy	switch (md->pmd_cputype) {
286184802Sjkoshy#if	defined(__i386__) || defined(__amd64__)
287185363Sjkoshy	case PMC_CPU_INTEL_ATOM:
288185363Sjkoshy	case PMC_CPU_INTEL_CORE:
289185363Sjkoshy	case PMC_CPU_INTEL_CORE2:
290185585Sjkoshy	case PMC_CPU_INTEL_CORE2EXTREME:
291206089Sfabient	case PMC_CPU_INTEL_COREI7:
292248842Ssbruno	case PMC_CPU_INTEL_HASWELL:
293240164Sfabient	case PMC_CPU_INTEL_IVYBRIDGE:
294232366Sdavide	case PMC_CPU_INTEL_SANDYBRIDGE:
295206089Sfabient	case PMC_CPU_INTEL_WESTMERE:
296241738Ssbruno	case PMC_CPU_INTEL_SANDYBRIDGE_XEON:
297246166Ssbruno	case PMC_CPU_INTEL_IVYBRIDGE_XEON:
298185363Sjkoshy		pmc_core_finalize(md);
299185363Sjkoshy		break;
300185363Sjkoshy
301184802Sjkoshy	case PMC_CPU_INTEL_PIV:
302184802Sjkoshy		pmc_p4_finalize(md);
303184802Sjkoshy		break;
304184802Sjkoshy#endif
305184802Sjkoshy#if	defined(__i386__)
306184802Sjkoshy	case PMC_CPU_INTEL_P6:
307184802Sjkoshy	case PMC_CPU_INTEL_CL:
308184802Sjkoshy	case PMC_CPU_INTEL_PII:
309184802Sjkoshy	case PMC_CPU_INTEL_PIII:
310184802Sjkoshy	case PMC_CPU_INTEL_PM:
311184802Sjkoshy		pmc_p6_finalize(md);
312184802Sjkoshy		break;
313184802Sjkoshy	case PMC_CPU_INTEL_P5:
314184802Sjkoshy		pmc_p5_finalize(md);
315184802Sjkoshy		break;
316184802Sjkoshy#endif
317184802Sjkoshy	default:
318184802Sjkoshy		KASSERT(0, ("[intel,%d] unknown CPU type", __LINE__));
319184802Sjkoshy	}
320206089Sfabient
321206089Sfabient	/*
322206089Sfabient	 * Uncore.
323206089Sfabient	 */
324206089Sfabient#if	defined(__i386__) || defined(__amd64__)
325206089Sfabient	switch (md->pmd_cputype) {
326206089Sfabient	case PMC_CPU_INTEL_COREI7:
327248842Ssbruno	case PMC_CPU_INTEL_HASWELL:
328232366Sdavide	case PMC_CPU_INTEL_SANDYBRIDGE:
329206089Sfabient	case PMC_CPU_INTEL_WESTMERE:
330206089Sfabient		pmc_uncore_finalize(md);
331206089Sfabient		break;
332206089Sfabient	default:
333206089Sfabient		break;
334206089Sfabient	}
335206089Sfabient#endif
336184802Sjkoshy}
337