xref: /freebsd/lib/libpmc/libpmc.c (revision 75f46cf6c81eff6229b9579513b6e7769b91d75d)
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
85bc88bb2bSRuslan Bukin #if defined(__aarch64__)
86bc88bb2bSRuslan Bukin static int arm64_allocate_pmc(enum pmc_event _pe, char *_ctrspec,
87bc88bb2bSRuslan Bukin     struct pmc_op_pmcallocate *_pmc_config);
88bc88bb2bSRuslan 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);
165bc88bb2bSRuslan 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 
220f19bae41SRandall Stewart static const struct pmc_event_descr broadwell_event_table[] =
221f19bae41SRandall Stewart {
222f19bae41SRandall Stewart 	__PMC_EV_ALIAS_BROADWELL()
223f19bae41SRandall Stewart };
224f19bae41SRandall Stewart 
225f19bae41SRandall Stewart static const struct pmc_event_descr broadwell_xeon_event_table[] =
226f19bae41SRandall Stewart {
227f19bae41SRandall Stewart 	__PMC_EV_ALIAS_BROADWELL_XEON()
228f19bae41SRandall Stewart };
229f19bae41SRandall Stewart 
230f19bae41SRandall Stewart static const struct pmc_event_descr skylake_event_table[] =
231f19bae41SRandall Stewart {
232f19bae41SRandall Stewart 	__PMC_EV_ALIAS_SKYLAKE()
233f19bae41SRandall Stewart };
234d95b3509SRandall Stewart 
2351e862e5aSFabien Thomas static const struct pmc_event_descr ivybridge_event_table[] =
2361e862e5aSFabien Thomas {
2371e862e5aSFabien Thomas 	__PMC_EV_ALIAS_IVYBRIDGE()
2381e862e5aSFabien Thomas };
2391e862e5aSFabien Thomas 
2403f929d8cSSean Bruno static const struct pmc_event_descr ivybridge_xeon_event_table[] =
2413f929d8cSSean Bruno {
2423f929d8cSSean Bruno 	__PMC_EV_ALIAS_IVYBRIDGE_XEON()
2433f929d8cSSean Bruno };
2443f929d8cSSean Bruno 
24578d763a2SDavide Italiano static const struct pmc_event_descr sandybridge_event_table[] =
24678d763a2SDavide Italiano {
24778d763a2SDavide Italiano 	__PMC_EV_ALIAS_SANDYBRIDGE()
24878d763a2SDavide Italiano };
24978d763a2SDavide Italiano 
250fabe02f5SSean Bruno static const struct pmc_event_descr sandybridge_xeon_event_table[] =
251fabe02f5SSean Bruno {
252fabe02f5SSean Bruno 	__PMC_EV_ALIAS_SANDYBRIDGE_XEON()
253fabe02f5SSean Bruno };
254fabe02f5SSean Bruno 
2551fa7f10bSFabien Thomas static const struct pmc_event_descr westmere_event_table[] =
2561fa7f10bSFabien Thomas {
2571fa7f10bSFabien Thomas 	__PMC_EV_ALIAS_WESTMERE()
2581fa7f10bSFabien Thomas };
2591fa7f10bSFabien Thomas 
26049fe48abSKonstantin Belousov static const struct pmc_event_descr westmere_ex_event_table[] =
26149fe48abSKonstantin Belousov {
26249fe48abSKonstantin Belousov 	__PMC_EV_ALIAS_WESTMERE()
26349fe48abSKonstantin Belousov };
26449fe48abSKonstantin Belousov 
2651fa7f10bSFabien Thomas static const struct pmc_event_descr corei7uc_event_table[] =
2661fa7f10bSFabien Thomas {
2671fa7f10bSFabien Thomas 	__PMC_EV_ALIAS_COREI7UC()
2681fa7f10bSFabien Thomas };
2691fa7f10bSFabien Thomas 
270cc0c1555SSean Bruno static const struct pmc_event_descr haswelluc_event_table[] =
271cc0c1555SSean Bruno {
272cc0c1555SSean Bruno 	__PMC_EV_ALIAS_HASWELLUC()
273cc0c1555SSean Bruno };
274cc0c1555SSean Bruno 
275f19bae41SRandall Stewart static const struct pmc_event_descr broadwelluc_event_table[] =
276f19bae41SRandall Stewart {
277f19bae41SRandall Stewart 	__PMC_EV_ALIAS_BROADWELLUC()
278f19bae41SRandall Stewart };
279f19bae41SRandall Stewart 
28078d763a2SDavide Italiano static const struct pmc_event_descr sandybridgeuc_event_table[] =
28178d763a2SDavide Italiano {
28278d763a2SDavide Italiano 	__PMC_EV_ALIAS_SANDYBRIDGEUC()
28378d763a2SDavide Italiano };
28478d763a2SDavide Italiano 
2851fa7f10bSFabien Thomas static const struct pmc_event_descr westmereuc_event_table[] =
2861fa7f10bSFabien Thomas {
2871fa7f10bSFabien Thomas 	__PMC_EV_ALIAS_WESTMEREUC()
2881fa7f10bSFabien Thomas };
2891fa7f10bSFabien Thomas 
2903e0bfdd8SRuslan Bukin static const struct pmc_event_descr cortex_a8_event_table[] =
2913e0bfdd8SRuslan Bukin {
2923e0bfdd8SRuslan Bukin 	__PMC_EV_ALIAS_ARMV7_CORTEX_A8()
2933e0bfdd8SRuslan Bukin };
2943e0bfdd8SRuslan Bukin 
2953e0bfdd8SRuslan Bukin static const struct pmc_event_descr cortex_a9_event_table[] =
2963e0bfdd8SRuslan Bukin {
2973e0bfdd8SRuslan Bukin 	__PMC_EV_ALIAS_ARMV7_CORTEX_A9()
2983e0bfdd8SRuslan Bukin };
2993e0bfdd8SRuslan Bukin 
300bc88bb2bSRuslan Bukin static const struct pmc_event_descr cortex_a53_event_table[] =
301bc88bb2bSRuslan Bukin {
302bc88bb2bSRuslan Bukin 	__PMC_EV_ALIAS_ARMV8_CORTEX_A53()
303bc88bb2bSRuslan Bukin };
304bc88bb2bSRuslan Bukin 
305bc88bb2bSRuslan Bukin static const struct pmc_event_descr cortex_a57_event_table[] =
306bc88bb2bSRuslan Bukin {
307bc88bb2bSRuslan Bukin 	__PMC_EV_ALIAS_ARMV8_CORTEX_A57()
308bc88bb2bSRuslan Bukin };
309bc88bb2bSRuslan Bukin 
3100cfab8ddSJoseph Koshy /*
3110cfab8ddSJoseph Koshy  * PMC_MDEP_TABLE(NAME, PRIMARYCLASS, ADDITIONAL_CLASSES...)
3120cfab8ddSJoseph Koshy  *
3130cfab8ddSJoseph Koshy  * Map a CPU to the PMC classes it supports.
3140cfab8ddSJoseph Koshy  */
3150cfab8ddSJoseph Koshy #define	PMC_MDEP_TABLE(N,C,...)				\
316789140c0SJoseph Koshy 	static const enum pmc_class N##_pmc_classes[] = {	\
317789140c0SJoseph Koshy 		PMC_CLASS_##C, __VA_ARGS__			\
318789140c0SJoseph Koshy 	}
319789140c0SJoseph Koshy 
320f5f9340bSFabien Thomas PMC_MDEP_TABLE(atom, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC);
321e8f021a3SHiren Panchasara PMC_MDEP_TABLE(atom_silvermont, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC);
322f5f9340bSFabien Thomas PMC_MDEP_TABLE(core, IAP, PMC_CLASS_SOFT, PMC_CLASS_TSC);
323f5f9340bSFabien Thomas PMC_MDEP_TABLE(core2, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC);
324f5f9340bSFabien Thomas PMC_MDEP_TABLE(corei7, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC, PMC_CLASS_UCF, PMC_CLASS_UCP);
32549fe48abSKonstantin Belousov PMC_MDEP_TABLE(nehalem_ex, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC);
326cc0c1555SSean Bruno PMC_MDEP_TABLE(haswell, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC, PMC_CLASS_UCF, PMC_CLASS_UCP);
327d95b3509SRandall Stewart PMC_MDEP_TABLE(haswell_xeon, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC, PMC_CLASS_UCF, PMC_CLASS_UCP);
328f19bae41SRandall Stewart PMC_MDEP_TABLE(broadwell, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC, PMC_CLASS_UCF, PMC_CLASS_UCP);
329f19bae41SRandall Stewart PMC_MDEP_TABLE(broadwell_xeon, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC, PMC_CLASS_UCF, PMC_CLASS_UCP);
330f19bae41SRandall Stewart PMC_MDEP_TABLE(skylake, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC, PMC_CLASS_UCF, PMC_CLASS_UCP);
3311e862e5aSFabien Thomas PMC_MDEP_TABLE(ivybridge, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC);
3323f929d8cSSean Bruno PMC_MDEP_TABLE(ivybridge_xeon, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC);
333f5f9340bSFabien Thomas PMC_MDEP_TABLE(sandybridge, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC, PMC_CLASS_UCF, PMC_CLASS_UCP);
334fabe02f5SSean Bruno PMC_MDEP_TABLE(sandybridge_xeon, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC);
335f5f9340bSFabien Thomas PMC_MDEP_TABLE(westmere, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC, PMC_CLASS_UCF, PMC_CLASS_UCP);
33649fe48abSKonstantin Belousov PMC_MDEP_TABLE(westmere_ex, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC);
337f5f9340bSFabien Thomas PMC_MDEP_TABLE(k7, K7, PMC_CLASS_SOFT, PMC_CLASS_TSC);
338f5f9340bSFabien Thomas PMC_MDEP_TABLE(k8, K8, PMC_CLASS_SOFT, PMC_CLASS_TSC);
339f5f9340bSFabien Thomas PMC_MDEP_TABLE(p4, P4, PMC_CLASS_SOFT, PMC_CLASS_TSC);
340f5f9340bSFabien Thomas PMC_MDEP_TABLE(p5, P5, PMC_CLASS_SOFT, PMC_CLASS_TSC);
341f5f9340bSFabien Thomas PMC_MDEP_TABLE(p6, P6, PMC_CLASS_SOFT, PMC_CLASS_TSC);
342f5f9340bSFabien Thomas PMC_MDEP_TABLE(xscale, XSCALE, PMC_CLASS_SOFT, PMC_CLASS_XSCALE);
3433e0bfdd8SRuslan Bukin PMC_MDEP_TABLE(cortex_a8, ARMV7, PMC_CLASS_SOFT, PMC_CLASS_ARMV7);
3443e0bfdd8SRuslan Bukin PMC_MDEP_TABLE(cortex_a9, ARMV7, PMC_CLASS_SOFT, PMC_CLASS_ARMV7);
345bc88bb2bSRuslan Bukin PMC_MDEP_TABLE(cortex_a53, ARMV8, PMC_CLASS_SOFT, PMC_CLASS_ARMV8);
346bc88bb2bSRuslan Bukin PMC_MDEP_TABLE(cortex_a57, ARMV8, PMC_CLASS_SOFT, PMC_CLASS_ARMV8);
347f5f9340bSFabien Thomas PMC_MDEP_TABLE(mips24k, MIPS24K, PMC_CLASS_SOFT, PMC_CLASS_MIPS24K);
348f6e6460dSAdrian Chadd PMC_MDEP_TABLE(mips74k, MIPS74K, PMC_CLASS_SOFT, PMC_CLASS_MIPS74K);
349f5f9340bSFabien Thomas PMC_MDEP_TABLE(octeon, OCTEON, PMC_CLASS_SOFT, PMC_CLASS_OCTEON);
350a7452468SJustin Hibbits PMC_MDEP_TABLE(ppc7450, PPC7450, PMC_CLASS_SOFT, PMC_CLASS_PPC7450, PMC_CLASS_TSC);
351a7452468SJustin Hibbits PMC_MDEP_TABLE(ppc970, PPC970, PMC_CLASS_SOFT, PMC_CLASS_PPC970, PMC_CLASS_TSC);
352a7452468SJustin Hibbits PMC_MDEP_TABLE(e500, E500, PMC_CLASS_SOFT, PMC_CLASS_E500, PMC_CLASS_TSC);
353f5f9340bSFabien Thomas PMC_MDEP_TABLE(generic, SOFT, PMC_CLASS_SOFT);
354789140c0SJoseph Koshy 
355789140c0SJoseph Koshy static const struct pmc_event_descr tsc_event_table[] =
356789140c0SJoseph Koshy {
357789140c0SJoseph Koshy 	__PMC_EV_TSC()
358789140c0SJoseph Koshy };
359789140c0SJoseph Koshy 
360789140c0SJoseph Koshy #undef	PMC_CLASS_TABLE_DESC
3610cfab8ddSJoseph Koshy #define	PMC_CLASS_TABLE_DESC(NAME, CLASS, EVENTS, ALLOCATOR)	\
3620cfab8ddSJoseph Koshy static const struct pmc_class_descr NAME##_class_table_descr =	\
3630cfab8ddSJoseph Koshy 	{							\
3640cfab8ddSJoseph Koshy 		.pm_evc_name  = #CLASS "-",			\
3650cfab8ddSJoseph Koshy 		.pm_evc_name_size = sizeof(#CLASS "-") - 1,	\
3660cfab8ddSJoseph Koshy 		.pm_evc_class = PMC_CLASS_##CLASS ,		\
3670cfab8ddSJoseph Koshy 		.pm_evc_event_table = EVENTS##_event_table ,	\
368789140c0SJoseph Koshy 		.pm_evc_event_table_size = 			\
3690cfab8ddSJoseph Koshy 			PMC_EVENT_TABLE_SIZE(EVENTS),		\
3700cfab8ddSJoseph Koshy 		.pm_evc_allocate_pmc = ALLOCATOR##_allocate_pmc	\
371789140c0SJoseph Koshy 	}
372789140c0SJoseph Koshy 
373789140c0SJoseph Koshy #if	defined(__i386__) || defined(__amd64__)
3740cfab8ddSJoseph Koshy PMC_CLASS_TABLE_DESC(iaf, IAF, iaf, iaf);
3750cfab8ddSJoseph Koshy PMC_CLASS_TABLE_DESC(atom, IAP, atom, iap);
376e8f021a3SHiren Panchasara PMC_CLASS_TABLE_DESC(atom_silvermont, IAP, atom_silvermont, iap);
3770cfab8ddSJoseph Koshy PMC_CLASS_TABLE_DESC(core, IAP, core, iap);
3780cfab8ddSJoseph Koshy PMC_CLASS_TABLE_DESC(core2, IAP, core2, iap);
379597979c4SJeff Roberson PMC_CLASS_TABLE_DESC(corei7, IAP, corei7, iap);
38049fe48abSKonstantin Belousov PMC_CLASS_TABLE_DESC(nehalem_ex, IAP, nehalem_ex, iap);
381cc0c1555SSean Bruno PMC_CLASS_TABLE_DESC(haswell, IAP, haswell, iap);
382ae9975dbSRyan Stone PMC_CLASS_TABLE_DESC(haswell_xeon, IAP, haswell_xeon, iap);
383f19bae41SRandall Stewart PMC_CLASS_TABLE_DESC(broadwell, IAP, broadwell, iap);
384f19bae41SRandall Stewart PMC_CLASS_TABLE_DESC(broadwell_xeon, IAP, broadwell_xeon, iap);
385f19bae41SRandall Stewart PMC_CLASS_TABLE_DESC(skylake, IAP, skylake, iap);
3861e862e5aSFabien Thomas PMC_CLASS_TABLE_DESC(ivybridge, IAP, ivybridge, iap);
3873f929d8cSSean Bruno PMC_CLASS_TABLE_DESC(ivybridge_xeon, IAP, ivybridge_xeon, iap);
38878d763a2SDavide Italiano PMC_CLASS_TABLE_DESC(sandybridge, IAP, sandybridge, iap);
389fabe02f5SSean Bruno PMC_CLASS_TABLE_DESC(sandybridge_xeon, IAP, sandybridge_xeon, iap);
3901fa7f10bSFabien Thomas PMC_CLASS_TABLE_DESC(westmere, IAP, westmere, iap);
39149fe48abSKonstantin Belousov PMC_CLASS_TABLE_DESC(westmere_ex, IAP, westmere_ex, iap);
3921fa7f10bSFabien Thomas PMC_CLASS_TABLE_DESC(ucf, UCF, ucf, ucf);
3931fa7f10bSFabien Thomas PMC_CLASS_TABLE_DESC(corei7uc, UCP, corei7uc, ucp);
394cc0c1555SSean Bruno PMC_CLASS_TABLE_DESC(haswelluc, UCP, haswelluc, ucp);
395f19bae41SRandall Stewart PMC_CLASS_TABLE_DESC(broadwelluc, UCP, broadwelluc, ucp);
39678d763a2SDavide Italiano PMC_CLASS_TABLE_DESC(sandybridgeuc, UCP, sandybridgeuc, ucp);
3971fa7f10bSFabien Thomas PMC_CLASS_TABLE_DESC(westmereuc, UCP, westmereuc, ucp);
398789140c0SJoseph Koshy #endif
399789140c0SJoseph Koshy #if	defined(__i386__)
4000cfab8ddSJoseph Koshy PMC_CLASS_TABLE_DESC(k7, K7, k7, k7);
401789140c0SJoseph Koshy #endif
402789140c0SJoseph Koshy #if	defined(__i386__) || defined(__amd64__)
4030cfab8ddSJoseph Koshy PMC_CLASS_TABLE_DESC(k8, K8, k8, k8);
4040cfab8ddSJoseph Koshy PMC_CLASS_TABLE_DESC(p4, P4, p4, p4);
405789140c0SJoseph Koshy #endif
4060cfab8ddSJoseph Koshy #if	defined(__i386__)
4070cfab8ddSJoseph Koshy PMC_CLASS_TABLE_DESC(p5, P5, p5, p5);
4080cfab8ddSJoseph Koshy PMC_CLASS_TABLE_DESC(p6, P6, p6, p6);
4090cfab8ddSJoseph Koshy #endif
4100cfab8ddSJoseph Koshy #if	defined(__i386__) || defined(__amd64__)
4110cfab8ddSJoseph Koshy PMC_CLASS_TABLE_DESC(tsc, TSC, tsc, tsc);
4120cfab8ddSJoseph Koshy #endif
4136411d14dSRuslan Bukin #if	defined(__arm__)
4140ce207d2SRui Paulo #if	defined(__XSCALE__)
4150ce207d2SRui Paulo PMC_CLASS_TABLE_DESC(xscale, XSCALE, xscale, xscale);
4160ce207d2SRui Paulo #endif
4173ed01392SBjoern A. Zeeb PMC_CLASS_TABLE_DESC(cortex_a8, ARMV7, cortex_a8, armv7);
4183e0bfdd8SRuslan Bukin PMC_CLASS_TABLE_DESC(cortex_a9, ARMV7, cortex_a9, armv7);
4196411d14dSRuslan Bukin #endif
420bc88bb2bSRuslan Bukin #if	defined(__aarch64__)
421bc88bb2bSRuslan Bukin PMC_CLASS_TABLE_DESC(cortex_a53, ARMV8, cortex_a53, arm64);
422bc88bb2bSRuslan Bukin PMC_CLASS_TABLE_DESC(cortex_a57, ARMV8, cortex_a57, arm64);
423bc88bb2bSRuslan Bukin #endif
424660df75eSGeorge V. Neville-Neil #if defined(__mips__)
4252827d3e1SOleksandr Tymoshenko PMC_CLASS_TABLE_DESC(mips24k, MIPS24K, mips24k, mips);
426f6e6460dSAdrian Chadd PMC_CLASS_TABLE_DESC(mips74k, MIPS74K, mips74k, mips);
427c2657f80SOleksandr Tymoshenko PMC_CLASS_TABLE_DESC(octeon, OCTEON, octeon, mips);
428660df75eSGeorge V. Neville-Neil #endif /* __mips__ */
4297b25dccaSJustin Hibbits #if defined(__powerpc__)
430169dd953SJustin Hibbits PMC_CLASS_TABLE_DESC(ppc7450, PPC7450, ppc7450, powerpc);
431169dd953SJustin Hibbits PMC_CLASS_TABLE_DESC(ppc970, PPC970, ppc970, powerpc);
432a7452468SJustin Hibbits PMC_CLASS_TABLE_DESC(e500, E500, e500, powerpc);
4337b25dccaSJustin Hibbits #endif
4347b25dccaSJustin Hibbits 
435f5f9340bSFabien Thomas static struct pmc_class_descr soft_class_table_descr =
436f5f9340bSFabien Thomas {
437f5f9340bSFabien Thomas 	.pm_evc_name  = "SOFT-",
438f5f9340bSFabien Thomas 	.pm_evc_name_size = sizeof("SOFT-") - 1,
439f5f9340bSFabien Thomas 	.pm_evc_class = PMC_CLASS_SOFT,
440f5f9340bSFabien Thomas 	.pm_evc_event_table = NULL,
441f5f9340bSFabien Thomas 	.pm_evc_event_table_size = 0,
442f5f9340bSFabien Thomas 	.pm_evc_allocate_pmc = soft_allocate_pmc
443f5f9340bSFabien Thomas };
444f5f9340bSFabien Thomas 
445789140c0SJoseph Koshy #undef	PMC_CLASS_TABLE_DESC
446789140c0SJoseph Koshy 
4470cfab8ddSJoseph Koshy static const struct pmc_class_descr **pmc_class_table;
4480cfab8ddSJoseph Koshy #define	PMC_CLASS_TABLE_SIZE	cpu_info.pm_nclass
4490cfab8ddSJoseph Koshy 
450789140c0SJoseph Koshy static const enum pmc_class *pmc_mdep_class_list;
451789140c0SJoseph Koshy static size_t pmc_mdep_class_list_size;
452789140c0SJoseph Koshy 
453ebccf1e3SJoseph Koshy /*
454ebccf1e3SJoseph Koshy  * Mapping tables, mapping enumeration values to human readable
455ebccf1e3SJoseph Koshy  * strings.
456ebccf1e3SJoseph Koshy  */
457ebccf1e3SJoseph Koshy 
458ebccf1e3SJoseph Koshy static const char * pmc_capability_names[] = {
459ebccf1e3SJoseph Koshy #undef	__PMC_CAP
460ebccf1e3SJoseph Koshy #define	__PMC_CAP(N,V,D)	#N ,
461ebccf1e3SJoseph Koshy 	__PMC_CAPS()
462ebccf1e3SJoseph Koshy };
463ebccf1e3SJoseph Koshy 
4640ceb54c2SJohn Baldwin struct pmc_class_map {
4650ceb54c2SJohn Baldwin 	enum pmc_class	pm_class;
4660ceb54c2SJohn Baldwin 	const char	*pm_name;
4670ceb54c2SJohn Baldwin };
4680ceb54c2SJohn Baldwin 
4690ceb54c2SJohn Baldwin static const struct pmc_class_map pmc_class_names[] = {
470ebccf1e3SJoseph Koshy #undef	__PMC_CLASS
4710ceb54c2SJohn Baldwin #define __PMC_CLASS(S,V,D) { .pm_class = PMC_CLASS_##S, .pm_name = #S } ,
472ebccf1e3SJoseph Koshy 	__PMC_CLASSES()
473ebccf1e3SJoseph Koshy };
474ebccf1e3SJoseph Koshy 
475789140c0SJoseph Koshy struct pmc_cputype_map {
476562fc14bSDimitry Andric 	enum pmc_cputype pm_cputype;
477789140c0SJoseph Koshy 	const char	*pm_name;
478789140c0SJoseph Koshy };
479789140c0SJoseph Koshy 
480789140c0SJoseph Koshy static const struct pmc_cputype_map pmc_cputype_names[] = {
481ebccf1e3SJoseph Koshy #undef	__PMC_CPU
482789140c0SJoseph Koshy #define	__PMC_CPU(S, V, D) { .pm_cputype = PMC_CPU_##S, .pm_name = #S } ,
483ebccf1e3SJoseph Koshy 	__PMC_CPUS()
484ebccf1e3SJoseph Koshy };
485ebccf1e3SJoseph Koshy 
486ebccf1e3SJoseph Koshy static const char * pmc_disposition_names[] = {
487ebccf1e3SJoseph Koshy #undef	__PMC_DISP
488ebccf1e3SJoseph Koshy #define	__PMC_DISP(D)	#D ,
489ebccf1e3SJoseph Koshy 	__PMC_DISPOSITIONS()
490ebccf1e3SJoseph Koshy };
491ebccf1e3SJoseph Koshy 
492ebccf1e3SJoseph Koshy static const char * pmc_mode_names[] = {
493ebccf1e3SJoseph Koshy #undef  __PMC_MODE
494ebccf1e3SJoseph Koshy #define __PMC_MODE(M,N)	#M ,
495ebccf1e3SJoseph Koshy 	__PMC_MODES()
496ebccf1e3SJoseph Koshy };
497ebccf1e3SJoseph Koshy 
498ebccf1e3SJoseph Koshy static const char * pmc_state_names[] = {
499ebccf1e3SJoseph Koshy #undef  __PMC_STATE
500ebccf1e3SJoseph Koshy #define __PMC_STATE(S) #S ,
501ebccf1e3SJoseph Koshy 	__PMC_STATES()
502ebccf1e3SJoseph Koshy };
503ebccf1e3SJoseph Koshy 
504f5f9340bSFabien Thomas /*
505f5f9340bSFabien Thomas  * Filled in by pmc_init().
506f5f9340bSFabien Thomas  */
507f5f9340bSFabien Thomas static int pmc_syscall = -1;
508f5f9340bSFabien Thomas static struct pmc_cpuinfo cpu_info;
509f5f9340bSFabien Thomas static struct pmc_op_getdyneventinfo soft_event_info;
5101455fcd3SJoseph Koshy 
511ebccf1e3SJoseph Koshy /* Event masks for events */
512ebccf1e3SJoseph Koshy struct pmc_masks {
513ebccf1e3SJoseph Koshy 	const char	*pm_name;
5141e862e5aSFabien Thomas 	const uint64_t	pm_value;
515ebccf1e3SJoseph Koshy };
516ebccf1e3SJoseph Koshy #define	PMCMASK(N,V)	{ .pm_name = #N, .pm_value = (V) }
5171fa7f10bSFabien Thomas #define	NULLMASK	{ .pm_name = NULL }
518ebccf1e3SJoseph Koshy 
51986a65549SJoseph Koshy #if defined(__amd64__) || defined(__i386__)
520ebccf1e3SJoseph Koshy static int
5211e862e5aSFabien Thomas pmc_parse_mask(const struct pmc_masks *pmask, char *p, uint64_t *evmask)
522ebccf1e3SJoseph Koshy {
523ebccf1e3SJoseph Koshy 	const struct pmc_masks *pm;
524ebccf1e3SJoseph Koshy 	char *q, *r;
525ebccf1e3SJoseph Koshy 	int c;
526ebccf1e3SJoseph Koshy 
527ebccf1e3SJoseph Koshy 	if (pmask == NULL)	/* no mask keywords */
528aa342b1fSJoseph Koshy 		return (-1);
529ebccf1e3SJoseph Koshy 	q = strchr(p, '=');	/* skip '=' */
530ebccf1e3SJoseph Koshy 	if (*++q == '\0')	/* no more data */
531aa342b1fSJoseph Koshy 		return (-1);
532ebccf1e3SJoseph Koshy 	c = 0;			/* count of mask keywords seen */
533ebccf1e3SJoseph Koshy 	while ((r = strsep(&q, "+")) != NULL) {
534789140c0SJoseph Koshy 		for (pm = pmask; pm->pm_name && strcasecmp(r, pm->pm_name);
535789140c0SJoseph Koshy 		    pm++)
536ebccf1e3SJoseph Koshy 			;
537ebccf1e3SJoseph Koshy 		if (pm->pm_name == NULL) /* not found */
538aa342b1fSJoseph Koshy 			return (-1);
539ebccf1e3SJoseph Koshy 		*evmask |= pm->pm_value;
540ebccf1e3SJoseph Koshy 		c++;
541ebccf1e3SJoseph Koshy 	}
542aa342b1fSJoseph Koshy 	return (c);
543ebccf1e3SJoseph Koshy }
54404e9feb0SMarcel Moolenaar #endif
545ebccf1e3SJoseph Koshy 
546ebccf1e3SJoseph Koshy #define	KWMATCH(p,kw)		(strcasecmp((p), (kw)) == 0)
547ebccf1e3SJoseph Koshy #define	KWPREFIXMATCH(p,kw)	(strncasecmp((p), (kw), sizeof((kw)) - 1) == 0)
548ebccf1e3SJoseph Koshy #define	EV_ALIAS(N,S)		{ .pm_alias = N, .pm_spec = S }
549ebccf1e3SJoseph Koshy 
55004e9feb0SMarcel Moolenaar #if defined(__i386__)
551ebccf1e3SJoseph Koshy 
552ebccf1e3SJoseph Koshy /*
553ebccf1e3SJoseph Koshy  * AMD K7 (Athlon) CPUs.
554ebccf1e3SJoseph Koshy  */
555ebccf1e3SJoseph Koshy 
556ebccf1e3SJoseph Koshy static struct pmc_event_alias k7_aliases[] = {
557ebccf1e3SJoseph Koshy 	EV_ALIAS("branches",		"k7-retired-branches"),
558ebccf1e3SJoseph Koshy 	EV_ALIAS("branch-mispredicts",	"k7-retired-branches-mispredicted"),
559ebccf1e3SJoseph Koshy 	EV_ALIAS("cycles",		"tsc"),
5606aa5a193SJoseph Koshy 	EV_ALIAS("dc-misses",		"k7-dc-misses"),
561ebccf1e3SJoseph Koshy 	EV_ALIAS("ic-misses",		"k7-ic-misses"),
562ebccf1e3SJoseph Koshy 	EV_ALIAS("instructions",	"k7-retired-instructions"),
563ebccf1e3SJoseph Koshy 	EV_ALIAS("interrupts",		"k7-hardware-interrupts"),
564ebccf1e3SJoseph Koshy 	EV_ALIAS(NULL, NULL)
565ebccf1e3SJoseph Koshy };
566ebccf1e3SJoseph Koshy 
567ebccf1e3SJoseph Koshy #define	K7_KW_COUNT	"count"
568ebccf1e3SJoseph Koshy #define	K7_KW_EDGE	"edge"
569ebccf1e3SJoseph Koshy #define	K7_KW_INV	"inv"
570ebccf1e3SJoseph Koshy #define	K7_KW_OS	"os"
571ebccf1e3SJoseph Koshy #define	K7_KW_UNITMASK	"unitmask"
572ebccf1e3SJoseph Koshy #define	K7_KW_USR	"usr"
573ebccf1e3SJoseph Koshy 
574ebccf1e3SJoseph Koshy static int
575ebccf1e3SJoseph Koshy k7_allocate_pmc(enum pmc_event pe, char *ctrspec,
576ebccf1e3SJoseph Koshy     struct pmc_op_pmcallocate *pmc_config)
577ebccf1e3SJoseph Koshy {
578ebccf1e3SJoseph Koshy 	char		*e, *p, *q;
579ebccf1e3SJoseph Koshy 	int		c, has_unitmask;
580ebccf1e3SJoseph Koshy 	uint32_t	count, unitmask;
581ebccf1e3SJoseph Koshy 
582f263522aSJoseph Koshy 	pmc_config->pm_md.pm_amd.pm_amd_config = 0;
583789140c0SJoseph Koshy 	pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE);
584ebccf1e3SJoseph Koshy 
585ebccf1e3SJoseph Koshy 	if (pe == PMC_EV_K7_DC_REFILLS_FROM_L2 ||
586ebccf1e3SJoseph Koshy 	    pe == PMC_EV_K7_DC_REFILLS_FROM_SYSTEM ||
587ebccf1e3SJoseph Koshy 	    pe == PMC_EV_K7_DC_WRITEBACKS) {
588ebccf1e3SJoseph Koshy 		has_unitmask = 1;
589f263522aSJoseph Koshy 		unitmask = AMD_PMC_UNITMASK_MOESI;
590ebccf1e3SJoseph Koshy 	} else
591ebccf1e3SJoseph Koshy 		unitmask = has_unitmask = 0;
592ebccf1e3SJoseph Koshy 
593ebccf1e3SJoseph Koshy 	while ((p = strsep(&ctrspec, ",")) != NULL) {
594ebccf1e3SJoseph Koshy 		if (KWPREFIXMATCH(p, K7_KW_COUNT "=")) {
595ebccf1e3SJoseph Koshy 			q = strchr(p, '=');
596ebccf1e3SJoseph Koshy 			if (*++q == '\0') /* skip '=' */
597aa342b1fSJoseph Koshy 				return (-1);
598ebccf1e3SJoseph Koshy 
599ebccf1e3SJoseph Koshy 			count = strtol(q, &e, 0);
600ebccf1e3SJoseph Koshy 			if (e == q || *e != '\0')
601aa342b1fSJoseph Koshy 				return (-1);
602ebccf1e3SJoseph Koshy 
603ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_THRESHOLD;
604f263522aSJoseph Koshy 			pmc_config->pm_md.pm_amd.pm_amd_config |=
605f263522aSJoseph Koshy 			    AMD_PMC_TO_COUNTER(count);
606ebccf1e3SJoseph Koshy 
607ebccf1e3SJoseph Koshy 		} else if (KWMATCH(p, K7_KW_EDGE)) {
608ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_EDGE;
609ebccf1e3SJoseph Koshy 		} else if (KWMATCH(p, K7_KW_INV)) {
610ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_INVERT;
611ebccf1e3SJoseph Koshy 		} else if (KWMATCH(p, K7_KW_OS)) {
612ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_SYSTEM;
613ebccf1e3SJoseph Koshy 		} else if (KWPREFIXMATCH(p, K7_KW_UNITMASK "=")) {
614ebccf1e3SJoseph Koshy 			if (has_unitmask == 0)
615aa342b1fSJoseph Koshy 				return (-1);
616ebccf1e3SJoseph Koshy 			unitmask = 0;
617ebccf1e3SJoseph Koshy 			q = strchr(p, '=');
618ebccf1e3SJoseph Koshy 			if (*++q == '\0') /* skip '=' */
619aa342b1fSJoseph Koshy 				return (-1);
620ebccf1e3SJoseph Koshy 
621ebccf1e3SJoseph Koshy 			while ((c = tolower(*q++)) != 0)
622ebccf1e3SJoseph Koshy 				if (c == 'm')
623f263522aSJoseph Koshy 					unitmask |= AMD_PMC_UNITMASK_M;
624ebccf1e3SJoseph Koshy 				else if (c == 'o')
625f263522aSJoseph Koshy 					unitmask |= AMD_PMC_UNITMASK_O;
626ebccf1e3SJoseph Koshy 				else if (c == 'e')
627f263522aSJoseph Koshy 					unitmask |= AMD_PMC_UNITMASK_E;
628ebccf1e3SJoseph Koshy 				else if (c == 's')
629f263522aSJoseph Koshy 					unitmask |= AMD_PMC_UNITMASK_S;
630ebccf1e3SJoseph Koshy 				else if (c == 'i')
631f263522aSJoseph Koshy 					unitmask |= AMD_PMC_UNITMASK_I;
632ebccf1e3SJoseph Koshy 				else if (c == '+')
633ebccf1e3SJoseph Koshy 					continue;
634ebccf1e3SJoseph Koshy 				else
635aa342b1fSJoseph Koshy 					return (-1);
636ebccf1e3SJoseph Koshy 
637ebccf1e3SJoseph Koshy 			if (unitmask == 0)
638aa342b1fSJoseph Koshy 				return (-1);
639ebccf1e3SJoseph Koshy 
640ebccf1e3SJoseph Koshy 		} else if (KWMATCH(p, K7_KW_USR)) {
641ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_USER;
642ebccf1e3SJoseph Koshy 		} else
643aa342b1fSJoseph Koshy 			return (-1);
644ebccf1e3SJoseph Koshy 	}
645ebccf1e3SJoseph Koshy 
646ebccf1e3SJoseph Koshy 	if (has_unitmask) {
647ebccf1e3SJoseph Koshy 		pmc_config->pm_caps |= PMC_CAP_QUALIFIER;
648f263522aSJoseph Koshy 		pmc_config->pm_md.pm_amd.pm_amd_config |=
649f263522aSJoseph Koshy 		    AMD_PMC_TO_UNITMASK(unitmask);
650ebccf1e3SJoseph Koshy 	}
651ebccf1e3SJoseph Koshy 
652aa342b1fSJoseph Koshy 	return (0);
653ebccf1e3SJoseph Koshy 
654ebccf1e3SJoseph Koshy }
655ebccf1e3SJoseph Koshy 
656f263522aSJoseph Koshy #endif
657f263522aSJoseph Koshy 
65886a65549SJoseph Koshy #if defined(__amd64__) || defined(__i386__)
659f263522aSJoseph Koshy 
660f263522aSJoseph Koshy /*
6610cfab8ddSJoseph Koshy  * Intel Core (Family 6, Model E) PMCs.
6620cfab8ddSJoseph Koshy  */
6630cfab8ddSJoseph Koshy 
6640cfab8ddSJoseph Koshy static struct pmc_event_alias core_aliases[] = {
6650cfab8ddSJoseph Koshy 	EV_ALIAS("branches",		"iap-br-instr-ret"),
6660cfab8ddSJoseph Koshy 	EV_ALIAS("branch-mispredicts",	"iap-br-mispred-ret"),
6670cfab8ddSJoseph Koshy 	EV_ALIAS("cycles",		"tsc-tsc"),
6680cfab8ddSJoseph Koshy 	EV_ALIAS("ic-misses",		"iap-icache-misses"),
6690cfab8ddSJoseph Koshy 	EV_ALIAS("instructions",	"iap-instr-ret"),
6700cfab8ddSJoseph Koshy 	EV_ALIAS("interrupts",		"iap-core-hw-int-rx"),
6710cfab8ddSJoseph Koshy 	EV_ALIAS("unhalted-cycles",	"iap-unhalted-core-cycles"),
6720cfab8ddSJoseph Koshy 	EV_ALIAS(NULL, NULL)
6730cfab8ddSJoseph Koshy };
6740cfab8ddSJoseph Koshy 
6750cfab8ddSJoseph Koshy /*
6760cfab8ddSJoseph Koshy  * Intel Core2 (Family 6, Model F), Core2Extreme (Family 6, Model 17H)
6770cfab8ddSJoseph Koshy  * and Atom (Family 6, model 1CH) PMCs.
678791f5d5bSJoseph Koshy  *
679791f5d5bSJoseph Koshy  * We map aliases to events on the fixed-function counters if these
680791f5d5bSJoseph Koshy  * are present.  Note that not all CPUs in this family contain fixed-function
681791f5d5bSJoseph Koshy  * counters.
6820cfab8ddSJoseph Koshy  */
6830cfab8ddSJoseph Koshy 
6840cfab8ddSJoseph Koshy static struct pmc_event_alias core2_aliases[] = {
6850cfab8ddSJoseph Koshy 	EV_ALIAS("branches",		"iap-br-inst-retired.any"),
6860cfab8ddSJoseph Koshy 	EV_ALIAS("branch-mispredicts",	"iap-br-inst-retired.mispred"),
6870cfab8ddSJoseph Koshy 	EV_ALIAS("cycles",		"tsc-tsc"),
6880cfab8ddSJoseph Koshy 	EV_ALIAS("ic-misses",		"iap-l1i-misses"),
6890cfab8ddSJoseph Koshy 	EV_ALIAS("instructions",	"iaf-instr-retired.any"),
6900cfab8ddSJoseph Koshy 	EV_ALIAS("interrupts",		"iap-hw-int-rcv"),
6910cfab8ddSJoseph Koshy 	EV_ALIAS("unhalted-cycles",	"iaf-cpu-clk-unhalted.core"),
6920cfab8ddSJoseph Koshy 	EV_ALIAS(NULL, NULL)
6930cfab8ddSJoseph Koshy };
694791f5d5bSJoseph Koshy 
695791f5d5bSJoseph Koshy static struct pmc_event_alias core2_aliases_without_iaf[] = {
696791f5d5bSJoseph Koshy 	EV_ALIAS("branches",		"iap-br-inst-retired.any"),
697791f5d5bSJoseph Koshy 	EV_ALIAS("branch-mispredicts",	"iap-br-inst-retired.mispred"),
698791f5d5bSJoseph Koshy 	EV_ALIAS("cycles",		"tsc-tsc"),
699791f5d5bSJoseph Koshy 	EV_ALIAS("ic-misses",		"iap-l1i-misses"),
700791f5d5bSJoseph Koshy 	EV_ALIAS("instructions",	"iap-inst-retired.any_p"),
701791f5d5bSJoseph Koshy 	EV_ALIAS("interrupts",		"iap-hw-int-rcv"),
702791f5d5bSJoseph Koshy 	EV_ALIAS("unhalted-cycles",	"iap-cpu-clk-unhalted.core_p"),
703791f5d5bSJoseph Koshy 	EV_ALIAS(NULL, NULL)
704791f5d5bSJoseph Koshy };
705791f5d5bSJoseph Koshy 
7060cfab8ddSJoseph Koshy #define	atom_aliases			core2_aliases
707791f5d5bSJoseph Koshy #define	atom_aliases_without_iaf	core2_aliases_without_iaf
708e8f021a3SHiren Panchasara #define	atom_silvermont_aliases		core2_aliases
709e8f021a3SHiren Panchasara #define	atom_silvermont_aliases_without_iaf	core2_aliases_without_iaf
710597979c4SJeff Roberson #define corei7_aliases			core2_aliases
711791f5d5bSJoseph Koshy #define corei7_aliases_without_iaf	core2_aliases_without_iaf
71249fe48abSKonstantin Belousov #define nehalem_ex_aliases		core2_aliases
71349fe48abSKonstantin Belousov #define nehalem_ex_aliases_without_iaf	core2_aliases_without_iaf
714cc0c1555SSean Bruno #define haswell_aliases			core2_aliases
715cc0c1555SSean Bruno #define haswell_aliases_without_iaf	core2_aliases_without_iaf
716d95b3509SRandall Stewart #define haswell_xeon_aliases			core2_aliases
717d95b3509SRandall Stewart #define haswell_xeon_aliases_without_iaf	core2_aliases_without_iaf
718f19bae41SRandall Stewart #define broadwell_aliases			core2_aliases
719f19bae41SRandall Stewart #define broadwell_aliases_without_iaf	core2_aliases_without_iaf
720f19bae41SRandall Stewart #define broadwell_xeon_aliases			core2_aliases
721f19bae41SRandall Stewart #define broadwell_xeon_aliases_without_iaf	core2_aliases_without_iaf
722f19bae41SRandall Stewart #define skylake_aliases			core2_aliases
723f19bae41SRandall Stewart #define skylake_aliases_without_iaf	core2_aliases_without_iaf
7241e862e5aSFabien Thomas #define ivybridge_aliases		core2_aliases
7251e862e5aSFabien Thomas #define ivybridge_aliases_without_iaf	core2_aliases_without_iaf
7263f929d8cSSean Bruno #define ivybridge_xeon_aliases		core2_aliases
7273f929d8cSSean Bruno #define ivybridge_xeon_aliases_without_iaf	core2_aliases_without_iaf
72878d763a2SDavide Italiano #define sandybridge_aliases		core2_aliases
72978d763a2SDavide Italiano #define sandybridge_aliases_without_iaf	core2_aliases_without_iaf
730fabe02f5SSean Bruno #define sandybridge_xeon_aliases	core2_aliases
731fabe02f5SSean Bruno #define sandybridge_xeon_aliases_without_iaf	core2_aliases_without_iaf
7321fa7f10bSFabien Thomas #define westmere_aliases		core2_aliases
7331fa7f10bSFabien Thomas #define westmere_aliases_without_iaf	core2_aliases_without_iaf
73449fe48abSKonstantin Belousov #define westmere_ex_aliases		core2_aliases
73549fe48abSKonstantin Belousov #define westmere_ex_aliases_without_iaf	core2_aliases_without_iaf
7360cfab8ddSJoseph Koshy 
7370cfab8ddSJoseph Koshy #define	IAF_KW_OS		"os"
7380cfab8ddSJoseph Koshy #define	IAF_KW_USR		"usr"
7390cfab8ddSJoseph Koshy #define	IAF_KW_ANYTHREAD	"anythread"
7400cfab8ddSJoseph Koshy 
7410cfab8ddSJoseph Koshy /*
7420cfab8ddSJoseph Koshy  * Parse an event specifier for Intel fixed function counters.
7430cfab8ddSJoseph Koshy  */
7440cfab8ddSJoseph Koshy static int
7450cfab8ddSJoseph Koshy iaf_allocate_pmc(enum pmc_event pe, char *ctrspec,
7460cfab8ddSJoseph Koshy     struct pmc_op_pmcallocate *pmc_config)
7470cfab8ddSJoseph Koshy {
7480cfab8ddSJoseph Koshy 	char *p;
7490cfab8ddSJoseph Koshy 
7500cfab8ddSJoseph Koshy 	(void) pe;
7510cfab8ddSJoseph Koshy 
7520cfab8ddSJoseph Koshy 	pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE);
7530cfab8ddSJoseph Koshy 	pmc_config->pm_md.pm_iaf.pm_iaf_flags = 0;
7540cfab8ddSJoseph Koshy 
7550cfab8ddSJoseph Koshy 	while ((p = strsep(&ctrspec, ",")) != NULL) {
7560cfab8ddSJoseph Koshy 		if (KWMATCH(p, IAF_KW_OS))
7570cfab8ddSJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_SYSTEM;
7580cfab8ddSJoseph Koshy 		else if (KWMATCH(p, IAF_KW_USR))
7590cfab8ddSJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_USER;
7600cfab8ddSJoseph Koshy 		else if (KWMATCH(p, IAF_KW_ANYTHREAD))
7610cfab8ddSJoseph Koshy 			pmc_config->pm_md.pm_iaf.pm_iaf_flags |= IAF_ANY;
7620cfab8ddSJoseph Koshy 		else
7630cfab8ddSJoseph Koshy 			return (-1);
7640cfab8ddSJoseph Koshy 	}
7650cfab8ddSJoseph Koshy 
7660cfab8ddSJoseph Koshy 	return (0);
7670cfab8ddSJoseph Koshy }
7680cfab8ddSJoseph Koshy 
7690cfab8ddSJoseph Koshy /*
7700cfab8ddSJoseph Koshy  * Core/Core2 support.
7710cfab8ddSJoseph Koshy  */
7720cfab8ddSJoseph Koshy 
7730cfab8ddSJoseph Koshy #define	IAP_KW_AGENT		"agent"
7740cfab8ddSJoseph Koshy #define	IAP_KW_ANYTHREAD	"anythread"
7750cfab8ddSJoseph Koshy #define	IAP_KW_CACHESTATE	"cachestate"
7760cfab8ddSJoseph Koshy #define	IAP_KW_CMASK		"cmask"
7770cfab8ddSJoseph Koshy #define	IAP_KW_CORE		"core"
7780cfab8ddSJoseph Koshy #define	IAP_KW_EDGE		"edge"
7790cfab8ddSJoseph Koshy #define	IAP_KW_INV		"inv"
7800cfab8ddSJoseph Koshy #define	IAP_KW_OS		"os"
7810cfab8ddSJoseph Koshy #define	IAP_KW_PREFETCH		"prefetch"
7820cfab8ddSJoseph Koshy #define	IAP_KW_SNOOPRESPONSE	"snoopresponse"
7830cfab8ddSJoseph Koshy #define	IAP_KW_SNOOPTYPE	"snooptype"
7840cfab8ddSJoseph Koshy #define	IAP_KW_TRANSITION	"trans"
7850cfab8ddSJoseph Koshy #define	IAP_KW_USR		"usr"
7861fa7f10bSFabien Thomas #define	IAP_KW_RSP		"rsp"
7870cfab8ddSJoseph Koshy 
7880cfab8ddSJoseph Koshy static struct pmc_masks iap_core_mask[] = {
7890cfab8ddSJoseph Koshy 	PMCMASK(all,	(0x3 << 14)),
7900cfab8ddSJoseph Koshy 	PMCMASK(this,	(0x1 << 14)),
7910cfab8ddSJoseph Koshy 	NULLMASK
7920cfab8ddSJoseph Koshy };
7930cfab8ddSJoseph Koshy 
7940cfab8ddSJoseph Koshy static struct pmc_masks iap_agent_mask[] = {
7950cfab8ddSJoseph Koshy 	PMCMASK(this,	0),
7960cfab8ddSJoseph Koshy 	PMCMASK(any,	(0x1 << 13)),
7970cfab8ddSJoseph Koshy 	NULLMASK
7980cfab8ddSJoseph Koshy };
7990cfab8ddSJoseph Koshy 
8000cfab8ddSJoseph Koshy static struct pmc_masks iap_prefetch_mask[] = {
8010cfab8ddSJoseph Koshy 	PMCMASK(both,		(0x3 << 12)),
8020cfab8ddSJoseph Koshy 	PMCMASK(only,		(0x1 << 12)),
8030cfab8ddSJoseph Koshy 	PMCMASK(exclude,	0),
8040cfab8ddSJoseph Koshy 	NULLMASK
8050cfab8ddSJoseph Koshy };
8060cfab8ddSJoseph Koshy 
8070cfab8ddSJoseph Koshy static struct pmc_masks iap_cachestate_mask[] = {
8080cfab8ddSJoseph Koshy 	PMCMASK(i,		(1 <<  8)),
8090cfab8ddSJoseph Koshy 	PMCMASK(s,		(1 <<  9)),
8100cfab8ddSJoseph Koshy 	PMCMASK(e,		(1 << 10)),
8110cfab8ddSJoseph Koshy 	PMCMASK(m,		(1 << 11)),
8120cfab8ddSJoseph Koshy 	NULLMASK
8130cfab8ddSJoseph Koshy };
8140cfab8ddSJoseph Koshy 
8150cfab8ddSJoseph Koshy static struct pmc_masks iap_snoopresponse_mask[] = {
8160cfab8ddSJoseph Koshy 	PMCMASK(clean,		(1 << 8)),
8170cfab8ddSJoseph Koshy 	PMCMASK(hit,		(1 << 9)),
8180cfab8ddSJoseph Koshy 	PMCMASK(hitm,		(1 << 11)),
8190cfab8ddSJoseph Koshy 	NULLMASK
8200cfab8ddSJoseph Koshy };
8210cfab8ddSJoseph Koshy 
8220cfab8ddSJoseph Koshy static struct pmc_masks iap_snooptype_mask[] = {
8230cfab8ddSJoseph Koshy 	PMCMASK(cmp2s,		(1 << 8)),
8240cfab8ddSJoseph Koshy 	PMCMASK(cmp2i,		(1 << 9)),
8250cfab8ddSJoseph Koshy 	NULLMASK
8260cfab8ddSJoseph Koshy };
8270cfab8ddSJoseph Koshy 
8280cfab8ddSJoseph Koshy static struct pmc_masks iap_transition_mask[] = {
8290cfab8ddSJoseph Koshy 	PMCMASK(any,		0x00),
8300cfab8ddSJoseph Koshy 	PMCMASK(frequency,	0x10),
8310cfab8ddSJoseph Koshy 	NULLMASK
8320cfab8ddSJoseph Koshy };
8330cfab8ddSJoseph Koshy 
8341e862e5aSFabien Thomas static struct pmc_masks iap_rsp_mask_i7_wm[] = {
8351fa7f10bSFabien Thomas 	PMCMASK(DMND_DATA_RD,		(1 <<  0)),
8361fa7f10bSFabien Thomas 	PMCMASK(DMND_RFO,		(1 <<  1)),
8371fa7f10bSFabien Thomas 	PMCMASK(DMND_IFETCH,		(1 <<  2)),
8381fa7f10bSFabien Thomas 	PMCMASK(WB,			(1 <<  3)),
8391fa7f10bSFabien Thomas 	PMCMASK(PF_DATA_RD,		(1 <<  4)),
8401fa7f10bSFabien Thomas 	PMCMASK(PF_RFO,			(1 <<  5)),
8411fa7f10bSFabien Thomas 	PMCMASK(PF_IFETCH,		(1 <<  6)),
8421fa7f10bSFabien Thomas 	PMCMASK(OTHER,			(1 <<  7)),
8431fa7f10bSFabien Thomas 	PMCMASK(UNCORE_HIT,		(1 <<  8)),
8441fa7f10bSFabien Thomas 	PMCMASK(OTHER_CORE_HIT_SNP,	(1 <<  9)),
8451fa7f10bSFabien Thomas 	PMCMASK(OTHER_CORE_HITM,	(1 << 10)),
8461fa7f10bSFabien Thomas 	PMCMASK(REMOTE_CACHE_FWD,	(1 << 12)),
8471fa7f10bSFabien Thomas 	PMCMASK(REMOTE_DRAM,		(1 << 13)),
8481fa7f10bSFabien Thomas 	PMCMASK(LOCAL_DRAM,		(1 << 14)),
8491fa7f10bSFabien Thomas 	PMCMASK(NON_DRAM,		(1 << 15)),
8501fa7f10bSFabien Thomas 	NULLMASK
8511fa7f10bSFabien Thomas };
8521fa7f10bSFabien Thomas 
853fabe02f5SSean Bruno static struct pmc_masks iap_rsp_mask_sb_sbx_ib[] = {
8541e862e5aSFabien Thomas 	PMCMASK(REQ_DMND_DATA_RD,	(1ULL <<  0)),
8551e862e5aSFabien Thomas 	PMCMASK(REQ_DMND_RFO,		(1ULL <<  1)),
8561e862e5aSFabien Thomas 	PMCMASK(REQ_DMND_IFETCH,	(1ULL <<  2)),
8571e862e5aSFabien Thomas 	PMCMASK(REQ_WB,			(1ULL <<  3)),
8581e862e5aSFabien Thomas 	PMCMASK(REQ_PF_DATA_RD,		(1ULL <<  4)),
8591e862e5aSFabien Thomas 	PMCMASK(REQ_PF_RFO,		(1ULL <<  5)),
8601e862e5aSFabien Thomas 	PMCMASK(REQ_PF_IFETCH,		(1ULL <<  6)),
8611e862e5aSFabien Thomas 	PMCMASK(REQ_PF_LLC_DATA_RD,	(1ULL <<  7)),
8621e862e5aSFabien Thomas 	PMCMASK(REQ_PF_LLC_RFO,		(1ULL <<  8)),
8631e862e5aSFabien Thomas 	PMCMASK(REQ_PF_LLC_IFETCH,	(1ULL <<  9)),
8641e862e5aSFabien Thomas 	PMCMASK(REQ_BUS_LOCKS,		(1ULL << 10)),
8651e862e5aSFabien Thomas 	PMCMASK(REQ_STRM_ST,		(1ULL << 11)),
8661e862e5aSFabien Thomas 	PMCMASK(REQ_OTHER,		(1ULL << 15)),
8671e862e5aSFabien Thomas 	PMCMASK(RES_ANY,		(1ULL << 16)),
8681e862e5aSFabien Thomas 	PMCMASK(RES_SUPPLIER_SUPP,	(1ULL << 17)),
8691e862e5aSFabien Thomas 	PMCMASK(RES_SUPPLIER_LLC_HITM,	(1ULL << 18)),
8701e862e5aSFabien Thomas 	PMCMASK(RES_SUPPLIER_LLC_HITE,	(1ULL << 19)),
8711e862e5aSFabien Thomas 	PMCMASK(RES_SUPPLIER_LLC_HITS,	(1ULL << 20)),
8721e862e5aSFabien Thomas 	PMCMASK(RES_SUPPLIER_LLC_HITF,	(1ULL << 21)),
8731e862e5aSFabien Thomas 	PMCMASK(RES_SUPPLIER_LOCAL,	(1ULL << 22)),
874cdfd0cc8SSean Bruno 	PMCMASK(RES_SNOOP_SNP_NONE,	(1ULL << 31)),
8751e862e5aSFabien Thomas 	PMCMASK(RES_SNOOP_SNP_NO_NEEDED,(1ULL << 32)),
8761e862e5aSFabien Thomas 	PMCMASK(RES_SNOOP_SNP_MISS,	(1ULL << 33)),
8771e862e5aSFabien Thomas 	PMCMASK(RES_SNOOP_HIT_NO_FWD,	(1ULL << 34)),
8781e862e5aSFabien Thomas 	PMCMASK(RES_SNOOP_HIT_FWD,	(1ULL << 35)),
8791e862e5aSFabien Thomas 	PMCMASK(RES_SNOOP_HITM,		(1ULL << 36)),
8801e862e5aSFabien Thomas 	PMCMASK(RES_NON_DRAM,		(1ULL << 37)),
8811e862e5aSFabien Thomas 	NULLMASK
8821e862e5aSFabien Thomas };
8831e862e5aSFabien Thomas 
884f19bae41SRandall Stewart /* Broadwell is defined to use the same mask as Haswell */
885cc0c1555SSean Bruno static struct pmc_masks iap_rsp_mask_haswell[] = {
886cc0c1555SSean Bruno 	PMCMASK(REQ_DMND_DATA_RD,	(1ULL <<  0)),
887cc0c1555SSean Bruno 	PMCMASK(REQ_DMND_RFO,		(1ULL <<  1)),
888cc0c1555SSean Bruno 	PMCMASK(REQ_DMND_IFETCH,	(1ULL <<  2)),
889cc0c1555SSean Bruno 	PMCMASK(REQ_PF_DATA_RD,		(1ULL <<  4)),
890cc0c1555SSean Bruno 	PMCMASK(REQ_PF_RFO,		(1ULL <<  5)),
891cc0c1555SSean Bruno 	PMCMASK(REQ_PF_IFETCH,		(1ULL <<  6)),
892cc0c1555SSean Bruno 	PMCMASK(REQ_OTHER,		(1ULL << 15)),
893cc0c1555SSean Bruno 	PMCMASK(RES_ANY,		(1ULL << 16)),
894cc0c1555SSean Bruno 	PMCMASK(RES_SUPPLIER_SUPP,	(1ULL << 17)),
895cc0c1555SSean Bruno 	PMCMASK(RES_SUPPLIER_LLC_HITM,	(1ULL << 18)),
896cc0c1555SSean Bruno 	PMCMASK(RES_SUPPLIER_LLC_HITE,	(1ULL << 19)),
897cc0c1555SSean Bruno 	PMCMASK(RES_SUPPLIER_LLC_HITS,	(1ULL << 20)),
898cc0c1555SSean Bruno 	PMCMASK(RES_SUPPLIER_LLC_HITF,	(1ULL << 21)),
899cc0c1555SSean Bruno 	PMCMASK(RES_SUPPLIER_LOCAL,	(1ULL << 22)),
900f19bae41SRandall Stewart 	/*
901f19bae41SRandall Stewart 	 * For processor type 06_45H 22 is L4_HIT_LOCAL_L4
902f19bae41SRandall Stewart 	 * and 23, 24 and 25 are also defined.
903f19bae41SRandall Stewart 	 */
904cc0c1555SSean Bruno 	PMCMASK(RES_SNOOP_SNP_NONE,	(1ULL << 31)),
905cc0c1555SSean Bruno 	PMCMASK(RES_SNOOP_SNP_NO_NEEDED,(1ULL << 32)),
906cc0c1555SSean Bruno 	PMCMASK(RES_SNOOP_SNP_MISS,	(1ULL << 33)),
907cc0c1555SSean Bruno 	PMCMASK(RES_SNOOP_HIT_NO_FWD,	(1ULL << 34)),
908cc0c1555SSean Bruno 	PMCMASK(RES_SNOOP_HIT_FWD,	(1ULL << 35)),
909cc0c1555SSean Bruno 	PMCMASK(RES_SNOOP_HITM,		(1ULL << 36)),
910cc0c1555SSean Bruno 	PMCMASK(RES_NON_DRAM,		(1ULL << 37)),
911cc0c1555SSean Bruno 	NULLMASK
912cc0c1555SSean Bruno };
913cc0c1555SSean Bruno 
914f19bae41SRandall Stewart static struct pmc_masks iap_rsp_mask_skylake[] = {
915f19bae41SRandall Stewart 	PMCMASK(REQ_DMND_DATA_RD,	(1ULL <<  0)),
916f19bae41SRandall Stewart 	PMCMASK(REQ_DMND_RFO,		(1ULL <<  1)),
917f19bae41SRandall Stewart 	PMCMASK(REQ_DMND_IFETCH,	(1ULL <<  2)),
918f19bae41SRandall Stewart 	PMCMASK(REQ_PF_DATA_RD,		(1ULL <<  7)),
919f19bae41SRandall Stewart 	PMCMASK(REQ_PF_RFO,		(1ULL <<  8)),
920f19bae41SRandall Stewart 	PMCMASK(REQ_STRM_ST,		(1ULL << 11)),
921f19bae41SRandall Stewart 	PMCMASK(REQ_OTHER,		(1ULL << 15)),
922f19bae41SRandall Stewart 	PMCMASK(RES_ANY,		(1ULL << 16)),
923f19bae41SRandall Stewart 	PMCMASK(RES_SUPPLIER_SUPP,	(1ULL << 17)),
924f19bae41SRandall Stewart 	PMCMASK(RES_SUPPLIER_LLC_HITM,	(1ULL << 18)),
925f19bae41SRandall Stewart 	PMCMASK(RES_SUPPLIER_LLC_HITE,	(1ULL << 19)),
926f19bae41SRandall Stewart 	PMCMASK(RES_SUPPLIER_LLC_HITS,	(1ULL << 20)),
927f19bae41SRandall Stewart 	PMCMASK(RES_SUPPLIER_L4_HIT,	(1ULL << 22)),
928f19bae41SRandall Stewart 	PMCMASK(RES_SUPPLIER_DRAM,	(1ULL << 26)),
929f19bae41SRandall Stewart 	PMCMASK(RES_SUPPLIER_SPL_HIT,	(1ULL << 30)),
930f19bae41SRandall Stewart 	PMCMASK(RES_SNOOP_SNP_NONE,	(1ULL << 31)),
931f19bae41SRandall Stewart 	PMCMASK(RES_SNOOP_SNP_NO_NEEDED,(1ULL << 32)),
932f19bae41SRandall Stewart 	PMCMASK(RES_SNOOP_SNP_MISS,	(1ULL << 33)),
933f19bae41SRandall Stewart 	PMCMASK(RES_SNOOP_HIT_NO_FWD,	(1ULL << 34)),
934f19bae41SRandall Stewart 	PMCMASK(RES_SNOOP_HIT_FWD,	(1ULL << 35)),
935f19bae41SRandall Stewart 	PMCMASK(RES_SNOOP_HITM,		(1ULL << 36)),
936f19bae41SRandall Stewart 	PMCMASK(RES_NON_DRAM,		(1ULL << 37)),
937f19bae41SRandall Stewart 	NULLMASK
938f19bae41SRandall Stewart };
939f19bae41SRandall Stewart 
940f19bae41SRandall Stewart 
9410cfab8ddSJoseph Koshy static int
9420cfab8ddSJoseph Koshy iap_allocate_pmc(enum pmc_event pe, char *ctrspec,
9430cfab8ddSJoseph Koshy     struct pmc_op_pmcallocate *pmc_config)
9440cfab8ddSJoseph Koshy {
9450cfab8ddSJoseph Koshy 	char *e, *p, *q;
9461e862e5aSFabien Thomas 	uint64_t cachestate, evmask, rsp;
9470cfab8ddSJoseph Koshy 	int count, n;
9480cfab8ddSJoseph Koshy 
9490cfab8ddSJoseph Koshy 	pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE |
9500cfab8ddSJoseph Koshy 	    PMC_CAP_QUALIFIER);
9510cfab8ddSJoseph Koshy 	pmc_config->pm_md.pm_iap.pm_iap_config = 0;
9520cfab8ddSJoseph Koshy 
9531fa7f10bSFabien Thomas 	cachestate = evmask = rsp = 0;
9540cfab8ddSJoseph Koshy 
9550cfab8ddSJoseph Koshy 	/* Parse additional modifiers if present */
9560cfab8ddSJoseph Koshy 	while ((p = strsep(&ctrspec, ",")) != NULL) {
9570cfab8ddSJoseph Koshy 
9580cfab8ddSJoseph Koshy 		n = 0;
9590cfab8ddSJoseph Koshy 		if (KWPREFIXMATCH(p, IAP_KW_CMASK "=")) {
9600cfab8ddSJoseph Koshy 			q = strchr(p, '=');
9610cfab8ddSJoseph Koshy 			if (*++q == '\0') /* skip '=' */
9620cfab8ddSJoseph Koshy 				return (-1);
9630cfab8ddSJoseph Koshy 			count = strtol(q, &e, 0);
9640cfab8ddSJoseph Koshy 			if (e == q || *e != '\0')
9650cfab8ddSJoseph Koshy 				return (-1);
9660cfab8ddSJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_THRESHOLD;
9670cfab8ddSJoseph Koshy 			pmc_config->pm_md.pm_iap.pm_iap_config |=
9680cfab8ddSJoseph Koshy 			    IAP_CMASK(count);
9690cfab8ddSJoseph Koshy 		} else if (KWMATCH(p, IAP_KW_EDGE)) {
9700cfab8ddSJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_EDGE;
9710cfab8ddSJoseph Koshy 		} else if (KWMATCH(p, IAP_KW_INV)) {
9720cfab8ddSJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_INVERT;
9730cfab8ddSJoseph Koshy 		} else if (KWMATCH(p, IAP_KW_OS)) {
9740cfab8ddSJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_SYSTEM;
9750cfab8ddSJoseph Koshy 		} else if (KWMATCH(p, IAP_KW_USR)) {
9760cfab8ddSJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_USER;
9770cfab8ddSJoseph Koshy 		} else if (KWMATCH(p, IAP_KW_ANYTHREAD)) {
9780cfab8ddSJoseph Koshy 			pmc_config->pm_md.pm_iap.pm_iap_config |= IAP_ANY;
979b47ea38eSJoseph Koshy 		} else if (KWPREFIXMATCH(p, IAP_KW_CORE "=")) {
9800cfab8ddSJoseph Koshy 			n = pmc_parse_mask(iap_core_mask, p, &evmask);
9810cfab8ddSJoseph Koshy 			if (n != 1)
9820cfab8ddSJoseph Koshy 				return (-1);
983b47ea38eSJoseph Koshy 		} else if (KWPREFIXMATCH(p, IAP_KW_AGENT "=")) {
9840cfab8ddSJoseph Koshy 			n = pmc_parse_mask(iap_agent_mask, p, &evmask);
9850cfab8ddSJoseph Koshy 			if (n != 1)
9860cfab8ddSJoseph Koshy 				return (-1);
987b47ea38eSJoseph Koshy 		} else if (KWPREFIXMATCH(p, IAP_KW_PREFETCH "=")) {
9880cfab8ddSJoseph Koshy 			n = pmc_parse_mask(iap_prefetch_mask, p, &evmask);
9890cfab8ddSJoseph Koshy 			if (n != 1)
9900cfab8ddSJoseph Koshy 				return (-1);
991b47ea38eSJoseph Koshy 		} else if (KWPREFIXMATCH(p, IAP_KW_CACHESTATE "=")) {
9920cfab8ddSJoseph Koshy 			n = pmc_parse_mask(iap_cachestate_mask, p, &cachestate);
9930cfab8ddSJoseph Koshy 		} else if (cpu_info.pm_cputype == PMC_CPU_INTEL_CORE &&
994b47ea38eSJoseph Koshy 		    KWPREFIXMATCH(p, IAP_KW_TRANSITION "=")) {
9950cfab8ddSJoseph Koshy 			n = pmc_parse_mask(iap_transition_mask, p, &evmask);
9960cfab8ddSJoseph Koshy 			if (n != 1)
9970cfab8ddSJoseph Koshy 				return (-1);
9980cfab8ddSJoseph Koshy 		} else if (cpu_info.pm_cputype == PMC_CPU_INTEL_ATOM ||
999e8f021a3SHiren Panchasara 		    cpu_info.pm_cputype == PMC_CPU_INTEL_ATOM_SILVERMONT ||
1000b4d091f3SJoseph Koshy 		    cpu_info.pm_cputype == PMC_CPU_INTEL_CORE2 ||
10011fa7f10bSFabien Thomas 		    cpu_info.pm_cputype == PMC_CPU_INTEL_CORE2EXTREME) {
1002b47ea38eSJoseph Koshy 			if (KWPREFIXMATCH(p, IAP_KW_SNOOPRESPONSE "=")) {
10030cfab8ddSJoseph Koshy 				n = pmc_parse_mask(iap_snoopresponse_mask, p,
10040cfab8ddSJoseph Koshy 				    &evmask);
1005b47ea38eSJoseph Koshy 			} else if (KWPREFIXMATCH(p, IAP_KW_SNOOPTYPE "=")) {
10060cfab8ddSJoseph Koshy 				n = pmc_parse_mask(iap_snooptype_mask, p,
10070cfab8ddSJoseph Koshy 				    &evmask);
10080cfab8ddSJoseph Koshy 			} else
10090cfab8ddSJoseph Koshy 				return (-1);
10101fa7f10bSFabien Thomas 		} else if (cpu_info.pm_cputype == PMC_CPU_INTEL_COREI7 ||
101149fe48abSKonstantin Belousov 		    cpu_info.pm_cputype == PMC_CPU_INTEL_WESTMERE ||
101249fe48abSKonstantin Belousov 		    cpu_info.pm_cputype == PMC_CPU_INTEL_NEHALEM_EX ||
101349fe48abSKonstantin Belousov 		    cpu_info.pm_cputype == PMC_CPU_INTEL_WESTMERE_EX) {
10141fa7f10bSFabien Thomas 			if (KWPREFIXMATCH(p, IAP_KW_RSP "=")) {
10151e862e5aSFabien Thomas 				n = pmc_parse_mask(iap_rsp_mask_i7_wm, p, &rsp);
10161e862e5aSFabien Thomas 			} else
10171e862e5aSFabien Thomas 				return (-1);
10181e862e5aSFabien Thomas 		} else if (cpu_info.pm_cputype == PMC_CPU_INTEL_SANDYBRIDGE ||
1019fabe02f5SSean Bruno 		    cpu_info.pm_cputype == PMC_CPU_INTEL_SANDYBRIDGE_XEON ||
10203f929d8cSSean Bruno 			cpu_info.pm_cputype == PMC_CPU_INTEL_IVYBRIDGE ||
10213f929d8cSSean Bruno 			cpu_info.pm_cputype == PMC_CPU_INTEL_IVYBRIDGE_XEON ) {
10221e862e5aSFabien Thomas 			if (KWPREFIXMATCH(p, IAP_KW_RSP "=")) {
1023fabe02f5SSean Bruno 				n = pmc_parse_mask(iap_rsp_mask_sb_sbx_ib, p, &rsp);
10241fa7f10bSFabien Thomas 			} else
10251fa7f10bSFabien Thomas 				return (-1);
1026d95b3509SRandall Stewart 		} else if (cpu_info.pm_cputype == PMC_CPU_INTEL_HASWELL ||
1027d95b3509SRandall Stewart 			cpu_info.pm_cputype == PMC_CPU_INTEL_HASWELL_XEON) {
1028cc0c1555SSean Bruno 			if (KWPREFIXMATCH(p, IAP_KW_RSP "=")) {
1029cc0c1555SSean Bruno 				n = pmc_parse_mask(iap_rsp_mask_haswell, p, &rsp);
1030cc0c1555SSean Bruno 			} else
1031cc0c1555SSean Bruno 				return (-1);
1032f19bae41SRandall Stewart 		} else if (cpu_info.pm_cputype == PMC_CPU_INTEL_BROADWELL ||
1033f19bae41SRandall Stewart 			cpu_info.pm_cputype == PMC_CPU_INTEL_BROADWELL_XEON) {
1034f19bae41SRandall Stewart 			/* Broadwell is defined to use same mask as haswell */
1035f19bae41SRandall Stewart 			if (KWPREFIXMATCH(p, IAP_KW_RSP "=")) {
1036f19bae41SRandall Stewart 				n = pmc_parse_mask(iap_rsp_mask_haswell, p, &rsp);
1037f19bae41SRandall Stewart 			} else
1038f19bae41SRandall Stewart 				return (-1);
1039f19bae41SRandall Stewart 
1040f19bae41SRandall Stewart 		} else if (cpu_info.pm_cputype == PMC_CPU_INTEL_SKYLAKE) {
1041f19bae41SRandall Stewart 			if (KWPREFIXMATCH(p, IAP_KW_RSP "=")) {
1042f19bae41SRandall Stewart 				n = pmc_parse_mask(iap_rsp_mask_skylake, p, &rsp);
1043f19bae41SRandall Stewart 			} else
1044f19bae41SRandall Stewart 				return (-1);
1045f19bae41SRandall Stewart 
10460cfab8ddSJoseph Koshy 		} else
10470cfab8ddSJoseph Koshy 			return (-1);
10480cfab8ddSJoseph Koshy 
10490cfab8ddSJoseph Koshy 		if (n < 0)	/* Parsing failed. */
10500cfab8ddSJoseph Koshy 			return (-1);
10510cfab8ddSJoseph Koshy 	}
10520cfab8ddSJoseph Koshy 
10530cfab8ddSJoseph Koshy 	pmc_config->pm_md.pm_iap.pm_iap_config |= evmask;
10540cfab8ddSJoseph Koshy 
10550cfab8ddSJoseph Koshy 	/*
10560cfab8ddSJoseph Koshy 	 * If the event requires a 'cachestate' qualifier but was not
10570cfab8ddSJoseph Koshy 	 * specified by the user, use a sensible default.
10580cfab8ddSJoseph Koshy 	 */
10590cfab8ddSJoseph Koshy 	switch (pe) {
10600cfab8ddSJoseph Koshy 	case PMC_EV_IAP_EVENT_28H: /* Core, Core2, Atom */
10610cfab8ddSJoseph Koshy 	case PMC_EV_IAP_EVENT_29H: /* Core, Core2, Atom */
10620cfab8ddSJoseph Koshy 	case PMC_EV_IAP_EVENT_2AH: /* Core, Core2, Atom */
10630cfab8ddSJoseph Koshy 	case PMC_EV_IAP_EVENT_2BH: /* Atom, Core2 */
10640cfab8ddSJoseph Koshy 	case PMC_EV_IAP_EVENT_2EH: /* Core, Core2, Atom */
10650cfab8ddSJoseph Koshy 	case PMC_EV_IAP_EVENT_30H: /* Core, Core2, Atom */
10660cfab8ddSJoseph Koshy 	case PMC_EV_IAP_EVENT_32H: /* Core */
10670cfab8ddSJoseph Koshy 	case PMC_EV_IAP_EVENT_40H: /* Core */
10680cfab8ddSJoseph Koshy 	case PMC_EV_IAP_EVENT_41H: /* Core */
10690cfab8ddSJoseph Koshy 	case PMC_EV_IAP_EVENT_42H: /* Core, Core2, Atom */
10700cfab8ddSJoseph Koshy 		if (cachestate == 0)
10710cfab8ddSJoseph Koshy 			cachestate = (0xF << 8);
1072aa1b887bSRyan Stone 		break;
1073aa1b887bSRyan Stone 	case PMC_EV_IAP_EVENT_77H: /* Atom */
1074aa1b887bSRyan Stone 		/* IAP_EVENT_77H only accepts a cachestate qualifier on the
1075aa1b887bSRyan Stone 		 * Atom processor
1076aa1b887bSRyan Stone 		 */
1077aa1b887bSRyan Stone 		if(cpu_info.pm_cputype == PMC_CPU_INTEL_ATOM && cachestate == 0)
1078aa1b887bSRyan Stone 			cachestate = (0xF << 8);
1079aa1b887bSRyan Stone 	    break;
10800cfab8ddSJoseph Koshy 	default:
10810cfab8ddSJoseph Koshy 		break;
10820cfab8ddSJoseph Koshy 	}
10830cfab8ddSJoseph Koshy 
10840cfab8ddSJoseph Koshy 	pmc_config->pm_md.pm_iap.pm_iap_config |= cachestate;
10851fa7f10bSFabien Thomas 	pmc_config->pm_md.pm_iap.pm_iap_rsp = rsp;
10861fa7f10bSFabien Thomas 
10871fa7f10bSFabien Thomas 	return (0);
10881fa7f10bSFabien Thomas }
10891fa7f10bSFabien Thomas 
10901fa7f10bSFabien Thomas /*
10911fa7f10bSFabien Thomas  * Intel Uncore.
10921fa7f10bSFabien Thomas  */
10931fa7f10bSFabien Thomas 
10941fa7f10bSFabien Thomas static int
10951fa7f10bSFabien Thomas ucf_allocate_pmc(enum pmc_event pe, char *ctrspec,
10961fa7f10bSFabien Thomas     struct pmc_op_pmcallocate *pmc_config)
10971fa7f10bSFabien Thomas {
10981fa7f10bSFabien Thomas 	(void) pe;
10991fa7f10bSFabien Thomas 	(void) ctrspec;
11001fa7f10bSFabien Thomas 
11011fa7f10bSFabien Thomas 	pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE);
11021fa7f10bSFabien Thomas 	pmc_config->pm_md.pm_ucf.pm_ucf_flags = 0;
11031fa7f10bSFabien Thomas 
11041fa7f10bSFabien Thomas 	return (0);
11051fa7f10bSFabien Thomas }
11061fa7f10bSFabien Thomas 
11071fa7f10bSFabien Thomas #define	UCP_KW_CMASK		"cmask"
11081fa7f10bSFabien Thomas #define	UCP_KW_EDGE		"edge"
11091fa7f10bSFabien Thomas #define	UCP_KW_INV		"inv"
11101fa7f10bSFabien Thomas 
11111fa7f10bSFabien Thomas static int
11121fa7f10bSFabien Thomas ucp_allocate_pmc(enum pmc_event pe, char *ctrspec,
11131fa7f10bSFabien Thomas     struct pmc_op_pmcallocate *pmc_config)
11141fa7f10bSFabien Thomas {
11151fa7f10bSFabien Thomas 	char *e, *p, *q;
11161fa7f10bSFabien Thomas 	int count, n;
11171fa7f10bSFabien Thomas 
11181fa7f10bSFabien Thomas 	(void) pe;
11191fa7f10bSFabien Thomas 
11201fa7f10bSFabien Thomas 	pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE |
11211fa7f10bSFabien Thomas 	    PMC_CAP_QUALIFIER);
11221fa7f10bSFabien Thomas 	pmc_config->pm_md.pm_ucp.pm_ucp_config = 0;
11231fa7f10bSFabien Thomas 
11241fa7f10bSFabien Thomas 	/* Parse additional modifiers if present */
11251fa7f10bSFabien Thomas 	while ((p = strsep(&ctrspec, ",")) != NULL) {
11261fa7f10bSFabien Thomas 
11271fa7f10bSFabien Thomas 		n = 0;
11281fa7f10bSFabien Thomas 		if (KWPREFIXMATCH(p, UCP_KW_CMASK "=")) {
11291fa7f10bSFabien Thomas 			q = strchr(p, '=');
11301fa7f10bSFabien Thomas 			if (*++q == '\0') /* skip '=' */
11311fa7f10bSFabien Thomas 				return (-1);
11321fa7f10bSFabien Thomas 			count = strtol(q, &e, 0);
11331fa7f10bSFabien Thomas 			if (e == q || *e != '\0')
11341fa7f10bSFabien Thomas 				return (-1);
11351fa7f10bSFabien Thomas 			pmc_config->pm_caps |= PMC_CAP_THRESHOLD;
11361fa7f10bSFabien Thomas 			pmc_config->pm_md.pm_ucp.pm_ucp_config |=
11371fa7f10bSFabien Thomas 			    UCP_CMASK(count);
11381fa7f10bSFabien Thomas 		} else if (KWMATCH(p, UCP_KW_EDGE)) {
11391fa7f10bSFabien Thomas 			pmc_config->pm_caps |= PMC_CAP_EDGE;
11401fa7f10bSFabien Thomas 		} else if (KWMATCH(p, UCP_KW_INV)) {
11411fa7f10bSFabien Thomas 			pmc_config->pm_caps |= PMC_CAP_INVERT;
11421fa7f10bSFabien Thomas 		} else
11431fa7f10bSFabien Thomas 			return (-1);
11441fa7f10bSFabien Thomas 
11451fa7f10bSFabien Thomas 		if (n < 0)	/* Parsing failed. */
11461fa7f10bSFabien Thomas 			return (-1);
11471fa7f10bSFabien Thomas 	}
11480cfab8ddSJoseph Koshy 
11490cfab8ddSJoseph Koshy 	return (0);
11500cfab8ddSJoseph Koshy }
11510cfab8ddSJoseph Koshy 
11520cfab8ddSJoseph Koshy /*
1153f263522aSJoseph Koshy  * AMD K8 PMCs.
1154f263522aSJoseph Koshy  *
1155f263522aSJoseph Koshy  * These are very similar to AMD K7 PMCs, but support more kinds of
1156f263522aSJoseph Koshy  * events.
1157f263522aSJoseph Koshy  */
1158f263522aSJoseph Koshy 
1159f263522aSJoseph Koshy static struct pmc_event_alias k8_aliases[] = {
1160f263522aSJoseph Koshy 	EV_ALIAS("branches",		"k8-fr-retired-taken-branches"),
1161f263522aSJoseph Koshy 	EV_ALIAS("branch-mispredicts",
1162f263522aSJoseph Koshy 	    "k8-fr-retired-taken-branches-mispredicted"),
1163f263522aSJoseph Koshy 	EV_ALIAS("cycles",		"tsc"),
1164f263522aSJoseph Koshy 	EV_ALIAS("dc-misses",		"k8-dc-miss"),
1165f263522aSJoseph Koshy 	EV_ALIAS("ic-misses",		"k8-ic-miss"),
1166f263522aSJoseph Koshy 	EV_ALIAS("instructions",	"k8-fr-retired-x86-instructions"),
1167f263522aSJoseph Koshy 	EV_ALIAS("interrupts",		"k8-fr-taken-hardware-interrupts"),
1168177a2f22SJoseph Koshy 	EV_ALIAS("unhalted-cycles",	"k8-bu-cpu-clk-unhalted"),
1169f263522aSJoseph Koshy 	EV_ALIAS(NULL, NULL)
1170f263522aSJoseph Koshy };
1171f263522aSJoseph Koshy 
1172f263522aSJoseph Koshy #define	__K8MASK(N,V) PMCMASK(N,(1 << (V)))
1173f263522aSJoseph Koshy 
1174f263522aSJoseph Koshy /*
1175f263522aSJoseph Koshy  * Parsing tables
1176f263522aSJoseph Koshy  */
1177f263522aSJoseph Koshy 
1178f263522aSJoseph Koshy /* fp dispatched fpu ops */
1179f263522aSJoseph Koshy static const struct pmc_masks k8_mask_fdfo[] = {
1180f263522aSJoseph Koshy 	__K8MASK(add-pipe-excluding-junk-ops,	0),
1181f263522aSJoseph Koshy 	__K8MASK(multiply-pipe-excluding-junk-ops,	1),
1182f263522aSJoseph Koshy 	__K8MASK(store-pipe-excluding-junk-ops,	2),
1183f263522aSJoseph Koshy 	__K8MASK(add-pipe-junk-ops,		3),
1184f263522aSJoseph Koshy 	__K8MASK(multiply-pipe-junk-ops,	4),
1185f263522aSJoseph Koshy 	__K8MASK(store-pipe-junk-ops,		5),
1186f263522aSJoseph Koshy 	NULLMASK
1187f263522aSJoseph Koshy };
1188f263522aSJoseph Koshy 
1189f263522aSJoseph Koshy /* ls segment register loads */
1190f263522aSJoseph Koshy static const struct pmc_masks k8_mask_lsrl[] = {
1191f263522aSJoseph Koshy 	__K8MASK(es,	0),
1192f263522aSJoseph Koshy 	__K8MASK(cs,	1),
1193f263522aSJoseph Koshy 	__K8MASK(ss,	2),
1194f263522aSJoseph Koshy 	__K8MASK(ds,	3),
1195f263522aSJoseph Koshy 	__K8MASK(fs,	4),
1196f263522aSJoseph Koshy 	__K8MASK(gs,	5),
1197f263522aSJoseph Koshy 	__K8MASK(hs,	6),
1198f263522aSJoseph Koshy 	NULLMASK
1199f263522aSJoseph Koshy };
1200f263522aSJoseph Koshy 
1201f263522aSJoseph Koshy /* ls locked operation */
1202f263522aSJoseph Koshy static const struct pmc_masks k8_mask_llo[] = {
1203f263522aSJoseph Koshy 	__K8MASK(locked-instructions,	0),
1204f263522aSJoseph Koshy 	__K8MASK(cycles-in-request,	1),
1205f263522aSJoseph Koshy 	__K8MASK(cycles-to-complete,	2),
1206f263522aSJoseph Koshy 	NULLMASK
1207f263522aSJoseph Koshy };
1208f263522aSJoseph Koshy 
1209f263522aSJoseph Koshy /* dc refill from {l2,system} and dc copyback */
1210f263522aSJoseph Koshy static const struct pmc_masks k8_mask_dc[] = {
1211f263522aSJoseph Koshy 	__K8MASK(invalid,	0),
1212f263522aSJoseph Koshy 	__K8MASK(shared,	1),
1213f263522aSJoseph Koshy 	__K8MASK(exclusive,	2),
1214f263522aSJoseph Koshy 	__K8MASK(owner,		3),
1215f263522aSJoseph Koshy 	__K8MASK(modified,	4),
1216f263522aSJoseph Koshy 	NULLMASK
1217f263522aSJoseph Koshy };
1218f263522aSJoseph Koshy 
1219f263522aSJoseph Koshy /* dc one bit ecc error */
1220f263522aSJoseph Koshy static const struct pmc_masks k8_mask_dobee[] = {
1221f263522aSJoseph Koshy 	__K8MASK(scrubber,	0),
1222f263522aSJoseph Koshy 	__K8MASK(piggyback,	1),
1223f263522aSJoseph Koshy 	NULLMASK
1224f263522aSJoseph Koshy };
1225f263522aSJoseph Koshy 
1226f263522aSJoseph Koshy /* dc dispatched prefetch instructions */
1227f263522aSJoseph Koshy static const struct pmc_masks k8_mask_ddpi[] = {
1228f263522aSJoseph Koshy 	__K8MASK(load,	0),
1229f263522aSJoseph Koshy 	__K8MASK(store,	1),
1230f263522aSJoseph Koshy 	__K8MASK(nta,	2),
1231f263522aSJoseph Koshy 	NULLMASK
1232f263522aSJoseph Koshy };
1233f263522aSJoseph Koshy 
1234f263522aSJoseph Koshy /* dc dcache accesses by locks */
1235f263522aSJoseph Koshy static const struct pmc_masks k8_mask_dabl[] = {
1236f263522aSJoseph Koshy 	__K8MASK(accesses,	0),
1237f263522aSJoseph Koshy 	__K8MASK(misses,	1),
1238f263522aSJoseph Koshy 	NULLMASK
1239f263522aSJoseph Koshy };
1240f263522aSJoseph Koshy 
1241f263522aSJoseph Koshy /* bu internal l2 request */
1242f263522aSJoseph Koshy static const struct pmc_masks k8_mask_bilr[] = {
1243f263522aSJoseph Koshy 	__K8MASK(ic-fill,	0),
1244f263522aSJoseph Koshy 	__K8MASK(dc-fill,	1),
1245f263522aSJoseph Koshy 	__K8MASK(tlb-reload,	2),
1246f263522aSJoseph Koshy 	__K8MASK(tag-snoop,	3),
1247f263522aSJoseph Koshy 	__K8MASK(cancelled,	4),
1248f263522aSJoseph Koshy 	NULLMASK
1249f263522aSJoseph Koshy };
1250f263522aSJoseph Koshy 
1251f263522aSJoseph Koshy /* bu fill request l2 miss */
1252f263522aSJoseph Koshy static const struct pmc_masks k8_mask_bfrlm[] = {
1253f263522aSJoseph Koshy 	__K8MASK(ic-fill,	0),
1254f263522aSJoseph Koshy 	__K8MASK(dc-fill,	1),
1255f263522aSJoseph Koshy 	__K8MASK(tlb-reload,	2),
1256f263522aSJoseph Koshy 	NULLMASK
1257f263522aSJoseph Koshy };
1258f263522aSJoseph Koshy 
1259f263522aSJoseph Koshy /* bu fill into l2 */
1260f263522aSJoseph Koshy static const struct pmc_masks k8_mask_bfil[] = {
1261f263522aSJoseph Koshy 	__K8MASK(dirty-l2-victim,	0),
1262f263522aSJoseph Koshy 	__K8MASK(victim-from-l2,	1),
1263f263522aSJoseph Koshy 	NULLMASK
1264f263522aSJoseph Koshy };
1265f263522aSJoseph Koshy 
1266f263522aSJoseph Koshy /* fr retired fpu instructions */
1267f263522aSJoseph Koshy static const struct pmc_masks k8_mask_frfi[] = {
1268f263522aSJoseph Koshy 	__K8MASK(x87,			0),
1269f263522aSJoseph Koshy 	__K8MASK(mmx-3dnow,		1),
1270f263522aSJoseph Koshy 	__K8MASK(packed-sse-sse2,	2),
1271f263522aSJoseph Koshy 	__K8MASK(scalar-sse-sse2,	3),
1272f263522aSJoseph Koshy 	NULLMASK
1273f263522aSJoseph Koshy };
1274f263522aSJoseph Koshy 
1275f263522aSJoseph Koshy /* fr retired fastpath double op instructions */
1276f263522aSJoseph Koshy static const struct pmc_masks k8_mask_frfdoi[] = {
1277f263522aSJoseph Koshy 	__K8MASK(low-op-pos-0,		0),
1278f263522aSJoseph Koshy 	__K8MASK(low-op-pos-1,		1),
1279f263522aSJoseph Koshy 	__K8MASK(low-op-pos-2,		2),
1280f263522aSJoseph Koshy 	NULLMASK
1281f263522aSJoseph Koshy };
1282f263522aSJoseph Koshy 
1283f263522aSJoseph Koshy /* fr fpu exceptions */
1284f263522aSJoseph Koshy static const struct pmc_masks k8_mask_ffe[] = {
1285f263522aSJoseph Koshy 	__K8MASK(x87-reclass-microfaults,	0),
1286f263522aSJoseph Koshy 	__K8MASK(sse-retype-microfaults,	1),
1287f263522aSJoseph Koshy 	__K8MASK(sse-reclass-microfaults,	2),
1288f263522aSJoseph Koshy 	__K8MASK(sse-and-x87-microtraps,	3),
1289f263522aSJoseph Koshy 	NULLMASK
1290f263522aSJoseph Koshy };
1291f263522aSJoseph Koshy 
1292f263522aSJoseph Koshy /* nb memory controller page access event */
1293f263522aSJoseph Koshy static const struct pmc_masks k8_mask_nmcpae[] = {
1294f263522aSJoseph Koshy 	__K8MASK(page-hit,	0),
1295f263522aSJoseph Koshy 	__K8MASK(page-miss,	1),
1296f263522aSJoseph Koshy 	__K8MASK(page-conflict,	2),
1297f263522aSJoseph Koshy 	NULLMASK
1298f263522aSJoseph Koshy };
1299f263522aSJoseph Koshy 
1300f263522aSJoseph Koshy /* nb memory controller turnaround */
1301f263522aSJoseph Koshy static const struct pmc_masks k8_mask_nmct[] = {
1302f263522aSJoseph Koshy 	__K8MASK(dimm-turnaround,		0),
1303f263522aSJoseph Koshy 	__K8MASK(read-to-write-turnaround,	1),
1304f263522aSJoseph Koshy 	__K8MASK(write-to-read-turnaround,	2),
1305f263522aSJoseph Koshy 	NULLMASK
1306f263522aSJoseph Koshy };
1307f263522aSJoseph Koshy 
1308f263522aSJoseph Koshy /* nb memory controller bypass saturation */
1309f263522aSJoseph Koshy static const struct pmc_masks k8_mask_nmcbs[] = {
1310f263522aSJoseph Koshy 	__K8MASK(memory-controller-hi-pri-bypass,	0),
1311f263522aSJoseph Koshy 	__K8MASK(memory-controller-lo-pri-bypass,	1),
1312f263522aSJoseph Koshy 	__K8MASK(dram-controller-interface-bypass,	2),
1313f263522aSJoseph Koshy 	__K8MASK(dram-controller-queue-bypass,		3),
1314f263522aSJoseph Koshy 	NULLMASK
1315f263522aSJoseph Koshy };
1316f263522aSJoseph Koshy 
1317f263522aSJoseph Koshy /* nb sized commands */
1318f263522aSJoseph Koshy static const struct pmc_masks k8_mask_nsc[] = {
1319f263522aSJoseph Koshy 	__K8MASK(nonpostwrszbyte,	0),
1320f263522aSJoseph Koshy 	__K8MASK(nonpostwrszdword,	1),
1321f263522aSJoseph Koshy 	__K8MASK(postwrszbyte,		2),
1322f263522aSJoseph Koshy 	__K8MASK(postwrszdword,		3),
1323f263522aSJoseph Koshy 	__K8MASK(rdszbyte,		4),
1324f263522aSJoseph Koshy 	__K8MASK(rdszdword,		5),
1325f263522aSJoseph Koshy 	__K8MASK(rdmodwr,		6),
1326f263522aSJoseph Koshy 	NULLMASK
1327f263522aSJoseph Koshy };
1328f263522aSJoseph Koshy 
1329f263522aSJoseph Koshy /* nb probe result */
1330f263522aSJoseph Koshy static const struct pmc_masks k8_mask_npr[] = {
1331f263522aSJoseph Koshy 	__K8MASK(probe-miss,		0),
1332f263522aSJoseph Koshy 	__K8MASK(probe-hit,		1),
1333f263522aSJoseph Koshy 	__K8MASK(probe-hit-dirty-no-memory-cancel, 2),
1334f263522aSJoseph Koshy 	__K8MASK(probe-hit-dirty-with-memory-cancel, 3),
1335f263522aSJoseph Koshy 	NULLMASK
1336f263522aSJoseph Koshy };
1337f263522aSJoseph Koshy 
1338f263522aSJoseph Koshy /* nb hypertransport bus bandwidth */
1339f263522aSJoseph Koshy static const struct pmc_masks k8_mask_nhbb[] = { /* HT bus bandwidth */
1340f263522aSJoseph Koshy 	__K8MASK(command,	0),
1341f263522aSJoseph Koshy 	__K8MASK(data,	1),
1342f263522aSJoseph Koshy 	__K8MASK(buffer-release, 2),
1343f263522aSJoseph Koshy 	__K8MASK(nop,	3),
1344f263522aSJoseph Koshy 	NULLMASK
1345f263522aSJoseph Koshy };
1346f263522aSJoseph Koshy 
1347f263522aSJoseph Koshy #undef	__K8MASK
1348f263522aSJoseph Koshy 
1349f263522aSJoseph Koshy #define	K8_KW_COUNT	"count"
1350f263522aSJoseph Koshy #define	K8_KW_EDGE	"edge"
1351f263522aSJoseph Koshy #define	K8_KW_INV	"inv"
1352f263522aSJoseph Koshy #define	K8_KW_MASK	"mask"
1353f263522aSJoseph Koshy #define	K8_KW_OS	"os"
1354f263522aSJoseph Koshy #define	K8_KW_USR	"usr"
1355f263522aSJoseph Koshy 
1356f263522aSJoseph Koshy static int
1357f263522aSJoseph Koshy k8_allocate_pmc(enum pmc_event pe, char *ctrspec,
1358f263522aSJoseph Koshy     struct pmc_op_pmcallocate *pmc_config)
1359f263522aSJoseph Koshy {
1360f263522aSJoseph Koshy 	char		*e, *p, *q;
1361f263522aSJoseph Koshy 	int		n;
13621e862e5aSFabien Thomas 	uint32_t	count;
13631e862e5aSFabien Thomas 	uint64_t	evmask;
1364f263522aSJoseph Koshy 	const struct pmc_masks	*pm, *pmask;
1365f263522aSJoseph Koshy 
1366789140c0SJoseph Koshy 	pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE);
1367f263522aSJoseph Koshy 	pmc_config->pm_md.pm_amd.pm_amd_config = 0;
1368f263522aSJoseph Koshy 
1369f263522aSJoseph Koshy 	pmask = NULL;
1370f263522aSJoseph Koshy 	evmask = 0;
1371f263522aSJoseph Koshy 
1372f263522aSJoseph Koshy #define	__K8SETMASK(M) pmask = k8_mask_##M
1373f263522aSJoseph Koshy 
1374f263522aSJoseph Koshy 	/* setup parsing tables */
1375f263522aSJoseph Koshy 	switch (pe) {
1376f263522aSJoseph Koshy 	case PMC_EV_K8_FP_DISPATCHED_FPU_OPS:
1377f263522aSJoseph Koshy 		__K8SETMASK(fdfo);
1378f263522aSJoseph Koshy 		break;
1379f263522aSJoseph Koshy 	case PMC_EV_K8_LS_SEGMENT_REGISTER_LOAD:
1380f263522aSJoseph Koshy 		__K8SETMASK(lsrl);
1381f263522aSJoseph Koshy 		break;
1382f263522aSJoseph Koshy 	case PMC_EV_K8_LS_LOCKED_OPERATION:
1383f263522aSJoseph Koshy 		__K8SETMASK(llo);
1384f263522aSJoseph Koshy 		break;
1385f263522aSJoseph Koshy 	case PMC_EV_K8_DC_REFILL_FROM_L2:
1386f263522aSJoseph Koshy 	case PMC_EV_K8_DC_REFILL_FROM_SYSTEM:
1387f263522aSJoseph Koshy 	case PMC_EV_K8_DC_COPYBACK:
1388f263522aSJoseph Koshy 		__K8SETMASK(dc);
1389f263522aSJoseph Koshy 		break;
1390f263522aSJoseph Koshy 	case PMC_EV_K8_DC_ONE_BIT_ECC_ERROR:
1391f263522aSJoseph Koshy 		__K8SETMASK(dobee);
1392f263522aSJoseph Koshy 		break;
1393f263522aSJoseph Koshy 	case PMC_EV_K8_DC_DISPATCHED_PREFETCH_INSTRUCTIONS:
1394f263522aSJoseph Koshy 		__K8SETMASK(ddpi);
1395f263522aSJoseph Koshy 		break;
1396f263522aSJoseph Koshy 	case PMC_EV_K8_DC_DCACHE_ACCESSES_BY_LOCKS:
1397f263522aSJoseph Koshy 		__K8SETMASK(dabl);
1398f263522aSJoseph Koshy 		break;
1399f263522aSJoseph Koshy 	case PMC_EV_K8_BU_INTERNAL_L2_REQUEST:
1400f263522aSJoseph Koshy 		__K8SETMASK(bilr);
1401f263522aSJoseph Koshy 		break;
1402f263522aSJoseph Koshy 	case PMC_EV_K8_BU_FILL_REQUEST_L2_MISS:
1403f263522aSJoseph Koshy 		__K8SETMASK(bfrlm);
1404f263522aSJoseph Koshy 		break;
1405f263522aSJoseph Koshy 	case PMC_EV_K8_BU_FILL_INTO_L2:
1406f263522aSJoseph Koshy 		__K8SETMASK(bfil);
1407f263522aSJoseph Koshy 		break;
1408f263522aSJoseph Koshy 	case PMC_EV_K8_FR_RETIRED_FPU_INSTRUCTIONS:
1409f263522aSJoseph Koshy 		__K8SETMASK(frfi);
1410f263522aSJoseph Koshy 		break;
1411f263522aSJoseph Koshy 	case PMC_EV_K8_FR_RETIRED_FASTPATH_DOUBLE_OP_INSTRUCTIONS:
1412f263522aSJoseph Koshy 		__K8SETMASK(frfdoi);
1413f263522aSJoseph Koshy 		break;
1414f263522aSJoseph Koshy 	case PMC_EV_K8_FR_FPU_EXCEPTIONS:
1415f263522aSJoseph Koshy 		__K8SETMASK(ffe);
1416f263522aSJoseph Koshy 		break;
1417f263522aSJoseph Koshy 	case PMC_EV_K8_NB_MEMORY_CONTROLLER_PAGE_ACCESS_EVENT:
1418f263522aSJoseph Koshy 		__K8SETMASK(nmcpae);
1419f263522aSJoseph Koshy 		break;
1420f263522aSJoseph Koshy 	case PMC_EV_K8_NB_MEMORY_CONTROLLER_TURNAROUND:
1421f263522aSJoseph Koshy 		__K8SETMASK(nmct);
1422f263522aSJoseph Koshy 		break;
1423f263522aSJoseph Koshy 	case PMC_EV_K8_NB_MEMORY_CONTROLLER_BYPASS_SATURATION:
1424f263522aSJoseph Koshy 		__K8SETMASK(nmcbs);
1425f263522aSJoseph Koshy 		break;
1426f263522aSJoseph Koshy 	case PMC_EV_K8_NB_SIZED_COMMANDS:
1427f263522aSJoseph Koshy 		__K8SETMASK(nsc);
1428f263522aSJoseph Koshy 		break;
1429f263522aSJoseph Koshy 	case PMC_EV_K8_NB_PROBE_RESULT:
1430f263522aSJoseph Koshy 		__K8SETMASK(npr);
1431f263522aSJoseph Koshy 		break;
1432f263522aSJoseph Koshy 	case PMC_EV_K8_NB_HT_BUS0_BANDWIDTH:
1433f263522aSJoseph Koshy 	case PMC_EV_K8_NB_HT_BUS1_BANDWIDTH:
1434f263522aSJoseph Koshy 	case PMC_EV_K8_NB_HT_BUS2_BANDWIDTH:
1435f263522aSJoseph Koshy 		__K8SETMASK(nhbb);
1436f263522aSJoseph Koshy 		break;
1437f263522aSJoseph Koshy 
1438f263522aSJoseph Koshy 	default:
1439f263522aSJoseph Koshy 		break;		/* no options defined */
1440f263522aSJoseph Koshy 	}
1441f263522aSJoseph Koshy 
1442f263522aSJoseph Koshy 	while ((p = strsep(&ctrspec, ",")) != NULL) {
1443f263522aSJoseph Koshy 		if (KWPREFIXMATCH(p, K8_KW_COUNT "=")) {
1444f263522aSJoseph Koshy 			q = strchr(p, '=');
1445f263522aSJoseph Koshy 			if (*++q == '\0') /* skip '=' */
1446aa342b1fSJoseph Koshy 				return (-1);
1447f263522aSJoseph Koshy 
1448f263522aSJoseph Koshy 			count = strtol(q, &e, 0);
1449f263522aSJoseph Koshy 			if (e == q || *e != '\0')
1450aa342b1fSJoseph Koshy 				return (-1);
1451f263522aSJoseph Koshy 
1452f263522aSJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_THRESHOLD;
1453f263522aSJoseph Koshy 			pmc_config->pm_md.pm_amd.pm_amd_config |=
1454f263522aSJoseph Koshy 			    AMD_PMC_TO_COUNTER(count);
1455f263522aSJoseph Koshy 
1456f263522aSJoseph Koshy 		} else if (KWMATCH(p, K8_KW_EDGE)) {
1457f263522aSJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_EDGE;
1458f263522aSJoseph Koshy 		} else if (KWMATCH(p, K8_KW_INV)) {
1459f263522aSJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_INVERT;
1460f263522aSJoseph Koshy 		} else if (KWPREFIXMATCH(p, K8_KW_MASK "=")) {
1461f263522aSJoseph Koshy 			if ((n = pmc_parse_mask(pmask, p, &evmask)) < 0)
1462aa342b1fSJoseph Koshy 				return (-1);
1463f263522aSJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_QUALIFIER;
1464f263522aSJoseph Koshy 		} else if (KWMATCH(p, K8_KW_OS)) {
1465f263522aSJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_SYSTEM;
1466f263522aSJoseph Koshy 		} else if (KWMATCH(p, K8_KW_USR)) {
1467f263522aSJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_USER;
1468f263522aSJoseph Koshy 		} else
1469aa342b1fSJoseph Koshy 			return (-1);
1470f263522aSJoseph Koshy 	}
1471f263522aSJoseph Koshy 
1472f263522aSJoseph Koshy 	/* other post processing */
1473f263522aSJoseph Koshy 	switch (pe) {
1474f263522aSJoseph Koshy 	case PMC_EV_K8_FP_DISPATCHED_FPU_OPS:
1475f263522aSJoseph Koshy 	case PMC_EV_K8_FP_CYCLES_WITH_NO_FPU_OPS_RETIRED:
1476f263522aSJoseph Koshy 	case PMC_EV_K8_FP_DISPATCHED_FPU_FAST_FLAG_OPS:
1477f263522aSJoseph Koshy 	case PMC_EV_K8_FR_RETIRED_FASTPATH_DOUBLE_OP_INSTRUCTIONS:
1478f263522aSJoseph Koshy 	case PMC_EV_K8_FR_RETIRED_FPU_INSTRUCTIONS:
1479f263522aSJoseph Koshy 	case PMC_EV_K8_FR_FPU_EXCEPTIONS:
1480f263522aSJoseph Koshy 		/* XXX only available in rev B and later */
1481f263522aSJoseph Koshy 		break;
1482f263522aSJoseph Koshy 	case PMC_EV_K8_DC_DCACHE_ACCESSES_BY_LOCKS:
1483f263522aSJoseph Koshy 		/* XXX only available in rev C and later */
1484f263522aSJoseph Koshy 		break;
1485f263522aSJoseph Koshy 	case PMC_EV_K8_LS_LOCKED_OPERATION:
1486f263522aSJoseph Koshy 		/* XXX CPU Rev A,B evmask is to be zero */
1487f263522aSJoseph Koshy 		if (evmask & (evmask - 1)) /* > 1 bit set */
1488aa342b1fSJoseph Koshy 			return (-1);
1489f263522aSJoseph Koshy 		if (evmask == 0) {
1490f263522aSJoseph Koshy 			evmask = 0x01; /* Rev C and later: #instrs */
1491f263522aSJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_QUALIFIER;
1492f263522aSJoseph Koshy 		}
1493f263522aSJoseph Koshy 		break;
1494f263522aSJoseph Koshy 	default:
1495f263522aSJoseph Koshy 		if (evmask == 0 && pmask != NULL) {
1496f263522aSJoseph Koshy 			for (pm = pmask; pm->pm_name; pm++)
1497f263522aSJoseph Koshy 				evmask |= pm->pm_value;
1498f263522aSJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_QUALIFIER;
1499f263522aSJoseph Koshy 		}
1500f263522aSJoseph Koshy 	}
1501f263522aSJoseph Koshy 
1502f263522aSJoseph Koshy 	if (pmc_config->pm_caps & PMC_CAP_QUALIFIER)
1503f263522aSJoseph Koshy 		pmc_config->pm_md.pm_amd.pm_amd_config =
1504f263522aSJoseph Koshy 		    AMD_PMC_TO_UNITMASK(evmask);
1505f263522aSJoseph Koshy 
1506aa342b1fSJoseph Koshy 	return (0);
1507f263522aSJoseph Koshy }
1508f263522aSJoseph Koshy 
1509f263522aSJoseph Koshy #endif
1510f263522aSJoseph Koshy 
151186a65549SJoseph Koshy #if defined(__amd64__) || defined(__i386__)
1512f263522aSJoseph Koshy 
1513ebccf1e3SJoseph Koshy /*
1514ebccf1e3SJoseph Koshy  * Intel P4 PMCs
1515ebccf1e3SJoseph Koshy  */
1516ebccf1e3SJoseph Koshy 
1517ebccf1e3SJoseph Koshy static struct pmc_event_alias p4_aliases[] = {
1518d56c5d4bSJoseph Koshy 	EV_ALIAS("branches",		"p4-branch-retired,mask=mmtp+mmtm"),
1519d56c5d4bSJoseph Koshy 	EV_ALIAS("branch-mispredicts",	"p4-mispred-branch-retired"),
1520ebccf1e3SJoseph Koshy 	EV_ALIAS("cycles",		"tsc"),
1521d56c5d4bSJoseph Koshy 	EV_ALIAS("instructions",
1522d56c5d4bSJoseph Koshy 	    "p4-instr-retired,mask=nbogusntag+nbogustag"),
1523177a2f22SJoseph Koshy 	EV_ALIAS("unhalted-cycles",	"p4-global-power-events"),
1524ebccf1e3SJoseph Koshy 	EV_ALIAS(NULL, NULL)
1525ebccf1e3SJoseph Koshy };
1526ebccf1e3SJoseph Koshy 
1527ebccf1e3SJoseph Koshy #define	P4_KW_ACTIVE	"active"
1528ebccf1e3SJoseph Koshy #define	P4_KW_ACTIVE_ANY "any"
1529ebccf1e3SJoseph Koshy #define	P4_KW_ACTIVE_BOTH "both"
1530ebccf1e3SJoseph Koshy #define	P4_KW_ACTIVE_NONE "none"
1531ebccf1e3SJoseph Koshy #define	P4_KW_ACTIVE_SINGLE "single"
1532ebccf1e3SJoseph Koshy #define	P4_KW_BUSREQTYPE "busreqtype"
1533ebccf1e3SJoseph Koshy #define	P4_KW_CASCADE	"cascade"
1534ebccf1e3SJoseph Koshy #define	P4_KW_EDGE	"edge"
1535ebccf1e3SJoseph Koshy #define	P4_KW_INV	"complement"
1536ebccf1e3SJoseph Koshy #define	P4_KW_OS	"os"
1537ebccf1e3SJoseph Koshy #define	P4_KW_MASK	"mask"
1538ebccf1e3SJoseph Koshy #define	P4_KW_PRECISE	"precise"
1539ebccf1e3SJoseph Koshy #define	P4_KW_TAG	"tag"
1540ebccf1e3SJoseph Koshy #define	P4_KW_THRESHOLD	"threshold"
1541ebccf1e3SJoseph Koshy #define	P4_KW_USR	"usr"
1542ebccf1e3SJoseph Koshy 
1543ebccf1e3SJoseph Koshy #define	__P4MASK(N,V) PMCMASK(N, (1 << (V)))
1544ebccf1e3SJoseph Koshy 
1545ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_tcdm[] = { /* tc deliver mode */
1546ebccf1e3SJoseph Koshy 	__P4MASK(dd, 0),
1547ebccf1e3SJoseph Koshy 	__P4MASK(db, 1),
1548ebccf1e3SJoseph Koshy 	__P4MASK(di, 2),
1549ebccf1e3SJoseph Koshy 	__P4MASK(bd, 3),
1550ebccf1e3SJoseph Koshy 	__P4MASK(bb, 4),
1551ebccf1e3SJoseph Koshy 	__P4MASK(bi, 5),
1552ebccf1e3SJoseph Koshy 	__P4MASK(id, 6),
1553ebccf1e3SJoseph Koshy 	__P4MASK(ib, 7),
1554ebccf1e3SJoseph Koshy 	NULLMASK
1555ebccf1e3SJoseph Koshy };
1556ebccf1e3SJoseph Koshy 
1557ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_bfr[] = { /* bpu fetch request */
1558ebccf1e3SJoseph Koshy 	__P4MASK(tcmiss, 0),
1559ebccf1e3SJoseph Koshy 	NULLMASK,
1560ebccf1e3SJoseph Koshy };
1561ebccf1e3SJoseph Koshy 
1562ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_ir[] = { /* itlb reference */
1563ebccf1e3SJoseph Koshy 	__P4MASK(hit, 0),
1564ebccf1e3SJoseph Koshy 	__P4MASK(miss, 1),
1565ebccf1e3SJoseph Koshy 	__P4MASK(hit-uc, 2),
1566ebccf1e3SJoseph Koshy 	NULLMASK
1567ebccf1e3SJoseph Koshy };
1568ebccf1e3SJoseph Koshy 
1569ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_memcan[] = { /* memory cancel */
1570ebccf1e3SJoseph Koshy 	__P4MASK(st-rb-full, 2),
1571ebccf1e3SJoseph Koshy 	__P4MASK(64k-conf, 3),
1572ebccf1e3SJoseph Koshy 	NULLMASK
1573ebccf1e3SJoseph Koshy };
1574ebccf1e3SJoseph Koshy 
1575ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_memcomp[] = { /* memory complete */
1576ebccf1e3SJoseph Koshy 	__P4MASK(lsc, 0),
1577ebccf1e3SJoseph Koshy 	__P4MASK(ssc, 1),
1578ebccf1e3SJoseph Koshy 	NULLMASK
1579ebccf1e3SJoseph Koshy };
1580ebccf1e3SJoseph Koshy 
1581ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_lpr[] = { /* load port replay */
1582ebccf1e3SJoseph Koshy 	__P4MASK(split-ld, 1),
1583ebccf1e3SJoseph Koshy 	NULLMASK
1584ebccf1e3SJoseph Koshy };
1585ebccf1e3SJoseph Koshy 
1586ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_spr[] = { /* store port replay */
1587ebccf1e3SJoseph Koshy 	__P4MASK(split-st, 1),
1588ebccf1e3SJoseph Koshy 	NULLMASK
1589ebccf1e3SJoseph Koshy };
1590ebccf1e3SJoseph Koshy 
1591ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_mlr[] = { /* mob load replay */
1592ebccf1e3SJoseph Koshy 	__P4MASK(no-sta, 1),
1593ebccf1e3SJoseph Koshy 	__P4MASK(no-std, 3),
1594ebccf1e3SJoseph Koshy 	__P4MASK(partial-data, 4),
1595ebccf1e3SJoseph Koshy 	__P4MASK(unalgn-addr, 5),
1596ebccf1e3SJoseph Koshy 	NULLMASK
1597ebccf1e3SJoseph Koshy };
1598ebccf1e3SJoseph Koshy 
1599ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_pwt[] = { /* page walk type */
1600ebccf1e3SJoseph Koshy 	__P4MASK(dtmiss, 0),
1601ebccf1e3SJoseph Koshy 	__P4MASK(itmiss, 1),
1602ebccf1e3SJoseph Koshy 	NULLMASK
1603ebccf1e3SJoseph Koshy };
1604ebccf1e3SJoseph Koshy 
1605ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_bcr[] = { /* bsq cache reference */
1606ebccf1e3SJoseph Koshy 	__P4MASK(rd-2ndl-hits, 0),
1607ebccf1e3SJoseph Koshy 	__P4MASK(rd-2ndl-hite, 1),
1608ebccf1e3SJoseph Koshy 	__P4MASK(rd-2ndl-hitm, 2),
1609ebccf1e3SJoseph Koshy 	__P4MASK(rd-3rdl-hits, 3),
1610ebccf1e3SJoseph Koshy 	__P4MASK(rd-3rdl-hite, 4),
1611ebccf1e3SJoseph Koshy 	__P4MASK(rd-3rdl-hitm, 5),
1612ebccf1e3SJoseph Koshy 	__P4MASK(rd-2ndl-miss, 8),
1613ebccf1e3SJoseph Koshy 	__P4MASK(rd-3rdl-miss, 9),
1614ebccf1e3SJoseph Koshy 	__P4MASK(wr-2ndl-miss, 10),
1615ebccf1e3SJoseph Koshy 	NULLMASK
1616ebccf1e3SJoseph Koshy };
1617ebccf1e3SJoseph Koshy 
1618ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_ia[] = { /* ioq allocation */
1619ebccf1e3SJoseph Koshy 	__P4MASK(all-read, 5),
1620ebccf1e3SJoseph Koshy 	__P4MASK(all-write, 6),
1621ebccf1e3SJoseph Koshy 	__P4MASK(mem-uc, 7),
1622ebccf1e3SJoseph Koshy 	__P4MASK(mem-wc, 8),
1623ebccf1e3SJoseph Koshy 	__P4MASK(mem-wt, 9),
1624ebccf1e3SJoseph Koshy 	__P4MASK(mem-wp, 10),
1625ebccf1e3SJoseph Koshy 	__P4MASK(mem-wb, 11),
1626ebccf1e3SJoseph Koshy 	__P4MASK(own, 13),
1627ebccf1e3SJoseph Koshy 	__P4MASK(other, 14),
1628ebccf1e3SJoseph Koshy 	__P4MASK(prefetch, 15),
1629ebccf1e3SJoseph Koshy 	NULLMASK
1630ebccf1e3SJoseph Koshy };
1631ebccf1e3SJoseph Koshy 
1632ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_iae[] = { /* ioq active entries */
1633ebccf1e3SJoseph Koshy 	__P4MASK(all-read, 5),
1634ebccf1e3SJoseph Koshy 	__P4MASK(all-write, 6),
1635ebccf1e3SJoseph Koshy 	__P4MASK(mem-uc, 7),
1636ebccf1e3SJoseph Koshy 	__P4MASK(mem-wc, 8),
1637ebccf1e3SJoseph Koshy 	__P4MASK(mem-wt, 9),
1638ebccf1e3SJoseph Koshy 	__P4MASK(mem-wp, 10),
1639ebccf1e3SJoseph Koshy 	__P4MASK(mem-wb, 11),
1640ebccf1e3SJoseph Koshy 	__P4MASK(own, 13),
1641ebccf1e3SJoseph Koshy 	__P4MASK(other, 14),
1642ebccf1e3SJoseph Koshy 	__P4MASK(prefetch, 15),
1643ebccf1e3SJoseph Koshy 	NULLMASK
1644ebccf1e3SJoseph Koshy };
1645ebccf1e3SJoseph Koshy 
1646ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_fda[] = { /* fsb data activity */
1647ebccf1e3SJoseph Koshy 	__P4MASK(drdy-drv, 0),
1648ebccf1e3SJoseph Koshy 	__P4MASK(drdy-own, 1),
1649ebccf1e3SJoseph Koshy 	__P4MASK(drdy-other, 2),
1650ebccf1e3SJoseph Koshy 	__P4MASK(dbsy-drv, 3),
1651ebccf1e3SJoseph Koshy 	__P4MASK(dbsy-own, 4),
1652ebccf1e3SJoseph Koshy 	__P4MASK(dbsy-other, 5),
1653ebccf1e3SJoseph Koshy 	NULLMASK
1654ebccf1e3SJoseph Koshy };
1655ebccf1e3SJoseph Koshy 
1656ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_ba[] = { /* bsq allocation */
1657ebccf1e3SJoseph Koshy 	__P4MASK(req-type0, 0),
1658ebccf1e3SJoseph Koshy 	__P4MASK(req-type1, 1),
1659ebccf1e3SJoseph Koshy 	__P4MASK(req-len0, 2),
1660ebccf1e3SJoseph Koshy 	__P4MASK(req-len1, 3),
1661ebccf1e3SJoseph Koshy 	__P4MASK(req-io-type, 5),
1662ebccf1e3SJoseph Koshy 	__P4MASK(req-lock-type, 6),
1663ebccf1e3SJoseph Koshy 	__P4MASK(req-cache-type, 7),
1664ebccf1e3SJoseph Koshy 	__P4MASK(req-split-type, 8),
1665ebccf1e3SJoseph Koshy 	__P4MASK(req-dem-type, 9),
1666ebccf1e3SJoseph Koshy 	__P4MASK(req-ord-type, 10),
1667ebccf1e3SJoseph Koshy 	__P4MASK(mem-type0, 11),
1668ebccf1e3SJoseph Koshy 	__P4MASK(mem-type1, 12),
1669ebccf1e3SJoseph Koshy 	__P4MASK(mem-type2, 13),
1670ebccf1e3SJoseph Koshy 	NULLMASK
1671ebccf1e3SJoseph Koshy };
1672ebccf1e3SJoseph Koshy 
1673ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_sia[] = { /* sse input assist */
1674ebccf1e3SJoseph Koshy 	__P4MASK(all, 15),
1675ebccf1e3SJoseph Koshy 	NULLMASK
1676ebccf1e3SJoseph Koshy };
1677ebccf1e3SJoseph Koshy 
1678ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_psu[] = { /* packed sp uop */
1679ebccf1e3SJoseph Koshy 	__P4MASK(all, 15),
1680ebccf1e3SJoseph Koshy 	NULLMASK
1681ebccf1e3SJoseph Koshy };
1682ebccf1e3SJoseph Koshy 
1683ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_pdu[] = { /* packed dp uop */
1684ebccf1e3SJoseph Koshy 	__P4MASK(all, 15),
1685ebccf1e3SJoseph Koshy 	NULLMASK
1686ebccf1e3SJoseph Koshy };
1687ebccf1e3SJoseph Koshy 
1688ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_ssu[] = { /* scalar sp uop */
1689ebccf1e3SJoseph Koshy 	__P4MASK(all, 15),
1690ebccf1e3SJoseph Koshy 	NULLMASK
1691ebccf1e3SJoseph Koshy };
1692ebccf1e3SJoseph Koshy 
1693ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_sdu[] = { /* scalar dp uop */
1694ebccf1e3SJoseph Koshy 	__P4MASK(all, 15),
1695ebccf1e3SJoseph Koshy 	NULLMASK
1696ebccf1e3SJoseph Koshy };
1697ebccf1e3SJoseph Koshy 
1698ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_64bmu[] = { /* 64 bit mmx uop */
1699ebccf1e3SJoseph Koshy 	__P4MASK(all, 15),
1700ebccf1e3SJoseph Koshy 	NULLMASK
1701ebccf1e3SJoseph Koshy };
1702ebccf1e3SJoseph Koshy 
1703ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_128bmu[] = { /* 128 bit mmx uop */
1704ebccf1e3SJoseph Koshy 	__P4MASK(all, 15),
1705ebccf1e3SJoseph Koshy 	NULLMASK
1706ebccf1e3SJoseph Koshy };
1707ebccf1e3SJoseph Koshy 
1708ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_xfu[] = { /* X87 fp uop */
1709ebccf1e3SJoseph Koshy 	__P4MASK(all, 15),
1710ebccf1e3SJoseph Koshy 	NULLMASK
1711ebccf1e3SJoseph Koshy };
1712ebccf1e3SJoseph Koshy 
1713ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_xsmu[] = { /* x87 simd moves uop */
1714ebccf1e3SJoseph Koshy 	__P4MASK(allp0, 3),
1715ebccf1e3SJoseph Koshy 	__P4MASK(allp2, 4),
1716ebccf1e3SJoseph Koshy 	NULLMASK
1717ebccf1e3SJoseph Koshy };
1718ebccf1e3SJoseph Koshy 
1719ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_gpe[] = { /* global power events */
1720ebccf1e3SJoseph Koshy 	__P4MASK(running, 0),
1721ebccf1e3SJoseph Koshy 	NULLMASK
1722ebccf1e3SJoseph Koshy };
1723ebccf1e3SJoseph Koshy 
1724ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_tmx[] = { /* TC ms xfer */
1725ebccf1e3SJoseph Koshy 	__P4MASK(cisc, 0),
1726ebccf1e3SJoseph Koshy 	NULLMASK
1727ebccf1e3SJoseph Koshy };
1728ebccf1e3SJoseph Koshy 
1729ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_uqw[] = { /* uop queue writes */
1730ebccf1e3SJoseph Koshy 	__P4MASK(from-tc-build, 0),
1731ebccf1e3SJoseph Koshy 	__P4MASK(from-tc-deliver, 1),
1732ebccf1e3SJoseph Koshy 	__P4MASK(from-rom, 2),
1733ebccf1e3SJoseph Koshy 	NULLMASK
1734ebccf1e3SJoseph Koshy };
1735ebccf1e3SJoseph Koshy 
1736d56c5d4bSJoseph Koshy static const struct pmc_masks p4_mask_rmbt[] = {
1737d56c5d4bSJoseph Koshy 	/* retired mispred branch type */
1738ebccf1e3SJoseph Koshy 	__P4MASK(conditional, 1),
1739ebccf1e3SJoseph Koshy 	__P4MASK(call, 2),
1740ebccf1e3SJoseph Koshy 	__P4MASK(return, 3),
1741ebccf1e3SJoseph Koshy 	__P4MASK(indirect, 4),
1742ebccf1e3SJoseph Koshy 	NULLMASK
1743ebccf1e3SJoseph Koshy };
1744ebccf1e3SJoseph Koshy 
1745ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_rbt[] = { /* retired branch type */
1746ebccf1e3SJoseph Koshy 	__P4MASK(conditional, 1),
1747ebccf1e3SJoseph Koshy 	__P4MASK(call, 2),
1748ebccf1e3SJoseph Koshy 	__P4MASK(retired, 3),
1749ebccf1e3SJoseph Koshy 	__P4MASK(indirect, 4),
1750ebccf1e3SJoseph Koshy 	NULLMASK
1751ebccf1e3SJoseph Koshy };
1752ebccf1e3SJoseph Koshy 
1753ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_rs[] = { /* resource stall */
1754ebccf1e3SJoseph Koshy 	__P4MASK(sbfull, 5),
1755ebccf1e3SJoseph Koshy 	NULLMASK
1756ebccf1e3SJoseph Koshy };
1757ebccf1e3SJoseph Koshy 
1758ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_wb[] = { /* WC buffer */
1759ebccf1e3SJoseph Koshy 	__P4MASK(wcb-evicts, 0),
1760ebccf1e3SJoseph Koshy 	__P4MASK(wcb-full-evict, 1),
1761ebccf1e3SJoseph Koshy 	NULLMASK
1762ebccf1e3SJoseph Koshy };
1763ebccf1e3SJoseph Koshy 
1764ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_fee[] = { /* front end event */
1765ebccf1e3SJoseph Koshy 	__P4MASK(nbogus, 0),
1766ebccf1e3SJoseph Koshy 	__P4MASK(bogus, 1),
1767ebccf1e3SJoseph Koshy 	NULLMASK
1768ebccf1e3SJoseph Koshy };
1769ebccf1e3SJoseph Koshy 
1770ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_ee[] = { /* execution event */
1771ebccf1e3SJoseph Koshy 	__P4MASK(nbogus0, 0),
1772ebccf1e3SJoseph Koshy 	__P4MASK(nbogus1, 1),
1773ebccf1e3SJoseph Koshy 	__P4MASK(nbogus2, 2),
1774ebccf1e3SJoseph Koshy 	__P4MASK(nbogus3, 3),
1775ebccf1e3SJoseph Koshy 	__P4MASK(bogus0, 4),
1776ebccf1e3SJoseph Koshy 	__P4MASK(bogus1, 5),
1777ebccf1e3SJoseph Koshy 	__P4MASK(bogus2, 6),
1778ebccf1e3SJoseph Koshy 	__P4MASK(bogus3, 7),
1779ebccf1e3SJoseph Koshy 	NULLMASK
1780ebccf1e3SJoseph Koshy };
1781ebccf1e3SJoseph Koshy 
1782ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_re[] = { /* replay event */
1783ebccf1e3SJoseph Koshy 	__P4MASK(nbogus, 0),
1784ebccf1e3SJoseph Koshy 	__P4MASK(bogus, 1),
1785ebccf1e3SJoseph Koshy 	NULLMASK
1786ebccf1e3SJoseph Koshy };
1787ebccf1e3SJoseph Koshy 
1788ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_insret[] = { /* instr retired */
1789ebccf1e3SJoseph Koshy 	__P4MASK(nbogusntag, 0),
1790ebccf1e3SJoseph Koshy 	__P4MASK(nbogustag, 1),
1791ebccf1e3SJoseph Koshy 	__P4MASK(bogusntag, 2),
1792ebccf1e3SJoseph Koshy 	__P4MASK(bogustag, 3),
1793ebccf1e3SJoseph Koshy 	NULLMASK
1794ebccf1e3SJoseph Koshy };
1795ebccf1e3SJoseph Koshy 
1796ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_ur[] = { /* uops retired */
1797ebccf1e3SJoseph Koshy 	__P4MASK(nbogus, 0),
1798ebccf1e3SJoseph Koshy 	__P4MASK(bogus, 1),
1799ebccf1e3SJoseph Koshy 	NULLMASK
1800ebccf1e3SJoseph Koshy };
1801ebccf1e3SJoseph Koshy 
1802ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_ut[] = { /* uop type */
1803ebccf1e3SJoseph Koshy 	__P4MASK(tagloads, 1),
1804ebccf1e3SJoseph Koshy 	__P4MASK(tagstores, 2),
1805ebccf1e3SJoseph Koshy 	NULLMASK
1806ebccf1e3SJoseph Koshy };
1807ebccf1e3SJoseph Koshy 
1808ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_br[] = { /* branch retired */
1809ebccf1e3SJoseph Koshy 	__P4MASK(mmnp, 0),
1810ebccf1e3SJoseph Koshy 	__P4MASK(mmnm, 1),
1811ebccf1e3SJoseph Koshy 	__P4MASK(mmtp, 2),
1812ebccf1e3SJoseph Koshy 	__P4MASK(mmtm, 3),
1813ebccf1e3SJoseph Koshy 	NULLMASK
1814ebccf1e3SJoseph Koshy };
1815ebccf1e3SJoseph Koshy 
1816ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_mbr[] = { /* mispred branch retired */
1817ebccf1e3SJoseph Koshy 	__P4MASK(nbogus, 0),
1818ebccf1e3SJoseph Koshy 	NULLMASK
1819ebccf1e3SJoseph Koshy };
1820ebccf1e3SJoseph Koshy 
1821ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_xa[] = { /* x87 assist */
1822ebccf1e3SJoseph Koshy 	__P4MASK(fpsu, 0),
1823ebccf1e3SJoseph Koshy 	__P4MASK(fpso, 1),
1824ebccf1e3SJoseph Koshy 	__P4MASK(poao, 2),
1825ebccf1e3SJoseph Koshy 	__P4MASK(poau, 3),
1826ebccf1e3SJoseph Koshy 	__P4MASK(prea, 4),
1827ebccf1e3SJoseph Koshy 	NULLMASK
1828ebccf1e3SJoseph Koshy };
1829ebccf1e3SJoseph Koshy 
1830ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_machclr[] = { /* machine clear */
1831ebccf1e3SJoseph Koshy 	__P4MASK(clear, 0),
1832ebccf1e3SJoseph Koshy 	__P4MASK(moclear, 2),
1833ebccf1e3SJoseph Koshy 	__P4MASK(smclear, 3),
1834ebccf1e3SJoseph Koshy 	NULLMASK
1835ebccf1e3SJoseph Koshy };
1836ebccf1e3SJoseph Koshy 
1837ebccf1e3SJoseph Koshy /* P4 event parser */
1838ebccf1e3SJoseph Koshy static int
1839ebccf1e3SJoseph Koshy p4_allocate_pmc(enum pmc_event pe, char *ctrspec,
1840ebccf1e3SJoseph Koshy     struct pmc_op_pmcallocate *pmc_config)
1841ebccf1e3SJoseph Koshy {
1842ebccf1e3SJoseph Koshy 
1843ebccf1e3SJoseph Koshy 	char	*e, *p, *q;
1844ebccf1e3SJoseph Koshy 	int	count, has_tag, has_busreqtype, n;
18451e862e5aSFabien Thomas 	uint32_t cccractivemask;
18461e862e5aSFabien Thomas 	uint64_t evmask;
1847ebccf1e3SJoseph Koshy 	const struct pmc_masks *pm, *pmask;
1848ebccf1e3SJoseph Koshy 
1849789140c0SJoseph Koshy 	pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE);
1850f263522aSJoseph Koshy 	pmc_config->pm_md.pm_p4.pm_p4_cccrconfig =
1851f263522aSJoseph Koshy 	    pmc_config->pm_md.pm_p4.pm_p4_escrconfig = 0;
1852ebccf1e3SJoseph Koshy 
1853ebccf1e3SJoseph Koshy 	pmask   = NULL;
1854ebccf1e3SJoseph Koshy 	evmask  = 0;
1855ebccf1e3SJoseph Koshy 	cccractivemask = 0x3;
1856ebccf1e3SJoseph Koshy 	has_tag = has_busreqtype = 0;
1857ebccf1e3SJoseph Koshy 
1858ebccf1e3SJoseph Koshy #define	__P4SETMASK(M) do {				\
1859ebccf1e3SJoseph Koshy 	pmask = p4_mask_##M;				\
1860ebccf1e3SJoseph Koshy } while (0)
1861ebccf1e3SJoseph Koshy 
1862ebccf1e3SJoseph Koshy 	switch (pe) {
1863ebccf1e3SJoseph Koshy 	case PMC_EV_P4_TC_DELIVER_MODE:
1864ebccf1e3SJoseph Koshy 		__P4SETMASK(tcdm);
1865ebccf1e3SJoseph Koshy 		break;
1866ebccf1e3SJoseph Koshy 	case PMC_EV_P4_BPU_FETCH_REQUEST:
1867ebccf1e3SJoseph Koshy 		__P4SETMASK(bfr);
1868ebccf1e3SJoseph Koshy 		break;
1869ebccf1e3SJoseph Koshy 	case PMC_EV_P4_ITLB_REFERENCE:
1870ebccf1e3SJoseph Koshy 		__P4SETMASK(ir);
1871ebccf1e3SJoseph Koshy 		break;
1872ebccf1e3SJoseph Koshy 	case PMC_EV_P4_MEMORY_CANCEL:
1873ebccf1e3SJoseph Koshy 		__P4SETMASK(memcan);
1874ebccf1e3SJoseph Koshy 		break;
1875ebccf1e3SJoseph Koshy 	case PMC_EV_P4_MEMORY_COMPLETE:
1876ebccf1e3SJoseph Koshy 		__P4SETMASK(memcomp);
1877ebccf1e3SJoseph Koshy 		break;
1878ebccf1e3SJoseph Koshy 	case PMC_EV_P4_LOAD_PORT_REPLAY:
1879ebccf1e3SJoseph Koshy 		__P4SETMASK(lpr);
1880ebccf1e3SJoseph Koshy 		break;
1881ebccf1e3SJoseph Koshy 	case PMC_EV_P4_STORE_PORT_REPLAY:
1882ebccf1e3SJoseph Koshy 		__P4SETMASK(spr);
1883ebccf1e3SJoseph Koshy 		break;
1884ebccf1e3SJoseph Koshy 	case PMC_EV_P4_MOB_LOAD_REPLAY:
1885ebccf1e3SJoseph Koshy 		__P4SETMASK(mlr);
1886ebccf1e3SJoseph Koshy 		break;
1887ebccf1e3SJoseph Koshy 	case PMC_EV_P4_PAGE_WALK_TYPE:
1888ebccf1e3SJoseph Koshy 		__P4SETMASK(pwt);
1889ebccf1e3SJoseph Koshy 		break;
1890ebccf1e3SJoseph Koshy 	case PMC_EV_P4_BSQ_CACHE_REFERENCE:
1891ebccf1e3SJoseph Koshy 		__P4SETMASK(bcr);
1892ebccf1e3SJoseph Koshy 		break;
1893ebccf1e3SJoseph Koshy 	case PMC_EV_P4_IOQ_ALLOCATION:
1894ebccf1e3SJoseph Koshy 		__P4SETMASK(ia);
1895ebccf1e3SJoseph Koshy 		has_busreqtype = 1;
1896ebccf1e3SJoseph Koshy 		break;
1897ebccf1e3SJoseph Koshy 	case PMC_EV_P4_IOQ_ACTIVE_ENTRIES:
1898ebccf1e3SJoseph Koshy 		__P4SETMASK(iae);
1899ebccf1e3SJoseph Koshy 		has_busreqtype = 1;
1900ebccf1e3SJoseph Koshy 		break;
1901ebccf1e3SJoseph Koshy 	case PMC_EV_P4_FSB_DATA_ACTIVITY:
1902ebccf1e3SJoseph Koshy 		__P4SETMASK(fda);
1903ebccf1e3SJoseph Koshy 		break;
1904ebccf1e3SJoseph Koshy 	case PMC_EV_P4_BSQ_ALLOCATION:
1905ebccf1e3SJoseph Koshy 		__P4SETMASK(ba);
1906ebccf1e3SJoseph Koshy 		break;
1907ebccf1e3SJoseph Koshy 	case PMC_EV_P4_SSE_INPUT_ASSIST:
1908ebccf1e3SJoseph Koshy 		__P4SETMASK(sia);
1909ebccf1e3SJoseph Koshy 		break;
1910ebccf1e3SJoseph Koshy 	case PMC_EV_P4_PACKED_SP_UOP:
1911ebccf1e3SJoseph Koshy 		__P4SETMASK(psu);
1912ebccf1e3SJoseph Koshy 		break;
1913ebccf1e3SJoseph Koshy 	case PMC_EV_P4_PACKED_DP_UOP:
1914ebccf1e3SJoseph Koshy 		__P4SETMASK(pdu);
1915ebccf1e3SJoseph Koshy 		break;
1916ebccf1e3SJoseph Koshy 	case PMC_EV_P4_SCALAR_SP_UOP:
1917ebccf1e3SJoseph Koshy 		__P4SETMASK(ssu);
1918ebccf1e3SJoseph Koshy 		break;
1919ebccf1e3SJoseph Koshy 	case PMC_EV_P4_SCALAR_DP_UOP:
1920ebccf1e3SJoseph Koshy 		__P4SETMASK(sdu);
1921ebccf1e3SJoseph Koshy 		break;
1922ebccf1e3SJoseph Koshy 	case PMC_EV_P4_64BIT_MMX_UOP:
1923ebccf1e3SJoseph Koshy 		__P4SETMASK(64bmu);
1924ebccf1e3SJoseph Koshy 		break;
1925ebccf1e3SJoseph Koshy 	case PMC_EV_P4_128BIT_MMX_UOP:
1926ebccf1e3SJoseph Koshy 		__P4SETMASK(128bmu);
1927ebccf1e3SJoseph Koshy 		break;
1928ebccf1e3SJoseph Koshy 	case PMC_EV_P4_X87_FP_UOP:
1929ebccf1e3SJoseph Koshy 		__P4SETMASK(xfu);
1930ebccf1e3SJoseph Koshy 		break;
1931ebccf1e3SJoseph Koshy 	case PMC_EV_P4_X87_SIMD_MOVES_UOP:
1932ebccf1e3SJoseph Koshy 		__P4SETMASK(xsmu);
1933ebccf1e3SJoseph Koshy 		break;
1934ebccf1e3SJoseph Koshy 	case PMC_EV_P4_GLOBAL_POWER_EVENTS:
1935ebccf1e3SJoseph Koshy 		__P4SETMASK(gpe);
1936ebccf1e3SJoseph Koshy 		break;
1937ebccf1e3SJoseph Koshy 	case PMC_EV_P4_TC_MS_XFER:
1938ebccf1e3SJoseph Koshy 		__P4SETMASK(tmx);
1939ebccf1e3SJoseph Koshy 		break;
1940ebccf1e3SJoseph Koshy 	case PMC_EV_P4_UOP_QUEUE_WRITES:
1941ebccf1e3SJoseph Koshy 		__P4SETMASK(uqw);
1942ebccf1e3SJoseph Koshy 		break;
1943ebccf1e3SJoseph Koshy 	case PMC_EV_P4_RETIRED_MISPRED_BRANCH_TYPE:
1944ebccf1e3SJoseph Koshy 		__P4SETMASK(rmbt);
1945ebccf1e3SJoseph Koshy 		break;
1946ebccf1e3SJoseph Koshy 	case PMC_EV_P4_RETIRED_BRANCH_TYPE:
1947ebccf1e3SJoseph Koshy 		__P4SETMASK(rbt);
1948ebccf1e3SJoseph Koshy 		break;
1949ebccf1e3SJoseph Koshy 	case PMC_EV_P4_RESOURCE_STALL:
1950ebccf1e3SJoseph Koshy 		__P4SETMASK(rs);
1951ebccf1e3SJoseph Koshy 		break;
1952ebccf1e3SJoseph Koshy 	case PMC_EV_P4_WC_BUFFER:
1953ebccf1e3SJoseph Koshy 		__P4SETMASK(wb);
1954ebccf1e3SJoseph Koshy 		break;
1955ebccf1e3SJoseph Koshy 	case PMC_EV_P4_BSQ_ACTIVE_ENTRIES:
1956ebccf1e3SJoseph Koshy 	case PMC_EV_P4_B2B_CYCLES:
1957ebccf1e3SJoseph Koshy 	case PMC_EV_P4_BNR:
1958ebccf1e3SJoseph Koshy 	case PMC_EV_P4_SNOOP:
1959ebccf1e3SJoseph Koshy 	case PMC_EV_P4_RESPONSE:
1960ebccf1e3SJoseph Koshy 		break;
1961ebccf1e3SJoseph Koshy 	case PMC_EV_P4_FRONT_END_EVENT:
1962ebccf1e3SJoseph Koshy 		__P4SETMASK(fee);
1963ebccf1e3SJoseph Koshy 		break;
1964ebccf1e3SJoseph Koshy 	case PMC_EV_P4_EXECUTION_EVENT:
1965ebccf1e3SJoseph Koshy 		__P4SETMASK(ee);
1966ebccf1e3SJoseph Koshy 		break;
1967ebccf1e3SJoseph Koshy 	case PMC_EV_P4_REPLAY_EVENT:
1968ebccf1e3SJoseph Koshy 		__P4SETMASK(re);
1969ebccf1e3SJoseph Koshy 		break;
1970ebccf1e3SJoseph Koshy 	case PMC_EV_P4_INSTR_RETIRED:
1971ebccf1e3SJoseph Koshy 		__P4SETMASK(insret);
1972ebccf1e3SJoseph Koshy 		break;
1973ebccf1e3SJoseph Koshy 	case PMC_EV_P4_UOPS_RETIRED:
1974ebccf1e3SJoseph Koshy 		__P4SETMASK(ur);
1975ebccf1e3SJoseph Koshy 		break;
1976ebccf1e3SJoseph Koshy 	case PMC_EV_P4_UOP_TYPE:
1977ebccf1e3SJoseph Koshy 		__P4SETMASK(ut);
1978ebccf1e3SJoseph Koshy 		break;
1979ebccf1e3SJoseph Koshy 	case PMC_EV_P4_BRANCH_RETIRED:
1980ebccf1e3SJoseph Koshy 		__P4SETMASK(br);
1981ebccf1e3SJoseph Koshy 		break;
1982ebccf1e3SJoseph Koshy 	case PMC_EV_P4_MISPRED_BRANCH_RETIRED:
1983ebccf1e3SJoseph Koshy 		__P4SETMASK(mbr);
1984ebccf1e3SJoseph Koshy 		break;
1985ebccf1e3SJoseph Koshy 	case PMC_EV_P4_X87_ASSIST:
1986ebccf1e3SJoseph Koshy 		__P4SETMASK(xa);
1987ebccf1e3SJoseph Koshy 		break;
1988ebccf1e3SJoseph Koshy 	case PMC_EV_P4_MACHINE_CLEAR:
1989ebccf1e3SJoseph Koshy 		__P4SETMASK(machclr);
1990ebccf1e3SJoseph Koshy 		break;
1991ebccf1e3SJoseph Koshy 	default:
1992aa342b1fSJoseph Koshy 		return (-1);
1993ebccf1e3SJoseph Koshy 	}
1994ebccf1e3SJoseph Koshy 
1995ebccf1e3SJoseph Koshy 	/* process additional flags */
1996ebccf1e3SJoseph Koshy 	while ((p = strsep(&ctrspec, ",")) != NULL) {
1997ebccf1e3SJoseph Koshy 		if (KWPREFIXMATCH(p, P4_KW_ACTIVE)) {
1998ebccf1e3SJoseph Koshy 			q = strchr(p, '=');
1999ebccf1e3SJoseph Koshy 			if (*++q == '\0') /* skip '=' */
2000aa342b1fSJoseph Koshy 				return (-1);
2001ebccf1e3SJoseph Koshy 
2002789140c0SJoseph Koshy 			if (strcasecmp(q, P4_KW_ACTIVE_NONE) == 0)
2003ebccf1e3SJoseph Koshy 				cccractivemask = 0x0;
2004789140c0SJoseph Koshy 			else if (strcasecmp(q, P4_KW_ACTIVE_SINGLE) == 0)
2005ebccf1e3SJoseph Koshy 				cccractivemask = 0x1;
2006789140c0SJoseph Koshy 			else if (strcasecmp(q, P4_KW_ACTIVE_BOTH) == 0)
2007ebccf1e3SJoseph Koshy 				cccractivemask = 0x2;
2008789140c0SJoseph Koshy 			else if (strcasecmp(q, P4_KW_ACTIVE_ANY) == 0)
2009ebccf1e3SJoseph Koshy 				cccractivemask = 0x3;
2010ebccf1e3SJoseph Koshy 			else
2011aa342b1fSJoseph Koshy 				return (-1);
2012ebccf1e3SJoseph Koshy 
2013ebccf1e3SJoseph Koshy 		} else if (KWPREFIXMATCH(p, P4_KW_BUSREQTYPE)) {
2014ebccf1e3SJoseph Koshy 			if (has_busreqtype == 0)
2015aa342b1fSJoseph Koshy 				return (-1);
2016ebccf1e3SJoseph Koshy 
2017ebccf1e3SJoseph Koshy 			q = strchr(p, '=');
2018ebccf1e3SJoseph Koshy 			if (*++q == '\0') /* skip '=' */
2019aa342b1fSJoseph Koshy 				return (-1);
2020ebccf1e3SJoseph Koshy 
2021ebccf1e3SJoseph Koshy 			count = strtol(q, &e, 0);
2022ebccf1e3SJoseph Koshy 			if (e == q || *e != '\0')
2023aa342b1fSJoseph Koshy 				return (-1);
2024ebccf1e3SJoseph Koshy 			evmask = (evmask & ~0x1F) | (count & 0x1F);
2025ebccf1e3SJoseph Koshy 		} else if (KWMATCH(p, P4_KW_CASCADE))
2026ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_CASCADE;
2027ebccf1e3SJoseph Koshy 		else if (KWMATCH(p, P4_KW_EDGE))
2028ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_EDGE;
2029ebccf1e3SJoseph Koshy 		else if (KWMATCH(p, P4_KW_INV))
2030ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_INVERT;
2031ebccf1e3SJoseph Koshy 		else if (KWPREFIXMATCH(p, P4_KW_MASK "=")) {
2032ebccf1e3SJoseph Koshy 			if ((n = pmc_parse_mask(pmask, p, &evmask)) < 0)
2033aa342b1fSJoseph Koshy 				return (-1);
2034ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_QUALIFIER;
2035ebccf1e3SJoseph Koshy 		} else if (KWMATCH(p, P4_KW_OS))
2036ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_SYSTEM;
2037ebccf1e3SJoseph Koshy 		else if (KWMATCH(p, P4_KW_PRECISE))
2038ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_PRECISE;
2039ebccf1e3SJoseph Koshy 		else if (KWPREFIXMATCH(p, P4_KW_TAG "=")) {
2040ebccf1e3SJoseph Koshy 			if (has_tag == 0)
2041aa342b1fSJoseph Koshy 				return (-1);
2042ebccf1e3SJoseph Koshy 
2043ebccf1e3SJoseph Koshy 			q = strchr(p, '=');
2044ebccf1e3SJoseph Koshy 			if (*++q == '\0') /* skip '=' */
2045aa342b1fSJoseph Koshy 				return (-1);
2046ebccf1e3SJoseph Koshy 
2047ebccf1e3SJoseph Koshy 			count = strtol(q, &e, 0);
2048ebccf1e3SJoseph Koshy 			if (e == q || *e != '\0')
2049aa342b1fSJoseph Koshy 				return (-1);
2050ebccf1e3SJoseph Koshy 
2051ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_TAGGING;
2052f263522aSJoseph Koshy 			pmc_config->pm_md.pm_p4.pm_p4_escrconfig |=
2053ebccf1e3SJoseph Koshy 			    P4_ESCR_TO_TAG_VALUE(count);
2054ebccf1e3SJoseph Koshy 		} else if (KWPREFIXMATCH(p, P4_KW_THRESHOLD "=")) {
2055ebccf1e3SJoseph Koshy 			q = strchr(p, '=');
2056ebccf1e3SJoseph Koshy 			if (*++q == '\0') /* skip '=' */
2057aa342b1fSJoseph Koshy 				return (-1);
2058ebccf1e3SJoseph Koshy 
2059ebccf1e3SJoseph Koshy 			count = strtol(q, &e, 0);
2060ebccf1e3SJoseph Koshy 			if (e == q || *e != '\0')
2061aa342b1fSJoseph Koshy 				return (-1);
2062ebccf1e3SJoseph Koshy 
2063ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_THRESHOLD;
2064f263522aSJoseph Koshy 			pmc_config->pm_md.pm_p4.pm_p4_cccrconfig &=
2065f263522aSJoseph Koshy 			    ~P4_CCCR_THRESHOLD_MASK;
2066f263522aSJoseph Koshy 			pmc_config->pm_md.pm_p4.pm_p4_cccrconfig |=
2067f263522aSJoseph Koshy 			    P4_CCCR_TO_THRESHOLD(count);
2068ebccf1e3SJoseph Koshy 		} else if (KWMATCH(p, P4_KW_USR))
2069ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_USER;
2070ebccf1e3SJoseph Koshy 		else
2071aa342b1fSJoseph Koshy 			return (-1);
2072ebccf1e3SJoseph Koshy 	}
2073ebccf1e3SJoseph Koshy 
2074ebccf1e3SJoseph Koshy 	/* other post processing */
2075ebccf1e3SJoseph Koshy 	if (pe == PMC_EV_P4_IOQ_ALLOCATION ||
2076ebccf1e3SJoseph Koshy 	    pe == PMC_EV_P4_FSB_DATA_ACTIVITY ||
2077ebccf1e3SJoseph Koshy 	    pe == PMC_EV_P4_BSQ_ALLOCATION)
2078ebccf1e3SJoseph Koshy 		pmc_config->pm_caps |= PMC_CAP_EDGE;
2079ebccf1e3SJoseph Koshy 
2080ebccf1e3SJoseph Koshy 	/* fill in thread activity mask */
2081f263522aSJoseph Koshy 	pmc_config->pm_md.pm_p4.pm_p4_cccrconfig |=
2082ebccf1e3SJoseph Koshy 	    P4_CCCR_TO_ACTIVE_THREAD(cccractivemask);
2083ebccf1e3SJoseph Koshy 
2084ebccf1e3SJoseph Koshy 	if (evmask)
2085ebccf1e3SJoseph Koshy 		pmc_config->pm_caps |= PMC_CAP_QUALIFIER;
2086ebccf1e3SJoseph Koshy 
2087ebccf1e3SJoseph Koshy 	switch (pe) {
2088ebccf1e3SJoseph Koshy 	case PMC_EV_P4_FSB_DATA_ACTIVITY:
2089ebccf1e3SJoseph Koshy 		if ((evmask & 0x06) == 0x06 ||
2090ebccf1e3SJoseph Koshy 		    (evmask & 0x18) == 0x18)
2091aa342b1fSJoseph Koshy 			return (-1); /* can't have own+other bits together */
2092ebccf1e3SJoseph Koshy 		if (evmask == 0) /* default:drdy-{drv,own}+dbsy{drv,own} */
2093ebccf1e3SJoseph Koshy 			evmask = 0x1D;
2094ebccf1e3SJoseph Koshy 		break;
2095ebccf1e3SJoseph Koshy 	case PMC_EV_P4_MACHINE_CLEAR:
2096ebccf1e3SJoseph Koshy 		/* only one bit is allowed to be set */
2097ebccf1e3SJoseph Koshy 		if ((evmask & (evmask - 1)) != 0)
2098aa342b1fSJoseph Koshy 			return (-1);
2099ebccf1e3SJoseph Koshy 		if (evmask == 0) {
2100ebccf1e3SJoseph Koshy 			evmask = 0x1;	/* 'CLEAR' */
2101ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_QUALIFIER;
2102ebccf1e3SJoseph Koshy 		}
2103ebccf1e3SJoseph Koshy 		break;
2104ebccf1e3SJoseph Koshy 	default:
2105ebccf1e3SJoseph Koshy 		if (evmask == 0 && pmask) {
2106ebccf1e3SJoseph Koshy 			for (pm = pmask; pm->pm_name; pm++)
2107ebccf1e3SJoseph Koshy 				evmask |= pm->pm_value;
2108ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_QUALIFIER;
2109ebccf1e3SJoseph Koshy 		}
2110ebccf1e3SJoseph Koshy 	}
2111ebccf1e3SJoseph Koshy 
2112f263522aSJoseph Koshy 	pmc_config->pm_md.pm_p4.pm_p4_escrconfig =
2113f263522aSJoseph Koshy 	    P4_ESCR_TO_EVENT_MASK(evmask);
2114ebccf1e3SJoseph Koshy 
2115aa342b1fSJoseph Koshy 	return (0);
2116ebccf1e3SJoseph Koshy }
2117ebccf1e3SJoseph Koshy 
211886a65549SJoseph Koshy #endif
211986a65549SJoseph Koshy 
212086a65549SJoseph Koshy #if defined(__i386__)
212186a65549SJoseph Koshy 
2122ebccf1e3SJoseph Koshy /*
2123f263522aSJoseph Koshy  * Pentium style PMCs
2124f263522aSJoseph Koshy  */
2125f263522aSJoseph Koshy 
2126f263522aSJoseph Koshy static struct pmc_event_alias p5_aliases[] = {
21270b9b757dSJoseph Koshy 	EV_ALIAS("branches",		"p5-taken-branches"),
2128f263522aSJoseph Koshy 	EV_ALIAS("cycles",		"tsc"),
21290b9b757dSJoseph Koshy 	EV_ALIAS("dc-misses",		"p5-data-read-miss-or-write-miss"),
21300b9b757dSJoseph Koshy 	EV_ALIAS("ic-misses",		"p5-code-cache-miss"),
21310b9b757dSJoseph Koshy 	EV_ALIAS("instructions",	"p5-instructions-executed"),
21320b9b757dSJoseph Koshy 	EV_ALIAS("interrupts",		"p5-hardware-interrupts"),
21330b9b757dSJoseph Koshy 	EV_ALIAS("unhalted-cycles",
21340b9b757dSJoseph Koshy 	    "p5-number-of-cycles-not-in-halt-state"),
2135f263522aSJoseph Koshy 	EV_ALIAS(NULL, NULL)
2136f263522aSJoseph Koshy };
2137f263522aSJoseph Koshy 
2138f263522aSJoseph Koshy static int
2139f263522aSJoseph Koshy p5_allocate_pmc(enum pmc_event pe, char *ctrspec,
2140f263522aSJoseph Koshy     struct pmc_op_pmcallocate *pmc_config)
2141f263522aSJoseph Koshy {
2142aa342b1fSJoseph Koshy 	return (-1 || pe || ctrspec || pmc_config); /* shut up gcc */
2143f263522aSJoseph Koshy }
2144f263522aSJoseph Koshy 
2145f263522aSJoseph Koshy /*
2146ebccf1e3SJoseph Koshy  * Pentium Pro style PMCs.  These PMCs are found in Pentium II, Pentium III,
2147ebccf1e3SJoseph Koshy  * and Pentium M CPUs.
2148ebccf1e3SJoseph Koshy  */
2149ebccf1e3SJoseph Koshy 
2150ebccf1e3SJoseph Koshy static struct pmc_event_alias p6_aliases[] = {
2151ebccf1e3SJoseph Koshy 	EV_ALIAS("branches",		"p6-br-inst-retired"),
2152ebccf1e3SJoseph Koshy 	EV_ALIAS("branch-mispredicts",	"p6-br-miss-pred-retired"),
2153ebccf1e3SJoseph Koshy 	EV_ALIAS("cycles",		"tsc"),
2154d56c5d4bSJoseph Koshy 	EV_ALIAS("dc-misses",		"p6-dcu-lines-in"),
215573e2d811SJoseph Koshy 	EV_ALIAS("ic-misses",		"p6-ifu-fetch-miss"),
2156ebccf1e3SJoseph Koshy 	EV_ALIAS("instructions",	"p6-inst-retired"),
2157ebccf1e3SJoseph Koshy 	EV_ALIAS("interrupts",		"p6-hw-int-rx"),
2158177a2f22SJoseph Koshy 	EV_ALIAS("unhalted-cycles",	"p6-cpu-clk-unhalted"),
2159ebccf1e3SJoseph Koshy 	EV_ALIAS(NULL, NULL)
2160ebccf1e3SJoseph Koshy };
2161ebccf1e3SJoseph Koshy 
2162ebccf1e3SJoseph Koshy #define	P6_KW_CMASK	"cmask"
2163ebccf1e3SJoseph Koshy #define	P6_KW_EDGE	"edge"
2164ebccf1e3SJoseph Koshy #define	P6_KW_INV	"inv"
2165ebccf1e3SJoseph Koshy #define	P6_KW_OS	"os"
2166ebccf1e3SJoseph Koshy #define	P6_KW_UMASK	"umask"
2167ebccf1e3SJoseph Koshy #define	P6_KW_USR	"usr"
2168ebccf1e3SJoseph Koshy 
2169ebccf1e3SJoseph Koshy static struct pmc_masks p6_mask_mesi[] = {
2170ebccf1e3SJoseph Koshy 	PMCMASK(m,	0x01),
2171ebccf1e3SJoseph Koshy 	PMCMASK(e,	0x02),
2172ebccf1e3SJoseph Koshy 	PMCMASK(s,	0x04),
2173ebccf1e3SJoseph Koshy 	PMCMASK(i,	0x08),
2174ebccf1e3SJoseph Koshy 	NULLMASK
2175ebccf1e3SJoseph Koshy };
2176ebccf1e3SJoseph Koshy 
2177ebccf1e3SJoseph Koshy static struct pmc_masks p6_mask_mesihw[] = {
2178ebccf1e3SJoseph Koshy 	PMCMASK(m,	0x01),
2179ebccf1e3SJoseph Koshy 	PMCMASK(e,	0x02),
2180ebccf1e3SJoseph Koshy 	PMCMASK(s,	0x04),
2181ebccf1e3SJoseph Koshy 	PMCMASK(i,	0x08),
2182ebccf1e3SJoseph Koshy 	PMCMASK(nonhw,	0x00),
2183ebccf1e3SJoseph Koshy 	PMCMASK(hw,	0x10),
2184ebccf1e3SJoseph Koshy 	PMCMASK(both,	0x30),
2185ebccf1e3SJoseph Koshy 	NULLMASK
2186ebccf1e3SJoseph Koshy };
2187ebccf1e3SJoseph Koshy 
2188ebccf1e3SJoseph Koshy static struct pmc_masks p6_mask_hw[] = {
2189ebccf1e3SJoseph Koshy 	PMCMASK(nonhw,	0x00),
2190ebccf1e3SJoseph Koshy 	PMCMASK(hw,	0x10),
2191ebccf1e3SJoseph Koshy 	PMCMASK(both,	0x30),
2192ebccf1e3SJoseph Koshy 	NULLMASK
2193ebccf1e3SJoseph Koshy };
2194ebccf1e3SJoseph Koshy 
2195ebccf1e3SJoseph Koshy static struct pmc_masks p6_mask_any[] = {
2196ebccf1e3SJoseph Koshy 	PMCMASK(self,	0x00),
2197ebccf1e3SJoseph Koshy 	PMCMASK(any,	0x20),
2198ebccf1e3SJoseph Koshy 	NULLMASK
2199ebccf1e3SJoseph Koshy };
2200ebccf1e3SJoseph Koshy 
2201ebccf1e3SJoseph Koshy static struct pmc_masks p6_mask_ekp[] = {
2202ebccf1e3SJoseph Koshy 	PMCMASK(nta,	0x00),
2203ebccf1e3SJoseph Koshy 	PMCMASK(t1,	0x01),
2204ebccf1e3SJoseph Koshy 	PMCMASK(t2,	0x02),
2205ebccf1e3SJoseph Koshy 	PMCMASK(wos,	0x03),
2206ebccf1e3SJoseph Koshy 	NULLMASK
2207ebccf1e3SJoseph Koshy };
2208ebccf1e3SJoseph Koshy 
2209ebccf1e3SJoseph Koshy static struct pmc_masks p6_mask_pps[] = {
2210ebccf1e3SJoseph Koshy 	PMCMASK(packed-and-scalar, 0x00),
2211ebccf1e3SJoseph Koshy 	PMCMASK(scalar,	0x01),
2212ebccf1e3SJoseph Koshy 	NULLMASK
2213ebccf1e3SJoseph Koshy };
2214ebccf1e3SJoseph Koshy 
2215ebccf1e3SJoseph Koshy static struct pmc_masks p6_mask_mite[] = {
2216ebccf1e3SJoseph Koshy 	PMCMASK(packed-multiply,	 0x01),
2217ebccf1e3SJoseph Koshy 	PMCMASK(packed-shift,		0x02),
2218ebccf1e3SJoseph Koshy 	PMCMASK(pack,			0x04),
2219ebccf1e3SJoseph Koshy 	PMCMASK(unpack,			0x08),
2220ebccf1e3SJoseph Koshy 	PMCMASK(packed-logical,		0x10),
2221ebccf1e3SJoseph Koshy 	PMCMASK(packed-arithmetic,	0x20),
2222ebccf1e3SJoseph Koshy 	NULLMASK
2223ebccf1e3SJoseph Koshy };
2224ebccf1e3SJoseph Koshy 
2225ebccf1e3SJoseph Koshy static struct pmc_masks p6_mask_fmt[] = {
2226ebccf1e3SJoseph Koshy 	PMCMASK(mmxtofp,	0x00),
2227ebccf1e3SJoseph Koshy 	PMCMASK(fptommx,	0x01),
2228ebccf1e3SJoseph Koshy 	NULLMASK
2229ebccf1e3SJoseph Koshy };
2230ebccf1e3SJoseph Koshy 
2231ebccf1e3SJoseph Koshy static struct pmc_masks p6_mask_sr[] = {
2232ebccf1e3SJoseph Koshy 	PMCMASK(es,	0x01),
2233ebccf1e3SJoseph Koshy 	PMCMASK(ds,	0x02),
2234ebccf1e3SJoseph Koshy 	PMCMASK(fs,	0x04),
2235ebccf1e3SJoseph Koshy 	PMCMASK(gs,	0x08),
2236ebccf1e3SJoseph Koshy 	NULLMASK
2237ebccf1e3SJoseph Koshy };
2238ebccf1e3SJoseph Koshy 
2239ebccf1e3SJoseph Koshy static struct pmc_masks p6_mask_eet[] = {
2240ebccf1e3SJoseph Koshy 	PMCMASK(all,	0x00),
2241ebccf1e3SJoseph Koshy 	PMCMASK(freq,	0x02),
2242ebccf1e3SJoseph Koshy 	NULLMASK
2243ebccf1e3SJoseph Koshy };
2244ebccf1e3SJoseph Koshy 
2245ebccf1e3SJoseph Koshy static struct pmc_masks p6_mask_efur[] = {
2246ebccf1e3SJoseph Koshy 	PMCMASK(all,	0x00),
2247ebccf1e3SJoseph Koshy 	PMCMASK(loadop,	0x01),
2248ebccf1e3SJoseph Koshy 	PMCMASK(stdsta,	0x02),
2249ebccf1e3SJoseph Koshy 	NULLMASK
2250ebccf1e3SJoseph Koshy };
2251ebccf1e3SJoseph Koshy 
2252ebccf1e3SJoseph Koshy static struct pmc_masks p6_mask_essir[] = {
2253ebccf1e3SJoseph Koshy 	PMCMASK(sse-packed-single,	0x00),
2254ebccf1e3SJoseph Koshy 	PMCMASK(sse-packed-single-scalar-single, 0x01),
2255ebccf1e3SJoseph Koshy 	PMCMASK(sse2-packed-double,	0x02),
2256ebccf1e3SJoseph Koshy 	PMCMASK(sse2-scalar-double,	0x03),
2257ebccf1e3SJoseph Koshy 	NULLMASK
2258ebccf1e3SJoseph Koshy };
2259ebccf1e3SJoseph Koshy 
2260ebccf1e3SJoseph Koshy static struct pmc_masks p6_mask_esscir[] = {
2261ebccf1e3SJoseph Koshy 	PMCMASK(sse-packed-single,	0x00),
2262ebccf1e3SJoseph Koshy 	PMCMASK(sse-scalar-single,	0x01),
2263ebccf1e3SJoseph Koshy 	PMCMASK(sse2-packed-double,	0x02),
2264ebccf1e3SJoseph Koshy 	PMCMASK(sse2-scalar-double,	0x03),
2265ebccf1e3SJoseph Koshy 	NULLMASK
2266ebccf1e3SJoseph Koshy };
2267ebccf1e3SJoseph Koshy 
2268ebccf1e3SJoseph Koshy /* P6 event parser */
2269ebccf1e3SJoseph Koshy static int
2270ebccf1e3SJoseph Koshy p6_allocate_pmc(enum pmc_event pe, char *ctrspec,
2271ebccf1e3SJoseph Koshy     struct pmc_op_pmcallocate *pmc_config)
2272ebccf1e3SJoseph Koshy {
2273ebccf1e3SJoseph Koshy 	char *e, *p, *q;
22741e862e5aSFabien Thomas 	uint64_t evmask;
2275ebccf1e3SJoseph Koshy 	int count, n;
2276ebccf1e3SJoseph Koshy 	const struct pmc_masks *pm, *pmask;
2277ebccf1e3SJoseph Koshy 
2278789140c0SJoseph Koshy 	pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE);
2279f263522aSJoseph Koshy 	pmc_config->pm_md.pm_ppro.pm_ppro_config = 0;
2280ebccf1e3SJoseph Koshy 
2281ebccf1e3SJoseph Koshy 	evmask = 0;
2282ebccf1e3SJoseph Koshy 
2283ebccf1e3SJoseph Koshy #define	P6MASKSET(M)	pmask = p6_mask_ ## M
2284ebccf1e3SJoseph Koshy 
2285ebccf1e3SJoseph Koshy 	switch(pe) {
2286ebccf1e3SJoseph Koshy 	case PMC_EV_P6_L2_IFETCH:	P6MASKSET(mesi); break;
2287ebccf1e3SJoseph Koshy 	case PMC_EV_P6_L2_LD:		P6MASKSET(mesi); break;
2288ebccf1e3SJoseph Koshy 	case PMC_EV_P6_L2_ST:		P6MASKSET(mesi); break;
2289ebccf1e3SJoseph Koshy 	case PMC_EV_P6_L2_RQSTS:	P6MASKSET(mesi); break;
2290ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_DRDY_CLOCKS:
2291ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_LOCK_CLOCKS:
2292ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_BRD:
2293ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_RFO:
2294ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRANS_WB:
2295ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_IFETCH:
2296ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_INVAL:
2297ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_PWR:
2298ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRANS_P:
2299ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRANS_IO:
2300ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_DEF:
2301ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_BURST:
2302ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_ANY:
2303ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_MEM:
2304ebccf1e3SJoseph Koshy 		P6MASKSET(any);	break;
2305ebccf1e3SJoseph Koshy 	case PMC_EV_P6_EMON_KNI_PREF_DISPATCHED:
2306ebccf1e3SJoseph Koshy 	case PMC_EV_P6_EMON_KNI_PREF_MISS:
2307ebccf1e3SJoseph Koshy 		P6MASKSET(ekp); break;
2308ebccf1e3SJoseph Koshy 	case PMC_EV_P6_EMON_KNI_INST_RETIRED:
2309ebccf1e3SJoseph Koshy 	case PMC_EV_P6_EMON_KNI_COMP_INST_RET:
2310ebccf1e3SJoseph Koshy 		P6MASKSET(pps);	break;
2311ebccf1e3SJoseph Koshy 	case PMC_EV_P6_MMX_INSTR_TYPE_EXEC:
2312ebccf1e3SJoseph Koshy 		P6MASKSET(mite); break;
2313ebccf1e3SJoseph Koshy 	case PMC_EV_P6_FP_MMX_TRANS:
2314ebccf1e3SJoseph Koshy 		P6MASKSET(fmt);	break;
2315ebccf1e3SJoseph Koshy 	case PMC_EV_P6_SEG_RENAME_STALLS:
2316ebccf1e3SJoseph Koshy 	case PMC_EV_P6_SEG_REG_RENAMES:
2317ebccf1e3SJoseph Koshy 		P6MASKSET(sr);	break;
2318ebccf1e3SJoseph Koshy 	case PMC_EV_P6_EMON_EST_TRANS:
2319ebccf1e3SJoseph Koshy 		P6MASKSET(eet);	break;
2320ebccf1e3SJoseph Koshy 	case PMC_EV_P6_EMON_FUSED_UOPS_RET:
2321ebccf1e3SJoseph Koshy 		P6MASKSET(efur); break;
2322ebccf1e3SJoseph Koshy 	case PMC_EV_P6_EMON_SSE_SSE2_INST_RETIRED:
2323ebccf1e3SJoseph Koshy 		P6MASKSET(essir); break;
2324ebccf1e3SJoseph Koshy 	case PMC_EV_P6_EMON_SSE_SSE2_COMP_INST_RETIRED:
2325ebccf1e3SJoseph Koshy 		P6MASKSET(esscir); break;
2326ebccf1e3SJoseph Koshy 	default:
2327ebccf1e3SJoseph Koshy 		pmask = NULL;
2328ebccf1e3SJoseph Koshy 		break;
2329ebccf1e3SJoseph Koshy 	}
2330ebccf1e3SJoseph Koshy 
2331ebccf1e3SJoseph Koshy 	/* Pentium M PMCs have a few events with different semantics */
2332ebccf1e3SJoseph Koshy 	if (cpu_info.pm_cputype == PMC_CPU_INTEL_PM) {
2333ebccf1e3SJoseph Koshy 		if (pe == PMC_EV_P6_L2_LD ||
2334ebccf1e3SJoseph Koshy 		    pe == PMC_EV_P6_L2_LINES_IN ||
2335ebccf1e3SJoseph Koshy 		    pe == PMC_EV_P6_L2_LINES_OUT)
2336ebccf1e3SJoseph Koshy 			P6MASKSET(mesihw);
2337ebccf1e3SJoseph Koshy 		else if (pe == PMC_EV_P6_L2_M_LINES_OUTM)
2338ebccf1e3SJoseph Koshy 			P6MASKSET(hw);
2339ebccf1e3SJoseph Koshy 	}
2340ebccf1e3SJoseph Koshy 
2341ebccf1e3SJoseph Koshy 	/* Parse additional modifiers if present */
2342ebccf1e3SJoseph Koshy 	while ((p = strsep(&ctrspec, ",")) != NULL) {
2343ebccf1e3SJoseph Koshy 		if (KWPREFIXMATCH(p, P6_KW_CMASK "=")) {
2344ebccf1e3SJoseph Koshy 			q = strchr(p, '=');
2345ebccf1e3SJoseph Koshy 			if (*++q == '\0') /* skip '=' */
2346aa342b1fSJoseph Koshy 				return (-1);
2347ebccf1e3SJoseph Koshy 			count = strtol(q, &e, 0);
2348ebccf1e3SJoseph Koshy 			if (e == q || *e != '\0')
2349aa342b1fSJoseph Koshy 				return (-1);
2350ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_THRESHOLD;
2351f263522aSJoseph Koshy 			pmc_config->pm_md.pm_ppro.pm_ppro_config |=
2352f263522aSJoseph Koshy 			    P6_EVSEL_TO_CMASK(count);
2353ebccf1e3SJoseph Koshy 		} else if (KWMATCH(p, P6_KW_EDGE)) {
2354ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_EDGE;
2355ebccf1e3SJoseph Koshy 		} else if (KWMATCH(p, P6_KW_INV)) {
2356ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_INVERT;
2357ebccf1e3SJoseph Koshy 		} else if (KWMATCH(p, P6_KW_OS)) {
2358ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_SYSTEM;
2359ebccf1e3SJoseph Koshy 		} else if (KWPREFIXMATCH(p, P6_KW_UMASK "=")) {
2360ebccf1e3SJoseph Koshy 			evmask = 0;
2361ebccf1e3SJoseph Koshy 			if ((n = pmc_parse_mask(pmask, p, &evmask)) < 0)
2362aa342b1fSJoseph Koshy 				return (-1);
2363ebccf1e3SJoseph Koshy 			if ((pe == PMC_EV_P6_BUS_DRDY_CLOCKS ||
2364ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_BUS_LOCK_CLOCKS ||
2365ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_BUS_TRAN_BRD ||
2366ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_BUS_TRAN_RFO ||
2367ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_BUS_TRAN_IFETCH ||
2368ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_BUS_TRAN_INVAL ||
2369ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_BUS_TRAN_PWR ||
2370ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_BUS_TRAN_DEF ||
2371ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_BUS_TRAN_BURST ||
2372ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_BUS_TRAN_ANY ||
2373ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_BUS_TRAN_MEM ||
2374ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_BUS_TRANS_IO ||
2375ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_BUS_TRANS_P ||
2376ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_BUS_TRANS_WB ||
2377ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_EMON_EST_TRANS ||
2378ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_EMON_FUSED_UOPS_RET ||
2379ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_EMON_KNI_COMP_INST_RET ||
2380ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_EMON_KNI_INST_RETIRED ||
2381ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_EMON_KNI_PREF_DISPATCHED ||
2382ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_EMON_KNI_PREF_MISS ||
2383ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_EMON_SSE_SSE2_COMP_INST_RETIRED ||
2384ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_EMON_SSE_SSE2_INST_RETIRED ||
2385ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_FP_MMX_TRANS)
2386aa342b1fSJoseph Koshy 			    && (n > 1))	/* Only one mask keyword is allowed. */
2387aa342b1fSJoseph Koshy 				return (-1);
2388ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_QUALIFIER;
2389ebccf1e3SJoseph Koshy 		} else if (KWMATCH(p, P6_KW_USR)) {
2390ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_USER;
2391ebccf1e3SJoseph Koshy 		} else
2392aa342b1fSJoseph Koshy 			return (-1);
2393ebccf1e3SJoseph Koshy 	}
2394ebccf1e3SJoseph Koshy 
2395ebccf1e3SJoseph Koshy 	/* post processing */
2396ebccf1e3SJoseph Koshy 	switch (pe) {
2397ebccf1e3SJoseph Koshy 
2398ebccf1e3SJoseph Koshy 		/*
2399ebccf1e3SJoseph Koshy 		 * The following events default to an evmask of 0
2400ebccf1e3SJoseph Koshy 		 */
2401ebccf1e3SJoseph Koshy 
2402ebccf1e3SJoseph Koshy 		/* default => 'self' */
2403ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_DRDY_CLOCKS:
2404ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_LOCK_CLOCKS:
2405ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_BRD:
2406ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_RFO:
2407ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRANS_WB:
2408ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_IFETCH:
2409ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_INVAL:
2410ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_PWR:
2411ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRANS_P:
2412ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRANS_IO:
2413ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_DEF:
2414ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_BURST:
2415ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_ANY:
2416ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_MEM:
2417ebccf1e3SJoseph Koshy 
2418ebccf1e3SJoseph Koshy 		/* default => 'nta' */
2419ebccf1e3SJoseph Koshy 	case PMC_EV_P6_EMON_KNI_PREF_DISPATCHED:
2420ebccf1e3SJoseph Koshy 	case PMC_EV_P6_EMON_KNI_PREF_MISS:
2421ebccf1e3SJoseph Koshy 
2422ebccf1e3SJoseph Koshy 		/* default => 'packed and scalar' */
2423ebccf1e3SJoseph Koshy 	case PMC_EV_P6_EMON_KNI_INST_RETIRED:
2424ebccf1e3SJoseph Koshy 	case PMC_EV_P6_EMON_KNI_COMP_INST_RET:
2425ebccf1e3SJoseph Koshy 
2426ebccf1e3SJoseph Koshy 		/* default => 'mmx to fp transitions' */
2427ebccf1e3SJoseph Koshy 	case PMC_EV_P6_FP_MMX_TRANS:
2428ebccf1e3SJoseph Koshy 
2429ebccf1e3SJoseph Koshy 		/* default => 'SSE Packed Single' */
2430ebccf1e3SJoseph Koshy 	case PMC_EV_P6_EMON_SSE_SSE2_INST_RETIRED:
2431ebccf1e3SJoseph Koshy 	case PMC_EV_P6_EMON_SSE_SSE2_COMP_INST_RETIRED:
2432ebccf1e3SJoseph Koshy 
2433ebccf1e3SJoseph Koshy 		/* default => 'all fused micro-ops' */
2434ebccf1e3SJoseph Koshy 	case PMC_EV_P6_EMON_FUSED_UOPS_RET:
2435ebccf1e3SJoseph Koshy 
2436ebccf1e3SJoseph Koshy 		/* default => 'all transitions' */
2437ebccf1e3SJoseph Koshy 	case PMC_EV_P6_EMON_EST_TRANS:
2438ebccf1e3SJoseph Koshy 		break;
2439ebccf1e3SJoseph Koshy 
2440ebccf1e3SJoseph Koshy 	case PMC_EV_P6_MMX_UOPS_EXEC:
2441ebccf1e3SJoseph Koshy 		evmask = 0x0F;		/* only value allowed */
2442ebccf1e3SJoseph Koshy 		break;
2443ebccf1e3SJoseph Koshy 
2444ebccf1e3SJoseph Koshy 	default:
2445ebccf1e3SJoseph Koshy 		/*
2446ebccf1e3SJoseph Koshy 		 * For all other events, set the default event mask
2447ebccf1e3SJoseph Koshy 		 * to a logical OR of all the allowed event mask bits.
2448ebccf1e3SJoseph Koshy 		 */
2449ebccf1e3SJoseph Koshy 		if (evmask == 0 && pmask) {
2450ebccf1e3SJoseph Koshy 			for (pm = pmask; pm->pm_name; pm++)
2451ebccf1e3SJoseph Koshy 				evmask |= pm->pm_value;
2452ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_QUALIFIER;
2453ebccf1e3SJoseph Koshy 		}
2454ebccf1e3SJoseph Koshy 
2455ebccf1e3SJoseph Koshy 		break;
2456ebccf1e3SJoseph Koshy 	}
2457ebccf1e3SJoseph Koshy 
2458ebccf1e3SJoseph Koshy 	if (pmc_config->pm_caps & PMC_CAP_QUALIFIER)
2459f263522aSJoseph Koshy 		pmc_config->pm_md.pm_ppro.pm_ppro_config |=
2460f263522aSJoseph Koshy 		    P6_EVSEL_TO_UMASK(evmask);
2461ebccf1e3SJoseph Koshy 
2462aa342b1fSJoseph Koshy 	return (0);
2463ebccf1e3SJoseph Koshy }
2464ebccf1e3SJoseph Koshy 
2465ebccf1e3SJoseph Koshy #endif
2466ebccf1e3SJoseph Koshy 
2467789140c0SJoseph Koshy #if	defined(__i386__) || defined(__amd64__)
2468789140c0SJoseph Koshy static int
2469789140c0SJoseph Koshy tsc_allocate_pmc(enum pmc_event pe, char *ctrspec,
2470789140c0SJoseph Koshy     struct pmc_op_pmcallocate *pmc_config)
2471789140c0SJoseph Koshy {
2472789140c0SJoseph Koshy 	if (pe != PMC_EV_TSC_TSC)
2473789140c0SJoseph Koshy 		return (-1);
2474789140c0SJoseph Koshy 
2475789140c0SJoseph Koshy 	/* TSC events must be unqualified. */
2476789140c0SJoseph Koshy 	if (ctrspec && *ctrspec != '\0')
2477789140c0SJoseph Koshy 		return (-1);
2478789140c0SJoseph Koshy 
2479789140c0SJoseph Koshy 	pmc_config->pm_md.pm_amd.pm_amd_config = 0;
2480789140c0SJoseph Koshy 	pmc_config->pm_caps |= PMC_CAP_READ;
2481789140c0SJoseph Koshy 
2482789140c0SJoseph Koshy 	return (0);
2483789140c0SJoseph Koshy }
2484789140c0SJoseph Koshy #endif
2485789140c0SJoseph Koshy 
2486f5f9340bSFabien Thomas static struct pmc_event_alias generic_aliases[] = {
2487f5f9340bSFabien Thomas 	EV_ALIAS("instructions",		"SOFT-CLOCK.HARD"),
2488f5f9340bSFabien Thomas 	EV_ALIAS(NULL, NULL)
2489f5f9340bSFabien Thomas };
2490f5f9340bSFabien Thomas 
2491f5f9340bSFabien Thomas static int
2492f5f9340bSFabien Thomas soft_allocate_pmc(enum pmc_event pe, char *ctrspec,
2493f5f9340bSFabien Thomas     struct pmc_op_pmcallocate *pmc_config)
2494f5f9340bSFabien Thomas {
2495f5f9340bSFabien Thomas 	(void)ctrspec;
2496f5f9340bSFabien Thomas 	(void)pmc_config;
2497f5f9340bSFabien Thomas 
2498f0bbe9aaSDimitry Andric 	if ((int)pe < PMC_EV_SOFT_FIRST || (int)pe > PMC_EV_SOFT_LAST)
2499f5f9340bSFabien Thomas 		return (-1);
2500f5f9340bSFabien Thomas 
2501f5f9340bSFabien Thomas 	pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE);
2502f5f9340bSFabien Thomas 	return (0);
2503f5f9340bSFabien Thomas }
2504f5f9340bSFabien Thomas 
25056411d14dSRuslan Bukin #if	defined(__arm__)
25060ce207d2SRui Paulo #if	defined(__XSCALE__)
25070ce207d2SRui Paulo 
25080ce207d2SRui Paulo static struct pmc_event_alias xscale_aliases[] = {
25090ce207d2SRui Paulo 	EV_ALIAS("branches",		"BRANCH_RETIRED"),
25100ce207d2SRui Paulo 	EV_ALIAS("branch-mispredicts",	"BRANCH_MISPRED"),
25110ce207d2SRui Paulo 	EV_ALIAS("dc-misses",		"DC_MISS"),
25120ce207d2SRui Paulo 	EV_ALIAS("ic-misses",		"IC_MISS"),
25130ce207d2SRui Paulo 	EV_ALIAS("instructions",	"INSTR_RETIRED"),
25140ce207d2SRui Paulo 	EV_ALIAS(NULL, NULL)
25150ce207d2SRui Paulo };
25160ce207d2SRui Paulo static int
25170ce207d2SRui Paulo xscale_allocate_pmc(enum pmc_event pe, char *ctrspec __unused,
25180ce207d2SRui Paulo     struct pmc_op_pmcallocate *pmc_config __unused)
25190ce207d2SRui Paulo {
25200ce207d2SRui Paulo 	switch (pe) {
25210ce207d2SRui Paulo 	default:
25220ce207d2SRui Paulo 		break;
25230ce207d2SRui Paulo 	}
25240ce207d2SRui Paulo 
25250ce207d2SRui Paulo 	return (0);
25260ce207d2SRui Paulo }
25270ce207d2SRui Paulo #endif
25280ce207d2SRui Paulo 
25293e0bfdd8SRuslan Bukin static struct pmc_event_alias cortex_a8_aliases[] = {
25306411d14dSRuslan Bukin 	EV_ALIAS("dc-misses",		"L1_DCACHE_REFILL"),
25316411d14dSRuslan Bukin 	EV_ALIAS("ic-misses",		"L1_ICACHE_REFILL"),
25326411d14dSRuslan Bukin 	EV_ALIAS("instructions",	"INSTR_EXECUTED"),
25336411d14dSRuslan Bukin 	EV_ALIAS(NULL, NULL)
25346411d14dSRuslan Bukin };
25353e0bfdd8SRuslan Bukin 
25363e0bfdd8SRuslan Bukin static struct pmc_event_alias cortex_a9_aliases[] = {
25373e0bfdd8SRuslan Bukin 	EV_ALIAS("dc-misses",		"L1_DCACHE_REFILL"),
25383e0bfdd8SRuslan Bukin 	EV_ALIAS("ic-misses",		"L1_ICACHE_REFILL"),
25393e0bfdd8SRuslan Bukin 	EV_ALIAS("instructions",	"INSTR_EXECUTED"),
25403e0bfdd8SRuslan Bukin 	EV_ALIAS(NULL, NULL)
25413e0bfdd8SRuslan Bukin };
25423e0bfdd8SRuslan Bukin 
25436411d14dSRuslan Bukin static int
25446411d14dSRuslan Bukin armv7_allocate_pmc(enum pmc_event pe, char *ctrspec __unused,
25456411d14dSRuslan Bukin     struct pmc_op_pmcallocate *pmc_config __unused)
25466411d14dSRuslan Bukin {
25476411d14dSRuslan Bukin 	switch (pe) {
25486411d14dSRuslan Bukin 	default:
25496411d14dSRuslan Bukin 		break;
25506411d14dSRuslan Bukin 	}
25516411d14dSRuslan Bukin 
25526411d14dSRuslan Bukin 	return (0);
25536411d14dSRuslan Bukin }
25546411d14dSRuslan Bukin #endif
25556411d14dSRuslan Bukin 
2556bc88bb2bSRuslan Bukin #if	defined(__aarch64__)
2557bc88bb2bSRuslan Bukin static struct pmc_event_alias cortex_a53_aliases[] = {
2558bc88bb2bSRuslan Bukin 	EV_ALIAS(NULL, NULL)
2559bc88bb2bSRuslan Bukin };
2560bc88bb2bSRuslan Bukin static struct pmc_event_alias cortex_a57_aliases[] = {
2561bc88bb2bSRuslan Bukin 	EV_ALIAS(NULL, NULL)
2562bc88bb2bSRuslan Bukin };
2563bc88bb2bSRuslan Bukin static int
2564bc88bb2bSRuslan Bukin arm64_allocate_pmc(enum pmc_event pe, char *ctrspec __unused,
2565bc88bb2bSRuslan Bukin     struct pmc_op_pmcallocate *pmc_config __unused)
2566bc88bb2bSRuslan Bukin {
2567bc88bb2bSRuslan Bukin 	switch (pe) {
2568bc88bb2bSRuslan Bukin 	default:
2569bc88bb2bSRuslan Bukin 		break;
2570bc88bb2bSRuslan Bukin 	}
2571bc88bb2bSRuslan Bukin 
2572bc88bb2bSRuslan Bukin 	return (0);
2573bc88bb2bSRuslan Bukin }
2574bc88bb2bSRuslan Bukin #endif
2575bc88bb2bSRuslan Bukin 
2576660df75eSGeorge V. Neville-Neil #if defined(__mips__)
2577660df75eSGeorge V. Neville-Neil 
2578660df75eSGeorge V. Neville-Neil static struct pmc_event_alias mips24k_aliases[] = {
2579660df75eSGeorge V. Neville-Neil 	EV_ALIAS("instructions",	"INSTR_EXECUTED"),
2580660df75eSGeorge V. Neville-Neil 	EV_ALIAS("branches",		"BRANCH_COMPLETED"),
2581660df75eSGeorge V. Neville-Neil 	EV_ALIAS("branch-mispredicts",	"BRANCH_MISPRED"),
2582660df75eSGeorge V. Neville-Neil 	EV_ALIAS(NULL, NULL)
2583660df75eSGeorge V. Neville-Neil };
2584660df75eSGeorge V. Neville-Neil 
2585f6e6460dSAdrian Chadd static struct pmc_event_alias mips74k_aliases[] = {
2586f6e6460dSAdrian Chadd 	EV_ALIAS("instructions",	"INSTR_EXECUTED"),
2587f6e6460dSAdrian Chadd 	EV_ALIAS("branches",		"BRANCH_INSNS"),
2588f6e6460dSAdrian Chadd 	EV_ALIAS("branch-mispredicts",	"MISPREDICTED_BRANCH_INSNS"),
2589f6e6460dSAdrian Chadd 	EV_ALIAS(NULL, NULL)
2590f6e6460dSAdrian Chadd };
2591f6e6460dSAdrian Chadd 
2592c2657f80SOleksandr Tymoshenko static struct pmc_event_alias octeon_aliases[] = {
2593c2657f80SOleksandr Tymoshenko 	EV_ALIAS("instructions",	"RET"),
2594c2657f80SOleksandr Tymoshenko 	EV_ALIAS("branches",		"BR"),
2595c2657f80SOleksandr Tymoshenko 	EV_ALIAS("branch-mispredicts",	"BRMIS"),
2596c2657f80SOleksandr Tymoshenko 	EV_ALIAS(NULL, NULL)
2597c2657f80SOleksandr Tymoshenko };
2598c2657f80SOleksandr Tymoshenko 
25992827d3e1SOleksandr Tymoshenko #define	MIPS_KW_OS		"os"
26002827d3e1SOleksandr Tymoshenko #define	MIPS_KW_USR		"usr"
26012827d3e1SOleksandr Tymoshenko #define	MIPS_KW_ANYTHREAD	"anythread"
2602660df75eSGeorge V. Neville-Neil 
2603660df75eSGeorge V. Neville-Neil static int
26042827d3e1SOleksandr Tymoshenko mips_allocate_pmc(enum pmc_event pe, char *ctrspec __unused,
2605660df75eSGeorge V. Neville-Neil 		  struct pmc_op_pmcallocate *pmc_config __unused)
2606660df75eSGeorge V. Neville-Neil {
2607660df75eSGeorge V. Neville-Neil 	char *p;
2608660df75eSGeorge V. Neville-Neil 
2609660df75eSGeorge V. Neville-Neil 	(void) pe;
2610660df75eSGeorge V. Neville-Neil 
2611660df75eSGeorge V. Neville-Neil 	pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE);
2612660df75eSGeorge V. Neville-Neil 
2613660df75eSGeorge V. Neville-Neil 	while ((p = strsep(&ctrspec, ",")) != NULL) {
26142827d3e1SOleksandr Tymoshenko 		if (KWMATCH(p, MIPS_KW_OS))
2615660df75eSGeorge V. Neville-Neil 			pmc_config->pm_caps |= PMC_CAP_SYSTEM;
26162827d3e1SOleksandr Tymoshenko 		else if (KWMATCH(p, MIPS_KW_USR))
2617660df75eSGeorge V. Neville-Neil 			pmc_config->pm_caps |= PMC_CAP_USER;
26182827d3e1SOleksandr Tymoshenko 		else if (KWMATCH(p, MIPS_KW_ANYTHREAD))
2619660df75eSGeorge V. Neville-Neil 			pmc_config->pm_caps |= (PMC_CAP_USER | PMC_CAP_SYSTEM);
2620660df75eSGeorge V. Neville-Neil 		else
2621660df75eSGeorge V. Neville-Neil 			return (-1);
2622660df75eSGeorge V. Neville-Neil 	}
2623660df75eSGeorge V. Neville-Neil 
2624660df75eSGeorge V. Neville-Neil 	return (0);
2625660df75eSGeorge V. Neville-Neil }
26262827d3e1SOleksandr Tymoshenko 
2627660df75eSGeorge V. Neville-Neil #endif /* __mips__ */
2628660df75eSGeorge V. Neville-Neil 
26297b25dccaSJustin Hibbits #if defined(__powerpc__)
26307b25dccaSJustin Hibbits 
26317b25dccaSJustin Hibbits static struct pmc_event_alias ppc7450_aliases[] = {
26327b25dccaSJustin Hibbits 	EV_ALIAS("instructions",	"INSTR_COMPLETED"),
26337b25dccaSJustin Hibbits 	EV_ALIAS("branches",		"BRANCHES_COMPLETED"),
26347b25dccaSJustin Hibbits 	EV_ALIAS("branch-mispredicts",	"MISPREDICTED_BRANCHES"),
26357b25dccaSJustin Hibbits 	EV_ALIAS(NULL, NULL)
26367b25dccaSJustin Hibbits };
26377b25dccaSJustin Hibbits 
2638169dd953SJustin Hibbits static struct pmc_event_alias ppc970_aliases[] = {
2639169dd953SJustin Hibbits 	EV_ALIAS("instructions", "INSTR_COMPLETED"),
2640169dd953SJustin Hibbits 	EV_ALIAS("cycles",       "CYCLES"),
2641169dd953SJustin Hibbits 	EV_ALIAS(NULL, NULL)
2642169dd953SJustin Hibbits };
2643169dd953SJustin Hibbits 
2644a7452468SJustin Hibbits static struct pmc_event_alias e500_aliases[] = {
2645a7452468SJustin Hibbits 	EV_ALIAS("instructions", "INSTR_COMPLETED"),
2646a7452468SJustin Hibbits 	EV_ALIAS("cycles",       "CYCLES"),
2647a7452468SJustin Hibbits 	EV_ALIAS(NULL, NULL)
2648a7452468SJustin Hibbits };
2649a7452468SJustin Hibbits 
2650169dd953SJustin Hibbits #define	POWERPC_KW_OS		"os"
2651169dd953SJustin Hibbits #define	POWERPC_KW_USR		"usr"
2652169dd953SJustin Hibbits #define	POWERPC_KW_ANYTHREAD	"anythread"
26537b25dccaSJustin Hibbits 
26547b25dccaSJustin Hibbits static int
2655169dd953SJustin Hibbits powerpc_allocate_pmc(enum pmc_event pe, char *ctrspec __unused,
26567b25dccaSJustin Hibbits 		     struct pmc_op_pmcallocate *pmc_config __unused)
26577b25dccaSJustin Hibbits {
26587b25dccaSJustin Hibbits 	char *p;
26597b25dccaSJustin Hibbits 
26607b25dccaSJustin Hibbits 	(void) pe;
26617b25dccaSJustin Hibbits 
26627b25dccaSJustin Hibbits 	pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE);
26637b25dccaSJustin Hibbits 
26647b25dccaSJustin Hibbits 	while ((p = strsep(&ctrspec, ",")) != NULL) {
2665169dd953SJustin Hibbits 		if (KWMATCH(p, POWERPC_KW_OS))
26667b25dccaSJustin Hibbits 			pmc_config->pm_caps |= PMC_CAP_SYSTEM;
2667169dd953SJustin Hibbits 		else if (KWMATCH(p, POWERPC_KW_USR))
26687b25dccaSJustin Hibbits 			pmc_config->pm_caps |= PMC_CAP_USER;
2669169dd953SJustin Hibbits 		else if (KWMATCH(p, POWERPC_KW_ANYTHREAD))
26707b25dccaSJustin Hibbits 			pmc_config->pm_caps |= (PMC_CAP_USER | PMC_CAP_SYSTEM);
26717b25dccaSJustin Hibbits 		else
26727b25dccaSJustin Hibbits 			return (-1);
26737b25dccaSJustin Hibbits 	}
26747b25dccaSJustin Hibbits 
26757b25dccaSJustin Hibbits 	return (0);
26767b25dccaSJustin Hibbits }
2677169dd953SJustin Hibbits 
26787b25dccaSJustin Hibbits #endif /* __powerpc__ */
26797b25dccaSJustin Hibbits 
2680660df75eSGeorge V. Neville-Neil 
2681789140c0SJoseph Koshy /*
2682789140c0SJoseph Koshy  * Match an event name `name' with its canonical form.
2683789140c0SJoseph Koshy  *
26840cfab8ddSJoseph Koshy  * Matches are case insensitive and spaces, periods, underscores and
26850cfab8ddSJoseph Koshy  * hyphen characters are considered to match each other.
2686789140c0SJoseph Koshy  *
2687789140c0SJoseph Koshy  * Returns 1 for a match, 0 otherwise.
2688789140c0SJoseph Koshy  */
2689789140c0SJoseph Koshy 
2690789140c0SJoseph Koshy static int
2691789140c0SJoseph Koshy pmc_match_event_name(const char *name, const char *canonicalname)
2692789140c0SJoseph Koshy {
2693789140c0SJoseph Koshy 	int cc, nc;
2694789140c0SJoseph Koshy 	const unsigned char *c, *n;
2695789140c0SJoseph Koshy 
2696789140c0SJoseph Koshy 	c = (const unsigned char *) canonicalname;
2697789140c0SJoseph Koshy 	n = (const unsigned char *) name;
2698789140c0SJoseph Koshy 
2699789140c0SJoseph Koshy 	for (; (nc = *n) && (cc = *c); n++, c++) {
2700789140c0SJoseph Koshy 
27010cfab8ddSJoseph Koshy 		if ((nc == ' ' || nc == '_' || nc == '-' || nc == '.') &&
27020cfab8ddSJoseph Koshy 		    (cc == ' ' || cc == '_' || cc == '-' || cc == '.'))
2703789140c0SJoseph Koshy 			continue;
2704789140c0SJoseph Koshy 
27050cfab8ddSJoseph Koshy 		if (toupper(nc) == toupper(cc))
2706789140c0SJoseph Koshy 			continue;
2707789140c0SJoseph Koshy 
27080cfab8ddSJoseph Koshy 
2709789140c0SJoseph Koshy 		return (0);
2710789140c0SJoseph Koshy 	}
2711789140c0SJoseph Koshy 
2712789140c0SJoseph Koshy 	if (*n == '\0' && *c == '\0')
2713789140c0SJoseph Koshy 		return (1);
2714789140c0SJoseph Koshy 
2715789140c0SJoseph Koshy 	return (0);
2716789140c0SJoseph Koshy }
2717789140c0SJoseph Koshy 
2718789140c0SJoseph Koshy /*
2719789140c0SJoseph Koshy  * Match an event name against all the event named supported by a
2720789140c0SJoseph Koshy  * PMC class.
2721789140c0SJoseph Koshy  *
2722789140c0SJoseph Koshy  * Returns an event descriptor pointer on match or NULL otherwise.
2723789140c0SJoseph Koshy  */
2724789140c0SJoseph Koshy static const struct pmc_event_descr *
2725789140c0SJoseph Koshy pmc_match_event_class(const char *name,
2726789140c0SJoseph Koshy     const struct pmc_class_descr *pcd)
2727789140c0SJoseph Koshy {
2728789140c0SJoseph Koshy 	size_t n;
2729789140c0SJoseph Koshy 	const struct pmc_event_descr *ev;
2730789140c0SJoseph Koshy 
2731789140c0SJoseph Koshy 	ev = pcd->pm_evc_event_table;
2732789140c0SJoseph Koshy 	for (n = 0; n < pcd->pm_evc_event_table_size; n++, ev++)
2733789140c0SJoseph Koshy 		if (pmc_match_event_name(name, ev->pm_ev_name))
2734789140c0SJoseph Koshy 			return (ev);
2735789140c0SJoseph Koshy 
2736789140c0SJoseph Koshy 	return (NULL);
2737789140c0SJoseph Koshy }
2738789140c0SJoseph Koshy 
2739789140c0SJoseph Koshy static int
2740789140c0SJoseph Koshy pmc_mdep_is_compatible_class(enum pmc_class pc)
2741789140c0SJoseph Koshy {
2742789140c0SJoseph Koshy 	size_t n;
2743789140c0SJoseph Koshy 
2744789140c0SJoseph Koshy 	for (n = 0; n < pmc_mdep_class_list_size; n++)
2745789140c0SJoseph Koshy 		if (pmc_mdep_class_list[n] == pc)
2746789140c0SJoseph Koshy 			return (1);
2747789140c0SJoseph Koshy 	return (0);
2748789140c0SJoseph Koshy }
2749789140c0SJoseph Koshy 
2750ebccf1e3SJoseph Koshy /*
2751ebccf1e3SJoseph Koshy  * API entry points
2752ebccf1e3SJoseph Koshy  */
2753ebccf1e3SJoseph Koshy 
2754ebccf1e3SJoseph Koshy int
2755ebccf1e3SJoseph Koshy pmc_allocate(const char *ctrspec, enum pmc_mode mode,
2756ebccf1e3SJoseph Koshy     uint32_t flags, int cpu, pmc_id_t *pmcid)
2757ebccf1e3SJoseph Koshy {
2758789140c0SJoseph Koshy 	size_t n;
2759ebccf1e3SJoseph Koshy 	int retval;
2760ebccf1e3SJoseph Koshy 	char *r, *spec_copy;
2761ebccf1e3SJoseph Koshy 	const char *ctrname;
2762789140c0SJoseph Koshy 	const struct pmc_event_descr *ev;
2763789140c0SJoseph Koshy 	const struct pmc_event_alias *alias;
2764ebccf1e3SJoseph Koshy 	struct pmc_op_pmcallocate pmc_config;
2765789140c0SJoseph Koshy 	const struct pmc_class_descr *pcd;
2766ebccf1e3SJoseph Koshy 
2767ebccf1e3SJoseph Koshy 	spec_copy = NULL;
2768ebccf1e3SJoseph Koshy 	retval    = -1;
2769ebccf1e3SJoseph Koshy 
2770ebccf1e3SJoseph Koshy 	if (mode != PMC_MODE_SS && mode != PMC_MODE_TS &&
2771ebccf1e3SJoseph Koshy 	    mode != PMC_MODE_SC && mode != PMC_MODE_TC) {
2772ebccf1e3SJoseph Koshy 		errno = EINVAL;
2773ebccf1e3SJoseph Koshy 		goto out;
2774ebccf1e3SJoseph Koshy 	}
2775ebccf1e3SJoseph Koshy 
2776ebccf1e3SJoseph Koshy 	/* replace an event alias with the canonical event specifier */
2777ebccf1e3SJoseph Koshy 	if (pmc_mdep_event_aliases)
2778789140c0SJoseph Koshy 		for (alias = pmc_mdep_event_aliases; alias->pm_alias; alias++)
2779789140c0SJoseph Koshy 			if (!strcasecmp(ctrspec, alias->pm_alias)) {
2780789140c0SJoseph Koshy 				spec_copy = strdup(alias->pm_spec);
2781ebccf1e3SJoseph Koshy 				break;
2782ebccf1e3SJoseph Koshy 			}
2783ebccf1e3SJoseph Koshy 
2784ebccf1e3SJoseph Koshy 	if (spec_copy == NULL)
2785ebccf1e3SJoseph Koshy 		spec_copy = strdup(ctrspec);
2786ebccf1e3SJoseph Koshy 
2787ebccf1e3SJoseph Koshy 	r = spec_copy;
2788ebccf1e3SJoseph Koshy 	ctrname = strsep(&r, ",");
2789ebccf1e3SJoseph Koshy 
2790789140c0SJoseph Koshy 	/*
2791789140c0SJoseph Koshy 	 * If a explicit class prefix was given by the user, restrict the
2792789140c0SJoseph Koshy 	 * search for the event to the specified PMC class.
2793789140c0SJoseph Koshy 	 */
2794789140c0SJoseph Koshy 	ev = NULL;
27950cfab8ddSJoseph Koshy 	for (n = 0; n < PMC_CLASS_TABLE_SIZE; n++) {
27960cfab8ddSJoseph Koshy 		pcd = pmc_class_table[n];
2797789140c0SJoseph Koshy 		if (pmc_mdep_is_compatible_class(pcd->pm_evc_class) &&
2798789140c0SJoseph Koshy 		    strncasecmp(ctrname, pcd->pm_evc_name,
2799789140c0SJoseph Koshy 				pcd->pm_evc_name_size) == 0) {
2800789140c0SJoseph Koshy 			if ((ev = pmc_match_event_class(ctrname +
2801789140c0SJoseph Koshy 			    pcd->pm_evc_name_size, pcd)) == NULL) {
2802789140c0SJoseph Koshy 				errno = EINVAL;
2803789140c0SJoseph Koshy 				goto out;
2804789140c0SJoseph Koshy 			}
2805ebccf1e3SJoseph Koshy 			break;
2806789140c0SJoseph Koshy 		}
2807789140c0SJoseph Koshy 	}
2808ebccf1e3SJoseph Koshy 
2809789140c0SJoseph Koshy 	/*
2810789140c0SJoseph Koshy 	 * Otherwise, search for this event in all compatible PMC
2811789140c0SJoseph Koshy 	 * classes.
2812789140c0SJoseph Koshy 	 */
28130cfab8ddSJoseph Koshy 	for (n = 0; ev == NULL && n < PMC_CLASS_TABLE_SIZE; n++) {
28140cfab8ddSJoseph Koshy 		pcd = pmc_class_table[n];
2815789140c0SJoseph Koshy 		if (pmc_mdep_is_compatible_class(pcd->pm_evc_class))
2816789140c0SJoseph Koshy 			ev = pmc_match_event_class(ctrname, pcd);
2817789140c0SJoseph Koshy 	}
2818789140c0SJoseph Koshy 
2819789140c0SJoseph Koshy 	if (ev == NULL) {
2820ebccf1e3SJoseph Koshy 		errno = EINVAL;
2821ebccf1e3SJoseph Koshy 		goto out;
2822ebccf1e3SJoseph Koshy 	}
2823ebccf1e3SJoseph Koshy 
2824ebccf1e3SJoseph Koshy 	bzero(&pmc_config, sizeof(pmc_config));
2825789140c0SJoseph Koshy 	pmc_config.pm_ev    = ev->pm_ev_code;
2826789140c0SJoseph Koshy 	pmc_config.pm_class = pcd->pm_evc_class;
2827ebccf1e3SJoseph Koshy 	pmc_config.pm_cpu   = cpu;
2828ebccf1e3SJoseph Koshy 	pmc_config.pm_mode  = mode;
2829ebccf1e3SJoseph Koshy 	pmc_config.pm_flags = flags;
2830ebccf1e3SJoseph Koshy 
2831ebccf1e3SJoseph Koshy 	if (PMC_IS_SAMPLING_MODE(mode))
2832ebccf1e3SJoseph Koshy 		pmc_config.pm_caps |= PMC_CAP_INTERRUPT;
2833ebccf1e3SJoseph Koshy 
2834789140c0SJoseph Koshy  	if (pcd->pm_evc_allocate_pmc(ev->pm_ev_code, r, &pmc_config) < 0) {
2835ebccf1e3SJoseph Koshy 		errno = EINVAL;
2836ebccf1e3SJoseph Koshy 		goto out;
2837ebccf1e3SJoseph Koshy 	}
2838ebccf1e3SJoseph Koshy 
2839ebccf1e3SJoseph Koshy 	if (PMC_CALL(PMCALLOCATE, &pmc_config) < 0)
2840ebccf1e3SJoseph Koshy 		goto out;
2841ebccf1e3SJoseph Koshy 
2842ebccf1e3SJoseph Koshy 	*pmcid = pmc_config.pm_pmcid;
2843ebccf1e3SJoseph Koshy 
2844ebccf1e3SJoseph Koshy 	retval = 0;
2845ebccf1e3SJoseph Koshy 
2846ebccf1e3SJoseph Koshy  out:
2847ebccf1e3SJoseph Koshy 	if (spec_copy)
2848ebccf1e3SJoseph Koshy 		free(spec_copy);
2849ebccf1e3SJoseph Koshy 
2850aa342b1fSJoseph Koshy 	return (retval);
2851ebccf1e3SJoseph Koshy }
2852ebccf1e3SJoseph Koshy 
2853ebccf1e3SJoseph Koshy int
2854ebccf1e3SJoseph Koshy pmc_attach(pmc_id_t pmc, pid_t pid)
2855ebccf1e3SJoseph Koshy {
2856ebccf1e3SJoseph Koshy 	struct pmc_op_pmcattach pmc_attach_args;
2857ebccf1e3SJoseph Koshy 
2858ebccf1e3SJoseph Koshy 	pmc_attach_args.pm_pmc = pmc;
2859ebccf1e3SJoseph Koshy 	pmc_attach_args.pm_pid = pid;
2860ebccf1e3SJoseph Koshy 
2861aa342b1fSJoseph Koshy 	return (PMC_CALL(PMCATTACH, &pmc_attach_args));
2862ebccf1e3SJoseph Koshy }
2863ebccf1e3SJoseph Koshy 
2864ebccf1e3SJoseph Koshy int
2865c5153e19SJoseph Koshy pmc_capabilities(pmc_id_t pmcid, uint32_t *caps)
2866c5153e19SJoseph Koshy {
2867c5153e19SJoseph Koshy 	unsigned int i;
2868c5153e19SJoseph Koshy 	enum pmc_class cl;
2869c5153e19SJoseph Koshy 
2870c5153e19SJoseph Koshy 	cl = PMC_ID_TO_CLASS(pmcid);
2871c5153e19SJoseph Koshy 	for (i = 0; i < cpu_info.pm_nclass; i++)
2872c5153e19SJoseph Koshy 		if (cpu_info.pm_classes[i].pm_class == cl) {
2873c5153e19SJoseph Koshy 			*caps = cpu_info.pm_classes[i].pm_caps;
2874aa342b1fSJoseph Koshy 			return (0);
2875c5153e19SJoseph Koshy 		}
2876484202faSJoseph Koshy 	errno = EINVAL;
2877484202faSJoseph Koshy 	return (-1);
2878c5153e19SJoseph Koshy }
2879c5153e19SJoseph Koshy 
2880f263522aSJoseph Koshy int
2881f263522aSJoseph Koshy pmc_configure_logfile(int fd)
2882ebccf1e3SJoseph Koshy {
2883f263522aSJoseph Koshy 	struct pmc_op_configurelog cla;
2884f263522aSJoseph Koshy 
2885f263522aSJoseph Koshy 	cla.pm_logfd = fd;
2886f263522aSJoseph Koshy 	if (PMC_CALL(CONFIGURELOG, &cla) < 0)
2887aa342b1fSJoseph Koshy 		return (-1);
2888aa342b1fSJoseph Koshy 	return (0);
2889ebccf1e3SJoseph Koshy }
2890ebccf1e3SJoseph Koshy 
2891f263522aSJoseph Koshy int
2892f263522aSJoseph Koshy pmc_cpuinfo(const struct pmc_cpuinfo **pci)
2893ebccf1e3SJoseph Koshy {
2894f263522aSJoseph Koshy 	if (pmc_syscall == -1) {
2895f263522aSJoseph Koshy 		errno = ENXIO;
2896aa342b1fSJoseph Koshy 		return (-1);
2897ebccf1e3SJoseph Koshy 	}
2898ebccf1e3SJoseph Koshy 
28991455fcd3SJoseph Koshy 	*pci = &cpu_info;
2900aa342b1fSJoseph Koshy 	return (0);
2901ebccf1e3SJoseph Koshy }
2902ebccf1e3SJoseph Koshy 
2903f263522aSJoseph Koshy int
2904f263522aSJoseph Koshy pmc_detach(pmc_id_t pmc, pid_t pid)
2905ebccf1e3SJoseph Koshy {
2906f263522aSJoseph Koshy 	struct pmc_op_pmcattach pmc_detach_args;
2907ebccf1e3SJoseph Koshy 
2908f263522aSJoseph Koshy 	pmc_detach_args.pm_pmc = pmc;
2909f263522aSJoseph Koshy 	pmc_detach_args.pm_pid = pid;
2910aa342b1fSJoseph Koshy 	return (PMC_CALL(PMCDETACH, &pmc_detach_args));
2911ebccf1e3SJoseph Koshy }
2912ebccf1e3SJoseph Koshy 
2913f263522aSJoseph Koshy int
2914f263522aSJoseph Koshy pmc_disable(int cpu, int pmc)
2915ebccf1e3SJoseph Koshy {
2916f263522aSJoseph Koshy 	struct pmc_op_pmcadmin ssa;
2917ebccf1e3SJoseph Koshy 
2918f263522aSJoseph Koshy 	ssa.pm_cpu = cpu;
2919f263522aSJoseph Koshy 	ssa.pm_pmc = pmc;
2920f263522aSJoseph Koshy 	ssa.pm_state = PMC_STATE_DISABLED;
2921aa342b1fSJoseph Koshy 	return (PMC_CALL(PMCADMIN, &ssa));
2922ebccf1e3SJoseph Koshy }
2923ebccf1e3SJoseph Koshy 
2924f263522aSJoseph Koshy int
2925f263522aSJoseph Koshy pmc_enable(int cpu, int pmc)
2926ebccf1e3SJoseph Koshy {
2927f263522aSJoseph Koshy 	struct pmc_op_pmcadmin ssa;
2928ebccf1e3SJoseph Koshy 
2929f263522aSJoseph Koshy 	ssa.pm_cpu = cpu;
2930f263522aSJoseph Koshy 	ssa.pm_pmc = pmc;
2931f263522aSJoseph Koshy 	ssa.pm_state = PMC_STATE_FREE;
2932aa342b1fSJoseph Koshy 	return (PMC_CALL(PMCADMIN, &ssa));
2933ebccf1e3SJoseph Koshy }
2934ebccf1e3SJoseph Koshy 
2935ebccf1e3SJoseph Koshy /*
2936ebccf1e3SJoseph Koshy  * Return a list of events known to a given PMC class.  'cl' is the
2937ebccf1e3SJoseph Koshy  * PMC class identifier, 'eventnames' is the returned list of 'const
2938ebccf1e3SJoseph Koshy  * char *' pointers pointing to the names of the events. 'nevents' is
2939ebccf1e3SJoseph Koshy  * the number of event name pointers returned.
2940ebccf1e3SJoseph Koshy  *
2941ebccf1e3SJoseph Koshy  * The space for 'eventnames' is allocated using malloc(3).  The caller
2942ebccf1e3SJoseph Koshy  * is responsible for freeing this space when done.
2943ebccf1e3SJoseph Koshy  */
2944ebccf1e3SJoseph Koshy int
2945ebccf1e3SJoseph Koshy pmc_event_names_of_class(enum pmc_class cl, const char ***eventnames,
2946ebccf1e3SJoseph Koshy     int *nevents)
2947ebccf1e3SJoseph Koshy {
2948ebccf1e3SJoseph Koshy 	int count;
2949ebccf1e3SJoseph Koshy 	const char **names;
2950ebccf1e3SJoseph Koshy 	const struct pmc_event_descr *ev;
2951ebccf1e3SJoseph Koshy 
2952ebccf1e3SJoseph Koshy 	switch (cl)
2953ebccf1e3SJoseph Koshy 	{
29540cfab8ddSJoseph Koshy 	case PMC_CLASS_IAF:
29550cfab8ddSJoseph Koshy 		ev = iaf_event_table;
29560cfab8ddSJoseph Koshy 		count = PMC_EVENT_TABLE_SIZE(iaf);
29570cfab8ddSJoseph Koshy 		break;
29580cfab8ddSJoseph Koshy 	case PMC_CLASS_IAP:
29590cfab8ddSJoseph Koshy 		/*
29600cfab8ddSJoseph Koshy 		 * Return the most appropriate set of event name
29610cfab8ddSJoseph Koshy 		 * spellings for the current CPU.
29620cfab8ddSJoseph Koshy 		 */
29630cfab8ddSJoseph Koshy 		switch (cpu_info.pm_cputype) {
29640cfab8ddSJoseph Koshy 		default:
29650cfab8ddSJoseph Koshy 		case PMC_CPU_INTEL_ATOM:
29660cfab8ddSJoseph Koshy 			ev = atom_event_table;
29670cfab8ddSJoseph Koshy 			count = PMC_EVENT_TABLE_SIZE(atom);
29680cfab8ddSJoseph Koshy 			break;
2969e8f021a3SHiren Panchasara 		case PMC_CPU_INTEL_ATOM_SILVERMONT:
2970e8f021a3SHiren Panchasara 			ev = atom_silvermont_event_table;
2971e8f021a3SHiren Panchasara 			count = PMC_EVENT_TABLE_SIZE(atom_silvermont);
2972e8f021a3SHiren Panchasara 			break;
29730cfab8ddSJoseph Koshy 		case PMC_CPU_INTEL_CORE:
29740cfab8ddSJoseph Koshy 			ev = core_event_table;
29750cfab8ddSJoseph Koshy 			count = PMC_EVENT_TABLE_SIZE(core);
29760cfab8ddSJoseph Koshy 			break;
29770cfab8ddSJoseph Koshy 		case PMC_CPU_INTEL_CORE2:
2978b4d091f3SJoseph Koshy 		case PMC_CPU_INTEL_CORE2EXTREME:
29790cfab8ddSJoseph Koshy 			ev = core2_event_table;
29800cfab8ddSJoseph Koshy 			count = PMC_EVENT_TABLE_SIZE(core2);
29810cfab8ddSJoseph Koshy 			break;
2982597979c4SJeff Roberson 		case PMC_CPU_INTEL_COREI7:
2983597979c4SJeff Roberson 			ev = corei7_event_table;
2984597979c4SJeff Roberson 			count = PMC_EVENT_TABLE_SIZE(corei7);
2985597979c4SJeff Roberson 			break;
298649fe48abSKonstantin Belousov 		case PMC_CPU_INTEL_NEHALEM_EX:
298749fe48abSKonstantin Belousov 			ev = nehalem_ex_event_table;
298849fe48abSKonstantin Belousov 			count = PMC_EVENT_TABLE_SIZE(nehalem_ex);
298949fe48abSKonstantin Belousov 			break;
2990cc0c1555SSean Bruno 		case PMC_CPU_INTEL_HASWELL:
2991cc0c1555SSean Bruno 			ev = haswell_event_table;
2992cc0c1555SSean Bruno 			count = PMC_EVENT_TABLE_SIZE(haswell);
2993cc0c1555SSean Bruno 			break;
2994d95b3509SRandall Stewart 		case PMC_CPU_INTEL_HASWELL_XEON:
2995d95b3509SRandall Stewart 			ev = haswell_xeon_event_table;
2996d95b3509SRandall Stewart 			count = PMC_EVENT_TABLE_SIZE(haswell_xeon);
2997d95b3509SRandall Stewart 			break;
2998f19bae41SRandall Stewart 		case PMC_CPU_INTEL_BROADWELL:
2999f19bae41SRandall Stewart 			ev = broadwell_event_table;
3000f19bae41SRandall Stewart 			count = PMC_EVENT_TABLE_SIZE(broadwell);
3001f19bae41SRandall Stewart 			break;
3002f19bae41SRandall Stewart 		case PMC_CPU_INTEL_BROADWELL_XEON:
3003f19bae41SRandall Stewart 			ev = broadwell_xeon_event_table;
3004f19bae41SRandall Stewart 			count = PMC_EVENT_TABLE_SIZE(broadwell_xeon);
3005f19bae41SRandall Stewart 			break;
3006f19bae41SRandall Stewart 		case PMC_CPU_INTEL_SKYLAKE:
3007f19bae41SRandall Stewart 			ev = skylake_event_table;
3008f19bae41SRandall Stewart 			count = PMC_EVENT_TABLE_SIZE(skylake);
3009f19bae41SRandall Stewart 			break;
30101e862e5aSFabien Thomas 		case PMC_CPU_INTEL_IVYBRIDGE:
30111e862e5aSFabien Thomas 			ev = ivybridge_event_table;
30121e862e5aSFabien Thomas 			count = PMC_EVENT_TABLE_SIZE(ivybridge);
30131e862e5aSFabien Thomas 			break;
30143f929d8cSSean Bruno 		case PMC_CPU_INTEL_IVYBRIDGE_XEON:
30153f929d8cSSean Bruno 			ev = ivybridge_xeon_event_table;
30163f929d8cSSean Bruno 			count = PMC_EVENT_TABLE_SIZE(ivybridge_xeon);
30173f929d8cSSean Bruno 			break;
301878d763a2SDavide Italiano 		case PMC_CPU_INTEL_SANDYBRIDGE:
301978d763a2SDavide Italiano 			ev = sandybridge_event_table;
302078d763a2SDavide Italiano 			count = PMC_EVENT_TABLE_SIZE(sandybridge);
302178d763a2SDavide Italiano 			break;
3022fabe02f5SSean Bruno 		case PMC_CPU_INTEL_SANDYBRIDGE_XEON:
3023fabe02f5SSean Bruno 			ev = sandybridge_xeon_event_table;
3024fabe02f5SSean Bruno 			count = PMC_EVENT_TABLE_SIZE(sandybridge_xeon);
3025fabe02f5SSean Bruno 			break;
30261fa7f10bSFabien Thomas 		case PMC_CPU_INTEL_WESTMERE:
30271fa7f10bSFabien Thomas 			ev = westmere_event_table;
30281fa7f10bSFabien Thomas 			count = PMC_EVENT_TABLE_SIZE(westmere);
30291fa7f10bSFabien Thomas 			break;
303049fe48abSKonstantin Belousov 		case PMC_CPU_INTEL_WESTMERE_EX:
303149fe48abSKonstantin Belousov 			ev = westmere_ex_event_table;
303249fe48abSKonstantin Belousov 			count = PMC_EVENT_TABLE_SIZE(westmere_ex);
303349fe48abSKonstantin Belousov 			break;
30341fa7f10bSFabien Thomas 		}
30351fa7f10bSFabien Thomas 		break;
30361fa7f10bSFabien Thomas 	case PMC_CLASS_UCF:
30371fa7f10bSFabien Thomas 		ev = ucf_event_table;
30381fa7f10bSFabien Thomas 		count = PMC_EVENT_TABLE_SIZE(ucf);
30391fa7f10bSFabien Thomas 		break;
30401fa7f10bSFabien Thomas 	case PMC_CLASS_UCP:
30411fa7f10bSFabien Thomas 		/*
30421fa7f10bSFabien Thomas 		 * Return the most appropriate set of event name
30431fa7f10bSFabien Thomas 		 * spellings for the current CPU.
30441fa7f10bSFabien Thomas 		 */
30451fa7f10bSFabien Thomas 		switch (cpu_info.pm_cputype) {
30461fa7f10bSFabien Thomas 		default:
30471fa7f10bSFabien Thomas 		case PMC_CPU_INTEL_COREI7:
30481fa7f10bSFabien Thomas 			ev = corei7uc_event_table;
30491fa7f10bSFabien Thomas 			count = PMC_EVENT_TABLE_SIZE(corei7uc);
30501fa7f10bSFabien Thomas 			break;
3051cc0c1555SSean Bruno 		case PMC_CPU_INTEL_HASWELL:
3052cc0c1555SSean Bruno 			ev = haswelluc_event_table;
3053cc0c1555SSean Bruno 			count = PMC_EVENT_TABLE_SIZE(haswelluc);
3054cc0c1555SSean Bruno 			break;
3055f19bae41SRandall Stewart 		case PMC_CPU_INTEL_BROADWELL:
3056f19bae41SRandall Stewart 			ev = broadwelluc_event_table;
3057f19bae41SRandall Stewart 			count = PMC_EVENT_TABLE_SIZE(broadwelluc);
3058f19bae41SRandall Stewart 			break;
305978d763a2SDavide Italiano 		case PMC_CPU_INTEL_SANDYBRIDGE:
306078d763a2SDavide Italiano 			ev = sandybridgeuc_event_table;
306178d763a2SDavide Italiano 			count = PMC_EVENT_TABLE_SIZE(sandybridgeuc);
306278d763a2SDavide Italiano 			break;
30631fa7f10bSFabien Thomas 		case PMC_CPU_INTEL_WESTMERE:
30641fa7f10bSFabien Thomas 			ev = westmereuc_event_table;
30651fa7f10bSFabien Thomas 			count = PMC_EVENT_TABLE_SIZE(westmereuc);
30661fa7f10bSFabien Thomas 			break;
30670cfab8ddSJoseph Koshy 		}
30680cfab8ddSJoseph Koshy 		break;
3069ebccf1e3SJoseph Koshy 	case PMC_CLASS_TSC:
3070789140c0SJoseph Koshy 		ev = tsc_event_table;
3071789140c0SJoseph Koshy 		count = PMC_EVENT_TABLE_SIZE(tsc);
3072ebccf1e3SJoseph Koshy 		break;
3073ebccf1e3SJoseph Koshy 	case PMC_CLASS_K7:
3074789140c0SJoseph Koshy 		ev = k7_event_table;
3075789140c0SJoseph Koshy 		count = PMC_EVENT_TABLE_SIZE(k7);
3076ebccf1e3SJoseph Koshy 		break;
3077ebccf1e3SJoseph Koshy 	case PMC_CLASS_K8:
3078789140c0SJoseph Koshy 		ev = k8_event_table;
3079789140c0SJoseph Koshy 		count = PMC_EVENT_TABLE_SIZE(k8);
3080ebccf1e3SJoseph Koshy 		break;
3081ebccf1e3SJoseph Koshy 	case PMC_CLASS_P4:
3082789140c0SJoseph Koshy 		ev = p4_event_table;
3083789140c0SJoseph Koshy 		count = PMC_EVENT_TABLE_SIZE(p4);
3084789140c0SJoseph Koshy 		break;
3085789140c0SJoseph Koshy 	case PMC_CLASS_P5:
3086789140c0SJoseph Koshy 		ev = p5_event_table;
3087789140c0SJoseph Koshy 		count = PMC_EVENT_TABLE_SIZE(p5);
3088789140c0SJoseph Koshy 		break;
3089789140c0SJoseph Koshy 	case PMC_CLASS_P6:
3090789140c0SJoseph Koshy 		ev = p6_event_table;
3091789140c0SJoseph Koshy 		count = PMC_EVENT_TABLE_SIZE(p6);
3092ebccf1e3SJoseph Koshy 		break;
30930ce207d2SRui Paulo 	case PMC_CLASS_XSCALE:
30940ce207d2SRui Paulo 		ev = xscale_event_table;
30950ce207d2SRui Paulo 		count = PMC_EVENT_TABLE_SIZE(xscale);
30960ce207d2SRui Paulo 		break;
30976411d14dSRuslan Bukin 	case PMC_CLASS_ARMV7:
30983e0bfdd8SRuslan Bukin 		switch (cpu_info.pm_cputype) {
30993e0bfdd8SRuslan Bukin 		default:
31003e0bfdd8SRuslan Bukin 		case PMC_CPU_ARMV7_CORTEX_A8:
31013e0bfdd8SRuslan Bukin 			ev = cortex_a8_event_table;
31023e0bfdd8SRuslan Bukin 			count = PMC_EVENT_TABLE_SIZE(cortex_a8);
31033e0bfdd8SRuslan Bukin 			break;
31043e0bfdd8SRuslan Bukin 		case PMC_CPU_ARMV7_CORTEX_A9:
31053e0bfdd8SRuslan Bukin 			ev = cortex_a9_event_table;
31063e0bfdd8SRuslan Bukin 			count = PMC_EVENT_TABLE_SIZE(cortex_a9);
31073e0bfdd8SRuslan Bukin 			break;
31083e0bfdd8SRuslan Bukin 		}
31096411d14dSRuslan Bukin 		break;
3110bc88bb2bSRuslan Bukin 	case PMC_CLASS_ARMV8:
3111bc88bb2bSRuslan Bukin 		switch (cpu_info.pm_cputype) {
3112bc88bb2bSRuslan Bukin 		default:
3113bc88bb2bSRuslan Bukin 		case PMC_CPU_ARMV8_CORTEX_A53:
3114bc88bb2bSRuslan Bukin 			ev = cortex_a53_event_table;
3115bc88bb2bSRuslan Bukin 			count = PMC_EVENT_TABLE_SIZE(cortex_a53);
3116bc88bb2bSRuslan Bukin 			break;
3117bc88bb2bSRuslan Bukin 		case PMC_CPU_ARMV8_CORTEX_A57:
3118bc88bb2bSRuslan Bukin 			ev = cortex_a57_event_table;
3119bc88bb2bSRuslan Bukin 			count = PMC_EVENT_TABLE_SIZE(cortex_a57);
3120bc88bb2bSRuslan Bukin 			break;
3121bc88bb2bSRuslan Bukin 		}
3122bc88bb2bSRuslan Bukin 		break;
3123660df75eSGeorge V. Neville-Neil 	case PMC_CLASS_MIPS24K:
3124660df75eSGeorge V. Neville-Neil 		ev = mips24k_event_table;
3125660df75eSGeorge V. Neville-Neil 		count = PMC_EVENT_TABLE_SIZE(mips24k);
3126660df75eSGeorge V. Neville-Neil 		break;
3127f6e6460dSAdrian Chadd 	case PMC_CLASS_MIPS74K:
3128f6e6460dSAdrian Chadd 		ev = mips74k_event_table;
3129f6e6460dSAdrian Chadd 		count = PMC_EVENT_TABLE_SIZE(mips74k);
3130f6e6460dSAdrian Chadd 		break;
3131c2657f80SOleksandr Tymoshenko 	case PMC_CLASS_OCTEON:
3132c2657f80SOleksandr Tymoshenko 		ev = octeon_event_table;
3133c2657f80SOleksandr Tymoshenko 		count = PMC_EVENT_TABLE_SIZE(octeon);
3134c2657f80SOleksandr Tymoshenko 		break;
31357b25dccaSJustin Hibbits 	case PMC_CLASS_PPC7450:
31367b25dccaSJustin Hibbits 		ev = ppc7450_event_table;
31377b25dccaSJustin Hibbits 		count = PMC_EVENT_TABLE_SIZE(ppc7450);
31387b25dccaSJustin Hibbits 		break;
3139169dd953SJustin Hibbits 	case PMC_CLASS_PPC970:
3140169dd953SJustin Hibbits 		ev = ppc970_event_table;
3141169dd953SJustin Hibbits 		count = PMC_EVENT_TABLE_SIZE(ppc970);
3142169dd953SJustin Hibbits 		break;
3143a7452468SJustin Hibbits 	case PMC_CLASS_E500:
3144a7452468SJustin Hibbits 		ev = e500_event_table;
3145a7452468SJustin Hibbits 		count = PMC_EVENT_TABLE_SIZE(e500);
3146a7452468SJustin Hibbits 		break;
3147f5f9340bSFabien Thomas 	case PMC_CLASS_SOFT:
3148f5f9340bSFabien Thomas 		ev = soft_event_table;
3149f5f9340bSFabien Thomas 		count = soft_event_info.pm_nevent;
3150f5f9340bSFabien Thomas 		break;
3151ebccf1e3SJoseph Koshy 	default:
3152ebccf1e3SJoseph Koshy 		errno = EINVAL;
3153aa342b1fSJoseph Koshy 		return (-1);
3154ebccf1e3SJoseph Koshy 	}
3155ebccf1e3SJoseph Koshy 
3156ebccf1e3SJoseph Koshy 	if ((names = malloc(count * sizeof(const char *))) == NULL)
3157aa342b1fSJoseph Koshy 		return (-1);
3158ebccf1e3SJoseph Koshy 
3159ebccf1e3SJoseph Koshy 	*eventnames = names;
3160ebccf1e3SJoseph Koshy 	*nevents = count;
3161ebccf1e3SJoseph Koshy 
3162ebccf1e3SJoseph Koshy 	for (;count--; ev++, names++)
3163ebccf1e3SJoseph Koshy 		*names = ev->pm_ev_name;
3164f5f9340bSFabien Thomas 
3165aa342b1fSJoseph Koshy 	return (0);
3166ebccf1e3SJoseph Koshy }
3167ebccf1e3SJoseph Koshy 
3168f263522aSJoseph Koshy int
3169f263522aSJoseph Koshy pmc_flush_logfile(void)
3170f263522aSJoseph Koshy {
3171aa342b1fSJoseph Koshy 	return (PMC_CALL(FLUSHLOG,0));
3172f263522aSJoseph Koshy }
3173ebccf1e3SJoseph Koshy 
3174ebccf1e3SJoseph Koshy int
3175dceed24aSFabien Thomas pmc_close_logfile(void)
3176dceed24aSFabien Thomas {
3177dceed24aSFabien Thomas 	return (PMC_CALL(CLOSELOG,0));
3178dceed24aSFabien Thomas }
3179dceed24aSFabien Thomas 
3180dceed24aSFabien Thomas int
3181f263522aSJoseph Koshy pmc_get_driver_stats(struct pmc_driverstats *ds)
3182ebccf1e3SJoseph Koshy {
3183f263522aSJoseph Koshy 	struct pmc_op_getdriverstats gms;
3184f263522aSJoseph Koshy 
3185f263522aSJoseph Koshy 	if (PMC_CALL(GETDRIVERSTATS, &gms) < 0)
3186aa342b1fSJoseph Koshy 		return (-1);
3187f263522aSJoseph Koshy 
3188f263522aSJoseph Koshy 	/* copy out fields in the current userland<->library interface */
3189f263522aSJoseph Koshy 	ds->pm_intr_ignored    = gms.pm_intr_ignored;
3190f263522aSJoseph Koshy 	ds->pm_intr_processed  = gms.pm_intr_processed;
3191f263522aSJoseph Koshy 	ds->pm_intr_bufferfull = gms.pm_intr_bufferfull;
3192f263522aSJoseph Koshy 	ds->pm_syscalls        = gms.pm_syscalls;
3193f263522aSJoseph Koshy 	ds->pm_syscall_errors  = gms.pm_syscall_errors;
3194f263522aSJoseph Koshy 	ds->pm_buffer_requests = gms.pm_buffer_requests;
3195f263522aSJoseph Koshy 	ds->pm_buffer_requests_failed = gms.pm_buffer_requests_failed;
3196f263522aSJoseph Koshy 	ds->pm_log_sweeps      = gms.pm_log_sweeps;
3197aa342b1fSJoseph Koshy 	return (0);
3198f263522aSJoseph Koshy }
3199f263522aSJoseph Koshy 
3200f263522aSJoseph Koshy int
3201f263522aSJoseph Koshy pmc_get_msr(pmc_id_t pmc, uint32_t *msr)
3202f263522aSJoseph Koshy {
3203f263522aSJoseph Koshy 	struct pmc_op_getmsr gm;
3204ebccf1e3SJoseph Koshy 
3205ebccf1e3SJoseph Koshy 	gm.pm_pmcid = pmc;
3206f263522aSJoseph Koshy 	if (PMC_CALL(PMCGETMSR, &gm) < 0)
3207aa342b1fSJoseph Koshy 		return (-1);
3208ebccf1e3SJoseph Koshy 	*msr = gm.pm_msr;
3209aa342b1fSJoseph Koshy 	return (0);
3210ebccf1e3SJoseph Koshy }
3211ebccf1e3SJoseph Koshy 
3212f263522aSJoseph Koshy int
3213f263522aSJoseph Koshy pmc_init(void)
3214f263522aSJoseph Koshy {
3215f263522aSJoseph Koshy 	int error, pmc_mod_id;
32161455fcd3SJoseph Koshy 	unsigned int n;
3217f263522aSJoseph Koshy 	uint32_t abi_version;
3218f263522aSJoseph Koshy 	struct module_stat pmc_modstat;
32191455fcd3SJoseph Koshy 	struct pmc_op_getcpuinfo op_cpu_info;
3220791f5d5bSJoseph Koshy #if defined(__amd64__) || defined(__i386__)
3221791f5d5bSJoseph Koshy 	int cpu_has_iaf_counters;
3222791f5d5bSJoseph Koshy 	unsigned int t;
3223791f5d5bSJoseph Koshy #endif
3224f263522aSJoseph Koshy 
3225f263522aSJoseph Koshy 	if (pmc_syscall != -1) /* already inited */
3226aa342b1fSJoseph Koshy 		return (0);
3227f263522aSJoseph Koshy 
3228f263522aSJoseph Koshy 	/* retrieve the system call number from the KLD */
3229f263522aSJoseph Koshy 	if ((pmc_mod_id = modfind(PMC_MODULE_NAME)) < 0)
3230aa342b1fSJoseph Koshy 		return (-1);
3231f263522aSJoseph Koshy 
3232f263522aSJoseph Koshy 	pmc_modstat.version = sizeof(struct module_stat);
3233f263522aSJoseph Koshy 	if ((error = modstat(pmc_mod_id, &pmc_modstat)) < 0)
3234aa342b1fSJoseph Koshy 		return (-1);
3235f263522aSJoseph Koshy 
3236f263522aSJoseph Koshy 	pmc_syscall = pmc_modstat.data.intval;
3237f263522aSJoseph Koshy 
3238f263522aSJoseph Koshy 	/* check the kernel module's ABI against our compiled-in version */
3239f263522aSJoseph Koshy 	abi_version = PMC_VERSION;
3240f263522aSJoseph Koshy 	if (PMC_CALL(GETMODULEVERSION, &abi_version) < 0)
3241f263522aSJoseph Koshy 		return (pmc_syscall = -1);
3242f263522aSJoseph Koshy 
3243*75f46cf6SPedro F. Giffuni 	/* ignore patch & minor numbers for the comparison */
3244f263522aSJoseph Koshy 	if ((abi_version & 0xFF000000) != (PMC_VERSION & 0xFF000000)) {
3245f263522aSJoseph Koshy 		errno  = EPROGMISMATCH;
3246f263522aSJoseph Koshy 		return (pmc_syscall = -1);
3247f263522aSJoseph Koshy 	}
3248f263522aSJoseph Koshy 
32491455fcd3SJoseph Koshy 	if (PMC_CALL(GETCPUINFO, &op_cpu_info) < 0)
3250f263522aSJoseph Koshy 		return (pmc_syscall = -1);
3251f263522aSJoseph Koshy 
32521455fcd3SJoseph Koshy 	cpu_info.pm_cputype = op_cpu_info.pm_cputype;
32531455fcd3SJoseph Koshy 	cpu_info.pm_ncpu    = op_cpu_info.pm_ncpu;
32541455fcd3SJoseph Koshy 	cpu_info.pm_npmc    = op_cpu_info.pm_npmc;
32551455fcd3SJoseph Koshy 	cpu_info.pm_nclass  = op_cpu_info.pm_nclass;
32561455fcd3SJoseph Koshy 	for (n = 0; n < cpu_info.pm_nclass; n++)
32571455fcd3SJoseph Koshy 		cpu_info.pm_classes[n] = op_cpu_info.pm_classes[n];
32581455fcd3SJoseph Koshy 
32590cfab8ddSJoseph Koshy 	pmc_class_table = malloc(PMC_CLASS_TABLE_SIZE *
32600cfab8ddSJoseph Koshy 	    sizeof(struct pmc_class_descr *));
32610cfab8ddSJoseph Koshy 
32620cfab8ddSJoseph Koshy 	if (pmc_class_table == NULL)
32630cfab8ddSJoseph Koshy 		return (-1);
32640cfab8ddSJoseph Koshy 
3265791f5d5bSJoseph Koshy 	for (n = 0; n < PMC_CLASS_TABLE_SIZE; n++)
3266791f5d5bSJoseph Koshy 		pmc_class_table[n] = NULL;
32670cfab8ddSJoseph Koshy 
32680cfab8ddSJoseph Koshy 	/*
3269f5f9340bSFabien Thomas 	 * Get soft events list.
3270f5f9340bSFabien Thomas 	 */
3271f5f9340bSFabien Thomas 	soft_event_info.pm_class = PMC_CLASS_SOFT;
3272f5f9340bSFabien Thomas 	if (PMC_CALL(GETDYNEVENTINFO, &soft_event_info) < 0)
3273f5f9340bSFabien Thomas 		return (pmc_syscall = -1);
3274f5f9340bSFabien Thomas 
3275f5f9340bSFabien Thomas 	/* Map soft events to static list. */
3276f5f9340bSFabien Thomas 	for (n = 0; n < soft_event_info.pm_nevent; n++) {
3277f5f9340bSFabien Thomas 		soft_event_table[n].pm_ev_name =
3278f5f9340bSFabien Thomas 		    soft_event_info.pm_events[n].pm_ev_name;
3279f5f9340bSFabien Thomas 		soft_event_table[n].pm_ev_code =
3280f5f9340bSFabien Thomas 		    soft_event_info.pm_events[n].pm_ev_code;
3281f5f9340bSFabien Thomas 	}
3282f5f9340bSFabien Thomas 	soft_class_table_descr.pm_evc_event_table_size = \
3283f5f9340bSFabien Thomas 	    soft_event_info.pm_nevent;
3284f5f9340bSFabien Thomas 	soft_class_table_descr.pm_evc_event_table = \
3285f5f9340bSFabien Thomas 	    soft_event_table;
3286f5f9340bSFabien Thomas 
3287f5f9340bSFabien Thomas 	/*
32880cfab8ddSJoseph Koshy 	 * Fill in the class table.
32890cfab8ddSJoseph Koshy 	 */
32900cfab8ddSJoseph Koshy 	n = 0;
3291f5f9340bSFabien Thomas 
3292f5f9340bSFabien Thomas 	/* Fill soft events information. */
3293f5f9340bSFabien Thomas 	pmc_class_table[n++] = &soft_class_table_descr;
32940cfab8ddSJoseph Koshy #if defined(__amd64__) || defined(__i386__)
3295f5f9340bSFabien Thomas 	if (cpu_info.pm_cputype != PMC_CPU_GENERIC)
32960cfab8ddSJoseph Koshy 		pmc_class_table[n++] = &tsc_class_table_descr;
3297791f5d5bSJoseph Koshy 
3298791f5d5bSJoseph Koshy 	/*
3299791f5d5bSJoseph Koshy  	 * Check if this CPU has fixed function counters.
3300791f5d5bSJoseph Koshy 	 */
3301791f5d5bSJoseph Koshy 	cpu_has_iaf_counters = 0;
3302791f5d5bSJoseph Koshy 	for (t = 0; t < cpu_info.pm_nclass; t++)
33032aef9dd6SFabien Thomas 		if (cpu_info.pm_classes[t].pm_class == PMC_CLASS_IAF &&
33042aef9dd6SFabien Thomas 		    cpu_info.pm_classes[t].pm_num > 0)
3305791f5d5bSJoseph Koshy 			cpu_has_iaf_counters = 1;
33060cfab8ddSJoseph Koshy #endif
33070cfab8ddSJoseph Koshy 
3308789140c0SJoseph Koshy #define	PMC_MDEP_INIT(C) do {					\
3309789140c0SJoseph Koshy 		pmc_mdep_event_aliases    = C##_aliases;	\
3310789140c0SJoseph Koshy 		pmc_mdep_class_list  = C##_pmc_classes;		\
3311789140c0SJoseph Koshy 		pmc_mdep_class_list_size =			\
3312789140c0SJoseph Koshy 		    PMC_TABLE_SIZE(C##_pmc_classes);		\
3313789140c0SJoseph Koshy 	} while (0)
3314789140c0SJoseph Koshy 
3315791f5d5bSJoseph Koshy #define	PMC_MDEP_INIT_INTEL_V2(C) do {					\
3316791f5d5bSJoseph Koshy 		PMC_MDEP_INIT(C);					\
3317791f5d5bSJoseph Koshy 		pmc_class_table[n++] = &iaf_class_table_descr;		\
33182aef9dd6SFabien Thomas 		if (!cpu_has_iaf_counters) 				\
3319791f5d5bSJoseph Koshy 			pmc_mdep_event_aliases =			\
3320791f5d5bSJoseph Koshy 				C##_aliases_without_iaf;		\
3321791f5d5bSJoseph Koshy 		pmc_class_table[n] = &C##_class_table_descr;		\
3322791f5d5bSJoseph Koshy 	} while (0)
3323791f5d5bSJoseph Koshy 
3324789140c0SJoseph Koshy 	/* Configure the event name parser. */
3325f263522aSJoseph Koshy 	switch (cpu_info.pm_cputype) {
3326f263522aSJoseph Koshy #if defined(__i386__)
3327f263522aSJoseph Koshy 	case PMC_CPU_AMD_K7:
3328789140c0SJoseph Koshy 		PMC_MDEP_INIT(k7);
33290cfab8ddSJoseph Koshy 		pmc_class_table[n] = &k7_class_table_descr;
3330f263522aSJoseph Koshy 		break;
3331f263522aSJoseph Koshy 	case PMC_CPU_INTEL_P5:
3332789140c0SJoseph Koshy 		PMC_MDEP_INIT(p5);
33330cfab8ddSJoseph Koshy 		pmc_class_table[n]  = &p5_class_table_descr;
3334f263522aSJoseph Koshy 		break;
3335f263522aSJoseph Koshy 	case PMC_CPU_INTEL_P6:		/* P6 ... Pentium M CPUs have */
3336f263522aSJoseph Koshy 	case PMC_CPU_INTEL_PII:		/* similar PMCs. */
3337f263522aSJoseph Koshy 	case PMC_CPU_INTEL_PIII:
3338f263522aSJoseph Koshy 	case PMC_CPU_INTEL_PM:
3339789140c0SJoseph Koshy 		PMC_MDEP_INIT(p6);
33400cfab8ddSJoseph Koshy 		pmc_class_table[n] = &p6_class_table_descr;
3341f263522aSJoseph Koshy 		break;
334286a65549SJoseph Koshy #endif
334386a65549SJoseph Koshy #if defined(__amd64__) || defined(__i386__)
3344f263522aSJoseph Koshy 	case PMC_CPU_AMD_K8:
3345789140c0SJoseph Koshy 		PMC_MDEP_INIT(k8);
33460cfab8ddSJoseph Koshy 		pmc_class_table[n] = &k8_class_table_descr;
33470cfab8ddSJoseph Koshy 		break;
33480cfab8ddSJoseph Koshy 	case PMC_CPU_INTEL_ATOM:
3349791f5d5bSJoseph Koshy 		PMC_MDEP_INIT_INTEL_V2(atom);
33500cfab8ddSJoseph Koshy 		break;
3351e8f021a3SHiren Panchasara 	case PMC_CPU_INTEL_ATOM_SILVERMONT:
3352e8f021a3SHiren Panchasara 		PMC_MDEP_INIT_INTEL_V2(atom_silvermont);
3353e8f021a3SHiren Panchasara 		break;
33540cfab8ddSJoseph Koshy 	case PMC_CPU_INTEL_CORE:
33550cfab8ddSJoseph Koshy 		PMC_MDEP_INIT(core);
3356bc315bbdSJoseph Koshy 		pmc_class_table[n] = &core_class_table_descr;
33570cfab8ddSJoseph Koshy 		break;
33580cfab8ddSJoseph Koshy 	case PMC_CPU_INTEL_CORE2:
3359b4d091f3SJoseph Koshy 	case PMC_CPU_INTEL_CORE2EXTREME:
3360791f5d5bSJoseph Koshy 		PMC_MDEP_INIT_INTEL_V2(core2);
3361789140c0SJoseph Koshy 		break;
3362597979c4SJeff Roberson 	case PMC_CPU_INTEL_COREI7:
33631fa7f10bSFabien Thomas 		pmc_class_table[n++] = &ucf_class_table_descr;
33641fa7f10bSFabien Thomas 		pmc_class_table[n++] = &corei7uc_class_table_descr;
3365791f5d5bSJoseph Koshy 		PMC_MDEP_INIT_INTEL_V2(corei7);
3366597979c4SJeff Roberson 		break;
336749fe48abSKonstantin Belousov 	case PMC_CPU_INTEL_NEHALEM_EX:
336849fe48abSKonstantin Belousov 		PMC_MDEP_INIT_INTEL_V2(nehalem_ex);
336949fe48abSKonstantin Belousov 		break;
3370cc0c1555SSean Bruno 	case PMC_CPU_INTEL_HASWELL:
3371cc0c1555SSean Bruno 		pmc_class_table[n++] = &ucf_class_table_descr;
3372cc0c1555SSean Bruno 		pmc_class_table[n++] = &haswelluc_class_table_descr;
3373cc0c1555SSean Bruno 		PMC_MDEP_INIT_INTEL_V2(haswell);
3374cc0c1555SSean Bruno 		break;
3375d95b3509SRandall Stewart 	case PMC_CPU_INTEL_HASWELL_XEON:
3376d95b3509SRandall Stewart 		PMC_MDEP_INIT_INTEL_V2(haswell_xeon);
3377d95b3509SRandall Stewart 		break;
3378f19bae41SRandall Stewart 	case PMC_CPU_INTEL_BROADWELL:
3379f19bae41SRandall Stewart 		pmc_class_table[n++] = &ucf_class_table_descr;
3380f19bae41SRandall Stewart 		pmc_class_table[n++] = &broadwelluc_class_table_descr;
3381f19bae41SRandall Stewart 		PMC_MDEP_INIT_INTEL_V2(broadwell);
3382f19bae41SRandall Stewart 		break;
3383f19bae41SRandall Stewart 	case PMC_CPU_INTEL_BROADWELL_XEON:
3384f19bae41SRandall Stewart 		PMC_MDEP_INIT_INTEL_V2(broadwell_xeon);
3385f19bae41SRandall Stewart 		break;
3386f19bae41SRandall Stewart 	case PMC_CPU_INTEL_SKYLAKE:
3387f19bae41SRandall Stewart 		PMC_MDEP_INIT_INTEL_V2(skylake);
3388f19bae41SRandall Stewart 		break;
33891e862e5aSFabien Thomas 	case PMC_CPU_INTEL_IVYBRIDGE:
33901e862e5aSFabien Thomas 		PMC_MDEP_INIT_INTEL_V2(ivybridge);
33911e862e5aSFabien Thomas 		break;
33923f929d8cSSean Bruno 	case PMC_CPU_INTEL_IVYBRIDGE_XEON:
33933f929d8cSSean Bruno 		PMC_MDEP_INIT_INTEL_V2(ivybridge_xeon);
33943f929d8cSSean Bruno 		break;
339578d763a2SDavide Italiano 	case PMC_CPU_INTEL_SANDYBRIDGE:
339678d763a2SDavide Italiano 		pmc_class_table[n++] = &ucf_class_table_descr;
339778d763a2SDavide Italiano 		pmc_class_table[n++] = &sandybridgeuc_class_table_descr;
339878d763a2SDavide Italiano 		PMC_MDEP_INIT_INTEL_V2(sandybridge);
339978d763a2SDavide Italiano 		break;
3400fabe02f5SSean Bruno 	case PMC_CPU_INTEL_SANDYBRIDGE_XEON:
3401fabe02f5SSean Bruno 		PMC_MDEP_INIT_INTEL_V2(sandybridge_xeon);
3402fabe02f5SSean Bruno 		break;
34031fa7f10bSFabien Thomas 	case PMC_CPU_INTEL_WESTMERE:
34041fa7f10bSFabien Thomas 		pmc_class_table[n++] = &ucf_class_table_descr;
34051fa7f10bSFabien Thomas 		pmc_class_table[n++] = &westmereuc_class_table_descr;
34061fa7f10bSFabien Thomas 		PMC_MDEP_INIT_INTEL_V2(westmere);
34071fa7f10bSFabien Thomas 		break;
340849fe48abSKonstantin Belousov 	case PMC_CPU_INTEL_WESTMERE_EX:
340949fe48abSKonstantin Belousov 		PMC_MDEP_INIT_INTEL_V2(westmere_ex);
341049fe48abSKonstantin Belousov 		break;
3411789140c0SJoseph Koshy 	case PMC_CPU_INTEL_PIV:
3412789140c0SJoseph Koshy 		PMC_MDEP_INIT(p4);
34130cfab8ddSJoseph Koshy 		pmc_class_table[n] = &p4_class_table_descr;
3414f263522aSJoseph Koshy 		break;
3415ebccf1e3SJoseph Koshy #endif
3416f5f9340bSFabien Thomas 	case PMC_CPU_GENERIC:
3417f5f9340bSFabien Thomas 		PMC_MDEP_INIT(generic);
3418f5f9340bSFabien Thomas 		break;
34196411d14dSRuslan Bukin #if defined(__arm__)
34200ce207d2SRui Paulo #if defined(__XSCALE__)
34210ce207d2SRui Paulo 	case PMC_CPU_INTEL_XSCALE:
34220ce207d2SRui Paulo 		PMC_MDEP_INIT(xscale);
34230ce207d2SRui Paulo 		pmc_class_table[n] = &xscale_class_table_descr;
34240ce207d2SRui Paulo 		break;
34250ce207d2SRui Paulo #endif
34263e0bfdd8SRuslan Bukin 	case PMC_CPU_ARMV7_CORTEX_A8:
34273e0bfdd8SRuslan Bukin 		PMC_MDEP_INIT(cortex_a8);
34283e0bfdd8SRuslan Bukin 		pmc_class_table[n] = &cortex_a8_class_table_descr;
34293e0bfdd8SRuslan Bukin 		break;
34303e0bfdd8SRuslan Bukin 	case PMC_CPU_ARMV7_CORTEX_A9:
34313e0bfdd8SRuslan Bukin 		PMC_MDEP_INIT(cortex_a9);
34323e0bfdd8SRuslan Bukin 		pmc_class_table[n] = &cortex_a9_class_table_descr;
34336411d14dSRuslan Bukin 		break;
34346411d14dSRuslan Bukin #endif
3435bc88bb2bSRuslan Bukin #if defined(__aarch64__)
3436bc88bb2bSRuslan Bukin 	case PMC_CPU_ARMV8_CORTEX_A53:
3437bc88bb2bSRuslan Bukin 		PMC_MDEP_INIT(cortex_a53);
3438bc88bb2bSRuslan Bukin 		pmc_class_table[n] = &cortex_a53_class_table_descr;
3439bc88bb2bSRuslan Bukin 		break;
3440bc88bb2bSRuslan Bukin 	case PMC_CPU_ARMV8_CORTEX_A57:
3441bc88bb2bSRuslan Bukin 		PMC_MDEP_INIT(cortex_a57);
3442bc88bb2bSRuslan Bukin 		pmc_class_table[n] = &cortex_a57_class_table_descr;
3443bc88bb2bSRuslan Bukin 		break;
3444bc88bb2bSRuslan Bukin #endif
3445660df75eSGeorge V. Neville-Neil #if defined(__mips__)
3446660df75eSGeorge V. Neville-Neil 	case PMC_CPU_MIPS_24K:
3447660df75eSGeorge V. Neville-Neil 		PMC_MDEP_INIT(mips24k);
3448660df75eSGeorge V. Neville-Neil 		pmc_class_table[n] = &mips24k_class_table_descr;
3449660df75eSGeorge V. Neville-Neil 		break;
3450f6e6460dSAdrian Chadd 	case PMC_CPU_MIPS_74K:
3451f6e6460dSAdrian Chadd 		PMC_MDEP_INIT(mips74k);
3452f6e6460dSAdrian Chadd 		pmc_class_table[n] = &mips74k_class_table_descr;
3453f6e6460dSAdrian Chadd 		break;
3454c2657f80SOleksandr Tymoshenko 	case PMC_CPU_MIPS_OCTEON:
3455c2657f80SOleksandr Tymoshenko 		PMC_MDEP_INIT(octeon);
3456c2657f80SOleksandr Tymoshenko 		pmc_class_table[n] = &octeon_class_table_descr;
3457c2657f80SOleksandr Tymoshenko 		break;
3458660df75eSGeorge V. Neville-Neil #endif /* __mips__ */
34597b25dccaSJustin Hibbits #if defined(__powerpc__)
34607b25dccaSJustin Hibbits 	case PMC_CPU_PPC_7450:
34617b25dccaSJustin Hibbits 		PMC_MDEP_INIT(ppc7450);
34627b25dccaSJustin Hibbits 		pmc_class_table[n] = &ppc7450_class_table_descr;
34637b25dccaSJustin Hibbits 		break;
3464169dd953SJustin Hibbits 	case PMC_CPU_PPC_970:
3465169dd953SJustin Hibbits 		PMC_MDEP_INIT(ppc970);
3466169dd953SJustin Hibbits 		pmc_class_table[n] = &ppc970_class_table_descr;
3467169dd953SJustin Hibbits 		break;
3468a7452468SJustin Hibbits 	case PMC_CPU_PPC_E500:
3469a7452468SJustin Hibbits 		PMC_MDEP_INIT(e500);
3470a7452468SJustin Hibbits 		pmc_class_table[n] = &e500_class_table_descr;
3471a7452468SJustin Hibbits 		break;
34727b25dccaSJustin Hibbits #endif
3473f263522aSJoseph Koshy 	default:
3474f263522aSJoseph Koshy 		/*
3475f263522aSJoseph Koshy 		 * Some kind of CPU this version of the library knows nothing
3476f263522aSJoseph Koshy 		 * about.  This shouldn't happen since the abi version check
3477f263522aSJoseph Koshy 		 * should have caught this.
3478f263522aSJoseph Koshy 		 */
3479f263522aSJoseph Koshy 		errno = ENXIO;
3480f263522aSJoseph Koshy 		return (pmc_syscall = -1);
3481f263522aSJoseph Koshy 	}
3482f263522aSJoseph Koshy 
3483aa342b1fSJoseph Koshy 	return (0);
3484f263522aSJoseph Koshy }
3485f263522aSJoseph Koshy 
3486f263522aSJoseph Koshy const char *
3487f263522aSJoseph Koshy pmc_name_of_capability(enum pmc_caps cap)
3488f263522aSJoseph Koshy {
3489f263522aSJoseph Koshy 	int i;
3490f263522aSJoseph Koshy 
3491f263522aSJoseph Koshy 	/*
3492f263522aSJoseph Koshy 	 * 'cap' should have a single bit set and should be in
3493f263522aSJoseph Koshy 	 * range.
3494f263522aSJoseph Koshy 	 */
3495f263522aSJoseph Koshy 	if ((cap & (cap - 1)) || cap < PMC_CAP_FIRST ||
3496f263522aSJoseph Koshy 	    cap > PMC_CAP_LAST) {
3497f263522aSJoseph Koshy 		errno = EINVAL;
3498aa342b1fSJoseph Koshy 		return (NULL);
3499f263522aSJoseph Koshy 	}
3500f263522aSJoseph Koshy 
3501f263522aSJoseph Koshy 	i = ffs(cap);
3502aa342b1fSJoseph Koshy 	return (pmc_capability_names[i - 1]);
3503f263522aSJoseph Koshy }
3504f263522aSJoseph Koshy 
3505f263522aSJoseph Koshy const char *
3506f263522aSJoseph Koshy pmc_name_of_class(enum pmc_class pc)
3507f263522aSJoseph Koshy {
35080ceb54c2SJohn Baldwin 	size_t n;
35090ceb54c2SJohn Baldwin 
35100ceb54c2SJohn Baldwin 	for (n = 0; n < PMC_TABLE_SIZE(pmc_class_names); n++)
35110ceb54c2SJohn Baldwin 		if (pc == pmc_class_names[n].pm_class)
35120ceb54c2SJohn Baldwin 			return (pmc_class_names[n].pm_name);
3513f263522aSJoseph Koshy 
3514f263522aSJoseph Koshy 	errno = EINVAL;
3515aa342b1fSJoseph Koshy 	return (NULL);
3516f263522aSJoseph Koshy }
3517f263522aSJoseph Koshy 
3518f263522aSJoseph Koshy const char *
3519f263522aSJoseph Koshy pmc_name_of_cputype(enum pmc_cputype cp)
3520f263522aSJoseph Koshy {
3521789140c0SJoseph Koshy 	size_t n;
3522789140c0SJoseph Koshy 
3523789140c0SJoseph Koshy 	for (n = 0; n < PMC_TABLE_SIZE(pmc_cputype_names); n++)
3524789140c0SJoseph Koshy 		if (cp == pmc_cputype_names[n].pm_cputype)
3525789140c0SJoseph Koshy 			return (pmc_cputype_names[n].pm_name);
3526789140c0SJoseph Koshy 
3527f263522aSJoseph Koshy 	errno = EINVAL;
3528aa342b1fSJoseph Koshy 	return (NULL);
3529f263522aSJoseph Koshy }
3530f263522aSJoseph Koshy 
3531f263522aSJoseph Koshy const char *
3532f263522aSJoseph Koshy pmc_name_of_disposition(enum pmc_disp pd)
3533f263522aSJoseph Koshy {
3534f263522aSJoseph Koshy 	if ((int) pd >= PMC_DISP_FIRST &&
3535f263522aSJoseph Koshy 	    pd <= PMC_DISP_LAST)
3536aa342b1fSJoseph Koshy 		return (pmc_disposition_names[pd]);
3537f263522aSJoseph Koshy 
3538f263522aSJoseph Koshy 	errno = EINVAL;
3539aa342b1fSJoseph Koshy 	return (NULL);
3540f263522aSJoseph Koshy }
3541f263522aSJoseph Koshy 
3542f263522aSJoseph Koshy const char *
35430cfab8ddSJoseph Koshy _pmc_name_of_event(enum pmc_event pe, enum pmc_cputype cpu)
3544f263522aSJoseph Koshy {
3545789140c0SJoseph Koshy 	const struct pmc_event_descr *ev, *evfence;
3546789140c0SJoseph Koshy 
3547789140c0SJoseph Koshy 	ev = evfence = NULL;
35480cfab8ddSJoseph Koshy 	if (pe >= PMC_EV_IAF_FIRST && pe <= PMC_EV_IAF_LAST) {
35490cfab8ddSJoseph Koshy 		ev = iaf_event_table;
35500cfab8ddSJoseph Koshy 		evfence = iaf_event_table + PMC_EVENT_TABLE_SIZE(iaf);
35510cfab8ddSJoseph Koshy 	} else if (pe >= PMC_EV_IAP_FIRST && pe <= PMC_EV_IAP_LAST) {
35520cfab8ddSJoseph Koshy 		switch (cpu) {
35530cfab8ddSJoseph Koshy 		case PMC_CPU_INTEL_ATOM:
35540cfab8ddSJoseph Koshy 			ev = atom_event_table;
35550cfab8ddSJoseph Koshy 			evfence = atom_event_table + PMC_EVENT_TABLE_SIZE(atom);
35560cfab8ddSJoseph Koshy 			break;
3557e8f021a3SHiren Panchasara 		case PMC_CPU_INTEL_ATOM_SILVERMONT:
3558e8f021a3SHiren Panchasara 			ev = atom_silvermont_event_table;
3559e8f021a3SHiren Panchasara 			evfence = atom_silvermont_event_table +
3560e8f021a3SHiren Panchasara 			    PMC_EVENT_TABLE_SIZE(atom_silvermont);
3561e8f021a3SHiren Panchasara 			break;
35620cfab8ddSJoseph Koshy 		case PMC_CPU_INTEL_CORE:
35630cfab8ddSJoseph Koshy 			ev = core_event_table;
35640cfab8ddSJoseph Koshy 			evfence = core_event_table + PMC_EVENT_TABLE_SIZE(core);
35650cfab8ddSJoseph Koshy 			break;
35660cfab8ddSJoseph Koshy 		case PMC_CPU_INTEL_CORE2:
3567b4d091f3SJoseph Koshy 		case PMC_CPU_INTEL_CORE2EXTREME:
35680cfab8ddSJoseph Koshy 			ev = core2_event_table;
35690cfab8ddSJoseph Koshy 			evfence = core2_event_table + PMC_EVENT_TABLE_SIZE(core2);
35700cfab8ddSJoseph Koshy 			break;
3571597979c4SJeff Roberson 		case PMC_CPU_INTEL_COREI7:
3572597979c4SJeff Roberson 			ev = corei7_event_table;
3573597979c4SJeff Roberson 			evfence = corei7_event_table + PMC_EVENT_TABLE_SIZE(corei7);
3574597979c4SJeff Roberson 			break;
357549fe48abSKonstantin Belousov 		case PMC_CPU_INTEL_NEHALEM_EX:
357649fe48abSKonstantin Belousov 			ev = nehalem_ex_event_table;
357749fe48abSKonstantin Belousov 			evfence = nehalem_ex_event_table +
357849fe48abSKonstantin Belousov 			    PMC_EVENT_TABLE_SIZE(nehalem_ex);
357949fe48abSKonstantin Belousov 			break;
3580cc0c1555SSean Bruno 		case PMC_CPU_INTEL_HASWELL:
3581cc0c1555SSean Bruno 			ev = haswell_event_table;
3582cc0c1555SSean Bruno 			evfence = haswell_event_table + PMC_EVENT_TABLE_SIZE(haswell);
3583cc0c1555SSean Bruno 			break;
3584d95b3509SRandall Stewart 		case PMC_CPU_INTEL_HASWELL_XEON:
3585d95b3509SRandall Stewart 			ev = haswell_xeon_event_table;
3586d95b3509SRandall Stewart 			evfence = haswell_xeon_event_table + PMC_EVENT_TABLE_SIZE(haswell_xeon);
3587d95b3509SRandall Stewart 			break;
3588f19bae41SRandall Stewart 		case PMC_CPU_INTEL_BROADWELL:
3589f19bae41SRandall Stewart 			ev = broadwell_event_table;
3590f19bae41SRandall Stewart 			evfence = broadwell_event_table + PMC_EVENT_TABLE_SIZE(broadwell);
3591f19bae41SRandall Stewart 			break;
3592f19bae41SRandall Stewart 		case PMC_CPU_INTEL_BROADWELL_XEON:
3593f19bae41SRandall Stewart 			ev = broadwell_xeon_event_table;
3594f19bae41SRandall Stewart 			evfence = broadwell_xeon_event_table + PMC_EVENT_TABLE_SIZE(broadwell_xeon);
3595f19bae41SRandall Stewart 			break;
3596f19bae41SRandall Stewart 		case PMC_CPU_INTEL_SKYLAKE:
3597f19bae41SRandall Stewart 			ev = skylake_event_table;
3598f19bae41SRandall Stewart 			evfence = skylake_event_table + PMC_EVENT_TABLE_SIZE(skylake);
3599f19bae41SRandall Stewart 			break;
36001e862e5aSFabien Thomas 		case PMC_CPU_INTEL_IVYBRIDGE:
36011e862e5aSFabien Thomas 			ev = ivybridge_event_table;
36021e862e5aSFabien Thomas 			evfence = ivybridge_event_table + PMC_EVENT_TABLE_SIZE(ivybridge);
36031e862e5aSFabien Thomas 			break;
36043f929d8cSSean Bruno 		case PMC_CPU_INTEL_IVYBRIDGE_XEON:
36053f929d8cSSean Bruno 			ev = ivybridge_xeon_event_table;
36063f929d8cSSean Bruno 			evfence = ivybridge_xeon_event_table + PMC_EVENT_TABLE_SIZE(ivybridge_xeon);
36073f929d8cSSean Bruno 			break;
360878d763a2SDavide Italiano 		case PMC_CPU_INTEL_SANDYBRIDGE:
360978d763a2SDavide Italiano 			ev = sandybridge_event_table;
361078d763a2SDavide Italiano 			evfence = sandybridge_event_table + PMC_EVENT_TABLE_SIZE(sandybridge);
361178d763a2SDavide Italiano 			break;
3612fabe02f5SSean Bruno 		case PMC_CPU_INTEL_SANDYBRIDGE_XEON:
3613fabe02f5SSean Bruno 			ev = sandybridge_xeon_event_table;
3614fabe02f5SSean Bruno 			evfence = sandybridge_xeon_event_table + PMC_EVENT_TABLE_SIZE(sandybridge_xeon);
3615fabe02f5SSean Bruno 			break;
36161fa7f10bSFabien Thomas 		case PMC_CPU_INTEL_WESTMERE:
36171fa7f10bSFabien Thomas 			ev = westmere_event_table;
36181fa7f10bSFabien Thomas 			evfence = westmere_event_table + PMC_EVENT_TABLE_SIZE(westmere);
36191fa7f10bSFabien Thomas 			break;
362049fe48abSKonstantin Belousov 		case PMC_CPU_INTEL_WESTMERE_EX:
362149fe48abSKonstantin Belousov 			ev = westmere_ex_event_table;
362249fe48abSKonstantin Belousov 			evfence = westmere_ex_event_table +
362349fe48abSKonstantin Belousov 			    PMC_EVENT_TABLE_SIZE(westmere_ex);
362449fe48abSKonstantin Belousov 			break;
36250cfab8ddSJoseph Koshy 		default:	/* Unknown CPU type. */
36260cfab8ddSJoseph Koshy 			break;
36270cfab8ddSJoseph Koshy 		}
36281fa7f10bSFabien Thomas 	} else if (pe >= PMC_EV_UCF_FIRST && pe <= PMC_EV_UCF_LAST) {
36291fa7f10bSFabien Thomas 		ev = ucf_event_table;
36301fa7f10bSFabien Thomas 		evfence = ucf_event_table + PMC_EVENT_TABLE_SIZE(ucf);
36311fa7f10bSFabien Thomas 	} else if (pe >= PMC_EV_UCP_FIRST && pe <= PMC_EV_UCP_LAST) {
36321fa7f10bSFabien Thomas 		switch (cpu) {
36331fa7f10bSFabien Thomas 		case PMC_CPU_INTEL_COREI7:
36341fa7f10bSFabien Thomas 			ev = corei7uc_event_table;
36351fa7f10bSFabien Thomas 			evfence = corei7uc_event_table + PMC_EVENT_TABLE_SIZE(corei7uc);
36361fa7f10bSFabien Thomas 			break;
363778d763a2SDavide Italiano 		case PMC_CPU_INTEL_SANDYBRIDGE:
363878d763a2SDavide Italiano 			ev = sandybridgeuc_event_table;
363978d763a2SDavide Italiano 			evfence = sandybridgeuc_event_table + PMC_EVENT_TABLE_SIZE(sandybridgeuc);
364078d763a2SDavide Italiano 			break;
36411fa7f10bSFabien Thomas 		case PMC_CPU_INTEL_WESTMERE:
36421fa7f10bSFabien Thomas 			ev = westmereuc_event_table;
36431fa7f10bSFabien Thomas 			evfence = westmereuc_event_table + PMC_EVENT_TABLE_SIZE(westmereuc);
36441fa7f10bSFabien Thomas 			break;
36451fa7f10bSFabien Thomas 		default:	/* Unknown CPU type. */
36461fa7f10bSFabien Thomas 			break;
36471fa7f10bSFabien Thomas 		}
36481fa7f10bSFabien Thomas 	} else if (pe >= PMC_EV_K7_FIRST && pe <= PMC_EV_K7_LAST) {
3649789140c0SJoseph Koshy 		ev = k7_event_table;
3650789140c0SJoseph Koshy 		evfence = k7_event_table + PMC_EVENT_TABLE_SIZE(k7);
3651789140c0SJoseph Koshy 	} else if (pe >= PMC_EV_K8_FIRST && pe <= PMC_EV_K8_LAST) {
3652789140c0SJoseph Koshy 		ev = k8_event_table;
3653789140c0SJoseph Koshy 		evfence = k8_event_table + PMC_EVENT_TABLE_SIZE(k8);
3654789140c0SJoseph Koshy 	} else if (pe >= PMC_EV_P4_FIRST && pe <= PMC_EV_P4_LAST) {
3655789140c0SJoseph Koshy 		ev = p4_event_table;
3656789140c0SJoseph Koshy 		evfence = p4_event_table + PMC_EVENT_TABLE_SIZE(p4);
3657789140c0SJoseph Koshy 	} else if (pe >= PMC_EV_P5_FIRST && pe <= PMC_EV_P5_LAST) {
3658789140c0SJoseph Koshy 		ev = p5_event_table;
3659789140c0SJoseph Koshy 		evfence = p5_event_table + PMC_EVENT_TABLE_SIZE(p5);
3660789140c0SJoseph Koshy 	} else if (pe >= PMC_EV_P6_FIRST && pe <= PMC_EV_P6_LAST) {
3661789140c0SJoseph Koshy 		ev = p6_event_table;
3662789140c0SJoseph Koshy 		evfence = p6_event_table + PMC_EVENT_TABLE_SIZE(p6);
36630ce207d2SRui Paulo 	} else if (pe >= PMC_EV_XSCALE_FIRST && pe <= PMC_EV_XSCALE_LAST) {
36640ce207d2SRui Paulo 		ev = xscale_event_table;
36650ce207d2SRui Paulo 		evfence = xscale_event_table + PMC_EVENT_TABLE_SIZE(xscale);
36666411d14dSRuslan Bukin 	} else if (pe >= PMC_EV_ARMV7_FIRST && pe <= PMC_EV_ARMV7_LAST) {
36673e0bfdd8SRuslan Bukin 		switch (cpu) {
36683e0bfdd8SRuslan Bukin 		case PMC_CPU_ARMV7_CORTEX_A8:
36693e0bfdd8SRuslan Bukin 			ev = cortex_a8_event_table;
36703e0bfdd8SRuslan Bukin 			evfence = cortex_a8_event_table + PMC_EVENT_TABLE_SIZE(cortex_a8);
36713e0bfdd8SRuslan Bukin 			break;
36723e0bfdd8SRuslan Bukin 		case PMC_CPU_ARMV7_CORTEX_A9:
36733e0bfdd8SRuslan Bukin 			ev = cortex_a9_event_table;
36743e0bfdd8SRuslan Bukin 			evfence = cortex_a9_event_table + PMC_EVENT_TABLE_SIZE(cortex_a9);
36753e0bfdd8SRuslan Bukin 			break;
36763e0bfdd8SRuslan Bukin 		default:	/* Unknown CPU type. */
36773e0bfdd8SRuslan Bukin 			break;
36783e0bfdd8SRuslan Bukin 		}
3679bc88bb2bSRuslan Bukin 	} else if (pe >= PMC_EV_ARMV8_FIRST && pe <= PMC_EV_ARMV8_LAST) {
3680bc88bb2bSRuslan Bukin 		switch (cpu) {
3681bc88bb2bSRuslan Bukin 		case PMC_CPU_ARMV8_CORTEX_A53:
3682bc88bb2bSRuslan Bukin 			ev = cortex_a53_event_table;
3683bc88bb2bSRuslan Bukin 			evfence = cortex_a53_event_table + PMC_EVENT_TABLE_SIZE(cortex_a53);
3684bc88bb2bSRuslan Bukin 			break;
3685bc88bb2bSRuslan Bukin 		case PMC_CPU_ARMV8_CORTEX_A57:
3686bc88bb2bSRuslan Bukin 			ev = cortex_a57_event_table;
3687bc88bb2bSRuslan Bukin 			evfence = cortex_a57_event_table + PMC_EVENT_TABLE_SIZE(cortex_a57);
3688bc88bb2bSRuslan Bukin 			break;
3689bc88bb2bSRuslan Bukin 		default:	/* Unknown CPU type. */
3690bc88bb2bSRuslan Bukin 			break;
3691bc88bb2bSRuslan Bukin 		}
3692660df75eSGeorge V. Neville-Neil 	} else if (pe >= PMC_EV_MIPS24K_FIRST && pe <= PMC_EV_MIPS24K_LAST) {
3693660df75eSGeorge V. Neville-Neil 		ev = mips24k_event_table;
3694f5f9340bSFabien Thomas 		evfence = mips24k_event_table + PMC_EVENT_TABLE_SIZE(mips24k);
3695f6e6460dSAdrian Chadd 	} else if (pe >= PMC_EV_MIPS74K_FIRST && pe <= PMC_EV_MIPS74K_LAST) {
3696f6e6460dSAdrian Chadd 		ev = mips74k_event_table;
3697f6e6460dSAdrian Chadd 		evfence = mips74k_event_table + PMC_EVENT_TABLE_SIZE(mips74k);
3698c2657f80SOleksandr Tymoshenko 	} else if (pe >= PMC_EV_OCTEON_FIRST && pe <= PMC_EV_OCTEON_LAST) {
3699c2657f80SOleksandr Tymoshenko 		ev = octeon_event_table;
3700c2657f80SOleksandr Tymoshenko 		evfence = octeon_event_table + PMC_EVENT_TABLE_SIZE(octeon);
37017b25dccaSJustin Hibbits 	} else if (pe >= PMC_EV_PPC7450_FIRST && pe <= PMC_EV_PPC7450_LAST) {
37027b25dccaSJustin Hibbits 		ev = ppc7450_event_table;
3703f5f9340bSFabien Thomas 		evfence = ppc7450_event_table + PMC_EVENT_TABLE_SIZE(ppc7450);
3704169dd953SJustin Hibbits 	} else if (pe >= PMC_EV_PPC970_FIRST && pe <= PMC_EV_PPC970_LAST) {
3705169dd953SJustin Hibbits 		ev = ppc970_event_table;
3706169dd953SJustin Hibbits 		evfence = ppc970_event_table + PMC_EVENT_TABLE_SIZE(ppc970);
3707a7452468SJustin Hibbits 	} else if (pe >= PMC_EV_E500_FIRST && pe <= PMC_EV_E500_LAST) {
3708a7452468SJustin Hibbits 		ev = e500_event_table;
3709a7452468SJustin Hibbits 		evfence = e500_event_table + PMC_EVENT_TABLE_SIZE(e500);
3710789140c0SJoseph Koshy 	} else if (pe == PMC_EV_TSC_TSC) {
3711789140c0SJoseph Koshy 		ev = tsc_event_table;
3712789140c0SJoseph Koshy 		evfence = tsc_event_table + PMC_EVENT_TABLE_SIZE(tsc);
3713f0bbe9aaSDimitry Andric 	} else if ((int)pe >= PMC_EV_SOFT_FIRST && (int)pe <= PMC_EV_SOFT_LAST) {
3714f5f9340bSFabien Thomas 		ev = soft_event_table;
3715f5f9340bSFabien Thomas 		evfence = soft_event_table + soft_event_info.pm_nevent;
3716789140c0SJoseph Koshy 	}
3717789140c0SJoseph Koshy 
3718789140c0SJoseph Koshy 	for (; ev != evfence; ev++)
3719789140c0SJoseph Koshy 		if (pe == ev->pm_ev_code)
3720789140c0SJoseph Koshy 			return (ev->pm_ev_name);
3721f263522aSJoseph Koshy 
37220cfab8ddSJoseph Koshy 	return (NULL);
37230cfab8ddSJoseph Koshy }
37240cfab8ddSJoseph Koshy 
37250cfab8ddSJoseph Koshy const char *
37260cfab8ddSJoseph Koshy pmc_name_of_event(enum pmc_event pe)
37270cfab8ddSJoseph Koshy {
37280cfab8ddSJoseph Koshy 	const char *n;
37290cfab8ddSJoseph Koshy 
37300cfab8ddSJoseph Koshy 	if ((n = _pmc_name_of_event(pe, cpu_info.pm_cputype)) != NULL)
37310cfab8ddSJoseph Koshy 		return (n);
37320cfab8ddSJoseph Koshy 
3733f263522aSJoseph Koshy 	errno = EINVAL;
3734aa342b1fSJoseph Koshy 	return (NULL);
3735f263522aSJoseph Koshy }
3736f263522aSJoseph Koshy 
3737f263522aSJoseph Koshy const char *
3738f263522aSJoseph Koshy pmc_name_of_mode(enum pmc_mode pm)
3739f263522aSJoseph Koshy {
3740f263522aSJoseph Koshy 	if ((int) pm >= PMC_MODE_FIRST &&
3741f263522aSJoseph Koshy 	    pm <= PMC_MODE_LAST)
3742aa342b1fSJoseph Koshy 		return (pmc_mode_names[pm]);
3743f263522aSJoseph Koshy 
3744f263522aSJoseph Koshy 	errno = EINVAL;
3745aa342b1fSJoseph Koshy 	return (NULL);
3746f263522aSJoseph Koshy }
3747f263522aSJoseph Koshy 
3748f263522aSJoseph Koshy const char *
3749f263522aSJoseph Koshy pmc_name_of_state(enum pmc_state ps)
3750f263522aSJoseph Koshy {
3751f263522aSJoseph Koshy 	if ((int) ps >= PMC_STATE_FIRST &&
3752f263522aSJoseph Koshy 	    ps <= PMC_STATE_LAST)
3753aa342b1fSJoseph Koshy 		return (pmc_state_names[ps]);
3754f263522aSJoseph Koshy 
3755f263522aSJoseph Koshy 	errno = EINVAL;
3756aa342b1fSJoseph Koshy 	return (NULL);
3757f263522aSJoseph Koshy }
3758f263522aSJoseph Koshy 
3759f263522aSJoseph Koshy int
3760f263522aSJoseph Koshy pmc_ncpu(void)
3761f263522aSJoseph Koshy {
3762f263522aSJoseph Koshy 	if (pmc_syscall == -1) {
3763f263522aSJoseph Koshy 		errno = ENXIO;
3764aa342b1fSJoseph Koshy 		return (-1);
3765f263522aSJoseph Koshy 	}
3766f263522aSJoseph Koshy 
3767aa342b1fSJoseph Koshy 	return (cpu_info.pm_ncpu);
3768f263522aSJoseph Koshy }
3769f263522aSJoseph Koshy 
3770f263522aSJoseph Koshy int
3771f263522aSJoseph Koshy pmc_npmc(int cpu)
3772f263522aSJoseph Koshy {
3773f263522aSJoseph Koshy 	if (pmc_syscall == -1) {
3774f263522aSJoseph Koshy 		errno = ENXIO;
3775aa342b1fSJoseph Koshy 		return (-1);
3776f263522aSJoseph Koshy 	}
3777f263522aSJoseph Koshy 
3778f263522aSJoseph Koshy 	if (cpu < 0 || cpu >= (int) cpu_info.pm_ncpu) {
3779f263522aSJoseph Koshy 		errno = EINVAL;
3780aa342b1fSJoseph Koshy 		return (-1);
3781f263522aSJoseph Koshy 	}
3782f263522aSJoseph Koshy 
3783aa342b1fSJoseph Koshy 	return (cpu_info.pm_npmc);
3784f263522aSJoseph Koshy }
3785f263522aSJoseph Koshy 
3786f263522aSJoseph Koshy int
3787f263522aSJoseph Koshy pmc_pmcinfo(int cpu, struct pmc_pmcinfo **ppmci)
3788f263522aSJoseph Koshy {
3789f263522aSJoseph Koshy 	int nbytes, npmc;
3790f263522aSJoseph Koshy 	struct pmc_op_getpmcinfo *pmci;
3791f263522aSJoseph Koshy 
3792f263522aSJoseph Koshy 	if ((npmc = pmc_npmc(cpu)) < 0)
3793aa342b1fSJoseph Koshy 		return (-1);
3794f263522aSJoseph Koshy 
3795f263522aSJoseph Koshy 	nbytes = sizeof(struct pmc_op_getpmcinfo) +
3796f263522aSJoseph Koshy 	    npmc * sizeof(struct pmc_info);
3797f263522aSJoseph Koshy 
3798f263522aSJoseph Koshy 	if ((pmci = calloc(1, nbytes)) == NULL)
3799aa342b1fSJoseph Koshy 		return (-1);
3800f263522aSJoseph Koshy 
3801f263522aSJoseph Koshy 	pmci->pm_cpu  = cpu;
3802f263522aSJoseph Koshy 
3803f263522aSJoseph Koshy 	if (PMC_CALL(GETPMCINFO, pmci) < 0) {
3804f263522aSJoseph Koshy 		free(pmci);
3805aa342b1fSJoseph Koshy 		return (-1);
3806f263522aSJoseph Koshy 	}
3807f263522aSJoseph Koshy 
3808f263522aSJoseph Koshy 	/* kernel<->library, library<->userland interfaces are identical */
3809f263522aSJoseph Koshy 	*ppmci = (struct pmc_pmcinfo *) pmci;
3810aa342b1fSJoseph Koshy 	return (0);
3811f263522aSJoseph Koshy }
3812f263522aSJoseph Koshy 
3813f263522aSJoseph Koshy int
3814f263522aSJoseph Koshy pmc_read(pmc_id_t pmc, pmc_value_t *value)
3815f263522aSJoseph Koshy {
3816f263522aSJoseph Koshy 	struct pmc_op_pmcrw pmc_read_op;
3817f263522aSJoseph Koshy 
3818f263522aSJoseph Koshy 	pmc_read_op.pm_pmcid = pmc;
3819f263522aSJoseph Koshy 	pmc_read_op.pm_flags = PMC_F_OLDVALUE;
3820f263522aSJoseph Koshy 	pmc_read_op.pm_value = -1;
3821f263522aSJoseph Koshy 
3822f263522aSJoseph Koshy 	if (PMC_CALL(PMCRW, &pmc_read_op) < 0)
3823aa342b1fSJoseph Koshy 		return (-1);
3824f263522aSJoseph Koshy 
3825f263522aSJoseph Koshy 	*value = pmc_read_op.pm_value;
3826aa342b1fSJoseph Koshy 	return (0);
3827f263522aSJoseph Koshy }
3828f263522aSJoseph Koshy 
3829f263522aSJoseph Koshy int
3830f263522aSJoseph Koshy pmc_release(pmc_id_t pmc)
3831f263522aSJoseph Koshy {
3832f263522aSJoseph Koshy 	struct pmc_op_simple	pmc_release_args;
3833f263522aSJoseph Koshy 
3834f263522aSJoseph Koshy 	pmc_release_args.pm_pmcid = pmc;
3835aa342b1fSJoseph Koshy 	return (PMC_CALL(PMCRELEASE, &pmc_release_args));
3836f263522aSJoseph Koshy }
3837f263522aSJoseph Koshy 
3838f263522aSJoseph Koshy int
3839f263522aSJoseph Koshy pmc_rw(pmc_id_t pmc, pmc_value_t newvalue, pmc_value_t *oldvaluep)
3840f263522aSJoseph Koshy {
3841f263522aSJoseph Koshy 	struct pmc_op_pmcrw pmc_rw_op;
3842f263522aSJoseph Koshy 
3843f263522aSJoseph Koshy 	pmc_rw_op.pm_pmcid = pmc;
3844f263522aSJoseph Koshy 	pmc_rw_op.pm_flags = PMC_F_NEWVALUE | PMC_F_OLDVALUE;
3845f263522aSJoseph Koshy 	pmc_rw_op.pm_value = newvalue;
3846f263522aSJoseph Koshy 
3847f263522aSJoseph Koshy 	if (PMC_CALL(PMCRW, &pmc_rw_op) < 0)
3848aa342b1fSJoseph Koshy 		return (-1);
3849f263522aSJoseph Koshy 
3850f263522aSJoseph Koshy 	*oldvaluep = pmc_rw_op.pm_value;
3851aa342b1fSJoseph Koshy 	return (0);
3852f263522aSJoseph Koshy }
3853f263522aSJoseph Koshy 
3854f263522aSJoseph Koshy int
3855f263522aSJoseph Koshy pmc_set(pmc_id_t pmc, pmc_value_t value)
3856f263522aSJoseph Koshy {
3857f263522aSJoseph Koshy 	struct pmc_op_pmcsetcount sc;
3858f263522aSJoseph Koshy 
3859f263522aSJoseph Koshy 	sc.pm_pmcid = pmc;
3860f263522aSJoseph Koshy 	sc.pm_count = value;
3861f263522aSJoseph Koshy 
3862f263522aSJoseph Koshy 	if (PMC_CALL(PMCSETCOUNT, &sc) < 0)
3863aa342b1fSJoseph Koshy 		return (-1);
3864aa342b1fSJoseph Koshy 	return (0);
3865f263522aSJoseph Koshy }
3866f263522aSJoseph Koshy 
3867f263522aSJoseph Koshy int
3868f263522aSJoseph Koshy pmc_start(pmc_id_t pmc)
3869f263522aSJoseph Koshy {
3870f263522aSJoseph Koshy 	struct pmc_op_simple	pmc_start_args;
3871f263522aSJoseph Koshy 
3872f263522aSJoseph Koshy 	pmc_start_args.pm_pmcid = pmc;
3873aa342b1fSJoseph Koshy 	return (PMC_CALL(PMCSTART, &pmc_start_args));
3874f263522aSJoseph Koshy }
3875f263522aSJoseph Koshy 
3876f263522aSJoseph Koshy int
3877f263522aSJoseph Koshy pmc_stop(pmc_id_t pmc)
3878f263522aSJoseph Koshy {
3879f263522aSJoseph Koshy 	struct pmc_op_simple	pmc_stop_args;
3880f263522aSJoseph Koshy 
3881f263522aSJoseph Koshy 	pmc_stop_args.pm_pmcid = pmc;
3882aa342b1fSJoseph Koshy 	return (PMC_CALL(PMCSTOP, &pmc_stop_args));
3883f263522aSJoseph Koshy }
3884f263522aSJoseph Koshy 
3885f263522aSJoseph Koshy int
3886f263522aSJoseph Koshy pmc_width(pmc_id_t pmcid, uint32_t *width)
3887f263522aSJoseph Koshy {
3888f263522aSJoseph Koshy 	unsigned int i;
3889f263522aSJoseph Koshy 	enum pmc_class cl;
3890f263522aSJoseph Koshy 
3891f263522aSJoseph Koshy 	cl = PMC_ID_TO_CLASS(pmcid);
3892f263522aSJoseph Koshy 	for (i = 0; i < cpu_info.pm_nclass; i++)
3893f263522aSJoseph Koshy 		if (cpu_info.pm_classes[i].pm_class == cl) {
3894f263522aSJoseph Koshy 			*width = cpu_info.pm_classes[i].pm_width;
3895aa342b1fSJoseph Koshy 			return (0);
3896f263522aSJoseph Koshy 		}
3897484202faSJoseph Koshy 	errno = EINVAL;
3898484202faSJoseph Koshy 	return (-1);
3899f263522aSJoseph Koshy }
3900f263522aSJoseph Koshy 
3901f263522aSJoseph Koshy int
3902f263522aSJoseph Koshy pmc_write(pmc_id_t pmc, pmc_value_t value)
3903f263522aSJoseph Koshy {
3904f263522aSJoseph Koshy 	struct pmc_op_pmcrw pmc_write_op;
3905f263522aSJoseph Koshy 
3906f263522aSJoseph Koshy 	pmc_write_op.pm_pmcid = pmc;
3907f263522aSJoseph Koshy 	pmc_write_op.pm_flags = PMC_F_NEWVALUE;
3908f263522aSJoseph Koshy 	pmc_write_op.pm_value = value;
3909aa342b1fSJoseph Koshy 	return (PMC_CALL(PMCRW, &pmc_write_op));
3910f263522aSJoseph Koshy }
3911f263522aSJoseph Koshy 
3912f263522aSJoseph Koshy int
3913f263522aSJoseph Koshy pmc_writelog(uint32_t userdata)
3914f263522aSJoseph Koshy {
3915f263522aSJoseph Koshy 	struct pmc_op_writelog wl;
3916f263522aSJoseph Koshy 
3917f263522aSJoseph Koshy 	wl.pm_userdata = userdata;
3918aa342b1fSJoseph Koshy 	return (PMC_CALL(WRITELOG, &wl));
3919f263522aSJoseph Koshy }
3920