xref: /onnv-gate/usr/src/lib/libcpc/i386/event_pentium.c (revision 13093:48f2dbca79a2)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*13093SRoger.Faulkner@Oracle.COM  * Common Development and Distribution License (the "License").
6*13093SRoger.Faulkner@Oracle.COM  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
21*13093SRoger.Faulkner@Oracle.COM 
220Sstevel@tonic-gate /*
23*13093SRoger.Faulkner@Oracle.COM  * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate /*
270Sstevel@tonic-gate  * Routines to capture processor-dependencies in event specification.
280Sstevel@tonic-gate  */
290Sstevel@tonic-gate 
300Sstevel@tonic-gate #include <sys/types.h>
310Sstevel@tonic-gate #include <string.h>
320Sstevel@tonic-gate #include <strings.h>
330Sstevel@tonic-gate #include <stdlib.h>
340Sstevel@tonic-gate #include <stdio.h>
350Sstevel@tonic-gate #include <libintl.h>
360Sstevel@tonic-gate #include <assert.h>
370Sstevel@tonic-gate #include <errno.h>
380Sstevel@tonic-gate 
390Sstevel@tonic-gate #include "libcpc.h"
400Sstevel@tonic-gate #include "libcpc_impl.h"
410Sstevel@tonic-gate 
420Sstevel@tonic-gate /*
430Sstevel@tonic-gate  * Event specifications for Pentium performance counters are based
440Sstevel@tonic-gate  * on the content of a getsubopt-like string.
450Sstevel@tonic-gate  * The string should contain something that looks like this:
460Sstevel@tonic-gate  *
470Sstevel@tonic-gate  *	pic0=<eventspec>,pic1=<eventspec>
480Sstevel@tonic-gate  *		[,cmask0=<maskspec>][,cmask1=<maskspec>]
490Sstevel@tonic-gate  *		[,umask0=<maskspec>][,umask1=<maskspec>]
500Sstevel@tonic-gate  *		[,inv[0|1]][,noedge[0|1]]
510Sstevel@tonic-gate  *		[,sys[0|1]][,nouser[0|1]]
520Sstevel@tonic-gate  *
530Sstevel@tonic-gate  * For example:
540Sstevel@tonic-gate  *	pic0=data_mem_refs,pic1=l2_ld,sys
550Sstevel@tonic-gate  * or
560Sstevel@tonic-gate  *	pic0=l2_ld,pic1=bus_drdy_clocks,umask1=0x20,nouser1
570Sstevel@tonic-gate  *
580Sstevel@tonic-gate  * By default, user event counting is enabled, system event counting
590Sstevel@tonic-gate  * is disabled.
600Sstevel@tonic-gate  *
610Sstevel@tonic-gate  * Note that Pentium and Pentium Pro have different event specifications.
620Sstevel@tonic-gate  *
630Sstevel@tonic-gate  * The two events must be named.  The names can be ascii or
640Sstevel@tonic-gate  * a decimal, octal or hexadecimal number as parsed by strtol(3C).
650Sstevel@tonic-gate  *
660Sstevel@tonic-gate  * The routine counts the number of errors encountered while parsing
670Sstevel@tonic-gate  * the string, if no errors are encountered, the event handle is
680Sstevel@tonic-gate  * returned.
690Sstevel@tonic-gate  */
700Sstevel@tonic-gate 
710Sstevel@tonic-gate const char *
cpc_getusage(int cpuver)720Sstevel@tonic-gate cpc_getusage(int cpuver)
730Sstevel@tonic-gate {
740Sstevel@tonic-gate 	switch (cpuver) {
750Sstevel@tonic-gate 	case CPC_PENTIUM_PRO_MMX:
760Sstevel@tonic-gate 	case CPC_PENTIUM_PRO:
770Sstevel@tonic-gate 		return ("pic0=<event0>,pic1=<event1> "
780Sstevel@tonic-gate 		    "[,sys[0|1]] "
790Sstevel@tonic-gate 		    "[,nouser[0|1]] "
800Sstevel@tonic-gate 		    "[,noedge[0|1]] "
810Sstevel@tonic-gate 		    "[,pc[0|1]] "
820Sstevel@tonic-gate 		    "[,int[0|1]] "
830Sstevel@tonic-gate 		    "[,inv[0|1]] "
840Sstevel@tonic-gate 		    "[,cmask[0|1]=<maskspec>] "
850Sstevel@tonic-gate 		    "[,umask[0|1]=<maskspec>] ");
860Sstevel@tonic-gate 	case CPC_PENTIUM_MMX:
870Sstevel@tonic-gate 	case CPC_PENTIUM:
880Sstevel@tonic-gate 		return ("pic0=<event0>,pic1=<event1> "
890Sstevel@tonic-gate 		    "[,sys[0|1]] "
900Sstevel@tonic-gate 		    "[,nouser[0|1]] "
910Sstevel@tonic-gate 		    "[,noedge[0|1]] "
920Sstevel@tonic-gate 		    "[,pc[0|1]]");
930Sstevel@tonic-gate 	default:
940Sstevel@tonic-gate 		return (NULL);
950Sstevel@tonic-gate 	}
960Sstevel@tonic-gate }
970Sstevel@tonic-gate 
980Sstevel@tonic-gate struct keyval {
990Sstevel@tonic-gate 	char *kv_token;
1000Sstevel@tonic-gate 	int (*kv_action)(const char *,
1010Sstevel@tonic-gate 	    const struct keyval *, int, char *, uint32_t *);
1020Sstevel@tonic-gate 	uint_t kv_regno;
1030Sstevel@tonic-gate 	uint32_t kv_mask;
1040Sstevel@tonic-gate 	int kv_shift;
1050Sstevel@tonic-gate };
1060Sstevel@tonic-gate 
1070Sstevel@tonic-gate /*ARGSUSED*/
1080Sstevel@tonic-gate static int
eightbits(const char * fn,const struct keyval * kv,int cpuver,char * value,uint32_t * bits)1090Sstevel@tonic-gate eightbits(const char *fn,
1100Sstevel@tonic-gate     const struct keyval *kv, int cpuver, char *value, uint32_t *bits)
1110Sstevel@tonic-gate {
1120Sstevel@tonic-gate 	char *eptr = NULL;
1130Sstevel@tonic-gate 	long l;
1140Sstevel@tonic-gate 
1150Sstevel@tonic-gate 	if (value == NULL) {
1160Sstevel@tonic-gate 		__cpc_error(fn, gettext("missing '%s' value\n"),
1170Sstevel@tonic-gate 		    kv->kv_token);
1180Sstevel@tonic-gate 		return (-1);
1190Sstevel@tonic-gate 	}
1200Sstevel@tonic-gate 	l = strtol(value, &eptr, 0);
1210Sstevel@tonic-gate 	if (value == eptr || l < 0 || l > UINT8_MAX) {
1220Sstevel@tonic-gate 		__cpc_error(fn, gettext("bad '%s' value\n"), kv->kv_token);
1230Sstevel@tonic-gate 		return (-1);
1240Sstevel@tonic-gate 	}
1250Sstevel@tonic-gate 	bits[kv->kv_regno] |= ((uint8_t)l & kv->kv_mask) << kv->kv_shift;
1260Sstevel@tonic-gate 	return (0);
1270Sstevel@tonic-gate }
1280Sstevel@tonic-gate 
1290Sstevel@tonic-gate static int
picbits(const char * fn,const struct keyval * kv,int cpuver,char * value,uint32_t * bits)1300Sstevel@tonic-gate picbits(const char *fn,
1310Sstevel@tonic-gate     const struct keyval *kv, int cpuver, char *value, uint32_t *bits)
1320Sstevel@tonic-gate {
1330Sstevel@tonic-gate 	uint8_t val8;
1340Sstevel@tonic-gate 	uint_t regno;
1350Sstevel@tonic-gate 
1360Sstevel@tonic-gate 	regno = strcmp(kv->kv_token, "pic0") == 0 ? 0 : 1;
1370Sstevel@tonic-gate 
1380Sstevel@tonic-gate 	if (value == NULL) {
1390Sstevel@tonic-gate 		__cpc_error(fn, gettext("missing '%s' value\n"),
1400Sstevel@tonic-gate 		    kv->kv_token);
1410Sstevel@tonic-gate 		return (-1);
1420Sstevel@tonic-gate 	}
1430Sstevel@tonic-gate 
1440Sstevel@tonic-gate 	if (__cpc_name_to_reg(cpuver, regno, value, &val8) != 0) {
1450Sstevel@tonic-gate 		switch (cpuver) {
1460Sstevel@tonic-gate 		case CPC_PENTIUM_PRO_MMX:
1470Sstevel@tonic-gate 		case CPC_PENTIUM_PRO:
1480Sstevel@tonic-gate 			assert(kv->kv_regno == regno);
1490Sstevel@tonic-gate 			__cpc_error(fn, gettext(
1500Sstevel@tonic-gate 			    "PerfCtr%d cannot measure '%s' on this cpu\n"),
1510Sstevel@tonic-gate 			    regno, value);
1520Sstevel@tonic-gate 			break;
1530Sstevel@tonic-gate 		case CPC_PENTIUM_MMX:
1540Sstevel@tonic-gate 		case CPC_PENTIUM:
1550Sstevel@tonic-gate 			assert(kv->kv_regno == 0);
1560Sstevel@tonic-gate 			__cpc_error(fn, gettext(
1570Sstevel@tonic-gate 			    "CTR%d cannot measure '%s' on this cpu\n"),
1580Sstevel@tonic-gate 			    regno, value);
1590Sstevel@tonic-gate 			break;
1600Sstevel@tonic-gate 		}
1610Sstevel@tonic-gate 		return (-1);
1620Sstevel@tonic-gate 	}
1630Sstevel@tonic-gate 	bits[kv->kv_regno] |= (val8 & kv->kv_mask) << kv->kv_shift;
1640Sstevel@tonic-gate 	return (0);
1650Sstevel@tonic-gate }
1660Sstevel@tonic-gate 
1670Sstevel@tonic-gate /*ARGSUSED2*/
1680Sstevel@tonic-gate static int
bitclr(const char * fn,const struct keyval * kv,int cpuver,char * value,uint32_t * bits)1690Sstevel@tonic-gate bitclr(const char *fn,
1700Sstevel@tonic-gate     const struct keyval *kv, int cpuver, char *value, uint32_t *bits)
1710Sstevel@tonic-gate {
1720Sstevel@tonic-gate 	if (value != NULL) {
1730Sstevel@tonic-gate 		__cpc_error(fn, gettext("bad arg to '%s'\n"), kv->kv_token);
1740Sstevel@tonic-gate 		return (-1);
1750Sstevel@tonic-gate 	}
1760Sstevel@tonic-gate 	bits[kv->kv_regno] &= ~(kv->kv_mask << kv->kv_shift);
1770Sstevel@tonic-gate 	return (0);
1780Sstevel@tonic-gate }
1790Sstevel@tonic-gate 
1800Sstevel@tonic-gate /*ARGSUSED2*/
1810Sstevel@tonic-gate static int
bitset(const char * fn,const struct keyval * kv,int cpuver,char * value,uint32_t * bits)1820Sstevel@tonic-gate bitset(const char *fn,
1830Sstevel@tonic-gate     const struct keyval *kv, int cpuver, char *value, uint32_t *bits)
1840Sstevel@tonic-gate {
1850Sstevel@tonic-gate 	if (value != NULL) {
1860Sstevel@tonic-gate 		__cpc_error(fn, gettext("bad arg to '%s'\n"), kv->kv_token);
1870Sstevel@tonic-gate 		return (-1);
1880Sstevel@tonic-gate 	}
1890Sstevel@tonic-gate 	bits[kv->kv_regno] |= (kv->kv_mask << kv->kv_shift);
1900Sstevel@tonic-gate 	return (0);
1910Sstevel@tonic-gate }
1920Sstevel@tonic-gate 
1930Sstevel@tonic-gate static int
nextpair(const char * fn,const struct keyval * kv,int cpuver,char * value,uint32_t * bits)1940Sstevel@tonic-gate nextpair(const char *fn,
1950Sstevel@tonic-gate     const struct keyval *kv, int cpuver, char *value, uint32_t *bits)
1960Sstevel@tonic-gate {
1970Sstevel@tonic-gate 	int rv;
1980Sstevel@tonic-gate 
1990Sstevel@tonic-gate 	if (value != NULL) {
2000Sstevel@tonic-gate 		__cpc_error(fn, gettext("bad arg to '%s'\n"), kv->kv_token);
2010Sstevel@tonic-gate 		return (-1);
2020Sstevel@tonic-gate 	}
2030Sstevel@tonic-gate 	kv++;
2040Sstevel@tonic-gate 	if ((rv = kv->kv_action(fn, kv, cpuver, value, bits)) != 0)
2050Sstevel@tonic-gate 		return (rv);
2060Sstevel@tonic-gate 	kv++;
2070Sstevel@tonic-gate 	return (kv->kv_action(fn, kv, cpuver, value, bits));
2080Sstevel@tonic-gate }
2090Sstevel@tonic-gate 
2100Sstevel@tonic-gate /*
2110Sstevel@tonic-gate  * This token table must match the keyval tables below.
2120Sstevel@tonic-gate  */
2130Sstevel@tonic-gate 
2140Sstevel@tonic-gate static char * const tokens[] = {
2150Sstevel@tonic-gate #define	D_pic0		0
2160Sstevel@tonic-gate 	"pic0",			/* takes a valid event name */
2170Sstevel@tonic-gate #define	D_pic1		1
2180Sstevel@tonic-gate 	"pic1",			/* takes a valid event name */
2190Sstevel@tonic-gate #define	D_nouser	2
2200Sstevel@tonic-gate 	"nouser",		/* disables user counts */
2210Sstevel@tonic-gate #define	D_nouser0	3
2220Sstevel@tonic-gate 	"nouser0",
2230Sstevel@tonic-gate #define	D_nouser1	4
2240Sstevel@tonic-gate 	"nouser1",
2250Sstevel@tonic-gate #define	D_sys		5
2260Sstevel@tonic-gate 	"sys",			/* enables system counts */
2270Sstevel@tonic-gate #define	D_sys0		6
2280Sstevel@tonic-gate 	"sys0",
2290Sstevel@tonic-gate #define	D_sys1		7
2300Sstevel@tonic-gate 	"sys1",
2310Sstevel@tonic-gate #define	D_noedge	8
2320Sstevel@tonic-gate 	"noedge",		/* disable edge detect */
2330Sstevel@tonic-gate #define	D_noedge0	9
2340Sstevel@tonic-gate 	"noedge0",
2350Sstevel@tonic-gate #define	D_noedge1	10
2360Sstevel@tonic-gate 	"noedge1",
2370Sstevel@tonic-gate #define	D_pc		11
2380Sstevel@tonic-gate 	"pc",			/* sets pin control high */
2390Sstevel@tonic-gate #define	D_pc0		12
2400Sstevel@tonic-gate 	"pc0",
2410Sstevel@tonic-gate #define	D_pc1		13
2420Sstevel@tonic-gate 	"pc1",
2430Sstevel@tonic-gate 
2440Sstevel@tonic-gate /*
2450Sstevel@tonic-gate  * These additional keywords are for Pentium Pro / Pentium II machines.
2460Sstevel@tonic-gate  */
2470Sstevel@tonic-gate #define	D_int		14
2480Sstevel@tonic-gate 	"int",			/* enable interrupt on counter overflow */
2490Sstevel@tonic-gate #define	D_int0		15
2500Sstevel@tonic-gate 	"int0",
2510Sstevel@tonic-gate #define	D_int1		16
2520Sstevel@tonic-gate 	"int1",
2530Sstevel@tonic-gate #define	D_inv		17
2540Sstevel@tonic-gate 	"inv",			/* invert cmask comparison */
2550Sstevel@tonic-gate #define	D_inv0		18
2560Sstevel@tonic-gate 	"inv0",
2570Sstevel@tonic-gate #define	D_inv1		19
2580Sstevel@tonic-gate 	"inv1",
2590Sstevel@tonic-gate #define	D_umask0	20
2600Sstevel@tonic-gate 	"umask0",		/* PerfCtr0 unit mask */
2610Sstevel@tonic-gate #define	D_umask1	21
2620Sstevel@tonic-gate 	"umask1",		/* PerfCtr1 unit mask */
2630Sstevel@tonic-gate #define	D_cmask0	22
2640Sstevel@tonic-gate 	"cmask0",		/* PerfCtr0 counter mask */
2650Sstevel@tonic-gate #define	D_cmask1	23
2660Sstevel@tonic-gate 	"cmask1",		/* PerfCtr1 counter mask */
2670Sstevel@tonic-gate 	NULL
2680Sstevel@tonic-gate };
2690Sstevel@tonic-gate 
2700Sstevel@tonic-gate static const struct keyval p6_keyvals[] = {
2710Sstevel@tonic-gate 	{ "pic0",	picbits,	0,
2720Sstevel@tonic-gate 		CPC_P6_PES_PIC0_MASK,	0 },
2730Sstevel@tonic-gate 	{ "pic1",	picbits,	1,
2740Sstevel@tonic-gate 		CPC_P6_PES_PIC1_MASK,	0 },
2750Sstevel@tonic-gate 	{ "nouser",	nextpair },
2760Sstevel@tonic-gate 	{ "nouser0",	bitclr,		0,
2770Sstevel@tonic-gate 		UINT32_C(1),		CPC_P6_PES_USR },
2780Sstevel@tonic-gate 	{ "nouser1",	bitclr,		1,
2790Sstevel@tonic-gate 		UINT32_C(1),		CPC_P6_PES_USR },
2800Sstevel@tonic-gate 	{ "sys",	nextpair },
2810Sstevel@tonic-gate 	{ "sys0",	bitset,		0,
2820Sstevel@tonic-gate 		UINT32_C(1),		CPC_P6_PES_OS },
2830Sstevel@tonic-gate 	{ "sys1",	bitset,		1,
2840Sstevel@tonic-gate 		UINT32_C(1),		CPC_P6_PES_OS },
2850Sstevel@tonic-gate 	{ "noedge",	nextpair },
2860Sstevel@tonic-gate 	{ "noedge0",	bitclr,		0,
2870Sstevel@tonic-gate 		UINT32_C(1),		CPC_P6_PES_E },
2880Sstevel@tonic-gate 	{ "noedge1",	bitclr,		1,
2890Sstevel@tonic-gate 		UINT32_C(1),		CPC_P6_PES_E },
2900Sstevel@tonic-gate 	{ "pc",		nextpair },
2910Sstevel@tonic-gate 	{ "pc0",	bitset,		0,
2920Sstevel@tonic-gate 		UINT32_C(1),		CPC_P6_PES_PC },
2930Sstevel@tonic-gate 	{ "pc1",	bitset,		1,
2940Sstevel@tonic-gate 		UINT32_C(1),		CPC_P6_PES_PC },
2950Sstevel@tonic-gate 	{ "int",	nextpair },
2960Sstevel@tonic-gate 	{ "int0",	bitset,		0,
2970Sstevel@tonic-gate 		UINT32_C(1),		CPC_P6_PES_INT },
2980Sstevel@tonic-gate 	{ "int1",	bitset,		1,
2990Sstevel@tonic-gate 		UINT32_C(1),		CPC_P6_PES_INT },
3000Sstevel@tonic-gate 	{ "inv",	nextpair },
3010Sstevel@tonic-gate 	{ "inv0",	bitset,		0,
3020Sstevel@tonic-gate 		UINT32_C(1),		CPC_P6_PES_INV },
3030Sstevel@tonic-gate 	{ "inv1",	bitset,		1,
3040Sstevel@tonic-gate 		UINT32_C(1),		CPC_P6_PES_INV },
3050Sstevel@tonic-gate 	{ "umask0",	eightbits,	0,
3060Sstevel@tonic-gate 		CPC_P6_PES_UMASK_MASK,	CPC_P6_PES_UMASK_SHIFT },
3070Sstevel@tonic-gate 	{ "umask1",	eightbits,	1,
3080Sstevel@tonic-gate 		CPC_P6_PES_UMASK_MASK,	CPC_P6_PES_UMASK_SHIFT },
3090Sstevel@tonic-gate 	{ "cmask0",	eightbits,	0,
3100Sstevel@tonic-gate 		CPC_P6_PES_CMASK_MASK,	CPC_P6_PES_CMASK_SHIFT },
3110Sstevel@tonic-gate 	{ "cmask1",	eightbits,	1,
3120Sstevel@tonic-gate 		CPC_P6_PES_CMASK_MASK,	CPC_P6_PES_CMASK_SHIFT },
3130Sstevel@tonic-gate };
3140Sstevel@tonic-gate 
3150Sstevel@tonic-gate /*
3160Sstevel@tonic-gate  * Note that this table -must- be an identically indexed
3170Sstevel@tonic-gate  * subset of p6_keyvals.
3180Sstevel@tonic-gate  */
3190Sstevel@tonic-gate static const struct keyval p5_keyvals[] = {
3200Sstevel@tonic-gate 	{ "pic0",	picbits,	0,
3210Sstevel@tonic-gate 		CPC_P5_CESR_ES0_MASK,	CPC_P5_CESR_ES0_SHIFT },
3220Sstevel@tonic-gate 	{ "pic1",	picbits,	0,
3230Sstevel@tonic-gate 		CPC_P5_CESR_ES1_MASK,	CPC_P5_CESR_ES1_SHIFT },
3240Sstevel@tonic-gate 	{ "nouser",	nextpair },
3250Sstevel@tonic-gate 	{ "nouser0",	bitclr,		0,
3260Sstevel@tonic-gate 		UINT32_C(1),		CPC_P5_CESR_USR0 },
3270Sstevel@tonic-gate 	{ "nouser1",	bitclr,		0,
3280Sstevel@tonic-gate 		UINT32_C(1),		CPC_P5_CESR_USR1 },
3290Sstevel@tonic-gate 	{ "sys",	nextpair },
3300Sstevel@tonic-gate 	{ "sys0",	bitset,		0,
3310Sstevel@tonic-gate 		UINT32_C(1),		CPC_P5_CESR_OS0 },
3320Sstevel@tonic-gate 	{ "sys1",	bitset,		0,
3330Sstevel@tonic-gate 		UINT32_C(1),		CPC_P5_CESR_OS1 },
3340Sstevel@tonic-gate 	{ "noedge",	nextpair },
3350Sstevel@tonic-gate 	{ "noedge0",	bitset,		0,
3360Sstevel@tonic-gate 		UINT32_C(1),		CPC_P5_CESR_CLK0 },
3370Sstevel@tonic-gate 	{ "noedge1",	bitset,		0,
3380Sstevel@tonic-gate 		UINT32_C(1),		CPC_P5_CESR_CLK1 },
3390Sstevel@tonic-gate 	{ "pc",		nextpair },
3400Sstevel@tonic-gate 	{ "pc0",	bitset,		0,
3410Sstevel@tonic-gate 		UINT32_C(1),		CPC_P5_CESR_PC0 },
3420Sstevel@tonic-gate 	{ "pc1",	bitset,		0,
3430Sstevel@tonic-gate 		UINT32_C(1),		CPC_P5_CESR_PC1 },
3440Sstevel@tonic-gate };
3450Sstevel@tonic-gate 
3460Sstevel@tonic-gate #if !defined(NDEBUG)
3470Sstevel@tonic-gate #pragma	init(__tablecheck)
3480Sstevel@tonic-gate 
3490Sstevel@tonic-gate static void
__tablecheck(void)3500Sstevel@tonic-gate __tablecheck(void)
3510Sstevel@tonic-gate {
3520Sstevel@tonic-gate 	uint_t ntokens = sizeof (tokens) / sizeof (tokens[0]) - 1;
3530Sstevel@tonic-gate 	uint_t p6_nkeys = sizeof (p6_keyvals) / sizeof (p6_keyvals[0]);
3540Sstevel@tonic-gate 	uint_t p5_nkeys = sizeof (p5_keyvals) / sizeof (p5_keyvals[0]);
3550Sstevel@tonic-gate 	uint_t n;
3560Sstevel@tonic-gate 
3570Sstevel@tonic-gate 	assert(ntokens == p6_nkeys);
3580Sstevel@tonic-gate 	for (n = 0; n < ntokens; n++)
3590Sstevel@tonic-gate 		assert(strcmp(tokens[n], p6_keyvals[n].kv_token) == 0);
3600Sstevel@tonic-gate 	assert(p6_nkeys >= p5_nkeys);
3610Sstevel@tonic-gate 	for (n = 0; n < p5_nkeys; n++)
3620Sstevel@tonic-gate 		assert(strcmp(tokens[n], p5_keyvals[n].kv_token) == 0);
3630Sstevel@tonic-gate }
3640Sstevel@tonic-gate 
3650Sstevel@tonic-gate #endif	/* !NDEBUG */
3660Sstevel@tonic-gate 
3670Sstevel@tonic-gate int
cpc_strtoevent(int cpuver,const char * spec,cpc_event_t * event)3680Sstevel@tonic-gate cpc_strtoevent(int cpuver, const char *spec, cpc_event_t *event)
3690Sstevel@tonic-gate {
3700Sstevel@tonic-gate 	static const char fn[] = "strtoevent";
3710Sstevel@tonic-gate 	char *value;
3720Sstevel@tonic-gate 	char *pic[2];
3730Sstevel@tonic-gate 	char *opts;
3740Sstevel@tonic-gate 	int errcnt = 0;
3750Sstevel@tonic-gate 	uint_t ntokens;
3760Sstevel@tonic-gate 	const struct keyval *keyvals;
3770Sstevel@tonic-gate 	uint32_t *bits;
3780Sstevel@tonic-gate 
3790Sstevel@tonic-gate 	if (spec == NULL)
3800Sstevel@tonic-gate 		return (errcnt = 1);
3810Sstevel@tonic-gate 
3820Sstevel@tonic-gate 	bzero(event, sizeof (*event));
3830Sstevel@tonic-gate 	switch (event->ce_cpuver = cpuver) {
3840Sstevel@tonic-gate 	case CPC_PENTIUM_PRO_MMX:
3850Sstevel@tonic-gate 	case CPC_PENTIUM_PRO:
3860Sstevel@tonic-gate 		keyvals = p6_keyvals;
3870Sstevel@tonic-gate 		ntokens = sizeof (p6_keyvals) / sizeof (p6_keyvals[0]);
3880Sstevel@tonic-gate 		bits = &event->ce_pes[0];
3890Sstevel@tonic-gate 		bits[0] = bits[1] =
3900Sstevel@tonic-gate 		    (1u << CPC_P6_PES_USR) | (1u << CPC_P6_PES_E);
3910Sstevel@tonic-gate 		break;
3920Sstevel@tonic-gate 	case CPC_PENTIUM_MMX:
3930Sstevel@tonic-gate 	case CPC_PENTIUM:
3940Sstevel@tonic-gate 		keyvals = p5_keyvals;
3950Sstevel@tonic-gate 		ntokens = sizeof (p5_keyvals) / sizeof (p5_keyvals[0]);
3960Sstevel@tonic-gate 		bits = &event->ce_cesr;
3970Sstevel@tonic-gate 		bits[0] =
3980Sstevel@tonic-gate 		    (1u << CPC_P5_CESR_USR0) | (1u << CPC_P5_CESR_USR1);
3990Sstevel@tonic-gate 		break;
4000Sstevel@tonic-gate 	default:
4010Sstevel@tonic-gate 		return (errcnt = 1);
4020Sstevel@tonic-gate 	}
4030Sstevel@tonic-gate 
4040Sstevel@tonic-gate 	pic[0] = pic[1] = NULL;
4050Sstevel@tonic-gate 
406*13093SRoger.Faulkner@Oracle.COM 	opts = strdupa(spec);
4070Sstevel@tonic-gate 	while (*opts != '\0') {
4080Sstevel@tonic-gate 		const struct keyval *kv;
4090Sstevel@tonic-gate 		int idx = getsubopt(&opts, tokens, &value);
4100Sstevel@tonic-gate 
4110Sstevel@tonic-gate 		if (idx >= 0 && idx < ntokens) {
4120Sstevel@tonic-gate 			kv = &keyvals[idx];
4130Sstevel@tonic-gate 			if (kv->kv_action(fn, kv, cpuver, value, bits) != 0) {
4140Sstevel@tonic-gate 				errcnt++;
4150Sstevel@tonic-gate 				break;
4160Sstevel@tonic-gate 			}
4170Sstevel@tonic-gate 
4180Sstevel@tonic-gate 			if (idx == D_pic0) {
4190Sstevel@tonic-gate 				if (pic[0] != NULL) {
4200Sstevel@tonic-gate 					__cpc_error(fn,
4210Sstevel@tonic-gate 					    "repeated '%s' token\n",
4220Sstevel@tonic-gate 					    tokens[idx]);
4230Sstevel@tonic-gate 					errcnt++;
4240Sstevel@tonic-gate 					break;
4250Sstevel@tonic-gate 				}
4260Sstevel@tonic-gate 				pic[0] = value;
4270Sstevel@tonic-gate 			} else if (idx == D_pic1) {
4280Sstevel@tonic-gate 				if (pic[1] != NULL) {
4290Sstevel@tonic-gate 					__cpc_error(fn,
4300Sstevel@tonic-gate 					    "repeated '%s' token\n",
4310Sstevel@tonic-gate 					    tokens[idx]);
4320Sstevel@tonic-gate 					errcnt++;
4330Sstevel@tonic-gate 					break;
4340Sstevel@tonic-gate 				}
4350Sstevel@tonic-gate 				pic[1] = value;
4360Sstevel@tonic-gate 			}
4370Sstevel@tonic-gate 		} else if (idx == -1) {
4380Sstevel@tonic-gate 			/*
4390Sstevel@tonic-gate 			 * The token given wasn't recognized.
4400Sstevel@tonic-gate 			 * See if it was an implicit pic specification..
4410Sstevel@tonic-gate 			 */
4420Sstevel@tonic-gate 			if (pic[0] == NULL) {
4430Sstevel@tonic-gate 				kv = &keyvals[D_pic0];
4440Sstevel@tonic-gate 				if (kv->kv_action(fn,
4450Sstevel@tonic-gate 				    kv, cpuver, value, bits) != 0) {
4460Sstevel@tonic-gate 					errcnt++;
4470Sstevel@tonic-gate 					break;
4480Sstevel@tonic-gate 				}
4490Sstevel@tonic-gate 				pic[0] = value;
4500Sstevel@tonic-gate 			} else if (pic[1] == NULL) {
4510Sstevel@tonic-gate 				kv = &keyvals[D_pic1];
4520Sstevel@tonic-gate 				if (kv->kv_action(fn,
4530Sstevel@tonic-gate 				    kv, cpuver, value, bits) != 0) {
4540Sstevel@tonic-gate 					errcnt++;
4550Sstevel@tonic-gate 					break;
4560Sstevel@tonic-gate 				}
4570Sstevel@tonic-gate 				pic[1] = value;
4580Sstevel@tonic-gate 			} else {
4590Sstevel@tonic-gate 				__cpc_error(fn,
4600Sstevel@tonic-gate 				    gettext("bad token '%s'\n"), value);
4610Sstevel@tonic-gate 				errcnt++;
4620Sstevel@tonic-gate 				break;
4630Sstevel@tonic-gate 			}
4640Sstevel@tonic-gate 		} else {
4650Sstevel@tonic-gate 			if (idx >= 0 &&
4660Sstevel@tonic-gate 			    idx < sizeof (tokens) / sizeof (tokens[0]))
4670Sstevel@tonic-gate 				__cpc_error(fn,
4680Sstevel@tonic-gate 				    gettext("bad token '%s'\n"), tokens[idx]);
4690Sstevel@tonic-gate 			else
4700Sstevel@tonic-gate 				__cpc_error(fn, gettext("bad token\n"));
4710Sstevel@tonic-gate 			errcnt++;
4720Sstevel@tonic-gate 			break;
4730Sstevel@tonic-gate 		}
4740Sstevel@tonic-gate 	}
4750Sstevel@tonic-gate 
4760Sstevel@tonic-gate 	if (pic[0] == NULL || pic[1] == NULL) {
4770Sstevel@tonic-gate 		__cpc_error(fn, gettext("two events must be specified\n"));
4780Sstevel@tonic-gate 		errcnt++;
4790Sstevel@tonic-gate 	}
4800Sstevel@tonic-gate 
4810Sstevel@tonic-gate 	return (errcnt);
4820Sstevel@tonic-gate }
4830Sstevel@tonic-gate 
4840Sstevel@tonic-gate /*
4850Sstevel@tonic-gate  * Return a printable description of the control registers.
4860Sstevel@tonic-gate  *
4870Sstevel@tonic-gate  * This routine should always succeed (notwithstanding heap problems),
4880Sstevel@tonic-gate  * but may not be able to correctly decode the registers, if, for
4890Sstevel@tonic-gate  * example, a new processor is under test.
4900Sstevel@tonic-gate  *
4910Sstevel@tonic-gate  * The caller is responsible for free(3c)ing the string returned.
4920Sstevel@tonic-gate  */
4930Sstevel@tonic-gate 
4940Sstevel@tonic-gate static void
flagstostr(char * buf,int flag0,int flag1,int defvalue,char * tok)4950Sstevel@tonic-gate flagstostr(char *buf, int flag0, int flag1, int defvalue, char *tok)
4960Sstevel@tonic-gate {
4970Sstevel@tonic-gate 	buf += strlen(buf);
4980Sstevel@tonic-gate 	if (flag0 != defvalue) {
4990Sstevel@tonic-gate 		if (flag1 != defvalue)
5000Sstevel@tonic-gate 			(void) sprintf(buf, ",%s", tok);
5010Sstevel@tonic-gate 		else
5020Sstevel@tonic-gate 			(void) sprintf(buf, ",%s0", tok);
5030Sstevel@tonic-gate 	} else {
5040Sstevel@tonic-gate 		if (flag1 != defvalue)
5050Sstevel@tonic-gate 			(void) sprintf(buf, ",%s1", tok);
5060Sstevel@tonic-gate 	}
5070Sstevel@tonic-gate }
5080Sstevel@tonic-gate 
5090Sstevel@tonic-gate static void
masktostr(char * buf,uint8_t bits,char * tok)5100Sstevel@tonic-gate masktostr(char *buf, uint8_t bits, char *tok)
5110Sstevel@tonic-gate {
5120Sstevel@tonic-gate 	if (bits != 0) {
5130Sstevel@tonic-gate 		buf += strlen(buf);
5140Sstevel@tonic-gate 		(void) sprintf(buf, ",%s=0x%x", tok, bits);
5150Sstevel@tonic-gate 	}
5160Sstevel@tonic-gate }
5170Sstevel@tonic-gate 
5180Sstevel@tonic-gate static char *
val8tostr(uint8_t bits)5190Sstevel@tonic-gate val8tostr(uint8_t bits)
5200Sstevel@tonic-gate {
5210Sstevel@tonic-gate 	char buf[2 + 2 + 1];	/* 0x %2x \0 */
5220Sstevel@tonic-gate 	(void) snprintf(buf, sizeof (buf), "0x%x", bits);
5230Sstevel@tonic-gate 	return (strdup(buf));
5240Sstevel@tonic-gate }
5250Sstevel@tonic-gate 
5260Sstevel@tonic-gate static char *
regtostr(int cpuver,int regno,uint8_t bits)5270Sstevel@tonic-gate regtostr(int cpuver, int regno, uint8_t bits)
5280Sstevel@tonic-gate {
5290Sstevel@tonic-gate 	const char *sname;
5300Sstevel@tonic-gate 
5310Sstevel@tonic-gate 	if ((sname = __cpc_reg_to_name(cpuver, regno, bits)) != NULL)
5320Sstevel@tonic-gate 		return (strdup(sname));
5330Sstevel@tonic-gate 	return (val8tostr(bits));
5340Sstevel@tonic-gate }
5350Sstevel@tonic-gate 
5360Sstevel@tonic-gate struct xpes {
5370Sstevel@tonic-gate 	uint8_t cmask, umask, evsel;
5380Sstevel@tonic-gate 	int usr, sys, edge, inv, irupt, pc;
5390Sstevel@tonic-gate };
5400Sstevel@tonic-gate 
5410Sstevel@tonic-gate /*ARGSUSED1*/
5420Sstevel@tonic-gate static void
unmake_pes(uint32_t pes,int cpuver,struct xpes * xpes)5430Sstevel@tonic-gate unmake_pes(uint32_t pes, int cpuver, struct xpes *xpes)
5440Sstevel@tonic-gate {
5450Sstevel@tonic-gate 	xpes->cmask = (uint8_t)(pes >> CPC_P6_PES_CMASK_SHIFT);
5460Sstevel@tonic-gate 	xpes->pc = (pes >> CPC_P6_PES_PC) & 1u;
5470Sstevel@tonic-gate 	xpes->inv = (pes >> CPC_P6_PES_INV) & 1u;
5480Sstevel@tonic-gate 	xpes->irupt = (pes >> CPC_P6_PES_INT) & 1u;
5490Sstevel@tonic-gate 	xpes->edge = (pes >> CPC_P6_PES_E) & 1u;
5500Sstevel@tonic-gate 	xpes->sys = (pes >> CPC_P6_PES_OS) & 1u;
5510Sstevel@tonic-gate 	xpes->usr = (pes >> CPC_P6_PES_USR) & 1u;
5520Sstevel@tonic-gate 	xpes->umask = (uint8_t)(pes >> CPC_P6_PES_UMASK_SHIFT);
5530Sstevel@tonic-gate 	xpes->evsel = (uint8_t)pes;
5540Sstevel@tonic-gate }
5550Sstevel@tonic-gate 
5560Sstevel@tonic-gate struct xcesr {
5570Sstevel@tonic-gate 	uint8_t evsel[2];
5580Sstevel@tonic-gate 	int usr[2], sys[2], clk[2], pc[2];
5590Sstevel@tonic-gate };
5600Sstevel@tonic-gate 
5610Sstevel@tonic-gate /*ARGSUSED1*/
5620Sstevel@tonic-gate static void
unmake_cesr(uint32_t cesr,int cpuver,struct xcesr * xcesr)5630Sstevel@tonic-gate unmake_cesr(uint32_t cesr, int cpuver, struct xcesr *xcesr)
5640Sstevel@tonic-gate {
5650Sstevel@tonic-gate 	xcesr->evsel[0] = (cesr >> CPC_P5_CESR_ES0_SHIFT) &
5660Sstevel@tonic-gate 	    CPC_P5_CESR_ES0_MASK;
5670Sstevel@tonic-gate 	xcesr->evsel[1] = (cesr >> CPC_P5_CESR_ES1_SHIFT) &
5680Sstevel@tonic-gate 	    CPC_P5_CESR_ES1_MASK;
5690Sstevel@tonic-gate 	xcesr->usr[0] = (cesr >> CPC_P5_CESR_USR0) & 1u;
5700Sstevel@tonic-gate 	xcesr->usr[1] = (cesr >> CPC_P5_CESR_USR1) & 1u;
5710Sstevel@tonic-gate 	xcesr->sys[0] = (cesr >> CPC_P5_CESR_OS0) & 1u;
5720Sstevel@tonic-gate 	xcesr->sys[1] = (cesr >> CPC_P5_CESR_OS1) & 1u;
5730Sstevel@tonic-gate 	xcesr->clk[0] = (cesr >> CPC_P5_CESR_CLK0) & 1u;
5740Sstevel@tonic-gate 	xcesr->clk[1] = (cesr >> CPC_P5_CESR_CLK1) & 1u;
5750Sstevel@tonic-gate 	xcesr->pc[0] = (cesr >> CPC_P5_CESR_PC0) & 1u;
5760Sstevel@tonic-gate 	xcesr->pc[1] = (cesr >> CPC_P5_CESR_PC1) & 1u;
5770Sstevel@tonic-gate 	/*
5780Sstevel@tonic-gate 	 * If usr and sys are both disabled, the counter is disabled.
5790Sstevel@tonic-gate 	 */
5800Sstevel@tonic-gate 	if (xcesr->usr[0] == 0 && xcesr->sys[0] == 0)
5810Sstevel@tonic-gate 		xcesr->clk[0] = 0;
5820Sstevel@tonic-gate 	if (xcesr->usr[1] == 0 && xcesr->sys[1] == 0)
5830Sstevel@tonic-gate 		xcesr->clk[1] = 0;
5840Sstevel@tonic-gate }
5850Sstevel@tonic-gate 
5860Sstevel@tonic-gate char *
cpc_eventtostr(cpc_event_t * event)5870Sstevel@tonic-gate cpc_eventtostr(cpc_event_t *event)
5880Sstevel@tonic-gate {
5890Sstevel@tonic-gate 	char *pic[2];
5900Sstevel@tonic-gate 	char buffer[1024];
5910Sstevel@tonic-gate 	int cpuver = event->ce_cpuver;
5920Sstevel@tonic-gate 
5930Sstevel@tonic-gate 	switch (cpuver) {
5940Sstevel@tonic-gate 	case CPC_PENTIUM_PRO_MMX:
5950Sstevel@tonic-gate 	case CPC_PENTIUM_PRO:
5960Sstevel@tonic-gate 	{
5970Sstevel@tonic-gate 		struct xpes xpes[2];
5980Sstevel@tonic-gate 
5990Sstevel@tonic-gate 		unmake_pes(event->ce_pes[0], cpuver, &xpes[0]);
6000Sstevel@tonic-gate 		if ((pic[0] = regtostr(cpuver, 0, xpes[0].evsel)) == NULL)
6010Sstevel@tonic-gate 			return (NULL);
6020Sstevel@tonic-gate 
6030Sstevel@tonic-gate 		unmake_pes(event->ce_pes[1], cpuver, &xpes[1]);
6040Sstevel@tonic-gate 		if ((pic[1] = regtostr(cpuver, 1, xpes[1].evsel)) == NULL) {
6050Sstevel@tonic-gate 			free(pic[0]);
6060Sstevel@tonic-gate 			return (NULL);
6070Sstevel@tonic-gate 		}
6080Sstevel@tonic-gate 		(void) snprintf(buffer, sizeof (buffer), "%s=%s,%s=%s",
6090Sstevel@tonic-gate 		    tokens[D_pic0], pic[0], tokens[D_pic1], pic[1]);
6100Sstevel@tonic-gate 		free(pic[1]);
6110Sstevel@tonic-gate 		free(pic[0]);
6120Sstevel@tonic-gate 		masktostr(buffer, xpes[0].cmask, tokens[D_cmask0]);
6130Sstevel@tonic-gate 		masktostr(buffer, xpes[1].cmask, tokens[D_cmask1]);
6140Sstevel@tonic-gate 		masktostr(buffer, xpes[0].umask, tokens[D_umask0]);
6150Sstevel@tonic-gate 		masktostr(buffer, xpes[1].umask, tokens[D_umask1]);
6160Sstevel@tonic-gate 		flagstostr(buffer,
6170Sstevel@tonic-gate 		    xpes[0].usr, xpes[1].usr, 1, tokens[D_nouser]);
6180Sstevel@tonic-gate 		flagstostr(buffer,
6190Sstevel@tonic-gate 		    xpes[0].sys, xpes[1].sys, 0, tokens[D_sys]);
6200Sstevel@tonic-gate 		flagstostr(buffer,
6210Sstevel@tonic-gate 		    xpes[0].edge, xpes[1].edge, 1, tokens[D_noedge]);
6220Sstevel@tonic-gate 		flagstostr(buffer,
6230Sstevel@tonic-gate 		    xpes[0].irupt, xpes[1].irupt, 0, tokens[D_int]);
6240Sstevel@tonic-gate 		flagstostr(buffer,
6250Sstevel@tonic-gate 		    xpes[0].inv, xpes[1].inv, 0, tokens[D_inv]);
6260Sstevel@tonic-gate 		flagstostr(buffer,
6270Sstevel@tonic-gate 		    xpes[0].pc, xpes[1].pc, 0, tokens[D_pc]);
628*13093SRoger.Faulkner@Oracle.COM 		break;
629*13093SRoger.Faulkner@Oracle.COM 	}
6300Sstevel@tonic-gate 	case CPC_PENTIUM_MMX:
6310Sstevel@tonic-gate 	case CPC_PENTIUM:
6320Sstevel@tonic-gate 	{
6330Sstevel@tonic-gate 		struct xcesr xcesr;
6340Sstevel@tonic-gate 
6350Sstevel@tonic-gate 		unmake_cesr(event->ce_cesr, cpuver, &xcesr);
6360Sstevel@tonic-gate 		if ((pic[0] = regtostr(cpuver, 0, xcesr.evsel[0])) == NULL)
6370Sstevel@tonic-gate 			return (NULL);
6380Sstevel@tonic-gate 		if ((pic[1] = regtostr(cpuver, 1, xcesr.evsel[1])) == NULL) {
6390Sstevel@tonic-gate 			free(pic[0]);
6400Sstevel@tonic-gate 			return (NULL);
6410Sstevel@tonic-gate 		}
6420Sstevel@tonic-gate 		(void) snprintf(buffer, sizeof (buffer), "%s=%s,%s=%s",
6430Sstevel@tonic-gate 		    tokens[D_pic0], pic[0], tokens[D_pic1], pic[1]);
6440Sstevel@tonic-gate 		free(pic[1]);
6450Sstevel@tonic-gate 		free(pic[0]);
6460Sstevel@tonic-gate 		flagstostr(buffer,
6470Sstevel@tonic-gate 		    xcesr.usr[0], xcesr.usr[1], 1, tokens[D_nouser]);
6480Sstevel@tonic-gate 		flagstostr(buffer,
6490Sstevel@tonic-gate 		    xcesr.sys[0], xcesr.sys[1], 0, tokens[D_sys]);
6500Sstevel@tonic-gate 		flagstostr(buffer,
6510Sstevel@tonic-gate 		    xcesr.clk[0], xcesr.clk[1], 0, tokens[D_noedge]);
6520Sstevel@tonic-gate 		flagstostr(buffer,
6530Sstevel@tonic-gate 		    xcesr.pc[0], xcesr.pc[1], 0, tokens[D_pc]);
654*13093SRoger.Faulkner@Oracle.COM 		break;
655*13093SRoger.Faulkner@Oracle.COM 	}
6560Sstevel@tonic-gate 	default:
6570Sstevel@tonic-gate 		return (NULL);
6580Sstevel@tonic-gate 	}
6590Sstevel@tonic-gate 	return (strdup(buffer));
6600Sstevel@tonic-gate }
6610Sstevel@tonic-gate 
6620Sstevel@tonic-gate /*
6630Sstevel@tonic-gate  * Utility operations on events
6640Sstevel@tonic-gate  */
6650Sstevel@tonic-gate void
cpc_event_accum(cpc_event_t * accum,cpc_event_t * event)6660Sstevel@tonic-gate cpc_event_accum(cpc_event_t *accum, cpc_event_t *event)
6670Sstevel@tonic-gate {
6680Sstevel@tonic-gate 	if (accum->ce_hrt < event->ce_hrt)
6690Sstevel@tonic-gate 		accum->ce_hrt = event->ce_hrt;
6700Sstevel@tonic-gate 	accum->ce_tsc += event->ce_tsc;
6710Sstevel@tonic-gate 	accum->ce_pic[0] += event->ce_pic[0];
6720Sstevel@tonic-gate 	accum->ce_pic[1] += event->ce_pic[1];
6730Sstevel@tonic-gate }
6740Sstevel@tonic-gate 
6750Sstevel@tonic-gate void
cpc_event_diff(cpc_event_t * diff,cpc_event_t * left,cpc_event_t * right)6760Sstevel@tonic-gate cpc_event_diff(cpc_event_t *diff, cpc_event_t *left, cpc_event_t *right)
6770Sstevel@tonic-gate {
6780Sstevel@tonic-gate 	diff->ce_hrt = left->ce_hrt;
6790Sstevel@tonic-gate 	diff->ce_tsc = left->ce_tsc - right->ce_tsc;
6800Sstevel@tonic-gate 	diff->ce_pic[0] = left->ce_pic[0] - right->ce_pic[0];
6810Sstevel@tonic-gate 	diff->ce_pic[1] = left->ce_pic[1] - right->ce_pic[1];
6820Sstevel@tonic-gate }
6830Sstevel@tonic-gate 
6840Sstevel@tonic-gate /*
6850Sstevel@tonic-gate  * Given a cpc_event_t and cpc_bind_event() flags,
6860Sstevel@tonic-gate  * translate the cpc_event_t into the cpc_set_t format.
6870Sstevel@tonic-gate  *
6880Sstevel@tonic-gate  * Returns NULL on failure.
6890Sstevel@tonic-gate  */
6900Sstevel@tonic-gate cpc_set_t *
__cpc_eventtoset(cpc_t * cpc,cpc_event_t * event,int iflags)6910Sstevel@tonic-gate __cpc_eventtoset(cpc_t *cpc, cpc_event_t *event, int iflags)
6920Sstevel@tonic-gate {
6930Sstevel@tonic-gate 	cpc_set_t	*set;
6940Sstevel@tonic-gate 	int		cpuver = event->ce_cpuver;
6950Sstevel@tonic-gate 	char		*pic[2];
6960Sstevel@tonic-gate 	int		flags[2] = { 0, 0 };
6970Sstevel@tonic-gate 	int		i;
6980Sstevel@tonic-gate 	int		j;
6990Sstevel@tonic-gate 	int		nattrs;
7000Sstevel@tonic-gate 	cpc_attr_t	*attr;
7010Sstevel@tonic-gate 	int		intr;
7020Sstevel@tonic-gate 
7030Sstevel@tonic-gate 	if ((set = cpc_set_create(cpc)) == NULL) {
7040Sstevel@tonic-gate 		return (NULL);
7050Sstevel@tonic-gate 	}
7060Sstevel@tonic-gate 
7070Sstevel@tonic-gate 	if (iflags & CPC_BIND_EMT_OVF)
7080Sstevel@tonic-gate 		flags[0] = flags[1] = CPC_OVF_NOTIFY_EMT;
7090Sstevel@tonic-gate 
7100Sstevel@tonic-gate 	switch (cpuver) {
7110Sstevel@tonic-gate 	case CPC_PENTIUM_PRO_MMX:
7120Sstevel@tonic-gate 	case CPC_PENTIUM_PRO:
7130Sstevel@tonic-gate 	{
7140Sstevel@tonic-gate 		struct xpes xpes[2];
7150Sstevel@tonic-gate 
7160Sstevel@tonic-gate 		for (i = 0; i < 2; i++) {
7170Sstevel@tonic-gate 			intr = 0;
7180Sstevel@tonic-gate 			nattrs = j = 1;
7190Sstevel@tonic-gate 			unmake_pes(event->ce_pes[i], cpuver, &xpes[i]);
7200Sstevel@tonic-gate 			if ((pic[i] = regtostr(cpuver, i,
7210Sstevel@tonic-gate 			    xpes[i].evsel)) == NULL) {
7220Sstevel@tonic-gate 				(void) cpc_set_destroy(cpc, set);
7230Sstevel@tonic-gate 				return (NULL);
7240Sstevel@tonic-gate 			}
7250Sstevel@tonic-gate 			if (xpes[i].usr == 1)
7260Sstevel@tonic-gate 				flags[i] |= CPC_COUNT_USER;
7270Sstevel@tonic-gate 			if (xpes[i].sys == 1)
7280Sstevel@tonic-gate 				flags[i] |= CPC_COUNT_SYSTEM;
7290Sstevel@tonic-gate 			if (xpes[i].irupt == 1) {
7300Sstevel@tonic-gate 				nattrs++;
7310Sstevel@tonic-gate 				intr = 1;
7320Sstevel@tonic-gate 			}
7330Sstevel@tonic-gate 
7340Sstevel@tonic-gate 			if (xpes[i].cmask)
7350Sstevel@tonic-gate 				nattrs++;
7360Sstevel@tonic-gate 			if (xpes[i].umask)
7370Sstevel@tonic-gate 				nattrs++;
7380Sstevel@tonic-gate 			if (xpes[i].inv)
7390Sstevel@tonic-gate 				nattrs++;
7400Sstevel@tonic-gate 			if (xpes[i].pc)
7410Sstevel@tonic-gate 				nattrs++;
7420Sstevel@tonic-gate 			if (xpes[i].edge == 0)
7430Sstevel@tonic-gate 				nattrs++;
7440Sstevel@tonic-gate 
7450Sstevel@tonic-gate 			if ((attr = (cpc_attr_t *)malloc(nattrs *
7460Sstevel@tonic-gate 			    sizeof (cpc_attr_t))) == NULL) {
7470Sstevel@tonic-gate 				(void) cpc_set_destroy(cpc, set);
7480Sstevel@tonic-gate 				errno = ENOMEM;
7490Sstevel@tonic-gate 				return (NULL);
7500Sstevel@tonic-gate 			}
7510Sstevel@tonic-gate 
7520Sstevel@tonic-gate 			/*
7530Sstevel@tonic-gate 			 * Ensure that pic[0] in the cpc_event_t is bound to
7540Sstevel@tonic-gate 			 * physical pic0.
7550Sstevel@tonic-gate 			 */
7560Sstevel@tonic-gate 			attr[0].ca_name = "picnum";
7570Sstevel@tonic-gate 			attr[0].ca_val = i;
7580Sstevel@tonic-gate 
7590Sstevel@tonic-gate 			if (intr) {
7600Sstevel@tonic-gate 				attr[j].ca_name = "int";
7610Sstevel@tonic-gate 				attr[j].ca_val = 1;
7620Sstevel@tonic-gate 				j++;
7630Sstevel@tonic-gate 			}
7640Sstevel@tonic-gate 			if (xpes[i].cmask) {
7650Sstevel@tonic-gate 				attr[j].ca_name = "cmask";
7660Sstevel@tonic-gate 				attr[j].ca_val = xpes[i].cmask;
7670Sstevel@tonic-gate 				j++;
7680Sstevel@tonic-gate 			}
7690Sstevel@tonic-gate 			if (xpes[i].umask) {
7700Sstevel@tonic-gate 				attr[j].ca_name = "umask";
7710Sstevel@tonic-gate 				attr[j].ca_val = xpes[i].umask;
7720Sstevel@tonic-gate 				j++;
7730Sstevel@tonic-gate 			}
7740Sstevel@tonic-gate 			if (xpes[i].inv) {
7750Sstevel@tonic-gate 				attr[j].ca_name = "inv";
7760Sstevel@tonic-gate 				attr[j].ca_val = 1;
7770Sstevel@tonic-gate 				j++;
7780Sstevel@tonic-gate 			}
7790Sstevel@tonic-gate 			if (xpes[i].pc) {
7800Sstevel@tonic-gate 				attr[j].ca_name = "pc";
7810Sstevel@tonic-gate 				attr[j].ca_val = 1;
7820Sstevel@tonic-gate 				j++;
7830Sstevel@tonic-gate 			}
7840Sstevel@tonic-gate 			if (xpes[i].edge == 0) {
7850Sstevel@tonic-gate 				attr[j].ca_name = "noedge";
7860Sstevel@tonic-gate 				attr[j].ca_val = 1;
7870Sstevel@tonic-gate 				j++;
7880Sstevel@tonic-gate 			}
7890Sstevel@tonic-gate 
7900Sstevel@tonic-gate 			if (cpc_set_add_request(cpc, set, pic[i],
7910Sstevel@tonic-gate 			    event->ce_pic[i], flags[i], nattrs, attr) == -1) {
7920Sstevel@tonic-gate 				(void) cpc_set_destroy(cpc, set);
7930Sstevel@tonic-gate 				free(pic[i]);
7940Sstevel@tonic-gate 				free(attr);
7950Sstevel@tonic-gate 				return (NULL);
7960Sstevel@tonic-gate 			}
7970Sstevel@tonic-gate 			free(pic[i]);
7980Sstevel@tonic-gate 			free(attr);
7990Sstevel@tonic-gate 		}
8000Sstevel@tonic-gate 	}
8010Sstevel@tonic-gate 	break;
8020Sstevel@tonic-gate 	case CPC_PENTIUM_MMX:
8030Sstevel@tonic-gate 	case CPC_PENTIUM:
8040Sstevel@tonic-gate 	{
8050Sstevel@tonic-gate 		struct xcesr xcesr;
8060Sstevel@tonic-gate 		unmake_cesr(event->ce_cesr, cpuver, &xcesr);
8070Sstevel@tonic-gate 
8080Sstevel@tonic-gate 		for (i = 0; i < 2; i++) {
8090Sstevel@tonic-gate 			nattrs = j = 1;
8100Sstevel@tonic-gate 
8110Sstevel@tonic-gate 			if ((pic[i] = regtostr(cpuver, i, xcesr.evsel[i]))
8120Sstevel@tonic-gate 			    == NULL) {
8130Sstevel@tonic-gate 				(void) cpc_set_destroy(cpc, set);
8140Sstevel@tonic-gate 				return (NULL);
8150Sstevel@tonic-gate 			}
8160Sstevel@tonic-gate 
8170Sstevel@tonic-gate 			if (xcesr.usr[i] == 1)
8180Sstevel@tonic-gate 				flags[i] |= CPC_COUNT_USER;
8190Sstevel@tonic-gate 			if (xcesr.sys[i] == 1)
8200Sstevel@tonic-gate 				flags[i] |= CPC_COUNT_SYSTEM;
8210Sstevel@tonic-gate 			if (xcesr.clk[i] == 1)
8220Sstevel@tonic-gate 				nattrs++;
8230Sstevel@tonic-gate 			if (xcesr.pc[i] == 1)
8240Sstevel@tonic-gate 				nattrs++;
8250Sstevel@tonic-gate 
8260Sstevel@tonic-gate 			if ((attr = (cpc_attr_t *)malloc(nattrs *
8270Sstevel@tonic-gate 			    sizeof (cpc_attr_t))) == NULL) {
8280Sstevel@tonic-gate 				(void) cpc_set_destroy(cpc, set);
8290Sstevel@tonic-gate 				errno = ENOMEM;
8300Sstevel@tonic-gate 				return (NULL);
8310Sstevel@tonic-gate 			}
8320Sstevel@tonic-gate 
8330Sstevel@tonic-gate 			/*
8340Sstevel@tonic-gate 			 * Ensure that pic[0] in the cpc_event_t is bound to
8350Sstevel@tonic-gate 			 * physical pic0.
8360Sstevel@tonic-gate 			 */
8370Sstevel@tonic-gate 			attr[0].ca_name = "picnum";
8380Sstevel@tonic-gate 			attr[0].ca_val = i;
8390Sstevel@tonic-gate 
8400Sstevel@tonic-gate 			if (xcesr.clk[i] == 1) {
8410Sstevel@tonic-gate 				attr[j].ca_name = "noedge";
8420Sstevel@tonic-gate 				attr[j].ca_val = 1;
8430Sstevel@tonic-gate 				j++;
8440Sstevel@tonic-gate 			}
8450Sstevel@tonic-gate 
8460Sstevel@tonic-gate 			if (xcesr.pc[i] == 1) {
8470Sstevel@tonic-gate 				attr[j].ca_name = "pc";
8480Sstevel@tonic-gate 				attr[j].ca_val = 1;
8490Sstevel@tonic-gate 				j++;
8500Sstevel@tonic-gate 			}
8510Sstevel@tonic-gate 
8520Sstevel@tonic-gate 			if (cpc_set_add_request(cpc, set, pic[i],
8530Sstevel@tonic-gate 			    event->ce_pic[i], flags[i], nattrs, attr) == -1) {
8540Sstevel@tonic-gate 				(void) cpc_set_destroy(cpc, set);
8550Sstevel@tonic-gate 				free(pic[i]);
8560Sstevel@tonic-gate 				free(attr);
8570Sstevel@tonic-gate 				return (NULL);
8580Sstevel@tonic-gate 			}
8590Sstevel@tonic-gate 
8600Sstevel@tonic-gate 			free(pic[i]);
8610Sstevel@tonic-gate 			free(attr);
8620Sstevel@tonic-gate 		}
8630Sstevel@tonic-gate 	}
8640Sstevel@tonic-gate 	break;
8650Sstevel@tonic-gate 	default:
8660Sstevel@tonic-gate 		(void) cpc_set_destroy(cpc, set);
8670Sstevel@tonic-gate 		return (NULL);
8680Sstevel@tonic-gate 	}
8690Sstevel@tonic-gate 
8700Sstevel@tonic-gate 	return (set);
8710Sstevel@tonic-gate }
872