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