niagara_perfctr.c revision 59ac0c1669407488b67ae9e273667a340dccc611
/*
* 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
*/
/*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <sys/ddi_impldefs.h>
#include <sys/machsystm.h>
#include <sys/hypervisor_api.h>
#if defined(NIAGARA_IMPL)
#include <sys/niagararegs.h>
#include <sys/niagara2regs.h>
#endif
extern char cpu_module_name[];
#define NUM_OF_PICS 2
/*
* Data structure used to build array of event-names and pcr-mask values
*/
typedef struct ni_kev_mask {
char *event_name;
/*
* Kstat data structure for DRAM and JBUS performance counters
*
* Note that these performance counters are only 31 bits wide. Since
* the "busstat" command assumes a 32-bit counter, we emulate a 32-bit
* counter by detecting overflow on read of these performance counters
* and using the least significant bit of the overflow count as the
* most significant bit (i.e. bit# 31) of the DRAM and JBUS performance
* counters.
*/
#define NUM_OF_PICS 2
typedef struct ni_ksinfo {
} ni_ksinfo_t;
#if defined(NIAGARA_IMPL)
static ni_ksinfo_t *ni_jbus_kstat;
#endif
typedef struct ni_perf_regs {
static ni_perf_regs_t dram_perf_regs[] = {
};
static void ni_delete_name_kstat(ni_ksinfo_t *);
static kstat_t *ni_create_cntr_kstat(char *, int,
static int ni_cntr_kstat_update(kstat_t *, int);
static kstat_t *ni_create_picN_kstat(char *, int, int, int,
ni_kev_mask_t *);
#ifdef DEBUG
static int ni_perf_debug;
#endif
/*
* Niagara, Niagara2 and VFalls DRAM Performance Events
*/
static ni_kev_mask_t
niagara_dram_events[] = {
{"mem_reads", 0x0},
{"mem_writes", 0x1},
{"mem_read_write", 0x2},
{"bank_busy_stalls", 0x3},
{"rd_queue_latency", 0x4},
{"wr_queue_latency", 0x5},
{"rw_queue_latency", 0x6},
{"wb_buf_hits", 0x7},
{"clear_pic", 0xf}
};
#if defined(NIAGARA_IMPL)
/*
* Niagara JBUS Performance Events
*/
static ni_kev_mask_t
niagara_jbus_events[] = {
{"jbus_cycles", 0x1},
{"dma_reads", 0x2},
{"dma_read_latency", 0x3},
{"dma_writes", 0x4},
{"dma_write8", 0x5},
{"ordering_waits", 0x6},
{"pio_reads", 0x8},
{"pio_read_latency", 0x9},
{"aok_dok_off_cycles", 0xc},
{"aok_off_cycles", 0xd},
{"dok_off_cycles", 0xe},
{"clear_pic", 0xf}
};
#endif
/*
* Create the picN kstats for DRAM and JBUS events
*/
void
{
int i;
#ifdef DEBUG
if (ni_perf_debug)
printf("ni_kstat_init called\n");
#endif
/*
* Create DRAM perf events kstat
*/
for (i = 0; i < NIAGARA_DRAM_BANKS; i++) {
#ifdef VFALLS_IMPL
/* check if this dram instance is enabled in the HW */
H_EINVAL) {
#endif
sizeof (ni_ksinfo_t), KM_NOSLEEP);
"%s: no space for dram kstat\n",
break;
}
sizeof (niagara_dram_events) /
sizeof (ni_kev_mask_t);
ni_dram_kstats[i] = ksinfop;
if (i == 0)
/* create counter kstats */
#ifdef VFALLS_IMPL
}
#endif
}
#if defined(NIAGARA_IMPL)
/*
* Create JBUS perf events kstat
*/
if (ni_jbus_kstat == NULL) {
} else {
sizeof (niagara_jbus_events) / sizeof (ni_kev_mask_t);
}
#endif
}
void
{
int i;
#ifdef DEBUG
if (ni_perf_debug)
printf("ni_kstat_fini called\n");
#endif
for (i = 0; i < NIAGARA_DRAM_BANKS; i++) {
if (ni_dram_kstats[i] != NULL) {
ni_dram_kstats[i] = NULL;
}
}
#if defined(NIAGARA_IMPL)
if (ni_jbus_kstat != NULL) {
}
#endif
}
static void
{
int i;
#ifdef DEBUG
if (ni_perf_debug > 1)
#endif
for (i = 0; i < NUM_OF_PICS; i++) {
}
}
}
static void
{
int i;
for (i = 0; i < NUM_OF_PICS; i++) {
}
}
}
/*
* Create the picN kstat. Returns a pointer to the
* kstat which the driver must store to allow it
* to be deleted when necessary.
*/
static kstat_t *
{
struct kstat_named *pic_named_data;
int inst = 0;
int event;
char pic_name[30];
/*
* It is up to the calling function to delete any kstats
* that may have been created already. We just
* return NULL to indicate an error has occured.
*/
return (NULL);
}
pic_named_data = (struct kstat_named *)
/*
* Write event names and their associated pcr masks. The
* last entry in the array (clear_pic) is added seperately
* below as the pic value must be inverted.
*/
}
/*
* add the clear_pic entry.
*/
return (picN_ksp);
}
/*
* Create the "counters" kstat.
*/
static kstat_t *
void *ksinfop)
{
struct kstat *counters_ksp;
struct kstat_named *counters_named_data;
char pic_str[10];
int i;
int num_pics = NUM_OF_PICS;
#ifdef DEBUG
if (ni_perf_debug > 1)
printf("ni_create_cntr_kstat: name: %s instance: %d\n",
#endif
/*
* Size of kstat is num_pics + 1 as it
* also contains the %pcr
*/
"%s: kstat_create for %s%d failed", cpu_module_name,
return (NULL);
}
/*
* Iinitialize the named kstats
*/
for (i = 0; i < num_pics; i++) {
}
/*
* Store the register offset's in the kstat's
* private field so that they are available
* to the update function.
*/
return (counters_ksp);
}
/*
*/
static int
{
struct kstat_named *data_p;
int stat = 0;
if (rw == KSTAT_WRITE) {
#ifdef DEBUG
if (ni_perf_debug)
printf("ni_cntr_kstat_update: wr pcr-%d: %lx\n",
#endif
} else {
else {
/*
* Generate a 32-bit PIC0 value by detecting overflow
*/
ksinfop->pic_overflow[0]++;
/*
* Generate a 32-bit PIC1 value by detecting overflow
*/
}
#ifdef DEBUG
if (ni_perf_debug)
printf("ni_cntr_kstat_update: rd pcr%d: %lx "
"pic%d: %16lx pic0: %8lx pic1: %8lx\n",
#endif
}
return (stat);
}