Home | History | Annotate | Download | only in cpu
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 /*
     22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     23  * Use is subject to license terms.
     24  */
     25 
     26 #include <sys/types.h>
     27 #include <sys/async.h>
     28 #include <sys/sunddi.h>
     29 #include <sys/sunndi.h>
     30 #include <sys/ddi_impldefs.h>
     31 #include <sys/machsystm.h>
     32 #include <sys/hypervisor_api.h>
     33 #include <sys/kstat.h>
     34 #if defined(NIAGARA_IMPL)
     35 #include <sys/niagararegs.h>
     36 #elif defined(NIAGARA2_IMPL) || defined(VFALLS_IMPL) || defined(KT_IMPL)
     37 #include <sys/niagara2regs.h>
     38 #endif
     39 
     40 extern char cpu_module_name[];
     41 
     42 /*
     43  * Data structure used to build array of event-names and pcr-mask values
     44  */
     45 typedef struct ni_kev_mask {
     46 	char		*event_name;
     47 	uint64_t	pcr_mask;
     48 } ni_kev_mask_t;
     49 
     50 /*
     51  * Kstat data structure for DRAM and JBUS performance counters
     52  *
     53  * Note that these performance counters are only 31 bits wide. Since
     54  * the "busstat" command assumes a 32-bit counter, we emulate a 32-bit
     55  * counter by detecting overflow on read of these performance counters
     56  * and using the least significant bit of the overflow count as the
     57  * most significant bit (i.e. bit# 31) of the DRAM and JBUS performance
     58  * counters.
     59  */
     60 #define	NUM_OF_PICS	2
     61 #define	NUM_OF_PIC_REGS	1
     62 
     63 typedef struct ni_ksinfo {
     64 	uint8_t		pic_no_evs;			/* number of events */
     65 	uint8_t		pic_sel_shift[NUM_OF_PICS];
     66 	uint8_t		pic_shift[NUM_OF_PICS];
     67 	uint64_t	pic_mask[NUM_OF_PICS];
     68 	kstat_t		*pic_name_ksp[NUM_OF_PICS];
     69 	kstat_t		*cntr_ksp;
     70 	uint32_t	pic_reg[NUM_OF_PIC_REGS];
     71 	uint32_t	pcr_reg;
     72 	uint32_t	pic_overflow[NUM_OF_PICS];	/* overflow count */
     73 	uint32_t	pic_last_val[NUM_OF_PICS];	/* last PIC value */
     74 } ni_ksinfo_t;
     75 
     76 static ni_ksinfo_t	*ni_dram_kstats[DRAM_BANKS];
     77 
     78 #if defined(NIAGARA_IMPL)
     79 static ni_ksinfo_t	*ni_jbus_kstat;
     80 #endif
     81 
     82 typedef struct ni_perf_regs {
     83 	uint32_t	pcr_reg;
     84 	uint32_t	pic_reg[NUM_OF_PIC_REGS];
     85 } ni_perf_regs_t;
     86 
     87 static ni_perf_regs_t dram_perf_regs[] = {
     88 #if defined(NIAGARA_IMPL) || defined(NIAGARA2_IMPL)
     89 	{HV_DRAM_CTL0, HV_DRAM_COUNT0},
     90 	{HV_DRAM_CTL1, HV_DRAM_COUNT1},
     91 	{HV_DRAM_CTL2, HV_DRAM_COUNT2},
     92 	{HV_DRAM_CTL3, HV_DRAM_COUNT3},
     93 #elif defined(VFALLS_IMPL) || defined(KT_IMPL)
     94 	{HV_DRAM_CTL0, HV_DRAM_COUNT0},
     95 	{HV_DRAM_CTL1, HV_DRAM_COUNT1},
     96 	{HV_DRAM_CTL2, HV_DRAM_COUNT2},
     97 	{HV_DRAM_CTL3, HV_DRAM_COUNT3},
     98 	{HV_DRAM_CTL4, HV_DRAM_COUNT4},
     99 	{HV_DRAM_CTL5, HV_DRAM_COUNT5},
    100 	{HV_DRAM_CTL6, HV_DRAM_COUNT6},
    101 	{HV_DRAM_CTL7, HV_DRAM_COUNT7}
    102 #endif
    103 };
    104 
    105 #ifdef VFALLS_IMPL
    106 /*
    107  * Kstat data structure for Zambezi performance counters
    108  * These performance counters are 64 bits wide.
    109  */
    110 static ni_ksinfo_t	*zam_lpu_kstats[ZAMBEZI_LPU_COUNTERS];
    111 static ni_ksinfo_t	*zam_gpd_kstats[ZAMBEZI_GPD_COUNTERS];
    112 static ni_ksinfo_t	*zam_asu_kstats[ZAMBEZI_ASU_COUNTERS];
    113 
    114 typedef struct zam_perf_regs {
    115 	uint32_t	pcr_reg;
    116 	uint32_t	pic_reg[NUM_OF_PICS];
    117 } zam_perf_regs_t;
    118 
    119 static zam_perf_regs_t lpu_perf_regs[] = {
    120 	{HV_ZAM0_LPU_A_PCR, HV_ZAM0_LPU_A_PIC0, HV_ZAM0_LPU_A_PIC1},
    121 	{HV_ZAM0_LPU_B_PCR, HV_ZAM0_LPU_B_PIC0, HV_ZAM0_LPU_B_PIC1},
    122 	{HV_ZAM0_LPU_C_PCR, HV_ZAM0_LPU_C_PIC0, HV_ZAM0_LPU_C_PIC1},
    123 	{HV_ZAM0_LPU_D_PCR, HV_ZAM0_LPU_D_PIC0, HV_ZAM0_LPU_D_PIC1},
    124 
    125 	{HV_ZAM1_LPU_A_PCR, HV_ZAM1_LPU_A_PIC0, HV_ZAM1_LPU_A_PIC1},
    126 	{HV_ZAM1_LPU_B_PCR, HV_ZAM1_LPU_B_PIC0, HV_ZAM1_LPU_B_PIC1},
    127 	{HV_ZAM1_LPU_C_PCR, HV_ZAM1_LPU_C_PIC0, HV_ZAM1_LPU_C_PIC1},
    128 	{HV_ZAM1_LPU_D_PCR, HV_ZAM1_LPU_D_PIC0, HV_ZAM1_LPU_D_PIC1},
    129 
    130 	{HV_ZAM2_LPU_A_PCR, HV_ZAM2_LPU_A_PIC0, HV_ZAM2_LPU_A_PIC1},
    131 	{HV_ZAM2_LPU_B_PCR, HV_ZAM2_LPU_B_PIC0, HV_ZAM2_LPU_B_PIC1},
    132 	{HV_ZAM2_LPU_C_PCR, HV_ZAM2_LPU_C_PIC0, HV_ZAM2_LPU_C_PIC1},
    133 	{HV_ZAM2_LPU_D_PCR, HV_ZAM2_LPU_D_PIC0, HV_ZAM2_LPU_D_PIC1},
    134 
    135 	{HV_ZAM3_LPU_A_PCR, HV_ZAM3_LPU_A_PIC0, HV_ZAM3_LPU_A_PIC1},
    136 	{HV_ZAM3_LPU_B_PCR, HV_ZAM3_LPU_B_PIC0, HV_ZAM3_LPU_B_PIC1},
    137 	{HV_ZAM3_LPU_C_PCR, HV_ZAM3_LPU_C_PIC0, HV_ZAM3_LPU_C_PIC1},
    138 	{HV_ZAM3_LPU_D_PCR, HV_ZAM3_LPU_D_PIC0, HV_ZAM3_LPU_D_PIC1}
    139 };
    140 
    141 static zam_perf_regs_t gpd_perf_regs[] = {
    142 	{HV_ZAM0_GPD_PCR, HV_ZAM0_GPD_PIC0, HV_ZAM0_GPD_PIC1},
    143 	{HV_ZAM1_GPD_PCR, HV_ZAM1_GPD_PIC0, HV_ZAM1_GPD_PIC1},
    144 	{HV_ZAM2_GPD_PCR, HV_ZAM2_GPD_PIC0, HV_ZAM2_GPD_PIC1},
    145 	{HV_ZAM3_GPD_PCR, HV_ZAM3_GPD_PIC0, HV_ZAM3_GPD_PIC1}
    146 };
    147 
    148 static zam_perf_regs_t asu_perf_regs[] = {
    149 	{HV_ZAM0_ASU_PCR, HV_ZAM0_ASU_PIC0, HV_ZAM0_ASU_PIC1},
    150 	{HV_ZAM1_ASU_PCR, HV_ZAM1_ASU_PIC0, HV_ZAM1_ASU_PIC1},
    151 	{HV_ZAM2_ASU_PCR, HV_ZAM2_ASU_PIC0, HV_ZAM2_ASU_PIC1},
    152 	{HV_ZAM3_ASU_PCR, HV_ZAM3_ASU_PIC0, HV_ZAM3_ASU_PIC1}
    153 };
    154 
    155 static int zam_cntr_kstat_update(kstat_t *, int);
    156 #endif
    157 
    158 static void ni_create_name_kstat(char *, ni_ksinfo_t *, ni_kev_mask_t *);
    159 static void ni_delete_name_kstat(ni_ksinfo_t *);
    160 
    161 static kstat_t *ni_create_cntr_kstat(char *, int,
    162 	int (*update)(kstat_t *, int), void *);
    163 
    164 static int ni_cntr_kstat_update(kstat_t *, int);
    165 
    166 static kstat_t *ni_create_picN_kstat(char *, int, int, int,
    167 	ni_kev_mask_t *);
    168 
    169 #ifdef DEBUG
    170 static int	ni_perf_debug;
    171 #endif
    172 
    173 /*
    174  * Niagara, Niagara2 and VFalls DRAM Performance Events
    175  */
    176 static ni_kev_mask_t
    177 niagara_dram_events[] = {
    178 #if defined(NIAGARA_IMPL) || defined(NIAGARA2_IMPL) || defined(VFALLS_IMPL)
    179 	{"mem_reads",		0x0},
    180 	{"mem_writes",		0x1},
    181 	{"mem_read_write",	0x2},
    182 #elif defined(KT_IMPL)
    183 	{"remote_reads",	0x0},
    184 	{"remote_writes",	0x1},
    185 	{"remote_read_write",	0x2},
    186 #endif
    187 #if defined(NIAGARA_IMPL) || defined(KT_IMPL)
    188 	{"bank_busy_stalls",	0x3},
    189 #endif
    190 	{"rd_queue_latency",	0x4},
    191 	{"wr_queue_latency",	0x5},
    192 	{"rw_queue_latency",	0x6},
    193 #if defined(NIAGARA_IMPL) || defined(NIAGARA2_IMPL) || defined(VFALLS_IMPL)
    194 	{"wb_buf_hits",		0x7},
    195 #elif defined(KT_IMPL)
    196 	{"write_queue_drain",	0x7},
    197 	{"read_all_channels",	0x8},
    198 	{"write_starved",	0x9},
    199 	{"write_all_channels",	0xa},
    200 	{"read_write_channel0",	0xb},
    201 	{"read_write_channel1",	0xc},
    202 #endif
    203 	{"clear_pic",		0xf}
    204 };
    205 
    206 #if defined(VFALLS_IMPL)
    207 /*
    208  * Zambezi Performance Events
    209  */
    210 static ni_kev_mask_t
    211 zam_lpu_perf_events[] = {
    212 	{"none",		0x0},
    213 	{"clock_cycles",	0x1},
    214 	{"cycles_c2c_portX",	0x2},
    215 	{"cycles_mem_portX",	0x3},
    216 	{"cycles_WB_portX",	0x4},
    217 	{"cycles_NC_portX",	0x5},
    218 	{"cycles_c2c_portY",	0x6},
    219 	{"cycles_mem_portY",	0x7},
    220 	{"cycles_WB_portY",	0x8},
    221 	{"cycles_NC_portY",	0x9},
    222 	{"cycles_c2c_portZ",	0xa},
    223 	{"cycles_mem_portZ",	0xb},
    224 	{"cycles_WB_portZ",	0xc},
    225 	{"cycles_NC_portZ",	0xd},
    226 	{"cycles_TID_WB",	0xe},
    227 	{"cycles_TID_INV",	0xf},
    228 	{"cycles_TID_RTD",	0x10},
    229 	{"cycles_TID_RTO",	0x11},
    230 	{"cycles_TID_RTS",	0x12},
    231 	{"cycles_IO_WRM",	0x13},
    232 	{"cycles_IO_RD",	0x14},
    233 	{"cycles_WB_egress",	0x15},
    234 	{"cycles_INV_egress",	0x16},
    235 	{"cycles_RTO_egress",	0x17},
    236 	{"cycles_RTD_egress",	0x18},
    237 	{"cycles_RTS_egress",	0x19},
    238 	{"cycles_no_WB",	0x1a},
    239 	{"cycles_no_read/inv",	0x1b},
    240 	{"cycles_HIT_M",	0x1c},
    241 	{"cycles_HIT_O",	0x1d},
    242 	{"cycles_HIT_S",	0x1e},
    243 	{"cycles_WB_HIT",	0x1f},
    244 	{"cycles_MISS",		0x20},
    245 	{"cycles_READ_or_INV",	0x21},
    246 	{"cycles_WB",		0x22},
    247 	{"cycles_NDR",		0x23},
    248 	{"cycles_cache_miss",	0x24},
    249 	{"cycles_cache_hit",	0x25},
    250 	{"cycles_CRC_errors",	0x26},
    251 	{"cycles_replys_sent",	0x27},
    252 	{"cycles_replys_recev",	0x28},
    253 	{"cycles_link_retrain",	0x29},
    254 	{"clear_pic",		0xff}
    255 };
    256 
    257 static ni_kev_mask_t
    258 zam_gpd_perf_events[] = {
    259 	{"none",		0x0},
    260 	{"clock_cycles",	0x1},
    261 	{"clear_pic",		0xf}
    262 };
    263 
    264 static ni_kev_mask_t
    265 zam_asu_perf_events[] = {
    266 	{"none",		0x0},
    267 	{"clock_cycles",	0x1},
    268 	{"asu_in_pck",		0x2},
    269 	{"asu_out_pck",		0x3},
    270 	{"asu_CAM_hit",		0x4},
    271 	{"asu_wakeup",		0x5},
    272 	{"clear_pic",		0xf}
    273 };
    274 #endif
    275 
    276 #if defined(NIAGARA_IMPL)
    277 /*
    278  * Niagara JBUS Performance Events
    279  */
    280 static ni_kev_mask_t
    281 niagara_jbus_events[] = {
    282 	{"jbus_cycles",		0x1},
    283 	{"dma_reads",		0x2},
    284 	{"dma_read_latency",	0x3},
    285 	{"dma_writes",		0x4},
    286 	{"dma_write8",		0x5},
    287 	{"ordering_waits",	0x6},
    288 	{"pio_reads",		0x8},
    289 	{"pio_read_latency",	0x9},
    290 	{"aok_dok_off_cycles",	0xc},
    291 	{"aok_off_cycles",	0xd},
    292 	{"dok_off_cycles",	0xe},
    293 	{"clear_pic",		0xf}
    294 };
    295 #endif
    296 
    297 /*
    298  * Create the picN kstats for DRAM, JBUS and Zambezi events
    299  */
    300 void
    301 niagara_kstat_init()
    302 {
    303 	int i;
    304 	ni_ksinfo_t *ksinfop;
    305 #if defined(VFALLS_IMPL) || defined(KT_IMPL)
    306 	uint64_t stat, pcr;
    307 #endif
    308 
    309 #ifdef DEBUG
    310 	if (ni_perf_debug)
    311 		printf("ni_kstat_init called\n");
    312 #endif
    313 
    314 	/*
    315 	 * Create DRAM perf events kstat
    316 	 */
    317 	for (i = 0; i < DRAM_BANKS; i++) {
    318 #if defined(VFALLS_IMPL) || defined(KT_IMPL)
    319 		/* check if this dram instance is enabled in the HW */
    320 		stat = hv_niagara_getperf(dram_perf_regs[i].pcr_reg, &pcr);
    321 		if ((stat != H_EINVAL) && (stat != H_ENOTSUPPORTED)) {
    322 #endif
    323 			ksinfop = (ni_ksinfo_t *)kmem_zalloc(
    324 			    sizeof (ni_ksinfo_t), KM_NOSLEEP);
    325 
    326 			if (ksinfop == NULL) {
    327 				cmn_err(CE_WARN,
    328 				    "%s: no space for dram kstat\n",
    329 				    cpu_module_name);
    330 				break;
    331 			}
    332 			ksinfop->pic_no_evs =
    333 			    sizeof (niagara_dram_events) /
    334 			    sizeof (ni_kev_mask_t);
    335 			ksinfop->pic_sel_shift[0] = DRAM_PIC0_SEL_SHIFT;
    336 			ksinfop->pic_shift[0] = DRAM_PIC0_SHIFT;
    337 			ksinfop->pic_mask[0] = DRAM_PIC0_MASK;
    338 			ksinfop->pic_sel_shift[1] = DRAM_PIC1_SEL_SHIFT;
    339 			ksinfop->pic_shift[1] = DRAM_PIC1_SHIFT;
    340 			ksinfop->pic_mask[1] = DRAM_PIC1_MASK;
    341 			ksinfop->pic_reg[0] = dram_perf_regs[i].pic_reg[0];
    342 			ksinfop->pcr_reg = dram_perf_regs[i].pcr_reg;
    343 			ni_dram_kstats[i] = ksinfop;
    344 
    345 			/* create basic pic event/mask pair (only once) */
    346 			if (i == 0)
    347 				ni_create_name_kstat("dram", ksinfop,
    348 				    niagara_dram_events);
    349 
    350 			/* create counter kstats */
    351 			ni_dram_kstats[i]->cntr_ksp = ni_create_cntr_kstat(
    352 			    "dram", i, ni_cntr_kstat_update, ksinfop);
    353 #if defined(VFALLS_IMPL) || defined(KT_IMPL)
    354 		}
    355 #endif
    356 	}
    357 
    358 #ifdef VFALLS_IMPL
    359 	/*
    360 	 * Create Zambezi LPU perf events kstat
    361 	 */
    362 	for (i = 0; i < ZAMBEZI_LPU_COUNTERS; i++) {
    363 		/* check if this Zambezi LPU instance is enabled in the HW */
    364 		stat = hv_niagara_getperf(lpu_perf_regs[i].pcr_reg, &pcr);
    365 		if ((stat != H_EINVAL) && (stat != H_ENOTSUPPORTED)) {
    366 			ksinfop = (ni_ksinfo_t *)kmem_zalloc(
    367 			    sizeof (ni_ksinfo_t), KM_NOSLEEP);
    368 
    369 			if (ksinfop == NULL) {
    370 				cmn_err(CE_WARN,
    371 				    "%s: no space for zambezi lpu kstat\n",
    372 				    cpu_module_name);
    373 				break;
    374 			}
    375 			ksinfop->pic_no_evs =
    376 			    sizeof (zam_lpu_perf_events) /
    377 			    sizeof (ni_kev_mask_t);
    378 			ksinfop->pic_sel_shift[0] = ZAMBEZI_PIC0_SEL_SHIFT;
    379 			ksinfop->pic_reg[0] = lpu_perf_regs[i].pic_reg[0];
    380 			ksinfop->pic_sel_shift[1] = ZAMBEZI_PIC1_SEL_SHIFT;
    381 			ksinfop->pic_reg[1] = lpu_perf_regs[i].pic_reg[1];
    382 			ksinfop->pcr_reg = lpu_perf_regs[i].pcr_reg;
    383 			zam_lpu_kstats[i] = ksinfop;
    384 
    385 			/* create basic pic event/mask pair (only once) */
    386 			if (i == 0)
    387 				ni_create_name_kstat("lpu", ksinfop,
    388 				    zam_lpu_perf_events);
    389 
    390 			/* create counter kstats */
    391 			zam_lpu_kstats[i]->cntr_ksp = ni_create_cntr_kstat(
    392 			    "lpu", i, zam_cntr_kstat_update, ksinfop);
    393 		}
    394 	}
    395 	/*
    396 	 * Create Zambezi GPD perf events kstat
    397 	 */
    398 	for (i = 0; i < ZAMBEZI_GPD_COUNTERS; i++) {
    399 		/* check if this Zambezi GPD instance is enabled in the HW */
    400 		stat = hv_niagara_getperf(gpd_perf_regs[i].pcr_reg, &pcr);
    401 		if ((stat != H_EINVAL) && (stat != H_ENOTSUPPORTED)) {
    402 			ksinfop = (ni_ksinfo_t *)kmem_zalloc(
    403 			    sizeof (ni_ksinfo_t), KM_NOSLEEP);
    404 
    405 			if (ksinfop == NULL) {
    406 				cmn_err(CE_WARN,
    407 				    "%s: no space for zambezi gpd kstat\n",
    408 				    cpu_module_name);
    409 				break;
    410 			}
    411 			ksinfop->pic_no_evs =
    412 			    sizeof (zam_gpd_perf_events) /
    413 			    sizeof (ni_kev_mask_t);
    414 			ksinfop->pic_sel_shift[0] = ZAMBEZI_PIC0_SEL_SHIFT;
    415 			ksinfop->pic_reg[0] = gpd_perf_regs[i].pic_reg[0];
    416 			ksinfop->pic_sel_shift[1] = ZAMBEZI_PIC1_SEL_SHIFT;
    417 			ksinfop->pic_reg[1] = gpd_perf_regs[i].pic_reg[1];
    418 			ksinfop->pcr_reg = gpd_perf_regs[i].pcr_reg;
    419 			zam_gpd_kstats[i] = ksinfop;
    420 
    421 			/* create basic pic event/mask pair (only once) */
    422 			if (i == 0)
    423 				ni_create_name_kstat("gpd", ksinfop,
    424 				    zam_gpd_perf_events);
    425 
    426 			/* create counter kstats */
    427 			zam_lpu_kstats[i]->cntr_ksp = ni_create_cntr_kstat(
    428 			    "gpd", i, zam_cntr_kstat_update, ksinfop);
    429 		}
    430 	}
    431 	/*
    432 	 * Create Zambezi ASU perf events kstat
    433 	 */
    434 	for (i = 0; i < ZAMBEZI_ASU_COUNTERS; i++) {
    435 		/* check if this Zambezi ASU instance is enabled in the HW */
    436 		stat = hv_niagara_getperf(asu_perf_regs[i].pcr_reg, &pcr);
    437 		if ((stat != H_EINVAL) && (stat != H_ENOTSUPPORTED)) {
    438 			ksinfop = (ni_ksinfo_t *)kmem_zalloc(
    439 			    sizeof (ni_ksinfo_t), KM_NOSLEEP);
    440 
    441 			if (ksinfop == NULL) {
    442 				cmn_err(CE_WARN,
    443 				    "%s: no space for zambezi asu kstat\n",
    444 				    cpu_module_name);
    445 				break;
    446 			}
    447 			ksinfop->pic_no_evs =
    448 			    sizeof (zam_asu_perf_events) /
    449 			    sizeof (ni_kev_mask_t);
    450 			ksinfop->pic_sel_shift[0] = ZAMBEZI_PIC0_SEL_SHIFT;
    451 			ksinfop->pic_reg[0] = asu_perf_regs[i].pic_reg[0];
    452 			ksinfop->pic_sel_shift[1] = ZAMBEZI_PIC1_SEL_SHIFT;
    453 			ksinfop->pic_reg[1] = asu_perf_regs[i].pic_reg[1];
    454 			ksinfop->pcr_reg = asu_perf_regs[i].pcr_reg;
    455 			zam_asu_kstats[i] = ksinfop;
    456 
    457 			/* create basic pic event/mask pair (only once) */
    458 			if (i == 0)
    459 				ni_create_name_kstat("asu", ksinfop,
    460 				    zam_asu_perf_events);
    461 
    462 			/* create counter kstats */
    463 			zam_lpu_kstats[i]->cntr_ksp = ni_create_cntr_kstat(
    464 			    "asu", i, zam_cntr_kstat_update, ksinfop);
    465 		}
    466 	}
    467 #endif
    468 
    469 #if defined(NIAGARA_IMPL)
    470 	/*
    471 	 * Create JBUS perf events kstat
    472 	 */
    473 	ni_jbus_kstat = (ni_ksinfo_t *)kmem_alloc(sizeof (ni_ksinfo_t),
    474 	    KM_NOSLEEP);
    475 
    476 	if (ni_jbus_kstat == NULL) {
    477 		cmn_err(CE_WARN, "%s: no space for niagara jbus kstat\n",
    478 		    cpu_module_name);
    479 	} else {
    480 		ni_jbus_kstat->pic_no_evs =
    481 		    sizeof (niagara_jbus_events) / sizeof (ni_kev_mask_t);
    482 		ni_jbus_kstat->pic_sel_shift[0] = NIAGARA_JBUS_PIC0_SEL_SHIFT;
    483 		ni_jbus_kstat->pic_shift[0] = NIAGARA_JBUS_PIC0_SHIFT;
    484 		ni_jbus_kstat->pic_mask[0] = NIAGARA_JBUS_PIC0_MASK;
    485 		ni_jbus_kstat->pic_sel_shift[1] = NIAGARA_JBUS_PIC1_SEL_SHIFT;
    486 		ni_jbus_kstat->pic_shift[1] = NIAGARA_JBUS_PIC1_SHIFT;
    487 		ni_jbus_kstat->pic_mask[1] = NIAGARA_JBUS_PIC1_MASK;
    488 		ni_jbus_kstat->pic_reg[0] = HV_NIAGARA_JBUS_COUNT;
    489 		ni_jbus_kstat->pcr_reg = HV_NIAGARA_JBUS_CTL;
    490 		ni_create_name_kstat("jbus", ni_jbus_kstat,
    491 		    niagara_jbus_events);
    492 		ni_jbus_kstat->cntr_ksp = ni_create_cntr_kstat("jbus", 0,
    493 		    ni_cntr_kstat_update, ni_jbus_kstat);
    494 	}
    495 #endif
    496 }
    497 
    498 void
    499 niagara_kstat_fini()
    500 {
    501 	int i;
    502 
    503 #ifdef DEBUG
    504 	if (ni_perf_debug)
    505 		printf("ni_kstat_fini called\n");
    506 #endif
    507 
    508 	for (i = 0; i < DRAM_BANKS; i++) {
    509 		if (ni_dram_kstats[i] != NULL) {
    510 			ni_delete_name_kstat(ni_dram_kstats[i]);
    511 			if (ni_dram_kstats[i]->cntr_ksp != NULL)
    512 				kstat_delete(ni_dram_kstats[i]->cntr_ksp);
    513 			kmem_free(ni_dram_kstats[i], sizeof (ni_ksinfo_t));
    514 			ni_dram_kstats[i] = NULL;
    515 		}
    516 	}
    517 
    518 #if defined(VFALLS_IMPL)
    519 	for (i = 0; i < ZAMBEZI_LPU_COUNTERS; i++) {
    520 		if (zam_lpu_kstats[i] != NULL) {
    521 			ni_delete_name_kstat(zam_lpu_kstats[i]);
    522 			if (zam_lpu_kstats[i]->cntr_ksp != NULL)
    523 				kstat_delete(zam_lpu_kstats[i]->cntr_ksp);
    524 			kmem_free(zam_lpu_kstats[i], sizeof (ni_ksinfo_t));
    525 			zam_lpu_kstats[i] = NULL;
    526 		}
    527 	}
    528 
    529 	for (i = 0; i < ZAMBEZI_GPD_COUNTERS; i++) {
    530 		if (zam_gpd_kstats[i] != NULL) {
    531 			ni_delete_name_kstat(zam_gpd_kstats[i]);
    532 			if (zam_gpd_kstats[i]->cntr_ksp != NULL)
    533 				kstat_delete(zam_gpd_kstats[i]->cntr_ksp);
    534 			kmem_free(zam_gpd_kstats[i], sizeof (ni_ksinfo_t));
    535 			zam_gpd_kstats[i] = NULL;
    536 		}
    537 	}
    538 
    539 	for (i = 0; i < ZAMBEZI_ASU_COUNTERS; i++) {
    540 		if (zam_asu_kstats[i] != NULL) {
    541 			ni_delete_name_kstat(zam_asu_kstats[i]);
    542 			if (zam_asu_kstats[i]->cntr_ksp != NULL)
    543 				kstat_delete(zam_asu_kstats[i]->cntr_ksp);
    544 			kmem_free(zam_asu_kstats[i], sizeof (ni_ksinfo_t));
    545 			zam_asu_kstats[i] = NULL;
    546 		}
    547 	}
    548 #endif
    549 
    550 #if defined(NIAGARA_IMPL)
    551 	if (ni_jbus_kstat != NULL) {
    552 		ni_delete_name_kstat(ni_jbus_kstat);
    553 		if (ni_jbus_kstat->cntr_ksp != NULL)
    554 			kstat_delete(ni_jbus_kstat->cntr_ksp);
    555 		kmem_free(ni_jbus_kstat, sizeof (ni_ksinfo_t));
    556 		ni_jbus_kstat = NULL;
    557 	}
    558 #endif
    559 }
    560 
    561 static void
    562 ni_create_name_kstat(char *name, ni_ksinfo_t *pp, ni_kev_mask_t *ev)
    563 {
    564 	int	i;
    565 
    566 #ifdef DEBUG
    567 	if (ni_perf_debug > 1)
    568 		printf("ni_create_name_kstat: name: %s\n", name);
    569 #endif
    570 	for (i = 0; i < NUM_OF_PICS; i++) {
    571 		pp->pic_name_ksp[i] = ni_create_picN_kstat(name,
    572 		    i, pp->pic_sel_shift[i], pp->pic_no_evs, ev);
    573 
    574 		if (pp->pic_name_ksp[i] == NULL) {
    575 			cmn_err(CE_WARN, "%s: unable to create name kstat",
    576 			    cpu_module_name);
    577 		}
    578 	}
    579 }
    580 
    581 static void
    582 ni_delete_name_kstat(ni_ksinfo_t *pp)
    583 {
    584 	int	i;
    585 
    586 	if (pp != NULL) {
    587 		for (i = 0; i < NUM_OF_PICS; i++) {
    588 			if (pp->pic_name_ksp[i] != NULL)
    589 				kstat_delete(pp->pic_name_ksp[i]);
    590 		}
    591 	}
    592 }
    593 
    594 /*
    595  * Create the picN kstat. Returns a pointer to the
    596  * kstat which the driver must store to allow it
    597  * to be deleted when necessary.
    598  */
    599 static kstat_t *
    600 ni_create_picN_kstat(char *mod_name, int pic, int pic_sel_shift,
    601 	int num_ev, ni_kev_mask_t *ev_array)
    602 {
    603 	struct kstat_named *pic_named_data;
    604 	int	inst = 0;
    605 	int	event;
    606 	char	pic_name[30];
    607 	kstat_t	*picN_ksp = NULL;
    608 
    609 	(void) sprintf(pic_name, "pic%d", pic);
    610 	if ((picN_ksp = kstat_create(mod_name, inst, pic_name,
    611 	    "bus", KSTAT_TYPE_NAMED, num_ev, NULL)) == NULL) {
    612 		cmn_err(CE_WARN, "%s %s : kstat create failed",
    613 		    mod_name, pic_name);
    614 
    615 		/*
    616 		 * It is up to the calling function to delete any kstats
    617 		 * that may have been created already. We just
    618 		 * return NULL to indicate an error has occured.
    619 		 */
    620 		return (NULL);
    621 	}
    622 
    623 	pic_named_data = (struct kstat_named *)
    624 	    picN_ksp->ks_data;
    625 
    626 	/*
    627 	 * Write event names and their associated pcr masks. The
    628 	 * last entry in the array (clear_pic) is added seperately
    629 	 * below as the pic value must be inverted.
    630 	 */
    631 	for (event = 0; event < num_ev - 1; event++) {
    632 		pic_named_data[event].value.ui64 =
    633 		    (ev_array[event].pcr_mask << pic_sel_shift);
    634 
    635 		kstat_named_init(&pic_named_data[event],
    636 		    ev_array[event].event_name,
    637 		    KSTAT_DATA_UINT64);
    638 	}
    639 
    640 	/*
    641 	 * add the clear_pic entry.
    642 	 */
    643 	pic_named_data[event].value.ui64 =
    644 	    (uint64_t)~(ev_array[event].pcr_mask << pic_sel_shift);
    645 
    646 	kstat_named_init(&pic_named_data[event], ev_array[event].event_name,
    647 	    KSTAT_DATA_UINT64);
    648 
    649 	kstat_install(picN_ksp);
    650 
    651 	return (picN_ksp);
    652 }
    653 
    654 /*
    655  * Create the "counters" kstat.
    656  */
    657 static kstat_t *
    658 ni_create_cntr_kstat(char *name, int instance, int (*update)(kstat_t *, int),
    659 	void *ksinfop)
    660 {
    661 	struct kstat	*counters_ksp;
    662 	struct kstat_named	*counters_named_data;
    663 	char		pic_str[10];
    664 	int		i;
    665 	int		num_pics = NUM_OF_PICS;
    666 
    667 #ifdef DEBUG
    668 	if (ni_perf_debug > 1)
    669 		printf("ni_create_cntr_kstat: name: %s instance: %d\n",
    670 		    name, instance);
    671 #endif
    672 
    673 	/*
    674 	 * Size of kstat is num_pics + 1 as it
    675 	 * also contains the %pcr
    676 	 */
    677 	if ((counters_ksp = kstat_create(name, instance, "counters", "bus",
    678 	    KSTAT_TYPE_NAMED, num_pics + 1, KSTAT_FLAG_WRITABLE)) == NULL) {
    679 		cmn_err(CE_WARN,
    680 		    "%s: kstat_create for %s%d failed", cpu_module_name,
    681 		    name, instance);
    682 		return (NULL);
    683 	}
    684 
    685 	counters_named_data = (struct kstat_named *)(counters_ksp->ks_data);
    686 
    687 	/*
    688 	 * Iinitialize the named kstats
    689 	 */
    690 	kstat_named_init(&counters_named_data[0], "pcr", KSTAT_DATA_UINT64);
    691 
    692 	for (i = 0; i < num_pics; i++) {
    693 		(void) sprintf(pic_str, "pic%d", i);
    694 
    695 		kstat_named_init(&counters_named_data[i+1], pic_str,
    696 		    KSTAT_DATA_UINT64);
    697 	}
    698 
    699 	/*
    700 	 * Store the register offset's in the kstat's
    701 	 * private field so that they are available
    702 	 * to the update function.
    703 	 */
    704 	counters_ksp->ks_private = (void *)ksinfop;
    705 	counters_ksp->ks_update = update;
    706 
    707 	kstat_install(counters_ksp);
    708 
    709 	return (counters_ksp);
    710 }
    711 
    712 #if defined(VFALLS_IMPL)
    713 /*
    714  * zambezi kstat update function. Handles reads/writes
    715  * from/to kstat.
    716  */
    717 static int
    718 zam_cntr_kstat_update(kstat_t *ksp, int rw)
    719 {
    720 	struct kstat_named	*data_p;
    721 	ni_ksinfo_t	*ksinfop = ksp->ks_private;
    722 	uint64_t	pic0, pic1, pcr;
    723 	int		stat = 0;
    724 	uint64_t	pic0_stat = 0, pic1_stat = 0, pcr_stat = 0;
    725 
    726 	data_p = (struct kstat_named *)ksp->ks_data;
    727 
    728 	if (rw == KSTAT_WRITE) {
    729 #ifdef DEBUG
    730 		if (ni_perf_debug)
    731 			printf("zam_cntr_kstat_update: wr pcr-%d: %lx\n",
    732 			    ksinfop->pcr_reg, data_p[0].value.ui64);
    733 #endif
    734 		if (hv_niagara_setperf(ksinfop->pcr_reg, data_p[0].value.ui64))
    735 			stat = EACCES;
    736 	} else {
    737 		do {
    738 			pic0_stat = hv_niagara_getperf(ksinfop->pic_reg[0],
    739 			    &pic0);
    740 		} while (pic0_stat == H_EWOULDBLOCK);
    741 		do {
    742 			pic1_stat = hv_niagara_getperf(ksinfop->pic_reg[1],
    743 			    &pic1);
    744 		} while (pic1_stat == H_EWOULDBLOCK);
    745 		do {
    746 			pcr_stat = hv_niagara_getperf(ksinfop->pcr_reg,
    747 			    &pcr);
    748 		} while (pcr_stat == H_EWOULDBLOCK);
    749 		if (pic0_stat != 0 || pic1_stat != 0 || pcr_stat != 0)
    750 			stat = EACCES;
    751 		else {
    752 			data_p[0].value.ui64 = pcr;
    753 			data_p[1].value.ui64 = pic0;
    754 			data_p[2].value.ui64 = pic1;
    755 		}
    756 #ifdef DEBUG
    757 		if (ni_perf_debug)
    758 			printf("zam_cntr_kstat_update: rd pcr%d: %lx  "
    759 			    "pic0: %16lx pic1: %16lx\n",
    760 			    ksinfop->pcr_reg, pcr,
    761 			    data_p[1].value.ui64, data_p[2].value.ui64);
    762 #endif
    763 	}
    764 
    765 	return (stat);
    766 }
    767 #endif
    768 
    769 /*
    770  * kstat update function. Handles reads/writes
    771  * from/to kstat.
    772  */
    773 static int
    774 ni_cntr_kstat_update(kstat_t *ksp, int rw)
    775 {
    776 	struct kstat_named	*data_p;
    777 	ni_ksinfo_t	*ksinfop = ksp->ks_private;
    778 	uint64_t	pic, pcr;
    779 	int		stat = 0;
    780 	uint32_t	pic0, pic1;
    781 
    782 	data_p = (struct kstat_named *)ksp->ks_data;
    783 
    784 	if (rw == KSTAT_WRITE) {
    785 #ifdef DEBUG
    786 		if (ni_perf_debug)
    787 			printf("ni_cntr_kstat_update: wr pcr-%d: %lx\n",
    788 			    ksinfop->pcr_reg, data_p[0].value.ui64);
    789 #endif
    790 		if (hv_niagara_setperf(ksinfop->pcr_reg, data_p[0].value.ui64))
    791 			stat = EACCES;
    792 	} else {
    793 		if (hv_niagara_getperf(ksinfop->pic_reg[0], &pic) != 0 ||
    794 		    hv_niagara_getperf(ksinfop->pcr_reg, &pcr) != 0)
    795 			stat = EACCES;
    796 		else {
    797 			data_p[0].value.ui64 = pcr;
    798 
    799 			/*
    800 			 * Generate a 32-bit PIC0 value by detecting overflow
    801 			 */
    802 			pic0 = (uint32_t)((pic >> ksinfop->pic_shift[0]) &
    803 			    ksinfop->pic_mask[0]);
    804 			if (pic0 < ksinfop->pic_last_val[0])
    805 				ksinfop->pic_overflow[0]++;
    806 			ksinfop->pic_last_val[0] = pic0;
    807 			pic0 += (ksinfop->pic_overflow[0] & 1) << 31;
    808 			data_p[1].value.ui64 = (uint64_t)pic0;
    809 
    810 			/*
    811 			 * Generate a 32-bit PIC1 value by detecting overflow
    812 			 */
    813 			pic1 = (uint32_t)((pic >> ksinfop->pic_shift[1]) &
    814 			    ksinfop->pic_mask[1]);
    815 			if (pic1 < ksinfop->pic_last_val[1])
    816 				ksinfop->pic_overflow[1]++;
    817 			ksinfop->pic_last_val[1] = pic1;
    818 			pic1 += (ksinfop->pic_overflow[1] & 1) << 31;
    819 			data_p[2].value.ui64 = (uint64_t)pic1;
    820 		}
    821 #ifdef DEBUG
    822 		if (ni_perf_debug)
    823 			printf("ni_cntr_kstat_update: rd pcr%d: %lx  "
    824 			    "pic%d: %16lx pic0: %8lx pic1: %8lx\n",
    825 			    ksinfop->pcr_reg, pcr, ksinfop->pic_reg[0], pic,
    826 			    data_p[1].value.ui64, data_p[2].value.ui64);
    827 #endif
    828 	}
    829 	return (stat);
    830 }
    831