xref: /titanic_51/usr/src/uts/sun4v/cpu/niagara_perfctr.c (revision 4df55fde49134f9735f84011f23a767c75e393c7)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5c56c1e58Sgirish  * Common Development and Distribution License (the "License").
6c56c1e58Sgirish  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22*4df55fdeSJanie Lu  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate #include <sys/types.h>
277c478bd9Sstevel@tonic-gate #include <sys/async.h>
287c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
297c478bd9Sstevel@tonic-gate #include <sys/sunndi.h>
307c478bd9Sstevel@tonic-gate #include <sys/ddi_impldefs.h>
317c478bd9Sstevel@tonic-gate #include <sys/machsystm.h>
327c478bd9Sstevel@tonic-gate #include <sys/hypervisor_api.h>
337c478bd9Sstevel@tonic-gate #include <sys/kstat.h>
3444961713Sgirish #if defined(NIAGARA_IMPL)
3544961713Sgirish #include <sys/niagararegs.h>
36*4df55fdeSJanie Lu #elif defined(NIAGARA2_IMPL) || defined(VFALLS_IMPL) || defined(KT_IMPL)
3744961713Sgirish #include <sys/niagara2regs.h>
3844961713Sgirish #endif
397c478bd9Sstevel@tonic-gate 
40c56c1e58Sgirish extern char cpu_module_name[];
417c478bd9Sstevel@tonic-gate 
427c478bd9Sstevel@tonic-gate /*
437c478bd9Sstevel@tonic-gate  * Data structure used to build array of event-names and pcr-mask values
447c478bd9Sstevel@tonic-gate  */
457c478bd9Sstevel@tonic-gate typedef struct ni_kev_mask {
467c478bd9Sstevel@tonic-gate 	char		*event_name;
477c478bd9Sstevel@tonic-gate 	uint64_t	pcr_mask;
487c478bd9Sstevel@tonic-gate } ni_kev_mask_t;
497c478bd9Sstevel@tonic-gate 
507c478bd9Sstevel@tonic-gate /*
517c478bd9Sstevel@tonic-gate  * Kstat data structure for DRAM and JBUS performance counters
527c478bd9Sstevel@tonic-gate  *
537c478bd9Sstevel@tonic-gate  * Note that these performance counters are only 31 bits wide. Since
547c478bd9Sstevel@tonic-gate  * the "busstat" command assumes a 32-bit counter, we emulate a 32-bit
557c478bd9Sstevel@tonic-gate  * counter by detecting overflow on read of these performance counters
567c478bd9Sstevel@tonic-gate  * and using the least significant bit of the overflow count as the
577c478bd9Sstevel@tonic-gate  * most significant bit (i.e. bit# 31) of the DRAM and JBUS performance
587c478bd9Sstevel@tonic-gate  * counters.
597c478bd9Sstevel@tonic-gate  */
60c56c1e58Sgirish #define	NUM_OF_PICS	2
61*4df55fdeSJanie Lu #define	NUM_OF_PIC_REGS	1
62c56c1e58Sgirish 
637c478bd9Sstevel@tonic-gate typedef struct ni_ksinfo {
647c478bd9Sstevel@tonic-gate 	uint8_t		pic_no_evs;			/* number of events */
657c478bd9Sstevel@tonic-gate 	uint8_t		pic_sel_shift[NUM_OF_PICS];
667c478bd9Sstevel@tonic-gate 	uint8_t		pic_shift[NUM_OF_PICS];
677c478bd9Sstevel@tonic-gate 	uint64_t	pic_mask[NUM_OF_PICS];
687c478bd9Sstevel@tonic-gate 	kstat_t		*pic_name_ksp[NUM_OF_PICS];
697c478bd9Sstevel@tonic-gate 	kstat_t		*cntr_ksp;
70*4df55fdeSJanie Lu 	uint32_t	pic_reg[NUM_OF_PIC_REGS];
717c478bd9Sstevel@tonic-gate 	uint32_t	pcr_reg;
727c478bd9Sstevel@tonic-gate 	uint32_t	pic_overflow[NUM_OF_PICS];	/* overflow count */
737c478bd9Sstevel@tonic-gate 	uint32_t	pic_last_val[NUM_OF_PICS];	/* last PIC value */
747c478bd9Sstevel@tonic-gate } ni_ksinfo_t;
757c478bd9Sstevel@tonic-gate 
76*4df55fdeSJanie Lu static ni_ksinfo_t	*ni_dram_kstats[DRAM_BANKS];
7744961713Sgirish 
7844961713Sgirish #if defined(NIAGARA_IMPL)
797c478bd9Sstevel@tonic-gate static ni_ksinfo_t	*ni_jbus_kstat;
8044961713Sgirish #endif
817c478bd9Sstevel@tonic-gate 
827c478bd9Sstevel@tonic-gate typedef struct ni_perf_regs {
837c478bd9Sstevel@tonic-gate 	uint32_t	pcr_reg;
84*4df55fdeSJanie Lu 	uint32_t	pic_reg[NUM_OF_PIC_REGS];
857c478bd9Sstevel@tonic-gate } ni_perf_regs_t;
867c478bd9Sstevel@tonic-gate 
877c478bd9Sstevel@tonic-gate static ni_perf_regs_t dram_perf_regs[] = {
88*4df55fdeSJanie Lu #if defined(NIAGARA_IMPL) || defined(NIAGARA2_IMPL)
89*4df55fdeSJanie Lu 	{HV_DRAM_CTL0, HV_DRAM_COUNT0},
90*4df55fdeSJanie Lu 	{HV_DRAM_CTL1, HV_DRAM_COUNT1},
91*4df55fdeSJanie Lu 	{HV_DRAM_CTL2, HV_DRAM_COUNT2},
92*4df55fdeSJanie Lu 	{HV_DRAM_CTL3, HV_DRAM_COUNT3},
93*4df55fdeSJanie Lu #elif defined(VFALLS_IMPL) || defined(KT_IMPL)
94*4df55fdeSJanie Lu 	{HV_DRAM_CTL0, HV_DRAM_COUNT0},
95*4df55fdeSJanie Lu 	{HV_DRAM_CTL1, HV_DRAM_COUNT1},
96*4df55fdeSJanie Lu 	{HV_DRAM_CTL2, HV_DRAM_COUNT2},
97*4df55fdeSJanie Lu 	{HV_DRAM_CTL3, HV_DRAM_COUNT3},
98*4df55fdeSJanie Lu 	{HV_DRAM_CTL4, HV_DRAM_COUNT4},
99*4df55fdeSJanie Lu 	{HV_DRAM_CTL5, HV_DRAM_COUNT5},
100*4df55fdeSJanie Lu 	{HV_DRAM_CTL6, HV_DRAM_COUNT6},
101*4df55fdeSJanie Lu 	{HV_DRAM_CTL7, HV_DRAM_COUNT7}
10264cfc8edSsvemuri #endif
1037c478bd9Sstevel@tonic-gate };
1047c478bd9Sstevel@tonic-gate 
10564cfc8edSsvemuri #ifdef VFALLS_IMPL
10664cfc8edSsvemuri /*
10764cfc8edSsvemuri  * Kstat data structure for Zambezi performance counters
10864cfc8edSsvemuri  * These performance counters are 64 bits wide.
10964cfc8edSsvemuri  */
11064cfc8edSsvemuri static ni_ksinfo_t	*zam_lpu_kstats[ZAMBEZI_LPU_COUNTERS];
11164cfc8edSsvemuri static ni_ksinfo_t	*zam_gpd_kstats[ZAMBEZI_GPD_COUNTERS];
11264cfc8edSsvemuri static ni_ksinfo_t	*zam_asu_kstats[ZAMBEZI_ASU_COUNTERS];
11364cfc8edSsvemuri 
11464cfc8edSsvemuri typedef struct zam_perf_regs {
11564cfc8edSsvemuri 	uint32_t	pcr_reg;
11664cfc8edSsvemuri 	uint32_t	pic_reg[NUM_OF_PICS];
11764cfc8edSsvemuri } zam_perf_regs_t;
11864cfc8edSsvemuri 
11964cfc8edSsvemuri static zam_perf_regs_t lpu_perf_regs[] = {
12064cfc8edSsvemuri 	{HV_ZAM0_LPU_A_PCR, HV_ZAM0_LPU_A_PIC0, HV_ZAM0_LPU_A_PIC1},
12164cfc8edSsvemuri 	{HV_ZAM0_LPU_B_PCR, HV_ZAM0_LPU_B_PIC0, HV_ZAM0_LPU_B_PIC1},
12264cfc8edSsvemuri 	{HV_ZAM0_LPU_C_PCR, HV_ZAM0_LPU_C_PIC0, HV_ZAM0_LPU_C_PIC1},
12364cfc8edSsvemuri 	{HV_ZAM0_LPU_D_PCR, HV_ZAM0_LPU_D_PIC0, HV_ZAM0_LPU_D_PIC1},
12464cfc8edSsvemuri 
12564cfc8edSsvemuri 	{HV_ZAM1_LPU_A_PCR, HV_ZAM1_LPU_A_PIC0, HV_ZAM1_LPU_A_PIC1},
12664cfc8edSsvemuri 	{HV_ZAM1_LPU_B_PCR, HV_ZAM1_LPU_B_PIC0, HV_ZAM1_LPU_B_PIC1},
12764cfc8edSsvemuri 	{HV_ZAM1_LPU_C_PCR, HV_ZAM1_LPU_C_PIC0, HV_ZAM1_LPU_C_PIC1},
12864cfc8edSsvemuri 	{HV_ZAM1_LPU_D_PCR, HV_ZAM1_LPU_D_PIC0, HV_ZAM1_LPU_D_PIC1},
12964cfc8edSsvemuri 
13064cfc8edSsvemuri 	{HV_ZAM2_LPU_A_PCR, HV_ZAM2_LPU_A_PIC0, HV_ZAM2_LPU_A_PIC1},
13164cfc8edSsvemuri 	{HV_ZAM2_LPU_B_PCR, HV_ZAM2_LPU_B_PIC0, HV_ZAM2_LPU_B_PIC1},
13264cfc8edSsvemuri 	{HV_ZAM2_LPU_C_PCR, HV_ZAM2_LPU_C_PIC0, HV_ZAM2_LPU_C_PIC1},
13364cfc8edSsvemuri 	{HV_ZAM2_LPU_D_PCR, HV_ZAM2_LPU_D_PIC0, HV_ZAM2_LPU_D_PIC1},
13464cfc8edSsvemuri 
13564cfc8edSsvemuri 	{HV_ZAM3_LPU_A_PCR, HV_ZAM3_LPU_A_PIC0, HV_ZAM3_LPU_A_PIC1},
13664cfc8edSsvemuri 	{HV_ZAM3_LPU_B_PCR, HV_ZAM3_LPU_B_PIC0, HV_ZAM3_LPU_B_PIC1},
13764cfc8edSsvemuri 	{HV_ZAM3_LPU_C_PCR, HV_ZAM3_LPU_C_PIC0, HV_ZAM3_LPU_C_PIC1},
13864cfc8edSsvemuri 	{HV_ZAM3_LPU_D_PCR, HV_ZAM3_LPU_D_PIC0, HV_ZAM3_LPU_D_PIC1}
13964cfc8edSsvemuri };
14064cfc8edSsvemuri 
14164cfc8edSsvemuri static zam_perf_regs_t gpd_perf_regs[] = {
14264cfc8edSsvemuri 	{HV_ZAM0_GPD_PCR, HV_ZAM0_GPD_PIC0, HV_ZAM0_GPD_PIC1},
14364cfc8edSsvemuri 	{HV_ZAM1_GPD_PCR, HV_ZAM1_GPD_PIC0, HV_ZAM1_GPD_PIC1},
14464cfc8edSsvemuri 	{HV_ZAM2_GPD_PCR, HV_ZAM2_GPD_PIC0, HV_ZAM2_GPD_PIC1},
14564cfc8edSsvemuri 	{HV_ZAM3_GPD_PCR, HV_ZAM3_GPD_PIC0, HV_ZAM3_GPD_PIC1}
14664cfc8edSsvemuri };
14764cfc8edSsvemuri 
14864cfc8edSsvemuri static zam_perf_regs_t asu_perf_regs[] = {
14964cfc8edSsvemuri 	{HV_ZAM0_ASU_PCR, HV_ZAM0_ASU_PIC0, HV_ZAM0_ASU_PIC1},
15064cfc8edSsvemuri 	{HV_ZAM1_ASU_PCR, HV_ZAM1_ASU_PIC0, HV_ZAM1_ASU_PIC1},
15164cfc8edSsvemuri 	{HV_ZAM2_ASU_PCR, HV_ZAM2_ASU_PIC0, HV_ZAM2_ASU_PIC1},
15264cfc8edSsvemuri 	{HV_ZAM3_ASU_PCR, HV_ZAM3_ASU_PIC0, HV_ZAM3_ASU_PIC1}
15364cfc8edSsvemuri };
15464cfc8edSsvemuri 
15564cfc8edSsvemuri static int zam_cntr_kstat_update(kstat_t *, int);
15664cfc8edSsvemuri #endif
15764cfc8edSsvemuri 
1587c478bd9Sstevel@tonic-gate static void ni_create_name_kstat(char *, ni_ksinfo_t *, ni_kev_mask_t *);
1597c478bd9Sstevel@tonic-gate static void ni_delete_name_kstat(ni_ksinfo_t *);
1607c478bd9Sstevel@tonic-gate 
1617c478bd9Sstevel@tonic-gate static kstat_t *ni_create_cntr_kstat(char *, int,
1627c478bd9Sstevel@tonic-gate 	int (*update)(kstat_t *, int), void *);
1637c478bd9Sstevel@tonic-gate 
1647c478bd9Sstevel@tonic-gate static int ni_cntr_kstat_update(kstat_t *, int);
1657c478bd9Sstevel@tonic-gate 
1667c478bd9Sstevel@tonic-gate static kstat_t *ni_create_picN_kstat(char *, int, int, int,
1677c478bd9Sstevel@tonic-gate 	ni_kev_mask_t *);
1687c478bd9Sstevel@tonic-gate 
1697c478bd9Sstevel@tonic-gate #ifdef DEBUG
1707c478bd9Sstevel@tonic-gate static int	ni_perf_debug;
1717c478bd9Sstevel@tonic-gate #endif
1727c478bd9Sstevel@tonic-gate 
1737c478bd9Sstevel@tonic-gate /*
17459ac0c16Sdavemq  * Niagara, Niagara2 and VFalls DRAM Performance Events
1757c478bd9Sstevel@tonic-gate  */
1767c478bd9Sstevel@tonic-gate static ni_kev_mask_t
1777c478bd9Sstevel@tonic-gate niagara_dram_events[] = {
178*4df55fdeSJanie Lu #if defined(NIAGARA_IMPL) || defined(NIAGARA2_IMPL) || defined(VFALLS_IMPL)
1797c478bd9Sstevel@tonic-gate 	{"mem_reads",		0x0},
1807c478bd9Sstevel@tonic-gate 	{"mem_writes",		0x1},
1817c478bd9Sstevel@tonic-gate 	{"mem_read_write",	0x2},
182*4df55fdeSJanie Lu #elif defined(KT_IMPL)
183*4df55fdeSJanie Lu 	{"remote_reads",	0x0},
184*4df55fdeSJanie Lu 	{"remote_writes",	0x1},
185*4df55fdeSJanie Lu 	{"remote_read_write",	0x2},
186*4df55fdeSJanie Lu #endif
187*4df55fdeSJanie Lu #if defined(NIAGARA_IMPL) || defined(KT_IMPL)
1887c478bd9Sstevel@tonic-gate 	{"bank_busy_stalls",	0x3},
189a588362cSSree Vemuri #endif
1907c478bd9Sstevel@tonic-gate 	{"rd_queue_latency",	0x4},
1917c478bd9Sstevel@tonic-gate 	{"wr_queue_latency",	0x5},
1927c478bd9Sstevel@tonic-gate 	{"rw_queue_latency",	0x6},
193*4df55fdeSJanie Lu #if defined(NIAGARA_IMPL) || defined(NIAGARA2_IMPL) || defined(VFALLS_IMPL)
1947c478bd9Sstevel@tonic-gate 	{"wb_buf_hits",		0x7},
195*4df55fdeSJanie Lu #elif defined(KT_IMPL)
196*4df55fdeSJanie Lu 	{"write_queue_drain",	0x7},
197*4df55fdeSJanie Lu 	{"read_all_channels",	0x8},
198*4df55fdeSJanie Lu 	{"write_starved",	0x9},
199*4df55fdeSJanie Lu 	{"write_all_channels",	0xa},
200*4df55fdeSJanie Lu 	{"read_write_channel0",	0xb},
201*4df55fdeSJanie Lu 	{"read_write_channel1",	0xc},
202*4df55fdeSJanie Lu #endif
2037c478bd9Sstevel@tonic-gate 	{"clear_pic",		0xf}
2047c478bd9Sstevel@tonic-gate };
2057c478bd9Sstevel@tonic-gate 
20664cfc8edSsvemuri #if defined(VFALLS_IMPL)
20764cfc8edSsvemuri /*
20864cfc8edSsvemuri  * Zambezi Performance Events
20964cfc8edSsvemuri  */
21064cfc8edSsvemuri static ni_kev_mask_t
21164cfc8edSsvemuri zam_lpu_perf_events[] = {
21264cfc8edSsvemuri 	{"none",		0x0},
21364cfc8edSsvemuri 	{"clock_cycles",	0x1},
21464cfc8edSsvemuri 	{"cycles_c2c_portX",	0x2},
21564cfc8edSsvemuri 	{"cycles_mem_portX",	0x3},
21664cfc8edSsvemuri 	{"cycles_WB_portX",	0x4},
21764cfc8edSsvemuri 	{"cycles_NC_portX",	0x5},
21864cfc8edSsvemuri 	{"cycles_c2c_portY",	0x6},
21964cfc8edSsvemuri 	{"cycles_mem_portY",	0x7},
22064cfc8edSsvemuri 	{"cycles_WB_portY",	0x8},
22164cfc8edSsvemuri 	{"cycles_NC_portY",	0x9},
22264cfc8edSsvemuri 	{"cycles_c2c_portZ",	0xa},
22364cfc8edSsvemuri 	{"cycles_mem_portZ",	0xb},
22464cfc8edSsvemuri 	{"cycles_WB_portZ",	0xc},
22564cfc8edSsvemuri 	{"cycles_NC_portZ",	0xd},
22664cfc8edSsvemuri 	{"cycles_TID_WB",	0xe},
22764cfc8edSsvemuri 	{"cycles_TID_INV",	0xf},
22864cfc8edSsvemuri 	{"cycles_TID_RTD",	0x10},
22964cfc8edSsvemuri 	{"cycles_TID_RTO",	0x11},
23064cfc8edSsvemuri 	{"cycles_TID_RTS",	0x12},
23164cfc8edSsvemuri 	{"cycles_IO_WRM",	0x13},
23264cfc8edSsvemuri 	{"cycles_IO_RD",	0x14},
23364cfc8edSsvemuri 	{"cycles_WB_egress",	0x15},
23464cfc8edSsvemuri 	{"cycles_INV_egress",	0x16},
23564cfc8edSsvemuri 	{"cycles_RTO_egress",	0x17},
23664cfc8edSsvemuri 	{"cycles_RTD_egress",	0x18},
23764cfc8edSsvemuri 	{"cycles_RTS_egress",	0x19},
23864cfc8edSsvemuri 	{"cycles_no_WB",	0x1a},
23964cfc8edSsvemuri 	{"cycles_no_read/inv",	0x1b},
24064cfc8edSsvemuri 	{"cycles_HIT_M",	0x1c},
24164cfc8edSsvemuri 	{"cycles_HIT_O",	0x1d},
24264cfc8edSsvemuri 	{"cycles_HIT_S",	0x1e},
24364cfc8edSsvemuri 	{"cycles_WB_HIT",	0x1f},
24464cfc8edSsvemuri 	{"cycles_MISS",		0x20},
24564cfc8edSsvemuri 	{"cycles_READ_or_INV",	0x21},
24664cfc8edSsvemuri 	{"cycles_WB",		0x22},
24764cfc8edSsvemuri 	{"cycles_NDR",		0x23},
24864cfc8edSsvemuri 	{"cycles_cache_miss",	0x24},
24964cfc8edSsvemuri 	{"cycles_cache_hit",	0x25},
25064cfc8edSsvemuri 	{"cycles_CRC_errors",	0x26},
25164cfc8edSsvemuri 	{"cycles_replys_sent",	0x27},
25264cfc8edSsvemuri 	{"cycles_replys_recev",	0x28},
25364cfc8edSsvemuri 	{"cycles_link_retrain",	0x29},
25464cfc8edSsvemuri 	{"clear_pic",		0xff}
25564cfc8edSsvemuri };
25664cfc8edSsvemuri 
25764cfc8edSsvemuri static ni_kev_mask_t
25864cfc8edSsvemuri zam_gpd_perf_events[] = {
25964cfc8edSsvemuri 	{"none",		0x0},
26064cfc8edSsvemuri 	{"clock_cycles",	0x1},
26164cfc8edSsvemuri 	{"clear_pic",		0xf}
26264cfc8edSsvemuri };
26364cfc8edSsvemuri 
26464cfc8edSsvemuri static ni_kev_mask_t
26564cfc8edSsvemuri zam_asu_perf_events[] = {
26664cfc8edSsvemuri 	{"none",		0x0},
26764cfc8edSsvemuri 	{"clock_cycles",	0x1},
26864cfc8edSsvemuri 	{"asu_in_pck",		0x2},
26964cfc8edSsvemuri 	{"asu_out_pck",		0x3},
27064cfc8edSsvemuri 	{"asu_CAM_hit",		0x4},
27164cfc8edSsvemuri 	{"asu_wakeup",		0x5},
27264cfc8edSsvemuri 	{"clear_pic",		0xf}
27364cfc8edSsvemuri };
27464cfc8edSsvemuri #endif
2757c478bd9Sstevel@tonic-gate 
27644961713Sgirish #if defined(NIAGARA_IMPL)
2777c478bd9Sstevel@tonic-gate /*
2787c478bd9Sstevel@tonic-gate  * Niagara JBUS Performance Events
2797c478bd9Sstevel@tonic-gate  */
2807c478bd9Sstevel@tonic-gate static ni_kev_mask_t
2817c478bd9Sstevel@tonic-gate niagara_jbus_events[] = {
2827c478bd9Sstevel@tonic-gate 	{"jbus_cycles",		0x1},
2837c478bd9Sstevel@tonic-gate 	{"dma_reads",		0x2},
2847c478bd9Sstevel@tonic-gate 	{"dma_read_latency",	0x3},
2857c478bd9Sstevel@tonic-gate 	{"dma_writes",		0x4},
2867c478bd9Sstevel@tonic-gate 	{"dma_write8",		0x5},
2877c478bd9Sstevel@tonic-gate 	{"ordering_waits",	0x6},
2887c478bd9Sstevel@tonic-gate 	{"pio_reads",		0x8},
2897c478bd9Sstevel@tonic-gate 	{"pio_read_latency",	0x9},
2907c478bd9Sstevel@tonic-gate 	{"aok_dok_off_cycles",	0xc},
2917c478bd9Sstevel@tonic-gate 	{"aok_off_cycles",	0xd},
2927c478bd9Sstevel@tonic-gate 	{"dok_off_cycles",	0xe},
2937c478bd9Sstevel@tonic-gate 	{"clear_pic",		0xf}
2947c478bd9Sstevel@tonic-gate };
29544961713Sgirish #endif
2967c478bd9Sstevel@tonic-gate 
2977c478bd9Sstevel@tonic-gate /*
29864cfc8edSsvemuri  * Create the picN kstats for DRAM, JBUS and Zambezi events
2997c478bd9Sstevel@tonic-gate  */
3007c478bd9Sstevel@tonic-gate void
3017c478bd9Sstevel@tonic-gate niagara_kstat_init()
3027c478bd9Sstevel@tonic-gate {
3037c478bd9Sstevel@tonic-gate 	int i;
3047c478bd9Sstevel@tonic-gate 	ni_ksinfo_t *ksinfop;
305*4df55fdeSJanie Lu #if defined(VFALLS_IMPL) || defined(KT_IMPL)
306b02e9a2dSsvemuri 	uint64_t stat, pcr;
307b02e9a2dSsvemuri #endif
3087c478bd9Sstevel@tonic-gate 
3097c478bd9Sstevel@tonic-gate #ifdef DEBUG
3107c478bd9Sstevel@tonic-gate 	if (ni_perf_debug)
3117c478bd9Sstevel@tonic-gate 		printf("ni_kstat_init called\n");
3127c478bd9Sstevel@tonic-gate #endif
3137c478bd9Sstevel@tonic-gate 
3147c478bd9Sstevel@tonic-gate 	/*
3157c478bd9Sstevel@tonic-gate 	 * Create DRAM perf events kstat
3167c478bd9Sstevel@tonic-gate 	 */
317*4df55fdeSJanie Lu 	for (i = 0; i < DRAM_BANKS; i++) {
318*4df55fdeSJanie Lu #if defined(VFALLS_IMPL) || defined(KT_IMPL)
31959ac0c16Sdavemq 		/* check if this dram instance is enabled in the HW */
32064cfc8edSsvemuri 		stat = hv_niagara_getperf(dram_perf_regs[i].pcr_reg, &pcr);
32164cfc8edSsvemuri 		if ((stat != H_EINVAL) && (stat != H_ENOTSUPPORTED)) {
32259ac0c16Sdavemq #endif
32359ac0c16Sdavemq 			ksinfop = (ni_ksinfo_t *)kmem_zalloc(
32459ac0c16Sdavemq 			    sizeof (ni_ksinfo_t), KM_NOSLEEP);
3257c478bd9Sstevel@tonic-gate 
3267c478bd9Sstevel@tonic-gate 			if (ksinfop == NULL) {
3277c478bd9Sstevel@tonic-gate 				cmn_err(CE_WARN,
32859ac0c16Sdavemq 				    "%s: no space for dram kstat\n",
329c56c1e58Sgirish 				    cpu_module_name);
3307c478bd9Sstevel@tonic-gate 				break;
3317c478bd9Sstevel@tonic-gate 			}
3327c478bd9Sstevel@tonic-gate 			ksinfop->pic_no_evs =
33359ac0c16Sdavemq 			    sizeof (niagara_dram_events) /
33459ac0c16Sdavemq 			    sizeof (ni_kev_mask_t);
335*4df55fdeSJanie Lu 			ksinfop->pic_sel_shift[0] = DRAM_PIC0_SEL_SHIFT;
336*4df55fdeSJanie Lu 			ksinfop->pic_shift[0] = DRAM_PIC0_SHIFT;
337*4df55fdeSJanie Lu 			ksinfop->pic_mask[0] = DRAM_PIC0_MASK;
338*4df55fdeSJanie Lu 			ksinfop->pic_sel_shift[1] = DRAM_PIC1_SEL_SHIFT;
339*4df55fdeSJanie Lu 			ksinfop->pic_shift[1] = DRAM_PIC1_SHIFT;
340*4df55fdeSJanie Lu 			ksinfop->pic_mask[1] = DRAM_PIC1_MASK;
341*4df55fdeSJanie Lu 			ksinfop->pic_reg[0] = dram_perf_regs[i].pic_reg[0];
3427c478bd9Sstevel@tonic-gate 			ksinfop->pcr_reg = dram_perf_regs[i].pcr_reg;
3437c478bd9Sstevel@tonic-gate 			ni_dram_kstats[i] = ksinfop;
3447c478bd9Sstevel@tonic-gate 
3457c478bd9Sstevel@tonic-gate 			/* create basic pic event/mask pair (only once) */
3467c478bd9Sstevel@tonic-gate 			if (i == 0)
3477c478bd9Sstevel@tonic-gate 				ni_create_name_kstat("dram", ksinfop,
3487c478bd9Sstevel@tonic-gate 				    niagara_dram_events);
3497c478bd9Sstevel@tonic-gate 
3507c478bd9Sstevel@tonic-gate 			/* create counter kstats */
35159ac0c16Sdavemq 			ni_dram_kstats[i]->cntr_ksp = ni_create_cntr_kstat(
35259ac0c16Sdavemq 			    "dram", i, ni_cntr_kstat_update, ksinfop);
353*4df55fdeSJanie Lu #if defined(VFALLS_IMPL) || defined(KT_IMPL)
35459ac0c16Sdavemq 		}
35559ac0c16Sdavemq #endif
3567c478bd9Sstevel@tonic-gate 	}
3577c478bd9Sstevel@tonic-gate 
35864cfc8edSsvemuri #ifdef VFALLS_IMPL
35964cfc8edSsvemuri 	/*
36064cfc8edSsvemuri 	 * Create Zambezi LPU perf events kstat
36164cfc8edSsvemuri 	 */
36264cfc8edSsvemuri 	for (i = 0; i < ZAMBEZI_LPU_COUNTERS; i++) {
36364cfc8edSsvemuri 		/* check if this Zambezi LPU instance is enabled in the HW */
36464cfc8edSsvemuri 		stat = hv_niagara_getperf(lpu_perf_regs[i].pcr_reg, &pcr);
36564cfc8edSsvemuri 		if ((stat != H_EINVAL) && (stat != H_ENOTSUPPORTED)) {
36664cfc8edSsvemuri 			ksinfop = (ni_ksinfo_t *)kmem_zalloc(
36764cfc8edSsvemuri 			    sizeof (ni_ksinfo_t), KM_NOSLEEP);
36864cfc8edSsvemuri 
36964cfc8edSsvemuri 			if (ksinfop == NULL) {
37064cfc8edSsvemuri 				cmn_err(CE_WARN,
37164cfc8edSsvemuri 				    "%s: no space for zambezi lpu kstat\n",
37264cfc8edSsvemuri 				    cpu_module_name);
37364cfc8edSsvemuri 				break;
37464cfc8edSsvemuri 			}
37564cfc8edSsvemuri 			ksinfop->pic_no_evs =
37664cfc8edSsvemuri 			    sizeof (zam_lpu_perf_events) /
37764cfc8edSsvemuri 			    sizeof (ni_kev_mask_t);
37864cfc8edSsvemuri 			ksinfop->pic_sel_shift[0] = ZAMBEZI_PIC0_SEL_SHIFT;
37964cfc8edSsvemuri 			ksinfop->pic_reg[0] = lpu_perf_regs[i].pic_reg[0];
38064cfc8edSsvemuri 			ksinfop->pic_sel_shift[1] = ZAMBEZI_PIC1_SEL_SHIFT;
38164cfc8edSsvemuri 			ksinfop->pic_reg[1] = lpu_perf_regs[i].pic_reg[1];
38264cfc8edSsvemuri 			ksinfop->pcr_reg = lpu_perf_regs[i].pcr_reg;
38364cfc8edSsvemuri 			zam_lpu_kstats[i] = ksinfop;
38464cfc8edSsvemuri 
38564cfc8edSsvemuri 			/* create basic pic event/mask pair (only once) */
38664cfc8edSsvemuri 			if (i == 0)
38764cfc8edSsvemuri 				ni_create_name_kstat("lpu", ksinfop,
38864cfc8edSsvemuri 				    zam_lpu_perf_events);
38964cfc8edSsvemuri 
39064cfc8edSsvemuri 			/* create counter kstats */
39164cfc8edSsvemuri 			zam_lpu_kstats[i]->cntr_ksp = ni_create_cntr_kstat(
39264cfc8edSsvemuri 			    "lpu", i, zam_cntr_kstat_update, ksinfop);
39364cfc8edSsvemuri 		}
39464cfc8edSsvemuri 	}
39564cfc8edSsvemuri 	/*
39664cfc8edSsvemuri 	 * Create Zambezi GPD perf events kstat
39764cfc8edSsvemuri 	 */
39864cfc8edSsvemuri 	for (i = 0; i < ZAMBEZI_GPD_COUNTERS; i++) {
39964cfc8edSsvemuri 		/* check if this Zambezi GPD instance is enabled in the HW */
40064cfc8edSsvemuri 		stat = hv_niagara_getperf(gpd_perf_regs[i].pcr_reg, &pcr);
40164cfc8edSsvemuri 		if ((stat != H_EINVAL) && (stat != H_ENOTSUPPORTED)) {
40264cfc8edSsvemuri 			ksinfop = (ni_ksinfo_t *)kmem_zalloc(
40364cfc8edSsvemuri 			    sizeof (ni_ksinfo_t), KM_NOSLEEP);
40464cfc8edSsvemuri 
40564cfc8edSsvemuri 			if (ksinfop == NULL) {
40664cfc8edSsvemuri 				cmn_err(CE_WARN,
40764cfc8edSsvemuri 				    "%s: no space for zambezi gpd kstat\n",
40864cfc8edSsvemuri 				    cpu_module_name);
40964cfc8edSsvemuri 				break;
41064cfc8edSsvemuri 			}
41164cfc8edSsvemuri 			ksinfop->pic_no_evs =
41264cfc8edSsvemuri 			    sizeof (zam_gpd_perf_events) /
41364cfc8edSsvemuri 			    sizeof (ni_kev_mask_t);
41464cfc8edSsvemuri 			ksinfop->pic_sel_shift[0] = ZAMBEZI_PIC0_SEL_SHIFT;
41564cfc8edSsvemuri 			ksinfop->pic_reg[0] = gpd_perf_regs[i].pic_reg[0];
41664cfc8edSsvemuri 			ksinfop->pic_sel_shift[1] = ZAMBEZI_PIC1_SEL_SHIFT;
41764cfc8edSsvemuri 			ksinfop->pic_reg[1] = gpd_perf_regs[i].pic_reg[1];
41864cfc8edSsvemuri 			ksinfop->pcr_reg = gpd_perf_regs[i].pcr_reg;
41964cfc8edSsvemuri 			zam_gpd_kstats[i] = ksinfop;
42064cfc8edSsvemuri 
42164cfc8edSsvemuri 			/* create basic pic event/mask pair (only once) */
42264cfc8edSsvemuri 			if (i == 0)
42364cfc8edSsvemuri 				ni_create_name_kstat("gpd", ksinfop,
42464cfc8edSsvemuri 				    zam_gpd_perf_events);
42564cfc8edSsvemuri 
42664cfc8edSsvemuri 			/* create counter kstats */
42764cfc8edSsvemuri 			zam_lpu_kstats[i]->cntr_ksp = ni_create_cntr_kstat(
42864cfc8edSsvemuri 			    "gpd", i, zam_cntr_kstat_update, ksinfop);
42964cfc8edSsvemuri 		}
43064cfc8edSsvemuri 	}
43164cfc8edSsvemuri 	/*
43264cfc8edSsvemuri 	 * Create Zambezi ASU perf events kstat
43364cfc8edSsvemuri 	 */
43464cfc8edSsvemuri 	for (i = 0; i < ZAMBEZI_ASU_COUNTERS; i++) {
43564cfc8edSsvemuri 		/* check if this Zambezi ASU instance is enabled in the HW */
43664cfc8edSsvemuri 		stat = hv_niagara_getperf(asu_perf_regs[i].pcr_reg, &pcr);
43764cfc8edSsvemuri 		if ((stat != H_EINVAL) && (stat != H_ENOTSUPPORTED)) {
43864cfc8edSsvemuri 			ksinfop = (ni_ksinfo_t *)kmem_zalloc(
43964cfc8edSsvemuri 			    sizeof (ni_ksinfo_t), KM_NOSLEEP);
44064cfc8edSsvemuri 
44164cfc8edSsvemuri 			if (ksinfop == NULL) {
44264cfc8edSsvemuri 				cmn_err(CE_WARN,
44364cfc8edSsvemuri 				    "%s: no space for zambezi asu kstat\n",
44464cfc8edSsvemuri 				    cpu_module_name);
44564cfc8edSsvemuri 				break;
44664cfc8edSsvemuri 			}
44764cfc8edSsvemuri 			ksinfop->pic_no_evs =
44864cfc8edSsvemuri 			    sizeof (zam_asu_perf_events) /
44964cfc8edSsvemuri 			    sizeof (ni_kev_mask_t);
45064cfc8edSsvemuri 			ksinfop->pic_sel_shift[0] = ZAMBEZI_PIC0_SEL_SHIFT;
45164cfc8edSsvemuri 			ksinfop->pic_reg[0] = asu_perf_regs[i].pic_reg[0];
45264cfc8edSsvemuri 			ksinfop->pic_sel_shift[1] = ZAMBEZI_PIC1_SEL_SHIFT;
45364cfc8edSsvemuri 			ksinfop->pic_reg[1] = asu_perf_regs[i].pic_reg[1];
45464cfc8edSsvemuri 			ksinfop->pcr_reg = asu_perf_regs[i].pcr_reg;
45564cfc8edSsvemuri 			zam_asu_kstats[i] = ksinfop;
45664cfc8edSsvemuri 
45764cfc8edSsvemuri 			/* create basic pic event/mask pair (only once) */
45864cfc8edSsvemuri 			if (i == 0)
45964cfc8edSsvemuri 				ni_create_name_kstat("asu", ksinfop,
46064cfc8edSsvemuri 				    zam_asu_perf_events);
46164cfc8edSsvemuri 
46264cfc8edSsvemuri 			/* create counter kstats */
46364cfc8edSsvemuri 			zam_lpu_kstats[i]->cntr_ksp = ni_create_cntr_kstat(
46464cfc8edSsvemuri 			    "asu", i, zam_cntr_kstat_update, ksinfop);
46564cfc8edSsvemuri 		}
46664cfc8edSsvemuri 	}
46764cfc8edSsvemuri #endif
46864cfc8edSsvemuri 
46944961713Sgirish #if defined(NIAGARA_IMPL)
4707c478bd9Sstevel@tonic-gate 	/*
4717c478bd9Sstevel@tonic-gate 	 * Create JBUS perf events kstat
4727c478bd9Sstevel@tonic-gate 	 */
4737c478bd9Sstevel@tonic-gate 	ni_jbus_kstat = (ni_ksinfo_t *)kmem_alloc(sizeof (ni_ksinfo_t),
4747c478bd9Sstevel@tonic-gate 	    KM_NOSLEEP);
4757c478bd9Sstevel@tonic-gate 
4767c478bd9Sstevel@tonic-gate 	if (ni_jbus_kstat == NULL) {
4777c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "%s: no space for niagara jbus kstat\n",
478c56c1e58Sgirish 		    cpu_module_name);
4797c478bd9Sstevel@tonic-gate 	} else {
4807c478bd9Sstevel@tonic-gate 		ni_jbus_kstat->pic_no_evs =
4817c478bd9Sstevel@tonic-gate 		    sizeof (niagara_jbus_events) / sizeof (ni_kev_mask_t);
4827c478bd9Sstevel@tonic-gate 		ni_jbus_kstat->pic_sel_shift[0] = NIAGARA_JBUS_PIC0_SEL_SHIFT;
4837c478bd9Sstevel@tonic-gate 		ni_jbus_kstat->pic_shift[0] = NIAGARA_JBUS_PIC0_SHIFT;
4847c478bd9Sstevel@tonic-gate 		ni_jbus_kstat->pic_mask[0] = NIAGARA_JBUS_PIC0_MASK;
4857c478bd9Sstevel@tonic-gate 		ni_jbus_kstat->pic_sel_shift[1] = NIAGARA_JBUS_PIC1_SEL_SHIFT;
4867c478bd9Sstevel@tonic-gate 		ni_jbus_kstat->pic_shift[1] = NIAGARA_JBUS_PIC1_SHIFT;
4877c478bd9Sstevel@tonic-gate 		ni_jbus_kstat->pic_mask[1] = NIAGARA_JBUS_PIC1_MASK;
48864cfc8edSsvemuri 		ni_jbus_kstat->pic_reg[0] = HV_NIAGARA_JBUS_COUNT;
4897c478bd9Sstevel@tonic-gate 		ni_jbus_kstat->pcr_reg = HV_NIAGARA_JBUS_CTL;
4907c478bd9Sstevel@tonic-gate 		ni_create_name_kstat("jbus", ni_jbus_kstat,
4917c478bd9Sstevel@tonic-gate 		    niagara_jbus_events);
4927c478bd9Sstevel@tonic-gate 		ni_jbus_kstat->cntr_ksp = ni_create_cntr_kstat("jbus", 0,
4937c478bd9Sstevel@tonic-gate 		    ni_cntr_kstat_update, ni_jbus_kstat);
4947c478bd9Sstevel@tonic-gate 	}
49544961713Sgirish #endif
4967c478bd9Sstevel@tonic-gate }
4977c478bd9Sstevel@tonic-gate 
4987c478bd9Sstevel@tonic-gate void
4997c478bd9Sstevel@tonic-gate niagara_kstat_fini()
5007c478bd9Sstevel@tonic-gate {
5017c478bd9Sstevel@tonic-gate 	int i;
5027c478bd9Sstevel@tonic-gate 
5037c478bd9Sstevel@tonic-gate #ifdef DEBUG
5047c478bd9Sstevel@tonic-gate 	if (ni_perf_debug)
5057c478bd9Sstevel@tonic-gate 		printf("ni_kstat_fini called\n");
5067c478bd9Sstevel@tonic-gate #endif
50764cfc8edSsvemuri 
508*4df55fdeSJanie Lu 	for (i = 0; i < DRAM_BANKS; i++) {
5097c478bd9Sstevel@tonic-gate 		if (ni_dram_kstats[i] != NULL) {
5107c478bd9Sstevel@tonic-gate 			ni_delete_name_kstat(ni_dram_kstats[i]);
5117c478bd9Sstevel@tonic-gate 			if (ni_dram_kstats[i]->cntr_ksp != NULL)
5127c478bd9Sstevel@tonic-gate 				kstat_delete(ni_dram_kstats[i]->cntr_ksp);
5137c478bd9Sstevel@tonic-gate 			kmem_free(ni_dram_kstats[i], sizeof (ni_ksinfo_t));
5147c478bd9Sstevel@tonic-gate 			ni_dram_kstats[i] = NULL;
5157c478bd9Sstevel@tonic-gate 		}
5167c478bd9Sstevel@tonic-gate 	}
5177c478bd9Sstevel@tonic-gate 
51864cfc8edSsvemuri #if defined(VFALLS_IMPL)
51964cfc8edSsvemuri 	for (i = 0; i < ZAMBEZI_LPU_COUNTERS; i++) {
52064cfc8edSsvemuri 		if (zam_lpu_kstats[i] != NULL) {
52164cfc8edSsvemuri 			ni_delete_name_kstat(zam_lpu_kstats[i]);
52264cfc8edSsvemuri 			if (zam_lpu_kstats[i]->cntr_ksp != NULL)
52364cfc8edSsvemuri 				kstat_delete(zam_lpu_kstats[i]->cntr_ksp);
52464cfc8edSsvemuri 			kmem_free(zam_lpu_kstats[i], sizeof (ni_ksinfo_t));
52564cfc8edSsvemuri 			zam_lpu_kstats[i] = NULL;
52664cfc8edSsvemuri 		}
52764cfc8edSsvemuri 	}
52864cfc8edSsvemuri 
52964cfc8edSsvemuri 	for (i = 0; i < ZAMBEZI_GPD_COUNTERS; i++) {
53064cfc8edSsvemuri 		if (zam_gpd_kstats[i] != NULL) {
53164cfc8edSsvemuri 			ni_delete_name_kstat(zam_gpd_kstats[i]);
53264cfc8edSsvemuri 			if (zam_gpd_kstats[i]->cntr_ksp != NULL)
53364cfc8edSsvemuri 				kstat_delete(zam_gpd_kstats[i]->cntr_ksp);
53464cfc8edSsvemuri 			kmem_free(zam_gpd_kstats[i], sizeof (ni_ksinfo_t));
53564cfc8edSsvemuri 			zam_gpd_kstats[i] = NULL;
53664cfc8edSsvemuri 		}
53764cfc8edSsvemuri 	}
53864cfc8edSsvemuri 
53964cfc8edSsvemuri 	for (i = 0; i < ZAMBEZI_ASU_COUNTERS; i++) {
54064cfc8edSsvemuri 		if (zam_asu_kstats[i] != NULL) {
54164cfc8edSsvemuri 			ni_delete_name_kstat(zam_asu_kstats[i]);
54264cfc8edSsvemuri 			if (zam_asu_kstats[i]->cntr_ksp != NULL)
54364cfc8edSsvemuri 				kstat_delete(zam_asu_kstats[i]->cntr_ksp);
54464cfc8edSsvemuri 			kmem_free(zam_asu_kstats[i], sizeof (ni_ksinfo_t));
54564cfc8edSsvemuri 			zam_asu_kstats[i] = NULL;
54664cfc8edSsvemuri 		}
54764cfc8edSsvemuri 	}
54864cfc8edSsvemuri #endif
54964cfc8edSsvemuri 
55044961713Sgirish #if defined(NIAGARA_IMPL)
5517c478bd9Sstevel@tonic-gate 	if (ni_jbus_kstat != NULL) {
5527c478bd9Sstevel@tonic-gate 		ni_delete_name_kstat(ni_jbus_kstat);
5537c478bd9Sstevel@tonic-gate 		if (ni_jbus_kstat->cntr_ksp != NULL)
5547c478bd9Sstevel@tonic-gate 			kstat_delete(ni_jbus_kstat->cntr_ksp);
5557c478bd9Sstevel@tonic-gate 		kmem_free(ni_jbus_kstat, sizeof (ni_ksinfo_t));
5567c478bd9Sstevel@tonic-gate 		ni_jbus_kstat = NULL;
5577c478bd9Sstevel@tonic-gate 	}
55844961713Sgirish #endif
5597c478bd9Sstevel@tonic-gate }
5607c478bd9Sstevel@tonic-gate 
5617c478bd9Sstevel@tonic-gate static void
5627c478bd9Sstevel@tonic-gate ni_create_name_kstat(char *name, ni_ksinfo_t *pp, ni_kev_mask_t *ev)
5637c478bd9Sstevel@tonic-gate {
5647c478bd9Sstevel@tonic-gate 	int	i;
5657c478bd9Sstevel@tonic-gate 
5667c478bd9Sstevel@tonic-gate #ifdef DEBUG
5677c478bd9Sstevel@tonic-gate 	if (ni_perf_debug > 1)
5687c478bd9Sstevel@tonic-gate 		printf("ni_create_name_kstat: name: %s\n", name);
5697c478bd9Sstevel@tonic-gate #endif
5707c478bd9Sstevel@tonic-gate 	for (i = 0; i < NUM_OF_PICS; i++) {
5717c478bd9Sstevel@tonic-gate 		pp->pic_name_ksp[i] = ni_create_picN_kstat(name,
5727c478bd9Sstevel@tonic-gate 		    i, pp->pic_sel_shift[i], pp->pic_no_evs, ev);
5737c478bd9Sstevel@tonic-gate 
5747c478bd9Sstevel@tonic-gate 		if (pp->pic_name_ksp[i] == NULL) {
5757c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN, "%s: unable to create name kstat",
576c56c1e58Sgirish 			    cpu_module_name);
5777c478bd9Sstevel@tonic-gate 		}
5787c478bd9Sstevel@tonic-gate 	}
5797c478bd9Sstevel@tonic-gate }
5807c478bd9Sstevel@tonic-gate 
5817c478bd9Sstevel@tonic-gate static void
5827c478bd9Sstevel@tonic-gate ni_delete_name_kstat(ni_ksinfo_t *pp)
5837c478bd9Sstevel@tonic-gate {
5847c478bd9Sstevel@tonic-gate 	int	i;
5857c478bd9Sstevel@tonic-gate 
5867c478bd9Sstevel@tonic-gate 	if (pp != NULL) {
5877c478bd9Sstevel@tonic-gate 		for (i = 0; i < NUM_OF_PICS; i++) {
5887c478bd9Sstevel@tonic-gate 			if (pp->pic_name_ksp[i] != NULL)
5897c478bd9Sstevel@tonic-gate 				kstat_delete(pp->pic_name_ksp[i]);
5907c478bd9Sstevel@tonic-gate 		}
5917c478bd9Sstevel@tonic-gate 	}
5927c478bd9Sstevel@tonic-gate }
5937c478bd9Sstevel@tonic-gate 
5947c478bd9Sstevel@tonic-gate /*
5957c478bd9Sstevel@tonic-gate  * Create the picN kstat. Returns a pointer to the
5967c478bd9Sstevel@tonic-gate  * kstat which the driver must store to allow it
5977c478bd9Sstevel@tonic-gate  * to be deleted when necessary.
5987c478bd9Sstevel@tonic-gate  */
5997c478bd9Sstevel@tonic-gate static kstat_t *
6007c478bd9Sstevel@tonic-gate ni_create_picN_kstat(char *mod_name, int pic, int pic_sel_shift,
6017c478bd9Sstevel@tonic-gate 	int num_ev, ni_kev_mask_t *ev_array)
6027c478bd9Sstevel@tonic-gate {
6037c478bd9Sstevel@tonic-gate 	struct kstat_named *pic_named_data;
6047c478bd9Sstevel@tonic-gate 	int	inst = 0;
6057c478bd9Sstevel@tonic-gate 	int	event;
6067c478bd9Sstevel@tonic-gate 	char	pic_name[30];
6077c478bd9Sstevel@tonic-gate 	kstat_t	*picN_ksp = NULL;
6087c478bd9Sstevel@tonic-gate 
6097c478bd9Sstevel@tonic-gate 	(void) sprintf(pic_name, "pic%d", pic);
6107c478bd9Sstevel@tonic-gate 	if ((picN_ksp = kstat_create(mod_name, inst, pic_name,
6117c478bd9Sstevel@tonic-gate 	    "bus", KSTAT_TYPE_NAMED, num_ev, NULL)) == NULL) {
6127c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "%s %s : kstat create failed",
6137c478bd9Sstevel@tonic-gate 		    mod_name, pic_name);
6147c478bd9Sstevel@tonic-gate 
6157c478bd9Sstevel@tonic-gate 		/*
6167c478bd9Sstevel@tonic-gate 		 * It is up to the calling function to delete any kstats
6177c478bd9Sstevel@tonic-gate 		 * that may have been created already. We just
6187c478bd9Sstevel@tonic-gate 		 * return NULL to indicate an error has occured.
6197c478bd9Sstevel@tonic-gate 		 */
6207c478bd9Sstevel@tonic-gate 		return (NULL);
6217c478bd9Sstevel@tonic-gate 	}
6227c478bd9Sstevel@tonic-gate 
6237c478bd9Sstevel@tonic-gate 	pic_named_data = (struct kstat_named *)
6247c478bd9Sstevel@tonic-gate 	    picN_ksp->ks_data;
6257c478bd9Sstevel@tonic-gate 
6267c478bd9Sstevel@tonic-gate 	/*
6277c478bd9Sstevel@tonic-gate 	 * Write event names and their associated pcr masks. The
6287c478bd9Sstevel@tonic-gate 	 * last entry in the array (clear_pic) is added seperately
6297c478bd9Sstevel@tonic-gate 	 * below as the pic value must be inverted.
6307c478bd9Sstevel@tonic-gate 	 */
6317c478bd9Sstevel@tonic-gate 	for (event = 0; event < num_ev - 1; event++) {
6327c478bd9Sstevel@tonic-gate 		pic_named_data[event].value.ui64 =
6337c478bd9Sstevel@tonic-gate 		    (ev_array[event].pcr_mask << pic_sel_shift);
6347c478bd9Sstevel@tonic-gate 
6357c478bd9Sstevel@tonic-gate 		kstat_named_init(&pic_named_data[event],
6367c478bd9Sstevel@tonic-gate 		    ev_array[event].event_name,
6377c478bd9Sstevel@tonic-gate 		    KSTAT_DATA_UINT64);
6387c478bd9Sstevel@tonic-gate 	}
6397c478bd9Sstevel@tonic-gate 
6407c478bd9Sstevel@tonic-gate 	/*
6417c478bd9Sstevel@tonic-gate 	 * add the clear_pic entry.
6427c478bd9Sstevel@tonic-gate 	 */
6437c478bd9Sstevel@tonic-gate 	pic_named_data[event].value.ui64 =
6447c478bd9Sstevel@tonic-gate 	    (uint64_t)~(ev_array[event].pcr_mask << pic_sel_shift);
6457c478bd9Sstevel@tonic-gate 
6467c478bd9Sstevel@tonic-gate 	kstat_named_init(&pic_named_data[event], ev_array[event].event_name,
6477c478bd9Sstevel@tonic-gate 	    KSTAT_DATA_UINT64);
6487c478bd9Sstevel@tonic-gate 
6497c478bd9Sstevel@tonic-gate 	kstat_install(picN_ksp);
6507c478bd9Sstevel@tonic-gate 
6517c478bd9Sstevel@tonic-gate 	return (picN_ksp);
6527c478bd9Sstevel@tonic-gate }
6537c478bd9Sstevel@tonic-gate 
6547c478bd9Sstevel@tonic-gate /*
6557c478bd9Sstevel@tonic-gate  * Create the "counters" kstat.
6567c478bd9Sstevel@tonic-gate  */
6577c478bd9Sstevel@tonic-gate static kstat_t *
6587c478bd9Sstevel@tonic-gate ni_create_cntr_kstat(char *name, int instance, int (*update)(kstat_t *, int),
6597c478bd9Sstevel@tonic-gate 	void *ksinfop)
6607c478bd9Sstevel@tonic-gate {
6617c478bd9Sstevel@tonic-gate 	struct kstat	*counters_ksp;
6627c478bd9Sstevel@tonic-gate 	struct kstat_named	*counters_named_data;
6637c478bd9Sstevel@tonic-gate 	char		pic_str[10];
6647c478bd9Sstevel@tonic-gate 	int		i;
6657c478bd9Sstevel@tonic-gate 	int		num_pics = NUM_OF_PICS;
6667c478bd9Sstevel@tonic-gate 
6677c478bd9Sstevel@tonic-gate #ifdef DEBUG
6687c478bd9Sstevel@tonic-gate 	if (ni_perf_debug > 1)
6697c478bd9Sstevel@tonic-gate 		printf("ni_create_cntr_kstat: name: %s instance: %d\n",
6707c478bd9Sstevel@tonic-gate 		    name, instance);
6717c478bd9Sstevel@tonic-gate #endif
6727c478bd9Sstevel@tonic-gate 
6737c478bd9Sstevel@tonic-gate 	/*
6747c478bd9Sstevel@tonic-gate 	 * Size of kstat is num_pics + 1 as it
6757c478bd9Sstevel@tonic-gate 	 * also contains the %pcr
6767c478bd9Sstevel@tonic-gate 	 */
6777c478bd9Sstevel@tonic-gate 	if ((counters_ksp = kstat_create(name, instance, "counters", "bus",
6787c478bd9Sstevel@tonic-gate 	    KSTAT_TYPE_NAMED, num_pics + 1, KSTAT_FLAG_WRITABLE)) == NULL) {
6797c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN,
680c56c1e58Sgirish 		    "%s: kstat_create for %s%d failed", cpu_module_name,
6817c478bd9Sstevel@tonic-gate 		    name, instance);
6827c478bd9Sstevel@tonic-gate 		return (NULL);
6837c478bd9Sstevel@tonic-gate 	}
6847c478bd9Sstevel@tonic-gate 
6857c478bd9Sstevel@tonic-gate 	counters_named_data = (struct kstat_named *)(counters_ksp->ks_data);
6867c478bd9Sstevel@tonic-gate 
6877c478bd9Sstevel@tonic-gate 	/*
6887c478bd9Sstevel@tonic-gate 	 * Iinitialize the named kstats
6897c478bd9Sstevel@tonic-gate 	 */
6907c478bd9Sstevel@tonic-gate 	kstat_named_init(&counters_named_data[0], "pcr", KSTAT_DATA_UINT64);
6917c478bd9Sstevel@tonic-gate 
6927c478bd9Sstevel@tonic-gate 	for (i = 0; i < num_pics; i++) {
6937c478bd9Sstevel@tonic-gate 		(void) sprintf(pic_str, "pic%d", i);
6947c478bd9Sstevel@tonic-gate 
6957c478bd9Sstevel@tonic-gate 		kstat_named_init(&counters_named_data[i+1], pic_str,
6967c478bd9Sstevel@tonic-gate 		    KSTAT_DATA_UINT64);
6977c478bd9Sstevel@tonic-gate 	}
6987c478bd9Sstevel@tonic-gate 
6997c478bd9Sstevel@tonic-gate 	/*
7007c478bd9Sstevel@tonic-gate 	 * Store the register offset's in the kstat's
7017c478bd9Sstevel@tonic-gate 	 * private field so that they are available
7027c478bd9Sstevel@tonic-gate 	 * to the update function.
7037c478bd9Sstevel@tonic-gate 	 */
7047c478bd9Sstevel@tonic-gate 	counters_ksp->ks_private = (void *)ksinfop;
7057c478bd9Sstevel@tonic-gate 	counters_ksp->ks_update = update;
7067c478bd9Sstevel@tonic-gate 
7077c478bd9Sstevel@tonic-gate 	kstat_install(counters_ksp);
7087c478bd9Sstevel@tonic-gate 
7097c478bd9Sstevel@tonic-gate 	return (counters_ksp);
7107c478bd9Sstevel@tonic-gate }
7117c478bd9Sstevel@tonic-gate 
71264cfc8edSsvemuri #if defined(VFALLS_IMPL)
71364cfc8edSsvemuri /*
71464cfc8edSsvemuri  * zambezi kstat update function. Handles reads/writes
71564cfc8edSsvemuri  * from/to kstat.
71664cfc8edSsvemuri  */
71764cfc8edSsvemuri static int
71864cfc8edSsvemuri zam_cntr_kstat_update(kstat_t *ksp, int rw)
71964cfc8edSsvemuri {
72064cfc8edSsvemuri 	struct kstat_named	*data_p;
72164cfc8edSsvemuri 	ni_ksinfo_t	*ksinfop = ksp->ks_private;
72264cfc8edSsvemuri 	uint64_t	pic0, pic1, pcr;
72364cfc8edSsvemuri 	int		stat = 0;
72464cfc8edSsvemuri 	uint64_t	pic0_stat = 0, pic1_stat = 0, pcr_stat = 0;
72564cfc8edSsvemuri 
72664cfc8edSsvemuri 	data_p = (struct kstat_named *)ksp->ks_data;
72764cfc8edSsvemuri 
72864cfc8edSsvemuri 	if (rw == KSTAT_WRITE) {
72964cfc8edSsvemuri #ifdef DEBUG
73064cfc8edSsvemuri 		if (ni_perf_debug)
73164cfc8edSsvemuri 			printf("zam_cntr_kstat_update: wr pcr-%d: %lx\n",
73264cfc8edSsvemuri 			    ksinfop->pcr_reg, data_p[0].value.ui64);
73364cfc8edSsvemuri #endif
73464cfc8edSsvemuri 		if (hv_niagara_setperf(ksinfop->pcr_reg, data_p[0].value.ui64))
73564cfc8edSsvemuri 			stat = EACCES;
73664cfc8edSsvemuri 	} else {
73764cfc8edSsvemuri 		do {
73864cfc8edSsvemuri 			pic0_stat = hv_niagara_getperf(ksinfop->pic_reg[0],
73964cfc8edSsvemuri 			    &pic0);
74064cfc8edSsvemuri 		} while (pic0_stat == H_EWOULDBLOCK);
74164cfc8edSsvemuri 		do {
74264cfc8edSsvemuri 			pic1_stat = hv_niagara_getperf(ksinfop->pic_reg[1],
74364cfc8edSsvemuri 			    &pic1);
74464cfc8edSsvemuri 		} while (pic1_stat == H_EWOULDBLOCK);
74564cfc8edSsvemuri 		do {
74664cfc8edSsvemuri 			pcr_stat = hv_niagara_getperf(ksinfop->pcr_reg,
74764cfc8edSsvemuri 			    &pcr);
74864cfc8edSsvemuri 		} while (pcr_stat == H_EWOULDBLOCK);
74964cfc8edSsvemuri 		if (pic0_stat != 0 || pic1_stat != 0 || pcr_stat != 0)
75064cfc8edSsvemuri 			stat = EACCES;
75164cfc8edSsvemuri 		else {
75264cfc8edSsvemuri 			data_p[0].value.ui64 = pcr;
75364cfc8edSsvemuri 			data_p[1].value.ui64 = pic0;
75464cfc8edSsvemuri 			data_p[2].value.ui64 = pic1;
75564cfc8edSsvemuri 		}
75664cfc8edSsvemuri #ifdef DEBUG
75764cfc8edSsvemuri 		if (ni_perf_debug)
75864cfc8edSsvemuri 			printf("zam_cntr_kstat_update: rd pcr%d: %lx  "
75964cfc8edSsvemuri 			    "pic0: %16lx pic1: %16lx\n",
76064cfc8edSsvemuri 			    ksinfop->pcr_reg, pcr,
76164cfc8edSsvemuri 			    data_p[1].value.ui64, data_p[2].value.ui64);
76264cfc8edSsvemuri #endif
76364cfc8edSsvemuri 	}
76464cfc8edSsvemuri 
76564cfc8edSsvemuri 	return (stat);
76664cfc8edSsvemuri }
76764cfc8edSsvemuri #endif
76864cfc8edSsvemuri 
7697c478bd9Sstevel@tonic-gate /*
7707c478bd9Sstevel@tonic-gate  * kstat update function. Handles reads/writes
7717c478bd9Sstevel@tonic-gate  * from/to kstat.
7727c478bd9Sstevel@tonic-gate  */
7737c478bd9Sstevel@tonic-gate static int
7747c478bd9Sstevel@tonic-gate ni_cntr_kstat_update(kstat_t *ksp, int rw)
7757c478bd9Sstevel@tonic-gate {
7767c478bd9Sstevel@tonic-gate 	struct kstat_named	*data_p;
7777c478bd9Sstevel@tonic-gate 	ni_ksinfo_t	*ksinfop = ksp->ks_private;
7787c478bd9Sstevel@tonic-gate 	uint64_t	pic, pcr;
7797c478bd9Sstevel@tonic-gate 	int		stat = 0;
7807c478bd9Sstevel@tonic-gate 	uint32_t	pic0, pic1;
7817c478bd9Sstevel@tonic-gate 
7827c478bd9Sstevel@tonic-gate 	data_p = (struct kstat_named *)ksp->ks_data;
7837c478bd9Sstevel@tonic-gate 
7847c478bd9Sstevel@tonic-gate 	if (rw == KSTAT_WRITE) {
7857c478bd9Sstevel@tonic-gate #ifdef DEBUG
7867c478bd9Sstevel@tonic-gate 		if (ni_perf_debug)
7870bd5614cSiskreen 			printf("ni_cntr_kstat_update: wr pcr-%d: %lx\n",
7887c478bd9Sstevel@tonic-gate 			    ksinfop->pcr_reg, data_p[0].value.ui64);
7897c478bd9Sstevel@tonic-gate #endif
7907c478bd9Sstevel@tonic-gate 		if (hv_niagara_setperf(ksinfop->pcr_reg, data_p[0].value.ui64))
7917c478bd9Sstevel@tonic-gate 			stat = EACCES;
7927c478bd9Sstevel@tonic-gate 	} else {
79364cfc8edSsvemuri 		if (hv_niagara_getperf(ksinfop->pic_reg[0], &pic) != 0 ||
7947c478bd9Sstevel@tonic-gate 		    hv_niagara_getperf(ksinfop->pcr_reg, &pcr) != 0)
7957c478bd9Sstevel@tonic-gate 			stat = EACCES;
7967c478bd9Sstevel@tonic-gate 		else {
7977c478bd9Sstevel@tonic-gate 			data_p[0].value.ui64 = pcr;
7987c478bd9Sstevel@tonic-gate 
7997c478bd9Sstevel@tonic-gate 			/*
8007c478bd9Sstevel@tonic-gate 			 * Generate a 32-bit PIC0 value by detecting overflow
8017c478bd9Sstevel@tonic-gate 			 */
8027c478bd9Sstevel@tonic-gate 			pic0 = (uint32_t)((pic >> ksinfop->pic_shift[0]) &
8037c478bd9Sstevel@tonic-gate 			    ksinfop->pic_mask[0]);
8047c478bd9Sstevel@tonic-gate 			if (pic0 < ksinfop->pic_last_val[0])
8057c478bd9Sstevel@tonic-gate 				ksinfop->pic_overflow[0]++;
8067c478bd9Sstevel@tonic-gate 			ksinfop->pic_last_val[0] = pic0;
8077c478bd9Sstevel@tonic-gate 			pic0 += (ksinfop->pic_overflow[0] & 1) << 31;
8087c478bd9Sstevel@tonic-gate 			data_p[1].value.ui64 = (uint64_t)pic0;
8097c478bd9Sstevel@tonic-gate 
8107c478bd9Sstevel@tonic-gate 			/*
8117c478bd9Sstevel@tonic-gate 			 * Generate a 32-bit PIC1 value by detecting overflow
8127c478bd9Sstevel@tonic-gate 			 */
8137c478bd9Sstevel@tonic-gate 			pic1 = (uint32_t)((pic >> ksinfop->pic_shift[1]) &
8147c478bd9Sstevel@tonic-gate 			    ksinfop->pic_mask[1]);
8157c478bd9Sstevel@tonic-gate 			if (pic1 < ksinfop->pic_last_val[1])
8167c478bd9Sstevel@tonic-gate 				ksinfop->pic_overflow[1]++;
8177c478bd9Sstevel@tonic-gate 			ksinfop->pic_last_val[1] = pic1;
8187c478bd9Sstevel@tonic-gate 			pic1 += (ksinfop->pic_overflow[1] & 1) << 31;
8197c478bd9Sstevel@tonic-gate 			data_p[2].value.ui64 = (uint64_t)pic1;
8207c478bd9Sstevel@tonic-gate 		}
8217c478bd9Sstevel@tonic-gate #ifdef DEBUG
8227c478bd9Sstevel@tonic-gate 		if (ni_perf_debug)
8237c478bd9Sstevel@tonic-gate 			printf("ni_cntr_kstat_update: rd pcr%d: %lx  "
8247c478bd9Sstevel@tonic-gate 			    "pic%d: %16lx pic0: %8lx pic1: %8lx\n",
82564cfc8edSsvemuri 			    ksinfop->pcr_reg, pcr, ksinfop->pic_reg[0], pic,
8267c478bd9Sstevel@tonic-gate 			    data_p[1].value.ui64, data_p[2].value.ui64);
8277c478bd9Sstevel@tonic-gate #endif
8287c478bd9Sstevel@tonic-gate 	}
8297c478bd9Sstevel@tonic-gate 	return (stat);
8307c478bd9Sstevel@tonic-gate }
831