hwpmc_intel.c revision 240164
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 240164 2012-09-06 13:54:01Z 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;
145232366Sdavide		case 0x2A:	/* Per Intel document 253669-039US 05/2011. */
146232366Sdavide			cputype = PMC_CPU_INTEL_SANDYBRIDGE;
147232366Sdavide			nclasses = 5;
148232366Sdavide			break;
149240164Sfabient		case 0x3A:	/* Per Intel document 253669-043US 05/2012. */
150240164Sfabient			cputype = PMC_CPU_INTEL_IVYBRIDGE;
151240164Sfabient			nclasses = 3;
152240164Sfabient			break;
153184802Sjkoshy		}
154184802Sjkoshy		break;
155184802Sjkoshy#if	defined(__i386__) || defined(__amd64__)
156184802Sjkoshy	case 0xF00:		/* P4 */
157184802Sjkoshy		if (model >= 0 && model <= 6) /* known models */
158184802Sjkoshy			cputype = PMC_CPU_INTEL_PIV;
159184802Sjkoshy		break;
160184802Sjkoshy	}
161184802Sjkoshy#endif
162184802Sjkoshy
163184802Sjkoshy	if ((int) cputype == -1) {
164184802Sjkoshy		printf("pmc: Unknown Intel CPU.\n");
165184802Sjkoshy		return (NULL);
166184802Sjkoshy	}
167184802Sjkoshy
168233628Sfabient	/* Allocate base class and initialize machine dependent struct */
169233628Sfabient	pmc_mdep = pmc_mdep_alloc(nclasses);
170184802Sjkoshy
171184802Sjkoshy	pmc_mdep->pmd_cputype 	 = cputype;
172184802Sjkoshy	pmc_mdep->pmd_switch_in	 = intel_switch_in;
173184802Sjkoshy	pmc_mdep->pmd_switch_out = intel_switch_out;
174184802Sjkoshy
175184802Sjkoshy	ncpus = pmc_cpu_max();
176184802Sjkoshy
177184802Sjkoshy	error = pmc_tsc_initialize(pmc_mdep, ncpus);
178184802Sjkoshy	if (error)
179184802Sjkoshy		goto error;
180184802Sjkoshy
181184802Sjkoshy	switch (cputype) {
182184802Sjkoshy#if	defined(__i386__) || defined(__amd64__)
183185363Sjkoshy		/*
184185363Sjkoshy		 * Intel Core, Core 2 and Atom processors.
185185363Sjkoshy		 */
186185363Sjkoshy	case PMC_CPU_INTEL_ATOM:
187185363Sjkoshy	case PMC_CPU_INTEL_CORE:
188185363Sjkoshy	case PMC_CPU_INTEL_CORE2:
189185585Sjkoshy	case PMC_CPU_INTEL_CORE2EXTREME:
190187761Sjeff	case PMC_CPU_INTEL_COREI7:
191240164Sfabient	case PMC_CPU_INTEL_IVYBRIDGE:
192232366Sdavide	case PMC_CPU_INTEL_SANDYBRIDGE:
193206089Sfabient	case PMC_CPU_INTEL_WESTMERE:
194185363Sjkoshy		error = pmc_core_initialize(pmc_mdep, ncpus);
195185363Sjkoshy		break;
196184802Sjkoshy
197184802Sjkoshy		/*
198184802Sjkoshy		 * Intel Pentium 4 Processors, and P4/EMT64 processors.
199184802Sjkoshy		 */
200184802Sjkoshy
201184802Sjkoshy	case PMC_CPU_INTEL_PIV:
202184802Sjkoshy		error = pmc_p4_initialize(pmc_mdep, ncpus);
203184802Sjkoshy		break;
204184802Sjkoshy#endif
205184802Sjkoshy
206184802Sjkoshy#if	defined(__i386__)
207184802Sjkoshy		/*
208184802Sjkoshy		 * P6 Family Processors
209184802Sjkoshy		 */
210184802Sjkoshy
211184802Sjkoshy	case PMC_CPU_INTEL_P6:
212184802Sjkoshy	case PMC_CPU_INTEL_CL:
213184802Sjkoshy	case PMC_CPU_INTEL_PII:
214184802Sjkoshy	case PMC_CPU_INTEL_PIII:
215184802Sjkoshy	case PMC_CPU_INTEL_PM:
216184802Sjkoshy		error = pmc_p6_initialize(pmc_mdep, ncpus);
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		break;
226184802Sjkoshy#endif
227184802Sjkoshy
228184802Sjkoshy	default:
229184802Sjkoshy		KASSERT(0, ("[intel,%d] Unknown CPU type", __LINE__));
230184802Sjkoshy	}
231184802Sjkoshy
232233569Sgonzo	if (error)
233233569Sgonzo		goto error;
234233569Sgonzo
235206089Sfabient	/*
236206089Sfabient	 * Init the uncore class.
237206089Sfabient	 */
238206089Sfabient#if	defined(__i386__) || defined(__amd64__)
239206089Sfabient	switch (cputype) {
240206089Sfabient		/*
241206089Sfabient		 * Intel Corei7 and Westmere processors.
242206089Sfabient		 */
243206089Sfabient	case PMC_CPU_INTEL_COREI7:
244232366Sdavide	case PMC_CPU_INTEL_SANDYBRIDGE:
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:
274240164Sfabient	case PMC_CPU_INTEL_IVYBRIDGE:
275232366Sdavide	case PMC_CPU_INTEL_SANDYBRIDGE:
276206089Sfabient	case PMC_CPU_INTEL_WESTMERE:
277185363Sjkoshy		pmc_core_finalize(md);
278185363Sjkoshy		break;
279185363Sjkoshy
280184802Sjkoshy	case PMC_CPU_INTEL_PIV:
281184802Sjkoshy		pmc_p4_finalize(md);
282184802Sjkoshy		break;
283184802Sjkoshy#endif
284184802Sjkoshy#if	defined(__i386__)
285184802Sjkoshy	case PMC_CPU_INTEL_P6:
286184802Sjkoshy	case PMC_CPU_INTEL_CL:
287184802Sjkoshy	case PMC_CPU_INTEL_PII:
288184802Sjkoshy	case PMC_CPU_INTEL_PIII:
289184802Sjkoshy	case PMC_CPU_INTEL_PM:
290184802Sjkoshy		pmc_p6_finalize(md);
291184802Sjkoshy		break;
292184802Sjkoshy	case PMC_CPU_INTEL_P5:
293184802Sjkoshy		pmc_p5_finalize(md);
294184802Sjkoshy		break;
295184802Sjkoshy#endif
296184802Sjkoshy	default:
297184802Sjkoshy		KASSERT(0, ("[intel,%d] unknown CPU type", __LINE__));
298184802Sjkoshy	}
299206089Sfabient
300206089Sfabient	/*
301206089Sfabient	 * Uncore.
302206089Sfabient	 */
303206089Sfabient#if	defined(__i386__) || defined(__amd64__)
304206089Sfabient	switch (md->pmd_cputype) {
305206089Sfabient	case PMC_CPU_INTEL_COREI7:
306232366Sdavide	case PMC_CPU_INTEL_SANDYBRIDGE:
307206089Sfabient	case PMC_CPU_INTEL_WESTMERE:
308206089Sfabient		pmc_uncore_finalize(md);
309206089Sfabient		break;
310206089Sfabient	default:
311206089Sfabient		break;
312206089Sfabient	}
313206089Sfabient#endif
314184802Sjkoshy}
315