1145256Sjkoshy/*-
2177107Sjkoshy * Copyright (c) 2003-2008 Joseph Koshy
3145256Sjkoshy * All rights reserved.
4145256Sjkoshy *
5145256Sjkoshy * Redistribution and use in source and binary forms, with or without
6145256Sjkoshy * modification, are permitted provided that the following conditions
7145256Sjkoshy * are met:
8145256Sjkoshy * 1. Redistributions of source code must retain the above copyright
9145256Sjkoshy *    notice, this list of conditions and the following disclaimer.
10145256Sjkoshy * 2. Redistributions in binary form must reproduce the above copyright
11145256Sjkoshy *    notice, this list of conditions and the following disclaimer in the
12145256Sjkoshy *    documentation and/or other materials provided with the distribution.
13145256Sjkoshy *
14145256Sjkoshy * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15145256Sjkoshy * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16145256Sjkoshy * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17145256Sjkoshy * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18145256Sjkoshy * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19145256Sjkoshy * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20145256Sjkoshy * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21145256Sjkoshy * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22145256Sjkoshy * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23145256Sjkoshy * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24145256Sjkoshy * SUCH DAMAGE.
25145256Sjkoshy */
26145256Sjkoshy
27145256Sjkoshy#include <sys/cdefs.h>
28145256Sjkoshy__FBSDID("$FreeBSD: stable/11/lib/libpmc/libpmc.c 339767 2018-10-26 05:12:56Z mmacy $");
29145256Sjkoshy
30145256Sjkoshy#include <sys/types.h>
31261342Sjhibbits#include <sys/param.h>
32145256Sjkoshy#include <sys/module.h>
33145256Sjkoshy#include <sys/pmc.h>
34145256Sjkoshy#include <sys/syscall.h>
35145256Sjkoshy
36145256Sjkoshy#include <ctype.h>
37145256Sjkoshy#include <errno.h>
38145256Sjkoshy#include <fcntl.h>
39145256Sjkoshy#include <pmc.h>
40145256Sjkoshy#include <stdio.h>
41145256Sjkoshy#include <stdlib.h>
42145256Sjkoshy#include <string.h>
43145256Sjkoshy#include <strings.h>
44145256Sjkoshy#include <unistd.h>
45145256Sjkoshy
46185363Sjkoshy#include "libpmcinternal.h"
47185363Sjkoshy
48145256Sjkoshy/* Function prototypes */
49145340Smarcel#if defined(__i386__)
50145256Sjkoshystatic int k7_allocate_pmc(enum pmc_event _pe, char *_ctrspec,
51145256Sjkoshy    struct pmc_op_pmcallocate *_pmc_config);
52147191Sjkoshy#endif
53147759Sjkoshy#if defined(__amd64__) || defined(__i386__)
54185363Sjkoshystatic int iaf_allocate_pmc(enum pmc_event _pe, char *_ctrspec,
55185363Sjkoshy    struct pmc_op_pmcallocate *_pmc_config);
56185363Sjkoshystatic int iap_allocate_pmc(enum pmc_event _pe, char *_ctrspec,
57185363Sjkoshy    struct pmc_op_pmcallocate *_pmc_config);
58206089Sfabientstatic int ucf_allocate_pmc(enum pmc_event _pe, char *_ctrspec,
59206089Sfabient    struct pmc_op_pmcallocate *_pmc_config);
60206089Sfabientstatic int ucp_allocate_pmc(enum pmc_event _pe, char *_ctrspec,
61206089Sfabient    struct pmc_op_pmcallocate *_pmc_config);
62147191Sjkoshystatic int k8_allocate_pmc(enum pmc_event _pe, char *_ctrspec,
63145256Sjkoshy    struct pmc_op_pmcallocate *_pmc_config);
64339767Smmacystatic int f17h_allocate_pmc(enum pmc_event _pe, char *_ctrspec,
65339767Smmacy		struct pmc_op_pmcallocate *_pmc_config);
66147759Sjkoshystatic int p4_allocate_pmc(enum pmc_event _pe, char *_ctrspec,
67147759Sjkoshy    struct pmc_op_pmcallocate *_pmc_config);
68147191Sjkoshy#endif
69147191Sjkoshy#if defined(__i386__)
70145256Sjkoshystatic int p5_allocate_pmc(enum pmc_event _pe, char *_ctrspec,
71145256Sjkoshy    struct pmc_op_pmcallocate *_pmc_config);
72147191Sjkoshystatic int p6_allocate_pmc(enum pmc_event _pe, char *_ctrspec,
73145256Sjkoshy    struct pmc_op_pmcallocate *_pmc_config);
74145256Sjkoshy#endif
75183725Sjkoshy#if defined(__amd64__) || defined(__i386__)
76183725Sjkoshystatic int tsc_allocate_pmc(enum pmc_event _pe, char *_ctrspec,
77183725Sjkoshy    struct pmc_op_pmcallocate *_pmc_config);
78183725Sjkoshy#endif
79277835Sbr#if defined(__arm__)
80200928Srpaulo#if defined(__XSCALE__)
81200928Srpaulostatic int xscale_allocate_pmc(enum pmc_event _pe, char *_ctrspec,
82200928Srpaulo    struct pmc_op_pmcallocate *_pmc_config);
83200928Srpaulo#endif
84277835Sbrstatic int armv7_allocate_pmc(enum pmc_event _pe, char *_ctrspec,
85277835Sbr    struct pmc_op_pmcallocate *_pmc_config);
86277835Sbr#endif
87283112Sbr#if defined(__aarch64__)
88283112Sbrstatic int arm64_allocate_pmc(enum pmc_event _pe, char *_ctrspec,
89283112Sbr    struct pmc_op_pmcallocate *_pmc_config);
90283112Sbr#endif
91204635Sgnn#if defined(__mips__)
92233320Sgonzostatic int mips_allocate_pmc(enum pmc_event _pe, char* ctrspec,
93204635Sgnn			     struct pmc_op_pmcallocate *_pmc_config);
94204635Sgnn#endif /* __mips__ */
95233628Sfabientstatic int soft_allocate_pmc(enum pmc_event _pe, char *_ctrspec,
96233628Sfabient    struct pmc_op_pmcallocate *_pmc_config);
97204635Sgnn
98228869Sjhibbits#if defined(__powerpc__)
99261342Sjhibbitsstatic int powerpc_allocate_pmc(enum pmc_event _pe, char* ctrspec,
100228869Sjhibbits			     struct pmc_op_pmcallocate *_pmc_config);
101228869Sjhibbits#endif /* __powerpc__ */
102204635Sgnn
103145256Sjkoshy#define PMC_CALL(cmd, params)				\
104145256Sjkoshy	syscall(pmc_syscall, PMC_OP_##cmd, (params))
105145256Sjkoshy
106145256Sjkoshy/*
107145256Sjkoshy * Event aliases provide a way for the user to ask for generic events
108145256Sjkoshy * like "cache-misses", or "instructions-retired".  These aliases are
109145256Sjkoshy * mapped to the appropriate canonical event descriptions using a
110145256Sjkoshy * lookup table.
111145256Sjkoshy */
112145256Sjkoshystruct pmc_event_alias {
113145256Sjkoshy	const char	*pm_alias;
114145256Sjkoshy	const char	*pm_spec;
115145256Sjkoshy};
116145256Sjkoshy
117145256Sjkoshystatic const struct pmc_event_alias *pmc_mdep_event_aliases;
118145256Sjkoshy
119145256Sjkoshy/*
120183725Sjkoshy * The pmc_event_descr structure maps symbolic names known to the user
121145256Sjkoshy * to integer codes used by the PMC KLD.
122145256Sjkoshy */
123145256Sjkoshystruct pmc_event_descr {
124145256Sjkoshy	const char	*pm_ev_name;
125145256Sjkoshy	enum pmc_event	pm_ev_code;
126145256Sjkoshy};
127145256Sjkoshy
128183725Sjkoshy/*
129183725Sjkoshy * The pmc_class_descr structure maps class name prefixes for
130183725Sjkoshy * event names to event tables and other PMC class data.
131183725Sjkoshy */
132183725Sjkoshystruct pmc_class_descr {
133183725Sjkoshy	const char	*pm_evc_name;
134183725Sjkoshy	size_t		pm_evc_name_size;
135183725Sjkoshy	enum pmc_class	pm_evc_class;
136183725Sjkoshy	const struct pmc_event_descr *pm_evc_event_table;
137183725Sjkoshy	size_t		pm_evc_event_table_size;
138183725Sjkoshy	int		(*pm_evc_allocate_pmc)(enum pmc_event _pe,
139183725Sjkoshy			    char *_ctrspec, struct pmc_op_pmcallocate *_pa);
140183725Sjkoshy};
141183725Sjkoshy
142183725Sjkoshy#define	PMC_TABLE_SIZE(N)	(sizeof(N)/sizeof(N[0]))
143183725Sjkoshy#define	PMC_EVENT_TABLE_SIZE(N)	PMC_TABLE_SIZE(N##_event_table)
144183725Sjkoshy
145183725Sjkoshy#undef	__PMC_EV
146183725Sjkoshy#define	__PMC_EV(C,N) { #N, PMC_EV_ ## C ## _ ## N },
147183725Sjkoshy
148183725Sjkoshy/*
149185363Sjkoshy * PMC_CLASSDEP_TABLE(NAME, CLASS)
150183725Sjkoshy *
151185363Sjkoshy * Define a table mapping event names and aliases to HWPMC event IDs.
152183725Sjkoshy */
153185363Sjkoshy#define	PMC_CLASSDEP_TABLE(N, C)				\
154183725Sjkoshy	static const struct pmc_event_descr N##_event_table[] =	\
155183725Sjkoshy	{							\
156183725Sjkoshy		__PMC_EV_##C()					\
157185363Sjkoshy	}
158185363Sjkoshy
159185363SjkoshyPMC_CLASSDEP_TABLE(iaf, IAF);
160185363SjkoshyPMC_CLASSDEP_TABLE(k7, K7);
161185363SjkoshyPMC_CLASSDEP_TABLE(k8, K8);
162339767SmmacyPMC_CLASSDEP_TABLE(f17h, F17H);
163185363SjkoshyPMC_CLASSDEP_TABLE(p4, P4);
164185363SjkoshyPMC_CLASSDEP_TABLE(p5, P5);
165185363SjkoshyPMC_CLASSDEP_TABLE(p6, P6);
166200928SrpauloPMC_CLASSDEP_TABLE(xscale, XSCALE);
167277835SbrPMC_CLASSDEP_TABLE(armv7, ARMV7);
168283112SbrPMC_CLASSDEP_TABLE(armv8, ARMV8);
169204635SgnnPMC_CLASSDEP_TABLE(mips24k, MIPS24K);
170281098SadrianPMC_CLASSDEP_TABLE(mips74k, MIPS74K);
171233335SgonzoPMC_CLASSDEP_TABLE(octeon, OCTEON);
172206089SfabientPMC_CLASSDEP_TABLE(ucf, UCF);
173228869SjhibbitsPMC_CLASSDEP_TABLE(ppc7450, PPC7450);
174261342SjhibbitsPMC_CLASSDEP_TABLE(ppc970, PPC970);
175281713SjhibbitsPMC_CLASSDEP_TABLE(e500, E500);
176185363Sjkoshy
177233628Sfabientstatic struct pmc_event_descr soft_event_table[PMC_EV_DYN_COUNT];
178233628Sfabient
179185363Sjkoshy#undef	__PMC_EV_ALIAS
180185363Sjkoshy#define	__PMC_EV_ALIAS(N,CODE) 	{ N, PMC_EV_##CODE },
181185363Sjkoshy
182185363Sjkoshystatic const struct pmc_event_descr atom_event_table[] =
183185363Sjkoshy{
184185363Sjkoshy	__PMC_EV_ALIAS_ATOM()
185185363Sjkoshy};
186185363Sjkoshy
187263446Shirenstatic const struct pmc_event_descr atom_silvermont_event_table[] =
188263446Shiren{
189263446Shiren	__PMC_EV_ALIAS_ATOM_SILVERMONT()
190263446Shiren};
191263446Shiren
192185363Sjkoshystatic const struct pmc_event_descr core_event_table[] =
193185363Sjkoshy{
194185363Sjkoshy	__PMC_EV_ALIAS_CORE()
195185363Sjkoshy};
196185363Sjkoshy
197185363Sjkoshy
198185363Sjkoshystatic const struct pmc_event_descr core2_event_table[] =
199185363Sjkoshy{
200185363Sjkoshy	__PMC_EV_ALIAS_CORE2()
201185363Sjkoshy};
202185363Sjkoshy
203187761Sjeffstatic const struct pmc_event_descr corei7_event_table[] =
204187761Sjeff{
205187761Sjeff	__PMC_EV_ALIAS_COREI7()
206187761Sjeff};
207187761Sjeff
208267062Skibstatic const struct pmc_event_descr nehalem_ex_event_table[] =
209267062Skib{
210267062Skib	__PMC_EV_ALIAS_COREI7()
211267062Skib};
212267062Skib
213248842Ssbrunostatic const struct pmc_event_descr haswell_event_table[] =
214248842Ssbruno{
215248842Ssbruno	__PMC_EV_ALIAS_HASWELL()
216248842Ssbruno};
217248842Ssbruno
218277177Srrsstatic const struct pmc_event_descr haswell_xeon_event_table[] =
219277177Srrs{
220277177Srrs	__PMC_EV_ALIAS_HASWELL_XEON()
221277177Srrs};
222277177Srrs
223291494Srrsstatic const struct pmc_event_descr broadwell_event_table[] =
224291494Srrs{
225291494Srrs	__PMC_EV_ALIAS_BROADWELL()
226291494Srrs};
227277177Srrs
228291494Srrsstatic const struct pmc_event_descr broadwell_xeon_event_table[] =
229291494Srrs{
230291494Srrs	__PMC_EV_ALIAS_BROADWELL_XEON()
231291494Srrs};
232291494Srrs
233291494Srrsstatic const struct pmc_event_descr skylake_event_table[] =
234291494Srrs{
235291494Srrs	__PMC_EV_ALIAS_SKYLAKE()
236291494Srrs};
237291494Srrs
238323799Skibstatic const struct pmc_event_descr skylake_xeon_event_table[] =
239323799Skib{
240323799Skib	__PMC_EV_ALIAS_SKYLAKE_XEON()
241323799Skib};
242323799Skib
243240164Sfabientstatic const struct pmc_event_descr ivybridge_event_table[] =
244240164Sfabient{
245240164Sfabient	__PMC_EV_ALIAS_IVYBRIDGE()
246240164Sfabient};
247240164Sfabient
248246166Ssbrunostatic const struct pmc_event_descr ivybridge_xeon_event_table[] =
249246166Ssbruno{
250246166Ssbruno	__PMC_EV_ALIAS_IVYBRIDGE_XEON()
251246166Ssbruno};
252246166Ssbruno
253232366Sdavidestatic const struct pmc_event_descr sandybridge_event_table[] =
254232366Sdavide{
255232366Sdavide	__PMC_EV_ALIAS_SANDYBRIDGE()
256232366Sdavide};
257232366Sdavide
258241738Ssbrunostatic const struct pmc_event_descr sandybridge_xeon_event_table[] =
259241738Ssbruno{
260241738Ssbruno	__PMC_EV_ALIAS_SANDYBRIDGE_XEON()
261241738Ssbruno};
262241738Ssbruno
263206089Sfabientstatic const struct pmc_event_descr westmere_event_table[] =
264206089Sfabient{
265206089Sfabient	__PMC_EV_ALIAS_WESTMERE()
266206089Sfabient};
267206089Sfabient
268267062Skibstatic const struct pmc_event_descr westmere_ex_event_table[] =
269267062Skib{
270267062Skib	__PMC_EV_ALIAS_WESTMERE()
271267062Skib};
272267062Skib
273206089Sfabientstatic const struct pmc_event_descr corei7uc_event_table[] =
274206089Sfabient{
275206089Sfabient	__PMC_EV_ALIAS_COREI7UC()
276206089Sfabient};
277206089Sfabient
278248842Ssbrunostatic const struct pmc_event_descr haswelluc_event_table[] =
279248842Ssbruno{
280248842Ssbruno	__PMC_EV_ALIAS_HASWELLUC()
281248842Ssbruno};
282248842Ssbruno
283291494Srrsstatic const struct pmc_event_descr broadwelluc_event_table[] =
284291494Srrs{
285291494Srrs	__PMC_EV_ALIAS_BROADWELLUC()
286291494Srrs};
287291494Srrs
288232366Sdavidestatic const struct pmc_event_descr sandybridgeuc_event_table[] =
289232366Sdavide{
290232366Sdavide	__PMC_EV_ALIAS_SANDYBRIDGEUC()
291232366Sdavide};
292232366Sdavide
293206089Sfabientstatic const struct pmc_event_descr westmereuc_event_table[] =
294206089Sfabient{
295206089Sfabient	__PMC_EV_ALIAS_WESTMEREUC()
296206089Sfabient};
297206089Sfabient
298284218Sbrstatic const struct pmc_event_descr cortex_a8_event_table[] =
299284218Sbr{
300284218Sbr	__PMC_EV_ALIAS_ARMV7_CORTEX_A8()
301284218Sbr};
302284218Sbr
303284218Sbrstatic const struct pmc_event_descr cortex_a9_event_table[] =
304284218Sbr{
305284218Sbr	__PMC_EV_ALIAS_ARMV7_CORTEX_A9()
306284218Sbr};
307284218Sbr
308283112Sbrstatic const struct pmc_event_descr cortex_a53_event_table[] =
309283112Sbr{
310283112Sbr	__PMC_EV_ALIAS_ARMV8_CORTEX_A53()
311283112Sbr};
312283112Sbr
313283112Sbrstatic const struct pmc_event_descr cortex_a57_event_table[] =
314283112Sbr{
315283112Sbr	__PMC_EV_ALIAS_ARMV8_CORTEX_A57()
316283112Sbr};
317283112Sbr
318185363Sjkoshy/*
319185363Sjkoshy * PMC_MDEP_TABLE(NAME, PRIMARYCLASS, ADDITIONAL_CLASSES...)
320185363Sjkoshy *
321185363Sjkoshy * Map a CPU to the PMC classes it supports.
322185363Sjkoshy */
323185363Sjkoshy#define	PMC_MDEP_TABLE(N,C,...)				\
324183725Sjkoshy	static const enum pmc_class N##_pmc_classes[] = {	\
325183725Sjkoshy		PMC_CLASS_##C, __VA_ARGS__			\
326183725Sjkoshy	}
327183725Sjkoshy
328233628SfabientPMC_MDEP_TABLE(atom, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC);
329263446ShirenPMC_MDEP_TABLE(atom_silvermont, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC);
330233628SfabientPMC_MDEP_TABLE(core, IAP, PMC_CLASS_SOFT, PMC_CLASS_TSC);
331233628SfabientPMC_MDEP_TABLE(core2, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC);
332233628SfabientPMC_MDEP_TABLE(corei7, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC, PMC_CLASS_UCF, PMC_CLASS_UCP);
333267062SkibPMC_MDEP_TABLE(nehalem_ex, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC);
334248842SsbrunoPMC_MDEP_TABLE(haswell, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC, PMC_CLASS_UCF, PMC_CLASS_UCP);
335277177SrrsPMC_MDEP_TABLE(haswell_xeon, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC, PMC_CLASS_UCF, PMC_CLASS_UCP);
336291494SrrsPMC_MDEP_TABLE(broadwell, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC, PMC_CLASS_UCF, PMC_CLASS_UCP);
337291494SrrsPMC_MDEP_TABLE(broadwell_xeon, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC, PMC_CLASS_UCF, PMC_CLASS_UCP);
338291494SrrsPMC_MDEP_TABLE(skylake, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC, PMC_CLASS_UCF, PMC_CLASS_UCP);
339323799SkibPMC_MDEP_TABLE(skylake_xeon, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC);
340240164SfabientPMC_MDEP_TABLE(ivybridge, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC);
341246166SsbrunoPMC_MDEP_TABLE(ivybridge_xeon, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC);
342233628SfabientPMC_MDEP_TABLE(sandybridge, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC, PMC_CLASS_UCF, PMC_CLASS_UCP);
343241738SsbrunoPMC_MDEP_TABLE(sandybridge_xeon, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC);
344233628SfabientPMC_MDEP_TABLE(westmere, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC, PMC_CLASS_UCF, PMC_CLASS_UCP);
345267062SkibPMC_MDEP_TABLE(westmere_ex, IAP, PMC_CLASS_SOFT, PMC_CLASS_IAF, PMC_CLASS_TSC);
346233628SfabientPMC_MDEP_TABLE(k7, K7, PMC_CLASS_SOFT, PMC_CLASS_TSC);
347233628SfabientPMC_MDEP_TABLE(k8, K8, PMC_CLASS_SOFT, PMC_CLASS_TSC);
348339767SmmacyPMC_MDEP_TABLE(f17h, F17H, PMC_CLASS_SOFT, PMC_CLASS_TSC);
349233628SfabientPMC_MDEP_TABLE(p4, P4, PMC_CLASS_SOFT, PMC_CLASS_TSC);
350233628SfabientPMC_MDEP_TABLE(p5, P5, PMC_CLASS_SOFT, PMC_CLASS_TSC);
351233628SfabientPMC_MDEP_TABLE(p6, P6, PMC_CLASS_SOFT, PMC_CLASS_TSC);
352233628SfabientPMC_MDEP_TABLE(xscale, XSCALE, PMC_CLASS_SOFT, PMC_CLASS_XSCALE);
353284218SbrPMC_MDEP_TABLE(cortex_a8, ARMV7, PMC_CLASS_SOFT, PMC_CLASS_ARMV7);
354284218SbrPMC_MDEP_TABLE(cortex_a9, ARMV7, PMC_CLASS_SOFT, PMC_CLASS_ARMV7);
355283112SbrPMC_MDEP_TABLE(cortex_a53, ARMV8, PMC_CLASS_SOFT, PMC_CLASS_ARMV8);
356283112SbrPMC_MDEP_TABLE(cortex_a57, ARMV8, PMC_CLASS_SOFT, PMC_CLASS_ARMV8);
357233628SfabientPMC_MDEP_TABLE(mips24k, MIPS24K, PMC_CLASS_SOFT, PMC_CLASS_MIPS24K);
358281098SadrianPMC_MDEP_TABLE(mips74k, MIPS74K, PMC_CLASS_SOFT, PMC_CLASS_MIPS74K);
359233628SfabientPMC_MDEP_TABLE(octeon, OCTEON, PMC_CLASS_SOFT, PMC_CLASS_OCTEON);
360281713SjhibbitsPMC_MDEP_TABLE(ppc7450, PPC7450, PMC_CLASS_SOFT, PMC_CLASS_PPC7450, PMC_CLASS_TSC);
361281713SjhibbitsPMC_MDEP_TABLE(ppc970, PPC970, PMC_CLASS_SOFT, PMC_CLASS_PPC970, PMC_CLASS_TSC);
362281713SjhibbitsPMC_MDEP_TABLE(e500, E500, PMC_CLASS_SOFT, PMC_CLASS_E500, PMC_CLASS_TSC);
363233628SfabientPMC_MDEP_TABLE(generic, SOFT, PMC_CLASS_SOFT);
364183725Sjkoshy
365183725Sjkoshystatic const struct pmc_event_descr tsc_event_table[] =
366145256Sjkoshy{
367183725Sjkoshy	__PMC_EV_TSC()
368145256Sjkoshy};
369145256Sjkoshy
370183725Sjkoshy#undef	PMC_CLASS_TABLE_DESC
371185363Sjkoshy#define	PMC_CLASS_TABLE_DESC(NAME, CLASS, EVENTS, ALLOCATOR)	\
372185363Sjkoshystatic const struct pmc_class_descr NAME##_class_table_descr =	\
373185363Sjkoshy	{							\
374185363Sjkoshy		.pm_evc_name  = #CLASS "-",			\
375185363Sjkoshy		.pm_evc_name_size = sizeof(#CLASS "-") - 1,	\
376185363Sjkoshy		.pm_evc_class = PMC_CLASS_##CLASS ,		\
377185363Sjkoshy		.pm_evc_event_table = EVENTS##_event_table ,	\
378183725Sjkoshy		.pm_evc_event_table_size = 			\
379185363Sjkoshy			PMC_EVENT_TABLE_SIZE(EVENTS),		\
380185363Sjkoshy		.pm_evc_allocate_pmc = ALLOCATOR##_allocate_pmc	\
381183725Sjkoshy	}
382183725Sjkoshy
383185363Sjkoshy#if	defined(__i386__) || defined(__amd64__)
384185363SjkoshyPMC_CLASS_TABLE_DESC(iaf, IAF, iaf, iaf);
385185363SjkoshyPMC_CLASS_TABLE_DESC(atom, IAP, atom, iap);
386263446ShirenPMC_CLASS_TABLE_DESC(atom_silvermont, IAP, atom_silvermont, iap);
387185363SjkoshyPMC_CLASS_TABLE_DESC(core, IAP, core, iap);
388185363SjkoshyPMC_CLASS_TABLE_DESC(core2, IAP, core2, iap);
389187761SjeffPMC_CLASS_TABLE_DESC(corei7, IAP, corei7, iap);
390267062SkibPMC_CLASS_TABLE_DESC(nehalem_ex, IAP, nehalem_ex, iap);
391248842SsbrunoPMC_CLASS_TABLE_DESC(haswell, IAP, haswell, iap);
392279833SrstonePMC_CLASS_TABLE_DESC(haswell_xeon, IAP, haswell_xeon, iap);
393291494SrrsPMC_CLASS_TABLE_DESC(broadwell, IAP, broadwell, iap);
394291494SrrsPMC_CLASS_TABLE_DESC(broadwell_xeon, IAP, broadwell_xeon, iap);
395291494SrrsPMC_CLASS_TABLE_DESC(skylake, IAP, skylake, iap);
396323799SkibPMC_CLASS_TABLE_DESC(skylake_xeon, IAP, skylake_xeon, iap);
397240164SfabientPMC_CLASS_TABLE_DESC(ivybridge, IAP, ivybridge, iap);
398246166SsbrunoPMC_CLASS_TABLE_DESC(ivybridge_xeon, IAP, ivybridge_xeon, iap);
399232366SdavidePMC_CLASS_TABLE_DESC(sandybridge, IAP, sandybridge, iap);
400241738SsbrunoPMC_CLASS_TABLE_DESC(sandybridge_xeon, IAP, sandybridge_xeon, iap);
401206089SfabientPMC_CLASS_TABLE_DESC(westmere, IAP, westmere, iap);
402267062SkibPMC_CLASS_TABLE_DESC(westmere_ex, IAP, westmere_ex, iap);
403206089SfabientPMC_CLASS_TABLE_DESC(ucf, UCF, ucf, ucf);
404206089SfabientPMC_CLASS_TABLE_DESC(corei7uc, UCP, corei7uc, ucp);
405248842SsbrunoPMC_CLASS_TABLE_DESC(haswelluc, UCP, haswelluc, ucp);
406291494SrrsPMC_CLASS_TABLE_DESC(broadwelluc, UCP, broadwelluc, ucp);
407232366SdavidePMC_CLASS_TABLE_DESC(sandybridgeuc, UCP, sandybridgeuc, ucp);
408206089SfabientPMC_CLASS_TABLE_DESC(westmereuc, UCP, westmereuc, ucp);
409185363Sjkoshy#endif
410183725Sjkoshy#if	defined(__i386__)
411185363SjkoshyPMC_CLASS_TABLE_DESC(k7, K7, k7, k7);
412183725Sjkoshy#endif
413183725Sjkoshy#if	defined(__i386__) || defined(__amd64__)
414185363SjkoshyPMC_CLASS_TABLE_DESC(k8, K8, k8, k8);
415339767SmmacyPMC_CLASS_TABLE_DESC(f17h, F17H, f17h, f17h);
416185363SjkoshyPMC_CLASS_TABLE_DESC(p4, P4, p4, p4);
417183725Sjkoshy#endif
418183725Sjkoshy#if	defined(__i386__)
419185363SjkoshyPMC_CLASS_TABLE_DESC(p5, P5, p5, p5);
420185363SjkoshyPMC_CLASS_TABLE_DESC(p6, P6, p6, p6);
421183725Sjkoshy#endif
422183725Sjkoshy#if	defined(__i386__) || defined(__amd64__)
423185363SjkoshyPMC_CLASS_TABLE_DESC(tsc, TSC, tsc, tsc);
424183725Sjkoshy#endif
425277835Sbr#if	defined(__arm__)
426200928Srpaulo#if	defined(__XSCALE__)
427200928SrpauloPMC_CLASS_TABLE_DESC(xscale, XSCALE, xscale, xscale);
428200928Srpaulo#endif
429289317SbzPMC_CLASS_TABLE_DESC(cortex_a8, ARMV7, cortex_a8, armv7);
430284218SbrPMC_CLASS_TABLE_DESC(cortex_a9, ARMV7, cortex_a9, armv7);
431277835Sbr#endif
432283112Sbr#if	defined(__aarch64__)
433283112SbrPMC_CLASS_TABLE_DESC(cortex_a53, ARMV8, cortex_a53, arm64);
434283112SbrPMC_CLASS_TABLE_DESC(cortex_a57, ARMV8, cortex_a57, arm64);
435283112Sbr#endif
436204635Sgnn#if defined(__mips__)
437233320SgonzoPMC_CLASS_TABLE_DESC(mips24k, MIPS24K, mips24k, mips);
438281098SadrianPMC_CLASS_TABLE_DESC(mips74k, MIPS74K, mips74k, mips);
439233335SgonzoPMC_CLASS_TABLE_DESC(octeon, OCTEON, octeon, mips);
440204635Sgnn#endif /* __mips__ */
441228869Sjhibbits#if defined(__powerpc__)
442261342SjhibbitsPMC_CLASS_TABLE_DESC(ppc7450, PPC7450, ppc7450, powerpc);
443261342SjhibbitsPMC_CLASS_TABLE_DESC(ppc970, PPC970, ppc970, powerpc);
444281713SjhibbitsPMC_CLASS_TABLE_DESC(e500, E500, e500, powerpc);
445228869Sjhibbits#endif
446228869Sjhibbits
447233628Sfabientstatic struct pmc_class_descr soft_class_table_descr =
448233628Sfabient{
449233628Sfabient	.pm_evc_name  = "SOFT-",
450233628Sfabient	.pm_evc_name_size = sizeof("SOFT-") - 1,
451233628Sfabient	.pm_evc_class = PMC_CLASS_SOFT,
452233628Sfabient	.pm_evc_event_table = NULL,
453233628Sfabient	.pm_evc_event_table_size = 0,
454233628Sfabient	.pm_evc_allocate_pmc = soft_allocate_pmc
455233628Sfabient};
456233628Sfabient
457183725Sjkoshy#undef	PMC_CLASS_TABLE_DESC
458183725Sjkoshy
459185363Sjkoshystatic const struct pmc_class_descr **pmc_class_table;
460185363Sjkoshy#define	PMC_CLASS_TABLE_SIZE	cpu_info.pm_nclass
461185363Sjkoshy
462183725Sjkoshystatic const enum pmc_class *pmc_mdep_class_list;
463183725Sjkoshystatic size_t pmc_mdep_class_list_size;
464183725Sjkoshy
465145256Sjkoshy/*
466145256Sjkoshy * Mapping tables, mapping enumeration values to human readable
467145256Sjkoshy * strings.
468145256Sjkoshy */
469145256Sjkoshy
470145256Sjkoshystatic const char * pmc_capability_names[] = {
471145256Sjkoshy#undef	__PMC_CAP
472145256Sjkoshy#define	__PMC_CAP(N,V,D)	#N ,
473145256Sjkoshy	__PMC_CAPS()
474145256Sjkoshy};
475145256Sjkoshy
476283120Sjhbstruct pmc_class_map {
477283120Sjhb	enum pmc_class	pm_class;
478283120Sjhb	const char	*pm_name;
479283120Sjhb};
480283120Sjhb
481283120Sjhbstatic const struct pmc_class_map pmc_class_names[] = {
482145256Sjkoshy#undef	__PMC_CLASS
483283120Sjhb#define __PMC_CLASS(S,V,D) { .pm_class = PMC_CLASS_##S, .pm_name = #S } ,
484145256Sjkoshy	__PMC_CLASSES()
485145256Sjkoshy};
486145256Sjkoshy
487183725Sjkoshystruct pmc_cputype_map {
488228557Sdim	enum pmc_cputype pm_cputype;
489183725Sjkoshy	const char	*pm_name;
490183725Sjkoshy};
491183725Sjkoshy
492183725Sjkoshystatic const struct pmc_cputype_map pmc_cputype_names[] = {
493145256Sjkoshy#undef	__PMC_CPU
494183725Sjkoshy#define	__PMC_CPU(S, V, D) { .pm_cputype = PMC_CPU_##S, .pm_name = #S } ,
495145256Sjkoshy	__PMC_CPUS()
496145256Sjkoshy};
497145256Sjkoshy
498145256Sjkoshystatic const char * pmc_disposition_names[] = {
499145256Sjkoshy#undef	__PMC_DISP
500145256Sjkoshy#define	__PMC_DISP(D)	#D ,
501145256Sjkoshy	__PMC_DISPOSITIONS()
502145256Sjkoshy};
503145256Sjkoshy
504145256Sjkoshystatic const char * pmc_mode_names[] = {
505145256Sjkoshy#undef  __PMC_MODE
506145256Sjkoshy#define __PMC_MODE(M,N)	#M ,
507145256Sjkoshy	__PMC_MODES()
508145256Sjkoshy};
509145256Sjkoshy
510145256Sjkoshystatic const char * pmc_state_names[] = {
511145256Sjkoshy#undef  __PMC_STATE
512145256Sjkoshy#define __PMC_STATE(S) #S ,
513145256Sjkoshy	__PMC_STATES()
514145256Sjkoshy};
515145256Sjkoshy
516233628Sfabient/*
517233628Sfabient * Filled in by pmc_init().
518233628Sfabient */
519233628Sfabientstatic int pmc_syscall = -1;
520233628Sfabientstatic struct pmc_cpuinfo cpu_info;
521233628Sfabientstatic struct pmc_op_getdyneventinfo soft_event_info;
522145256Sjkoshy
523145256Sjkoshy/* Event masks for events */
524145256Sjkoshystruct pmc_masks {
525145256Sjkoshy	const char	*pm_name;
526240164Sfabient	const uint64_t	pm_value;
527145256Sjkoshy};
528145256Sjkoshy#define	PMCMASK(N,V)	{ .pm_name = #N, .pm_value = (V) }
529206089Sfabient#define	NULLMASK	{ .pm_name = NULL }
530145256Sjkoshy
531147759Sjkoshy#if defined(__amd64__) || defined(__i386__)
532145256Sjkoshystatic int
533240164Sfabientpmc_parse_mask(const struct pmc_masks *pmask, char *p, uint64_t *evmask)
534145256Sjkoshy{
535145256Sjkoshy	const struct pmc_masks *pm;
536145256Sjkoshy	char *q, *r;
537145256Sjkoshy	int c;
538145256Sjkoshy
539145256Sjkoshy	if (pmask == NULL)	/* no mask keywords */
540174406Sjkoshy		return (-1);
541183107Sjkoshy	q = strchr(p, '=');	/* skip '=' */
542145256Sjkoshy	if (*++q == '\0')	/* no more data */
543174406Sjkoshy		return (-1);
544145256Sjkoshy	c = 0;			/* count of mask keywords seen */
545145256Sjkoshy	while ((r = strsep(&q, "+")) != NULL) {
546183725Sjkoshy		for (pm = pmask; pm->pm_name && strcasecmp(r, pm->pm_name);
547183725Sjkoshy		    pm++)
548145256Sjkoshy			;
549145256Sjkoshy		if (pm->pm_name == NULL) /* not found */
550174406Sjkoshy			return (-1);
551145256Sjkoshy		*evmask |= pm->pm_value;
552145256Sjkoshy		c++;
553145256Sjkoshy	}
554174406Sjkoshy	return (c);
555145256Sjkoshy}
556145340Smarcel#endif
557145256Sjkoshy
558145256Sjkoshy#define	KWMATCH(p,kw)		(strcasecmp((p), (kw)) == 0)
559145256Sjkoshy#define	KWPREFIXMATCH(p,kw)	(strncasecmp((p), (kw), sizeof((kw)) - 1) == 0)
560145256Sjkoshy#define	EV_ALIAS(N,S)		{ .pm_alias = N, .pm_spec = S }
561145256Sjkoshy
562145340Smarcel#if defined(__i386__)
563145256Sjkoshy
564145256Sjkoshy/*
565145256Sjkoshy * AMD K7 (Athlon) CPUs.
566145256Sjkoshy */
567145256Sjkoshy
568145256Sjkoshystatic struct pmc_event_alias k7_aliases[] = {
569145351Sjkoshy	EV_ALIAS("branches",		"k7-retired-branches"),
570145351Sjkoshy	EV_ALIAS("branch-mispredicts",	"k7-retired-branches-mispredicted"),
571145351Sjkoshy	EV_ALIAS("cycles",		"tsc"),
572183075Sjkoshy	EV_ALIAS("dc-misses",		"k7-dc-misses"),
573145351Sjkoshy	EV_ALIAS("ic-misses",		"k7-ic-misses"),
574145351Sjkoshy	EV_ALIAS("instructions",	"k7-retired-instructions"),
575145351Sjkoshy	EV_ALIAS("interrupts",		"k7-hardware-interrupts"),
576145351Sjkoshy	EV_ALIAS(NULL, NULL)
577145256Sjkoshy};
578145256Sjkoshy
579145256Sjkoshy#define	K7_KW_COUNT	"count"
580145256Sjkoshy#define	K7_KW_EDGE	"edge"
581145256Sjkoshy#define	K7_KW_INV	"inv"
582145256Sjkoshy#define	K7_KW_OS	"os"
583145256Sjkoshy#define	K7_KW_UNITMASK	"unitmask"
584145256Sjkoshy#define	K7_KW_USR	"usr"
585145256Sjkoshy
586145256Sjkoshystatic int
587145256Sjkoshyk7_allocate_pmc(enum pmc_event pe, char *ctrspec,
588145256Sjkoshy    struct pmc_op_pmcallocate *pmc_config)
589145256Sjkoshy{
590183107Sjkoshy	char		*e, *p, *q;
591183107Sjkoshy	int		c, has_unitmask;
592145256Sjkoshy	uint32_t	count, unitmask;
593145256Sjkoshy
594147191Sjkoshy	pmc_config->pm_md.pm_amd.pm_amd_config = 0;
595183725Sjkoshy	pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE);
596145256Sjkoshy
597145256Sjkoshy	if (pe == PMC_EV_K7_DC_REFILLS_FROM_L2 ||
598145256Sjkoshy	    pe == PMC_EV_K7_DC_REFILLS_FROM_SYSTEM ||
599145256Sjkoshy	    pe == PMC_EV_K7_DC_WRITEBACKS) {
600145256Sjkoshy		has_unitmask = 1;
601147191Sjkoshy		unitmask = AMD_PMC_UNITMASK_MOESI;
602145256Sjkoshy	} else
603145256Sjkoshy		unitmask = has_unitmask = 0;
604145256Sjkoshy
605145256Sjkoshy	while ((p = strsep(&ctrspec, ",")) != NULL) {
606145256Sjkoshy		if (KWPREFIXMATCH(p, K7_KW_COUNT "=")) {
607145256Sjkoshy			q = strchr(p, '=');
608145256Sjkoshy			if (*++q == '\0') /* skip '=' */
609174406Sjkoshy				return (-1);
610145256Sjkoshy
611145256Sjkoshy			count = strtol(q, &e, 0);
612145256Sjkoshy			if (e == q || *e != '\0')
613174406Sjkoshy				return (-1);
614145256Sjkoshy
615145256Sjkoshy			pmc_config->pm_caps |= PMC_CAP_THRESHOLD;
616147191Sjkoshy			pmc_config->pm_md.pm_amd.pm_amd_config |=
617147191Sjkoshy			    AMD_PMC_TO_COUNTER(count);
618145256Sjkoshy
619145256Sjkoshy		} else if (KWMATCH(p, K7_KW_EDGE)) {
620145256Sjkoshy			pmc_config->pm_caps |= PMC_CAP_EDGE;
621145256Sjkoshy		} else if (KWMATCH(p, K7_KW_INV)) {
622145256Sjkoshy			pmc_config->pm_caps |= PMC_CAP_INVERT;
623145256Sjkoshy		} else if (KWMATCH(p, K7_KW_OS)) {
624145256Sjkoshy			pmc_config->pm_caps |= PMC_CAP_SYSTEM;
625145256Sjkoshy		} else if (KWPREFIXMATCH(p, K7_KW_UNITMASK "=")) {
626145256Sjkoshy			if (has_unitmask == 0)
627174406Sjkoshy				return (-1);
628145256Sjkoshy			unitmask = 0;
629145256Sjkoshy			q = strchr(p, '=');
630145256Sjkoshy			if (*++q == '\0') /* skip '=' */
631174406Sjkoshy				return (-1);
632145256Sjkoshy
633145256Sjkoshy			while ((c = tolower(*q++)) != 0)
634145256Sjkoshy				if (c == 'm')
635147191Sjkoshy					unitmask |= AMD_PMC_UNITMASK_M;
636145256Sjkoshy				else if (c == 'o')
637147191Sjkoshy					unitmask |= AMD_PMC_UNITMASK_O;
638145256Sjkoshy				else if (c == 'e')
639147191Sjkoshy					unitmask |= AMD_PMC_UNITMASK_E;
640145256Sjkoshy				else if (c == 's')
641147191Sjkoshy					unitmask |= AMD_PMC_UNITMASK_S;
642145256Sjkoshy				else if (c == 'i')
643147191Sjkoshy					unitmask |= AMD_PMC_UNITMASK_I;
644145256Sjkoshy				else if (c == '+')
645145256Sjkoshy					continue;
646145256Sjkoshy				else
647174406Sjkoshy					return (-1);
648145256Sjkoshy
649145256Sjkoshy			if (unitmask == 0)
650174406Sjkoshy				return (-1);
651145256Sjkoshy
652145256Sjkoshy		} else if (KWMATCH(p, K7_KW_USR)) {
653145256Sjkoshy			pmc_config->pm_caps |= PMC_CAP_USER;
654145256Sjkoshy		} else
655174406Sjkoshy			return (-1);
656145256Sjkoshy	}
657145256Sjkoshy
658145256Sjkoshy	if (has_unitmask) {
659145256Sjkoshy		pmc_config->pm_caps |= PMC_CAP_QUALIFIER;
660147191Sjkoshy		pmc_config->pm_md.pm_amd.pm_amd_config |=
661147191Sjkoshy		    AMD_PMC_TO_UNITMASK(unitmask);
662145256Sjkoshy	}
663145256Sjkoshy
664174406Sjkoshy	return (0);
665145256Sjkoshy
666145256Sjkoshy}
667145256Sjkoshy
668147191Sjkoshy#endif
669147191Sjkoshy
670147759Sjkoshy#if defined(__amd64__) || defined(__i386__)
671147191Sjkoshy
672145256Sjkoshy/*
673185363Sjkoshy * Intel Core (Family 6, Model E) PMCs.
674185363Sjkoshy */
675185363Sjkoshy
676185363Sjkoshystatic struct pmc_event_alias core_aliases[] = {
677185363Sjkoshy	EV_ALIAS("branches",		"iap-br-instr-ret"),
678185363Sjkoshy	EV_ALIAS("branch-mispredicts",	"iap-br-mispred-ret"),
679185363Sjkoshy	EV_ALIAS("cycles",		"tsc-tsc"),
680185363Sjkoshy	EV_ALIAS("ic-misses",		"iap-icache-misses"),
681185363Sjkoshy	EV_ALIAS("instructions",	"iap-instr-ret"),
682185363Sjkoshy	EV_ALIAS("interrupts",		"iap-core-hw-int-rx"),
683185363Sjkoshy	EV_ALIAS("unhalted-cycles",	"iap-unhalted-core-cycles"),
684185363Sjkoshy	EV_ALIAS(NULL, NULL)
685185363Sjkoshy};
686185363Sjkoshy
687185363Sjkoshy/*
688185363Sjkoshy * Intel Core2 (Family 6, Model F), Core2Extreme (Family 6, Model 17H)
689185363Sjkoshy * and Atom (Family 6, model 1CH) PMCs.
690198433Sjkoshy *
691198433Sjkoshy * We map aliases to events on the fixed-function counters if these
692198433Sjkoshy * are present.  Note that not all CPUs in this family contain fixed-function
693198433Sjkoshy * counters.
694185363Sjkoshy */
695185363Sjkoshy
696185363Sjkoshystatic struct pmc_event_alias core2_aliases[] = {
697185363Sjkoshy	EV_ALIAS("branches",		"iap-br-inst-retired.any"),
698185363Sjkoshy	EV_ALIAS("branch-mispredicts",	"iap-br-inst-retired.mispred"),
699185363Sjkoshy	EV_ALIAS("cycles",		"tsc-tsc"),
700185363Sjkoshy	EV_ALIAS("ic-misses",		"iap-l1i-misses"),
701185363Sjkoshy	EV_ALIAS("instructions",	"iaf-instr-retired.any"),
702185363Sjkoshy	EV_ALIAS("interrupts",		"iap-hw-int-rcv"),
703185363Sjkoshy	EV_ALIAS("unhalted-cycles",	"iaf-cpu-clk-unhalted.core"),
704185363Sjkoshy	EV_ALIAS(NULL, NULL)
705185363Sjkoshy};
706185363Sjkoshy
707198433Sjkoshystatic struct pmc_event_alias core2_aliases_without_iaf[] = {
708198433Sjkoshy	EV_ALIAS("branches",		"iap-br-inst-retired.any"),
709198433Sjkoshy	EV_ALIAS("branch-mispredicts",	"iap-br-inst-retired.mispred"),
710198433Sjkoshy	EV_ALIAS("cycles",		"tsc-tsc"),
711198433Sjkoshy	EV_ALIAS("ic-misses",		"iap-l1i-misses"),
712198433Sjkoshy	EV_ALIAS("instructions",	"iap-inst-retired.any_p"),
713198433Sjkoshy	EV_ALIAS("interrupts",		"iap-hw-int-rcv"),
714198433Sjkoshy	EV_ALIAS("unhalted-cycles",	"iap-cpu-clk-unhalted.core_p"),
715198433Sjkoshy	EV_ALIAS(NULL, NULL)
716198433Sjkoshy};
717198433Sjkoshy
718198433Sjkoshy#define	atom_aliases			core2_aliases
719198433Sjkoshy#define	atom_aliases_without_iaf	core2_aliases_without_iaf
720263446Shiren#define	atom_silvermont_aliases		core2_aliases
721263446Shiren#define	atom_silvermont_aliases_without_iaf	core2_aliases_without_iaf
722198433Sjkoshy#define corei7_aliases			core2_aliases
723198433Sjkoshy#define corei7_aliases_without_iaf	core2_aliases_without_iaf
724267062Skib#define nehalem_ex_aliases		core2_aliases
725267062Skib#define nehalem_ex_aliases_without_iaf	core2_aliases_without_iaf
726248842Ssbruno#define haswell_aliases			core2_aliases
727248842Ssbruno#define haswell_aliases_without_iaf	core2_aliases_without_iaf
728277177Srrs#define haswell_xeon_aliases			core2_aliases
729277177Srrs#define haswell_xeon_aliases_without_iaf	core2_aliases_without_iaf
730291494Srrs#define broadwell_aliases			core2_aliases
731291494Srrs#define broadwell_aliases_without_iaf	core2_aliases_without_iaf
732291494Srrs#define broadwell_xeon_aliases			core2_aliases
733291494Srrs#define broadwell_xeon_aliases_without_iaf	core2_aliases_without_iaf
734291494Srrs#define skylake_aliases			core2_aliases
735291494Srrs#define skylake_aliases_without_iaf	core2_aliases_without_iaf
736323799Skib#define skylake_xeon_aliases		core2_aliases
737323799Skib#define skylake_xeon_aliases_without_iaf	core2_aliases_without_iaf
738240164Sfabient#define ivybridge_aliases		core2_aliases
739240164Sfabient#define ivybridge_aliases_without_iaf	core2_aliases_without_iaf
740246166Ssbruno#define ivybridge_xeon_aliases		core2_aliases
741246166Ssbruno#define ivybridge_xeon_aliases_without_iaf	core2_aliases_without_iaf
742232366Sdavide#define sandybridge_aliases		core2_aliases
743232366Sdavide#define sandybridge_aliases_without_iaf	core2_aliases_without_iaf
744241738Ssbruno#define sandybridge_xeon_aliases	core2_aliases
745241738Ssbruno#define sandybridge_xeon_aliases_without_iaf	core2_aliases_without_iaf
746206089Sfabient#define westmere_aliases		core2_aliases
747206089Sfabient#define westmere_aliases_without_iaf	core2_aliases_without_iaf
748267062Skib#define westmere_ex_aliases		core2_aliases
749267062Skib#define westmere_ex_aliases_without_iaf	core2_aliases_without_iaf
750198433Sjkoshy
751185363Sjkoshy#define	IAF_KW_OS		"os"
752185363Sjkoshy#define	IAF_KW_USR		"usr"
753185363Sjkoshy#define	IAF_KW_ANYTHREAD	"anythread"
754185363Sjkoshy
755185363Sjkoshy/*
756185363Sjkoshy * Parse an event specifier for Intel fixed function counters.
757185363Sjkoshy */
758185363Sjkoshystatic int
759185363Sjkoshyiaf_allocate_pmc(enum pmc_event pe, char *ctrspec,
760185363Sjkoshy    struct pmc_op_pmcallocate *pmc_config)
761185363Sjkoshy{
762185363Sjkoshy	char *p;
763185363Sjkoshy
764185363Sjkoshy	(void) pe;
765185363Sjkoshy
766185363Sjkoshy	pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE);
767185363Sjkoshy	pmc_config->pm_md.pm_iaf.pm_iaf_flags = 0;
768185363Sjkoshy
769185363Sjkoshy	while ((p = strsep(&ctrspec, ",")) != NULL) {
770185363Sjkoshy		if (KWMATCH(p, IAF_KW_OS))
771185363Sjkoshy			pmc_config->pm_caps |= PMC_CAP_SYSTEM;
772185363Sjkoshy		else if (KWMATCH(p, IAF_KW_USR))
773185363Sjkoshy			pmc_config->pm_caps |= PMC_CAP_USER;
774185363Sjkoshy		else if (KWMATCH(p, IAF_KW_ANYTHREAD))
775185363Sjkoshy			pmc_config->pm_md.pm_iaf.pm_iaf_flags |= IAF_ANY;
776185363Sjkoshy		else
777185363Sjkoshy			return (-1);
778185363Sjkoshy	}
779185363Sjkoshy
780185363Sjkoshy	return (0);
781185363Sjkoshy}
782185363Sjkoshy
783185363Sjkoshy/*
784185363Sjkoshy * Core/Core2 support.
785185363Sjkoshy */
786185363Sjkoshy
787185363Sjkoshy#define	IAP_KW_AGENT		"agent"
788185363Sjkoshy#define	IAP_KW_ANYTHREAD	"anythread"
789185363Sjkoshy#define	IAP_KW_CACHESTATE	"cachestate"
790185363Sjkoshy#define	IAP_KW_CMASK		"cmask"
791185363Sjkoshy#define	IAP_KW_CORE		"core"
792185363Sjkoshy#define	IAP_KW_EDGE		"edge"
793185363Sjkoshy#define	IAP_KW_INV		"inv"
794185363Sjkoshy#define	IAP_KW_OS		"os"
795185363Sjkoshy#define	IAP_KW_PREFETCH		"prefetch"
796185363Sjkoshy#define	IAP_KW_SNOOPRESPONSE	"snoopresponse"
797185363Sjkoshy#define	IAP_KW_SNOOPTYPE	"snooptype"
798185363Sjkoshy#define	IAP_KW_TRANSITION	"trans"
799185363Sjkoshy#define	IAP_KW_USR		"usr"
800206089Sfabient#define	IAP_KW_RSP		"rsp"
801185363Sjkoshy
802185363Sjkoshystatic struct pmc_masks iap_core_mask[] = {
803185363Sjkoshy	PMCMASK(all,	(0x3 << 14)),
804185363Sjkoshy	PMCMASK(this,	(0x1 << 14)),
805185363Sjkoshy	NULLMASK
806185363Sjkoshy};
807185363Sjkoshy
808185363Sjkoshystatic struct pmc_masks iap_agent_mask[] = {
809185363Sjkoshy	PMCMASK(this,	0),
810185363Sjkoshy	PMCMASK(any,	(0x1 << 13)),
811185363Sjkoshy	NULLMASK
812185363Sjkoshy};
813185363Sjkoshy
814185363Sjkoshystatic struct pmc_masks iap_prefetch_mask[] = {
815185363Sjkoshy	PMCMASK(both,		(0x3 << 12)),
816185363Sjkoshy	PMCMASK(only,		(0x1 << 12)),
817185363Sjkoshy	PMCMASK(exclude,	0),
818185363Sjkoshy	NULLMASK
819185363Sjkoshy};
820185363Sjkoshy
821185363Sjkoshystatic struct pmc_masks iap_cachestate_mask[] = {
822185363Sjkoshy	PMCMASK(i,		(1 <<  8)),
823185363Sjkoshy	PMCMASK(s,		(1 <<  9)),
824185363Sjkoshy	PMCMASK(e,		(1 << 10)),
825185363Sjkoshy	PMCMASK(m,		(1 << 11)),
826185363Sjkoshy	NULLMASK
827185363Sjkoshy};
828185363Sjkoshy
829185363Sjkoshystatic struct pmc_masks iap_snoopresponse_mask[] = {
830185363Sjkoshy	PMCMASK(clean,		(1 << 8)),
831185363Sjkoshy	PMCMASK(hit,		(1 << 9)),
832185363Sjkoshy	PMCMASK(hitm,		(1 << 11)),
833185363Sjkoshy	NULLMASK
834185363Sjkoshy};
835185363Sjkoshy
836185363Sjkoshystatic struct pmc_masks iap_snooptype_mask[] = {
837185363Sjkoshy	PMCMASK(cmp2s,		(1 << 8)),
838185363Sjkoshy	PMCMASK(cmp2i,		(1 << 9)),
839185363Sjkoshy	NULLMASK
840185363Sjkoshy};
841185363Sjkoshy
842185363Sjkoshystatic struct pmc_masks iap_transition_mask[] = {
843185363Sjkoshy	PMCMASK(any,		0x00),
844185363Sjkoshy	PMCMASK(frequency,	0x10),
845185363Sjkoshy	NULLMASK
846185363Sjkoshy};
847185363Sjkoshy
848240164Sfabientstatic struct pmc_masks iap_rsp_mask_i7_wm[] = {
849206089Sfabient	PMCMASK(DMND_DATA_RD,		(1 <<  0)),
850206089Sfabient	PMCMASK(DMND_RFO,		(1 <<  1)),
851206089Sfabient	PMCMASK(DMND_IFETCH,		(1 <<  2)),
852206089Sfabient	PMCMASK(WB,			(1 <<  3)),
853206089Sfabient	PMCMASK(PF_DATA_RD,		(1 <<  4)),
854206089Sfabient	PMCMASK(PF_RFO,			(1 <<  5)),
855206089Sfabient	PMCMASK(PF_IFETCH,		(1 <<  6)),
856206089Sfabient	PMCMASK(OTHER,			(1 <<  7)),
857206089Sfabient	PMCMASK(UNCORE_HIT,		(1 <<  8)),
858206089Sfabient	PMCMASK(OTHER_CORE_HIT_SNP,	(1 <<  9)),
859206089Sfabient	PMCMASK(OTHER_CORE_HITM,	(1 << 10)),
860206089Sfabient	PMCMASK(REMOTE_CACHE_FWD,	(1 << 12)),
861206089Sfabient	PMCMASK(REMOTE_DRAM,		(1 << 13)),
862206089Sfabient	PMCMASK(LOCAL_DRAM,		(1 << 14)),
863206089Sfabient	PMCMASK(NON_DRAM,		(1 << 15)),
864206089Sfabient	NULLMASK
865206089Sfabient};
866206089Sfabient
867241738Ssbrunostatic struct pmc_masks iap_rsp_mask_sb_sbx_ib[] = {
868240164Sfabient	PMCMASK(REQ_DMND_DATA_RD,	(1ULL <<  0)),
869240164Sfabient	PMCMASK(REQ_DMND_RFO,		(1ULL <<  1)),
870240164Sfabient	PMCMASK(REQ_DMND_IFETCH,	(1ULL <<  2)),
871240164Sfabient	PMCMASK(REQ_WB,			(1ULL <<  3)),
872240164Sfabient	PMCMASK(REQ_PF_DATA_RD,		(1ULL <<  4)),
873240164Sfabient	PMCMASK(REQ_PF_RFO,		(1ULL <<  5)),
874240164Sfabient	PMCMASK(REQ_PF_IFETCH,		(1ULL <<  6)),
875240164Sfabient	PMCMASK(REQ_PF_LLC_DATA_RD,	(1ULL <<  7)),
876240164Sfabient	PMCMASK(REQ_PF_LLC_RFO,		(1ULL <<  8)),
877240164Sfabient	PMCMASK(REQ_PF_LLC_IFETCH,	(1ULL <<  9)),
878240164Sfabient	PMCMASK(REQ_BUS_LOCKS,		(1ULL << 10)),
879240164Sfabient	PMCMASK(REQ_STRM_ST,		(1ULL << 11)),
880240164Sfabient	PMCMASK(REQ_OTHER,		(1ULL << 15)),
881240164Sfabient	PMCMASK(RES_ANY,		(1ULL << 16)),
882240164Sfabient	PMCMASK(RES_SUPPLIER_SUPP,	(1ULL << 17)),
883240164Sfabient	PMCMASK(RES_SUPPLIER_LLC_HITM,	(1ULL << 18)),
884240164Sfabient	PMCMASK(RES_SUPPLIER_LLC_HITE,	(1ULL << 19)),
885240164Sfabient	PMCMASK(RES_SUPPLIER_LLC_HITS,	(1ULL << 20)),
886240164Sfabient	PMCMASK(RES_SUPPLIER_LLC_HITF,	(1ULL << 21)),
887240164Sfabient	PMCMASK(RES_SUPPLIER_LOCAL,	(1ULL << 22)),
888241974Ssbruno	PMCMASK(RES_SNOOP_SNP_NONE,	(1ULL << 31)),
889240164Sfabient	PMCMASK(RES_SNOOP_SNP_NO_NEEDED,(1ULL << 32)),
890240164Sfabient	PMCMASK(RES_SNOOP_SNP_MISS,	(1ULL << 33)),
891240164Sfabient	PMCMASK(RES_SNOOP_HIT_NO_FWD,	(1ULL << 34)),
892240164Sfabient	PMCMASK(RES_SNOOP_HIT_FWD,	(1ULL << 35)),
893240164Sfabient	PMCMASK(RES_SNOOP_HITM,		(1ULL << 36)),
894240164Sfabient	PMCMASK(RES_NON_DRAM,		(1ULL << 37)),
895240164Sfabient	NULLMASK
896240164Sfabient};
897240164Sfabient
898291494Srrs/* Broadwell is defined to use the same mask as Haswell */
899248842Ssbrunostatic struct pmc_masks iap_rsp_mask_haswell[] = {
900248842Ssbruno	PMCMASK(REQ_DMND_DATA_RD,	(1ULL <<  0)),
901248842Ssbruno	PMCMASK(REQ_DMND_RFO,		(1ULL <<  1)),
902248842Ssbruno	PMCMASK(REQ_DMND_IFETCH,	(1ULL <<  2)),
903248842Ssbruno	PMCMASK(REQ_PF_DATA_RD,		(1ULL <<  4)),
904248842Ssbruno	PMCMASK(REQ_PF_RFO,		(1ULL <<  5)),
905248842Ssbruno	PMCMASK(REQ_PF_IFETCH,		(1ULL <<  6)),
906248842Ssbruno	PMCMASK(REQ_OTHER,		(1ULL << 15)),
907248842Ssbruno	PMCMASK(RES_ANY,		(1ULL << 16)),
908248842Ssbruno	PMCMASK(RES_SUPPLIER_SUPP,	(1ULL << 17)),
909248842Ssbruno	PMCMASK(RES_SUPPLIER_LLC_HITM,	(1ULL << 18)),
910248842Ssbruno	PMCMASK(RES_SUPPLIER_LLC_HITE,	(1ULL << 19)),
911248842Ssbruno	PMCMASK(RES_SUPPLIER_LLC_HITS,	(1ULL << 20)),
912248842Ssbruno	PMCMASK(RES_SUPPLIER_LLC_HITF,	(1ULL << 21)),
913248842Ssbruno	PMCMASK(RES_SUPPLIER_LOCAL,	(1ULL << 22)),
914291494Srrs	/*
915291494Srrs	 * For processor type 06_45H 22 is L4_HIT_LOCAL_L4
916291494Srrs	 * and 23, 24 and 25 are also defined.
917291494Srrs	 */
918248842Ssbruno	PMCMASK(RES_SNOOP_SNP_NONE,	(1ULL << 31)),
919248842Ssbruno	PMCMASK(RES_SNOOP_SNP_NO_NEEDED,(1ULL << 32)),
920248842Ssbruno	PMCMASK(RES_SNOOP_SNP_MISS,	(1ULL << 33)),
921248842Ssbruno	PMCMASK(RES_SNOOP_HIT_NO_FWD,	(1ULL << 34)),
922248842Ssbruno	PMCMASK(RES_SNOOP_HIT_FWD,	(1ULL << 35)),
923248842Ssbruno	PMCMASK(RES_SNOOP_HITM,		(1ULL << 36)),
924248842Ssbruno	PMCMASK(RES_NON_DRAM,		(1ULL << 37)),
925248842Ssbruno	NULLMASK
926248842Ssbruno};
927248842Ssbruno
928291494Srrsstatic struct pmc_masks iap_rsp_mask_skylake[] = {
929291494Srrs	PMCMASK(REQ_DMND_DATA_RD,	(1ULL <<  0)),
930291494Srrs	PMCMASK(REQ_DMND_RFO,		(1ULL <<  1)),
931291494Srrs	PMCMASK(REQ_DMND_IFETCH,	(1ULL <<  2)),
932291494Srrs	PMCMASK(REQ_PF_DATA_RD,		(1ULL <<  7)),
933291494Srrs	PMCMASK(REQ_PF_RFO,		(1ULL <<  8)),
934291494Srrs	PMCMASK(REQ_STRM_ST,		(1ULL << 11)),
935291494Srrs	PMCMASK(REQ_OTHER,		(1ULL << 15)),
936291494Srrs	PMCMASK(RES_ANY,		(1ULL << 16)),
937291494Srrs	PMCMASK(RES_SUPPLIER_SUPP,	(1ULL << 17)),
938291494Srrs	PMCMASK(RES_SUPPLIER_LLC_HITM,	(1ULL << 18)),
939291494Srrs	PMCMASK(RES_SUPPLIER_LLC_HITE,	(1ULL << 19)),
940291494Srrs	PMCMASK(RES_SUPPLIER_LLC_HITS,	(1ULL << 20)),
941291494Srrs	PMCMASK(RES_SUPPLIER_L4_HIT,	(1ULL << 22)),
942291494Srrs	PMCMASK(RES_SUPPLIER_DRAM,	(1ULL << 26)),
943291494Srrs	PMCMASK(RES_SUPPLIER_SPL_HIT,	(1ULL << 30)),
944291494Srrs	PMCMASK(RES_SNOOP_SNP_NONE,	(1ULL << 31)),
945291494Srrs	PMCMASK(RES_SNOOP_SNP_NO_NEEDED,(1ULL << 32)),
946291494Srrs	PMCMASK(RES_SNOOP_SNP_MISS,	(1ULL << 33)),
947291494Srrs	PMCMASK(RES_SNOOP_HIT_NO_FWD,	(1ULL << 34)),
948291494Srrs	PMCMASK(RES_SNOOP_HIT_FWD,	(1ULL << 35)),
949291494Srrs	PMCMASK(RES_SNOOP_HITM,		(1ULL << 36)),
950291494Srrs	PMCMASK(RES_NON_DRAM,		(1ULL << 37)),
951291494Srrs	NULLMASK
952291494Srrs};
953291494Srrs
954291494Srrs
955185363Sjkoshystatic int
956185363Sjkoshyiap_allocate_pmc(enum pmc_event pe, char *ctrspec,
957185363Sjkoshy    struct pmc_op_pmcallocate *pmc_config)
958185363Sjkoshy{
959185363Sjkoshy	char *e, *p, *q;
960240164Sfabient	uint64_t cachestate, evmask, rsp;
961185363Sjkoshy	int count, n;
962185363Sjkoshy
963185363Sjkoshy	pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE |
964185363Sjkoshy	    PMC_CAP_QUALIFIER);
965185363Sjkoshy	pmc_config->pm_md.pm_iap.pm_iap_config = 0;
966185363Sjkoshy
967206089Sfabient	cachestate = evmask = rsp = 0;
968185363Sjkoshy
969185363Sjkoshy	/* Parse additional modifiers if present */
970185363Sjkoshy	while ((p = strsep(&ctrspec, ",")) != NULL) {
971185363Sjkoshy
972185363Sjkoshy		n = 0;
973185363Sjkoshy		if (KWPREFIXMATCH(p, IAP_KW_CMASK "=")) {
974185363Sjkoshy			q = strchr(p, '=');
975185363Sjkoshy			if (*++q == '\0') /* skip '=' */
976185363Sjkoshy				return (-1);
977185363Sjkoshy			count = strtol(q, &e, 0);
978185363Sjkoshy			if (e == q || *e != '\0')
979185363Sjkoshy				return (-1);
980185363Sjkoshy			pmc_config->pm_caps |= PMC_CAP_THRESHOLD;
981185363Sjkoshy			pmc_config->pm_md.pm_iap.pm_iap_config |=
982185363Sjkoshy			    IAP_CMASK(count);
983185363Sjkoshy		} else if (KWMATCH(p, IAP_KW_EDGE)) {
984185363Sjkoshy			pmc_config->pm_caps |= PMC_CAP_EDGE;
985185363Sjkoshy		} else if (KWMATCH(p, IAP_KW_INV)) {
986185363Sjkoshy			pmc_config->pm_caps |= PMC_CAP_INVERT;
987185363Sjkoshy		} else if (KWMATCH(p, IAP_KW_OS)) {
988185363Sjkoshy			pmc_config->pm_caps |= PMC_CAP_SYSTEM;
989185363Sjkoshy		} else if (KWMATCH(p, IAP_KW_USR)) {
990185363Sjkoshy			pmc_config->pm_caps |= PMC_CAP_USER;
991185363Sjkoshy		} else if (KWMATCH(p, IAP_KW_ANYTHREAD)) {
992185363Sjkoshy			pmc_config->pm_md.pm_iap.pm_iap_config |= IAP_ANY;
993193809Sjkoshy		} else if (KWPREFIXMATCH(p, IAP_KW_CORE "=")) {
994185363Sjkoshy			n = pmc_parse_mask(iap_core_mask, p, &evmask);
995185363Sjkoshy			if (n != 1)
996185363Sjkoshy				return (-1);
997193809Sjkoshy		} else if (KWPREFIXMATCH(p, IAP_KW_AGENT "=")) {
998185363Sjkoshy			n = pmc_parse_mask(iap_agent_mask, p, &evmask);
999185363Sjkoshy			if (n != 1)
1000185363Sjkoshy				return (-1);
1001193809Sjkoshy		} else if (KWPREFIXMATCH(p, IAP_KW_PREFETCH "=")) {
1002185363Sjkoshy			n = pmc_parse_mask(iap_prefetch_mask, p, &evmask);
1003185363Sjkoshy			if (n != 1)
1004185363Sjkoshy				return (-1);
1005193809Sjkoshy		} else if (KWPREFIXMATCH(p, IAP_KW_CACHESTATE "=")) {
1006185363Sjkoshy			n = pmc_parse_mask(iap_cachestate_mask, p, &cachestate);
1007185363Sjkoshy		} else if (cpu_info.pm_cputype == PMC_CPU_INTEL_CORE &&
1008193809Sjkoshy		    KWPREFIXMATCH(p, IAP_KW_TRANSITION "=")) {
1009185363Sjkoshy			n = pmc_parse_mask(iap_transition_mask, p, &evmask);
1010185363Sjkoshy			if (n != 1)
1011185363Sjkoshy				return (-1);
1012185363Sjkoshy		} else if (cpu_info.pm_cputype == PMC_CPU_INTEL_ATOM ||
1013263446Shiren		    cpu_info.pm_cputype == PMC_CPU_INTEL_ATOM_SILVERMONT ||
1014185585Sjkoshy		    cpu_info.pm_cputype == PMC_CPU_INTEL_CORE2 ||
1015206089Sfabient		    cpu_info.pm_cputype == PMC_CPU_INTEL_CORE2EXTREME) {
1016193809Sjkoshy			if (KWPREFIXMATCH(p, IAP_KW_SNOOPRESPONSE "=")) {
1017185363Sjkoshy				n = pmc_parse_mask(iap_snoopresponse_mask, p,
1018185363Sjkoshy				    &evmask);
1019193809Sjkoshy			} else if (KWPREFIXMATCH(p, IAP_KW_SNOOPTYPE "=")) {
1020185363Sjkoshy				n = pmc_parse_mask(iap_snooptype_mask, p,
1021185363Sjkoshy				    &evmask);
1022185363Sjkoshy			} else
1023185363Sjkoshy				return (-1);
1024206089Sfabient		} else if (cpu_info.pm_cputype == PMC_CPU_INTEL_COREI7 ||
1025267062Skib		    cpu_info.pm_cputype == PMC_CPU_INTEL_WESTMERE ||
1026267062Skib		    cpu_info.pm_cputype == PMC_CPU_INTEL_NEHALEM_EX ||
1027267062Skib		    cpu_info.pm_cputype == PMC_CPU_INTEL_WESTMERE_EX) {
1028206089Sfabient			if (KWPREFIXMATCH(p, IAP_KW_RSP "=")) {
1029240164Sfabient				n = pmc_parse_mask(iap_rsp_mask_i7_wm, p, &rsp);
1030206089Sfabient			} else
1031206089Sfabient				return (-1);
1032240164Sfabient		} else if (cpu_info.pm_cputype == PMC_CPU_INTEL_SANDYBRIDGE ||
1033241738Ssbruno		    cpu_info.pm_cputype == PMC_CPU_INTEL_SANDYBRIDGE_XEON ||
1034323798Skib		    cpu_info.pm_cputype == PMC_CPU_INTEL_IVYBRIDGE ||
1035323798Skib		    cpu_info.pm_cputype == PMC_CPU_INTEL_IVYBRIDGE_XEON ) {
1036240164Sfabient			if (KWPREFIXMATCH(p, IAP_KW_RSP "=")) {
1037241738Ssbruno				n = pmc_parse_mask(iap_rsp_mask_sb_sbx_ib, p, &rsp);
1038240164Sfabient			} else
1039240164Sfabient				return (-1);
1040277177Srrs		} else if (cpu_info.pm_cputype == PMC_CPU_INTEL_HASWELL ||
1041323798Skib		    cpu_info.pm_cputype == PMC_CPU_INTEL_HASWELL_XEON) {
1042248842Ssbruno			if (KWPREFIXMATCH(p, IAP_KW_RSP "=")) {
1043248842Ssbruno				n = pmc_parse_mask(iap_rsp_mask_haswell, p, &rsp);
1044248842Ssbruno			} else
1045248842Ssbruno				return (-1);
1046291494Srrs		} else if (cpu_info.pm_cputype == PMC_CPU_INTEL_BROADWELL ||
1047323798Skib		    cpu_info.pm_cputype == PMC_CPU_INTEL_BROADWELL_XEON) {
1048291494Srrs			/* Broadwell is defined to use same mask as haswell */
1049291494Srrs			if (KWPREFIXMATCH(p, IAP_KW_RSP "=")) {
1050291494Srrs				n = pmc_parse_mask(iap_rsp_mask_haswell, p, &rsp);
1051291494Srrs			} else
1052291494Srrs				return (-1);
1053291494Srrs
1054323799Skib		} else if (cpu_info.pm_cputype == PMC_CPU_INTEL_SKYLAKE ||
1055323799Skib		    cpu_info.pm_cputype == PMC_CPU_INTEL_SKYLAKE_XEON) {
1056291494Srrs			if (KWPREFIXMATCH(p, IAP_KW_RSP "=")) {
1057291494Srrs				n = pmc_parse_mask(iap_rsp_mask_skylake, p, &rsp);
1058291494Srrs			} else
1059291494Srrs				return (-1);
1060291494Srrs
1061185363Sjkoshy		} else
1062185363Sjkoshy			return (-1);
1063185363Sjkoshy
1064185363Sjkoshy		if (n < 0)	/* Parsing failed. */
1065185363Sjkoshy			return (-1);
1066185363Sjkoshy	}
1067185363Sjkoshy
1068185363Sjkoshy	pmc_config->pm_md.pm_iap.pm_iap_config |= evmask;
1069185363Sjkoshy
1070185363Sjkoshy	/*
1071185363Sjkoshy	 * If the event requires a 'cachestate' qualifier but was not
1072185363Sjkoshy	 * specified by the user, use a sensible default.
1073185363Sjkoshy	 */
1074185363Sjkoshy	switch (pe) {
1075185363Sjkoshy	case PMC_EV_IAP_EVENT_28H: /* Core, Core2, Atom */
1076185363Sjkoshy	case PMC_EV_IAP_EVENT_29H: /* Core, Core2, Atom */
1077185363Sjkoshy	case PMC_EV_IAP_EVENT_2AH: /* Core, Core2, Atom */
1078185363Sjkoshy	case PMC_EV_IAP_EVENT_2BH: /* Atom, Core2 */
1079185363Sjkoshy	case PMC_EV_IAP_EVENT_2EH: /* Core, Core2, Atom */
1080185363Sjkoshy	case PMC_EV_IAP_EVENT_30H: /* Core, Core2, Atom */
1081185363Sjkoshy	case PMC_EV_IAP_EVENT_32H: /* Core */
1082185363Sjkoshy	case PMC_EV_IAP_EVENT_40H: /* Core */
1083185363Sjkoshy	case PMC_EV_IAP_EVENT_41H: /* Core */
1084185363Sjkoshy	case PMC_EV_IAP_EVENT_42H: /* Core, Core2, Atom */
1085185363Sjkoshy		if (cachestate == 0)
1086185363Sjkoshy			cachestate = (0xF << 8);
1087207482Srstone		break;
1088207482Srstone	case PMC_EV_IAP_EVENT_77H: /* Atom */
1089207482Srstone		/* IAP_EVENT_77H only accepts a cachestate qualifier on the
1090207482Srstone		 * Atom processor
1091207482Srstone		 */
1092207482Srstone		if(cpu_info.pm_cputype == PMC_CPU_INTEL_ATOM && cachestate == 0)
1093207482Srstone			cachestate = (0xF << 8);
1094207482Srstone	    break;
1095185363Sjkoshy	default:
1096185363Sjkoshy		break;
1097185363Sjkoshy	}
1098185363Sjkoshy
1099185363Sjkoshy	pmc_config->pm_md.pm_iap.pm_iap_config |= cachestate;
1100206089Sfabient	pmc_config->pm_md.pm_iap.pm_iap_rsp = rsp;
1101185363Sjkoshy
1102185363Sjkoshy	return (0);
1103185363Sjkoshy}
1104185363Sjkoshy
1105185363Sjkoshy/*
1106206089Sfabient * Intel Uncore.
1107206089Sfabient */
1108206089Sfabient
1109206089Sfabientstatic int
1110206089Sfabientucf_allocate_pmc(enum pmc_event pe, char *ctrspec,
1111206089Sfabient    struct pmc_op_pmcallocate *pmc_config)
1112206089Sfabient{
1113206089Sfabient	(void) pe;
1114206089Sfabient	(void) ctrspec;
1115206089Sfabient
1116206089Sfabient	pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE);
1117206089Sfabient	pmc_config->pm_md.pm_ucf.pm_ucf_flags = 0;
1118206089Sfabient
1119206089Sfabient	return (0);
1120206089Sfabient}
1121206089Sfabient
1122206089Sfabient#define	UCP_KW_CMASK		"cmask"
1123206089Sfabient#define	UCP_KW_EDGE		"edge"
1124206089Sfabient#define	UCP_KW_INV		"inv"
1125206089Sfabient
1126206089Sfabientstatic int
1127206089Sfabientucp_allocate_pmc(enum pmc_event pe, char *ctrspec,
1128206089Sfabient    struct pmc_op_pmcallocate *pmc_config)
1129206089Sfabient{
1130206089Sfabient	char *e, *p, *q;
1131206089Sfabient	int count, n;
1132206089Sfabient
1133206089Sfabient	(void) pe;
1134206089Sfabient
1135206089Sfabient	pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE |
1136206089Sfabient	    PMC_CAP_QUALIFIER);
1137206089Sfabient	pmc_config->pm_md.pm_ucp.pm_ucp_config = 0;
1138206089Sfabient
1139206089Sfabient	/* Parse additional modifiers if present */
1140206089Sfabient	while ((p = strsep(&ctrspec, ",")) != NULL) {
1141206089Sfabient
1142206089Sfabient		n = 0;
1143206089Sfabient		if (KWPREFIXMATCH(p, UCP_KW_CMASK "=")) {
1144206089Sfabient			q = strchr(p, '=');
1145206089Sfabient			if (*++q == '\0') /* skip '=' */
1146206089Sfabient				return (-1);
1147206089Sfabient			count = strtol(q, &e, 0);
1148206089Sfabient			if (e == q || *e != '\0')
1149206089Sfabient				return (-1);
1150206089Sfabient			pmc_config->pm_caps |= PMC_CAP_THRESHOLD;
1151206089Sfabient			pmc_config->pm_md.pm_ucp.pm_ucp_config |=
1152206089Sfabient			    UCP_CMASK(count);
1153206089Sfabient		} else if (KWMATCH(p, UCP_KW_EDGE)) {
1154206089Sfabient			pmc_config->pm_caps |= PMC_CAP_EDGE;
1155206089Sfabient		} else if (KWMATCH(p, UCP_KW_INV)) {
1156206089Sfabient			pmc_config->pm_caps |= PMC_CAP_INVERT;
1157206089Sfabient		} else
1158206089Sfabient			return (-1);
1159206089Sfabient
1160206089Sfabient		if (n < 0)	/* Parsing failed. */
1161206089Sfabient			return (-1);
1162206089Sfabient	}
1163206089Sfabient
1164206089Sfabient	return (0);
1165206089Sfabient}
1166339767Smmacy/* AMD Fam17H PMCs */
1167339767Smmacystatic struct pmc_event_alias f17h_aliases[] = {
1168339767Smmacy	EV_ALIAS("branches",		"ex_ret_brn_tkn"),
1169339767Smmacy	EV_ALIAS("branch-mispredicts",
1170339767Smmacy	    "ex_ret_brn_tkn_misp"),
1171339767Smmacy	EV_ALIAS("cycles",		"tsc"),
1172339767Smmacy	EV_ALIAS("dc-access",		"ls_dc_access"),
1173339767Smmacy	EV_ALIAS("ic-misses",		"ic_fw32_miss"),
1174339767Smmacy	EV_ALIAS("instructions",	"ex_ret_inst"),
1175339767Smmacy	EV_ALIAS("unhalted-cycles",	"ls_not_halted_cycle"),
1176339767Smmacy	EV_ALIAS(NULL, NULL)
1177339767Smmacy};
1178339767Smmacy#define	__F17HMASK(N, V) PMCMASK(N, (1 << (V)))
1179339767Smmacystatic const struct pmc_masks f17h_mask_FPU_PIPEASSIGMENT[] = {
1180339767Smmacy	__F17HMASK(FPU_PIPEASSIGMENT_uOP_P0,	0),
1181339767Smmacy	__F17HMASK(FPU_PIPEASSIGMENT_uOP_P1,	1),
1182339767Smmacy	__F17HMASK(FPU_PIPEASSIGMENT_uOP_P2,	2),
1183339767Smmacy	__F17HMASK(FPU_PIPEASSIGMENT_uOP_P3,	3),
1184339767Smmacy	__F17HMASK(FPU_PIPEASSIGMENT_MultiuOP_P0,	4),
1185339767Smmacy	__F17HMASK(FPU_PIPEASSIGMENT_MultiuOP_P1,	5),
1186339767Smmacy	__F17HMASK(FPU_PIPEASSIGMENT_MultiuOP_P2,	6),
1187339767Smmacy	__F17HMASK(FPU_PIPEASSIGMENT_MultiuOP_P3,	7),
1188339767Smmacy	NULLMASK
1189339767Smmacy};
1190339767Smmacystatic const struct pmc_masks f17h_mask_FP_SCHED_EMPTY[] = {
1191339767Smmacy	__F17HMASK(FP_SCHED_EMPTY,	0x0),
1192339767Smmacy	NULLMASK
1193339767Smmacy};
1194339767Smmacystatic const struct pmc_masks f17h_mask_FP_RET_X87_FPOPS[] = {
1195339767Smmacy	__F17HMASK(FP_RET_X87_ADDSUBOPS,   0),
1196339767Smmacy	__F17HMASK(FP_RET_X87_MULOPS,      1),
1197339767Smmacy	__F17HMASK(FP_RET_X87_DIVSQRTOPS,  2),
1198339767Smmacy	NULLMASK
1199339767Smmacy};
1200339767Smmacystatic const struct pmc_masks f17h_mask_FP_RET_SSEAVX_OPS[] = {
1201339767Smmacy	__F17HMASK(FP_RET_SSEAVX_SPADDSUBOPS,	0),
1202339767Smmacy	__F17HMASK(FP_RET_SSEAVX_SPMULOPS,	1),
1203339767Smmacy	__F17HMASK(FP_RET_SSEAVX_SPDIVOPS,	2),
1204339767Smmacy	__F17HMASK(FP_RET_SSEAVX_SPMULADDOPS,	3),
1205339767Smmacy	__F17HMASK(FP_RET_SSEAVX_DPADDSUBOPS,	4),
1206339767Smmacy	__F17HMASK(FP_RET_SSEAVX_DPMULOPS,	5),
1207339767Smmacy	__F17HMASK(FP_RET_SSEAVX_DPDIVOPS,	6),
1208339767Smmacy	__F17HMASK(FP_RET_SSEAVX_DPMULADDOPS,	7),
1209339767Smmacy	NULLMASK
1210339767Smmacy};
1211339767Smmacystatic const struct pmc_masks f17h_mask_FP_NUM_MOVELIM_SCAL_OPT[] = {
1212339767Smmacy	__F17HMASK(FP_NUM_SSEMOV_OPS,	0),
1213339767Smmacy	__F17HMASK(FP_NUM_SSEMOV_ELIM,	1),
1214339767Smmacy	__F17HMASK(FP_NUM_OPS_OPTPOT,	2),
1215339767Smmacy	__F17HMASK(FP_NUM_OPS_OPT,	3),
1216339767Smmacy	NULLMASK
1217339767Smmacy};
1218339767Smmacystatic const struct pmc_masks f17h_mask_FP_RET_SEROPS[] = {
1219339767Smmacy	__F17HMASK(FP_RET_SSE_BOTEXEC,	0),
1220339767Smmacy	__F17HMASK(FP_RET_SSE_CTRL,	1),
1221339767Smmacy	__F17HMASK(FP_RET_BOTEXEC,	2),
1222339767Smmacy	__F17HMASK(FP_RET_X87_CTRL,	3),
1223339767Smmacy	NULLMASK
1224339767Smmacy};
1225339767Smmacystatic const struct pmc_masks f17h_mask_LS_BAD_STATUS2[] = {
1226339767Smmacy	__F17HMASK(LS_BAD_STATUS2_STLI_NOSTATE,	0),
1227339767Smmacy	__F17HMASK(LS_BAD_STATUS2_STLI_OTHER,	1),
1228339767Smmacy	__F17HMASK(LS_BAD_STATUS2_STLF_NODATA,	2),
1229339767Smmacy	NULLMASK
1230339767Smmacy};
1231339767Smmacystatic const struct pmc_masks f17h_mask_LS_LOCKS[] = {
1232339767Smmacy	__F17HMASK(LS_LOCKS_BUSLOCKS,	         0),
1233339767Smmacy	__F17HMASK(LS_LOCKS_NONSPECLOCK,	 1),
1234339767Smmacy	__F17HMASK(LS_SPECLOCK,			 2),
1235339767Smmacy	__F17HMASK(LS_SPECLCOK_MAPCOMMIT,	 3),
1236339767Smmacy	NULLMASK
1237339767Smmacy};
1238339767Smmacystatic const struct pmc_masks f17h_mask_LS_RET_CLFLUSH_INST[] = {
1239339767Smmacy	__F17HMASK(LS_RET_CLFLUSH_INST,	0x0),
1240339767Smmacy	NULLMASK
1241339767Smmacy};
1242339767Smmacystatic const struct pmc_masks f17h_mask_LS_RET_CPUID_INST[] = {
1243339767Smmacy	__F17HMASK(LS_RET_CPUID_INST,	0x0),
1244339767Smmacy	NULLMASK
1245339767Smmacy};
1246339767Smmacystatic const struct pmc_masks f17h_mask_LS_DISPATCH[] = {
1247339767Smmacy	__F17HMASK(LS_DISPATCH_LD,	0),
1248339767Smmacy	__F17HMASK(LS_DISPATCH_STR,	1),
1249339767Smmacy	__F17HMASK(LS_DISPATCH_LDSTR,	2),
1250339767Smmacy	NULLMASK
1251339767Smmacy};
1252339767Smmacystatic const struct pmc_masks f17h_mask_LS_SMI_RX[] = {
1253339767Smmacy	__F17HMASK(LS_SMI_RX,	0x0),
1254339767Smmacy	NULLMASK
1255339767Smmacy};
1256339767Smmacystatic const struct pmc_masks f17h_mask_LS_STLF[] = {
1257339767Smmacy	__F17HMASK(LS_STLF,	0x0),
1258339767Smmacy	NULLMASK
1259339767Smmacy};
1260339767Smmacystatic const struct pmc_masks f17h_mask_LS_STLF_COMMITCANCEL[] = {
1261339767Smmacy	__F17HMASK(LS_STLF_COMMITCANCEL,	0x0),
1262339767Smmacy	NULLMASK
1263339767Smmacy};
1264339767Smmacystatic const struct pmc_masks f17h_mask_LS_DC_ACCESS[] = {
1265339767Smmacy	__F17HMASK(LS_DC_ACCESS,	0x0),
1266339767Smmacy	NULLMASK
1267339767Smmacy};
1268339767Smmacystatic const struct pmc_masks f17h_mask_LS_MAB_ALLOCPIPE[] = {
1269339767Smmacy	__F17HMASK(LS_MAB_ALLOCPIPE_DATAPIPE,	  0),
1270339767Smmacy	__F17HMASK(LS_MAB_ALLOCPIPE_STPIPE,	  1),
1271339767Smmacy	__F17HMASK(LS_MAB_ALLOCPIPE_TLBPIPELATE,  2),
1272339767Smmacy	__F17HMASK(LS_MAB_ALLOCPIPE_HWPF,	  3),
1273339767Smmacy	__F17HMASK(LS_MAB_ALLOCPIPE_TLPPIPEEARLY, 4),
1274339767Smmacy	NULLMASK
1275339767Smmacy};
1276339767Smmacystatic const struct pmc_masks f17h_mask_LS_REFFILS_FROM_SYS[] = {
1277339767Smmacy	__F17HMASK(LS_MABRESP_LCL_L2,	     0),
1278339767Smmacy	__F17HMASK(LS_MABRESP_LCL_CACHE,     1),
1279339767Smmacy	__F17HMASK(LS_MABRESP_LCL_DRAM,	     3),
1280339767Smmacy	__F17HMASK(LS_MABRESP_LCL_RMT_CACHE, 4),
1281339767Smmacy	__F17HMASK(LS_MABRESP_LCL_RMT_DRAM,  6),
1282339767Smmacy	NULLMASK
1283339767Smmacy};
1284339767Smmacystatic const struct pmc_masks f17h_mask_LS_L1_DTLBMISS[] = {
1285339767Smmacy	__F17HMASK(LS_TLBRELOAD_4KL2HIT,	 0),
1286339767Smmacy	__F17HMASK(LS_TLBRELOAD_32KL2HIT,	 1),
1287339767Smmacy	__F17HMASK(LS_TLBRELOAD_2ML2HIT,	 2),
1288339767Smmacy	__F17HMASK(LS_TLBRELOAD_1GL2HIT,	 3),
1289339767Smmacy	__F17HMASK(LS_TLBRELOAD_4KL2MISS,	 4),
1290339767Smmacy	__F17HMASK(LS_TLBRELOAD_32KML2MISS,	 5),
1291339767Smmacy	__F17HMASK(LS_TLBRELOAD_2ML2MISS,	 6),
1292339767Smmacy	__F17HMASK(LS_TLBRELOAD_1GL2MISS,	 7),
1293339767Smmacy	NULLMASK
1294339767Smmacy};
1295339767Smmacystatic const struct pmc_masks f17h_mask_LS_TABLEWALKER[] = {
1296339767Smmacy	__F17HMASK(LS_PERFMON_TW_ALLOCDSIDE0,	0),
1297339767Smmacy	__F17HMASK(LS_PERFMON_TW_ALLOCDSIDE1,	1),
1298339767Smmacy	__F17HMASK(LS_PERFMON_TW_ALLOCISIDE0,	2),
1299339767Smmacy	__F17HMASK(LS_PERFMON_TW_ALLOCISIDE1,	3),
1300339767Smmacy	NULLMASK
1301339767Smmacy};
1302339767Smmacystatic const struct pmc_masks f17h_mask_LS_MISAL_ACCESS[] = {
1303339767Smmacy	__F17HMASK(LS_MISAL_ACCESS,	0x0),
1304339767Smmacy	NULLMASK
1305339767Smmacy};
1306339767Smmacystatic const struct pmc_masks f17h_mask_LS_PREF_INST_DISPATCH[] = {
1307339767Smmacy	__F17HMASK(LS_LOAD_PREF_W,	 0),
1308339767Smmacy	__F17HMASK(LS_STORE_PREF_W,	 1),
1309339767Smmacy	__F17HMASK(LS_PREF_PREFETCH_NTA, 2),
1310339767Smmacy	NULLMASK
1311339767Smmacy};
1312339767Smmacystatic const struct pmc_masks f17h_mask_LS_HWPF_ALLOCATED[] = {
1313339767Smmacy	__F17HMASK(LS_ALLOC_STREAM_PF,	0),
1314339767Smmacy	__F17HMASK(LS_ALLOC_STRIDE_PF,	1),
1315339767Smmacy	NULLMASK
1316339767Smmacy};
1317339767Smmacystatic const struct pmc_masks f17h_mask_LS_HWPF_HIT[] = {
1318339767Smmacy	__F17HMASK(LS_HIT_STREAM_PF,	0),
1319339767Smmacy	__F17HMASK(LS_HIT_STRIDE_PF,	1),
1320339767Smmacy	NULLMASK
1321339767Smmacy};
1322339767Smmacystatic const struct pmc_masks f17h_mask_LS_TW_INPROG_DSIDE[] = {
1323339767Smmacy	__F17HMASK(LS_TW_INPROG_DSIDE0,	0),
1324339767Smmacy	__F17HMASK(LS_TW_INPROG_ISIDE0,	1),
1325339767Smmacy	__F17HMASK(LS_TW_INPROG_DSIDE1,	2),
1326339767Smmacy	__F17HMASK(LS_TW_INPROG_ISIDE1,	3),
1327339767Smmacy	NULLMASK
1328339767Smmacy};
1329339767Smmacystatic const struct pmc_masks f17h_mask_LS_INEF_SW_PREF[] = {
1330339767Smmacy	__F17HMASK(LS_INEF_SW_PREF_DATAPIPE_SW_PF_DCHIT,	0),
1331339767Smmacy	__F17HMASK(LS_INEF_SW_PREF_MAB_MCH_CNT,	                1),
1332339767Smmacy	NULLMASK
1333339767Smmacy};
1334339767Smmacystatic const struct pmc_masks f17h_mask_LS_MAB_MCH_CNT[] = {
1335339767Smmacy	__F17HMASK(LS_MAB_MCH_CNT,	0x0),
1336339767Smmacy	NULLMASK
1337339767Smmacy};
1338339767Smmacystatic const struct pmc_masks f17h_mask_LS_HW_PF_MABALLOC[] = {
1339339767Smmacy	__F17HMASK(LS_MABALLOC_HW_PFSTREAM,	0),
1340339767Smmacy	__F17HMASK(LS_MABALLOC_HW_PFSTRIDE,	1),
1341339767Smmacy	__F17HMASK(LS_MABALLOC_PFREGION,	2),
1342339767Smmacy	NULLMASK
1343339767Smmacy};
1344339767Smmacystatic const struct pmc_masks f17h_mask_LS_HW_PF_MATCH[] = {
1345339767Smmacy	__F17HMASK(LS_MATCH_HW_PFSTREAM,	0),
1346339767Smmacy	__F17HMASK(LS_MATCH_HW_PFSTRIDE,	1),
1347339767Smmacy	__F17HMASK(LS_MATCH_HW_PFREGION,	2),
1348339767Smmacy	NULLMASK
1349339767Smmacy};
1350339767Smmacystatic const struct pmc_masks f17h_mask_LS_SW_PF_DCFILLS[] = {
1351339767Smmacy	__F17HMASK(LS_SW_PF_MABRESP_LCL_L2,	  0),
1352339767Smmacy	__F17HMASK(LS_SW_PF_MABRESP_LCL_L2_CACHE, 1),
1353339767Smmacy	__F17HMASK(LS_SW_PF_MABRESP_LCL_DRM,	  3),
1354339767Smmacy	__F17HMASK(LS_SW_PF_MABRESP_RMT_CACHE,	  4),
1355339767Smmacy	__F17HMASK(LS_SW_PF_MABRESP_RMT_DRAM,	  6),
1356339767Smmacy	NULLMASK
1357339767Smmacy};
1358339767Smmacystatic const struct pmc_masks f17h_mask_LS_HW_PF_DCFILLS[] = {
1359339767Smmacy	__F17HMASK(LS_HW_PF_MABRESP_LCL_L2,	  0),
1360339767Smmacy	__F17HMASK(LS_HW_PF_MABRESP_LCL_CACHE,    1),
1361339767Smmacy	__F17HMASK(LS_HW_PF_MABRESP_LCL_DRAM,	  3),
1362339767Smmacy	__F17HMASK(LS_HW_PF_MABRESP_RMT_CACHE,	  4),
1363339767Smmacy	__F17HMASK(LS_HW_PF_MABRESP_RMT_DRAM,	  6),
1364339767Smmacy	NULLMASK
1365339767Smmacy};
1366339767Smmacystatic const struct pmc_masks f17h_mask_LS_TW_DCFILLS[] = {
1367339767Smmacy	__F17HMASK(LS_TW_MABRESP_LCL_L2,	0),
1368339767Smmacy	__F17HMASK(LS_TW_MABRESP_LCL_CACHE,	1),
1369339767Smmacy	__F17HMASK(LS_TW_MABRESP_LCL_DRAM,	3),
1370339767Smmacy	__F17HMASK(LS_TW_MABRESP_RMT_CACHE,	4),
1371339767Smmacy	__F17HMASK(LS_TW_MABRESP_RMT_DRAM,	6),
1372339767Smmacy	NULLMASK
1373339767Smmacy};
1374206089Sfabient
1375339767Smmacystatic const struct pmc_masks f17h_mask_LS_ALLOC_MAB_COUNT[] = {
1376339767Smmacy	__F17HMASK(LS_ALLOC_MAB_COUNT,	0x0),
1377339767Smmacy	NULLMASK
1378339767Smmacy};
1379339767Smmacystatic const struct pmc_masks f17h_mask_LS_TW_INITLEVEL[] = {
1380339767Smmacy	__F17HMASK(LS_TW_INITLGH_NATIVE_PDPT,	0),
1381339767Smmacy	__F17HMASK(LS_TW_INITLGH_NATIVE_PDT,	1),
1382339767Smmacy	__F17HMASK(LS_TW_INITLGH_NATIVE_PFT,	2),
1383339767Smmacy	__F17HMASK(LS_TW_INITLGH_NATIVE_PG,	3),
1384339767Smmacy	__F17HMASK(LS_TW_INITL_NESTED_PDPT,	4),
1385339767Smmacy	__F17HMASK(LS_TW_INITL_NESTED_PDT,	5),
1386339767Smmacy	__F17HMASK(LS_TW_INITL_NESTED_PFT,	6),
1387339767Smmacy	__F17HMASK(LS_TW_INITL_NESTED_PG,	7),
1388339767Smmacy	NULLMASK
1389339767Smmacy};
1390339767Smmacystatic const struct pmc_masks f17h_mask_LS_NOT_HALTED_CYCLE[] = {
1391339767Smmacy	__F17HMASK(LS_NOT_HALTED_CYCLE,	0x00),
1392339767Smmacy	NULLMASK
1393339767Smmacy};
1394339767Smmacystatic const struct pmc_masks f17h_mask_LS_TW_RETURN_TYPES[] = {
1395339767Smmacy	__F17HMASK(LS_TWC_RET_TYPE_SPEC_VALID,		0),
1396339767Smmacy	__F17HMASK(LS_TWC_RET_TYPE_SPEC_FAULT_NAB,	2),
1397339767Smmacy	__F17HMASK(LS_TWC_RET_TYPE_SPEC_FAULT_AB,	3),
1398339767Smmacy	__F17HMASK(LS_TWC_RET_TYPE_NONSPEC_VALID,	6),
1399339767Smmacy	__F17HMASK(LS_TWC_RET_TYPE_NONSPEC_FAULT,	7),
1400339767Smmacy	NULLMASK
1401339767Smmacy};
1402339767Smmacystatic const struct pmc_masks f17h_mask_IC_FW32[] = {
1403339767Smmacy	__F17HMASK(IC_FW32,	0x0),
1404339767Smmacy	NULLMASK
1405339767Smmacy};
1406339767Smmacystatic const struct pmc_masks f17h_mask_IC_FW32_MISS[] = {
1407339767Smmacy	__F17HMASK(IC_FW32_MISS,	0x0),
1408339767Smmacy	NULLMASK
1409339767Smmacy};
1410339767Smmacystatic const struct pmc_masks f17h_mask_IC_CACHEFILL_L2[] = {
1411339767Smmacy	__F17HMASK(IC_CACHEFILL_L2,	0x0),
1412339767Smmacy	NULLMASK
1413339767Smmacy};
1414339767Smmacystatic const struct pmc_masks f17h_mask_IC_CACHEFILL_SYS[] = {
1415339767Smmacy	__F17HMASK(IC_CACHEFILL_SYS,	0x0),
1416339767Smmacy	NULLMASK
1417339767Smmacy};
1418339767Smmacystatic const struct pmc_masks f17h_mask_BP_L1TLBMISS_L2HIT[] = {
1419339767Smmacy	__F17HMASK(BP_L1TLBMISS_L2HIT,	0x0),
1420339767Smmacy	NULLMASK
1421339767Smmacy};
1422339767Smmacystatic const struct pmc_masks f17h_mask_BP_L1TLBMISS_L2MISS[] = {
1423339767Smmacy	__F17HMASK(BP_L1TLBMISS_L2MISS,	0x0),
1424339767Smmacy	NULLMASK
1425339767Smmacy};
1426339767Smmacystatic const struct pmc_masks f17h_mask_IC_FETCHSTALL[] = {
1427339767Smmacy	__F17HMASK(IC_FETCHSTALL_BACKPRESSURE,	0),
1428339767Smmacy	__F17HMASK(IC_FETCHSTALL_DQEMPTY,	1),
1429339767Smmacy	__F17HMASK(IC_FETCHSTALL_ANY,	        2),
1430339767Smmacy	NULLMASK
1431339767Smmacy};
1432339767Smmacystatic const struct pmc_masks f17h_mask_BP_L1_BTBCORRECT[] = {
1433339767Smmacy	__F17HMASK(BP_L1_BTBCORRECT,	0x0),
1434339767Smmacy	NULLMASK
1435339767Smmacy};
1436339767Smmacystatic const struct pmc_masks f17h_mask_BP_L2_BTBCORRECT[] = {
1437339767Smmacy	__F17HMASK(BP_L2_BTBCORRECT,	0x0),
1438339767Smmacy	NULLMASK
1439339767Smmacy};
1440339767Smmacystatic const struct pmc_masks f17h_mask_IC_CACHEINVAL[] = {
1441339767Smmacy	__F17HMASK(IC_CACHEINVAL_FILLINV,	0),
1442339767Smmacy	__F17HMASK(IC_CACHEINVAL_L2_INV_PROVBE,	1),
1443339767Smmacy	NULLMASK
1444339767Smmacy};
1445339767Smmacystatic const struct pmc_masks f17h_mask_BP_TLB_REL[] = {
1446339767Smmacy	__F17HMASK(BP_TLB_REL,	0x0),
1447339767Smmacy	NULLMASK
1448339767Smmacy};
1449339767Smmacystatic const struct pmc_masks f17h_mask_ICOC_MODE_SWITCH[] = {
1450339767Smmacy	__F17HMASK(IC2OC_MODE_SWITCH,	0),
1451339767Smmacy	__F17HMASK(OC2IC_MODE_SWITCH,	1),
1452339767Smmacy	NULLMASK
1453339767Smmacy};
1454339767Smmacystatic const struct pmc_masks f17h_mask_DE_DISPATCH_TOKEN_STALLS[] = {
1455339767Smmacy	__F17HMASK(DE_ALSQ1_TOKEN_STALL,	0),
1456339767Smmacy	__F17HMASK(DE_ALSQ2_TOKEN_STALL,	1),
1457339767Smmacy	__F17HMASK(DE_ALSQ3_TOKEN_STALL,	2),
1458339767Smmacy	__F17HMASK(DE_ALSQ3_0_TOKEN_STALL,	3),
1459339767Smmacy	__F17HMASK(DE_ALU_TOKEN_STALL,		4),
1460339767Smmacy	__F17HMASK(DE_AGSQ_TOKEN_STALL,		5),
1461339767Smmacy	__F17HMASK(DE_RETIRE_TOKEN_STALLS,	6),
1462339767Smmacy	NULLMASK
1463339767Smmacy};
1464339767Smmacystatic const struct pmc_masks f17h_mask_EX_RET_INST[] = {
1465339767Smmacy	__F17HMASK(EX_RET_INST,	0x0),
1466339767Smmacy	NULLMASK
1467339767Smmacy};
1468339767Smmacystatic const struct pmc_masks f17h_mask_EX_RET_COPS[] = {
1469339767Smmacy	__F17HMASK(EX_RET_COPS,	0x0),
1470339767Smmacy	NULLMASK
1471339767Smmacy};
1472339767Smmacystatic const struct pmc_masks f17h_mask_EX_RET_BRN[] = {
1473339767Smmacy	__F17HMASK(EX_RET_BRN,	0x0),
1474339767Smmacy	NULLMASK
1475339767Smmacy};
1476339767Smmacystatic const struct pmc_masks f17h_mask_EX_RET_BRN_MISP[] = {
1477339767Smmacy	__F17HMASK(EX_RET_BRN_MISP,	0x0),
1478339767Smmacy	NULLMASK
1479339767Smmacy};
1480339767Smmacystatic const struct pmc_masks f17h_mask_EX_RET_BRN_TKN[] = {
1481339767Smmacy	__F17HMASK(EX_RET_BRN_TKN,	0x0),
1482339767Smmacy	NULLMASK
1483339767Smmacy};
1484339767Smmacystatic const struct pmc_masks f17h_mask_EX_RET_BRN_TKN_MISP[] = {
1485339767Smmacy	__F17HMASK(EX_RET_BRN_TKN_MISP,	0x0),
1486339767Smmacy	NULLMASK
1487339767Smmacy};
1488339767Smmacystatic const struct pmc_masks f17h_mask_EX_RET_BRN_FAR[] = {
1489339767Smmacy	__F17HMASK(EX_RET_BRN_FAR,	0x0),
1490339767Smmacy	NULLMASK
1491339767Smmacy};
1492339767Smmacystatic const struct pmc_masks f17h_mask_EX_RET_BRN_RESYNC[] = {
1493339767Smmacy	__F17HMASK(EX_RET_BRN_RESYNC,	0x0),
1494339767Smmacy	NULLMASK
1495339767Smmacy};
1496339767Smmacystatic const struct pmc_masks f17h_mask_EX_RET_BRN_NEAR_RET[] = {
1497339767Smmacy	__F17HMASK(EX_RET_BRN_NEAR_RET,	0x0),
1498339767Smmacy	NULLMASK
1499339767Smmacy};
1500339767Smmacystatic const struct pmc_masks f17h_mask_EX_RET_BRN_NEAR_RET_MISPRED[] = {
1501339767Smmacy	__F17HMASK(EX_RET_BRN_NEAR_RET_MISPRED,	0x0),
1502339767Smmacy	NULLMASK
1503339767Smmacy};
1504339767Smmacystatic const struct pmc_masks f17h_mask_EX_RET_BRN_IND_MISP[] = {
1505339767Smmacy	__F17HMASK(EX_RET_BRN_IND_MISP,	0x0),
1506339767Smmacy	NULLMASK
1507339767Smmacy};
1508339767Smmacystatic const struct pmc_masks f17h_mask_EX_RET_MMX_FP_INSTR[] = {
1509339767Smmacy	__F17HMASK(EX_RET_MMX_X87_INST,	0),
1510339767Smmacy	__F17HMASK(EX_RET_MMX_INSTR,	1),
1511339767Smmacy	__F17HMASK(EX_RET_MMX_SSE_INSTR,	2),
1512339767Smmacy	NULLMASK
1513339767Smmacy};
1514339767Smmacystatic const struct pmc_masks f17h_mask_EX_RET_COND_BRN[] = {
1515339767Smmacy	__F17HMASK(EX_RET_COND_BRN,	0x0),
1516339767Smmacy	NULLMASK
1517339767Smmacy};
1518339767Smmacystatic const struct pmc_masks f17h_mask_EX_DIV_BUSY[] = {
1519339767Smmacy	__F17HMASK(EX_DIV_BUSY,	0x0),
1520339767Smmacy	NULLMASK
1521339767Smmacy};
1522339767Smmacystatic const struct pmc_masks f17h_mask_EX_DIV_COUNT[] = {
1523339767Smmacy	__F17HMASK(EX_DIV_COUNT,	0x0),
1524339767Smmacy	NULLMASK
1525339767Smmacy};
1526339767Smmacystatic const struct pmc_masks f17h_mask_L2_REQUEST_G1[] = {
1527339767Smmacy	__F17HMASK(L2_REQUEST_G1_OTHERREQ,	0),
1528339767Smmacy	__F17HMASK(L2_REQUEST_G1_HWPF,		1),
1529339767Smmacy	__F17HMASK(L2_REQUEST_G1_PREFETCHL2,	2),
1530339767Smmacy	__F17HMASK(L2_REQUEST_G1_CHANGETOX,	3),
1531339767Smmacy	__F17HMASK(L2_REQUEST_G1_CACHEABLEICRD,	4),
1532339767Smmacy	__F17HMASK(L2_REQUEST_G1_LSRDBLKC,	5),
1533339767Smmacy	__F17HMASK(L2_REQUEST_G1_RDBLKX,	6),
1534339767Smmacy	__F17HMASK(L2_REQUEST_G1_RDBLKL,	7),
1535339767Smmacy	NULLMASK
1536339767Smmacy};
1537339767Smmacystatic const struct pmc_masks f17h_mask_L2_REQUEST_G2[] = {
1538339767Smmacy	__F17HMASK(L2_REQUEST_G2_BUSLOCKRESP,	0),
1539339767Smmacy	__F17HMASK(L2_REQUEST_G2_BUSLOCKORIG,	1),
1540339767Smmacy	__F17HMASK(L2_REQUEST_G2_SMCINV,	2),
1541339767Smmacy	__F17HMASK(L2_REQUEST_G2_ICRDSIZENC,	3),
1542339767Smmacy	__F17HMASK(L2_REQUEST_G2_ICRDSIZE,	4),
1543339767Smmacy	__F17HMASK(L2_REQUEST_G2_LSRDSIZENC,	5),
1544339767Smmacy	__F17HMASK(L2_REQUEST_G2_LSRDSIZE,	6),
1545339767Smmacy	__F17HMASK(L2_REQUEST_G2_GROUP1,	7),
1546339767Smmacy	NULLMASK
1547339767Smmacy};
1548339767Smmacystatic const struct pmc_masks f17h_mask_L2_LATENCY[] = {
1549339767Smmacy	__F17HMASK(L2_LATENCY_CYC_WAITINGONFILLS,	0x0),
1550339767Smmacy	NULLMASK
1551339767Smmacy};
1552339767Smmacystatic const struct pmc_masks f17h_mask_L2_WBCREQ[] = {
1553339767Smmacy	__F17HMASK(L2_WBCREQ_CLZERO,		0),
1554339767Smmacy	__F17HMASK(L2_WBCREQ_LOCALICCLR,	1),
1555339767Smmacy	__F17HMASK(L2_WBCREQ_ZEROBYTESTORE,	2),
1556339767Smmacy	__F17HMASK(L2_WBCREQ_ILINEFLUSH,	3),
1557339767Smmacy	__F17HMASK(L2_WBCREQ_CACHELINEFLUSH,	4),
1558339767Smmacy	__F17HMASK(L2_WBCREQ_WBCCLOSE,		5),
1559339767Smmacy	__F17HMASK(L2_WBCREQ_WCBWRITE,		6),
1560339767Smmacy	NULLMASK
1561339767Smmacy};
1562339767Smmacystatic const struct pmc_masks f17h_mask_L2_CACHEREQSTAT[] = {
1563339767Smmacy	__F17HMASK(L2_CACHEREQSTAT_ICFILLMISS,	0),
1564339767Smmacy	__F17HMASK(L2_CACHEREQSTAT_ICFILLHITS,	1),
1565339767Smmacy	__F17HMASK(L2_CACHEREQSTAT_ICFILLHITX,	2),
1566339767Smmacy	__F17HMASK(L2_CACHEREQSTAT_LSRDBLKC,	3),
1567339767Smmacy	__F17HMASK(L2_CACHEREQSTAT_LSRDBLKX,	4),
1568339767Smmacy	__F17HMASK(L2_CACHEREQSTAT_LSRDBLKLHITS, 5),
1569339767Smmacy	__F17HMASK(L2_CACHEREQSTAT_LSRDBLKLHITX, 6),
1570339767Smmacy	__F17HMASK(L2_CACHEREQSTAT_LSRDBLKCS,	 7),
1571339767Smmacy	NULLMASK
1572339767Smmacy};
1573339767Smmacystatic const struct pmc_masks f17h_mask_L2_SMCEVENTS[] = {
1574339767Smmacy	__F17HMASK(L2_SMCEVENTS_ICFILLSTQCAMMATOT,      0),
1575339767Smmacy	__F17HMASK(L2_SMCEVENTS_ICFILLSTQCAMMATTT,	1),
1576339767Smmacy	__F17HMASK(L2_SMCEVENTS_LSRDBLKLSXCHGTOX,	2),
1577339767Smmacy	__F17HMASK(L2_SMCEVENTS_RDBLKXCHGTOX,	        3),
1578339767Smmacy	__F17HMASK(L2_SMCEVENTS_LSRDBLKLSCHITL2ICVAL,	4),
1579339767Smmacy	__F17HMASK(L2_SMCEVENTS_ICFETCHHITL2,           5),
1580339767Smmacy	__F17HMASK(L2_SMCEVENTS_ICFETCHHITL2DCVAL,      6),
1581339767Smmacy	NULLMASK
1582339767Smmacy};
1583339767Smmacystatic const struct pmc_masks f17h_mask_L2_FILLPENDING[] = {
1584339767Smmacy	__F17HMASK(L2_FILLPENDING_L2FILLBUSY,	0),
1585339767Smmacy	NULLMASK
1586339767Smmacy};
1587339767Smmacystatic const struct pmc_masks f17h_mask_EX_TAGGED_IBSOPS[] = {
1588339767Smmacy	__F17HMASK(EX_TAGGED_IBSOPS,		0x0),
1589339767Smmacy	__F17HMASK(EX_TAGGED_IBSOPS_RET,	0x1),
1590339767Smmacy	__F17HMASK(EX_TAGGED_IBSOPS_CNT_RLOVER,	0x2),
1591339767Smmacy	NULLMASK
1592339767Smmacy};
1593339767Smmacystatic const struct pmc_masks f17h_mask_EX_RET_FUSED_BRNCH_INST[] = {
1594339767Smmacy	__F17HMASK(EX_RET_FUSED_BRNCH_INST,	0x0),
1595339767Smmacy	NULLMASK
1596339767Smmacy};
1597339767Smmacy
1598339767Smmacy#define	F17H_KW_COUNT	"count"
1599339767Smmacy#define	F17H_KW_EDGE	"edge"
1600339767Smmacy#define	F17H_KW_INV	"inv"
1601339767Smmacy#define	F17H_KW_MASK	"mask"
1602339767Smmacy#define	F17H_KW_OS	"os"
1603339767Smmacy#define	F17H_KW_USR	"usr"
1604339767Smmacy
1605339767Smmacystatic int
1606339767Smmacyf17h_allocate_pmc(enum pmc_event pe, char *ctrspec,
1607339767Smmacy		struct pmc_op_pmcallocate *pmc_config)
1608339767Smmacy{
1609339767Smmacy	char		*e, *p, *q;
1610339767Smmacy	int		n;
1611339767Smmacy	uint32_t	count;
1612339767Smmacy	const struct pmc_masks	 *pmask;
1613339767Smmacy	uint64_t	evmask = 0;
1614339767Smmacy	(void)ctrspec;
1615339767Smmacy
1616339767Smmacy	pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE);
1617339767Smmacy	pmc_config->pm_md.pm_amd.pm_amd_config = 0;
1618339767Smmacy
1619339767Smmacy
1620339767Smmacy#define	__F17HSETMASK(M) pmask = f17h_mask_##M
1621339767Smmacy	switch (pe) {
1622339767Smmacy	case PMC_EV_F17H_FPU_PIPEASSIGMENT:
1623339767Smmacy		__F17HSETMASK(FPU_PIPEASSIGMENT);
1624339767Smmacy		break;
1625339767Smmacy	case PMC_EV_F17H_FP_SCHED_EMPTY:
1626339767Smmacy		__F17HSETMASK(FP_SCHED_EMPTY);
1627339767Smmacy		break;
1628339767Smmacy	case PMC_EV_F17H_FP_RET_X87_FPOPS:
1629339767Smmacy		__F17HSETMASK(FP_RET_X87_FPOPS);
1630339767Smmacy		break;
1631339767Smmacy	case PMC_EV_F17H_FP_RET_SSEAVX_OPS:
1632339767Smmacy		__F17HSETMASK(FP_RET_SSEAVX_OPS);
1633339767Smmacy		break;
1634339767Smmacy	case PMC_EV_F17H_FP_NUM_MOVELIM_SCAL_OPT:
1635339767Smmacy		__F17HSETMASK(FP_NUM_MOVELIM_SCAL_OPT);
1636339767Smmacy		break;
1637339767Smmacy	case PMC_EV_F17H_FP_RET_SEROPS:
1638339767Smmacy		__F17HSETMASK(FP_RET_SEROPS);
1639339767Smmacy		break;
1640339767Smmacy	case PMC_EV_F17H_LS_BAD_STATUS2:
1641339767Smmacy		__F17HSETMASK(LS_BAD_STATUS2);
1642339767Smmacy		break;
1643339767Smmacy	case PMC_EV_F17H_LS_LOCKS:
1644339767Smmacy		__F17HSETMASK(LS_LOCKS);
1645339767Smmacy		break;
1646339767Smmacy	case PMC_EV_F17H_LS_RET_CLFLUSH_INST:
1647339767Smmacy		__F17HSETMASK(LS_RET_CLFLUSH_INST);
1648339767Smmacy		break;
1649339767Smmacy	case PMC_EV_F17H_LS_RET_CPUID_INST:
1650339767Smmacy		__F17HSETMASK(LS_RET_CPUID_INST);
1651339767Smmacy		break;
1652339767Smmacy	case PMC_EV_F17H_LS_DISPATCH:
1653339767Smmacy		__F17HSETMASK(LS_DISPATCH);
1654339767Smmacy		break;
1655339767Smmacy	case PMC_EV_F17H_LS_SMI_RX:
1656339767Smmacy		__F17HSETMASK(LS_SMI_RX);
1657339767Smmacy		break;
1658339767Smmacy	case PMC_EV_F17H_LS_STLF:
1659339767Smmacy		__F17HSETMASK(LS_STLF);
1660339767Smmacy		break;
1661339767Smmacy	case PMC_EV_F17H_LS_STLF_COMMITCANCEL:
1662339767Smmacy		__F17HSETMASK(LS_STLF_COMMITCANCEL);
1663339767Smmacy		break;
1664339767Smmacy	case PMC_EV_F17H_LS_DC_ACCESS:
1665339767Smmacy		__F17HSETMASK(LS_DC_ACCESS);
1666339767Smmacy		break;
1667339767Smmacy	case PMC_EV_F17H_LS_MAB_ALLOCPIPE:
1668339767Smmacy		__F17HSETMASK(LS_MAB_ALLOCPIPE);
1669339767Smmacy		break;
1670339767Smmacy	case PMC_EV_F17H_LS_REFFILS_FROM_SYS:
1671339767Smmacy		__F17HSETMASK(LS_REFFILS_FROM_SYS);
1672339767Smmacy		break;
1673339767Smmacy	case PMC_EV_F17H_LS_L1_DTLBMISS:
1674339767Smmacy		__F17HSETMASK(LS_L1_DTLBMISS);
1675339767Smmacy		break;
1676339767Smmacy	case PMC_EV_F17H_LS_TABLEWALKER:
1677339767Smmacy		__F17HSETMASK(LS_TABLEWALKER);
1678339767Smmacy		break;
1679339767Smmacy	case PMC_EV_F17H_LS_MISAL_ACCESS:
1680339767Smmacy		__F17HSETMASK(LS_MISAL_ACCESS);
1681339767Smmacy		break;
1682339767Smmacy	case PMC_EV_F17H_LS_PREF_INST_DISPATCH:
1683339767Smmacy		__F17HSETMASK(LS_PREF_INST_DISPATCH);
1684339767Smmacy		break;
1685339767Smmacy	case PMC_EV_F17H_LS_HWPF_ALLOCATED:
1686339767Smmacy		__F17HSETMASK(LS_HWPF_ALLOCATED);
1687339767Smmacy		break;
1688339767Smmacy	case PMC_EV_F17H_LS_HWPF_HIT:
1689339767Smmacy		__F17HSETMASK(LS_HWPF_HIT);
1690339767Smmacy		break;
1691339767Smmacy	case PMC_EV_F17H_LS_TW_INPROG_DSIDE:
1692339767Smmacy		__F17HSETMASK(LS_TW_INPROG_DSIDE);
1693339767Smmacy		break;
1694339767Smmacy	case PMC_EV_F17H_LS_INEF_SW_PREF:
1695339767Smmacy		__F17HSETMASK(LS_INEF_SW_PREF);
1696339767Smmacy		break;
1697339767Smmacy	case PMC_EV_F17H_LS_MAB_MCH_CNT:
1698339767Smmacy		__F17HSETMASK(LS_MAB_MCH_CNT);
1699339767Smmacy		break;
1700339767Smmacy	case PMC_EV_F17H_LS_HW_PF_MABALLOC:
1701339767Smmacy		__F17HSETMASK(LS_HW_PF_MABALLOC);
1702339767Smmacy		break;
1703339767Smmacy	case PMC_EV_F17H_LS_HW_PF_MATCH:
1704339767Smmacy		__F17HSETMASK(LS_HW_PF_MATCH);
1705339767Smmacy		break;
1706339767Smmacy	case PMC_EV_F17H_LS_SW_PF_DCFILLS:
1707339767Smmacy		__F17HSETMASK(LS_SW_PF_DCFILLS);
1708339767Smmacy		break;
1709339767Smmacy	case PMC_EV_F17H_LS_HW_PF_DCFILLS:
1710339767Smmacy		__F17HSETMASK(LS_HW_PF_DCFILLS);
1711339767Smmacy		break;
1712339767Smmacy	case PMC_EV_F17H_LS_TW_DCFILLS:
1713339767Smmacy	__F17HSETMASK(LS_TW_DCFILLS);
1714339767Smmacy		break;
1715339767Smmacy	case PMC_EV_F17H_LS_ALLOC_MAB_COUNT:
1716339767Smmacy		__F17HSETMASK(LS_ALLOC_MAB_COUNT);
1717339767Smmacy		break;
1718339767Smmacy	case PMC_EV_F17H_LS_TW_INITLEVEL:
1719339767Smmacy		__F17HSETMASK(LS_TW_INITLEVEL);
1720339767Smmacy		break;
1721339767Smmacy	case PMC_EV_F17H_LS_NOT_HALTED_CYCLE:
1722339767Smmacy		__F17HSETMASK(LS_NOT_HALTED_CYCLE);
1723339767Smmacy		break;
1724339767Smmacy	case PMC_EV_F17H_LS_TW_RETURN_TYPES:
1725339767Smmacy		__F17HSETMASK(LS_TW_RETURN_TYPES);
1726339767Smmacy		break;
1727339767Smmacy	case PMC_EV_F17H_IC_FW32:
1728339767Smmacy		__F17HSETMASK(IC_FW32);
1729339767Smmacy		break;
1730339767Smmacy	case PMC_EV_F17H_IC_FW32_MISS:
1731339767Smmacy		__F17HSETMASK(IC_FW32_MISS);
1732339767Smmacy		break;
1733339767Smmacy	case PMC_EV_F17H_IC_CACHEFILL_L2:
1734339767Smmacy		__F17HSETMASK(IC_CACHEFILL_L2);
1735339767Smmacy		break;
1736339767Smmacy	case PMC_EV_F17H_IC_CACHEFILL_SYS:
1737339767Smmacy		__F17HSETMASK(IC_CACHEFILL_SYS);
1738339767Smmacy		break;
1739339767Smmacy	case PMC_EV_F17H_BP_L1TLBMISS_L2HIT:
1740339767Smmacy		__F17HSETMASK(BP_L1TLBMISS_L2HIT);
1741339767Smmacy		break;
1742339767Smmacy	case PMC_EV_F17H_BP_L1TLBMISS_L2MISS:
1743339767Smmacy		__F17HSETMASK(BP_L1TLBMISS_L2MISS);
1744339767Smmacy		break;
1745339767Smmacy	case PMC_EV_F17H_IC_FETCHSTALL:
1746339767Smmacy		__F17HSETMASK(IC_FETCHSTALL);
1747339767Smmacy		break;
1748339767Smmacy	case PMC_EV_F17H_BP_L1_BTBCORRECT:
1749339767Smmacy		__F17HSETMASK(BP_L1_BTBCORRECT);
1750339767Smmacy		break;
1751339767Smmacy	case PMC_EV_F17H_BP_L2_BTBCORRECT:
1752339767Smmacy		__F17HSETMASK(BP_L2_BTBCORRECT);
1753339767Smmacy		break;
1754339767Smmacy	case PMC_EV_F17H_IC_CACHEINVAL:
1755339767Smmacy		__F17HSETMASK(IC_CACHEINVAL);
1756339767Smmacy		break;
1757339767Smmacy	case PMC_EV_F17H_BP_TLB_REL:
1758339767Smmacy		__F17HSETMASK(BP_TLB_REL);
1759339767Smmacy		break;
1760339767Smmacy	case PMC_EV_F17H_ICOC_MODE_SWITCH:
1761339767Smmacy		__F17HSETMASK(ICOC_MODE_SWITCH);
1762339767Smmacy		break;
1763339767Smmacy	case PMC_EV_F17H_DE_DISPATCH_TOKEN_STALLS:
1764339767Smmacy		__F17HSETMASK(DE_DISPATCH_TOKEN_STALLS);
1765339767Smmacy		break;
1766339767Smmacy	case PMC_EV_F17H_EX_RET_INST:
1767339767Smmacy		__F17HSETMASK(EX_RET_INST);
1768339767Smmacy		break;
1769339767Smmacy	case PMC_EV_F17H_EX_RET_COPS:
1770339767Smmacy		__F17HSETMASK(EX_RET_COPS);
1771339767Smmacy		break;
1772339767Smmacy	case PMC_EV_F17H_EX_RET_BRN:
1773339767Smmacy		__F17HSETMASK(EX_RET_BRN);
1774339767Smmacy		break;
1775339767Smmacy	case PMC_EV_F17H_EX_RET_BRN_MISP:
1776339767Smmacy		__F17HSETMASK(EX_RET_BRN_MISP);
1777339767Smmacy		break;
1778339767Smmacy	case PMC_EV_F17H_EX_RET_BRN_TKN:
1779339767Smmacy		__F17HSETMASK(EX_RET_BRN_TKN);
1780339767Smmacy		break;
1781339767Smmacy	case PMC_EV_F17H_EX_RET_BRN_TKN_MISP:
1782339767Smmacy		__F17HSETMASK(EX_RET_BRN_TKN_MISP);
1783339767Smmacy		break;
1784339767Smmacy	case PMC_EV_F17H_EX_RET_BRN_FAR:
1785339767Smmacy		__F17HSETMASK(EX_RET_BRN_FAR);
1786339767Smmacy		break;
1787339767Smmacy	case PMC_EV_F17H_EX_RET_BRN_RESYNC:
1788339767Smmacy		__F17HSETMASK(EX_RET_BRN_RESYNC);
1789339767Smmacy		break;
1790339767Smmacy	case PMC_EV_F17H_EX_RET_BRN_NEAR_RET:
1791339767Smmacy		__F17HSETMASK(EX_RET_BRN_NEAR_RET);
1792339767Smmacy		break;
1793339767Smmacy	case PMC_EV_F17H_EX_RET_BRN_NEAR_RET_MISPRED:
1794339767Smmacy		__F17HSETMASK(EX_RET_BRN_NEAR_RET_MISPRED);
1795339767Smmacy		break;
1796339767Smmacy	case PMC_EV_F17H_EX_RET_BRN_IND_MISP:
1797339767Smmacy		__F17HSETMASK(EX_RET_BRN_IND_MISP);
1798339767Smmacy		break;
1799339767Smmacy	case PMC_EV_F17H_EX_RET_MMX_FP_INSTR:
1800339767Smmacy		__F17HSETMASK(EX_RET_MMX_FP_INSTR);
1801339767Smmacy		break;
1802339767Smmacy	case PMC_EV_F17H_EX_RET_COND_BRN:
1803339767Smmacy		__F17HSETMASK(EX_RET_COND_BRN);
1804339767Smmacy		break;
1805339767Smmacy	case PMC_EV_F17H_EX_DIV_BUSY:
1806339767Smmacy		__F17HSETMASK(EX_DIV_BUSY);
1807339767Smmacy		break;
1808339767Smmacy	case PMC_EV_F17H_EX_DIV_COUNT:
1809339767Smmacy		__F17HSETMASK(EX_DIV_COUNT);
1810339767Smmacy		break;
1811339767Smmacy	case PMC_EV_F17H_L2_REQUEST_G1:
1812339767Smmacy		__F17HSETMASK(L2_REQUEST_G1);
1813339767Smmacy		break;
1814339767Smmacy	case PMC_EV_F17H_L2_REQUEST_G2:
1815339767Smmacy		__F17HSETMASK(L2_REQUEST_G2);
1816339767Smmacy		break;
1817339767Smmacy	case PMC_EV_F17H_L2_LATENCY:
1818339767Smmacy		__F17HSETMASK(L2_LATENCY);
1819339767Smmacy		break;
1820339767Smmacy	case PMC_EV_F17H_L2_WBCREQ:
1821339767Smmacy		__F17HSETMASK(L2_WBCREQ);
1822339767Smmacy		break;
1823339767Smmacy	case PMC_EV_F17H_L2_CACHEREQSTAT:
1824339767Smmacy		__F17HSETMASK(L2_CACHEREQSTAT);
1825339767Smmacy		break;
1826339767Smmacy	case PMC_EV_F17H_L2_SMCEVENTS:
1827339767Smmacy		__F17HSETMASK(L2_SMCEVENTS);
1828339767Smmacy		break;
1829339767Smmacy	case PMC_EV_F17H_L2_FILLPENDING:
1830339767Smmacy		__F17HSETMASK(L2_FILLPENDING);
1831339767Smmacy		break;
1832339767Smmacy	case PMC_EV_F17H_EX_TAGGED_IBSOPS:
1833339767Smmacy		__F17HSETMASK(EX_TAGGED_IBSOPS);
1834339767Smmacy		break;
1835339767Smmacy	case PMC_EV_F17H_EX_RET_FUSED_BRNCH_INST:
1836339767Smmacy		__F17HSETMASK(EX_RET_FUSED_BRNCH_INST);
1837339767Smmacy		break;
1838339767Smmacy	default:
1839339767Smmacy		printf(" %s failed, event not supported\n", __FUNCTION__);
1840339767Smmacy		return -1;
1841339767Smmacy	}
1842339767Smmacy	while ((p = strsep(&ctrspec, ",")) != NULL) {
1843339767Smmacy		if (KWPREFIXMATCH(p, F17H_KW_COUNT "=")) {
1844339767Smmacy			q = strchr(p, '=');
1845339767Smmacy			if (*++q == '\0') /* skip '=' */
1846339767Smmacy				return (-1);
1847339767Smmacy
1848339767Smmacy			count = strtol(q, &e, 0);
1849339767Smmacy			if (e == q || *e != '\0')
1850339767Smmacy				return (-1);
1851339767Smmacy
1852339767Smmacy			pmc_config->pm_caps |= PMC_CAP_THRESHOLD;
1853339767Smmacy			pmc_config->pm_md.pm_amd.pm_amd_config |=
1854339767Smmacy			    AMD_PMC_TO_COUNTER(count);
1855339767Smmacy
1856339767Smmacy		} else if (KWMATCH(p, F17H_KW_EDGE)) {
1857339767Smmacy			pmc_config->pm_caps |= PMC_CAP_EDGE;
1858339767Smmacy		} else if (KWMATCH(p, F17H_KW_INV)) {
1859339767Smmacy			pmc_config->pm_caps |= PMC_CAP_INVERT;
1860339767Smmacy		} else if (KWPREFIXMATCH(p, F17H_KW_MASK "=")) {
1861339767Smmacy			if ((n = pmc_parse_mask(pmask, p, &evmask)) < 0)
1862339767Smmacy				return (-1);
1863339767Smmacy			pmc_config->pm_caps |= PMC_CAP_QUALIFIER;
1864339767Smmacy		} else if (KWMATCH(p, F17H_KW_OS)) {
1865339767Smmacy			pmc_config->pm_caps |= PMC_CAP_SYSTEM;
1866339767Smmacy		} else if (KWMATCH(p, F17H_KW_USR)) {
1867339767Smmacy			pmc_config->pm_caps |= PMC_CAP_USER;
1868339767Smmacy		} else
1869339767Smmacy			return (-1);
1870339767Smmacy}
1871339767Smmacy	if (pmc_config->pm_caps & PMC_CAP_QUALIFIER) {
1872339767Smmacy		pmc_config->pm_md.pm_amd.pm_amd_config =
1873339767Smmacy		    AMD_PMC_TO_UNITMASK(evmask);
1874339767Smmacy	}
1875339767Smmacy	return 0;
1876339767Smmacy}
1877206089Sfabient/*
1878147191Sjkoshy * AMD K8 PMCs.
1879147191Sjkoshy *
1880147191Sjkoshy * These are very similar to AMD K7 PMCs, but support more kinds of
1881147191Sjkoshy * events.
1882147191Sjkoshy */
1883147191Sjkoshy
1884147191Sjkoshystatic struct pmc_event_alias k8_aliases[] = {
1885147191Sjkoshy	EV_ALIAS("branches",		"k8-fr-retired-taken-branches"),
1886147191Sjkoshy	EV_ALIAS("branch-mispredicts",
1887147191Sjkoshy	    "k8-fr-retired-taken-branches-mispredicted"),
1888147191Sjkoshy	EV_ALIAS("cycles",		"tsc"),
1889147191Sjkoshy	EV_ALIAS("dc-misses",		"k8-dc-miss"),
1890147191Sjkoshy	EV_ALIAS("ic-misses",		"k8-ic-miss"),
1891183107Sjkoshy	EV_ALIAS("instructions",	"k8-fr-retired-x86-instructions"),
1892147191Sjkoshy	EV_ALIAS("interrupts",		"k8-fr-taken-hardware-interrupts"),
1893155998Sjkoshy	EV_ALIAS("unhalted-cycles",	"k8-bu-cpu-clk-unhalted"),
1894147191Sjkoshy	EV_ALIAS(NULL, NULL)
1895147191Sjkoshy};
1896147191Sjkoshy
1897147191Sjkoshy#define	__K8MASK(N,V) PMCMASK(N,(1 << (V)))
1898147191Sjkoshy
1899147191Sjkoshy/*
1900147191Sjkoshy * Parsing tables
1901147191Sjkoshy */
1902147191Sjkoshy
1903147191Sjkoshy/* fp dispatched fpu ops */
1904147191Sjkoshystatic const struct pmc_masks k8_mask_fdfo[] = {
1905147191Sjkoshy	__K8MASK(add-pipe-excluding-junk-ops,	0),
1906147191Sjkoshy	__K8MASK(multiply-pipe-excluding-junk-ops,	1),
1907147191Sjkoshy	__K8MASK(store-pipe-excluding-junk-ops,	2),
1908147191Sjkoshy	__K8MASK(add-pipe-junk-ops,		3),
1909147191Sjkoshy	__K8MASK(multiply-pipe-junk-ops,	4),
1910147191Sjkoshy	__K8MASK(store-pipe-junk-ops,		5),
1911147191Sjkoshy	NULLMASK
1912147191Sjkoshy};
1913147191Sjkoshy
1914147191Sjkoshy/* ls segment register loads */
1915147191Sjkoshystatic const struct pmc_masks k8_mask_lsrl[] = {
1916147191Sjkoshy	__K8MASK(es,	0),
1917147191Sjkoshy	__K8MASK(cs,	1),
1918147191Sjkoshy	__K8MASK(ss,	2),
1919147191Sjkoshy	__K8MASK(ds,	3),
1920147191Sjkoshy	__K8MASK(fs,	4),
1921147191Sjkoshy	__K8MASK(gs,	5),
1922147191Sjkoshy	__K8MASK(hs,	6),
1923147191Sjkoshy	NULLMASK
1924147191Sjkoshy};
1925147191Sjkoshy
1926147191Sjkoshy/* ls locked operation */
1927147191Sjkoshystatic const struct pmc_masks k8_mask_llo[] = {
1928147191Sjkoshy	__K8MASK(locked-instructions,	0),
1929147191Sjkoshy	__K8MASK(cycles-in-request,	1),
1930147191Sjkoshy	__K8MASK(cycles-to-complete,	2),
1931147191Sjkoshy	NULLMASK
1932147191Sjkoshy};
1933147191Sjkoshy
1934147191Sjkoshy/* dc refill from {l2,system} and dc copyback */
1935147191Sjkoshystatic const struct pmc_masks k8_mask_dc[] = {
1936147191Sjkoshy	__K8MASK(invalid,	0),
1937147191Sjkoshy	__K8MASK(shared,	1),
1938147191Sjkoshy	__K8MASK(exclusive,	2),
1939147191Sjkoshy	__K8MASK(owner,		3),
1940147191Sjkoshy	__K8MASK(modified,	4),
1941147191Sjkoshy	NULLMASK
1942147191Sjkoshy};
1943147191Sjkoshy
1944147191Sjkoshy/* dc one bit ecc error */
1945147191Sjkoshystatic const struct pmc_masks k8_mask_dobee[] = {
1946147191Sjkoshy	__K8MASK(scrubber,	0),
1947147191Sjkoshy	__K8MASK(piggyback,	1),
1948147191Sjkoshy	NULLMASK
1949147191Sjkoshy};
1950147191Sjkoshy
1951147191Sjkoshy/* dc dispatched prefetch instructions */
1952147191Sjkoshystatic const struct pmc_masks k8_mask_ddpi[] = {
1953147191Sjkoshy	__K8MASK(load,	0),
1954147191Sjkoshy	__K8MASK(store,	1),
1955147191Sjkoshy	__K8MASK(nta,	2),
1956147191Sjkoshy	NULLMASK
1957147191Sjkoshy};
1958147191Sjkoshy
1959147191Sjkoshy/* dc dcache accesses by locks */
1960147191Sjkoshystatic const struct pmc_masks k8_mask_dabl[] = {
1961147191Sjkoshy	__K8MASK(accesses,	0),
1962147191Sjkoshy	__K8MASK(misses,	1),
1963147191Sjkoshy	NULLMASK
1964147191Sjkoshy};
1965147191Sjkoshy
1966147191Sjkoshy/* bu internal l2 request */
1967147191Sjkoshystatic const struct pmc_masks k8_mask_bilr[] = {
1968147191Sjkoshy	__K8MASK(ic-fill,	0),
1969147191Sjkoshy	__K8MASK(dc-fill,	1),
1970147191Sjkoshy	__K8MASK(tlb-reload,	2),
1971147191Sjkoshy	__K8MASK(tag-snoop,	3),
1972147191Sjkoshy	__K8MASK(cancelled,	4),
1973147191Sjkoshy	NULLMASK
1974147191Sjkoshy};
1975147191Sjkoshy
1976147191Sjkoshy/* bu fill request l2 miss */
1977147191Sjkoshystatic const struct pmc_masks k8_mask_bfrlm[] = {
1978147191Sjkoshy	__K8MASK(ic-fill,	0),
1979147191Sjkoshy	__K8MASK(dc-fill,	1),
1980147191Sjkoshy	__K8MASK(tlb-reload,	2),
1981147191Sjkoshy	NULLMASK
1982147191Sjkoshy};
1983147191Sjkoshy
1984147191Sjkoshy/* bu fill into l2 */
1985147191Sjkoshystatic const struct pmc_masks k8_mask_bfil[] = {
1986147191Sjkoshy	__K8MASK(dirty-l2-victim,	0),
1987147191Sjkoshy	__K8MASK(victim-from-l2,	1),
1988147191Sjkoshy	NULLMASK
1989147191Sjkoshy};
1990147191Sjkoshy
1991147191Sjkoshy/* fr retired fpu instructions */
1992147191Sjkoshystatic const struct pmc_masks k8_mask_frfi[] = {
1993147191Sjkoshy	__K8MASK(x87,			0),
1994147191Sjkoshy	__K8MASK(mmx-3dnow,		1),
1995147191Sjkoshy	__K8MASK(packed-sse-sse2,	2),
1996147191Sjkoshy	__K8MASK(scalar-sse-sse2,	3),
1997147191Sjkoshy	NULLMASK
1998147191Sjkoshy};
1999147191Sjkoshy
2000147191Sjkoshy/* fr retired fastpath double op instructions */
2001147191Sjkoshystatic const struct pmc_masks k8_mask_frfdoi[] = {
2002147191Sjkoshy	__K8MASK(low-op-pos-0,		0),
2003147191Sjkoshy	__K8MASK(low-op-pos-1,		1),
2004147191Sjkoshy	__K8MASK(low-op-pos-2,		2),
2005147191Sjkoshy	NULLMASK
2006147191Sjkoshy};
2007147191Sjkoshy
2008147191Sjkoshy/* fr fpu exceptions */
2009147191Sjkoshystatic const struct pmc_masks k8_mask_ffe[] = {
2010147191Sjkoshy	__K8MASK(x87-reclass-microfaults,	0),
2011147191Sjkoshy	__K8MASK(sse-retype-microfaults,	1),
2012147191Sjkoshy	__K8MASK(sse-reclass-microfaults,	2),
2013147191Sjkoshy	__K8MASK(sse-and-x87-microtraps,	3),
2014147191Sjkoshy	NULLMASK
2015147191Sjkoshy};
2016147191Sjkoshy
2017147191Sjkoshy/* nb memory controller page access event */
2018147191Sjkoshystatic const struct pmc_masks k8_mask_nmcpae[] = {
2019147191Sjkoshy	__K8MASK(page-hit,	0),
2020147191Sjkoshy	__K8MASK(page-miss,	1),
2021147191Sjkoshy	__K8MASK(page-conflict,	2),
2022147191Sjkoshy	NULLMASK
2023147191Sjkoshy};
2024147191Sjkoshy
2025147191Sjkoshy/* nb memory controller turnaround */
2026147191Sjkoshystatic const struct pmc_masks k8_mask_nmct[] = {
2027147191Sjkoshy	__K8MASK(dimm-turnaround,		0),
2028147191Sjkoshy	__K8MASK(read-to-write-turnaround,	1),
2029147191Sjkoshy	__K8MASK(write-to-read-turnaround,	2),
2030147191Sjkoshy	NULLMASK
2031147191Sjkoshy};
2032147191Sjkoshy
2033147191Sjkoshy/* nb memory controller bypass saturation */
2034147191Sjkoshystatic const struct pmc_masks k8_mask_nmcbs[] = {
2035147191Sjkoshy	__K8MASK(memory-controller-hi-pri-bypass,	0),
2036147191Sjkoshy	__K8MASK(memory-controller-lo-pri-bypass,	1),
2037147191Sjkoshy	__K8MASK(dram-controller-interface-bypass,	2),
2038147191Sjkoshy	__K8MASK(dram-controller-queue-bypass,		3),
2039147191Sjkoshy	NULLMASK
2040147191Sjkoshy};
2041147191Sjkoshy
2042147191Sjkoshy/* nb sized commands */
2043147191Sjkoshystatic const struct pmc_masks k8_mask_nsc[] = {
2044147191Sjkoshy	__K8MASK(nonpostwrszbyte,	0),
2045147191Sjkoshy	__K8MASK(nonpostwrszdword,	1),
2046147191Sjkoshy	__K8MASK(postwrszbyte,		2),
2047147191Sjkoshy	__K8MASK(postwrszdword,		3),
2048147191Sjkoshy	__K8MASK(rdszbyte,		4),
2049147191Sjkoshy	__K8MASK(rdszdword,		5),
2050147191Sjkoshy	__K8MASK(rdmodwr,		6),
2051147191Sjkoshy	NULLMASK
2052147191Sjkoshy};
2053147191Sjkoshy
2054147191Sjkoshy/* nb probe result */
2055147191Sjkoshystatic const struct pmc_masks k8_mask_npr[] = {
2056147191Sjkoshy	__K8MASK(probe-miss,		0),
2057147191Sjkoshy	__K8MASK(probe-hit,		1),
2058147191Sjkoshy	__K8MASK(probe-hit-dirty-no-memory-cancel, 2),
2059147191Sjkoshy	__K8MASK(probe-hit-dirty-with-memory-cancel, 3),
2060147191Sjkoshy	NULLMASK
2061147191Sjkoshy};
2062147191Sjkoshy
2063147191Sjkoshy/* nb hypertransport bus bandwidth */
2064147191Sjkoshystatic const struct pmc_masks k8_mask_nhbb[] = { /* HT bus bandwidth */
2065147191Sjkoshy	__K8MASK(command,	0),
2066183107Sjkoshy	__K8MASK(data,	1),
2067147191Sjkoshy	__K8MASK(buffer-release, 2),
2068147191Sjkoshy	__K8MASK(nop,	3),
2069147191Sjkoshy	NULLMASK
2070147191Sjkoshy};
2071147191Sjkoshy
2072147191Sjkoshy#undef	__K8MASK
2073147191Sjkoshy
2074147191Sjkoshy#define	K8_KW_COUNT	"count"
2075147191Sjkoshy#define	K8_KW_EDGE	"edge"
2076147191Sjkoshy#define	K8_KW_INV	"inv"
2077147191Sjkoshy#define	K8_KW_MASK	"mask"
2078147191Sjkoshy#define	K8_KW_OS	"os"
2079147191Sjkoshy#define	K8_KW_USR	"usr"
2080147191Sjkoshy
2081147191Sjkoshystatic int
2082147191Sjkoshyk8_allocate_pmc(enum pmc_event pe, char *ctrspec,
2083147191Sjkoshy    struct pmc_op_pmcallocate *pmc_config)
2084147191Sjkoshy{
2085183107Sjkoshy	char		*e, *p, *q;
2086183107Sjkoshy	int		n;
2087240164Sfabient	uint32_t	count;
2088240164Sfabient	uint64_t	evmask;
2089147191Sjkoshy	const struct pmc_masks	*pm, *pmask;
2090147191Sjkoshy
2091183725Sjkoshy	pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE);
2092147191Sjkoshy	pmc_config->pm_md.pm_amd.pm_amd_config = 0;
2093147191Sjkoshy
2094147191Sjkoshy	pmask = NULL;
2095147191Sjkoshy	evmask = 0;
2096147191Sjkoshy
2097147191Sjkoshy#define	__K8SETMASK(M) pmask = k8_mask_##M
2098147191Sjkoshy
2099147191Sjkoshy	/* setup parsing tables */
2100147191Sjkoshy	switch (pe) {
2101147191Sjkoshy	case PMC_EV_K8_FP_DISPATCHED_FPU_OPS:
2102147191Sjkoshy		__K8SETMASK(fdfo);
2103147191Sjkoshy		break;
2104147191Sjkoshy	case PMC_EV_K8_LS_SEGMENT_REGISTER_LOAD:
2105147191Sjkoshy		__K8SETMASK(lsrl);
2106147191Sjkoshy		break;
2107147191Sjkoshy	case PMC_EV_K8_LS_LOCKED_OPERATION:
2108147191Sjkoshy		__K8SETMASK(llo);
2109147191Sjkoshy		break;
2110147191Sjkoshy	case PMC_EV_K8_DC_REFILL_FROM_L2:
2111147191Sjkoshy	case PMC_EV_K8_DC_REFILL_FROM_SYSTEM:
2112147191Sjkoshy	case PMC_EV_K8_DC_COPYBACK:
2113147191Sjkoshy		__K8SETMASK(dc);
2114147191Sjkoshy		break;
2115147191Sjkoshy	case PMC_EV_K8_DC_ONE_BIT_ECC_ERROR:
2116147191Sjkoshy		__K8SETMASK(dobee);
2117147191Sjkoshy		break;
2118147191Sjkoshy	case PMC_EV_K8_DC_DISPATCHED_PREFETCH_INSTRUCTIONS:
2119147191Sjkoshy		__K8SETMASK(ddpi);
2120147191Sjkoshy		break;
2121147191Sjkoshy	case PMC_EV_K8_DC_DCACHE_ACCESSES_BY_LOCKS:
2122147191Sjkoshy		__K8SETMASK(dabl);
2123147191Sjkoshy		break;
2124147191Sjkoshy	case PMC_EV_K8_BU_INTERNAL_L2_REQUEST:
2125147191Sjkoshy		__K8SETMASK(bilr);
2126147191Sjkoshy		break;
2127147191Sjkoshy	case PMC_EV_K8_BU_FILL_REQUEST_L2_MISS:
2128147191Sjkoshy		__K8SETMASK(bfrlm);
2129147191Sjkoshy		break;
2130147191Sjkoshy	case PMC_EV_K8_BU_FILL_INTO_L2:
2131147191Sjkoshy		__K8SETMASK(bfil);
2132147191Sjkoshy		break;
2133147191Sjkoshy	case PMC_EV_K8_FR_RETIRED_FPU_INSTRUCTIONS:
2134147191Sjkoshy		__K8SETMASK(frfi);
2135147191Sjkoshy		break;
2136147191Sjkoshy	case PMC_EV_K8_FR_RETIRED_FASTPATH_DOUBLE_OP_INSTRUCTIONS:
2137147191Sjkoshy		__K8SETMASK(frfdoi);
2138147191Sjkoshy		break;
2139147191Sjkoshy	case PMC_EV_K8_FR_FPU_EXCEPTIONS:
2140147191Sjkoshy		__K8SETMASK(ffe);
2141147191Sjkoshy		break;
2142147191Sjkoshy	case PMC_EV_K8_NB_MEMORY_CONTROLLER_PAGE_ACCESS_EVENT:
2143147191Sjkoshy		__K8SETMASK(nmcpae);
2144147191Sjkoshy		break;
2145147191Sjkoshy	case PMC_EV_K8_NB_MEMORY_CONTROLLER_TURNAROUND:
2146147191Sjkoshy		__K8SETMASK(nmct);
2147147191Sjkoshy		break;
2148147191Sjkoshy	case PMC_EV_K8_NB_MEMORY_CONTROLLER_BYPASS_SATURATION:
2149147191Sjkoshy		__K8SETMASK(nmcbs);
2150147191Sjkoshy		break;
2151147191Sjkoshy	case PMC_EV_K8_NB_SIZED_COMMANDS:
2152147191Sjkoshy		__K8SETMASK(nsc);
2153147191Sjkoshy		break;
2154147191Sjkoshy	case PMC_EV_K8_NB_PROBE_RESULT:
2155147191Sjkoshy		__K8SETMASK(npr);
2156147191Sjkoshy		break;
2157147191Sjkoshy	case PMC_EV_K8_NB_HT_BUS0_BANDWIDTH:
2158147191Sjkoshy	case PMC_EV_K8_NB_HT_BUS1_BANDWIDTH:
2159147191Sjkoshy	case PMC_EV_K8_NB_HT_BUS2_BANDWIDTH:
2160147191Sjkoshy		__K8SETMASK(nhbb);
2161147191Sjkoshy		break;
2162147191Sjkoshy
2163147191Sjkoshy	default:
2164147191Sjkoshy		break;		/* no options defined */
2165147191Sjkoshy	}
2166147191Sjkoshy
2167147191Sjkoshy	while ((p = strsep(&ctrspec, ",")) != NULL) {
2168147191Sjkoshy		if (KWPREFIXMATCH(p, K8_KW_COUNT "=")) {
2169147191Sjkoshy			q = strchr(p, '=');
2170147191Sjkoshy			if (*++q == '\0') /* skip '=' */
2171174406Sjkoshy				return (-1);
2172147191Sjkoshy
2173147191Sjkoshy			count = strtol(q, &e, 0);
2174147191Sjkoshy			if (e == q || *e != '\0')
2175174406Sjkoshy				return (-1);
2176147191Sjkoshy
2177147191Sjkoshy			pmc_config->pm_caps |= PMC_CAP_THRESHOLD;
2178147191Sjkoshy			pmc_config->pm_md.pm_amd.pm_amd_config |=
2179147191Sjkoshy			    AMD_PMC_TO_COUNTER(count);
2180147191Sjkoshy
2181147191Sjkoshy		} else if (KWMATCH(p, K8_KW_EDGE)) {
2182147191Sjkoshy			pmc_config->pm_caps |= PMC_CAP_EDGE;
2183147191Sjkoshy		} else if (KWMATCH(p, K8_KW_INV)) {
2184147191Sjkoshy			pmc_config->pm_caps |= PMC_CAP_INVERT;
2185147191Sjkoshy		} else if (KWPREFIXMATCH(p, K8_KW_MASK "=")) {
2186147191Sjkoshy			if ((n = pmc_parse_mask(pmask, p, &evmask)) < 0)
2187174406Sjkoshy				return (-1);
2188147191Sjkoshy			pmc_config->pm_caps |= PMC_CAP_QUALIFIER;
2189147191Sjkoshy		} else if (KWMATCH(p, K8_KW_OS)) {
2190147191Sjkoshy			pmc_config->pm_caps |= PMC_CAP_SYSTEM;
2191147191Sjkoshy		} else if (KWMATCH(p, K8_KW_USR)) {
2192147191Sjkoshy			pmc_config->pm_caps |= PMC_CAP_USER;
2193147191Sjkoshy		} else
2194174406Sjkoshy			return (-1);
2195147191Sjkoshy	}
2196147191Sjkoshy
2197147191Sjkoshy	/* other post processing */
2198147191Sjkoshy	switch (pe) {
2199147191Sjkoshy	case PMC_EV_K8_FP_DISPATCHED_FPU_OPS:
2200147191Sjkoshy	case PMC_EV_K8_FP_CYCLES_WITH_NO_FPU_OPS_RETIRED:
2201147191Sjkoshy	case PMC_EV_K8_FP_DISPATCHED_FPU_FAST_FLAG_OPS:
2202147191Sjkoshy	case PMC_EV_K8_FR_RETIRED_FASTPATH_DOUBLE_OP_INSTRUCTIONS:
2203147191Sjkoshy	case PMC_EV_K8_FR_RETIRED_FPU_INSTRUCTIONS:
2204147191Sjkoshy	case PMC_EV_K8_FR_FPU_EXCEPTIONS:
2205147191Sjkoshy		/* XXX only available in rev B and later */
2206147191Sjkoshy		break;
2207147191Sjkoshy	case PMC_EV_K8_DC_DCACHE_ACCESSES_BY_LOCKS:
2208147191Sjkoshy		/* XXX only available in rev C and later */
2209147191Sjkoshy		break;
2210147191Sjkoshy	case PMC_EV_K8_LS_LOCKED_OPERATION:
2211147191Sjkoshy		/* XXX CPU Rev A,B evmask is to be zero */
2212147191Sjkoshy		if (evmask & (evmask - 1)) /* > 1 bit set */
2213174406Sjkoshy			return (-1);
2214147191Sjkoshy		if (evmask == 0) {
2215147191Sjkoshy			evmask = 0x01; /* Rev C and later: #instrs */
2216147191Sjkoshy			pmc_config->pm_caps |= PMC_CAP_QUALIFIER;
2217147191Sjkoshy		}
2218147191Sjkoshy		break;
2219147191Sjkoshy	default:
2220147191Sjkoshy		if (evmask == 0 && pmask != NULL) {
2221147191Sjkoshy			for (pm = pmask; pm->pm_name; pm++)
2222147191Sjkoshy				evmask |= pm->pm_value;
2223147191Sjkoshy			pmc_config->pm_caps |= PMC_CAP_QUALIFIER;
2224147191Sjkoshy		}
2225147191Sjkoshy	}
2226147191Sjkoshy
2227147191Sjkoshy	if (pmc_config->pm_caps & PMC_CAP_QUALIFIER)
2228147191Sjkoshy		pmc_config->pm_md.pm_amd.pm_amd_config =
2229147191Sjkoshy		    AMD_PMC_TO_UNITMASK(evmask);
2230147191Sjkoshy
2231174406Sjkoshy	return (0);
2232147191Sjkoshy}
2233147191Sjkoshy
2234147191Sjkoshy#endif
2235147191Sjkoshy
2236147759Sjkoshy#if defined(__amd64__) || defined(__i386__)
2237147191Sjkoshy
2238147191Sjkoshy/*
2239145256Sjkoshy * Intel P4 PMCs
2240145256Sjkoshy */
2241145256Sjkoshy
2242145256Sjkoshystatic struct pmc_event_alias p4_aliases[] = {
2243145351Sjkoshy	EV_ALIAS("branches",		"p4-branch-retired,mask=mmtp+mmtm"),
2244145351Sjkoshy	EV_ALIAS("branch-mispredicts",	"p4-mispred-branch-retired"),
2245145351Sjkoshy	EV_ALIAS("cycles",		"tsc"),
2246145351Sjkoshy	EV_ALIAS("instructions",
2247145351Sjkoshy	    "p4-instr-retired,mask=nbogusntag+nbogustag"),
2248155998Sjkoshy	EV_ALIAS("unhalted-cycles",	"p4-global-power-events"),
2249145256Sjkoshy	EV_ALIAS(NULL, NULL)
2250145256Sjkoshy};
2251145256Sjkoshy
2252145256Sjkoshy#define	P4_KW_ACTIVE	"active"
2253145256Sjkoshy#define	P4_KW_ACTIVE_ANY "any"
2254145256Sjkoshy#define	P4_KW_ACTIVE_BOTH "both"
2255145256Sjkoshy#define	P4_KW_ACTIVE_NONE "none"
2256145256Sjkoshy#define	P4_KW_ACTIVE_SINGLE "single"
2257145256Sjkoshy#define	P4_KW_BUSREQTYPE "busreqtype"
2258145256Sjkoshy#define	P4_KW_CASCADE	"cascade"
2259145256Sjkoshy#define	P4_KW_EDGE	"edge"
2260145256Sjkoshy#define	P4_KW_INV	"complement"
2261145256Sjkoshy#define	P4_KW_OS	"os"
2262145256Sjkoshy#define	P4_KW_MASK	"mask"
2263145256Sjkoshy#define	P4_KW_PRECISE	"precise"
2264145256Sjkoshy#define	P4_KW_TAG	"tag"
2265145256Sjkoshy#define	P4_KW_THRESHOLD	"threshold"
2266145256Sjkoshy#define	P4_KW_USR	"usr"
2267145256Sjkoshy
2268145256Sjkoshy#define	__P4MASK(N,V) PMCMASK(N, (1 << (V)))
2269145256Sjkoshy
2270145256Sjkoshystatic const struct pmc_masks p4_mask_tcdm[] = { /* tc deliver mode */
2271145256Sjkoshy	__P4MASK(dd, 0),
2272145256Sjkoshy	__P4MASK(db, 1),
2273145256Sjkoshy	__P4MASK(di, 2),
2274145256Sjkoshy	__P4MASK(bd, 3),
2275145256Sjkoshy	__P4MASK(bb, 4),
2276145256Sjkoshy	__P4MASK(bi, 5),
2277145256Sjkoshy	__P4MASK(id, 6),
2278145256Sjkoshy	__P4MASK(ib, 7),
2279145256Sjkoshy	NULLMASK
2280145256Sjkoshy};
2281145256Sjkoshy
2282145256Sjkoshystatic const struct pmc_masks p4_mask_bfr[] = { /* bpu fetch request */
2283145256Sjkoshy	__P4MASK(tcmiss, 0),
2284145256Sjkoshy	NULLMASK,
2285145256Sjkoshy};
2286145256Sjkoshy
2287145256Sjkoshystatic const struct pmc_masks p4_mask_ir[] = { /* itlb reference */
2288145256Sjkoshy	__P4MASK(hit, 0),
2289145256Sjkoshy	__P4MASK(miss, 1),
2290145256Sjkoshy	__P4MASK(hit-uc, 2),
2291145256Sjkoshy	NULLMASK
2292145256Sjkoshy};
2293145256Sjkoshy
2294145256Sjkoshystatic const struct pmc_masks p4_mask_memcan[] = { /* memory cancel */
2295145256Sjkoshy	__P4MASK(st-rb-full, 2),
2296145256Sjkoshy	__P4MASK(64k-conf, 3),
2297145256Sjkoshy	NULLMASK
2298145256Sjkoshy};
2299145256Sjkoshy
2300145256Sjkoshystatic const struct pmc_masks p4_mask_memcomp[] = { /* memory complete */
2301145256Sjkoshy	__P4MASK(lsc, 0),
2302145256Sjkoshy	__P4MASK(ssc, 1),
2303145256Sjkoshy	NULLMASK
2304145256Sjkoshy};
2305145256Sjkoshy
2306145256Sjkoshystatic const struct pmc_masks p4_mask_lpr[] = { /* load port replay */
2307145256Sjkoshy	__P4MASK(split-ld, 1),
2308145256Sjkoshy	NULLMASK
2309145256Sjkoshy};
2310145256Sjkoshy
2311145256Sjkoshystatic const struct pmc_masks p4_mask_spr[] = { /* store port replay */
2312145256Sjkoshy	__P4MASK(split-st, 1),
2313145256Sjkoshy	NULLMASK
2314145256Sjkoshy};
2315145256Sjkoshy
2316145256Sjkoshystatic const struct pmc_masks p4_mask_mlr[] = { /* mob load replay */
2317145256Sjkoshy	__P4MASK(no-sta, 1),
2318145256Sjkoshy	__P4MASK(no-std, 3),
2319145256Sjkoshy	__P4MASK(partial-data, 4),
2320145256Sjkoshy	__P4MASK(unalgn-addr, 5),
2321145256Sjkoshy	NULLMASK
2322145256Sjkoshy};
2323145256Sjkoshy
2324145256Sjkoshystatic const struct pmc_masks p4_mask_pwt[] = { /* page walk type */
2325145256Sjkoshy	__P4MASK(dtmiss, 0),
2326145256Sjkoshy	__P4MASK(itmiss, 1),
2327145256Sjkoshy	NULLMASK
2328145256Sjkoshy};
2329145256Sjkoshy
2330145256Sjkoshystatic const struct pmc_masks p4_mask_bcr[] = { /* bsq cache reference */
2331145256Sjkoshy	__P4MASK(rd-2ndl-hits, 0),
2332145256Sjkoshy	__P4MASK(rd-2ndl-hite, 1),
2333145256Sjkoshy	__P4MASK(rd-2ndl-hitm, 2),
2334145256Sjkoshy	__P4MASK(rd-3rdl-hits, 3),
2335145256Sjkoshy	__P4MASK(rd-3rdl-hite, 4),
2336145256Sjkoshy	__P4MASK(rd-3rdl-hitm, 5),
2337145256Sjkoshy	__P4MASK(rd-2ndl-miss, 8),
2338145256Sjkoshy	__P4MASK(rd-3rdl-miss, 9),
2339145256Sjkoshy	__P4MASK(wr-2ndl-miss, 10),
2340145256Sjkoshy	NULLMASK
2341145256Sjkoshy};
2342145256Sjkoshy
2343145256Sjkoshystatic const struct pmc_masks p4_mask_ia[] = { /* ioq allocation */
2344145256Sjkoshy	__P4MASK(all-read, 5),
2345145256Sjkoshy	__P4MASK(all-write, 6),
2346145256Sjkoshy	__P4MASK(mem-uc, 7),
2347145256Sjkoshy	__P4MASK(mem-wc, 8),
2348145256Sjkoshy	__P4MASK(mem-wt, 9),
2349145256Sjkoshy	__P4MASK(mem-wp, 10),
2350145256Sjkoshy	__P4MASK(mem-wb, 11),
2351145256Sjkoshy	__P4MASK(own, 13),
2352145256Sjkoshy	__P4MASK(other, 14),
2353145256Sjkoshy	__P4MASK(prefetch, 15),
2354145256Sjkoshy	NULLMASK
2355145256Sjkoshy};
2356145256Sjkoshy
2357145256Sjkoshystatic const struct pmc_masks p4_mask_iae[] = { /* ioq active entries */
2358145256Sjkoshy	__P4MASK(all-read, 5),
2359145256Sjkoshy	__P4MASK(all-write, 6),
2360145256Sjkoshy	__P4MASK(mem-uc, 7),
2361145256Sjkoshy	__P4MASK(mem-wc, 8),
2362145256Sjkoshy	__P4MASK(mem-wt, 9),
2363145256Sjkoshy	__P4MASK(mem-wp, 10),
2364145256Sjkoshy	__P4MASK(mem-wb, 11),
2365145256Sjkoshy	__P4MASK(own, 13),
2366145256Sjkoshy	__P4MASK(other, 14),
2367145256Sjkoshy	__P4MASK(prefetch, 15),
2368145256Sjkoshy	NULLMASK
2369145256Sjkoshy};
2370145256Sjkoshy
2371145256Sjkoshystatic const struct pmc_masks p4_mask_fda[] = { /* fsb data activity */
2372145256Sjkoshy	__P4MASK(drdy-drv, 0),
2373145256Sjkoshy	__P4MASK(drdy-own, 1),
2374145256Sjkoshy	__P4MASK(drdy-other, 2),
2375145256Sjkoshy	__P4MASK(dbsy-drv, 3),
2376145256Sjkoshy	__P4MASK(dbsy-own, 4),
2377145256Sjkoshy	__P4MASK(dbsy-other, 5),
2378145256Sjkoshy	NULLMASK
2379145256Sjkoshy};
2380145256Sjkoshy
2381145256Sjkoshystatic const struct pmc_masks p4_mask_ba[] = { /* bsq allocation */
2382145256Sjkoshy	__P4MASK(req-type0, 0),
2383145256Sjkoshy	__P4MASK(req-type1, 1),
2384145256Sjkoshy	__P4MASK(req-len0, 2),
2385145256Sjkoshy	__P4MASK(req-len1, 3),
2386145256Sjkoshy	__P4MASK(req-io-type, 5),
2387145256Sjkoshy	__P4MASK(req-lock-type, 6),
2388145256Sjkoshy	__P4MASK(req-cache-type, 7),
2389145256Sjkoshy	__P4MASK(req-split-type, 8),
2390145256Sjkoshy	__P4MASK(req-dem-type, 9),
2391145256Sjkoshy	__P4MASK(req-ord-type, 10),
2392145256Sjkoshy	__P4MASK(mem-type0, 11),
2393145256Sjkoshy	__P4MASK(mem-type1, 12),
2394145256Sjkoshy	__P4MASK(mem-type2, 13),
2395145256Sjkoshy	NULLMASK
2396145256Sjkoshy};
2397145256Sjkoshy
2398145256Sjkoshystatic const struct pmc_masks p4_mask_sia[] = { /* sse input assist */
2399145256Sjkoshy	__P4MASK(all, 15),
2400145256Sjkoshy	NULLMASK
2401145256Sjkoshy};
2402145256Sjkoshy
2403145256Sjkoshystatic const struct pmc_masks p4_mask_psu[] = { /* packed sp uop */
2404145256Sjkoshy	__P4MASK(all, 15),
2405145256Sjkoshy	NULLMASK
2406145256Sjkoshy};
2407145256Sjkoshy
2408145256Sjkoshystatic const struct pmc_masks p4_mask_pdu[] = { /* packed dp uop */
2409145256Sjkoshy	__P4MASK(all, 15),
2410145256Sjkoshy	NULLMASK
2411145256Sjkoshy};
2412145256Sjkoshy
2413145256Sjkoshystatic const struct pmc_masks p4_mask_ssu[] = { /* scalar sp uop */
2414145256Sjkoshy	__P4MASK(all, 15),
2415145256Sjkoshy	NULLMASK
2416145256Sjkoshy};
2417145256Sjkoshy
2418145256Sjkoshystatic const struct pmc_masks p4_mask_sdu[] = { /* scalar dp uop */
2419145256Sjkoshy	__P4MASK(all, 15),
2420145256Sjkoshy	NULLMASK
2421145256Sjkoshy};
2422145256Sjkoshy
2423145256Sjkoshystatic const struct pmc_masks p4_mask_64bmu[] = { /* 64 bit mmx uop */
2424145256Sjkoshy	__P4MASK(all, 15),
2425145256Sjkoshy	NULLMASK
2426145256Sjkoshy};
2427145256Sjkoshy
2428145256Sjkoshystatic const struct pmc_masks p4_mask_128bmu[] = { /* 128 bit mmx uop */
2429145256Sjkoshy	__P4MASK(all, 15),
2430145256Sjkoshy	NULLMASK
2431145256Sjkoshy};
2432145256Sjkoshy
2433145256Sjkoshystatic const struct pmc_masks p4_mask_xfu[] = { /* X87 fp uop */
2434145256Sjkoshy	__P4MASK(all, 15),
2435145256Sjkoshy	NULLMASK
2436145256Sjkoshy};
2437145256Sjkoshy
2438145256Sjkoshystatic const struct pmc_masks p4_mask_xsmu[] = { /* x87 simd moves uop */
2439145256Sjkoshy	__P4MASK(allp0, 3),
2440145256Sjkoshy	__P4MASK(allp2, 4),
2441145256Sjkoshy	NULLMASK
2442145256Sjkoshy};
2443145256Sjkoshy
2444145256Sjkoshystatic const struct pmc_masks p4_mask_gpe[] = { /* global power events */
2445145256Sjkoshy	__P4MASK(running, 0),
2446145256Sjkoshy	NULLMASK
2447145256Sjkoshy};
2448145256Sjkoshy
2449145256Sjkoshystatic const struct pmc_masks p4_mask_tmx[] = { /* TC ms xfer */
2450145256Sjkoshy	__P4MASK(cisc, 0),
2451145256Sjkoshy	NULLMASK
2452145256Sjkoshy};
2453145256Sjkoshy
2454145256Sjkoshystatic const struct pmc_masks p4_mask_uqw[] = { /* uop queue writes */
2455145256Sjkoshy	__P4MASK(from-tc-build, 0),
2456145256Sjkoshy	__P4MASK(from-tc-deliver, 1),
2457145256Sjkoshy	__P4MASK(from-rom, 2),
2458145256Sjkoshy	NULLMASK
2459145256Sjkoshy};
2460145256Sjkoshy
2461145351Sjkoshystatic const struct pmc_masks p4_mask_rmbt[] = {
2462145351Sjkoshy	/* retired mispred branch type */
2463145256Sjkoshy	__P4MASK(conditional, 1),
2464145256Sjkoshy	__P4MASK(call, 2),
2465145256Sjkoshy	__P4MASK(return, 3),
2466145256Sjkoshy	__P4MASK(indirect, 4),
2467145256Sjkoshy	NULLMASK
2468145256Sjkoshy};
2469145256Sjkoshy
2470145256Sjkoshystatic const struct pmc_masks p4_mask_rbt[] = { /* retired branch type */
2471145256Sjkoshy	__P4MASK(conditional, 1),
2472145256Sjkoshy	__P4MASK(call, 2),
2473145256Sjkoshy	__P4MASK(retired, 3),
2474145256Sjkoshy	__P4MASK(indirect, 4),
2475145256Sjkoshy	NULLMASK
2476145256Sjkoshy};
2477145256Sjkoshy
2478145256Sjkoshystatic const struct pmc_masks p4_mask_rs[] = { /* resource stall */
2479145256Sjkoshy	__P4MASK(sbfull, 5),
2480145256Sjkoshy	NULLMASK
2481145256Sjkoshy};
2482145256Sjkoshy
2483145256Sjkoshystatic const struct pmc_masks p4_mask_wb[] = { /* WC buffer */
2484145256Sjkoshy	__P4MASK(wcb-evicts, 0),
2485145256Sjkoshy	__P4MASK(wcb-full-evict, 1),
2486145256Sjkoshy	NULLMASK
2487145256Sjkoshy};
2488145256Sjkoshy
2489145256Sjkoshystatic const struct pmc_masks p4_mask_fee[] = { /* front end event */
2490145256Sjkoshy	__P4MASK(nbogus, 0),
2491145256Sjkoshy	__P4MASK(bogus, 1),
2492145256Sjkoshy	NULLMASK
2493145256Sjkoshy};
2494145256Sjkoshy
2495145256Sjkoshystatic const struct pmc_masks p4_mask_ee[] = { /* execution event */
2496145256Sjkoshy	__P4MASK(nbogus0, 0),
2497145256Sjkoshy	__P4MASK(nbogus1, 1),
2498145256Sjkoshy	__P4MASK(nbogus2, 2),
2499145256Sjkoshy	__P4MASK(nbogus3, 3),
2500145256Sjkoshy	__P4MASK(bogus0, 4),
2501145256Sjkoshy	__P4MASK(bogus1, 5),
2502145256Sjkoshy	__P4MASK(bogus2, 6),
2503145256Sjkoshy	__P4MASK(bogus3, 7),
2504145256Sjkoshy	NULLMASK
2505145256Sjkoshy};
2506145256Sjkoshy
2507145256Sjkoshystatic const struct pmc_masks p4_mask_re[] = { /* replay event */
2508145256Sjkoshy	__P4MASK(nbogus, 0),
2509145256Sjkoshy	__P4MASK(bogus, 1),
2510145256Sjkoshy	NULLMASK
2511145256Sjkoshy};
2512145256Sjkoshy
2513145256Sjkoshystatic const struct pmc_masks p4_mask_insret[] = { /* instr retired */
2514145256Sjkoshy	__P4MASK(nbogusntag, 0),
2515145256Sjkoshy	__P4MASK(nbogustag, 1),
2516145256Sjkoshy	__P4MASK(bogusntag, 2),
2517145256Sjkoshy	__P4MASK(bogustag, 3),
2518145256Sjkoshy	NULLMASK
2519145256Sjkoshy};
2520145256Sjkoshy
2521145256Sjkoshystatic const struct pmc_masks p4_mask_ur[] = { /* uops retired */
2522145256Sjkoshy	__P4MASK(nbogus, 0),
2523145256Sjkoshy	__P4MASK(bogus, 1),
2524145256Sjkoshy	NULLMASK
2525145256Sjkoshy};
2526145256Sjkoshy
2527145256Sjkoshystatic const struct pmc_masks p4_mask_ut[] = { /* uop type */
2528145256Sjkoshy	__P4MASK(tagloads, 1),
2529145256Sjkoshy	__P4MASK(tagstores, 2),
2530145256Sjkoshy	NULLMASK
2531145256Sjkoshy};
2532145256Sjkoshy
2533145256Sjkoshystatic const struct pmc_masks p4_mask_br[] = { /* branch retired */
2534145256Sjkoshy	__P4MASK(mmnp, 0),
2535145256Sjkoshy	__P4MASK(mmnm, 1),
2536145256Sjkoshy	__P4MASK(mmtp, 2),
2537145256Sjkoshy	__P4MASK(mmtm, 3),
2538145256Sjkoshy	NULLMASK
2539145256Sjkoshy};
2540145256Sjkoshy
2541145256Sjkoshystatic const struct pmc_masks p4_mask_mbr[] = { /* mispred branch retired */
2542145256Sjkoshy	__P4MASK(nbogus, 0),
2543145256Sjkoshy	NULLMASK
2544145256Sjkoshy};
2545145256Sjkoshy
2546145256Sjkoshystatic const struct pmc_masks p4_mask_xa[] = { /* x87 assist */
2547145256Sjkoshy	__P4MASK(fpsu, 0),
2548145256Sjkoshy	__P4MASK(fpso, 1),
2549145256Sjkoshy	__P4MASK(poao, 2),
2550145256Sjkoshy	__P4MASK(poau, 3),
2551145256Sjkoshy	__P4MASK(prea, 4),
2552145256Sjkoshy	NULLMASK
2553145256Sjkoshy};
2554145256Sjkoshy
2555145256Sjkoshystatic const struct pmc_masks p4_mask_machclr[] = { /* machine clear */
2556145256Sjkoshy	__P4MASK(clear, 0),
2557145256Sjkoshy	__P4MASK(moclear, 2),
2558145256Sjkoshy	__P4MASK(smclear, 3),
2559145256Sjkoshy	NULLMASK
2560145256Sjkoshy};
2561145256Sjkoshy
2562145256Sjkoshy/* P4 event parser */
2563145256Sjkoshystatic int
2564145256Sjkoshyp4_allocate_pmc(enum pmc_event pe, char *ctrspec,
2565145256Sjkoshy    struct pmc_op_pmcallocate *pmc_config)
2566145256Sjkoshy{
2567145256Sjkoshy
2568145256Sjkoshy	char	*e, *p, *q;
2569145256Sjkoshy	int	count, has_tag, has_busreqtype, n;
2570240164Sfabient	uint32_t cccractivemask;
2571240164Sfabient	uint64_t evmask;
2572145256Sjkoshy	const struct pmc_masks *pm, *pmask;
2573145256Sjkoshy
2574183725Sjkoshy	pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE);
2575147191Sjkoshy	pmc_config->pm_md.pm_p4.pm_p4_cccrconfig =
2576147191Sjkoshy	    pmc_config->pm_md.pm_p4.pm_p4_escrconfig = 0;
2577145256Sjkoshy
2578145256Sjkoshy	pmask   = NULL;
2579145256Sjkoshy	evmask  = 0;
2580145256Sjkoshy	cccractivemask = 0x3;
2581145256Sjkoshy	has_tag = has_busreqtype = 0;
2582145256Sjkoshy
2583145256Sjkoshy#define	__P4SETMASK(M) do {				\
2584183107Sjkoshy	pmask = p4_mask_##M;				\
2585145256Sjkoshy} while (0)
2586145256Sjkoshy
2587145256Sjkoshy	switch (pe) {
2588145256Sjkoshy	case PMC_EV_P4_TC_DELIVER_MODE:
2589145256Sjkoshy		__P4SETMASK(tcdm);
2590145256Sjkoshy		break;
2591145256Sjkoshy	case PMC_EV_P4_BPU_FETCH_REQUEST:
2592145256Sjkoshy		__P4SETMASK(bfr);
2593145256Sjkoshy		break;
2594145256Sjkoshy	case PMC_EV_P4_ITLB_REFERENCE:
2595145256Sjkoshy		__P4SETMASK(ir);
2596145256Sjkoshy		break;
2597145256Sjkoshy	case PMC_EV_P4_MEMORY_CANCEL:
2598145256Sjkoshy		__P4SETMASK(memcan);
2599145256Sjkoshy		break;
2600145256Sjkoshy	case PMC_EV_P4_MEMORY_COMPLETE:
2601145256Sjkoshy		__P4SETMASK(memcomp);
2602145256Sjkoshy		break;
2603145256Sjkoshy	case PMC_EV_P4_LOAD_PORT_REPLAY:
2604145256Sjkoshy		__P4SETMASK(lpr);
2605145256Sjkoshy		break;
2606145256Sjkoshy	case PMC_EV_P4_STORE_PORT_REPLAY:
2607145256Sjkoshy		__P4SETMASK(spr);
2608145256Sjkoshy		break;
2609145256Sjkoshy	case PMC_EV_P4_MOB_LOAD_REPLAY:
2610145256Sjkoshy		__P4SETMASK(mlr);
2611145256Sjkoshy		break;
2612145256Sjkoshy	case PMC_EV_P4_PAGE_WALK_TYPE:
2613145256Sjkoshy		__P4SETMASK(pwt);
2614145256Sjkoshy		break;
2615145256Sjkoshy	case PMC_EV_P4_BSQ_CACHE_REFERENCE:
2616145256Sjkoshy		__P4SETMASK(bcr);
2617145256Sjkoshy		break;
2618145256Sjkoshy	case PMC_EV_P4_IOQ_ALLOCATION:
2619145256Sjkoshy		__P4SETMASK(ia);
2620145256Sjkoshy		has_busreqtype = 1;
2621145256Sjkoshy		break;
2622145256Sjkoshy	case PMC_EV_P4_IOQ_ACTIVE_ENTRIES:
2623145256Sjkoshy		__P4SETMASK(iae);
2624145256Sjkoshy		has_busreqtype = 1;
2625145256Sjkoshy		break;
2626145256Sjkoshy	case PMC_EV_P4_FSB_DATA_ACTIVITY:
2627145256Sjkoshy		__P4SETMASK(fda);
2628145256Sjkoshy		break;
2629145256Sjkoshy	case PMC_EV_P4_BSQ_ALLOCATION:
2630145256Sjkoshy		__P4SETMASK(ba);
2631145256Sjkoshy		break;
2632145256Sjkoshy	case PMC_EV_P4_SSE_INPUT_ASSIST:
2633145256Sjkoshy		__P4SETMASK(sia);
2634145256Sjkoshy		break;
2635145256Sjkoshy	case PMC_EV_P4_PACKED_SP_UOP:
2636145256Sjkoshy		__P4SETMASK(psu);
2637145256Sjkoshy		break;
2638145256Sjkoshy	case PMC_EV_P4_PACKED_DP_UOP:
2639145256Sjkoshy		__P4SETMASK(pdu);
2640145256Sjkoshy		break;
2641145256Sjkoshy	case PMC_EV_P4_SCALAR_SP_UOP:
2642145256Sjkoshy		__P4SETMASK(ssu);
2643145256Sjkoshy		break;
2644145256Sjkoshy	case PMC_EV_P4_SCALAR_DP_UOP:
2645145256Sjkoshy		__P4SETMASK(sdu);
2646145256Sjkoshy		break;
2647145256Sjkoshy	case PMC_EV_P4_64BIT_MMX_UOP:
2648145256Sjkoshy		__P4SETMASK(64bmu);
2649145256Sjkoshy		break;
2650145256Sjkoshy	case PMC_EV_P4_128BIT_MMX_UOP:
2651145256Sjkoshy		__P4SETMASK(128bmu);
2652145256Sjkoshy		break;
2653145256Sjkoshy	case PMC_EV_P4_X87_FP_UOP:
2654145256Sjkoshy		__P4SETMASK(xfu);
2655145256Sjkoshy		break;
2656145256Sjkoshy	case PMC_EV_P4_X87_SIMD_MOVES_UOP:
2657145256Sjkoshy		__P4SETMASK(xsmu);
2658145256Sjkoshy		break;
2659145256Sjkoshy	case PMC_EV_P4_GLOBAL_POWER_EVENTS:
2660145256Sjkoshy		__P4SETMASK(gpe);
2661145256Sjkoshy		break;
2662145256Sjkoshy	case PMC_EV_P4_TC_MS_XFER:
2663145256Sjkoshy		__P4SETMASK(tmx);
2664145256Sjkoshy		break;
2665145256Sjkoshy	case PMC_EV_P4_UOP_QUEUE_WRITES:
2666145256Sjkoshy		__P4SETMASK(uqw);
2667145256Sjkoshy		break;
2668145256Sjkoshy	case PMC_EV_P4_RETIRED_MISPRED_BRANCH_TYPE:
2669145256Sjkoshy		__P4SETMASK(rmbt);
2670145256Sjkoshy		break;
2671145256Sjkoshy	case PMC_EV_P4_RETIRED_BRANCH_TYPE:
2672145256Sjkoshy		__P4SETMASK(rbt);
2673145256Sjkoshy		break;
2674145256Sjkoshy	case PMC_EV_P4_RESOURCE_STALL:
2675145256Sjkoshy		__P4SETMASK(rs);
2676145256Sjkoshy		break;
2677145256Sjkoshy	case PMC_EV_P4_WC_BUFFER:
2678145256Sjkoshy		__P4SETMASK(wb);
2679145256Sjkoshy		break;
2680145256Sjkoshy	case PMC_EV_P4_BSQ_ACTIVE_ENTRIES:
2681145256Sjkoshy	case PMC_EV_P4_B2B_CYCLES:
2682145256Sjkoshy	case PMC_EV_P4_BNR:
2683145256Sjkoshy	case PMC_EV_P4_SNOOP:
2684145256Sjkoshy	case PMC_EV_P4_RESPONSE:
2685145256Sjkoshy		break;
2686145256Sjkoshy	case PMC_EV_P4_FRONT_END_EVENT:
2687145256Sjkoshy		__P4SETMASK(fee);
2688145256Sjkoshy		break;
2689145256Sjkoshy	case PMC_EV_P4_EXECUTION_EVENT:
2690145256Sjkoshy		__P4SETMASK(ee);
2691145256Sjkoshy		break;
2692145256Sjkoshy	case PMC_EV_P4_REPLAY_EVENT:
2693145256Sjkoshy		__P4SETMASK(re);
2694145256Sjkoshy		break;
2695145256Sjkoshy	case PMC_EV_P4_INSTR_RETIRED:
2696145256Sjkoshy		__P4SETMASK(insret);
2697145256Sjkoshy		break;
2698145256Sjkoshy	case PMC_EV_P4_UOPS_RETIRED:
2699145256Sjkoshy		__P4SETMASK(ur);
2700145256Sjkoshy		break;
2701145256Sjkoshy	case PMC_EV_P4_UOP_TYPE:
2702145256Sjkoshy		__P4SETMASK(ut);
2703145256Sjkoshy		break;
2704145256Sjkoshy	case PMC_EV_P4_BRANCH_RETIRED:
2705145256Sjkoshy		__P4SETMASK(br);
2706145256Sjkoshy		break;
2707145256Sjkoshy	case PMC_EV_P4_MISPRED_BRANCH_RETIRED:
2708145256Sjkoshy		__P4SETMASK(mbr);
2709145256Sjkoshy		break;
2710145256Sjkoshy	case PMC_EV_P4_X87_ASSIST:
2711145256Sjkoshy		__P4SETMASK(xa);
2712145256Sjkoshy		break;
2713145256Sjkoshy	case PMC_EV_P4_MACHINE_CLEAR:
2714145256Sjkoshy		__P4SETMASK(machclr);
2715145256Sjkoshy		break;
2716145256Sjkoshy	default:
2717174406Sjkoshy		return (-1);
2718145256Sjkoshy	}
2719145256Sjkoshy
2720145256Sjkoshy	/* process additional flags */
2721145256Sjkoshy	while ((p = strsep(&ctrspec, ",")) != NULL) {
2722145256Sjkoshy		if (KWPREFIXMATCH(p, P4_KW_ACTIVE)) {
2723145256Sjkoshy			q = strchr(p, '=');
2724145256Sjkoshy			if (*++q == '\0') /* skip '=' */
2725174406Sjkoshy				return (-1);
2726145256Sjkoshy
2727183725Sjkoshy			if (strcasecmp(q, P4_KW_ACTIVE_NONE) == 0)
2728145256Sjkoshy				cccractivemask = 0x0;
2729183725Sjkoshy			else if (strcasecmp(q, P4_KW_ACTIVE_SINGLE) == 0)
2730145256Sjkoshy				cccractivemask = 0x1;
2731183725Sjkoshy			else if (strcasecmp(q, P4_KW_ACTIVE_BOTH) == 0)
2732145256Sjkoshy				cccractivemask = 0x2;
2733183725Sjkoshy			else if (strcasecmp(q, P4_KW_ACTIVE_ANY) == 0)
2734145256Sjkoshy				cccractivemask = 0x3;
2735145256Sjkoshy			else
2736174406Sjkoshy				return (-1);
2737145256Sjkoshy
2738145256Sjkoshy		} else if (KWPREFIXMATCH(p, P4_KW_BUSREQTYPE)) {
2739145256Sjkoshy			if (has_busreqtype == 0)
2740174406Sjkoshy				return (-1);
2741145256Sjkoshy
2742145256Sjkoshy			q = strchr(p, '=');
2743145256Sjkoshy			if (*++q == '\0') /* skip '=' */
2744174406Sjkoshy				return (-1);
2745145256Sjkoshy
2746145256Sjkoshy			count = strtol(q, &e, 0);
2747145256Sjkoshy			if (e == q || *e != '\0')
2748174406Sjkoshy				return (-1);
2749145256Sjkoshy			evmask = (evmask & ~0x1F) | (count & 0x1F);
2750145256Sjkoshy		} else if (KWMATCH(p, P4_KW_CASCADE))
2751145256Sjkoshy			pmc_config->pm_caps |= PMC_CAP_CASCADE;
2752145256Sjkoshy		else if (KWMATCH(p, P4_KW_EDGE))
2753145256Sjkoshy			pmc_config->pm_caps |= PMC_CAP_EDGE;
2754145256Sjkoshy		else if (KWMATCH(p, P4_KW_INV))
2755145256Sjkoshy			pmc_config->pm_caps |= PMC_CAP_INVERT;
2756145256Sjkoshy		else if (KWPREFIXMATCH(p, P4_KW_MASK "=")) {
2757145256Sjkoshy			if ((n = pmc_parse_mask(pmask, p, &evmask)) < 0)
2758174406Sjkoshy				return (-1);
2759145256Sjkoshy			pmc_config->pm_caps |= PMC_CAP_QUALIFIER;
2760145256Sjkoshy		} else if (KWMATCH(p, P4_KW_OS))
2761145256Sjkoshy			pmc_config->pm_caps |= PMC_CAP_SYSTEM;
2762145256Sjkoshy		else if (KWMATCH(p, P4_KW_PRECISE))
2763145256Sjkoshy			pmc_config->pm_caps |= PMC_CAP_PRECISE;
2764145256Sjkoshy		else if (KWPREFIXMATCH(p, P4_KW_TAG "=")) {
2765145256Sjkoshy			if (has_tag == 0)
2766174406Sjkoshy				return (-1);
2767145256Sjkoshy
2768145256Sjkoshy			q = strchr(p, '=');
2769145256Sjkoshy			if (*++q == '\0') /* skip '=' */
2770174406Sjkoshy				return (-1);
2771145256Sjkoshy
2772145256Sjkoshy			count = strtol(q, &e, 0);
2773145256Sjkoshy			if (e == q || *e != '\0')
2774174406Sjkoshy				return (-1);
2775145256Sjkoshy
2776145256Sjkoshy			pmc_config->pm_caps |= PMC_CAP_TAGGING;
2777147191Sjkoshy			pmc_config->pm_md.pm_p4.pm_p4_escrconfig |=
2778145256Sjkoshy			    P4_ESCR_TO_TAG_VALUE(count);
2779145256Sjkoshy		} else if (KWPREFIXMATCH(p, P4_KW_THRESHOLD "=")) {
2780145256Sjkoshy			q = strchr(p, '=');
2781145256Sjkoshy			if (*++q == '\0') /* skip '=' */
2782174406Sjkoshy				return (-1);
2783145256Sjkoshy
2784145256Sjkoshy			count = strtol(q, &e, 0);
2785145256Sjkoshy			if (e == q || *e != '\0')
2786174406Sjkoshy				return (-1);
2787145256Sjkoshy
2788145256Sjkoshy			pmc_config->pm_caps |= PMC_CAP_THRESHOLD;
2789147191Sjkoshy			pmc_config->pm_md.pm_p4.pm_p4_cccrconfig &=
2790147191Sjkoshy			    ~P4_CCCR_THRESHOLD_MASK;
2791147191Sjkoshy			pmc_config->pm_md.pm_p4.pm_p4_cccrconfig |=
2792147191Sjkoshy			    P4_CCCR_TO_THRESHOLD(count);
2793145256Sjkoshy		} else if (KWMATCH(p, P4_KW_USR))
2794145256Sjkoshy			pmc_config->pm_caps |= PMC_CAP_USER;
2795145256Sjkoshy		else
2796174406Sjkoshy			return (-1);
2797145256Sjkoshy	}
2798145256Sjkoshy
2799145256Sjkoshy	/* other post processing */
2800145256Sjkoshy	if (pe == PMC_EV_P4_IOQ_ALLOCATION ||
2801145256Sjkoshy	    pe == PMC_EV_P4_FSB_DATA_ACTIVITY ||
2802145256Sjkoshy	    pe == PMC_EV_P4_BSQ_ALLOCATION)
2803145256Sjkoshy		pmc_config->pm_caps |= PMC_CAP_EDGE;
2804145256Sjkoshy
2805145256Sjkoshy	/* fill in thread activity mask */
2806147191Sjkoshy	pmc_config->pm_md.pm_p4.pm_p4_cccrconfig |=
2807145256Sjkoshy	    P4_CCCR_TO_ACTIVE_THREAD(cccractivemask);
2808145256Sjkoshy
2809145256Sjkoshy	if (evmask)
2810145256Sjkoshy		pmc_config->pm_caps |= PMC_CAP_QUALIFIER;
2811145256Sjkoshy
2812145256Sjkoshy	switch (pe) {
2813145256Sjkoshy	case PMC_EV_P4_FSB_DATA_ACTIVITY:
2814145256Sjkoshy		if ((evmask & 0x06) == 0x06 ||
2815145256Sjkoshy		    (evmask & 0x18) == 0x18)
2816174406Sjkoshy			return (-1); /* can't have own+other bits together */
2817145256Sjkoshy		if (evmask == 0) /* default:drdy-{drv,own}+dbsy{drv,own} */
2818145256Sjkoshy			evmask = 0x1D;
2819145256Sjkoshy		break;
2820145256Sjkoshy	case PMC_EV_P4_MACHINE_CLEAR:
2821145256Sjkoshy		/* only one bit is allowed to be set */
2822145256Sjkoshy		if ((evmask & (evmask - 1)) != 0)
2823174406Sjkoshy			return (-1);
2824145256Sjkoshy		if (evmask == 0) {
2825183107Sjkoshy			evmask = 0x1;	/* 'CLEAR' */
2826145256Sjkoshy			pmc_config->pm_caps |= PMC_CAP_QUALIFIER;
2827145256Sjkoshy		}
2828145256Sjkoshy		break;
2829145256Sjkoshy	default:
2830145256Sjkoshy		if (evmask == 0 && pmask) {
2831145256Sjkoshy			for (pm = pmask; pm->pm_name; pm++)
2832145256Sjkoshy				evmask |= pm->pm_value;
2833145256Sjkoshy			pmc_config->pm_caps |= PMC_CAP_QUALIFIER;
2834145256Sjkoshy		}
2835145256Sjkoshy	}
2836145256Sjkoshy
2837147191Sjkoshy	pmc_config->pm_md.pm_p4.pm_p4_escrconfig =
2838147191Sjkoshy	    P4_ESCR_TO_EVENT_MASK(evmask);
2839145256Sjkoshy
2840174406Sjkoshy	return (0);
2841145256Sjkoshy}
2842145256Sjkoshy
2843147759Sjkoshy#endif
2844147759Sjkoshy
2845147759Sjkoshy#if defined(__i386__)
2846147759Sjkoshy
2847145256Sjkoshy/*
2848147191Sjkoshy * Pentium style PMCs
2849147191Sjkoshy */
2850147191Sjkoshy
2851147191Sjkoshystatic struct pmc_event_alias p5_aliases[] = {
2852183105Sjkoshy	EV_ALIAS("branches",		"p5-taken-branches"),
2853183105Sjkoshy	EV_ALIAS("cycles",		"tsc"),
2854183105Sjkoshy	EV_ALIAS("dc-misses",		"p5-data-read-miss-or-write-miss"),
2855183105Sjkoshy	EV_ALIAS("ic-misses",		"p5-code-cache-miss"),
2856183105Sjkoshy	EV_ALIAS("instructions",	"p5-instructions-executed"),
2857183105Sjkoshy	EV_ALIAS("interrupts",		"p5-hardware-interrupts"),
2858183105Sjkoshy	EV_ALIAS("unhalted-cycles",
2859183105Sjkoshy	    "p5-number-of-cycles-not-in-halt-state"),
2860147191Sjkoshy	EV_ALIAS(NULL, NULL)
2861147191Sjkoshy};
2862147191Sjkoshy
2863147191Sjkoshystatic int
2864147191Sjkoshyp5_allocate_pmc(enum pmc_event pe, char *ctrspec,
2865147191Sjkoshy    struct pmc_op_pmcallocate *pmc_config)
2866147191Sjkoshy{
2867174406Sjkoshy	return (-1 || pe || ctrspec || pmc_config); /* shut up gcc */
2868147191Sjkoshy}
2869147191Sjkoshy
2870147191Sjkoshy/*
2871145256Sjkoshy * Pentium Pro style PMCs.  These PMCs are found in Pentium II, Pentium III,
2872145256Sjkoshy * and Pentium M CPUs.
2873145256Sjkoshy */
2874145256Sjkoshy
2875145256Sjkoshystatic struct pmc_event_alias p6_aliases[] = {
2876145351Sjkoshy	EV_ALIAS("branches",		"p6-br-inst-retired"),
2877145351Sjkoshy	EV_ALIAS("branch-mispredicts",	"p6-br-miss-pred-retired"),
2878145351Sjkoshy	EV_ALIAS("cycles",		"tsc"),
2879145351Sjkoshy	EV_ALIAS("dc-misses",		"p6-dcu-lines-in"),
2880168612Sjkoshy	EV_ALIAS("ic-misses",		"p6-ifu-fetch-miss"),
2881145351Sjkoshy	EV_ALIAS("instructions",	"p6-inst-retired"),
2882145351Sjkoshy	EV_ALIAS("interrupts",		"p6-hw-int-rx"),
2883155998Sjkoshy	EV_ALIAS("unhalted-cycles",	"p6-cpu-clk-unhalted"),
2884145351Sjkoshy	EV_ALIAS(NULL, NULL)
2885145256Sjkoshy};
2886145256Sjkoshy
2887145256Sjkoshy#define	P6_KW_CMASK	"cmask"
2888145256Sjkoshy#define	P6_KW_EDGE	"edge"
2889145256Sjkoshy#define	P6_KW_INV	"inv"
2890145256Sjkoshy#define	P6_KW_OS	"os"
2891145256Sjkoshy#define	P6_KW_UMASK	"umask"
2892145256Sjkoshy#define	P6_KW_USR	"usr"
2893145256Sjkoshy
2894145256Sjkoshystatic struct pmc_masks p6_mask_mesi[] = {
2895145256Sjkoshy	PMCMASK(m,	0x01),
2896145256Sjkoshy	PMCMASK(e,	0x02),
2897145256Sjkoshy	PMCMASK(s,	0x04),
2898145256Sjkoshy	PMCMASK(i,	0x08),
2899145256Sjkoshy	NULLMASK
2900145256Sjkoshy};
2901145256Sjkoshy
2902145256Sjkoshystatic struct pmc_masks p6_mask_mesihw[] = {
2903145256Sjkoshy	PMCMASK(m,	0x01),
2904145256Sjkoshy	PMCMASK(e,	0x02),
2905145256Sjkoshy	PMCMASK(s,	0x04),
2906145256Sjkoshy	PMCMASK(i,	0x08),
2907145256Sjkoshy	PMCMASK(nonhw,	0x00),
2908145256Sjkoshy	PMCMASK(hw,	0x10),
2909145256Sjkoshy	PMCMASK(both,	0x30),
2910145256Sjkoshy	NULLMASK
2911145256Sjkoshy};
2912145256Sjkoshy
2913145256Sjkoshystatic struct pmc_masks p6_mask_hw[] = {
2914145256Sjkoshy	PMCMASK(nonhw,	0x00),
2915145256Sjkoshy	PMCMASK(hw,	0x10),
2916145256Sjkoshy	PMCMASK(both,	0x30),
2917145256Sjkoshy	NULLMASK
2918145256Sjkoshy};
2919145256Sjkoshy
2920145256Sjkoshystatic struct pmc_masks p6_mask_any[] = {
2921145256Sjkoshy	PMCMASK(self,	0x00),
2922145256Sjkoshy	PMCMASK(any,	0x20),
2923145256Sjkoshy	NULLMASK
2924145256Sjkoshy};
2925145256Sjkoshy
2926145256Sjkoshystatic struct pmc_masks p6_mask_ekp[] = {
2927145256Sjkoshy	PMCMASK(nta,	0x00),
2928145256Sjkoshy	PMCMASK(t1,	0x01),
2929145256Sjkoshy	PMCMASK(t2,	0x02),
2930145256Sjkoshy	PMCMASK(wos,	0x03),
2931145256Sjkoshy	NULLMASK
2932145256Sjkoshy};
2933145256Sjkoshy
2934145256Sjkoshystatic struct pmc_masks p6_mask_pps[] = {
2935145256Sjkoshy	PMCMASK(packed-and-scalar, 0x00),
2936145256Sjkoshy	PMCMASK(scalar,	0x01),
2937145256Sjkoshy	NULLMASK
2938145256Sjkoshy};
2939145256Sjkoshy
2940145256Sjkoshystatic struct pmc_masks p6_mask_mite[] = {
2941145256Sjkoshy	PMCMASK(packed-multiply,	 0x01),
2942145256Sjkoshy	PMCMASK(packed-shift,		0x02),
2943145256Sjkoshy	PMCMASK(pack,			0x04),
2944145256Sjkoshy	PMCMASK(unpack,			0x08),
2945145256Sjkoshy	PMCMASK(packed-logical,		0x10),
2946145256Sjkoshy	PMCMASK(packed-arithmetic,	0x20),
2947145256Sjkoshy	NULLMASK
2948145256Sjkoshy};
2949145256Sjkoshy
2950145256Sjkoshystatic struct pmc_masks p6_mask_fmt[] = {
2951145256Sjkoshy	PMCMASK(mmxtofp,	0x00),
2952145256Sjkoshy	PMCMASK(fptommx,	0x01),
2953145256Sjkoshy	NULLMASK
2954145256Sjkoshy};
2955145256Sjkoshy
2956145256Sjkoshystatic struct pmc_masks p6_mask_sr[] = {
2957145256Sjkoshy	PMCMASK(es,	0x01),
2958145256Sjkoshy	PMCMASK(ds,	0x02),
2959145256Sjkoshy	PMCMASK(fs,	0x04),
2960145256Sjkoshy	PMCMASK(gs,	0x08),
2961145256Sjkoshy	NULLMASK
2962145256Sjkoshy};
2963145256Sjkoshy
2964145256Sjkoshystatic struct pmc_masks p6_mask_eet[] = {
2965145256Sjkoshy	PMCMASK(all,	0x00),
2966145256Sjkoshy	PMCMASK(freq,	0x02),
2967145256Sjkoshy	NULLMASK
2968145256Sjkoshy};
2969145256Sjkoshy
2970145256Sjkoshystatic struct pmc_masks p6_mask_efur[] = {
2971145256Sjkoshy	PMCMASK(all,	0x00),
2972145256Sjkoshy	PMCMASK(loadop,	0x01),
2973145256Sjkoshy	PMCMASK(stdsta,	0x02),
2974145256Sjkoshy	NULLMASK
2975145256Sjkoshy};
2976145256Sjkoshy
2977145256Sjkoshystatic struct pmc_masks p6_mask_essir[] = {
2978145256Sjkoshy	PMCMASK(sse-packed-single,	0x00),
2979145256Sjkoshy	PMCMASK(sse-packed-single-scalar-single, 0x01),
2980145256Sjkoshy	PMCMASK(sse2-packed-double,	0x02),
2981145256Sjkoshy	PMCMASK(sse2-scalar-double,	0x03),
2982145256Sjkoshy	NULLMASK
2983145256Sjkoshy};
2984145256Sjkoshy
2985145256Sjkoshystatic struct pmc_masks p6_mask_esscir[] = {
2986145256Sjkoshy	PMCMASK(sse-packed-single,	0x00),
2987145256Sjkoshy	PMCMASK(sse-scalar-single,	0x01),
2988145256Sjkoshy	PMCMASK(sse2-packed-double,	0x02),
2989145256Sjkoshy	PMCMASK(sse2-scalar-double,	0x03),
2990145256Sjkoshy	NULLMASK
2991145256Sjkoshy};
2992145256Sjkoshy
2993145256Sjkoshy/* P6 event parser */
2994145256Sjkoshystatic int
2995145256Sjkoshyp6_allocate_pmc(enum pmc_event pe, char *ctrspec,
2996145256Sjkoshy    struct pmc_op_pmcallocate *pmc_config)
2997145256Sjkoshy{
2998145256Sjkoshy	char *e, *p, *q;
2999240164Sfabient	uint64_t evmask;
3000145256Sjkoshy	int count, n;
3001145256Sjkoshy	const struct pmc_masks *pm, *pmask;
3002145256Sjkoshy
3003183725Sjkoshy	pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE);
3004147191Sjkoshy	pmc_config->pm_md.pm_ppro.pm_ppro_config = 0;
3005145256Sjkoshy
3006145256Sjkoshy	evmask = 0;
3007145256Sjkoshy
3008145256Sjkoshy#define	P6MASKSET(M)	pmask = p6_mask_ ## M
3009145256Sjkoshy
3010145256Sjkoshy	switch(pe) {
3011183107Sjkoshy	case PMC_EV_P6_L2_IFETCH:	P6MASKSET(mesi); break;
3012145256Sjkoshy	case PMC_EV_P6_L2_LD:		P6MASKSET(mesi); break;
3013145256Sjkoshy	case PMC_EV_P6_L2_ST:		P6MASKSET(mesi); break;
3014145256Sjkoshy	case PMC_EV_P6_L2_RQSTS:	P6MASKSET(mesi); break;
3015145256Sjkoshy	case PMC_EV_P6_BUS_DRDY_CLOCKS:
3016145256Sjkoshy	case PMC_EV_P6_BUS_LOCK_CLOCKS:
3017145256Sjkoshy	case PMC_EV_P6_BUS_TRAN_BRD:
3018145256Sjkoshy	case PMC_EV_P6_BUS_TRAN_RFO:
3019145256Sjkoshy	case PMC_EV_P6_BUS_TRANS_WB:
3020145256Sjkoshy	case PMC_EV_P6_BUS_TRAN_IFETCH:
3021145256Sjkoshy	case PMC_EV_P6_BUS_TRAN_INVAL:
3022145256Sjkoshy	case PMC_EV_P6_BUS_TRAN_PWR:
3023145256Sjkoshy	case PMC_EV_P6_BUS_TRANS_P:
3024145256Sjkoshy	case PMC_EV_P6_BUS_TRANS_IO:
3025145256Sjkoshy	case PMC_EV_P6_BUS_TRAN_DEF:
3026145256Sjkoshy	case PMC_EV_P6_BUS_TRAN_BURST:
3027145256Sjkoshy	case PMC_EV_P6_BUS_TRAN_ANY:
3028145256Sjkoshy	case PMC_EV_P6_BUS_TRAN_MEM:
3029145256Sjkoshy		P6MASKSET(any);	break;
3030145256Sjkoshy	case PMC_EV_P6_EMON_KNI_PREF_DISPATCHED:
3031145256Sjkoshy	case PMC_EV_P6_EMON_KNI_PREF_MISS:
3032145256Sjkoshy		P6MASKSET(ekp); break;
3033145256Sjkoshy	case PMC_EV_P6_EMON_KNI_INST_RETIRED:
3034145256Sjkoshy	case PMC_EV_P6_EMON_KNI_COMP_INST_RET:
3035145256Sjkoshy		P6MASKSET(pps);	break;
3036145256Sjkoshy	case PMC_EV_P6_MMX_INSTR_TYPE_EXEC:
3037145256Sjkoshy		P6MASKSET(mite); break;
3038145256Sjkoshy	case PMC_EV_P6_FP_MMX_TRANS:
3039145256Sjkoshy		P6MASKSET(fmt);	break;
3040145256Sjkoshy	case PMC_EV_P6_SEG_RENAME_STALLS:
3041145256Sjkoshy	case PMC_EV_P6_SEG_REG_RENAMES:
3042145256Sjkoshy		P6MASKSET(sr);	break;
3043145256Sjkoshy	case PMC_EV_P6_EMON_EST_TRANS:
3044145256Sjkoshy		P6MASKSET(eet);	break;
3045145256Sjkoshy	case PMC_EV_P6_EMON_FUSED_UOPS_RET:
3046145256Sjkoshy		P6MASKSET(efur); break;
3047145256Sjkoshy	case PMC_EV_P6_EMON_SSE_SSE2_INST_RETIRED:
3048145256Sjkoshy		P6MASKSET(essir); break;
3049145256Sjkoshy	case PMC_EV_P6_EMON_SSE_SSE2_COMP_INST_RETIRED:
3050145256Sjkoshy		P6MASKSET(esscir); break;
3051145256Sjkoshy	default:
3052145256Sjkoshy		pmask = NULL;
3053145256Sjkoshy		break;
3054145256Sjkoshy	}
3055145256Sjkoshy
3056145256Sjkoshy	/* Pentium M PMCs have a few events with different semantics */
3057145256Sjkoshy	if (cpu_info.pm_cputype == PMC_CPU_INTEL_PM) {
3058145256Sjkoshy		if (pe == PMC_EV_P6_L2_LD ||
3059145256Sjkoshy		    pe == PMC_EV_P6_L2_LINES_IN ||
3060145256Sjkoshy		    pe == PMC_EV_P6_L2_LINES_OUT)
3061145256Sjkoshy			P6MASKSET(mesihw);
3062145256Sjkoshy		else if (pe == PMC_EV_P6_L2_M_LINES_OUTM)
3063145256Sjkoshy			P6MASKSET(hw);
3064145256Sjkoshy	}
3065145256Sjkoshy
3066145256Sjkoshy	/* Parse additional modifiers if present */
3067145256Sjkoshy	while ((p = strsep(&ctrspec, ",")) != NULL) {
3068145256Sjkoshy		if (KWPREFIXMATCH(p, P6_KW_CMASK "=")) {
3069145256Sjkoshy			q = strchr(p, '=');
3070145256Sjkoshy			if (*++q == '\0') /* skip '=' */
3071174406Sjkoshy				return (-1);
3072145256Sjkoshy			count = strtol(q, &e, 0);
3073145256Sjkoshy			if (e == q || *e != '\0')
3074174406Sjkoshy				return (-1);
3075145256Sjkoshy			pmc_config->pm_caps |= PMC_CAP_THRESHOLD;
3076147191Sjkoshy			pmc_config->pm_md.pm_ppro.pm_ppro_config |=
3077147191Sjkoshy			    P6_EVSEL_TO_CMASK(count);
3078145256Sjkoshy		} else if (KWMATCH(p, P6_KW_EDGE)) {
3079145256Sjkoshy			pmc_config->pm_caps |= PMC_CAP_EDGE;
3080145256Sjkoshy		} else if (KWMATCH(p, P6_KW_INV)) {
3081145256Sjkoshy			pmc_config->pm_caps |= PMC_CAP_INVERT;
3082145256Sjkoshy		} else if (KWMATCH(p, P6_KW_OS)) {
3083145256Sjkoshy			pmc_config->pm_caps |= PMC_CAP_SYSTEM;
3084145256Sjkoshy		} else if (KWPREFIXMATCH(p, P6_KW_UMASK "=")) {
3085145256Sjkoshy			evmask = 0;
3086145256Sjkoshy			if ((n = pmc_parse_mask(pmask, p, &evmask)) < 0)
3087174406Sjkoshy				return (-1);
3088145256Sjkoshy			if ((pe == PMC_EV_P6_BUS_DRDY_CLOCKS ||
3089145256Sjkoshy			     pe == PMC_EV_P6_BUS_LOCK_CLOCKS ||
3090145256Sjkoshy			     pe == PMC_EV_P6_BUS_TRAN_BRD ||
3091145256Sjkoshy			     pe == PMC_EV_P6_BUS_TRAN_RFO ||
3092145256Sjkoshy			     pe == PMC_EV_P6_BUS_TRAN_IFETCH ||
3093145256Sjkoshy			     pe == PMC_EV_P6_BUS_TRAN_INVAL ||
3094145256Sjkoshy			     pe == PMC_EV_P6_BUS_TRAN_PWR ||
3095145256Sjkoshy			     pe == PMC_EV_P6_BUS_TRAN_DEF ||
3096145256Sjkoshy			     pe == PMC_EV_P6_BUS_TRAN_BURST ||
3097145256Sjkoshy			     pe == PMC_EV_P6_BUS_TRAN_ANY ||
3098145256Sjkoshy			     pe == PMC_EV_P6_BUS_TRAN_MEM ||
3099145256Sjkoshy			     pe == PMC_EV_P6_BUS_TRANS_IO ||
3100145256Sjkoshy			     pe == PMC_EV_P6_BUS_TRANS_P ||
3101145256Sjkoshy			     pe == PMC_EV_P6_BUS_TRANS_WB ||
3102145256Sjkoshy			     pe == PMC_EV_P6_EMON_EST_TRANS ||
3103145256Sjkoshy			     pe == PMC_EV_P6_EMON_FUSED_UOPS_RET ||
3104145256Sjkoshy			     pe == PMC_EV_P6_EMON_KNI_COMP_INST_RET ||
3105145256Sjkoshy			     pe == PMC_EV_P6_EMON_KNI_INST_RETIRED ||
3106145256Sjkoshy			     pe == PMC_EV_P6_EMON_KNI_PREF_DISPATCHED ||
3107145256Sjkoshy			     pe == PMC_EV_P6_EMON_KNI_PREF_MISS ||
3108145256Sjkoshy			     pe == PMC_EV_P6_EMON_SSE_SSE2_COMP_INST_RETIRED ||
3109145256Sjkoshy			     pe == PMC_EV_P6_EMON_SSE_SSE2_INST_RETIRED ||
3110145256Sjkoshy			     pe == PMC_EV_P6_FP_MMX_TRANS)
3111174406Sjkoshy			    && (n > 1))	/* Only one mask keyword is allowed. */
3112174406Sjkoshy				return (-1);
3113145256Sjkoshy			pmc_config->pm_caps |= PMC_CAP_QUALIFIER;
3114145256Sjkoshy		} else if (KWMATCH(p, P6_KW_USR)) {
3115145256Sjkoshy			pmc_config->pm_caps |= PMC_CAP_USER;
3116145256Sjkoshy		} else
3117174406Sjkoshy			return (-1);
3118145256Sjkoshy	}
3119145256Sjkoshy
3120145256Sjkoshy	/* post processing */
3121145256Sjkoshy	switch (pe) {
3122145256Sjkoshy
3123145256Sjkoshy		/*
3124145256Sjkoshy		 * The following events default to an evmask of 0
3125145256Sjkoshy		 */
3126145256Sjkoshy
3127145256Sjkoshy		/* default => 'self' */
3128145256Sjkoshy	case PMC_EV_P6_BUS_DRDY_CLOCKS:
3129145256Sjkoshy	case PMC_EV_P6_BUS_LOCK_CLOCKS:
3130145256Sjkoshy	case PMC_EV_P6_BUS_TRAN_BRD:
3131145256Sjkoshy	case PMC_EV_P6_BUS_TRAN_RFO:
3132145256Sjkoshy	case PMC_EV_P6_BUS_TRANS_WB:
3133145256Sjkoshy	case PMC_EV_P6_BUS_TRAN_IFETCH:
3134145256Sjkoshy	case PMC_EV_P6_BUS_TRAN_INVAL:
3135145256Sjkoshy	case PMC_EV_P6_BUS_TRAN_PWR:
3136145256Sjkoshy	case PMC_EV_P6_BUS_TRANS_P:
3137145256Sjkoshy	case PMC_EV_P6_BUS_TRANS_IO:
3138145256Sjkoshy	case PMC_EV_P6_BUS_TRAN_DEF:
3139145256Sjkoshy	case PMC_EV_P6_BUS_TRAN_BURST:
3140145256Sjkoshy	case PMC_EV_P6_BUS_TRAN_ANY:
3141145256Sjkoshy	case PMC_EV_P6_BUS_TRAN_MEM:
3142145256Sjkoshy
3143145256Sjkoshy		/* default => 'nta' */
3144145256Sjkoshy	case PMC_EV_P6_EMON_KNI_PREF_DISPATCHED:
3145145256Sjkoshy	case PMC_EV_P6_EMON_KNI_PREF_MISS:
3146145256Sjkoshy
3147145256Sjkoshy		/* default => 'packed and scalar' */
3148145256Sjkoshy	case PMC_EV_P6_EMON_KNI_INST_RETIRED:
3149145256Sjkoshy	case PMC_EV_P6_EMON_KNI_COMP_INST_RET:
3150145256Sjkoshy
3151145256Sjkoshy		/* default => 'mmx to fp transitions' */
3152145256Sjkoshy	case PMC_EV_P6_FP_MMX_TRANS:
3153145256Sjkoshy
3154145256Sjkoshy		/* default => 'SSE Packed Single' */
3155145256Sjkoshy	case PMC_EV_P6_EMON_SSE_SSE2_INST_RETIRED:
3156145256Sjkoshy	case PMC_EV_P6_EMON_SSE_SSE2_COMP_INST_RETIRED:
3157145256Sjkoshy
3158145256Sjkoshy		/* default => 'all fused micro-ops' */
3159145256Sjkoshy	case PMC_EV_P6_EMON_FUSED_UOPS_RET:
3160145256Sjkoshy
3161145256Sjkoshy		/* default => 'all transitions' */
3162145256Sjkoshy	case PMC_EV_P6_EMON_EST_TRANS:
3163145256Sjkoshy		break;
3164145256Sjkoshy
3165145256Sjkoshy	case PMC_EV_P6_MMX_UOPS_EXEC:
3166145256Sjkoshy		evmask = 0x0F;		/* only value allowed */
3167145256Sjkoshy		break;
3168145256Sjkoshy
3169145256Sjkoshy	default:
3170145256Sjkoshy		/*
3171145256Sjkoshy		 * For all other events, set the default event mask
3172145256Sjkoshy		 * to a logical OR of all the allowed event mask bits.
3173145256Sjkoshy		 */
3174145256Sjkoshy		if (evmask == 0 && pmask) {
3175145256Sjkoshy			for (pm = pmask; pm->pm_name; pm++)
3176145256Sjkoshy				evmask |= pm->pm_value;
3177145256Sjkoshy			pmc_config->pm_caps |= PMC_CAP_QUALIFIER;
3178145256Sjkoshy		}
3179145256Sjkoshy
3180145256Sjkoshy		break;
3181145256Sjkoshy	}
3182145256Sjkoshy
3183145256Sjkoshy	if (pmc_config->pm_caps & PMC_CAP_QUALIFIER)
3184147191Sjkoshy		pmc_config->pm_md.pm_ppro.pm_ppro_config |=
3185147191Sjkoshy		    P6_EVSEL_TO_UMASK(evmask);
3186145256Sjkoshy
3187174406Sjkoshy	return (0);
3188145256Sjkoshy}
3189145256Sjkoshy
3190147191Sjkoshy#endif
3191147191Sjkoshy
3192183725Sjkoshy#if	defined(__i386__) || defined(__amd64__)
3193183725Sjkoshystatic int
3194183725Sjkoshytsc_allocate_pmc(enum pmc_event pe, char *ctrspec,
3195183725Sjkoshy    struct pmc_op_pmcallocate *pmc_config)
3196183725Sjkoshy{
3197183725Sjkoshy	if (pe != PMC_EV_TSC_TSC)
3198183725Sjkoshy		return (-1);
3199183725Sjkoshy
3200183725Sjkoshy	/* TSC events must be unqualified. */
3201183725Sjkoshy	if (ctrspec && *ctrspec != '\0')
3202183725Sjkoshy		return (-1);
3203183725Sjkoshy
3204183725Sjkoshy	pmc_config->pm_md.pm_amd.pm_amd_config = 0;
3205183725Sjkoshy	pmc_config->pm_caps |= PMC_CAP_READ;
3206183725Sjkoshy
3207183725Sjkoshy	return (0);
3208183725Sjkoshy}
3209183725Sjkoshy#endif
3210183725Sjkoshy
3211233628Sfabientstatic struct pmc_event_alias generic_aliases[] = {
3212233628Sfabient	EV_ALIAS("instructions",		"SOFT-CLOCK.HARD"),
3213233628Sfabient	EV_ALIAS(NULL, NULL)
3214233628Sfabient};
3215233628Sfabient
3216233628Sfabientstatic int
3217233628Sfabientsoft_allocate_pmc(enum pmc_event pe, char *ctrspec,
3218233628Sfabient    struct pmc_op_pmcallocate *pmc_config)
3219233628Sfabient{
3220233628Sfabient	(void)ctrspec;
3221233628Sfabient	(void)pmc_config;
3222233628Sfabient
3223242622Sdim	if ((int)pe < PMC_EV_SOFT_FIRST || (int)pe > PMC_EV_SOFT_LAST)
3224233628Sfabient		return (-1);
3225233628Sfabient
3226233628Sfabient	pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE);
3227233628Sfabient	return (0);
3228233628Sfabient}
3229233628Sfabient
3230277835Sbr#if	defined(__arm__)
3231200928Srpaulo#if	defined(__XSCALE__)
3232200928Srpaulo
3233200928Srpaulostatic struct pmc_event_alias xscale_aliases[] = {
3234200928Srpaulo	EV_ALIAS("branches",		"BRANCH_RETIRED"),
3235200928Srpaulo	EV_ALIAS("branch-mispredicts",	"BRANCH_MISPRED"),
3236200928Srpaulo	EV_ALIAS("dc-misses",		"DC_MISS"),
3237200928Srpaulo	EV_ALIAS("ic-misses",		"IC_MISS"),
3238200928Srpaulo	EV_ALIAS("instructions",	"INSTR_RETIRED"),
3239200928Srpaulo	EV_ALIAS(NULL, NULL)
3240200928Srpaulo};
3241200928Srpaulostatic int
3242200928Srpauloxscale_allocate_pmc(enum pmc_event pe, char *ctrspec __unused,
3243200928Srpaulo    struct pmc_op_pmcallocate *pmc_config __unused)
3244200928Srpaulo{
3245200928Srpaulo	switch (pe) {
3246200928Srpaulo	default:
3247200928Srpaulo		break;
3248200928Srpaulo	}
3249200928Srpaulo
3250200928Srpaulo	return (0);
3251200928Srpaulo}
3252200928Srpaulo#endif
3253200928Srpaulo
3254284218Sbrstatic struct pmc_event_alias cortex_a8_aliases[] = {
3255277835Sbr	EV_ALIAS("dc-misses",		"L1_DCACHE_REFILL"),
3256277835Sbr	EV_ALIAS("ic-misses",		"L1_ICACHE_REFILL"),
3257277835Sbr	EV_ALIAS("instructions",	"INSTR_EXECUTED"),
3258277835Sbr	EV_ALIAS(NULL, NULL)
3259277835Sbr};
3260284218Sbr
3261284218Sbrstatic struct pmc_event_alias cortex_a9_aliases[] = {
3262284218Sbr	EV_ALIAS("dc-misses",		"L1_DCACHE_REFILL"),
3263284218Sbr	EV_ALIAS("ic-misses",		"L1_ICACHE_REFILL"),
3264284218Sbr	EV_ALIAS("instructions",	"INSTR_EXECUTED"),
3265284218Sbr	EV_ALIAS(NULL, NULL)
3266284218Sbr};
3267284218Sbr
3268277835Sbrstatic int
3269277835Sbrarmv7_allocate_pmc(enum pmc_event pe, char *ctrspec __unused,
3270277835Sbr    struct pmc_op_pmcallocate *pmc_config __unused)
3271277835Sbr{
3272277835Sbr	switch (pe) {
3273277835Sbr	default:
3274277835Sbr		break;
3275277835Sbr	}
3276277835Sbr
3277277835Sbr	return (0);
3278277835Sbr}
3279277835Sbr#endif
3280277835Sbr
3281283112Sbr#if	defined(__aarch64__)
3282283112Sbrstatic struct pmc_event_alias cortex_a53_aliases[] = {
3283283112Sbr	EV_ALIAS(NULL, NULL)
3284283112Sbr};
3285283112Sbrstatic struct pmc_event_alias cortex_a57_aliases[] = {
3286283112Sbr	EV_ALIAS(NULL, NULL)
3287283112Sbr};
3288283112Sbrstatic int
3289283112Sbrarm64_allocate_pmc(enum pmc_event pe, char *ctrspec __unused,
3290283112Sbr    struct pmc_op_pmcallocate *pmc_config __unused)
3291283112Sbr{
3292283112Sbr	switch (pe) {
3293283112Sbr	default:
3294283112Sbr		break;
3295283112Sbr	}
3296283112Sbr
3297283112Sbr	return (0);
3298283112Sbr}
3299283112Sbr#endif
3300283112Sbr
3301204635Sgnn#if defined(__mips__)
3302204635Sgnn
3303204635Sgnnstatic struct pmc_event_alias mips24k_aliases[] = {
3304204635Sgnn	EV_ALIAS("instructions",	"INSTR_EXECUTED"),
3305204635Sgnn	EV_ALIAS("branches",		"BRANCH_COMPLETED"),
3306204635Sgnn	EV_ALIAS("branch-mispredicts",	"BRANCH_MISPRED"),
3307204635Sgnn	EV_ALIAS(NULL, NULL)
3308204635Sgnn};
3309204635Sgnn
3310281098Sadrianstatic struct pmc_event_alias mips74k_aliases[] = {
3311281098Sadrian	EV_ALIAS("instructions",	"INSTR_EXECUTED"),
3312281098Sadrian	EV_ALIAS("branches",		"BRANCH_INSNS"),
3313281098Sadrian	EV_ALIAS("branch-mispredicts",	"MISPREDICTED_BRANCH_INSNS"),
3314281098Sadrian	EV_ALIAS(NULL, NULL)
3315281098Sadrian};
3316281098Sadrian
3317233335Sgonzostatic struct pmc_event_alias octeon_aliases[] = {
3318233335Sgonzo	EV_ALIAS("instructions",	"RET"),
3319233335Sgonzo	EV_ALIAS("branches",		"BR"),
3320233335Sgonzo	EV_ALIAS("branch-mispredicts",	"BRMIS"),
3321233335Sgonzo	EV_ALIAS(NULL, NULL)
3322233335Sgonzo};
3323233335Sgonzo
3324233320Sgonzo#define	MIPS_KW_OS		"os"
3325233320Sgonzo#define	MIPS_KW_USR		"usr"
3326233320Sgonzo#define	MIPS_KW_ANYTHREAD	"anythread"
3327204635Sgnn
3328204635Sgnnstatic int
3329233320Sgonzomips_allocate_pmc(enum pmc_event pe, char *ctrspec __unused,
3330204635Sgnn		  struct pmc_op_pmcallocate *pmc_config __unused)
3331204635Sgnn{
3332204635Sgnn	char *p;
3333204635Sgnn
3334204635Sgnn	(void) pe;
3335204635Sgnn
3336204635Sgnn	pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE);
3337204635Sgnn
3338204635Sgnn	while ((p = strsep(&ctrspec, ",")) != NULL) {
3339233320Sgonzo		if (KWMATCH(p, MIPS_KW_OS))
3340204635Sgnn			pmc_config->pm_caps |= PMC_CAP_SYSTEM;
3341233320Sgonzo		else if (KWMATCH(p, MIPS_KW_USR))
3342204635Sgnn			pmc_config->pm_caps |= PMC_CAP_USER;
3343233320Sgonzo		else if (KWMATCH(p, MIPS_KW_ANYTHREAD))
3344204635Sgnn			pmc_config->pm_caps |= (PMC_CAP_USER | PMC_CAP_SYSTEM);
3345204635Sgnn		else
3346204635Sgnn			return (-1);
3347204635Sgnn	}
3348204635Sgnn
3349204635Sgnn	return (0);
3350204635Sgnn}
3351233320Sgonzo
3352204635Sgnn#endif /* __mips__ */
3353204635Sgnn
3354228869Sjhibbits#if defined(__powerpc__)
3355204635Sgnn
3356228869Sjhibbitsstatic struct pmc_event_alias ppc7450_aliases[] = {
3357228869Sjhibbits	EV_ALIAS("instructions",	"INSTR_COMPLETED"),
3358228869Sjhibbits	EV_ALIAS("branches",		"BRANCHES_COMPLETED"),
3359228869Sjhibbits	EV_ALIAS("branch-mispredicts",	"MISPREDICTED_BRANCHES"),
3360228869Sjhibbits	EV_ALIAS(NULL, NULL)
3361228869Sjhibbits};
3362228869Sjhibbits
3363261342Sjhibbitsstatic struct pmc_event_alias ppc970_aliases[] = {
3364261342Sjhibbits	EV_ALIAS("instructions", "INSTR_COMPLETED"),
3365261342Sjhibbits	EV_ALIAS("cycles",       "CYCLES"),
3366261342Sjhibbits	EV_ALIAS(NULL, NULL)
3367261342Sjhibbits};
3368228869Sjhibbits
3369281713Sjhibbitsstatic struct pmc_event_alias e500_aliases[] = {
3370281713Sjhibbits	EV_ALIAS("instructions", "INSTR_COMPLETED"),
3371281713Sjhibbits	EV_ALIAS("cycles",       "CYCLES"),
3372281713Sjhibbits	EV_ALIAS(NULL, NULL)
3373281713Sjhibbits};
3374281713Sjhibbits
3375261342Sjhibbits#define	POWERPC_KW_OS		"os"
3376261342Sjhibbits#define	POWERPC_KW_USR		"usr"
3377261342Sjhibbits#define	POWERPC_KW_ANYTHREAD	"anythread"
3378261342Sjhibbits
3379228869Sjhibbitsstatic int
3380261342Sjhibbitspowerpc_allocate_pmc(enum pmc_event pe, char *ctrspec __unused,
3381261342Sjhibbits		     struct pmc_op_pmcallocate *pmc_config __unused)
3382228869Sjhibbits{
3383228869Sjhibbits	char *p;
3384228869Sjhibbits
3385228869Sjhibbits	(void) pe;
3386228869Sjhibbits
3387228869Sjhibbits	pmc_config->pm_caps |= (PMC_CAP_READ | PMC_CAP_WRITE);
3388228869Sjhibbits
3389228869Sjhibbits	while ((p = strsep(&ctrspec, ",")) != NULL) {
3390261342Sjhibbits		if (KWMATCH(p, POWERPC_KW_OS))
3391228869Sjhibbits			pmc_config->pm_caps |= PMC_CAP_SYSTEM;
3392261342Sjhibbits		else if (KWMATCH(p, POWERPC_KW_USR))
3393228869Sjhibbits			pmc_config->pm_caps |= PMC_CAP_USER;
3394261342Sjhibbits		else if (KWMATCH(p, POWERPC_KW_ANYTHREAD))
3395228869Sjhibbits			pmc_config->pm_caps |= (PMC_CAP_USER | PMC_CAP_SYSTEM);
3396228869Sjhibbits		else
3397228869Sjhibbits			return (-1);
3398228869Sjhibbits	}
3399228869Sjhibbits
3400228869Sjhibbits	return (0);
3401228869Sjhibbits}
3402261342Sjhibbits
3403228869Sjhibbits#endif /* __powerpc__ */
3404228869Sjhibbits
3405228869Sjhibbits
3406145256Sjkoshy/*
3407183725Sjkoshy * Match an event name `name' with its canonical form.
3408183725Sjkoshy *
3409185363Sjkoshy * Matches are case insensitive and spaces, periods, underscores and
3410185363Sjkoshy * hyphen characters are considered to match each other.
3411185363Sjkoshy *
3412183725Sjkoshy * Returns 1 for a match, 0 otherwise.
3413183725Sjkoshy */
3414183725Sjkoshy
3415183725Sjkoshystatic int
3416183725Sjkoshypmc_match_event_name(const char *name, const char *canonicalname)
3417183725Sjkoshy{
3418183725Sjkoshy	int cc, nc;
3419183725Sjkoshy	const unsigned char *c, *n;
3420183725Sjkoshy
3421183725Sjkoshy	c = (const unsigned char *) canonicalname;
3422183725Sjkoshy	n = (const unsigned char *) name;
3423183725Sjkoshy
3424183725Sjkoshy	for (; (nc = *n) && (cc = *c); n++, c++) {
3425183725Sjkoshy
3426185363Sjkoshy		if ((nc == ' ' || nc == '_' || nc == '-' || nc == '.') &&
3427185363Sjkoshy		    (cc == ' ' || cc == '_' || cc == '-' || cc == '.'))
3428183725Sjkoshy			continue;
3429183725Sjkoshy
3430185363Sjkoshy		if (toupper(nc) == toupper(cc))
3431183725Sjkoshy			continue;
3432183725Sjkoshy
3433185363Sjkoshy
3434183725Sjkoshy		return (0);
3435183725Sjkoshy	}
3436183725Sjkoshy
3437183725Sjkoshy	if (*n == '\0' && *c == '\0')
3438183725Sjkoshy		return (1);
3439183725Sjkoshy
3440183725Sjkoshy	return (0);
3441183725Sjkoshy}
3442183725Sjkoshy
3443183725Sjkoshy/*
3444183725Sjkoshy * Match an event name against all the event named supported by a
3445183725Sjkoshy * PMC class.
3446183725Sjkoshy *
3447183725Sjkoshy * Returns an event descriptor pointer on match or NULL otherwise.
3448183725Sjkoshy */
3449183725Sjkoshystatic const struct pmc_event_descr *
3450183725Sjkoshypmc_match_event_class(const char *name,
3451183725Sjkoshy    const struct pmc_class_descr *pcd)
3452183725Sjkoshy{
3453183725Sjkoshy	size_t n;
3454183725Sjkoshy	const struct pmc_event_descr *ev;
3455185363Sjkoshy
3456183725Sjkoshy	ev = pcd->pm_evc_event_table;
3457183725Sjkoshy	for (n = 0; n < pcd->pm_evc_event_table_size; n++, ev++)
3458183725Sjkoshy		if (pmc_match_event_name(name, ev->pm_ev_name))
3459183725Sjkoshy			return (ev);
3460183725Sjkoshy
3461183725Sjkoshy	return (NULL);
3462183725Sjkoshy}
3463183725Sjkoshy
3464183725Sjkoshystatic int
3465183725Sjkoshypmc_mdep_is_compatible_class(enum pmc_class pc)
3466183725Sjkoshy{
3467183725Sjkoshy	size_t n;
3468183725Sjkoshy
3469183725Sjkoshy	for (n = 0; n < pmc_mdep_class_list_size; n++)
3470183725Sjkoshy		if (pmc_mdep_class_list[n] == pc)
3471183725Sjkoshy			return (1);
3472183725Sjkoshy	return (0);
3473183725Sjkoshy}
3474183725Sjkoshy
3475183725Sjkoshy/*
3476147191Sjkoshy * API entry points
3477145256Sjkoshy */
3478145256Sjkoshy
3479147191Sjkoshyint
3480147191Sjkoshypmc_allocate(const char *ctrspec, enum pmc_mode mode,
3481147191Sjkoshy    uint32_t flags, int cpu, pmc_id_t *pmcid)
3482145256Sjkoshy{
3483183725Sjkoshy	size_t n;
3484147191Sjkoshy	int retval;
3485147191Sjkoshy	char *r, *spec_copy;
3486147191Sjkoshy	const char *ctrname;
3487183725Sjkoshy	const struct pmc_event_descr *ev;
3488183725Sjkoshy	const struct pmc_event_alias *alias;
3489147191Sjkoshy	struct pmc_op_pmcallocate pmc_config;
3490183725Sjkoshy	const struct pmc_class_descr *pcd;
3491145256Sjkoshy
3492147191Sjkoshy	spec_copy = NULL;
3493147191Sjkoshy	retval    = -1;
3494145256Sjkoshy
3495147191Sjkoshy	if (mode != PMC_MODE_SS && mode != PMC_MODE_TS &&
3496147191Sjkoshy	    mode != PMC_MODE_SC && mode != PMC_MODE_TC) {
3497147191Sjkoshy		errno = EINVAL;
3498147191Sjkoshy		goto out;
3499147191Sjkoshy	}
3500145256Sjkoshy
3501147191Sjkoshy	/* replace an event alias with the canonical event specifier */
3502147191Sjkoshy	if (pmc_mdep_event_aliases)
3503183725Sjkoshy		for (alias = pmc_mdep_event_aliases; alias->pm_alias; alias++)
3504183725Sjkoshy			if (!strcasecmp(ctrspec, alias->pm_alias)) {
3505183725Sjkoshy				spec_copy = strdup(alias->pm_spec);
3506147191Sjkoshy				break;
3507147191Sjkoshy			}
3508145256Sjkoshy
3509147191Sjkoshy	if (spec_copy == NULL)
3510147191Sjkoshy		spec_copy = strdup(ctrspec);
3511145256Sjkoshy
3512147191Sjkoshy	r = spec_copy;
3513147191Sjkoshy	ctrname = strsep(&r, ",");
3514145256Sjkoshy
3515183725Sjkoshy	/*
3516183725Sjkoshy	 * If a explicit class prefix was given by the user, restrict the
3517183725Sjkoshy	 * search for the event to the specified PMC class.
3518183725Sjkoshy	 */
3519183725Sjkoshy	ev = NULL;
3520185363Sjkoshy	for (n = 0; n < PMC_CLASS_TABLE_SIZE; n++) {
3521185363Sjkoshy		pcd = pmc_class_table[n];
3522183725Sjkoshy		if (pmc_mdep_is_compatible_class(pcd->pm_evc_class) &&
3523183725Sjkoshy		    strncasecmp(ctrname, pcd->pm_evc_name,
3524183725Sjkoshy				pcd->pm_evc_name_size) == 0) {
3525183725Sjkoshy			if ((ev = pmc_match_event_class(ctrname +
3526183725Sjkoshy			    pcd->pm_evc_name_size, pcd)) == NULL) {
3527183725Sjkoshy				errno = EINVAL;
3528183725Sjkoshy				goto out;
3529183725Sjkoshy			}
3530147191Sjkoshy			break;
3531183725Sjkoshy		}
3532183725Sjkoshy	}
3533145256Sjkoshy
3534183725Sjkoshy	/*
3535183725Sjkoshy	 * Otherwise, search for this event in all compatible PMC
3536183725Sjkoshy	 * classes.
3537183725Sjkoshy	 */
3538185363Sjkoshy	for (n = 0; ev == NULL && n < PMC_CLASS_TABLE_SIZE; n++) {
3539185363Sjkoshy		pcd = pmc_class_table[n];
3540183725Sjkoshy		if (pmc_mdep_is_compatible_class(pcd->pm_evc_class))
3541183725Sjkoshy			ev = pmc_match_event_class(ctrname, pcd);
3542183725Sjkoshy	}
3543183725Sjkoshy
3544183725Sjkoshy	if (ev == NULL) {
3545147191Sjkoshy		errno = EINVAL;
3546147191Sjkoshy		goto out;
3547147191Sjkoshy	}
3548145256Sjkoshy
3549147191Sjkoshy	bzero(&pmc_config, sizeof(pmc_config));
3550183725Sjkoshy	pmc_config.pm_ev    = ev->pm_ev_code;
3551183725Sjkoshy	pmc_config.pm_class = pcd->pm_evc_class;
3552147191Sjkoshy	pmc_config.pm_cpu   = cpu;
3553147191Sjkoshy	pmc_config.pm_mode  = mode;
3554147191Sjkoshy	pmc_config.pm_flags = flags;
3555145256Sjkoshy
3556147191Sjkoshy	if (PMC_IS_SAMPLING_MODE(mode))
3557147191Sjkoshy		pmc_config.pm_caps |= PMC_CAP_INTERRUPT;
3558145256Sjkoshy
3559183725Sjkoshy 	if (pcd->pm_evc_allocate_pmc(ev->pm_ev_code, r, &pmc_config) < 0) {
3560147191Sjkoshy		errno = EINVAL;
3561147191Sjkoshy		goto out;
3562147191Sjkoshy	}
3563145256Sjkoshy
3564147191Sjkoshy	if (PMC_CALL(PMCALLOCATE, &pmc_config) < 0)
3565147191Sjkoshy		goto out;
3566145256Sjkoshy
3567147191Sjkoshy	*pmcid = pmc_config.pm_pmcid;
3568145256Sjkoshy
3569147191Sjkoshy	retval = 0;
3570145256Sjkoshy
3571147191Sjkoshy out:
3572147191Sjkoshy	if (spec_copy)
3573147191Sjkoshy		free(spec_copy);
3574145256Sjkoshy
3575174406Sjkoshy	return (retval);
3576147191Sjkoshy}
3577145256Sjkoshy
3578147191Sjkoshyint
3579147191Sjkoshypmc_attach(pmc_id_t pmc, pid_t pid)
3580147191Sjkoshy{
3581147191Sjkoshy	struct pmc_op_pmcattach pmc_attach_args;
3582145256Sjkoshy
3583147191Sjkoshy	pmc_attach_args.pm_pmc = pmc;
3584147191Sjkoshy	pmc_attach_args.pm_pid = pid;
3585145256Sjkoshy
3586174406Sjkoshy	return (PMC_CALL(PMCATTACH, &pmc_attach_args));
3587147191Sjkoshy}
3588145256Sjkoshy
3589147191Sjkoshyint
3590147191Sjkoshypmc_capabilities(pmc_id_t pmcid, uint32_t *caps)
3591147191Sjkoshy{
3592147191Sjkoshy	unsigned int i;
3593147191Sjkoshy	enum pmc_class cl;
3594145256Sjkoshy
3595147191Sjkoshy	cl = PMC_ID_TO_CLASS(pmcid);
3596147191Sjkoshy	for (i = 0; i < cpu_info.pm_nclass; i++)
3597147191Sjkoshy		if (cpu_info.pm_classes[i].pm_class == cl) {
3598147191Sjkoshy			*caps = cpu_info.pm_classes[i].pm_caps;
3599174406Sjkoshy			return (0);
3600147191Sjkoshy		}
3601177107Sjkoshy	errno = EINVAL;
3602177107Sjkoshy	return (-1);
3603147191Sjkoshy}
3604145256Sjkoshy
3605147191Sjkoshyint
3606147191Sjkoshypmc_configure_logfile(int fd)
3607147191Sjkoshy{
3608147191Sjkoshy	struct pmc_op_configurelog cla;
3609145256Sjkoshy
3610147191Sjkoshy	cla.pm_logfd = fd;
3611147191Sjkoshy	if (PMC_CALL(CONFIGURELOG, &cla) < 0)
3612174406Sjkoshy		return (-1);
3613174406Sjkoshy	return (0);
3614147191Sjkoshy}
3615145256Sjkoshy
3616147191Sjkoshyint
3617147191Sjkoshypmc_cpuinfo(const struct pmc_cpuinfo **pci)
3618147191Sjkoshy{
3619147191Sjkoshy	if (pmc_syscall == -1) {
3620147191Sjkoshy		errno = ENXIO;
3621174406Sjkoshy		return (-1);
3622147191Sjkoshy	}
3623145256Sjkoshy
3624147219Sjkoshy	*pci = &cpu_info;
3625174406Sjkoshy	return (0);
3626147191Sjkoshy}
3627145256Sjkoshy
3628147191Sjkoshyint
3629147191Sjkoshypmc_detach(pmc_id_t pmc, pid_t pid)
3630147191Sjkoshy{
3631147191Sjkoshy	struct pmc_op_pmcattach pmc_detach_args;
3632145256Sjkoshy
3633147191Sjkoshy	pmc_detach_args.pm_pmc = pmc;
3634147191Sjkoshy	pmc_detach_args.pm_pid = pid;
3635174406Sjkoshy	return (PMC_CALL(PMCDETACH, &pmc_detach_args));
3636147191Sjkoshy}
3637147191Sjkoshy
3638147191Sjkoshyint
3639147191Sjkoshypmc_disable(int cpu, int pmc)
3640145256Sjkoshy{
3641147191Sjkoshy	struct pmc_op_pmcadmin ssa;
3642145256Sjkoshy
3643147191Sjkoshy	ssa.pm_cpu = cpu;
3644147191Sjkoshy	ssa.pm_pmc = pmc;
3645147191Sjkoshy	ssa.pm_state = PMC_STATE_DISABLED;
3646174406Sjkoshy	return (PMC_CALL(PMCADMIN, &ssa));
3647147191Sjkoshy}
3648145256Sjkoshy
3649147191Sjkoshyint
3650147191Sjkoshypmc_enable(int cpu, int pmc)
3651147191Sjkoshy{
3652147191Sjkoshy	struct pmc_op_pmcadmin ssa;
3653145256Sjkoshy
3654147191Sjkoshy	ssa.pm_cpu = cpu;
3655147191Sjkoshy	ssa.pm_pmc = pmc;
3656147191Sjkoshy	ssa.pm_state = PMC_STATE_FREE;
3657174406Sjkoshy	return (PMC_CALL(PMCADMIN, &ssa));
3658147191Sjkoshy}
3659145256Sjkoshy
3660147191Sjkoshy/*
3661147191Sjkoshy * Return a list of events known to a given PMC class.  'cl' is the
3662147191Sjkoshy * PMC class identifier, 'eventnames' is the returned list of 'const
3663147191Sjkoshy * char *' pointers pointing to the names of the events. 'nevents' is
3664147191Sjkoshy * the number of event name pointers returned.
3665147191Sjkoshy *
3666147191Sjkoshy * The space for 'eventnames' is allocated using malloc(3).  The caller
3667147191Sjkoshy * is responsible for freeing this space when done.
3668147191Sjkoshy */
3669147191Sjkoshyint
3670147191Sjkoshypmc_event_names_of_class(enum pmc_class cl, const char ***eventnames,
3671147191Sjkoshy    int *nevents)
3672147191Sjkoshy{
3673147191Sjkoshy	int count;
3674147191Sjkoshy	const char **names;
3675147191Sjkoshy	const struct pmc_event_descr *ev;
3676147191Sjkoshy
3677147191Sjkoshy	switch (cl)
3678147191Sjkoshy	{
3679185363Sjkoshy	case PMC_CLASS_IAF:
3680185363Sjkoshy		ev = iaf_event_table;
3681185363Sjkoshy		count = PMC_EVENT_TABLE_SIZE(iaf);
3682185363Sjkoshy		break;
3683185363Sjkoshy	case PMC_CLASS_IAP:
3684185363Sjkoshy		/*
3685185363Sjkoshy		 * Return the most appropriate set of event name
3686185363Sjkoshy		 * spellings for the current CPU.
3687185363Sjkoshy		 */
3688185363Sjkoshy		switch (cpu_info.pm_cputype) {
3689185363Sjkoshy		default:
3690185363Sjkoshy		case PMC_CPU_INTEL_ATOM:
3691185363Sjkoshy			ev = atom_event_table;
3692185363Sjkoshy			count = PMC_EVENT_TABLE_SIZE(atom);
3693185363Sjkoshy			break;
3694263446Shiren		case PMC_CPU_INTEL_ATOM_SILVERMONT:
3695263446Shiren			ev = atom_silvermont_event_table;
3696263446Shiren			count = PMC_EVENT_TABLE_SIZE(atom_silvermont);
3697263446Shiren			break;
3698185363Sjkoshy		case PMC_CPU_INTEL_CORE:
3699185363Sjkoshy			ev = core_event_table;
3700185363Sjkoshy			count = PMC_EVENT_TABLE_SIZE(core);
3701185363Sjkoshy			break;
3702185363Sjkoshy		case PMC_CPU_INTEL_CORE2:
3703185585Sjkoshy		case PMC_CPU_INTEL_CORE2EXTREME:
3704185363Sjkoshy			ev = core2_event_table;
3705185363Sjkoshy			count = PMC_EVENT_TABLE_SIZE(core2);
3706185363Sjkoshy			break;
3707187761Sjeff		case PMC_CPU_INTEL_COREI7:
3708187761Sjeff			ev = corei7_event_table;
3709187761Sjeff			count = PMC_EVENT_TABLE_SIZE(corei7);
3710187761Sjeff			break;
3711267062Skib		case PMC_CPU_INTEL_NEHALEM_EX:
3712267062Skib			ev = nehalem_ex_event_table;
3713267062Skib			count = PMC_EVENT_TABLE_SIZE(nehalem_ex);
3714267062Skib			break;
3715248842Ssbruno		case PMC_CPU_INTEL_HASWELL:
3716248842Ssbruno			ev = haswell_event_table;
3717248842Ssbruno			count = PMC_EVENT_TABLE_SIZE(haswell);
3718248842Ssbruno			break;
3719277177Srrs		case PMC_CPU_INTEL_HASWELL_XEON:
3720277177Srrs			ev = haswell_xeon_event_table;
3721277177Srrs			count = PMC_EVENT_TABLE_SIZE(haswell_xeon);
3722277177Srrs			break;
3723291494Srrs		case PMC_CPU_INTEL_BROADWELL:
3724291494Srrs			ev = broadwell_event_table;
3725291494Srrs			count = PMC_EVENT_TABLE_SIZE(broadwell);
3726291494Srrs			break;
3727291494Srrs		case PMC_CPU_INTEL_BROADWELL_XEON:
3728291494Srrs			ev = broadwell_xeon_event_table;
3729291494Srrs			count = PMC_EVENT_TABLE_SIZE(broadwell_xeon);
3730291494Srrs			break;
3731291494Srrs		case PMC_CPU_INTEL_SKYLAKE:
3732291494Srrs			ev = skylake_event_table;
3733291494Srrs			count = PMC_EVENT_TABLE_SIZE(skylake);
3734291494Srrs			break;
3735323799Skib		case PMC_CPU_INTEL_SKYLAKE_XEON:
3736323799Skib			ev = skylake_xeon_event_table;
3737323799Skib			count = PMC_EVENT_TABLE_SIZE(skylake_xeon);
3738323799Skib			break;
3739240164Sfabient		case PMC_CPU_INTEL_IVYBRIDGE:
3740240164Sfabient			ev = ivybridge_event_table;
3741240164Sfabient			count = PMC_EVENT_TABLE_SIZE(ivybridge);
3742240164Sfabient			break;
3743246166Ssbruno		case PMC_CPU_INTEL_IVYBRIDGE_XEON:
3744246166Ssbruno			ev = ivybridge_xeon_event_table;
3745246166Ssbruno			count = PMC_EVENT_TABLE_SIZE(ivybridge_xeon);
3746246166Ssbruno			break;
3747232366Sdavide		case PMC_CPU_INTEL_SANDYBRIDGE:
3748232366Sdavide			ev = sandybridge_event_table;
3749232366Sdavide			count = PMC_EVENT_TABLE_SIZE(sandybridge);
3750232366Sdavide			break;
3751241738Ssbruno		case PMC_CPU_INTEL_SANDYBRIDGE_XEON:
3752241738Ssbruno			ev = sandybridge_xeon_event_table;
3753241738Ssbruno			count = PMC_EVENT_TABLE_SIZE(sandybridge_xeon);
3754241738Ssbruno			break;
3755206089Sfabient		case PMC_CPU_INTEL_WESTMERE:
3756206089Sfabient			ev = westmere_event_table;
3757206089Sfabient			count = PMC_EVENT_TABLE_SIZE(westmere);
3758206089Sfabient			break;
3759267062Skib		case PMC_CPU_INTEL_WESTMERE_EX:
3760267062Skib			ev = westmere_ex_event_table;
3761267062Skib			count = PMC_EVENT_TABLE_SIZE(westmere_ex);
3762267062Skib			break;
3763185363Sjkoshy		}
3764185363Sjkoshy		break;
3765206089Sfabient	case PMC_CLASS_UCF:
3766206089Sfabient		ev = ucf_event_table;
3767206089Sfabient		count = PMC_EVENT_TABLE_SIZE(ucf);
3768206089Sfabient		break;
3769206089Sfabient	case PMC_CLASS_UCP:
3770206089Sfabient		/*
3771206089Sfabient		 * Return the most appropriate set of event name
3772206089Sfabient		 * spellings for the current CPU.
3773206089Sfabient		 */
3774206089Sfabient		switch (cpu_info.pm_cputype) {
3775206089Sfabient		default:
3776206089Sfabient		case PMC_CPU_INTEL_COREI7:
3777206089Sfabient			ev = corei7uc_event_table;
3778206089Sfabient			count = PMC_EVENT_TABLE_SIZE(corei7uc);
3779206089Sfabient			break;
3780248842Ssbruno		case PMC_CPU_INTEL_HASWELL:
3781248842Ssbruno			ev = haswelluc_event_table;
3782248842Ssbruno			count = PMC_EVENT_TABLE_SIZE(haswelluc);
3783248842Ssbruno			break;
3784291494Srrs		case PMC_CPU_INTEL_BROADWELL:
3785291494Srrs			ev = broadwelluc_event_table;
3786291494Srrs			count = PMC_EVENT_TABLE_SIZE(broadwelluc);
3787291494Srrs			break;
3788232366Sdavide		case PMC_CPU_INTEL_SANDYBRIDGE:
3789232366Sdavide			ev = sandybridgeuc_event_table;
3790232366Sdavide			count = PMC_EVENT_TABLE_SIZE(sandybridgeuc);
3791232366Sdavide			break;
3792206089Sfabient		case PMC_CPU_INTEL_WESTMERE:
3793206089Sfabient			ev = westmereuc_event_table;
3794206089Sfabient			count = PMC_EVENT_TABLE_SIZE(westmereuc);
3795206089Sfabient			break;
3796206089Sfabient		}
3797206089Sfabient		break;
3798147191Sjkoshy	case PMC_CLASS_TSC:
3799183725Sjkoshy		ev = tsc_event_table;
3800183725Sjkoshy		count = PMC_EVENT_TABLE_SIZE(tsc);
3801145256Sjkoshy		break;
3802147191Sjkoshy	case PMC_CLASS_K7:
3803183725Sjkoshy		ev = k7_event_table;
3804183725Sjkoshy		count = PMC_EVENT_TABLE_SIZE(k7);
3805145256Sjkoshy		break;
3806147191Sjkoshy	case PMC_CLASS_K8:
3807183725Sjkoshy		ev = k8_event_table;
3808183725Sjkoshy		count = PMC_EVENT_TABLE_SIZE(k8);
3809145256Sjkoshy		break;
3810339767Smmacy	case PMC_CLASS_F17H:
3811339767Smmacy		ev = f17h_event_table;
3812339767Smmacy		count = PMC_EVENT_TABLE_SIZE(f17h);
3813339767Smmacy		break;
3814183725Sjkoshy	case PMC_CLASS_P4:
3815183725Sjkoshy		ev = p4_event_table;
3816183725Sjkoshy		count = PMC_EVENT_TABLE_SIZE(p4);
3817183725Sjkoshy		break;
3818147191Sjkoshy	case PMC_CLASS_P5:
3819183725Sjkoshy		ev = p5_event_table;
3820183725Sjkoshy		count = PMC_EVENT_TABLE_SIZE(p5);
3821145256Sjkoshy		break;
3822147191Sjkoshy	case PMC_CLASS_P6:
3823183725Sjkoshy		ev = p6_event_table;
3824183725Sjkoshy		count = PMC_EVENT_TABLE_SIZE(p6);
3825145256Sjkoshy		break;
3826200928Srpaulo	case PMC_CLASS_XSCALE:
3827200928Srpaulo		ev = xscale_event_table;
3828200928Srpaulo		count = PMC_EVENT_TABLE_SIZE(xscale);
3829200928Srpaulo		break;
3830277835Sbr	case PMC_CLASS_ARMV7:
3831284218Sbr		switch (cpu_info.pm_cputype) {
3832284218Sbr		default:
3833284218Sbr		case PMC_CPU_ARMV7_CORTEX_A8:
3834284218Sbr			ev = cortex_a8_event_table;
3835284218Sbr			count = PMC_EVENT_TABLE_SIZE(cortex_a8);
3836284218Sbr			break;
3837284218Sbr		case PMC_CPU_ARMV7_CORTEX_A9:
3838284218Sbr			ev = cortex_a9_event_table;
3839284218Sbr			count = PMC_EVENT_TABLE_SIZE(cortex_a9);
3840284218Sbr			break;
3841284218Sbr		}
3842277835Sbr		break;
3843283112Sbr	case PMC_CLASS_ARMV8:
3844283112Sbr		switch (cpu_info.pm_cputype) {
3845283112Sbr		default:
3846283112Sbr		case PMC_CPU_ARMV8_CORTEX_A53:
3847283112Sbr			ev = cortex_a53_event_table;
3848283112Sbr			count = PMC_EVENT_TABLE_SIZE(cortex_a53);
3849283112Sbr			break;
3850283112Sbr		case PMC_CPU_ARMV8_CORTEX_A57:
3851283112Sbr			ev = cortex_a57_event_table;
3852283112Sbr			count = PMC_EVENT_TABLE_SIZE(cortex_a57);
3853283112Sbr			break;
3854283112Sbr		}
3855283112Sbr		break;
3856204635Sgnn	case PMC_CLASS_MIPS24K:
3857204635Sgnn		ev = mips24k_event_table;
3858204635Sgnn		count = PMC_EVENT_TABLE_SIZE(mips24k);
3859204635Sgnn		break;
3860281098Sadrian	case PMC_CLASS_MIPS74K:
3861281098Sadrian		ev = mips74k_event_table;
3862281098Sadrian		count = PMC_EVENT_TABLE_SIZE(mips74k);
3863281098Sadrian		break;
3864233335Sgonzo	case PMC_CLASS_OCTEON:
3865233335Sgonzo		ev = octeon_event_table;
3866233335Sgonzo		count = PMC_EVENT_TABLE_SIZE(octeon);
3867233335Sgonzo		break;
3868228869Sjhibbits	case PMC_CLASS_PPC7450:
3869228869Sjhibbits		ev = ppc7450_event_table;
3870228869Sjhibbits		count = PMC_EVENT_TABLE_SIZE(ppc7450);
3871228869Sjhibbits		break;
3872261342Sjhibbits	case PMC_CLASS_PPC970:
3873261342Sjhibbits		ev = ppc970_event_table;
3874261342Sjhibbits		count = PMC_EVENT_TABLE_SIZE(ppc970);
3875261342Sjhibbits		break;
3876281713Sjhibbits	case PMC_CLASS_E500:
3877281713Sjhibbits		ev = e500_event_table;
3878281713Sjhibbits		count = PMC_EVENT_TABLE_SIZE(e500);
3879281713Sjhibbits		break;
3880233628Sfabient	case PMC_CLASS_SOFT:
3881233628Sfabient		ev = soft_event_table;
3882233628Sfabient		count = soft_event_info.pm_nevent;
3883233628Sfabient		break;
3884145256Sjkoshy	default:
3885147191Sjkoshy		errno = EINVAL;
3886174406Sjkoshy		return (-1);
3887145256Sjkoshy	}
3888145256Sjkoshy
3889147191Sjkoshy	if ((names = malloc(count * sizeof(const char *))) == NULL)
3890174406Sjkoshy		return (-1);
3891145256Sjkoshy
3892147191Sjkoshy	*eventnames = names;
3893147191Sjkoshy	*nevents = count;
3894145256Sjkoshy
3895147191Sjkoshy	for (;count--; ev++, names++)
3896147191Sjkoshy		*names = ev->pm_ev_name;
3897233628Sfabient
3898174406Sjkoshy	return (0);
3899147191Sjkoshy}
3900145256Sjkoshy
3901147191Sjkoshyint
3902147191Sjkoshypmc_flush_logfile(void)
3903147191Sjkoshy{
3904174406Sjkoshy	return (PMC_CALL(FLUSHLOG,0));
3905147191Sjkoshy}
3906145256Sjkoshy
3907147191Sjkoshyint
3908226514Sfabientpmc_close_logfile(void)
3909226514Sfabient{
3910226514Sfabient	return (PMC_CALL(CLOSELOG,0));
3911226514Sfabient}
3912226514Sfabient
3913226514Sfabientint
3914147191Sjkoshypmc_get_driver_stats(struct pmc_driverstats *ds)
3915147191Sjkoshy{
3916147191Sjkoshy	struct pmc_op_getdriverstats gms;
3917145256Sjkoshy
3918147191Sjkoshy	if (PMC_CALL(GETDRIVERSTATS, &gms) < 0)
3919174406Sjkoshy		return (-1);
3920145256Sjkoshy
3921147191Sjkoshy	/* copy out fields in the current userland<->library interface */
3922147191Sjkoshy	ds->pm_intr_ignored    = gms.pm_intr_ignored;
3923147191Sjkoshy	ds->pm_intr_processed  = gms.pm_intr_processed;
3924147191Sjkoshy	ds->pm_intr_bufferfull = gms.pm_intr_bufferfull;
3925147191Sjkoshy	ds->pm_syscalls        = gms.pm_syscalls;
3926147191Sjkoshy	ds->pm_syscall_errors  = gms.pm_syscall_errors;
3927147191Sjkoshy	ds->pm_buffer_requests = gms.pm_buffer_requests;
3928147191Sjkoshy	ds->pm_buffer_requests_failed = gms.pm_buffer_requests_failed;
3929147191Sjkoshy	ds->pm_log_sweeps      = gms.pm_log_sweeps;
3930174406Sjkoshy	return (0);
3931147191Sjkoshy}
3932145256Sjkoshy
3933147191Sjkoshyint
3934147191Sjkoshypmc_get_msr(pmc_id_t pmc, uint32_t *msr)
3935147191Sjkoshy{
3936147191Sjkoshy	struct pmc_op_getmsr gm;
3937147191Sjkoshy
3938147191Sjkoshy	gm.pm_pmcid = pmc;
3939147191Sjkoshy	if (PMC_CALL(PMCGETMSR, &gm) < 0)
3940174406Sjkoshy		return (-1);
3941147191Sjkoshy	*msr = gm.pm_msr;
3942174406Sjkoshy	return (0);
3943145256Sjkoshy}
3944145256Sjkoshy
3945145256Sjkoshyint
3946145256Sjkoshypmc_init(void)
3947145256Sjkoshy{
3948145256Sjkoshy	int error, pmc_mod_id;
3949147219Sjkoshy	unsigned int n;
3950145256Sjkoshy	uint32_t abi_version;
3951145256Sjkoshy	struct module_stat pmc_modstat;
3952147219Sjkoshy	struct pmc_op_getcpuinfo op_cpu_info;
3953198433Sjkoshy#if defined(__amd64__) || defined(__i386__)
3954198433Sjkoshy	int cpu_has_iaf_counters;
3955198433Sjkoshy	unsigned int t;
3956198433Sjkoshy#endif
3957145256Sjkoshy
3958145256Sjkoshy	if (pmc_syscall != -1) /* already inited */
3959174406Sjkoshy		return (0);
3960145256Sjkoshy
3961145256Sjkoshy	/* retrieve the system call number from the KLD */
3962145256Sjkoshy	if ((pmc_mod_id = modfind(PMC_MODULE_NAME)) < 0)
3963174406Sjkoshy		return (-1);
3964145256Sjkoshy
3965145256Sjkoshy	pmc_modstat.version = sizeof(struct module_stat);
3966145256Sjkoshy	if ((error = modstat(pmc_mod_id, &pmc_modstat)) < 0)
3967174406Sjkoshy		return (-1);
3968145256Sjkoshy
3969145256Sjkoshy	pmc_syscall = pmc_modstat.data.intval;
3970145256Sjkoshy
3971147191Sjkoshy	/* check the kernel module's ABI against our compiled-in version */
3972147191Sjkoshy	abi_version = PMC_VERSION;
3973145256Sjkoshy	if (PMC_CALL(GETMODULEVERSION, &abi_version) < 0)
3974145256Sjkoshy		return (pmc_syscall = -1);
3975145256Sjkoshy
3976298896Spfg	/* ignore patch & minor numbers for the comparison */
3977147191Sjkoshy	if ((abi_version & 0xFF000000) != (PMC_VERSION & 0xFF000000)) {
3978145256Sjkoshy		errno  = EPROGMISMATCH;
3979145256Sjkoshy		return (pmc_syscall = -1);
3980145256Sjkoshy	}
3981145256Sjkoshy
3982147219Sjkoshy	if (PMC_CALL(GETCPUINFO, &op_cpu_info) < 0)
3983145256Sjkoshy		return (pmc_syscall = -1);
3984145256Sjkoshy
3985147219Sjkoshy	cpu_info.pm_cputype = op_cpu_info.pm_cputype;
3986147219Sjkoshy	cpu_info.pm_ncpu    = op_cpu_info.pm_ncpu;
3987147219Sjkoshy	cpu_info.pm_npmc    = op_cpu_info.pm_npmc;
3988147219Sjkoshy	cpu_info.pm_nclass  = op_cpu_info.pm_nclass;
3989147219Sjkoshy	for (n = 0; n < cpu_info.pm_nclass; n++)
3990328837Sjhibbits		memcpy(&cpu_info.pm_classes[n], &op_cpu_info.pm_classes[n],
3991328837Sjhibbits		    sizeof(cpu_info.pm_classes[n]));
3992147219Sjkoshy
3993185363Sjkoshy	pmc_class_table = malloc(PMC_CLASS_TABLE_SIZE *
3994185363Sjkoshy	    sizeof(struct pmc_class_descr *));
3995185363Sjkoshy
3996185363Sjkoshy	if (pmc_class_table == NULL)
3997185363Sjkoshy		return (-1);
3998185363Sjkoshy
3999198433Sjkoshy	for (n = 0; n < PMC_CLASS_TABLE_SIZE; n++)
4000198433Sjkoshy		pmc_class_table[n] = NULL;
4001185363Sjkoshy
4002185363Sjkoshy	/*
4003233628Sfabient	 * Get soft events list.
4004233628Sfabient	 */
4005233628Sfabient	soft_event_info.pm_class = PMC_CLASS_SOFT;
4006233628Sfabient	if (PMC_CALL(GETDYNEVENTINFO, &soft_event_info) < 0)
4007233628Sfabient		return (pmc_syscall = -1);
4008233628Sfabient
4009233628Sfabient	/* Map soft events to static list. */
4010233628Sfabient	for (n = 0; n < soft_event_info.pm_nevent; n++) {
4011233628Sfabient		soft_event_table[n].pm_ev_name =
4012233628Sfabient		    soft_event_info.pm_events[n].pm_ev_name;
4013233628Sfabient		soft_event_table[n].pm_ev_code =
4014233628Sfabient		    soft_event_info.pm_events[n].pm_ev_code;
4015233628Sfabient	}
4016233628Sfabient	soft_class_table_descr.pm_evc_event_table_size = \
4017233628Sfabient	    soft_event_info.pm_nevent;
4018233628Sfabient	soft_class_table_descr.pm_evc_event_table = \
4019233628Sfabient	    soft_event_table;
4020233628Sfabient
4021233628Sfabient	/*
4022185363Sjkoshy	 * Fill in the class table.
4023185363Sjkoshy	 */
4024185363Sjkoshy	n = 0;
4025233628Sfabient
4026233628Sfabient	/* Fill soft events information. */
4027233628Sfabient	pmc_class_table[n++] = &soft_class_table_descr;
4028185363Sjkoshy#if defined(__amd64__) || defined(__i386__)
4029233628Sfabient	if (cpu_info.pm_cputype != PMC_CPU_GENERIC)
4030233628Sfabient		pmc_class_table[n++] = &tsc_class_table_descr;
4031198433Sjkoshy
4032198433Sjkoshy	/*
4033198433Sjkoshy 	 * Check if this CPU has fixed function counters.
4034198433Sjkoshy	 */
4035198433Sjkoshy	cpu_has_iaf_counters = 0;
4036198433Sjkoshy	for (t = 0; t < cpu_info.pm_nclass; t++)
4037212224Sfabient		if (cpu_info.pm_classes[t].pm_class == PMC_CLASS_IAF &&
4038212224Sfabient		    cpu_info.pm_classes[t].pm_num > 0)
4039198433Sjkoshy			cpu_has_iaf_counters = 1;
4040185363Sjkoshy#endif
4041185363Sjkoshy
4042183725Sjkoshy#define	PMC_MDEP_INIT(C) do {					\
4043183725Sjkoshy		pmc_mdep_event_aliases    = C##_aliases;	\
4044183725Sjkoshy		pmc_mdep_class_list  = C##_pmc_classes;		\
4045183725Sjkoshy		pmc_mdep_class_list_size =			\
4046183725Sjkoshy		    PMC_TABLE_SIZE(C##_pmc_classes);		\
4047183725Sjkoshy	} while (0)
4048183725Sjkoshy
4049198433Sjkoshy#define	PMC_MDEP_INIT_INTEL_V2(C) do {					\
4050198433Sjkoshy		PMC_MDEP_INIT(C);					\
4051212224Sfabient		pmc_class_table[n++] = &iaf_class_table_descr;		\
4052212224Sfabient		if (!cpu_has_iaf_counters) 				\
4053198433Sjkoshy			pmc_mdep_event_aliases =			\
4054198433Sjkoshy				C##_aliases_without_iaf;		\
4055198433Sjkoshy		pmc_class_table[n] = &C##_class_table_descr;		\
4056198433Sjkoshy	} while (0)
4057198433Sjkoshy
4058183725Sjkoshy	/* Configure the event name parser. */
4059145256Sjkoshy	switch (cpu_info.pm_cputype) {
4060145340Smarcel#if defined(__i386__)
4061145256Sjkoshy	case PMC_CPU_AMD_K7:
4062183725Sjkoshy		PMC_MDEP_INIT(k7);
4063185363Sjkoshy		pmc_class_table[n] = &k7_class_table_descr;
4064145256Sjkoshy		break;
4065145256Sjkoshy	case PMC_CPU_INTEL_P5:
4066183725Sjkoshy		PMC_MDEP_INIT(p5);
4067185363Sjkoshy		pmc_class_table[n]  = &p5_class_table_descr;
4068145256Sjkoshy		break;
4069145256Sjkoshy	case PMC_CPU_INTEL_P6:		/* P6 ... Pentium M CPUs have */
4070145256Sjkoshy	case PMC_CPU_INTEL_PII:		/* similar PMCs. */
4071145256Sjkoshy	case PMC_CPU_INTEL_PIII:
4072145256Sjkoshy	case PMC_CPU_INTEL_PM:
4073183725Sjkoshy		PMC_MDEP_INIT(p6);
4074185363Sjkoshy		pmc_class_table[n] = &p6_class_table_descr;
4075145256Sjkoshy		break;
4076147759Sjkoshy#endif
4077147759Sjkoshy#if defined(__amd64__) || defined(__i386__)
4078183725Sjkoshy	case PMC_CPU_AMD_K8:
4079183725Sjkoshy		PMC_MDEP_INIT(k8);
4080185363Sjkoshy		pmc_class_table[n] = &k8_class_table_descr;
4081183725Sjkoshy		break;
4082339767Smmacy	case PMC_CPU_AMD_F17H:
4083339767Smmacy		PMC_MDEP_INIT(f17h);
4084339767Smmacy		pmc_class_table[n] = &f17h_class_table_descr;
4085339767Smmacy		break;
4086185363Sjkoshy	case PMC_CPU_INTEL_ATOM:
4087198433Sjkoshy		PMC_MDEP_INIT_INTEL_V2(atom);
4088185363Sjkoshy		break;
4089263446Shiren	case PMC_CPU_INTEL_ATOM_SILVERMONT:
4090263446Shiren		PMC_MDEP_INIT_INTEL_V2(atom_silvermont);
4091263446Shiren		break;
4092185363Sjkoshy	case PMC_CPU_INTEL_CORE:
4093185363Sjkoshy		PMC_MDEP_INIT(core);
4094202157Sjkoshy		pmc_class_table[n] = &core_class_table_descr;
4095185363Sjkoshy		break;
4096185363Sjkoshy	case PMC_CPU_INTEL_CORE2:
4097185585Sjkoshy	case PMC_CPU_INTEL_CORE2EXTREME:
4098198433Sjkoshy		PMC_MDEP_INIT_INTEL_V2(core2);
4099185363Sjkoshy		break;
4100187761Sjeff	case PMC_CPU_INTEL_COREI7:
4101206089Sfabient		pmc_class_table[n++] = &ucf_class_table_descr;
4102206089Sfabient		pmc_class_table[n++] = &corei7uc_class_table_descr;
4103198433Sjkoshy		PMC_MDEP_INIT_INTEL_V2(corei7);
4104187761Sjeff		break;
4105267062Skib	case PMC_CPU_INTEL_NEHALEM_EX:
4106267062Skib		PMC_MDEP_INIT_INTEL_V2(nehalem_ex);
4107267062Skib		break;
4108248842Ssbruno	case PMC_CPU_INTEL_HASWELL:
4109248842Ssbruno		pmc_class_table[n++] = &ucf_class_table_descr;
4110248842Ssbruno		pmc_class_table[n++] = &haswelluc_class_table_descr;
4111248842Ssbruno		PMC_MDEP_INIT_INTEL_V2(haswell);
4112248842Ssbruno		break;
4113277177Srrs	case PMC_CPU_INTEL_HASWELL_XEON:
4114277177Srrs		PMC_MDEP_INIT_INTEL_V2(haswell_xeon);
4115277177Srrs		break;
4116291494Srrs	case PMC_CPU_INTEL_BROADWELL:
4117291494Srrs		pmc_class_table[n++] = &ucf_class_table_descr;
4118291494Srrs		pmc_class_table[n++] = &broadwelluc_class_table_descr;
4119291494Srrs		PMC_MDEP_INIT_INTEL_V2(broadwell);
4120291494Srrs		break;
4121291494Srrs	case PMC_CPU_INTEL_BROADWELL_XEON:
4122291494Srrs		PMC_MDEP_INIT_INTEL_V2(broadwell_xeon);
4123291494Srrs		break;
4124291494Srrs	case PMC_CPU_INTEL_SKYLAKE:
4125291494Srrs		PMC_MDEP_INIT_INTEL_V2(skylake);
4126291494Srrs		break;
4127323799Skib	case PMC_CPU_INTEL_SKYLAKE_XEON:
4128323799Skib		PMC_MDEP_INIT_INTEL_V2(skylake_xeon);
4129323799Skib		break;
4130240164Sfabient	case PMC_CPU_INTEL_IVYBRIDGE:
4131240164Sfabient		PMC_MDEP_INIT_INTEL_V2(ivybridge);
4132240164Sfabient		break;
4133246166Ssbruno	case PMC_CPU_INTEL_IVYBRIDGE_XEON:
4134246166Ssbruno		PMC_MDEP_INIT_INTEL_V2(ivybridge_xeon);
4135246166Ssbruno		break;
4136232366Sdavide	case PMC_CPU_INTEL_SANDYBRIDGE:
4137232366Sdavide		pmc_class_table[n++] = &ucf_class_table_descr;
4138232366Sdavide		pmc_class_table[n++] = &sandybridgeuc_class_table_descr;
4139232366Sdavide		PMC_MDEP_INIT_INTEL_V2(sandybridge);
4140232366Sdavide		break;
4141241738Ssbruno	case PMC_CPU_INTEL_SANDYBRIDGE_XEON:
4142241738Ssbruno		PMC_MDEP_INIT_INTEL_V2(sandybridge_xeon);
4143241738Ssbruno		break;
4144206089Sfabient	case PMC_CPU_INTEL_WESTMERE:
4145206089Sfabient		pmc_class_table[n++] = &ucf_class_table_descr;
4146206089Sfabient		pmc_class_table[n++] = &westmereuc_class_table_descr;
4147206089Sfabient		PMC_MDEP_INIT_INTEL_V2(westmere);
4148206089Sfabient		break;
4149267062Skib	case PMC_CPU_INTEL_WESTMERE_EX:
4150267062Skib		PMC_MDEP_INIT_INTEL_V2(westmere_ex);
4151267062Skib		break;
4152145256Sjkoshy	case PMC_CPU_INTEL_PIV:
4153183725Sjkoshy		PMC_MDEP_INIT(p4);
4154185363Sjkoshy		pmc_class_table[n] = &p4_class_table_descr;
4155145256Sjkoshy		break;
4156145256Sjkoshy#endif
4157233628Sfabient	case PMC_CPU_GENERIC:
4158233628Sfabient		PMC_MDEP_INIT(generic);
4159233628Sfabient		break;
4160277835Sbr#if defined(__arm__)
4161200928Srpaulo#if defined(__XSCALE__)
4162200928Srpaulo	case PMC_CPU_INTEL_XSCALE:
4163200928Srpaulo		PMC_MDEP_INIT(xscale);
4164200928Srpaulo		pmc_class_table[n] = &xscale_class_table_descr;
4165200928Srpaulo		break;
4166200928Srpaulo#endif
4167284218Sbr	case PMC_CPU_ARMV7_CORTEX_A8:
4168284218Sbr		PMC_MDEP_INIT(cortex_a8);
4169284218Sbr		pmc_class_table[n] = &cortex_a8_class_table_descr;
4170277835Sbr		break;
4171284218Sbr	case PMC_CPU_ARMV7_CORTEX_A9:
4172284218Sbr		PMC_MDEP_INIT(cortex_a9);
4173284218Sbr		pmc_class_table[n] = &cortex_a9_class_table_descr;
4174284218Sbr		break;
4175277835Sbr#endif
4176283112Sbr#if defined(__aarch64__)
4177283112Sbr	case PMC_CPU_ARMV8_CORTEX_A53:
4178283112Sbr		PMC_MDEP_INIT(cortex_a53);
4179283112Sbr		pmc_class_table[n] = &cortex_a53_class_table_descr;
4180283112Sbr		break;
4181283112Sbr	case PMC_CPU_ARMV8_CORTEX_A57:
4182283112Sbr		PMC_MDEP_INIT(cortex_a57);
4183283112Sbr		pmc_class_table[n] = &cortex_a57_class_table_descr;
4184283112Sbr		break;
4185283112Sbr#endif
4186204635Sgnn#if defined(__mips__)
4187204635Sgnn	case PMC_CPU_MIPS_24K:
4188204635Sgnn		PMC_MDEP_INIT(mips24k);
4189204635Sgnn		pmc_class_table[n] = &mips24k_class_table_descr;
4190204635Sgnn		break;
4191281098Sadrian	case PMC_CPU_MIPS_74K:
4192281098Sadrian		PMC_MDEP_INIT(mips74k);
4193281098Sadrian		pmc_class_table[n] = &mips74k_class_table_descr;
4194281098Sadrian		break;
4195233335Sgonzo	case PMC_CPU_MIPS_OCTEON:
4196233335Sgonzo		PMC_MDEP_INIT(octeon);
4197233335Sgonzo		pmc_class_table[n] = &octeon_class_table_descr;
4198233335Sgonzo		break;
4199204635Sgnn#endif /* __mips__ */
4200228869Sjhibbits#if defined(__powerpc__)
4201228869Sjhibbits	case PMC_CPU_PPC_7450:
4202228869Sjhibbits		PMC_MDEP_INIT(ppc7450);
4203228869Sjhibbits		pmc_class_table[n] = &ppc7450_class_table_descr;
4204228869Sjhibbits		break;
4205261342Sjhibbits	case PMC_CPU_PPC_970:
4206261342Sjhibbits		PMC_MDEP_INIT(ppc970);
4207261342Sjhibbits		pmc_class_table[n] = &ppc970_class_table_descr;
4208261342Sjhibbits		break;
4209281713Sjhibbits	case PMC_CPU_PPC_E500:
4210281713Sjhibbits		PMC_MDEP_INIT(e500);
4211281713Sjhibbits		pmc_class_table[n] = &e500_class_table_descr;
4212281713Sjhibbits		break;
4213228869Sjhibbits#endif
4214145256Sjkoshy	default:
4215145256Sjkoshy		/*
4216145256Sjkoshy		 * Some kind of CPU this version of the library knows nothing
4217145256Sjkoshy		 * about.  This shouldn't happen since the abi version check
4218145256Sjkoshy		 * should have caught this.
4219145256Sjkoshy		 */
4220145256Sjkoshy		errno = ENXIO;
4221145256Sjkoshy		return (pmc_syscall = -1);
4222145256Sjkoshy	}
4223145256Sjkoshy
4224174406Sjkoshy	return (0);
4225145256Sjkoshy}
4226145256Sjkoshy
4227147191Sjkoshyconst char *
4228147191Sjkoshypmc_name_of_capability(enum pmc_caps cap)
4229145256Sjkoshy{
4230147191Sjkoshy	int i;
4231145256Sjkoshy
4232147191Sjkoshy	/*
4233147191Sjkoshy	 * 'cap' should have a single bit set and should be in
4234147191Sjkoshy	 * range.
4235147191Sjkoshy	 */
4236147191Sjkoshy	if ((cap & (cap - 1)) || cap < PMC_CAP_FIRST ||
4237147191Sjkoshy	    cap > PMC_CAP_LAST) {
4238145256Sjkoshy		errno = EINVAL;
4239174406Sjkoshy		return (NULL);
4240145256Sjkoshy	}
4241145256Sjkoshy
4242147191Sjkoshy	i = ffs(cap);
4243174406Sjkoshy	return (pmc_capability_names[i - 1]);
4244147191Sjkoshy}
4245145256Sjkoshy
4246147191Sjkoshyconst char *
4247147191Sjkoshypmc_name_of_class(enum pmc_class pc)
4248147191Sjkoshy{
4249283120Sjhb	size_t n;
4250145256Sjkoshy
4251283120Sjhb	for (n = 0; n < PMC_TABLE_SIZE(pmc_class_names); n++)
4252283120Sjhb		if (pc == pmc_class_names[n].pm_class)
4253283120Sjhb			return (pmc_class_names[n].pm_name);
4254283120Sjhb
4255147191Sjkoshy	errno = EINVAL;
4256174406Sjkoshy	return (NULL);
4257147191Sjkoshy}
4258145256Sjkoshy
4259147191Sjkoshyconst char *
4260147191Sjkoshypmc_name_of_cputype(enum pmc_cputype cp)
4261147191Sjkoshy{
4262183725Sjkoshy	size_t n;
4263183725Sjkoshy
4264183725Sjkoshy	for (n = 0; n < PMC_TABLE_SIZE(pmc_cputype_names); n++)
4265183725Sjkoshy		if (cp == pmc_cputype_names[n].pm_cputype)
4266183725Sjkoshy			return (pmc_cputype_names[n].pm_name);
4267183725Sjkoshy
4268147191Sjkoshy	errno = EINVAL;
4269174406Sjkoshy	return (NULL);
4270147191Sjkoshy}
4271145256Sjkoshy
4272147191Sjkoshyconst char *
4273147191Sjkoshypmc_name_of_disposition(enum pmc_disp pd)
4274147191Sjkoshy{
4275147191Sjkoshy	if ((int) pd >= PMC_DISP_FIRST &&
4276147191Sjkoshy	    pd <= PMC_DISP_LAST)
4277174406Sjkoshy		return (pmc_disposition_names[pd]);
4278145256Sjkoshy
4279147191Sjkoshy	errno = EINVAL;
4280174406Sjkoshy	return (NULL);
4281147191Sjkoshy}
4282145256Sjkoshy
4283147191Sjkoshyconst char *
4284185363Sjkoshy_pmc_name_of_event(enum pmc_event pe, enum pmc_cputype cpu)
4285147191Sjkoshy{
4286183725Sjkoshy	const struct pmc_event_descr *ev, *evfence;
4287145256Sjkoshy
4288183725Sjkoshy	ev = evfence = NULL;
4289185363Sjkoshy	if (pe >= PMC_EV_IAF_FIRST && pe <= PMC_EV_IAF_LAST) {
4290185363Sjkoshy		ev = iaf_event_table;
4291185363Sjkoshy		evfence = iaf_event_table + PMC_EVENT_TABLE_SIZE(iaf);
4292185363Sjkoshy	} else if (pe >= PMC_EV_IAP_FIRST && pe <= PMC_EV_IAP_LAST) {
4293185363Sjkoshy		switch (cpu) {
4294185363Sjkoshy		case PMC_CPU_INTEL_ATOM:
4295185363Sjkoshy			ev = atom_event_table;
4296185363Sjkoshy			evfence = atom_event_table + PMC_EVENT_TABLE_SIZE(atom);
4297185363Sjkoshy			break;
4298263446Shiren		case PMC_CPU_INTEL_ATOM_SILVERMONT:
4299263446Shiren			ev = atom_silvermont_event_table;
4300263446Shiren			evfence = atom_silvermont_event_table +
4301263446Shiren			    PMC_EVENT_TABLE_SIZE(atom_silvermont);
4302263446Shiren			break;
4303185363Sjkoshy		case PMC_CPU_INTEL_CORE:
4304185363Sjkoshy			ev = core_event_table;
4305185363Sjkoshy			evfence = core_event_table + PMC_EVENT_TABLE_SIZE(core);
4306185363Sjkoshy			break;
4307185363Sjkoshy		case PMC_CPU_INTEL_CORE2:
4308185585Sjkoshy		case PMC_CPU_INTEL_CORE2EXTREME:
4309185363Sjkoshy			ev = core2_event_table;
4310185363Sjkoshy			evfence = core2_event_table + PMC_EVENT_TABLE_SIZE(core2);
4311185363Sjkoshy			break;
4312187761Sjeff		case PMC_CPU_INTEL_COREI7:
4313187761Sjeff			ev = corei7_event_table;
4314187761Sjeff			evfence = corei7_event_table + PMC_EVENT_TABLE_SIZE(corei7);
4315187761Sjeff			break;
4316267062Skib		case PMC_CPU_INTEL_NEHALEM_EX:
4317267062Skib			ev = nehalem_ex_event_table;
4318267062Skib			evfence = nehalem_ex_event_table +
4319267062Skib			    PMC_EVENT_TABLE_SIZE(nehalem_ex);
4320267062Skib			break;
4321248842Ssbruno		case PMC_CPU_INTEL_HASWELL:
4322248842Ssbruno			ev = haswell_event_table;
4323248842Ssbruno			evfence = haswell_event_table + PMC_EVENT_TABLE_SIZE(haswell);
4324248842Ssbruno			break;
4325277177Srrs		case PMC_CPU_INTEL_HASWELL_XEON:
4326277177Srrs			ev = haswell_xeon_event_table;
4327277177Srrs			evfence = haswell_xeon_event_table + PMC_EVENT_TABLE_SIZE(haswell_xeon);
4328277177Srrs			break;
4329291494Srrs		case PMC_CPU_INTEL_BROADWELL:
4330291494Srrs			ev = broadwell_event_table;
4331291494Srrs			evfence = broadwell_event_table + PMC_EVENT_TABLE_SIZE(broadwell);
4332291494Srrs			break;
4333291494Srrs		case PMC_CPU_INTEL_BROADWELL_XEON:
4334291494Srrs			ev = broadwell_xeon_event_table;
4335291494Srrs			evfence = broadwell_xeon_event_table + PMC_EVENT_TABLE_SIZE(broadwell_xeon);
4336291494Srrs			break;
4337291494Srrs		case PMC_CPU_INTEL_SKYLAKE:
4338291494Srrs			ev = skylake_event_table;
4339323798Skib			evfence = skylake_event_table +
4340323798Skib			    PMC_EVENT_TABLE_SIZE(skylake);
4341291494Srrs			break;
4342323799Skib		case PMC_CPU_INTEL_SKYLAKE_XEON:
4343323799Skib			ev = skylake_xeon_event_table;
4344323799Skib			evfence = skylake_xeon_event_table +
4345323799Skib			    PMC_EVENT_TABLE_SIZE(skylake_xeon);
4346323799Skib			break;
4347240164Sfabient		case PMC_CPU_INTEL_IVYBRIDGE:
4348240164Sfabient			ev = ivybridge_event_table;
4349240164Sfabient			evfence = ivybridge_event_table + PMC_EVENT_TABLE_SIZE(ivybridge);
4350240164Sfabient			break;
4351246166Ssbruno		case PMC_CPU_INTEL_IVYBRIDGE_XEON:
4352246166Ssbruno			ev = ivybridge_xeon_event_table;
4353246166Ssbruno			evfence = ivybridge_xeon_event_table + PMC_EVENT_TABLE_SIZE(ivybridge_xeon);
4354246166Ssbruno			break;
4355232366Sdavide		case PMC_CPU_INTEL_SANDYBRIDGE:
4356232366Sdavide			ev = sandybridge_event_table;
4357232366Sdavide			evfence = sandybridge_event_table + PMC_EVENT_TABLE_SIZE(sandybridge);
4358232366Sdavide			break;
4359241738Ssbruno		case PMC_CPU_INTEL_SANDYBRIDGE_XEON:
4360241738Ssbruno			ev = sandybridge_xeon_event_table;
4361241738Ssbruno			evfence = sandybridge_xeon_event_table + PMC_EVENT_TABLE_SIZE(sandybridge_xeon);
4362241738Ssbruno			break;
4363206089Sfabient		case PMC_CPU_INTEL_WESTMERE:
4364206089Sfabient			ev = westmere_event_table;
4365206089Sfabient			evfence = westmere_event_table + PMC_EVENT_TABLE_SIZE(westmere);
4366206089Sfabient			break;
4367267062Skib		case PMC_CPU_INTEL_WESTMERE_EX:
4368267062Skib			ev = westmere_ex_event_table;
4369267062Skib			evfence = westmere_ex_event_table +
4370267062Skib			    PMC_EVENT_TABLE_SIZE(westmere_ex);
4371267062Skib			break;
4372185363Sjkoshy		default:	/* Unknown CPU type. */
4373185363Sjkoshy			break;
4374185363Sjkoshy		}
4375206089Sfabient	} else if (pe >= PMC_EV_UCF_FIRST && pe <= PMC_EV_UCF_LAST) {
4376206089Sfabient		ev = ucf_event_table;
4377206089Sfabient		evfence = ucf_event_table + PMC_EVENT_TABLE_SIZE(ucf);
4378206089Sfabient	} else if (pe >= PMC_EV_UCP_FIRST && pe <= PMC_EV_UCP_LAST) {
4379206089Sfabient		switch (cpu) {
4380206089Sfabient		case PMC_CPU_INTEL_COREI7:
4381206089Sfabient			ev = corei7uc_event_table;
4382206089Sfabient			evfence = corei7uc_event_table + PMC_EVENT_TABLE_SIZE(corei7uc);
4383206089Sfabient			break;
4384232366Sdavide		case PMC_CPU_INTEL_SANDYBRIDGE:
4385232366Sdavide			ev = sandybridgeuc_event_table;
4386232366Sdavide			evfence = sandybridgeuc_event_table + PMC_EVENT_TABLE_SIZE(sandybridgeuc);
4387232366Sdavide			break;
4388206089Sfabient		case PMC_CPU_INTEL_WESTMERE:
4389206089Sfabient			ev = westmereuc_event_table;
4390206089Sfabient			evfence = westmereuc_event_table + PMC_EVENT_TABLE_SIZE(westmereuc);
4391206089Sfabient			break;
4392206089Sfabient		default:	/* Unknown CPU type. */
4393206089Sfabient			break;
4394206089Sfabient		}
4395206089Sfabient	} else if (pe >= PMC_EV_K7_FIRST && pe <= PMC_EV_K7_LAST) {
4396183725Sjkoshy		ev = k7_event_table;
4397183725Sjkoshy		evfence = k7_event_table + PMC_EVENT_TABLE_SIZE(k7);
4398183725Sjkoshy	} else if (pe >= PMC_EV_K8_FIRST && pe <= PMC_EV_K8_LAST) {
4399183725Sjkoshy		ev = k8_event_table;
4400183725Sjkoshy		evfence = k8_event_table + PMC_EVENT_TABLE_SIZE(k8);
4401339767Smmacy	} else if ((int)pe >= PMC_EV_F17H_FIRST &&
4402339767Smmacy			(int)pe <= PMC_EV_F17H_LAST) {
4403339767Smmacy		ev = f17h_event_table;
4404339767Smmacy		evfence = f17h_event_table + PMC_EVENT_TABLE_SIZE(f17h);
4405183725Sjkoshy	} else if (pe >= PMC_EV_P4_FIRST && pe <= PMC_EV_P4_LAST) {
4406183725Sjkoshy		ev = p4_event_table;
4407183725Sjkoshy		evfence = p4_event_table + PMC_EVENT_TABLE_SIZE(p4);
4408183725Sjkoshy	} else if (pe >= PMC_EV_P5_FIRST && pe <= PMC_EV_P5_LAST) {
4409183725Sjkoshy		ev = p5_event_table;
4410183725Sjkoshy		evfence = p5_event_table + PMC_EVENT_TABLE_SIZE(p5);
4411183725Sjkoshy	} else if (pe >= PMC_EV_P6_FIRST && pe <= PMC_EV_P6_LAST) {
4412183725Sjkoshy		ev = p6_event_table;
4413183725Sjkoshy		evfence = p6_event_table + PMC_EVENT_TABLE_SIZE(p6);
4414200928Srpaulo	} else if (pe >= PMC_EV_XSCALE_FIRST && pe <= PMC_EV_XSCALE_LAST) {
4415200928Srpaulo		ev = xscale_event_table;
4416200928Srpaulo		evfence = xscale_event_table + PMC_EVENT_TABLE_SIZE(xscale);
4417277835Sbr	} else if (pe >= PMC_EV_ARMV7_FIRST && pe <= PMC_EV_ARMV7_LAST) {
4418284218Sbr		switch (cpu) {
4419284218Sbr		case PMC_CPU_ARMV7_CORTEX_A8:
4420284218Sbr			ev = cortex_a8_event_table;
4421284218Sbr			evfence = cortex_a8_event_table + PMC_EVENT_TABLE_SIZE(cortex_a8);
4422284218Sbr			break;
4423284218Sbr		case PMC_CPU_ARMV7_CORTEX_A9:
4424284218Sbr			ev = cortex_a9_event_table;
4425284218Sbr			evfence = cortex_a9_event_table + PMC_EVENT_TABLE_SIZE(cortex_a9);
4426284218Sbr			break;
4427284218Sbr		default:	/* Unknown CPU type. */
4428284218Sbr			break;
4429284218Sbr		}
4430283112Sbr	} else if (pe >= PMC_EV_ARMV8_FIRST && pe <= PMC_EV_ARMV8_LAST) {
4431283112Sbr		switch (cpu) {
4432283112Sbr		case PMC_CPU_ARMV8_CORTEX_A53:
4433283112Sbr			ev = cortex_a53_event_table;
4434283112Sbr			evfence = cortex_a53_event_table + PMC_EVENT_TABLE_SIZE(cortex_a53);
4435283112Sbr			break;
4436283112Sbr		case PMC_CPU_ARMV8_CORTEX_A57:
4437283112Sbr			ev = cortex_a57_event_table;
4438283112Sbr			evfence = cortex_a57_event_table + PMC_EVENT_TABLE_SIZE(cortex_a57);
4439283112Sbr			break;
4440283112Sbr		default:	/* Unknown CPU type. */
4441283112Sbr			break;
4442283112Sbr		}
4443204635Sgnn	} else if (pe >= PMC_EV_MIPS24K_FIRST && pe <= PMC_EV_MIPS24K_LAST) {
4444204635Sgnn		ev = mips24k_event_table;
4445233628Sfabient		evfence = mips24k_event_table + PMC_EVENT_TABLE_SIZE(mips24k);
4446281098Sadrian	} else if (pe >= PMC_EV_MIPS74K_FIRST && pe <= PMC_EV_MIPS74K_LAST) {
4447281098Sadrian		ev = mips74k_event_table;
4448281098Sadrian		evfence = mips74k_event_table + PMC_EVENT_TABLE_SIZE(mips74k);
4449233335Sgonzo	} else if (pe >= PMC_EV_OCTEON_FIRST && pe <= PMC_EV_OCTEON_LAST) {
4450233335Sgonzo		ev = octeon_event_table;
4451233335Sgonzo		evfence = octeon_event_table + PMC_EVENT_TABLE_SIZE(octeon);
4452228869Sjhibbits	} else if (pe >= PMC_EV_PPC7450_FIRST && pe <= PMC_EV_PPC7450_LAST) {
4453228869Sjhibbits		ev = ppc7450_event_table;
4454233628Sfabient		evfence = ppc7450_event_table + PMC_EVENT_TABLE_SIZE(ppc7450);
4455261342Sjhibbits	} else if (pe >= PMC_EV_PPC970_FIRST && pe <= PMC_EV_PPC970_LAST) {
4456261342Sjhibbits		ev = ppc970_event_table;
4457261342Sjhibbits		evfence = ppc970_event_table + PMC_EVENT_TABLE_SIZE(ppc970);
4458281713Sjhibbits	} else if (pe >= PMC_EV_E500_FIRST && pe <= PMC_EV_E500_LAST) {
4459281713Sjhibbits		ev = e500_event_table;
4460281713Sjhibbits		evfence = e500_event_table + PMC_EVENT_TABLE_SIZE(e500);
4461183725Sjkoshy	} else if (pe == PMC_EV_TSC_TSC) {
4462183725Sjkoshy		ev = tsc_event_table;
4463183725Sjkoshy		evfence = tsc_event_table + PMC_EVENT_TABLE_SIZE(tsc);
4464242622Sdim	} else if ((int)pe >= PMC_EV_SOFT_FIRST && (int)pe <= PMC_EV_SOFT_LAST) {
4465233628Sfabient		ev = soft_event_table;
4466233628Sfabient		evfence = soft_event_table + soft_event_info.pm_nevent;
4467183725Sjkoshy	}
4468183725Sjkoshy
4469183725Sjkoshy	for (; ev != evfence; ev++)
4470183725Sjkoshy		if (pe == ev->pm_ev_code)
4471183725Sjkoshy			return (ev->pm_ev_name);
4472183725Sjkoshy
4473185363Sjkoshy	return (NULL);
4474185363Sjkoshy}
4475185363Sjkoshy
4476185363Sjkoshyconst char *
4477185363Sjkoshypmc_name_of_event(enum pmc_event pe)
4478185363Sjkoshy{
4479185363Sjkoshy	const char *n;
4480185363Sjkoshy
4481185363Sjkoshy	if ((n = _pmc_name_of_event(pe, cpu_info.pm_cputype)) != NULL)
4482185363Sjkoshy		return (n);
4483185363Sjkoshy
4484147191Sjkoshy	errno = EINVAL;
4485174406Sjkoshy	return (NULL);
4486147191Sjkoshy}
4487145256Sjkoshy
4488147191Sjkoshyconst char *
4489147191Sjkoshypmc_name_of_mode(enum pmc_mode pm)
4490147191Sjkoshy{
4491147191Sjkoshy	if ((int) pm >= PMC_MODE_FIRST &&
4492147191Sjkoshy	    pm <= PMC_MODE_LAST)
4493174406Sjkoshy		return (pmc_mode_names[pm]);
4494145256Sjkoshy
4495147191Sjkoshy	errno = EINVAL;
4496174406Sjkoshy	return (NULL);
4497147191Sjkoshy}
4498145256Sjkoshy
4499147191Sjkoshyconst char *
4500147191Sjkoshypmc_name_of_state(enum pmc_state ps)
4501147191Sjkoshy{
4502147191Sjkoshy	if ((int) ps >= PMC_STATE_FIRST &&
4503147191Sjkoshy	    ps <= PMC_STATE_LAST)
4504174406Sjkoshy		return (pmc_state_names[ps]);
4505145256Sjkoshy
4506147191Sjkoshy	errno = EINVAL;
4507174406Sjkoshy	return (NULL);
4508145256Sjkoshy}
4509145256Sjkoshy
4510145256Sjkoshyint
4511147191Sjkoshypmc_ncpu(void)
4512145256Sjkoshy{
4513147191Sjkoshy	if (pmc_syscall == -1) {
4514147191Sjkoshy		errno = ENXIO;
4515174406Sjkoshy		return (-1);
4516147191Sjkoshy	}
4517145256Sjkoshy
4518174406Sjkoshy	return (cpu_info.pm_ncpu);
4519145256Sjkoshy}
4520145256Sjkoshy
4521145256Sjkoshyint
4522147191Sjkoshypmc_npmc(int cpu)
4523145256Sjkoshy{
4524147191Sjkoshy	if (pmc_syscall == -1) {
4525147191Sjkoshy		errno = ENXIO;
4526174406Sjkoshy		return (-1);
4527147191Sjkoshy	}
4528145256Sjkoshy
4529147191Sjkoshy	if (cpu < 0 || cpu >= (int) cpu_info.pm_ncpu) {
4530147191Sjkoshy		errno = EINVAL;
4531174406Sjkoshy		return (-1);
4532147191Sjkoshy	}
4533145256Sjkoshy
4534174406Sjkoshy	return (cpu_info.pm_npmc);
4535145256Sjkoshy}
4536145256Sjkoshy
4537145256Sjkoshyint
4538147191Sjkoshypmc_pmcinfo(int cpu, struct pmc_pmcinfo **ppmci)
4539145256Sjkoshy{
4540147191Sjkoshy	int nbytes, npmc;
4541147191Sjkoshy	struct pmc_op_getpmcinfo *pmci;
4542145256Sjkoshy
4543147191Sjkoshy	if ((npmc = pmc_npmc(cpu)) < 0)
4544174406Sjkoshy		return (-1);
4545145256Sjkoshy
4546147191Sjkoshy	nbytes = sizeof(struct pmc_op_getpmcinfo) +
4547147191Sjkoshy	    npmc * sizeof(struct pmc_info);
4548145256Sjkoshy
4549147191Sjkoshy	if ((pmci = calloc(1, nbytes)) == NULL)
4550174406Sjkoshy		return (-1);
4551145256Sjkoshy
4552147191Sjkoshy	pmci->pm_cpu  = cpu;
4553145256Sjkoshy
4554147191Sjkoshy	if (PMC_CALL(GETPMCINFO, pmci) < 0) {
4555147191Sjkoshy		free(pmci);
4556174406Sjkoshy		return (-1);
4557147191Sjkoshy	}
4558145256Sjkoshy
4559147191Sjkoshy	/* kernel<->library, library<->userland interfaces are identical */
4560147191Sjkoshy	*ppmci = (struct pmc_pmcinfo *) pmci;
4561174406Sjkoshy	return (0);
4562145256Sjkoshy}
4563145256Sjkoshy
4564145256Sjkoshyint
4565145256Sjkoshypmc_read(pmc_id_t pmc, pmc_value_t *value)
4566145256Sjkoshy{
4567145256Sjkoshy	struct pmc_op_pmcrw pmc_read_op;
4568145256Sjkoshy
4569145256Sjkoshy	pmc_read_op.pm_pmcid = pmc;
4570145256Sjkoshy	pmc_read_op.pm_flags = PMC_F_OLDVALUE;
4571145256Sjkoshy	pmc_read_op.pm_value = -1;
4572145256Sjkoshy
4573145256Sjkoshy	if (PMC_CALL(PMCRW, &pmc_read_op) < 0)
4574174406Sjkoshy		return (-1);
4575145256Sjkoshy
4576145256Sjkoshy	*value = pmc_read_op.pm_value;
4577174406Sjkoshy	return (0);
4578145256Sjkoshy}
4579145256Sjkoshy
4580145256Sjkoshyint
4581147191Sjkoshypmc_release(pmc_id_t pmc)
4582145256Sjkoshy{
4583147191Sjkoshy	struct pmc_op_simple	pmc_release_args;
4584145256Sjkoshy
4585147191Sjkoshy	pmc_release_args.pm_pmcid = pmc;
4586174406Sjkoshy	return (PMC_CALL(PMCRELEASE, &pmc_release_args));
4587145256Sjkoshy}
4588145256Sjkoshy
4589145256Sjkoshyint
4590145256Sjkoshypmc_rw(pmc_id_t pmc, pmc_value_t newvalue, pmc_value_t *oldvaluep)
4591145256Sjkoshy{
4592145256Sjkoshy	struct pmc_op_pmcrw pmc_rw_op;
4593145256Sjkoshy
4594145256Sjkoshy	pmc_rw_op.pm_pmcid = pmc;
4595145256Sjkoshy	pmc_rw_op.pm_flags = PMC_F_NEWVALUE | PMC_F_OLDVALUE;
4596145256Sjkoshy	pmc_rw_op.pm_value = newvalue;
4597145256Sjkoshy
4598145256Sjkoshy	if (PMC_CALL(PMCRW, &pmc_rw_op) < 0)
4599174406Sjkoshy		return (-1);
4600145256Sjkoshy
4601145256Sjkoshy	*oldvaluep = pmc_rw_op.pm_value;
4602174406Sjkoshy	return (0);
4603145256Sjkoshy}
4604145256Sjkoshy
4605145256Sjkoshyint
4606145256Sjkoshypmc_set(pmc_id_t pmc, pmc_value_t value)
4607145256Sjkoshy{
4608145256Sjkoshy	struct pmc_op_pmcsetcount sc;
4609145256Sjkoshy
4610145256Sjkoshy	sc.pm_pmcid = pmc;
4611145256Sjkoshy	sc.pm_count = value;
4612145256Sjkoshy
4613145256Sjkoshy	if (PMC_CALL(PMCSETCOUNT, &sc) < 0)
4614174406Sjkoshy		return (-1);
4615174406Sjkoshy	return (0);
4616145256Sjkoshy}
4617145256Sjkoshy
4618145256Sjkoshyint
4619147191Sjkoshypmc_start(pmc_id_t pmc)
4620145256Sjkoshy{
4621147191Sjkoshy	struct pmc_op_simple	pmc_start_args;
4622145256Sjkoshy
4623147191Sjkoshy	pmc_start_args.pm_pmcid = pmc;
4624174406Sjkoshy	return (PMC_CALL(PMCSTART, &pmc_start_args));
4625145256Sjkoshy}
4626145256Sjkoshy
4627145256Sjkoshyint
4628147191Sjkoshypmc_stop(pmc_id_t pmc)
4629145256Sjkoshy{
4630147191Sjkoshy	struct pmc_op_simple	pmc_stop_args;
4631145256Sjkoshy
4632147191Sjkoshy	pmc_stop_args.pm_pmcid = pmc;
4633174406Sjkoshy	return (PMC_CALL(PMCSTOP, &pmc_stop_args));
4634145256Sjkoshy}
4635145256Sjkoshy
4636145256Sjkoshyint
4637145774Sjkoshypmc_width(pmc_id_t pmcid, uint32_t *width)
4638145774Sjkoshy{
4639145774Sjkoshy	unsigned int i;
4640145774Sjkoshy	enum pmc_class cl;
4641145774Sjkoshy
4642145774Sjkoshy	cl = PMC_ID_TO_CLASS(pmcid);
4643145774Sjkoshy	for (i = 0; i < cpu_info.pm_nclass; i++)
4644145774Sjkoshy		if (cpu_info.pm_classes[i].pm_class == cl) {
4645145774Sjkoshy			*width = cpu_info.pm_classes[i].pm_width;
4646174406Sjkoshy			return (0);
4647145774Sjkoshy		}
4648177107Sjkoshy	errno = EINVAL;
4649177107Sjkoshy	return (-1);
4650145774Sjkoshy}
4651145774Sjkoshy
4652145774Sjkoshyint
4653147191Sjkoshypmc_write(pmc_id_t pmc, pmc_value_t value)
4654145774Sjkoshy{
4655147191Sjkoshy	struct pmc_op_pmcrw pmc_write_op;
4656145774Sjkoshy
4657147191Sjkoshy	pmc_write_op.pm_pmcid = pmc;
4658147191Sjkoshy	pmc_write_op.pm_flags = PMC_F_NEWVALUE;
4659147191Sjkoshy	pmc_write_op.pm_value = value;
4660174406Sjkoshy	return (PMC_CALL(PMCRW, &pmc_write_op));
4661145256Sjkoshy}
4662145256Sjkoshy
4663145256Sjkoshyint
4664147191Sjkoshypmc_writelog(uint32_t userdata)
4665145256Sjkoshy{
4666147191Sjkoshy	struct pmc_op_writelog wl;
4667145256Sjkoshy
4668147191Sjkoshy	wl.pm_userdata = userdata;
4669174406Sjkoshy	return (PMC_CALL(WRITELOG, &wl));
4670145256Sjkoshy}
4671