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