1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24*0Sstevel@tonic-gate * Use is subject to license terms. 25*0Sstevel@tonic-gate */ 26*0Sstevel@tonic-gate 27*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*0Sstevel@tonic-gate 29*0Sstevel@tonic-gate #include <sys/types.h> 30*0Sstevel@tonic-gate #include <sys/async.h> 31*0Sstevel@tonic-gate #include <sys/sunddi.h> 32*0Sstevel@tonic-gate #include <sys/sunndi.h> 33*0Sstevel@tonic-gate #include <sys/ddi_impldefs.h> 34*0Sstevel@tonic-gate #include <sys/machsystm.h> 35*0Sstevel@tonic-gate #include <sys/niagararegs.h> 36*0Sstevel@tonic-gate #include <sys/hypervisor_api.h> 37*0Sstevel@tonic-gate #include <sys/kstat.h> 38*0Sstevel@tonic-gate 39*0Sstevel@tonic-gate #define NIAGARA_MODNAME "SUNW,UltraSPARC-T1" 40*0Sstevel@tonic-gate #define NUM_OF_PICS 2 41*0Sstevel@tonic-gate 42*0Sstevel@tonic-gate /* 43*0Sstevel@tonic-gate * Data structure used to build array of event-names and pcr-mask values 44*0Sstevel@tonic-gate */ 45*0Sstevel@tonic-gate typedef struct ni_kev_mask { 46*0Sstevel@tonic-gate char *event_name; 47*0Sstevel@tonic-gate uint64_t pcr_mask; 48*0Sstevel@tonic-gate } ni_kev_mask_t; 49*0Sstevel@tonic-gate 50*0Sstevel@tonic-gate /* 51*0Sstevel@tonic-gate * Kstat data structure for DRAM and JBUS performance counters 52*0Sstevel@tonic-gate * 53*0Sstevel@tonic-gate * Note that these performance counters are only 31 bits wide. Since 54*0Sstevel@tonic-gate * the "busstat" command assumes a 32-bit counter, we emulate a 32-bit 55*0Sstevel@tonic-gate * counter by detecting overflow on read of these performance counters 56*0Sstevel@tonic-gate * and using the least significant bit of the overflow count as the 57*0Sstevel@tonic-gate * most significant bit (i.e. bit# 31) of the DRAM and JBUS performance 58*0Sstevel@tonic-gate * counters. 59*0Sstevel@tonic-gate */ 60*0Sstevel@tonic-gate typedef struct ni_ksinfo { 61*0Sstevel@tonic-gate uint8_t pic_no_evs; /* number of events */ 62*0Sstevel@tonic-gate uint8_t pic_sel_shift[NUM_OF_PICS]; 63*0Sstevel@tonic-gate uint8_t pic_shift[NUM_OF_PICS]; 64*0Sstevel@tonic-gate uint64_t pic_mask[NUM_OF_PICS]; 65*0Sstevel@tonic-gate kstat_t *pic_name_ksp[NUM_OF_PICS]; 66*0Sstevel@tonic-gate kstat_t *cntr_ksp; 67*0Sstevel@tonic-gate uint32_t pic_reg; 68*0Sstevel@tonic-gate uint32_t pcr_reg; 69*0Sstevel@tonic-gate uint32_t pic_overflow[NUM_OF_PICS]; /* overflow count */ 70*0Sstevel@tonic-gate uint32_t pic_last_val[NUM_OF_PICS]; /* last PIC value */ 71*0Sstevel@tonic-gate } ni_ksinfo_t; 72*0Sstevel@tonic-gate 73*0Sstevel@tonic-gate static ni_ksinfo_t *ni_dram_kstats[NIAGARA_DRAM_BANKS]; 74*0Sstevel@tonic-gate static ni_ksinfo_t *ni_jbus_kstat; 75*0Sstevel@tonic-gate 76*0Sstevel@tonic-gate typedef struct ni_perf_regs { 77*0Sstevel@tonic-gate uint32_t pcr_reg; 78*0Sstevel@tonic-gate uint32_t pic_reg; 79*0Sstevel@tonic-gate } ni_perf_regs_t; 80*0Sstevel@tonic-gate 81*0Sstevel@tonic-gate static ni_perf_regs_t dram_perf_regs[] = { 82*0Sstevel@tonic-gate {HV_NIAGARA_DRAM_CTL0, HV_NIAGARA_DRAM_COUNT0}, 83*0Sstevel@tonic-gate {HV_NIAGARA_DRAM_CTL1, HV_NIAGARA_DRAM_COUNT1}, 84*0Sstevel@tonic-gate {HV_NIAGARA_DRAM_CTL2, HV_NIAGARA_DRAM_COUNT2}, 85*0Sstevel@tonic-gate {HV_NIAGARA_DRAM_CTL3, HV_NIAGARA_DRAM_COUNT3}, 86*0Sstevel@tonic-gate }; 87*0Sstevel@tonic-gate 88*0Sstevel@tonic-gate 89*0Sstevel@tonic-gate static void ni_create_name_kstat(char *, ni_ksinfo_t *, ni_kev_mask_t *); 90*0Sstevel@tonic-gate static void ni_delete_name_kstat(ni_ksinfo_t *); 91*0Sstevel@tonic-gate 92*0Sstevel@tonic-gate static kstat_t *ni_create_cntr_kstat(char *, int, 93*0Sstevel@tonic-gate int (*update)(kstat_t *, int), void *); 94*0Sstevel@tonic-gate 95*0Sstevel@tonic-gate static int ni_cntr_kstat_update(kstat_t *, int); 96*0Sstevel@tonic-gate 97*0Sstevel@tonic-gate static kstat_t *ni_create_picN_kstat(char *, int, int, int, 98*0Sstevel@tonic-gate ni_kev_mask_t *); 99*0Sstevel@tonic-gate 100*0Sstevel@tonic-gate #ifdef DEBUG 101*0Sstevel@tonic-gate static int ni_perf_debug; 102*0Sstevel@tonic-gate #endif 103*0Sstevel@tonic-gate 104*0Sstevel@tonic-gate /* 105*0Sstevel@tonic-gate * Niagara DRAM Performance Events 106*0Sstevel@tonic-gate */ 107*0Sstevel@tonic-gate static ni_kev_mask_t 108*0Sstevel@tonic-gate niagara_dram_events[] = { 109*0Sstevel@tonic-gate {"mem_reads", 0x0}, 110*0Sstevel@tonic-gate {"mem_writes", 0x1}, 111*0Sstevel@tonic-gate {"mem_read_write", 0x2}, 112*0Sstevel@tonic-gate {"bank_busy_stalls", 0x3}, 113*0Sstevel@tonic-gate {"rd_queue_latency", 0x4}, 114*0Sstevel@tonic-gate {"wr_queue_latency", 0x5}, 115*0Sstevel@tonic-gate {"rw_queue_latency", 0x6}, 116*0Sstevel@tonic-gate {"wb_buf_hits", 0x7}, 117*0Sstevel@tonic-gate {"clear_pic", 0xf} 118*0Sstevel@tonic-gate }; 119*0Sstevel@tonic-gate 120*0Sstevel@tonic-gate 121*0Sstevel@tonic-gate /* 122*0Sstevel@tonic-gate * Niagara JBUS Performance Events 123*0Sstevel@tonic-gate */ 124*0Sstevel@tonic-gate static ni_kev_mask_t 125*0Sstevel@tonic-gate niagara_jbus_events[] = { 126*0Sstevel@tonic-gate {"jbus_cycles", 0x1}, 127*0Sstevel@tonic-gate {"dma_reads", 0x2}, 128*0Sstevel@tonic-gate {"dma_read_latency", 0x3}, 129*0Sstevel@tonic-gate {"dma_writes", 0x4}, 130*0Sstevel@tonic-gate {"dma_write8", 0x5}, 131*0Sstevel@tonic-gate {"ordering_waits", 0x6}, 132*0Sstevel@tonic-gate {"pio_reads", 0x8}, 133*0Sstevel@tonic-gate {"pio_read_latency", 0x9}, 134*0Sstevel@tonic-gate {"aok_dok_off_cycles", 0xc}, 135*0Sstevel@tonic-gate {"aok_off_cycles", 0xd}, 136*0Sstevel@tonic-gate {"dok_off_cycles", 0xe}, 137*0Sstevel@tonic-gate {"clear_pic", 0xf} 138*0Sstevel@tonic-gate }; 139*0Sstevel@tonic-gate 140*0Sstevel@tonic-gate /* 141*0Sstevel@tonic-gate * Create the picN kstats for DRAM and JBUS events 142*0Sstevel@tonic-gate */ 143*0Sstevel@tonic-gate void 144*0Sstevel@tonic-gate niagara_kstat_init() 145*0Sstevel@tonic-gate { 146*0Sstevel@tonic-gate int i; 147*0Sstevel@tonic-gate ni_ksinfo_t *ksinfop; 148*0Sstevel@tonic-gate 149*0Sstevel@tonic-gate #ifdef DEBUG 150*0Sstevel@tonic-gate if (ni_perf_debug) 151*0Sstevel@tonic-gate printf("ni_kstat_init called\n"); 152*0Sstevel@tonic-gate #endif 153*0Sstevel@tonic-gate 154*0Sstevel@tonic-gate /* 155*0Sstevel@tonic-gate * Create DRAM perf events kstat 156*0Sstevel@tonic-gate */ 157*0Sstevel@tonic-gate for (i = 0; i < NIAGARA_DRAM_BANKS; i++) { 158*0Sstevel@tonic-gate ksinfop = (ni_ksinfo_t *)kmem_zalloc(sizeof (ni_ksinfo_t), 159*0Sstevel@tonic-gate KM_NOSLEEP); 160*0Sstevel@tonic-gate 161*0Sstevel@tonic-gate if (ksinfop == NULL) { 162*0Sstevel@tonic-gate cmn_err(CE_WARN, 163*0Sstevel@tonic-gate "%s: no space for niagara dram kstat\n", 164*0Sstevel@tonic-gate NIAGARA_MODNAME); 165*0Sstevel@tonic-gate break; 166*0Sstevel@tonic-gate } 167*0Sstevel@tonic-gate ksinfop->pic_no_evs = 168*0Sstevel@tonic-gate sizeof (niagara_dram_events) / sizeof (ni_kev_mask_t); 169*0Sstevel@tonic-gate ksinfop->pic_sel_shift[0] = NIAGARA_DRAM_PIC0_SEL_SHIFT; 170*0Sstevel@tonic-gate ksinfop->pic_shift[0] = NIAGARA_DRAM_PIC0_SHIFT; 171*0Sstevel@tonic-gate ksinfop->pic_mask[0] = NIAGARA_DRAM_PIC0_MASK; 172*0Sstevel@tonic-gate ksinfop->pic_sel_shift[1] = NIAGARA_DRAM_PIC1_SEL_SHIFT; 173*0Sstevel@tonic-gate ksinfop->pic_shift[1] = NIAGARA_DRAM_PIC1_SHIFT; 174*0Sstevel@tonic-gate ksinfop->pic_mask[1] = NIAGARA_DRAM_PIC1_MASK; 175*0Sstevel@tonic-gate ksinfop->pic_reg = dram_perf_regs[i].pic_reg; 176*0Sstevel@tonic-gate ksinfop->pcr_reg = dram_perf_regs[i].pcr_reg; 177*0Sstevel@tonic-gate ni_dram_kstats[i] = ksinfop; 178*0Sstevel@tonic-gate 179*0Sstevel@tonic-gate /* create basic pic event/mask pair (only once) */ 180*0Sstevel@tonic-gate if (i == 0) 181*0Sstevel@tonic-gate ni_create_name_kstat("dram", ksinfop, 182*0Sstevel@tonic-gate niagara_dram_events); 183*0Sstevel@tonic-gate 184*0Sstevel@tonic-gate /* create counter kstats */ 185*0Sstevel@tonic-gate ni_dram_kstats[i]->cntr_ksp = ni_create_cntr_kstat("dram", i, 186*0Sstevel@tonic-gate ni_cntr_kstat_update, ksinfop); 187*0Sstevel@tonic-gate } 188*0Sstevel@tonic-gate 189*0Sstevel@tonic-gate /* 190*0Sstevel@tonic-gate * Create JBUS perf events kstat 191*0Sstevel@tonic-gate */ 192*0Sstevel@tonic-gate ni_jbus_kstat = (ni_ksinfo_t *)kmem_alloc(sizeof (ni_ksinfo_t), 193*0Sstevel@tonic-gate KM_NOSLEEP); 194*0Sstevel@tonic-gate 195*0Sstevel@tonic-gate if (ni_jbus_kstat == NULL) { 196*0Sstevel@tonic-gate cmn_err(CE_WARN, "%s: no space for niagara jbus kstat\n", 197*0Sstevel@tonic-gate NIAGARA_MODNAME); 198*0Sstevel@tonic-gate } else { 199*0Sstevel@tonic-gate ni_jbus_kstat->pic_no_evs = 200*0Sstevel@tonic-gate sizeof (niagara_jbus_events) / sizeof (ni_kev_mask_t); 201*0Sstevel@tonic-gate ni_jbus_kstat->pic_sel_shift[0] = NIAGARA_JBUS_PIC0_SEL_SHIFT; 202*0Sstevel@tonic-gate ni_jbus_kstat->pic_shift[0] = NIAGARA_JBUS_PIC0_SHIFT; 203*0Sstevel@tonic-gate ni_jbus_kstat->pic_mask[0] = NIAGARA_JBUS_PIC0_MASK; 204*0Sstevel@tonic-gate ni_jbus_kstat->pic_sel_shift[1] = NIAGARA_JBUS_PIC1_SEL_SHIFT; 205*0Sstevel@tonic-gate ni_jbus_kstat->pic_shift[1] = NIAGARA_JBUS_PIC1_SHIFT; 206*0Sstevel@tonic-gate ni_jbus_kstat->pic_mask[1] = NIAGARA_JBUS_PIC1_MASK; 207*0Sstevel@tonic-gate ni_jbus_kstat->pic_reg = HV_NIAGARA_JBUS_COUNT; 208*0Sstevel@tonic-gate ni_jbus_kstat->pcr_reg = HV_NIAGARA_JBUS_CTL; 209*0Sstevel@tonic-gate ni_create_name_kstat("jbus", ni_jbus_kstat, 210*0Sstevel@tonic-gate niagara_jbus_events); 211*0Sstevel@tonic-gate ni_jbus_kstat->cntr_ksp = ni_create_cntr_kstat("jbus", 0, 212*0Sstevel@tonic-gate ni_cntr_kstat_update, ni_jbus_kstat); 213*0Sstevel@tonic-gate } 214*0Sstevel@tonic-gate } 215*0Sstevel@tonic-gate 216*0Sstevel@tonic-gate void 217*0Sstevel@tonic-gate niagara_kstat_fini() 218*0Sstevel@tonic-gate { 219*0Sstevel@tonic-gate int i; 220*0Sstevel@tonic-gate 221*0Sstevel@tonic-gate #ifdef DEBUG 222*0Sstevel@tonic-gate if (ni_perf_debug) 223*0Sstevel@tonic-gate printf("ni_kstat_fini called\n"); 224*0Sstevel@tonic-gate #endif 225*0Sstevel@tonic-gate for (i = 0; i < NIAGARA_DRAM_BANKS; i++) { 226*0Sstevel@tonic-gate if (ni_dram_kstats[i] != NULL) { 227*0Sstevel@tonic-gate ni_delete_name_kstat(ni_dram_kstats[i]); 228*0Sstevel@tonic-gate if (ni_dram_kstats[i]->cntr_ksp != NULL) 229*0Sstevel@tonic-gate kstat_delete(ni_dram_kstats[i]->cntr_ksp); 230*0Sstevel@tonic-gate kmem_free(ni_dram_kstats[i], sizeof (ni_ksinfo_t)); 231*0Sstevel@tonic-gate ni_dram_kstats[i] = NULL; 232*0Sstevel@tonic-gate } 233*0Sstevel@tonic-gate } 234*0Sstevel@tonic-gate 235*0Sstevel@tonic-gate if (ni_jbus_kstat != NULL) { 236*0Sstevel@tonic-gate ni_delete_name_kstat(ni_jbus_kstat); 237*0Sstevel@tonic-gate if (ni_jbus_kstat->cntr_ksp != NULL) 238*0Sstevel@tonic-gate kstat_delete(ni_jbus_kstat->cntr_ksp); 239*0Sstevel@tonic-gate kmem_free(ni_jbus_kstat, sizeof (ni_ksinfo_t)); 240*0Sstevel@tonic-gate ni_jbus_kstat = NULL; 241*0Sstevel@tonic-gate } 242*0Sstevel@tonic-gate } 243*0Sstevel@tonic-gate 244*0Sstevel@tonic-gate static void 245*0Sstevel@tonic-gate ni_create_name_kstat(char *name, ni_ksinfo_t *pp, ni_kev_mask_t *ev) 246*0Sstevel@tonic-gate { 247*0Sstevel@tonic-gate int i; 248*0Sstevel@tonic-gate 249*0Sstevel@tonic-gate #ifdef DEBUG 250*0Sstevel@tonic-gate if (ni_perf_debug > 1) 251*0Sstevel@tonic-gate printf("ni_create_name_kstat: name: %s\n", name); 252*0Sstevel@tonic-gate #endif 253*0Sstevel@tonic-gate for (i = 0; i < NUM_OF_PICS; i++) { 254*0Sstevel@tonic-gate pp->pic_name_ksp[i] = ni_create_picN_kstat(name, 255*0Sstevel@tonic-gate i, pp->pic_sel_shift[i], pp->pic_no_evs, ev); 256*0Sstevel@tonic-gate 257*0Sstevel@tonic-gate if (pp->pic_name_ksp[i] == NULL) { 258*0Sstevel@tonic-gate cmn_err(CE_WARN, "%s: unable to create name kstat", 259*0Sstevel@tonic-gate NIAGARA_MODNAME); 260*0Sstevel@tonic-gate } 261*0Sstevel@tonic-gate } 262*0Sstevel@tonic-gate } 263*0Sstevel@tonic-gate 264*0Sstevel@tonic-gate static void 265*0Sstevel@tonic-gate ni_delete_name_kstat(ni_ksinfo_t *pp) 266*0Sstevel@tonic-gate { 267*0Sstevel@tonic-gate int i; 268*0Sstevel@tonic-gate 269*0Sstevel@tonic-gate if (pp != NULL) { 270*0Sstevel@tonic-gate for (i = 0; i < NUM_OF_PICS; i++) { 271*0Sstevel@tonic-gate if (pp->pic_name_ksp[i] != NULL) 272*0Sstevel@tonic-gate kstat_delete(pp->pic_name_ksp[i]); 273*0Sstevel@tonic-gate } 274*0Sstevel@tonic-gate } 275*0Sstevel@tonic-gate } 276*0Sstevel@tonic-gate 277*0Sstevel@tonic-gate /* 278*0Sstevel@tonic-gate * Create the picN kstat. Returns a pointer to the 279*0Sstevel@tonic-gate * kstat which the driver must store to allow it 280*0Sstevel@tonic-gate * to be deleted when necessary. 281*0Sstevel@tonic-gate */ 282*0Sstevel@tonic-gate static kstat_t * 283*0Sstevel@tonic-gate ni_create_picN_kstat(char *mod_name, int pic, int pic_sel_shift, 284*0Sstevel@tonic-gate int num_ev, ni_kev_mask_t *ev_array) 285*0Sstevel@tonic-gate { 286*0Sstevel@tonic-gate struct kstat_named *pic_named_data; 287*0Sstevel@tonic-gate int inst = 0; 288*0Sstevel@tonic-gate int event; 289*0Sstevel@tonic-gate char pic_name[30]; 290*0Sstevel@tonic-gate kstat_t *picN_ksp = NULL; 291*0Sstevel@tonic-gate 292*0Sstevel@tonic-gate (void) sprintf(pic_name, "pic%d", pic); 293*0Sstevel@tonic-gate if ((picN_ksp = kstat_create(mod_name, inst, pic_name, 294*0Sstevel@tonic-gate "bus", KSTAT_TYPE_NAMED, num_ev, NULL)) == NULL) { 295*0Sstevel@tonic-gate cmn_err(CE_WARN, "%s %s : kstat create failed", 296*0Sstevel@tonic-gate mod_name, pic_name); 297*0Sstevel@tonic-gate 298*0Sstevel@tonic-gate /* 299*0Sstevel@tonic-gate * It is up to the calling function to delete any kstats 300*0Sstevel@tonic-gate * that may have been created already. We just 301*0Sstevel@tonic-gate * return NULL to indicate an error has occured. 302*0Sstevel@tonic-gate */ 303*0Sstevel@tonic-gate return (NULL); 304*0Sstevel@tonic-gate } 305*0Sstevel@tonic-gate 306*0Sstevel@tonic-gate pic_named_data = (struct kstat_named *) 307*0Sstevel@tonic-gate picN_ksp->ks_data; 308*0Sstevel@tonic-gate 309*0Sstevel@tonic-gate /* 310*0Sstevel@tonic-gate * Write event names and their associated pcr masks. The 311*0Sstevel@tonic-gate * last entry in the array (clear_pic) is added seperately 312*0Sstevel@tonic-gate * below as the pic value must be inverted. 313*0Sstevel@tonic-gate */ 314*0Sstevel@tonic-gate for (event = 0; event < num_ev - 1; event++) { 315*0Sstevel@tonic-gate pic_named_data[event].value.ui64 = 316*0Sstevel@tonic-gate (ev_array[event].pcr_mask << pic_sel_shift); 317*0Sstevel@tonic-gate 318*0Sstevel@tonic-gate kstat_named_init(&pic_named_data[event], 319*0Sstevel@tonic-gate ev_array[event].event_name, 320*0Sstevel@tonic-gate KSTAT_DATA_UINT64); 321*0Sstevel@tonic-gate } 322*0Sstevel@tonic-gate 323*0Sstevel@tonic-gate /* 324*0Sstevel@tonic-gate * add the clear_pic entry. 325*0Sstevel@tonic-gate */ 326*0Sstevel@tonic-gate pic_named_data[event].value.ui64 = 327*0Sstevel@tonic-gate (uint64_t)~(ev_array[event].pcr_mask << pic_sel_shift); 328*0Sstevel@tonic-gate 329*0Sstevel@tonic-gate kstat_named_init(&pic_named_data[event], ev_array[event].event_name, 330*0Sstevel@tonic-gate KSTAT_DATA_UINT64); 331*0Sstevel@tonic-gate 332*0Sstevel@tonic-gate kstat_install(picN_ksp); 333*0Sstevel@tonic-gate 334*0Sstevel@tonic-gate return (picN_ksp); 335*0Sstevel@tonic-gate } 336*0Sstevel@tonic-gate 337*0Sstevel@tonic-gate /* 338*0Sstevel@tonic-gate * Create the "counters" kstat. 339*0Sstevel@tonic-gate */ 340*0Sstevel@tonic-gate static kstat_t * 341*0Sstevel@tonic-gate ni_create_cntr_kstat(char *name, int instance, int (*update)(kstat_t *, int), 342*0Sstevel@tonic-gate void *ksinfop) 343*0Sstevel@tonic-gate { 344*0Sstevel@tonic-gate struct kstat *counters_ksp; 345*0Sstevel@tonic-gate struct kstat_named *counters_named_data; 346*0Sstevel@tonic-gate char pic_str[10]; 347*0Sstevel@tonic-gate int i; 348*0Sstevel@tonic-gate int num_pics = NUM_OF_PICS; 349*0Sstevel@tonic-gate 350*0Sstevel@tonic-gate #ifdef DEBUG 351*0Sstevel@tonic-gate if (ni_perf_debug > 1) 352*0Sstevel@tonic-gate printf("ni_create_cntr_kstat: name: %s instance: %d\n", 353*0Sstevel@tonic-gate name, instance); 354*0Sstevel@tonic-gate #endif 355*0Sstevel@tonic-gate 356*0Sstevel@tonic-gate /* 357*0Sstevel@tonic-gate * Size of kstat is num_pics + 1 as it 358*0Sstevel@tonic-gate * also contains the %pcr 359*0Sstevel@tonic-gate */ 360*0Sstevel@tonic-gate if ((counters_ksp = kstat_create(name, instance, "counters", "bus", 361*0Sstevel@tonic-gate KSTAT_TYPE_NAMED, num_pics + 1, KSTAT_FLAG_WRITABLE)) == NULL) { 362*0Sstevel@tonic-gate cmn_err(CE_WARN, 363*0Sstevel@tonic-gate "%s: kstat_create for %s%d failed", NIAGARA_MODNAME, 364*0Sstevel@tonic-gate name, instance); 365*0Sstevel@tonic-gate return (NULL); 366*0Sstevel@tonic-gate } 367*0Sstevel@tonic-gate 368*0Sstevel@tonic-gate counters_named_data = (struct kstat_named *)(counters_ksp->ks_data); 369*0Sstevel@tonic-gate 370*0Sstevel@tonic-gate /* 371*0Sstevel@tonic-gate * Iinitialize the named kstats 372*0Sstevel@tonic-gate */ 373*0Sstevel@tonic-gate kstat_named_init(&counters_named_data[0], "pcr", KSTAT_DATA_UINT64); 374*0Sstevel@tonic-gate 375*0Sstevel@tonic-gate for (i = 0; i < num_pics; i++) { 376*0Sstevel@tonic-gate (void) sprintf(pic_str, "pic%d", i); 377*0Sstevel@tonic-gate 378*0Sstevel@tonic-gate kstat_named_init(&counters_named_data[i+1], pic_str, 379*0Sstevel@tonic-gate KSTAT_DATA_UINT64); 380*0Sstevel@tonic-gate } 381*0Sstevel@tonic-gate 382*0Sstevel@tonic-gate /* 383*0Sstevel@tonic-gate * Store the register offset's in the kstat's 384*0Sstevel@tonic-gate * private field so that they are available 385*0Sstevel@tonic-gate * to the update function. 386*0Sstevel@tonic-gate */ 387*0Sstevel@tonic-gate counters_ksp->ks_private = (void *)ksinfop; 388*0Sstevel@tonic-gate counters_ksp->ks_update = update; 389*0Sstevel@tonic-gate 390*0Sstevel@tonic-gate kstat_install(counters_ksp); 391*0Sstevel@tonic-gate 392*0Sstevel@tonic-gate return (counters_ksp); 393*0Sstevel@tonic-gate } 394*0Sstevel@tonic-gate 395*0Sstevel@tonic-gate /* 396*0Sstevel@tonic-gate * kstat update function. Handles reads/writes 397*0Sstevel@tonic-gate * from/to kstat. 398*0Sstevel@tonic-gate */ 399*0Sstevel@tonic-gate static int 400*0Sstevel@tonic-gate ni_cntr_kstat_update(kstat_t *ksp, int rw) 401*0Sstevel@tonic-gate { 402*0Sstevel@tonic-gate struct kstat_named *data_p; 403*0Sstevel@tonic-gate ni_ksinfo_t *ksinfop = ksp->ks_private; 404*0Sstevel@tonic-gate uint64_t pic, pcr; 405*0Sstevel@tonic-gate int stat = 0; 406*0Sstevel@tonic-gate uint32_t pic0, pic1; 407*0Sstevel@tonic-gate 408*0Sstevel@tonic-gate data_p = (struct kstat_named *)ksp->ks_data; 409*0Sstevel@tonic-gate 410*0Sstevel@tonic-gate if (rw == KSTAT_WRITE) { 411*0Sstevel@tonic-gate #ifdef DEBUG 412*0Sstevel@tonic-gate if (ni_perf_debug) 413*0Sstevel@tonic-gate printf("ni_cntr_kstat_update: wr pcr-%d: %llx\n", 414*0Sstevel@tonic-gate ksinfop->pcr_reg, data_p[0].value.ui64); 415*0Sstevel@tonic-gate #endif 416*0Sstevel@tonic-gate if (hv_niagara_setperf(ksinfop->pcr_reg, data_p[0].value.ui64)) 417*0Sstevel@tonic-gate stat = EACCES; 418*0Sstevel@tonic-gate } else { 419*0Sstevel@tonic-gate if (hv_niagara_getperf(ksinfop->pic_reg, &pic) != 0 || 420*0Sstevel@tonic-gate hv_niagara_getperf(ksinfop->pcr_reg, &pcr) != 0) 421*0Sstevel@tonic-gate stat = EACCES; 422*0Sstevel@tonic-gate else { 423*0Sstevel@tonic-gate 424*0Sstevel@tonic-gate data_p[0].value.ui64 = pcr; 425*0Sstevel@tonic-gate 426*0Sstevel@tonic-gate /* 427*0Sstevel@tonic-gate * Generate a 32-bit PIC0 value by detecting overflow 428*0Sstevel@tonic-gate */ 429*0Sstevel@tonic-gate pic0 = (uint32_t)((pic >> ksinfop->pic_shift[0]) & 430*0Sstevel@tonic-gate ksinfop->pic_mask[0]); 431*0Sstevel@tonic-gate if (pic0 < ksinfop->pic_last_val[0]) 432*0Sstevel@tonic-gate ksinfop->pic_overflow[0]++; 433*0Sstevel@tonic-gate ksinfop->pic_last_val[0] = pic0; 434*0Sstevel@tonic-gate pic0 += (ksinfop->pic_overflow[0] & 1) << 31; 435*0Sstevel@tonic-gate data_p[1].value.ui64 = (uint64_t)pic0; 436*0Sstevel@tonic-gate 437*0Sstevel@tonic-gate /* 438*0Sstevel@tonic-gate * Generate a 32-bit PIC1 value by detecting overflow 439*0Sstevel@tonic-gate */ 440*0Sstevel@tonic-gate pic1 = (uint32_t)((pic >> ksinfop->pic_shift[1]) & 441*0Sstevel@tonic-gate ksinfop->pic_mask[1]); 442*0Sstevel@tonic-gate if (pic1 < ksinfop->pic_last_val[1]) 443*0Sstevel@tonic-gate ksinfop->pic_overflow[1]++; 444*0Sstevel@tonic-gate ksinfop->pic_last_val[1] = pic1; 445*0Sstevel@tonic-gate pic1 += (ksinfop->pic_overflow[1] & 1) << 31; 446*0Sstevel@tonic-gate data_p[2].value.ui64 = (uint64_t)pic1; 447*0Sstevel@tonic-gate } 448*0Sstevel@tonic-gate #ifdef DEBUG 449*0Sstevel@tonic-gate if (ni_perf_debug) 450*0Sstevel@tonic-gate printf("ni_cntr_kstat_update: rd pcr%d: %lx " 451*0Sstevel@tonic-gate "pic%d: %16lx pic0: %8lx pic1: %8lx\n", 452*0Sstevel@tonic-gate ksinfop->pcr_reg, pcr, ksinfop->pic_reg, pic, 453*0Sstevel@tonic-gate data_p[1].value.ui64, data_p[2].value.ui64); 454*0Sstevel@tonic-gate #endif 455*0Sstevel@tonic-gate } 456*0Sstevel@tonic-gate return (stat); 457*0Sstevel@tonic-gate } 458