xref: /freebsd/lib/libpmc/libpmc.c (revision 1fa7f10bac396ef8fe623f3845b7d9280e078abd)
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 {
292789140c0SJoseph Koshy 	enum pmc_class	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 	case PMC_EV_IAP_EVENT_77H: /* Core */
7410cfab8ddSJoseph Koshy 		if (cachestate == 0)
7420cfab8ddSJoseph Koshy 			cachestate = (0xF << 8);
7430cfab8ddSJoseph Koshy 	default:
7440cfab8ddSJoseph Koshy 		break;
7450cfab8ddSJoseph Koshy 	}
7460cfab8ddSJoseph Koshy 
7470cfab8ddSJoseph Koshy 	pmc_config->pm_md.pm_iap.pm_iap_config |= cachestate;
7481fa7f10bSFabien Thomas 	pmc_config->pm_md.pm_iap.pm_iap_rsp = rsp;
7491fa7f10bSFabien Thomas 
7501fa7f10bSFabien Thomas 	return (0);
7511fa7f10bSFabien Thomas }
7521fa7f10bSFabien Thomas 
7531fa7f10bSFabien Thomas /*
7541fa7f10bSFabien Thomas  * Intel Uncore.
7551fa7f10bSFabien Thomas  */
7561fa7f10bSFabien Thomas 
7571fa7f10bSFabien Thomas static int
7581fa7f10bSFabien Thomas ucf_allocate_pmc(enum pmc_event pe, char *ctrspec,
7591fa7f10bSFabien Thomas     struct pmc_op_pmcallocate *pmc_config)
7601fa7f10bSFabien Thomas {
7611fa7f10bSFabien Thomas 	(void) pe;
7621fa7f10bSFabien Thomas 	(void) ctrspec;
7631fa7f10bSFabien Thomas 
7641fa7f10bSFabien Thomas 	pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE);
7651fa7f10bSFabien Thomas 	pmc_config->pm_md.pm_ucf.pm_ucf_flags = 0;
7661fa7f10bSFabien Thomas 
7671fa7f10bSFabien Thomas 	return (0);
7681fa7f10bSFabien Thomas }
7691fa7f10bSFabien Thomas 
7701fa7f10bSFabien Thomas #define	UCP_KW_CMASK		"cmask"
7711fa7f10bSFabien Thomas #define	UCP_KW_EDGE		"edge"
7721fa7f10bSFabien Thomas #define	UCP_KW_INV		"inv"
7731fa7f10bSFabien Thomas 
7741fa7f10bSFabien Thomas static int
7751fa7f10bSFabien Thomas ucp_allocate_pmc(enum pmc_event pe, char *ctrspec,
7761fa7f10bSFabien Thomas     struct pmc_op_pmcallocate *pmc_config)
7771fa7f10bSFabien Thomas {
7781fa7f10bSFabien Thomas 	char *e, *p, *q;
7791fa7f10bSFabien Thomas 	int count, n;
7801fa7f10bSFabien Thomas 
7811fa7f10bSFabien Thomas 	(void) pe;
7821fa7f10bSFabien Thomas 
7831fa7f10bSFabien Thomas 	pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE |
7841fa7f10bSFabien Thomas 	    PMC_CAP_QUALIFIER);
7851fa7f10bSFabien Thomas 	pmc_config->pm_md.pm_ucp.pm_ucp_config = 0;
7861fa7f10bSFabien Thomas 
7871fa7f10bSFabien Thomas 	/* Parse additional modifiers if present */
7881fa7f10bSFabien Thomas 	while ((p = strsep(&ctrspec, ",")) != NULL) {
7891fa7f10bSFabien Thomas 
7901fa7f10bSFabien Thomas 		n = 0;
7911fa7f10bSFabien Thomas 		if (KWPREFIXMATCH(p, UCP_KW_CMASK "=")) {
7921fa7f10bSFabien Thomas 			q = strchr(p, '=');
7931fa7f10bSFabien Thomas 			if (*++q == '\0') /* skip '=' */
7941fa7f10bSFabien Thomas 				return (-1);
7951fa7f10bSFabien Thomas 			count = strtol(q, &e, 0);
7961fa7f10bSFabien Thomas 			if (e == q || *e != '\0')
7971fa7f10bSFabien Thomas 				return (-1);
7981fa7f10bSFabien Thomas 			pmc_config->pm_caps |= PMC_CAP_THRESHOLD;
7991fa7f10bSFabien Thomas 			pmc_config->pm_md.pm_ucp.pm_ucp_config |=
8001fa7f10bSFabien Thomas 			    UCP_CMASK(count);
8011fa7f10bSFabien Thomas 		} else if (KWMATCH(p, UCP_KW_EDGE)) {
8021fa7f10bSFabien Thomas 			pmc_config->pm_caps |= PMC_CAP_EDGE;
8031fa7f10bSFabien Thomas 		} else if (KWMATCH(p, UCP_KW_INV)) {
8041fa7f10bSFabien Thomas 			pmc_config->pm_caps |= PMC_CAP_INVERT;
8051fa7f10bSFabien Thomas 		} else
8061fa7f10bSFabien Thomas 			return (-1);
8071fa7f10bSFabien Thomas 
8081fa7f10bSFabien Thomas 		if (n < 0)	/* Parsing failed. */
8091fa7f10bSFabien Thomas 			return (-1);
8101fa7f10bSFabien Thomas 	}
8110cfab8ddSJoseph Koshy 
8120cfab8ddSJoseph Koshy 	return (0);
8130cfab8ddSJoseph Koshy }
8140cfab8ddSJoseph Koshy 
8150cfab8ddSJoseph Koshy /*
816f263522aSJoseph Koshy  * AMD K8 PMCs.
817f263522aSJoseph Koshy  *
818f263522aSJoseph Koshy  * These are very similar to AMD K7 PMCs, but support more kinds of
819f263522aSJoseph Koshy  * events.
820f263522aSJoseph Koshy  */
821f263522aSJoseph Koshy 
822f263522aSJoseph Koshy static struct pmc_event_alias k8_aliases[] = {
823f263522aSJoseph Koshy 	EV_ALIAS("branches",		"k8-fr-retired-taken-branches"),
824f263522aSJoseph Koshy 	EV_ALIAS("branch-mispredicts",
825f263522aSJoseph Koshy 	    "k8-fr-retired-taken-branches-mispredicted"),
826f263522aSJoseph Koshy 	EV_ALIAS("cycles",		"tsc"),
827f263522aSJoseph Koshy 	EV_ALIAS("dc-misses",		"k8-dc-miss"),
828f263522aSJoseph Koshy 	EV_ALIAS("ic-misses",		"k8-ic-miss"),
829f263522aSJoseph Koshy 	EV_ALIAS("instructions",	"k8-fr-retired-x86-instructions"),
830f263522aSJoseph Koshy 	EV_ALIAS("interrupts",		"k8-fr-taken-hardware-interrupts"),
831177a2f22SJoseph Koshy 	EV_ALIAS("unhalted-cycles",	"k8-bu-cpu-clk-unhalted"),
832f263522aSJoseph Koshy 	EV_ALIAS(NULL, NULL)
833f263522aSJoseph Koshy };
834f263522aSJoseph Koshy 
835f263522aSJoseph Koshy #define	__K8MASK(N,V) PMCMASK(N,(1 << (V)))
836f263522aSJoseph Koshy 
837f263522aSJoseph Koshy /*
838f263522aSJoseph Koshy  * Parsing tables
839f263522aSJoseph Koshy  */
840f263522aSJoseph Koshy 
841f263522aSJoseph Koshy /* fp dispatched fpu ops */
842f263522aSJoseph Koshy static const struct pmc_masks k8_mask_fdfo[] = {
843f263522aSJoseph Koshy 	__K8MASK(add-pipe-excluding-junk-ops,	0),
844f263522aSJoseph Koshy 	__K8MASK(multiply-pipe-excluding-junk-ops,	1),
845f263522aSJoseph Koshy 	__K8MASK(store-pipe-excluding-junk-ops,	2),
846f263522aSJoseph Koshy 	__K8MASK(add-pipe-junk-ops,		3),
847f263522aSJoseph Koshy 	__K8MASK(multiply-pipe-junk-ops,	4),
848f263522aSJoseph Koshy 	__K8MASK(store-pipe-junk-ops,		5),
849f263522aSJoseph Koshy 	NULLMASK
850f263522aSJoseph Koshy };
851f263522aSJoseph Koshy 
852f263522aSJoseph Koshy /* ls segment register loads */
853f263522aSJoseph Koshy static const struct pmc_masks k8_mask_lsrl[] = {
854f263522aSJoseph Koshy 	__K8MASK(es,	0),
855f263522aSJoseph Koshy 	__K8MASK(cs,	1),
856f263522aSJoseph Koshy 	__K8MASK(ss,	2),
857f263522aSJoseph Koshy 	__K8MASK(ds,	3),
858f263522aSJoseph Koshy 	__K8MASK(fs,	4),
859f263522aSJoseph Koshy 	__K8MASK(gs,	5),
860f263522aSJoseph Koshy 	__K8MASK(hs,	6),
861f263522aSJoseph Koshy 	NULLMASK
862f263522aSJoseph Koshy };
863f263522aSJoseph Koshy 
864f263522aSJoseph Koshy /* ls locked operation */
865f263522aSJoseph Koshy static const struct pmc_masks k8_mask_llo[] = {
866f263522aSJoseph Koshy 	__K8MASK(locked-instructions,	0),
867f263522aSJoseph Koshy 	__K8MASK(cycles-in-request,	1),
868f263522aSJoseph Koshy 	__K8MASK(cycles-to-complete,	2),
869f263522aSJoseph Koshy 	NULLMASK
870f263522aSJoseph Koshy };
871f263522aSJoseph Koshy 
872f263522aSJoseph Koshy /* dc refill from {l2,system} and dc copyback */
873f263522aSJoseph Koshy static const struct pmc_masks k8_mask_dc[] = {
874f263522aSJoseph Koshy 	__K8MASK(invalid,	0),
875f263522aSJoseph Koshy 	__K8MASK(shared,	1),
876f263522aSJoseph Koshy 	__K8MASK(exclusive,	2),
877f263522aSJoseph Koshy 	__K8MASK(owner,		3),
878f263522aSJoseph Koshy 	__K8MASK(modified,	4),
879f263522aSJoseph Koshy 	NULLMASK
880f263522aSJoseph Koshy };
881f263522aSJoseph Koshy 
882f263522aSJoseph Koshy /* dc one bit ecc error */
883f263522aSJoseph Koshy static const struct pmc_masks k8_mask_dobee[] = {
884f263522aSJoseph Koshy 	__K8MASK(scrubber,	0),
885f263522aSJoseph Koshy 	__K8MASK(piggyback,	1),
886f263522aSJoseph Koshy 	NULLMASK
887f263522aSJoseph Koshy };
888f263522aSJoseph Koshy 
889f263522aSJoseph Koshy /* dc dispatched prefetch instructions */
890f263522aSJoseph Koshy static const struct pmc_masks k8_mask_ddpi[] = {
891f263522aSJoseph Koshy 	__K8MASK(load,	0),
892f263522aSJoseph Koshy 	__K8MASK(store,	1),
893f263522aSJoseph Koshy 	__K8MASK(nta,	2),
894f263522aSJoseph Koshy 	NULLMASK
895f263522aSJoseph Koshy };
896f263522aSJoseph Koshy 
897f263522aSJoseph Koshy /* dc dcache accesses by locks */
898f263522aSJoseph Koshy static const struct pmc_masks k8_mask_dabl[] = {
899f263522aSJoseph Koshy 	__K8MASK(accesses,	0),
900f263522aSJoseph Koshy 	__K8MASK(misses,	1),
901f263522aSJoseph Koshy 	NULLMASK
902f263522aSJoseph Koshy };
903f263522aSJoseph Koshy 
904f263522aSJoseph Koshy /* bu internal l2 request */
905f263522aSJoseph Koshy static const struct pmc_masks k8_mask_bilr[] = {
906f263522aSJoseph Koshy 	__K8MASK(ic-fill,	0),
907f263522aSJoseph Koshy 	__K8MASK(dc-fill,	1),
908f263522aSJoseph Koshy 	__K8MASK(tlb-reload,	2),
909f263522aSJoseph Koshy 	__K8MASK(tag-snoop,	3),
910f263522aSJoseph Koshy 	__K8MASK(cancelled,	4),
911f263522aSJoseph Koshy 	NULLMASK
912f263522aSJoseph Koshy };
913f263522aSJoseph Koshy 
914f263522aSJoseph Koshy /* bu fill request l2 miss */
915f263522aSJoseph Koshy static const struct pmc_masks k8_mask_bfrlm[] = {
916f263522aSJoseph Koshy 	__K8MASK(ic-fill,	0),
917f263522aSJoseph Koshy 	__K8MASK(dc-fill,	1),
918f263522aSJoseph Koshy 	__K8MASK(tlb-reload,	2),
919f263522aSJoseph Koshy 	NULLMASK
920f263522aSJoseph Koshy };
921f263522aSJoseph Koshy 
922f263522aSJoseph Koshy /* bu fill into l2 */
923f263522aSJoseph Koshy static const struct pmc_masks k8_mask_bfil[] = {
924f263522aSJoseph Koshy 	__K8MASK(dirty-l2-victim,	0),
925f263522aSJoseph Koshy 	__K8MASK(victim-from-l2,	1),
926f263522aSJoseph Koshy 	NULLMASK
927f263522aSJoseph Koshy };
928f263522aSJoseph Koshy 
929f263522aSJoseph Koshy /* fr retired fpu instructions */
930f263522aSJoseph Koshy static const struct pmc_masks k8_mask_frfi[] = {
931f263522aSJoseph Koshy 	__K8MASK(x87,			0),
932f263522aSJoseph Koshy 	__K8MASK(mmx-3dnow,		1),
933f263522aSJoseph Koshy 	__K8MASK(packed-sse-sse2,	2),
934f263522aSJoseph Koshy 	__K8MASK(scalar-sse-sse2,	3),
935f263522aSJoseph Koshy 	NULLMASK
936f263522aSJoseph Koshy };
937f263522aSJoseph Koshy 
938f263522aSJoseph Koshy /* fr retired fastpath double op instructions */
939f263522aSJoseph Koshy static const struct pmc_masks k8_mask_frfdoi[] = {
940f263522aSJoseph Koshy 	__K8MASK(low-op-pos-0,		0),
941f263522aSJoseph Koshy 	__K8MASK(low-op-pos-1,		1),
942f263522aSJoseph Koshy 	__K8MASK(low-op-pos-2,		2),
943f263522aSJoseph Koshy 	NULLMASK
944f263522aSJoseph Koshy };
945f263522aSJoseph Koshy 
946f263522aSJoseph Koshy /* fr fpu exceptions */
947f263522aSJoseph Koshy static const struct pmc_masks k8_mask_ffe[] = {
948f263522aSJoseph Koshy 	__K8MASK(x87-reclass-microfaults,	0),
949f263522aSJoseph Koshy 	__K8MASK(sse-retype-microfaults,	1),
950f263522aSJoseph Koshy 	__K8MASK(sse-reclass-microfaults,	2),
951f263522aSJoseph Koshy 	__K8MASK(sse-and-x87-microtraps,	3),
952f263522aSJoseph Koshy 	NULLMASK
953f263522aSJoseph Koshy };
954f263522aSJoseph Koshy 
955f263522aSJoseph Koshy /* nb memory controller page access event */
956f263522aSJoseph Koshy static const struct pmc_masks k8_mask_nmcpae[] = {
957f263522aSJoseph Koshy 	__K8MASK(page-hit,	0),
958f263522aSJoseph Koshy 	__K8MASK(page-miss,	1),
959f263522aSJoseph Koshy 	__K8MASK(page-conflict,	2),
960f263522aSJoseph Koshy 	NULLMASK
961f263522aSJoseph Koshy };
962f263522aSJoseph Koshy 
963f263522aSJoseph Koshy /* nb memory controller turnaround */
964f263522aSJoseph Koshy static const struct pmc_masks k8_mask_nmct[] = {
965f263522aSJoseph Koshy 	__K8MASK(dimm-turnaround,		0),
966f263522aSJoseph Koshy 	__K8MASK(read-to-write-turnaround,	1),
967f263522aSJoseph Koshy 	__K8MASK(write-to-read-turnaround,	2),
968f263522aSJoseph Koshy 	NULLMASK
969f263522aSJoseph Koshy };
970f263522aSJoseph Koshy 
971f263522aSJoseph Koshy /* nb memory controller bypass saturation */
972f263522aSJoseph Koshy static const struct pmc_masks k8_mask_nmcbs[] = {
973f263522aSJoseph Koshy 	__K8MASK(memory-controller-hi-pri-bypass,	0),
974f263522aSJoseph Koshy 	__K8MASK(memory-controller-lo-pri-bypass,	1),
975f263522aSJoseph Koshy 	__K8MASK(dram-controller-interface-bypass,	2),
976f263522aSJoseph Koshy 	__K8MASK(dram-controller-queue-bypass,		3),
977f263522aSJoseph Koshy 	NULLMASK
978f263522aSJoseph Koshy };
979f263522aSJoseph Koshy 
980f263522aSJoseph Koshy /* nb sized commands */
981f263522aSJoseph Koshy static const struct pmc_masks k8_mask_nsc[] = {
982f263522aSJoseph Koshy 	__K8MASK(nonpostwrszbyte,	0),
983f263522aSJoseph Koshy 	__K8MASK(nonpostwrszdword,	1),
984f263522aSJoseph Koshy 	__K8MASK(postwrszbyte,		2),
985f263522aSJoseph Koshy 	__K8MASK(postwrszdword,		3),
986f263522aSJoseph Koshy 	__K8MASK(rdszbyte,		4),
987f263522aSJoseph Koshy 	__K8MASK(rdszdword,		5),
988f263522aSJoseph Koshy 	__K8MASK(rdmodwr,		6),
989f263522aSJoseph Koshy 	NULLMASK
990f263522aSJoseph Koshy };
991f263522aSJoseph Koshy 
992f263522aSJoseph Koshy /* nb probe result */
993f263522aSJoseph Koshy static const struct pmc_masks k8_mask_npr[] = {
994f263522aSJoseph Koshy 	__K8MASK(probe-miss,		0),
995f263522aSJoseph Koshy 	__K8MASK(probe-hit,		1),
996f263522aSJoseph Koshy 	__K8MASK(probe-hit-dirty-no-memory-cancel, 2),
997f263522aSJoseph Koshy 	__K8MASK(probe-hit-dirty-with-memory-cancel, 3),
998f263522aSJoseph Koshy 	NULLMASK
999f263522aSJoseph Koshy };
1000f263522aSJoseph Koshy 
1001f263522aSJoseph Koshy /* nb hypertransport bus bandwidth */
1002f263522aSJoseph Koshy static const struct pmc_masks k8_mask_nhbb[] = { /* HT bus bandwidth */
1003f263522aSJoseph Koshy 	__K8MASK(command,	0),
1004f263522aSJoseph Koshy 	__K8MASK(data,	1),
1005f263522aSJoseph Koshy 	__K8MASK(buffer-release, 2),
1006f263522aSJoseph Koshy 	__K8MASK(nop,	3),
1007f263522aSJoseph Koshy 	NULLMASK
1008f263522aSJoseph Koshy };
1009f263522aSJoseph Koshy 
1010f263522aSJoseph Koshy #undef	__K8MASK
1011f263522aSJoseph Koshy 
1012f263522aSJoseph Koshy #define	K8_KW_COUNT	"count"
1013f263522aSJoseph Koshy #define	K8_KW_EDGE	"edge"
1014f263522aSJoseph Koshy #define	K8_KW_INV	"inv"
1015f263522aSJoseph Koshy #define	K8_KW_MASK	"mask"
1016f263522aSJoseph Koshy #define	K8_KW_OS	"os"
1017f263522aSJoseph Koshy #define	K8_KW_USR	"usr"
1018f263522aSJoseph Koshy 
1019f263522aSJoseph Koshy static int
1020f263522aSJoseph Koshy k8_allocate_pmc(enum pmc_event pe, char *ctrspec,
1021f263522aSJoseph Koshy     struct pmc_op_pmcallocate *pmc_config)
1022f263522aSJoseph Koshy {
1023f263522aSJoseph Koshy 	char		*e, *p, *q;
1024f263522aSJoseph Koshy 	int		n;
1025f263522aSJoseph Koshy 	uint32_t	count, evmask;
1026f263522aSJoseph Koshy 	const struct pmc_masks	*pm, *pmask;
1027f263522aSJoseph Koshy 
1028789140c0SJoseph Koshy 	pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE);
1029f263522aSJoseph Koshy 	pmc_config->pm_md.pm_amd.pm_amd_config = 0;
1030f263522aSJoseph Koshy 
1031f263522aSJoseph Koshy 	pmask = NULL;
1032f263522aSJoseph Koshy 	evmask = 0;
1033f263522aSJoseph Koshy 
1034f263522aSJoseph Koshy #define	__K8SETMASK(M) pmask = k8_mask_##M
1035f263522aSJoseph Koshy 
1036f263522aSJoseph Koshy 	/* setup parsing tables */
1037f263522aSJoseph Koshy 	switch (pe) {
1038f263522aSJoseph Koshy 	case PMC_EV_K8_FP_DISPATCHED_FPU_OPS:
1039f263522aSJoseph Koshy 		__K8SETMASK(fdfo);
1040f263522aSJoseph Koshy 		break;
1041f263522aSJoseph Koshy 	case PMC_EV_K8_LS_SEGMENT_REGISTER_LOAD:
1042f263522aSJoseph Koshy 		__K8SETMASK(lsrl);
1043f263522aSJoseph Koshy 		break;
1044f263522aSJoseph Koshy 	case PMC_EV_K8_LS_LOCKED_OPERATION:
1045f263522aSJoseph Koshy 		__K8SETMASK(llo);
1046f263522aSJoseph Koshy 		break;
1047f263522aSJoseph Koshy 	case PMC_EV_K8_DC_REFILL_FROM_L2:
1048f263522aSJoseph Koshy 	case PMC_EV_K8_DC_REFILL_FROM_SYSTEM:
1049f263522aSJoseph Koshy 	case PMC_EV_K8_DC_COPYBACK:
1050f263522aSJoseph Koshy 		__K8SETMASK(dc);
1051f263522aSJoseph Koshy 		break;
1052f263522aSJoseph Koshy 	case PMC_EV_K8_DC_ONE_BIT_ECC_ERROR:
1053f263522aSJoseph Koshy 		__K8SETMASK(dobee);
1054f263522aSJoseph Koshy 		break;
1055f263522aSJoseph Koshy 	case PMC_EV_K8_DC_DISPATCHED_PREFETCH_INSTRUCTIONS:
1056f263522aSJoseph Koshy 		__K8SETMASK(ddpi);
1057f263522aSJoseph Koshy 		break;
1058f263522aSJoseph Koshy 	case PMC_EV_K8_DC_DCACHE_ACCESSES_BY_LOCKS:
1059f263522aSJoseph Koshy 		__K8SETMASK(dabl);
1060f263522aSJoseph Koshy 		break;
1061f263522aSJoseph Koshy 	case PMC_EV_K8_BU_INTERNAL_L2_REQUEST:
1062f263522aSJoseph Koshy 		__K8SETMASK(bilr);
1063f263522aSJoseph Koshy 		break;
1064f263522aSJoseph Koshy 	case PMC_EV_K8_BU_FILL_REQUEST_L2_MISS:
1065f263522aSJoseph Koshy 		__K8SETMASK(bfrlm);
1066f263522aSJoseph Koshy 		break;
1067f263522aSJoseph Koshy 	case PMC_EV_K8_BU_FILL_INTO_L2:
1068f263522aSJoseph Koshy 		__K8SETMASK(bfil);
1069f263522aSJoseph Koshy 		break;
1070f263522aSJoseph Koshy 	case PMC_EV_K8_FR_RETIRED_FPU_INSTRUCTIONS:
1071f263522aSJoseph Koshy 		__K8SETMASK(frfi);
1072f263522aSJoseph Koshy 		break;
1073f263522aSJoseph Koshy 	case PMC_EV_K8_FR_RETIRED_FASTPATH_DOUBLE_OP_INSTRUCTIONS:
1074f263522aSJoseph Koshy 		__K8SETMASK(frfdoi);
1075f263522aSJoseph Koshy 		break;
1076f263522aSJoseph Koshy 	case PMC_EV_K8_FR_FPU_EXCEPTIONS:
1077f263522aSJoseph Koshy 		__K8SETMASK(ffe);
1078f263522aSJoseph Koshy 		break;
1079f263522aSJoseph Koshy 	case PMC_EV_K8_NB_MEMORY_CONTROLLER_PAGE_ACCESS_EVENT:
1080f263522aSJoseph Koshy 		__K8SETMASK(nmcpae);
1081f263522aSJoseph Koshy 		break;
1082f263522aSJoseph Koshy 	case PMC_EV_K8_NB_MEMORY_CONTROLLER_TURNAROUND:
1083f263522aSJoseph Koshy 		__K8SETMASK(nmct);
1084f263522aSJoseph Koshy 		break;
1085f263522aSJoseph Koshy 	case PMC_EV_K8_NB_MEMORY_CONTROLLER_BYPASS_SATURATION:
1086f263522aSJoseph Koshy 		__K8SETMASK(nmcbs);
1087f263522aSJoseph Koshy 		break;
1088f263522aSJoseph Koshy 	case PMC_EV_K8_NB_SIZED_COMMANDS:
1089f263522aSJoseph Koshy 		__K8SETMASK(nsc);
1090f263522aSJoseph Koshy 		break;
1091f263522aSJoseph Koshy 	case PMC_EV_K8_NB_PROBE_RESULT:
1092f263522aSJoseph Koshy 		__K8SETMASK(npr);
1093f263522aSJoseph Koshy 		break;
1094f263522aSJoseph Koshy 	case PMC_EV_K8_NB_HT_BUS0_BANDWIDTH:
1095f263522aSJoseph Koshy 	case PMC_EV_K8_NB_HT_BUS1_BANDWIDTH:
1096f263522aSJoseph Koshy 	case PMC_EV_K8_NB_HT_BUS2_BANDWIDTH:
1097f263522aSJoseph Koshy 		__K8SETMASK(nhbb);
1098f263522aSJoseph Koshy 		break;
1099f263522aSJoseph Koshy 
1100f263522aSJoseph Koshy 	default:
1101f263522aSJoseph Koshy 		break;		/* no options defined */
1102f263522aSJoseph Koshy 	}
1103f263522aSJoseph Koshy 
1104f263522aSJoseph Koshy 	while ((p = strsep(&ctrspec, ",")) != NULL) {
1105f263522aSJoseph Koshy 		if (KWPREFIXMATCH(p, K8_KW_COUNT "=")) {
1106f263522aSJoseph Koshy 			q = strchr(p, '=');
1107f263522aSJoseph Koshy 			if (*++q == '\0') /* skip '=' */
1108aa342b1fSJoseph Koshy 				return (-1);
1109f263522aSJoseph Koshy 
1110f263522aSJoseph Koshy 			count = strtol(q, &e, 0);
1111f263522aSJoseph Koshy 			if (e == q || *e != '\0')
1112aa342b1fSJoseph Koshy 				return (-1);
1113f263522aSJoseph Koshy 
1114f263522aSJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_THRESHOLD;
1115f263522aSJoseph Koshy 			pmc_config->pm_md.pm_amd.pm_amd_config |=
1116f263522aSJoseph Koshy 			    AMD_PMC_TO_COUNTER(count);
1117f263522aSJoseph Koshy 
1118f263522aSJoseph Koshy 		} else if (KWMATCH(p, K8_KW_EDGE)) {
1119f263522aSJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_EDGE;
1120f263522aSJoseph Koshy 		} else if (KWMATCH(p, K8_KW_INV)) {
1121f263522aSJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_INVERT;
1122f263522aSJoseph Koshy 		} else if (KWPREFIXMATCH(p, K8_KW_MASK "=")) {
1123f263522aSJoseph Koshy 			if ((n = pmc_parse_mask(pmask, p, &evmask)) < 0)
1124aa342b1fSJoseph Koshy 				return (-1);
1125f263522aSJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_QUALIFIER;
1126f263522aSJoseph Koshy 		} else if (KWMATCH(p, K8_KW_OS)) {
1127f263522aSJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_SYSTEM;
1128f263522aSJoseph Koshy 		} else if (KWMATCH(p, K8_KW_USR)) {
1129f263522aSJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_USER;
1130f263522aSJoseph Koshy 		} else
1131aa342b1fSJoseph Koshy 			return (-1);
1132f263522aSJoseph Koshy 	}
1133f263522aSJoseph Koshy 
1134f263522aSJoseph Koshy 	/* other post processing */
1135f263522aSJoseph Koshy 	switch (pe) {
1136f263522aSJoseph Koshy 	case PMC_EV_K8_FP_DISPATCHED_FPU_OPS:
1137f263522aSJoseph Koshy 	case PMC_EV_K8_FP_CYCLES_WITH_NO_FPU_OPS_RETIRED:
1138f263522aSJoseph Koshy 	case PMC_EV_K8_FP_DISPATCHED_FPU_FAST_FLAG_OPS:
1139f263522aSJoseph Koshy 	case PMC_EV_K8_FR_RETIRED_FASTPATH_DOUBLE_OP_INSTRUCTIONS:
1140f263522aSJoseph Koshy 	case PMC_EV_K8_FR_RETIRED_FPU_INSTRUCTIONS:
1141f263522aSJoseph Koshy 	case PMC_EV_K8_FR_FPU_EXCEPTIONS:
1142f263522aSJoseph Koshy 		/* XXX only available in rev B and later */
1143f263522aSJoseph Koshy 		break;
1144f263522aSJoseph Koshy 	case PMC_EV_K8_DC_DCACHE_ACCESSES_BY_LOCKS:
1145f263522aSJoseph Koshy 		/* XXX only available in rev C and later */
1146f263522aSJoseph Koshy 		break;
1147f263522aSJoseph Koshy 	case PMC_EV_K8_LS_LOCKED_OPERATION:
1148f263522aSJoseph Koshy 		/* XXX CPU Rev A,B evmask is to be zero */
1149f263522aSJoseph Koshy 		if (evmask & (evmask - 1)) /* > 1 bit set */
1150aa342b1fSJoseph Koshy 			return (-1);
1151f263522aSJoseph Koshy 		if (evmask == 0) {
1152f263522aSJoseph Koshy 			evmask = 0x01; /* Rev C and later: #instrs */
1153f263522aSJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_QUALIFIER;
1154f263522aSJoseph Koshy 		}
1155f263522aSJoseph Koshy 		break;
1156f263522aSJoseph Koshy 	default:
1157f263522aSJoseph Koshy 		if (evmask == 0 && pmask != NULL) {
1158f263522aSJoseph Koshy 			for (pm = pmask; pm->pm_name; pm++)
1159f263522aSJoseph Koshy 				evmask |= pm->pm_value;
1160f263522aSJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_QUALIFIER;
1161f263522aSJoseph Koshy 		}
1162f263522aSJoseph Koshy 	}
1163f263522aSJoseph Koshy 
1164f263522aSJoseph Koshy 	if (pmc_config->pm_caps & PMC_CAP_QUALIFIER)
1165f263522aSJoseph Koshy 		pmc_config->pm_md.pm_amd.pm_amd_config =
1166f263522aSJoseph Koshy 		    AMD_PMC_TO_UNITMASK(evmask);
1167f263522aSJoseph Koshy 
1168aa342b1fSJoseph Koshy 	return (0);
1169f263522aSJoseph Koshy }
1170f263522aSJoseph Koshy 
1171f263522aSJoseph Koshy #endif
1172f263522aSJoseph Koshy 
117386a65549SJoseph Koshy #if defined(__amd64__) || defined(__i386__)
1174f263522aSJoseph Koshy 
1175ebccf1e3SJoseph Koshy /*
1176ebccf1e3SJoseph Koshy  * Intel P4 PMCs
1177ebccf1e3SJoseph Koshy  */
1178ebccf1e3SJoseph Koshy 
1179ebccf1e3SJoseph Koshy static struct pmc_event_alias p4_aliases[] = {
1180d56c5d4bSJoseph Koshy 	EV_ALIAS("branches",		"p4-branch-retired,mask=mmtp+mmtm"),
1181d56c5d4bSJoseph Koshy 	EV_ALIAS("branch-mispredicts",	"p4-mispred-branch-retired"),
1182ebccf1e3SJoseph Koshy 	EV_ALIAS("cycles",		"tsc"),
1183d56c5d4bSJoseph Koshy 	EV_ALIAS("instructions",
1184d56c5d4bSJoseph Koshy 	    "p4-instr-retired,mask=nbogusntag+nbogustag"),
1185177a2f22SJoseph Koshy 	EV_ALIAS("unhalted-cycles",	"p4-global-power-events"),
1186ebccf1e3SJoseph Koshy 	EV_ALIAS(NULL, NULL)
1187ebccf1e3SJoseph Koshy };
1188ebccf1e3SJoseph Koshy 
1189ebccf1e3SJoseph Koshy #define	P4_KW_ACTIVE	"active"
1190ebccf1e3SJoseph Koshy #define	P4_KW_ACTIVE_ANY "any"
1191ebccf1e3SJoseph Koshy #define	P4_KW_ACTIVE_BOTH "both"
1192ebccf1e3SJoseph Koshy #define	P4_KW_ACTIVE_NONE "none"
1193ebccf1e3SJoseph Koshy #define	P4_KW_ACTIVE_SINGLE "single"
1194ebccf1e3SJoseph Koshy #define	P4_KW_BUSREQTYPE "busreqtype"
1195ebccf1e3SJoseph Koshy #define	P4_KW_CASCADE	"cascade"
1196ebccf1e3SJoseph Koshy #define	P4_KW_EDGE	"edge"
1197ebccf1e3SJoseph Koshy #define	P4_KW_INV	"complement"
1198ebccf1e3SJoseph Koshy #define	P4_KW_OS	"os"
1199ebccf1e3SJoseph Koshy #define	P4_KW_MASK	"mask"
1200ebccf1e3SJoseph Koshy #define	P4_KW_PRECISE	"precise"
1201ebccf1e3SJoseph Koshy #define	P4_KW_TAG	"tag"
1202ebccf1e3SJoseph Koshy #define	P4_KW_THRESHOLD	"threshold"
1203ebccf1e3SJoseph Koshy #define	P4_KW_USR	"usr"
1204ebccf1e3SJoseph Koshy 
1205ebccf1e3SJoseph Koshy #define	__P4MASK(N,V) PMCMASK(N, (1 << (V)))
1206ebccf1e3SJoseph Koshy 
1207ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_tcdm[] = { /* tc deliver mode */
1208ebccf1e3SJoseph Koshy 	__P4MASK(dd, 0),
1209ebccf1e3SJoseph Koshy 	__P4MASK(db, 1),
1210ebccf1e3SJoseph Koshy 	__P4MASK(di, 2),
1211ebccf1e3SJoseph Koshy 	__P4MASK(bd, 3),
1212ebccf1e3SJoseph Koshy 	__P4MASK(bb, 4),
1213ebccf1e3SJoseph Koshy 	__P4MASK(bi, 5),
1214ebccf1e3SJoseph Koshy 	__P4MASK(id, 6),
1215ebccf1e3SJoseph Koshy 	__P4MASK(ib, 7),
1216ebccf1e3SJoseph Koshy 	NULLMASK
1217ebccf1e3SJoseph Koshy };
1218ebccf1e3SJoseph Koshy 
1219ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_bfr[] = { /* bpu fetch request */
1220ebccf1e3SJoseph Koshy 	__P4MASK(tcmiss, 0),
1221ebccf1e3SJoseph Koshy 	NULLMASK,
1222ebccf1e3SJoseph Koshy };
1223ebccf1e3SJoseph Koshy 
1224ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_ir[] = { /* itlb reference */
1225ebccf1e3SJoseph Koshy 	__P4MASK(hit, 0),
1226ebccf1e3SJoseph Koshy 	__P4MASK(miss, 1),
1227ebccf1e3SJoseph Koshy 	__P4MASK(hit-uc, 2),
1228ebccf1e3SJoseph Koshy 	NULLMASK
1229ebccf1e3SJoseph Koshy };
1230ebccf1e3SJoseph Koshy 
1231ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_memcan[] = { /* memory cancel */
1232ebccf1e3SJoseph Koshy 	__P4MASK(st-rb-full, 2),
1233ebccf1e3SJoseph Koshy 	__P4MASK(64k-conf, 3),
1234ebccf1e3SJoseph Koshy 	NULLMASK
1235ebccf1e3SJoseph Koshy };
1236ebccf1e3SJoseph Koshy 
1237ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_memcomp[] = { /* memory complete */
1238ebccf1e3SJoseph Koshy 	__P4MASK(lsc, 0),
1239ebccf1e3SJoseph Koshy 	__P4MASK(ssc, 1),
1240ebccf1e3SJoseph Koshy 	NULLMASK
1241ebccf1e3SJoseph Koshy };
1242ebccf1e3SJoseph Koshy 
1243ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_lpr[] = { /* load port replay */
1244ebccf1e3SJoseph Koshy 	__P4MASK(split-ld, 1),
1245ebccf1e3SJoseph Koshy 	NULLMASK
1246ebccf1e3SJoseph Koshy };
1247ebccf1e3SJoseph Koshy 
1248ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_spr[] = { /* store port replay */
1249ebccf1e3SJoseph Koshy 	__P4MASK(split-st, 1),
1250ebccf1e3SJoseph Koshy 	NULLMASK
1251ebccf1e3SJoseph Koshy };
1252ebccf1e3SJoseph Koshy 
1253ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_mlr[] = { /* mob load replay */
1254ebccf1e3SJoseph Koshy 	__P4MASK(no-sta, 1),
1255ebccf1e3SJoseph Koshy 	__P4MASK(no-std, 3),
1256ebccf1e3SJoseph Koshy 	__P4MASK(partial-data, 4),
1257ebccf1e3SJoseph Koshy 	__P4MASK(unalgn-addr, 5),
1258ebccf1e3SJoseph Koshy 	NULLMASK
1259ebccf1e3SJoseph Koshy };
1260ebccf1e3SJoseph Koshy 
1261ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_pwt[] = { /* page walk type */
1262ebccf1e3SJoseph Koshy 	__P4MASK(dtmiss, 0),
1263ebccf1e3SJoseph Koshy 	__P4MASK(itmiss, 1),
1264ebccf1e3SJoseph Koshy 	NULLMASK
1265ebccf1e3SJoseph Koshy };
1266ebccf1e3SJoseph Koshy 
1267ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_bcr[] = { /* bsq cache reference */
1268ebccf1e3SJoseph Koshy 	__P4MASK(rd-2ndl-hits, 0),
1269ebccf1e3SJoseph Koshy 	__P4MASK(rd-2ndl-hite, 1),
1270ebccf1e3SJoseph Koshy 	__P4MASK(rd-2ndl-hitm, 2),
1271ebccf1e3SJoseph Koshy 	__P4MASK(rd-3rdl-hits, 3),
1272ebccf1e3SJoseph Koshy 	__P4MASK(rd-3rdl-hite, 4),
1273ebccf1e3SJoseph Koshy 	__P4MASK(rd-3rdl-hitm, 5),
1274ebccf1e3SJoseph Koshy 	__P4MASK(rd-2ndl-miss, 8),
1275ebccf1e3SJoseph Koshy 	__P4MASK(rd-3rdl-miss, 9),
1276ebccf1e3SJoseph Koshy 	__P4MASK(wr-2ndl-miss, 10),
1277ebccf1e3SJoseph Koshy 	NULLMASK
1278ebccf1e3SJoseph Koshy };
1279ebccf1e3SJoseph Koshy 
1280ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_ia[] = { /* ioq allocation */
1281ebccf1e3SJoseph Koshy 	__P4MASK(all-read, 5),
1282ebccf1e3SJoseph Koshy 	__P4MASK(all-write, 6),
1283ebccf1e3SJoseph Koshy 	__P4MASK(mem-uc, 7),
1284ebccf1e3SJoseph Koshy 	__P4MASK(mem-wc, 8),
1285ebccf1e3SJoseph Koshy 	__P4MASK(mem-wt, 9),
1286ebccf1e3SJoseph Koshy 	__P4MASK(mem-wp, 10),
1287ebccf1e3SJoseph Koshy 	__P4MASK(mem-wb, 11),
1288ebccf1e3SJoseph Koshy 	__P4MASK(own, 13),
1289ebccf1e3SJoseph Koshy 	__P4MASK(other, 14),
1290ebccf1e3SJoseph Koshy 	__P4MASK(prefetch, 15),
1291ebccf1e3SJoseph Koshy 	NULLMASK
1292ebccf1e3SJoseph Koshy };
1293ebccf1e3SJoseph Koshy 
1294ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_iae[] = { /* ioq active entries */
1295ebccf1e3SJoseph Koshy 	__P4MASK(all-read, 5),
1296ebccf1e3SJoseph Koshy 	__P4MASK(all-write, 6),
1297ebccf1e3SJoseph Koshy 	__P4MASK(mem-uc, 7),
1298ebccf1e3SJoseph Koshy 	__P4MASK(mem-wc, 8),
1299ebccf1e3SJoseph Koshy 	__P4MASK(mem-wt, 9),
1300ebccf1e3SJoseph Koshy 	__P4MASK(mem-wp, 10),
1301ebccf1e3SJoseph Koshy 	__P4MASK(mem-wb, 11),
1302ebccf1e3SJoseph Koshy 	__P4MASK(own, 13),
1303ebccf1e3SJoseph Koshy 	__P4MASK(other, 14),
1304ebccf1e3SJoseph Koshy 	__P4MASK(prefetch, 15),
1305ebccf1e3SJoseph Koshy 	NULLMASK
1306ebccf1e3SJoseph Koshy };
1307ebccf1e3SJoseph Koshy 
1308ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_fda[] = { /* fsb data activity */
1309ebccf1e3SJoseph Koshy 	__P4MASK(drdy-drv, 0),
1310ebccf1e3SJoseph Koshy 	__P4MASK(drdy-own, 1),
1311ebccf1e3SJoseph Koshy 	__P4MASK(drdy-other, 2),
1312ebccf1e3SJoseph Koshy 	__P4MASK(dbsy-drv, 3),
1313ebccf1e3SJoseph Koshy 	__P4MASK(dbsy-own, 4),
1314ebccf1e3SJoseph Koshy 	__P4MASK(dbsy-other, 5),
1315ebccf1e3SJoseph Koshy 	NULLMASK
1316ebccf1e3SJoseph Koshy };
1317ebccf1e3SJoseph Koshy 
1318ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_ba[] = { /* bsq allocation */
1319ebccf1e3SJoseph Koshy 	__P4MASK(req-type0, 0),
1320ebccf1e3SJoseph Koshy 	__P4MASK(req-type1, 1),
1321ebccf1e3SJoseph Koshy 	__P4MASK(req-len0, 2),
1322ebccf1e3SJoseph Koshy 	__P4MASK(req-len1, 3),
1323ebccf1e3SJoseph Koshy 	__P4MASK(req-io-type, 5),
1324ebccf1e3SJoseph Koshy 	__P4MASK(req-lock-type, 6),
1325ebccf1e3SJoseph Koshy 	__P4MASK(req-cache-type, 7),
1326ebccf1e3SJoseph Koshy 	__P4MASK(req-split-type, 8),
1327ebccf1e3SJoseph Koshy 	__P4MASK(req-dem-type, 9),
1328ebccf1e3SJoseph Koshy 	__P4MASK(req-ord-type, 10),
1329ebccf1e3SJoseph Koshy 	__P4MASK(mem-type0, 11),
1330ebccf1e3SJoseph Koshy 	__P4MASK(mem-type1, 12),
1331ebccf1e3SJoseph Koshy 	__P4MASK(mem-type2, 13),
1332ebccf1e3SJoseph Koshy 	NULLMASK
1333ebccf1e3SJoseph Koshy };
1334ebccf1e3SJoseph Koshy 
1335ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_sia[] = { /* sse input assist */
1336ebccf1e3SJoseph Koshy 	__P4MASK(all, 15),
1337ebccf1e3SJoseph Koshy 	NULLMASK
1338ebccf1e3SJoseph Koshy };
1339ebccf1e3SJoseph Koshy 
1340ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_psu[] = { /* packed sp uop */
1341ebccf1e3SJoseph Koshy 	__P4MASK(all, 15),
1342ebccf1e3SJoseph Koshy 	NULLMASK
1343ebccf1e3SJoseph Koshy };
1344ebccf1e3SJoseph Koshy 
1345ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_pdu[] = { /* packed dp uop */
1346ebccf1e3SJoseph Koshy 	__P4MASK(all, 15),
1347ebccf1e3SJoseph Koshy 	NULLMASK
1348ebccf1e3SJoseph Koshy };
1349ebccf1e3SJoseph Koshy 
1350ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_ssu[] = { /* scalar sp uop */
1351ebccf1e3SJoseph Koshy 	__P4MASK(all, 15),
1352ebccf1e3SJoseph Koshy 	NULLMASK
1353ebccf1e3SJoseph Koshy };
1354ebccf1e3SJoseph Koshy 
1355ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_sdu[] = { /* scalar dp uop */
1356ebccf1e3SJoseph Koshy 	__P4MASK(all, 15),
1357ebccf1e3SJoseph Koshy 	NULLMASK
1358ebccf1e3SJoseph Koshy };
1359ebccf1e3SJoseph Koshy 
1360ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_64bmu[] = { /* 64 bit mmx uop */
1361ebccf1e3SJoseph Koshy 	__P4MASK(all, 15),
1362ebccf1e3SJoseph Koshy 	NULLMASK
1363ebccf1e3SJoseph Koshy };
1364ebccf1e3SJoseph Koshy 
1365ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_128bmu[] = { /* 128 bit mmx uop */
1366ebccf1e3SJoseph Koshy 	__P4MASK(all, 15),
1367ebccf1e3SJoseph Koshy 	NULLMASK
1368ebccf1e3SJoseph Koshy };
1369ebccf1e3SJoseph Koshy 
1370ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_xfu[] = { /* X87 fp uop */
1371ebccf1e3SJoseph Koshy 	__P4MASK(all, 15),
1372ebccf1e3SJoseph Koshy 	NULLMASK
1373ebccf1e3SJoseph Koshy };
1374ebccf1e3SJoseph Koshy 
1375ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_xsmu[] = { /* x87 simd moves uop */
1376ebccf1e3SJoseph Koshy 	__P4MASK(allp0, 3),
1377ebccf1e3SJoseph Koshy 	__P4MASK(allp2, 4),
1378ebccf1e3SJoseph Koshy 	NULLMASK
1379ebccf1e3SJoseph Koshy };
1380ebccf1e3SJoseph Koshy 
1381ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_gpe[] = { /* global power events */
1382ebccf1e3SJoseph Koshy 	__P4MASK(running, 0),
1383ebccf1e3SJoseph Koshy 	NULLMASK
1384ebccf1e3SJoseph Koshy };
1385ebccf1e3SJoseph Koshy 
1386ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_tmx[] = { /* TC ms xfer */
1387ebccf1e3SJoseph Koshy 	__P4MASK(cisc, 0),
1388ebccf1e3SJoseph Koshy 	NULLMASK
1389ebccf1e3SJoseph Koshy };
1390ebccf1e3SJoseph Koshy 
1391ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_uqw[] = { /* uop queue writes */
1392ebccf1e3SJoseph Koshy 	__P4MASK(from-tc-build, 0),
1393ebccf1e3SJoseph Koshy 	__P4MASK(from-tc-deliver, 1),
1394ebccf1e3SJoseph Koshy 	__P4MASK(from-rom, 2),
1395ebccf1e3SJoseph Koshy 	NULLMASK
1396ebccf1e3SJoseph Koshy };
1397ebccf1e3SJoseph Koshy 
1398d56c5d4bSJoseph Koshy static const struct pmc_masks p4_mask_rmbt[] = {
1399d56c5d4bSJoseph Koshy 	/* retired mispred branch type */
1400ebccf1e3SJoseph Koshy 	__P4MASK(conditional, 1),
1401ebccf1e3SJoseph Koshy 	__P4MASK(call, 2),
1402ebccf1e3SJoseph Koshy 	__P4MASK(return, 3),
1403ebccf1e3SJoseph Koshy 	__P4MASK(indirect, 4),
1404ebccf1e3SJoseph Koshy 	NULLMASK
1405ebccf1e3SJoseph Koshy };
1406ebccf1e3SJoseph Koshy 
1407ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_rbt[] = { /* retired branch type */
1408ebccf1e3SJoseph Koshy 	__P4MASK(conditional, 1),
1409ebccf1e3SJoseph Koshy 	__P4MASK(call, 2),
1410ebccf1e3SJoseph Koshy 	__P4MASK(retired, 3),
1411ebccf1e3SJoseph Koshy 	__P4MASK(indirect, 4),
1412ebccf1e3SJoseph Koshy 	NULLMASK
1413ebccf1e3SJoseph Koshy };
1414ebccf1e3SJoseph Koshy 
1415ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_rs[] = { /* resource stall */
1416ebccf1e3SJoseph Koshy 	__P4MASK(sbfull, 5),
1417ebccf1e3SJoseph Koshy 	NULLMASK
1418ebccf1e3SJoseph Koshy };
1419ebccf1e3SJoseph Koshy 
1420ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_wb[] = { /* WC buffer */
1421ebccf1e3SJoseph Koshy 	__P4MASK(wcb-evicts, 0),
1422ebccf1e3SJoseph Koshy 	__P4MASK(wcb-full-evict, 1),
1423ebccf1e3SJoseph Koshy 	NULLMASK
1424ebccf1e3SJoseph Koshy };
1425ebccf1e3SJoseph Koshy 
1426ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_fee[] = { /* front end event */
1427ebccf1e3SJoseph Koshy 	__P4MASK(nbogus, 0),
1428ebccf1e3SJoseph Koshy 	__P4MASK(bogus, 1),
1429ebccf1e3SJoseph Koshy 	NULLMASK
1430ebccf1e3SJoseph Koshy };
1431ebccf1e3SJoseph Koshy 
1432ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_ee[] = { /* execution event */
1433ebccf1e3SJoseph Koshy 	__P4MASK(nbogus0, 0),
1434ebccf1e3SJoseph Koshy 	__P4MASK(nbogus1, 1),
1435ebccf1e3SJoseph Koshy 	__P4MASK(nbogus2, 2),
1436ebccf1e3SJoseph Koshy 	__P4MASK(nbogus3, 3),
1437ebccf1e3SJoseph Koshy 	__P4MASK(bogus0, 4),
1438ebccf1e3SJoseph Koshy 	__P4MASK(bogus1, 5),
1439ebccf1e3SJoseph Koshy 	__P4MASK(bogus2, 6),
1440ebccf1e3SJoseph Koshy 	__P4MASK(bogus3, 7),
1441ebccf1e3SJoseph Koshy 	NULLMASK
1442ebccf1e3SJoseph Koshy };
1443ebccf1e3SJoseph Koshy 
1444ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_re[] = { /* replay event */
1445ebccf1e3SJoseph Koshy 	__P4MASK(nbogus, 0),
1446ebccf1e3SJoseph Koshy 	__P4MASK(bogus, 1),
1447ebccf1e3SJoseph Koshy 	NULLMASK
1448ebccf1e3SJoseph Koshy };
1449ebccf1e3SJoseph Koshy 
1450ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_insret[] = { /* instr retired */
1451ebccf1e3SJoseph Koshy 	__P4MASK(nbogusntag, 0),
1452ebccf1e3SJoseph Koshy 	__P4MASK(nbogustag, 1),
1453ebccf1e3SJoseph Koshy 	__P4MASK(bogusntag, 2),
1454ebccf1e3SJoseph Koshy 	__P4MASK(bogustag, 3),
1455ebccf1e3SJoseph Koshy 	NULLMASK
1456ebccf1e3SJoseph Koshy };
1457ebccf1e3SJoseph Koshy 
1458ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_ur[] = { /* uops retired */
1459ebccf1e3SJoseph Koshy 	__P4MASK(nbogus, 0),
1460ebccf1e3SJoseph Koshy 	__P4MASK(bogus, 1),
1461ebccf1e3SJoseph Koshy 	NULLMASK
1462ebccf1e3SJoseph Koshy };
1463ebccf1e3SJoseph Koshy 
1464ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_ut[] = { /* uop type */
1465ebccf1e3SJoseph Koshy 	__P4MASK(tagloads, 1),
1466ebccf1e3SJoseph Koshy 	__P4MASK(tagstores, 2),
1467ebccf1e3SJoseph Koshy 	NULLMASK
1468ebccf1e3SJoseph Koshy };
1469ebccf1e3SJoseph Koshy 
1470ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_br[] = { /* branch retired */
1471ebccf1e3SJoseph Koshy 	__P4MASK(mmnp, 0),
1472ebccf1e3SJoseph Koshy 	__P4MASK(mmnm, 1),
1473ebccf1e3SJoseph Koshy 	__P4MASK(mmtp, 2),
1474ebccf1e3SJoseph Koshy 	__P4MASK(mmtm, 3),
1475ebccf1e3SJoseph Koshy 	NULLMASK
1476ebccf1e3SJoseph Koshy };
1477ebccf1e3SJoseph Koshy 
1478ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_mbr[] = { /* mispred branch retired */
1479ebccf1e3SJoseph Koshy 	__P4MASK(nbogus, 0),
1480ebccf1e3SJoseph Koshy 	NULLMASK
1481ebccf1e3SJoseph Koshy };
1482ebccf1e3SJoseph Koshy 
1483ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_xa[] = { /* x87 assist */
1484ebccf1e3SJoseph Koshy 	__P4MASK(fpsu, 0),
1485ebccf1e3SJoseph Koshy 	__P4MASK(fpso, 1),
1486ebccf1e3SJoseph Koshy 	__P4MASK(poao, 2),
1487ebccf1e3SJoseph Koshy 	__P4MASK(poau, 3),
1488ebccf1e3SJoseph Koshy 	__P4MASK(prea, 4),
1489ebccf1e3SJoseph Koshy 	NULLMASK
1490ebccf1e3SJoseph Koshy };
1491ebccf1e3SJoseph Koshy 
1492ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_machclr[] = { /* machine clear */
1493ebccf1e3SJoseph Koshy 	__P4MASK(clear, 0),
1494ebccf1e3SJoseph Koshy 	__P4MASK(moclear, 2),
1495ebccf1e3SJoseph Koshy 	__P4MASK(smclear, 3),
1496ebccf1e3SJoseph Koshy 	NULLMASK
1497ebccf1e3SJoseph Koshy };
1498ebccf1e3SJoseph Koshy 
1499ebccf1e3SJoseph Koshy /* P4 event parser */
1500ebccf1e3SJoseph Koshy static int
1501ebccf1e3SJoseph Koshy p4_allocate_pmc(enum pmc_event pe, char *ctrspec,
1502ebccf1e3SJoseph Koshy     struct pmc_op_pmcallocate *pmc_config)
1503ebccf1e3SJoseph Koshy {
1504ebccf1e3SJoseph Koshy 
1505ebccf1e3SJoseph Koshy 	char	*e, *p, *q;
1506ebccf1e3SJoseph Koshy 	int	count, has_tag, has_busreqtype, n;
1507ebccf1e3SJoseph Koshy 	uint32_t evmask, cccractivemask;
1508ebccf1e3SJoseph Koshy 	const struct pmc_masks *pm, *pmask;
1509ebccf1e3SJoseph Koshy 
1510789140c0SJoseph Koshy 	pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE);
1511f263522aSJoseph Koshy 	pmc_config->pm_md.pm_p4.pm_p4_cccrconfig =
1512f263522aSJoseph Koshy 	    pmc_config->pm_md.pm_p4.pm_p4_escrconfig = 0;
1513ebccf1e3SJoseph Koshy 
1514ebccf1e3SJoseph Koshy 	pmask   = NULL;
1515ebccf1e3SJoseph Koshy 	evmask  = 0;
1516ebccf1e3SJoseph Koshy 	cccractivemask = 0x3;
1517ebccf1e3SJoseph Koshy 	has_tag = has_busreqtype = 0;
1518ebccf1e3SJoseph Koshy 
1519ebccf1e3SJoseph Koshy #define	__P4SETMASK(M) do {				\
1520ebccf1e3SJoseph Koshy 	pmask = p4_mask_##M;				\
1521ebccf1e3SJoseph Koshy } while (0)
1522ebccf1e3SJoseph Koshy 
1523ebccf1e3SJoseph Koshy 	switch (pe) {
1524ebccf1e3SJoseph Koshy 	case PMC_EV_P4_TC_DELIVER_MODE:
1525ebccf1e3SJoseph Koshy 		__P4SETMASK(tcdm);
1526ebccf1e3SJoseph Koshy 		break;
1527ebccf1e3SJoseph Koshy 	case PMC_EV_P4_BPU_FETCH_REQUEST:
1528ebccf1e3SJoseph Koshy 		__P4SETMASK(bfr);
1529ebccf1e3SJoseph Koshy 		break;
1530ebccf1e3SJoseph Koshy 	case PMC_EV_P4_ITLB_REFERENCE:
1531ebccf1e3SJoseph Koshy 		__P4SETMASK(ir);
1532ebccf1e3SJoseph Koshy 		break;
1533ebccf1e3SJoseph Koshy 	case PMC_EV_P4_MEMORY_CANCEL:
1534ebccf1e3SJoseph Koshy 		__P4SETMASK(memcan);
1535ebccf1e3SJoseph Koshy 		break;
1536ebccf1e3SJoseph Koshy 	case PMC_EV_P4_MEMORY_COMPLETE:
1537ebccf1e3SJoseph Koshy 		__P4SETMASK(memcomp);
1538ebccf1e3SJoseph Koshy 		break;
1539ebccf1e3SJoseph Koshy 	case PMC_EV_P4_LOAD_PORT_REPLAY:
1540ebccf1e3SJoseph Koshy 		__P4SETMASK(lpr);
1541ebccf1e3SJoseph Koshy 		break;
1542ebccf1e3SJoseph Koshy 	case PMC_EV_P4_STORE_PORT_REPLAY:
1543ebccf1e3SJoseph Koshy 		__P4SETMASK(spr);
1544ebccf1e3SJoseph Koshy 		break;
1545ebccf1e3SJoseph Koshy 	case PMC_EV_P4_MOB_LOAD_REPLAY:
1546ebccf1e3SJoseph Koshy 		__P4SETMASK(mlr);
1547ebccf1e3SJoseph Koshy 		break;
1548ebccf1e3SJoseph Koshy 	case PMC_EV_P4_PAGE_WALK_TYPE:
1549ebccf1e3SJoseph Koshy 		__P4SETMASK(pwt);
1550ebccf1e3SJoseph Koshy 		break;
1551ebccf1e3SJoseph Koshy 	case PMC_EV_P4_BSQ_CACHE_REFERENCE:
1552ebccf1e3SJoseph Koshy 		__P4SETMASK(bcr);
1553ebccf1e3SJoseph Koshy 		break;
1554ebccf1e3SJoseph Koshy 	case PMC_EV_P4_IOQ_ALLOCATION:
1555ebccf1e3SJoseph Koshy 		__P4SETMASK(ia);
1556ebccf1e3SJoseph Koshy 		has_busreqtype = 1;
1557ebccf1e3SJoseph Koshy 		break;
1558ebccf1e3SJoseph Koshy 	case PMC_EV_P4_IOQ_ACTIVE_ENTRIES:
1559ebccf1e3SJoseph Koshy 		__P4SETMASK(iae);
1560ebccf1e3SJoseph Koshy 		has_busreqtype = 1;
1561ebccf1e3SJoseph Koshy 		break;
1562ebccf1e3SJoseph Koshy 	case PMC_EV_P4_FSB_DATA_ACTIVITY:
1563ebccf1e3SJoseph Koshy 		__P4SETMASK(fda);
1564ebccf1e3SJoseph Koshy 		break;
1565ebccf1e3SJoseph Koshy 	case PMC_EV_P4_BSQ_ALLOCATION:
1566ebccf1e3SJoseph Koshy 		__P4SETMASK(ba);
1567ebccf1e3SJoseph Koshy 		break;
1568ebccf1e3SJoseph Koshy 	case PMC_EV_P4_SSE_INPUT_ASSIST:
1569ebccf1e3SJoseph Koshy 		__P4SETMASK(sia);
1570ebccf1e3SJoseph Koshy 		break;
1571ebccf1e3SJoseph Koshy 	case PMC_EV_P4_PACKED_SP_UOP:
1572ebccf1e3SJoseph Koshy 		__P4SETMASK(psu);
1573ebccf1e3SJoseph Koshy 		break;
1574ebccf1e3SJoseph Koshy 	case PMC_EV_P4_PACKED_DP_UOP:
1575ebccf1e3SJoseph Koshy 		__P4SETMASK(pdu);
1576ebccf1e3SJoseph Koshy 		break;
1577ebccf1e3SJoseph Koshy 	case PMC_EV_P4_SCALAR_SP_UOP:
1578ebccf1e3SJoseph Koshy 		__P4SETMASK(ssu);
1579ebccf1e3SJoseph Koshy 		break;
1580ebccf1e3SJoseph Koshy 	case PMC_EV_P4_SCALAR_DP_UOP:
1581ebccf1e3SJoseph Koshy 		__P4SETMASK(sdu);
1582ebccf1e3SJoseph Koshy 		break;
1583ebccf1e3SJoseph Koshy 	case PMC_EV_P4_64BIT_MMX_UOP:
1584ebccf1e3SJoseph Koshy 		__P4SETMASK(64bmu);
1585ebccf1e3SJoseph Koshy 		break;
1586ebccf1e3SJoseph Koshy 	case PMC_EV_P4_128BIT_MMX_UOP:
1587ebccf1e3SJoseph Koshy 		__P4SETMASK(128bmu);
1588ebccf1e3SJoseph Koshy 		break;
1589ebccf1e3SJoseph Koshy 	case PMC_EV_P4_X87_FP_UOP:
1590ebccf1e3SJoseph Koshy 		__P4SETMASK(xfu);
1591ebccf1e3SJoseph Koshy 		break;
1592ebccf1e3SJoseph Koshy 	case PMC_EV_P4_X87_SIMD_MOVES_UOP:
1593ebccf1e3SJoseph Koshy 		__P4SETMASK(xsmu);
1594ebccf1e3SJoseph Koshy 		break;
1595ebccf1e3SJoseph Koshy 	case PMC_EV_P4_GLOBAL_POWER_EVENTS:
1596ebccf1e3SJoseph Koshy 		__P4SETMASK(gpe);
1597ebccf1e3SJoseph Koshy 		break;
1598ebccf1e3SJoseph Koshy 	case PMC_EV_P4_TC_MS_XFER:
1599ebccf1e3SJoseph Koshy 		__P4SETMASK(tmx);
1600ebccf1e3SJoseph Koshy 		break;
1601ebccf1e3SJoseph Koshy 	case PMC_EV_P4_UOP_QUEUE_WRITES:
1602ebccf1e3SJoseph Koshy 		__P4SETMASK(uqw);
1603ebccf1e3SJoseph Koshy 		break;
1604ebccf1e3SJoseph Koshy 	case PMC_EV_P4_RETIRED_MISPRED_BRANCH_TYPE:
1605ebccf1e3SJoseph Koshy 		__P4SETMASK(rmbt);
1606ebccf1e3SJoseph Koshy 		break;
1607ebccf1e3SJoseph Koshy 	case PMC_EV_P4_RETIRED_BRANCH_TYPE:
1608ebccf1e3SJoseph Koshy 		__P4SETMASK(rbt);
1609ebccf1e3SJoseph Koshy 		break;
1610ebccf1e3SJoseph Koshy 	case PMC_EV_P4_RESOURCE_STALL:
1611ebccf1e3SJoseph Koshy 		__P4SETMASK(rs);
1612ebccf1e3SJoseph Koshy 		break;
1613ebccf1e3SJoseph Koshy 	case PMC_EV_P4_WC_BUFFER:
1614ebccf1e3SJoseph Koshy 		__P4SETMASK(wb);
1615ebccf1e3SJoseph Koshy 		break;
1616ebccf1e3SJoseph Koshy 	case PMC_EV_P4_BSQ_ACTIVE_ENTRIES:
1617ebccf1e3SJoseph Koshy 	case PMC_EV_P4_B2B_CYCLES:
1618ebccf1e3SJoseph Koshy 	case PMC_EV_P4_BNR:
1619ebccf1e3SJoseph Koshy 	case PMC_EV_P4_SNOOP:
1620ebccf1e3SJoseph Koshy 	case PMC_EV_P4_RESPONSE:
1621ebccf1e3SJoseph Koshy 		break;
1622ebccf1e3SJoseph Koshy 	case PMC_EV_P4_FRONT_END_EVENT:
1623ebccf1e3SJoseph Koshy 		__P4SETMASK(fee);
1624ebccf1e3SJoseph Koshy 		break;
1625ebccf1e3SJoseph Koshy 	case PMC_EV_P4_EXECUTION_EVENT:
1626ebccf1e3SJoseph Koshy 		__P4SETMASK(ee);
1627ebccf1e3SJoseph Koshy 		break;
1628ebccf1e3SJoseph Koshy 	case PMC_EV_P4_REPLAY_EVENT:
1629ebccf1e3SJoseph Koshy 		__P4SETMASK(re);
1630ebccf1e3SJoseph Koshy 		break;
1631ebccf1e3SJoseph Koshy 	case PMC_EV_P4_INSTR_RETIRED:
1632ebccf1e3SJoseph Koshy 		__P4SETMASK(insret);
1633ebccf1e3SJoseph Koshy 		break;
1634ebccf1e3SJoseph Koshy 	case PMC_EV_P4_UOPS_RETIRED:
1635ebccf1e3SJoseph Koshy 		__P4SETMASK(ur);
1636ebccf1e3SJoseph Koshy 		break;
1637ebccf1e3SJoseph Koshy 	case PMC_EV_P4_UOP_TYPE:
1638ebccf1e3SJoseph Koshy 		__P4SETMASK(ut);
1639ebccf1e3SJoseph Koshy 		break;
1640ebccf1e3SJoseph Koshy 	case PMC_EV_P4_BRANCH_RETIRED:
1641ebccf1e3SJoseph Koshy 		__P4SETMASK(br);
1642ebccf1e3SJoseph Koshy 		break;
1643ebccf1e3SJoseph Koshy 	case PMC_EV_P4_MISPRED_BRANCH_RETIRED:
1644ebccf1e3SJoseph Koshy 		__P4SETMASK(mbr);
1645ebccf1e3SJoseph Koshy 		break;
1646ebccf1e3SJoseph Koshy 	case PMC_EV_P4_X87_ASSIST:
1647ebccf1e3SJoseph Koshy 		__P4SETMASK(xa);
1648ebccf1e3SJoseph Koshy 		break;
1649ebccf1e3SJoseph Koshy 	case PMC_EV_P4_MACHINE_CLEAR:
1650ebccf1e3SJoseph Koshy 		__P4SETMASK(machclr);
1651ebccf1e3SJoseph Koshy 		break;
1652ebccf1e3SJoseph Koshy 	default:
1653aa342b1fSJoseph Koshy 		return (-1);
1654ebccf1e3SJoseph Koshy 	}
1655ebccf1e3SJoseph Koshy 
1656ebccf1e3SJoseph Koshy 	/* process additional flags */
1657ebccf1e3SJoseph Koshy 	while ((p = strsep(&ctrspec, ",")) != NULL) {
1658ebccf1e3SJoseph Koshy 		if (KWPREFIXMATCH(p, P4_KW_ACTIVE)) {
1659ebccf1e3SJoseph Koshy 			q = strchr(p, '=');
1660ebccf1e3SJoseph Koshy 			if (*++q == '\0') /* skip '=' */
1661aa342b1fSJoseph Koshy 				return (-1);
1662ebccf1e3SJoseph Koshy 
1663789140c0SJoseph Koshy 			if (strcasecmp(q, P4_KW_ACTIVE_NONE) == 0)
1664ebccf1e3SJoseph Koshy 				cccractivemask = 0x0;
1665789140c0SJoseph Koshy 			else if (strcasecmp(q, P4_KW_ACTIVE_SINGLE) == 0)
1666ebccf1e3SJoseph Koshy 				cccractivemask = 0x1;
1667789140c0SJoseph Koshy 			else if (strcasecmp(q, P4_KW_ACTIVE_BOTH) == 0)
1668ebccf1e3SJoseph Koshy 				cccractivemask = 0x2;
1669789140c0SJoseph Koshy 			else if (strcasecmp(q, P4_KW_ACTIVE_ANY) == 0)
1670ebccf1e3SJoseph Koshy 				cccractivemask = 0x3;
1671ebccf1e3SJoseph Koshy 			else
1672aa342b1fSJoseph Koshy 				return (-1);
1673ebccf1e3SJoseph Koshy 
1674ebccf1e3SJoseph Koshy 		} else if (KWPREFIXMATCH(p, P4_KW_BUSREQTYPE)) {
1675ebccf1e3SJoseph Koshy 			if (has_busreqtype == 0)
1676aa342b1fSJoseph Koshy 				return (-1);
1677ebccf1e3SJoseph Koshy 
1678ebccf1e3SJoseph Koshy 			q = strchr(p, '=');
1679ebccf1e3SJoseph Koshy 			if (*++q == '\0') /* skip '=' */
1680aa342b1fSJoseph Koshy 				return (-1);
1681ebccf1e3SJoseph Koshy 
1682ebccf1e3SJoseph Koshy 			count = strtol(q, &e, 0);
1683ebccf1e3SJoseph Koshy 			if (e == q || *e != '\0')
1684aa342b1fSJoseph Koshy 				return (-1);
1685ebccf1e3SJoseph Koshy 			evmask = (evmask & ~0x1F) | (count & 0x1F);
1686ebccf1e3SJoseph Koshy 		} else if (KWMATCH(p, P4_KW_CASCADE))
1687ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_CASCADE;
1688ebccf1e3SJoseph Koshy 		else if (KWMATCH(p, P4_KW_EDGE))
1689ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_EDGE;
1690ebccf1e3SJoseph Koshy 		else if (KWMATCH(p, P4_KW_INV))
1691ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_INVERT;
1692ebccf1e3SJoseph Koshy 		else if (KWPREFIXMATCH(p, P4_KW_MASK "=")) {
1693ebccf1e3SJoseph Koshy 			if ((n = pmc_parse_mask(pmask, p, &evmask)) < 0)
1694aa342b1fSJoseph Koshy 				return (-1);
1695ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_QUALIFIER;
1696ebccf1e3SJoseph Koshy 		} else if (KWMATCH(p, P4_KW_OS))
1697ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_SYSTEM;
1698ebccf1e3SJoseph Koshy 		else if (KWMATCH(p, P4_KW_PRECISE))
1699ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_PRECISE;
1700ebccf1e3SJoseph Koshy 		else if (KWPREFIXMATCH(p, P4_KW_TAG "=")) {
1701ebccf1e3SJoseph Koshy 			if (has_tag == 0)
1702aa342b1fSJoseph Koshy 				return (-1);
1703ebccf1e3SJoseph Koshy 
1704ebccf1e3SJoseph Koshy 			q = strchr(p, '=');
1705ebccf1e3SJoseph Koshy 			if (*++q == '\0') /* skip '=' */
1706aa342b1fSJoseph Koshy 				return (-1);
1707ebccf1e3SJoseph Koshy 
1708ebccf1e3SJoseph Koshy 			count = strtol(q, &e, 0);
1709ebccf1e3SJoseph Koshy 			if (e == q || *e != '\0')
1710aa342b1fSJoseph Koshy 				return (-1);
1711ebccf1e3SJoseph Koshy 
1712ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_TAGGING;
1713f263522aSJoseph Koshy 			pmc_config->pm_md.pm_p4.pm_p4_escrconfig |=
1714ebccf1e3SJoseph Koshy 			    P4_ESCR_TO_TAG_VALUE(count);
1715ebccf1e3SJoseph Koshy 		} else if (KWPREFIXMATCH(p, P4_KW_THRESHOLD "=")) {
1716ebccf1e3SJoseph Koshy 			q = strchr(p, '=');
1717ebccf1e3SJoseph Koshy 			if (*++q == '\0') /* skip '=' */
1718aa342b1fSJoseph Koshy 				return (-1);
1719ebccf1e3SJoseph Koshy 
1720ebccf1e3SJoseph Koshy 			count = strtol(q, &e, 0);
1721ebccf1e3SJoseph Koshy 			if (e == q || *e != '\0')
1722aa342b1fSJoseph Koshy 				return (-1);
1723ebccf1e3SJoseph Koshy 
1724ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_THRESHOLD;
1725f263522aSJoseph Koshy 			pmc_config->pm_md.pm_p4.pm_p4_cccrconfig &=
1726f263522aSJoseph Koshy 			    ~P4_CCCR_THRESHOLD_MASK;
1727f263522aSJoseph Koshy 			pmc_config->pm_md.pm_p4.pm_p4_cccrconfig |=
1728f263522aSJoseph Koshy 			    P4_CCCR_TO_THRESHOLD(count);
1729ebccf1e3SJoseph Koshy 		} else if (KWMATCH(p, P4_KW_USR))
1730ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_USER;
1731ebccf1e3SJoseph Koshy 		else
1732aa342b1fSJoseph Koshy 			return (-1);
1733ebccf1e3SJoseph Koshy 	}
1734ebccf1e3SJoseph Koshy 
1735ebccf1e3SJoseph Koshy 	/* other post processing */
1736ebccf1e3SJoseph Koshy 	if (pe == PMC_EV_P4_IOQ_ALLOCATION ||
1737ebccf1e3SJoseph Koshy 	    pe == PMC_EV_P4_FSB_DATA_ACTIVITY ||
1738ebccf1e3SJoseph Koshy 	    pe == PMC_EV_P4_BSQ_ALLOCATION)
1739ebccf1e3SJoseph Koshy 		pmc_config->pm_caps |= PMC_CAP_EDGE;
1740ebccf1e3SJoseph Koshy 
1741ebccf1e3SJoseph Koshy 	/* fill in thread activity mask */
1742f263522aSJoseph Koshy 	pmc_config->pm_md.pm_p4.pm_p4_cccrconfig |=
1743ebccf1e3SJoseph Koshy 	    P4_CCCR_TO_ACTIVE_THREAD(cccractivemask);
1744ebccf1e3SJoseph Koshy 
1745ebccf1e3SJoseph Koshy 	if (evmask)
1746ebccf1e3SJoseph Koshy 		pmc_config->pm_caps |= PMC_CAP_QUALIFIER;
1747ebccf1e3SJoseph Koshy 
1748ebccf1e3SJoseph Koshy 	switch (pe) {
1749ebccf1e3SJoseph Koshy 	case PMC_EV_P4_FSB_DATA_ACTIVITY:
1750ebccf1e3SJoseph Koshy 		if ((evmask & 0x06) == 0x06 ||
1751ebccf1e3SJoseph Koshy 		    (evmask & 0x18) == 0x18)
1752aa342b1fSJoseph Koshy 			return (-1); /* can't have own+other bits together */
1753ebccf1e3SJoseph Koshy 		if (evmask == 0) /* default:drdy-{drv,own}+dbsy{drv,own} */
1754ebccf1e3SJoseph Koshy 			evmask = 0x1D;
1755ebccf1e3SJoseph Koshy 		break;
1756ebccf1e3SJoseph Koshy 	case PMC_EV_P4_MACHINE_CLEAR:
1757ebccf1e3SJoseph Koshy 		/* only one bit is allowed to be set */
1758ebccf1e3SJoseph Koshy 		if ((evmask & (evmask - 1)) != 0)
1759aa342b1fSJoseph Koshy 			return (-1);
1760ebccf1e3SJoseph Koshy 		if (evmask == 0) {
1761ebccf1e3SJoseph Koshy 			evmask = 0x1;	/* 'CLEAR' */
1762ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_QUALIFIER;
1763ebccf1e3SJoseph Koshy 		}
1764ebccf1e3SJoseph Koshy 		break;
1765ebccf1e3SJoseph Koshy 	default:
1766ebccf1e3SJoseph Koshy 		if (evmask == 0 && pmask) {
1767ebccf1e3SJoseph Koshy 			for (pm = pmask; pm->pm_name; pm++)
1768ebccf1e3SJoseph Koshy 				evmask |= pm->pm_value;
1769ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_QUALIFIER;
1770ebccf1e3SJoseph Koshy 		}
1771ebccf1e3SJoseph Koshy 	}
1772ebccf1e3SJoseph Koshy 
1773f263522aSJoseph Koshy 	pmc_config->pm_md.pm_p4.pm_p4_escrconfig =
1774f263522aSJoseph Koshy 	    P4_ESCR_TO_EVENT_MASK(evmask);
1775ebccf1e3SJoseph Koshy 
1776aa342b1fSJoseph Koshy 	return (0);
1777ebccf1e3SJoseph Koshy }
1778ebccf1e3SJoseph Koshy 
177986a65549SJoseph Koshy #endif
178086a65549SJoseph Koshy 
178186a65549SJoseph Koshy #if defined(__i386__)
178286a65549SJoseph Koshy 
1783ebccf1e3SJoseph Koshy /*
1784f263522aSJoseph Koshy  * Pentium style PMCs
1785f263522aSJoseph Koshy  */
1786f263522aSJoseph Koshy 
1787f263522aSJoseph Koshy static struct pmc_event_alias p5_aliases[] = {
17880b9b757dSJoseph Koshy 	EV_ALIAS("branches",		"p5-taken-branches"),
1789f263522aSJoseph Koshy 	EV_ALIAS("cycles",		"tsc"),
17900b9b757dSJoseph Koshy 	EV_ALIAS("dc-misses",		"p5-data-read-miss-or-write-miss"),
17910b9b757dSJoseph Koshy 	EV_ALIAS("ic-misses",		"p5-code-cache-miss"),
17920b9b757dSJoseph Koshy 	EV_ALIAS("instructions",	"p5-instructions-executed"),
17930b9b757dSJoseph Koshy 	EV_ALIAS("interrupts",		"p5-hardware-interrupts"),
17940b9b757dSJoseph Koshy 	EV_ALIAS("unhalted-cycles",
17950b9b757dSJoseph Koshy 	    "p5-number-of-cycles-not-in-halt-state"),
1796f263522aSJoseph Koshy 	EV_ALIAS(NULL, NULL)
1797f263522aSJoseph Koshy };
1798f263522aSJoseph Koshy 
1799f263522aSJoseph Koshy static int
1800f263522aSJoseph Koshy p5_allocate_pmc(enum pmc_event pe, char *ctrspec,
1801f263522aSJoseph Koshy     struct pmc_op_pmcallocate *pmc_config)
1802f263522aSJoseph Koshy {
1803aa342b1fSJoseph Koshy 	return (-1 || pe || ctrspec || pmc_config); /* shut up gcc */
1804f263522aSJoseph Koshy }
1805f263522aSJoseph Koshy 
1806f263522aSJoseph Koshy /*
1807ebccf1e3SJoseph Koshy  * Pentium Pro style PMCs.  These PMCs are found in Pentium II, Pentium III,
1808ebccf1e3SJoseph Koshy  * and Pentium M CPUs.
1809ebccf1e3SJoseph Koshy  */
1810ebccf1e3SJoseph Koshy 
1811ebccf1e3SJoseph Koshy static struct pmc_event_alias p6_aliases[] = {
1812ebccf1e3SJoseph Koshy 	EV_ALIAS("branches",		"p6-br-inst-retired"),
1813ebccf1e3SJoseph Koshy 	EV_ALIAS("branch-mispredicts",	"p6-br-miss-pred-retired"),
1814ebccf1e3SJoseph Koshy 	EV_ALIAS("cycles",		"tsc"),
1815d56c5d4bSJoseph Koshy 	EV_ALIAS("dc-misses",		"p6-dcu-lines-in"),
181673e2d811SJoseph Koshy 	EV_ALIAS("ic-misses",		"p6-ifu-fetch-miss"),
1817ebccf1e3SJoseph Koshy 	EV_ALIAS("instructions",	"p6-inst-retired"),
1818ebccf1e3SJoseph Koshy 	EV_ALIAS("interrupts",		"p6-hw-int-rx"),
1819177a2f22SJoseph Koshy 	EV_ALIAS("unhalted-cycles",	"p6-cpu-clk-unhalted"),
1820ebccf1e3SJoseph Koshy 	EV_ALIAS(NULL, NULL)
1821ebccf1e3SJoseph Koshy };
1822ebccf1e3SJoseph Koshy 
1823ebccf1e3SJoseph Koshy #define	P6_KW_CMASK	"cmask"
1824ebccf1e3SJoseph Koshy #define	P6_KW_EDGE	"edge"
1825ebccf1e3SJoseph Koshy #define	P6_KW_INV	"inv"
1826ebccf1e3SJoseph Koshy #define	P6_KW_OS	"os"
1827ebccf1e3SJoseph Koshy #define	P6_KW_UMASK	"umask"
1828ebccf1e3SJoseph Koshy #define	P6_KW_USR	"usr"
1829ebccf1e3SJoseph Koshy 
1830ebccf1e3SJoseph Koshy static struct pmc_masks p6_mask_mesi[] = {
1831ebccf1e3SJoseph Koshy 	PMCMASK(m,	0x01),
1832ebccf1e3SJoseph Koshy 	PMCMASK(e,	0x02),
1833ebccf1e3SJoseph Koshy 	PMCMASK(s,	0x04),
1834ebccf1e3SJoseph Koshy 	PMCMASK(i,	0x08),
1835ebccf1e3SJoseph Koshy 	NULLMASK
1836ebccf1e3SJoseph Koshy };
1837ebccf1e3SJoseph Koshy 
1838ebccf1e3SJoseph Koshy static struct pmc_masks p6_mask_mesihw[] = {
1839ebccf1e3SJoseph Koshy 	PMCMASK(m,	0x01),
1840ebccf1e3SJoseph Koshy 	PMCMASK(e,	0x02),
1841ebccf1e3SJoseph Koshy 	PMCMASK(s,	0x04),
1842ebccf1e3SJoseph Koshy 	PMCMASK(i,	0x08),
1843ebccf1e3SJoseph Koshy 	PMCMASK(nonhw,	0x00),
1844ebccf1e3SJoseph Koshy 	PMCMASK(hw,	0x10),
1845ebccf1e3SJoseph Koshy 	PMCMASK(both,	0x30),
1846ebccf1e3SJoseph Koshy 	NULLMASK
1847ebccf1e3SJoseph Koshy };
1848ebccf1e3SJoseph Koshy 
1849ebccf1e3SJoseph Koshy static struct pmc_masks p6_mask_hw[] = {
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_any[] = {
1857ebccf1e3SJoseph Koshy 	PMCMASK(self,	0x00),
1858ebccf1e3SJoseph Koshy 	PMCMASK(any,	0x20),
1859ebccf1e3SJoseph Koshy 	NULLMASK
1860ebccf1e3SJoseph Koshy };
1861ebccf1e3SJoseph Koshy 
1862ebccf1e3SJoseph Koshy static struct pmc_masks p6_mask_ekp[] = {
1863ebccf1e3SJoseph Koshy 	PMCMASK(nta,	0x00),
1864ebccf1e3SJoseph Koshy 	PMCMASK(t1,	0x01),
1865ebccf1e3SJoseph Koshy 	PMCMASK(t2,	0x02),
1866ebccf1e3SJoseph Koshy 	PMCMASK(wos,	0x03),
1867ebccf1e3SJoseph Koshy 	NULLMASK
1868ebccf1e3SJoseph Koshy };
1869ebccf1e3SJoseph Koshy 
1870ebccf1e3SJoseph Koshy static struct pmc_masks p6_mask_pps[] = {
1871ebccf1e3SJoseph Koshy 	PMCMASK(packed-and-scalar, 0x00),
1872ebccf1e3SJoseph Koshy 	PMCMASK(scalar,	0x01),
1873ebccf1e3SJoseph Koshy 	NULLMASK
1874ebccf1e3SJoseph Koshy };
1875ebccf1e3SJoseph Koshy 
1876ebccf1e3SJoseph Koshy static struct pmc_masks p6_mask_mite[] = {
1877ebccf1e3SJoseph Koshy 	PMCMASK(packed-multiply,	 0x01),
1878ebccf1e3SJoseph Koshy 	PMCMASK(packed-shift,		0x02),
1879ebccf1e3SJoseph Koshy 	PMCMASK(pack,			0x04),
1880ebccf1e3SJoseph Koshy 	PMCMASK(unpack,			0x08),
1881ebccf1e3SJoseph Koshy 	PMCMASK(packed-logical,		0x10),
1882ebccf1e3SJoseph Koshy 	PMCMASK(packed-arithmetic,	0x20),
1883ebccf1e3SJoseph Koshy 	NULLMASK
1884ebccf1e3SJoseph Koshy };
1885ebccf1e3SJoseph Koshy 
1886ebccf1e3SJoseph Koshy static struct pmc_masks p6_mask_fmt[] = {
1887ebccf1e3SJoseph Koshy 	PMCMASK(mmxtofp,	0x00),
1888ebccf1e3SJoseph Koshy 	PMCMASK(fptommx,	0x01),
1889ebccf1e3SJoseph Koshy 	NULLMASK
1890ebccf1e3SJoseph Koshy };
1891ebccf1e3SJoseph Koshy 
1892ebccf1e3SJoseph Koshy static struct pmc_masks p6_mask_sr[] = {
1893ebccf1e3SJoseph Koshy 	PMCMASK(es,	0x01),
1894ebccf1e3SJoseph Koshy 	PMCMASK(ds,	0x02),
1895ebccf1e3SJoseph Koshy 	PMCMASK(fs,	0x04),
1896ebccf1e3SJoseph Koshy 	PMCMASK(gs,	0x08),
1897ebccf1e3SJoseph Koshy 	NULLMASK
1898ebccf1e3SJoseph Koshy };
1899ebccf1e3SJoseph Koshy 
1900ebccf1e3SJoseph Koshy static struct pmc_masks p6_mask_eet[] = {
1901ebccf1e3SJoseph Koshy 	PMCMASK(all,	0x00),
1902ebccf1e3SJoseph Koshy 	PMCMASK(freq,	0x02),
1903ebccf1e3SJoseph Koshy 	NULLMASK
1904ebccf1e3SJoseph Koshy };
1905ebccf1e3SJoseph Koshy 
1906ebccf1e3SJoseph Koshy static struct pmc_masks p6_mask_efur[] = {
1907ebccf1e3SJoseph Koshy 	PMCMASK(all,	0x00),
1908ebccf1e3SJoseph Koshy 	PMCMASK(loadop,	0x01),
1909ebccf1e3SJoseph Koshy 	PMCMASK(stdsta,	0x02),
1910ebccf1e3SJoseph Koshy 	NULLMASK
1911ebccf1e3SJoseph Koshy };
1912ebccf1e3SJoseph Koshy 
1913ebccf1e3SJoseph Koshy static struct pmc_masks p6_mask_essir[] = {
1914ebccf1e3SJoseph Koshy 	PMCMASK(sse-packed-single,	0x00),
1915ebccf1e3SJoseph Koshy 	PMCMASK(sse-packed-single-scalar-single, 0x01),
1916ebccf1e3SJoseph Koshy 	PMCMASK(sse2-packed-double,	0x02),
1917ebccf1e3SJoseph Koshy 	PMCMASK(sse2-scalar-double,	0x03),
1918ebccf1e3SJoseph Koshy 	NULLMASK
1919ebccf1e3SJoseph Koshy };
1920ebccf1e3SJoseph Koshy 
1921ebccf1e3SJoseph Koshy static struct pmc_masks p6_mask_esscir[] = {
1922ebccf1e3SJoseph Koshy 	PMCMASK(sse-packed-single,	0x00),
1923ebccf1e3SJoseph Koshy 	PMCMASK(sse-scalar-single,	0x01),
1924ebccf1e3SJoseph Koshy 	PMCMASK(sse2-packed-double,	0x02),
1925ebccf1e3SJoseph Koshy 	PMCMASK(sse2-scalar-double,	0x03),
1926ebccf1e3SJoseph Koshy 	NULLMASK
1927ebccf1e3SJoseph Koshy };
1928ebccf1e3SJoseph Koshy 
1929ebccf1e3SJoseph Koshy /* P6 event parser */
1930ebccf1e3SJoseph Koshy static int
1931ebccf1e3SJoseph Koshy p6_allocate_pmc(enum pmc_event pe, char *ctrspec,
1932ebccf1e3SJoseph Koshy     struct pmc_op_pmcallocate *pmc_config)
1933ebccf1e3SJoseph Koshy {
1934ebccf1e3SJoseph Koshy 	char *e, *p, *q;
1935ebccf1e3SJoseph Koshy 	uint32_t evmask;
1936ebccf1e3SJoseph Koshy 	int count, n;
1937ebccf1e3SJoseph Koshy 	const struct pmc_masks *pm, *pmask;
1938ebccf1e3SJoseph Koshy 
1939789140c0SJoseph Koshy 	pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE);
1940f263522aSJoseph Koshy 	pmc_config->pm_md.pm_ppro.pm_ppro_config = 0;
1941ebccf1e3SJoseph Koshy 
1942ebccf1e3SJoseph Koshy 	evmask = 0;
1943ebccf1e3SJoseph Koshy 
1944ebccf1e3SJoseph Koshy #define	P6MASKSET(M)	pmask = p6_mask_ ## M
1945ebccf1e3SJoseph Koshy 
1946ebccf1e3SJoseph Koshy 	switch(pe) {
1947ebccf1e3SJoseph Koshy 	case PMC_EV_P6_L2_IFETCH:	P6MASKSET(mesi); break;
1948ebccf1e3SJoseph Koshy 	case PMC_EV_P6_L2_LD:		P6MASKSET(mesi); break;
1949ebccf1e3SJoseph Koshy 	case PMC_EV_P6_L2_ST:		P6MASKSET(mesi); break;
1950ebccf1e3SJoseph Koshy 	case PMC_EV_P6_L2_RQSTS:	P6MASKSET(mesi); break;
1951ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_DRDY_CLOCKS:
1952ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_LOCK_CLOCKS:
1953ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_BRD:
1954ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_RFO:
1955ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRANS_WB:
1956ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_IFETCH:
1957ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_INVAL:
1958ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_PWR:
1959ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRANS_P:
1960ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRANS_IO:
1961ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_DEF:
1962ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_BURST:
1963ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_ANY:
1964ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_MEM:
1965ebccf1e3SJoseph Koshy 		P6MASKSET(any);	break;
1966ebccf1e3SJoseph Koshy 	case PMC_EV_P6_EMON_KNI_PREF_DISPATCHED:
1967ebccf1e3SJoseph Koshy 	case PMC_EV_P6_EMON_KNI_PREF_MISS:
1968ebccf1e3SJoseph Koshy 		P6MASKSET(ekp); break;
1969ebccf1e3SJoseph Koshy 	case PMC_EV_P6_EMON_KNI_INST_RETIRED:
1970ebccf1e3SJoseph Koshy 	case PMC_EV_P6_EMON_KNI_COMP_INST_RET:
1971ebccf1e3SJoseph Koshy 		P6MASKSET(pps);	break;
1972ebccf1e3SJoseph Koshy 	case PMC_EV_P6_MMX_INSTR_TYPE_EXEC:
1973ebccf1e3SJoseph Koshy 		P6MASKSET(mite); break;
1974ebccf1e3SJoseph Koshy 	case PMC_EV_P6_FP_MMX_TRANS:
1975ebccf1e3SJoseph Koshy 		P6MASKSET(fmt);	break;
1976ebccf1e3SJoseph Koshy 	case PMC_EV_P6_SEG_RENAME_STALLS:
1977ebccf1e3SJoseph Koshy 	case PMC_EV_P6_SEG_REG_RENAMES:
1978ebccf1e3SJoseph Koshy 		P6MASKSET(sr);	break;
1979ebccf1e3SJoseph Koshy 	case PMC_EV_P6_EMON_EST_TRANS:
1980ebccf1e3SJoseph Koshy 		P6MASKSET(eet);	break;
1981ebccf1e3SJoseph Koshy 	case PMC_EV_P6_EMON_FUSED_UOPS_RET:
1982ebccf1e3SJoseph Koshy 		P6MASKSET(efur); break;
1983ebccf1e3SJoseph Koshy 	case PMC_EV_P6_EMON_SSE_SSE2_INST_RETIRED:
1984ebccf1e3SJoseph Koshy 		P6MASKSET(essir); break;
1985ebccf1e3SJoseph Koshy 	case PMC_EV_P6_EMON_SSE_SSE2_COMP_INST_RETIRED:
1986ebccf1e3SJoseph Koshy 		P6MASKSET(esscir); break;
1987ebccf1e3SJoseph Koshy 	default:
1988ebccf1e3SJoseph Koshy 		pmask = NULL;
1989ebccf1e3SJoseph Koshy 		break;
1990ebccf1e3SJoseph Koshy 	}
1991ebccf1e3SJoseph Koshy 
1992ebccf1e3SJoseph Koshy 	/* Pentium M PMCs have a few events with different semantics */
1993ebccf1e3SJoseph Koshy 	if (cpu_info.pm_cputype == PMC_CPU_INTEL_PM) {
1994ebccf1e3SJoseph Koshy 		if (pe == PMC_EV_P6_L2_LD ||
1995ebccf1e3SJoseph Koshy 		    pe == PMC_EV_P6_L2_LINES_IN ||
1996ebccf1e3SJoseph Koshy 		    pe == PMC_EV_P6_L2_LINES_OUT)
1997ebccf1e3SJoseph Koshy 			P6MASKSET(mesihw);
1998ebccf1e3SJoseph Koshy 		else if (pe == PMC_EV_P6_L2_M_LINES_OUTM)
1999ebccf1e3SJoseph Koshy 			P6MASKSET(hw);
2000ebccf1e3SJoseph Koshy 	}
2001ebccf1e3SJoseph Koshy 
2002ebccf1e3SJoseph Koshy 	/* Parse additional modifiers if present */
2003ebccf1e3SJoseph Koshy 	while ((p = strsep(&ctrspec, ",")) != NULL) {
2004ebccf1e3SJoseph Koshy 		if (KWPREFIXMATCH(p, P6_KW_CMASK "=")) {
2005ebccf1e3SJoseph Koshy 			q = strchr(p, '=');
2006ebccf1e3SJoseph Koshy 			if (*++q == '\0') /* skip '=' */
2007aa342b1fSJoseph Koshy 				return (-1);
2008ebccf1e3SJoseph Koshy 			count = strtol(q, &e, 0);
2009ebccf1e3SJoseph Koshy 			if (e == q || *e != '\0')
2010aa342b1fSJoseph Koshy 				return (-1);
2011ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_THRESHOLD;
2012f263522aSJoseph Koshy 			pmc_config->pm_md.pm_ppro.pm_ppro_config |=
2013f263522aSJoseph Koshy 			    P6_EVSEL_TO_CMASK(count);
2014ebccf1e3SJoseph Koshy 		} else if (KWMATCH(p, P6_KW_EDGE)) {
2015ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_EDGE;
2016ebccf1e3SJoseph Koshy 		} else if (KWMATCH(p, P6_KW_INV)) {
2017ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_INVERT;
2018ebccf1e3SJoseph Koshy 		} else if (KWMATCH(p, P6_KW_OS)) {
2019ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_SYSTEM;
2020ebccf1e3SJoseph Koshy 		} else if (KWPREFIXMATCH(p, P6_KW_UMASK "=")) {
2021ebccf1e3SJoseph Koshy 			evmask = 0;
2022ebccf1e3SJoseph Koshy 			if ((n = pmc_parse_mask(pmask, p, &evmask)) < 0)
2023aa342b1fSJoseph Koshy 				return (-1);
2024ebccf1e3SJoseph Koshy 			if ((pe == PMC_EV_P6_BUS_DRDY_CLOCKS ||
2025ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_BUS_LOCK_CLOCKS ||
2026ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_BUS_TRAN_BRD ||
2027ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_BUS_TRAN_RFO ||
2028ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_BUS_TRAN_IFETCH ||
2029ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_BUS_TRAN_INVAL ||
2030ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_BUS_TRAN_PWR ||
2031ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_BUS_TRAN_DEF ||
2032ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_BUS_TRAN_BURST ||
2033ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_BUS_TRAN_ANY ||
2034ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_BUS_TRAN_MEM ||
2035ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_BUS_TRANS_IO ||
2036ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_BUS_TRANS_P ||
2037ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_BUS_TRANS_WB ||
2038ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_EMON_EST_TRANS ||
2039ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_EMON_FUSED_UOPS_RET ||
2040ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_EMON_KNI_COMP_INST_RET ||
2041ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_EMON_KNI_INST_RETIRED ||
2042ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_EMON_KNI_PREF_DISPATCHED ||
2043ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_EMON_KNI_PREF_MISS ||
2044ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_EMON_SSE_SSE2_COMP_INST_RETIRED ||
2045ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_EMON_SSE_SSE2_INST_RETIRED ||
2046ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_FP_MMX_TRANS)
2047aa342b1fSJoseph Koshy 			    && (n > 1))	/* Only one mask keyword is allowed. */
2048aa342b1fSJoseph Koshy 				return (-1);
2049ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_QUALIFIER;
2050ebccf1e3SJoseph Koshy 		} else if (KWMATCH(p, P6_KW_USR)) {
2051ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_USER;
2052ebccf1e3SJoseph Koshy 		} else
2053aa342b1fSJoseph Koshy 			return (-1);
2054ebccf1e3SJoseph Koshy 	}
2055ebccf1e3SJoseph Koshy 
2056ebccf1e3SJoseph Koshy 	/* post processing */
2057ebccf1e3SJoseph Koshy 	switch (pe) {
2058ebccf1e3SJoseph Koshy 
2059ebccf1e3SJoseph Koshy 		/*
2060ebccf1e3SJoseph Koshy 		 * The following events default to an evmask of 0
2061ebccf1e3SJoseph Koshy 		 */
2062ebccf1e3SJoseph Koshy 
2063ebccf1e3SJoseph Koshy 		/* default => 'self' */
2064ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_DRDY_CLOCKS:
2065ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_LOCK_CLOCKS:
2066ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_BRD:
2067ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_RFO:
2068ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRANS_WB:
2069ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_IFETCH:
2070ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_INVAL:
2071ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_PWR:
2072ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRANS_P:
2073ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRANS_IO:
2074ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_DEF:
2075ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_BURST:
2076ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_ANY:
2077ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_MEM:
2078ebccf1e3SJoseph Koshy 
2079ebccf1e3SJoseph Koshy 		/* default => 'nta' */
2080ebccf1e3SJoseph Koshy 	case PMC_EV_P6_EMON_KNI_PREF_DISPATCHED:
2081ebccf1e3SJoseph Koshy 	case PMC_EV_P6_EMON_KNI_PREF_MISS:
2082ebccf1e3SJoseph Koshy 
2083ebccf1e3SJoseph Koshy 		/* default => 'packed and scalar' */
2084ebccf1e3SJoseph Koshy 	case PMC_EV_P6_EMON_KNI_INST_RETIRED:
2085ebccf1e3SJoseph Koshy 	case PMC_EV_P6_EMON_KNI_COMP_INST_RET:
2086ebccf1e3SJoseph Koshy 
2087ebccf1e3SJoseph Koshy 		/* default => 'mmx to fp transitions' */
2088ebccf1e3SJoseph Koshy 	case PMC_EV_P6_FP_MMX_TRANS:
2089ebccf1e3SJoseph Koshy 
2090ebccf1e3SJoseph Koshy 		/* default => 'SSE Packed Single' */
2091ebccf1e3SJoseph Koshy 	case PMC_EV_P6_EMON_SSE_SSE2_INST_RETIRED:
2092ebccf1e3SJoseph Koshy 	case PMC_EV_P6_EMON_SSE_SSE2_COMP_INST_RETIRED:
2093ebccf1e3SJoseph Koshy 
2094ebccf1e3SJoseph Koshy 		/* default => 'all fused micro-ops' */
2095ebccf1e3SJoseph Koshy 	case PMC_EV_P6_EMON_FUSED_UOPS_RET:
2096ebccf1e3SJoseph Koshy 
2097ebccf1e3SJoseph Koshy 		/* default => 'all transitions' */
2098ebccf1e3SJoseph Koshy 	case PMC_EV_P6_EMON_EST_TRANS:
2099ebccf1e3SJoseph Koshy 		break;
2100ebccf1e3SJoseph Koshy 
2101ebccf1e3SJoseph Koshy 	case PMC_EV_P6_MMX_UOPS_EXEC:
2102ebccf1e3SJoseph Koshy 		evmask = 0x0F;		/* only value allowed */
2103ebccf1e3SJoseph Koshy 		break;
2104ebccf1e3SJoseph Koshy 
2105ebccf1e3SJoseph Koshy 	default:
2106ebccf1e3SJoseph Koshy 		/*
2107ebccf1e3SJoseph Koshy 		 * For all other events, set the default event mask
2108ebccf1e3SJoseph Koshy 		 * to a logical OR of all the allowed event mask bits.
2109ebccf1e3SJoseph Koshy 		 */
2110ebccf1e3SJoseph Koshy 		if (evmask == 0 && pmask) {
2111ebccf1e3SJoseph Koshy 			for (pm = pmask; pm->pm_name; pm++)
2112ebccf1e3SJoseph Koshy 				evmask |= pm->pm_value;
2113ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_QUALIFIER;
2114ebccf1e3SJoseph Koshy 		}
2115ebccf1e3SJoseph Koshy 
2116ebccf1e3SJoseph Koshy 		break;
2117ebccf1e3SJoseph Koshy 	}
2118ebccf1e3SJoseph Koshy 
2119ebccf1e3SJoseph Koshy 	if (pmc_config->pm_caps & PMC_CAP_QUALIFIER)
2120f263522aSJoseph Koshy 		pmc_config->pm_md.pm_ppro.pm_ppro_config |=
2121f263522aSJoseph Koshy 		    P6_EVSEL_TO_UMASK(evmask);
2122ebccf1e3SJoseph Koshy 
2123aa342b1fSJoseph Koshy 	return (0);
2124ebccf1e3SJoseph Koshy }
2125ebccf1e3SJoseph Koshy 
2126ebccf1e3SJoseph Koshy #endif
2127ebccf1e3SJoseph Koshy 
2128789140c0SJoseph Koshy #if	defined(__i386__) || defined(__amd64__)
2129789140c0SJoseph Koshy static int
2130789140c0SJoseph Koshy tsc_allocate_pmc(enum pmc_event pe, char *ctrspec,
2131789140c0SJoseph Koshy     struct pmc_op_pmcallocate *pmc_config)
2132789140c0SJoseph Koshy {
2133789140c0SJoseph Koshy 	if (pe != PMC_EV_TSC_TSC)
2134789140c0SJoseph Koshy 		return (-1);
2135789140c0SJoseph Koshy 
2136789140c0SJoseph Koshy 	/* TSC events must be unqualified. */
2137789140c0SJoseph Koshy 	if (ctrspec && *ctrspec != '\0')
2138789140c0SJoseph Koshy 		return (-1);
2139789140c0SJoseph Koshy 
2140789140c0SJoseph Koshy 	pmc_config->pm_md.pm_amd.pm_amd_config = 0;
2141789140c0SJoseph Koshy 	pmc_config->pm_caps |= PMC_CAP_READ;
2142789140c0SJoseph Koshy 
2143789140c0SJoseph Koshy 	return (0);
2144789140c0SJoseph Koshy }
2145789140c0SJoseph Koshy #endif
2146789140c0SJoseph Koshy 
21470ce207d2SRui Paulo #if	defined(__XSCALE__)
21480ce207d2SRui Paulo 
21490ce207d2SRui Paulo static struct pmc_event_alias xscale_aliases[] = {
21500ce207d2SRui Paulo 	EV_ALIAS("branches",		"BRANCH_RETIRED"),
21510ce207d2SRui Paulo 	EV_ALIAS("branch-mispredicts",	"BRANCH_MISPRED"),
21520ce207d2SRui Paulo 	EV_ALIAS("dc-misses",		"DC_MISS"),
21530ce207d2SRui Paulo 	EV_ALIAS("ic-misses",		"IC_MISS"),
21540ce207d2SRui Paulo 	EV_ALIAS("instructions",	"INSTR_RETIRED"),
21550ce207d2SRui Paulo 	EV_ALIAS(NULL, NULL)
21560ce207d2SRui Paulo };
21570ce207d2SRui Paulo static int
21580ce207d2SRui Paulo xscale_allocate_pmc(enum pmc_event pe, char *ctrspec __unused,
21590ce207d2SRui Paulo     struct pmc_op_pmcallocate *pmc_config __unused)
21600ce207d2SRui Paulo {
21610ce207d2SRui Paulo 	switch (pe) {
21620ce207d2SRui Paulo 	default:
21630ce207d2SRui Paulo 		break;
21640ce207d2SRui Paulo 	}
21650ce207d2SRui Paulo 
21660ce207d2SRui Paulo 	return (0);
21670ce207d2SRui Paulo }
21680ce207d2SRui Paulo #endif
21690ce207d2SRui Paulo 
2170660df75eSGeorge V. Neville-Neil #if defined(__mips__)
2171660df75eSGeorge V. Neville-Neil 
2172660df75eSGeorge V. Neville-Neil static struct pmc_event_alias mips24k_aliases[] = {
2173660df75eSGeorge V. Neville-Neil 	EV_ALIAS("instructions",	"INSTR_EXECUTED"),
2174660df75eSGeorge V. Neville-Neil 	EV_ALIAS("branches",		"BRANCH_COMPLETED"),
2175660df75eSGeorge V. Neville-Neil 	EV_ALIAS("branch-mispredicts",	"BRANCH_MISPRED"),
2176660df75eSGeorge V. Neville-Neil 	EV_ALIAS(NULL, NULL)
2177660df75eSGeorge V. Neville-Neil };
2178660df75eSGeorge V. Neville-Neil 
2179660df75eSGeorge V. Neville-Neil #define	MIPS24K_KW_OS		"os"
2180660df75eSGeorge V. Neville-Neil #define	MIPS24K_KW_USR		"usr"
2181660df75eSGeorge V. Neville-Neil #define	MIPS24K_KW_ANYTHREAD	"anythread"
2182660df75eSGeorge V. Neville-Neil 
2183660df75eSGeorge V. Neville-Neil static int
2184660df75eSGeorge V. Neville-Neil mips24k_allocate_pmc(enum pmc_event pe, char *ctrspec __unused,
2185660df75eSGeorge V. Neville-Neil 		  struct pmc_op_pmcallocate *pmc_config __unused)
2186660df75eSGeorge V. Neville-Neil {
2187660df75eSGeorge V. Neville-Neil 	char *p;
2188660df75eSGeorge V. Neville-Neil 
2189660df75eSGeorge V. Neville-Neil 	(void) pe;
2190660df75eSGeorge V. Neville-Neil 
2191660df75eSGeorge V. Neville-Neil 	pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE);
2192660df75eSGeorge V. Neville-Neil 
2193660df75eSGeorge V. Neville-Neil 	while ((p = strsep(&ctrspec, ",")) != NULL) {
2194660df75eSGeorge V. Neville-Neil 		if (KWMATCH(p, MIPS24K_KW_OS))
2195660df75eSGeorge V. Neville-Neil 			pmc_config->pm_caps |= PMC_CAP_SYSTEM;
2196660df75eSGeorge V. Neville-Neil 		else if (KWMATCH(p, MIPS24K_KW_USR))
2197660df75eSGeorge V. Neville-Neil 			pmc_config->pm_caps |= PMC_CAP_USER;
2198660df75eSGeorge V. Neville-Neil 		else if (KWMATCH(p, MIPS24K_KW_ANYTHREAD))
2199660df75eSGeorge V. Neville-Neil 			pmc_config->pm_caps |= (PMC_CAP_USER | PMC_CAP_SYSTEM);
2200660df75eSGeorge V. Neville-Neil 		else
2201660df75eSGeorge V. Neville-Neil 			return (-1);
2202660df75eSGeorge V. Neville-Neil 	}
2203660df75eSGeorge V. Neville-Neil 
2204660df75eSGeorge V. Neville-Neil 	return (0);
2205660df75eSGeorge V. Neville-Neil }
2206660df75eSGeorge V. Neville-Neil #endif /* __mips__ */
2207660df75eSGeorge V. Neville-Neil 
2208660df75eSGeorge V. Neville-Neil 
2209789140c0SJoseph Koshy /*
2210789140c0SJoseph Koshy  * Match an event name `name' with its canonical form.
2211789140c0SJoseph Koshy  *
22120cfab8ddSJoseph Koshy  * Matches are case insensitive and spaces, periods, underscores and
22130cfab8ddSJoseph Koshy  * hyphen characters are considered to match each other.
2214789140c0SJoseph Koshy  *
2215789140c0SJoseph Koshy  * Returns 1 for a match, 0 otherwise.
2216789140c0SJoseph Koshy  */
2217789140c0SJoseph Koshy 
2218789140c0SJoseph Koshy static int
2219789140c0SJoseph Koshy pmc_match_event_name(const char *name, const char *canonicalname)
2220789140c0SJoseph Koshy {
2221789140c0SJoseph Koshy 	int cc, nc;
2222789140c0SJoseph Koshy 	const unsigned char *c, *n;
2223789140c0SJoseph Koshy 
2224789140c0SJoseph Koshy 	c = (const unsigned char *) canonicalname;
2225789140c0SJoseph Koshy 	n = (const unsigned char *) name;
2226789140c0SJoseph Koshy 
2227789140c0SJoseph Koshy 	for (; (nc = *n) && (cc = *c); n++, c++) {
2228789140c0SJoseph Koshy 
22290cfab8ddSJoseph Koshy 		if ((nc == ' ' || nc == '_' || nc == '-' || nc == '.') &&
22300cfab8ddSJoseph Koshy 		    (cc == ' ' || cc == '_' || cc == '-' || cc == '.'))
2231789140c0SJoseph Koshy 			continue;
2232789140c0SJoseph Koshy 
22330cfab8ddSJoseph Koshy 		if (toupper(nc) == toupper(cc))
2234789140c0SJoseph Koshy 			continue;
2235789140c0SJoseph Koshy 
22360cfab8ddSJoseph Koshy 
2237789140c0SJoseph Koshy 		return (0);
2238789140c0SJoseph Koshy 	}
2239789140c0SJoseph Koshy 
2240789140c0SJoseph Koshy 	if (*n == '\0' && *c == '\0')
2241789140c0SJoseph Koshy 		return (1);
2242789140c0SJoseph Koshy 
2243789140c0SJoseph Koshy 	return (0);
2244789140c0SJoseph Koshy }
2245789140c0SJoseph Koshy 
2246789140c0SJoseph Koshy /*
2247789140c0SJoseph Koshy  * Match an event name against all the event named supported by a
2248789140c0SJoseph Koshy  * PMC class.
2249789140c0SJoseph Koshy  *
2250789140c0SJoseph Koshy  * Returns an event descriptor pointer on match or NULL otherwise.
2251789140c0SJoseph Koshy  */
2252789140c0SJoseph Koshy static const struct pmc_event_descr *
2253789140c0SJoseph Koshy pmc_match_event_class(const char *name,
2254789140c0SJoseph Koshy     const struct pmc_class_descr *pcd)
2255789140c0SJoseph Koshy {
2256789140c0SJoseph Koshy 	size_t n;
2257789140c0SJoseph Koshy 	const struct pmc_event_descr *ev;
2258789140c0SJoseph Koshy 
2259789140c0SJoseph Koshy 	ev = pcd->pm_evc_event_table;
2260789140c0SJoseph Koshy 	for (n = 0; n < pcd->pm_evc_event_table_size; n++, ev++)
2261789140c0SJoseph Koshy 		if (pmc_match_event_name(name, ev->pm_ev_name))
2262789140c0SJoseph Koshy 			return (ev);
2263789140c0SJoseph Koshy 
2264789140c0SJoseph Koshy 	return (NULL);
2265789140c0SJoseph Koshy }
2266789140c0SJoseph Koshy 
2267789140c0SJoseph Koshy static int
2268789140c0SJoseph Koshy pmc_mdep_is_compatible_class(enum pmc_class pc)
2269789140c0SJoseph Koshy {
2270789140c0SJoseph Koshy 	size_t n;
2271789140c0SJoseph Koshy 
2272789140c0SJoseph Koshy 	for (n = 0; n < pmc_mdep_class_list_size; n++)
2273789140c0SJoseph Koshy 		if (pmc_mdep_class_list[n] == pc)
2274789140c0SJoseph Koshy 			return (1);
2275789140c0SJoseph Koshy 	return (0);
2276789140c0SJoseph Koshy }
2277789140c0SJoseph Koshy 
2278ebccf1e3SJoseph Koshy /*
2279ebccf1e3SJoseph Koshy  * API entry points
2280ebccf1e3SJoseph Koshy  */
2281ebccf1e3SJoseph Koshy 
2282ebccf1e3SJoseph Koshy int
2283ebccf1e3SJoseph Koshy pmc_allocate(const char *ctrspec, enum pmc_mode mode,
2284ebccf1e3SJoseph Koshy     uint32_t flags, int cpu, pmc_id_t *pmcid)
2285ebccf1e3SJoseph Koshy {
2286789140c0SJoseph Koshy 	size_t n;
2287ebccf1e3SJoseph Koshy 	int retval;
2288ebccf1e3SJoseph Koshy 	char *r, *spec_copy;
2289ebccf1e3SJoseph Koshy 	const char *ctrname;
2290789140c0SJoseph Koshy 	const struct pmc_event_descr *ev;
2291789140c0SJoseph Koshy 	const struct pmc_event_alias *alias;
2292ebccf1e3SJoseph Koshy 	struct pmc_op_pmcallocate pmc_config;
2293789140c0SJoseph Koshy 	const struct pmc_class_descr *pcd;
2294ebccf1e3SJoseph Koshy 
2295ebccf1e3SJoseph Koshy 	spec_copy = NULL;
2296ebccf1e3SJoseph Koshy 	retval    = -1;
2297ebccf1e3SJoseph Koshy 
2298ebccf1e3SJoseph Koshy 	if (mode != PMC_MODE_SS && mode != PMC_MODE_TS &&
2299ebccf1e3SJoseph Koshy 	    mode != PMC_MODE_SC && mode != PMC_MODE_TC) {
2300ebccf1e3SJoseph Koshy 		errno = EINVAL;
2301ebccf1e3SJoseph Koshy 		goto out;
2302ebccf1e3SJoseph Koshy 	}
2303ebccf1e3SJoseph Koshy 
2304ebccf1e3SJoseph Koshy 	/* replace an event alias with the canonical event specifier */
2305ebccf1e3SJoseph Koshy 	if (pmc_mdep_event_aliases)
2306789140c0SJoseph Koshy 		for (alias = pmc_mdep_event_aliases; alias->pm_alias; alias++)
2307789140c0SJoseph Koshy 			if (!strcasecmp(ctrspec, alias->pm_alias)) {
2308789140c0SJoseph Koshy 				spec_copy = strdup(alias->pm_spec);
2309ebccf1e3SJoseph Koshy 				break;
2310ebccf1e3SJoseph Koshy 			}
2311ebccf1e3SJoseph Koshy 
2312ebccf1e3SJoseph Koshy 	if (spec_copy == NULL)
2313ebccf1e3SJoseph Koshy 		spec_copy = strdup(ctrspec);
2314ebccf1e3SJoseph Koshy 
2315ebccf1e3SJoseph Koshy 	r = spec_copy;
2316ebccf1e3SJoseph Koshy 	ctrname = strsep(&r, ",");
2317ebccf1e3SJoseph Koshy 
2318789140c0SJoseph Koshy 	/*
2319789140c0SJoseph Koshy 	 * If a explicit class prefix was given by the user, restrict the
2320789140c0SJoseph Koshy 	 * search for the event to the specified PMC class.
2321789140c0SJoseph Koshy 	 */
2322789140c0SJoseph Koshy 	ev = NULL;
23230cfab8ddSJoseph Koshy 	for (n = 0; n < PMC_CLASS_TABLE_SIZE; n++) {
23240cfab8ddSJoseph Koshy 		pcd = pmc_class_table[n];
2325789140c0SJoseph Koshy 		if (pmc_mdep_is_compatible_class(pcd->pm_evc_class) &&
2326789140c0SJoseph Koshy 		    strncasecmp(ctrname, pcd->pm_evc_name,
2327789140c0SJoseph Koshy 				pcd->pm_evc_name_size) == 0) {
2328789140c0SJoseph Koshy 			if ((ev = pmc_match_event_class(ctrname +
2329789140c0SJoseph Koshy 			    pcd->pm_evc_name_size, pcd)) == NULL) {
2330789140c0SJoseph Koshy 				errno = EINVAL;
2331789140c0SJoseph Koshy 				goto out;
2332789140c0SJoseph Koshy 			}
2333ebccf1e3SJoseph Koshy 			break;
2334789140c0SJoseph Koshy 		}
2335789140c0SJoseph Koshy 	}
2336ebccf1e3SJoseph Koshy 
2337789140c0SJoseph Koshy 	/*
2338789140c0SJoseph Koshy 	 * Otherwise, search for this event in all compatible PMC
2339789140c0SJoseph Koshy 	 * classes.
2340789140c0SJoseph Koshy 	 */
23410cfab8ddSJoseph Koshy 	for (n = 0; ev == NULL && n < PMC_CLASS_TABLE_SIZE; n++) {
23420cfab8ddSJoseph Koshy 		pcd = pmc_class_table[n];
2343789140c0SJoseph Koshy 		if (pmc_mdep_is_compatible_class(pcd->pm_evc_class))
2344789140c0SJoseph Koshy 			ev = pmc_match_event_class(ctrname, pcd);
2345789140c0SJoseph Koshy 	}
2346789140c0SJoseph Koshy 
2347789140c0SJoseph Koshy 	if (ev == NULL) {
2348ebccf1e3SJoseph Koshy 		errno = EINVAL;
2349ebccf1e3SJoseph Koshy 		goto out;
2350ebccf1e3SJoseph Koshy 	}
2351ebccf1e3SJoseph Koshy 
2352ebccf1e3SJoseph Koshy 	bzero(&pmc_config, sizeof(pmc_config));
2353789140c0SJoseph Koshy 	pmc_config.pm_ev    = ev->pm_ev_code;
2354789140c0SJoseph Koshy 	pmc_config.pm_class = pcd->pm_evc_class;
2355ebccf1e3SJoseph Koshy 	pmc_config.pm_cpu   = cpu;
2356ebccf1e3SJoseph Koshy 	pmc_config.pm_mode  = mode;
2357ebccf1e3SJoseph Koshy 	pmc_config.pm_flags = flags;
2358ebccf1e3SJoseph Koshy 
2359ebccf1e3SJoseph Koshy 	if (PMC_IS_SAMPLING_MODE(mode))
2360ebccf1e3SJoseph Koshy 		pmc_config.pm_caps |= PMC_CAP_INTERRUPT;
2361ebccf1e3SJoseph Koshy 
2362789140c0SJoseph Koshy  	if (pcd->pm_evc_allocate_pmc(ev->pm_ev_code, r, &pmc_config) < 0) {
2363ebccf1e3SJoseph Koshy 		errno = EINVAL;
2364ebccf1e3SJoseph Koshy 		goto out;
2365ebccf1e3SJoseph Koshy 	}
2366ebccf1e3SJoseph Koshy 
2367ebccf1e3SJoseph Koshy 	if (PMC_CALL(PMCALLOCATE, &pmc_config) < 0)
2368ebccf1e3SJoseph Koshy 		goto out;
2369ebccf1e3SJoseph Koshy 
2370ebccf1e3SJoseph Koshy 	*pmcid = pmc_config.pm_pmcid;
2371ebccf1e3SJoseph Koshy 
2372ebccf1e3SJoseph Koshy 	retval = 0;
2373ebccf1e3SJoseph Koshy 
2374ebccf1e3SJoseph Koshy  out:
2375ebccf1e3SJoseph Koshy 	if (spec_copy)
2376ebccf1e3SJoseph Koshy 		free(spec_copy);
2377ebccf1e3SJoseph Koshy 
2378aa342b1fSJoseph Koshy 	return (retval);
2379ebccf1e3SJoseph Koshy }
2380ebccf1e3SJoseph Koshy 
2381ebccf1e3SJoseph Koshy int
2382ebccf1e3SJoseph Koshy pmc_attach(pmc_id_t pmc, pid_t pid)
2383ebccf1e3SJoseph Koshy {
2384ebccf1e3SJoseph Koshy 	struct pmc_op_pmcattach pmc_attach_args;
2385ebccf1e3SJoseph Koshy 
2386ebccf1e3SJoseph Koshy 	pmc_attach_args.pm_pmc = pmc;
2387ebccf1e3SJoseph Koshy 	pmc_attach_args.pm_pid = pid;
2388ebccf1e3SJoseph Koshy 
2389aa342b1fSJoseph Koshy 	return (PMC_CALL(PMCATTACH, &pmc_attach_args));
2390ebccf1e3SJoseph Koshy }
2391ebccf1e3SJoseph Koshy 
2392ebccf1e3SJoseph Koshy int
2393c5153e19SJoseph Koshy pmc_capabilities(pmc_id_t pmcid, uint32_t *caps)
2394c5153e19SJoseph Koshy {
2395c5153e19SJoseph Koshy 	unsigned int i;
2396c5153e19SJoseph Koshy 	enum pmc_class cl;
2397c5153e19SJoseph Koshy 
2398c5153e19SJoseph Koshy 	cl = PMC_ID_TO_CLASS(pmcid);
2399c5153e19SJoseph Koshy 	for (i = 0; i < cpu_info.pm_nclass; i++)
2400c5153e19SJoseph Koshy 		if (cpu_info.pm_classes[i].pm_class == cl) {
2401c5153e19SJoseph Koshy 			*caps = cpu_info.pm_classes[i].pm_caps;
2402aa342b1fSJoseph Koshy 			return (0);
2403c5153e19SJoseph Koshy 		}
2404484202faSJoseph Koshy 	errno = EINVAL;
2405484202faSJoseph Koshy 	return (-1);
2406c5153e19SJoseph Koshy }
2407c5153e19SJoseph Koshy 
2408f263522aSJoseph Koshy int
2409f263522aSJoseph Koshy pmc_configure_logfile(int fd)
2410ebccf1e3SJoseph Koshy {
2411f263522aSJoseph Koshy 	struct pmc_op_configurelog cla;
2412f263522aSJoseph Koshy 
2413f263522aSJoseph Koshy 	cla.pm_logfd = fd;
2414f263522aSJoseph Koshy 	if (PMC_CALL(CONFIGURELOG, &cla) < 0)
2415aa342b1fSJoseph Koshy 		return (-1);
2416aa342b1fSJoseph Koshy 	return (0);
2417ebccf1e3SJoseph Koshy }
2418ebccf1e3SJoseph Koshy 
2419f263522aSJoseph Koshy int
2420f263522aSJoseph Koshy pmc_cpuinfo(const struct pmc_cpuinfo **pci)
2421ebccf1e3SJoseph Koshy {
2422f263522aSJoseph Koshy 	if (pmc_syscall == -1) {
2423f263522aSJoseph Koshy 		errno = ENXIO;
2424aa342b1fSJoseph Koshy 		return (-1);
2425ebccf1e3SJoseph Koshy 	}
2426ebccf1e3SJoseph Koshy 
24271455fcd3SJoseph Koshy 	*pci = &cpu_info;
2428aa342b1fSJoseph Koshy 	return (0);
2429ebccf1e3SJoseph Koshy }
2430ebccf1e3SJoseph Koshy 
2431f263522aSJoseph Koshy int
2432f263522aSJoseph Koshy pmc_detach(pmc_id_t pmc, pid_t pid)
2433ebccf1e3SJoseph Koshy {
2434f263522aSJoseph Koshy 	struct pmc_op_pmcattach pmc_detach_args;
2435ebccf1e3SJoseph Koshy 
2436f263522aSJoseph Koshy 	pmc_detach_args.pm_pmc = pmc;
2437f263522aSJoseph Koshy 	pmc_detach_args.pm_pid = pid;
2438aa342b1fSJoseph Koshy 	return (PMC_CALL(PMCDETACH, &pmc_detach_args));
2439ebccf1e3SJoseph Koshy }
2440ebccf1e3SJoseph Koshy 
2441f263522aSJoseph Koshy int
2442f263522aSJoseph Koshy pmc_disable(int cpu, int pmc)
2443ebccf1e3SJoseph Koshy {
2444f263522aSJoseph Koshy 	struct pmc_op_pmcadmin ssa;
2445ebccf1e3SJoseph Koshy 
2446f263522aSJoseph Koshy 	ssa.pm_cpu = cpu;
2447f263522aSJoseph Koshy 	ssa.pm_pmc = pmc;
2448f263522aSJoseph Koshy 	ssa.pm_state = PMC_STATE_DISABLED;
2449aa342b1fSJoseph Koshy 	return (PMC_CALL(PMCADMIN, &ssa));
2450ebccf1e3SJoseph Koshy }
2451ebccf1e3SJoseph Koshy 
2452f263522aSJoseph Koshy int
2453f263522aSJoseph Koshy pmc_enable(int cpu, int pmc)
2454ebccf1e3SJoseph Koshy {
2455f263522aSJoseph Koshy 	struct pmc_op_pmcadmin ssa;
2456ebccf1e3SJoseph Koshy 
2457f263522aSJoseph Koshy 	ssa.pm_cpu = cpu;
2458f263522aSJoseph Koshy 	ssa.pm_pmc = pmc;
2459f263522aSJoseph Koshy 	ssa.pm_state = PMC_STATE_FREE;
2460aa342b1fSJoseph Koshy 	return (PMC_CALL(PMCADMIN, &ssa));
2461ebccf1e3SJoseph Koshy }
2462ebccf1e3SJoseph Koshy 
2463ebccf1e3SJoseph Koshy /*
2464ebccf1e3SJoseph Koshy  * Return a list of events known to a given PMC class.  'cl' is the
2465ebccf1e3SJoseph Koshy  * PMC class identifier, 'eventnames' is the returned list of 'const
2466ebccf1e3SJoseph Koshy  * char *' pointers pointing to the names of the events. 'nevents' is
2467ebccf1e3SJoseph Koshy  * the number of event name pointers returned.
2468ebccf1e3SJoseph Koshy  *
2469ebccf1e3SJoseph Koshy  * The space for 'eventnames' is allocated using malloc(3).  The caller
2470ebccf1e3SJoseph Koshy  * is responsible for freeing this space when done.
2471ebccf1e3SJoseph Koshy  */
2472ebccf1e3SJoseph Koshy int
2473ebccf1e3SJoseph Koshy pmc_event_names_of_class(enum pmc_class cl, const char ***eventnames,
2474ebccf1e3SJoseph Koshy     int *nevents)
2475ebccf1e3SJoseph Koshy {
2476ebccf1e3SJoseph Koshy 	int count;
2477ebccf1e3SJoseph Koshy 	const char **names;
2478ebccf1e3SJoseph Koshy 	const struct pmc_event_descr *ev;
2479ebccf1e3SJoseph Koshy 
2480ebccf1e3SJoseph Koshy 	switch (cl)
2481ebccf1e3SJoseph Koshy 	{
24820cfab8ddSJoseph Koshy 	case PMC_CLASS_IAF:
24830cfab8ddSJoseph Koshy 		ev = iaf_event_table;
24840cfab8ddSJoseph Koshy 		count = PMC_EVENT_TABLE_SIZE(iaf);
24850cfab8ddSJoseph Koshy 		break;
24860cfab8ddSJoseph Koshy 	case PMC_CLASS_IAP:
24870cfab8ddSJoseph Koshy 		/*
24880cfab8ddSJoseph Koshy 		 * Return the most appropriate set of event name
24890cfab8ddSJoseph Koshy 		 * spellings for the current CPU.
24900cfab8ddSJoseph Koshy 		 */
24910cfab8ddSJoseph Koshy 		switch (cpu_info.pm_cputype) {
24920cfab8ddSJoseph Koshy 		default:
24930cfab8ddSJoseph Koshy 		case PMC_CPU_INTEL_ATOM:
24940cfab8ddSJoseph Koshy 			ev = atom_event_table;
24950cfab8ddSJoseph Koshy 			count = PMC_EVENT_TABLE_SIZE(atom);
24960cfab8ddSJoseph Koshy 			break;
24970cfab8ddSJoseph Koshy 		case PMC_CPU_INTEL_CORE:
24980cfab8ddSJoseph Koshy 			ev = core_event_table;
24990cfab8ddSJoseph Koshy 			count = PMC_EVENT_TABLE_SIZE(core);
25000cfab8ddSJoseph Koshy 			break;
25010cfab8ddSJoseph Koshy 		case PMC_CPU_INTEL_CORE2:
2502b4d091f3SJoseph Koshy 		case PMC_CPU_INTEL_CORE2EXTREME:
25030cfab8ddSJoseph Koshy 			ev = core2_event_table;
25040cfab8ddSJoseph Koshy 			count = PMC_EVENT_TABLE_SIZE(core2);
25050cfab8ddSJoseph Koshy 			break;
2506597979c4SJeff Roberson 		case PMC_CPU_INTEL_COREI7:
2507597979c4SJeff Roberson 			ev = corei7_event_table;
2508597979c4SJeff Roberson 			count = PMC_EVENT_TABLE_SIZE(corei7);
2509597979c4SJeff Roberson 			break;
25101fa7f10bSFabien Thomas 		case PMC_CPU_INTEL_WESTMERE:
25111fa7f10bSFabien Thomas 			ev = westmere_event_table;
25121fa7f10bSFabien Thomas 			count = PMC_EVENT_TABLE_SIZE(westmere);
25131fa7f10bSFabien Thomas 			break;
25141fa7f10bSFabien Thomas 		}
25151fa7f10bSFabien Thomas 		break;
25161fa7f10bSFabien Thomas 	case PMC_CLASS_UCF:
25171fa7f10bSFabien Thomas 		ev = ucf_event_table;
25181fa7f10bSFabien Thomas 		count = PMC_EVENT_TABLE_SIZE(ucf);
25191fa7f10bSFabien Thomas 		break;
25201fa7f10bSFabien Thomas 	case PMC_CLASS_UCP:
25211fa7f10bSFabien Thomas 		/*
25221fa7f10bSFabien Thomas 		 * Return the most appropriate set of event name
25231fa7f10bSFabien Thomas 		 * spellings for the current CPU.
25241fa7f10bSFabien Thomas 		 */
25251fa7f10bSFabien Thomas 		switch (cpu_info.pm_cputype) {
25261fa7f10bSFabien Thomas 		default:
25271fa7f10bSFabien Thomas 		case PMC_CPU_INTEL_COREI7:
25281fa7f10bSFabien Thomas 			ev = corei7uc_event_table;
25291fa7f10bSFabien Thomas 			count = PMC_EVENT_TABLE_SIZE(corei7uc);
25301fa7f10bSFabien Thomas 			break;
25311fa7f10bSFabien Thomas 		case PMC_CPU_INTEL_WESTMERE:
25321fa7f10bSFabien Thomas 			ev = westmereuc_event_table;
25331fa7f10bSFabien Thomas 			count = PMC_EVENT_TABLE_SIZE(westmereuc);
25341fa7f10bSFabien Thomas 			break;
25350cfab8ddSJoseph Koshy 		}
25360cfab8ddSJoseph Koshy 		break;
2537ebccf1e3SJoseph Koshy 	case PMC_CLASS_TSC:
2538789140c0SJoseph Koshy 		ev = tsc_event_table;
2539789140c0SJoseph Koshy 		count = PMC_EVENT_TABLE_SIZE(tsc);
2540ebccf1e3SJoseph Koshy 		break;
2541ebccf1e3SJoseph Koshy 	case PMC_CLASS_K7:
2542789140c0SJoseph Koshy 		ev = k7_event_table;
2543789140c0SJoseph Koshy 		count = PMC_EVENT_TABLE_SIZE(k7);
2544ebccf1e3SJoseph Koshy 		break;
2545ebccf1e3SJoseph Koshy 	case PMC_CLASS_K8:
2546789140c0SJoseph Koshy 		ev = k8_event_table;
2547789140c0SJoseph Koshy 		count = PMC_EVENT_TABLE_SIZE(k8);
2548ebccf1e3SJoseph Koshy 		break;
2549ebccf1e3SJoseph Koshy 	case PMC_CLASS_P4:
2550789140c0SJoseph Koshy 		ev = p4_event_table;
2551789140c0SJoseph Koshy 		count = PMC_EVENT_TABLE_SIZE(p4);
2552789140c0SJoseph Koshy 		break;
2553789140c0SJoseph Koshy 	case PMC_CLASS_P5:
2554789140c0SJoseph Koshy 		ev = p5_event_table;
2555789140c0SJoseph Koshy 		count = PMC_EVENT_TABLE_SIZE(p5);
2556789140c0SJoseph Koshy 		break;
2557789140c0SJoseph Koshy 	case PMC_CLASS_P6:
2558789140c0SJoseph Koshy 		ev = p6_event_table;
2559789140c0SJoseph Koshy 		count = PMC_EVENT_TABLE_SIZE(p6);
2560ebccf1e3SJoseph Koshy 		break;
25610ce207d2SRui Paulo 	case PMC_CLASS_XSCALE:
25620ce207d2SRui Paulo 		ev = xscale_event_table;
25630ce207d2SRui Paulo 		count = PMC_EVENT_TABLE_SIZE(xscale);
25640ce207d2SRui Paulo 		break;
2565660df75eSGeorge V. Neville-Neil 	case PMC_CLASS_MIPS24K:
2566660df75eSGeorge V. Neville-Neil 		ev = mips24k_event_table;
2567660df75eSGeorge V. Neville-Neil 		count = PMC_EVENT_TABLE_SIZE(mips24k);
2568660df75eSGeorge V. Neville-Neil 		break;
2569ebccf1e3SJoseph Koshy 	default:
2570ebccf1e3SJoseph Koshy 		errno = EINVAL;
2571aa342b1fSJoseph Koshy 		return (-1);
2572ebccf1e3SJoseph Koshy 	}
2573ebccf1e3SJoseph Koshy 
2574ebccf1e3SJoseph Koshy 	if ((names = malloc(count * sizeof(const char *))) == NULL)
2575aa342b1fSJoseph Koshy 		return (-1);
2576ebccf1e3SJoseph Koshy 
2577ebccf1e3SJoseph Koshy 	*eventnames = names;
2578ebccf1e3SJoseph Koshy 	*nevents = count;
2579ebccf1e3SJoseph Koshy 
2580ebccf1e3SJoseph Koshy 	for (;count--; ev++, names++)
2581ebccf1e3SJoseph Koshy 		*names = ev->pm_ev_name;
2582aa342b1fSJoseph Koshy 	return (0);
2583ebccf1e3SJoseph Koshy }
2584ebccf1e3SJoseph Koshy 
2585f263522aSJoseph Koshy int
2586f263522aSJoseph Koshy pmc_flush_logfile(void)
2587f263522aSJoseph Koshy {
2588aa342b1fSJoseph Koshy 	return (PMC_CALL(FLUSHLOG,0));
2589f263522aSJoseph Koshy }
2590ebccf1e3SJoseph Koshy 
2591ebccf1e3SJoseph Koshy int
2592f263522aSJoseph Koshy pmc_get_driver_stats(struct pmc_driverstats *ds)
2593ebccf1e3SJoseph Koshy {
2594f263522aSJoseph Koshy 	struct pmc_op_getdriverstats gms;
2595f263522aSJoseph Koshy 
2596f263522aSJoseph Koshy 	if (PMC_CALL(GETDRIVERSTATS, &gms) < 0)
2597aa342b1fSJoseph Koshy 		return (-1);
2598f263522aSJoseph Koshy 
2599f263522aSJoseph Koshy 	/* copy out fields in the current userland<->library interface */
2600f263522aSJoseph Koshy 	ds->pm_intr_ignored    = gms.pm_intr_ignored;
2601f263522aSJoseph Koshy 	ds->pm_intr_processed  = gms.pm_intr_processed;
2602f263522aSJoseph Koshy 	ds->pm_intr_bufferfull = gms.pm_intr_bufferfull;
2603f263522aSJoseph Koshy 	ds->pm_syscalls        = gms.pm_syscalls;
2604f263522aSJoseph Koshy 	ds->pm_syscall_errors  = gms.pm_syscall_errors;
2605f263522aSJoseph Koshy 	ds->pm_buffer_requests = gms.pm_buffer_requests;
2606f263522aSJoseph Koshy 	ds->pm_buffer_requests_failed = gms.pm_buffer_requests_failed;
2607f263522aSJoseph Koshy 	ds->pm_log_sweeps      = gms.pm_log_sweeps;
2608aa342b1fSJoseph Koshy 	return (0);
2609f263522aSJoseph Koshy }
2610f263522aSJoseph Koshy 
2611f263522aSJoseph Koshy int
2612f263522aSJoseph Koshy pmc_get_msr(pmc_id_t pmc, uint32_t *msr)
2613f263522aSJoseph Koshy {
2614f263522aSJoseph Koshy 	struct pmc_op_getmsr gm;
2615ebccf1e3SJoseph Koshy 
2616ebccf1e3SJoseph Koshy 	gm.pm_pmcid = pmc;
2617f263522aSJoseph Koshy 	if (PMC_CALL(PMCGETMSR, &gm) < 0)
2618aa342b1fSJoseph Koshy 		return (-1);
2619ebccf1e3SJoseph Koshy 	*msr = gm.pm_msr;
2620aa342b1fSJoseph Koshy 	return (0);
2621ebccf1e3SJoseph Koshy }
2622ebccf1e3SJoseph Koshy 
2623f263522aSJoseph Koshy int
2624f263522aSJoseph Koshy pmc_init(void)
2625f263522aSJoseph Koshy {
2626f263522aSJoseph Koshy 	int error, pmc_mod_id;
26271455fcd3SJoseph Koshy 	unsigned int n;
2628f263522aSJoseph Koshy 	uint32_t abi_version;
2629f263522aSJoseph Koshy 	struct module_stat pmc_modstat;
26301455fcd3SJoseph Koshy 	struct pmc_op_getcpuinfo op_cpu_info;
2631791f5d5bSJoseph Koshy #if defined(__amd64__) || defined(__i386__)
2632791f5d5bSJoseph Koshy 	int cpu_has_iaf_counters;
2633791f5d5bSJoseph Koshy 	unsigned int t;
2634791f5d5bSJoseph Koshy #endif
2635f263522aSJoseph Koshy 
2636f263522aSJoseph Koshy 	if (pmc_syscall != -1) /* already inited */
2637aa342b1fSJoseph Koshy 		return (0);
2638f263522aSJoseph Koshy 
2639f263522aSJoseph Koshy 	/* retrieve the system call number from the KLD */
2640f263522aSJoseph Koshy 	if ((pmc_mod_id = modfind(PMC_MODULE_NAME)) < 0)
2641aa342b1fSJoseph Koshy 		return (-1);
2642f263522aSJoseph Koshy 
2643f263522aSJoseph Koshy 	pmc_modstat.version = sizeof(struct module_stat);
2644f263522aSJoseph Koshy 	if ((error = modstat(pmc_mod_id, &pmc_modstat)) < 0)
2645aa342b1fSJoseph Koshy 		return (-1);
2646f263522aSJoseph Koshy 
2647f263522aSJoseph Koshy 	pmc_syscall = pmc_modstat.data.intval;
2648f263522aSJoseph Koshy 
2649f263522aSJoseph Koshy 	/* check the kernel module's ABI against our compiled-in version */
2650f263522aSJoseph Koshy 	abi_version = PMC_VERSION;
2651f263522aSJoseph Koshy 	if (PMC_CALL(GETMODULEVERSION, &abi_version) < 0)
2652f263522aSJoseph Koshy 		return (pmc_syscall = -1);
2653f263522aSJoseph Koshy 
2654f263522aSJoseph Koshy 	/* ignore patch & minor numbers for the comparision */
2655f263522aSJoseph Koshy 	if ((abi_version & 0xFF000000) != (PMC_VERSION & 0xFF000000)) {
2656f263522aSJoseph Koshy 		errno  = EPROGMISMATCH;
2657f263522aSJoseph Koshy 		return (pmc_syscall = -1);
2658f263522aSJoseph Koshy 	}
2659f263522aSJoseph Koshy 
26601455fcd3SJoseph Koshy 	if (PMC_CALL(GETCPUINFO, &op_cpu_info) < 0)
2661f263522aSJoseph Koshy 		return (pmc_syscall = -1);
2662f263522aSJoseph Koshy 
26631455fcd3SJoseph Koshy 	cpu_info.pm_cputype = op_cpu_info.pm_cputype;
26641455fcd3SJoseph Koshy 	cpu_info.pm_ncpu    = op_cpu_info.pm_ncpu;
26651455fcd3SJoseph Koshy 	cpu_info.pm_npmc    = op_cpu_info.pm_npmc;
26661455fcd3SJoseph Koshy 	cpu_info.pm_nclass  = op_cpu_info.pm_nclass;
26671455fcd3SJoseph Koshy 	for (n = 0; n < cpu_info.pm_nclass; n++)
26681455fcd3SJoseph Koshy 		cpu_info.pm_classes[n] = op_cpu_info.pm_classes[n];
26691455fcd3SJoseph Koshy 
26700cfab8ddSJoseph Koshy 	pmc_class_table = malloc(PMC_CLASS_TABLE_SIZE *
26710cfab8ddSJoseph Koshy 	    sizeof(struct pmc_class_descr *));
26720cfab8ddSJoseph Koshy 
26730cfab8ddSJoseph Koshy 	if (pmc_class_table == NULL)
26740cfab8ddSJoseph Koshy 		return (-1);
26750cfab8ddSJoseph Koshy 
2676791f5d5bSJoseph Koshy 	for (n = 0; n < PMC_CLASS_TABLE_SIZE; n++)
2677791f5d5bSJoseph Koshy 		pmc_class_table[n] = NULL;
26780cfab8ddSJoseph Koshy 
26790cfab8ddSJoseph Koshy 	/*
26800cfab8ddSJoseph Koshy 	 * Fill in the class table.
26810cfab8ddSJoseph Koshy 	 */
26820cfab8ddSJoseph Koshy 	n = 0;
26830cfab8ddSJoseph Koshy #if defined(__amd64__) || defined(__i386__)
26840cfab8ddSJoseph Koshy 	pmc_class_table[n++] = &tsc_class_table_descr;
2685791f5d5bSJoseph Koshy 
2686791f5d5bSJoseph Koshy 	/*
2687791f5d5bSJoseph Koshy  	 * Check if this CPU has fixed function counters.
2688791f5d5bSJoseph Koshy 	 */
2689791f5d5bSJoseph Koshy 	cpu_has_iaf_counters = 0;
2690791f5d5bSJoseph Koshy 	for (t = 0; t < cpu_info.pm_nclass; t++)
2691791f5d5bSJoseph Koshy 		if (cpu_info.pm_classes[t].pm_class == PMC_CLASS_IAF)
2692791f5d5bSJoseph Koshy 			cpu_has_iaf_counters = 1;
26930cfab8ddSJoseph Koshy #endif
26940cfab8ddSJoseph Koshy 
2695789140c0SJoseph Koshy #define	PMC_MDEP_INIT(C) do {					\
2696789140c0SJoseph Koshy 		pmc_mdep_event_aliases    = C##_aliases;	\
2697789140c0SJoseph Koshy 		pmc_mdep_class_list  = C##_pmc_classes;		\
2698789140c0SJoseph Koshy 		pmc_mdep_class_list_size =			\
2699789140c0SJoseph Koshy 		    PMC_TABLE_SIZE(C##_pmc_classes);		\
2700789140c0SJoseph Koshy 	} while (0)
2701789140c0SJoseph Koshy 
2702791f5d5bSJoseph Koshy #define	PMC_MDEP_INIT_INTEL_V2(C) do {					\
2703791f5d5bSJoseph Koshy 		PMC_MDEP_INIT(C);					\
2704791f5d5bSJoseph Koshy 		if (cpu_has_iaf_counters) 				\
2705791f5d5bSJoseph Koshy 			pmc_class_table[n++] = &iaf_class_table_descr;	\
2706791f5d5bSJoseph Koshy 		else							\
2707791f5d5bSJoseph Koshy 			pmc_mdep_event_aliases =			\
2708791f5d5bSJoseph Koshy 				C##_aliases_without_iaf;		\
2709791f5d5bSJoseph Koshy 		pmc_class_table[n] = &C##_class_table_descr;		\
2710791f5d5bSJoseph Koshy 	} while (0)
2711791f5d5bSJoseph Koshy 
2712789140c0SJoseph Koshy 	/* Configure the event name parser. */
2713f263522aSJoseph Koshy 	switch (cpu_info.pm_cputype) {
2714f263522aSJoseph Koshy #if defined(__i386__)
2715f263522aSJoseph Koshy 	case PMC_CPU_AMD_K7:
2716789140c0SJoseph Koshy 		PMC_MDEP_INIT(k7);
27170cfab8ddSJoseph Koshy 		pmc_class_table[n] = &k7_class_table_descr;
2718f263522aSJoseph Koshy 		break;
2719f263522aSJoseph Koshy 	case PMC_CPU_INTEL_P5:
2720789140c0SJoseph Koshy 		PMC_MDEP_INIT(p5);
27210cfab8ddSJoseph Koshy 		pmc_class_table[n]  = &p5_class_table_descr;
2722f263522aSJoseph Koshy 		break;
2723f263522aSJoseph Koshy 	case PMC_CPU_INTEL_P6:		/* P6 ... Pentium M CPUs have */
2724f263522aSJoseph Koshy 	case PMC_CPU_INTEL_PII:		/* similar PMCs. */
2725f263522aSJoseph Koshy 	case PMC_CPU_INTEL_PIII:
2726f263522aSJoseph Koshy 	case PMC_CPU_INTEL_PM:
2727789140c0SJoseph Koshy 		PMC_MDEP_INIT(p6);
27280cfab8ddSJoseph Koshy 		pmc_class_table[n] = &p6_class_table_descr;
2729f263522aSJoseph Koshy 		break;
273086a65549SJoseph Koshy #endif
273186a65549SJoseph Koshy #if defined(__amd64__) || defined(__i386__)
2732f263522aSJoseph Koshy 	case PMC_CPU_AMD_K8:
2733789140c0SJoseph Koshy 		PMC_MDEP_INIT(k8);
27340cfab8ddSJoseph Koshy 		pmc_class_table[n] = &k8_class_table_descr;
27350cfab8ddSJoseph Koshy 		break;
27360cfab8ddSJoseph Koshy 	case PMC_CPU_INTEL_ATOM:
2737791f5d5bSJoseph Koshy 		PMC_MDEP_INIT_INTEL_V2(atom);
27380cfab8ddSJoseph Koshy 		break;
27390cfab8ddSJoseph Koshy 	case PMC_CPU_INTEL_CORE:
27400cfab8ddSJoseph Koshy 		PMC_MDEP_INIT(core);
2741bc315bbdSJoseph Koshy 		pmc_class_table[n] = &core_class_table_descr;
27420cfab8ddSJoseph Koshy 		break;
27430cfab8ddSJoseph Koshy 	case PMC_CPU_INTEL_CORE2:
2744b4d091f3SJoseph Koshy 	case PMC_CPU_INTEL_CORE2EXTREME:
2745791f5d5bSJoseph Koshy 		PMC_MDEP_INIT_INTEL_V2(core2);
2746789140c0SJoseph Koshy 		break;
2747597979c4SJeff Roberson 	case PMC_CPU_INTEL_COREI7:
27481fa7f10bSFabien Thomas 		pmc_class_table[n++] = &ucf_class_table_descr;
27491fa7f10bSFabien Thomas 		pmc_class_table[n++] = &corei7uc_class_table_descr;
2750791f5d5bSJoseph Koshy 		PMC_MDEP_INIT_INTEL_V2(corei7);
2751597979c4SJeff Roberson 		break;
27521fa7f10bSFabien Thomas 	case PMC_CPU_INTEL_WESTMERE:
27531fa7f10bSFabien Thomas 		pmc_class_table[n++] = &ucf_class_table_descr;
27541fa7f10bSFabien Thomas 		pmc_class_table[n++] = &westmereuc_class_table_descr;
27551fa7f10bSFabien Thomas 		PMC_MDEP_INIT_INTEL_V2(westmere);
27561fa7f10bSFabien Thomas 		break;
2757789140c0SJoseph Koshy 	case PMC_CPU_INTEL_PIV:
2758789140c0SJoseph Koshy 		PMC_MDEP_INIT(p4);
27590cfab8ddSJoseph Koshy 		pmc_class_table[n] = &p4_class_table_descr;
2760f263522aSJoseph Koshy 		break;
2761ebccf1e3SJoseph Koshy #endif
27620ce207d2SRui Paulo #if defined(__XSCALE__)
27630ce207d2SRui Paulo 	case PMC_CPU_INTEL_XSCALE:
27640ce207d2SRui Paulo 		PMC_MDEP_INIT(xscale);
27650ce207d2SRui Paulo 		pmc_class_table[n] = &xscale_class_table_descr;
27660ce207d2SRui Paulo 		break;
27670ce207d2SRui Paulo #endif
2768660df75eSGeorge V. Neville-Neil #if defined(__mips__)
2769660df75eSGeorge V. Neville-Neil 	case PMC_CPU_MIPS_24K:
2770660df75eSGeorge V. Neville-Neil 		PMC_MDEP_INIT(mips24k);
2771660df75eSGeorge V. Neville-Neil 		pmc_class_table[n] = &mips24k_class_table_descr;
2772660df75eSGeorge V. Neville-Neil 		break;
2773660df75eSGeorge V. Neville-Neil #endif /* __mips__ */
2774f263522aSJoseph Koshy 	default:
2775f263522aSJoseph Koshy 		/*
2776f263522aSJoseph Koshy 		 * Some kind of CPU this version of the library knows nothing
2777f263522aSJoseph Koshy 		 * about.  This shouldn't happen since the abi version check
2778f263522aSJoseph Koshy 		 * should have caught this.
2779f263522aSJoseph Koshy 		 */
2780f263522aSJoseph Koshy 		errno = ENXIO;
2781f263522aSJoseph Koshy 		return (pmc_syscall = -1);
2782f263522aSJoseph Koshy 	}
2783f263522aSJoseph Koshy 
2784aa342b1fSJoseph Koshy 	return (0);
2785f263522aSJoseph Koshy }
2786f263522aSJoseph Koshy 
2787f263522aSJoseph Koshy const char *
2788f263522aSJoseph Koshy pmc_name_of_capability(enum pmc_caps cap)
2789f263522aSJoseph Koshy {
2790f263522aSJoseph Koshy 	int i;
2791f263522aSJoseph Koshy 
2792f263522aSJoseph Koshy 	/*
2793f263522aSJoseph Koshy 	 * 'cap' should have a single bit set and should be in
2794f263522aSJoseph Koshy 	 * range.
2795f263522aSJoseph Koshy 	 */
2796f263522aSJoseph Koshy 	if ((cap & (cap - 1)) || cap < PMC_CAP_FIRST ||
2797f263522aSJoseph Koshy 	    cap > PMC_CAP_LAST) {
2798f263522aSJoseph Koshy 		errno = EINVAL;
2799aa342b1fSJoseph Koshy 		return (NULL);
2800f263522aSJoseph Koshy 	}
2801f263522aSJoseph Koshy 
2802f263522aSJoseph Koshy 	i = ffs(cap);
2803aa342b1fSJoseph Koshy 	return (pmc_capability_names[i - 1]);
2804f263522aSJoseph Koshy }
2805f263522aSJoseph Koshy 
2806f263522aSJoseph Koshy const char *
2807f263522aSJoseph Koshy pmc_name_of_class(enum pmc_class pc)
2808f263522aSJoseph Koshy {
2809f263522aSJoseph Koshy 	if ((int) pc >= PMC_CLASS_FIRST &&
2810f263522aSJoseph Koshy 	    pc <= PMC_CLASS_LAST)
2811aa342b1fSJoseph Koshy 		return (pmc_class_names[pc]);
2812f263522aSJoseph Koshy 
2813f263522aSJoseph Koshy 	errno = EINVAL;
2814aa342b1fSJoseph Koshy 	return (NULL);
2815f263522aSJoseph Koshy }
2816f263522aSJoseph Koshy 
2817f263522aSJoseph Koshy const char *
2818f263522aSJoseph Koshy pmc_name_of_cputype(enum pmc_cputype cp)
2819f263522aSJoseph Koshy {
2820789140c0SJoseph Koshy 	size_t n;
2821789140c0SJoseph Koshy 
2822789140c0SJoseph Koshy 	for (n = 0; n < PMC_TABLE_SIZE(pmc_cputype_names); n++)
2823789140c0SJoseph Koshy 		if (cp == pmc_cputype_names[n].pm_cputype)
2824789140c0SJoseph Koshy 			return (pmc_cputype_names[n].pm_name);
2825789140c0SJoseph Koshy 
2826f263522aSJoseph Koshy 	errno = EINVAL;
2827aa342b1fSJoseph Koshy 	return (NULL);
2828f263522aSJoseph Koshy }
2829f263522aSJoseph Koshy 
2830f263522aSJoseph Koshy const char *
2831f263522aSJoseph Koshy pmc_name_of_disposition(enum pmc_disp pd)
2832f263522aSJoseph Koshy {
2833f263522aSJoseph Koshy 	if ((int) pd >= PMC_DISP_FIRST &&
2834f263522aSJoseph Koshy 	    pd <= PMC_DISP_LAST)
2835aa342b1fSJoseph Koshy 		return (pmc_disposition_names[pd]);
2836f263522aSJoseph Koshy 
2837f263522aSJoseph Koshy 	errno = EINVAL;
2838aa342b1fSJoseph Koshy 	return (NULL);
2839f263522aSJoseph Koshy }
2840f263522aSJoseph Koshy 
2841f263522aSJoseph Koshy const char *
28420cfab8ddSJoseph Koshy _pmc_name_of_event(enum pmc_event pe, enum pmc_cputype cpu)
2843f263522aSJoseph Koshy {
2844789140c0SJoseph Koshy 	const struct pmc_event_descr *ev, *evfence;
2845789140c0SJoseph Koshy 
2846789140c0SJoseph Koshy 	ev = evfence = NULL;
28470cfab8ddSJoseph Koshy 	if (pe >= PMC_EV_IAF_FIRST && pe <= PMC_EV_IAF_LAST) {
28480cfab8ddSJoseph Koshy 		ev = iaf_event_table;
28490cfab8ddSJoseph Koshy 		evfence = iaf_event_table + PMC_EVENT_TABLE_SIZE(iaf);
28500cfab8ddSJoseph Koshy 	} else if (pe >= PMC_EV_IAP_FIRST && pe <= PMC_EV_IAP_LAST) {
28510cfab8ddSJoseph Koshy 		switch (cpu) {
28520cfab8ddSJoseph Koshy 		case PMC_CPU_INTEL_ATOM:
28530cfab8ddSJoseph Koshy 			ev = atom_event_table;
28540cfab8ddSJoseph Koshy 			evfence = atom_event_table + PMC_EVENT_TABLE_SIZE(atom);
28550cfab8ddSJoseph Koshy 			break;
28560cfab8ddSJoseph Koshy 		case PMC_CPU_INTEL_CORE:
28570cfab8ddSJoseph Koshy 			ev = core_event_table;
28580cfab8ddSJoseph Koshy 			evfence = core_event_table + PMC_EVENT_TABLE_SIZE(core);
28590cfab8ddSJoseph Koshy 			break;
28600cfab8ddSJoseph Koshy 		case PMC_CPU_INTEL_CORE2:
2861b4d091f3SJoseph Koshy 		case PMC_CPU_INTEL_CORE2EXTREME:
28620cfab8ddSJoseph Koshy 			ev = core2_event_table;
28630cfab8ddSJoseph Koshy 			evfence = core2_event_table + PMC_EVENT_TABLE_SIZE(core2);
28640cfab8ddSJoseph Koshy 			break;
2865597979c4SJeff Roberson 		case PMC_CPU_INTEL_COREI7:
2866597979c4SJeff Roberson 			ev = corei7_event_table;
2867597979c4SJeff Roberson 			evfence = corei7_event_table + PMC_EVENT_TABLE_SIZE(corei7);
2868597979c4SJeff Roberson 			break;
28691fa7f10bSFabien Thomas 		case PMC_CPU_INTEL_WESTMERE:
28701fa7f10bSFabien Thomas 			ev = westmere_event_table;
28711fa7f10bSFabien Thomas 			evfence = westmere_event_table + PMC_EVENT_TABLE_SIZE(westmere);
28721fa7f10bSFabien Thomas 			break;
28730cfab8ddSJoseph Koshy 		default:	/* Unknown CPU type. */
28740cfab8ddSJoseph Koshy 			break;
28750cfab8ddSJoseph Koshy 		}
28761fa7f10bSFabien Thomas 	} else if (pe >= PMC_EV_UCF_FIRST && pe <= PMC_EV_UCF_LAST) {
28771fa7f10bSFabien Thomas 		ev = ucf_event_table;
28781fa7f10bSFabien Thomas 		evfence = ucf_event_table + PMC_EVENT_TABLE_SIZE(ucf);
28791fa7f10bSFabien Thomas 	} else if (pe >= PMC_EV_UCP_FIRST && pe <= PMC_EV_UCP_LAST) {
28801fa7f10bSFabien Thomas 		switch (cpu) {
28811fa7f10bSFabien Thomas 		case PMC_CPU_INTEL_COREI7:
28821fa7f10bSFabien Thomas 			ev = corei7uc_event_table;
28831fa7f10bSFabien Thomas 			evfence = corei7uc_event_table + PMC_EVENT_TABLE_SIZE(corei7uc);
28841fa7f10bSFabien Thomas 			break;
28851fa7f10bSFabien Thomas 		case PMC_CPU_INTEL_WESTMERE:
28861fa7f10bSFabien Thomas 			ev = westmereuc_event_table;
28871fa7f10bSFabien Thomas 			evfence = westmereuc_event_table + PMC_EVENT_TABLE_SIZE(westmereuc);
28881fa7f10bSFabien Thomas 			break;
28891fa7f10bSFabien Thomas 		default:	/* Unknown CPU type. */
28901fa7f10bSFabien Thomas 			break;
28911fa7f10bSFabien Thomas 		}
28921fa7f10bSFabien Thomas 	} else if (pe >= PMC_EV_K7_FIRST && pe <= PMC_EV_K7_LAST) {
2893789140c0SJoseph Koshy 		ev = k7_event_table;
2894789140c0SJoseph Koshy 		evfence = k7_event_table + PMC_EVENT_TABLE_SIZE(k7);
2895789140c0SJoseph Koshy 	} else if (pe >= PMC_EV_K8_FIRST && pe <= PMC_EV_K8_LAST) {
2896789140c0SJoseph Koshy 		ev = k8_event_table;
2897789140c0SJoseph Koshy 		evfence = k8_event_table + PMC_EVENT_TABLE_SIZE(k8);
2898789140c0SJoseph Koshy 	} else if (pe >= PMC_EV_P4_FIRST && pe <= PMC_EV_P4_LAST) {
2899789140c0SJoseph Koshy 		ev = p4_event_table;
2900789140c0SJoseph Koshy 		evfence = p4_event_table + PMC_EVENT_TABLE_SIZE(p4);
2901789140c0SJoseph Koshy 	} else if (pe >= PMC_EV_P5_FIRST && pe <= PMC_EV_P5_LAST) {
2902789140c0SJoseph Koshy 		ev = p5_event_table;
2903789140c0SJoseph Koshy 		evfence = p5_event_table + PMC_EVENT_TABLE_SIZE(p5);
2904789140c0SJoseph Koshy 	} else if (pe >= PMC_EV_P6_FIRST && pe <= PMC_EV_P6_LAST) {
2905789140c0SJoseph Koshy 		ev = p6_event_table;
2906789140c0SJoseph Koshy 		evfence = p6_event_table + PMC_EVENT_TABLE_SIZE(p6);
29070ce207d2SRui Paulo 	} else if (pe >= PMC_EV_XSCALE_FIRST && pe <= PMC_EV_XSCALE_LAST) {
29080ce207d2SRui Paulo 		ev = xscale_event_table;
29090ce207d2SRui Paulo 		evfence = xscale_event_table + PMC_EVENT_TABLE_SIZE(xscale);
2910660df75eSGeorge V. Neville-Neil 	} else if (pe >= PMC_EV_MIPS24K_FIRST && pe <= PMC_EV_MIPS24K_LAST) {
2911660df75eSGeorge V. Neville-Neil 		ev = mips24k_event_table;
2912660df75eSGeorge V. Neville-Neil 		evfence = mips24k_event_table + PMC_EVENT_TABLE_SIZE(mips24k
2913660df75eSGeorge V. Neville-Neil );
2914789140c0SJoseph Koshy 	} else if (pe == PMC_EV_TSC_TSC) {
2915789140c0SJoseph Koshy 		ev = tsc_event_table;
2916789140c0SJoseph Koshy 		evfence = tsc_event_table + PMC_EVENT_TABLE_SIZE(tsc);
2917789140c0SJoseph Koshy 	}
2918789140c0SJoseph Koshy 
2919789140c0SJoseph Koshy 	for (; ev != evfence; ev++)
2920789140c0SJoseph Koshy 		if (pe == ev->pm_ev_code)
2921789140c0SJoseph Koshy 			return (ev->pm_ev_name);
2922f263522aSJoseph Koshy 
29230cfab8ddSJoseph Koshy 	return (NULL);
29240cfab8ddSJoseph Koshy }
29250cfab8ddSJoseph Koshy 
29260cfab8ddSJoseph Koshy const char *
29270cfab8ddSJoseph Koshy pmc_name_of_event(enum pmc_event pe)
29280cfab8ddSJoseph Koshy {
29290cfab8ddSJoseph Koshy 	const char *n;
29300cfab8ddSJoseph Koshy 
29310cfab8ddSJoseph Koshy 	if ((n = _pmc_name_of_event(pe, cpu_info.pm_cputype)) != NULL)
29320cfab8ddSJoseph Koshy 		return (n);
29330cfab8ddSJoseph Koshy 
2934f263522aSJoseph Koshy 	errno = EINVAL;
2935aa342b1fSJoseph Koshy 	return (NULL);
2936f263522aSJoseph Koshy }
2937f263522aSJoseph Koshy 
2938f263522aSJoseph Koshy const char *
2939f263522aSJoseph Koshy pmc_name_of_mode(enum pmc_mode pm)
2940f263522aSJoseph Koshy {
2941f263522aSJoseph Koshy 	if ((int) pm >= PMC_MODE_FIRST &&
2942f263522aSJoseph Koshy 	    pm <= PMC_MODE_LAST)
2943aa342b1fSJoseph Koshy 		return (pmc_mode_names[pm]);
2944f263522aSJoseph Koshy 
2945f263522aSJoseph Koshy 	errno = EINVAL;
2946aa342b1fSJoseph Koshy 	return (NULL);
2947f263522aSJoseph Koshy }
2948f263522aSJoseph Koshy 
2949f263522aSJoseph Koshy const char *
2950f263522aSJoseph Koshy pmc_name_of_state(enum pmc_state ps)
2951f263522aSJoseph Koshy {
2952f263522aSJoseph Koshy 	if ((int) ps >= PMC_STATE_FIRST &&
2953f263522aSJoseph Koshy 	    ps <= PMC_STATE_LAST)
2954aa342b1fSJoseph Koshy 		return (pmc_state_names[ps]);
2955f263522aSJoseph Koshy 
2956f263522aSJoseph Koshy 	errno = EINVAL;
2957aa342b1fSJoseph Koshy 	return (NULL);
2958f263522aSJoseph Koshy }
2959f263522aSJoseph Koshy 
2960f263522aSJoseph Koshy int
2961f263522aSJoseph Koshy pmc_ncpu(void)
2962f263522aSJoseph Koshy {
2963f263522aSJoseph Koshy 	if (pmc_syscall == -1) {
2964f263522aSJoseph Koshy 		errno = ENXIO;
2965aa342b1fSJoseph Koshy 		return (-1);
2966f263522aSJoseph Koshy 	}
2967f263522aSJoseph Koshy 
2968aa342b1fSJoseph Koshy 	return (cpu_info.pm_ncpu);
2969f263522aSJoseph Koshy }
2970f263522aSJoseph Koshy 
2971f263522aSJoseph Koshy int
2972f263522aSJoseph Koshy pmc_npmc(int cpu)
2973f263522aSJoseph Koshy {
2974f263522aSJoseph Koshy 	if (pmc_syscall == -1) {
2975f263522aSJoseph Koshy 		errno = ENXIO;
2976aa342b1fSJoseph Koshy 		return (-1);
2977f263522aSJoseph Koshy 	}
2978f263522aSJoseph Koshy 
2979f263522aSJoseph Koshy 	if (cpu < 0 || cpu >= (int) cpu_info.pm_ncpu) {
2980f263522aSJoseph Koshy 		errno = EINVAL;
2981aa342b1fSJoseph Koshy 		return (-1);
2982f263522aSJoseph Koshy 	}
2983f263522aSJoseph Koshy 
2984aa342b1fSJoseph Koshy 	return (cpu_info.pm_npmc);
2985f263522aSJoseph Koshy }
2986f263522aSJoseph Koshy 
2987f263522aSJoseph Koshy int
2988f263522aSJoseph Koshy pmc_pmcinfo(int cpu, struct pmc_pmcinfo **ppmci)
2989f263522aSJoseph Koshy {
2990f263522aSJoseph Koshy 	int nbytes, npmc;
2991f263522aSJoseph Koshy 	struct pmc_op_getpmcinfo *pmci;
2992f263522aSJoseph Koshy 
2993f263522aSJoseph Koshy 	if ((npmc = pmc_npmc(cpu)) < 0)
2994aa342b1fSJoseph Koshy 		return (-1);
2995f263522aSJoseph Koshy 
2996f263522aSJoseph Koshy 	nbytes = sizeof(struct pmc_op_getpmcinfo) +
2997f263522aSJoseph Koshy 	    npmc * sizeof(struct pmc_info);
2998f263522aSJoseph Koshy 
2999f263522aSJoseph Koshy 	if ((pmci = calloc(1, nbytes)) == NULL)
3000aa342b1fSJoseph Koshy 		return (-1);
3001f263522aSJoseph Koshy 
3002f263522aSJoseph Koshy 	pmci->pm_cpu  = cpu;
3003f263522aSJoseph Koshy 
3004f263522aSJoseph Koshy 	if (PMC_CALL(GETPMCINFO, pmci) < 0) {
3005f263522aSJoseph Koshy 		free(pmci);
3006aa342b1fSJoseph Koshy 		return (-1);
3007f263522aSJoseph Koshy 	}
3008f263522aSJoseph Koshy 
3009f263522aSJoseph Koshy 	/* kernel<->library, library<->userland interfaces are identical */
3010f263522aSJoseph Koshy 	*ppmci = (struct pmc_pmcinfo *) pmci;
3011aa342b1fSJoseph Koshy 	return (0);
3012f263522aSJoseph Koshy }
3013f263522aSJoseph Koshy 
3014f263522aSJoseph Koshy int
3015f263522aSJoseph Koshy pmc_read(pmc_id_t pmc, pmc_value_t *value)
3016f263522aSJoseph Koshy {
3017f263522aSJoseph Koshy 	struct pmc_op_pmcrw pmc_read_op;
3018f263522aSJoseph Koshy 
3019f263522aSJoseph Koshy 	pmc_read_op.pm_pmcid = pmc;
3020f263522aSJoseph Koshy 	pmc_read_op.pm_flags = PMC_F_OLDVALUE;
3021f263522aSJoseph Koshy 	pmc_read_op.pm_value = -1;
3022f263522aSJoseph Koshy 
3023f263522aSJoseph Koshy 	if (PMC_CALL(PMCRW, &pmc_read_op) < 0)
3024aa342b1fSJoseph Koshy 		return (-1);
3025f263522aSJoseph Koshy 
3026f263522aSJoseph Koshy 	*value = pmc_read_op.pm_value;
3027aa342b1fSJoseph Koshy 	return (0);
3028f263522aSJoseph Koshy }
3029f263522aSJoseph Koshy 
3030f263522aSJoseph Koshy int
3031f263522aSJoseph Koshy pmc_release(pmc_id_t pmc)
3032f263522aSJoseph Koshy {
3033f263522aSJoseph Koshy 	struct pmc_op_simple	pmc_release_args;
3034f263522aSJoseph Koshy 
3035f263522aSJoseph Koshy 	pmc_release_args.pm_pmcid = pmc;
3036aa342b1fSJoseph Koshy 	return (PMC_CALL(PMCRELEASE, &pmc_release_args));
3037f263522aSJoseph Koshy }
3038f263522aSJoseph Koshy 
3039f263522aSJoseph Koshy int
3040f263522aSJoseph Koshy pmc_rw(pmc_id_t pmc, pmc_value_t newvalue, pmc_value_t *oldvaluep)
3041f263522aSJoseph Koshy {
3042f263522aSJoseph Koshy 	struct pmc_op_pmcrw pmc_rw_op;
3043f263522aSJoseph Koshy 
3044f263522aSJoseph Koshy 	pmc_rw_op.pm_pmcid = pmc;
3045f263522aSJoseph Koshy 	pmc_rw_op.pm_flags = PMC_F_NEWVALUE | PMC_F_OLDVALUE;
3046f263522aSJoseph Koshy 	pmc_rw_op.pm_value = newvalue;
3047f263522aSJoseph Koshy 
3048f263522aSJoseph Koshy 	if (PMC_CALL(PMCRW, &pmc_rw_op) < 0)
3049aa342b1fSJoseph Koshy 		return (-1);
3050f263522aSJoseph Koshy 
3051f263522aSJoseph Koshy 	*oldvaluep = pmc_rw_op.pm_value;
3052aa342b1fSJoseph Koshy 	return (0);
3053f263522aSJoseph Koshy }
3054f263522aSJoseph Koshy 
3055f263522aSJoseph Koshy int
3056f263522aSJoseph Koshy pmc_set(pmc_id_t pmc, pmc_value_t value)
3057f263522aSJoseph Koshy {
3058f263522aSJoseph Koshy 	struct pmc_op_pmcsetcount sc;
3059f263522aSJoseph Koshy 
3060f263522aSJoseph Koshy 	sc.pm_pmcid = pmc;
3061f263522aSJoseph Koshy 	sc.pm_count = value;
3062f263522aSJoseph Koshy 
3063f263522aSJoseph Koshy 	if (PMC_CALL(PMCSETCOUNT, &sc) < 0)
3064aa342b1fSJoseph Koshy 		return (-1);
3065aa342b1fSJoseph Koshy 	return (0);
3066f263522aSJoseph Koshy }
3067f263522aSJoseph Koshy 
3068f263522aSJoseph Koshy int
3069f263522aSJoseph Koshy pmc_start(pmc_id_t pmc)
3070f263522aSJoseph Koshy {
3071f263522aSJoseph Koshy 	struct pmc_op_simple	pmc_start_args;
3072f263522aSJoseph Koshy 
3073f263522aSJoseph Koshy 	pmc_start_args.pm_pmcid = pmc;
3074aa342b1fSJoseph Koshy 	return (PMC_CALL(PMCSTART, &pmc_start_args));
3075f263522aSJoseph Koshy }
3076f263522aSJoseph Koshy 
3077f263522aSJoseph Koshy int
3078f263522aSJoseph Koshy pmc_stop(pmc_id_t pmc)
3079f263522aSJoseph Koshy {
3080f263522aSJoseph Koshy 	struct pmc_op_simple	pmc_stop_args;
3081f263522aSJoseph Koshy 
3082f263522aSJoseph Koshy 	pmc_stop_args.pm_pmcid = pmc;
3083aa342b1fSJoseph Koshy 	return (PMC_CALL(PMCSTOP, &pmc_stop_args));
3084f263522aSJoseph Koshy }
3085f263522aSJoseph Koshy 
3086f263522aSJoseph Koshy int
3087f263522aSJoseph Koshy pmc_width(pmc_id_t pmcid, uint32_t *width)
3088f263522aSJoseph Koshy {
3089f263522aSJoseph Koshy 	unsigned int i;
3090f263522aSJoseph Koshy 	enum pmc_class cl;
3091f263522aSJoseph Koshy 
3092f263522aSJoseph Koshy 	cl = PMC_ID_TO_CLASS(pmcid);
3093f263522aSJoseph Koshy 	for (i = 0; i < cpu_info.pm_nclass; i++)
3094f263522aSJoseph Koshy 		if (cpu_info.pm_classes[i].pm_class == cl) {
3095f263522aSJoseph Koshy 			*width = cpu_info.pm_classes[i].pm_width;
3096aa342b1fSJoseph Koshy 			return (0);
3097f263522aSJoseph Koshy 		}
3098484202faSJoseph Koshy 	errno = EINVAL;
3099484202faSJoseph Koshy 	return (-1);
3100f263522aSJoseph Koshy }
3101f263522aSJoseph Koshy 
3102f263522aSJoseph Koshy int
3103f263522aSJoseph Koshy pmc_write(pmc_id_t pmc, pmc_value_t value)
3104f263522aSJoseph Koshy {
3105f263522aSJoseph Koshy 	struct pmc_op_pmcrw pmc_write_op;
3106f263522aSJoseph Koshy 
3107f263522aSJoseph Koshy 	pmc_write_op.pm_pmcid = pmc;
3108f263522aSJoseph Koshy 	pmc_write_op.pm_flags = PMC_F_NEWVALUE;
3109f263522aSJoseph Koshy 	pmc_write_op.pm_value = value;
3110aa342b1fSJoseph Koshy 	return (PMC_CALL(PMCRW, &pmc_write_op));
3111f263522aSJoseph Koshy }
3112f263522aSJoseph Koshy 
3113f263522aSJoseph Koshy int
3114f263522aSJoseph Koshy pmc_writelog(uint32_t userdata)
3115f263522aSJoseph Koshy {
3116f263522aSJoseph Koshy 	struct pmc_op_writelog wl;
3117f263522aSJoseph Koshy 
3118f263522aSJoseph Koshy 	wl.pm_userdata = userdata;
3119aa342b1fSJoseph Koshy 	return (PMC_CALL(WRITELOG, &wl));
3120f263522aSJoseph Koshy }
3121