xref: /freebsd/lib/libpmc/libpmc.c (revision b83aeb5c6b68ec66e52c4d3157d01f371b193d56)
1ebccf1e3SJoseph Koshy /*-
25e53a4f9SPedro F. Giffuni  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
35e53a4f9SPedro F. Giffuni  *
4484202faSJoseph Koshy  * Copyright (c) 2003-2008 Joseph Koshy
5ebccf1e3SJoseph Koshy  * All rights reserved.
6ebccf1e3SJoseph Koshy  *
7ebccf1e3SJoseph Koshy  * Redistribution and use in source and binary forms, with or without
8ebccf1e3SJoseph Koshy  * modification, are permitted provided that the following conditions
9ebccf1e3SJoseph Koshy  * are met:
10ebccf1e3SJoseph Koshy  * 1. Redistributions of source code must retain the above copyright
11ebccf1e3SJoseph Koshy  *    notice, this list of conditions and the following disclaimer.
12ebccf1e3SJoseph Koshy  * 2. Redistributions in binary form must reproduce the above copyright
13ebccf1e3SJoseph Koshy  *    notice, this list of conditions and the following disclaimer in the
14ebccf1e3SJoseph Koshy  *    documentation and/or other materials provided with the distribution.
15ebccf1e3SJoseph Koshy  *
16ebccf1e3SJoseph Koshy  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17ebccf1e3SJoseph Koshy  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18ebccf1e3SJoseph Koshy  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19ebccf1e3SJoseph Koshy  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20ebccf1e3SJoseph Koshy  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21ebccf1e3SJoseph Koshy  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22ebccf1e3SJoseph Koshy  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23ebccf1e3SJoseph Koshy  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24ebccf1e3SJoseph Koshy  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25ebccf1e3SJoseph Koshy  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26ebccf1e3SJoseph Koshy  * SUCH DAMAGE.
27ebccf1e3SJoseph Koshy  */
28ebccf1e3SJoseph Koshy 
29ebccf1e3SJoseph Koshy #include <sys/cdefs.h>
30ebccf1e3SJoseph Koshy __FBSDID("$FreeBSD$");
31ebccf1e3SJoseph Koshy 
32ebccf1e3SJoseph Koshy #include <sys/types.h>
33169dd953SJustin Hibbits #include <sys/param.h>
34ebccf1e3SJoseph Koshy #include <sys/module.h>
35ebccf1e3SJoseph Koshy #include <sys/pmc.h>
36ebccf1e3SJoseph Koshy #include <sys/syscall.h>
37ebccf1e3SJoseph Koshy 
38ebccf1e3SJoseph Koshy #include <ctype.h>
39ebccf1e3SJoseph Koshy #include <errno.h>
40ebccf1e3SJoseph Koshy #include <fcntl.h>
41ebccf1e3SJoseph Koshy #include <pmc.h>
42ebccf1e3SJoseph Koshy #include <stdio.h>
43ebccf1e3SJoseph Koshy #include <stdlib.h>
44ebccf1e3SJoseph Koshy #include <string.h>
45ebccf1e3SJoseph Koshy #include <strings.h>
46ebccf1e3SJoseph Koshy #include <unistd.h>
47ebccf1e3SJoseph Koshy 
480cfab8ddSJoseph Koshy #include "libpmcinternal.h"
490cfab8ddSJoseph Koshy 
50ebccf1e3SJoseph Koshy /* Function prototypes */
5104e9feb0SMarcel Moolenaar #if defined(__i386__)
52ebccf1e3SJoseph Koshy static int k7_allocate_pmc(enum pmc_event _pe, char *_ctrspec,
53ebccf1e3SJoseph Koshy     struct pmc_op_pmcallocate *_pmc_config);
54f263522aSJoseph Koshy #endif
5586a65549SJoseph Koshy #if defined(__amd64__) || defined(__i386__)
560cfab8ddSJoseph Koshy static int iaf_allocate_pmc(enum pmc_event _pe, char *_ctrspec,
570cfab8ddSJoseph Koshy     struct pmc_op_pmcallocate *_pmc_config);
580cfab8ddSJoseph Koshy static int iap_allocate_pmc(enum pmc_event _pe, char *_ctrspec,
590cfab8ddSJoseph Koshy     struct pmc_op_pmcallocate *_pmc_config);
601fa7f10bSFabien Thomas static int ucf_allocate_pmc(enum pmc_event _pe, char *_ctrspec,
611fa7f10bSFabien Thomas     struct pmc_op_pmcallocate *_pmc_config);
621fa7f10bSFabien Thomas static int ucp_allocate_pmc(enum pmc_event _pe, char *_ctrspec,
631fa7f10bSFabien Thomas     struct pmc_op_pmcallocate *_pmc_config);
64f263522aSJoseph Koshy static int k8_allocate_pmc(enum pmc_event _pe, char *_ctrspec,
65ebccf1e3SJoseph Koshy     struct pmc_op_pmcallocate *_pmc_config);
6686a65549SJoseph Koshy static int p4_allocate_pmc(enum pmc_event _pe, char *_ctrspec,
6786a65549SJoseph Koshy     struct pmc_op_pmcallocate *_pmc_config);
68f263522aSJoseph Koshy #endif
69f263522aSJoseph Koshy #if defined(__i386__)
70ebccf1e3SJoseph Koshy static int p5_allocate_pmc(enum pmc_event _pe, char *_ctrspec,
71ebccf1e3SJoseph Koshy     struct pmc_op_pmcallocate *_pmc_config);
72f263522aSJoseph Koshy static int p6_allocate_pmc(enum pmc_event _pe, char *_ctrspec,
73ebccf1e3SJoseph Koshy     struct pmc_op_pmcallocate *_pmc_config);
74ebccf1e3SJoseph Koshy #endif
75789140c0SJoseph Koshy #if defined(__amd64__) || defined(__i386__)
76789140c0SJoseph Koshy static int tsc_allocate_pmc(enum pmc_event _pe, char *_ctrspec,
77789140c0SJoseph Koshy     struct pmc_op_pmcallocate *_pmc_config);
78789140c0SJoseph Koshy #endif
796411d14dSRuslan Bukin #if defined(__arm__)
800ce207d2SRui Paulo #if defined(__XSCALE__)
810ce207d2SRui Paulo static int xscale_allocate_pmc(enum pmc_event _pe, char *_ctrspec,
820ce207d2SRui Paulo     struct pmc_op_pmcallocate *_pmc_config);
830ce207d2SRui Paulo #endif
846411d14dSRuslan Bukin static int armv7_allocate_pmc(enum pmc_event _pe, char *_ctrspec,
856411d14dSRuslan Bukin     struct pmc_op_pmcallocate *_pmc_config);
866411d14dSRuslan Bukin #endif
87bc88bb2bSRuslan Bukin #if defined(__aarch64__)
88bc88bb2bSRuslan Bukin static int arm64_allocate_pmc(enum pmc_event _pe, char *_ctrspec,
89bc88bb2bSRuslan Bukin     struct pmc_op_pmcallocate *_pmc_config);
90bc88bb2bSRuslan Bukin #endif
91660df75eSGeorge V. Neville-Neil #if defined(__mips__)
922827d3e1SOleksandr Tymoshenko static int mips_allocate_pmc(enum pmc_event _pe, char* ctrspec,
93660df75eSGeorge V. Neville-Neil 			     struct pmc_op_pmcallocate *_pmc_config);
94660df75eSGeorge V. Neville-Neil #endif /* __mips__ */
95f5f9340bSFabien Thomas static int soft_allocate_pmc(enum pmc_event _pe, char *_ctrspec,
96f5f9340bSFabien Thomas     struct pmc_op_pmcallocate *_pmc_config);
97660df75eSGeorge V. Neville-Neil 
987b25dccaSJustin Hibbits #if defined(__powerpc__)
99169dd953SJustin Hibbits static int powerpc_allocate_pmc(enum pmc_event _pe, char* ctrspec,
1007b25dccaSJustin Hibbits 			     struct pmc_op_pmcallocate *_pmc_config);
1017b25dccaSJustin Hibbits #endif /* __powerpc__ */
102660df75eSGeorge V. Neville-Neil 
103ebccf1e3SJoseph Koshy #define PMC_CALL(cmd, params)				\
104ebccf1e3SJoseph Koshy 	syscall(pmc_syscall, PMC_OP_##cmd, (params))
105ebccf1e3SJoseph Koshy 
106ebccf1e3SJoseph Koshy /*
107ebccf1e3SJoseph Koshy  * Event aliases provide a way for the user to ask for generic events
108ebccf1e3SJoseph Koshy  * like "cache-misses", or "instructions-retired".  These aliases are
109ebccf1e3SJoseph Koshy  * mapped to the appropriate canonical event descriptions using a
110ebccf1e3SJoseph Koshy  * lookup table.
111ebccf1e3SJoseph Koshy  */
112ebccf1e3SJoseph Koshy struct pmc_event_alias {
113ebccf1e3SJoseph Koshy 	const char	*pm_alias;
114ebccf1e3SJoseph Koshy 	const char	*pm_spec;
115ebccf1e3SJoseph Koshy };
116ebccf1e3SJoseph Koshy 
117ebccf1e3SJoseph Koshy static const struct pmc_event_alias *pmc_mdep_event_aliases;
118ebccf1e3SJoseph Koshy 
119ebccf1e3SJoseph Koshy /*
120789140c0SJoseph Koshy  * The pmc_event_descr structure maps symbolic names known to the user
121ebccf1e3SJoseph Koshy  * to integer codes used by the PMC KLD.
122ebccf1e3SJoseph Koshy  */
123ebccf1e3SJoseph Koshy struct pmc_event_descr {
124ebccf1e3SJoseph Koshy 	const char	*pm_ev_name;
125ebccf1e3SJoseph Koshy 	enum pmc_event	pm_ev_code;
126ebccf1e3SJoseph Koshy };
127ebccf1e3SJoseph Koshy 
128789140c0SJoseph Koshy /*
129789140c0SJoseph Koshy  * The pmc_class_descr structure maps class name prefixes for
130789140c0SJoseph Koshy  * event names to event tables and other PMC class data.
131789140c0SJoseph Koshy  */
132789140c0SJoseph Koshy struct pmc_class_descr {
133789140c0SJoseph Koshy 	const char	*pm_evc_name;
134789140c0SJoseph Koshy 	size_t		pm_evc_name_size;
135789140c0SJoseph Koshy 	enum pmc_class	pm_evc_class;
136789140c0SJoseph Koshy 	const struct pmc_event_descr *pm_evc_event_table;
137789140c0SJoseph Koshy 	size_t		pm_evc_event_table_size;
138789140c0SJoseph Koshy 	int		(*pm_evc_allocate_pmc)(enum pmc_event _pe,
139789140c0SJoseph Koshy 			    char *_ctrspec, struct pmc_op_pmcallocate *_pa);
140ebccf1e3SJoseph Koshy };
141ebccf1e3SJoseph Koshy 
142789140c0SJoseph Koshy #define	PMC_TABLE_SIZE(N)	(sizeof(N)/sizeof(N[0]))
143789140c0SJoseph Koshy #define	PMC_EVENT_TABLE_SIZE(N)	PMC_TABLE_SIZE(N##_event_table)
144789140c0SJoseph Koshy 
145789140c0SJoseph Koshy #undef	__PMC_EV
146789140c0SJoseph Koshy #define	__PMC_EV(C,N) { #N, PMC_EV_ ## C ## _ ## N },
147789140c0SJoseph Koshy 
148789140c0SJoseph Koshy /*
1490cfab8ddSJoseph Koshy  * PMC_CLASSDEP_TABLE(NAME, CLASS)
150789140c0SJoseph Koshy  *
1510cfab8ddSJoseph Koshy  * Define a table mapping event names and aliases to HWPMC event IDs.
152789140c0SJoseph Koshy  */
1530cfab8ddSJoseph Koshy #define	PMC_CLASSDEP_TABLE(N, C)				\
154789140c0SJoseph Koshy 	static const struct pmc_event_descr N##_event_table[] =	\
155789140c0SJoseph Koshy 	{							\
156789140c0SJoseph Koshy 		__PMC_EV_##C()					\
1570cfab8ddSJoseph Koshy 	}
1580cfab8ddSJoseph Koshy 
1590cfab8ddSJoseph Koshy PMC_CLASSDEP_TABLE(iaf, IAF);
1600cfab8ddSJoseph Koshy PMC_CLASSDEP_TABLE(k7, K7);
1610cfab8ddSJoseph Koshy PMC_CLASSDEP_TABLE(k8, K8);
1620cfab8ddSJoseph Koshy PMC_CLASSDEP_TABLE(p4, P4);
1630cfab8ddSJoseph Koshy PMC_CLASSDEP_TABLE(p5, P5);
1640cfab8ddSJoseph Koshy PMC_CLASSDEP_TABLE(p6, P6);
1650ce207d2SRui Paulo PMC_CLASSDEP_TABLE(xscale, XSCALE);
1666411d14dSRuslan Bukin PMC_CLASSDEP_TABLE(armv7, ARMV7);
167bc88bb2bSRuslan Bukin PMC_CLASSDEP_TABLE(armv8, ARMV8);
168660df75eSGeorge V. Neville-Neil PMC_CLASSDEP_TABLE(mips24k, MIPS24K);
169f6e6460dSAdrian Chadd PMC_CLASSDEP_TABLE(mips74k, MIPS74K);
170c2657f80SOleksandr Tymoshenko PMC_CLASSDEP_TABLE(octeon, OCTEON);
1711fa7f10bSFabien Thomas PMC_CLASSDEP_TABLE(ucf, UCF);
1727b25dccaSJustin Hibbits PMC_CLASSDEP_TABLE(ppc7450, PPC7450);
173169dd953SJustin Hibbits PMC_CLASSDEP_TABLE(ppc970, PPC970);
174a7452468SJustin Hibbits PMC_CLASSDEP_TABLE(e500, E500);
1750cfab8ddSJoseph Koshy 
176f5f9340bSFabien Thomas static struct pmc_event_descr soft_event_table[PMC_EV_DYN_COUNT];
177f5f9340bSFabien Thomas 
1780cfab8ddSJoseph Koshy #undef	__PMC_EV_ALIAS
1790cfab8ddSJoseph Koshy #define	__PMC_EV_ALIAS(N,CODE) 	{ N, PMC_EV_##CODE },
1800cfab8ddSJoseph Koshy 
1810cfab8ddSJoseph Koshy static const struct pmc_event_descr atom_event_table[] =
1820cfab8ddSJoseph Koshy {
1830cfab8ddSJoseph Koshy 	__PMC_EV_ALIAS_ATOM()
1840cfab8ddSJoseph Koshy };
1850cfab8ddSJoseph Koshy 
186e8f021a3SHiren Panchasara static const struct pmc_event_descr atom_silvermont_event_table[] =
187e8f021a3SHiren Panchasara {
188e8f021a3SHiren Panchasara 	__PMC_EV_ALIAS_ATOM_SILVERMONT()
189e8f021a3SHiren Panchasara };
190e8f021a3SHiren Panchasara 
1910cfab8ddSJoseph Koshy static const struct pmc_event_descr core_event_table[] =
1920cfab8ddSJoseph Koshy {
1930cfab8ddSJoseph Koshy 	__PMC_EV_ALIAS_CORE()
1940cfab8ddSJoseph Koshy };
1950cfab8ddSJoseph Koshy 
1960cfab8ddSJoseph Koshy 
1970cfab8ddSJoseph Koshy static const struct pmc_event_descr core2_event_table[] =
1980cfab8ddSJoseph Koshy {
1990cfab8ddSJoseph Koshy 	__PMC_EV_ALIAS_CORE2()
2000cfab8ddSJoseph Koshy };
2010cfab8ddSJoseph Koshy 
202597979c4SJeff Roberson static const struct pmc_event_descr corei7_event_table[] =
203597979c4SJeff Roberson {
204597979c4SJeff Roberson 	__PMC_EV_ALIAS_COREI7()
205597979c4SJeff Roberson };
206597979c4SJeff Roberson 
20749fe48abSKonstantin Belousov static const struct pmc_event_descr nehalem_ex_event_table[] =
20849fe48abSKonstantin Belousov {
20949fe48abSKonstantin Belousov 	__PMC_EV_ALIAS_COREI7()
21049fe48abSKonstantin Belousov };
21149fe48abSKonstantin Belousov 
212cc0c1555SSean Bruno static const struct pmc_event_descr haswell_event_table[] =
213cc0c1555SSean Bruno {
214cc0c1555SSean Bruno 	__PMC_EV_ALIAS_HASWELL()
215cc0c1555SSean Bruno };
216cc0c1555SSean Bruno 
217d95b3509SRandall Stewart static const struct pmc_event_descr haswell_xeon_event_table[] =
218d95b3509SRandall Stewart {
219d95b3509SRandall Stewart 	__PMC_EV_ALIAS_HASWELL_XEON()
220d95b3509SRandall Stewart };
221d95b3509SRandall Stewart 
222f19bae41SRandall Stewart static const struct pmc_event_descr broadwell_event_table[] =
223f19bae41SRandall Stewart {
224f19bae41SRandall Stewart 	__PMC_EV_ALIAS_BROADWELL()
225f19bae41SRandall Stewart };
226f19bae41SRandall Stewart 
227f19bae41SRandall Stewart static const struct pmc_event_descr broadwell_xeon_event_table[] =
228f19bae41SRandall Stewart {
229f19bae41SRandall Stewart 	__PMC_EV_ALIAS_BROADWELL_XEON()
230f19bae41SRandall Stewart };
231f19bae41SRandall Stewart 
232f19bae41SRandall Stewart static const struct pmc_event_descr skylake_event_table[] =
233f19bae41SRandall Stewart {
234f19bae41SRandall Stewart 	__PMC_EV_ALIAS_SKYLAKE()
235f19bae41SRandall Stewart };
236d95b3509SRandall Stewart 
237b99b705dSKonstantin Belousov static const struct pmc_event_descr skylake_xeon_event_table[] =
238b99b705dSKonstantin Belousov {
239b99b705dSKonstantin Belousov 	__PMC_EV_ALIAS_SKYLAKE_XEON()
240b99b705dSKonstantin Belousov };
241b99b705dSKonstantin Belousov 
2421e862e5aSFabien Thomas static const struct pmc_event_descr ivybridge_event_table[] =
2431e862e5aSFabien Thomas {
2441e862e5aSFabien Thomas 	__PMC_EV_ALIAS_IVYBRIDGE()
2451e862e5aSFabien Thomas };
2461e862e5aSFabien Thomas 
2473f929d8cSSean Bruno static const struct pmc_event_descr ivybridge_xeon_event_table[] =
2483f929d8cSSean Bruno {
2493f929d8cSSean Bruno 	__PMC_EV_ALIAS_IVYBRIDGE_XEON()
2503f929d8cSSean Bruno };
2513f929d8cSSean Bruno 
25278d763a2SDavide Italiano static const struct pmc_event_descr sandybridge_event_table[] =
25378d763a2SDavide Italiano {
25478d763a2SDavide Italiano 	__PMC_EV_ALIAS_SANDYBRIDGE()
25578d763a2SDavide Italiano };
25678d763a2SDavide Italiano 
257fabe02f5SSean Bruno static const struct pmc_event_descr sandybridge_xeon_event_table[] =
258fabe02f5SSean Bruno {
259fabe02f5SSean Bruno 	__PMC_EV_ALIAS_SANDYBRIDGE_XEON()
260fabe02f5SSean Bruno };
261fabe02f5SSean Bruno 
2621fa7f10bSFabien Thomas static const struct pmc_event_descr westmere_event_table[] =
2631fa7f10bSFabien Thomas {
2641fa7f10bSFabien Thomas 	__PMC_EV_ALIAS_WESTMERE()
2651fa7f10bSFabien Thomas };
2661fa7f10bSFabien Thomas 
26749fe48abSKonstantin Belousov static const struct pmc_event_descr westmere_ex_event_table[] =
26849fe48abSKonstantin Belousov {
26949fe48abSKonstantin Belousov 	__PMC_EV_ALIAS_WESTMERE()
27049fe48abSKonstantin Belousov };
27149fe48abSKonstantin Belousov 
2721fa7f10bSFabien Thomas static const struct pmc_event_descr corei7uc_event_table[] =
2731fa7f10bSFabien Thomas {
2741fa7f10bSFabien Thomas 	__PMC_EV_ALIAS_COREI7UC()
2751fa7f10bSFabien Thomas };
2761fa7f10bSFabien Thomas 
277cc0c1555SSean Bruno static const struct pmc_event_descr haswelluc_event_table[] =
278cc0c1555SSean Bruno {
279cc0c1555SSean Bruno 	__PMC_EV_ALIAS_HASWELLUC()
280cc0c1555SSean Bruno };
281cc0c1555SSean Bruno 
282f19bae41SRandall Stewart static const struct pmc_event_descr broadwelluc_event_table[] =
283f19bae41SRandall Stewart {
284f19bae41SRandall Stewart 	__PMC_EV_ALIAS_BROADWELLUC()
285f19bae41SRandall Stewart };
286f19bae41SRandall Stewart 
28778d763a2SDavide Italiano static const struct pmc_event_descr sandybridgeuc_event_table[] =
28878d763a2SDavide Italiano {
28978d763a2SDavide Italiano 	__PMC_EV_ALIAS_SANDYBRIDGEUC()
29078d763a2SDavide Italiano };
29178d763a2SDavide Italiano 
2921fa7f10bSFabien Thomas static const struct pmc_event_descr westmereuc_event_table[] =
2931fa7f10bSFabien Thomas {
2941fa7f10bSFabien Thomas 	__PMC_EV_ALIAS_WESTMEREUC()
2951fa7f10bSFabien Thomas };
2961fa7f10bSFabien Thomas 
2973e0bfdd8SRuslan Bukin static const struct pmc_event_descr cortex_a8_event_table[] =
2983e0bfdd8SRuslan Bukin {
2993e0bfdd8SRuslan Bukin 	__PMC_EV_ALIAS_ARMV7_CORTEX_A8()
3003e0bfdd8SRuslan Bukin };
3013e0bfdd8SRuslan Bukin 
3023e0bfdd8SRuslan Bukin static const struct pmc_event_descr cortex_a9_event_table[] =
3033e0bfdd8SRuslan Bukin {
3043e0bfdd8SRuslan Bukin 	__PMC_EV_ALIAS_ARMV7_CORTEX_A9()
3053e0bfdd8SRuslan Bukin };
3063e0bfdd8SRuslan Bukin 
307bc88bb2bSRuslan Bukin static const struct pmc_event_descr cortex_a53_event_table[] =
308bc88bb2bSRuslan Bukin {
309bc88bb2bSRuslan Bukin 	__PMC_EV_ALIAS_ARMV8_CORTEX_A53()
310bc88bb2bSRuslan Bukin };
311bc88bb2bSRuslan Bukin 
312bc88bb2bSRuslan Bukin static const struct pmc_event_descr cortex_a57_event_table[] =
313bc88bb2bSRuslan Bukin {
314bc88bb2bSRuslan Bukin 	__PMC_EV_ALIAS_ARMV8_CORTEX_A57()
315bc88bb2bSRuslan Bukin };
316bc88bb2bSRuslan Bukin 
3170cfab8ddSJoseph Koshy /*
3180cfab8ddSJoseph Koshy  * PMC_MDEP_TABLE(NAME, PRIMARYCLASS, ADDITIONAL_CLASSES...)
3190cfab8ddSJoseph Koshy  *
3200cfab8ddSJoseph Koshy  * Map a CPU to the PMC classes it supports.
3210cfab8ddSJoseph Koshy  */
3220cfab8ddSJoseph Koshy #define	PMC_MDEP_TABLE(N,C,...)				\
323789140c0SJoseph Koshy 	static const enum pmc_class N##_pmc_classes[] = {	\
324789140c0SJoseph Koshy 		PMC_CLASS_##C, __VA_ARGS__			\
325789140c0SJoseph Koshy 	}
326789140c0SJoseph Koshy 
327f5f9340bSFabien Thomas PMC_MDEP_TABLE(atom, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC);
328e8f021a3SHiren Panchasara PMC_MDEP_TABLE(atom_silvermont, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC);
329f5f9340bSFabien Thomas PMC_MDEP_TABLE(core, IAP, PMC_CLASS_SOFT, PMC_CLASS_TSC);
330f5f9340bSFabien Thomas PMC_MDEP_TABLE(core2, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC);
331f5f9340bSFabien Thomas PMC_MDEP_TABLE(corei7, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC, PMC_CLASS_UCF, PMC_CLASS_UCP);
33249fe48abSKonstantin Belousov PMC_MDEP_TABLE(nehalem_ex, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC);
333cc0c1555SSean Bruno PMC_MDEP_TABLE(haswell, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC, PMC_CLASS_UCF, PMC_CLASS_UCP);
334d95b3509SRandall Stewart PMC_MDEP_TABLE(haswell_xeon, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC, PMC_CLASS_UCF, PMC_CLASS_UCP);
335f19bae41SRandall Stewart PMC_MDEP_TABLE(broadwell, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC, PMC_CLASS_UCF, PMC_CLASS_UCP);
336f19bae41SRandall Stewart PMC_MDEP_TABLE(broadwell_xeon, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC, PMC_CLASS_UCF, PMC_CLASS_UCP);
337f19bae41SRandall Stewart PMC_MDEP_TABLE(skylake, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC, PMC_CLASS_UCF, PMC_CLASS_UCP);
338b99b705dSKonstantin Belousov PMC_MDEP_TABLE(skylake_xeon, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC);
3391e862e5aSFabien Thomas PMC_MDEP_TABLE(ivybridge, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC);
3403f929d8cSSean Bruno PMC_MDEP_TABLE(ivybridge_xeon, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC);
341f5f9340bSFabien Thomas PMC_MDEP_TABLE(sandybridge, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC, PMC_CLASS_UCF, PMC_CLASS_UCP);
342fabe02f5SSean Bruno PMC_MDEP_TABLE(sandybridge_xeon, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC);
343f5f9340bSFabien Thomas PMC_MDEP_TABLE(westmere, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC, PMC_CLASS_UCF, PMC_CLASS_UCP);
34449fe48abSKonstantin Belousov PMC_MDEP_TABLE(westmere_ex, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC);
345f5f9340bSFabien Thomas PMC_MDEP_TABLE(k7, K7, PMC_CLASS_SOFT, PMC_CLASS_TSC);
346f5f9340bSFabien Thomas PMC_MDEP_TABLE(k8, K8, PMC_CLASS_SOFT, PMC_CLASS_TSC);
347f5f9340bSFabien Thomas PMC_MDEP_TABLE(p4, P4, PMC_CLASS_SOFT, PMC_CLASS_TSC);
348f5f9340bSFabien Thomas PMC_MDEP_TABLE(p5, P5, PMC_CLASS_SOFT, PMC_CLASS_TSC);
349f5f9340bSFabien Thomas PMC_MDEP_TABLE(p6, P6, PMC_CLASS_SOFT, PMC_CLASS_TSC);
350f5f9340bSFabien Thomas PMC_MDEP_TABLE(xscale, XSCALE, PMC_CLASS_SOFT, PMC_CLASS_XSCALE);
3513e0bfdd8SRuslan Bukin PMC_MDEP_TABLE(cortex_a8, ARMV7, PMC_CLASS_SOFT, PMC_CLASS_ARMV7);
3523e0bfdd8SRuslan Bukin PMC_MDEP_TABLE(cortex_a9, ARMV7, PMC_CLASS_SOFT, PMC_CLASS_ARMV7);
353bc88bb2bSRuslan Bukin PMC_MDEP_TABLE(cortex_a53, ARMV8, PMC_CLASS_SOFT, PMC_CLASS_ARMV8);
354bc88bb2bSRuslan Bukin PMC_MDEP_TABLE(cortex_a57, ARMV8, PMC_CLASS_SOFT, PMC_CLASS_ARMV8);
355f5f9340bSFabien Thomas PMC_MDEP_TABLE(mips24k, MIPS24K, PMC_CLASS_SOFT, PMC_CLASS_MIPS24K);
356f6e6460dSAdrian Chadd PMC_MDEP_TABLE(mips74k, MIPS74K, PMC_CLASS_SOFT, PMC_CLASS_MIPS74K);
357f5f9340bSFabien Thomas PMC_MDEP_TABLE(octeon, OCTEON, PMC_CLASS_SOFT, PMC_CLASS_OCTEON);
358a7452468SJustin Hibbits PMC_MDEP_TABLE(ppc7450, PPC7450, PMC_CLASS_SOFT, PMC_CLASS_PPC7450, PMC_CLASS_TSC);
359a7452468SJustin Hibbits PMC_MDEP_TABLE(ppc970, PPC970, PMC_CLASS_SOFT, PMC_CLASS_PPC970, PMC_CLASS_TSC);
360a7452468SJustin Hibbits PMC_MDEP_TABLE(e500, E500, PMC_CLASS_SOFT, PMC_CLASS_E500, PMC_CLASS_TSC);
361f5f9340bSFabien Thomas PMC_MDEP_TABLE(generic, SOFT, PMC_CLASS_SOFT);
362789140c0SJoseph Koshy 
363789140c0SJoseph Koshy static const struct pmc_event_descr tsc_event_table[] =
364789140c0SJoseph Koshy {
365789140c0SJoseph Koshy 	__PMC_EV_TSC()
366789140c0SJoseph Koshy };
367789140c0SJoseph Koshy 
368789140c0SJoseph Koshy #undef	PMC_CLASS_TABLE_DESC
3690cfab8ddSJoseph Koshy #define	PMC_CLASS_TABLE_DESC(NAME, CLASS, EVENTS, ALLOCATOR)	\
3700cfab8ddSJoseph Koshy static const struct pmc_class_descr NAME##_class_table_descr =	\
3710cfab8ddSJoseph Koshy 	{							\
3720cfab8ddSJoseph Koshy 		.pm_evc_name  = #CLASS "-",			\
3730cfab8ddSJoseph Koshy 		.pm_evc_name_size = sizeof(#CLASS "-") - 1,	\
3740cfab8ddSJoseph Koshy 		.pm_evc_class = PMC_CLASS_##CLASS ,		\
3750cfab8ddSJoseph Koshy 		.pm_evc_event_table = EVENTS##_event_table ,	\
376789140c0SJoseph Koshy 		.pm_evc_event_table_size = 			\
3770cfab8ddSJoseph Koshy 			PMC_EVENT_TABLE_SIZE(EVENTS),		\
3780cfab8ddSJoseph Koshy 		.pm_evc_allocate_pmc = ALLOCATOR##_allocate_pmc	\
379789140c0SJoseph Koshy 	}
380789140c0SJoseph Koshy 
381789140c0SJoseph Koshy #if	defined(__i386__) || defined(__amd64__)
3820cfab8ddSJoseph Koshy PMC_CLASS_TABLE_DESC(iaf, IAF, iaf, iaf);
3830cfab8ddSJoseph Koshy PMC_CLASS_TABLE_DESC(atom, IAP, atom, iap);
384e8f021a3SHiren Panchasara PMC_CLASS_TABLE_DESC(atom_silvermont, IAP, atom_silvermont, iap);
3850cfab8ddSJoseph Koshy PMC_CLASS_TABLE_DESC(core, IAP, core, iap);
3860cfab8ddSJoseph Koshy PMC_CLASS_TABLE_DESC(core2, IAP, core2, iap);
387597979c4SJeff Roberson PMC_CLASS_TABLE_DESC(corei7, IAP, corei7, iap);
38849fe48abSKonstantin Belousov PMC_CLASS_TABLE_DESC(nehalem_ex, IAP, nehalem_ex, iap);
389cc0c1555SSean Bruno PMC_CLASS_TABLE_DESC(haswell, IAP, haswell, iap);
390ae9975dbSRyan Stone PMC_CLASS_TABLE_DESC(haswell_xeon, IAP, haswell_xeon, iap);
391f19bae41SRandall Stewart PMC_CLASS_TABLE_DESC(broadwell, IAP, broadwell, iap);
392f19bae41SRandall Stewart PMC_CLASS_TABLE_DESC(broadwell_xeon, IAP, broadwell_xeon, iap);
393f19bae41SRandall Stewart PMC_CLASS_TABLE_DESC(skylake, IAP, skylake, iap);
394b99b705dSKonstantin Belousov PMC_CLASS_TABLE_DESC(skylake_xeon, IAP, skylake_xeon, iap);
3951e862e5aSFabien Thomas PMC_CLASS_TABLE_DESC(ivybridge, IAP, ivybridge, iap);
3963f929d8cSSean Bruno PMC_CLASS_TABLE_DESC(ivybridge_xeon, IAP, ivybridge_xeon, iap);
39778d763a2SDavide Italiano PMC_CLASS_TABLE_DESC(sandybridge, IAP, sandybridge, iap);
398fabe02f5SSean Bruno PMC_CLASS_TABLE_DESC(sandybridge_xeon, IAP, sandybridge_xeon, iap);
3991fa7f10bSFabien Thomas PMC_CLASS_TABLE_DESC(westmere, IAP, westmere, iap);
40049fe48abSKonstantin Belousov PMC_CLASS_TABLE_DESC(westmere_ex, IAP, westmere_ex, iap);
4011fa7f10bSFabien Thomas PMC_CLASS_TABLE_DESC(ucf, UCF, ucf, ucf);
4021fa7f10bSFabien Thomas PMC_CLASS_TABLE_DESC(corei7uc, UCP, corei7uc, ucp);
403cc0c1555SSean Bruno PMC_CLASS_TABLE_DESC(haswelluc, UCP, haswelluc, ucp);
404f19bae41SRandall Stewart PMC_CLASS_TABLE_DESC(broadwelluc, UCP, broadwelluc, ucp);
40578d763a2SDavide Italiano PMC_CLASS_TABLE_DESC(sandybridgeuc, UCP, sandybridgeuc, ucp);
4061fa7f10bSFabien Thomas PMC_CLASS_TABLE_DESC(westmereuc, UCP, westmereuc, ucp);
407789140c0SJoseph Koshy #endif
408789140c0SJoseph Koshy #if	defined(__i386__)
4090cfab8ddSJoseph Koshy PMC_CLASS_TABLE_DESC(k7, K7, k7, k7);
410789140c0SJoseph Koshy #endif
411789140c0SJoseph Koshy #if	defined(__i386__) || defined(__amd64__)
4120cfab8ddSJoseph Koshy PMC_CLASS_TABLE_DESC(k8, K8, k8, k8);
4130cfab8ddSJoseph Koshy PMC_CLASS_TABLE_DESC(p4, P4, p4, p4);
414789140c0SJoseph Koshy #endif
4150cfab8ddSJoseph Koshy #if	defined(__i386__)
4160cfab8ddSJoseph Koshy PMC_CLASS_TABLE_DESC(p5, P5, p5, p5);
4170cfab8ddSJoseph Koshy PMC_CLASS_TABLE_DESC(p6, P6, p6, p6);
4180cfab8ddSJoseph Koshy #endif
4190cfab8ddSJoseph Koshy #if	defined(__i386__) || defined(__amd64__)
4200cfab8ddSJoseph Koshy PMC_CLASS_TABLE_DESC(tsc, TSC, tsc, tsc);
4210cfab8ddSJoseph Koshy #endif
4226411d14dSRuslan Bukin #if	defined(__arm__)
4230ce207d2SRui Paulo #if	defined(__XSCALE__)
4240ce207d2SRui Paulo PMC_CLASS_TABLE_DESC(xscale, XSCALE, xscale, xscale);
4250ce207d2SRui Paulo #endif
4263ed01392SBjoern A. Zeeb PMC_CLASS_TABLE_DESC(cortex_a8, ARMV7, cortex_a8, armv7);
4273e0bfdd8SRuslan Bukin PMC_CLASS_TABLE_DESC(cortex_a9, ARMV7, cortex_a9, armv7);
4286411d14dSRuslan Bukin #endif
429bc88bb2bSRuslan Bukin #if	defined(__aarch64__)
430bc88bb2bSRuslan Bukin PMC_CLASS_TABLE_DESC(cortex_a53, ARMV8, cortex_a53, arm64);
431bc88bb2bSRuslan Bukin PMC_CLASS_TABLE_DESC(cortex_a57, ARMV8, cortex_a57, arm64);
432bc88bb2bSRuslan Bukin #endif
433660df75eSGeorge V. Neville-Neil #if defined(__mips__)
4342827d3e1SOleksandr Tymoshenko PMC_CLASS_TABLE_DESC(mips24k, MIPS24K, mips24k, mips);
435f6e6460dSAdrian Chadd PMC_CLASS_TABLE_DESC(mips74k, MIPS74K, mips74k, mips);
436c2657f80SOleksandr Tymoshenko PMC_CLASS_TABLE_DESC(octeon, OCTEON, octeon, mips);
437660df75eSGeorge V. Neville-Neil #endif /* __mips__ */
4387b25dccaSJustin Hibbits #if defined(__powerpc__)
439169dd953SJustin Hibbits PMC_CLASS_TABLE_DESC(ppc7450, PPC7450, ppc7450, powerpc);
440169dd953SJustin Hibbits PMC_CLASS_TABLE_DESC(ppc970, PPC970, ppc970, powerpc);
441a7452468SJustin Hibbits PMC_CLASS_TABLE_DESC(e500, E500, e500, powerpc);
4427b25dccaSJustin Hibbits #endif
4437b25dccaSJustin Hibbits 
444f5f9340bSFabien Thomas static struct pmc_class_descr soft_class_table_descr =
445f5f9340bSFabien Thomas {
446f5f9340bSFabien Thomas 	.pm_evc_name  = "SOFT-",
447f5f9340bSFabien Thomas 	.pm_evc_name_size = sizeof("SOFT-") - 1,
448f5f9340bSFabien Thomas 	.pm_evc_class = PMC_CLASS_SOFT,
449f5f9340bSFabien Thomas 	.pm_evc_event_table = NULL,
450f5f9340bSFabien Thomas 	.pm_evc_event_table_size = 0,
451f5f9340bSFabien Thomas 	.pm_evc_allocate_pmc = soft_allocate_pmc
452f5f9340bSFabien Thomas };
453f5f9340bSFabien Thomas 
454789140c0SJoseph Koshy #undef	PMC_CLASS_TABLE_DESC
455789140c0SJoseph Koshy 
4560cfab8ddSJoseph Koshy static const struct pmc_class_descr **pmc_class_table;
4570cfab8ddSJoseph Koshy #define	PMC_CLASS_TABLE_SIZE	cpu_info.pm_nclass
4580cfab8ddSJoseph Koshy 
459789140c0SJoseph Koshy static const enum pmc_class *pmc_mdep_class_list;
460789140c0SJoseph Koshy static size_t pmc_mdep_class_list_size;
461789140c0SJoseph Koshy 
462ebccf1e3SJoseph Koshy /*
463ebccf1e3SJoseph Koshy  * Mapping tables, mapping enumeration values to human readable
464ebccf1e3SJoseph Koshy  * strings.
465ebccf1e3SJoseph Koshy  */
466ebccf1e3SJoseph Koshy 
467ebccf1e3SJoseph Koshy static const char * pmc_capability_names[] = {
468ebccf1e3SJoseph Koshy #undef	__PMC_CAP
469ebccf1e3SJoseph Koshy #define	__PMC_CAP(N,V,D)	#N ,
470ebccf1e3SJoseph Koshy 	__PMC_CAPS()
471ebccf1e3SJoseph Koshy };
472ebccf1e3SJoseph Koshy 
4730ceb54c2SJohn Baldwin struct pmc_class_map {
4740ceb54c2SJohn Baldwin 	enum pmc_class	pm_class;
4750ceb54c2SJohn Baldwin 	const char	*pm_name;
4760ceb54c2SJohn Baldwin };
4770ceb54c2SJohn Baldwin 
4780ceb54c2SJohn Baldwin static const struct pmc_class_map pmc_class_names[] = {
479ebccf1e3SJoseph Koshy #undef	__PMC_CLASS
4800ceb54c2SJohn Baldwin #define __PMC_CLASS(S,V,D) { .pm_class = PMC_CLASS_##S, .pm_name = #S } ,
481ebccf1e3SJoseph Koshy 	__PMC_CLASSES()
482ebccf1e3SJoseph Koshy };
483ebccf1e3SJoseph Koshy 
484789140c0SJoseph Koshy struct pmc_cputype_map {
485562fc14bSDimitry Andric 	enum pmc_cputype pm_cputype;
486789140c0SJoseph Koshy 	const char	*pm_name;
487789140c0SJoseph Koshy };
488789140c0SJoseph Koshy 
489789140c0SJoseph Koshy static const struct pmc_cputype_map pmc_cputype_names[] = {
490ebccf1e3SJoseph Koshy #undef	__PMC_CPU
491789140c0SJoseph Koshy #define	__PMC_CPU(S, V, D) { .pm_cputype = PMC_CPU_##S, .pm_name = #S } ,
492ebccf1e3SJoseph Koshy 	__PMC_CPUS()
493ebccf1e3SJoseph Koshy };
494ebccf1e3SJoseph Koshy 
495ebccf1e3SJoseph Koshy static const char * pmc_disposition_names[] = {
496ebccf1e3SJoseph Koshy #undef	__PMC_DISP
497ebccf1e3SJoseph Koshy #define	__PMC_DISP(D)	#D ,
498ebccf1e3SJoseph Koshy 	__PMC_DISPOSITIONS()
499ebccf1e3SJoseph Koshy };
500ebccf1e3SJoseph Koshy 
501ebccf1e3SJoseph Koshy static const char * pmc_mode_names[] = {
502ebccf1e3SJoseph Koshy #undef  __PMC_MODE
503ebccf1e3SJoseph Koshy #define __PMC_MODE(M,N)	#M ,
504ebccf1e3SJoseph Koshy 	__PMC_MODES()
505ebccf1e3SJoseph Koshy };
506ebccf1e3SJoseph Koshy 
507ebccf1e3SJoseph Koshy static const char * pmc_state_names[] = {
508ebccf1e3SJoseph Koshy #undef  __PMC_STATE
509ebccf1e3SJoseph Koshy #define __PMC_STATE(S) #S ,
510ebccf1e3SJoseph Koshy 	__PMC_STATES()
511ebccf1e3SJoseph Koshy };
512ebccf1e3SJoseph Koshy 
513f5f9340bSFabien Thomas /*
514f5f9340bSFabien Thomas  * Filled in by pmc_init().
515f5f9340bSFabien Thomas  */
516f5f9340bSFabien Thomas static int pmc_syscall = -1;
517f5f9340bSFabien Thomas static struct pmc_cpuinfo cpu_info;
518f5f9340bSFabien Thomas static struct pmc_op_getdyneventinfo soft_event_info;
5191455fcd3SJoseph Koshy 
520ebccf1e3SJoseph Koshy /* Event masks for events */
521ebccf1e3SJoseph Koshy struct pmc_masks {
522ebccf1e3SJoseph Koshy 	const char	*pm_name;
5231e862e5aSFabien Thomas 	const uint64_t	pm_value;
524ebccf1e3SJoseph Koshy };
525ebccf1e3SJoseph Koshy #define	PMCMASK(N,V)	{ .pm_name = #N, .pm_value = (V) }
5261fa7f10bSFabien Thomas #define	NULLMASK	{ .pm_name = NULL }
527ebccf1e3SJoseph Koshy 
52886a65549SJoseph Koshy #if defined(__amd64__) || defined(__i386__)
529ebccf1e3SJoseph Koshy static int
5301e862e5aSFabien Thomas pmc_parse_mask(const struct pmc_masks *pmask, char *p, uint64_t *evmask)
531ebccf1e3SJoseph Koshy {
532ebccf1e3SJoseph Koshy 	const struct pmc_masks *pm;
533ebccf1e3SJoseph Koshy 	char *q, *r;
534ebccf1e3SJoseph Koshy 	int c;
535ebccf1e3SJoseph Koshy 
536ebccf1e3SJoseph Koshy 	if (pmask == NULL)	/* no mask keywords */
537aa342b1fSJoseph Koshy 		return (-1);
538ebccf1e3SJoseph Koshy 	q = strchr(p, '=');	/* skip '=' */
539ebccf1e3SJoseph Koshy 	if (*++q == '\0')	/* no more data */
540aa342b1fSJoseph Koshy 		return (-1);
541ebccf1e3SJoseph Koshy 	c = 0;			/* count of mask keywords seen */
542ebccf1e3SJoseph Koshy 	while ((r = strsep(&q, "+")) != NULL) {
543789140c0SJoseph Koshy 		for (pm = pmask; pm->pm_name && strcasecmp(r, pm->pm_name);
544789140c0SJoseph Koshy 		    pm++)
545ebccf1e3SJoseph Koshy 			;
546ebccf1e3SJoseph Koshy 		if (pm->pm_name == NULL) /* not found */
547aa342b1fSJoseph Koshy 			return (-1);
548ebccf1e3SJoseph Koshy 		*evmask |= pm->pm_value;
549ebccf1e3SJoseph Koshy 		c++;
550ebccf1e3SJoseph Koshy 	}
551aa342b1fSJoseph Koshy 	return (c);
552ebccf1e3SJoseph Koshy }
55304e9feb0SMarcel Moolenaar #endif
554ebccf1e3SJoseph Koshy 
555ebccf1e3SJoseph Koshy #define	KWMATCH(p,kw)		(strcasecmp((p), (kw)) == 0)
556ebccf1e3SJoseph Koshy #define	KWPREFIXMATCH(p,kw)	(strncasecmp((p), (kw), sizeof((kw)) - 1) == 0)
557ebccf1e3SJoseph Koshy #define	EV_ALIAS(N,S)		{ .pm_alias = N, .pm_spec = S }
558ebccf1e3SJoseph Koshy 
55904e9feb0SMarcel Moolenaar #if defined(__i386__)
560ebccf1e3SJoseph Koshy 
561ebccf1e3SJoseph Koshy /*
562ebccf1e3SJoseph Koshy  * AMD K7 (Athlon) CPUs.
563ebccf1e3SJoseph Koshy  */
564ebccf1e3SJoseph Koshy 
565ebccf1e3SJoseph Koshy static struct pmc_event_alias k7_aliases[] = {
566ebccf1e3SJoseph Koshy 	EV_ALIAS("branches",		"k7-retired-branches"),
567ebccf1e3SJoseph Koshy 	EV_ALIAS("branch-mispredicts",	"k7-retired-branches-mispredicted"),
568ebccf1e3SJoseph Koshy 	EV_ALIAS("cycles",		"tsc"),
5696aa5a193SJoseph Koshy 	EV_ALIAS("dc-misses",		"k7-dc-misses"),
570ebccf1e3SJoseph Koshy 	EV_ALIAS("ic-misses",		"k7-ic-misses"),
571ebccf1e3SJoseph Koshy 	EV_ALIAS("instructions",	"k7-retired-instructions"),
572ebccf1e3SJoseph Koshy 	EV_ALIAS("interrupts",		"k7-hardware-interrupts"),
573ebccf1e3SJoseph Koshy 	EV_ALIAS(NULL, NULL)
574ebccf1e3SJoseph Koshy };
575ebccf1e3SJoseph Koshy 
576ebccf1e3SJoseph Koshy #define	K7_KW_COUNT	"count"
577ebccf1e3SJoseph Koshy #define	K7_KW_EDGE	"edge"
578ebccf1e3SJoseph Koshy #define	K7_KW_INV	"inv"
579ebccf1e3SJoseph Koshy #define	K7_KW_OS	"os"
580ebccf1e3SJoseph Koshy #define	K7_KW_UNITMASK	"unitmask"
581ebccf1e3SJoseph Koshy #define	K7_KW_USR	"usr"
582ebccf1e3SJoseph Koshy 
583ebccf1e3SJoseph Koshy static int
584ebccf1e3SJoseph Koshy k7_allocate_pmc(enum pmc_event pe, char *ctrspec,
585ebccf1e3SJoseph Koshy     struct pmc_op_pmcallocate *pmc_config)
586ebccf1e3SJoseph Koshy {
587ebccf1e3SJoseph Koshy 	char		*e, *p, *q;
588ebccf1e3SJoseph Koshy 	int		c, has_unitmask;
589ebccf1e3SJoseph Koshy 	uint32_t	count, unitmask;
590ebccf1e3SJoseph Koshy 
591f263522aSJoseph Koshy 	pmc_config->pm_md.pm_amd.pm_amd_config = 0;
592789140c0SJoseph Koshy 	pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE);
593ebccf1e3SJoseph Koshy 
594ebccf1e3SJoseph Koshy 	if (pe == PMC_EV_K7_DC_REFILLS_FROM_L2 ||
595ebccf1e3SJoseph Koshy 	    pe == PMC_EV_K7_DC_REFILLS_FROM_SYSTEM ||
596ebccf1e3SJoseph Koshy 	    pe == PMC_EV_K7_DC_WRITEBACKS) {
597ebccf1e3SJoseph Koshy 		has_unitmask = 1;
598f263522aSJoseph Koshy 		unitmask = AMD_PMC_UNITMASK_MOESI;
599ebccf1e3SJoseph Koshy 	} else
600ebccf1e3SJoseph Koshy 		unitmask = has_unitmask = 0;
601ebccf1e3SJoseph Koshy 
602ebccf1e3SJoseph Koshy 	while ((p = strsep(&ctrspec, ",")) != NULL) {
603ebccf1e3SJoseph Koshy 		if (KWPREFIXMATCH(p, K7_KW_COUNT "=")) {
604ebccf1e3SJoseph Koshy 			q = strchr(p, '=');
605ebccf1e3SJoseph Koshy 			if (*++q == '\0') /* skip '=' */
606aa342b1fSJoseph Koshy 				return (-1);
607ebccf1e3SJoseph Koshy 
608ebccf1e3SJoseph Koshy 			count = strtol(q, &e, 0);
609ebccf1e3SJoseph Koshy 			if (e == q || *e != '\0')
610aa342b1fSJoseph Koshy 				return (-1);
611ebccf1e3SJoseph Koshy 
612ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_THRESHOLD;
613f263522aSJoseph Koshy 			pmc_config->pm_md.pm_amd.pm_amd_config |=
614f263522aSJoseph Koshy 			    AMD_PMC_TO_COUNTER(count);
615ebccf1e3SJoseph Koshy 
616ebccf1e3SJoseph Koshy 		} else if (KWMATCH(p, K7_KW_EDGE)) {
617ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_EDGE;
618ebccf1e3SJoseph Koshy 		} else if (KWMATCH(p, K7_KW_INV)) {
619ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_INVERT;
620ebccf1e3SJoseph Koshy 		} else if (KWMATCH(p, K7_KW_OS)) {
621ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_SYSTEM;
622ebccf1e3SJoseph Koshy 		} else if (KWPREFIXMATCH(p, K7_KW_UNITMASK "=")) {
623ebccf1e3SJoseph Koshy 			if (has_unitmask == 0)
624aa342b1fSJoseph Koshy 				return (-1);
625ebccf1e3SJoseph Koshy 			unitmask = 0;
626ebccf1e3SJoseph Koshy 			q = strchr(p, '=');
627ebccf1e3SJoseph Koshy 			if (*++q == '\0') /* skip '=' */
628aa342b1fSJoseph Koshy 				return (-1);
629ebccf1e3SJoseph Koshy 
630ebccf1e3SJoseph Koshy 			while ((c = tolower(*q++)) != 0)
631ebccf1e3SJoseph Koshy 				if (c == 'm')
632f263522aSJoseph Koshy 					unitmask |= AMD_PMC_UNITMASK_M;
633ebccf1e3SJoseph Koshy 				else if (c == 'o')
634f263522aSJoseph Koshy 					unitmask |= AMD_PMC_UNITMASK_O;
635ebccf1e3SJoseph Koshy 				else if (c == 'e')
636f263522aSJoseph Koshy 					unitmask |= AMD_PMC_UNITMASK_E;
637ebccf1e3SJoseph Koshy 				else if (c == 's')
638f263522aSJoseph Koshy 					unitmask |= AMD_PMC_UNITMASK_S;
639ebccf1e3SJoseph Koshy 				else if (c == 'i')
640f263522aSJoseph Koshy 					unitmask |= AMD_PMC_UNITMASK_I;
641ebccf1e3SJoseph Koshy 				else if (c == '+')
642ebccf1e3SJoseph Koshy 					continue;
643ebccf1e3SJoseph Koshy 				else
644aa342b1fSJoseph Koshy 					return (-1);
645ebccf1e3SJoseph Koshy 
646ebccf1e3SJoseph Koshy 			if (unitmask == 0)
647aa342b1fSJoseph Koshy 				return (-1);
648ebccf1e3SJoseph Koshy 
649ebccf1e3SJoseph Koshy 		} else if (KWMATCH(p, K7_KW_USR)) {
650ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_USER;
651ebccf1e3SJoseph Koshy 		} else
652aa342b1fSJoseph Koshy 			return (-1);
653ebccf1e3SJoseph Koshy 	}
654ebccf1e3SJoseph Koshy 
655ebccf1e3SJoseph Koshy 	if (has_unitmask) {
656ebccf1e3SJoseph Koshy 		pmc_config->pm_caps |= PMC_CAP_QUALIFIER;
657f263522aSJoseph Koshy 		pmc_config->pm_md.pm_amd.pm_amd_config |=
658f263522aSJoseph Koshy 		    AMD_PMC_TO_UNITMASK(unitmask);
659ebccf1e3SJoseph Koshy 	}
660ebccf1e3SJoseph Koshy 
661aa342b1fSJoseph Koshy 	return (0);
662ebccf1e3SJoseph Koshy 
663ebccf1e3SJoseph Koshy }
664ebccf1e3SJoseph Koshy 
665f263522aSJoseph Koshy #endif
666f263522aSJoseph Koshy 
66786a65549SJoseph Koshy #if defined(__amd64__) || defined(__i386__)
668f263522aSJoseph Koshy 
669f263522aSJoseph Koshy /*
6700cfab8ddSJoseph Koshy  * Intel Core (Family 6, Model E) PMCs.
6710cfab8ddSJoseph Koshy  */
6720cfab8ddSJoseph Koshy 
6730cfab8ddSJoseph Koshy static struct pmc_event_alias core_aliases[] = {
6740cfab8ddSJoseph Koshy 	EV_ALIAS("branches",		"iap-br-instr-ret"),
6750cfab8ddSJoseph Koshy 	EV_ALIAS("branch-mispredicts",	"iap-br-mispred-ret"),
6760cfab8ddSJoseph Koshy 	EV_ALIAS("cycles",		"tsc-tsc"),
6770cfab8ddSJoseph Koshy 	EV_ALIAS("ic-misses",		"iap-icache-misses"),
6780cfab8ddSJoseph Koshy 	EV_ALIAS("instructions",	"iap-instr-ret"),
6790cfab8ddSJoseph Koshy 	EV_ALIAS("interrupts",		"iap-core-hw-int-rx"),
6800cfab8ddSJoseph Koshy 	EV_ALIAS("unhalted-cycles",	"iap-unhalted-core-cycles"),
6810cfab8ddSJoseph Koshy 	EV_ALIAS(NULL, NULL)
6820cfab8ddSJoseph Koshy };
6830cfab8ddSJoseph Koshy 
6840cfab8ddSJoseph Koshy /*
6850cfab8ddSJoseph Koshy  * Intel Core2 (Family 6, Model F), Core2Extreme (Family 6, Model 17H)
6860cfab8ddSJoseph Koshy  * and Atom (Family 6, model 1CH) PMCs.
687791f5d5bSJoseph Koshy  *
688791f5d5bSJoseph Koshy  * We map aliases to events on the fixed-function counters if these
689791f5d5bSJoseph Koshy  * are present.  Note that not all CPUs in this family contain fixed-function
690791f5d5bSJoseph Koshy  * counters.
6910cfab8ddSJoseph Koshy  */
6920cfab8ddSJoseph Koshy 
6930cfab8ddSJoseph Koshy static struct pmc_event_alias core2_aliases[] = {
6940cfab8ddSJoseph Koshy 	EV_ALIAS("branches",		"iap-br-inst-retired.any"),
6950cfab8ddSJoseph Koshy 	EV_ALIAS("branch-mispredicts",	"iap-br-inst-retired.mispred"),
6960cfab8ddSJoseph Koshy 	EV_ALIAS("cycles",		"tsc-tsc"),
6970cfab8ddSJoseph Koshy 	EV_ALIAS("ic-misses",		"iap-l1i-misses"),
6980cfab8ddSJoseph Koshy 	EV_ALIAS("instructions",	"iaf-instr-retired.any"),
6990cfab8ddSJoseph Koshy 	EV_ALIAS("interrupts",		"iap-hw-int-rcv"),
7000cfab8ddSJoseph Koshy 	EV_ALIAS("unhalted-cycles",	"iaf-cpu-clk-unhalted.core"),
7010cfab8ddSJoseph Koshy 	EV_ALIAS(NULL, NULL)
7020cfab8ddSJoseph Koshy };
703791f5d5bSJoseph Koshy 
704791f5d5bSJoseph Koshy static struct pmc_event_alias core2_aliases_without_iaf[] = {
705791f5d5bSJoseph Koshy 	EV_ALIAS("branches",		"iap-br-inst-retired.any"),
706791f5d5bSJoseph Koshy 	EV_ALIAS("branch-mispredicts",	"iap-br-inst-retired.mispred"),
707791f5d5bSJoseph Koshy 	EV_ALIAS("cycles",		"tsc-tsc"),
708791f5d5bSJoseph Koshy 	EV_ALIAS("ic-misses",		"iap-l1i-misses"),
709791f5d5bSJoseph Koshy 	EV_ALIAS("instructions",	"iap-inst-retired.any_p"),
710791f5d5bSJoseph Koshy 	EV_ALIAS("interrupts",		"iap-hw-int-rcv"),
711791f5d5bSJoseph Koshy 	EV_ALIAS("unhalted-cycles",	"iap-cpu-clk-unhalted.core_p"),
712791f5d5bSJoseph Koshy 	EV_ALIAS(NULL, NULL)
713791f5d5bSJoseph Koshy };
714791f5d5bSJoseph Koshy 
7150cfab8ddSJoseph Koshy #define	atom_aliases			core2_aliases
716791f5d5bSJoseph Koshy #define	atom_aliases_without_iaf	core2_aliases_without_iaf
717e8f021a3SHiren Panchasara #define	atom_silvermont_aliases		core2_aliases
718e8f021a3SHiren Panchasara #define	atom_silvermont_aliases_without_iaf	core2_aliases_without_iaf
719597979c4SJeff Roberson #define corei7_aliases			core2_aliases
720791f5d5bSJoseph Koshy #define corei7_aliases_without_iaf	core2_aliases_without_iaf
72149fe48abSKonstantin Belousov #define nehalem_ex_aliases		core2_aliases
72249fe48abSKonstantin Belousov #define nehalem_ex_aliases_without_iaf	core2_aliases_without_iaf
723cc0c1555SSean Bruno #define haswell_aliases			core2_aliases
724cc0c1555SSean Bruno #define haswell_aliases_without_iaf	core2_aliases_without_iaf
725d95b3509SRandall Stewart #define haswell_xeon_aliases			core2_aliases
726d95b3509SRandall Stewart #define haswell_xeon_aliases_without_iaf	core2_aliases_without_iaf
727f19bae41SRandall Stewart #define broadwell_aliases			core2_aliases
728f19bae41SRandall Stewart #define broadwell_aliases_without_iaf	core2_aliases_without_iaf
729f19bae41SRandall Stewart #define broadwell_xeon_aliases			core2_aliases
730f19bae41SRandall Stewart #define broadwell_xeon_aliases_without_iaf	core2_aliases_without_iaf
731f19bae41SRandall Stewart #define skylake_aliases			core2_aliases
732f19bae41SRandall Stewart #define skylake_aliases_without_iaf	core2_aliases_without_iaf
733b99b705dSKonstantin Belousov #define skylake_xeon_aliases		core2_aliases
734b99b705dSKonstantin Belousov #define skylake_xeon_aliases_without_iaf	core2_aliases_without_iaf
7351e862e5aSFabien Thomas #define ivybridge_aliases		core2_aliases
7361e862e5aSFabien Thomas #define ivybridge_aliases_without_iaf	core2_aliases_without_iaf
7373f929d8cSSean Bruno #define ivybridge_xeon_aliases		core2_aliases
7383f929d8cSSean Bruno #define ivybridge_xeon_aliases_without_iaf	core2_aliases_without_iaf
73978d763a2SDavide Italiano #define sandybridge_aliases		core2_aliases
74078d763a2SDavide Italiano #define sandybridge_aliases_without_iaf	core2_aliases_without_iaf
741fabe02f5SSean Bruno #define sandybridge_xeon_aliases	core2_aliases
742fabe02f5SSean Bruno #define sandybridge_xeon_aliases_without_iaf	core2_aliases_without_iaf
7431fa7f10bSFabien Thomas #define westmere_aliases		core2_aliases
7441fa7f10bSFabien Thomas #define westmere_aliases_without_iaf	core2_aliases_without_iaf
74549fe48abSKonstantin Belousov #define westmere_ex_aliases		core2_aliases
74649fe48abSKonstantin Belousov #define westmere_ex_aliases_without_iaf	core2_aliases_without_iaf
7470cfab8ddSJoseph Koshy 
7480cfab8ddSJoseph Koshy #define	IAF_KW_OS		"os"
7490cfab8ddSJoseph Koshy #define	IAF_KW_USR		"usr"
7500cfab8ddSJoseph Koshy #define	IAF_KW_ANYTHREAD	"anythread"
7510cfab8ddSJoseph Koshy 
7520cfab8ddSJoseph Koshy /*
7530cfab8ddSJoseph Koshy  * Parse an event specifier for Intel fixed function counters.
7540cfab8ddSJoseph Koshy  */
7550cfab8ddSJoseph Koshy static int
7560cfab8ddSJoseph Koshy iaf_allocate_pmc(enum pmc_event pe, char *ctrspec,
7570cfab8ddSJoseph Koshy     struct pmc_op_pmcallocate *pmc_config)
7580cfab8ddSJoseph Koshy {
7590cfab8ddSJoseph Koshy 	char *p;
7600cfab8ddSJoseph Koshy 
7610cfab8ddSJoseph Koshy 	(void) pe;
7620cfab8ddSJoseph Koshy 
7630cfab8ddSJoseph Koshy 	pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE);
7640cfab8ddSJoseph Koshy 	pmc_config->pm_md.pm_iaf.pm_iaf_flags = 0;
7650cfab8ddSJoseph Koshy 
7660cfab8ddSJoseph Koshy 	while ((p = strsep(&ctrspec, ",")) != NULL) {
7670cfab8ddSJoseph Koshy 		if (KWMATCH(p, IAF_KW_OS))
7680cfab8ddSJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_SYSTEM;
7690cfab8ddSJoseph Koshy 		else if (KWMATCH(p, IAF_KW_USR))
7700cfab8ddSJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_USER;
7710cfab8ddSJoseph Koshy 		else if (KWMATCH(p, IAF_KW_ANYTHREAD))
7720cfab8ddSJoseph Koshy 			pmc_config->pm_md.pm_iaf.pm_iaf_flags |= IAF_ANY;
7730cfab8ddSJoseph Koshy 		else
7740cfab8ddSJoseph Koshy 			return (-1);
7750cfab8ddSJoseph Koshy 	}
7760cfab8ddSJoseph Koshy 
7770cfab8ddSJoseph Koshy 	return (0);
7780cfab8ddSJoseph Koshy }
7790cfab8ddSJoseph Koshy 
7800cfab8ddSJoseph Koshy /*
7810cfab8ddSJoseph Koshy  * Core/Core2 support.
7820cfab8ddSJoseph Koshy  */
7830cfab8ddSJoseph Koshy 
7840cfab8ddSJoseph Koshy #define	IAP_KW_AGENT		"agent"
7850cfab8ddSJoseph Koshy #define	IAP_KW_ANYTHREAD	"anythread"
7860cfab8ddSJoseph Koshy #define	IAP_KW_CACHESTATE	"cachestate"
7870cfab8ddSJoseph Koshy #define	IAP_KW_CMASK		"cmask"
7880cfab8ddSJoseph Koshy #define	IAP_KW_CORE		"core"
7890cfab8ddSJoseph Koshy #define	IAP_KW_EDGE		"edge"
7900cfab8ddSJoseph Koshy #define	IAP_KW_INV		"inv"
7910cfab8ddSJoseph Koshy #define	IAP_KW_OS		"os"
7920cfab8ddSJoseph Koshy #define	IAP_KW_PREFETCH		"prefetch"
7930cfab8ddSJoseph Koshy #define	IAP_KW_SNOOPRESPONSE	"snoopresponse"
7940cfab8ddSJoseph Koshy #define	IAP_KW_SNOOPTYPE	"snooptype"
7950cfab8ddSJoseph Koshy #define	IAP_KW_TRANSITION	"trans"
7960cfab8ddSJoseph Koshy #define	IAP_KW_USR		"usr"
7971fa7f10bSFabien Thomas #define	IAP_KW_RSP		"rsp"
7980cfab8ddSJoseph Koshy 
7990cfab8ddSJoseph Koshy static struct pmc_masks iap_core_mask[] = {
8000cfab8ddSJoseph Koshy 	PMCMASK(all,	(0x3 << 14)),
8010cfab8ddSJoseph Koshy 	PMCMASK(this,	(0x1 << 14)),
8020cfab8ddSJoseph Koshy 	NULLMASK
8030cfab8ddSJoseph Koshy };
8040cfab8ddSJoseph Koshy 
8050cfab8ddSJoseph Koshy static struct pmc_masks iap_agent_mask[] = {
8060cfab8ddSJoseph Koshy 	PMCMASK(this,	0),
8070cfab8ddSJoseph Koshy 	PMCMASK(any,	(0x1 << 13)),
8080cfab8ddSJoseph Koshy 	NULLMASK
8090cfab8ddSJoseph Koshy };
8100cfab8ddSJoseph Koshy 
8110cfab8ddSJoseph Koshy static struct pmc_masks iap_prefetch_mask[] = {
8120cfab8ddSJoseph Koshy 	PMCMASK(both,		(0x3 << 12)),
8130cfab8ddSJoseph Koshy 	PMCMASK(only,		(0x1 << 12)),
8140cfab8ddSJoseph Koshy 	PMCMASK(exclude,	0),
8150cfab8ddSJoseph Koshy 	NULLMASK
8160cfab8ddSJoseph Koshy };
8170cfab8ddSJoseph Koshy 
8180cfab8ddSJoseph Koshy static struct pmc_masks iap_cachestate_mask[] = {
8190cfab8ddSJoseph Koshy 	PMCMASK(i,		(1 <<  8)),
8200cfab8ddSJoseph Koshy 	PMCMASK(s,		(1 <<  9)),
8210cfab8ddSJoseph Koshy 	PMCMASK(e,		(1 << 10)),
8220cfab8ddSJoseph Koshy 	PMCMASK(m,		(1 << 11)),
8230cfab8ddSJoseph Koshy 	NULLMASK
8240cfab8ddSJoseph Koshy };
8250cfab8ddSJoseph Koshy 
8260cfab8ddSJoseph Koshy static struct pmc_masks iap_snoopresponse_mask[] = {
8270cfab8ddSJoseph Koshy 	PMCMASK(clean,		(1 << 8)),
8280cfab8ddSJoseph Koshy 	PMCMASK(hit,		(1 << 9)),
8290cfab8ddSJoseph Koshy 	PMCMASK(hitm,		(1 << 11)),
8300cfab8ddSJoseph Koshy 	NULLMASK
8310cfab8ddSJoseph Koshy };
8320cfab8ddSJoseph Koshy 
8330cfab8ddSJoseph Koshy static struct pmc_masks iap_snooptype_mask[] = {
8340cfab8ddSJoseph Koshy 	PMCMASK(cmp2s,		(1 << 8)),
8350cfab8ddSJoseph Koshy 	PMCMASK(cmp2i,		(1 << 9)),
8360cfab8ddSJoseph Koshy 	NULLMASK
8370cfab8ddSJoseph Koshy };
8380cfab8ddSJoseph Koshy 
8390cfab8ddSJoseph Koshy static struct pmc_masks iap_transition_mask[] = {
8400cfab8ddSJoseph Koshy 	PMCMASK(any,		0x00),
8410cfab8ddSJoseph Koshy 	PMCMASK(frequency,	0x10),
8420cfab8ddSJoseph Koshy 	NULLMASK
8430cfab8ddSJoseph Koshy };
8440cfab8ddSJoseph Koshy 
8451e862e5aSFabien Thomas static struct pmc_masks iap_rsp_mask_i7_wm[] = {
8461fa7f10bSFabien Thomas 	PMCMASK(DMND_DATA_RD,		(1 <<  0)),
8471fa7f10bSFabien Thomas 	PMCMASK(DMND_RFO,		(1 <<  1)),
8481fa7f10bSFabien Thomas 	PMCMASK(DMND_IFETCH,		(1 <<  2)),
8491fa7f10bSFabien Thomas 	PMCMASK(WB,			(1 <<  3)),
8501fa7f10bSFabien Thomas 	PMCMASK(PF_DATA_RD,		(1 <<  4)),
8511fa7f10bSFabien Thomas 	PMCMASK(PF_RFO,			(1 <<  5)),
8521fa7f10bSFabien Thomas 	PMCMASK(PF_IFETCH,		(1 <<  6)),
8531fa7f10bSFabien Thomas 	PMCMASK(OTHER,			(1 <<  7)),
8541fa7f10bSFabien Thomas 	PMCMASK(UNCORE_HIT,		(1 <<  8)),
8551fa7f10bSFabien Thomas 	PMCMASK(OTHER_CORE_HIT_SNP,	(1 <<  9)),
8561fa7f10bSFabien Thomas 	PMCMASK(OTHER_CORE_HITM,	(1 << 10)),
8571fa7f10bSFabien Thomas 	PMCMASK(REMOTE_CACHE_FWD,	(1 << 12)),
8581fa7f10bSFabien Thomas 	PMCMASK(REMOTE_DRAM,		(1 << 13)),
8591fa7f10bSFabien Thomas 	PMCMASK(LOCAL_DRAM,		(1 << 14)),
8601fa7f10bSFabien Thomas 	PMCMASK(NON_DRAM,		(1 << 15)),
8611fa7f10bSFabien Thomas 	NULLMASK
8621fa7f10bSFabien Thomas };
8631fa7f10bSFabien Thomas 
864fabe02f5SSean Bruno static struct pmc_masks iap_rsp_mask_sb_sbx_ib[] = {
8651e862e5aSFabien Thomas 	PMCMASK(REQ_DMND_DATA_RD,	(1ULL <<  0)),
8661e862e5aSFabien Thomas 	PMCMASK(REQ_DMND_RFO,		(1ULL <<  1)),
8671e862e5aSFabien Thomas 	PMCMASK(REQ_DMND_IFETCH,	(1ULL <<  2)),
8681e862e5aSFabien Thomas 	PMCMASK(REQ_WB,			(1ULL <<  3)),
8691e862e5aSFabien Thomas 	PMCMASK(REQ_PF_DATA_RD,		(1ULL <<  4)),
8701e862e5aSFabien Thomas 	PMCMASK(REQ_PF_RFO,		(1ULL <<  5)),
8711e862e5aSFabien Thomas 	PMCMASK(REQ_PF_IFETCH,		(1ULL <<  6)),
8721e862e5aSFabien Thomas 	PMCMASK(REQ_PF_LLC_DATA_RD,	(1ULL <<  7)),
8731e862e5aSFabien Thomas 	PMCMASK(REQ_PF_LLC_RFO,		(1ULL <<  8)),
8741e862e5aSFabien Thomas 	PMCMASK(REQ_PF_LLC_IFETCH,	(1ULL <<  9)),
8751e862e5aSFabien Thomas 	PMCMASK(REQ_BUS_LOCKS,		(1ULL << 10)),
8761e862e5aSFabien Thomas 	PMCMASK(REQ_STRM_ST,		(1ULL << 11)),
8771e862e5aSFabien Thomas 	PMCMASK(REQ_OTHER,		(1ULL << 15)),
8781e862e5aSFabien Thomas 	PMCMASK(RES_ANY,		(1ULL << 16)),
8791e862e5aSFabien Thomas 	PMCMASK(RES_SUPPLIER_SUPP,	(1ULL << 17)),
8801e862e5aSFabien Thomas 	PMCMASK(RES_SUPPLIER_LLC_HITM,	(1ULL << 18)),
8811e862e5aSFabien Thomas 	PMCMASK(RES_SUPPLIER_LLC_HITE,	(1ULL << 19)),
8821e862e5aSFabien Thomas 	PMCMASK(RES_SUPPLIER_LLC_HITS,	(1ULL << 20)),
8831e862e5aSFabien Thomas 	PMCMASK(RES_SUPPLIER_LLC_HITF,	(1ULL << 21)),
8841e862e5aSFabien Thomas 	PMCMASK(RES_SUPPLIER_LOCAL,	(1ULL << 22)),
885cdfd0cc8SSean Bruno 	PMCMASK(RES_SNOOP_SNP_NONE,	(1ULL << 31)),
8861e862e5aSFabien Thomas 	PMCMASK(RES_SNOOP_SNP_NO_NEEDED,(1ULL << 32)),
8871e862e5aSFabien Thomas 	PMCMASK(RES_SNOOP_SNP_MISS,	(1ULL << 33)),
8881e862e5aSFabien Thomas 	PMCMASK(RES_SNOOP_HIT_NO_FWD,	(1ULL << 34)),
8891e862e5aSFabien Thomas 	PMCMASK(RES_SNOOP_HIT_FWD,	(1ULL << 35)),
8901e862e5aSFabien Thomas 	PMCMASK(RES_SNOOP_HITM,		(1ULL << 36)),
8911e862e5aSFabien Thomas 	PMCMASK(RES_NON_DRAM,		(1ULL << 37)),
8921e862e5aSFabien Thomas 	NULLMASK
8931e862e5aSFabien Thomas };
8941e862e5aSFabien Thomas 
895f19bae41SRandall Stewart /* Broadwell is defined to use the same mask as Haswell */
896cc0c1555SSean Bruno static struct pmc_masks iap_rsp_mask_haswell[] = {
897cc0c1555SSean Bruno 	PMCMASK(REQ_DMND_DATA_RD,	(1ULL <<  0)),
898cc0c1555SSean Bruno 	PMCMASK(REQ_DMND_RFO,		(1ULL <<  1)),
899cc0c1555SSean Bruno 	PMCMASK(REQ_DMND_IFETCH,	(1ULL <<  2)),
900cc0c1555SSean Bruno 	PMCMASK(REQ_PF_DATA_RD,		(1ULL <<  4)),
901cc0c1555SSean Bruno 	PMCMASK(REQ_PF_RFO,		(1ULL <<  5)),
902cc0c1555SSean Bruno 	PMCMASK(REQ_PF_IFETCH,		(1ULL <<  6)),
903cc0c1555SSean Bruno 	PMCMASK(REQ_OTHER,		(1ULL << 15)),
904cc0c1555SSean Bruno 	PMCMASK(RES_ANY,		(1ULL << 16)),
905cc0c1555SSean Bruno 	PMCMASK(RES_SUPPLIER_SUPP,	(1ULL << 17)),
906cc0c1555SSean Bruno 	PMCMASK(RES_SUPPLIER_LLC_HITM,	(1ULL << 18)),
907cc0c1555SSean Bruno 	PMCMASK(RES_SUPPLIER_LLC_HITE,	(1ULL << 19)),
908cc0c1555SSean Bruno 	PMCMASK(RES_SUPPLIER_LLC_HITS,	(1ULL << 20)),
909cc0c1555SSean Bruno 	PMCMASK(RES_SUPPLIER_LLC_HITF,	(1ULL << 21)),
910cc0c1555SSean Bruno 	PMCMASK(RES_SUPPLIER_LOCAL,	(1ULL << 22)),
911f19bae41SRandall Stewart 	/*
912f19bae41SRandall Stewart 	 * For processor type 06_45H 22 is L4_HIT_LOCAL_L4
913f19bae41SRandall Stewart 	 * and 23, 24 and 25 are also defined.
914f19bae41SRandall Stewart 	 */
915cc0c1555SSean Bruno 	PMCMASK(RES_SNOOP_SNP_NONE,	(1ULL << 31)),
916cc0c1555SSean Bruno 	PMCMASK(RES_SNOOP_SNP_NO_NEEDED,(1ULL << 32)),
917cc0c1555SSean Bruno 	PMCMASK(RES_SNOOP_SNP_MISS,	(1ULL << 33)),
918cc0c1555SSean Bruno 	PMCMASK(RES_SNOOP_HIT_NO_FWD,	(1ULL << 34)),
919cc0c1555SSean Bruno 	PMCMASK(RES_SNOOP_HIT_FWD,	(1ULL << 35)),
920cc0c1555SSean Bruno 	PMCMASK(RES_SNOOP_HITM,		(1ULL << 36)),
921cc0c1555SSean Bruno 	PMCMASK(RES_NON_DRAM,		(1ULL << 37)),
922cc0c1555SSean Bruno 	NULLMASK
923cc0c1555SSean Bruno };
924cc0c1555SSean Bruno 
925f19bae41SRandall Stewart static struct pmc_masks iap_rsp_mask_skylake[] = {
926f19bae41SRandall Stewart 	PMCMASK(REQ_DMND_DATA_RD,	(1ULL <<  0)),
927f19bae41SRandall Stewart 	PMCMASK(REQ_DMND_RFO,		(1ULL <<  1)),
928f19bae41SRandall Stewart 	PMCMASK(REQ_DMND_IFETCH,	(1ULL <<  2)),
929f19bae41SRandall Stewart 	PMCMASK(REQ_PF_DATA_RD,		(1ULL <<  7)),
930f19bae41SRandall Stewart 	PMCMASK(REQ_PF_RFO,		(1ULL <<  8)),
931f19bae41SRandall Stewart 	PMCMASK(REQ_STRM_ST,		(1ULL << 11)),
932f19bae41SRandall Stewart 	PMCMASK(REQ_OTHER,		(1ULL << 15)),
933f19bae41SRandall Stewart 	PMCMASK(RES_ANY,		(1ULL << 16)),
934f19bae41SRandall Stewart 	PMCMASK(RES_SUPPLIER_SUPP,	(1ULL << 17)),
935f19bae41SRandall Stewart 	PMCMASK(RES_SUPPLIER_LLC_HITM,	(1ULL << 18)),
936f19bae41SRandall Stewart 	PMCMASK(RES_SUPPLIER_LLC_HITE,	(1ULL << 19)),
937f19bae41SRandall Stewart 	PMCMASK(RES_SUPPLIER_LLC_HITS,	(1ULL << 20)),
938f19bae41SRandall Stewart 	PMCMASK(RES_SUPPLIER_L4_HIT,	(1ULL << 22)),
939f19bae41SRandall Stewart 	PMCMASK(RES_SUPPLIER_DRAM,	(1ULL << 26)),
940f19bae41SRandall Stewart 	PMCMASK(RES_SUPPLIER_SPL_HIT,	(1ULL << 30)),
941f19bae41SRandall Stewart 	PMCMASK(RES_SNOOP_SNP_NONE,	(1ULL << 31)),
942f19bae41SRandall Stewart 	PMCMASK(RES_SNOOP_SNP_NO_NEEDED,(1ULL << 32)),
943f19bae41SRandall Stewart 	PMCMASK(RES_SNOOP_SNP_MISS,	(1ULL << 33)),
944f19bae41SRandall Stewart 	PMCMASK(RES_SNOOP_HIT_NO_FWD,	(1ULL << 34)),
945f19bae41SRandall Stewart 	PMCMASK(RES_SNOOP_HIT_FWD,	(1ULL << 35)),
946f19bae41SRandall Stewart 	PMCMASK(RES_SNOOP_HITM,		(1ULL << 36)),
947f19bae41SRandall Stewart 	PMCMASK(RES_NON_DRAM,		(1ULL << 37)),
948f19bae41SRandall Stewart 	NULLMASK
949f19bae41SRandall Stewart };
950f19bae41SRandall Stewart 
951f19bae41SRandall Stewart 
9520cfab8ddSJoseph Koshy static int
9530cfab8ddSJoseph Koshy iap_allocate_pmc(enum pmc_event pe, char *ctrspec,
9540cfab8ddSJoseph Koshy     struct pmc_op_pmcallocate *pmc_config)
9550cfab8ddSJoseph Koshy {
9560cfab8ddSJoseph Koshy 	char *e, *p, *q;
9571e862e5aSFabien Thomas 	uint64_t cachestate, evmask, rsp;
9580cfab8ddSJoseph Koshy 	int count, n;
9590cfab8ddSJoseph Koshy 
9600cfab8ddSJoseph Koshy 	pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE |
9610cfab8ddSJoseph Koshy 	    PMC_CAP_QUALIFIER);
9620cfab8ddSJoseph Koshy 	pmc_config->pm_md.pm_iap.pm_iap_config = 0;
9630cfab8ddSJoseph Koshy 
9641fa7f10bSFabien Thomas 	cachestate = evmask = rsp = 0;
9650cfab8ddSJoseph Koshy 
9660cfab8ddSJoseph Koshy 	/* Parse additional modifiers if present */
9670cfab8ddSJoseph Koshy 	while ((p = strsep(&ctrspec, ",")) != NULL) {
9680cfab8ddSJoseph Koshy 
9690cfab8ddSJoseph Koshy 		n = 0;
9700cfab8ddSJoseph Koshy 		if (KWPREFIXMATCH(p, IAP_KW_CMASK "=")) {
9710cfab8ddSJoseph Koshy 			q = strchr(p, '=');
9720cfab8ddSJoseph Koshy 			if (*++q == '\0') /* skip '=' */
9730cfab8ddSJoseph Koshy 				return (-1);
9740cfab8ddSJoseph Koshy 			count = strtol(q, &e, 0);
9750cfab8ddSJoseph Koshy 			if (e == q || *e != '\0')
9760cfab8ddSJoseph Koshy 				return (-1);
9770cfab8ddSJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_THRESHOLD;
9780cfab8ddSJoseph Koshy 			pmc_config->pm_md.pm_iap.pm_iap_config |=
9790cfab8ddSJoseph Koshy 			    IAP_CMASK(count);
9800cfab8ddSJoseph Koshy 		} else if (KWMATCH(p, IAP_KW_EDGE)) {
9810cfab8ddSJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_EDGE;
9820cfab8ddSJoseph Koshy 		} else if (KWMATCH(p, IAP_KW_INV)) {
9830cfab8ddSJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_INVERT;
9840cfab8ddSJoseph Koshy 		} else if (KWMATCH(p, IAP_KW_OS)) {
9850cfab8ddSJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_SYSTEM;
9860cfab8ddSJoseph Koshy 		} else if (KWMATCH(p, IAP_KW_USR)) {
9870cfab8ddSJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_USER;
9880cfab8ddSJoseph Koshy 		} else if (KWMATCH(p, IAP_KW_ANYTHREAD)) {
9890cfab8ddSJoseph Koshy 			pmc_config->pm_md.pm_iap.pm_iap_config |= IAP_ANY;
990b47ea38eSJoseph Koshy 		} else if (KWPREFIXMATCH(p, IAP_KW_CORE "=")) {
9910cfab8ddSJoseph Koshy 			n = pmc_parse_mask(iap_core_mask, p, &evmask);
9920cfab8ddSJoseph Koshy 			if (n != 1)
9930cfab8ddSJoseph Koshy 				return (-1);
994b47ea38eSJoseph Koshy 		} else if (KWPREFIXMATCH(p, IAP_KW_AGENT "=")) {
9950cfab8ddSJoseph Koshy 			n = pmc_parse_mask(iap_agent_mask, p, &evmask);
9960cfab8ddSJoseph Koshy 			if (n != 1)
9970cfab8ddSJoseph Koshy 				return (-1);
998b47ea38eSJoseph Koshy 		} else if (KWPREFIXMATCH(p, IAP_KW_PREFETCH "=")) {
9990cfab8ddSJoseph Koshy 			n = pmc_parse_mask(iap_prefetch_mask, p, &evmask);
10000cfab8ddSJoseph Koshy 			if (n != 1)
10010cfab8ddSJoseph Koshy 				return (-1);
1002b47ea38eSJoseph Koshy 		} else if (KWPREFIXMATCH(p, IAP_KW_CACHESTATE "=")) {
10030cfab8ddSJoseph Koshy 			n = pmc_parse_mask(iap_cachestate_mask, p, &cachestate);
10040cfab8ddSJoseph Koshy 		} else if (cpu_info.pm_cputype == PMC_CPU_INTEL_CORE &&
1005b47ea38eSJoseph Koshy 		    KWPREFIXMATCH(p, IAP_KW_TRANSITION "=")) {
10060cfab8ddSJoseph Koshy 			n = pmc_parse_mask(iap_transition_mask, p, &evmask);
10070cfab8ddSJoseph Koshy 			if (n != 1)
10080cfab8ddSJoseph Koshy 				return (-1);
10090cfab8ddSJoseph Koshy 		} else if (cpu_info.pm_cputype == PMC_CPU_INTEL_ATOM ||
1010e8f021a3SHiren Panchasara 		    cpu_info.pm_cputype == PMC_CPU_INTEL_ATOM_SILVERMONT ||
1011b4d091f3SJoseph Koshy 		    cpu_info.pm_cputype == PMC_CPU_INTEL_CORE2 ||
10121fa7f10bSFabien Thomas 		    cpu_info.pm_cputype == PMC_CPU_INTEL_CORE2EXTREME) {
1013b47ea38eSJoseph Koshy 			if (KWPREFIXMATCH(p, IAP_KW_SNOOPRESPONSE "=")) {
10140cfab8ddSJoseph Koshy 				n = pmc_parse_mask(iap_snoopresponse_mask, p,
10150cfab8ddSJoseph Koshy 				    &evmask);
1016b47ea38eSJoseph Koshy 			} else if (KWPREFIXMATCH(p, IAP_KW_SNOOPTYPE "=")) {
10170cfab8ddSJoseph Koshy 				n = pmc_parse_mask(iap_snooptype_mask, p,
10180cfab8ddSJoseph Koshy 				    &evmask);
10190cfab8ddSJoseph Koshy 			} else
10200cfab8ddSJoseph Koshy 				return (-1);
10211fa7f10bSFabien Thomas 		} else if (cpu_info.pm_cputype == PMC_CPU_INTEL_COREI7 ||
102249fe48abSKonstantin Belousov 		    cpu_info.pm_cputype == PMC_CPU_INTEL_WESTMERE ||
102349fe48abSKonstantin Belousov 		    cpu_info.pm_cputype == PMC_CPU_INTEL_NEHALEM_EX ||
102449fe48abSKonstantin Belousov 		    cpu_info.pm_cputype == PMC_CPU_INTEL_WESTMERE_EX) {
10251fa7f10bSFabien Thomas 			if (KWPREFIXMATCH(p, IAP_KW_RSP "=")) {
10261e862e5aSFabien Thomas 				n = pmc_parse_mask(iap_rsp_mask_i7_wm, p, &rsp);
10271e862e5aSFabien Thomas 			} else
10281e862e5aSFabien Thomas 				return (-1);
10291e862e5aSFabien Thomas 		} else if (cpu_info.pm_cputype == PMC_CPU_INTEL_SANDYBRIDGE ||
1030fabe02f5SSean Bruno 		    cpu_info.pm_cputype == PMC_CPU_INTEL_SANDYBRIDGE_XEON ||
10313f929d8cSSean Bruno 		    cpu_info.pm_cputype == PMC_CPU_INTEL_IVYBRIDGE ||
10323f929d8cSSean Bruno 		    cpu_info.pm_cputype == PMC_CPU_INTEL_IVYBRIDGE_XEON ) {
10331e862e5aSFabien Thomas 			if (KWPREFIXMATCH(p, IAP_KW_RSP "=")) {
1034fabe02f5SSean Bruno 				n = pmc_parse_mask(iap_rsp_mask_sb_sbx_ib, p, &rsp);
10351fa7f10bSFabien Thomas 			} else
10361fa7f10bSFabien Thomas 				return (-1);
1037d95b3509SRandall Stewart 		} else if (cpu_info.pm_cputype == PMC_CPU_INTEL_HASWELL ||
1038d95b3509SRandall Stewart 		    cpu_info.pm_cputype == PMC_CPU_INTEL_HASWELL_XEON) {
1039cc0c1555SSean Bruno 			if (KWPREFIXMATCH(p, IAP_KW_RSP "=")) {
1040cc0c1555SSean Bruno 				n = pmc_parse_mask(iap_rsp_mask_haswell, p, &rsp);
1041cc0c1555SSean Bruno 			} else
1042cc0c1555SSean Bruno 				return (-1);
1043f19bae41SRandall Stewart 		} else if (cpu_info.pm_cputype == PMC_CPU_INTEL_BROADWELL ||
1044f19bae41SRandall Stewart 		    cpu_info.pm_cputype == PMC_CPU_INTEL_BROADWELL_XEON) {
1045f19bae41SRandall Stewart 			/* Broadwell is defined to use same mask as haswell */
1046f19bae41SRandall Stewart 			if (KWPREFIXMATCH(p, IAP_KW_RSP "=")) {
1047f19bae41SRandall Stewart 				n = pmc_parse_mask(iap_rsp_mask_haswell, p, &rsp);
1048f19bae41SRandall Stewart 			} else
1049f19bae41SRandall Stewart 				return (-1);
1050f19bae41SRandall Stewart 
1051b99b705dSKonstantin Belousov 		} else if (cpu_info.pm_cputype == PMC_CPU_INTEL_SKYLAKE ||
1052b99b705dSKonstantin Belousov 		    cpu_info.pm_cputype == PMC_CPU_INTEL_SKYLAKE_XEON) {
1053f19bae41SRandall Stewart 			if (KWPREFIXMATCH(p, IAP_KW_RSP "=")) {
1054f19bae41SRandall Stewart 				n = pmc_parse_mask(iap_rsp_mask_skylake, p, &rsp);
1055f19bae41SRandall Stewart 			} else
1056f19bae41SRandall Stewart 				return (-1);
1057f19bae41SRandall Stewart 
10580cfab8ddSJoseph Koshy 		} else
10590cfab8ddSJoseph Koshy 			return (-1);
10600cfab8ddSJoseph Koshy 
10610cfab8ddSJoseph Koshy 		if (n < 0)	/* Parsing failed. */
10620cfab8ddSJoseph Koshy 			return (-1);
10630cfab8ddSJoseph Koshy 	}
10640cfab8ddSJoseph Koshy 
10650cfab8ddSJoseph Koshy 	pmc_config->pm_md.pm_iap.pm_iap_config |= evmask;
10660cfab8ddSJoseph Koshy 
10670cfab8ddSJoseph Koshy 	/*
10680cfab8ddSJoseph Koshy 	 * If the event requires a 'cachestate' qualifier but was not
10690cfab8ddSJoseph Koshy 	 * specified by the user, use a sensible default.
10700cfab8ddSJoseph Koshy 	 */
10710cfab8ddSJoseph Koshy 	switch (pe) {
10720cfab8ddSJoseph Koshy 	case PMC_EV_IAP_EVENT_28H: /* Core, Core2, Atom */
10730cfab8ddSJoseph Koshy 	case PMC_EV_IAP_EVENT_29H: /* Core, Core2, Atom */
10740cfab8ddSJoseph Koshy 	case PMC_EV_IAP_EVENT_2AH: /* Core, Core2, Atom */
10750cfab8ddSJoseph Koshy 	case PMC_EV_IAP_EVENT_2BH: /* Atom, Core2 */
10760cfab8ddSJoseph Koshy 	case PMC_EV_IAP_EVENT_2EH: /* Core, Core2, Atom */
10770cfab8ddSJoseph Koshy 	case PMC_EV_IAP_EVENT_30H: /* Core, Core2, Atom */
10780cfab8ddSJoseph Koshy 	case PMC_EV_IAP_EVENT_32H: /* Core */
10790cfab8ddSJoseph Koshy 	case PMC_EV_IAP_EVENT_40H: /* Core */
10800cfab8ddSJoseph Koshy 	case PMC_EV_IAP_EVENT_41H: /* Core */
10810cfab8ddSJoseph Koshy 	case PMC_EV_IAP_EVENT_42H: /* Core, Core2, Atom */
10820cfab8ddSJoseph Koshy 		if (cachestate == 0)
10830cfab8ddSJoseph Koshy 			cachestate = (0xF << 8);
1084aa1b887bSRyan Stone 		break;
1085aa1b887bSRyan Stone 	case PMC_EV_IAP_EVENT_77H: /* Atom */
1086aa1b887bSRyan Stone 		/* IAP_EVENT_77H only accepts a cachestate qualifier on the
1087aa1b887bSRyan Stone 		 * Atom processor
1088aa1b887bSRyan Stone 		 */
1089aa1b887bSRyan Stone 		if(cpu_info.pm_cputype == PMC_CPU_INTEL_ATOM && cachestate == 0)
1090aa1b887bSRyan Stone 			cachestate = (0xF << 8);
1091aa1b887bSRyan Stone 	    break;
10920cfab8ddSJoseph Koshy 	default:
10930cfab8ddSJoseph Koshy 		break;
10940cfab8ddSJoseph Koshy 	}
10950cfab8ddSJoseph Koshy 
10960cfab8ddSJoseph Koshy 	pmc_config->pm_md.pm_iap.pm_iap_config |= cachestate;
10971fa7f10bSFabien Thomas 	pmc_config->pm_md.pm_iap.pm_iap_rsp = rsp;
10981fa7f10bSFabien Thomas 
10991fa7f10bSFabien Thomas 	return (0);
11001fa7f10bSFabien Thomas }
11011fa7f10bSFabien Thomas 
11021fa7f10bSFabien Thomas /*
11031fa7f10bSFabien Thomas  * Intel Uncore.
11041fa7f10bSFabien Thomas  */
11051fa7f10bSFabien Thomas 
11061fa7f10bSFabien Thomas static int
11071fa7f10bSFabien Thomas ucf_allocate_pmc(enum pmc_event pe, char *ctrspec,
11081fa7f10bSFabien Thomas     struct pmc_op_pmcallocate *pmc_config)
11091fa7f10bSFabien Thomas {
11101fa7f10bSFabien Thomas 	(void) pe;
11111fa7f10bSFabien Thomas 	(void) ctrspec;
11121fa7f10bSFabien Thomas 
11131fa7f10bSFabien Thomas 	pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE);
11141fa7f10bSFabien Thomas 	pmc_config->pm_md.pm_ucf.pm_ucf_flags = 0;
11151fa7f10bSFabien Thomas 
11161fa7f10bSFabien Thomas 	return (0);
11171fa7f10bSFabien Thomas }
11181fa7f10bSFabien Thomas 
11191fa7f10bSFabien Thomas #define	UCP_KW_CMASK		"cmask"
11201fa7f10bSFabien Thomas #define	UCP_KW_EDGE		"edge"
11211fa7f10bSFabien Thomas #define	UCP_KW_INV		"inv"
11221fa7f10bSFabien Thomas 
11231fa7f10bSFabien Thomas static int
11241fa7f10bSFabien Thomas ucp_allocate_pmc(enum pmc_event pe, char *ctrspec,
11251fa7f10bSFabien Thomas     struct pmc_op_pmcallocate *pmc_config)
11261fa7f10bSFabien Thomas {
11271fa7f10bSFabien Thomas 	char *e, *p, *q;
11281fa7f10bSFabien Thomas 	int count, n;
11291fa7f10bSFabien Thomas 
11301fa7f10bSFabien Thomas 	(void) pe;
11311fa7f10bSFabien Thomas 
11321fa7f10bSFabien Thomas 	pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE |
11331fa7f10bSFabien Thomas 	    PMC_CAP_QUALIFIER);
11341fa7f10bSFabien Thomas 	pmc_config->pm_md.pm_ucp.pm_ucp_config = 0;
11351fa7f10bSFabien Thomas 
11361fa7f10bSFabien Thomas 	/* Parse additional modifiers if present */
11371fa7f10bSFabien Thomas 	while ((p = strsep(&ctrspec, ",")) != NULL) {
11381fa7f10bSFabien Thomas 
11391fa7f10bSFabien Thomas 		n = 0;
11401fa7f10bSFabien Thomas 		if (KWPREFIXMATCH(p, UCP_KW_CMASK "=")) {
11411fa7f10bSFabien Thomas 			q = strchr(p, '=');
11421fa7f10bSFabien Thomas 			if (*++q == '\0') /* skip '=' */
11431fa7f10bSFabien Thomas 				return (-1);
11441fa7f10bSFabien Thomas 			count = strtol(q, &e, 0);
11451fa7f10bSFabien Thomas 			if (e == q || *e != '\0')
11461fa7f10bSFabien Thomas 				return (-1);
11471fa7f10bSFabien Thomas 			pmc_config->pm_caps |= PMC_CAP_THRESHOLD;
11481fa7f10bSFabien Thomas 			pmc_config->pm_md.pm_ucp.pm_ucp_config |=
11491fa7f10bSFabien Thomas 			    UCP_CMASK(count);
11501fa7f10bSFabien Thomas 		} else if (KWMATCH(p, UCP_KW_EDGE)) {
11511fa7f10bSFabien Thomas 			pmc_config->pm_caps |= PMC_CAP_EDGE;
11521fa7f10bSFabien Thomas 		} else if (KWMATCH(p, UCP_KW_INV)) {
11531fa7f10bSFabien Thomas 			pmc_config->pm_caps |= PMC_CAP_INVERT;
11541fa7f10bSFabien Thomas 		} else
11551fa7f10bSFabien Thomas 			return (-1);
11561fa7f10bSFabien Thomas 
11571fa7f10bSFabien Thomas 		if (n < 0)	/* Parsing failed. */
11581fa7f10bSFabien Thomas 			return (-1);
11591fa7f10bSFabien Thomas 	}
11600cfab8ddSJoseph Koshy 
11610cfab8ddSJoseph Koshy 	return (0);
11620cfab8ddSJoseph Koshy }
11630cfab8ddSJoseph Koshy 
11640cfab8ddSJoseph Koshy /*
1165f263522aSJoseph Koshy  * AMD K8 PMCs.
1166f263522aSJoseph Koshy  *
1167f263522aSJoseph Koshy  * These are very similar to AMD K7 PMCs, but support more kinds of
1168f263522aSJoseph Koshy  * events.
1169f263522aSJoseph Koshy  */
1170f263522aSJoseph Koshy 
1171f263522aSJoseph Koshy static struct pmc_event_alias k8_aliases[] = {
1172f263522aSJoseph Koshy 	EV_ALIAS("branches",		"k8-fr-retired-taken-branches"),
1173f263522aSJoseph Koshy 	EV_ALIAS("branch-mispredicts",
1174f263522aSJoseph Koshy 	    "k8-fr-retired-taken-branches-mispredicted"),
1175f263522aSJoseph Koshy 	EV_ALIAS("cycles",		"tsc"),
1176f263522aSJoseph Koshy 	EV_ALIAS("dc-misses",		"k8-dc-miss"),
1177f263522aSJoseph Koshy 	EV_ALIAS("ic-misses",		"k8-ic-miss"),
1178f263522aSJoseph Koshy 	EV_ALIAS("instructions",	"k8-fr-retired-x86-instructions"),
1179f263522aSJoseph Koshy 	EV_ALIAS("interrupts",		"k8-fr-taken-hardware-interrupts"),
1180177a2f22SJoseph Koshy 	EV_ALIAS("unhalted-cycles",	"k8-bu-cpu-clk-unhalted"),
1181f263522aSJoseph Koshy 	EV_ALIAS(NULL, NULL)
1182f263522aSJoseph Koshy };
1183f263522aSJoseph Koshy 
1184f263522aSJoseph Koshy #define	__K8MASK(N,V) PMCMASK(N,(1 << (V)))
1185f263522aSJoseph Koshy 
1186f263522aSJoseph Koshy /*
1187f263522aSJoseph Koshy  * Parsing tables
1188f263522aSJoseph Koshy  */
1189f263522aSJoseph Koshy 
1190f263522aSJoseph Koshy /* fp dispatched fpu ops */
1191f263522aSJoseph Koshy static const struct pmc_masks k8_mask_fdfo[] = {
1192f263522aSJoseph Koshy 	__K8MASK(add-pipe-excluding-junk-ops,	0),
1193f263522aSJoseph Koshy 	__K8MASK(multiply-pipe-excluding-junk-ops,	1),
1194f263522aSJoseph Koshy 	__K8MASK(store-pipe-excluding-junk-ops,	2),
1195f263522aSJoseph Koshy 	__K8MASK(add-pipe-junk-ops,		3),
1196f263522aSJoseph Koshy 	__K8MASK(multiply-pipe-junk-ops,	4),
1197f263522aSJoseph Koshy 	__K8MASK(store-pipe-junk-ops,		5),
1198f263522aSJoseph Koshy 	NULLMASK
1199f263522aSJoseph Koshy };
1200f263522aSJoseph Koshy 
1201f263522aSJoseph Koshy /* ls segment register loads */
1202f263522aSJoseph Koshy static const struct pmc_masks k8_mask_lsrl[] = {
1203f263522aSJoseph Koshy 	__K8MASK(es,	0),
1204f263522aSJoseph Koshy 	__K8MASK(cs,	1),
1205f263522aSJoseph Koshy 	__K8MASK(ss,	2),
1206f263522aSJoseph Koshy 	__K8MASK(ds,	3),
1207f263522aSJoseph Koshy 	__K8MASK(fs,	4),
1208f263522aSJoseph Koshy 	__K8MASK(gs,	5),
1209f263522aSJoseph Koshy 	__K8MASK(hs,	6),
1210f263522aSJoseph Koshy 	NULLMASK
1211f263522aSJoseph Koshy };
1212f263522aSJoseph Koshy 
1213f263522aSJoseph Koshy /* ls locked operation */
1214f263522aSJoseph Koshy static const struct pmc_masks k8_mask_llo[] = {
1215f263522aSJoseph Koshy 	__K8MASK(locked-instructions,	0),
1216f263522aSJoseph Koshy 	__K8MASK(cycles-in-request,	1),
1217f263522aSJoseph Koshy 	__K8MASK(cycles-to-complete,	2),
1218f263522aSJoseph Koshy 	NULLMASK
1219f263522aSJoseph Koshy };
1220f263522aSJoseph Koshy 
1221f263522aSJoseph Koshy /* dc refill from {l2,system} and dc copyback */
1222f263522aSJoseph Koshy static const struct pmc_masks k8_mask_dc[] = {
1223f263522aSJoseph Koshy 	__K8MASK(invalid,	0),
1224f263522aSJoseph Koshy 	__K8MASK(shared,	1),
1225f263522aSJoseph Koshy 	__K8MASK(exclusive,	2),
1226f263522aSJoseph Koshy 	__K8MASK(owner,		3),
1227f263522aSJoseph Koshy 	__K8MASK(modified,	4),
1228f263522aSJoseph Koshy 	NULLMASK
1229f263522aSJoseph Koshy };
1230f263522aSJoseph Koshy 
1231f263522aSJoseph Koshy /* dc one bit ecc error */
1232f263522aSJoseph Koshy static const struct pmc_masks k8_mask_dobee[] = {
1233f263522aSJoseph Koshy 	__K8MASK(scrubber,	0),
1234f263522aSJoseph Koshy 	__K8MASK(piggyback,	1),
1235f263522aSJoseph Koshy 	NULLMASK
1236f263522aSJoseph Koshy };
1237f263522aSJoseph Koshy 
1238f263522aSJoseph Koshy /* dc dispatched prefetch instructions */
1239f263522aSJoseph Koshy static const struct pmc_masks k8_mask_ddpi[] = {
1240f263522aSJoseph Koshy 	__K8MASK(load,	0),
1241f263522aSJoseph Koshy 	__K8MASK(store,	1),
1242f263522aSJoseph Koshy 	__K8MASK(nta,	2),
1243f263522aSJoseph Koshy 	NULLMASK
1244f263522aSJoseph Koshy };
1245f263522aSJoseph Koshy 
1246f263522aSJoseph Koshy /* dc dcache accesses by locks */
1247f263522aSJoseph Koshy static const struct pmc_masks k8_mask_dabl[] = {
1248f263522aSJoseph Koshy 	__K8MASK(accesses,	0),
1249f263522aSJoseph Koshy 	__K8MASK(misses,	1),
1250f263522aSJoseph Koshy 	NULLMASK
1251f263522aSJoseph Koshy };
1252f263522aSJoseph Koshy 
1253f263522aSJoseph Koshy /* bu internal l2 request */
1254f263522aSJoseph Koshy static const struct pmc_masks k8_mask_bilr[] = {
1255f263522aSJoseph Koshy 	__K8MASK(ic-fill,	0),
1256f263522aSJoseph Koshy 	__K8MASK(dc-fill,	1),
1257f263522aSJoseph Koshy 	__K8MASK(tlb-reload,	2),
1258f263522aSJoseph Koshy 	__K8MASK(tag-snoop,	3),
1259f263522aSJoseph Koshy 	__K8MASK(cancelled,	4),
1260f263522aSJoseph Koshy 	NULLMASK
1261f263522aSJoseph Koshy };
1262f263522aSJoseph Koshy 
1263f263522aSJoseph Koshy /* bu fill request l2 miss */
1264f263522aSJoseph Koshy static const struct pmc_masks k8_mask_bfrlm[] = {
1265f263522aSJoseph Koshy 	__K8MASK(ic-fill,	0),
1266f263522aSJoseph Koshy 	__K8MASK(dc-fill,	1),
1267f263522aSJoseph Koshy 	__K8MASK(tlb-reload,	2),
1268f263522aSJoseph Koshy 	NULLMASK
1269f263522aSJoseph Koshy };
1270f263522aSJoseph Koshy 
1271f263522aSJoseph Koshy /* bu fill into l2 */
1272f263522aSJoseph Koshy static const struct pmc_masks k8_mask_bfil[] = {
1273f263522aSJoseph Koshy 	__K8MASK(dirty-l2-victim,	0),
1274f263522aSJoseph Koshy 	__K8MASK(victim-from-l2,	1),
1275f263522aSJoseph Koshy 	NULLMASK
1276f263522aSJoseph Koshy };
1277f263522aSJoseph Koshy 
1278f263522aSJoseph Koshy /* fr retired fpu instructions */
1279f263522aSJoseph Koshy static const struct pmc_masks k8_mask_frfi[] = {
1280f263522aSJoseph Koshy 	__K8MASK(x87,			0),
1281f263522aSJoseph Koshy 	__K8MASK(mmx-3dnow,		1),
1282f263522aSJoseph Koshy 	__K8MASK(packed-sse-sse2,	2),
1283f263522aSJoseph Koshy 	__K8MASK(scalar-sse-sse2,	3),
1284f263522aSJoseph Koshy 	NULLMASK
1285f263522aSJoseph Koshy };
1286f263522aSJoseph Koshy 
1287f263522aSJoseph Koshy /* fr retired fastpath double op instructions */
1288f263522aSJoseph Koshy static const struct pmc_masks k8_mask_frfdoi[] = {
1289f263522aSJoseph Koshy 	__K8MASK(low-op-pos-0,		0),
1290f263522aSJoseph Koshy 	__K8MASK(low-op-pos-1,		1),
1291f263522aSJoseph Koshy 	__K8MASK(low-op-pos-2,		2),
1292f263522aSJoseph Koshy 	NULLMASK
1293f263522aSJoseph Koshy };
1294f263522aSJoseph Koshy 
1295f263522aSJoseph Koshy /* fr fpu exceptions */
1296f263522aSJoseph Koshy static const struct pmc_masks k8_mask_ffe[] = {
1297f263522aSJoseph Koshy 	__K8MASK(x87-reclass-microfaults,	0),
1298f263522aSJoseph Koshy 	__K8MASK(sse-retype-microfaults,	1),
1299f263522aSJoseph Koshy 	__K8MASK(sse-reclass-microfaults,	2),
1300f263522aSJoseph Koshy 	__K8MASK(sse-and-x87-microtraps,	3),
1301f263522aSJoseph Koshy 	NULLMASK
1302f263522aSJoseph Koshy };
1303f263522aSJoseph Koshy 
1304f263522aSJoseph Koshy /* nb memory controller page access event */
1305f263522aSJoseph Koshy static const struct pmc_masks k8_mask_nmcpae[] = {
1306f263522aSJoseph Koshy 	__K8MASK(page-hit,	0),
1307f263522aSJoseph Koshy 	__K8MASK(page-miss,	1),
1308f263522aSJoseph Koshy 	__K8MASK(page-conflict,	2),
1309f263522aSJoseph Koshy 	NULLMASK
1310f263522aSJoseph Koshy };
1311f263522aSJoseph Koshy 
1312f263522aSJoseph Koshy /* nb memory controller turnaround */
1313f263522aSJoseph Koshy static const struct pmc_masks k8_mask_nmct[] = {
1314f263522aSJoseph Koshy 	__K8MASK(dimm-turnaround,		0),
1315f263522aSJoseph Koshy 	__K8MASK(read-to-write-turnaround,	1),
1316f263522aSJoseph Koshy 	__K8MASK(write-to-read-turnaround,	2),
1317f263522aSJoseph Koshy 	NULLMASK
1318f263522aSJoseph Koshy };
1319f263522aSJoseph Koshy 
1320f263522aSJoseph Koshy /* nb memory controller bypass saturation */
1321f263522aSJoseph Koshy static const struct pmc_masks k8_mask_nmcbs[] = {
1322f263522aSJoseph Koshy 	__K8MASK(memory-controller-hi-pri-bypass,	0),
1323f263522aSJoseph Koshy 	__K8MASK(memory-controller-lo-pri-bypass,	1),
1324f263522aSJoseph Koshy 	__K8MASK(dram-controller-interface-bypass,	2),
1325f263522aSJoseph Koshy 	__K8MASK(dram-controller-queue-bypass,		3),
1326f263522aSJoseph Koshy 	NULLMASK
1327f263522aSJoseph Koshy };
1328f263522aSJoseph Koshy 
1329f263522aSJoseph Koshy /* nb sized commands */
1330f263522aSJoseph Koshy static const struct pmc_masks k8_mask_nsc[] = {
1331f263522aSJoseph Koshy 	__K8MASK(nonpostwrszbyte,	0),
1332f263522aSJoseph Koshy 	__K8MASK(nonpostwrszdword,	1),
1333f263522aSJoseph Koshy 	__K8MASK(postwrszbyte,		2),
1334f263522aSJoseph Koshy 	__K8MASK(postwrszdword,		3),
1335f263522aSJoseph Koshy 	__K8MASK(rdszbyte,		4),
1336f263522aSJoseph Koshy 	__K8MASK(rdszdword,		5),
1337f263522aSJoseph Koshy 	__K8MASK(rdmodwr,		6),
1338f263522aSJoseph Koshy 	NULLMASK
1339f263522aSJoseph Koshy };
1340f263522aSJoseph Koshy 
1341f263522aSJoseph Koshy /* nb probe result */
1342f263522aSJoseph Koshy static const struct pmc_masks k8_mask_npr[] = {
1343f263522aSJoseph Koshy 	__K8MASK(probe-miss,		0),
1344f263522aSJoseph Koshy 	__K8MASK(probe-hit,		1),
1345f263522aSJoseph Koshy 	__K8MASK(probe-hit-dirty-no-memory-cancel, 2),
1346f263522aSJoseph Koshy 	__K8MASK(probe-hit-dirty-with-memory-cancel, 3),
1347f263522aSJoseph Koshy 	NULLMASK
1348f263522aSJoseph Koshy };
1349f263522aSJoseph Koshy 
1350f263522aSJoseph Koshy /* nb hypertransport bus bandwidth */
1351f263522aSJoseph Koshy static const struct pmc_masks k8_mask_nhbb[] = { /* HT bus bandwidth */
1352f263522aSJoseph Koshy 	__K8MASK(command,	0),
1353f263522aSJoseph Koshy 	__K8MASK(data,	1),
1354f263522aSJoseph Koshy 	__K8MASK(buffer-release, 2),
1355f263522aSJoseph Koshy 	__K8MASK(nop,	3),
1356f263522aSJoseph Koshy 	NULLMASK
1357f263522aSJoseph Koshy };
1358f263522aSJoseph Koshy 
1359f263522aSJoseph Koshy #undef	__K8MASK
1360f263522aSJoseph Koshy 
1361f263522aSJoseph Koshy #define	K8_KW_COUNT	"count"
1362f263522aSJoseph Koshy #define	K8_KW_EDGE	"edge"
1363f263522aSJoseph Koshy #define	K8_KW_INV	"inv"
1364f263522aSJoseph Koshy #define	K8_KW_MASK	"mask"
1365f263522aSJoseph Koshy #define	K8_KW_OS	"os"
1366f263522aSJoseph Koshy #define	K8_KW_USR	"usr"
1367f263522aSJoseph Koshy 
1368f263522aSJoseph Koshy static int
1369f263522aSJoseph Koshy k8_allocate_pmc(enum pmc_event pe, char *ctrspec,
1370f263522aSJoseph Koshy     struct pmc_op_pmcallocate *pmc_config)
1371f263522aSJoseph Koshy {
1372f263522aSJoseph Koshy 	char		*e, *p, *q;
1373f263522aSJoseph Koshy 	int		n;
13741e862e5aSFabien Thomas 	uint32_t	count;
13751e862e5aSFabien Thomas 	uint64_t	evmask;
1376f263522aSJoseph Koshy 	const struct pmc_masks	*pm, *pmask;
1377f263522aSJoseph Koshy 
1378789140c0SJoseph Koshy 	pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE);
1379f263522aSJoseph Koshy 	pmc_config->pm_md.pm_amd.pm_amd_config = 0;
1380f263522aSJoseph Koshy 
1381f263522aSJoseph Koshy 	pmask = NULL;
1382f263522aSJoseph Koshy 	evmask = 0;
1383f263522aSJoseph Koshy 
1384f263522aSJoseph Koshy #define	__K8SETMASK(M) pmask = k8_mask_##M
1385f263522aSJoseph Koshy 
1386f263522aSJoseph Koshy 	/* setup parsing tables */
1387f263522aSJoseph Koshy 	switch (pe) {
1388f263522aSJoseph Koshy 	case PMC_EV_K8_FP_DISPATCHED_FPU_OPS:
1389f263522aSJoseph Koshy 		__K8SETMASK(fdfo);
1390f263522aSJoseph Koshy 		break;
1391f263522aSJoseph Koshy 	case PMC_EV_K8_LS_SEGMENT_REGISTER_LOAD:
1392f263522aSJoseph Koshy 		__K8SETMASK(lsrl);
1393f263522aSJoseph Koshy 		break;
1394f263522aSJoseph Koshy 	case PMC_EV_K8_LS_LOCKED_OPERATION:
1395f263522aSJoseph Koshy 		__K8SETMASK(llo);
1396f263522aSJoseph Koshy 		break;
1397f263522aSJoseph Koshy 	case PMC_EV_K8_DC_REFILL_FROM_L2:
1398f263522aSJoseph Koshy 	case PMC_EV_K8_DC_REFILL_FROM_SYSTEM:
1399f263522aSJoseph Koshy 	case PMC_EV_K8_DC_COPYBACK:
1400f263522aSJoseph Koshy 		__K8SETMASK(dc);
1401f263522aSJoseph Koshy 		break;
1402f263522aSJoseph Koshy 	case PMC_EV_K8_DC_ONE_BIT_ECC_ERROR:
1403f263522aSJoseph Koshy 		__K8SETMASK(dobee);
1404f263522aSJoseph Koshy 		break;
1405f263522aSJoseph Koshy 	case PMC_EV_K8_DC_DISPATCHED_PREFETCH_INSTRUCTIONS:
1406f263522aSJoseph Koshy 		__K8SETMASK(ddpi);
1407f263522aSJoseph Koshy 		break;
1408f263522aSJoseph Koshy 	case PMC_EV_K8_DC_DCACHE_ACCESSES_BY_LOCKS:
1409f263522aSJoseph Koshy 		__K8SETMASK(dabl);
1410f263522aSJoseph Koshy 		break;
1411f263522aSJoseph Koshy 	case PMC_EV_K8_BU_INTERNAL_L2_REQUEST:
1412f263522aSJoseph Koshy 		__K8SETMASK(bilr);
1413f263522aSJoseph Koshy 		break;
1414f263522aSJoseph Koshy 	case PMC_EV_K8_BU_FILL_REQUEST_L2_MISS:
1415f263522aSJoseph Koshy 		__K8SETMASK(bfrlm);
1416f263522aSJoseph Koshy 		break;
1417f263522aSJoseph Koshy 	case PMC_EV_K8_BU_FILL_INTO_L2:
1418f263522aSJoseph Koshy 		__K8SETMASK(bfil);
1419f263522aSJoseph Koshy 		break;
1420f263522aSJoseph Koshy 	case PMC_EV_K8_FR_RETIRED_FPU_INSTRUCTIONS:
1421f263522aSJoseph Koshy 		__K8SETMASK(frfi);
1422f263522aSJoseph Koshy 		break;
1423f263522aSJoseph Koshy 	case PMC_EV_K8_FR_RETIRED_FASTPATH_DOUBLE_OP_INSTRUCTIONS:
1424f263522aSJoseph Koshy 		__K8SETMASK(frfdoi);
1425f263522aSJoseph Koshy 		break;
1426f263522aSJoseph Koshy 	case PMC_EV_K8_FR_FPU_EXCEPTIONS:
1427f263522aSJoseph Koshy 		__K8SETMASK(ffe);
1428f263522aSJoseph Koshy 		break;
1429f263522aSJoseph Koshy 	case PMC_EV_K8_NB_MEMORY_CONTROLLER_PAGE_ACCESS_EVENT:
1430f263522aSJoseph Koshy 		__K8SETMASK(nmcpae);
1431f263522aSJoseph Koshy 		break;
1432f263522aSJoseph Koshy 	case PMC_EV_K8_NB_MEMORY_CONTROLLER_TURNAROUND:
1433f263522aSJoseph Koshy 		__K8SETMASK(nmct);
1434f263522aSJoseph Koshy 		break;
1435f263522aSJoseph Koshy 	case PMC_EV_K8_NB_MEMORY_CONTROLLER_BYPASS_SATURATION:
1436f263522aSJoseph Koshy 		__K8SETMASK(nmcbs);
1437f263522aSJoseph Koshy 		break;
1438f263522aSJoseph Koshy 	case PMC_EV_K8_NB_SIZED_COMMANDS:
1439f263522aSJoseph Koshy 		__K8SETMASK(nsc);
1440f263522aSJoseph Koshy 		break;
1441f263522aSJoseph Koshy 	case PMC_EV_K8_NB_PROBE_RESULT:
1442f263522aSJoseph Koshy 		__K8SETMASK(npr);
1443f263522aSJoseph Koshy 		break;
1444f263522aSJoseph Koshy 	case PMC_EV_K8_NB_HT_BUS0_BANDWIDTH:
1445f263522aSJoseph Koshy 	case PMC_EV_K8_NB_HT_BUS1_BANDWIDTH:
1446f263522aSJoseph Koshy 	case PMC_EV_K8_NB_HT_BUS2_BANDWIDTH:
1447f263522aSJoseph Koshy 		__K8SETMASK(nhbb);
1448f263522aSJoseph Koshy 		break;
1449f263522aSJoseph Koshy 
1450f263522aSJoseph Koshy 	default:
1451f263522aSJoseph Koshy 		break;		/* no options defined */
1452f263522aSJoseph Koshy 	}
1453f263522aSJoseph Koshy 
1454f263522aSJoseph Koshy 	while ((p = strsep(&ctrspec, ",")) != NULL) {
1455f263522aSJoseph Koshy 		if (KWPREFIXMATCH(p, K8_KW_COUNT "=")) {
1456f263522aSJoseph Koshy 			q = strchr(p, '=');
1457f263522aSJoseph Koshy 			if (*++q == '\0') /* skip '=' */
1458aa342b1fSJoseph Koshy 				return (-1);
1459f263522aSJoseph Koshy 
1460f263522aSJoseph Koshy 			count = strtol(q, &e, 0);
1461f263522aSJoseph Koshy 			if (e == q || *e != '\0')
1462aa342b1fSJoseph Koshy 				return (-1);
1463f263522aSJoseph Koshy 
1464f263522aSJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_THRESHOLD;
1465f263522aSJoseph Koshy 			pmc_config->pm_md.pm_amd.pm_amd_config |=
1466f263522aSJoseph Koshy 			    AMD_PMC_TO_COUNTER(count);
1467f263522aSJoseph Koshy 
1468f263522aSJoseph Koshy 		} else if (KWMATCH(p, K8_KW_EDGE)) {
1469f263522aSJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_EDGE;
1470f263522aSJoseph Koshy 		} else if (KWMATCH(p, K8_KW_INV)) {
1471f263522aSJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_INVERT;
1472f263522aSJoseph Koshy 		} else if (KWPREFIXMATCH(p, K8_KW_MASK "=")) {
1473f263522aSJoseph Koshy 			if ((n = pmc_parse_mask(pmask, p, &evmask)) < 0)
1474aa342b1fSJoseph Koshy 				return (-1);
1475f263522aSJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_QUALIFIER;
1476f263522aSJoseph Koshy 		} else if (KWMATCH(p, K8_KW_OS)) {
1477f263522aSJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_SYSTEM;
1478f263522aSJoseph Koshy 		} else if (KWMATCH(p, K8_KW_USR)) {
1479f263522aSJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_USER;
1480f263522aSJoseph Koshy 		} else
1481aa342b1fSJoseph Koshy 			return (-1);
1482f263522aSJoseph Koshy 	}
1483f263522aSJoseph Koshy 
1484f263522aSJoseph Koshy 	/* other post processing */
1485f263522aSJoseph Koshy 	switch (pe) {
1486f263522aSJoseph Koshy 	case PMC_EV_K8_FP_DISPATCHED_FPU_OPS:
1487f263522aSJoseph Koshy 	case PMC_EV_K8_FP_CYCLES_WITH_NO_FPU_OPS_RETIRED:
1488f263522aSJoseph Koshy 	case PMC_EV_K8_FP_DISPATCHED_FPU_FAST_FLAG_OPS:
1489f263522aSJoseph Koshy 	case PMC_EV_K8_FR_RETIRED_FASTPATH_DOUBLE_OP_INSTRUCTIONS:
1490f263522aSJoseph Koshy 	case PMC_EV_K8_FR_RETIRED_FPU_INSTRUCTIONS:
1491f263522aSJoseph Koshy 	case PMC_EV_K8_FR_FPU_EXCEPTIONS:
1492f263522aSJoseph Koshy 		/* XXX only available in rev B and later */
1493f263522aSJoseph Koshy 		break;
1494f263522aSJoseph Koshy 	case PMC_EV_K8_DC_DCACHE_ACCESSES_BY_LOCKS:
1495f263522aSJoseph Koshy 		/* XXX only available in rev C and later */
1496f263522aSJoseph Koshy 		break;
1497f263522aSJoseph Koshy 	case PMC_EV_K8_LS_LOCKED_OPERATION:
1498f263522aSJoseph Koshy 		/* XXX CPU Rev A,B evmask is to be zero */
1499f263522aSJoseph Koshy 		if (evmask & (evmask - 1)) /* > 1 bit set */
1500aa342b1fSJoseph Koshy 			return (-1);
1501f263522aSJoseph Koshy 		if (evmask == 0) {
1502f263522aSJoseph Koshy 			evmask = 0x01; /* Rev C and later: #instrs */
1503f263522aSJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_QUALIFIER;
1504f263522aSJoseph Koshy 		}
1505f263522aSJoseph Koshy 		break;
1506f263522aSJoseph Koshy 	default:
1507f263522aSJoseph Koshy 		if (evmask == 0 && pmask != NULL) {
1508f263522aSJoseph Koshy 			for (pm = pmask; pm->pm_name; pm++)
1509f263522aSJoseph Koshy 				evmask |= pm->pm_value;
1510f263522aSJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_QUALIFIER;
1511f263522aSJoseph Koshy 		}
1512f263522aSJoseph Koshy 	}
1513f263522aSJoseph Koshy 
1514f263522aSJoseph Koshy 	if (pmc_config->pm_caps & PMC_CAP_QUALIFIER)
1515f263522aSJoseph Koshy 		pmc_config->pm_md.pm_amd.pm_amd_config =
1516f263522aSJoseph Koshy 		    AMD_PMC_TO_UNITMASK(evmask);
1517f263522aSJoseph Koshy 
1518aa342b1fSJoseph Koshy 	return (0);
1519f263522aSJoseph Koshy }
1520f263522aSJoseph Koshy 
1521f263522aSJoseph Koshy #endif
1522f263522aSJoseph Koshy 
152386a65549SJoseph Koshy #if defined(__amd64__) || defined(__i386__)
1524f263522aSJoseph Koshy 
1525ebccf1e3SJoseph Koshy /*
1526ebccf1e3SJoseph Koshy  * Intel P4 PMCs
1527ebccf1e3SJoseph Koshy  */
1528ebccf1e3SJoseph Koshy 
1529ebccf1e3SJoseph Koshy static struct pmc_event_alias p4_aliases[] = {
1530d56c5d4bSJoseph Koshy 	EV_ALIAS("branches",		"p4-branch-retired,mask=mmtp+mmtm"),
1531d56c5d4bSJoseph Koshy 	EV_ALIAS("branch-mispredicts",	"p4-mispred-branch-retired"),
1532ebccf1e3SJoseph Koshy 	EV_ALIAS("cycles",		"tsc"),
1533d56c5d4bSJoseph Koshy 	EV_ALIAS("instructions",
1534d56c5d4bSJoseph Koshy 	    "p4-instr-retired,mask=nbogusntag+nbogustag"),
1535177a2f22SJoseph Koshy 	EV_ALIAS("unhalted-cycles",	"p4-global-power-events"),
1536ebccf1e3SJoseph Koshy 	EV_ALIAS(NULL, NULL)
1537ebccf1e3SJoseph Koshy };
1538ebccf1e3SJoseph Koshy 
1539ebccf1e3SJoseph Koshy #define	P4_KW_ACTIVE	"active"
1540ebccf1e3SJoseph Koshy #define	P4_KW_ACTIVE_ANY "any"
1541ebccf1e3SJoseph Koshy #define	P4_KW_ACTIVE_BOTH "both"
1542ebccf1e3SJoseph Koshy #define	P4_KW_ACTIVE_NONE "none"
1543ebccf1e3SJoseph Koshy #define	P4_KW_ACTIVE_SINGLE "single"
1544ebccf1e3SJoseph Koshy #define	P4_KW_BUSREQTYPE "busreqtype"
1545ebccf1e3SJoseph Koshy #define	P4_KW_CASCADE	"cascade"
1546ebccf1e3SJoseph Koshy #define	P4_KW_EDGE	"edge"
1547ebccf1e3SJoseph Koshy #define	P4_KW_INV	"complement"
1548ebccf1e3SJoseph Koshy #define	P4_KW_OS	"os"
1549ebccf1e3SJoseph Koshy #define	P4_KW_MASK	"mask"
1550ebccf1e3SJoseph Koshy #define	P4_KW_PRECISE	"precise"
1551ebccf1e3SJoseph Koshy #define	P4_KW_TAG	"tag"
1552ebccf1e3SJoseph Koshy #define	P4_KW_THRESHOLD	"threshold"
1553ebccf1e3SJoseph Koshy #define	P4_KW_USR	"usr"
1554ebccf1e3SJoseph Koshy 
1555ebccf1e3SJoseph Koshy #define	__P4MASK(N,V) PMCMASK(N, (1 << (V)))
1556ebccf1e3SJoseph Koshy 
1557ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_tcdm[] = { /* tc deliver mode */
1558ebccf1e3SJoseph Koshy 	__P4MASK(dd, 0),
1559ebccf1e3SJoseph Koshy 	__P4MASK(db, 1),
1560ebccf1e3SJoseph Koshy 	__P4MASK(di, 2),
1561ebccf1e3SJoseph Koshy 	__P4MASK(bd, 3),
1562ebccf1e3SJoseph Koshy 	__P4MASK(bb, 4),
1563ebccf1e3SJoseph Koshy 	__P4MASK(bi, 5),
1564ebccf1e3SJoseph Koshy 	__P4MASK(id, 6),
1565ebccf1e3SJoseph Koshy 	__P4MASK(ib, 7),
1566ebccf1e3SJoseph Koshy 	NULLMASK
1567ebccf1e3SJoseph Koshy };
1568ebccf1e3SJoseph Koshy 
1569ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_bfr[] = { /* bpu fetch request */
1570ebccf1e3SJoseph Koshy 	__P4MASK(tcmiss, 0),
1571ebccf1e3SJoseph Koshy 	NULLMASK,
1572ebccf1e3SJoseph Koshy };
1573ebccf1e3SJoseph Koshy 
1574ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_ir[] = { /* itlb reference */
1575ebccf1e3SJoseph Koshy 	__P4MASK(hit, 0),
1576ebccf1e3SJoseph Koshy 	__P4MASK(miss, 1),
1577ebccf1e3SJoseph Koshy 	__P4MASK(hit-uc, 2),
1578ebccf1e3SJoseph Koshy 	NULLMASK
1579ebccf1e3SJoseph Koshy };
1580ebccf1e3SJoseph Koshy 
1581ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_memcan[] = { /* memory cancel */
1582ebccf1e3SJoseph Koshy 	__P4MASK(st-rb-full, 2),
1583ebccf1e3SJoseph Koshy 	__P4MASK(64k-conf, 3),
1584ebccf1e3SJoseph Koshy 	NULLMASK
1585ebccf1e3SJoseph Koshy };
1586ebccf1e3SJoseph Koshy 
1587ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_memcomp[] = { /* memory complete */
1588ebccf1e3SJoseph Koshy 	__P4MASK(lsc, 0),
1589ebccf1e3SJoseph Koshy 	__P4MASK(ssc, 1),
1590ebccf1e3SJoseph Koshy 	NULLMASK
1591ebccf1e3SJoseph Koshy };
1592ebccf1e3SJoseph Koshy 
1593ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_lpr[] = { /* load port replay */
1594ebccf1e3SJoseph Koshy 	__P4MASK(split-ld, 1),
1595ebccf1e3SJoseph Koshy 	NULLMASK
1596ebccf1e3SJoseph Koshy };
1597ebccf1e3SJoseph Koshy 
1598ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_spr[] = { /* store port replay */
1599ebccf1e3SJoseph Koshy 	__P4MASK(split-st, 1),
1600ebccf1e3SJoseph Koshy 	NULLMASK
1601ebccf1e3SJoseph Koshy };
1602ebccf1e3SJoseph Koshy 
1603ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_mlr[] = { /* mob load replay */
1604ebccf1e3SJoseph Koshy 	__P4MASK(no-sta, 1),
1605ebccf1e3SJoseph Koshy 	__P4MASK(no-std, 3),
1606ebccf1e3SJoseph Koshy 	__P4MASK(partial-data, 4),
1607ebccf1e3SJoseph Koshy 	__P4MASK(unalgn-addr, 5),
1608ebccf1e3SJoseph Koshy 	NULLMASK
1609ebccf1e3SJoseph Koshy };
1610ebccf1e3SJoseph Koshy 
1611ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_pwt[] = { /* page walk type */
1612ebccf1e3SJoseph Koshy 	__P4MASK(dtmiss, 0),
1613ebccf1e3SJoseph Koshy 	__P4MASK(itmiss, 1),
1614ebccf1e3SJoseph Koshy 	NULLMASK
1615ebccf1e3SJoseph Koshy };
1616ebccf1e3SJoseph Koshy 
1617ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_bcr[] = { /* bsq cache reference */
1618ebccf1e3SJoseph Koshy 	__P4MASK(rd-2ndl-hits, 0),
1619ebccf1e3SJoseph Koshy 	__P4MASK(rd-2ndl-hite, 1),
1620ebccf1e3SJoseph Koshy 	__P4MASK(rd-2ndl-hitm, 2),
1621ebccf1e3SJoseph Koshy 	__P4MASK(rd-3rdl-hits, 3),
1622ebccf1e3SJoseph Koshy 	__P4MASK(rd-3rdl-hite, 4),
1623ebccf1e3SJoseph Koshy 	__P4MASK(rd-3rdl-hitm, 5),
1624ebccf1e3SJoseph Koshy 	__P4MASK(rd-2ndl-miss, 8),
1625ebccf1e3SJoseph Koshy 	__P4MASK(rd-3rdl-miss, 9),
1626ebccf1e3SJoseph Koshy 	__P4MASK(wr-2ndl-miss, 10),
1627ebccf1e3SJoseph Koshy 	NULLMASK
1628ebccf1e3SJoseph Koshy };
1629ebccf1e3SJoseph Koshy 
1630ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_ia[] = { /* ioq allocation */
1631ebccf1e3SJoseph Koshy 	__P4MASK(all-read, 5),
1632ebccf1e3SJoseph Koshy 	__P4MASK(all-write, 6),
1633ebccf1e3SJoseph Koshy 	__P4MASK(mem-uc, 7),
1634ebccf1e3SJoseph Koshy 	__P4MASK(mem-wc, 8),
1635ebccf1e3SJoseph Koshy 	__P4MASK(mem-wt, 9),
1636ebccf1e3SJoseph Koshy 	__P4MASK(mem-wp, 10),
1637ebccf1e3SJoseph Koshy 	__P4MASK(mem-wb, 11),
1638ebccf1e3SJoseph Koshy 	__P4MASK(own, 13),
1639ebccf1e3SJoseph Koshy 	__P4MASK(other, 14),
1640ebccf1e3SJoseph Koshy 	__P4MASK(prefetch, 15),
1641ebccf1e3SJoseph Koshy 	NULLMASK
1642ebccf1e3SJoseph Koshy };
1643ebccf1e3SJoseph Koshy 
1644ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_iae[] = { /* ioq active entries */
1645ebccf1e3SJoseph Koshy 	__P4MASK(all-read, 5),
1646ebccf1e3SJoseph Koshy 	__P4MASK(all-write, 6),
1647ebccf1e3SJoseph Koshy 	__P4MASK(mem-uc, 7),
1648ebccf1e3SJoseph Koshy 	__P4MASK(mem-wc, 8),
1649ebccf1e3SJoseph Koshy 	__P4MASK(mem-wt, 9),
1650ebccf1e3SJoseph Koshy 	__P4MASK(mem-wp, 10),
1651ebccf1e3SJoseph Koshy 	__P4MASK(mem-wb, 11),
1652ebccf1e3SJoseph Koshy 	__P4MASK(own, 13),
1653ebccf1e3SJoseph Koshy 	__P4MASK(other, 14),
1654ebccf1e3SJoseph Koshy 	__P4MASK(prefetch, 15),
1655ebccf1e3SJoseph Koshy 	NULLMASK
1656ebccf1e3SJoseph Koshy };
1657ebccf1e3SJoseph Koshy 
1658ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_fda[] = { /* fsb data activity */
1659ebccf1e3SJoseph Koshy 	__P4MASK(drdy-drv, 0),
1660ebccf1e3SJoseph Koshy 	__P4MASK(drdy-own, 1),
1661ebccf1e3SJoseph Koshy 	__P4MASK(drdy-other, 2),
1662ebccf1e3SJoseph Koshy 	__P4MASK(dbsy-drv, 3),
1663ebccf1e3SJoseph Koshy 	__P4MASK(dbsy-own, 4),
1664ebccf1e3SJoseph Koshy 	__P4MASK(dbsy-other, 5),
1665ebccf1e3SJoseph Koshy 	NULLMASK
1666ebccf1e3SJoseph Koshy };
1667ebccf1e3SJoseph Koshy 
1668ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_ba[] = { /* bsq allocation */
1669ebccf1e3SJoseph Koshy 	__P4MASK(req-type0, 0),
1670ebccf1e3SJoseph Koshy 	__P4MASK(req-type1, 1),
1671ebccf1e3SJoseph Koshy 	__P4MASK(req-len0, 2),
1672ebccf1e3SJoseph Koshy 	__P4MASK(req-len1, 3),
1673ebccf1e3SJoseph Koshy 	__P4MASK(req-io-type, 5),
1674ebccf1e3SJoseph Koshy 	__P4MASK(req-lock-type, 6),
1675ebccf1e3SJoseph Koshy 	__P4MASK(req-cache-type, 7),
1676ebccf1e3SJoseph Koshy 	__P4MASK(req-split-type, 8),
1677ebccf1e3SJoseph Koshy 	__P4MASK(req-dem-type, 9),
1678ebccf1e3SJoseph Koshy 	__P4MASK(req-ord-type, 10),
1679ebccf1e3SJoseph Koshy 	__P4MASK(mem-type0, 11),
1680ebccf1e3SJoseph Koshy 	__P4MASK(mem-type1, 12),
1681ebccf1e3SJoseph Koshy 	__P4MASK(mem-type2, 13),
1682ebccf1e3SJoseph Koshy 	NULLMASK
1683ebccf1e3SJoseph Koshy };
1684ebccf1e3SJoseph Koshy 
1685ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_sia[] = { /* sse input assist */
1686ebccf1e3SJoseph Koshy 	__P4MASK(all, 15),
1687ebccf1e3SJoseph Koshy 	NULLMASK
1688ebccf1e3SJoseph Koshy };
1689ebccf1e3SJoseph Koshy 
1690ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_psu[] = { /* packed sp uop */
1691ebccf1e3SJoseph Koshy 	__P4MASK(all, 15),
1692ebccf1e3SJoseph Koshy 	NULLMASK
1693ebccf1e3SJoseph Koshy };
1694ebccf1e3SJoseph Koshy 
1695ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_pdu[] = { /* packed dp uop */
1696ebccf1e3SJoseph Koshy 	__P4MASK(all, 15),
1697ebccf1e3SJoseph Koshy 	NULLMASK
1698ebccf1e3SJoseph Koshy };
1699ebccf1e3SJoseph Koshy 
1700ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_ssu[] = { /* scalar sp uop */
1701ebccf1e3SJoseph Koshy 	__P4MASK(all, 15),
1702ebccf1e3SJoseph Koshy 	NULLMASK
1703ebccf1e3SJoseph Koshy };
1704ebccf1e3SJoseph Koshy 
1705ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_sdu[] = { /* scalar dp uop */
1706ebccf1e3SJoseph Koshy 	__P4MASK(all, 15),
1707ebccf1e3SJoseph Koshy 	NULLMASK
1708ebccf1e3SJoseph Koshy };
1709ebccf1e3SJoseph Koshy 
1710ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_64bmu[] = { /* 64 bit mmx uop */
1711ebccf1e3SJoseph Koshy 	__P4MASK(all, 15),
1712ebccf1e3SJoseph Koshy 	NULLMASK
1713ebccf1e3SJoseph Koshy };
1714ebccf1e3SJoseph Koshy 
1715ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_128bmu[] = { /* 128 bit mmx uop */
1716ebccf1e3SJoseph Koshy 	__P4MASK(all, 15),
1717ebccf1e3SJoseph Koshy 	NULLMASK
1718ebccf1e3SJoseph Koshy };
1719ebccf1e3SJoseph Koshy 
1720ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_xfu[] = { /* X87 fp uop */
1721ebccf1e3SJoseph Koshy 	__P4MASK(all, 15),
1722ebccf1e3SJoseph Koshy 	NULLMASK
1723ebccf1e3SJoseph Koshy };
1724ebccf1e3SJoseph Koshy 
1725ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_xsmu[] = { /* x87 simd moves uop */
1726ebccf1e3SJoseph Koshy 	__P4MASK(allp0, 3),
1727ebccf1e3SJoseph Koshy 	__P4MASK(allp2, 4),
1728ebccf1e3SJoseph Koshy 	NULLMASK
1729ebccf1e3SJoseph Koshy };
1730ebccf1e3SJoseph Koshy 
1731ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_gpe[] = { /* global power events */
1732ebccf1e3SJoseph Koshy 	__P4MASK(running, 0),
1733ebccf1e3SJoseph Koshy 	NULLMASK
1734ebccf1e3SJoseph Koshy };
1735ebccf1e3SJoseph Koshy 
1736ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_tmx[] = { /* TC ms xfer */
1737ebccf1e3SJoseph Koshy 	__P4MASK(cisc, 0),
1738ebccf1e3SJoseph Koshy 	NULLMASK
1739ebccf1e3SJoseph Koshy };
1740ebccf1e3SJoseph Koshy 
1741ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_uqw[] = { /* uop queue writes */
1742ebccf1e3SJoseph Koshy 	__P4MASK(from-tc-build, 0),
1743ebccf1e3SJoseph Koshy 	__P4MASK(from-tc-deliver, 1),
1744ebccf1e3SJoseph Koshy 	__P4MASK(from-rom, 2),
1745ebccf1e3SJoseph Koshy 	NULLMASK
1746ebccf1e3SJoseph Koshy };
1747ebccf1e3SJoseph Koshy 
1748d56c5d4bSJoseph Koshy static const struct pmc_masks p4_mask_rmbt[] = {
1749d56c5d4bSJoseph Koshy 	/* retired mispred branch type */
1750ebccf1e3SJoseph Koshy 	__P4MASK(conditional, 1),
1751ebccf1e3SJoseph Koshy 	__P4MASK(call, 2),
1752ebccf1e3SJoseph Koshy 	__P4MASK(return, 3),
1753ebccf1e3SJoseph Koshy 	__P4MASK(indirect, 4),
1754ebccf1e3SJoseph Koshy 	NULLMASK
1755ebccf1e3SJoseph Koshy };
1756ebccf1e3SJoseph Koshy 
1757ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_rbt[] = { /* retired branch type */
1758ebccf1e3SJoseph Koshy 	__P4MASK(conditional, 1),
1759ebccf1e3SJoseph Koshy 	__P4MASK(call, 2),
1760ebccf1e3SJoseph Koshy 	__P4MASK(retired, 3),
1761ebccf1e3SJoseph Koshy 	__P4MASK(indirect, 4),
1762ebccf1e3SJoseph Koshy 	NULLMASK
1763ebccf1e3SJoseph Koshy };
1764ebccf1e3SJoseph Koshy 
1765ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_rs[] = { /* resource stall */
1766ebccf1e3SJoseph Koshy 	__P4MASK(sbfull, 5),
1767ebccf1e3SJoseph Koshy 	NULLMASK
1768ebccf1e3SJoseph Koshy };
1769ebccf1e3SJoseph Koshy 
1770ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_wb[] = { /* WC buffer */
1771ebccf1e3SJoseph Koshy 	__P4MASK(wcb-evicts, 0),
1772ebccf1e3SJoseph Koshy 	__P4MASK(wcb-full-evict, 1),
1773ebccf1e3SJoseph Koshy 	NULLMASK
1774ebccf1e3SJoseph Koshy };
1775ebccf1e3SJoseph Koshy 
1776ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_fee[] = { /* front end event */
1777ebccf1e3SJoseph Koshy 	__P4MASK(nbogus, 0),
1778ebccf1e3SJoseph Koshy 	__P4MASK(bogus, 1),
1779ebccf1e3SJoseph Koshy 	NULLMASK
1780ebccf1e3SJoseph Koshy };
1781ebccf1e3SJoseph Koshy 
1782ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_ee[] = { /* execution event */
1783ebccf1e3SJoseph Koshy 	__P4MASK(nbogus0, 0),
1784ebccf1e3SJoseph Koshy 	__P4MASK(nbogus1, 1),
1785ebccf1e3SJoseph Koshy 	__P4MASK(nbogus2, 2),
1786ebccf1e3SJoseph Koshy 	__P4MASK(nbogus3, 3),
1787ebccf1e3SJoseph Koshy 	__P4MASK(bogus0, 4),
1788ebccf1e3SJoseph Koshy 	__P4MASK(bogus1, 5),
1789ebccf1e3SJoseph Koshy 	__P4MASK(bogus2, 6),
1790ebccf1e3SJoseph Koshy 	__P4MASK(bogus3, 7),
1791ebccf1e3SJoseph Koshy 	NULLMASK
1792ebccf1e3SJoseph Koshy };
1793ebccf1e3SJoseph Koshy 
1794ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_re[] = { /* replay event */
1795ebccf1e3SJoseph Koshy 	__P4MASK(nbogus, 0),
1796ebccf1e3SJoseph Koshy 	__P4MASK(bogus, 1),
1797ebccf1e3SJoseph Koshy 	NULLMASK
1798ebccf1e3SJoseph Koshy };
1799ebccf1e3SJoseph Koshy 
1800ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_insret[] = { /* instr retired */
1801ebccf1e3SJoseph Koshy 	__P4MASK(nbogusntag, 0),
1802ebccf1e3SJoseph Koshy 	__P4MASK(nbogustag, 1),
1803ebccf1e3SJoseph Koshy 	__P4MASK(bogusntag, 2),
1804ebccf1e3SJoseph Koshy 	__P4MASK(bogustag, 3),
1805ebccf1e3SJoseph Koshy 	NULLMASK
1806ebccf1e3SJoseph Koshy };
1807ebccf1e3SJoseph Koshy 
1808ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_ur[] = { /* uops retired */
1809ebccf1e3SJoseph Koshy 	__P4MASK(nbogus, 0),
1810ebccf1e3SJoseph Koshy 	__P4MASK(bogus, 1),
1811ebccf1e3SJoseph Koshy 	NULLMASK
1812ebccf1e3SJoseph Koshy };
1813ebccf1e3SJoseph Koshy 
1814ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_ut[] = { /* uop type */
1815ebccf1e3SJoseph Koshy 	__P4MASK(tagloads, 1),
1816ebccf1e3SJoseph Koshy 	__P4MASK(tagstores, 2),
1817ebccf1e3SJoseph Koshy 	NULLMASK
1818ebccf1e3SJoseph Koshy };
1819ebccf1e3SJoseph Koshy 
1820ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_br[] = { /* branch retired */
1821ebccf1e3SJoseph Koshy 	__P4MASK(mmnp, 0),
1822ebccf1e3SJoseph Koshy 	__P4MASK(mmnm, 1),
1823ebccf1e3SJoseph Koshy 	__P4MASK(mmtp, 2),
1824ebccf1e3SJoseph Koshy 	__P4MASK(mmtm, 3),
1825ebccf1e3SJoseph Koshy 	NULLMASK
1826ebccf1e3SJoseph Koshy };
1827ebccf1e3SJoseph Koshy 
1828ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_mbr[] = { /* mispred branch retired */
1829ebccf1e3SJoseph Koshy 	__P4MASK(nbogus, 0),
1830ebccf1e3SJoseph Koshy 	NULLMASK
1831ebccf1e3SJoseph Koshy };
1832ebccf1e3SJoseph Koshy 
1833ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_xa[] = { /* x87 assist */
1834ebccf1e3SJoseph Koshy 	__P4MASK(fpsu, 0),
1835ebccf1e3SJoseph Koshy 	__P4MASK(fpso, 1),
1836ebccf1e3SJoseph Koshy 	__P4MASK(poao, 2),
1837ebccf1e3SJoseph Koshy 	__P4MASK(poau, 3),
1838ebccf1e3SJoseph Koshy 	__P4MASK(prea, 4),
1839ebccf1e3SJoseph Koshy 	NULLMASK
1840ebccf1e3SJoseph Koshy };
1841ebccf1e3SJoseph Koshy 
1842ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_machclr[] = { /* machine clear */
1843ebccf1e3SJoseph Koshy 	__P4MASK(clear, 0),
1844ebccf1e3SJoseph Koshy 	__P4MASK(moclear, 2),
1845ebccf1e3SJoseph Koshy 	__P4MASK(smclear, 3),
1846ebccf1e3SJoseph Koshy 	NULLMASK
1847ebccf1e3SJoseph Koshy };
1848ebccf1e3SJoseph Koshy 
1849ebccf1e3SJoseph Koshy /* P4 event parser */
1850ebccf1e3SJoseph Koshy static int
1851ebccf1e3SJoseph Koshy p4_allocate_pmc(enum pmc_event pe, char *ctrspec,
1852ebccf1e3SJoseph Koshy     struct pmc_op_pmcallocate *pmc_config)
1853ebccf1e3SJoseph Koshy {
1854ebccf1e3SJoseph Koshy 
1855ebccf1e3SJoseph Koshy 	char	*e, *p, *q;
1856ebccf1e3SJoseph Koshy 	int	count, has_tag, has_busreqtype, n;
18571e862e5aSFabien Thomas 	uint32_t cccractivemask;
18581e862e5aSFabien Thomas 	uint64_t evmask;
1859ebccf1e3SJoseph Koshy 	const struct pmc_masks *pm, *pmask;
1860ebccf1e3SJoseph Koshy 
1861789140c0SJoseph Koshy 	pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE);
1862f263522aSJoseph Koshy 	pmc_config->pm_md.pm_p4.pm_p4_cccrconfig =
1863f263522aSJoseph Koshy 	    pmc_config->pm_md.pm_p4.pm_p4_escrconfig = 0;
1864ebccf1e3SJoseph Koshy 
1865ebccf1e3SJoseph Koshy 	pmask   = NULL;
1866ebccf1e3SJoseph Koshy 	evmask  = 0;
1867ebccf1e3SJoseph Koshy 	cccractivemask = 0x3;
1868ebccf1e3SJoseph Koshy 	has_tag = has_busreqtype = 0;
1869ebccf1e3SJoseph Koshy 
1870ebccf1e3SJoseph Koshy #define	__P4SETMASK(M) do {				\
1871ebccf1e3SJoseph Koshy 	pmask = p4_mask_##M;				\
1872ebccf1e3SJoseph Koshy } while (0)
1873ebccf1e3SJoseph Koshy 
1874ebccf1e3SJoseph Koshy 	switch (pe) {
1875ebccf1e3SJoseph Koshy 	case PMC_EV_P4_TC_DELIVER_MODE:
1876ebccf1e3SJoseph Koshy 		__P4SETMASK(tcdm);
1877ebccf1e3SJoseph Koshy 		break;
1878ebccf1e3SJoseph Koshy 	case PMC_EV_P4_BPU_FETCH_REQUEST:
1879ebccf1e3SJoseph Koshy 		__P4SETMASK(bfr);
1880ebccf1e3SJoseph Koshy 		break;
1881ebccf1e3SJoseph Koshy 	case PMC_EV_P4_ITLB_REFERENCE:
1882ebccf1e3SJoseph Koshy 		__P4SETMASK(ir);
1883ebccf1e3SJoseph Koshy 		break;
1884ebccf1e3SJoseph Koshy 	case PMC_EV_P4_MEMORY_CANCEL:
1885ebccf1e3SJoseph Koshy 		__P4SETMASK(memcan);
1886ebccf1e3SJoseph Koshy 		break;
1887ebccf1e3SJoseph Koshy 	case PMC_EV_P4_MEMORY_COMPLETE:
1888ebccf1e3SJoseph Koshy 		__P4SETMASK(memcomp);
1889ebccf1e3SJoseph Koshy 		break;
1890ebccf1e3SJoseph Koshy 	case PMC_EV_P4_LOAD_PORT_REPLAY:
1891ebccf1e3SJoseph Koshy 		__P4SETMASK(lpr);
1892ebccf1e3SJoseph Koshy 		break;
1893ebccf1e3SJoseph Koshy 	case PMC_EV_P4_STORE_PORT_REPLAY:
1894ebccf1e3SJoseph Koshy 		__P4SETMASK(spr);
1895ebccf1e3SJoseph Koshy 		break;
1896ebccf1e3SJoseph Koshy 	case PMC_EV_P4_MOB_LOAD_REPLAY:
1897ebccf1e3SJoseph Koshy 		__P4SETMASK(mlr);
1898ebccf1e3SJoseph Koshy 		break;
1899ebccf1e3SJoseph Koshy 	case PMC_EV_P4_PAGE_WALK_TYPE:
1900ebccf1e3SJoseph Koshy 		__P4SETMASK(pwt);
1901ebccf1e3SJoseph Koshy 		break;
1902ebccf1e3SJoseph Koshy 	case PMC_EV_P4_BSQ_CACHE_REFERENCE:
1903ebccf1e3SJoseph Koshy 		__P4SETMASK(bcr);
1904ebccf1e3SJoseph Koshy 		break;
1905ebccf1e3SJoseph Koshy 	case PMC_EV_P4_IOQ_ALLOCATION:
1906ebccf1e3SJoseph Koshy 		__P4SETMASK(ia);
1907ebccf1e3SJoseph Koshy 		has_busreqtype = 1;
1908ebccf1e3SJoseph Koshy 		break;
1909ebccf1e3SJoseph Koshy 	case PMC_EV_P4_IOQ_ACTIVE_ENTRIES:
1910ebccf1e3SJoseph Koshy 		__P4SETMASK(iae);
1911ebccf1e3SJoseph Koshy 		has_busreqtype = 1;
1912ebccf1e3SJoseph Koshy 		break;
1913ebccf1e3SJoseph Koshy 	case PMC_EV_P4_FSB_DATA_ACTIVITY:
1914ebccf1e3SJoseph Koshy 		__P4SETMASK(fda);
1915ebccf1e3SJoseph Koshy 		break;
1916ebccf1e3SJoseph Koshy 	case PMC_EV_P4_BSQ_ALLOCATION:
1917ebccf1e3SJoseph Koshy 		__P4SETMASK(ba);
1918ebccf1e3SJoseph Koshy 		break;
1919ebccf1e3SJoseph Koshy 	case PMC_EV_P4_SSE_INPUT_ASSIST:
1920ebccf1e3SJoseph Koshy 		__P4SETMASK(sia);
1921ebccf1e3SJoseph Koshy 		break;
1922ebccf1e3SJoseph Koshy 	case PMC_EV_P4_PACKED_SP_UOP:
1923ebccf1e3SJoseph Koshy 		__P4SETMASK(psu);
1924ebccf1e3SJoseph Koshy 		break;
1925ebccf1e3SJoseph Koshy 	case PMC_EV_P4_PACKED_DP_UOP:
1926ebccf1e3SJoseph Koshy 		__P4SETMASK(pdu);
1927ebccf1e3SJoseph Koshy 		break;
1928ebccf1e3SJoseph Koshy 	case PMC_EV_P4_SCALAR_SP_UOP:
1929ebccf1e3SJoseph Koshy 		__P4SETMASK(ssu);
1930ebccf1e3SJoseph Koshy 		break;
1931ebccf1e3SJoseph Koshy 	case PMC_EV_P4_SCALAR_DP_UOP:
1932ebccf1e3SJoseph Koshy 		__P4SETMASK(sdu);
1933ebccf1e3SJoseph Koshy 		break;
1934ebccf1e3SJoseph Koshy 	case PMC_EV_P4_64BIT_MMX_UOP:
1935ebccf1e3SJoseph Koshy 		__P4SETMASK(64bmu);
1936ebccf1e3SJoseph Koshy 		break;
1937ebccf1e3SJoseph Koshy 	case PMC_EV_P4_128BIT_MMX_UOP:
1938ebccf1e3SJoseph Koshy 		__P4SETMASK(128bmu);
1939ebccf1e3SJoseph Koshy 		break;
1940ebccf1e3SJoseph Koshy 	case PMC_EV_P4_X87_FP_UOP:
1941ebccf1e3SJoseph Koshy 		__P4SETMASK(xfu);
1942ebccf1e3SJoseph Koshy 		break;
1943ebccf1e3SJoseph Koshy 	case PMC_EV_P4_X87_SIMD_MOVES_UOP:
1944ebccf1e3SJoseph Koshy 		__P4SETMASK(xsmu);
1945ebccf1e3SJoseph Koshy 		break;
1946ebccf1e3SJoseph Koshy 	case PMC_EV_P4_GLOBAL_POWER_EVENTS:
1947ebccf1e3SJoseph Koshy 		__P4SETMASK(gpe);
1948ebccf1e3SJoseph Koshy 		break;
1949ebccf1e3SJoseph Koshy 	case PMC_EV_P4_TC_MS_XFER:
1950ebccf1e3SJoseph Koshy 		__P4SETMASK(tmx);
1951ebccf1e3SJoseph Koshy 		break;
1952ebccf1e3SJoseph Koshy 	case PMC_EV_P4_UOP_QUEUE_WRITES:
1953ebccf1e3SJoseph Koshy 		__P4SETMASK(uqw);
1954ebccf1e3SJoseph Koshy 		break;
1955ebccf1e3SJoseph Koshy 	case PMC_EV_P4_RETIRED_MISPRED_BRANCH_TYPE:
1956ebccf1e3SJoseph Koshy 		__P4SETMASK(rmbt);
1957ebccf1e3SJoseph Koshy 		break;
1958ebccf1e3SJoseph Koshy 	case PMC_EV_P4_RETIRED_BRANCH_TYPE:
1959ebccf1e3SJoseph Koshy 		__P4SETMASK(rbt);
1960ebccf1e3SJoseph Koshy 		break;
1961ebccf1e3SJoseph Koshy 	case PMC_EV_P4_RESOURCE_STALL:
1962ebccf1e3SJoseph Koshy 		__P4SETMASK(rs);
1963ebccf1e3SJoseph Koshy 		break;
1964ebccf1e3SJoseph Koshy 	case PMC_EV_P4_WC_BUFFER:
1965ebccf1e3SJoseph Koshy 		__P4SETMASK(wb);
1966ebccf1e3SJoseph Koshy 		break;
1967ebccf1e3SJoseph Koshy 	case PMC_EV_P4_BSQ_ACTIVE_ENTRIES:
1968ebccf1e3SJoseph Koshy 	case PMC_EV_P4_B2B_CYCLES:
1969ebccf1e3SJoseph Koshy 	case PMC_EV_P4_BNR:
1970ebccf1e3SJoseph Koshy 	case PMC_EV_P4_SNOOP:
1971ebccf1e3SJoseph Koshy 	case PMC_EV_P4_RESPONSE:
1972ebccf1e3SJoseph Koshy 		break;
1973ebccf1e3SJoseph Koshy 	case PMC_EV_P4_FRONT_END_EVENT:
1974ebccf1e3SJoseph Koshy 		__P4SETMASK(fee);
1975ebccf1e3SJoseph Koshy 		break;
1976ebccf1e3SJoseph Koshy 	case PMC_EV_P4_EXECUTION_EVENT:
1977ebccf1e3SJoseph Koshy 		__P4SETMASK(ee);
1978ebccf1e3SJoseph Koshy 		break;
1979ebccf1e3SJoseph Koshy 	case PMC_EV_P4_REPLAY_EVENT:
1980ebccf1e3SJoseph Koshy 		__P4SETMASK(re);
1981ebccf1e3SJoseph Koshy 		break;
1982ebccf1e3SJoseph Koshy 	case PMC_EV_P4_INSTR_RETIRED:
1983ebccf1e3SJoseph Koshy 		__P4SETMASK(insret);
1984ebccf1e3SJoseph Koshy 		break;
1985ebccf1e3SJoseph Koshy 	case PMC_EV_P4_UOPS_RETIRED:
1986ebccf1e3SJoseph Koshy 		__P4SETMASK(ur);
1987ebccf1e3SJoseph Koshy 		break;
1988ebccf1e3SJoseph Koshy 	case PMC_EV_P4_UOP_TYPE:
1989ebccf1e3SJoseph Koshy 		__P4SETMASK(ut);
1990ebccf1e3SJoseph Koshy 		break;
1991ebccf1e3SJoseph Koshy 	case PMC_EV_P4_BRANCH_RETIRED:
1992ebccf1e3SJoseph Koshy 		__P4SETMASK(br);
1993ebccf1e3SJoseph Koshy 		break;
1994ebccf1e3SJoseph Koshy 	case PMC_EV_P4_MISPRED_BRANCH_RETIRED:
1995ebccf1e3SJoseph Koshy 		__P4SETMASK(mbr);
1996ebccf1e3SJoseph Koshy 		break;
1997ebccf1e3SJoseph Koshy 	case PMC_EV_P4_X87_ASSIST:
1998ebccf1e3SJoseph Koshy 		__P4SETMASK(xa);
1999ebccf1e3SJoseph Koshy 		break;
2000ebccf1e3SJoseph Koshy 	case PMC_EV_P4_MACHINE_CLEAR:
2001ebccf1e3SJoseph Koshy 		__P4SETMASK(machclr);
2002ebccf1e3SJoseph Koshy 		break;
2003ebccf1e3SJoseph Koshy 	default:
2004aa342b1fSJoseph Koshy 		return (-1);
2005ebccf1e3SJoseph Koshy 	}
2006ebccf1e3SJoseph Koshy 
2007ebccf1e3SJoseph Koshy 	/* process additional flags */
2008ebccf1e3SJoseph Koshy 	while ((p = strsep(&ctrspec, ",")) != NULL) {
2009ebccf1e3SJoseph Koshy 		if (KWPREFIXMATCH(p, P4_KW_ACTIVE)) {
2010ebccf1e3SJoseph Koshy 			q = strchr(p, '=');
2011ebccf1e3SJoseph Koshy 			if (*++q == '\0') /* skip '=' */
2012aa342b1fSJoseph Koshy 				return (-1);
2013ebccf1e3SJoseph Koshy 
2014789140c0SJoseph Koshy 			if (strcasecmp(q, P4_KW_ACTIVE_NONE) == 0)
2015ebccf1e3SJoseph Koshy 				cccractivemask = 0x0;
2016789140c0SJoseph Koshy 			else if (strcasecmp(q, P4_KW_ACTIVE_SINGLE) == 0)
2017ebccf1e3SJoseph Koshy 				cccractivemask = 0x1;
2018789140c0SJoseph Koshy 			else if (strcasecmp(q, P4_KW_ACTIVE_BOTH) == 0)
2019ebccf1e3SJoseph Koshy 				cccractivemask = 0x2;
2020789140c0SJoseph Koshy 			else if (strcasecmp(q, P4_KW_ACTIVE_ANY) == 0)
2021ebccf1e3SJoseph Koshy 				cccractivemask = 0x3;
2022ebccf1e3SJoseph Koshy 			else
2023aa342b1fSJoseph Koshy 				return (-1);
2024ebccf1e3SJoseph Koshy 
2025ebccf1e3SJoseph Koshy 		} else if (KWPREFIXMATCH(p, P4_KW_BUSREQTYPE)) {
2026ebccf1e3SJoseph Koshy 			if (has_busreqtype == 0)
2027aa342b1fSJoseph Koshy 				return (-1);
2028ebccf1e3SJoseph Koshy 
2029ebccf1e3SJoseph Koshy 			q = strchr(p, '=');
2030ebccf1e3SJoseph Koshy 			if (*++q == '\0') /* skip '=' */
2031aa342b1fSJoseph Koshy 				return (-1);
2032ebccf1e3SJoseph Koshy 
2033ebccf1e3SJoseph Koshy 			count = strtol(q, &e, 0);
2034ebccf1e3SJoseph Koshy 			if (e == q || *e != '\0')
2035aa342b1fSJoseph Koshy 				return (-1);
2036ebccf1e3SJoseph Koshy 			evmask = (evmask & ~0x1F) | (count & 0x1F);
2037ebccf1e3SJoseph Koshy 		} else if (KWMATCH(p, P4_KW_CASCADE))
2038ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_CASCADE;
2039ebccf1e3SJoseph Koshy 		else if (KWMATCH(p, P4_KW_EDGE))
2040ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_EDGE;
2041ebccf1e3SJoseph Koshy 		else if (KWMATCH(p, P4_KW_INV))
2042ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_INVERT;
2043ebccf1e3SJoseph Koshy 		else if (KWPREFIXMATCH(p, P4_KW_MASK "=")) {
2044ebccf1e3SJoseph Koshy 			if ((n = pmc_parse_mask(pmask, p, &evmask)) < 0)
2045aa342b1fSJoseph Koshy 				return (-1);
2046ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_QUALIFIER;
2047ebccf1e3SJoseph Koshy 		} else if (KWMATCH(p, P4_KW_OS))
2048ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_SYSTEM;
2049ebccf1e3SJoseph Koshy 		else if (KWMATCH(p, P4_KW_PRECISE))
2050ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_PRECISE;
2051ebccf1e3SJoseph Koshy 		else if (KWPREFIXMATCH(p, P4_KW_TAG "=")) {
2052ebccf1e3SJoseph Koshy 			if (has_tag == 0)
2053aa342b1fSJoseph Koshy 				return (-1);
2054ebccf1e3SJoseph Koshy 
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_TAGGING;
2064f263522aSJoseph Koshy 			pmc_config->pm_md.pm_p4.pm_p4_escrconfig |=
2065ebccf1e3SJoseph Koshy 			    P4_ESCR_TO_TAG_VALUE(count);
2066ebccf1e3SJoseph Koshy 		} else if (KWPREFIXMATCH(p, P4_KW_THRESHOLD "=")) {
2067ebccf1e3SJoseph Koshy 			q = strchr(p, '=');
2068ebccf1e3SJoseph Koshy 			if (*++q == '\0') /* skip '=' */
2069aa342b1fSJoseph Koshy 				return (-1);
2070ebccf1e3SJoseph Koshy 
2071ebccf1e3SJoseph Koshy 			count = strtol(q, &e, 0);
2072ebccf1e3SJoseph Koshy 			if (e == q || *e != '\0')
2073aa342b1fSJoseph Koshy 				return (-1);
2074ebccf1e3SJoseph Koshy 
2075ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_THRESHOLD;
2076f263522aSJoseph Koshy 			pmc_config->pm_md.pm_p4.pm_p4_cccrconfig &=
2077f263522aSJoseph Koshy 			    ~P4_CCCR_THRESHOLD_MASK;
2078f263522aSJoseph Koshy 			pmc_config->pm_md.pm_p4.pm_p4_cccrconfig |=
2079f263522aSJoseph Koshy 			    P4_CCCR_TO_THRESHOLD(count);
2080ebccf1e3SJoseph Koshy 		} else if (KWMATCH(p, P4_KW_USR))
2081ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_USER;
2082ebccf1e3SJoseph Koshy 		else
2083aa342b1fSJoseph Koshy 			return (-1);
2084ebccf1e3SJoseph Koshy 	}
2085ebccf1e3SJoseph Koshy 
2086ebccf1e3SJoseph Koshy 	/* other post processing */
2087ebccf1e3SJoseph Koshy 	if (pe == PMC_EV_P4_IOQ_ALLOCATION ||
2088ebccf1e3SJoseph Koshy 	    pe == PMC_EV_P4_FSB_DATA_ACTIVITY ||
2089ebccf1e3SJoseph Koshy 	    pe == PMC_EV_P4_BSQ_ALLOCATION)
2090ebccf1e3SJoseph Koshy 		pmc_config->pm_caps |= PMC_CAP_EDGE;
2091ebccf1e3SJoseph Koshy 
2092ebccf1e3SJoseph Koshy 	/* fill in thread activity mask */
2093f263522aSJoseph Koshy 	pmc_config->pm_md.pm_p4.pm_p4_cccrconfig |=
2094ebccf1e3SJoseph Koshy 	    P4_CCCR_TO_ACTIVE_THREAD(cccractivemask);
2095ebccf1e3SJoseph Koshy 
2096ebccf1e3SJoseph Koshy 	if (evmask)
2097ebccf1e3SJoseph Koshy 		pmc_config->pm_caps |= PMC_CAP_QUALIFIER;
2098ebccf1e3SJoseph Koshy 
2099ebccf1e3SJoseph Koshy 	switch (pe) {
2100ebccf1e3SJoseph Koshy 	case PMC_EV_P4_FSB_DATA_ACTIVITY:
2101ebccf1e3SJoseph Koshy 		if ((evmask & 0x06) == 0x06 ||
2102ebccf1e3SJoseph Koshy 		    (evmask & 0x18) == 0x18)
2103aa342b1fSJoseph Koshy 			return (-1); /* can't have own+other bits together */
2104ebccf1e3SJoseph Koshy 		if (evmask == 0) /* default:drdy-{drv,own}+dbsy{drv,own} */
2105ebccf1e3SJoseph Koshy 			evmask = 0x1D;
2106ebccf1e3SJoseph Koshy 		break;
2107ebccf1e3SJoseph Koshy 	case PMC_EV_P4_MACHINE_CLEAR:
2108ebccf1e3SJoseph Koshy 		/* only one bit is allowed to be set */
2109ebccf1e3SJoseph Koshy 		if ((evmask & (evmask - 1)) != 0)
2110aa342b1fSJoseph Koshy 			return (-1);
2111ebccf1e3SJoseph Koshy 		if (evmask == 0) {
2112ebccf1e3SJoseph Koshy 			evmask = 0x1;	/* 'CLEAR' */
2113ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_QUALIFIER;
2114ebccf1e3SJoseph Koshy 		}
2115ebccf1e3SJoseph Koshy 		break;
2116ebccf1e3SJoseph Koshy 	default:
2117ebccf1e3SJoseph Koshy 		if (evmask == 0 && pmask) {
2118ebccf1e3SJoseph Koshy 			for (pm = pmask; pm->pm_name; pm++)
2119ebccf1e3SJoseph Koshy 				evmask |= pm->pm_value;
2120ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_QUALIFIER;
2121ebccf1e3SJoseph Koshy 		}
2122ebccf1e3SJoseph Koshy 	}
2123ebccf1e3SJoseph Koshy 
2124f263522aSJoseph Koshy 	pmc_config->pm_md.pm_p4.pm_p4_escrconfig =
2125f263522aSJoseph Koshy 	    P4_ESCR_TO_EVENT_MASK(evmask);
2126ebccf1e3SJoseph Koshy 
2127aa342b1fSJoseph Koshy 	return (0);
2128ebccf1e3SJoseph Koshy }
2129ebccf1e3SJoseph Koshy 
213086a65549SJoseph Koshy #endif
213186a65549SJoseph Koshy 
213286a65549SJoseph Koshy #if defined(__i386__)
213386a65549SJoseph Koshy 
2134ebccf1e3SJoseph Koshy /*
2135f263522aSJoseph Koshy  * Pentium style PMCs
2136f263522aSJoseph Koshy  */
2137f263522aSJoseph Koshy 
2138f263522aSJoseph Koshy static struct pmc_event_alias p5_aliases[] = {
21390b9b757dSJoseph Koshy 	EV_ALIAS("branches",		"p5-taken-branches"),
2140f263522aSJoseph Koshy 	EV_ALIAS("cycles",		"tsc"),
21410b9b757dSJoseph Koshy 	EV_ALIAS("dc-misses",		"p5-data-read-miss-or-write-miss"),
21420b9b757dSJoseph Koshy 	EV_ALIAS("ic-misses",		"p5-code-cache-miss"),
21430b9b757dSJoseph Koshy 	EV_ALIAS("instructions",	"p5-instructions-executed"),
21440b9b757dSJoseph Koshy 	EV_ALIAS("interrupts",		"p5-hardware-interrupts"),
21450b9b757dSJoseph Koshy 	EV_ALIAS("unhalted-cycles",
21460b9b757dSJoseph Koshy 	    "p5-number-of-cycles-not-in-halt-state"),
2147f263522aSJoseph Koshy 	EV_ALIAS(NULL, NULL)
2148f263522aSJoseph Koshy };
2149f263522aSJoseph Koshy 
2150f263522aSJoseph Koshy static int
2151f263522aSJoseph Koshy p5_allocate_pmc(enum pmc_event pe, char *ctrspec,
2152f263522aSJoseph Koshy     struct pmc_op_pmcallocate *pmc_config)
2153f263522aSJoseph Koshy {
2154aa342b1fSJoseph Koshy 	return (-1 || pe || ctrspec || pmc_config); /* shut up gcc */
2155f263522aSJoseph Koshy }
2156f263522aSJoseph Koshy 
2157f263522aSJoseph Koshy /*
2158ebccf1e3SJoseph Koshy  * Pentium Pro style PMCs.  These PMCs are found in Pentium II, Pentium III,
2159ebccf1e3SJoseph Koshy  * and Pentium M CPUs.
2160ebccf1e3SJoseph Koshy  */
2161ebccf1e3SJoseph Koshy 
2162ebccf1e3SJoseph Koshy static struct pmc_event_alias p6_aliases[] = {
2163ebccf1e3SJoseph Koshy 	EV_ALIAS("branches",		"p6-br-inst-retired"),
2164ebccf1e3SJoseph Koshy 	EV_ALIAS("branch-mispredicts",	"p6-br-miss-pred-retired"),
2165ebccf1e3SJoseph Koshy 	EV_ALIAS("cycles",		"tsc"),
2166d56c5d4bSJoseph Koshy 	EV_ALIAS("dc-misses",		"p6-dcu-lines-in"),
216773e2d811SJoseph Koshy 	EV_ALIAS("ic-misses",		"p6-ifu-fetch-miss"),
2168ebccf1e3SJoseph Koshy 	EV_ALIAS("instructions",	"p6-inst-retired"),
2169ebccf1e3SJoseph Koshy 	EV_ALIAS("interrupts",		"p6-hw-int-rx"),
2170177a2f22SJoseph Koshy 	EV_ALIAS("unhalted-cycles",	"p6-cpu-clk-unhalted"),
2171ebccf1e3SJoseph Koshy 	EV_ALIAS(NULL, NULL)
2172ebccf1e3SJoseph Koshy };
2173ebccf1e3SJoseph Koshy 
2174ebccf1e3SJoseph Koshy #define	P6_KW_CMASK	"cmask"
2175ebccf1e3SJoseph Koshy #define	P6_KW_EDGE	"edge"
2176ebccf1e3SJoseph Koshy #define	P6_KW_INV	"inv"
2177ebccf1e3SJoseph Koshy #define	P6_KW_OS	"os"
2178ebccf1e3SJoseph Koshy #define	P6_KW_UMASK	"umask"
2179ebccf1e3SJoseph Koshy #define	P6_KW_USR	"usr"
2180ebccf1e3SJoseph Koshy 
2181ebccf1e3SJoseph Koshy static struct pmc_masks p6_mask_mesi[] = {
2182ebccf1e3SJoseph Koshy 	PMCMASK(m,	0x01),
2183ebccf1e3SJoseph Koshy 	PMCMASK(e,	0x02),
2184ebccf1e3SJoseph Koshy 	PMCMASK(s,	0x04),
2185ebccf1e3SJoseph Koshy 	PMCMASK(i,	0x08),
2186ebccf1e3SJoseph Koshy 	NULLMASK
2187ebccf1e3SJoseph Koshy };
2188ebccf1e3SJoseph Koshy 
2189ebccf1e3SJoseph Koshy static struct pmc_masks p6_mask_mesihw[] = {
2190ebccf1e3SJoseph Koshy 	PMCMASK(m,	0x01),
2191ebccf1e3SJoseph Koshy 	PMCMASK(e,	0x02),
2192ebccf1e3SJoseph Koshy 	PMCMASK(s,	0x04),
2193ebccf1e3SJoseph Koshy 	PMCMASK(i,	0x08),
2194ebccf1e3SJoseph Koshy 	PMCMASK(nonhw,	0x00),
2195ebccf1e3SJoseph Koshy 	PMCMASK(hw,	0x10),
2196ebccf1e3SJoseph Koshy 	PMCMASK(both,	0x30),
2197ebccf1e3SJoseph Koshy 	NULLMASK
2198ebccf1e3SJoseph Koshy };
2199ebccf1e3SJoseph Koshy 
2200ebccf1e3SJoseph Koshy static struct pmc_masks p6_mask_hw[] = {
2201ebccf1e3SJoseph Koshy 	PMCMASK(nonhw,	0x00),
2202ebccf1e3SJoseph Koshy 	PMCMASK(hw,	0x10),
2203ebccf1e3SJoseph Koshy 	PMCMASK(both,	0x30),
2204ebccf1e3SJoseph Koshy 	NULLMASK
2205ebccf1e3SJoseph Koshy };
2206ebccf1e3SJoseph Koshy 
2207ebccf1e3SJoseph Koshy static struct pmc_masks p6_mask_any[] = {
2208ebccf1e3SJoseph Koshy 	PMCMASK(self,	0x00),
2209ebccf1e3SJoseph Koshy 	PMCMASK(any,	0x20),
2210ebccf1e3SJoseph Koshy 	NULLMASK
2211ebccf1e3SJoseph Koshy };
2212ebccf1e3SJoseph Koshy 
2213ebccf1e3SJoseph Koshy static struct pmc_masks p6_mask_ekp[] = {
2214ebccf1e3SJoseph Koshy 	PMCMASK(nta,	0x00),
2215ebccf1e3SJoseph Koshy 	PMCMASK(t1,	0x01),
2216ebccf1e3SJoseph Koshy 	PMCMASK(t2,	0x02),
2217ebccf1e3SJoseph Koshy 	PMCMASK(wos,	0x03),
2218ebccf1e3SJoseph Koshy 	NULLMASK
2219ebccf1e3SJoseph Koshy };
2220ebccf1e3SJoseph Koshy 
2221ebccf1e3SJoseph Koshy static struct pmc_masks p6_mask_pps[] = {
2222ebccf1e3SJoseph Koshy 	PMCMASK(packed-and-scalar, 0x00),
2223ebccf1e3SJoseph Koshy 	PMCMASK(scalar,	0x01),
2224ebccf1e3SJoseph Koshy 	NULLMASK
2225ebccf1e3SJoseph Koshy };
2226ebccf1e3SJoseph Koshy 
2227ebccf1e3SJoseph Koshy static struct pmc_masks p6_mask_mite[] = {
2228ebccf1e3SJoseph Koshy 	PMCMASK(packed-multiply,	 0x01),
2229ebccf1e3SJoseph Koshy 	PMCMASK(packed-shift,		0x02),
2230ebccf1e3SJoseph Koshy 	PMCMASK(pack,			0x04),
2231ebccf1e3SJoseph Koshy 	PMCMASK(unpack,			0x08),
2232ebccf1e3SJoseph Koshy 	PMCMASK(packed-logical,		0x10),
2233ebccf1e3SJoseph Koshy 	PMCMASK(packed-arithmetic,	0x20),
2234ebccf1e3SJoseph Koshy 	NULLMASK
2235ebccf1e3SJoseph Koshy };
2236ebccf1e3SJoseph Koshy 
2237ebccf1e3SJoseph Koshy static struct pmc_masks p6_mask_fmt[] = {
2238ebccf1e3SJoseph Koshy 	PMCMASK(mmxtofp,	0x00),
2239ebccf1e3SJoseph Koshy 	PMCMASK(fptommx,	0x01),
2240ebccf1e3SJoseph Koshy 	NULLMASK
2241ebccf1e3SJoseph Koshy };
2242ebccf1e3SJoseph Koshy 
2243ebccf1e3SJoseph Koshy static struct pmc_masks p6_mask_sr[] = {
2244ebccf1e3SJoseph Koshy 	PMCMASK(es,	0x01),
2245ebccf1e3SJoseph Koshy 	PMCMASK(ds,	0x02),
2246ebccf1e3SJoseph Koshy 	PMCMASK(fs,	0x04),
2247ebccf1e3SJoseph Koshy 	PMCMASK(gs,	0x08),
2248ebccf1e3SJoseph Koshy 	NULLMASK
2249ebccf1e3SJoseph Koshy };
2250ebccf1e3SJoseph Koshy 
2251ebccf1e3SJoseph Koshy static struct pmc_masks p6_mask_eet[] = {
2252ebccf1e3SJoseph Koshy 	PMCMASK(all,	0x00),
2253ebccf1e3SJoseph Koshy 	PMCMASK(freq,	0x02),
2254ebccf1e3SJoseph Koshy 	NULLMASK
2255ebccf1e3SJoseph Koshy };
2256ebccf1e3SJoseph Koshy 
2257ebccf1e3SJoseph Koshy static struct pmc_masks p6_mask_efur[] = {
2258ebccf1e3SJoseph Koshy 	PMCMASK(all,	0x00),
2259ebccf1e3SJoseph Koshy 	PMCMASK(loadop,	0x01),
2260ebccf1e3SJoseph Koshy 	PMCMASK(stdsta,	0x02),
2261ebccf1e3SJoseph Koshy 	NULLMASK
2262ebccf1e3SJoseph Koshy };
2263ebccf1e3SJoseph Koshy 
2264ebccf1e3SJoseph Koshy static struct pmc_masks p6_mask_essir[] = {
2265ebccf1e3SJoseph Koshy 	PMCMASK(sse-packed-single,	0x00),
2266ebccf1e3SJoseph Koshy 	PMCMASK(sse-packed-single-scalar-single, 0x01),
2267ebccf1e3SJoseph Koshy 	PMCMASK(sse2-packed-double,	0x02),
2268ebccf1e3SJoseph Koshy 	PMCMASK(sse2-scalar-double,	0x03),
2269ebccf1e3SJoseph Koshy 	NULLMASK
2270ebccf1e3SJoseph Koshy };
2271ebccf1e3SJoseph Koshy 
2272ebccf1e3SJoseph Koshy static struct pmc_masks p6_mask_esscir[] = {
2273ebccf1e3SJoseph Koshy 	PMCMASK(sse-packed-single,	0x00),
2274ebccf1e3SJoseph Koshy 	PMCMASK(sse-scalar-single,	0x01),
2275ebccf1e3SJoseph Koshy 	PMCMASK(sse2-packed-double,	0x02),
2276ebccf1e3SJoseph Koshy 	PMCMASK(sse2-scalar-double,	0x03),
2277ebccf1e3SJoseph Koshy 	NULLMASK
2278ebccf1e3SJoseph Koshy };
2279ebccf1e3SJoseph Koshy 
2280ebccf1e3SJoseph Koshy /* P6 event parser */
2281ebccf1e3SJoseph Koshy static int
2282ebccf1e3SJoseph Koshy p6_allocate_pmc(enum pmc_event pe, char *ctrspec,
2283ebccf1e3SJoseph Koshy     struct pmc_op_pmcallocate *pmc_config)
2284ebccf1e3SJoseph Koshy {
2285ebccf1e3SJoseph Koshy 	char *e, *p, *q;
22861e862e5aSFabien Thomas 	uint64_t evmask;
2287ebccf1e3SJoseph Koshy 	int count, n;
2288ebccf1e3SJoseph Koshy 	const struct pmc_masks *pm, *pmask;
2289ebccf1e3SJoseph Koshy 
2290789140c0SJoseph Koshy 	pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE);
2291f263522aSJoseph Koshy 	pmc_config->pm_md.pm_ppro.pm_ppro_config = 0;
2292ebccf1e3SJoseph Koshy 
2293ebccf1e3SJoseph Koshy 	evmask = 0;
2294ebccf1e3SJoseph Koshy 
2295ebccf1e3SJoseph Koshy #define	P6MASKSET(M)	pmask = p6_mask_ ## M
2296ebccf1e3SJoseph Koshy 
2297ebccf1e3SJoseph Koshy 	switch(pe) {
2298ebccf1e3SJoseph Koshy 	case PMC_EV_P6_L2_IFETCH:	P6MASKSET(mesi); break;
2299ebccf1e3SJoseph Koshy 	case PMC_EV_P6_L2_LD:		P6MASKSET(mesi); break;
2300ebccf1e3SJoseph Koshy 	case PMC_EV_P6_L2_ST:		P6MASKSET(mesi); break;
2301ebccf1e3SJoseph Koshy 	case PMC_EV_P6_L2_RQSTS:	P6MASKSET(mesi); break;
2302ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_DRDY_CLOCKS:
2303ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_LOCK_CLOCKS:
2304ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_BRD:
2305ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_RFO:
2306ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRANS_WB:
2307ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_IFETCH:
2308ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_INVAL:
2309ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_PWR:
2310ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRANS_P:
2311ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRANS_IO:
2312ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_DEF:
2313ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_BURST:
2314ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_ANY:
2315ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_MEM:
2316ebccf1e3SJoseph Koshy 		P6MASKSET(any);	break;
2317ebccf1e3SJoseph Koshy 	case PMC_EV_P6_EMON_KNI_PREF_DISPATCHED:
2318ebccf1e3SJoseph Koshy 	case PMC_EV_P6_EMON_KNI_PREF_MISS:
2319ebccf1e3SJoseph Koshy 		P6MASKSET(ekp); break;
2320ebccf1e3SJoseph Koshy 	case PMC_EV_P6_EMON_KNI_INST_RETIRED:
2321ebccf1e3SJoseph Koshy 	case PMC_EV_P6_EMON_KNI_COMP_INST_RET:
2322ebccf1e3SJoseph Koshy 		P6MASKSET(pps);	break;
2323ebccf1e3SJoseph Koshy 	case PMC_EV_P6_MMX_INSTR_TYPE_EXEC:
2324ebccf1e3SJoseph Koshy 		P6MASKSET(mite); break;
2325ebccf1e3SJoseph Koshy 	case PMC_EV_P6_FP_MMX_TRANS:
2326ebccf1e3SJoseph Koshy 		P6MASKSET(fmt);	break;
2327ebccf1e3SJoseph Koshy 	case PMC_EV_P6_SEG_RENAME_STALLS:
2328ebccf1e3SJoseph Koshy 	case PMC_EV_P6_SEG_REG_RENAMES:
2329ebccf1e3SJoseph Koshy 		P6MASKSET(sr);	break;
2330ebccf1e3SJoseph Koshy 	case PMC_EV_P6_EMON_EST_TRANS:
2331ebccf1e3SJoseph Koshy 		P6MASKSET(eet);	break;
2332ebccf1e3SJoseph Koshy 	case PMC_EV_P6_EMON_FUSED_UOPS_RET:
2333ebccf1e3SJoseph Koshy 		P6MASKSET(efur); break;
2334ebccf1e3SJoseph Koshy 	case PMC_EV_P6_EMON_SSE_SSE2_INST_RETIRED:
2335ebccf1e3SJoseph Koshy 		P6MASKSET(essir); break;
2336ebccf1e3SJoseph Koshy 	case PMC_EV_P6_EMON_SSE_SSE2_COMP_INST_RETIRED:
2337ebccf1e3SJoseph Koshy 		P6MASKSET(esscir); break;
2338ebccf1e3SJoseph Koshy 	default:
2339ebccf1e3SJoseph Koshy 		pmask = NULL;
2340ebccf1e3SJoseph Koshy 		break;
2341ebccf1e3SJoseph Koshy 	}
2342ebccf1e3SJoseph Koshy 
2343ebccf1e3SJoseph Koshy 	/* Pentium M PMCs have a few events with different semantics */
2344ebccf1e3SJoseph Koshy 	if (cpu_info.pm_cputype == PMC_CPU_INTEL_PM) {
2345ebccf1e3SJoseph Koshy 		if (pe == PMC_EV_P6_L2_LD ||
2346ebccf1e3SJoseph Koshy 		    pe == PMC_EV_P6_L2_LINES_IN ||
2347ebccf1e3SJoseph Koshy 		    pe == PMC_EV_P6_L2_LINES_OUT)
2348ebccf1e3SJoseph Koshy 			P6MASKSET(mesihw);
2349ebccf1e3SJoseph Koshy 		else if (pe == PMC_EV_P6_L2_M_LINES_OUTM)
2350ebccf1e3SJoseph Koshy 			P6MASKSET(hw);
2351ebccf1e3SJoseph Koshy 	}
2352ebccf1e3SJoseph Koshy 
2353ebccf1e3SJoseph Koshy 	/* Parse additional modifiers if present */
2354ebccf1e3SJoseph Koshy 	while ((p = strsep(&ctrspec, ",")) != NULL) {
2355ebccf1e3SJoseph Koshy 		if (KWPREFIXMATCH(p, P6_KW_CMASK "=")) {
2356ebccf1e3SJoseph Koshy 			q = strchr(p, '=');
2357ebccf1e3SJoseph Koshy 			if (*++q == '\0') /* skip '=' */
2358aa342b1fSJoseph Koshy 				return (-1);
2359ebccf1e3SJoseph Koshy 			count = strtol(q, &e, 0);
2360ebccf1e3SJoseph Koshy 			if (e == q || *e != '\0')
2361aa342b1fSJoseph Koshy 				return (-1);
2362ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_THRESHOLD;
2363f263522aSJoseph Koshy 			pmc_config->pm_md.pm_ppro.pm_ppro_config |=
2364f263522aSJoseph Koshy 			    P6_EVSEL_TO_CMASK(count);
2365ebccf1e3SJoseph Koshy 		} else if (KWMATCH(p, P6_KW_EDGE)) {
2366ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_EDGE;
2367ebccf1e3SJoseph Koshy 		} else if (KWMATCH(p, P6_KW_INV)) {
2368ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_INVERT;
2369ebccf1e3SJoseph Koshy 		} else if (KWMATCH(p, P6_KW_OS)) {
2370ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_SYSTEM;
2371ebccf1e3SJoseph Koshy 		} else if (KWPREFIXMATCH(p, P6_KW_UMASK "=")) {
2372ebccf1e3SJoseph Koshy 			evmask = 0;
2373ebccf1e3SJoseph Koshy 			if ((n = pmc_parse_mask(pmask, p, &evmask)) < 0)
2374aa342b1fSJoseph Koshy 				return (-1);
2375ebccf1e3SJoseph Koshy 			if ((pe == PMC_EV_P6_BUS_DRDY_CLOCKS ||
2376ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_BUS_LOCK_CLOCKS ||
2377ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_BUS_TRAN_BRD ||
2378ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_BUS_TRAN_RFO ||
2379ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_BUS_TRAN_IFETCH ||
2380ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_BUS_TRAN_INVAL ||
2381ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_BUS_TRAN_PWR ||
2382ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_BUS_TRAN_DEF ||
2383ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_BUS_TRAN_BURST ||
2384ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_BUS_TRAN_ANY ||
2385ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_BUS_TRAN_MEM ||
2386ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_BUS_TRANS_IO ||
2387ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_BUS_TRANS_P ||
2388ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_BUS_TRANS_WB ||
2389ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_EMON_EST_TRANS ||
2390ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_EMON_FUSED_UOPS_RET ||
2391ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_EMON_KNI_COMP_INST_RET ||
2392ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_EMON_KNI_INST_RETIRED ||
2393ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_EMON_KNI_PREF_DISPATCHED ||
2394ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_EMON_KNI_PREF_MISS ||
2395ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_EMON_SSE_SSE2_COMP_INST_RETIRED ||
2396ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_EMON_SSE_SSE2_INST_RETIRED ||
2397ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_FP_MMX_TRANS)
2398aa342b1fSJoseph Koshy 			    && (n > 1))	/* Only one mask keyword is allowed. */
2399aa342b1fSJoseph Koshy 				return (-1);
2400ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_QUALIFIER;
2401ebccf1e3SJoseph Koshy 		} else if (KWMATCH(p, P6_KW_USR)) {
2402ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_USER;
2403ebccf1e3SJoseph Koshy 		} else
2404aa342b1fSJoseph Koshy 			return (-1);
2405ebccf1e3SJoseph Koshy 	}
2406ebccf1e3SJoseph Koshy 
2407ebccf1e3SJoseph Koshy 	/* post processing */
2408ebccf1e3SJoseph Koshy 	switch (pe) {
2409ebccf1e3SJoseph Koshy 
2410ebccf1e3SJoseph Koshy 		/*
2411ebccf1e3SJoseph Koshy 		 * The following events default to an evmask of 0
2412ebccf1e3SJoseph Koshy 		 */
2413ebccf1e3SJoseph Koshy 
2414ebccf1e3SJoseph Koshy 		/* default => 'self' */
2415ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_DRDY_CLOCKS:
2416ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_LOCK_CLOCKS:
2417ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_BRD:
2418ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_RFO:
2419ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRANS_WB:
2420ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_IFETCH:
2421ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_INVAL:
2422ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_PWR:
2423ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRANS_P:
2424ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRANS_IO:
2425ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_DEF:
2426ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_BURST:
2427ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_ANY:
2428ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_MEM:
2429ebccf1e3SJoseph Koshy 
2430ebccf1e3SJoseph Koshy 		/* default => 'nta' */
2431ebccf1e3SJoseph Koshy 	case PMC_EV_P6_EMON_KNI_PREF_DISPATCHED:
2432ebccf1e3SJoseph Koshy 	case PMC_EV_P6_EMON_KNI_PREF_MISS:
2433ebccf1e3SJoseph Koshy 
2434ebccf1e3SJoseph Koshy 		/* default => 'packed and scalar' */
2435ebccf1e3SJoseph Koshy 	case PMC_EV_P6_EMON_KNI_INST_RETIRED:
2436ebccf1e3SJoseph Koshy 	case PMC_EV_P6_EMON_KNI_COMP_INST_RET:
2437ebccf1e3SJoseph Koshy 
2438ebccf1e3SJoseph Koshy 		/* default => 'mmx to fp transitions' */
2439ebccf1e3SJoseph Koshy 	case PMC_EV_P6_FP_MMX_TRANS:
2440ebccf1e3SJoseph Koshy 
2441ebccf1e3SJoseph Koshy 		/* default => 'SSE Packed Single' */
2442ebccf1e3SJoseph Koshy 	case PMC_EV_P6_EMON_SSE_SSE2_INST_RETIRED:
2443ebccf1e3SJoseph Koshy 	case PMC_EV_P6_EMON_SSE_SSE2_COMP_INST_RETIRED:
2444ebccf1e3SJoseph Koshy 
2445ebccf1e3SJoseph Koshy 		/* default => 'all fused micro-ops' */
2446ebccf1e3SJoseph Koshy 	case PMC_EV_P6_EMON_FUSED_UOPS_RET:
2447ebccf1e3SJoseph Koshy 
2448ebccf1e3SJoseph Koshy 		/* default => 'all transitions' */
2449ebccf1e3SJoseph Koshy 	case PMC_EV_P6_EMON_EST_TRANS:
2450ebccf1e3SJoseph Koshy 		break;
2451ebccf1e3SJoseph Koshy 
2452ebccf1e3SJoseph Koshy 	case PMC_EV_P6_MMX_UOPS_EXEC:
2453ebccf1e3SJoseph Koshy 		evmask = 0x0F;		/* only value allowed */
2454ebccf1e3SJoseph Koshy 		break;
2455ebccf1e3SJoseph Koshy 
2456ebccf1e3SJoseph Koshy 	default:
2457ebccf1e3SJoseph Koshy 		/*
2458ebccf1e3SJoseph Koshy 		 * For all other events, set the default event mask
2459ebccf1e3SJoseph Koshy 		 * to a logical OR of all the allowed event mask bits.
2460ebccf1e3SJoseph Koshy 		 */
2461ebccf1e3SJoseph Koshy 		if (evmask == 0 && pmask) {
2462ebccf1e3SJoseph Koshy 			for (pm = pmask; pm->pm_name; pm++)
2463ebccf1e3SJoseph Koshy 				evmask |= pm->pm_value;
2464ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_QUALIFIER;
2465ebccf1e3SJoseph Koshy 		}
2466ebccf1e3SJoseph Koshy 
2467ebccf1e3SJoseph Koshy 		break;
2468ebccf1e3SJoseph Koshy 	}
2469ebccf1e3SJoseph Koshy 
2470ebccf1e3SJoseph Koshy 	if (pmc_config->pm_caps & PMC_CAP_QUALIFIER)
2471f263522aSJoseph Koshy 		pmc_config->pm_md.pm_ppro.pm_ppro_config |=
2472f263522aSJoseph Koshy 		    P6_EVSEL_TO_UMASK(evmask);
2473ebccf1e3SJoseph Koshy 
2474aa342b1fSJoseph Koshy 	return (0);
2475ebccf1e3SJoseph Koshy }
2476ebccf1e3SJoseph Koshy 
2477ebccf1e3SJoseph Koshy #endif
2478ebccf1e3SJoseph Koshy 
2479789140c0SJoseph Koshy #if	defined(__i386__) || defined(__amd64__)
2480789140c0SJoseph Koshy static int
2481789140c0SJoseph Koshy tsc_allocate_pmc(enum pmc_event pe, char *ctrspec,
2482789140c0SJoseph Koshy     struct pmc_op_pmcallocate *pmc_config)
2483789140c0SJoseph Koshy {
2484789140c0SJoseph Koshy 	if (pe != PMC_EV_TSC_TSC)
2485789140c0SJoseph Koshy 		return (-1);
2486789140c0SJoseph Koshy 
2487789140c0SJoseph Koshy 	/* TSC events must be unqualified. */
2488789140c0SJoseph Koshy 	if (ctrspec && *ctrspec != '\0')
2489789140c0SJoseph Koshy 		return (-1);
2490789140c0SJoseph Koshy 
2491789140c0SJoseph Koshy 	pmc_config->pm_md.pm_amd.pm_amd_config = 0;
2492789140c0SJoseph Koshy 	pmc_config->pm_caps |= PMC_CAP_READ;
2493789140c0SJoseph Koshy 
2494789140c0SJoseph Koshy 	return (0);
2495789140c0SJoseph Koshy }
2496789140c0SJoseph Koshy #endif
2497789140c0SJoseph Koshy 
2498f5f9340bSFabien Thomas static struct pmc_event_alias generic_aliases[] = {
2499f5f9340bSFabien Thomas 	EV_ALIAS("instructions",		"SOFT-CLOCK.HARD"),
2500f5f9340bSFabien Thomas 	EV_ALIAS(NULL, NULL)
2501f5f9340bSFabien Thomas };
2502f5f9340bSFabien Thomas 
2503f5f9340bSFabien Thomas static int
2504f5f9340bSFabien Thomas soft_allocate_pmc(enum pmc_event pe, char *ctrspec,
2505f5f9340bSFabien Thomas     struct pmc_op_pmcallocate *pmc_config)
2506f5f9340bSFabien Thomas {
2507f5f9340bSFabien Thomas 	(void)ctrspec;
2508f5f9340bSFabien Thomas 	(void)pmc_config;
2509f5f9340bSFabien Thomas 
2510f0bbe9aaSDimitry Andric 	if ((int)pe < PMC_EV_SOFT_FIRST || (int)pe > PMC_EV_SOFT_LAST)
2511f5f9340bSFabien Thomas 		return (-1);
2512f5f9340bSFabien Thomas 
2513f5f9340bSFabien Thomas 	pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE);
2514f5f9340bSFabien Thomas 	return (0);
2515f5f9340bSFabien Thomas }
2516f5f9340bSFabien Thomas 
25176411d14dSRuslan Bukin #if	defined(__arm__)
25180ce207d2SRui Paulo #if	defined(__XSCALE__)
25190ce207d2SRui Paulo 
25200ce207d2SRui Paulo static struct pmc_event_alias xscale_aliases[] = {
25210ce207d2SRui Paulo 	EV_ALIAS("branches",		"BRANCH_RETIRED"),
25220ce207d2SRui Paulo 	EV_ALIAS("branch-mispredicts",	"BRANCH_MISPRED"),
25230ce207d2SRui Paulo 	EV_ALIAS("dc-misses",		"DC_MISS"),
25240ce207d2SRui Paulo 	EV_ALIAS("ic-misses",		"IC_MISS"),
25250ce207d2SRui Paulo 	EV_ALIAS("instructions",	"INSTR_RETIRED"),
25260ce207d2SRui Paulo 	EV_ALIAS(NULL, NULL)
25270ce207d2SRui Paulo };
25280ce207d2SRui Paulo static int
25290ce207d2SRui Paulo xscale_allocate_pmc(enum pmc_event pe, char *ctrspec __unused,
25300ce207d2SRui Paulo     struct pmc_op_pmcallocate *pmc_config __unused)
25310ce207d2SRui Paulo {
25320ce207d2SRui Paulo 	switch (pe) {
25330ce207d2SRui Paulo 	default:
25340ce207d2SRui Paulo 		break;
25350ce207d2SRui Paulo 	}
25360ce207d2SRui Paulo 
25370ce207d2SRui Paulo 	return (0);
25380ce207d2SRui Paulo }
25390ce207d2SRui Paulo #endif
25400ce207d2SRui Paulo 
25413e0bfdd8SRuslan Bukin static struct pmc_event_alias cortex_a8_aliases[] = {
25426411d14dSRuslan Bukin 	EV_ALIAS("dc-misses",		"L1_DCACHE_REFILL"),
25436411d14dSRuslan Bukin 	EV_ALIAS("ic-misses",		"L1_ICACHE_REFILL"),
25446411d14dSRuslan Bukin 	EV_ALIAS("instructions",	"INSTR_EXECUTED"),
25456411d14dSRuslan Bukin 	EV_ALIAS(NULL, NULL)
25466411d14dSRuslan Bukin };
25473e0bfdd8SRuslan Bukin 
25483e0bfdd8SRuslan Bukin static struct pmc_event_alias cortex_a9_aliases[] = {
25493e0bfdd8SRuslan Bukin 	EV_ALIAS("dc-misses",		"L1_DCACHE_REFILL"),
25503e0bfdd8SRuslan Bukin 	EV_ALIAS("ic-misses",		"L1_ICACHE_REFILL"),
25513e0bfdd8SRuslan Bukin 	EV_ALIAS("instructions",	"INSTR_EXECUTED"),
25523e0bfdd8SRuslan Bukin 	EV_ALIAS(NULL, NULL)
25533e0bfdd8SRuslan Bukin };
25543e0bfdd8SRuslan Bukin 
25556411d14dSRuslan Bukin static int
25566411d14dSRuslan Bukin armv7_allocate_pmc(enum pmc_event pe, char *ctrspec __unused,
25576411d14dSRuslan Bukin     struct pmc_op_pmcallocate *pmc_config __unused)
25586411d14dSRuslan Bukin {
25596411d14dSRuslan Bukin 	switch (pe) {
25606411d14dSRuslan Bukin 	default:
25616411d14dSRuslan Bukin 		break;
25626411d14dSRuslan Bukin 	}
25636411d14dSRuslan Bukin 
25646411d14dSRuslan Bukin 	return (0);
25656411d14dSRuslan Bukin }
25666411d14dSRuslan Bukin #endif
25676411d14dSRuslan Bukin 
2568bc88bb2bSRuslan Bukin #if	defined(__aarch64__)
2569bc88bb2bSRuslan Bukin static struct pmc_event_alias cortex_a53_aliases[] = {
2570bc88bb2bSRuslan Bukin 	EV_ALIAS(NULL, NULL)
2571bc88bb2bSRuslan Bukin };
2572bc88bb2bSRuslan Bukin static struct pmc_event_alias cortex_a57_aliases[] = {
2573bc88bb2bSRuslan Bukin 	EV_ALIAS(NULL, NULL)
2574bc88bb2bSRuslan Bukin };
2575bc88bb2bSRuslan Bukin static int
2576bc88bb2bSRuslan Bukin arm64_allocate_pmc(enum pmc_event pe, char *ctrspec __unused,
2577bc88bb2bSRuslan Bukin     struct pmc_op_pmcallocate *pmc_config __unused)
2578bc88bb2bSRuslan Bukin {
2579bc88bb2bSRuslan Bukin 	switch (pe) {
2580bc88bb2bSRuslan Bukin 	default:
2581bc88bb2bSRuslan Bukin 		break;
2582bc88bb2bSRuslan Bukin 	}
2583bc88bb2bSRuslan Bukin 
2584bc88bb2bSRuslan Bukin 	return (0);
2585bc88bb2bSRuslan Bukin }
2586bc88bb2bSRuslan Bukin #endif
2587bc88bb2bSRuslan Bukin 
2588660df75eSGeorge V. Neville-Neil #if defined(__mips__)
2589660df75eSGeorge V. Neville-Neil 
2590660df75eSGeorge V. Neville-Neil static struct pmc_event_alias mips24k_aliases[] = {
2591660df75eSGeorge V. Neville-Neil 	EV_ALIAS("instructions",	"INSTR_EXECUTED"),
2592660df75eSGeorge V. Neville-Neil 	EV_ALIAS("branches",		"BRANCH_COMPLETED"),
2593660df75eSGeorge V. Neville-Neil 	EV_ALIAS("branch-mispredicts",	"BRANCH_MISPRED"),
2594660df75eSGeorge V. Neville-Neil 	EV_ALIAS(NULL, NULL)
2595660df75eSGeorge V. Neville-Neil };
2596660df75eSGeorge V. Neville-Neil 
2597f6e6460dSAdrian Chadd static struct pmc_event_alias mips74k_aliases[] = {
2598f6e6460dSAdrian Chadd 	EV_ALIAS("instructions",	"INSTR_EXECUTED"),
2599f6e6460dSAdrian Chadd 	EV_ALIAS("branches",		"BRANCH_INSNS"),
2600f6e6460dSAdrian Chadd 	EV_ALIAS("branch-mispredicts",	"MISPREDICTED_BRANCH_INSNS"),
2601f6e6460dSAdrian Chadd 	EV_ALIAS(NULL, NULL)
2602f6e6460dSAdrian Chadd };
2603f6e6460dSAdrian Chadd 
2604c2657f80SOleksandr Tymoshenko static struct pmc_event_alias octeon_aliases[] = {
2605c2657f80SOleksandr Tymoshenko 	EV_ALIAS("instructions",	"RET"),
2606c2657f80SOleksandr Tymoshenko 	EV_ALIAS("branches",		"BR"),
2607c2657f80SOleksandr Tymoshenko 	EV_ALIAS("branch-mispredicts",	"BRMIS"),
2608c2657f80SOleksandr Tymoshenko 	EV_ALIAS(NULL, NULL)
2609c2657f80SOleksandr Tymoshenko };
2610c2657f80SOleksandr Tymoshenko 
26112827d3e1SOleksandr Tymoshenko #define	MIPS_KW_OS		"os"
26122827d3e1SOleksandr Tymoshenko #define	MIPS_KW_USR		"usr"
26132827d3e1SOleksandr Tymoshenko #define	MIPS_KW_ANYTHREAD	"anythread"
2614660df75eSGeorge V. Neville-Neil 
2615660df75eSGeorge V. Neville-Neil static int
26162827d3e1SOleksandr Tymoshenko mips_allocate_pmc(enum pmc_event pe, char *ctrspec __unused,
2617660df75eSGeorge V. Neville-Neil 		  struct pmc_op_pmcallocate *pmc_config __unused)
2618660df75eSGeorge V. Neville-Neil {
2619660df75eSGeorge V. Neville-Neil 	char *p;
2620660df75eSGeorge V. Neville-Neil 
2621660df75eSGeorge V. Neville-Neil 	(void) pe;
2622660df75eSGeorge V. Neville-Neil 
2623660df75eSGeorge V. Neville-Neil 	pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE);
2624660df75eSGeorge V. Neville-Neil 
2625660df75eSGeorge V. Neville-Neil 	while ((p = strsep(&ctrspec, ",")) != NULL) {
26262827d3e1SOleksandr Tymoshenko 		if (KWMATCH(p, MIPS_KW_OS))
2627660df75eSGeorge V. Neville-Neil 			pmc_config->pm_caps |= PMC_CAP_SYSTEM;
26282827d3e1SOleksandr Tymoshenko 		else if (KWMATCH(p, MIPS_KW_USR))
2629660df75eSGeorge V. Neville-Neil 			pmc_config->pm_caps |= PMC_CAP_USER;
26302827d3e1SOleksandr Tymoshenko 		else if (KWMATCH(p, MIPS_KW_ANYTHREAD))
2631660df75eSGeorge V. Neville-Neil 			pmc_config->pm_caps |= (PMC_CAP_USER | PMC_CAP_SYSTEM);
2632660df75eSGeorge V. Neville-Neil 		else
2633660df75eSGeorge V. Neville-Neil 			return (-1);
2634660df75eSGeorge V. Neville-Neil 	}
2635660df75eSGeorge V. Neville-Neil 
2636660df75eSGeorge V. Neville-Neil 	return (0);
2637660df75eSGeorge V. Neville-Neil }
26382827d3e1SOleksandr Tymoshenko 
2639660df75eSGeorge V. Neville-Neil #endif /* __mips__ */
2640660df75eSGeorge V. Neville-Neil 
26417b25dccaSJustin Hibbits #if defined(__powerpc__)
26427b25dccaSJustin Hibbits 
26437b25dccaSJustin Hibbits static struct pmc_event_alias ppc7450_aliases[] = {
26447b25dccaSJustin Hibbits 	EV_ALIAS("instructions",	"INSTR_COMPLETED"),
26457b25dccaSJustin Hibbits 	EV_ALIAS("branches",		"BRANCHES_COMPLETED"),
26467b25dccaSJustin Hibbits 	EV_ALIAS("branch-mispredicts",	"MISPREDICTED_BRANCHES"),
26477b25dccaSJustin Hibbits 	EV_ALIAS(NULL, NULL)
26487b25dccaSJustin Hibbits };
26497b25dccaSJustin Hibbits 
2650169dd953SJustin Hibbits static struct pmc_event_alias ppc970_aliases[] = {
2651169dd953SJustin Hibbits 	EV_ALIAS("instructions", "INSTR_COMPLETED"),
2652169dd953SJustin Hibbits 	EV_ALIAS("cycles",       "CYCLES"),
2653169dd953SJustin Hibbits 	EV_ALIAS(NULL, NULL)
2654169dd953SJustin Hibbits };
2655169dd953SJustin Hibbits 
2656a7452468SJustin Hibbits static struct pmc_event_alias e500_aliases[] = {
2657a7452468SJustin Hibbits 	EV_ALIAS("instructions", "INSTR_COMPLETED"),
2658a7452468SJustin Hibbits 	EV_ALIAS("cycles",       "CYCLES"),
2659a7452468SJustin Hibbits 	EV_ALIAS(NULL, NULL)
2660a7452468SJustin Hibbits };
2661a7452468SJustin Hibbits 
2662169dd953SJustin Hibbits #define	POWERPC_KW_OS		"os"
2663169dd953SJustin Hibbits #define	POWERPC_KW_USR		"usr"
2664169dd953SJustin Hibbits #define	POWERPC_KW_ANYTHREAD	"anythread"
26657b25dccaSJustin Hibbits 
26667b25dccaSJustin Hibbits static int
2667169dd953SJustin Hibbits powerpc_allocate_pmc(enum pmc_event pe, char *ctrspec __unused,
26687b25dccaSJustin Hibbits 		     struct pmc_op_pmcallocate *pmc_config __unused)
26697b25dccaSJustin Hibbits {
26707b25dccaSJustin Hibbits 	char *p;
26717b25dccaSJustin Hibbits 
26727b25dccaSJustin Hibbits 	(void) pe;
26737b25dccaSJustin Hibbits 
26747b25dccaSJustin Hibbits 	pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE);
26757b25dccaSJustin Hibbits 
26767b25dccaSJustin Hibbits 	while ((p = strsep(&ctrspec, ",")) != NULL) {
2677169dd953SJustin Hibbits 		if (KWMATCH(p, POWERPC_KW_OS))
26787b25dccaSJustin Hibbits 			pmc_config->pm_caps |= PMC_CAP_SYSTEM;
2679169dd953SJustin Hibbits 		else if (KWMATCH(p, POWERPC_KW_USR))
26807b25dccaSJustin Hibbits 			pmc_config->pm_caps |= PMC_CAP_USER;
2681169dd953SJustin Hibbits 		else if (KWMATCH(p, POWERPC_KW_ANYTHREAD))
26827b25dccaSJustin Hibbits 			pmc_config->pm_caps |= (PMC_CAP_USER | PMC_CAP_SYSTEM);
26837b25dccaSJustin Hibbits 		else
26847b25dccaSJustin Hibbits 			return (-1);
26857b25dccaSJustin Hibbits 	}
26867b25dccaSJustin Hibbits 
26877b25dccaSJustin Hibbits 	return (0);
26887b25dccaSJustin Hibbits }
2689169dd953SJustin Hibbits 
26907b25dccaSJustin Hibbits #endif /* __powerpc__ */
26917b25dccaSJustin Hibbits 
2692660df75eSGeorge V. Neville-Neil 
2693789140c0SJoseph Koshy /*
2694789140c0SJoseph Koshy  * Match an event name `name' with its canonical form.
2695789140c0SJoseph Koshy  *
26960cfab8ddSJoseph Koshy  * Matches are case insensitive and spaces, periods, underscores and
26970cfab8ddSJoseph Koshy  * hyphen characters are considered to match each other.
2698789140c0SJoseph Koshy  *
2699789140c0SJoseph Koshy  * Returns 1 for a match, 0 otherwise.
2700789140c0SJoseph Koshy  */
2701789140c0SJoseph Koshy 
2702789140c0SJoseph Koshy static int
2703789140c0SJoseph Koshy pmc_match_event_name(const char *name, const char *canonicalname)
2704789140c0SJoseph Koshy {
2705789140c0SJoseph Koshy 	int cc, nc;
2706789140c0SJoseph Koshy 	const unsigned char *c, *n;
2707789140c0SJoseph Koshy 
2708789140c0SJoseph Koshy 	c = (const unsigned char *) canonicalname;
2709789140c0SJoseph Koshy 	n = (const unsigned char *) name;
2710789140c0SJoseph Koshy 
2711789140c0SJoseph Koshy 	for (; (nc = *n) && (cc = *c); n++, c++) {
2712789140c0SJoseph Koshy 
27130cfab8ddSJoseph Koshy 		if ((nc == ' ' || nc == '_' || nc == '-' || nc == '.') &&
27140cfab8ddSJoseph Koshy 		    (cc == ' ' || cc == '_' || cc == '-' || cc == '.'))
2715789140c0SJoseph Koshy 			continue;
2716789140c0SJoseph Koshy 
27170cfab8ddSJoseph Koshy 		if (toupper(nc) == toupper(cc))
2718789140c0SJoseph Koshy 			continue;
2719789140c0SJoseph Koshy 
27200cfab8ddSJoseph Koshy 
2721789140c0SJoseph Koshy 		return (0);
2722789140c0SJoseph Koshy 	}
2723789140c0SJoseph Koshy 
2724789140c0SJoseph Koshy 	if (*n == '\0' && *c == '\0')
2725789140c0SJoseph Koshy 		return (1);
2726789140c0SJoseph Koshy 
2727789140c0SJoseph Koshy 	return (0);
2728789140c0SJoseph Koshy }
2729789140c0SJoseph Koshy 
2730789140c0SJoseph Koshy /*
2731789140c0SJoseph Koshy  * Match an event name against all the event named supported by a
2732789140c0SJoseph Koshy  * PMC class.
2733789140c0SJoseph Koshy  *
2734789140c0SJoseph Koshy  * Returns an event descriptor pointer on match or NULL otherwise.
2735789140c0SJoseph Koshy  */
2736789140c0SJoseph Koshy static const struct pmc_event_descr *
2737789140c0SJoseph Koshy pmc_match_event_class(const char *name,
2738789140c0SJoseph Koshy     const struct pmc_class_descr *pcd)
2739789140c0SJoseph Koshy {
2740789140c0SJoseph Koshy 	size_t n;
2741789140c0SJoseph Koshy 	const struct pmc_event_descr *ev;
2742789140c0SJoseph Koshy 
2743789140c0SJoseph Koshy 	ev = pcd->pm_evc_event_table;
2744789140c0SJoseph Koshy 	for (n = 0; n < pcd->pm_evc_event_table_size; n++, ev++)
2745789140c0SJoseph Koshy 		if (pmc_match_event_name(name, ev->pm_ev_name))
2746789140c0SJoseph Koshy 			return (ev);
2747789140c0SJoseph Koshy 
2748789140c0SJoseph Koshy 	return (NULL);
2749789140c0SJoseph Koshy }
2750789140c0SJoseph Koshy 
2751789140c0SJoseph Koshy static int
2752789140c0SJoseph Koshy pmc_mdep_is_compatible_class(enum pmc_class pc)
2753789140c0SJoseph Koshy {
2754789140c0SJoseph Koshy 	size_t n;
2755789140c0SJoseph Koshy 
2756789140c0SJoseph Koshy 	for (n = 0; n < pmc_mdep_class_list_size; n++)
2757789140c0SJoseph Koshy 		if (pmc_mdep_class_list[n] == pc)
2758789140c0SJoseph Koshy 			return (1);
2759789140c0SJoseph Koshy 	return (0);
2760789140c0SJoseph Koshy }
2761789140c0SJoseph Koshy 
2762ebccf1e3SJoseph Koshy /*
2763ebccf1e3SJoseph Koshy  * API entry points
2764ebccf1e3SJoseph Koshy  */
2765ebccf1e3SJoseph Koshy 
2766ebccf1e3SJoseph Koshy int
2767ebccf1e3SJoseph Koshy pmc_allocate(const char *ctrspec, enum pmc_mode mode,
2768ebccf1e3SJoseph Koshy     uint32_t flags, int cpu, pmc_id_t *pmcid)
2769ebccf1e3SJoseph Koshy {
2770789140c0SJoseph Koshy 	size_t n;
2771ebccf1e3SJoseph Koshy 	int retval;
2772ebccf1e3SJoseph Koshy 	char *r, *spec_copy;
2773ebccf1e3SJoseph Koshy 	const char *ctrname;
2774789140c0SJoseph Koshy 	const struct pmc_event_descr *ev;
2775789140c0SJoseph Koshy 	const struct pmc_event_alias *alias;
2776ebccf1e3SJoseph Koshy 	struct pmc_op_pmcallocate pmc_config;
2777789140c0SJoseph Koshy 	const struct pmc_class_descr *pcd;
2778ebccf1e3SJoseph Koshy 
2779ebccf1e3SJoseph Koshy 	spec_copy = NULL;
2780ebccf1e3SJoseph Koshy 	retval    = -1;
2781ebccf1e3SJoseph Koshy 
2782ebccf1e3SJoseph Koshy 	if (mode != PMC_MODE_SS && mode != PMC_MODE_TS &&
2783ebccf1e3SJoseph Koshy 	    mode != PMC_MODE_SC && mode != PMC_MODE_TC) {
2784ebccf1e3SJoseph Koshy 		errno = EINVAL;
2785ebccf1e3SJoseph Koshy 		goto out;
2786ebccf1e3SJoseph Koshy 	}
2787ebccf1e3SJoseph Koshy 
2788ebccf1e3SJoseph Koshy 	/* replace an event alias with the canonical event specifier */
2789ebccf1e3SJoseph Koshy 	if (pmc_mdep_event_aliases)
2790789140c0SJoseph Koshy 		for (alias = pmc_mdep_event_aliases; alias->pm_alias; alias++)
2791789140c0SJoseph Koshy 			if (!strcasecmp(ctrspec, alias->pm_alias)) {
2792789140c0SJoseph Koshy 				spec_copy = strdup(alias->pm_spec);
2793ebccf1e3SJoseph Koshy 				break;
2794ebccf1e3SJoseph Koshy 			}
2795ebccf1e3SJoseph Koshy 
2796ebccf1e3SJoseph Koshy 	if (spec_copy == NULL)
2797ebccf1e3SJoseph Koshy 		spec_copy = strdup(ctrspec);
2798ebccf1e3SJoseph Koshy 
2799ebccf1e3SJoseph Koshy 	r = spec_copy;
2800ebccf1e3SJoseph Koshy 	ctrname = strsep(&r, ",");
2801ebccf1e3SJoseph Koshy 
2802789140c0SJoseph Koshy 	/*
2803789140c0SJoseph Koshy 	 * If a explicit class prefix was given by the user, restrict the
2804789140c0SJoseph Koshy 	 * search for the event to the specified PMC class.
2805789140c0SJoseph Koshy 	 */
2806789140c0SJoseph Koshy 	ev = NULL;
28070cfab8ddSJoseph Koshy 	for (n = 0; n < PMC_CLASS_TABLE_SIZE; n++) {
28080cfab8ddSJoseph Koshy 		pcd = pmc_class_table[n];
2809789140c0SJoseph Koshy 		if (pmc_mdep_is_compatible_class(pcd->pm_evc_class) &&
2810789140c0SJoseph Koshy 		    strncasecmp(ctrname, pcd->pm_evc_name,
2811789140c0SJoseph Koshy 				pcd->pm_evc_name_size) == 0) {
2812789140c0SJoseph Koshy 			if ((ev = pmc_match_event_class(ctrname +
2813789140c0SJoseph Koshy 			    pcd->pm_evc_name_size, pcd)) == NULL) {
2814789140c0SJoseph Koshy 				errno = EINVAL;
2815789140c0SJoseph Koshy 				goto out;
2816789140c0SJoseph Koshy 			}
2817ebccf1e3SJoseph Koshy 			break;
2818789140c0SJoseph Koshy 		}
2819789140c0SJoseph Koshy 	}
2820ebccf1e3SJoseph Koshy 
2821789140c0SJoseph Koshy 	/*
2822789140c0SJoseph Koshy 	 * Otherwise, search for this event in all compatible PMC
2823789140c0SJoseph Koshy 	 * classes.
2824789140c0SJoseph Koshy 	 */
28250cfab8ddSJoseph Koshy 	for (n = 0; ev == NULL && n < PMC_CLASS_TABLE_SIZE; n++) {
28260cfab8ddSJoseph Koshy 		pcd = pmc_class_table[n];
2827789140c0SJoseph Koshy 		if (pmc_mdep_is_compatible_class(pcd->pm_evc_class))
2828789140c0SJoseph Koshy 			ev = pmc_match_event_class(ctrname, pcd);
2829789140c0SJoseph Koshy 	}
2830789140c0SJoseph Koshy 
2831789140c0SJoseph Koshy 	if (ev == NULL) {
2832ebccf1e3SJoseph Koshy 		errno = EINVAL;
2833ebccf1e3SJoseph Koshy 		goto out;
2834ebccf1e3SJoseph Koshy 	}
2835ebccf1e3SJoseph Koshy 
2836ebccf1e3SJoseph Koshy 	bzero(&pmc_config, sizeof(pmc_config));
2837789140c0SJoseph Koshy 	pmc_config.pm_ev    = ev->pm_ev_code;
2838789140c0SJoseph Koshy 	pmc_config.pm_class = pcd->pm_evc_class;
2839ebccf1e3SJoseph Koshy 	pmc_config.pm_cpu   = cpu;
2840ebccf1e3SJoseph Koshy 	pmc_config.pm_mode  = mode;
2841ebccf1e3SJoseph Koshy 	pmc_config.pm_flags = flags;
2842ebccf1e3SJoseph Koshy 
2843ebccf1e3SJoseph Koshy 	if (PMC_IS_SAMPLING_MODE(mode))
2844ebccf1e3SJoseph Koshy 		pmc_config.pm_caps |= PMC_CAP_INTERRUPT;
2845ebccf1e3SJoseph Koshy 
2846789140c0SJoseph Koshy  	if (pcd->pm_evc_allocate_pmc(ev->pm_ev_code, r, &pmc_config) < 0) {
2847ebccf1e3SJoseph Koshy 		errno = EINVAL;
2848ebccf1e3SJoseph Koshy 		goto out;
2849ebccf1e3SJoseph Koshy 	}
2850ebccf1e3SJoseph Koshy 
2851ebccf1e3SJoseph Koshy 	if (PMC_CALL(PMCALLOCATE, &pmc_config) < 0)
2852ebccf1e3SJoseph Koshy 		goto out;
2853ebccf1e3SJoseph Koshy 
2854ebccf1e3SJoseph Koshy 	*pmcid = pmc_config.pm_pmcid;
2855ebccf1e3SJoseph Koshy 
2856ebccf1e3SJoseph Koshy 	retval = 0;
2857ebccf1e3SJoseph Koshy 
2858ebccf1e3SJoseph Koshy  out:
2859ebccf1e3SJoseph Koshy 	if (spec_copy)
2860ebccf1e3SJoseph Koshy 		free(spec_copy);
2861ebccf1e3SJoseph Koshy 
2862aa342b1fSJoseph Koshy 	return (retval);
2863ebccf1e3SJoseph Koshy }
2864ebccf1e3SJoseph Koshy 
2865ebccf1e3SJoseph Koshy int
2866ebccf1e3SJoseph Koshy pmc_attach(pmc_id_t pmc, pid_t pid)
2867ebccf1e3SJoseph Koshy {
2868ebccf1e3SJoseph Koshy 	struct pmc_op_pmcattach pmc_attach_args;
2869ebccf1e3SJoseph Koshy 
2870ebccf1e3SJoseph Koshy 	pmc_attach_args.pm_pmc = pmc;
2871ebccf1e3SJoseph Koshy 	pmc_attach_args.pm_pid = pid;
2872ebccf1e3SJoseph Koshy 
2873aa342b1fSJoseph Koshy 	return (PMC_CALL(PMCATTACH, &pmc_attach_args));
2874ebccf1e3SJoseph Koshy }
2875ebccf1e3SJoseph Koshy 
2876ebccf1e3SJoseph Koshy int
2877c5153e19SJoseph Koshy pmc_capabilities(pmc_id_t pmcid, uint32_t *caps)
2878c5153e19SJoseph Koshy {
2879c5153e19SJoseph Koshy 	unsigned int i;
2880c5153e19SJoseph Koshy 	enum pmc_class cl;
2881c5153e19SJoseph Koshy 
2882c5153e19SJoseph Koshy 	cl = PMC_ID_TO_CLASS(pmcid);
2883c5153e19SJoseph Koshy 	for (i = 0; i < cpu_info.pm_nclass; i++)
2884c5153e19SJoseph Koshy 		if (cpu_info.pm_classes[i].pm_class == cl) {
2885c5153e19SJoseph Koshy 			*caps = cpu_info.pm_classes[i].pm_caps;
2886aa342b1fSJoseph Koshy 			return (0);
2887c5153e19SJoseph Koshy 		}
2888484202faSJoseph Koshy 	errno = EINVAL;
2889484202faSJoseph Koshy 	return (-1);
2890c5153e19SJoseph Koshy }
2891c5153e19SJoseph Koshy 
2892f263522aSJoseph Koshy int
2893f263522aSJoseph Koshy pmc_configure_logfile(int fd)
2894ebccf1e3SJoseph Koshy {
2895f263522aSJoseph Koshy 	struct pmc_op_configurelog cla;
2896f263522aSJoseph Koshy 
2897f263522aSJoseph Koshy 	cla.pm_logfd = fd;
2898f263522aSJoseph Koshy 	if (PMC_CALL(CONFIGURELOG, &cla) < 0)
2899aa342b1fSJoseph Koshy 		return (-1);
2900aa342b1fSJoseph Koshy 	return (0);
2901ebccf1e3SJoseph Koshy }
2902ebccf1e3SJoseph Koshy 
2903f263522aSJoseph Koshy int
2904f263522aSJoseph Koshy pmc_cpuinfo(const struct pmc_cpuinfo **pci)
2905ebccf1e3SJoseph Koshy {
2906f263522aSJoseph Koshy 	if (pmc_syscall == -1) {
2907f263522aSJoseph Koshy 		errno = ENXIO;
2908aa342b1fSJoseph Koshy 		return (-1);
2909ebccf1e3SJoseph Koshy 	}
2910ebccf1e3SJoseph Koshy 
29111455fcd3SJoseph Koshy 	*pci = &cpu_info;
2912aa342b1fSJoseph Koshy 	return (0);
2913ebccf1e3SJoseph Koshy }
2914ebccf1e3SJoseph Koshy 
2915f263522aSJoseph Koshy int
2916f263522aSJoseph Koshy pmc_detach(pmc_id_t pmc, pid_t pid)
2917ebccf1e3SJoseph Koshy {
2918f263522aSJoseph Koshy 	struct pmc_op_pmcattach pmc_detach_args;
2919ebccf1e3SJoseph Koshy 
2920f263522aSJoseph Koshy 	pmc_detach_args.pm_pmc = pmc;
2921f263522aSJoseph Koshy 	pmc_detach_args.pm_pid = pid;
2922aa342b1fSJoseph Koshy 	return (PMC_CALL(PMCDETACH, &pmc_detach_args));
2923ebccf1e3SJoseph Koshy }
2924ebccf1e3SJoseph Koshy 
2925f263522aSJoseph Koshy int
2926f263522aSJoseph Koshy pmc_disable(int cpu, int pmc)
2927ebccf1e3SJoseph Koshy {
2928f263522aSJoseph Koshy 	struct pmc_op_pmcadmin ssa;
2929ebccf1e3SJoseph Koshy 
2930f263522aSJoseph Koshy 	ssa.pm_cpu = cpu;
2931f263522aSJoseph Koshy 	ssa.pm_pmc = pmc;
2932f263522aSJoseph Koshy 	ssa.pm_state = PMC_STATE_DISABLED;
2933aa342b1fSJoseph Koshy 	return (PMC_CALL(PMCADMIN, &ssa));
2934ebccf1e3SJoseph Koshy }
2935ebccf1e3SJoseph Koshy 
2936f263522aSJoseph Koshy int
2937f263522aSJoseph Koshy pmc_enable(int cpu, int pmc)
2938ebccf1e3SJoseph Koshy {
2939f263522aSJoseph Koshy 	struct pmc_op_pmcadmin ssa;
2940ebccf1e3SJoseph Koshy 
2941f263522aSJoseph Koshy 	ssa.pm_cpu = cpu;
2942f263522aSJoseph Koshy 	ssa.pm_pmc = pmc;
2943f263522aSJoseph Koshy 	ssa.pm_state = PMC_STATE_FREE;
2944aa342b1fSJoseph Koshy 	return (PMC_CALL(PMCADMIN, &ssa));
2945ebccf1e3SJoseph Koshy }
2946ebccf1e3SJoseph Koshy 
2947ebccf1e3SJoseph Koshy /*
2948ebccf1e3SJoseph Koshy  * Return a list of events known to a given PMC class.  'cl' is the
2949ebccf1e3SJoseph Koshy  * PMC class identifier, 'eventnames' is the returned list of 'const
2950ebccf1e3SJoseph Koshy  * char *' pointers pointing to the names of the events. 'nevents' is
2951ebccf1e3SJoseph Koshy  * the number of event name pointers returned.
2952ebccf1e3SJoseph Koshy  *
2953ebccf1e3SJoseph Koshy  * The space for 'eventnames' is allocated using malloc(3).  The caller
2954ebccf1e3SJoseph Koshy  * is responsible for freeing this space when done.
2955ebccf1e3SJoseph Koshy  */
2956ebccf1e3SJoseph Koshy int
2957ebccf1e3SJoseph Koshy pmc_event_names_of_class(enum pmc_class cl, const char ***eventnames,
2958ebccf1e3SJoseph Koshy     int *nevents)
2959ebccf1e3SJoseph Koshy {
2960ebccf1e3SJoseph Koshy 	int count;
2961ebccf1e3SJoseph Koshy 	const char **names;
2962ebccf1e3SJoseph Koshy 	const struct pmc_event_descr *ev;
2963ebccf1e3SJoseph Koshy 
2964ebccf1e3SJoseph Koshy 	switch (cl)
2965ebccf1e3SJoseph Koshy 	{
29660cfab8ddSJoseph Koshy 	case PMC_CLASS_IAF:
29670cfab8ddSJoseph Koshy 		ev = iaf_event_table;
29680cfab8ddSJoseph Koshy 		count = PMC_EVENT_TABLE_SIZE(iaf);
29690cfab8ddSJoseph Koshy 		break;
29700cfab8ddSJoseph Koshy 	case PMC_CLASS_IAP:
29710cfab8ddSJoseph Koshy 		/*
29720cfab8ddSJoseph Koshy 		 * Return the most appropriate set of event name
29730cfab8ddSJoseph Koshy 		 * spellings for the current CPU.
29740cfab8ddSJoseph Koshy 		 */
29750cfab8ddSJoseph Koshy 		switch (cpu_info.pm_cputype) {
29760cfab8ddSJoseph Koshy 		default:
29770cfab8ddSJoseph Koshy 		case PMC_CPU_INTEL_ATOM:
29780cfab8ddSJoseph Koshy 			ev = atom_event_table;
29790cfab8ddSJoseph Koshy 			count = PMC_EVENT_TABLE_SIZE(atom);
29800cfab8ddSJoseph Koshy 			break;
2981e8f021a3SHiren Panchasara 		case PMC_CPU_INTEL_ATOM_SILVERMONT:
2982e8f021a3SHiren Panchasara 			ev = atom_silvermont_event_table;
2983e8f021a3SHiren Panchasara 			count = PMC_EVENT_TABLE_SIZE(atom_silvermont);
2984e8f021a3SHiren Panchasara 			break;
29850cfab8ddSJoseph Koshy 		case PMC_CPU_INTEL_CORE:
29860cfab8ddSJoseph Koshy 			ev = core_event_table;
29870cfab8ddSJoseph Koshy 			count = PMC_EVENT_TABLE_SIZE(core);
29880cfab8ddSJoseph Koshy 			break;
29890cfab8ddSJoseph Koshy 		case PMC_CPU_INTEL_CORE2:
2990b4d091f3SJoseph Koshy 		case PMC_CPU_INTEL_CORE2EXTREME:
29910cfab8ddSJoseph Koshy 			ev = core2_event_table;
29920cfab8ddSJoseph Koshy 			count = PMC_EVENT_TABLE_SIZE(core2);
29930cfab8ddSJoseph Koshy 			break;
2994597979c4SJeff Roberson 		case PMC_CPU_INTEL_COREI7:
2995597979c4SJeff Roberson 			ev = corei7_event_table;
2996597979c4SJeff Roberson 			count = PMC_EVENT_TABLE_SIZE(corei7);
2997597979c4SJeff Roberson 			break;
299849fe48abSKonstantin Belousov 		case PMC_CPU_INTEL_NEHALEM_EX:
299949fe48abSKonstantin Belousov 			ev = nehalem_ex_event_table;
300049fe48abSKonstantin Belousov 			count = PMC_EVENT_TABLE_SIZE(nehalem_ex);
300149fe48abSKonstantin Belousov 			break;
3002cc0c1555SSean Bruno 		case PMC_CPU_INTEL_HASWELL:
3003cc0c1555SSean Bruno 			ev = haswell_event_table;
3004cc0c1555SSean Bruno 			count = PMC_EVENT_TABLE_SIZE(haswell);
3005cc0c1555SSean Bruno 			break;
3006d95b3509SRandall Stewart 		case PMC_CPU_INTEL_HASWELL_XEON:
3007d95b3509SRandall Stewart 			ev = haswell_xeon_event_table;
3008d95b3509SRandall Stewart 			count = PMC_EVENT_TABLE_SIZE(haswell_xeon);
3009d95b3509SRandall Stewart 			break;
3010f19bae41SRandall Stewart 		case PMC_CPU_INTEL_BROADWELL:
3011f19bae41SRandall Stewart 			ev = broadwell_event_table;
3012f19bae41SRandall Stewart 			count = PMC_EVENT_TABLE_SIZE(broadwell);
3013f19bae41SRandall Stewart 			break;
3014f19bae41SRandall Stewart 		case PMC_CPU_INTEL_BROADWELL_XEON:
3015f19bae41SRandall Stewart 			ev = broadwell_xeon_event_table;
3016f19bae41SRandall Stewart 			count = PMC_EVENT_TABLE_SIZE(broadwell_xeon);
3017f19bae41SRandall Stewart 			break;
3018f19bae41SRandall Stewart 		case PMC_CPU_INTEL_SKYLAKE:
3019f19bae41SRandall Stewart 			ev = skylake_event_table;
3020f19bae41SRandall Stewart 			count = PMC_EVENT_TABLE_SIZE(skylake);
3021f19bae41SRandall Stewart 			break;
3022b99b705dSKonstantin Belousov 		case PMC_CPU_INTEL_SKYLAKE_XEON:
3023b99b705dSKonstantin Belousov 			ev = skylake_xeon_event_table;
3024b99b705dSKonstantin Belousov 			count = PMC_EVENT_TABLE_SIZE(skylake_xeon);
3025b99b705dSKonstantin Belousov 			break;
30261e862e5aSFabien Thomas 		case PMC_CPU_INTEL_IVYBRIDGE:
30271e862e5aSFabien Thomas 			ev = ivybridge_event_table;
30281e862e5aSFabien Thomas 			count = PMC_EVENT_TABLE_SIZE(ivybridge);
30291e862e5aSFabien Thomas 			break;
30303f929d8cSSean Bruno 		case PMC_CPU_INTEL_IVYBRIDGE_XEON:
30313f929d8cSSean Bruno 			ev = ivybridge_xeon_event_table;
30323f929d8cSSean Bruno 			count = PMC_EVENT_TABLE_SIZE(ivybridge_xeon);
30333f929d8cSSean Bruno 			break;
303478d763a2SDavide Italiano 		case PMC_CPU_INTEL_SANDYBRIDGE:
303578d763a2SDavide Italiano 			ev = sandybridge_event_table;
303678d763a2SDavide Italiano 			count = PMC_EVENT_TABLE_SIZE(sandybridge);
303778d763a2SDavide Italiano 			break;
3038fabe02f5SSean Bruno 		case PMC_CPU_INTEL_SANDYBRIDGE_XEON:
3039fabe02f5SSean Bruno 			ev = sandybridge_xeon_event_table;
3040fabe02f5SSean Bruno 			count = PMC_EVENT_TABLE_SIZE(sandybridge_xeon);
3041fabe02f5SSean Bruno 			break;
30421fa7f10bSFabien Thomas 		case PMC_CPU_INTEL_WESTMERE:
30431fa7f10bSFabien Thomas 			ev = westmere_event_table;
30441fa7f10bSFabien Thomas 			count = PMC_EVENT_TABLE_SIZE(westmere);
30451fa7f10bSFabien Thomas 			break;
304649fe48abSKonstantin Belousov 		case PMC_CPU_INTEL_WESTMERE_EX:
304749fe48abSKonstantin Belousov 			ev = westmere_ex_event_table;
304849fe48abSKonstantin Belousov 			count = PMC_EVENT_TABLE_SIZE(westmere_ex);
304949fe48abSKonstantin Belousov 			break;
30501fa7f10bSFabien Thomas 		}
30511fa7f10bSFabien Thomas 		break;
30521fa7f10bSFabien Thomas 	case PMC_CLASS_UCF:
30531fa7f10bSFabien Thomas 		ev = ucf_event_table;
30541fa7f10bSFabien Thomas 		count = PMC_EVENT_TABLE_SIZE(ucf);
30551fa7f10bSFabien Thomas 		break;
30561fa7f10bSFabien Thomas 	case PMC_CLASS_UCP:
30571fa7f10bSFabien Thomas 		/*
30581fa7f10bSFabien Thomas 		 * Return the most appropriate set of event name
30591fa7f10bSFabien Thomas 		 * spellings for the current CPU.
30601fa7f10bSFabien Thomas 		 */
30611fa7f10bSFabien Thomas 		switch (cpu_info.pm_cputype) {
30621fa7f10bSFabien Thomas 		default:
30631fa7f10bSFabien Thomas 		case PMC_CPU_INTEL_COREI7:
30641fa7f10bSFabien Thomas 			ev = corei7uc_event_table;
30651fa7f10bSFabien Thomas 			count = PMC_EVENT_TABLE_SIZE(corei7uc);
30661fa7f10bSFabien Thomas 			break;
3067cc0c1555SSean Bruno 		case PMC_CPU_INTEL_HASWELL:
3068cc0c1555SSean Bruno 			ev = haswelluc_event_table;
3069cc0c1555SSean Bruno 			count = PMC_EVENT_TABLE_SIZE(haswelluc);
3070cc0c1555SSean Bruno 			break;
3071f19bae41SRandall Stewart 		case PMC_CPU_INTEL_BROADWELL:
3072f19bae41SRandall Stewart 			ev = broadwelluc_event_table;
3073f19bae41SRandall Stewart 			count = PMC_EVENT_TABLE_SIZE(broadwelluc);
3074f19bae41SRandall Stewart 			break;
307578d763a2SDavide Italiano 		case PMC_CPU_INTEL_SANDYBRIDGE:
307678d763a2SDavide Italiano 			ev = sandybridgeuc_event_table;
307778d763a2SDavide Italiano 			count = PMC_EVENT_TABLE_SIZE(sandybridgeuc);
307878d763a2SDavide Italiano 			break;
30791fa7f10bSFabien Thomas 		case PMC_CPU_INTEL_WESTMERE:
30801fa7f10bSFabien Thomas 			ev = westmereuc_event_table;
30811fa7f10bSFabien Thomas 			count = PMC_EVENT_TABLE_SIZE(westmereuc);
30821fa7f10bSFabien Thomas 			break;
30830cfab8ddSJoseph Koshy 		}
30840cfab8ddSJoseph Koshy 		break;
3085ebccf1e3SJoseph Koshy 	case PMC_CLASS_TSC:
3086789140c0SJoseph Koshy 		ev = tsc_event_table;
3087789140c0SJoseph Koshy 		count = PMC_EVENT_TABLE_SIZE(tsc);
3088ebccf1e3SJoseph Koshy 		break;
3089ebccf1e3SJoseph Koshy 	case PMC_CLASS_K7:
3090789140c0SJoseph Koshy 		ev = k7_event_table;
3091789140c0SJoseph Koshy 		count = PMC_EVENT_TABLE_SIZE(k7);
3092ebccf1e3SJoseph Koshy 		break;
3093ebccf1e3SJoseph Koshy 	case PMC_CLASS_K8:
3094789140c0SJoseph Koshy 		ev = k8_event_table;
3095789140c0SJoseph Koshy 		count = PMC_EVENT_TABLE_SIZE(k8);
3096ebccf1e3SJoseph Koshy 		break;
3097ebccf1e3SJoseph Koshy 	case PMC_CLASS_P4:
3098789140c0SJoseph Koshy 		ev = p4_event_table;
3099789140c0SJoseph Koshy 		count = PMC_EVENT_TABLE_SIZE(p4);
3100789140c0SJoseph Koshy 		break;
3101789140c0SJoseph Koshy 	case PMC_CLASS_P5:
3102789140c0SJoseph Koshy 		ev = p5_event_table;
3103789140c0SJoseph Koshy 		count = PMC_EVENT_TABLE_SIZE(p5);
3104789140c0SJoseph Koshy 		break;
3105789140c0SJoseph Koshy 	case PMC_CLASS_P6:
3106789140c0SJoseph Koshy 		ev = p6_event_table;
3107789140c0SJoseph Koshy 		count = PMC_EVENT_TABLE_SIZE(p6);
3108ebccf1e3SJoseph Koshy 		break;
31090ce207d2SRui Paulo 	case PMC_CLASS_XSCALE:
31100ce207d2SRui Paulo 		ev = xscale_event_table;
31110ce207d2SRui Paulo 		count = PMC_EVENT_TABLE_SIZE(xscale);
31120ce207d2SRui Paulo 		break;
31136411d14dSRuslan Bukin 	case PMC_CLASS_ARMV7:
31143e0bfdd8SRuslan Bukin 		switch (cpu_info.pm_cputype) {
31153e0bfdd8SRuslan Bukin 		default:
31163e0bfdd8SRuslan Bukin 		case PMC_CPU_ARMV7_CORTEX_A8:
31173e0bfdd8SRuslan Bukin 			ev = cortex_a8_event_table;
31183e0bfdd8SRuslan Bukin 			count = PMC_EVENT_TABLE_SIZE(cortex_a8);
31193e0bfdd8SRuslan Bukin 			break;
31203e0bfdd8SRuslan Bukin 		case PMC_CPU_ARMV7_CORTEX_A9:
31213e0bfdd8SRuslan Bukin 			ev = cortex_a9_event_table;
31223e0bfdd8SRuslan Bukin 			count = PMC_EVENT_TABLE_SIZE(cortex_a9);
31233e0bfdd8SRuslan Bukin 			break;
31243e0bfdd8SRuslan Bukin 		}
31256411d14dSRuslan Bukin 		break;
3126bc88bb2bSRuslan Bukin 	case PMC_CLASS_ARMV8:
3127bc88bb2bSRuslan Bukin 		switch (cpu_info.pm_cputype) {
3128bc88bb2bSRuslan Bukin 		default:
3129bc88bb2bSRuslan Bukin 		case PMC_CPU_ARMV8_CORTEX_A53:
3130bc88bb2bSRuslan Bukin 			ev = cortex_a53_event_table;
3131bc88bb2bSRuslan Bukin 			count = PMC_EVENT_TABLE_SIZE(cortex_a53);
3132bc88bb2bSRuslan Bukin 			break;
3133bc88bb2bSRuslan Bukin 		case PMC_CPU_ARMV8_CORTEX_A57:
3134bc88bb2bSRuslan Bukin 			ev = cortex_a57_event_table;
3135bc88bb2bSRuslan Bukin 			count = PMC_EVENT_TABLE_SIZE(cortex_a57);
3136bc88bb2bSRuslan Bukin 			break;
3137bc88bb2bSRuslan Bukin 		}
3138bc88bb2bSRuslan Bukin 		break;
3139660df75eSGeorge V. Neville-Neil 	case PMC_CLASS_MIPS24K:
3140660df75eSGeorge V. Neville-Neil 		ev = mips24k_event_table;
3141660df75eSGeorge V. Neville-Neil 		count = PMC_EVENT_TABLE_SIZE(mips24k);
3142660df75eSGeorge V. Neville-Neil 		break;
3143f6e6460dSAdrian Chadd 	case PMC_CLASS_MIPS74K:
3144f6e6460dSAdrian Chadd 		ev = mips74k_event_table;
3145f6e6460dSAdrian Chadd 		count = PMC_EVENT_TABLE_SIZE(mips74k);
3146f6e6460dSAdrian Chadd 		break;
3147c2657f80SOleksandr Tymoshenko 	case PMC_CLASS_OCTEON:
3148c2657f80SOleksandr Tymoshenko 		ev = octeon_event_table;
3149c2657f80SOleksandr Tymoshenko 		count = PMC_EVENT_TABLE_SIZE(octeon);
3150c2657f80SOleksandr Tymoshenko 		break;
31517b25dccaSJustin Hibbits 	case PMC_CLASS_PPC7450:
31527b25dccaSJustin Hibbits 		ev = ppc7450_event_table;
31537b25dccaSJustin Hibbits 		count = PMC_EVENT_TABLE_SIZE(ppc7450);
31547b25dccaSJustin Hibbits 		break;
3155169dd953SJustin Hibbits 	case PMC_CLASS_PPC970:
3156169dd953SJustin Hibbits 		ev = ppc970_event_table;
3157169dd953SJustin Hibbits 		count = PMC_EVENT_TABLE_SIZE(ppc970);
3158169dd953SJustin Hibbits 		break;
3159a7452468SJustin Hibbits 	case PMC_CLASS_E500:
3160a7452468SJustin Hibbits 		ev = e500_event_table;
3161a7452468SJustin Hibbits 		count = PMC_EVENT_TABLE_SIZE(e500);
3162a7452468SJustin Hibbits 		break;
3163f5f9340bSFabien Thomas 	case PMC_CLASS_SOFT:
3164f5f9340bSFabien Thomas 		ev = soft_event_table;
3165f5f9340bSFabien Thomas 		count = soft_event_info.pm_nevent;
3166f5f9340bSFabien Thomas 		break;
3167ebccf1e3SJoseph Koshy 	default:
3168ebccf1e3SJoseph Koshy 		errno = EINVAL;
3169aa342b1fSJoseph Koshy 		return (-1);
3170ebccf1e3SJoseph Koshy 	}
3171ebccf1e3SJoseph Koshy 
3172ebccf1e3SJoseph Koshy 	if ((names = malloc(count * sizeof(const char *))) == NULL)
3173aa342b1fSJoseph Koshy 		return (-1);
3174ebccf1e3SJoseph Koshy 
3175ebccf1e3SJoseph Koshy 	*eventnames = names;
3176ebccf1e3SJoseph Koshy 	*nevents = count;
3177ebccf1e3SJoseph Koshy 
3178ebccf1e3SJoseph Koshy 	for (;count--; ev++, names++)
3179ebccf1e3SJoseph Koshy 		*names = ev->pm_ev_name;
3180f5f9340bSFabien Thomas 
3181aa342b1fSJoseph Koshy 	return (0);
3182ebccf1e3SJoseph Koshy }
3183ebccf1e3SJoseph Koshy 
3184f263522aSJoseph Koshy int
3185f263522aSJoseph Koshy pmc_flush_logfile(void)
3186f263522aSJoseph Koshy {
3187aa342b1fSJoseph Koshy 	return (PMC_CALL(FLUSHLOG,0));
3188f263522aSJoseph Koshy }
3189ebccf1e3SJoseph Koshy 
3190ebccf1e3SJoseph Koshy int
3191dceed24aSFabien Thomas pmc_close_logfile(void)
3192dceed24aSFabien Thomas {
3193dceed24aSFabien Thomas 	return (PMC_CALL(CLOSELOG,0));
3194dceed24aSFabien Thomas }
3195dceed24aSFabien Thomas 
3196dceed24aSFabien Thomas int
3197f263522aSJoseph Koshy pmc_get_driver_stats(struct pmc_driverstats *ds)
3198ebccf1e3SJoseph Koshy {
3199f263522aSJoseph Koshy 	struct pmc_op_getdriverstats gms;
3200f263522aSJoseph Koshy 
3201f263522aSJoseph Koshy 	if (PMC_CALL(GETDRIVERSTATS, &gms) < 0)
3202aa342b1fSJoseph Koshy 		return (-1);
3203f263522aSJoseph Koshy 
3204f263522aSJoseph Koshy 	/* copy out fields in the current userland<->library interface */
3205f263522aSJoseph Koshy 	ds->pm_intr_ignored    = gms.pm_intr_ignored;
3206f263522aSJoseph Koshy 	ds->pm_intr_processed  = gms.pm_intr_processed;
3207f263522aSJoseph Koshy 	ds->pm_intr_bufferfull = gms.pm_intr_bufferfull;
3208f263522aSJoseph Koshy 	ds->pm_syscalls        = gms.pm_syscalls;
3209f263522aSJoseph Koshy 	ds->pm_syscall_errors  = gms.pm_syscall_errors;
3210f263522aSJoseph Koshy 	ds->pm_buffer_requests = gms.pm_buffer_requests;
3211f263522aSJoseph Koshy 	ds->pm_buffer_requests_failed = gms.pm_buffer_requests_failed;
3212f263522aSJoseph Koshy 	ds->pm_log_sweeps      = gms.pm_log_sweeps;
3213aa342b1fSJoseph Koshy 	return (0);
3214f263522aSJoseph Koshy }
3215f263522aSJoseph Koshy 
3216f263522aSJoseph Koshy int
3217f263522aSJoseph Koshy pmc_get_msr(pmc_id_t pmc, uint32_t *msr)
3218f263522aSJoseph Koshy {
3219f263522aSJoseph Koshy 	struct pmc_op_getmsr gm;
3220ebccf1e3SJoseph Koshy 
3221ebccf1e3SJoseph Koshy 	gm.pm_pmcid = pmc;
3222f263522aSJoseph Koshy 	if (PMC_CALL(PMCGETMSR, &gm) < 0)
3223aa342b1fSJoseph Koshy 		return (-1);
3224ebccf1e3SJoseph Koshy 	*msr = gm.pm_msr;
3225aa342b1fSJoseph Koshy 	return (0);
3226ebccf1e3SJoseph Koshy }
3227ebccf1e3SJoseph Koshy 
3228f263522aSJoseph Koshy int
3229f263522aSJoseph Koshy pmc_init(void)
3230f263522aSJoseph Koshy {
3231f263522aSJoseph Koshy 	int error, pmc_mod_id;
32321455fcd3SJoseph Koshy 	unsigned int n;
3233f263522aSJoseph Koshy 	uint32_t abi_version;
3234f263522aSJoseph Koshy 	struct module_stat pmc_modstat;
32351455fcd3SJoseph Koshy 	struct pmc_op_getcpuinfo op_cpu_info;
3236791f5d5bSJoseph Koshy #if defined(__amd64__) || defined(__i386__)
3237791f5d5bSJoseph Koshy 	int cpu_has_iaf_counters;
3238791f5d5bSJoseph Koshy 	unsigned int t;
3239791f5d5bSJoseph Koshy #endif
3240f263522aSJoseph Koshy 
3241f263522aSJoseph Koshy 	if (pmc_syscall != -1) /* already inited */
3242aa342b1fSJoseph Koshy 		return (0);
3243f263522aSJoseph Koshy 
3244f263522aSJoseph Koshy 	/* retrieve the system call number from the KLD */
3245f263522aSJoseph Koshy 	if ((pmc_mod_id = modfind(PMC_MODULE_NAME)) < 0)
3246aa342b1fSJoseph Koshy 		return (-1);
3247f263522aSJoseph Koshy 
3248f263522aSJoseph Koshy 	pmc_modstat.version = sizeof(struct module_stat);
3249f263522aSJoseph Koshy 	if ((error = modstat(pmc_mod_id, &pmc_modstat)) < 0)
3250aa342b1fSJoseph Koshy 		return (-1);
3251f263522aSJoseph Koshy 
3252f263522aSJoseph Koshy 	pmc_syscall = pmc_modstat.data.intval;
3253f263522aSJoseph Koshy 
3254f263522aSJoseph Koshy 	/* check the kernel module's ABI against our compiled-in version */
3255f263522aSJoseph Koshy 	abi_version = PMC_VERSION;
3256f263522aSJoseph Koshy 	if (PMC_CALL(GETMODULEVERSION, &abi_version) < 0)
3257f263522aSJoseph Koshy 		return (pmc_syscall = -1);
3258f263522aSJoseph Koshy 
325975f46cf6SPedro F. Giffuni 	/* ignore patch & minor numbers for the comparison */
3260f263522aSJoseph Koshy 	if ((abi_version & 0xFF000000) != (PMC_VERSION & 0xFF000000)) {
3261f263522aSJoseph Koshy 		errno  = EPROGMISMATCH;
3262f263522aSJoseph Koshy 		return (pmc_syscall = -1);
3263f263522aSJoseph Koshy 	}
3264f263522aSJoseph Koshy 
32651455fcd3SJoseph Koshy 	if (PMC_CALL(GETCPUINFO, &op_cpu_info) < 0)
3266f263522aSJoseph Koshy 		return (pmc_syscall = -1);
3267f263522aSJoseph Koshy 
32681455fcd3SJoseph Koshy 	cpu_info.pm_cputype = op_cpu_info.pm_cputype;
32691455fcd3SJoseph Koshy 	cpu_info.pm_ncpu    = op_cpu_info.pm_ncpu;
32701455fcd3SJoseph Koshy 	cpu_info.pm_npmc    = op_cpu_info.pm_npmc;
32711455fcd3SJoseph Koshy 	cpu_info.pm_nclass  = op_cpu_info.pm_nclass;
32721455fcd3SJoseph Koshy 	for (n = 0; n < cpu_info.pm_nclass; n++)
3273*b83aeb5cSJustin Hibbits 		memcpy(&cpu_info.pm_classes[n], &op_cpu_info.pm_classes[n],
3274*b83aeb5cSJustin Hibbits 		    sizeof(cpu_info.pm_classes[n]));
32751455fcd3SJoseph Koshy 
32760cfab8ddSJoseph Koshy 	pmc_class_table = malloc(PMC_CLASS_TABLE_SIZE *
32770cfab8ddSJoseph Koshy 	    sizeof(struct pmc_class_descr *));
32780cfab8ddSJoseph Koshy 
32790cfab8ddSJoseph Koshy 	if (pmc_class_table == NULL)
32800cfab8ddSJoseph Koshy 		return (-1);
32810cfab8ddSJoseph Koshy 
3282791f5d5bSJoseph Koshy 	for (n = 0; n < PMC_CLASS_TABLE_SIZE; n++)
3283791f5d5bSJoseph Koshy 		pmc_class_table[n] = NULL;
32840cfab8ddSJoseph Koshy 
32850cfab8ddSJoseph Koshy 	/*
3286f5f9340bSFabien Thomas 	 * Get soft events list.
3287f5f9340bSFabien Thomas 	 */
3288f5f9340bSFabien Thomas 	soft_event_info.pm_class = PMC_CLASS_SOFT;
3289f5f9340bSFabien Thomas 	if (PMC_CALL(GETDYNEVENTINFO, &soft_event_info) < 0)
3290f5f9340bSFabien Thomas 		return (pmc_syscall = -1);
3291f5f9340bSFabien Thomas 
3292f5f9340bSFabien Thomas 	/* Map soft events to static list. */
3293f5f9340bSFabien Thomas 	for (n = 0; n < soft_event_info.pm_nevent; n++) {
3294f5f9340bSFabien Thomas 		soft_event_table[n].pm_ev_name =
3295f5f9340bSFabien Thomas 		    soft_event_info.pm_events[n].pm_ev_name;
3296f5f9340bSFabien Thomas 		soft_event_table[n].pm_ev_code =
3297f5f9340bSFabien Thomas 		    soft_event_info.pm_events[n].pm_ev_code;
3298f5f9340bSFabien Thomas 	}
3299f5f9340bSFabien Thomas 	soft_class_table_descr.pm_evc_event_table_size = \
3300f5f9340bSFabien Thomas 	    soft_event_info.pm_nevent;
3301f5f9340bSFabien Thomas 	soft_class_table_descr.pm_evc_event_table = \
3302f5f9340bSFabien Thomas 	    soft_event_table;
3303f5f9340bSFabien Thomas 
3304f5f9340bSFabien Thomas 	/*
33050cfab8ddSJoseph Koshy 	 * Fill in the class table.
33060cfab8ddSJoseph Koshy 	 */
33070cfab8ddSJoseph Koshy 	n = 0;
3308f5f9340bSFabien Thomas 
3309f5f9340bSFabien Thomas 	/* Fill soft events information. */
3310f5f9340bSFabien Thomas 	pmc_class_table[n++] = &soft_class_table_descr;
33110cfab8ddSJoseph Koshy #if defined(__amd64__) || defined(__i386__)
3312f5f9340bSFabien Thomas 	if (cpu_info.pm_cputype != PMC_CPU_GENERIC)
33130cfab8ddSJoseph Koshy 		pmc_class_table[n++] = &tsc_class_table_descr;
3314791f5d5bSJoseph Koshy 
3315791f5d5bSJoseph Koshy 	/*
3316791f5d5bSJoseph Koshy  	 * Check if this CPU has fixed function counters.
3317791f5d5bSJoseph Koshy 	 */
3318791f5d5bSJoseph Koshy 	cpu_has_iaf_counters = 0;
3319791f5d5bSJoseph Koshy 	for (t = 0; t < cpu_info.pm_nclass; t++)
33202aef9dd6SFabien Thomas 		if (cpu_info.pm_classes[t].pm_class == PMC_CLASS_IAF &&
33212aef9dd6SFabien Thomas 		    cpu_info.pm_classes[t].pm_num > 0)
3322791f5d5bSJoseph Koshy 			cpu_has_iaf_counters = 1;
33230cfab8ddSJoseph Koshy #endif
33240cfab8ddSJoseph Koshy 
3325789140c0SJoseph Koshy #define	PMC_MDEP_INIT(C) do {					\
3326789140c0SJoseph Koshy 		pmc_mdep_event_aliases    = C##_aliases;	\
3327789140c0SJoseph Koshy 		pmc_mdep_class_list  = C##_pmc_classes;		\
3328789140c0SJoseph Koshy 		pmc_mdep_class_list_size =			\
3329789140c0SJoseph Koshy 		    PMC_TABLE_SIZE(C##_pmc_classes);		\
3330789140c0SJoseph Koshy 	} while (0)
3331789140c0SJoseph Koshy 
3332791f5d5bSJoseph Koshy #define	PMC_MDEP_INIT_INTEL_V2(C) do {					\
3333791f5d5bSJoseph Koshy 		PMC_MDEP_INIT(C);					\
3334791f5d5bSJoseph Koshy 		pmc_class_table[n++] = &iaf_class_table_descr;		\
33352aef9dd6SFabien Thomas 		if (!cpu_has_iaf_counters) 				\
3336791f5d5bSJoseph Koshy 			pmc_mdep_event_aliases =			\
3337791f5d5bSJoseph Koshy 				C##_aliases_without_iaf;		\
3338791f5d5bSJoseph Koshy 		pmc_class_table[n] = &C##_class_table_descr;		\
3339791f5d5bSJoseph Koshy 	} while (0)
3340791f5d5bSJoseph Koshy 
3341789140c0SJoseph Koshy 	/* Configure the event name parser. */
3342f263522aSJoseph Koshy 	switch (cpu_info.pm_cputype) {
3343f263522aSJoseph Koshy #if defined(__i386__)
3344f263522aSJoseph Koshy 	case PMC_CPU_AMD_K7:
3345789140c0SJoseph Koshy 		PMC_MDEP_INIT(k7);
33460cfab8ddSJoseph Koshy 		pmc_class_table[n] = &k7_class_table_descr;
3347f263522aSJoseph Koshy 		break;
3348f263522aSJoseph Koshy 	case PMC_CPU_INTEL_P5:
3349789140c0SJoseph Koshy 		PMC_MDEP_INIT(p5);
33500cfab8ddSJoseph Koshy 		pmc_class_table[n]  = &p5_class_table_descr;
3351f263522aSJoseph Koshy 		break;
3352f263522aSJoseph Koshy 	case PMC_CPU_INTEL_P6:		/* P6 ... Pentium M CPUs have */
3353f263522aSJoseph Koshy 	case PMC_CPU_INTEL_PII:		/* similar PMCs. */
3354f263522aSJoseph Koshy 	case PMC_CPU_INTEL_PIII:
3355f263522aSJoseph Koshy 	case PMC_CPU_INTEL_PM:
3356789140c0SJoseph Koshy 		PMC_MDEP_INIT(p6);
33570cfab8ddSJoseph Koshy 		pmc_class_table[n] = &p6_class_table_descr;
3358f263522aSJoseph Koshy 		break;
335986a65549SJoseph Koshy #endif
336086a65549SJoseph Koshy #if defined(__amd64__) || defined(__i386__)
3361f263522aSJoseph Koshy 	case PMC_CPU_AMD_K8:
3362789140c0SJoseph Koshy 		PMC_MDEP_INIT(k8);
33630cfab8ddSJoseph Koshy 		pmc_class_table[n] = &k8_class_table_descr;
33640cfab8ddSJoseph Koshy 		break;
33650cfab8ddSJoseph Koshy 	case PMC_CPU_INTEL_ATOM:
3366791f5d5bSJoseph Koshy 		PMC_MDEP_INIT_INTEL_V2(atom);
33670cfab8ddSJoseph Koshy 		break;
3368e8f021a3SHiren Panchasara 	case PMC_CPU_INTEL_ATOM_SILVERMONT:
3369e8f021a3SHiren Panchasara 		PMC_MDEP_INIT_INTEL_V2(atom_silvermont);
3370e8f021a3SHiren Panchasara 		break;
33710cfab8ddSJoseph Koshy 	case PMC_CPU_INTEL_CORE:
33720cfab8ddSJoseph Koshy 		PMC_MDEP_INIT(core);
3373bc315bbdSJoseph Koshy 		pmc_class_table[n] = &core_class_table_descr;
33740cfab8ddSJoseph Koshy 		break;
33750cfab8ddSJoseph Koshy 	case PMC_CPU_INTEL_CORE2:
3376b4d091f3SJoseph Koshy 	case PMC_CPU_INTEL_CORE2EXTREME:
3377791f5d5bSJoseph Koshy 		PMC_MDEP_INIT_INTEL_V2(core2);
3378789140c0SJoseph Koshy 		break;
3379597979c4SJeff Roberson 	case PMC_CPU_INTEL_COREI7:
33801fa7f10bSFabien Thomas 		pmc_class_table[n++] = &ucf_class_table_descr;
33811fa7f10bSFabien Thomas 		pmc_class_table[n++] = &corei7uc_class_table_descr;
3382791f5d5bSJoseph Koshy 		PMC_MDEP_INIT_INTEL_V2(corei7);
3383597979c4SJeff Roberson 		break;
338449fe48abSKonstantin Belousov 	case PMC_CPU_INTEL_NEHALEM_EX:
338549fe48abSKonstantin Belousov 		PMC_MDEP_INIT_INTEL_V2(nehalem_ex);
338649fe48abSKonstantin Belousov 		break;
3387cc0c1555SSean Bruno 	case PMC_CPU_INTEL_HASWELL:
3388cc0c1555SSean Bruno 		pmc_class_table[n++] = &ucf_class_table_descr;
3389cc0c1555SSean Bruno 		pmc_class_table[n++] = &haswelluc_class_table_descr;
3390cc0c1555SSean Bruno 		PMC_MDEP_INIT_INTEL_V2(haswell);
3391cc0c1555SSean Bruno 		break;
3392d95b3509SRandall Stewart 	case PMC_CPU_INTEL_HASWELL_XEON:
3393d95b3509SRandall Stewart 		PMC_MDEP_INIT_INTEL_V2(haswell_xeon);
3394d95b3509SRandall Stewart 		break;
3395f19bae41SRandall Stewart 	case PMC_CPU_INTEL_BROADWELL:
3396f19bae41SRandall Stewart 		pmc_class_table[n++] = &ucf_class_table_descr;
3397f19bae41SRandall Stewart 		pmc_class_table[n++] = &broadwelluc_class_table_descr;
3398f19bae41SRandall Stewart 		PMC_MDEP_INIT_INTEL_V2(broadwell);
3399f19bae41SRandall Stewart 		break;
3400f19bae41SRandall Stewart 	case PMC_CPU_INTEL_BROADWELL_XEON:
3401f19bae41SRandall Stewart 		PMC_MDEP_INIT_INTEL_V2(broadwell_xeon);
3402f19bae41SRandall Stewart 		break;
3403f19bae41SRandall Stewart 	case PMC_CPU_INTEL_SKYLAKE:
3404f19bae41SRandall Stewart 		PMC_MDEP_INIT_INTEL_V2(skylake);
3405f19bae41SRandall Stewart 		break;
3406b99b705dSKonstantin Belousov 	case PMC_CPU_INTEL_SKYLAKE_XEON:
3407b99b705dSKonstantin Belousov 		PMC_MDEP_INIT_INTEL_V2(skylake_xeon);
3408b99b705dSKonstantin Belousov 		break;
34091e862e5aSFabien Thomas 	case PMC_CPU_INTEL_IVYBRIDGE:
34101e862e5aSFabien Thomas 		PMC_MDEP_INIT_INTEL_V2(ivybridge);
34111e862e5aSFabien Thomas 		break;
34123f929d8cSSean Bruno 	case PMC_CPU_INTEL_IVYBRIDGE_XEON:
34133f929d8cSSean Bruno 		PMC_MDEP_INIT_INTEL_V2(ivybridge_xeon);
34143f929d8cSSean Bruno 		break;
341578d763a2SDavide Italiano 	case PMC_CPU_INTEL_SANDYBRIDGE:
341678d763a2SDavide Italiano 		pmc_class_table[n++] = &ucf_class_table_descr;
341778d763a2SDavide Italiano 		pmc_class_table[n++] = &sandybridgeuc_class_table_descr;
341878d763a2SDavide Italiano 		PMC_MDEP_INIT_INTEL_V2(sandybridge);
341978d763a2SDavide Italiano 		break;
3420fabe02f5SSean Bruno 	case PMC_CPU_INTEL_SANDYBRIDGE_XEON:
3421fabe02f5SSean Bruno 		PMC_MDEP_INIT_INTEL_V2(sandybridge_xeon);
3422fabe02f5SSean Bruno 		break;
34231fa7f10bSFabien Thomas 	case PMC_CPU_INTEL_WESTMERE:
34241fa7f10bSFabien Thomas 		pmc_class_table[n++] = &ucf_class_table_descr;
34251fa7f10bSFabien Thomas 		pmc_class_table[n++] = &westmereuc_class_table_descr;
34261fa7f10bSFabien Thomas 		PMC_MDEP_INIT_INTEL_V2(westmere);
34271fa7f10bSFabien Thomas 		break;
342849fe48abSKonstantin Belousov 	case PMC_CPU_INTEL_WESTMERE_EX:
342949fe48abSKonstantin Belousov 		PMC_MDEP_INIT_INTEL_V2(westmere_ex);
343049fe48abSKonstantin Belousov 		break;
3431789140c0SJoseph Koshy 	case PMC_CPU_INTEL_PIV:
3432789140c0SJoseph Koshy 		PMC_MDEP_INIT(p4);
34330cfab8ddSJoseph Koshy 		pmc_class_table[n] = &p4_class_table_descr;
3434f263522aSJoseph Koshy 		break;
3435ebccf1e3SJoseph Koshy #endif
3436f5f9340bSFabien Thomas 	case PMC_CPU_GENERIC:
3437f5f9340bSFabien Thomas 		PMC_MDEP_INIT(generic);
3438f5f9340bSFabien Thomas 		break;
34396411d14dSRuslan Bukin #if defined(__arm__)
34400ce207d2SRui Paulo #if defined(__XSCALE__)
34410ce207d2SRui Paulo 	case PMC_CPU_INTEL_XSCALE:
34420ce207d2SRui Paulo 		PMC_MDEP_INIT(xscale);
34430ce207d2SRui Paulo 		pmc_class_table[n] = &xscale_class_table_descr;
34440ce207d2SRui Paulo 		break;
34450ce207d2SRui Paulo #endif
34463e0bfdd8SRuslan Bukin 	case PMC_CPU_ARMV7_CORTEX_A8:
34473e0bfdd8SRuslan Bukin 		PMC_MDEP_INIT(cortex_a8);
34483e0bfdd8SRuslan Bukin 		pmc_class_table[n] = &cortex_a8_class_table_descr;
34493e0bfdd8SRuslan Bukin 		break;
34503e0bfdd8SRuslan Bukin 	case PMC_CPU_ARMV7_CORTEX_A9:
34513e0bfdd8SRuslan Bukin 		PMC_MDEP_INIT(cortex_a9);
34523e0bfdd8SRuslan Bukin 		pmc_class_table[n] = &cortex_a9_class_table_descr;
34536411d14dSRuslan Bukin 		break;
34546411d14dSRuslan Bukin #endif
3455bc88bb2bSRuslan Bukin #if defined(__aarch64__)
3456bc88bb2bSRuslan Bukin 	case PMC_CPU_ARMV8_CORTEX_A53:
3457bc88bb2bSRuslan Bukin 		PMC_MDEP_INIT(cortex_a53);
3458bc88bb2bSRuslan Bukin 		pmc_class_table[n] = &cortex_a53_class_table_descr;
3459bc88bb2bSRuslan Bukin 		break;
3460bc88bb2bSRuslan Bukin 	case PMC_CPU_ARMV8_CORTEX_A57:
3461bc88bb2bSRuslan Bukin 		PMC_MDEP_INIT(cortex_a57);
3462bc88bb2bSRuslan Bukin 		pmc_class_table[n] = &cortex_a57_class_table_descr;
3463bc88bb2bSRuslan Bukin 		break;
3464bc88bb2bSRuslan Bukin #endif
3465660df75eSGeorge V. Neville-Neil #if defined(__mips__)
3466660df75eSGeorge V. Neville-Neil 	case PMC_CPU_MIPS_24K:
3467660df75eSGeorge V. Neville-Neil 		PMC_MDEP_INIT(mips24k);
3468660df75eSGeorge V. Neville-Neil 		pmc_class_table[n] = &mips24k_class_table_descr;
3469660df75eSGeorge V. Neville-Neil 		break;
3470f6e6460dSAdrian Chadd 	case PMC_CPU_MIPS_74K:
3471f6e6460dSAdrian Chadd 		PMC_MDEP_INIT(mips74k);
3472f6e6460dSAdrian Chadd 		pmc_class_table[n] = &mips74k_class_table_descr;
3473f6e6460dSAdrian Chadd 		break;
3474c2657f80SOleksandr Tymoshenko 	case PMC_CPU_MIPS_OCTEON:
3475c2657f80SOleksandr Tymoshenko 		PMC_MDEP_INIT(octeon);
3476c2657f80SOleksandr Tymoshenko 		pmc_class_table[n] = &octeon_class_table_descr;
3477c2657f80SOleksandr Tymoshenko 		break;
3478660df75eSGeorge V. Neville-Neil #endif /* __mips__ */
34797b25dccaSJustin Hibbits #if defined(__powerpc__)
34807b25dccaSJustin Hibbits 	case PMC_CPU_PPC_7450:
34817b25dccaSJustin Hibbits 		PMC_MDEP_INIT(ppc7450);
34827b25dccaSJustin Hibbits 		pmc_class_table[n] = &ppc7450_class_table_descr;
34837b25dccaSJustin Hibbits 		break;
3484169dd953SJustin Hibbits 	case PMC_CPU_PPC_970:
3485169dd953SJustin Hibbits 		PMC_MDEP_INIT(ppc970);
3486169dd953SJustin Hibbits 		pmc_class_table[n] = &ppc970_class_table_descr;
3487169dd953SJustin Hibbits 		break;
3488a7452468SJustin Hibbits 	case PMC_CPU_PPC_E500:
3489a7452468SJustin Hibbits 		PMC_MDEP_INIT(e500);
3490a7452468SJustin Hibbits 		pmc_class_table[n] = &e500_class_table_descr;
3491a7452468SJustin Hibbits 		break;
34927b25dccaSJustin Hibbits #endif
3493f263522aSJoseph Koshy 	default:
3494f263522aSJoseph Koshy 		/*
3495f263522aSJoseph Koshy 		 * Some kind of CPU this version of the library knows nothing
3496f263522aSJoseph Koshy 		 * about.  This shouldn't happen since the abi version check
3497f263522aSJoseph Koshy 		 * should have caught this.
3498f263522aSJoseph Koshy 		 */
3499f263522aSJoseph Koshy 		errno = ENXIO;
3500f263522aSJoseph Koshy 		return (pmc_syscall = -1);
3501f263522aSJoseph Koshy 	}
3502f263522aSJoseph Koshy 
3503aa342b1fSJoseph Koshy 	return (0);
3504f263522aSJoseph Koshy }
3505f263522aSJoseph Koshy 
3506f263522aSJoseph Koshy const char *
3507f263522aSJoseph Koshy pmc_name_of_capability(enum pmc_caps cap)
3508f263522aSJoseph Koshy {
3509f263522aSJoseph Koshy 	int i;
3510f263522aSJoseph Koshy 
3511f263522aSJoseph Koshy 	/*
3512f263522aSJoseph Koshy 	 * 'cap' should have a single bit set and should be in
3513f263522aSJoseph Koshy 	 * range.
3514f263522aSJoseph Koshy 	 */
3515f263522aSJoseph Koshy 	if ((cap & (cap - 1)) || cap < PMC_CAP_FIRST ||
3516f263522aSJoseph Koshy 	    cap > PMC_CAP_LAST) {
3517f263522aSJoseph Koshy 		errno = EINVAL;
3518aa342b1fSJoseph Koshy 		return (NULL);
3519f263522aSJoseph Koshy 	}
3520f263522aSJoseph Koshy 
3521f263522aSJoseph Koshy 	i = ffs(cap);
3522aa342b1fSJoseph Koshy 	return (pmc_capability_names[i - 1]);
3523f263522aSJoseph Koshy }
3524f263522aSJoseph Koshy 
3525f263522aSJoseph Koshy const char *
3526f263522aSJoseph Koshy pmc_name_of_class(enum pmc_class pc)
3527f263522aSJoseph Koshy {
35280ceb54c2SJohn Baldwin 	size_t n;
35290ceb54c2SJohn Baldwin 
35300ceb54c2SJohn Baldwin 	for (n = 0; n < PMC_TABLE_SIZE(pmc_class_names); n++)
35310ceb54c2SJohn Baldwin 		if (pc == pmc_class_names[n].pm_class)
35320ceb54c2SJohn Baldwin 			return (pmc_class_names[n].pm_name);
3533f263522aSJoseph Koshy 
3534f263522aSJoseph Koshy 	errno = EINVAL;
3535aa342b1fSJoseph Koshy 	return (NULL);
3536f263522aSJoseph Koshy }
3537f263522aSJoseph Koshy 
3538f263522aSJoseph Koshy const char *
3539f263522aSJoseph Koshy pmc_name_of_cputype(enum pmc_cputype cp)
3540f263522aSJoseph Koshy {
3541789140c0SJoseph Koshy 	size_t n;
3542789140c0SJoseph Koshy 
3543789140c0SJoseph Koshy 	for (n = 0; n < PMC_TABLE_SIZE(pmc_cputype_names); n++)
3544789140c0SJoseph Koshy 		if (cp == pmc_cputype_names[n].pm_cputype)
3545789140c0SJoseph Koshy 			return (pmc_cputype_names[n].pm_name);
3546789140c0SJoseph Koshy 
3547f263522aSJoseph Koshy 	errno = EINVAL;
3548aa342b1fSJoseph Koshy 	return (NULL);
3549f263522aSJoseph Koshy }
3550f263522aSJoseph Koshy 
3551f263522aSJoseph Koshy const char *
3552f263522aSJoseph Koshy pmc_name_of_disposition(enum pmc_disp pd)
3553f263522aSJoseph Koshy {
3554f263522aSJoseph Koshy 	if ((int) pd >= PMC_DISP_FIRST &&
3555f263522aSJoseph Koshy 	    pd <= PMC_DISP_LAST)
3556aa342b1fSJoseph Koshy 		return (pmc_disposition_names[pd]);
3557f263522aSJoseph Koshy 
3558f263522aSJoseph Koshy 	errno = EINVAL;
3559aa342b1fSJoseph Koshy 	return (NULL);
3560f263522aSJoseph Koshy }
3561f263522aSJoseph Koshy 
3562f263522aSJoseph Koshy const char *
35630cfab8ddSJoseph Koshy _pmc_name_of_event(enum pmc_event pe, enum pmc_cputype cpu)
3564f263522aSJoseph Koshy {
3565789140c0SJoseph Koshy 	const struct pmc_event_descr *ev, *evfence;
3566789140c0SJoseph Koshy 
3567789140c0SJoseph Koshy 	ev = evfence = NULL;
35680cfab8ddSJoseph Koshy 	if (pe >= PMC_EV_IAF_FIRST && pe <= PMC_EV_IAF_LAST) {
35690cfab8ddSJoseph Koshy 		ev = iaf_event_table;
35700cfab8ddSJoseph Koshy 		evfence = iaf_event_table + PMC_EVENT_TABLE_SIZE(iaf);
35710cfab8ddSJoseph Koshy 	} else if (pe >= PMC_EV_IAP_FIRST && pe <= PMC_EV_IAP_LAST) {
35720cfab8ddSJoseph Koshy 		switch (cpu) {
35730cfab8ddSJoseph Koshy 		case PMC_CPU_INTEL_ATOM:
35740cfab8ddSJoseph Koshy 			ev = atom_event_table;
35750cfab8ddSJoseph Koshy 			evfence = atom_event_table + PMC_EVENT_TABLE_SIZE(atom);
35760cfab8ddSJoseph Koshy 			break;
3577e8f021a3SHiren Panchasara 		case PMC_CPU_INTEL_ATOM_SILVERMONT:
3578e8f021a3SHiren Panchasara 			ev = atom_silvermont_event_table;
3579e8f021a3SHiren Panchasara 			evfence = atom_silvermont_event_table +
3580e8f021a3SHiren Panchasara 			    PMC_EVENT_TABLE_SIZE(atom_silvermont);
3581e8f021a3SHiren Panchasara 			break;
35820cfab8ddSJoseph Koshy 		case PMC_CPU_INTEL_CORE:
35830cfab8ddSJoseph Koshy 			ev = core_event_table;
35840cfab8ddSJoseph Koshy 			evfence = core_event_table + PMC_EVENT_TABLE_SIZE(core);
35850cfab8ddSJoseph Koshy 			break;
35860cfab8ddSJoseph Koshy 		case PMC_CPU_INTEL_CORE2:
3587b4d091f3SJoseph Koshy 		case PMC_CPU_INTEL_CORE2EXTREME:
35880cfab8ddSJoseph Koshy 			ev = core2_event_table;
35890cfab8ddSJoseph Koshy 			evfence = core2_event_table + PMC_EVENT_TABLE_SIZE(core2);
35900cfab8ddSJoseph Koshy 			break;
3591597979c4SJeff Roberson 		case PMC_CPU_INTEL_COREI7:
3592597979c4SJeff Roberson 			ev = corei7_event_table;
3593597979c4SJeff Roberson 			evfence = corei7_event_table + PMC_EVENT_TABLE_SIZE(corei7);
3594597979c4SJeff Roberson 			break;
359549fe48abSKonstantin Belousov 		case PMC_CPU_INTEL_NEHALEM_EX:
359649fe48abSKonstantin Belousov 			ev = nehalem_ex_event_table;
359749fe48abSKonstantin Belousov 			evfence = nehalem_ex_event_table +
359849fe48abSKonstantin Belousov 			    PMC_EVENT_TABLE_SIZE(nehalem_ex);
359949fe48abSKonstantin Belousov 			break;
3600cc0c1555SSean Bruno 		case PMC_CPU_INTEL_HASWELL:
3601cc0c1555SSean Bruno 			ev = haswell_event_table;
3602cc0c1555SSean Bruno 			evfence = haswell_event_table + PMC_EVENT_TABLE_SIZE(haswell);
3603cc0c1555SSean Bruno 			break;
3604d95b3509SRandall Stewart 		case PMC_CPU_INTEL_HASWELL_XEON:
3605d95b3509SRandall Stewart 			ev = haswell_xeon_event_table;
3606d95b3509SRandall Stewart 			evfence = haswell_xeon_event_table + PMC_EVENT_TABLE_SIZE(haswell_xeon);
3607d95b3509SRandall Stewart 			break;
3608f19bae41SRandall Stewart 		case PMC_CPU_INTEL_BROADWELL:
3609f19bae41SRandall Stewart 			ev = broadwell_event_table;
3610f19bae41SRandall Stewart 			evfence = broadwell_event_table + PMC_EVENT_TABLE_SIZE(broadwell);
3611f19bae41SRandall Stewart 			break;
3612f19bae41SRandall Stewart 		case PMC_CPU_INTEL_BROADWELL_XEON:
3613f19bae41SRandall Stewart 			ev = broadwell_xeon_event_table;
3614f19bae41SRandall Stewart 			evfence = broadwell_xeon_event_table + PMC_EVENT_TABLE_SIZE(broadwell_xeon);
3615f19bae41SRandall Stewart 			break;
3616f19bae41SRandall Stewart 		case PMC_CPU_INTEL_SKYLAKE:
3617f19bae41SRandall Stewart 			ev = skylake_event_table;
36189491ba75SKonstantin Belousov 			evfence = skylake_event_table +
36199491ba75SKonstantin Belousov 			    PMC_EVENT_TABLE_SIZE(skylake);
3620f19bae41SRandall Stewart 			break;
3621b99b705dSKonstantin Belousov 		case PMC_CPU_INTEL_SKYLAKE_XEON:
3622b99b705dSKonstantin Belousov 			ev = skylake_xeon_event_table;
3623b99b705dSKonstantin Belousov 			evfence = skylake_xeon_event_table +
3624b99b705dSKonstantin Belousov 			    PMC_EVENT_TABLE_SIZE(skylake_xeon);
3625b99b705dSKonstantin Belousov 			break;
36261e862e5aSFabien Thomas 		case PMC_CPU_INTEL_IVYBRIDGE:
36271e862e5aSFabien Thomas 			ev = ivybridge_event_table;
36281e862e5aSFabien Thomas 			evfence = ivybridge_event_table + PMC_EVENT_TABLE_SIZE(ivybridge);
36291e862e5aSFabien Thomas 			break;
36303f929d8cSSean Bruno 		case PMC_CPU_INTEL_IVYBRIDGE_XEON:
36313f929d8cSSean Bruno 			ev = ivybridge_xeon_event_table;
36323f929d8cSSean Bruno 			evfence = ivybridge_xeon_event_table + PMC_EVENT_TABLE_SIZE(ivybridge_xeon);
36333f929d8cSSean Bruno 			break;
363478d763a2SDavide Italiano 		case PMC_CPU_INTEL_SANDYBRIDGE:
363578d763a2SDavide Italiano 			ev = sandybridge_event_table;
363678d763a2SDavide Italiano 			evfence = sandybridge_event_table + PMC_EVENT_TABLE_SIZE(sandybridge);
363778d763a2SDavide Italiano 			break;
3638fabe02f5SSean Bruno 		case PMC_CPU_INTEL_SANDYBRIDGE_XEON:
3639fabe02f5SSean Bruno 			ev = sandybridge_xeon_event_table;
3640fabe02f5SSean Bruno 			evfence = sandybridge_xeon_event_table + PMC_EVENT_TABLE_SIZE(sandybridge_xeon);
3641fabe02f5SSean Bruno 			break;
36421fa7f10bSFabien Thomas 		case PMC_CPU_INTEL_WESTMERE:
36431fa7f10bSFabien Thomas 			ev = westmere_event_table;
36441fa7f10bSFabien Thomas 			evfence = westmere_event_table + PMC_EVENT_TABLE_SIZE(westmere);
36451fa7f10bSFabien Thomas 			break;
364649fe48abSKonstantin Belousov 		case PMC_CPU_INTEL_WESTMERE_EX:
364749fe48abSKonstantin Belousov 			ev = westmere_ex_event_table;
364849fe48abSKonstantin Belousov 			evfence = westmere_ex_event_table +
364949fe48abSKonstantin Belousov 			    PMC_EVENT_TABLE_SIZE(westmere_ex);
365049fe48abSKonstantin Belousov 			break;
36510cfab8ddSJoseph Koshy 		default:	/* Unknown CPU type. */
36520cfab8ddSJoseph Koshy 			break;
36530cfab8ddSJoseph Koshy 		}
36541fa7f10bSFabien Thomas 	} else if (pe >= PMC_EV_UCF_FIRST && pe <= PMC_EV_UCF_LAST) {
36551fa7f10bSFabien Thomas 		ev = ucf_event_table;
36561fa7f10bSFabien Thomas 		evfence = ucf_event_table + PMC_EVENT_TABLE_SIZE(ucf);
36571fa7f10bSFabien Thomas 	} else if (pe >= PMC_EV_UCP_FIRST && pe <= PMC_EV_UCP_LAST) {
36581fa7f10bSFabien Thomas 		switch (cpu) {
36591fa7f10bSFabien Thomas 		case PMC_CPU_INTEL_COREI7:
36601fa7f10bSFabien Thomas 			ev = corei7uc_event_table;
36611fa7f10bSFabien Thomas 			evfence = corei7uc_event_table + PMC_EVENT_TABLE_SIZE(corei7uc);
36621fa7f10bSFabien Thomas 			break;
366378d763a2SDavide Italiano 		case PMC_CPU_INTEL_SANDYBRIDGE:
366478d763a2SDavide Italiano 			ev = sandybridgeuc_event_table;
366578d763a2SDavide Italiano 			evfence = sandybridgeuc_event_table + PMC_EVENT_TABLE_SIZE(sandybridgeuc);
366678d763a2SDavide Italiano 			break;
36671fa7f10bSFabien Thomas 		case PMC_CPU_INTEL_WESTMERE:
36681fa7f10bSFabien Thomas 			ev = westmereuc_event_table;
36691fa7f10bSFabien Thomas 			evfence = westmereuc_event_table + PMC_EVENT_TABLE_SIZE(westmereuc);
36701fa7f10bSFabien Thomas 			break;
36711fa7f10bSFabien Thomas 		default:	/* Unknown CPU type. */
36721fa7f10bSFabien Thomas 			break;
36731fa7f10bSFabien Thomas 		}
36741fa7f10bSFabien Thomas 	} else if (pe >= PMC_EV_K7_FIRST && pe <= PMC_EV_K7_LAST) {
3675789140c0SJoseph Koshy 		ev = k7_event_table;
3676789140c0SJoseph Koshy 		evfence = k7_event_table + PMC_EVENT_TABLE_SIZE(k7);
3677789140c0SJoseph Koshy 	} else if (pe >= PMC_EV_K8_FIRST && pe <= PMC_EV_K8_LAST) {
3678789140c0SJoseph Koshy 		ev = k8_event_table;
3679789140c0SJoseph Koshy 		evfence = k8_event_table + PMC_EVENT_TABLE_SIZE(k8);
3680789140c0SJoseph Koshy 	} else if (pe >= PMC_EV_P4_FIRST && pe <= PMC_EV_P4_LAST) {
3681789140c0SJoseph Koshy 		ev = p4_event_table;
3682789140c0SJoseph Koshy 		evfence = p4_event_table + PMC_EVENT_TABLE_SIZE(p4);
3683789140c0SJoseph Koshy 	} else if (pe >= PMC_EV_P5_FIRST && pe <= PMC_EV_P5_LAST) {
3684789140c0SJoseph Koshy 		ev = p5_event_table;
3685789140c0SJoseph Koshy 		evfence = p5_event_table + PMC_EVENT_TABLE_SIZE(p5);
3686789140c0SJoseph Koshy 	} else if (pe >= PMC_EV_P6_FIRST && pe <= PMC_EV_P6_LAST) {
3687789140c0SJoseph Koshy 		ev = p6_event_table;
3688789140c0SJoseph Koshy 		evfence = p6_event_table + PMC_EVENT_TABLE_SIZE(p6);
36890ce207d2SRui Paulo 	} else if (pe >= PMC_EV_XSCALE_FIRST && pe <= PMC_EV_XSCALE_LAST) {
36900ce207d2SRui Paulo 		ev = xscale_event_table;
36910ce207d2SRui Paulo 		evfence = xscale_event_table + PMC_EVENT_TABLE_SIZE(xscale);
36926411d14dSRuslan Bukin 	} else if (pe >= PMC_EV_ARMV7_FIRST && pe <= PMC_EV_ARMV7_LAST) {
36933e0bfdd8SRuslan Bukin 		switch (cpu) {
36943e0bfdd8SRuslan Bukin 		case PMC_CPU_ARMV7_CORTEX_A8:
36953e0bfdd8SRuslan Bukin 			ev = cortex_a8_event_table;
36963e0bfdd8SRuslan Bukin 			evfence = cortex_a8_event_table + PMC_EVENT_TABLE_SIZE(cortex_a8);
36973e0bfdd8SRuslan Bukin 			break;
36983e0bfdd8SRuslan Bukin 		case PMC_CPU_ARMV7_CORTEX_A9:
36993e0bfdd8SRuslan Bukin 			ev = cortex_a9_event_table;
37003e0bfdd8SRuslan Bukin 			evfence = cortex_a9_event_table + PMC_EVENT_TABLE_SIZE(cortex_a9);
37013e0bfdd8SRuslan Bukin 			break;
37023e0bfdd8SRuslan Bukin 		default:	/* Unknown CPU type. */
37033e0bfdd8SRuslan Bukin 			break;
37043e0bfdd8SRuslan Bukin 		}
3705bc88bb2bSRuslan Bukin 	} else if (pe >= PMC_EV_ARMV8_FIRST && pe <= PMC_EV_ARMV8_LAST) {
3706bc88bb2bSRuslan Bukin 		switch (cpu) {
3707bc88bb2bSRuslan Bukin 		case PMC_CPU_ARMV8_CORTEX_A53:
3708bc88bb2bSRuslan Bukin 			ev = cortex_a53_event_table;
3709bc88bb2bSRuslan Bukin 			evfence = cortex_a53_event_table + PMC_EVENT_TABLE_SIZE(cortex_a53);
3710bc88bb2bSRuslan Bukin 			break;
3711bc88bb2bSRuslan Bukin 		case PMC_CPU_ARMV8_CORTEX_A57:
3712bc88bb2bSRuslan Bukin 			ev = cortex_a57_event_table;
3713bc88bb2bSRuslan Bukin 			evfence = cortex_a57_event_table + PMC_EVENT_TABLE_SIZE(cortex_a57);
3714bc88bb2bSRuslan Bukin 			break;
3715bc88bb2bSRuslan Bukin 		default:	/* Unknown CPU type. */
3716bc88bb2bSRuslan Bukin 			break;
3717bc88bb2bSRuslan Bukin 		}
3718660df75eSGeorge V. Neville-Neil 	} else if (pe >= PMC_EV_MIPS24K_FIRST && pe <= PMC_EV_MIPS24K_LAST) {
3719660df75eSGeorge V. Neville-Neil 		ev = mips24k_event_table;
3720f5f9340bSFabien Thomas 		evfence = mips24k_event_table + PMC_EVENT_TABLE_SIZE(mips24k);
3721f6e6460dSAdrian Chadd 	} else if (pe >= PMC_EV_MIPS74K_FIRST && pe <= PMC_EV_MIPS74K_LAST) {
3722f6e6460dSAdrian Chadd 		ev = mips74k_event_table;
3723f6e6460dSAdrian Chadd 		evfence = mips74k_event_table + PMC_EVENT_TABLE_SIZE(mips74k);
3724c2657f80SOleksandr Tymoshenko 	} else if (pe >= PMC_EV_OCTEON_FIRST && pe <= PMC_EV_OCTEON_LAST) {
3725c2657f80SOleksandr Tymoshenko 		ev = octeon_event_table;
3726c2657f80SOleksandr Tymoshenko 		evfence = octeon_event_table + PMC_EVENT_TABLE_SIZE(octeon);
37277b25dccaSJustin Hibbits 	} else if (pe >= PMC_EV_PPC7450_FIRST && pe <= PMC_EV_PPC7450_LAST) {
37287b25dccaSJustin Hibbits 		ev = ppc7450_event_table;
3729f5f9340bSFabien Thomas 		evfence = ppc7450_event_table + PMC_EVENT_TABLE_SIZE(ppc7450);
3730169dd953SJustin Hibbits 	} else if (pe >= PMC_EV_PPC970_FIRST && pe <= PMC_EV_PPC970_LAST) {
3731169dd953SJustin Hibbits 		ev = ppc970_event_table;
3732169dd953SJustin Hibbits 		evfence = ppc970_event_table + PMC_EVENT_TABLE_SIZE(ppc970);
3733a7452468SJustin Hibbits 	} else if (pe >= PMC_EV_E500_FIRST && pe <= PMC_EV_E500_LAST) {
3734a7452468SJustin Hibbits 		ev = e500_event_table;
3735a7452468SJustin Hibbits 		evfence = e500_event_table + PMC_EVENT_TABLE_SIZE(e500);
3736789140c0SJoseph Koshy 	} else if (pe == PMC_EV_TSC_TSC) {
3737789140c0SJoseph Koshy 		ev = tsc_event_table;
3738789140c0SJoseph Koshy 		evfence = tsc_event_table + PMC_EVENT_TABLE_SIZE(tsc);
3739f0bbe9aaSDimitry Andric 	} else if ((int)pe >= PMC_EV_SOFT_FIRST && (int)pe <= PMC_EV_SOFT_LAST) {
3740f5f9340bSFabien Thomas 		ev = soft_event_table;
3741f5f9340bSFabien Thomas 		evfence = soft_event_table + soft_event_info.pm_nevent;
3742789140c0SJoseph Koshy 	}
3743789140c0SJoseph Koshy 
3744789140c0SJoseph Koshy 	for (; ev != evfence; ev++)
3745789140c0SJoseph Koshy 		if (pe == ev->pm_ev_code)
3746789140c0SJoseph Koshy 			return (ev->pm_ev_name);
3747f263522aSJoseph Koshy 
37480cfab8ddSJoseph Koshy 	return (NULL);
37490cfab8ddSJoseph Koshy }
37500cfab8ddSJoseph Koshy 
37510cfab8ddSJoseph Koshy const char *
37520cfab8ddSJoseph Koshy pmc_name_of_event(enum pmc_event pe)
37530cfab8ddSJoseph Koshy {
37540cfab8ddSJoseph Koshy 	const char *n;
37550cfab8ddSJoseph Koshy 
37560cfab8ddSJoseph Koshy 	if ((n = _pmc_name_of_event(pe, cpu_info.pm_cputype)) != NULL)
37570cfab8ddSJoseph Koshy 		return (n);
37580cfab8ddSJoseph Koshy 
3759f263522aSJoseph Koshy 	errno = EINVAL;
3760aa342b1fSJoseph Koshy 	return (NULL);
3761f263522aSJoseph Koshy }
3762f263522aSJoseph Koshy 
3763f263522aSJoseph Koshy const char *
3764f263522aSJoseph Koshy pmc_name_of_mode(enum pmc_mode pm)
3765f263522aSJoseph Koshy {
3766f263522aSJoseph Koshy 	if ((int) pm >= PMC_MODE_FIRST &&
3767f263522aSJoseph Koshy 	    pm <= PMC_MODE_LAST)
3768aa342b1fSJoseph Koshy 		return (pmc_mode_names[pm]);
3769f263522aSJoseph Koshy 
3770f263522aSJoseph Koshy 	errno = EINVAL;
3771aa342b1fSJoseph Koshy 	return (NULL);
3772f263522aSJoseph Koshy }
3773f263522aSJoseph Koshy 
3774f263522aSJoseph Koshy const char *
3775f263522aSJoseph Koshy pmc_name_of_state(enum pmc_state ps)
3776f263522aSJoseph Koshy {
3777f263522aSJoseph Koshy 	if ((int) ps >= PMC_STATE_FIRST &&
3778f263522aSJoseph Koshy 	    ps <= PMC_STATE_LAST)
3779aa342b1fSJoseph Koshy 		return (pmc_state_names[ps]);
3780f263522aSJoseph Koshy 
3781f263522aSJoseph Koshy 	errno = EINVAL;
3782aa342b1fSJoseph Koshy 	return (NULL);
3783f263522aSJoseph Koshy }
3784f263522aSJoseph Koshy 
3785f263522aSJoseph Koshy int
3786f263522aSJoseph Koshy pmc_ncpu(void)
3787f263522aSJoseph Koshy {
3788f263522aSJoseph Koshy 	if (pmc_syscall == -1) {
3789f263522aSJoseph Koshy 		errno = ENXIO;
3790aa342b1fSJoseph Koshy 		return (-1);
3791f263522aSJoseph Koshy 	}
3792f263522aSJoseph Koshy 
3793aa342b1fSJoseph Koshy 	return (cpu_info.pm_ncpu);
3794f263522aSJoseph Koshy }
3795f263522aSJoseph Koshy 
3796f263522aSJoseph Koshy int
3797f263522aSJoseph Koshy pmc_npmc(int cpu)
3798f263522aSJoseph Koshy {
3799f263522aSJoseph Koshy 	if (pmc_syscall == -1) {
3800f263522aSJoseph Koshy 		errno = ENXIO;
3801aa342b1fSJoseph Koshy 		return (-1);
3802f263522aSJoseph Koshy 	}
3803f263522aSJoseph Koshy 
3804f263522aSJoseph Koshy 	if (cpu < 0 || cpu >= (int) cpu_info.pm_ncpu) {
3805f263522aSJoseph Koshy 		errno = EINVAL;
3806aa342b1fSJoseph Koshy 		return (-1);
3807f263522aSJoseph Koshy 	}
3808f263522aSJoseph Koshy 
3809aa342b1fSJoseph Koshy 	return (cpu_info.pm_npmc);
3810f263522aSJoseph Koshy }
3811f263522aSJoseph Koshy 
3812f263522aSJoseph Koshy int
3813f263522aSJoseph Koshy pmc_pmcinfo(int cpu, struct pmc_pmcinfo **ppmci)
3814f263522aSJoseph Koshy {
3815f263522aSJoseph Koshy 	int nbytes, npmc;
3816f263522aSJoseph Koshy 	struct pmc_op_getpmcinfo *pmci;
3817f263522aSJoseph Koshy 
3818f263522aSJoseph Koshy 	if ((npmc = pmc_npmc(cpu)) < 0)
3819aa342b1fSJoseph Koshy 		return (-1);
3820f263522aSJoseph Koshy 
3821f263522aSJoseph Koshy 	nbytes = sizeof(struct pmc_op_getpmcinfo) +
3822f263522aSJoseph Koshy 	    npmc * sizeof(struct pmc_info);
3823f263522aSJoseph Koshy 
3824f263522aSJoseph Koshy 	if ((pmci = calloc(1, nbytes)) == NULL)
3825aa342b1fSJoseph Koshy 		return (-1);
3826f263522aSJoseph Koshy 
3827f263522aSJoseph Koshy 	pmci->pm_cpu  = cpu;
3828f263522aSJoseph Koshy 
3829f263522aSJoseph Koshy 	if (PMC_CALL(GETPMCINFO, pmci) < 0) {
3830f263522aSJoseph Koshy 		free(pmci);
3831aa342b1fSJoseph Koshy 		return (-1);
3832f263522aSJoseph Koshy 	}
3833f263522aSJoseph Koshy 
3834f263522aSJoseph Koshy 	/* kernel<->library, library<->userland interfaces are identical */
3835f263522aSJoseph Koshy 	*ppmci = (struct pmc_pmcinfo *) pmci;
3836aa342b1fSJoseph Koshy 	return (0);
3837f263522aSJoseph Koshy }
3838f263522aSJoseph Koshy 
3839f263522aSJoseph Koshy int
3840f263522aSJoseph Koshy pmc_read(pmc_id_t pmc, pmc_value_t *value)
3841f263522aSJoseph Koshy {
3842f263522aSJoseph Koshy 	struct pmc_op_pmcrw pmc_read_op;
3843f263522aSJoseph Koshy 
3844f263522aSJoseph Koshy 	pmc_read_op.pm_pmcid = pmc;
3845f263522aSJoseph Koshy 	pmc_read_op.pm_flags = PMC_F_OLDVALUE;
3846f263522aSJoseph Koshy 	pmc_read_op.pm_value = -1;
3847f263522aSJoseph Koshy 
3848f263522aSJoseph Koshy 	if (PMC_CALL(PMCRW, &pmc_read_op) < 0)
3849aa342b1fSJoseph Koshy 		return (-1);
3850f263522aSJoseph Koshy 
3851f263522aSJoseph Koshy 	*value = pmc_read_op.pm_value;
3852aa342b1fSJoseph Koshy 	return (0);
3853f263522aSJoseph Koshy }
3854f263522aSJoseph Koshy 
3855f263522aSJoseph Koshy int
3856f263522aSJoseph Koshy pmc_release(pmc_id_t pmc)
3857f263522aSJoseph Koshy {
3858f263522aSJoseph Koshy 	struct pmc_op_simple	pmc_release_args;
3859f263522aSJoseph Koshy 
3860f263522aSJoseph Koshy 	pmc_release_args.pm_pmcid = pmc;
3861aa342b1fSJoseph Koshy 	return (PMC_CALL(PMCRELEASE, &pmc_release_args));
3862f263522aSJoseph Koshy }
3863f263522aSJoseph Koshy 
3864f263522aSJoseph Koshy int
3865f263522aSJoseph Koshy pmc_rw(pmc_id_t pmc, pmc_value_t newvalue, pmc_value_t *oldvaluep)
3866f263522aSJoseph Koshy {
3867f263522aSJoseph Koshy 	struct pmc_op_pmcrw pmc_rw_op;
3868f263522aSJoseph Koshy 
3869f263522aSJoseph Koshy 	pmc_rw_op.pm_pmcid = pmc;
3870f263522aSJoseph Koshy 	pmc_rw_op.pm_flags = PMC_F_NEWVALUE | PMC_F_OLDVALUE;
3871f263522aSJoseph Koshy 	pmc_rw_op.pm_value = newvalue;
3872f263522aSJoseph Koshy 
3873f263522aSJoseph Koshy 	if (PMC_CALL(PMCRW, &pmc_rw_op) < 0)
3874aa342b1fSJoseph Koshy 		return (-1);
3875f263522aSJoseph Koshy 
3876f263522aSJoseph Koshy 	*oldvaluep = pmc_rw_op.pm_value;
3877aa342b1fSJoseph Koshy 	return (0);
3878f263522aSJoseph Koshy }
3879f263522aSJoseph Koshy 
3880f263522aSJoseph Koshy int
3881f263522aSJoseph Koshy pmc_set(pmc_id_t pmc, pmc_value_t value)
3882f263522aSJoseph Koshy {
3883f263522aSJoseph Koshy 	struct pmc_op_pmcsetcount sc;
3884f263522aSJoseph Koshy 
3885f263522aSJoseph Koshy 	sc.pm_pmcid = pmc;
3886f263522aSJoseph Koshy 	sc.pm_count = value;
3887f263522aSJoseph Koshy 
3888f263522aSJoseph Koshy 	if (PMC_CALL(PMCSETCOUNT, &sc) < 0)
3889aa342b1fSJoseph Koshy 		return (-1);
3890aa342b1fSJoseph Koshy 	return (0);
3891f263522aSJoseph Koshy }
3892f263522aSJoseph Koshy 
3893f263522aSJoseph Koshy int
3894f263522aSJoseph Koshy pmc_start(pmc_id_t pmc)
3895f263522aSJoseph Koshy {
3896f263522aSJoseph Koshy 	struct pmc_op_simple	pmc_start_args;
3897f263522aSJoseph Koshy 
3898f263522aSJoseph Koshy 	pmc_start_args.pm_pmcid = pmc;
3899aa342b1fSJoseph Koshy 	return (PMC_CALL(PMCSTART, &pmc_start_args));
3900f263522aSJoseph Koshy }
3901f263522aSJoseph Koshy 
3902f263522aSJoseph Koshy int
3903f263522aSJoseph Koshy pmc_stop(pmc_id_t pmc)
3904f263522aSJoseph Koshy {
3905f263522aSJoseph Koshy 	struct pmc_op_simple	pmc_stop_args;
3906f263522aSJoseph Koshy 
3907f263522aSJoseph Koshy 	pmc_stop_args.pm_pmcid = pmc;
3908aa342b1fSJoseph Koshy 	return (PMC_CALL(PMCSTOP, &pmc_stop_args));
3909f263522aSJoseph Koshy }
3910f263522aSJoseph Koshy 
3911f263522aSJoseph Koshy int
3912f263522aSJoseph Koshy pmc_width(pmc_id_t pmcid, uint32_t *width)
3913f263522aSJoseph Koshy {
3914f263522aSJoseph Koshy 	unsigned int i;
3915f263522aSJoseph Koshy 	enum pmc_class cl;
3916f263522aSJoseph Koshy 
3917f263522aSJoseph Koshy 	cl = PMC_ID_TO_CLASS(pmcid);
3918f263522aSJoseph Koshy 	for (i = 0; i < cpu_info.pm_nclass; i++)
3919f263522aSJoseph Koshy 		if (cpu_info.pm_classes[i].pm_class == cl) {
3920f263522aSJoseph Koshy 			*width = cpu_info.pm_classes[i].pm_width;
3921aa342b1fSJoseph Koshy 			return (0);
3922f263522aSJoseph Koshy 		}
3923484202faSJoseph Koshy 	errno = EINVAL;
3924484202faSJoseph Koshy 	return (-1);
3925f263522aSJoseph Koshy }
3926f263522aSJoseph Koshy 
3927f263522aSJoseph Koshy int
3928f263522aSJoseph Koshy pmc_write(pmc_id_t pmc, pmc_value_t value)
3929f263522aSJoseph Koshy {
3930f263522aSJoseph Koshy 	struct pmc_op_pmcrw pmc_write_op;
3931f263522aSJoseph Koshy 
3932f263522aSJoseph Koshy 	pmc_write_op.pm_pmcid = pmc;
3933f263522aSJoseph Koshy 	pmc_write_op.pm_flags = PMC_F_NEWVALUE;
3934f263522aSJoseph Koshy 	pmc_write_op.pm_value = value;
3935aa342b1fSJoseph Koshy 	return (PMC_CALL(PMCRW, &pmc_write_op));
3936f263522aSJoseph Koshy }
3937f263522aSJoseph Koshy 
3938f263522aSJoseph Koshy int
3939f263522aSJoseph Koshy pmc_writelog(uint32_t userdata)
3940f263522aSJoseph Koshy {
3941f263522aSJoseph Koshy 	struct pmc_op_writelog wl;
3942f263522aSJoseph Koshy 
3943f263522aSJoseph Koshy 	wl.pm_userdata = userdata;
3944aa342b1fSJoseph Koshy 	return (PMC_CALL(WRITELOG, &wl));
3945f263522aSJoseph Koshy }
3946