xref: /freebsd/lib/libpmc/libpmc.c (revision 562fc14bc9c866c3e6efa82d775c953cf1f0f177)
1ebccf1e3SJoseph Koshy /*-
2484202faSJoseph Koshy  * Copyright (c) 2003-2008 Joseph Koshy
3ebccf1e3SJoseph Koshy  * All rights reserved.
4ebccf1e3SJoseph Koshy  *
5ebccf1e3SJoseph Koshy  * Redistribution and use in source and binary forms, with or without
6ebccf1e3SJoseph Koshy  * modification, are permitted provided that the following conditions
7ebccf1e3SJoseph Koshy  * are met:
8ebccf1e3SJoseph Koshy  * 1. Redistributions of source code must retain the above copyright
9ebccf1e3SJoseph Koshy  *    notice, this list of conditions and the following disclaimer.
10ebccf1e3SJoseph Koshy  * 2. Redistributions in binary form must reproduce the above copyright
11ebccf1e3SJoseph Koshy  *    notice, this list of conditions and the following disclaimer in the
12ebccf1e3SJoseph Koshy  *    documentation and/or other materials provided with the distribution.
13ebccf1e3SJoseph Koshy  *
14ebccf1e3SJoseph Koshy  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15ebccf1e3SJoseph Koshy  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16ebccf1e3SJoseph Koshy  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17ebccf1e3SJoseph Koshy  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18ebccf1e3SJoseph Koshy  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19ebccf1e3SJoseph Koshy  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20ebccf1e3SJoseph Koshy  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21ebccf1e3SJoseph Koshy  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22ebccf1e3SJoseph Koshy  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23ebccf1e3SJoseph Koshy  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24ebccf1e3SJoseph Koshy  * SUCH DAMAGE.
25ebccf1e3SJoseph Koshy  */
26ebccf1e3SJoseph Koshy 
27ebccf1e3SJoseph Koshy #include <sys/cdefs.h>
28ebccf1e3SJoseph Koshy __FBSDID("$FreeBSD$");
29ebccf1e3SJoseph Koshy 
30ebccf1e3SJoseph Koshy #include <sys/types.h>
31ebccf1e3SJoseph Koshy #include <sys/module.h>
32ebccf1e3SJoseph Koshy #include <sys/pmc.h>
33ebccf1e3SJoseph Koshy #include <sys/syscall.h>
34ebccf1e3SJoseph Koshy 
35ebccf1e3SJoseph Koshy #include <ctype.h>
36ebccf1e3SJoseph Koshy #include <errno.h>
37ebccf1e3SJoseph Koshy #include <fcntl.h>
38ebccf1e3SJoseph Koshy #include <pmc.h>
39ebccf1e3SJoseph Koshy #include <stdio.h>
40ebccf1e3SJoseph Koshy #include <stdlib.h>
41ebccf1e3SJoseph Koshy #include <string.h>
42ebccf1e3SJoseph Koshy #include <strings.h>
43ebccf1e3SJoseph Koshy #include <unistd.h>
44ebccf1e3SJoseph Koshy 
450cfab8ddSJoseph Koshy #include "libpmcinternal.h"
460cfab8ddSJoseph Koshy 
47ebccf1e3SJoseph Koshy /* Function prototypes */
4804e9feb0SMarcel Moolenaar #if defined(__i386__)
49ebccf1e3SJoseph Koshy static int k7_allocate_pmc(enum pmc_event _pe, char *_ctrspec,
50ebccf1e3SJoseph Koshy     struct pmc_op_pmcallocate *_pmc_config);
51f263522aSJoseph Koshy #endif
5286a65549SJoseph Koshy #if defined(__amd64__) || defined(__i386__)
530cfab8ddSJoseph Koshy static int iaf_allocate_pmc(enum pmc_event _pe, char *_ctrspec,
540cfab8ddSJoseph Koshy     struct pmc_op_pmcallocate *_pmc_config);
550cfab8ddSJoseph Koshy static int iap_allocate_pmc(enum pmc_event _pe, char *_ctrspec,
560cfab8ddSJoseph Koshy     struct pmc_op_pmcallocate *_pmc_config);
571fa7f10bSFabien Thomas static int ucf_allocate_pmc(enum pmc_event _pe, char *_ctrspec,
581fa7f10bSFabien Thomas     struct pmc_op_pmcallocate *_pmc_config);
591fa7f10bSFabien Thomas static int ucp_allocate_pmc(enum pmc_event _pe, char *_ctrspec,
601fa7f10bSFabien Thomas     struct pmc_op_pmcallocate *_pmc_config);
61f263522aSJoseph Koshy static int k8_allocate_pmc(enum pmc_event _pe, char *_ctrspec,
62ebccf1e3SJoseph Koshy     struct pmc_op_pmcallocate *_pmc_config);
6386a65549SJoseph Koshy static int p4_allocate_pmc(enum pmc_event _pe, char *_ctrspec,
6486a65549SJoseph Koshy     struct pmc_op_pmcallocate *_pmc_config);
65f263522aSJoseph Koshy #endif
66f263522aSJoseph Koshy #if defined(__i386__)
67ebccf1e3SJoseph Koshy static int p5_allocate_pmc(enum pmc_event _pe, char *_ctrspec,
68ebccf1e3SJoseph Koshy     struct pmc_op_pmcallocate *_pmc_config);
69f263522aSJoseph Koshy static int p6_allocate_pmc(enum pmc_event _pe, char *_ctrspec,
70ebccf1e3SJoseph Koshy     struct pmc_op_pmcallocate *_pmc_config);
71ebccf1e3SJoseph Koshy #endif
72789140c0SJoseph Koshy #if defined(__amd64__) || defined(__i386__)
73789140c0SJoseph Koshy static int tsc_allocate_pmc(enum pmc_event _pe, char *_ctrspec,
74789140c0SJoseph Koshy     struct pmc_op_pmcallocate *_pmc_config);
75789140c0SJoseph Koshy #endif
760ce207d2SRui Paulo #if defined(__XSCALE__)
770ce207d2SRui Paulo static int xscale_allocate_pmc(enum pmc_event _pe, char *_ctrspec,
780ce207d2SRui Paulo     struct pmc_op_pmcallocate *_pmc_config);
790ce207d2SRui Paulo #endif
80ebccf1e3SJoseph Koshy 
81660df75eSGeorge V. Neville-Neil #if defined(__mips__)
82660df75eSGeorge V. Neville-Neil static int mips24k_allocate_pmc(enum pmc_event _pe, char* ctrspec,
83660df75eSGeorge V. Neville-Neil 			     struct pmc_op_pmcallocate *_pmc_config);
84660df75eSGeorge V. Neville-Neil #endif /* __mips__ */
85660df75eSGeorge V. Neville-Neil 
86660df75eSGeorge V. Neville-Neil 
87ebccf1e3SJoseph Koshy #define PMC_CALL(cmd, params)				\
88ebccf1e3SJoseph Koshy 	syscall(pmc_syscall, PMC_OP_##cmd, (params))
89ebccf1e3SJoseph Koshy 
90ebccf1e3SJoseph Koshy /*
91ebccf1e3SJoseph Koshy  * Event aliases provide a way for the user to ask for generic events
92ebccf1e3SJoseph Koshy  * like "cache-misses", or "instructions-retired".  These aliases are
93ebccf1e3SJoseph Koshy  * mapped to the appropriate canonical event descriptions using a
94ebccf1e3SJoseph Koshy  * lookup table.
95ebccf1e3SJoseph Koshy  */
96ebccf1e3SJoseph Koshy struct pmc_event_alias {
97ebccf1e3SJoseph Koshy 	const char	*pm_alias;
98ebccf1e3SJoseph Koshy 	const char	*pm_spec;
99ebccf1e3SJoseph Koshy };
100ebccf1e3SJoseph Koshy 
101ebccf1e3SJoseph Koshy static const struct pmc_event_alias *pmc_mdep_event_aliases;
102ebccf1e3SJoseph Koshy 
103ebccf1e3SJoseph Koshy /*
104789140c0SJoseph Koshy  * The pmc_event_descr structure maps symbolic names known to the user
105ebccf1e3SJoseph Koshy  * to integer codes used by the PMC KLD.
106ebccf1e3SJoseph Koshy  */
107ebccf1e3SJoseph Koshy struct pmc_event_descr {
108ebccf1e3SJoseph Koshy 	const char	*pm_ev_name;
109ebccf1e3SJoseph Koshy 	enum pmc_event	pm_ev_code;
110ebccf1e3SJoseph Koshy };
111ebccf1e3SJoseph Koshy 
112789140c0SJoseph Koshy /*
113789140c0SJoseph Koshy  * The pmc_class_descr structure maps class name prefixes for
114789140c0SJoseph Koshy  * event names to event tables and other PMC class data.
115789140c0SJoseph Koshy  */
116789140c0SJoseph Koshy struct pmc_class_descr {
117789140c0SJoseph Koshy 	const char	*pm_evc_name;
118789140c0SJoseph Koshy 	size_t		pm_evc_name_size;
119789140c0SJoseph Koshy 	enum pmc_class	pm_evc_class;
120789140c0SJoseph Koshy 	const struct pmc_event_descr *pm_evc_event_table;
121789140c0SJoseph Koshy 	size_t		pm_evc_event_table_size;
122789140c0SJoseph Koshy 	int		(*pm_evc_allocate_pmc)(enum pmc_event _pe,
123789140c0SJoseph Koshy 			    char *_ctrspec, struct pmc_op_pmcallocate *_pa);
124ebccf1e3SJoseph Koshy };
125ebccf1e3SJoseph Koshy 
126789140c0SJoseph Koshy #define	PMC_TABLE_SIZE(N)	(sizeof(N)/sizeof(N[0]))
127789140c0SJoseph Koshy #define	PMC_EVENT_TABLE_SIZE(N)	PMC_TABLE_SIZE(N##_event_table)
128789140c0SJoseph Koshy 
129789140c0SJoseph Koshy #undef	__PMC_EV
130789140c0SJoseph Koshy #define	__PMC_EV(C,N) { #N, PMC_EV_ ## C ## _ ## N },
131789140c0SJoseph Koshy 
132789140c0SJoseph Koshy /*
1330cfab8ddSJoseph Koshy  * PMC_CLASSDEP_TABLE(NAME, CLASS)
134789140c0SJoseph Koshy  *
1350cfab8ddSJoseph Koshy  * Define a table mapping event names and aliases to HWPMC event IDs.
136789140c0SJoseph Koshy  */
1370cfab8ddSJoseph Koshy #define	PMC_CLASSDEP_TABLE(N, C)				\
138789140c0SJoseph Koshy 	static const struct pmc_event_descr N##_event_table[] =	\
139789140c0SJoseph Koshy 	{							\
140789140c0SJoseph Koshy 		__PMC_EV_##C()					\
1410cfab8ddSJoseph Koshy 	}
1420cfab8ddSJoseph Koshy 
1430cfab8ddSJoseph Koshy PMC_CLASSDEP_TABLE(iaf, IAF);
1440cfab8ddSJoseph Koshy PMC_CLASSDEP_TABLE(k7, K7);
1450cfab8ddSJoseph Koshy PMC_CLASSDEP_TABLE(k8, K8);
1460cfab8ddSJoseph Koshy PMC_CLASSDEP_TABLE(p4, P4);
1470cfab8ddSJoseph Koshy PMC_CLASSDEP_TABLE(p5, P5);
1480cfab8ddSJoseph Koshy PMC_CLASSDEP_TABLE(p6, P6);
1490ce207d2SRui Paulo PMC_CLASSDEP_TABLE(xscale, XSCALE);
150660df75eSGeorge V. Neville-Neil PMC_CLASSDEP_TABLE(mips24k, MIPS24K);
1511fa7f10bSFabien Thomas PMC_CLASSDEP_TABLE(ucf, UCF);
1520cfab8ddSJoseph Koshy 
1530cfab8ddSJoseph Koshy #undef	__PMC_EV_ALIAS
1540cfab8ddSJoseph Koshy #define	__PMC_EV_ALIAS(N,CODE) 	{ N, PMC_EV_##CODE },
1550cfab8ddSJoseph Koshy 
1560cfab8ddSJoseph Koshy static const struct pmc_event_descr atom_event_table[] =
1570cfab8ddSJoseph Koshy {
1580cfab8ddSJoseph Koshy 	__PMC_EV_ALIAS_ATOM()
1590cfab8ddSJoseph Koshy };
1600cfab8ddSJoseph Koshy 
1610cfab8ddSJoseph Koshy static const struct pmc_event_descr core_event_table[] =
1620cfab8ddSJoseph Koshy {
1630cfab8ddSJoseph Koshy 	__PMC_EV_ALIAS_CORE()
1640cfab8ddSJoseph Koshy };
1650cfab8ddSJoseph Koshy 
1660cfab8ddSJoseph Koshy 
1670cfab8ddSJoseph Koshy static const struct pmc_event_descr core2_event_table[] =
1680cfab8ddSJoseph Koshy {
1690cfab8ddSJoseph Koshy 	__PMC_EV_ALIAS_CORE2()
1700cfab8ddSJoseph Koshy };
1710cfab8ddSJoseph Koshy 
172597979c4SJeff Roberson static const struct pmc_event_descr corei7_event_table[] =
173597979c4SJeff Roberson {
174597979c4SJeff Roberson 	__PMC_EV_ALIAS_COREI7()
175597979c4SJeff Roberson };
176597979c4SJeff Roberson 
1771fa7f10bSFabien Thomas static const struct pmc_event_descr westmere_event_table[] =
1781fa7f10bSFabien Thomas {
1791fa7f10bSFabien Thomas 	__PMC_EV_ALIAS_WESTMERE()
1801fa7f10bSFabien Thomas };
1811fa7f10bSFabien Thomas 
1821fa7f10bSFabien Thomas static const struct pmc_event_descr corei7uc_event_table[] =
1831fa7f10bSFabien Thomas {
1841fa7f10bSFabien Thomas 	__PMC_EV_ALIAS_COREI7UC()
1851fa7f10bSFabien Thomas };
1861fa7f10bSFabien Thomas 
1871fa7f10bSFabien Thomas static const struct pmc_event_descr westmereuc_event_table[] =
1881fa7f10bSFabien Thomas {
1891fa7f10bSFabien Thomas 	__PMC_EV_ALIAS_WESTMEREUC()
1901fa7f10bSFabien Thomas };
1911fa7f10bSFabien Thomas 
1920cfab8ddSJoseph Koshy /*
1930cfab8ddSJoseph Koshy  * PMC_MDEP_TABLE(NAME, PRIMARYCLASS, ADDITIONAL_CLASSES...)
1940cfab8ddSJoseph Koshy  *
1950cfab8ddSJoseph Koshy  * Map a CPU to the PMC classes it supports.
1960cfab8ddSJoseph Koshy  */
1970cfab8ddSJoseph Koshy #define	PMC_MDEP_TABLE(N,C,...)				\
198789140c0SJoseph Koshy 	static const enum pmc_class N##_pmc_classes[] = {	\
199789140c0SJoseph Koshy 		PMC_CLASS_##C, __VA_ARGS__			\
200789140c0SJoseph Koshy 	}
201789140c0SJoseph Koshy 
2020cfab8ddSJoseph Koshy PMC_MDEP_TABLE(atom, IAP, PMC_CLASS_IAF, PMC_CLASS_TSC);
2030cfab8ddSJoseph Koshy PMC_MDEP_TABLE(core, IAP, PMC_CLASS_TSC);
2040cfab8ddSJoseph Koshy PMC_MDEP_TABLE(core2, IAP, PMC_CLASS_IAF, PMC_CLASS_TSC);
2051fa7f10bSFabien Thomas PMC_MDEP_TABLE(corei7, IAP, PMC_CLASS_IAF, PMC_CLASS_TSC, PMC_CLASS_UCF, PMC_CLASS_UCP);
2061fa7f10bSFabien Thomas PMC_MDEP_TABLE(westmere, IAP, PMC_CLASS_IAF, PMC_CLASS_TSC, PMC_CLASS_UCF, PMC_CLASS_UCP);
207789140c0SJoseph Koshy PMC_MDEP_TABLE(k7, K7, PMC_CLASS_TSC);
208789140c0SJoseph Koshy PMC_MDEP_TABLE(k8, K8, PMC_CLASS_TSC);
209789140c0SJoseph Koshy PMC_MDEP_TABLE(p4, P4, PMC_CLASS_TSC);
210789140c0SJoseph Koshy PMC_MDEP_TABLE(p5, P5, PMC_CLASS_TSC);
211789140c0SJoseph Koshy PMC_MDEP_TABLE(p6, P6, PMC_CLASS_TSC);
2120ce207d2SRui Paulo PMC_MDEP_TABLE(xscale, XSCALE, PMC_CLASS_XSCALE);
213660df75eSGeorge V. Neville-Neil PMC_MDEP_TABLE(mips24k, MIPS24K, PMC_CLASS_MIPS24K);
214789140c0SJoseph Koshy 
215789140c0SJoseph Koshy static const struct pmc_event_descr tsc_event_table[] =
216789140c0SJoseph Koshy {
217789140c0SJoseph Koshy 	__PMC_EV_TSC()
218789140c0SJoseph Koshy };
219789140c0SJoseph Koshy 
220789140c0SJoseph Koshy #undef	PMC_CLASS_TABLE_DESC
2210cfab8ddSJoseph Koshy #define	PMC_CLASS_TABLE_DESC(NAME, CLASS, EVENTS, ALLOCATOR)	\
2220cfab8ddSJoseph Koshy static const struct pmc_class_descr NAME##_class_table_descr =	\
2230cfab8ddSJoseph Koshy 	{							\
2240cfab8ddSJoseph Koshy 		.pm_evc_name  = #CLASS "-",			\
2250cfab8ddSJoseph Koshy 		.pm_evc_name_size = sizeof(#CLASS "-") - 1,	\
2260cfab8ddSJoseph Koshy 		.pm_evc_class = PMC_CLASS_##CLASS ,		\
2270cfab8ddSJoseph Koshy 		.pm_evc_event_table = EVENTS##_event_table ,	\
228789140c0SJoseph Koshy 		.pm_evc_event_table_size = 			\
2290cfab8ddSJoseph Koshy 			PMC_EVENT_TABLE_SIZE(EVENTS),		\
2300cfab8ddSJoseph Koshy 		.pm_evc_allocate_pmc = ALLOCATOR##_allocate_pmc	\
231789140c0SJoseph Koshy 	}
232789140c0SJoseph Koshy 
233789140c0SJoseph Koshy #if	defined(__i386__) || defined(__amd64__)
2340cfab8ddSJoseph Koshy PMC_CLASS_TABLE_DESC(iaf, IAF, iaf, iaf);
2350cfab8ddSJoseph Koshy PMC_CLASS_TABLE_DESC(atom, IAP, atom, iap);
2360cfab8ddSJoseph Koshy PMC_CLASS_TABLE_DESC(core, IAP, core, iap);
2370cfab8ddSJoseph Koshy PMC_CLASS_TABLE_DESC(core2, IAP, core2, iap);
238597979c4SJeff Roberson PMC_CLASS_TABLE_DESC(corei7, IAP, corei7, iap);
2391fa7f10bSFabien Thomas PMC_CLASS_TABLE_DESC(westmere, IAP, westmere, iap);
2401fa7f10bSFabien Thomas PMC_CLASS_TABLE_DESC(ucf, UCF, ucf, ucf);
2411fa7f10bSFabien Thomas PMC_CLASS_TABLE_DESC(corei7uc, UCP, corei7uc, ucp);
2421fa7f10bSFabien Thomas PMC_CLASS_TABLE_DESC(westmereuc, UCP, westmereuc, ucp);
243789140c0SJoseph Koshy #endif
244789140c0SJoseph Koshy #if	defined(__i386__)
2450cfab8ddSJoseph Koshy PMC_CLASS_TABLE_DESC(k7, K7, k7, k7);
246789140c0SJoseph Koshy #endif
247789140c0SJoseph Koshy #if	defined(__i386__) || defined(__amd64__)
2480cfab8ddSJoseph Koshy PMC_CLASS_TABLE_DESC(k8, K8, k8, k8);
2490cfab8ddSJoseph Koshy PMC_CLASS_TABLE_DESC(p4, P4, p4, p4);
250789140c0SJoseph Koshy #endif
2510cfab8ddSJoseph Koshy #if	defined(__i386__)
2520cfab8ddSJoseph Koshy PMC_CLASS_TABLE_DESC(p5, P5, p5, p5);
2530cfab8ddSJoseph Koshy PMC_CLASS_TABLE_DESC(p6, P6, p6, p6);
2540cfab8ddSJoseph Koshy #endif
2550cfab8ddSJoseph Koshy #if	defined(__i386__) || defined(__amd64__)
2560cfab8ddSJoseph Koshy PMC_CLASS_TABLE_DESC(tsc, TSC, tsc, tsc);
2570cfab8ddSJoseph Koshy #endif
2580ce207d2SRui Paulo #if	defined(__XSCALE__)
2590ce207d2SRui Paulo PMC_CLASS_TABLE_DESC(xscale, XSCALE, xscale, xscale);
2600ce207d2SRui Paulo #endif
261789140c0SJoseph Koshy 
262660df75eSGeorge V. Neville-Neil #if defined(__mips__)
263660df75eSGeorge V. Neville-Neil PMC_CLASS_TABLE_DESC(mips24k, MIPS24K, mips24k, mips24k);
264660df75eSGeorge V. Neville-Neil #endif /* __mips__ */
265660df75eSGeorge V. Neville-Neil 
266789140c0SJoseph Koshy #undef	PMC_CLASS_TABLE_DESC
267789140c0SJoseph Koshy 
2680cfab8ddSJoseph Koshy static const struct pmc_class_descr **pmc_class_table;
2690cfab8ddSJoseph Koshy #define	PMC_CLASS_TABLE_SIZE	cpu_info.pm_nclass
2700cfab8ddSJoseph Koshy 
271789140c0SJoseph Koshy static const enum pmc_class *pmc_mdep_class_list;
272789140c0SJoseph Koshy static size_t pmc_mdep_class_list_size;
273789140c0SJoseph Koshy 
274ebccf1e3SJoseph Koshy /*
275ebccf1e3SJoseph Koshy  * Mapping tables, mapping enumeration values to human readable
276ebccf1e3SJoseph Koshy  * strings.
277ebccf1e3SJoseph Koshy  */
278ebccf1e3SJoseph Koshy 
279ebccf1e3SJoseph Koshy static const char * pmc_capability_names[] = {
280ebccf1e3SJoseph Koshy #undef	__PMC_CAP
281ebccf1e3SJoseph Koshy #define	__PMC_CAP(N,V,D)	#N ,
282ebccf1e3SJoseph Koshy 	__PMC_CAPS()
283ebccf1e3SJoseph Koshy };
284ebccf1e3SJoseph Koshy 
285ebccf1e3SJoseph Koshy static const char * pmc_class_names[] = {
286ebccf1e3SJoseph Koshy #undef	__PMC_CLASS
287ebccf1e3SJoseph Koshy #define __PMC_CLASS(C)	#C ,
288ebccf1e3SJoseph Koshy 	__PMC_CLASSES()
289ebccf1e3SJoseph Koshy };
290ebccf1e3SJoseph Koshy 
291789140c0SJoseph Koshy struct pmc_cputype_map {
292*562fc14bSDimitry Andric 	enum pmc_cputype pm_cputype;
293789140c0SJoseph Koshy 	const char	*pm_name;
294789140c0SJoseph Koshy };
295789140c0SJoseph Koshy 
296789140c0SJoseph Koshy static const struct pmc_cputype_map pmc_cputype_names[] = {
297ebccf1e3SJoseph Koshy #undef	__PMC_CPU
298789140c0SJoseph Koshy #define	__PMC_CPU(S, V, D) { .pm_cputype = PMC_CPU_##S, .pm_name = #S } ,
299ebccf1e3SJoseph Koshy 	__PMC_CPUS()
300ebccf1e3SJoseph Koshy };
301ebccf1e3SJoseph Koshy 
302ebccf1e3SJoseph Koshy static const char * pmc_disposition_names[] = {
303ebccf1e3SJoseph Koshy #undef	__PMC_DISP
304ebccf1e3SJoseph Koshy #define	__PMC_DISP(D)	#D ,
305ebccf1e3SJoseph Koshy 	__PMC_DISPOSITIONS()
306ebccf1e3SJoseph Koshy };
307ebccf1e3SJoseph Koshy 
308ebccf1e3SJoseph Koshy static const char * pmc_mode_names[] = {
309ebccf1e3SJoseph Koshy #undef  __PMC_MODE
310ebccf1e3SJoseph Koshy #define __PMC_MODE(M,N)	#M ,
311ebccf1e3SJoseph Koshy 	__PMC_MODES()
312ebccf1e3SJoseph Koshy };
313ebccf1e3SJoseph Koshy 
314ebccf1e3SJoseph Koshy static const char * pmc_state_names[] = {
315ebccf1e3SJoseph Koshy #undef  __PMC_STATE
316ebccf1e3SJoseph Koshy #define __PMC_STATE(S) #S ,
317ebccf1e3SJoseph Koshy 	__PMC_STATES()
318ebccf1e3SJoseph Koshy };
319ebccf1e3SJoseph Koshy 
320ebccf1e3SJoseph Koshy static int pmc_syscall = -1;		/* filled in by pmc_init() */
321ebccf1e3SJoseph Koshy 
3221455fcd3SJoseph Koshy static struct pmc_cpuinfo cpu_info;	/* filled in by pmc_init() */
3231455fcd3SJoseph Koshy 
324ebccf1e3SJoseph Koshy /* Event masks for events */
325ebccf1e3SJoseph Koshy struct pmc_masks {
326ebccf1e3SJoseph Koshy 	const char	*pm_name;
327ebccf1e3SJoseph Koshy 	const uint32_t	pm_value;
328ebccf1e3SJoseph Koshy };
329ebccf1e3SJoseph Koshy #define	PMCMASK(N,V)	{ .pm_name = #N, .pm_value = (V) }
3301fa7f10bSFabien Thomas #define	NULLMASK	{ .pm_name = NULL }
331ebccf1e3SJoseph Koshy 
33286a65549SJoseph Koshy #if defined(__amd64__) || defined(__i386__)
333ebccf1e3SJoseph Koshy static int
334ebccf1e3SJoseph Koshy pmc_parse_mask(const struct pmc_masks *pmask, char *p, uint32_t *evmask)
335ebccf1e3SJoseph Koshy {
336ebccf1e3SJoseph Koshy 	const struct pmc_masks *pm;
337ebccf1e3SJoseph Koshy 	char *q, *r;
338ebccf1e3SJoseph Koshy 	int c;
339ebccf1e3SJoseph Koshy 
340ebccf1e3SJoseph Koshy 	if (pmask == NULL)	/* no mask keywords */
341aa342b1fSJoseph Koshy 		return (-1);
342ebccf1e3SJoseph Koshy 	q = strchr(p, '=');	/* skip '=' */
343ebccf1e3SJoseph Koshy 	if (*++q == '\0')	/* no more data */
344aa342b1fSJoseph Koshy 		return (-1);
345ebccf1e3SJoseph Koshy 	c = 0;			/* count of mask keywords seen */
346ebccf1e3SJoseph Koshy 	while ((r = strsep(&q, "+")) != NULL) {
347789140c0SJoseph Koshy 		for (pm = pmask; pm->pm_name && strcasecmp(r, pm->pm_name);
348789140c0SJoseph Koshy 		    pm++)
349ebccf1e3SJoseph Koshy 			;
350ebccf1e3SJoseph Koshy 		if (pm->pm_name == NULL) /* not found */
351aa342b1fSJoseph Koshy 			return (-1);
352ebccf1e3SJoseph Koshy 		*evmask |= pm->pm_value;
353ebccf1e3SJoseph Koshy 		c++;
354ebccf1e3SJoseph Koshy 	}
355aa342b1fSJoseph Koshy 	return (c);
356ebccf1e3SJoseph Koshy }
35704e9feb0SMarcel Moolenaar #endif
358ebccf1e3SJoseph Koshy 
359ebccf1e3SJoseph Koshy #define	KWMATCH(p,kw)		(strcasecmp((p), (kw)) == 0)
360ebccf1e3SJoseph Koshy #define	KWPREFIXMATCH(p,kw)	(strncasecmp((p), (kw), sizeof((kw)) - 1) == 0)
361ebccf1e3SJoseph Koshy #define	EV_ALIAS(N,S)		{ .pm_alias = N, .pm_spec = S }
362ebccf1e3SJoseph Koshy 
36304e9feb0SMarcel Moolenaar #if defined(__i386__)
364ebccf1e3SJoseph Koshy 
365ebccf1e3SJoseph Koshy /*
366ebccf1e3SJoseph Koshy  * AMD K7 (Athlon) CPUs.
367ebccf1e3SJoseph Koshy  */
368ebccf1e3SJoseph Koshy 
369ebccf1e3SJoseph Koshy static struct pmc_event_alias k7_aliases[] = {
370ebccf1e3SJoseph Koshy 	EV_ALIAS("branches",		"k7-retired-branches"),
371ebccf1e3SJoseph Koshy 	EV_ALIAS("branch-mispredicts",	"k7-retired-branches-mispredicted"),
372ebccf1e3SJoseph Koshy 	EV_ALIAS("cycles",		"tsc"),
3736aa5a193SJoseph Koshy 	EV_ALIAS("dc-misses",		"k7-dc-misses"),
374ebccf1e3SJoseph Koshy 	EV_ALIAS("ic-misses",		"k7-ic-misses"),
375ebccf1e3SJoseph Koshy 	EV_ALIAS("instructions",	"k7-retired-instructions"),
376ebccf1e3SJoseph Koshy 	EV_ALIAS("interrupts",		"k7-hardware-interrupts"),
377ebccf1e3SJoseph Koshy 	EV_ALIAS(NULL, NULL)
378ebccf1e3SJoseph Koshy };
379ebccf1e3SJoseph Koshy 
380ebccf1e3SJoseph Koshy #define	K7_KW_COUNT	"count"
381ebccf1e3SJoseph Koshy #define	K7_KW_EDGE	"edge"
382ebccf1e3SJoseph Koshy #define	K7_KW_INV	"inv"
383ebccf1e3SJoseph Koshy #define	K7_KW_OS	"os"
384ebccf1e3SJoseph Koshy #define	K7_KW_UNITMASK	"unitmask"
385ebccf1e3SJoseph Koshy #define	K7_KW_USR	"usr"
386ebccf1e3SJoseph Koshy 
387ebccf1e3SJoseph Koshy static int
388ebccf1e3SJoseph Koshy k7_allocate_pmc(enum pmc_event pe, char *ctrspec,
389ebccf1e3SJoseph Koshy     struct pmc_op_pmcallocate *pmc_config)
390ebccf1e3SJoseph Koshy {
391ebccf1e3SJoseph Koshy 	char		*e, *p, *q;
392ebccf1e3SJoseph Koshy 	int		c, has_unitmask;
393ebccf1e3SJoseph Koshy 	uint32_t	count, unitmask;
394ebccf1e3SJoseph Koshy 
395f263522aSJoseph Koshy 	pmc_config->pm_md.pm_amd.pm_amd_config = 0;
396789140c0SJoseph Koshy 	pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE);
397ebccf1e3SJoseph Koshy 
398ebccf1e3SJoseph Koshy 	if (pe == PMC_EV_K7_DC_REFILLS_FROM_L2 ||
399ebccf1e3SJoseph Koshy 	    pe == PMC_EV_K7_DC_REFILLS_FROM_SYSTEM ||
400ebccf1e3SJoseph Koshy 	    pe == PMC_EV_K7_DC_WRITEBACKS) {
401ebccf1e3SJoseph Koshy 		has_unitmask = 1;
402f263522aSJoseph Koshy 		unitmask = AMD_PMC_UNITMASK_MOESI;
403ebccf1e3SJoseph Koshy 	} else
404ebccf1e3SJoseph Koshy 		unitmask = has_unitmask = 0;
405ebccf1e3SJoseph Koshy 
406ebccf1e3SJoseph Koshy 	while ((p = strsep(&ctrspec, ",")) != NULL) {
407ebccf1e3SJoseph Koshy 		if (KWPREFIXMATCH(p, K7_KW_COUNT "=")) {
408ebccf1e3SJoseph Koshy 			q = strchr(p, '=');
409ebccf1e3SJoseph Koshy 			if (*++q == '\0') /* skip '=' */
410aa342b1fSJoseph Koshy 				return (-1);
411ebccf1e3SJoseph Koshy 
412ebccf1e3SJoseph Koshy 			count = strtol(q, &e, 0);
413ebccf1e3SJoseph Koshy 			if (e == q || *e != '\0')
414aa342b1fSJoseph Koshy 				return (-1);
415ebccf1e3SJoseph Koshy 
416ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_THRESHOLD;
417f263522aSJoseph Koshy 			pmc_config->pm_md.pm_amd.pm_amd_config |=
418f263522aSJoseph Koshy 			    AMD_PMC_TO_COUNTER(count);
419ebccf1e3SJoseph Koshy 
420ebccf1e3SJoseph Koshy 		} else if (KWMATCH(p, K7_KW_EDGE)) {
421ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_EDGE;
422ebccf1e3SJoseph Koshy 		} else if (KWMATCH(p, K7_KW_INV)) {
423ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_INVERT;
424ebccf1e3SJoseph Koshy 		} else if (KWMATCH(p, K7_KW_OS)) {
425ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_SYSTEM;
426ebccf1e3SJoseph Koshy 		} else if (KWPREFIXMATCH(p, K7_KW_UNITMASK "=")) {
427ebccf1e3SJoseph Koshy 			if (has_unitmask == 0)
428aa342b1fSJoseph Koshy 				return (-1);
429ebccf1e3SJoseph Koshy 			unitmask = 0;
430ebccf1e3SJoseph Koshy 			q = strchr(p, '=');
431ebccf1e3SJoseph Koshy 			if (*++q == '\0') /* skip '=' */
432aa342b1fSJoseph Koshy 				return (-1);
433ebccf1e3SJoseph Koshy 
434ebccf1e3SJoseph Koshy 			while ((c = tolower(*q++)) != 0)
435ebccf1e3SJoseph Koshy 				if (c == 'm')
436f263522aSJoseph Koshy 					unitmask |= AMD_PMC_UNITMASK_M;
437ebccf1e3SJoseph Koshy 				else if (c == 'o')
438f263522aSJoseph Koshy 					unitmask |= AMD_PMC_UNITMASK_O;
439ebccf1e3SJoseph Koshy 				else if (c == 'e')
440f263522aSJoseph Koshy 					unitmask |= AMD_PMC_UNITMASK_E;
441ebccf1e3SJoseph Koshy 				else if (c == 's')
442f263522aSJoseph Koshy 					unitmask |= AMD_PMC_UNITMASK_S;
443ebccf1e3SJoseph Koshy 				else if (c == 'i')
444f263522aSJoseph Koshy 					unitmask |= AMD_PMC_UNITMASK_I;
445ebccf1e3SJoseph Koshy 				else if (c == '+')
446ebccf1e3SJoseph Koshy 					continue;
447ebccf1e3SJoseph Koshy 				else
448aa342b1fSJoseph Koshy 					return (-1);
449ebccf1e3SJoseph Koshy 
450ebccf1e3SJoseph Koshy 			if (unitmask == 0)
451aa342b1fSJoseph Koshy 				return (-1);
452ebccf1e3SJoseph Koshy 
453ebccf1e3SJoseph Koshy 		} else if (KWMATCH(p, K7_KW_USR)) {
454ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_USER;
455ebccf1e3SJoseph Koshy 		} else
456aa342b1fSJoseph Koshy 			return (-1);
457ebccf1e3SJoseph Koshy 	}
458ebccf1e3SJoseph Koshy 
459ebccf1e3SJoseph Koshy 	if (has_unitmask) {
460ebccf1e3SJoseph Koshy 		pmc_config->pm_caps |= PMC_CAP_QUALIFIER;
461f263522aSJoseph Koshy 		pmc_config->pm_md.pm_amd.pm_amd_config |=
462f263522aSJoseph Koshy 		    AMD_PMC_TO_UNITMASK(unitmask);
463ebccf1e3SJoseph Koshy 	}
464ebccf1e3SJoseph Koshy 
465aa342b1fSJoseph Koshy 	return (0);
466ebccf1e3SJoseph Koshy 
467ebccf1e3SJoseph Koshy }
468ebccf1e3SJoseph Koshy 
469f263522aSJoseph Koshy #endif
470f263522aSJoseph Koshy 
47186a65549SJoseph Koshy #if defined(__amd64__) || defined(__i386__)
472f263522aSJoseph Koshy 
473f263522aSJoseph Koshy /*
4740cfab8ddSJoseph Koshy  * Intel Core (Family 6, Model E) PMCs.
4750cfab8ddSJoseph Koshy  */
4760cfab8ddSJoseph Koshy 
4770cfab8ddSJoseph Koshy static struct pmc_event_alias core_aliases[] = {
4780cfab8ddSJoseph Koshy 	EV_ALIAS("branches",		"iap-br-instr-ret"),
4790cfab8ddSJoseph Koshy 	EV_ALIAS("branch-mispredicts",	"iap-br-mispred-ret"),
4800cfab8ddSJoseph Koshy 	EV_ALIAS("cycles",		"tsc-tsc"),
4810cfab8ddSJoseph Koshy 	EV_ALIAS("ic-misses",		"iap-icache-misses"),
4820cfab8ddSJoseph Koshy 	EV_ALIAS("instructions",	"iap-instr-ret"),
4830cfab8ddSJoseph Koshy 	EV_ALIAS("interrupts",		"iap-core-hw-int-rx"),
4840cfab8ddSJoseph Koshy 	EV_ALIAS("unhalted-cycles",	"iap-unhalted-core-cycles"),
4850cfab8ddSJoseph Koshy 	EV_ALIAS(NULL, NULL)
4860cfab8ddSJoseph Koshy };
4870cfab8ddSJoseph Koshy 
4880cfab8ddSJoseph Koshy /*
4890cfab8ddSJoseph Koshy  * Intel Core2 (Family 6, Model F), Core2Extreme (Family 6, Model 17H)
4900cfab8ddSJoseph Koshy  * and Atom (Family 6, model 1CH) PMCs.
491791f5d5bSJoseph Koshy  *
492791f5d5bSJoseph Koshy  * We map aliases to events on the fixed-function counters if these
493791f5d5bSJoseph Koshy  * are present.  Note that not all CPUs in this family contain fixed-function
494791f5d5bSJoseph Koshy  * counters.
4950cfab8ddSJoseph Koshy  */
4960cfab8ddSJoseph Koshy 
4970cfab8ddSJoseph Koshy static struct pmc_event_alias core2_aliases[] = {
4980cfab8ddSJoseph Koshy 	EV_ALIAS("branches",		"iap-br-inst-retired.any"),
4990cfab8ddSJoseph Koshy 	EV_ALIAS("branch-mispredicts",	"iap-br-inst-retired.mispred"),
5000cfab8ddSJoseph Koshy 	EV_ALIAS("cycles",		"tsc-tsc"),
5010cfab8ddSJoseph Koshy 	EV_ALIAS("ic-misses",		"iap-l1i-misses"),
5020cfab8ddSJoseph Koshy 	EV_ALIAS("instructions",	"iaf-instr-retired.any"),
5030cfab8ddSJoseph Koshy 	EV_ALIAS("interrupts",		"iap-hw-int-rcv"),
5040cfab8ddSJoseph Koshy 	EV_ALIAS("unhalted-cycles",	"iaf-cpu-clk-unhalted.core"),
5050cfab8ddSJoseph Koshy 	EV_ALIAS(NULL, NULL)
5060cfab8ddSJoseph Koshy };
507791f5d5bSJoseph Koshy 
508791f5d5bSJoseph Koshy static struct pmc_event_alias core2_aliases_without_iaf[] = {
509791f5d5bSJoseph Koshy 	EV_ALIAS("branches",		"iap-br-inst-retired.any"),
510791f5d5bSJoseph Koshy 	EV_ALIAS("branch-mispredicts",	"iap-br-inst-retired.mispred"),
511791f5d5bSJoseph Koshy 	EV_ALIAS("cycles",		"tsc-tsc"),
512791f5d5bSJoseph Koshy 	EV_ALIAS("ic-misses",		"iap-l1i-misses"),
513791f5d5bSJoseph Koshy 	EV_ALIAS("instructions",	"iap-inst-retired.any_p"),
514791f5d5bSJoseph Koshy 	EV_ALIAS("interrupts",		"iap-hw-int-rcv"),
515791f5d5bSJoseph Koshy 	EV_ALIAS("unhalted-cycles",	"iap-cpu-clk-unhalted.core_p"),
516791f5d5bSJoseph Koshy 	EV_ALIAS(NULL, NULL)
517791f5d5bSJoseph Koshy };
518791f5d5bSJoseph Koshy 
5190cfab8ddSJoseph Koshy #define	atom_aliases			core2_aliases
520791f5d5bSJoseph Koshy #define	atom_aliases_without_iaf	core2_aliases_without_iaf
521597979c4SJeff Roberson #define corei7_aliases			core2_aliases
522791f5d5bSJoseph Koshy #define corei7_aliases_without_iaf	core2_aliases_without_iaf
5231fa7f10bSFabien Thomas #define westmere_aliases		core2_aliases
5241fa7f10bSFabien Thomas #define westmere_aliases_without_iaf	core2_aliases_without_iaf
5250cfab8ddSJoseph Koshy 
5260cfab8ddSJoseph Koshy #define	IAF_KW_OS		"os"
5270cfab8ddSJoseph Koshy #define	IAF_KW_USR		"usr"
5280cfab8ddSJoseph Koshy #define	IAF_KW_ANYTHREAD	"anythread"
5290cfab8ddSJoseph Koshy 
5300cfab8ddSJoseph Koshy /*
5310cfab8ddSJoseph Koshy  * Parse an event specifier for Intel fixed function counters.
5320cfab8ddSJoseph Koshy  */
5330cfab8ddSJoseph Koshy static int
5340cfab8ddSJoseph Koshy iaf_allocate_pmc(enum pmc_event pe, char *ctrspec,
5350cfab8ddSJoseph Koshy     struct pmc_op_pmcallocate *pmc_config)
5360cfab8ddSJoseph Koshy {
5370cfab8ddSJoseph Koshy 	char *p;
5380cfab8ddSJoseph Koshy 
5390cfab8ddSJoseph Koshy 	(void) pe;
5400cfab8ddSJoseph Koshy 
5410cfab8ddSJoseph Koshy 	pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE);
5420cfab8ddSJoseph Koshy 	pmc_config->pm_md.pm_iaf.pm_iaf_flags = 0;
5430cfab8ddSJoseph Koshy 
5440cfab8ddSJoseph Koshy 	while ((p = strsep(&ctrspec, ",")) != NULL) {
5450cfab8ddSJoseph Koshy 		if (KWMATCH(p, IAF_KW_OS))
5460cfab8ddSJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_SYSTEM;
5470cfab8ddSJoseph Koshy 		else if (KWMATCH(p, IAF_KW_USR))
5480cfab8ddSJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_USER;
5490cfab8ddSJoseph Koshy 		else if (KWMATCH(p, IAF_KW_ANYTHREAD))
5500cfab8ddSJoseph Koshy 			pmc_config->pm_md.pm_iaf.pm_iaf_flags |= IAF_ANY;
5510cfab8ddSJoseph Koshy 		else
5520cfab8ddSJoseph Koshy 			return (-1);
5530cfab8ddSJoseph Koshy 	}
5540cfab8ddSJoseph Koshy 
5550cfab8ddSJoseph Koshy 	return (0);
5560cfab8ddSJoseph Koshy }
5570cfab8ddSJoseph Koshy 
5580cfab8ddSJoseph Koshy /*
5590cfab8ddSJoseph Koshy  * Core/Core2 support.
5600cfab8ddSJoseph Koshy  */
5610cfab8ddSJoseph Koshy 
5620cfab8ddSJoseph Koshy #define	IAP_KW_AGENT		"agent"
5630cfab8ddSJoseph Koshy #define	IAP_KW_ANYTHREAD	"anythread"
5640cfab8ddSJoseph Koshy #define	IAP_KW_CACHESTATE	"cachestate"
5650cfab8ddSJoseph Koshy #define	IAP_KW_CMASK		"cmask"
5660cfab8ddSJoseph Koshy #define	IAP_KW_CORE		"core"
5670cfab8ddSJoseph Koshy #define	IAP_KW_EDGE		"edge"
5680cfab8ddSJoseph Koshy #define	IAP_KW_INV		"inv"
5690cfab8ddSJoseph Koshy #define	IAP_KW_OS		"os"
5700cfab8ddSJoseph Koshy #define	IAP_KW_PREFETCH		"prefetch"
5710cfab8ddSJoseph Koshy #define	IAP_KW_SNOOPRESPONSE	"snoopresponse"
5720cfab8ddSJoseph Koshy #define	IAP_KW_SNOOPTYPE	"snooptype"
5730cfab8ddSJoseph Koshy #define	IAP_KW_TRANSITION	"trans"
5740cfab8ddSJoseph Koshy #define	IAP_KW_USR		"usr"
5751fa7f10bSFabien Thomas #define	IAP_KW_RSP		"rsp"
5760cfab8ddSJoseph Koshy 
5770cfab8ddSJoseph Koshy static struct pmc_masks iap_core_mask[] = {
5780cfab8ddSJoseph Koshy 	PMCMASK(all,	(0x3 << 14)),
5790cfab8ddSJoseph Koshy 	PMCMASK(this,	(0x1 << 14)),
5800cfab8ddSJoseph Koshy 	NULLMASK
5810cfab8ddSJoseph Koshy };
5820cfab8ddSJoseph Koshy 
5830cfab8ddSJoseph Koshy static struct pmc_masks iap_agent_mask[] = {
5840cfab8ddSJoseph Koshy 	PMCMASK(this,	0),
5850cfab8ddSJoseph Koshy 	PMCMASK(any,	(0x1 << 13)),
5860cfab8ddSJoseph Koshy 	NULLMASK
5870cfab8ddSJoseph Koshy };
5880cfab8ddSJoseph Koshy 
5890cfab8ddSJoseph Koshy static struct pmc_masks iap_prefetch_mask[] = {
5900cfab8ddSJoseph Koshy 	PMCMASK(both,		(0x3 << 12)),
5910cfab8ddSJoseph Koshy 	PMCMASK(only,		(0x1 << 12)),
5920cfab8ddSJoseph Koshy 	PMCMASK(exclude,	0),
5930cfab8ddSJoseph Koshy 	NULLMASK
5940cfab8ddSJoseph Koshy };
5950cfab8ddSJoseph Koshy 
5960cfab8ddSJoseph Koshy static struct pmc_masks iap_cachestate_mask[] = {
5970cfab8ddSJoseph Koshy 	PMCMASK(i,		(1 <<  8)),
5980cfab8ddSJoseph Koshy 	PMCMASK(s,		(1 <<  9)),
5990cfab8ddSJoseph Koshy 	PMCMASK(e,		(1 << 10)),
6000cfab8ddSJoseph Koshy 	PMCMASK(m,		(1 << 11)),
6010cfab8ddSJoseph Koshy 	NULLMASK
6020cfab8ddSJoseph Koshy };
6030cfab8ddSJoseph Koshy 
6040cfab8ddSJoseph Koshy static struct pmc_masks iap_snoopresponse_mask[] = {
6050cfab8ddSJoseph Koshy 	PMCMASK(clean,		(1 << 8)),
6060cfab8ddSJoseph Koshy 	PMCMASK(hit,		(1 << 9)),
6070cfab8ddSJoseph Koshy 	PMCMASK(hitm,		(1 << 11)),
6080cfab8ddSJoseph Koshy 	NULLMASK
6090cfab8ddSJoseph Koshy };
6100cfab8ddSJoseph Koshy 
6110cfab8ddSJoseph Koshy static struct pmc_masks iap_snooptype_mask[] = {
6120cfab8ddSJoseph Koshy 	PMCMASK(cmp2s,		(1 << 8)),
6130cfab8ddSJoseph Koshy 	PMCMASK(cmp2i,		(1 << 9)),
6140cfab8ddSJoseph Koshy 	NULLMASK
6150cfab8ddSJoseph Koshy };
6160cfab8ddSJoseph Koshy 
6170cfab8ddSJoseph Koshy static struct pmc_masks iap_transition_mask[] = {
6180cfab8ddSJoseph Koshy 	PMCMASK(any,		0x00),
6190cfab8ddSJoseph Koshy 	PMCMASK(frequency,	0x10),
6200cfab8ddSJoseph Koshy 	NULLMASK
6210cfab8ddSJoseph Koshy };
6220cfab8ddSJoseph Koshy 
6231fa7f10bSFabien Thomas static struct pmc_masks iap_rsp_mask[] = {
6241fa7f10bSFabien Thomas 	PMCMASK(DMND_DATA_RD,		(1 <<  0)),
6251fa7f10bSFabien Thomas 	PMCMASK(DMND_RFO,		(1 <<  1)),
6261fa7f10bSFabien Thomas 	PMCMASK(DMND_IFETCH,		(1 <<  2)),
6271fa7f10bSFabien Thomas 	PMCMASK(WB,			(1 <<  3)),
6281fa7f10bSFabien Thomas 	PMCMASK(PF_DATA_RD,		(1 <<  4)),
6291fa7f10bSFabien Thomas 	PMCMASK(PF_RFO,			(1 <<  5)),
6301fa7f10bSFabien Thomas 	PMCMASK(PF_IFETCH,		(1 <<  6)),
6311fa7f10bSFabien Thomas 	PMCMASK(OTHER,			(1 <<  7)),
6321fa7f10bSFabien Thomas 	PMCMASK(UNCORE_HIT,		(1 <<  8)),
6331fa7f10bSFabien Thomas 	PMCMASK(OTHER_CORE_HIT_SNP,	(1 <<  9)),
6341fa7f10bSFabien Thomas 	PMCMASK(OTHER_CORE_HITM,	(1 << 10)),
6351fa7f10bSFabien Thomas 	PMCMASK(REMOTE_CACHE_FWD,	(1 << 12)),
6361fa7f10bSFabien Thomas 	PMCMASK(REMOTE_DRAM,		(1 << 13)),
6371fa7f10bSFabien Thomas 	PMCMASK(LOCAL_DRAM,		(1 << 14)),
6381fa7f10bSFabien Thomas 	PMCMASK(NON_DRAM,		(1 << 15)),
6391fa7f10bSFabien Thomas 	NULLMASK
6401fa7f10bSFabien Thomas };
6411fa7f10bSFabien Thomas 
6420cfab8ddSJoseph Koshy static int
6430cfab8ddSJoseph Koshy iap_allocate_pmc(enum pmc_event pe, char *ctrspec,
6440cfab8ddSJoseph Koshy     struct pmc_op_pmcallocate *pmc_config)
6450cfab8ddSJoseph Koshy {
6460cfab8ddSJoseph Koshy 	char *e, *p, *q;
6471fa7f10bSFabien Thomas 	uint32_t cachestate, evmask, rsp;
6480cfab8ddSJoseph Koshy 	int count, n;
6490cfab8ddSJoseph Koshy 
6500cfab8ddSJoseph Koshy 	pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE |
6510cfab8ddSJoseph Koshy 	    PMC_CAP_QUALIFIER);
6520cfab8ddSJoseph Koshy 	pmc_config->pm_md.pm_iap.pm_iap_config = 0;
6530cfab8ddSJoseph Koshy 
6541fa7f10bSFabien Thomas 	cachestate = evmask = rsp = 0;
6550cfab8ddSJoseph Koshy 
6560cfab8ddSJoseph Koshy 	/* Parse additional modifiers if present */
6570cfab8ddSJoseph Koshy 	while ((p = strsep(&ctrspec, ",")) != NULL) {
6580cfab8ddSJoseph Koshy 
6590cfab8ddSJoseph Koshy 		n = 0;
6600cfab8ddSJoseph Koshy 		if (KWPREFIXMATCH(p, IAP_KW_CMASK "=")) {
6610cfab8ddSJoseph Koshy 			q = strchr(p, '=');
6620cfab8ddSJoseph Koshy 			if (*++q == '\0') /* skip '=' */
6630cfab8ddSJoseph Koshy 				return (-1);
6640cfab8ddSJoseph Koshy 			count = strtol(q, &e, 0);
6650cfab8ddSJoseph Koshy 			if (e == q || *e != '\0')
6660cfab8ddSJoseph Koshy 				return (-1);
6670cfab8ddSJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_THRESHOLD;
6680cfab8ddSJoseph Koshy 			pmc_config->pm_md.pm_iap.pm_iap_config |=
6690cfab8ddSJoseph Koshy 			    IAP_CMASK(count);
6700cfab8ddSJoseph Koshy 		} else if (KWMATCH(p, IAP_KW_EDGE)) {
6710cfab8ddSJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_EDGE;
6720cfab8ddSJoseph Koshy 		} else if (KWMATCH(p, IAP_KW_INV)) {
6730cfab8ddSJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_INVERT;
6740cfab8ddSJoseph Koshy 		} else if (KWMATCH(p, IAP_KW_OS)) {
6750cfab8ddSJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_SYSTEM;
6760cfab8ddSJoseph Koshy 		} else if (KWMATCH(p, IAP_KW_USR)) {
6770cfab8ddSJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_USER;
6780cfab8ddSJoseph Koshy 		} else if (KWMATCH(p, IAP_KW_ANYTHREAD)) {
6790cfab8ddSJoseph Koshy 			pmc_config->pm_md.pm_iap.pm_iap_config |= IAP_ANY;
680b47ea38eSJoseph Koshy 		} else if (KWPREFIXMATCH(p, IAP_KW_CORE "=")) {
6810cfab8ddSJoseph Koshy 			n = pmc_parse_mask(iap_core_mask, p, &evmask);
6820cfab8ddSJoseph Koshy 			if (n != 1)
6830cfab8ddSJoseph Koshy 				return (-1);
684b47ea38eSJoseph Koshy 		} else if (KWPREFIXMATCH(p, IAP_KW_AGENT "=")) {
6850cfab8ddSJoseph Koshy 			n = pmc_parse_mask(iap_agent_mask, p, &evmask);
6860cfab8ddSJoseph Koshy 			if (n != 1)
6870cfab8ddSJoseph Koshy 				return (-1);
688b47ea38eSJoseph Koshy 		} else if (KWPREFIXMATCH(p, IAP_KW_PREFETCH "=")) {
6890cfab8ddSJoseph Koshy 			n = pmc_parse_mask(iap_prefetch_mask, p, &evmask);
6900cfab8ddSJoseph Koshy 			if (n != 1)
6910cfab8ddSJoseph Koshy 				return (-1);
692b47ea38eSJoseph Koshy 		} else if (KWPREFIXMATCH(p, IAP_KW_CACHESTATE "=")) {
6930cfab8ddSJoseph Koshy 			n = pmc_parse_mask(iap_cachestate_mask, p, &cachestate);
6940cfab8ddSJoseph Koshy 		} else if (cpu_info.pm_cputype == PMC_CPU_INTEL_CORE &&
695b47ea38eSJoseph Koshy 		    KWPREFIXMATCH(p, IAP_KW_TRANSITION "=")) {
6960cfab8ddSJoseph Koshy 			n = pmc_parse_mask(iap_transition_mask, p, &evmask);
6970cfab8ddSJoseph Koshy 			if (n != 1)
6980cfab8ddSJoseph Koshy 				return (-1);
6990cfab8ddSJoseph Koshy 		} else if (cpu_info.pm_cputype == PMC_CPU_INTEL_ATOM ||
700b4d091f3SJoseph Koshy 		    cpu_info.pm_cputype == PMC_CPU_INTEL_CORE2 ||
7011fa7f10bSFabien Thomas 		    cpu_info.pm_cputype == PMC_CPU_INTEL_CORE2EXTREME) {
702b47ea38eSJoseph Koshy 			if (KWPREFIXMATCH(p, IAP_KW_SNOOPRESPONSE "=")) {
7030cfab8ddSJoseph Koshy 				n = pmc_parse_mask(iap_snoopresponse_mask, p,
7040cfab8ddSJoseph Koshy 				    &evmask);
705b47ea38eSJoseph Koshy 			} else if (KWPREFIXMATCH(p, IAP_KW_SNOOPTYPE "=")) {
7060cfab8ddSJoseph Koshy 				n = pmc_parse_mask(iap_snooptype_mask, p,
7070cfab8ddSJoseph Koshy 				    &evmask);
7080cfab8ddSJoseph Koshy 			} else
7090cfab8ddSJoseph Koshy 				return (-1);
7101fa7f10bSFabien Thomas 		} else if (cpu_info.pm_cputype == PMC_CPU_INTEL_COREI7 ||
7111fa7f10bSFabien Thomas 		    cpu_info.pm_cputype == PMC_CPU_INTEL_WESTMERE) {
7121fa7f10bSFabien Thomas 			if (KWPREFIXMATCH(p, IAP_KW_RSP "=")) {
7131fa7f10bSFabien Thomas 				n = pmc_parse_mask(iap_rsp_mask, p, &rsp);
7141fa7f10bSFabien Thomas 			} else
7151fa7f10bSFabien Thomas 				return (-1);
7160cfab8ddSJoseph Koshy 		} else
7170cfab8ddSJoseph Koshy 			return (-1);
7180cfab8ddSJoseph Koshy 
7190cfab8ddSJoseph Koshy 		if (n < 0)	/* Parsing failed. */
7200cfab8ddSJoseph Koshy 			return (-1);
7210cfab8ddSJoseph Koshy 	}
7220cfab8ddSJoseph Koshy 
7230cfab8ddSJoseph Koshy 	pmc_config->pm_md.pm_iap.pm_iap_config |= evmask;
7240cfab8ddSJoseph Koshy 
7250cfab8ddSJoseph Koshy 	/*
7260cfab8ddSJoseph Koshy 	 * If the event requires a 'cachestate' qualifier but was not
7270cfab8ddSJoseph Koshy 	 * specified by the user, use a sensible default.
7280cfab8ddSJoseph Koshy 	 */
7290cfab8ddSJoseph Koshy 	switch (pe) {
7300cfab8ddSJoseph Koshy 	case PMC_EV_IAP_EVENT_28H: /* Core, Core2, Atom */
7310cfab8ddSJoseph Koshy 	case PMC_EV_IAP_EVENT_29H: /* Core, Core2, Atom */
7320cfab8ddSJoseph Koshy 	case PMC_EV_IAP_EVENT_2AH: /* Core, Core2, Atom */
7330cfab8ddSJoseph Koshy 	case PMC_EV_IAP_EVENT_2BH: /* Atom, Core2 */
7340cfab8ddSJoseph Koshy 	case PMC_EV_IAP_EVENT_2EH: /* Core, Core2, Atom */
7350cfab8ddSJoseph Koshy 	case PMC_EV_IAP_EVENT_30H: /* Core, Core2, Atom */
7360cfab8ddSJoseph Koshy 	case PMC_EV_IAP_EVENT_32H: /* Core */
7370cfab8ddSJoseph Koshy 	case PMC_EV_IAP_EVENT_40H: /* Core */
7380cfab8ddSJoseph Koshy 	case PMC_EV_IAP_EVENT_41H: /* Core */
7390cfab8ddSJoseph Koshy 	case PMC_EV_IAP_EVENT_42H: /* Core, Core2, Atom */
7400cfab8ddSJoseph Koshy 		if (cachestate == 0)
7410cfab8ddSJoseph Koshy 			cachestate = (0xF << 8);
742aa1b887bSRyan Stone 		break;
743aa1b887bSRyan Stone 	case PMC_EV_IAP_EVENT_77H: /* Atom */
744aa1b887bSRyan Stone 		/* IAP_EVENT_77H only accepts a cachestate qualifier on the
745aa1b887bSRyan Stone 		 * Atom processor
746aa1b887bSRyan Stone 		 */
747aa1b887bSRyan Stone 		if(cpu_info.pm_cputype == PMC_CPU_INTEL_ATOM && cachestate == 0)
748aa1b887bSRyan Stone 			cachestate = (0xF << 8);
749aa1b887bSRyan Stone 	    break;
7500cfab8ddSJoseph Koshy 	default:
7510cfab8ddSJoseph Koshy 		break;
7520cfab8ddSJoseph Koshy 	}
7530cfab8ddSJoseph Koshy 
7540cfab8ddSJoseph Koshy 	pmc_config->pm_md.pm_iap.pm_iap_config |= cachestate;
7551fa7f10bSFabien Thomas 	pmc_config->pm_md.pm_iap.pm_iap_rsp = rsp;
7561fa7f10bSFabien Thomas 
7571fa7f10bSFabien Thomas 	return (0);
7581fa7f10bSFabien Thomas }
7591fa7f10bSFabien Thomas 
7601fa7f10bSFabien Thomas /*
7611fa7f10bSFabien Thomas  * Intel Uncore.
7621fa7f10bSFabien Thomas  */
7631fa7f10bSFabien Thomas 
7641fa7f10bSFabien Thomas static int
7651fa7f10bSFabien Thomas ucf_allocate_pmc(enum pmc_event pe, char *ctrspec,
7661fa7f10bSFabien Thomas     struct pmc_op_pmcallocate *pmc_config)
7671fa7f10bSFabien Thomas {
7681fa7f10bSFabien Thomas 	(void) pe;
7691fa7f10bSFabien Thomas 	(void) ctrspec;
7701fa7f10bSFabien Thomas 
7711fa7f10bSFabien Thomas 	pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE);
7721fa7f10bSFabien Thomas 	pmc_config->pm_md.pm_ucf.pm_ucf_flags = 0;
7731fa7f10bSFabien Thomas 
7741fa7f10bSFabien Thomas 	return (0);
7751fa7f10bSFabien Thomas }
7761fa7f10bSFabien Thomas 
7771fa7f10bSFabien Thomas #define	UCP_KW_CMASK		"cmask"
7781fa7f10bSFabien Thomas #define	UCP_KW_EDGE		"edge"
7791fa7f10bSFabien Thomas #define	UCP_KW_INV		"inv"
7801fa7f10bSFabien Thomas 
7811fa7f10bSFabien Thomas static int
7821fa7f10bSFabien Thomas ucp_allocate_pmc(enum pmc_event pe, char *ctrspec,
7831fa7f10bSFabien Thomas     struct pmc_op_pmcallocate *pmc_config)
7841fa7f10bSFabien Thomas {
7851fa7f10bSFabien Thomas 	char *e, *p, *q;
7861fa7f10bSFabien Thomas 	int count, n;
7871fa7f10bSFabien Thomas 
7881fa7f10bSFabien Thomas 	(void) pe;
7891fa7f10bSFabien Thomas 
7901fa7f10bSFabien Thomas 	pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE |
7911fa7f10bSFabien Thomas 	    PMC_CAP_QUALIFIER);
7921fa7f10bSFabien Thomas 	pmc_config->pm_md.pm_ucp.pm_ucp_config = 0;
7931fa7f10bSFabien Thomas 
7941fa7f10bSFabien Thomas 	/* Parse additional modifiers if present */
7951fa7f10bSFabien Thomas 	while ((p = strsep(&ctrspec, ",")) != NULL) {
7961fa7f10bSFabien Thomas 
7971fa7f10bSFabien Thomas 		n = 0;
7981fa7f10bSFabien Thomas 		if (KWPREFIXMATCH(p, UCP_KW_CMASK "=")) {
7991fa7f10bSFabien Thomas 			q = strchr(p, '=');
8001fa7f10bSFabien Thomas 			if (*++q == '\0') /* skip '=' */
8011fa7f10bSFabien Thomas 				return (-1);
8021fa7f10bSFabien Thomas 			count = strtol(q, &e, 0);
8031fa7f10bSFabien Thomas 			if (e == q || *e != '\0')
8041fa7f10bSFabien Thomas 				return (-1);
8051fa7f10bSFabien Thomas 			pmc_config->pm_caps |= PMC_CAP_THRESHOLD;
8061fa7f10bSFabien Thomas 			pmc_config->pm_md.pm_ucp.pm_ucp_config |=
8071fa7f10bSFabien Thomas 			    UCP_CMASK(count);
8081fa7f10bSFabien Thomas 		} else if (KWMATCH(p, UCP_KW_EDGE)) {
8091fa7f10bSFabien Thomas 			pmc_config->pm_caps |= PMC_CAP_EDGE;
8101fa7f10bSFabien Thomas 		} else if (KWMATCH(p, UCP_KW_INV)) {
8111fa7f10bSFabien Thomas 			pmc_config->pm_caps |= PMC_CAP_INVERT;
8121fa7f10bSFabien Thomas 		} else
8131fa7f10bSFabien Thomas 			return (-1);
8141fa7f10bSFabien Thomas 
8151fa7f10bSFabien Thomas 		if (n < 0)	/* Parsing failed. */
8161fa7f10bSFabien Thomas 			return (-1);
8171fa7f10bSFabien Thomas 	}
8180cfab8ddSJoseph Koshy 
8190cfab8ddSJoseph Koshy 	return (0);
8200cfab8ddSJoseph Koshy }
8210cfab8ddSJoseph Koshy 
8220cfab8ddSJoseph Koshy /*
823f263522aSJoseph Koshy  * AMD K8 PMCs.
824f263522aSJoseph Koshy  *
825f263522aSJoseph Koshy  * These are very similar to AMD K7 PMCs, but support more kinds of
826f263522aSJoseph Koshy  * events.
827f263522aSJoseph Koshy  */
828f263522aSJoseph Koshy 
829f263522aSJoseph Koshy static struct pmc_event_alias k8_aliases[] = {
830f263522aSJoseph Koshy 	EV_ALIAS("branches",		"k8-fr-retired-taken-branches"),
831f263522aSJoseph Koshy 	EV_ALIAS("branch-mispredicts",
832f263522aSJoseph Koshy 	    "k8-fr-retired-taken-branches-mispredicted"),
833f263522aSJoseph Koshy 	EV_ALIAS("cycles",		"tsc"),
834f263522aSJoseph Koshy 	EV_ALIAS("dc-misses",		"k8-dc-miss"),
835f263522aSJoseph Koshy 	EV_ALIAS("ic-misses",		"k8-ic-miss"),
836f263522aSJoseph Koshy 	EV_ALIAS("instructions",	"k8-fr-retired-x86-instructions"),
837f263522aSJoseph Koshy 	EV_ALIAS("interrupts",		"k8-fr-taken-hardware-interrupts"),
838177a2f22SJoseph Koshy 	EV_ALIAS("unhalted-cycles",	"k8-bu-cpu-clk-unhalted"),
839f263522aSJoseph Koshy 	EV_ALIAS(NULL, NULL)
840f263522aSJoseph Koshy };
841f263522aSJoseph Koshy 
842f263522aSJoseph Koshy #define	__K8MASK(N,V) PMCMASK(N,(1 << (V)))
843f263522aSJoseph Koshy 
844f263522aSJoseph Koshy /*
845f263522aSJoseph Koshy  * Parsing tables
846f263522aSJoseph Koshy  */
847f263522aSJoseph Koshy 
848f263522aSJoseph Koshy /* fp dispatched fpu ops */
849f263522aSJoseph Koshy static const struct pmc_masks k8_mask_fdfo[] = {
850f263522aSJoseph Koshy 	__K8MASK(add-pipe-excluding-junk-ops,	0),
851f263522aSJoseph Koshy 	__K8MASK(multiply-pipe-excluding-junk-ops,	1),
852f263522aSJoseph Koshy 	__K8MASK(store-pipe-excluding-junk-ops,	2),
853f263522aSJoseph Koshy 	__K8MASK(add-pipe-junk-ops,		3),
854f263522aSJoseph Koshy 	__K8MASK(multiply-pipe-junk-ops,	4),
855f263522aSJoseph Koshy 	__K8MASK(store-pipe-junk-ops,		5),
856f263522aSJoseph Koshy 	NULLMASK
857f263522aSJoseph Koshy };
858f263522aSJoseph Koshy 
859f263522aSJoseph Koshy /* ls segment register loads */
860f263522aSJoseph Koshy static const struct pmc_masks k8_mask_lsrl[] = {
861f263522aSJoseph Koshy 	__K8MASK(es,	0),
862f263522aSJoseph Koshy 	__K8MASK(cs,	1),
863f263522aSJoseph Koshy 	__K8MASK(ss,	2),
864f263522aSJoseph Koshy 	__K8MASK(ds,	3),
865f263522aSJoseph Koshy 	__K8MASK(fs,	4),
866f263522aSJoseph Koshy 	__K8MASK(gs,	5),
867f263522aSJoseph Koshy 	__K8MASK(hs,	6),
868f263522aSJoseph Koshy 	NULLMASK
869f263522aSJoseph Koshy };
870f263522aSJoseph Koshy 
871f263522aSJoseph Koshy /* ls locked operation */
872f263522aSJoseph Koshy static const struct pmc_masks k8_mask_llo[] = {
873f263522aSJoseph Koshy 	__K8MASK(locked-instructions,	0),
874f263522aSJoseph Koshy 	__K8MASK(cycles-in-request,	1),
875f263522aSJoseph Koshy 	__K8MASK(cycles-to-complete,	2),
876f263522aSJoseph Koshy 	NULLMASK
877f263522aSJoseph Koshy };
878f263522aSJoseph Koshy 
879f263522aSJoseph Koshy /* dc refill from {l2,system} and dc copyback */
880f263522aSJoseph Koshy static const struct pmc_masks k8_mask_dc[] = {
881f263522aSJoseph Koshy 	__K8MASK(invalid,	0),
882f263522aSJoseph Koshy 	__K8MASK(shared,	1),
883f263522aSJoseph Koshy 	__K8MASK(exclusive,	2),
884f263522aSJoseph Koshy 	__K8MASK(owner,		3),
885f263522aSJoseph Koshy 	__K8MASK(modified,	4),
886f263522aSJoseph Koshy 	NULLMASK
887f263522aSJoseph Koshy };
888f263522aSJoseph Koshy 
889f263522aSJoseph Koshy /* dc one bit ecc error */
890f263522aSJoseph Koshy static const struct pmc_masks k8_mask_dobee[] = {
891f263522aSJoseph Koshy 	__K8MASK(scrubber,	0),
892f263522aSJoseph Koshy 	__K8MASK(piggyback,	1),
893f263522aSJoseph Koshy 	NULLMASK
894f263522aSJoseph Koshy };
895f263522aSJoseph Koshy 
896f263522aSJoseph Koshy /* dc dispatched prefetch instructions */
897f263522aSJoseph Koshy static const struct pmc_masks k8_mask_ddpi[] = {
898f263522aSJoseph Koshy 	__K8MASK(load,	0),
899f263522aSJoseph Koshy 	__K8MASK(store,	1),
900f263522aSJoseph Koshy 	__K8MASK(nta,	2),
901f263522aSJoseph Koshy 	NULLMASK
902f263522aSJoseph Koshy };
903f263522aSJoseph Koshy 
904f263522aSJoseph Koshy /* dc dcache accesses by locks */
905f263522aSJoseph Koshy static const struct pmc_masks k8_mask_dabl[] = {
906f263522aSJoseph Koshy 	__K8MASK(accesses,	0),
907f263522aSJoseph Koshy 	__K8MASK(misses,	1),
908f263522aSJoseph Koshy 	NULLMASK
909f263522aSJoseph Koshy };
910f263522aSJoseph Koshy 
911f263522aSJoseph Koshy /* bu internal l2 request */
912f263522aSJoseph Koshy static const struct pmc_masks k8_mask_bilr[] = {
913f263522aSJoseph Koshy 	__K8MASK(ic-fill,	0),
914f263522aSJoseph Koshy 	__K8MASK(dc-fill,	1),
915f263522aSJoseph Koshy 	__K8MASK(tlb-reload,	2),
916f263522aSJoseph Koshy 	__K8MASK(tag-snoop,	3),
917f263522aSJoseph Koshy 	__K8MASK(cancelled,	4),
918f263522aSJoseph Koshy 	NULLMASK
919f263522aSJoseph Koshy };
920f263522aSJoseph Koshy 
921f263522aSJoseph Koshy /* bu fill request l2 miss */
922f263522aSJoseph Koshy static const struct pmc_masks k8_mask_bfrlm[] = {
923f263522aSJoseph Koshy 	__K8MASK(ic-fill,	0),
924f263522aSJoseph Koshy 	__K8MASK(dc-fill,	1),
925f263522aSJoseph Koshy 	__K8MASK(tlb-reload,	2),
926f263522aSJoseph Koshy 	NULLMASK
927f263522aSJoseph Koshy };
928f263522aSJoseph Koshy 
929f263522aSJoseph Koshy /* bu fill into l2 */
930f263522aSJoseph Koshy static const struct pmc_masks k8_mask_bfil[] = {
931f263522aSJoseph Koshy 	__K8MASK(dirty-l2-victim,	0),
932f263522aSJoseph Koshy 	__K8MASK(victim-from-l2,	1),
933f263522aSJoseph Koshy 	NULLMASK
934f263522aSJoseph Koshy };
935f263522aSJoseph Koshy 
936f263522aSJoseph Koshy /* fr retired fpu instructions */
937f263522aSJoseph Koshy static const struct pmc_masks k8_mask_frfi[] = {
938f263522aSJoseph Koshy 	__K8MASK(x87,			0),
939f263522aSJoseph Koshy 	__K8MASK(mmx-3dnow,		1),
940f263522aSJoseph Koshy 	__K8MASK(packed-sse-sse2,	2),
941f263522aSJoseph Koshy 	__K8MASK(scalar-sse-sse2,	3),
942f263522aSJoseph Koshy 	NULLMASK
943f263522aSJoseph Koshy };
944f263522aSJoseph Koshy 
945f263522aSJoseph Koshy /* fr retired fastpath double op instructions */
946f263522aSJoseph Koshy static const struct pmc_masks k8_mask_frfdoi[] = {
947f263522aSJoseph Koshy 	__K8MASK(low-op-pos-0,		0),
948f263522aSJoseph Koshy 	__K8MASK(low-op-pos-1,		1),
949f263522aSJoseph Koshy 	__K8MASK(low-op-pos-2,		2),
950f263522aSJoseph Koshy 	NULLMASK
951f263522aSJoseph Koshy };
952f263522aSJoseph Koshy 
953f263522aSJoseph Koshy /* fr fpu exceptions */
954f263522aSJoseph Koshy static const struct pmc_masks k8_mask_ffe[] = {
955f263522aSJoseph Koshy 	__K8MASK(x87-reclass-microfaults,	0),
956f263522aSJoseph Koshy 	__K8MASK(sse-retype-microfaults,	1),
957f263522aSJoseph Koshy 	__K8MASK(sse-reclass-microfaults,	2),
958f263522aSJoseph Koshy 	__K8MASK(sse-and-x87-microtraps,	3),
959f263522aSJoseph Koshy 	NULLMASK
960f263522aSJoseph Koshy };
961f263522aSJoseph Koshy 
962f263522aSJoseph Koshy /* nb memory controller page access event */
963f263522aSJoseph Koshy static const struct pmc_masks k8_mask_nmcpae[] = {
964f263522aSJoseph Koshy 	__K8MASK(page-hit,	0),
965f263522aSJoseph Koshy 	__K8MASK(page-miss,	1),
966f263522aSJoseph Koshy 	__K8MASK(page-conflict,	2),
967f263522aSJoseph Koshy 	NULLMASK
968f263522aSJoseph Koshy };
969f263522aSJoseph Koshy 
970f263522aSJoseph Koshy /* nb memory controller turnaround */
971f263522aSJoseph Koshy static const struct pmc_masks k8_mask_nmct[] = {
972f263522aSJoseph Koshy 	__K8MASK(dimm-turnaround,		0),
973f263522aSJoseph Koshy 	__K8MASK(read-to-write-turnaround,	1),
974f263522aSJoseph Koshy 	__K8MASK(write-to-read-turnaround,	2),
975f263522aSJoseph Koshy 	NULLMASK
976f263522aSJoseph Koshy };
977f263522aSJoseph Koshy 
978f263522aSJoseph Koshy /* nb memory controller bypass saturation */
979f263522aSJoseph Koshy static const struct pmc_masks k8_mask_nmcbs[] = {
980f263522aSJoseph Koshy 	__K8MASK(memory-controller-hi-pri-bypass,	0),
981f263522aSJoseph Koshy 	__K8MASK(memory-controller-lo-pri-bypass,	1),
982f263522aSJoseph Koshy 	__K8MASK(dram-controller-interface-bypass,	2),
983f263522aSJoseph Koshy 	__K8MASK(dram-controller-queue-bypass,		3),
984f263522aSJoseph Koshy 	NULLMASK
985f263522aSJoseph Koshy };
986f263522aSJoseph Koshy 
987f263522aSJoseph Koshy /* nb sized commands */
988f263522aSJoseph Koshy static const struct pmc_masks k8_mask_nsc[] = {
989f263522aSJoseph Koshy 	__K8MASK(nonpostwrszbyte,	0),
990f263522aSJoseph Koshy 	__K8MASK(nonpostwrszdword,	1),
991f263522aSJoseph Koshy 	__K8MASK(postwrszbyte,		2),
992f263522aSJoseph Koshy 	__K8MASK(postwrszdword,		3),
993f263522aSJoseph Koshy 	__K8MASK(rdszbyte,		4),
994f263522aSJoseph Koshy 	__K8MASK(rdszdword,		5),
995f263522aSJoseph Koshy 	__K8MASK(rdmodwr,		6),
996f263522aSJoseph Koshy 	NULLMASK
997f263522aSJoseph Koshy };
998f263522aSJoseph Koshy 
999f263522aSJoseph Koshy /* nb probe result */
1000f263522aSJoseph Koshy static const struct pmc_masks k8_mask_npr[] = {
1001f263522aSJoseph Koshy 	__K8MASK(probe-miss,		0),
1002f263522aSJoseph Koshy 	__K8MASK(probe-hit,		1),
1003f263522aSJoseph Koshy 	__K8MASK(probe-hit-dirty-no-memory-cancel, 2),
1004f263522aSJoseph Koshy 	__K8MASK(probe-hit-dirty-with-memory-cancel, 3),
1005f263522aSJoseph Koshy 	NULLMASK
1006f263522aSJoseph Koshy };
1007f263522aSJoseph Koshy 
1008f263522aSJoseph Koshy /* nb hypertransport bus bandwidth */
1009f263522aSJoseph Koshy static const struct pmc_masks k8_mask_nhbb[] = { /* HT bus bandwidth */
1010f263522aSJoseph Koshy 	__K8MASK(command,	0),
1011f263522aSJoseph Koshy 	__K8MASK(data,	1),
1012f263522aSJoseph Koshy 	__K8MASK(buffer-release, 2),
1013f263522aSJoseph Koshy 	__K8MASK(nop,	3),
1014f263522aSJoseph Koshy 	NULLMASK
1015f263522aSJoseph Koshy };
1016f263522aSJoseph Koshy 
1017f263522aSJoseph Koshy #undef	__K8MASK
1018f263522aSJoseph Koshy 
1019f263522aSJoseph Koshy #define	K8_KW_COUNT	"count"
1020f263522aSJoseph Koshy #define	K8_KW_EDGE	"edge"
1021f263522aSJoseph Koshy #define	K8_KW_INV	"inv"
1022f263522aSJoseph Koshy #define	K8_KW_MASK	"mask"
1023f263522aSJoseph Koshy #define	K8_KW_OS	"os"
1024f263522aSJoseph Koshy #define	K8_KW_USR	"usr"
1025f263522aSJoseph Koshy 
1026f263522aSJoseph Koshy static int
1027f263522aSJoseph Koshy k8_allocate_pmc(enum pmc_event pe, char *ctrspec,
1028f263522aSJoseph Koshy     struct pmc_op_pmcallocate *pmc_config)
1029f263522aSJoseph Koshy {
1030f263522aSJoseph Koshy 	char		*e, *p, *q;
1031f263522aSJoseph Koshy 	int		n;
1032f263522aSJoseph Koshy 	uint32_t	count, evmask;
1033f263522aSJoseph Koshy 	const struct pmc_masks	*pm, *pmask;
1034f263522aSJoseph Koshy 
1035789140c0SJoseph Koshy 	pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE);
1036f263522aSJoseph Koshy 	pmc_config->pm_md.pm_amd.pm_amd_config = 0;
1037f263522aSJoseph Koshy 
1038f263522aSJoseph Koshy 	pmask = NULL;
1039f263522aSJoseph Koshy 	evmask = 0;
1040f263522aSJoseph Koshy 
1041f263522aSJoseph Koshy #define	__K8SETMASK(M) pmask = k8_mask_##M
1042f263522aSJoseph Koshy 
1043f263522aSJoseph Koshy 	/* setup parsing tables */
1044f263522aSJoseph Koshy 	switch (pe) {
1045f263522aSJoseph Koshy 	case PMC_EV_K8_FP_DISPATCHED_FPU_OPS:
1046f263522aSJoseph Koshy 		__K8SETMASK(fdfo);
1047f263522aSJoseph Koshy 		break;
1048f263522aSJoseph Koshy 	case PMC_EV_K8_LS_SEGMENT_REGISTER_LOAD:
1049f263522aSJoseph Koshy 		__K8SETMASK(lsrl);
1050f263522aSJoseph Koshy 		break;
1051f263522aSJoseph Koshy 	case PMC_EV_K8_LS_LOCKED_OPERATION:
1052f263522aSJoseph Koshy 		__K8SETMASK(llo);
1053f263522aSJoseph Koshy 		break;
1054f263522aSJoseph Koshy 	case PMC_EV_K8_DC_REFILL_FROM_L2:
1055f263522aSJoseph Koshy 	case PMC_EV_K8_DC_REFILL_FROM_SYSTEM:
1056f263522aSJoseph Koshy 	case PMC_EV_K8_DC_COPYBACK:
1057f263522aSJoseph Koshy 		__K8SETMASK(dc);
1058f263522aSJoseph Koshy 		break;
1059f263522aSJoseph Koshy 	case PMC_EV_K8_DC_ONE_BIT_ECC_ERROR:
1060f263522aSJoseph Koshy 		__K8SETMASK(dobee);
1061f263522aSJoseph Koshy 		break;
1062f263522aSJoseph Koshy 	case PMC_EV_K8_DC_DISPATCHED_PREFETCH_INSTRUCTIONS:
1063f263522aSJoseph Koshy 		__K8SETMASK(ddpi);
1064f263522aSJoseph Koshy 		break;
1065f263522aSJoseph Koshy 	case PMC_EV_K8_DC_DCACHE_ACCESSES_BY_LOCKS:
1066f263522aSJoseph Koshy 		__K8SETMASK(dabl);
1067f263522aSJoseph Koshy 		break;
1068f263522aSJoseph Koshy 	case PMC_EV_K8_BU_INTERNAL_L2_REQUEST:
1069f263522aSJoseph Koshy 		__K8SETMASK(bilr);
1070f263522aSJoseph Koshy 		break;
1071f263522aSJoseph Koshy 	case PMC_EV_K8_BU_FILL_REQUEST_L2_MISS:
1072f263522aSJoseph Koshy 		__K8SETMASK(bfrlm);
1073f263522aSJoseph Koshy 		break;
1074f263522aSJoseph Koshy 	case PMC_EV_K8_BU_FILL_INTO_L2:
1075f263522aSJoseph Koshy 		__K8SETMASK(bfil);
1076f263522aSJoseph Koshy 		break;
1077f263522aSJoseph Koshy 	case PMC_EV_K8_FR_RETIRED_FPU_INSTRUCTIONS:
1078f263522aSJoseph Koshy 		__K8SETMASK(frfi);
1079f263522aSJoseph Koshy 		break;
1080f263522aSJoseph Koshy 	case PMC_EV_K8_FR_RETIRED_FASTPATH_DOUBLE_OP_INSTRUCTIONS:
1081f263522aSJoseph Koshy 		__K8SETMASK(frfdoi);
1082f263522aSJoseph Koshy 		break;
1083f263522aSJoseph Koshy 	case PMC_EV_K8_FR_FPU_EXCEPTIONS:
1084f263522aSJoseph Koshy 		__K8SETMASK(ffe);
1085f263522aSJoseph Koshy 		break;
1086f263522aSJoseph Koshy 	case PMC_EV_K8_NB_MEMORY_CONTROLLER_PAGE_ACCESS_EVENT:
1087f263522aSJoseph Koshy 		__K8SETMASK(nmcpae);
1088f263522aSJoseph Koshy 		break;
1089f263522aSJoseph Koshy 	case PMC_EV_K8_NB_MEMORY_CONTROLLER_TURNAROUND:
1090f263522aSJoseph Koshy 		__K8SETMASK(nmct);
1091f263522aSJoseph Koshy 		break;
1092f263522aSJoseph Koshy 	case PMC_EV_K8_NB_MEMORY_CONTROLLER_BYPASS_SATURATION:
1093f263522aSJoseph Koshy 		__K8SETMASK(nmcbs);
1094f263522aSJoseph Koshy 		break;
1095f263522aSJoseph Koshy 	case PMC_EV_K8_NB_SIZED_COMMANDS:
1096f263522aSJoseph Koshy 		__K8SETMASK(nsc);
1097f263522aSJoseph Koshy 		break;
1098f263522aSJoseph Koshy 	case PMC_EV_K8_NB_PROBE_RESULT:
1099f263522aSJoseph Koshy 		__K8SETMASK(npr);
1100f263522aSJoseph Koshy 		break;
1101f263522aSJoseph Koshy 	case PMC_EV_K8_NB_HT_BUS0_BANDWIDTH:
1102f263522aSJoseph Koshy 	case PMC_EV_K8_NB_HT_BUS1_BANDWIDTH:
1103f263522aSJoseph Koshy 	case PMC_EV_K8_NB_HT_BUS2_BANDWIDTH:
1104f263522aSJoseph Koshy 		__K8SETMASK(nhbb);
1105f263522aSJoseph Koshy 		break;
1106f263522aSJoseph Koshy 
1107f263522aSJoseph Koshy 	default:
1108f263522aSJoseph Koshy 		break;		/* no options defined */
1109f263522aSJoseph Koshy 	}
1110f263522aSJoseph Koshy 
1111f263522aSJoseph Koshy 	while ((p = strsep(&ctrspec, ",")) != NULL) {
1112f263522aSJoseph Koshy 		if (KWPREFIXMATCH(p, K8_KW_COUNT "=")) {
1113f263522aSJoseph Koshy 			q = strchr(p, '=');
1114f263522aSJoseph Koshy 			if (*++q == '\0') /* skip '=' */
1115aa342b1fSJoseph Koshy 				return (-1);
1116f263522aSJoseph Koshy 
1117f263522aSJoseph Koshy 			count = strtol(q, &e, 0);
1118f263522aSJoseph Koshy 			if (e == q || *e != '\0')
1119aa342b1fSJoseph Koshy 				return (-1);
1120f263522aSJoseph Koshy 
1121f263522aSJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_THRESHOLD;
1122f263522aSJoseph Koshy 			pmc_config->pm_md.pm_amd.pm_amd_config |=
1123f263522aSJoseph Koshy 			    AMD_PMC_TO_COUNTER(count);
1124f263522aSJoseph Koshy 
1125f263522aSJoseph Koshy 		} else if (KWMATCH(p, K8_KW_EDGE)) {
1126f263522aSJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_EDGE;
1127f263522aSJoseph Koshy 		} else if (KWMATCH(p, K8_KW_INV)) {
1128f263522aSJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_INVERT;
1129f263522aSJoseph Koshy 		} else if (KWPREFIXMATCH(p, K8_KW_MASK "=")) {
1130f263522aSJoseph Koshy 			if ((n = pmc_parse_mask(pmask, p, &evmask)) < 0)
1131aa342b1fSJoseph Koshy 				return (-1);
1132f263522aSJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_QUALIFIER;
1133f263522aSJoseph Koshy 		} else if (KWMATCH(p, K8_KW_OS)) {
1134f263522aSJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_SYSTEM;
1135f263522aSJoseph Koshy 		} else if (KWMATCH(p, K8_KW_USR)) {
1136f263522aSJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_USER;
1137f263522aSJoseph Koshy 		} else
1138aa342b1fSJoseph Koshy 			return (-1);
1139f263522aSJoseph Koshy 	}
1140f263522aSJoseph Koshy 
1141f263522aSJoseph Koshy 	/* other post processing */
1142f263522aSJoseph Koshy 	switch (pe) {
1143f263522aSJoseph Koshy 	case PMC_EV_K8_FP_DISPATCHED_FPU_OPS:
1144f263522aSJoseph Koshy 	case PMC_EV_K8_FP_CYCLES_WITH_NO_FPU_OPS_RETIRED:
1145f263522aSJoseph Koshy 	case PMC_EV_K8_FP_DISPATCHED_FPU_FAST_FLAG_OPS:
1146f263522aSJoseph Koshy 	case PMC_EV_K8_FR_RETIRED_FASTPATH_DOUBLE_OP_INSTRUCTIONS:
1147f263522aSJoseph Koshy 	case PMC_EV_K8_FR_RETIRED_FPU_INSTRUCTIONS:
1148f263522aSJoseph Koshy 	case PMC_EV_K8_FR_FPU_EXCEPTIONS:
1149f263522aSJoseph Koshy 		/* XXX only available in rev B and later */
1150f263522aSJoseph Koshy 		break;
1151f263522aSJoseph Koshy 	case PMC_EV_K8_DC_DCACHE_ACCESSES_BY_LOCKS:
1152f263522aSJoseph Koshy 		/* XXX only available in rev C and later */
1153f263522aSJoseph Koshy 		break;
1154f263522aSJoseph Koshy 	case PMC_EV_K8_LS_LOCKED_OPERATION:
1155f263522aSJoseph Koshy 		/* XXX CPU Rev A,B evmask is to be zero */
1156f263522aSJoseph Koshy 		if (evmask & (evmask - 1)) /* > 1 bit set */
1157aa342b1fSJoseph Koshy 			return (-1);
1158f263522aSJoseph Koshy 		if (evmask == 0) {
1159f263522aSJoseph Koshy 			evmask = 0x01; /* Rev C and later: #instrs */
1160f263522aSJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_QUALIFIER;
1161f263522aSJoseph Koshy 		}
1162f263522aSJoseph Koshy 		break;
1163f263522aSJoseph Koshy 	default:
1164f263522aSJoseph Koshy 		if (evmask == 0 && pmask != NULL) {
1165f263522aSJoseph Koshy 			for (pm = pmask; pm->pm_name; pm++)
1166f263522aSJoseph Koshy 				evmask |= pm->pm_value;
1167f263522aSJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_QUALIFIER;
1168f263522aSJoseph Koshy 		}
1169f263522aSJoseph Koshy 	}
1170f263522aSJoseph Koshy 
1171f263522aSJoseph Koshy 	if (pmc_config->pm_caps & PMC_CAP_QUALIFIER)
1172f263522aSJoseph Koshy 		pmc_config->pm_md.pm_amd.pm_amd_config =
1173f263522aSJoseph Koshy 		    AMD_PMC_TO_UNITMASK(evmask);
1174f263522aSJoseph Koshy 
1175aa342b1fSJoseph Koshy 	return (0);
1176f263522aSJoseph Koshy }
1177f263522aSJoseph Koshy 
1178f263522aSJoseph Koshy #endif
1179f263522aSJoseph Koshy 
118086a65549SJoseph Koshy #if defined(__amd64__) || defined(__i386__)
1181f263522aSJoseph Koshy 
1182ebccf1e3SJoseph Koshy /*
1183ebccf1e3SJoseph Koshy  * Intel P4 PMCs
1184ebccf1e3SJoseph Koshy  */
1185ebccf1e3SJoseph Koshy 
1186ebccf1e3SJoseph Koshy static struct pmc_event_alias p4_aliases[] = {
1187d56c5d4bSJoseph Koshy 	EV_ALIAS("branches",		"p4-branch-retired,mask=mmtp+mmtm"),
1188d56c5d4bSJoseph Koshy 	EV_ALIAS("branch-mispredicts",	"p4-mispred-branch-retired"),
1189ebccf1e3SJoseph Koshy 	EV_ALIAS("cycles",		"tsc"),
1190d56c5d4bSJoseph Koshy 	EV_ALIAS("instructions",
1191d56c5d4bSJoseph Koshy 	    "p4-instr-retired,mask=nbogusntag+nbogustag"),
1192177a2f22SJoseph Koshy 	EV_ALIAS("unhalted-cycles",	"p4-global-power-events"),
1193ebccf1e3SJoseph Koshy 	EV_ALIAS(NULL, NULL)
1194ebccf1e3SJoseph Koshy };
1195ebccf1e3SJoseph Koshy 
1196ebccf1e3SJoseph Koshy #define	P4_KW_ACTIVE	"active"
1197ebccf1e3SJoseph Koshy #define	P4_KW_ACTIVE_ANY "any"
1198ebccf1e3SJoseph Koshy #define	P4_KW_ACTIVE_BOTH "both"
1199ebccf1e3SJoseph Koshy #define	P4_KW_ACTIVE_NONE "none"
1200ebccf1e3SJoseph Koshy #define	P4_KW_ACTIVE_SINGLE "single"
1201ebccf1e3SJoseph Koshy #define	P4_KW_BUSREQTYPE "busreqtype"
1202ebccf1e3SJoseph Koshy #define	P4_KW_CASCADE	"cascade"
1203ebccf1e3SJoseph Koshy #define	P4_KW_EDGE	"edge"
1204ebccf1e3SJoseph Koshy #define	P4_KW_INV	"complement"
1205ebccf1e3SJoseph Koshy #define	P4_KW_OS	"os"
1206ebccf1e3SJoseph Koshy #define	P4_KW_MASK	"mask"
1207ebccf1e3SJoseph Koshy #define	P4_KW_PRECISE	"precise"
1208ebccf1e3SJoseph Koshy #define	P4_KW_TAG	"tag"
1209ebccf1e3SJoseph Koshy #define	P4_KW_THRESHOLD	"threshold"
1210ebccf1e3SJoseph Koshy #define	P4_KW_USR	"usr"
1211ebccf1e3SJoseph Koshy 
1212ebccf1e3SJoseph Koshy #define	__P4MASK(N,V) PMCMASK(N, (1 << (V)))
1213ebccf1e3SJoseph Koshy 
1214ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_tcdm[] = { /* tc deliver mode */
1215ebccf1e3SJoseph Koshy 	__P4MASK(dd, 0),
1216ebccf1e3SJoseph Koshy 	__P4MASK(db, 1),
1217ebccf1e3SJoseph Koshy 	__P4MASK(di, 2),
1218ebccf1e3SJoseph Koshy 	__P4MASK(bd, 3),
1219ebccf1e3SJoseph Koshy 	__P4MASK(bb, 4),
1220ebccf1e3SJoseph Koshy 	__P4MASK(bi, 5),
1221ebccf1e3SJoseph Koshy 	__P4MASK(id, 6),
1222ebccf1e3SJoseph Koshy 	__P4MASK(ib, 7),
1223ebccf1e3SJoseph Koshy 	NULLMASK
1224ebccf1e3SJoseph Koshy };
1225ebccf1e3SJoseph Koshy 
1226ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_bfr[] = { /* bpu fetch request */
1227ebccf1e3SJoseph Koshy 	__P4MASK(tcmiss, 0),
1228ebccf1e3SJoseph Koshy 	NULLMASK,
1229ebccf1e3SJoseph Koshy };
1230ebccf1e3SJoseph Koshy 
1231ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_ir[] = { /* itlb reference */
1232ebccf1e3SJoseph Koshy 	__P4MASK(hit, 0),
1233ebccf1e3SJoseph Koshy 	__P4MASK(miss, 1),
1234ebccf1e3SJoseph Koshy 	__P4MASK(hit-uc, 2),
1235ebccf1e3SJoseph Koshy 	NULLMASK
1236ebccf1e3SJoseph Koshy };
1237ebccf1e3SJoseph Koshy 
1238ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_memcan[] = { /* memory cancel */
1239ebccf1e3SJoseph Koshy 	__P4MASK(st-rb-full, 2),
1240ebccf1e3SJoseph Koshy 	__P4MASK(64k-conf, 3),
1241ebccf1e3SJoseph Koshy 	NULLMASK
1242ebccf1e3SJoseph Koshy };
1243ebccf1e3SJoseph Koshy 
1244ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_memcomp[] = { /* memory complete */
1245ebccf1e3SJoseph Koshy 	__P4MASK(lsc, 0),
1246ebccf1e3SJoseph Koshy 	__P4MASK(ssc, 1),
1247ebccf1e3SJoseph Koshy 	NULLMASK
1248ebccf1e3SJoseph Koshy };
1249ebccf1e3SJoseph Koshy 
1250ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_lpr[] = { /* load port replay */
1251ebccf1e3SJoseph Koshy 	__P4MASK(split-ld, 1),
1252ebccf1e3SJoseph Koshy 	NULLMASK
1253ebccf1e3SJoseph Koshy };
1254ebccf1e3SJoseph Koshy 
1255ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_spr[] = { /* store port replay */
1256ebccf1e3SJoseph Koshy 	__P4MASK(split-st, 1),
1257ebccf1e3SJoseph Koshy 	NULLMASK
1258ebccf1e3SJoseph Koshy };
1259ebccf1e3SJoseph Koshy 
1260ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_mlr[] = { /* mob load replay */
1261ebccf1e3SJoseph Koshy 	__P4MASK(no-sta, 1),
1262ebccf1e3SJoseph Koshy 	__P4MASK(no-std, 3),
1263ebccf1e3SJoseph Koshy 	__P4MASK(partial-data, 4),
1264ebccf1e3SJoseph Koshy 	__P4MASK(unalgn-addr, 5),
1265ebccf1e3SJoseph Koshy 	NULLMASK
1266ebccf1e3SJoseph Koshy };
1267ebccf1e3SJoseph Koshy 
1268ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_pwt[] = { /* page walk type */
1269ebccf1e3SJoseph Koshy 	__P4MASK(dtmiss, 0),
1270ebccf1e3SJoseph Koshy 	__P4MASK(itmiss, 1),
1271ebccf1e3SJoseph Koshy 	NULLMASK
1272ebccf1e3SJoseph Koshy };
1273ebccf1e3SJoseph Koshy 
1274ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_bcr[] = { /* bsq cache reference */
1275ebccf1e3SJoseph Koshy 	__P4MASK(rd-2ndl-hits, 0),
1276ebccf1e3SJoseph Koshy 	__P4MASK(rd-2ndl-hite, 1),
1277ebccf1e3SJoseph Koshy 	__P4MASK(rd-2ndl-hitm, 2),
1278ebccf1e3SJoseph Koshy 	__P4MASK(rd-3rdl-hits, 3),
1279ebccf1e3SJoseph Koshy 	__P4MASK(rd-3rdl-hite, 4),
1280ebccf1e3SJoseph Koshy 	__P4MASK(rd-3rdl-hitm, 5),
1281ebccf1e3SJoseph Koshy 	__P4MASK(rd-2ndl-miss, 8),
1282ebccf1e3SJoseph Koshy 	__P4MASK(rd-3rdl-miss, 9),
1283ebccf1e3SJoseph Koshy 	__P4MASK(wr-2ndl-miss, 10),
1284ebccf1e3SJoseph Koshy 	NULLMASK
1285ebccf1e3SJoseph Koshy };
1286ebccf1e3SJoseph Koshy 
1287ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_ia[] = { /* ioq allocation */
1288ebccf1e3SJoseph Koshy 	__P4MASK(all-read, 5),
1289ebccf1e3SJoseph Koshy 	__P4MASK(all-write, 6),
1290ebccf1e3SJoseph Koshy 	__P4MASK(mem-uc, 7),
1291ebccf1e3SJoseph Koshy 	__P4MASK(mem-wc, 8),
1292ebccf1e3SJoseph Koshy 	__P4MASK(mem-wt, 9),
1293ebccf1e3SJoseph Koshy 	__P4MASK(mem-wp, 10),
1294ebccf1e3SJoseph Koshy 	__P4MASK(mem-wb, 11),
1295ebccf1e3SJoseph Koshy 	__P4MASK(own, 13),
1296ebccf1e3SJoseph Koshy 	__P4MASK(other, 14),
1297ebccf1e3SJoseph Koshy 	__P4MASK(prefetch, 15),
1298ebccf1e3SJoseph Koshy 	NULLMASK
1299ebccf1e3SJoseph Koshy };
1300ebccf1e3SJoseph Koshy 
1301ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_iae[] = { /* ioq active entries */
1302ebccf1e3SJoseph Koshy 	__P4MASK(all-read, 5),
1303ebccf1e3SJoseph Koshy 	__P4MASK(all-write, 6),
1304ebccf1e3SJoseph Koshy 	__P4MASK(mem-uc, 7),
1305ebccf1e3SJoseph Koshy 	__P4MASK(mem-wc, 8),
1306ebccf1e3SJoseph Koshy 	__P4MASK(mem-wt, 9),
1307ebccf1e3SJoseph Koshy 	__P4MASK(mem-wp, 10),
1308ebccf1e3SJoseph Koshy 	__P4MASK(mem-wb, 11),
1309ebccf1e3SJoseph Koshy 	__P4MASK(own, 13),
1310ebccf1e3SJoseph Koshy 	__P4MASK(other, 14),
1311ebccf1e3SJoseph Koshy 	__P4MASK(prefetch, 15),
1312ebccf1e3SJoseph Koshy 	NULLMASK
1313ebccf1e3SJoseph Koshy };
1314ebccf1e3SJoseph Koshy 
1315ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_fda[] = { /* fsb data activity */
1316ebccf1e3SJoseph Koshy 	__P4MASK(drdy-drv, 0),
1317ebccf1e3SJoseph Koshy 	__P4MASK(drdy-own, 1),
1318ebccf1e3SJoseph Koshy 	__P4MASK(drdy-other, 2),
1319ebccf1e3SJoseph Koshy 	__P4MASK(dbsy-drv, 3),
1320ebccf1e3SJoseph Koshy 	__P4MASK(dbsy-own, 4),
1321ebccf1e3SJoseph Koshy 	__P4MASK(dbsy-other, 5),
1322ebccf1e3SJoseph Koshy 	NULLMASK
1323ebccf1e3SJoseph Koshy };
1324ebccf1e3SJoseph Koshy 
1325ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_ba[] = { /* bsq allocation */
1326ebccf1e3SJoseph Koshy 	__P4MASK(req-type0, 0),
1327ebccf1e3SJoseph Koshy 	__P4MASK(req-type1, 1),
1328ebccf1e3SJoseph Koshy 	__P4MASK(req-len0, 2),
1329ebccf1e3SJoseph Koshy 	__P4MASK(req-len1, 3),
1330ebccf1e3SJoseph Koshy 	__P4MASK(req-io-type, 5),
1331ebccf1e3SJoseph Koshy 	__P4MASK(req-lock-type, 6),
1332ebccf1e3SJoseph Koshy 	__P4MASK(req-cache-type, 7),
1333ebccf1e3SJoseph Koshy 	__P4MASK(req-split-type, 8),
1334ebccf1e3SJoseph Koshy 	__P4MASK(req-dem-type, 9),
1335ebccf1e3SJoseph Koshy 	__P4MASK(req-ord-type, 10),
1336ebccf1e3SJoseph Koshy 	__P4MASK(mem-type0, 11),
1337ebccf1e3SJoseph Koshy 	__P4MASK(mem-type1, 12),
1338ebccf1e3SJoseph Koshy 	__P4MASK(mem-type2, 13),
1339ebccf1e3SJoseph Koshy 	NULLMASK
1340ebccf1e3SJoseph Koshy };
1341ebccf1e3SJoseph Koshy 
1342ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_sia[] = { /* sse input assist */
1343ebccf1e3SJoseph Koshy 	__P4MASK(all, 15),
1344ebccf1e3SJoseph Koshy 	NULLMASK
1345ebccf1e3SJoseph Koshy };
1346ebccf1e3SJoseph Koshy 
1347ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_psu[] = { /* packed sp uop */
1348ebccf1e3SJoseph Koshy 	__P4MASK(all, 15),
1349ebccf1e3SJoseph Koshy 	NULLMASK
1350ebccf1e3SJoseph Koshy };
1351ebccf1e3SJoseph Koshy 
1352ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_pdu[] = { /* packed dp uop */
1353ebccf1e3SJoseph Koshy 	__P4MASK(all, 15),
1354ebccf1e3SJoseph Koshy 	NULLMASK
1355ebccf1e3SJoseph Koshy };
1356ebccf1e3SJoseph Koshy 
1357ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_ssu[] = { /* scalar sp uop */
1358ebccf1e3SJoseph Koshy 	__P4MASK(all, 15),
1359ebccf1e3SJoseph Koshy 	NULLMASK
1360ebccf1e3SJoseph Koshy };
1361ebccf1e3SJoseph Koshy 
1362ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_sdu[] = { /* scalar dp uop */
1363ebccf1e3SJoseph Koshy 	__P4MASK(all, 15),
1364ebccf1e3SJoseph Koshy 	NULLMASK
1365ebccf1e3SJoseph Koshy };
1366ebccf1e3SJoseph Koshy 
1367ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_64bmu[] = { /* 64 bit mmx uop */
1368ebccf1e3SJoseph Koshy 	__P4MASK(all, 15),
1369ebccf1e3SJoseph Koshy 	NULLMASK
1370ebccf1e3SJoseph Koshy };
1371ebccf1e3SJoseph Koshy 
1372ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_128bmu[] = { /* 128 bit mmx uop */
1373ebccf1e3SJoseph Koshy 	__P4MASK(all, 15),
1374ebccf1e3SJoseph Koshy 	NULLMASK
1375ebccf1e3SJoseph Koshy };
1376ebccf1e3SJoseph Koshy 
1377ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_xfu[] = { /* X87 fp uop */
1378ebccf1e3SJoseph Koshy 	__P4MASK(all, 15),
1379ebccf1e3SJoseph Koshy 	NULLMASK
1380ebccf1e3SJoseph Koshy };
1381ebccf1e3SJoseph Koshy 
1382ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_xsmu[] = { /* x87 simd moves uop */
1383ebccf1e3SJoseph Koshy 	__P4MASK(allp0, 3),
1384ebccf1e3SJoseph Koshy 	__P4MASK(allp2, 4),
1385ebccf1e3SJoseph Koshy 	NULLMASK
1386ebccf1e3SJoseph Koshy };
1387ebccf1e3SJoseph Koshy 
1388ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_gpe[] = { /* global power events */
1389ebccf1e3SJoseph Koshy 	__P4MASK(running, 0),
1390ebccf1e3SJoseph Koshy 	NULLMASK
1391ebccf1e3SJoseph Koshy };
1392ebccf1e3SJoseph Koshy 
1393ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_tmx[] = { /* TC ms xfer */
1394ebccf1e3SJoseph Koshy 	__P4MASK(cisc, 0),
1395ebccf1e3SJoseph Koshy 	NULLMASK
1396ebccf1e3SJoseph Koshy };
1397ebccf1e3SJoseph Koshy 
1398ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_uqw[] = { /* uop queue writes */
1399ebccf1e3SJoseph Koshy 	__P4MASK(from-tc-build, 0),
1400ebccf1e3SJoseph Koshy 	__P4MASK(from-tc-deliver, 1),
1401ebccf1e3SJoseph Koshy 	__P4MASK(from-rom, 2),
1402ebccf1e3SJoseph Koshy 	NULLMASK
1403ebccf1e3SJoseph Koshy };
1404ebccf1e3SJoseph Koshy 
1405d56c5d4bSJoseph Koshy static const struct pmc_masks p4_mask_rmbt[] = {
1406d56c5d4bSJoseph Koshy 	/* retired mispred branch type */
1407ebccf1e3SJoseph Koshy 	__P4MASK(conditional, 1),
1408ebccf1e3SJoseph Koshy 	__P4MASK(call, 2),
1409ebccf1e3SJoseph Koshy 	__P4MASK(return, 3),
1410ebccf1e3SJoseph Koshy 	__P4MASK(indirect, 4),
1411ebccf1e3SJoseph Koshy 	NULLMASK
1412ebccf1e3SJoseph Koshy };
1413ebccf1e3SJoseph Koshy 
1414ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_rbt[] = { /* retired branch type */
1415ebccf1e3SJoseph Koshy 	__P4MASK(conditional, 1),
1416ebccf1e3SJoseph Koshy 	__P4MASK(call, 2),
1417ebccf1e3SJoseph Koshy 	__P4MASK(retired, 3),
1418ebccf1e3SJoseph Koshy 	__P4MASK(indirect, 4),
1419ebccf1e3SJoseph Koshy 	NULLMASK
1420ebccf1e3SJoseph Koshy };
1421ebccf1e3SJoseph Koshy 
1422ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_rs[] = { /* resource stall */
1423ebccf1e3SJoseph Koshy 	__P4MASK(sbfull, 5),
1424ebccf1e3SJoseph Koshy 	NULLMASK
1425ebccf1e3SJoseph Koshy };
1426ebccf1e3SJoseph Koshy 
1427ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_wb[] = { /* WC buffer */
1428ebccf1e3SJoseph Koshy 	__P4MASK(wcb-evicts, 0),
1429ebccf1e3SJoseph Koshy 	__P4MASK(wcb-full-evict, 1),
1430ebccf1e3SJoseph Koshy 	NULLMASK
1431ebccf1e3SJoseph Koshy };
1432ebccf1e3SJoseph Koshy 
1433ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_fee[] = { /* front end event */
1434ebccf1e3SJoseph Koshy 	__P4MASK(nbogus, 0),
1435ebccf1e3SJoseph Koshy 	__P4MASK(bogus, 1),
1436ebccf1e3SJoseph Koshy 	NULLMASK
1437ebccf1e3SJoseph Koshy };
1438ebccf1e3SJoseph Koshy 
1439ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_ee[] = { /* execution event */
1440ebccf1e3SJoseph Koshy 	__P4MASK(nbogus0, 0),
1441ebccf1e3SJoseph Koshy 	__P4MASK(nbogus1, 1),
1442ebccf1e3SJoseph Koshy 	__P4MASK(nbogus2, 2),
1443ebccf1e3SJoseph Koshy 	__P4MASK(nbogus3, 3),
1444ebccf1e3SJoseph Koshy 	__P4MASK(bogus0, 4),
1445ebccf1e3SJoseph Koshy 	__P4MASK(bogus1, 5),
1446ebccf1e3SJoseph Koshy 	__P4MASK(bogus2, 6),
1447ebccf1e3SJoseph Koshy 	__P4MASK(bogus3, 7),
1448ebccf1e3SJoseph Koshy 	NULLMASK
1449ebccf1e3SJoseph Koshy };
1450ebccf1e3SJoseph Koshy 
1451ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_re[] = { /* replay event */
1452ebccf1e3SJoseph Koshy 	__P4MASK(nbogus, 0),
1453ebccf1e3SJoseph Koshy 	__P4MASK(bogus, 1),
1454ebccf1e3SJoseph Koshy 	NULLMASK
1455ebccf1e3SJoseph Koshy };
1456ebccf1e3SJoseph Koshy 
1457ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_insret[] = { /* instr retired */
1458ebccf1e3SJoseph Koshy 	__P4MASK(nbogusntag, 0),
1459ebccf1e3SJoseph Koshy 	__P4MASK(nbogustag, 1),
1460ebccf1e3SJoseph Koshy 	__P4MASK(bogusntag, 2),
1461ebccf1e3SJoseph Koshy 	__P4MASK(bogustag, 3),
1462ebccf1e3SJoseph Koshy 	NULLMASK
1463ebccf1e3SJoseph Koshy };
1464ebccf1e3SJoseph Koshy 
1465ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_ur[] = { /* uops retired */
1466ebccf1e3SJoseph Koshy 	__P4MASK(nbogus, 0),
1467ebccf1e3SJoseph Koshy 	__P4MASK(bogus, 1),
1468ebccf1e3SJoseph Koshy 	NULLMASK
1469ebccf1e3SJoseph Koshy };
1470ebccf1e3SJoseph Koshy 
1471ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_ut[] = { /* uop type */
1472ebccf1e3SJoseph Koshy 	__P4MASK(tagloads, 1),
1473ebccf1e3SJoseph Koshy 	__P4MASK(tagstores, 2),
1474ebccf1e3SJoseph Koshy 	NULLMASK
1475ebccf1e3SJoseph Koshy };
1476ebccf1e3SJoseph Koshy 
1477ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_br[] = { /* branch retired */
1478ebccf1e3SJoseph Koshy 	__P4MASK(mmnp, 0),
1479ebccf1e3SJoseph Koshy 	__P4MASK(mmnm, 1),
1480ebccf1e3SJoseph Koshy 	__P4MASK(mmtp, 2),
1481ebccf1e3SJoseph Koshy 	__P4MASK(mmtm, 3),
1482ebccf1e3SJoseph Koshy 	NULLMASK
1483ebccf1e3SJoseph Koshy };
1484ebccf1e3SJoseph Koshy 
1485ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_mbr[] = { /* mispred branch retired */
1486ebccf1e3SJoseph Koshy 	__P4MASK(nbogus, 0),
1487ebccf1e3SJoseph Koshy 	NULLMASK
1488ebccf1e3SJoseph Koshy };
1489ebccf1e3SJoseph Koshy 
1490ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_xa[] = { /* x87 assist */
1491ebccf1e3SJoseph Koshy 	__P4MASK(fpsu, 0),
1492ebccf1e3SJoseph Koshy 	__P4MASK(fpso, 1),
1493ebccf1e3SJoseph Koshy 	__P4MASK(poao, 2),
1494ebccf1e3SJoseph Koshy 	__P4MASK(poau, 3),
1495ebccf1e3SJoseph Koshy 	__P4MASK(prea, 4),
1496ebccf1e3SJoseph Koshy 	NULLMASK
1497ebccf1e3SJoseph Koshy };
1498ebccf1e3SJoseph Koshy 
1499ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_machclr[] = { /* machine clear */
1500ebccf1e3SJoseph Koshy 	__P4MASK(clear, 0),
1501ebccf1e3SJoseph Koshy 	__P4MASK(moclear, 2),
1502ebccf1e3SJoseph Koshy 	__P4MASK(smclear, 3),
1503ebccf1e3SJoseph Koshy 	NULLMASK
1504ebccf1e3SJoseph Koshy };
1505ebccf1e3SJoseph Koshy 
1506ebccf1e3SJoseph Koshy /* P4 event parser */
1507ebccf1e3SJoseph Koshy static int
1508ebccf1e3SJoseph Koshy p4_allocate_pmc(enum pmc_event pe, char *ctrspec,
1509ebccf1e3SJoseph Koshy     struct pmc_op_pmcallocate *pmc_config)
1510ebccf1e3SJoseph Koshy {
1511ebccf1e3SJoseph Koshy 
1512ebccf1e3SJoseph Koshy 	char	*e, *p, *q;
1513ebccf1e3SJoseph Koshy 	int	count, has_tag, has_busreqtype, n;
1514ebccf1e3SJoseph Koshy 	uint32_t evmask, cccractivemask;
1515ebccf1e3SJoseph Koshy 	const struct pmc_masks *pm, *pmask;
1516ebccf1e3SJoseph Koshy 
1517789140c0SJoseph Koshy 	pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE);
1518f263522aSJoseph Koshy 	pmc_config->pm_md.pm_p4.pm_p4_cccrconfig =
1519f263522aSJoseph Koshy 	    pmc_config->pm_md.pm_p4.pm_p4_escrconfig = 0;
1520ebccf1e3SJoseph Koshy 
1521ebccf1e3SJoseph Koshy 	pmask   = NULL;
1522ebccf1e3SJoseph Koshy 	evmask  = 0;
1523ebccf1e3SJoseph Koshy 	cccractivemask = 0x3;
1524ebccf1e3SJoseph Koshy 	has_tag = has_busreqtype = 0;
1525ebccf1e3SJoseph Koshy 
1526ebccf1e3SJoseph Koshy #define	__P4SETMASK(M) do {				\
1527ebccf1e3SJoseph Koshy 	pmask = p4_mask_##M;				\
1528ebccf1e3SJoseph Koshy } while (0)
1529ebccf1e3SJoseph Koshy 
1530ebccf1e3SJoseph Koshy 	switch (pe) {
1531ebccf1e3SJoseph Koshy 	case PMC_EV_P4_TC_DELIVER_MODE:
1532ebccf1e3SJoseph Koshy 		__P4SETMASK(tcdm);
1533ebccf1e3SJoseph Koshy 		break;
1534ebccf1e3SJoseph Koshy 	case PMC_EV_P4_BPU_FETCH_REQUEST:
1535ebccf1e3SJoseph Koshy 		__P4SETMASK(bfr);
1536ebccf1e3SJoseph Koshy 		break;
1537ebccf1e3SJoseph Koshy 	case PMC_EV_P4_ITLB_REFERENCE:
1538ebccf1e3SJoseph Koshy 		__P4SETMASK(ir);
1539ebccf1e3SJoseph Koshy 		break;
1540ebccf1e3SJoseph Koshy 	case PMC_EV_P4_MEMORY_CANCEL:
1541ebccf1e3SJoseph Koshy 		__P4SETMASK(memcan);
1542ebccf1e3SJoseph Koshy 		break;
1543ebccf1e3SJoseph Koshy 	case PMC_EV_P4_MEMORY_COMPLETE:
1544ebccf1e3SJoseph Koshy 		__P4SETMASK(memcomp);
1545ebccf1e3SJoseph Koshy 		break;
1546ebccf1e3SJoseph Koshy 	case PMC_EV_P4_LOAD_PORT_REPLAY:
1547ebccf1e3SJoseph Koshy 		__P4SETMASK(lpr);
1548ebccf1e3SJoseph Koshy 		break;
1549ebccf1e3SJoseph Koshy 	case PMC_EV_P4_STORE_PORT_REPLAY:
1550ebccf1e3SJoseph Koshy 		__P4SETMASK(spr);
1551ebccf1e3SJoseph Koshy 		break;
1552ebccf1e3SJoseph Koshy 	case PMC_EV_P4_MOB_LOAD_REPLAY:
1553ebccf1e3SJoseph Koshy 		__P4SETMASK(mlr);
1554ebccf1e3SJoseph Koshy 		break;
1555ebccf1e3SJoseph Koshy 	case PMC_EV_P4_PAGE_WALK_TYPE:
1556ebccf1e3SJoseph Koshy 		__P4SETMASK(pwt);
1557ebccf1e3SJoseph Koshy 		break;
1558ebccf1e3SJoseph Koshy 	case PMC_EV_P4_BSQ_CACHE_REFERENCE:
1559ebccf1e3SJoseph Koshy 		__P4SETMASK(bcr);
1560ebccf1e3SJoseph Koshy 		break;
1561ebccf1e3SJoseph Koshy 	case PMC_EV_P4_IOQ_ALLOCATION:
1562ebccf1e3SJoseph Koshy 		__P4SETMASK(ia);
1563ebccf1e3SJoseph Koshy 		has_busreqtype = 1;
1564ebccf1e3SJoseph Koshy 		break;
1565ebccf1e3SJoseph Koshy 	case PMC_EV_P4_IOQ_ACTIVE_ENTRIES:
1566ebccf1e3SJoseph Koshy 		__P4SETMASK(iae);
1567ebccf1e3SJoseph Koshy 		has_busreqtype = 1;
1568ebccf1e3SJoseph Koshy 		break;
1569ebccf1e3SJoseph Koshy 	case PMC_EV_P4_FSB_DATA_ACTIVITY:
1570ebccf1e3SJoseph Koshy 		__P4SETMASK(fda);
1571ebccf1e3SJoseph Koshy 		break;
1572ebccf1e3SJoseph Koshy 	case PMC_EV_P4_BSQ_ALLOCATION:
1573ebccf1e3SJoseph Koshy 		__P4SETMASK(ba);
1574ebccf1e3SJoseph Koshy 		break;
1575ebccf1e3SJoseph Koshy 	case PMC_EV_P4_SSE_INPUT_ASSIST:
1576ebccf1e3SJoseph Koshy 		__P4SETMASK(sia);
1577ebccf1e3SJoseph Koshy 		break;
1578ebccf1e3SJoseph Koshy 	case PMC_EV_P4_PACKED_SP_UOP:
1579ebccf1e3SJoseph Koshy 		__P4SETMASK(psu);
1580ebccf1e3SJoseph Koshy 		break;
1581ebccf1e3SJoseph Koshy 	case PMC_EV_P4_PACKED_DP_UOP:
1582ebccf1e3SJoseph Koshy 		__P4SETMASK(pdu);
1583ebccf1e3SJoseph Koshy 		break;
1584ebccf1e3SJoseph Koshy 	case PMC_EV_P4_SCALAR_SP_UOP:
1585ebccf1e3SJoseph Koshy 		__P4SETMASK(ssu);
1586ebccf1e3SJoseph Koshy 		break;
1587ebccf1e3SJoseph Koshy 	case PMC_EV_P4_SCALAR_DP_UOP:
1588ebccf1e3SJoseph Koshy 		__P4SETMASK(sdu);
1589ebccf1e3SJoseph Koshy 		break;
1590ebccf1e3SJoseph Koshy 	case PMC_EV_P4_64BIT_MMX_UOP:
1591ebccf1e3SJoseph Koshy 		__P4SETMASK(64bmu);
1592ebccf1e3SJoseph Koshy 		break;
1593ebccf1e3SJoseph Koshy 	case PMC_EV_P4_128BIT_MMX_UOP:
1594ebccf1e3SJoseph Koshy 		__P4SETMASK(128bmu);
1595ebccf1e3SJoseph Koshy 		break;
1596ebccf1e3SJoseph Koshy 	case PMC_EV_P4_X87_FP_UOP:
1597ebccf1e3SJoseph Koshy 		__P4SETMASK(xfu);
1598ebccf1e3SJoseph Koshy 		break;
1599ebccf1e3SJoseph Koshy 	case PMC_EV_P4_X87_SIMD_MOVES_UOP:
1600ebccf1e3SJoseph Koshy 		__P4SETMASK(xsmu);
1601ebccf1e3SJoseph Koshy 		break;
1602ebccf1e3SJoseph Koshy 	case PMC_EV_P4_GLOBAL_POWER_EVENTS:
1603ebccf1e3SJoseph Koshy 		__P4SETMASK(gpe);
1604ebccf1e3SJoseph Koshy 		break;
1605ebccf1e3SJoseph Koshy 	case PMC_EV_P4_TC_MS_XFER:
1606ebccf1e3SJoseph Koshy 		__P4SETMASK(tmx);
1607ebccf1e3SJoseph Koshy 		break;
1608ebccf1e3SJoseph Koshy 	case PMC_EV_P4_UOP_QUEUE_WRITES:
1609ebccf1e3SJoseph Koshy 		__P4SETMASK(uqw);
1610ebccf1e3SJoseph Koshy 		break;
1611ebccf1e3SJoseph Koshy 	case PMC_EV_P4_RETIRED_MISPRED_BRANCH_TYPE:
1612ebccf1e3SJoseph Koshy 		__P4SETMASK(rmbt);
1613ebccf1e3SJoseph Koshy 		break;
1614ebccf1e3SJoseph Koshy 	case PMC_EV_P4_RETIRED_BRANCH_TYPE:
1615ebccf1e3SJoseph Koshy 		__P4SETMASK(rbt);
1616ebccf1e3SJoseph Koshy 		break;
1617ebccf1e3SJoseph Koshy 	case PMC_EV_P4_RESOURCE_STALL:
1618ebccf1e3SJoseph Koshy 		__P4SETMASK(rs);
1619ebccf1e3SJoseph Koshy 		break;
1620ebccf1e3SJoseph Koshy 	case PMC_EV_P4_WC_BUFFER:
1621ebccf1e3SJoseph Koshy 		__P4SETMASK(wb);
1622ebccf1e3SJoseph Koshy 		break;
1623ebccf1e3SJoseph Koshy 	case PMC_EV_P4_BSQ_ACTIVE_ENTRIES:
1624ebccf1e3SJoseph Koshy 	case PMC_EV_P4_B2B_CYCLES:
1625ebccf1e3SJoseph Koshy 	case PMC_EV_P4_BNR:
1626ebccf1e3SJoseph Koshy 	case PMC_EV_P4_SNOOP:
1627ebccf1e3SJoseph Koshy 	case PMC_EV_P4_RESPONSE:
1628ebccf1e3SJoseph Koshy 		break;
1629ebccf1e3SJoseph Koshy 	case PMC_EV_P4_FRONT_END_EVENT:
1630ebccf1e3SJoseph Koshy 		__P4SETMASK(fee);
1631ebccf1e3SJoseph Koshy 		break;
1632ebccf1e3SJoseph Koshy 	case PMC_EV_P4_EXECUTION_EVENT:
1633ebccf1e3SJoseph Koshy 		__P4SETMASK(ee);
1634ebccf1e3SJoseph Koshy 		break;
1635ebccf1e3SJoseph Koshy 	case PMC_EV_P4_REPLAY_EVENT:
1636ebccf1e3SJoseph Koshy 		__P4SETMASK(re);
1637ebccf1e3SJoseph Koshy 		break;
1638ebccf1e3SJoseph Koshy 	case PMC_EV_P4_INSTR_RETIRED:
1639ebccf1e3SJoseph Koshy 		__P4SETMASK(insret);
1640ebccf1e3SJoseph Koshy 		break;
1641ebccf1e3SJoseph Koshy 	case PMC_EV_P4_UOPS_RETIRED:
1642ebccf1e3SJoseph Koshy 		__P4SETMASK(ur);
1643ebccf1e3SJoseph Koshy 		break;
1644ebccf1e3SJoseph Koshy 	case PMC_EV_P4_UOP_TYPE:
1645ebccf1e3SJoseph Koshy 		__P4SETMASK(ut);
1646ebccf1e3SJoseph Koshy 		break;
1647ebccf1e3SJoseph Koshy 	case PMC_EV_P4_BRANCH_RETIRED:
1648ebccf1e3SJoseph Koshy 		__P4SETMASK(br);
1649ebccf1e3SJoseph Koshy 		break;
1650ebccf1e3SJoseph Koshy 	case PMC_EV_P4_MISPRED_BRANCH_RETIRED:
1651ebccf1e3SJoseph Koshy 		__P4SETMASK(mbr);
1652ebccf1e3SJoseph Koshy 		break;
1653ebccf1e3SJoseph Koshy 	case PMC_EV_P4_X87_ASSIST:
1654ebccf1e3SJoseph Koshy 		__P4SETMASK(xa);
1655ebccf1e3SJoseph Koshy 		break;
1656ebccf1e3SJoseph Koshy 	case PMC_EV_P4_MACHINE_CLEAR:
1657ebccf1e3SJoseph Koshy 		__P4SETMASK(machclr);
1658ebccf1e3SJoseph Koshy 		break;
1659ebccf1e3SJoseph Koshy 	default:
1660aa342b1fSJoseph Koshy 		return (-1);
1661ebccf1e3SJoseph Koshy 	}
1662ebccf1e3SJoseph Koshy 
1663ebccf1e3SJoseph Koshy 	/* process additional flags */
1664ebccf1e3SJoseph Koshy 	while ((p = strsep(&ctrspec, ",")) != NULL) {
1665ebccf1e3SJoseph Koshy 		if (KWPREFIXMATCH(p, P4_KW_ACTIVE)) {
1666ebccf1e3SJoseph Koshy 			q = strchr(p, '=');
1667ebccf1e3SJoseph Koshy 			if (*++q == '\0') /* skip '=' */
1668aa342b1fSJoseph Koshy 				return (-1);
1669ebccf1e3SJoseph Koshy 
1670789140c0SJoseph Koshy 			if (strcasecmp(q, P4_KW_ACTIVE_NONE) == 0)
1671ebccf1e3SJoseph Koshy 				cccractivemask = 0x0;
1672789140c0SJoseph Koshy 			else if (strcasecmp(q, P4_KW_ACTIVE_SINGLE) == 0)
1673ebccf1e3SJoseph Koshy 				cccractivemask = 0x1;
1674789140c0SJoseph Koshy 			else if (strcasecmp(q, P4_KW_ACTIVE_BOTH) == 0)
1675ebccf1e3SJoseph Koshy 				cccractivemask = 0x2;
1676789140c0SJoseph Koshy 			else if (strcasecmp(q, P4_KW_ACTIVE_ANY) == 0)
1677ebccf1e3SJoseph Koshy 				cccractivemask = 0x3;
1678ebccf1e3SJoseph Koshy 			else
1679aa342b1fSJoseph Koshy 				return (-1);
1680ebccf1e3SJoseph Koshy 
1681ebccf1e3SJoseph Koshy 		} else if (KWPREFIXMATCH(p, P4_KW_BUSREQTYPE)) {
1682ebccf1e3SJoseph Koshy 			if (has_busreqtype == 0)
1683aa342b1fSJoseph Koshy 				return (-1);
1684ebccf1e3SJoseph Koshy 
1685ebccf1e3SJoseph Koshy 			q = strchr(p, '=');
1686ebccf1e3SJoseph Koshy 			if (*++q == '\0') /* skip '=' */
1687aa342b1fSJoseph Koshy 				return (-1);
1688ebccf1e3SJoseph Koshy 
1689ebccf1e3SJoseph Koshy 			count = strtol(q, &e, 0);
1690ebccf1e3SJoseph Koshy 			if (e == q || *e != '\0')
1691aa342b1fSJoseph Koshy 				return (-1);
1692ebccf1e3SJoseph Koshy 			evmask = (evmask & ~0x1F) | (count & 0x1F);
1693ebccf1e3SJoseph Koshy 		} else if (KWMATCH(p, P4_KW_CASCADE))
1694ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_CASCADE;
1695ebccf1e3SJoseph Koshy 		else if (KWMATCH(p, P4_KW_EDGE))
1696ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_EDGE;
1697ebccf1e3SJoseph Koshy 		else if (KWMATCH(p, P4_KW_INV))
1698ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_INVERT;
1699ebccf1e3SJoseph Koshy 		else if (KWPREFIXMATCH(p, P4_KW_MASK "=")) {
1700ebccf1e3SJoseph Koshy 			if ((n = pmc_parse_mask(pmask, p, &evmask)) < 0)
1701aa342b1fSJoseph Koshy 				return (-1);
1702ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_QUALIFIER;
1703ebccf1e3SJoseph Koshy 		} else if (KWMATCH(p, P4_KW_OS))
1704ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_SYSTEM;
1705ebccf1e3SJoseph Koshy 		else if (KWMATCH(p, P4_KW_PRECISE))
1706ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_PRECISE;
1707ebccf1e3SJoseph Koshy 		else if (KWPREFIXMATCH(p, P4_KW_TAG "=")) {
1708ebccf1e3SJoseph Koshy 			if (has_tag == 0)
1709aa342b1fSJoseph Koshy 				return (-1);
1710ebccf1e3SJoseph Koshy 
1711ebccf1e3SJoseph Koshy 			q = strchr(p, '=');
1712ebccf1e3SJoseph Koshy 			if (*++q == '\0') /* skip '=' */
1713aa342b1fSJoseph Koshy 				return (-1);
1714ebccf1e3SJoseph Koshy 
1715ebccf1e3SJoseph Koshy 			count = strtol(q, &e, 0);
1716ebccf1e3SJoseph Koshy 			if (e == q || *e != '\0')
1717aa342b1fSJoseph Koshy 				return (-1);
1718ebccf1e3SJoseph Koshy 
1719ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_TAGGING;
1720f263522aSJoseph Koshy 			pmc_config->pm_md.pm_p4.pm_p4_escrconfig |=
1721ebccf1e3SJoseph Koshy 			    P4_ESCR_TO_TAG_VALUE(count);
1722ebccf1e3SJoseph Koshy 		} else if (KWPREFIXMATCH(p, P4_KW_THRESHOLD "=")) {
1723ebccf1e3SJoseph Koshy 			q = strchr(p, '=');
1724ebccf1e3SJoseph Koshy 			if (*++q == '\0') /* skip '=' */
1725aa342b1fSJoseph Koshy 				return (-1);
1726ebccf1e3SJoseph Koshy 
1727ebccf1e3SJoseph Koshy 			count = strtol(q, &e, 0);
1728ebccf1e3SJoseph Koshy 			if (e == q || *e != '\0')
1729aa342b1fSJoseph Koshy 				return (-1);
1730ebccf1e3SJoseph Koshy 
1731ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_THRESHOLD;
1732f263522aSJoseph Koshy 			pmc_config->pm_md.pm_p4.pm_p4_cccrconfig &=
1733f263522aSJoseph Koshy 			    ~P4_CCCR_THRESHOLD_MASK;
1734f263522aSJoseph Koshy 			pmc_config->pm_md.pm_p4.pm_p4_cccrconfig |=
1735f263522aSJoseph Koshy 			    P4_CCCR_TO_THRESHOLD(count);
1736ebccf1e3SJoseph Koshy 		} else if (KWMATCH(p, P4_KW_USR))
1737ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_USER;
1738ebccf1e3SJoseph Koshy 		else
1739aa342b1fSJoseph Koshy 			return (-1);
1740ebccf1e3SJoseph Koshy 	}
1741ebccf1e3SJoseph Koshy 
1742ebccf1e3SJoseph Koshy 	/* other post processing */
1743ebccf1e3SJoseph Koshy 	if (pe == PMC_EV_P4_IOQ_ALLOCATION ||
1744ebccf1e3SJoseph Koshy 	    pe == PMC_EV_P4_FSB_DATA_ACTIVITY ||
1745ebccf1e3SJoseph Koshy 	    pe == PMC_EV_P4_BSQ_ALLOCATION)
1746ebccf1e3SJoseph Koshy 		pmc_config->pm_caps |= PMC_CAP_EDGE;
1747ebccf1e3SJoseph Koshy 
1748ebccf1e3SJoseph Koshy 	/* fill in thread activity mask */
1749f263522aSJoseph Koshy 	pmc_config->pm_md.pm_p4.pm_p4_cccrconfig |=
1750ebccf1e3SJoseph Koshy 	    P4_CCCR_TO_ACTIVE_THREAD(cccractivemask);
1751ebccf1e3SJoseph Koshy 
1752ebccf1e3SJoseph Koshy 	if (evmask)
1753ebccf1e3SJoseph Koshy 		pmc_config->pm_caps |= PMC_CAP_QUALIFIER;
1754ebccf1e3SJoseph Koshy 
1755ebccf1e3SJoseph Koshy 	switch (pe) {
1756ebccf1e3SJoseph Koshy 	case PMC_EV_P4_FSB_DATA_ACTIVITY:
1757ebccf1e3SJoseph Koshy 		if ((evmask & 0x06) == 0x06 ||
1758ebccf1e3SJoseph Koshy 		    (evmask & 0x18) == 0x18)
1759aa342b1fSJoseph Koshy 			return (-1); /* can't have own+other bits together */
1760ebccf1e3SJoseph Koshy 		if (evmask == 0) /* default:drdy-{drv,own}+dbsy{drv,own} */
1761ebccf1e3SJoseph Koshy 			evmask = 0x1D;
1762ebccf1e3SJoseph Koshy 		break;
1763ebccf1e3SJoseph Koshy 	case PMC_EV_P4_MACHINE_CLEAR:
1764ebccf1e3SJoseph Koshy 		/* only one bit is allowed to be set */
1765ebccf1e3SJoseph Koshy 		if ((evmask & (evmask - 1)) != 0)
1766aa342b1fSJoseph Koshy 			return (-1);
1767ebccf1e3SJoseph Koshy 		if (evmask == 0) {
1768ebccf1e3SJoseph Koshy 			evmask = 0x1;	/* 'CLEAR' */
1769ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_QUALIFIER;
1770ebccf1e3SJoseph Koshy 		}
1771ebccf1e3SJoseph Koshy 		break;
1772ebccf1e3SJoseph Koshy 	default:
1773ebccf1e3SJoseph Koshy 		if (evmask == 0 && pmask) {
1774ebccf1e3SJoseph Koshy 			for (pm = pmask; pm->pm_name; pm++)
1775ebccf1e3SJoseph Koshy 				evmask |= pm->pm_value;
1776ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_QUALIFIER;
1777ebccf1e3SJoseph Koshy 		}
1778ebccf1e3SJoseph Koshy 	}
1779ebccf1e3SJoseph Koshy 
1780f263522aSJoseph Koshy 	pmc_config->pm_md.pm_p4.pm_p4_escrconfig =
1781f263522aSJoseph Koshy 	    P4_ESCR_TO_EVENT_MASK(evmask);
1782ebccf1e3SJoseph Koshy 
1783aa342b1fSJoseph Koshy 	return (0);
1784ebccf1e3SJoseph Koshy }
1785ebccf1e3SJoseph Koshy 
178686a65549SJoseph Koshy #endif
178786a65549SJoseph Koshy 
178886a65549SJoseph Koshy #if defined(__i386__)
178986a65549SJoseph Koshy 
1790ebccf1e3SJoseph Koshy /*
1791f263522aSJoseph Koshy  * Pentium style PMCs
1792f263522aSJoseph Koshy  */
1793f263522aSJoseph Koshy 
1794f263522aSJoseph Koshy static struct pmc_event_alias p5_aliases[] = {
17950b9b757dSJoseph Koshy 	EV_ALIAS("branches",		"p5-taken-branches"),
1796f263522aSJoseph Koshy 	EV_ALIAS("cycles",		"tsc"),
17970b9b757dSJoseph Koshy 	EV_ALIAS("dc-misses",		"p5-data-read-miss-or-write-miss"),
17980b9b757dSJoseph Koshy 	EV_ALIAS("ic-misses",		"p5-code-cache-miss"),
17990b9b757dSJoseph Koshy 	EV_ALIAS("instructions",	"p5-instructions-executed"),
18000b9b757dSJoseph Koshy 	EV_ALIAS("interrupts",		"p5-hardware-interrupts"),
18010b9b757dSJoseph Koshy 	EV_ALIAS("unhalted-cycles",
18020b9b757dSJoseph Koshy 	    "p5-number-of-cycles-not-in-halt-state"),
1803f263522aSJoseph Koshy 	EV_ALIAS(NULL, NULL)
1804f263522aSJoseph Koshy };
1805f263522aSJoseph Koshy 
1806f263522aSJoseph Koshy static int
1807f263522aSJoseph Koshy p5_allocate_pmc(enum pmc_event pe, char *ctrspec,
1808f263522aSJoseph Koshy     struct pmc_op_pmcallocate *pmc_config)
1809f263522aSJoseph Koshy {
1810aa342b1fSJoseph Koshy 	return (-1 || pe || ctrspec || pmc_config); /* shut up gcc */
1811f263522aSJoseph Koshy }
1812f263522aSJoseph Koshy 
1813f263522aSJoseph Koshy /*
1814ebccf1e3SJoseph Koshy  * Pentium Pro style PMCs.  These PMCs are found in Pentium II, Pentium III,
1815ebccf1e3SJoseph Koshy  * and Pentium M CPUs.
1816ebccf1e3SJoseph Koshy  */
1817ebccf1e3SJoseph Koshy 
1818ebccf1e3SJoseph Koshy static struct pmc_event_alias p6_aliases[] = {
1819ebccf1e3SJoseph Koshy 	EV_ALIAS("branches",		"p6-br-inst-retired"),
1820ebccf1e3SJoseph Koshy 	EV_ALIAS("branch-mispredicts",	"p6-br-miss-pred-retired"),
1821ebccf1e3SJoseph Koshy 	EV_ALIAS("cycles",		"tsc"),
1822d56c5d4bSJoseph Koshy 	EV_ALIAS("dc-misses",		"p6-dcu-lines-in"),
182373e2d811SJoseph Koshy 	EV_ALIAS("ic-misses",		"p6-ifu-fetch-miss"),
1824ebccf1e3SJoseph Koshy 	EV_ALIAS("instructions",	"p6-inst-retired"),
1825ebccf1e3SJoseph Koshy 	EV_ALIAS("interrupts",		"p6-hw-int-rx"),
1826177a2f22SJoseph Koshy 	EV_ALIAS("unhalted-cycles",	"p6-cpu-clk-unhalted"),
1827ebccf1e3SJoseph Koshy 	EV_ALIAS(NULL, NULL)
1828ebccf1e3SJoseph Koshy };
1829ebccf1e3SJoseph Koshy 
1830ebccf1e3SJoseph Koshy #define	P6_KW_CMASK	"cmask"
1831ebccf1e3SJoseph Koshy #define	P6_KW_EDGE	"edge"
1832ebccf1e3SJoseph Koshy #define	P6_KW_INV	"inv"
1833ebccf1e3SJoseph Koshy #define	P6_KW_OS	"os"
1834ebccf1e3SJoseph Koshy #define	P6_KW_UMASK	"umask"
1835ebccf1e3SJoseph Koshy #define	P6_KW_USR	"usr"
1836ebccf1e3SJoseph Koshy 
1837ebccf1e3SJoseph Koshy static struct pmc_masks p6_mask_mesi[] = {
1838ebccf1e3SJoseph Koshy 	PMCMASK(m,	0x01),
1839ebccf1e3SJoseph Koshy 	PMCMASK(e,	0x02),
1840ebccf1e3SJoseph Koshy 	PMCMASK(s,	0x04),
1841ebccf1e3SJoseph Koshy 	PMCMASK(i,	0x08),
1842ebccf1e3SJoseph Koshy 	NULLMASK
1843ebccf1e3SJoseph Koshy };
1844ebccf1e3SJoseph Koshy 
1845ebccf1e3SJoseph Koshy static struct pmc_masks p6_mask_mesihw[] = {
1846ebccf1e3SJoseph Koshy 	PMCMASK(m,	0x01),
1847ebccf1e3SJoseph Koshy 	PMCMASK(e,	0x02),
1848ebccf1e3SJoseph Koshy 	PMCMASK(s,	0x04),
1849ebccf1e3SJoseph Koshy 	PMCMASK(i,	0x08),
1850ebccf1e3SJoseph Koshy 	PMCMASK(nonhw,	0x00),
1851ebccf1e3SJoseph Koshy 	PMCMASK(hw,	0x10),
1852ebccf1e3SJoseph Koshy 	PMCMASK(both,	0x30),
1853ebccf1e3SJoseph Koshy 	NULLMASK
1854ebccf1e3SJoseph Koshy };
1855ebccf1e3SJoseph Koshy 
1856ebccf1e3SJoseph Koshy static struct pmc_masks p6_mask_hw[] = {
1857ebccf1e3SJoseph Koshy 	PMCMASK(nonhw,	0x00),
1858ebccf1e3SJoseph Koshy 	PMCMASK(hw,	0x10),
1859ebccf1e3SJoseph Koshy 	PMCMASK(both,	0x30),
1860ebccf1e3SJoseph Koshy 	NULLMASK
1861ebccf1e3SJoseph Koshy };
1862ebccf1e3SJoseph Koshy 
1863ebccf1e3SJoseph Koshy static struct pmc_masks p6_mask_any[] = {
1864ebccf1e3SJoseph Koshy 	PMCMASK(self,	0x00),
1865ebccf1e3SJoseph Koshy 	PMCMASK(any,	0x20),
1866ebccf1e3SJoseph Koshy 	NULLMASK
1867ebccf1e3SJoseph Koshy };
1868ebccf1e3SJoseph Koshy 
1869ebccf1e3SJoseph Koshy static struct pmc_masks p6_mask_ekp[] = {
1870ebccf1e3SJoseph Koshy 	PMCMASK(nta,	0x00),
1871ebccf1e3SJoseph Koshy 	PMCMASK(t1,	0x01),
1872ebccf1e3SJoseph Koshy 	PMCMASK(t2,	0x02),
1873ebccf1e3SJoseph Koshy 	PMCMASK(wos,	0x03),
1874ebccf1e3SJoseph Koshy 	NULLMASK
1875ebccf1e3SJoseph Koshy };
1876ebccf1e3SJoseph Koshy 
1877ebccf1e3SJoseph Koshy static struct pmc_masks p6_mask_pps[] = {
1878ebccf1e3SJoseph Koshy 	PMCMASK(packed-and-scalar, 0x00),
1879ebccf1e3SJoseph Koshy 	PMCMASK(scalar,	0x01),
1880ebccf1e3SJoseph Koshy 	NULLMASK
1881ebccf1e3SJoseph Koshy };
1882ebccf1e3SJoseph Koshy 
1883ebccf1e3SJoseph Koshy static struct pmc_masks p6_mask_mite[] = {
1884ebccf1e3SJoseph Koshy 	PMCMASK(packed-multiply,	 0x01),
1885ebccf1e3SJoseph Koshy 	PMCMASK(packed-shift,		0x02),
1886ebccf1e3SJoseph Koshy 	PMCMASK(pack,			0x04),
1887ebccf1e3SJoseph Koshy 	PMCMASK(unpack,			0x08),
1888ebccf1e3SJoseph Koshy 	PMCMASK(packed-logical,		0x10),
1889ebccf1e3SJoseph Koshy 	PMCMASK(packed-arithmetic,	0x20),
1890ebccf1e3SJoseph Koshy 	NULLMASK
1891ebccf1e3SJoseph Koshy };
1892ebccf1e3SJoseph Koshy 
1893ebccf1e3SJoseph Koshy static struct pmc_masks p6_mask_fmt[] = {
1894ebccf1e3SJoseph Koshy 	PMCMASK(mmxtofp,	0x00),
1895ebccf1e3SJoseph Koshy 	PMCMASK(fptommx,	0x01),
1896ebccf1e3SJoseph Koshy 	NULLMASK
1897ebccf1e3SJoseph Koshy };
1898ebccf1e3SJoseph Koshy 
1899ebccf1e3SJoseph Koshy static struct pmc_masks p6_mask_sr[] = {
1900ebccf1e3SJoseph Koshy 	PMCMASK(es,	0x01),
1901ebccf1e3SJoseph Koshy 	PMCMASK(ds,	0x02),
1902ebccf1e3SJoseph Koshy 	PMCMASK(fs,	0x04),
1903ebccf1e3SJoseph Koshy 	PMCMASK(gs,	0x08),
1904ebccf1e3SJoseph Koshy 	NULLMASK
1905ebccf1e3SJoseph Koshy };
1906ebccf1e3SJoseph Koshy 
1907ebccf1e3SJoseph Koshy static struct pmc_masks p6_mask_eet[] = {
1908ebccf1e3SJoseph Koshy 	PMCMASK(all,	0x00),
1909ebccf1e3SJoseph Koshy 	PMCMASK(freq,	0x02),
1910ebccf1e3SJoseph Koshy 	NULLMASK
1911ebccf1e3SJoseph Koshy };
1912ebccf1e3SJoseph Koshy 
1913ebccf1e3SJoseph Koshy static struct pmc_masks p6_mask_efur[] = {
1914ebccf1e3SJoseph Koshy 	PMCMASK(all,	0x00),
1915ebccf1e3SJoseph Koshy 	PMCMASK(loadop,	0x01),
1916ebccf1e3SJoseph Koshy 	PMCMASK(stdsta,	0x02),
1917ebccf1e3SJoseph Koshy 	NULLMASK
1918ebccf1e3SJoseph Koshy };
1919ebccf1e3SJoseph Koshy 
1920ebccf1e3SJoseph Koshy static struct pmc_masks p6_mask_essir[] = {
1921ebccf1e3SJoseph Koshy 	PMCMASK(sse-packed-single,	0x00),
1922ebccf1e3SJoseph Koshy 	PMCMASK(sse-packed-single-scalar-single, 0x01),
1923ebccf1e3SJoseph Koshy 	PMCMASK(sse2-packed-double,	0x02),
1924ebccf1e3SJoseph Koshy 	PMCMASK(sse2-scalar-double,	0x03),
1925ebccf1e3SJoseph Koshy 	NULLMASK
1926ebccf1e3SJoseph Koshy };
1927ebccf1e3SJoseph Koshy 
1928ebccf1e3SJoseph Koshy static struct pmc_masks p6_mask_esscir[] = {
1929ebccf1e3SJoseph Koshy 	PMCMASK(sse-packed-single,	0x00),
1930ebccf1e3SJoseph Koshy 	PMCMASK(sse-scalar-single,	0x01),
1931ebccf1e3SJoseph Koshy 	PMCMASK(sse2-packed-double,	0x02),
1932ebccf1e3SJoseph Koshy 	PMCMASK(sse2-scalar-double,	0x03),
1933ebccf1e3SJoseph Koshy 	NULLMASK
1934ebccf1e3SJoseph Koshy };
1935ebccf1e3SJoseph Koshy 
1936ebccf1e3SJoseph Koshy /* P6 event parser */
1937ebccf1e3SJoseph Koshy static int
1938ebccf1e3SJoseph Koshy p6_allocate_pmc(enum pmc_event pe, char *ctrspec,
1939ebccf1e3SJoseph Koshy     struct pmc_op_pmcallocate *pmc_config)
1940ebccf1e3SJoseph Koshy {
1941ebccf1e3SJoseph Koshy 	char *e, *p, *q;
1942ebccf1e3SJoseph Koshy 	uint32_t evmask;
1943ebccf1e3SJoseph Koshy 	int count, n;
1944ebccf1e3SJoseph Koshy 	const struct pmc_masks *pm, *pmask;
1945ebccf1e3SJoseph Koshy 
1946789140c0SJoseph Koshy 	pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE);
1947f263522aSJoseph Koshy 	pmc_config->pm_md.pm_ppro.pm_ppro_config = 0;
1948ebccf1e3SJoseph Koshy 
1949ebccf1e3SJoseph Koshy 	evmask = 0;
1950ebccf1e3SJoseph Koshy 
1951ebccf1e3SJoseph Koshy #define	P6MASKSET(M)	pmask = p6_mask_ ## M
1952ebccf1e3SJoseph Koshy 
1953ebccf1e3SJoseph Koshy 	switch(pe) {
1954ebccf1e3SJoseph Koshy 	case PMC_EV_P6_L2_IFETCH:	P6MASKSET(mesi); break;
1955ebccf1e3SJoseph Koshy 	case PMC_EV_P6_L2_LD:		P6MASKSET(mesi); break;
1956ebccf1e3SJoseph Koshy 	case PMC_EV_P6_L2_ST:		P6MASKSET(mesi); break;
1957ebccf1e3SJoseph Koshy 	case PMC_EV_P6_L2_RQSTS:	P6MASKSET(mesi); break;
1958ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_DRDY_CLOCKS:
1959ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_LOCK_CLOCKS:
1960ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_BRD:
1961ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_RFO:
1962ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRANS_WB:
1963ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_IFETCH:
1964ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_INVAL:
1965ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_PWR:
1966ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRANS_P:
1967ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRANS_IO:
1968ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_DEF:
1969ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_BURST:
1970ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_ANY:
1971ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_MEM:
1972ebccf1e3SJoseph Koshy 		P6MASKSET(any);	break;
1973ebccf1e3SJoseph Koshy 	case PMC_EV_P6_EMON_KNI_PREF_DISPATCHED:
1974ebccf1e3SJoseph Koshy 	case PMC_EV_P6_EMON_KNI_PREF_MISS:
1975ebccf1e3SJoseph Koshy 		P6MASKSET(ekp); break;
1976ebccf1e3SJoseph Koshy 	case PMC_EV_P6_EMON_KNI_INST_RETIRED:
1977ebccf1e3SJoseph Koshy 	case PMC_EV_P6_EMON_KNI_COMP_INST_RET:
1978ebccf1e3SJoseph Koshy 		P6MASKSET(pps);	break;
1979ebccf1e3SJoseph Koshy 	case PMC_EV_P6_MMX_INSTR_TYPE_EXEC:
1980ebccf1e3SJoseph Koshy 		P6MASKSET(mite); break;
1981ebccf1e3SJoseph Koshy 	case PMC_EV_P6_FP_MMX_TRANS:
1982ebccf1e3SJoseph Koshy 		P6MASKSET(fmt);	break;
1983ebccf1e3SJoseph Koshy 	case PMC_EV_P6_SEG_RENAME_STALLS:
1984ebccf1e3SJoseph Koshy 	case PMC_EV_P6_SEG_REG_RENAMES:
1985ebccf1e3SJoseph Koshy 		P6MASKSET(sr);	break;
1986ebccf1e3SJoseph Koshy 	case PMC_EV_P6_EMON_EST_TRANS:
1987ebccf1e3SJoseph Koshy 		P6MASKSET(eet);	break;
1988ebccf1e3SJoseph Koshy 	case PMC_EV_P6_EMON_FUSED_UOPS_RET:
1989ebccf1e3SJoseph Koshy 		P6MASKSET(efur); break;
1990ebccf1e3SJoseph Koshy 	case PMC_EV_P6_EMON_SSE_SSE2_INST_RETIRED:
1991ebccf1e3SJoseph Koshy 		P6MASKSET(essir); break;
1992ebccf1e3SJoseph Koshy 	case PMC_EV_P6_EMON_SSE_SSE2_COMP_INST_RETIRED:
1993ebccf1e3SJoseph Koshy 		P6MASKSET(esscir); break;
1994ebccf1e3SJoseph Koshy 	default:
1995ebccf1e3SJoseph Koshy 		pmask = NULL;
1996ebccf1e3SJoseph Koshy 		break;
1997ebccf1e3SJoseph Koshy 	}
1998ebccf1e3SJoseph Koshy 
1999ebccf1e3SJoseph Koshy 	/* Pentium M PMCs have a few events with different semantics */
2000ebccf1e3SJoseph Koshy 	if (cpu_info.pm_cputype == PMC_CPU_INTEL_PM) {
2001ebccf1e3SJoseph Koshy 		if (pe == PMC_EV_P6_L2_LD ||
2002ebccf1e3SJoseph Koshy 		    pe == PMC_EV_P6_L2_LINES_IN ||
2003ebccf1e3SJoseph Koshy 		    pe == PMC_EV_P6_L2_LINES_OUT)
2004ebccf1e3SJoseph Koshy 			P6MASKSET(mesihw);
2005ebccf1e3SJoseph Koshy 		else if (pe == PMC_EV_P6_L2_M_LINES_OUTM)
2006ebccf1e3SJoseph Koshy 			P6MASKSET(hw);
2007ebccf1e3SJoseph Koshy 	}
2008ebccf1e3SJoseph Koshy 
2009ebccf1e3SJoseph Koshy 	/* Parse additional modifiers if present */
2010ebccf1e3SJoseph Koshy 	while ((p = strsep(&ctrspec, ",")) != NULL) {
2011ebccf1e3SJoseph Koshy 		if (KWPREFIXMATCH(p, P6_KW_CMASK "=")) {
2012ebccf1e3SJoseph Koshy 			q = strchr(p, '=');
2013ebccf1e3SJoseph Koshy 			if (*++q == '\0') /* skip '=' */
2014aa342b1fSJoseph Koshy 				return (-1);
2015ebccf1e3SJoseph Koshy 			count = strtol(q, &e, 0);
2016ebccf1e3SJoseph Koshy 			if (e == q || *e != '\0')
2017aa342b1fSJoseph Koshy 				return (-1);
2018ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_THRESHOLD;
2019f263522aSJoseph Koshy 			pmc_config->pm_md.pm_ppro.pm_ppro_config |=
2020f263522aSJoseph Koshy 			    P6_EVSEL_TO_CMASK(count);
2021ebccf1e3SJoseph Koshy 		} else if (KWMATCH(p, P6_KW_EDGE)) {
2022ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_EDGE;
2023ebccf1e3SJoseph Koshy 		} else if (KWMATCH(p, P6_KW_INV)) {
2024ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_INVERT;
2025ebccf1e3SJoseph Koshy 		} else if (KWMATCH(p, P6_KW_OS)) {
2026ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_SYSTEM;
2027ebccf1e3SJoseph Koshy 		} else if (KWPREFIXMATCH(p, P6_KW_UMASK "=")) {
2028ebccf1e3SJoseph Koshy 			evmask = 0;
2029ebccf1e3SJoseph Koshy 			if ((n = pmc_parse_mask(pmask, p, &evmask)) < 0)
2030aa342b1fSJoseph Koshy 				return (-1);
2031ebccf1e3SJoseph Koshy 			if ((pe == PMC_EV_P6_BUS_DRDY_CLOCKS ||
2032ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_BUS_LOCK_CLOCKS ||
2033ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_BUS_TRAN_BRD ||
2034ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_BUS_TRAN_RFO ||
2035ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_BUS_TRAN_IFETCH ||
2036ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_BUS_TRAN_INVAL ||
2037ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_BUS_TRAN_PWR ||
2038ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_BUS_TRAN_DEF ||
2039ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_BUS_TRAN_BURST ||
2040ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_BUS_TRAN_ANY ||
2041ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_BUS_TRAN_MEM ||
2042ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_BUS_TRANS_IO ||
2043ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_BUS_TRANS_P ||
2044ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_BUS_TRANS_WB ||
2045ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_EMON_EST_TRANS ||
2046ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_EMON_FUSED_UOPS_RET ||
2047ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_EMON_KNI_COMP_INST_RET ||
2048ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_EMON_KNI_INST_RETIRED ||
2049ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_EMON_KNI_PREF_DISPATCHED ||
2050ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_EMON_KNI_PREF_MISS ||
2051ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_EMON_SSE_SSE2_COMP_INST_RETIRED ||
2052ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_EMON_SSE_SSE2_INST_RETIRED ||
2053ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_FP_MMX_TRANS)
2054aa342b1fSJoseph Koshy 			    && (n > 1))	/* Only one mask keyword is allowed. */
2055aa342b1fSJoseph Koshy 				return (-1);
2056ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_QUALIFIER;
2057ebccf1e3SJoseph Koshy 		} else if (KWMATCH(p, P6_KW_USR)) {
2058ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_USER;
2059ebccf1e3SJoseph Koshy 		} else
2060aa342b1fSJoseph Koshy 			return (-1);
2061ebccf1e3SJoseph Koshy 	}
2062ebccf1e3SJoseph Koshy 
2063ebccf1e3SJoseph Koshy 	/* post processing */
2064ebccf1e3SJoseph Koshy 	switch (pe) {
2065ebccf1e3SJoseph Koshy 
2066ebccf1e3SJoseph Koshy 		/*
2067ebccf1e3SJoseph Koshy 		 * The following events default to an evmask of 0
2068ebccf1e3SJoseph Koshy 		 */
2069ebccf1e3SJoseph Koshy 
2070ebccf1e3SJoseph Koshy 		/* default => 'self' */
2071ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_DRDY_CLOCKS:
2072ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_LOCK_CLOCKS:
2073ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_BRD:
2074ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_RFO:
2075ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRANS_WB:
2076ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_IFETCH:
2077ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_INVAL:
2078ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_PWR:
2079ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRANS_P:
2080ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRANS_IO:
2081ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_DEF:
2082ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_BURST:
2083ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_ANY:
2084ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_MEM:
2085ebccf1e3SJoseph Koshy 
2086ebccf1e3SJoseph Koshy 		/* default => 'nta' */
2087ebccf1e3SJoseph Koshy 	case PMC_EV_P6_EMON_KNI_PREF_DISPATCHED:
2088ebccf1e3SJoseph Koshy 	case PMC_EV_P6_EMON_KNI_PREF_MISS:
2089ebccf1e3SJoseph Koshy 
2090ebccf1e3SJoseph Koshy 		/* default => 'packed and scalar' */
2091ebccf1e3SJoseph Koshy 	case PMC_EV_P6_EMON_KNI_INST_RETIRED:
2092ebccf1e3SJoseph Koshy 	case PMC_EV_P6_EMON_KNI_COMP_INST_RET:
2093ebccf1e3SJoseph Koshy 
2094ebccf1e3SJoseph Koshy 		/* default => 'mmx to fp transitions' */
2095ebccf1e3SJoseph Koshy 	case PMC_EV_P6_FP_MMX_TRANS:
2096ebccf1e3SJoseph Koshy 
2097ebccf1e3SJoseph Koshy 		/* default => 'SSE Packed Single' */
2098ebccf1e3SJoseph Koshy 	case PMC_EV_P6_EMON_SSE_SSE2_INST_RETIRED:
2099ebccf1e3SJoseph Koshy 	case PMC_EV_P6_EMON_SSE_SSE2_COMP_INST_RETIRED:
2100ebccf1e3SJoseph Koshy 
2101ebccf1e3SJoseph Koshy 		/* default => 'all fused micro-ops' */
2102ebccf1e3SJoseph Koshy 	case PMC_EV_P6_EMON_FUSED_UOPS_RET:
2103ebccf1e3SJoseph Koshy 
2104ebccf1e3SJoseph Koshy 		/* default => 'all transitions' */
2105ebccf1e3SJoseph Koshy 	case PMC_EV_P6_EMON_EST_TRANS:
2106ebccf1e3SJoseph Koshy 		break;
2107ebccf1e3SJoseph Koshy 
2108ebccf1e3SJoseph Koshy 	case PMC_EV_P6_MMX_UOPS_EXEC:
2109ebccf1e3SJoseph Koshy 		evmask = 0x0F;		/* only value allowed */
2110ebccf1e3SJoseph Koshy 		break;
2111ebccf1e3SJoseph Koshy 
2112ebccf1e3SJoseph Koshy 	default:
2113ebccf1e3SJoseph Koshy 		/*
2114ebccf1e3SJoseph Koshy 		 * For all other events, set the default event mask
2115ebccf1e3SJoseph Koshy 		 * to a logical OR of all the allowed event mask bits.
2116ebccf1e3SJoseph Koshy 		 */
2117ebccf1e3SJoseph Koshy 		if (evmask == 0 && pmask) {
2118ebccf1e3SJoseph Koshy 			for (pm = pmask; pm->pm_name; pm++)
2119ebccf1e3SJoseph Koshy 				evmask |= pm->pm_value;
2120ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_QUALIFIER;
2121ebccf1e3SJoseph Koshy 		}
2122ebccf1e3SJoseph Koshy 
2123ebccf1e3SJoseph Koshy 		break;
2124ebccf1e3SJoseph Koshy 	}
2125ebccf1e3SJoseph Koshy 
2126ebccf1e3SJoseph Koshy 	if (pmc_config->pm_caps & PMC_CAP_QUALIFIER)
2127f263522aSJoseph Koshy 		pmc_config->pm_md.pm_ppro.pm_ppro_config |=
2128f263522aSJoseph Koshy 		    P6_EVSEL_TO_UMASK(evmask);
2129ebccf1e3SJoseph Koshy 
2130aa342b1fSJoseph Koshy 	return (0);
2131ebccf1e3SJoseph Koshy }
2132ebccf1e3SJoseph Koshy 
2133ebccf1e3SJoseph Koshy #endif
2134ebccf1e3SJoseph Koshy 
2135789140c0SJoseph Koshy #if	defined(__i386__) || defined(__amd64__)
2136789140c0SJoseph Koshy static int
2137789140c0SJoseph Koshy tsc_allocate_pmc(enum pmc_event pe, char *ctrspec,
2138789140c0SJoseph Koshy     struct pmc_op_pmcallocate *pmc_config)
2139789140c0SJoseph Koshy {
2140789140c0SJoseph Koshy 	if (pe != PMC_EV_TSC_TSC)
2141789140c0SJoseph Koshy 		return (-1);
2142789140c0SJoseph Koshy 
2143789140c0SJoseph Koshy 	/* TSC events must be unqualified. */
2144789140c0SJoseph Koshy 	if (ctrspec && *ctrspec != '\0')
2145789140c0SJoseph Koshy 		return (-1);
2146789140c0SJoseph Koshy 
2147789140c0SJoseph Koshy 	pmc_config->pm_md.pm_amd.pm_amd_config = 0;
2148789140c0SJoseph Koshy 	pmc_config->pm_caps |= PMC_CAP_READ;
2149789140c0SJoseph Koshy 
2150789140c0SJoseph Koshy 	return (0);
2151789140c0SJoseph Koshy }
2152789140c0SJoseph Koshy #endif
2153789140c0SJoseph Koshy 
21540ce207d2SRui Paulo #if	defined(__XSCALE__)
21550ce207d2SRui Paulo 
21560ce207d2SRui Paulo static struct pmc_event_alias xscale_aliases[] = {
21570ce207d2SRui Paulo 	EV_ALIAS("branches",		"BRANCH_RETIRED"),
21580ce207d2SRui Paulo 	EV_ALIAS("branch-mispredicts",	"BRANCH_MISPRED"),
21590ce207d2SRui Paulo 	EV_ALIAS("dc-misses",		"DC_MISS"),
21600ce207d2SRui Paulo 	EV_ALIAS("ic-misses",		"IC_MISS"),
21610ce207d2SRui Paulo 	EV_ALIAS("instructions",	"INSTR_RETIRED"),
21620ce207d2SRui Paulo 	EV_ALIAS(NULL, NULL)
21630ce207d2SRui Paulo };
21640ce207d2SRui Paulo static int
21650ce207d2SRui Paulo xscale_allocate_pmc(enum pmc_event pe, char *ctrspec __unused,
21660ce207d2SRui Paulo     struct pmc_op_pmcallocate *pmc_config __unused)
21670ce207d2SRui Paulo {
21680ce207d2SRui Paulo 	switch (pe) {
21690ce207d2SRui Paulo 	default:
21700ce207d2SRui Paulo 		break;
21710ce207d2SRui Paulo 	}
21720ce207d2SRui Paulo 
21730ce207d2SRui Paulo 	return (0);
21740ce207d2SRui Paulo }
21750ce207d2SRui Paulo #endif
21760ce207d2SRui Paulo 
2177660df75eSGeorge V. Neville-Neil #if defined(__mips__)
2178660df75eSGeorge V. Neville-Neil 
2179660df75eSGeorge V. Neville-Neil static struct pmc_event_alias mips24k_aliases[] = {
2180660df75eSGeorge V. Neville-Neil 	EV_ALIAS("instructions",	"INSTR_EXECUTED"),
2181660df75eSGeorge V. Neville-Neil 	EV_ALIAS("branches",		"BRANCH_COMPLETED"),
2182660df75eSGeorge V. Neville-Neil 	EV_ALIAS("branch-mispredicts",	"BRANCH_MISPRED"),
2183660df75eSGeorge V. Neville-Neil 	EV_ALIAS(NULL, NULL)
2184660df75eSGeorge V. Neville-Neil };
2185660df75eSGeorge V. Neville-Neil 
2186660df75eSGeorge V. Neville-Neil #define	MIPS24K_KW_OS		"os"
2187660df75eSGeorge V. Neville-Neil #define	MIPS24K_KW_USR		"usr"
2188660df75eSGeorge V. Neville-Neil #define	MIPS24K_KW_ANYTHREAD	"anythread"
2189660df75eSGeorge V. Neville-Neil 
2190660df75eSGeorge V. Neville-Neil static int
2191660df75eSGeorge V. Neville-Neil mips24k_allocate_pmc(enum pmc_event pe, char *ctrspec __unused,
2192660df75eSGeorge V. Neville-Neil 		  struct pmc_op_pmcallocate *pmc_config __unused)
2193660df75eSGeorge V. Neville-Neil {
2194660df75eSGeorge V. Neville-Neil 	char *p;
2195660df75eSGeorge V. Neville-Neil 
2196660df75eSGeorge V. Neville-Neil 	(void) pe;
2197660df75eSGeorge V. Neville-Neil 
2198660df75eSGeorge V. Neville-Neil 	pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE);
2199660df75eSGeorge V. Neville-Neil 
2200660df75eSGeorge V. Neville-Neil 	while ((p = strsep(&ctrspec, ",")) != NULL) {
2201660df75eSGeorge V. Neville-Neil 		if (KWMATCH(p, MIPS24K_KW_OS))
2202660df75eSGeorge V. Neville-Neil 			pmc_config->pm_caps |= PMC_CAP_SYSTEM;
2203660df75eSGeorge V. Neville-Neil 		else if (KWMATCH(p, MIPS24K_KW_USR))
2204660df75eSGeorge V. Neville-Neil 			pmc_config->pm_caps |= PMC_CAP_USER;
2205660df75eSGeorge V. Neville-Neil 		else if (KWMATCH(p, MIPS24K_KW_ANYTHREAD))
2206660df75eSGeorge V. Neville-Neil 			pmc_config->pm_caps |= (PMC_CAP_USER | PMC_CAP_SYSTEM);
2207660df75eSGeorge V. Neville-Neil 		else
2208660df75eSGeorge V. Neville-Neil 			return (-1);
2209660df75eSGeorge V. Neville-Neil 	}
2210660df75eSGeorge V. Neville-Neil 
2211660df75eSGeorge V. Neville-Neil 	return (0);
2212660df75eSGeorge V. Neville-Neil }
2213660df75eSGeorge V. Neville-Neil #endif /* __mips__ */
2214660df75eSGeorge V. Neville-Neil 
2215660df75eSGeorge V. Neville-Neil 
2216789140c0SJoseph Koshy /*
2217789140c0SJoseph Koshy  * Match an event name `name' with its canonical form.
2218789140c0SJoseph Koshy  *
22190cfab8ddSJoseph Koshy  * Matches are case insensitive and spaces, periods, underscores and
22200cfab8ddSJoseph Koshy  * hyphen characters are considered to match each other.
2221789140c0SJoseph Koshy  *
2222789140c0SJoseph Koshy  * Returns 1 for a match, 0 otherwise.
2223789140c0SJoseph Koshy  */
2224789140c0SJoseph Koshy 
2225789140c0SJoseph Koshy static int
2226789140c0SJoseph Koshy pmc_match_event_name(const char *name, const char *canonicalname)
2227789140c0SJoseph Koshy {
2228789140c0SJoseph Koshy 	int cc, nc;
2229789140c0SJoseph Koshy 	const unsigned char *c, *n;
2230789140c0SJoseph Koshy 
2231789140c0SJoseph Koshy 	c = (const unsigned char *) canonicalname;
2232789140c0SJoseph Koshy 	n = (const unsigned char *) name;
2233789140c0SJoseph Koshy 
2234789140c0SJoseph Koshy 	for (; (nc = *n) && (cc = *c); n++, c++) {
2235789140c0SJoseph Koshy 
22360cfab8ddSJoseph Koshy 		if ((nc == ' ' || nc == '_' || nc == '-' || nc == '.') &&
22370cfab8ddSJoseph Koshy 		    (cc == ' ' || cc == '_' || cc == '-' || cc == '.'))
2238789140c0SJoseph Koshy 			continue;
2239789140c0SJoseph Koshy 
22400cfab8ddSJoseph Koshy 		if (toupper(nc) == toupper(cc))
2241789140c0SJoseph Koshy 			continue;
2242789140c0SJoseph Koshy 
22430cfab8ddSJoseph Koshy 
2244789140c0SJoseph Koshy 		return (0);
2245789140c0SJoseph Koshy 	}
2246789140c0SJoseph Koshy 
2247789140c0SJoseph Koshy 	if (*n == '\0' && *c == '\0')
2248789140c0SJoseph Koshy 		return (1);
2249789140c0SJoseph Koshy 
2250789140c0SJoseph Koshy 	return (0);
2251789140c0SJoseph Koshy }
2252789140c0SJoseph Koshy 
2253789140c0SJoseph Koshy /*
2254789140c0SJoseph Koshy  * Match an event name against all the event named supported by a
2255789140c0SJoseph Koshy  * PMC class.
2256789140c0SJoseph Koshy  *
2257789140c0SJoseph Koshy  * Returns an event descriptor pointer on match or NULL otherwise.
2258789140c0SJoseph Koshy  */
2259789140c0SJoseph Koshy static const struct pmc_event_descr *
2260789140c0SJoseph Koshy pmc_match_event_class(const char *name,
2261789140c0SJoseph Koshy     const struct pmc_class_descr *pcd)
2262789140c0SJoseph Koshy {
2263789140c0SJoseph Koshy 	size_t n;
2264789140c0SJoseph Koshy 	const struct pmc_event_descr *ev;
2265789140c0SJoseph Koshy 
2266789140c0SJoseph Koshy 	ev = pcd->pm_evc_event_table;
2267789140c0SJoseph Koshy 	for (n = 0; n < pcd->pm_evc_event_table_size; n++, ev++)
2268789140c0SJoseph Koshy 		if (pmc_match_event_name(name, ev->pm_ev_name))
2269789140c0SJoseph Koshy 			return (ev);
2270789140c0SJoseph Koshy 
2271789140c0SJoseph Koshy 	return (NULL);
2272789140c0SJoseph Koshy }
2273789140c0SJoseph Koshy 
2274789140c0SJoseph Koshy static int
2275789140c0SJoseph Koshy pmc_mdep_is_compatible_class(enum pmc_class pc)
2276789140c0SJoseph Koshy {
2277789140c0SJoseph Koshy 	size_t n;
2278789140c0SJoseph Koshy 
2279789140c0SJoseph Koshy 	for (n = 0; n < pmc_mdep_class_list_size; n++)
2280789140c0SJoseph Koshy 		if (pmc_mdep_class_list[n] == pc)
2281789140c0SJoseph Koshy 			return (1);
2282789140c0SJoseph Koshy 	return (0);
2283789140c0SJoseph Koshy }
2284789140c0SJoseph Koshy 
2285ebccf1e3SJoseph Koshy /*
2286ebccf1e3SJoseph Koshy  * API entry points
2287ebccf1e3SJoseph Koshy  */
2288ebccf1e3SJoseph Koshy 
2289ebccf1e3SJoseph Koshy int
2290ebccf1e3SJoseph Koshy pmc_allocate(const char *ctrspec, enum pmc_mode mode,
2291ebccf1e3SJoseph Koshy     uint32_t flags, int cpu, pmc_id_t *pmcid)
2292ebccf1e3SJoseph Koshy {
2293789140c0SJoseph Koshy 	size_t n;
2294ebccf1e3SJoseph Koshy 	int retval;
2295ebccf1e3SJoseph Koshy 	char *r, *spec_copy;
2296ebccf1e3SJoseph Koshy 	const char *ctrname;
2297789140c0SJoseph Koshy 	const struct pmc_event_descr *ev;
2298789140c0SJoseph Koshy 	const struct pmc_event_alias *alias;
2299ebccf1e3SJoseph Koshy 	struct pmc_op_pmcallocate pmc_config;
2300789140c0SJoseph Koshy 	const struct pmc_class_descr *pcd;
2301ebccf1e3SJoseph Koshy 
2302ebccf1e3SJoseph Koshy 	spec_copy = NULL;
2303ebccf1e3SJoseph Koshy 	retval    = -1;
2304ebccf1e3SJoseph Koshy 
2305ebccf1e3SJoseph Koshy 	if (mode != PMC_MODE_SS && mode != PMC_MODE_TS &&
2306ebccf1e3SJoseph Koshy 	    mode != PMC_MODE_SC && mode != PMC_MODE_TC) {
2307ebccf1e3SJoseph Koshy 		errno = EINVAL;
2308ebccf1e3SJoseph Koshy 		goto out;
2309ebccf1e3SJoseph Koshy 	}
2310ebccf1e3SJoseph Koshy 
2311ebccf1e3SJoseph Koshy 	/* replace an event alias with the canonical event specifier */
2312ebccf1e3SJoseph Koshy 	if (pmc_mdep_event_aliases)
2313789140c0SJoseph Koshy 		for (alias = pmc_mdep_event_aliases; alias->pm_alias; alias++)
2314789140c0SJoseph Koshy 			if (!strcasecmp(ctrspec, alias->pm_alias)) {
2315789140c0SJoseph Koshy 				spec_copy = strdup(alias->pm_spec);
2316ebccf1e3SJoseph Koshy 				break;
2317ebccf1e3SJoseph Koshy 			}
2318ebccf1e3SJoseph Koshy 
2319ebccf1e3SJoseph Koshy 	if (spec_copy == NULL)
2320ebccf1e3SJoseph Koshy 		spec_copy = strdup(ctrspec);
2321ebccf1e3SJoseph Koshy 
2322ebccf1e3SJoseph Koshy 	r = spec_copy;
2323ebccf1e3SJoseph Koshy 	ctrname = strsep(&r, ",");
2324ebccf1e3SJoseph Koshy 
2325789140c0SJoseph Koshy 	/*
2326789140c0SJoseph Koshy 	 * If a explicit class prefix was given by the user, restrict the
2327789140c0SJoseph Koshy 	 * search for the event to the specified PMC class.
2328789140c0SJoseph Koshy 	 */
2329789140c0SJoseph Koshy 	ev = NULL;
23300cfab8ddSJoseph Koshy 	for (n = 0; n < PMC_CLASS_TABLE_SIZE; n++) {
23310cfab8ddSJoseph Koshy 		pcd = pmc_class_table[n];
2332789140c0SJoseph Koshy 		if (pmc_mdep_is_compatible_class(pcd->pm_evc_class) &&
2333789140c0SJoseph Koshy 		    strncasecmp(ctrname, pcd->pm_evc_name,
2334789140c0SJoseph Koshy 				pcd->pm_evc_name_size) == 0) {
2335789140c0SJoseph Koshy 			if ((ev = pmc_match_event_class(ctrname +
2336789140c0SJoseph Koshy 			    pcd->pm_evc_name_size, pcd)) == NULL) {
2337789140c0SJoseph Koshy 				errno = EINVAL;
2338789140c0SJoseph Koshy 				goto out;
2339789140c0SJoseph Koshy 			}
2340ebccf1e3SJoseph Koshy 			break;
2341789140c0SJoseph Koshy 		}
2342789140c0SJoseph Koshy 	}
2343ebccf1e3SJoseph Koshy 
2344789140c0SJoseph Koshy 	/*
2345789140c0SJoseph Koshy 	 * Otherwise, search for this event in all compatible PMC
2346789140c0SJoseph Koshy 	 * classes.
2347789140c0SJoseph Koshy 	 */
23480cfab8ddSJoseph Koshy 	for (n = 0; ev == NULL && n < PMC_CLASS_TABLE_SIZE; n++) {
23490cfab8ddSJoseph Koshy 		pcd = pmc_class_table[n];
2350789140c0SJoseph Koshy 		if (pmc_mdep_is_compatible_class(pcd->pm_evc_class))
2351789140c0SJoseph Koshy 			ev = pmc_match_event_class(ctrname, pcd);
2352789140c0SJoseph Koshy 	}
2353789140c0SJoseph Koshy 
2354789140c0SJoseph Koshy 	if (ev == NULL) {
2355ebccf1e3SJoseph Koshy 		errno = EINVAL;
2356ebccf1e3SJoseph Koshy 		goto out;
2357ebccf1e3SJoseph Koshy 	}
2358ebccf1e3SJoseph Koshy 
2359ebccf1e3SJoseph Koshy 	bzero(&pmc_config, sizeof(pmc_config));
2360789140c0SJoseph Koshy 	pmc_config.pm_ev    = ev->pm_ev_code;
2361789140c0SJoseph Koshy 	pmc_config.pm_class = pcd->pm_evc_class;
2362ebccf1e3SJoseph Koshy 	pmc_config.pm_cpu   = cpu;
2363ebccf1e3SJoseph Koshy 	pmc_config.pm_mode  = mode;
2364ebccf1e3SJoseph Koshy 	pmc_config.pm_flags = flags;
2365ebccf1e3SJoseph Koshy 
2366ebccf1e3SJoseph Koshy 	if (PMC_IS_SAMPLING_MODE(mode))
2367ebccf1e3SJoseph Koshy 		pmc_config.pm_caps |= PMC_CAP_INTERRUPT;
2368ebccf1e3SJoseph Koshy 
2369789140c0SJoseph Koshy  	if (pcd->pm_evc_allocate_pmc(ev->pm_ev_code, r, &pmc_config) < 0) {
2370ebccf1e3SJoseph Koshy 		errno = EINVAL;
2371ebccf1e3SJoseph Koshy 		goto out;
2372ebccf1e3SJoseph Koshy 	}
2373ebccf1e3SJoseph Koshy 
2374ebccf1e3SJoseph Koshy 	if (PMC_CALL(PMCALLOCATE, &pmc_config) < 0)
2375ebccf1e3SJoseph Koshy 		goto out;
2376ebccf1e3SJoseph Koshy 
2377ebccf1e3SJoseph Koshy 	*pmcid = pmc_config.pm_pmcid;
2378ebccf1e3SJoseph Koshy 
2379ebccf1e3SJoseph Koshy 	retval = 0;
2380ebccf1e3SJoseph Koshy 
2381ebccf1e3SJoseph Koshy  out:
2382ebccf1e3SJoseph Koshy 	if (spec_copy)
2383ebccf1e3SJoseph Koshy 		free(spec_copy);
2384ebccf1e3SJoseph Koshy 
2385aa342b1fSJoseph Koshy 	return (retval);
2386ebccf1e3SJoseph Koshy }
2387ebccf1e3SJoseph Koshy 
2388ebccf1e3SJoseph Koshy int
2389ebccf1e3SJoseph Koshy pmc_attach(pmc_id_t pmc, pid_t pid)
2390ebccf1e3SJoseph Koshy {
2391ebccf1e3SJoseph Koshy 	struct pmc_op_pmcattach pmc_attach_args;
2392ebccf1e3SJoseph Koshy 
2393ebccf1e3SJoseph Koshy 	pmc_attach_args.pm_pmc = pmc;
2394ebccf1e3SJoseph Koshy 	pmc_attach_args.pm_pid = pid;
2395ebccf1e3SJoseph Koshy 
2396aa342b1fSJoseph Koshy 	return (PMC_CALL(PMCATTACH, &pmc_attach_args));
2397ebccf1e3SJoseph Koshy }
2398ebccf1e3SJoseph Koshy 
2399ebccf1e3SJoseph Koshy int
2400c5153e19SJoseph Koshy pmc_capabilities(pmc_id_t pmcid, uint32_t *caps)
2401c5153e19SJoseph Koshy {
2402c5153e19SJoseph Koshy 	unsigned int i;
2403c5153e19SJoseph Koshy 	enum pmc_class cl;
2404c5153e19SJoseph Koshy 
2405c5153e19SJoseph Koshy 	cl = PMC_ID_TO_CLASS(pmcid);
2406c5153e19SJoseph Koshy 	for (i = 0; i < cpu_info.pm_nclass; i++)
2407c5153e19SJoseph Koshy 		if (cpu_info.pm_classes[i].pm_class == cl) {
2408c5153e19SJoseph Koshy 			*caps = cpu_info.pm_classes[i].pm_caps;
2409aa342b1fSJoseph Koshy 			return (0);
2410c5153e19SJoseph Koshy 		}
2411484202faSJoseph Koshy 	errno = EINVAL;
2412484202faSJoseph Koshy 	return (-1);
2413c5153e19SJoseph Koshy }
2414c5153e19SJoseph Koshy 
2415f263522aSJoseph Koshy int
2416f263522aSJoseph Koshy pmc_configure_logfile(int fd)
2417ebccf1e3SJoseph Koshy {
2418f263522aSJoseph Koshy 	struct pmc_op_configurelog cla;
2419f263522aSJoseph Koshy 
2420f263522aSJoseph Koshy 	cla.pm_logfd = fd;
2421f263522aSJoseph Koshy 	if (PMC_CALL(CONFIGURELOG, &cla) < 0)
2422aa342b1fSJoseph Koshy 		return (-1);
2423aa342b1fSJoseph Koshy 	return (0);
2424ebccf1e3SJoseph Koshy }
2425ebccf1e3SJoseph Koshy 
2426f263522aSJoseph Koshy int
2427f263522aSJoseph Koshy pmc_cpuinfo(const struct pmc_cpuinfo **pci)
2428ebccf1e3SJoseph Koshy {
2429f263522aSJoseph Koshy 	if (pmc_syscall == -1) {
2430f263522aSJoseph Koshy 		errno = ENXIO;
2431aa342b1fSJoseph Koshy 		return (-1);
2432ebccf1e3SJoseph Koshy 	}
2433ebccf1e3SJoseph Koshy 
24341455fcd3SJoseph Koshy 	*pci = &cpu_info;
2435aa342b1fSJoseph Koshy 	return (0);
2436ebccf1e3SJoseph Koshy }
2437ebccf1e3SJoseph Koshy 
2438f263522aSJoseph Koshy int
2439f263522aSJoseph Koshy pmc_detach(pmc_id_t pmc, pid_t pid)
2440ebccf1e3SJoseph Koshy {
2441f263522aSJoseph Koshy 	struct pmc_op_pmcattach pmc_detach_args;
2442ebccf1e3SJoseph Koshy 
2443f263522aSJoseph Koshy 	pmc_detach_args.pm_pmc = pmc;
2444f263522aSJoseph Koshy 	pmc_detach_args.pm_pid = pid;
2445aa342b1fSJoseph Koshy 	return (PMC_CALL(PMCDETACH, &pmc_detach_args));
2446ebccf1e3SJoseph Koshy }
2447ebccf1e3SJoseph Koshy 
2448f263522aSJoseph Koshy int
2449f263522aSJoseph Koshy pmc_disable(int cpu, int pmc)
2450ebccf1e3SJoseph Koshy {
2451f263522aSJoseph Koshy 	struct pmc_op_pmcadmin ssa;
2452ebccf1e3SJoseph Koshy 
2453f263522aSJoseph Koshy 	ssa.pm_cpu = cpu;
2454f263522aSJoseph Koshy 	ssa.pm_pmc = pmc;
2455f263522aSJoseph Koshy 	ssa.pm_state = PMC_STATE_DISABLED;
2456aa342b1fSJoseph Koshy 	return (PMC_CALL(PMCADMIN, &ssa));
2457ebccf1e3SJoseph Koshy }
2458ebccf1e3SJoseph Koshy 
2459f263522aSJoseph Koshy int
2460f263522aSJoseph Koshy pmc_enable(int cpu, int pmc)
2461ebccf1e3SJoseph Koshy {
2462f263522aSJoseph Koshy 	struct pmc_op_pmcadmin ssa;
2463ebccf1e3SJoseph Koshy 
2464f263522aSJoseph Koshy 	ssa.pm_cpu = cpu;
2465f263522aSJoseph Koshy 	ssa.pm_pmc = pmc;
2466f263522aSJoseph Koshy 	ssa.pm_state = PMC_STATE_FREE;
2467aa342b1fSJoseph Koshy 	return (PMC_CALL(PMCADMIN, &ssa));
2468ebccf1e3SJoseph Koshy }
2469ebccf1e3SJoseph Koshy 
2470ebccf1e3SJoseph Koshy /*
2471ebccf1e3SJoseph Koshy  * Return a list of events known to a given PMC class.  'cl' is the
2472ebccf1e3SJoseph Koshy  * PMC class identifier, 'eventnames' is the returned list of 'const
2473ebccf1e3SJoseph Koshy  * char *' pointers pointing to the names of the events. 'nevents' is
2474ebccf1e3SJoseph Koshy  * the number of event name pointers returned.
2475ebccf1e3SJoseph Koshy  *
2476ebccf1e3SJoseph Koshy  * The space for 'eventnames' is allocated using malloc(3).  The caller
2477ebccf1e3SJoseph Koshy  * is responsible for freeing this space when done.
2478ebccf1e3SJoseph Koshy  */
2479ebccf1e3SJoseph Koshy int
2480ebccf1e3SJoseph Koshy pmc_event_names_of_class(enum pmc_class cl, const char ***eventnames,
2481ebccf1e3SJoseph Koshy     int *nevents)
2482ebccf1e3SJoseph Koshy {
2483ebccf1e3SJoseph Koshy 	int count;
2484ebccf1e3SJoseph Koshy 	const char **names;
2485ebccf1e3SJoseph Koshy 	const struct pmc_event_descr *ev;
2486ebccf1e3SJoseph Koshy 
2487ebccf1e3SJoseph Koshy 	switch (cl)
2488ebccf1e3SJoseph Koshy 	{
24890cfab8ddSJoseph Koshy 	case PMC_CLASS_IAF:
24900cfab8ddSJoseph Koshy 		ev = iaf_event_table;
24910cfab8ddSJoseph Koshy 		count = PMC_EVENT_TABLE_SIZE(iaf);
24920cfab8ddSJoseph Koshy 		break;
24930cfab8ddSJoseph Koshy 	case PMC_CLASS_IAP:
24940cfab8ddSJoseph Koshy 		/*
24950cfab8ddSJoseph Koshy 		 * Return the most appropriate set of event name
24960cfab8ddSJoseph Koshy 		 * spellings for the current CPU.
24970cfab8ddSJoseph Koshy 		 */
24980cfab8ddSJoseph Koshy 		switch (cpu_info.pm_cputype) {
24990cfab8ddSJoseph Koshy 		default:
25000cfab8ddSJoseph Koshy 		case PMC_CPU_INTEL_ATOM:
25010cfab8ddSJoseph Koshy 			ev = atom_event_table;
25020cfab8ddSJoseph Koshy 			count = PMC_EVENT_TABLE_SIZE(atom);
25030cfab8ddSJoseph Koshy 			break;
25040cfab8ddSJoseph Koshy 		case PMC_CPU_INTEL_CORE:
25050cfab8ddSJoseph Koshy 			ev = core_event_table;
25060cfab8ddSJoseph Koshy 			count = PMC_EVENT_TABLE_SIZE(core);
25070cfab8ddSJoseph Koshy 			break;
25080cfab8ddSJoseph Koshy 		case PMC_CPU_INTEL_CORE2:
2509b4d091f3SJoseph Koshy 		case PMC_CPU_INTEL_CORE2EXTREME:
25100cfab8ddSJoseph Koshy 			ev = core2_event_table;
25110cfab8ddSJoseph Koshy 			count = PMC_EVENT_TABLE_SIZE(core2);
25120cfab8ddSJoseph Koshy 			break;
2513597979c4SJeff Roberson 		case PMC_CPU_INTEL_COREI7:
2514597979c4SJeff Roberson 			ev = corei7_event_table;
2515597979c4SJeff Roberson 			count = PMC_EVENT_TABLE_SIZE(corei7);
2516597979c4SJeff Roberson 			break;
25171fa7f10bSFabien Thomas 		case PMC_CPU_INTEL_WESTMERE:
25181fa7f10bSFabien Thomas 			ev = westmere_event_table;
25191fa7f10bSFabien Thomas 			count = PMC_EVENT_TABLE_SIZE(westmere);
25201fa7f10bSFabien Thomas 			break;
25211fa7f10bSFabien Thomas 		}
25221fa7f10bSFabien Thomas 		break;
25231fa7f10bSFabien Thomas 	case PMC_CLASS_UCF:
25241fa7f10bSFabien Thomas 		ev = ucf_event_table;
25251fa7f10bSFabien Thomas 		count = PMC_EVENT_TABLE_SIZE(ucf);
25261fa7f10bSFabien Thomas 		break;
25271fa7f10bSFabien Thomas 	case PMC_CLASS_UCP:
25281fa7f10bSFabien Thomas 		/*
25291fa7f10bSFabien Thomas 		 * Return the most appropriate set of event name
25301fa7f10bSFabien Thomas 		 * spellings for the current CPU.
25311fa7f10bSFabien Thomas 		 */
25321fa7f10bSFabien Thomas 		switch (cpu_info.pm_cputype) {
25331fa7f10bSFabien Thomas 		default:
25341fa7f10bSFabien Thomas 		case PMC_CPU_INTEL_COREI7:
25351fa7f10bSFabien Thomas 			ev = corei7uc_event_table;
25361fa7f10bSFabien Thomas 			count = PMC_EVENT_TABLE_SIZE(corei7uc);
25371fa7f10bSFabien Thomas 			break;
25381fa7f10bSFabien Thomas 		case PMC_CPU_INTEL_WESTMERE:
25391fa7f10bSFabien Thomas 			ev = westmereuc_event_table;
25401fa7f10bSFabien Thomas 			count = PMC_EVENT_TABLE_SIZE(westmereuc);
25411fa7f10bSFabien Thomas 			break;
25420cfab8ddSJoseph Koshy 		}
25430cfab8ddSJoseph Koshy 		break;
2544ebccf1e3SJoseph Koshy 	case PMC_CLASS_TSC:
2545789140c0SJoseph Koshy 		ev = tsc_event_table;
2546789140c0SJoseph Koshy 		count = PMC_EVENT_TABLE_SIZE(tsc);
2547ebccf1e3SJoseph Koshy 		break;
2548ebccf1e3SJoseph Koshy 	case PMC_CLASS_K7:
2549789140c0SJoseph Koshy 		ev = k7_event_table;
2550789140c0SJoseph Koshy 		count = PMC_EVENT_TABLE_SIZE(k7);
2551ebccf1e3SJoseph Koshy 		break;
2552ebccf1e3SJoseph Koshy 	case PMC_CLASS_K8:
2553789140c0SJoseph Koshy 		ev = k8_event_table;
2554789140c0SJoseph Koshy 		count = PMC_EVENT_TABLE_SIZE(k8);
2555ebccf1e3SJoseph Koshy 		break;
2556ebccf1e3SJoseph Koshy 	case PMC_CLASS_P4:
2557789140c0SJoseph Koshy 		ev = p4_event_table;
2558789140c0SJoseph Koshy 		count = PMC_EVENT_TABLE_SIZE(p4);
2559789140c0SJoseph Koshy 		break;
2560789140c0SJoseph Koshy 	case PMC_CLASS_P5:
2561789140c0SJoseph Koshy 		ev = p5_event_table;
2562789140c0SJoseph Koshy 		count = PMC_EVENT_TABLE_SIZE(p5);
2563789140c0SJoseph Koshy 		break;
2564789140c0SJoseph Koshy 	case PMC_CLASS_P6:
2565789140c0SJoseph Koshy 		ev = p6_event_table;
2566789140c0SJoseph Koshy 		count = PMC_EVENT_TABLE_SIZE(p6);
2567ebccf1e3SJoseph Koshy 		break;
25680ce207d2SRui Paulo 	case PMC_CLASS_XSCALE:
25690ce207d2SRui Paulo 		ev = xscale_event_table;
25700ce207d2SRui Paulo 		count = PMC_EVENT_TABLE_SIZE(xscale);
25710ce207d2SRui Paulo 		break;
2572660df75eSGeorge V. Neville-Neil 	case PMC_CLASS_MIPS24K:
2573660df75eSGeorge V. Neville-Neil 		ev = mips24k_event_table;
2574660df75eSGeorge V. Neville-Neil 		count = PMC_EVENT_TABLE_SIZE(mips24k);
2575660df75eSGeorge V. Neville-Neil 		break;
2576ebccf1e3SJoseph Koshy 	default:
2577ebccf1e3SJoseph Koshy 		errno = EINVAL;
2578aa342b1fSJoseph Koshy 		return (-1);
2579ebccf1e3SJoseph Koshy 	}
2580ebccf1e3SJoseph Koshy 
2581ebccf1e3SJoseph Koshy 	if ((names = malloc(count * sizeof(const char *))) == NULL)
2582aa342b1fSJoseph Koshy 		return (-1);
2583ebccf1e3SJoseph Koshy 
2584ebccf1e3SJoseph Koshy 	*eventnames = names;
2585ebccf1e3SJoseph Koshy 	*nevents = count;
2586ebccf1e3SJoseph Koshy 
2587ebccf1e3SJoseph Koshy 	for (;count--; ev++, names++)
2588ebccf1e3SJoseph Koshy 		*names = ev->pm_ev_name;
2589aa342b1fSJoseph Koshy 	return (0);
2590ebccf1e3SJoseph Koshy }
2591ebccf1e3SJoseph Koshy 
2592f263522aSJoseph Koshy int
2593f263522aSJoseph Koshy pmc_flush_logfile(void)
2594f263522aSJoseph Koshy {
2595aa342b1fSJoseph Koshy 	return (PMC_CALL(FLUSHLOG,0));
2596f263522aSJoseph Koshy }
2597ebccf1e3SJoseph Koshy 
2598ebccf1e3SJoseph Koshy int
2599dceed24aSFabien Thomas pmc_close_logfile(void)
2600dceed24aSFabien Thomas {
2601dceed24aSFabien Thomas 	return (PMC_CALL(CLOSELOG,0));
2602dceed24aSFabien Thomas }
2603dceed24aSFabien Thomas 
2604dceed24aSFabien Thomas int
2605f263522aSJoseph Koshy pmc_get_driver_stats(struct pmc_driverstats *ds)
2606ebccf1e3SJoseph Koshy {
2607f263522aSJoseph Koshy 	struct pmc_op_getdriverstats gms;
2608f263522aSJoseph Koshy 
2609f263522aSJoseph Koshy 	if (PMC_CALL(GETDRIVERSTATS, &gms) < 0)
2610aa342b1fSJoseph Koshy 		return (-1);
2611f263522aSJoseph Koshy 
2612f263522aSJoseph Koshy 	/* copy out fields in the current userland<->library interface */
2613f263522aSJoseph Koshy 	ds->pm_intr_ignored    = gms.pm_intr_ignored;
2614f263522aSJoseph Koshy 	ds->pm_intr_processed  = gms.pm_intr_processed;
2615f263522aSJoseph Koshy 	ds->pm_intr_bufferfull = gms.pm_intr_bufferfull;
2616f263522aSJoseph Koshy 	ds->pm_syscalls        = gms.pm_syscalls;
2617f263522aSJoseph Koshy 	ds->pm_syscall_errors  = gms.pm_syscall_errors;
2618f263522aSJoseph Koshy 	ds->pm_buffer_requests = gms.pm_buffer_requests;
2619f263522aSJoseph Koshy 	ds->pm_buffer_requests_failed = gms.pm_buffer_requests_failed;
2620f263522aSJoseph Koshy 	ds->pm_log_sweeps      = gms.pm_log_sweeps;
2621aa342b1fSJoseph Koshy 	return (0);
2622f263522aSJoseph Koshy }
2623f263522aSJoseph Koshy 
2624f263522aSJoseph Koshy int
2625f263522aSJoseph Koshy pmc_get_msr(pmc_id_t pmc, uint32_t *msr)
2626f263522aSJoseph Koshy {
2627f263522aSJoseph Koshy 	struct pmc_op_getmsr gm;
2628ebccf1e3SJoseph Koshy 
2629ebccf1e3SJoseph Koshy 	gm.pm_pmcid = pmc;
2630f263522aSJoseph Koshy 	if (PMC_CALL(PMCGETMSR, &gm) < 0)
2631aa342b1fSJoseph Koshy 		return (-1);
2632ebccf1e3SJoseph Koshy 	*msr = gm.pm_msr;
2633aa342b1fSJoseph Koshy 	return (0);
2634ebccf1e3SJoseph Koshy }
2635ebccf1e3SJoseph Koshy 
2636f263522aSJoseph Koshy int
2637f263522aSJoseph Koshy pmc_init(void)
2638f263522aSJoseph Koshy {
2639f263522aSJoseph Koshy 	int error, pmc_mod_id;
26401455fcd3SJoseph Koshy 	unsigned int n;
2641f263522aSJoseph Koshy 	uint32_t abi_version;
2642f263522aSJoseph Koshy 	struct module_stat pmc_modstat;
26431455fcd3SJoseph Koshy 	struct pmc_op_getcpuinfo op_cpu_info;
2644791f5d5bSJoseph Koshy #if defined(__amd64__) || defined(__i386__)
2645791f5d5bSJoseph Koshy 	int cpu_has_iaf_counters;
2646791f5d5bSJoseph Koshy 	unsigned int t;
2647791f5d5bSJoseph Koshy #endif
2648f263522aSJoseph Koshy 
2649f263522aSJoseph Koshy 	if (pmc_syscall != -1) /* already inited */
2650aa342b1fSJoseph Koshy 		return (0);
2651f263522aSJoseph Koshy 
2652f263522aSJoseph Koshy 	/* retrieve the system call number from the KLD */
2653f263522aSJoseph Koshy 	if ((pmc_mod_id = modfind(PMC_MODULE_NAME)) < 0)
2654aa342b1fSJoseph Koshy 		return (-1);
2655f263522aSJoseph Koshy 
2656f263522aSJoseph Koshy 	pmc_modstat.version = sizeof(struct module_stat);
2657f263522aSJoseph Koshy 	if ((error = modstat(pmc_mod_id, &pmc_modstat)) < 0)
2658aa342b1fSJoseph Koshy 		return (-1);
2659f263522aSJoseph Koshy 
2660f263522aSJoseph Koshy 	pmc_syscall = pmc_modstat.data.intval;
2661f263522aSJoseph Koshy 
2662f263522aSJoseph Koshy 	/* check the kernel module's ABI against our compiled-in version */
2663f263522aSJoseph Koshy 	abi_version = PMC_VERSION;
2664f263522aSJoseph Koshy 	if (PMC_CALL(GETMODULEVERSION, &abi_version) < 0)
2665f263522aSJoseph Koshy 		return (pmc_syscall = -1);
2666f263522aSJoseph Koshy 
2667f263522aSJoseph Koshy 	/* ignore patch & minor numbers for the comparision */
2668f263522aSJoseph Koshy 	if ((abi_version & 0xFF000000) != (PMC_VERSION & 0xFF000000)) {
2669f263522aSJoseph Koshy 		errno  = EPROGMISMATCH;
2670f263522aSJoseph Koshy 		return (pmc_syscall = -1);
2671f263522aSJoseph Koshy 	}
2672f263522aSJoseph Koshy 
26731455fcd3SJoseph Koshy 	if (PMC_CALL(GETCPUINFO, &op_cpu_info) < 0)
2674f263522aSJoseph Koshy 		return (pmc_syscall = -1);
2675f263522aSJoseph Koshy 
26761455fcd3SJoseph Koshy 	cpu_info.pm_cputype = op_cpu_info.pm_cputype;
26771455fcd3SJoseph Koshy 	cpu_info.pm_ncpu    = op_cpu_info.pm_ncpu;
26781455fcd3SJoseph Koshy 	cpu_info.pm_npmc    = op_cpu_info.pm_npmc;
26791455fcd3SJoseph Koshy 	cpu_info.pm_nclass  = op_cpu_info.pm_nclass;
26801455fcd3SJoseph Koshy 	for (n = 0; n < cpu_info.pm_nclass; n++)
26811455fcd3SJoseph Koshy 		cpu_info.pm_classes[n] = op_cpu_info.pm_classes[n];
26821455fcd3SJoseph Koshy 
26830cfab8ddSJoseph Koshy 	pmc_class_table = malloc(PMC_CLASS_TABLE_SIZE *
26840cfab8ddSJoseph Koshy 	    sizeof(struct pmc_class_descr *));
26850cfab8ddSJoseph Koshy 
26860cfab8ddSJoseph Koshy 	if (pmc_class_table == NULL)
26870cfab8ddSJoseph Koshy 		return (-1);
26880cfab8ddSJoseph Koshy 
2689791f5d5bSJoseph Koshy 	for (n = 0; n < PMC_CLASS_TABLE_SIZE; n++)
2690791f5d5bSJoseph Koshy 		pmc_class_table[n] = NULL;
26910cfab8ddSJoseph Koshy 
26920cfab8ddSJoseph Koshy 	/*
26930cfab8ddSJoseph Koshy 	 * Fill in the class table.
26940cfab8ddSJoseph Koshy 	 */
26950cfab8ddSJoseph Koshy 	n = 0;
26960cfab8ddSJoseph Koshy #if defined(__amd64__) || defined(__i386__)
26970cfab8ddSJoseph Koshy 	pmc_class_table[n++] = &tsc_class_table_descr;
2698791f5d5bSJoseph Koshy 
2699791f5d5bSJoseph Koshy 	/*
2700791f5d5bSJoseph Koshy  	 * Check if this CPU has fixed function counters.
2701791f5d5bSJoseph Koshy 	 */
2702791f5d5bSJoseph Koshy 	cpu_has_iaf_counters = 0;
2703791f5d5bSJoseph Koshy 	for (t = 0; t < cpu_info.pm_nclass; t++)
27042aef9dd6SFabien Thomas 		if (cpu_info.pm_classes[t].pm_class == PMC_CLASS_IAF &&
27052aef9dd6SFabien Thomas 		    cpu_info.pm_classes[t].pm_num > 0)
2706791f5d5bSJoseph Koshy 			cpu_has_iaf_counters = 1;
27070cfab8ddSJoseph Koshy #endif
27080cfab8ddSJoseph Koshy 
2709789140c0SJoseph Koshy #define	PMC_MDEP_INIT(C) do {					\
2710789140c0SJoseph Koshy 		pmc_mdep_event_aliases    = C##_aliases;	\
2711789140c0SJoseph Koshy 		pmc_mdep_class_list  = C##_pmc_classes;		\
2712789140c0SJoseph Koshy 		pmc_mdep_class_list_size =			\
2713789140c0SJoseph Koshy 		    PMC_TABLE_SIZE(C##_pmc_classes);		\
2714789140c0SJoseph Koshy 	} while (0)
2715789140c0SJoseph Koshy 
2716791f5d5bSJoseph Koshy #define	PMC_MDEP_INIT_INTEL_V2(C) do {					\
2717791f5d5bSJoseph Koshy 		PMC_MDEP_INIT(C);					\
2718791f5d5bSJoseph Koshy 		pmc_class_table[n++] = &iaf_class_table_descr;		\
27192aef9dd6SFabien Thomas 		if (!cpu_has_iaf_counters) 				\
2720791f5d5bSJoseph Koshy 			pmc_mdep_event_aliases =			\
2721791f5d5bSJoseph Koshy 				C##_aliases_without_iaf;		\
2722791f5d5bSJoseph Koshy 		pmc_class_table[n] = &C##_class_table_descr;		\
2723791f5d5bSJoseph Koshy 	} while (0)
2724791f5d5bSJoseph Koshy 
2725789140c0SJoseph Koshy 	/* Configure the event name parser. */
2726f263522aSJoseph Koshy 	switch (cpu_info.pm_cputype) {
2727f263522aSJoseph Koshy #if defined(__i386__)
2728f263522aSJoseph Koshy 	case PMC_CPU_AMD_K7:
2729789140c0SJoseph Koshy 		PMC_MDEP_INIT(k7);
27300cfab8ddSJoseph Koshy 		pmc_class_table[n] = &k7_class_table_descr;
2731f263522aSJoseph Koshy 		break;
2732f263522aSJoseph Koshy 	case PMC_CPU_INTEL_P5:
2733789140c0SJoseph Koshy 		PMC_MDEP_INIT(p5);
27340cfab8ddSJoseph Koshy 		pmc_class_table[n]  = &p5_class_table_descr;
2735f263522aSJoseph Koshy 		break;
2736f263522aSJoseph Koshy 	case PMC_CPU_INTEL_P6:		/* P6 ... Pentium M CPUs have */
2737f263522aSJoseph Koshy 	case PMC_CPU_INTEL_PII:		/* similar PMCs. */
2738f263522aSJoseph Koshy 	case PMC_CPU_INTEL_PIII:
2739f263522aSJoseph Koshy 	case PMC_CPU_INTEL_PM:
2740789140c0SJoseph Koshy 		PMC_MDEP_INIT(p6);
27410cfab8ddSJoseph Koshy 		pmc_class_table[n] = &p6_class_table_descr;
2742f263522aSJoseph Koshy 		break;
274386a65549SJoseph Koshy #endif
274486a65549SJoseph Koshy #if defined(__amd64__) || defined(__i386__)
2745f263522aSJoseph Koshy 	case PMC_CPU_AMD_K8:
2746789140c0SJoseph Koshy 		PMC_MDEP_INIT(k8);
27470cfab8ddSJoseph Koshy 		pmc_class_table[n] = &k8_class_table_descr;
27480cfab8ddSJoseph Koshy 		break;
27490cfab8ddSJoseph Koshy 	case PMC_CPU_INTEL_ATOM:
2750791f5d5bSJoseph Koshy 		PMC_MDEP_INIT_INTEL_V2(atom);
27510cfab8ddSJoseph Koshy 		break;
27520cfab8ddSJoseph Koshy 	case PMC_CPU_INTEL_CORE:
27530cfab8ddSJoseph Koshy 		PMC_MDEP_INIT(core);
2754bc315bbdSJoseph Koshy 		pmc_class_table[n] = &core_class_table_descr;
27550cfab8ddSJoseph Koshy 		break;
27560cfab8ddSJoseph Koshy 	case PMC_CPU_INTEL_CORE2:
2757b4d091f3SJoseph Koshy 	case PMC_CPU_INTEL_CORE2EXTREME:
2758791f5d5bSJoseph Koshy 		PMC_MDEP_INIT_INTEL_V2(core2);
2759789140c0SJoseph Koshy 		break;
2760597979c4SJeff Roberson 	case PMC_CPU_INTEL_COREI7:
27611fa7f10bSFabien Thomas 		pmc_class_table[n++] = &ucf_class_table_descr;
27621fa7f10bSFabien Thomas 		pmc_class_table[n++] = &corei7uc_class_table_descr;
2763791f5d5bSJoseph Koshy 		PMC_MDEP_INIT_INTEL_V2(corei7);
2764597979c4SJeff Roberson 		break;
27651fa7f10bSFabien Thomas 	case PMC_CPU_INTEL_WESTMERE:
27661fa7f10bSFabien Thomas 		pmc_class_table[n++] = &ucf_class_table_descr;
27671fa7f10bSFabien Thomas 		pmc_class_table[n++] = &westmereuc_class_table_descr;
27681fa7f10bSFabien Thomas 		PMC_MDEP_INIT_INTEL_V2(westmere);
27691fa7f10bSFabien Thomas 		break;
2770789140c0SJoseph Koshy 	case PMC_CPU_INTEL_PIV:
2771789140c0SJoseph Koshy 		PMC_MDEP_INIT(p4);
27720cfab8ddSJoseph Koshy 		pmc_class_table[n] = &p4_class_table_descr;
2773f263522aSJoseph Koshy 		break;
2774ebccf1e3SJoseph Koshy #endif
27750ce207d2SRui Paulo #if defined(__XSCALE__)
27760ce207d2SRui Paulo 	case PMC_CPU_INTEL_XSCALE:
27770ce207d2SRui Paulo 		PMC_MDEP_INIT(xscale);
27780ce207d2SRui Paulo 		pmc_class_table[n] = &xscale_class_table_descr;
27790ce207d2SRui Paulo 		break;
27800ce207d2SRui Paulo #endif
2781660df75eSGeorge V. Neville-Neil #if defined(__mips__)
2782660df75eSGeorge V. Neville-Neil 	case PMC_CPU_MIPS_24K:
2783660df75eSGeorge V. Neville-Neil 		PMC_MDEP_INIT(mips24k);
2784660df75eSGeorge V. Neville-Neil 		pmc_class_table[n] = &mips24k_class_table_descr;
2785660df75eSGeorge V. Neville-Neil 		break;
2786660df75eSGeorge V. Neville-Neil #endif /* __mips__ */
2787f263522aSJoseph Koshy 	default:
2788f263522aSJoseph Koshy 		/*
2789f263522aSJoseph Koshy 		 * Some kind of CPU this version of the library knows nothing
2790f263522aSJoseph Koshy 		 * about.  This shouldn't happen since the abi version check
2791f263522aSJoseph Koshy 		 * should have caught this.
2792f263522aSJoseph Koshy 		 */
2793f263522aSJoseph Koshy 		errno = ENXIO;
2794f263522aSJoseph Koshy 		return (pmc_syscall = -1);
2795f263522aSJoseph Koshy 	}
2796f263522aSJoseph Koshy 
2797aa342b1fSJoseph Koshy 	return (0);
2798f263522aSJoseph Koshy }
2799f263522aSJoseph Koshy 
2800f263522aSJoseph Koshy const char *
2801f263522aSJoseph Koshy pmc_name_of_capability(enum pmc_caps cap)
2802f263522aSJoseph Koshy {
2803f263522aSJoseph Koshy 	int i;
2804f263522aSJoseph Koshy 
2805f263522aSJoseph Koshy 	/*
2806f263522aSJoseph Koshy 	 * 'cap' should have a single bit set and should be in
2807f263522aSJoseph Koshy 	 * range.
2808f263522aSJoseph Koshy 	 */
2809f263522aSJoseph Koshy 	if ((cap & (cap - 1)) || cap < PMC_CAP_FIRST ||
2810f263522aSJoseph Koshy 	    cap > PMC_CAP_LAST) {
2811f263522aSJoseph Koshy 		errno = EINVAL;
2812aa342b1fSJoseph Koshy 		return (NULL);
2813f263522aSJoseph Koshy 	}
2814f263522aSJoseph Koshy 
2815f263522aSJoseph Koshy 	i = ffs(cap);
2816aa342b1fSJoseph Koshy 	return (pmc_capability_names[i - 1]);
2817f263522aSJoseph Koshy }
2818f263522aSJoseph Koshy 
2819f263522aSJoseph Koshy const char *
2820f263522aSJoseph Koshy pmc_name_of_class(enum pmc_class pc)
2821f263522aSJoseph Koshy {
2822f263522aSJoseph Koshy 	if ((int) pc >= PMC_CLASS_FIRST &&
2823f263522aSJoseph Koshy 	    pc <= PMC_CLASS_LAST)
2824aa342b1fSJoseph Koshy 		return (pmc_class_names[pc]);
2825f263522aSJoseph Koshy 
2826f263522aSJoseph Koshy 	errno = EINVAL;
2827aa342b1fSJoseph Koshy 	return (NULL);
2828f263522aSJoseph Koshy }
2829f263522aSJoseph Koshy 
2830f263522aSJoseph Koshy const char *
2831f263522aSJoseph Koshy pmc_name_of_cputype(enum pmc_cputype cp)
2832f263522aSJoseph Koshy {
2833789140c0SJoseph Koshy 	size_t n;
2834789140c0SJoseph Koshy 
2835789140c0SJoseph Koshy 	for (n = 0; n < PMC_TABLE_SIZE(pmc_cputype_names); n++)
2836789140c0SJoseph Koshy 		if (cp == pmc_cputype_names[n].pm_cputype)
2837789140c0SJoseph Koshy 			return (pmc_cputype_names[n].pm_name);
2838789140c0SJoseph Koshy 
2839f263522aSJoseph Koshy 	errno = EINVAL;
2840aa342b1fSJoseph Koshy 	return (NULL);
2841f263522aSJoseph Koshy }
2842f263522aSJoseph Koshy 
2843f263522aSJoseph Koshy const char *
2844f263522aSJoseph Koshy pmc_name_of_disposition(enum pmc_disp pd)
2845f263522aSJoseph Koshy {
2846f263522aSJoseph Koshy 	if ((int) pd >= PMC_DISP_FIRST &&
2847f263522aSJoseph Koshy 	    pd <= PMC_DISP_LAST)
2848aa342b1fSJoseph Koshy 		return (pmc_disposition_names[pd]);
2849f263522aSJoseph Koshy 
2850f263522aSJoseph Koshy 	errno = EINVAL;
2851aa342b1fSJoseph Koshy 	return (NULL);
2852f263522aSJoseph Koshy }
2853f263522aSJoseph Koshy 
2854f263522aSJoseph Koshy const char *
28550cfab8ddSJoseph Koshy _pmc_name_of_event(enum pmc_event pe, enum pmc_cputype cpu)
2856f263522aSJoseph Koshy {
2857789140c0SJoseph Koshy 	const struct pmc_event_descr *ev, *evfence;
2858789140c0SJoseph Koshy 
2859789140c0SJoseph Koshy 	ev = evfence = NULL;
28600cfab8ddSJoseph Koshy 	if (pe >= PMC_EV_IAF_FIRST && pe <= PMC_EV_IAF_LAST) {
28610cfab8ddSJoseph Koshy 		ev = iaf_event_table;
28620cfab8ddSJoseph Koshy 		evfence = iaf_event_table + PMC_EVENT_TABLE_SIZE(iaf);
28630cfab8ddSJoseph Koshy 	} else if (pe >= PMC_EV_IAP_FIRST && pe <= PMC_EV_IAP_LAST) {
28640cfab8ddSJoseph Koshy 		switch (cpu) {
28650cfab8ddSJoseph Koshy 		case PMC_CPU_INTEL_ATOM:
28660cfab8ddSJoseph Koshy 			ev = atom_event_table;
28670cfab8ddSJoseph Koshy 			evfence = atom_event_table + PMC_EVENT_TABLE_SIZE(atom);
28680cfab8ddSJoseph Koshy 			break;
28690cfab8ddSJoseph Koshy 		case PMC_CPU_INTEL_CORE:
28700cfab8ddSJoseph Koshy 			ev = core_event_table;
28710cfab8ddSJoseph Koshy 			evfence = core_event_table + PMC_EVENT_TABLE_SIZE(core);
28720cfab8ddSJoseph Koshy 			break;
28730cfab8ddSJoseph Koshy 		case PMC_CPU_INTEL_CORE2:
2874b4d091f3SJoseph Koshy 		case PMC_CPU_INTEL_CORE2EXTREME:
28750cfab8ddSJoseph Koshy 			ev = core2_event_table;
28760cfab8ddSJoseph Koshy 			evfence = core2_event_table + PMC_EVENT_TABLE_SIZE(core2);
28770cfab8ddSJoseph Koshy 			break;
2878597979c4SJeff Roberson 		case PMC_CPU_INTEL_COREI7:
2879597979c4SJeff Roberson 			ev = corei7_event_table;
2880597979c4SJeff Roberson 			evfence = corei7_event_table + PMC_EVENT_TABLE_SIZE(corei7);
2881597979c4SJeff Roberson 			break;
28821fa7f10bSFabien Thomas 		case PMC_CPU_INTEL_WESTMERE:
28831fa7f10bSFabien Thomas 			ev = westmere_event_table;
28841fa7f10bSFabien Thomas 			evfence = westmere_event_table + PMC_EVENT_TABLE_SIZE(westmere);
28851fa7f10bSFabien Thomas 			break;
28860cfab8ddSJoseph Koshy 		default:	/* Unknown CPU type. */
28870cfab8ddSJoseph Koshy 			break;
28880cfab8ddSJoseph Koshy 		}
28891fa7f10bSFabien Thomas 	} else if (pe >= PMC_EV_UCF_FIRST && pe <= PMC_EV_UCF_LAST) {
28901fa7f10bSFabien Thomas 		ev = ucf_event_table;
28911fa7f10bSFabien Thomas 		evfence = ucf_event_table + PMC_EVENT_TABLE_SIZE(ucf);
28921fa7f10bSFabien Thomas 	} else if (pe >= PMC_EV_UCP_FIRST && pe <= PMC_EV_UCP_LAST) {
28931fa7f10bSFabien Thomas 		switch (cpu) {
28941fa7f10bSFabien Thomas 		case PMC_CPU_INTEL_COREI7:
28951fa7f10bSFabien Thomas 			ev = corei7uc_event_table;
28961fa7f10bSFabien Thomas 			evfence = corei7uc_event_table + PMC_EVENT_TABLE_SIZE(corei7uc);
28971fa7f10bSFabien Thomas 			break;
28981fa7f10bSFabien Thomas 		case PMC_CPU_INTEL_WESTMERE:
28991fa7f10bSFabien Thomas 			ev = westmereuc_event_table;
29001fa7f10bSFabien Thomas 			evfence = westmereuc_event_table + PMC_EVENT_TABLE_SIZE(westmereuc);
29011fa7f10bSFabien Thomas 			break;
29021fa7f10bSFabien Thomas 		default:	/* Unknown CPU type. */
29031fa7f10bSFabien Thomas 			break;
29041fa7f10bSFabien Thomas 		}
29051fa7f10bSFabien Thomas 	} else if (pe >= PMC_EV_K7_FIRST && pe <= PMC_EV_K7_LAST) {
2906789140c0SJoseph Koshy 		ev = k7_event_table;
2907789140c0SJoseph Koshy 		evfence = k7_event_table + PMC_EVENT_TABLE_SIZE(k7);
2908789140c0SJoseph Koshy 	} else if (pe >= PMC_EV_K8_FIRST && pe <= PMC_EV_K8_LAST) {
2909789140c0SJoseph Koshy 		ev = k8_event_table;
2910789140c0SJoseph Koshy 		evfence = k8_event_table + PMC_EVENT_TABLE_SIZE(k8);
2911789140c0SJoseph Koshy 	} else if (pe >= PMC_EV_P4_FIRST && pe <= PMC_EV_P4_LAST) {
2912789140c0SJoseph Koshy 		ev = p4_event_table;
2913789140c0SJoseph Koshy 		evfence = p4_event_table + PMC_EVENT_TABLE_SIZE(p4);
2914789140c0SJoseph Koshy 	} else if (pe >= PMC_EV_P5_FIRST && pe <= PMC_EV_P5_LAST) {
2915789140c0SJoseph Koshy 		ev = p5_event_table;
2916789140c0SJoseph Koshy 		evfence = p5_event_table + PMC_EVENT_TABLE_SIZE(p5);
2917789140c0SJoseph Koshy 	} else if (pe >= PMC_EV_P6_FIRST && pe <= PMC_EV_P6_LAST) {
2918789140c0SJoseph Koshy 		ev = p6_event_table;
2919789140c0SJoseph Koshy 		evfence = p6_event_table + PMC_EVENT_TABLE_SIZE(p6);
29200ce207d2SRui Paulo 	} else if (pe >= PMC_EV_XSCALE_FIRST && pe <= PMC_EV_XSCALE_LAST) {
29210ce207d2SRui Paulo 		ev = xscale_event_table;
29220ce207d2SRui Paulo 		evfence = xscale_event_table + PMC_EVENT_TABLE_SIZE(xscale);
2923660df75eSGeorge V. Neville-Neil 	} else if (pe >= PMC_EV_MIPS24K_FIRST && pe <= PMC_EV_MIPS24K_LAST) {
2924660df75eSGeorge V. Neville-Neil 		ev = mips24k_event_table;
2925660df75eSGeorge V. Neville-Neil 		evfence = mips24k_event_table + PMC_EVENT_TABLE_SIZE(mips24k
2926660df75eSGeorge V. Neville-Neil );
2927789140c0SJoseph Koshy 	} else if (pe == PMC_EV_TSC_TSC) {
2928789140c0SJoseph Koshy 		ev = tsc_event_table;
2929789140c0SJoseph Koshy 		evfence = tsc_event_table + PMC_EVENT_TABLE_SIZE(tsc);
2930789140c0SJoseph Koshy 	}
2931789140c0SJoseph Koshy 
2932789140c0SJoseph Koshy 	for (; ev != evfence; ev++)
2933789140c0SJoseph Koshy 		if (pe == ev->pm_ev_code)
2934789140c0SJoseph Koshy 			return (ev->pm_ev_name);
2935f263522aSJoseph Koshy 
29360cfab8ddSJoseph Koshy 	return (NULL);
29370cfab8ddSJoseph Koshy }
29380cfab8ddSJoseph Koshy 
29390cfab8ddSJoseph Koshy const char *
29400cfab8ddSJoseph Koshy pmc_name_of_event(enum pmc_event pe)
29410cfab8ddSJoseph Koshy {
29420cfab8ddSJoseph Koshy 	const char *n;
29430cfab8ddSJoseph Koshy 
29440cfab8ddSJoseph Koshy 	if ((n = _pmc_name_of_event(pe, cpu_info.pm_cputype)) != NULL)
29450cfab8ddSJoseph Koshy 		return (n);
29460cfab8ddSJoseph Koshy 
2947f263522aSJoseph Koshy 	errno = EINVAL;
2948aa342b1fSJoseph Koshy 	return (NULL);
2949f263522aSJoseph Koshy }
2950f263522aSJoseph Koshy 
2951f263522aSJoseph Koshy const char *
2952f263522aSJoseph Koshy pmc_name_of_mode(enum pmc_mode pm)
2953f263522aSJoseph Koshy {
2954f263522aSJoseph Koshy 	if ((int) pm >= PMC_MODE_FIRST &&
2955f263522aSJoseph Koshy 	    pm <= PMC_MODE_LAST)
2956aa342b1fSJoseph Koshy 		return (pmc_mode_names[pm]);
2957f263522aSJoseph Koshy 
2958f263522aSJoseph Koshy 	errno = EINVAL;
2959aa342b1fSJoseph Koshy 	return (NULL);
2960f263522aSJoseph Koshy }
2961f263522aSJoseph Koshy 
2962f263522aSJoseph Koshy const char *
2963f263522aSJoseph Koshy pmc_name_of_state(enum pmc_state ps)
2964f263522aSJoseph Koshy {
2965f263522aSJoseph Koshy 	if ((int) ps >= PMC_STATE_FIRST &&
2966f263522aSJoseph Koshy 	    ps <= PMC_STATE_LAST)
2967aa342b1fSJoseph Koshy 		return (pmc_state_names[ps]);
2968f263522aSJoseph Koshy 
2969f263522aSJoseph Koshy 	errno = EINVAL;
2970aa342b1fSJoseph Koshy 	return (NULL);
2971f263522aSJoseph Koshy }
2972f263522aSJoseph Koshy 
2973f263522aSJoseph Koshy int
2974f263522aSJoseph Koshy pmc_ncpu(void)
2975f263522aSJoseph Koshy {
2976f263522aSJoseph Koshy 	if (pmc_syscall == -1) {
2977f263522aSJoseph Koshy 		errno = ENXIO;
2978aa342b1fSJoseph Koshy 		return (-1);
2979f263522aSJoseph Koshy 	}
2980f263522aSJoseph Koshy 
2981aa342b1fSJoseph Koshy 	return (cpu_info.pm_ncpu);
2982f263522aSJoseph Koshy }
2983f263522aSJoseph Koshy 
2984f263522aSJoseph Koshy int
2985f263522aSJoseph Koshy pmc_npmc(int cpu)
2986f263522aSJoseph Koshy {
2987f263522aSJoseph Koshy 	if (pmc_syscall == -1) {
2988f263522aSJoseph Koshy 		errno = ENXIO;
2989aa342b1fSJoseph Koshy 		return (-1);
2990f263522aSJoseph Koshy 	}
2991f263522aSJoseph Koshy 
2992f263522aSJoseph Koshy 	if (cpu < 0 || cpu >= (int) cpu_info.pm_ncpu) {
2993f263522aSJoseph Koshy 		errno = EINVAL;
2994aa342b1fSJoseph Koshy 		return (-1);
2995f263522aSJoseph Koshy 	}
2996f263522aSJoseph Koshy 
2997aa342b1fSJoseph Koshy 	return (cpu_info.pm_npmc);
2998f263522aSJoseph Koshy }
2999f263522aSJoseph Koshy 
3000f263522aSJoseph Koshy int
3001f263522aSJoseph Koshy pmc_pmcinfo(int cpu, struct pmc_pmcinfo **ppmci)
3002f263522aSJoseph Koshy {
3003f263522aSJoseph Koshy 	int nbytes, npmc;
3004f263522aSJoseph Koshy 	struct pmc_op_getpmcinfo *pmci;
3005f263522aSJoseph Koshy 
3006f263522aSJoseph Koshy 	if ((npmc = pmc_npmc(cpu)) < 0)
3007aa342b1fSJoseph Koshy 		return (-1);
3008f263522aSJoseph Koshy 
3009f263522aSJoseph Koshy 	nbytes = sizeof(struct pmc_op_getpmcinfo) +
3010f263522aSJoseph Koshy 	    npmc * sizeof(struct pmc_info);
3011f263522aSJoseph Koshy 
3012f263522aSJoseph Koshy 	if ((pmci = calloc(1, nbytes)) == NULL)
3013aa342b1fSJoseph Koshy 		return (-1);
3014f263522aSJoseph Koshy 
3015f263522aSJoseph Koshy 	pmci->pm_cpu  = cpu;
3016f263522aSJoseph Koshy 
3017f263522aSJoseph Koshy 	if (PMC_CALL(GETPMCINFO, pmci) < 0) {
3018f263522aSJoseph Koshy 		free(pmci);
3019aa342b1fSJoseph Koshy 		return (-1);
3020f263522aSJoseph Koshy 	}
3021f263522aSJoseph Koshy 
3022f263522aSJoseph Koshy 	/* kernel<->library, library<->userland interfaces are identical */
3023f263522aSJoseph Koshy 	*ppmci = (struct pmc_pmcinfo *) pmci;
3024aa342b1fSJoseph Koshy 	return (0);
3025f263522aSJoseph Koshy }
3026f263522aSJoseph Koshy 
3027f263522aSJoseph Koshy int
3028f263522aSJoseph Koshy pmc_read(pmc_id_t pmc, pmc_value_t *value)
3029f263522aSJoseph Koshy {
3030f263522aSJoseph Koshy 	struct pmc_op_pmcrw pmc_read_op;
3031f263522aSJoseph Koshy 
3032f263522aSJoseph Koshy 	pmc_read_op.pm_pmcid = pmc;
3033f263522aSJoseph Koshy 	pmc_read_op.pm_flags = PMC_F_OLDVALUE;
3034f263522aSJoseph Koshy 	pmc_read_op.pm_value = -1;
3035f263522aSJoseph Koshy 
3036f263522aSJoseph Koshy 	if (PMC_CALL(PMCRW, &pmc_read_op) < 0)
3037aa342b1fSJoseph Koshy 		return (-1);
3038f263522aSJoseph Koshy 
3039f263522aSJoseph Koshy 	*value = pmc_read_op.pm_value;
3040aa342b1fSJoseph Koshy 	return (0);
3041f263522aSJoseph Koshy }
3042f263522aSJoseph Koshy 
3043f263522aSJoseph Koshy int
3044f263522aSJoseph Koshy pmc_release(pmc_id_t pmc)
3045f263522aSJoseph Koshy {
3046f263522aSJoseph Koshy 	struct pmc_op_simple	pmc_release_args;
3047f263522aSJoseph Koshy 
3048f263522aSJoseph Koshy 	pmc_release_args.pm_pmcid = pmc;
3049aa342b1fSJoseph Koshy 	return (PMC_CALL(PMCRELEASE, &pmc_release_args));
3050f263522aSJoseph Koshy }
3051f263522aSJoseph Koshy 
3052f263522aSJoseph Koshy int
3053f263522aSJoseph Koshy pmc_rw(pmc_id_t pmc, pmc_value_t newvalue, pmc_value_t *oldvaluep)
3054f263522aSJoseph Koshy {
3055f263522aSJoseph Koshy 	struct pmc_op_pmcrw pmc_rw_op;
3056f263522aSJoseph Koshy 
3057f263522aSJoseph Koshy 	pmc_rw_op.pm_pmcid = pmc;
3058f263522aSJoseph Koshy 	pmc_rw_op.pm_flags = PMC_F_NEWVALUE | PMC_F_OLDVALUE;
3059f263522aSJoseph Koshy 	pmc_rw_op.pm_value = newvalue;
3060f263522aSJoseph Koshy 
3061f263522aSJoseph Koshy 	if (PMC_CALL(PMCRW, &pmc_rw_op) < 0)
3062aa342b1fSJoseph Koshy 		return (-1);
3063f263522aSJoseph Koshy 
3064f263522aSJoseph Koshy 	*oldvaluep = pmc_rw_op.pm_value;
3065aa342b1fSJoseph Koshy 	return (0);
3066f263522aSJoseph Koshy }
3067f263522aSJoseph Koshy 
3068f263522aSJoseph Koshy int
3069f263522aSJoseph Koshy pmc_set(pmc_id_t pmc, pmc_value_t value)
3070f263522aSJoseph Koshy {
3071f263522aSJoseph Koshy 	struct pmc_op_pmcsetcount sc;
3072f263522aSJoseph Koshy 
3073f263522aSJoseph Koshy 	sc.pm_pmcid = pmc;
3074f263522aSJoseph Koshy 	sc.pm_count = value;
3075f263522aSJoseph Koshy 
3076f263522aSJoseph Koshy 	if (PMC_CALL(PMCSETCOUNT, &sc) < 0)
3077aa342b1fSJoseph Koshy 		return (-1);
3078aa342b1fSJoseph Koshy 	return (0);
3079f263522aSJoseph Koshy }
3080f263522aSJoseph Koshy 
3081f263522aSJoseph Koshy int
3082f263522aSJoseph Koshy pmc_start(pmc_id_t pmc)
3083f263522aSJoseph Koshy {
3084f263522aSJoseph Koshy 	struct pmc_op_simple	pmc_start_args;
3085f263522aSJoseph Koshy 
3086f263522aSJoseph Koshy 	pmc_start_args.pm_pmcid = pmc;
3087aa342b1fSJoseph Koshy 	return (PMC_CALL(PMCSTART, &pmc_start_args));
3088f263522aSJoseph Koshy }
3089f263522aSJoseph Koshy 
3090f263522aSJoseph Koshy int
3091f263522aSJoseph Koshy pmc_stop(pmc_id_t pmc)
3092f263522aSJoseph Koshy {
3093f263522aSJoseph Koshy 	struct pmc_op_simple	pmc_stop_args;
3094f263522aSJoseph Koshy 
3095f263522aSJoseph Koshy 	pmc_stop_args.pm_pmcid = pmc;
3096aa342b1fSJoseph Koshy 	return (PMC_CALL(PMCSTOP, &pmc_stop_args));
3097f263522aSJoseph Koshy }
3098f263522aSJoseph Koshy 
3099f263522aSJoseph Koshy int
3100f263522aSJoseph Koshy pmc_width(pmc_id_t pmcid, uint32_t *width)
3101f263522aSJoseph Koshy {
3102f263522aSJoseph Koshy 	unsigned int i;
3103f263522aSJoseph Koshy 	enum pmc_class cl;
3104f263522aSJoseph Koshy 
3105f263522aSJoseph Koshy 	cl = PMC_ID_TO_CLASS(pmcid);
3106f263522aSJoseph Koshy 	for (i = 0; i < cpu_info.pm_nclass; i++)
3107f263522aSJoseph Koshy 		if (cpu_info.pm_classes[i].pm_class == cl) {
3108f263522aSJoseph Koshy 			*width = cpu_info.pm_classes[i].pm_width;
3109aa342b1fSJoseph Koshy 			return (0);
3110f263522aSJoseph Koshy 		}
3111484202faSJoseph Koshy 	errno = EINVAL;
3112484202faSJoseph Koshy 	return (-1);
3113f263522aSJoseph Koshy }
3114f263522aSJoseph Koshy 
3115f263522aSJoseph Koshy int
3116f263522aSJoseph Koshy pmc_write(pmc_id_t pmc, pmc_value_t value)
3117f263522aSJoseph Koshy {
3118f263522aSJoseph Koshy 	struct pmc_op_pmcrw pmc_write_op;
3119f263522aSJoseph Koshy 
3120f263522aSJoseph Koshy 	pmc_write_op.pm_pmcid = pmc;
3121f263522aSJoseph Koshy 	pmc_write_op.pm_flags = PMC_F_NEWVALUE;
3122f263522aSJoseph Koshy 	pmc_write_op.pm_value = value;
3123aa342b1fSJoseph Koshy 	return (PMC_CALL(PMCRW, &pmc_write_op));
3124f263522aSJoseph Koshy }
3125f263522aSJoseph Koshy 
3126f263522aSJoseph Koshy int
3127f263522aSJoseph Koshy pmc_writelog(uint32_t userdata)
3128f263522aSJoseph Koshy {
3129f263522aSJoseph Koshy 	struct pmc_op_writelog wl;
3130f263522aSJoseph Koshy 
3131f263522aSJoseph Koshy 	wl.pm_userdata = userdata;
3132aa342b1fSJoseph Koshy 	return (PMC_CALL(WRITELOG, &wl));
3133f263522aSJoseph Koshy }
3134