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$");
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				 */
142187761Sjeff			cputype = PMC_CPU_INTEL_COREI7;
143206089Sfabient			nclasses = 5;
144187761Sjeff			break;
145267602Skib		case 0x2E:
146267602Skib			cputype = PMC_CPU_INTEL_NEHALEM_EX;
147267602Skib			nclasses = 3;
148267602Skib			break;
149206089Sfabient		case 0x25:	/* Per Intel document 253669-033US 12/2009. */
150206089Sfabient		case 0x2C:	/* Per Intel document 253669-033US 12/2009. */
151206089Sfabient			cputype = PMC_CPU_INTEL_WESTMERE;
152206089Sfabient			nclasses = 5;
153206089Sfabient			break;
154267602Skib		case 0x2F:	/* Westmere-EX, seen in wild */
155267602Skib			cputype = PMC_CPU_INTEL_WESTMERE_EX;
156267602Skib			nclasses = 3;
157267602Skib			break;
158232366Sdavide		case 0x2A:	/* Per Intel document 253669-039US 05/2011. */
159232366Sdavide			cputype = PMC_CPU_INTEL_SANDYBRIDGE;
160232366Sdavide			nclasses = 5;
161232366Sdavide			break;
162241738Ssbruno		case 0x2D:	/* Per Intel document 253669-044US 08/2012. */
163241738Ssbruno			cputype = PMC_CPU_INTEL_SANDYBRIDGE_XEON;
164241738Ssbruno			nclasses = 3;
165241738Ssbruno			break;
166240164Sfabient		case 0x3A:	/* Per Intel document 253669-043US 05/2012. */
167240164Sfabient			cputype = PMC_CPU_INTEL_IVYBRIDGE;
168240164Sfabient			nclasses = 3;
169240164Sfabient			break;
170246166Ssbruno		case 0x3E:	/* Per Intel document 325462-045US 01/2013. */
171246166Ssbruno			cputype = PMC_CPU_INTEL_IVYBRIDGE_XEON;
172246166Ssbruno			nclasses = 3;
173246166Ssbruno			break;
174248842Ssbruno		case 0x3C:	/* Per Intel document 325462-045US 01/2013. */
175248842Ssbruno			cputype = PMC_CPU_INTEL_HASWELL;
176248842Ssbruno			nclasses = 5;
177248842Ssbruno			break;
178266911Shiren		case 0x4D:      /* Per Intel document 330061-001 01/2014. */
179266911Shiren			cputype = PMC_CPU_INTEL_ATOM_SILVERMONT;
180266911Shiren			nclasses = 3;
181266911Shiren			break;
182184802Sjkoshy		}
183184802Sjkoshy		break;
184184802Sjkoshy#if	defined(__i386__) || defined(__amd64__)
185184802Sjkoshy	case 0xF00:		/* P4 */
186184802Sjkoshy		if (model >= 0 && model <= 6) /* known models */
187184802Sjkoshy			cputype = PMC_CPU_INTEL_PIV;
188184802Sjkoshy		break;
189184802Sjkoshy	}
190184802Sjkoshy#endif
191184802Sjkoshy
192184802Sjkoshy	if ((int) cputype == -1) {
193184802Sjkoshy		printf("pmc: Unknown Intel CPU.\n");
194184802Sjkoshy		return (NULL);
195184802Sjkoshy	}
196184802Sjkoshy
197233628Sfabient	/* Allocate base class and initialize machine dependent struct */
198233628Sfabient	pmc_mdep = pmc_mdep_alloc(nclasses);
199184802Sjkoshy
200249069Ssbruno	pmc_mdep->pmd_cputype	 = cputype;
201184802Sjkoshy	pmc_mdep->pmd_switch_in	 = intel_switch_in;
202184802Sjkoshy	pmc_mdep->pmd_switch_out = intel_switch_out;
203184802Sjkoshy
204184802Sjkoshy	ncpus = pmc_cpu_max();
205250101Sdavide	error = pmc_tsc_initialize(pmc_mdep, ncpus);
206250101Sdavide	if (error)
207250101Sdavide		goto error;
208184802Sjkoshy	switch (cputype) {
209184802Sjkoshy#if	defined(__i386__) || defined(__amd64__)
210185363Sjkoshy		/*
211185363Sjkoshy		 * Intel Core, Core 2 and Atom processors.
212185363Sjkoshy		 */
213185363Sjkoshy	case PMC_CPU_INTEL_ATOM:
214266911Shiren	case PMC_CPU_INTEL_ATOM_SILVERMONT:
215185363Sjkoshy	case PMC_CPU_INTEL_CORE:
216185363Sjkoshy	case PMC_CPU_INTEL_CORE2:
217185585Sjkoshy	case PMC_CPU_INTEL_CORE2EXTREME:
218187761Sjeff	case PMC_CPU_INTEL_COREI7:
219267602Skib	case PMC_CPU_INTEL_NEHALEM_EX:
220240164Sfabient	case PMC_CPU_INTEL_IVYBRIDGE:
221232366Sdavide	case PMC_CPU_INTEL_SANDYBRIDGE:
222206089Sfabient	case PMC_CPU_INTEL_WESTMERE:
223267602Skib	case PMC_CPU_INTEL_WESTMERE_EX:
224241738Ssbruno	case PMC_CPU_INTEL_SANDYBRIDGE_XEON:
225246166Ssbruno	case PMC_CPU_INTEL_IVYBRIDGE_XEON:
226248842Ssbruno	case PMC_CPU_INTEL_HASWELL:
227185363Sjkoshy		error = pmc_core_initialize(pmc_mdep, ncpus);
228185363Sjkoshy		break;
229184802Sjkoshy
230184802Sjkoshy		/*
231184802Sjkoshy		 * Intel Pentium 4 Processors, and P4/EMT64 processors.
232184802Sjkoshy		 */
233184802Sjkoshy
234184802Sjkoshy	case PMC_CPU_INTEL_PIV:
235184802Sjkoshy		error = pmc_p4_initialize(pmc_mdep, ncpus);
236184802Sjkoshy		break;
237184802Sjkoshy#endif
238184802Sjkoshy
239184802Sjkoshy#if	defined(__i386__)
240184802Sjkoshy		/*
241184802Sjkoshy		 * P6 Family Processors
242184802Sjkoshy		 */
243184802Sjkoshy
244184802Sjkoshy	case PMC_CPU_INTEL_P6:
245184802Sjkoshy	case PMC_CPU_INTEL_CL:
246184802Sjkoshy	case PMC_CPU_INTEL_PII:
247184802Sjkoshy	case PMC_CPU_INTEL_PIII:
248184802Sjkoshy	case PMC_CPU_INTEL_PM:
249184802Sjkoshy		error = pmc_p6_initialize(pmc_mdep, ncpus);
250184802Sjkoshy		break;
251184802Sjkoshy
252184802Sjkoshy		/*
253184802Sjkoshy		 * Intel Pentium PMCs.
254184802Sjkoshy		 */
255184802Sjkoshy
256184802Sjkoshy	case PMC_CPU_INTEL_P5:
257184802Sjkoshy		error = pmc_p5_initialize(pmc_mdep, ncpus);
258184802Sjkoshy		break;
259184802Sjkoshy#endif
260184802Sjkoshy
261184802Sjkoshy	default:
262184802Sjkoshy		KASSERT(0, ("[intel,%d] Unknown CPU type", __LINE__));
263184802Sjkoshy	}
264184802Sjkoshy
265250101Sdavide	if (error) {
266250101Sdavide		pmc_tsc_finalize(pmc_mdep);
267233569Sgonzo		goto error;
268250101Sdavide	}
269233569Sgonzo
270206089Sfabient	/*
271206089Sfabient	 * Init the uncore class.
272206089Sfabient	 */
273206089Sfabient#if	defined(__i386__) || defined(__amd64__)
274206089Sfabient	switch (cputype) {
275206089Sfabient		/*
276206089Sfabient		 * Intel Corei7 and Westmere processors.
277206089Sfabient		 */
278206089Sfabient	case PMC_CPU_INTEL_COREI7:
279248842Ssbruno	case PMC_CPU_INTEL_HASWELL:
280232366Sdavide	case PMC_CPU_INTEL_SANDYBRIDGE:
281206089Sfabient	case PMC_CPU_INTEL_WESTMERE:
282206089Sfabient		error = pmc_uncore_initialize(pmc_mdep, ncpus);
283206089Sfabient		break;
284206089Sfabient	default:
285206089Sfabient		break;
286206089Sfabient	}
287206089Sfabient#endif
288184802Sjkoshy  error:
289184802Sjkoshy	if (error) {
290250097Sdavide		pmc_mdep_free(pmc_mdep);
291184802Sjkoshy		pmc_mdep = NULL;
292184802Sjkoshy	}
293184802Sjkoshy
294184802Sjkoshy	return (pmc_mdep);
295184802Sjkoshy}
296184802Sjkoshy
297184802Sjkoshyvoid
298184802Sjkoshypmc_intel_finalize(struct pmc_mdep *md)
299184802Sjkoshy{
300184802Sjkoshy	pmc_tsc_finalize(md);
301184802Sjkoshy
302184802Sjkoshy	switch (md->pmd_cputype) {
303184802Sjkoshy#if	defined(__i386__) || defined(__amd64__)
304185363Sjkoshy	case PMC_CPU_INTEL_ATOM:
305266911Shiren	case PMC_CPU_INTEL_ATOM_SILVERMONT:
306185363Sjkoshy	case PMC_CPU_INTEL_CORE:
307185363Sjkoshy	case PMC_CPU_INTEL_CORE2:
308185585Sjkoshy	case PMC_CPU_INTEL_CORE2EXTREME:
309206089Sfabient	case PMC_CPU_INTEL_COREI7:
310267602Skib	case PMC_CPU_INTEL_NEHALEM_EX:
311248842Ssbruno	case PMC_CPU_INTEL_HASWELL:
312240164Sfabient	case PMC_CPU_INTEL_IVYBRIDGE:
313232366Sdavide	case PMC_CPU_INTEL_SANDYBRIDGE:
314206089Sfabient	case PMC_CPU_INTEL_WESTMERE:
315267602Skib	case PMC_CPU_INTEL_WESTMERE_EX:
316241738Ssbruno	case PMC_CPU_INTEL_SANDYBRIDGE_XEON:
317246166Ssbruno	case PMC_CPU_INTEL_IVYBRIDGE_XEON:
318185363Sjkoshy		pmc_core_finalize(md);
319185363Sjkoshy		break;
320185363Sjkoshy
321184802Sjkoshy	case PMC_CPU_INTEL_PIV:
322184802Sjkoshy		pmc_p4_finalize(md);
323184802Sjkoshy		break;
324184802Sjkoshy#endif
325184802Sjkoshy#if	defined(__i386__)
326184802Sjkoshy	case PMC_CPU_INTEL_P6:
327184802Sjkoshy	case PMC_CPU_INTEL_CL:
328184802Sjkoshy	case PMC_CPU_INTEL_PII:
329184802Sjkoshy	case PMC_CPU_INTEL_PIII:
330184802Sjkoshy	case PMC_CPU_INTEL_PM:
331184802Sjkoshy		pmc_p6_finalize(md);
332184802Sjkoshy		break;
333184802Sjkoshy	case PMC_CPU_INTEL_P5:
334184802Sjkoshy		pmc_p5_finalize(md);
335184802Sjkoshy		break;
336184802Sjkoshy#endif
337184802Sjkoshy	default:
338184802Sjkoshy		KASSERT(0, ("[intel,%d] unknown CPU type", __LINE__));
339184802Sjkoshy	}
340206089Sfabient
341206089Sfabient	/*
342206089Sfabient	 * Uncore.
343206089Sfabient	 */
344206089Sfabient#if	defined(__i386__) || defined(__amd64__)
345206089Sfabient	switch (md->pmd_cputype) {
346206089Sfabient	case PMC_CPU_INTEL_COREI7:
347248842Ssbruno	case PMC_CPU_INTEL_HASWELL:
348232366Sdavide	case PMC_CPU_INTEL_SANDYBRIDGE:
349206089Sfabient	case PMC_CPU_INTEL_WESTMERE:
350206089Sfabient		pmc_uncore_finalize(md);
351206089Sfabient		break;
352206089Sfabient	default:
353206089Sfabient		break;
354206089Sfabient	}
355206089Sfabient#endif
356184802Sjkoshy}
357