hwpmc_amd.c revision 145581
1/*-
2 * Copyright (c) 2003-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
28#include <sys/cdefs.h>
29__FBSDID("$FreeBSD: head/sys/dev/hwpmc/hwpmc_amd.c 145338 2005-04-20 20:26:39Z marcel $");
30
31/* Support for the AMD K7 and later processors */
32
33#include <sys/param.h>
34#include <sys/lock.h>
35#include <sys/malloc.h>
36#include <sys/mutex.h>
37#include <sys/pmc.h>
38#include <sys/smp.h>
39#include <sys/systm.h>
40
41#include <machine/md_var.h>
42
43/* AMD K7 and K8 PMCs */
44
45#define	AMD_PMC_EVSEL_0		0xC0010000
46#define	AMD_PMC_EVSEL_1		0xC0010001
47#define	AMD_PMC_EVSEL_2		0xC0010002
48#define	AMD_PMC_EVSEL_3		0xC0010003
49
50#define	AMD_PMC_PERFCTR_0	0xC0010004
51#define	AMD_PMC_PERFCTR_1	0xC0010005
52#define	AMD_PMC_PERFCTR_2	0xC0010006
53#define	AMD_PMC_PERFCTR_3	0xC0010007
54
55#define	K7_VALID_EVENT_CODE(c) (((c) >= 0x40 && (c) <= 0x47) ||		\
56	((c) >= 0x80 && (c) <= 0x85) || ((c) >= 0xC0 && (c) <= 0xC7) ||	\
57	((c) >= 0xCD && (c) <= 0xCF))
58
59#define AMD_PMC_CAPS (PMC_CAP_INTERRUPT | PMC_CAP_USER | \
60	PMC_CAP_SYSTEM | PMC_CAP_EDGE | PMC_CAP_THRESHOLD | \
61	PMC_CAP_READ | PMC_CAP_WRITE | PMC_CAP_INVERT | PMC_CAP_QUALIFIER)
62
63/* reserved bits include bit 21 and the top two bits of the unit mask */
64#define K7_PMC_RESERVED ((1 << 21) | (3 << 13))
65
66#define	K8_PMC_RESERVED (1 << 21)
67
68#define AMD_PMC_IS_STOPPED(evsel) ((rdmsr((evsel)) & AMD_PMC_ENABLE) == 0)
69#define AMD_PMC_HAS_OVERFLOWED(pmc) ((rdpmc(pmc) & (1ULL << 47)) == 0)
70
71#if	__i386__
72#define	AMD_NPMCS		K7_NPMCS
73#define	AMD_PMC_CLASS		PMC_CLASS_K7
74#define	AMD_PMC_COUNTERMASK	K7_PMC_COUNTERMASK
75#define	AMD_PMC_TO_COUNTER(x)	K7_PMC_TO_COUNTER(x)
76#define	AMD_PMC_INVERT		K7_PMC_INVERT
77#define	AMD_PMC_ENABLE		K7_PMC_ENABLE
78#define	AMD_PMC_INT		K7_PMC_INT
79#define	AMD_PMC_PC		K7_PMC_PC
80#define	AMD_PMC_EDGE		K7_PMC_EDGE
81#define	AMD_PMC_OS		K7_PMC_OS
82#define	AMD_PMC_USR		K7_PMC_USR
83
84#define	AMD_PMC_UNITMASK_M	K7_PMC_UNITMASK_M
85#define	AMD_PMC_UNITMASK_O	K7_PMC_UNITMASK_O
86#define	AMD_PMC_UNITMASK_E	K7_PMC_UNITMASK_E
87#define	AMD_PMC_UNITMASK_S	K7_PMC_UNITMASK_S
88#define	AMD_PMC_UNITMASK_I	K7_PMC_UNITMASK_I
89
90#define	AMD_PMC_UNITMASK	K7_PMC_UNITMASK
91#define	AMD_PMC_EVENTMASK	K7_PMC_EVENTMASK
92#define	AMD_PMC_TO_UNITMASK(x)	K7_PMC_TO_UNITMASK(x)
93#define	AMD_PMC_TO_EVENTMASK(x)	K7_PMC_TO_EVENTMASK(x)
94#define	AMD_VALID_BITS		K7_VALID_BITS
95
96#define	AMD_PMC_CLASS_NAME	"K7-"
97
98#elif	__amd64__
99
100#define	AMD_NPMCS		K8_NPMCS
101#define	AMD_PMC_CLASS		PMC_CLASS_K8
102#define	AMD_PMC_COUNTERMASK	K8_PMC_COUNTERMASK
103#define	AMD_PMC_TO_COUNTER(x)	K8_PMC_TO_COUNTER(x)
104#define	AMD_PMC_INVERT		K8_PMC_INVERT
105#define	AMD_PMC_ENABLE		K8_PMC_ENABLE
106#define	AMD_PMC_INT		K8_PMC_INT
107#define	AMD_PMC_PC		K8_PMC_PC
108#define	AMD_PMC_EDGE		K8_PMC_EDGE
109#define	AMD_PMC_OS		K8_PMC_OS
110#define	AMD_PMC_USR		K8_PMC_USR
111
112#define	AMD_PMC_UNITMASK_M	K8_PMC_UNITMASK_M
113#define	AMD_PMC_UNITMASK_O	K8_PMC_UNITMASK_O
114#define	AMD_PMC_UNITMASK_E	K8_PMC_UNITMASK_E
115#define	AMD_PMC_UNITMASK_S	K8_PMC_UNITMASK_S
116#define	AMD_PMC_UNITMASK_I	K8_PMC_UNITMASK_I
117
118#define	AMD_PMC_UNITMASK	K8_PMC_UNITMASK
119#define	AMD_PMC_EVENTMASK	K8_PMC_EVENTMASK
120#define	AMD_PMC_TO_UNITMASK(x)	K8_PMC_TO_UNITMASK(x)
121#define	AMD_PMC_TO_EVENTMASK(x)	K8_PMC_TO_EVENTMASK(x)
122#define	AMD_VALID_BITS		K8_VALID_BITS
123
124#define	AMD_PMC_CLASS_NAME	"K8-"
125
126#else
127#error	Unsupported architecture.
128#endif
129
130/* AMD K7 & K8 PMCs */
131struct amd_descr {
132	struct pmc_descr pm_descr;  /* "base class" */
133	uint32_t	pm_evsel;   /* address of EVSEL register */
134	uint32_t	pm_perfctr; /* address of PERFCTR register */
135};
136
137static const struct amd_descr amd_pmcdesc[AMD_NPMCS] =
138{
139    {
140	.pm_descr =
141	{
142		.pd_name  = "TSC",
143		.pd_class = PMC_CLASS_TSC,
144		.pd_caps  = PMC_CAP_READ,
145		.pd_width = 64
146	},
147	.pm_evsel   = MSR_TSC,
148	.pm_perfctr = 0	/* unused */
149    },
150
151    {
152	.pm_descr =
153	{
154		.pd_name  = AMD_PMC_CLASS_NAME "0",
155		.pd_class = AMD_PMC_CLASS,
156		.pd_caps  = AMD_PMC_CAPS,
157		.pd_width = 48
158	},
159	.pm_evsel   = AMD_PMC_EVSEL_0,
160	.pm_perfctr = AMD_PMC_PERFCTR_0
161    },
162    {
163	.pm_descr =
164	{
165		.pd_name  = AMD_PMC_CLASS_NAME "1",
166		.pd_class = AMD_PMC_CLASS,
167		.pd_caps  = AMD_PMC_CAPS,
168		.pd_width = 48
169	},
170	.pm_evsel   = AMD_PMC_EVSEL_1,
171	.pm_perfctr = AMD_PMC_PERFCTR_1
172    },
173    {
174	.pm_descr =
175	{
176		.pd_name  = AMD_PMC_CLASS_NAME "2",
177		.pd_class = AMD_PMC_CLASS,
178		.pd_caps  = AMD_PMC_CAPS,
179		.pd_width = 48
180	},
181	.pm_evsel   = AMD_PMC_EVSEL_2,
182	.pm_perfctr = AMD_PMC_PERFCTR_2
183    },
184    {
185	.pm_descr =
186	{
187		.pd_name  = AMD_PMC_CLASS_NAME "3",
188		.pd_class = AMD_PMC_CLASS,
189		.pd_caps  = AMD_PMC_CAPS,
190		.pd_width = 48
191	},
192	.pm_evsel   = AMD_PMC_EVSEL_3,
193	.pm_perfctr = AMD_PMC_PERFCTR_3
194    }
195};
196
197struct amd_event_code_map {
198	enum pmc_event	pe_ev;	 /* enum value */
199	uint8_t		pe_code; /* encoded event mask */
200	uint8_t		pe_mask; /* bits allowed in unit mask */
201};
202
203const struct amd_event_code_map amd_event_codes[] = {
204#if	__i386__
205	{ PMC_EV_K7_DC_ACCESSES, 		0x40, 0 },
206	{ PMC_EV_K7_DC_MISSES,			0x41, 0 },
207	{ PMC_EV_K7_DC_REFILLS_FROM_L2,		0x42, K7_PMC_UNITMASK_MOESI },
208	{ PMC_EV_K7_DC_REFILLS_FROM_SYSTEM,	0x43, K7_PMC_UNITMASK_MOESI },
209	{ PMC_EV_K7_DC_WRITEBACKS,		0x44, K7_PMC_UNITMASK_MOESI },
210	{ PMC_EV_K7_L1_DTLB_MISS_AND_L2_DTLB_HITS, 0x45, 0 },
211	{ PMC_EV_K7_L1_AND_L2_DTLB_MISSES,	0x46, 0 },
212	{ PMC_EV_K7_MISALIGNED_REFERENCES,	0x47, 0 },
213
214	{ PMC_EV_K7_IC_FETCHES,			0x80, 0 },
215	{ PMC_EV_K7_IC_MISSES,			0x81, 0 },
216
217	{ PMC_EV_K7_L1_ITLB_MISSES,		0x84, 0 },
218	{ PMC_EV_K7_L1_L2_ITLB_MISSES,		0x85, 0 },
219
220	{ PMC_EV_K7_RETIRED_INSTRUCTIONS,	0xC0, 0 },
221	{ PMC_EV_K7_RETIRED_OPS,		0xC1, 0 },
222	{ PMC_EV_K7_RETIRED_BRANCHES,		0xC2, 0 },
223	{ PMC_EV_K7_RETIRED_BRANCHES_MISPREDICTED, 0xC3, 0 },
224	{ PMC_EV_K7_RETIRED_TAKEN_BRANCHES, 	0xC4, 0 },
225	{ PMC_EV_K7_RETIRED_TAKEN_BRANCHES_MISPREDICTED, 0xC5, 0 },
226	{ PMC_EV_K7_RETIRED_FAR_CONTROL_TRANSFERS, 0xC6, 0 },
227	{ PMC_EV_K7_RETIRED_RESYNC_BRANCHES,	0xC7, 0 },
228	{ PMC_EV_K7_INTERRUPTS_MASKED_CYCLES,	0xCD, 0 },
229	{ PMC_EV_K7_INTERRUPTS_MASKED_WHILE_PENDING_CYCLES, 0xCE, 0 },
230	{ PMC_EV_K7_HARDWARE_INTERRUPTS,	0xCF, 0 }
231#endif
232
233#if	__amd64__
234	{ PMC_EV_K8_FP_DISPATCHED_FPU_OPS,		0x00, 0x3F },
235	{ PMC_EV_K8_FP_CYCLES_WITH_NO_FPU_OPS_RETIRED,	0x01, 0x00 },
236	{ PMC_EV_K8_FP_DISPATCHED_FPU_FAST_FLAG_OPS,	0x02, 0x00 },
237
238	{ PMC_EV_K8_LS_SEGMENT_REGISTER_LOAD, 		0x20, 0x7F },
239	{ PMC_EV_K8_LS_MICROARCHITECTURAL_RESYNC_BY_SELF_MODIFYING_CODE,
240	  						0x21, 0x00 },
241	{ PMC_EV_K8_LS_MICROARCHITECTURAL_RESYNC_BY_SNOOP, 0x22, 0x00 },
242	{ PMC_EV_K8_LS_BUFFER2_FULL,			0x23, 0x00 },
243	{ PMC_EV_K8_LS_LOCKED_OPERATION,		0x24, 0x07 },
244	{ PMC_EV_K8_LS_MICROARCHITECTURAL_LATE_CANCEL,	0x25, 0x00 },
245	{ PMC_EV_K8_LS_RETIRED_CFLUSH_INSTRUCTIONS,	0x26, 0x00 },
246	{ PMC_EV_K8_LS_RETIRED_CPUID_INSTRUCTIONS,	0x27, 0x00 },
247
248	{ PMC_EV_K8_DC_ACCESS,				0x40, 0x00 },
249	{ PMC_EV_K8_DC_MISS,				0x41, 0x00 },
250	{ PMC_EV_K8_DC_REFILL_FROM_L2,			0x42, 0x1F },
251	{ PMC_EV_K8_DC_REFILL_FROM_SYSTEM,		0x43, 0x1F },
252	{ PMC_EV_K8_DC_COPYBACK,			0x44, 0x1F },
253	{ PMC_EV_K8_DC_L1_DTLB_MISS_AND_L2_DTLB_HIT,	0x45, 0x00 },
254	{ PMC_EV_K8_DC_L1_DTLB_MISS_AND_L2_DTLB_MISS,	0x46, 0x00 },
255	{ PMC_EV_K8_DC_MISALIGNED_DATA_REFERENCE,	0x47, 0x00 },
256	{ PMC_EV_K8_DC_MICROARCHITECTURAL_LATE_CANCEL,	0x48, 0x00 },
257	{ PMC_EV_K8_DC_MICROARCHITECTURAL_EARLY_CANCEL, 0x49, 0x00 },
258	{ PMC_EV_K8_DC_ONE_BIT_ECC_ERROR,		0x4A, 0x03 },
259	{ PMC_EV_K8_DC_DISPATCHED_PREFETCH_INSTRUCTIONS, 0x4B, 0x07 },
260	{ PMC_EV_K8_DC_DCACHE_ACCESSES_BY_LOCKS,	0x4C, 0x03 },
261
262	{ PMC_EV_K8_BU_CPU_CLK_UNHALTED,		0x76, 0x00 },
263	{ PMC_EV_K8_BU_INTERNAL_L2_REQUEST,		0x7D, 0x1F },
264	{ PMC_EV_K8_BU_FILL_REQUEST_L2_MISS,		0x7E, 0x07 },
265	{ PMC_EV_K8_BU_FILL_INTO_L2,			0x7F, 0x03 },
266
267	{ PMC_EV_K8_IC_FETCH,				0x80, 0x00 },
268	{ PMC_EV_K8_IC_MISS,				0x81, 0x00 },
269	{ PMC_EV_K8_IC_REFILL_FROM_L2,			0x82, 0x00 },
270	{ PMC_EV_K8_IC_REFILL_FROM_SYSTEM,		0x83, 0x00 },
271	{ PMC_EV_K8_IC_L1_ITLB_MISS_AND_L2_ITLB_HIT,	0x84, 0x00 },
272	{ PMC_EV_K8_IC_L1_ITLB_MISS_AND_L2_ITLB_MISS,	0x85, 0x00 },
273	{ PMC_EV_K8_IC_MICROARCHITECTURAL_RESYNC_BY_SNOOP, 0x86, 0x00 },
274	{ PMC_EV_K8_IC_INSTRUCTION_FETCH_STALL,		0x87, 0x00 },
275	{ PMC_EV_K8_IC_RETURN_STACK_HIT,		0x88, 0x00 },
276	{ PMC_EV_K8_IC_RETURN_STACK_OVERFLOW,		0x89, 0x00 },
277
278	{ PMC_EV_K8_FR_RETIRED_X86_INSTRUCTIONS,	0xC0, 0x00 },
279	{ PMC_EV_K8_FR_RETIRED_UOPS,			0xC1, 0x00 },
280	{ PMC_EV_K8_FR_RETIRED_BRANCHES,		0xC2, 0x00 },
281	{ PMC_EV_K8_FR_RETIRED_BRANCHES_MISPREDICTED,	0xC3, 0x00 },
282	{ PMC_EV_K8_FR_RETIRED_TAKEN_BRANCHES,		0xC4, 0x00 },
283	{ PMC_EV_K8_FR_RETIRED_TAKEN_BRANCHES_MISPREDICTED, 0xC5, 0x00 },
284	{ PMC_EV_K8_FR_RETIRED_FAR_CONTROL_TRANSFERS,	0xC6, 0x00 },
285	{ PMC_EV_K8_FR_RETIRED_RESYNCS,			0xC7, 0x00 },
286	{ PMC_EV_K8_FR_RETIRED_NEAR_RETURNS,		0xC8, 0x00 },
287	{ PMC_EV_K8_FR_RETIRED_NEAR_RETURNS_MISPREDICTED, 0xC9, 0x00 },
288	{ PMC_EV_K8_FR_RETIRED_TAKEN_BRANCHES_MISPREDICTED_BY_ADDR_MISCOMPARE,
289							0xCA, 0x00 },
290	{ PMC_EV_K8_FR_RETIRED_FPU_INSTRUCTIONS,	0xCB, 0x0F },
291	{ PMC_EV_K8_FR_RETIRED_FASTPATH_DOUBLE_OP_INSTRUCTIONS,
292							0xCC, 0x07 },
293	{ PMC_EV_K8_FR_INTERRUPTS_MASKED_CYCLES,	0xCD, 0x00 },
294	{ PMC_EV_K8_FR_INTERRUPTS_MASKED_WHILE_PENDING_CYCLES, 0xCE, 0x00 },
295	{ PMC_EV_K8_FR_TAKEN_HARDWARE_INTERRUPTS,	0xCF, 0x00 },
296
297	{ PMC_EV_K8_FR_DECODER_EMPTY,			0xD0, 0x00 },
298	{ PMC_EV_K8_FR_DISPATCH_STALLS,			0xD1, 0x00 },
299	{ PMC_EV_K8_FR_DISPATCH_STALL_FROM_BRANCH_ABORT_TO_RETIRE,
300							0xD2, 0x00 },
301	{ PMC_EV_K8_FR_DISPATCH_STALL_FOR_SERIALIZATION, 0xD3, 0x00 },
302	{ PMC_EV_K8_FR_DISPATCH_STALL_FOR_SEGMENT_LOAD,	0xD4, 0x00 },
303	{ PMC_EV_K8_FR_DISPATCH_STALL_WHEN_REORDER_BUFFER_IS_FULL,
304							0xD5, 0x00 },
305	{ PMC_EV_K8_FR_DISPATCH_STALL_WHEN_RESERVATION_STATIONS_ARE_FULL,
306							0xD6, 0x00 },
307	{ PMC_EV_K8_FR_DISPATCH_STALL_WHEN_FPU_IS_FULL,	0xD7, 0x00 },
308	{ PMC_EV_K8_FR_DISPATCH_STALL_WHEN_LS_IS_FULL,	0xD8, 0x00 },
309	{ PMC_EV_K8_FR_DISPATCH_STALL_WHEN_WAITING_FOR_ALL_TO_BE_QUIET,
310							0xD9, 0x00 },
311	{ PMC_EV_K8_FR_DISPATCH_STALL_WHEN_FAR_XFER_OR_RESYNC_BRANCH_PENDING,
312							0xDA, 0x00 },
313	{ PMC_EV_K8_FR_FPU_EXCEPTIONS,			0xDB, 0x0F },
314	{ PMC_EV_K8_FR_NUMBER_OF_BREAKPOINTS_FOR_DR0,	0xDC, 0x00 },
315	{ PMC_EV_K8_FR_NUMBER_OF_BREAKPOINTS_FOR_DR1,	0xDD, 0x00 },
316	{ PMC_EV_K8_FR_NUMBER_OF_BREAKPOINTS_FOR_DR2,	0xDE, 0x00 },
317	{ PMC_EV_K8_FR_NUMBER_OF_BREAKPOINTS_FOR_DR3,	0xDF, 0x00 },
318
319	{ PMC_EV_K8_NB_MEMORY_CONTROLLER_PAGE_ACCESS_EVENT, 0xE0, 0x7 },
320	{ PMC_EV_K8_NB_MEMORY_CONTROLLER_PAGE_TABLE_OVERFLOW, 0xE1, 0x00 },
321	{ PMC_EV_K8_NB_MEMORY_CONTROLLER_DRAM_COMMAND_SLOTS_MISSED,
322							0xE2, 0x00 },
323	{ PMC_EV_K8_NB_MEMORY_CONTROLLER_TURNAROUND,	0xE3, 0x07 },
324	{ PMC_EV_K8_NB_MEMORY_CONTROLLER_BYPASS_SATURATION, 0xE4, 0x0F },
325	{ PMC_EV_K8_NB_SIZED_COMMANDS,			0xEB, 0x7F },
326	{ PMC_EV_K8_NB_PROBE_RESULT,			0xEC, 0x0F },
327	{ PMC_EV_K8_NB_HT_BUS0_BANDWIDTH,		0xF6, 0x0F },
328	{ PMC_EV_K8_NB_HT_BUS1_BANDWIDTH,		0xF7, 0x0F },
329	{ PMC_EV_K8_NB_HT_BUS2_BANDWIDTH,		0xF8, 0x0F }
330#endif
331
332};
333
334const int amd_event_codes_size =
335	sizeof(amd_event_codes) / sizeof(amd_event_codes[0]);
336
337/*
338 * read a pmc register
339 */
340
341static int
342amd_read_pmc(int cpu, int ri, pmc_value_t *v)
343{
344	enum pmc_mode mode;
345	const struct amd_descr *pd;
346	struct pmc *pm;
347	const struct pmc_hw *phw;
348	pmc_value_t tmp;
349
350	KASSERT(cpu >= 0 && cpu < mp_ncpus,
351	    ("[amd,%d] illegal CPU value %d", __LINE__, cpu));
352	KASSERT(ri >= 0 && ri < AMD_NPMCS,
353	    ("[amd,%d] illegal row-index %d", __LINE__, ri));
354
355	phw = pmc_pcpu[cpu]->pc_hwpmcs[ri];
356	pd  = &amd_pmcdesc[ri];
357	pm  = phw->phw_pmc;
358
359	KASSERT(pm != NULL,
360	    ("[amd,%d] No owner for HWPMC [cpu%d,pmc%d]", __LINE__,
361		cpu, ri));
362
363	mode = pm->pm_mode;
364
365	PMCDBG(MDP,REA,1,"amd-read id=%d class=%d", ri, pd->pm_descr.pd_class);
366
367	/* Reading the TSC is a special case */
368	if (pd->pm_descr.pd_class == PMC_CLASS_TSC) {
369		KASSERT(PMC_IS_COUNTING_MODE(mode),
370		    ("[amd,%d] TSC counter in non-counting mode", __LINE__));
371		*v = rdtsc();
372		PMCDBG(MDP,REA,2,"amd-read id=%d -> %jd", ri, *v);
373		return 0;
374	}
375
376	KASSERT(pd->pm_descr.pd_class == AMD_PMC_CLASS,
377	    ("[amd,%d] unknown PMC class (%d)", __LINE__,
378		pd->pm_descr.pd_class));
379
380	tmp = rdmsr(pd->pm_perfctr); /* RDMSR serializes */
381	if (PMC_IS_SAMPLING_MODE(mode))
382		*v = -tmp;
383	else
384		*v = tmp;
385
386	PMCDBG(MDP,REA,2,"amd-read id=%d -> %jd", ri, *v);
387
388	return 0;
389}
390
391/*
392 * Write a PMC MSR.
393 */
394
395static int
396amd_write_pmc(int cpu, int ri, pmc_value_t v)
397{
398	const struct amd_descr *pd;
399	struct pmc *pm;
400	const struct pmc_hw *phw;
401	enum pmc_mode mode;
402
403	KASSERT(cpu >= 0 && cpu < mp_ncpus,
404	    ("[amd,%d] illegal CPU value %d", __LINE__, cpu));
405	KASSERT(ri >= 0 && ri < AMD_NPMCS,
406	    ("[amd,%d] illegal row-index %d", __LINE__, ri));
407
408	phw = pmc_pcpu[cpu]->pc_hwpmcs[ri];
409	pd  = &amd_pmcdesc[ri];
410	pm  = phw->phw_pmc;
411
412	KASSERT(pm != NULL,
413	    ("[amd,%d] PMC not owned (cpu%d,pmc%d)", __LINE__,
414		cpu, ri));
415
416	mode = pm->pm_mode;
417
418	if (pd->pm_descr.pd_class == PMC_CLASS_TSC)
419		return 0;
420
421	KASSERT(pd->pm_descr.pd_class == AMD_PMC_CLASS,
422	    ("[amd,%d] unknown PMC class (%d)", __LINE__,
423		pd->pm_descr.pd_class));
424
425	/* use 2's complement of the count for sampling mode PMCs */
426	if (PMC_IS_SAMPLING_MODE(mode))
427		v = -v;
428
429	PMCDBG(MDP,WRI,1,"amd-write cpu=%d ri=%d v=%jx", cpu, ri, v);
430
431	/* write the PMC value */
432	wrmsr(pd->pm_perfctr, v);
433	return 0;
434}
435
436/*
437 * configure hardware pmc according to the configuration recorded in
438 * pmc 'pm'.
439 */
440
441static int
442amd_config_pmc(int cpu, int ri, struct pmc *pm)
443{
444	struct pmc_hw *phw;
445
446	KASSERT(cpu >= 0 && cpu < mp_ncpus,
447	    ("[amd,%d] illegal CPU value %d", __LINE__, cpu));
448	KASSERT(ri >= 0 && ri < AMD_NPMCS,
449	    ("[amd,%d] illegal row-index %d", __LINE__, ri));
450
451	phw = pmc_pcpu[cpu]->pc_hwpmcs[ri];
452
453	KASSERT(pm == NULL || phw->phw_pmc == NULL,
454	    ("[amd,%d] hwpmc not unconfigured before re-config", __LINE__));
455
456	phw->phw_pmc = pm;
457	return 0;
458}
459
460/*
461 * Machine dependent actions taken during the context switch in of a
462 * thread.
463 */
464
465static int
466amd_switch_in(struct pmc_cpu *pc)
467{
468	(void) pc;
469
470	/* enable the RDPMC instruction */
471	load_cr4(rcr4() | CR4_PCE);
472	return 0;
473}
474
475/*
476 * Machine dependent actions taken during the context switch out of a
477 * thread.
478 */
479
480static int
481amd_switch_out(struct pmc_cpu *pc)
482{
483	(void) pc;
484
485	/* disallow RDPMC instruction */
486	load_cr4(rcr4() & ~CR4_PCE);
487	return 0;
488}
489
490/*
491 * Check if a given allocation is feasible.
492 */
493
494static int
495amd_allocate_pmc(int cpu, int ri, struct pmc *pm,
496    const struct pmc_op_pmcallocate *a)
497{
498	int i;
499	uint32_t allowed_unitmask, caps, config, unitmask;
500	enum pmc_event pe;
501	const struct pmc_descr *pd;
502
503	(void) cpu;
504
505	KASSERT(cpu >= 0 && cpu < mp_ncpus,
506	    ("[amd,%d] illegal CPU value %d", __LINE__, cpu));
507	KASSERT(ri >= 0 && ri < AMD_NPMCS,
508	    ("[amd,%d] illegal row index %d", __LINE__, ri));
509
510	pd = &amd_pmcdesc[ri].pm_descr;
511
512	/* check class match */
513	if (pd->pd_class != pm->pm_class)
514		return EINVAL;
515
516	caps = pm->pm_caps;
517
518	PMCDBG(MDP,ALL,1,"amd-allocate ri=%d caps=0x%x", ri, caps);
519
520	if ((pd->pd_caps & caps) != caps)
521		return EPERM;
522	if (pd->pd_class == PMC_CLASS_TSC) {
523		/* TSC's are always allocated in system-wide counting mode */
524		if (a->pm_ev != PMC_EV_TSC_TSC ||
525		    a->pm_mode != PMC_MODE_SC)
526			return EINVAL;
527		return 0;
528	}
529
530	KASSERT(pd->pd_class == AMD_PMC_CLASS,
531	    ("[amd,%d] Unknown PMC class (%d)", __LINE__, pd->pd_class));
532
533	pe = a->pm_ev;
534
535	/* map ev to the correct event mask code */
536	config = allowed_unitmask = 0;
537	for (i = 0; i < amd_event_codes_size; i++)
538		if (amd_event_codes[i].pe_ev == pe) {
539			config =
540			    AMD_PMC_TO_EVENTMASK(amd_event_codes[i].pe_code);
541			allowed_unitmask =
542			    AMD_PMC_TO_UNITMASK(amd_event_codes[i].pe_mask);
543			break;
544		}
545	if (i == amd_event_codes_size)
546		return EINVAL;
547
548	unitmask = a->pm_amd_config & AMD_PMC_UNITMASK;
549	if (unitmask & ~allowed_unitmask) /* disallow reserved bits */
550		return EINVAL;
551
552	if (unitmask && (caps & PMC_CAP_QUALIFIER))
553		config |= unitmask;
554
555	if (caps & PMC_CAP_THRESHOLD)
556		config |= a->pm_amd_config & AMD_PMC_COUNTERMASK;
557
558	/* set at least one of the 'usr' or 'os' caps */
559	if (caps & PMC_CAP_USER)
560		config |= AMD_PMC_USR;
561	if (caps & PMC_CAP_SYSTEM)
562		config |= AMD_PMC_OS;
563	if ((caps & (PMC_CAP_USER|PMC_CAP_SYSTEM)) == 0)
564		config |= (AMD_PMC_USR|AMD_PMC_OS);
565
566	if (caps & PMC_CAP_EDGE)
567		config |= AMD_PMC_EDGE;
568	if (caps & PMC_CAP_INVERT)
569		config |= AMD_PMC_INVERT;
570	if (caps & PMC_CAP_INTERRUPT)
571		config |= AMD_PMC_INT;
572
573	pm->pm_md.pm_amd.pm_amd_evsel = config; /* save config value */
574
575	PMCDBG(MDP,ALL,2,"amd-allocate ri=%d -> config=0x%x", ri, config);
576
577	return 0;
578}
579
580/*
581 * Release machine dependent state associated with a PMC.  This is a
582 * no-op on this architecture.
583 *
584 */
585
586/* ARGSUSED0 */
587static int
588amd_release_pmc(int cpu, int ri, struct pmc *pmc)
589{
590#if	DEBUG
591	const struct amd_descr *pd;
592#endif
593	struct pmc_hw *phw;
594
595	(void) pmc;
596
597	KASSERT(cpu >= 0 && cpu < mp_ncpus,
598	    ("[amd,%d] illegal CPU value %d", __LINE__, cpu));
599	KASSERT(ri >= 0 && ri < AMD_NPMCS,
600	    ("[amd,%d] illegal row-index %d", __LINE__, ri));
601
602	phw = pmc_pcpu[cpu]->pc_hwpmcs[ri];
603
604	KASSERT(phw->phw_pmc == NULL,
605	    ("[amd,%d] PHW pmc %p non-NULL", __LINE__, phw->phw_pmc));
606
607#if 	DEBUG
608	pd = &amd_pmcdesc[ri];
609	if (pd->pm_descr.pd_class == AMD_PMC_CLASS)
610		KASSERT(AMD_PMC_IS_STOPPED(pd->pm_evsel),
611		    ("[amd,%d] PMC %d released while active", __LINE__, ri));
612#endif
613
614	return 0;
615}
616
617/*
618 * start a PMC.
619 */
620
621static int
622amd_start_pmc(int cpu, int ri)
623{
624	uint32_t config;
625	struct pmc *pm;
626	struct pmc_hw *phw;
627	const struct amd_descr *pd;
628
629	KASSERT(cpu >= 0 && cpu < mp_ncpus,
630	    ("[amd,%d] illegal CPU value %d", __LINE__, cpu));
631	KASSERT(ri >= 0 && ri < AMD_NPMCS,
632	    ("[amd,%d] illegal row-index %d", __LINE__, ri));
633
634	phw = pmc_pcpu[cpu]->pc_hwpmcs[ri];
635	pm  = phw->phw_pmc;
636	pd = &amd_pmcdesc[ri];
637
638	KASSERT(pm != NULL,
639	    ("[amd,%d] starting cpu%d,pmc%d with null pmc record", __LINE__,
640		cpu, ri));
641
642	PMCDBG(MDP,STA,1,"amd-start cpu=%d ri=%d", cpu, ri);
643
644	if (pd->pm_descr.pd_class == PMC_CLASS_TSC)
645		return 0;	/* TSCs are always running */
646
647	KASSERT(pd->pm_descr.pd_class == AMD_PMC_CLASS,
648	    ("[amd,%d] unknown PMC class (%d)", __LINE__,
649		pd->pm_descr.pd_class));
650
651	KASSERT(AMD_PMC_IS_STOPPED(pd->pm_evsel),
652	    ("[amd,%d] pmc%d,cpu%d: Starting active PMC \"%s\"", __LINE__,
653	    ri, cpu, pd->pm_descr.pd_name));
654
655	/* turn on the PMC ENABLE bit */
656	config = pm->pm_md.pm_amd.pm_amd_evsel | AMD_PMC_ENABLE;
657
658	PMCDBG(MDP,STA,2,"amd-start config=0x%x", config);
659
660	wrmsr(pd->pm_evsel, config);
661	return 0;
662}
663
664/*
665 * Stop a PMC.
666 */
667
668static int
669amd_stop_pmc(int cpu, int ri)
670{
671	struct pmc *pm;
672	struct pmc_hw *phw;
673	const struct amd_descr *pd;
674	uint64_t config;
675
676	KASSERT(cpu >= 0 && cpu < mp_ncpus,
677	    ("[amd,%d] illegal CPU value %d", __LINE__, cpu));
678	KASSERT(ri >= 0 && ri < AMD_NPMCS,
679	    ("[amd,%d] illegal row-index %d", __LINE__, ri));
680
681	phw = pmc_pcpu[cpu]->pc_hwpmcs[ri];
682	pm  = phw->phw_pmc;
683	pd  = &amd_pmcdesc[ri];
684
685	KASSERT(pm != NULL,
686	    ("[amd,%d] cpu%d,pmc%d no PMC to stop", __LINE__,
687		cpu, ri));
688
689	/* can't stop a TSC */
690	if (pd->pm_descr.pd_class == PMC_CLASS_TSC)
691		return 0;
692
693	KASSERT(pd->pm_descr.pd_class == AMD_PMC_CLASS,
694	    ("[amd,%d] unknown PMC class (%d)", __LINE__,
695		pd->pm_descr.pd_class));
696
697	KASSERT(!AMD_PMC_IS_STOPPED(pd->pm_evsel),
698	    ("[amd,%d] PMC%d, CPU%d \"%s\" already stopped",
699		__LINE__, ri, cpu, pd->pm_descr.pd_name));
700
701	PMCDBG(MDP,STO,1,"amd-stop ri=%d", ri);
702
703	/* turn off the PMC ENABLE bit */
704	config = pm->pm_md.pm_amd.pm_amd_evsel & ~AMD_PMC_ENABLE;
705	wrmsr(pd->pm_evsel, config);
706	return 0;
707}
708
709/*
710 * Interrupt handler.  This function needs to return '1' if the
711 * interrupt was this CPU's PMCs or '0' otherwise.  It is not allowed
712 * to sleep or do anything a 'fast' interrupt handler is not allowed
713 * to do.
714 */
715
716static int
717amd_intr(int cpu, uintptr_t eip)
718{
719	int i, retval;
720	enum pmc_mode mode;
721	uint32_t perfctr;
722	struct pmc *pm;
723	struct pmc_cpu *pc;
724	struct pmc_hw *phw;
725
726	KASSERT(cpu >= 0 && cpu < mp_ncpus,
727	    ("[amd,%d] out of range CPU %d", __LINE__, cpu));
728
729	retval = 0;
730
731	pc = pmc_pcpu[cpu];
732
733	/*
734	 * look for all PMCs that have interrupted:
735	 * - skip over the TSC [PMC#0]
736	 * - look for a PMC with a valid 'struct pmc' association
737	 * - look for a PMC in (a) sampling mode and (b) which has
738	 *   overflowed.  If found, we update the process's
739	 *   histogram or send it a profiling signal by calling
740	 *   the appropriate helper function.
741	 */
742
743	for (i = 1; i < AMD_NPMCS; i++) {
744
745		phw = pc->pc_hwpmcs[i];
746		perfctr = amd_pmcdesc[i].pm_perfctr;
747		KASSERT(phw != NULL, ("[amd,%d] null PHW pointer", __LINE__));
748
749		if ((pm = phw->phw_pmc) == NULL ||
750		    pm->pm_state != PMC_STATE_RUNNING) {
751			atomic_add_int(&pmc_stats.pm_intr_ignored, 1);
752			continue;
753		}
754
755		mode = pm->pm_mode;
756		if (PMC_IS_SAMPLING_MODE(mode) &&
757		    AMD_PMC_HAS_OVERFLOWED(perfctr)) {
758			atomic_add_int(&pmc_stats.pm_intr_processed, 1);
759			if (PMC_IS_SYSTEM_MODE(mode))
760				pmc_update_histogram(phw, eip);
761			else if (PMC_IS_VIRTUAL_MODE(mode))
762				pmc_send_signal(pm);
763			retval = 1;
764		}
765	}
766	return retval;
767}
768
769/*
770 * describe a PMC
771 */
772static int
773amd_describe(int cpu, int ri, struct pmc_info *pi, struct pmc **ppmc)
774{
775	int error;
776	size_t copied;
777	const struct amd_descr *pd;
778	struct pmc_hw *phw;
779
780	KASSERT(cpu >= 0 && cpu < mp_ncpus,
781	    ("[amd,%d] illegal CPU %d", __LINE__, cpu));
782	KASSERT(ri >= 0 && ri < AMD_NPMCS,
783	    ("[amd,%d] row-index %d out of range", __LINE__, ri));
784
785	phw = pmc_pcpu[cpu]->pc_hwpmcs[ri];
786	pd  = &amd_pmcdesc[ri];
787
788	if ((error = copystr(pd->pm_descr.pd_name, pi->pm_name,
789		 PMC_NAME_MAX, &copied)) != 0)
790		return error;
791
792	pi->pm_class = pd->pm_descr.pd_class;
793	pi->pm_caps  = pd->pm_descr.pd_caps;
794	pi->pm_width = pd->pm_descr.pd_width;
795
796	if (phw->phw_state & PMC_PHW_FLAG_IS_ENABLED) {
797		pi->pm_enabled = TRUE;
798		*ppmc          = phw->phw_pmc;
799	} else {
800		pi->pm_enabled = FALSE;
801		*ppmc          = NULL;
802	}
803
804	return 0;
805}
806
807/*
808 * i386 specific entry points
809 */
810
811/*
812 * return the MSR address of the given PMC.
813 */
814
815static int
816amd_get_msr(int ri, uint32_t *msr)
817{
818	KASSERT(ri >= 0 && ri < AMD_NPMCS,
819	    ("[amd,%d] ri %d out of range", __LINE__, ri));
820
821	*msr = amd_pmcdesc[ri].pm_perfctr;
822	return 0;
823}
824
825/*
826 * processor dependent initialization.
827 */
828
829/*
830 * Per-processor data structure
831 *
832 * [common stuff]
833 * [5 struct pmc_hw pointers]
834 * [5 struct pmc_hw structures]
835 */
836
837struct amd_cpu {
838	struct pmc_cpu	pc_common;
839	struct pmc_hw	*pc_hwpmcs[AMD_NPMCS];
840	struct pmc_hw	pc_amdpmcs[AMD_NPMCS];
841};
842
843
844static int
845amd_init(int cpu)
846{
847	int n;
848	struct amd_cpu *pcs;
849	struct pmc_hw  *phw;
850
851	KASSERT(cpu >= 0 && cpu < mp_ncpus,
852	    ("[amd,%d] insane cpu number %d", __LINE__, cpu));
853
854	PMCDBG(MDP,INI,1,"amd-init cpu=%d", cpu);
855
856	MALLOC(pcs, struct amd_cpu *, sizeof(struct amd_cpu), M_PMC,
857	    M_WAITOK|M_ZERO);
858
859	if (pcs == NULL)
860		return ENOMEM;
861
862	phw = &pcs->pc_amdpmcs[0];
863
864	/*
865	 * Initialize the per-cpu mutex and set the content of the
866	 * hardware descriptors to a known state.
867	 */
868
869	for (n = 0; n < AMD_NPMCS; n++, phw++) {
870		phw->phw_state 	  = PMC_PHW_FLAG_IS_ENABLED |
871		    PMC_PHW_CPU_TO_STATE(cpu) | PMC_PHW_INDEX_TO_STATE(n);
872		phw->phw_pmc	  = NULL;
873		pcs->pc_hwpmcs[n] = phw;
874	}
875
876	/* Mark the TSC as shareable */
877	pcs->pc_hwpmcs[0]->phw_state |= PMC_PHW_FLAG_IS_SHAREABLE;
878
879	pmc_pcpu[cpu] = (struct pmc_cpu *) pcs;
880
881	return 0;
882}
883
884
885/*
886 * processor dependent cleanup prior to the KLD
887 * being unloaded
888 */
889
890static int
891amd_cleanup(int cpu)
892{
893	int i;
894	uint32_t evsel;
895	struct pmc_cpu *pcs;
896
897	KASSERT(cpu >= 0 && cpu < mp_ncpus,
898	    ("[amd,%d] insane cpu number (%d)", __LINE__, cpu));
899
900	PMCDBG(MDP,INI,1,"amd-cleanup cpu=%d", cpu);
901
902	/*
903	 * First, turn off all PMCs on this CPU.
904	 */
905
906	for (i = 0; i < 4; i++) { /* XXX this loop is now not needed */
907		evsel = rdmsr(AMD_PMC_EVSEL_0 + i);
908		evsel &= ~AMD_PMC_ENABLE;
909		wrmsr(AMD_PMC_EVSEL_0 + i, evsel);
910	}
911
912	/*
913	 * Next, free up allocated space.
914	 */
915
916	pcs = pmc_pcpu[cpu];
917
918#if	DEBUG
919	/* check the TSC */
920	KASSERT(pcs->pc_hwpmcs[0]->phw_pmc == NULL,
921	    ("[amd,%d] CPU%d,PMC0 still in use", __LINE__, cpu));
922	for (i = 1; i < AMD_NPMCS; i++) {
923		KASSERT(pcs->pc_hwpmcs[i]->phw_pmc == NULL,
924		    ("[amd,%d] CPU%d/PMC%d in use", __LINE__, cpu, i));
925		KASSERT(AMD_PMC_IS_STOPPED(AMD_PMC_EVSEL_0 + (i-1)),
926		    ("[amd,%d] CPU%d/PMC%d not stopped", __LINE__, cpu, i));
927	}
928#endif
929	KASSERT(pcs != NULL,
930	    ("[amd,%d] null per-cpu state pointer (cpu%d)", __LINE__, cpu));
931
932	pmc_pcpu[cpu] = NULL;
933	FREE(pcs, M_PMC);
934	return 0;
935}
936
937/*
938 * Initialize ourselves.
939 */
940
941struct pmc_mdep *
942pmc_amd_initialize(void)
943{
944
945	struct pmc_mdep *pmc_mdep;
946
947	/* The presence of hardware performance counters on the AMD
948	   Athlon, Duron or later processors, is _not_ indicated by
949	   any of the processor feature flags set by the 'CPUID'
950	   instruction, so we only check the 'instruction family'
951	   field returned by CPUID for instruction family >= 6. This
952	   test needs to be be refined. */
953
954	if ((cpu_id & 0xF00) < 0x600)
955		return NULL;
956
957	MALLOC(pmc_mdep, struct pmc_mdep *, sizeof(struct pmc_mdep),
958	    M_PMC, M_WAITOK|M_ZERO);
959
960#if	__i386__
961	pmc_mdep->pmd_cputype	   = PMC_CPU_AMD_K7;
962#elif	__amd64__
963	pmc_mdep->pmd_cputype	   = PMC_CPU_AMD_K8;
964#else
965#error	Unknown AMD CPU type.
966#endif
967
968	pmc_mdep->pmd_npmc 	   = AMD_NPMCS;
969
970	/* this processor has two classes of usable PMCs */
971	pmc_mdep->pmd_nclass       = 2;
972	pmc_mdep->pmd_classes[0]   = PMC_CLASS_TSC;
973	pmc_mdep->pmd_classes[1]   = AMD_PMC_CLASS;
974	pmc_mdep->pmd_nclasspmcs[0] = 1;
975	pmc_mdep->pmd_nclasspmcs[1] = (AMD_NPMCS-1);
976
977	pmc_mdep->pmd_init    	   = amd_init;
978	pmc_mdep->pmd_cleanup 	   = amd_cleanup;
979	pmc_mdep->pmd_switch_in    = amd_switch_in;
980	pmc_mdep->pmd_switch_out   = amd_switch_out;
981	pmc_mdep->pmd_read_pmc 	   = amd_read_pmc;
982	pmc_mdep->pmd_write_pmc    = amd_write_pmc;
983	pmc_mdep->pmd_config_pmc   = amd_config_pmc;
984	pmc_mdep->pmd_allocate_pmc = amd_allocate_pmc;
985	pmc_mdep->pmd_release_pmc  = amd_release_pmc;
986	pmc_mdep->pmd_start_pmc    = amd_start_pmc;
987	pmc_mdep->pmd_stop_pmc     = amd_stop_pmc;
988	pmc_mdep->pmd_intr	   = amd_intr;
989	pmc_mdep->pmd_describe     = amd_describe;
990	pmc_mdep->pmd_get_msr  	   = amd_get_msr; /* i386 */
991
992	PMCDBG(MDP,INI,0,"%s","amd-initialize");
993
994	return pmc_mdep;
995}
996