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: releng/11.0/sys/dev/hwpmc/hwpmc_intel.c 291494 2015-11-30 17:35:49Z rrs $");
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
49282658Sjhb	PMCDBG3(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
56282658Sjhb	PMCDBG1(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
67282658Sjhb	PMCDBG3(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;
81259647Sattilio	int error, model, nclasses, ncpus, stepping, verov;
82184802Sjkoshy
83185341Sjkim	KASSERT(cpu_vendor_id == CPU_VENDOR_INTEL,
84184802Sjkoshy	    ("[intel,%d] Initializing non-intel processor", __LINE__));
85184802Sjkoshy
86282658Sjhb	PMCDBG1(MDP,INI,0, "intel-initialize cpuid=0x%x", cpu_id);
87184802Sjkoshy
88184802Sjkoshy	cputype = -1;
89184802Sjkoshy	nclasses = 2;
90250097Sdavide	error = 0;
91259647Sattilio	verov = 0;
92185363Sjkoshy	model = ((cpu_id & 0xF0000) >> 12) | ((cpu_id & 0xF0) >> 4);
93259647Sattilio	stepping = cpu_id & 0xF;
94185363Sjkoshy
95184802Sjkoshy	switch (cpu_id & 0xF00) {
96184802Sjkoshy#if	defined(__i386__)
97184802Sjkoshy	case 0x500:		/* Pentium family processors */
98184802Sjkoshy		cputype = PMC_CPU_INTEL_P5;
99184802Sjkoshy		break;
100185363Sjkoshy#endif
101184802Sjkoshy	case 0x600:		/* Pentium Pro, Celeron, Pentium II & III */
102185363Sjkoshy		switch (model) {
103185363Sjkoshy#if	defined(__i386__)
104184802Sjkoshy		case 0x1:
105184802Sjkoshy			cputype = PMC_CPU_INTEL_P6;
106184802Sjkoshy			break;
107184802Sjkoshy		case 0x3: case 0x5:
108184802Sjkoshy			cputype = PMC_CPU_INTEL_PII;
109184802Sjkoshy			break;
110185363Sjkoshy		case 0x6: case 0x16:
111184802Sjkoshy			cputype = PMC_CPU_INTEL_CL;
112184802Sjkoshy			break;
113184802Sjkoshy		case 0x7: case 0x8: case 0xA: case 0xB:
114184802Sjkoshy			cputype = PMC_CPU_INTEL_PIII;
115184802Sjkoshy			break;
116184802Sjkoshy		case 0x9: case 0xD:
117184802Sjkoshy			cputype = PMC_CPU_INTEL_PM;
118184802Sjkoshy			break;
119185363Sjkoshy#endif
120185363Sjkoshy		case 0xE:
121185363Sjkoshy			cputype = PMC_CPU_INTEL_CORE;
122185363Sjkoshy			break;
123185363Sjkoshy		case 0xF:
124259647Sattilio			/* Per Intel document 315338-020. */
125259647Sattilio			if (stepping == 0x7) {
126259647Sattilio				cputype = PMC_CPU_INTEL_CORE;
127259647Sattilio				verov = 1;
128259647Sattilio			} else {
129259647Sattilio				cputype = PMC_CPU_INTEL_CORE2;
130259647Sattilio				nclasses = 3;
131259647Sattilio			}
132185363Sjkoshy			break;
133185363Sjkoshy		case 0x17:
134185363Sjkoshy			cputype = PMC_CPU_INTEL_CORE2EXTREME;
135185363Sjkoshy			nclasses = 3;
136185363Sjkoshy			break;
137185363Sjkoshy		case 0x1C:	/* Per Intel document 320047-002. */
138185363Sjkoshy			cputype = PMC_CPU_INTEL_ATOM;
139185363Sjkoshy			nclasses = 3;
140185363Sjkoshy			break;
141187761Sjeff		case 0x1A:
142249069Ssbruno		case 0x1E:	/*
143249069Ssbruno				 * Per Intel document 253669-032 9/2009,
144249069Ssbruno				 * pages A-2 and A-57
145249069Ssbruno				 */
146249069Ssbruno		case 0x1F:	/*
147249069Ssbruno				 * Per Intel document 253669-032 9/2009,
148249069Ssbruno				 * pages A-2 and A-57
149249069Ssbruno				 */
150187761Sjeff			cputype = PMC_CPU_INTEL_COREI7;
151206089Sfabient			nclasses = 5;
152187761Sjeff			break;
153267062Skib		case 0x2E:
154267062Skib			cputype = PMC_CPU_INTEL_NEHALEM_EX;
155267062Skib			nclasses = 3;
156267062Skib			break;
157206089Sfabient		case 0x25:	/* Per Intel document 253669-033US 12/2009. */
158206089Sfabient		case 0x2C:	/* Per Intel document 253669-033US 12/2009. */
159206089Sfabient			cputype = PMC_CPU_INTEL_WESTMERE;
160206089Sfabient			nclasses = 5;
161206089Sfabient			break;
162267062Skib		case 0x2F:	/* Westmere-EX, seen in wild */
163267062Skib			cputype = PMC_CPU_INTEL_WESTMERE_EX;
164267062Skib			nclasses = 3;
165267062Skib			break;
166232366Sdavide		case 0x2A:	/* Per Intel document 253669-039US 05/2011. */
167232366Sdavide			cputype = PMC_CPU_INTEL_SANDYBRIDGE;
168232366Sdavide			nclasses = 5;
169232366Sdavide			break;
170241738Ssbruno		case 0x2D:	/* Per Intel document 253669-044US 08/2012. */
171241738Ssbruno			cputype = PMC_CPU_INTEL_SANDYBRIDGE_XEON;
172241738Ssbruno			nclasses = 3;
173241738Ssbruno			break;
174240164Sfabient		case 0x3A:	/* Per Intel document 253669-043US 05/2012. */
175240164Sfabient			cputype = PMC_CPU_INTEL_IVYBRIDGE;
176240164Sfabient			nclasses = 3;
177240164Sfabient			break;
178246166Ssbruno		case 0x3E:	/* Per Intel document 325462-045US 01/2013. */
179246166Ssbruno			cputype = PMC_CPU_INTEL_IVYBRIDGE_XEON;
180246166Ssbruno			nclasses = 3;
181246166Ssbruno			break;
182291494Srrs		case 0x4e:
183291494Srrs		case 0x5e:
184291494Srrs			cputype = PMC_CPU_INTEL_SKYLAKE;
185291494Srrs			nclasses = 3;
186291494Srrs			break;
187281102Srpaulo		case 0x3D:
188291494Srrs		case 0x47:
189281102Srpaulo			cputype = PMC_CPU_INTEL_BROADWELL;
190281102Srpaulo			nclasses = 3;
191281102Srpaulo			break;
192291494Srrs		case 0x4f:
193291494Srrs		case 0x56:
194291494Srrs			cputype = PMC_CPU_INTEL_BROADWELL_XEON;
195291494Srrs			nclasses = 3;
196291494Srrs			break;
197277177Srrs		case 0x3F:	/* Per Intel document 325462-045US 09/2014. */
198277177Srrs		case 0x46:	/* Per Intel document 325462-045US 09/2014. */
199277177Srrs			        /* Should 46 be XEON. probably its own? */
200277177Srrs			cputype = PMC_CPU_INTEL_HASWELL_XEON;
201277177Srrs			nclasses = 3;
202277177Srrs			break;
203248842Ssbruno		case 0x3C:	/* Per Intel document 325462-045US 01/2013. */
204277177Srrs		case 0x45:	/* Per Intel document 325462-045US 09/2014. */
205248842Ssbruno			cputype = PMC_CPU_INTEL_HASWELL;
206248842Ssbruno			nclasses = 5;
207248842Ssbruno			break;
208263446Shiren		case 0x4D:      /* Per Intel document 330061-001 01/2014. */
209263446Shiren			cputype = PMC_CPU_INTEL_ATOM_SILVERMONT;
210263446Shiren			nclasses = 3;
211263446Shiren			break;
212184802Sjkoshy		}
213184802Sjkoshy		break;
214184802Sjkoshy#if	defined(__i386__) || defined(__amd64__)
215184802Sjkoshy	case 0xF00:		/* P4 */
216184802Sjkoshy		if (model >= 0 && model <= 6) /* known models */
217184802Sjkoshy			cputype = PMC_CPU_INTEL_PIV;
218184802Sjkoshy		break;
219184802Sjkoshy	}
220184802Sjkoshy#endif
221184802Sjkoshy
222184802Sjkoshy	if ((int) cputype == -1) {
223184802Sjkoshy		printf("pmc: Unknown Intel CPU.\n");
224184802Sjkoshy		return (NULL);
225184802Sjkoshy	}
226184802Sjkoshy
227233628Sfabient	/* Allocate base class and initialize machine dependent struct */
228233628Sfabient	pmc_mdep = pmc_mdep_alloc(nclasses);
229184802Sjkoshy
230249069Ssbruno	pmc_mdep->pmd_cputype	 = cputype;
231184802Sjkoshy	pmc_mdep->pmd_switch_in	 = intel_switch_in;
232184802Sjkoshy	pmc_mdep->pmd_switch_out = intel_switch_out;
233184802Sjkoshy
234184802Sjkoshy	ncpus = pmc_cpu_max();
235250101Sdavide	error = pmc_tsc_initialize(pmc_mdep, ncpus);
236250101Sdavide	if (error)
237250101Sdavide		goto error;
238184802Sjkoshy	switch (cputype) {
239184802Sjkoshy#if	defined(__i386__) || defined(__amd64__)
240185363Sjkoshy		/*
241185363Sjkoshy		 * Intel Core, Core 2 and Atom processors.
242185363Sjkoshy		 */
243185363Sjkoshy	case PMC_CPU_INTEL_ATOM:
244263446Shiren	case PMC_CPU_INTEL_ATOM_SILVERMONT:
245281102Srpaulo	case PMC_CPU_INTEL_BROADWELL:
246291494Srrs	case PMC_CPU_INTEL_BROADWELL_XEON:
247291494Srrs	case PMC_CPU_INTEL_SKYLAKE:
248185363Sjkoshy	case PMC_CPU_INTEL_CORE:
249185363Sjkoshy	case PMC_CPU_INTEL_CORE2:
250185585Sjkoshy	case PMC_CPU_INTEL_CORE2EXTREME:
251187761Sjeff	case PMC_CPU_INTEL_COREI7:
252267062Skib	case PMC_CPU_INTEL_NEHALEM_EX:
253240164Sfabient	case PMC_CPU_INTEL_IVYBRIDGE:
254232366Sdavide	case PMC_CPU_INTEL_SANDYBRIDGE:
255206089Sfabient	case PMC_CPU_INTEL_WESTMERE:
256267062Skib	case PMC_CPU_INTEL_WESTMERE_EX:
257241738Ssbruno	case PMC_CPU_INTEL_SANDYBRIDGE_XEON:
258246166Ssbruno	case PMC_CPU_INTEL_IVYBRIDGE_XEON:
259248842Ssbruno	case PMC_CPU_INTEL_HASWELL:
260277177Srrs	case PMC_CPU_INTEL_HASWELL_XEON:
261259647Sattilio		error = pmc_core_initialize(pmc_mdep, ncpus, verov);
262185363Sjkoshy		break;
263184802Sjkoshy
264184802Sjkoshy		/*
265184802Sjkoshy		 * Intel Pentium 4 Processors, and P4/EMT64 processors.
266184802Sjkoshy		 */
267184802Sjkoshy
268184802Sjkoshy	case PMC_CPU_INTEL_PIV:
269184802Sjkoshy		error = pmc_p4_initialize(pmc_mdep, ncpus);
270184802Sjkoshy		break;
271184802Sjkoshy#endif
272184802Sjkoshy
273184802Sjkoshy#if	defined(__i386__)
274184802Sjkoshy		/*
275184802Sjkoshy		 * P6 Family Processors
276184802Sjkoshy		 */
277184802Sjkoshy
278184802Sjkoshy	case PMC_CPU_INTEL_P6:
279184802Sjkoshy	case PMC_CPU_INTEL_CL:
280184802Sjkoshy	case PMC_CPU_INTEL_PII:
281184802Sjkoshy	case PMC_CPU_INTEL_PIII:
282184802Sjkoshy	case PMC_CPU_INTEL_PM:
283184802Sjkoshy		error = pmc_p6_initialize(pmc_mdep, ncpus);
284184802Sjkoshy		break;
285184802Sjkoshy
286184802Sjkoshy		/*
287184802Sjkoshy		 * Intel Pentium PMCs.
288184802Sjkoshy		 */
289184802Sjkoshy
290184802Sjkoshy	case PMC_CPU_INTEL_P5:
291184802Sjkoshy		error = pmc_p5_initialize(pmc_mdep, ncpus);
292184802Sjkoshy		break;
293184802Sjkoshy#endif
294184802Sjkoshy
295184802Sjkoshy	default:
296184802Sjkoshy		KASSERT(0, ("[intel,%d] Unknown CPU type", __LINE__));
297184802Sjkoshy	}
298184802Sjkoshy
299250101Sdavide	if (error) {
300250101Sdavide		pmc_tsc_finalize(pmc_mdep);
301233569Sgonzo		goto error;
302250101Sdavide	}
303233569Sgonzo
304206089Sfabient	/*
305206089Sfabient	 * Init the uncore class.
306206089Sfabient	 */
307206089Sfabient#if	defined(__i386__) || defined(__amd64__)
308206089Sfabient	switch (cputype) {
309206089Sfabient		/*
310206089Sfabient		 * Intel Corei7 and Westmere processors.
311206089Sfabient		 */
312206089Sfabient	case PMC_CPU_INTEL_COREI7:
313248842Ssbruno	case PMC_CPU_INTEL_HASWELL:
314232366Sdavide	case PMC_CPU_INTEL_SANDYBRIDGE:
315206089Sfabient	case PMC_CPU_INTEL_WESTMERE:
316281102Srpaulo	case PMC_CPU_INTEL_BROADWELL:
317206089Sfabient		error = pmc_uncore_initialize(pmc_mdep, ncpus);
318206089Sfabient		break;
319206089Sfabient	default:
320206089Sfabient		break;
321206089Sfabient	}
322206089Sfabient#endif
323184802Sjkoshy  error:
324184802Sjkoshy	if (error) {
325250097Sdavide		pmc_mdep_free(pmc_mdep);
326184802Sjkoshy		pmc_mdep = NULL;
327184802Sjkoshy	}
328184802Sjkoshy
329184802Sjkoshy	return (pmc_mdep);
330184802Sjkoshy}
331184802Sjkoshy
332184802Sjkoshyvoid
333184802Sjkoshypmc_intel_finalize(struct pmc_mdep *md)
334184802Sjkoshy{
335184802Sjkoshy	pmc_tsc_finalize(md);
336184802Sjkoshy
337184802Sjkoshy	switch (md->pmd_cputype) {
338184802Sjkoshy#if	defined(__i386__) || defined(__amd64__)
339185363Sjkoshy	case PMC_CPU_INTEL_ATOM:
340263446Shiren	case PMC_CPU_INTEL_ATOM_SILVERMONT:
341281102Srpaulo	case PMC_CPU_INTEL_BROADWELL:
342291494Srrs	case PMC_CPU_INTEL_BROADWELL_XEON:
343291494Srrs	case PMC_CPU_INTEL_SKYLAKE:
344185363Sjkoshy	case PMC_CPU_INTEL_CORE:
345185363Sjkoshy	case PMC_CPU_INTEL_CORE2:
346185585Sjkoshy	case PMC_CPU_INTEL_CORE2EXTREME:
347206089Sfabient	case PMC_CPU_INTEL_COREI7:
348267062Skib	case PMC_CPU_INTEL_NEHALEM_EX:
349248842Ssbruno	case PMC_CPU_INTEL_HASWELL:
350277177Srrs	case PMC_CPU_INTEL_HASWELL_XEON:
351240164Sfabient	case PMC_CPU_INTEL_IVYBRIDGE:
352232366Sdavide	case PMC_CPU_INTEL_SANDYBRIDGE:
353206089Sfabient	case PMC_CPU_INTEL_WESTMERE:
354267062Skib	case PMC_CPU_INTEL_WESTMERE_EX:
355241738Ssbruno	case PMC_CPU_INTEL_SANDYBRIDGE_XEON:
356246166Ssbruno	case PMC_CPU_INTEL_IVYBRIDGE_XEON:
357185363Sjkoshy		pmc_core_finalize(md);
358185363Sjkoshy		break;
359185363Sjkoshy
360184802Sjkoshy	case PMC_CPU_INTEL_PIV:
361184802Sjkoshy		pmc_p4_finalize(md);
362184802Sjkoshy		break;
363184802Sjkoshy#endif
364184802Sjkoshy#if	defined(__i386__)
365184802Sjkoshy	case PMC_CPU_INTEL_P6:
366184802Sjkoshy	case PMC_CPU_INTEL_CL:
367184802Sjkoshy	case PMC_CPU_INTEL_PII:
368184802Sjkoshy	case PMC_CPU_INTEL_PIII:
369184802Sjkoshy	case PMC_CPU_INTEL_PM:
370184802Sjkoshy		pmc_p6_finalize(md);
371184802Sjkoshy		break;
372184802Sjkoshy	case PMC_CPU_INTEL_P5:
373184802Sjkoshy		pmc_p5_finalize(md);
374184802Sjkoshy		break;
375184802Sjkoshy#endif
376184802Sjkoshy	default:
377184802Sjkoshy		KASSERT(0, ("[intel,%d] unknown CPU type", __LINE__));
378184802Sjkoshy	}
379206089Sfabient
380206089Sfabient	/*
381206089Sfabient	 * Uncore.
382206089Sfabient	 */
383206089Sfabient#if	defined(__i386__) || defined(__amd64__)
384206089Sfabient	switch (md->pmd_cputype) {
385281102Srpaulo	case PMC_CPU_INTEL_BROADWELL:
386206089Sfabient	case PMC_CPU_INTEL_COREI7:
387248842Ssbruno	case PMC_CPU_INTEL_HASWELL:
388232366Sdavide	case PMC_CPU_INTEL_SANDYBRIDGE:
389206089Sfabient	case PMC_CPU_INTEL_WESTMERE:
390206089Sfabient		pmc_uncore_finalize(md);
391206089Sfabient		break;
392206089Sfabient	default:
393206089Sfabient		break;
394206089Sfabient	}
395206089Sfabient#endif
396184802Sjkoshy}
397