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 /* 27 * Niagara2 Performance Counter Backend 28 */ 29 30 #include <sys/cpuvar.h> 31 #include <sys/systm.h> 32 #include <sys/archsystm.h> 33 #include <sys/cmn_err.h> 34 #include <sys/cpc_impl.h> 35 #include <sys/cpc_pcbe.h> 36 #include <sys/modctl.h> 37 #include <sys/machsystm.h> 38 #include <sys/sdt.h> 39 #include <sys/niagara2regs.h> 40 #include <sys/hsvc.h> 41 #include <sys/hypervisor_api.h> 42 #include <sys/disp.h> 43 44 /*LINTLIBRARY*/ 45 static int ni2_pcbe_init(void); 46 static uint_t ni2_pcbe_ncounters(void); 47 static const char *ni2_pcbe_impl_name(void); 48 static const char *ni2_pcbe_cpuref(void); 49 static char *ni2_pcbe_list_events(uint_t picnum); 50 static char *ni2_pcbe_list_attrs(void); 51 static uint64_t ni2_pcbe_event_coverage(char *event); 52 static uint64_t ni2_pcbe_overflow_bitmap(void); 53 static int ni2_pcbe_configure(uint_t picnum, char *event, uint64_t preset, 54 uint32_t flags, uint_t nattrs, kcpc_attr_t *attrs, void **data, 55 void *token); 56 static void ni2_pcbe_program(void *token); 57 static void ni2_pcbe_allstop(void); 58 static void ni2_pcbe_sample(void *token); 59 static void ni2_pcbe_free(void *config); 60 61 extern void ultra_setpcr(uint64_t); 62 extern uint64_t ultra_getpcr(void); 63 extern void ultra_setpic(uint64_t); 64 extern uint64_t ultra_getpic(void); 65 extern uint64_t ultra_gettick(void); 66 extern char cpu_module_name[]; 67 68 pcbe_ops_t ni2_pcbe_ops = { 69 PCBE_VER_1, 70 CPC_CAP_OVERFLOW_INTERRUPT | CPC_CAP_OVERFLOW_PRECISE, 71 ni2_pcbe_ncounters, 72 ni2_pcbe_impl_name, 73 ni2_pcbe_cpuref, 74 ni2_pcbe_list_events, 75 ni2_pcbe_list_attrs, 76 ni2_pcbe_event_coverage, 77 ni2_pcbe_overflow_bitmap, 78 ni2_pcbe_configure, 79 ni2_pcbe_program, 80 ni2_pcbe_allstop, 81 ni2_pcbe_sample, 82 ni2_pcbe_free 83 }; 84 85 typedef struct _ni2_pcbe_config { 86 uint_t pcbe_picno; /* 0 for pic0 or 1 for pic1 */ 87 uint32_t pcbe_evsel; /* %pcr event code unshifted */ 88 uint32_t pcbe_flags; /* hpriv/user/system/priv */ 89 uint32_t pcbe_pic; /* unshifted raw %pic value */ 90 } ni2_pcbe_config_t; 91 92 typedef struct _ni2_event { 93 const char *name; 94 const uint32_t emask; 95 const uint32_t emask_valid; /* Mask of unreserved MASK bits */ 96 } ni2_event_t; 97 98 #define ULTRA_PCR_PRIVPIC (UINT64_C(1) << CPC_NIAGARA2_PCR_PRIV_SHIFT) 99 #define EV_END {NULL, 0, 0} 100 101 static const uint64_t allstopped = (ULTRA_PCR_PRIVPIC | 102 CPC_NIAGARA2_PCR_HOLDOV0 | CPC_NIAGARA2_PCR_HOLDOV1); 103 104 /* 105 * We update this array in the program and allstop routine. The array 106 * is checked in the sample routine to allow us to only perform the 107 * PCR.ht bit check when counting is in progress. 108 */ 109 static boolean_t ni2_cpc_counting[NCPU]; 110 111 static ni2_event_t ni2_events[] = { 112 { "Idle_strands", 0x000, 0x00 }, 113 { "Br_completed", 0x201, 0xff }, 114 { "Br_taken", 0x202, 0xff }, 115 { "Instr_FGU_arithmetic", 0x204, 0xff }, 116 { "Instr_ld", 0x208, 0xff }, 117 { "Instr_st", 0x210, 0xff }, 118 { "Instr_sw", 0x220, 0xff }, 119 { "Instr_other", 0x240, 0xff }, 120 { "Atomics", 0x280, 0xff }, 121 { "Instr_cnt", 0x2fd, 0xff }, 122 { "IC_miss", 0x301, 0x33 }, 123 { "DC_miss", 0x302, 0x33 }, 124 { "L2_imiss", 0x310, 0x33 }, 125 { "L2_dmiss_ld", 0x320, 0x33 }, 126 { "ITLB_HWTW_ref_L2", 0x404, 0x3c }, 127 { "DTLB_HWTW_ref_L2", 0x408, 0x3c }, 128 { "ITLB_HWTW_miss_L2", 0x410, 0x3c }, 129 { "DTLB_HWTW_miss_L2", 0x420, 0x3c }, 130 { "Stream_ld_to_PCX", 0x501, 0x3f }, 131 { "Stream_st_to_PCX", 0x502, 0x3f }, 132 { "CPU_ld_to_PCX", 0x504, 0x3f }, 133 { "CPU_ifetch_to_PCX", 0x508, 0x3f }, 134 { "CPU_st_to_PCX", 0x510, 0x3f }, 135 { "MMU_ld_to_PCX", 0x520, 0x3f }, 136 { "DES_3DES_op", 0x601, 0x3f }, 137 { "AES_op", 0x602, 0x3f }, 138 { "RC4_op", 0x604, 0x3f }, 139 { "MD5_SHA-1_SHA-256_op", 0x608, 0x3f }, 140 { "MA_op", 0x610, 0x3f }, 141 { "CRC_TCPIP_cksum", 0x620, 0x3f }, 142 { "DES_3DES_busy_cycle", 0x701, 0x3f }, 143 { "AES_busy_cycle", 0x702, 0x3f }, 144 { "RC4_busy_cycle", 0x704, 0x3f }, 145 { "MD5_SHA-1_SHA-256_busy_cycle", 0x708, 0x3f }, 146 { "MA_busy_cycle", 0x710, 0x3f }, 147 { "CRC_MPA_cksum", 0x720, 0x3f }, 148 { "ITLB_miss", 0xb04, 0x0c }, 149 { "DTLB_miss", 0xb08, 0x0c }, 150 { "TLB_miss", 0xb0c, 0x0c }, 151 EV_END 152 }; 153 154 static char *evlist; 155 static size_t evlist_sz; 156 static uint16_t pcr_pic0_mask; 157 static uint16_t pcr_pic1_mask; 158 159 #define CPU_REF_URL " Documentation for Sun processors can be found at: " \ 160 "http://www.sun.com/processors/manuals" 161 162 #if defined(NIAGARA2_IMPL) 163 static const char *cpu_impl_name = "UltraSPARC T2"; 164 static const char *cpu_pcbe_ref = "See the \"UltraSPARC T2 User's Manual\" " 165 "for descriptions of these events." CPU_REF_URL; 166 #elif defined(VFALLS_IMPL) 167 static const char *cpu_impl_name = "UltraSPARC T2+"; 168 static const char *cpu_pcbe_ref = "See the \"UltraSPARC T2+ User's Manual\" " 169 "for descriptions of these events." CPU_REF_URL; 170 #endif 171 172 static boolean_t cpu_hsvc_available = B_TRUE; 173 174 static int 175 ni2_pcbe_init(void) 176 { 177 ni2_event_t *evp; 178 int status; 179 uint64_t cpu_hsvc_major; 180 uint64_t cpu_hsvc_minor; 181 #if defined(NIAGARA2_IMPL) 182 uint64_t hsvc_cpu_group = HSVC_GROUP_NIAGARA2_CPU; 183 uint64_t hsvc_cpu_major = NIAGARA2_HSVC_MAJOR; 184 #elif defined(VFALLS_IMPL) 185 uint64_t hsvc_cpu_group = HSVC_GROUP_VFALLS_CPU; 186 uint64_t hsvc_cpu_major = VFALLS_HSVC_MAJOR; 187 #endif 188 189 pcr_pic0_mask = CPC_NIAGARA2_PCR_PIC0_MASK; 190 pcr_pic1_mask = CPC_NIAGARA2_PCR_PIC1_MASK; 191 192 /* 193 * Validate API version for Niagara2 specific hypervisor services 194 */ 195 status = hsvc_version(hsvc_cpu_group, &cpu_hsvc_major, 196 &cpu_hsvc_minor); 197 if ((status != 0) || (cpu_hsvc_major != hsvc_cpu_major)) { 198 cmn_err(CE_WARN, "hypervisor services not negotiated " 199 "or unsupported major number: group: 0x%lx major: 0x%lx " 200 "minor: 0x%lx errno: %d", hsvc_cpu_group, 201 cpu_hsvc_major, cpu_hsvc_minor, status); 202 cpu_hsvc_available = B_FALSE; 203 } 204 205 /* 206 * Construct event list. 207 * 208 * First pass: Calculate size needed. We'll need an additional byte 209 * for the NULL pointer during the last strcat. 210 * 211 * Second pass: Copy strings. 212 */ 213 for (evp = ni2_events; evp->name != NULL; evp++) 214 evlist_sz += strlen(evp->name) + 1; 215 216 evlist = kmem_alloc(evlist_sz + 1, KM_SLEEP); 217 evlist[0] = '\0'; 218 219 for (evp = ni2_events; evp->name != NULL; evp++) { 220 (void) strcat(evlist, evp->name); 221 (void) strcat(evlist, ","); 222 } 223 /* 224 * Remove trailing comma. 225 */ 226 evlist[evlist_sz - 1] = '\0'; 227 228 return (0); 229 } 230 231 static uint_t 232 ni2_pcbe_ncounters(void) 233 { 234 return (2); 235 } 236 237 static const char * 238 ni2_pcbe_impl_name(void) 239 { 240 return (cpu_impl_name); 241 } 242 243 static const char * 244 ni2_pcbe_cpuref(void) 245 { 246 return (cpu_pcbe_ref); 247 } 248 249 static char * 250 ni2_pcbe_list_events(uint_t picnum) 251 { 252 ASSERT(picnum < cpc_ncounters); 253 254 return (evlist); 255 } 256 257 static char * 258 ni2_pcbe_list_attrs(void) 259 { 260 if (cpu_hsvc_available == B_TRUE) 261 #if defined(NIAGARA2_IMPL) 262 return ("hpriv,emask"); 263 #elif defined(VFALLS_IMPL) 264 return ("hpriv,l2ctl,emask"); 265 #endif 266 else 267 return ("emask"); 268 } 269 270 static ni2_event_t * 271 find_event(char *name) 272 { 273 ni2_event_t *evp; 274 275 for (evp = ni2_events; evp->name != NULL; evp++) 276 if (strcmp(name, evp->name) == 0) 277 return (evp); 278 279 return (NULL); 280 } 281 282 /*ARGSUSED*/ 283 static uint64_t 284 ni2_pcbe_event_coverage(char *event) 285 { 286 /* 287 * Fortunately, both pic0 and pic1 can count all events. 288 */ 289 return (0x3); 290 } 291 292 static uint64_t 293 ni2_pcbe_overflow_bitmap(void) 294 { 295 uint64_t pcr, overflow; 296 uint64_t pic; 297 uint32_t pic0, pic1; 298 boolean_t update_pic = B_FALSE; 299 300 ASSERT(getpil() >= DISP_LEVEL); 301 pcr = ultra_getpcr(); 302 DTRACE_PROBE1(niagara2__getpcr, uint64_t, pcr); 303 overflow = (pcr & CPC_NIAGARA2_PCR_OV0_MASK) >> 304 CPC_NIAGARA2_PCR_OV0_SHIFT; 305 overflow |= (pcr & CPC_NIAGARA2_PCR_OV1_MASK) >> 306 CPC_NIAGARA2_PCR_OV1_SHIFT; 307 308 pic = ultra_getpic(); 309 pic0 = (uint32_t)(pic & PIC0_MASK); 310 pic1 = (uint32_t)((pic >> PIC1_SHIFT) & PIC0_MASK); 311 312 pcr |= (CPC_NIAGARA2_PCR_HOLDOV0 | CPC_NIAGARA2_PCR_HOLDOV1); 313 314 if (overflow & 0x1) { 315 pcr &= ~(CPC_NIAGARA2_PCR_OV0_MASK | 316 CPC_NIAGARA2_PCR_HOLDOV0); 317 if (PIC_IN_OV_RANGE(pic0)) { 318 pic0 = 0; 319 update_pic = B_TRUE; 320 } 321 } 322 323 if (overflow & 0x2) { 324 pcr &= ~(CPC_NIAGARA2_PCR_OV1_MASK | 325 CPC_NIAGARA2_PCR_HOLDOV1); 326 if (PIC_IN_OV_RANGE(pic1)) { 327 pic1 = 0; 328 update_pic = B_TRUE; 329 } 330 } 331 332 if (update_pic) 333 ultra_setpic(((uint64_t)pic1 << PIC1_SHIFT) | pic0); 334 335 /* 336 * The HV interface does not need to be used here because we are 337 * only resetting the OV bits and do not need to set the HT bit. 338 */ 339 DTRACE_PROBE1(niagara2__setpcr, uint64_t, pcr); 340 ultra_setpcr(pcr); 341 342 return (overflow); 343 } 344 345 /*ARGSUSED*/ 346 static int 347 ni2_pcbe_configure(uint_t picnum, char *event, uint64_t preset, uint32_t flags, 348 uint_t nattrs, kcpc_attr_t *attrs, void **data, void *token) 349 { 350 ni2_pcbe_config_t *cfg; 351 ni2_pcbe_config_t *other_config; 352 ni2_event_t *evp; 353 int i; 354 uint32_t evsel; 355 #if defined(VFALLS_IMPL) 356 uint64_t l2ctl = 0; 357 #endif 358 359 /* 360 * If we've been handed an existing configuration, we need only preset 361 * the counter value. 362 */ 363 if (*data != NULL) { 364 cfg = *data; 365 cfg->pcbe_pic = (uint32_t)preset; 366 return (0); 367 } 368 369 if (picnum > 1) 370 return (CPC_INVALID_PICNUM); 371 372 if ((evp = find_event(event)) == NULL) 373 return (CPC_INVALID_EVENT); 374 375 evsel = evp->emask; 376 377 for (i = 0; i < nattrs; i++) { 378 if (strcmp(attrs[i].ka_name, "hpriv") == 0) { 379 if (attrs[i].ka_val != 0) 380 flags |= CPC_COUNT_HV; 381 } else if (strcmp(attrs[i].ka_name, "emask") == 0) { 382 if ((attrs[i].ka_val | evp->emask_valid) != 383 evp->emask_valid) 384 return (CPC_ATTRIBUTE_OUT_OF_RANGE); 385 evsel |= attrs[i].ka_val; 386 #if defined(VFALLS_IMPL) 387 } else if (strcmp(attrs[i].ka_name, "l2ctl") == 0) { 388 if ((attrs[i].ka_val | VFALLS_L2_CTL_MASK) != 389 VFALLS_L2_CTL_MASK) 390 return (CPC_ATTRIBUTE_OUT_OF_RANGE); 391 else 392 l2ctl = attrs[i].ka_val; 393 #endif 394 } else 395 return (CPC_INVALID_ATTRIBUTE); 396 } 397 398 #if defined(VFALLS_IMPL) 399 /* 400 * Set PERF_CONTROL bits in L2_CONTROL_REG only when events have 401 * SL bits equal to 3. 402 */ 403 if ((evsel & VFALLS_SL3_MASK) == VFALLS_SL3_MASK) { 404 if ((hv_niagara_setperf(HV_NIAGARA_L2_CTL, l2ctl)) != 0) 405 return (CPC_HV_NO_ACCESS); 406 } 407 #endif 408 409 /* 410 * Find other requests that will be programmed with this one, and ensure 411 * the flags don't conflict. 412 */ 413 if (((other_config = kcpc_next_config(token, NULL, NULL)) != NULL) && 414 (other_config->pcbe_flags != flags)) 415 return (CPC_CONFLICTING_REQS); 416 417 /* 418 * If the hpriv attribute is present, make sure we have 419 * access to hyperprivileged events before continuing with 420 * this configuration. If we can set the ht bit in the PCR 421 * successfully, we must have access to hyperprivileged 422 * events. 423 * 424 * If this is a static per-CPU configuration, the CPC 425 * driver ensures there can not be more than one for this 426 * CPU. If this is a per-LWP configuration, the driver 427 * ensures no static per-CPU counting is ongoing and that 428 * the target LWP is not already being monitored. 429 */ 430 if (flags & CPC_COUNT_HV) { 431 kpreempt_disable(); 432 433 DTRACE_PROBE1(niagara2__setpcr, uint64_t, 434 allstopped | CPC_NIAGARA2_PCR_HT); 435 if (hv_niagara_setperf(HV_NIAGARA_SPARC_CTL, 436 allstopped | CPC_NIAGARA2_PCR_HT) != H_EOK) { 437 kpreempt_enable(); 438 return (CPC_HV_NO_ACCESS); 439 } 440 441 DTRACE_PROBE1(niagara2__setpcr, uint64_t, allstopped); 442 (void) hv_niagara_setperf(HV_NIAGARA_SPARC_CTL, allstopped); 443 444 kpreempt_enable(); 445 } 446 447 cfg = kmem_alloc(sizeof (*cfg), KM_SLEEP); 448 449 cfg->pcbe_picno = picnum; 450 cfg->pcbe_evsel = evsel; 451 cfg->pcbe_flags = flags; 452 cfg->pcbe_pic = (uint32_t)preset; 453 454 *data = cfg; 455 return (0); 456 } 457 458 static void 459 ni2_pcbe_program(void *token) 460 { 461 ni2_pcbe_config_t *pic0; 462 ni2_pcbe_config_t *pic1; 463 ni2_pcbe_config_t *tmp; 464 ni2_pcbe_config_t nullcfg = { 1, 0, 0, 0 }; 465 uint64_t pcr; 466 uint64_t curpic; 467 uint64_t toe; 468 469 /* enable trap-on-event for pic0 and pic1 */ 470 toe = (CPC_NIAGARA2_PCR_TOE0 | CPC_NIAGARA2_PCR_TOE1); 471 472 if ((pic0 = (ni2_pcbe_config_t *)kcpc_next_config(token, NULL, NULL)) == 473 NULL) 474 panic("ni2_pcbe: token %p has no configs", token); 475 476 if ((pic1 = kcpc_next_config(token, pic0, NULL)) == NULL) { 477 pic1 = &nullcfg; 478 nullcfg.pcbe_flags = pic0->pcbe_flags; 479 toe = CPC_NIAGARA2_PCR_TOE0; /* enable trap-on-event for pic0 */ 480 } 481 482 if (pic0->pcbe_picno != 0) { 483 /* 484 * pic0 is counter 1, so if we need the null config it should 485 * be counter 0. 486 */ 487 nullcfg.pcbe_picno = 0; 488 tmp = pic0; 489 pic0 = pic1; 490 pic1 = tmp; 491 toe = CPC_NIAGARA2_PCR_TOE1; /* enable trap-on-event for pic1 */ 492 } 493 494 if (pic0->pcbe_picno != 0 || pic1->pcbe_picno != 1) 495 panic("%s: bad config on token %p\n", cpu_impl_name, token); 496 497 /* 498 * UltraSPARC does not allow pic0 to be configured differently 499 * from pic1. If the flags on these two configurations are 500 * different, they are incompatible. This condition should be 501 * caught at configure time. 502 */ 503 ASSERT(pic0->pcbe_flags == pic1->pcbe_flags); 504 505 ni2_pcbe_allstop(); 506 507 ultra_setpic(((uint64_t)pic1->pcbe_pic << PIC1_SHIFT) | 508 (uint64_t)pic0->pcbe_pic); 509 510 pcr = (pic0->pcbe_evsel & pcr_pic0_mask) << CPC_NIAGARA2_PCR_PIC0_SHIFT; 511 pcr |= (pic1->pcbe_evsel & pcr_pic1_mask) << 512 CPC_NIAGARA2_PCR_PIC1_SHIFT; 513 514 if (pic0->pcbe_flags & CPC_COUNT_USER) 515 pcr |= (1ull << CPC_NIAGARA2_PCR_UT_SHIFT); 516 if (pic0->pcbe_flags & CPC_COUNT_SYSTEM) 517 pcr |= (1ull << CPC_NIAGARA2_PCR_ST_SHIFT); 518 if (pic0->pcbe_flags & CPC_COUNT_HV) 519 pcr |= (1ull << CPC_NIAGARA2_PCR_HT_SHIFT); 520 pcr |= toe; 521 522 DTRACE_PROBE1(niagara2__setpcr, uint64_t, pcr); 523 524 if (pic0->pcbe_flags & CPC_COUNT_HV) { 525 /* 526 * The ht bit in the PCR is only writable in 527 * hyperprivileged mode. So if we are counting 528 * hpriv events, we must use the HV interface 529 * hv_niagara_setperf to set the PCR. If this 530 * fails, assume we no longer have access to 531 * hpriv events. 532 */ 533 if (hv_niagara_setperf(HV_NIAGARA_SPARC_CTL, pcr) != H_EOK) { 534 kcpc_invalidate_config(token); 535 return; 536 } 537 } else 538 /* Set the PCR with no hpriv event counting enabled. */ 539 ultra_setpcr(pcr); 540 541 ni2_cpc_counting[CPU->cpu_id] = B_TRUE; 542 543 /* 544 * On UltraSPARC, only read-to-read counts are accurate. We cannot 545 * expect the value we wrote into the PIC, above, to be there after 546 * starting the counter. We must sample the counter value now and use 547 * that as the baseline for future samples. 548 */ 549 curpic = ultra_getpic(); 550 pic0->pcbe_pic = (uint32_t)(curpic & PIC0_MASK); 551 pic1->pcbe_pic = (uint32_t)(curpic >> PIC1_SHIFT); 552 553 DTRACE_PROBE1(niagara2__newpic, uint64_t, curpic); 554 } 555 556 static void 557 ni2_pcbe_allstop(void) 558 { 559 /* 560 * We use the HV interface here because if we were counting 561 * hyperprivileged events, we must reset the PCR.ht bit to stop 562 * the counting. In the event that this HV call fails, we fall 563 * back on ultra_setpcr which does not have write access to the 564 * ht bit. 565 */ 566 if (hv_niagara_setperf(HV_NIAGARA_SPARC_CTL, allstopped) != H_EOK) 567 ultra_setpcr(allstopped); 568 569 ni2_cpc_counting[CPU->cpu_id] = B_FALSE; 570 } 571 572 static void 573 ni2_pcbe_sample(void *token) 574 { 575 uint64_t curpic; 576 int64_t diff; 577 uint64_t *pic0_data; 578 uint64_t *pic1_data; 579 uint64_t *dtmp; 580 uint64_t tmp; 581 uint64_t pcr; 582 ni2_pcbe_config_t *pic0; 583 ni2_pcbe_config_t *pic1; 584 ni2_pcbe_config_t nullcfg = { 1, 0, 0, 0 }; 585 ni2_pcbe_config_t *ctmp; 586 587 curpic = ultra_getpic(); 588 DTRACE_PROBE1(niagara2__getpic, uint64_t, curpic); 589 590 if ((pic0 = kcpc_next_config(token, NULL, &pic0_data)) == NULL) 591 panic("%s: token %p has no configs", cpu_impl_name, token); 592 593 if ((pic1 = kcpc_next_config(token, pic0, &pic1_data)) == NULL) { 594 pic1 = &nullcfg; 595 pic1_data = &tmp; 596 } 597 598 if (pic0->pcbe_picno != 0) { 599 nullcfg.pcbe_picno = 0; 600 ctmp = pic0; 601 pic0 = pic1; 602 pic1 = ctmp; 603 dtmp = pic0_data; 604 pic0_data = pic1_data; 605 pic1_data = dtmp; 606 } 607 608 if (pic0->pcbe_picno != 0 || pic1->pcbe_picno != 1) 609 panic("%s: bad config on token %p\n", cpu_impl_name, token); 610 611 612 if (pic0->pcbe_flags & CPC_COUNT_HV) { 613 /* 614 * If the hpriv attribute is present, but the HT bit 615 * is not set in the PCR, access to hyperprivileged 616 * events must have been revoked. Only perform this 617 * check if counting is not stopped. 618 */ 619 pcr = ultra_getpcr(); 620 DTRACE_PROBE1(niagara2__getpcr, uint64_t, pcr); 621 if (ni2_cpc_counting[CPU->cpu_id] && 622 !(pcr & CPC_NIAGARA2_PCR_HT)) { 623 kcpc_invalidate_config(token); 624 return; 625 } 626 } 627 628 diff = (curpic & PIC0_MASK) - (uint64_t)pic0->pcbe_pic; 629 if (diff < 0) 630 diff += (1ll << 32); 631 *pic0_data += diff; 632 633 diff = (curpic >> 32) - (uint64_t)pic1->pcbe_pic; 634 if (diff < 0) 635 diff += (1ll << 32); 636 *pic1_data += diff; 637 638 pic0->pcbe_pic = (uint32_t)(curpic & PIC0_MASK); 639 pic1->pcbe_pic = (uint32_t)(curpic >> PIC1_SHIFT); 640 } 641 642 static void 643 ni2_pcbe_free(void *config) 644 { 645 kmem_free(config, sizeof (ni2_pcbe_config_t)); 646 } 647 648 649 static struct modlpcbe modlpcbe = { 650 &mod_pcbeops, 651 #if defined(NIAGARA2_IMPL) 652 "UltraSPARC T2 Performance Counters", 653 #elif defined(VFALLS_IMPL) 654 "UltraSPARC T2+ Performance Counters", 655 #endif 656 &ni2_pcbe_ops 657 }; 658 659 static struct modlinkage modl = { 660 MODREV_1, 661 &modlpcbe, 662 }; 663 664 int 665 _init(void) 666 { 667 if (ni2_pcbe_init() != 0) 668 return (ENOTSUP); 669 return (mod_install(&modl)); 670 } 671 672 int 673 _fini(void) 674 { 675 return (mod_remove(&modl)); 676 } 677 678 int 679 _info(struct modinfo *mi) 680 { 681 return (mod_info(&modl, mi)); 682 } 683