/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (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
*/
/*
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <string.h>
#include <alloca.h>
#include <stdlib.h>
#include <stdio.h>
#include <libintl.h>
#include <libdevinfo.h>
#include "libcpc.h"
#include "libcpc_impl.h"
/*
* Configuration data for UltraSPARC performance counters.
*
* Definitions taken from [1], [2], [3] [4] and [5]. See the references to
* understand what any of these settings actually means.
*
* Note that in the current draft of [2], there is some re-use
* of existing bit assignments in the various fields of the %pcr
* register - this may change before FCS.
*
* The following are the Internal Documents. Customers need to be
* told about the Public docs in cpc_getcpuref().
* [1] "UltraSPARC I & II User's Manual," January 1997.
* [2] "UltraSPARC-III Programmer's Reference Manual," April 1999.
* [3] "Cheetah+ Programmer's Reference Manual," November 2000.
* [4] "UltraSPARC-IIIi Programmer's Reference Manual," November 2000.
* [5] "UltraSPARC-IV+ Programmer's Reference Manual," October 2004.
*/
/*
* map from "cpu version" to flag bits
*/
V_US12, /* CPC_ULTRA1 */
V_US12, /* CPC_ULTRA2 */
V_US3, /* CPC_ULTRA3 */
V_US3_PLUS, /* CPC_ULTRA3_PLUS */
V_US3_I, /* CPC_ULTRA3I */
V_US4_PLUS /* CPC_ULTRA4_PLUS */
};
struct nametable {
const char *name;
};
/*
* Definitions for counter 0
*/
#define USall_EVENTS_0(v) \
{v, 0x0, "Cycle_cnt"}, \
{v, 0x1, "Instr_cnt"}, \
{v, 0x2, "Dispatch0_IC_miss"}, \
{v, 0x8, "IC_ref"}, \
{v, 0x9, "DC_rd"}, \
{v, 0xa, "DC_wr"}, \
{v, 0xc, "EC_ref"}, \
{v, 0xe, "EC_snoop_inv"}
{V_END}
};
#define US3all_EVENTS_0(v) \
{v, 0x3, "Dispatch0_br_target"}, \
{v, 0x4, "Dispatch0_2nd_br"}, \
{v, 0x5, "Rstall_storeQ"}, \
{v, 0x6, "Rstall_IU_use"}, \
{v, 0xd, "EC_write_hit_RTO"}, \
{v, 0xf, "EC_rd_miss"}, \
{v, 0x10, "PC_port0_rd"}, \
{v, 0x11, "SI_snoop"}, \
{v, 0x12, "SI_ciq_flow"}, \
{v, 0x13, "SI_owned"}, \
{v, 0x14, "SW_count_0"}, \
{v, 0x15, "IU_Stat_Br_miss_taken"}, \
{v, 0x16, "IU_Stat_Br_count_taken"}, \
{v, 0x17, "Dispatch_rs_mispred"}, \
{v, 0x18, "FA_pipe_completion"}
#define US3_MC_EVENTS_0(v) \
{v, 0x20, "MC_reads_0"}, \
{v, 0x21, "MC_reads_1"}, \
{v, 0x22, "MC_reads_2"}, \
{v, 0x23, "MC_reads_3"}, \
{v, 0x24, "MC_stalls_0"}, \
{v, 0x25, "MC_stalls_2"}
#define US3_I_MC_EVENTS_0(v) \
{v, 0x20, "MC_read_dispatched"}, \
{v, 0x21, "MC_write_dispatched"}, \
{v, 0x22, "MC_read_returned_to_JBU"}, \
{v, 0x23, "MC_msl_busy_stall"}, \
{v, 0x24, "MC_mdb_overflow_stall"}, \
{v, 0x25, "MC_miu_spec_request"}
{V_END}
};
{V_END}
};
{V_END}
};
{V_END}
};
#define USall_EVENTS_1(v) \
{v, 0x0, "Cycle_cnt"}, \
{v, 0x1, "Instr_cnt"}, \
{v, 0x2, "Dispatch0_mispred"}, \
{v, 0xd, "EC_wb"}, \
{v, 0xe, "EC_snoop_cb"}
{V_END}
};
#define US3all_EVENTS_1(v) \
{v, 0x3, "IC_miss_cancelled"}, \
{v, 0x5, "Re_FPU_bypass"}, \
{v, 0x6, "Re_DC_miss"}, \
{v, 0x7, "Re_EC_miss"}, \
{v, 0x8, "IC_miss"}, \
{v, 0x9, "DC_rd_miss"}, \
{v, 0xa, "DC_wr_miss"}, \
{v, 0xb, "Rstall_FP_use"}, \
{v, 0xc, "EC_misses"}, \
{v, 0xf, "EC_ic_miss"}, \
{v, 0x10, "Re_PC_miss"}, \
{v, 0x11, "ITLB_miss"}, \
{v, 0x12, "DTLB_miss"}, \
{v, 0x13, "WC_miss"}, \
{v, 0x14, "WC_snoop_cb"}, \
{v, 0x15, "WC_scrubbed"}, \
{v, 0x16, "WC_wb_wo_read"}, \
{v, 0x18, "PC_soft_hit"}, \
{v, 0x19, "PC_snoop_inv"}, \
{v, 0x1a, "PC_hard_hit"}, \
{v, 0x1b, "PC_port1_rd"}, \
{v, 0x1c, "SW_count_1"}, \
{v, 0x1d, "IU_Stat_Br_miss_untaken"}, \
{v, 0x1e, "IU_Stat_Br_count_untaken"}, \
{v, 0x1f, "PC_MS_misses"}, \
{v, 0x26, "Re_RAW_miss"}, \
{v, 0x27, "FM_pipe_completion"}
#define US3_MC_EVENTS_1(v) \
{v, 0x20, "MC_writes_0"}, \
{v, 0x21, "MC_writes_1"}, \
{v, 0x22, "MC_writes_2"}, \
{v, 0x23, "MC_writes_3"}, \
{v, 0x24, "MC_stalls_1"}, \
{v, 0x25, "MC_stalls_3"}
#define US3_I_MC_EVENTS_1(v) \
{v, 0x20, "MC_open_bank_cmds"}, \
{v, 0x21, "MC_reads"}, \
{v, 0x22, "MC_writes"}, \
{v, 0x23, "MC_page_close_stall"}
{V_END}
};
{V_END}
};
{V_END}
};
{V_END}
};
};
};
};
};
};
static int
{
return (0);
cpuver -= CPC_ULTRA1;
if (cpuver < 0 ||
return (0);
return (1);
}
/*ARGSUSED*/
static int
{
return (0);
return (1);
}
static const struct nametable *
{
const struct nametable *n;
return (NULL);
case V_US12:
n = US12_names[regno];
break;
case V_US3:
break;
case V_US3_PLUS:
n = US3_PLUS_names[regno];
break;
case V_US3_I:
n = US3_I_names[regno];
break;
case V_US4_PLUS:
n = US4_PLUS_names[regno];
break;
default:
n = NULL;
break;
}
return (n);
}
void
{
const struct nametable *n;
return;
}
const char *
{
const struct nametable *n;
return (NULL);
return (n->name);
return (NULL);
}
/*
* Register names can be specified as strings or even as numbers
*/
int
{
const struct nametable *n;
long value;
return (-1);
return (0);
}
return (0);
}
return (-1);
}
const char *
{
case V_US12:
return ("UltraSPARC I&II");
case V_US3:
return ("UltraSPARC III");
case V_US3_PLUS:
return ("UltraSPARC III+ & IV");
case V_US3_I:
return ("UltraSPARC IIIi & IIIi+");
case V_US4_PLUS:
return ("UltraSPARC IV+");
default:
break;
}
return (NULL);
}
const char *
{
case V_US12:
return (gettext(
"(Part No. 802-7220-02) "
"for descriptions of these events." CPU_REF_URL));
case V_US3:
case V_US3_PLUS:
return (gettext(
"See the \"UltraSPARC III Cu User's Manual\" "
"for descriptions of these events." CPU_REF_URL));
case V_US3_I:
return (gettext(
"See the \"UltraSPARC IIIi User's Manual\" "
"for descriptions of these events." CPU_REF_URL));
case V_US4_PLUS:
return (gettext(
"See the \"UltraSPARC IV User's Manual"
"Supplement\" "
"for descriptions of these events." CPU_REF_URL));
default:
break;
}
return (NULL);
}
/*
* This is a functional interface to allow CPUs with fewer %pic registers
* to share the same data structure as those with more %pic registers
* within the same instruction family.
*/
{
/*LINTED*/
switch (cpuver) {
case CPC_ULTRA1:
case CPC_ULTRA2:
case CPC_ULTRA3:
case CPC_ULTRA3_PLUS:
case CPC_ULTRA3_I:
case CPC_ULTRA4_PLUS:
default:
return (0);
}
}
/*
* Compares the given string against the list of all known CPU node names, and
* returns the CPC CPU version code if there is a match. If there is no match,
* returns -1.
*/
static int
{
return (CPC_ULTRA1);
return (CPC_ULTRA3);
return (CPC_ULTRA3_PLUS);
return (CPC_ULTRA3_I);
return (CPC_ULTRA4_PLUS);
return (-1);
}
static int
{
found = 1;
/*
* CPU nodes associated with CMP use the generic name
* of "cpu". We must look at the compatible property
* in order to find the implementation specific name.
*/
&compatible_array)) > 0) {
for (i = 0; i < n_names; i++) {
!= -1) {
found = 1;
break;
}
}
}
}
}
if (found == 0)
return (DI_WALK_CONTINUE);
return (DI_WALK_TERMINATE);
}
/*
* Return the version of the current processor.
*
* Version -1 is defined as 'not performance counter capable'
*
* XXX A better solution would be to use the di_prom_props for the cpu
* devinfo nodes. That way we could look at the 'device-type', 'sparc-version'
* and 'implementation#' properties in order to determine which version of
* UltraSPARC we are running on.
*
* The problem with this is that di_prom_init() requires root access to
* we have to settle for the di_props that we can see as non-root users.
*/
int
cpc_getcpuver(void)
{
if (ver == -1) {
return (-1);
(void *)&ver, cpc_get_cpu_ver);
}
return (ver);
}