xref: /freebsd/lib/libpmc/libpmc.c (revision bc88bb2bf390a057d105fff3e9dd31c525de2685)
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>
31169dd953SJustin Hibbits #include <sys/param.h>
32ebccf1e3SJoseph Koshy #include <sys/module.h>
33ebccf1e3SJoseph Koshy #include <sys/pmc.h>
34ebccf1e3SJoseph Koshy #include <sys/syscall.h>
35ebccf1e3SJoseph Koshy 
36ebccf1e3SJoseph Koshy #include <ctype.h>
37ebccf1e3SJoseph Koshy #include <errno.h>
38ebccf1e3SJoseph Koshy #include <fcntl.h>
39ebccf1e3SJoseph Koshy #include <pmc.h>
40ebccf1e3SJoseph Koshy #include <stdio.h>
41ebccf1e3SJoseph Koshy #include <stdlib.h>
42ebccf1e3SJoseph Koshy #include <string.h>
43ebccf1e3SJoseph Koshy #include <strings.h>
44ebccf1e3SJoseph Koshy #include <unistd.h>
45ebccf1e3SJoseph Koshy 
460cfab8ddSJoseph Koshy #include "libpmcinternal.h"
470cfab8ddSJoseph Koshy 
48ebccf1e3SJoseph Koshy /* Function prototypes */
4904e9feb0SMarcel Moolenaar #if defined(__i386__)
50ebccf1e3SJoseph Koshy static int k7_allocate_pmc(enum pmc_event _pe, char *_ctrspec,
51ebccf1e3SJoseph Koshy     struct pmc_op_pmcallocate *_pmc_config);
52f263522aSJoseph Koshy #endif
5386a65549SJoseph Koshy #if defined(__amd64__) || defined(__i386__)
540cfab8ddSJoseph Koshy static int iaf_allocate_pmc(enum pmc_event _pe, char *_ctrspec,
550cfab8ddSJoseph Koshy     struct pmc_op_pmcallocate *_pmc_config);
560cfab8ddSJoseph Koshy static int iap_allocate_pmc(enum pmc_event _pe, char *_ctrspec,
570cfab8ddSJoseph Koshy     struct pmc_op_pmcallocate *_pmc_config);
581fa7f10bSFabien Thomas static int ucf_allocate_pmc(enum pmc_event _pe, char *_ctrspec,
591fa7f10bSFabien Thomas     struct pmc_op_pmcallocate *_pmc_config);
601fa7f10bSFabien Thomas static int ucp_allocate_pmc(enum pmc_event _pe, char *_ctrspec,
611fa7f10bSFabien Thomas     struct pmc_op_pmcallocate *_pmc_config);
62f263522aSJoseph Koshy static int k8_allocate_pmc(enum pmc_event _pe, char *_ctrspec,
63ebccf1e3SJoseph Koshy     struct pmc_op_pmcallocate *_pmc_config);
6486a65549SJoseph Koshy static int p4_allocate_pmc(enum pmc_event _pe, char *_ctrspec,
6586a65549SJoseph Koshy     struct pmc_op_pmcallocate *_pmc_config);
66f263522aSJoseph Koshy #endif
67f263522aSJoseph Koshy #if defined(__i386__)
68ebccf1e3SJoseph Koshy static int p5_allocate_pmc(enum pmc_event _pe, char *_ctrspec,
69ebccf1e3SJoseph Koshy     struct pmc_op_pmcallocate *_pmc_config);
70f263522aSJoseph Koshy static int p6_allocate_pmc(enum pmc_event _pe, char *_ctrspec,
71ebccf1e3SJoseph Koshy     struct pmc_op_pmcallocate *_pmc_config);
72ebccf1e3SJoseph Koshy #endif
73789140c0SJoseph Koshy #if defined(__amd64__) || defined(__i386__)
74789140c0SJoseph Koshy static int tsc_allocate_pmc(enum pmc_event _pe, char *_ctrspec,
75789140c0SJoseph Koshy     struct pmc_op_pmcallocate *_pmc_config);
76789140c0SJoseph Koshy #endif
776411d14dSRuslan Bukin #if defined(__arm__)
780ce207d2SRui Paulo #if defined(__XSCALE__)
790ce207d2SRui Paulo static int xscale_allocate_pmc(enum pmc_event _pe, char *_ctrspec,
800ce207d2SRui Paulo     struct pmc_op_pmcallocate *_pmc_config);
810ce207d2SRui Paulo #endif
826411d14dSRuslan Bukin static int armv7_allocate_pmc(enum pmc_event _pe, char *_ctrspec,
836411d14dSRuslan Bukin     struct pmc_op_pmcallocate *_pmc_config);
846411d14dSRuslan Bukin #endif
85*bc88bb2bSRuslan Bukin #if defined(__aarch64__)
86*bc88bb2bSRuslan Bukin static int arm64_allocate_pmc(enum pmc_event _pe, char *_ctrspec,
87*bc88bb2bSRuslan Bukin     struct pmc_op_pmcallocate *_pmc_config);
88*bc88bb2bSRuslan Bukin #endif
89660df75eSGeorge V. Neville-Neil #if defined(__mips__)
902827d3e1SOleksandr Tymoshenko static int mips_allocate_pmc(enum pmc_event _pe, char* ctrspec,
91660df75eSGeorge V. Neville-Neil 			     struct pmc_op_pmcallocate *_pmc_config);
92660df75eSGeorge V. Neville-Neil #endif /* __mips__ */
93f5f9340bSFabien Thomas static int soft_allocate_pmc(enum pmc_event _pe, char *_ctrspec,
94f5f9340bSFabien Thomas     struct pmc_op_pmcallocate *_pmc_config);
95660df75eSGeorge V. Neville-Neil 
967b25dccaSJustin Hibbits #if defined(__powerpc__)
97169dd953SJustin Hibbits static int powerpc_allocate_pmc(enum pmc_event _pe, char* ctrspec,
987b25dccaSJustin Hibbits 			     struct pmc_op_pmcallocate *_pmc_config);
997b25dccaSJustin Hibbits #endif /* __powerpc__ */
100660df75eSGeorge V. Neville-Neil 
101ebccf1e3SJoseph Koshy #define PMC_CALL(cmd, params)				\
102ebccf1e3SJoseph Koshy 	syscall(pmc_syscall, PMC_OP_##cmd, (params))
103ebccf1e3SJoseph Koshy 
104ebccf1e3SJoseph Koshy /*
105ebccf1e3SJoseph Koshy  * Event aliases provide a way for the user to ask for generic events
106ebccf1e3SJoseph Koshy  * like "cache-misses", or "instructions-retired".  These aliases are
107ebccf1e3SJoseph Koshy  * mapped to the appropriate canonical event descriptions using a
108ebccf1e3SJoseph Koshy  * lookup table.
109ebccf1e3SJoseph Koshy  */
110ebccf1e3SJoseph Koshy struct pmc_event_alias {
111ebccf1e3SJoseph Koshy 	const char	*pm_alias;
112ebccf1e3SJoseph Koshy 	const char	*pm_spec;
113ebccf1e3SJoseph Koshy };
114ebccf1e3SJoseph Koshy 
115ebccf1e3SJoseph Koshy static const struct pmc_event_alias *pmc_mdep_event_aliases;
116ebccf1e3SJoseph Koshy 
117ebccf1e3SJoseph Koshy /*
118789140c0SJoseph Koshy  * The pmc_event_descr structure maps symbolic names known to the user
119ebccf1e3SJoseph Koshy  * to integer codes used by the PMC KLD.
120ebccf1e3SJoseph Koshy  */
121ebccf1e3SJoseph Koshy struct pmc_event_descr {
122ebccf1e3SJoseph Koshy 	const char	*pm_ev_name;
123ebccf1e3SJoseph Koshy 	enum pmc_event	pm_ev_code;
124ebccf1e3SJoseph Koshy };
125ebccf1e3SJoseph Koshy 
126789140c0SJoseph Koshy /*
127789140c0SJoseph Koshy  * The pmc_class_descr structure maps class name prefixes for
128789140c0SJoseph Koshy  * event names to event tables and other PMC class data.
129789140c0SJoseph Koshy  */
130789140c0SJoseph Koshy struct pmc_class_descr {
131789140c0SJoseph Koshy 	const char	*pm_evc_name;
132789140c0SJoseph Koshy 	size_t		pm_evc_name_size;
133789140c0SJoseph Koshy 	enum pmc_class	pm_evc_class;
134789140c0SJoseph Koshy 	const struct pmc_event_descr *pm_evc_event_table;
135789140c0SJoseph Koshy 	size_t		pm_evc_event_table_size;
136789140c0SJoseph Koshy 	int		(*pm_evc_allocate_pmc)(enum pmc_event _pe,
137789140c0SJoseph Koshy 			    char *_ctrspec, struct pmc_op_pmcallocate *_pa);
138ebccf1e3SJoseph Koshy };
139ebccf1e3SJoseph Koshy 
140789140c0SJoseph Koshy #define	PMC_TABLE_SIZE(N)	(sizeof(N)/sizeof(N[0]))
141789140c0SJoseph Koshy #define	PMC_EVENT_TABLE_SIZE(N)	PMC_TABLE_SIZE(N##_event_table)
142789140c0SJoseph Koshy 
143789140c0SJoseph Koshy #undef	__PMC_EV
144789140c0SJoseph Koshy #define	__PMC_EV(C,N) { #N, PMC_EV_ ## C ## _ ## N },
145789140c0SJoseph Koshy 
146789140c0SJoseph Koshy /*
1470cfab8ddSJoseph Koshy  * PMC_CLASSDEP_TABLE(NAME, CLASS)
148789140c0SJoseph Koshy  *
1490cfab8ddSJoseph Koshy  * Define a table mapping event names and aliases to HWPMC event IDs.
150789140c0SJoseph Koshy  */
1510cfab8ddSJoseph Koshy #define	PMC_CLASSDEP_TABLE(N, C)				\
152789140c0SJoseph Koshy 	static const struct pmc_event_descr N##_event_table[] =	\
153789140c0SJoseph Koshy 	{							\
154789140c0SJoseph Koshy 		__PMC_EV_##C()					\
1550cfab8ddSJoseph Koshy 	}
1560cfab8ddSJoseph Koshy 
1570cfab8ddSJoseph Koshy PMC_CLASSDEP_TABLE(iaf, IAF);
1580cfab8ddSJoseph Koshy PMC_CLASSDEP_TABLE(k7, K7);
1590cfab8ddSJoseph Koshy PMC_CLASSDEP_TABLE(k8, K8);
1600cfab8ddSJoseph Koshy PMC_CLASSDEP_TABLE(p4, P4);
1610cfab8ddSJoseph Koshy PMC_CLASSDEP_TABLE(p5, P5);
1620cfab8ddSJoseph Koshy PMC_CLASSDEP_TABLE(p6, P6);
1630ce207d2SRui Paulo PMC_CLASSDEP_TABLE(xscale, XSCALE);
1646411d14dSRuslan Bukin PMC_CLASSDEP_TABLE(armv7, ARMV7);
165*bc88bb2bSRuslan Bukin PMC_CLASSDEP_TABLE(armv8, ARMV8);
166660df75eSGeorge V. Neville-Neil PMC_CLASSDEP_TABLE(mips24k, MIPS24K);
167f6e6460dSAdrian Chadd PMC_CLASSDEP_TABLE(mips74k, MIPS74K);
168c2657f80SOleksandr Tymoshenko PMC_CLASSDEP_TABLE(octeon, OCTEON);
1691fa7f10bSFabien Thomas PMC_CLASSDEP_TABLE(ucf, UCF);
1707b25dccaSJustin Hibbits PMC_CLASSDEP_TABLE(ppc7450, PPC7450);
171169dd953SJustin Hibbits PMC_CLASSDEP_TABLE(ppc970, PPC970);
172a7452468SJustin Hibbits PMC_CLASSDEP_TABLE(e500, E500);
1730cfab8ddSJoseph Koshy 
174f5f9340bSFabien Thomas static struct pmc_event_descr soft_event_table[PMC_EV_DYN_COUNT];
175f5f9340bSFabien Thomas 
1760cfab8ddSJoseph Koshy #undef	__PMC_EV_ALIAS
1770cfab8ddSJoseph Koshy #define	__PMC_EV_ALIAS(N,CODE) 	{ N, PMC_EV_##CODE },
1780cfab8ddSJoseph Koshy 
1790cfab8ddSJoseph Koshy static const struct pmc_event_descr atom_event_table[] =
1800cfab8ddSJoseph Koshy {
1810cfab8ddSJoseph Koshy 	__PMC_EV_ALIAS_ATOM()
1820cfab8ddSJoseph Koshy };
1830cfab8ddSJoseph Koshy 
184e8f021a3SHiren Panchasara static const struct pmc_event_descr atom_silvermont_event_table[] =
185e8f021a3SHiren Panchasara {
186e8f021a3SHiren Panchasara 	__PMC_EV_ALIAS_ATOM_SILVERMONT()
187e8f021a3SHiren Panchasara };
188e8f021a3SHiren Panchasara 
1890cfab8ddSJoseph Koshy static const struct pmc_event_descr core_event_table[] =
1900cfab8ddSJoseph Koshy {
1910cfab8ddSJoseph Koshy 	__PMC_EV_ALIAS_CORE()
1920cfab8ddSJoseph Koshy };
1930cfab8ddSJoseph Koshy 
1940cfab8ddSJoseph Koshy 
1950cfab8ddSJoseph Koshy static const struct pmc_event_descr core2_event_table[] =
1960cfab8ddSJoseph Koshy {
1970cfab8ddSJoseph Koshy 	__PMC_EV_ALIAS_CORE2()
1980cfab8ddSJoseph Koshy };
1990cfab8ddSJoseph Koshy 
200597979c4SJeff Roberson static const struct pmc_event_descr corei7_event_table[] =
201597979c4SJeff Roberson {
202597979c4SJeff Roberson 	__PMC_EV_ALIAS_COREI7()
203597979c4SJeff Roberson };
204597979c4SJeff Roberson 
20549fe48abSKonstantin Belousov static const struct pmc_event_descr nehalem_ex_event_table[] =
20649fe48abSKonstantin Belousov {
20749fe48abSKonstantin Belousov 	__PMC_EV_ALIAS_COREI7()
20849fe48abSKonstantin Belousov };
20949fe48abSKonstantin Belousov 
210cc0c1555SSean Bruno static const struct pmc_event_descr haswell_event_table[] =
211cc0c1555SSean Bruno {
212cc0c1555SSean Bruno 	__PMC_EV_ALIAS_HASWELL()
213cc0c1555SSean Bruno };
214cc0c1555SSean Bruno 
215d95b3509SRandall Stewart static const struct pmc_event_descr haswell_xeon_event_table[] =
216d95b3509SRandall Stewart {
217d95b3509SRandall Stewart 	__PMC_EV_ALIAS_HASWELL_XEON()
218d95b3509SRandall Stewart };
219d95b3509SRandall Stewart 
220d95b3509SRandall Stewart 
2211e862e5aSFabien Thomas static const struct pmc_event_descr ivybridge_event_table[] =
2221e862e5aSFabien Thomas {
2231e862e5aSFabien Thomas 	__PMC_EV_ALIAS_IVYBRIDGE()
2241e862e5aSFabien Thomas };
2251e862e5aSFabien Thomas 
2263f929d8cSSean Bruno static const struct pmc_event_descr ivybridge_xeon_event_table[] =
2273f929d8cSSean Bruno {
2283f929d8cSSean Bruno 	__PMC_EV_ALIAS_IVYBRIDGE_XEON()
2293f929d8cSSean Bruno };
2303f929d8cSSean Bruno 
23178d763a2SDavide Italiano static const struct pmc_event_descr sandybridge_event_table[] =
23278d763a2SDavide Italiano {
23378d763a2SDavide Italiano 	__PMC_EV_ALIAS_SANDYBRIDGE()
23478d763a2SDavide Italiano };
23578d763a2SDavide Italiano 
236fabe02f5SSean Bruno static const struct pmc_event_descr sandybridge_xeon_event_table[] =
237fabe02f5SSean Bruno {
238fabe02f5SSean Bruno 	__PMC_EV_ALIAS_SANDYBRIDGE_XEON()
239fabe02f5SSean Bruno };
240fabe02f5SSean Bruno 
2411fa7f10bSFabien Thomas static const struct pmc_event_descr westmere_event_table[] =
2421fa7f10bSFabien Thomas {
2431fa7f10bSFabien Thomas 	__PMC_EV_ALIAS_WESTMERE()
2441fa7f10bSFabien Thomas };
2451fa7f10bSFabien Thomas 
24649fe48abSKonstantin Belousov static const struct pmc_event_descr westmere_ex_event_table[] =
24749fe48abSKonstantin Belousov {
24849fe48abSKonstantin Belousov 	__PMC_EV_ALIAS_WESTMERE()
24949fe48abSKonstantin Belousov };
25049fe48abSKonstantin Belousov 
2511fa7f10bSFabien Thomas static const struct pmc_event_descr corei7uc_event_table[] =
2521fa7f10bSFabien Thomas {
2531fa7f10bSFabien Thomas 	__PMC_EV_ALIAS_COREI7UC()
2541fa7f10bSFabien Thomas };
2551fa7f10bSFabien Thomas 
256cc0c1555SSean Bruno static const struct pmc_event_descr haswelluc_event_table[] =
257cc0c1555SSean Bruno {
258cc0c1555SSean Bruno 	__PMC_EV_ALIAS_HASWELLUC()
259cc0c1555SSean Bruno };
260cc0c1555SSean Bruno 
26178d763a2SDavide Italiano static const struct pmc_event_descr sandybridgeuc_event_table[] =
26278d763a2SDavide Italiano {
26378d763a2SDavide Italiano 	__PMC_EV_ALIAS_SANDYBRIDGEUC()
26478d763a2SDavide Italiano };
26578d763a2SDavide Italiano 
2661fa7f10bSFabien Thomas static const struct pmc_event_descr westmereuc_event_table[] =
2671fa7f10bSFabien Thomas {
2681fa7f10bSFabien Thomas 	__PMC_EV_ALIAS_WESTMEREUC()
2691fa7f10bSFabien Thomas };
2701fa7f10bSFabien Thomas 
271*bc88bb2bSRuslan Bukin static const struct pmc_event_descr cortex_a53_event_table[] =
272*bc88bb2bSRuslan Bukin {
273*bc88bb2bSRuslan Bukin 	__PMC_EV_ALIAS_ARMV8_CORTEX_A53()
274*bc88bb2bSRuslan Bukin };
275*bc88bb2bSRuslan Bukin 
276*bc88bb2bSRuslan Bukin static const struct pmc_event_descr cortex_a57_event_table[] =
277*bc88bb2bSRuslan Bukin {
278*bc88bb2bSRuslan Bukin 	__PMC_EV_ALIAS_ARMV8_CORTEX_A57()
279*bc88bb2bSRuslan Bukin };
280*bc88bb2bSRuslan Bukin 
2810cfab8ddSJoseph Koshy /*
2820cfab8ddSJoseph Koshy  * PMC_MDEP_TABLE(NAME, PRIMARYCLASS, ADDITIONAL_CLASSES...)
2830cfab8ddSJoseph Koshy  *
2840cfab8ddSJoseph Koshy  * Map a CPU to the PMC classes it supports.
2850cfab8ddSJoseph Koshy  */
2860cfab8ddSJoseph Koshy #define	PMC_MDEP_TABLE(N,C,...)				\
287789140c0SJoseph Koshy 	static const enum pmc_class N##_pmc_classes[] = {	\
288789140c0SJoseph Koshy 		PMC_CLASS_##C, __VA_ARGS__			\
289789140c0SJoseph Koshy 	}
290789140c0SJoseph Koshy 
291f5f9340bSFabien Thomas PMC_MDEP_TABLE(atom, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC);
292e8f021a3SHiren Panchasara PMC_MDEP_TABLE(atom_silvermont, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC);
293f5f9340bSFabien Thomas PMC_MDEP_TABLE(core, IAP, PMC_CLASS_SOFT, PMC_CLASS_TSC);
294f5f9340bSFabien Thomas PMC_MDEP_TABLE(core2, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC);
295f5f9340bSFabien Thomas PMC_MDEP_TABLE(corei7, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC, PMC_CLASS_UCF, PMC_CLASS_UCP);
29649fe48abSKonstantin Belousov PMC_MDEP_TABLE(nehalem_ex, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC);
297cc0c1555SSean Bruno PMC_MDEP_TABLE(haswell, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC, PMC_CLASS_UCF, PMC_CLASS_UCP);
298d95b3509SRandall Stewart PMC_MDEP_TABLE(haswell_xeon, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC, PMC_CLASS_UCF, PMC_CLASS_UCP);
2991e862e5aSFabien Thomas PMC_MDEP_TABLE(ivybridge, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC);
3003f929d8cSSean Bruno PMC_MDEP_TABLE(ivybridge_xeon, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC);
301f5f9340bSFabien Thomas PMC_MDEP_TABLE(sandybridge, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC, PMC_CLASS_UCF, PMC_CLASS_UCP);
302fabe02f5SSean Bruno PMC_MDEP_TABLE(sandybridge_xeon, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC);
303f5f9340bSFabien Thomas PMC_MDEP_TABLE(westmere, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC, PMC_CLASS_UCF, PMC_CLASS_UCP);
30449fe48abSKonstantin Belousov PMC_MDEP_TABLE(westmere_ex, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC);
305f5f9340bSFabien Thomas PMC_MDEP_TABLE(k7, K7, PMC_CLASS_SOFT, PMC_CLASS_TSC);
306f5f9340bSFabien Thomas PMC_MDEP_TABLE(k8, K8, PMC_CLASS_SOFT, PMC_CLASS_TSC);
307f5f9340bSFabien Thomas PMC_MDEP_TABLE(p4, P4, PMC_CLASS_SOFT, PMC_CLASS_TSC);
308f5f9340bSFabien Thomas PMC_MDEP_TABLE(p5, P5, PMC_CLASS_SOFT, PMC_CLASS_TSC);
309f5f9340bSFabien Thomas PMC_MDEP_TABLE(p6, P6, PMC_CLASS_SOFT, PMC_CLASS_TSC);
310f5f9340bSFabien Thomas PMC_MDEP_TABLE(xscale, XSCALE, PMC_CLASS_SOFT, PMC_CLASS_XSCALE);
3116411d14dSRuslan Bukin PMC_MDEP_TABLE(armv7, ARMV7, PMC_CLASS_SOFT, PMC_CLASS_ARMV7);
312*bc88bb2bSRuslan Bukin PMC_MDEP_TABLE(cortex_a53, ARMV8, PMC_CLASS_SOFT, PMC_CLASS_ARMV8);
313*bc88bb2bSRuslan Bukin PMC_MDEP_TABLE(cortex_a57, ARMV8, PMC_CLASS_SOFT, PMC_CLASS_ARMV8);
314f5f9340bSFabien Thomas PMC_MDEP_TABLE(mips24k, MIPS24K, PMC_CLASS_SOFT, PMC_CLASS_MIPS24K);
315f6e6460dSAdrian Chadd PMC_MDEP_TABLE(mips74k, MIPS74K, PMC_CLASS_SOFT, PMC_CLASS_MIPS74K);
316f5f9340bSFabien Thomas PMC_MDEP_TABLE(octeon, OCTEON, PMC_CLASS_SOFT, PMC_CLASS_OCTEON);
317a7452468SJustin Hibbits PMC_MDEP_TABLE(ppc7450, PPC7450, PMC_CLASS_SOFT, PMC_CLASS_PPC7450, PMC_CLASS_TSC);
318a7452468SJustin Hibbits PMC_MDEP_TABLE(ppc970, PPC970, PMC_CLASS_SOFT, PMC_CLASS_PPC970, PMC_CLASS_TSC);
319a7452468SJustin Hibbits PMC_MDEP_TABLE(e500, E500, PMC_CLASS_SOFT, PMC_CLASS_E500, PMC_CLASS_TSC);
320f5f9340bSFabien Thomas PMC_MDEP_TABLE(generic, SOFT, PMC_CLASS_SOFT);
321789140c0SJoseph Koshy 
322789140c0SJoseph Koshy static const struct pmc_event_descr tsc_event_table[] =
323789140c0SJoseph Koshy {
324789140c0SJoseph Koshy 	__PMC_EV_TSC()
325789140c0SJoseph Koshy };
326789140c0SJoseph Koshy 
327789140c0SJoseph Koshy #undef	PMC_CLASS_TABLE_DESC
3280cfab8ddSJoseph Koshy #define	PMC_CLASS_TABLE_DESC(NAME, CLASS, EVENTS, ALLOCATOR)	\
3290cfab8ddSJoseph Koshy static const struct pmc_class_descr NAME##_class_table_descr =	\
3300cfab8ddSJoseph Koshy 	{							\
3310cfab8ddSJoseph Koshy 		.pm_evc_name  = #CLASS "-",			\
3320cfab8ddSJoseph Koshy 		.pm_evc_name_size = sizeof(#CLASS "-") - 1,	\
3330cfab8ddSJoseph Koshy 		.pm_evc_class = PMC_CLASS_##CLASS ,		\
3340cfab8ddSJoseph Koshy 		.pm_evc_event_table = EVENTS##_event_table ,	\
335789140c0SJoseph Koshy 		.pm_evc_event_table_size = 			\
3360cfab8ddSJoseph Koshy 			PMC_EVENT_TABLE_SIZE(EVENTS),		\
3370cfab8ddSJoseph Koshy 		.pm_evc_allocate_pmc = ALLOCATOR##_allocate_pmc	\
338789140c0SJoseph Koshy 	}
339789140c0SJoseph Koshy 
340789140c0SJoseph Koshy #if	defined(__i386__) || defined(__amd64__)
3410cfab8ddSJoseph Koshy PMC_CLASS_TABLE_DESC(iaf, IAF, iaf, iaf);
3420cfab8ddSJoseph Koshy PMC_CLASS_TABLE_DESC(atom, IAP, atom, iap);
343e8f021a3SHiren Panchasara PMC_CLASS_TABLE_DESC(atom_silvermont, IAP, atom_silvermont, iap);
3440cfab8ddSJoseph Koshy PMC_CLASS_TABLE_DESC(core, IAP, core, iap);
3450cfab8ddSJoseph Koshy PMC_CLASS_TABLE_DESC(core2, IAP, core2, iap);
346597979c4SJeff Roberson PMC_CLASS_TABLE_DESC(corei7, IAP, corei7, iap);
34749fe48abSKonstantin Belousov PMC_CLASS_TABLE_DESC(nehalem_ex, IAP, nehalem_ex, iap);
348cc0c1555SSean Bruno PMC_CLASS_TABLE_DESC(haswell, IAP, haswell, iap);
349ae9975dbSRyan Stone PMC_CLASS_TABLE_DESC(haswell_xeon, IAP, haswell_xeon, iap);
3501e862e5aSFabien Thomas PMC_CLASS_TABLE_DESC(ivybridge, IAP, ivybridge, iap);
3513f929d8cSSean Bruno PMC_CLASS_TABLE_DESC(ivybridge_xeon, IAP, ivybridge_xeon, iap);
35278d763a2SDavide Italiano PMC_CLASS_TABLE_DESC(sandybridge, IAP, sandybridge, iap);
353fabe02f5SSean Bruno PMC_CLASS_TABLE_DESC(sandybridge_xeon, IAP, sandybridge_xeon, iap);
3541fa7f10bSFabien Thomas PMC_CLASS_TABLE_DESC(westmere, IAP, westmere, iap);
35549fe48abSKonstantin Belousov PMC_CLASS_TABLE_DESC(westmere_ex, IAP, westmere_ex, iap);
3561fa7f10bSFabien Thomas PMC_CLASS_TABLE_DESC(ucf, UCF, ucf, ucf);
3571fa7f10bSFabien Thomas PMC_CLASS_TABLE_DESC(corei7uc, UCP, corei7uc, ucp);
358cc0c1555SSean Bruno PMC_CLASS_TABLE_DESC(haswelluc, UCP, haswelluc, ucp);
35978d763a2SDavide Italiano PMC_CLASS_TABLE_DESC(sandybridgeuc, UCP, sandybridgeuc, ucp);
3601fa7f10bSFabien Thomas PMC_CLASS_TABLE_DESC(westmereuc, UCP, westmereuc, ucp);
361789140c0SJoseph Koshy #endif
362789140c0SJoseph Koshy #if	defined(__i386__)
3630cfab8ddSJoseph Koshy PMC_CLASS_TABLE_DESC(k7, K7, k7, k7);
364789140c0SJoseph Koshy #endif
365789140c0SJoseph Koshy #if	defined(__i386__) || defined(__amd64__)
3660cfab8ddSJoseph Koshy PMC_CLASS_TABLE_DESC(k8, K8, k8, k8);
3670cfab8ddSJoseph Koshy PMC_CLASS_TABLE_DESC(p4, P4, p4, p4);
368789140c0SJoseph Koshy #endif
3690cfab8ddSJoseph Koshy #if	defined(__i386__)
3700cfab8ddSJoseph Koshy PMC_CLASS_TABLE_DESC(p5, P5, p5, p5);
3710cfab8ddSJoseph Koshy PMC_CLASS_TABLE_DESC(p6, P6, p6, p6);
3720cfab8ddSJoseph Koshy #endif
3730cfab8ddSJoseph Koshy #if	defined(__i386__) || defined(__amd64__)
3740cfab8ddSJoseph Koshy PMC_CLASS_TABLE_DESC(tsc, TSC, tsc, tsc);
3750cfab8ddSJoseph Koshy #endif
3766411d14dSRuslan Bukin #if	defined(__arm__)
3770ce207d2SRui Paulo #if	defined(__XSCALE__)
3780ce207d2SRui Paulo PMC_CLASS_TABLE_DESC(xscale, XSCALE, xscale, xscale);
3790ce207d2SRui Paulo #endif
3806411d14dSRuslan Bukin PMC_CLASS_TABLE_DESC(armv7, ARMV7, armv7, armv7);
3816411d14dSRuslan Bukin #endif
382*bc88bb2bSRuslan Bukin #if	defined(__aarch64__)
383*bc88bb2bSRuslan Bukin PMC_CLASS_TABLE_DESC(cortex_a53, ARMV8, cortex_a53, arm64);
384*bc88bb2bSRuslan Bukin PMC_CLASS_TABLE_DESC(cortex_a57, ARMV8, cortex_a57, arm64);
385*bc88bb2bSRuslan Bukin #endif
386660df75eSGeorge V. Neville-Neil #if defined(__mips__)
3872827d3e1SOleksandr Tymoshenko PMC_CLASS_TABLE_DESC(mips24k, MIPS24K, mips24k, mips);
388f6e6460dSAdrian Chadd PMC_CLASS_TABLE_DESC(mips74k, MIPS74K, mips74k, mips);
389c2657f80SOleksandr Tymoshenko PMC_CLASS_TABLE_DESC(octeon, OCTEON, octeon, mips);
390660df75eSGeorge V. Neville-Neil #endif /* __mips__ */
3917b25dccaSJustin Hibbits #if defined(__powerpc__)
392169dd953SJustin Hibbits PMC_CLASS_TABLE_DESC(ppc7450, PPC7450, ppc7450, powerpc);
393169dd953SJustin Hibbits PMC_CLASS_TABLE_DESC(ppc970, PPC970, ppc970, powerpc);
394a7452468SJustin Hibbits PMC_CLASS_TABLE_DESC(e500, E500, e500, powerpc);
3957b25dccaSJustin Hibbits #endif
3967b25dccaSJustin Hibbits 
397f5f9340bSFabien Thomas static struct pmc_class_descr soft_class_table_descr =
398f5f9340bSFabien Thomas {
399f5f9340bSFabien Thomas 	.pm_evc_name  = "SOFT-",
400f5f9340bSFabien Thomas 	.pm_evc_name_size = sizeof("SOFT-") - 1,
401f5f9340bSFabien Thomas 	.pm_evc_class = PMC_CLASS_SOFT,
402f5f9340bSFabien Thomas 	.pm_evc_event_table = NULL,
403f5f9340bSFabien Thomas 	.pm_evc_event_table_size = 0,
404f5f9340bSFabien Thomas 	.pm_evc_allocate_pmc = soft_allocate_pmc
405f5f9340bSFabien Thomas };
406f5f9340bSFabien Thomas 
407789140c0SJoseph Koshy #undef	PMC_CLASS_TABLE_DESC
408789140c0SJoseph Koshy 
4090cfab8ddSJoseph Koshy static const struct pmc_class_descr **pmc_class_table;
4100cfab8ddSJoseph Koshy #define	PMC_CLASS_TABLE_SIZE	cpu_info.pm_nclass
4110cfab8ddSJoseph Koshy 
412789140c0SJoseph Koshy static const enum pmc_class *pmc_mdep_class_list;
413789140c0SJoseph Koshy static size_t pmc_mdep_class_list_size;
414789140c0SJoseph Koshy 
415ebccf1e3SJoseph Koshy /*
416ebccf1e3SJoseph Koshy  * Mapping tables, mapping enumeration values to human readable
417ebccf1e3SJoseph Koshy  * strings.
418ebccf1e3SJoseph Koshy  */
419ebccf1e3SJoseph Koshy 
420ebccf1e3SJoseph Koshy static const char * pmc_capability_names[] = {
421ebccf1e3SJoseph Koshy #undef	__PMC_CAP
422ebccf1e3SJoseph Koshy #define	__PMC_CAP(N,V,D)	#N ,
423ebccf1e3SJoseph Koshy 	__PMC_CAPS()
424ebccf1e3SJoseph Koshy };
425ebccf1e3SJoseph Koshy 
426ebccf1e3SJoseph Koshy static const char * pmc_class_names[] = {
427ebccf1e3SJoseph Koshy #undef	__PMC_CLASS
428ebccf1e3SJoseph Koshy #define __PMC_CLASS(C)	#C ,
429ebccf1e3SJoseph Koshy 	__PMC_CLASSES()
430ebccf1e3SJoseph Koshy };
431ebccf1e3SJoseph Koshy 
432789140c0SJoseph Koshy struct pmc_cputype_map {
433562fc14bSDimitry Andric 	enum pmc_cputype pm_cputype;
434789140c0SJoseph Koshy 	const char	*pm_name;
435789140c0SJoseph Koshy };
436789140c0SJoseph Koshy 
437789140c0SJoseph Koshy static const struct pmc_cputype_map pmc_cputype_names[] = {
438ebccf1e3SJoseph Koshy #undef	__PMC_CPU
439789140c0SJoseph Koshy #define	__PMC_CPU(S, V, D) { .pm_cputype = PMC_CPU_##S, .pm_name = #S } ,
440ebccf1e3SJoseph Koshy 	__PMC_CPUS()
441ebccf1e3SJoseph Koshy };
442ebccf1e3SJoseph Koshy 
443ebccf1e3SJoseph Koshy static const char * pmc_disposition_names[] = {
444ebccf1e3SJoseph Koshy #undef	__PMC_DISP
445ebccf1e3SJoseph Koshy #define	__PMC_DISP(D)	#D ,
446ebccf1e3SJoseph Koshy 	__PMC_DISPOSITIONS()
447ebccf1e3SJoseph Koshy };
448ebccf1e3SJoseph Koshy 
449ebccf1e3SJoseph Koshy static const char * pmc_mode_names[] = {
450ebccf1e3SJoseph Koshy #undef  __PMC_MODE
451ebccf1e3SJoseph Koshy #define __PMC_MODE(M,N)	#M ,
452ebccf1e3SJoseph Koshy 	__PMC_MODES()
453ebccf1e3SJoseph Koshy };
454ebccf1e3SJoseph Koshy 
455ebccf1e3SJoseph Koshy static const char * pmc_state_names[] = {
456ebccf1e3SJoseph Koshy #undef  __PMC_STATE
457ebccf1e3SJoseph Koshy #define __PMC_STATE(S) #S ,
458ebccf1e3SJoseph Koshy 	__PMC_STATES()
459ebccf1e3SJoseph Koshy };
460ebccf1e3SJoseph Koshy 
461f5f9340bSFabien Thomas /*
462f5f9340bSFabien Thomas  * Filled in by pmc_init().
463f5f9340bSFabien Thomas  */
464f5f9340bSFabien Thomas static int pmc_syscall = -1;
465f5f9340bSFabien Thomas static struct pmc_cpuinfo cpu_info;
466f5f9340bSFabien Thomas static struct pmc_op_getdyneventinfo soft_event_info;
4671455fcd3SJoseph Koshy 
468ebccf1e3SJoseph Koshy /* Event masks for events */
469ebccf1e3SJoseph Koshy struct pmc_masks {
470ebccf1e3SJoseph Koshy 	const char	*pm_name;
4711e862e5aSFabien Thomas 	const uint64_t	pm_value;
472ebccf1e3SJoseph Koshy };
473ebccf1e3SJoseph Koshy #define	PMCMASK(N,V)	{ .pm_name = #N, .pm_value = (V) }
4741fa7f10bSFabien Thomas #define	NULLMASK	{ .pm_name = NULL }
475ebccf1e3SJoseph Koshy 
47686a65549SJoseph Koshy #if defined(__amd64__) || defined(__i386__)
477ebccf1e3SJoseph Koshy static int
4781e862e5aSFabien Thomas pmc_parse_mask(const struct pmc_masks *pmask, char *p, uint64_t *evmask)
479ebccf1e3SJoseph Koshy {
480ebccf1e3SJoseph Koshy 	const struct pmc_masks *pm;
481ebccf1e3SJoseph Koshy 	char *q, *r;
482ebccf1e3SJoseph Koshy 	int c;
483ebccf1e3SJoseph Koshy 
484ebccf1e3SJoseph Koshy 	if (pmask == NULL)	/* no mask keywords */
485aa342b1fSJoseph Koshy 		return (-1);
486ebccf1e3SJoseph Koshy 	q = strchr(p, '=');	/* skip '=' */
487ebccf1e3SJoseph Koshy 	if (*++q == '\0')	/* no more data */
488aa342b1fSJoseph Koshy 		return (-1);
489ebccf1e3SJoseph Koshy 	c = 0;			/* count of mask keywords seen */
490ebccf1e3SJoseph Koshy 	while ((r = strsep(&q, "+")) != NULL) {
491789140c0SJoseph Koshy 		for (pm = pmask; pm->pm_name && strcasecmp(r, pm->pm_name);
492789140c0SJoseph Koshy 		    pm++)
493ebccf1e3SJoseph Koshy 			;
494ebccf1e3SJoseph Koshy 		if (pm->pm_name == NULL) /* not found */
495aa342b1fSJoseph Koshy 			return (-1);
496ebccf1e3SJoseph Koshy 		*evmask |= pm->pm_value;
497ebccf1e3SJoseph Koshy 		c++;
498ebccf1e3SJoseph Koshy 	}
499aa342b1fSJoseph Koshy 	return (c);
500ebccf1e3SJoseph Koshy }
50104e9feb0SMarcel Moolenaar #endif
502ebccf1e3SJoseph Koshy 
503ebccf1e3SJoseph Koshy #define	KWMATCH(p,kw)		(strcasecmp((p), (kw)) == 0)
504ebccf1e3SJoseph Koshy #define	KWPREFIXMATCH(p,kw)	(strncasecmp((p), (kw), sizeof((kw)) - 1) == 0)
505ebccf1e3SJoseph Koshy #define	EV_ALIAS(N,S)		{ .pm_alias = N, .pm_spec = S }
506ebccf1e3SJoseph Koshy 
50704e9feb0SMarcel Moolenaar #if defined(__i386__)
508ebccf1e3SJoseph Koshy 
509ebccf1e3SJoseph Koshy /*
510ebccf1e3SJoseph Koshy  * AMD K7 (Athlon) CPUs.
511ebccf1e3SJoseph Koshy  */
512ebccf1e3SJoseph Koshy 
513ebccf1e3SJoseph Koshy static struct pmc_event_alias k7_aliases[] = {
514ebccf1e3SJoseph Koshy 	EV_ALIAS("branches",		"k7-retired-branches"),
515ebccf1e3SJoseph Koshy 	EV_ALIAS("branch-mispredicts",	"k7-retired-branches-mispredicted"),
516ebccf1e3SJoseph Koshy 	EV_ALIAS("cycles",		"tsc"),
5176aa5a193SJoseph Koshy 	EV_ALIAS("dc-misses",		"k7-dc-misses"),
518ebccf1e3SJoseph Koshy 	EV_ALIAS("ic-misses",		"k7-ic-misses"),
519ebccf1e3SJoseph Koshy 	EV_ALIAS("instructions",	"k7-retired-instructions"),
520ebccf1e3SJoseph Koshy 	EV_ALIAS("interrupts",		"k7-hardware-interrupts"),
521ebccf1e3SJoseph Koshy 	EV_ALIAS(NULL, NULL)
522ebccf1e3SJoseph Koshy };
523ebccf1e3SJoseph Koshy 
524ebccf1e3SJoseph Koshy #define	K7_KW_COUNT	"count"
525ebccf1e3SJoseph Koshy #define	K7_KW_EDGE	"edge"
526ebccf1e3SJoseph Koshy #define	K7_KW_INV	"inv"
527ebccf1e3SJoseph Koshy #define	K7_KW_OS	"os"
528ebccf1e3SJoseph Koshy #define	K7_KW_UNITMASK	"unitmask"
529ebccf1e3SJoseph Koshy #define	K7_KW_USR	"usr"
530ebccf1e3SJoseph Koshy 
531ebccf1e3SJoseph Koshy static int
532ebccf1e3SJoseph Koshy k7_allocate_pmc(enum pmc_event pe, char *ctrspec,
533ebccf1e3SJoseph Koshy     struct pmc_op_pmcallocate *pmc_config)
534ebccf1e3SJoseph Koshy {
535ebccf1e3SJoseph Koshy 	char		*e, *p, *q;
536ebccf1e3SJoseph Koshy 	int		c, has_unitmask;
537ebccf1e3SJoseph Koshy 	uint32_t	count, unitmask;
538ebccf1e3SJoseph Koshy 
539f263522aSJoseph Koshy 	pmc_config->pm_md.pm_amd.pm_amd_config = 0;
540789140c0SJoseph Koshy 	pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE);
541ebccf1e3SJoseph Koshy 
542ebccf1e3SJoseph Koshy 	if (pe == PMC_EV_K7_DC_REFILLS_FROM_L2 ||
543ebccf1e3SJoseph Koshy 	    pe == PMC_EV_K7_DC_REFILLS_FROM_SYSTEM ||
544ebccf1e3SJoseph Koshy 	    pe == PMC_EV_K7_DC_WRITEBACKS) {
545ebccf1e3SJoseph Koshy 		has_unitmask = 1;
546f263522aSJoseph Koshy 		unitmask = AMD_PMC_UNITMASK_MOESI;
547ebccf1e3SJoseph Koshy 	} else
548ebccf1e3SJoseph Koshy 		unitmask = has_unitmask = 0;
549ebccf1e3SJoseph Koshy 
550ebccf1e3SJoseph Koshy 	while ((p = strsep(&ctrspec, ",")) != NULL) {
551ebccf1e3SJoseph Koshy 		if (KWPREFIXMATCH(p, K7_KW_COUNT "=")) {
552ebccf1e3SJoseph Koshy 			q = strchr(p, '=');
553ebccf1e3SJoseph Koshy 			if (*++q == '\0') /* skip '=' */
554aa342b1fSJoseph Koshy 				return (-1);
555ebccf1e3SJoseph Koshy 
556ebccf1e3SJoseph Koshy 			count = strtol(q, &e, 0);
557ebccf1e3SJoseph Koshy 			if (e == q || *e != '\0')
558aa342b1fSJoseph Koshy 				return (-1);
559ebccf1e3SJoseph Koshy 
560ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_THRESHOLD;
561f263522aSJoseph Koshy 			pmc_config->pm_md.pm_amd.pm_amd_config |=
562f263522aSJoseph Koshy 			    AMD_PMC_TO_COUNTER(count);
563ebccf1e3SJoseph Koshy 
564ebccf1e3SJoseph Koshy 		} else if (KWMATCH(p, K7_KW_EDGE)) {
565ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_EDGE;
566ebccf1e3SJoseph Koshy 		} else if (KWMATCH(p, K7_KW_INV)) {
567ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_INVERT;
568ebccf1e3SJoseph Koshy 		} else if (KWMATCH(p, K7_KW_OS)) {
569ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_SYSTEM;
570ebccf1e3SJoseph Koshy 		} else if (KWPREFIXMATCH(p, K7_KW_UNITMASK "=")) {
571ebccf1e3SJoseph Koshy 			if (has_unitmask == 0)
572aa342b1fSJoseph Koshy 				return (-1);
573ebccf1e3SJoseph Koshy 			unitmask = 0;
574ebccf1e3SJoseph Koshy 			q = strchr(p, '=');
575ebccf1e3SJoseph Koshy 			if (*++q == '\0') /* skip '=' */
576aa342b1fSJoseph Koshy 				return (-1);
577ebccf1e3SJoseph Koshy 
578ebccf1e3SJoseph Koshy 			while ((c = tolower(*q++)) != 0)
579ebccf1e3SJoseph Koshy 				if (c == 'm')
580f263522aSJoseph Koshy 					unitmask |= AMD_PMC_UNITMASK_M;
581ebccf1e3SJoseph Koshy 				else if (c == 'o')
582f263522aSJoseph Koshy 					unitmask |= AMD_PMC_UNITMASK_O;
583ebccf1e3SJoseph Koshy 				else if (c == 'e')
584f263522aSJoseph Koshy 					unitmask |= AMD_PMC_UNITMASK_E;
585ebccf1e3SJoseph Koshy 				else if (c == 's')
586f263522aSJoseph Koshy 					unitmask |= AMD_PMC_UNITMASK_S;
587ebccf1e3SJoseph Koshy 				else if (c == 'i')
588f263522aSJoseph Koshy 					unitmask |= AMD_PMC_UNITMASK_I;
589ebccf1e3SJoseph Koshy 				else if (c == '+')
590ebccf1e3SJoseph Koshy 					continue;
591ebccf1e3SJoseph Koshy 				else
592aa342b1fSJoseph Koshy 					return (-1);
593ebccf1e3SJoseph Koshy 
594ebccf1e3SJoseph Koshy 			if (unitmask == 0)
595aa342b1fSJoseph Koshy 				return (-1);
596ebccf1e3SJoseph Koshy 
597ebccf1e3SJoseph Koshy 		} else if (KWMATCH(p, K7_KW_USR)) {
598ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_USER;
599ebccf1e3SJoseph Koshy 		} else
600aa342b1fSJoseph Koshy 			return (-1);
601ebccf1e3SJoseph Koshy 	}
602ebccf1e3SJoseph Koshy 
603ebccf1e3SJoseph Koshy 	if (has_unitmask) {
604ebccf1e3SJoseph Koshy 		pmc_config->pm_caps |= PMC_CAP_QUALIFIER;
605f263522aSJoseph Koshy 		pmc_config->pm_md.pm_amd.pm_amd_config |=
606f263522aSJoseph Koshy 		    AMD_PMC_TO_UNITMASK(unitmask);
607ebccf1e3SJoseph Koshy 	}
608ebccf1e3SJoseph Koshy 
609aa342b1fSJoseph Koshy 	return (0);
610ebccf1e3SJoseph Koshy 
611ebccf1e3SJoseph Koshy }
612ebccf1e3SJoseph Koshy 
613f263522aSJoseph Koshy #endif
614f263522aSJoseph Koshy 
61586a65549SJoseph Koshy #if defined(__amd64__) || defined(__i386__)
616f263522aSJoseph Koshy 
617f263522aSJoseph Koshy /*
6180cfab8ddSJoseph Koshy  * Intel Core (Family 6, Model E) PMCs.
6190cfab8ddSJoseph Koshy  */
6200cfab8ddSJoseph Koshy 
6210cfab8ddSJoseph Koshy static struct pmc_event_alias core_aliases[] = {
6220cfab8ddSJoseph Koshy 	EV_ALIAS("branches",		"iap-br-instr-ret"),
6230cfab8ddSJoseph Koshy 	EV_ALIAS("branch-mispredicts",	"iap-br-mispred-ret"),
6240cfab8ddSJoseph Koshy 	EV_ALIAS("cycles",		"tsc-tsc"),
6250cfab8ddSJoseph Koshy 	EV_ALIAS("ic-misses",		"iap-icache-misses"),
6260cfab8ddSJoseph Koshy 	EV_ALIAS("instructions",	"iap-instr-ret"),
6270cfab8ddSJoseph Koshy 	EV_ALIAS("interrupts",		"iap-core-hw-int-rx"),
6280cfab8ddSJoseph Koshy 	EV_ALIAS("unhalted-cycles",	"iap-unhalted-core-cycles"),
6290cfab8ddSJoseph Koshy 	EV_ALIAS(NULL, NULL)
6300cfab8ddSJoseph Koshy };
6310cfab8ddSJoseph Koshy 
6320cfab8ddSJoseph Koshy /*
6330cfab8ddSJoseph Koshy  * Intel Core2 (Family 6, Model F), Core2Extreme (Family 6, Model 17H)
6340cfab8ddSJoseph Koshy  * and Atom (Family 6, model 1CH) PMCs.
635791f5d5bSJoseph Koshy  *
636791f5d5bSJoseph Koshy  * We map aliases to events on the fixed-function counters if these
637791f5d5bSJoseph Koshy  * are present.  Note that not all CPUs in this family contain fixed-function
638791f5d5bSJoseph Koshy  * counters.
6390cfab8ddSJoseph Koshy  */
6400cfab8ddSJoseph Koshy 
6410cfab8ddSJoseph Koshy static struct pmc_event_alias core2_aliases[] = {
6420cfab8ddSJoseph Koshy 	EV_ALIAS("branches",		"iap-br-inst-retired.any"),
6430cfab8ddSJoseph Koshy 	EV_ALIAS("branch-mispredicts",	"iap-br-inst-retired.mispred"),
6440cfab8ddSJoseph Koshy 	EV_ALIAS("cycles",		"tsc-tsc"),
6450cfab8ddSJoseph Koshy 	EV_ALIAS("ic-misses",		"iap-l1i-misses"),
6460cfab8ddSJoseph Koshy 	EV_ALIAS("instructions",	"iaf-instr-retired.any"),
6470cfab8ddSJoseph Koshy 	EV_ALIAS("interrupts",		"iap-hw-int-rcv"),
6480cfab8ddSJoseph Koshy 	EV_ALIAS("unhalted-cycles",	"iaf-cpu-clk-unhalted.core"),
6490cfab8ddSJoseph Koshy 	EV_ALIAS(NULL, NULL)
6500cfab8ddSJoseph Koshy };
651791f5d5bSJoseph Koshy 
652791f5d5bSJoseph Koshy static struct pmc_event_alias core2_aliases_without_iaf[] = {
653791f5d5bSJoseph Koshy 	EV_ALIAS("branches",		"iap-br-inst-retired.any"),
654791f5d5bSJoseph Koshy 	EV_ALIAS("branch-mispredicts",	"iap-br-inst-retired.mispred"),
655791f5d5bSJoseph Koshy 	EV_ALIAS("cycles",		"tsc-tsc"),
656791f5d5bSJoseph Koshy 	EV_ALIAS("ic-misses",		"iap-l1i-misses"),
657791f5d5bSJoseph Koshy 	EV_ALIAS("instructions",	"iap-inst-retired.any_p"),
658791f5d5bSJoseph Koshy 	EV_ALIAS("interrupts",		"iap-hw-int-rcv"),
659791f5d5bSJoseph Koshy 	EV_ALIAS("unhalted-cycles",	"iap-cpu-clk-unhalted.core_p"),
660791f5d5bSJoseph Koshy 	EV_ALIAS(NULL, NULL)
661791f5d5bSJoseph Koshy };
662791f5d5bSJoseph Koshy 
6630cfab8ddSJoseph Koshy #define	atom_aliases			core2_aliases
664791f5d5bSJoseph Koshy #define	atom_aliases_without_iaf	core2_aliases_without_iaf
665e8f021a3SHiren Panchasara #define	atom_silvermont_aliases		core2_aliases
666e8f021a3SHiren Panchasara #define	atom_silvermont_aliases_without_iaf	core2_aliases_without_iaf
667597979c4SJeff Roberson #define corei7_aliases			core2_aliases
668791f5d5bSJoseph Koshy #define corei7_aliases_without_iaf	core2_aliases_without_iaf
66949fe48abSKonstantin Belousov #define nehalem_ex_aliases		core2_aliases
67049fe48abSKonstantin Belousov #define nehalem_ex_aliases_without_iaf	core2_aliases_without_iaf
671cc0c1555SSean Bruno #define haswell_aliases			core2_aliases
672cc0c1555SSean Bruno #define haswell_aliases_without_iaf	core2_aliases_without_iaf
673d95b3509SRandall Stewart #define haswell_xeon_aliases			core2_aliases
674d95b3509SRandall Stewart #define haswell_xeon_aliases_without_iaf	core2_aliases_without_iaf
6751e862e5aSFabien Thomas #define ivybridge_aliases		core2_aliases
6761e862e5aSFabien Thomas #define ivybridge_aliases_without_iaf	core2_aliases_without_iaf
6773f929d8cSSean Bruno #define ivybridge_xeon_aliases		core2_aliases
6783f929d8cSSean Bruno #define ivybridge_xeon_aliases_without_iaf	core2_aliases_without_iaf
67978d763a2SDavide Italiano #define sandybridge_aliases		core2_aliases
68078d763a2SDavide Italiano #define sandybridge_aliases_without_iaf	core2_aliases_without_iaf
681fabe02f5SSean Bruno #define sandybridge_xeon_aliases	core2_aliases
682fabe02f5SSean Bruno #define sandybridge_xeon_aliases_without_iaf	core2_aliases_without_iaf
6831fa7f10bSFabien Thomas #define westmere_aliases		core2_aliases
6841fa7f10bSFabien Thomas #define westmere_aliases_without_iaf	core2_aliases_without_iaf
68549fe48abSKonstantin Belousov #define westmere_ex_aliases		core2_aliases
68649fe48abSKonstantin Belousov #define westmere_ex_aliases_without_iaf	core2_aliases_without_iaf
6870cfab8ddSJoseph Koshy 
6880cfab8ddSJoseph Koshy #define	IAF_KW_OS		"os"
6890cfab8ddSJoseph Koshy #define	IAF_KW_USR		"usr"
6900cfab8ddSJoseph Koshy #define	IAF_KW_ANYTHREAD	"anythread"
6910cfab8ddSJoseph Koshy 
6920cfab8ddSJoseph Koshy /*
6930cfab8ddSJoseph Koshy  * Parse an event specifier for Intel fixed function counters.
6940cfab8ddSJoseph Koshy  */
6950cfab8ddSJoseph Koshy static int
6960cfab8ddSJoseph Koshy iaf_allocate_pmc(enum pmc_event pe, char *ctrspec,
6970cfab8ddSJoseph Koshy     struct pmc_op_pmcallocate *pmc_config)
6980cfab8ddSJoseph Koshy {
6990cfab8ddSJoseph Koshy 	char *p;
7000cfab8ddSJoseph Koshy 
7010cfab8ddSJoseph Koshy 	(void) pe;
7020cfab8ddSJoseph Koshy 
7030cfab8ddSJoseph Koshy 	pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE);
7040cfab8ddSJoseph Koshy 	pmc_config->pm_md.pm_iaf.pm_iaf_flags = 0;
7050cfab8ddSJoseph Koshy 
7060cfab8ddSJoseph Koshy 	while ((p = strsep(&ctrspec, ",")) != NULL) {
7070cfab8ddSJoseph Koshy 		if (KWMATCH(p, IAF_KW_OS))
7080cfab8ddSJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_SYSTEM;
7090cfab8ddSJoseph Koshy 		else if (KWMATCH(p, IAF_KW_USR))
7100cfab8ddSJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_USER;
7110cfab8ddSJoseph Koshy 		else if (KWMATCH(p, IAF_KW_ANYTHREAD))
7120cfab8ddSJoseph Koshy 			pmc_config->pm_md.pm_iaf.pm_iaf_flags |= IAF_ANY;
7130cfab8ddSJoseph Koshy 		else
7140cfab8ddSJoseph Koshy 			return (-1);
7150cfab8ddSJoseph Koshy 	}
7160cfab8ddSJoseph Koshy 
7170cfab8ddSJoseph Koshy 	return (0);
7180cfab8ddSJoseph Koshy }
7190cfab8ddSJoseph Koshy 
7200cfab8ddSJoseph Koshy /*
7210cfab8ddSJoseph Koshy  * Core/Core2 support.
7220cfab8ddSJoseph Koshy  */
7230cfab8ddSJoseph Koshy 
7240cfab8ddSJoseph Koshy #define	IAP_KW_AGENT		"agent"
7250cfab8ddSJoseph Koshy #define	IAP_KW_ANYTHREAD	"anythread"
7260cfab8ddSJoseph Koshy #define	IAP_KW_CACHESTATE	"cachestate"
7270cfab8ddSJoseph Koshy #define	IAP_KW_CMASK		"cmask"
7280cfab8ddSJoseph Koshy #define	IAP_KW_CORE		"core"
7290cfab8ddSJoseph Koshy #define	IAP_KW_EDGE		"edge"
7300cfab8ddSJoseph Koshy #define	IAP_KW_INV		"inv"
7310cfab8ddSJoseph Koshy #define	IAP_KW_OS		"os"
7320cfab8ddSJoseph Koshy #define	IAP_KW_PREFETCH		"prefetch"
7330cfab8ddSJoseph Koshy #define	IAP_KW_SNOOPRESPONSE	"snoopresponse"
7340cfab8ddSJoseph Koshy #define	IAP_KW_SNOOPTYPE	"snooptype"
7350cfab8ddSJoseph Koshy #define	IAP_KW_TRANSITION	"trans"
7360cfab8ddSJoseph Koshy #define	IAP_KW_USR		"usr"
7371fa7f10bSFabien Thomas #define	IAP_KW_RSP		"rsp"
7380cfab8ddSJoseph Koshy 
7390cfab8ddSJoseph Koshy static struct pmc_masks iap_core_mask[] = {
7400cfab8ddSJoseph Koshy 	PMCMASK(all,	(0x3 << 14)),
7410cfab8ddSJoseph Koshy 	PMCMASK(this,	(0x1 << 14)),
7420cfab8ddSJoseph Koshy 	NULLMASK
7430cfab8ddSJoseph Koshy };
7440cfab8ddSJoseph Koshy 
7450cfab8ddSJoseph Koshy static struct pmc_masks iap_agent_mask[] = {
7460cfab8ddSJoseph Koshy 	PMCMASK(this,	0),
7470cfab8ddSJoseph Koshy 	PMCMASK(any,	(0x1 << 13)),
7480cfab8ddSJoseph Koshy 	NULLMASK
7490cfab8ddSJoseph Koshy };
7500cfab8ddSJoseph Koshy 
7510cfab8ddSJoseph Koshy static struct pmc_masks iap_prefetch_mask[] = {
7520cfab8ddSJoseph Koshy 	PMCMASK(both,		(0x3 << 12)),
7530cfab8ddSJoseph Koshy 	PMCMASK(only,		(0x1 << 12)),
7540cfab8ddSJoseph Koshy 	PMCMASK(exclude,	0),
7550cfab8ddSJoseph Koshy 	NULLMASK
7560cfab8ddSJoseph Koshy };
7570cfab8ddSJoseph Koshy 
7580cfab8ddSJoseph Koshy static struct pmc_masks iap_cachestate_mask[] = {
7590cfab8ddSJoseph Koshy 	PMCMASK(i,		(1 <<  8)),
7600cfab8ddSJoseph Koshy 	PMCMASK(s,		(1 <<  9)),
7610cfab8ddSJoseph Koshy 	PMCMASK(e,		(1 << 10)),
7620cfab8ddSJoseph Koshy 	PMCMASK(m,		(1 << 11)),
7630cfab8ddSJoseph Koshy 	NULLMASK
7640cfab8ddSJoseph Koshy };
7650cfab8ddSJoseph Koshy 
7660cfab8ddSJoseph Koshy static struct pmc_masks iap_snoopresponse_mask[] = {
7670cfab8ddSJoseph Koshy 	PMCMASK(clean,		(1 << 8)),
7680cfab8ddSJoseph Koshy 	PMCMASK(hit,		(1 << 9)),
7690cfab8ddSJoseph Koshy 	PMCMASK(hitm,		(1 << 11)),
7700cfab8ddSJoseph Koshy 	NULLMASK
7710cfab8ddSJoseph Koshy };
7720cfab8ddSJoseph Koshy 
7730cfab8ddSJoseph Koshy static struct pmc_masks iap_snooptype_mask[] = {
7740cfab8ddSJoseph Koshy 	PMCMASK(cmp2s,		(1 << 8)),
7750cfab8ddSJoseph Koshy 	PMCMASK(cmp2i,		(1 << 9)),
7760cfab8ddSJoseph Koshy 	NULLMASK
7770cfab8ddSJoseph Koshy };
7780cfab8ddSJoseph Koshy 
7790cfab8ddSJoseph Koshy static struct pmc_masks iap_transition_mask[] = {
7800cfab8ddSJoseph Koshy 	PMCMASK(any,		0x00),
7810cfab8ddSJoseph Koshy 	PMCMASK(frequency,	0x10),
7820cfab8ddSJoseph Koshy 	NULLMASK
7830cfab8ddSJoseph Koshy };
7840cfab8ddSJoseph Koshy 
7851e862e5aSFabien Thomas static struct pmc_masks iap_rsp_mask_i7_wm[] = {
7861fa7f10bSFabien Thomas 	PMCMASK(DMND_DATA_RD,		(1 <<  0)),
7871fa7f10bSFabien Thomas 	PMCMASK(DMND_RFO,		(1 <<  1)),
7881fa7f10bSFabien Thomas 	PMCMASK(DMND_IFETCH,		(1 <<  2)),
7891fa7f10bSFabien Thomas 	PMCMASK(WB,			(1 <<  3)),
7901fa7f10bSFabien Thomas 	PMCMASK(PF_DATA_RD,		(1 <<  4)),
7911fa7f10bSFabien Thomas 	PMCMASK(PF_RFO,			(1 <<  5)),
7921fa7f10bSFabien Thomas 	PMCMASK(PF_IFETCH,		(1 <<  6)),
7931fa7f10bSFabien Thomas 	PMCMASK(OTHER,			(1 <<  7)),
7941fa7f10bSFabien Thomas 	PMCMASK(UNCORE_HIT,		(1 <<  8)),
7951fa7f10bSFabien Thomas 	PMCMASK(OTHER_CORE_HIT_SNP,	(1 <<  9)),
7961fa7f10bSFabien Thomas 	PMCMASK(OTHER_CORE_HITM,	(1 << 10)),
7971fa7f10bSFabien Thomas 	PMCMASK(REMOTE_CACHE_FWD,	(1 << 12)),
7981fa7f10bSFabien Thomas 	PMCMASK(REMOTE_DRAM,		(1 << 13)),
7991fa7f10bSFabien Thomas 	PMCMASK(LOCAL_DRAM,		(1 << 14)),
8001fa7f10bSFabien Thomas 	PMCMASK(NON_DRAM,		(1 << 15)),
8011fa7f10bSFabien Thomas 	NULLMASK
8021fa7f10bSFabien Thomas };
8031fa7f10bSFabien Thomas 
804fabe02f5SSean Bruno static struct pmc_masks iap_rsp_mask_sb_sbx_ib[] = {
8051e862e5aSFabien Thomas 	PMCMASK(REQ_DMND_DATA_RD,	(1ULL <<  0)),
8061e862e5aSFabien Thomas 	PMCMASK(REQ_DMND_RFO,		(1ULL <<  1)),
8071e862e5aSFabien Thomas 	PMCMASK(REQ_DMND_IFETCH,	(1ULL <<  2)),
8081e862e5aSFabien Thomas 	PMCMASK(REQ_WB,			(1ULL <<  3)),
8091e862e5aSFabien Thomas 	PMCMASK(REQ_PF_DATA_RD,		(1ULL <<  4)),
8101e862e5aSFabien Thomas 	PMCMASK(REQ_PF_RFO,		(1ULL <<  5)),
8111e862e5aSFabien Thomas 	PMCMASK(REQ_PF_IFETCH,		(1ULL <<  6)),
8121e862e5aSFabien Thomas 	PMCMASK(REQ_PF_LLC_DATA_RD,	(1ULL <<  7)),
8131e862e5aSFabien Thomas 	PMCMASK(REQ_PF_LLC_RFO,		(1ULL <<  8)),
8141e862e5aSFabien Thomas 	PMCMASK(REQ_PF_LLC_IFETCH,	(1ULL <<  9)),
8151e862e5aSFabien Thomas 	PMCMASK(REQ_BUS_LOCKS,		(1ULL << 10)),
8161e862e5aSFabien Thomas 	PMCMASK(REQ_STRM_ST,		(1ULL << 11)),
8171e862e5aSFabien Thomas 	PMCMASK(REQ_OTHER,		(1ULL << 15)),
8181e862e5aSFabien Thomas 	PMCMASK(RES_ANY,		(1ULL << 16)),
8191e862e5aSFabien Thomas 	PMCMASK(RES_SUPPLIER_SUPP,	(1ULL << 17)),
8201e862e5aSFabien Thomas 	PMCMASK(RES_SUPPLIER_LLC_HITM,	(1ULL << 18)),
8211e862e5aSFabien Thomas 	PMCMASK(RES_SUPPLIER_LLC_HITE,	(1ULL << 19)),
8221e862e5aSFabien Thomas 	PMCMASK(RES_SUPPLIER_LLC_HITS,	(1ULL << 20)),
8231e862e5aSFabien Thomas 	PMCMASK(RES_SUPPLIER_LLC_HITF,	(1ULL << 21)),
8241e862e5aSFabien Thomas 	PMCMASK(RES_SUPPLIER_LOCAL,	(1ULL << 22)),
825cdfd0cc8SSean Bruno 	PMCMASK(RES_SNOOP_SNP_NONE,	(1ULL << 31)),
8261e862e5aSFabien Thomas 	PMCMASK(RES_SNOOP_SNP_NO_NEEDED,(1ULL << 32)),
8271e862e5aSFabien Thomas 	PMCMASK(RES_SNOOP_SNP_MISS,	(1ULL << 33)),
8281e862e5aSFabien Thomas 	PMCMASK(RES_SNOOP_HIT_NO_FWD,	(1ULL << 34)),
8291e862e5aSFabien Thomas 	PMCMASK(RES_SNOOP_HIT_FWD,	(1ULL << 35)),
8301e862e5aSFabien Thomas 	PMCMASK(RES_SNOOP_HITM,		(1ULL << 36)),
8311e862e5aSFabien Thomas 	PMCMASK(RES_NON_DRAM,		(1ULL << 37)),
8321e862e5aSFabien Thomas 	NULLMASK
8331e862e5aSFabien Thomas };
8341e862e5aSFabien Thomas 
835cc0c1555SSean Bruno static struct pmc_masks iap_rsp_mask_haswell[] = {
836cc0c1555SSean Bruno 	PMCMASK(REQ_DMND_DATA_RD,	(1ULL <<  0)),
837cc0c1555SSean Bruno 	PMCMASK(REQ_DMND_RFO,		(1ULL <<  1)),
838cc0c1555SSean Bruno 	PMCMASK(REQ_DMND_IFETCH,	(1ULL <<  2)),
839cc0c1555SSean Bruno 	PMCMASK(REQ_PF_DATA_RD,		(1ULL <<  4)),
840cc0c1555SSean Bruno 	PMCMASK(REQ_PF_RFO,		(1ULL <<  5)),
841cc0c1555SSean Bruno 	PMCMASK(REQ_PF_IFETCH,		(1ULL <<  6)),
842cc0c1555SSean Bruno 	PMCMASK(REQ_OTHER,		(1ULL << 15)),
843cc0c1555SSean Bruno 	PMCMASK(RES_ANY,		(1ULL << 16)),
844cc0c1555SSean Bruno 	PMCMASK(RES_SUPPLIER_SUPP,	(1ULL << 17)),
845cc0c1555SSean Bruno 	PMCMASK(RES_SUPPLIER_LLC_HITM,	(1ULL << 18)),
846cc0c1555SSean Bruno 	PMCMASK(RES_SUPPLIER_LLC_HITE,	(1ULL << 19)),
847cc0c1555SSean Bruno 	PMCMASK(RES_SUPPLIER_LLC_HITS,	(1ULL << 20)),
848cc0c1555SSean Bruno 	PMCMASK(RES_SUPPLIER_LLC_HITF,	(1ULL << 21)),
849cc0c1555SSean Bruno 	PMCMASK(RES_SUPPLIER_LOCAL,	(1ULL << 22)),
850cc0c1555SSean Bruno 	PMCMASK(RES_SNOOP_SNP_NONE,	(1ULL << 31)),
851cc0c1555SSean Bruno 	PMCMASK(RES_SNOOP_SNP_NO_NEEDED,(1ULL << 32)),
852cc0c1555SSean Bruno 	PMCMASK(RES_SNOOP_SNP_MISS,	(1ULL << 33)),
853cc0c1555SSean Bruno 	PMCMASK(RES_SNOOP_HIT_NO_FWD,	(1ULL << 34)),
854cc0c1555SSean Bruno 	PMCMASK(RES_SNOOP_HIT_FWD,	(1ULL << 35)),
855cc0c1555SSean Bruno 	PMCMASK(RES_SNOOP_HITM,		(1ULL << 36)),
856cc0c1555SSean Bruno 	PMCMASK(RES_NON_DRAM,		(1ULL << 37)),
857cc0c1555SSean Bruno 	NULLMASK
858cc0c1555SSean Bruno };
859cc0c1555SSean Bruno 
8600cfab8ddSJoseph Koshy static int
8610cfab8ddSJoseph Koshy iap_allocate_pmc(enum pmc_event pe, char *ctrspec,
8620cfab8ddSJoseph Koshy     struct pmc_op_pmcallocate *pmc_config)
8630cfab8ddSJoseph Koshy {
8640cfab8ddSJoseph Koshy 	char *e, *p, *q;
8651e862e5aSFabien Thomas 	uint64_t cachestate, evmask, rsp;
8660cfab8ddSJoseph Koshy 	int count, n;
8670cfab8ddSJoseph Koshy 
8680cfab8ddSJoseph Koshy 	pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE |
8690cfab8ddSJoseph Koshy 	    PMC_CAP_QUALIFIER);
8700cfab8ddSJoseph Koshy 	pmc_config->pm_md.pm_iap.pm_iap_config = 0;
8710cfab8ddSJoseph Koshy 
8721fa7f10bSFabien Thomas 	cachestate = evmask = rsp = 0;
8730cfab8ddSJoseph Koshy 
8740cfab8ddSJoseph Koshy 	/* Parse additional modifiers if present */
8750cfab8ddSJoseph Koshy 	while ((p = strsep(&ctrspec, ",")) != NULL) {
8760cfab8ddSJoseph Koshy 
8770cfab8ddSJoseph Koshy 		n = 0;
8780cfab8ddSJoseph Koshy 		if (KWPREFIXMATCH(p, IAP_KW_CMASK "=")) {
8790cfab8ddSJoseph Koshy 			q = strchr(p, '=');
8800cfab8ddSJoseph Koshy 			if (*++q == '\0') /* skip '=' */
8810cfab8ddSJoseph Koshy 				return (-1);
8820cfab8ddSJoseph Koshy 			count = strtol(q, &e, 0);
8830cfab8ddSJoseph Koshy 			if (e == q || *e != '\0')
8840cfab8ddSJoseph Koshy 				return (-1);
8850cfab8ddSJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_THRESHOLD;
8860cfab8ddSJoseph Koshy 			pmc_config->pm_md.pm_iap.pm_iap_config |=
8870cfab8ddSJoseph Koshy 			    IAP_CMASK(count);
8880cfab8ddSJoseph Koshy 		} else if (KWMATCH(p, IAP_KW_EDGE)) {
8890cfab8ddSJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_EDGE;
8900cfab8ddSJoseph Koshy 		} else if (KWMATCH(p, IAP_KW_INV)) {
8910cfab8ddSJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_INVERT;
8920cfab8ddSJoseph Koshy 		} else if (KWMATCH(p, IAP_KW_OS)) {
8930cfab8ddSJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_SYSTEM;
8940cfab8ddSJoseph Koshy 		} else if (KWMATCH(p, IAP_KW_USR)) {
8950cfab8ddSJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_USER;
8960cfab8ddSJoseph Koshy 		} else if (KWMATCH(p, IAP_KW_ANYTHREAD)) {
8970cfab8ddSJoseph Koshy 			pmc_config->pm_md.pm_iap.pm_iap_config |= IAP_ANY;
898b47ea38eSJoseph Koshy 		} else if (KWPREFIXMATCH(p, IAP_KW_CORE "=")) {
8990cfab8ddSJoseph Koshy 			n = pmc_parse_mask(iap_core_mask, p, &evmask);
9000cfab8ddSJoseph Koshy 			if (n != 1)
9010cfab8ddSJoseph Koshy 				return (-1);
902b47ea38eSJoseph Koshy 		} else if (KWPREFIXMATCH(p, IAP_KW_AGENT "=")) {
9030cfab8ddSJoseph Koshy 			n = pmc_parse_mask(iap_agent_mask, p, &evmask);
9040cfab8ddSJoseph Koshy 			if (n != 1)
9050cfab8ddSJoseph Koshy 				return (-1);
906b47ea38eSJoseph Koshy 		} else if (KWPREFIXMATCH(p, IAP_KW_PREFETCH "=")) {
9070cfab8ddSJoseph Koshy 			n = pmc_parse_mask(iap_prefetch_mask, p, &evmask);
9080cfab8ddSJoseph Koshy 			if (n != 1)
9090cfab8ddSJoseph Koshy 				return (-1);
910b47ea38eSJoseph Koshy 		} else if (KWPREFIXMATCH(p, IAP_KW_CACHESTATE "=")) {
9110cfab8ddSJoseph Koshy 			n = pmc_parse_mask(iap_cachestate_mask, p, &cachestate);
9120cfab8ddSJoseph Koshy 		} else if (cpu_info.pm_cputype == PMC_CPU_INTEL_CORE &&
913b47ea38eSJoseph Koshy 		    KWPREFIXMATCH(p, IAP_KW_TRANSITION "=")) {
9140cfab8ddSJoseph Koshy 			n = pmc_parse_mask(iap_transition_mask, p, &evmask);
9150cfab8ddSJoseph Koshy 			if (n != 1)
9160cfab8ddSJoseph Koshy 				return (-1);
9170cfab8ddSJoseph Koshy 		} else if (cpu_info.pm_cputype == PMC_CPU_INTEL_ATOM ||
918e8f021a3SHiren Panchasara 		    cpu_info.pm_cputype == PMC_CPU_INTEL_ATOM_SILVERMONT ||
919b4d091f3SJoseph Koshy 		    cpu_info.pm_cputype == PMC_CPU_INTEL_CORE2 ||
9201fa7f10bSFabien Thomas 		    cpu_info.pm_cputype == PMC_CPU_INTEL_CORE2EXTREME) {
921b47ea38eSJoseph Koshy 			if (KWPREFIXMATCH(p, IAP_KW_SNOOPRESPONSE "=")) {
9220cfab8ddSJoseph Koshy 				n = pmc_parse_mask(iap_snoopresponse_mask, p,
9230cfab8ddSJoseph Koshy 				    &evmask);
924b47ea38eSJoseph Koshy 			} else if (KWPREFIXMATCH(p, IAP_KW_SNOOPTYPE "=")) {
9250cfab8ddSJoseph Koshy 				n = pmc_parse_mask(iap_snooptype_mask, p,
9260cfab8ddSJoseph Koshy 				    &evmask);
9270cfab8ddSJoseph Koshy 			} else
9280cfab8ddSJoseph Koshy 				return (-1);
9291fa7f10bSFabien Thomas 		} else if (cpu_info.pm_cputype == PMC_CPU_INTEL_COREI7 ||
93049fe48abSKonstantin Belousov 		    cpu_info.pm_cputype == PMC_CPU_INTEL_WESTMERE ||
93149fe48abSKonstantin Belousov 		    cpu_info.pm_cputype == PMC_CPU_INTEL_NEHALEM_EX ||
93249fe48abSKonstantin Belousov 		    cpu_info.pm_cputype == PMC_CPU_INTEL_WESTMERE_EX) {
9331fa7f10bSFabien Thomas 			if (KWPREFIXMATCH(p, IAP_KW_RSP "=")) {
9341e862e5aSFabien Thomas 				n = pmc_parse_mask(iap_rsp_mask_i7_wm, p, &rsp);
9351e862e5aSFabien Thomas 			} else
9361e862e5aSFabien Thomas 				return (-1);
9371e862e5aSFabien Thomas 		} else if (cpu_info.pm_cputype == PMC_CPU_INTEL_SANDYBRIDGE ||
938fabe02f5SSean Bruno 		    cpu_info.pm_cputype == PMC_CPU_INTEL_SANDYBRIDGE_XEON ||
9393f929d8cSSean Bruno 			cpu_info.pm_cputype == PMC_CPU_INTEL_IVYBRIDGE ||
9403f929d8cSSean Bruno 			cpu_info.pm_cputype == PMC_CPU_INTEL_IVYBRIDGE_XEON ) {
9411e862e5aSFabien Thomas 			if (KWPREFIXMATCH(p, IAP_KW_RSP "=")) {
942fabe02f5SSean Bruno 				n = pmc_parse_mask(iap_rsp_mask_sb_sbx_ib, p, &rsp);
9431fa7f10bSFabien Thomas 			} else
9441fa7f10bSFabien Thomas 				return (-1);
945d95b3509SRandall Stewart 		} else if (cpu_info.pm_cputype == PMC_CPU_INTEL_HASWELL ||
946d95b3509SRandall Stewart 			cpu_info.pm_cputype == PMC_CPU_INTEL_HASWELL_XEON) {
947cc0c1555SSean Bruno 			if (KWPREFIXMATCH(p, IAP_KW_RSP "=")) {
948cc0c1555SSean Bruno 				n = pmc_parse_mask(iap_rsp_mask_haswell, p, &rsp);
949cc0c1555SSean Bruno 			} else
950cc0c1555SSean Bruno 				return (-1);
9510cfab8ddSJoseph Koshy 		} else
9520cfab8ddSJoseph Koshy 			return (-1);
9530cfab8ddSJoseph Koshy 
9540cfab8ddSJoseph Koshy 		if (n < 0)	/* Parsing failed. */
9550cfab8ddSJoseph Koshy 			return (-1);
9560cfab8ddSJoseph Koshy 	}
9570cfab8ddSJoseph Koshy 
9580cfab8ddSJoseph Koshy 	pmc_config->pm_md.pm_iap.pm_iap_config |= evmask;
9590cfab8ddSJoseph Koshy 
9600cfab8ddSJoseph Koshy 	/*
9610cfab8ddSJoseph Koshy 	 * If the event requires a 'cachestate' qualifier but was not
9620cfab8ddSJoseph Koshy 	 * specified by the user, use a sensible default.
9630cfab8ddSJoseph Koshy 	 */
9640cfab8ddSJoseph Koshy 	switch (pe) {
9650cfab8ddSJoseph Koshy 	case PMC_EV_IAP_EVENT_28H: /* Core, Core2, Atom */
9660cfab8ddSJoseph Koshy 	case PMC_EV_IAP_EVENT_29H: /* Core, Core2, Atom */
9670cfab8ddSJoseph Koshy 	case PMC_EV_IAP_EVENT_2AH: /* Core, Core2, Atom */
9680cfab8ddSJoseph Koshy 	case PMC_EV_IAP_EVENT_2BH: /* Atom, Core2 */
9690cfab8ddSJoseph Koshy 	case PMC_EV_IAP_EVENT_2EH: /* Core, Core2, Atom */
9700cfab8ddSJoseph Koshy 	case PMC_EV_IAP_EVENT_30H: /* Core, Core2, Atom */
9710cfab8ddSJoseph Koshy 	case PMC_EV_IAP_EVENT_32H: /* Core */
9720cfab8ddSJoseph Koshy 	case PMC_EV_IAP_EVENT_40H: /* Core */
9730cfab8ddSJoseph Koshy 	case PMC_EV_IAP_EVENT_41H: /* Core */
9740cfab8ddSJoseph Koshy 	case PMC_EV_IAP_EVENT_42H: /* Core, Core2, Atom */
9750cfab8ddSJoseph Koshy 		if (cachestate == 0)
9760cfab8ddSJoseph Koshy 			cachestate = (0xF << 8);
977aa1b887bSRyan Stone 		break;
978aa1b887bSRyan Stone 	case PMC_EV_IAP_EVENT_77H: /* Atom */
979aa1b887bSRyan Stone 		/* IAP_EVENT_77H only accepts a cachestate qualifier on the
980aa1b887bSRyan Stone 		 * Atom processor
981aa1b887bSRyan Stone 		 */
982aa1b887bSRyan Stone 		if(cpu_info.pm_cputype == PMC_CPU_INTEL_ATOM && cachestate == 0)
983aa1b887bSRyan Stone 			cachestate = (0xF << 8);
984aa1b887bSRyan Stone 	    break;
9850cfab8ddSJoseph Koshy 	default:
9860cfab8ddSJoseph Koshy 		break;
9870cfab8ddSJoseph Koshy 	}
9880cfab8ddSJoseph Koshy 
9890cfab8ddSJoseph Koshy 	pmc_config->pm_md.pm_iap.pm_iap_config |= cachestate;
9901fa7f10bSFabien Thomas 	pmc_config->pm_md.pm_iap.pm_iap_rsp = rsp;
9911fa7f10bSFabien Thomas 
9921fa7f10bSFabien Thomas 	return (0);
9931fa7f10bSFabien Thomas }
9941fa7f10bSFabien Thomas 
9951fa7f10bSFabien Thomas /*
9961fa7f10bSFabien Thomas  * Intel Uncore.
9971fa7f10bSFabien Thomas  */
9981fa7f10bSFabien Thomas 
9991fa7f10bSFabien Thomas static int
10001fa7f10bSFabien Thomas ucf_allocate_pmc(enum pmc_event pe, char *ctrspec,
10011fa7f10bSFabien Thomas     struct pmc_op_pmcallocate *pmc_config)
10021fa7f10bSFabien Thomas {
10031fa7f10bSFabien Thomas 	(void) pe;
10041fa7f10bSFabien Thomas 	(void) ctrspec;
10051fa7f10bSFabien Thomas 
10061fa7f10bSFabien Thomas 	pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE);
10071fa7f10bSFabien Thomas 	pmc_config->pm_md.pm_ucf.pm_ucf_flags = 0;
10081fa7f10bSFabien Thomas 
10091fa7f10bSFabien Thomas 	return (0);
10101fa7f10bSFabien Thomas }
10111fa7f10bSFabien Thomas 
10121fa7f10bSFabien Thomas #define	UCP_KW_CMASK		"cmask"
10131fa7f10bSFabien Thomas #define	UCP_KW_EDGE		"edge"
10141fa7f10bSFabien Thomas #define	UCP_KW_INV		"inv"
10151fa7f10bSFabien Thomas 
10161fa7f10bSFabien Thomas static int
10171fa7f10bSFabien Thomas ucp_allocate_pmc(enum pmc_event pe, char *ctrspec,
10181fa7f10bSFabien Thomas     struct pmc_op_pmcallocate *pmc_config)
10191fa7f10bSFabien Thomas {
10201fa7f10bSFabien Thomas 	char *e, *p, *q;
10211fa7f10bSFabien Thomas 	int count, n;
10221fa7f10bSFabien Thomas 
10231fa7f10bSFabien Thomas 	(void) pe;
10241fa7f10bSFabien Thomas 
10251fa7f10bSFabien Thomas 	pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE |
10261fa7f10bSFabien Thomas 	    PMC_CAP_QUALIFIER);
10271fa7f10bSFabien Thomas 	pmc_config->pm_md.pm_ucp.pm_ucp_config = 0;
10281fa7f10bSFabien Thomas 
10291fa7f10bSFabien Thomas 	/* Parse additional modifiers if present */
10301fa7f10bSFabien Thomas 	while ((p = strsep(&ctrspec, ",")) != NULL) {
10311fa7f10bSFabien Thomas 
10321fa7f10bSFabien Thomas 		n = 0;
10331fa7f10bSFabien Thomas 		if (KWPREFIXMATCH(p, UCP_KW_CMASK "=")) {
10341fa7f10bSFabien Thomas 			q = strchr(p, '=');
10351fa7f10bSFabien Thomas 			if (*++q == '\0') /* skip '=' */
10361fa7f10bSFabien Thomas 				return (-1);
10371fa7f10bSFabien Thomas 			count = strtol(q, &e, 0);
10381fa7f10bSFabien Thomas 			if (e == q || *e != '\0')
10391fa7f10bSFabien Thomas 				return (-1);
10401fa7f10bSFabien Thomas 			pmc_config->pm_caps |= PMC_CAP_THRESHOLD;
10411fa7f10bSFabien Thomas 			pmc_config->pm_md.pm_ucp.pm_ucp_config |=
10421fa7f10bSFabien Thomas 			    UCP_CMASK(count);
10431fa7f10bSFabien Thomas 		} else if (KWMATCH(p, UCP_KW_EDGE)) {
10441fa7f10bSFabien Thomas 			pmc_config->pm_caps |= PMC_CAP_EDGE;
10451fa7f10bSFabien Thomas 		} else if (KWMATCH(p, UCP_KW_INV)) {
10461fa7f10bSFabien Thomas 			pmc_config->pm_caps |= PMC_CAP_INVERT;
10471fa7f10bSFabien Thomas 		} else
10481fa7f10bSFabien Thomas 			return (-1);
10491fa7f10bSFabien Thomas 
10501fa7f10bSFabien Thomas 		if (n < 0)	/* Parsing failed. */
10511fa7f10bSFabien Thomas 			return (-1);
10521fa7f10bSFabien Thomas 	}
10530cfab8ddSJoseph Koshy 
10540cfab8ddSJoseph Koshy 	return (0);
10550cfab8ddSJoseph Koshy }
10560cfab8ddSJoseph Koshy 
10570cfab8ddSJoseph Koshy /*
1058f263522aSJoseph Koshy  * AMD K8 PMCs.
1059f263522aSJoseph Koshy  *
1060f263522aSJoseph Koshy  * These are very similar to AMD K7 PMCs, but support more kinds of
1061f263522aSJoseph Koshy  * events.
1062f263522aSJoseph Koshy  */
1063f263522aSJoseph Koshy 
1064f263522aSJoseph Koshy static struct pmc_event_alias k8_aliases[] = {
1065f263522aSJoseph Koshy 	EV_ALIAS("branches",		"k8-fr-retired-taken-branches"),
1066f263522aSJoseph Koshy 	EV_ALIAS("branch-mispredicts",
1067f263522aSJoseph Koshy 	    "k8-fr-retired-taken-branches-mispredicted"),
1068f263522aSJoseph Koshy 	EV_ALIAS("cycles",		"tsc"),
1069f263522aSJoseph Koshy 	EV_ALIAS("dc-misses",		"k8-dc-miss"),
1070f263522aSJoseph Koshy 	EV_ALIAS("ic-misses",		"k8-ic-miss"),
1071f263522aSJoseph Koshy 	EV_ALIAS("instructions",	"k8-fr-retired-x86-instructions"),
1072f263522aSJoseph Koshy 	EV_ALIAS("interrupts",		"k8-fr-taken-hardware-interrupts"),
1073177a2f22SJoseph Koshy 	EV_ALIAS("unhalted-cycles",	"k8-bu-cpu-clk-unhalted"),
1074f263522aSJoseph Koshy 	EV_ALIAS(NULL, NULL)
1075f263522aSJoseph Koshy };
1076f263522aSJoseph Koshy 
1077f263522aSJoseph Koshy #define	__K8MASK(N,V) PMCMASK(N,(1 << (V)))
1078f263522aSJoseph Koshy 
1079f263522aSJoseph Koshy /*
1080f263522aSJoseph Koshy  * Parsing tables
1081f263522aSJoseph Koshy  */
1082f263522aSJoseph Koshy 
1083f263522aSJoseph Koshy /* fp dispatched fpu ops */
1084f263522aSJoseph Koshy static const struct pmc_masks k8_mask_fdfo[] = {
1085f263522aSJoseph Koshy 	__K8MASK(add-pipe-excluding-junk-ops,	0),
1086f263522aSJoseph Koshy 	__K8MASK(multiply-pipe-excluding-junk-ops,	1),
1087f263522aSJoseph Koshy 	__K8MASK(store-pipe-excluding-junk-ops,	2),
1088f263522aSJoseph Koshy 	__K8MASK(add-pipe-junk-ops,		3),
1089f263522aSJoseph Koshy 	__K8MASK(multiply-pipe-junk-ops,	4),
1090f263522aSJoseph Koshy 	__K8MASK(store-pipe-junk-ops,		5),
1091f263522aSJoseph Koshy 	NULLMASK
1092f263522aSJoseph Koshy };
1093f263522aSJoseph Koshy 
1094f263522aSJoseph Koshy /* ls segment register loads */
1095f263522aSJoseph Koshy static const struct pmc_masks k8_mask_lsrl[] = {
1096f263522aSJoseph Koshy 	__K8MASK(es,	0),
1097f263522aSJoseph Koshy 	__K8MASK(cs,	1),
1098f263522aSJoseph Koshy 	__K8MASK(ss,	2),
1099f263522aSJoseph Koshy 	__K8MASK(ds,	3),
1100f263522aSJoseph Koshy 	__K8MASK(fs,	4),
1101f263522aSJoseph Koshy 	__K8MASK(gs,	5),
1102f263522aSJoseph Koshy 	__K8MASK(hs,	6),
1103f263522aSJoseph Koshy 	NULLMASK
1104f263522aSJoseph Koshy };
1105f263522aSJoseph Koshy 
1106f263522aSJoseph Koshy /* ls locked operation */
1107f263522aSJoseph Koshy static const struct pmc_masks k8_mask_llo[] = {
1108f263522aSJoseph Koshy 	__K8MASK(locked-instructions,	0),
1109f263522aSJoseph Koshy 	__K8MASK(cycles-in-request,	1),
1110f263522aSJoseph Koshy 	__K8MASK(cycles-to-complete,	2),
1111f263522aSJoseph Koshy 	NULLMASK
1112f263522aSJoseph Koshy };
1113f263522aSJoseph Koshy 
1114f263522aSJoseph Koshy /* dc refill from {l2,system} and dc copyback */
1115f263522aSJoseph Koshy static const struct pmc_masks k8_mask_dc[] = {
1116f263522aSJoseph Koshy 	__K8MASK(invalid,	0),
1117f263522aSJoseph Koshy 	__K8MASK(shared,	1),
1118f263522aSJoseph Koshy 	__K8MASK(exclusive,	2),
1119f263522aSJoseph Koshy 	__K8MASK(owner,		3),
1120f263522aSJoseph Koshy 	__K8MASK(modified,	4),
1121f263522aSJoseph Koshy 	NULLMASK
1122f263522aSJoseph Koshy };
1123f263522aSJoseph Koshy 
1124f263522aSJoseph Koshy /* dc one bit ecc error */
1125f263522aSJoseph Koshy static const struct pmc_masks k8_mask_dobee[] = {
1126f263522aSJoseph Koshy 	__K8MASK(scrubber,	0),
1127f263522aSJoseph Koshy 	__K8MASK(piggyback,	1),
1128f263522aSJoseph Koshy 	NULLMASK
1129f263522aSJoseph Koshy };
1130f263522aSJoseph Koshy 
1131f263522aSJoseph Koshy /* dc dispatched prefetch instructions */
1132f263522aSJoseph Koshy static const struct pmc_masks k8_mask_ddpi[] = {
1133f263522aSJoseph Koshy 	__K8MASK(load,	0),
1134f263522aSJoseph Koshy 	__K8MASK(store,	1),
1135f263522aSJoseph Koshy 	__K8MASK(nta,	2),
1136f263522aSJoseph Koshy 	NULLMASK
1137f263522aSJoseph Koshy };
1138f263522aSJoseph Koshy 
1139f263522aSJoseph Koshy /* dc dcache accesses by locks */
1140f263522aSJoseph Koshy static const struct pmc_masks k8_mask_dabl[] = {
1141f263522aSJoseph Koshy 	__K8MASK(accesses,	0),
1142f263522aSJoseph Koshy 	__K8MASK(misses,	1),
1143f263522aSJoseph Koshy 	NULLMASK
1144f263522aSJoseph Koshy };
1145f263522aSJoseph Koshy 
1146f263522aSJoseph Koshy /* bu internal l2 request */
1147f263522aSJoseph Koshy static const struct pmc_masks k8_mask_bilr[] = {
1148f263522aSJoseph Koshy 	__K8MASK(ic-fill,	0),
1149f263522aSJoseph Koshy 	__K8MASK(dc-fill,	1),
1150f263522aSJoseph Koshy 	__K8MASK(tlb-reload,	2),
1151f263522aSJoseph Koshy 	__K8MASK(tag-snoop,	3),
1152f263522aSJoseph Koshy 	__K8MASK(cancelled,	4),
1153f263522aSJoseph Koshy 	NULLMASK
1154f263522aSJoseph Koshy };
1155f263522aSJoseph Koshy 
1156f263522aSJoseph Koshy /* bu fill request l2 miss */
1157f263522aSJoseph Koshy static const struct pmc_masks k8_mask_bfrlm[] = {
1158f263522aSJoseph Koshy 	__K8MASK(ic-fill,	0),
1159f263522aSJoseph Koshy 	__K8MASK(dc-fill,	1),
1160f263522aSJoseph Koshy 	__K8MASK(tlb-reload,	2),
1161f263522aSJoseph Koshy 	NULLMASK
1162f263522aSJoseph Koshy };
1163f263522aSJoseph Koshy 
1164f263522aSJoseph Koshy /* bu fill into l2 */
1165f263522aSJoseph Koshy static const struct pmc_masks k8_mask_bfil[] = {
1166f263522aSJoseph Koshy 	__K8MASK(dirty-l2-victim,	0),
1167f263522aSJoseph Koshy 	__K8MASK(victim-from-l2,	1),
1168f263522aSJoseph Koshy 	NULLMASK
1169f263522aSJoseph Koshy };
1170f263522aSJoseph Koshy 
1171f263522aSJoseph Koshy /* fr retired fpu instructions */
1172f263522aSJoseph Koshy static const struct pmc_masks k8_mask_frfi[] = {
1173f263522aSJoseph Koshy 	__K8MASK(x87,			0),
1174f263522aSJoseph Koshy 	__K8MASK(mmx-3dnow,		1),
1175f263522aSJoseph Koshy 	__K8MASK(packed-sse-sse2,	2),
1176f263522aSJoseph Koshy 	__K8MASK(scalar-sse-sse2,	3),
1177f263522aSJoseph Koshy 	NULLMASK
1178f263522aSJoseph Koshy };
1179f263522aSJoseph Koshy 
1180f263522aSJoseph Koshy /* fr retired fastpath double op instructions */
1181f263522aSJoseph Koshy static const struct pmc_masks k8_mask_frfdoi[] = {
1182f263522aSJoseph Koshy 	__K8MASK(low-op-pos-0,		0),
1183f263522aSJoseph Koshy 	__K8MASK(low-op-pos-1,		1),
1184f263522aSJoseph Koshy 	__K8MASK(low-op-pos-2,		2),
1185f263522aSJoseph Koshy 	NULLMASK
1186f263522aSJoseph Koshy };
1187f263522aSJoseph Koshy 
1188f263522aSJoseph Koshy /* fr fpu exceptions */
1189f263522aSJoseph Koshy static const struct pmc_masks k8_mask_ffe[] = {
1190f263522aSJoseph Koshy 	__K8MASK(x87-reclass-microfaults,	0),
1191f263522aSJoseph Koshy 	__K8MASK(sse-retype-microfaults,	1),
1192f263522aSJoseph Koshy 	__K8MASK(sse-reclass-microfaults,	2),
1193f263522aSJoseph Koshy 	__K8MASK(sse-and-x87-microtraps,	3),
1194f263522aSJoseph Koshy 	NULLMASK
1195f263522aSJoseph Koshy };
1196f263522aSJoseph Koshy 
1197f263522aSJoseph Koshy /* nb memory controller page access event */
1198f263522aSJoseph Koshy static const struct pmc_masks k8_mask_nmcpae[] = {
1199f263522aSJoseph Koshy 	__K8MASK(page-hit,	0),
1200f263522aSJoseph Koshy 	__K8MASK(page-miss,	1),
1201f263522aSJoseph Koshy 	__K8MASK(page-conflict,	2),
1202f263522aSJoseph Koshy 	NULLMASK
1203f263522aSJoseph Koshy };
1204f263522aSJoseph Koshy 
1205f263522aSJoseph Koshy /* nb memory controller turnaround */
1206f263522aSJoseph Koshy static const struct pmc_masks k8_mask_nmct[] = {
1207f263522aSJoseph Koshy 	__K8MASK(dimm-turnaround,		0),
1208f263522aSJoseph Koshy 	__K8MASK(read-to-write-turnaround,	1),
1209f263522aSJoseph Koshy 	__K8MASK(write-to-read-turnaround,	2),
1210f263522aSJoseph Koshy 	NULLMASK
1211f263522aSJoseph Koshy };
1212f263522aSJoseph Koshy 
1213f263522aSJoseph Koshy /* nb memory controller bypass saturation */
1214f263522aSJoseph Koshy static const struct pmc_masks k8_mask_nmcbs[] = {
1215f263522aSJoseph Koshy 	__K8MASK(memory-controller-hi-pri-bypass,	0),
1216f263522aSJoseph Koshy 	__K8MASK(memory-controller-lo-pri-bypass,	1),
1217f263522aSJoseph Koshy 	__K8MASK(dram-controller-interface-bypass,	2),
1218f263522aSJoseph Koshy 	__K8MASK(dram-controller-queue-bypass,		3),
1219f263522aSJoseph Koshy 	NULLMASK
1220f263522aSJoseph Koshy };
1221f263522aSJoseph Koshy 
1222f263522aSJoseph Koshy /* nb sized commands */
1223f263522aSJoseph Koshy static const struct pmc_masks k8_mask_nsc[] = {
1224f263522aSJoseph Koshy 	__K8MASK(nonpostwrszbyte,	0),
1225f263522aSJoseph Koshy 	__K8MASK(nonpostwrszdword,	1),
1226f263522aSJoseph Koshy 	__K8MASK(postwrszbyte,		2),
1227f263522aSJoseph Koshy 	__K8MASK(postwrszdword,		3),
1228f263522aSJoseph Koshy 	__K8MASK(rdszbyte,		4),
1229f263522aSJoseph Koshy 	__K8MASK(rdszdword,		5),
1230f263522aSJoseph Koshy 	__K8MASK(rdmodwr,		6),
1231f263522aSJoseph Koshy 	NULLMASK
1232f263522aSJoseph Koshy };
1233f263522aSJoseph Koshy 
1234f263522aSJoseph Koshy /* nb probe result */
1235f263522aSJoseph Koshy static const struct pmc_masks k8_mask_npr[] = {
1236f263522aSJoseph Koshy 	__K8MASK(probe-miss,		0),
1237f263522aSJoseph Koshy 	__K8MASK(probe-hit,		1),
1238f263522aSJoseph Koshy 	__K8MASK(probe-hit-dirty-no-memory-cancel, 2),
1239f263522aSJoseph Koshy 	__K8MASK(probe-hit-dirty-with-memory-cancel, 3),
1240f263522aSJoseph Koshy 	NULLMASK
1241f263522aSJoseph Koshy };
1242f263522aSJoseph Koshy 
1243f263522aSJoseph Koshy /* nb hypertransport bus bandwidth */
1244f263522aSJoseph Koshy static const struct pmc_masks k8_mask_nhbb[] = { /* HT bus bandwidth */
1245f263522aSJoseph Koshy 	__K8MASK(command,	0),
1246f263522aSJoseph Koshy 	__K8MASK(data,	1),
1247f263522aSJoseph Koshy 	__K8MASK(buffer-release, 2),
1248f263522aSJoseph Koshy 	__K8MASK(nop,	3),
1249f263522aSJoseph Koshy 	NULLMASK
1250f263522aSJoseph Koshy };
1251f263522aSJoseph Koshy 
1252f263522aSJoseph Koshy #undef	__K8MASK
1253f263522aSJoseph Koshy 
1254f263522aSJoseph Koshy #define	K8_KW_COUNT	"count"
1255f263522aSJoseph Koshy #define	K8_KW_EDGE	"edge"
1256f263522aSJoseph Koshy #define	K8_KW_INV	"inv"
1257f263522aSJoseph Koshy #define	K8_KW_MASK	"mask"
1258f263522aSJoseph Koshy #define	K8_KW_OS	"os"
1259f263522aSJoseph Koshy #define	K8_KW_USR	"usr"
1260f263522aSJoseph Koshy 
1261f263522aSJoseph Koshy static int
1262f263522aSJoseph Koshy k8_allocate_pmc(enum pmc_event pe, char *ctrspec,
1263f263522aSJoseph Koshy     struct pmc_op_pmcallocate *pmc_config)
1264f263522aSJoseph Koshy {
1265f263522aSJoseph Koshy 	char		*e, *p, *q;
1266f263522aSJoseph Koshy 	int		n;
12671e862e5aSFabien Thomas 	uint32_t	count;
12681e862e5aSFabien Thomas 	uint64_t	evmask;
1269f263522aSJoseph Koshy 	const struct pmc_masks	*pm, *pmask;
1270f263522aSJoseph Koshy 
1271789140c0SJoseph Koshy 	pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE);
1272f263522aSJoseph Koshy 	pmc_config->pm_md.pm_amd.pm_amd_config = 0;
1273f263522aSJoseph Koshy 
1274f263522aSJoseph Koshy 	pmask = NULL;
1275f263522aSJoseph Koshy 	evmask = 0;
1276f263522aSJoseph Koshy 
1277f263522aSJoseph Koshy #define	__K8SETMASK(M) pmask = k8_mask_##M
1278f263522aSJoseph Koshy 
1279f263522aSJoseph Koshy 	/* setup parsing tables */
1280f263522aSJoseph Koshy 	switch (pe) {
1281f263522aSJoseph Koshy 	case PMC_EV_K8_FP_DISPATCHED_FPU_OPS:
1282f263522aSJoseph Koshy 		__K8SETMASK(fdfo);
1283f263522aSJoseph Koshy 		break;
1284f263522aSJoseph Koshy 	case PMC_EV_K8_LS_SEGMENT_REGISTER_LOAD:
1285f263522aSJoseph Koshy 		__K8SETMASK(lsrl);
1286f263522aSJoseph Koshy 		break;
1287f263522aSJoseph Koshy 	case PMC_EV_K8_LS_LOCKED_OPERATION:
1288f263522aSJoseph Koshy 		__K8SETMASK(llo);
1289f263522aSJoseph Koshy 		break;
1290f263522aSJoseph Koshy 	case PMC_EV_K8_DC_REFILL_FROM_L2:
1291f263522aSJoseph Koshy 	case PMC_EV_K8_DC_REFILL_FROM_SYSTEM:
1292f263522aSJoseph Koshy 	case PMC_EV_K8_DC_COPYBACK:
1293f263522aSJoseph Koshy 		__K8SETMASK(dc);
1294f263522aSJoseph Koshy 		break;
1295f263522aSJoseph Koshy 	case PMC_EV_K8_DC_ONE_BIT_ECC_ERROR:
1296f263522aSJoseph Koshy 		__K8SETMASK(dobee);
1297f263522aSJoseph Koshy 		break;
1298f263522aSJoseph Koshy 	case PMC_EV_K8_DC_DISPATCHED_PREFETCH_INSTRUCTIONS:
1299f263522aSJoseph Koshy 		__K8SETMASK(ddpi);
1300f263522aSJoseph Koshy 		break;
1301f263522aSJoseph Koshy 	case PMC_EV_K8_DC_DCACHE_ACCESSES_BY_LOCKS:
1302f263522aSJoseph Koshy 		__K8SETMASK(dabl);
1303f263522aSJoseph Koshy 		break;
1304f263522aSJoseph Koshy 	case PMC_EV_K8_BU_INTERNAL_L2_REQUEST:
1305f263522aSJoseph Koshy 		__K8SETMASK(bilr);
1306f263522aSJoseph Koshy 		break;
1307f263522aSJoseph Koshy 	case PMC_EV_K8_BU_FILL_REQUEST_L2_MISS:
1308f263522aSJoseph Koshy 		__K8SETMASK(bfrlm);
1309f263522aSJoseph Koshy 		break;
1310f263522aSJoseph Koshy 	case PMC_EV_K8_BU_FILL_INTO_L2:
1311f263522aSJoseph Koshy 		__K8SETMASK(bfil);
1312f263522aSJoseph Koshy 		break;
1313f263522aSJoseph Koshy 	case PMC_EV_K8_FR_RETIRED_FPU_INSTRUCTIONS:
1314f263522aSJoseph Koshy 		__K8SETMASK(frfi);
1315f263522aSJoseph Koshy 		break;
1316f263522aSJoseph Koshy 	case PMC_EV_K8_FR_RETIRED_FASTPATH_DOUBLE_OP_INSTRUCTIONS:
1317f263522aSJoseph Koshy 		__K8SETMASK(frfdoi);
1318f263522aSJoseph Koshy 		break;
1319f263522aSJoseph Koshy 	case PMC_EV_K8_FR_FPU_EXCEPTIONS:
1320f263522aSJoseph Koshy 		__K8SETMASK(ffe);
1321f263522aSJoseph Koshy 		break;
1322f263522aSJoseph Koshy 	case PMC_EV_K8_NB_MEMORY_CONTROLLER_PAGE_ACCESS_EVENT:
1323f263522aSJoseph Koshy 		__K8SETMASK(nmcpae);
1324f263522aSJoseph Koshy 		break;
1325f263522aSJoseph Koshy 	case PMC_EV_K8_NB_MEMORY_CONTROLLER_TURNAROUND:
1326f263522aSJoseph Koshy 		__K8SETMASK(nmct);
1327f263522aSJoseph Koshy 		break;
1328f263522aSJoseph Koshy 	case PMC_EV_K8_NB_MEMORY_CONTROLLER_BYPASS_SATURATION:
1329f263522aSJoseph Koshy 		__K8SETMASK(nmcbs);
1330f263522aSJoseph Koshy 		break;
1331f263522aSJoseph Koshy 	case PMC_EV_K8_NB_SIZED_COMMANDS:
1332f263522aSJoseph Koshy 		__K8SETMASK(nsc);
1333f263522aSJoseph Koshy 		break;
1334f263522aSJoseph Koshy 	case PMC_EV_K8_NB_PROBE_RESULT:
1335f263522aSJoseph Koshy 		__K8SETMASK(npr);
1336f263522aSJoseph Koshy 		break;
1337f263522aSJoseph Koshy 	case PMC_EV_K8_NB_HT_BUS0_BANDWIDTH:
1338f263522aSJoseph Koshy 	case PMC_EV_K8_NB_HT_BUS1_BANDWIDTH:
1339f263522aSJoseph Koshy 	case PMC_EV_K8_NB_HT_BUS2_BANDWIDTH:
1340f263522aSJoseph Koshy 		__K8SETMASK(nhbb);
1341f263522aSJoseph Koshy 		break;
1342f263522aSJoseph Koshy 
1343f263522aSJoseph Koshy 	default:
1344f263522aSJoseph Koshy 		break;		/* no options defined */
1345f263522aSJoseph Koshy 	}
1346f263522aSJoseph Koshy 
1347f263522aSJoseph Koshy 	while ((p = strsep(&ctrspec, ",")) != NULL) {
1348f263522aSJoseph Koshy 		if (KWPREFIXMATCH(p, K8_KW_COUNT "=")) {
1349f263522aSJoseph Koshy 			q = strchr(p, '=');
1350f263522aSJoseph Koshy 			if (*++q == '\0') /* skip '=' */
1351aa342b1fSJoseph Koshy 				return (-1);
1352f263522aSJoseph Koshy 
1353f263522aSJoseph Koshy 			count = strtol(q, &e, 0);
1354f263522aSJoseph Koshy 			if (e == q || *e != '\0')
1355aa342b1fSJoseph Koshy 				return (-1);
1356f263522aSJoseph Koshy 
1357f263522aSJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_THRESHOLD;
1358f263522aSJoseph Koshy 			pmc_config->pm_md.pm_amd.pm_amd_config |=
1359f263522aSJoseph Koshy 			    AMD_PMC_TO_COUNTER(count);
1360f263522aSJoseph Koshy 
1361f263522aSJoseph Koshy 		} else if (KWMATCH(p, K8_KW_EDGE)) {
1362f263522aSJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_EDGE;
1363f263522aSJoseph Koshy 		} else if (KWMATCH(p, K8_KW_INV)) {
1364f263522aSJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_INVERT;
1365f263522aSJoseph Koshy 		} else if (KWPREFIXMATCH(p, K8_KW_MASK "=")) {
1366f263522aSJoseph Koshy 			if ((n = pmc_parse_mask(pmask, p, &evmask)) < 0)
1367aa342b1fSJoseph Koshy 				return (-1);
1368f263522aSJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_QUALIFIER;
1369f263522aSJoseph Koshy 		} else if (KWMATCH(p, K8_KW_OS)) {
1370f263522aSJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_SYSTEM;
1371f263522aSJoseph Koshy 		} else if (KWMATCH(p, K8_KW_USR)) {
1372f263522aSJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_USER;
1373f263522aSJoseph Koshy 		} else
1374aa342b1fSJoseph Koshy 			return (-1);
1375f263522aSJoseph Koshy 	}
1376f263522aSJoseph Koshy 
1377f263522aSJoseph Koshy 	/* other post processing */
1378f263522aSJoseph Koshy 	switch (pe) {
1379f263522aSJoseph Koshy 	case PMC_EV_K8_FP_DISPATCHED_FPU_OPS:
1380f263522aSJoseph Koshy 	case PMC_EV_K8_FP_CYCLES_WITH_NO_FPU_OPS_RETIRED:
1381f263522aSJoseph Koshy 	case PMC_EV_K8_FP_DISPATCHED_FPU_FAST_FLAG_OPS:
1382f263522aSJoseph Koshy 	case PMC_EV_K8_FR_RETIRED_FASTPATH_DOUBLE_OP_INSTRUCTIONS:
1383f263522aSJoseph Koshy 	case PMC_EV_K8_FR_RETIRED_FPU_INSTRUCTIONS:
1384f263522aSJoseph Koshy 	case PMC_EV_K8_FR_FPU_EXCEPTIONS:
1385f263522aSJoseph Koshy 		/* XXX only available in rev B and later */
1386f263522aSJoseph Koshy 		break;
1387f263522aSJoseph Koshy 	case PMC_EV_K8_DC_DCACHE_ACCESSES_BY_LOCKS:
1388f263522aSJoseph Koshy 		/* XXX only available in rev C and later */
1389f263522aSJoseph Koshy 		break;
1390f263522aSJoseph Koshy 	case PMC_EV_K8_LS_LOCKED_OPERATION:
1391f263522aSJoseph Koshy 		/* XXX CPU Rev A,B evmask is to be zero */
1392f263522aSJoseph Koshy 		if (evmask & (evmask - 1)) /* > 1 bit set */
1393aa342b1fSJoseph Koshy 			return (-1);
1394f263522aSJoseph Koshy 		if (evmask == 0) {
1395f263522aSJoseph Koshy 			evmask = 0x01; /* Rev C and later: #instrs */
1396f263522aSJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_QUALIFIER;
1397f263522aSJoseph Koshy 		}
1398f263522aSJoseph Koshy 		break;
1399f263522aSJoseph Koshy 	default:
1400f263522aSJoseph Koshy 		if (evmask == 0 && pmask != NULL) {
1401f263522aSJoseph Koshy 			for (pm = pmask; pm->pm_name; pm++)
1402f263522aSJoseph Koshy 				evmask |= pm->pm_value;
1403f263522aSJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_QUALIFIER;
1404f263522aSJoseph Koshy 		}
1405f263522aSJoseph Koshy 	}
1406f263522aSJoseph Koshy 
1407f263522aSJoseph Koshy 	if (pmc_config->pm_caps & PMC_CAP_QUALIFIER)
1408f263522aSJoseph Koshy 		pmc_config->pm_md.pm_amd.pm_amd_config =
1409f263522aSJoseph Koshy 		    AMD_PMC_TO_UNITMASK(evmask);
1410f263522aSJoseph Koshy 
1411aa342b1fSJoseph Koshy 	return (0);
1412f263522aSJoseph Koshy }
1413f263522aSJoseph Koshy 
1414f263522aSJoseph Koshy #endif
1415f263522aSJoseph Koshy 
141686a65549SJoseph Koshy #if defined(__amd64__) || defined(__i386__)
1417f263522aSJoseph Koshy 
1418ebccf1e3SJoseph Koshy /*
1419ebccf1e3SJoseph Koshy  * Intel P4 PMCs
1420ebccf1e3SJoseph Koshy  */
1421ebccf1e3SJoseph Koshy 
1422ebccf1e3SJoseph Koshy static struct pmc_event_alias p4_aliases[] = {
1423d56c5d4bSJoseph Koshy 	EV_ALIAS("branches",		"p4-branch-retired,mask=mmtp+mmtm"),
1424d56c5d4bSJoseph Koshy 	EV_ALIAS("branch-mispredicts",	"p4-mispred-branch-retired"),
1425ebccf1e3SJoseph Koshy 	EV_ALIAS("cycles",		"tsc"),
1426d56c5d4bSJoseph Koshy 	EV_ALIAS("instructions",
1427d56c5d4bSJoseph Koshy 	    "p4-instr-retired,mask=nbogusntag+nbogustag"),
1428177a2f22SJoseph Koshy 	EV_ALIAS("unhalted-cycles",	"p4-global-power-events"),
1429ebccf1e3SJoseph Koshy 	EV_ALIAS(NULL, NULL)
1430ebccf1e3SJoseph Koshy };
1431ebccf1e3SJoseph Koshy 
1432ebccf1e3SJoseph Koshy #define	P4_KW_ACTIVE	"active"
1433ebccf1e3SJoseph Koshy #define	P4_KW_ACTIVE_ANY "any"
1434ebccf1e3SJoseph Koshy #define	P4_KW_ACTIVE_BOTH "both"
1435ebccf1e3SJoseph Koshy #define	P4_KW_ACTIVE_NONE "none"
1436ebccf1e3SJoseph Koshy #define	P4_KW_ACTIVE_SINGLE "single"
1437ebccf1e3SJoseph Koshy #define	P4_KW_BUSREQTYPE "busreqtype"
1438ebccf1e3SJoseph Koshy #define	P4_KW_CASCADE	"cascade"
1439ebccf1e3SJoseph Koshy #define	P4_KW_EDGE	"edge"
1440ebccf1e3SJoseph Koshy #define	P4_KW_INV	"complement"
1441ebccf1e3SJoseph Koshy #define	P4_KW_OS	"os"
1442ebccf1e3SJoseph Koshy #define	P4_KW_MASK	"mask"
1443ebccf1e3SJoseph Koshy #define	P4_KW_PRECISE	"precise"
1444ebccf1e3SJoseph Koshy #define	P4_KW_TAG	"tag"
1445ebccf1e3SJoseph Koshy #define	P4_KW_THRESHOLD	"threshold"
1446ebccf1e3SJoseph Koshy #define	P4_KW_USR	"usr"
1447ebccf1e3SJoseph Koshy 
1448ebccf1e3SJoseph Koshy #define	__P4MASK(N,V) PMCMASK(N, (1 << (V)))
1449ebccf1e3SJoseph Koshy 
1450ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_tcdm[] = { /* tc deliver mode */
1451ebccf1e3SJoseph Koshy 	__P4MASK(dd, 0),
1452ebccf1e3SJoseph Koshy 	__P4MASK(db, 1),
1453ebccf1e3SJoseph Koshy 	__P4MASK(di, 2),
1454ebccf1e3SJoseph Koshy 	__P4MASK(bd, 3),
1455ebccf1e3SJoseph Koshy 	__P4MASK(bb, 4),
1456ebccf1e3SJoseph Koshy 	__P4MASK(bi, 5),
1457ebccf1e3SJoseph Koshy 	__P4MASK(id, 6),
1458ebccf1e3SJoseph Koshy 	__P4MASK(ib, 7),
1459ebccf1e3SJoseph Koshy 	NULLMASK
1460ebccf1e3SJoseph Koshy };
1461ebccf1e3SJoseph Koshy 
1462ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_bfr[] = { /* bpu fetch request */
1463ebccf1e3SJoseph Koshy 	__P4MASK(tcmiss, 0),
1464ebccf1e3SJoseph Koshy 	NULLMASK,
1465ebccf1e3SJoseph Koshy };
1466ebccf1e3SJoseph Koshy 
1467ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_ir[] = { /* itlb reference */
1468ebccf1e3SJoseph Koshy 	__P4MASK(hit, 0),
1469ebccf1e3SJoseph Koshy 	__P4MASK(miss, 1),
1470ebccf1e3SJoseph Koshy 	__P4MASK(hit-uc, 2),
1471ebccf1e3SJoseph Koshy 	NULLMASK
1472ebccf1e3SJoseph Koshy };
1473ebccf1e3SJoseph Koshy 
1474ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_memcan[] = { /* memory cancel */
1475ebccf1e3SJoseph Koshy 	__P4MASK(st-rb-full, 2),
1476ebccf1e3SJoseph Koshy 	__P4MASK(64k-conf, 3),
1477ebccf1e3SJoseph Koshy 	NULLMASK
1478ebccf1e3SJoseph Koshy };
1479ebccf1e3SJoseph Koshy 
1480ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_memcomp[] = { /* memory complete */
1481ebccf1e3SJoseph Koshy 	__P4MASK(lsc, 0),
1482ebccf1e3SJoseph Koshy 	__P4MASK(ssc, 1),
1483ebccf1e3SJoseph Koshy 	NULLMASK
1484ebccf1e3SJoseph Koshy };
1485ebccf1e3SJoseph Koshy 
1486ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_lpr[] = { /* load port replay */
1487ebccf1e3SJoseph Koshy 	__P4MASK(split-ld, 1),
1488ebccf1e3SJoseph Koshy 	NULLMASK
1489ebccf1e3SJoseph Koshy };
1490ebccf1e3SJoseph Koshy 
1491ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_spr[] = { /* store port replay */
1492ebccf1e3SJoseph Koshy 	__P4MASK(split-st, 1),
1493ebccf1e3SJoseph Koshy 	NULLMASK
1494ebccf1e3SJoseph Koshy };
1495ebccf1e3SJoseph Koshy 
1496ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_mlr[] = { /* mob load replay */
1497ebccf1e3SJoseph Koshy 	__P4MASK(no-sta, 1),
1498ebccf1e3SJoseph Koshy 	__P4MASK(no-std, 3),
1499ebccf1e3SJoseph Koshy 	__P4MASK(partial-data, 4),
1500ebccf1e3SJoseph Koshy 	__P4MASK(unalgn-addr, 5),
1501ebccf1e3SJoseph Koshy 	NULLMASK
1502ebccf1e3SJoseph Koshy };
1503ebccf1e3SJoseph Koshy 
1504ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_pwt[] = { /* page walk type */
1505ebccf1e3SJoseph Koshy 	__P4MASK(dtmiss, 0),
1506ebccf1e3SJoseph Koshy 	__P4MASK(itmiss, 1),
1507ebccf1e3SJoseph Koshy 	NULLMASK
1508ebccf1e3SJoseph Koshy };
1509ebccf1e3SJoseph Koshy 
1510ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_bcr[] = { /* bsq cache reference */
1511ebccf1e3SJoseph Koshy 	__P4MASK(rd-2ndl-hits, 0),
1512ebccf1e3SJoseph Koshy 	__P4MASK(rd-2ndl-hite, 1),
1513ebccf1e3SJoseph Koshy 	__P4MASK(rd-2ndl-hitm, 2),
1514ebccf1e3SJoseph Koshy 	__P4MASK(rd-3rdl-hits, 3),
1515ebccf1e3SJoseph Koshy 	__P4MASK(rd-3rdl-hite, 4),
1516ebccf1e3SJoseph Koshy 	__P4MASK(rd-3rdl-hitm, 5),
1517ebccf1e3SJoseph Koshy 	__P4MASK(rd-2ndl-miss, 8),
1518ebccf1e3SJoseph Koshy 	__P4MASK(rd-3rdl-miss, 9),
1519ebccf1e3SJoseph Koshy 	__P4MASK(wr-2ndl-miss, 10),
1520ebccf1e3SJoseph Koshy 	NULLMASK
1521ebccf1e3SJoseph Koshy };
1522ebccf1e3SJoseph Koshy 
1523ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_ia[] = { /* ioq allocation */
1524ebccf1e3SJoseph Koshy 	__P4MASK(all-read, 5),
1525ebccf1e3SJoseph Koshy 	__P4MASK(all-write, 6),
1526ebccf1e3SJoseph Koshy 	__P4MASK(mem-uc, 7),
1527ebccf1e3SJoseph Koshy 	__P4MASK(mem-wc, 8),
1528ebccf1e3SJoseph Koshy 	__P4MASK(mem-wt, 9),
1529ebccf1e3SJoseph Koshy 	__P4MASK(mem-wp, 10),
1530ebccf1e3SJoseph Koshy 	__P4MASK(mem-wb, 11),
1531ebccf1e3SJoseph Koshy 	__P4MASK(own, 13),
1532ebccf1e3SJoseph Koshy 	__P4MASK(other, 14),
1533ebccf1e3SJoseph Koshy 	__P4MASK(prefetch, 15),
1534ebccf1e3SJoseph Koshy 	NULLMASK
1535ebccf1e3SJoseph Koshy };
1536ebccf1e3SJoseph Koshy 
1537ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_iae[] = { /* ioq active entries */
1538ebccf1e3SJoseph Koshy 	__P4MASK(all-read, 5),
1539ebccf1e3SJoseph Koshy 	__P4MASK(all-write, 6),
1540ebccf1e3SJoseph Koshy 	__P4MASK(mem-uc, 7),
1541ebccf1e3SJoseph Koshy 	__P4MASK(mem-wc, 8),
1542ebccf1e3SJoseph Koshy 	__P4MASK(mem-wt, 9),
1543ebccf1e3SJoseph Koshy 	__P4MASK(mem-wp, 10),
1544ebccf1e3SJoseph Koshy 	__P4MASK(mem-wb, 11),
1545ebccf1e3SJoseph Koshy 	__P4MASK(own, 13),
1546ebccf1e3SJoseph Koshy 	__P4MASK(other, 14),
1547ebccf1e3SJoseph Koshy 	__P4MASK(prefetch, 15),
1548ebccf1e3SJoseph Koshy 	NULLMASK
1549ebccf1e3SJoseph Koshy };
1550ebccf1e3SJoseph Koshy 
1551ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_fda[] = { /* fsb data activity */
1552ebccf1e3SJoseph Koshy 	__P4MASK(drdy-drv, 0),
1553ebccf1e3SJoseph Koshy 	__P4MASK(drdy-own, 1),
1554ebccf1e3SJoseph Koshy 	__P4MASK(drdy-other, 2),
1555ebccf1e3SJoseph Koshy 	__P4MASK(dbsy-drv, 3),
1556ebccf1e3SJoseph Koshy 	__P4MASK(dbsy-own, 4),
1557ebccf1e3SJoseph Koshy 	__P4MASK(dbsy-other, 5),
1558ebccf1e3SJoseph Koshy 	NULLMASK
1559ebccf1e3SJoseph Koshy };
1560ebccf1e3SJoseph Koshy 
1561ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_ba[] = { /* bsq allocation */
1562ebccf1e3SJoseph Koshy 	__P4MASK(req-type0, 0),
1563ebccf1e3SJoseph Koshy 	__P4MASK(req-type1, 1),
1564ebccf1e3SJoseph Koshy 	__P4MASK(req-len0, 2),
1565ebccf1e3SJoseph Koshy 	__P4MASK(req-len1, 3),
1566ebccf1e3SJoseph Koshy 	__P4MASK(req-io-type, 5),
1567ebccf1e3SJoseph Koshy 	__P4MASK(req-lock-type, 6),
1568ebccf1e3SJoseph Koshy 	__P4MASK(req-cache-type, 7),
1569ebccf1e3SJoseph Koshy 	__P4MASK(req-split-type, 8),
1570ebccf1e3SJoseph Koshy 	__P4MASK(req-dem-type, 9),
1571ebccf1e3SJoseph Koshy 	__P4MASK(req-ord-type, 10),
1572ebccf1e3SJoseph Koshy 	__P4MASK(mem-type0, 11),
1573ebccf1e3SJoseph Koshy 	__P4MASK(mem-type1, 12),
1574ebccf1e3SJoseph Koshy 	__P4MASK(mem-type2, 13),
1575ebccf1e3SJoseph Koshy 	NULLMASK
1576ebccf1e3SJoseph Koshy };
1577ebccf1e3SJoseph Koshy 
1578ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_sia[] = { /* sse input assist */
1579ebccf1e3SJoseph Koshy 	__P4MASK(all, 15),
1580ebccf1e3SJoseph Koshy 	NULLMASK
1581ebccf1e3SJoseph Koshy };
1582ebccf1e3SJoseph Koshy 
1583ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_psu[] = { /* packed sp uop */
1584ebccf1e3SJoseph Koshy 	__P4MASK(all, 15),
1585ebccf1e3SJoseph Koshy 	NULLMASK
1586ebccf1e3SJoseph Koshy };
1587ebccf1e3SJoseph Koshy 
1588ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_pdu[] = { /* packed dp uop */
1589ebccf1e3SJoseph Koshy 	__P4MASK(all, 15),
1590ebccf1e3SJoseph Koshy 	NULLMASK
1591ebccf1e3SJoseph Koshy };
1592ebccf1e3SJoseph Koshy 
1593ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_ssu[] = { /* scalar sp uop */
1594ebccf1e3SJoseph Koshy 	__P4MASK(all, 15),
1595ebccf1e3SJoseph Koshy 	NULLMASK
1596ebccf1e3SJoseph Koshy };
1597ebccf1e3SJoseph Koshy 
1598ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_sdu[] = { /* scalar dp uop */
1599ebccf1e3SJoseph Koshy 	__P4MASK(all, 15),
1600ebccf1e3SJoseph Koshy 	NULLMASK
1601ebccf1e3SJoseph Koshy };
1602ebccf1e3SJoseph Koshy 
1603ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_64bmu[] = { /* 64 bit mmx uop */
1604ebccf1e3SJoseph Koshy 	__P4MASK(all, 15),
1605ebccf1e3SJoseph Koshy 	NULLMASK
1606ebccf1e3SJoseph Koshy };
1607ebccf1e3SJoseph Koshy 
1608ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_128bmu[] = { /* 128 bit mmx uop */
1609ebccf1e3SJoseph Koshy 	__P4MASK(all, 15),
1610ebccf1e3SJoseph Koshy 	NULLMASK
1611ebccf1e3SJoseph Koshy };
1612ebccf1e3SJoseph Koshy 
1613ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_xfu[] = { /* X87 fp uop */
1614ebccf1e3SJoseph Koshy 	__P4MASK(all, 15),
1615ebccf1e3SJoseph Koshy 	NULLMASK
1616ebccf1e3SJoseph Koshy };
1617ebccf1e3SJoseph Koshy 
1618ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_xsmu[] = { /* x87 simd moves uop */
1619ebccf1e3SJoseph Koshy 	__P4MASK(allp0, 3),
1620ebccf1e3SJoseph Koshy 	__P4MASK(allp2, 4),
1621ebccf1e3SJoseph Koshy 	NULLMASK
1622ebccf1e3SJoseph Koshy };
1623ebccf1e3SJoseph Koshy 
1624ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_gpe[] = { /* global power events */
1625ebccf1e3SJoseph Koshy 	__P4MASK(running, 0),
1626ebccf1e3SJoseph Koshy 	NULLMASK
1627ebccf1e3SJoseph Koshy };
1628ebccf1e3SJoseph Koshy 
1629ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_tmx[] = { /* TC ms xfer */
1630ebccf1e3SJoseph Koshy 	__P4MASK(cisc, 0),
1631ebccf1e3SJoseph Koshy 	NULLMASK
1632ebccf1e3SJoseph Koshy };
1633ebccf1e3SJoseph Koshy 
1634ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_uqw[] = { /* uop queue writes */
1635ebccf1e3SJoseph Koshy 	__P4MASK(from-tc-build, 0),
1636ebccf1e3SJoseph Koshy 	__P4MASK(from-tc-deliver, 1),
1637ebccf1e3SJoseph Koshy 	__P4MASK(from-rom, 2),
1638ebccf1e3SJoseph Koshy 	NULLMASK
1639ebccf1e3SJoseph Koshy };
1640ebccf1e3SJoseph Koshy 
1641d56c5d4bSJoseph Koshy static const struct pmc_masks p4_mask_rmbt[] = {
1642d56c5d4bSJoseph Koshy 	/* retired mispred branch type */
1643ebccf1e3SJoseph Koshy 	__P4MASK(conditional, 1),
1644ebccf1e3SJoseph Koshy 	__P4MASK(call, 2),
1645ebccf1e3SJoseph Koshy 	__P4MASK(return, 3),
1646ebccf1e3SJoseph Koshy 	__P4MASK(indirect, 4),
1647ebccf1e3SJoseph Koshy 	NULLMASK
1648ebccf1e3SJoseph Koshy };
1649ebccf1e3SJoseph Koshy 
1650ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_rbt[] = { /* retired branch type */
1651ebccf1e3SJoseph Koshy 	__P4MASK(conditional, 1),
1652ebccf1e3SJoseph Koshy 	__P4MASK(call, 2),
1653ebccf1e3SJoseph Koshy 	__P4MASK(retired, 3),
1654ebccf1e3SJoseph Koshy 	__P4MASK(indirect, 4),
1655ebccf1e3SJoseph Koshy 	NULLMASK
1656ebccf1e3SJoseph Koshy };
1657ebccf1e3SJoseph Koshy 
1658ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_rs[] = { /* resource stall */
1659ebccf1e3SJoseph Koshy 	__P4MASK(sbfull, 5),
1660ebccf1e3SJoseph Koshy 	NULLMASK
1661ebccf1e3SJoseph Koshy };
1662ebccf1e3SJoseph Koshy 
1663ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_wb[] = { /* WC buffer */
1664ebccf1e3SJoseph Koshy 	__P4MASK(wcb-evicts, 0),
1665ebccf1e3SJoseph Koshy 	__P4MASK(wcb-full-evict, 1),
1666ebccf1e3SJoseph Koshy 	NULLMASK
1667ebccf1e3SJoseph Koshy };
1668ebccf1e3SJoseph Koshy 
1669ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_fee[] = { /* front end event */
1670ebccf1e3SJoseph Koshy 	__P4MASK(nbogus, 0),
1671ebccf1e3SJoseph Koshy 	__P4MASK(bogus, 1),
1672ebccf1e3SJoseph Koshy 	NULLMASK
1673ebccf1e3SJoseph Koshy };
1674ebccf1e3SJoseph Koshy 
1675ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_ee[] = { /* execution event */
1676ebccf1e3SJoseph Koshy 	__P4MASK(nbogus0, 0),
1677ebccf1e3SJoseph Koshy 	__P4MASK(nbogus1, 1),
1678ebccf1e3SJoseph Koshy 	__P4MASK(nbogus2, 2),
1679ebccf1e3SJoseph Koshy 	__P4MASK(nbogus3, 3),
1680ebccf1e3SJoseph Koshy 	__P4MASK(bogus0, 4),
1681ebccf1e3SJoseph Koshy 	__P4MASK(bogus1, 5),
1682ebccf1e3SJoseph Koshy 	__P4MASK(bogus2, 6),
1683ebccf1e3SJoseph Koshy 	__P4MASK(bogus3, 7),
1684ebccf1e3SJoseph Koshy 	NULLMASK
1685ebccf1e3SJoseph Koshy };
1686ebccf1e3SJoseph Koshy 
1687ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_re[] = { /* replay event */
1688ebccf1e3SJoseph Koshy 	__P4MASK(nbogus, 0),
1689ebccf1e3SJoseph Koshy 	__P4MASK(bogus, 1),
1690ebccf1e3SJoseph Koshy 	NULLMASK
1691ebccf1e3SJoseph Koshy };
1692ebccf1e3SJoseph Koshy 
1693ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_insret[] = { /* instr retired */
1694ebccf1e3SJoseph Koshy 	__P4MASK(nbogusntag, 0),
1695ebccf1e3SJoseph Koshy 	__P4MASK(nbogustag, 1),
1696ebccf1e3SJoseph Koshy 	__P4MASK(bogusntag, 2),
1697ebccf1e3SJoseph Koshy 	__P4MASK(bogustag, 3),
1698ebccf1e3SJoseph Koshy 	NULLMASK
1699ebccf1e3SJoseph Koshy };
1700ebccf1e3SJoseph Koshy 
1701ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_ur[] = { /* uops retired */
1702ebccf1e3SJoseph Koshy 	__P4MASK(nbogus, 0),
1703ebccf1e3SJoseph Koshy 	__P4MASK(bogus, 1),
1704ebccf1e3SJoseph Koshy 	NULLMASK
1705ebccf1e3SJoseph Koshy };
1706ebccf1e3SJoseph Koshy 
1707ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_ut[] = { /* uop type */
1708ebccf1e3SJoseph Koshy 	__P4MASK(tagloads, 1),
1709ebccf1e3SJoseph Koshy 	__P4MASK(tagstores, 2),
1710ebccf1e3SJoseph Koshy 	NULLMASK
1711ebccf1e3SJoseph Koshy };
1712ebccf1e3SJoseph Koshy 
1713ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_br[] = { /* branch retired */
1714ebccf1e3SJoseph Koshy 	__P4MASK(mmnp, 0),
1715ebccf1e3SJoseph Koshy 	__P4MASK(mmnm, 1),
1716ebccf1e3SJoseph Koshy 	__P4MASK(mmtp, 2),
1717ebccf1e3SJoseph Koshy 	__P4MASK(mmtm, 3),
1718ebccf1e3SJoseph Koshy 	NULLMASK
1719ebccf1e3SJoseph Koshy };
1720ebccf1e3SJoseph Koshy 
1721ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_mbr[] = { /* mispred branch retired */
1722ebccf1e3SJoseph Koshy 	__P4MASK(nbogus, 0),
1723ebccf1e3SJoseph Koshy 	NULLMASK
1724ebccf1e3SJoseph Koshy };
1725ebccf1e3SJoseph Koshy 
1726ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_xa[] = { /* x87 assist */
1727ebccf1e3SJoseph Koshy 	__P4MASK(fpsu, 0),
1728ebccf1e3SJoseph Koshy 	__P4MASK(fpso, 1),
1729ebccf1e3SJoseph Koshy 	__P4MASK(poao, 2),
1730ebccf1e3SJoseph Koshy 	__P4MASK(poau, 3),
1731ebccf1e3SJoseph Koshy 	__P4MASK(prea, 4),
1732ebccf1e3SJoseph Koshy 	NULLMASK
1733ebccf1e3SJoseph Koshy };
1734ebccf1e3SJoseph Koshy 
1735ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_machclr[] = { /* machine clear */
1736ebccf1e3SJoseph Koshy 	__P4MASK(clear, 0),
1737ebccf1e3SJoseph Koshy 	__P4MASK(moclear, 2),
1738ebccf1e3SJoseph Koshy 	__P4MASK(smclear, 3),
1739ebccf1e3SJoseph Koshy 	NULLMASK
1740ebccf1e3SJoseph Koshy };
1741ebccf1e3SJoseph Koshy 
1742ebccf1e3SJoseph Koshy /* P4 event parser */
1743ebccf1e3SJoseph Koshy static int
1744ebccf1e3SJoseph Koshy p4_allocate_pmc(enum pmc_event pe, char *ctrspec,
1745ebccf1e3SJoseph Koshy     struct pmc_op_pmcallocate *pmc_config)
1746ebccf1e3SJoseph Koshy {
1747ebccf1e3SJoseph Koshy 
1748ebccf1e3SJoseph Koshy 	char	*e, *p, *q;
1749ebccf1e3SJoseph Koshy 	int	count, has_tag, has_busreqtype, n;
17501e862e5aSFabien Thomas 	uint32_t cccractivemask;
17511e862e5aSFabien Thomas 	uint64_t evmask;
1752ebccf1e3SJoseph Koshy 	const struct pmc_masks *pm, *pmask;
1753ebccf1e3SJoseph Koshy 
1754789140c0SJoseph Koshy 	pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE);
1755f263522aSJoseph Koshy 	pmc_config->pm_md.pm_p4.pm_p4_cccrconfig =
1756f263522aSJoseph Koshy 	    pmc_config->pm_md.pm_p4.pm_p4_escrconfig = 0;
1757ebccf1e3SJoseph Koshy 
1758ebccf1e3SJoseph Koshy 	pmask   = NULL;
1759ebccf1e3SJoseph Koshy 	evmask  = 0;
1760ebccf1e3SJoseph Koshy 	cccractivemask = 0x3;
1761ebccf1e3SJoseph Koshy 	has_tag = has_busreqtype = 0;
1762ebccf1e3SJoseph Koshy 
1763ebccf1e3SJoseph Koshy #define	__P4SETMASK(M) do {				\
1764ebccf1e3SJoseph Koshy 	pmask = p4_mask_##M;				\
1765ebccf1e3SJoseph Koshy } while (0)
1766ebccf1e3SJoseph Koshy 
1767ebccf1e3SJoseph Koshy 	switch (pe) {
1768ebccf1e3SJoseph Koshy 	case PMC_EV_P4_TC_DELIVER_MODE:
1769ebccf1e3SJoseph Koshy 		__P4SETMASK(tcdm);
1770ebccf1e3SJoseph Koshy 		break;
1771ebccf1e3SJoseph Koshy 	case PMC_EV_P4_BPU_FETCH_REQUEST:
1772ebccf1e3SJoseph Koshy 		__P4SETMASK(bfr);
1773ebccf1e3SJoseph Koshy 		break;
1774ebccf1e3SJoseph Koshy 	case PMC_EV_P4_ITLB_REFERENCE:
1775ebccf1e3SJoseph Koshy 		__P4SETMASK(ir);
1776ebccf1e3SJoseph Koshy 		break;
1777ebccf1e3SJoseph Koshy 	case PMC_EV_P4_MEMORY_CANCEL:
1778ebccf1e3SJoseph Koshy 		__P4SETMASK(memcan);
1779ebccf1e3SJoseph Koshy 		break;
1780ebccf1e3SJoseph Koshy 	case PMC_EV_P4_MEMORY_COMPLETE:
1781ebccf1e3SJoseph Koshy 		__P4SETMASK(memcomp);
1782ebccf1e3SJoseph Koshy 		break;
1783ebccf1e3SJoseph Koshy 	case PMC_EV_P4_LOAD_PORT_REPLAY:
1784ebccf1e3SJoseph Koshy 		__P4SETMASK(lpr);
1785ebccf1e3SJoseph Koshy 		break;
1786ebccf1e3SJoseph Koshy 	case PMC_EV_P4_STORE_PORT_REPLAY:
1787ebccf1e3SJoseph Koshy 		__P4SETMASK(spr);
1788ebccf1e3SJoseph Koshy 		break;
1789ebccf1e3SJoseph Koshy 	case PMC_EV_P4_MOB_LOAD_REPLAY:
1790ebccf1e3SJoseph Koshy 		__P4SETMASK(mlr);
1791ebccf1e3SJoseph Koshy 		break;
1792ebccf1e3SJoseph Koshy 	case PMC_EV_P4_PAGE_WALK_TYPE:
1793ebccf1e3SJoseph Koshy 		__P4SETMASK(pwt);
1794ebccf1e3SJoseph Koshy 		break;
1795ebccf1e3SJoseph Koshy 	case PMC_EV_P4_BSQ_CACHE_REFERENCE:
1796ebccf1e3SJoseph Koshy 		__P4SETMASK(bcr);
1797ebccf1e3SJoseph Koshy 		break;
1798ebccf1e3SJoseph Koshy 	case PMC_EV_P4_IOQ_ALLOCATION:
1799ebccf1e3SJoseph Koshy 		__P4SETMASK(ia);
1800ebccf1e3SJoseph Koshy 		has_busreqtype = 1;
1801ebccf1e3SJoseph Koshy 		break;
1802ebccf1e3SJoseph Koshy 	case PMC_EV_P4_IOQ_ACTIVE_ENTRIES:
1803ebccf1e3SJoseph Koshy 		__P4SETMASK(iae);
1804ebccf1e3SJoseph Koshy 		has_busreqtype = 1;
1805ebccf1e3SJoseph Koshy 		break;
1806ebccf1e3SJoseph Koshy 	case PMC_EV_P4_FSB_DATA_ACTIVITY:
1807ebccf1e3SJoseph Koshy 		__P4SETMASK(fda);
1808ebccf1e3SJoseph Koshy 		break;
1809ebccf1e3SJoseph Koshy 	case PMC_EV_P4_BSQ_ALLOCATION:
1810ebccf1e3SJoseph Koshy 		__P4SETMASK(ba);
1811ebccf1e3SJoseph Koshy 		break;
1812ebccf1e3SJoseph Koshy 	case PMC_EV_P4_SSE_INPUT_ASSIST:
1813ebccf1e3SJoseph Koshy 		__P4SETMASK(sia);
1814ebccf1e3SJoseph Koshy 		break;
1815ebccf1e3SJoseph Koshy 	case PMC_EV_P4_PACKED_SP_UOP:
1816ebccf1e3SJoseph Koshy 		__P4SETMASK(psu);
1817ebccf1e3SJoseph Koshy 		break;
1818ebccf1e3SJoseph Koshy 	case PMC_EV_P4_PACKED_DP_UOP:
1819ebccf1e3SJoseph Koshy 		__P4SETMASK(pdu);
1820ebccf1e3SJoseph Koshy 		break;
1821ebccf1e3SJoseph Koshy 	case PMC_EV_P4_SCALAR_SP_UOP:
1822ebccf1e3SJoseph Koshy 		__P4SETMASK(ssu);
1823ebccf1e3SJoseph Koshy 		break;
1824ebccf1e3SJoseph Koshy 	case PMC_EV_P4_SCALAR_DP_UOP:
1825ebccf1e3SJoseph Koshy 		__P4SETMASK(sdu);
1826ebccf1e3SJoseph Koshy 		break;
1827ebccf1e3SJoseph Koshy 	case PMC_EV_P4_64BIT_MMX_UOP:
1828ebccf1e3SJoseph Koshy 		__P4SETMASK(64bmu);
1829ebccf1e3SJoseph Koshy 		break;
1830ebccf1e3SJoseph Koshy 	case PMC_EV_P4_128BIT_MMX_UOP:
1831ebccf1e3SJoseph Koshy 		__P4SETMASK(128bmu);
1832ebccf1e3SJoseph Koshy 		break;
1833ebccf1e3SJoseph Koshy 	case PMC_EV_P4_X87_FP_UOP:
1834ebccf1e3SJoseph Koshy 		__P4SETMASK(xfu);
1835ebccf1e3SJoseph Koshy 		break;
1836ebccf1e3SJoseph Koshy 	case PMC_EV_P4_X87_SIMD_MOVES_UOP:
1837ebccf1e3SJoseph Koshy 		__P4SETMASK(xsmu);
1838ebccf1e3SJoseph Koshy 		break;
1839ebccf1e3SJoseph Koshy 	case PMC_EV_P4_GLOBAL_POWER_EVENTS:
1840ebccf1e3SJoseph Koshy 		__P4SETMASK(gpe);
1841ebccf1e3SJoseph Koshy 		break;
1842ebccf1e3SJoseph Koshy 	case PMC_EV_P4_TC_MS_XFER:
1843ebccf1e3SJoseph Koshy 		__P4SETMASK(tmx);
1844ebccf1e3SJoseph Koshy 		break;
1845ebccf1e3SJoseph Koshy 	case PMC_EV_P4_UOP_QUEUE_WRITES:
1846ebccf1e3SJoseph Koshy 		__P4SETMASK(uqw);
1847ebccf1e3SJoseph Koshy 		break;
1848ebccf1e3SJoseph Koshy 	case PMC_EV_P4_RETIRED_MISPRED_BRANCH_TYPE:
1849ebccf1e3SJoseph Koshy 		__P4SETMASK(rmbt);
1850ebccf1e3SJoseph Koshy 		break;
1851ebccf1e3SJoseph Koshy 	case PMC_EV_P4_RETIRED_BRANCH_TYPE:
1852ebccf1e3SJoseph Koshy 		__P4SETMASK(rbt);
1853ebccf1e3SJoseph Koshy 		break;
1854ebccf1e3SJoseph Koshy 	case PMC_EV_P4_RESOURCE_STALL:
1855ebccf1e3SJoseph Koshy 		__P4SETMASK(rs);
1856ebccf1e3SJoseph Koshy 		break;
1857ebccf1e3SJoseph Koshy 	case PMC_EV_P4_WC_BUFFER:
1858ebccf1e3SJoseph Koshy 		__P4SETMASK(wb);
1859ebccf1e3SJoseph Koshy 		break;
1860ebccf1e3SJoseph Koshy 	case PMC_EV_P4_BSQ_ACTIVE_ENTRIES:
1861ebccf1e3SJoseph Koshy 	case PMC_EV_P4_B2B_CYCLES:
1862ebccf1e3SJoseph Koshy 	case PMC_EV_P4_BNR:
1863ebccf1e3SJoseph Koshy 	case PMC_EV_P4_SNOOP:
1864ebccf1e3SJoseph Koshy 	case PMC_EV_P4_RESPONSE:
1865ebccf1e3SJoseph Koshy 		break;
1866ebccf1e3SJoseph Koshy 	case PMC_EV_P4_FRONT_END_EVENT:
1867ebccf1e3SJoseph Koshy 		__P4SETMASK(fee);
1868ebccf1e3SJoseph Koshy 		break;
1869ebccf1e3SJoseph Koshy 	case PMC_EV_P4_EXECUTION_EVENT:
1870ebccf1e3SJoseph Koshy 		__P4SETMASK(ee);
1871ebccf1e3SJoseph Koshy 		break;
1872ebccf1e3SJoseph Koshy 	case PMC_EV_P4_REPLAY_EVENT:
1873ebccf1e3SJoseph Koshy 		__P4SETMASK(re);
1874ebccf1e3SJoseph Koshy 		break;
1875ebccf1e3SJoseph Koshy 	case PMC_EV_P4_INSTR_RETIRED:
1876ebccf1e3SJoseph Koshy 		__P4SETMASK(insret);
1877ebccf1e3SJoseph Koshy 		break;
1878ebccf1e3SJoseph Koshy 	case PMC_EV_P4_UOPS_RETIRED:
1879ebccf1e3SJoseph Koshy 		__P4SETMASK(ur);
1880ebccf1e3SJoseph Koshy 		break;
1881ebccf1e3SJoseph Koshy 	case PMC_EV_P4_UOP_TYPE:
1882ebccf1e3SJoseph Koshy 		__P4SETMASK(ut);
1883ebccf1e3SJoseph Koshy 		break;
1884ebccf1e3SJoseph Koshy 	case PMC_EV_P4_BRANCH_RETIRED:
1885ebccf1e3SJoseph Koshy 		__P4SETMASK(br);
1886ebccf1e3SJoseph Koshy 		break;
1887ebccf1e3SJoseph Koshy 	case PMC_EV_P4_MISPRED_BRANCH_RETIRED:
1888ebccf1e3SJoseph Koshy 		__P4SETMASK(mbr);
1889ebccf1e3SJoseph Koshy 		break;
1890ebccf1e3SJoseph Koshy 	case PMC_EV_P4_X87_ASSIST:
1891ebccf1e3SJoseph Koshy 		__P4SETMASK(xa);
1892ebccf1e3SJoseph Koshy 		break;
1893ebccf1e3SJoseph Koshy 	case PMC_EV_P4_MACHINE_CLEAR:
1894ebccf1e3SJoseph Koshy 		__P4SETMASK(machclr);
1895ebccf1e3SJoseph Koshy 		break;
1896ebccf1e3SJoseph Koshy 	default:
1897aa342b1fSJoseph Koshy 		return (-1);
1898ebccf1e3SJoseph Koshy 	}
1899ebccf1e3SJoseph Koshy 
1900ebccf1e3SJoseph Koshy 	/* process additional flags */
1901ebccf1e3SJoseph Koshy 	while ((p = strsep(&ctrspec, ",")) != NULL) {
1902ebccf1e3SJoseph Koshy 		if (KWPREFIXMATCH(p, P4_KW_ACTIVE)) {
1903ebccf1e3SJoseph Koshy 			q = strchr(p, '=');
1904ebccf1e3SJoseph Koshy 			if (*++q == '\0') /* skip '=' */
1905aa342b1fSJoseph Koshy 				return (-1);
1906ebccf1e3SJoseph Koshy 
1907789140c0SJoseph Koshy 			if (strcasecmp(q, P4_KW_ACTIVE_NONE) == 0)
1908ebccf1e3SJoseph Koshy 				cccractivemask = 0x0;
1909789140c0SJoseph Koshy 			else if (strcasecmp(q, P4_KW_ACTIVE_SINGLE) == 0)
1910ebccf1e3SJoseph Koshy 				cccractivemask = 0x1;
1911789140c0SJoseph Koshy 			else if (strcasecmp(q, P4_KW_ACTIVE_BOTH) == 0)
1912ebccf1e3SJoseph Koshy 				cccractivemask = 0x2;
1913789140c0SJoseph Koshy 			else if (strcasecmp(q, P4_KW_ACTIVE_ANY) == 0)
1914ebccf1e3SJoseph Koshy 				cccractivemask = 0x3;
1915ebccf1e3SJoseph Koshy 			else
1916aa342b1fSJoseph Koshy 				return (-1);
1917ebccf1e3SJoseph Koshy 
1918ebccf1e3SJoseph Koshy 		} else if (KWPREFIXMATCH(p, P4_KW_BUSREQTYPE)) {
1919ebccf1e3SJoseph Koshy 			if (has_busreqtype == 0)
1920aa342b1fSJoseph Koshy 				return (-1);
1921ebccf1e3SJoseph Koshy 
1922ebccf1e3SJoseph Koshy 			q = strchr(p, '=');
1923ebccf1e3SJoseph Koshy 			if (*++q == '\0') /* skip '=' */
1924aa342b1fSJoseph Koshy 				return (-1);
1925ebccf1e3SJoseph Koshy 
1926ebccf1e3SJoseph Koshy 			count = strtol(q, &e, 0);
1927ebccf1e3SJoseph Koshy 			if (e == q || *e != '\0')
1928aa342b1fSJoseph Koshy 				return (-1);
1929ebccf1e3SJoseph Koshy 			evmask = (evmask & ~0x1F) | (count & 0x1F);
1930ebccf1e3SJoseph Koshy 		} else if (KWMATCH(p, P4_KW_CASCADE))
1931ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_CASCADE;
1932ebccf1e3SJoseph Koshy 		else if (KWMATCH(p, P4_KW_EDGE))
1933ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_EDGE;
1934ebccf1e3SJoseph Koshy 		else if (KWMATCH(p, P4_KW_INV))
1935ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_INVERT;
1936ebccf1e3SJoseph Koshy 		else if (KWPREFIXMATCH(p, P4_KW_MASK "=")) {
1937ebccf1e3SJoseph Koshy 			if ((n = pmc_parse_mask(pmask, p, &evmask)) < 0)
1938aa342b1fSJoseph Koshy 				return (-1);
1939ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_QUALIFIER;
1940ebccf1e3SJoseph Koshy 		} else if (KWMATCH(p, P4_KW_OS))
1941ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_SYSTEM;
1942ebccf1e3SJoseph Koshy 		else if (KWMATCH(p, P4_KW_PRECISE))
1943ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_PRECISE;
1944ebccf1e3SJoseph Koshy 		else if (KWPREFIXMATCH(p, P4_KW_TAG "=")) {
1945ebccf1e3SJoseph Koshy 			if (has_tag == 0)
1946aa342b1fSJoseph Koshy 				return (-1);
1947ebccf1e3SJoseph Koshy 
1948ebccf1e3SJoseph Koshy 			q = strchr(p, '=');
1949ebccf1e3SJoseph Koshy 			if (*++q == '\0') /* skip '=' */
1950aa342b1fSJoseph Koshy 				return (-1);
1951ebccf1e3SJoseph Koshy 
1952ebccf1e3SJoseph Koshy 			count = strtol(q, &e, 0);
1953ebccf1e3SJoseph Koshy 			if (e == q || *e != '\0')
1954aa342b1fSJoseph Koshy 				return (-1);
1955ebccf1e3SJoseph Koshy 
1956ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_TAGGING;
1957f263522aSJoseph Koshy 			pmc_config->pm_md.pm_p4.pm_p4_escrconfig |=
1958ebccf1e3SJoseph Koshy 			    P4_ESCR_TO_TAG_VALUE(count);
1959ebccf1e3SJoseph Koshy 		} else if (KWPREFIXMATCH(p, P4_KW_THRESHOLD "=")) {
1960ebccf1e3SJoseph Koshy 			q = strchr(p, '=');
1961ebccf1e3SJoseph Koshy 			if (*++q == '\0') /* skip '=' */
1962aa342b1fSJoseph Koshy 				return (-1);
1963ebccf1e3SJoseph Koshy 
1964ebccf1e3SJoseph Koshy 			count = strtol(q, &e, 0);
1965ebccf1e3SJoseph Koshy 			if (e == q || *e != '\0')
1966aa342b1fSJoseph Koshy 				return (-1);
1967ebccf1e3SJoseph Koshy 
1968ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_THRESHOLD;
1969f263522aSJoseph Koshy 			pmc_config->pm_md.pm_p4.pm_p4_cccrconfig &=
1970f263522aSJoseph Koshy 			    ~P4_CCCR_THRESHOLD_MASK;
1971f263522aSJoseph Koshy 			pmc_config->pm_md.pm_p4.pm_p4_cccrconfig |=
1972f263522aSJoseph Koshy 			    P4_CCCR_TO_THRESHOLD(count);
1973ebccf1e3SJoseph Koshy 		} else if (KWMATCH(p, P4_KW_USR))
1974ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_USER;
1975ebccf1e3SJoseph Koshy 		else
1976aa342b1fSJoseph Koshy 			return (-1);
1977ebccf1e3SJoseph Koshy 	}
1978ebccf1e3SJoseph Koshy 
1979ebccf1e3SJoseph Koshy 	/* other post processing */
1980ebccf1e3SJoseph Koshy 	if (pe == PMC_EV_P4_IOQ_ALLOCATION ||
1981ebccf1e3SJoseph Koshy 	    pe == PMC_EV_P4_FSB_DATA_ACTIVITY ||
1982ebccf1e3SJoseph Koshy 	    pe == PMC_EV_P4_BSQ_ALLOCATION)
1983ebccf1e3SJoseph Koshy 		pmc_config->pm_caps |= PMC_CAP_EDGE;
1984ebccf1e3SJoseph Koshy 
1985ebccf1e3SJoseph Koshy 	/* fill in thread activity mask */
1986f263522aSJoseph Koshy 	pmc_config->pm_md.pm_p4.pm_p4_cccrconfig |=
1987ebccf1e3SJoseph Koshy 	    P4_CCCR_TO_ACTIVE_THREAD(cccractivemask);
1988ebccf1e3SJoseph Koshy 
1989ebccf1e3SJoseph Koshy 	if (evmask)
1990ebccf1e3SJoseph Koshy 		pmc_config->pm_caps |= PMC_CAP_QUALIFIER;
1991ebccf1e3SJoseph Koshy 
1992ebccf1e3SJoseph Koshy 	switch (pe) {
1993ebccf1e3SJoseph Koshy 	case PMC_EV_P4_FSB_DATA_ACTIVITY:
1994ebccf1e3SJoseph Koshy 		if ((evmask & 0x06) == 0x06 ||
1995ebccf1e3SJoseph Koshy 		    (evmask & 0x18) == 0x18)
1996aa342b1fSJoseph Koshy 			return (-1); /* can't have own+other bits together */
1997ebccf1e3SJoseph Koshy 		if (evmask == 0) /* default:drdy-{drv,own}+dbsy{drv,own} */
1998ebccf1e3SJoseph Koshy 			evmask = 0x1D;
1999ebccf1e3SJoseph Koshy 		break;
2000ebccf1e3SJoseph Koshy 	case PMC_EV_P4_MACHINE_CLEAR:
2001ebccf1e3SJoseph Koshy 		/* only one bit is allowed to be set */
2002ebccf1e3SJoseph Koshy 		if ((evmask & (evmask - 1)) != 0)
2003aa342b1fSJoseph Koshy 			return (-1);
2004ebccf1e3SJoseph Koshy 		if (evmask == 0) {
2005ebccf1e3SJoseph Koshy 			evmask = 0x1;	/* 'CLEAR' */
2006ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_QUALIFIER;
2007ebccf1e3SJoseph Koshy 		}
2008ebccf1e3SJoseph Koshy 		break;
2009ebccf1e3SJoseph Koshy 	default:
2010ebccf1e3SJoseph Koshy 		if (evmask == 0 && pmask) {
2011ebccf1e3SJoseph Koshy 			for (pm = pmask; pm->pm_name; pm++)
2012ebccf1e3SJoseph Koshy 				evmask |= pm->pm_value;
2013ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_QUALIFIER;
2014ebccf1e3SJoseph Koshy 		}
2015ebccf1e3SJoseph Koshy 	}
2016ebccf1e3SJoseph Koshy 
2017f263522aSJoseph Koshy 	pmc_config->pm_md.pm_p4.pm_p4_escrconfig =
2018f263522aSJoseph Koshy 	    P4_ESCR_TO_EVENT_MASK(evmask);
2019ebccf1e3SJoseph Koshy 
2020aa342b1fSJoseph Koshy 	return (0);
2021ebccf1e3SJoseph Koshy }
2022ebccf1e3SJoseph Koshy 
202386a65549SJoseph Koshy #endif
202486a65549SJoseph Koshy 
202586a65549SJoseph Koshy #if defined(__i386__)
202686a65549SJoseph Koshy 
2027ebccf1e3SJoseph Koshy /*
2028f263522aSJoseph Koshy  * Pentium style PMCs
2029f263522aSJoseph Koshy  */
2030f263522aSJoseph Koshy 
2031f263522aSJoseph Koshy static struct pmc_event_alias p5_aliases[] = {
20320b9b757dSJoseph Koshy 	EV_ALIAS("branches",		"p5-taken-branches"),
2033f263522aSJoseph Koshy 	EV_ALIAS("cycles",		"tsc"),
20340b9b757dSJoseph Koshy 	EV_ALIAS("dc-misses",		"p5-data-read-miss-or-write-miss"),
20350b9b757dSJoseph Koshy 	EV_ALIAS("ic-misses",		"p5-code-cache-miss"),
20360b9b757dSJoseph Koshy 	EV_ALIAS("instructions",	"p5-instructions-executed"),
20370b9b757dSJoseph Koshy 	EV_ALIAS("interrupts",		"p5-hardware-interrupts"),
20380b9b757dSJoseph Koshy 	EV_ALIAS("unhalted-cycles",
20390b9b757dSJoseph Koshy 	    "p5-number-of-cycles-not-in-halt-state"),
2040f263522aSJoseph Koshy 	EV_ALIAS(NULL, NULL)
2041f263522aSJoseph Koshy };
2042f263522aSJoseph Koshy 
2043f263522aSJoseph Koshy static int
2044f263522aSJoseph Koshy p5_allocate_pmc(enum pmc_event pe, char *ctrspec,
2045f263522aSJoseph Koshy     struct pmc_op_pmcallocate *pmc_config)
2046f263522aSJoseph Koshy {
2047aa342b1fSJoseph Koshy 	return (-1 || pe || ctrspec || pmc_config); /* shut up gcc */
2048f263522aSJoseph Koshy }
2049f263522aSJoseph Koshy 
2050f263522aSJoseph Koshy /*
2051ebccf1e3SJoseph Koshy  * Pentium Pro style PMCs.  These PMCs are found in Pentium II, Pentium III,
2052ebccf1e3SJoseph Koshy  * and Pentium M CPUs.
2053ebccf1e3SJoseph Koshy  */
2054ebccf1e3SJoseph Koshy 
2055ebccf1e3SJoseph Koshy static struct pmc_event_alias p6_aliases[] = {
2056ebccf1e3SJoseph Koshy 	EV_ALIAS("branches",		"p6-br-inst-retired"),
2057ebccf1e3SJoseph Koshy 	EV_ALIAS("branch-mispredicts",	"p6-br-miss-pred-retired"),
2058ebccf1e3SJoseph Koshy 	EV_ALIAS("cycles",		"tsc"),
2059d56c5d4bSJoseph Koshy 	EV_ALIAS("dc-misses",		"p6-dcu-lines-in"),
206073e2d811SJoseph Koshy 	EV_ALIAS("ic-misses",		"p6-ifu-fetch-miss"),
2061ebccf1e3SJoseph Koshy 	EV_ALIAS("instructions",	"p6-inst-retired"),
2062ebccf1e3SJoseph Koshy 	EV_ALIAS("interrupts",		"p6-hw-int-rx"),
2063177a2f22SJoseph Koshy 	EV_ALIAS("unhalted-cycles",	"p6-cpu-clk-unhalted"),
2064ebccf1e3SJoseph Koshy 	EV_ALIAS(NULL, NULL)
2065ebccf1e3SJoseph Koshy };
2066ebccf1e3SJoseph Koshy 
2067ebccf1e3SJoseph Koshy #define	P6_KW_CMASK	"cmask"
2068ebccf1e3SJoseph Koshy #define	P6_KW_EDGE	"edge"
2069ebccf1e3SJoseph Koshy #define	P6_KW_INV	"inv"
2070ebccf1e3SJoseph Koshy #define	P6_KW_OS	"os"
2071ebccf1e3SJoseph Koshy #define	P6_KW_UMASK	"umask"
2072ebccf1e3SJoseph Koshy #define	P6_KW_USR	"usr"
2073ebccf1e3SJoseph Koshy 
2074ebccf1e3SJoseph Koshy static struct pmc_masks p6_mask_mesi[] = {
2075ebccf1e3SJoseph Koshy 	PMCMASK(m,	0x01),
2076ebccf1e3SJoseph Koshy 	PMCMASK(e,	0x02),
2077ebccf1e3SJoseph Koshy 	PMCMASK(s,	0x04),
2078ebccf1e3SJoseph Koshy 	PMCMASK(i,	0x08),
2079ebccf1e3SJoseph Koshy 	NULLMASK
2080ebccf1e3SJoseph Koshy };
2081ebccf1e3SJoseph Koshy 
2082ebccf1e3SJoseph Koshy static struct pmc_masks p6_mask_mesihw[] = {
2083ebccf1e3SJoseph Koshy 	PMCMASK(m,	0x01),
2084ebccf1e3SJoseph Koshy 	PMCMASK(e,	0x02),
2085ebccf1e3SJoseph Koshy 	PMCMASK(s,	0x04),
2086ebccf1e3SJoseph Koshy 	PMCMASK(i,	0x08),
2087ebccf1e3SJoseph Koshy 	PMCMASK(nonhw,	0x00),
2088ebccf1e3SJoseph Koshy 	PMCMASK(hw,	0x10),
2089ebccf1e3SJoseph Koshy 	PMCMASK(both,	0x30),
2090ebccf1e3SJoseph Koshy 	NULLMASK
2091ebccf1e3SJoseph Koshy };
2092ebccf1e3SJoseph Koshy 
2093ebccf1e3SJoseph Koshy static struct pmc_masks p6_mask_hw[] = {
2094ebccf1e3SJoseph Koshy 	PMCMASK(nonhw,	0x00),
2095ebccf1e3SJoseph Koshy 	PMCMASK(hw,	0x10),
2096ebccf1e3SJoseph Koshy 	PMCMASK(both,	0x30),
2097ebccf1e3SJoseph Koshy 	NULLMASK
2098ebccf1e3SJoseph Koshy };
2099ebccf1e3SJoseph Koshy 
2100ebccf1e3SJoseph Koshy static struct pmc_masks p6_mask_any[] = {
2101ebccf1e3SJoseph Koshy 	PMCMASK(self,	0x00),
2102ebccf1e3SJoseph Koshy 	PMCMASK(any,	0x20),
2103ebccf1e3SJoseph Koshy 	NULLMASK
2104ebccf1e3SJoseph Koshy };
2105ebccf1e3SJoseph Koshy 
2106ebccf1e3SJoseph Koshy static struct pmc_masks p6_mask_ekp[] = {
2107ebccf1e3SJoseph Koshy 	PMCMASK(nta,	0x00),
2108ebccf1e3SJoseph Koshy 	PMCMASK(t1,	0x01),
2109ebccf1e3SJoseph Koshy 	PMCMASK(t2,	0x02),
2110ebccf1e3SJoseph Koshy 	PMCMASK(wos,	0x03),
2111ebccf1e3SJoseph Koshy 	NULLMASK
2112ebccf1e3SJoseph Koshy };
2113ebccf1e3SJoseph Koshy 
2114ebccf1e3SJoseph Koshy static struct pmc_masks p6_mask_pps[] = {
2115ebccf1e3SJoseph Koshy 	PMCMASK(packed-and-scalar, 0x00),
2116ebccf1e3SJoseph Koshy 	PMCMASK(scalar,	0x01),
2117ebccf1e3SJoseph Koshy 	NULLMASK
2118ebccf1e3SJoseph Koshy };
2119ebccf1e3SJoseph Koshy 
2120ebccf1e3SJoseph Koshy static struct pmc_masks p6_mask_mite[] = {
2121ebccf1e3SJoseph Koshy 	PMCMASK(packed-multiply,	 0x01),
2122ebccf1e3SJoseph Koshy 	PMCMASK(packed-shift,		0x02),
2123ebccf1e3SJoseph Koshy 	PMCMASK(pack,			0x04),
2124ebccf1e3SJoseph Koshy 	PMCMASK(unpack,			0x08),
2125ebccf1e3SJoseph Koshy 	PMCMASK(packed-logical,		0x10),
2126ebccf1e3SJoseph Koshy 	PMCMASK(packed-arithmetic,	0x20),
2127ebccf1e3SJoseph Koshy 	NULLMASK
2128ebccf1e3SJoseph Koshy };
2129ebccf1e3SJoseph Koshy 
2130ebccf1e3SJoseph Koshy static struct pmc_masks p6_mask_fmt[] = {
2131ebccf1e3SJoseph Koshy 	PMCMASK(mmxtofp,	0x00),
2132ebccf1e3SJoseph Koshy 	PMCMASK(fptommx,	0x01),
2133ebccf1e3SJoseph Koshy 	NULLMASK
2134ebccf1e3SJoseph Koshy };
2135ebccf1e3SJoseph Koshy 
2136ebccf1e3SJoseph Koshy static struct pmc_masks p6_mask_sr[] = {
2137ebccf1e3SJoseph Koshy 	PMCMASK(es,	0x01),
2138ebccf1e3SJoseph Koshy 	PMCMASK(ds,	0x02),
2139ebccf1e3SJoseph Koshy 	PMCMASK(fs,	0x04),
2140ebccf1e3SJoseph Koshy 	PMCMASK(gs,	0x08),
2141ebccf1e3SJoseph Koshy 	NULLMASK
2142ebccf1e3SJoseph Koshy };
2143ebccf1e3SJoseph Koshy 
2144ebccf1e3SJoseph Koshy static struct pmc_masks p6_mask_eet[] = {
2145ebccf1e3SJoseph Koshy 	PMCMASK(all,	0x00),
2146ebccf1e3SJoseph Koshy 	PMCMASK(freq,	0x02),
2147ebccf1e3SJoseph Koshy 	NULLMASK
2148ebccf1e3SJoseph Koshy };
2149ebccf1e3SJoseph Koshy 
2150ebccf1e3SJoseph Koshy static struct pmc_masks p6_mask_efur[] = {
2151ebccf1e3SJoseph Koshy 	PMCMASK(all,	0x00),
2152ebccf1e3SJoseph Koshy 	PMCMASK(loadop,	0x01),
2153ebccf1e3SJoseph Koshy 	PMCMASK(stdsta,	0x02),
2154ebccf1e3SJoseph Koshy 	NULLMASK
2155ebccf1e3SJoseph Koshy };
2156ebccf1e3SJoseph Koshy 
2157ebccf1e3SJoseph Koshy static struct pmc_masks p6_mask_essir[] = {
2158ebccf1e3SJoseph Koshy 	PMCMASK(sse-packed-single,	0x00),
2159ebccf1e3SJoseph Koshy 	PMCMASK(sse-packed-single-scalar-single, 0x01),
2160ebccf1e3SJoseph Koshy 	PMCMASK(sse2-packed-double,	0x02),
2161ebccf1e3SJoseph Koshy 	PMCMASK(sse2-scalar-double,	0x03),
2162ebccf1e3SJoseph Koshy 	NULLMASK
2163ebccf1e3SJoseph Koshy };
2164ebccf1e3SJoseph Koshy 
2165ebccf1e3SJoseph Koshy static struct pmc_masks p6_mask_esscir[] = {
2166ebccf1e3SJoseph Koshy 	PMCMASK(sse-packed-single,	0x00),
2167ebccf1e3SJoseph Koshy 	PMCMASK(sse-scalar-single,	0x01),
2168ebccf1e3SJoseph Koshy 	PMCMASK(sse2-packed-double,	0x02),
2169ebccf1e3SJoseph Koshy 	PMCMASK(sse2-scalar-double,	0x03),
2170ebccf1e3SJoseph Koshy 	NULLMASK
2171ebccf1e3SJoseph Koshy };
2172ebccf1e3SJoseph Koshy 
2173ebccf1e3SJoseph Koshy /* P6 event parser */
2174ebccf1e3SJoseph Koshy static int
2175ebccf1e3SJoseph Koshy p6_allocate_pmc(enum pmc_event pe, char *ctrspec,
2176ebccf1e3SJoseph Koshy     struct pmc_op_pmcallocate *pmc_config)
2177ebccf1e3SJoseph Koshy {
2178ebccf1e3SJoseph Koshy 	char *e, *p, *q;
21791e862e5aSFabien Thomas 	uint64_t evmask;
2180ebccf1e3SJoseph Koshy 	int count, n;
2181ebccf1e3SJoseph Koshy 	const struct pmc_masks *pm, *pmask;
2182ebccf1e3SJoseph Koshy 
2183789140c0SJoseph Koshy 	pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE);
2184f263522aSJoseph Koshy 	pmc_config->pm_md.pm_ppro.pm_ppro_config = 0;
2185ebccf1e3SJoseph Koshy 
2186ebccf1e3SJoseph Koshy 	evmask = 0;
2187ebccf1e3SJoseph Koshy 
2188ebccf1e3SJoseph Koshy #define	P6MASKSET(M)	pmask = p6_mask_ ## M
2189ebccf1e3SJoseph Koshy 
2190ebccf1e3SJoseph Koshy 	switch(pe) {
2191ebccf1e3SJoseph Koshy 	case PMC_EV_P6_L2_IFETCH:	P6MASKSET(mesi); break;
2192ebccf1e3SJoseph Koshy 	case PMC_EV_P6_L2_LD:		P6MASKSET(mesi); break;
2193ebccf1e3SJoseph Koshy 	case PMC_EV_P6_L2_ST:		P6MASKSET(mesi); break;
2194ebccf1e3SJoseph Koshy 	case PMC_EV_P6_L2_RQSTS:	P6MASKSET(mesi); break;
2195ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_DRDY_CLOCKS:
2196ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_LOCK_CLOCKS:
2197ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_BRD:
2198ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_RFO:
2199ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRANS_WB:
2200ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_IFETCH:
2201ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_INVAL:
2202ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_PWR:
2203ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRANS_P:
2204ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRANS_IO:
2205ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_DEF:
2206ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_BURST:
2207ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_ANY:
2208ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_MEM:
2209ebccf1e3SJoseph Koshy 		P6MASKSET(any);	break;
2210ebccf1e3SJoseph Koshy 	case PMC_EV_P6_EMON_KNI_PREF_DISPATCHED:
2211ebccf1e3SJoseph Koshy 	case PMC_EV_P6_EMON_KNI_PREF_MISS:
2212ebccf1e3SJoseph Koshy 		P6MASKSET(ekp); break;
2213ebccf1e3SJoseph Koshy 	case PMC_EV_P6_EMON_KNI_INST_RETIRED:
2214ebccf1e3SJoseph Koshy 	case PMC_EV_P6_EMON_KNI_COMP_INST_RET:
2215ebccf1e3SJoseph Koshy 		P6MASKSET(pps);	break;
2216ebccf1e3SJoseph Koshy 	case PMC_EV_P6_MMX_INSTR_TYPE_EXEC:
2217ebccf1e3SJoseph Koshy 		P6MASKSET(mite); break;
2218ebccf1e3SJoseph Koshy 	case PMC_EV_P6_FP_MMX_TRANS:
2219ebccf1e3SJoseph Koshy 		P6MASKSET(fmt);	break;
2220ebccf1e3SJoseph Koshy 	case PMC_EV_P6_SEG_RENAME_STALLS:
2221ebccf1e3SJoseph Koshy 	case PMC_EV_P6_SEG_REG_RENAMES:
2222ebccf1e3SJoseph Koshy 		P6MASKSET(sr);	break;
2223ebccf1e3SJoseph Koshy 	case PMC_EV_P6_EMON_EST_TRANS:
2224ebccf1e3SJoseph Koshy 		P6MASKSET(eet);	break;
2225ebccf1e3SJoseph Koshy 	case PMC_EV_P6_EMON_FUSED_UOPS_RET:
2226ebccf1e3SJoseph Koshy 		P6MASKSET(efur); break;
2227ebccf1e3SJoseph Koshy 	case PMC_EV_P6_EMON_SSE_SSE2_INST_RETIRED:
2228ebccf1e3SJoseph Koshy 		P6MASKSET(essir); break;
2229ebccf1e3SJoseph Koshy 	case PMC_EV_P6_EMON_SSE_SSE2_COMP_INST_RETIRED:
2230ebccf1e3SJoseph Koshy 		P6MASKSET(esscir); break;
2231ebccf1e3SJoseph Koshy 	default:
2232ebccf1e3SJoseph Koshy 		pmask = NULL;
2233ebccf1e3SJoseph Koshy 		break;
2234ebccf1e3SJoseph Koshy 	}
2235ebccf1e3SJoseph Koshy 
2236ebccf1e3SJoseph Koshy 	/* Pentium M PMCs have a few events with different semantics */
2237ebccf1e3SJoseph Koshy 	if (cpu_info.pm_cputype == PMC_CPU_INTEL_PM) {
2238ebccf1e3SJoseph Koshy 		if (pe == PMC_EV_P6_L2_LD ||
2239ebccf1e3SJoseph Koshy 		    pe == PMC_EV_P6_L2_LINES_IN ||
2240ebccf1e3SJoseph Koshy 		    pe == PMC_EV_P6_L2_LINES_OUT)
2241ebccf1e3SJoseph Koshy 			P6MASKSET(mesihw);
2242ebccf1e3SJoseph Koshy 		else if (pe == PMC_EV_P6_L2_M_LINES_OUTM)
2243ebccf1e3SJoseph Koshy 			P6MASKSET(hw);
2244ebccf1e3SJoseph Koshy 	}
2245ebccf1e3SJoseph Koshy 
2246ebccf1e3SJoseph Koshy 	/* Parse additional modifiers if present */
2247ebccf1e3SJoseph Koshy 	while ((p = strsep(&ctrspec, ",")) != NULL) {
2248ebccf1e3SJoseph Koshy 		if (KWPREFIXMATCH(p, P6_KW_CMASK "=")) {
2249ebccf1e3SJoseph Koshy 			q = strchr(p, '=');
2250ebccf1e3SJoseph Koshy 			if (*++q == '\0') /* skip '=' */
2251aa342b1fSJoseph Koshy 				return (-1);
2252ebccf1e3SJoseph Koshy 			count = strtol(q, &e, 0);
2253ebccf1e3SJoseph Koshy 			if (e == q || *e != '\0')
2254aa342b1fSJoseph Koshy 				return (-1);
2255ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_THRESHOLD;
2256f263522aSJoseph Koshy 			pmc_config->pm_md.pm_ppro.pm_ppro_config |=
2257f263522aSJoseph Koshy 			    P6_EVSEL_TO_CMASK(count);
2258ebccf1e3SJoseph Koshy 		} else if (KWMATCH(p, P6_KW_EDGE)) {
2259ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_EDGE;
2260ebccf1e3SJoseph Koshy 		} else if (KWMATCH(p, P6_KW_INV)) {
2261ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_INVERT;
2262ebccf1e3SJoseph Koshy 		} else if (KWMATCH(p, P6_KW_OS)) {
2263ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_SYSTEM;
2264ebccf1e3SJoseph Koshy 		} else if (KWPREFIXMATCH(p, P6_KW_UMASK "=")) {
2265ebccf1e3SJoseph Koshy 			evmask = 0;
2266ebccf1e3SJoseph Koshy 			if ((n = pmc_parse_mask(pmask, p, &evmask)) < 0)
2267aa342b1fSJoseph Koshy 				return (-1);
2268ebccf1e3SJoseph Koshy 			if ((pe == PMC_EV_P6_BUS_DRDY_CLOCKS ||
2269ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_BUS_LOCK_CLOCKS ||
2270ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_BUS_TRAN_BRD ||
2271ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_BUS_TRAN_RFO ||
2272ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_BUS_TRAN_IFETCH ||
2273ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_BUS_TRAN_INVAL ||
2274ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_BUS_TRAN_PWR ||
2275ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_BUS_TRAN_DEF ||
2276ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_BUS_TRAN_BURST ||
2277ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_BUS_TRAN_ANY ||
2278ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_BUS_TRAN_MEM ||
2279ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_BUS_TRANS_IO ||
2280ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_BUS_TRANS_P ||
2281ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_BUS_TRANS_WB ||
2282ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_EMON_EST_TRANS ||
2283ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_EMON_FUSED_UOPS_RET ||
2284ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_EMON_KNI_COMP_INST_RET ||
2285ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_EMON_KNI_INST_RETIRED ||
2286ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_EMON_KNI_PREF_DISPATCHED ||
2287ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_EMON_KNI_PREF_MISS ||
2288ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_EMON_SSE_SSE2_COMP_INST_RETIRED ||
2289ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_EMON_SSE_SSE2_INST_RETIRED ||
2290ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_FP_MMX_TRANS)
2291aa342b1fSJoseph Koshy 			    && (n > 1))	/* Only one mask keyword is allowed. */
2292aa342b1fSJoseph Koshy 				return (-1);
2293ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_QUALIFIER;
2294ebccf1e3SJoseph Koshy 		} else if (KWMATCH(p, P6_KW_USR)) {
2295ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_USER;
2296ebccf1e3SJoseph Koshy 		} else
2297aa342b1fSJoseph Koshy 			return (-1);
2298ebccf1e3SJoseph Koshy 	}
2299ebccf1e3SJoseph Koshy 
2300ebccf1e3SJoseph Koshy 	/* post processing */
2301ebccf1e3SJoseph Koshy 	switch (pe) {
2302ebccf1e3SJoseph Koshy 
2303ebccf1e3SJoseph Koshy 		/*
2304ebccf1e3SJoseph Koshy 		 * The following events default to an evmask of 0
2305ebccf1e3SJoseph Koshy 		 */
2306ebccf1e3SJoseph Koshy 
2307ebccf1e3SJoseph Koshy 		/* default => 'self' */
2308ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_DRDY_CLOCKS:
2309ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_LOCK_CLOCKS:
2310ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_BRD:
2311ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_RFO:
2312ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRANS_WB:
2313ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_IFETCH:
2314ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_INVAL:
2315ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_PWR:
2316ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRANS_P:
2317ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRANS_IO:
2318ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_DEF:
2319ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_BURST:
2320ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_ANY:
2321ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_MEM:
2322ebccf1e3SJoseph Koshy 
2323ebccf1e3SJoseph Koshy 		/* default => 'nta' */
2324ebccf1e3SJoseph Koshy 	case PMC_EV_P6_EMON_KNI_PREF_DISPATCHED:
2325ebccf1e3SJoseph Koshy 	case PMC_EV_P6_EMON_KNI_PREF_MISS:
2326ebccf1e3SJoseph Koshy 
2327ebccf1e3SJoseph Koshy 		/* default => 'packed and scalar' */
2328ebccf1e3SJoseph Koshy 	case PMC_EV_P6_EMON_KNI_INST_RETIRED:
2329ebccf1e3SJoseph Koshy 	case PMC_EV_P6_EMON_KNI_COMP_INST_RET:
2330ebccf1e3SJoseph Koshy 
2331ebccf1e3SJoseph Koshy 		/* default => 'mmx to fp transitions' */
2332ebccf1e3SJoseph Koshy 	case PMC_EV_P6_FP_MMX_TRANS:
2333ebccf1e3SJoseph Koshy 
2334ebccf1e3SJoseph Koshy 		/* default => 'SSE Packed Single' */
2335ebccf1e3SJoseph Koshy 	case PMC_EV_P6_EMON_SSE_SSE2_INST_RETIRED:
2336ebccf1e3SJoseph Koshy 	case PMC_EV_P6_EMON_SSE_SSE2_COMP_INST_RETIRED:
2337ebccf1e3SJoseph Koshy 
2338ebccf1e3SJoseph Koshy 		/* default => 'all fused micro-ops' */
2339ebccf1e3SJoseph Koshy 	case PMC_EV_P6_EMON_FUSED_UOPS_RET:
2340ebccf1e3SJoseph Koshy 
2341ebccf1e3SJoseph Koshy 		/* default => 'all transitions' */
2342ebccf1e3SJoseph Koshy 	case PMC_EV_P6_EMON_EST_TRANS:
2343ebccf1e3SJoseph Koshy 		break;
2344ebccf1e3SJoseph Koshy 
2345ebccf1e3SJoseph Koshy 	case PMC_EV_P6_MMX_UOPS_EXEC:
2346ebccf1e3SJoseph Koshy 		evmask = 0x0F;		/* only value allowed */
2347ebccf1e3SJoseph Koshy 		break;
2348ebccf1e3SJoseph Koshy 
2349ebccf1e3SJoseph Koshy 	default:
2350ebccf1e3SJoseph Koshy 		/*
2351ebccf1e3SJoseph Koshy 		 * For all other events, set the default event mask
2352ebccf1e3SJoseph Koshy 		 * to a logical OR of all the allowed event mask bits.
2353ebccf1e3SJoseph Koshy 		 */
2354ebccf1e3SJoseph Koshy 		if (evmask == 0 && pmask) {
2355ebccf1e3SJoseph Koshy 			for (pm = pmask; pm->pm_name; pm++)
2356ebccf1e3SJoseph Koshy 				evmask |= pm->pm_value;
2357ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_QUALIFIER;
2358ebccf1e3SJoseph Koshy 		}
2359ebccf1e3SJoseph Koshy 
2360ebccf1e3SJoseph Koshy 		break;
2361ebccf1e3SJoseph Koshy 	}
2362ebccf1e3SJoseph Koshy 
2363ebccf1e3SJoseph Koshy 	if (pmc_config->pm_caps & PMC_CAP_QUALIFIER)
2364f263522aSJoseph Koshy 		pmc_config->pm_md.pm_ppro.pm_ppro_config |=
2365f263522aSJoseph Koshy 		    P6_EVSEL_TO_UMASK(evmask);
2366ebccf1e3SJoseph Koshy 
2367aa342b1fSJoseph Koshy 	return (0);
2368ebccf1e3SJoseph Koshy }
2369ebccf1e3SJoseph Koshy 
2370ebccf1e3SJoseph Koshy #endif
2371ebccf1e3SJoseph Koshy 
2372789140c0SJoseph Koshy #if	defined(__i386__) || defined(__amd64__)
2373789140c0SJoseph Koshy static int
2374789140c0SJoseph Koshy tsc_allocate_pmc(enum pmc_event pe, char *ctrspec,
2375789140c0SJoseph Koshy     struct pmc_op_pmcallocate *pmc_config)
2376789140c0SJoseph Koshy {
2377789140c0SJoseph Koshy 	if (pe != PMC_EV_TSC_TSC)
2378789140c0SJoseph Koshy 		return (-1);
2379789140c0SJoseph Koshy 
2380789140c0SJoseph Koshy 	/* TSC events must be unqualified. */
2381789140c0SJoseph Koshy 	if (ctrspec && *ctrspec != '\0')
2382789140c0SJoseph Koshy 		return (-1);
2383789140c0SJoseph Koshy 
2384789140c0SJoseph Koshy 	pmc_config->pm_md.pm_amd.pm_amd_config = 0;
2385789140c0SJoseph Koshy 	pmc_config->pm_caps |= PMC_CAP_READ;
2386789140c0SJoseph Koshy 
2387789140c0SJoseph Koshy 	return (0);
2388789140c0SJoseph Koshy }
2389789140c0SJoseph Koshy #endif
2390789140c0SJoseph Koshy 
2391f5f9340bSFabien Thomas static struct pmc_event_alias generic_aliases[] = {
2392f5f9340bSFabien Thomas 	EV_ALIAS("instructions",		"SOFT-CLOCK.HARD"),
2393f5f9340bSFabien Thomas 	EV_ALIAS(NULL, NULL)
2394f5f9340bSFabien Thomas };
2395f5f9340bSFabien Thomas 
2396f5f9340bSFabien Thomas static int
2397f5f9340bSFabien Thomas soft_allocate_pmc(enum pmc_event pe, char *ctrspec,
2398f5f9340bSFabien Thomas     struct pmc_op_pmcallocate *pmc_config)
2399f5f9340bSFabien Thomas {
2400f5f9340bSFabien Thomas 	(void)ctrspec;
2401f5f9340bSFabien Thomas 	(void)pmc_config;
2402f5f9340bSFabien Thomas 
2403f0bbe9aaSDimitry Andric 	if ((int)pe < PMC_EV_SOFT_FIRST || (int)pe > PMC_EV_SOFT_LAST)
2404f5f9340bSFabien Thomas 		return (-1);
2405f5f9340bSFabien Thomas 
2406f5f9340bSFabien Thomas 	pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE);
2407f5f9340bSFabien Thomas 	return (0);
2408f5f9340bSFabien Thomas }
2409f5f9340bSFabien Thomas 
24106411d14dSRuslan Bukin #if	defined(__arm__)
24110ce207d2SRui Paulo #if	defined(__XSCALE__)
24120ce207d2SRui Paulo 
24130ce207d2SRui Paulo static struct pmc_event_alias xscale_aliases[] = {
24140ce207d2SRui Paulo 	EV_ALIAS("branches",		"BRANCH_RETIRED"),
24150ce207d2SRui Paulo 	EV_ALIAS("branch-mispredicts",	"BRANCH_MISPRED"),
24160ce207d2SRui Paulo 	EV_ALIAS("dc-misses",		"DC_MISS"),
24170ce207d2SRui Paulo 	EV_ALIAS("ic-misses",		"IC_MISS"),
24180ce207d2SRui Paulo 	EV_ALIAS("instructions",	"INSTR_RETIRED"),
24190ce207d2SRui Paulo 	EV_ALIAS(NULL, NULL)
24200ce207d2SRui Paulo };
24210ce207d2SRui Paulo static int
24220ce207d2SRui Paulo xscale_allocate_pmc(enum pmc_event pe, char *ctrspec __unused,
24230ce207d2SRui Paulo     struct pmc_op_pmcallocate *pmc_config __unused)
24240ce207d2SRui Paulo {
24250ce207d2SRui Paulo 	switch (pe) {
24260ce207d2SRui Paulo 	default:
24270ce207d2SRui Paulo 		break;
24280ce207d2SRui Paulo 	}
24290ce207d2SRui Paulo 
24300ce207d2SRui Paulo 	return (0);
24310ce207d2SRui Paulo }
24320ce207d2SRui Paulo #endif
24330ce207d2SRui Paulo 
24346411d14dSRuslan Bukin static struct pmc_event_alias armv7_aliases[] = {
24356411d14dSRuslan Bukin 	EV_ALIAS("dc-misses",		"L1_DCACHE_REFILL"),
24366411d14dSRuslan Bukin 	EV_ALIAS("ic-misses",		"L1_ICACHE_REFILL"),
24376411d14dSRuslan Bukin 	EV_ALIAS("instructions",	"INSTR_EXECUTED"),
24386411d14dSRuslan Bukin 	EV_ALIAS(NULL, NULL)
24396411d14dSRuslan Bukin };
24406411d14dSRuslan Bukin static int
24416411d14dSRuslan Bukin armv7_allocate_pmc(enum pmc_event pe, char *ctrspec __unused,
24426411d14dSRuslan Bukin     struct pmc_op_pmcallocate *pmc_config __unused)
24436411d14dSRuslan Bukin {
24446411d14dSRuslan Bukin 	switch (pe) {
24456411d14dSRuslan Bukin 	default:
24466411d14dSRuslan Bukin 		break;
24476411d14dSRuslan Bukin 	}
24486411d14dSRuslan Bukin 
24496411d14dSRuslan Bukin 	return (0);
24506411d14dSRuslan Bukin }
24516411d14dSRuslan Bukin #endif
24526411d14dSRuslan Bukin 
2453*bc88bb2bSRuslan Bukin #if	defined(__aarch64__)
2454*bc88bb2bSRuslan Bukin static struct pmc_event_alias cortex_a53_aliases[] = {
2455*bc88bb2bSRuslan Bukin 	EV_ALIAS(NULL, NULL)
2456*bc88bb2bSRuslan Bukin };
2457*bc88bb2bSRuslan Bukin static struct pmc_event_alias cortex_a57_aliases[] = {
2458*bc88bb2bSRuslan Bukin 	EV_ALIAS(NULL, NULL)
2459*bc88bb2bSRuslan Bukin };
2460*bc88bb2bSRuslan Bukin static int
2461*bc88bb2bSRuslan Bukin arm64_allocate_pmc(enum pmc_event pe, char *ctrspec __unused,
2462*bc88bb2bSRuslan Bukin     struct pmc_op_pmcallocate *pmc_config __unused)
2463*bc88bb2bSRuslan Bukin {
2464*bc88bb2bSRuslan Bukin 	switch (pe) {
2465*bc88bb2bSRuslan Bukin 	default:
2466*bc88bb2bSRuslan Bukin 		break;
2467*bc88bb2bSRuslan Bukin 	}
2468*bc88bb2bSRuslan Bukin 
2469*bc88bb2bSRuslan Bukin 	return (0);
2470*bc88bb2bSRuslan Bukin }
2471*bc88bb2bSRuslan Bukin #endif
2472*bc88bb2bSRuslan Bukin 
2473660df75eSGeorge V. Neville-Neil #if defined(__mips__)
2474660df75eSGeorge V. Neville-Neil 
2475660df75eSGeorge V. Neville-Neil static struct pmc_event_alias mips24k_aliases[] = {
2476660df75eSGeorge V. Neville-Neil 	EV_ALIAS("instructions",	"INSTR_EXECUTED"),
2477660df75eSGeorge V. Neville-Neil 	EV_ALIAS("branches",		"BRANCH_COMPLETED"),
2478660df75eSGeorge V. Neville-Neil 	EV_ALIAS("branch-mispredicts",	"BRANCH_MISPRED"),
2479660df75eSGeorge V. Neville-Neil 	EV_ALIAS(NULL, NULL)
2480660df75eSGeorge V. Neville-Neil };
2481660df75eSGeorge V. Neville-Neil 
2482f6e6460dSAdrian Chadd static struct pmc_event_alias mips74k_aliases[] = {
2483f6e6460dSAdrian Chadd 	EV_ALIAS("instructions",	"INSTR_EXECUTED"),
2484f6e6460dSAdrian Chadd 	EV_ALIAS("branches",		"BRANCH_INSNS"),
2485f6e6460dSAdrian Chadd 	EV_ALIAS("branch-mispredicts",	"MISPREDICTED_BRANCH_INSNS"),
2486f6e6460dSAdrian Chadd 	EV_ALIAS(NULL, NULL)
2487f6e6460dSAdrian Chadd };
2488f6e6460dSAdrian Chadd 
2489c2657f80SOleksandr Tymoshenko static struct pmc_event_alias octeon_aliases[] = {
2490c2657f80SOleksandr Tymoshenko 	EV_ALIAS("instructions",	"RET"),
2491c2657f80SOleksandr Tymoshenko 	EV_ALIAS("branches",		"BR"),
2492c2657f80SOleksandr Tymoshenko 	EV_ALIAS("branch-mispredicts",	"BRMIS"),
2493c2657f80SOleksandr Tymoshenko 	EV_ALIAS(NULL, NULL)
2494c2657f80SOleksandr Tymoshenko };
2495c2657f80SOleksandr Tymoshenko 
24962827d3e1SOleksandr Tymoshenko #define	MIPS_KW_OS		"os"
24972827d3e1SOleksandr Tymoshenko #define	MIPS_KW_USR		"usr"
24982827d3e1SOleksandr Tymoshenko #define	MIPS_KW_ANYTHREAD	"anythread"
2499660df75eSGeorge V. Neville-Neil 
2500660df75eSGeorge V. Neville-Neil static int
25012827d3e1SOleksandr Tymoshenko mips_allocate_pmc(enum pmc_event pe, char *ctrspec __unused,
2502660df75eSGeorge V. Neville-Neil 		  struct pmc_op_pmcallocate *pmc_config __unused)
2503660df75eSGeorge V. Neville-Neil {
2504660df75eSGeorge V. Neville-Neil 	char *p;
2505660df75eSGeorge V. Neville-Neil 
2506660df75eSGeorge V. Neville-Neil 	(void) pe;
2507660df75eSGeorge V. Neville-Neil 
2508660df75eSGeorge V. Neville-Neil 	pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE);
2509660df75eSGeorge V. Neville-Neil 
2510660df75eSGeorge V. Neville-Neil 	while ((p = strsep(&ctrspec, ",")) != NULL) {
25112827d3e1SOleksandr Tymoshenko 		if (KWMATCH(p, MIPS_KW_OS))
2512660df75eSGeorge V. Neville-Neil 			pmc_config->pm_caps |= PMC_CAP_SYSTEM;
25132827d3e1SOleksandr Tymoshenko 		else if (KWMATCH(p, MIPS_KW_USR))
2514660df75eSGeorge V. Neville-Neil 			pmc_config->pm_caps |= PMC_CAP_USER;
25152827d3e1SOleksandr Tymoshenko 		else if (KWMATCH(p, MIPS_KW_ANYTHREAD))
2516660df75eSGeorge V. Neville-Neil 			pmc_config->pm_caps |= (PMC_CAP_USER | PMC_CAP_SYSTEM);
2517660df75eSGeorge V. Neville-Neil 		else
2518660df75eSGeorge V. Neville-Neil 			return (-1);
2519660df75eSGeorge V. Neville-Neil 	}
2520660df75eSGeorge V. Neville-Neil 
2521660df75eSGeorge V. Neville-Neil 	return (0);
2522660df75eSGeorge V. Neville-Neil }
25232827d3e1SOleksandr Tymoshenko 
2524660df75eSGeorge V. Neville-Neil #endif /* __mips__ */
2525660df75eSGeorge V. Neville-Neil 
25267b25dccaSJustin Hibbits #if defined(__powerpc__)
25277b25dccaSJustin Hibbits 
25287b25dccaSJustin Hibbits static struct pmc_event_alias ppc7450_aliases[] = {
25297b25dccaSJustin Hibbits 	EV_ALIAS("instructions",	"INSTR_COMPLETED"),
25307b25dccaSJustin Hibbits 	EV_ALIAS("branches",		"BRANCHES_COMPLETED"),
25317b25dccaSJustin Hibbits 	EV_ALIAS("branch-mispredicts",	"MISPREDICTED_BRANCHES"),
25327b25dccaSJustin Hibbits 	EV_ALIAS(NULL, NULL)
25337b25dccaSJustin Hibbits };
25347b25dccaSJustin Hibbits 
2535169dd953SJustin Hibbits static struct pmc_event_alias ppc970_aliases[] = {
2536169dd953SJustin Hibbits 	EV_ALIAS("instructions", "INSTR_COMPLETED"),
2537169dd953SJustin Hibbits 	EV_ALIAS("cycles",       "CYCLES"),
2538169dd953SJustin Hibbits 	EV_ALIAS(NULL, NULL)
2539169dd953SJustin Hibbits };
2540169dd953SJustin Hibbits 
2541a7452468SJustin Hibbits static struct pmc_event_alias e500_aliases[] = {
2542a7452468SJustin Hibbits 	EV_ALIAS("instructions", "INSTR_COMPLETED"),
2543a7452468SJustin Hibbits 	EV_ALIAS("cycles",       "CYCLES"),
2544a7452468SJustin Hibbits 	EV_ALIAS(NULL, NULL)
2545a7452468SJustin Hibbits };
2546a7452468SJustin Hibbits 
2547169dd953SJustin Hibbits #define	POWERPC_KW_OS		"os"
2548169dd953SJustin Hibbits #define	POWERPC_KW_USR		"usr"
2549169dd953SJustin Hibbits #define	POWERPC_KW_ANYTHREAD	"anythread"
25507b25dccaSJustin Hibbits 
25517b25dccaSJustin Hibbits static int
2552169dd953SJustin Hibbits powerpc_allocate_pmc(enum pmc_event pe, char *ctrspec __unused,
25537b25dccaSJustin Hibbits 		     struct pmc_op_pmcallocate *pmc_config __unused)
25547b25dccaSJustin Hibbits {
25557b25dccaSJustin Hibbits 	char *p;
25567b25dccaSJustin Hibbits 
25577b25dccaSJustin Hibbits 	(void) pe;
25587b25dccaSJustin Hibbits 
25597b25dccaSJustin Hibbits 	pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE);
25607b25dccaSJustin Hibbits 
25617b25dccaSJustin Hibbits 	while ((p = strsep(&ctrspec, ",")) != NULL) {
2562169dd953SJustin Hibbits 		if (KWMATCH(p, POWERPC_KW_OS))
25637b25dccaSJustin Hibbits 			pmc_config->pm_caps |= PMC_CAP_SYSTEM;
2564169dd953SJustin Hibbits 		else if (KWMATCH(p, POWERPC_KW_USR))
25657b25dccaSJustin Hibbits 			pmc_config->pm_caps |= PMC_CAP_USER;
2566169dd953SJustin Hibbits 		else if (KWMATCH(p, POWERPC_KW_ANYTHREAD))
25677b25dccaSJustin Hibbits 			pmc_config->pm_caps |= (PMC_CAP_USER | PMC_CAP_SYSTEM);
25687b25dccaSJustin Hibbits 		else
25697b25dccaSJustin Hibbits 			return (-1);
25707b25dccaSJustin Hibbits 	}
25717b25dccaSJustin Hibbits 
25727b25dccaSJustin Hibbits 	return (0);
25737b25dccaSJustin Hibbits }
2574169dd953SJustin Hibbits 
25757b25dccaSJustin Hibbits #endif /* __powerpc__ */
25767b25dccaSJustin Hibbits 
2577660df75eSGeorge V. Neville-Neil 
2578789140c0SJoseph Koshy /*
2579789140c0SJoseph Koshy  * Match an event name `name' with its canonical form.
2580789140c0SJoseph Koshy  *
25810cfab8ddSJoseph Koshy  * Matches are case insensitive and spaces, periods, underscores and
25820cfab8ddSJoseph Koshy  * hyphen characters are considered to match each other.
2583789140c0SJoseph Koshy  *
2584789140c0SJoseph Koshy  * Returns 1 for a match, 0 otherwise.
2585789140c0SJoseph Koshy  */
2586789140c0SJoseph Koshy 
2587789140c0SJoseph Koshy static int
2588789140c0SJoseph Koshy pmc_match_event_name(const char *name, const char *canonicalname)
2589789140c0SJoseph Koshy {
2590789140c0SJoseph Koshy 	int cc, nc;
2591789140c0SJoseph Koshy 	const unsigned char *c, *n;
2592789140c0SJoseph Koshy 
2593789140c0SJoseph Koshy 	c = (const unsigned char *) canonicalname;
2594789140c0SJoseph Koshy 	n = (const unsigned char *) name;
2595789140c0SJoseph Koshy 
2596789140c0SJoseph Koshy 	for (; (nc = *n) && (cc = *c); n++, c++) {
2597789140c0SJoseph Koshy 
25980cfab8ddSJoseph Koshy 		if ((nc == ' ' || nc == '_' || nc == '-' || nc == '.') &&
25990cfab8ddSJoseph Koshy 		    (cc == ' ' || cc == '_' || cc == '-' || cc == '.'))
2600789140c0SJoseph Koshy 			continue;
2601789140c0SJoseph Koshy 
26020cfab8ddSJoseph Koshy 		if (toupper(nc) == toupper(cc))
2603789140c0SJoseph Koshy 			continue;
2604789140c0SJoseph Koshy 
26050cfab8ddSJoseph Koshy 
2606789140c0SJoseph Koshy 		return (0);
2607789140c0SJoseph Koshy 	}
2608789140c0SJoseph Koshy 
2609789140c0SJoseph Koshy 	if (*n == '\0' && *c == '\0')
2610789140c0SJoseph Koshy 		return (1);
2611789140c0SJoseph Koshy 
2612789140c0SJoseph Koshy 	return (0);
2613789140c0SJoseph Koshy }
2614789140c0SJoseph Koshy 
2615789140c0SJoseph Koshy /*
2616789140c0SJoseph Koshy  * Match an event name against all the event named supported by a
2617789140c0SJoseph Koshy  * PMC class.
2618789140c0SJoseph Koshy  *
2619789140c0SJoseph Koshy  * Returns an event descriptor pointer on match or NULL otherwise.
2620789140c0SJoseph Koshy  */
2621789140c0SJoseph Koshy static const struct pmc_event_descr *
2622789140c0SJoseph Koshy pmc_match_event_class(const char *name,
2623789140c0SJoseph Koshy     const struct pmc_class_descr *pcd)
2624789140c0SJoseph Koshy {
2625789140c0SJoseph Koshy 	size_t n;
2626789140c0SJoseph Koshy 	const struct pmc_event_descr *ev;
2627789140c0SJoseph Koshy 
2628789140c0SJoseph Koshy 	ev = pcd->pm_evc_event_table;
2629789140c0SJoseph Koshy 	for (n = 0; n < pcd->pm_evc_event_table_size; n++, ev++)
2630789140c0SJoseph Koshy 		if (pmc_match_event_name(name, ev->pm_ev_name))
2631789140c0SJoseph Koshy 			return (ev);
2632789140c0SJoseph Koshy 
2633789140c0SJoseph Koshy 	return (NULL);
2634789140c0SJoseph Koshy }
2635789140c0SJoseph Koshy 
2636789140c0SJoseph Koshy static int
2637789140c0SJoseph Koshy pmc_mdep_is_compatible_class(enum pmc_class pc)
2638789140c0SJoseph Koshy {
2639789140c0SJoseph Koshy 	size_t n;
2640789140c0SJoseph Koshy 
2641789140c0SJoseph Koshy 	for (n = 0; n < pmc_mdep_class_list_size; n++)
2642789140c0SJoseph Koshy 		if (pmc_mdep_class_list[n] == pc)
2643789140c0SJoseph Koshy 			return (1);
2644789140c0SJoseph Koshy 	return (0);
2645789140c0SJoseph Koshy }
2646789140c0SJoseph Koshy 
2647ebccf1e3SJoseph Koshy /*
2648ebccf1e3SJoseph Koshy  * API entry points
2649ebccf1e3SJoseph Koshy  */
2650ebccf1e3SJoseph Koshy 
2651ebccf1e3SJoseph Koshy int
2652ebccf1e3SJoseph Koshy pmc_allocate(const char *ctrspec, enum pmc_mode mode,
2653ebccf1e3SJoseph Koshy     uint32_t flags, int cpu, pmc_id_t *pmcid)
2654ebccf1e3SJoseph Koshy {
2655789140c0SJoseph Koshy 	size_t n;
2656ebccf1e3SJoseph Koshy 	int retval;
2657ebccf1e3SJoseph Koshy 	char *r, *spec_copy;
2658ebccf1e3SJoseph Koshy 	const char *ctrname;
2659789140c0SJoseph Koshy 	const struct pmc_event_descr *ev;
2660789140c0SJoseph Koshy 	const struct pmc_event_alias *alias;
2661ebccf1e3SJoseph Koshy 	struct pmc_op_pmcallocate pmc_config;
2662789140c0SJoseph Koshy 	const struct pmc_class_descr *pcd;
2663ebccf1e3SJoseph Koshy 
2664ebccf1e3SJoseph Koshy 	spec_copy = NULL;
2665ebccf1e3SJoseph Koshy 	retval    = -1;
2666ebccf1e3SJoseph Koshy 
2667ebccf1e3SJoseph Koshy 	if (mode != PMC_MODE_SS && mode != PMC_MODE_TS &&
2668ebccf1e3SJoseph Koshy 	    mode != PMC_MODE_SC && mode != PMC_MODE_TC) {
2669ebccf1e3SJoseph Koshy 		errno = EINVAL;
2670ebccf1e3SJoseph Koshy 		goto out;
2671ebccf1e3SJoseph Koshy 	}
2672ebccf1e3SJoseph Koshy 
2673ebccf1e3SJoseph Koshy 	/* replace an event alias with the canonical event specifier */
2674ebccf1e3SJoseph Koshy 	if (pmc_mdep_event_aliases)
2675789140c0SJoseph Koshy 		for (alias = pmc_mdep_event_aliases; alias->pm_alias; alias++)
2676789140c0SJoseph Koshy 			if (!strcasecmp(ctrspec, alias->pm_alias)) {
2677789140c0SJoseph Koshy 				spec_copy = strdup(alias->pm_spec);
2678ebccf1e3SJoseph Koshy 				break;
2679ebccf1e3SJoseph Koshy 			}
2680ebccf1e3SJoseph Koshy 
2681ebccf1e3SJoseph Koshy 	if (spec_copy == NULL)
2682ebccf1e3SJoseph Koshy 		spec_copy = strdup(ctrspec);
2683ebccf1e3SJoseph Koshy 
2684ebccf1e3SJoseph Koshy 	r = spec_copy;
2685ebccf1e3SJoseph Koshy 	ctrname = strsep(&r, ",");
2686ebccf1e3SJoseph Koshy 
2687789140c0SJoseph Koshy 	/*
2688789140c0SJoseph Koshy 	 * If a explicit class prefix was given by the user, restrict the
2689789140c0SJoseph Koshy 	 * search for the event to the specified PMC class.
2690789140c0SJoseph Koshy 	 */
2691789140c0SJoseph Koshy 	ev = NULL;
26920cfab8ddSJoseph Koshy 	for (n = 0; n < PMC_CLASS_TABLE_SIZE; n++) {
26930cfab8ddSJoseph Koshy 		pcd = pmc_class_table[n];
2694789140c0SJoseph Koshy 		if (pmc_mdep_is_compatible_class(pcd->pm_evc_class) &&
2695789140c0SJoseph Koshy 		    strncasecmp(ctrname, pcd->pm_evc_name,
2696789140c0SJoseph Koshy 				pcd->pm_evc_name_size) == 0) {
2697789140c0SJoseph Koshy 			if ((ev = pmc_match_event_class(ctrname +
2698789140c0SJoseph Koshy 			    pcd->pm_evc_name_size, pcd)) == NULL) {
2699789140c0SJoseph Koshy 				errno = EINVAL;
2700789140c0SJoseph Koshy 				goto out;
2701789140c0SJoseph Koshy 			}
2702ebccf1e3SJoseph Koshy 			break;
2703789140c0SJoseph Koshy 		}
2704789140c0SJoseph Koshy 	}
2705ebccf1e3SJoseph Koshy 
2706789140c0SJoseph Koshy 	/*
2707789140c0SJoseph Koshy 	 * Otherwise, search for this event in all compatible PMC
2708789140c0SJoseph Koshy 	 * classes.
2709789140c0SJoseph Koshy 	 */
27100cfab8ddSJoseph Koshy 	for (n = 0; ev == NULL && n < PMC_CLASS_TABLE_SIZE; n++) {
27110cfab8ddSJoseph Koshy 		pcd = pmc_class_table[n];
2712789140c0SJoseph Koshy 		if (pmc_mdep_is_compatible_class(pcd->pm_evc_class))
2713789140c0SJoseph Koshy 			ev = pmc_match_event_class(ctrname, pcd);
2714789140c0SJoseph Koshy 	}
2715789140c0SJoseph Koshy 
2716789140c0SJoseph Koshy 	if (ev == NULL) {
2717ebccf1e3SJoseph Koshy 		errno = EINVAL;
2718ebccf1e3SJoseph Koshy 		goto out;
2719ebccf1e3SJoseph Koshy 	}
2720ebccf1e3SJoseph Koshy 
2721ebccf1e3SJoseph Koshy 	bzero(&pmc_config, sizeof(pmc_config));
2722789140c0SJoseph Koshy 	pmc_config.pm_ev    = ev->pm_ev_code;
2723789140c0SJoseph Koshy 	pmc_config.pm_class = pcd->pm_evc_class;
2724ebccf1e3SJoseph Koshy 	pmc_config.pm_cpu   = cpu;
2725ebccf1e3SJoseph Koshy 	pmc_config.pm_mode  = mode;
2726ebccf1e3SJoseph Koshy 	pmc_config.pm_flags = flags;
2727ebccf1e3SJoseph Koshy 
2728ebccf1e3SJoseph Koshy 	if (PMC_IS_SAMPLING_MODE(mode))
2729ebccf1e3SJoseph Koshy 		pmc_config.pm_caps |= PMC_CAP_INTERRUPT;
2730ebccf1e3SJoseph Koshy 
2731789140c0SJoseph Koshy  	if (pcd->pm_evc_allocate_pmc(ev->pm_ev_code, r, &pmc_config) < 0) {
2732ebccf1e3SJoseph Koshy 		errno = EINVAL;
2733ebccf1e3SJoseph Koshy 		goto out;
2734ebccf1e3SJoseph Koshy 	}
2735ebccf1e3SJoseph Koshy 
2736ebccf1e3SJoseph Koshy 	if (PMC_CALL(PMCALLOCATE, &pmc_config) < 0)
2737ebccf1e3SJoseph Koshy 		goto out;
2738ebccf1e3SJoseph Koshy 
2739ebccf1e3SJoseph Koshy 	*pmcid = pmc_config.pm_pmcid;
2740ebccf1e3SJoseph Koshy 
2741ebccf1e3SJoseph Koshy 	retval = 0;
2742ebccf1e3SJoseph Koshy 
2743ebccf1e3SJoseph Koshy  out:
2744ebccf1e3SJoseph Koshy 	if (spec_copy)
2745ebccf1e3SJoseph Koshy 		free(spec_copy);
2746ebccf1e3SJoseph Koshy 
2747aa342b1fSJoseph Koshy 	return (retval);
2748ebccf1e3SJoseph Koshy }
2749ebccf1e3SJoseph Koshy 
2750ebccf1e3SJoseph Koshy int
2751ebccf1e3SJoseph Koshy pmc_attach(pmc_id_t pmc, pid_t pid)
2752ebccf1e3SJoseph Koshy {
2753ebccf1e3SJoseph Koshy 	struct pmc_op_pmcattach pmc_attach_args;
2754ebccf1e3SJoseph Koshy 
2755ebccf1e3SJoseph Koshy 	pmc_attach_args.pm_pmc = pmc;
2756ebccf1e3SJoseph Koshy 	pmc_attach_args.pm_pid = pid;
2757ebccf1e3SJoseph Koshy 
2758aa342b1fSJoseph Koshy 	return (PMC_CALL(PMCATTACH, &pmc_attach_args));
2759ebccf1e3SJoseph Koshy }
2760ebccf1e3SJoseph Koshy 
2761ebccf1e3SJoseph Koshy int
2762c5153e19SJoseph Koshy pmc_capabilities(pmc_id_t pmcid, uint32_t *caps)
2763c5153e19SJoseph Koshy {
2764c5153e19SJoseph Koshy 	unsigned int i;
2765c5153e19SJoseph Koshy 	enum pmc_class cl;
2766c5153e19SJoseph Koshy 
2767c5153e19SJoseph Koshy 	cl = PMC_ID_TO_CLASS(pmcid);
2768c5153e19SJoseph Koshy 	for (i = 0; i < cpu_info.pm_nclass; i++)
2769c5153e19SJoseph Koshy 		if (cpu_info.pm_classes[i].pm_class == cl) {
2770c5153e19SJoseph Koshy 			*caps = cpu_info.pm_classes[i].pm_caps;
2771aa342b1fSJoseph Koshy 			return (0);
2772c5153e19SJoseph Koshy 		}
2773484202faSJoseph Koshy 	errno = EINVAL;
2774484202faSJoseph Koshy 	return (-1);
2775c5153e19SJoseph Koshy }
2776c5153e19SJoseph Koshy 
2777f263522aSJoseph Koshy int
2778f263522aSJoseph Koshy pmc_configure_logfile(int fd)
2779ebccf1e3SJoseph Koshy {
2780f263522aSJoseph Koshy 	struct pmc_op_configurelog cla;
2781f263522aSJoseph Koshy 
2782f263522aSJoseph Koshy 	cla.pm_logfd = fd;
2783f263522aSJoseph Koshy 	if (PMC_CALL(CONFIGURELOG, &cla) < 0)
2784aa342b1fSJoseph Koshy 		return (-1);
2785aa342b1fSJoseph Koshy 	return (0);
2786ebccf1e3SJoseph Koshy }
2787ebccf1e3SJoseph Koshy 
2788f263522aSJoseph Koshy int
2789f263522aSJoseph Koshy pmc_cpuinfo(const struct pmc_cpuinfo **pci)
2790ebccf1e3SJoseph Koshy {
2791f263522aSJoseph Koshy 	if (pmc_syscall == -1) {
2792f263522aSJoseph Koshy 		errno = ENXIO;
2793aa342b1fSJoseph Koshy 		return (-1);
2794ebccf1e3SJoseph Koshy 	}
2795ebccf1e3SJoseph Koshy 
27961455fcd3SJoseph Koshy 	*pci = &cpu_info;
2797aa342b1fSJoseph Koshy 	return (0);
2798ebccf1e3SJoseph Koshy }
2799ebccf1e3SJoseph Koshy 
2800f263522aSJoseph Koshy int
2801f263522aSJoseph Koshy pmc_detach(pmc_id_t pmc, pid_t pid)
2802ebccf1e3SJoseph Koshy {
2803f263522aSJoseph Koshy 	struct pmc_op_pmcattach pmc_detach_args;
2804ebccf1e3SJoseph Koshy 
2805f263522aSJoseph Koshy 	pmc_detach_args.pm_pmc = pmc;
2806f263522aSJoseph Koshy 	pmc_detach_args.pm_pid = pid;
2807aa342b1fSJoseph Koshy 	return (PMC_CALL(PMCDETACH, &pmc_detach_args));
2808ebccf1e3SJoseph Koshy }
2809ebccf1e3SJoseph Koshy 
2810f263522aSJoseph Koshy int
2811f263522aSJoseph Koshy pmc_disable(int cpu, int pmc)
2812ebccf1e3SJoseph Koshy {
2813f263522aSJoseph Koshy 	struct pmc_op_pmcadmin ssa;
2814ebccf1e3SJoseph Koshy 
2815f263522aSJoseph Koshy 	ssa.pm_cpu = cpu;
2816f263522aSJoseph Koshy 	ssa.pm_pmc = pmc;
2817f263522aSJoseph Koshy 	ssa.pm_state = PMC_STATE_DISABLED;
2818aa342b1fSJoseph Koshy 	return (PMC_CALL(PMCADMIN, &ssa));
2819ebccf1e3SJoseph Koshy }
2820ebccf1e3SJoseph Koshy 
2821f263522aSJoseph Koshy int
2822f263522aSJoseph Koshy pmc_enable(int cpu, int pmc)
2823ebccf1e3SJoseph Koshy {
2824f263522aSJoseph Koshy 	struct pmc_op_pmcadmin ssa;
2825ebccf1e3SJoseph Koshy 
2826f263522aSJoseph Koshy 	ssa.pm_cpu = cpu;
2827f263522aSJoseph Koshy 	ssa.pm_pmc = pmc;
2828f263522aSJoseph Koshy 	ssa.pm_state = PMC_STATE_FREE;
2829aa342b1fSJoseph Koshy 	return (PMC_CALL(PMCADMIN, &ssa));
2830ebccf1e3SJoseph Koshy }
2831ebccf1e3SJoseph Koshy 
2832ebccf1e3SJoseph Koshy /*
2833ebccf1e3SJoseph Koshy  * Return a list of events known to a given PMC class.  'cl' is the
2834ebccf1e3SJoseph Koshy  * PMC class identifier, 'eventnames' is the returned list of 'const
2835ebccf1e3SJoseph Koshy  * char *' pointers pointing to the names of the events. 'nevents' is
2836ebccf1e3SJoseph Koshy  * the number of event name pointers returned.
2837ebccf1e3SJoseph Koshy  *
2838ebccf1e3SJoseph Koshy  * The space for 'eventnames' is allocated using malloc(3).  The caller
2839ebccf1e3SJoseph Koshy  * is responsible for freeing this space when done.
2840ebccf1e3SJoseph Koshy  */
2841ebccf1e3SJoseph Koshy int
2842ebccf1e3SJoseph Koshy pmc_event_names_of_class(enum pmc_class cl, const char ***eventnames,
2843ebccf1e3SJoseph Koshy     int *nevents)
2844ebccf1e3SJoseph Koshy {
2845ebccf1e3SJoseph Koshy 	int count;
2846ebccf1e3SJoseph Koshy 	const char **names;
2847ebccf1e3SJoseph Koshy 	const struct pmc_event_descr *ev;
2848ebccf1e3SJoseph Koshy 
2849ebccf1e3SJoseph Koshy 	switch (cl)
2850ebccf1e3SJoseph Koshy 	{
28510cfab8ddSJoseph Koshy 	case PMC_CLASS_IAF:
28520cfab8ddSJoseph Koshy 		ev = iaf_event_table;
28530cfab8ddSJoseph Koshy 		count = PMC_EVENT_TABLE_SIZE(iaf);
28540cfab8ddSJoseph Koshy 		break;
28550cfab8ddSJoseph Koshy 	case PMC_CLASS_IAP:
28560cfab8ddSJoseph Koshy 		/*
28570cfab8ddSJoseph Koshy 		 * Return the most appropriate set of event name
28580cfab8ddSJoseph Koshy 		 * spellings for the current CPU.
28590cfab8ddSJoseph Koshy 		 */
28600cfab8ddSJoseph Koshy 		switch (cpu_info.pm_cputype) {
28610cfab8ddSJoseph Koshy 		default:
28620cfab8ddSJoseph Koshy 		case PMC_CPU_INTEL_ATOM:
28630cfab8ddSJoseph Koshy 			ev = atom_event_table;
28640cfab8ddSJoseph Koshy 			count = PMC_EVENT_TABLE_SIZE(atom);
28650cfab8ddSJoseph Koshy 			break;
2866e8f021a3SHiren Panchasara 		case PMC_CPU_INTEL_ATOM_SILVERMONT:
2867e8f021a3SHiren Panchasara 			ev = atom_silvermont_event_table;
2868e8f021a3SHiren Panchasara 			count = PMC_EVENT_TABLE_SIZE(atom_silvermont);
2869e8f021a3SHiren Panchasara 			break;
28700cfab8ddSJoseph Koshy 		case PMC_CPU_INTEL_CORE:
28710cfab8ddSJoseph Koshy 			ev = core_event_table;
28720cfab8ddSJoseph Koshy 			count = PMC_EVENT_TABLE_SIZE(core);
28730cfab8ddSJoseph Koshy 			break;
28740cfab8ddSJoseph Koshy 		case PMC_CPU_INTEL_CORE2:
2875b4d091f3SJoseph Koshy 		case PMC_CPU_INTEL_CORE2EXTREME:
28760cfab8ddSJoseph Koshy 			ev = core2_event_table;
28770cfab8ddSJoseph Koshy 			count = PMC_EVENT_TABLE_SIZE(core2);
28780cfab8ddSJoseph Koshy 			break;
2879597979c4SJeff Roberson 		case PMC_CPU_INTEL_COREI7:
2880597979c4SJeff Roberson 			ev = corei7_event_table;
2881597979c4SJeff Roberson 			count = PMC_EVENT_TABLE_SIZE(corei7);
2882597979c4SJeff Roberson 			break;
288349fe48abSKonstantin Belousov 		case PMC_CPU_INTEL_NEHALEM_EX:
288449fe48abSKonstantin Belousov 			ev = nehalem_ex_event_table;
288549fe48abSKonstantin Belousov 			count = PMC_EVENT_TABLE_SIZE(nehalem_ex);
288649fe48abSKonstantin Belousov 			break;
2887cc0c1555SSean Bruno 		case PMC_CPU_INTEL_HASWELL:
2888cc0c1555SSean Bruno 			ev = haswell_event_table;
2889cc0c1555SSean Bruno 			count = PMC_EVENT_TABLE_SIZE(haswell);
2890cc0c1555SSean Bruno 			break;
2891d95b3509SRandall Stewart 		case PMC_CPU_INTEL_HASWELL_XEON:
2892d95b3509SRandall Stewart 			ev = haswell_xeon_event_table;
2893d95b3509SRandall Stewart 			count = PMC_EVENT_TABLE_SIZE(haswell_xeon);
2894d95b3509SRandall Stewart 			break;
28951e862e5aSFabien Thomas 		case PMC_CPU_INTEL_IVYBRIDGE:
28961e862e5aSFabien Thomas 			ev = ivybridge_event_table;
28971e862e5aSFabien Thomas 			count = PMC_EVENT_TABLE_SIZE(ivybridge);
28981e862e5aSFabien Thomas 			break;
28993f929d8cSSean Bruno 		case PMC_CPU_INTEL_IVYBRIDGE_XEON:
29003f929d8cSSean Bruno 			ev = ivybridge_xeon_event_table;
29013f929d8cSSean Bruno 			count = PMC_EVENT_TABLE_SIZE(ivybridge_xeon);
29023f929d8cSSean Bruno 			break;
290378d763a2SDavide Italiano 		case PMC_CPU_INTEL_SANDYBRIDGE:
290478d763a2SDavide Italiano 			ev = sandybridge_event_table;
290578d763a2SDavide Italiano 			count = PMC_EVENT_TABLE_SIZE(sandybridge);
290678d763a2SDavide Italiano 			break;
2907fabe02f5SSean Bruno 		case PMC_CPU_INTEL_SANDYBRIDGE_XEON:
2908fabe02f5SSean Bruno 			ev = sandybridge_xeon_event_table;
2909fabe02f5SSean Bruno 			count = PMC_EVENT_TABLE_SIZE(sandybridge_xeon);
2910fabe02f5SSean Bruno 			break;
29111fa7f10bSFabien Thomas 		case PMC_CPU_INTEL_WESTMERE:
29121fa7f10bSFabien Thomas 			ev = westmere_event_table;
29131fa7f10bSFabien Thomas 			count = PMC_EVENT_TABLE_SIZE(westmere);
29141fa7f10bSFabien Thomas 			break;
291549fe48abSKonstantin Belousov 		case PMC_CPU_INTEL_WESTMERE_EX:
291649fe48abSKonstantin Belousov 			ev = westmere_ex_event_table;
291749fe48abSKonstantin Belousov 			count = PMC_EVENT_TABLE_SIZE(westmere_ex);
291849fe48abSKonstantin Belousov 			break;
29191fa7f10bSFabien Thomas 		}
29201fa7f10bSFabien Thomas 		break;
29211fa7f10bSFabien Thomas 	case PMC_CLASS_UCF:
29221fa7f10bSFabien Thomas 		ev = ucf_event_table;
29231fa7f10bSFabien Thomas 		count = PMC_EVENT_TABLE_SIZE(ucf);
29241fa7f10bSFabien Thomas 		break;
29251fa7f10bSFabien Thomas 	case PMC_CLASS_UCP:
29261fa7f10bSFabien Thomas 		/*
29271fa7f10bSFabien Thomas 		 * Return the most appropriate set of event name
29281fa7f10bSFabien Thomas 		 * spellings for the current CPU.
29291fa7f10bSFabien Thomas 		 */
29301fa7f10bSFabien Thomas 		switch (cpu_info.pm_cputype) {
29311fa7f10bSFabien Thomas 		default:
29321fa7f10bSFabien Thomas 		case PMC_CPU_INTEL_COREI7:
29331fa7f10bSFabien Thomas 			ev = corei7uc_event_table;
29341fa7f10bSFabien Thomas 			count = PMC_EVENT_TABLE_SIZE(corei7uc);
29351fa7f10bSFabien Thomas 			break;
2936cc0c1555SSean Bruno 		case PMC_CPU_INTEL_HASWELL:
2937cc0c1555SSean Bruno 			ev = haswelluc_event_table;
2938cc0c1555SSean Bruno 			count = PMC_EVENT_TABLE_SIZE(haswelluc);
2939cc0c1555SSean Bruno 			break;
294078d763a2SDavide Italiano 		case PMC_CPU_INTEL_SANDYBRIDGE:
294178d763a2SDavide Italiano 			ev = sandybridgeuc_event_table;
294278d763a2SDavide Italiano 			count = PMC_EVENT_TABLE_SIZE(sandybridgeuc);
294378d763a2SDavide Italiano 			break;
29441fa7f10bSFabien Thomas 		case PMC_CPU_INTEL_WESTMERE:
29451fa7f10bSFabien Thomas 			ev = westmereuc_event_table;
29461fa7f10bSFabien Thomas 			count = PMC_EVENT_TABLE_SIZE(westmereuc);
29471fa7f10bSFabien Thomas 			break;
29480cfab8ddSJoseph Koshy 		}
29490cfab8ddSJoseph Koshy 		break;
2950ebccf1e3SJoseph Koshy 	case PMC_CLASS_TSC:
2951789140c0SJoseph Koshy 		ev = tsc_event_table;
2952789140c0SJoseph Koshy 		count = PMC_EVENT_TABLE_SIZE(tsc);
2953ebccf1e3SJoseph Koshy 		break;
2954ebccf1e3SJoseph Koshy 	case PMC_CLASS_K7:
2955789140c0SJoseph Koshy 		ev = k7_event_table;
2956789140c0SJoseph Koshy 		count = PMC_EVENT_TABLE_SIZE(k7);
2957ebccf1e3SJoseph Koshy 		break;
2958ebccf1e3SJoseph Koshy 	case PMC_CLASS_K8:
2959789140c0SJoseph Koshy 		ev = k8_event_table;
2960789140c0SJoseph Koshy 		count = PMC_EVENT_TABLE_SIZE(k8);
2961ebccf1e3SJoseph Koshy 		break;
2962ebccf1e3SJoseph Koshy 	case PMC_CLASS_P4:
2963789140c0SJoseph Koshy 		ev = p4_event_table;
2964789140c0SJoseph Koshy 		count = PMC_EVENT_TABLE_SIZE(p4);
2965789140c0SJoseph Koshy 		break;
2966789140c0SJoseph Koshy 	case PMC_CLASS_P5:
2967789140c0SJoseph Koshy 		ev = p5_event_table;
2968789140c0SJoseph Koshy 		count = PMC_EVENT_TABLE_SIZE(p5);
2969789140c0SJoseph Koshy 		break;
2970789140c0SJoseph Koshy 	case PMC_CLASS_P6:
2971789140c0SJoseph Koshy 		ev = p6_event_table;
2972789140c0SJoseph Koshy 		count = PMC_EVENT_TABLE_SIZE(p6);
2973ebccf1e3SJoseph Koshy 		break;
29740ce207d2SRui Paulo 	case PMC_CLASS_XSCALE:
29750ce207d2SRui Paulo 		ev = xscale_event_table;
29760ce207d2SRui Paulo 		count = PMC_EVENT_TABLE_SIZE(xscale);
29770ce207d2SRui Paulo 		break;
29786411d14dSRuslan Bukin 	case PMC_CLASS_ARMV7:
29796411d14dSRuslan Bukin 		ev = armv7_event_table;
29806411d14dSRuslan Bukin 		count = PMC_EVENT_TABLE_SIZE(armv7);
29816411d14dSRuslan Bukin 		break;
2982*bc88bb2bSRuslan Bukin 	case PMC_CLASS_ARMV8:
2983*bc88bb2bSRuslan Bukin 		switch (cpu_info.pm_cputype) {
2984*bc88bb2bSRuslan Bukin 		default:
2985*bc88bb2bSRuslan Bukin 		case PMC_CPU_ARMV8_CORTEX_A53:
2986*bc88bb2bSRuslan Bukin 			ev = cortex_a53_event_table;
2987*bc88bb2bSRuslan Bukin 			count = PMC_EVENT_TABLE_SIZE(cortex_a53);
2988*bc88bb2bSRuslan Bukin 			break;
2989*bc88bb2bSRuslan Bukin 		case PMC_CPU_ARMV8_CORTEX_A57:
2990*bc88bb2bSRuslan Bukin 			ev = cortex_a57_event_table;
2991*bc88bb2bSRuslan Bukin 			count = PMC_EVENT_TABLE_SIZE(cortex_a57);
2992*bc88bb2bSRuslan Bukin 			break;
2993*bc88bb2bSRuslan Bukin 		}
2994*bc88bb2bSRuslan Bukin 		break;
2995660df75eSGeorge V. Neville-Neil 	case PMC_CLASS_MIPS24K:
2996660df75eSGeorge V. Neville-Neil 		ev = mips24k_event_table;
2997660df75eSGeorge V. Neville-Neil 		count = PMC_EVENT_TABLE_SIZE(mips24k);
2998660df75eSGeorge V. Neville-Neil 		break;
2999f6e6460dSAdrian Chadd 	case PMC_CLASS_MIPS74K:
3000f6e6460dSAdrian Chadd 		ev = mips74k_event_table;
3001f6e6460dSAdrian Chadd 		count = PMC_EVENT_TABLE_SIZE(mips74k);
3002f6e6460dSAdrian Chadd 		break;
3003c2657f80SOleksandr Tymoshenko 	case PMC_CLASS_OCTEON:
3004c2657f80SOleksandr Tymoshenko 		ev = octeon_event_table;
3005c2657f80SOleksandr Tymoshenko 		count = PMC_EVENT_TABLE_SIZE(octeon);
3006c2657f80SOleksandr Tymoshenko 		break;
30077b25dccaSJustin Hibbits 	case PMC_CLASS_PPC7450:
30087b25dccaSJustin Hibbits 		ev = ppc7450_event_table;
30097b25dccaSJustin Hibbits 		count = PMC_EVENT_TABLE_SIZE(ppc7450);
30107b25dccaSJustin Hibbits 		break;
3011169dd953SJustin Hibbits 	case PMC_CLASS_PPC970:
3012169dd953SJustin Hibbits 		ev = ppc970_event_table;
3013169dd953SJustin Hibbits 		count = PMC_EVENT_TABLE_SIZE(ppc970);
3014169dd953SJustin Hibbits 		break;
3015a7452468SJustin Hibbits 	case PMC_CLASS_E500:
3016a7452468SJustin Hibbits 		ev = e500_event_table;
3017a7452468SJustin Hibbits 		count = PMC_EVENT_TABLE_SIZE(e500);
3018a7452468SJustin Hibbits 		break;
3019f5f9340bSFabien Thomas 	case PMC_CLASS_SOFT:
3020f5f9340bSFabien Thomas 		ev = soft_event_table;
3021f5f9340bSFabien Thomas 		count = soft_event_info.pm_nevent;
3022f5f9340bSFabien Thomas 		break;
3023ebccf1e3SJoseph Koshy 	default:
3024ebccf1e3SJoseph Koshy 		errno = EINVAL;
3025aa342b1fSJoseph Koshy 		return (-1);
3026ebccf1e3SJoseph Koshy 	}
3027ebccf1e3SJoseph Koshy 
3028ebccf1e3SJoseph Koshy 	if ((names = malloc(count * sizeof(const char *))) == NULL)
3029aa342b1fSJoseph Koshy 		return (-1);
3030ebccf1e3SJoseph Koshy 
3031ebccf1e3SJoseph Koshy 	*eventnames = names;
3032ebccf1e3SJoseph Koshy 	*nevents = count;
3033ebccf1e3SJoseph Koshy 
3034ebccf1e3SJoseph Koshy 	for (;count--; ev++, names++)
3035ebccf1e3SJoseph Koshy 		*names = ev->pm_ev_name;
3036f5f9340bSFabien Thomas 
3037aa342b1fSJoseph Koshy 	return (0);
3038ebccf1e3SJoseph Koshy }
3039ebccf1e3SJoseph Koshy 
3040f263522aSJoseph Koshy int
3041f263522aSJoseph Koshy pmc_flush_logfile(void)
3042f263522aSJoseph Koshy {
3043aa342b1fSJoseph Koshy 	return (PMC_CALL(FLUSHLOG,0));
3044f263522aSJoseph Koshy }
3045ebccf1e3SJoseph Koshy 
3046ebccf1e3SJoseph Koshy int
3047dceed24aSFabien Thomas pmc_close_logfile(void)
3048dceed24aSFabien Thomas {
3049dceed24aSFabien Thomas 	return (PMC_CALL(CLOSELOG,0));
3050dceed24aSFabien Thomas }
3051dceed24aSFabien Thomas 
3052dceed24aSFabien Thomas int
3053f263522aSJoseph Koshy pmc_get_driver_stats(struct pmc_driverstats *ds)
3054ebccf1e3SJoseph Koshy {
3055f263522aSJoseph Koshy 	struct pmc_op_getdriverstats gms;
3056f263522aSJoseph Koshy 
3057f263522aSJoseph Koshy 	if (PMC_CALL(GETDRIVERSTATS, &gms) < 0)
3058aa342b1fSJoseph Koshy 		return (-1);
3059f263522aSJoseph Koshy 
3060f263522aSJoseph Koshy 	/* copy out fields in the current userland<->library interface */
3061f263522aSJoseph Koshy 	ds->pm_intr_ignored    = gms.pm_intr_ignored;
3062f263522aSJoseph Koshy 	ds->pm_intr_processed  = gms.pm_intr_processed;
3063f263522aSJoseph Koshy 	ds->pm_intr_bufferfull = gms.pm_intr_bufferfull;
3064f263522aSJoseph Koshy 	ds->pm_syscalls        = gms.pm_syscalls;
3065f263522aSJoseph Koshy 	ds->pm_syscall_errors  = gms.pm_syscall_errors;
3066f263522aSJoseph Koshy 	ds->pm_buffer_requests = gms.pm_buffer_requests;
3067f263522aSJoseph Koshy 	ds->pm_buffer_requests_failed = gms.pm_buffer_requests_failed;
3068f263522aSJoseph Koshy 	ds->pm_log_sweeps      = gms.pm_log_sweeps;
3069aa342b1fSJoseph Koshy 	return (0);
3070f263522aSJoseph Koshy }
3071f263522aSJoseph Koshy 
3072f263522aSJoseph Koshy int
3073f263522aSJoseph Koshy pmc_get_msr(pmc_id_t pmc, uint32_t *msr)
3074f263522aSJoseph Koshy {
3075f263522aSJoseph Koshy 	struct pmc_op_getmsr gm;
3076ebccf1e3SJoseph Koshy 
3077ebccf1e3SJoseph Koshy 	gm.pm_pmcid = pmc;
3078f263522aSJoseph Koshy 	if (PMC_CALL(PMCGETMSR, &gm) < 0)
3079aa342b1fSJoseph Koshy 		return (-1);
3080ebccf1e3SJoseph Koshy 	*msr = gm.pm_msr;
3081aa342b1fSJoseph Koshy 	return (0);
3082ebccf1e3SJoseph Koshy }
3083ebccf1e3SJoseph Koshy 
3084f263522aSJoseph Koshy int
3085f263522aSJoseph Koshy pmc_init(void)
3086f263522aSJoseph Koshy {
3087f263522aSJoseph Koshy 	int error, pmc_mod_id;
30881455fcd3SJoseph Koshy 	unsigned int n;
3089f263522aSJoseph Koshy 	uint32_t abi_version;
3090f263522aSJoseph Koshy 	struct module_stat pmc_modstat;
30911455fcd3SJoseph Koshy 	struct pmc_op_getcpuinfo op_cpu_info;
3092791f5d5bSJoseph Koshy #if defined(__amd64__) || defined(__i386__)
3093791f5d5bSJoseph Koshy 	int cpu_has_iaf_counters;
3094791f5d5bSJoseph Koshy 	unsigned int t;
3095791f5d5bSJoseph Koshy #endif
3096f263522aSJoseph Koshy 
3097f263522aSJoseph Koshy 	if (pmc_syscall != -1) /* already inited */
3098aa342b1fSJoseph Koshy 		return (0);
3099f263522aSJoseph Koshy 
3100f263522aSJoseph Koshy 	/* retrieve the system call number from the KLD */
3101f263522aSJoseph Koshy 	if ((pmc_mod_id = modfind(PMC_MODULE_NAME)) < 0)
3102aa342b1fSJoseph Koshy 		return (-1);
3103f263522aSJoseph Koshy 
3104f263522aSJoseph Koshy 	pmc_modstat.version = sizeof(struct module_stat);
3105f263522aSJoseph Koshy 	if ((error = modstat(pmc_mod_id, &pmc_modstat)) < 0)
3106aa342b1fSJoseph Koshy 		return (-1);
3107f263522aSJoseph Koshy 
3108f263522aSJoseph Koshy 	pmc_syscall = pmc_modstat.data.intval;
3109f263522aSJoseph Koshy 
3110f263522aSJoseph Koshy 	/* check the kernel module's ABI against our compiled-in version */
3111f263522aSJoseph Koshy 	abi_version = PMC_VERSION;
3112f263522aSJoseph Koshy 	if (PMC_CALL(GETMODULEVERSION, &abi_version) < 0)
3113f263522aSJoseph Koshy 		return (pmc_syscall = -1);
3114f263522aSJoseph Koshy 
3115f263522aSJoseph Koshy 	/* ignore patch & minor numbers for the comparision */
3116f263522aSJoseph Koshy 	if ((abi_version & 0xFF000000) != (PMC_VERSION & 0xFF000000)) {
3117f263522aSJoseph Koshy 		errno  = EPROGMISMATCH;
3118f263522aSJoseph Koshy 		return (pmc_syscall = -1);
3119f263522aSJoseph Koshy 	}
3120f263522aSJoseph Koshy 
31211455fcd3SJoseph Koshy 	if (PMC_CALL(GETCPUINFO, &op_cpu_info) < 0)
3122f263522aSJoseph Koshy 		return (pmc_syscall = -1);
3123f263522aSJoseph Koshy 
31241455fcd3SJoseph Koshy 	cpu_info.pm_cputype = op_cpu_info.pm_cputype;
31251455fcd3SJoseph Koshy 	cpu_info.pm_ncpu    = op_cpu_info.pm_ncpu;
31261455fcd3SJoseph Koshy 	cpu_info.pm_npmc    = op_cpu_info.pm_npmc;
31271455fcd3SJoseph Koshy 	cpu_info.pm_nclass  = op_cpu_info.pm_nclass;
31281455fcd3SJoseph Koshy 	for (n = 0; n < cpu_info.pm_nclass; n++)
31291455fcd3SJoseph Koshy 		cpu_info.pm_classes[n] = op_cpu_info.pm_classes[n];
31301455fcd3SJoseph Koshy 
31310cfab8ddSJoseph Koshy 	pmc_class_table = malloc(PMC_CLASS_TABLE_SIZE *
31320cfab8ddSJoseph Koshy 	    sizeof(struct pmc_class_descr *));
31330cfab8ddSJoseph Koshy 
31340cfab8ddSJoseph Koshy 	if (pmc_class_table == NULL)
31350cfab8ddSJoseph Koshy 		return (-1);
31360cfab8ddSJoseph Koshy 
3137791f5d5bSJoseph Koshy 	for (n = 0; n < PMC_CLASS_TABLE_SIZE; n++)
3138791f5d5bSJoseph Koshy 		pmc_class_table[n] = NULL;
31390cfab8ddSJoseph Koshy 
31400cfab8ddSJoseph Koshy 	/*
3141f5f9340bSFabien Thomas 	 * Get soft events list.
3142f5f9340bSFabien Thomas 	 */
3143f5f9340bSFabien Thomas 	soft_event_info.pm_class = PMC_CLASS_SOFT;
3144f5f9340bSFabien Thomas 	if (PMC_CALL(GETDYNEVENTINFO, &soft_event_info) < 0)
3145f5f9340bSFabien Thomas 		return (pmc_syscall = -1);
3146f5f9340bSFabien Thomas 
3147f5f9340bSFabien Thomas 	/* Map soft events to static list. */
3148f5f9340bSFabien Thomas 	for (n = 0; n < soft_event_info.pm_nevent; n++) {
3149f5f9340bSFabien Thomas 		soft_event_table[n].pm_ev_name =
3150f5f9340bSFabien Thomas 		    soft_event_info.pm_events[n].pm_ev_name;
3151f5f9340bSFabien Thomas 		soft_event_table[n].pm_ev_code =
3152f5f9340bSFabien Thomas 		    soft_event_info.pm_events[n].pm_ev_code;
3153f5f9340bSFabien Thomas 	}
3154f5f9340bSFabien Thomas 	soft_class_table_descr.pm_evc_event_table_size = \
3155f5f9340bSFabien Thomas 	    soft_event_info.pm_nevent;
3156f5f9340bSFabien Thomas 	soft_class_table_descr.pm_evc_event_table = \
3157f5f9340bSFabien Thomas 	    soft_event_table;
3158f5f9340bSFabien Thomas 
3159f5f9340bSFabien Thomas 	/*
31600cfab8ddSJoseph Koshy 	 * Fill in the class table.
31610cfab8ddSJoseph Koshy 	 */
31620cfab8ddSJoseph Koshy 	n = 0;
3163f5f9340bSFabien Thomas 
3164f5f9340bSFabien Thomas 	/* Fill soft events information. */
3165f5f9340bSFabien Thomas 	pmc_class_table[n++] = &soft_class_table_descr;
31660cfab8ddSJoseph Koshy #if defined(__amd64__) || defined(__i386__)
3167f5f9340bSFabien Thomas 	if (cpu_info.pm_cputype != PMC_CPU_GENERIC)
31680cfab8ddSJoseph Koshy 		pmc_class_table[n++] = &tsc_class_table_descr;
3169791f5d5bSJoseph Koshy 
3170791f5d5bSJoseph Koshy 	/*
3171791f5d5bSJoseph Koshy  	 * Check if this CPU has fixed function counters.
3172791f5d5bSJoseph Koshy 	 */
3173791f5d5bSJoseph Koshy 	cpu_has_iaf_counters = 0;
3174791f5d5bSJoseph Koshy 	for (t = 0; t < cpu_info.pm_nclass; t++)
31752aef9dd6SFabien Thomas 		if (cpu_info.pm_classes[t].pm_class == PMC_CLASS_IAF &&
31762aef9dd6SFabien Thomas 		    cpu_info.pm_classes[t].pm_num > 0)
3177791f5d5bSJoseph Koshy 			cpu_has_iaf_counters = 1;
31780cfab8ddSJoseph Koshy #endif
31790cfab8ddSJoseph Koshy 
3180789140c0SJoseph Koshy #define	PMC_MDEP_INIT(C) do {					\
3181789140c0SJoseph Koshy 		pmc_mdep_event_aliases    = C##_aliases;	\
3182789140c0SJoseph Koshy 		pmc_mdep_class_list  = C##_pmc_classes;		\
3183789140c0SJoseph Koshy 		pmc_mdep_class_list_size =			\
3184789140c0SJoseph Koshy 		    PMC_TABLE_SIZE(C##_pmc_classes);		\
3185789140c0SJoseph Koshy 	} while (0)
3186789140c0SJoseph Koshy 
3187791f5d5bSJoseph Koshy #define	PMC_MDEP_INIT_INTEL_V2(C) do {					\
3188791f5d5bSJoseph Koshy 		PMC_MDEP_INIT(C);					\
3189791f5d5bSJoseph Koshy 		pmc_class_table[n++] = &iaf_class_table_descr;		\
31902aef9dd6SFabien Thomas 		if (!cpu_has_iaf_counters) 				\
3191791f5d5bSJoseph Koshy 			pmc_mdep_event_aliases =			\
3192791f5d5bSJoseph Koshy 				C##_aliases_without_iaf;		\
3193791f5d5bSJoseph Koshy 		pmc_class_table[n] = &C##_class_table_descr;		\
3194791f5d5bSJoseph Koshy 	} while (0)
3195791f5d5bSJoseph Koshy 
3196789140c0SJoseph Koshy 	/* Configure the event name parser. */
3197f263522aSJoseph Koshy 	switch (cpu_info.pm_cputype) {
3198f263522aSJoseph Koshy #if defined(__i386__)
3199f263522aSJoseph Koshy 	case PMC_CPU_AMD_K7:
3200789140c0SJoseph Koshy 		PMC_MDEP_INIT(k7);
32010cfab8ddSJoseph Koshy 		pmc_class_table[n] = &k7_class_table_descr;
3202f263522aSJoseph Koshy 		break;
3203f263522aSJoseph Koshy 	case PMC_CPU_INTEL_P5:
3204789140c0SJoseph Koshy 		PMC_MDEP_INIT(p5);
32050cfab8ddSJoseph Koshy 		pmc_class_table[n]  = &p5_class_table_descr;
3206f263522aSJoseph Koshy 		break;
3207f263522aSJoseph Koshy 	case PMC_CPU_INTEL_P6:		/* P6 ... Pentium M CPUs have */
3208f263522aSJoseph Koshy 	case PMC_CPU_INTEL_PII:		/* similar PMCs. */
3209f263522aSJoseph Koshy 	case PMC_CPU_INTEL_PIII:
3210f263522aSJoseph Koshy 	case PMC_CPU_INTEL_PM:
3211789140c0SJoseph Koshy 		PMC_MDEP_INIT(p6);
32120cfab8ddSJoseph Koshy 		pmc_class_table[n] = &p6_class_table_descr;
3213f263522aSJoseph Koshy 		break;
321486a65549SJoseph Koshy #endif
321586a65549SJoseph Koshy #if defined(__amd64__) || defined(__i386__)
3216f263522aSJoseph Koshy 	case PMC_CPU_AMD_K8:
3217789140c0SJoseph Koshy 		PMC_MDEP_INIT(k8);
32180cfab8ddSJoseph Koshy 		pmc_class_table[n] = &k8_class_table_descr;
32190cfab8ddSJoseph Koshy 		break;
32200cfab8ddSJoseph Koshy 	case PMC_CPU_INTEL_ATOM:
3221791f5d5bSJoseph Koshy 		PMC_MDEP_INIT_INTEL_V2(atom);
32220cfab8ddSJoseph Koshy 		break;
3223e8f021a3SHiren Panchasara 	case PMC_CPU_INTEL_ATOM_SILVERMONT:
3224e8f021a3SHiren Panchasara 		PMC_MDEP_INIT_INTEL_V2(atom_silvermont);
3225e8f021a3SHiren Panchasara 		break;
32260cfab8ddSJoseph Koshy 	case PMC_CPU_INTEL_CORE:
32270cfab8ddSJoseph Koshy 		PMC_MDEP_INIT(core);
3228bc315bbdSJoseph Koshy 		pmc_class_table[n] = &core_class_table_descr;
32290cfab8ddSJoseph Koshy 		break;
32300cfab8ddSJoseph Koshy 	case PMC_CPU_INTEL_CORE2:
3231b4d091f3SJoseph Koshy 	case PMC_CPU_INTEL_CORE2EXTREME:
3232791f5d5bSJoseph Koshy 		PMC_MDEP_INIT_INTEL_V2(core2);
3233789140c0SJoseph Koshy 		break;
3234597979c4SJeff Roberson 	case PMC_CPU_INTEL_COREI7:
32351fa7f10bSFabien Thomas 		pmc_class_table[n++] = &ucf_class_table_descr;
32361fa7f10bSFabien Thomas 		pmc_class_table[n++] = &corei7uc_class_table_descr;
3237791f5d5bSJoseph Koshy 		PMC_MDEP_INIT_INTEL_V2(corei7);
3238597979c4SJeff Roberson 		break;
323949fe48abSKonstantin Belousov 	case PMC_CPU_INTEL_NEHALEM_EX:
324049fe48abSKonstantin Belousov 		PMC_MDEP_INIT_INTEL_V2(nehalem_ex);
324149fe48abSKonstantin Belousov 		break;
3242cc0c1555SSean Bruno 	case PMC_CPU_INTEL_HASWELL:
3243cc0c1555SSean Bruno 		pmc_class_table[n++] = &ucf_class_table_descr;
3244cc0c1555SSean Bruno 		pmc_class_table[n++] = &haswelluc_class_table_descr;
3245cc0c1555SSean Bruno 		PMC_MDEP_INIT_INTEL_V2(haswell);
3246cc0c1555SSean Bruno 		break;
3247d95b3509SRandall Stewart 	case PMC_CPU_INTEL_HASWELL_XEON:
3248d95b3509SRandall Stewart 		PMC_MDEP_INIT_INTEL_V2(haswell_xeon);
3249d95b3509SRandall Stewart 		break;
32501e862e5aSFabien Thomas 	case PMC_CPU_INTEL_IVYBRIDGE:
32511e862e5aSFabien Thomas 		PMC_MDEP_INIT_INTEL_V2(ivybridge);
32521e862e5aSFabien Thomas 		break;
32533f929d8cSSean Bruno 	case PMC_CPU_INTEL_IVYBRIDGE_XEON:
32543f929d8cSSean Bruno 		PMC_MDEP_INIT_INTEL_V2(ivybridge_xeon);
32553f929d8cSSean Bruno 		break;
325678d763a2SDavide Italiano 	case PMC_CPU_INTEL_SANDYBRIDGE:
325778d763a2SDavide Italiano 		pmc_class_table[n++] = &ucf_class_table_descr;
325878d763a2SDavide Italiano 		pmc_class_table[n++] = &sandybridgeuc_class_table_descr;
325978d763a2SDavide Italiano 		PMC_MDEP_INIT_INTEL_V2(sandybridge);
326078d763a2SDavide Italiano 		break;
3261fabe02f5SSean Bruno 	case PMC_CPU_INTEL_SANDYBRIDGE_XEON:
3262fabe02f5SSean Bruno 		PMC_MDEP_INIT_INTEL_V2(sandybridge_xeon);
3263fabe02f5SSean Bruno 		break;
32641fa7f10bSFabien Thomas 	case PMC_CPU_INTEL_WESTMERE:
32651fa7f10bSFabien Thomas 		pmc_class_table[n++] = &ucf_class_table_descr;
32661fa7f10bSFabien Thomas 		pmc_class_table[n++] = &westmereuc_class_table_descr;
32671fa7f10bSFabien Thomas 		PMC_MDEP_INIT_INTEL_V2(westmere);
32681fa7f10bSFabien Thomas 		break;
326949fe48abSKonstantin Belousov 	case PMC_CPU_INTEL_WESTMERE_EX:
327049fe48abSKonstantin Belousov 		PMC_MDEP_INIT_INTEL_V2(westmere_ex);
327149fe48abSKonstantin Belousov 		break;
3272789140c0SJoseph Koshy 	case PMC_CPU_INTEL_PIV:
3273789140c0SJoseph Koshy 		PMC_MDEP_INIT(p4);
32740cfab8ddSJoseph Koshy 		pmc_class_table[n] = &p4_class_table_descr;
3275f263522aSJoseph Koshy 		break;
3276ebccf1e3SJoseph Koshy #endif
3277f5f9340bSFabien Thomas 	case PMC_CPU_GENERIC:
3278f5f9340bSFabien Thomas 		PMC_MDEP_INIT(generic);
3279f5f9340bSFabien Thomas 		break;
32806411d14dSRuslan Bukin #if defined(__arm__)
32810ce207d2SRui Paulo #if defined(__XSCALE__)
32820ce207d2SRui Paulo 	case PMC_CPU_INTEL_XSCALE:
32830ce207d2SRui Paulo 		PMC_MDEP_INIT(xscale);
32840ce207d2SRui Paulo 		pmc_class_table[n] = &xscale_class_table_descr;
32850ce207d2SRui Paulo 		break;
32860ce207d2SRui Paulo #endif
32876411d14dSRuslan Bukin 	case PMC_CPU_ARMV7:
32886411d14dSRuslan Bukin 		PMC_MDEP_INIT(armv7);
32896411d14dSRuslan Bukin 		pmc_class_table[n] = &armv7_class_table_descr;
32906411d14dSRuslan Bukin 		break;
32916411d14dSRuslan Bukin #endif
3292*bc88bb2bSRuslan Bukin #if defined(__aarch64__)
3293*bc88bb2bSRuslan Bukin 	case PMC_CPU_ARMV8_CORTEX_A53:
3294*bc88bb2bSRuslan Bukin 		PMC_MDEP_INIT(cortex_a53);
3295*bc88bb2bSRuslan Bukin 		pmc_class_table[n] = &cortex_a53_class_table_descr;
3296*bc88bb2bSRuslan Bukin 		break;
3297*bc88bb2bSRuslan Bukin 	case PMC_CPU_ARMV8_CORTEX_A57:
3298*bc88bb2bSRuslan Bukin 		PMC_MDEP_INIT(cortex_a57);
3299*bc88bb2bSRuslan Bukin 		pmc_class_table[n] = &cortex_a57_class_table_descr;
3300*bc88bb2bSRuslan Bukin 		break;
3301*bc88bb2bSRuslan Bukin #endif
3302660df75eSGeorge V. Neville-Neil #if defined(__mips__)
3303660df75eSGeorge V. Neville-Neil 	case PMC_CPU_MIPS_24K:
3304660df75eSGeorge V. Neville-Neil 		PMC_MDEP_INIT(mips24k);
3305660df75eSGeorge V. Neville-Neil 		pmc_class_table[n] = &mips24k_class_table_descr;
3306660df75eSGeorge V. Neville-Neil 		break;
3307f6e6460dSAdrian Chadd 	case PMC_CPU_MIPS_74K:
3308f6e6460dSAdrian Chadd 		PMC_MDEP_INIT(mips74k);
3309f6e6460dSAdrian Chadd 		pmc_class_table[n] = &mips74k_class_table_descr;
3310f6e6460dSAdrian Chadd 		break;
3311c2657f80SOleksandr Tymoshenko 	case PMC_CPU_MIPS_OCTEON:
3312c2657f80SOleksandr Tymoshenko 		PMC_MDEP_INIT(octeon);
3313c2657f80SOleksandr Tymoshenko 		pmc_class_table[n] = &octeon_class_table_descr;
3314c2657f80SOleksandr Tymoshenko 		break;
3315660df75eSGeorge V. Neville-Neil #endif /* __mips__ */
33167b25dccaSJustin Hibbits #if defined(__powerpc__)
33177b25dccaSJustin Hibbits 	case PMC_CPU_PPC_7450:
33187b25dccaSJustin Hibbits 		PMC_MDEP_INIT(ppc7450);
33197b25dccaSJustin Hibbits 		pmc_class_table[n] = &ppc7450_class_table_descr;
33207b25dccaSJustin Hibbits 		break;
3321169dd953SJustin Hibbits 	case PMC_CPU_PPC_970:
3322169dd953SJustin Hibbits 		PMC_MDEP_INIT(ppc970);
3323169dd953SJustin Hibbits 		pmc_class_table[n] = &ppc970_class_table_descr;
3324169dd953SJustin Hibbits 		break;
3325a7452468SJustin Hibbits 	case PMC_CPU_PPC_E500:
3326a7452468SJustin Hibbits 		PMC_MDEP_INIT(e500);
3327a7452468SJustin Hibbits 		pmc_class_table[n] = &e500_class_table_descr;
3328a7452468SJustin Hibbits 		break;
33297b25dccaSJustin Hibbits #endif
3330f263522aSJoseph Koshy 	default:
3331f263522aSJoseph Koshy 		/*
3332f263522aSJoseph Koshy 		 * Some kind of CPU this version of the library knows nothing
3333f263522aSJoseph Koshy 		 * about.  This shouldn't happen since the abi version check
3334f263522aSJoseph Koshy 		 * should have caught this.
3335f263522aSJoseph Koshy 		 */
3336f263522aSJoseph Koshy 		errno = ENXIO;
3337f263522aSJoseph Koshy 		return (pmc_syscall = -1);
3338f263522aSJoseph Koshy 	}
3339f263522aSJoseph Koshy 
3340aa342b1fSJoseph Koshy 	return (0);
3341f263522aSJoseph Koshy }
3342f263522aSJoseph Koshy 
3343f263522aSJoseph Koshy const char *
3344f263522aSJoseph Koshy pmc_name_of_capability(enum pmc_caps cap)
3345f263522aSJoseph Koshy {
3346f263522aSJoseph Koshy 	int i;
3347f263522aSJoseph Koshy 
3348f263522aSJoseph Koshy 	/*
3349f263522aSJoseph Koshy 	 * 'cap' should have a single bit set and should be in
3350f263522aSJoseph Koshy 	 * range.
3351f263522aSJoseph Koshy 	 */
3352f263522aSJoseph Koshy 	if ((cap & (cap - 1)) || cap < PMC_CAP_FIRST ||
3353f263522aSJoseph Koshy 	    cap > PMC_CAP_LAST) {
3354f263522aSJoseph Koshy 		errno = EINVAL;
3355aa342b1fSJoseph Koshy 		return (NULL);
3356f263522aSJoseph Koshy 	}
3357f263522aSJoseph Koshy 
3358f263522aSJoseph Koshy 	i = ffs(cap);
3359aa342b1fSJoseph Koshy 	return (pmc_capability_names[i - 1]);
3360f263522aSJoseph Koshy }
3361f263522aSJoseph Koshy 
3362f263522aSJoseph Koshy const char *
3363f263522aSJoseph Koshy pmc_name_of_class(enum pmc_class pc)
3364f263522aSJoseph Koshy {
3365f263522aSJoseph Koshy 	if ((int) pc >= PMC_CLASS_FIRST &&
3366f263522aSJoseph Koshy 	    pc <= PMC_CLASS_LAST)
3367aa342b1fSJoseph Koshy 		return (pmc_class_names[pc]);
3368f263522aSJoseph Koshy 
3369f263522aSJoseph Koshy 	errno = EINVAL;
3370aa342b1fSJoseph Koshy 	return (NULL);
3371f263522aSJoseph Koshy }
3372f263522aSJoseph Koshy 
3373f263522aSJoseph Koshy const char *
3374f263522aSJoseph Koshy pmc_name_of_cputype(enum pmc_cputype cp)
3375f263522aSJoseph Koshy {
3376789140c0SJoseph Koshy 	size_t n;
3377789140c0SJoseph Koshy 
3378789140c0SJoseph Koshy 	for (n = 0; n < PMC_TABLE_SIZE(pmc_cputype_names); n++)
3379789140c0SJoseph Koshy 		if (cp == pmc_cputype_names[n].pm_cputype)
3380789140c0SJoseph Koshy 			return (pmc_cputype_names[n].pm_name);
3381789140c0SJoseph Koshy 
3382f263522aSJoseph Koshy 	errno = EINVAL;
3383aa342b1fSJoseph Koshy 	return (NULL);
3384f263522aSJoseph Koshy }
3385f263522aSJoseph Koshy 
3386f263522aSJoseph Koshy const char *
3387f263522aSJoseph Koshy pmc_name_of_disposition(enum pmc_disp pd)
3388f263522aSJoseph Koshy {
3389f263522aSJoseph Koshy 	if ((int) pd >= PMC_DISP_FIRST &&
3390f263522aSJoseph Koshy 	    pd <= PMC_DISP_LAST)
3391aa342b1fSJoseph Koshy 		return (pmc_disposition_names[pd]);
3392f263522aSJoseph Koshy 
3393f263522aSJoseph Koshy 	errno = EINVAL;
3394aa342b1fSJoseph Koshy 	return (NULL);
3395f263522aSJoseph Koshy }
3396f263522aSJoseph Koshy 
3397f263522aSJoseph Koshy const char *
33980cfab8ddSJoseph Koshy _pmc_name_of_event(enum pmc_event pe, enum pmc_cputype cpu)
3399f263522aSJoseph Koshy {
3400789140c0SJoseph Koshy 	const struct pmc_event_descr *ev, *evfence;
3401789140c0SJoseph Koshy 
3402789140c0SJoseph Koshy 	ev = evfence = NULL;
34030cfab8ddSJoseph Koshy 	if (pe >= PMC_EV_IAF_FIRST && pe <= PMC_EV_IAF_LAST) {
34040cfab8ddSJoseph Koshy 		ev = iaf_event_table;
34050cfab8ddSJoseph Koshy 		evfence = iaf_event_table + PMC_EVENT_TABLE_SIZE(iaf);
34060cfab8ddSJoseph Koshy 	} else if (pe >= PMC_EV_IAP_FIRST && pe <= PMC_EV_IAP_LAST) {
34070cfab8ddSJoseph Koshy 		switch (cpu) {
34080cfab8ddSJoseph Koshy 		case PMC_CPU_INTEL_ATOM:
34090cfab8ddSJoseph Koshy 			ev = atom_event_table;
34100cfab8ddSJoseph Koshy 			evfence = atom_event_table + PMC_EVENT_TABLE_SIZE(atom);
34110cfab8ddSJoseph Koshy 			break;
3412e8f021a3SHiren Panchasara 		case PMC_CPU_INTEL_ATOM_SILVERMONT:
3413e8f021a3SHiren Panchasara 			ev = atom_silvermont_event_table;
3414e8f021a3SHiren Panchasara 			evfence = atom_silvermont_event_table +
3415e8f021a3SHiren Panchasara 			    PMC_EVENT_TABLE_SIZE(atom_silvermont);
3416e8f021a3SHiren Panchasara 			break;
34170cfab8ddSJoseph Koshy 		case PMC_CPU_INTEL_CORE:
34180cfab8ddSJoseph Koshy 			ev = core_event_table;
34190cfab8ddSJoseph Koshy 			evfence = core_event_table + PMC_EVENT_TABLE_SIZE(core);
34200cfab8ddSJoseph Koshy 			break;
34210cfab8ddSJoseph Koshy 		case PMC_CPU_INTEL_CORE2:
3422b4d091f3SJoseph Koshy 		case PMC_CPU_INTEL_CORE2EXTREME:
34230cfab8ddSJoseph Koshy 			ev = core2_event_table;
34240cfab8ddSJoseph Koshy 			evfence = core2_event_table + PMC_EVENT_TABLE_SIZE(core2);
34250cfab8ddSJoseph Koshy 			break;
3426597979c4SJeff Roberson 		case PMC_CPU_INTEL_COREI7:
3427597979c4SJeff Roberson 			ev = corei7_event_table;
3428597979c4SJeff Roberson 			evfence = corei7_event_table + PMC_EVENT_TABLE_SIZE(corei7);
3429597979c4SJeff Roberson 			break;
343049fe48abSKonstantin Belousov 		case PMC_CPU_INTEL_NEHALEM_EX:
343149fe48abSKonstantin Belousov 			ev = nehalem_ex_event_table;
343249fe48abSKonstantin Belousov 			evfence = nehalem_ex_event_table +
343349fe48abSKonstantin Belousov 			    PMC_EVENT_TABLE_SIZE(nehalem_ex);
343449fe48abSKonstantin Belousov 			break;
3435cc0c1555SSean Bruno 		case PMC_CPU_INTEL_HASWELL:
3436cc0c1555SSean Bruno 			ev = haswell_event_table;
3437cc0c1555SSean Bruno 			evfence = haswell_event_table + PMC_EVENT_TABLE_SIZE(haswell);
3438cc0c1555SSean Bruno 			break;
3439d95b3509SRandall Stewart 		case PMC_CPU_INTEL_HASWELL_XEON:
3440d95b3509SRandall Stewart 			ev = haswell_xeon_event_table;
3441d95b3509SRandall Stewart 			evfence = haswell_xeon_event_table + PMC_EVENT_TABLE_SIZE(haswell_xeon);
3442d95b3509SRandall Stewart 			break;
3443d95b3509SRandall Stewart 
34441e862e5aSFabien Thomas 		case PMC_CPU_INTEL_IVYBRIDGE:
34451e862e5aSFabien Thomas 			ev = ivybridge_event_table;
34461e862e5aSFabien Thomas 			evfence = ivybridge_event_table + PMC_EVENT_TABLE_SIZE(ivybridge);
34471e862e5aSFabien Thomas 			break;
34483f929d8cSSean Bruno 		case PMC_CPU_INTEL_IVYBRIDGE_XEON:
34493f929d8cSSean Bruno 			ev = ivybridge_xeon_event_table;
34503f929d8cSSean Bruno 			evfence = ivybridge_xeon_event_table + PMC_EVENT_TABLE_SIZE(ivybridge_xeon);
34513f929d8cSSean Bruno 			break;
345278d763a2SDavide Italiano 		case PMC_CPU_INTEL_SANDYBRIDGE:
345378d763a2SDavide Italiano 			ev = sandybridge_event_table;
345478d763a2SDavide Italiano 			evfence = sandybridge_event_table + PMC_EVENT_TABLE_SIZE(sandybridge);
345578d763a2SDavide Italiano 			break;
3456fabe02f5SSean Bruno 		case PMC_CPU_INTEL_SANDYBRIDGE_XEON:
3457fabe02f5SSean Bruno 			ev = sandybridge_xeon_event_table;
3458fabe02f5SSean Bruno 			evfence = sandybridge_xeon_event_table + PMC_EVENT_TABLE_SIZE(sandybridge_xeon);
3459fabe02f5SSean Bruno 			break;
34601fa7f10bSFabien Thomas 		case PMC_CPU_INTEL_WESTMERE:
34611fa7f10bSFabien Thomas 			ev = westmere_event_table;
34621fa7f10bSFabien Thomas 			evfence = westmere_event_table + PMC_EVENT_TABLE_SIZE(westmere);
34631fa7f10bSFabien Thomas 			break;
346449fe48abSKonstantin Belousov 		case PMC_CPU_INTEL_WESTMERE_EX:
346549fe48abSKonstantin Belousov 			ev = westmere_ex_event_table;
346649fe48abSKonstantin Belousov 			evfence = westmere_ex_event_table +
346749fe48abSKonstantin Belousov 			    PMC_EVENT_TABLE_SIZE(westmere_ex);
346849fe48abSKonstantin Belousov 			break;
34690cfab8ddSJoseph Koshy 		default:	/* Unknown CPU type. */
34700cfab8ddSJoseph Koshy 			break;
34710cfab8ddSJoseph Koshy 		}
34721fa7f10bSFabien Thomas 	} else if (pe >= PMC_EV_UCF_FIRST && pe <= PMC_EV_UCF_LAST) {
34731fa7f10bSFabien Thomas 		ev = ucf_event_table;
34741fa7f10bSFabien Thomas 		evfence = ucf_event_table + PMC_EVENT_TABLE_SIZE(ucf);
34751fa7f10bSFabien Thomas 	} else if (pe >= PMC_EV_UCP_FIRST && pe <= PMC_EV_UCP_LAST) {
34761fa7f10bSFabien Thomas 		switch (cpu) {
34771fa7f10bSFabien Thomas 		case PMC_CPU_INTEL_COREI7:
34781fa7f10bSFabien Thomas 			ev = corei7uc_event_table;
34791fa7f10bSFabien Thomas 			evfence = corei7uc_event_table + PMC_EVENT_TABLE_SIZE(corei7uc);
34801fa7f10bSFabien Thomas 			break;
348178d763a2SDavide Italiano 		case PMC_CPU_INTEL_SANDYBRIDGE:
348278d763a2SDavide Italiano 			ev = sandybridgeuc_event_table;
348378d763a2SDavide Italiano 			evfence = sandybridgeuc_event_table + PMC_EVENT_TABLE_SIZE(sandybridgeuc);
348478d763a2SDavide Italiano 			break;
34851fa7f10bSFabien Thomas 		case PMC_CPU_INTEL_WESTMERE:
34861fa7f10bSFabien Thomas 			ev = westmereuc_event_table;
34871fa7f10bSFabien Thomas 			evfence = westmereuc_event_table + PMC_EVENT_TABLE_SIZE(westmereuc);
34881fa7f10bSFabien Thomas 			break;
34891fa7f10bSFabien Thomas 		default:	/* Unknown CPU type. */
34901fa7f10bSFabien Thomas 			break;
34911fa7f10bSFabien Thomas 		}
34921fa7f10bSFabien Thomas 	} else if (pe >= PMC_EV_K7_FIRST && pe <= PMC_EV_K7_LAST) {
3493789140c0SJoseph Koshy 		ev = k7_event_table;
3494789140c0SJoseph Koshy 		evfence = k7_event_table + PMC_EVENT_TABLE_SIZE(k7);
3495789140c0SJoseph Koshy 	} else if (pe >= PMC_EV_K8_FIRST && pe <= PMC_EV_K8_LAST) {
3496789140c0SJoseph Koshy 		ev = k8_event_table;
3497789140c0SJoseph Koshy 		evfence = k8_event_table + PMC_EVENT_TABLE_SIZE(k8);
3498789140c0SJoseph Koshy 	} else if (pe >= PMC_EV_P4_FIRST && pe <= PMC_EV_P4_LAST) {
3499789140c0SJoseph Koshy 		ev = p4_event_table;
3500789140c0SJoseph Koshy 		evfence = p4_event_table + PMC_EVENT_TABLE_SIZE(p4);
3501789140c0SJoseph Koshy 	} else if (pe >= PMC_EV_P5_FIRST && pe <= PMC_EV_P5_LAST) {
3502789140c0SJoseph Koshy 		ev = p5_event_table;
3503789140c0SJoseph Koshy 		evfence = p5_event_table + PMC_EVENT_TABLE_SIZE(p5);
3504789140c0SJoseph Koshy 	} else if (pe >= PMC_EV_P6_FIRST && pe <= PMC_EV_P6_LAST) {
3505789140c0SJoseph Koshy 		ev = p6_event_table;
3506789140c0SJoseph Koshy 		evfence = p6_event_table + PMC_EVENT_TABLE_SIZE(p6);
35070ce207d2SRui Paulo 	} else if (pe >= PMC_EV_XSCALE_FIRST && pe <= PMC_EV_XSCALE_LAST) {
35080ce207d2SRui Paulo 		ev = xscale_event_table;
35090ce207d2SRui Paulo 		evfence = xscale_event_table + PMC_EVENT_TABLE_SIZE(xscale);
35106411d14dSRuslan Bukin 	} else if (pe >= PMC_EV_ARMV7_FIRST && pe <= PMC_EV_ARMV7_LAST) {
35116411d14dSRuslan Bukin 		ev = armv7_event_table;
35126411d14dSRuslan Bukin 		evfence = armv7_event_table + PMC_EVENT_TABLE_SIZE(armv7);
3513*bc88bb2bSRuslan Bukin 	} else if (pe >= PMC_EV_ARMV8_FIRST && pe <= PMC_EV_ARMV8_LAST) {
3514*bc88bb2bSRuslan Bukin 		switch (cpu) {
3515*bc88bb2bSRuslan Bukin 		case PMC_CPU_ARMV8_CORTEX_A53:
3516*bc88bb2bSRuslan Bukin 			ev = cortex_a53_event_table;
3517*bc88bb2bSRuslan Bukin 			evfence = cortex_a53_event_table + PMC_EVENT_TABLE_SIZE(cortex_a53);
3518*bc88bb2bSRuslan Bukin 			break;
3519*bc88bb2bSRuslan Bukin 		case PMC_CPU_ARMV8_CORTEX_A57:
3520*bc88bb2bSRuslan Bukin 			ev = cortex_a57_event_table;
3521*bc88bb2bSRuslan Bukin 			evfence = cortex_a57_event_table + PMC_EVENT_TABLE_SIZE(cortex_a57);
3522*bc88bb2bSRuslan Bukin 			break;
3523*bc88bb2bSRuslan Bukin 		default:	/* Unknown CPU type. */
3524*bc88bb2bSRuslan Bukin 			break;
3525*bc88bb2bSRuslan Bukin 		}
3526660df75eSGeorge V. Neville-Neil 	} else if (pe >= PMC_EV_MIPS24K_FIRST && pe <= PMC_EV_MIPS24K_LAST) {
3527660df75eSGeorge V. Neville-Neil 		ev = mips24k_event_table;
3528f5f9340bSFabien Thomas 		evfence = mips24k_event_table + PMC_EVENT_TABLE_SIZE(mips24k);
3529f6e6460dSAdrian Chadd 	} else if (pe >= PMC_EV_MIPS74K_FIRST && pe <= PMC_EV_MIPS74K_LAST) {
3530f6e6460dSAdrian Chadd 		ev = mips74k_event_table;
3531f6e6460dSAdrian Chadd 		evfence = mips74k_event_table + PMC_EVENT_TABLE_SIZE(mips74k);
3532c2657f80SOleksandr Tymoshenko 	} else if (pe >= PMC_EV_OCTEON_FIRST && pe <= PMC_EV_OCTEON_LAST) {
3533c2657f80SOleksandr Tymoshenko 		ev = octeon_event_table;
3534c2657f80SOleksandr Tymoshenko 		evfence = octeon_event_table + PMC_EVENT_TABLE_SIZE(octeon);
35357b25dccaSJustin Hibbits 	} else if (pe >= PMC_EV_PPC7450_FIRST && pe <= PMC_EV_PPC7450_LAST) {
35367b25dccaSJustin Hibbits 		ev = ppc7450_event_table;
3537f5f9340bSFabien Thomas 		evfence = ppc7450_event_table + PMC_EVENT_TABLE_SIZE(ppc7450);
3538169dd953SJustin Hibbits 	} else if (pe >= PMC_EV_PPC970_FIRST && pe <= PMC_EV_PPC970_LAST) {
3539169dd953SJustin Hibbits 		ev = ppc970_event_table;
3540169dd953SJustin Hibbits 		evfence = ppc970_event_table + PMC_EVENT_TABLE_SIZE(ppc970);
3541a7452468SJustin Hibbits 	} else if (pe >= PMC_EV_E500_FIRST && pe <= PMC_EV_E500_LAST) {
3542a7452468SJustin Hibbits 		ev = e500_event_table;
3543a7452468SJustin Hibbits 		evfence = e500_event_table + PMC_EVENT_TABLE_SIZE(e500);
3544789140c0SJoseph Koshy 	} else if (pe == PMC_EV_TSC_TSC) {
3545789140c0SJoseph Koshy 		ev = tsc_event_table;
3546789140c0SJoseph Koshy 		evfence = tsc_event_table + PMC_EVENT_TABLE_SIZE(tsc);
3547f0bbe9aaSDimitry Andric 	} else if ((int)pe >= PMC_EV_SOFT_FIRST && (int)pe <= PMC_EV_SOFT_LAST) {
3548f5f9340bSFabien Thomas 		ev = soft_event_table;
3549f5f9340bSFabien Thomas 		evfence = soft_event_table + soft_event_info.pm_nevent;
3550789140c0SJoseph Koshy 	}
3551789140c0SJoseph Koshy 
3552789140c0SJoseph Koshy 	for (; ev != evfence; ev++)
3553789140c0SJoseph Koshy 		if (pe == ev->pm_ev_code)
3554789140c0SJoseph Koshy 			return (ev->pm_ev_name);
3555f263522aSJoseph Koshy 
35560cfab8ddSJoseph Koshy 	return (NULL);
35570cfab8ddSJoseph Koshy }
35580cfab8ddSJoseph Koshy 
35590cfab8ddSJoseph Koshy const char *
35600cfab8ddSJoseph Koshy pmc_name_of_event(enum pmc_event pe)
35610cfab8ddSJoseph Koshy {
35620cfab8ddSJoseph Koshy 	const char *n;
35630cfab8ddSJoseph Koshy 
35640cfab8ddSJoseph Koshy 	if ((n = _pmc_name_of_event(pe, cpu_info.pm_cputype)) != NULL)
35650cfab8ddSJoseph Koshy 		return (n);
35660cfab8ddSJoseph Koshy 
3567f263522aSJoseph Koshy 	errno = EINVAL;
3568aa342b1fSJoseph Koshy 	return (NULL);
3569f263522aSJoseph Koshy }
3570f263522aSJoseph Koshy 
3571f263522aSJoseph Koshy const char *
3572f263522aSJoseph Koshy pmc_name_of_mode(enum pmc_mode pm)
3573f263522aSJoseph Koshy {
3574f263522aSJoseph Koshy 	if ((int) pm >= PMC_MODE_FIRST &&
3575f263522aSJoseph Koshy 	    pm <= PMC_MODE_LAST)
3576aa342b1fSJoseph Koshy 		return (pmc_mode_names[pm]);
3577f263522aSJoseph Koshy 
3578f263522aSJoseph Koshy 	errno = EINVAL;
3579aa342b1fSJoseph Koshy 	return (NULL);
3580f263522aSJoseph Koshy }
3581f263522aSJoseph Koshy 
3582f263522aSJoseph Koshy const char *
3583f263522aSJoseph Koshy pmc_name_of_state(enum pmc_state ps)
3584f263522aSJoseph Koshy {
3585f263522aSJoseph Koshy 	if ((int) ps >= PMC_STATE_FIRST &&
3586f263522aSJoseph Koshy 	    ps <= PMC_STATE_LAST)
3587aa342b1fSJoseph Koshy 		return (pmc_state_names[ps]);
3588f263522aSJoseph Koshy 
3589f263522aSJoseph Koshy 	errno = EINVAL;
3590aa342b1fSJoseph Koshy 	return (NULL);
3591f263522aSJoseph Koshy }
3592f263522aSJoseph Koshy 
3593f263522aSJoseph Koshy int
3594f263522aSJoseph Koshy pmc_ncpu(void)
3595f263522aSJoseph Koshy {
3596f263522aSJoseph Koshy 	if (pmc_syscall == -1) {
3597f263522aSJoseph Koshy 		errno = ENXIO;
3598aa342b1fSJoseph Koshy 		return (-1);
3599f263522aSJoseph Koshy 	}
3600f263522aSJoseph Koshy 
3601aa342b1fSJoseph Koshy 	return (cpu_info.pm_ncpu);
3602f263522aSJoseph Koshy }
3603f263522aSJoseph Koshy 
3604f263522aSJoseph Koshy int
3605f263522aSJoseph Koshy pmc_npmc(int cpu)
3606f263522aSJoseph Koshy {
3607f263522aSJoseph Koshy 	if (pmc_syscall == -1) {
3608f263522aSJoseph Koshy 		errno = ENXIO;
3609aa342b1fSJoseph Koshy 		return (-1);
3610f263522aSJoseph Koshy 	}
3611f263522aSJoseph Koshy 
3612f263522aSJoseph Koshy 	if (cpu < 0 || cpu >= (int) cpu_info.pm_ncpu) {
3613f263522aSJoseph Koshy 		errno = EINVAL;
3614aa342b1fSJoseph Koshy 		return (-1);
3615f263522aSJoseph Koshy 	}
3616f263522aSJoseph Koshy 
3617aa342b1fSJoseph Koshy 	return (cpu_info.pm_npmc);
3618f263522aSJoseph Koshy }
3619f263522aSJoseph Koshy 
3620f263522aSJoseph Koshy int
3621f263522aSJoseph Koshy pmc_pmcinfo(int cpu, struct pmc_pmcinfo **ppmci)
3622f263522aSJoseph Koshy {
3623f263522aSJoseph Koshy 	int nbytes, npmc;
3624f263522aSJoseph Koshy 	struct pmc_op_getpmcinfo *pmci;
3625f263522aSJoseph Koshy 
3626f263522aSJoseph Koshy 	if ((npmc = pmc_npmc(cpu)) < 0)
3627aa342b1fSJoseph Koshy 		return (-1);
3628f263522aSJoseph Koshy 
3629f263522aSJoseph Koshy 	nbytes = sizeof(struct pmc_op_getpmcinfo) +
3630f263522aSJoseph Koshy 	    npmc * sizeof(struct pmc_info);
3631f263522aSJoseph Koshy 
3632f263522aSJoseph Koshy 	if ((pmci = calloc(1, nbytes)) == NULL)
3633aa342b1fSJoseph Koshy 		return (-1);
3634f263522aSJoseph Koshy 
3635f263522aSJoseph Koshy 	pmci->pm_cpu  = cpu;
3636f263522aSJoseph Koshy 
3637f263522aSJoseph Koshy 	if (PMC_CALL(GETPMCINFO, pmci) < 0) {
3638f263522aSJoseph Koshy 		free(pmci);
3639aa342b1fSJoseph Koshy 		return (-1);
3640f263522aSJoseph Koshy 	}
3641f263522aSJoseph Koshy 
3642f263522aSJoseph Koshy 	/* kernel<->library, library<->userland interfaces are identical */
3643f263522aSJoseph Koshy 	*ppmci = (struct pmc_pmcinfo *) pmci;
3644aa342b1fSJoseph Koshy 	return (0);
3645f263522aSJoseph Koshy }
3646f263522aSJoseph Koshy 
3647f263522aSJoseph Koshy int
3648f263522aSJoseph Koshy pmc_read(pmc_id_t pmc, pmc_value_t *value)
3649f263522aSJoseph Koshy {
3650f263522aSJoseph Koshy 	struct pmc_op_pmcrw pmc_read_op;
3651f263522aSJoseph Koshy 
3652f263522aSJoseph Koshy 	pmc_read_op.pm_pmcid = pmc;
3653f263522aSJoseph Koshy 	pmc_read_op.pm_flags = PMC_F_OLDVALUE;
3654f263522aSJoseph Koshy 	pmc_read_op.pm_value = -1;
3655f263522aSJoseph Koshy 
3656f263522aSJoseph Koshy 	if (PMC_CALL(PMCRW, &pmc_read_op) < 0)
3657aa342b1fSJoseph Koshy 		return (-1);
3658f263522aSJoseph Koshy 
3659f263522aSJoseph Koshy 	*value = pmc_read_op.pm_value;
3660aa342b1fSJoseph Koshy 	return (0);
3661f263522aSJoseph Koshy }
3662f263522aSJoseph Koshy 
3663f263522aSJoseph Koshy int
3664f263522aSJoseph Koshy pmc_release(pmc_id_t pmc)
3665f263522aSJoseph Koshy {
3666f263522aSJoseph Koshy 	struct pmc_op_simple	pmc_release_args;
3667f263522aSJoseph Koshy 
3668f263522aSJoseph Koshy 	pmc_release_args.pm_pmcid = pmc;
3669aa342b1fSJoseph Koshy 	return (PMC_CALL(PMCRELEASE, &pmc_release_args));
3670f263522aSJoseph Koshy }
3671f263522aSJoseph Koshy 
3672f263522aSJoseph Koshy int
3673f263522aSJoseph Koshy pmc_rw(pmc_id_t pmc, pmc_value_t newvalue, pmc_value_t *oldvaluep)
3674f263522aSJoseph Koshy {
3675f263522aSJoseph Koshy 	struct pmc_op_pmcrw pmc_rw_op;
3676f263522aSJoseph Koshy 
3677f263522aSJoseph Koshy 	pmc_rw_op.pm_pmcid = pmc;
3678f263522aSJoseph Koshy 	pmc_rw_op.pm_flags = PMC_F_NEWVALUE | PMC_F_OLDVALUE;
3679f263522aSJoseph Koshy 	pmc_rw_op.pm_value = newvalue;
3680f263522aSJoseph Koshy 
3681f263522aSJoseph Koshy 	if (PMC_CALL(PMCRW, &pmc_rw_op) < 0)
3682aa342b1fSJoseph Koshy 		return (-1);
3683f263522aSJoseph Koshy 
3684f263522aSJoseph Koshy 	*oldvaluep = pmc_rw_op.pm_value;
3685aa342b1fSJoseph Koshy 	return (0);
3686f263522aSJoseph Koshy }
3687f263522aSJoseph Koshy 
3688f263522aSJoseph Koshy int
3689f263522aSJoseph Koshy pmc_set(pmc_id_t pmc, pmc_value_t value)
3690f263522aSJoseph Koshy {
3691f263522aSJoseph Koshy 	struct pmc_op_pmcsetcount sc;
3692f263522aSJoseph Koshy 
3693f263522aSJoseph Koshy 	sc.pm_pmcid = pmc;
3694f263522aSJoseph Koshy 	sc.pm_count = value;
3695f263522aSJoseph Koshy 
3696f263522aSJoseph Koshy 	if (PMC_CALL(PMCSETCOUNT, &sc) < 0)
3697aa342b1fSJoseph Koshy 		return (-1);
3698aa342b1fSJoseph Koshy 	return (0);
3699f263522aSJoseph Koshy }
3700f263522aSJoseph Koshy 
3701f263522aSJoseph Koshy int
3702f263522aSJoseph Koshy pmc_start(pmc_id_t pmc)
3703f263522aSJoseph Koshy {
3704f263522aSJoseph Koshy 	struct pmc_op_simple	pmc_start_args;
3705f263522aSJoseph Koshy 
3706f263522aSJoseph Koshy 	pmc_start_args.pm_pmcid = pmc;
3707aa342b1fSJoseph Koshy 	return (PMC_CALL(PMCSTART, &pmc_start_args));
3708f263522aSJoseph Koshy }
3709f263522aSJoseph Koshy 
3710f263522aSJoseph Koshy int
3711f263522aSJoseph Koshy pmc_stop(pmc_id_t pmc)
3712f263522aSJoseph Koshy {
3713f263522aSJoseph Koshy 	struct pmc_op_simple	pmc_stop_args;
3714f263522aSJoseph Koshy 
3715f263522aSJoseph Koshy 	pmc_stop_args.pm_pmcid = pmc;
3716aa342b1fSJoseph Koshy 	return (PMC_CALL(PMCSTOP, &pmc_stop_args));
3717f263522aSJoseph Koshy }
3718f263522aSJoseph Koshy 
3719f263522aSJoseph Koshy int
3720f263522aSJoseph Koshy pmc_width(pmc_id_t pmcid, uint32_t *width)
3721f263522aSJoseph Koshy {
3722f263522aSJoseph Koshy 	unsigned int i;
3723f263522aSJoseph Koshy 	enum pmc_class cl;
3724f263522aSJoseph Koshy 
3725f263522aSJoseph Koshy 	cl = PMC_ID_TO_CLASS(pmcid);
3726f263522aSJoseph Koshy 	for (i = 0; i < cpu_info.pm_nclass; i++)
3727f263522aSJoseph Koshy 		if (cpu_info.pm_classes[i].pm_class == cl) {
3728f263522aSJoseph Koshy 			*width = cpu_info.pm_classes[i].pm_width;
3729aa342b1fSJoseph Koshy 			return (0);
3730f263522aSJoseph Koshy 		}
3731484202faSJoseph Koshy 	errno = EINVAL;
3732484202faSJoseph Koshy 	return (-1);
3733f263522aSJoseph Koshy }
3734f263522aSJoseph Koshy 
3735f263522aSJoseph Koshy int
3736f263522aSJoseph Koshy pmc_write(pmc_id_t pmc, pmc_value_t value)
3737f263522aSJoseph Koshy {
3738f263522aSJoseph Koshy 	struct pmc_op_pmcrw pmc_write_op;
3739f263522aSJoseph Koshy 
3740f263522aSJoseph Koshy 	pmc_write_op.pm_pmcid = pmc;
3741f263522aSJoseph Koshy 	pmc_write_op.pm_flags = PMC_F_NEWVALUE;
3742f263522aSJoseph Koshy 	pmc_write_op.pm_value = value;
3743aa342b1fSJoseph Koshy 	return (PMC_CALL(PMCRW, &pmc_write_op));
3744f263522aSJoseph Koshy }
3745f263522aSJoseph Koshy 
3746f263522aSJoseph Koshy int
3747f263522aSJoseph Koshy pmc_writelog(uint32_t userdata)
3748f263522aSJoseph Koshy {
3749f263522aSJoseph Koshy 	struct pmc_op_writelog wl;
3750f263522aSJoseph Koshy 
3751f263522aSJoseph Koshy 	wl.pm_userdata = userdata;
3752aa342b1fSJoseph Koshy 	return (PMC_CALL(WRITELOG, &wl));
3753f263522aSJoseph Koshy }
3754