/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
*/
/*
* Routines to capture processor-dependencies in event specification.
*/
#include <string.h>
#include <strings.h>
#include <stdlib.h>
#include <stdio.h>
#include <libintl.h>
#include <assert.h>
#include <errno.h>
#include "libcpc.h"
#include "libcpc_impl.h"
/*
* Event specifications for Pentium performance counters are based
* on the content of a getsubopt-like string.
* The string should contain something that looks like this:
*
* pic0=<eventspec>,pic1=<eventspec>
* [,cmask0=<maskspec>][,cmask1=<maskspec>]
* [,umask0=<maskspec>][,umask1=<maskspec>]
* [,inv[0|1]][,noedge[0|1]]
* [,sys[0|1]][,nouser[0|1]]
*
* For example:
* pic0=data_mem_refs,pic1=l2_ld,sys
* or
* pic0=l2_ld,pic1=bus_drdy_clocks,umask1=0x20,nouser1
*
* By default, user event counting is enabled, system event counting
* is disabled.
*
* Note that Pentium and Pentium Pro have different event specifications.
*
* The two events must be named. The names can be ascii or
* a decimal, octal or hexadecimal number as parsed by strtol(3C).
*
* The routine counts the number of errors encountered while parsing
* the string, if no errors are encountered, the event handle is
* returned.
*/
const char *
{
switch (cpuver) {
case CPC_PENTIUM_PRO_MMX:
case CPC_PENTIUM_PRO:
return ("pic0=<event0>,pic1=<event1> "
"[,sys[0|1]] "
"[,nouser[0|1]] "
"[,noedge[0|1]] "
"[,pc[0|1]] "
"[,int[0|1]] "
"[,inv[0|1]] "
"[,cmask[0|1]=<maskspec>] "
"[,umask[0|1]=<maskspec>] ");
case CPC_PENTIUM_MMX:
case CPC_PENTIUM:
return ("pic0=<event0>,pic1=<event1> "
"[,sys[0|1]] "
"[,nouser[0|1]] "
"[,noedge[0|1]] "
"[,pc[0|1]]");
default:
return (NULL);
}
}
struct keyval {
char *kv_token;
int (*kv_action)(const char *,
int kv_shift;
};
/*ARGSUSED*/
static int
{
long l;
return (-1);
}
return (-1);
}
return (0);
}
static int
{
return (-1);
}
switch (cpuver) {
case CPC_PENTIUM_PRO_MMX:
case CPC_PENTIUM_PRO:
"PerfCtr%d cannot measure '%s' on this cpu\n"),
break;
case CPC_PENTIUM_MMX:
case CPC_PENTIUM:
"CTR%d cannot measure '%s' on this cpu\n"),
break;
}
return (-1);
}
return (0);
}
/*ARGSUSED2*/
static int
{
return (-1);
}
return (0);
}
/*ARGSUSED2*/
static int
{
return (-1);
}
return (0);
}
static int
{
int rv;
return (-1);
}
kv++;
return (rv);
kv++;
}
/*
* This token table must match the keyval tables below.
*/
static char * const tokens[] = {
#define D_pic0 0
"pic0", /* takes a valid event name */
"pic1", /* takes a valid event name */
"nouser", /* disables user counts */
"nouser0",
"nouser1",
"sys", /* enables system counts */
"sys0",
"sys1",
"noedge", /* disable edge detect */
"noedge0",
"noedge1",
"pc", /* sets pin control high */
"pc0",
"pc1",
/*
* These additional keywords are for Pentium Pro / Pentium II machines.
*/
"int", /* enable interrupt on counter overflow */
"int0",
"int1",
"inv", /* invert cmask comparison */
"inv0",
"inv1",
"umask0", /* PerfCtr0 unit mask */
"umask1", /* PerfCtr1 unit mask */
"cmask0", /* PerfCtr0 counter mask */
"cmask1", /* PerfCtr1 counter mask */
};
{ "pic0", picbits, 0,
CPC_P6_PES_PIC0_MASK, 0 },
CPC_P6_PES_PIC1_MASK, 0 },
{ "nouser", nextpair },
{ "nouser0", bitclr, 0,
{ "sys", nextpair },
{ "sys0", bitset, 0,
{ "noedge", nextpair },
{ "noedge0", bitclr, 0,
{ "pc", nextpair },
{ "pc0", bitset, 0,
{ "int", nextpair },
{ "int0", bitset, 0,
{ "inv", nextpair },
{ "inv0", bitset, 0,
{ "umask0", eightbits, 0,
{ "cmask0", eightbits, 0,
};
/*
* Note that this table -must- be an identically indexed
* subset of p6_keyvals.
*/
{ "pic0", picbits, 0,
{ "pic1", picbits, 0,
{ "nouser", nextpair },
{ "nouser0", bitclr, 0,
{ "nouser1", bitclr, 0,
{ "sys", nextpair },
{ "sys0", bitset, 0,
{ "sys1", bitset, 0,
{ "noedge", nextpair },
{ "noedge0", bitset, 0,
{ "noedge1", bitset, 0,
{ "pc", nextpair },
{ "pc0", bitset, 0,
{ "pc1", bitset, 0,
};
#if !defined(NDEBUG)
#pragma init(__tablecheck)
static void
__tablecheck(void)
{
uint_t n;
for (n = 0; n < ntokens; n++)
for (n = 0; n < p5_nkeys; n++)
}
#endif /* !NDEBUG */
int
{
char *value;
char *opts;
int errcnt = 0;
return (errcnt = 1);
case CPC_PENTIUM_PRO_MMX:
case CPC_PENTIUM_PRO:
break;
case CPC_PENTIUM_MMX:
case CPC_PENTIUM:
bits[0] =
break;
default:
return (errcnt = 1);
}
while (*opts != '\0') {
errcnt++;
break;
}
"repeated '%s' token\n",
errcnt++;
break;
}
"repeated '%s' token\n",
errcnt++;
break;
}
}
} else if (idx == -1) {
/*
* The token given wasn't recognized.
* See if it was an implicit pic specification..
*/
errcnt++;
break;
}
errcnt++;
break;
}
} else {
errcnt++;
break;
}
} else {
if (idx >= 0 &&
else
errcnt++;
break;
}
}
errcnt++;
}
return (errcnt);
}
/*
* Return a printable description of the control registers.
*
* This routine should always succeed (notwithstanding heap problems),
* but may not be able to correctly decode the registers, if, for
* example, a new processor is under test.
*
* The caller is responsible for free(3c)ing the string returned.
*/
static void
{
else
} else {
}
}
static void
{
if (bits != 0) {
}
}
static char *
{
}
static char *
{
const char *sname;
}
struct xpes {
};
/*ARGSUSED1*/
static void
{
}
struct xcesr {
};
/*ARGSUSED1*/
static void
{
/*
* If usr and sys are both disabled, the counter is disabled.
*/
}
char *
{
switch (cpuver) {
case CPC_PENTIUM_PRO_MMX:
case CPC_PENTIUM_PRO:
{
return (NULL);
return (NULL);
}
break;
}
case CPC_PENTIUM_MMX:
case CPC_PENTIUM:
{
return (NULL);
return (NULL);
}
break;
}
default:
return (NULL);
}
}
/*
* Utility operations on events
*/
void
{
}
void
{
}
/*
* Given a cpc_event_t and cpc_bind_event() flags,
* translate the cpc_event_t into the cpc_set_t format.
*
* Returns NULL on failure.
*/
{
int i;
int j;
int nattrs;
int intr;
return (NULL);
}
if (iflags & CPC_BIND_EMT_OVF)
switch (cpuver) {
case CPC_PENTIUM_PRO_MMX:
case CPC_PENTIUM_PRO:
{
for (i = 0; i < 2; i++) {
intr = 0;
nattrs = j = 1;
return (NULL);
}
flags[i] |= CPC_COUNT_USER;
flags[i] |= CPC_COUNT_SYSTEM;
nattrs++;
intr = 1;
}
nattrs++;
nattrs++;
nattrs++;
nattrs++;
nattrs++;
sizeof (cpc_attr_t))) == NULL) {
return (NULL);
}
/*
* Ensure that pic[0] in the cpc_event_t is bound to
* physical pic0.
*/
if (intr) {
j++;
}
j++;
}
j++;
}
j++;
}
j++;
}
j++;
}
return (NULL);
}
}
}
break;
case CPC_PENTIUM_MMX:
case CPC_PENTIUM:
{
for (i = 0; i < 2; i++) {
nattrs = j = 1;
== NULL) {
return (NULL);
}
flags[i] |= CPC_COUNT_USER;
flags[i] |= CPC_COUNT_SYSTEM;
nattrs++;
nattrs++;
sizeof (cpc_attr_t))) == NULL) {
return (NULL);
}
/*
* Ensure that pic[0] in the cpc_event_t is bound to
* physical pic0.
*/
j++;
}
j++;
}
return (NULL);
}
}
}
break;
default:
return (NULL);
}
return (set);
}