xref: /onnv-gate/usr/src/uts/sun4v/cpu/niagara_perfctr.c (revision 5146:27fbcf92f645)
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
51592Sgirish  * Common Development and Distribution License (the "License").
61592Sgirish  * 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  */
210Sstevel@tonic-gate /*
224732Sdavemq  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
270Sstevel@tonic-gate 
280Sstevel@tonic-gate #include <sys/types.h>
290Sstevel@tonic-gate #include <sys/async.h>
300Sstevel@tonic-gate #include <sys/sunddi.h>
310Sstevel@tonic-gate #include <sys/sunndi.h>
320Sstevel@tonic-gate #include <sys/ddi_impldefs.h>
330Sstevel@tonic-gate #include <sys/machsystm.h>
340Sstevel@tonic-gate #include <sys/hypervisor_api.h>
350Sstevel@tonic-gate #include <sys/kstat.h>
363156Sgirish #if defined(NIAGARA_IMPL)
373156Sgirish #include <sys/niagararegs.h>
384732Sdavemq #elif defined(NIAGARA2_IMPL) || defined(VFALLS_IMPL)
393156Sgirish #include <sys/niagara2regs.h>
403156Sgirish #endif
410Sstevel@tonic-gate 
421592Sgirish extern char cpu_module_name[];
430Sstevel@tonic-gate 
440Sstevel@tonic-gate /*
450Sstevel@tonic-gate  * Data structure used to build array of event-names and pcr-mask values
460Sstevel@tonic-gate  */
470Sstevel@tonic-gate typedef struct ni_kev_mask {
480Sstevel@tonic-gate 	char		*event_name;
490Sstevel@tonic-gate 	uint64_t	pcr_mask;
500Sstevel@tonic-gate } ni_kev_mask_t;
510Sstevel@tonic-gate 
520Sstevel@tonic-gate /*
530Sstevel@tonic-gate  * Kstat data structure for DRAM and JBUS performance counters
540Sstevel@tonic-gate  *
550Sstevel@tonic-gate  * Note that these performance counters are only 31 bits wide. Since
560Sstevel@tonic-gate  * the "busstat" command assumes a 32-bit counter, we emulate a 32-bit
570Sstevel@tonic-gate  * counter by detecting overflow on read of these performance counters
580Sstevel@tonic-gate  * and using the least significant bit of the overflow count as the
590Sstevel@tonic-gate  * most significant bit (i.e. bit# 31) of the DRAM and JBUS performance
600Sstevel@tonic-gate  * counters.
610Sstevel@tonic-gate  */
621592Sgirish #define	NUM_OF_PICS	2
631592Sgirish 
640Sstevel@tonic-gate typedef struct ni_ksinfo {
650Sstevel@tonic-gate 	uint8_t		pic_no_evs;			/* number of events */
660Sstevel@tonic-gate 	uint8_t		pic_sel_shift[NUM_OF_PICS];
670Sstevel@tonic-gate 	uint8_t		pic_shift[NUM_OF_PICS];
680Sstevel@tonic-gate 	uint64_t	pic_mask[NUM_OF_PICS];
690Sstevel@tonic-gate 	kstat_t		*pic_name_ksp[NUM_OF_PICS];
700Sstevel@tonic-gate 	kstat_t		*cntr_ksp;
71*5146Ssvemuri 	uint32_t	pic_reg[NUM_OF_PICS];
720Sstevel@tonic-gate 	uint32_t	pcr_reg;
730Sstevel@tonic-gate 	uint32_t	pic_overflow[NUM_OF_PICS];	/* overflow count */
740Sstevel@tonic-gate 	uint32_t	pic_last_val[NUM_OF_PICS];	/* last PIC value */
750Sstevel@tonic-gate } ni_ksinfo_t;
760Sstevel@tonic-gate 
770Sstevel@tonic-gate static ni_ksinfo_t	*ni_dram_kstats[NIAGARA_DRAM_BANKS];
783156Sgirish 
793156Sgirish #if defined(NIAGARA_IMPL)
800Sstevel@tonic-gate static ni_ksinfo_t	*ni_jbus_kstat;
813156Sgirish #endif
820Sstevel@tonic-gate 
830Sstevel@tonic-gate typedef struct ni_perf_regs {
840Sstevel@tonic-gate 	uint32_t	pcr_reg;
850Sstevel@tonic-gate 	uint32_t	pic_reg;
860Sstevel@tonic-gate } ni_perf_regs_t;
870Sstevel@tonic-gate 
880Sstevel@tonic-gate static ni_perf_regs_t dram_perf_regs[] = {
890Sstevel@tonic-gate 	{HV_NIAGARA_DRAM_CTL0, HV_NIAGARA_DRAM_COUNT0},
900Sstevel@tonic-gate 	{HV_NIAGARA_DRAM_CTL1, HV_NIAGARA_DRAM_COUNT1},
910Sstevel@tonic-gate 	{HV_NIAGARA_DRAM_CTL2, HV_NIAGARA_DRAM_COUNT2},
920Sstevel@tonic-gate 	{HV_NIAGARA_DRAM_CTL3, HV_NIAGARA_DRAM_COUNT3},
93*5146Ssvemuri #ifdef VFALLS_IMPL
94*5146Ssvemuri 	{HV_NIAGARA_DRAM_CTL4, HV_NIAGARA_DRAM_COUNT4},
95*5146Ssvemuri 	{HV_NIAGARA_DRAM_CTL5, HV_NIAGARA_DRAM_COUNT5},
96*5146Ssvemuri 	{HV_NIAGARA_DRAM_CTL6, HV_NIAGARA_DRAM_COUNT6},
97*5146Ssvemuri 	{HV_NIAGARA_DRAM_CTL7, HV_NIAGARA_DRAM_COUNT7}
98*5146Ssvemuri #endif
990Sstevel@tonic-gate };
1000Sstevel@tonic-gate 
101*5146Ssvemuri #ifdef VFALLS_IMPL
102*5146Ssvemuri /*
103*5146Ssvemuri  * Kstat data structure for Zambezi performance counters
104*5146Ssvemuri  * These performance counters are 64 bits wide.
105*5146Ssvemuri  */
106*5146Ssvemuri static ni_ksinfo_t	*zam_lpu_kstats[ZAMBEZI_LPU_COUNTERS];
107*5146Ssvemuri static ni_ksinfo_t	*zam_gpd_kstats[ZAMBEZI_GPD_COUNTERS];
108*5146Ssvemuri static ni_ksinfo_t	*zam_asu_kstats[ZAMBEZI_ASU_COUNTERS];
109*5146Ssvemuri 
110*5146Ssvemuri typedef struct zam_perf_regs {
111*5146Ssvemuri 	uint32_t	pcr_reg;
112*5146Ssvemuri 	uint32_t	pic_reg[NUM_OF_PICS];
113*5146Ssvemuri } zam_perf_regs_t;
114*5146Ssvemuri 
115*5146Ssvemuri static zam_perf_regs_t lpu_perf_regs[] = {
116*5146Ssvemuri 	{HV_ZAM0_LPU_A_PCR, HV_ZAM0_LPU_A_PIC0, HV_ZAM0_LPU_A_PIC1},
117*5146Ssvemuri 	{HV_ZAM0_LPU_B_PCR, HV_ZAM0_LPU_B_PIC0, HV_ZAM0_LPU_B_PIC1},
118*5146Ssvemuri 	{HV_ZAM0_LPU_C_PCR, HV_ZAM0_LPU_C_PIC0, HV_ZAM0_LPU_C_PIC1},
119*5146Ssvemuri 	{HV_ZAM0_LPU_D_PCR, HV_ZAM0_LPU_D_PIC0, HV_ZAM0_LPU_D_PIC1},
120*5146Ssvemuri 
121*5146Ssvemuri 	{HV_ZAM1_LPU_A_PCR, HV_ZAM1_LPU_A_PIC0, HV_ZAM1_LPU_A_PIC1},
122*5146Ssvemuri 	{HV_ZAM1_LPU_B_PCR, HV_ZAM1_LPU_B_PIC0, HV_ZAM1_LPU_B_PIC1},
123*5146Ssvemuri 	{HV_ZAM1_LPU_C_PCR, HV_ZAM1_LPU_C_PIC0, HV_ZAM1_LPU_C_PIC1},
124*5146Ssvemuri 	{HV_ZAM1_LPU_D_PCR, HV_ZAM1_LPU_D_PIC0, HV_ZAM1_LPU_D_PIC1},
125*5146Ssvemuri 
126*5146Ssvemuri 	{HV_ZAM2_LPU_A_PCR, HV_ZAM2_LPU_A_PIC0, HV_ZAM2_LPU_A_PIC1},
127*5146Ssvemuri 	{HV_ZAM2_LPU_B_PCR, HV_ZAM2_LPU_B_PIC0, HV_ZAM2_LPU_B_PIC1},
128*5146Ssvemuri 	{HV_ZAM2_LPU_C_PCR, HV_ZAM2_LPU_C_PIC0, HV_ZAM2_LPU_C_PIC1},
129*5146Ssvemuri 	{HV_ZAM2_LPU_D_PCR, HV_ZAM2_LPU_D_PIC0, HV_ZAM2_LPU_D_PIC1},
130*5146Ssvemuri 
131*5146Ssvemuri 	{HV_ZAM3_LPU_A_PCR, HV_ZAM3_LPU_A_PIC0, HV_ZAM3_LPU_A_PIC1},
132*5146Ssvemuri 	{HV_ZAM3_LPU_B_PCR, HV_ZAM3_LPU_B_PIC0, HV_ZAM3_LPU_B_PIC1},
133*5146Ssvemuri 	{HV_ZAM3_LPU_C_PCR, HV_ZAM3_LPU_C_PIC0, HV_ZAM3_LPU_C_PIC1},
134*5146Ssvemuri 	{HV_ZAM3_LPU_D_PCR, HV_ZAM3_LPU_D_PIC0, HV_ZAM3_LPU_D_PIC1}
135*5146Ssvemuri };
136*5146Ssvemuri 
137*5146Ssvemuri static zam_perf_regs_t gpd_perf_regs[] = {
138*5146Ssvemuri 	{HV_ZAM0_GPD_PCR, HV_ZAM0_GPD_PIC0, HV_ZAM0_GPD_PIC1},
139*5146Ssvemuri 	{HV_ZAM1_GPD_PCR, HV_ZAM1_GPD_PIC0, HV_ZAM1_GPD_PIC1},
140*5146Ssvemuri 	{HV_ZAM2_GPD_PCR, HV_ZAM2_GPD_PIC0, HV_ZAM2_GPD_PIC1},
141*5146Ssvemuri 	{HV_ZAM3_GPD_PCR, HV_ZAM3_GPD_PIC0, HV_ZAM3_GPD_PIC1}
142*5146Ssvemuri };
143*5146Ssvemuri 
144*5146Ssvemuri static zam_perf_regs_t asu_perf_regs[] = {
145*5146Ssvemuri 	{HV_ZAM0_ASU_PCR, HV_ZAM0_ASU_PIC0, HV_ZAM0_ASU_PIC1},
146*5146Ssvemuri 	{HV_ZAM1_ASU_PCR, HV_ZAM1_ASU_PIC0, HV_ZAM1_ASU_PIC1},
147*5146Ssvemuri 	{HV_ZAM2_ASU_PCR, HV_ZAM2_ASU_PIC0, HV_ZAM2_ASU_PIC1},
148*5146Ssvemuri 	{HV_ZAM3_ASU_PCR, HV_ZAM3_ASU_PIC0, HV_ZAM3_ASU_PIC1}
149*5146Ssvemuri };
150*5146Ssvemuri 
151*5146Ssvemuri static int zam_cntr_kstat_update(kstat_t *, int);
152*5146Ssvemuri #endif
153*5146Ssvemuri 
1540Sstevel@tonic-gate static void ni_create_name_kstat(char *, ni_ksinfo_t *, ni_kev_mask_t *);
1550Sstevel@tonic-gate static void ni_delete_name_kstat(ni_ksinfo_t *);
1560Sstevel@tonic-gate 
1570Sstevel@tonic-gate static kstat_t *ni_create_cntr_kstat(char *, int,
1580Sstevel@tonic-gate 	int (*update)(kstat_t *, int), void *);
1590Sstevel@tonic-gate 
1600Sstevel@tonic-gate static int ni_cntr_kstat_update(kstat_t *, int);
1610Sstevel@tonic-gate 
1620Sstevel@tonic-gate static kstat_t *ni_create_picN_kstat(char *, int, int, int,
1630Sstevel@tonic-gate 	ni_kev_mask_t *);
1640Sstevel@tonic-gate 
1650Sstevel@tonic-gate #ifdef DEBUG
1660Sstevel@tonic-gate static int	ni_perf_debug;
1670Sstevel@tonic-gate #endif
1680Sstevel@tonic-gate 
1690Sstevel@tonic-gate /*
1704732Sdavemq  * Niagara, Niagara2 and VFalls DRAM Performance Events
1710Sstevel@tonic-gate  */
1720Sstevel@tonic-gate static ni_kev_mask_t
1730Sstevel@tonic-gate niagara_dram_events[] = {
1740Sstevel@tonic-gate 	{"mem_reads",		0x0},
1750Sstevel@tonic-gate 	{"mem_writes",		0x1},
1760Sstevel@tonic-gate 	{"mem_read_write",	0x2},
1770Sstevel@tonic-gate 	{"bank_busy_stalls",	0x3},
1780Sstevel@tonic-gate 	{"rd_queue_latency",	0x4},
1790Sstevel@tonic-gate 	{"wr_queue_latency",	0x5},
1800Sstevel@tonic-gate 	{"rw_queue_latency",	0x6},
1810Sstevel@tonic-gate 	{"wb_buf_hits",		0x7},
182*5146Ssvemuri 	{"clear_pic",		0xf}
1830Sstevel@tonic-gate };
1840Sstevel@tonic-gate 
185*5146Ssvemuri #if defined(VFALLS_IMPL)
186*5146Ssvemuri /*
187*5146Ssvemuri  * Zambezi Performance Events
188*5146Ssvemuri  */
189*5146Ssvemuri static ni_kev_mask_t
190*5146Ssvemuri zam_lpu_perf_events[] = {
191*5146Ssvemuri 	{"none",		0x0},
192*5146Ssvemuri 	{"clock_cycles",	0x1},
193*5146Ssvemuri 	{"cycles_c2c_portX",	0x2},
194*5146Ssvemuri 	{"cycles_mem_portX",	0x3},
195*5146Ssvemuri 	{"cycles_WB_portX",	0x4},
196*5146Ssvemuri 	{"cycles_NC_portX",	0x5},
197*5146Ssvemuri 	{"cycles_c2c_portY",	0x6},
198*5146Ssvemuri 	{"cycles_mem_portY",	0x7},
199*5146Ssvemuri 	{"cycles_WB_portY",	0x8},
200*5146Ssvemuri 	{"cycles_NC_portY",	0x9},
201*5146Ssvemuri 	{"cycles_c2c_portZ",	0xa},
202*5146Ssvemuri 	{"cycles_mem_portZ",	0xb},
203*5146Ssvemuri 	{"cycles_WB_portZ",	0xc},
204*5146Ssvemuri 	{"cycles_NC_portZ",	0xd},
205*5146Ssvemuri 	{"cycles_TID_WB",	0xe},
206*5146Ssvemuri 	{"cycles_TID_INV",	0xf},
207*5146Ssvemuri 	{"cycles_TID_RTD",	0x10},
208*5146Ssvemuri 	{"cycles_TID_RTO",	0x11},
209*5146Ssvemuri 	{"cycles_TID_RTS",	0x12},
210*5146Ssvemuri 	{"cycles_IO_WRM",	0x13},
211*5146Ssvemuri 	{"cycles_IO_RD",	0x14},
212*5146Ssvemuri 	{"cycles_WB_egress",	0x15},
213*5146Ssvemuri 	{"cycles_INV_egress",	0x16},
214*5146Ssvemuri 	{"cycles_RTO_egress",	0x17},
215*5146Ssvemuri 	{"cycles_RTD_egress",	0x18},
216*5146Ssvemuri 	{"cycles_RTS_egress",	0x19},
217*5146Ssvemuri 	{"cycles_no_WB",	0x1a},
218*5146Ssvemuri 	{"cycles_no_read/inv",	0x1b},
219*5146Ssvemuri 	{"cycles_HIT_M",	0x1c},
220*5146Ssvemuri 	{"cycles_HIT_O",	0x1d},
221*5146Ssvemuri 	{"cycles_HIT_S",	0x1e},
222*5146Ssvemuri 	{"cycles_WB_HIT",	0x1f},
223*5146Ssvemuri 	{"cycles_MISS",		0x20},
224*5146Ssvemuri 	{"cycles_READ_or_INV",	0x21},
225*5146Ssvemuri 	{"cycles_WB",		0x22},
226*5146Ssvemuri 	{"cycles_NDR",		0x23},
227*5146Ssvemuri 	{"cycles_cache_miss",	0x24},
228*5146Ssvemuri 	{"cycles_cache_hit",	0x25},
229*5146Ssvemuri 	{"cycles_CRC_errors",	0x26},
230*5146Ssvemuri 	{"cycles_replys_sent",	0x27},
231*5146Ssvemuri 	{"cycles_replys_recev",	0x28},
232*5146Ssvemuri 	{"cycles_link_retrain",	0x29},
233*5146Ssvemuri 	{"clear_pic",		0xff}
234*5146Ssvemuri };
235*5146Ssvemuri 
236*5146Ssvemuri static ni_kev_mask_t
237*5146Ssvemuri zam_gpd_perf_events[] = {
238*5146Ssvemuri 	{"none",		0x0},
239*5146Ssvemuri 	{"clock_cycles",	0x1},
240*5146Ssvemuri 	{"clear_pic",		0xf}
241*5146Ssvemuri };
242*5146Ssvemuri 
243*5146Ssvemuri static ni_kev_mask_t
244*5146Ssvemuri zam_asu_perf_events[] = {
245*5146Ssvemuri 	{"none",		0x0},
246*5146Ssvemuri 	{"clock_cycles",	0x1},
247*5146Ssvemuri 	{"asu_in_pck",		0x2},
248*5146Ssvemuri 	{"asu_out_pck",		0x3},
249*5146Ssvemuri 	{"asu_CAM_hit",		0x4},
250*5146Ssvemuri 	{"asu_wakeup",		0x5},
251*5146Ssvemuri 	{"clear_pic",		0xf}
252*5146Ssvemuri };
253*5146Ssvemuri #endif
2540Sstevel@tonic-gate 
2553156Sgirish #if defined(NIAGARA_IMPL)
2560Sstevel@tonic-gate /*
2570Sstevel@tonic-gate  * Niagara JBUS Performance Events
2580Sstevel@tonic-gate  */
2590Sstevel@tonic-gate static ni_kev_mask_t
2600Sstevel@tonic-gate niagara_jbus_events[] = {
2610Sstevel@tonic-gate 	{"jbus_cycles",		0x1},
2620Sstevel@tonic-gate 	{"dma_reads",		0x2},
2630Sstevel@tonic-gate 	{"dma_read_latency",	0x3},
2640Sstevel@tonic-gate 	{"dma_writes",		0x4},
2650Sstevel@tonic-gate 	{"dma_write8",		0x5},
2660Sstevel@tonic-gate 	{"ordering_waits",	0x6},
2670Sstevel@tonic-gate 	{"pio_reads",		0x8},
2680Sstevel@tonic-gate 	{"pio_read_latency",	0x9},
2690Sstevel@tonic-gate 	{"aok_dok_off_cycles",	0xc},
2700Sstevel@tonic-gate 	{"aok_off_cycles",	0xd},
2710Sstevel@tonic-gate 	{"dok_off_cycles",	0xe},
2720Sstevel@tonic-gate 	{"clear_pic",		0xf}
2730Sstevel@tonic-gate };
2743156Sgirish #endif
2750Sstevel@tonic-gate 
2760Sstevel@tonic-gate /*
277*5146Ssvemuri  * Create the picN kstats for DRAM, JBUS and Zambezi events
2780Sstevel@tonic-gate  */
2790Sstevel@tonic-gate void
2800Sstevel@tonic-gate niagara_kstat_init()
2810Sstevel@tonic-gate {
2820Sstevel@tonic-gate 	int i;
2830Sstevel@tonic-gate 	ni_ksinfo_t *ksinfop;
284*5146Ssvemuri 	uint64_t pcr;
285*5146Ssvemuri 	uint64_t stat;
2860Sstevel@tonic-gate 
2870Sstevel@tonic-gate #ifdef DEBUG
2880Sstevel@tonic-gate 	if (ni_perf_debug)
2890Sstevel@tonic-gate 		printf("ni_kstat_init called\n");
2900Sstevel@tonic-gate #endif
2910Sstevel@tonic-gate 
2920Sstevel@tonic-gate 	/*
2930Sstevel@tonic-gate 	 * Create DRAM perf events kstat
2940Sstevel@tonic-gate 	 */
2950Sstevel@tonic-gate 	for (i = 0; i < NIAGARA_DRAM_BANKS; i++) {
2964732Sdavemq #ifdef VFALLS_IMPL
2974732Sdavemq 		/* check if this dram instance is enabled in the HW */
298*5146Ssvemuri 		stat = hv_niagara_getperf(dram_perf_regs[i].pcr_reg, &pcr);
299*5146Ssvemuri 		if ((stat != H_EINVAL) && (stat != H_ENOTSUPPORTED)) {
3004732Sdavemq #endif
3014732Sdavemq 			ksinfop = (ni_ksinfo_t *)kmem_zalloc(
3024732Sdavemq 			    sizeof (ni_ksinfo_t), KM_NOSLEEP);
3030Sstevel@tonic-gate 
3044732Sdavemq 			if (ksinfop == NULL) {
3054732Sdavemq 				cmn_err(CE_WARN,
3064732Sdavemq 				    "%s: no space for dram kstat\n",
3074732Sdavemq 				    cpu_module_name);
3084732Sdavemq 				break;
3094732Sdavemq 			}
3104732Sdavemq 			ksinfop->pic_no_evs =
3114732Sdavemq 			    sizeof (niagara_dram_events) /
3124732Sdavemq 			    sizeof (ni_kev_mask_t);
3134732Sdavemq 			ksinfop->pic_sel_shift[0] = NIAGARA_DRAM_PIC0_SEL_SHIFT;
3144732Sdavemq 			ksinfop->pic_shift[0] = NIAGARA_DRAM_PIC0_SHIFT;
3154732Sdavemq 			ksinfop->pic_mask[0] = NIAGARA_DRAM_PIC0_MASK;
3164732Sdavemq 			ksinfop->pic_sel_shift[1] = NIAGARA_DRAM_PIC1_SEL_SHIFT;
3174732Sdavemq 			ksinfop->pic_shift[1] = NIAGARA_DRAM_PIC1_SHIFT;
3184732Sdavemq 			ksinfop->pic_mask[1] = NIAGARA_DRAM_PIC1_MASK;
319*5146Ssvemuri 			ksinfop->pic_reg[0] = dram_perf_regs[i].pic_reg;
3204732Sdavemq 			ksinfop->pcr_reg = dram_perf_regs[i].pcr_reg;
3214732Sdavemq 			ni_dram_kstats[i] = ksinfop;
3220Sstevel@tonic-gate 
3234732Sdavemq 			/* create basic pic event/mask pair (only once) */
3244732Sdavemq 			if (i == 0)
3254732Sdavemq 				ni_create_name_kstat("dram", ksinfop,
3260Sstevel@tonic-gate 				    niagara_dram_events);
3270Sstevel@tonic-gate 
3284732Sdavemq 			/* create counter kstats */
3294732Sdavemq 			ni_dram_kstats[i]->cntr_ksp = ni_create_cntr_kstat(
3304732Sdavemq 			    "dram", i, ni_cntr_kstat_update, ksinfop);
3314732Sdavemq #ifdef VFALLS_IMPL
3324732Sdavemq 		}
3334732Sdavemq #endif
3340Sstevel@tonic-gate 	}
3350Sstevel@tonic-gate 
336*5146Ssvemuri #ifdef VFALLS_IMPL
337*5146Ssvemuri 	/*
338*5146Ssvemuri 	 * Create Zambezi LPU perf events kstat
339*5146Ssvemuri 	 */
340*5146Ssvemuri 	for (i = 0; i < ZAMBEZI_LPU_COUNTERS; i++) {
341*5146Ssvemuri 		/* check if this Zambezi LPU instance is enabled in the HW */
342*5146Ssvemuri 		stat = hv_niagara_getperf(lpu_perf_regs[i].pcr_reg, &pcr);
343*5146Ssvemuri 		if ((stat != H_EINVAL) && (stat != H_ENOTSUPPORTED)) {
344*5146Ssvemuri 			ksinfop = (ni_ksinfo_t *)kmem_zalloc(
345*5146Ssvemuri 			    sizeof (ni_ksinfo_t), KM_NOSLEEP);
346*5146Ssvemuri 
347*5146Ssvemuri 			if (ksinfop == NULL) {
348*5146Ssvemuri 				cmn_err(CE_WARN,
349*5146Ssvemuri 				    "%s: no space for zambezi lpu kstat\n",
350*5146Ssvemuri 				    cpu_module_name);
351*5146Ssvemuri 				break;
352*5146Ssvemuri 			}
353*5146Ssvemuri 			ksinfop->pic_no_evs =
354*5146Ssvemuri 			    sizeof (zam_lpu_perf_events) /
355*5146Ssvemuri 			    sizeof (ni_kev_mask_t);
356*5146Ssvemuri 			ksinfop->pic_sel_shift[0] = ZAMBEZI_PIC0_SEL_SHIFT;
357*5146Ssvemuri 			ksinfop->pic_reg[0] = lpu_perf_regs[i].pic_reg[0];
358*5146Ssvemuri 			ksinfop->pic_sel_shift[1] = ZAMBEZI_PIC1_SEL_SHIFT;
359*5146Ssvemuri 			ksinfop->pic_reg[1] = lpu_perf_regs[i].pic_reg[1];
360*5146Ssvemuri 			ksinfop->pcr_reg = lpu_perf_regs[i].pcr_reg;
361*5146Ssvemuri 			zam_lpu_kstats[i] = ksinfop;
362*5146Ssvemuri 
363*5146Ssvemuri 			/* create basic pic event/mask pair (only once) */
364*5146Ssvemuri 			if (i == 0)
365*5146Ssvemuri 				ni_create_name_kstat("lpu", ksinfop,
366*5146Ssvemuri 				    zam_lpu_perf_events);
367*5146Ssvemuri 
368*5146Ssvemuri 			/* create counter kstats */
369*5146Ssvemuri 			zam_lpu_kstats[i]->cntr_ksp = ni_create_cntr_kstat(
370*5146Ssvemuri 			    "lpu", i, zam_cntr_kstat_update, ksinfop);
371*5146Ssvemuri 		}
372*5146Ssvemuri 	}
373*5146Ssvemuri 	/*
374*5146Ssvemuri 	 * Create Zambezi GPD perf events kstat
375*5146Ssvemuri 	 */
376*5146Ssvemuri 	for (i = 0; i < ZAMBEZI_GPD_COUNTERS; i++) {
377*5146Ssvemuri 		/* check if this Zambezi GPD instance is enabled in the HW */
378*5146Ssvemuri 		stat = hv_niagara_getperf(gpd_perf_regs[i].pcr_reg, &pcr);
379*5146Ssvemuri 		if ((stat != H_EINVAL) && (stat != H_ENOTSUPPORTED)) {
380*5146Ssvemuri 			ksinfop = (ni_ksinfo_t *)kmem_zalloc(
381*5146Ssvemuri 			    sizeof (ni_ksinfo_t), KM_NOSLEEP);
382*5146Ssvemuri 
383*5146Ssvemuri 			if (ksinfop == NULL) {
384*5146Ssvemuri 				cmn_err(CE_WARN,
385*5146Ssvemuri 				    "%s: no space for zambezi gpd kstat\n",
386*5146Ssvemuri 				    cpu_module_name);
387*5146Ssvemuri 				break;
388*5146Ssvemuri 			}
389*5146Ssvemuri 			ksinfop->pic_no_evs =
390*5146Ssvemuri 			    sizeof (zam_gpd_perf_events) /
391*5146Ssvemuri 			    sizeof (ni_kev_mask_t);
392*5146Ssvemuri 			ksinfop->pic_sel_shift[0] = ZAMBEZI_PIC0_SEL_SHIFT;
393*5146Ssvemuri 			ksinfop->pic_reg[0] = gpd_perf_regs[i].pic_reg[0];
394*5146Ssvemuri 			ksinfop->pic_sel_shift[1] = ZAMBEZI_PIC1_SEL_SHIFT;
395*5146Ssvemuri 			ksinfop->pic_reg[1] = gpd_perf_regs[i].pic_reg[1];
396*5146Ssvemuri 			ksinfop->pcr_reg = gpd_perf_regs[i].pcr_reg;
397*5146Ssvemuri 			zam_gpd_kstats[i] = ksinfop;
398*5146Ssvemuri 
399*5146Ssvemuri 			/* create basic pic event/mask pair (only once) */
400*5146Ssvemuri 			if (i == 0)
401*5146Ssvemuri 				ni_create_name_kstat("gpd", ksinfop,
402*5146Ssvemuri 				    zam_gpd_perf_events);
403*5146Ssvemuri 
404*5146Ssvemuri 			/* create counter kstats */
405*5146Ssvemuri 			zam_lpu_kstats[i]->cntr_ksp = ni_create_cntr_kstat(
406*5146Ssvemuri 			    "gpd", i, zam_cntr_kstat_update, ksinfop);
407*5146Ssvemuri 		}
408*5146Ssvemuri 	}
409*5146Ssvemuri 	/*
410*5146Ssvemuri 	 * Create Zambezi ASU perf events kstat
411*5146Ssvemuri 	 */
412*5146Ssvemuri 	for (i = 0; i < ZAMBEZI_ASU_COUNTERS; i++) {
413*5146Ssvemuri 		/* check if this Zambezi ASU instance is enabled in the HW */
414*5146Ssvemuri 		stat = hv_niagara_getperf(asu_perf_regs[i].pcr_reg, &pcr);
415*5146Ssvemuri 		if ((stat != H_EINVAL) && (stat != H_ENOTSUPPORTED)) {
416*5146Ssvemuri 			ksinfop = (ni_ksinfo_t *)kmem_zalloc(
417*5146Ssvemuri 			    sizeof (ni_ksinfo_t), KM_NOSLEEP);
418*5146Ssvemuri 
419*5146Ssvemuri 			if (ksinfop == NULL) {
420*5146Ssvemuri 				cmn_err(CE_WARN,
421*5146Ssvemuri 				    "%s: no space for zambezi asu kstat\n",
422*5146Ssvemuri 				    cpu_module_name);
423*5146Ssvemuri 				break;
424*5146Ssvemuri 			}
425*5146Ssvemuri 			ksinfop->pic_no_evs =
426*5146Ssvemuri 			    sizeof (zam_asu_perf_events) /
427*5146Ssvemuri 			    sizeof (ni_kev_mask_t);
428*5146Ssvemuri 			ksinfop->pic_sel_shift[0] = ZAMBEZI_PIC0_SEL_SHIFT;
429*5146Ssvemuri 			ksinfop->pic_reg[0] = asu_perf_regs[i].pic_reg[0];
430*5146Ssvemuri 			ksinfop->pic_sel_shift[1] = ZAMBEZI_PIC1_SEL_SHIFT;
431*5146Ssvemuri 			ksinfop->pic_reg[1] = asu_perf_regs[i].pic_reg[1];
432*5146Ssvemuri 			ksinfop->pcr_reg = asu_perf_regs[i].pcr_reg;
433*5146Ssvemuri 			zam_asu_kstats[i] = ksinfop;
434*5146Ssvemuri 
435*5146Ssvemuri 			/* create basic pic event/mask pair (only once) */
436*5146Ssvemuri 			if (i == 0)
437*5146Ssvemuri 				ni_create_name_kstat("asu", ksinfop,
438*5146Ssvemuri 				    zam_asu_perf_events);
439*5146Ssvemuri 
440*5146Ssvemuri 			/* create counter kstats */
441*5146Ssvemuri 			zam_lpu_kstats[i]->cntr_ksp = ni_create_cntr_kstat(
442*5146Ssvemuri 			    "asu", i, zam_cntr_kstat_update, ksinfop);
443*5146Ssvemuri 		}
444*5146Ssvemuri 	}
445*5146Ssvemuri #endif
446*5146Ssvemuri 
4473156Sgirish #if defined(NIAGARA_IMPL)
4480Sstevel@tonic-gate 	/*
4490Sstevel@tonic-gate 	 * Create JBUS perf events kstat
4500Sstevel@tonic-gate 	 */
4510Sstevel@tonic-gate 	ni_jbus_kstat = (ni_ksinfo_t *)kmem_alloc(sizeof (ni_ksinfo_t),
4524732Sdavemq 	    KM_NOSLEEP);
4530Sstevel@tonic-gate 
4540Sstevel@tonic-gate 	if (ni_jbus_kstat == NULL) {
4550Sstevel@tonic-gate 		cmn_err(CE_WARN, "%s: no space for niagara jbus kstat\n",
4561592Sgirish 		    cpu_module_name);
4570Sstevel@tonic-gate 	} else {
4580Sstevel@tonic-gate 		ni_jbus_kstat->pic_no_evs =
4594732Sdavemq 		    sizeof (niagara_jbus_events) / sizeof (ni_kev_mask_t);
4600Sstevel@tonic-gate 		ni_jbus_kstat->pic_sel_shift[0] = NIAGARA_JBUS_PIC0_SEL_SHIFT;
4610Sstevel@tonic-gate 		ni_jbus_kstat->pic_shift[0] = NIAGARA_JBUS_PIC0_SHIFT;
4620Sstevel@tonic-gate 		ni_jbus_kstat->pic_mask[0] = NIAGARA_JBUS_PIC0_MASK;
4630Sstevel@tonic-gate 		ni_jbus_kstat->pic_sel_shift[1] = NIAGARA_JBUS_PIC1_SEL_SHIFT;
4640Sstevel@tonic-gate 		ni_jbus_kstat->pic_shift[1] = NIAGARA_JBUS_PIC1_SHIFT;
4650Sstevel@tonic-gate 		ni_jbus_kstat->pic_mask[1] = NIAGARA_JBUS_PIC1_MASK;
466*5146Ssvemuri 		ni_jbus_kstat->pic_reg[0] = HV_NIAGARA_JBUS_COUNT;
4670Sstevel@tonic-gate 		ni_jbus_kstat->pcr_reg = HV_NIAGARA_JBUS_CTL;
4680Sstevel@tonic-gate 		ni_create_name_kstat("jbus", ni_jbus_kstat,
4690Sstevel@tonic-gate 		    niagara_jbus_events);
4700Sstevel@tonic-gate 		ni_jbus_kstat->cntr_ksp = ni_create_cntr_kstat("jbus", 0,
4710Sstevel@tonic-gate 		    ni_cntr_kstat_update, ni_jbus_kstat);
4720Sstevel@tonic-gate 	}
4733156Sgirish #endif
4740Sstevel@tonic-gate }
4750Sstevel@tonic-gate 
4760Sstevel@tonic-gate void
4770Sstevel@tonic-gate niagara_kstat_fini()
4780Sstevel@tonic-gate {
4790Sstevel@tonic-gate 	int i;
4800Sstevel@tonic-gate 
4810Sstevel@tonic-gate #ifdef DEBUG
4820Sstevel@tonic-gate 	if (ni_perf_debug)
4830Sstevel@tonic-gate 		printf("ni_kstat_fini called\n");
4840Sstevel@tonic-gate #endif
485*5146Ssvemuri 
4860Sstevel@tonic-gate 	for (i = 0; i < NIAGARA_DRAM_BANKS; i++) {
4870Sstevel@tonic-gate 		if (ni_dram_kstats[i] != NULL) {
4880Sstevel@tonic-gate 			ni_delete_name_kstat(ni_dram_kstats[i]);
4890Sstevel@tonic-gate 			if (ni_dram_kstats[i]->cntr_ksp != NULL)
4900Sstevel@tonic-gate 				kstat_delete(ni_dram_kstats[i]->cntr_ksp);
4910Sstevel@tonic-gate 			kmem_free(ni_dram_kstats[i], sizeof (ni_ksinfo_t));
4920Sstevel@tonic-gate 			ni_dram_kstats[i] = NULL;
4930Sstevel@tonic-gate 		}
4940Sstevel@tonic-gate 	}
4950Sstevel@tonic-gate 
496*5146Ssvemuri #if defined(VFALLS_IMPL)
497*5146Ssvemuri 	for (i = 0; i < ZAMBEZI_LPU_COUNTERS; i++) {
498*5146Ssvemuri 		if (zam_lpu_kstats[i] != NULL) {
499*5146Ssvemuri 			ni_delete_name_kstat(zam_lpu_kstats[i]);
500*5146Ssvemuri 			if (zam_lpu_kstats[i]->cntr_ksp != NULL)
501*5146Ssvemuri 				kstat_delete(zam_lpu_kstats[i]->cntr_ksp);
502*5146Ssvemuri 			kmem_free(zam_lpu_kstats[i], sizeof (ni_ksinfo_t));
503*5146Ssvemuri 			zam_lpu_kstats[i] = NULL;
504*5146Ssvemuri 		}
505*5146Ssvemuri 	}
506*5146Ssvemuri 
507*5146Ssvemuri 	for (i = 0; i < ZAMBEZI_GPD_COUNTERS; i++) {
508*5146Ssvemuri 		if (zam_gpd_kstats[i] != NULL) {
509*5146Ssvemuri 			ni_delete_name_kstat(zam_gpd_kstats[i]);
510*5146Ssvemuri 			if (zam_gpd_kstats[i]->cntr_ksp != NULL)
511*5146Ssvemuri 				kstat_delete(zam_gpd_kstats[i]->cntr_ksp);
512*5146Ssvemuri 			kmem_free(zam_gpd_kstats[i], sizeof (ni_ksinfo_t));
513*5146Ssvemuri 			zam_gpd_kstats[i] = NULL;
514*5146Ssvemuri 		}
515*5146Ssvemuri 	}
516*5146Ssvemuri 
517*5146Ssvemuri 	for (i = 0; i < ZAMBEZI_ASU_COUNTERS; i++) {
518*5146Ssvemuri 		if (zam_asu_kstats[i] != NULL) {
519*5146Ssvemuri 			ni_delete_name_kstat(zam_asu_kstats[i]);
520*5146Ssvemuri 			if (zam_asu_kstats[i]->cntr_ksp != NULL)
521*5146Ssvemuri 				kstat_delete(zam_asu_kstats[i]->cntr_ksp);
522*5146Ssvemuri 			kmem_free(zam_asu_kstats[i], sizeof (ni_ksinfo_t));
523*5146Ssvemuri 			zam_asu_kstats[i] = NULL;
524*5146Ssvemuri 		}
525*5146Ssvemuri 	}
526*5146Ssvemuri #endif
527*5146Ssvemuri 
5283156Sgirish #if defined(NIAGARA_IMPL)
5290Sstevel@tonic-gate 	if (ni_jbus_kstat != NULL) {
5300Sstevel@tonic-gate 		ni_delete_name_kstat(ni_jbus_kstat);
5310Sstevel@tonic-gate 		if (ni_jbus_kstat->cntr_ksp != NULL)
5320Sstevel@tonic-gate 			kstat_delete(ni_jbus_kstat->cntr_ksp);
5330Sstevel@tonic-gate 		kmem_free(ni_jbus_kstat, sizeof (ni_ksinfo_t));
5340Sstevel@tonic-gate 		ni_jbus_kstat = NULL;
5350Sstevel@tonic-gate 	}
5363156Sgirish #endif
5370Sstevel@tonic-gate }
5380Sstevel@tonic-gate 
5390Sstevel@tonic-gate static void
5400Sstevel@tonic-gate ni_create_name_kstat(char *name, ni_ksinfo_t *pp, ni_kev_mask_t *ev)
5410Sstevel@tonic-gate {
5420Sstevel@tonic-gate 	int	i;
5430Sstevel@tonic-gate 
5440Sstevel@tonic-gate #ifdef DEBUG
5450Sstevel@tonic-gate 	if (ni_perf_debug > 1)
5460Sstevel@tonic-gate 		printf("ni_create_name_kstat: name: %s\n", name);
5470Sstevel@tonic-gate #endif
5480Sstevel@tonic-gate 	for (i = 0; i < NUM_OF_PICS; i++) {
5490Sstevel@tonic-gate 		pp->pic_name_ksp[i] = ni_create_picN_kstat(name,
5504732Sdavemq 		    i, pp->pic_sel_shift[i], pp->pic_no_evs, ev);
5510Sstevel@tonic-gate 
5520Sstevel@tonic-gate 		if (pp->pic_name_ksp[i] == NULL) {
5530Sstevel@tonic-gate 			cmn_err(CE_WARN, "%s: unable to create name kstat",
5541592Sgirish 			    cpu_module_name);
5550Sstevel@tonic-gate 		}
5560Sstevel@tonic-gate 	}
5570Sstevel@tonic-gate }
5580Sstevel@tonic-gate 
5590Sstevel@tonic-gate static void
5600Sstevel@tonic-gate ni_delete_name_kstat(ni_ksinfo_t *pp)
5610Sstevel@tonic-gate {
5620Sstevel@tonic-gate 	int	i;
5630Sstevel@tonic-gate 
5640Sstevel@tonic-gate 	if (pp != NULL) {
5650Sstevel@tonic-gate 		for (i = 0; i < NUM_OF_PICS; i++) {
5660Sstevel@tonic-gate 			if (pp->pic_name_ksp[i] != NULL)
5670Sstevel@tonic-gate 				kstat_delete(pp->pic_name_ksp[i]);
5680Sstevel@tonic-gate 		}
5690Sstevel@tonic-gate 	}
5700Sstevel@tonic-gate }
5710Sstevel@tonic-gate 
5720Sstevel@tonic-gate /*
5730Sstevel@tonic-gate  * Create the picN kstat. Returns a pointer to the
5740Sstevel@tonic-gate  * kstat which the driver must store to allow it
5750Sstevel@tonic-gate  * to be deleted when necessary.
5760Sstevel@tonic-gate  */
5770Sstevel@tonic-gate static kstat_t *
5780Sstevel@tonic-gate ni_create_picN_kstat(char *mod_name, int pic, int pic_sel_shift,
5790Sstevel@tonic-gate 	int num_ev, ni_kev_mask_t *ev_array)
5800Sstevel@tonic-gate {
5810Sstevel@tonic-gate 	struct kstat_named *pic_named_data;
5820Sstevel@tonic-gate 	int	inst = 0;
5830Sstevel@tonic-gate 	int	event;
5840Sstevel@tonic-gate 	char	pic_name[30];
5850Sstevel@tonic-gate 	kstat_t	*picN_ksp = NULL;
5860Sstevel@tonic-gate 
5870Sstevel@tonic-gate 	(void) sprintf(pic_name, "pic%d", pic);
5880Sstevel@tonic-gate 	if ((picN_ksp = kstat_create(mod_name, inst, pic_name,
5890Sstevel@tonic-gate 	    "bus", KSTAT_TYPE_NAMED, num_ev, NULL)) == NULL) {
5900Sstevel@tonic-gate 		cmn_err(CE_WARN, "%s %s : kstat create failed",
5914732Sdavemq 		    mod_name, pic_name);
5920Sstevel@tonic-gate 
5930Sstevel@tonic-gate 		/*
5940Sstevel@tonic-gate 		 * It is up to the calling function to delete any kstats
5950Sstevel@tonic-gate 		 * that may have been created already. We just
5960Sstevel@tonic-gate 		 * return NULL to indicate an error has occured.
5970Sstevel@tonic-gate 		 */
5980Sstevel@tonic-gate 		return (NULL);
5990Sstevel@tonic-gate 	}
6000Sstevel@tonic-gate 
6010Sstevel@tonic-gate 	pic_named_data = (struct kstat_named *)
6020Sstevel@tonic-gate 	    picN_ksp->ks_data;
6030Sstevel@tonic-gate 
6040Sstevel@tonic-gate 	/*
6050Sstevel@tonic-gate 	 * Write event names and their associated pcr masks. The
6060Sstevel@tonic-gate 	 * last entry in the array (clear_pic) is added seperately
6070Sstevel@tonic-gate 	 * below as the pic value must be inverted.
6080Sstevel@tonic-gate 	 */
6090Sstevel@tonic-gate 	for (event = 0; event < num_ev - 1; event++) {
6100Sstevel@tonic-gate 		pic_named_data[event].value.ui64 =
6114732Sdavemq 		    (ev_array[event].pcr_mask << pic_sel_shift);
6120Sstevel@tonic-gate 
6130Sstevel@tonic-gate 		kstat_named_init(&pic_named_data[event],
6144732Sdavemq 		    ev_array[event].event_name,
6154732Sdavemq 		    KSTAT_DATA_UINT64);
6160Sstevel@tonic-gate 	}
6170Sstevel@tonic-gate 
6180Sstevel@tonic-gate 	/*
6190Sstevel@tonic-gate 	 * add the clear_pic entry.
6200Sstevel@tonic-gate 	 */
6210Sstevel@tonic-gate 	pic_named_data[event].value.ui64 =
6224732Sdavemq 	    (uint64_t)~(ev_array[event].pcr_mask << pic_sel_shift);
6230Sstevel@tonic-gate 
6240Sstevel@tonic-gate 	kstat_named_init(&pic_named_data[event], ev_array[event].event_name,
6250Sstevel@tonic-gate 	    KSTAT_DATA_UINT64);
6260Sstevel@tonic-gate 
6270Sstevel@tonic-gate 	kstat_install(picN_ksp);
6280Sstevel@tonic-gate 
6290Sstevel@tonic-gate 	return (picN_ksp);
6300Sstevel@tonic-gate }
6310Sstevel@tonic-gate 
6320Sstevel@tonic-gate /*
6330Sstevel@tonic-gate  * Create the "counters" kstat.
6340Sstevel@tonic-gate  */
6350Sstevel@tonic-gate static kstat_t *
6360Sstevel@tonic-gate ni_create_cntr_kstat(char *name, int instance, int (*update)(kstat_t *, int),
6370Sstevel@tonic-gate 	void *ksinfop)
6380Sstevel@tonic-gate {
6390Sstevel@tonic-gate 	struct kstat	*counters_ksp;
6400Sstevel@tonic-gate 	struct kstat_named	*counters_named_data;
6410Sstevel@tonic-gate 	char		pic_str[10];
6420Sstevel@tonic-gate 	int		i;
6430Sstevel@tonic-gate 	int		num_pics = NUM_OF_PICS;
6440Sstevel@tonic-gate 
6450Sstevel@tonic-gate #ifdef DEBUG
6460Sstevel@tonic-gate 	if (ni_perf_debug > 1)
6470Sstevel@tonic-gate 		printf("ni_create_cntr_kstat: name: %s instance: %d\n",
6480Sstevel@tonic-gate 		    name, instance);
6490Sstevel@tonic-gate #endif
6500Sstevel@tonic-gate 
6510Sstevel@tonic-gate 	/*
6520Sstevel@tonic-gate 	 * Size of kstat is num_pics + 1 as it
6530Sstevel@tonic-gate 	 * also contains the %pcr
6540Sstevel@tonic-gate 	 */
6550Sstevel@tonic-gate 	if ((counters_ksp = kstat_create(name, instance, "counters", "bus",
6560Sstevel@tonic-gate 	    KSTAT_TYPE_NAMED, num_pics + 1, KSTAT_FLAG_WRITABLE)) == NULL) {
6570Sstevel@tonic-gate 		cmn_err(CE_WARN,
6581592Sgirish 		    "%s: kstat_create for %s%d failed", cpu_module_name,
6590Sstevel@tonic-gate 		    name, instance);
6600Sstevel@tonic-gate 		return (NULL);
6610Sstevel@tonic-gate 	}
6620Sstevel@tonic-gate 
6630Sstevel@tonic-gate 	counters_named_data = (struct kstat_named *)(counters_ksp->ks_data);
6640Sstevel@tonic-gate 
6650Sstevel@tonic-gate 	/*
6660Sstevel@tonic-gate 	 * Iinitialize the named kstats
6670Sstevel@tonic-gate 	 */
6680Sstevel@tonic-gate 	kstat_named_init(&counters_named_data[0], "pcr", KSTAT_DATA_UINT64);
6690Sstevel@tonic-gate 
6700Sstevel@tonic-gate 	for (i = 0; i < num_pics; i++) {
6710Sstevel@tonic-gate 		(void) sprintf(pic_str, "pic%d", i);
6720Sstevel@tonic-gate 
6730Sstevel@tonic-gate 		kstat_named_init(&counters_named_data[i+1], pic_str,
6740Sstevel@tonic-gate 		    KSTAT_DATA_UINT64);
6750Sstevel@tonic-gate 	}
6760Sstevel@tonic-gate 
6770Sstevel@tonic-gate 	/*
6780Sstevel@tonic-gate 	 * Store the register offset's in the kstat's
6790Sstevel@tonic-gate 	 * private field so that they are available
6800Sstevel@tonic-gate 	 * to the update function.
6810Sstevel@tonic-gate 	 */
6820Sstevel@tonic-gate 	counters_ksp->ks_private = (void *)ksinfop;
6830Sstevel@tonic-gate 	counters_ksp->ks_update = update;
6840Sstevel@tonic-gate 
6850Sstevel@tonic-gate 	kstat_install(counters_ksp);
6860Sstevel@tonic-gate 
6870Sstevel@tonic-gate 	return (counters_ksp);
6880Sstevel@tonic-gate }
6890Sstevel@tonic-gate 
690*5146Ssvemuri #if defined(VFALLS_IMPL)
691*5146Ssvemuri /*
692*5146Ssvemuri  * zambezi kstat update function. Handles reads/writes
693*5146Ssvemuri  * from/to kstat.
694*5146Ssvemuri  */
695*5146Ssvemuri static int
696*5146Ssvemuri zam_cntr_kstat_update(kstat_t *ksp, int rw)
697*5146Ssvemuri {
698*5146Ssvemuri 	struct kstat_named	*data_p;
699*5146Ssvemuri 	ni_ksinfo_t	*ksinfop = ksp->ks_private;
700*5146Ssvemuri 	uint64_t	pic0, pic1, pcr;
701*5146Ssvemuri 	int		stat = 0;
702*5146Ssvemuri 	uint64_t	pic0_stat = 0, pic1_stat = 0, pcr_stat = 0;
703*5146Ssvemuri 
704*5146Ssvemuri 	data_p = (struct kstat_named *)ksp->ks_data;
705*5146Ssvemuri 
706*5146Ssvemuri 	if (rw == KSTAT_WRITE) {
707*5146Ssvemuri #ifdef DEBUG
708*5146Ssvemuri 		if (ni_perf_debug)
709*5146Ssvemuri 			printf("zam_cntr_kstat_update: wr pcr-%d: %lx\n",
710*5146Ssvemuri 			    ksinfop->pcr_reg, data_p[0].value.ui64);
711*5146Ssvemuri #endif
712*5146Ssvemuri 		if (hv_niagara_setperf(ksinfop->pcr_reg, data_p[0].value.ui64))
713*5146Ssvemuri 			stat = EACCES;
714*5146Ssvemuri 	} else {
715*5146Ssvemuri 		do {
716*5146Ssvemuri 			pic0_stat = hv_niagara_getperf(ksinfop->pic_reg[0],
717*5146Ssvemuri 			    &pic0);
718*5146Ssvemuri 		} while (pic0_stat == H_EWOULDBLOCK);
719*5146Ssvemuri 		do {
720*5146Ssvemuri 			pic1_stat = hv_niagara_getperf(ksinfop->pic_reg[1],
721*5146Ssvemuri 			    &pic1);
722*5146Ssvemuri 		} while (pic1_stat == H_EWOULDBLOCK);
723*5146Ssvemuri 		do {
724*5146Ssvemuri 			pcr_stat = hv_niagara_getperf(ksinfop->pcr_reg,
725*5146Ssvemuri 			    &pcr);
726*5146Ssvemuri 		} while (pcr_stat == H_EWOULDBLOCK);
727*5146Ssvemuri 		if (pic0_stat != 0 || pic1_stat != 0 || pcr_stat != 0)
728*5146Ssvemuri 			stat = EACCES;
729*5146Ssvemuri 		else {
730*5146Ssvemuri 			data_p[0].value.ui64 = pcr;
731*5146Ssvemuri 			data_p[1].value.ui64 = pic0;
732*5146Ssvemuri 			data_p[2].value.ui64 = pic1;
733*5146Ssvemuri 		}
734*5146Ssvemuri #ifdef DEBUG
735*5146Ssvemuri 		if (ni_perf_debug)
736*5146Ssvemuri 			printf("zam_cntr_kstat_update: rd pcr%d: %lx  "
737*5146Ssvemuri 			    "pic0: %16lx pic1: %16lx\n",
738*5146Ssvemuri 			    ksinfop->pcr_reg, pcr,
739*5146Ssvemuri 			    data_p[1].value.ui64, data_p[2].value.ui64);
740*5146Ssvemuri #endif
741*5146Ssvemuri 	}
742*5146Ssvemuri 
743*5146Ssvemuri 	return (stat);
744*5146Ssvemuri }
745*5146Ssvemuri #endif
746*5146Ssvemuri 
7470Sstevel@tonic-gate /*
7480Sstevel@tonic-gate  * kstat update function. Handles reads/writes
7490Sstevel@tonic-gate  * from/to kstat.
7500Sstevel@tonic-gate  */
7510Sstevel@tonic-gate static int
7520Sstevel@tonic-gate ni_cntr_kstat_update(kstat_t *ksp, int rw)
7530Sstevel@tonic-gate {
7540Sstevel@tonic-gate 	struct kstat_named	*data_p;
7550Sstevel@tonic-gate 	ni_ksinfo_t	*ksinfop = ksp->ks_private;
7560Sstevel@tonic-gate 	uint64_t	pic, pcr;
7570Sstevel@tonic-gate 	int		stat = 0;
7580Sstevel@tonic-gate 	uint32_t	pic0, pic1;
7590Sstevel@tonic-gate 
7600Sstevel@tonic-gate 	data_p = (struct kstat_named *)ksp->ks_data;
7610Sstevel@tonic-gate 
7620Sstevel@tonic-gate 	if (rw == KSTAT_WRITE) {
7630Sstevel@tonic-gate #ifdef DEBUG
7640Sstevel@tonic-gate 		if (ni_perf_debug)
765911Siskreen 			printf("ni_cntr_kstat_update: wr pcr-%d: %lx\n",
7660Sstevel@tonic-gate 			    ksinfop->pcr_reg, data_p[0].value.ui64);
7670Sstevel@tonic-gate #endif
7680Sstevel@tonic-gate 		if (hv_niagara_setperf(ksinfop->pcr_reg, data_p[0].value.ui64))
7690Sstevel@tonic-gate 			stat = EACCES;
7700Sstevel@tonic-gate 	} else {
771*5146Ssvemuri 		if (hv_niagara_getperf(ksinfop->pic_reg[0], &pic) != 0 ||
7720Sstevel@tonic-gate 		    hv_niagara_getperf(ksinfop->pcr_reg, &pcr) != 0)
7730Sstevel@tonic-gate 			stat = EACCES;
7740Sstevel@tonic-gate 		else {
7750Sstevel@tonic-gate 
7760Sstevel@tonic-gate 			data_p[0].value.ui64 = pcr;
7770Sstevel@tonic-gate 
7780Sstevel@tonic-gate 			/*
7790Sstevel@tonic-gate 			 * Generate a 32-bit PIC0 value by detecting overflow
7800Sstevel@tonic-gate 			 */
7810Sstevel@tonic-gate 			pic0 = (uint32_t)((pic >> ksinfop->pic_shift[0]) &
7820Sstevel@tonic-gate 			    ksinfop->pic_mask[0]);
7830Sstevel@tonic-gate 			if (pic0 < ksinfop->pic_last_val[0])
7840Sstevel@tonic-gate 				ksinfop->pic_overflow[0]++;
7850Sstevel@tonic-gate 			ksinfop->pic_last_val[0] = pic0;
7860Sstevel@tonic-gate 			pic0 += (ksinfop->pic_overflow[0] & 1) << 31;
7870Sstevel@tonic-gate 			data_p[1].value.ui64 = (uint64_t)pic0;
7880Sstevel@tonic-gate 
7890Sstevel@tonic-gate 			/*
7900Sstevel@tonic-gate 			 * Generate a 32-bit PIC1 value by detecting overflow
7910Sstevel@tonic-gate 			 */
7920Sstevel@tonic-gate 			pic1 = (uint32_t)((pic >> ksinfop->pic_shift[1]) &
7930Sstevel@tonic-gate 			    ksinfop->pic_mask[1]);
7940Sstevel@tonic-gate 			if (pic1 < ksinfop->pic_last_val[1])
7950Sstevel@tonic-gate 				ksinfop->pic_overflow[1]++;
7960Sstevel@tonic-gate 			ksinfop->pic_last_val[1] = pic1;
7970Sstevel@tonic-gate 			pic1 += (ksinfop->pic_overflow[1] & 1) << 31;
7980Sstevel@tonic-gate 			data_p[2].value.ui64 = (uint64_t)pic1;
7990Sstevel@tonic-gate 		}
8000Sstevel@tonic-gate #ifdef DEBUG
8010Sstevel@tonic-gate 		if (ni_perf_debug)
8020Sstevel@tonic-gate 			printf("ni_cntr_kstat_update: rd pcr%d: %lx  "
8030Sstevel@tonic-gate 			    "pic%d: %16lx pic0: %8lx pic1: %8lx\n",
804*5146Ssvemuri 			    ksinfop->pcr_reg, pcr, ksinfop->pic_reg[0], pic,
8050Sstevel@tonic-gate 			    data_p[1].value.ui64, data_p[2].value.ui64);
8060Sstevel@tonic-gate #endif
8070Sstevel@tonic-gate 	}
8080Sstevel@tonic-gate 	return (stat);
8090Sstevel@tonic-gate }
810