xref: /freebsd/lib/libpmc/libpmc.c (revision 7b25dcca76ae1fcae855e75d6a8e3c00868f6ac1)
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 
86*7b25dccaSJustin Hibbits #if defined(__powerpc__)
87*7b25dccaSJustin Hibbits static int ppc7450_allocate_pmc(enum pmc_event _pe, char* ctrspec,
88*7b25dccaSJustin Hibbits 			     struct pmc_op_pmcallocate *_pmc_config);
89*7b25dccaSJustin Hibbits #endif /* __powerpc__ */
90660df75eSGeorge V. Neville-Neil 
91ebccf1e3SJoseph Koshy #define PMC_CALL(cmd, params)				\
92ebccf1e3SJoseph Koshy 	syscall(pmc_syscall, PMC_OP_##cmd, (params))
93ebccf1e3SJoseph Koshy 
94ebccf1e3SJoseph Koshy /*
95ebccf1e3SJoseph Koshy  * Event aliases provide a way for the user to ask for generic events
96ebccf1e3SJoseph Koshy  * like "cache-misses", or "instructions-retired".  These aliases are
97ebccf1e3SJoseph Koshy  * mapped to the appropriate canonical event descriptions using a
98ebccf1e3SJoseph Koshy  * lookup table.
99ebccf1e3SJoseph Koshy  */
100ebccf1e3SJoseph Koshy struct pmc_event_alias {
101ebccf1e3SJoseph Koshy 	const char	*pm_alias;
102ebccf1e3SJoseph Koshy 	const char	*pm_spec;
103ebccf1e3SJoseph Koshy };
104ebccf1e3SJoseph Koshy 
105ebccf1e3SJoseph Koshy static const struct pmc_event_alias *pmc_mdep_event_aliases;
106ebccf1e3SJoseph Koshy 
107ebccf1e3SJoseph Koshy /*
108789140c0SJoseph Koshy  * The pmc_event_descr structure maps symbolic names known to the user
109ebccf1e3SJoseph Koshy  * to integer codes used by the PMC KLD.
110ebccf1e3SJoseph Koshy  */
111ebccf1e3SJoseph Koshy struct pmc_event_descr {
112ebccf1e3SJoseph Koshy 	const char	*pm_ev_name;
113ebccf1e3SJoseph Koshy 	enum pmc_event	pm_ev_code;
114ebccf1e3SJoseph Koshy };
115ebccf1e3SJoseph Koshy 
116789140c0SJoseph Koshy /*
117789140c0SJoseph Koshy  * The pmc_class_descr structure maps class name prefixes for
118789140c0SJoseph Koshy  * event names to event tables and other PMC class data.
119789140c0SJoseph Koshy  */
120789140c0SJoseph Koshy struct pmc_class_descr {
121789140c0SJoseph Koshy 	const char	*pm_evc_name;
122789140c0SJoseph Koshy 	size_t		pm_evc_name_size;
123789140c0SJoseph Koshy 	enum pmc_class	pm_evc_class;
124789140c0SJoseph Koshy 	const struct pmc_event_descr *pm_evc_event_table;
125789140c0SJoseph Koshy 	size_t		pm_evc_event_table_size;
126789140c0SJoseph Koshy 	int		(*pm_evc_allocate_pmc)(enum pmc_event _pe,
127789140c0SJoseph Koshy 			    char *_ctrspec, struct pmc_op_pmcallocate *_pa);
128ebccf1e3SJoseph Koshy };
129ebccf1e3SJoseph Koshy 
130789140c0SJoseph Koshy #define	PMC_TABLE_SIZE(N)	(sizeof(N)/sizeof(N[0]))
131789140c0SJoseph Koshy #define	PMC_EVENT_TABLE_SIZE(N)	PMC_TABLE_SIZE(N##_event_table)
132789140c0SJoseph Koshy 
133789140c0SJoseph Koshy #undef	__PMC_EV
134789140c0SJoseph Koshy #define	__PMC_EV(C,N) { #N, PMC_EV_ ## C ## _ ## N },
135789140c0SJoseph Koshy 
136789140c0SJoseph Koshy /*
1370cfab8ddSJoseph Koshy  * PMC_CLASSDEP_TABLE(NAME, CLASS)
138789140c0SJoseph Koshy  *
1390cfab8ddSJoseph Koshy  * Define a table mapping event names and aliases to HWPMC event IDs.
140789140c0SJoseph Koshy  */
1410cfab8ddSJoseph Koshy #define	PMC_CLASSDEP_TABLE(N, C)				\
142789140c0SJoseph Koshy 	static const struct pmc_event_descr N##_event_table[] =	\
143789140c0SJoseph Koshy 	{							\
144789140c0SJoseph Koshy 		__PMC_EV_##C()					\
1450cfab8ddSJoseph Koshy 	}
1460cfab8ddSJoseph Koshy 
1470cfab8ddSJoseph Koshy PMC_CLASSDEP_TABLE(iaf, IAF);
1480cfab8ddSJoseph Koshy PMC_CLASSDEP_TABLE(k7, K7);
1490cfab8ddSJoseph Koshy PMC_CLASSDEP_TABLE(k8, K8);
1500cfab8ddSJoseph Koshy PMC_CLASSDEP_TABLE(p4, P4);
1510cfab8ddSJoseph Koshy PMC_CLASSDEP_TABLE(p5, P5);
1520cfab8ddSJoseph Koshy PMC_CLASSDEP_TABLE(p6, P6);
1530ce207d2SRui Paulo PMC_CLASSDEP_TABLE(xscale, XSCALE);
154660df75eSGeorge V. Neville-Neil PMC_CLASSDEP_TABLE(mips24k, MIPS24K);
1551fa7f10bSFabien Thomas PMC_CLASSDEP_TABLE(ucf, UCF);
156*7b25dccaSJustin Hibbits PMC_CLASSDEP_TABLE(ppc7450, PPC7450);
1570cfab8ddSJoseph Koshy 
1580cfab8ddSJoseph Koshy #undef	__PMC_EV_ALIAS
1590cfab8ddSJoseph Koshy #define	__PMC_EV_ALIAS(N,CODE) 	{ N, PMC_EV_##CODE },
1600cfab8ddSJoseph Koshy 
1610cfab8ddSJoseph Koshy static const struct pmc_event_descr atom_event_table[] =
1620cfab8ddSJoseph Koshy {
1630cfab8ddSJoseph Koshy 	__PMC_EV_ALIAS_ATOM()
1640cfab8ddSJoseph Koshy };
1650cfab8ddSJoseph Koshy 
1660cfab8ddSJoseph Koshy static const struct pmc_event_descr core_event_table[] =
1670cfab8ddSJoseph Koshy {
1680cfab8ddSJoseph Koshy 	__PMC_EV_ALIAS_CORE()
1690cfab8ddSJoseph Koshy };
1700cfab8ddSJoseph Koshy 
1710cfab8ddSJoseph Koshy 
1720cfab8ddSJoseph Koshy static const struct pmc_event_descr core2_event_table[] =
1730cfab8ddSJoseph Koshy {
1740cfab8ddSJoseph Koshy 	__PMC_EV_ALIAS_CORE2()
1750cfab8ddSJoseph Koshy };
1760cfab8ddSJoseph Koshy 
177597979c4SJeff Roberson static const struct pmc_event_descr corei7_event_table[] =
178597979c4SJeff Roberson {
179597979c4SJeff Roberson 	__PMC_EV_ALIAS_COREI7()
180597979c4SJeff Roberson };
181597979c4SJeff Roberson 
1821fa7f10bSFabien Thomas static const struct pmc_event_descr westmere_event_table[] =
1831fa7f10bSFabien Thomas {
1841fa7f10bSFabien Thomas 	__PMC_EV_ALIAS_WESTMERE()
1851fa7f10bSFabien Thomas };
1861fa7f10bSFabien Thomas 
1871fa7f10bSFabien Thomas static const struct pmc_event_descr corei7uc_event_table[] =
1881fa7f10bSFabien Thomas {
1891fa7f10bSFabien Thomas 	__PMC_EV_ALIAS_COREI7UC()
1901fa7f10bSFabien Thomas };
1911fa7f10bSFabien Thomas 
1921fa7f10bSFabien Thomas static const struct pmc_event_descr westmereuc_event_table[] =
1931fa7f10bSFabien Thomas {
1941fa7f10bSFabien Thomas 	__PMC_EV_ALIAS_WESTMEREUC()
1951fa7f10bSFabien Thomas };
1961fa7f10bSFabien Thomas 
1970cfab8ddSJoseph Koshy /*
1980cfab8ddSJoseph Koshy  * PMC_MDEP_TABLE(NAME, PRIMARYCLASS, ADDITIONAL_CLASSES...)
1990cfab8ddSJoseph Koshy  *
2000cfab8ddSJoseph Koshy  * Map a CPU to the PMC classes it supports.
2010cfab8ddSJoseph Koshy  */
2020cfab8ddSJoseph Koshy #define	PMC_MDEP_TABLE(N,C,...)				\
203789140c0SJoseph Koshy 	static const enum pmc_class N##_pmc_classes[] = {	\
204789140c0SJoseph Koshy 		PMC_CLASS_##C, __VA_ARGS__			\
205789140c0SJoseph Koshy 	}
206789140c0SJoseph Koshy 
2070cfab8ddSJoseph Koshy PMC_MDEP_TABLE(atom, IAP, PMC_CLASS_IAF, PMC_CLASS_TSC);
2080cfab8ddSJoseph Koshy PMC_MDEP_TABLE(core, IAP, PMC_CLASS_TSC);
2090cfab8ddSJoseph Koshy PMC_MDEP_TABLE(core2, IAP, PMC_CLASS_IAF, PMC_CLASS_TSC);
2101fa7f10bSFabien Thomas PMC_MDEP_TABLE(corei7, IAP, PMC_CLASS_IAF, PMC_CLASS_TSC, PMC_CLASS_UCF, PMC_CLASS_UCP);
2111fa7f10bSFabien Thomas PMC_MDEP_TABLE(westmere, IAP, PMC_CLASS_IAF, PMC_CLASS_TSC, PMC_CLASS_UCF, PMC_CLASS_UCP);
212789140c0SJoseph Koshy PMC_MDEP_TABLE(k7, K7, PMC_CLASS_TSC);
213789140c0SJoseph Koshy PMC_MDEP_TABLE(k8, K8, PMC_CLASS_TSC);
214789140c0SJoseph Koshy PMC_MDEP_TABLE(p4, P4, PMC_CLASS_TSC);
215789140c0SJoseph Koshy PMC_MDEP_TABLE(p5, P5, PMC_CLASS_TSC);
216789140c0SJoseph Koshy PMC_MDEP_TABLE(p6, P6, PMC_CLASS_TSC);
2170ce207d2SRui Paulo PMC_MDEP_TABLE(xscale, XSCALE, PMC_CLASS_XSCALE);
218660df75eSGeorge V. Neville-Neil PMC_MDEP_TABLE(mips24k, MIPS24K, PMC_CLASS_MIPS24K);
219*7b25dccaSJustin Hibbits PMC_MDEP_TABLE(ppc7450, PPC7450, PMC_CLASS_PPC7450);
220789140c0SJoseph Koshy 
221789140c0SJoseph Koshy static const struct pmc_event_descr tsc_event_table[] =
222789140c0SJoseph Koshy {
223789140c0SJoseph Koshy 	__PMC_EV_TSC()
224789140c0SJoseph Koshy };
225789140c0SJoseph Koshy 
226789140c0SJoseph Koshy #undef	PMC_CLASS_TABLE_DESC
2270cfab8ddSJoseph Koshy #define	PMC_CLASS_TABLE_DESC(NAME, CLASS, EVENTS, ALLOCATOR)	\
2280cfab8ddSJoseph Koshy static const struct pmc_class_descr NAME##_class_table_descr =	\
2290cfab8ddSJoseph Koshy 	{							\
2300cfab8ddSJoseph Koshy 		.pm_evc_name  = #CLASS "-",			\
2310cfab8ddSJoseph Koshy 		.pm_evc_name_size = sizeof(#CLASS "-") - 1,	\
2320cfab8ddSJoseph Koshy 		.pm_evc_class = PMC_CLASS_##CLASS ,		\
2330cfab8ddSJoseph Koshy 		.pm_evc_event_table = EVENTS##_event_table ,	\
234789140c0SJoseph Koshy 		.pm_evc_event_table_size = 			\
2350cfab8ddSJoseph Koshy 			PMC_EVENT_TABLE_SIZE(EVENTS),		\
2360cfab8ddSJoseph Koshy 		.pm_evc_allocate_pmc = ALLOCATOR##_allocate_pmc	\
237789140c0SJoseph Koshy 	}
238789140c0SJoseph Koshy 
239789140c0SJoseph Koshy #if	defined(__i386__) || defined(__amd64__)
2400cfab8ddSJoseph Koshy PMC_CLASS_TABLE_DESC(iaf, IAF, iaf, iaf);
2410cfab8ddSJoseph Koshy PMC_CLASS_TABLE_DESC(atom, IAP, atom, iap);
2420cfab8ddSJoseph Koshy PMC_CLASS_TABLE_DESC(core, IAP, core, iap);
2430cfab8ddSJoseph Koshy PMC_CLASS_TABLE_DESC(core2, IAP, core2, iap);
244597979c4SJeff Roberson PMC_CLASS_TABLE_DESC(corei7, IAP, corei7, iap);
2451fa7f10bSFabien Thomas PMC_CLASS_TABLE_DESC(westmere, IAP, westmere, iap);
2461fa7f10bSFabien Thomas PMC_CLASS_TABLE_DESC(ucf, UCF, ucf, ucf);
2471fa7f10bSFabien Thomas PMC_CLASS_TABLE_DESC(corei7uc, UCP, corei7uc, ucp);
2481fa7f10bSFabien Thomas PMC_CLASS_TABLE_DESC(westmereuc, UCP, westmereuc, ucp);
249789140c0SJoseph Koshy #endif
250789140c0SJoseph Koshy #if	defined(__i386__)
2510cfab8ddSJoseph Koshy PMC_CLASS_TABLE_DESC(k7, K7, k7, k7);
252789140c0SJoseph Koshy #endif
253789140c0SJoseph Koshy #if	defined(__i386__) || defined(__amd64__)
2540cfab8ddSJoseph Koshy PMC_CLASS_TABLE_DESC(k8, K8, k8, k8);
2550cfab8ddSJoseph Koshy PMC_CLASS_TABLE_DESC(p4, P4, p4, p4);
256789140c0SJoseph Koshy #endif
2570cfab8ddSJoseph Koshy #if	defined(__i386__)
2580cfab8ddSJoseph Koshy PMC_CLASS_TABLE_DESC(p5, P5, p5, p5);
2590cfab8ddSJoseph Koshy PMC_CLASS_TABLE_DESC(p6, P6, p6, p6);
2600cfab8ddSJoseph Koshy #endif
2610cfab8ddSJoseph Koshy #if	defined(__i386__) || defined(__amd64__)
2620cfab8ddSJoseph Koshy PMC_CLASS_TABLE_DESC(tsc, TSC, tsc, tsc);
2630cfab8ddSJoseph Koshy #endif
2640ce207d2SRui Paulo #if	defined(__XSCALE__)
2650ce207d2SRui Paulo PMC_CLASS_TABLE_DESC(xscale, XSCALE, xscale, xscale);
2660ce207d2SRui Paulo #endif
267789140c0SJoseph Koshy 
268660df75eSGeorge V. Neville-Neil #if defined(__mips__)
269660df75eSGeorge V. Neville-Neil PMC_CLASS_TABLE_DESC(mips24k, MIPS24K, mips24k, mips24k);
270660df75eSGeorge V. Neville-Neil #endif /* __mips__ */
271660df75eSGeorge V. Neville-Neil 
272*7b25dccaSJustin Hibbits #if defined(__powerpc__)
273*7b25dccaSJustin Hibbits PMC_CLASS_TABLE_DESC(ppc7450, PPC7450, ppc7450, ppc7450);
274*7b25dccaSJustin Hibbits #endif
275*7b25dccaSJustin Hibbits 
276789140c0SJoseph Koshy #undef	PMC_CLASS_TABLE_DESC
277789140c0SJoseph Koshy 
2780cfab8ddSJoseph Koshy static const struct pmc_class_descr **pmc_class_table;
2790cfab8ddSJoseph Koshy #define	PMC_CLASS_TABLE_SIZE	cpu_info.pm_nclass
2800cfab8ddSJoseph Koshy 
281789140c0SJoseph Koshy static const enum pmc_class *pmc_mdep_class_list;
282789140c0SJoseph Koshy static size_t pmc_mdep_class_list_size;
283789140c0SJoseph Koshy 
284ebccf1e3SJoseph Koshy /*
285ebccf1e3SJoseph Koshy  * Mapping tables, mapping enumeration values to human readable
286ebccf1e3SJoseph Koshy  * strings.
287ebccf1e3SJoseph Koshy  */
288ebccf1e3SJoseph Koshy 
289ebccf1e3SJoseph Koshy static const char * pmc_capability_names[] = {
290ebccf1e3SJoseph Koshy #undef	__PMC_CAP
291ebccf1e3SJoseph Koshy #define	__PMC_CAP(N,V,D)	#N ,
292ebccf1e3SJoseph Koshy 	__PMC_CAPS()
293ebccf1e3SJoseph Koshy };
294ebccf1e3SJoseph Koshy 
295ebccf1e3SJoseph Koshy static const char * pmc_class_names[] = {
296ebccf1e3SJoseph Koshy #undef	__PMC_CLASS
297ebccf1e3SJoseph Koshy #define __PMC_CLASS(C)	#C ,
298ebccf1e3SJoseph Koshy 	__PMC_CLASSES()
299ebccf1e3SJoseph Koshy };
300ebccf1e3SJoseph Koshy 
301789140c0SJoseph Koshy struct pmc_cputype_map {
302562fc14bSDimitry Andric 	enum pmc_cputype pm_cputype;
303789140c0SJoseph Koshy 	const char	*pm_name;
304789140c0SJoseph Koshy };
305789140c0SJoseph Koshy 
306789140c0SJoseph Koshy static const struct pmc_cputype_map pmc_cputype_names[] = {
307ebccf1e3SJoseph Koshy #undef	__PMC_CPU
308789140c0SJoseph Koshy #define	__PMC_CPU(S, V, D) { .pm_cputype = PMC_CPU_##S, .pm_name = #S } ,
309ebccf1e3SJoseph Koshy 	__PMC_CPUS()
310ebccf1e3SJoseph Koshy };
311ebccf1e3SJoseph Koshy 
312ebccf1e3SJoseph Koshy static const char * pmc_disposition_names[] = {
313ebccf1e3SJoseph Koshy #undef	__PMC_DISP
314ebccf1e3SJoseph Koshy #define	__PMC_DISP(D)	#D ,
315ebccf1e3SJoseph Koshy 	__PMC_DISPOSITIONS()
316ebccf1e3SJoseph Koshy };
317ebccf1e3SJoseph Koshy 
318ebccf1e3SJoseph Koshy static const char * pmc_mode_names[] = {
319ebccf1e3SJoseph Koshy #undef  __PMC_MODE
320ebccf1e3SJoseph Koshy #define __PMC_MODE(M,N)	#M ,
321ebccf1e3SJoseph Koshy 	__PMC_MODES()
322ebccf1e3SJoseph Koshy };
323ebccf1e3SJoseph Koshy 
324ebccf1e3SJoseph Koshy static const char * pmc_state_names[] = {
325ebccf1e3SJoseph Koshy #undef  __PMC_STATE
326ebccf1e3SJoseph Koshy #define __PMC_STATE(S) #S ,
327ebccf1e3SJoseph Koshy 	__PMC_STATES()
328ebccf1e3SJoseph Koshy };
329ebccf1e3SJoseph Koshy 
330ebccf1e3SJoseph Koshy static int pmc_syscall = -1;		/* filled in by pmc_init() */
331ebccf1e3SJoseph Koshy 
3321455fcd3SJoseph Koshy static struct pmc_cpuinfo cpu_info;	/* filled in by pmc_init() */
3331455fcd3SJoseph Koshy 
334ebccf1e3SJoseph Koshy /* Event masks for events */
335ebccf1e3SJoseph Koshy struct pmc_masks {
336ebccf1e3SJoseph Koshy 	const char	*pm_name;
337ebccf1e3SJoseph Koshy 	const uint32_t	pm_value;
338ebccf1e3SJoseph Koshy };
339ebccf1e3SJoseph Koshy #define	PMCMASK(N,V)	{ .pm_name = #N, .pm_value = (V) }
3401fa7f10bSFabien Thomas #define	NULLMASK	{ .pm_name = NULL }
341ebccf1e3SJoseph Koshy 
34286a65549SJoseph Koshy #if defined(__amd64__) || defined(__i386__)
343ebccf1e3SJoseph Koshy static int
344ebccf1e3SJoseph Koshy pmc_parse_mask(const struct pmc_masks *pmask, char *p, uint32_t *evmask)
345ebccf1e3SJoseph Koshy {
346ebccf1e3SJoseph Koshy 	const struct pmc_masks *pm;
347ebccf1e3SJoseph Koshy 	char *q, *r;
348ebccf1e3SJoseph Koshy 	int c;
349ebccf1e3SJoseph Koshy 
350ebccf1e3SJoseph Koshy 	if (pmask == NULL)	/* no mask keywords */
351aa342b1fSJoseph Koshy 		return (-1);
352ebccf1e3SJoseph Koshy 	q = strchr(p, '=');	/* skip '=' */
353ebccf1e3SJoseph Koshy 	if (*++q == '\0')	/* no more data */
354aa342b1fSJoseph Koshy 		return (-1);
355ebccf1e3SJoseph Koshy 	c = 0;			/* count of mask keywords seen */
356ebccf1e3SJoseph Koshy 	while ((r = strsep(&q, "+")) != NULL) {
357789140c0SJoseph Koshy 		for (pm = pmask; pm->pm_name && strcasecmp(r, pm->pm_name);
358789140c0SJoseph Koshy 		    pm++)
359ebccf1e3SJoseph Koshy 			;
360ebccf1e3SJoseph Koshy 		if (pm->pm_name == NULL) /* not found */
361aa342b1fSJoseph Koshy 			return (-1);
362ebccf1e3SJoseph Koshy 		*evmask |= pm->pm_value;
363ebccf1e3SJoseph Koshy 		c++;
364ebccf1e3SJoseph Koshy 	}
365aa342b1fSJoseph Koshy 	return (c);
366ebccf1e3SJoseph Koshy }
36704e9feb0SMarcel Moolenaar #endif
368ebccf1e3SJoseph Koshy 
369ebccf1e3SJoseph Koshy #define	KWMATCH(p,kw)		(strcasecmp((p), (kw)) == 0)
370ebccf1e3SJoseph Koshy #define	KWPREFIXMATCH(p,kw)	(strncasecmp((p), (kw), sizeof((kw)) - 1) == 0)
371ebccf1e3SJoseph Koshy #define	EV_ALIAS(N,S)		{ .pm_alias = N, .pm_spec = S }
372ebccf1e3SJoseph Koshy 
37304e9feb0SMarcel Moolenaar #if defined(__i386__)
374ebccf1e3SJoseph Koshy 
375ebccf1e3SJoseph Koshy /*
376ebccf1e3SJoseph Koshy  * AMD K7 (Athlon) CPUs.
377ebccf1e3SJoseph Koshy  */
378ebccf1e3SJoseph Koshy 
379ebccf1e3SJoseph Koshy static struct pmc_event_alias k7_aliases[] = {
380ebccf1e3SJoseph Koshy 	EV_ALIAS("branches",		"k7-retired-branches"),
381ebccf1e3SJoseph Koshy 	EV_ALIAS("branch-mispredicts",	"k7-retired-branches-mispredicted"),
382ebccf1e3SJoseph Koshy 	EV_ALIAS("cycles",		"tsc"),
3836aa5a193SJoseph Koshy 	EV_ALIAS("dc-misses",		"k7-dc-misses"),
384ebccf1e3SJoseph Koshy 	EV_ALIAS("ic-misses",		"k7-ic-misses"),
385ebccf1e3SJoseph Koshy 	EV_ALIAS("instructions",	"k7-retired-instructions"),
386ebccf1e3SJoseph Koshy 	EV_ALIAS("interrupts",		"k7-hardware-interrupts"),
387ebccf1e3SJoseph Koshy 	EV_ALIAS(NULL, NULL)
388ebccf1e3SJoseph Koshy };
389ebccf1e3SJoseph Koshy 
390ebccf1e3SJoseph Koshy #define	K7_KW_COUNT	"count"
391ebccf1e3SJoseph Koshy #define	K7_KW_EDGE	"edge"
392ebccf1e3SJoseph Koshy #define	K7_KW_INV	"inv"
393ebccf1e3SJoseph Koshy #define	K7_KW_OS	"os"
394ebccf1e3SJoseph Koshy #define	K7_KW_UNITMASK	"unitmask"
395ebccf1e3SJoseph Koshy #define	K7_KW_USR	"usr"
396ebccf1e3SJoseph Koshy 
397ebccf1e3SJoseph Koshy static int
398ebccf1e3SJoseph Koshy k7_allocate_pmc(enum pmc_event pe, char *ctrspec,
399ebccf1e3SJoseph Koshy     struct pmc_op_pmcallocate *pmc_config)
400ebccf1e3SJoseph Koshy {
401ebccf1e3SJoseph Koshy 	char		*e, *p, *q;
402ebccf1e3SJoseph Koshy 	int		c, has_unitmask;
403ebccf1e3SJoseph Koshy 	uint32_t	count, unitmask;
404ebccf1e3SJoseph Koshy 
405f263522aSJoseph Koshy 	pmc_config->pm_md.pm_amd.pm_amd_config = 0;
406789140c0SJoseph Koshy 	pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE);
407ebccf1e3SJoseph Koshy 
408ebccf1e3SJoseph Koshy 	if (pe == PMC_EV_K7_DC_REFILLS_FROM_L2 ||
409ebccf1e3SJoseph Koshy 	    pe == PMC_EV_K7_DC_REFILLS_FROM_SYSTEM ||
410ebccf1e3SJoseph Koshy 	    pe == PMC_EV_K7_DC_WRITEBACKS) {
411ebccf1e3SJoseph Koshy 		has_unitmask = 1;
412f263522aSJoseph Koshy 		unitmask = AMD_PMC_UNITMASK_MOESI;
413ebccf1e3SJoseph Koshy 	} else
414ebccf1e3SJoseph Koshy 		unitmask = has_unitmask = 0;
415ebccf1e3SJoseph Koshy 
416ebccf1e3SJoseph Koshy 	while ((p = strsep(&ctrspec, ",")) != NULL) {
417ebccf1e3SJoseph Koshy 		if (KWPREFIXMATCH(p, K7_KW_COUNT "=")) {
418ebccf1e3SJoseph Koshy 			q = strchr(p, '=');
419ebccf1e3SJoseph Koshy 			if (*++q == '\0') /* skip '=' */
420aa342b1fSJoseph Koshy 				return (-1);
421ebccf1e3SJoseph Koshy 
422ebccf1e3SJoseph Koshy 			count = strtol(q, &e, 0);
423ebccf1e3SJoseph Koshy 			if (e == q || *e != '\0')
424aa342b1fSJoseph Koshy 				return (-1);
425ebccf1e3SJoseph Koshy 
426ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_THRESHOLD;
427f263522aSJoseph Koshy 			pmc_config->pm_md.pm_amd.pm_amd_config |=
428f263522aSJoseph Koshy 			    AMD_PMC_TO_COUNTER(count);
429ebccf1e3SJoseph Koshy 
430ebccf1e3SJoseph Koshy 		} else if (KWMATCH(p, K7_KW_EDGE)) {
431ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_EDGE;
432ebccf1e3SJoseph Koshy 		} else if (KWMATCH(p, K7_KW_INV)) {
433ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_INVERT;
434ebccf1e3SJoseph Koshy 		} else if (KWMATCH(p, K7_KW_OS)) {
435ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_SYSTEM;
436ebccf1e3SJoseph Koshy 		} else if (KWPREFIXMATCH(p, K7_KW_UNITMASK "=")) {
437ebccf1e3SJoseph Koshy 			if (has_unitmask == 0)
438aa342b1fSJoseph Koshy 				return (-1);
439ebccf1e3SJoseph Koshy 			unitmask = 0;
440ebccf1e3SJoseph Koshy 			q = strchr(p, '=');
441ebccf1e3SJoseph Koshy 			if (*++q == '\0') /* skip '=' */
442aa342b1fSJoseph Koshy 				return (-1);
443ebccf1e3SJoseph Koshy 
444ebccf1e3SJoseph Koshy 			while ((c = tolower(*q++)) != 0)
445ebccf1e3SJoseph Koshy 				if (c == 'm')
446f263522aSJoseph Koshy 					unitmask |= AMD_PMC_UNITMASK_M;
447ebccf1e3SJoseph Koshy 				else if (c == 'o')
448f263522aSJoseph Koshy 					unitmask |= AMD_PMC_UNITMASK_O;
449ebccf1e3SJoseph Koshy 				else if (c == 'e')
450f263522aSJoseph Koshy 					unitmask |= AMD_PMC_UNITMASK_E;
451ebccf1e3SJoseph Koshy 				else if (c == 's')
452f263522aSJoseph Koshy 					unitmask |= AMD_PMC_UNITMASK_S;
453ebccf1e3SJoseph Koshy 				else if (c == 'i')
454f263522aSJoseph Koshy 					unitmask |= AMD_PMC_UNITMASK_I;
455ebccf1e3SJoseph Koshy 				else if (c == '+')
456ebccf1e3SJoseph Koshy 					continue;
457ebccf1e3SJoseph Koshy 				else
458aa342b1fSJoseph Koshy 					return (-1);
459ebccf1e3SJoseph Koshy 
460ebccf1e3SJoseph Koshy 			if (unitmask == 0)
461aa342b1fSJoseph Koshy 				return (-1);
462ebccf1e3SJoseph Koshy 
463ebccf1e3SJoseph Koshy 		} else if (KWMATCH(p, K7_KW_USR)) {
464ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_USER;
465ebccf1e3SJoseph Koshy 		} else
466aa342b1fSJoseph Koshy 			return (-1);
467ebccf1e3SJoseph Koshy 	}
468ebccf1e3SJoseph Koshy 
469ebccf1e3SJoseph Koshy 	if (has_unitmask) {
470ebccf1e3SJoseph Koshy 		pmc_config->pm_caps |= PMC_CAP_QUALIFIER;
471f263522aSJoseph Koshy 		pmc_config->pm_md.pm_amd.pm_amd_config |=
472f263522aSJoseph Koshy 		    AMD_PMC_TO_UNITMASK(unitmask);
473ebccf1e3SJoseph Koshy 	}
474ebccf1e3SJoseph Koshy 
475aa342b1fSJoseph Koshy 	return (0);
476ebccf1e3SJoseph Koshy 
477ebccf1e3SJoseph Koshy }
478ebccf1e3SJoseph Koshy 
479f263522aSJoseph Koshy #endif
480f263522aSJoseph Koshy 
48186a65549SJoseph Koshy #if defined(__amd64__) || defined(__i386__)
482f263522aSJoseph Koshy 
483f263522aSJoseph Koshy /*
4840cfab8ddSJoseph Koshy  * Intel Core (Family 6, Model E) PMCs.
4850cfab8ddSJoseph Koshy  */
4860cfab8ddSJoseph Koshy 
4870cfab8ddSJoseph Koshy static struct pmc_event_alias core_aliases[] = {
4880cfab8ddSJoseph Koshy 	EV_ALIAS("branches",		"iap-br-instr-ret"),
4890cfab8ddSJoseph Koshy 	EV_ALIAS("branch-mispredicts",	"iap-br-mispred-ret"),
4900cfab8ddSJoseph Koshy 	EV_ALIAS("cycles",		"tsc-tsc"),
4910cfab8ddSJoseph Koshy 	EV_ALIAS("ic-misses",		"iap-icache-misses"),
4920cfab8ddSJoseph Koshy 	EV_ALIAS("instructions",	"iap-instr-ret"),
4930cfab8ddSJoseph Koshy 	EV_ALIAS("interrupts",		"iap-core-hw-int-rx"),
4940cfab8ddSJoseph Koshy 	EV_ALIAS("unhalted-cycles",	"iap-unhalted-core-cycles"),
4950cfab8ddSJoseph Koshy 	EV_ALIAS(NULL, NULL)
4960cfab8ddSJoseph Koshy };
4970cfab8ddSJoseph Koshy 
4980cfab8ddSJoseph Koshy /*
4990cfab8ddSJoseph Koshy  * Intel Core2 (Family 6, Model F), Core2Extreme (Family 6, Model 17H)
5000cfab8ddSJoseph Koshy  * and Atom (Family 6, model 1CH) PMCs.
501791f5d5bSJoseph Koshy  *
502791f5d5bSJoseph Koshy  * We map aliases to events on the fixed-function counters if these
503791f5d5bSJoseph Koshy  * are present.  Note that not all CPUs in this family contain fixed-function
504791f5d5bSJoseph Koshy  * counters.
5050cfab8ddSJoseph Koshy  */
5060cfab8ddSJoseph Koshy 
5070cfab8ddSJoseph Koshy static struct pmc_event_alias core2_aliases[] = {
5080cfab8ddSJoseph Koshy 	EV_ALIAS("branches",		"iap-br-inst-retired.any"),
5090cfab8ddSJoseph Koshy 	EV_ALIAS("branch-mispredicts",	"iap-br-inst-retired.mispred"),
5100cfab8ddSJoseph Koshy 	EV_ALIAS("cycles",		"tsc-tsc"),
5110cfab8ddSJoseph Koshy 	EV_ALIAS("ic-misses",		"iap-l1i-misses"),
5120cfab8ddSJoseph Koshy 	EV_ALIAS("instructions",	"iaf-instr-retired.any"),
5130cfab8ddSJoseph Koshy 	EV_ALIAS("interrupts",		"iap-hw-int-rcv"),
5140cfab8ddSJoseph Koshy 	EV_ALIAS("unhalted-cycles",	"iaf-cpu-clk-unhalted.core"),
5150cfab8ddSJoseph Koshy 	EV_ALIAS(NULL, NULL)
5160cfab8ddSJoseph Koshy };
517791f5d5bSJoseph Koshy 
518791f5d5bSJoseph Koshy static struct pmc_event_alias core2_aliases_without_iaf[] = {
519791f5d5bSJoseph Koshy 	EV_ALIAS("branches",		"iap-br-inst-retired.any"),
520791f5d5bSJoseph Koshy 	EV_ALIAS("branch-mispredicts",	"iap-br-inst-retired.mispred"),
521791f5d5bSJoseph Koshy 	EV_ALIAS("cycles",		"tsc-tsc"),
522791f5d5bSJoseph Koshy 	EV_ALIAS("ic-misses",		"iap-l1i-misses"),
523791f5d5bSJoseph Koshy 	EV_ALIAS("instructions",	"iap-inst-retired.any_p"),
524791f5d5bSJoseph Koshy 	EV_ALIAS("interrupts",		"iap-hw-int-rcv"),
525791f5d5bSJoseph Koshy 	EV_ALIAS("unhalted-cycles",	"iap-cpu-clk-unhalted.core_p"),
526791f5d5bSJoseph Koshy 	EV_ALIAS(NULL, NULL)
527791f5d5bSJoseph Koshy };
528791f5d5bSJoseph Koshy 
5290cfab8ddSJoseph Koshy #define	atom_aliases			core2_aliases
530791f5d5bSJoseph Koshy #define	atom_aliases_without_iaf	core2_aliases_without_iaf
531597979c4SJeff Roberson #define corei7_aliases			core2_aliases
532791f5d5bSJoseph Koshy #define corei7_aliases_without_iaf	core2_aliases_without_iaf
5331fa7f10bSFabien Thomas #define westmere_aliases		core2_aliases
5341fa7f10bSFabien Thomas #define westmere_aliases_without_iaf	core2_aliases_without_iaf
5350cfab8ddSJoseph Koshy 
5360cfab8ddSJoseph Koshy #define	IAF_KW_OS		"os"
5370cfab8ddSJoseph Koshy #define	IAF_KW_USR		"usr"
5380cfab8ddSJoseph Koshy #define	IAF_KW_ANYTHREAD	"anythread"
5390cfab8ddSJoseph Koshy 
5400cfab8ddSJoseph Koshy /*
5410cfab8ddSJoseph Koshy  * Parse an event specifier for Intel fixed function counters.
5420cfab8ddSJoseph Koshy  */
5430cfab8ddSJoseph Koshy static int
5440cfab8ddSJoseph Koshy iaf_allocate_pmc(enum pmc_event pe, char *ctrspec,
5450cfab8ddSJoseph Koshy     struct pmc_op_pmcallocate *pmc_config)
5460cfab8ddSJoseph Koshy {
5470cfab8ddSJoseph Koshy 	char *p;
5480cfab8ddSJoseph Koshy 
5490cfab8ddSJoseph Koshy 	(void) pe;
5500cfab8ddSJoseph Koshy 
5510cfab8ddSJoseph Koshy 	pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE);
5520cfab8ddSJoseph Koshy 	pmc_config->pm_md.pm_iaf.pm_iaf_flags = 0;
5530cfab8ddSJoseph Koshy 
5540cfab8ddSJoseph Koshy 	while ((p = strsep(&ctrspec, ",")) != NULL) {
5550cfab8ddSJoseph Koshy 		if (KWMATCH(p, IAF_KW_OS))
5560cfab8ddSJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_SYSTEM;
5570cfab8ddSJoseph Koshy 		else if (KWMATCH(p, IAF_KW_USR))
5580cfab8ddSJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_USER;
5590cfab8ddSJoseph Koshy 		else if (KWMATCH(p, IAF_KW_ANYTHREAD))
5600cfab8ddSJoseph Koshy 			pmc_config->pm_md.pm_iaf.pm_iaf_flags |= IAF_ANY;
5610cfab8ddSJoseph Koshy 		else
5620cfab8ddSJoseph Koshy 			return (-1);
5630cfab8ddSJoseph Koshy 	}
5640cfab8ddSJoseph Koshy 
5650cfab8ddSJoseph Koshy 	return (0);
5660cfab8ddSJoseph Koshy }
5670cfab8ddSJoseph Koshy 
5680cfab8ddSJoseph Koshy /*
5690cfab8ddSJoseph Koshy  * Core/Core2 support.
5700cfab8ddSJoseph Koshy  */
5710cfab8ddSJoseph Koshy 
5720cfab8ddSJoseph Koshy #define	IAP_KW_AGENT		"agent"
5730cfab8ddSJoseph Koshy #define	IAP_KW_ANYTHREAD	"anythread"
5740cfab8ddSJoseph Koshy #define	IAP_KW_CACHESTATE	"cachestate"
5750cfab8ddSJoseph Koshy #define	IAP_KW_CMASK		"cmask"
5760cfab8ddSJoseph Koshy #define	IAP_KW_CORE		"core"
5770cfab8ddSJoseph Koshy #define	IAP_KW_EDGE		"edge"
5780cfab8ddSJoseph Koshy #define	IAP_KW_INV		"inv"
5790cfab8ddSJoseph Koshy #define	IAP_KW_OS		"os"
5800cfab8ddSJoseph Koshy #define	IAP_KW_PREFETCH		"prefetch"
5810cfab8ddSJoseph Koshy #define	IAP_KW_SNOOPRESPONSE	"snoopresponse"
5820cfab8ddSJoseph Koshy #define	IAP_KW_SNOOPTYPE	"snooptype"
5830cfab8ddSJoseph Koshy #define	IAP_KW_TRANSITION	"trans"
5840cfab8ddSJoseph Koshy #define	IAP_KW_USR		"usr"
5851fa7f10bSFabien Thomas #define	IAP_KW_RSP		"rsp"
5860cfab8ddSJoseph Koshy 
5870cfab8ddSJoseph Koshy static struct pmc_masks iap_core_mask[] = {
5880cfab8ddSJoseph Koshy 	PMCMASK(all,	(0x3 << 14)),
5890cfab8ddSJoseph Koshy 	PMCMASK(this,	(0x1 << 14)),
5900cfab8ddSJoseph Koshy 	NULLMASK
5910cfab8ddSJoseph Koshy };
5920cfab8ddSJoseph Koshy 
5930cfab8ddSJoseph Koshy static struct pmc_masks iap_agent_mask[] = {
5940cfab8ddSJoseph Koshy 	PMCMASK(this,	0),
5950cfab8ddSJoseph Koshy 	PMCMASK(any,	(0x1 << 13)),
5960cfab8ddSJoseph Koshy 	NULLMASK
5970cfab8ddSJoseph Koshy };
5980cfab8ddSJoseph Koshy 
5990cfab8ddSJoseph Koshy static struct pmc_masks iap_prefetch_mask[] = {
6000cfab8ddSJoseph Koshy 	PMCMASK(both,		(0x3 << 12)),
6010cfab8ddSJoseph Koshy 	PMCMASK(only,		(0x1 << 12)),
6020cfab8ddSJoseph Koshy 	PMCMASK(exclude,	0),
6030cfab8ddSJoseph Koshy 	NULLMASK
6040cfab8ddSJoseph Koshy };
6050cfab8ddSJoseph Koshy 
6060cfab8ddSJoseph Koshy static struct pmc_masks iap_cachestate_mask[] = {
6070cfab8ddSJoseph Koshy 	PMCMASK(i,		(1 <<  8)),
6080cfab8ddSJoseph Koshy 	PMCMASK(s,		(1 <<  9)),
6090cfab8ddSJoseph Koshy 	PMCMASK(e,		(1 << 10)),
6100cfab8ddSJoseph Koshy 	PMCMASK(m,		(1 << 11)),
6110cfab8ddSJoseph Koshy 	NULLMASK
6120cfab8ddSJoseph Koshy };
6130cfab8ddSJoseph Koshy 
6140cfab8ddSJoseph Koshy static struct pmc_masks iap_snoopresponse_mask[] = {
6150cfab8ddSJoseph Koshy 	PMCMASK(clean,		(1 << 8)),
6160cfab8ddSJoseph Koshy 	PMCMASK(hit,		(1 << 9)),
6170cfab8ddSJoseph Koshy 	PMCMASK(hitm,		(1 << 11)),
6180cfab8ddSJoseph Koshy 	NULLMASK
6190cfab8ddSJoseph Koshy };
6200cfab8ddSJoseph Koshy 
6210cfab8ddSJoseph Koshy static struct pmc_masks iap_snooptype_mask[] = {
6220cfab8ddSJoseph Koshy 	PMCMASK(cmp2s,		(1 << 8)),
6230cfab8ddSJoseph Koshy 	PMCMASK(cmp2i,		(1 << 9)),
6240cfab8ddSJoseph Koshy 	NULLMASK
6250cfab8ddSJoseph Koshy };
6260cfab8ddSJoseph Koshy 
6270cfab8ddSJoseph Koshy static struct pmc_masks iap_transition_mask[] = {
6280cfab8ddSJoseph Koshy 	PMCMASK(any,		0x00),
6290cfab8ddSJoseph Koshy 	PMCMASK(frequency,	0x10),
6300cfab8ddSJoseph Koshy 	NULLMASK
6310cfab8ddSJoseph Koshy };
6320cfab8ddSJoseph Koshy 
6331fa7f10bSFabien Thomas static struct pmc_masks iap_rsp_mask[] = {
6341fa7f10bSFabien Thomas 	PMCMASK(DMND_DATA_RD,		(1 <<  0)),
6351fa7f10bSFabien Thomas 	PMCMASK(DMND_RFO,		(1 <<  1)),
6361fa7f10bSFabien Thomas 	PMCMASK(DMND_IFETCH,		(1 <<  2)),
6371fa7f10bSFabien Thomas 	PMCMASK(WB,			(1 <<  3)),
6381fa7f10bSFabien Thomas 	PMCMASK(PF_DATA_RD,		(1 <<  4)),
6391fa7f10bSFabien Thomas 	PMCMASK(PF_RFO,			(1 <<  5)),
6401fa7f10bSFabien Thomas 	PMCMASK(PF_IFETCH,		(1 <<  6)),
6411fa7f10bSFabien Thomas 	PMCMASK(OTHER,			(1 <<  7)),
6421fa7f10bSFabien Thomas 	PMCMASK(UNCORE_HIT,		(1 <<  8)),
6431fa7f10bSFabien Thomas 	PMCMASK(OTHER_CORE_HIT_SNP,	(1 <<  9)),
6441fa7f10bSFabien Thomas 	PMCMASK(OTHER_CORE_HITM,	(1 << 10)),
6451fa7f10bSFabien Thomas 	PMCMASK(REMOTE_CACHE_FWD,	(1 << 12)),
6461fa7f10bSFabien Thomas 	PMCMASK(REMOTE_DRAM,		(1 << 13)),
6471fa7f10bSFabien Thomas 	PMCMASK(LOCAL_DRAM,		(1 << 14)),
6481fa7f10bSFabien Thomas 	PMCMASK(NON_DRAM,		(1 << 15)),
6491fa7f10bSFabien Thomas 	NULLMASK
6501fa7f10bSFabien Thomas };
6511fa7f10bSFabien Thomas 
6520cfab8ddSJoseph Koshy static int
6530cfab8ddSJoseph Koshy iap_allocate_pmc(enum pmc_event pe, char *ctrspec,
6540cfab8ddSJoseph Koshy     struct pmc_op_pmcallocate *pmc_config)
6550cfab8ddSJoseph Koshy {
6560cfab8ddSJoseph Koshy 	char *e, *p, *q;
6571fa7f10bSFabien Thomas 	uint32_t cachestate, evmask, rsp;
6580cfab8ddSJoseph Koshy 	int count, n;
6590cfab8ddSJoseph Koshy 
6600cfab8ddSJoseph Koshy 	pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE |
6610cfab8ddSJoseph Koshy 	    PMC_CAP_QUALIFIER);
6620cfab8ddSJoseph Koshy 	pmc_config->pm_md.pm_iap.pm_iap_config = 0;
6630cfab8ddSJoseph Koshy 
6641fa7f10bSFabien Thomas 	cachestate = evmask = rsp = 0;
6650cfab8ddSJoseph Koshy 
6660cfab8ddSJoseph Koshy 	/* Parse additional modifiers if present */
6670cfab8ddSJoseph Koshy 	while ((p = strsep(&ctrspec, ",")) != NULL) {
6680cfab8ddSJoseph Koshy 
6690cfab8ddSJoseph Koshy 		n = 0;
6700cfab8ddSJoseph Koshy 		if (KWPREFIXMATCH(p, IAP_KW_CMASK "=")) {
6710cfab8ddSJoseph Koshy 			q = strchr(p, '=');
6720cfab8ddSJoseph Koshy 			if (*++q == '\0') /* skip '=' */
6730cfab8ddSJoseph Koshy 				return (-1);
6740cfab8ddSJoseph Koshy 			count = strtol(q, &e, 0);
6750cfab8ddSJoseph Koshy 			if (e == q || *e != '\0')
6760cfab8ddSJoseph Koshy 				return (-1);
6770cfab8ddSJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_THRESHOLD;
6780cfab8ddSJoseph Koshy 			pmc_config->pm_md.pm_iap.pm_iap_config |=
6790cfab8ddSJoseph Koshy 			    IAP_CMASK(count);
6800cfab8ddSJoseph Koshy 		} else if (KWMATCH(p, IAP_KW_EDGE)) {
6810cfab8ddSJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_EDGE;
6820cfab8ddSJoseph Koshy 		} else if (KWMATCH(p, IAP_KW_INV)) {
6830cfab8ddSJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_INVERT;
6840cfab8ddSJoseph Koshy 		} else if (KWMATCH(p, IAP_KW_OS)) {
6850cfab8ddSJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_SYSTEM;
6860cfab8ddSJoseph Koshy 		} else if (KWMATCH(p, IAP_KW_USR)) {
6870cfab8ddSJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_USER;
6880cfab8ddSJoseph Koshy 		} else if (KWMATCH(p, IAP_KW_ANYTHREAD)) {
6890cfab8ddSJoseph Koshy 			pmc_config->pm_md.pm_iap.pm_iap_config |= IAP_ANY;
690b47ea38eSJoseph Koshy 		} else if (KWPREFIXMATCH(p, IAP_KW_CORE "=")) {
6910cfab8ddSJoseph Koshy 			n = pmc_parse_mask(iap_core_mask, p, &evmask);
6920cfab8ddSJoseph Koshy 			if (n != 1)
6930cfab8ddSJoseph Koshy 				return (-1);
694b47ea38eSJoseph Koshy 		} else if (KWPREFIXMATCH(p, IAP_KW_AGENT "=")) {
6950cfab8ddSJoseph Koshy 			n = pmc_parse_mask(iap_agent_mask, p, &evmask);
6960cfab8ddSJoseph Koshy 			if (n != 1)
6970cfab8ddSJoseph Koshy 				return (-1);
698b47ea38eSJoseph Koshy 		} else if (KWPREFIXMATCH(p, IAP_KW_PREFETCH "=")) {
6990cfab8ddSJoseph Koshy 			n = pmc_parse_mask(iap_prefetch_mask, p, &evmask);
7000cfab8ddSJoseph Koshy 			if (n != 1)
7010cfab8ddSJoseph Koshy 				return (-1);
702b47ea38eSJoseph Koshy 		} else if (KWPREFIXMATCH(p, IAP_KW_CACHESTATE "=")) {
7030cfab8ddSJoseph Koshy 			n = pmc_parse_mask(iap_cachestate_mask, p, &cachestate);
7040cfab8ddSJoseph Koshy 		} else if (cpu_info.pm_cputype == PMC_CPU_INTEL_CORE &&
705b47ea38eSJoseph Koshy 		    KWPREFIXMATCH(p, IAP_KW_TRANSITION "=")) {
7060cfab8ddSJoseph Koshy 			n = pmc_parse_mask(iap_transition_mask, p, &evmask);
7070cfab8ddSJoseph Koshy 			if (n != 1)
7080cfab8ddSJoseph Koshy 				return (-1);
7090cfab8ddSJoseph Koshy 		} else if (cpu_info.pm_cputype == PMC_CPU_INTEL_ATOM ||
710b4d091f3SJoseph Koshy 		    cpu_info.pm_cputype == PMC_CPU_INTEL_CORE2 ||
7111fa7f10bSFabien Thomas 		    cpu_info.pm_cputype == PMC_CPU_INTEL_CORE2EXTREME) {
712b47ea38eSJoseph Koshy 			if (KWPREFIXMATCH(p, IAP_KW_SNOOPRESPONSE "=")) {
7130cfab8ddSJoseph Koshy 				n = pmc_parse_mask(iap_snoopresponse_mask, p,
7140cfab8ddSJoseph Koshy 				    &evmask);
715b47ea38eSJoseph Koshy 			} else if (KWPREFIXMATCH(p, IAP_KW_SNOOPTYPE "=")) {
7160cfab8ddSJoseph Koshy 				n = pmc_parse_mask(iap_snooptype_mask, p,
7170cfab8ddSJoseph Koshy 				    &evmask);
7180cfab8ddSJoseph Koshy 			} else
7190cfab8ddSJoseph Koshy 				return (-1);
7201fa7f10bSFabien Thomas 		} else if (cpu_info.pm_cputype == PMC_CPU_INTEL_COREI7 ||
7211fa7f10bSFabien Thomas 		    cpu_info.pm_cputype == PMC_CPU_INTEL_WESTMERE) {
7221fa7f10bSFabien Thomas 			if (KWPREFIXMATCH(p, IAP_KW_RSP "=")) {
7231fa7f10bSFabien Thomas 				n = pmc_parse_mask(iap_rsp_mask, p, &rsp);
7241fa7f10bSFabien Thomas 			} else
7251fa7f10bSFabien Thomas 				return (-1);
7260cfab8ddSJoseph Koshy 		} else
7270cfab8ddSJoseph Koshy 			return (-1);
7280cfab8ddSJoseph Koshy 
7290cfab8ddSJoseph Koshy 		if (n < 0)	/* Parsing failed. */
7300cfab8ddSJoseph Koshy 			return (-1);
7310cfab8ddSJoseph Koshy 	}
7320cfab8ddSJoseph Koshy 
7330cfab8ddSJoseph Koshy 	pmc_config->pm_md.pm_iap.pm_iap_config |= evmask;
7340cfab8ddSJoseph Koshy 
7350cfab8ddSJoseph Koshy 	/*
7360cfab8ddSJoseph Koshy 	 * If the event requires a 'cachestate' qualifier but was not
7370cfab8ddSJoseph Koshy 	 * specified by the user, use a sensible default.
7380cfab8ddSJoseph Koshy 	 */
7390cfab8ddSJoseph Koshy 	switch (pe) {
7400cfab8ddSJoseph Koshy 	case PMC_EV_IAP_EVENT_28H: /* Core, Core2, Atom */
7410cfab8ddSJoseph Koshy 	case PMC_EV_IAP_EVENT_29H: /* Core, Core2, Atom */
7420cfab8ddSJoseph Koshy 	case PMC_EV_IAP_EVENT_2AH: /* Core, Core2, Atom */
7430cfab8ddSJoseph Koshy 	case PMC_EV_IAP_EVENT_2BH: /* Atom, Core2 */
7440cfab8ddSJoseph Koshy 	case PMC_EV_IAP_EVENT_2EH: /* Core, Core2, Atom */
7450cfab8ddSJoseph Koshy 	case PMC_EV_IAP_EVENT_30H: /* Core, Core2, Atom */
7460cfab8ddSJoseph Koshy 	case PMC_EV_IAP_EVENT_32H: /* Core */
7470cfab8ddSJoseph Koshy 	case PMC_EV_IAP_EVENT_40H: /* Core */
7480cfab8ddSJoseph Koshy 	case PMC_EV_IAP_EVENT_41H: /* Core */
7490cfab8ddSJoseph Koshy 	case PMC_EV_IAP_EVENT_42H: /* Core, Core2, Atom */
7500cfab8ddSJoseph Koshy 		if (cachestate == 0)
7510cfab8ddSJoseph Koshy 			cachestate = (0xF << 8);
752aa1b887bSRyan Stone 		break;
753aa1b887bSRyan Stone 	case PMC_EV_IAP_EVENT_77H: /* Atom */
754aa1b887bSRyan Stone 		/* IAP_EVENT_77H only accepts a cachestate qualifier on the
755aa1b887bSRyan Stone 		 * Atom processor
756aa1b887bSRyan Stone 		 */
757aa1b887bSRyan Stone 		if(cpu_info.pm_cputype == PMC_CPU_INTEL_ATOM && cachestate == 0)
758aa1b887bSRyan Stone 			cachestate = (0xF << 8);
759aa1b887bSRyan Stone 	    break;
7600cfab8ddSJoseph Koshy 	default:
7610cfab8ddSJoseph Koshy 		break;
7620cfab8ddSJoseph Koshy 	}
7630cfab8ddSJoseph Koshy 
7640cfab8ddSJoseph Koshy 	pmc_config->pm_md.pm_iap.pm_iap_config |= cachestate;
7651fa7f10bSFabien Thomas 	pmc_config->pm_md.pm_iap.pm_iap_rsp = rsp;
7661fa7f10bSFabien Thomas 
7671fa7f10bSFabien Thomas 	return (0);
7681fa7f10bSFabien Thomas }
7691fa7f10bSFabien Thomas 
7701fa7f10bSFabien Thomas /*
7711fa7f10bSFabien Thomas  * Intel Uncore.
7721fa7f10bSFabien Thomas  */
7731fa7f10bSFabien Thomas 
7741fa7f10bSFabien Thomas static int
7751fa7f10bSFabien Thomas ucf_allocate_pmc(enum pmc_event pe, char *ctrspec,
7761fa7f10bSFabien Thomas     struct pmc_op_pmcallocate *pmc_config)
7771fa7f10bSFabien Thomas {
7781fa7f10bSFabien Thomas 	(void) pe;
7791fa7f10bSFabien Thomas 	(void) ctrspec;
7801fa7f10bSFabien Thomas 
7811fa7f10bSFabien Thomas 	pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE);
7821fa7f10bSFabien Thomas 	pmc_config->pm_md.pm_ucf.pm_ucf_flags = 0;
7831fa7f10bSFabien Thomas 
7841fa7f10bSFabien Thomas 	return (0);
7851fa7f10bSFabien Thomas }
7861fa7f10bSFabien Thomas 
7871fa7f10bSFabien Thomas #define	UCP_KW_CMASK		"cmask"
7881fa7f10bSFabien Thomas #define	UCP_KW_EDGE		"edge"
7891fa7f10bSFabien Thomas #define	UCP_KW_INV		"inv"
7901fa7f10bSFabien Thomas 
7911fa7f10bSFabien Thomas static int
7921fa7f10bSFabien Thomas ucp_allocate_pmc(enum pmc_event pe, char *ctrspec,
7931fa7f10bSFabien Thomas     struct pmc_op_pmcallocate *pmc_config)
7941fa7f10bSFabien Thomas {
7951fa7f10bSFabien Thomas 	char *e, *p, *q;
7961fa7f10bSFabien Thomas 	int count, n;
7971fa7f10bSFabien Thomas 
7981fa7f10bSFabien Thomas 	(void) pe;
7991fa7f10bSFabien Thomas 
8001fa7f10bSFabien Thomas 	pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE |
8011fa7f10bSFabien Thomas 	    PMC_CAP_QUALIFIER);
8021fa7f10bSFabien Thomas 	pmc_config->pm_md.pm_ucp.pm_ucp_config = 0;
8031fa7f10bSFabien Thomas 
8041fa7f10bSFabien Thomas 	/* Parse additional modifiers if present */
8051fa7f10bSFabien Thomas 	while ((p = strsep(&ctrspec, ",")) != NULL) {
8061fa7f10bSFabien Thomas 
8071fa7f10bSFabien Thomas 		n = 0;
8081fa7f10bSFabien Thomas 		if (KWPREFIXMATCH(p, UCP_KW_CMASK "=")) {
8091fa7f10bSFabien Thomas 			q = strchr(p, '=');
8101fa7f10bSFabien Thomas 			if (*++q == '\0') /* skip '=' */
8111fa7f10bSFabien Thomas 				return (-1);
8121fa7f10bSFabien Thomas 			count = strtol(q, &e, 0);
8131fa7f10bSFabien Thomas 			if (e == q || *e != '\0')
8141fa7f10bSFabien Thomas 				return (-1);
8151fa7f10bSFabien Thomas 			pmc_config->pm_caps |= PMC_CAP_THRESHOLD;
8161fa7f10bSFabien Thomas 			pmc_config->pm_md.pm_ucp.pm_ucp_config |=
8171fa7f10bSFabien Thomas 			    UCP_CMASK(count);
8181fa7f10bSFabien Thomas 		} else if (KWMATCH(p, UCP_KW_EDGE)) {
8191fa7f10bSFabien Thomas 			pmc_config->pm_caps |= PMC_CAP_EDGE;
8201fa7f10bSFabien Thomas 		} else if (KWMATCH(p, UCP_KW_INV)) {
8211fa7f10bSFabien Thomas 			pmc_config->pm_caps |= PMC_CAP_INVERT;
8221fa7f10bSFabien Thomas 		} else
8231fa7f10bSFabien Thomas 			return (-1);
8241fa7f10bSFabien Thomas 
8251fa7f10bSFabien Thomas 		if (n < 0)	/* Parsing failed. */
8261fa7f10bSFabien Thomas 			return (-1);
8271fa7f10bSFabien Thomas 	}
8280cfab8ddSJoseph Koshy 
8290cfab8ddSJoseph Koshy 	return (0);
8300cfab8ddSJoseph Koshy }
8310cfab8ddSJoseph Koshy 
8320cfab8ddSJoseph Koshy /*
833f263522aSJoseph Koshy  * AMD K8 PMCs.
834f263522aSJoseph Koshy  *
835f263522aSJoseph Koshy  * These are very similar to AMD K7 PMCs, but support more kinds of
836f263522aSJoseph Koshy  * events.
837f263522aSJoseph Koshy  */
838f263522aSJoseph Koshy 
839f263522aSJoseph Koshy static struct pmc_event_alias k8_aliases[] = {
840f263522aSJoseph Koshy 	EV_ALIAS("branches",		"k8-fr-retired-taken-branches"),
841f263522aSJoseph Koshy 	EV_ALIAS("branch-mispredicts",
842f263522aSJoseph Koshy 	    "k8-fr-retired-taken-branches-mispredicted"),
843f263522aSJoseph Koshy 	EV_ALIAS("cycles",		"tsc"),
844f263522aSJoseph Koshy 	EV_ALIAS("dc-misses",		"k8-dc-miss"),
845f263522aSJoseph Koshy 	EV_ALIAS("ic-misses",		"k8-ic-miss"),
846f263522aSJoseph Koshy 	EV_ALIAS("instructions",	"k8-fr-retired-x86-instructions"),
847f263522aSJoseph Koshy 	EV_ALIAS("interrupts",		"k8-fr-taken-hardware-interrupts"),
848177a2f22SJoseph Koshy 	EV_ALIAS("unhalted-cycles",	"k8-bu-cpu-clk-unhalted"),
849f263522aSJoseph Koshy 	EV_ALIAS(NULL, NULL)
850f263522aSJoseph Koshy };
851f263522aSJoseph Koshy 
852f263522aSJoseph Koshy #define	__K8MASK(N,V) PMCMASK(N,(1 << (V)))
853f263522aSJoseph Koshy 
854f263522aSJoseph Koshy /*
855f263522aSJoseph Koshy  * Parsing tables
856f263522aSJoseph Koshy  */
857f263522aSJoseph Koshy 
858f263522aSJoseph Koshy /* fp dispatched fpu ops */
859f263522aSJoseph Koshy static const struct pmc_masks k8_mask_fdfo[] = {
860f263522aSJoseph Koshy 	__K8MASK(add-pipe-excluding-junk-ops,	0),
861f263522aSJoseph Koshy 	__K8MASK(multiply-pipe-excluding-junk-ops,	1),
862f263522aSJoseph Koshy 	__K8MASK(store-pipe-excluding-junk-ops,	2),
863f263522aSJoseph Koshy 	__K8MASK(add-pipe-junk-ops,		3),
864f263522aSJoseph Koshy 	__K8MASK(multiply-pipe-junk-ops,	4),
865f263522aSJoseph Koshy 	__K8MASK(store-pipe-junk-ops,		5),
866f263522aSJoseph Koshy 	NULLMASK
867f263522aSJoseph Koshy };
868f263522aSJoseph Koshy 
869f263522aSJoseph Koshy /* ls segment register loads */
870f263522aSJoseph Koshy static const struct pmc_masks k8_mask_lsrl[] = {
871f263522aSJoseph Koshy 	__K8MASK(es,	0),
872f263522aSJoseph Koshy 	__K8MASK(cs,	1),
873f263522aSJoseph Koshy 	__K8MASK(ss,	2),
874f263522aSJoseph Koshy 	__K8MASK(ds,	3),
875f263522aSJoseph Koshy 	__K8MASK(fs,	4),
876f263522aSJoseph Koshy 	__K8MASK(gs,	5),
877f263522aSJoseph Koshy 	__K8MASK(hs,	6),
878f263522aSJoseph Koshy 	NULLMASK
879f263522aSJoseph Koshy };
880f263522aSJoseph Koshy 
881f263522aSJoseph Koshy /* ls locked operation */
882f263522aSJoseph Koshy static const struct pmc_masks k8_mask_llo[] = {
883f263522aSJoseph Koshy 	__K8MASK(locked-instructions,	0),
884f263522aSJoseph Koshy 	__K8MASK(cycles-in-request,	1),
885f263522aSJoseph Koshy 	__K8MASK(cycles-to-complete,	2),
886f263522aSJoseph Koshy 	NULLMASK
887f263522aSJoseph Koshy };
888f263522aSJoseph Koshy 
889f263522aSJoseph Koshy /* dc refill from {l2,system} and dc copyback */
890f263522aSJoseph Koshy static const struct pmc_masks k8_mask_dc[] = {
891f263522aSJoseph Koshy 	__K8MASK(invalid,	0),
892f263522aSJoseph Koshy 	__K8MASK(shared,	1),
893f263522aSJoseph Koshy 	__K8MASK(exclusive,	2),
894f263522aSJoseph Koshy 	__K8MASK(owner,		3),
895f263522aSJoseph Koshy 	__K8MASK(modified,	4),
896f263522aSJoseph Koshy 	NULLMASK
897f263522aSJoseph Koshy };
898f263522aSJoseph Koshy 
899f263522aSJoseph Koshy /* dc one bit ecc error */
900f263522aSJoseph Koshy static const struct pmc_masks k8_mask_dobee[] = {
901f263522aSJoseph Koshy 	__K8MASK(scrubber,	0),
902f263522aSJoseph Koshy 	__K8MASK(piggyback,	1),
903f263522aSJoseph Koshy 	NULLMASK
904f263522aSJoseph Koshy };
905f263522aSJoseph Koshy 
906f263522aSJoseph Koshy /* dc dispatched prefetch instructions */
907f263522aSJoseph Koshy static const struct pmc_masks k8_mask_ddpi[] = {
908f263522aSJoseph Koshy 	__K8MASK(load,	0),
909f263522aSJoseph Koshy 	__K8MASK(store,	1),
910f263522aSJoseph Koshy 	__K8MASK(nta,	2),
911f263522aSJoseph Koshy 	NULLMASK
912f263522aSJoseph Koshy };
913f263522aSJoseph Koshy 
914f263522aSJoseph Koshy /* dc dcache accesses by locks */
915f263522aSJoseph Koshy static const struct pmc_masks k8_mask_dabl[] = {
916f263522aSJoseph Koshy 	__K8MASK(accesses,	0),
917f263522aSJoseph Koshy 	__K8MASK(misses,	1),
918f263522aSJoseph Koshy 	NULLMASK
919f263522aSJoseph Koshy };
920f263522aSJoseph Koshy 
921f263522aSJoseph Koshy /* bu internal l2 request */
922f263522aSJoseph Koshy static const struct pmc_masks k8_mask_bilr[] = {
923f263522aSJoseph Koshy 	__K8MASK(ic-fill,	0),
924f263522aSJoseph Koshy 	__K8MASK(dc-fill,	1),
925f263522aSJoseph Koshy 	__K8MASK(tlb-reload,	2),
926f263522aSJoseph Koshy 	__K8MASK(tag-snoop,	3),
927f263522aSJoseph Koshy 	__K8MASK(cancelled,	4),
928f263522aSJoseph Koshy 	NULLMASK
929f263522aSJoseph Koshy };
930f263522aSJoseph Koshy 
931f263522aSJoseph Koshy /* bu fill request l2 miss */
932f263522aSJoseph Koshy static const struct pmc_masks k8_mask_bfrlm[] = {
933f263522aSJoseph Koshy 	__K8MASK(ic-fill,	0),
934f263522aSJoseph Koshy 	__K8MASK(dc-fill,	1),
935f263522aSJoseph Koshy 	__K8MASK(tlb-reload,	2),
936f263522aSJoseph Koshy 	NULLMASK
937f263522aSJoseph Koshy };
938f263522aSJoseph Koshy 
939f263522aSJoseph Koshy /* bu fill into l2 */
940f263522aSJoseph Koshy static const struct pmc_masks k8_mask_bfil[] = {
941f263522aSJoseph Koshy 	__K8MASK(dirty-l2-victim,	0),
942f263522aSJoseph Koshy 	__K8MASK(victim-from-l2,	1),
943f263522aSJoseph Koshy 	NULLMASK
944f263522aSJoseph Koshy };
945f263522aSJoseph Koshy 
946f263522aSJoseph Koshy /* fr retired fpu instructions */
947f263522aSJoseph Koshy static const struct pmc_masks k8_mask_frfi[] = {
948f263522aSJoseph Koshy 	__K8MASK(x87,			0),
949f263522aSJoseph Koshy 	__K8MASK(mmx-3dnow,		1),
950f263522aSJoseph Koshy 	__K8MASK(packed-sse-sse2,	2),
951f263522aSJoseph Koshy 	__K8MASK(scalar-sse-sse2,	3),
952f263522aSJoseph Koshy 	NULLMASK
953f263522aSJoseph Koshy };
954f263522aSJoseph Koshy 
955f263522aSJoseph Koshy /* fr retired fastpath double op instructions */
956f263522aSJoseph Koshy static const struct pmc_masks k8_mask_frfdoi[] = {
957f263522aSJoseph Koshy 	__K8MASK(low-op-pos-0,		0),
958f263522aSJoseph Koshy 	__K8MASK(low-op-pos-1,		1),
959f263522aSJoseph Koshy 	__K8MASK(low-op-pos-2,		2),
960f263522aSJoseph Koshy 	NULLMASK
961f263522aSJoseph Koshy };
962f263522aSJoseph Koshy 
963f263522aSJoseph Koshy /* fr fpu exceptions */
964f263522aSJoseph Koshy static const struct pmc_masks k8_mask_ffe[] = {
965f263522aSJoseph Koshy 	__K8MASK(x87-reclass-microfaults,	0),
966f263522aSJoseph Koshy 	__K8MASK(sse-retype-microfaults,	1),
967f263522aSJoseph Koshy 	__K8MASK(sse-reclass-microfaults,	2),
968f263522aSJoseph Koshy 	__K8MASK(sse-and-x87-microtraps,	3),
969f263522aSJoseph Koshy 	NULLMASK
970f263522aSJoseph Koshy };
971f263522aSJoseph Koshy 
972f263522aSJoseph Koshy /* nb memory controller page access event */
973f263522aSJoseph Koshy static const struct pmc_masks k8_mask_nmcpae[] = {
974f263522aSJoseph Koshy 	__K8MASK(page-hit,	0),
975f263522aSJoseph Koshy 	__K8MASK(page-miss,	1),
976f263522aSJoseph Koshy 	__K8MASK(page-conflict,	2),
977f263522aSJoseph Koshy 	NULLMASK
978f263522aSJoseph Koshy };
979f263522aSJoseph Koshy 
980f263522aSJoseph Koshy /* nb memory controller turnaround */
981f263522aSJoseph Koshy static const struct pmc_masks k8_mask_nmct[] = {
982f263522aSJoseph Koshy 	__K8MASK(dimm-turnaround,		0),
983f263522aSJoseph Koshy 	__K8MASK(read-to-write-turnaround,	1),
984f263522aSJoseph Koshy 	__K8MASK(write-to-read-turnaround,	2),
985f263522aSJoseph Koshy 	NULLMASK
986f263522aSJoseph Koshy };
987f263522aSJoseph Koshy 
988f263522aSJoseph Koshy /* nb memory controller bypass saturation */
989f263522aSJoseph Koshy static const struct pmc_masks k8_mask_nmcbs[] = {
990f263522aSJoseph Koshy 	__K8MASK(memory-controller-hi-pri-bypass,	0),
991f263522aSJoseph Koshy 	__K8MASK(memory-controller-lo-pri-bypass,	1),
992f263522aSJoseph Koshy 	__K8MASK(dram-controller-interface-bypass,	2),
993f263522aSJoseph Koshy 	__K8MASK(dram-controller-queue-bypass,		3),
994f263522aSJoseph Koshy 	NULLMASK
995f263522aSJoseph Koshy };
996f263522aSJoseph Koshy 
997f263522aSJoseph Koshy /* nb sized commands */
998f263522aSJoseph Koshy static const struct pmc_masks k8_mask_nsc[] = {
999f263522aSJoseph Koshy 	__K8MASK(nonpostwrszbyte,	0),
1000f263522aSJoseph Koshy 	__K8MASK(nonpostwrszdword,	1),
1001f263522aSJoseph Koshy 	__K8MASK(postwrszbyte,		2),
1002f263522aSJoseph Koshy 	__K8MASK(postwrszdword,		3),
1003f263522aSJoseph Koshy 	__K8MASK(rdszbyte,		4),
1004f263522aSJoseph Koshy 	__K8MASK(rdszdword,		5),
1005f263522aSJoseph Koshy 	__K8MASK(rdmodwr,		6),
1006f263522aSJoseph Koshy 	NULLMASK
1007f263522aSJoseph Koshy };
1008f263522aSJoseph Koshy 
1009f263522aSJoseph Koshy /* nb probe result */
1010f263522aSJoseph Koshy static const struct pmc_masks k8_mask_npr[] = {
1011f263522aSJoseph Koshy 	__K8MASK(probe-miss,		0),
1012f263522aSJoseph Koshy 	__K8MASK(probe-hit,		1),
1013f263522aSJoseph Koshy 	__K8MASK(probe-hit-dirty-no-memory-cancel, 2),
1014f263522aSJoseph Koshy 	__K8MASK(probe-hit-dirty-with-memory-cancel, 3),
1015f263522aSJoseph Koshy 	NULLMASK
1016f263522aSJoseph Koshy };
1017f263522aSJoseph Koshy 
1018f263522aSJoseph Koshy /* nb hypertransport bus bandwidth */
1019f263522aSJoseph Koshy static const struct pmc_masks k8_mask_nhbb[] = { /* HT bus bandwidth */
1020f263522aSJoseph Koshy 	__K8MASK(command,	0),
1021f263522aSJoseph Koshy 	__K8MASK(data,	1),
1022f263522aSJoseph Koshy 	__K8MASK(buffer-release, 2),
1023f263522aSJoseph Koshy 	__K8MASK(nop,	3),
1024f263522aSJoseph Koshy 	NULLMASK
1025f263522aSJoseph Koshy };
1026f263522aSJoseph Koshy 
1027f263522aSJoseph Koshy #undef	__K8MASK
1028f263522aSJoseph Koshy 
1029f263522aSJoseph Koshy #define	K8_KW_COUNT	"count"
1030f263522aSJoseph Koshy #define	K8_KW_EDGE	"edge"
1031f263522aSJoseph Koshy #define	K8_KW_INV	"inv"
1032f263522aSJoseph Koshy #define	K8_KW_MASK	"mask"
1033f263522aSJoseph Koshy #define	K8_KW_OS	"os"
1034f263522aSJoseph Koshy #define	K8_KW_USR	"usr"
1035f263522aSJoseph Koshy 
1036f263522aSJoseph Koshy static int
1037f263522aSJoseph Koshy k8_allocate_pmc(enum pmc_event pe, char *ctrspec,
1038f263522aSJoseph Koshy     struct pmc_op_pmcallocate *pmc_config)
1039f263522aSJoseph Koshy {
1040f263522aSJoseph Koshy 	char		*e, *p, *q;
1041f263522aSJoseph Koshy 	int		n;
1042f263522aSJoseph Koshy 	uint32_t	count, evmask;
1043f263522aSJoseph Koshy 	const struct pmc_masks	*pm, *pmask;
1044f263522aSJoseph Koshy 
1045789140c0SJoseph Koshy 	pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE);
1046f263522aSJoseph Koshy 	pmc_config->pm_md.pm_amd.pm_amd_config = 0;
1047f263522aSJoseph Koshy 
1048f263522aSJoseph Koshy 	pmask = NULL;
1049f263522aSJoseph Koshy 	evmask = 0;
1050f263522aSJoseph Koshy 
1051f263522aSJoseph Koshy #define	__K8SETMASK(M) pmask = k8_mask_##M
1052f263522aSJoseph Koshy 
1053f263522aSJoseph Koshy 	/* setup parsing tables */
1054f263522aSJoseph Koshy 	switch (pe) {
1055f263522aSJoseph Koshy 	case PMC_EV_K8_FP_DISPATCHED_FPU_OPS:
1056f263522aSJoseph Koshy 		__K8SETMASK(fdfo);
1057f263522aSJoseph Koshy 		break;
1058f263522aSJoseph Koshy 	case PMC_EV_K8_LS_SEGMENT_REGISTER_LOAD:
1059f263522aSJoseph Koshy 		__K8SETMASK(lsrl);
1060f263522aSJoseph Koshy 		break;
1061f263522aSJoseph Koshy 	case PMC_EV_K8_LS_LOCKED_OPERATION:
1062f263522aSJoseph Koshy 		__K8SETMASK(llo);
1063f263522aSJoseph Koshy 		break;
1064f263522aSJoseph Koshy 	case PMC_EV_K8_DC_REFILL_FROM_L2:
1065f263522aSJoseph Koshy 	case PMC_EV_K8_DC_REFILL_FROM_SYSTEM:
1066f263522aSJoseph Koshy 	case PMC_EV_K8_DC_COPYBACK:
1067f263522aSJoseph Koshy 		__K8SETMASK(dc);
1068f263522aSJoseph Koshy 		break;
1069f263522aSJoseph Koshy 	case PMC_EV_K8_DC_ONE_BIT_ECC_ERROR:
1070f263522aSJoseph Koshy 		__K8SETMASK(dobee);
1071f263522aSJoseph Koshy 		break;
1072f263522aSJoseph Koshy 	case PMC_EV_K8_DC_DISPATCHED_PREFETCH_INSTRUCTIONS:
1073f263522aSJoseph Koshy 		__K8SETMASK(ddpi);
1074f263522aSJoseph Koshy 		break;
1075f263522aSJoseph Koshy 	case PMC_EV_K8_DC_DCACHE_ACCESSES_BY_LOCKS:
1076f263522aSJoseph Koshy 		__K8SETMASK(dabl);
1077f263522aSJoseph Koshy 		break;
1078f263522aSJoseph Koshy 	case PMC_EV_K8_BU_INTERNAL_L2_REQUEST:
1079f263522aSJoseph Koshy 		__K8SETMASK(bilr);
1080f263522aSJoseph Koshy 		break;
1081f263522aSJoseph Koshy 	case PMC_EV_K8_BU_FILL_REQUEST_L2_MISS:
1082f263522aSJoseph Koshy 		__K8SETMASK(bfrlm);
1083f263522aSJoseph Koshy 		break;
1084f263522aSJoseph Koshy 	case PMC_EV_K8_BU_FILL_INTO_L2:
1085f263522aSJoseph Koshy 		__K8SETMASK(bfil);
1086f263522aSJoseph Koshy 		break;
1087f263522aSJoseph Koshy 	case PMC_EV_K8_FR_RETIRED_FPU_INSTRUCTIONS:
1088f263522aSJoseph Koshy 		__K8SETMASK(frfi);
1089f263522aSJoseph Koshy 		break;
1090f263522aSJoseph Koshy 	case PMC_EV_K8_FR_RETIRED_FASTPATH_DOUBLE_OP_INSTRUCTIONS:
1091f263522aSJoseph Koshy 		__K8SETMASK(frfdoi);
1092f263522aSJoseph Koshy 		break;
1093f263522aSJoseph Koshy 	case PMC_EV_K8_FR_FPU_EXCEPTIONS:
1094f263522aSJoseph Koshy 		__K8SETMASK(ffe);
1095f263522aSJoseph Koshy 		break;
1096f263522aSJoseph Koshy 	case PMC_EV_K8_NB_MEMORY_CONTROLLER_PAGE_ACCESS_EVENT:
1097f263522aSJoseph Koshy 		__K8SETMASK(nmcpae);
1098f263522aSJoseph Koshy 		break;
1099f263522aSJoseph Koshy 	case PMC_EV_K8_NB_MEMORY_CONTROLLER_TURNAROUND:
1100f263522aSJoseph Koshy 		__K8SETMASK(nmct);
1101f263522aSJoseph Koshy 		break;
1102f263522aSJoseph Koshy 	case PMC_EV_K8_NB_MEMORY_CONTROLLER_BYPASS_SATURATION:
1103f263522aSJoseph Koshy 		__K8SETMASK(nmcbs);
1104f263522aSJoseph Koshy 		break;
1105f263522aSJoseph Koshy 	case PMC_EV_K8_NB_SIZED_COMMANDS:
1106f263522aSJoseph Koshy 		__K8SETMASK(nsc);
1107f263522aSJoseph Koshy 		break;
1108f263522aSJoseph Koshy 	case PMC_EV_K8_NB_PROBE_RESULT:
1109f263522aSJoseph Koshy 		__K8SETMASK(npr);
1110f263522aSJoseph Koshy 		break;
1111f263522aSJoseph Koshy 	case PMC_EV_K8_NB_HT_BUS0_BANDWIDTH:
1112f263522aSJoseph Koshy 	case PMC_EV_K8_NB_HT_BUS1_BANDWIDTH:
1113f263522aSJoseph Koshy 	case PMC_EV_K8_NB_HT_BUS2_BANDWIDTH:
1114f263522aSJoseph Koshy 		__K8SETMASK(nhbb);
1115f263522aSJoseph Koshy 		break;
1116f263522aSJoseph Koshy 
1117f263522aSJoseph Koshy 	default:
1118f263522aSJoseph Koshy 		break;		/* no options defined */
1119f263522aSJoseph Koshy 	}
1120f263522aSJoseph Koshy 
1121f263522aSJoseph Koshy 	while ((p = strsep(&ctrspec, ",")) != NULL) {
1122f263522aSJoseph Koshy 		if (KWPREFIXMATCH(p, K8_KW_COUNT "=")) {
1123f263522aSJoseph Koshy 			q = strchr(p, '=');
1124f263522aSJoseph Koshy 			if (*++q == '\0') /* skip '=' */
1125aa342b1fSJoseph Koshy 				return (-1);
1126f263522aSJoseph Koshy 
1127f263522aSJoseph Koshy 			count = strtol(q, &e, 0);
1128f263522aSJoseph Koshy 			if (e == q || *e != '\0')
1129aa342b1fSJoseph Koshy 				return (-1);
1130f263522aSJoseph Koshy 
1131f263522aSJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_THRESHOLD;
1132f263522aSJoseph Koshy 			pmc_config->pm_md.pm_amd.pm_amd_config |=
1133f263522aSJoseph Koshy 			    AMD_PMC_TO_COUNTER(count);
1134f263522aSJoseph Koshy 
1135f263522aSJoseph Koshy 		} else if (KWMATCH(p, K8_KW_EDGE)) {
1136f263522aSJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_EDGE;
1137f263522aSJoseph Koshy 		} else if (KWMATCH(p, K8_KW_INV)) {
1138f263522aSJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_INVERT;
1139f263522aSJoseph Koshy 		} else if (KWPREFIXMATCH(p, K8_KW_MASK "=")) {
1140f263522aSJoseph Koshy 			if ((n = pmc_parse_mask(pmask, p, &evmask)) < 0)
1141aa342b1fSJoseph Koshy 				return (-1);
1142f263522aSJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_QUALIFIER;
1143f263522aSJoseph Koshy 		} else if (KWMATCH(p, K8_KW_OS)) {
1144f263522aSJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_SYSTEM;
1145f263522aSJoseph Koshy 		} else if (KWMATCH(p, K8_KW_USR)) {
1146f263522aSJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_USER;
1147f263522aSJoseph Koshy 		} else
1148aa342b1fSJoseph Koshy 			return (-1);
1149f263522aSJoseph Koshy 	}
1150f263522aSJoseph Koshy 
1151f263522aSJoseph Koshy 	/* other post processing */
1152f263522aSJoseph Koshy 	switch (pe) {
1153f263522aSJoseph Koshy 	case PMC_EV_K8_FP_DISPATCHED_FPU_OPS:
1154f263522aSJoseph Koshy 	case PMC_EV_K8_FP_CYCLES_WITH_NO_FPU_OPS_RETIRED:
1155f263522aSJoseph Koshy 	case PMC_EV_K8_FP_DISPATCHED_FPU_FAST_FLAG_OPS:
1156f263522aSJoseph Koshy 	case PMC_EV_K8_FR_RETIRED_FASTPATH_DOUBLE_OP_INSTRUCTIONS:
1157f263522aSJoseph Koshy 	case PMC_EV_K8_FR_RETIRED_FPU_INSTRUCTIONS:
1158f263522aSJoseph Koshy 	case PMC_EV_K8_FR_FPU_EXCEPTIONS:
1159f263522aSJoseph Koshy 		/* XXX only available in rev B and later */
1160f263522aSJoseph Koshy 		break;
1161f263522aSJoseph Koshy 	case PMC_EV_K8_DC_DCACHE_ACCESSES_BY_LOCKS:
1162f263522aSJoseph Koshy 		/* XXX only available in rev C and later */
1163f263522aSJoseph Koshy 		break;
1164f263522aSJoseph Koshy 	case PMC_EV_K8_LS_LOCKED_OPERATION:
1165f263522aSJoseph Koshy 		/* XXX CPU Rev A,B evmask is to be zero */
1166f263522aSJoseph Koshy 		if (evmask & (evmask - 1)) /* > 1 bit set */
1167aa342b1fSJoseph Koshy 			return (-1);
1168f263522aSJoseph Koshy 		if (evmask == 0) {
1169f263522aSJoseph Koshy 			evmask = 0x01; /* Rev C and later: #instrs */
1170f263522aSJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_QUALIFIER;
1171f263522aSJoseph Koshy 		}
1172f263522aSJoseph Koshy 		break;
1173f263522aSJoseph Koshy 	default:
1174f263522aSJoseph Koshy 		if (evmask == 0 && pmask != NULL) {
1175f263522aSJoseph Koshy 			for (pm = pmask; pm->pm_name; pm++)
1176f263522aSJoseph Koshy 				evmask |= pm->pm_value;
1177f263522aSJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_QUALIFIER;
1178f263522aSJoseph Koshy 		}
1179f263522aSJoseph Koshy 	}
1180f263522aSJoseph Koshy 
1181f263522aSJoseph Koshy 	if (pmc_config->pm_caps & PMC_CAP_QUALIFIER)
1182f263522aSJoseph Koshy 		pmc_config->pm_md.pm_amd.pm_amd_config =
1183f263522aSJoseph Koshy 		    AMD_PMC_TO_UNITMASK(evmask);
1184f263522aSJoseph Koshy 
1185aa342b1fSJoseph Koshy 	return (0);
1186f263522aSJoseph Koshy }
1187f263522aSJoseph Koshy 
1188f263522aSJoseph Koshy #endif
1189f263522aSJoseph Koshy 
119086a65549SJoseph Koshy #if defined(__amd64__) || defined(__i386__)
1191f263522aSJoseph Koshy 
1192ebccf1e3SJoseph Koshy /*
1193ebccf1e3SJoseph Koshy  * Intel P4 PMCs
1194ebccf1e3SJoseph Koshy  */
1195ebccf1e3SJoseph Koshy 
1196ebccf1e3SJoseph Koshy static struct pmc_event_alias p4_aliases[] = {
1197d56c5d4bSJoseph Koshy 	EV_ALIAS("branches",		"p4-branch-retired,mask=mmtp+mmtm"),
1198d56c5d4bSJoseph Koshy 	EV_ALIAS("branch-mispredicts",	"p4-mispred-branch-retired"),
1199ebccf1e3SJoseph Koshy 	EV_ALIAS("cycles",		"tsc"),
1200d56c5d4bSJoseph Koshy 	EV_ALIAS("instructions",
1201d56c5d4bSJoseph Koshy 	    "p4-instr-retired,mask=nbogusntag+nbogustag"),
1202177a2f22SJoseph Koshy 	EV_ALIAS("unhalted-cycles",	"p4-global-power-events"),
1203ebccf1e3SJoseph Koshy 	EV_ALIAS(NULL, NULL)
1204ebccf1e3SJoseph Koshy };
1205ebccf1e3SJoseph Koshy 
1206ebccf1e3SJoseph Koshy #define	P4_KW_ACTIVE	"active"
1207ebccf1e3SJoseph Koshy #define	P4_KW_ACTIVE_ANY "any"
1208ebccf1e3SJoseph Koshy #define	P4_KW_ACTIVE_BOTH "both"
1209ebccf1e3SJoseph Koshy #define	P4_KW_ACTIVE_NONE "none"
1210ebccf1e3SJoseph Koshy #define	P4_KW_ACTIVE_SINGLE "single"
1211ebccf1e3SJoseph Koshy #define	P4_KW_BUSREQTYPE "busreqtype"
1212ebccf1e3SJoseph Koshy #define	P4_KW_CASCADE	"cascade"
1213ebccf1e3SJoseph Koshy #define	P4_KW_EDGE	"edge"
1214ebccf1e3SJoseph Koshy #define	P4_KW_INV	"complement"
1215ebccf1e3SJoseph Koshy #define	P4_KW_OS	"os"
1216ebccf1e3SJoseph Koshy #define	P4_KW_MASK	"mask"
1217ebccf1e3SJoseph Koshy #define	P4_KW_PRECISE	"precise"
1218ebccf1e3SJoseph Koshy #define	P4_KW_TAG	"tag"
1219ebccf1e3SJoseph Koshy #define	P4_KW_THRESHOLD	"threshold"
1220ebccf1e3SJoseph Koshy #define	P4_KW_USR	"usr"
1221ebccf1e3SJoseph Koshy 
1222ebccf1e3SJoseph Koshy #define	__P4MASK(N,V) PMCMASK(N, (1 << (V)))
1223ebccf1e3SJoseph Koshy 
1224ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_tcdm[] = { /* tc deliver mode */
1225ebccf1e3SJoseph Koshy 	__P4MASK(dd, 0),
1226ebccf1e3SJoseph Koshy 	__P4MASK(db, 1),
1227ebccf1e3SJoseph Koshy 	__P4MASK(di, 2),
1228ebccf1e3SJoseph Koshy 	__P4MASK(bd, 3),
1229ebccf1e3SJoseph Koshy 	__P4MASK(bb, 4),
1230ebccf1e3SJoseph Koshy 	__P4MASK(bi, 5),
1231ebccf1e3SJoseph Koshy 	__P4MASK(id, 6),
1232ebccf1e3SJoseph Koshy 	__P4MASK(ib, 7),
1233ebccf1e3SJoseph Koshy 	NULLMASK
1234ebccf1e3SJoseph Koshy };
1235ebccf1e3SJoseph Koshy 
1236ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_bfr[] = { /* bpu fetch request */
1237ebccf1e3SJoseph Koshy 	__P4MASK(tcmiss, 0),
1238ebccf1e3SJoseph Koshy 	NULLMASK,
1239ebccf1e3SJoseph Koshy };
1240ebccf1e3SJoseph Koshy 
1241ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_ir[] = { /* itlb reference */
1242ebccf1e3SJoseph Koshy 	__P4MASK(hit, 0),
1243ebccf1e3SJoseph Koshy 	__P4MASK(miss, 1),
1244ebccf1e3SJoseph Koshy 	__P4MASK(hit-uc, 2),
1245ebccf1e3SJoseph Koshy 	NULLMASK
1246ebccf1e3SJoseph Koshy };
1247ebccf1e3SJoseph Koshy 
1248ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_memcan[] = { /* memory cancel */
1249ebccf1e3SJoseph Koshy 	__P4MASK(st-rb-full, 2),
1250ebccf1e3SJoseph Koshy 	__P4MASK(64k-conf, 3),
1251ebccf1e3SJoseph Koshy 	NULLMASK
1252ebccf1e3SJoseph Koshy };
1253ebccf1e3SJoseph Koshy 
1254ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_memcomp[] = { /* memory complete */
1255ebccf1e3SJoseph Koshy 	__P4MASK(lsc, 0),
1256ebccf1e3SJoseph Koshy 	__P4MASK(ssc, 1),
1257ebccf1e3SJoseph Koshy 	NULLMASK
1258ebccf1e3SJoseph Koshy };
1259ebccf1e3SJoseph Koshy 
1260ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_lpr[] = { /* load port replay */
1261ebccf1e3SJoseph Koshy 	__P4MASK(split-ld, 1),
1262ebccf1e3SJoseph Koshy 	NULLMASK
1263ebccf1e3SJoseph Koshy };
1264ebccf1e3SJoseph Koshy 
1265ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_spr[] = { /* store port replay */
1266ebccf1e3SJoseph Koshy 	__P4MASK(split-st, 1),
1267ebccf1e3SJoseph Koshy 	NULLMASK
1268ebccf1e3SJoseph Koshy };
1269ebccf1e3SJoseph Koshy 
1270ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_mlr[] = { /* mob load replay */
1271ebccf1e3SJoseph Koshy 	__P4MASK(no-sta, 1),
1272ebccf1e3SJoseph Koshy 	__P4MASK(no-std, 3),
1273ebccf1e3SJoseph Koshy 	__P4MASK(partial-data, 4),
1274ebccf1e3SJoseph Koshy 	__P4MASK(unalgn-addr, 5),
1275ebccf1e3SJoseph Koshy 	NULLMASK
1276ebccf1e3SJoseph Koshy };
1277ebccf1e3SJoseph Koshy 
1278ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_pwt[] = { /* page walk type */
1279ebccf1e3SJoseph Koshy 	__P4MASK(dtmiss, 0),
1280ebccf1e3SJoseph Koshy 	__P4MASK(itmiss, 1),
1281ebccf1e3SJoseph Koshy 	NULLMASK
1282ebccf1e3SJoseph Koshy };
1283ebccf1e3SJoseph Koshy 
1284ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_bcr[] = { /* bsq cache reference */
1285ebccf1e3SJoseph Koshy 	__P4MASK(rd-2ndl-hits, 0),
1286ebccf1e3SJoseph Koshy 	__P4MASK(rd-2ndl-hite, 1),
1287ebccf1e3SJoseph Koshy 	__P4MASK(rd-2ndl-hitm, 2),
1288ebccf1e3SJoseph Koshy 	__P4MASK(rd-3rdl-hits, 3),
1289ebccf1e3SJoseph Koshy 	__P4MASK(rd-3rdl-hite, 4),
1290ebccf1e3SJoseph Koshy 	__P4MASK(rd-3rdl-hitm, 5),
1291ebccf1e3SJoseph Koshy 	__P4MASK(rd-2ndl-miss, 8),
1292ebccf1e3SJoseph Koshy 	__P4MASK(rd-3rdl-miss, 9),
1293ebccf1e3SJoseph Koshy 	__P4MASK(wr-2ndl-miss, 10),
1294ebccf1e3SJoseph Koshy 	NULLMASK
1295ebccf1e3SJoseph Koshy };
1296ebccf1e3SJoseph Koshy 
1297ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_ia[] = { /* ioq allocation */
1298ebccf1e3SJoseph Koshy 	__P4MASK(all-read, 5),
1299ebccf1e3SJoseph Koshy 	__P4MASK(all-write, 6),
1300ebccf1e3SJoseph Koshy 	__P4MASK(mem-uc, 7),
1301ebccf1e3SJoseph Koshy 	__P4MASK(mem-wc, 8),
1302ebccf1e3SJoseph Koshy 	__P4MASK(mem-wt, 9),
1303ebccf1e3SJoseph Koshy 	__P4MASK(mem-wp, 10),
1304ebccf1e3SJoseph Koshy 	__P4MASK(mem-wb, 11),
1305ebccf1e3SJoseph Koshy 	__P4MASK(own, 13),
1306ebccf1e3SJoseph Koshy 	__P4MASK(other, 14),
1307ebccf1e3SJoseph Koshy 	__P4MASK(prefetch, 15),
1308ebccf1e3SJoseph Koshy 	NULLMASK
1309ebccf1e3SJoseph Koshy };
1310ebccf1e3SJoseph Koshy 
1311ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_iae[] = { /* ioq active entries */
1312ebccf1e3SJoseph Koshy 	__P4MASK(all-read, 5),
1313ebccf1e3SJoseph Koshy 	__P4MASK(all-write, 6),
1314ebccf1e3SJoseph Koshy 	__P4MASK(mem-uc, 7),
1315ebccf1e3SJoseph Koshy 	__P4MASK(mem-wc, 8),
1316ebccf1e3SJoseph Koshy 	__P4MASK(mem-wt, 9),
1317ebccf1e3SJoseph Koshy 	__P4MASK(mem-wp, 10),
1318ebccf1e3SJoseph Koshy 	__P4MASK(mem-wb, 11),
1319ebccf1e3SJoseph Koshy 	__P4MASK(own, 13),
1320ebccf1e3SJoseph Koshy 	__P4MASK(other, 14),
1321ebccf1e3SJoseph Koshy 	__P4MASK(prefetch, 15),
1322ebccf1e3SJoseph Koshy 	NULLMASK
1323ebccf1e3SJoseph Koshy };
1324ebccf1e3SJoseph Koshy 
1325ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_fda[] = { /* fsb data activity */
1326ebccf1e3SJoseph Koshy 	__P4MASK(drdy-drv, 0),
1327ebccf1e3SJoseph Koshy 	__P4MASK(drdy-own, 1),
1328ebccf1e3SJoseph Koshy 	__P4MASK(drdy-other, 2),
1329ebccf1e3SJoseph Koshy 	__P4MASK(dbsy-drv, 3),
1330ebccf1e3SJoseph Koshy 	__P4MASK(dbsy-own, 4),
1331ebccf1e3SJoseph Koshy 	__P4MASK(dbsy-other, 5),
1332ebccf1e3SJoseph Koshy 	NULLMASK
1333ebccf1e3SJoseph Koshy };
1334ebccf1e3SJoseph Koshy 
1335ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_ba[] = { /* bsq allocation */
1336ebccf1e3SJoseph Koshy 	__P4MASK(req-type0, 0),
1337ebccf1e3SJoseph Koshy 	__P4MASK(req-type1, 1),
1338ebccf1e3SJoseph Koshy 	__P4MASK(req-len0, 2),
1339ebccf1e3SJoseph Koshy 	__P4MASK(req-len1, 3),
1340ebccf1e3SJoseph Koshy 	__P4MASK(req-io-type, 5),
1341ebccf1e3SJoseph Koshy 	__P4MASK(req-lock-type, 6),
1342ebccf1e3SJoseph Koshy 	__P4MASK(req-cache-type, 7),
1343ebccf1e3SJoseph Koshy 	__P4MASK(req-split-type, 8),
1344ebccf1e3SJoseph Koshy 	__P4MASK(req-dem-type, 9),
1345ebccf1e3SJoseph Koshy 	__P4MASK(req-ord-type, 10),
1346ebccf1e3SJoseph Koshy 	__P4MASK(mem-type0, 11),
1347ebccf1e3SJoseph Koshy 	__P4MASK(mem-type1, 12),
1348ebccf1e3SJoseph Koshy 	__P4MASK(mem-type2, 13),
1349ebccf1e3SJoseph Koshy 	NULLMASK
1350ebccf1e3SJoseph Koshy };
1351ebccf1e3SJoseph Koshy 
1352ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_sia[] = { /* sse input assist */
1353ebccf1e3SJoseph Koshy 	__P4MASK(all, 15),
1354ebccf1e3SJoseph Koshy 	NULLMASK
1355ebccf1e3SJoseph Koshy };
1356ebccf1e3SJoseph Koshy 
1357ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_psu[] = { /* packed sp uop */
1358ebccf1e3SJoseph Koshy 	__P4MASK(all, 15),
1359ebccf1e3SJoseph Koshy 	NULLMASK
1360ebccf1e3SJoseph Koshy };
1361ebccf1e3SJoseph Koshy 
1362ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_pdu[] = { /* packed dp uop */
1363ebccf1e3SJoseph Koshy 	__P4MASK(all, 15),
1364ebccf1e3SJoseph Koshy 	NULLMASK
1365ebccf1e3SJoseph Koshy };
1366ebccf1e3SJoseph Koshy 
1367ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_ssu[] = { /* scalar sp uop */
1368ebccf1e3SJoseph Koshy 	__P4MASK(all, 15),
1369ebccf1e3SJoseph Koshy 	NULLMASK
1370ebccf1e3SJoseph Koshy };
1371ebccf1e3SJoseph Koshy 
1372ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_sdu[] = { /* scalar dp uop */
1373ebccf1e3SJoseph Koshy 	__P4MASK(all, 15),
1374ebccf1e3SJoseph Koshy 	NULLMASK
1375ebccf1e3SJoseph Koshy };
1376ebccf1e3SJoseph Koshy 
1377ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_64bmu[] = { /* 64 bit mmx uop */
1378ebccf1e3SJoseph Koshy 	__P4MASK(all, 15),
1379ebccf1e3SJoseph Koshy 	NULLMASK
1380ebccf1e3SJoseph Koshy };
1381ebccf1e3SJoseph Koshy 
1382ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_128bmu[] = { /* 128 bit mmx uop */
1383ebccf1e3SJoseph Koshy 	__P4MASK(all, 15),
1384ebccf1e3SJoseph Koshy 	NULLMASK
1385ebccf1e3SJoseph Koshy };
1386ebccf1e3SJoseph Koshy 
1387ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_xfu[] = { /* X87 fp uop */
1388ebccf1e3SJoseph Koshy 	__P4MASK(all, 15),
1389ebccf1e3SJoseph Koshy 	NULLMASK
1390ebccf1e3SJoseph Koshy };
1391ebccf1e3SJoseph Koshy 
1392ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_xsmu[] = { /* x87 simd moves uop */
1393ebccf1e3SJoseph Koshy 	__P4MASK(allp0, 3),
1394ebccf1e3SJoseph Koshy 	__P4MASK(allp2, 4),
1395ebccf1e3SJoseph Koshy 	NULLMASK
1396ebccf1e3SJoseph Koshy };
1397ebccf1e3SJoseph Koshy 
1398ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_gpe[] = { /* global power events */
1399ebccf1e3SJoseph Koshy 	__P4MASK(running, 0),
1400ebccf1e3SJoseph Koshy 	NULLMASK
1401ebccf1e3SJoseph Koshy };
1402ebccf1e3SJoseph Koshy 
1403ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_tmx[] = { /* TC ms xfer */
1404ebccf1e3SJoseph Koshy 	__P4MASK(cisc, 0),
1405ebccf1e3SJoseph Koshy 	NULLMASK
1406ebccf1e3SJoseph Koshy };
1407ebccf1e3SJoseph Koshy 
1408ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_uqw[] = { /* uop queue writes */
1409ebccf1e3SJoseph Koshy 	__P4MASK(from-tc-build, 0),
1410ebccf1e3SJoseph Koshy 	__P4MASK(from-tc-deliver, 1),
1411ebccf1e3SJoseph Koshy 	__P4MASK(from-rom, 2),
1412ebccf1e3SJoseph Koshy 	NULLMASK
1413ebccf1e3SJoseph Koshy };
1414ebccf1e3SJoseph Koshy 
1415d56c5d4bSJoseph Koshy static const struct pmc_masks p4_mask_rmbt[] = {
1416d56c5d4bSJoseph Koshy 	/* retired mispred branch type */
1417ebccf1e3SJoseph Koshy 	__P4MASK(conditional, 1),
1418ebccf1e3SJoseph Koshy 	__P4MASK(call, 2),
1419ebccf1e3SJoseph Koshy 	__P4MASK(return, 3),
1420ebccf1e3SJoseph Koshy 	__P4MASK(indirect, 4),
1421ebccf1e3SJoseph Koshy 	NULLMASK
1422ebccf1e3SJoseph Koshy };
1423ebccf1e3SJoseph Koshy 
1424ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_rbt[] = { /* retired branch type */
1425ebccf1e3SJoseph Koshy 	__P4MASK(conditional, 1),
1426ebccf1e3SJoseph Koshy 	__P4MASK(call, 2),
1427ebccf1e3SJoseph Koshy 	__P4MASK(retired, 3),
1428ebccf1e3SJoseph Koshy 	__P4MASK(indirect, 4),
1429ebccf1e3SJoseph Koshy 	NULLMASK
1430ebccf1e3SJoseph Koshy };
1431ebccf1e3SJoseph Koshy 
1432ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_rs[] = { /* resource stall */
1433ebccf1e3SJoseph Koshy 	__P4MASK(sbfull, 5),
1434ebccf1e3SJoseph Koshy 	NULLMASK
1435ebccf1e3SJoseph Koshy };
1436ebccf1e3SJoseph Koshy 
1437ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_wb[] = { /* WC buffer */
1438ebccf1e3SJoseph Koshy 	__P4MASK(wcb-evicts, 0),
1439ebccf1e3SJoseph Koshy 	__P4MASK(wcb-full-evict, 1),
1440ebccf1e3SJoseph Koshy 	NULLMASK
1441ebccf1e3SJoseph Koshy };
1442ebccf1e3SJoseph Koshy 
1443ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_fee[] = { /* front end event */
1444ebccf1e3SJoseph Koshy 	__P4MASK(nbogus, 0),
1445ebccf1e3SJoseph Koshy 	__P4MASK(bogus, 1),
1446ebccf1e3SJoseph Koshy 	NULLMASK
1447ebccf1e3SJoseph Koshy };
1448ebccf1e3SJoseph Koshy 
1449ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_ee[] = { /* execution event */
1450ebccf1e3SJoseph Koshy 	__P4MASK(nbogus0, 0),
1451ebccf1e3SJoseph Koshy 	__P4MASK(nbogus1, 1),
1452ebccf1e3SJoseph Koshy 	__P4MASK(nbogus2, 2),
1453ebccf1e3SJoseph Koshy 	__P4MASK(nbogus3, 3),
1454ebccf1e3SJoseph Koshy 	__P4MASK(bogus0, 4),
1455ebccf1e3SJoseph Koshy 	__P4MASK(bogus1, 5),
1456ebccf1e3SJoseph Koshy 	__P4MASK(bogus2, 6),
1457ebccf1e3SJoseph Koshy 	__P4MASK(bogus3, 7),
1458ebccf1e3SJoseph Koshy 	NULLMASK
1459ebccf1e3SJoseph Koshy };
1460ebccf1e3SJoseph Koshy 
1461ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_re[] = { /* replay event */
1462ebccf1e3SJoseph Koshy 	__P4MASK(nbogus, 0),
1463ebccf1e3SJoseph Koshy 	__P4MASK(bogus, 1),
1464ebccf1e3SJoseph Koshy 	NULLMASK
1465ebccf1e3SJoseph Koshy };
1466ebccf1e3SJoseph Koshy 
1467ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_insret[] = { /* instr retired */
1468ebccf1e3SJoseph Koshy 	__P4MASK(nbogusntag, 0),
1469ebccf1e3SJoseph Koshy 	__P4MASK(nbogustag, 1),
1470ebccf1e3SJoseph Koshy 	__P4MASK(bogusntag, 2),
1471ebccf1e3SJoseph Koshy 	__P4MASK(bogustag, 3),
1472ebccf1e3SJoseph Koshy 	NULLMASK
1473ebccf1e3SJoseph Koshy };
1474ebccf1e3SJoseph Koshy 
1475ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_ur[] = { /* uops retired */
1476ebccf1e3SJoseph Koshy 	__P4MASK(nbogus, 0),
1477ebccf1e3SJoseph Koshy 	__P4MASK(bogus, 1),
1478ebccf1e3SJoseph Koshy 	NULLMASK
1479ebccf1e3SJoseph Koshy };
1480ebccf1e3SJoseph Koshy 
1481ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_ut[] = { /* uop type */
1482ebccf1e3SJoseph Koshy 	__P4MASK(tagloads, 1),
1483ebccf1e3SJoseph Koshy 	__P4MASK(tagstores, 2),
1484ebccf1e3SJoseph Koshy 	NULLMASK
1485ebccf1e3SJoseph Koshy };
1486ebccf1e3SJoseph Koshy 
1487ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_br[] = { /* branch retired */
1488ebccf1e3SJoseph Koshy 	__P4MASK(mmnp, 0),
1489ebccf1e3SJoseph Koshy 	__P4MASK(mmnm, 1),
1490ebccf1e3SJoseph Koshy 	__P4MASK(mmtp, 2),
1491ebccf1e3SJoseph Koshy 	__P4MASK(mmtm, 3),
1492ebccf1e3SJoseph Koshy 	NULLMASK
1493ebccf1e3SJoseph Koshy };
1494ebccf1e3SJoseph Koshy 
1495ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_mbr[] = { /* mispred branch retired */
1496ebccf1e3SJoseph Koshy 	__P4MASK(nbogus, 0),
1497ebccf1e3SJoseph Koshy 	NULLMASK
1498ebccf1e3SJoseph Koshy };
1499ebccf1e3SJoseph Koshy 
1500ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_xa[] = { /* x87 assist */
1501ebccf1e3SJoseph Koshy 	__P4MASK(fpsu, 0),
1502ebccf1e3SJoseph Koshy 	__P4MASK(fpso, 1),
1503ebccf1e3SJoseph Koshy 	__P4MASK(poao, 2),
1504ebccf1e3SJoseph Koshy 	__P4MASK(poau, 3),
1505ebccf1e3SJoseph Koshy 	__P4MASK(prea, 4),
1506ebccf1e3SJoseph Koshy 	NULLMASK
1507ebccf1e3SJoseph Koshy };
1508ebccf1e3SJoseph Koshy 
1509ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_machclr[] = { /* machine clear */
1510ebccf1e3SJoseph Koshy 	__P4MASK(clear, 0),
1511ebccf1e3SJoseph Koshy 	__P4MASK(moclear, 2),
1512ebccf1e3SJoseph Koshy 	__P4MASK(smclear, 3),
1513ebccf1e3SJoseph Koshy 	NULLMASK
1514ebccf1e3SJoseph Koshy };
1515ebccf1e3SJoseph Koshy 
1516ebccf1e3SJoseph Koshy /* P4 event parser */
1517ebccf1e3SJoseph Koshy static int
1518ebccf1e3SJoseph Koshy p4_allocate_pmc(enum pmc_event pe, char *ctrspec,
1519ebccf1e3SJoseph Koshy     struct pmc_op_pmcallocate *pmc_config)
1520ebccf1e3SJoseph Koshy {
1521ebccf1e3SJoseph Koshy 
1522ebccf1e3SJoseph Koshy 	char	*e, *p, *q;
1523ebccf1e3SJoseph Koshy 	int	count, has_tag, has_busreqtype, n;
1524ebccf1e3SJoseph Koshy 	uint32_t evmask, cccractivemask;
1525ebccf1e3SJoseph Koshy 	const struct pmc_masks *pm, *pmask;
1526ebccf1e3SJoseph Koshy 
1527789140c0SJoseph Koshy 	pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE);
1528f263522aSJoseph Koshy 	pmc_config->pm_md.pm_p4.pm_p4_cccrconfig =
1529f263522aSJoseph Koshy 	    pmc_config->pm_md.pm_p4.pm_p4_escrconfig = 0;
1530ebccf1e3SJoseph Koshy 
1531ebccf1e3SJoseph Koshy 	pmask   = NULL;
1532ebccf1e3SJoseph Koshy 	evmask  = 0;
1533ebccf1e3SJoseph Koshy 	cccractivemask = 0x3;
1534ebccf1e3SJoseph Koshy 	has_tag = has_busreqtype = 0;
1535ebccf1e3SJoseph Koshy 
1536ebccf1e3SJoseph Koshy #define	__P4SETMASK(M) do {				\
1537ebccf1e3SJoseph Koshy 	pmask = p4_mask_##M;				\
1538ebccf1e3SJoseph Koshy } while (0)
1539ebccf1e3SJoseph Koshy 
1540ebccf1e3SJoseph Koshy 	switch (pe) {
1541ebccf1e3SJoseph Koshy 	case PMC_EV_P4_TC_DELIVER_MODE:
1542ebccf1e3SJoseph Koshy 		__P4SETMASK(tcdm);
1543ebccf1e3SJoseph Koshy 		break;
1544ebccf1e3SJoseph Koshy 	case PMC_EV_P4_BPU_FETCH_REQUEST:
1545ebccf1e3SJoseph Koshy 		__P4SETMASK(bfr);
1546ebccf1e3SJoseph Koshy 		break;
1547ebccf1e3SJoseph Koshy 	case PMC_EV_P4_ITLB_REFERENCE:
1548ebccf1e3SJoseph Koshy 		__P4SETMASK(ir);
1549ebccf1e3SJoseph Koshy 		break;
1550ebccf1e3SJoseph Koshy 	case PMC_EV_P4_MEMORY_CANCEL:
1551ebccf1e3SJoseph Koshy 		__P4SETMASK(memcan);
1552ebccf1e3SJoseph Koshy 		break;
1553ebccf1e3SJoseph Koshy 	case PMC_EV_P4_MEMORY_COMPLETE:
1554ebccf1e3SJoseph Koshy 		__P4SETMASK(memcomp);
1555ebccf1e3SJoseph Koshy 		break;
1556ebccf1e3SJoseph Koshy 	case PMC_EV_P4_LOAD_PORT_REPLAY:
1557ebccf1e3SJoseph Koshy 		__P4SETMASK(lpr);
1558ebccf1e3SJoseph Koshy 		break;
1559ebccf1e3SJoseph Koshy 	case PMC_EV_P4_STORE_PORT_REPLAY:
1560ebccf1e3SJoseph Koshy 		__P4SETMASK(spr);
1561ebccf1e3SJoseph Koshy 		break;
1562ebccf1e3SJoseph Koshy 	case PMC_EV_P4_MOB_LOAD_REPLAY:
1563ebccf1e3SJoseph Koshy 		__P4SETMASK(mlr);
1564ebccf1e3SJoseph Koshy 		break;
1565ebccf1e3SJoseph Koshy 	case PMC_EV_P4_PAGE_WALK_TYPE:
1566ebccf1e3SJoseph Koshy 		__P4SETMASK(pwt);
1567ebccf1e3SJoseph Koshy 		break;
1568ebccf1e3SJoseph Koshy 	case PMC_EV_P4_BSQ_CACHE_REFERENCE:
1569ebccf1e3SJoseph Koshy 		__P4SETMASK(bcr);
1570ebccf1e3SJoseph Koshy 		break;
1571ebccf1e3SJoseph Koshy 	case PMC_EV_P4_IOQ_ALLOCATION:
1572ebccf1e3SJoseph Koshy 		__P4SETMASK(ia);
1573ebccf1e3SJoseph Koshy 		has_busreqtype = 1;
1574ebccf1e3SJoseph Koshy 		break;
1575ebccf1e3SJoseph Koshy 	case PMC_EV_P4_IOQ_ACTIVE_ENTRIES:
1576ebccf1e3SJoseph Koshy 		__P4SETMASK(iae);
1577ebccf1e3SJoseph Koshy 		has_busreqtype = 1;
1578ebccf1e3SJoseph Koshy 		break;
1579ebccf1e3SJoseph Koshy 	case PMC_EV_P4_FSB_DATA_ACTIVITY:
1580ebccf1e3SJoseph Koshy 		__P4SETMASK(fda);
1581ebccf1e3SJoseph Koshy 		break;
1582ebccf1e3SJoseph Koshy 	case PMC_EV_P4_BSQ_ALLOCATION:
1583ebccf1e3SJoseph Koshy 		__P4SETMASK(ba);
1584ebccf1e3SJoseph Koshy 		break;
1585ebccf1e3SJoseph Koshy 	case PMC_EV_P4_SSE_INPUT_ASSIST:
1586ebccf1e3SJoseph Koshy 		__P4SETMASK(sia);
1587ebccf1e3SJoseph Koshy 		break;
1588ebccf1e3SJoseph Koshy 	case PMC_EV_P4_PACKED_SP_UOP:
1589ebccf1e3SJoseph Koshy 		__P4SETMASK(psu);
1590ebccf1e3SJoseph Koshy 		break;
1591ebccf1e3SJoseph Koshy 	case PMC_EV_P4_PACKED_DP_UOP:
1592ebccf1e3SJoseph Koshy 		__P4SETMASK(pdu);
1593ebccf1e3SJoseph Koshy 		break;
1594ebccf1e3SJoseph Koshy 	case PMC_EV_P4_SCALAR_SP_UOP:
1595ebccf1e3SJoseph Koshy 		__P4SETMASK(ssu);
1596ebccf1e3SJoseph Koshy 		break;
1597ebccf1e3SJoseph Koshy 	case PMC_EV_P4_SCALAR_DP_UOP:
1598ebccf1e3SJoseph Koshy 		__P4SETMASK(sdu);
1599ebccf1e3SJoseph Koshy 		break;
1600ebccf1e3SJoseph Koshy 	case PMC_EV_P4_64BIT_MMX_UOP:
1601ebccf1e3SJoseph Koshy 		__P4SETMASK(64bmu);
1602ebccf1e3SJoseph Koshy 		break;
1603ebccf1e3SJoseph Koshy 	case PMC_EV_P4_128BIT_MMX_UOP:
1604ebccf1e3SJoseph Koshy 		__P4SETMASK(128bmu);
1605ebccf1e3SJoseph Koshy 		break;
1606ebccf1e3SJoseph Koshy 	case PMC_EV_P4_X87_FP_UOP:
1607ebccf1e3SJoseph Koshy 		__P4SETMASK(xfu);
1608ebccf1e3SJoseph Koshy 		break;
1609ebccf1e3SJoseph Koshy 	case PMC_EV_P4_X87_SIMD_MOVES_UOP:
1610ebccf1e3SJoseph Koshy 		__P4SETMASK(xsmu);
1611ebccf1e3SJoseph Koshy 		break;
1612ebccf1e3SJoseph Koshy 	case PMC_EV_P4_GLOBAL_POWER_EVENTS:
1613ebccf1e3SJoseph Koshy 		__P4SETMASK(gpe);
1614ebccf1e3SJoseph Koshy 		break;
1615ebccf1e3SJoseph Koshy 	case PMC_EV_P4_TC_MS_XFER:
1616ebccf1e3SJoseph Koshy 		__P4SETMASK(tmx);
1617ebccf1e3SJoseph Koshy 		break;
1618ebccf1e3SJoseph Koshy 	case PMC_EV_P4_UOP_QUEUE_WRITES:
1619ebccf1e3SJoseph Koshy 		__P4SETMASK(uqw);
1620ebccf1e3SJoseph Koshy 		break;
1621ebccf1e3SJoseph Koshy 	case PMC_EV_P4_RETIRED_MISPRED_BRANCH_TYPE:
1622ebccf1e3SJoseph Koshy 		__P4SETMASK(rmbt);
1623ebccf1e3SJoseph Koshy 		break;
1624ebccf1e3SJoseph Koshy 	case PMC_EV_P4_RETIRED_BRANCH_TYPE:
1625ebccf1e3SJoseph Koshy 		__P4SETMASK(rbt);
1626ebccf1e3SJoseph Koshy 		break;
1627ebccf1e3SJoseph Koshy 	case PMC_EV_P4_RESOURCE_STALL:
1628ebccf1e3SJoseph Koshy 		__P4SETMASK(rs);
1629ebccf1e3SJoseph Koshy 		break;
1630ebccf1e3SJoseph Koshy 	case PMC_EV_P4_WC_BUFFER:
1631ebccf1e3SJoseph Koshy 		__P4SETMASK(wb);
1632ebccf1e3SJoseph Koshy 		break;
1633ebccf1e3SJoseph Koshy 	case PMC_EV_P4_BSQ_ACTIVE_ENTRIES:
1634ebccf1e3SJoseph Koshy 	case PMC_EV_P4_B2B_CYCLES:
1635ebccf1e3SJoseph Koshy 	case PMC_EV_P4_BNR:
1636ebccf1e3SJoseph Koshy 	case PMC_EV_P4_SNOOP:
1637ebccf1e3SJoseph Koshy 	case PMC_EV_P4_RESPONSE:
1638ebccf1e3SJoseph Koshy 		break;
1639ebccf1e3SJoseph Koshy 	case PMC_EV_P4_FRONT_END_EVENT:
1640ebccf1e3SJoseph Koshy 		__P4SETMASK(fee);
1641ebccf1e3SJoseph Koshy 		break;
1642ebccf1e3SJoseph Koshy 	case PMC_EV_P4_EXECUTION_EVENT:
1643ebccf1e3SJoseph Koshy 		__P4SETMASK(ee);
1644ebccf1e3SJoseph Koshy 		break;
1645ebccf1e3SJoseph Koshy 	case PMC_EV_P4_REPLAY_EVENT:
1646ebccf1e3SJoseph Koshy 		__P4SETMASK(re);
1647ebccf1e3SJoseph Koshy 		break;
1648ebccf1e3SJoseph Koshy 	case PMC_EV_P4_INSTR_RETIRED:
1649ebccf1e3SJoseph Koshy 		__P4SETMASK(insret);
1650ebccf1e3SJoseph Koshy 		break;
1651ebccf1e3SJoseph Koshy 	case PMC_EV_P4_UOPS_RETIRED:
1652ebccf1e3SJoseph Koshy 		__P4SETMASK(ur);
1653ebccf1e3SJoseph Koshy 		break;
1654ebccf1e3SJoseph Koshy 	case PMC_EV_P4_UOP_TYPE:
1655ebccf1e3SJoseph Koshy 		__P4SETMASK(ut);
1656ebccf1e3SJoseph Koshy 		break;
1657ebccf1e3SJoseph Koshy 	case PMC_EV_P4_BRANCH_RETIRED:
1658ebccf1e3SJoseph Koshy 		__P4SETMASK(br);
1659ebccf1e3SJoseph Koshy 		break;
1660ebccf1e3SJoseph Koshy 	case PMC_EV_P4_MISPRED_BRANCH_RETIRED:
1661ebccf1e3SJoseph Koshy 		__P4SETMASK(mbr);
1662ebccf1e3SJoseph Koshy 		break;
1663ebccf1e3SJoseph Koshy 	case PMC_EV_P4_X87_ASSIST:
1664ebccf1e3SJoseph Koshy 		__P4SETMASK(xa);
1665ebccf1e3SJoseph Koshy 		break;
1666ebccf1e3SJoseph Koshy 	case PMC_EV_P4_MACHINE_CLEAR:
1667ebccf1e3SJoseph Koshy 		__P4SETMASK(machclr);
1668ebccf1e3SJoseph Koshy 		break;
1669ebccf1e3SJoseph Koshy 	default:
1670aa342b1fSJoseph Koshy 		return (-1);
1671ebccf1e3SJoseph Koshy 	}
1672ebccf1e3SJoseph Koshy 
1673ebccf1e3SJoseph Koshy 	/* process additional flags */
1674ebccf1e3SJoseph Koshy 	while ((p = strsep(&ctrspec, ",")) != NULL) {
1675ebccf1e3SJoseph Koshy 		if (KWPREFIXMATCH(p, P4_KW_ACTIVE)) {
1676ebccf1e3SJoseph Koshy 			q = strchr(p, '=');
1677ebccf1e3SJoseph Koshy 			if (*++q == '\0') /* skip '=' */
1678aa342b1fSJoseph Koshy 				return (-1);
1679ebccf1e3SJoseph Koshy 
1680789140c0SJoseph Koshy 			if (strcasecmp(q, P4_KW_ACTIVE_NONE) == 0)
1681ebccf1e3SJoseph Koshy 				cccractivemask = 0x0;
1682789140c0SJoseph Koshy 			else if (strcasecmp(q, P4_KW_ACTIVE_SINGLE) == 0)
1683ebccf1e3SJoseph Koshy 				cccractivemask = 0x1;
1684789140c0SJoseph Koshy 			else if (strcasecmp(q, P4_KW_ACTIVE_BOTH) == 0)
1685ebccf1e3SJoseph Koshy 				cccractivemask = 0x2;
1686789140c0SJoseph Koshy 			else if (strcasecmp(q, P4_KW_ACTIVE_ANY) == 0)
1687ebccf1e3SJoseph Koshy 				cccractivemask = 0x3;
1688ebccf1e3SJoseph Koshy 			else
1689aa342b1fSJoseph Koshy 				return (-1);
1690ebccf1e3SJoseph Koshy 
1691ebccf1e3SJoseph Koshy 		} else if (KWPREFIXMATCH(p, P4_KW_BUSREQTYPE)) {
1692ebccf1e3SJoseph Koshy 			if (has_busreqtype == 0)
1693aa342b1fSJoseph Koshy 				return (-1);
1694ebccf1e3SJoseph Koshy 
1695ebccf1e3SJoseph Koshy 			q = strchr(p, '=');
1696ebccf1e3SJoseph Koshy 			if (*++q == '\0') /* skip '=' */
1697aa342b1fSJoseph Koshy 				return (-1);
1698ebccf1e3SJoseph Koshy 
1699ebccf1e3SJoseph Koshy 			count = strtol(q, &e, 0);
1700ebccf1e3SJoseph Koshy 			if (e == q || *e != '\0')
1701aa342b1fSJoseph Koshy 				return (-1);
1702ebccf1e3SJoseph Koshy 			evmask = (evmask & ~0x1F) | (count & 0x1F);
1703ebccf1e3SJoseph Koshy 		} else if (KWMATCH(p, P4_KW_CASCADE))
1704ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_CASCADE;
1705ebccf1e3SJoseph Koshy 		else if (KWMATCH(p, P4_KW_EDGE))
1706ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_EDGE;
1707ebccf1e3SJoseph Koshy 		else if (KWMATCH(p, P4_KW_INV))
1708ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_INVERT;
1709ebccf1e3SJoseph Koshy 		else if (KWPREFIXMATCH(p, P4_KW_MASK "=")) {
1710ebccf1e3SJoseph Koshy 			if ((n = pmc_parse_mask(pmask, p, &evmask)) < 0)
1711aa342b1fSJoseph Koshy 				return (-1);
1712ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_QUALIFIER;
1713ebccf1e3SJoseph Koshy 		} else if (KWMATCH(p, P4_KW_OS))
1714ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_SYSTEM;
1715ebccf1e3SJoseph Koshy 		else if (KWMATCH(p, P4_KW_PRECISE))
1716ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_PRECISE;
1717ebccf1e3SJoseph Koshy 		else if (KWPREFIXMATCH(p, P4_KW_TAG "=")) {
1718ebccf1e3SJoseph Koshy 			if (has_tag == 0)
1719aa342b1fSJoseph Koshy 				return (-1);
1720ebccf1e3SJoseph Koshy 
1721ebccf1e3SJoseph Koshy 			q = strchr(p, '=');
1722ebccf1e3SJoseph Koshy 			if (*++q == '\0') /* skip '=' */
1723aa342b1fSJoseph Koshy 				return (-1);
1724ebccf1e3SJoseph Koshy 
1725ebccf1e3SJoseph Koshy 			count = strtol(q, &e, 0);
1726ebccf1e3SJoseph Koshy 			if (e == q || *e != '\0')
1727aa342b1fSJoseph Koshy 				return (-1);
1728ebccf1e3SJoseph Koshy 
1729ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_TAGGING;
1730f263522aSJoseph Koshy 			pmc_config->pm_md.pm_p4.pm_p4_escrconfig |=
1731ebccf1e3SJoseph Koshy 			    P4_ESCR_TO_TAG_VALUE(count);
1732ebccf1e3SJoseph Koshy 		} else if (KWPREFIXMATCH(p, P4_KW_THRESHOLD "=")) {
1733ebccf1e3SJoseph Koshy 			q = strchr(p, '=');
1734ebccf1e3SJoseph Koshy 			if (*++q == '\0') /* skip '=' */
1735aa342b1fSJoseph Koshy 				return (-1);
1736ebccf1e3SJoseph Koshy 
1737ebccf1e3SJoseph Koshy 			count = strtol(q, &e, 0);
1738ebccf1e3SJoseph Koshy 			if (e == q || *e != '\0')
1739aa342b1fSJoseph Koshy 				return (-1);
1740ebccf1e3SJoseph Koshy 
1741ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_THRESHOLD;
1742f263522aSJoseph Koshy 			pmc_config->pm_md.pm_p4.pm_p4_cccrconfig &=
1743f263522aSJoseph Koshy 			    ~P4_CCCR_THRESHOLD_MASK;
1744f263522aSJoseph Koshy 			pmc_config->pm_md.pm_p4.pm_p4_cccrconfig |=
1745f263522aSJoseph Koshy 			    P4_CCCR_TO_THRESHOLD(count);
1746ebccf1e3SJoseph Koshy 		} else if (KWMATCH(p, P4_KW_USR))
1747ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_USER;
1748ebccf1e3SJoseph Koshy 		else
1749aa342b1fSJoseph Koshy 			return (-1);
1750ebccf1e3SJoseph Koshy 	}
1751ebccf1e3SJoseph Koshy 
1752ebccf1e3SJoseph Koshy 	/* other post processing */
1753ebccf1e3SJoseph Koshy 	if (pe == PMC_EV_P4_IOQ_ALLOCATION ||
1754ebccf1e3SJoseph Koshy 	    pe == PMC_EV_P4_FSB_DATA_ACTIVITY ||
1755ebccf1e3SJoseph Koshy 	    pe == PMC_EV_P4_BSQ_ALLOCATION)
1756ebccf1e3SJoseph Koshy 		pmc_config->pm_caps |= PMC_CAP_EDGE;
1757ebccf1e3SJoseph Koshy 
1758ebccf1e3SJoseph Koshy 	/* fill in thread activity mask */
1759f263522aSJoseph Koshy 	pmc_config->pm_md.pm_p4.pm_p4_cccrconfig |=
1760ebccf1e3SJoseph Koshy 	    P4_CCCR_TO_ACTIVE_THREAD(cccractivemask);
1761ebccf1e3SJoseph Koshy 
1762ebccf1e3SJoseph Koshy 	if (evmask)
1763ebccf1e3SJoseph Koshy 		pmc_config->pm_caps |= PMC_CAP_QUALIFIER;
1764ebccf1e3SJoseph Koshy 
1765ebccf1e3SJoseph Koshy 	switch (pe) {
1766ebccf1e3SJoseph Koshy 	case PMC_EV_P4_FSB_DATA_ACTIVITY:
1767ebccf1e3SJoseph Koshy 		if ((evmask & 0x06) == 0x06 ||
1768ebccf1e3SJoseph Koshy 		    (evmask & 0x18) == 0x18)
1769aa342b1fSJoseph Koshy 			return (-1); /* can't have own+other bits together */
1770ebccf1e3SJoseph Koshy 		if (evmask == 0) /* default:drdy-{drv,own}+dbsy{drv,own} */
1771ebccf1e3SJoseph Koshy 			evmask = 0x1D;
1772ebccf1e3SJoseph Koshy 		break;
1773ebccf1e3SJoseph Koshy 	case PMC_EV_P4_MACHINE_CLEAR:
1774ebccf1e3SJoseph Koshy 		/* only one bit is allowed to be set */
1775ebccf1e3SJoseph Koshy 		if ((evmask & (evmask - 1)) != 0)
1776aa342b1fSJoseph Koshy 			return (-1);
1777ebccf1e3SJoseph Koshy 		if (evmask == 0) {
1778ebccf1e3SJoseph Koshy 			evmask = 0x1;	/* 'CLEAR' */
1779ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_QUALIFIER;
1780ebccf1e3SJoseph Koshy 		}
1781ebccf1e3SJoseph Koshy 		break;
1782ebccf1e3SJoseph Koshy 	default:
1783ebccf1e3SJoseph Koshy 		if (evmask == 0 && pmask) {
1784ebccf1e3SJoseph Koshy 			for (pm = pmask; pm->pm_name; pm++)
1785ebccf1e3SJoseph Koshy 				evmask |= pm->pm_value;
1786ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_QUALIFIER;
1787ebccf1e3SJoseph Koshy 		}
1788ebccf1e3SJoseph Koshy 	}
1789ebccf1e3SJoseph Koshy 
1790f263522aSJoseph Koshy 	pmc_config->pm_md.pm_p4.pm_p4_escrconfig =
1791f263522aSJoseph Koshy 	    P4_ESCR_TO_EVENT_MASK(evmask);
1792ebccf1e3SJoseph Koshy 
1793aa342b1fSJoseph Koshy 	return (0);
1794ebccf1e3SJoseph Koshy }
1795ebccf1e3SJoseph Koshy 
179686a65549SJoseph Koshy #endif
179786a65549SJoseph Koshy 
179886a65549SJoseph Koshy #if defined(__i386__)
179986a65549SJoseph Koshy 
1800ebccf1e3SJoseph Koshy /*
1801f263522aSJoseph Koshy  * Pentium style PMCs
1802f263522aSJoseph Koshy  */
1803f263522aSJoseph Koshy 
1804f263522aSJoseph Koshy static struct pmc_event_alias p5_aliases[] = {
18050b9b757dSJoseph Koshy 	EV_ALIAS("branches",		"p5-taken-branches"),
1806f263522aSJoseph Koshy 	EV_ALIAS("cycles",		"tsc"),
18070b9b757dSJoseph Koshy 	EV_ALIAS("dc-misses",		"p5-data-read-miss-or-write-miss"),
18080b9b757dSJoseph Koshy 	EV_ALIAS("ic-misses",		"p5-code-cache-miss"),
18090b9b757dSJoseph Koshy 	EV_ALIAS("instructions",	"p5-instructions-executed"),
18100b9b757dSJoseph Koshy 	EV_ALIAS("interrupts",		"p5-hardware-interrupts"),
18110b9b757dSJoseph Koshy 	EV_ALIAS("unhalted-cycles",
18120b9b757dSJoseph Koshy 	    "p5-number-of-cycles-not-in-halt-state"),
1813f263522aSJoseph Koshy 	EV_ALIAS(NULL, NULL)
1814f263522aSJoseph Koshy };
1815f263522aSJoseph Koshy 
1816f263522aSJoseph Koshy static int
1817f263522aSJoseph Koshy p5_allocate_pmc(enum pmc_event pe, char *ctrspec,
1818f263522aSJoseph Koshy     struct pmc_op_pmcallocate *pmc_config)
1819f263522aSJoseph Koshy {
1820aa342b1fSJoseph Koshy 	return (-1 || pe || ctrspec || pmc_config); /* shut up gcc */
1821f263522aSJoseph Koshy }
1822f263522aSJoseph Koshy 
1823f263522aSJoseph Koshy /*
1824ebccf1e3SJoseph Koshy  * Pentium Pro style PMCs.  These PMCs are found in Pentium II, Pentium III,
1825ebccf1e3SJoseph Koshy  * and Pentium M CPUs.
1826ebccf1e3SJoseph Koshy  */
1827ebccf1e3SJoseph Koshy 
1828ebccf1e3SJoseph Koshy static struct pmc_event_alias p6_aliases[] = {
1829ebccf1e3SJoseph Koshy 	EV_ALIAS("branches",		"p6-br-inst-retired"),
1830ebccf1e3SJoseph Koshy 	EV_ALIAS("branch-mispredicts",	"p6-br-miss-pred-retired"),
1831ebccf1e3SJoseph Koshy 	EV_ALIAS("cycles",		"tsc"),
1832d56c5d4bSJoseph Koshy 	EV_ALIAS("dc-misses",		"p6-dcu-lines-in"),
183373e2d811SJoseph Koshy 	EV_ALIAS("ic-misses",		"p6-ifu-fetch-miss"),
1834ebccf1e3SJoseph Koshy 	EV_ALIAS("instructions",	"p6-inst-retired"),
1835ebccf1e3SJoseph Koshy 	EV_ALIAS("interrupts",		"p6-hw-int-rx"),
1836177a2f22SJoseph Koshy 	EV_ALIAS("unhalted-cycles",	"p6-cpu-clk-unhalted"),
1837ebccf1e3SJoseph Koshy 	EV_ALIAS(NULL, NULL)
1838ebccf1e3SJoseph Koshy };
1839ebccf1e3SJoseph Koshy 
1840ebccf1e3SJoseph Koshy #define	P6_KW_CMASK	"cmask"
1841ebccf1e3SJoseph Koshy #define	P6_KW_EDGE	"edge"
1842ebccf1e3SJoseph Koshy #define	P6_KW_INV	"inv"
1843ebccf1e3SJoseph Koshy #define	P6_KW_OS	"os"
1844ebccf1e3SJoseph Koshy #define	P6_KW_UMASK	"umask"
1845ebccf1e3SJoseph Koshy #define	P6_KW_USR	"usr"
1846ebccf1e3SJoseph Koshy 
1847ebccf1e3SJoseph Koshy static struct pmc_masks p6_mask_mesi[] = {
1848ebccf1e3SJoseph Koshy 	PMCMASK(m,	0x01),
1849ebccf1e3SJoseph Koshy 	PMCMASK(e,	0x02),
1850ebccf1e3SJoseph Koshy 	PMCMASK(s,	0x04),
1851ebccf1e3SJoseph Koshy 	PMCMASK(i,	0x08),
1852ebccf1e3SJoseph Koshy 	NULLMASK
1853ebccf1e3SJoseph Koshy };
1854ebccf1e3SJoseph Koshy 
1855ebccf1e3SJoseph Koshy static struct pmc_masks p6_mask_mesihw[] = {
1856ebccf1e3SJoseph Koshy 	PMCMASK(m,	0x01),
1857ebccf1e3SJoseph Koshy 	PMCMASK(e,	0x02),
1858ebccf1e3SJoseph Koshy 	PMCMASK(s,	0x04),
1859ebccf1e3SJoseph Koshy 	PMCMASK(i,	0x08),
1860ebccf1e3SJoseph Koshy 	PMCMASK(nonhw,	0x00),
1861ebccf1e3SJoseph Koshy 	PMCMASK(hw,	0x10),
1862ebccf1e3SJoseph Koshy 	PMCMASK(both,	0x30),
1863ebccf1e3SJoseph Koshy 	NULLMASK
1864ebccf1e3SJoseph Koshy };
1865ebccf1e3SJoseph Koshy 
1866ebccf1e3SJoseph Koshy static struct pmc_masks p6_mask_hw[] = {
1867ebccf1e3SJoseph Koshy 	PMCMASK(nonhw,	0x00),
1868ebccf1e3SJoseph Koshy 	PMCMASK(hw,	0x10),
1869ebccf1e3SJoseph Koshy 	PMCMASK(both,	0x30),
1870ebccf1e3SJoseph Koshy 	NULLMASK
1871ebccf1e3SJoseph Koshy };
1872ebccf1e3SJoseph Koshy 
1873ebccf1e3SJoseph Koshy static struct pmc_masks p6_mask_any[] = {
1874ebccf1e3SJoseph Koshy 	PMCMASK(self,	0x00),
1875ebccf1e3SJoseph Koshy 	PMCMASK(any,	0x20),
1876ebccf1e3SJoseph Koshy 	NULLMASK
1877ebccf1e3SJoseph Koshy };
1878ebccf1e3SJoseph Koshy 
1879ebccf1e3SJoseph Koshy static struct pmc_masks p6_mask_ekp[] = {
1880ebccf1e3SJoseph Koshy 	PMCMASK(nta,	0x00),
1881ebccf1e3SJoseph Koshy 	PMCMASK(t1,	0x01),
1882ebccf1e3SJoseph Koshy 	PMCMASK(t2,	0x02),
1883ebccf1e3SJoseph Koshy 	PMCMASK(wos,	0x03),
1884ebccf1e3SJoseph Koshy 	NULLMASK
1885ebccf1e3SJoseph Koshy };
1886ebccf1e3SJoseph Koshy 
1887ebccf1e3SJoseph Koshy static struct pmc_masks p6_mask_pps[] = {
1888ebccf1e3SJoseph Koshy 	PMCMASK(packed-and-scalar, 0x00),
1889ebccf1e3SJoseph Koshy 	PMCMASK(scalar,	0x01),
1890ebccf1e3SJoseph Koshy 	NULLMASK
1891ebccf1e3SJoseph Koshy };
1892ebccf1e3SJoseph Koshy 
1893ebccf1e3SJoseph Koshy static struct pmc_masks p6_mask_mite[] = {
1894ebccf1e3SJoseph Koshy 	PMCMASK(packed-multiply,	 0x01),
1895ebccf1e3SJoseph Koshy 	PMCMASK(packed-shift,		0x02),
1896ebccf1e3SJoseph Koshy 	PMCMASK(pack,			0x04),
1897ebccf1e3SJoseph Koshy 	PMCMASK(unpack,			0x08),
1898ebccf1e3SJoseph Koshy 	PMCMASK(packed-logical,		0x10),
1899ebccf1e3SJoseph Koshy 	PMCMASK(packed-arithmetic,	0x20),
1900ebccf1e3SJoseph Koshy 	NULLMASK
1901ebccf1e3SJoseph Koshy };
1902ebccf1e3SJoseph Koshy 
1903ebccf1e3SJoseph Koshy static struct pmc_masks p6_mask_fmt[] = {
1904ebccf1e3SJoseph Koshy 	PMCMASK(mmxtofp,	0x00),
1905ebccf1e3SJoseph Koshy 	PMCMASK(fptommx,	0x01),
1906ebccf1e3SJoseph Koshy 	NULLMASK
1907ebccf1e3SJoseph Koshy };
1908ebccf1e3SJoseph Koshy 
1909ebccf1e3SJoseph Koshy static struct pmc_masks p6_mask_sr[] = {
1910ebccf1e3SJoseph Koshy 	PMCMASK(es,	0x01),
1911ebccf1e3SJoseph Koshy 	PMCMASK(ds,	0x02),
1912ebccf1e3SJoseph Koshy 	PMCMASK(fs,	0x04),
1913ebccf1e3SJoseph Koshy 	PMCMASK(gs,	0x08),
1914ebccf1e3SJoseph Koshy 	NULLMASK
1915ebccf1e3SJoseph Koshy };
1916ebccf1e3SJoseph Koshy 
1917ebccf1e3SJoseph Koshy static struct pmc_masks p6_mask_eet[] = {
1918ebccf1e3SJoseph Koshy 	PMCMASK(all,	0x00),
1919ebccf1e3SJoseph Koshy 	PMCMASK(freq,	0x02),
1920ebccf1e3SJoseph Koshy 	NULLMASK
1921ebccf1e3SJoseph Koshy };
1922ebccf1e3SJoseph Koshy 
1923ebccf1e3SJoseph Koshy static struct pmc_masks p6_mask_efur[] = {
1924ebccf1e3SJoseph Koshy 	PMCMASK(all,	0x00),
1925ebccf1e3SJoseph Koshy 	PMCMASK(loadop,	0x01),
1926ebccf1e3SJoseph Koshy 	PMCMASK(stdsta,	0x02),
1927ebccf1e3SJoseph Koshy 	NULLMASK
1928ebccf1e3SJoseph Koshy };
1929ebccf1e3SJoseph Koshy 
1930ebccf1e3SJoseph Koshy static struct pmc_masks p6_mask_essir[] = {
1931ebccf1e3SJoseph Koshy 	PMCMASK(sse-packed-single,	0x00),
1932ebccf1e3SJoseph Koshy 	PMCMASK(sse-packed-single-scalar-single, 0x01),
1933ebccf1e3SJoseph Koshy 	PMCMASK(sse2-packed-double,	0x02),
1934ebccf1e3SJoseph Koshy 	PMCMASK(sse2-scalar-double,	0x03),
1935ebccf1e3SJoseph Koshy 	NULLMASK
1936ebccf1e3SJoseph Koshy };
1937ebccf1e3SJoseph Koshy 
1938ebccf1e3SJoseph Koshy static struct pmc_masks p6_mask_esscir[] = {
1939ebccf1e3SJoseph Koshy 	PMCMASK(sse-packed-single,	0x00),
1940ebccf1e3SJoseph Koshy 	PMCMASK(sse-scalar-single,	0x01),
1941ebccf1e3SJoseph Koshy 	PMCMASK(sse2-packed-double,	0x02),
1942ebccf1e3SJoseph Koshy 	PMCMASK(sse2-scalar-double,	0x03),
1943ebccf1e3SJoseph Koshy 	NULLMASK
1944ebccf1e3SJoseph Koshy };
1945ebccf1e3SJoseph Koshy 
1946ebccf1e3SJoseph Koshy /* P6 event parser */
1947ebccf1e3SJoseph Koshy static int
1948ebccf1e3SJoseph Koshy p6_allocate_pmc(enum pmc_event pe, char *ctrspec,
1949ebccf1e3SJoseph Koshy     struct pmc_op_pmcallocate *pmc_config)
1950ebccf1e3SJoseph Koshy {
1951ebccf1e3SJoseph Koshy 	char *e, *p, *q;
1952ebccf1e3SJoseph Koshy 	uint32_t evmask;
1953ebccf1e3SJoseph Koshy 	int count, n;
1954ebccf1e3SJoseph Koshy 	const struct pmc_masks *pm, *pmask;
1955ebccf1e3SJoseph Koshy 
1956789140c0SJoseph Koshy 	pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE);
1957f263522aSJoseph Koshy 	pmc_config->pm_md.pm_ppro.pm_ppro_config = 0;
1958ebccf1e3SJoseph Koshy 
1959ebccf1e3SJoseph Koshy 	evmask = 0;
1960ebccf1e3SJoseph Koshy 
1961ebccf1e3SJoseph Koshy #define	P6MASKSET(M)	pmask = p6_mask_ ## M
1962ebccf1e3SJoseph Koshy 
1963ebccf1e3SJoseph Koshy 	switch(pe) {
1964ebccf1e3SJoseph Koshy 	case PMC_EV_P6_L2_IFETCH:	P6MASKSET(mesi); break;
1965ebccf1e3SJoseph Koshy 	case PMC_EV_P6_L2_LD:		P6MASKSET(mesi); break;
1966ebccf1e3SJoseph Koshy 	case PMC_EV_P6_L2_ST:		P6MASKSET(mesi); break;
1967ebccf1e3SJoseph Koshy 	case PMC_EV_P6_L2_RQSTS:	P6MASKSET(mesi); break;
1968ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_DRDY_CLOCKS:
1969ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_LOCK_CLOCKS:
1970ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_BRD:
1971ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_RFO:
1972ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRANS_WB:
1973ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_IFETCH:
1974ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_INVAL:
1975ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_PWR:
1976ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRANS_P:
1977ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRANS_IO:
1978ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_DEF:
1979ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_BURST:
1980ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_ANY:
1981ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_MEM:
1982ebccf1e3SJoseph Koshy 		P6MASKSET(any);	break;
1983ebccf1e3SJoseph Koshy 	case PMC_EV_P6_EMON_KNI_PREF_DISPATCHED:
1984ebccf1e3SJoseph Koshy 	case PMC_EV_P6_EMON_KNI_PREF_MISS:
1985ebccf1e3SJoseph Koshy 		P6MASKSET(ekp); break;
1986ebccf1e3SJoseph Koshy 	case PMC_EV_P6_EMON_KNI_INST_RETIRED:
1987ebccf1e3SJoseph Koshy 	case PMC_EV_P6_EMON_KNI_COMP_INST_RET:
1988ebccf1e3SJoseph Koshy 		P6MASKSET(pps);	break;
1989ebccf1e3SJoseph Koshy 	case PMC_EV_P6_MMX_INSTR_TYPE_EXEC:
1990ebccf1e3SJoseph Koshy 		P6MASKSET(mite); break;
1991ebccf1e3SJoseph Koshy 	case PMC_EV_P6_FP_MMX_TRANS:
1992ebccf1e3SJoseph Koshy 		P6MASKSET(fmt);	break;
1993ebccf1e3SJoseph Koshy 	case PMC_EV_P6_SEG_RENAME_STALLS:
1994ebccf1e3SJoseph Koshy 	case PMC_EV_P6_SEG_REG_RENAMES:
1995ebccf1e3SJoseph Koshy 		P6MASKSET(sr);	break;
1996ebccf1e3SJoseph Koshy 	case PMC_EV_P6_EMON_EST_TRANS:
1997ebccf1e3SJoseph Koshy 		P6MASKSET(eet);	break;
1998ebccf1e3SJoseph Koshy 	case PMC_EV_P6_EMON_FUSED_UOPS_RET:
1999ebccf1e3SJoseph Koshy 		P6MASKSET(efur); break;
2000ebccf1e3SJoseph Koshy 	case PMC_EV_P6_EMON_SSE_SSE2_INST_RETIRED:
2001ebccf1e3SJoseph Koshy 		P6MASKSET(essir); break;
2002ebccf1e3SJoseph Koshy 	case PMC_EV_P6_EMON_SSE_SSE2_COMP_INST_RETIRED:
2003ebccf1e3SJoseph Koshy 		P6MASKSET(esscir); break;
2004ebccf1e3SJoseph Koshy 	default:
2005ebccf1e3SJoseph Koshy 		pmask = NULL;
2006ebccf1e3SJoseph Koshy 		break;
2007ebccf1e3SJoseph Koshy 	}
2008ebccf1e3SJoseph Koshy 
2009ebccf1e3SJoseph Koshy 	/* Pentium M PMCs have a few events with different semantics */
2010ebccf1e3SJoseph Koshy 	if (cpu_info.pm_cputype == PMC_CPU_INTEL_PM) {
2011ebccf1e3SJoseph Koshy 		if (pe == PMC_EV_P6_L2_LD ||
2012ebccf1e3SJoseph Koshy 		    pe == PMC_EV_P6_L2_LINES_IN ||
2013ebccf1e3SJoseph Koshy 		    pe == PMC_EV_P6_L2_LINES_OUT)
2014ebccf1e3SJoseph Koshy 			P6MASKSET(mesihw);
2015ebccf1e3SJoseph Koshy 		else if (pe == PMC_EV_P6_L2_M_LINES_OUTM)
2016ebccf1e3SJoseph Koshy 			P6MASKSET(hw);
2017ebccf1e3SJoseph Koshy 	}
2018ebccf1e3SJoseph Koshy 
2019ebccf1e3SJoseph Koshy 	/* Parse additional modifiers if present */
2020ebccf1e3SJoseph Koshy 	while ((p = strsep(&ctrspec, ",")) != NULL) {
2021ebccf1e3SJoseph Koshy 		if (KWPREFIXMATCH(p, P6_KW_CMASK "=")) {
2022ebccf1e3SJoseph Koshy 			q = strchr(p, '=');
2023ebccf1e3SJoseph Koshy 			if (*++q == '\0') /* skip '=' */
2024aa342b1fSJoseph Koshy 				return (-1);
2025ebccf1e3SJoseph Koshy 			count = strtol(q, &e, 0);
2026ebccf1e3SJoseph Koshy 			if (e == q || *e != '\0')
2027aa342b1fSJoseph Koshy 				return (-1);
2028ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_THRESHOLD;
2029f263522aSJoseph Koshy 			pmc_config->pm_md.pm_ppro.pm_ppro_config |=
2030f263522aSJoseph Koshy 			    P6_EVSEL_TO_CMASK(count);
2031ebccf1e3SJoseph Koshy 		} else if (KWMATCH(p, P6_KW_EDGE)) {
2032ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_EDGE;
2033ebccf1e3SJoseph Koshy 		} else if (KWMATCH(p, P6_KW_INV)) {
2034ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_INVERT;
2035ebccf1e3SJoseph Koshy 		} else if (KWMATCH(p, P6_KW_OS)) {
2036ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_SYSTEM;
2037ebccf1e3SJoseph Koshy 		} else if (KWPREFIXMATCH(p, P6_KW_UMASK "=")) {
2038ebccf1e3SJoseph Koshy 			evmask = 0;
2039ebccf1e3SJoseph Koshy 			if ((n = pmc_parse_mask(pmask, p, &evmask)) < 0)
2040aa342b1fSJoseph Koshy 				return (-1);
2041ebccf1e3SJoseph Koshy 			if ((pe == PMC_EV_P6_BUS_DRDY_CLOCKS ||
2042ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_BUS_LOCK_CLOCKS ||
2043ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_BUS_TRAN_BRD ||
2044ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_BUS_TRAN_RFO ||
2045ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_BUS_TRAN_IFETCH ||
2046ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_BUS_TRAN_INVAL ||
2047ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_BUS_TRAN_PWR ||
2048ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_BUS_TRAN_DEF ||
2049ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_BUS_TRAN_BURST ||
2050ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_BUS_TRAN_ANY ||
2051ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_BUS_TRAN_MEM ||
2052ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_BUS_TRANS_IO ||
2053ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_BUS_TRANS_P ||
2054ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_BUS_TRANS_WB ||
2055ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_EMON_EST_TRANS ||
2056ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_EMON_FUSED_UOPS_RET ||
2057ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_EMON_KNI_COMP_INST_RET ||
2058ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_EMON_KNI_INST_RETIRED ||
2059ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_EMON_KNI_PREF_DISPATCHED ||
2060ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_EMON_KNI_PREF_MISS ||
2061ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_EMON_SSE_SSE2_COMP_INST_RETIRED ||
2062ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_EMON_SSE_SSE2_INST_RETIRED ||
2063ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_FP_MMX_TRANS)
2064aa342b1fSJoseph Koshy 			    && (n > 1))	/* Only one mask keyword is allowed. */
2065aa342b1fSJoseph Koshy 				return (-1);
2066ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_QUALIFIER;
2067ebccf1e3SJoseph Koshy 		} else if (KWMATCH(p, P6_KW_USR)) {
2068ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_USER;
2069ebccf1e3SJoseph Koshy 		} else
2070aa342b1fSJoseph Koshy 			return (-1);
2071ebccf1e3SJoseph Koshy 	}
2072ebccf1e3SJoseph Koshy 
2073ebccf1e3SJoseph Koshy 	/* post processing */
2074ebccf1e3SJoseph Koshy 	switch (pe) {
2075ebccf1e3SJoseph Koshy 
2076ebccf1e3SJoseph Koshy 		/*
2077ebccf1e3SJoseph Koshy 		 * The following events default to an evmask of 0
2078ebccf1e3SJoseph Koshy 		 */
2079ebccf1e3SJoseph Koshy 
2080ebccf1e3SJoseph Koshy 		/* default => 'self' */
2081ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_DRDY_CLOCKS:
2082ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_LOCK_CLOCKS:
2083ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_BRD:
2084ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_RFO:
2085ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRANS_WB:
2086ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_IFETCH:
2087ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_INVAL:
2088ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_PWR:
2089ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRANS_P:
2090ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRANS_IO:
2091ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_DEF:
2092ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_BURST:
2093ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_ANY:
2094ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_MEM:
2095ebccf1e3SJoseph Koshy 
2096ebccf1e3SJoseph Koshy 		/* default => 'nta' */
2097ebccf1e3SJoseph Koshy 	case PMC_EV_P6_EMON_KNI_PREF_DISPATCHED:
2098ebccf1e3SJoseph Koshy 	case PMC_EV_P6_EMON_KNI_PREF_MISS:
2099ebccf1e3SJoseph Koshy 
2100ebccf1e3SJoseph Koshy 		/* default => 'packed and scalar' */
2101ebccf1e3SJoseph Koshy 	case PMC_EV_P6_EMON_KNI_INST_RETIRED:
2102ebccf1e3SJoseph Koshy 	case PMC_EV_P6_EMON_KNI_COMP_INST_RET:
2103ebccf1e3SJoseph Koshy 
2104ebccf1e3SJoseph Koshy 		/* default => 'mmx to fp transitions' */
2105ebccf1e3SJoseph Koshy 	case PMC_EV_P6_FP_MMX_TRANS:
2106ebccf1e3SJoseph Koshy 
2107ebccf1e3SJoseph Koshy 		/* default => 'SSE Packed Single' */
2108ebccf1e3SJoseph Koshy 	case PMC_EV_P6_EMON_SSE_SSE2_INST_RETIRED:
2109ebccf1e3SJoseph Koshy 	case PMC_EV_P6_EMON_SSE_SSE2_COMP_INST_RETIRED:
2110ebccf1e3SJoseph Koshy 
2111ebccf1e3SJoseph Koshy 		/* default => 'all fused micro-ops' */
2112ebccf1e3SJoseph Koshy 	case PMC_EV_P6_EMON_FUSED_UOPS_RET:
2113ebccf1e3SJoseph Koshy 
2114ebccf1e3SJoseph Koshy 		/* default => 'all transitions' */
2115ebccf1e3SJoseph Koshy 	case PMC_EV_P6_EMON_EST_TRANS:
2116ebccf1e3SJoseph Koshy 		break;
2117ebccf1e3SJoseph Koshy 
2118ebccf1e3SJoseph Koshy 	case PMC_EV_P6_MMX_UOPS_EXEC:
2119ebccf1e3SJoseph Koshy 		evmask = 0x0F;		/* only value allowed */
2120ebccf1e3SJoseph Koshy 		break;
2121ebccf1e3SJoseph Koshy 
2122ebccf1e3SJoseph Koshy 	default:
2123ebccf1e3SJoseph Koshy 		/*
2124ebccf1e3SJoseph Koshy 		 * For all other events, set the default event mask
2125ebccf1e3SJoseph Koshy 		 * to a logical OR of all the allowed event mask bits.
2126ebccf1e3SJoseph Koshy 		 */
2127ebccf1e3SJoseph Koshy 		if (evmask == 0 && pmask) {
2128ebccf1e3SJoseph Koshy 			for (pm = pmask; pm->pm_name; pm++)
2129ebccf1e3SJoseph Koshy 				evmask |= pm->pm_value;
2130ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_QUALIFIER;
2131ebccf1e3SJoseph Koshy 		}
2132ebccf1e3SJoseph Koshy 
2133ebccf1e3SJoseph Koshy 		break;
2134ebccf1e3SJoseph Koshy 	}
2135ebccf1e3SJoseph Koshy 
2136ebccf1e3SJoseph Koshy 	if (pmc_config->pm_caps & PMC_CAP_QUALIFIER)
2137f263522aSJoseph Koshy 		pmc_config->pm_md.pm_ppro.pm_ppro_config |=
2138f263522aSJoseph Koshy 		    P6_EVSEL_TO_UMASK(evmask);
2139ebccf1e3SJoseph Koshy 
2140aa342b1fSJoseph Koshy 	return (0);
2141ebccf1e3SJoseph Koshy }
2142ebccf1e3SJoseph Koshy 
2143ebccf1e3SJoseph Koshy #endif
2144ebccf1e3SJoseph Koshy 
2145789140c0SJoseph Koshy #if	defined(__i386__) || defined(__amd64__)
2146789140c0SJoseph Koshy static int
2147789140c0SJoseph Koshy tsc_allocate_pmc(enum pmc_event pe, char *ctrspec,
2148789140c0SJoseph Koshy     struct pmc_op_pmcallocate *pmc_config)
2149789140c0SJoseph Koshy {
2150789140c0SJoseph Koshy 	if (pe != PMC_EV_TSC_TSC)
2151789140c0SJoseph Koshy 		return (-1);
2152789140c0SJoseph Koshy 
2153789140c0SJoseph Koshy 	/* TSC events must be unqualified. */
2154789140c0SJoseph Koshy 	if (ctrspec && *ctrspec != '\0')
2155789140c0SJoseph Koshy 		return (-1);
2156789140c0SJoseph Koshy 
2157789140c0SJoseph Koshy 	pmc_config->pm_md.pm_amd.pm_amd_config = 0;
2158789140c0SJoseph Koshy 	pmc_config->pm_caps |= PMC_CAP_READ;
2159789140c0SJoseph Koshy 
2160789140c0SJoseph Koshy 	return (0);
2161789140c0SJoseph Koshy }
2162789140c0SJoseph Koshy #endif
2163789140c0SJoseph Koshy 
21640ce207d2SRui Paulo #if	defined(__XSCALE__)
21650ce207d2SRui Paulo 
21660ce207d2SRui Paulo static struct pmc_event_alias xscale_aliases[] = {
21670ce207d2SRui Paulo 	EV_ALIAS("branches",		"BRANCH_RETIRED"),
21680ce207d2SRui Paulo 	EV_ALIAS("branch-mispredicts",	"BRANCH_MISPRED"),
21690ce207d2SRui Paulo 	EV_ALIAS("dc-misses",		"DC_MISS"),
21700ce207d2SRui Paulo 	EV_ALIAS("ic-misses",		"IC_MISS"),
21710ce207d2SRui Paulo 	EV_ALIAS("instructions",	"INSTR_RETIRED"),
21720ce207d2SRui Paulo 	EV_ALIAS(NULL, NULL)
21730ce207d2SRui Paulo };
21740ce207d2SRui Paulo static int
21750ce207d2SRui Paulo xscale_allocate_pmc(enum pmc_event pe, char *ctrspec __unused,
21760ce207d2SRui Paulo     struct pmc_op_pmcallocate *pmc_config __unused)
21770ce207d2SRui Paulo {
21780ce207d2SRui Paulo 	switch (pe) {
21790ce207d2SRui Paulo 	default:
21800ce207d2SRui Paulo 		break;
21810ce207d2SRui Paulo 	}
21820ce207d2SRui Paulo 
21830ce207d2SRui Paulo 	return (0);
21840ce207d2SRui Paulo }
21850ce207d2SRui Paulo #endif
21860ce207d2SRui Paulo 
2187660df75eSGeorge V. Neville-Neil #if defined(__mips__)
2188660df75eSGeorge V. Neville-Neil 
2189660df75eSGeorge V. Neville-Neil static struct pmc_event_alias mips24k_aliases[] = {
2190660df75eSGeorge V. Neville-Neil 	EV_ALIAS("instructions",	"INSTR_EXECUTED"),
2191660df75eSGeorge V. Neville-Neil 	EV_ALIAS("branches",		"BRANCH_COMPLETED"),
2192660df75eSGeorge V. Neville-Neil 	EV_ALIAS("branch-mispredicts",	"BRANCH_MISPRED"),
2193660df75eSGeorge V. Neville-Neil 	EV_ALIAS(NULL, NULL)
2194660df75eSGeorge V. Neville-Neil };
2195660df75eSGeorge V. Neville-Neil 
2196660df75eSGeorge V. Neville-Neil #define	MIPS24K_KW_OS		"os"
2197660df75eSGeorge V. Neville-Neil #define	MIPS24K_KW_USR		"usr"
2198660df75eSGeorge V. Neville-Neil #define	MIPS24K_KW_ANYTHREAD	"anythread"
2199660df75eSGeorge V. Neville-Neil 
2200660df75eSGeorge V. Neville-Neil static int
2201660df75eSGeorge V. Neville-Neil mips24k_allocate_pmc(enum pmc_event pe, char *ctrspec __unused,
2202660df75eSGeorge V. Neville-Neil 		  struct pmc_op_pmcallocate *pmc_config __unused)
2203660df75eSGeorge V. Neville-Neil {
2204660df75eSGeorge V. Neville-Neil 	char *p;
2205660df75eSGeorge V. Neville-Neil 
2206660df75eSGeorge V. Neville-Neil 	(void) pe;
2207660df75eSGeorge V. Neville-Neil 
2208660df75eSGeorge V. Neville-Neil 	pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE);
2209660df75eSGeorge V. Neville-Neil 
2210660df75eSGeorge V. Neville-Neil 	while ((p = strsep(&ctrspec, ",")) != NULL) {
2211660df75eSGeorge V. Neville-Neil 		if (KWMATCH(p, MIPS24K_KW_OS))
2212660df75eSGeorge V. Neville-Neil 			pmc_config->pm_caps |= PMC_CAP_SYSTEM;
2213660df75eSGeorge V. Neville-Neil 		else if (KWMATCH(p, MIPS24K_KW_USR))
2214660df75eSGeorge V. Neville-Neil 			pmc_config->pm_caps |= PMC_CAP_USER;
2215660df75eSGeorge V. Neville-Neil 		else if (KWMATCH(p, MIPS24K_KW_ANYTHREAD))
2216660df75eSGeorge V. Neville-Neil 			pmc_config->pm_caps |= (PMC_CAP_USER | PMC_CAP_SYSTEM);
2217660df75eSGeorge V. Neville-Neil 		else
2218660df75eSGeorge V. Neville-Neil 			return (-1);
2219660df75eSGeorge V. Neville-Neil 	}
2220660df75eSGeorge V. Neville-Neil 
2221660df75eSGeorge V. Neville-Neil 	return (0);
2222660df75eSGeorge V. Neville-Neil }
2223660df75eSGeorge V. Neville-Neil #endif /* __mips__ */
2224660df75eSGeorge V. Neville-Neil 
2225*7b25dccaSJustin Hibbits #if defined(__powerpc__)
2226*7b25dccaSJustin Hibbits 
2227*7b25dccaSJustin Hibbits static struct pmc_event_alias ppc7450_aliases[] = {
2228*7b25dccaSJustin Hibbits 	EV_ALIAS("instructions",	"INSTR_COMPLETED"),
2229*7b25dccaSJustin Hibbits 	EV_ALIAS("branches",		"BRANCHES_COMPLETED"),
2230*7b25dccaSJustin Hibbits 	EV_ALIAS("branch-mispredicts",	"MISPREDICTED_BRANCHES"),
2231*7b25dccaSJustin Hibbits 	EV_ALIAS(NULL, NULL)
2232*7b25dccaSJustin Hibbits };
2233*7b25dccaSJustin Hibbits 
2234*7b25dccaSJustin Hibbits #define	PPC7450_KW_OS		"os"
2235*7b25dccaSJustin Hibbits #define	PPC7450_KW_USR		"usr"
2236*7b25dccaSJustin Hibbits #define	PPC7450_KW_ANYTHREAD	"anythread"
2237*7b25dccaSJustin Hibbits 
2238*7b25dccaSJustin Hibbits static int
2239*7b25dccaSJustin Hibbits ppc7450_allocate_pmc(enum pmc_event pe, char *ctrspec __unused,
2240*7b25dccaSJustin Hibbits 		  struct pmc_op_pmcallocate *pmc_config __unused)
2241*7b25dccaSJustin Hibbits {
2242*7b25dccaSJustin Hibbits 	char *p;
2243*7b25dccaSJustin Hibbits 
2244*7b25dccaSJustin Hibbits 	(void) pe;
2245*7b25dccaSJustin Hibbits 
2246*7b25dccaSJustin Hibbits 	pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE);
2247*7b25dccaSJustin Hibbits 
2248*7b25dccaSJustin Hibbits 	while ((p = strsep(&ctrspec, ",")) != NULL) {
2249*7b25dccaSJustin Hibbits 		if (KWMATCH(p, PPC7450_KW_OS))
2250*7b25dccaSJustin Hibbits 			pmc_config->pm_caps |= PMC_CAP_SYSTEM;
2251*7b25dccaSJustin Hibbits 		else if (KWMATCH(p, PPC7450_KW_USR))
2252*7b25dccaSJustin Hibbits 			pmc_config->pm_caps |= PMC_CAP_USER;
2253*7b25dccaSJustin Hibbits 		else if (KWMATCH(p, PPC7450_KW_ANYTHREAD))
2254*7b25dccaSJustin Hibbits 			pmc_config->pm_caps |= (PMC_CAP_USER | PMC_CAP_SYSTEM);
2255*7b25dccaSJustin Hibbits 		else
2256*7b25dccaSJustin Hibbits 			return (-1);
2257*7b25dccaSJustin Hibbits 	}
2258*7b25dccaSJustin Hibbits 
2259*7b25dccaSJustin Hibbits 	return (0);
2260*7b25dccaSJustin Hibbits }
2261*7b25dccaSJustin Hibbits #endif /* __powerpc__ */
2262*7b25dccaSJustin Hibbits 
2263660df75eSGeorge V. Neville-Neil 
2264789140c0SJoseph Koshy /*
2265789140c0SJoseph Koshy  * Match an event name `name' with its canonical form.
2266789140c0SJoseph Koshy  *
22670cfab8ddSJoseph Koshy  * Matches are case insensitive and spaces, periods, underscores and
22680cfab8ddSJoseph Koshy  * hyphen characters are considered to match each other.
2269789140c0SJoseph Koshy  *
2270789140c0SJoseph Koshy  * Returns 1 for a match, 0 otherwise.
2271789140c0SJoseph Koshy  */
2272789140c0SJoseph Koshy 
2273789140c0SJoseph Koshy static int
2274789140c0SJoseph Koshy pmc_match_event_name(const char *name, const char *canonicalname)
2275789140c0SJoseph Koshy {
2276789140c0SJoseph Koshy 	int cc, nc;
2277789140c0SJoseph Koshy 	const unsigned char *c, *n;
2278789140c0SJoseph Koshy 
2279789140c0SJoseph Koshy 	c = (const unsigned char *) canonicalname;
2280789140c0SJoseph Koshy 	n = (const unsigned char *) name;
2281789140c0SJoseph Koshy 
2282789140c0SJoseph Koshy 	for (; (nc = *n) && (cc = *c); n++, c++) {
2283789140c0SJoseph Koshy 
22840cfab8ddSJoseph Koshy 		if ((nc == ' ' || nc == '_' || nc == '-' || nc == '.') &&
22850cfab8ddSJoseph Koshy 		    (cc == ' ' || cc == '_' || cc == '-' || cc == '.'))
2286789140c0SJoseph Koshy 			continue;
2287789140c0SJoseph Koshy 
22880cfab8ddSJoseph Koshy 		if (toupper(nc) == toupper(cc))
2289789140c0SJoseph Koshy 			continue;
2290789140c0SJoseph Koshy 
22910cfab8ddSJoseph Koshy 
2292789140c0SJoseph Koshy 		return (0);
2293789140c0SJoseph Koshy 	}
2294789140c0SJoseph Koshy 
2295789140c0SJoseph Koshy 	if (*n == '\0' && *c == '\0')
2296789140c0SJoseph Koshy 		return (1);
2297789140c0SJoseph Koshy 
2298789140c0SJoseph Koshy 	return (0);
2299789140c0SJoseph Koshy }
2300789140c0SJoseph Koshy 
2301789140c0SJoseph Koshy /*
2302789140c0SJoseph Koshy  * Match an event name against all the event named supported by a
2303789140c0SJoseph Koshy  * PMC class.
2304789140c0SJoseph Koshy  *
2305789140c0SJoseph Koshy  * Returns an event descriptor pointer on match or NULL otherwise.
2306789140c0SJoseph Koshy  */
2307789140c0SJoseph Koshy static const struct pmc_event_descr *
2308789140c0SJoseph Koshy pmc_match_event_class(const char *name,
2309789140c0SJoseph Koshy     const struct pmc_class_descr *pcd)
2310789140c0SJoseph Koshy {
2311789140c0SJoseph Koshy 	size_t n;
2312789140c0SJoseph Koshy 	const struct pmc_event_descr *ev;
2313789140c0SJoseph Koshy 
2314789140c0SJoseph Koshy 	ev = pcd->pm_evc_event_table;
2315789140c0SJoseph Koshy 	for (n = 0; n < pcd->pm_evc_event_table_size; n++, ev++)
2316789140c0SJoseph Koshy 		if (pmc_match_event_name(name, ev->pm_ev_name))
2317789140c0SJoseph Koshy 			return (ev);
2318789140c0SJoseph Koshy 
2319789140c0SJoseph Koshy 	return (NULL);
2320789140c0SJoseph Koshy }
2321789140c0SJoseph Koshy 
2322789140c0SJoseph Koshy static int
2323789140c0SJoseph Koshy pmc_mdep_is_compatible_class(enum pmc_class pc)
2324789140c0SJoseph Koshy {
2325789140c0SJoseph Koshy 	size_t n;
2326789140c0SJoseph Koshy 
2327789140c0SJoseph Koshy 	for (n = 0; n < pmc_mdep_class_list_size; n++)
2328789140c0SJoseph Koshy 		if (pmc_mdep_class_list[n] == pc)
2329789140c0SJoseph Koshy 			return (1);
2330789140c0SJoseph Koshy 	return (0);
2331789140c0SJoseph Koshy }
2332789140c0SJoseph Koshy 
2333ebccf1e3SJoseph Koshy /*
2334ebccf1e3SJoseph Koshy  * API entry points
2335ebccf1e3SJoseph Koshy  */
2336ebccf1e3SJoseph Koshy 
2337ebccf1e3SJoseph Koshy int
2338ebccf1e3SJoseph Koshy pmc_allocate(const char *ctrspec, enum pmc_mode mode,
2339ebccf1e3SJoseph Koshy     uint32_t flags, int cpu, pmc_id_t *pmcid)
2340ebccf1e3SJoseph Koshy {
2341789140c0SJoseph Koshy 	size_t n;
2342ebccf1e3SJoseph Koshy 	int retval;
2343ebccf1e3SJoseph Koshy 	char *r, *spec_copy;
2344ebccf1e3SJoseph Koshy 	const char *ctrname;
2345789140c0SJoseph Koshy 	const struct pmc_event_descr *ev;
2346789140c0SJoseph Koshy 	const struct pmc_event_alias *alias;
2347ebccf1e3SJoseph Koshy 	struct pmc_op_pmcallocate pmc_config;
2348789140c0SJoseph Koshy 	const struct pmc_class_descr *pcd;
2349ebccf1e3SJoseph Koshy 
2350ebccf1e3SJoseph Koshy 	spec_copy = NULL;
2351ebccf1e3SJoseph Koshy 	retval    = -1;
2352ebccf1e3SJoseph Koshy 
2353ebccf1e3SJoseph Koshy 	if (mode != PMC_MODE_SS && mode != PMC_MODE_TS &&
2354ebccf1e3SJoseph Koshy 	    mode != PMC_MODE_SC && mode != PMC_MODE_TC) {
2355ebccf1e3SJoseph Koshy 		errno = EINVAL;
2356ebccf1e3SJoseph Koshy 		goto out;
2357ebccf1e3SJoseph Koshy 	}
2358ebccf1e3SJoseph Koshy 
2359ebccf1e3SJoseph Koshy 	/* replace an event alias with the canonical event specifier */
2360ebccf1e3SJoseph Koshy 	if (pmc_mdep_event_aliases)
2361789140c0SJoseph Koshy 		for (alias = pmc_mdep_event_aliases; alias->pm_alias; alias++)
2362789140c0SJoseph Koshy 			if (!strcasecmp(ctrspec, alias->pm_alias)) {
2363789140c0SJoseph Koshy 				spec_copy = strdup(alias->pm_spec);
2364ebccf1e3SJoseph Koshy 				break;
2365ebccf1e3SJoseph Koshy 			}
2366ebccf1e3SJoseph Koshy 
2367ebccf1e3SJoseph Koshy 	if (spec_copy == NULL)
2368ebccf1e3SJoseph Koshy 		spec_copy = strdup(ctrspec);
2369ebccf1e3SJoseph Koshy 
2370ebccf1e3SJoseph Koshy 	r = spec_copy;
2371ebccf1e3SJoseph Koshy 	ctrname = strsep(&r, ",");
2372ebccf1e3SJoseph Koshy 
2373789140c0SJoseph Koshy 	/*
2374789140c0SJoseph Koshy 	 * If a explicit class prefix was given by the user, restrict the
2375789140c0SJoseph Koshy 	 * search for the event to the specified PMC class.
2376789140c0SJoseph Koshy 	 */
2377789140c0SJoseph Koshy 	ev = NULL;
23780cfab8ddSJoseph Koshy 	for (n = 0; n < PMC_CLASS_TABLE_SIZE; n++) {
23790cfab8ddSJoseph Koshy 		pcd = pmc_class_table[n];
2380789140c0SJoseph Koshy 		if (pmc_mdep_is_compatible_class(pcd->pm_evc_class) &&
2381789140c0SJoseph Koshy 		    strncasecmp(ctrname, pcd->pm_evc_name,
2382789140c0SJoseph Koshy 				pcd->pm_evc_name_size) == 0) {
2383789140c0SJoseph Koshy 			if ((ev = pmc_match_event_class(ctrname +
2384789140c0SJoseph Koshy 			    pcd->pm_evc_name_size, pcd)) == NULL) {
2385789140c0SJoseph Koshy 				errno = EINVAL;
2386789140c0SJoseph Koshy 				goto out;
2387789140c0SJoseph Koshy 			}
2388ebccf1e3SJoseph Koshy 			break;
2389789140c0SJoseph Koshy 		}
2390789140c0SJoseph Koshy 	}
2391ebccf1e3SJoseph Koshy 
2392789140c0SJoseph Koshy 	/*
2393789140c0SJoseph Koshy 	 * Otherwise, search for this event in all compatible PMC
2394789140c0SJoseph Koshy 	 * classes.
2395789140c0SJoseph Koshy 	 */
23960cfab8ddSJoseph Koshy 	for (n = 0; ev == NULL && n < PMC_CLASS_TABLE_SIZE; n++) {
23970cfab8ddSJoseph Koshy 		pcd = pmc_class_table[n];
2398789140c0SJoseph Koshy 		if (pmc_mdep_is_compatible_class(pcd->pm_evc_class))
2399789140c0SJoseph Koshy 			ev = pmc_match_event_class(ctrname, pcd);
2400789140c0SJoseph Koshy 	}
2401789140c0SJoseph Koshy 
2402789140c0SJoseph Koshy 	if (ev == NULL) {
2403ebccf1e3SJoseph Koshy 		errno = EINVAL;
2404ebccf1e3SJoseph Koshy 		goto out;
2405ebccf1e3SJoseph Koshy 	}
2406ebccf1e3SJoseph Koshy 
2407ebccf1e3SJoseph Koshy 	bzero(&pmc_config, sizeof(pmc_config));
2408789140c0SJoseph Koshy 	pmc_config.pm_ev    = ev->pm_ev_code;
2409789140c0SJoseph Koshy 	pmc_config.pm_class = pcd->pm_evc_class;
2410ebccf1e3SJoseph Koshy 	pmc_config.pm_cpu   = cpu;
2411ebccf1e3SJoseph Koshy 	pmc_config.pm_mode  = mode;
2412ebccf1e3SJoseph Koshy 	pmc_config.pm_flags = flags;
2413ebccf1e3SJoseph Koshy 
2414ebccf1e3SJoseph Koshy 	if (PMC_IS_SAMPLING_MODE(mode))
2415ebccf1e3SJoseph Koshy 		pmc_config.pm_caps |= PMC_CAP_INTERRUPT;
2416ebccf1e3SJoseph Koshy 
2417789140c0SJoseph Koshy  	if (pcd->pm_evc_allocate_pmc(ev->pm_ev_code, r, &pmc_config) < 0) {
2418ebccf1e3SJoseph Koshy 		errno = EINVAL;
2419ebccf1e3SJoseph Koshy 		goto out;
2420ebccf1e3SJoseph Koshy 	}
2421ebccf1e3SJoseph Koshy 
2422ebccf1e3SJoseph Koshy 	if (PMC_CALL(PMCALLOCATE, &pmc_config) < 0)
2423ebccf1e3SJoseph Koshy 		goto out;
2424ebccf1e3SJoseph Koshy 
2425ebccf1e3SJoseph Koshy 	*pmcid = pmc_config.pm_pmcid;
2426ebccf1e3SJoseph Koshy 
2427ebccf1e3SJoseph Koshy 	retval = 0;
2428ebccf1e3SJoseph Koshy 
2429ebccf1e3SJoseph Koshy  out:
2430ebccf1e3SJoseph Koshy 	if (spec_copy)
2431ebccf1e3SJoseph Koshy 		free(spec_copy);
2432ebccf1e3SJoseph Koshy 
2433aa342b1fSJoseph Koshy 	return (retval);
2434ebccf1e3SJoseph Koshy }
2435ebccf1e3SJoseph Koshy 
2436ebccf1e3SJoseph Koshy int
2437ebccf1e3SJoseph Koshy pmc_attach(pmc_id_t pmc, pid_t pid)
2438ebccf1e3SJoseph Koshy {
2439ebccf1e3SJoseph Koshy 	struct pmc_op_pmcattach pmc_attach_args;
2440ebccf1e3SJoseph Koshy 
2441ebccf1e3SJoseph Koshy 	pmc_attach_args.pm_pmc = pmc;
2442ebccf1e3SJoseph Koshy 	pmc_attach_args.pm_pid = pid;
2443ebccf1e3SJoseph Koshy 
2444aa342b1fSJoseph Koshy 	return (PMC_CALL(PMCATTACH, &pmc_attach_args));
2445ebccf1e3SJoseph Koshy }
2446ebccf1e3SJoseph Koshy 
2447ebccf1e3SJoseph Koshy int
2448c5153e19SJoseph Koshy pmc_capabilities(pmc_id_t pmcid, uint32_t *caps)
2449c5153e19SJoseph Koshy {
2450c5153e19SJoseph Koshy 	unsigned int i;
2451c5153e19SJoseph Koshy 	enum pmc_class cl;
2452c5153e19SJoseph Koshy 
2453c5153e19SJoseph Koshy 	cl = PMC_ID_TO_CLASS(pmcid);
2454c5153e19SJoseph Koshy 	for (i = 0; i < cpu_info.pm_nclass; i++)
2455c5153e19SJoseph Koshy 		if (cpu_info.pm_classes[i].pm_class == cl) {
2456c5153e19SJoseph Koshy 			*caps = cpu_info.pm_classes[i].pm_caps;
2457aa342b1fSJoseph Koshy 			return (0);
2458c5153e19SJoseph Koshy 		}
2459484202faSJoseph Koshy 	errno = EINVAL;
2460484202faSJoseph Koshy 	return (-1);
2461c5153e19SJoseph Koshy }
2462c5153e19SJoseph Koshy 
2463f263522aSJoseph Koshy int
2464f263522aSJoseph Koshy pmc_configure_logfile(int fd)
2465ebccf1e3SJoseph Koshy {
2466f263522aSJoseph Koshy 	struct pmc_op_configurelog cla;
2467f263522aSJoseph Koshy 
2468f263522aSJoseph Koshy 	cla.pm_logfd = fd;
2469f263522aSJoseph Koshy 	if (PMC_CALL(CONFIGURELOG, &cla) < 0)
2470aa342b1fSJoseph Koshy 		return (-1);
2471aa342b1fSJoseph Koshy 	return (0);
2472ebccf1e3SJoseph Koshy }
2473ebccf1e3SJoseph Koshy 
2474f263522aSJoseph Koshy int
2475f263522aSJoseph Koshy pmc_cpuinfo(const struct pmc_cpuinfo **pci)
2476ebccf1e3SJoseph Koshy {
2477f263522aSJoseph Koshy 	if (pmc_syscall == -1) {
2478f263522aSJoseph Koshy 		errno = ENXIO;
2479aa342b1fSJoseph Koshy 		return (-1);
2480ebccf1e3SJoseph Koshy 	}
2481ebccf1e3SJoseph Koshy 
24821455fcd3SJoseph Koshy 	*pci = &cpu_info;
2483aa342b1fSJoseph Koshy 	return (0);
2484ebccf1e3SJoseph Koshy }
2485ebccf1e3SJoseph Koshy 
2486f263522aSJoseph Koshy int
2487f263522aSJoseph Koshy pmc_detach(pmc_id_t pmc, pid_t pid)
2488ebccf1e3SJoseph Koshy {
2489f263522aSJoseph Koshy 	struct pmc_op_pmcattach pmc_detach_args;
2490ebccf1e3SJoseph Koshy 
2491f263522aSJoseph Koshy 	pmc_detach_args.pm_pmc = pmc;
2492f263522aSJoseph Koshy 	pmc_detach_args.pm_pid = pid;
2493aa342b1fSJoseph Koshy 	return (PMC_CALL(PMCDETACH, &pmc_detach_args));
2494ebccf1e3SJoseph Koshy }
2495ebccf1e3SJoseph Koshy 
2496f263522aSJoseph Koshy int
2497f263522aSJoseph Koshy pmc_disable(int cpu, int pmc)
2498ebccf1e3SJoseph Koshy {
2499f263522aSJoseph Koshy 	struct pmc_op_pmcadmin ssa;
2500ebccf1e3SJoseph Koshy 
2501f263522aSJoseph Koshy 	ssa.pm_cpu = cpu;
2502f263522aSJoseph Koshy 	ssa.pm_pmc = pmc;
2503f263522aSJoseph Koshy 	ssa.pm_state = PMC_STATE_DISABLED;
2504aa342b1fSJoseph Koshy 	return (PMC_CALL(PMCADMIN, &ssa));
2505ebccf1e3SJoseph Koshy }
2506ebccf1e3SJoseph Koshy 
2507f263522aSJoseph Koshy int
2508f263522aSJoseph Koshy pmc_enable(int cpu, int pmc)
2509ebccf1e3SJoseph Koshy {
2510f263522aSJoseph Koshy 	struct pmc_op_pmcadmin ssa;
2511ebccf1e3SJoseph Koshy 
2512f263522aSJoseph Koshy 	ssa.pm_cpu = cpu;
2513f263522aSJoseph Koshy 	ssa.pm_pmc = pmc;
2514f263522aSJoseph Koshy 	ssa.pm_state = PMC_STATE_FREE;
2515aa342b1fSJoseph Koshy 	return (PMC_CALL(PMCADMIN, &ssa));
2516ebccf1e3SJoseph Koshy }
2517ebccf1e3SJoseph Koshy 
2518ebccf1e3SJoseph Koshy /*
2519ebccf1e3SJoseph Koshy  * Return a list of events known to a given PMC class.  'cl' is the
2520ebccf1e3SJoseph Koshy  * PMC class identifier, 'eventnames' is the returned list of 'const
2521ebccf1e3SJoseph Koshy  * char *' pointers pointing to the names of the events. 'nevents' is
2522ebccf1e3SJoseph Koshy  * the number of event name pointers returned.
2523ebccf1e3SJoseph Koshy  *
2524ebccf1e3SJoseph Koshy  * The space for 'eventnames' is allocated using malloc(3).  The caller
2525ebccf1e3SJoseph Koshy  * is responsible for freeing this space when done.
2526ebccf1e3SJoseph Koshy  */
2527ebccf1e3SJoseph Koshy int
2528ebccf1e3SJoseph Koshy pmc_event_names_of_class(enum pmc_class cl, const char ***eventnames,
2529ebccf1e3SJoseph Koshy     int *nevents)
2530ebccf1e3SJoseph Koshy {
2531ebccf1e3SJoseph Koshy 	int count;
2532ebccf1e3SJoseph Koshy 	const char **names;
2533ebccf1e3SJoseph Koshy 	const struct pmc_event_descr *ev;
2534ebccf1e3SJoseph Koshy 
2535ebccf1e3SJoseph Koshy 	switch (cl)
2536ebccf1e3SJoseph Koshy 	{
25370cfab8ddSJoseph Koshy 	case PMC_CLASS_IAF:
25380cfab8ddSJoseph Koshy 		ev = iaf_event_table;
25390cfab8ddSJoseph Koshy 		count = PMC_EVENT_TABLE_SIZE(iaf);
25400cfab8ddSJoseph Koshy 		break;
25410cfab8ddSJoseph Koshy 	case PMC_CLASS_IAP:
25420cfab8ddSJoseph Koshy 		/*
25430cfab8ddSJoseph Koshy 		 * Return the most appropriate set of event name
25440cfab8ddSJoseph Koshy 		 * spellings for the current CPU.
25450cfab8ddSJoseph Koshy 		 */
25460cfab8ddSJoseph Koshy 		switch (cpu_info.pm_cputype) {
25470cfab8ddSJoseph Koshy 		default:
25480cfab8ddSJoseph Koshy 		case PMC_CPU_INTEL_ATOM:
25490cfab8ddSJoseph Koshy 			ev = atom_event_table;
25500cfab8ddSJoseph Koshy 			count = PMC_EVENT_TABLE_SIZE(atom);
25510cfab8ddSJoseph Koshy 			break;
25520cfab8ddSJoseph Koshy 		case PMC_CPU_INTEL_CORE:
25530cfab8ddSJoseph Koshy 			ev = core_event_table;
25540cfab8ddSJoseph Koshy 			count = PMC_EVENT_TABLE_SIZE(core);
25550cfab8ddSJoseph Koshy 			break;
25560cfab8ddSJoseph Koshy 		case PMC_CPU_INTEL_CORE2:
2557b4d091f3SJoseph Koshy 		case PMC_CPU_INTEL_CORE2EXTREME:
25580cfab8ddSJoseph Koshy 			ev = core2_event_table;
25590cfab8ddSJoseph Koshy 			count = PMC_EVENT_TABLE_SIZE(core2);
25600cfab8ddSJoseph Koshy 			break;
2561597979c4SJeff Roberson 		case PMC_CPU_INTEL_COREI7:
2562597979c4SJeff Roberson 			ev = corei7_event_table;
2563597979c4SJeff Roberson 			count = PMC_EVENT_TABLE_SIZE(corei7);
2564597979c4SJeff Roberson 			break;
25651fa7f10bSFabien Thomas 		case PMC_CPU_INTEL_WESTMERE:
25661fa7f10bSFabien Thomas 			ev = westmere_event_table;
25671fa7f10bSFabien Thomas 			count = PMC_EVENT_TABLE_SIZE(westmere);
25681fa7f10bSFabien Thomas 			break;
25691fa7f10bSFabien Thomas 		}
25701fa7f10bSFabien Thomas 		break;
25711fa7f10bSFabien Thomas 	case PMC_CLASS_UCF:
25721fa7f10bSFabien Thomas 		ev = ucf_event_table;
25731fa7f10bSFabien Thomas 		count = PMC_EVENT_TABLE_SIZE(ucf);
25741fa7f10bSFabien Thomas 		break;
25751fa7f10bSFabien Thomas 	case PMC_CLASS_UCP:
25761fa7f10bSFabien Thomas 		/*
25771fa7f10bSFabien Thomas 		 * Return the most appropriate set of event name
25781fa7f10bSFabien Thomas 		 * spellings for the current CPU.
25791fa7f10bSFabien Thomas 		 */
25801fa7f10bSFabien Thomas 		switch (cpu_info.pm_cputype) {
25811fa7f10bSFabien Thomas 		default:
25821fa7f10bSFabien Thomas 		case PMC_CPU_INTEL_COREI7:
25831fa7f10bSFabien Thomas 			ev = corei7uc_event_table;
25841fa7f10bSFabien Thomas 			count = PMC_EVENT_TABLE_SIZE(corei7uc);
25851fa7f10bSFabien Thomas 			break;
25861fa7f10bSFabien Thomas 		case PMC_CPU_INTEL_WESTMERE:
25871fa7f10bSFabien Thomas 			ev = westmereuc_event_table;
25881fa7f10bSFabien Thomas 			count = PMC_EVENT_TABLE_SIZE(westmereuc);
25891fa7f10bSFabien Thomas 			break;
25900cfab8ddSJoseph Koshy 		}
25910cfab8ddSJoseph Koshy 		break;
2592ebccf1e3SJoseph Koshy 	case PMC_CLASS_TSC:
2593789140c0SJoseph Koshy 		ev = tsc_event_table;
2594789140c0SJoseph Koshy 		count = PMC_EVENT_TABLE_SIZE(tsc);
2595ebccf1e3SJoseph Koshy 		break;
2596ebccf1e3SJoseph Koshy 	case PMC_CLASS_K7:
2597789140c0SJoseph Koshy 		ev = k7_event_table;
2598789140c0SJoseph Koshy 		count = PMC_EVENT_TABLE_SIZE(k7);
2599ebccf1e3SJoseph Koshy 		break;
2600ebccf1e3SJoseph Koshy 	case PMC_CLASS_K8:
2601789140c0SJoseph Koshy 		ev = k8_event_table;
2602789140c0SJoseph Koshy 		count = PMC_EVENT_TABLE_SIZE(k8);
2603ebccf1e3SJoseph Koshy 		break;
2604ebccf1e3SJoseph Koshy 	case PMC_CLASS_P4:
2605789140c0SJoseph Koshy 		ev = p4_event_table;
2606789140c0SJoseph Koshy 		count = PMC_EVENT_TABLE_SIZE(p4);
2607789140c0SJoseph Koshy 		break;
2608789140c0SJoseph Koshy 	case PMC_CLASS_P5:
2609789140c0SJoseph Koshy 		ev = p5_event_table;
2610789140c0SJoseph Koshy 		count = PMC_EVENT_TABLE_SIZE(p5);
2611789140c0SJoseph Koshy 		break;
2612789140c0SJoseph Koshy 	case PMC_CLASS_P6:
2613789140c0SJoseph Koshy 		ev = p6_event_table;
2614789140c0SJoseph Koshy 		count = PMC_EVENT_TABLE_SIZE(p6);
2615ebccf1e3SJoseph Koshy 		break;
26160ce207d2SRui Paulo 	case PMC_CLASS_XSCALE:
26170ce207d2SRui Paulo 		ev = xscale_event_table;
26180ce207d2SRui Paulo 		count = PMC_EVENT_TABLE_SIZE(xscale);
26190ce207d2SRui Paulo 		break;
2620660df75eSGeorge V. Neville-Neil 	case PMC_CLASS_MIPS24K:
2621660df75eSGeorge V. Neville-Neil 		ev = mips24k_event_table;
2622660df75eSGeorge V. Neville-Neil 		count = PMC_EVENT_TABLE_SIZE(mips24k);
2623660df75eSGeorge V. Neville-Neil 		break;
2624*7b25dccaSJustin Hibbits 	case PMC_CLASS_PPC7450:
2625*7b25dccaSJustin Hibbits 		ev = ppc7450_event_table;
2626*7b25dccaSJustin Hibbits 		count = PMC_EVENT_TABLE_SIZE(ppc7450);
2627*7b25dccaSJustin Hibbits 		break;
2628ebccf1e3SJoseph Koshy 	default:
2629ebccf1e3SJoseph Koshy 		errno = EINVAL;
2630aa342b1fSJoseph Koshy 		return (-1);
2631ebccf1e3SJoseph Koshy 	}
2632ebccf1e3SJoseph Koshy 
2633ebccf1e3SJoseph Koshy 	if ((names = malloc(count * sizeof(const char *))) == NULL)
2634aa342b1fSJoseph Koshy 		return (-1);
2635ebccf1e3SJoseph Koshy 
2636ebccf1e3SJoseph Koshy 	*eventnames = names;
2637ebccf1e3SJoseph Koshy 	*nevents = count;
2638ebccf1e3SJoseph Koshy 
2639ebccf1e3SJoseph Koshy 	for (;count--; ev++, names++)
2640ebccf1e3SJoseph Koshy 		*names = ev->pm_ev_name;
2641aa342b1fSJoseph Koshy 	return (0);
2642ebccf1e3SJoseph Koshy }
2643ebccf1e3SJoseph Koshy 
2644f263522aSJoseph Koshy int
2645f263522aSJoseph Koshy pmc_flush_logfile(void)
2646f263522aSJoseph Koshy {
2647aa342b1fSJoseph Koshy 	return (PMC_CALL(FLUSHLOG,0));
2648f263522aSJoseph Koshy }
2649ebccf1e3SJoseph Koshy 
2650ebccf1e3SJoseph Koshy int
2651dceed24aSFabien Thomas pmc_close_logfile(void)
2652dceed24aSFabien Thomas {
2653dceed24aSFabien Thomas 	return (PMC_CALL(CLOSELOG,0));
2654dceed24aSFabien Thomas }
2655dceed24aSFabien Thomas 
2656dceed24aSFabien Thomas int
2657f263522aSJoseph Koshy pmc_get_driver_stats(struct pmc_driverstats *ds)
2658ebccf1e3SJoseph Koshy {
2659f263522aSJoseph Koshy 	struct pmc_op_getdriverstats gms;
2660f263522aSJoseph Koshy 
2661f263522aSJoseph Koshy 	if (PMC_CALL(GETDRIVERSTATS, &gms) < 0)
2662aa342b1fSJoseph Koshy 		return (-1);
2663f263522aSJoseph Koshy 
2664f263522aSJoseph Koshy 	/* copy out fields in the current userland<->library interface */
2665f263522aSJoseph Koshy 	ds->pm_intr_ignored    = gms.pm_intr_ignored;
2666f263522aSJoseph Koshy 	ds->pm_intr_processed  = gms.pm_intr_processed;
2667f263522aSJoseph Koshy 	ds->pm_intr_bufferfull = gms.pm_intr_bufferfull;
2668f263522aSJoseph Koshy 	ds->pm_syscalls        = gms.pm_syscalls;
2669f263522aSJoseph Koshy 	ds->pm_syscall_errors  = gms.pm_syscall_errors;
2670f263522aSJoseph Koshy 	ds->pm_buffer_requests = gms.pm_buffer_requests;
2671f263522aSJoseph Koshy 	ds->pm_buffer_requests_failed = gms.pm_buffer_requests_failed;
2672f263522aSJoseph Koshy 	ds->pm_log_sweeps      = gms.pm_log_sweeps;
2673aa342b1fSJoseph Koshy 	return (0);
2674f263522aSJoseph Koshy }
2675f263522aSJoseph Koshy 
2676f263522aSJoseph Koshy int
2677f263522aSJoseph Koshy pmc_get_msr(pmc_id_t pmc, uint32_t *msr)
2678f263522aSJoseph Koshy {
2679f263522aSJoseph Koshy 	struct pmc_op_getmsr gm;
2680ebccf1e3SJoseph Koshy 
2681ebccf1e3SJoseph Koshy 	gm.pm_pmcid = pmc;
2682f263522aSJoseph Koshy 	if (PMC_CALL(PMCGETMSR, &gm) < 0)
2683aa342b1fSJoseph Koshy 		return (-1);
2684ebccf1e3SJoseph Koshy 	*msr = gm.pm_msr;
2685aa342b1fSJoseph Koshy 	return (0);
2686ebccf1e3SJoseph Koshy }
2687ebccf1e3SJoseph Koshy 
2688f263522aSJoseph Koshy int
2689f263522aSJoseph Koshy pmc_init(void)
2690f263522aSJoseph Koshy {
2691f263522aSJoseph Koshy 	int error, pmc_mod_id;
26921455fcd3SJoseph Koshy 	unsigned int n;
2693f263522aSJoseph Koshy 	uint32_t abi_version;
2694f263522aSJoseph Koshy 	struct module_stat pmc_modstat;
26951455fcd3SJoseph Koshy 	struct pmc_op_getcpuinfo op_cpu_info;
2696791f5d5bSJoseph Koshy #if defined(__amd64__) || defined(__i386__)
2697791f5d5bSJoseph Koshy 	int cpu_has_iaf_counters;
2698791f5d5bSJoseph Koshy 	unsigned int t;
2699791f5d5bSJoseph Koshy #endif
2700f263522aSJoseph Koshy 
2701f263522aSJoseph Koshy 	if (pmc_syscall != -1) /* already inited */
2702aa342b1fSJoseph Koshy 		return (0);
2703f263522aSJoseph Koshy 
2704f263522aSJoseph Koshy 	/* retrieve the system call number from the KLD */
2705f263522aSJoseph Koshy 	if ((pmc_mod_id = modfind(PMC_MODULE_NAME)) < 0)
2706aa342b1fSJoseph Koshy 		return (-1);
2707f263522aSJoseph Koshy 
2708f263522aSJoseph Koshy 	pmc_modstat.version = sizeof(struct module_stat);
2709f263522aSJoseph Koshy 	if ((error = modstat(pmc_mod_id, &pmc_modstat)) < 0)
2710aa342b1fSJoseph Koshy 		return (-1);
2711f263522aSJoseph Koshy 
2712f263522aSJoseph Koshy 	pmc_syscall = pmc_modstat.data.intval;
2713f263522aSJoseph Koshy 
2714f263522aSJoseph Koshy 	/* check the kernel module's ABI against our compiled-in version */
2715f263522aSJoseph Koshy 	abi_version = PMC_VERSION;
2716f263522aSJoseph Koshy 	if (PMC_CALL(GETMODULEVERSION, &abi_version) < 0)
2717f263522aSJoseph Koshy 		return (pmc_syscall = -1);
2718f263522aSJoseph Koshy 
2719f263522aSJoseph Koshy 	/* ignore patch & minor numbers for the comparision */
2720f263522aSJoseph Koshy 	if ((abi_version & 0xFF000000) != (PMC_VERSION & 0xFF000000)) {
2721f263522aSJoseph Koshy 		errno  = EPROGMISMATCH;
2722f263522aSJoseph Koshy 		return (pmc_syscall = -1);
2723f263522aSJoseph Koshy 	}
2724f263522aSJoseph Koshy 
27251455fcd3SJoseph Koshy 	if (PMC_CALL(GETCPUINFO, &op_cpu_info) < 0)
2726f263522aSJoseph Koshy 		return (pmc_syscall = -1);
2727f263522aSJoseph Koshy 
27281455fcd3SJoseph Koshy 	cpu_info.pm_cputype = op_cpu_info.pm_cputype;
27291455fcd3SJoseph Koshy 	cpu_info.pm_ncpu    = op_cpu_info.pm_ncpu;
27301455fcd3SJoseph Koshy 	cpu_info.pm_npmc    = op_cpu_info.pm_npmc;
27311455fcd3SJoseph Koshy 	cpu_info.pm_nclass  = op_cpu_info.pm_nclass;
27321455fcd3SJoseph Koshy 	for (n = 0; n < cpu_info.pm_nclass; n++)
27331455fcd3SJoseph Koshy 		cpu_info.pm_classes[n] = op_cpu_info.pm_classes[n];
27341455fcd3SJoseph Koshy 
27350cfab8ddSJoseph Koshy 	pmc_class_table = malloc(PMC_CLASS_TABLE_SIZE *
27360cfab8ddSJoseph Koshy 	    sizeof(struct pmc_class_descr *));
27370cfab8ddSJoseph Koshy 
27380cfab8ddSJoseph Koshy 	if (pmc_class_table == NULL)
27390cfab8ddSJoseph Koshy 		return (-1);
27400cfab8ddSJoseph Koshy 
2741791f5d5bSJoseph Koshy 	for (n = 0; n < PMC_CLASS_TABLE_SIZE; n++)
2742791f5d5bSJoseph Koshy 		pmc_class_table[n] = NULL;
27430cfab8ddSJoseph Koshy 
27440cfab8ddSJoseph Koshy 	/*
27450cfab8ddSJoseph Koshy 	 * Fill in the class table.
27460cfab8ddSJoseph Koshy 	 */
27470cfab8ddSJoseph Koshy 	n = 0;
27480cfab8ddSJoseph Koshy #if defined(__amd64__) || defined(__i386__)
27490cfab8ddSJoseph Koshy 	pmc_class_table[n++] = &tsc_class_table_descr;
2750791f5d5bSJoseph Koshy 
2751791f5d5bSJoseph Koshy 	/*
2752791f5d5bSJoseph Koshy  	 * Check if this CPU has fixed function counters.
2753791f5d5bSJoseph Koshy 	 */
2754791f5d5bSJoseph Koshy 	cpu_has_iaf_counters = 0;
2755791f5d5bSJoseph Koshy 	for (t = 0; t < cpu_info.pm_nclass; t++)
27562aef9dd6SFabien Thomas 		if (cpu_info.pm_classes[t].pm_class == PMC_CLASS_IAF &&
27572aef9dd6SFabien Thomas 		    cpu_info.pm_classes[t].pm_num > 0)
2758791f5d5bSJoseph Koshy 			cpu_has_iaf_counters = 1;
27590cfab8ddSJoseph Koshy #endif
27600cfab8ddSJoseph Koshy 
2761789140c0SJoseph Koshy #define	PMC_MDEP_INIT(C) do {					\
2762789140c0SJoseph Koshy 		pmc_mdep_event_aliases    = C##_aliases;	\
2763789140c0SJoseph Koshy 		pmc_mdep_class_list  = C##_pmc_classes;		\
2764789140c0SJoseph Koshy 		pmc_mdep_class_list_size =			\
2765789140c0SJoseph Koshy 		    PMC_TABLE_SIZE(C##_pmc_classes);		\
2766789140c0SJoseph Koshy 	} while (0)
2767789140c0SJoseph Koshy 
2768791f5d5bSJoseph Koshy #define	PMC_MDEP_INIT_INTEL_V2(C) do {					\
2769791f5d5bSJoseph Koshy 		PMC_MDEP_INIT(C);					\
2770791f5d5bSJoseph Koshy 		pmc_class_table[n++] = &iaf_class_table_descr;		\
27712aef9dd6SFabien Thomas 		if (!cpu_has_iaf_counters) 				\
2772791f5d5bSJoseph Koshy 			pmc_mdep_event_aliases =			\
2773791f5d5bSJoseph Koshy 				C##_aliases_without_iaf;		\
2774791f5d5bSJoseph Koshy 		pmc_class_table[n] = &C##_class_table_descr;		\
2775791f5d5bSJoseph Koshy 	} while (0)
2776791f5d5bSJoseph Koshy 
2777789140c0SJoseph Koshy 	/* Configure the event name parser. */
2778f263522aSJoseph Koshy 	switch (cpu_info.pm_cputype) {
2779f263522aSJoseph Koshy #if defined(__i386__)
2780f263522aSJoseph Koshy 	case PMC_CPU_AMD_K7:
2781789140c0SJoseph Koshy 		PMC_MDEP_INIT(k7);
27820cfab8ddSJoseph Koshy 		pmc_class_table[n] = &k7_class_table_descr;
2783f263522aSJoseph Koshy 		break;
2784f263522aSJoseph Koshy 	case PMC_CPU_INTEL_P5:
2785789140c0SJoseph Koshy 		PMC_MDEP_INIT(p5);
27860cfab8ddSJoseph Koshy 		pmc_class_table[n]  = &p5_class_table_descr;
2787f263522aSJoseph Koshy 		break;
2788f263522aSJoseph Koshy 	case PMC_CPU_INTEL_P6:		/* P6 ... Pentium M CPUs have */
2789f263522aSJoseph Koshy 	case PMC_CPU_INTEL_PII:		/* similar PMCs. */
2790f263522aSJoseph Koshy 	case PMC_CPU_INTEL_PIII:
2791f263522aSJoseph Koshy 	case PMC_CPU_INTEL_PM:
2792789140c0SJoseph Koshy 		PMC_MDEP_INIT(p6);
27930cfab8ddSJoseph Koshy 		pmc_class_table[n] = &p6_class_table_descr;
2794f263522aSJoseph Koshy 		break;
279586a65549SJoseph Koshy #endif
279686a65549SJoseph Koshy #if defined(__amd64__) || defined(__i386__)
2797f263522aSJoseph Koshy 	case PMC_CPU_AMD_K8:
2798789140c0SJoseph Koshy 		PMC_MDEP_INIT(k8);
27990cfab8ddSJoseph Koshy 		pmc_class_table[n] = &k8_class_table_descr;
28000cfab8ddSJoseph Koshy 		break;
28010cfab8ddSJoseph Koshy 	case PMC_CPU_INTEL_ATOM:
2802791f5d5bSJoseph Koshy 		PMC_MDEP_INIT_INTEL_V2(atom);
28030cfab8ddSJoseph Koshy 		break;
28040cfab8ddSJoseph Koshy 	case PMC_CPU_INTEL_CORE:
28050cfab8ddSJoseph Koshy 		PMC_MDEP_INIT(core);
2806bc315bbdSJoseph Koshy 		pmc_class_table[n] = &core_class_table_descr;
28070cfab8ddSJoseph Koshy 		break;
28080cfab8ddSJoseph Koshy 	case PMC_CPU_INTEL_CORE2:
2809b4d091f3SJoseph Koshy 	case PMC_CPU_INTEL_CORE2EXTREME:
2810791f5d5bSJoseph Koshy 		PMC_MDEP_INIT_INTEL_V2(core2);
2811789140c0SJoseph Koshy 		break;
2812597979c4SJeff Roberson 	case PMC_CPU_INTEL_COREI7:
28131fa7f10bSFabien Thomas 		pmc_class_table[n++] = &ucf_class_table_descr;
28141fa7f10bSFabien Thomas 		pmc_class_table[n++] = &corei7uc_class_table_descr;
2815791f5d5bSJoseph Koshy 		PMC_MDEP_INIT_INTEL_V2(corei7);
2816597979c4SJeff Roberson 		break;
28171fa7f10bSFabien Thomas 	case PMC_CPU_INTEL_WESTMERE:
28181fa7f10bSFabien Thomas 		pmc_class_table[n++] = &ucf_class_table_descr;
28191fa7f10bSFabien Thomas 		pmc_class_table[n++] = &westmereuc_class_table_descr;
28201fa7f10bSFabien Thomas 		PMC_MDEP_INIT_INTEL_V2(westmere);
28211fa7f10bSFabien Thomas 		break;
2822789140c0SJoseph Koshy 	case PMC_CPU_INTEL_PIV:
2823789140c0SJoseph Koshy 		PMC_MDEP_INIT(p4);
28240cfab8ddSJoseph Koshy 		pmc_class_table[n] = &p4_class_table_descr;
2825f263522aSJoseph Koshy 		break;
2826ebccf1e3SJoseph Koshy #endif
28270ce207d2SRui Paulo #if defined(__XSCALE__)
28280ce207d2SRui Paulo 	case PMC_CPU_INTEL_XSCALE:
28290ce207d2SRui Paulo 		PMC_MDEP_INIT(xscale);
28300ce207d2SRui Paulo 		pmc_class_table[n] = &xscale_class_table_descr;
28310ce207d2SRui Paulo 		break;
28320ce207d2SRui Paulo #endif
2833660df75eSGeorge V. Neville-Neil #if defined(__mips__)
2834660df75eSGeorge V. Neville-Neil 	case PMC_CPU_MIPS_24K:
2835660df75eSGeorge V. Neville-Neil 		PMC_MDEP_INIT(mips24k);
2836660df75eSGeorge V. Neville-Neil 		pmc_class_table[n] = &mips24k_class_table_descr;
2837660df75eSGeorge V. Neville-Neil 		break;
2838660df75eSGeorge V. Neville-Neil #endif /* __mips__ */
2839*7b25dccaSJustin Hibbits #if defined(__powerpc__)
2840*7b25dccaSJustin Hibbits 	case PMC_CPU_PPC_7450:
2841*7b25dccaSJustin Hibbits 		PMC_MDEP_INIT(ppc7450);
2842*7b25dccaSJustin Hibbits 		pmc_class_table[n] = &ppc7450_class_table_descr;
2843*7b25dccaSJustin Hibbits 		break;
2844*7b25dccaSJustin Hibbits #endif
2845f263522aSJoseph Koshy 	default:
2846f263522aSJoseph Koshy 		/*
2847f263522aSJoseph Koshy 		 * Some kind of CPU this version of the library knows nothing
2848f263522aSJoseph Koshy 		 * about.  This shouldn't happen since the abi version check
2849f263522aSJoseph Koshy 		 * should have caught this.
2850f263522aSJoseph Koshy 		 */
2851f263522aSJoseph Koshy 		errno = ENXIO;
2852f263522aSJoseph Koshy 		return (pmc_syscall = -1);
2853f263522aSJoseph Koshy 	}
2854f263522aSJoseph Koshy 
2855aa342b1fSJoseph Koshy 	return (0);
2856f263522aSJoseph Koshy }
2857f263522aSJoseph Koshy 
2858f263522aSJoseph Koshy const char *
2859f263522aSJoseph Koshy pmc_name_of_capability(enum pmc_caps cap)
2860f263522aSJoseph Koshy {
2861f263522aSJoseph Koshy 	int i;
2862f263522aSJoseph Koshy 
2863f263522aSJoseph Koshy 	/*
2864f263522aSJoseph Koshy 	 * 'cap' should have a single bit set and should be in
2865f263522aSJoseph Koshy 	 * range.
2866f263522aSJoseph Koshy 	 */
2867f263522aSJoseph Koshy 	if ((cap & (cap - 1)) || cap < PMC_CAP_FIRST ||
2868f263522aSJoseph Koshy 	    cap > PMC_CAP_LAST) {
2869f263522aSJoseph Koshy 		errno = EINVAL;
2870aa342b1fSJoseph Koshy 		return (NULL);
2871f263522aSJoseph Koshy 	}
2872f263522aSJoseph Koshy 
2873f263522aSJoseph Koshy 	i = ffs(cap);
2874aa342b1fSJoseph Koshy 	return (pmc_capability_names[i - 1]);
2875f263522aSJoseph Koshy }
2876f263522aSJoseph Koshy 
2877f263522aSJoseph Koshy const char *
2878f263522aSJoseph Koshy pmc_name_of_class(enum pmc_class pc)
2879f263522aSJoseph Koshy {
2880f263522aSJoseph Koshy 	if ((int) pc >= PMC_CLASS_FIRST &&
2881f263522aSJoseph Koshy 	    pc <= PMC_CLASS_LAST)
2882aa342b1fSJoseph Koshy 		return (pmc_class_names[pc]);
2883f263522aSJoseph Koshy 
2884f263522aSJoseph Koshy 	errno = EINVAL;
2885aa342b1fSJoseph Koshy 	return (NULL);
2886f263522aSJoseph Koshy }
2887f263522aSJoseph Koshy 
2888f263522aSJoseph Koshy const char *
2889f263522aSJoseph Koshy pmc_name_of_cputype(enum pmc_cputype cp)
2890f263522aSJoseph Koshy {
2891789140c0SJoseph Koshy 	size_t n;
2892789140c0SJoseph Koshy 
2893789140c0SJoseph Koshy 	for (n = 0; n < PMC_TABLE_SIZE(pmc_cputype_names); n++)
2894789140c0SJoseph Koshy 		if (cp == pmc_cputype_names[n].pm_cputype)
2895789140c0SJoseph Koshy 			return (pmc_cputype_names[n].pm_name);
2896789140c0SJoseph Koshy 
2897f263522aSJoseph Koshy 	errno = EINVAL;
2898aa342b1fSJoseph Koshy 	return (NULL);
2899f263522aSJoseph Koshy }
2900f263522aSJoseph Koshy 
2901f263522aSJoseph Koshy const char *
2902f263522aSJoseph Koshy pmc_name_of_disposition(enum pmc_disp pd)
2903f263522aSJoseph Koshy {
2904f263522aSJoseph Koshy 	if ((int) pd >= PMC_DISP_FIRST &&
2905f263522aSJoseph Koshy 	    pd <= PMC_DISP_LAST)
2906aa342b1fSJoseph Koshy 		return (pmc_disposition_names[pd]);
2907f263522aSJoseph Koshy 
2908f263522aSJoseph Koshy 	errno = EINVAL;
2909aa342b1fSJoseph Koshy 	return (NULL);
2910f263522aSJoseph Koshy }
2911f263522aSJoseph Koshy 
2912f263522aSJoseph Koshy const char *
29130cfab8ddSJoseph Koshy _pmc_name_of_event(enum pmc_event pe, enum pmc_cputype cpu)
2914f263522aSJoseph Koshy {
2915789140c0SJoseph Koshy 	const struct pmc_event_descr *ev, *evfence;
2916789140c0SJoseph Koshy 
2917789140c0SJoseph Koshy 	ev = evfence = NULL;
29180cfab8ddSJoseph Koshy 	if (pe >= PMC_EV_IAF_FIRST && pe <= PMC_EV_IAF_LAST) {
29190cfab8ddSJoseph Koshy 		ev = iaf_event_table;
29200cfab8ddSJoseph Koshy 		evfence = iaf_event_table + PMC_EVENT_TABLE_SIZE(iaf);
29210cfab8ddSJoseph Koshy 	} else if (pe >= PMC_EV_IAP_FIRST && pe <= PMC_EV_IAP_LAST) {
29220cfab8ddSJoseph Koshy 		switch (cpu) {
29230cfab8ddSJoseph Koshy 		case PMC_CPU_INTEL_ATOM:
29240cfab8ddSJoseph Koshy 			ev = atom_event_table;
29250cfab8ddSJoseph Koshy 			evfence = atom_event_table + PMC_EVENT_TABLE_SIZE(atom);
29260cfab8ddSJoseph Koshy 			break;
29270cfab8ddSJoseph Koshy 		case PMC_CPU_INTEL_CORE:
29280cfab8ddSJoseph Koshy 			ev = core_event_table;
29290cfab8ddSJoseph Koshy 			evfence = core_event_table + PMC_EVENT_TABLE_SIZE(core);
29300cfab8ddSJoseph Koshy 			break;
29310cfab8ddSJoseph Koshy 		case PMC_CPU_INTEL_CORE2:
2932b4d091f3SJoseph Koshy 		case PMC_CPU_INTEL_CORE2EXTREME:
29330cfab8ddSJoseph Koshy 			ev = core2_event_table;
29340cfab8ddSJoseph Koshy 			evfence = core2_event_table + PMC_EVENT_TABLE_SIZE(core2);
29350cfab8ddSJoseph Koshy 			break;
2936597979c4SJeff Roberson 		case PMC_CPU_INTEL_COREI7:
2937597979c4SJeff Roberson 			ev = corei7_event_table;
2938597979c4SJeff Roberson 			evfence = corei7_event_table + PMC_EVENT_TABLE_SIZE(corei7);
2939597979c4SJeff Roberson 			break;
29401fa7f10bSFabien Thomas 		case PMC_CPU_INTEL_WESTMERE:
29411fa7f10bSFabien Thomas 			ev = westmere_event_table;
29421fa7f10bSFabien Thomas 			evfence = westmere_event_table + PMC_EVENT_TABLE_SIZE(westmere);
29431fa7f10bSFabien Thomas 			break;
29440cfab8ddSJoseph Koshy 		default:	/* Unknown CPU type. */
29450cfab8ddSJoseph Koshy 			break;
29460cfab8ddSJoseph Koshy 		}
29471fa7f10bSFabien Thomas 	} else if (pe >= PMC_EV_UCF_FIRST && pe <= PMC_EV_UCF_LAST) {
29481fa7f10bSFabien Thomas 		ev = ucf_event_table;
29491fa7f10bSFabien Thomas 		evfence = ucf_event_table + PMC_EVENT_TABLE_SIZE(ucf);
29501fa7f10bSFabien Thomas 	} else if (pe >= PMC_EV_UCP_FIRST && pe <= PMC_EV_UCP_LAST) {
29511fa7f10bSFabien Thomas 		switch (cpu) {
29521fa7f10bSFabien Thomas 		case PMC_CPU_INTEL_COREI7:
29531fa7f10bSFabien Thomas 			ev = corei7uc_event_table;
29541fa7f10bSFabien Thomas 			evfence = corei7uc_event_table + PMC_EVENT_TABLE_SIZE(corei7uc);
29551fa7f10bSFabien Thomas 			break;
29561fa7f10bSFabien Thomas 		case PMC_CPU_INTEL_WESTMERE:
29571fa7f10bSFabien Thomas 			ev = westmereuc_event_table;
29581fa7f10bSFabien Thomas 			evfence = westmereuc_event_table + PMC_EVENT_TABLE_SIZE(westmereuc);
29591fa7f10bSFabien Thomas 			break;
29601fa7f10bSFabien Thomas 		default:	/* Unknown CPU type. */
29611fa7f10bSFabien Thomas 			break;
29621fa7f10bSFabien Thomas 		}
29631fa7f10bSFabien Thomas 	} else if (pe >= PMC_EV_K7_FIRST && pe <= PMC_EV_K7_LAST) {
2964789140c0SJoseph Koshy 		ev = k7_event_table;
2965789140c0SJoseph Koshy 		evfence = k7_event_table + PMC_EVENT_TABLE_SIZE(k7);
2966789140c0SJoseph Koshy 	} else if (pe >= PMC_EV_K8_FIRST && pe <= PMC_EV_K8_LAST) {
2967789140c0SJoseph Koshy 		ev = k8_event_table;
2968789140c0SJoseph Koshy 		evfence = k8_event_table + PMC_EVENT_TABLE_SIZE(k8);
2969789140c0SJoseph Koshy 	} else if (pe >= PMC_EV_P4_FIRST && pe <= PMC_EV_P4_LAST) {
2970789140c0SJoseph Koshy 		ev = p4_event_table;
2971789140c0SJoseph Koshy 		evfence = p4_event_table + PMC_EVENT_TABLE_SIZE(p4);
2972789140c0SJoseph Koshy 	} else if (pe >= PMC_EV_P5_FIRST && pe <= PMC_EV_P5_LAST) {
2973789140c0SJoseph Koshy 		ev = p5_event_table;
2974789140c0SJoseph Koshy 		evfence = p5_event_table + PMC_EVENT_TABLE_SIZE(p5);
2975789140c0SJoseph Koshy 	} else if (pe >= PMC_EV_P6_FIRST && pe <= PMC_EV_P6_LAST) {
2976789140c0SJoseph Koshy 		ev = p6_event_table;
2977789140c0SJoseph Koshy 		evfence = p6_event_table + PMC_EVENT_TABLE_SIZE(p6);
29780ce207d2SRui Paulo 	} else if (pe >= PMC_EV_XSCALE_FIRST && pe <= PMC_EV_XSCALE_LAST) {
29790ce207d2SRui Paulo 		ev = xscale_event_table;
29800ce207d2SRui Paulo 		evfence = xscale_event_table + PMC_EVENT_TABLE_SIZE(xscale);
2981660df75eSGeorge V. Neville-Neil 	} else if (pe >= PMC_EV_MIPS24K_FIRST && pe <= PMC_EV_MIPS24K_LAST) {
2982660df75eSGeorge V. Neville-Neil 		ev = mips24k_event_table;
2983660df75eSGeorge V. Neville-Neil 		evfence = mips24k_event_table + PMC_EVENT_TABLE_SIZE(mips24k
2984660df75eSGeorge V. Neville-Neil );
2985*7b25dccaSJustin Hibbits 	} else if (pe >= PMC_EV_PPC7450_FIRST && pe <= PMC_EV_PPC7450_LAST) {
2986*7b25dccaSJustin Hibbits 		ev = ppc7450_event_table;
2987*7b25dccaSJustin Hibbits 		evfence = ppc7450_event_table + PMC_EVENT_TABLE_SIZE(ppc7450
2988*7b25dccaSJustin Hibbits );
2989789140c0SJoseph Koshy 	} else if (pe == PMC_EV_TSC_TSC) {
2990789140c0SJoseph Koshy 		ev = tsc_event_table;
2991789140c0SJoseph Koshy 		evfence = tsc_event_table + PMC_EVENT_TABLE_SIZE(tsc);
2992789140c0SJoseph Koshy 	}
2993789140c0SJoseph Koshy 
2994789140c0SJoseph Koshy 	for (; ev != evfence; ev++)
2995789140c0SJoseph Koshy 		if (pe == ev->pm_ev_code)
2996789140c0SJoseph Koshy 			return (ev->pm_ev_name);
2997f263522aSJoseph Koshy 
29980cfab8ddSJoseph Koshy 	return (NULL);
29990cfab8ddSJoseph Koshy }
30000cfab8ddSJoseph Koshy 
30010cfab8ddSJoseph Koshy const char *
30020cfab8ddSJoseph Koshy pmc_name_of_event(enum pmc_event pe)
30030cfab8ddSJoseph Koshy {
30040cfab8ddSJoseph Koshy 	const char *n;
30050cfab8ddSJoseph Koshy 
30060cfab8ddSJoseph Koshy 	if ((n = _pmc_name_of_event(pe, cpu_info.pm_cputype)) != NULL)
30070cfab8ddSJoseph Koshy 		return (n);
30080cfab8ddSJoseph Koshy 
3009f263522aSJoseph Koshy 	errno = EINVAL;
3010aa342b1fSJoseph Koshy 	return (NULL);
3011f263522aSJoseph Koshy }
3012f263522aSJoseph Koshy 
3013f263522aSJoseph Koshy const char *
3014f263522aSJoseph Koshy pmc_name_of_mode(enum pmc_mode pm)
3015f263522aSJoseph Koshy {
3016f263522aSJoseph Koshy 	if ((int) pm >= PMC_MODE_FIRST &&
3017f263522aSJoseph Koshy 	    pm <= PMC_MODE_LAST)
3018aa342b1fSJoseph Koshy 		return (pmc_mode_names[pm]);
3019f263522aSJoseph Koshy 
3020f263522aSJoseph Koshy 	errno = EINVAL;
3021aa342b1fSJoseph Koshy 	return (NULL);
3022f263522aSJoseph Koshy }
3023f263522aSJoseph Koshy 
3024f263522aSJoseph Koshy const char *
3025f263522aSJoseph Koshy pmc_name_of_state(enum pmc_state ps)
3026f263522aSJoseph Koshy {
3027f263522aSJoseph Koshy 	if ((int) ps >= PMC_STATE_FIRST &&
3028f263522aSJoseph Koshy 	    ps <= PMC_STATE_LAST)
3029aa342b1fSJoseph Koshy 		return (pmc_state_names[ps]);
3030f263522aSJoseph Koshy 
3031f263522aSJoseph Koshy 	errno = EINVAL;
3032aa342b1fSJoseph Koshy 	return (NULL);
3033f263522aSJoseph Koshy }
3034f263522aSJoseph Koshy 
3035f263522aSJoseph Koshy int
3036f263522aSJoseph Koshy pmc_ncpu(void)
3037f263522aSJoseph Koshy {
3038f263522aSJoseph Koshy 	if (pmc_syscall == -1) {
3039f263522aSJoseph Koshy 		errno = ENXIO;
3040aa342b1fSJoseph Koshy 		return (-1);
3041f263522aSJoseph Koshy 	}
3042f263522aSJoseph Koshy 
3043aa342b1fSJoseph Koshy 	return (cpu_info.pm_ncpu);
3044f263522aSJoseph Koshy }
3045f263522aSJoseph Koshy 
3046f263522aSJoseph Koshy int
3047f263522aSJoseph Koshy pmc_npmc(int cpu)
3048f263522aSJoseph Koshy {
3049f263522aSJoseph Koshy 	if (pmc_syscall == -1) {
3050f263522aSJoseph Koshy 		errno = ENXIO;
3051aa342b1fSJoseph Koshy 		return (-1);
3052f263522aSJoseph Koshy 	}
3053f263522aSJoseph Koshy 
3054f263522aSJoseph Koshy 	if (cpu < 0 || cpu >= (int) cpu_info.pm_ncpu) {
3055f263522aSJoseph Koshy 		errno = EINVAL;
3056aa342b1fSJoseph Koshy 		return (-1);
3057f263522aSJoseph Koshy 	}
3058f263522aSJoseph Koshy 
3059aa342b1fSJoseph Koshy 	return (cpu_info.pm_npmc);
3060f263522aSJoseph Koshy }
3061f263522aSJoseph Koshy 
3062f263522aSJoseph Koshy int
3063f263522aSJoseph Koshy pmc_pmcinfo(int cpu, struct pmc_pmcinfo **ppmci)
3064f263522aSJoseph Koshy {
3065f263522aSJoseph Koshy 	int nbytes, npmc;
3066f263522aSJoseph Koshy 	struct pmc_op_getpmcinfo *pmci;
3067f263522aSJoseph Koshy 
3068f263522aSJoseph Koshy 	if ((npmc = pmc_npmc(cpu)) < 0)
3069aa342b1fSJoseph Koshy 		return (-1);
3070f263522aSJoseph Koshy 
3071f263522aSJoseph Koshy 	nbytes = sizeof(struct pmc_op_getpmcinfo) +
3072f263522aSJoseph Koshy 	    npmc * sizeof(struct pmc_info);
3073f263522aSJoseph Koshy 
3074f263522aSJoseph Koshy 	if ((pmci = calloc(1, nbytes)) == NULL)
3075aa342b1fSJoseph Koshy 		return (-1);
3076f263522aSJoseph Koshy 
3077f263522aSJoseph Koshy 	pmci->pm_cpu  = cpu;
3078f263522aSJoseph Koshy 
3079f263522aSJoseph Koshy 	if (PMC_CALL(GETPMCINFO, pmci) < 0) {
3080f263522aSJoseph Koshy 		free(pmci);
3081aa342b1fSJoseph Koshy 		return (-1);
3082f263522aSJoseph Koshy 	}
3083f263522aSJoseph Koshy 
3084f263522aSJoseph Koshy 	/* kernel<->library, library<->userland interfaces are identical */
3085f263522aSJoseph Koshy 	*ppmci = (struct pmc_pmcinfo *) pmci;
3086aa342b1fSJoseph Koshy 	return (0);
3087f263522aSJoseph Koshy }
3088f263522aSJoseph Koshy 
3089f263522aSJoseph Koshy int
3090f263522aSJoseph Koshy pmc_read(pmc_id_t pmc, pmc_value_t *value)
3091f263522aSJoseph Koshy {
3092f263522aSJoseph Koshy 	struct pmc_op_pmcrw pmc_read_op;
3093f263522aSJoseph Koshy 
3094f263522aSJoseph Koshy 	pmc_read_op.pm_pmcid = pmc;
3095f263522aSJoseph Koshy 	pmc_read_op.pm_flags = PMC_F_OLDVALUE;
3096f263522aSJoseph Koshy 	pmc_read_op.pm_value = -1;
3097f263522aSJoseph Koshy 
3098f263522aSJoseph Koshy 	if (PMC_CALL(PMCRW, &pmc_read_op) < 0)
3099aa342b1fSJoseph Koshy 		return (-1);
3100f263522aSJoseph Koshy 
3101f263522aSJoseph Koshy 	*value = pmc_read_op.pm_value;
3102aa342b1fSJoseph Koshy 	return (0);
3103f263522aSJoseph Koshy }
3104f263522aSJoseph Koshy 
3105f263522aSJoseph Koshy int
3106f263522aSJoseph Koshy pmc_release(pmc_id_t pmc)
3107f263522aSJoseph Koshy {
3108f263522aSJoseph Koshy 	struct pmc_op_simple	pmc_release_args;
3109f263522aSJoseph Koshy 
3110f263522aSJoseph Koshy 	pmc_release_args.pm_pmcid = pmc;
3111aa342b1fSJoseph Koshy 	return (PMC_CALL(PMCRELEASE, &pmc_release_args));
3112f263522aSJoseph Koshy }
3113f263522aSJoseph Koshy 
3114f263522aSJoseph Koshy int
3115f263522aSJoseph Koshy pmc_rw(pmc_id_t pmc, pmc_value_t newvalue, pmc_value_t *oldvaluep)
3116f263522aSJoseph Koshy {
3117f263522aSJoseph Koshy 	struct pmc_op_pmcrw pmc_rw_op;
3118f263522aSJoseph Koshy 
3119f263522aSJoseph Koshy 	pmc_rw_op.pm_pmcid = pmc;
3120f263522aSJoseph Koshy 	pmc_rw_op.pm_flags = PMC_F_NEWVALUE | PMC_F_OLDVALUE;
3121f263522aSJoseph Koshy 	pmc_rw_op.pm_value = newvalue;
3122f263522aSJoseph Koshy 
3123f263522aSJoseph Koshy 	if (PMC_CALL(PMCRW, &pmc_rw_op) < 0)
3124aa342b1fSJoseph Koshy 		return (-1);
3125f263522aSJoseph Koshy 
3126f263522aSJoseph Koshy 	*oldvaluep = pmc_rw_op.pm_value;
3127aa342b1fSJoseph Koshy 	return (0);
3128f263522aSJoseph Koshy }
3129f263522aSJoseph Koshy 
3130f263522aSJoseph Koshy int
3131f263522aSJoseph Koshy pmc_set(pmc_id_t pmc, pmc_value_t value)
3132f263522aSJoseph Koshy {
3133f263522aSJoseph Koshy 	struct pmc_op_pmcsetcount sc;
3134f263522aSJoseph Koshy 
3135f263522aSJoseph Koshy 	sc.pm_pmcid = pmc;
3136f263522aSJoseph Koshy 	sc.pm_count = value;
3137f263522aSJoseph Koshy 
3138f263522aSJoseph Koshy 	if (PMC_CALL(PMCSETCOUNT, &sc) < 0)
3139aa342b1fSJoseph Koshy 		return (-1);
3140aa342b1fSJoseph Koshy 	return (0);
3141f263522aSJoseph Koshy }
3142f263522aSJoseph Koshy 
3143f263522aSJoseph Koshy int
3144f263522aSJoseph Koshy pmc_start(pmc_id_t pmc)
3145f263522aSJoseph Koshy {
3146f263522aSJoseph Koshy 	struct pmc_op_simple	pmc_start_args;
3147f263522aSJoseph Koshy 
3148f263522aSJoseph Koshy 	pmc_start_args.pm_pmcid = pmc;
3149aa342b1fSJoseph Koshy 	return (PMC_CALL(PMCSTART, &pmc_start_args));
3150f263522aSJoseph Koshy }
3151f263522aSJoseph Koshy 
3152f263522aSJoseph Koshy int
3153f263522aSJoseph Koshy pmc_stop(pmc_id_t pmc)
3154f263522aSJoseph Koshy {
3155f263522aSJoseph Koshy 	struct pmc_op_simple	pmc_stop_args;
3156f263522aSJoseph Koshy 
3157f263522aSJoseph Koshy 	pmc_stop_args.pm_pmcid = pmc;
3158aa342b1fSJoseph Koshy 	return (PMC_CALL(PMCSTOP, &pmc_stop_args));
3159f263522aSJoseph Koshy }
3160f263522aSJoseph Koshy 
3161f263522aSJoseph Koshy int
3162f263522aSJoseph Koshy pmc_width(pmc_id_t pmcid, uint32_t *width)
3163f263522aSJoseph Koshy {
3164f263522aSJoseph Koshy 	unsigned int i;
3165f263522aSJoseph Koshy 	enum pmc_class cl;
3166f263522aSJoseph Koshy 
3167f263522aSJoseph Koshy 	cl = PMC_ID_TO_CLASS(pmcid);
3168f263522aSJoseph Koshy 	for (i = 0; i < cpu_info.pm_nclass; i++)
3169f263522aSJoseph Koshy 		if (cpu_info.pm_classes[i].pm_class == cl) {
3170f263522aSJoseph Koshy 			*width = cpu_info.pm_classes[i].pm_width;
3171aa342b1fSJoseph Koshy 			return (0);
3172f263522aSJoseph Koshy 		}
3173484202faSJoseph Koshy 	errno = EINVAL;
3174484202faSJoseph Koshy 	return (-1);
3175f263522aSJoseph Koshy }
3176f263522aSJoseph Koshy 
3177f263522aSJoseph Koshy int
3178f263522aSJoseph Koshy pmc_write(pmc_id_t pmc, pmc_value_t value)
3179f263522aSJoseph Koshy {
3180f263522aSJoseph Koshy 	struct pmc_op_pmcrw pmc_write_op;
3181f263522aSJoseph Koshy 
3182f263522aSJoseph Koshy 	pmc_write_op.pm_pmcid = pmc;
3183f263522aSJoseph Koshy 	pmc_write_op.pm_flags = PMC_F_NEWVALUE;
3184f263522aSJoseph Koshy 	pmc_write_op.pm_value = value;
3185aa342b1fSJoseph Koshy 	return (PMC_CALL(PMCRW, &pmc_write_op));
3186f263522aSJoseph Koshy }
3187f263522aSJoseph Koshy 
3188f263522aSJoseph Koshy int
3189f263522aSJoseph Koshy pmc_writelog(uint32_t userdata)
3190f263522aSJoseph Koshy {
3191f263522aSJoseph Koshy 	struct pmc_op_writelog wl;
3192f263522aSJoseph Koshy 
3193f263522aSJoseph Koshy 	wl.pm_userdata = userdata;
3194aa342b1fSJoseph Koshy 	return (PMC_CALL(WRITELOG, &wl));
3195f263522aSJoseph Koshy }
3196