xref: /freebsd/lib/libpmc/libpmc.c (revision 789140c0e714ee2a1c33d1d76d3c577eb1e4e393)
1ebccf1e3SJoseph Koshy /*-
2484202faSJoseph Koshy  * Copyright (c) 2003-2008 Joseph Koshy
3ebccf1e3SJoseph Koshy  * All rights reserved.
4ebccf1e3SJoseph Koshy  *
5ebccf1e3SJoseph Koshy  * Redistribution and use in source and binary forms, with or without
6ebccf1e3SJoseph Koshy  * modification, are permitted provided that the following conditions
7ebccf1e3SJoseph Koshy  * are met:
8ebccf1e3SJoseph Koshy  * 1. Redistributions of source code must retain the above copyright
9ebccf1e3SJoseph Koshy  *    notice, this list of conditions and the following disclaimer.
10ebccf1e3SJoseph Koshy  * 2. Redistributions in binary form must reproduce the above copyright
11ebccf1e3SJoseph Koshy  *    notice, this list of conditions and the following disclaimer in the
12ebccf1e3SJoseph Koshy  *    documentation and/or other materials provided with the distribution.
13ebccf1e3SJoseph Koshy  *
14ebccf1e3SJoseph Koshy  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15ebccf1e3SJoseph Koshy  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16ebccf1e3SJoseph Koshy  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17ebccf1e3SJoseph Koshy  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18ebccf1e3SJoseph Koshy  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19ebccf1e3SJoseph Koshy  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20ebccf1e3SJoseph Koshy  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21ebccf1e3SJoseph Koshy  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22ebccf1e3SJoseph Koshy  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23ebccf1e3SJoseph Koshy  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24ebccf1e3SJoseph Koshy  * SUCH DAMAGE.
25ebccf1e3SJoseph Koshy  */
26ebccf1e3SJoseph Koshy 
27ebccf1e3SJoseph Koshy #include <sys/cdefs.h>
28ebccf1e3SJoseph Koshy __FBSDID("$FreeBSD$");
29ebccf1e3SJoseph Koshy 
30ebccf1e3SJoseph Koshy #include <sys/types.h>
31ebccf1e3SJoseph Koshy #include <sys/module.h>
32ebccf1e3SJoseph Koshy #include <sys/pmc.h>
33ebccf1e3SJoseph Koshy #include <sys/syscall.h>
34ebccf1e3SJoseph Koshy 
35ebccf1e3SJoseph Koshy #include <ctype.h>
36ebccf1e3SJoseph Koshy #include <errno.h>
37ebccf1e3SJoseph Koshy #include <fcntl.h>
38ebccf1e3SJoseph Koshy #include <pmc.h>
39ebccf1e3SJoseph Koshy #include <stdio.h>
40ebccf1e3SJoseph Koshy #include <stdlib.h>
41ebccf1e3SJoseph Koshy #include <string.h>
42ebccf1e3SJoseph Koshy #include <strings.h>
43ebccf1e3SJoseph Koshy #include <unistd.h>
44ebccf1e3SJoseph Koshy 
45ebccf1e3SJoseph Koshy /* Function prototypes */
4604e9feb0SMarcel Moolenaar #if defined(__i386__)
47ebccf1e3SJoseph Koshy static int k7_allocate_pmc(enum pmc_event _pe, char *_ctrspec,
48ebccf1e3SJoseph Koshy     struct pmc_op_pmcallocate *_pmc_config);
49f263522aSJoseph Koshy #endif
5086a65549SJoseph Koshy #if defined(__amd64__) || defined(__i386__)
51f263522aSJoseph Koshy static int k8_allocate_pmc(enum pmc_event _pe, char *_ctrspec,
52ebccf1e3SJoseph Koshy     struct pmc_op_pmcallocate *_pmc_config);
5386a65549SJoseph Koshy static int p4_allocate_pmc(enum pmc_event _pe, char *_ctrspec,
5486a65549SJoseph Koshy     struct pmc_op_pmcallocate *_pmc_config);
55f263522aSJoseph Koshy #endif
56f263522aSJoseph Koshy #if defined(__i386__)
57ebccf1e3SJoseph Koshy static int p5_allocate_pmc(enum pmc_event _pe, char *_ctrspec,
58ebccf1e3SJoseph Koshy     struct pmc_op_pmcallocate *_pmc_config);
59f263522aSJoseph Koshy static int p6_allocate_pmc(enum pmc_event _pe, char *_ctrspec,
60ebccf1e3SJoseph Koshy     struct pmc_op_pmcallocate *_pmc_config);
61ebccf1e3SJoseph Koshy #endif
62789140c0SJoseph Koshy #if defined(__amd64__) || defined(__i386__)
63789140c0SJoseph Koshy static int tsc_allocate_pmc(enum pmc_event _pe, char *_ctrspec,
64789140c0SJoseph Koshy     struct pmc_op_pmcallocate *_pmc_config);
65789140c0SJoseph Koshy #endif
66ebccf1e3SJoseph Koshy 
67ebccf1e3SJoseph Koshy #define PMC_CALL(cmd, params)				\
68ebccf1e3SJoseph Koshy 	syscall(pmc_syscall, PMC_OP_##cmd, (params))
69ebccf1e3SJoseph Koshy 
70ebccf1e3SJoseph Koshy /*
71ebccf1e3SJoseph Koshy  * Event aliases provide a way for the user to ask for generic events
72ebccf1e3SJoseph Koshy  * like "cache-misses", or "instructions-retired".  These aliases are
73ebccf1e3SJoseph Koshy  * mapped to the appropriate canonical event descriptions using a
74ebccf1e3SJoseph Koshy  * lookup table.
75ebccf1e3SJoseph Koshy  */
76ebccf1e3SJoseph Koshy struct pmc_event_alias {
77ebccf1e3SJoseph Koshy 	const char	*pm_alias;
78ebccf1e3SJoseph Koshy 	const char	*pm_spec;
79ebccf1e3SJoseph Koshy };
80ebccf1e3SJoseph Koshy 
81ebccf1e3SJoseph Koshy static const struct pmc_event_alias *pmc_mdep_event_aliases;
82ebccf1e3SJoseph Koshy 
83ebccf1e3SJoseph Koshy /*
84789140c0SJoseph Koshy  * The pmc_event_descr structure maps symbolic names known to the user
85ebccf1e3SJoseph Koshy  * to integer codes used by the PMC KLD.
86ebccf1e3SJoseph Koshy  */
87ebccf1e3SJoseph Koshy struct pmc_event_descr {
88ebccf1e3SJoseph Koshy 	const char	*pm_ev_name;
89ebccf1e3SJoseph Koshy 	enum pmc_event	pm_ev_code;
90ebccf1e3SJoseph Koshy };
91ebccf1e3SJoseph Koshy 
92789140c0SJoseph Koshy /*
93789140c0SJoseph Koshy  * The pmc_class_descr structure maps class name prefixes for
94789140c0SJoseph Koshy  * event names to event tables and other PMC class data.
95789140c0SJoseph Koshy  */
96789140c0SJoseph Koshy struct pmc_class_descr {
97789140c0SJoseph Koshy 	const char	*pm_evc_name;
98789140c0SJoseph Koshy 	size_t		pm_evc_name_size;
99789140c0SJoseph Koshy 	enum pmc_class	pm_evc_class;
100789140c0SJoseph Koshy 	const struct pmc_event_descr *pm_evc_event_table;
101789140c0SJoseph Koshy 	size_t		pm_evc_event_table_size;
102789140c0SJoseph Koshy 	int		(*pm_evc_allocate_pmc)(enum pmc_event _pe,
103789140c0SJoseph Koshy 			    char *_ctrspec, struct pmc_op_pmcallocate *_pa);
104ebccf1e3SJoseph Koshy };
105ebccf1e3SJoseph Koshy 
106789140c0SJoseph Koshy #define	PMC_TABLE_SIZE(N)	(sizeof(N)/sizeof(N[0]))
107789140c0SJoseph Koshy #define	PMC_EVENT_TABLE_SIZE(N)	PMC_TABLE_SIZE(N##_event_table)
108789140c0SJoseph Koshy 
109789140c0SJoseph Koshy #undef	__PMC_EV
110789140c0SJoseph Koshy #define	__PMC_EV(C,N) { #N, PMC_EV_ ## C ## _ ## N },
111789140c0SJoseph Koshy 
112789140c0SJoseph Koshy /*
113789140c0SJoseph Koshy  * PMC_MDEP_TABLE(NAME, CLASS, ADDITIONAL_CLASSES...)
114789140c0SJoseph Koshy  *
115789140c0SJoseph Koshy  * Build an event descriptor table and a list of valid PMC classes.
116789140c0SJoseph Koshy  */
117789140c0SJoseph Koshy #define	PMC_MDEP_TABLE(N,C,...)				\
118789140c0SJoseph Koshy 	static const struct pmc_event_descr N##_event_table[] =	\
119789140c0SJoseph Koshy 	{							\
120789140c0SJoseph Koshy 		__PMC_EV_##C()					\
121789140c0SJoseph Koshy 	};							\
122789140c0SJoseph Koshy 	static const enum pmc_class N##_pmc_classes[] = {	\
123789140c0SJoseph Koshy 		PMC_CLASS_##C, __VA_ARGS__			\
124789140c0SJoseph Koshy 	}
125789140c0SJoseph Koshy 
126789140c0SJoseph Koshy PMC_MDEP_TABLE(k7, K7, PMC_CLASS_TSC);
127789140c0SJoseph Koshy PMC_MDEP_TABLE(k8, K8, PMC_CLASS_TSC);
128789140c0SJoseph Koshy PMC_MDEP_TABLE(p4, P4, PMC_CLASS_TSC);
129789140c0SJoseph Koshy PMC_MDEP_TABLE(p5, P5, PMC_CLASS_TSC);
130789140c0SJoseph Koshy PMC_MDEP_TABLE(p6, P6, PMC_CLASS_TSC);
131789140c0SJoseph Koshy 
132789140c0SJoseph Koshy static const struct pmc_event_descr tsc_event_table[] =
133789140c0SJoseph Koshy {
134789140c0SJoseph Koshy 	__PMC_EV_TSC()
135789140c0SJoseph Koshy };
136789140c0SJoseph Koshy 
137789140c0SJoseph Koshy #undef	PMC_CLASS_TABLE_DESC
138789140c0SJoseph Koshy #define	PMC_CLASS_TABLE_DESC(N, C)	{			\
139789140c0SJoseph Koshy 		.pm_evc_name  = #N "-",				\
140789140c0SJoseph Koshy 		.pm_evc_name_size = sizeof(#N "-") - 1,		\
141789140c0SJoseph Koshy 		.pm_evc_class = PMC_CLASS_##C ,			\
142789140c0SJoseph Koshy 		.pm_evc_event_table = N##_event_table ,		\
143789140c0SJoseph Koshy 		.pm_evc_event_table_size = 			\
144789140c0SJoseph Koshy 			PMC_EVENT_TABLE_SIZE(N),		\
145789140c0SJoseph Koshy 		.pm_evc_allocate_pmc = N##_allocate_pmc		\
146789140c0SJoseph Koshy 	}
147789140c0SJoseph Koshy 
148789140c0SJoseph Koshy static const struct pmc_class_descr pmc_class_table[] =
149789140c0SJoseph Koshy {
150789140c0SJoseph Koshy #if	defined(__i386__)
151789140c0SJoseph Koshy 	PMC_CLASS_TABLE_DESC(k7, K7),
152789140c0SJoseph Koshy #endif
153789140c0SJoseph Koshy #if	defined(__i386__) || defined(__amd64__)
154789140c0SJoseph Koshy 	PMC_CLASS_TABLE_DESC(k8, K8),
155789140c0SJoseph Koshy 	PMC_CLASS_TABLE_DESC(p4, P4),
156789140c0SJoseph Koshy #endif
157789140c0SJoseph Koshy #if	defined(__i386__)
158789140c0SJoseph Koshy 	PMC_CLASS_TABLE_DESC(p5, P5),
159789140c0SJoseph Koshy 	PMC_CLASS_TABLE_DESC(p6, P6),
160789140c0SJoseph Koshy #endif
161789140c0SJoseph Koshy #if	defined(__i386__) || defined(__amd64__)
162789140c0SJoseph Koshy 	PMC_CLASS_TABLE_DESC(tsc, TSC)
163789140c0SJoseph Koshy #endif
164789140c0SJoseph Koshy };
165789140c0SJoseph Koshy 
166789140c0SJoseph Koshy static size_t pmc_event_class_table_size =
167789140c0SJoseph Koshy     PMC_TABLE_SIZE(pmc_class_table);
168789140c0SJoseph Koshy 
169789140c0SJoseph Koshy #undef	PMC_CLASS_TABLE_DESC
170789140c0SJoseph Koshy 
171789140c0SJoseph Koshy static const enum pmc_class *pmc_mdep_class_list;
172789140c0SJoseph Koshy static size_t pmc_mdep_class_list_size;
173789140c0SJoseph Koshy 
174ebccf1e3SJoseph Koshy /*
175ebccf1e3SJoseph Koshy  * Mapping tables, mapping enumeration values to human readable
176ebccf1e3SJoseph Koshy  * strings.
177ebccf1e3SJoseph Koshy  */
178ebccf1e3SJoseph Koshy 
179ebccf1e3SJoseph Koshy static const char * pmc_capability_names[] = {
180ebccf1e3SJoseph Koshy #undef	__PMC_CAP
181ebccf1e3SJoseph Koshy #define	__PMC_CAP(N,V,D)	#N ,
182ebccf1e3SJoseph Koshy 	__PMC_CAPS()
183ebccf1e3SJoseph Koshy };
184ebccf1e3SJoseph Koshy 
185ebccf1e3SJoseph Koshy static const char * pmc_class_names[] = {
186ebccf1e3SJoseph Koshy #undef	__PMC_CLASS
187ebccf1e3SJoseph Koshy #define __PMC_CLASS(C)	#C ,
188ebccf1e3SJoseph Koshy 	__PMC_CLASSES()
189ebccf1e3SJoseph Koshy };
190ebccf1e3SJoseph Koshy 
191789140c0SJoseph Koshy struct pmc_cputype_map {
192789140c0SJoseph Koshy 	enum pmc_class	pm_cputype;
193789140c0SJoseph Koshy 	const char	*pm_name;
194789140c0SJoseph Koshy };
195789140c0SJoseph Koshy 
196789140c0SJoseph Koshy static const struct pmc_cputype_map pmc_cputype_names[] = {
197ebccf1e3SJoseph Koshy #undef	__PMC_CPU
198789140c0SJoseph Koshy #define	__PMC_CPU(S, V, D) { .pm_cputype = PMC_CPU_##S, .pm_name = #S } ,
199ebccf1e3SJoseph Koshy 	__PMC_CPUS()
200ebccf1e3SJoseph Koshy };
201ebccf1e3SJoseph Koshy 
202ebccf1e3SJoseph Koshy static const char * pmc_disposition_names[] = {
203ebccf1e3SJoseph Koshy #undef	__PMC_DISP
204ebccf1e3SJoseph Koshy #define	__PMC_DISP(D)	#D ,
205ebccf1e3SJoseph Koshy 	__PMC_DISPOSITIONS()
206ebccf1e3SJoseph Koshy };
207ebccf1e3SJoseph Koshy 
208ebccf1e3SJoseph Koshy static const char * pmc_mode_names[] = {
209ebccf1e3SJoseph Koshy #undef  __PMC_MODE
210ebccf1e3SJoseph Koshy #define __PMC_MODE(M,N)	#M ,
211ebccf1e3SJoseph Koshy 	__PMC_MODES()
212ebccf1e3SJoseph Koshy };
213ebccf1e3SJoseph Koshy 
214ebccf1e3SJoseph Koshy static const char * pmc_state_names[] = {
215ebccf1e3SJoseph Koshy #undef  __PMC_STATE
216ebccf1e3SJoseph Koshy #define __PMC_STATE(S) #S ,
217ebccf1e3SJoseph Koshy 	__PMC_STATES()
218ebccf1e3SJoseph Koshy };
219ebccf1e3SJoseph Koshy 
220ebccf1e3SJoseph Koshy static int pmc_syscall = -1;		/* filled in by pmc_init() */
221ebccf1e3SJoseph Koshy 
2221455fcd3SJoseph Koshy static struct pmc_cpuinfo cpu_info;	/* filled in by pmc_init() */
2231455fcd3SJoseph Koshy 
224ebccf1e3SJoseph Koshy /* Event masks for events */
225ebccf1e3SJoseph Koshy struct pmc_masks {
226ebccf1e3SJoseph Koshy 	const char	*pm_name;
227ebccf1e3SJoseph Koshy 	const uint32_t	pm_value;
228ebccf1e3SJoseph Koshy };
229ebccf1e3SJoseph Koshy #define	PMCMASK(N,V)	{ .pm_name = #N, .pm_value = (V) }
230ebccf1e3SJoseph Koshy #define	NULLMASK	PMCMASK(NULL,0)
231ebccf1e3SJoseph Koshy 
23286a65549SJoseph Koshy #if defined(__amd64__) || defined(__i386__)
233ebccf1e3SJoseph Koshy static int
234ebccf1e3SJoseph Koshy pmc_parse_mask(const struct pmc_masks *pmask, char *p, uint32_t *evmask)
235ebccf1e3SJoseph Koshy {
236ebccf1e3SJoseph Koshy 	const struct pmc_masks *pm;
237ebccf1e3SJoseph Koshy 	char *q, *r;
238ebccf1e3SJoseph Koshy 	int c;
239ebccf1e3SJoseph Koshy 
240ebccf1e3SJoseph Koshy 	if (pmask == NULL)	/* no mask keywords */
241aa342b1fSJoseph Koshy 		return (-1);
242ebccf1e3SJoseph Koshy 	q = strchr(p, '=');	/* skip '=' */
243ebccf1e3SJoseph Koshy 	if (*++q == '\0')	/* no more data */
244aa342b1fSJoseph Koshy 		return (-1);
245ebccf1e3SJoseph Koshy 	c = 0;			/* count of mask keywords seen */
246ebccf1e3SJoseph Koshy 	while ((r = strsep(&q, "+")) != NULL) {
247789140c0SJoseph Koshy 		for (pm = pmask; pm->pm_name && strcasecmp(r, pm->pm_name);
248789140c0SJoseph Koshy 		    pm++)
249ebccf1e3SJoseph Koshy 			;
250ebccf1e3SJoseph Koshy 		if (pm->pm_name == NULL) /* not found */
251aa342b1fSJoseph Koshy 			return (-1);
252ebccf1e3SJoseph Koshy 		*evmask |= pm->pm_value;
253ebccf1e3SJoseph Koshy 		c++;
254ebccf1e3SJoseph Koshy 	}
255aa342b1fSJoseph Koshy 	return (c);
256ebccf1e3SJoseph Koshy }
25704e9feb0SMarcel Moolenaar #endif
258ebccf1e3SJoseph Koshy 
259ebccf1e3SJoseph Koshy #define	KWMATCH(p,kw)		(strcasecmp((p), (kw)) == 0)
260ebccf1e3SJoseph Koshy #define	KWPREFIXMATCH(p,kw)	(strncasecmp((p), (kw), sizeof((kw)) - 1) == 0)
261ebccf1e3SJoseph Koshy #define	EV_ALIAS(N,S)		{ .pm_alias = N, .pm_spec = S }
262ebccf1e3SJoseph Koshy 
26304e9feb0SMarcel Moolenaar #if defined(__i386__)
264ebccf1e3SJoseph Koshy 
265ebccf1e3SJoseph Koshy /*
266ebccf1e3SJoseph Koshy  * AMD K7 (Athlon) CPUs.
267ebccf1e3SJoseph Koshy  */
268ebccf1e3SJoseph Koshy 
269ebccf1e3SJoseph Koshy static struct pmc_event_alias k7_aliases[] = {
270ebccf1e3SJoseph Koshy 	EV_ALIAS("branches",		"k7-retired-branches"),
271ebccf1e3SJoseph Koshy 	EV_ALIAS("branch-mispredicts",	"k7-retired-branches-mispredicted"),
272ebccf1e3SJoseph Koshy 	EV_ALIAS("cycles",		"tsc"),
2736aa5a193SJoseph Koshy 	EV_ALIAS("dc-misses",		"k7-dc-misses"),
274ebccf1e3SJoseph Koshy 	EV_ALIAS("ic-misses",		"k7-ic-misses"),
275ebccf1e3SJoseph Koshy 	EV_ALIAS("instructions",	"k7-retired-instructions"),
276ebccf1e3SJoseph Koshy 	EV_ALIAS("interrupts",		"k7-hardware-interrupts"),
277ebccf1e3SJoseph Koshy 	EV_ALIAS(NULL, NULL)
278ebccf1e3SJoseph Koshy };
279ebccf1e3SJoseph Koshy 
280ebccf1e3SJoseph Koshy #define	K7_KW_COUNT	"count"
281ebccf1e3SJoseph Koshy #define	K7_KW_EDGE	"edge"
282ebccf1e3SJoseph Koshy #define	K7_KW_INV	"inv"
283ebccf1e3SJoseph Koshy #define	K7_KW_OS	"os"
284ebccf1e3SJoseph Koshy #define	K7_KW_UNITMASK	"unitmask"
285ebccf1e3SJoseph Koshy #define	K7_KW_USR	"usr"
286ebccf1e3SJoseph Koshy 
287ebccf1e3SJoseph Koshy static int
288ebccf1e3SJoseph Koshy k7_allocate_pmc(enum pmc_event pe, char *ctrspec,
289ebccf1e3SJoseph Koshy     struct pmc_op_pmcallocate *pmc_config)
290ebccf1e3SJoseph Koshy {
291ebccf1e3SJoseph Koshy 	char		*e, *p, *q;
292ebccf1e3SJoseph Koshy 	int		c, has_unitmask;
293ebccf1e3SJoseph Koshy 	uint32_t	count, unitmask;
294ebccf1e3SJoseph Koshy 
295f263522aSJoseph Koshy 	pmc_config->pm_md.pm_amd.pm_amd_config = 0;
296789140c0SJoseph Koshy 	pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE);
297ebccf1e3SJoseph Koshy 
298ebccf1e3SJoseph Koshy 	if (pe == PMC_EV_K7_DC_REFILLS_FROM_L2 ||
299ebccf1e3SJoseph Koshy 	    pe == PMC_EV_K7_DC_REFILLS_FROM_SYSTEM ||
300ebccf1e3SJoseph Koshy 	    pe == PMC_EV_K7_DC_WRITEBACKS) {
301ebccf1e3SJoseph Koshy 		has_unitmask = 1;
302f263522aSJoseph Koshy 		unitmask = AMD_PMC_UNITMASK_MOESI;
303ebccf1e3SJoseph Koshy 	} else
304ebccf1e3SJoseph Koshy 		unitmask = has_unitmask = 0;
305ebccf1e3SJoseph Koshy 
306ebccf1e3SJoseph Koshy 	while ((p = strsep(&ctrspec, ",")) != NULL) {
307ebccf1e3SJoseph Koshy 		if (KWPREFIXMATCH(p, K7_KW_COUNT "=")) {
308ebccf1e3SJoseph Koshy 			q = strchr(p, '=');
309ebccf1e3SJoseph Koshy 			if (*++q == '\0') /* skip '=' */
310aa342b1fSJoseph Koshy 				return (-1);
311ebccf1e3SJoseph Koshy 
312ebccf1e3SJoseph Koshy 			count = strtol(q, &e, 0);
313ebccf1e3SJoseph Koshy 			if (e == q || *e != '\0')
314aa342b1fSJoseph Koshy 				return (-1);
315ebccf1e3SJoseph Koshy 
316ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_THRESHOLD;
317f263522aSJoseph Koshy 			pmc_config->pm_md.pm_amd.pm_amd_config |=
318f263522aSJoseph Koshy 			    AMD_PMC_TO_COUNTER(count);
319ebccf1e3SJoseph Koshy 
320ebccf1e3SJoseph Koshy 		} else if (KWMATCH(p, K7_KW_EDGE)) {
321ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_EDGE;
322ebccf1e3SJoseph Koshy 		} else if (KWMATCH(p, K7_KW_INV)) {
323ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_INVERT;
324ebccf1e3SJoseph Koshy 		} else if (KWMATCH(p, K7_KW_OS)) {
325ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_SYSTEM;
326ebccf1e3SJoseph Koshy 		} else if (KWPREFIXMATCH(p, K7_KW_UNITMASK "=")) {
327ebccf1e3SJoseph Koshy 			if (has_unitmask == 0)
328aa342b1fSJoseph Koshy 				return (-1);
329ebccf1e3SJoseph Koshy 			unitmask = 0;
330ebccf1e3SJoseph Koshy 			q = strchr(p, '=');
331ebccf1e3SJoseph Koshy 			if (*++q == '\0') /* skip '=' */
332aa342b1fSJoseph Koshy 				return (-1);
333ebccf1e3SJoseph Koshy 
334ebccf1e3SJoseph Koshy 			while ((c = tolower(*q++)) != 0)
335ebccf1e3SJoseph Koshy 				if (c == 'm')
336f263522aSJoseph Koshy 					unitmask |= AMD_PMC_UNITMASK_M;
337ebccf1e3SJoseph Koshy 				else if (c == 'o')
338f263522aSJoseph Koshy 					unitmask |= AMD_PMC_UNITMASK_O;
339ebccf1e3SJoseph Koshy 				else if (c == 'e')
340f263522aSJoseph Koshy 					unitmask |= AMD_PMC_UNITMASK_E;
341ebccf1e3SJoseph Koshy 				else if (c == 's')
342f263522aSJoseph Koshy 					unitmask |= AMD_PMC_UNITMASK_S;
343ebccf1e3SJoseph Koshy 				else if (c == 'i')
344f263522aSJoseph Koshy 					unitmask |= AMD_PMC_UNITMASK_I;
345ebccf1e3SJoseph Koshy 				else if (c == '+')
346ebccf1e3SJoseph Koshy 					continue;
347ebccf1e3SJoseph Koshy 				else
348aa342b1fSJoseph Koshy 					return (-1);
349ebccf1e3SJoseph Koshy 
350ebccf1e3SJoseph Koshy 			if (unitmask == 0)
351aa342b1fSJoseph Koshy 				return (-1);
352ebccf1e3SJoseph Koshy 
353ebccf1e3SJoseph Koshy 		} else if (KWMATCH(p, K7_KW_USR)) {
354ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_USER;
355ebccf1e3SJoseph Koshy 		} else
356aa342b1fSJoseph Koshy 			return (-1);
357ebccf1e3SJoseph Koshy 	}
358ebccf1e3SJoseph Koshy 
359ebccf1e3SJoseph Koshy 	if (has_unitmask) {
360ebccf1e3SJoseph Koshy 		pmc_config->pm_caps |= PMC_CAP_QUALIFIER;
361f263522aSJoseph Koshy 		pmc_config->pm_md.pm_amd.pm_amd_config |=
362f263522aSJoseph Koshy 		    AMD_PMC_TO_UNITMASK(unitmask);
363ebccf1e3SJoseph Koshy 	}
364ebccf1e3SJoseph Koshy 
365aa342b1fSJoseph Koshy 	return (0);
366ebccf1e3SJoseph Koshy 
367ebccf1e3SJoseph Koshy }
368ebccf1e3SJoseph Koshy 
369f263522aSJoseph Koshy #endif
370f263522aSJoseph Koshy 
37186a65549SJoseph Koshy #if defined(__amd64__) || defined(__i386__)
372f263522aSJoseph Koshy 
373f263522aSJoseph Koshy /*
374f263522aSJoseph Koshy  * AMD K8 PMCs.
375f263522aSJoseph Koshy  *
376f263522aSJoseph Koshy  * These are very similar to AMD K7 PMCs, but support more kinds of
377f263522aSJoseph Koshy  * events.
378f263522aSJoseph Koshy  */
379f263522aSJoseph Koshy 
380f263522aSJoseph Koshy static struct pmc_event_alias k8_aliases[] = {
381f263522aSJoseph Koshy 	EV_ALIAS("branches",		"k8-fr-retired-taken-branches"),
382f263522aSJoseph Koshy 	EV_ALIAS("branch-mispredicts",
383f263522aSJoseph Koshy 	    "k8-fr-retired-taken-branches-mispredicted"),
384f263522aSJoseph Koshy 	EV_ALIAS("cycles",		"tsc"),
385f263522aSJoseph Koshy 	EV_ALIAS("dc-misses",		"k8-dc-miss"),
386f263522aSJoseph Koshy 	EV_ALIAS("ic-misses",		"k8-ic-miss"),
387f263522aSJoseph Koshy 	EV_ALIAS("instructions",	"k8-fr-retired-x86-instructions"),
388f263522aSJoseph Koshy 	EV_ALIAS("interrupts",		"k8-fr-taken-hardware-interrupts"),
389177a2f22SJoseph Koshy 	EV_ALIAS("unhalted-cycles",	"k8-bu-cpu-clk-unhalted"),
390f263522aSJoseph Koshy 	EV_ALIAS(NULL, NULL)
391f263522aSJoseph Koshy };
392f263522aSJoseph Koshy 
393f263522aSJoseph Koshy #define	__K8MASK(N,V) PMCMASK(N,(1 << (V)))
394f263522aSJoseph Koshy 
395f263522aSJoseph Koshy /*
396f263522aSJoseph Koshy  * Parsing tables
397f263522aSJoseph Koshy  */
398f263522aSJoseph Koshy 
399f263522aSJoseph Koshy /* fp dispatched fpu ops */
400f263522aSJoseph Koshy static const struct pmc_masks k8_mask_fdfo[] = {
401f263522aSJoseph Koshy 	__K8MASK(add-pipe-excluding-junk-ops,	0),
402f263522aSJoseph Koshy 	__K8MASK(multiply-pipe-excluding-junk-ops,	1),
403f263522aSJoseph Koshy 	__K8MASK(store-pipe-excluding-junk-ops,	2),
404f263522aSJoseph Koshy 	__K8MASK(add-pipe-junk-ops,		3),
405f263522aSJoseph Koshy 	__K8MASK(multiply-pipe-junk-ops,	4),
406f263522aSJoseph Koshy 	__K8MASK(store-pipe-junk-ops,		5),
407f263522aSJoseph Koshy 	NULLMASK
408f263522aSJoseph Koshy };
409f263522aSJoseph Koshy 
410f263522aSJoseph Koshy /* ls segment register loads */
411f263522aSJoseph Koshy static const struct pmc_masks k8_mask_lsrl[] = {
412f263522aSJoseph Koshy 	__K8MASK(es,	0),
413f263522aSJoseph Koshy 	__K8MASK(cs,	1),
414f263522aSJoseph Koshy 	__K8MASK(ss,	2),
415f263522aSJoseph Koshy 	__K8MASK(ds,	3),
416f263522aSJoseph Koshy 	__K8MASK(fs,	4),
417f263522aSJoseph Koshy 	__K8MASK(gs,	5),
418f263522aSJoseph Koshy 	__K8MASK(hs,	6),
419f263522aSJoseph Koshy 	NULLMASK
420f263522aSJoseph Koshy };
421f263522aSJoseph Koshy 
422f263522aSJoseph Koshy /* ls locked operation */
423f263522aSJoseph Koshy static const struct pmc_masks k8_mask_llo[] = {
424f263522aSJoseph Koshy 	__K8MASK(locked-instructions,	0),
425f263522aSJoseph Koshy 	__K8MASK(cycles-in-request,	1),
426f263522aSJoseph Koshy 	__K8MASK(cycles-to-complete,	2),
427f263522aSJoseph Koshy 	NULLMASK
428f263522aSJoseph Koshy };
429f263522aSJoseph Koshy 
430f263522aSJoseph Koshy /* dc refill from {l2,system} and dc copyback */
431f263522aSJoseph Koshy static const struct pmc_masks k8_mask_dc[] = {
432f263522aSJoseph Koshy 	__K8MASK(invalid,	0),
433f263522aSJoseph Koshy 	__K8MASK(shared,	1),
434f263522aSJoseph Koshy 	__K8MASK(exclusive,	2),
435f263522aSJoseph Koshy 	__K8MASK(owner,		3),
436f263522aSJoseph Koshy 	__K8MASK(modified,	4),
437f263522aSJoseph Koshy 	NULLMASK
438f263522aSJoseph Koshy };
439f263522aSJoseph Koshy 
440f263522aSJoseph Koshy /* dc one bit ecc error */
441f263522aSJoseph Koshy static const struct pmc_masks k8_mask_dobee[] = {
442f263522aSJoseph Koshy 	__K8MASK(scrubber,	0),
443f263522aSJoseph Koshy 	__K8MASK(piggyback,	1),
444f263522aSJoseph Koshy 	NULLMASK
445f263522aSJoseph Koshy };
446f263522aSJoseph Koshy 
447f263522aSJoseph Koshy /* dc dispatched prefetch instructions */
448f263522aSJoseph Koshy static const struct pmc_masks k8_mask_ddpi[] = {
449f263522aSJoseph Koshy 	__K8MASK(load,	0),
450f263522aSJoseph Koshy 	__K8MASK(store,	1),
451f263522aSJoseph Koshy 	__K8MASK(nta,	2),
452f263522aSJoseph Koshy 	NULLMASK
453f263522aSJoseph Koshy };
454f263522aSJoseph Koshy 
455f263522aSJoseph Koshy /* dc dcache accesses by locks */
456f263522aSJoseph Koshy static const struct pmc_masks k8_mask_dabl[] = {
457f263522aSJoseph Koshy 	__K8MASK(accesses,	0),
458f263522aSJoseph Koshy 	__K8MASK(misses,	1),
459f263522aSJoseph Koshy 	NULLMASK
460f263522aSJoseph Koshy };
461f263522aSJoseph Koshy 
462f263522aSJoseph Koshy /* bu internal l2 request */
463f263522aSJoseph Koshy static const struct pmc_masks k8_mask_bilr[] = {
464f263522aSJoseph Koshy 	__K8MASK(ic-fill,	0),
465f263522aSJoseph Koshy 	__K8MASK(dc-fill,	1),
466f263522aSJoseph Koshy 	__K8MASK(tlb-reload,	2),
467f263522aSJoseph Koshy 	__K8MASK(tag-snoop,	3),
468f263522aSJoseph Koshy 	__K8MASK(cancelled,	4),
469f263522aSJoseph Koshy 	NULLMASK
470f263522aSJoseph Koshy };
471f263522aSJoseph Koshy 
472f263522aSJoseph Koshy /* bu fill request l2 miss */
473f263522aSJoseph Koshy static const struct pmc_masks k8_mask_bfrlm[] = {
474f263522aSJoseph Koshy 	__K8MASK(ic-fill,	0),
475f263522aSJoseph Koshy 	__K8MASK(dc-fill,	1),
476f263522aSJoseph Koshy 	__K8MASK(tlb-reload,	2),
477f263522aSJoseph Koshy 	NULLMASK
478f263522aSJoseph Koshy };
479f263522aSJoseph Koshy 
480f263522aSJoseph Koshy /* bu fill into l2 */
481f263522aSJoseph Koshy static const struct pmc_masks k8_mask_bfil[] = {
482f263522aSJoseph Koshy 	__K8MASK(dirty-l2-victim,	0),
483f263522aSJoseph Koshy 	__K8MASK(victim-from-l2,	1),
484f263522aSJoseph Koshy 	NULLMASK
485f263522aSJoseph Koshy };
486f263522aSJoseph Koshy 
487f263522aSJoseph Koshy /* fr retired fpu instructions */
488f263522aSJoseph Koshy static const struct pmc_masks k8_mask_frfi[] = {
489f263522aSJoseph Koshy 	__K8MASK(x87,			0),
490f263522aSJoseph Koshy 	__K8MASK(mmx-3dnow,		1),
491f263522aSJoseph Koshy 	__K8MASK(packed-sse-sse2,	2),
492f263522aSJoseph Koshy 	__K8MASK(scalar-sse-sse2,	3),
493f263522aSJoseph Koshy 	NULLMASK
494f263522aSJoseph Koshy };
495f263522aSJoseph Koshy 
496f263522aSJoseph Koshy /* fr retired fastpath double op instructions */
497f263522aSJoseph Koshy static const struct pmc_masks k8_mask_frfdoi[] = {
498f263522aSJoseph Koshy 	__K8MASK(low-op-pos-0,		0),
499f263522aSJoseph Koshy 	__K8MASK(low-op-pos-1,		1),
500f263522aSJoseph Koshy 	__K8MASK(low-op-pos-2,		2),
501f263522aSJoseph Koshy 	NULLMASK
502f263522aSJoseph Koshy };
503f263522aSJoseph Koshy 
504f263522aSJoseph Koshy /* fr fpu exceptions */
505f263522aSJoseph Koshy static const struct pmc_masks k8_mask_ffe[] = {
506f263522aSJoseph Koshy 	__K8MASK(x87-reclass-microfaults,	0),
507f263522aSJoseph Koshy 	__K8MASK(sse-retype-microfaults,	1),
508f263522aSJoseph Koshy 	__K8MASK(sse-reclass-microfaults,	2),
509f263522aSJoseph Koshy 	__K8MASK(sse-and-x87-microtraps,	3),
510f263522aSJoseph Koshy 	NULLMASK
511f263522aSJoseph Koshy };
512f263522aSJoseph Koshy 
513f263522aSJoseph Koshy /* nb memory controller page access event */
514f263522aSJoseph Koshy static const struct pmc_masks k8_mask_nmcpae[] = {
515f263522aSJoseph Koshy 	__K8MASK(page-hit,	0),
516f263522aSJoseph Koshy 	__K8MASK(page-miss,	1),
517f263522aSJoseph Koshy 	__K8MASK(page-conflict,	2),
518f263522aSJoseph Koshy 	NULLMASK
519f263522aSJoseph Koshy };
520f263522aSJoseph Koshy 
521f263522aSJoseph Koshy /* nb memory controller turnaround */
522f263522aSJoseph Koshy static const struct pmc_masks k8_mask_nmct[] = {
523f263522aSJoseph Koshy 	__K8MASK(dimm-turnaround,		0),
524f263522aSJoseph Koshy 	__K8MASK(read-to-write-turnaround,	1),
525f263522aSJoseph Koshy 	__K8MASK(write-to-read-turnaround,	2),
526f263522aSJoseph Koshy 	NULLMASK
527f263522aSJoseph Koshy };
528f263522aSJoseph Koshy 
529f263522aSJoseph Koshy /* nb memory controller bypass saturation */
530f263522aSJoseph Koshy static const struct pmc_masks k8_mask_nmcbs[] = {
531f263522aSJoseph Koshy 	__K8MASK(memory-controller-hi-pri-bypass,	0),
532f263522aSJoseph Koshy 	__K8MASK(memory-controller-lo-pri-bypass,	1),
533f263522aSJoseph Koshy 	__K8MASK(dram-controller-interface-bypass,	2),
534f263522aSJoseph Koshy 	__K8MASK(dram-controller-queue-bypass,		3),
535f263522aSJoseph Koshy 	NULLMASK
536f263522aSJoseph Koshy };
537f263522aSJoseph Koshy 
538f263522aSJoseph Koshy /* nb sized commands */
539f263522aSJoseph Koshy static const struct pmc_masks k8_mask_nsc[] = {
540f263522aSJoseph Koshy 	__K8MASK(nonpostwrszbyte,	0),
541f263522aSJoseph Koshy 	__K8MASK(nonpostwrszdword,	1),
542f263522aSJoseph Koshy 	__K8MASK(postwrszbyte,		2),
543f263522aSJoseph Koshy 	__K8MASK(postwrszdword,		3),
544f263522aSJoseph Koshy 	__K8MASK(rdszbyte,		4),
545f263522aSJoseph Koshy 	__K8MASK(rdszdword,		5),
546f263522aSJoseph Koshy 	__K8MASK(rdmodwr,		6),
547f263522aSJoseph Koshy 	NULLMASK
548f263522aSJoseph Koshy };
549f263522aSJoseph Koshy 
550f263522aSJoseph Koshy /* nb probe result */
551f263522aSJoseph Koshy static const struct pmc_masks k8_mask_npr[] = {
552f263522aSJoseph Koshy 	__K8MASK(probe-miss,		0),
553f263522aSJoseph Koshy 	__K8MASK(probe-hit,		1),
554f263522aSJoseph Koshy 	__K8MASK(probe-hit-dirty-no-memory-cancel, 2),
555f263522aSJoseph Koshy 	__K8MASK(probe-hit-dirty-with-memory-cancel, 3),
556f263522aSJoseph Koshy 	NULLMASK
557f263522aSJoseph Koshy };
558f263522aSJoseph Koshy 
559f263522aSJoseph Koshy /* nb hypertransport bus bandwidth */
560f263522aSJoseph Koshy static const struct pmc_masks k8_mask_nhbb[] = { /* HT bus bandwidth */
561f263522aSJoseph Koshy 	__K8MASK(command,	0),
562f263522aSJoseph Koshy 	__K8MASK(data,	1),
563f263522aSJoseph Koshy 	__K8MASK(buffer-release, 2),
564f263522aSJoseph Koshy 	__K8MASK(nop,	3),
565f263522aSJoseph Koshy 	NULLMASK
566f263522aSJoseph Koshy };
567f263522aSJoseph Koshy 
568f263522aSJoseph Koshy #undef	__K8MASK
569f263522aSJoseph Koshy 
570f263522aSJoseph Koshy #define	K8_KW_COUNT	"count"
571f263522aSJoseph Koshy #define	K8_KW_EDGE	"edge"
572f263522aSJoseph Koshy #define	K8_KW_INV	"inv"
573f263522aSJoseph Koshy #define	K8_KW_MASK	"mask"
574f263522aSJoseph Koshy #define	K8_KW_OS	"os"
575f263522aSJoseph Koshy #define	K8_KW_USR	"usr"
576f263522aSJoseph Koshy 
577f263522aSJoseph Koshy static int
578f263522aSJoseph Koshy k8_allocate_pmc(enum pmc_event pe, char *ctrspec,
579f263522aSJoseph Koshy     struct pmc_op_pmcallocate *pmc_config)
580f263522aSJoseph Koshy {
581f263522aSJoseph Koshy 	char		*e, *p, *q;
582f263522aSJoseph Koshy 	int		n;
583f263522aSJoseph Koshy 	uint32_t	count, evmask;
584f263522aSJoseph Koshy 	const struct pmc_masks	*pm, *pmask;
585f263522aSJoseph Koshy 
586789140c0SJoseph Koshy 	pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE);
587f263522aSJoseph Koshy 	pmc_config->pm_md.pm_amd.pm_amd_config = 0;
588f263522aSJoseph Koshy 
589f263522aSJoseph Koshy 	pmask = NULL;
590f263522aSJoseph Koshy 	evmask = 0;
591f263522aSJoseph Koshy 
592f263522aSJoseph Koshy #define	__K8SETMASK(M) pmask = k8_mask_##M
593f263522aSJoseph Koshy 
594f263522aSJoseph Koshy 	/* setup parsing tables */
595f263522aSJoseph Koshy 	switch (pe) {
596f263522aSJoseph Koshy 	case PMC_EV_K8_FP_DISPATCHED_FPU_OPS:
597f263522aSJoseph Koshy 		__K8SETMASK(fdfo);
598f263522aSJoseph Koshy 		break;
599f263522aSJoseph Koshy 	case PMC_EV_K8_LS_SEGMENT_REGISTER_LOAD:
600f263522aSJoseph Koshy 		__K8SETMASK(lsrl);
601f263522aSJoseph Koshy 		break;
602f263522aSJoseph Koshy 	case PMC_EV_K8_LS_LOCKED_OPERATION:
603f263522aSJoseph Koshy 		__K8SETMASK(llo);
604f263522aSJoseph Koshy 		break;
605f263522aSJoseph Koshy 	case PMC_EV_K8_DC_REFILL_FROM_L2:
606f263522aSJoseph Koshy 	case PMC_EV_K8_DC_REFILL_FROM_SYSTEM:
607f263522aSJoseph Koshy 	case PMC_EV_K8_DC_COPYBACK:
608f263522aSJoseph Koshy 		__K8SETMASK(dc);
609f263522aSJoseph Koshy 		break;
610f263522aSJoseph Koshy 	case PMC_EV_K8_DC_ONE_BIT_ECC_ERROR:
611f263522aSJoseph Koshy 		__K8SETMASK(dobee);
612f263522aSJoseph Koshy 		break;
613f263522aSJoseph Koshy 	case PMC_EV_K8_DC_DISPATCHED_PREFETCH_INSTRUCTIONS:
614f263522aSJoseph Koshy 		__K8SETMASK(ddpi);
615f263522aSJoseph Koshy 		break;
616f263522aSJoseph Koshy 	case PMC_EV_K8_DC_DCACHE_ACCESSES_BY_LOCKS:
617f263522aSJoseph Koshy 		__K8SETMASK(dabl);
618f263522aSJoseph Koshy 		break;
619f263522aSJoseph Koshy 	case PMC_EV_K8_BU_INTERNAL_L2_REQUEST:
620f263522aSJoseph Koshy 		__K8SETMASK(bilr);
621f263522aSJoseph Koshy 		break;
622f263522aSJoseph Koshy 	case PMC_EV_K8_BU_FILL_REQUEST_L2_MISS:
623f263522aSJoseph Koshy 		__K8SETMASK(bfrlm);
624f263522aSJoseph Koshy 		break;
625f263522aSJoseph Koshy 	case PMC_EV_K8_BU_FILL_INTO_L2:
626f263522aSJoseph Koshy 		__K8SETMASK(bfil);
627f263522aSJoseph Koshy 		break;
628f263522aSJoseph Koshy 	case PMC_EV_K8_FR_RETIRED_FPU_INSTRUCTIONS:
629f263522aSJoseph Koshy 		__K8SETMASK(frfi);
630f263522aSJoseph Koshy 		break;
631f263522aSJoseph Koshy 	case PMC_EV_K8_FR_RETIRED_FASTPATH_DOUBLE_OP_INSTRUCTIONS:
632f263522aSJoseph Koshy 		__K8SETMASK(frfdoi);
633f263522aSJoseph Koshy 		break;
634f263522aSJoseph Koshy 	case PMC_EV_K8_FR_FPU_EXCEPTIONS:
635f263522aSJoseph Koshy 		__K8SETMASK(ffe);
636f263522aSJoseph Koshy 		break;
637f263522aSJoseph Koshy 	case PMC_EV_K8_NB_MEMORY_CONTROLLER_PAGE_ACCESS_EVENT:
638f263522aSJoseph Koshy 		__K8SETMASK(nmcpae);
639f263522aSJoseph Koshy 		break;
640f263522aSJoseph Koshy 	case PMC_EV_K8_NB_MEMORY_CONTROLLER_TURNAROUND:
641f263522aSJoseph Koshy 		__K8SETMASK(nmct);
642f263522aSJoseph Koshy 		break;
643f263522aSJoseph Koshy 	case PMC_EV_K8_NB_MEMORY_CONTROLLER_BYPASS_SATURATION:
644f263522aSJoseph Koshy 		__K8SETMASK(nmcbs);
645f263522aSJoseph Koshy 		break;
646f263522aSJoseph Koshy 	case PMC_EV_K8_NB_SIZED_COMMANDS:
647f263522aSJoseph Koshy 		__K8SETMASK(nsc);
648f263522aSJoseph Koshy 		break;
649f263522aSJoseph Koshy 	case PMC_EV_K8_NB_PROBE_RESULT:
650f263522aSJoseph Koshy 		__K8SETMASK(npr);
651f263522aSJoseph Koshy 		break;
652f263522aSJoseph Koshy 	case PMC_EV_K8_NB_HT_BUS0_BANDWIDTH:
653f263522aSJoseph Koshy 	case PMC_EV_K8_NB_HT_BUS1_BANDWIDTH:
654f263522aSJoseph Koshy 	case PMC_EV_K8_NB_HT_BUS2_BANDWIDTH:
655f263522aSJoseph Koshy 		__K8SETMASK(nhbb);
656f263522aSJoseph Koshy 		break;
657f263522aSJoseph Koshy 
658f263522aSJoseph Koshy 	default:
659f263522aSJoseph Koshy 		break;		/* no options defined */
660f263522aSJoseph Koshy 	}
661f263522aSJoseph Koshy 
662f263522aSJoseph Koshy 	while ((p = strsep(&ctrspec, ",")) != NULL) {
663f263522aSJoseph Koshy 		if (KWPREFIXMATCH(p, K8_KW_COUNT "=")) {
664f263522aSJoseph Koshy 			q = strchr(p, '=');
665f263522aSJoseph Koshy 			if (*++q == '\0') /* skip '=' */
666aa342b1fSJoseph Koshy 				return (-1);
667f263522aSJoseph Koshy 
668f263522aSJoseph Koshy 			count = strtol(q, &e, 0);
669f263522aSJoseph Koshy 			if (e == q || *e != '\0')
670aa342b1fSJoseph Koshy 				return (-1);
671f263522aSJoseph Koshy 
672f263522aSJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_THRESHOLD;
673f263522aSJoseph Koshy 			pmc_config->pm_md.pm_amd.pm_amd_config |=
674f263522aSJoseph Koshy 			    AMD_PMC_TO_COUNTER(count);
675f263522aSJoseph Koshy 
676f263522aSJoseph Koshy 		} else if (KWMATCH(p, K8_KW_EDGE)) {
677f263522aSJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_EDGE;
678f263522aSJoseph Koshy 		} else if (KWMATCH(p, K8_KW_INV)) {
679f263522aSJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_INVERT;
680f263522aSJoseph Koshy 		} else if (KWPREFIXMATCH(p, K8_KW_MASK "=")) {
681f263522aSJoseph Koshy 			if ((n = pmc_parse_mask(pmask, p, &evmask)) < 0)
682aa342b1fSJoseph Koshy 				return (-1);
683f263522aSJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_QUALIFIER;
684f263522aSJoseph Koshy 		} else if (KWMATCH(p, K8_KW_OS)) {
685f263522aSJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_SYSTEM;
686f263522aSJoseph Koshy 		} else if (KWMATCH(p, K8_KW_USR)) {
687f263522aSJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_USER;
688f263522aSJoseph Koshy 		} else
689aa342b1fSJoseph Koshy 			return (-1);
690f263522aSJoseph Koshy 	}
691f263522aSJoseph Koshy 
692f263522aSJoseph Koshy 	/* other post processing */
693f263522aSJoseph Koshy 	switch (pe) {
694f263522aSJoseph Koshy 	case PMC_EV_K8_FP_DISPATCHED_FPU_OPS:
695f263522aSJoseph Koshy 	case PMC_EV_K8_FP_CYCLES_WITH_NO_FPU_OPS_RETIRED:
696f263522aSJoseph Koshy 	case PMC_EV_K8_FP_DISPATCHED_FPU_FAST_FLAG_OPS:
697f263522aSJoseph Koshy 	case PMC_EV_K8_FR_RETIRED_FASTPATH_DOUBLE_OP_INSTRUCTIONS:
698f263522aSJoseph Koshy 	case PMC_EV_K8_FR_RETIRED_FPU_INSTRUCTIONS:
699f263522aSJoseph Koshy 	case PMC_EV_K8_FR_FPU_EXCEPTIONS:
700f263522aSJoseph Koshy 		/* XXX only available in rev B and later */
701f263522aSJoseph Koshy 		break;
702f263522aSJoseph Koshy 	case PMC_EV_K8_DC_DCACHE_ACCESSES_BY_LOCKS:
703f263522aSJoseph Koshy 		/* XXX only available in rev C and later */
704f263522aSJoseph Koshy 		break;
705f263522aSJoseph Koshy 	case PMC_EV_K8_LS_LOCKED_OPERATION:
706f263522aSJoseph Koshy 		/* XXX CPU Rev A,B evmask is to be zero */
707f263522aSJoseph Koshy 		if (evmask & (evmask - 1)) /* > 1 bit set */
708aa342b1fSJoseph Koshy 			return (-1);
709f263522aSJoseph Koshy 		if (evmask == 0) {
710f263522aSJoseph Koshy 			evmask = 0x01; /* Rev C and later: #instrs */
711f263522aSJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_QUALIFIER;
712f263522aSJoseph Koshy 		}
713f263522aSJoseph Koshy 		break;
714f263522aSJoseph Koshy 	default:
715f263522aSJoseph Koshy 		if (evmask == 0 && pmask != NULL) {
716f263522aSJoseph Koshy 			for (pm = pmask; pm->pm_name; pm++)
717f263522aSJoseph Koshy 				evmask |= pm->pm_value;
718f263522aSJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_QUALIFIER;
719f263522aSJoseph Koshy 		}
720f263522aSJoseph Koshy 	}
721f263522aSJoseph Koshy 
722f263522aSJoseph Koshy 	if (pmc_config->pm_caps & PMC_CAP_QUALIFIER)
723f263522aSJoseph Koshy 		pmc_config->pm_md.pm_amd.pm_amd_config =
724f263522aSJoseph Koshy 		    AMD_PMC_TO_UNITMASK(evmask);
725f263522aSJoseph Koshy 
726aa342b1fSJoseph Koshy 	return (0);
727f263522aSJoseph Koshy }
728f263522aSJoseph Koshy 
729f263522aSJoseph Koshy #endif
730f263522aSJoseph Koshy 
73186a65549SJoseph Koshy #if defined(__amd64__) || defined(__i386__)
732f263522aSJoseph Koshy 
733ebccf1e3SJoseph Koshy /*
734ebccf1e3SJoseph Koshy  * Intel P4 PMCs
735ebccf1e3SJoseph Koshy  */
736ebccf1e3SJoseph Koshy 
737ebccf1e3SJoseph Koshy static struct pmc_event_alias p4_aliases[] = {
738d56c5d4bSJoseph Koshy 	EV_ALIAS("branches",		"p4-branch-retired,mask=mmtp+mmtm"),
739d56c5d4bSJoseph Koshy 	EV_ALIAS("branch-mispredicts",	"p4-mispred-branch-retired"),
740ebccf1e3SJoseph Koshy 	EV_ALIAS("cycles",		"tsc"),
741d56c5d4bSJoseph Koshy 	EV_ALIAS("instructions",
742d56c5d4bSJoseph Koshy 	    "p4-instr-retired,mask=nbogusntag+nbogustag"),
743177a2f22SJoseph Koshy 	EV_ALIAS("unhalted-cycles",	"p4-global-power-events"),
744ebccf1e3SJoseph Koshy 	EV_ALIAS(NULL, NULL)
745ebccf1e3SJoseph Koshy };
746ebccf1e3SJoseph Koshy 
747ebccf1e3SJoseph Koshy #define	P4_KW_ACTIVE	"active"
748ebccf1e3SJoseph Koshy #define	P4_KW_ACTIVE_ANY "any"
749ebccf1e3SJoseph Koshy #define	P4_KW_ACTIVE_BOTH "both"
750ebccf1e3SJoseph Koshy #define	P4_KW_ACTIVE_NONE "none"
751ebccf1e3SJoseph Koshy #define	P4_KW_ACTIVE_SINGLE "single"
752ebccf1e3SJoseph Koshy #define	P4_KW_BUSREQTYPE "busreqtype"
753ebccf1e3SJoseph Koshy #define	P4_KW_CASCADE	"cascade"
754ebccf1e3SJoseph Koshy #define	P4_KW_EDGE	"edge"
755ebccf1e3SJoseph Koshy #define	P4_KW_INV	"complement"
756ebccf1e3SJoseph Koshy #define	P4_KW_OS	"os"
757ebccf1e3SJoseph Koshy #define	P4_KW_MASK	"mask"
758ebccf1e3SJoseph Koshy #define	P4_KW_PRECISE	"precise"
759ebccf1e3SJoseph Koshy #define	P4_KW_TAG	"tag"
760ebccf1e3SJoseph Koshy #define	P4_KW_THRESHOLD	"threshold"
761ebccf1e3SJoseph Koshy #define	P4_KW_USR	"usr"
762ebccf1e3SJoseph Koshy 
763ebccf1e3SJoseph Koshy #define	__P4MASK(N,V) PMCMASK(N, (1 << (V)))
764ebccf1e3SJoseph Koshy 
765ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_tcdm[] = { /* tc deliver mode */
766ebccf1e3SJoseph Koshy 	__P4MASK(dd, 0),
767ebccf1e3SJoseph Koshy 	__P4MASK(db, 1),
768ebccf1e3SJoseph Koshy 	__P4MASK(di, 2),
769ebccf1e3SJoseph Koshy 	__P4MASK(bd, 3),
770ebccf1e3SJoseph Koshy 	__P4MASK(bb, 4),
771ebccf1e3SJoseph Koshy 	__P4MASK(bi, 5),
772ebccf1e3SJoseph Koshy 	__P4MASK(id, 6),
773ebccf1e3SJoseph Koshy 	__P4MASK(ib, 7),
774ebccf1e3SJoseph Koshy 	NULLMASK
775ebccf1e3SJoseph Koshy };
776ebccf1e3SJoseph Koshy 
777ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_bfr[] = { /* bpu fetch request */
778ebccf1e3SJoseph Koshy 	__P4MASK(tcmiss, 0),
779ebccf1e3SJoseph Koshy 	NULLMASK,
780ebccf1e3SJoseph Koshy };
781ebccf1e3SJoseph Koshy 
782ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_ir[] = { /* itlb reference */
783ebccf1e3SJoseph Koshy 	__P4MASK(hit, 0),
784ebccf1e3SJoseph Koshy 	__P4MASK(miss, 1),
785ebccf1e3SJoseph Koshy 	__P4MASK(hit-uc, 2),
786ebccf1e3SJoseph Koshy 	NULLMASK
787ebccf1e3SJoseph Koshy };
788ebccf1e3SJoseph Koshy 
789ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_memcan[] = { /* memory cancel */
790ebccf1e3SJoseph Koshy 	__P4MASK(st-rb-full, 2),
791ebccf1e3SJoseph Koshy 	__P4MASK(64k-conf, 3),
792ebccf1e3SJoseph Koshy 	NULLMASK
793ebccf1e3SJoseph Koshy };
794ebccf1e3SJoseph Koshy 
795ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_memcomp[] = { /* memory complete */
796ebccf1e3SJoseph Koshy 	__P4MASK(lsc, 0),
797ebccf1e3SJoseph Koshy 	__P4MASK(ssc, 1),
798ebccf1e3SJoseph Koshy 	NULLMASK
799ebccf1e3SJoseph Koshy };
800ebccf1e3SJoseph Koshy 
801ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_lpr[] = { /* load port replay */
802ebccf1e3SJoseph Koshy 	__P4MASK(split-ld, 1),
803ebccf1e3SJoseph Koshy 	NULLMASK
804ebccf1e3SJoseph Koshy };
805ebccf1e3SJoseph Koshy 
806ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_spr[] = { /* store port replay */
807ebccf1e3SJoseph Koshy 	__P4MASK(split-st, 1),
808ebccf1e3SJoseph Koshy 	NULLMASK
809ebccf1e3SJoseph Koshy };
810ebccf1e3SJoseph Koshy 
811ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_mlr[] = { /* mob load replay */
812ebccf1e3SJoseph Koshy 	__P4MASK(no-sta, 1),
813ebccf1e3SJoseph Koshy 	__P4MASK(no-std, 3),
814ebccf1e3SJoseph Koshy 	__P4MASK(partial-data, 4),
815ebccf1e3SJoseph Koshy 	__P4MASK(unalgn-addr, 5),
816ebccf1e3SJoseph Koshy 	NULLMASK
817ebccf1e3SJoseph Koshy };
818ebccf1e3SJoseph Koshy 
819ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_pwt[] = { /* page walk type */
820ebccf1e3SJoseph Koshy 	__P4MASK(dtmiss, 0),
821ebccf1e3SJoseph Koshy 	__P4MASK(itmiss, 1),
822ebccf1e3SJoseph Koshy 	NULLMASK
823ebccf1e3SJoseph Koshy };
824ebccf1e3SJoseph Koshy 
825ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_bcr[] = { /* bsq cache reference */
826ebccf1e3SJoseph Koshy 	__P4MASK(rd-2ndl-hits, 0),
827ebccf1e3SJoseph Koshy 	__P4MASK(rd-2ndl-hite, 1),
828ebccf1e3SJoseph Koshy 	__P4MASK(rd-2ndl-hitm, 2),
829ebccf1e3SJoseph Koshy 	__P4MASK(rd-3rdl-hits, 3),
830ebccf1e3SJoseph Koshy 	__P4MASK(rd-3rdl-hite, 4),
831ebccf1e3SJoseph Koshy 	__P4MASK(rd-3rdl-hitm, 5),
832ebccf1e3SJoseph Koshy 	__P4MASK(rd-2ndl-miss, 8),
833ebccf1e3SJoseph Koshy 	__P4MASK(rd-3rdl-miss, 9),
834ebccf1e3SJoseph Koshy 	__P4MASK(wr-2ndl-miss, 10),
835ebccf1e3SJoseph Koshy 	NULLMASK
836ebccf1e3SJoseph Koshy };
837ebccf1e3SJoseph Koshy 
838ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_ia[] = { /* ioq allocation */
839ebccf1e3SJoseph Koshy 	__P4MASK(all-read, 5),
840ebccf1e3SJoseph Koshy 	__P4MASK(all-write, 6),
841ebccf1e3SJoseph Koshy 	__P4MASK(mem-uc, 7),
842ebccf1e3SJoseph Koshy 	__P4MASK(mem-wc, 8),
843ebccf1e3SJoseph Koshy 	__P4MASK(mem-wt, 9),
844ebccf1e3SJoseph Koshy 	__P4MASK(mem-wp, 10),
845ebccf1e3SJoseph Koshy 	__P4MASK(mem-wb, 11),
846ebccf1e3SJoseph Koshy 	__P4MASK(own, 13),
847ebccf1e3SJoseph Koshy 	__P4MASK(other, 14),
848ebccf1e3SJoseph Koshy 	__P4MASK(prefetch, 15),
849ebccf1e3SJoseph Koshy 	NULLMASK
850ebccf1e3SJoseph Koshy };
851ebccf1e3SJoseph Koshy 
852ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_iae[] = { /* ioq active entries */
853ebccf1e3SJoseph Koshy 	__P4MASK(all-read, 5),
854ebccf1e3SJoseph Koshy 	__P4MASK(all-write, 6),
855ebccf1e3SJoseph Koshy 	__P4MASK(mem-uc, 7),
856ebccf1e3SJoseph Koshy 	__P4MASK(mem-wc, 8),
857ebccf1e3SJoseph Koshy 	__P4MASK(mem-wt, 9),
858ebccf1e3SJoseph Koshy 	__P4MASK(mem-wp, 10),
859ebccf1e3SJoseph Koshy 	__P4MASK(mem-wb, 11),
860ebccf1e3SJoseph Koshy 	__P4MASK(own, 13),
861ebccf1e3SJoseph Koshy 	__P4MASK(other, 14),
862ebccf1e3SJoseph Koshy 	__P4MASK(prefetch, 15),
863ebccf1e3SJoseph Koshy 	NULLMASK
864ebccf1e3SJoseph Koshy };
865ebccf1e3SJoseph Koshy 
866ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_fda[] = { /* fsb data activity */
867ebccf1e3SJoseph Koshy 	__P4MASK(drdy-drv, 0),
868ebccf1e3SJoseph Koshy 	__P4MASK(drdy-own, 1),
869ebccf1e3SJoseph Koshy 	__P4MASK(drdy-other, 2),
870ebccf1e3SJoseph Koshy 	__P4MASK(dbsy-drv, 3),
871ebccf1e3SJoseph Koshy 	__P4MASK(dbsy-own, 4),
872ebccf1e3SJoseph Koshy 	__P4MASK(dbsy-other, 5),
873ebccf1e3SJoseph Koshy 	NULLMASK
874ebccf1e3SJoseph Koshy };
875ebccf1e3SJoseph Koshy 
876ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_ba[] = { /* bsq allocation */
877ebccf1e3SJoseph Koshy 	__P4MASK(req-type0, 0),
878ebccf1e3SJoseph Koshy 	__P4MASK(req-type1, 1),
879ebccf1e3SJoseph Koshy 	__P4MASK(req-len0, 2),
880ebccf1e3SJoseph Koshy 	__P4MASK(req-len1, 3),
881ebccf1e3SJoseph Koshy 	__P4MASK(req-io-type, 5),
882ebccf1e3SJoseph Koshy 	__P4MASK(req-lock-type, 6),
883ebccf1e3SJoseph Koshy 	__P4MASK(req-cache-type, 7),
884ebccf1e3SJoseph Koshy 	__P4MASK(req-split-type, 8),
885ebccf1e3SJoseph Koshy 	__P4MASK(req-dem-type, 9),
886ebccf1e3SJoseph Koshy 	__P4MASK(req-ord-type, 10),
887ebccf1e3SJoseph Koshy 	__P4MASK(mem-type0, 11),
888ebccf1e3SJoseph Koshy 	__P4MASK(mem-type1, 12),
889ebccf1e3SJoseph Koshy 	__P4MASK(mem-type2, 13),
890ebccf1e3SJoseph Koshy 	NULLMASK
891ebccf1e3SJoseph Koshy };
892ebccf1e3SJoseph Koshy 
893ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_sia[] = { /* sse input assist */
894ebccf1e3SJoseph Koshy 	__P4MASK(all, 15),
895ebccf1e3SJoseph Koshy 	NULLMASK
896ebccf1e3SJoseph Koshy };
897ebccf1e3SJoseph Koshy 
898ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_psu[] = { /* packed sp uop */
899ebccf1e3SJoseph Koshy 	__P4MASK(all, 15),
900ebccf1e3SJoseph Koshy 	NULLMASK
901ebccf1e3SJoseph Koshy };
902ebccf1e3SJoseph Koshy 
903ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_pdu[] = { /* packed dp uop */
904ebccf1e3SJoseph Koshy 	__P4MASK(all, 15),
905ebccf1e3SJoseph Koshy 	NULLMASK
906ebccf1e3SJoseph Koshy };
907ebccf1e3SJoseph Koshy 
908ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_ssu[] = { /* scalar sp uop */
909ebccf1e3SJoseph Koshy 	__P4MASK(all, 15),
910ebccf1e3SJoseph Koshy 	NULLMASK
911ebccf1e3SJoseph Koshy };
912ebccf1e3SJoseph Koshy 
913ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_sdu[] = { /* scalar dp uop */
914ebccf1e3SJoseph Koshy 	__P4MASK(all, 15),
915ebccf1e3SJoseph Koshy 	NULLMASK
916ebccf1e3SJoseph Koshy };
917ebccf1e3SJoseph Koshy 
918ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_64bmu[] = { /* 64 bit mmx uop */
919ebccf1e3SJoseph Koshy 	__P4MASK(all, 15),
920ebccf1e3SJoseph Koshy 	NULLMASK
921ebccf1e3SJoseph Koshy };
922ebccf1e3SJoseph Koshy 
923ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_128bmu[] = { /* 128 bit mmx uop */
924ebccf1e3SJoseph Koshy 	__P4MASK(all, 15),
925ebccf1e3SJoseph Koshy 	NULLMASK
926ebccf1e3SJoseph Koshy };
927ebccf1e3SJoseph Koshy 
928ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_xfu[] = { /* X87 fp uop */
929ebccf1e3SJoseph Koshy 	__P4MASK(all, 15),
930ebccf1e3SJoseph Koshy 	NULLMASK
931ebccf1e3SJoseph Koshy };
932ebccf1e3SJoseph Koshy 
933ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_xsmu[] = { /* x87 simd moves uop */
934ebccf1e3SJoseph Koshy 	__P4MASK(allp0, 3),
935ebccf1e3SJoseph Koshy 	__P4MASK(allp2, 4),
936ebccf1e3SJoseph Koshy 	NULLMASK
937ebccf1e3SJoseph Koshy };
938ebccf1e3SJoseph Koshy 
939ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_gpe[] = { /* global power events */
940ebccf1e3SJoseph Koshy 	__P4MASK(running, 0),
941ebccf1e3SJoseph Koshy 	NULLMASK
942ebccf1e3SJoseph Koshy };
943ebccf1e3SJoseph Koshy 
944ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_tmx[] = { /* TC ms xfer */
945ebccf1e3SJoseph Koshy 	__P4MASK(cisc, 0),
946ebccf1e3SJoseph Koshy 	NULLMASK
947ebccf1e3SJoseph Koshy };
948ebccf1e3SJoseph Koshy 
949ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_uqw[] = { /* uop queue writes */
950ebccf1e3SJoseph Koshy 	__P4MASK(from-tc-build, 0),
951ebccf1e3SJoseph Koshy 	__P4MASK(from-tc-deliver, 1),
952ebccf1e3SJoseph Koshy 	__P4MASK(from-rom, 2),
953ebccf1e3SJoseph Koshy 	NULLMASK
954ebccf1e3SJoseph Koshy };
955ebccf1e3SJoseph Koshy 
956d56c5d4bSJoseph Koshy static const struct pmc_masks p4_mask_rmbt[] = {
957d56c5d4bSJoseph Koshy 	/* retired mispred branch type */
958ebccf1e3SJoseph Koshy 	__P4MASK(conditional, 1),
959ebccf1e3SJoseph Koshy 	__P4MASK(call, 2),
960ebccf1e3SJoseph Koshy 	__P4MASK(return, 3),
961ebccf1e3SJoseph Koshy 	__P4MASK(indirect, 4),
962ebccf1e3SJoseph Koshy 	NULLMASK
963ebccf1e3SJoseph Koshy };
964ebccf1e3SJoseph Koshy 
965ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_rbt[] = { /* retired branch type */
966ebccf1e3SJoseph Koshy 	__P4MASK(conditional, 1),
967ebccf1e3SJoseph Koshy 	__P4MASK(call, 2),
968ebccf1e3SJoseph Koshy 	__P4MASK(retired, 3),
969ebccf1e3SJoseph Koshy 	__P4MASK(indirect, 4),
970ebccf1e3SJoseph Koshy 	NULLMASK
971ebccf1e3SJoseph Koshy };
972ebccf1e3SJoseph Koshy 
973ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_rs[] = { /* resource stall */
974ebccf1e3SJoseph Koshy 	__P4MASK(sbfull, 5),
975ebccf1e3SJoseph Koshy 	NULLMASK
976ebccf1e3SJoseph Koshy };
977ebccf1e3SJoseph Koshy 
978ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_wb[] = { /* WC buffer */
979ebccf1e3SJoseph Koshy 	__P4MASK(wcb-evicts, 0),
980ebccf1e3SJoseph Koshy 	__P4MASK(wcb-full-evict, 1),
981ebccf1e3SJoseph Koshy 	NULLMASK
982ebccf1e3SJoseph Koshy };
983ebccf1e3SJoseph Koshy 
984ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_fee[] = { /* front end event */
985ebccf1e3SJoseph Koshy 	__P4MASK(nbogus, 0),
986ebccf1e3SJoseph Koshy 	__P4MASK(bogus, 1),
987ebccf1e3SJoseph Koshy 	NULLMASK
988ebccf1e3SJoseph Koshy };
989ebccf1e3SJoseph Koshy 
990ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_ee[] = { /* execution event */
991ebccf1e3SJoseph Koshy 	__P4MASK(nbogus0, 0),
992ebccf1e3SJoseph Koshy 	__P4MASK(nbogus1, 1),
993ebccf1e3SJoseph Koshy 	__P4MASK(nbogus2, 2),
994ebccf1e3SJoseph Koshy 	__P4MASK(nbogus3, 3),
995ebccf1e3SJoseph Koshy 	__P4MASK(bogus0, 4),
996ebccf1e3SJoseph Koshy 	__P4MASK(bogus1, 5),
997ebccf1e3SJoseph Koshy 	__P4MASK(bogus2, 6),
998ebccf1e3SJoseph Koshy 	__P4MASK(bogus3, 7),
999ebccf1e3SJoseph Koshy 	NULLMASK
1000ebccf1e3SJoseph Koshy };
1001ebccf1e3SJoseph Koshy 
1002ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_re[] = { /* replay event */
1003ebccf1e3SJoseph Koshy 	__P4MASK(nbogus, 0),
1004ebccf1e3SJoseph Koshy 	__P4MASK(bogus, 1),
1005ebccf1e3SJoseph Koshy 	NULLMASK
1006ebccf1e3SJoseph Koshy };
1007ebccf1e3SJoseph Koshy 
1008ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_insret[] = { /* instr retired */
1009ebccf1e3SJoseph Koshy 	__P4MASK(nbogusntag, 0),
1010ebccf1e3SJoseph Koshy 	__P4MASK(nbogustag, 1),
1011ebccf1e3SJoseph Koshy 	__P4MASK(bogusntag, 2),
1012ebccf1e3SJoseph Koshy 	__P4MASK(bogustag, 3),
1013ebccf1e3SJoseph Koshy 	NULLMASK
1014ebccf1e3SJoseph Koshy };
1015ebccf1e3SJoseph Koshy 
1016ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_ur[] = { /* uops retired */
1017ebccf1e3SJoseph Koshy 	__P4MASK(nbogus, 0),
1018ebccf1e3SJoseph Koshy 	__P4MASK(bogus, 1),
1019ebccf1e3SJoseph Koshy 	NULLMASK
1020ebccf1e3SJoseph Koshy };
1021ebccf1e3SJoseph Koshy 
1022ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_ut[] = { /* uop type */
1023ebccf1e3SJoseph Koshy 	__P4MASK(tagloads, 1),
1024ebccf1e3SJoseph Koshy 	__P4MASK(tagstores, 2),
1025ebccf1e3SJoseph Koshy 	NULLMASK
1026ebccf1e3SJoseph Koshy };
1027ebccf1e3SJoseph Koshy 
1028ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_br[] = { /* branch retired */
1029ebccf1e3SJoseph Koshy 	__P4MASK(mmnp, 0),
1030ebccf1e3SJoseph Koshy 	__P4MASK(mmnm, 1),
1031ebccf1e3SJoseph Koshy 	__P4MASK(mmtp, 2),
1032ebccf1e3SJoseph Koshy 	__P4MASK(mmtm, 3),
1033ebccf1e3SJoseph Koshy 	NULLMASK
1034ebccf1e3SJoseph Koshy };
1035ebccf1e3SJoseph Koshy 
1036ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_mbr[] = { /* mispred branch retired */
1037ebccf1e3SJoseph Koshy 	__P4MASK(nbogus, 0),
1038ebccf1e3SJoseph Koshy 	NULLMASK
1039ebccf1e3SJoseph Koshy };
1040ebccf1e3SJoseph Koshy 
1041ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_xa[] = { /* x87 assist */
1042ebccf1e3SJoseph Koshy 	__P4MASK(fpsu, 0),
1043ebccf1e3SJoseph Koshy 	__P4MASK(fpso, 1),
1044ebccf1e3SJoseph Koshy 	__P4MASK(poao, 2),
1045ebccf1e3SJoseph Koshy 	__P4MASK(poau, 3),
1046ebccf1e3SJoseph Koshy 	__P4MASK(prea, 4),
1047ebccf1e3SJoseph Koshy 	NULLMASK
1048ebccf1e3SJoseph Koshy };
1049ebccf1e3SJoseph Koshy 
1050ebccf1e3SJoseph Koshy static const struct pmc_masks p4_mask_machclr[] = { /* machine clear */
1051ebccf1e3SJoseph Koshy 	__P4MASK(clear, 0),
1052ebccf1e3SJoseph Koshy 	__P4MASK(moclear, 2),
1053ebccf1e3SJoseph Koshy 	__P4MASK(smclear, 3),
1054ebccf1e3SJoseph Koshy 	NULLMASK
1055ebccf1e3SJoseph Koshy };
1056ebccf1e3SJoseph Koshy 
1057ebccf1e3SJoseph Koshy /* P4 event parser */
1058ebccf1e3SJoseph Koshy static int
1059ebccf1e3SJoseph Koshy p4_allocate_pmc(enum pmc_event pe, char *ctrspec,
1060ebccf1e3SJoseph Koshy     struct pmc_op_pmcallocate *pmc_config)
1061ebccf1e3SJoseph Koshy {
1062ebccf1e3SJoseph Koshy 
1063ebccf1e3SJoseph Koshy 	char	*e, *p, *q;
1064ebccf1e3SJoseph Koshy 	int	count, has_tag, has_busreqtype, n;
1065ebccf1e3SJoseph Koshy 	uint32_t evmask, cccractivemask;
1066ebccf1e3SJoseph Koshy 	const struct pmc_masks *pm, *pmask;
1067ebccf1e3SJoseph Koshy 
1068789140c0SJoseph Koshy 	pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE);
1069f263522aSJoseph Koshy 	pmc_config->pm_md.pm_p4.pm_p4_cccrconfig =
1070f263522aSJoseph Koshy 	    pmc_config->pm_md.pm_p4.pm_p4_escrconfig = 0;
1071ebccf1e3SJoseph Koshy 
1072ebccf1e3SJoseph Koshy 	pmask   = NULL;
1073ebccf1e3SJoseph Koshy 	evmask  = 0;
1074ebccf1e3SJoseph Koshy 	cccractivemask = 0x3;
1075ebccf1e3SJoseph Koshy 	has_tag = has_busreqtype = 0;
1076ebccf1e3SJoseph Koshy 
1077ebccf1e3SJoseph Koshy #define	__P4SETMASK(M) do {				\
1078ebccf1e3SJoseph Koshy 	pmask = p4_mask_##M;				\
1079ebccf1e3SJoseph Koshy } while (0)
1080ebccf1e3SJoseph Koshy 
1081ebccf1e3SJoseph Koshy 	switch (pe) {
1082ebccf1e3SJoseph Koshy 	case PMC_EV_P4_TC_DELIVER_MODE:
1083ebccf1e3SJoseph Koshy 		__P4SETMASK(tcdm);
1084ebccf1e3SJoseph Koshy 		break;
1085ebccf1e3SJoseph Koshy 	case PMC_EV_P4_BPU_FETCH_REQUEST:
1086ebccf1e3SJoseph Koshy 		__P4SETMASK(bfr);
1087ebccf1e3SJoseph Koshy 		break;
1088ebccf1e3SJoseph Koshy 	case PMC_EV_P4_ITLB_REFERENCE:
1089ebccf1e3SJoseph Koshy 		__P4SETMASK(ir);
1090ebccf1e3SJoseph Koshy 		break;
1091ebccf1e3SJoseph Koshy 	case PMC_EV_P4_MEMORY_CANCEL:
1092ebccf1e3SJoseph Koshy 		__P4SETMASK(memcan);
1093ebccf1e3SJoseph Koshy 		break;
1094ebccf1e3SJoseph Koshy 	case PMC_EV_P4_MEMORY_COMPLETE:
1095ebccf1e3SJoseph Koshy 		__P4SETMASK(memcomp);
1096ebccf1e3SJoseph Koshy 		break;
1097ebccf1e3SJoseph Koshy 	case PMC_EV_P4_LOAD_PORT_REPLAY:
1098ebccf1e3SJoseph Koshy 		__P4SETMASK(lpr);
1099ebccf1e3SJoseph Koshy 		break;
1100ebccf1e3SJoseph Koshy 	case PMC_EV_P4_STORE_PORT_REPLAY:
1101ebccf1e3SJoseph Koshy 		__P4SETMASK(spr);
1102ebccf1e3SJoseph Koshy 		break;
1103ebccf1e3SJoseph Koshy 	case PMC_EV_P4_MOB_LOAD_REPLAY:
1104ebccf1e3SJoseph Koshy 		__P4SETMASK(mlr);
1105ebccf1e3SJoseph Koshy 		break;
1106ebccf1e3SJoseph Koshy 	case PMC_EV_P4_PAGE_WALK_TYPE:
1107ebccf1e3SJoseph Koshy 		__P4SETMASK(pwt);
1108ebccf1e3SJoseph Koshy 		break;
1109ebccf1e3SJoseph Koshy 	case PMC_EV_P4_BSQ_CACHE_REFERENCE:
1110ebccf1e3SJoseph Koshy 		__P4SETMASK(bcr);
1111ebccf1e3SJoseph Koshy 		break;
1112ebccf1e3SJoseph Koshy 	case PMC_EV_P4_IOQ_ALLOCATION:
1113ebccf1e3SJoseph Koshy 		__P4SETMASK(ia);
1114ebccf1e3SJoseph Koshy 		has_busreqtype = 1;
1115ebccf1e3SJoseph Koshy 		break;
1116ebccf1e3SJoseph Koshy 	case PMC_EV_P4_IOQ_ACTIVE_ENTRIES:
1117ebccf1e3SJoseph Koshy 		__P4SETMASK(iae);
1118ebccf1e3SJoseph Koshy 		has_busreqtype = 1;
1119ebccf1e3SJoseph Koshy 		break;
1120ebccf1e3SJoseph Koshy 	case PMC_EV_P4_FSB_DATA_ACTIVITY:
1121ebccf1e3SJoseph Koshy 		__P4SETMASK(fda);
1122ebccf1e3SJoseph Koshy 		break;
1123ebccf1e3SJoseph Koshy 	case PMC_EV_P4_BSQ_ALLOCATION:
1124ebccf1e3SJoseph Koshy 		__P4SETMASK(ba);
1125ebccf1e3SJoseph Koshy 		break;
1126ebccf1e3SJoseph Koshy 	case PMC_EV_P4_SSE_INPUT_ASSIST:
1127ebccf1e3SJoseph Koshy 		__P4SETMASK(sia);
1128ebccf1e3SJoseph Koshy 		break;
1129ebccf1e3SJoseph Koshy 	case PMC_EV_P4_PACKED_SP_UOP:
1130ebccf1e3SJoseph Koshy 		__P4SETMASK(psu);
1131ebccf1e3SJoseph Koshy 		break;
1132ebccf1e3SJoseph Koshy 	case PMC_EV_P4_PACKED_DP_UOP:
1133ebccf1e3SJoseph Koshy 		__P4SETMASK(pdu);
1134ebccf1e3SJoseph Koshy 		break;
1135ebccf1e3SJoseph Koshy 	case PMC_EV_P4_SCALAR_SP_UOP:
1136ebccf1e3SJoseph Koshy 		__P4SETMASK(ssu);
1137ebccf1e3SJoseph Koshy 		break;
1138ebccf1e3SJoseph Koshy 	case PMC_EV_P4_SCALAR_DP_UOP:
1139ebccf1e3SJoseph Koshy 		__P4SETMASK(sdu);
1140ebccf1e3SJoseph Koshy 		break;
1141ebccf1e3SJoseph Koshy 	case PMC_EV_P4_64BIT_MMX_UOP:
1142ebccf1e3SJoseph Koshy 		__P4SETMASK(64bmu);
1143ebccf1e3SJoseph Koshy 		break;
1144ebccf1e3SJoseph Koshy 	case PMC_EV_P4_128BIT_MMX_UOP:
1145ebccf1e3SJoseph Koshy 		__P4SETMASK(128bmu);
1146ebccf1e3SJoseph Koshy 		break;
1147ebccf1e3SJoseph Koshy 	case PMC_EV_P4_X87_FP_UOP:
1148ebccf1e3SJoseph Koshy 		__P4SETMASK(xfu);
1149ebccf1e3SJoseph Koshy 		break;
1150ebccf1e3SJoseph Koshy 	case PMC_EV_P4_X87_SIMD_MOVES_UOP:
1151ebccf1e3SJoseph Koshy 		__P4SETMASK(xsmu);
1152ebccf1e3SJoseph Koshy 		break;
1153ebccf1e3SJoseph Koshy 	case PMC_EV_P4_GLOBAL_POWER_EVENTS:
1154ebccf1e3SJoseph Koshy 		__P4SETMASK(gpe);
1155ebccf1e3SJoseph Koshy 		break;
1156ebccf1e3SJoseph Koshy 	case PMC_EV_P4_TC_MS_XFER:
1157ebccf1e3SJoseph Koshy 		__P4SETMASK(tmx);
1158ebccf1e3SJoseph Koshy 		break;
1159ebccf1e3SJoseph Koshy 	case PMC_EV_P4_UOP_QUEUE_WRITES:
1160ebccf1e3SJoseph Koshy 		__P4SETMASK(uqw);
1161ebccf1e3SJoseph Koshy 		break;
1162ebccf1e3SJoseph Koshy 	case PMC_EV_P4_RETIRED_MISPRED_BRANCH_TYPE:
1163ebccf1e3SJoseph Koshy 		__P4SETMASK(rmbt);
1164ebccf1e3SJoseph Koshy 		break;
1165ebccf1e3SJoseph Koshy 	case PMC_EV_P4_RETIRED_BRANCH_TYPE:
1166ebccf1e3SJoseph Koshy 		__P4SETMASK(rbt);
1167ebccf1e3SJoseph Koshy 		break;
1168ebccf1e3SJoseph Koshy 	case PMC_EV_P4_RESOURCE_STALL:
1169ebccf1e3SJoseph Koshy 		__P4SETMASK(rs);
1170ebccf1e3SJoseph Koshy 		break;
1171ebccf1e3SJoseph Koshy 	case PMC_EV_P4_WC_BUFFER:
1172ebccf1e3SJoseph Koshy 		__P4SETMASK(wb);
1173ebccf1e3SJoseph Koshy 		break;
1174ebccf1e3SJoseph Koshy 	case PMC_EV_P4_BSQ_ACTIVE_ENTRIES:
1175ebccf1e3SJoseph Koshy 	case PMC_EV_P4_B2B_CYCLES:
1176ebccf1e3SJoseph Koshy 	case PMC_EV_P4_BNR:
1177ebccf1e3SJoseph Koshy 	case PMC_EV_P4_SNOOP:
1178ebccf1e3SJoseph Koshy 	case PMC_EV_P4_RESPONSE:
1179ebccf1e3SJoseph Koshy 		break;
1180ebccf1e3SJoseph Koshy 	case PMC_EV_P4_FRONT_END_EVENT:
1181ebccf1e3SJoseph Koshy 		__P4SETMASK(fee);
1182ebccf1e3SJoseph Koshy 		break;
1183ebccf1e3SJoseph Koshy 	case PMC_EV_P4_EXECUTION_EVENT:
1184ebccf1e3SJoseph Koshy 		__P4SETMASK(ee);
1185ebccf1e3SJoseph Koshy 		break;
1186ebccf1e3SJoseph Koshy 	case PMC_EV_P4_REPLAY_EVENT:
1187ebccf1e3SJoseph Koshy 		__P4SETMASK(re);
1188ebccf1e3SJoseph Koshy 		break;
1189ebccf1e3SJoseph Koshy 	case PMC_EV_P4_INSTR_RETIRED:
1190ebccf1e3SJoseph Koshy 		__P4SETMASK(insret);
1191ebccf1e3SJoseph Koshy 		break;
1192ebccf1e3SJoseph Koshy 	case PMC_EV_P4_UOPS_RETIRED:
1193ebccf1e3SJoseph Koshy 		__P4SETMASK(ur);
1194ebccf1e3SJoseph Koshy 		break;
1195ebccf1e3SJoseph Koshy 	case PMC_EV_P4_UOP_TYPE:
1196ebccf1e3SJoseph Koshy 		__P4SETMASK(ut);
1197ebccf1e3SJoseph Koshy 		break;
1198ebccf1e3SJoseph Koshy 	case PMC_EV_P4_BRANCH_RETIRED:
1199ebccf1e3SJoseph Koshy 		__P4SETMASK(br);
1200ebccf1e3SJoseph Koshy 		break;
1201ebccf1e3SJoseph Koshy 	case PMC_EV_P4_MISPRED_BRANCH_RETIRED:
1202ebccf1e3SJoseph Koshy 		__P4SETMASK(mbr);
1203ebccf1e3SJoseph Koshy 		break;
1204ebccf1e3SJoseph Koshy 	case PMC_EV_P4_X87_ASSIST:
1205ebccf1e3SJoseph Koshy 		__P4SETMASK(xa);
1206ebccf1e3SJoseph Koshy 		break;
1207ebccf1e3SJoseph Koshy 	case PMC_EV_P4_MACHINE_CLEAR:
1208ebccf1e3SJoseph Koshy 		__P4SETMASK(machclr);
1209ebccf1e3SJoseph Koshy 		break;
1210ebccf1e3SJoseph Koshy 	default:
1211aa342b1fSJoseph Koshy 		return (-1);
1212ebccf1e3SJoseph Koshy 	}
1213ebccf1e3SJoseph Koshy 
1214ebccf1e3SJoseph Koshy 	/* process additional flags */
1215ebccf1e3SJoseph Koshy 	while ((p = strsep(&ctrspec, ",")) != NULL) {
1216ebccf1e3SJoseph Koshy 		if (KWPREFIXMATCH(p, P4_KW_ACTIVE)) {
1217ebccf1e3SJoseph Koshy 			q = strchr(p, '=');
1218ebccf1e3SJoseph Koshy 			if (*++q == '\0') /* skip '=' */
1219aa342b1fSJoseph Koshy 				return (-1);
1220ebccf1e3SJoseph Koshy 
1221789140c0SJoseph Koshy 			if (strcasecmp(q, P4_KW_ACTIVE_NONE) == 0)
1222ebccf1e3SJoseph Koshy 				cccractivemask = 0x0;
1223789140c0SJoseph Koshy 			else if (strcasecmp(q, P4_KW_ACTIVE_SINGLE) == 0)
1224ebccf1e3SJoseph Koshy 				cccractivemask = 0x1;
1225789140c0SJoseph Koshy 			else if (strcasecmp(q, P4_KW_ACTIVE_BOTH) == 0)
1226ebccf1e3SJoseph Koshy 				cccractivemask = 0x2;
1227789140c0SJoseph Koshy 			else if (strcasecmp(q, P4_KW_ACTIVE_ANY) == 0)
1228ebccf1e3SJoseph Koshy 				cccractivemask = 0x3;
1229ebccf1e3SJoseph Koshy 			else
1230aa342b1fSJoseph Koshy 				return (-1);
1231ebccf1e3SJoseph Koshy 
1232ebccf1e3SJoseph Koshy 		} else if (KWPREFIXMATCH(p, P4_KW_BUSREQTYPE)) {
1233ebccf1e3SJoseph Koshy 			if (has_busreqtype == 0)
1234aa342b1fSJoseph Koshy 				return (-1);
1235ebccf1e3SJoseph Koshy 
1236ebccf1e3SJoseph Koshy 			q = strchr(p, '=');
1237ebccf1e3SJoseph Koshy 			if (*++q == '\0') /* skip '=' */
1238aa342b1fSJoseph Koshy 				return (-1);
1239ebccf1e3SJoseph Koshy 
1240ebccf1e3SJoseph Koshy 			count = strtol(q, &e, 0);
1241ebccf1e3SJoseph Koshy 			if (e == q || *e != '\0')
1242aa342b1fSJoseph Koshy 				return (-1);
1243ebccf1e3SJoseph Koshy 			evmask = (evmask & ~0x1F) | (count & 0x1F);
1244ebccf1e3SJoseph Koshy 		} else if (KWMATCH(p, P4_KW_CASCADE))
1245ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_CASCADE;
1246ebccf1e3SJoseph Koshy 		else if (KWMATCH(p, P4_KW_EDGE))
1247ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_EDGE;
1248ebccf1e3SJoseph Koshy 		else if (KWMATCH(p, P4_KW_INV))
1249ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_INVERT;
1250ebccf1e3SJoseph Koshy 		else if (KWPREFIXMATCH(p, P4_KW_MASK "=")) {
1251ebccf1e3SJoseph Koshy 			if ((n = pmc_parse_mask(pmask, p, &evmask)) < 0)
1252aa342b1fSJoseph Koshy 				return (-1);
1253ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_QUALIFIER;
1254ebccf1e3SJoseph Koshy 		} else if (KWMATCH(p, P4_KW_OS))
1255ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_SYSTEM;
1256ebccf1e3SJoseph Koshy 		else if (KWMATCH(p, P4_KW_PRECISE))
1257ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_PRECISE;
1258ebccf1e3SJoseph Koshy 		else if (KWPREFIXMATCH(p, P4_KW_TAG "=")) {
1259ebccf1e3SJoseph Koshy 			if (has_tag == 0)
1260aa342b1fSJoseph Koshy 				return (-1);
1261ebccf1e3SJoseph Koshy 
1262ebccf1e3SJoseph Koshy 			q = strchr(p, '=');
1263ebccf1e3SJoseph Koshy 			if (*++q == '\0') /* skip '=' */
1264aa342b1fSJoseph Koshy 				return (-1);
1265ebccf1e3SJoseph Koshy 
1266ebccf1e3SJoseph Koshy 			count = strtol(q, &e, 0);
1267ebccf1e3SJoseph Koshy 			if (e == q || *e != '\0')
1268aa342b1fSJoseph Koshy 				return (-1);
1269ebccf1e3SJoseph Koshy 
1270ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_TAGGING;
1271f263522aSJoseph Koshy 			pmc_config->pm_md.pm_p4.pm_p4_escrconfig |=
1272ebccf1e3SJoseph Koshy 			    P4_ESCR_TO_TAG_VALUE(count);
1273ebccf1e3SJoseph Koshy 		} else if (KWPREFIXMATCH(p, P4_KW_THRESHOLD "=")) {
1274ebccf1e3SJoseph Koshy 			q = strchr(p, '=');
1275ebccf1e3SJoseph Koshy 			if (*++q == '\0') /* skip '=' */
1276aa342b1fSJoseph Koshy 				return (-1);
1277ebccf1e3SJoseph Koshy 
1278ebccf1e3SJoseph Koshy 			count = strtol(q, &e, 0);
1279ebccf1e3SJoseph Koshy 			if (e == q || *e != '\0')
1280aa342b1fSJoseph Koshy 				return (-1);
1281ebccf1e3SJoseph Koshy 
1282ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_THRESHOLD;
1283f263522aSJoseph Koshy 			pmc_config->pm_md.pm_p4.pm_p4_cccrconfig &=
1284f263522aSJoseph Koshy 			    ~P4_CCCR_THRESHOLD_MASK;
1285f263522aSJoseph Koshy 			pmc_config->pm_md.pm_p4.pm_p4_cccrconfig |=
1286f263522aSJoseph Koshy 			    P4_CCCR_TO_THRESHOLD(count);
1287ebccf1e3SJoseph Koshy 		} else if (KWMATCH(p, P4_KW_USR))
1288ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_USER;
1289ebccf1e3SJoseph Koshy 		else
1290aa342b1fSJoseph Koshy 			return (-1);
1291ebccf1e3SJoseph Koshy 	}
1292ebccf1e3SJoseph Koshy 
1293ebccf1e3SJoseph Koshy 	/* other post processing */
1294ebccf1e3SJoseph Koshy 	if (pe == PMC_EV_P4_IOQ_ALLOCATION ||
1295ebccf1e3SJoseph Koshy 	    pe == PMC_EV_P4_FSB_DATA_ACTIVITY ||
1296ebccf1e3SJoseph Koshy 	    pe == PMC_EV_P4_BSQ_ALLOCATION)
1297ebccf1e3SJoseph Koshy 		pmc_config->pm_caps |= PMC_CAP_EDGE;
1298ebccf1e3SJoseph Koshy 
1299ebccf1e3SJoseph Koshy 	/* fill in thread activity mask */
1300f263522aSJoseph Koshy 	pmc_config->pm_md.pm_p4.pm_p4_cccrconfig |=
1301ebccf1e3SJoseph Koshy 	    P4_CCCR_TO_ACTIVE_THREAD(cccractivemask);
1302ebccf1e3SJoseph Koshy 
1303ebccf1e3SJoseph Koshy 	if (evmask)
1304ebccf1e3SJoseph Koshy 		pmc_config->pm_caps |= PMC_CAP_QUALIFIER;
1305ebccf1e3SJoseph Koshy 
1306ebccf1e3SJoseph Koshy 	switch (pe) {
1307ebccf1e3SJoseph Koshy 	case PMC_EV_P4_FSB_DATA_ACTIVITY:
1308ebccf1e3SJoseph Koshy 		if ((evmask & 0x06) == 0x06 ||
1309ebccf1e3SJoseph Koshy 		    (evmask & 0x18) == 0x18)
1310aa342b1fSJoseph Koshy 			return (-1); /* can't have own+other bits together */
1311ebccf1e3SJoseph Koshy 		if (evmask == 0) /* default:drdy-{drv,own}+dbsy{drv,own} */
1312ebccf1e3SJoseph Koshy 			evmask = 0x1D;
1313ebccf1e3SJoseph Koshy 		break;
1314ebccf1e3SJoseph Koshy 	case PMC_EV_P4_MACHINE_CLEAR:
1315ebccf1e3SJoseph Koshy 		/* only one bit is allowed to be set */
1316ebccf1e3SJoseph Koshy 		if ((evmask & (evmask - 1)) != 0)
1317aa342b1fSJoseph Koshy 			return (-1);
1318ebccf1e3SJoseph Koshy 		if (evmask == 0) {
1319ebccf1e3SJoseph Koshy 			evmask = 0x1;	/* 'CLEAR' */
1320ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_QUALIFIER;
1321ebccf1e3SJoseph Koshy 		}
1322ebccf1e3SJoseph Koshy 		break;
1323ebccf1e3SJoseph Koshy 	default:
1324ebccf1e3SJoseph Koshy 		if (evmask == 0 && pmask) {
1325ebccf1e3SJoseph Koshy 			for (pm = pmask; pm->pm_name; pm++)
1326ebccf1e3SJoseph Koshy 				evmask |= pm->pm_value;
1327ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_QUALIFIER;
1328ebccf1e3SJoseph Koshy 		}
1329ebccf1e3SJoseph Koshy 	}
1330ebccf1e3SJoseph Koshy 
1331f263522aSJoseph Koshy 	pmc_config->pm_md.pm_p4.pm_p4_escrconfig =
1332f263522aSJoseph Koshy 	    P4_ESCR_TO_EVENT_MASK(evmask);
1333ebccf1e3SJoseph Koshy 
1334aa342b1fSJoseph Koshy 	return (0);
1335ebccf1e3SJoseph Koshy }
1336ebccf1e3SJoseph Koshy 
133786a65549SJoseph Koshy #endif
133886a65549SJoseph Koshy 
133986a65549SJoseph Koshy #if defined(__i386__)
134086a65549SJoseph Koshy 
1341ebccf1e3SJoseph Koshy /*
1342f263522aSJoseph Koshy  * Pentium style PMCs
1343f263522aSJoseph Koshy  */
1344f263522aSJoseph Koshy 
1345f263522aSJoseph Koshy static struct pmc_event_alias p5_aliases[] = {
13460b9b757dSJoseph Koshy 	EV_ALIAS("branches",		"p5-taken-branches"),
1347f263522aSJoseph Koshy 	EV_ALIAS("cycles",		"tsc"),
13480b9b757dSJoseph Koshy 	EV_ALIAS("dc-misses",		"p5-data-read-miss-or-write-miss"),
13490b9b757dSJoseph Koshy 	EV_ALIAS("ic-misses",		"p5-code-cache-miss"),
13500b9b757dSJoseph Koshy 	EV_ALIAS("instructions",	"p5-instructions-executed"),
13510b9b757dSJoseph Koshy 	EV_ALIAS("interrupts",		"p5-hardware-interrupts"),
13520b9b757dSJoseph Koshy 	EV_ALIAS("unhalted-cycles",
13530b9b757dSJoseph Koshy 	    "p5-number-of-cycles-not-in-halt-state"),
1354f263522aSJoseph Koshy 	EV_ALIAS(NULL, NULL)
1355f263522aSJoseph Koshy };
1356f263522aSJoseph Koshy 
1357f263522aSJoseph Koshy static int
1358f263522aSJoseph Koshy p5_allocate_pmc(enum pmc_event pe, char *ctrspec,
1359f263522aSJoseph Koshy     struct pmc_op_pmcallocate *pmc_config)
1360f263522aSJoseph Koshy {
1361aa342b1fSJoseph Koshy 	return (-1 || pe || ctrspec || pmc_config); /* shut up gcc */
1362f263522aSJoseph Koshy }
1363f263522aSJoseph Koshy 
1364f263522aSJoseph Koshy /*
1365ebccf1e3SJoseph Koshy  * Pentium Pro style PMCs.  These PMCs are found in Pentium II, Pentium III,
1366ebccf1e3SJoseph Koshy  * and Pentium M CPUs.
1367ebccf1e3SJoseph Koshy  */
1368ebccf1e3SJoseph Koshy 
1369ebccf1e3SJoseph Koshy static struct pmc_event_alias p6_aliases[] = {
1370ebccf1e3SJoseph Koshy 	EV_ALIAS("branches",		"p6-br-inst-retired"),
1371ebccf1e3SJoseph Koshy 	EV_ALIAS("branch-mispredicts",	"p6-br-miss-pred-retired"),
1372ebccf1e3SJoseph Koshy 	EV_ALIAS("cycles",		"tsc"),
1373d56c5d4bSJoseph Koshy 	EV_ALIAS("dc-misses",		"p6-dcu-lines-in"),
137473e2d811SJoseph Koshy 	EV_ALIAS("ic-misses",		"p6-ifu-fetch-miss"),
1375ebccf1e3SJoseph Koshy 	EV_ALIAS("instructions",	"p6-inst-retired"),
1376ebccf1e3SJoseph Koshy 	EV_ALIAS("interrupts",		"p6-hw-int-rx"),
1377177a2f22SJoseph Koshy 	EV_ALIAS("unhalted-cycles",	"p6-cpu-clk-unhalted"),
1378ebccf1e3SJoseph Koshy 	EV_ALIAS(NULL, NULL)
1379ebccf1e3SJoseph Koshy };
1380ebccf1e3SJoseph Koshy 
1381ebccf1e3SJoseph Koshy #define	P6_KW_CMASK	"cmask"
1382ebccf1e3SJoseph Koshy #define	P6_KW_EDGE	"edge"
1383ebccf1e3SJoseph Koshy #define	P6_KW_INV	"inv"
1384ebccf1e3SJoseph Koshy #define	P6_KW_OS	"os"
1385ebccf1e3SJoseph Koshy #define	P6_KW_UMASK	"umask"
1386ebccf1e3SJoseph Koshy #define	P6_KW_USR	"usr"
1387ebccf1e3SJoseph Koshy 
1388ebccf1e3SJoseph Koshy static struct pmc_masks p6_mask_mesi[] = {
1389ebccf1e3SJoseph Koshy 	PMCMASK(m,	0x01),
1390ebccf1e3SJoseph Koshy 	PMCMASK(e,	0x02),
1391ebccf1e3SJoseph Koshy 	PMCMASK(s,	0x04),
1392ebccf1e3SJoseph Koshy 	PMCMASK(i,	0x08),
1393ebccf1e3SJoseph Koshy 	NULLMASK
1394ebccf1e3SJoseph Koshy };
1395ebccf1e3SJoseph Koshy 
1396ebccf1e3SJoseph Koshy static struct pmc_masks p6_mask_mesihw[] = {
1397ebccf1e3SJoseph Koshy 	PMCMASK(m,	0x01),
1398ebccf1e3SJoseph Koshy 	PMCMASK(e,	0x02),
1399ebccf1e3SJoseph Koshy 	PMCMASK(s,	0x04),
1400ebccf1e3SJoseph Koshy 	PMCMASK(i,	0x08),
1401ebccf1e3SJoseph Koshy 	PMCMASK(nonhw,	0x00),
1402ebccf1e3SJoseph Koshy 	PMCMASK(hw,	0x10),
1403ebccf1e3SJoseph Koshy 	PMCMASK(both,	0x30),
1404ebccf1e3SJoseph Koshy 	NULLMASK
1405ebccf1e3SJoseph Koshy };
1406ebccf1e3SJoseph Koshy 
1407ebccf1e3SJoseph Koshy static struct pmc_masks p6_mask_hw[] = {
1408ebccf1e3SJoseph Koshy 	PMCMASK(nonhw,	0x00),
1409ebccf1e3SJoseph Koshy 	PMCMASK(hw,	0x10),
1410ebccf1e3SJoseph Koshy 	PMCMASK(both,	0x30),
1411ebccf1e3SJoseph Koshy 	NULLMASK
1412ebccf1e3SJoseph Koshy };
1413ebccf1e3SJoseph Koshy 
1414ebccf1e3SJoseph Koshy static struct pmc_masks p6_mask_any[] = {
1415ebccf1e3SJoseph Koshy 	PMCMASK(self,	0x00),
1416ebccf1e3SJoseph Koshy 	PMCMASK(any,	0x20),
1417ebccf1e3SJoseph Koshy 	NULLMASK
1418ebccf1e3SJoseph Koshy };
1419ebccf1e3SJoseph Koshy 
1420ebccf1e3SJoseph Koshy static struct pmc_masks p6_mask_ekp[] = {
1421ebccf1e3SJoseph Koshy 	PMCMASK(nta,	0x00),
1422ebccf1e3SJoseph Koshy 	PMCMASK(t1,	0x01),
1423ebccf1e3SJoseph Koshy 	PMCMASK(t2,	0x02),
1424ebccf1e3SJoseph Koshy 	PMCMASK(wos,	0x03),
1425ebccf1e3SJoseph Koshy 	NULLMASK
1426ebccf1e3SJoseph Koshy };
1427ebccf1e3SJoseph Koshy 
1428ebccf1e3SJoseph Koshy static struct pmc_masks p6_mask_pps[] = {
1429ebccf1e3SJoseph Koshy 	PMCMASK(packed-and-scalar, 0x00),
1430ebccf1e3SJoseph Koshy 	PMCMASK(scalar,	0x01),
1431ebccf1e3SJoseph Koshy 	NULLMASK
1432ebccf1e3SJoseph Koshy };
1433ebccf1e3SJoseph Koshy 
1434ebccf1e3SJoseph Koshy static struct pmc_masks p6_mask_mite[] = {
1435ebccf1e3SJoseph Koshy 	PMCMASK(packed-multiply,	 0x01),
1436ebccf1e3SJoseph Koshy 	PMCMASK(packed-shift,		0x02),
1437ebccf1e3SJoseph Koshy 	PMCMASK(pack,			0x04),
1438ebccf1e3SJoseph Koshy 	PMCMASK(unpack,			0x08),
1439ebccf1e3SJoseph Koshy 	PMCMASK(packed-logical,		0x10),
1440ebccf1e3SJoseph Koshy 	PMCMASK(packed-arithmetic,	0x20),
1441ebccf1e3SJoseph Koshy 	NULLMASK
1442ebccf1e3SJoseph Koshy };
1443ebccf1e3SJoseph Koshy 
1444ebccf1e3SJoseph Koshy static struct pmc_masks p6_mask_fmt[] = {
1445ebccf1e3SJoseph Koshy 	PMCMASK(mmxtofp,	0x00),
1446ebccf1e3SJoseph Koshy 	PMCMASK(fptommx,	0x01),
1447ebccf1e3SJoseph Koshy 	NULLMASK
1448ebccf1e3SJoseph Koshy };
1449ebccf1e3SJoseph Koshy 
1450ebccf1e3SJoseph Koshy static struct pmc_masks p6_mask_sr[] = {
1451ebccf1e3SJoseph Koshy 	PMCMASK(es,	0x01),
1452ebccf1e3SJoseph Koshy 	PMCMASK(ds,	0x02),
1453ebccf1e3SJoseph Koshy 	PMCMASK(fs,	0x04),
1454ebccf1e3SJoseph Koshy 	PMCMASK(gs,	0x08),
1455ebccf1e3SJoseph Koshy 	NULLMASK
1456ebccf1e3SJoseph Koshy };
1457ebccf1e3SJoseph Koshy 
1458ebccf1e3SJoseph Koshy static struct pmc_masks p6_mask_eet[] = {
1459ebccf1e3SJoseph Koshy 	PMCMASK(all,	0x00),
1460ebccf1e3SJoseph Koshy 	PMCMASK(freq,	0x02),
1461ebccf1e3SJoseph Koshy 	NULLMASK
1462ebccf1e3SJoseph Koshy };
1463ebccf1e3SJoseph Koshy 
1464ebccf1e3SJoseph Koshy static struct pmc_masks p6_mask_efur[] = {
1465ebccf1e3SJoseph Koshy 	PMCMASK(all,	0x00),
1466ebccf1e3SJoseph Koshy 	PMCMASK(loadop,	0x01),
1467ebccf1e3SJoseph Koshy 	PMCMASK(stdsta,	0x02),
1468ebccf1e3SJoseph Koshy 	NULLMASK
1469ebccf1e3SJoseph Koshy };
1470ebccf1e3SJoseph Koshy 
1471ebccf1e3SJoseph Koshy static struct pmc_masks p6_mask_essir[] = {
1472ebccf1e3SJoseph Koshy 	PMCMASK(sse-packed-single,	0x00),
1473ebccf1e3SJoseph Koshy 	PMCMASK(sse-packed-single-scalar-single, 0x01),
1474ebccf1e3SJoseph Koshy 	PMCMASK(sse2-packed-double,	0x02),
1475ebccf1e3SJoseph Koshy 	PMCMASK(sse2-scalar-double,	0x03),
1476ebccf1e3SJoseph Koshy 	NULLMASK
1477ebccf1e3SJoseph Koshy };
1478ebccf1e3SJoseph Koshy 
1479ebccf1e3SJoseph Koshy static struct pmc_masks p6_mask_esscir[] = {
1480ebccf1e3SJoseph Koshy 	PMCMASK(sse-packed-single,	0x00),
1481ebccf1e3SJoseph Koshy 	PMCMASK(sse-scalar-single,	0x01),
1482ebccf1e3SJoseph Koshy 	PMCMASK(sse2-packed-double,	0x02),
1483ebccf1e3SJoseph Koshy 	PMCMASK(sse2-scalar-double,	0x03),
1484ebccf1e3SJoseph Koshy 	NULLMASK
1485ebccf1e3SJoseph Koshy };
1486ebccf1e3SJoseph Koshy 
1487ebccf1e3SJoseph Koshy /* P6 event parser */
1488ebccf1e3SJoseph Koshy static int
1489ebccf1e3SJoseph Koshy p6_allocate_pmc(enum pmc_event pe, char *ctrspec,
1490ebccf1e3SJoseph Koshy     struct pmc_op_pmcallocate *pmc_config)
1491ebccf1e3SJoseph Koshy {
1492ebccf1e3SJoseph Koshy 	char *e, *p, *q;
1493ebccf1e3SJoseph Koshy 	uint32_t evmask;
1494ebccf1e3SJoseph Koshy 	int count, n;
1495ebccf1e3SJoseph Koshy 	const struct pmc_masks *pm, *pmask;
1496ebccf1e3SJoseph Koshy 
1497789140c0SJoseph Koshy 	pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE);
1498f263522aSJoseph Koshy 	pmc_config->pm_md.pm_ppro.pm_ppro_config = 0;
1499ebccf1e3SJoseph Koshy 
1500ebccf1e3SJoseph Koshy 	evmask = 0;
1501ebccf1e3SJoseph Koshy 
1502ebccf1e3SJoseph Koshy #define	P6MASKSET(M)	pmask = p6_mask_ ## M
1503ebccf1e3SJoseph Koshy 
1504ebccf1e3SJoseph Koshy 	switch(pe) {
1505ebccf1e3SJoseph Koshy 	case PMC_EV_P6_L2_IFETCH:	P6MASKSET(mesi); break;
1506ebccf1e3SJoseph Koshy 	case PMC_EV_P6_L2_LD:		P6MASKSET(mesi); break;
1507ebccf1e3SJoseph Koshy 	case PMC_EV_P6_L2_ST:		P6MASKSET(mesi); break;
1508ebccf1e3SJoseph Koshy 	case PMC_EV_P6_L2_RQSTS:	P6MASKSET(mesi); break;
1509ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_DRDY_CLOCKS:
1510ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_LOCK_CLOCKS:
1511ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_BRD:
1512ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_RFO:
1513ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRANS_WB:
1514ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_IFETCH:
1515ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_INVAL:
1516ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_PWR:
1517ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRANS_P:
1518ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRANS_IO:
1519ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_DEF:
1520ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_BURST:
1521ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_ANY:
1522ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_MEM:
1523ebccf1e3SJoseph Koshy 		P6MASKSET(any);	break;
1524ebccf1e3SJoseph Koshy 	case PMC_EV_P6_EMON_KNI_PREF_DISPATCHED:
1525ebccf1e3SJoseph Koshy 	case PMC_EV_P6_EMON_KNI_PREF_MISS:
1526ebccf1e3SJoseph Koshy 		P6MASKSET(ekp); break;
1527ebccf1e3SJoseph Koshy 	case PMC_EV_P6_EMON_KNI_INST_RETIRED:
1528ebccf1e3SJoseph Koshy 	case PMC_EV_P6_EMON_KNI_COMP_INST_RET:
1529ebccf1e3SJoseph Koshy 		P6MASKSET(pps);	break;
1530ebccf1e3SJoseph Koshy 	case PMC_EV_P6_MMX_INSTR_TYPE_EXEC:
1531ebccf1e3SJoseph Koshy 		P6MASKSET(mite); break;
1532ebccf1e3SJoseph Koshy 	case PMC_EV_P6_FP_MMX_TRANS:
1533ebccf1e3SJoseph Koshy 		P6MASKSET(fmt);	break;
1534ebccf1e3SJoseph Koshy 	case PMC_EV_P6_SEG_RENAME_STALLS:
1535ebccf1e3SJoseph Koshy 	case PMC_EV_P6_SEG_REG_RENAMES:
1536ebccf1e3SJoseph Koshy 		P6MASKSET(sr);	break;
1537ebccf1e3SJoseph Koshy 	case PMC_EV_P6_EMON_EST_TRANS:
1538ebccf1e3SJoseph Koshy 		P6MASKSET(eet);	break;
1539ebccf1e3SJoseph Koshy 	case PMC_EV_P6_EMON_FUSED_UOPS_RET:
1540ebccf1e3SJoseph Koshy 		P6MASKSET(efur); break;
1541ebccf1e3SJoseph Koshy 	case PMC_EV_P6_EMON_SSE_SSE2_INST_RETIRED:
1542ebccf1e3SJoseph Koshy 		P6MASKSET(essir); break;
1543ebccf1e3SJoseph Koshy 	case PMC_EV_P6_EMON_SSE_SSE2_COMP_INST_RETIRED:
1544ebccf1e3SJoseph Koshy 		P6MASKSET(esscir); break;
1545ebccf1e3SJoseph Koshy 	default:
1546ebccf1e3SJoseph Koshy 		pmask = NULL;
1547ebccf1e3SJoseph Koshy 		break;
1548ebccf1e3SJoseph Koshy 	}
1549ebccf1e3SJoseph Koshy 
1550ebccf1e3SJoseph Koshy 	/* Pentium M PMCs have a few events with different semantics */
1551ebccf1e3SJoseph Koshy 	if (cpu_info.pm_cputype == PMC_CPU_INTEL_PM) {
1552ebccf1e3SJoseph Koshy 		if (pe == PMC_EV_P6_L2_LD ||
1553ebccf1e3SJoseph Koshy 		    pe == PMC_EV_P6_L2_LINES_IN ||
1554ebccf1e3SJoseph Koshy 		    pe == PMC_EV_P6_L2_LINES_OUT)
1555ebccf1e3SJoseph Koshy 			P6MASKSET(mesihw);
1556ebccf1e3SJoseph Koshy 		else if (pe == PMC_EV_P6_L2_M_LINES_OUTM)
1557ebccf1e3SJoseph Koshy 			P6MASKSET(hw);
1558ebccf1e3SJoseph Koshy 	}
1559ebccf1e3SJoseph Koshy 
1560ebccf1e3SJoseph Koshy 	/* Parse additional modifiers if present */
1561ebccf1e3SJoseph Koshy 	while ((p = strsep(&ctrspec, ",")) != NULL) {
1562ebccf1e3SJoseph Koshy 		if (KWPREFIXMATCH(p, P6_KW_CMASK "=")) {
1563ebccf1e3SJoseph Koshy 			q = strchr(p, '=');
1564ebccf1e3SJoseph Koshy 			if (*++q == '\0') /* skip '=' */
1565aa342b1fSJoseph Koshy 				return (-1);
1566ebccf1e3SJoseph Koshy 			count = strtol(q, &e, 0);
1567ebccf1e3SJoseph Koshy 			if (e == q || *e != '\0')
1568aa342b1fSJoseph Koshy 				return (-1);
1569ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_THRESHOLD;
1570f263522aSJoseph Koshy 			pmc_config->pm_md.pm_ppro.pm_ppro_config |=
1571f263522aSJoseph Koshy 			    P6_EVSEL_TO_CMASK(count);
1572ebccf1e3SJoseph Koshy 		} else if (KWMATCH(p, P6_KW_EDGE)) {
1573ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_EDGE;
1574ebccf1e3SJoseph Koshy 		} else if (KWMATCH(p, P6_KW_INV)) {
1575ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_INVERT;
1576ebccf1e3SJoseph Koshy 		} else if (KWMATCH(p, P6_KW_OS)) {
1577ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_SYSTEM;
1578ebccf1e3SJoseph Koshy 		} else if (KWPREFIXMATCH(p, P6_KW_UMASK "=")) {
1579ebccf1e3SJoseph Koshy 			evmask = 0;
1580ebccf1e3SJoseph Koshy 			if ((n = pmc_parse_mask(pmask, p, &evmask)) < 0)
1581aa342b1fSJoseph Koshy 				return (-1);
1582ebccf1e3SJoseph Koshy 			if ((pe == PMC_EV_P6_BUS_DRDY_CLOCKS ||
1583ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_BUS_LOCK_CLOCKS ||
1584ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_BUS_TRAN_BRD ||
1585ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_BUS_TRAN_RFO ||
1586ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_BUS_TRAN_IFETCH ||
1587ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_BUS_TRAN_INVAL ||
1588ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_BUS_TRAN_PWR ||
1589ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_BUS_TRAN_DEF ||
1590ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_BUS_TRAN_BURST ||
1591ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_BUS_TRAN_ANY ||
1592ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_BUS_TRAN_MEM ||
1593ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_BUS_TRANS_IO ||
1594ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_BUS_TRANS_P ||
1595ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_BUS_TRANS_WB ||
1596ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_EMON_EST_TRANS ||
1597ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_EMON_FUSED_UOPS_RET ||
1598ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_EMON_KNI_COMP_INST_RET ||
1599ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_EMON_KNI_INST_RETIRED ||
1600ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_EMON_KNI_PREF_DISPATCHED ||
1601ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_EMON_KNI_PREF_MISS ||
1602ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_EMON_SSE_SSE2_COMP_INST_RETIRED ||
1603ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_EMON_SSE_SSE2_INST_RETIRED ||
1604ebccf1e3SJoseph Koshy 			     pe == PMC_EV_P6_FP_MMX_TRANS)
1605aa342b1fSJoseph Koshy 			    && (n > 1))	/* Only one mask keyword is allowed. */
1606aa342b1fSJoseph Koshy 				return (-1);
1607ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_QUALIFIER;
1608ebccf1e3SJoseph Koshy 		} else if (KWMATCH(p, P6_KW_USR)) {
1609ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_USER;
1610ebccf1e3SJoseph Koshy 		} else
1611aa342b1fSJoseph Koshy 			return (-1);
1612ebccf1e3SJoseph Koshy 	}
1613ebccf1e3SJoseph Koshy 
1614ebccf1e3SJoseph Koshy 	/* post processing */
1615ebccf1e3SJoseph Koshy 	switch (pe) {
1616ebccf1e3SJoseph Koshy 
1617ebccf1e3SJoseph Koshy 		/*
1618ebccf1e3SJoseph Koshy 		 * The following events default to an evmask of 0
1619ebccf1e3SJoseph Koshy 		 */
1620ebccf1e3SJoseph Koshy 
1621ebccf1e3SJoseph Koshy 		/* default => 'self' */
1622ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_DRDY_CLOCKS:
1623ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_LOCK_CLOCKS:
1624ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_BRD:
1625ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_RFO:
1626ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRANS_WB:
1627ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_IFETCH:
1628ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_INVAL:
1629ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_PWR:
1630ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRANS_P:
1631ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRANS_IO:
1632ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_DEF:
1633ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_BURST:
1634ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_ANY:
1635ebccf1e3SJoseph Koshy 	case PMC_EV_P6_BUS_TRAN_MEM:
1636ebccf1e3SJoseph Koshy 
1637ebccf1e3SJoseph Koshy 		/* default => 'nta' */
1638ebccf1e3SJoseph Koshy 	case PMC_EV_P6_EMON_KNI_PREF_DISPATCHED:
1639ebccf1e3SJoseph Koshy 	case PMC_EV_P6_EMON_KNI_PREF_MISS:
1640ebccf1e3SJoseph Koshy 
1641ebccf1e3SJoseph Koshy 		/* default => 'packed and scalar' */
1642ebccf1e3SJoseph Koshy 	case PMC_EV_P6_EMON_KNI_INST_RETIRED:
1643ebccf1e3SJoseph Koshy 	case PMC_EV_P6_EMON_KNI_COMP_INST_RET:
1644ebccf1e3SJoseph Koshy 
1645ebccf1e3SJoseph Koshy 		/* default => 'mmx to fp transitions' */
1646ebccf1e3SJoseph Koshy 	case PMC_EV_P6_FP_MMX_TRANS:
1647ebccf1e3SJoseph Koshy 
1648ebccf1e3SJoseph Koshy 		/* default => 'SSE Packed Single' */
1649ebccf1e3SJoseph Koshy 	case PMC_EV_P6_EMON_SSE_SSE2_INST_RETIRED:
1650ebccf1e3SJoseph Koshy 	case PMC_EV_P6_EMON_SSE_SSE2_COMP_INST_RETIRED:
1651ebccf1e3SJoseph Koshy 
1652ebccf1e3SJoseph Koshy 		/* default => 'all fused micro-ops' */
1653ebccf1e3SJoseph Koshy 	case PMC_EV_P6_EMON_FUSED_UOPS_RET:
1654ebccf1e3SJoseph Koshy 
1655ebccf1e3SJoseph Koshy 		/* default => 'all transitions' */
1656ebccf1e3SJoseph Koshy 	case PMC_EV_P6_EMON_EST_TRANS:
1657ebccf1e3SJoseph Koshy 		break;
1658ebccf1e3SJoseph Koshy 
1659ebccf1e3SJoseph Koshy 	case PMC_EV_P6_MMX_UOPS_EXEC:
1660ebccf1e3SJoseph Koshy 		evmask = 0x0F;		/* only value allowed */
1661ebccf1e3SJoseph Koshy 		break;
1662ebccf1e3SJoseph Koshy 
1663ebccf1e3SJoseph Koshy 	default:
1664ebccf1e3SJoseph Koshy 		/*
1665ebccf1e3SJoseph Koshy 		 * For all other events, set the default event mask
1666ebccf1e3SJoseph Koshy 		 * to a logical OR of all the allowed event mask bits.
1667ebccf1e3SJoseph Koshy 		 */
1668ebccf1e3SJoseph Koshy 		if (evmask == 0 && pmask) {
1669ebccf1e3SJoseph Koshy 			for (pm = pmask; pm->pm_name; pm++)
1670ebccf1e3SJoseph Koshy 				evmask |= pm->pm_value;
1671ebccf1e3SJoseph Koshy 			pmc_config->pm_caps |= PMC_CAP_QUALIFIER;
1672ebccf1e3SJoseph Koshy 		}
1673ebccf1e3SJoseph Koshy 
1674ebccf1e3SJoseph Koshy 		break;
1675ebccf1e3SJoseph Koshy 	}
1676ebccf1e3SJoseph Koshy 
1677ebccf1e3SJoseph Koshy 	if (pmc_config->pm_caps & PMC_CAP_QUALIFIER)
1678f263522aSJoseph Koshy 		pmc_config->pm_md.pm_ppro.pm_ppro_config |=
1679f263522aSJoseph Koshy 		    P6_EVSEL_TO_UMASK(evmask);
1680ebccf1e3SJoseph Koshy 
1681aa342b1fSJoseph Koshy 	return (0);
1682ebccf1e3SJoseph Koshy }
1683ebccf1e3SJoseph Koshy 
1684ebccf1e3SJoseph Koshy #endif
1685ebccf1e3SJoseph Koshy 
1686789140c0SJoseph Koshy #if	defined(__i386__) || defined(__amd64__)
1687789140c0SJoseph Koshy static int
1688789140c0SJoseph Koshy tsc_allocate_pmc(enum pmc_event pe, char *ctrspec,
1689789140c0SJoseph Koshy     struct pmc_op_pmcallocate *pmc_config)
1690789140c0SJoseph Koshy {
1691789140c0SJoseph Koshy 	if (pe != PMC_EV_TSC_TSC)
1692789140c0SJoseph Koshy 		return (-1);
1693789140c0SJoseph Koshy 
1694789140c0SJoseph Koshy 	/* TSC events must be unqualified. */
1695789140c0SJoseph Koshy 	if (ctrspec && *ctrspec != '\0')
1696789140c0SJoseph Koshy 		return (-1);
1697789140c0SJoseph Koshy 
1698789140c0SJoseph Koshy 	pmc_config->pm_md.pm_amd.pm_amd_config = 0;
1699789140c0SJoseph Koshy 	pmc_config->pm_caps |= PMC_CAP_READ;
1700789140c0SJoseph Koshy 
1701789140c0SJoseph Koshy 	return (0);
1702789140c0SJoseph Koshy }
1703789140c0SJoseph Koshy #endif
1704789140c0SJoseph Koshy 
1705789140c0SJoseph Koshy /*
1706789140c0SJoseph Koshy  * Match an event name `name' with its canonical form.
1707789140c0SJoseph Koshy  *
1708789140c0SJoseph Koshy  * Matches are case insensitive and spaces, underscores and hyphen
1709789140c0SJoseph Koshy  * characters are considered to match each other.
1710789140c0SJoseph Koshy  *
1711789140c0SJoseph Koshy  * Returns 1 for a match, 0 otherwise.
1712789140c0SJoseph Koshy  */
1713789140c0SJoseph Koshy 
1714789140c0SJoseph Koshy static int
1715789140c0SJoseph Koshy pmc_match_event_name(const char *name, const char *canonicalname)
1716789140c0SJoseph Koshy {
1717789140c0SJoseph Koshy 	int cc, nc;
1718789140c0SJoseph Koshy 	const unsigned char *c, *n;
1719789140c0SJoseph Koshy 
1720789140c0SJoseph Koshy 	c = (const unsigned char *) canonicalname;
1721789140c0SJoseph Koshy 	n = (const unsigned char *) name;
1722789140c0SJoseph Koshy 
1723789140c0SJoseph Koshy 	for (; (nc = *n) && (cc = *c); n++, c++) {
1724789140c0SJoseph Koshy 
1725789140c0SJoseph Koshy 		if (toupper(nc) == cc)
1726789140c0SJoseph Koshy 			continue;
1727789140c0SJoseph Koshy 
1728789140c0SJoseph Koshy 		if ((nc == ' ' || nc == '_' || nc == '-') &&
1729789140c0SJoseph Koshy 		    (cc == ' ' || cc == '_' || cc == '-'))
1730789140c0SJoseph Koshy 			continue;
1731789140c0SJoseph Koshy 
1732789140c0SJoseph Koshy 		return (0);
1733789140c0SJoseph Koshy 	}
1734789140c0SJoseph Koshy 
1735789140c0SJoseph Koshy 	if (*n == '\0' && *c == '\0')
1736789140c0SJoseph Koshy 		return (1);
1737789140c0SJoseph Koshy 
1738789140c0SJoseph Koshy 	return (0);
1739789140c0SJoseph Koshy }
1740789140c0SJoseph Koshy 
1741789140c0SJoseph Koshy /*
1742789140c0SJoseph Koshy  * Match an event name against all the event named supported by a
1743789140c0SJoseph Koshy  * PMC class.
1744789140c0SJoseph Koshy  *
1745789140c0SJoseph Koshy  * Returns an event descriptor pointer on match or NULL otherwise.
1746789140c0SJoseph Koshy  */
1747789140c0SJoseph Koshy static const struct pmc_event_descr *
1748789140c0SJoseph Koshy pmc_match_event_class(const char *name,
1749789140c0SJoseph Koshy     const struct pmc_class_descr *pcd)
1750789140c0SJoseph Koshy {
1751789140c0SJoseph Koshy 	size_t n;
1752789140c0SJoseph Koshy 	const struct pmc_event_descr *ev;
1753789140c0SJoseph Koshy 
1754789140c0SJoseph Koshy 	ev = pcd->pm_evc_event_table;
1755789140c0SJoseph Koshy 	for (n = 0; n < pcd->pm_evc_event_table_size; n++, ev++)
1756789140c0SJoseph Koshy 		if (pmc_match_event_name(name, ev->pm_ev_name))
1757789140c0SJoseph Koshy 			return (ev);
1758789140c0SJoseph Koshy 
1759789140c0SJoseph Koshy 	return (NULL);
1760789140c0SJoseph Koshy }
1761789140c0SJoseph Koshy 
1762789140c0SJoseph Koshy static int
1763789140c0SJoseph Koshy pmc_mdep_is_compatible_class(enum pmc_class pc)
1764789140c0SJoseph Koshy {
1765789140c0SJoseph Koshy 	size_t n;
1766789140c0SJoseph Koshy 
1767789140c0SJoseph Koshy 	for (n = 0; n < pmc_mdep_class_list_size; n++)
1768789140c0SJoseph Koshy 		if (pmc_mdep_class_list[n] == pc)
1769789140c0SJoseph Koshy 			return (1);
1770789140c0SJoseph Koshy 	return (0);
1771789140c0SJoseph Koshy }
1772789140c0SJoseph Koshy 
1773ebccf1e3SJoseph Koshy /*
1774ebccf1e3SJoseph Koshy  * API entry points
1775ebccf1e3SJoseph Koshy  */
1776ebccf1e3SJoseph Koshy 
1777ebccf1e3SJoseph Koshy int
1778ebccf1e3SJoseph Koshy pmc_allocate(const char *ctrspec, enum pmc_mode mode,
1779ebccf1e3SJoseph Koshy     uint32_t flags, int cpu, pmc_id_t *pmcid)
1780ebccf1e3SJoseph Koshy {
1781789140c0SJoseph Koshy 	size_t n;
1782ebccf1e3SJoseph Koshy 	int retval;
1783ebccf1e3SJoseph Koshy 	char *r, *spec_copy;
1784ebccf1e3SJoseph Koshy 	const char *ctrname;
1785789140c0SJoseph Koshy 	const struct pmc_event_descr *ev;
1786789140c0SJoseph Koshy 	const struct pmc_event_alias *alias;
1787ebccf1e3SJoseph Koshy 	struct pmc_op_pmcallocate pmc_config;
1788789140c0SJoseph Koshy 	const struct pmc_class_descr *pcd;
1789ebccf1e3SJoseph Koshy 
1790ebccf1e3SJoseph Koshy 	spec_copy = NULL;
1791ebccf1e3SJoseph Koshy 	retval    = -1;
1792ebccf1e3SJoseph Koshy 
1793ebccf1e3SJoseph Koshy 	if (mode != PMC_MODE_SS && mode != PMC_MODE_TS &&
1794ebccf1e3SJoseph Koshy 	    mode != PMC_MODE_SC && mode != PMC_MODE_TC) {
1795ebccf1e3SJoseph Koshy 		errno = EINVAL;
1796ebccf1e3SJoseph Koshy 		goto out;
1797ebccf1e3SJoseph Koshy 	}
1798ebccf1e3SJoseph Koshy 
1799ebccf1e3SJoseph Koshy 	/* replace an event alias with the canonical event specifier */
1800ebccf1e3SJoseph Koshy 	if (pmc_mdep_event_aliases)
1801789140c0SJoseph Koshy 		for (alias = pmc_mdep_event_aliases; alias->pm_alias; alias++)
1802789140c0SJoseph Koshy 			if (!strcasecmp(ctrspec, alias->pm_alias)) {
1803789140c0SJoseph Koshy 				spec_copy = strdup(alias->pm_spec);
1804ebccf1e3SJoseph Koshy 				break;
1805ebccf1e3SJoseph Koshy 			}
1806ebccf1e3SJoseph Koshy 
1807ebccf1e3SJoseph Koshy 	if (spec_copy == NULL)
1808ebccf1e3SJoseph Koshy 		spec_copy = strdup(ctrspec);
1809ebccf1e3SJoseph Koshy 
1810ebccf1e3SJoseph Koshy 	r = spec_copy;
1811ebccf1e3SJoseph Koshy 	ctrname = strsep(&r, ",");
1812ebccf1e3SJoseph Koshy 
1813789140c0SJoseph Koshy 	/*
1814789140c0SJoseph Koshy 	 * If a explicit class prefix was given by the user, restrict the
1815789140c0SJoseph Koshy 	 * search for the event to the specified PMC class.
1816789140c0SJoseph Koshy 	 */
1817789140c0SJoseph Koshy 	ev = NULL;
1818789140c0SJoseph Koshy 	for (n = 0; n < pmc_event_class_table_size; n++) {
1819789140c0SJoseph Koshy 		pcd = &pmc_class_table[n];
1820789140c0SJoseph Koshy 		if (pmc_mdep_is_compatible_class(pcd->pm_evc_class) &&
1821789140c0SJoseph Koshy 		    strncasecmp(ctrname, pcd->pm_evc_name,
1822789140c0SJoseph Koshy 				pcd->pm_evc_name_size) == 0) {
1823789140c0SJoseph Koshy 			if ((ev = pmc_match_event_class(ctrname +
1824789140c0SJoseph Koshy 			    pcd->pm_evc_name_size, pcd)) == NULL) {
1825789140c0SJoseph Koshy 				errno = EINVAL;
1826789140c0SJoseph Koshy 				goto out;
1827789140c0SJoseph Koshy 			}
1828ebccf1e3SJoseph Koshy 			break;
1829789140c0SJoseph Koshy 		}
1830789140c0SJoseph Koshy 	}
1831ebccf1e3SJoseph Koshy 
1832789140c0SJoseph Koshy 	/*
1833789140c0SJoseph Koshy 	 * Otherwise, search for this event in all compatible PMC
1834789140c0SJoseph Koshy 	 * classes.
1835789140c0SJoseph Koshy 	 */
1836789140c0SJoseph Koshy 	for (n = 0; ev == NULL && n < pmc_event_class_table_size; n++) {
1837789140c0SJoseph Koshy 		pcd = &pmc_class_table[n];
1838789140c0SJoseph Koshy 		if (pmc_mdep_is_compatible_class(pcd->pm_evc_class))
1839789140c0SJoseph Koshy 			ev = pmc_match_event_class(ctrname, pcd);
1840789140c0SJoseph Koshy 	}
1841789140c0SJoseph Koshy 
1842789140c0SJoseph Koshy 	if (ev == NULL) {
1843ebccf1e3SJoseph Koshy 		errno = EINVAL;
1844ebccf1e3SJoseph Koshy 		goto out;
1845ebccf1e3SJoseph Koshy 	}
1846ebccf1e3SJoseph Koshy 
1847ebccf1e3SJoseph Koshy 	bzero(&pmc_config, sizeof(pmc_config));
1848789140c0SJoseph Koshy 	pmc_config.pm_ev    = ev->pm_ev_code;
1849789140c0SJoseph Koshy 	pmc_config.pm_class = pcd->pm_evc_class;
1850ebccf1e3SJoseph Koshy 	pmc_config.pm_cpu   = cpu;
1851ebccf1e3SJoseph Koshy 	pmc_config.pm_mode  = mode;
1852ebccf1e3SJoseph Koshy 	pmc_config.pm_flags = flags;
1853ebccf1e3SJoseph Koshy 
1854ebccf1e3SJoseph Koshy 	if (PMC_IS_SAMPLING_MODE(mode))
1855ebccf1e3SJoseph Koshy 		pmc_config.pm_caps |= PMC_CAP_INTERRUPT;
1856ebccf1e3SJoseph Koshy 
1857789140c0SJoseph Koshy  	if (pcd->pm_evc_allocate_pmc(ev->pm_ev_code, r, &pmc_config) < 0) {
1858ebccf1e3SJoseph Koshy 		errno = EINVAL;
1859ebccf1e3SJoseph Koshy 		goto out;
1860ebccf1e3SJoseph Koshy 	}
1861ebccf1e3SJoseph Koshy 
1862ebccf1e3SJoseph Koshy 	if (PMC_CALL(PMCALLOCATE, &pmc_config) < 0)
1863ebccf1e3SJoseph Koshy 		goto out;
1864ebccf1e3SJoseph Koshy 
1865ebccf1e3SJoseph Koshy 	*pmcid = pmc_config.pm_pmcid;
1866ebccf1e3SJoseph Koshy 
1867ebccf1e3SJoseph Koshy 	retval = 0;
1868ebccf1e3SJoseph Koshy 
1869ebccf1e3SJoseph Koshy  out:
1870ebccf1e3SJoseph Koshy 	if (spec_copy)
1871ebccf1e3SJoseph Koshy 		free(spec_copy);
1872ebccf1e3SJoseph Koshy 
1873aa342b1fSJoseph Koshy 	return (retval);
1874ebccf1e3SJoseph Koshy }
1875ebccf1e3SJoseph Koshy 
1876ebccf1e3SJoseph Koshy int
1877ebccf1e3SJoseph Koshy pmc_attach(pmc_id_t pmc, pid_t pid)
1878ebccf1e3SJoseph Koshy {
1879ebccf1e3SJoseph Koshy 	struct pmc_op_pmcattach pmc_attach_args;
1880ebccf1e3SJoseph Koshy 
1881ebccf1e3SJoseph Koshy 	pmc_attach_args.pm_pmc = pmc;
1882ebccf1e3SJoseph Koshy 	pmc_attach_args.pm_pid = pid;
1883ebccf1e3SJoseph Koshy 
1884aa342b1fSJoseph Koshy 	return (PMC_CALL(PMCATTACH, &pmc_attach_args));
1885ebccf1e3SJoseph Koshy }
1886ebccf1e3SJoseph Koshy 
1887ebccf1e3SJoseph Koshy int
1888c5153e19SJoseph Koshy pmc_capabilities(pmc_id_t pmcid, uint32_t *caps)
1889c5153e19SJoseph Koshy {
1890c5153e19SJoseph Koshy 	unsigned int i;
1891c5153e19SJoseph Koshy 	enum pmc_class cl;
1892c5153e19SJoseph Koshy 
1893c5153e19SJoseph Koshy 	cl = PMC_ID_TO_CLASS(pmcid);
1894c5153e19SJoseph Koshy 	for (i = 0; i < cpu_info.pm_nclass; i++)
1895c5153e19SJoseph Koshy 		if (cpu_info.pm_classes[i].pm_class == cl) {
1896c5153e19SJoseph Koshy 			*caps = cpu_info.pm_classes[i].pm_caps;
1897aa342b1fSJoseph Koshy 			return (0);
1898c5153e19SJoseph Koshy 		}
1899484202faSJoseph Koshy 	errno = EINVAL;
1900484202faSJoseph Koshy 	return (-1);
1901c5153e19SJoseph Koshy }
1902c5153e19SJoseph Koshy 
1903f263522aSJoseph Koshy int
1904f263522aSJoseph Koshy pmc_configure_logfile(int fd)
1905ebccf1e3SJoseph Koshy {
1906f263522aSJoseph Koshy 	struct pmc_op_configurelog cla;
1907f263522aSJoseph Koshy 
1908f263522aSJoseph Koshy 	cla.pm_logfd = fd;
1909f263522aSJoseph Koshy 	if (PMC_CALL(CONFIGURELOG, &cla) < 0)
1910aa342b1fSJoseph Koshy 		return (-1);
1911aa342b1fSJoseph Koshy 	return (0);
1912ebccf1e3SJoseph Koshy }
1913ebccf1e3SJoseph Koshy 
1914f263522aSJoseph Koshy int
1915f263522aSJoseph Koshy pmc_cpuinfo(const struct pmc_cpuinfo **pci)
1916ebccf1e3SJoseph Koshy {
1917f263522aSJoseph Koshy 	if (pmc_syscall == -1) {
1918f263522aSJoseph Koshy 		errno = ENXIO;
1919aa342b1fSJoseph Koshy 		return (-1);
1920ebccf1e3SJoseph Koshy 	}
1921ebccf1e3SJoseph Koshy 
19221455fcd3SJoseph Koshy 	*pci = &cpu_info;
1923aa342b1fSJoseph Koshy 	return (0);
1924ebccf1e3SJoseph Koshy }
1925ebccf1e3SJoseph Koshy 
1926f263522aSJoseph Koshy int
1927f263522aSJoseph Koshy pmc_detach(pmc_id_t pmc, pid_t pid)
1928ebccf1e3SJoseph Koshy {
1929f263522aSJoseph Koshy 	struct pmc_op_pmcattach pmc_detach_args;
1930ebccf1e3SJoseph Koshy 
1931f263522aSJoseph Koshy 	pmc_detach_args.pm_pmc = pmc;
1932f263522aSJoseph Koshy 	pmc_detach_args.pm_pid = pid;
1933aa342b1fSJoseph Koshy 	return (PMC_CALL(PMCDETACH, &pmc_detach_args));
1934ebccf1e3SJoseph Koshy }
1935ebccf1e3SJoseph Koshy 
1936f263522aSJoseph Koshy int
1937f263522aSJoseph Koshy pmc_disable(int cpu, int pmc)
1938ebccf1e3SJoseph Koshy {
1939f263522aSJoseph Koshy 	struct pmc_op_pmcadmin ssa;
1940ebccf1e3SJoseph Koshy 
1941f263522aSJoseph Koshy 	ssa.pm_cpu = cpu;
1942f263522aSJoseph Koshy 	ssa.pm_pmc = pmc;
1943f263522aSJoseph Koshy 	ssa.pm_state = PMC_STATE_DISABLED;
1944aa342b1fSJoseph Koshy 	return (PMC_CALL(PMCADMIN, &ssa));
1945ebccf1e3SJoseph Koshy }
1946ebccf1e3SJoseph Koshy 
1947f263522aSJoseph Koshy int
1948f263522aSJoseph Koshy pmc_enable(int cpu, int pmc)
1949ebccf1e3SJoseph Koshy {
1950f263522aSJoseph Koshy 	struct pmc_op_pmcadmin ssa;
1951ebccf1e3SJoseph Koshy 
1952f263522aSJoseph Koshy 	ssa.pm_cpu = cpu;
1953f263522aSJoseph Koshy 	ssa.pm_pmc = pmc;
1954f263522aSJoseph Koshy 	ssa.pm_state = PMC_STATE_FREE;
1955aa342b1fSJoseph Koshy 	return (PMC_CALL(PMCADMIN, &ssa));
1956ebccf1e3SJoseph Koshy }
1957ebccf1e3SJoseph Koshy 
1958ebccf1e3SJoseph Koshy /*
1959ebccf1e3SJoseph Koshy  * Return a list of events known to a given PMC class.  'cl' is the
1960ebccf1e3SJoseph Koshy  * PMC class identifier, 'eventnames' is the returned list of 'const
1961ebccf1e3SJoseph Koshy  * char *' pointers pointing to the names of the events. 'nevents' is
1962ebccf1e3SJoseph Koshy  * the number of event name pointers returned.
1963ebccf1e3SJoseph Koshy  *
1964ebccf1e3SJoseph Koshy  * The space for 'eventnames' is allocated using malloc(3).  The caller
1965ebccf1e3SJoseph Koshy  * is responsible for freeing this space when done.
1966ebccf1e3SJoseph Koshy  */
1967ebccf1e3SJoseph Koshy int
1968ebccf1e3SJoseph Koshy pmc_event_names_of_class(enum pmc_class cl, const char ***eventnames,
1969ebccf1e3SJoseph Koshy     int *nevents)
1970ebccf1e3SJoseph Koshy {
1971ebccf1e3SJoseph Koshy 	int count;
1972ebccf1e3SJoseph Koshy 	const char **names;
1973ebccf1e3SJoseph Koshy 	const struct pmc_event_descr *ev;
1974ebccf1e3SJoseph Koshy 
1975ebccf1e3SJoseph Koshy 	switch (cl)
1976ebccf1e3SJoseph Koshy 	{
1977ebccf1e3SJoseph Koshy 	case PMC_CLASS_TSC:
1978789140c0SJoseph Koshy 		ev = tsc_event_table;
1979789140c0SJoseph Koshy 		count = PMC_EVENT_TABLE_SIZE(tsc);
1980ebccf1e3SJoseph Koshy 		break;
1981ebccf1e3SJoseph Koshy 	case PMC_CLASS_K7:
1982789140c0SJoseph Koshy 		ev = k7_event_table;
1983789140c0SJoseph Koshy 		count = PMC_EVENT_TABLE_SIZE(k7);
1984ebccf1e3SJoseph Koshy 		break;
1985ebccf1e3SJoseph Koshy 	case PMC_CLASS_K8:
1986789140c0SJoseph Koshy 		ev = k8_event_table;
1987789140c0SJoseph Koshy 		count = PMC_EVENT_TABLE_SIZE(k8);
1988ebccf1e3SJoseph Koshy 		break;
1989ebccf1e3SJoseph Koshy 	case PMC_CLASS_P4:
1990789140c0SJoseph Koshy 		ev = p4_event_table;
1991789140c0SJoseph Koshy 		count = PMC_EVENT_TABLE_SIZE(p4);
1992789140c0SJoseph Koshy 		break;
1993789140c0SJoseph Koshy 	case PMC_CLASS_P5:
1994789140c0SJoseph Koshy 		ev = p5_event_table;
1995789140c0SJoseph Koshy 		count = PMC_EVENT_TABLE_SIZE(p5);
1996789140c0SJoseph Koshy 		break;
1997789140c0SJoseph Koshy 	case PMC_CLASS_P6:
1998789140c0SJoseph Koshy 		ev = p6_event_table;
1999789140c0SJoseph Koshy 		count = PMC_EVENT_TABLE_SIZE(p6);
2000ebccf1e3SJoseph Koshy 		break;
2001ebccf1e3SJoseph Koshy 	default:
2002ebccf1e3SJoseph Koshy 		errno = EINVAL;
2003aa342b1fSJoseph Koshy 		return (-1);
2004ebccf1e3SJoseph Koshy 	}
2005ebccf1e3SJoseph Koshy 
2006ebccf1e3SJoseph Koshy 	if ((names = malloc(count * sizeof(const char *))) == NULL)
2007aa342b1fSJoseph Koshy 		return (-1);
2008ebccf1e3SJoseph Koshy 
2009ebccf1e3SJoseph Koshy 	*eventnames = names;
2010ebccf1e3SJoseph Koshy 	*nevents = count;
2011ebccf1e3SJoseph Koshy 
2012ebccf1e3SJoseph Koshy 	for (;count--; ev++, names++)
2013ebccf1e3SJoseph Koshy 		*names = ev->pm_ev_name;
2014aa342b1fSJoseph Koshy 	return (0);
2015ebccf1e3SJoseph Koshy }
2016ebccf1e3SJoseph Koshy 
2017f263522aSJoseph Koshy int
2018f263522aSJoseph Koshy pmc_flush_logfile(void)
2019f263522aSJoseph Koshy {
2020aa342b1fSJoseph Koshy 	return (PMC_CALL(FLUSHLOG,0));
2021f263522aSJoseph Koshy }
2022ebccf1e3SJoseph Koshy 
2023ebccf1e3SJoseph Koshy int
2024f263522aSJoseph Koshy pmc_get_driver_stats(struct pmc_driverstats *ds)
2025ebccf1e3SJoseph Koshy {
2026f263522aSJoseph Koshy 	struct pmc_op_getdriverstats gms;
2027f263522aSJoseph Koshy 
2028f263522aSJoseph Koshy 	if (PMC_CALL(GETDRIVERSTATS, &gms) < 0)
2029aa342b1fSJoseph Koshy 		return (-1);
2030f263522aSJoseph Koshy 
2031f263522aSJoseph Koshy 	/* copy out fields in the current userland<->library interface */
2032f263522aSJoseph Koshy 	ds->pm_intr_ignored    = gms.pm_intr_ignored;
2033f263522aSJoseph Koshy 	ds->pm_intr_processed  = gms.pm_intr_processed;
2034f263522aSJoseph Koshy 	ds->pm_intr_bufferfull = gms.pm_intr_bufferfull;
2035f263522aSJoseph Koshy 	ds->pm_syscalls        = gms.pm_syscalls;
2036f263522aSJoseph Koshy 	ds->pm_syscall_errors  = gms.pm_syscall_errors;
2037f263522aSJoseph Koshy 	ds->pm_buffer_requests = gms.pm_buffer_requests;
2038f263522aSJoseph Koshy 	ds->pm_buffer_requests_failed = gms.pm_buffer_requests_failed;
2039f263522aSJoseph Koshy 	ds->pm_log_sweeps      = gms.pm_log_sweeps;
2040aa342b1fSJoseph Koshy 	return (0);
2041f263522aSJoseph Koshy }
2042f263522aSJoseph Koshy 
2043f263522aSJoseph Koshy int
2044f263522aSJoseph Koshy pmc_get_msr(pmc_id_t pmc, uint32_t *msr)
2045f263522aSJoseph Koshy {
2046f263522aSJoseph Koshy 	struct pmc_op_getmsr gm;
2047ebccf1e3SJoseph Koshy 
2048ebccf1e3SJoseph Koshy 	gm.pm_pmcid = pmc;
2049f263522aSJoseph Koshy 	if (PMC_CALL(PMCGETMSR, &gm) < 0)
2050aa342b1fSJoseph Koshy 		return (-1);
2051ebccf1e3SJoseph Koshy 	*msr = gm.pm_msr;
2052aa342b1fSJoseph Koshy 	return (0);
2053ebccf1e3SJoseph Koshy }
2054ebccf1e3SJoseph Koshy 
2055f263522aSJoseph Koshy int
2056f263522aSJoseph Koshy pmc_init(void)
2057f263522aSJoseph Koshy {
2058f263522aSJoseph Koshy 	int error, pmc_mod_id;
20591455fcd3SJoseph Koshy 	unsigned int n;
2060f263522aSJoseph Koshy 	uint32_t abi_version;
2061f263522aSJoseph Koshy 	struct module_stat pmc_modstat;
20621455fcd3SJoseph Koshy 	struct pmc_op_getcpuinfo op_cpu_info;
2063f263522aSJoseph Koshy 
2064f263522aSJoseph Koshy 	if (pmc_syscall != -1) /* already inited */
2065aa342b1fSJoseph Koshy 		return (0);
2066f263522aSJoseph Koshy 
2067f263522aSJoseph Koshy 	/* retrieve the system call number from the KLD */
2068f263522aSJoseph Koshy 	if ((pmc_mod_id = modfind(PMC_MODULE_NAME)) < 0)
2069aa342b1fSJoseph Koshy 		return (-1);
2070f263522aSJoseph Koshy 
2071f263522aSJoseph Koshy 	pmc_modstat.version = sizeof(struct module_stat);
2072f263522aSJoseph Koshy 	if ((error = modstat(pmc_mod_id, &pmc_modstat)) < 0)
2073aa342b1fSJoseph Koshy 		return (-1);
2074f263522aSJoseph Koshy 
2075f263522aSJoseph Koshy 	pmc_syscall = pmc_modstat.data.intval;
2076f263522aSJoseph Koshy 
2077f263522aSJoseph Koshy 	/* check the kernel module's ABI against our compiled-in version */
2078f263522aSJoseph Koshy 	abi_version = PMC_VERSION;
2079f263522aSJoseph Koshy 	if (PMC_CALL(GETMODULEVERSION, &abi_version) < 0)
2080f263522aSJoseph Koshy 		return (pmc_syscall = -1);
2081f263522aSJoseph Koshy 
2082f263522aSJoseph Koshy 	/* ignore patch & minor numbers for the comparision */
2083f263522aSJoseph Koshy 	if ((abi_version & 0xFF000000) != (PMC_VERSION & 0xFF000000)) {
2084f263522aSJoseph Koshy 		errno  = EPROGMISMATCH;
2085f263522aSJoseph Koshy 		return (pmc_syscall = -1);
2086f263522aSJoseph Koshy 	}
2087f263522aSJoseph Koshy 
20881455fcd3SJoseph Koshy 	if (PMC_CALL(GETCPUINFO, &op_cpu_info) < 0)
2089f263522aSJoseph Koshy 		return (pmc_syscall = -1);
2090f263522aSJoseph Koshy 
20911455fcd3SJoseph Koshy 	cpu_info.pm_cputype = op_cpu_info.pm_cputype;
20921455fcd3SJoseph Koshy 	cpu_info.pm_ncpu    = op_cpu_info.pm_ncpu;
20931455fcd3SJoseph Koshy 	cpu_info.pm_npmc    = op_cpu_info.pm_npmc;
20941455fcd3SJoseph Koshy 	cpu_info.pm_nclass  = op_cpu_info.pm_nclass;
20951455fcd3SJoseph Koshy 	for (n = 0; n < cpu_info.pm_nclass; n++)
20961455fcd3SJoseph Koshy 		cpu_info.pm_classes[n] = op_cpu_info.pm_classes[n];
20971455fcd3SJoseph Koshy 
2098789140c0SJoseph Koshy #define	PMC_MDEP_INIT(C) do {					\
2099789140c0SJoseph Koshy 		pmc_mdep_event_aliases    = C##_aliases;	\
2100789140c0SJoseph Koshy 		pmc_mdep_class_list  = C##_pmc_classes;		\
2101789140c0SJoseph Koshy 		pmc_mdep_class_list_size =			\
2102789140c0SJoseph Koshy 		    PMC_TABLE_SIZE(C##_pmc_classes);		\
2103789140c0SJoseph Koshy 	} while (0)
2104789140c0SJoseph Koshy 
2105789140c0SJoseph Koshy 	/* Configure the event name parser. */
2106f263522aSJoseph Koshy 	switch (cpu_info.pm_cputype) {
2107f263522aSJoseph Koshy #if defined(__i386__)
2108f263522aSJoseph Koshy 	case PMC_CPU_AMD_K7:
2109789140c0SJoseph Koshy 		PMC_MDEP_INIT(k7);
2110f263522aSJoseph Koshy 		break;
2111f263522aSJoseph Koshy 	case PMC_CPU_INTEL_P5:
2112789140c0SJoseph Koshy 		PMC_MDEP_INIT(p5);
2113f263522aSJoseph Koshy 		break;
2114f263522aSJoseph Koshy 	case PMC_CPU_INTEL_P6:		/* P6 ... Pentium M CPUs have */
2115f263522aSJoseph Koshy 	case PMC_CPU_INTEL_PII:		/* similar PMCs. */
2116f263522aSJoseph Koshy 	case PMC_CPU_INTEL_PIII:
2117f263522aSJoseph Koshy 	case PMC_CPU_INTEL_PM:
2118789140c0SJoseph Koshy 		PMC_MDEP_INIT(p6);
2119f263522aSJoseph Koshy 		break;
212086a65549SJoseph Koshy #endif
212186a65549SJoseph Koshy #if defined(__amd64__) || defined(__i386__)
2122f263522aSJoseph Koshy 	case PMC_CPU_AMD_K8:
2123789140c0SJoseph Koshy 		PMC_MDEP_INIT(k8);
2124789140c0SJoseph Koshy 		break;
2125789140c0SJoseph Koshy 	case PMC_CPU_INTEL_PIV:
2126789140c0SJoseph Koshy 		PMC_MDEP_INIT(p4);
2127f263522aSJoseph Koshy 		break;
2128ebccf1e3SJoseph Koshy #endif
2129f263522aSJoseph Koshy 
2130f263522aSJoseph Koshy 	default:
2131f263522aSJoseph Koshy 		/*
2132f263522aSJoseph Koshy 		 * Some kind of CPU this version of the library knows nothing
2133f263522aSJoseph Koshy 		 * about.  This shouldn't happen since the abi version check
2134f263522aSJoseph Koshy 		 * should have caught this.
2135f263522aSJoseph Koshy 		 */
2136f263522aSJoseph Koshy 		errno = ENXIO;
2137f263522aSJoseph Koshy 		return (pmc_syscall = -1);
2138f263522aSJoseph Koshy 	}
2139f263522aSJoseph Koshy 
2140aa342b1fSJoseph Koshy 	return (0);
2141f263522aSJoseph Koshy }
2142f263522aSJoseph Koshy 
2143f263522aSJoseph Koshy const char *
2144f263522aSJoseph Koshy pmc_name_of_capability(enum pmc_caps cap)
2145f263522aSJoseph Koshy {
2146f263522aSJoseph Koshy 	int i;
2147f263522aSJoseph Koshy 
2148f263522aSJoseph Koshy 	/*
2149f263522aSJoseph Koshy 	 * 'cap' should have a single bit set and should be in
2150f263522aSJoseph Koshy 	 * range.
2151f263522aSJoseph Koshy 	 */
2152f263522aSJoseph Koshy 	if ((cap & (cap - 1)) || cap < PMC_CAP_FIRST ||
2153f263522aSJoseph Koshy 	    cap > PMC_CAP_LAST) {
2154f263522aSJoseph Koshy 		errno = EINVAL;
2155aa342b1fSJoseph Koshy 		return (NULL);
2156f263522aSJoseph Koshy 	}
2157f263522aSJoseph Koshy 
2158f263522aSJoseph Koshy 	i = ffs(cap);
2159aa342b1fSJoseph Koshy 	return (pmc_capability_names[i - 1]);
2160f263522aSJoseph Koshy }
2161f263522aSJoseph Koshy 
2162f263522aSJoseph Koshy const char *
2163f263522aSJoseph Koshy pmc_name_of_class(enum pmc_class pc)
2164f263522aSJoseph Koshy {
2165f263522aSJoseph Koshy 	if ((int) pc >= PMC_CLASS_FIRST &&
2166f263522aSJoseph Koshy 	    pc <= PMC_CLASS_LAST)
2167aa342b1fSJoseph Koshy 		return (pmc_class_names[pc]);
2168f263522aSJoseph Koshy 
2169f263522aSJoseph Koshy 	errno = EINVAL;
2170aa342b1fSJoseph Koshy 	return (NULL);
2171f263522aSJoseph Koshy }
2172f263522aSJoseph Koshy 
2173f263522aSJoseph Koshy const char *
2174f263522aSJoseph Koshy pmc_name_of_cputype(enum pmc_cputype cp)
2175f263522aSJoseph Koshy {
2176789140c0SJoseph Koshy 	size_t n;
2177789140c0SJoseph Koshy 
2178789140c0SJoseph Koshy 	for (n = 0; n < PMC_TABLE_SIZE(pmc_cputype_names); n++)
2179789140c0SJoseph Koshy 		if (cp == pmc_cputype_names[n].pm_cputype)
2180789140c0SJoseph Koshy 			return (pmc_cputype_names[n].pm_name);
2181789140c0SJoseph Koshy 
2182f263522aSJoseph Koshy 	errno = EINVAL;
2183aa342b1fSJoseph Koshy 	return (NULL);
2184f263522aSJoseph Koshy }
2185f263522aSJoseph Koshy 
2186f263522aSJoseph Koshy const char *
2187f263522aSJoseph Koshy pmc_name_of_disposition(enum pmc_disp pd)
2188f263522aSJoseph Koshy {
2189f263522aSJoseph Koshy 	if ((int) pd >= PMC_DISP_FIRST &&
2190f263522aSJoseph Koshy 	    pd <= PMC_DISP_LAST)
2191aa342b1fSJoseph Koshy 		return (pmc_disposition_names[pd]);
2192f263522aSJoseph Koshy 
2193f263522aSJoseph Koshy 	errno = EINVAL;
2194aa342b1fSJoseph Koshy 	return (NULL);
2195f263522aSJoseph Koshy }
2196f263522aSJoseph Koshy 
2197f263522aSJoseph Koshy const char *
2198f263522aSJoseph Koshy pmc_name_of_event(enum pmc_event pe)
2199f263522aSJoseph Koshy {
2200789140c0SJoseph Koshy 	const struct pmc_event_descr *ev, *evfence;
2201789140c0SJoseph Koshy 
2202789140c0SJoseph Koshy 	ev = evfence = NULL;
2203789140c0SJoseph Koshy 	if (pe >= PMC_EV_K7_FIRST && pe <= PMC_EV_K7_LAST) {
2204789140c0SJoseph Koshy 		ev = k7_event_table;
2205789140c0SJoseph Koshy 		evfence = k7_event_table + PMC_EVENT_TABLE_SIZE(k7);
2206789140c0SJoseph Koshy 	} else if (pe >= PMC_EV_K8_FIRST && pe <= PMC_EV_K8_LAST) {
2207789140c0SJoseph Koshy 		ev = k8_event_table;
2208789140c0SJoseph Koshy 		evfence = k8_event_table + PMC_EVENT_TABLE_SIZE(k8);
2209789140c0SJoseph Koshy 	} else if (pe >= PMC_EV_P4_FIRST && pe <= PMC_EV_P4_LAST) {
2210789140c0SJoseph Koshy 		ev = p4_event_table;
2211789140c0SJoseph Koshy 		evfence = p4_event_table + PMC_EVENT_TABLE_SIZE(p4);
2212789140c0SJoseph Koshy 	} else if (pe >= PMC_EV_P5_FIRST && pe <= PMC_EV_P5_LAST) {
2213789140c0SJoseph Koshy 		ev = p5_event_table;
2214789140c0SJoseph Koshy 		evfence = p5_event_table + PMC_EVENT_TABLE_SIZE(p5);
2215789140c0SJoseph Koshy 	} else if (pe >= PMC_EV_P6_FIRST && pe <= PMC_EV_P6_LAST) {
2216789140c0SJoseph Koshy 		ev = p6_event_table;
2217789140c0SJoseph Koshy 		evfence = p6_event_table + PMC_EVENT_TABLE_SIZE(p6);
2218789140c0SJoseph Koshy 	} else if (pe == PMC_EV_TSC_TSC) {
2219789140c0SJoseph Koshy 		ev = tsc_event_table;
2220789140c0SJoseph Koshy 		evfence = tsc_event_table + PMC_EVENT_TABLE_SIZE(tsc);
2221789140c0SJoseph Koshy 	}
2222789140c0SJoseph Koshy 
2223789140c0SJoseph Koshy 	for (; ev != evfence; ev++)
2224789140c0SJoseph Koshy 		if (pe == ev->pm_ev_code)
2225789140c0SJoseph Koshy 			return (ev->pm_ev_name);
2226f263522aSJoseph Koshy 
2227f263522aSJoseph Koshy 	errno = EINVAL;
2228aa342b1fSJoseph Koshy 	return (NULL);
2229f263522aSJoseph Koshy }
2230f263522aSJoseph Koshy 
2231f263522aSJoseph Koshy const char *
2232f263522aSJoseph Koshy pmc_name_of_mode(enum pmc_mode pm)
2233f263522aSJoseph Koshy {
2234f263522aSJoseph Koshy 	if ((int) pm >= PMC_MODE_FIRST &&
2235f263522aSJoseph Koshy 	    pm <= PMC_MODE_LAST)
2236aa342b1fSJoseph Koshy 		return (pmc_mode_names[pm]);
2237f263522aSJoseph Koshy 
2238f263522aSJoseph Koshy 	errno = EINVAL;
2239aa342b1fSJoseph Koshy 	return (NULL);
2240f263522aSJoseph Koshy }
2241f263522aSJoseph Koshy 
2242f263522aSJoseph Koshy const char *
2243f263522aSJoseph Koshy pmc_name_of_state(enum pmc_state ps)
2244f263522aSJoseph Koshy {
2245f263522aSJoseph Koshy 	if ((int) ps >= PMC_STATE_FIRST &&
2246f263522aSJoseph Koshy 	    ps <= PMC_STATE_LAST)
2247aa342b1fSJoseph Koshy 		return (pmc_state_names[ps]);
2248f263522aSJoseph Koshy 
2249f263522aSJoseph Koshy 	errno = EINVAL;
2250aa342b1fSJoseph Koshy 	return (NULL);
2251f263522aSJoseph Koshy }
2252f263522aSJoseph Koshy 
2253f263522aSJoseph Koshy int
2254f263522aSJoseph Koshy pmc_ncpu(void)
2255f263522aSJoseph Koshy {
2256f263522aSJoseph Koshy 	if (pmc_syscall == -1) {
2257f263522aSJoseph Koshy 		errno = ENXIO;
2258aa342b1fSJoseph Koshy 		return (-1);
2259f263522aSJoseph Koshy 	}
2260f263522aSJoseph Koshy 
2261aa342b1fSJoseph Koshy 	return (cpu_info.pm_ncpu);
2262f263522aSJoseph Koshy }
2263f263522aSJoseph Koshy 
2264f263522aSJoseph Koshy int
2265f263522aSJoseph Koshy pmc_npmc(int cpu)
2266f263522aSJoseph Koshy {
2267f263522aSJoseph Koshy 	if (pmc_syscall == -1) {
2268f263522aSJoseph Koshy 		errno = ENXIO;
2269aa342b1fSJoseph Koshy 		return (-1);
2270f263522aSJoseph Koshy 	}
2271f263522aSJoseph Koshy 
2272f263522aSJoseph Koshy 	if (cpu < 0 || cpu >= (int) cpu_info.pm_ncpu) {
2273f263522aSJoseph Koshy 		errno = EINVAL;
2274aa342b1fSJoseph Koshy 		return (-1);
2275f263522aSJoseph Koshy 	}
2276f263522aSJoseph Koshy 
2277aa342b1fSJoseph Koshy 	return (cpu_info.pm_npmc);
2278f263522aSJoseph Koshy }
2279f263522aSJoseph Koshy 
2280f263522aSJoseph Koshy int
2281f263522aSJoseph Koshy pmc_pmcinfo(int cpu, struct pmc_pmcinfo **ppmci)
2282f263522aSJoseph Koshy {
2283f263522aSJoseph Koshy 	int nbytes, npmc;
2284f263522aSJoseph Koshy 	struct pmc_op_getpmcinfo *pmci;
2285f263522aSJoseph Koshy 
2286f263522aSJoseph Koshy 	if ((npmc = pmc_npmc(cpu)) < 0)
2287aa342b1fSJoseph Koshy 		return (-1);
2288f263522aSJoseph Koshy 
2289f263522aSJoseph Koshy 	nbytes = sizeof(struct pmc_op_getpmcinfo) +
2290f263522aSJoseph Koshy 	    npmc * sizeof(struct pmc_info);
2291f263522aSJoseph Koshy 
2292f263522aSJoseph Koshy 	if ((pmci = calloc(1, nbytes)) == NULL)
2293aa342b1fSJoseph Koshy 		return (-1);
2294f263522aSJoseph Koshy 
2295f263522aSJoseph Koshy 	pmci->pm_cpu  = cpu;
2296f263522aSJoseph Koshy 
2297f263522aSJoseph Koshy 	if (PMC_CALL(GETPMCINFO, pmci) < 0) {
2298f263522aSJoseph Koshy 		free(pmci);
2299aa342b1fSJoseph Koshy 		return (-1);
2300f263522aSJoseph Koshy 	}
2301f263522aSJoseph Koshy 
2302f263522aSJoseph Koshy 	/* kernel<->library, library<->userland interfaces are identical */
2303f263522aSJoseph Koshy 	*ppmci = (struct pmc_pmcinfo *) pmci;
2304aa342b1fSJoseph Koshy 	return (0);
2305f263522aSJoseph Koshy }
2306f263522aSJoseph Koshy 
2307f263522aSJoseph Koshy int
2308f263522aSJoseph Koshy pmc_read(pmc_id_t pmc, pmc_value_t *value)
2309f263522aSJoseph Koshy {
2310f263522aSJoseph Koshy 	struct pmc_op_pmcrw pmc_read_op;
2311f263522aSJoseph Koshy 
2312f263522aSJoseph Koshy 	pmc_read_op.pm_pmcid = pmc;
2313f263522aSJoseph Koshy 	pmc_read_op.pm_flags = PMC_F_OLDVALUE;
2314f263522aSJoseph Koshy 	pmc_read_op.pm_value = -1;
2315f263522aSJoseph Koshy 
2316f263522aSJoseph Koshy 	if (PMC_CALL(PMCRW, &pmc_read_op) < 0)
2317aa342b1fSJoseph Koshy 		return (-1);
2318f263522aSJoseph Koshy 
2319f263522aSJoseph Koshy 	*value = pmc_read_op.pm_value;
2320aa342b1fSJoseph Koshy 	return (0);
2321f263522aSJoseph Koshy }
2322f263522aSJoseph Koshy 
2323f263522aSJoseph Koshy int
2324f263522aSJoseph Koshy pmc_release(pmc_id_t pmc)
2325f263522aSJoseph Koshy {
2326f263522aSJoseph Koshy 	struct pmc_op_simple	pmc_release_args;
2327f263522aSJoseph Koshy 
2328f263522aSJoseph Koshy 	pmc_release_args.pm_pmcid = pmc;
2329aa342b1fSJoseph Koshy 	return (PMC_CALL(PMCRELEASE, &pmc_release_args));
2330f263522aSJoseph Koshy }
2331f263522aSJoseph Koshy 
2332f263522aSJoseph Koshy int
2333f263522aSJoseph Koshy pmc_rw(pmc_id_t pmc, pmc_value_t newvalue, pmc_value_t *oldvaluep)
2334f263522aSJoseph Koshy {
2335f263522aSJoseph Koshy 	struct pmc_op_pmcrw pmc_rw_op;
2336f263522aSJoseph Koshy 
2337f263522aSJoseph Koshy 	pmc_rw_op.pm_pmcid = pmc;
2338f263522aSJoseph Koshy 	pmc_rw_op.pm_flags = PMC_F_NEWVALUE | PMC_F_OLDVALUE;
2339f263522aSJoseph Koshy 	pmc_rw_op.pm_value = newvalue;
2340f263522aSJoseph Koshy 
2341f263522aSJoseph Koshy 	if (PMC_CALL(PMCRW, &pmc_rw_op) < 0)
2342aa342b1fSJoseph Koshy 		return (-1);
2343f263522aSJoseph Koshy 
2344f263522aSJoseph Koshy 	*oldvaluep = pmc_rw_op.pm_value;
2345aa342b1fSJoseph Koshy 	return (0);
2346f263522aSJoseph Koshy }
2347f263522aSJoseph Koshy 
2348f263522aSJoseph Koshy int
2349f263522aSJoseph Koshy pmc_set(pmc_id_t pmc, pmc_value_t value)
2350f263522aSJoseph Koshy {
2351f263522aSJoseph Koshy 	struct pmc_op_pmcsetcount sc;
2352f263522aSJoseph Koshy 
2353f263522aSJoseph Koshy 	sc.pm_pmcid = pmc;
2354f263522aSJoseph Koshy 	sc.pm_count = value;
2355f263522aSJoseph Koshy 
2356f263522aSJoseph Koshy 	if (PMC_CALL(PMCSETCOUNT, &sc) < 0)
2357aa342b1fSJoseph Koshy 		return (-1);
2358aa342b1fSJoseph Koshy 	return (0);
2359f263522aSJoseph Koshy }
2360f263522aSJoseph Koshy 
2361f263522aSJoseph Koshy int
2362f263522aSJoseph Koshy pmc_start(pmc_id_t pmc)
2363f263522aSJoseph Koshy {
2364f263522aSJoseph Koshy 	struct pmc_op_simple	pmc_start_args;
2365f263522aSJoseph Koshy 
2366f263522aSJoseph Koshy 	pmc_start_args.pm_pmcid = pmc;
2367aa342b1fSJoseph Koshy 	return (PMC_CALL(PMCSTART, &pmc_start_args));
2368f263522aSJoseph Koshy }
2369f263522aSJoseph Koshy 
2370f263522aSJoseph Koshy int
2371f263522aSJoseph Koshy pmc_stop(pmc_id_t pmc)
2372f263522aSJoseph Koshy {
2373f263522aSJoseph Koshy 	struct pmc_op_simple	pmc_stop_args;
2374f263522aSJoseph Koshy 
2375f263522aSJoseph Koshy 	pmc_stop_args.pm_pmcid = pmc;
2376aa342b1fSJoseph Koshy 	return (PMC_CALL(PMCSTOP, &pmc_stop_args));
2377f263522aSJoseph Koshy }
2378f263522aSJoseph Koshy 
2379f263522aSJoseph Koshy int
2380f263522aSJoseph Koshy pmc_width(pmc_id_t pmcid, uint32_t *width)
2381f263522aSJoseph Koshy {
2382f263522aSJoseph Koshy 	unsigned int i;
2383f263522aSJoseph Koshy 	enum pmc_class cl;
2384f263522aSJoseph Koshy 
2385f263522aSJoseph Koshy 	cl = PMC_ID_TO_CLASS(pmcid);
2386f263522aSJoseph Koshy 	for (i = 0; i < cpu_info.pm_nclass; i++)
2387f263522aSJoseph Koshy 		if (cpu_info.pm_classes[i].pm_class == cl) {
2388f263522aSJoseph Koshy 			*width = cpu_info.pm_classes[i].pm_width;
2389aa342b1fSJoseph Koshy 			return (0);
2390f263522aSJoseph Koshy 		}
2391484202faSJoseph Koshy 	errno = EINVAL;
2392484202faSJoseph Koshy 	return (-1);
2393f263522aSJoseph Koshy }
2394f263522aSJoseph Koshy 
2395f263522aSJoseph Koshy int
2396f263522aSJoseph Koshy pmc_write(pmc_id_t pmc, pmc_value_t value)
2397f263522aSJoseph Koshy {
2398f263522aSJoseph Koshy 	struct pmc_op_pmcrw pmc_write_op;
2399f263522aSJoseph Koshy 
2400f263522aSJoseph Koshy 	pmc_write_op.pm_pmcid = pmc;
2401f263522aSJoseph Koshy 	pmc_write_op.pm_flags = PMC_F_NEWVALUE;
2402f263522aSJoseph Koshy 	pmc_write_op.pm_value = value;
2403aa342b1fSJoseph Koshy 	return (PMC_CALL(PMCRW, &pmc_write_op));
2404f263522aSJoseph Koshy }
2405f263522aSJoseph Koshy 
2406f263522aSJoseph Koshy int
2407f263522aSJoseph Koshy pmc_writelog(uint32_t userdata)
2408f263522aSJoseph Koshy {
2409f263522aSJoseph Koshy 	struct pmc_op_writelog wl;
2410f263522aSJoseph Koshy 
2411f263522aSJoseph Koshy 	wl.pm_userdata = userdata;
2412aa342b1fSJoseph Koshy 	return (PMC_CALL(WRITELOG, &wl));
2413f263522aSJoseph Koshy }
2414