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