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 2006 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) 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 and Niagara2 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 159 #ifdef DEBUG 160 if (ni_perf_debug) 161 printf("ni_kstat_init called\n"); 162 #endif 163 164 /* 165 * Create DRAM perf events kstat 166 */ 167 for (i = 0; i < NIAGARA_DRAM_BANKS; i++) { 168 ksinfop = (ni_ksinfo_t *)kmem_zalloc(sizeof (ni_ksinfo_t), 169 KM_NOSLEEP); 170 171 if (ksinfop == NULL) { 172 cmn_err(CE_WARN, 173 "%s: no space for niagara dram kstat\n", 174 cpu_module_name); 175 break; 176 } 177 ksinfop->pic_no_evs = 178 sizeof (niagara_dram_events) / sizeof (ni_kev_mask_t); 179 ksinfop->pic_sel_shift[0] = NIAGARA_DRAM_PIC0_SEL_SHIFT; 180 ksinfop->pic_shift[0] = NIAGARA_DRAM_PIC0_SHIFT; 181 ksinfop->pic_mask[0] = NIAGARA_DRAM_PIC0_MASK; 182 ksinfop->pic_sel_shift[1] = NIAGARA_DRAM_PIC1_SEL_SHIFT; 183 ksinfop->pic_shift[1] = NIAGARA_DRAM_PIC1_SHIFT; 184 ksinfop->pic_mask[1] = NIAGARA_DRAM_PIC1_MASK; 185 ksinfop->pic_reg = dram_perf_regs[i].pic_reg; 186 ksinfop->pcr_reg = dram_perf_regs[i].pcr_reg; 187 ni_dram_kstats[i] = ksinfop; 188 189 /* create basic pic event/mask pair (only once) */ 190 if (i == 0) 191 ni_create_name_kstat("dram", ksinfop, 192 niagara_dram_events); 193 194 /* create counter kstats */ 195 ni_dram_kstats[i]->cntr_ksp = ni_create_cntr_kstat("dram", i, 196 ni_cntr_kstat_update, ksinfop); 197 } 198 199 #if defined(NIAGARA_IMPL) 200 /* 201 * Create JBUS perf events kstat 202 */ 203 ni_jbus_kstat = (ni_ksinfo_t *)kmem_alloc(sizeof (ni_ksinfo_t), 204 KM_NOSLEEP); 205 206 if (ni_jbus_kstat == NULL) { 207 cmn_err(CE_WARN, "%s: no space for niagara jbus kstat\n", 208 cpu_module_name); 209 } else { 210 ni_jbus_kstat->pic_no_evs = 211 sizeof (niagara_jbus_events) / sizeof (ni_kev_mask_t); 212 ni_jbus_kstat->pic_sel_shift[0] = NIAGARA_JBUS_PIC0_SEL_SHIFT; 213 ni_jbus_kstat->pic_shift[0] = NIAGARA_JBUS_PIC0_SHIFT; 214 ni_jbus_kstat->pic_mask[0] = NIAGARA_JBUS_PIC0_MASK; 215 ni_jbus_kstat->pic_sel_shift[1] = NIAGARA_JBUS_PIC1_SEL_SHIFT; 216 ni_jbus_kstat->pic_shift[1] = NIAGARA_JBUS_PIC1_SHIFT; 217 ni_jbus_kstat->pic_mask[1] = NIAGARA_JBUS_PIC1_MASK; 218 ni_jbus_kstat->pic_reg = HV_NIAGARA_JBUS_COUNT; 219 ni_jbus_kstat->pcr_reg = HV_NIAGARA_JBUS_CTL; 220 ni_create_name_kstat("jbus", ni_jbus_kstat, 221 niagara_jbus_events); 222 ni_jbus_kstat->cntr_ksp = ni_create_cntr_kstat("jbus", 0, 223 ni_cntr_kstat_update, ni_jbus_kstat); 224 } 225 #endif 226 } 227 228 void 229 niagara_kstat_fini() 230 { 231 int i; 232 233 #ifdef DEBUG 234 if (ni_perf_debug) 235 printf("ni_kstat_fini called\n"); 236 #endif 237 for (i = 0; i < NIAGARA_DRAM_BANKS; i++) { 238 if (ni_dram_kstats[i] != NULL) { 239 ni_delete_name_kstat(ni_dram_kstats[i]); 240 if (ni_dram_kstats[i]->cntr_ksp != NULL) 241 kstat_delete(ni_dram_kstats[i]->cntr_ksp); 242 kmem_free(ni_dram_kstats[i], sizeof (ni_ksinfo_t)); 243 ni_dram_kstats[i] = NULL; 244 } 245 } 246 247 #if defined(NIAGARA_IMPL) 248 if (ni_jbus_kstat != NULL) { 249 ni_delete_name_kstat(ni_jbus_kstat); 250 if (ni_jbus_kstat->cntr_ksp != NULL) 251 kstat_delete(ni_jbus_kstat->cntr_ksp); 252 kmem_free(ni_jbus_kstat, sizeof (ni_ksinfo_t)); 253 ni_jbus_kstat = NULL; 254 } 255 #endif 256 } 257 258 static void 259 ni_create_name_kstat(char *name, ni_ksinfo_t *pp, ni_kev_mask_t *ev) 260 { 261 int i; 262 263 #ifdef DEBUG 264 if (ni_perf_debug > 1) 265 printf("ni_create_name_kstat: name: %s\n", name); 266 #endif 267 for (i = 0; i < NUM_OF_PICS; i++) { 268 pp->pic_name_ksp[i] = ni_create_picN_kstat(name, 269 i, pp->pic_sel_shift[i], pp->pic_no_evs, ev); 270 271 if (pp->pic_name_ksp[i] == NULL) { 272 cmn_err(CE_WARN, "%s: unable to create name kstat", 273 cpu_module_name); 274 } 275 } 276 } 277 278 static void 279 ni_delete_name_kstat(ni_ksinfo_t *pp) 280 { 281 int i; 282 283 if (pp != NULL) { 284 for (i = 0; i < NUM_OF_PICS; i++) { 285 if (pp->pic_name_ksp[i] != NULL) 286 kstat_delete(pp->pic_name_ksp[i]); 287 } 288 } 289 } 290 291 /* 292 * Create the picN kstat. Returns a pointer to the 293 * kstat which the driver must store to allow it 294 * to be deleted when necessary. 295 */ 296 static kstat_t * 297 ni_create_picN_kstat(char *mod_name, int pic, int pic_sel_shift, 298 int num_ev, ni_kev_mask_t *ev_array) 299 { 300 struct kstat_named *pic_named_data; 301 int inst = 0; 302 int event; 303 char pic_name[30]; 304 kstat_t *picN_ksp = NULL; 305 306 (void) sprintf(pic_name, "pic%d", pic); 307 if ((picN_ksp = kstat_create(mod_name, inst, pic_name, 308 "bus", KSTAT_TYPE_NAMED, num_ev, NULL)) == NULL) { 309 cmn_err(CE_WARN, "%s %s : kstat create failed", 310 mod_name, pic_name); 311 312 /* 313 * It is up to the calling function to delete any kstats 314 * that may have been created already. We just 315 * return NULL to indicate an error has occured. 316 */ 317 return (NULL); 318 } 319 320 pic_named_data = (struct kstat_named *) 321 picN_ksp->ks_data; 322 323 /* 324 * Write event names and their associated pcr masks. The 325 * last entry in the array (clear_pic) is added seperately 326 * below as the pic value must be inverted. 327 */ 328 for (event = 0; event < num_ev - 1; event++) { 329 pic_named_data[event].value.ui64 = 330 (ev_array[event].pcr_mask << pic_sel_shift); 331 332 kstat_named_init(&pic_named_data[event], 333 ev_array[event].event_name, 334 KSTAT_DATA_UINT64); 335 } 336 337 /* 338 * add the clear_pic entry. 339 */ 340 pic_named_data[event].value.ui64 = 341 (uint64_t)~(ev_array[event].pcr_mask << pic_sel_shift); 342 343 kstat_named_init(&pic_named_data[event], ev_array[event].event_name, 344 KSTAT_DATA_UINT64); 345 346 kstat_install(picN_ksp); 347 348 return (picN_ksp); 349 } 350 351 /* 352 * Create the "counters" kstat. 353 */ 354 static kstat_t * 355 ni_create_cntr_kstat(char *name, int instance, int (*update)(kstat_t *, int), 356 void *ksinfop) 357 { 358 struct kstat *counters_ksp; 359 struct kstat_named *counters_named_data; 360 char pic_str[10]; 361 int i; 362 int num_pics = NUM_OF_PICS; 363 364 #ifdef DEBUG 365 if (ni_perf_debug > 1) 366 printf("ni_create_cntr_kstat: name: %s instance: %d\n", 367 name, instance); 368 #endif 369 370 /* 371 * Size of kstat is num_pics + 1 as it 372 * also contains the %pcr 373 */ 374 if ((counters_ksp = kstat_create(name, instance, "counters", "bus", 375 KSTAT_TYPE_NAMED, num_pics + 1, KSTAT_FLAG_WRITABLE)) == NULL) { 376 cmn_err(CE_WARN, 377 "%s: kstat_create for %s%d failed", cpu_module_name, 378 name, instance); 379 return (NULL); 380 } 381 382 counters_named_data = (struct kstat_named *)(counters_ksp->ks_data); 383 384 /* 385 * Iinitialize the named kstats 386 */ 387 kstat_named_init(&counters_named_data[0], "pcr", KSTAT_DATA_UINT64); 388 389 for (i = 0; i < num_pics; i++) { 390 (void) sprintf(pic_str, "pic%d", i); 391 392 kstat_named_init(&counters_named_data[i+1], pic_str, 393 KSTAT_DATA_UINT64); 394 } 395 396 /* 397 * Store the register offset's in the kstat's 398 * private field so that they are available 399 * to the update function. 400 */ 401 counters_ksp->ks_private = (void *)ksinfop; 402 counters_ksp->ks_update = update; 403 404 kstat_install(counters_ksp); 405 406 return (counters_ksp); 407 } 408 409 /* 410 * kstat update function. Handles reads/writes 411 * from/to kstat. 412 */ 413 static int 414 ni_cntr_kstat_update(kstat_t *ksp, int rw) 415 { 416 struct kstat_named *data_p; 417 ni_ksinfo_t *ksinfop = ksp->ks_private; 418 uint64_t pic, pcr; 419 int stat = 0; 420 uint32_t pic0, pic1; 421 422 data_p = (struct kstat_named *)ksp->ks_data; 423 424 if (rw == KSTAT_WRITE) { 425 #ifdef DEBUG 426 if (ni_perf_debug) 427 printf("ni_cntr_kstat_update: wr pcr-%d: %lx\n", 428 ksinfop->pcr_reg, data_p[0].value.ui64); 429 #endif 430 if (hv_niagara_setperf(ksinfop->pcr_reg, data_p[0].value.ui64)) 431 stat = EACCES; 432 } else { 433 if (hv_niagara_getperf(ksinfop->pic_reg, &pic) != 0 || 434 hv_niagara_getperf(ksinfop->pcr_reg, &pcr) != 0) 435 stat = EACCES; 436 else { 437 438 data_p[0].value.ui64 = pcr; 439 440 /* 441 * Generate a 32-bit PIC0 value by detecting overflow 442 */ 443 pic0 = (uint32_t)((pic >> ksinfop->pic_shift[0]) & 444 ksinfop->pic_mask[0]); 445 if (pic0 < ksinfop->pic_last_val[0]) 446 ksinfop->pic_overflow[0]++; 447 ksinfop->pic_last_val[0] = pic0; 448 pic0 += (ksinfop->pic_overflow[0] & 1) << 31; 449 data_p[1].value.ui64 = (uint64_t)pic0; 450 451 /* 452 * Generate a 32-bit PIC1 value by detecting overflow 453 */ 454 pic1 = (uint32_t)((pic >> ksinfop->pic_shift[1]) & 455 ksinfop->pic_mask[1]); 456 if (pic1 < ksinfop->pic_last_val[1]) 457 ksinfop->pic_overflow[1]++; 458 ksinfop->pic_last_val[1] = pic1; 459 pic1 += (ksinfop->pic_overflow[1] & 1) << 31; 460 data_p[2].value.ui64 = (uint64_t)pic1; 461 } 462 #ifdef DEBUG 463 if (ni_perf_debug) 464 printf("ni_cntr_kstat_update: rd pcr%d: %lx " 465 "pic%d: %16lx pic0: %8lx pic1: %8lx\n", 466 ksinfop->pcr_reg, pcr, ksinfop->pic_reg, pic, 467 data_p[1].value.ui64, data_p[2].value.ui64); 468 #endif 469 } 470 return (stat); 471 } 472