xref: /freebsd/lib/libpmc/libpmc.c (revision 6411d14d62a6bca53ba67bc581a1d89448f34944)
1ebccf1e3SJoseph Koshy /*-
2484202faSJoseph Koshy  * Copyright (c) 2003-2008 Joseph Koshy
3ebccf1e3SJoseph Koshy  * All rights reserved.
4ebccf1e3SJoseph Koshy  *
5ebccf1e3SJoseph Koshy  * Redistribution and use in source and binary forms, with or without
6ebccf1e3SJoseph Koshy  * modification, are permitted provided that the following conditions
7ebccf1e3SJoseph Koshy  * are met:
8ebccf1e3SJoseph Koshy  * 1. Redistributions of source code must retain the above copyright
9ebccf1e3SJoseph Koshy  *    notice, this list of conditions and the following disclaimer.
10ebccf1e3SJoseph Koshy  * 2. Redistributions in binary form must reproduce the above copyright
11ebccf1e3SJoseph Koshy  *    notice, this list of conditions and the following disclaimer in the
12ebccf1e3SJoseph Koshy  *    documentation and/or other materials provided with the distribution.
13ebccf1e3SJoseph Koshy  *
14ebccf1e3SJoseph Koshy  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15ebccf1e3SJoseph Koshy  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16ebccf1e3SJoseph Koshy  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17ebccf1e3SJoseph Koshy  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18ebccf1e3SJoseph Koshy  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19ebccf1e3SJoseph Koshy  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20ebccf1e3SJoseph Koshy  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21ebccf1e3SJoseph Koshy  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22ebccf1e3SJoseph Koshy  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23ebccf1e3SJoseph Koshy  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24ebccf1e3SJoseph Koshy  * SUCH DAMAGE.
25ebccf1e3SJoseph Koshy  */
26ebccf1e3SJoseph Koshy 
27ebccf1e3SJoseph Koshy #include <sys/cdefs.h>
28ebccf1e3SJoseph Koshy __FBSDID("$FreeBSD$");
29ebccf1e3SJoseph Koshy 
30ebccf1e3SJoseph Koshy #include <sys/types.h>
31169dd953SJustin Hibbits #include <sys/param.h>
32ebccf1e3SJoseph Koshy #include <sys/module.h>
33ebccf1e3SJoseph Koshy #include <sys/pmc.h>
34ebccf1e3SJoseph Koshy #include <sys/syscall.h>
35ebccf1e3SJoseph Koshy 
36ebccf1e3SJoseph Koshy #include <ctype.h>
37ebccf1e3SJoseph Koshy #include <errno.h>
38ebccf1e3SJoseph Koshy #include <fcntl.h>
39ebccf1e3SJoseph Koshy #include <pmc.h>
40ebccf1e3SJoseph Koshy #include <stdio.h>
41ebccf1e3SJoseph Koshy #include <stdlib.h>
42ebccf1e3SJoseph Koshy #include <string.h>
43ebccf1e3SJoseph Koshy #include <strings.h>
44ebccf1e3SJoseph Koshy #include <unistd.h>
45ebccf1e3SJoseph Koshy 
460cfab8ddSJoseph Koshy #include "libpmcinternal.h"
470cfab8ddSJoseph Koshy 
48ebccf1e3SJoseph Koshy /* Function prototypes */
4904e9feb0SMarcel Moolenaar #if defined(__i386__)
50ebccf1e3SJoseph Koshy static int k7_allocate_pmc(enum pmc_event _pe, char *_ctrspec,
51ebccf1e3SJoseph Koshy     struct pmc_op_pmcallocate *_pmc_config);
52f263522aSJoseph Koshy #endif
5386a65549SJoseph Koshy #if defined(__amd64__) || defined(__i386__)
540cfab8ddSJoseph Koshy static int iaf_allocate_pmc(enum pmc_event _pe, char *_ctrspec,
550cfab8ddSJoseph Koshy     struct pmc_op_pmcallocate *_pmc_config);
560cfab8ddSJoseph Koshy static int iap_allocate_pmc(enum pmc_event _pe, char *_ctrspec,
570cfab8ddSJoseph Koshy     struct pmc_op_pmcallocate *_pmc_config);
581fa7f10bSFabien Thomas static int ucf_allocate_pmc(enum pmc_event _pe, char *_ctrspec,
591fa7f10bSFabien Thomas     struct pmc_op_pmcallocate *_pmc_config);
601fa7f10bSFabien Thomas static int ucp_allocate_pmc(enum pmc_event _pe, char *_ctrspec,
611fa7f10bSFabien Thomas     struct pmc_op_pmcallocate *_pmc_config);
62f263522aSJoseph Koshy static int k8_allocate_pmc(enum pmc_event _pe, char *_ctrspec,
63ebccf1e3SJoseph Koshy     struct pmc_op_pmcallocate *_pmc_config);
6486a65549SJoseph Koshy static int p4_allocate_pmc(enum pmc_event _pe, char *_ctrspec,
6586a65549SJoseph Koshy     struct pmc_op_pmcallocate *_pmc_config);
66f263522aSJoseph Koshy #endif
67f263522aSJoseph Koshy #if defined(__i386__)
68ebccf1e3SJoseph Koshy static int p5_allocate_pmc(enum pmc_event _pe, char *_ctrspec,
69ebccf1e3SJoseph Koshy     struct pmc_op_pmcallocate *_pmc_config);
70f263522aSJoseph Koshy static int p6_allocate_pmc(enum pmc_event _pe, char *_ctrspec,
71ebccf1e3SJoseph Koshy     struct pmc_op_pmcallocate *_pmc_config);
72ebccf1e3SJoseph Koshy #endif
73789140c0SJoseph Koshy #if defined(__amd64__) || defined(__i386__)
74789140c0SJoseph Koshy static int tsc_allocate_pmc(enum pmc_event _pe, char *_ctrspec,
75789140c0SJoseph Koshy     struct pmc_op_pmcallocate *_pmc_config);
76789140c0SJoseph Koshy #endif
77*6411d14dSRuslan Bukin #if defined(__arm__)
780ce207d2SRui Paulo #if defined(__XSCALE__)
790ce207d2SRui Paulo static int xscale_allocate_pmc(enum pmc_event _pe, char *_ctrspec,
800ce207d2SRui Paulo     struct pmc_op_pmcallocate *_pmc_config);
810ce207d2SRui Paulo #endif
82*6411d14dSRuslan Bukin static int armv7_allocate_pmc(enum pmc_event _pe, char *_ctrspec,
83*6411d14dSRuslan Bukin     struct pmc_op_pmcallocate *_pmc_config);
84*6411d14dSRuslan Bukin #endif
85660df75eSGeorge V. Neville-Neil #if defined(__mips__)
862827d3e1SOleksandr Tymoshenko static int mips_allocate_pmc(enum pmc_event _pe, char* ctrspec,
87660df75eSGeorge V. Neville-Neil 			     struct pmc_op_pmcallocate *_pmc_config);
88660df75eSGeorge V. Neville-Neil #endif /* __mips__ */
89f5f9340bSFabien Thomas static int soft_allocate_pmc(enum pmc_event _pe, char *_ctrspec,
90f5f9340bSFabien Thomas     struct pmc_op_pmcallocate *_pmc_config);
91660df75eSGeorge V. Neville-Neil 
927b25dccaSJustin Hibbits #if defined(__powerpc__)
93169dd953SJustin Hibbits static int powerpc_allocate_pmc(enum pmc_event _pe, char* ctrspec,
947b25dccaSJustin Hibbits 			     struct pmc_op_pmcallocate *_pmc_config);
957b25dccaSJustin Hibbits #endif /* __powerpc__ */
96660df75eSGeorge V. Neville-Neil 
97ebccf1e3SJoseph Koshy #define PMC_CALL(cmd, params)				\
98ebccf1e3SJoseph Koshy 	syscall(pmc_syscall, PMC_OP_##cmd, (params))
99ebccf1e3SJoseph Koshy 
100ebccf1e3SJoseph Koshy /*
101ebccf1e3SJoseph Koshy  * Event aliases provide a way for the user to ask for generic events
102ebccf1e3SJoseph Koshy  * like "cache-misses", or "instructions-retired".  These aliases are
103ebccf1e3SJoseph Koshy  * mapped to the appropriate canonical event descriptions using a
104ebccf1e3SJoseph Koshy  * lookup table.
105ebccf1e3SJoseph Koshy  */
106ebccf1e3SJoseph Koshy struct pmc_event_alias {
107ebccf1e3SJoseph Koshy 	const char	*pm_alias;
108ebccf1e3SJoseph Koshy 	const char	*pm_spec;
109ebccf1e3SJoseph Koshy };
110ebccf1e3SJoseph Koshy 
111ebccf1e3SJoseph Koshy static const struct pmc_event_alias *pmc_mdep_event_aliases;
112ebccf1e3SJoseph Koshy 
113ebccf1e3SJoseph Koshy /*
114789140c0SJoseph Koshy  * The pmc_event_descr structure maps symbolic names known to the user
115ebccf1e3SJoseph Koshy  * to integer codes used by the PMC KLD.
116ebccf1e3SJoseph Koshy  */
117ebccf1e3SJoseph Koshy struct pmc_event_descr {
118ebccf1e3SJoseph Koshy 	const char	*pm_ev_name;
119ebccf1e3SJoseph Koshy 	enum pmc_event	pm_ev_code;
120ebccf1e3SJoseph Koshy };
121ebccf1e3SJoseph Koshy 
122789140c0SJoseph Koshy /*
123789140c0SJoseph Koshy  * The pmc_class_descr structure maps class name prefixes for
124789140c0SJoseph Koshy  * event names to event tables and other PMC class data.
125789140c0SJoseph Koshy  */
126789140c0SJoseph Koshy struct pmc_class_descr {
127789140c0SJoseph Koshy 	const char	*pm_evc_name;
128789140c0SJoseph Koshy 	size_t		pm_evc_name_size;
129789140c0SJoseph Koshy 	enum pmc_class	pm_evc_class;
130789140c0SJoseph Koshy 	const struct pmc_event_descr *pm_evc_event_table;
131789140c0SJoseph Koshy 	size_t		pm_evc_event_table_size;
132789140c0SJoseph Koshy 	int		(*pm_evc_allocate_pmc)(enum pmc_event _pe,
133789140c0SJoseph Koshy 			    char *_ctrspec, struct pmc_op_pmcallocate *_pa);
134ebccf1e3SJoseph Koshy };
135ebccf1e3SJoseph Koshy 
136789140c0SJoseph Koshy #define	PMC_TABLE_SIZE(N)	(sizeof(N)/sizeof(N[0]))
137789140c0SJoseph Koshy #define	PMC_EVENT_TABLE_SIZE(N)	PMC_TABLE_SIZE(N##_event_table)
138789140c0SJoseph Koshy 
139789140c0SJoseph Koshy #undef	__PMC_EV
140789140c0SJoseph Koshy #define	__PMC_EV(C,N) { #N, PMC_EV_ ## C ## _ ## N },
141789140c0SJoseph Koshy 
142789140c0SJoseph Koshy /*
1430cfab8ddSJoseph Koshy  * PMC_CLASSDEP_TABLE(NAME, CLASS)
144789140c0SJoseph Koshy  *
1450cfab8ddSJoseph Koshy  * Define a table mapping event names and aliases to HWPMC event IDs.
146789140c0SJoseph Koshy  */
1470cfab8ddSJoseph Koshy #define	PMC_CLASSDEP_TABLE(N, C)				\
148789140c0SJoseph Koshy 	static const struct pmc_event_descr N##_event_table[] =	\
149789140c0SJoseph Koshy 	{							\
150789140c0SJoseph Koshy 		__PMC_EV_##C()					\
1510cfab8ddSJoseph Koshy 	}
1520cfab8ddSJoseph Koshy 
1530cfab8ddSJoseph Koshy PMC_CLASSDEP_TABLE(iaf, IAF);
1540cfab8ddSJoseph Koshy PMC_CLASSDEP_TABLE(k7, K7);
1550cfab8ddSJoseph Koshy PMC_CLASSDEP_TABLE(k8, K8);
1560cfab8ddSJoseph Koshy PMC_CLASSDEP_TABLE(p4, P4);
1570cfab8ddSJoseph Koshy PMC_CLASSDEP_TABLE(p5, P5);
1580cfab8ddSJoseph Koshy PMC_CLASSDEP_TABLE(p6, P6);
1590ce207d2SRui Paulo PMC_CLASSDEP_TABLE(xscale, XSCALE);
160*6411d14dSRuslan Bukin PMC_CLASSDEP_TABLE(armv7, ARMV7);
161660df75eSGeorge V. Neville-Neil PMC_CLASSDEP_TABLE(mips24k, MIPS24K);
162c2657f80SOleksandr Tymoshenko PMC_CLASSDEP_TABLE(octeon, OCTEON);
1631fa7f10bSFabien Thomas PMC_CLASSDEP_TABLE(ucf, UCF);
1647b25dccaSJustin Hibbits PMC_CLASSDEP_TABLE(ppc7450, PPC7450);
165169dd953SJustin Hibbits PMC_CLASSDEP_TABLE(ppc970, PPC970);
1660cfab8ddSJoseph Koshy 
167f5f9340bSFabien Thomas static struct pmc_event_descr soft_event_table[PMC_EV_DYN_COUNT];
168f5f9340bSFabien Thomas 
1690cfab8ddSJoseph Koshy #undef	__PMC_EV_ALIAS
1700cfab8ddSJoseph Koshy #define	__PMC_EV_ALIAS(N,CODE) 	{ N, PMC_EV_##CODE },
1710cfab8ddSJoseph Koshy 
1720cfab8ddSJoseph Koshy static const struct pmc_event_descr atom_event_table[] =
1730cfab8ddSJoseph Koshy {
1740cfab8ddSJoseph Koshy 	__PMC_EV_ALIAS_ATOM()
1750cfab8ddSJoseph Koshy };
1760cfab8ddSJoseph Koshy 
177e8f021a3SHiren Panchasara static const struct pmc_event_descr atom_silvermont_event_table[] =
178e8f021a3SHiren Panchasara {
179e8f021a3SHiren Panchasara 	__PMC_EV_ALIAS_ATOM_SILVERMONT()
180e8f021a3SHiren Panchasara };
181e8f021a3SHiren Panchasara 
1820cfab8ddSJoseph Koshy static const struct pmc_event_descr core_event_table[] =
1830cfab8ddSJoseph Koshy {
1840cfab8ddSJoseph Koshy 	__PMC_EV_ALIAS_CORE()
1850cfab8ddSJoseph Koshy };
1860cfab8ddSJoseph Koshy 
1870cfab8ddSJoseph Koshy 
1880cfab8ddSJoseph Koshy static const struct pmc_event_descr core2_event_table[] =
1890cfab8ddSJoseph Koshy {
1900cfab8ddSJoseph Koshy 	__PMC_EV_ALIAS_CORE2()
1910cfab8ddSJoseph Koshy };
1920cfab8ddSJoseph Koshy 
193597979c4SJeff Roberson static const struct pmc_event_descr corei7_event_table[] =
194597979c4SJeff Roberson {
195597979c4SJeff Roberson 	__PMC_EV_ALIAS_COREI7()
196597979c4SJeff Roberson };
197597979c4SJeff Roberson 
19849fe48abSKonstantin Belousov static const struct pmc_event_descr nehalem_ex_event_table[] =
19949fe48abSKonstantin Belousov {
20049fe48abSKonstantin Belousov 	__PMC_EV_ALIAS_COREI7()
20149fe48abSKonstantin Belousov };
20249fe48abSKonstantin Belousov 
203cc0c1555SSean Bruno static const struct pmc_event_descr haswell_event_table[] =
204cc0c1555SSean Bruno {
205cc0c1555SSean Bruno 	__PMC_EV_ALIAS_HASWELL()
206cc0c1555SSean Bruno };
207cc0c1555SSean Bruno 
208d95b3509SRandall Stewart static const struct pmc_event_descr haswell_xeon_event_table[] =
209d95b3509SRandall Stewart {
210d95b3509SRandall Stewart 	__PMC_EV_ALIAS_HASWELL_XEON()
211d95b3509SRandall Stewart };
212d95b3509SRandall Stewart 
213d95b3509SRandall Stewart 
2141e862e5aSFabien Thomas static const struct pmc_event_descr ivybridge_event_table[] =
2151e862e5aSFabien Thomas {
2161e862e5aSFabien Thomas 	__PMC_EV_ALIAS_IVYBRIDGE()
2171e862e5aSFabien Thomas };
2181e862e5aSFabien Thomas 
2193f929d8cSSean Bruno static const struct pmc_event_descr ivybridge_xeon_event_table[] =
2203f929d8cSSean Bruno {
2213f929d8cSSean Bruno 	__PMC_EV_ALIAS_IVYBRIDGE_XEON()
2223f929d8cSSean Bruno };
2233f929d8cSSean Bruno 
22478d763a2SDavide Italiano static const struct pmc_event_descr sandybridge_event_table[] =
22578d763a2SDavide Italiano {
22678d763a2SDavide Italiano 	__PMC_EV_ALIAS_SANDYBRIDGE()
22778d763a2SDavide Italiano };
22878d763a2SDavide Italiano 
229fabe02f5SSean Bruno static const struct pmc_event_descr sandybridge_xeon_event_table[] =
230fabe02f5SSean Bruno {
231fabe02f5SSean Bruno 	__PMC_EV_ALIAS_SANDYBRIDGE_XEON()
232fabe02f5SSean Bruno };
233fabe02f5SSean Bruno 
2341fa7f10bSFabien Thomas static const struct pmc_event_descr westmere_event_table[] =
2351fa7f10bSFabien Thomas {
2361fa7f10bSFabien Thomas 	__PMC_EV_ALIAS_WESTMERE()
2371fa7f10bSFabien Thomas };
2381fa7f10bSFabien Thomas 
23949fe48abSKonstantin Belousov static const struct pmc_event_descr westmere_ex_event_table[] =
24049fe48abSKonstantin Belousov {
24149fe48abSKonstantin Belousov 	__PMC_EV_ALIAS_WESTMERE()
24249fe48abSKonstantin Belousov };
24349fe48abSKonstantin Belousov 
2441fa7f10bSFabien Thomas static const struct pmc_event_descr corei7uc_event_table[] =
2451fa7f10bSFabien Thomas {
2461fa7f10bSFabien Thomas 	__PMC_EV_ALIAS_COREI7UC()
2471fa7f10bSFabien Thomas };
2481fa7f10bSFabien Thomas 
249cc0c1555SSean Bruno static const struct pmc_event_descr haswelluc_event_table[] =
250cc0c1555SSean Bruno {
251cc0c1555SSean Bruno 	__PMC_EV_ALIAS_HASWELLUC()
252cc0c1555SSean Bruno };
253cc0c1555SSean Bruno 
25478d763a2SDavide Italiano static const struct pmc_event_descr sandybridgeuc_event_table[] =
25578d763a2SDavide Italiano {
25678d763a2SDavide Italiano 	__PMC_EV_ALIAS_SANDYBRIDGEUC()
25778d763a2SDavide Italiano };
25878d763a2SDavide Italiano 
2591fa7f10bSFabien Thomas static const struct pmc_event_descr westmereuc_event_table[] =
2601fa7f10bSFabien Thomas {
2611fa7f10bSFabien Thomas 	__PMC_EV_ALIAS_WESTMEREUC()
2621fa7f10bSFabien Thomas };
2631fa7f10bSFabien Thomas 
2640cfab8ddSJoseph Koshy /*
2650cfab8ddSJoseph Koshy  * PMC_MDEP_TABLE(NAME, PRIMARYCLASS, ADDITIONAL_CLASSES...)
2660cfab8ddSJoseph Koshy  *
2670cfab8ddSJoseph Koshy  * Map a CPU to the PMC classes it supports.
2680cfab8ddSJoseph Koshy  */
2690cfab8ddSJoseph Koshy #define	PMC_MDEP_TABLE(N,C,...)				\
270789140c0SJoseph Koshy 	static const enum pmc_class N##_pmc_classes[] = {	\
271789140c0SJoseph Koshy 		PMC_CLASS_##C, __VA_ARGS__			\
272789140c0SJoseph Koshy 	}
273789140c0SJoseph Koshy 
274f5f9340bSFabien Thomas PMC_MDEP_TABLE(atom, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC);
275e8f021a3SHiren Panchasara PMC_MDEP_TABLE(atom_silvermont, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC);
276f5f9340bSFabien Thomas PMC_MDEP_TABLE(core, IAP, PMC_CLASS_SOFT, PMC_CLASS_TSC);
277f5f9340bSFabien Thomas PMC_MDEP_TABLE(core2, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC);
278f5f9340bSFabien Thomas PMC_MDEP_TABLE(corei7, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC, PMC_CLASS_UCF, PMC_CLASS_UCP);
27949fe48abSKonstantin Belousov PMC_MDEP_TABLE(nehalem_ex, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC);
280cc0c1555SSean Bruno PMC_MDEP_TABLE(haswell, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC, PMC_CLASS_UCF, PMC_CLASS_UCP);
281d95b3509SRandall Stewart PMC_MDEP_TABLE(haswell_xeon, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC, PMC_CLASS_UCF, PMC_CLASS_UCP);
2821e862e5aSFabien Thomas PMC_MDEP_TABLE(ivybridge, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC);
2833f929d8cSSean Bruno PMC_MDEP_TABLE(ivybridge_xeon, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC);
284f5f9340bSFabien Thomas PMC_MDEP_TABLE(sandybridge, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC, PMC_CLASS_UCF, PMC_CLASS_UCP);
285fabe02f5SSean Bruno PMC_MDEP_TABLE(sandybridge_xeon, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC);
286f5f9340bSFabien Thomas PMC_MDEP_TABLE(westmere, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC, PMC_CLASS_UCF, PMC_CLASS_UCP);
28749fe48abSKonstantin Belousov PMC_MDEP_TABLE(westmere_ex, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC);
288f5f9340bSFabien Thomas PMC_MDEP_TABLE(k7, K7, PMC_CLASS_SOFT, PMC_CLASS_TSC);
289f5f9340bSFabien Thomas PMC_MDEP_TABLE(k8, K8, PMC_CLASS_SOFT, PMC_CLASS_TSC);
290f5f9340bSFabien Thomas PMC_MDEP_TABLE(p4, P4, PMC_CLASS_SOFT, PMC_CLASS_TSC);
291f5f9340bSFabien Thomas PMC_MDEP_TABLE(p5, P5, PMC_CLASS_SOFT, PMC_CLASS_TSC);
292f5f9340bSFabien Thomas PMC_MDEP_TABLE(p6, P6, PMC_CLASS_SOFT, PMC_CLASS_TSC);
293f5f9340bSFabien Thomas PMC_MDEP_TABLE(xscale, XSCALE, PMC_CLASS_SOFT, PMC_CLASS_XSCALE);
294*6411d14dSRuslan Bukin PMC_MDEP_TABLE(armv7, ARMV7, PMC_CLASS_SOFT, PMC_CLASS_ARMV7);
295f5f9340bSFabien Thomas PMC_MDEP_TABLE(mips24k, MIPS24K, PMC_CLASS_SOFT, PMC_CLASS_MIPS24K);
296f5f9340bSFabien Thomas PMC_MDEP_TABLE(octeon, OCTEON, PMC_CLASS_SOFT, PMC_CLASS_OCTEON);
297f5f9340bSFabien Thomas PMC_MDEP_TABLE(ppc7450, PPC7450, PMC_CLASS_SOFT, PMC_CLASS_PPC7450);
298169dd953SJustin Hibbits PMC_MDEP_TABLE(ppc970, PPC970, PMC_CLASS_SOFT, PMC_CLASS_PPC970);
299f5f9340bSFabien Thomas PMC_MDEP_TABLE(generic, SOFT, PMC_CLASS_SOFT);
300789140c0SJoseph Koshy 
301789140c0SJoseph Koshy static const struct pmc_event_descr tsc_event_table[] =
302789140c0SJoseph Koshy {
303789140c0SJoseph Koshy 	__PMC_EV_TSC()
304789140c0SJoseph Koshy };
305789140c0SJoseph Koshy 
306789140c0SJoseph Koshy #undef	PMC_CLASS_TABLE_DESC
3070cfab8ddSJoseph Koshy #define	PMC_CLASS_TABLE_DESC(NAME, CLASS, EVENTS, ALLOCATOR)	\
3080cfab8ddSJoseph Koshy static const struct pmc_class_descr NAME##_class_table_descr =	\
3090cfab8ddSJoseph Koshy 	{							\
3100cfab8ddSJoseph Koshy 		.pm_evc_name  = #CLASS "-",			\
3110cfab8ddSJoseph Koshy 		.pm_evc_name_size = sizeof(#CLASS "-") - 1,	\
3120cfab8ddSJoseph Koshy 		.pm_evc_class = PMC_CLASS_##CLASS ,		\
3130cfab8ddSJoseph Koshy 		.pm_evc_event_table = EVENTS##_event_table ,	\
314789140c0SJoseph Koshy 		.pm_evc_event_table_size = 			\
3150cfab8ddSJoseph Koshy 			PMC_EVENT_TABLE_SIZE(EVENTS),		\
3160cfab8ddSJoseph Koshy 		.pm_evc_allocate_pmc = ALLOCATOR##_allocate_pmc	\
317789140c0SJoseph Koshy 	}
318789140c0SJoseph Koshy 
319789140c0SJoseph Koshy #if	defined(__i386__) || defined(__amd64__)
3200cfab8ddSJoseph Koshy PMC_CLASS_TABLE_DESC(iaf, IAF, iaf, iaf);
3210cfab8ddSJoseph Koshy PMC_CLASS_TABLE_DESC(atom, IAP, atom, iap);
322e8f021a3SHiren Panchasara PMC_CLASS_TABLE_DESC(atom_silvermont, IAP, atom_silvermont, iap);
3230cfab8ddSJoseph Koshy PMC_CLASS_TABLE_DESC(core, IAP, core, iap);
3240cfab8ddSJoseph Koshy PMC_CLASS_TABLE_DESC(core2, IAP, core2, iap);
325597979c4SJeff Roberson PMC_CLASS_TABLE_DESC(corei7, IAP, corei7, iap);
32649fe48abSKonstantin Belousov PMC_CLASS_TABLE_DESC(nehalem_ex, IAP, nehalem_ex, iap);
327cc0c1555SSean Bruno PMC_CLASS_TABLE_DESC(haswell, IAP, haswell, iap);
328d95b3509SRandall Stewart PMC_CLASS_TABLE_DESC(haswell_xeon, IAP, haswell, iap);
3291e862e5aSFabien Thomas PMC_CLASS_TABLE_DESC(ivybridge, IAP, ivybridge, iap);
3303f929d8cSSean Bruno PMC_CLASS_TABLE_DESC(ivybridge_xeon, IAP, ivybridge_xeon, iap);
33178d763a2SDavide Italiano PMC_CLASS_TABLE_DESC(sandybridge, IAP, sandybridge, iap);
332fabe02f5SSean Bruno PMC_CLASS_TABLE_DESC(sandybridge_xeon, IAP, sandybridge_xeon, iap);
3331fa7f10bSFabien Thomas PMC_CLASS_TABLE_DESC(westmere, IAP, westmere, iap);
33449fe48abSKonstantin Belousov PMC_CLASS_TABLE_DESC(westmere_ex, IAP, westmere_ex, iap);
3351fa7f10bSFabien Thomas PMC_CLASS_TABLE_DESC(ucf, UCF, ucf, ucf);
3361fa7f10bSFabien Thomas PMC_CLASS_TABLE_DESC(corei7uc, UCP, corei7uc, ucp);
337cc0c1555SSean Bruno PMC_CLASS_TABLE_DESC(haswelluc, UCP, haswelluc, ucp);
33878d763a2SDavide Italiano PMC_CLASS_TABLE_DESC(sandybridgeuc, UCP, sandybridgeuc, ucp);
3391fa7f10bSFabien Thomas PMC_CLASS_TABLE_DESC(westmereuc, UCP, westmereuc, ucp);
340789140c0SJoseph Koshy #endif
341789140c0SJoseph Koshy #if	defined(__i386__)
3420cfab8ddSJoseph Koshy PMC_CLASS_TABLE_DESC(k7, K7, k7, k7);
343789140c0SJoseph Koshy #endif
344789140c0SJoseph Koshy #if	defined(__i386__) || defined(__amd64__)
3450cfab8ddSJoseph Koshy PMC_CLASS_TABLE_DESC(k8, K8, k8, k8);
3460cfab8ddSJoseph Koshy PMC_CLASS_TABLE_DESC(p4, P4, p4, p4);
347789140c0SJoseph Koshy #endif
3480cfab8ddSJoseph Koshy #if	defined(__i386__)
3490cfab8ddSJoseph Koshy PMC_CLASS_TABLE_DESC(p5, P5, p5, p5);
3500cfab8ddSJoseph Koshy PMC_CLASS_TABLE_DESC(p6, P6, p6, p6);
3510cfab8ddSJoseph Koshy #endif
3520cfab8ddSJoseph Koshy #if	defined(__i386__) || defined(__amd64__)
3530cfab8ddSJoseph Koshy PMC_CLASS_TABLE_DESC(tsc, TSC, tsc, tsc);
3540cfab8ddSJoseph Koshy #endif
355*6411d14dSRuslan Bukin #if	defined(__arm__)
3560ce207d2SRui Paulo #if	defined(__XSCALE__)
3570ce207d2SRui Paulo PMC_CLASS_TABLE_DESC(xscale, XSCALE, xscale, xscale);
3580ce207d2SRui Paulo #endif
359*6411d14dSRuslan Bukin PMC_CLASS_TABLE_DESC(armv7, ARMV7, armv7, armv7);
360*6411d14dSRuslan Bukin #endif
361660df75eSGeorge V. Neville-Neil #if defined(__mips__)
3622827d3e1SOleksandr Tymoshenko PMC_CLASS_TABLE_DESC(mips24k, MIPS24K, mips24k, mips);
363c2657f80SOleksandr Tymoshenko PMC_CLASS_TABLE_DESC(octeon, OCTEON, octeon, mips);
364660df75eSGeorge V. Neville-Neil #endif /* __mips__ */
3657b25dccaSJustin Hibbits #if defined(__powerpc__)
366169dd953SJustin Hibbits PMC_CLASS_TABLE_DESC(ppc7450, PPC7450, ppc7450, powerpc);
367169dd953SJustin Hibbits PMC_CLASS_TABLE_DESC(ppc970, PPC970, ppc970, powerpc);
3687b25dccaSJustin Hibbits #endif
3697b25dccaSJustin Hibbits 
370f5f9340bSFabien Thomas static struct pmc_class_descr soft_class_table_descr =
371f5f9340bSFabien Thomas {
372f5f9340bSFabien Thomas 	.pm_evc_name  = "SOFT-",
373f5f9340bSFabien Thomas 	.pm_evc_name_size = sizeof("SOFT-") - 1,
374f5f9340bSFabien Thomas 	.pm_evc_class = PMC_CLASS_SOFT,
375f5f9340bSFabien Thomas 	.pm_evc_event_table = NULL,
376f5f9340bSFabien Thomas 	.pm_evc_event_table_size = 0,
377f5f9340bSFabien Thomas 	.pm_evc_allocate_pmc = soft_allocate_pmc
378f5f9340bSFabien Thomas };
379f5f9340bSFabien Thomas 
380789140c0SJoseph Koshy #undef	PMC_CLASS_TABLE_DESC
381789140c0SJoseph Koshy 
3820cfab8ddSJoseph Koshy static const struct pmc_class_descr **pmc_class_table;
3830cfab8ddSJoseph Koshy #define	PMC_CLASS_TABLE_SIZE	cpu_info.pm_nclass
3840cfab8ddSJoseph Koshy 
385789140c0SJoseph Koshy static const enum pmc_class *pmc_mdep_class_list;
386789140c0SJoseph Koshy static size_t pmc_mdep_class_list_size;
387789140c0SJoseph Koshy 
388ebccf1e3SJoseph Koshy /*
389ebccf1e3SJoseph Koshy  * Mapping tables, mapping enumeration values to human readable
390ebccf1e3SJoseph Koshy  * strings.
391ebccf1e3SJoseph Koshy  */
392ebccf1e3SJoseph Koshy 
393ebccf1e3SJoseph Koshy static const char * pmc_capability_names[] = {
394ebccf1e3SJoseph Koshy #undef	__PMC_CAP
395ebccf1e3SJoseph Koshy #define	__PMC_CAP(N,V,D)	#N ,
396ebccf1e3SJoseph Koshy 	__PMC_CAPS()
397ebccf1e3SJoseph Koshy };
398ebccf1e3SJoseph Koshy 
399ebccf1e3SJoseph Koshy static const char * pmc_class_names[] = {
400ebccf1e3SJoseph Koshy #undef	__PMC_CLASS
401ebccf1e3SJoseph Koshy #define __PMC_CLASS(C)	#C ,
402ebccf1e3SJoseph Koshy 	__PMC_CLASSES()
403ebccf1e3SJoseph Koshy };
404ebccf1e3SJoseph Koshy 
405789140c0SJoseph Koshy struct pmc_cputype_map {
406562fc14bSDimitry Andric 	enum pmc_cputype pm_cputype;
407789140c0SJoseph Koshy 	const char	*pm_name;
408789140c0SJoseph Koshy };
409789140c0SJoseph Koshy 
410789140c0SJoseph Koshy static const struct pmc_cputype_map pmc_cputype_names[] = {
411ebccf1e3SJoseph Koshy #undef	__PMC_CPU
412789140c0SJoseph Koshy #define	__PMC_CPU(S, V, D) { .pm_cputype = PMC_CPU_##S, .pm_name = #S } ,
413ebccf1e3SJoseph Koshy 	__PMC_CPUS()
414ebccf1e3SJoseph Koshy };
415ebccf1e3SJoseph Koshy 
416ebccf1e3SJoseph Koshy static const char * pmc_disposition_names[] = {
417ebccf1e3SJoseph Koshy #undef	__PMC_DISP
418ebccf1e3SJoseph Koshy #define	__PMC_DISP(D)	#D ,
419ebccf1e3SJoseph Koshy 	__PMC_DISPOSITIONS()
420ebccf1e3SJoseph Koshy };
421ebccf1e3SJoseph Koshy 
422ebccf1e3SJoseph Koshy static const char * pmc_mode_names[] = {
423ebccf1e3SJoseph Koshy #undef  __PMC_MODE
424ebccf1e3SJoseph Koshy #define __PMC_MODE(M,N)	#M ,
425ebccf1e3SJoseph Koshy 	__PMC_MODES()
426ebccf1e3SJoseph Koshy };
427ebccf1e3SJoseph Koshy 
428ebccf1e3SJoseph Koshy static const char * pmc_state_names[] = {
429ebccf1e3SJoseph Koshy #undef  __PMC_STATE
430ebccf1e3SJoseph Koshy #define __PMC_STATE(S) #S ,
431ebccf1e3SJoseph Koshy 	__PMC_STATES()
432ebccf1e3SJoseph Koshy };
433ebccf1e3SJoseph Koshy 
434f5f9340bSFabien Thomas /*
435f5f9340bSFabien Thomas  * Filled in by pmc_init().
436f5f9340bSFabien Thomas  */
437f5f9340bSFabien Thomas static int pmc_syscall = -1;
438f5f9340bSFabien Thomas static struct pmc_cpuinfo cpu_info;
439f5f9340bSFabien Thomas static struct pmc_op_getdyneventinfo soft_event_info;
4401455fcd3SJoseph Koshy 
441ebccf1e3SJoseph Koshy /* Event masks for events */
442ebccf1e3SJoseph Koshy struct pmc_masks {
443ebccf1e3SJoseph Koshy 	const char	*pm_name;
4441e862e5aSFabien Thomas 	const uint64_t	pm_value;
445ebccf1e3SJoseph Koshy };
446ebccf1e3SJoseph Koshy #define	PMCMASK(N,V)	{ .pm_name = #N, .pm_value = (V) }
4471fa7f10bSFabien Thomas #define	NULLMASK	{ .pm_name = NULL }
448ebccf1e3SJoseph Koshy 
44986a65549SJoseph Koshy #if defined(__amd64__) || defined(__i386__)
450ebccf1e3SJoseph Koshy static int
4511e862e5aSFabien Thomas pmc_parse_mask(const struct pmc_masks *pmask, char *p, uint64_t *evmask)
452ebccf1e3SJoseph Koshy {
453ebccf1e3SJoseph Koshy 	const struct pmc_masks *pm;
454ebccf1e3SJoseph Koshy 	char *q, *r;
455ebccf1e3SJoseph Koshy 	int c;
456ebccf1e3SJoseph Koshy 
457ebccf1e3SJoseph Koshy 	if (pmask == NULL)	/* no mask keywords */
458aa342b1fSJoseph Koshy 		return (-1);
459ebccf1e3SJoseph Koshy 	q = strchr(p, '=');	/* skip '=' */
460ebccf1e3SJoseph Koshy 	if (*++q == '\0')	/* no more data */
461aa342b1fSJoseph Koshy 		return (-1);
462ebccf1e3SJoseph Koshy 	c = 0;			/* count of mask keywords seen */
463ebccf1e3SJoseph Koshy 	while ((r = strsep(&q, "+")) != NULL) {
464789140c0SJoseph Koshy 		for (pm = pmask; pm->pm_name && strcasecmp(r, pm->pm_name);
465789140c0SJoseph Koshy 		    pm++)
466ebccf1e3SJoseph Koshy 			;
467ebccf1e3SJoseph Koshy 		if (pm->pm_name == NULL) /* not found */
468aa342b1fSJoseph Koshy 			return (-1);
469ebccf1e3SJoseph Koshy 		*evmask |= pm->pm_value;
470ebccf1e3SJoseph Koshy 		c++;
471ebccf1e3SJoseph Koshy 	}
472aa342b1fSJoseph Koshy 	return (c);
473ebccf1e3SJoseph Koshy }
47404e9feb0SMarcel Moolenaar #endif
475ebccf1e3SJoseph Koshy 
476ebccf1e3SJoseph Koshy #define	KWMATCH(p,kw)		(strcasecmp((p), (kw)) == 0)
477ebccf1e3SJoseph Koshy #define	KWPREFIXMATCH(p,kw)	(strncasecmp((p), (kw), sizeof((kw)) - 1) == 0)
478ebccf1e3SJoseph Koshy #define	EV_ALIAS(N,S)		{ .pm_alias = N, .pm_spec = S }
479ebccf1e3SJoseph Koshy 
48004e9feb0SMarcel Moolenaar #if defined(__i386__)
481ebccf1e3SJoseph Koshy 
482ebccf1e3SJoseph Koshy /*
483ebccf1e3SJoseph Koshy  * AMD K7 (Athlon) CPUs.
484ebccf1e3SJoseph Koshy  */
485ebccf1e3SJoseph Koshy 
486ebccf1e3SJoseph Koshy static struct pmc_event_alias k7_aliases[] = {
487ebccf1e3SJoseph Koshy 	EV_ALIAS("branches",		"k7-retired-branches"),
488ebccf1e3SJoseph Koshy 	EV_ALIAS("branch-mispredicts",	"k7-retired-branches-mispredicted"),
489ebccf1e3SJoseph Koshy 	EV_ALIAS("cycles",		"tsc"),
4906aa5a193SJoseph Koshy 	EV_ALIAS("dc-misses",		"k7-dc-misses"),
491ebccf1e3SJoseph Koshy 	EV_ALIAS("ic-misses",		"k7-ic-misses"),
492ebccf1e3SJoseph Koshy 	EV_ALIAS("instructions",	"k7-retired-instructions"),
493ebccf1e3SJoseph Koshy 	EV_ALIAS("interrupts",		"k7-hardware-interrupts"),
494ebccf1e3SJoseph Koshy 	EV_ALIAS(NULL, NULL)
495ebccf1e3SJoseph Koshy };
496ebccf1e3SJoseph Koshy 
497ebccf1e3SJoseph Koshy #define	K7_KW_COUNT	"count"
498ebccf1e3SJoseph Koshy #define	K7_KW_EDGE	"edge"
499ebccf1e3SJoseph Koshy #define	K7_KW_INV	"inv"
500ebccf1e3SJoseph Koshy #define	K7_KW_OS	"os"
501ebccf1e3SJoseph Koshy #define	K7_KW_UNITMASK	"unitmask"
502ebccf1e3SJoseph Koshy #define	K7_KW_USR	"usr"
503ebccf1e3SJoseph Koshy 
504ebccf1e3SJoseph Koshy static int
505ebccf1e3SJoseph Koshy k7_allocate_pmc(enum pmc_event pe, char *ctrspec,
506ebccf1e3SJoseph Koshy     struct pmc_op_pmcallocate *pmc_config)
507ebccf1e3SJoseph Koshy {
508ebccf1e3SJoseph Koshy 	char		*e, *p, *q;
509ebccf1e3SJoseph Koshy 	int		c, has_unitmask;
510ebccf1e3SJoseph Koshy 	uint32_t	count, unitmask;
511ebccf1e3SJoseph Koshy 
512f263522aSJoseph Koshy 	pmc_config->pm_md.pm_amd.pm_amd_config = 0;
513789140c0SJoseph Koshy 	pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE);
514ebccf1e3SJoseph Koshy 
515ebccf1e3SJoseph Koshy 	if (pe == PMC_EV_K7_DC_REFILLS_FROM_L2 ||
516ebccf1e3SJoseph Koshy 	    pe == PMC_EV_K7_DC_REFILLS_FROM_SYSTEM ||
517ebccf1e3SJoseph Koshy 	    pe == PMC_EV_K7_DC_WRITEBACKS) {
518ebccf1e3SJoseph Koshy 		has_unitmask = 1;
519f263522aSJoseph Koshy 		unitmask = AMD_PMC_UNITMASK_MOESI;
520ebccf1e3SJoseph Koshy 	} else
521ebccf1e3SJoseph Koshy 		unitmask = has_unitmask = 0;
522ebccf1e3SJoseph Koshy 
523ebccf1e3SJoseph Koshy 	while ((p = strsep(&ctrspec, ",")) != NULL) {
524ebccf1e3SJoseph Koshy 		if (KWPREFIXMATCH(p, K7_KW_COUNT "=")) {
525ebccf1e3SJoseph Koshy 			q = strchr(p, '=');
526ebccf1e3SJoseph Koshy 			if (*++q == '\0') /* skip '=' */
527aa342b1fSJoseph Koshy 				return (-1);
528ebccf1e3SJoseph Koshy 
529ebccf1e3SJoseph Koshy 			count = strtol(q, &e, 0);
530ebccf1e3SJoseph Koshy 			if (e == q || *e != '\0')
531aa342b1fSJoseph Koshy 				return (-1);
532ebccf1e3SJoseph Koshy 
533ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_THRESHOLD;
534f263522aSJoseph Koshy 			pmc_config->pm_md.pm_amd.pm_amd_config |=
535f263522aSJoseph Koshy 			    AMD_PMC_TO_COUNTER(count);
536ebccf1e3SJoseph Koshy 
537ebccf1e3SJoseph Koshy 		} else if (KWMATCH(p, K7_KW_EDGE)) {
538ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_EDGE;
539ebccf1e3SJoseph Koshy 		} else if (KWMATCH(p, K7_KW_INV)) {
540ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_INVERT;
541ebccf1e3SJoseph Koshy 		} else if (KWMATCH(p, K7_KW_OS)) {
542ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_SYSTEM;
543ebccf1e3SJoseph Koshy 		} else if (KWPREFIXMATCH(p, K7_KW_UNITMASK "=")) {
544ebccf1e3SJoseph Koshy 			if (has_unitmask == 0)
545aa342b1fSJoseph Koshy 				return (-1);
546ebccf1e3SJoseph Koshy 			unitmask = 0;
547ebccf1e3SJoseph Koshy 			q = strchr(p, '=');
548ebccf1e3SJoseph Koshy 			if (*++q == '\0') /* skip '=' */
549aa342b1fSJoseph Koshy 				return (-1);
550ebccf1e3SJoseph Koshy 
551ebccf1e3SJoseph Koshy 			while ((c = tolower(*q++)) != 0)
552ebccf1e3SJoseph Koshy 				if (c == 'm')
553f263522aSJoseph Koshy 					unitmask |= AMD_PMC_UNITMASK_M;
554ebccf1e3SJoseph Koshy 				else if (c == 'o')
555f263522aSJoseph Koshy 					unitmask |= AMD_PMC_UNITMASK_O;
556ebccf1e3SJoseph Koshy 				else if (c == 'e')
557f263522aSJoseph Koshy 					unitmask |= AMD_PMC_UNITMASK_E;
558ebccf1e3SJoseph Koshy 				else if (c == 's')
559f263522aSJoseph Koshy 					unitmask |= AMD_PMC_UNITMASK_S;
560ebccf1e3SJoseph Koshy 				else if (c == 'i')
561f263522aSJoseph Koshy 					unitmask |= AMD_PMC_UNITMASK_I;
562ebccf1e3SJoseph Koshy 				else if (c == '+')
563ebccf1e3SJoseph Koshy 					continue;
564ebccf1e3SJoseph Koshy 				else
565aa342b1fSJoseph Koshy 					return (-1);
566ebccf1e3SJoseph Koshy 
567ebccf1e3SJoseph Koshy 			if (unitmask == 0)
568aa342b1fSJoseph Koshy 				return (-1);
569ebccf1e3SJoseph Koshy 
570ebccf1e3SJoseph Koshy 		} else if (KWMATCH(p, K7_KW_USR)) {
571ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_USER;
572ebccf1e3SJoseph Koshy 		} else
573aa342b1fSJoseph Koshy 			return (-1);
574ebccf1e3SJoseph Koshy 	}
575ebccf1e3SJoseph Koshy 
576ebccf1e3SJoseph Koshy 	if (has_unitmask) {
577ebccf1e3SJoseph Koshy 		pmc_config->pm_caps |= PMC_CAP_QUALIFIER;
578f263522aSJoseph Koshy 		pmc_config->pm_md.pm_amd.pm_amd_config |=
579f263522aSJoseph Koshy 		    AMD_PMC_TO_UNITMASK(unitmask);
580ebccf1e3SJoseph Koshy 	}
581ebccf1e3SJoseph Koshy 
582aa342b1fSJoseph Koshy 	return (0);
583ebccf1e3SJoseph Koshy 
584ebccf1e3SJoseph Koshy }
585ebccf1e3SJoseph Koshy 
586f263522aSJoseph Koshy #endif
587f263522aSJoseph Koshy 
58886a65549SJoseph Koshy #if defined(__amd64__) || defined(__i386__)
589f263522aSJoseph Koshy 
590f263522aSJoseph Koshy /*
5910cfab8ddSJoseph Koshy  * Intel Core (Family 6, Model E) PMCs.
5920cfab8ddSJoseph Koshy  */
5930cfab8ddSJoseph Koshy 
5940cfab8ddSJoseph Koshy static struct pmc_event_alias core_aliases[] = {
5950cfab8ddSJoseph Koshy 	EV_ALIAS("branches",		"iap-br-instr-ret"),
5960cfab8ddSJoseph Koshy 	EV_ALIAS("branch-mispredicts",	"iap-br-mispred-ret"),
5970cfab8ddSJoseph Koshy 	EV_ALIAS("cycles",		"tsc-tsc"),
5980cfab8ddSJoseph Koshy 	EV_ALIAS("ic-misses",		"iap-icache-misses"),
5990cfab8ddSJoseph Koshy 	EV_ALIAS("instructions",	"iap-instr-ret"),
6000cfab8ddSJoseph Koshy 	EV_ALIAS("interrupts",		"iap-core-hw-int-rx"),
6010cfab8ddSJoseph Koshy 	EV_ALIAS("unhalted-cycles",	"iap-unhalted-core-cycles"),
6020cfab8ddSJoseph Koshy 	EV_ALIAS(NULL, NULL)
6030cfab8ddSJoseph Koshy };
6040cfab8ddSJoseph Koshy 
6050cfab8ddSJoseph Koshy /*
6060cfab8ddSJoseph Koshy  * Intel Core2 (Family 6, Model F), Core2Extreme (Family 6, Model 17H)
6070cfab8ddSJoseph Koshy  * and Atom (Family 6, model 1CH) PMCs.
608791f5d5bSJoseph Koshy  *
609791f5d5bSJoseph Koshy  * We map aliases to events on the fixed-function counters if these
610791f5d5bSJoseph Koshy  * are present.  Note that not all CPUs in this family contain fixed-function
611791f5d5bSJoseph Koshy  * counters.
6120cfab8ddSJoseph Koshy  */
6130cfab8ddSJoseph Koshy 
6140cfab8ddSJoseph Koshy static struct pmc_event_alias core2_aliases[] = {
6150cfab8ddSJoseph Koshy 	EV_ALIAS("branches",		"iap-br-inst-retired.any"),
6160cfab8ddSJoseph Koshy 	EV_ALIAS("branch-mispredicts",	"iap-br-inst-retired.mispred"),
6170cfab8ddSJoseph Koshy 	EV_ALIAS("cycles",		"tsc-tsc"),
6180cfab8ddSJoseph Koshy 	EV_ALIAS("ic-misses",		"iap-l1i-misses"),
6190cfab8ddSJoseph Koshy 	EV_ALIAS("instructions",	"iaf-instr-retired.any"),
6200cfab8ddSJoseph Koshy 	EV_ALIAS("interrupts",		"iap-hw-int-rcv"),
6210cfab8ddSJoseph Koshy 	EV_ALIAS("unhalted-cycles",	"iaf-cpu-clk-unhalted.core"),
6220cfab8ddSJoseph Koshy 	EV_ALIAS(NULL, NULL)
6230cfab8ddSJoseph Koshy };
624791f5d5bSJoseph Koshy 
625791f5d5bSJoseph Koshy static struct pmc_event_alias core2_aliases_without_iaf[] = {
626791f5d5bSJoseph Koshy 	EV_ALIAS("branches",		"iap-br-inst-retired.any"),
627791f5d5bSJoseph Koshy 	EV_ALIAS("branch-mispredicts",	"iap-br-inst-retired.mispred"),
628791f5d5bSJoseph Koshy 	EV_ALIAS("cycles",		"tsc-tsc"),
629791f5d5bSJoseph Koshy 	EV_ALIAS("ic-misses",		"iap-l1i-misses"),
630791f5d5bSJoseph Koshy 	EV_ALIAS("instructions",	"iap-inst-retired.any_p"),
631791f5d5bSJoseph Koshy 	EV_ALIAS("interrupts",		"iap-hw-int-rcv"),
632791f5d5bSJoseph Koshy 	EV_ALIAS("unhalted-cycles",	"iap-cpu-clk-unhalted.core_p"),
633791f5d5bSJoseph Koshy 	EV_ALIAS(NULL, NULL)
634791f5d5bSJoseph Koshy };
635791f5d5bSJoseph Koshy 
6360cfab8ddSJoseph Koshy #define	atom_aliases			core2_aliases
637791f5d5bSJoseph Koshy #define	atom_aliases_without_iaf	core2_aliases_without_iaf
638e8f021a3SHiren Panchasara #define	atom_silvermont_aliases		core2_aliases
639e8f021a3SHiren Panchasara #define	atom_silvermont_aliases_without_iaf	core2_aliases_without_iaf
640597979c4SJeff Roberson #define corei7_aliases			core2_aliases
641791f5d5bSJoseph Koshy #define corei7_aliases_without_iaf	core2_aliases_without_iaf
64249fe48abSKonstantin Belousov #define nehalem_ex_aliases		core2_aliases
64349fe48abSKonstantin Belousov #define nehalem_ex_aliases_without_iaf	core2_aliases_without_iaf
644cc0c1555SSean Bruno #define haswell_aliases			core2_aliases
645cc0c1555SSean Bruno #define haswell_aliases_without_iaf	core2_aliases_without_iaf
646d95b3509SRandall Stewart #define haswell_xeon_aliases			core2_aliases
647d95b3509SRandall Stewart #define haswell_xeon_aliases_without_iaf	core2_aliases_without_iaf
6481e862e5aSFabien Thomas #define ivybridge_aliases		core2_aliases
6491e862e5aSFabien Thomas #define ivybridge_aliases_without_iaf	core2_aliases_without_iaf
6503f929d8cSSean Bruno #define ivybridge_xeon_aliases		core2_aliases
6513f929d8cSSean Bruno #define ivybridge_xeon_aliases_without_iaf	core2_aliases_without_iaf
65278d763a2SDavide Italiano #define sandybridge_aliases		core2_aliases
65378d763a2SDavide Italiano #define sandybridge_aliases_without_iaf	core2_aliases_without_iaf
654fabe02f5SSean Bruno #define sandybridge_xeon_aliases	core2_aliases
655fabe02f5SSean Bruno #define sandybridge_xeon_aliases_without_iaf	core2_aliases_without_iaf
6561fa7f10bSFabien Thomas #define westmere_aliases		core2_aliases
6571fa7f10bSFabien Thomas #define westmere_aliases_without_iaf	core2_aliases_without_iaf
65849fe48abSKonstantin Belousov #define westmere_ex_aliases		core2_aliases
65949fe48abSKonstantin Belousov #define westmere_ex_aliases_without_iaf	core2_aliases_without_iaf
6600cfab8ddSJoseph Koshy 
6610cfab8ddSJoseph Koshy #define	IAF_KW_OS		"os"
6620cfab8ddSJoseph Koshy #define	IAF_KW_USR		"usr"
6630cfab8ddSJoseph Koshy #define	IAF_KW_ANYTHREAD	"anythread"
6640cfab8ddSJoseph Koshy 
6650cfab8ddSJoseph Koshy /*
6660cfab8ddSJoseph Koshy  * Parse an event specifier for Intel fixed function counters.
6670cfab8ddSJoseph Koshy  */
6680cfab8ddSJoseph Koshy static int
6690cfab8ddSJoseph Koshy iaf_allocate_pmc(enum pmc_event pe, char *ctrspec,
6700cfab8ddSJoseph Koshy     struct pmc_op_pmcallocate *pmc_config)
6710cfab8ddSJoseph Koshy {
6720cfab8ddSJoseph Koshy 	char *p;
6730cfab8ddSJoseph Koshy 
6740cfab8ddSJoseph Koshy 	(void) pe;
6750cfab8ddSJoseph Koshy 
6760cfab8ddSJoseph Koshy 	pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE);
6770cfab8ddSJoseph Koshy 	pmc_config->pm_md.pm_iaf.pm_iaf_flags = 0;
6780cfab8ddSJoseph Koshy 
6790cfab8ddSJoseph Koshy 	while ((p = strsep(&ctrspec, ",")) != NULL) {
6800cfab8ddSJoseph Koshy 		if (KWMATCH(p, IAF_KW_OS))
6810cfab8ddSJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_SYSTEM;
6820cfab8ddSJoseph Koshy 		else if (KWMATCH(p, IAF_KW_USR))
6830cfab8ddSJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_USER;
6840cfab8ddSJoseph Koshy 		else if (KWMATCH(p, IAF_KW_ANYTHREAD))
6850cfab8ddSJoseph Koshy 			pmc_config->pm_md.pm_iaf.pm_iaf_flags |= IAF_ANY;
6860cfab8ddSJoseph Koshy 		else
6870cfab8ddSJoseph Koshy 			return (-1);
6880cfab8ddSJoseph Koshy 	}
6890cfab8ddSJoseph Koshy 
6900cfab8ddSJoseph Koshy 	return (0);
6910cfab8ddSJoseph Koshy }
6920cfab8ddSJoseph Koshy 
6930cfab8ddSJoseph Koshy /*
6940cfab8ddSJoseph Koshy  * Core/Core2 support.
6950cfab8ddSJoseph Koshy  */
6960cfab8ddSJoseph Koshy 
6970cfab8ddSJoseph Koshy #define	IAP_KW_AGENT		"agent"
6980cfab8ddSJoseph Koshy #define	IAP_KW_ANYTHREAD	"anythread"
6990cfab8ddSJoseph Koshy #define	IAP_KW_CACHESTATE	"cachestate"
7000cfab8ddSJoseph Koshy #define	IAP_KW_CMASK		"cmask"
7010cfab8ddSJoseph Koshy #define	IAP_KW_CORE		"core"
7020cfab8ddSJoseph Koshy #define	IAP_KW_EDGE		"edge"
7030cfab8ddSJoseph Koshy #define	IAP_KW_INV		"inv"
7040cfab8ddSJoseph Koshy #define	IAP_KW_OS		"os"
7050cfab8ddSJoseph Koshy #define	IAP_KW_PREFETCH		"prefetch"
7060cfab8ddSJoseph Koshy #define	IAP_KW_SNOOPRESPONSE	"snoopresponse"
7070cfab8ddSJoseph Koshy #define	IAP_KW_SNOOPTYPE	"snooptype"
7080cfab8ddSJoseph Koshy #define	IAP_KW_TRANSITION	"trans"
7090cfab8ddSJoseph Koshy #define	IAP_KW_USR		"usr"
7101fa7f10bSFabien Thomas #define	IAP_KW_RSP		"rsp"
7110cfab8ddSJoseph Koshy 
7120cfab8ddSJoseph Koshy static struct pmc_masks iap_core_mask[] = {
7130cfab8ddSJoseph Koshy 	PMCMASK(all,	(0x3 << 14)),
7140cfab8ddSJoseph Koshy 	PMCMASK(this,	(0x1 << 14)),
7150cfab8ddSJoseph Koshy 	NULLMASK
7160cfab8ddSJoseph Koshy };
7170cfab8ddSJoseph Koshy 
7180cfab8ddSJoseph Koshy static struct pmc_masks iap_agent_mask[] = {
7190cfab8ddSJoseph Koshy 	PMCMASK(this,	0),
7200cfab8ddSJoseph Koshy 	PMCMASK(any,	(0x1 << 13)),
7210cfab8ddSJoseph Koshy 	NULLMASK
7220cfab8ddSJoseph Koshy };
7230cfab8ddSJoseph Koshy 
7240cfab8ddSJoseph Koshy static struct pmc_masks iap_prefetch_mask[] = {
7250cfab8ddSJoseph Koshy 	PMCMASK(both,		(0x3 << 12)),
7260cfab8ddSJoseph Koshy 	PMCMASK(only,		(0x1 << 12)),
7270cfab8ddSJoseph Koshy 	PMCMASK(exclude,	0),
7280cfab8ddSJoseph Koshy 	NULLMASK
7290cfab8ddSJoseph Koshy };
7300cfab8ddSJoseph Koshy 
7310cfab8ddSJoseph Koshy static struct pmc_masks iap_cachestate_mask[] = {
7320cfab8ddSJoseph Koshy 	PMCMASK(i,		(1 <<  8)),
7330cfab8ddSJoseph Koshy 	PMCMASK(s,		(1 <<  9)),
7340cfab8ddSJoseph Koshy 	PMCMASK(e,		(1 << 10)),
7350cfab8ddSJoseph Koshy 	PMCMASK(m,		(1 << 11)),
7360cfab8ddSJoseph Koshy 	NULLMASK
7370cfab8ddSJoseph Koshy };
7380cfab8ddSJoseph Koshy 
7390cfab8ddSJoseph Koshy static struct pmc_masks iap_snoopresponse_mask[] = {
7400cfab8ddSJoseph Koshy 	PMCMASK(clean,		(1 << 8)),
7410cfab8ddSJoseph Koshy 	PMCMASK(hit,		(1 << 9)),
7420cfab8ddSJoseph Koshy 	PMCMASK(hitm,		(1 << 11)),
7430cfab8ddSJoseph Koshy 	NULLMASK
7440cfab8ddSJoseph Koshy };
7450cfab8ddSJoseph Koshy 
7460cfab8ddSJoseph Koshy static struct pmc_masks iap_snooptype_mask[] = {
7470cfab8ddSJoseph Koshy 	PMCMASK(cmp2s,		(1 << 8)),
7480cfab8ddSJoseph Koshy 	PMCMASK(cmp2i,		(1 << 9)),
7490cfab8ddSJoseph Koshy 	NULLMASK
7500cfab8ddSJoseph Koshy };
7510cfab8ddSJoseph Koshy 
7520cfab8ddSJoseph Koshy static struct pmc_masks iap_transition_mask[] = {
7530cfab8ddSJoseph Koshy 	PMCMASK(any,		0x00),
7540cfab8ddSJoseph Koshy 	PMCMASK(frequency,	0x10),
7550cfab8ddSJoseph Koshy 	NULLMASK
7560cfab8ddSJoseph Koshy };
7570cfab8ddSJoseph Koshy 
7581e862e5aSFabien Thomas static struct pmc_masks iap_rsp_mask_i7_wm[] = {
7591fa7f10bSFabien Thomas 	PMCMASK(DMND_DATA_RD,		(1 <<  0)),
7601fa7f10bSFabien Thomas 	PMCMASK(DMND_RFO,		(1 <<  1)),
7611fa7f10bSFabien Thomas 	PMCMASK(DMND_IFETCH,		(1 <<  2)),
7621fa7f10bSFabien Thomas 	PMCMASK(WB,			(1 <<  3)),
7631fa7f10bSFabien Thomas 	PMCMASK(PF_DATA_RD,		(1 <<  4)),
7641fa7f10bSFabien Thomas 	PMCMASK(PF_RFO,			(1 <<  5)),
7651fa7f10bSFabien Thomas 	PMCMASK(PF_IFETCH,		(1 <<  6)),
7661fa7f10bSFabien Thomas 	PMCMASK(OTHER,			(1 <<  7)),
7671fa7f10bSFabien Thomas 	PMCMASK(UNCORE_HIT,		(1 <<  8)),
7681fa7f10bSFabien Thomas 	PMCMASK(OTHER_CORE_HIT_SNP,	(1 <<  9)),
7691fa7f10bSFabien Thomas 	PMCMASK(OTHER_CORE_HITM,	(1 << 10)),
7701fa7f10bSFabien Thomas 	PMCMASK(REMOTE_CACHE_FWD,	(1 << 12)),
7711fa7f10bSFabien Thomas 	PMCMASK(REMOTE_DRAM,		(1 << 13)),
7721fa7f10bSFabien Thomas 	PMCMASK(LOCAL_DRAM,		(1 << 14)),
7731fa7f10bSFabien Thomas 	PMCMASK(NON_DRAM,		(1 << 15)),
7741fa7f10bSFabien Thomas 	NULLMASK
7751fa7f10bSFabien Thomas };
7761fa7f10bSFabien Thomas 
777fabe02f5SSean Bruno static struct pmc_masks iap_rsp_mask_sb_sbx_ib[] = {
7781e862e5aSFabien Thomas 	PMCMASK(REQ_DMND_DATA_RD,	(1ULL <<  0)),
7791e862e5aSFabien Thomas 	PMCMASK(REQ_DMND_RFO,		(1ULL <<  1)),
7801e862e5aSFabien Thomas 	PMCMASK(REQ_DMND_IFETCH,	(1ULL <<  2)),
7811e862e5aSFabien Thomas 	PMCMASK(REQ_WB,			(1ULL <<  3)),
7821e862e5aSFabien Thomas 	PMCMASK(REQ_PF_DATA_RD,		(1ULL <<  4)),
7831e862e5aSFabien Thomas 	PMCMASK(REQ_PF_RFO,		(1ULL <<  5)),
7841e862e5aSFabien Thomas 	PMCMASK(REQ_PF_IFETCH,		(1ULL <<  6)),
7851e862e5aSFabien Thomas 	PMCMASK(REQ_PF_LLC_DATA_RD,	(1ULL <<  7)),
7861e862e5aSFabien Thomas 	PMCMASK(REQ_PF_LLC_RFO,		(1ULL <<  8)),
7871e862e5aSFabien Thomas 	PMCMASK(REQ_PF_LLC_IFETCH,	(1ULL <<  9)),
7881e862e5aSFabien Thomas 	PMCMASK(REQ_BUS_LOCKS,		(1ULL << 10)),
7891e862e5aSFabien Thomas 	PMCMASK(REQ_STRM_ST,		(1ULL << 11)),
7901e862e5aSFabien Thomas 	PMCMASK(REQ_OTHER,		(1ULL << 15)),
7911e862e5aSFabien Thomas 	PMCMASK(RES_ANY,		(1ULL << 16)),
7921e862e5aSFabien Thomas 	PMCMASK(RES_SUPPLIER_SUPP,	(1ULL << 17)),
7931e862e5aSFabien Thomas 	PMCMASK(RES_SUPPLIER_LLC_HITM,	(1ULL << 18)),
7941e862e5aSFabien Thomas 	PMCMASK(RES_SUPPLIER_LLC_HITE,	(1ULL << 19)),
7951e862e5aSFabien Thomas 	PMCMASK(RES_SUPPLIER_LLC_HITS,	(1ULL << 20)),
7961e862e5aSFabien Thomas 	PMCMASK(RES_SUPPLIER_LLC_HITF,	(1ULL << 21)),
7971e862e5aSFabien Thomas 	PMCMASK(RES_SUPPLIER_LOCAL,	(1ULL << 22)),
798cdfd0cc8SSean Bruno 	PMCMASK(RES_SNOOP_SNP_NONE,	(1ULL << 31)),
7991e862e5aSFabien Thomas 	PMCMASK(RES_SNOOP_SNP_NO_NEEDED,(1ULL << 32)),
8001e862e5aSFabien Thomas 	PMCMASK(RES_SNOOP_SNP_MISS,	(1ULL << 33)),
8011e862e5aSFabien Thomas 	PMCMASK(RES_SNOOP_HIT_NO_FWD,	(1ULL << 34)),
8021e862e5aSFabien Thomas 	PMCMASK(RES_SNOOP_HIT_FWD,	(1ULL << 35)),
8031e862e5aSFabien Thomas 	PMCMASK(RES_SNOOP_HITM,		(1ULL << 36)),
8041e862e5aSFabien Thomas 	PMCMASK(RES_NON_DRAM,		(1ULL << 37)),
8051e862e5aSFabien Thomas 	NULLMASK
8061e862e5aSFabien Thomas };
8071e862e5aSFabien Thomas 
808cc0c1555SSean Bruno static struct pmc_masks iap_rsp_mask_haswell[] = {
809cc0c1555SSean Bruno 	PMCMASK(REQ_DMND_DATA_RD,	(1ULL <<  0)),
810cc0c1555SSean Bruno 	PMCMASK(REQ_DMND_RFO,		(1ULL <<  1)),
811cc0c1555SSean Bruno 	PMCMASK(REQ_DMND_IFETCH,	(1ULL <<  2)),
812cc0c1555SSean Bruno 	PMCMASK(REQ_PF_DATA_RD,		(1ULL <<  4)),
813cc0c1555SSean Bruno 	PMCMASK(REQ_PF_RFO,		(1ULL <<  5)),
814cc0c1555SSean Bruno 	PMCMASK(REQ_PF_IFETCH,		(1ULL <<  6)),
815cc0c1555SSean Bruno 	PMCMASK(REQ_OTHER,		(1ULL << 15)),
816cc0c1555SSean Bruno 	PMCMASK(RES_ANY,		(1ULL << 16)),
817cc0c1555SSean Bruno 	PMCMASK(RES_SUPPLIER_SUPP,	(1ULL << 17)),
818cc0c1555SSean Bruno 	PMCMASK(RES_SUPPLIER_LLC_HITM,	(1ULL << 18)),
819cc0c1555SSean Bruno 	PMCMASK(RES_SUPPLIER_LLC_HITE,	(1ULL << 19)),
820cc0c1555SSean Bruno 	PMCMASK(RES_SUPPLIER_LLC_HITS,	(1ULL << 20)),
821cc0c1555SSean Bruno 	PMCMASK(RES_SUPPLIER_LLC_HITF,	(1ULL << 21)),
822cc0c1555SSean Bruno 	PMCMASK(RES_SUPPLIER_LOCAL,	(1ULL << 22)),
823cc0c1555SSean Bruno 	PMCMASK(RES_SNOOP_SNP_NONE,	(1ULL << 31)),
824cc0c1555SSean Bruno 	PMCMASK(RES_SNOOP_SNP_NO_NEEDED,(1ULL << 32)),
825cc0c1555SSean Bruno 	PMCMASK(RES_SNOOP_SNP_MISS,	(1ULL << 33)),
826cc0c1555SSean Bruno 	PMCMASK(RES_SNOOP_HIT_NO_FWD,	(1ULL << 34)),
827cc0c1555SSean Bruno 	PMCMASK(RES_SNOOP_HIT_FWD,	(1ULL << 35)),
828cc0c1555SSean Bruno 	PMCMASK(RES_SNOOP_HITM,		(1ULL << 36)),
829cc0c1555SSean Bruno 	PMCMASK(RES_NON_DRAM,		(1ULL << 37)),
830cc0c1555SSean Bruno 	NULLMASK
831cc0c1555SSean Bruno };
832cc0c1555SSean Bruno 
8330cfab8ddSJoseph Koshy static int
8340cfab8ddSJoseph Koshy iap_allocate_pmc(enum pmc_event pe, char *ctrspec,
8350cfab8ddSJoseph Koshy     struct pmc_op_pmcallocate *pmc_config)
8360cfab8ddSJoseph Koshy {
8370cfab8ddSJoseph Koshy 	char *e, *p, *q;
8381e862e5aSFabien Thomas 	uint64_t cachestate, evmask, rsp;
8390cfab8ddSJoseph Koshy 	int count, n;
8400cfab8ddSJoseph Koshy 
8410cfab8ddSJoseph Koshy 	pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE |
8420cfab8ddSJoseph Koshy 	    PMC_CAP_QUALIFIER);
8430cfab8ddSJoseph Koshy 	pmc_config->pm_md.pm_iap.pm_iap_config = 0;
8440cfab8ddSJoseph Koshy 
8451fa7f10bSFabien Thomas 	cachestate = evmask = rsp = 0;
8460cfab8ddSJoseph Koshy 
8470cfab8ddSJoseph Koshy 	/* Parse additional modifiers if present */
8480cfab8ddSJoseph Koshy 	while ((p = strsep(&ctrspec, ",")) != NULL) {
8490cfab8ddSJoseph Koshy 
8500cfab8ddSJoseph Koshy 		n = 0;
8510cfab8ddSJoseph Koshy 		if (KWPREFIXMATCH(p, IAP_KW_CMASK "=")) {
8520cfab8ddSJoseph Koshy 			q = strchr(p, '=');
8530cfab8ddSJoseph Koshy 			if (*++q == '\0') /* skip '=' */
8540cfab8ddSJoseph Koshy 				return (-1);
8550cfab8ddSJoseph Koshy 			count = strtol(q, &e, 0);
8560cfab8ddSJoseph Koshy 			if (e == q || *e != '\0')
8570cfab8ddSJoseph Koshy 				return (-1);
8580cfab8ddSJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_THRESHOLD;
8590cfab8ddSJoseph Koshy 			pmc_config->pm_md.pm_iap.pm_iap_config |=
8600cfab8ddSJoseph Koshy 			    IAP_CMASK(count);
8610cfab8ddSJoseph Koshy 		} else if (KWMATCH(p, IAP_KW_EDGE)) {
8620cfab8ddSJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_EDGE;
8630cfab8ddSJoseph Koshy 		} else if (KWMATCH(p, IAP_KW_INV)) {
8640cfab8ddSJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_INVERT;
8650cfab8ddSJoseph Koshy 		} else if (KWMATCH(p, IAP_KW_OS)) {
8660cfab8ddSJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_SYSTEM;
8670cfab8ddSJoseph Koshy 		} else if (KWMATCH(p, IAP_KW_USR)) {
8680cfab8ddSJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_USER;
8690cfab8ddSJoseph Koshy 		} else if (KWMATCH(p, IAP_KW_ANYTHREAD)) {
8700cfab8ddSJoseph Koshy 			pmc_config->pm_md.pm_iap.pm_iap_config |= IAP_ANY;
871b47ea38eSJoseph Koshy 		} else if (KWPREFIXMATCH(p, IAP_KW_CORE "=")) {
8720cfab8ddSJoseph Koshy 			n = pmc_parse_mask(iap_core_mask, p, &evmask);
8730cfab8ddSJoseph Koshy 			if (n != 1)
8740cfab8ddSJoseph Koshy 				return (-1);
875b47ea38eSJoseph Koshy 		} else if (KWPREFIXMATCH(p, IAP_KW_AGENT "=")) {
8760cfab8ddSJoseph Koshy 			n = pmc_parse_mask(iap_agent_mask, p, &evmask);
8770cfab8ddSJoseph Koshy 			if (n != 1)
8780cfab8ddSJoseph Koshy 				return (-1);
879b47ea38eSJoseph Koshy 		} else if (KWPREFIXMATCH(p, IAP_KW_PREFETCH "=")) {
8800cfab8ddSJoseph Koshy 			n = pmc_parse_mask(iap_prefetch_mask, p, &evmask);
8810cfab8ddSJoseph Koshy 			if (n != 1)
8820cfab8ddSJoseph Koshy 				return (-1);
883b47ea38eSJoseph Koshy 		} else if (KWPREFIXMATCH(p, IAP_KW_CACHESTATE "=")) {
8840cfab8ddSJoseph Koshy 			n = pmc_parse_mask(iap_cachestate_mask, p, &cachestate);
8850cfab8ddSJoseph Koshy 		} else if (cpu_info.pm_cputype == PMC_CPU_INTEL_CORE &&
886b47ea38eSJoseph Koshy 		    KWPREFIXMATCH(p, IAP_KW_TRANSITION "=")) {
8870cfab8ddSJoseph Koshy 			n = pmc_parse_mask(iap_transition_mask, p, &evmask);
8880cfab8ddSJoseph Koshy 			if (n != 1)
8890cfab8ddSJoseph Koshy 				return (-1);
8900cfab8ddSJoseph Koshy 		} else if (cpu_info.pm_cputype == PMC_CPU_INTEL_ATOM ||
891e8f021a3SHiren Panchasara 		    cpu_info.pm_cputype == PMC_CPU_INTEL_ATOM_SILVERMONT ||
892b4d091f3SJoseph Koshy 		    cpu_info.pm_cputype == PMC_CPU_INTEL_CORE2 ||
8931fa7f10bSFabien Thomas 		    cpu_info.pm_cputype == PMC_CPU_INTEL_CORE2EXTREME) {
894b47ea38eSJoseph Koshy 			if (KWPREFIXMATCH(p, IAP_KW_SNOOPRESPONSE "=")) {
8950cfab8ddSJoseph Koshy 				n = pmc_parse_mask(iap_snoopresponse_mask, p,
8960cfab8ddSJoseph Koshy 				    &evmask);
897b47ea38eSJoseph Koshy 			} else if (KWPREFIXMATCH(p, IAP_KW_SNOOPTYPE "=")) {
8980cfab8ddSJoseph Koshy 				n = pmc_parse_mask(iap_snooptype_mask, p,
8990cfab8ddSJoseph Koshy 				    &evmask);
9000cfab8ddSJoseph Koshy 			} else
9010cfab8ddSJoseph Koshy 				return (-1);
9021fa7f10bSFabien Thomas 		} else if (cpu_info.pm_cputype == PMC_CPU_INTEL_COREI7 ||
90349fe48abSKonstantin Belousov 		    cpu_info.pm_cputype == PMC_CPU_INTEL_WESTMERE ||
90449fe48abSKonstantin Belousov 		    cpu_info.pm_cputype == PMC_CPU_INTEL_NEHALEM_EX ||
90549fe48abSKonstantin Belousov 		    cpu_info.pm_cputype == PMC_CPU_INTEL_WESTMERE_EX) {
9061fa7f10bSFabien Thomas 			if (KWPREFIXMATCH(p, IAP_KW_RSP "=")) {
9071e862e5aSFabien Thomas 				n = pmc_parse_mask(iap_rsp_mask_i7_wm, p, &rsp);
9081e862e5aSFabien Thomas 			} else
9091e862e5aSFabien Thomas 				return (-1);
9101e862e5aSFabien Thomas 		} else if (cpu_info.pm_cputype == PMC_CPU_INTEL_SANDYBRIDGE ||
911fabe02f5SSean Bruno 		    cpu_info.pm_cputype == PMC_CPU_INTEL_SANDYBRIDGE_XEON ||
9123f929d8cSSean Bruno 			cpu_info.pm_cputype == PMC_CPU_INTEL_IVYBRIDGE ||
9133f929d8cSSean Bruno 			cpu_info.pm_cputype == PMC_CPU_INTEL_IVYBRIDGE_XEON ) {
9141e862e5aSFabien Thomas 			if (KWPREFIXMATCH(p, IAP_KW_RSP "=")) {
915fabe02f5SSean Bruno 				n = pmc_parse_mask(iap_rsp_mask_sb_sbx_ib, p, &rsp);
9161fa7f10bSFabien Thomas 			} else
9171fa7f10bSFabien Thomas 				return (-1);
918d95b3509SRandall Stewart 		} else if (cpu_info.pm_cputype == PMC_CPU_INTEL_HASWELL ||
919d95b3509SRandall Stewart 			cpu_info.pm_cputype == PMC_CPU_INTEL_HASWELL_XEON) {
920cc0c1555SSean Bruno 			if (KWPREFIXMATCH(p, IAP_KW_RSP "=")) {
921cc0c1555SSean Bruno 				n = pmc_parse_mask(iap_rsp_mask_haswell, p, &rsp);
922cc0c1555SSean Bruno 			} else
923cc0c1555SSean Bruno 				return (-1);
9240cfab8ddSJoseph Koshy 		} else
9250cfab8ddSJoseph Koshy 			return (-1);
9260cfab8ddSJoseph Koshy 
9270cfab8ddSJoseph Koshy 		if (n < 0)	/* Parsing failed. */
9280cfab8ddSJoseph Koshy 			return (-1);
9290cfab8ddSJoseph Koshy 	}
9300cfab8ddSJoseph Koshy 
9310cfab8ddSJoseph Koshy 	pmc_config->pm_md.pm_iap.pm_iap_config |= evmask;
9320cfab8ddSJoseph Koshy 
9330cfab8ddSJoseph Koshy 	/*
9340cfab8ddSJoseph Koshy 	 * If the event requires a 'cachestate' qualifier but was not
9350cfab8ddSJoseph Koshy 	 * specified by the user, use a sensible default.
9360cfab8ddSJoseph Koshy 	 */
9370cfab8ddSJoseph Koshy 	switch (pe) {
9380cfab8ddSJoseph Koshy 	case PMC_EV_IAP_EVENT_28H: /* Core, Core2, Atom */
9390cfab8ddSJoseph Koshy 	case PMC_EV_IAP_EVENT_29H: /* Core, Core2, Atom */
9400cfab8ddSJoseph Koshy 	case PMC_EV_IAP_EVENT_2AH: /* Core, Core2, Atom */
9410cfab8ddSJoseph Koshy 	case PMC_EV_IAP_EVENT_2BH: /* Atom, Core2 */
9420cfab8ddSJoseph Koshy 	case PMC_EV_IAP_EVENT_2EH: /* Core, Core2, Atom */
9430cfab8ddSJoseph Koshy 	case PMC_EV_IAP_EVENT_30H: /* Core, Core2, Atom */
9440cfab8ddSJoseph Koshy 	case PMC_EV_IAP_EVENT_32H: /* Core */
9450cfab8ddSJoseph Koshy 	case PMC_EV_IAP_EVENT_40H: /* Core */
9460cfab8ddSJoseph Koshy 	case PMC_EV_IAP_EVENT_41H: /* Core */
9470cfab8ddSJoseph Koshy 	case PMC_EV_IAP_EVENT_42H: /* Core, Core2, Atom */
9480cfab8ddSJoseph Koshy 		if (cachestate == 0)
9490cfab8ddSJoseph Koshy 			cachestate = (0xF << 8);
950aa1b887bSRyan Stone 		break;
951aa1b887bSRyan Stone 	case PMC_EV_IAP_EVENT_77H: /* Atom */
952aa1b887bSRyan Stone 		/* IAP_EVENT_77H only accepts a cachestate qualifier on the
953aa1b887bSRyan Stone 		 * Atom processor
954aa1b887bSRyan Stone 		 */
955aa1b887bSRyan Stone 		if(cpu_info.pm_cputype == PMC_CPU_INTEL_ATOM && cachestate == 0)
956aa1b887bSRyan Stone 			cachestate = (0xF << 8);
957aa1b887bSRyan Stone 	    break;
9580cfab8ddSJoseph Koshy 	default:
9590cfab8ddSJoseph Koshy 		break;
9600cfab8ddSJoseph Koshy 	}
9610cfab8ddSJoseph Koshy 
9620cfab8ddSJoseph Koshy 	pmc_config->pm_md.pm_iap.pm_iap_config |= cachestate;
9631fa7f10bSFabien Thomas 	pmc_config->pm_md.pm_iap.pm_iap_rsp = rsp;
9641fa7f10bSFabien Thomas 
9651fa7f10bSFabien Thomas 	return (0);
9661fa7f10bSFabien Thomas }
9671fa7f10bSFabien Thomas 
9681fa7f10bSFabien Thomas /*
9691fa7f10bSFabien Thomas  * Intel Uncore.
9701fa7f10bSFabien Thomas  */
9711fa7f10bSFabien Thomas 
9721fa7f10bSFabien Thomas static int
9731fa7f10bSFabien Thomas ucf_allocate_pmc(enum pmc_event pe, char *ctrspec,
9741fa7f10bSFabien Thomas     struct pmc_op_pmcallocate *pmc_config)
9751fa7f10bSFabien Thomas {
9761fa7f10bSFabien Thomas 	(void) pe;
9771fa7f10bSFabien Thomas 	(void) ctrspec;
9781fa7f10bSFabien Thomas 
9791fa7f10bSFabien Thomas 	pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE);
9801fa7f10bSFabien Thomas 	pmc_config->pm_md.pm_ucf.pm_ucf_flags = 0;
9811fa7f10bSFabien Thomas 
9821fa7f10bSFabien Thomas 	return (0);
9831fa7f10bSFabien Thomas }
9841fa7f10bSFabien Thomas 
9851fa7f10bSFabien Thomas #define	UCP_KW_CMASK		"cmask"
9861fa7f10bSFabien Thomas #define	UCP_KW_EDGE		"edge"
9871fa7f10bSFabien Thomas #define	UCP_KW_INV		"inv"
9881fa7f10bSFabien Thomas 
9891fa7f10bSFabien Thomas static int
9901fa7f10bSFabien Thomas ucp_allocate_pmc(enum pmc_event pe, char *ctrspec,
9911fa7f10bSFabien Thomas     struct pmc_op_pmcallocate *pmc_config)
9921fa7f10bSFabien Thomas {
9931fa7f10bSFabien Thomas 	char *e, *p, *q;
9941fa7f10bSFabien Thomas 	int count, n;
9951fa7f10bSFabien Thomas 
9961fa7f10bSFabien Thomas 	(void) pe;
9971fa7f10bSFabien Thomas 
9981fa7f10bSFabien Thomas 	pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE |
9991fa7f10bSFabien Thomas 	    PMC_CAP_QUALIFIER);
10001fa7f10bSFabien Thomas 	pmc_config->pm_md.pm_ucp.pm_ucp_config = 0;
10011fa7f10bSFabien Thomas 
10021fa7f10bSFabien Thomas 	/* Parse additional modifiers if present */
10031fa7f10bSFabien Thomas 	while ((p = strsep(&ctrspec, ",")) != NULL) {
10041fa7f10bSFabien Thomas 
10051fa7f10bSFabien Thomas 		n = 0;
10061fa7f10bSFabien Thomas 		if (KWPREFIXMATCH(p, UCP_KW_CMASK "=")) {
10071fa7f10bSFabien Thomas 			q = strchr(p, '=');
10081fa7f10bSFabien Thomas 			if (*++q == '\0') /* skip '=' */
10091fa7f10bSFabien Thomas 				return (-1);
10101fa7f10bSFabien Thomas 			count = strtol(q, &e, 0);
10111fa7f10bSFabien Thomas 			if (e == q || *e != '\0')
10121fa7f10bSFabien Thomas 				return (-1);
10131fa7f10bSFabien Thomas 			pmc_config->pm_caps |= PMC_CAP_THRESHOLD;
10141fa7f10bSFabien Thomas 			pmc_config->pm_md.pm_ucp.pm_ucp_config |=
10151fa7f10bSFabien Thomas 			    UCP_CMASK(count);
10161fa7f10bSFabien Thomas 		} else if (KWMATCH(p, UCP_KW_EDGE)) {
10171fa7f10bSFabien Thomas 			pmc_config->pm_caps |= PMC_CAP_EDGE;
10181fa7f10bSFabien Thomas 		} else if (KWMATCH(p, UCP_KW_INV)) {
10191fa7f10bSFabien Thomas 			pmc_config->pm_caps |= PMC_CAP_INVERT;
10201fa7f10bSFabien Thomas 		} else
10211fa7f10bSFabien Thomas 			return (-1);
10221fa7f10bSFabien Thomas 
10231fa7f10bSFabien Thomas 		if (n < 0)	/* Parsing failed. */
10241fa7f10bSFabien Thomas 			return (-1);
10251fa7f10bSFabien Thomas 	}
10260cfab8ddSJoseph Koshy 
10270cfab8ddSJoseph Koshy 	return (0);
10280cfab8ddSJoseph Koshy }
10290cfab8ddSJoseph Koshy 
10300cfab8ddSJoseph Koshy /*
1031f263522aSJoseph Koshy  * AMD K8 PMCs.
1032f263522aSJoseph Koshy  *
1033f263522aSJoseph Koshy  * These are very similar to AMD K7 PMCs, but support more kinds of
1034f263522aSJoseph Koshy  * events.
1035f263522aSJoseph Koshy  */
1036f263522aSJoseph Koshy 
1037f263522aSJoseph Koshy static struct pmc_event_alias k8_aliases[] = {
1038f263522aSJoseph Koshy 	EV_ALIAS("branches",		"k8-fr-retired-taken-branches"),
1039f263522aSJoseph Koshy 	EV_ALIAS("branch-mispredicts",
1040f263522aSJoseph Koshy 	    "k8-fr-retired-taken-branches-mispredicted"),
1041f263522aSJoseph Koshy 	EV_ALIAS("cycles",		"tsc"),
1042f263522aSJoseph Koshy 	EV_ALIAS("dc-misses",		"k8-dc-miss"),
1043f263522aSJoseph Koshy 	EV_ALIAS("ic-misses",		"k8-ic-miss"),
1044f263522aSJoseph Koshy 	EV_ALIAS("instructions",	"k8-fr-retired-x86-instructions"),
1045f263522aSJoseph Koshy 	EV_ALIAS("interrupts",		"k8-fr-taken-hardware-interrupts"),
1046177a2f22SJoseph Koshy 	EV_ALIAS("unhalted-cycles",	"k8-bu-cpu-clk-unhalted"),
1047f263522aSJoseph Koshy 	EV_ALIAS(NULL, NULL)
1048f263522aSJoseph Koshy };
1049f263522aSJoseph Koshy 
1050f263522aSJoseph Koshy #define	__K8MASK(N,V) PMCMASK(N,(1 << (V)))
1051f263522aSJoseph Koshy 
1052f263522aSJoseph Koshy /*
1053f263522aSJoseph Koshy  * Parsing tables
1054f263522aSJoseph Koshy  */
1055f263522aSJoseph Koshy 
1056f263522aSJoseph Koshy /* fp dispatched fpu ops */
1057f263522aSJoseph Koshy static const struct pmc_masks k8_mask_fdfo[] = {
1058f263522aSJoseph Koshy 	__K8MASK(add-pipe-excluding-junk-ops,	0),
1059f263522aSJoseph Koshy 	__K8MASK(multiply-pipe-excluding-junk-ops,	1),
1060f263522aSJoseph Koshy 	__K8MASK(store-pipe-excluding-junk-ops,	2),
1061f263522aSJoseph Koshy 	__K8MASK(add-pipe-junk-ops,		3),
1062f263522aSJoseph Koshy 	__K8MASK(multiply-pipe-junk-ops,	4),
1063f263522aSJoseph Koshy 	__K8MASK(store-pipe-junk-ops,		5),
1064f263522aSJoseph Koshy 	NULLMASK
1065f263522aSJoseph Koshy };
1066f263522aSJoseph Koshy 
1067f263522aSJoseph Koshy /* ls segment register loads */
1068f263522aSJoseph Koshy static const struct pmc_masks k8_mask_lsrl[] = {
1069f263522aSJoseph Koshy 	__K8MASK(es,	0),
1070f263522aSJoseph Koshy 	__K8MASK(cs,	1),
1071f263522aSJoseph Koshy 	__K8MASK(ss,	2),
1072f263522aSJoseph Koshy 	__K8MASK(ds,	3),
1073f263522aSJoseph Koshy 	__K8MASK(fs,	4),
1074f263522aSJoseph Koshy 	__K8MASK(gs,	5),
1075f263522aSJoseph Koshy 	__K8MASK(hs,	6),
1076f263522aSJoseph Koshy 	NULLMASK
1077f263522aSJoseph Koshy };
1078f263522aSJoseph Koshy 
1079f263522aSJoseph Koshy /* ls locked operation */
1080f263522aSJoseph Koshy static const struct pmc_masks k8_mask_llo[] = {
1081f263522aSJoseph Koshy 	__K8MASK(locked-instructions,	0),
1082f263522aSJoseph Koshy 	__K8MASK(cycles-in-request,	1),
1083f263522aSJoseph Koshy 	__K8MASK(cycles-to-complete,	2),
1084f263522aSJoseph Koshy 	NULLMASK
1085f263522aSJoseph Koshy };
1086f263522aSJoseph Koshy 
1087f263522aSJoseph Koshy /* dc refill from {l2,system} and dc copyback */
1088f263522aSJoseph Koshy static const struct pmc_masks k8_mask_dc[] = {
1089f263522aSJoseph Koshy 	__K8MASK(invalid,	0),
1090f263522aSJoseph Koshy 	__K8MASK(shared,	1),
1091f263522aSJoseph Koshy 	__K8MASK(exclusive,	2),
1092f263522aSJoseph Koshy 	__K8MASK(owner,		3),
1093f263522aSJoseph Koshy 	__K8MASK(modified,	4),
1094f263522aSJoseph Koshy 	NULLMASK
1095f263522aSJoseph Koshy };
1096f263522aSJoseph Koshy 
1097f263522aSJoseph Koshy /* dc one bit ecc error */
1098f263522aSJoseph Koshy static const struct pmc_masks k8_mask_dobee[] = {
1099f263522aSJoseph Koshy 	__K8MASK(scrubber,	0),
1100f263522aSJoseph Koshy 	__K8MASK(piggyback,	1),
1101f263522aSJoseph Koshy 	NULLMASK
1102f263522aSJoseph Koshy };
1103f263522aSJoseph Koshy 
1104f263522aSJoseph Koshy /* dc dispatched prefetch instructions */
1105f263522aSJoseph Koshy static const struct pmc_masks k8_mask_ddpi[] = {
1106f263522aSJoseph Koshy 	__K8MASK(load,	0),
1107f263522aSJoseph Koshy 	__K8MASK(store,	1),
1108f263522aSJoseph Koshy 	__K8MASK(nta,	2),
1109f263522aSJoseph Koshy 	NULLMASK
1110f263522aSJoseph Koshy };
1111f263522aSJoseph Koshy 
1112f263522aSJoseph Koshy /* dc dcache accesses by locks */
1113f263522aSJoseph Koshy static const struct pmc_masks k8_mask_dabl[] = {
1114f263522aSJoseph Koshy 	__K8MASK(accesses,	0),
1115f263522aSJoseph Koshy 	__K8MASK(misses,	1),
1116f263522aSJoseph Koshy 	NULLMASK
1117f263522aSJoseph Koshy };
1118f263522aSJoseph Koshy 
1119f263522aSJoseph Koshy /* bu internal l2 request */
1120f263522aSJoseph Koshy static const struct pmc_masks k8_mask_bilr[] = {
1121f263522aSJoseph Koshy 	__K8MASK(ic-fill,	0),
1122f263522aSJoseph Koshy 	__K8MASK(dc-fill,	1),
1123f263522aSJoseph Koshy 	__K8MASK(tlb-reload,	2),
1124f263522aSJoseph Koshy 	__K8MASK(tag-snoop,	3),
1125f263522aSJoseph Koshy 	__K8MASK(cancelled,	4),
1126f263522aSJoseph Koshy 	NULLMASK
1127f263522aSJoseph Koshy };
1128f263522aSJoseph Koshy 
1129f263522aSJoseph Koshy /* bu fill request l2 miss */
1130f263522aSJoseph Koshy static const struct pmc_masks k8_mask_bfrlm[] = {
1131f263522aSJoseph Koshy 	__K8MASK(ic-fill,	0),
1132f263522aSJoseph Koshy 	__K8MASK(dc-fill,	1),
1133f263522aSJoseph Koshy 	__K8MASK(tlb-reload,	2),
1134f263522aSJoseph Koshy 	NULLMASK
1135f263522aSJoseph Koshy };
1136f263522aSJoseph Koshy 
1137f263522aSJoseph Koshy /* bu fill into l2 */
1138f263522aSJoseph Koshy static const struct pmc_masks k8_mask_bfil[] = {
1139f263522aSJoseph Koshy 	__K8MASK(dirty-l2-victim,	0),
1140f263522aSJoseph Koshy 	__K8MASK(victim-from-l2,	1),
1141f263522aSJoseph Koshy 	NULLMASK
1142f263522aSJoseph Koshy };
1143f263522aSJoseph Koshy 
1144f263522aSJoseph Koshy /* fr retired fpu instructions */
1145f263522aSJoseph Koshy static const struct pmc_masks k8_mask_frfi[] = {
1146f263522aSJoseph Koshy 	__K8MASK(x87,			0),
1147f263522aSJoseph Koshy 	__K8MASK(mmx-3dnow,		1),
1148f263522aSJoseph Koshy 	__K8MASK(packed-sse-sse2,	2),
1149f263522aSJoseph Koshy 	__K8MASK(scalar-sse-sse2,	3),
1150f263522aSJoseph Koshy 	NULLMASK
1151f263522aSJoseph Koshy };
1152f263522aSJoseph Koshy 
1153f263522aSJoseph Koshy /* fr retired fastpath double op instructions */
1154f263522aSJoseph Koshy static const struct pmc_masks k8_mask_frfdoi[] = {
1155f263522aSJoseph Koshy 	__K8MASK(low-op-pos-0,		0),
1156f263522aSJoseph Koshy 	__K8MASK(low-op-pos-1,		1),
1157f263522aSJoseph Koshy 	__K8MASK(low-op-pos-2,		2),
1158f263522aSJoseph Koshy 	NULLMASK
1159f263522aSJoseph Koshy };
1160f263522aSJoseph Koshy 
1161f263522aSJoseph Koshy /* fr fpu exceptions */
1162f263522aSJoseph Koshy static const struct pmc_masks k8_mask_ffe[] = {
1163f263522aSJoseph Koshy 	__K8MASK(x87-reclass-microfaults,	0),
1164f263522aSJoseph Koshy 	__K8MASK(sse-retype-microfaults,	1),
1165f263522aSJoseph Koshy 	__K8MASK(sse-reclass-microfaults,	2),
1166f263522aSJoseph Koshy 	__K8MASK(sse-and-x87-microtraps,	3),
1167f263522aSJoseph Koshy 	NULLMASK
1168f263522aSJoseph Koshy };
1169f263522aSJoseph Koshy 
1170f263522aSJoseph Koshy /* nb memory controller page access event */
1171f263522aSJoseph Koshy static const struct pmc_masks k8_mask_nmcpae[] = {
1172f263522aSJoseph Koshy 	__K8MASK(page-hit,	0),
1173f263522aSJoseph Koshy 	__K8MASK(page-miss,	1),
1174f263522aSJoseph Koshy 	__K8MASK(page-conflict,	2),
1175f263522aSJoseph Koshy 	NULLMASK
1176f263522aSJoseph Koshy };
1177f263522aSJoseph Koshy 
1178f263522aSJoseph Koshy /* nb memory controller turnaround */
1179f263522aSJoseph Koshy static const struct pmc_masks k8_mask_nmct[] = {
1180f263522aSJoseph Koshy 	__K8MASK(dimm-turnaround,		0),
1181f263522aSJoseph Koshy 	__K8MASK(read-to-write-turnaround,	1),
1182f263522aSJoseph Koshy 	__K8MASK(write-to-read-turnaround,	2),
1183f263522aSJoseph Koshy 	NULLMASK
1184f263522aSJoseph Koshy };
1185f263522aSJoseph Koshy 
1186f263522aSJoseph Koshy /* nb memory controller bypass saturation */
1187f263522aSJoseph Koshy static const struct pmc_masks k8_mask_nmcbs[] = {
1188f263522aSJoseph Koshy 	__K8MASK(memory-controller-hi-pri-bypass,	0),
1189f263522aSJoseph Koshy 	__K8MASK(memory-controller-lo-pri-bypass,	1),
1190f263522aSJoseph Koshy 	__K8MASK(dram-controller-interface-bypass,	2),
1191f263522aSJoseph Koshy 	__K8MASK(dram-controller-queue-bypass,		3),
1192f263522aSJoseph Koshy 	NULLMASK
1193f263522aSJoseph Koshy };
1194f263522aSJoseph Koshy 
1195f263522aSJoseph Koshy /* nb sized commands */
1196f263522aSJoseph Koshy static const struct pmc_masks k8_mask_nsc[] = {
1197f263522aSJoseph Koshy 	__K8MASK(nonpostwrszbyte,	0),
1198f263522aSJoseph Koshy 	__K8MASK(nonpostwrszdword,	1),
1199f263522aSJoseph Koshy 	__K8MASK(postwrszbyte,		2),
1200f263522aSJoseph Koshy 	__K8MASK(postwrszdword,		3),
1201f263522aSJoseph Koshy 	__K8MASK(rdszbyte,		4),
1202f263522aSJoseph Koshy 	__K8MASK(rdszdword,		5),
1203f263522aSJoseph Koshy 	__K8MASK(rdmodwr,		6),
1204f263522aSJoseph Koshy 	NULLMASK
1205f263522aSJoseph Koshy };
1206f263522aSJoseph Koshy 
1207f263522aSJoseph Koshy /* nb probe result */
1208f263522aSJoseph Koshy static const struct pmc_masks k8_mask_npr[] = {
1209f263522aSJoseph Koshy 	__K8MASK(probe-miss,		0),
1210f263522aSJoseph Koshy 	__K8MASK(probe-hit,		1),
1211f263522aSJoseph Koshy 	__K8MASK(probe-hit-dirty-no-memory-cancel, 2),
1212f263522aSJoseph Koshy 	__K8MASK(probe-hit-dirty-with-memory-cancel, 3),
1213f263522aSJoseph Koshy 	NULLMASK
1214f263522aSJoseph Koshy };
1215f263522aSJoseph Koshy 
1216f263522aSJoseph Koshy /* nb hypertransport bus bandwidth */
1217f263522aSJoseph Koshy static const struct pmc_masks k8_mask_nhbb[] = { /* HT bus bandwidth */
1218f263522aSJoseph Koshy 	__K8MASK(command,	0),
1219f263522aSJoseph Koshy 	__K8MASK(data,	1),
1220f263522aSJoseph Koshy 	__K8MASK(buffer-release, 2),
1221f263522aSJoseph Koshy 	__K8MASK(nop,	3),
1222f263522aSJoseph Koshy 	NULLMASK
1223f263522aSJoseph Koshy };
1224f263522aSJoseph Koshy 
1225f263522aSJoseph Koshy #undef	__K8MASK
1226f263522aSJoseph Koshy 
1227f263522aSJoseph Koshy #define	K8_KW_COUNT	"count"
1228f263522aSJoseph Koshy #define	K8_KW_EDGE	"edge"
1229f263522aSJoseph Koshy #define	K8_KW_INV	"inv"
1230f263522aSJoseph Koshy #define	K8_KW_MASK	"mask"
1231f263522aSJoseph Koshy #define	K8_KW_OS	"os"
1232f263522aSJoseph Koshy #define	K8_KW_USR	"usr"
1233f263522aSJoseph Koshy 
1234f263522aSJoseph Koshy static int
1235f263522aSJoseph Koshy k8_allocate_pmc(enum pmc_event pe, char *ctrspec,
1236f263522aSJoseph Koshy     struct pmc_op_pmcallocate *pmc_config)
1237f263522aSJoseph Koshy {
1238f263522aSJoseph Koshy 	char		*e, *p, *q;
1239f263522aSJoseph Koshy 	int		n;
12401e862e5aSFabien Thomas 	uint32_t	count;
12411e862e5aSFabien Thomas 	uint64_t	evmask;
1242f263522aSJoseph Koshy 	const struct pmc_masks	*pm, *pmask;
1243f263522aSJoseph Koshy 
1244789140c0SJoseph Koshy 	pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE);
1245f263522aSJoseph Koshy 	pmc_config->pm_md.pm_amd.pm_amd_config = 0;
1246f263522aSJoseph Koshy 
1247f263522aSJoseph Koshy 	pmask = NULL;
1248f263522aSJoseph Koshy 	evmask = 0;
1249f263522aSJoseph Koshy 
1250f263522aSJoseph Koshy #define	__K8SETMASK(M) pmask = k8_mask_##M
1251f263522aSJoseph Koshy 
1252f263522aSJoseph Koshy 	/* setup parsing tables */
1253f263522aSJoseph Koshy 	switch (pe) {
1254f263522aSJoseph Koshy 	case PMC_EV_K8_FP_DISPATCHED_FPU_OPS:
1255f263522aSJoseph Koshy 		__K8SETMASK(fdfo);
1256f263522aSJoseph Koshy 		break;
1257f263522aSJoseph Koshy 	case PMC_EV_K8_LS_SEGMENT_REGISTER_LOAD:
1258f263522aSJoseph Koshy 		__K8SETMASK(lsrl);
1259f263522aSJoseph Koshy 		break;
1260f263522aSJoseph Koshy 	case PMC_EV_K8_LS_LOCKED_OPERATION:
1261f263522aSJoseph Koshy 		__K8SETMASK(llo);
1262f263522aSJoseph Koshy 		break;
1263f263522aSJoseph Koshy 	case PMC_EV_K8_DC_REFILL_FROM_L2:
1264f263522aSJoseph Koshy 	case PMC_EV_K8_DC_REFILL_FROM_SYSTEM:
1265f263522aSJoseph Koshy 	case PMC_EV_K8_DC_COPYBACK:
1266f263522aSJoseph Koshy 		__K8SETMASK(dc);
1267f263522aSJoseph Koshy 		break;
1268f263522aSJoseph Koshy 	case PMC_EV_K8_DC_ONE_BIT_ECC_ERROR:
1269f263522aSJoseph Koshy 		__K8SETMASK(dobee);
1270f263522aSJoseph Koshy 		break;
1271f263522aSJoseph Koshy 	case PMC_EV_K8_DC_DISPATCHED_PREFETCH_INSTRUCTIONS:
1272f263522aSJoseph Koshy 		__K8SETMASK(ddpi);
1273f263522aSJoseph Koshy 		break;
1274f263522aSJoseph Koshy 	case PMC_EV_K8_DC_DCACHE_ACCESSES_BY_LOCKS:
1275f263522aSJoseph Koshy 		__K8SETMASK(dabl);
1276f263522aSJoseph Koshy 		break;
1277f263522aSJoseph Koshy 	case PMC_EV_K8_BU_INTERNAL_L2_REQUEST:
1278f263522aSJoseph Koshy 		__K8SETMASK(bilr);
1279f263522aSJoseph Koshy 		break;
1280f263522aSJoseph Koshy 	case PMC_EV_K8_BU_FILL_REQUEST_L2_MISS:
1281f263522aSJoseph Koshy 		__K8SETMASK(bfrlm);
1282f263522aSJoseph Koshy 		break;
1283f263522aSJoseph Koshy 	case PMC_EV_K8_BU_FILL_INTO_L2:
1284f263522aSJoseph Koshy 		__K8SETMASK(bfil);
1285f263522aSJoseph Koshy 		break;
1286f263522aSJoseph Koshy 	case PMC_EV_K8_FR_RETIRED_FPU_INSTRUCTIONS:
1287f263522aSJoseph Koshy 		__K8SETMASK(frfi);
1288f263522aSJoseph Koshy 		break;
1289f263522aSJoseph Koshy 	case PMC_EV_K8_FR_RETIRED_FASTPATH_DOUBLE_OP_INSTRUCTIONS:
1290f263522aSJoseph Koshy 		__K8SETMASK(frfdoi);
1291f263522aSJoseph Koshy 		break;
1292f263522aSJoseph Koshy 	case PMC_EV_K8_FR_FPU_EXCEPTIONS:
1293f263522aSJoseph Koshy 		__K8SETMASK(ffe);
1294f263522aSJoseph Koshy 		break;
1295f263522aSJoseph Koshy 	case PMC_EV_K8_NB_MEMORY_CONTROLLER_PAGE_ACCESS_EVENT:
1296f263522aSJoseph Koshy 		__K8SETMASK(nmcpae);
1297f263522aSJoseph Koshy 		break;
1298f263522aSJoseph Koshy 	case PMC_EV_K8_NB_MEMORY_CONTROLLER_TURNAROUND:
1299f263522aSJoseph Koshy 		__K8SETMASK(nmct);
1300f263522aSJoseph Koshy 		break;
1301f263522aSJoseph Koshy 	case PMC_EV_K8_NB_MEMORY_CONTROLLER_BYPASS_SATURATION:
1302f263522aSJoseph Koshy 		__K8SETMASK(nmcbs);
1303f263522aSJoseph Koshy 		break;
1304f263522aSJoseph Koshy 	case PMC_EV_K8_NB_SIZED_COMMANDS:
1305f263522aSJoseph Koshy 		__K8SETMASK(nsc);
1306f263522aSJoseph Koshy 		break;
1307f263522aSJoseph Koshy 	case PMC_EV_K8_NB_PROBE_RESULT:
1308f263522aSJoseph Koshy 		__K8SETMASK(npr);
1309f263522aSJoseph Koshy 		break;
1310f263522aSJoseph Koshy 	case PMC_EV_K8_NB_HT_BUS0_BANDWIDTH:
1311f263522aSJoseph Koshy 	case PMC_EV_K8_NB_HT_BUS1_BANDWIDTH:
1312f263522aSJoseph Koshy 	case PMC_EV_K8_NB_HT_BUS2_BANDWIDTH:
1313f263522aSJoseph Koshy 		__K8SETMASK(nhbb);
1314f263522aSJoseph Koshy 		break;
1315f263522aSJoseph Koshy 
1316f263522aSJoseph Koshy 	default:
1317f263522aSJoseph Koshy 		break;		/* no options defined */
1318f263522aSJoseph Koshy 	}
1319f263522aSJoseph Koshy 
1320f263522aSJoseph Koshy 	while ((p = strsep(&ctrspec, ",")) != NULL) {
1321f263522aSJoseph Koshy 		if (KWPREFIXMATCH(p, K8_KW_COUNT "=")) {
1322f263522aSJoseph Koshy 			q = strchr(p, '=');
1323f263522aSJoseph Koshy 			if (*++q == '\0') /* skip '=' */
1324aa342b1fSJoseph Koshy 				return (-1);
1325f263522aSJoseph Koshy 
1326f263522aSJoseph Koshy 			count = strtol(q, &e, 0);
1327f263522aSJoseph Koshy 			if (e == q || *e != '\0')
1328aa342b1fSJoseph Koshy 				return (-1);
1329f263522aSJoseph Koshy 
1330f263522aSJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_THRESHOLD;
1331f263522aSJoseph Koshy 			pmc_config->pm_md.pm_amd.pm_amd_config |=
1332f263522aSJoseph Koshy 			    AMD_PMC_TO_COUNTER(count);
1333f263522aSJoseph Koshy 
1334f263522aSJoseph Koshy 		} else if (KWMATCH(p, K8_KW_EDGE)) {
1335f263522aSJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_EDGE;
1336f263522aSJoseph Koshy 		} else if (KWMATCH(p, K8_KW_INV)) {
1337f263522aSJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_INVERT;
1338f263522aSJoseph Koshy 		} else if (KWPREFIXMATCH(p, K8_KW_MASK "=")) {
1339f263522aSJoseph Koshy 			if ((n = pmc_parse_mask(pmask, p, &evmask)) < 0)
1340aa342b1fSJoseph Koshy 				return (-1);
1341f263522aSJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_QUALIFIER;
1342f263522aSJoseph Koshy 		} else if (KWMATCH(p, K8_KW_OS)) {
1343f263522aSJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_SYSTEM;
1344f263522aSJoseph Koshy 		} else if (KWMATCH(p, K8_KW_USR)) {
1345f263522aSJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_USER;
1346f263522aSJoseph Koshy 		} else
1347aa342b1fSJoseph Koshy 			return (-1);
1348f263522aSJoseph Koshy 	}
1349f263522aSJoseph Koshy 
1350f263522aSJoseph Koshy 	/* other post processing */
1351f263522aSJoseph Koshy 	switch (pe) {
1352f263522aSJoseph Koshy 	case PMC_EV_K8_FP_DISPATCHED_FPU_OPS:
1353f263522aSJoseph Koshy 	case PMC_EV_K8_FP_CYCLES_WITH_NO_FPU_OPS_RETIRED:
1354f263522aSJoseph Koshy 	case PMC_EV_K8_FP_DISPATCHED_FPU_FAST_FLAG_OPS:
1355f263522aSJoseph Koshy 	case PMC_EV_K8_FR_RETIRED_FASTPATH_DOUBLE_OP_INSTRUCTIONS:
1356f263522aSJoseph Koshy 	case PMC_EV_K8_FR_RETIRED_FPU_INSTRUCTIONS:
1357f263522aSJoseph Koshy 	case PMC_EV_K8_FR_FPU_EXCEPTIONS:
1358f263522aSJoseph Koshy 		/* XXX only available in rev B and later */
1359f263522aSJoseph Koshy 		break;
1360f263522aSJoseph Koshy 	case PMC_EV_K8_DC_DCACHE_ACCESSES_BY_LOCKS:
1361f263522aSJoseph Koshy 		/* XXX only available in rev C and later */
1362f263522aSJoseph Koshy 		break;
1363f263522aSJoseph Koshy 	case PMC_EV_K8_LS_LOCKED_OPERATION:
1364f263522aSJoseph Koshy 		/* XXX CPU Rev A,B evmask is to be zero */
1365f263522aSJoseph Koshy 		if (evmask & (evmask - 1)) /* > 1 bit set */
1366aa342b1fSJoseph Koshy 			return (-1);
1367f263522aSJoseph Koshy 		if (evmask == 0) {
1368f263522aSJoseph Koshy 			evmask = 0x01; /* Rev C and later: #instrs */
1369f263522aSJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_QUALIFIER;
1370f263522aSJoseph Koshy 		}
1371f263522aSJoseph Koshy 		break;
1372f263522aSJoseph Koshy 	default:
1373f263522aSJoseph Koshy 		if (evmask == 0 && pmask != NULL) {
1374f263522aSJoseph Koshy 			for (pm = pmask; pm->pm_name; pm++)
1375f263522aSJoseph Koshy 				evmask |= pm->pm_value;
1376f263522aSJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_QUALIFIER;
1377f263522aSJoseph Koshy 		}
1378f263522aSJoseph Koshy 	}
1379f263522aSJoseph Koshy 
1380f263522aSJoseph Koshy 	if (pmc_config->pm_caps & PMC_CAP_QUALIFIER)
1381f263522aSJoseph Koshy 		pmc_config->pm_md.pm_amd.pm_amd_config =
1382f263522aSJoseph Koshy 		    AMD_PMC_TO_UNITMASK(evmask);
1383f263522aSJoseph Koshy 
1384aa342b1fSJoseph Koshy 	return (0);
1385f263522aSJoseph Koshy }
1386f263522aSJoseph Koshy 
1387f263522aSJoseph Koshy #endif
1388f263522aSJoseph Koshy 
138986a65549SJoseph Koshy #if defined(__amd64__) || defined(__i386__)
1390f263522aSJoseph Koshy 
1391ebccf1e3SJoseph Koshy /*
1392ebccf1e3SJoseph Koshy  * Intel P4 PMCs
1393ebccf1e3SJoseph Koshy  */
1394ebccf1e3SJoseph Koshy 
1395ebccf1e3SJoseph Koshy static struct pmc_event_alias p4_aliases[] = {
1396d56c5d4bSJoseph Koshy 	EV_ALIAS("branches",		"p4-branch-retired,mask=mmtp+mmtm"),
1397d56c5d4bSJoseph Koshy 	EV_ALIAS("branch-mispredicts",	"p4-mispred-branch-retired"),
1398ebccf1e3SJoseph Koshy 	EV_ALIAS("cycles",		"tsc"),
1399d56c5d4bSJoseph Koshy 	EV_ALIAS("instructions",
1400d56c5d4bSJoseph Koshy 	    "p4-instr-retired,mask=nbogusntag+nbogustag"),
1401177a2f22SJoseph Koshy 	EV_ALIAS("unhalted-cycles",	"p4-global-power-events"),
1402ebccf1e3SJoseph Koshy 	EV_ALIAS(NULL, NULL)
1403ebccf1e3SJoseph Koshy };
1404ebccf1e3SJoseph Koshy 
1405ebccf1e3SJoseph Koshy #define	P4_KW_ACTIVE	"active"
1406ebccf1e3SJoseph Koshy #define	P4_KW_ACTIVE_ANY "any"
1407ebccf1e3SJoseph Koshy #define	P4_KW_ACTIVE_BOTH "both"
1408ebccf1e3SJoseph Koshy #define	P4_KW_ACTIVE_NONE "none"
1409ebccf1e3SJoseph Koshy #define	P4_KW_ACTIVE_SINGLE "single"
1410ebccf1e3SJoseph Koshy #define	P4_KW_BUSREQTYPE "busreqtype"
1411ebccf1e3SJoseph Koshy #define	P4_KW_CASCADE	"cascade"
1412ebccf1e3SJoseph Koshy #define	P4_KW_EDGE	"edge"
1413ebccf1e3SJoseph Koshy #define	P4_KW_INV	"complement"
1414ebccf1e3SJoseph Koshy #define	P4_KW_OS	"os"
1415ebccf1e3SJoseph Koshy #define	P4_KW_MASK	"mask"
1416ebccf1e3SJoseph Koshy #define	P4_KW_PRECISE	"precise"
1417ebccf1e3SJoseph Koshy #define	P4_KW_TAG	"tag"
1418ebccf1e3SJoseph Koshy #define	P4_KW_THRESHOLD	"threshold"
1419ebccf1e3SJoseph Koshy #define	P4_KW_USR	"usr"
1420ebccf1e3SJoseph Koshy 
1421ebccf1e3SJoseph Koshy #define	__P4MASK(N,V) PMCMASK(N, (1 << (V)))
1422ebccf1e3SJoseph Koshy 
1423ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_tcdm[] = { /* tc deliver mode */
1424ebccf1e3SJoseph Koshy 	__P4MASK(dd, 0),
1425ebccf1e3SJoseph Koshy 	__P4MASK(db, 1),
1426ebccf1e3SJoseph Koshy 	__P4MASK(di, 2),
1427ebccf1e3SJoseph Koshy 	__P4MASK(bd, 3),
1428ebccf1e3SJoseph Koshy 	__P4MASK(bb, 4),
1429ebccf1e3SJoseph Koshy 	__P4MASK(bi, 5),
1430ebccf1e3SJoseph Koshy 	__P4MASK(id, 6),
1431ebccf1e3SJoseph Koshy 	__P4MASK(ib, 7),
1432ebccf1e3SJoseph Koshy 	NULLMASK
1433ebccf1e3SJoseph Koshy };
1434ebccf1e3SJoseph Koshy 
1435ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_bfr[] = { /* bpu fetch request */
1436ebccf1e3SJoseph Koshy 	__P4MASK(tcmiss, 0),
1437ebccf1e3SJoseph Koshy 	NULLMASK,
1438ebccf1e3SJoseph Koshy };
1439ebccf1e3SJoseph Koshy 
1440ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_ir[] = { /* itlb reference */
1441ebccf1e3SJoseph Koshy 	__P4MASK(hit, 0),
1442ebccf1e3SJoseph Koshy 	__P4MASK(miss, 1),
1443ebccf1e3SJoseph Koshy 	__P4MASK(hit-uc, 2),
1444ebccf1e3SJoseph Koshy 	NULLMASK
1445ebccf1e3SJoseph Koshy };
1446ebccf1e3SJoseph Koshy 
1447ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_memcan[] = { /* memory cancel */
1448ebccf1e3SJoseph Koshy 	__P4MASK(st-rb-full, 2),
1449ebccf1e3SJoseph Koshy 	__P4MASK(64k-conf, 3),
1450ebccf1e3SJoseph Koshy 	NULLMASK
1451ebccf1e3SJoseph Koshy };
1452ebccf1e3SJoseph Koshy 
1453ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_memcomp[] = { /* memory complete */
1454ebccf1e3SJoseph Koshy 	__P4MASK(lsc, 0),
1455ebccf1e3SJoseph Koshy 	__P4MASK(ssc, 1),
1456ebccf1e3SJoseph Koshy 	NULLMASK
1457ebccf1e3SJoseph Koshy };
1458ebccf1e3SJoseph Koshy 
1459ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_lpr[] = { /* load port replay */
1460ebccf1e3SJoseph Koshy 	__P4MASK(split-ld, 1),
1461ebccf1e3SJoseph Koshy 	NULLMASK
1462ebccf1e3SJoseph Koshy };
1463ebccf1e3SJoseph Koshy 
1464ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_spr[] = { /* store port replay */
1465ebccf1e3SJoseph Koshy 	__P4MASK(split-st, 1),
1466ebccf1e3SJoseph Koshy 	NULLMASK
1467ebccf1e3SJoseph Koshy };
1468ebccf1e3SJoseph Koshy 
1469ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_mlr[] = { /* mob load replay */
1470ebccf1e3SJoseph Koshy 	__P4MASK(no-sta, 1),
1471ebccf1e3SJoseph Koshy 	__P4MASK(no-std, 3),
1472ebccf1e3SJoseph Koshy 	__P4MASK(partial-data, 4),
1473ebccf1e3SJoseph Koshy 	__P4MASK(unalgn-addr, 5),
1474ebccf1e3SJoseph Koshy 	NULLMASK
1475ebccf1e3SJoseph Koshy };
1476ebccf1e3SJoseph Koshy 
1477ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_pwt[] = { /* page walk type */
1478ebccf1e3SJoseph Koshy 	__P4MASK(dtmiss, 0),
1479ebccf1e3SJoseph Koshy 	__P4MASK(itmiss, 1),
1480ebccf1e3SJoseph Koshy 	NULLMASK
1481ebccf1e3SJoseph Koshy };
1482ebccf1e3SJoseph Koshy 
1483ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_bcr[] = { /* bsq cache reference */
1484ebccf1e3SJoseph Koshy 	__P4MASK(rd-2ndl-hits, 0),
1485ebccf1e3SJoseph Koshy 	__P4MASK(rd-2ndl-hite, 1),
1486ebccf1e3SJoseph Koshy 	__P4MASK(rd-2ndl-hitm, 2),
1487ebccf1e3SJoseph Koshy 	__P4MASK(rd-3rdl-hits, 3),
1488ebccf1e3SJoseph Koshy 	__P4MASK(rd-3rdl-hite, 4),
1489ebccf1e3SJoseph Koshy 	__P4MASK(rd-3rdl-hitm, 5),
1490ebccf1e3SJoseph Koshy 	__P4MASK(rd-2ndl-miss, 8),
1491ebccf1e3SJoseph Koshy 	__P4MASK(rd-3rdl-miss, 9),
1492ebccf1e3SJoseph Koshy 	__P4MASK(wr-2ndl-miss, 10),
1493ebccf1e3SJoseph Koshy 	NULLMASK
1494ebccf1e3SJoseph Koshy };
1495ebccf1e3SJoseph Koshy 
1496ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_ia[] = { /* ioq allocation */
1497ebccf1e3SJoseph Koshy 	__P4MASK(all-read, 5),
1498ebccf1e3SJoseph Koshy 	__P4MASK(all-write, 6),
1499ebccf1e3SJoseph Koshy 	__P4MASK(mem-uc, 7),
1500ebccf1e3SJoseph Koshy 	__P4MASK(mem-wc, 8),
1501ebccf1e3SJoseph Koshy 	__P4MASK(mem-wt, 9),
1502ebccf1e3SJoseph Koshy 	__P4MASK(mem-wp, 10),
1503ebccf1e3SJoseph Koshy 	__P4MASK(mem-wb, 11),
1504ebccf1e3SJoseph Koshy 	__P4MASK(own, 13),
1505ebccf1e3SJoseph Koshy 	__P4MASK(other, 14),
1506ebccf1e3SJoseph Koshy 	__P4MASK(prefetch, 15),
1507ebccf1e3SJoseph Koshy 	NULLMASK
1508ebccf1e3SJoseph Koshy };
1509ebccf1e3SJoseph Koshy 
1510ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_iae[] = { /* ioq active entries */
1511ebccf1e3SJoseph Koshy 	__P4MASK(all-read, 5),
1512ebccf1e3SJoseph Koshy 	__P4MASK(all-write, 6),
1513ebccf1e3SJoseph Koshy 	__P4MASK(mem-uc, 7),
1514ebccf1e3SJoseph Koshy 	__P4MASK(mem-wc, 8),
1515ebccf1e3SJoseph Koshy 	__P4MASK(mem-wt, 9),
1516ebccf1e3SJoseph Koshy 	__P4MASK(mem-wp, 10),
1517ebccf1e3SJoseph Koshy 	__P4MASK(mem-wb, 11),
1518ebccf1e3SJoseph Koshy 	__P4MASK(own, 13),
1519ebccf1e3SJoseph Koshy 	__P4MASK(other, 14),
1520ebccf1e3SJoseph Koshy 	__P4MASK(prefetch, 15),
1521ebccf1e3SJoseph Koshy 	NULLMASK
1522ebccf1e3SJoseph Koshy };
1523ebccf1e3SJoseph Koshy 
1524ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_fda[] = { /* fsb data activity */
1525ebccf1e3SJoseph Koshy 	__P4MASK(drdy-drv, 0),
1526ebccf1e3SJoseph Koshy 	__P4MASK(drdy-own, 1),
1527ebccf1e3SJoseph Koshy 	__P4MASK(drdy-other, 2),
1528ebccf1e3SJoseph Koshy 	__P4MASK(dbsy-drv, 3),
1529ebccf1e3SJoseph Koshy 	__P4MASK(dbsy-own, 4),
1530ebccf1e3SJoseph Koshy 	__P4MASK(dbsy-other, 5),
1531ebccf1e3SJoseph Koshy 	NULLMASK
1532ebccf1e3SJoseph Koshy };
1533ebccf1e3SJoseph Koshy 
1534ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_ba[] = { /* bsq allocation */
1535ebccf1e3SJoseph Koshy 	__P4MASK(req-type0, 0),
1536ebccf1e3SJoseph Koshy 	__P4MASK(req-type1, 1),
1537ebccf1e3SJoseph Koshy 	__P4MASK(req-len0, 2),
1538ebccf1e3SJoseph Koshy 	__P4MASK(req-len1, 3),
1539ebccf1e3SJoseph Koshy 	__P4MASK(req-io-type, 5),
1540ebccf1e3SJoseph Koshy 	__P4MASK(req-lock-type, 6),
1541ebccf1e3SJoseph Koshy 	__P4MASK(req-cache-type, 7),
1542ebccf1e3SJoseph Koshy 	__P4MASK(req-split-type, 8),
1543ebccf1e3SJoseph Koshy 	__P4MASK(req-dem-type, 9),
1544ebccf1e3SJoseph Koshy 	__P4MASK(req-ord-type, 10),
1545ebccf1e3SJoseph Koshy 	__P4MASK(mem-type0, 11),
1546ebccf1e3SJoseph Koshy 	__P4MASK(mem-type1, 12),
1547ebccf1e3SJoseph Koshy 	__P4MASK(mem-type2, 13),
1548ebccf1e3SJoseph Koshy 	NULLMASK
1549ebccf1e3SJoseph Koshy };
1550ebccf1e3SJoseph Koshy 
1551ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_sia[] = { /* sse input assist */
1552ebccf1e3SJoseph Koshy 	__P4MASK(all, 15),
1553ebccf1e3SJoseph Koshy 	NULLMASK
1554ebccf1e3SJoseph Koshy };
1555ebccf1e3SJoseph Koshy 
1556ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_psu[] = { /* packed sp uop */
1557ebccf1e3SJoseph Koshy 	__P4MASK(all, 15),
1558ebccf1e3SJoseph Koshy 	NULLMASK
1559ebccf1e3SJoseph Koshy };
1560ebccf1e3SJoseph Koshy 
1561ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_pdu[] = { /* packed dp uop */
1562ebccf1e3SJoseph Koshy 	__P4MASK(all, 15),
1563ebccf1e3SJoseph Koshy 	NULLMASK
1564ebccf1e3SJoseph Koshy };
1565ebccf1e3SJoseph Koshy 
1566ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_ssu[] = { /* scalar sp uop */
1567ebccf1e3SJoseph Koshy 	__P4MASK(all, 15),
1568ebccf1e3SJoseph Koshy 	NULLMASK
1569ebccf1e3SJoseph Koshy };
1570ebccf1e3SJoseph Koshy 
1571ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_sdu[] = { /* scalar dp uop */
1572ebccf1e3SJoseph Koshy 	__P4MASK(all, 15),
1573ebccf1e3SJoseph Koshy 	NULLMASK
1574ebccf1e3SJoseph Koshy };
1575ebccf1e3SJoseph Koshy 
1576ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_64bmu[] = { /* 64 bit mmx uop */
1577ebccf1e3SJoseph Koshy 	__P4MASK(all, 15),
1578ebccf1e3SJoseph Koshy 	NULLMASK
1579ebccf1e3SJoseph Koshy };
1580ebccf1e3SJoseph Koshy 
1581ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_128bmu[] = { /* 128 bit mmx uop */
1582ebccf1e3SJoseph Koshy 	__P4MASK(all, 15),
1583ebccf1e3SJoseph Koshy 	NULLMASK
1584ebccf1e3SJoseph Koshy };
1585ebccf1e3SJoseph Koshy 
1586ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_xfu[] = { /* X87 fp uop */
1587ebccf1e3SJoseph Koshy 	__P4MASK(all, 15),
1588ebccf1e3SJoseph Koshy 	NULLMASK
1589ebccf1e3SJoseph Koshy };
1590ebccf1e3SJoseph Koshy 
1591ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_xsmu[] = { /* x87 simd moves uop */
1592ebccf1e3SJoseph Koshy 	__P4MASK(allp0, 3),
1593ebccf1e3SJoseph Koshy 	__P4MASK(allp2, 4),
1594ebccf1e3SJoseph Koshy 	NULLMASK
1595ebccf1e3SJoseph Koshy };
1596ebccf1e3SJoseph Koshy 
1597ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_gpe[] = { /* global power events */
1598ebccf1e3SJoseph Koshy 	__P4MASK(running, 0),
1599ebccf1e3SJoseph Koshy 	NULLMASK
1600ebccf1e3SJoseph Koshy };
1601ebccf1e3SJoseph Koshy 
1602ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_tmx[] = { /* TC ms xfer */
1603ebccf1e3SJoseph Koshy 	__P4MASK(cisc, 0),
1604ebccf1e3SJoseph Koshy 	NULLMASK
1605ebccf1e3SJoseph Koshy };
1606ebccf1e3SJoseph Koshy 
1607ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_uqw[] = { /* uop queue writes */
1608ebccf1e3SJoseph Koshy 	__P4MASK(from-tc-build, 0),
1609ebccf1e3SJoseph Koshy 	__P4MASK(from-tc-deliver, 1),
1610ebccf1e3SJoseph Koshy 	__P4MASK(from-rom, 2),
1611ebccf1e3SJoseph Koshy 	NULLMASK
1612ebccf1e3SJoseph Koshy };
1613ebccf1e3SJoseph Koshy 
1614d56c5d4bSJoseph Koshy static const struct pmc_masks p4_mask_rmbt[] = {
1615d56c5d4bSJoseph Koshy 	/* retired mispred branch type */
1616ebccf1e3SJoseph Koshy 	__P4MASK(conditional, 1),
1617ebccf1e3SJoseph Koshy 	__P4MASK(call, 2),
1618ebccf1e3SJoseph Koshy 	__P4MASK(return, 3),
1619ebccf1e3SJoseph Koshy 	__P4MASK(indirect, 4),
1620ebccf1e3SJoseph Koshy 	NULLMASK
1621ebccf1e3SJoseph Koshy };
1622ebccf1e3SJoseph Koshy 
1623ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_rbt[] = { /* retired branch type */
1624ebccf1e3SJoseph Koshy 	__P4MASK(conditional, 1),
1625ebccf1e3SJoseph Koshy 	__P4MASK(call, 2),
1626ebccf1e3SJoseph Koshy 	__P4MASK(retired, 3),
1627ebccf1e3SJoseph Koshy 	__P4MASK(indirect, 4),
1628ebccf1e3SJoseph Koshy 	NULLMASK
1629ebccf1e3SJoseph Koshy };
1630ebccf1e3SJoseph Koshy 
1631ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_rs[] = { /* resource stall */
1632ebccf1e3SJoseph Koshy 	__P4MASK(sbfull, 5),
1633ebccf1e3SJoseph Koshy 	NULLMASK
1634ebccf1e3SJoseph Koshy };
1635ebccf1e3SJoseph Koshy 
1636ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_wb[] = { /* WC buffer */
1637ebccf1e3SJoseph Koshy 	__P4MASK(wcb-evicts, 0),
1638ebccf1e3SJoseph Koshy 	__P4MASK(wcb-full-evict, 1),
1639ebccf1e3SJoseph Koshy 	NULLMASK
1640ebccf1e3SJoseph Koshy };
1641ebccf1e3SJoseph Koshy 
1642ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_fee[] = { /* front end event */
1643ebccf1e3SJoseph Koshy 	__P4MASK(nbogus, 0),
1644ebccf1e3SJoseph Koshy 	__P4MASK(bogus, 1),
1645ebccf1e3SJoseph Koshy 	NULLMASK
1646ebccf1e3SJoseph Koshy };
1647ebccf1e3SJoseph Koshy 
1648ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_ee[] = { /* execution event */
1649ebccf1e3SJoseph Koshy 	__P4MASK(nbogus0, 0),
1650ebccf1e3SJoseph Koshy 	__P4MASK(nbogus1, 1),
1651ebccf1e3SJoseph Koshy 	__P4MASK(nbogus2, 2),
1652ebccf1e3SJoseph Koshy 	__P4MASK(nbogus3, 3),
1653ebccf1e3SJoseph Koshy 	__P4MASK(bogus0, 4),
1654ebccf1e3SJoseph Koshy 	__P4MASK(bogus1, 5),
1655ebccf1e3SJoseph Koshy 	__P4MASK(bogus2, 6),
1656ebccf1e3SJoseph Koshy 	__P4MASK(bogus3, 7),
1657ebccf1e3SJoseph Koshy 	NULLMASK
1658ebccf1e3SJoseph Koshy };
1659ebccf1e3SJoseph Koshy 
1660ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_re[] = { /* replay event */
1661ebccf1e3SJoseph Koshy 	__P4MASK(nbogus, 0),
1662ebccf1e3SJoseph Koshy 	__P4MASK(bogus, 1),
1663ebccf1e3SJoseph Koshy 	NULLMASK
1664ebccf1e3SJoseph Koshy };
1665ebccf1e3SJoseph Koshy 
1666ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_insret[] = { /* instr retired */
1667ebccf1e3SJoseph Koshy 	__P4MASK(nbogusntag, 0),
1668ebccf1e3SJoseph Koshy 	__P4MASK(nbogustag, 1),
1669ebccf1e3SJoseph Koshy 	__P4MASK(bogusntag, 2),
1670ebccf1e3SJoseph Koshy 	__P4MASK(bogustag, 3),
1671ebccf1e3SJoseph Koshy 	NULLMASK
1672ebccf1e3SJoseph Koshy };
1673ebccf1e3SJoseph Koshy 
1674ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_ur[] = { /* uops retired */
1675ebccf1e3SJoseph Koshy 	__P4MASK(nbogus, 0),
1676ebccf1e3SJoseph Koshy 	__P4MASK(bogus, 1),
1677ebccf1e3SJoseph Koshy 	NULLMASK
1678ebccf1e3SJoseph Koshy };
1679ebccf1e3SJoseph Koshy 
1680ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_ut[] = { /* uop type */
1681ebccf1e3SJoseph Koshy 	__P4MASK(tagloads, 1),
1682ebccf1e3SJoseph Koshy 	__P4MASK(tagstores, 2),
1683ebccf1e3SJoseph Koshy 	NULLMASK
1684ebccf1e3SJoseph Koshy };
1685ebccf1e3SJoseph Koshy 
1686ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_br[] = { /* branch retired */
1687ebccf1e3SJoseph Koshy 	__P4MASK(mmnp, 0),
1688ebccf1e3SJoseph Koshy 	__P4MASK(mmnm, 1),
1689ebccf1e3SJoseph Koshy 	__P4MASK(mmtp, 2),
1690ebccf1e3SJoseph Koshy 	__P4MASK(mmtm, 3),
1691ebccf1e3SJoseph Koshy 	NULLMASK
1692ebccf1e3SJoseph Koshy };
1693ebccf1e3SJoseph Koshy 
1694ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_mbr[] = { /* mispred branch retired */
1695ebccf1e3SJoseph Koshy 	__P4MASK(nbogus, 0),
1696ebccf1e3SJoseph Koshy 	NULLMASK
1697ebccf1e3SJoseph Koshy };
1698ebccf1e3SJoseph Koshy 
1699ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_xa[] = { /* x87 assist */
1700ebccf1e3SJoseph Koshy 	__P4MASK(fpsu, 0),
1701ebccf1e3SJoseph Koshy 	__P4MASK(fpso, 1),
1702ebccf1e3SJoseph Koshy 	__P4MASK(poao, 2),
1703ebccf1e3SJoseph Koshy 	__P4MASK(poau, 3),
1704ebccf1e3SJoseph Koshy 	__P4MASK(prea, 4),
1705ebccf1e3SJoseph Koshy 	NULLMASK
1706ebccf1e3SJoseph Koshy };
1707ebccf1e3SJoseph Koshy 
1708ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_machclr[] = { /* machine clear */
1709ebccf1e3SJoseph Koshy 	__P4MASK(clear, 0),
1710ebccf1e3SJoseph Koshy 	__P4MASK(moclear, 2),
1711ebccf1e3SJoseph Koshy 	__P4MASK(smclear, 3),
1712ebccf1e3SJoseph Koshy 	NULLMASK
1713ebccf1e3SJoseph Koshy };
1714ebccf1e3SJoseph Koshy 
1715ebccf1e3SJoseph Koshy /* P4 event parser */
1716ebccf1e3SJoseph Koshy static int
1717ebccf1e3SJoseph Koshy p4_allocate_pmc(enum pmc_event pe, char *ctrspec,
1718ebccf1e3SJoseph Koshy     struct pmc_op_pmcallocate *pmc_config)
1719ebccf1e3SJoseph Koshy {
1720ebccf1e3SJoseph Koshy 
1721ebccf1e3SJoseph Koshy 	char	*e, *p, *q;
1722ebccf1e3SJoseph Koshy 	int	count, has_tag, has_busreqtype, n;
17231e862e5aSFabien Thomas 	uint32_t cccractivemask;
17241e862e5aSFabien Thomas 	uint64_t evmask;
1725ebccf1e3SJoseph Koshy 	const struct pmc_masks *pm, *pmask;
1726ebccf1e3SJoseph Koshy 
1727789140c0SJoseph Koshy 	pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE);
1728f263522aSJoseph Koshy 	pmc_config->pm_md.pm_p4.pm_p4_cccrconfig =
1729f263522aSJoseph Koshy 	    pmc_config->pm_md.pm_p4.pm_p4_escrconfig = 0;
1730ebccf1e3SJoseph Koshy 
1731ebccf1e3SJoseph Koshy 	pmask   = NULL;
1732ebccf1e3SJoseph Koshy 	evmask  = 0;
1733ebccf1e3SJoseph Koshy 	cccractivemask = 0x3;
1734ebccf1e3SJoseph Koshy 	has_tag = has_busreqtype = 0;
1735ebccf1e3SJoseph Koshy 
1736ebccf1e3SJoseph Koshy #define	__P4SETMASK(M) do {				\
1737ebccf1e3SJoseph Koshy 	pmask = p4_mask_##M;				\
1738ebccf1e3SJoseph Koshy } while (0)
1739ebccf1e3SJoseph Koshy 
1740ebccf1e3SJoseph Koshy 	switch (pe) {
1741ebccf1e3SJoseph Koshy 	case PMC_EV_P4_TC_DELIVER_MODE:
1742ebccf1e3SJoseph Koshy 		__P4SETMASK(tcdm);
1743ebccf1e3SJoseph Koshy 		break;
1744ebccf1e3SJoseph Koshy 	case PMC_EV_P4_BPU_FETCH_REQUEST:
1745ebccf1e3SJoseph Koshy 		__P4SETMASK(bfr);
1746ebccf1e3SJoseph Koshy 		break;
1747ebccf1e3SJoseph Koshy 	case PMC_EV_P4_ITLB_REFERENCE:
1748ebccf1e3SJoseph Koshy 		__P4SETMASK(ir);
1749ebccf1e3SJoseph Koshy 		break;
1750ebccf1e3SJoseph Koshy 	case PMC_EV_P4_MEMORY_CANCEL:
1751ebccf1e3SJoseph Koshy 		__P4SETMASK(memcan);
1752ebccf1e3SJoseph Koshy 		break;
1753ebccf1e3SJoseph Koshy 	case PMC_EV_P4_MEMORY_COMPLETE:
1754ebccf1e3SJoseph Koshy 		__P4SETMASK(memcomp);
1755ebccf1e3SJoseph Koshy 		break;
1756ebccf1e3SJoseph Koshy 	case PMC_EV_P4_LOAD_PORT_REPLAY:
1757ebccf1e3SJoseph Koshy 		__P4SETMASK(lpr);
1758ebccf1e3SJoseph Koshy 		break;
1759ebccf1e3SJoseph Koshy 	case PMC_EV_P4_STORE_PORT_REPLAY:
1760ebccf1e3SJoseph Koshy 		__P4SETMASK(spr);
1761ebccf1e3SJoseph Koshy 		break;
1762ebccf1e3SJoseph Koshy 	case PMC_EV_P4_MOB_LOAD_REPLAY:
1763ebccf1e3SJoseph Koshy 		__P4SETMASK(mlr);
1764ebccf1e3SJoseph Koshy 		break;
1765ebccf1e3SJoseph Koshy 	case PMC_EV_P4_PAGE_WALK_TYPE:
1766ebccf1e3SJoseph Koshy 		__P4SETMASK(pwt);
1767ebccf1e3SJoseph Koshy 		break;
1768ebccf1e3SJoseph Koshy 	case PMC_EV_P4_BSQ_CACHE_REFERENCE:
1769ebccf1e3SJoseph Koshy 		__P4SETMASK(bcr);
1770ebccf1e3SJoseph Koshy 		break;
1771ebccf1e3SJoseph Koshy 	case PMC_EV_P4_IOQ_ALLOCATION:
1772ebccf1e3SJoseph Koshy 		__P4SETMASK(ia);
1773ebccf1e3SJoseph Koshy 		has_busreqtype = 1;
1774ebccf1e3SJoseph Koshy 		break;
1775ebccf1e3SJoseph Koshy 	case PMC_EV_P4_IOQ_ACTIVE_ENTRIES:
1776ebccf1e3SJoseph Koshy 		__P4SETMASK(iae);
1777ebccf1e3SJoseph Koshy 		has_busreqtype = 1;
1778ebccf1e3SJoseph Koshy 		break;
1779ebccf1e3SJoseph Koshy 	case PMC_EV_P4_FSB_DATA_ACTIVITY:
1780ebccf1e3SJoseph Koshy 		__P4SETMASK(fda);
1781ebccf1e3SJoseph Koshy 		break;
1782ebccf1e3SJoseph Koshy 	case PMC_EV_P4_BSQ_ALLOCATION:
1783ebccf1e3SJoseph Koshy 		__P4SETMASK(ba);
1784ebccf1e3SJoseph Koshy 		break;
1785ebccf1e3SJoseph Koshy 	case PMC_EV_P4_SSE_INPUT_ASSIST:
1786ebccf1e3SJoseph Koshy 		__P4SETMASK(sia);
1787ebccf1e3SJoseph Koshy 		break;
1788ebccf1e3SJoseph Koshy 	case PMC_EV_P4_PACKED_SP_UOP:
1789ebccf1e3SJoseph Koshy 		__P4SETMASK(psu);
1790ebccf1e3SJoseph Koshy 		break;
1791ebccf1e3SJoseph Koshy 	case PMC_EV_P4_PACKED_DP_UOP:
1792ebccf1e3SJoseph Koshy 		__P4SETMASK(pdu);
1793ebccf1e3SJoseph Koshy 		break;
1794ebccf1e3SJoseph Koshy 	case PMC_EV_P4_SCALAR_SP_UOP:
1795ebccf1e3SJoseph Koshy 		__P4SETMASK(ssu);
1796ebccf1e3SJoseph Koshy 		break;
1797ebccf1e3SJoseph Koshy 	case PMC_EV_P4_SCALAR_DP_UOP:
1798ebccf1e3SJoseph Koshy 		__P4SETMASK(sdu);
1799ebccf1e3SJoseph Koshy 		break;
1800ebccf1e3SJoseph Koshy 	case PMC_EV_P4_64BIT_MMX_UOP:
1801ebccf1e3SJoseph Koshy 		__P4SETMASK(64bmu);
1802ebccf1e3SJoseph Koshy 		break;
1803ebccf1e3SJoseph Koshy 	case PMC_EV_P4_128BIT_MMX_UOP:
1804ebccf1e3SJoseph Koshy 		__P4SETMASK(128bmu);
1805ebccf1e3SJoseph Koshy 		break;
1806ebccf1e3SJoseph Koshy 	case PMC_EV_P4_X87_FP_UOP:
1807ebccf1e3SJoseph Koshy 		__P4SETMASK(xfu);
1808ebccf1e3SJoseph Koshy 		break;
1809ebccf1e3SJoseph Koshy 	case PMC_EV_P4_X87_SIMD_MOVES_UOP:
1810ebccf1e3SJoseph Koshy 		__P4SETMASK(xsmu);
1811ebccf1e3SJoseph Koshy 		break;
1812ebccf1e3SJoseph Koshy 	case PMC_EV_P4_GLOBAL_POWER_EVENTS:
1813ebccf1e3SJoseph Koshy 		__P4SETMASK(gpe);
1814ebccf1e3SJoseph Koshy 		break;
1815ebccf1e3SJoseph Koshy 	case PMC_EV_P4_TC_MS_XFER:
1816ebccf1e3SJoseph Koshy 		__P4SETMASK(tmx);
1817ebccf1e3SJoseph Koshy 		break;
1818ebccf1e3SJoseph Koshy 	case PMC_EV_P4_UOP_QUEUE_WRITES:
1819ebccf1e3SJoseph Koshy 		__P4SETMASK(uqw);
1820ebccf1e3SJoseph Koshy 		break;
1821ebccf1e3SJoseph Koshy 	case PMC_EV_P4_RETIRED_MISPRED_BRANCH_TYPE:
1822ebccf1e3SJoseph Koshy 		__P4SETMASK(rmbt);
1823ebccf1e3SJoseph Koshy 		break;
1824ebccf1e3SJoseph Koshy 	case PMC_EV_P4_RETIRED_BRANCH_TYPE:
1825ebccf1e3SJoseph Koshy 		__P4SETMASK(rbt);
1826ebccf1e3SJoseph Koshy 		break;
1827ebccf1e3SJoseph Koshy 	case PMC_EV_P4_RESOURCE_STALL:
1828ebccf1e3SJoseph Koshy 		__P4SETMASK(rs);
1829ebccf1e3SJoseph Koshy 		break;
1830ebccf1e3SJoseph Koshy 	case PMC_EV_P4_WC_BUFFER:
1831ebccf1e3SJoseph Koshy 		__P4SETMASK(wb);
1832ebccf1e3SJoseph Koshy 		break;
1833ebccf1e3SJoseph Koshy 	case PMC_EV_P4_BSQ_ACTIVE_ENTRIES:
1834ebccf1e3SJoseph Koshy 	case PMC_EV_P4_B2B_CYCLES:
1835ebccf1e3SJoseph Koshy 	case PMC_EV_P4_BNR:
1836ebccf1e3SJoseph Koshy 	case PMC_EV_P4_SNOOP:
1837ebccf1e3SJoseph Koshy 	case PMC_EV_P4_RESPONSE:
1838ebccf1e3SJoseph Koshy 		break;
1839ebccf1e3SJoseph Koshy 	case PMC_EV_P4_FRONT_END_EVENT:
1840ebccf1e3SJoseph Koshy 		__P4SETMASK(fee);
1841ebccf1e3SJoseph Koshy 		break;
1842ebccf1e3SJoseph Koshy 	case PMC_EV_P4_EXECUTION_EVENT:
1843ebccf1e3SJoseph Koshy 		__P4SETMASK(ee);
1844ebccf1e3SJoseph Koshy 		break;
1845ebccf1e3SJoseph Koshy 	case PMC_EV_P4_REPLAY_EVENT:
1846ebccf1e3SJoseph Koshy 		__P4SETMASK(re);
1847ebccf1e3SJoseph Koshy 		break;
1848ebccf1e3SJoseph Koshy 	case PMC_EV_P4_INSTR_RETIRED:
1849ebccf1e3SJoseph Koshy 		__P4SETMASK(insret);
1850ebccf1e3SJoseph Koshy 		break;
1851ebccf1e3SJoseph Koshy 	case PMC_EV_P4_UOPS_RETIRED:
1852ebccf1e3SJoseph Koshy 		__P4SETMASK(ur);
1853ebccf1e3SJoseph Koshy 		break;
1854ebccf1e3SJoseph Koshy 	case PMC_EV_P4_UOP_TYPE:
1855ebccf1e3SJoseph Koshy 		__P4SETMASK(ut);
1856ebccf1e3SJoseph Koshy 		break;
1857ebccf1e3SJoseph Koshy 	case PMC_EV_P4_BRANCH_RETIRED:
1858ebccf1e3SJoseph Koshy 		__P4SETMASK(br);
1859ebccf1e3SJoseph Koshy 		break;
1860ebccf1e3SJoseph Koshy 	case PMC_EV_P4_MISPRED_BRANCH_RETIRED:
1861ebccf1e3SJoseph Koshy 		__P4SETMASK(mbr);
1862ebccf1e3SJoseph Koshy 		break;
1863ebccf1e3SJoseph Koshy 	case PMC_EV_P4_X87_ASSIST:
1864ebccf1e3SJoseph Koshy 		__P4SETMASK(xa);
1865ebccf1e3SJoseph Koshy 		break;
1866ebccf1e3SJoseph Koshy 	case PMC_EV_P4_MACHINE_CLEAR:
1867ebccf1e3SJoseph Koshy 		__P4SETMASK(machclr);
1868ebccf1e3SJoseph Koshy 		break;
1869ebccf1e3SJoseph Koshy 	default:
1870aa342b1fSJoseph Koshy 		return (-1);
1871ebccf1e3SJoseph Koshy 	}
1872ebccf1e3SJoseph Koshy 
1873ebccf1e3SJoseph Koshy 	/* process additional flags */
1874ebccf1e3SJoseph Koshy 	while ((p = strsep(&ctrspec, ",")) != NULL) {
1875ebccf1e3SJoseph Koshy 		if (KWPREFIXMATCH(p, P4_KW_ACTIVE)) {
1876ebccf1e3SJoseph Koshy 			q = strchr(p, '=');
1877ebccf1e3SJoseph Koshy 			if (*++q == '\0') /* skip '=' */
1878aa342b1fSJoseph Koshy 				return (-1);
1879ebccf1e3SJoseph Koshy 
1880789140c0SJoseph Koshy 			if (strcasecmp(q, P4_KW_ACTIVE_NONE) == 0)
1881ebccf1e3SJoseph Koshy 				cccractivemask = 0x0;
1882789140c0SJoseph Koshy 			else if (strcasecmp(q, P4_KW_ACTIVE_SINGLE) == 0)
1883ebccf1e3SJoseph Koshy 				cccractivemask = 0x1;
1884789140c0SJoseph Koshy 			else if (strcasecmp(q, P4_KW_ACTIVE_BOTH) == 0)
1885ebccf1e3SJoseph Koshy 				cccractivemask = 0x2;
1886789140c0SJoseph Koshy 			else if (strcasecmp(q, P4_KW_ACTIVE_ANY) == 0)
1887ebccf1e3SJoseph Koshy 				cccractivemask = 0x3;
1888ebccf1e3SJoseph Koshy 			else
1889aa342b1fSJoseph Koshy 				return (-1);
1890ebccf1e3SJoseph Koshy 
1891ebccf1e3SJoseph Koshy 		} else if (KWPREFIXMATCH(p, P4_KW_BUSREQTYPE)) {
1892ebccf1e3SJoseph Koshy 			if (has_busreqtype == 0)
1893aa342b1fSJoseph Koshy 				return (-1);
1894ebccf1e3SJoseph Koshy 
1895ebccf1e3SJoseph Koshy 			q = strchr(p, '=');
1896ebccf1e3SJoseph Koshy 			if (*++q == '\0') /* skip '=' */
1897aa342b1fSJoseph Koshy 				return (-1);
1898ebccf1e3SJoseph Koshy 
1899ebccf1e3SJoseph Koshy 			count = strtol(q, &e, 0);
1900ebccf1e3SJoseph Koshy 			if (e == q || *e != '\0')
1901aa342b1fSJoseph Koshy 				return (-1);
1902ebccf1e3SJoseph Koshy 			evmask = (evmask & ~0x1F) | (count & 0x1F);
1903ebccf1e3SJoseph Koshy 		} else if (KWMATCH(p, P4_KW_CASCADE))
1904ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_CASCADE;
1905ebccf1e3SJoseph Koshy 		else if (KWMATCH(p, P4_KW_EDGE))
1906ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_EDGE;
1907ebccf1e3SJoseph Koshy 		else if (KWMATCH(p, P4_KW_INV))
1908ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_INVERT;
1909ebccf1e3SJoseph Koshy 		else if (KWPREFIXMATCH(p, P4_KW_MASK "=")) {
1910ebccf1e3SJoseph Koshy 			if ((n = pmc_parse_mask(pmask, p, &evmask)) < 0)
1911aa342b1fSJoseph Koshy 				return (-1);
1912ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_QUALIFIER;
1913ebccf1e3SJoseph Koshy 		} else if (KWMATCH(p, P4_KW_OS))
1914ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_SYSTEM;
1915ebccf1e3SJoseph Koshy 		else if (KWMATCH(p, P4_KW_PRECISE))
1916ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_PRECISE;
1917ebccf1e3SJoseph Koshy 		else if (KWPREFIXMATCH(p, P4_KW_TAG "=")) {
1918ebccf1e3SJoseph Koshy 			if (has_tag == 0)
1919aa342b1fSJoseph Koshy 				return (-1);
1920ebccf1e3SJoseph Koshy 
1921ebccf1e3SJoseph Koshy 			q = strchr(p, '=');
1922ebccf1e3SJoseph Koshy 			if (*++q == '\0') /* skip '=' */
1923aa342b1fSJoseph Koshy 				return (-1);
1924ebccf1e3SJoseph Koshy 
1925ebccf1e3SJoseph Koshy 			count = strtol(q, &e, 0);
1926ebccf1e3SJoseph Koshy 			if (e == q || *e != '\0')
1927aa342b1fSJoseph Koshy 				return (-1);
1928ebccf1e3SJoseph Koshy 
1929ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_TAGGING;
1930f263522aSJoseph Koshy 			pmc_config->pm_md.pm_p4.pm_p4_escrconfig |=
1931ebccf1e3SJoseph Koshy 			    P4_ESCR_TO_TAG_VALUE(count);
1932ebccf1e3SJoseph Koshy 		} else if (KWPREFIXMATCH(p, P4_KW_THRESHOLD "=")) {
1933ebccf1e3SJoseph Koshy 			q = strchr(p, '=');
1934ebccf1e3SJoseph Koshy 			if (*++q == '\0') /* skip '=' */
1935aa342b1fSJoseph Koshy 				return (-1);
1936ebccf1e3SJoseph Koshy 
1937ebccf1e3SJoseph Koshy 			count = strtol(q, &e, 0);
1938ebccf1e3SJoseph Koshy 			if (e == q || *e != '\0')
1939aa342b1fSJoseph Koshy 				return (-1);
1940ebccf1e3SJoseph Koshy 
1941ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_THRESHOLD;
1942f263522aSJoseph Koshy 			pmc_config->pm_md.pm_p4.pm_p4_cccrconfig &=
1943f263522aSJoseph Koshy 			    ~P4_CCCR_THRESHOLD_MASK;
1944f263522aSJoseph Koshy 			pmc_config->pm_md.pm_p4.pm_p4_cccrconfig |=
1945f263522aSJoseph Koshy 			    P4_CCCR_TO_THRESHOLD(count);
1946ebccf1e3SJoseph Koshy 		} else if (KWMATCH(p, P4_KW_USR))
1947ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_USER;
1948ebccf1e3SJoseph Koshy 		else
1949aa342b1fSJoseph Koshy 			return (-1);
1950ebccf1e3SJoseph Koshy 	}
1951ebccf1e3SJoseph Koshy 
1952ebccf1e3SJoseph Koshy 	/* other post processing */
1953ebccf1e3SJoseph Koshy 	if (pe == PMC_EV_P4_IOQ_ALLOCATION ||
1954ebccf1e3SJoseph Koshy 	    pe == PMC_EV_P4_FSB_DATA_ACTIVITY ||
1955ebccf1e3SJoseph Koshy 	    pe == PMC_EV_P4_BSQ_ALLOCATION)
1956ebccf1e3SJoseph Koshy 		pmc_config->pm_caps |= PMC_CAP_EDGE;
1957ebccf1e3SJoseph Koshy 
1958ebccf1e3SJoseph Koshy 	/* fill in thread activity mask */
1959f263522aSJoseph Koshy 	pmc_config->pm_md.pm_p4.pm_p4_cccrconfig |=
1960ebccf1e3SJoseph Koshy 	    P4_CCCR_TO_ACTIVE_THREAD(cccractivemask);
1961ebccf1e3SJoseph Koshy 
1962ebccf1e3SJoseph Koshy 	if (evmask)
1963ebccf1e3SJoseph Koshy 		pmc_config->pm_caps |= PMC_CAP_QUALIFIER;
1964ebccf1e3SJoseph Koshy 
1965ebccf1e3SJoseph Koshy 	switch (pe) {
1966ebccf1e3SJoseph Koshy 	case PMC_EV_P4_FSB_DATA_ACTIVITY:
1967ebccf1e3SJoseph Koshy 		if ((evmask & 0x06) == 0x06 ||
1968ebccf1e3SJoseph Koshy 		    (evmask & 0x18) == 0x18)
1969aa342b1fSJoseph Koshy 			return (-1); /* can't have own+other bits together */
1970ebccf1e3SJoseph Koshy 		if (evmask == 0) /* default:drdy-{drv,own}+dbsy{drv,own} */
1971ebccf1e3SJoseph Koshy 			evmask = 0x1D;
1972ebccf1e3SJoseph Koshy 		break;
1973ebccf1e3SJoseph Koshy 	case PMC_EV_P4_MACHINE_CLEAR:
1974ebccf1e3SJoseph Koshy 		/* only one bit is allowed to be set */
1975ebccf1e3SJoseph Koshy 		if ((evmask & (evmask - 1)) != 0)
1976aa342b1fSJoseph Koshy 			return (-1);
1977ebccf1e3SJoseph Koshy 		if (evmask == 0) {
1978ebccf1e3SJoseph Koshy 			evmask = 0x1;	/* 'CLEAR' */
1979ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_QUALIFIER;
1980ebccf1e3SJoseph Koshy 		}
1981ebccf1e3SJoseph Koshy 		break;
1982ebccf1e3SJoseph Koshy 	default:
1983ebccf1e3SJoseph Koshy 		if (evmask == 0 && pmask) {
1984ebccf1e3SJoseph Koshy 			for (pm = pmask; pm->pm_name; pm++)
1985ebccf1e3SJoseph Koshy 				evmask |= pm->pm_value;
1986ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_QUALIFIER;
1987ebccf1e3SJoseph Koshy 		}
1988ebccf1e3SJoseph Koshy 	}
1989ebccf1e3SJoseph Koshy 
1990f263522aSJoseph Koshy 	pmc_config->pm_md.pm_p4.pm_p4_escrconfig =
1991f263522aSJoseph Koshy 	    P4_ESCR_TO_EVENT_MASK(evmask);
1992ebccf1e3SJoseph Koshy 
1993aa342b1fSJoseph Koshy 	return (0);
1994ebccf1e3SJoseph Koshy }
1995ebccf1e3SJoseph Koshy 
199686a65549SJoseph Koshy #endif
199786a65549SJoseph Koshy 
199886a65549SJoseph Koshy #if defined(__i386__)
199986a65549SJoseph Koshy 
2000ebccf1e3SJoseph Koshy /*
2001f263522aSJoseph Koshy  * Pentium style PMCs
2002f263522aSJoseph Koshy  */
2003f263522aSJoseph Koshy 
2004f263522aSJoseph Koshy static struct pmc_event_alias p5_aliases[] = {
20050b9b757dSJoseph Koshy 	EV_ALIAS("branches",		"p5-taken-branches"),
2006f263522aSJoseph Koshy 	EV_ALIAS("cycles",		"tsc"),
20070b9b757dSJoseph Koshy 	EV_ALIAS("dc-misses",		"p5-data-read-miss-or-write-miss"),
20080b9b757dSJoseph Koshy 	EV_ALIAS("ic-misses",		"p5-code-cache-miss"),
20090b9b757dSJoseph Koshy 	EV_ALIAS("instructions",	"p5-instructions-executed"),
20100b9b757dSJoseph Koshy 	EV_ALIAS("interrupts",		"p5-hardware-interrupts"),
20110b9b757dSJoseph Koshy 	EV_ALIAS("unhalted-cycles",
20120b9b757dSJoseph Koshy 	    "p5-number-of-cycles-not-in-halt-state"),
2013f263522aSJoseph Koshy 	EV_ALIAS(NULL, NULL)
2014f263522aSJoseph Koshy };
2015f263522aSJoseph Koshy 
2016f263522aSJoseph Koshy static int
2017f263522aSJoseph Koshy p5_allocate_pmc(enum pmc_event pe, char *ctrspec,
2018f263522aSJoseph Koshy     struct pmc_op_pmcallocate *pmc_config)
2019f263522aSJoseph Koshy {
2020aa342b1fSJoseph Koshy 	return (-1 || pe || ctrspec || pmc_config); /* shut up gcc */
2021f263522aSJoseph Koshy }
2022f263522aSJoseph Koshy 
2023f263522aSJoseph Koshy /*
2024ebccf1e3SJoseph Koshy  * Pentium Pro style PMCs.  These PMCs are found in Pentium II, Pentium III,
2025ebccf1e3SJoseph Koshy  * and Pentium M CPUs.
2026ebccf1e3SJoseph Koshy  */
2027ebccf1e3SJoseph Koshy 
2028ebccf1e3SJoseph Koshy static struct pmc_event_alias p6_aliases[] = {
2029ebccf1e3SJoseph Koshy 	EV_ALIAS("branches",		"p6-br-inst-retired"),
2030ebccf1e3SJoseph Koshy 	EV_ALIAS("branch-mispredicts",	"p6-br-miss-pred-retired"),
2031ebccf1e3SJoseph Koshy 	EV_ALIAS("cycles",		"tsc"),
2032d56c5d4bSJoseph Koshy 	EV_ALIAS("dc-misses",		"p6-dcu-lines-in"),
203373e2d811SJoseph Koshy 	EV_ALIAS("ic-misses",		"p6-ifu-fetch-miss"),
2034ebccf1e3SJoseph Koshy 	EV_ALIAS("instructions",	"p6-inst-retired"),
2035ebccf1e3SJoseph Koshy 	EV_ALIAS("interrupts",		"p6-hw-int-rx"),
2036177a2f22SJoseph Koshy 	EV_ALIAS("unhalted-cycles",	"p6-cpu-clk-unhalted"),
2037ebccf1e3SJoseph Koshy 	EV_ALIAS(NULL, NULL)
2038ebccf1e3SJoseph Koshy };
2039ebccf1e3SJoseph Koshy 
2040ebccf1e3SJoseph Koshy #define	P6_KW_CMASK	"cmask"
2041ebccf1e3SJoseph Koshy #define	P6_KW_EDGE	"edge"
2042ebccf1e3SJoseph Koshy #define	P6_KW_INV	"inv"
2043ebccf1e3SJoseph Koshy #define	P6_KW_OS	"os"
2044ebccf1e3SJoseph Koshy #define	P6_KW_UMASK	"umask"
2045ebccf1e3SJoseph Koshy #define	P6_KW_USR	"usr"
2046ebccf1e3SJoseph Koshy 
2047ebccf1e3SJoseph Koshy static struct pmc_masks p6_mask_mesi[] = {
2048ebccf1e3SJoseph Koshy 	PMCMASK(m,	0x01),
2049ebccf1e3SJoseph Koshy 	PMCMASK(e,	0x02),
2050ebccf1e3SJoseph Koshy 	PMCMASK(s,	0x04),
2051ebccf1e3SJoseph Koshy 	PMCMASK(i,	0x08),
2052ebccf1e3SJoseph Koshy 	NULLMASK
2053ebccf1e3SJoseph Koshy };
2054ebccf1e3SJoseph Koshy 
2055ebccf1e3SJoseph Koshy static struct pmc_masks p6_mask_mesihw[] = {
2056ebccf1e3SJoseph Koshy 	PMCMASK(m,	0x01),
2057ebccf1e3SJoseph Koshy 	PMCMASK(e,	0x02),
2058ebccf1e3SJoseph Koshy 	PMCMASK(s,	0x04),
2059ebccf1e3SJoseph Koshy 	PMCMASK(i,	0x08),
2060ebccf1e3SJoseph Koshy 	PMCMASK(nonhw,	0x00),
2061ebccf1e3SJoseph Koshy 	PMCMASK(hw,	0x10),
2062ebccf1e3SJoseph Koshy 	PMCMASK(both,	0x30),
2063ebccf1e3SJoseph Koshy 	NULLMASK
2064ebccf1e3SJoseph Koshy };
2065ebccf1e3SJoseph Koshy 
2066ebccf1e3SJoseph Koshy static struct pmc_masks p6_mask_hw[] = {
2067ebccf1e3SJoseph Koshy 	PMCMASK(nonhw,	0x00),
2068ebccf1e3SJoseph Koshy 	PMCMASK(hw,	0x10),
2069ebccf1e3SJoseph Koshy 	PMCMASK(both,	0x30),
2070ebccf1e3SJoseph Koshy 	NULLMASK
2071ebccf1e3SJoseph Koshy };
2072ebccf1e3SJoseph Koshy 
2073ebccf1e3SJoseph Koshy static struct pmc_masks p6_mask_any[] = {
2074ebccf1e3SJoseph Koshy 	PMCMASK(self,	0x00),
2075ebccf1e3SJoseph Koshy 	PMCMASK(any,	0x20),
2076ebccf1e3SJoseph Koshy 	NULLMASK
2077ebccf1e3SJoseph Koshy };
2078ebccf1e3SJoseph Koshy 
2079ebccf1e3SJoseph Koshy static struct pmc_masks p6_mask_ekp[] = {
2080ebccf1e3SJoseph Koshy 	PMCMASK(nta,	0x00),
2081ebccf1e3SJoseph Koshy 	PMCMASK(t1,	0x01),
2082ebccf1e3SJoseph Koshy 	PMCMASK(t2,	0x02),
2083ebccf1e3SJoseph Koshy 	PMCMASK(wos,	0x03),
2084ebccf1e3SJoseph Koshy 	NULLMASK
2085ebccf1e3SJoseph Koshy };
2086ebccf1e3SJoseph Koshy 
2087ebccf1e3SJoseph Koshy static struct pmc_masks p6_mask_pps[] = {
2088ebccf1e3SJoseph Koshy 	PMCMASK(packed-and-scalar, 0x00),
2089ebccf1e3SJoseph Koshy 	PMCMASK(scalar,	0x01),
2090ebccf1e3SJoseph Koshy 	NULLMASK
2091ebccf1e3SJoseph Koshy };
2092ebccf1e3SJoseph Koshy 
2093ebccf1e3SJoseph Koshy static struct pmc_masks p6_mask_mite[] = {
2094ebccf1e3SJoseph Koshy 	PMCMASK(packed-multiply,	 0x01),
2095ebccf1e3SJoseph Koshy 	PMCMASK(packed-shift,		0x02),
2096ebccf1e3SJoseph Koshy 	PMCMASK(pack,			0x04),
2097ebccf1e3SJoseph Koshy 	PMCMASK(unpack,			0x08),
2098ebccf1e3SJoseph Koshy 	PMCMASK(packed-logical,		0x10),
2099ebccf1e3SJoseph Koshy 	PMCMASK(packed-arithmetic,	0x20),
2100ebccf1e3SJoseph Koshy 	NULLMASK
2101ebccf1e3SJoseph Koshy };
2102ebccf1e3SJoseph Koshy 
2103ebccf1e3SJoseph Koshy static struct pmc_masks p6_mask_fmt[] = {
2104ebccf1e3SJoseph Koshy 	PMCMASK(mmxtofp,	0x00),
2105ebccf1e3SJoseph Koshy 	PMCMASK(fptommx,	0x01),
2106ebccf1e3SJoseph Koshy 	NULLMASK
2107ebccf1e3SJoseph Koshy };
2108ebccf1e3SJoseph Koshy 
2109ebccf1e3SJoseph Koshy static struct pmc_masks p6_mask_sr[] = {
2110ebccf1e3SJoseph Koshy 	PMCMASK(es,	0x01),
2111ebccf1e3SJoseph Koshy 	PMCMASK(ds,	0x02),
2112ebccf1e3SJoseph Koshy 	PMCMASK(fs,	0x04),
2113ebccf1e3SJoseph Koshy 	PMCMASK(gs,	0x08),
2114ebccf1e3SJoseph Koshy 	NULLMASK
2115ebccf1e3SJoseph Koshy };
2116ebccf1e3SJoseph Koshy 
2117ebccf1e3SJoseph Koshy static struct pmc_masks p6_mask_eet[] = {
2118ebccf1e3SJoseph Koshy 	PMCMASK(all,	0x00),
2119ebccf1e3SJoseph Koshy 	PMCMASK(freq,	0x02),
2120ebccf1e3SJoseph Koshy 	NULLMASK
2121ebccf1e3SJoseph Koshy };
2122ebccf1e3SJoseph Koshy 
2123ebccf1e3SJoseph Koshy static struct pmc_masks p6_mask_efur[] = {
2124ebccf1e3SJoseph Koshy 	PMCMASK(all,	0x00),
2125ebccf1e3SJoseph Koshy 	PMCMASK(loadop,	0x01),
2126ebccf1e3SJoseph Koshy 	PMCMASK(stdsta,	0x02),
2127ebccf1e3SJoseph Koshy 	NULLMASK
2128ebccf1e3SJoseph Koshy };
2129ebccf1e3SJoseph Koshy 
2130ebccf1e3SJoseph Koshy static struct pmc_masks p6_mask_essir[] = {
2131ebccf1e3SJoseph Koshy 	PMCMASK(sse-packed-single,	0x00),
2132ebccf1e3SJoseph Koshy 	PMCMASK(sse-packed-single-scalar-single, 0x01),
2133ebccf1e3SJoseph Koshy 	PMCMASK(sse2-packed-double,	0x02),
2134ebccf1e3SJoseph Koshy 	PMCMASK(sse2-scalar-double,	0x03),
2135ebccf1e3SJoseph Koshy 	NULLMASK
2136ebccf1e3SJoseph Koshy };
2137ebccf1e3SJoseph Koshy 
2138ebccf1e3SJoseph Koshy static struct pmc_masks p6_mask_esscir[] = {
2139ebccf1e3SJoseph Koshy 	PMCMASK(sse-packed-single,	0x00),
2140ebccf1e3SJoseph Koshy 	PMCMASK(sse-scalar-single,	0x01),
2141ebccf1e3SJoseph Koshy 	PMCMASK(sse2-packed-double,	0x02),
2142ebccf1e3SJoseph Koshy 	PMCMASK(sse2-scalar-double,	0x03),
2143ebccf1e3SJoseph Koshy 	NULLMASK
2144ebccf1e3SJoseph Koshy };
2145ebccf1e3SJoseph Koshy 
2146ebccf1e3SJoseph Koshy /* P6 event parser */
2147ebccf1e3SJoseph Koshy static int
2148ebccf1e3SJoseph Koshy p6_allocate_pmc(enum pmc_event pe, char *ctrspec,
2149ebccf1e3SJoseph Koshy     struct pmc_op_pmcallocate *pmc_config)
2150ebccf1e3SJoseph Koshy {
2151ebccf1e3SJoseph Koshy 	char *e, *p, *q;
21521e862e5aSFabien Thomas 	uint64_t evmask;
2153ebccf1e3SJoseph Koshy 	int count, n;
2154ebccf1e3SJoseph Koshy 	const struct pmc_masks *pm, *pmask;
2155ebccf1e3SJoseph Koshy 
2156789140c0SJoseph Koshy 	pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE);
2157f263522aSJoseph Koshy 	pmc_config->pm_md.pm_ppro.pm_ppro_config = 0;
2158ebccf1e3SJoseph Koshy 
2159ebccf1e3SJoseph Koshy 	evmask = 0;
2160ebccf1e3SJoseph Koshy 
2161ebccf1e3SJoseph Koshy #define	P6MASKSET(M)	pmask = p6_mask_ ## M
2162ebccf1e3SJoseph Koshy 
2163ebccf1e3SJoseph Koshy 	switch(pe) {
2164ebccf1e3SJoseph Koshy 	case PMC_EV_P6_L2_IFETCH:	P6MASKSET(mesi); break;
2165ebccf1e3SJoseph Koshy 	case PMC_EV_P6_L2_LD:		P6MASKSET(mesi); break;
2166ebccf1e3SJoseph Koshy 	case PMC_EV_P6_L2_ST:		P6MASKSET(mesi); break;
2167ebccf1e3SJoseph Koshy 	case PMC_EV_P6_L2_RQSTS:	P6MASKSET(mesi); break;
2168ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_DRDY_CLOCKS:
2169ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_LOCK_CLOCKS:
2170ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_BRD:
2171ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_RFO:
2172ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRANS_WB:
2173ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_IFETCH:
2174ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_INVAL:
2175ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_PWR:
2176ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRANS_P:
2177ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRANS_IO:
2178ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_DEF:
2179ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_BURST:
2180ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_ANY:
2181ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_MEM:
2182ebccf1e3SJoseph Koshy 		P6MASKSET(any);	break;
2183ebccf1e3SJoseph Koshy 	case PMC_EV_P6_EMON_KNI_PREF_DISPATCHED:
2184ebccf1e3SJoseph Koshy 	case PMC_EV_P6_EMON_KNI_PREF_MISS:
2185ebccf1e3SJoseph Koshy 		P6MASKSET(ekp); break;
2186ebccf1e3SJoseph Koshy 	case PMC_EV_P6_EMON_KNI_INST_RETIRED:
2187ebccf1e3SJoseph Koshy 	case PMC_EV_P6_EMON_KNI_COMP_INST_RET:
2188ebccf1e3SJoseph Koshy 		P6MASKSET(pps);	break;
2189ebccf1e3SJoseph Koshy 	case PMC_EV_P6_MMX_INSTR_TYPE_EXEC:
2190ebccf1e3SJoseph Koshy 		P6MASKSET(mite); break;
2191ebccf1e3SJoseph Koshy 	case PMC_EV_P6_FP_MMX_TRANS:
2192ebccf1e3SJoseph Koshy 		P6MASKSET(fmt);	break;
2193ebccf1e3SJoseph Koshy 	case PMC_EV_P6_SEG_RENAME_STALLS:
2194ebccf1e3SJoseph Koshy 	case PMC_EV_P6_SEG_REG_RENAMES:
2195ebccf1e3SJoseph Koshy 		P6MASKSET(sr);	break;
2196ebccf1e3SJoseph Koshy 	case PMC_EV_P6_EMON_EST_TRANS:
2197ebccf1e3SJoseph Koshy 		P6MASKSET(eet);	break;
2198ebccf1e3SJoseph Koshy 	case PMC_EV_P6_EMON_FUSED_UOPS_RET:
2199ebccf1e3SJoseph Koshy 		P6MASKSET(efur); break;
2200ebccf1e3SJoseph Koshy 	case PMC_EV_P6_EMON_SSE_SSE2_INST_RETIRED:
2201ebccf1e3SJoseph Koshy 		P6MASKSET(essir); break;
2202ebccf1e3SJoseph Koshy 	case PMC_EV_P6_EMON_SSE_SSE2_COMP_INST_RETIRED:
2203ebccf1e3SJoseph Koshy 		P6MASKSET(esscir); break;
2204ebccf1e3SJoseph Koshy 	default:
2205ebccf1e3SJoseph Koshy 		pmask = NULL;
2206ebccf1e3SJoseph Koshy 		break;
2207ebccf1e3SJoseph Koshy 	}
2208ebccf1e3SJoseph Koshy 
2209ebccf1e3SJoseph Koshy 	/* Pentium M PMCs have a few events with different semantics */
2210ebccf1e3SJoseph Koshy 	if (cpu_info.pm_cputype == PMC_CPU_INTEL_PM) {
2211ebccf1e3SJoseph Koshy 		if (pe == PMC_EV_P6_L2_LD ||
2212ebccf1e3SJoseph Koshy 		    pe == PMC_EV_P6_L2_LINES_IN ||
2213ebccf1e3SJoseph Koshy 		    pe == PMC_EV_P6_L2_LINES_OUT)
2214ebccf1e3SJoseph Koshy 			P6MASKSET(mesihw);
2215ebccf1e3SJoseph Koshy 		else if (pe == PMC_EV_P6_L2_M_LINES_OUTM)
2216ebccf1e3SJoseph Koshy 			P6MASKSET(hw);
2217ebccf1e3SJoseph Koshy 	}
2218ebccf1e3SJoseph Koshy 
2219ebccf1e3SJoseph Koshy 	/* Parse additional modifiers if present */
2220ebccf1e3SJoseph Koshy 	while ((p = strsep(&ctrspec, ",")) != NULL) {
2221ebccf1e3SJoseph Koshy 		if (KWPREFIXMATCH(p, P6_KW_CMASK "=")) {
2222ebccf1e3SJoseph Koshy 			q = strchr(p, '=');
2223ebccf1e3SJoseph Koshy 			if (*++q == '\0') /* skip '=' */
2224aa342b1fSJoseph Koshy 				return (-1);
2225ebccf1e3SJoseph Koshy 			count = strtol(q, &e, 0);
2226ebccf1e3SJoseph Koshy 			if (e == q || *e != '\0')
2227aa342b1fSJoseph Koshy 				return (-1);
2228ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_THRESHOLD;
2229f263522aSJoseph Koshy 			pmc_config->pm_md.pm_ppro.pm_ppro_config |=
2230f263522aSJoseph Koshy 			    P6_EVSEL_TO_CMASK(count);
2231ebccf1e3SJoseph Koshy 		} else if (KWMATCH(p, P6_KW_EDGE)) {
2232ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_EDGE;
2233ebccf1e3SJoseph Koshy 		} else if (KWMATCH(p, P6_KW_INV)) {
2234ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_INVERT;
2235ebccf1e3SJoseph Koshy 		} else if (KWMATCH(p, P6_KW_OS)) {
2236ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_SYSTEM;
2237ebccf1e3SJoseph Koshy 		} else if (KWPREFIXMATCH(p, P6_KW_UMASK "=")) {
2238ebccf1e3SJoseph Koshy 			evmask = 0;
2239ebccf1e3SJoseph Koshy 			if ((n = pmc_parse_mask(pmask, p, &evmask)) < 0)
2240aa342b1fSJoseph Koshy 				return (-1);
2241ebccf1e3SJoseph Koshy 			if ((pe == PMC_EV_P6_BUS_DRDY_CLOCKS ||
2242ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_BUS_LOCK_CLOCKS ||
2243ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_BUS_TRAN_BRD ||
2244ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_BUS_TRAN_RFO ||
2245ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_BUS_TRAN_IFETCH ||
2246ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_BUS_TRAN_INVAL ||
2247ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_BUS_TRAN_PWR ||
2248ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_BUS_TRAN_DEF ||
2249ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_BUS_TRAN_BURST ||
2250ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_BUS_TRAN_ANY ||
2251ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_BUS_TRAN_MEM ||
2252ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_BUS_TRANS_IO ||
2253ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_BUS_TRANS_P ||
2254ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_BUS_TRANS_WB ||
2255ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_EMON_EST_TRANS ||
2256ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_EMON_FUSED_UOPS_RET ||
2257ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_EMON_KNI_COMP_INST_RET ||
2258ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_EMON_KNI_INST_RETIRED ||
2259ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_EMON_KNI_PREF_DISPATCHED ||
2260ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_EMON_KNI_PREF_MISS ||
2261ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_EMON_SSE_SSE2_COMP_INST_RETIRED ||
2262ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_EMON_SSE_SSE2_INST_RETIRED ||
2263ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_FP_MMX_TRANS)
2264aa342b1fSJoseph Koshy 			    && (n > 1))	/* Only one mask keyword is allowed. */
2265aa342b1fSJoseph Koshy 				return (-1);
2266ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_QUALIFIER;
2267ebccf1e3SJoseph Koshy 		} else if (KWMATCH(p, P6_KW_USR)) {
2268ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_USER;
2269ebccf1e3SJoseph Koshy 		} else
2270aa342b1fSJoseph Koshy 			return (-1);
2271ebccf1e3SJoseph Koshy 	}
2272ebccf1e3SJoseph Koshy 
2273ebccf1e3SJoseph Koshy 	/* post processing */
2274ebccf1e3SJoseph Koshy 	switch (pe) {
2275ebccf1e3SJoseph Koshy 
2276ebccf1e3SJoseph Koshy 		/*
2277ebccf1e3SJoseph Koshy 		 * The following events default to an evmask of 0
2278ebccf1e3SJoseph Koshy 		 */
2279ebccf1e3SJoseph Koshy 
2280ebccf1e3SJoseph Koshy 		/* default => 'self' */
2281ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_DRDY_CLOCKS:
2282ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_LOCK_CLOCKS:
2283ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_BRD:
2284ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_RFO:
2285ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRANS_WB:
2286ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_IFETCH:
2287ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_INVAL:
2288ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_PWR:
2289ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRANS_P:
2290ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRANS_IO:
2291ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_DEF:
2292ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_BURST:
2293ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_ANY:
2294ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_MEM:
2295ebccf1e3SJoseph Koshy 
2296ebccf1e3SJoseph Koshy 		/* default => 'nta' */
2297ebccf1e3SJoseph Koshy 	case PMC_EV_P6_EMON_KNI_PREF_DISPATCHED:
2298ebccf1e3SJoseph Koshy 	case PMC_EV_P6_EMON_KNI_PREF_MISS:
2299ebccf1e3SJoseph Koshy 
2300ebccf1e3SJoseph Koshy 		/* default => 'packed and scalar' */
2301ebccf1e3SJoseph Koshy 	case PMC_EV_P6_EMON_KNI_INST_RETIRED:
2302ebccf1e3SJoseph Koshy 	case PMC_EV_P6_EMON_KNI_COMP_INST_RET:
2303ebccf1e3SJoseph Koshy 
2304ebccf1e3SJoseph Koshy 		/* default => 'mmx to fp transitions' */
2305ebccf1e3SJoseph Koshy 	case PMC_EV_P6_FP_MMX_TRANS:
2306ebccf1e3SJoseph Koshy 
2307ebccf1e3SJoseph Koshy 		/* default => 'SSE Packed Single' */
2308ebccf1e3SJoseph Koshy 	case PMC_EV_P6_EMON_SSE_SSE2_INST_RETIRED:
2309ebccf1e3SJoseph Koshy 	case PMC_EV_P6_EMON_SSE_SSE2_COMP_INST_RETIRED:
2310ebccf1e3SJoseph Koshy 
2311ebccf1e3SJoseph Koshy 		/* default => 'all fused micro-ops' */
2312ebccf1e3SJoseph Koshy 	case PMC_EV_P6_EMON_FUSED_UOPS_RET:
2313ebccf1e3SJoseph Koshy 
2314ebccf1e3SJoseph Koshy 		/* default => 'all transitions' */
2315ebccf1e3SJoseph Koshy 	case PMC_EV_P6_EMON_EST_TRANS:
2316ebccf1e3SJoseph Koshy 		break;
2317ebccf1e3SJoseph Koshy 
2318ebccf1e3SJoseph Koshy 	case PMC_EV_P6_MMX_UOPS_EXEC:
2319ebccf1e3SJoseph Koshy 		evmask = 0x0F;		/* only value allowed */
2320ebccf1e3SJoseph Koshy 		break;
2321ebccf1e3SJoseph Koshy 
2322ebccf1e3SJoseph Koshy 	default:
2323ebccf1e3SJoseph Koshy 		/*
2324ebccf1e3SJoseph Koshy 		 * For all other events, set the default event mask
2325ebccf1e3SJoseph Koshy 		 * to a logical OR of all the allowed event mask bits.
2326ebccf1e3SJoseph Koshy 		 */
2327ebccf1e3SJoseph Koshy 		if (evmask == 0 && pmask) {
2328ebccf1e3SJoseph Koshy 			for (pm = pmask; pm->pm_name; pm++)
2329ebccf1e3SJoseph Koshy 				evmask |= pm->pm_value;
2330ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_QUALIFIER;
2331ebccf1e3SJoseph Koshy 		}
2332ebccf1e3SJoseph Koshy 
2333ebccf1e3SJoseph Koshy 		break;
2334ebccf1e3SJoseph Koshy 	}
2335ebccf1e3SJoseph Koshy 
2336ebccf1e3SJoseph Koshy 	if (pmc_config->pm_caps & PMC_CAP_QUALIFIER)
2337f263522aSJoseph Koshy 		pmc_config->pm_md.pm_ppro.pm_ppro_config |=
2338f263522aSJoseph Koshy 		    P6_EVSEL_TO_UMASK(evmask);
2339ebccf1e3SJoseph Koshy 
2340aa342b1fSJoseph Koshy 	return (0);
2341ebccf1e3SJoseph Koshy }
2342ebccf1e3SJoseph Koshy 
2343ebccf1e3SJoseph Koshy #endif
2344ebccf1e3SJoseph Koshy 
2345789140c0SJoseph Koshy #if	defined(__i386__) || defined(__amd64__)
2346789140c0SJoseph Koshy static int
2347789140c0SJoseph Koshy tsc_allocate_pmc(enum pmc_event pe, char *ctrspec,
2348789140c0SJoseph Koshy     struct pmc_op_pmcallocate *pmc_config)
2349789140c0SJoseph Koshy {
2350789140c0SJoseph Koshy 	if (pe != PMC_EV_TSC_TSC)
2351789140c0SJoseph Koshy 		return (-1);
2352789140c0SJoseph Koshy 
2353789140c0SJoseph Koshy 	/* TSC events must be unqualified. */
2354789140c0SJoseph Koshy 	if (ctrspec && *ctrspec != '\0')
2355789140c0SJoseph Koshy 		return (-1);
2356789140c0SJoseph Koshy 
2357789140c0SJoseph Koshy 	pmc_config->pm_md.pm_amd.pm_amd_config = 0;
2358789140c0SJoseph Koshy 	pmc_config->pm_caps |= PMC_CAP_READ;
2359789140c0SJoseph Koshy 
2360789140c0SJoseph Koshy 	return (0);
2361789140c0SJoseph Koshy }
2362789140c0SJoseph Koshy #endif
2363789140c0SJoseph Koshy 
2364f5f9340bSFabien Thomas static struct pmc_event_alias generic_aliases[] = {
2365f5f9340bSFabien Thomas 	EV_ALIAS("instructions",		"SOFT-CLOCK.HARD"),
2366f5f9340bSFabien Thomas 	EV_ALIAS(NULL, NULL)
2367f5f9340bSFabien Thomas };
2368f5f9340bSFabien Thomas 
2369f5f9340bSFabien Thomas static int
2370f5f9340bSFabien Thomas soft_allocate_pmc(enum pmc_event pe, char *ctrspec,
2371f5f9340bSFabien Thomas     struct pmc_op_pmcallocate *pmc_config)
2372f5f9340bSFabien Thomas {
2373f5f9340bSFabien Thomas 	(void)ctrspec;
2374f5f9340bSFabien Thomas 	(void)pmc_config;
2375f5f9340bSFabien Thomas 
2376f0bbe9aaSDimitry Andric 	if ((int)pe < PMC_EV_SOFT_FIRST || (int)pe > PMC_EV_SOFT_LAST)
2377f5f9340bSFabien Thomas 		return (-1);
2378f5f9340bSFabien Thomas 
2379f5f9340bSFabien Thomas 	pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE);
2380f5f9340bSFabien Thomas 	return (0);
2381f5f9340bSFabien Thomas }
2382f5f9340bSFabien Thomas 
2383*6411d14dSRuslan Bukin #if	defined(__arm__)
23840ce207d2SRui Paulo #if	defined(__XSCALE__)
23850ce207d2SRui Paulo 
23860ce207d2SRui Paulo static struct pmc_event_alias xscale_aliases[] = {
23870ce207d2SRui Paulo 	EV_ALIAS("branches",		"BRANCH_RETIRED"),
23880ce207d2SRui Paulo 	EV_ALIAS("branch-mispredicts",	"BRANCH_MISPRED"),
23890ce207d2SRui Paulo 	EV_ALIAS("dc-misses",		"DC_MISS"),
23900ce207d2SRui Paulo 	EV_ALIAS("ic-misses",		"IC_MISS"),
23910ce207d2SRui Paulo 	EV_ALIAS("instructions",	"INSTR_RETIRED"),
23920ce207d2SRui Paulo 	EV_ALIAS(NULL, NULL)
23930ce207d2SRui Paulo };
23940ce207d2SRui Paulo static int
23950ce207d2SRui Paulo xscale_allocate_pmc(enum pmc_event pe, char *ctrspec __unused,
23960ce207d2SRui Paulo     struct pmc_op_pmcallocate *pmc_config __unused)
23970ce207d2SRui Paulo {
23980ce207d2SRui Paulo 	switch (pe) {
23990ce207d2SRui Paulo 	default:
24000ce207d2SRui Paulo 		break;
24010ce207d2SRui Paulo 	}
24020ce207d2SRui Paulo 
24030ce207d2SRui Paulo 	return (0);
24040ce207d2SRui Paulo }
24050ce207d2SRui Paulo #endif
24060ce207d2SRui Paulo 
2407*6411d14dSRuslan Bukin static struct pmc_event_alias armv7_aliases[] = {
2408*6411d14dSRuslan Bukin 	EV_ALIAS("dc-misses",		"L1_DCACHE_REFILL"),
2409*6411d14dSRuslan Bukin 	EV_ALIAS("ic-misses",		"L1_ICACHE_REFILL"),
2410*6411d14dSRuslan Bukin 	EV_ALIAS("instructions",	"INSTR_EXECUTED"),
2411*6411d14dSRuslan Bukin 	EV_ALIAS(NULL, NULL)
2412*6411d14dSRuslan Bukin };
2413*6411d14dSRuslan Bukin static int
2414*6411d14dSRuslan Bukin armv7_allocate_pmc(enum pmc_event pe, char *ctrspec __unused,
2415*6411d14dSRuslan Bukin     struct pmc_op_pmcallocate *pmc_config __unused)
2416*6411d14dSRuslan Bukin {
2417*6411d14dSRuslan Bukin 	switch (pe) {
2418*6411d14dSRuslan Bukin 	default:
2419*6411d14dSRuslan Bukin 		break;
2420*6411d14dSRuslan Bukin 	}
2421*6411d14dSRuslan Bukin 
2422*6411d14dSRuslan Bukin 	return (0);
2423*6411d14dSRuslan Bukin }
2424*6411d14dSRuslan Bukin #endif
2425*6411d14dSRuslan Bukin 
2426660df75eSGeorge V. Neville-Neil #if defined(__mips__)
2427660df75eSGeorge V. Neville-Neil 
2428660df75eSGeorge V. Neville-Neil static struct pmc_event_alias mips24k_aliases[] = {
2429660df75eSGeorge V. Neville-Neil 	EV_ALIAS("instructions",	"INSTR_EXECUTED"),
2430660df75eSGeorge V. Neville-Neil 	EV_ALIAS("branches",		"BRANCH_COMPLETED"),
2431660df75eSGeorge V. Neville-Neil 	EV_ALIAS("branch-mispredicts",	"BRANCH_MISPRED"),
2432660df75eSGeorge V. Neville-Neil 	EV_ALIAS(NULL, NULL)
2433660df75eSGeorge V. Neville-Neil };
2434660df75eSGeorge V. Neville-Neil 
2435c2657f80SOleksandr Tymoshenko static struct pmc_event_alias octeon_aliases[] = {
2436c2657f80SOleksandr Tymoshenko 	EV_ALIAS("instructions",	"RET"),
2437c2657f80SOleksandr Tymoshenko 	EV_ALIAS("branches",		"BR"),
2438c2657f80SOleksandr Tymoshenko 	EV_ALIAS("branch-mispredicts",	"BRMIS"),
2439c2657f80SOleksandr Tymoshenko 	EV_ALIAS(NULL, NULL)
2440c2657f80SOleksandr Tymoshenko };
2441c2657f80SOleksandr Tymoshenko 
24422827d3e1SOleksandr Tymoshenko #define	MIPS_KW_OS		"os"
24432827d3e1SOleksandr Tymoshenko #define	MIPS_KW_USR		"usr"
24442827d3e1SOleksandr Tymoshenko #define	MIPS_KW_ANYTHREAD	"anythread"
2445660df75eSGeorge V. Neville-Neil 
2446660df75eSGeorge V. Neville-Neil static int
24472827d3e1SOleksandr Tymoshenko mips_allocate_pmc(enum pmc_event pe, char *ctrspec __unused,
2448660df75eSGeorge V. Neville-Neil 		  struct pmc_op_pmcallocate *pmc_config __unused)
2449660df75eSGeorge V. Neville-Neil {
2450660df75eSGeorge V. Neville-Neil 	char *p;
2451660df75eSGeorge V. Neville-Neil 
2452660df75eSGeorge V. Neville-Neil 	(void) pe;
2453660df75eSGeorge V. Neville-Neil 
2454660df75eSGeorge V. Neville-Neil 	pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE);
2455660df75eSGeorge V. Neville-Neil 
2456660df75eSGeorge V. Neville-Neil 	while ((p = strsep(&ctrspec, ",")) != NULL) {
24572827d3e1SOleksandr Tymoshenko 		if (KWMATCH(p, MIPS_KW_OS))
2458660df75eSGeorge V. Neville-Neil 			pmc_config->pm_caps |= PMC_CAP_SYSTEM;
24592827d3e1SOleksandr Tymoshenko 		else if (KWMATCH(p, MIPS_KW_USR))
2460660df75eSGeorge V. Neville-Neil 			pmc_config->pm_caps |= PMC_CAP_USER;
24612827d3e1SOleksandr Tymoshenko 		else if (KWMATCH(p, MIPS_KW_ANYTHREAD))
2462660df75eSGeorge V. Neville-Neil 			pmc_config->pm_caps |= (PMC_CAP_USER | PMC_CAP_SYSTEM);
2463660df75eSGeorge V. Neville-Neil 		else
2464660df75eSGeorge V. Neville-Neil 			return (-1);
2465660df75eSGeorge V. Neville-Neil 	}
2466660df75eSGeorge V. Neville-Neil 
2467660df75eSGeorge V. Neville-Neil 	return (0);
2468660df75eSGeorge V. Neville-Neil }
24692827d3e1SOleksandr Tymoshenko 
2470660df75eSGeorge V. Neville-Neil #endif /* __mips__ */
2471660df75eSGeorge V. Neville-Neil 
24727b25dccaSJustin Hibbits #if defined(__powerpc__)
24737b25dccaSJustin Hibbits 
24747b25dccaSJustin Hibbits static struct pmc_event_alias ppc7450_aliases[] = {
24757b25dccaSJustin Hibbits 	EV_ALIAS("instructions",	"INSTR_COMPLETED"),
24767b25dccaSJustin Hibbits 	EV_ALIAS("branches",		"BRANCHES_COMPLETED"),
24777b25dccaSJustin Hibbits 	EV_ALIAS("branch-mispredicts",	"MISPREDICTED_BRANCHES"),
24787b25dccaSJustin Hibbits 	EV_ALIAS(NULL, NULL)
24797b25dccaSJustin Hibbits };
24807b25dccaSJustin Hibbits 
2481169dd953SJustin Hibbits static struct pmc_event_alias ppc970_aliases[] = {
2482169dd953SJustin Hibbits 	EV_ALIAS("instructions", "INSTR_COMPLETED"),
2483169dd953SJustin Hibbits 	EV_ALIAS("cycles",       "CYCLES"),
2484169dd953SJustin Hibbits 	EV_ALIAS(NULL, NULL)
2485169dd953SJustin Hibbits };
2486169dd953SJustin Hibbits 
2487169dd953SJustin Hibbits #define	POWERPC_KW_OS		"os"
2488169dd953SJustin Hibbits #define	POWERPC_KW_USR		"usr"
2489169dd953SJustin Hibbits #define	POWERPC_KW_ANYTHREAD	"anythread"
24907b25dccaSJustin Hibbits 
24917b25dccaSJustin Hibbits static int
2492169dd953SJustin Hibbits powerpc_allocate_pmc(enum pmc_event pe, char *ctrspec __unused,
24937b25dccaSJustin Hibbits 		     struct pmc_op_pmcallocate *pmc_config __unused)
24947b25dccaSJustin Hibbits {
24957b25dccaSJustin Hibbits 	char *p;
24967b25dccaSJustin Hibbits 
24977b25dccaSJustin Hibbits 	(void) pe;
24987b25dccaSJustin Hibbits 
24997b25dccaSJustin Hibbits 	pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE);
25007b25dccaSJustin Hibbits 
25017b25dccaSJustin Hibbits 	while ((p = strsep(&ctrspec, ",")) != NULL) {
2502169dd953SJustin Hibbits 		if (KWMATCH(p, POWERPC_KW_OS))
25037b25dccaSJustin Hibbits 			pmc_config->pm_caps |= PMC_CAP_SYSTEM;
2504169dd953SJustin Hibbits 		else if (KWMATCH(p, POWERPC_KW_USR))
25057b25dccaSJustin Hibbits 			pmc_config->pm_caps |= PMC_CAP_USER;
2506169dd953SJustin Hibbits 		else if (KWMATCH(p, POWERPC_KW_ANYTHREAD))
25077b25dccaSJustin Hibbits 			pmc_config->pm_caps |= (PMC_CAP_USER | PMC_CAP_SYSTEM);
25087b25dccaSJustin Hibbits 		else
25097b25dccaSJustin Hibbits 			return (-1);
25107b25dccaSJustin Hibbits 	}
25117b25dccaSJustin Hibbits 
25127b25dccaSJustin Hibbits 	return (0);
25137b25dccaSJustin Hibbits }
2514169dd953SJustin Hibbits 
25157b25dccaSJustin Hibbits #endif /* __powerpc__ */
25167b25dccaSJustin Hibbits 
2517660df75eSGeorge V. Neville-Neil 
2518789140c0SJoseph Koshy /*
2519789140c0SJoseph Koshy  * Match an event name `name' with its canonical form.
2520789140c0SJoseph Koshy  *
25210cfab8ddSJoseph Koshy  * Matches are case insensitive and spaces, periods, underscores and
25220cfab8ddSJoseph Koshy  * hyphen characters are considered to match each other.
2523789140c0SJoseph Koshy  *
2524789140c0SJoseph Koshy  * Returns 1 for a match, 0 otherwise.
2525789140c0SJoseph Koshy  */
2526789140c0SJoseph Koshy 
2527789140c0SJoseph Koshy static int
2528789140c0SJoseph Koshy pmc_match_event_name(const char *name, const char *canonicalname)
2529789140c0SJoseph Koshy {
2530789140c0SJoseph Koshy 	int cc, nc;
2531789140c0SJoseph Koshy 	const unsigned char *c, *n;
2532789140c0SJoseph Koshy 
2533789140c0SJoseph Koshy 	c = (const unsigned char *) canonicalname;
2534789140c0SJoseph Koshy 	n = (const unsigned char *) name;
2535789140c0SJoseph Koshy 
2536789140c0SJoseph Koshy 	for (; (nc = *n) && (cc = *c); n++, c++) {
2537789140c0SJoseph Koshy 
25380cfab8ddSJoseph Koshy 		if ((nc == ' ' || nc == '_' || nc == '-' || nc == '.') &&
25390cfab8ddSJoseph Koshy 		    (cc == ' ' || cc == '_' || cc == '-' || cc == '.'))
2540789140c0SJoseph Koshy 			continue;
2541789140c0SJoseph Koshy 
25420cfab8ddSJoseph Koshy 		if (toupper(nc) == toupper(cc))
2543789140c0SJoseph Koshy 			continue;
2544789140c0SJoseph Koshy 
25450cfab8ddSJoseph Koshy 
2546789140c0SJoseph Koshy 		return (0);
2547789140c0SJoseph Koshy 	}
2548789140c0SJoseph Koshy 
2549789140c0SJoseph Koshy 	if (*n == '\0' && *c == '\0')
2550789140c0SJoseph Koshy 		return (1);
2551789140c0SJoseph Koshy 
2552789140c0SJoseph Koshy 	return (0);
2553789140c0SJoseph Koshy }
2554789140c0SJoseph Koshy 
2555789140c0SJoseph Koshy /*
2556789140c0SJoseph Koshy  * Match an event name against all the event named supported by a
2557789140c0SJoseph Koshy  * PMC class.
2558789140c0SJoseph Koshy  *
2559789140c0SJoseph Koshy  * Returns an event descriptor pointer on match or NULL otherwise.
2560789140c0SJoseph Koshy  */
2561789140c0SJoseph Koshy static const struct pmc_event_descr *
2562789140c0SJoseph Koshy pmc_match_event_class(const char *name,
2563789140c0SJoseph Koshy     const struct pmc_class_descr *pcd)
2564789140c0SJoseph Koshy {
2565789140c0SJoseph Koshy 	size_t n;
2566789140c0SJoseph Koshy 	const struct pmc_event_descr *ev;
2567789140c0SJoseph Koshy 
2568789140c0SJoseph Koshy 	ev = pcd->pm_evc_event_table;
2569789140c0SJoseph Koshy 	for (n = 0; n < pcd->pm_evc_event_table_size; n++, ev++)
2570789140c0SJoseph Koshy 		if (pmc_match_event_name(name, ev->pm_ev_name))
2571789140c0SJoseph Koshy 			return (ev);
2572789140c0SJoseph Koshy 
2573789140c0SJoseph Koshy 	return (NULL);
2574789140c0SJoseph Koshy }
2575789140c0SJoseph Koshy 
2576789140c0SJoseph Koshy static int
2577789140c0SJoseph Koshy pmc_mdep_is_compatible_class(enum pmc_class pc)
2578789140c0SJoseph Koshy {
2579789140c0SJoseph Koshy 	size_t n;
2580789140c0SJoseph Koshy 
2581789140c0SJoseph Koshy 	for (n = 0; n < pmc_mdep_class_list_size; n++)
2582789140c0SJoseph Koshy 		if (pmc_mdep_class_list[n] == pc)
2583789140c0SJoseph Koshy 			return (1);
2584789140c0SJoseph Koshy 	return (0);
2585789140c0SJoseph Koshy }
2586789140c0SJoseph Koshy 
2587ebccf1e3SJoseph Koshy /*
2588ebccf1e3SJoseph Koshy  * API entry points
2589ebccf1e3SJoseph Koshy  */
2590ebccf1e3SJoseph Koshy 
2591ebccf1e3SJoseph Koshy int
2592ebccf1e3SJoseph Koshy pmc_allocate(const char *ctrspec, enum pmc_mode mode,
2593ebccf1e3SJoseph Koshy     uint32_t flags, int cpu, pmc_id_t *pmcid)
2594ebccf1e3SJoseph Koshy {
2595789140c0SJoseph Koshy 	size_t n;
2596ebccf1e3SJoseph Koshy 	int retval;
2597ebccf1e3SJoseph Koshy 	char *r, *spec_copy;
2598ebccf1e3SJoseph Koshy 	const char *ctrname;
2599789140c0SJoseph Koshy 	const struct pmc_event_descr *ev;
2600789140c0SJoseph Koshy 	const struct pmc_event_alias *alias;
2601ebccf1e3SJoseph Koshy 	struct pmc_op_pmcallocate pmc_config;
2602789140c0SJoseph Koshy 	const struct pmc_class_descr *pcd;
2603ebccf1e3SJoseph Koshy 
2604ebccf1e3SJoseph Koshy 	spec_copy = NULL;
2605ebccf1e3SJoseph Koshy 	retval    = -1;
2606ebccf1e3SJoseph Koshy 
2607ebccf1e3SJoseph Koshy 	if (mode != PMC_MODE_SS && mode != PMC_MODE_TS &&
2608ebccf1e3SJoseph Koshy 	    mode != PMC_MODE_SC && mode != PMC_MODE_TC) {
2609ebccf1e3SJoseph Koshy 		errno = EINVAL;
2610ebccf1e3SJoseph Koshy 		goto out;
2611ebccf1e3SJoseph Koshy 	}
2612ebccf1e3SJoseph Koshy 
2613ebccf1e3SJoseph Koshy 	/* replace an event alias with the canonical event specifier */
2614ebccf1e3SJoseph Koshy 	if (pmc_mdep_event_aliases)
2615789140c0SJoseph Koshy 		for (alias = pmc_mdep_event_aliases; alias->pm_alias; alias++)
2616789140c0SJoseph Koshy 			if (!strcasecmp(ctrspec, alias->pm_alias)) {
2617789140c0SJoseph Koshy 				spec_copy = strdup(alias->pm_spec);
2618ebccf1e3SJoseph Koshy 				break;
2619ebccf1e3SJoseph Koshy 			}
2620ebccf1e3SJoseph Koshy 
2621ebccf1e3SJoseph Koshy 	if (spec_copy == NULL)
2622ebccf1e3SJoseph Koshy 		spec_copy = strdup(ctrspec);
2623ebccf1e3SJoseph Koshy 
2624ebccf1e3SJoseph Koshy 	r = spec_copy;
2625ebccf1e3SJoseph Koshy 	ctrname = strsep(&r, ",");
2626ebccf1e3SJoseph Koshy 
2627789140c0SJoseph Koshy 	/*
2628789140c0SJoseph Koshy 	 * If a explicit class prefix was given by the user, restrict the
2629789140c0SJoseph Koshy 	 * search for the event to the specified PMC class.
2630789140c0SJoseph Koshy 	 */
2631789140c0SJoseph Koshy 	ev = NULL;
26320cfab8ddSJoseph Koshy 	for (n = 0; n < PMC_CLASS_TABLE_SIZE; n++) {
26330cfab8ddSJoseph Koshy 		pcd = pmc_class_table[n];
2634789140c0SJoseph Koshy 		if (pmc_mdep_is_compatible_class(pcd->pm_evc_class) &&
2635789140c0SJoseph Koshy 		    strncasecmp(ctrname, pcd->pm_evc_name,
2636789140c0SJoseph Koshy 				pcd->pm_evc_name_size) == 0) {
2637789140c0SJoseph Koshy 			if ((ev = pmc_match_event_class(ctrname +
2638789140c0SJoseph Koshy 			    pcd->pm_evc_name_size, pcd)) == NULL) {
2639789140c0SJoseph Koshy 				errno = EINVAL;
2640789140c0SJoseph Koshy 				goto out;
2641789140c0SJoseph Koshy 			}
2642ebccf1e3SJoseph Koshy 			break;
2643789140c0SJoseph Koshy 		}
2644789140c0SJoseph Koshy 	}
2645ebccf1e3SJoseph Koshy 
2646789140c0SJoseph Koshy 	/*
2647789140c0SJoseph Koshy 	 * Otherwise, search for this event in all compatible PMC
2648789140c0SJoseph Koshy 	 * classes.
2649789140c0SJoseph Koshy 	 */
26500cfab8ddSJoseph Koshy 	for (n = 0; ev == NULL && n < PMC_CLASS_TABLE_SIZE; n++) {
26510cfab8ddSJoseph Koshy 		pcd = pmc_class_table[n];
2652789140c0SJoseph Koshy 		if (pmc_mdep_is_compatible_class(pcd->pm_evc_class))
2653789140c0SJoseph Koshy 			ev = pmc_match_event_class(ctrname, pcd);
2654789140c0SJoseph Koshy 	}
2655789140c0SJoseph Koshy 
2656789140c0SJoseph Koshy 	if (ev == NULL) {
2657ebccf1e3SJoseph Koshy 		errno = EINVAL;
2658ebccf1e3SJoseph Koshy 		goto out;
2659ebccf1e3SJoseph Koshy 	}
2660ebccf1e3SJoseph Koshy 
2661ebccf1e3SJoseph Koshy 	bzero(&pmc_config, sizeof(pmc_config));
2662789140c0SJoseph Koshy 	pmc_config.pm_ev    = ev->pm_ev_code;
2663789140c0SJoseph Koshy 	pmc_config.pm_class = pcd->pm_evc_class;
2664ebccf1e3SJoseph Koshy 	pmc_config.pm_cpu   = cpu;
2665ebccf1e3SJoseph Koshy 	pmc_config.pm_mode  = mode;
2666ebccf1e3SJoseph Koshy 	pmc_config.pm_flags = flags;
2667ebccf1e3SJoseph Koshy 
2668ebccf1e3SJoseph Koshy 	if (PMC_IS_SAMPLING_MODE(mode))
2669ebccf1e3SJoseph Koshy 		pmc_config.pm_caps |= PMC_CAP_INTERRUPT;
2670ebccf1e3SJoseph Koshy 
2671789140c0SJoseph Koshy  	if (pcd->pm_evc_allocate_pmc(ev->pm_ev_code, r, &pmc_config) < 0) {
2672ebccf1e3SJoseph Koshy 		errno = EINVAL;
2673ebccf1e3SJoseph Koshy 		goto out;
2674ebccf1e3SJoseph Koshy 	}
2675ebccf1e3SJoseph Koshy 
2676ebccf1e3SJoseph Koshy 	if (PMC_CALL(PMCALLOCATE, &pmc_config) < 0)
2677ebccf1e3SJoseph Koshy 		goto out;
2678ebccf1e3SJoseph Koshy 
2679ebccf1e3SJoseph Koshy 	*pmcid = pmc_config.pm_pmcid;
2680ebccf1e3SJoseph Koshy 
2681ebccf1e3SJoseph Koshy 	retval = 0;
2682ebccf1e3SJoseph Koshy 
2683ebccf1e3SJoseph Koshy  out:
2684ebccf1e3SJoseph Koshy 	if (spec_copy)
2685ebccf1e3SJoseph Koshy 		free(spec_copy);
2686ebccf1e3SJoseph Koshy 
2687aa342b1fSJoseph Koshy 	return (retval);
2688ebccf1e3SJoseph Koshy }
2689ebccf1e3SJoseph Koshy 
2690ebccf1e3SJoseph Koshy int
2691ebccf1e3SJoseph Koshy pmc_attach(pmc_id_t pmc, pid_t pid)
2692ebccf1e3SJoseph Koshy {
2693ebccf1e3SJoseph Koshy 	struct pmc_op_pmcattach pmc_attach_args;
2694ebccf1e3SJoseph Koshy 
2695ebccf1e3SJoseph Koshy 	pmc_attach_args.pm_pmc = pmc;
2696ebccf1e3SJoseph Koshy 	pmc_attach_args.pm_pid = pid;
2697ebccf1e3SJoseph Koshy 
2698aa342b1fSJoseph Koshy 	return (PMC_CALL(PMCATTACH, &pmc_attach_args));
2699ebccf1e3SJoseph Koshy }
2700ebccf1e3SJoseph Koshy 
2701ebccf1e3SJoseph Koshy int
2702c5153e19SJoseph Koshy pmc_capabilities(pmc_id_t pmcid, uint32_t *caps)
2703c5153e19SJoseph Koshy {
2704c5153e19SJoseph Koshy 	unsigned int i;
2705c5153e19SJoseph Koshy 	enum pmc_class cl;
2706c5153e19SJoseph Koshy 
2707c5153e19SJoseph Koshy 	cl = PMC_ID_TO_CLASS(pmcid);
2708c5153e19SJoseph Koshy 	for (i = 0; i < cpu_info.pm_nclass; i++)
2709c5153e19SJoseph Koshy 		if (cpu_info.pm_classes[i].pm_class == cl) {
2710c5153e19SJoseph Koshy 			*caps = cpu_info.pm_classes[i].pm_caps;
2711aa342b1fSJoseph Koshy 			return (0);
2712c5153e19SJoseph Koshy 		}
2713484202faSJoseph Koshy 	errno = EINVAL;
2714484202faSJoseph Koshy 	return (-1);
2715c5153e19SJoseph Koshy }
2716c5153e19SJoseph Koshy 
2717f263522aSJoseph Koshy int
2718f263522aSJoseph Koshy pmc_configure_logfile(int fd)
2719ebccf1e3SJoseph Koshy {
2720f263522aSJoseph Koshy 	struct pmc_op_configurelog cla;
2721f263522aSJoseph Koshy 
2722f263522aSJoseph Koshy 	cla.pm_logfd = fd;
2723f263522aSJoseph Koshy 	if (PMC_CALL(CONFIGURELOG, &cla) < 0)
2724aa342b1fSJoseph Koshy 		return (-1);
2725aa342b1fSJoseph Koshy 	return (0);
2726ebccf1e3SJoseph Koshy }
2727ebccf1e3SJoseph Koshy 
2728f263522aSJoseph Koshy int
2729f263522aSJoseph Koshy pmc_cpuinfo(const struct pmc_cpuinfo **pci)
2730ebccf1e3SJoseph Koshy {
2731f263522aSJoseph Koshy 	if (pmc_syscall == -1) {
2732f263522aSJoseph Koshy 		errno = ENXIO;
2733aa342b1fSJoseph Koshy 		return (-1);
2734ebccf1e3SJoseph Koshy 	}
2735ebccf1e3SJoseph Koshy 
27361455fcd3SJoseph Koshy 	*pci = &cpu_info;
2737aa342b1fSJoseph Koshy 	return (0);
2738ebccf1e3SJoseph Koshy }
2739ebccf1e3SJoseph Koshy 
2740f263522aSJoseph Koshy int
2741f263522aSJoseph Koshy pmc_detach(pmc_id_t pmc, pid_t pid)
2742ebccf1e3SJoseph Koshy {
2743f263522aSJoseph Koshy 	struct pmc_op_pmcattach pmc_detach_args;
2744ebccf1e3SJoseph Koshy 
2745f263522aSJoseph Koshy 	pmc_detach_args.pm_pmc = pmc;
2746f263522aSJoseph Koshy 	pmc_detach_args.pm_pid = pid;
2747aa342b1fSJoseph Koshy 	return (PMC_CALL(PMCDETACH, &pmc_detach_args));
2748ebccf1e3SJoseph Koshy }
2749ebccf1e3SJoseph Koshy 
2750f263522aSJoseph Koshy int
2751f263522aSJoseph Koshy pmc_disable(int cpu, int pmc)
2752ebccf1e3SJoseph Koshy {
2753f263522aSJoseph Koshy 	struct pmc_op_pmcadmin ssa;
2754ebccf1e3SJoseph Koshy 
2755f263522aSJoseph Koshy 	ssa.pm_cpu = cpu;
2756f263522aSJoseph Koshy 	ssa.pm_pmc = pmc;
2757f263522aSJoseph Koshy 	ssa.pm_state = PMC_STATE_DISABLED;
2758aa342b1fSJoseph Koshy 	return (PMC_CALL(PMCADMIN, &ssa));
2759ebccf1e3SJoseph Koshy }
2760ebccf1e3SJoseph Koshy 
2761f263522aSJoseph Koshy int
2762f263522aSJoseph Koshy pmc_enable(int cpu, int pmc)
2763ebccf1e3SJoseph Koshy {
2764f263522aSJoseph Koshy 	struct pmc_op_pmcadmin ssa;
2765ebccf1e3SJoseph Koshy 
2766f263522aSJoseph Koshy 	ssa.pm_cpu = cpu;
2767f263522aSJoseph Koshy 	ssa.pm_pmc = pmc;
2768f263522aSJoseph Koshy 	ssa.pm_state = PMC_STATE_FREE;
2769aa342b1fSJoseph Koshy 	return (PMC_CALL(PMCADMIN, &ssa));
2770ebccf1e3SJoseph Koshy }
2771ebccf1e3SJoseph Koshy 
2772ebccf1e3SJoseph Koshy /*
2773ebccf1e3SJoseph Koshy  * Return a list of events known to a given PMC class.  'cl' is the
2774ebccf1e3SJoseph Koshy  * PMC class identifier, 'eventnames' is the returned list of 'const
2775ebccf1e3SJoseph Koshy  * char *' pointers pointing to the names of the events. 'nevents' is
2776ebccf1e3SJoseph Koshy  * the number of event name pointers returned.
2777ebccf1e3SJoseph Koshy  *
2778ebccf1e3SJoseph Koshy  * The space for 'eventnames' is allocated using malloc(3).  The caller
2779ebccf1e3SJoseph Koshy  * is responsible for freeing this space when done.
2780ebccf1e3SJoseph Koshy  */
2781ebccf1e3SJoseph Koshy int
2782ebccf1e3SJoseph Koshy pmc_event_names_of_class(enum pmc_class cl, const char ***eventnames,
2783ebccf1e3SJoseph Koshy     int *nevents)
2784ebccf1e3SJoseph Koshy {
2785ebccf1e3SJoseph Koshy 	int count;
2786ebccf1e3SJoseph Koshy 	const char **names;
2787ebccf1e3SJoseph Koshy 	const struct pmc_event_descr *ev;
2788ebccf1e3SJoseph Koshy 
2789ebccf1e3SJoseph Koshy 	switch (cl)
2790ebccf1e3SJoseph Koshy 	{
27910cfab8ddSJoseph Koshy 	case PMC_CLASS_IAF:
27920cfab8ddSJoseph Koshy 		ev = iaf_event_table;
27930cfab8ddSJoseph Koshy 		count = PMC_EVENT_TABLE_SIZE(iaf);
27940cfab8ddSJoseph Koshy 		break;
27950cfab8ddSJoseph Koshy 	case PMC_CLASS_IAP:
27960cfab8ddSJoseph Koshy 		/*
27970cfab8ddSJoseph Koshy 		 * Return the most appropriate set of event name
27980cfab8ddSJoseph Koshy 		 * spellings for the current CPU.
27990cfab8ddSJoseph Koshy 		 */
28000cfab8ddSJoseph Koshy 		switch (cpu_info.pm_cputype) {
28010cfab8ddSJoseph Koshy 		default:
28020cfab8ddSJoseph Koshy 		case PMC_CPU_INTEL_ATOM:
28030cfab8ddSJoseph Koshy 			ev = atom_event_table;
28040cfab8ddSJoseph Koshy 			count = PMC_EVENT_TABLE_SIZE(atom);
28050cfab8ddSJoseph Koshy 			break;
2806e8f021a3SHiren Panchasara 		case PMC_CPU_INTEL_ATOM_SILVERMONT:
2807e8f021a3SHiren Panchasara 			ev = atom_silvermont_event_table;
2808e8f021a3SHiren Panchasara 			count = PMC_EVENT_TABLE_SIZE(atom_silvermont);
2809e8f021a3SHiren Panchasara 			break;
28100cfab8ddSJoseph Koshy 		case PMC_CPU_INTEL_CORE:
28110cfab8ddSJoseph Koshy 			ev = core_event_table;
28120cfab8ddSJoseph Koshy 			count = PMC_EVENT_TABLE_SIZE(core);
28130cfab8ddSJoseph Koshy 			break;
28140cfab8ddSJoseph Koshy 		case PMC_CPU_INTEL_CORE2:
2815b4d091f3SJoseph Koshy 		case PMC_CPU_INTEL_CORE2EXTREME:
28160cfab8ddSJoseph Koshy 			ev = core2_event_table;
28170cfab8ddSJoseph Koshy 			count = PMC_EVENT_TABLE_SIZE(core2);
28180cfab8ddSJoseph Koshy 			break;
2819597979c4SJeff Roberson 		case PMC_CPU_INTEL_COREI7:
2820597979c4SJeff Roberson 			ev = corei7_event_table;
2821597979c4SJeff Roberson 			count = PMC_EVENT_TABLE_SIZE(corei7);
2822597979c4SJeff Roberson 			break;
282349fe48abSKonstantin Belousov 		case PMC_CPU_INTEL_NEHALEM_EX:
282449fe48abSKonstantin Belousov 			ev = nehalem_ex_event_table;
282549fe48abSKonstantin Belousov 			count = PMC_EVENT_TABLE_SIZE(nehalem_ex);
282649fe48abSKonstantin Belousov 			break;
2827cc0c1555SSean Bruno 		case PMC_CPU_INTEL_HASWELL:
2828cc0c1555SSean Bruno 			ev = haswell_event_table;
2829cc0c1555SSean Bruno 			count = PMC_EVENT_TABLE_SIZE(haswell);
2830cc0c1555SSean Bruno 			break;
2831d95b3509SRandall Stewart 		case PMC_CPU_INTEL_HASWELL_XEON:
2832d95b3509SRandall Stewart 			ev = haswell_xeon_event_table;
2833d95b3509SRandall Stewart 			count = PMC_EVENT_TABLE_SIZE(haswell_xeon);
2834d95b3509SRandall Stewart 			break;
28351e862e5aSFabien Thomas 		case PMC_CPU_INTEL_IVYBRIDGE:
28361e862e5aSFabien Thomas 			ev = ivybridge_event_table;
28371e862e5aSFabien Thomas 			count = PMC_EVENT_TABLE_SIZE(ivybridge);
28381e862e5aSFabien Thomas 			break;
28393f929d8cSSean Bruno 		case PMC_CPU_INTEL_IVYBRIDGE_XEON:
28403f929d8cSSean Bruno 			ev = ivybridge_xeon_event_table;
28413f929d8cSSean Bruno 			count = PMC_EVENT_TABLE_SIZE(ivybridge_xeon);
28423f929d8cSSean Bruno 			break;
284378d763a2SDavide Italiano 		case PMC_CPU_INTEL_SANDYBRIDGE:
284478d763a2SDavide Italiano 			ev = sandybridge_event_table;
284578d763a2SDavide Italiano 			count = PMC_EVENT_TABLE_SIZE(sandybridge);
284678d763a2SDavide Italiano 			break;
2847fabe02f5SSean Bruno 		case PMC_CPU_INTEL_SANDYBRIDGE_XEON:
2848fabe02f5SSean Bruno 			ev = sandybridge_xeon_event_table;
2849fabe02f5SSean Bruno 			count = PMC_EVENT_TABLE_SIZE(sandybridge_xeon);
2850fabe02f5SSean Bruno 			break;
28511fa7f10bSFabien Thomas 		case PMC_CPU_INTEL_WESTMERE:
28521fa7f10bSFabien Thomas 			ev = westmere_event_table;
28531fa7f10bSFabien Thomas 			count = PMC_EVENT_TABLE_SIZE(westmere);
28541fa7f10bSFabien Thomas 			break;
285549fe48abSKonstantin Belousov 		case PMC_CPU_INTEL_WESTMERE_EX:
285649fe48abSKonstantin Belousov 			ev = westmere_ex_event_table;
285749fe48abSKonstantin Belousov 			count = PMC_EVENT_TABLE_SIZE(westmere_ex);
285849fe48abSKonstantin Belousov 			break;
28591fa7f10bSFabien Thomas 		}
28601fa7f10bSFabien Thomas 		break;
28611fa7f10bSFabien Thomas 	case PMC_CLASS_UCF:
28621fa7f10bSFabien Thomas 		ev = ucf_event_table;
28631fa7f10bSFabien Thomas 		count = PMC_EVENT_TABLE_SIZE(ucf);
28641fa7f10bSFabien Thomas 		break;
28651fa7f10bSFabien Thomas 	case PMC_CLASS_UCP:
28661fa7f10bSFabien Thomas 		/*
28671fa7f10bSFabien Thomas 		 * Return the most appropriate set of event name
28681fa7f10bSFabien Thomas 		 * spellings for the current CPU.
28691fa7f10bSFabien Thomas 		 */
28701fa7f10bSFabien Thomas 		switch (cpu_info.pm_cputype) {
28711fa7f10bSFabien Thomas 		default:
28721fa7f10bSFabien Thomas 		case PMC_CPU_INTEL_COREI7:
28731fa7f10bSFabien Thomas 			ev = corei7uc_event_table;
28741fa7f10bSFabien Thomas 			count = PMC_EVENT_TABLE_SIZE(corei7uc);
28751fa7f10bSFabien Thomas 			break;
2876cc0c1555SSean Bruno 		case PMC_CPU_INTEL_HASWELL:
2877cc0c1555SSean Bruno 			ev = haswelluc_event_table;
2878cc0c1555SSean Bruno 			count = PMC_EVENT_TABLE_SIZE(haswelluc);
2879cc0c1555SSean Bruno 			break;
288078d763a2SDavide Italiano 		case PMC_CPU_INTEL_SANDYBRIDGE:
288178d763a2SDavide Italiano 			ev = sandybridgeuc_event_table;
288278d763a2SDavide Italiano 			count = PMC_EVENT_TABLE_SIZE(sandybridgeuc);
288378d763a2SDavide Italiano 			break;
28841fa7f10bSFabien Thomas 		case PMC_CPU_INTEL_WESTMERE:
28851fa7f10bSFabien Thomas 			ev = westmereuc_event_table;
28861fa7f10bSFabien Thomas 			count = PMC_EVENT_TABLE_SIZE(westmereuc);
28871fa7f10bSFabien Thomas 			break;
28880cfab8ddSJoseph Koshy 		}
28890cfab8ddSJoseph Koshy 		break;
2890ebccf1e3SJoseph Koshy 	case PMC_CLASS_TSC:
2891789140c0SJoseph Koshy 		ev = tsc_event_table;
2892789140c0SJoseph Koshy 		count = PMC_EVENT_TABLE_SIZE(tsc);
2893ebccf1e3SJoseph Koshy 		break;
2894ebccf1e3SJoseph Koshy 	case PMC_CLASS_K7:
2895789140c0SJoseph Koshy 		ev = k7_event_table;
2896789140c0SJoseph Koshy 		count = PMC_EVENT_TABLE_SIZE(k7);
2897ebccf1e3SJoseph Koshy 		break;
2898ebccf1e3SJoseph Koshy 	case PMC_CLASS_K8:
2899789140c0SJoseph Koshy 		ev = k8_event_table;
2900789140c0SJoseph Koshy 		count = PMC_EVENT_TABLE_SIZE(k8);
2901ebccf1e3SJoseph Koshy 		break;
2902ebccf1e3SJoseph Koshy 	case PMC_CLASS_P4:
2903789140c0SJoseph Koshy 		ev = p4_event_table;
2904789140c0SJoseph Koshy 		count = PMC_EVENT_TABLE_SIZE(p4);
2905789140c0SJoseph Koshy 		break;
2906789140c0SJoseph Koshy 	case PMC_CLASS_P5:
2907789140c0SJoseph Koshy 		ev = p5_event_table;
2908789140c0SJoseph Koshy 		count = PMC_EVENT_TABLE_SIZE(p5);
2909789140c0SJoseph Koshy 		break;
2910789140c0SJoseph Koshy 	case PMC_CLASS_P6:
2911789140c0SJoseph Koshy 		ev = p6_event_table;
2912789140c0SJoseph Koshy 		count = PMC_EVENT_TABLE_SIZE(p6);
2913ebccf1e3SJoseph Koshy 		break;
29140ce207d2SRui Paulo 	case PMC_CLASS_XSCALE:
29150ce207d2SRui Paulo 		ev = xscale_event_table;
29160ce207d2SRui Paulo 		count = PMC_EVENT_TABLE_SIZE(xscale);
29170ce207d2SRui Paulo 		break;
2918*6411d14dSRuslan Bukin 	case PMC_CLASS_ARMV7:
2919*6411d14dSRuslan Bukin 		ev = armv7_event_table;
2920*6411d14dSRuslan Bukin 		count = PMC_EVENT_TABLE_SIZE(armv7);
2921*6411d14dSRuslan Bukin 		break;
2922660df75eSGeorge V. Neville-Neil 	case PMC_CLASS_MIPS24K:
2923660df75eSGeorge V. Neville-Neil 		ev = mips24k_event_table;
2924660df75eSGeorge V. Neville-Neil 		count = PMC_EVENT_TABLE_SIZE(mips24k);
2925660df75eSGeorge V. Neville-Neil 		break;
2926c2657f80SOleksandr Tymoshenko 	case PMC_CLASS_OCTEON:
2927c2657f80SOleksandr Tymoshenko 		ev = octeon_event_table;
2928c2657f80SOleksandr Tymoshenko 		count = PMC_EVENT_TABLE_SIZE(octeon);
2929c2657f80SOleksandr Tymoshenko 		break;
29307b25dccaSJustin Hibbits 	case PMC_CLASS_PPC7450:
29317b25dccaSJustin Hibbits 		ev = ppc7450_event_table;
29327b25dccaSJustin Hibbits 		count = PMC_EVENT_TABLE_SIZE(ppc7450);
29337b25dccaSJustin Hibbits 		break;
2934169dd953SJustin Hibbits 	case PMC_CLASS_PPC970:
2935169dd953SJustin Hibbits 		ev = ppc970_event_table;
2936169dd953SJustin Hibbits 		count = PMC_EVENT_TABLE_SIZE(ppc970);
2937169dd953SJustin Hibbits 		break;
2938f5f9340bSFabien Thomas 	case PMC_CLASS_SOFT:
2939f5f9340bSFabien Thomas 		ev = soft_event_table;
2940f5f9340bSFabien Thomas 		count = soft_event_info.pm_nevent;
2941f5f9340bSFabien Thomas 		break;
2942ebccf1e3SJoseph Koshy 	default:
2943ebccf1e3SJoseph Koshy 		errno = EINVAL;
2944aa342b1fSJoseph Koshy 		return (-1);
2945ebccf1e3SJoseph Koshy 	}
2946ebccf1e3SJoseph Koshy 
2947ebccf1e3SJoseph Koshy 	if ((names = malloc(count * sizeof(const char *))) == NULL)
2948aa342b1fSJoseph Koshy 		return (-1);
2949ebccf1e3SJoseph Koshy 
2950ebccf1e3SJoseph Koshy 	*eventnames = names;
2951ebccf1e3SJoseph Koshy 	*nevents = count;
2952ebccf1e3SJoseph Koshy 
2953ebccf1e3SJoseph Koshy 	for (;count--; ev++, names++)
2954ebccf1e3SJoseph Koshy 		*names = ev->pm_ev_name;
2955f5f9340bSFabien Thomas 
2956aa342b1fSJoseph Koshy 	return (0);
2957ebccf1e3SJoseph Koshy }
2958ebccf1e3SJoseph Koshy 
2959f263522aSJoseph Koshy int
2960f263522aSJoseph Koshy pmc_flush_logfile(void)
2961f263522aSJoseph Koshy {
2962aa342b1fSJoseph Koshy 	return (PMC_CALL(FLUSHLOG,0));
2963f263522aSJoseph Koshy }
2964ebccf1e3SJoseph Koshy 
2965ebccf1e3SJoseph Koshy int
2966dceed24aSFabien Thomas pmc_close_logfile(void)
2967dceed24aSFabien Thomas {
2968dceed24aSFabien Thomas 	return (PMC_CALL(CLOSELOG,0));
2969dceed24aSFabien Thomas }
2970dceed24aSFabien Thomas 
2971dceed24aSFabien Thomas int
2972f263522aSJoseph Koshy pmc_get_driver_stats(struct pmc_driverstats *ds)
2973ebccf1e3SJoseph Koshy {
2974f263522aSJoseph Koshy 	struct pmc_op_getdriverstats gms;
2975f263522aSJoseph Koshy 
2976f263522aSJoseph Koshy 	if (PMC_CALL(GETDRIVERSTATS, &gms) < 0)
2977aa342b1fSJoseph Koshy 		return (-1);
2978f263522aSJoseph Koshy 
2979f263522aSJoseph Koshy 	/* copy out fields in the current userland<->library interface */
2980f263522aSJoseph Koshy 	ds->pm_intr_ignored    = gms.pm_intr_ignored;
2981f263522aSJoseph Koshy 	ds->pm_intr_processed  = gms.pm_intr_processed;
2982f263522aSJoseph Koshy 	ds->pm_intr_bufferfull = gms.pm_intr_bufferfull;
2983f263522aSJoseph Koshy 	ds->pm_syscalls        = gms.pm_syscalls;
2984f263522aSJoseph Koshy 	ds->pm_syscall_errors  = gms.pm_syscall_errors;
2985f263522aSJoseph Koshy 	ds->pm_buffer_requests = gms.pm_buffer_requests;
2986f263522aSJoseph Koshy 	ds->pm_buffer_requests_failed = gms.pm_buffer_requests_failed;
2987f263522aSJoseph Koshy 	ds->pm_log_sweeps      = gms.pm_log_sweeps;
2988aa342b1fSJoseph Koshy 	return (0);
2989f263522aSJoseph Koshy }
2990f263522aSJoseph Koshy 
2991f263522aSJoseph Koshy int
2992f263522aSJoseph Koshy pmc_get_msr(pmc_id_t pmc, uint32_t *msr)
2993f263522aSJoseph Koshy {
2994f263522aSJoseph Koshy 	struct pmc_op_getmsr gm;
2995ebccf1e3SJoseph Koshy 
2996ebccf1e3SJoseph Koshy 	gm.pm_pmcid = pmc;
2997f263522aSJoseph Koshy 	if (PMC_CALL(PMCGETMSR, &gm) < 0)
2998aa342b1fSJoseph Koshy 		return (-1);
2999ebccf1e3SJoseph Koshy 	*msr = gm.pm_msr;
3000aa342b1fSJoseph Koshy 	return (0);
3001ebccf1e3SJoseph Koshy }
3002ebccf1e3SJoseph Koshy 
3003f263522aSJoseph Koshy int
3004f263522aSJoseph Koshy pmc_init(void)
3005f263522aSJoseph Koshy {
3006f263522aSJoseph Koshy 	int error, pmc_mod_id;
30071455fcd3SJoseph Koshy 	unsigned int n;
3008f263522aSJoseph Koshy 	uint32_t abi_version;
3009f263522aSJoseph Koshy 	struct module_stat pmc_modstat;
30101455fcd3SJoseph Koshy 	struct pmc_op_getcpuinfo op_cpu_info;
3011791f5d5bSJoseph Koshy #if defined(__amd64__) || defined(__i386__)
3012791f5d5bSJoseph Koshy 	int cpu_has_iaf_counters;
3013791f5d5bSJoseph Koshy 	unsigned int t;
3014791f5d5bSJoseph Koshy #endif
3015f263522aSJoseph Koshy 
3016f263522aSJoseph Koshy 	if (pmc_syscall != -1) /* already inited */
3017aa342b1fSJoseph Koshy 		return (0);
3018f263522aSJoseph Koshy 
3019f263522aSJoseph Koshy 	/* retrieve the system call number from the KLD */
3020f263522aSJoseph Koshy 	if ((pmc_mod_id = modfind(PMC_MODULE_NAME)) < 0)
3021aa342b1fSJoseph Koshy 		return (-1);
3022f263522aSJoseph Koshy 
3023f263522aSJoseph Koshy 	pmc_modstat.version = sizeof(struct module_stat);
3024f263522aSJoseph Koshy 	if ((error = modstat(pmc_mod_id, &pmc_modstat)) < 0)
3025aa342b1fSJoseph Koshy 		return (-1);
3026f263522aSJoseph Koshy 
3027f263522aSJoseph Koshy 	pmc_syscall = pmc_modstat.data.intval;
3028f263522aSJoseph Koshy 
3029f263522aSJoseph Koshy 	/* check the kernel module's ABI against our compiled-in version */
3030f263522aSJoseph Koshy 	abi_version = PMC_VERSION;
3031f263522aSJoseph Koshy 	if (PMC_CALL(GETMODULEVERSION, &abi_version) < 0)
3032f263522aSJoseph Koshy 		return (pmc_syscall = -1);
3033f263522aSJoseph Koshy 
3034f263522aSJoseph Koshy 	/* ignore patch & minor numbers for the comparision */
3035f263522aSJoseph Koshy 	if ((abi_version & 0xFF000000) != (PMC_VERSION & 0xFF000000)) {
3036f263522aSJoseph Koshy 		errno  = EPROGMISMATCH;
3037f263522aSJoseph Koshy 		return (pmc_syscall = -1);
3038f263522aSJoseph Koshy 	}
3039f263522aSJoseph Koshy 
30401455fcd3SJoseph Koshy 	if (PMC_CALL(GETCPUINFO, &op_cpu_info) < 0)
3041f263522aSJoseph Koshy 		return (pmc_syscall = -1);
3042f263522aSJoseph Koshy 
30431455fcd3SJoseph Koshy 	cpu_info.pm_cputype = op_cpu_info.pm_cputype;
30441455fcd3SJoseph Koshy 	cpu_info.pm_ncpu    = op_cpu_info.pm_ncpu;
30451455fcd3SJoseph Koshy 	cpu_info.pm_npmc    = op_cpu_info.pm_npmc;
30461455fcd3SJoseph Koshy 	cpu_info.pm_nclass  = op_cpu_info.pm_nclass;
30471455fcd3SJoseph Koshy 	for (n = 0; n < cpu_info.pm_nclass; n++)
30481455fcd3SJoseph Koshy 		cpu_info.pm_classes[n] = op_cpu_info.pm_classes[n];
30491455fcd3SJoseph Koshy 
30500cfab8ddSJoseph Koshy 	pmc_class_table = malloc(PMC_CLASS_TABLE_SIZE *
30510cfab8ddSJoseph Koshy 	    sizeof(struct pmc_class_descr *));
30520cfab8ddSJoseph Koshy 
30530cfab8ddSJoseph Koshy 	if (pmc_class_table == NULL)
30540cfab8ddSJoseph Koshy 		return (-1);
30550cfab8ddSJoseph Koshy 
3056791f5d5bSJoseph Koshy 	for (n = 0; n < PMC_CLASS_TABLE_SIZE; n++)
3057791f5d5bSJoseph Koshy 		pmc_class_table[n] = NULL;
30580cfab8ddSJoseph Koshy 
30590cfab8ddSJoseph Koshy 	/*
3060f5f9340bSFabien Thomas 	 * Get soft events list.
3061f5f9340bSFabien Thomas 	 */
3062f5f9340bSFabien Thomas 	soft_event_info.pm_class = PMC_CLASS_SOFT;
3063f5f9340bSFabien Thomas 	if (PMC_CALL(GETDYNEVENTINFO, &soft_event_info) < 0)
3064f5f9340bSFabien Thomas 		return (pmc_syscall = -1);
3065f5f9340bSFabien Thomas 
3066f5f9340bSFabien Thomas 	/* Map soft events to static list. */
3067f5f9340bSFabien Thomas 	for (n = 0; n < soft_event_info.pm_nevent; n++) {
3068f5f9340bSFabien Thomas 		soft_event_table[n].pm_ev_name =
3069f5f9340bSFabien Thomas 		    soft_event_info.pm_events[n].pm_ev_name;
3070f5f9340bSFabien Thomas 		soft_event_table[n].pm_ev_code =
3071f5f9340bSFabien Thomas 		    soft_event_info.pm_events[n].pm_ev_code;
3072f5f9340bSFabien Thomas 	}
3073f5f9340bSFabien Thomas 	soft_class_table_descr.pm_evc_event_table_size = \
3074f5f9340bSFabien Thomas 	    soft_event_info.pm_nevent;
3075f5f9340bSFabien Thomas 	soft_class_table_descr.pm_evc_event_table = \
3076f5f9340bSFabien Thomas 	    soft_event_table;
3077f5f9340bSFabien Thomas 
3078f5f9340bSFabien Thomas 	/*
30790cfab8ddSJoseph Koshy 	 * Fill in the class table.
30800cfab8ddSJoseph Koshy 	 */
30810cfab8ddSJoseph Koshy 	n = 0;
3082f5f9340bSFabien Thomas 
3083f5f9340bSFabien Thomas 	/* Fill soft events information. */
3084f5f9340bSFabien Thomas 	pmc_class_table[n++] = &soft_class_table_descr;
30850cfab8ddSJoseph Koshy #if defined(__amd64__) || defined(__i386__)
3086f5f9340bSFabien Thomas 	if (cpu_info.pm_cputype != PMC_CPU_GENERIC)
30870cfab8ddSJoseph Koshy 		pmc_class_table[n++] = &tsc_class_table_descr;
3088791f5d5bSJoseph Koshy 
3089791f5d5bSJoseph Koshy 	/*
3090791f5d5bSJoseph Koshy  	 * Check if this CPU has fixed function counters.
3091791f5d5bSJoseph Koshy 	 */
3092791f5d5bSJoseph Koshy 	cpu_has_iaf_counters = 0;
3093791f5d5bSJoseph Koshy 	for (t = 0; t < cpu_info.pm_nclass; t++)
30942aef9dd6SFabien Thomas 		if (cpu_info.pm_classes[t].pm_class == PMC_CLASS_IAF &&
30952aef9dd6SFabien Thomas 		    cpu_info.pm_classes[t].pm_num > 0)
3096791f5d5bSJoseph Koshy 			cpu_has_iaf_counters = 1;
30970cfab8ddSJoseph Koshy #endif
30980cfab8ddSJoseph Koshy 
3099789140c0SJoseph Koshy #define	PMC_MDEP_INIT(C) do {					\
3100789140c0SJoseph Koshy 		pmc_mdep_event_aliases    = C##_aliases;	\
3101789140c0SJoseph Koshy 		pmc_mdep_class_list  = C##_pmc_classes;		\
3102789140c0SJoseph Koshy 		pmc_mdep_class_list_size =			\
3103789140c0SJoseph Koshy 		    PMC_TABLE_SIZE(C##_pmc_classes);		\
3104789140c0SJoseph Koshy 	} while (0)
3105789140c0SJoseph Koshy 
3106791f5d5bSJoseph Koshy #define	PMC_MDEP_INIT_INTEL_V2(C) do {					\
3107791f5d5bSJoseph Koshy 		PMC_MDEP_INIT(C);					\
3108791f5d5bSJoseph Koshy 		pmc_class_table[n++] = &iaf_class_table_descr;		\
31092aef9dd6SFabien Thomas 		if (!cpu_has_iaf_counters) 				\
3110791f5d5bSJoseph Koshy 			pmc_mdep_event_aliases =			\
3111791f5d5bSJoseph Koshy 				C##_aliases_without_iaf;		\
3112791f5d5bSJoseph Koshy 		pmc_class_table[n] = &C##_class_table_descr;		\
3113791f5d5bSJoseph Koshy 	} while (0)
3114791f5d5bSJoseph Koshy 
3115789140c0SJoseph Koshy 	/* Configure the event name parser. */
3116f263522aSJoseph Koshy 	switch (cpu_info.pm_cputype) {
3117f263522aSJoseph Koshy #if defined(__i386__)
3118f263522aSJoseph Koshy 	case PMC_CPU_AMD_K7:
3119789140c0SJoseph Koshy 		PMC_MDEP_INIT(k7);
31200cfab8ddSJoseph Koshy 		pmc_class_table[n] = &k7_class_table_descr;
3121f263522aSJoseph Koshy 		break;
3122f263522aSJoseph Koshy 	case PMC_CPU_INTEL_P5:
3123789140c0SJoseph Koshy 		PMC_MDEP_INIT(p5);
31240cfab8ddSJoseph Koshy 		pmc_class_table[n]  = &p5_class_table_descr;
3125f263522aSJoseph Koshy 		break;
3126f263522aSJoseph Koshy 	case PMC_CPU_INTEL_P6:		/* P6 ... Pentium M CPUs have */
3127f263522aSJoseph Koshy 	case PMC_CPU_INTEL_PII:		/* similar PMCs. */
3128f263522aSJoseph Koshy 	case PMC_CPU_INTEL_PIII:
3129f263522aSJoseph Koshy 	case PMC_CPU_INTEL_PM:
3130789140c0SJoseph Koshy 		PMC_MDEP_INIT(p6);
31310cfab8ddSJoseph Koshy 		pmc_class_table[n] = &p6_class_table_descr;
3132f263522aSJoseph Koshy 		break;
313386a65549SJoseph Koshy #endif
313486a65549SJoseph Koshy #if defined(__amd64__) || defined(__i386__)
3135f263522aSJoseph Koshy 	case PMC_CPU_AMD_K8:
3136789140c0SJoseph Koshy 		PMC_MDEP_INIT(k8);
31370cfab8ddSJoseph Koshy 		pmc_class_table[n] = &k8_class_table_descr;
31380cfab8ddSJoseph Koshy 		break;
31390cfab8ddSJoseph Koshy 	case PMC_CPU_INTEL_ATOM:
3140791f5d5bSJoseph Koshy 		PMC_MDEP_INIT_INTEL_V2(atom);
31410cfab8ddSJoseph Koshy 		break;
3142e8f021a3SHiren Panchasara 	case PMC_CPU_INTEL_ATOM_SILVERMONT:
3143e8f021a3SHiren Panchasara 		PMC_MDEP_INIT_INTEL_V2(atom_silvermont);
3144e8f021a3SHiren Panchasara 		break;
31450cfab8ddSJoseph Koshy 	case PMC_CPU_INTEL_CORE:
31460cfab8ddSJoseph Koshy 		PMC_MDEP_INIT(core);
3147bc315bbdSJoseph Koshy 		pmc_class_table[n] = &core_class_table_descr;
31480cfab8ddSJoseph Koshy 		break;
31490cfab8ddSJoseph Koshy 	case PMC_CPU_INTEL_CORE2:
3150b4d091f3SJoseph Koshy 	case PMC_CPU_INTEL_CORE2EXTREME:
3151791f5d5bSJoseph Koshy 		PMC_MDEP_INIT_INTEL_V2(core2);
3152789140c0SJoseph Koshy 		break;
3153597979c4SJeff Roberson 	case PMC_CPU_INTEL_COREI7:
31541fa7f10bSFabien Thomas 		pmc_class_table[n++] = &ucf_class_table_descr;
31551fa7f10bSFabien Thomas 		pmc_class_table[n++] = &corei7uc_class_table_descr;
3156791f5d5bSJoseph Koshy 		PMC_MDEP_INIT_INTEL_V2(corei7);
3157597979c4SJeff Roberson 		break;
315849fe48abSKonstantin Belousov 	case PMC_CPU_INTEL_NEHALEM_EX:
315949fe48abSKonstantin Belousov 		PMC_MDEP_INIT_INTEL_V2(nehalem_ex);
316049fe48abSKonstantin Belousov 		break;
3161cc0c1555SSean Bruno 	case PMC_CPU_INTEL_HASWELL:
3162cc0c1555SSean Bruno 		pmc_class_table[n++] = &ucf_class_table_descr;
3163cc0c1555SSean Bruno 		pmc_class_table[n++] = &haswelluc_class_table_descr;
3164cc0c1555SSean Bruno 		PMC_MDEP_INIT_INTEL_V2(haswell);
3165cc0c1555SSean Bruno 		break;
3166d95b3509SRandall Stewart 	case PMC_CPU_INTEL_HASWELL_XEON:
3167d95b3509SRandall Stewart 		PMC_MDEP_INIT_INTEL_V2(haswell_xeon);
3168d95b3509SRandall Stewart 		break;
31691e862e5aSFabien Thomas 	case PMC_CPU_INTEL_IVYBRIDGE:
31701e862e5aSFabien Thomas 		PMC_MDEP_INIT_INTEL_V2(ivybridge);
31711e862e5aSFabien Thomas 		break;
31723f929d8cSSean Bruno 	case PMC_CPU_INTEL_IVYBRIDGE_XEON:
31733f929d8cSSean Bruno 		PMC_MDEP_INIT_INTEL_V2(ivybridge_xeon);
31743f929d8cSSean Bruno 		break;
317578d763a2SDavide Italiano 	case PMC_CPU_INTEL_SANDYBRIDGE:
317678d763a2SDavide Italiano 		pmc_class_table[n++] = &ucf_class_table_descr;
317778d763a2SDavide Italiano 		pmc_class_table[n++] = &sandybridgeuc_class_table_descr;
317878d763a2SDavide Italiano 		PMC_MDEP_INIT_INTEL_V2(sandybridge);
317978d763a2SDavide Italiano 		break;
3180fabe02f5SSean Bruno 	case PMC_CPU_INTEL_SANDYBRIDGE_XEON:
3181fabe02f5SSean Bruno 		PMC_MDEP_INIT_INTEL_V2(sandybridge_xeon);
3182fabe02f5SSean Bruno 		break;
31831fa7f10bSFabien Thomas 	case PMC_CPU_INTEL_WESTMERE:
31841fa7f10bSFabien Thomas 		pmc_class_table[n++] = &ucf_class_table_descr;
31851fa7f10bSFabien Thomas 		pmc_class_table[n++] = &westmereuc_class_table_descr;
31861fa7f10bSFabien Thomas 		PMC_MDEP_INIT_INTEL_V2(westmere);
31871fa7f10bSFabien Thomas 		break;
318849fe48abSKonstantin Belousov 	case PMC_CPU_INTEL_WESTMERE_EX:
318949fe48abSKonstantin Belousov 		PMC_MDEP_INIT_INTEL_V2(westmere_ex);
319049fe48abSKonstantin Belousov 		break;
3191789140c0SJoseph Koshy 	case PMC_CPU_INTEL_PIV:
3192789140c0SJoseph Koshy 		PMC_MDEP_INIT(p4);
31930cfab8ddSJoseph Koshy 		pmc_class_table[n] = &p4_class_table_descr;
3194f263522aSJoseph Koshy 		break;
3195ebccf1e3SJoseph Koshy #endif
3196f5f9340bSFabien Thomas 	case PMC_CPU_GENERIC:
3197f5f9340bSFabien Thomas 		PMC_MDEP_INIT(generic);
3198f5f9340bSFabien Thomas 		break;
3199*6411d14dSRuslan Bukin #if defined(__arm__)
32000ce207d2SRui Paulo #if defined(__XSCALE__)
32010ce207d2SRui Paulo 	case PMC_CPU_INTEL_XSCALE:
32020ce207d2SRui Paulo 		PMC_MDEP_INIT(xscale);
32030ce207d2SRui Paulo 		pmc_class_table[n] = &xscale_class_table_descr;
32040ce207d2SRui Paulo 		break;
32050ce207d2SRui Paulo #endif
3206*6411d14dSRuslan Bukin 	case PMC_CPU_ARMV7:
3207*6411d14dSRuslan Bukin 		PMC_MDEP_INIT(armv7);
3208*6411d14dSRuslan Bukin 		pmc_class_table[n] = &armv7_class_table_descr;
3209*6411d14dSRuslan Bukin 		break;
3210*6411d14dSRuslan Bukin #endif
3211660df75eSGeorge V. Neville-Neil #if defined(__mips__)
3212660df75eSGeorge V. Neville-Neil 	case PMC_CPU_MIPS_24K:
3213660df75eSGeorge V. Neville-Neil 		PMC_MDEP_INIT(mips24k);
3214660df75eSGeorge V. Neville-Neil 		pmc_class_table[n] = &mips24k_class_table_descr;
3215660df75eSGeorge V. Neville-Neil 		break;
3216c2657f80SOleksandr Tymoshenko 	case PMC_CPU_MIPS_OCTEON:
3217c2657f80SOleksandr Tymoshenko 		PMC_MDEP_INIT(octeon);
3218c2657f80SOleksandr Tymoshenko 		pmc_class_table[n] = &octeon_class_table_descr;
3219c2657f80SOleksandr Tymoshenko 		break;
3220660df75eSGeorge V. Neville-Neil #endif /* __mips__ */
32217b25dccaSJustin Hibbits #if defined(__powerpc__)
32227b25dccaSJustin Hibbits 	case PMC_CPU_PPC_7450:
32237b25dccaSJustin Hibbits 		PMC_MDEP_INIT(ppc7450);
32247b25dccaSJustin Hibbits 		pmc_class_table[n] = &ppc7450_class_table_descr;
32257b25dccaSJustin Hibbits 		break;
3226169dd953SJustin Hibbits 	case PMC_CPU_PPC_970:
3227169dd953SJustin Hibbits 		PMC_MDEP_INIT(ppc970);
3228169dd953SJustin Hibbits 		pmc_class_table[n] = &ppc970_class_table_descr;
3229169dd953SJustin Hibbits 		break;
32307b25dccaSJustin Hibbits #endif
3231f263522aSJoseph Koshy 	default:
3232f263522aSJoseph Koshy 		/*
3233f263522aSJoseph Koshy 		 * Some kind of CPU this version of the library knows nothing
3234f263522aSJoseph Koshy 		 * about.  This shouldn't happen since the abi version check
3235f263522aSJoseph Koshy 		 * should have caught this.
3236f263522aSJoseph Koshy 		 */
3237f263522aSJoseph Koshy 		errno = ENXIO;
3238f263522aSJoseph Koshy 		return (pmc_syscall = -1);
3239f263522aSJoseph Koshy 	}
3240f263522aSJoseph Koshy 
3241aa342b1fSJoseph Koshy 	return (0);
3242f263522aSJoseph Koshy }
3243f263522aSJoseph Koshy 
3244f263522aSJoseph Koshy const char *
3245f263522aSJoseph Koshy pmc_name_of_capability(enum pmc_caps cap)
3246f263522aSJoseph Koshy {
3247f263522aSJoseph Koshy 	int i;
3248f263522aSJoseph Koshy 
3249f263522aSJoseph Koshy 	/*
3250f263522aSJoseph Koshy 	 * 'cap' should have a single bit set and should be in
3251f263522aSJoseph Koshy 	 * range.
3252f263522aSJoseph Koshy 	 */
3253f263522aSJoseph Koshy 	if ((cap & (cap - 1)) || cap < PMC_CAP_FIRST ||
3254f263522aSJoseph Koshy 	    cap > PMC_CAP_LAST) {
3255f263522aSJoseph Koshy 		errno = EINVAL;
3256aa342b1fSJoseph Koshy 		return (NULL);
3257f263522aSJoseph Koshy 	}
3258f263522aSJoseph Koshy 
3259f263522aSJoseph Koshy 	i = ffs(cap);
3260aa342b1fSJoseph Koshy 	return (pmc_capability_names[i - 1]);
3261f263522aSJoseph Koshy }
3262f263522aSJoseph Koshy 
3263f263522aSJoseph Koshy const char *
3264f263522aSJoseph Koshy pmc_name_of_class(enum pmc_class pc)
3265f263522aSJoseph Koshy {
3266f263522aSJoseph Koshy 	if ((int) pc >= PMC_CLASS_FIRST &&
3267f263522aSJoseph Koshy 	    pc <= PMC_CLASS_LAST)
3268aa342b1fSJoseph Koshy 		return (pmc_class_names[pc]);
3269f263522aSJoseph Koshy 
3270f263522aSJoseph Koshy 	errno = EINVAL;
3271aa342b1fSJoseph Koshy 	return (NULL);
3272f263522aSJoseph Koshy }
3273f263522aSJoseph Koshy 
3274f263522aSJoseph Koshy const char *
3275f263522aSJoseph Koshy pmc_name_of_cputype(enum pmc_cputype cp)
3276f263522aSJoseph Koshy {
3277789140c0SJoseph Koshy 	size_t n;
3278789140c0SJoseph Koshy 
3279789140c0SJoseph Koshy 	for (n = 0; n < PMC_TABLE_SIZE(pmc_cputype_names); n++)
3280789140c0SJoseph Koshy 		if (cp == pmc_cputype_names[n].pm_cputype)
3281789140c0SJoseph Koshy 			return (pmc_cputype_names[n].pm_name);
3282789140c0SJoseph Koshy 
3283f263522aSJoseph Koshy 	errno = EINVAL;
3284aa342b1fSJoseph Koshy 	return (NULL);
3285f263522aSJoseph Koshy }
3286f263522aSJoseph Koshy 
3287f263522aSJoseph Koshy const char *
3288f263522aSJoseph Koshy pmc_name_of_disposition(enum pmc_disp pd)
3289f263522aSJoseph Koshy {
3290f263522aSJoseph Koshy 	if ((int) pd >= PMC_DISP_FIRST &&
3291f263522aSJoseph Koshy 	    pd <= PMC_DISP_LAST)
3292aa342b1fSJoseph Koshy 		return (pmc_disposition_names[pd]);
3293f263522aSJoseph Koshy 
3294f263522aSJoseph Koshy 	errno = EINVAL;
3295aa342b1fSJoseph Koshy 	return (NULL);
3296f263522aSJoseph Koshy }
3297f263522aSJoseph Koshy 
3298f263522aSJoseph Koshy const char *
32990cfab8ddSJoseph Koshy _pmc_name_of_event(enum pmc_event pe, enum pmc_cputype cpu)
3300f263522aSJoseph Koshy {
3301789140c0SJoseph Koshy 	const struct pmc_event_descr *ev, *evfence;
3302789140c0SJoseph Koshy 
3303789140c0SJoseph Koshy 	ev = evfence = NULL;
33040cfab8ddSJoseph Koshy 	if (pe >= PMC_EV_IAF_FIRST && pe <= PMC_EV_IAF_LAST) {
33050cfab8ddSJoseph Koshy 		ev = iaf_event_table;
33060cfab8ddSJoseph Koshy 		evfence = iaf_event_table + PMC_EVENT_TABLE_SIZE(iaf);
33070cfab8ddSJoseph Koshy 	} else if (pe >= PMC_EV_IAP_FIRST && pe <= PMC_EV_IAP_LAST) {
33080cfab8ddSJoseph Koshy 		switch (cpu) {
33090cfab8ddSJoseph Koshy 		case PMC_CPU_INTEL_ATOM:
33100cfab8ddSJoseph Koshy 			ev = atom_event_table;
33110cfab8ddSJoseph Koshy 			evfence = atom_event_table + PMC_EVENT_TABLE_SIZE(atom);
33120cfab8ddSJoseph Koshy 			break;
3313e8f021a3SHiren Panchasara 		case PMC_CPU_INTEL_ATOM_SILVERMONT:
3314e8f021a3SHiren Panchasara 			ev = atom_silvermont_event_table;
3315e8f021a3SHiren Panchasara 			evfence = atom_silvermont_event_table +
3316e8f021a3SHiren Panchasara 			    PMC_EVENT_TABLE_SIZE(atom_silvermont);
3317e8f021a3SHiren Panchasara 			break;
33180cfab8ddSJoseph Koshy 		case PMC_CPU_INTEL_CORE:
33190cfab8ddSJoseph Koshy 			ev = core_event_table;
33200cfab8ddSJoseph Koshy 			evfence = core_event_table + PMC_EVENT_TABLE_SIZE(core);
33210cfab8ddSJoseph Koshy 			break;
33220cfab8ddSJoseph Koshy 		case PMC_CPU_INTEL_CORE2:
3323b4d091f3SJoseph Koshy 		case PMC_CPU_INTEL_CORE2EXTREME:
33240cfab8ddSJoseph Koshy 			ev = core2_event_table;
33250cfab8ddSJoseph Koshy 			evfence = core2_event_table + PMC_EVENT_TABLE_SIZE(core2);
33260cfab8ddSJoseph Koshy 			break;
3327597979c4SJeff Roberson 		case PMC_CPU_INTEL_COREI7:
3328597979c4SJeff Roberson 			ev = corei7_event_table;
3329597979c4SJeff Roberson 			evfence = corei7_event_table + PMC_EVENT_TABLE_SIZE(corei7);
3330597979c4SJeff Roberson 			break;
333149fe48abSKonstantin Belousov 		case PMC_CPU_INTEL_NEHALEM_EX:
333249fe48abSKonstantin Belousov 			ev = nehalem_ex_event_table;
333349fe48abSKonstantin Belousov 			evfence = nehalem_ex_event_table +
333449fe48abSKonstantin Belousov 			    PMC_EVENT_TABLE_SIZE(nehalem_ex);
333549fe48abSKonstantin Belousov 			break;
3336cc0c1555SSean Bruno 		case PMC_CPU_INTEL_HASWELL:
3337cc0c1555SSean Bruno 			ev = haswell_event_table;
3338cc0c1555SSean Bruno 			evfence = haswell_event_table + PMC_EVENT_TABLE_SIZE(haswell);
3339cc0c1555SSean Bruno 			break;
3340d95b3509SRandall Stewart 		case PMC_CPU_INTEL_HASWELL_XEON:
3341d95b3509SRandall Stewart 			ev = haswell_xeon_event_table;
3342d95b3509SRandall Stewart 			evfence = haswell_xeon_event_table + PMC_EVENT_TABLE_SIZE(haswell_xeon);
3343d95b3509SRandall Stewart 			break;
3344d95b3509SRandall Stewart 
33451e862e5aSFabien Thomas 		case PMC_CPU_INTEL_IVYBRIDGE:
33461e862e5aSFabien Thomas 			ev = ivybridge_event_table;
33471e862e5aSFabien Thomas 			evfence = ivybridge_event_table + PMC_EVENT_TABLE_SIZE(ivybridge);
33481e862e5aSFabien Thomas 			break;
33493f929d8cSSean Bruno 		case PMC_CPU_INTEL_IVYBRIDGE_XEON:
33503f929d8cSSean Bruno 			ev = ivybridge_xeon_event_table;
33513f929d8cSSean Bruno 			evfence = ivybridge_xeon_event_table + PMC_EVENT_TABLE_SIZE(ivybridge_xeon);
33523f929d8cSSean Bruno 			break;
335378d763a2SDavide Italiano 		case PMC_CPU_INTEL_SANDYBRIDGE:
335478d763a2SDavide Italiano 			ev = sandybridge_event_table;
335578d763a2SDavide Italiano 			evfence = sandybridge_event_table + PMC_EVENT_TABLE_SIZE(sandybridge);
335678d763a2SDavide Italiano 			break;
3357fabe02f5SSean Bruno 		case PMC_CPU_INTEL_SANDYBRIDGE_XEON:
3358fabe02f5SSean Bruno 			ev = sandybridge_xeon_event_table;
3359fabe02f5SSean Bruno 			evfence = sandybridge_xeon_event_table + PMC_EVENT_TABLE_SIZE(sandybridge_xeon);
3360fabe02f5SSean Bruno 			break;
33611fa7f10bSFabien Thomas 		case PMC_CPU_INTEL_WESTMERE:
33621fa7f10bSFabien Thomas 			ev = westmere_event_table;
33631fa7f10bSFabien Thomas 			evfence = westmere_event_table + PMC_EVENT_TABLE_SIZE(westmere);
33641fa7f10bSFabien Thomas 			break;
336549fe48abSKonstantin Belousov 		case PMC_CPU_INTEL_WESTMERE_EX:
336649fe48abSKonstantin Belousov 			ev = westmere_ex_event_table;
336749fe48abSKonstantin Belousov 			evfence = westmere_ex_event_table +
336849fe48abSKonstantin Belousov 			    PMC_EVENT_TABLE_SIZE(westmere_ex);
336949fe48abSKonstantin Belousov 			break;
33700cfab8ddSJoseph Koshy 		default:	/* Unknown CPU type. */
33710cfab8ddSJoseph Koshy 			break;
33720cfab8ddSJoseph Koshy 		}
33731fa7f10bSFabien Thomas 	} else if (pe >= PMC_EV_UCF_FIRST && pe <= PMC_EV_UCF_LAST) {
33741fa7f10bSFabien Thomas 		ev = ucf_event_table;
33751fa7f10bSFabien Thomas 		evfence = ucf_event_table + PMC_EVENT_TABLE_SIZE(ucf);
33761fa7f10bSFabien Thomas 	} else if (pe >= PMC_EV_UCP_FIRST && pe <= PMC_EV_UCP_LAST) {
33771fa7f10bSFabien Thomas 		switch (cpu) {
33781fa7f10bSFabien Thomas 		case PMC_CPU_INTEL_COREI7:
33791fa7f10bSFabien Thomas 			ev = corei7uc_event_table;
33801fa7f10bSFabien Thomas 			evfence = corei7uc_event_table + PMC_EVENT_TABLE_SIZE(corei7uc);
33811fa7f10bSFabien Thomas 			break;
338278d763a2SDavide Italiano 		case PMC_CPU_INTEL_SANDYBRIDGE:
338378d763a2SDavide Italiano 			ev = sandybridgeuc_event_table;
338478d763a2SDavide Italiano 			evfence = sandybridgeuc_event_table + PMC_EVENT_TABLE_SIZE(sandybridgeuc);
338578d763a2SDavide Italiano 			break;
33861fa7f10bSFabien Thomas 		case PMC_CPU_INTEL_WESTMERE:
33871fa7f10bSFabien Thomas 			ev = westmereuc_event_table;
33881fa7f10bSFabien Thomas 			evfence = westmereuc_event_table + PMC_EVENT_TABLE_SIZE(westmereuc);
33891fa7f10bSFabien Thomas 			break;
33901fa7f10bSFabien Thomas 		default:	/* Unknown CPU type. */
33911fa7f10bSFabien Thomas 			break;
33921fa7f10bSFabien Thomas 		}
33931fa7f10bSFabien Thomas 	} else if (pe >= PMC_EV_K7_FIRST && pe <= PMC_EV_K7_LAST) {
3394789140c0SJoseph Koshy 		ev = k7_event_table;
3395789140c0SJoseph Koshy 		evfence = k7_event_table + PMC_EVENT_TABLE_SIZE(k7);
3396789140c0SJoseph Koshy 	} else if (pe >= PMC_EV_K8_FIRST && pe <= PMC_EV_K8_LAST) {
3397789140c0SJoseph Koshy 		ev = k8_event_table;
3398789140c0SJoseph Koshy 		evfence = k8_event_table + PMC_EVENT_TABLE_SIZE(k8);
3399789140c0SJoseph Koshy 	} else if (pe >= PMC_EV_P4_FIRST && pe <= PMC_EV_P4_LAST) {
3400789140c0SJoseph Koshy 		ev = p4_event_table;
3401789140c0SJoseph Koshy 		evfence = p4_event_table + PMC_EVENT_TABLE_SIZE(p4);
3402789140c0SJoseph Koshy 	} else if (pe >= PMC_EV_P5_FIRST && pe <= PMC_EV_P5_LAST) {
3403789140c0SJoseph Koshy 		ev = p5_event_table;
3404789140c0SJoseph Koshy 		evfence = p5_event_table + PMC_EVENT_TABLE_SIZE(p5);
3405789140c0SJoseph Koshy 	} else if (pe >= PMC_EV_P6_FIRST && pe <= PMC_EV_P6_LAST) {
3406789140c0SJoseph Koshy 		ev = p6_event_table;
3407789140c0SJoseph Koshy 		evfence = p6_event_table + PMC_EVENT_TABLE_SIZE(p6);
34080ce207d2SRui Paulo 	} else if (pe >= PMC_EV_XSCALE_FIRST && pe <= PMC_EV_XSCALE_LAST) {
34090ce207d2SRui Paulo 		ev = xscale_event_table;
34100ce207d2SRui Paulo 		evfence = xscale_event_table + PMC_EVENT_TABLE_SIZE(xscale);
3411*6411d14dSRuslan Bukin 	} else if (pe >= PMC_EV_ARMV7_FIRST && pe <= PMC_EV_ARMV7_LAST) {
3412*6411d14dSRuslan Bukin 		ev = armv7_event_table;
3413*6411d14dSRuslan Bukin 		evfence = armv7_event_table + PMC_EVENT_TABLE_SIZE(armv7);
3414660df75eSGeorge V. Neville-Neil 	} else if (pe >= PMC_EV_MIPS24K_FIRST && pe <= PMC_EV_MIPS24K_LAST) {
3415660df75eSGeorge V. Neville-Neil 		ev = mips24k_event_table;
3416f5f9340bSFabien Thomas 		evfence = mips24k_event_table + PMC_EVENT_TABLE_SIZE(mips24k);
3417c2657f80SOleksandr Tymoshenko 	} else if (pe >= PMC_EV_OCTEON_FIRST && pe <= PMC_EV_OCTEON_LAST) {
3418c2657f80SOleksandr Tymoshenko 		ev = octeon_event_table;
3419c2657f80SOleksandr Tymoshenko 		evfence = octeon_event_table + PMC_EVENT_TABLE_SIZE(octeon);
34207b25dccaSJustin Hibbits 	} else if (pe >= PMC_EV_PPC7450_FIRST && pe <= PMC_EV_PPC7450_LAST) {
34217b25dccaSJustin Hibbits 		ev = ppc7450_event_table;
3422f5f9340bSFabien Thomas 		evfence = ppc7450_event_table + PMC_EVENT_TABLE_SIZE(ppc7450);
3423169dd953SJustin Hibbits 	} else if (pe >= PMC_EV_PPC970_FIRST && pe <= PMC_EV_PPC970_LAST) {
3424169dd953SJustin Hibbits 		ev = ppc970_event_table;
3425169dd953SJustin Hibbits 		evfence = ppc970_event_table + PMC_EVENT_TABLE_SIZE(ppc970);
3426789140c0SJoseph Koshy 	} else if (pe == PMC_EV_TSC_TSC) {
3427789140c0SJoseph Koshy 		ev = tsc_event_table;
3428789140c0SJoseph Koshy 		evfence = tsc_event_table + PMC_EVENT_TABLE_SIZE(tsc);
3429f0bbe9aaSDimitry Andric 	} else if ((int)pe >= PMC_EV_SOFT_FIRST && (int)pe <= PMC_EV_SOFT_LAST) {
3430f5f9340bSFabien Thomas 		ev = soft_event_table;
3431f5f9340bSFabien Thomas 		evfence = soft_event_table + soft_event_info.pm_nevent;
3432789140c0SJoseph Koshy 	}
3433789140c0SJoseph Koshy 
3434789140c0SJoseph Koshy 	for (; ev != evfence; ev++)
3435789140c0SJoseph Koshy 		if (pe == ev->pm_ev_code)
3436789140c0SJoseph Koshy 			return (ev->pm_ev_name);
3437f263522aSJoseph Koshy 
34380cfab8ddSJoseph Koshy 	return (NULL);
34390cfab8ddSJoseph Koshy }
34400cfab8ddSJoseph Koshy 
34410cfab8ddSJoseph Koshy const char *
34420cfab8ddSJoseph Koshy pmc_name_of_event(enum pmc_event pe)
34430cfab8ddSJoseph Koshy {
34440cfab8ddSJoseph Koshy 	const char *n;
34450cfab8ddSJoseph Koshy 
34460cfab8ddSJoseph Koshy 	if ((n = _pmc_name_of_event(pe, cpu_info.pm_cputype)) != NULL)
34470cfab8ddSJoseph Koshy 		return (n);
34480cfab8ddSJoseph Koshy 
3449f263522aSJoseph Koshy 	errno = EINVAL;
3450aa342b1fSJoseph Koshy 	return (NULL);
3451f263522aSJoseph Koshy }
3452f263522aSJoseph Koshy 
3453f263522aSJoseph Koshy const char *
3454f263522aSJoseph Koshy pmc_name_of_mode(enum pmc_mode pm)
3455f263522aSJoseph Koshy {
3456f263522aSJoseph Koshy 	if ((int) pm >= PMC_MODE_FIRST &&
3457f263522aSJoseph Koshy 	    pm <= PMC_MODE_LAST)
3458aa342b1fSJoseph Koshy 		return (pmc_mode_names[pm]);
3459f263522aSJoseph Koshy 
3460f263522aSJoseph Koshy 	errno = EINVAL;
3461aa342b1fSJoseph Koshy 	return (NULL);
3462f263522aSJoseph Koshy }
3463f263522aSJoseph Koshy 
3464f263522aSJoseph Koshy const char *
3465f263522aSJoseph Koshy pmc_name_of_state(enum pmc_state ps)
3466f263522aSJoseph Koshy {
3467f263522aSJoseph Koshy 	if ((int) ps >= PMC_STATE_FIRST &&
3468f263522aSJoseph Koshy 	    ps <= PMC_STATE_LAST)
3469aa342b1fSJoseph Koshy 		return (pmc_state_names[ps]);
3470f263522aSJoseph Koshy 
3471f263522aSJoseph Koshy 	errno = EINVAL;
3472aa342b1fSJoseph Koshy 	return (NULL);
3473f263522aSJoseph Koshy }
3474f263522aSJoseph Koshy 
3475f263522aSJoseph Koshy int
3476f263522aSJoseph Koshy pmc_ncpu(void)
3477f263522aSJoseph Koshy {
3478f263522aSJoseph Koshy 	if (pmc_syscall == -1) {
3479f263522aSJoseph Koshy 		errno = ENXIO;
3480aa342b1fSJoseph Koshy 		return (-1);
3481f263522aSJoseph Koshy 	}
3482f263522aSJoseph Koshy 
3483aa342b1fSJoseph Koshy 	return (cpu_info.pm_ncpu);
3484f263522aSJoseph Koshy }
3485f263522aSJoseph Koshy 
3486f263522aSJoseph Koshy int
3487f263522aSJoseph Koshy pmc_npmc(int cpu)
3488f263522aSJoseph Koshy {
3489f263522aSJoseph Koshy 	if (pmc_syscall == -1) {
3490f263522aSJoseph Koshy 		errno = ENXIO;
3491aa342b1fSJoseph Koshy 		return (-1);
3492f263522aSJoseph Koshy 	}
3493f263522aSJoseph Koshy 
3494f263522aSJoseph Koshy 	if (cpu < 0 || cpu >= (int) cpu_info.pm_ncpu) {
3495f263522aSJoseph Koshy 		errno = EINVAL;
3496aa342b1fSJoseph Koshy 		return (-1);
3497f263522aSJoseph Koshy 	}
3498f263522aSJoseph Koshy 
3499aa342b1fSJoseph Koshy 	return (cpu_info.pm_npmc);
3500f263522aSJoseph Koshy }
3501f263522aSJoseph Koshy 
3502f263522aSJoseph Koshy int
3503f263522aSJoseph Koshy pmc_pmcinfo(int cpu, struct pmc_pmcinfo **ppmci)
3504f263522aSJoseph Koshy {
3505f263522aSJoseph Koshy 	int nbytes, npmc;
3506f263522aSJoseph Koshy 	struct pmc_op_getpmcinfo *pmci;
3507f263522aSJoseph Koshy 
3508f263522aSJoseph Koshy 	if ((npmc = pmc_npmc(cpu)) < 0)
3509aa342b1fSJoseph Koshy 		return (-1);
3510f263522aSJoseph Koshy 
3511f263522aSJoseph Koshy 	nbytes = sizeof(struct pmc_op_getpmcinfo) +
3512f263522aSJoseph Koshy 	    npmc * sizeof(struct pmc_info);
3513f263522aSJoseph Koshy 
3514f263522aSJoseph Koshy 	if ((pmci = calloc(1, nbytes)) == NULL)
3515aa342b1fSJoseph Koshy 		return (-1);
3516f263522aSJoseph Koshy 
3517f263522aSJoseph Koshy 	pmci->pm_cpu  = cpu;
3518f263522aSJoseph Koshy 
3519f263522aSJoseph Koshy 	if (PMC_CALL(GETPMCINFO, pmci) < 0) {
3520f263522aSJoseph Koshy 		free(pmci);
3521aa342b1fSJoseph Koshy 		return (-1);
3522f263522aSJoseph Koshy 	}
3523f263522aSJoseph Koshy 
3524f263522aSJoseph Koshy 	/* kernel<->library, library<->userland interfaces are identical */
3525f263522aSJoseph Koshy 	*ppmci = (struct pmc_pmcinfo *) pmci;
3526aa342b1fSJoseph Koshy 	return (0);
3527f263522aSJoseph Koshy }
3528f263522aSJoseph Koshy 
3529f263522aSJoseph Koshy int
3530f263522aSJoseph Koshy pmc_read(pmc_id_t pmc, pmc_value_t *value)
3531f263522aSJoseph Koshy {
3532f263522aSJoseph Koshy 	struct pmc_op_pmcrw pmc_read_op;
3533f263522aSJoseph Koshy 
3534f263522aSJoseph Koshy 	pmc_read_op.pm_pmcid = pmc;
3535f263522aSJoseph Koshy 	pmc_read_op.pm_flags = PMC_F_OLDVALUE;
3536f263522aSJoseph Koshy 	pmc_read_op.pm_value = -1;
3537f263522aSJoseph Koshy 
3538f263522aSJoseph Koshy 	if (PMC_CALL(PMCRW, &pmc_read_op) < 0)
3539aa342b1fSJoseph Koshy 		return (-1);
3540f263522aSJoseph Koshy 
3541f263522aSJoseph Koshy 	*value = pmc_read_op.pm_value;
3542aa342b1fSJoseph Koshy 	return (0);
3543f263522aSJoseph Koshy }
3544f263522aSJoseph Koshy 
3545f263522aSJoseph Koshy int
3546f263522aSJoseph Koshy pmc_release(pmc_id_t pmc)
3547f263522aSJoseph Koshy {
3548f263522aSJoseph Koshy 	struct pmc_op_simple	pmc_release_args;
3549f263522aSJoseph Koshy 
3550f263522aSJoseph Koshy 	pmc_release_args.pm_pmcid = pmc;
3551aa342b1fSJoseph Koshy 	return (PMC_CALL(PMCRELEASE, &pmc_release_args));
3552f263522aSJoseph Koshy }
3553f263522aSJoseph Koshy 
3554f263522aSJoseph Koshy int
3555f263522aSJoseph Koshy pmc_rw(pmc_id_t pmc, pmc_value_t newvalue, pmc_value_t *oldvaluep)
3556f263522aSJoseph Koshy {
3557f263522aSJoseph Koshy 	struct pmc_op_pmcrw pmc_rw_op;
3558f263522aSJoseph Koshy 
3559f263522aSJoseph Koshy 	pmc_rw_op.pm_pmcid = pmc;
3560f263522aSJoseph Koshy 	pmc_rw_op.pm_flags = PMC_F_NEWVALUE | PMC_F_OLDVALUE;
3561f263522aSJoseph Koshy 	pmc_rw_op.pm_value = newvalue;
3562f263522aSJoseph Koshy 
3563f263522aSJoseph Koshy 	if (PMC_CALL(PMCRW, &pmc_rw_op) < 0)
3564aa342b1fSJoseph Koshy 		return (-1);
3565f263522aSJoseph Koshy 
3566f263522aSJoseph Koshy 	*oldvaluep = pmc_rw_op.pm_value;
3567aa342b1fSJoseph Koshy 	return (0);
3568f263522aSJoseph Koshy }
3569f263522aSJoseph Koshy 
3570f263522aSJoseph Koshy int
3571f263522aSJoseph Koshy pmc_set(pmc_id_t pmc, pmc_value_t value)
3572f263522aSJoseph Koshy {
3573f263522aSJoseph Koshy 	struct pmc_op_pmcsetcount sc;
3574f263522aSJoseph Koshy 
3575f263522aSJoseph Koshy 	sc.pm_pmcid = pmc;
3576f263522aSJoseph Koshy 	sc.pm_count = value;
3577f263522aSJoseph Koshy 
3578f263522aSJoseph Koshy 	if (PMC_CALL(PMCSETCOUNT, &sc) < 0)
3579aa342b1fSJoseph Koshy 		return (-1);
3580aa342b1fSJoseph Koshy 	return (0);
3581f263522aSJoseph Koshy }
3582f263522aSJoseph Koshy 
3583f263522aSJoseph Koshy int
3584f263522aSJoseph Koshy pmc_start(pmc_id_t pmc)
3585f263522aSJoseph Koshy {
3586f263522aSJoseph Koshy 	struct pmc_op_simple	pmc_start_args;
3587f263522aSJoseph Koshy 
3588f263522aSJoseph Koshy 	pmc_start_args.pm_pmcid = pmc;
3589aa342b1fSJoseph Koshy 	return (PMC_CALL(PMCSTART, &pmc_start_args));
3590f263522aSJoseph Koshy }
3591f263522aSJoseph Koshy 
3592f263522aSJoseph Koshy int
3593f263522aSJoseph Koshy pmc_stop(pmc_id_t pmc)
3594f263522aSJoseph Koshy {
3595f263522aSJoseph Koshy 	struct pmc_op_simple	pmc_stop_args;
3596f263522aSJoseph Koshy 
3597f263522aSJoseph Koshy 	pmc_stop_args.pm_pmcid = pmc;
3598aa342b1fSJoseph Koshy 	return (PMC_CALL(PMCSTOP, &pmc_stop_args));
3599f263522aSJoseph Koshy }
3600f263522aSJoseph Koshy 
3601f263522aSJoseph Koshy int
3602f263522aSJoseph Koshy pmc_width(pmc_id_t pmcid, uint32_t *width)
3603f263522aSJoseph Koshy {
3604f263522aSJoseph Koshy 	unsigned int i;
3605f263522aSJoseph Koshy 	enum pmc_class cl;
3606f263522aSJoseph Koshy 
3607f263522aSJoseph Koshy 	cl = PMC_ID_TO_CLASS(pmcid);
3608f263522aSJoseph Koshy 	for (i = 0; i < cpu_info.pm_nclass; i++)
3609f263522aSJoseph Koshy 		if (cpu_info.pm_classes[i].pm_class == cl) {
3610f263522aSJoseph Koshy 			*width = cpu_info.pm_classes[i].pm_width;
3611aa342b1fSJoseph Koshy 			return (0);
3612f263522aSJoseph Koshy 		}
3613484202faSJoseph Koshy 	errno = EINVAL;
3614484202faSJoseph Koshy 	return (-1);
3615f263522aSJoseph Koshy }
3616f263522aSJoseph Koshy 
3617f263522aSJoseph Koshy int
3618f263522aSJoseph Koshy pmc_write(pmc_id_t pmc, pmc_value_t value)
3619f263522aSJoseph Koshy {
3620f263522aSJoseph Koshy 	struct pmc_op_pmcrw pmc_write_op;
3621f263522aSJoseph Koshy 
3622f263522aSJoseph Koshy 	pmc_write_op.pm_pmcid = pmc;
3623f263522aSJoseph Koshy 	pmc_write_op.pm_flags = PMC_F_NEWVALUE;
3624f263522aSJoseph Koshy 	pmc_write_op.pm_value = value;
3625aa342b1fSJoseph Koshy 	return (PMC_CALL(PMCRW, &pmc_write_op));
3626f263522aSJoseph Koshy }
3627f263522aSJoseph Koshy 
3628f263522aSJoseph Koshy int
3629f263522aSJoseph Koshy pmc_writelog(uint32_t userdata)
3630f263522aSJoseph Koshy {
3631f263522aSJoseph Koshy 	struct pmc_op_writelog wl;
3632f263522aSJoseph Koshy 
3633f263522aSJoseph Koshy 	wl.pm_userdata = userdata;
3634aa342b1fSJoseph Koshy 	return (PMC_CALL(WRITELOG, &wl));
3635f263522aSJoseph Koshy }
3636