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 /*
22*11304SJanie.Lu@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
230Sstevel@tonic-gate * Use is subject to license terms.
240Sstevel@tonic-gate */
250Sstevel@tonic-gate
260Sstevel@tonic-gate #include <sys/types.h>
270Sstevel@tonic-gate #include <sys/async.h>
280Sstevel@tonic-gate #include <sys/sunddi.h>
290Sstevel@tonic-gate #include <sys/sunndi.h>
300Sstevel@tonic-gate #include <sys/ddi_impldefs.h>
310Sstevel@tonic-gate #include <sys/machsystm.h>
320Sstevel@tonic-gate #include <sys/hypervisor_api.h>
330Sstevel@tonic-gate #include <sys/kstat.h>
343156Sgirish #if defined(NIAGARA_IMPL)
353156Sgirish #include <sys/niagararegs.h>
36*11304SJanie.Lu@Sun.COM #elif defined(NIAGARA2_IMPL) || defined(VFALLS_IMPL) || defined(KT_IMPL)
373156Sgirish #include <sys/niagara2regs.h>
383156Sgirish #endif
390Sstevel@tonic-gate
401592Sgirish extern char cpu_module_name[];
410Sstevel@tonic-gate
420Sstevel@tonic-gate /*
430Sstevel@tonic-gate * Data structure used to build array of event-names and pcr-mask values
440Sstevel@tonic-gate */
450Sstevel@tonic-gate typedef struct ni_kev_mask {
460Sstevel@tonic-gate char *event_name;
470Sstevel@tonic-gate uint64_t pcr_mask;
480Sstevel@tonic-gate } ni_kev_mask_t;
490Sstevel@tonic-gate
500Sstevel@tonic-gate /*
510Sstevel@tonic-gate * Kstat data structure for DRAM and JBUS performance counters
520Sstevel@tonic-gate *
530Sstevel@tonic-gate * Note that these performance counters are only 31 bits wide. Since
540Sstevel@tonic-gate * the "busstat" command assumes a 32-bit counter, we emulate a 32-bit
550Sstevel@tonic-gate * counter by detecting overflow on read of these performance counters
560Sstevel@tonic-gate * and using the least significant bit of the overflow count as the
570Sstevel@tonic-gate * most significant bit (i.e. bit# 31) of the DRAM and JBUS performance
580Sstevel@tonic-gate * counters.
590Sstevel@tonic-gate */
601592Sgirish #define NUM_OF_PICS 2
61*11304SJanie.Lu@Sun.COM #define NUM_OF_PIC_REGS 1
621592Sgirish
630Sstevel@tonic-gate typedef struct ni_ksinfo {
640Sstevel@tonic-gate uint8_t pic_no_evs; /* number of events */
650Sstevel@tonic-gate uint8_t pic_sel_shift[NUM_OF_PICS];
660Sstevel@tonic-gate uint8_t pic_shift[NUM_OF_PICS];
670Sstevel@tonic-gate uint64_t pic_mask[NUM_OF_PICS];
680Sstevel@tonic-gate kstat_t *pic_name_ksp[NUM_OF_PICS];
690Sstevel@tonic-gate kstat_t *cntr_ksp;
70*11304SJanie.Lu@Sun.COM uint32_t pic_reg[NUM_OF_PIC_REGS];
710Sstevel@tonic-gate uint32_t pcr_reg;
720Sstevel@tonic-gate uint32_t pic_overflow[NUM_OF_PICS]; /* overflow count */
730Sstevel@tonic-gate uint32_t pic_last_val[NUM_OF_PICS]; /* last PIC value */
740Sstevel@tonic-gate } ni_ksinfo_t;
750Sstevel@tonic-gate
76*11304SJanie.Lu@Sun.COM static ni_ksinfo_t *ni_dram_kstats[DRAM_BANKS];
773156Sgirish
783156Sgirish #if defined(NIAGARA_IMPL)
790Sstevel@tonic-gate static ni_ksinfo_t *ni_jbus_kstat;
803156Sgirish #endif
810Sstevel@tonic-gate
820Sstevel@tonic-gate typedef struct ni_perf_regs {
830Sstevel@tonic-gate uint32_t pcr_reg;
84*11304SJanie.Lu@Sun.COM uint32_t pic_reg[NUM_OF_PIC_REGS];
850Sstevel@tonic-gate } ni_perf_regs_t;
860Sstevel@tonic-gate
870Sstevel@tonic-gate static ni_perf_regs_t dram_perf_regs[] = {
88*11304SJanie.Lu@Sun.COM #if defined(NIAGARA_IMPL) || defined(NIAGARA2_IMPL)
89*11304SJanie.Lu@Sun.COM {HV_DRAM_CTL0, HV_DRAM_COUNT0},
90*11304SJanie.Lu@Sun.COM {HV_DRAM_CTL1, HV_DRAM_COUNT1},
91*11304SJanie.Lu@Sun.COM {HV_DRAM_CTL2, HV_DRAM_COUNT2},
92*11304SJanie.Lu@Sun.COM {HV_DRAM_CTL3, HV_DRAM_COUNT3},
93*11304SJanie.Lu@Sun.COM #elif defined(VFALLS_IMPL) || defined(KT_IMPL)
94*11304SJanie.Lu@Sun.COM {HV_DRAM_CTL0, HV_DRAM_COUNT0},
95*11304SJanie.Lu@Sun.COM {HV_DRAM_CTL1, HV_DRAM_COUNT1},
96*11304SJanie.Lu@Sun.COM {HV_DRAM_CTL2, HV_DRAM_COUNT2},
97*11304SJanie.Lu@Sun.COM {HV_DRAM_CTL3, HV_DRAM_COUNT3},
98*11304SJanie.Lu@Sun.COM {HV_DRAM_CTL4, HV_DRAM_COUNT4},
99*11304SJanie.Lu@Sun.COM {HV_DRAM_CTL5, HV_DRAM_COUNT5},
100*11304SJanie.Lu@Sun.COM {HV_DRAM_CTL6, HV_DRAM_COUNT6},
101*11304SJanie.Lu@Sun.COM {HV_DRAM_CTL7, HV_DRAM_COUNT7}
1025146Ssvemuri #endif
1030Sstevel@tonic-gate };
1040Sstevel@tonic-gate
1055146Ssvemuri #ifdef VFALLS_IMPL
1065146Ssvemuri /*
1075146Ssvemuri * Kstat data structure for Zambezi performance counters
1085146Ssvemuri * These performance counters are 64 bits wide.
1095146Ssvemuri */
1105146Ssvemuri static ni_ksinfo_t *zam_lpu_kstats[ZAMBEZI_LPU_COUNTERS];
1115146Ssvemuri static ni_ksinfo_t *zam_gpd_kstats[ZAMBEZI_GPD_COUNTERS];
1125146Ssvemuri static ni_ksinfo_t *zam_asu_kstats[ZAMBEZI_ASU_COUNTERS];
1135146Ssvemuri
1145146Ssvemuri typedef struct zam_perf_regs {
1155146Ssvemuri uint32_t pcr_reg;
1165146Ssvemuri uint32_t pic_reg[NUM_OF_PICS];
1175146Ssvemuri } zam_perf_regs_t;
1185146Ssvemuri
1195146Ssvemuri static zam_perf_regs_t lpu_perf_regs[] = {
1205146Ssvemuri {HV_ZAM0_LPU_A_PCR, HV_ZAM0_LPU_A_PIC0, HV_ZAM0_LPU_A_PIC1},
1215146Ssvemuri {HV_ZAM0_LPU_B_PCR, HV_ZAM0_LPU_B_PIC0, HV_ZAM0_LPU_B_PIC1},
1225146Ssvemuri {HV_ZAM0_LPU_C_PCR, HV_ZAM0_LPU_C_PIC0, HV_ZAM0_LPU_C_PIC1},
1235146Ssvemuri {HV_ZAM0_LPU_D_PCR, HV_ZAM0_LPU_D_PIC0, HV_ZAM0_LPU_D_PIC1},
1245146Ssvemuri
1255146Ssvemuri {HV_ZAM1_LPU_A_PCR, HV_ZAM1_LPU_A_PIC0, HV_ZAM1_LPU_A_PIC1},
1265146Ssvemuri {HV_ZAM1_LPU_B_PCR, HV_ZAM1_LPU_B_PIC0, HV_ZAM1_LPU_B_PIC1},
1275146Ssvemuri {HV_ZAM1_LPU_C_PCR, HV_ZAM1_LPU_C_PIC0, HV_ZAM1_LPU_C_PIC1},
1285146Ssvemuri {HV_ZAM1_LPU_D_PCR, HV_ZAM1_LPU_D_PIC0, HV_ZAM1_LPU_D_PIC1},
1295146Ssvemuri
1305146Ssvemuri {HV_ZAM2_LPU_A_PCR, HV_ZAM2_LPU_A_PIC0, HV_ZAM2_LPU_A_PIC1},
1315146Ssvemuri {HV_ZAM2_LPU_B_PCR, HV_ZAM2_LPU_B_PIC0, HV_ZAM2_LPU_B_PIC1},
1325146Ssvemuri {HV_ZAM2_LPU_C_PCR, HV_ZAM2_LPU_C_PIC0, HV_ZAM2_LPU_C_PIC1},
1335146Ssvemuri {HV_ZAM2_LPU_D_PCR, HV_ZAM2_LPU_D_PIC0, HV_ZAM2_LPU_D_PIC1},
1345146Ssvemuri
1355146Ssvemuri {HV_ZAM3_LPU_A_PCR, HV_ZAM3_LPU_A_PIC0, HV_ZAM3_LPU_A_PIC1},
1365146Ssvemuri {HV_ZAM3_LPU_B_PCR, HV_ZAM3_LPU_B_PIC0, HV_ZAM3_LPU_B_PIC1},
1375146Ssvemuri {HV_ZAM3_LPU_C_PCR, HV_ZAM3_LPU_C_PIC0, HV_ZAM3_LPU_C_PIC1},
1385146Ssvemuri {HV_ZAM3_LPU_D_PCR, HV_ZAM3_LPU_D_PIC0, HV_ZAM3_LPU_D_PIC1}
1395146Ssvemuri };
1405146Ssvemuri
1415146Ssvemuri static zam_perf_regs_t gpd_perf_regs[] = {
1425146Ssvemuri {HV_ZAM0_GPD_PCR, HV_ZAM0_GPD_PIC0, HV_ZAM0_GPD_PIC1},
1435146Ssvemuri {HV_ZAM1_GPD_PCR, HV_ZAM1_GPD_PIC0, HV_ZAM1_GPD_PIC1},
1445146Ssvemuri {HV_ZAM2_GPD_PCR, HV_ZAM2_GPD_PIC0, HV_ZAM2_GPD_PIC1},
1455146Ssvemuri {HV_ZAM3_GPD_PCR, HV_ZAM3_GPD_PIC0, HV_ZAM3_GPD_PIC1}
1465146Ssvemuri };
1475146Ssvemuri
1485146Ssvemuri static zam_perf_regs_t asu_perf_regs[] = {
1495146Ssvemuri {HV_ZAM0_ASU_PCR, HV_ZAM0_ASU_PIC0, HV_ZAM0_ASU_PIC1},
1505146Ssvemuri {HV_ZAM1_ASU_PCR, HV_ZAM1_ASU_PIC0, HV_ZAM1_ASU_PIC1},
1515146Ssvemuri {HV_ZAM2_ASU_PCR, HV_ZAM2_ASU_PIC0, HV_ZAM2_ASU_PIC1},
1525146Ssvemuri {HV_ZAM3_ASU_PCR, HV_ZAM3_ASU_PIC0, HV_ZAM3_ASU_PIC1}
1535146Ssvemuri };
1545146Ssvemuri
1555146Ssvemuri static int zam_cntr_kstat_update(kstat_t *, int);
1565146Ssvemuri #endif
1575146Ssvemuri
1580Sstevel@tonic-gate static void ni_create_name_kstat(char *, ni_ksinfo_t *, ni_kev_mask_t *);
1590Sstevel@tonic-gate static void ni_delete_name_kstat(ni_ksinfo_t *);
1600Sstevel@tonic-gate
1610Sstevel@tonic-gate static kstat_t *ni_create_cntr_kstat(char *, int,
1620Sstevel@tonic-gate int (*update)(kstat_t *, int), void *);
1630Sstevel@tonic-gate
1640Sstevel@tonic-gate static int ni_cntr_kstat_update(kstat_t *, int);
1650Sstevel@tonic-gate
1660Sstevel@tonic-gate static kstat_t *ni_create_picN_kstat(char *, int, int, int,
1670Sstevel@tonic-gate ni_kev_mask_t *);
1680Sstevel@tonic-gate
1690Sstevel@tonic-gate #ifdef DEBUG
1700Sstevel@tonic-gate static int ni_perf_debug;
1710Sstevel@tonic-gate #endif
1720Sstevel@tonic-gate
1730Sstevel@tonic-gate /*
1744732Sdavemq * Niagara, Niagara2 and VFalls DRAM Performance Events
1750Sstevel@tonic-gate */
1760Sstevel@tonic-gate static ni_kev_mask_t
1770Sstevel@tonic-gate niagara_dram_events[] = {
178*11304SJanie.Lu@Sun.COM #if defined(NIAGARA_IMPL) || defined(NIAGARA2_IMPL) || defined(VFALLS_IMPL)
1790Sstevel@tonic-gate {"mem_reads", 0x0},
1800Sstevel@tonic-gate {"mem_writes", 0x1},
1810Sstevel@tonic-gate {"mem_read_write", 0x2},
182*11304SJanie.Lu@Sun.COM #elif defined(KT_IMPL)
183*11304SJanie.Lu@Sun.COM {"remote_reads", 0x0},
184*11304SJanie.Lu@Sun.COM {"remote_writes", 0x1},
185*11304SJanie.Lu@Sun.COM {"remote_read_write", 0x2},
186*11304SJanie.Lu@Sun.COM #endif
187*11304SJanie.Lu@Sun.COM #if defined(NIAGARA_IMPL) || defined(KT_IMPL)
1880Sstevel@tonic-gate {"bank_busy_stalls", 0x3},
1897420SSree.Vemuri@Sun.COM #endif
1900Sstevel@tonic-gate {"rd_queue_latency", 0x4},
1910Sstevel@tonic-gate {"wr_queue_latency", 0x5},
1920Sstevel@tonic-gate {"rw_queue_latency", 0x6},
193*11304SJanie.Lu@Sun.COM #if defined(NIAGARA_IMPL) || defined(NIAGARA2_IMPL) || defined(VFALLS_IMPL)
1940Sstevel@tonic-gate {"wb_buf_hits", 0x7},
195*11304SJanie.Lu@Sun.COM #elif defined(KT_IMPL)
196*11304SJanie.Lu@Sun.COM {"write_queue_drain", 0x7},
197*11304SJanie.Lu@Sun.COM {"read_all_channels", 0x8},
198*11304SJanie.Lu@Sun.COM {"write_starved", 0x9},
199*11304SJanie.Lu@Sun.COM {"write_all_channels", 0xa},
200*11304SJanie.Lu@Sun.COM {"read_write_channel0", 0xb},
201*11304SJanie.Lu@Sun.COM {"read_write_channel1", 0xc},
202*11304SJanie.Lu@Sun.COM #endif
2035146Ssvemuri {"clear_pic", 0xf}
2040Sstevel@tonic-gate };
2050Sstevel@tonic-gate
2065146Ssvemuri #if defined(VFALLS_IMPL)
2075146Ssvemuri /*
2085146Ssvemuri * Zambezi Performance Events
2095146Ssvemuri */
2105146Ssvemuri static ni_kev_mask_t
2115146Ssvemuri zam_lpu_perf_events[] = {
2125146Ssvemuri {"none", 0x0},
2135146Ssvemuri {"clock_cycles", 0x1},
2145146Ssvemuri {"cycles_c2c_portX", 0x2},
2155146Ssvemuri {"cycles_mem_portX", 0x3},
2165146Ssvemuri {"cycles_WB_portX", 0x4},
2175146Ssvemuri {"cycles_NC_portX", 0x5},
2185146Ssvemuri {"cycles_c2c_portY", 0x6},
2195146Ssvemuri {"cycles_mem_portY", 0x7},
2205146Ssvemuri {"cycles_WB_portY", 0x8},
2215146Ssvemuri {"cycles_NC_portY", 0x9},
2225146Ssvemuri {"cycles_c2c_portZ", 0xa},
2235146Ssvemuri {"cycles_mem_portZ", 0xb},
2245146Ssvemuri {"cycles_WB_portZ", 0xc},
2255146Ssvemuri {"cycles_NC_portZ", 0xd},
2265146Ssvemuri {"cycles_TID_WB", 0xe},
2275146Ssvemuri {"cycles_TID_INV", 0xf},
2285146Ssvemuri {"cycles_TID_RTD", 0x10},
2295146Ssvemuri {"cycles_TID_RTO", 0x11},
2305146Ssvemuri {"cycles_TID_RTS", 0x12},
2315146Ssvemuri {"cycles_IO_WRM", 0x13},
2325146Ssvemuri {"cycles_IO_RD", 0x14},
2335146Ssvemuri {"cycles_WB_egress", 0x15},
2345146Ssvemuri {"cycles_INV_egress", 0x16},
2355146Ssvemuri {"cycles_RTO_egress", 0x17},
2365146Ssvemuri {"cycles_RTD_egress", 0x18},
2375146Ssvemuri {"cycles_RTS_egress", 0x19},
2385146Ssvemuri {"cycles_no_WB", 0x1a},
2395146Ssvemuri {"cycles_no_read/inv", 0x1b},
2405146Ssvemuri {"cycles_HIT_M", 0x1c},
2415146Ssvemuri {"cycles_HIT_O", 0x1d},
2425146Ssvemuri {"cycles_HIT_S", 0x1e},
2435146Ssvemuri {"cycles_WB_HIT", 0x1f},
2445146Ssvemuri {"cycles_MISS", 0x20},
2455146Ssvemuri {"cycles_READ_or_INV", 0x21},
2465146Ssvemuri {"cycles_WB", 0x22},
2475146Ssvemuri {"cycles_NDR", 0x23},
2485146Ssvemuri {"cycles_cache_miss", 0x24},
2495146Ssvemuri {"cycles_cache_hit", 0x25},
2505146Ssvemuri {"cycles_CRC_errors", 0x26},
2515146Ssvemuri {"cycles_replys_sent", 0x27},
2525146Ssvemuri {"cycles_replys_recev", 0x28},
2535146Ssvemuri {"cycles_link_retrain", 0x29},
2545146Ssvemuri {"clear_pic", 0xff}
2555146Ssvemuri };
2565146Ssvemuri
2575146Ssvemuri static ni_kev_mask_t
2585146Ssvemuri zam_gpd_perf_events[] = {
2595146Ssvemuri {"none", 0x0},
2605146Ssvemuri {"clock_cycles", 0x1},
2615146Ssvemuri {"clear_pic", 0xf}
2625146Ssvemuri };
2635146Ssvemuri
2645146Ssvemuri static ni_kev_mask_t
2655146Ssvemuri zam_asu_perf_events[] = {
2665146Ssvemuri {"none", 0x0},
2675146Ssvemuri {"clock_cycles", 0x1},
2685146Ssvemuri {"asu_in_pck", 0x2},
2695146Ssvemuri {"asu_out_pck", 0x3},
2705146Ssvemuri {"asu_CAM_hit", 0x4},
2715146Ssvemuri {"asu_wakeup", 0x5},
2725146Ssvemuri {"clear_pic", 0xf}
2735146Ssvemuri };
2745146Ssvemuri #endif
2750Sstevel@tonic-gate
2763156Sgirish #if defined(NIAGARA_IMPL)
2770Sstevel@tonic-gate /*
2780Sstevel@tonic-gate * Niagara JBUS Performance Events
2790Sstevel@tonic-gate */
2800Sstevel@tonic-gate static ni_kev_mask_t
2810Sstevel@tonic-gate niagara_jbus_events[] = {
2820Sstevel@tonic-gate {"jbus_cycles", 0x1},
2830Sstevel@tonic-gate {"dma_reads", 0x2},
2840Sstevel@tonic-gate {"dma_read_latency", 0x3},
2850Sstevel@tonic-gate {"dma_writes", 0x4},
2860Sstevel@tonic-gate {"dma_write8", 0x5},
2870Sstevel@tonic-gate {"ordering_waits", 0x6},
2880Sstevel@tonic-gate {"pio_reads", 0x8},
2890Sstevel@tonic-gate {"pio_read_latency", 0x9},
2900Sstevel@tonic-gate {"aok_dok_off_cycles", 0xc},
2910Sstevel@tonic-gate {"aok_off_cycles", 0xd},
2920Sstevel@tonic-gate {"dok_off_cycles", 0xe},
2930Sstevel@tonic-gate {"clear_pic", 0xf}
2940Sstevel@tonic-gate };
2953156Sgirish #endif
2960Sstevel@tonic-gate
2970Sstevel@tonic-gate /*
2985146Ssvemuri * Create the picN kstats for DRAM, JBUS and Zambezi events
2990Sstevel@tonic-gate */
3000Sstevel@tonic-gate void
niagara_kstat_init()3010Sstevel@tonic-gate niagara_kstat_init()
3020Sstevel@tonic-gate {
3030Sstevel@tonic-gate int i;
3040Sstevel@tonic-gate ni_ksinfo_t *ksinfop;
305*11304SJanie.Lu@Sun.COM #if defined(VFALLS_IMPL) || defined(KT_IMPL)
3065352Ssvemuri uint64_t stat, pcr;
3075352Ssvemuri #endif
3080Sstevel@tonic-gate
3090Sstevel@tonic-gate #ifdef DEBUG
3100Sstevel@tonic-gate if (ni_perf_debug)
3110Sstevel@tonic-gate printf("ni_kstat_init called\n");
3120Sstevel@tonic-gate #endif
3130Sstevel@tonic-gate
3140Sstevel@tonic-gate /*
3150Sstevel@tonic-gate * Create DRAM perf events kstat
3160Sstevel@tonic-gate */
317*11304SJanie.Lu@Sun.COM for (i = 0; i < DRAM_BANKS; i++) {
318*11304SJanie.Lu@Sun.COM #if defined(VFALLS_IMPL) || defined(KT_IMPL)
3194732Sdavemq /* check if this dram instance is enabled in the HW */
3205146Ssvemuri stat = hv_niagara_getperf(dram_perf_regs[i].pcr_reg, &pcr);
3215146Ssvemuri if ((stat != H_EINVAL) && (stat != H_ENOTSUPPORTED)) {
3224732Sdavemq #endif
3234732Sdavemq ksinfop = (ni_ksinfo_t *)kmem_zalloc(
3244732Sdavemq sizeof (ni_ksinfo_t), KM_NOSLEEP);
3250Sstevel@tonic-gate
3264732Sdavemq if (ksinfop == NULL) {
3274732Sdavemq cmn_err(CE_WARN,
3284732Sdavemq "%s: no space for dram kstat\n",
3294732Sdavemq cpu_module_name);
3304732Sdavemq break;
3314732Sdavemq }
3324732Sdavemq ksinfop->pic_no_evs =
3334732Sdavemq sizeof (niagara_dram_events) /
3344732Sdavemq sizeof (ni_kev_mask_t);
335*11304SJanie.Lu@Sun.COM ksinfop->pic_sel_shift[0] = DRAM_PIC0_SEL_SHIFT;
336*11304SJanie.Lu@Sun.COM ksinfop->pic_shift[0] = DRAM_PIC0_SHIFT;
337*11304SJanie.Lu@Sun.COM ksinfop->pic_mask[0] = DRAM_PIC0_MASK;
338*11304SJanie.Lu@Sun.COM ksinfop->pic_sel_shift[1] = DRAM_PIC1_SEL_SHIFT;
339*11304SJanie.Lu@Sun.COM ksinfop->pic_shift[1] = DRAM_PIC1_SHIFT;
340*11304SJanie.Lu@Sun.COM ksinfop->pic_mask[1] = DRAM_PIC1_MASK;
341*11304SJanie.Lu@Sun.COM ksinfop->pic_reg[0] = dram_perf_regs[i].pic_reg[0];
3424732Sdavemq ksinfop->pcr_reg = dram_perf_regs[i].pcr_reg;
3434732Sdavemq ni_dram_kstats[i] = ksinfop;
3440Sstevel@tonic-gate
3454732Sdavemq /* create basic pic event/mask pair (only once) */
3464732Sdavemq if (i == 0)
3474732Sdavemq ni_create_name_kstat("dram", ksinfop,
3480Sstevel@tonic-gate niagara_dram_events);
3490Sstevel@tonic-gate
3504732Sdavemq /* create counter kstats */
3514732Sdavemq ni_dram_kstats[i]->cntr_ksp = ni_create_cntr_kstat(
3524732Sdavemq "dram", i, ni_cntr_kstat_update, ksinfop);
353*11304SJanie.Lu@Sun.COM #if defined(VFALLS_IMPL) || defined(KT_IMPL)
3544732Sdavemq }
3554732Sdavemq #endif
3560Sstevel@tonic-gate }
3570Sstevel@tonic-gate
3585146Ssvemuri #ifdef VFALLS_IMPL
3595146Ssvemuri /*
3605146Ssvemuri * Create Zambezi LPU perf events kstat
3615146Ssvemuri */
3625146Ssvemuri for (i = 0; i < ZAMBEZI_LPU_COUNTERS; i++) {
3635146Ssvemuri /* check if this Zambezi LPU instance is enabled in the HW */
3645146Ssvemuri stat = hv_niagara_getperf(lpu_perf_regs[i].pcr_reg, &pcr);
3655146Ssvemuri if ((stat != H_EINVAL) && (stat != H_ENOTSUPPORTED)) {
3665146Ssvemuri ksinfop = (ni_ksinfo_t *)kmem_zalloc(
3675146Ssvemuri sizeof (ni_ksinfo_t), KM_NOSLEEP);
3685146Ssvemuri
3695146Ssvemuri if (ksinfop == NULL) {
3705146Ssvemuri cmn_err(CE_WARN,
3715146Ssvemuri "%s: no space for zambezi lpu kstat\n",
3725146Ssvemuri cpu_module_name);
3735146Ssvemuri break;
3745146Ssvemuri }
3755146Ssvemuri ksinfop->pic_no_evs =
3765146Ssvemuri sizeof (zam_lpu_perf_events) /
3775146Ssvemuri sizeof (ni_kev_mask_t);
3785146Ssvemuri ksinfop->pic_sel_shift[0] = ZAMBEZI_PIC0_SEL_SHIFT;
3795146Ssvemuri ksinfop->pic_reg[0] = lpu_perf_regs[i].pic_reg[0];
3805146Ssvemuri ksinfop->pic_sel_shift[1] = ZAMBEZI_PIC1_SEL_SHIFT;
3815146Ssvemuri ksinfop->pic_reg[1] = lpu_perf_regs[i].pic_reg[1];
3825146Ssvemuri ksinfop->pcr_reg = lpu_perf_regs[i].pcr_reg;
3835146Ssvemuri zam_lpu_kstats[i] = ksinfop;
3845146Ssvemuri
3855146Ssvemuri /* create basic pic event/mask pair (only once) */
3865146Ssvemuri if (i == 0)
3875146Ssvemuri ni_create_name_kstat("lpu", ksinfop,
3885146Ssvemuri zam_lpu_perf_events);
3895146Ssvemuri
3905146Ssvemuri /* create counter kstats */
3915146Ssvemuri zam_lpu_kstats[i]->cntr_ksp = ni_create_cntr_kstat(
3925146Ssvemuri "lpu", i, zam_cntr_kstat_update, ksinfop);
3935146Ssvemuri }
3945146Ssvemuri }
3955146Ssvemuri /*
3965146Ssvemuri * Create Zambezi GPD perf events kstat
3975146Ssvemuri */
3985146Ssvemuri for (i = 0; i < ZAMBEZI_GPD_COUNTERS; i++) {
3995146Ssvemuri /* check if this Zambezi GPD instance is enabled in the HW */
4005146Ssvemuri stat = hv_niagara_getperf(gpd_perf_regs[i].pcr_reg, &pcr);
4015146Ssvemuri if ((stat != H_EINVAL) && (stat != H_ENOTSUPPORTED)) {
4025146Ssvemuri ksinfop = (ni_ksinfo_t *)kmem_zalloc(
4035146Ssvemuri sizeof (ni_ksinfo_t), KM_NOSLEEP);
4045146Ssvemuri
4055146Ssvemuri if (ksinfop == NULL) {
4065146Ssvemuri cmn_err(CE_WARN,
4075146Ssvemuri "%s: no space for zambezi gpd kstat\n",
4085146Ssvemuri cpu_module_name);
4095146Ssvemuri break;
4105146Ssvemuri }
4115146Ssvemuri ksinfop->pic_no_evs =
4125146Ssvemuri sizeof (zam_gpd_perf_events) /
4135146Ssvemuri sizeof (ni_kev_mask_t);
4145146Ssvemuri ksinfop->pic_sel_shift[0] = ZAMBEZI_PIC0_SEL_SHIFT;
4155146Ssvemuri ksinfop->pic_reg[0] = gpd_perf_regs[i].pic_reg[0];
4165146Ssvemuri ksinfop->pic_sel_shift[1] = ZAMBEZI_PIC1_SEL_SHIFT;
4175146Ssvemuri ksinfop->pic_reg[1] = gpd_perf_regs[i].pic_reg[1];
4185146Ssvemuri ksinfop->pcr_reg = gpd_perf_regs[i].pcr_reg;
4195146Ssvemuri zam_gpd_kstats[i] = ksinfop;
4205146Ssvemuri
4215146Ssvemuri /* create basic pic event/mask pair (only once) */
4225146Ssvemuri if (i == 0)
4235146Ssvemuri ni_create_name_kstat("gpd", ksinfop,
4245146Ssvemuri zam_gpd_perf_events);
4255146Ssvemuri
4265146Ssvemuri /* create counter kstats */
4275146Ssvemuri zam_lpu_kstats[i]->cntr_ksp = ni_create_cntr_kstat(
4285146Ssvemuri "gpd", i, zam_cntr_kstat_update, ksinfop);
4295146Ssvemuri }
4305146Ssvemuri }
4315146Ssvemuri /*
4325146Ssvemuri * Create Zambezi ASU perf events kstat
4335146Ssvemuri */
4345146Ssvemuri for (i = 0; i < ZAMBEZI_ASU_COUNTERS; i++) {
4355146Ssvemuri /* check if this Zambezi ASU instance is enabled in the HW */
4365146Ssvemuri stat = hv_niagara_getperf(asu_perf_regs[i].pcr_reg, &pcr);
4375146Ssvemuri if ((stat != H_EINVAL) && (stat != H_ENOTSUPPORTED)) {
4385146Ssvemuri ksinfop = (ni_ksinfo_t *)kmem_zalloc(
4395146Ssvemuri sizeof (ni_ksinfo_t), KM_NOSLEEP);
4405146Ssvemuri
4415146Ssvemuri if (ksinfop == NULL) {
4425146Ssvemuri cmn_err(CE_WARN,
4435146Ssvemuri "%s: no space for zambezi asu kstat\n",
4445146Ssvemuri cpu_module_name);
4455146Ssvemuri break;
4465146Ssvemuri }
4475146Ssvemuri ksinfop->pic_no_evs =
4485146Ssvemuri sizeof (zam_asu_perf_events) /
4495146Ssvemuri sizeof (ni_kev_mask_t);
4505146Ssvemuri ksinfop->pic_sel_shift[0] = ZAMBEZI_PIC0_SEL_SHIFT;
4515146Ssvemuri ksinfop->pic_reg[0] = asu_perf_regs[i].pic_reg[0];
4525146Ssvemuri ksinfop->pic_sel_shift[1] = ZAMBEZI_PIC1_SEL_SHIFT;
4535146Ssvemuri ksinfop->pic_reg[1] = asu_perf_regs[i].pic_reg[1];
4545146Ssvemuri ksinfop->pcr_reg = asu_perf_regs[i].pcr_reg;
4555146Ssvemuri zam_asu_kstats[i] = ksinfop;
4565146Ssvemuri
4575146Ssvemuri /* create basic pic event/mask pair (only once) */
4585146Ssvemuri if (i == 0)
4595146Ssvemuri ni_create_name_kstat("asu", ksinfop,
4605146Ssvemuri zam_asu_perf_events);
4615146Ssvemuri
4625146Ssvemuri /* create counter kstats */
4635146Ssvemuri zam_lpu_kstats[i]->cntr_ksp = ni_create_cntr_kstat(
4645146Ssvemuri "asu", i, zam_cntr_kstat_update, ksinfop);
4655146Ssvemuri }
4665146Ssvemuri }
4675146Ssvemuri #endif
4685146Ssvemuri
4693156Sgirish #if defined(NIAGARA_IMPL)
4700Sstevel@tonic-gate /*
4710Sstevel@tonic-gate * Create JBUS perf events kstat
4720Sstevel@tonic-gate */
4730Sstevel@tonic-gate ni_jbus_kstat = (ni_ksinfo_t *)kmem_alloc(sizeof (ni_ksinfo_t),
4744732Sdavemq KM_NOSLEEP);
4750Sstevel@tonic-gate
4760Sstevel@tonic-gate if (ni_jbus_kstat == NULL) {
4770Sstevel@tonic-gate cmn_err(CE_WARN, "%s: no space for niagara jbus kstat\n",
4781592Sgirish cpu_module_name);
4790Sstevel@tonic-gate } else {
4800Sstevel@tonic-gate ni_jbus_kstat->pic_no_evs =
4814732Sdavemq sizeof (niagara_jbus_events) / sizeof (ni_kev_mask_t);
4820Sstevel@tonic-gate ni_jbus_kstat->pic_sel_shift[0] = NIAGARA_JBUS_PIC0_SEL_SHIFT;
4830Sstevel@tonic-gate ni_jbus_kstat->pic_shift[0] = NIAGARA_JBUS_PIC0_SHIFT;
4840Sstevel@tonic-gate ni_jbus_kstat->pic_mask[0] = NIAGARA_JBUS_PIC0_MASK;
4850Sstevel@tonic-gate ni_jbus_kstat->pic_sel_shift[1] = NIAGARA_JBUS_PIC1_SEL_SHIFT;
4860Sstevel@tonic-gate ni_jbus_kstat->pic_shift[1] = NIAGARA_JBUS_PIC1_SHIFT;
4870Sstevel@tonic-gate ni_jbus_kstat->pic_mask[1] = NIAGARA_JBUS_PIC1_MASK;
4885146Ssvemuri ni_jbus_kstat->pic_reg[0] = HV_NIAGARA_JBUS_COUNT;
4890Sstevel@tonic-gate ni_jbus_kstat->pcr_reg = HV_NIAGARA_JBUS_CTL;
4900Sstevel@tonic-gate ni_create_name_kstat("jbus", ni_jbus_kstat,
4910Sstevel@tonic-gate niagara_jbus_events);
4920Sstevel@tonic-gate ni_jbus_kstat->cntr_ksp = ni_create_cntr_kstat("jbus", 0,
4930Sstevel@tonic-gate ni_cntr_kstat_update, ni_jbus_kstat);
4940Sstevel@tonic-gate }
4953156Sgirish #endif
4960Sstevel@tonic-gate }
4970Sstevel@tonic-gate
4980Sstevel@tonic-gate void
niagara_kstat_fini()4990Sstevel@tonic-gate niagara_kstat_fini()
5000Sstevel@tonic-gate {
5010Sstevel@tonic-gate int i;
5020Sstevel@tonic-gate
5030Sstevel@tonic-gate #ifdef DEBUG
5040Sstevel@tonic-gate if (ni_perf_debug)
5050Sstevel@tonic-gate printf("ni_kstat_fini called\n");
5060Sstevel@tonic-gate #endif
5075146Ssvemuri
508*11304SJanie.Lu@Sun.COM for (i = 0; i < DRAM_BANKS; i++) {
5090Sstevel@tonic-gate if (ni_dram_kstats[i] != NULL) {
5100Sstevel@tonic-gate ni_delete_name_kstat(ni_dram_kstats[i]);
5110Sstevel@tonic-gate if (ni_dram_kstats[i]->cntr_ksp != NULL)
5120Sstevel@tonic-gate kstat_delete(ni_dram_kstats[i]->cntr_ksp);
5130Sstevel@tonic-gate kmem_free(ni_dram_kstats[i], sizeof (ni_ksinfo_t));
5140Sstevel@tonic-gate ni_dram_kstats[i] = NULL;
5150Sstevel@tonic-gate }
5160Sstevel@tonic-gate }
5170Sstevel@tonic-gate
5185146Ssvemuri #if defined(VFALLS_IMPL)
5195146Ssvemuri for (i = 0; i < ZAMBEZI_LPU_COUNTERS; i++) {
5205146Ssvemuri if (zam_lpu_kstats[i] != NULL) {
5215146Ssvemuri ni_delete_name_kstat(zam_lpu_kstats[i]);
5225146Ssvemuri if (zam_lpu_kstats[i]->cntr_ksp != NULL)
5235146Ssvemuri kstat_delete(zam_lpu_kstats[i]->cntr_ksp);
5245146Ssvemuri kmem_free(zam_lpu_kstats[i], sizeof (ni_ksinfo_t));
5255146Ssvemuri zam_lpu_kstats[i] = NULL;
5265146Ssvemuri }
5275146Ssvemuri }
5285146Ssvemuri
5295146Ssvemuri for (i = 0; i < ZAMBEZI_GPD_COUNTERS; i++) {
5305146Ssvemuri if (zam_gpd_kstats[i] != NULL) {
5315146Ssvemuri ni_delete_name_kstat(zam_gpd_kstats[i]);
5325146Ssvemuri if (zam_gpd_kstats[i]->cntr_ksp != NULL)
5335146Ssvemuri kstat_delete(zam_gpd_kstats[i]->cntr_ksp);
5345146Ssvemuri kmem_free(zam_gpd_kstats[i], sizeof (ni_ksinfo_t));
5355146Ssvemuri zam_gpd_kstats[i] = NULL;
5365146Ssvemuri }
5375146Ssvemuri }
5385146Ssvemuri
5395146Ssvemuri for (i = 0; i < ZAMBEZI_ASU_COUNTERS; i++) {
5405146Ssvemuri if (zam_asu_kstats[i] != NULL) {
5415146Ssvemuri ni_delete_name_kstat(zam_asu_kstats[i]);
5425146Ssvemuri if (zam_asu_kstats[i]->cntr_ksp != NULL)
5435146Ssvemuri kstat_delete(zam_asu_kstats[i]->cntr_ksp);
5445146Ssvemuri kmem_free(zam_asu_kstats[i], sizeof (ni_ksinfo_t));
5455146Ssvemuri zam_asu_kstats[i] = NULL;
5465146Ssvemuri }
5475146Ssvemuri }
5485146Ssvemuri #endif
5495146Ssvemuri
5503156Sgirish #if defined(NIAGARA_IMPL)
5510Sstevel@tonic-gate if (ni_jbus_kstat != NULL) {
5520Sstevel@tonic-gate ni_delete_name_kstat(ni_jbus_kstat);
5530Sstevel@tonic-gate if (ni_jbus_kstat->cntr_ksp != NULL)
5540Sstevel@tonic-gate kstat_delete(ni_jbus_kstat->cntr_ksp);
5550Sstevel@tonic-gate kmem_free(ni_jbus_kstat, sizeof (ni_ksinfo_t));
5560Sstevel@tonic-gate ni_jbus_kstat = NULL;
5570Sstevel@tonic-gate }
5583156Sgirish #endif
5590Sstevel@tonic-gate }
5600Sstevel@tonic-gate
5610Sstevel@tonic-gate static void
ni_create_name_kstat(char * name,ni_ksinfo_t * pp,ni_kev_mask_t * ev)5620Sstevel@tonic-gate ni_create_name_kstat(char *name, ni_ksinfo_t *pp, ni_kev_mask_t *ev)
5630Sstevel@tonic-gate {
5640Sstevel@tonic-gate int i;
5650Sstevel@tonic-gate
5660Sstevel@tonic-gate #ifdef DEBUG
5670Sstevel@tonic-gate if (ni_perf_debug > 1)
5680Sstevel@tonic-gate printf("ni_create_name_kstat: name: %s\n", name);
5690Sstevel@tonic-gate #endif
5700Sstevel@tonic-gate for (i = 0; i < NUM_OF_PICS; i++) {
5710Sstevel@tonic-gate pp->pic_name_ksp[i] = ni_create_picN_kstat(name,
5724732Sdavemq i, pp->pic_sel_shift[i], pp->pic_no_evs, ev);
5730Sstevel@tonic-gate
5740Sstevel@tonic-gate if (pp->pic_name_ksp[i] == NULL) {
5750Sstevel@tonic-gate cmn_err(CE_WARN, "%s: unable to create name kstat",
5761592Sgirish cpu_module_name);
5770Sstevel@tonic-gate }
5780Sstevel@tonic-gate }
5790Sstevel@tonic-gate }
5800Sstevel@tonic-gate
5810Sstevel@tonic-gate static void
ni_delete_name_kstat(ni_ksinfo_t * pp)5820Sstevel@tonic-gate ni_delete_name_kstat(ni_ksinfo_t *pp)
5830Sstevel@tonic-gate {
5840Sstevel@tonic-gate int i;
5850Sstevel@tonic-gate
5860Sstevel@tonic-gate if (pp != NULL) {
5870Sstevel@tonic-gate for (i = 0; i < NUM_OF_PICS; i++) {
5880Sstevel@tonic-gate if (pp->pic_name_ksp[i] != NULL)
5890Sstevel@tonic-gate kstat_delete(pp->pic_name_ksp[i]);
5900Sstevel@tonic-gate }
5910Sstevel@tonic-gate }
5920Sstevel@tonic-gate }
5930Sstevel@tonic-gate
5940Sstevel@tonic-gate /*
5950Sstevel@tonic-gate * Create the picN kstat. Returns a pointer to the
5960Sstevel@tonic-gate * kstat which the driver must store to allow it
5970Sstevel@tonic-gate * to be deleted when necessary.
5980Sstevel@tonic-gate */
5990Sstevel@tonic-gate static kstat_t *
ni_create_picN_kstat(char * mod_name,int pic,int pic_sel_shift,int num_ev,ni_kev_mask_t * ev_array)6000Sstevel@tonic-gate ni_create_picN_kstat(char *mod_name, int pic, int pic_sel_shift,
6010Sstevel@tonic-gate int num_ev, ni_kev_mask_t *ev_array)
6020Sstevel@tonic-gate {
6030Sstevel@tonic-gate struct kstat_named *pic_named_data;
6040Sstevel@tonic-gate int inst = 0;
6050Sstevel@tonic-gate int event;
6060Sstevel@tonic-gate char pic_name[30];
6070Sstevel@tonic-gate kstat_t *picN_ksp = NULL;
6080Sstevel@tonic-gate
6090Sstevel@tonic-gate (void) sprintf(pic_name, "pic%d", pic);
6100Sstevel@tonic-gate if ((picN_ksp = kstat_create(mod_name, inst, pic_name,
6110Sstevel@tonic-gate "bus", KSTAT_TYPE_NAMED, num_ev, NULL)) == NULL) {
6120Sstevel@tonic-gate cmn_err(CE_WARN, "%s %s : kstat create failed",
6134732Sdavemq mod_name, pic_name);
6140Sstevel@tonic-gate
6150Sstevel@tonic-gate /*
6160Sstevel@tonic-gate * It is up to the calling function to delete any kstats
6170Sstevel@tonic-gate * that may have been created already. We just
6180Sstevel@tonic-gate * return NULL to indicate an error has occured.
6190Sstevel@tonic-gate */
6200Sstevel@tonic-gate return (NULL);
6210Sstevel@tonic-gate }
6220Sstevel@tonic-gate
6230Sstevel@tonic-gate pic_named_data = (struct kstat_named *)
6240Sstevel@tonic-gate picN_ksp->ks_data;
6250Sstevel@tonic-gate
6260Sstevel@tonic-gate /*
6270Sstevel@tonic-gate * Write event names and their associated pcr masks. The
6280Sstevel@tonic-gate * last entry in the array (clear_pic) is added seperately
6290Sstevel@tonic-gate * below as the pic value must be inverted.
6300Sstevel@tonic-gate */
6310Sstevel@tonic-gate for (event = 0; event < num_ev - 1; event++) {
6320Sstevel@tonic-gate pic_named_data[event].value.ui64 =
6334732Sdavemq (ev_array[event].pcr_mask << pic_sel_shift);
6340Sstevel@tonic-gate
6350Sstevel@tonic-gate kstat_named_init(&pic_named_data[event],
6364732Sdavemq ev_array[event].event_name,
6374732Sdavemq KSTAT_DATA_UINT64);
6380Sstevel@tonic-gate }
6390Sstevel@tonic-gate
6400Sstevel@tonic-gate /*
6410Sstevel@tonic-gate * add the clear_pic entry.
6420Sstevel@tonic-gate */
6430Sstevel@tonic-gate pic_named_data[event].value.ui64 =
6444732Sdavemq (uint64_t)~(ev_array[event].pcr_mask << pic_sel_shift);
6450Sstevel@tonic-gate
6460Sstevel@tonic-gate kstat_named_init(&pic_named_data[event], ev_array[event].event_name,
6470Sstevel@tonic-gate KSTAT_DATA_UINT64);
6480Sstevel@tonic-gate
6490Sstevel@tonic-gate kstat_install(picN_ksp);
6500Sstevel@tonic-gate
6510Sstevel@tonic-gate return (picN_ksp);
6520Sstevel@tonic-gate }
6530Sstevel@tonic-gate
6540Sstevel@tonic-gate /*
6550Sstevel@tonic-gate * Create the "counters" kstat.
6560Sstevel@tonic-gate */
6570Sstevel@tonic-gate static kstat_t *
ni_create_cntr_kstat(char * name,int instance,int (* update)(kstat_t *,int),void * ksinfop)6580Sstevel@tonic-gate ni_create_cntr_kstat(char *name, int instance, int (*update)(kstat_t *, int),
6590Sstevel@tonic-gate void *ksinfop)
6600Sstevel@tonic-gate {
6610Sstevel@tonic-gate struct kstat *counters_ksp;
6620Sstevel@tonic-gate struct kstat_named *counters_named_data;
6630Sstevel@tonic-gate char pic_str[10];
6640Sstevel@tonic-gate int i;
6650Sstevel@tonic-gate int num_pics = NUM_OF_PICS;
6660Sstevel@tonic-gate
6670Sstevel@tonic-gate #ifdef DEBUG
6680Sstevel@tonic-gate if (ni_perf_debug > 1)
6690Sstevel@tonic-gate printf("ni_create_cntr_kstat: name: %s instance: %d\n",
6700Sstevel@tonic-gate name, instance);
6710Sstevel@tonic-gate #endif
6720Sstevel@tonic-gate
6730Sstevel@tonic-gate /*
6740Sstevel@tonic-gate * Size of kstat is num_pics + 1 as it
6750Sstevel@tonic-gate * also contains the %pcr
6760Sstevel@tonic-gate */
6770Sstevel@tonic-gate if ((counters_ksp = kstat_create(name, instance, "counters", "bus",
6780Sstevel@tonic-gate KSTAT_TYPE_NAMED, num_pics + 1, KSTAT_FLAG_WRITABLE)) == NULL) {
6790Sstevel@tonic-gate cmn_err(CE_WARN,
6801592Sgirish "%s: kstat_create for %s%d failed", cpu_module_name,
6810Sstevel@tonic-gate name, instance);
6820Sstevel@tonic-gate return (NULL);
6830Sstevel@tonic-gate }
6840Sstevel@tonic-gate
6850Sstevel@tonic-gate counters_named_data = (struct kstat_named *)(counters_ksp->ks_data);
6860Sstevel@tonic-gate
6870Sstevel@tonic-gate /*
6880Sstevel@tonic-gate * Iinitialize the named kstats
6890Sstevel@tonic-gate */
6900Sstevel@tonic-gate kstat_named_init(&counters_named_data[0], "pcr", KSTAT_DATA_UINT64);
6910Sstevel@tonic-gate
6920Sstevel@tonic-gate for (i = 0; i < num_pics; i++) {
6930Sstevel@tonic-gate (void) sprintf(pic_str, "pic%d", i);
6940Sstevel@tonic-gate
6950Sstevel@tonic-gate kstat_named_init(&counters_named_data[i+1], pic_str,
6960Sstevel@tonic-gate KSTAT_DATA_UINT64);
6970Sstevel@tonic-gate }
6980Sstevel@tonic-gate
6990Sstevel@tonic-gate /*
7000Sstevel@tonic-gate * Store the register offset's in the kstat's
7010Sstevel@tonic-gate * private field so that they are available
7020Sstevel@tonic-gate * to the update function.
7030Sstevel@tonic-gate */
7040Sstevel@tonic-gate counters_ksp->ks_private = (void *)ksinfop;
7050Sstevel@tonic-gate counters_ksp->ks_update = update;
7060Sstevel@tonic-gate
7070Sstevel@tonic-gate kstat_install(counters_ksp);
7080Sstevel@tonic-gate
7090Sstevel@tonic-gate return (counters_ksp);
7100Sstevel@tonic-gate }
7110Sstevel@tonic-gate
7125146Ssvemuri #if defined(VFALLS_IMPL)
7135146Ssvemuri /*
7145146Ssvemuri * zambezi kstat update function. Handles reads/writes
7155146Ssvemuri * from/to kstat.
7165146Ssvemuri */
7175146Ssvemuri static int
zam_cntr_kstat_update(kstat_t * ksp,int rw)7185146Ssvemuri zam_cntr_kstat_update(kstat_t *ksp, int rw)
7195146Ssvemuri {
7205146Ssvemuri struct kstat_named *data_p;
7215146Ssvemuri ni_ksinfo_t *ksinfop = ksp->ks_private;
7225146Ssvemuri uint64_t pic0, pic1, pcr;
7235146Ssvemuri int stat = 0;
7245146Ssvemuri uint64_t pic0_stat = 0, pic1_stat = 0, pcr_stat = 0;
7255146Ssvemuri
7265146Ssvemuri data_p = (struct kstat_named *)ksp->ks_data;
7275146Ssvemuri
7285146Ssvemuri if (rw == KSTAT_WRITE) {
7295146Ssvemuri #ifdef DEBUG
7305146Ssvemuri if (ni_perf_debug)
7315146Ssvemuri printf("zam_cntr_kstat_update: wr pcr-%d: %lx\n",
7325146Ssvemuri ksinfop->pcr_reg, data_p[0].value.ui64);
7335146Ssvemuri #endif
7345146Ssvemuri if (hv_niagara_setperf(ksinfop->pcr_reg, data_p[0].value.ui64))
7355146Ssvemuri stat = EACCES;
7365146Ssvemuri } else {
7375146Ssvemuri do {
7385146Ssvemuri pic0_stat = hv_niagara_getperf(ksinfop->pic_reg[0],
7395146Ssvemuri &pic0);
7405146Ssvemuri } while (pic0_stat == H_EWOULDBLOCK);
7415146Ssvemuri do {
7425146Ssvemuri pic1_stat = hv_niagara_getperf(ksinfop->pic_reg[1],
7435146Ssvemuri &pic1);
7445146Ssvemuri } while (pic1_stat == H_EWOULDBLOCK);
7455146Ssvemuri do {
7465146Ssvemuri pcr_stat = hv_niagara_getperf(ksinfop->pcr_reg,
7475146Ssvemuri &pcr);
7485146Ssvemuri } while (pcr_stat == H_EWOULDBLOCK);
7495146Ssvemuri if (pic0_stat != 0 || pic1_stat != 0 || pcr_stat != 0)
7505146Ssvemuri stat = EACCES;
7515146Ssvemuri else {
7525146Ssvemuri data_p[0].value.ui64 = pcr;
7535146Ssvemuri data_p[1].value.ui64 = pic0;
7545146Ssvemuri data_p[2].value.ui64 = pic1;
7555146Ssvemuri }
7565146Ssvemuri #ifdef DEBUG
7575146Ssvemuri if (ni_perf_debug)
7585146Ssvemuri printf("zam_cntr_kstat_update: rd pcr%d: %lx "
7595146Ssvemuri "pic0: %16lx pic1: %16lx\n",
7605146Ssvemuri ksinfop->pcr_reg, pcr,
7615146Ssvemuri data_p[1].value.ui64, data_p[2].value.ui64);
7625146Ssvemuri #endif
7635146Ssvemuri }
7645146Ssvemuri
7655146Ssvemuri return (stat);
7665146Ssvemuri }
7675146Ssvemuri #endif
7685146Ssvemuri
7690Sstevel@tonic-gate /*
7700Sstevel@tonic-gate * kstat update function. Handles reads/writes
7710Sstevel@tonic-gate * from/to kstat.
7720Sstevel@tonic-gate */
7730Sstevel@tonic-gate static int
ni_cntr_kstat_update(kstat_t * ksp,int rw)7740Sstevel@tonic-gate ni_cntr_kstat_update(kstat_t *ksp, int rw)
7750Sstevel@tonic-gate {
7760Sstevel@tonic-gate struct kstat_named *data_p;
7770Sstevel@tonic-gate ni_ksinfo_t *ksinfop = ksp->ks_private;
7780Sstevel@tonic-gate uint64_t pic, pcr;
7790Sstevel@tonic-gate int stat = 0;
7800Sstevel@tonic-gate uint32_t pic0, pic1;
7810Sstevel@tonic-gate
7820Sstevel@tonic-gate data_p = (struct kstat_named *)ksp->ks_data;
7830Sstevel@tonic-gate
7840Sstevel@tonic-gate if (rw == KSTAT_WRITE) {
7850Sstevel@tonic-gate #ifdef DEBUG
7860Sstevel@tonic-gate if (ni_perf_debug)
787911Siskreen printf("ni_cntr_kstat_update: wr pcr-%d: %lx\n",
7880Sstevel@tonic-gate ksinfop->pcr_reg, data_p[0].value.ui64);
7890Sstevel@tonic-gate #endif
7900Sstevel@tonic-gate if (hv_niagara_setperf(ksinfop->pcr_reg, data_p[0].value.ui64))
7910Sstevel@tonic-gate stat = EACCES;
7920Sstevel@tonic-gate } else {
7935146Ssvemuri if (hv_niagara_getperf(ksinfop->pic_reg[0], &pic) != 0 ||
7940Sstevel@tonic-gate hv_niagara_getperf(ksinfop->pcr_reg, &pcr) != 0)
7950Sstevel@tonic-gate stat = EACCES;
7960Sstevel@tonic-gate else {
7970Sstevel@tonic-gate data_p[0].value.ui64 = pcr;
7980Sstevel@tonic-gate
7990Sstevel@tonic-gate /*
8000Sstevel@tonic-gate * Generate a 32-bit PIC0 value by detecting overflow
8010Sstevel@tonic-gate */
8020Sstevel@tonic-gate pic0 = (uint32_t)((pic >> ksinfop->pic_shift[0]) &
8030Sstevel@tonic-gate ksinfop->pic_mask[0]);
8040Sstevel@tonic-gate if (pic0 < ksinfop->pic_last_val[0])
8050Sstevel@tonic-gate ksinfop->pic_overflow[0]++;
8060Sstevel@tonic-gate ksinfop->pic_last_val[0] = pic0;
8070Sstevel@tonic-gate pic0 += (ksinfop->pic_overflow[0] & 1) << 31;
8080Sstevel@tonic-gate data_p[1].value.ui64 = (uint64_t)pic0;
8090Sstevel@tonic-gate
8100Sstevel@tonic-gate /*
8110Sstevel@tonic-gate * Generate a 32-bit PIC1 value by detecting overflow
8120Sstevel@tonic-gate */
8130Sstevel@tonic-gate pic1 = (uint32_t)((pic >> ksinfop->pic_shift[1]) &
8140Sstevel@tonic-gate ksinfop->pic_mask[1]);
8150Sstevel@tonic-gate if (pic1 < ksinfop->pic_last_val[1])
8160Sstevel@tonic-gate ksinfop->pic_overflow[1]++;
8170Sstevel@tonic-gate ksinfop->pic_last_val[1] = pic1;
8180Sstevel@tonic-gate pic1 += (ksinfop->pic_overflow[1] & 1) << 31;
8190Sstevel@tonic-gate data_p[2].value.ui64 = (uint64_t)pic1;
8200Sstevel@tonic-gate }
8210Sstevel@tonic-gate #ifdef DEBUG
8220Sstevel@tonic-gate if (ni_perf_debug)
8230Sstevel@tonic-gate printf("ni_cntr_kstat_update: rd pcr%d: %lx "
8240Sstevel@tonic-gate "pic%d: %16lx pic0: %8lx pic1: %8lx\n",
8255146Ssvemuri ksinfop->pcr_reg, pcr, ksinfop->pic_reg[0], pic,
8260Sstevel@tonic-gate data_p[1].value.ui64, data_p[2].value.ui64);
8270Sstevel@tonic-gate #endif
8280Sstevel@tonic-gate }
8290Sstevel@tonic-gate return (stat);
8300Sstevel@tonic-gate }
831