xref: /freebsd/sys/dev/hwpmc/hwpmc_x86.c (revision 9f0c02d4255b2036f652c924d3df4fa88c7c721a)
1 /*-
2  * Copyright (c) 2005, Joseph Koshy
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26 
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
29 
30 #include <sys/param.h>
31 #include <sys/bus.h>
32 #include <sys/pmc.h>
33 #include <sys/systm.h>
34 
35 #include <machine/apicreg.h>
36 #include <machine/pmc_mdep.h>
37 #include <machine/md_var.h>
38 
39 extern volatile lapic_t *lapic;
40 
41 void
42 pmc_x86_lapic_enable_pmc_interrupt(void)
43 {
44 	uint32_t value;
45 
46 	value =  lapic->lvt_pcint;
47 	value &= ~APIC_LVT_M;
48 	lapic->lvt_pcint = value;
49 }
50 
51 
52 static struct pmc_mdep *
53 pmc_intel_initialize(void)
54 {
55 	struct pmc_mdep *pmc_mdep;
56 	enum pmc_cputype cputype;
57 	int error, model;
58 
59 	KASSERT(strcmp(cpu_vendor, "GenuineIntel") == 0,
60 	    ("[intel,%d] Initializing non-intel processor", __LINE__));
61 
62 	PMCDBG(MDP,INI,0, "intel-initialize cpuid=0x%x", cpu_id);
63 
64 	cputype = -1;
65 
66 	switch (cpu_id & 0xF00) {
67 #if	defined(__i386__)
68 	case 0x500:		/* Pentium family processors */
69 		cputype = PMC_CPU_INTEL_P5;
70 		break;
71 	case 0x600:		/* Pentium Pro, Celeron, Pentium II & III */
72 		switch ((cpu_id & 0xF0) >> 4) { /* model number field */
73 		case 0x1:
74 			cputype = PMC_CPU_INTEL_P6;
75 			break;
76 		case 0x3: case 0x5:
77 			cputype = PMC_CPU_INTEL_PII;
78 			break;
79 		case 0x6:
80 			cputype = PMC_CPU_INTEL_CL;
81 			break;
82 		case 0x7: case 0x8: case 0xA: case 0xB:
83 			cputype = PMC_CPU_INTEL_PIII;
84 			break;
85 		case 0x9: case 0xD: case 0xE:
86 			cputype = PMC_CPU_INTEL_PM;
87 			break;
88 		}
89 		break;
90 #endif
91 #if	defined(__i386__) || defined(__amd64__)
92 	case 0xF00:		/* P4 */
93 		model = ((cpu_id & 0xF0000) >> 12) | ((cpu_id & 0xF0) >> 4);
94 		if (model >= 0 && model <= 6) /* known models */
95 			cputype = PMC_CPU_INTEL_PIV;
96 		break;
97 	}
98 #endif
99 
100 	if ((int) cputype == -1) {
101 		printf("pmc: Unknown Intel CPU.\n");
102 		return NULL;
103 	}
104 
105 	MALLOC(pmc_mdep, struct pmc_mdep *, sizeof(struct pmc_mdep),
106 	    M_PMC, M_WAITOK|M_ZERO);
107 
108 	pmc_mdep->pmd_cputype 	    = cputype;
109 	pmc_mdep->pmd_nclass	    = 2;
110 	pmc_mdep->pmd_classes[0].pm_class    = PMC_CLASS_TSC;
111 	pmc_mdep->pmd_classes[0].pm_caps     = PMC_CAP_READ;
112 	pmc_mdep->pmd_classes[0].pm_width    = 64;
113 	pmc_mdep->pmd_nclasspmcs[0] = 1;
114 
115 	error = 0;
116 
117 	switch (cputype) {
118 
119 #if	defined(__i386__) || defined(__amd64__)
120 
121 		/*
122 		 * Intel Pentium 4 Processors, and P4/EMT64 processors.
123 		 */
124 
125 	case PMC_CPU_INTEL_PIV:
126 		error = pmc_initialize_p4(pmc_mdep);
127 		break;
128 #endif
129 
130 #if	defined(__i386__)
131 		/*
132 		 * P6 Family Processors
133 		 */
134 
135 	case PMC_CPU_INTEL_P6:
136 	case PMC_CPU_INTEL_CL:
137 	case PMC_CPU_INTEL_PII:
138 	case PMC_CPU_INTEL_PIII:
139 	case PMC_CPU_INTEL_PM:
140 
141 		error = pmc_initialize_p6(pmc_mdep);
142 		break;
143 
144 		/*
145 		 * Intel Pentium PMCs.
146 		 */
147 
148 	case PMC_CPU_INTEL_P5:
149 		error = pmc_initialize_p5(pmc_mdep);
150 		break;
151 #endif
152 
153 	default:
154 		KASSERT(0,("[intel,%d] Unknown CPU type", __LINE__));
155 	}
156 
157 	if (error) {
158 		FREE(pmc_mdep, M_PMC);
159 		pmc_mdep = NULL;
160 	}
161 
162 	return pmc_mdep;
163 }
164 
165 
166 /*
167  * Machine dependent initialization for x86 class platforms.
168  */
169 
170 struct pmc_mdep *
171 pmc_md_initialize()
172 {
173 	int i;
174 	struct pmc_mdep *md;
175 
176 	/* determine the CPU kind */
177 	md = NULL;
178 	if (strcmp(cpu_vendor, "AuthenticAMD") == 0)
179 		md = pmc_amd_initialize();
180 	else if (strcmp(cpu_vendor, "GenuineIntel") == 0)
181 		md = pmc_intel_initialize();
182 
183 	/* disallow sampling if we do not have an LAPIC */
184 	if (md != NULL && lapic == NULL)
185 		for (i = 1; i < md->pmd_nclass; i++)
186 			md->pmd_classes[i].pm_caps &= ~PMC_CAP_INTERRUPT;
187 
188 	return md;
189 }
190